From 6bb0209d40fc68cd7860c7fb9f32b7bdd0b7d7f6 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Sat, 19 Aug 2023 12:00:54 +0000 Subject: [PATCH 1/7] Modify NoteGetterOptions. --- .../src/client/client_execution_context.ts | 8 ++ .../src/client/pick_notes.test.ts | 94 +++++++++++++++++-- .../acir-simulator/src/client/pick_notes.ts | 17 +++- .../src/client/private_execution.ts | 15 ++- .../src/client/unconstrained_execution.ts | 15 ++- .../src/abis/ecdsa_account_contract.json | 2 +- .../src/abis/schnorr_account_contract.json | 2 +- .../escrow_contract/src/address_note.nr | 2 - .../src/address_note/filter.nr | 21 ----- .../src/contracts/escrow_contract/src/main.nr | 3 +- .../noir-aztec/src/note/note_getter.nr | 49 ++++++++-- .../src/note/note_getter_options.nr | 90 ++++++++++++------ .../noir-libs/noir-aztec/src/oracle/notes.nr | 13 ++- .../noir-libs/value-note/src/value_note.nr | 1 - 14 files changed, 250 insertions(+), 82 deletions(-) delete mode 100644 yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note/filter.nr diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index 4e28591132c..c12f96e5173 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -104,6 +104,9 @@ export class ClientTxExecutionContext { * * @param contractAddress - The contract address. * @param storageSlot - The storage slot. + * @param numSelects - The number of valid selects in selectBy and selectValues. + * @param selectBy - An array of indices of the fields to selects. + * @param selectValues - The values to match. * @param sortBy - An array of indices of the fields to sort. * @param sortOrder - The order of the corresponding index in sortBy. (1: DESC, 2: ASC, 0: Do nothing) * @param limit - The number of notes to retrieve per query. @@ -118,6 +121,9 @@ export class ClientTxExecutionContext { public async getNotes( contractAddress: AztecAddress, storageSlot: ACVMField, + numSelects: number, + selectBy: ACVMField[], + selectValues: ACVMField[], sortBy: ACVMField[], sortOrder: ACVMField[], limit: number, @@ -136,6 +142,8 @@ export class ClientTxExecutionContext { // Nullified pending notes are already removed from the list. const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { + selectBy: selectBy.slice(0, numSelects).map(field => +field), + selectValues: selectValues.slice(0, numSelects).map(field => fromACVMField(field)), sortBy: sortBy.map(field => +field), sortOrder: sortOrder.map(field => +field), limit, diff --git a/yarn-project/acir-simulator/src/client/pick_notes.test.ts b/yarn-project/acir-simulator/src/client/pick_notes.test.ts index fff9d3ab876..8f130706cd1 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.test.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.test.ts @@ -3,7 +3,7 @@ import { Fr } from '@aztec/foundation/fields'; import { SortOrder, pickNotes } from './pick_notes.js'; describe('getNotes', () => { - const expectSortedNotes = (notes: { preimage: Fr[] }[], ...expected: [number, bigint[]][]) => { + const expectNotesFields = (notes: { preimage: Fr[] }[], ...expected: [number, bigint[]][]) => { expect(notes.length).toBe(expected[0][1].length); expected.forEach(([fieldIndex, fields]) => { for (let i = 0; i < notes.length; ++i) { @@ -12,6 +12,13 @@ describe('getNotes', () => { }); }; + const expectNotes = (notes: { preimage: Fr[] }[], expected: bigint[][]) => { + expect(notes.length).toBe(expected.length); + notes.forEach((note, i) => { + expect(note.preimage.map(p => p.value)).toEqual(expected[i]); + }); + }; + const createNote = (preimage: bigint[]) => ({ preimage: preimage.map(f => new Fr(f)), }); @@ -30,21 +37,21 @@ describe('getNotes', () => { { const options = { sortBy: [1], sortOrder: [SortOrder.ASC] }; const result = pickNotes(notes, options); - expectSortedNotes(result, [1, [0n, 1n, 5n, 5n, 5n, 6n]]); + expectNotesFields(result, [1, [0n, 1n, 5n, 5n, 5n, 6n]]); } // Sort 1st field in descending order. { const options = { sortBy: [1] }; const result = pickNotes(notes, options); - expectSortedNotes(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 4n, 6n, 6n, 2n, 0n]]); + expectNotesFields(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 4n, 6n, 6n, 2n, 0n]]); } // Sort 1st and 0th fields in descending order. { const options = { sortBy: [1, 0] }; const result = pickNotes(notes, options); - expectSortedNotes(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 6n, 6n, 4n, 2n, 0n]]); + expectNotesFields(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 6n, 6n, 4n, 2n, 0n]]); } // Sort 1st field in descending order @@ -52,7 +59,7 @@ describe('getNotes', () => { { const options = { sortBy: [1, 0], sortOrder: [SortOrder.DESC, SortOrder.ASC] }; const result = pickNotes(notes, options); - expectSortedNotes( + expectNotesFields( result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 4n, 6n, 6n, 2n, 0n]], @@ -66,7 +73,7 @@ describe('getNotes', () => { { const options = { sortBy: [1, 0, 2], sortOrder: [SortOrder.DESC, SortOrder.ASC, SortOrder.DESC] }; const result = pickNotes(notes, options); - expectSortedNotes( + expectNotesFields( result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 4n, 6n, 6n, 2n, 0n]], @@ -84,19 +91,19 @@ describe('getNotes', () => { { const options = { sortBy, limit: 3 }; const result = pickNotes(notes, options); - expectSortedNotes(result, [0, [8n, 6n, 5n]]); + expectNotesFields(result, [0, [8n, 6n, 5n]]); } { const options = { sortBy, limit: 3, offset: 1 }; const result = pickNotes(notes, options); - expectSortedNotes(result, [0, [6n, 5n, 2n]]); + expectNotesFields(result, [0, [6n, 5n, 2n]]); } { const options = { sortBy, limit: 3, offset: 4 }; const result = pickNotes(notes, options); - expectSortedNotes(result, [0, [0n]]); + expectNotesFields(result, [0, [0n]]); } }); @@ -104,6 +111,73 @@ describe('getNotes', () => { const notes = [createNote([2n]), createNote([8n]), createNote([6n]), createNote([5n]), createNote([0n])]; const options = { sortBy: [0], sortOrder: [SortOrder.NADA] }; const result = pickNotes(notes, options); - expectSortedNotes(result, [0, [2n, 8n, 6n, 5n, 0n]]); + expectNotesFields(result, [0, [2n, 8n, 6n, 5n, 0n]]); + }); + + it('should get notes that have the required fields', () => { + const notes = [ + createNote([2n, 1n, 3n]), + createNote([1n, 2n, 3n]), + createNote([3n, 2n, 0n]), + createNote([2n, 2n, 0n]), + createNote([2n, 3n, 3n]), + ]; + + { + const options = { selectBy: [0], selectValues: [new Fr(2n)] }; + const result = pickNotes(notes, options); + expectNotes(result, [ + [2n, 1n, 3n], + [2n, 2n, 0n], + [2n, 3n, 3n], + ]); + } + + { + const options = { selectBy: [0, 2], selectValues: [new Fr(2n), new Fr(3n)] }; + const result = pickNotes(notes, options); + expectNotes(result, [ + [2n, 1n, 3n], + [2n, 3n, 3n], + ]); + } + + { + const options = { selectBy: [1, 2], selectValues: [new Fr(2n), new Fr(3n)] }; + const result = pickNotes(notes, options); + expectNotes(result, [[1n, 2n, 3n]]); + } + + { + const options = { selectBy: [1], selectValues: [new Fr(5n)] }; + const result = pickNotes(notes, options); + expectNotes(result, []); + } + + { + const options = { selectBy: [0, 1], selectValues: [new Fr(2), new Fr(5n)] }; + const result = pickNotes(notes, options); + expectNotes(result, []); + } + }); + + it('should get sorted matching notes', () => { + const notes = [ + createNote([2n, 1n, 3n]), + createNote([4n, 5n, 8n]), + createNote([7n, 6n, 8n]), + createNote([6n, 5n, 2n]), + createNote([0n, 0n, 8n]), + createNote([6n, 5n, 8n]), + ]; + + const options = { selectBy: [2], selectValues: [new Fr(8n)], sortBy: [1], sortOrder: [SortOrder.ASC] }; + const result = pickNotes(notes, options); + expectNotes(result, [ + [0n, 0n, 8n], + [4n, 5n, 8n], + [6n, 5n, 8n], + [7n, 6n, 8n], + ]); }); }); diff --git a/yarn-project/acir-simulator/src/client/pick_notes.ts b/yarn-project/acir-simulator/src/client/pick_notes.ts index 9f52b147399..535a0ca1ffa 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.ts @@ -13,6 +13,16 @@ export enum SortOrder { * Options for selecting items from the database. */ interface GetOptions { + /** + * An array of indices of the fields to select. + * Default: empty array. + */ + selectBy?: number[]; + /** + * An array of values of the corresponding fields to select and match. + * Default: empty array. + */ + selectValues?: Fr[]; /** * An array of indices of the fields to sort. * Default: empty array. @@ -45,6 +55,9 @@ interface BasicNoteData { preimage: Fr[]; } +const selectNotes = (notes: T[], selectBy: number[], selectValues: Fr[]): T[] => + notes.filter(note => selectBy.every((fieldIndex, i) => note.preimage[fieldIndex]?.equals(selectValues[i]))); + const sortNotes = (a: Fr[], b: Fr[], sortBy: number[], sortOrder: number[], level = 0): number => { const index = sortBy[level]; if (sortBy[level] === undefined) return 0; @@ -65,9 +78,9 @@ const sortNotes = (a: Fr[], b: Fr[], sortBy: number[], sortOrder: number[], leve */ export function pickNotes( notes: T[], - { sortBy = [], sortOrder = [], limit = 0, offset = 0 }: GetOptions, + { selectBy = [], selectValues = [], sortBy = [], sortOrder = [], limit = 0, offset = 0 }: GetOptions, ) { - return notes + return selectNotes(notes, selectBy, selectValues) .sort((a, b) => sortNotes(a.preimage, b.preimage, sortBy, sortOrder)) .slice(offset, limit ? offset + limit : undefined); } diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index fa9a4db3bae..80c8831cfeb 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -76,8 +76,19 @@ export class PrivateFunctionExecution { const { publicKey, partialAddress } = await this.context.db.getCompleteAddress(address); return [publicKey.x, publicKey.y, partialAddress].map(toACVMField); }, - getNotes: ([slot], sortBy, sortOrder, [limit], [offset], [returnSize]) => - this.context.getNotes(this.contractAddress, slot, sortBy, sortOrder, +limit, +offset, +returnSize), + getNotes: ([slot], [numSelects], selectBy, selectValues, sortBy, sortOrder, [limit], [offset], [returnSize]) => + this.context.getNotes( + this.contractAddress, + slot, + +numSelects, + selectBy, + selectValues, + sortBy, + sortOrder, + +limit, + +offset, + +returnSize, + ), getRandomField: () => Promise.resolve(toACVMField(Fr.random())), notifyCreatedNote: ([storageSlot], preimage, [innerNoteHash]) => { this.context.pushNewNote( diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts index 78ea53b52b8..986d2ac48f1 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts @@ -48,8 +48,19 @@ export class UnconstrainedFunctionExecution { const { publicKey, partialAddress } = await this.context.db.getCompleteAddress(address); return [publicKey.x, publicKey.y, partialAddress].map(toACVMField); }, - getNotes: ([slot], sortBy, sortOrder, [limit], [offset], [returnSize]) => - this.context.getNotes(this.contractAddress, slot, sortBy, sortOrder, +limit, +offset, +returnSize), + getNotes: ([slot], [numSelects], selectBy, selectValues, sortBy, sortOrder, [limit], [offset], [returnSize]) => + this.context.getNotes( + this.contractAddress, + slot, + +numSelects, + selectBy, + selectValues, + sortBy, + sortOrder, + +limit, + +offset, + +returnSize, + ), getRandomField: () => Promise.resolve(toACVMField(Fr.random())), debugLog: (...params) => { this.log(oracleDebugCallToFormattedStr(params)); diff --git a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json index a905bcd0bd6..cd11f71a080 100644 --- a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json +++ b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json @@ -153,7 +153,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "H4sIAAAAAAAA/+2dB3xcxdHA392pn7pkNcu2JDfZsq17Kpbkei6Yjo2xqQZcsMHBmGbTAhhCQgqBhF4ChN4hQAghhN4hQGghEEJJCKRAgEBCCPXblWbQ6OlZLjcrz37a9/uNZnd1t/uf2d15e+/2vTs43fOmpXmdR0RJVEkapDGfHshnQDq9620evN0rU1KupEJJJXkf/r9KyWAl1UqGwP+j5P9DlQxTUqOklrQ3XEkWyY8I5EcG8qMC+dGBfH0gPyaQHxvINwTy4wL58YH8hEC+MZBPBPJ+IN8UyDcH8i2BfGsgPzGQbwvk2wP5jkB+UiA/OZCfEshPDeSnBfLTA/lkID8jkJ8ZyM8K5GcH8lsF8nMC+a0D+W0C+W0D+e0C+e0D+R0C+R0D+Z0C+bmB/LxAfudAfn4gv0sgvyCQXxjI7xrI7xbI7x7I7xHI7xnI7xXILwrk9w7k9wnk9w3kFwfySwL5pZDX8SHmdY0Xfeg4oOe+nu96jut5Xe91zV89Z/U81XNTz0c9B/W803NNzy89p/Q80nNHzxc9R/S80HNBj3895vU412Nbj2c9hqdD23p86jGpx6Eee3q86TGmx5UeS3r86DGjx4keG3o86DEwF/p6Z+jTXaDvFkIf7QZ9sQf4fC/w7d7gw33BV0vAJ9o/OvbWgD90vP3S64q5WleArgRdBXow6GrQQ0APBT0MdA3oWtB1oIeDHgF6JOhRoEeDrgc9BvRY0A2gx4EeD3oC6EbQCdA+6CbQzaBbQLeS+pYp2S/ENxPhNW2g20F3gJ4EejLoKaCngp4GejroJOgZoGeCngV6NuitQM8BvTXobUBvC3o70NuD3gH0jqB3Aj0X9DzQO4OeD3oX0AtALyS+Wa5khdfziIBOgm5OTGxpWd7WtNxv9pckmjqWtrcmWlqXTmz32/3W9tb9mtqbm5e3t7S3dSztaEt0+C3Ny/0VrR3NKxJdx/6krkSKh0nOAyzhXGkJ5zcs4TzQEs5VlnAeZAnnaks4D7aE8xBLOA+1hPMwSzgPt4RzjSWcay3hPMISziMt4TzKEs6jGTmDn8n0Z1792WQ30LuD3gP0nqD3Ar0I9N6g9wG9L+jFoJeAXgp6f9AHgF4J+hugDwS9CvRBoFeDPhj0IaAPBX0Y6MNBrwG9FvQRoI8EfRToo73uz2THKPmm1/Pg7sNjPTvG2nGWcB5vCec6SzhPsITzREs4v2UJ50mWcH7bEs7vWMJ5siWc37WE83se/xqtEOrT19P1WmU56GNAHwv6ONDHg14H+gTQJ4L+FuiTQH8b9HdAnwz6u6C/53Wvkb6v5Ade13c/md76jySPD3xzdbc0G6y7xWDdrQbrnmiw7jaDdbdnQD16ztRA+hQlP1RyqpLTlPxIyY+VnK7kDCVnKjlLydlKzlFyrpLzlJyv5AIlP1FyoZKLlFys5KdKLlFyqZLLlFyu5AolVyq5SsnVSq5Rcq2S6wIs1yu5QcmNSm5S8jMlNyu5RcmtSn6u5DYlv1Byu5JfKrlDya+U3Knk10ruUnK3knuU3KvkPiX3K3lAyYNKHlLysJJHlDyq5DEljyt5Ahh+A/pJ0E+BftrrPqaUdOlsr+t7Xn2gb3UZzvl0Uob/TyNl+P8YKcP/R0kZ/j9CyvD/XqB9fSRBJ1I8MrzesT+R4qFtLiJ2eCH2RkL8Eg3xH/4/PcR/tD/w/9gv+UriIW1nEKYkj71+xOt5JEka26IsMUEsaYJY0gWxZAhiyRTEkiWIJbKFWWgcw0OP4Umx7v/jmpXGPoyNNPYVQ5rGvhJSJ5aVEpuxbBCkM0lZGaSzSBlyF5KyHEjTeI0+LiZluZAuIWV5kC4lZfmQHkTKCiBdFsJH+xDfkwSdSO3o7EPaTpLksa0cwlAmgCVLEEumIJYMQSzpgljSBLHEBLFEzbN0rp1LmOukMd4jdtIjSdIlxL5iA/YVGbCveBPsKyL2FRqwr9yAfYWbYF85sa/CgH2VBuyr2AT7Kol9VQbsY67T13UONsA5hLfONt0P1d7G98MQ0g9Dme3TdQwjbSEXthMn/88mHMOY+y5C2sR6MU/5NpY1xyLWuEWsuRax5lnEmm8Ra8EWZuVv1++MybRdffQVkylLDStL1zmnlrlOXUcd4UdbkT1O/l9LbKvj5fDp9wlYL+brSLvOftZ2nf2es9/Z7+x39jv7nf3Ofme/s9/Z7+yvcfY7+539zn5nv7Pf2e/sF2D/+vb+1hhg8QIsXohf8IgJYkkTxJIuiCVDEEumIJYsQSzZglhyBLHEBbHkCmLJE8SSL4ilQBBLoSCWIkEsxYJYSgSxlApiGSSIpUwQS7kglgpBLJWCWKoEsQwWxFItiGWIIJahglgM7qHbZJZaQSyRLcwSdm9kNvl/lJThNRt6P+RwSNP7IUdAmt4POZLYiWWjIE3vhxwNaXo/ZD2k6b2KYyBN72kcC2l6P2QDpOm9lOMgXUHKxkO6ipRNgPRgUtYI6WpShg9oGUrK0G81pAz9VkfK0G/DSRn6bQQpQ7+NJGXot1GkDP02mpThZ/B6UoafhceQMhyXY0kZfjZsIGX4GW0cKcPPSuNJGX5mmUDKsB8aSRmu4dGP2v5z0rr/j6+lYzERUg+m6ZzCtpPYBsOcou0kSR7boveqNgpgqRXEMkwQy1BBLEMEsVQLYhksiKVKEEulIJYKQSzlgljKBLEMEsRSKoilRBBLsSCWIkEshYJYCgSx5AtiyRPEkiuIJS6IJUcQS7YglixBLJmCWDIEsaQLYkkTxBITxBINYanlZem87IPXmDrrA11LOJBpPOEYx+wTXUdDCMc4woHtNxCOsbwc+mcNv76GRznGEg5sfwzhqOfl6Hw28egQjnrCge2PJhyjeDk6n2M8MoRjFOHA9uk16RG8HJ3PPB4ewjGCcGD7wwlHHS9H5/ORa0I46ggHto+vc3syN8zi9mS6PZmbwuL2ZLo9mZvC4vZkuj2Zm8Li9mS6PZmbwuL2ZLo9mZvC4vZkuj2Zm8Li9mS6PZmbwlIriKVOEMtwQSwjBLGMFMQyShDLaEEs9YJYxghiGSuIpUEQyzhBLOMFsUwQxNIoiCUhiCWyhVk2dB8H3YOPP1JK9+o3QZru88cfHKX3COAPhdL7C/AHPum9CfjDnPS+hmgIM36n45My/G6liZThdxzNpAy/a2ghZXjNv5WU4bV3ZOqsK7f7/zVQHiXvwR//pPe6tEOa3uvSQeuEskmQpve6TIY0vdcFeWpIGXK3kTK0r52UoR86SBn6axIpQ79ODmGhYxbfkwSdSO3oHLO0nSTJY1v0PonJAlgSglgaBbFMEMQyXhDLOEEsDYJYxgpiGSOIpV4Qy2hBLKMEsYwUxDJCEMtwQSx1glhqBbEME8QyVBDLEEEs1YJYBgtiqRLEUimIpUIQS7kgljJBLIMEsZQKYikRxFIsiKVIEEuhIJYCQSz5gljyBLHkCmKJC2LJEcSSLYglSxBLpiCWDEEs6YJY0gSxxASxRAMs9HumiaQMvw+i33/h90b0ezL8fol+n1YDafq92xRI0+/nogE++j0e/T4K+5J+b4VjjX6/hXOhhpThXMX2M+F12HYSdCLFI4Nw8tTZlKD+wKOv73DpvWTpBuzLYK4T+wMPtBXZ417Pe69QZ/JydM6ddK+nTzFP23f2s7br7Pec/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+zf8vYz9tu1/4G2q4++trfQFmyWFnM7W/IJvxoK7LHvZ7PUEWdzcvR2b9ZXk+f0t9FxHad/aztOvs9Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7N8y9pvYUzBQ68wmvo0SX+Pzjejz8PH5S+mkDJ8PRfspL6QsP6SsIKSMMqBGhhxShs/QiJMy5MolZThe80gZ7k/JJ2XIgEyZ8F58pl0SdCK1o0m3hc+mw6OvvTQlhBGf9Ud/43IQL1/nHCwNsGAe24oThkJzLG3x9bSNR5S0XWrAD17AD3iUhrDEBLGkCWJJF8SSIYglUxBLliCWbEEsOYJY4oJYcgWx5AliyRfEUiCIpVAQS5EglmJBLCWCWCJbmCXbC/9tNfw//YwyiKRR47PK6eeV8oCdugyf9U4/r+Cz6OnnlSpI088rgyFdQMrwtwaKSFk0xDZcq1J2XDOWkTJcu5WTMlxDVZAyXMtUkjJcU1SRMvTRYFKGPkJ23WZBbm87oyF20nowTccOtp0EnUjt6Bw7tJ0kyWNb9DfOBgtgKRHEUiyIpUgQS6EglgJBLPmCWPIEseQKYokLYskRxJItiCVLEEumIJYMQSzpgljSBLHEBLFEQ1gqeVk6v4vDtbU+cK1bSTiQqYJwlDNzRAIcNaTdctJuGXNf6DoGhdhPP1Nh+4NIGabpZ2ruvqGfAbFuPVda0s35I8Prfk4+lx26b/H3+vSxjthVQ/xnot1hgXbLAu3q1wwhDOsIK743Rl6TTO/uhymQziH14XjQfVcbaIt+Psb/4fd+dQZsxzaQAX1eR2yvI7bXkPdUENvxNVsR2z+Pd79vBC9750834O+BRgn3CMI6irfNzp+kGOl1H1j/cFJWT9IYJ/A99Ddv6wmniXhFObD9MlI2NoSznnCOCbxOczbwcnaOP8oRIe1iWzHyml3I2PqMjC0T/dzg9fbfKOKL8bxttup5P87refR1XXA8YZnAy5IwtYZoJPxoK7LHyf8riW2NvByd66oJXk+fYr6RtOvsZ23X2e85+22xf337eZjjbJ/f+0wIYYkJYkkTxJIuiCVDEEumIJYsQSzZglhyBLHEBbHkCmLJE8SSL4ilQBBLoSCWIkEsxYJYSgSxlApiGSSIpUwQS7kglgpBLJWCWKoEsQwWxFItiGWIIJahgliGCWKpEcRSK4ilThDLcEEsIwSxjBTEMkoQy2hBLPWCWMYIYhkriKVBEMs4QSwGv+vcZJbIFmZZ330g+P9qUobfZ4wjZQlIN5CyaEgb+F1DIynDa/5Yh77uXpfbu71oSHuNIVymfUnbSZI8tkXvi2gUwDJeEMs4QSwNgljGCmIZI4ilXhDLaEEsowSxjBTEMkIQy3BBLHWCWGoFsdQIYhkmiGWoIJYhgliqBbEMFsRSJYilUhBLhSCWckEsZYJYBgliKRXEUiKIpVgQS5EglkJBLAWCWPIFseQJYskVxBIXxJIjiCVbEEuWIJZMQSwZgljSBbGkCWKJCWKJBljcvSAbZnH3goSzuHtBwlncvSDhLO5ekHAWdy9IOEu+IJYCQSzuXpBwFncvSDiLuxcknMXdCxLO4u4FCWdx94KEs7h7QcJZ3L0g4Sw1glhqBbHUCWJx94KEs7h7QcJZ3L0g4SzuXpBwlgZBLO5ekHAW099XbApLQhBLZAuzbOgemQQpiwbeq78/WETuaZkI5VHynjZI09+hbId0GinrIHVi2SRIZ5CyyZDODGGdSMp8SLeRsiZIt5OyZkh3kLIWSE8iZa2QnhzCQvsQ35MEnUjt6OxD2k6S5LEtem/OZAEsCUEsjYJYxgtiGSeIpUEQy1hBLGMEsdQLYhktiGWUIJaRglhGCGIZLoilThBLrSCWGkEswwSxDBXEMkQQS7UglsGCWKoEsVQKYqkQxFIuiKVMEMsgQSylglhKBLEUC2IpEsRSKIilQBBLviCWPEEsuYJY4oJYcgSxZAtiyRLEkimIJUMQS7ogljRBLDFBLNEQlg5elib63ZVHmOiRJGn63VN7gFnztRnwVXuABfPYVpwwTDDG0pSIh7RtwOam7IDN+uirT+j3hvi9Yjvhm8LL19knEwMsmMe2qK98YyxdfRJs24DNTdkBm/XRV59g+/p9UyE9kfBN4+Xr7JOpARbMY1vUV00GWeIhbRtopyk7YLM++uoTbF+/bzqkpxK+JLMfIqQdrHd6oA3qq2aDLPGQtg2000R9i0dffYJp/b4ZkJ5O+GYy+yFC2sF6MY9tUV+1GGSJh7RtoJ2m7IDN+uirT7B9/b5ZkJ5B+GYz+yFC2sF6MY9tUV+1GmSJr6dtPKKk7VkG/OAF/IDHrBCWmCCWNEEs6YJYMgSxZApiyRLEki2IJUcQS1wQS64gljxBLPmCWAoEsRQKYikSxFIsiKVEEEupIJZBgljKBLGUC2KpEMRSKYilShDLYEEs1YJYhghiGSqIZZgglhpBLLWCWOoEsQwXxDJCEMtIQSyjBLGMFsRSL4hljCCWsYJYGgSxjBPEMl4QywRBLI2CWBKCWHxBLE2CWJoFsbQIYmkVxDJREEubIJZ2QSwdglgmCWKZLIhliiCWqYJYpglimS6IJSmIZYYglpmCWCJbmGV9zyPC/9Nn8uBeIvo8n60gTZ8FNAfSU0nZ1pCeTsq2gfQMUrYtpMtJ2XaQHk3Ktod0lJRFQ2yLQXo2KcN9PluRMtxvM4eU4b6XrUkZ7j/ZhpThPpBtSRnux9iOlOG+CGTXbR5Z3NsmOibw/UnQidSOzjFB20mSPLZFn2+0vQCWmYJYZghiSQpimS6IZZoglqmCWKYIYpksiGWSIJYOQSztgljaBLFMFMTSKoilRRBLsyCWJkEsviCWhCCWRkEsEwSxjBfEMk4QS4MglrGCWMYIYqkXxDJaEMsoQSwjBbGMEMQyXBBLnSCWWkEsNYJYhgliGSqIZYgglmpBLIMFsVQJYqkUxFIhiKVcEEuZIJZBglhKBbGUCGIpFsRSJIilUBBLgSCWfEEseYJYcgWxxAWx5AhiyRbEkiWIJVMQS4YglnRBLGmCWGKCWKIBlhzy/2JShvuP6PM3cZ9SOynD/UwTSdkcSE8lZbg/ajopw31UM0BjHPY891yp9bG450qFs2QIYnHPlQpncc+VCmeJC2Jxz5UKZ3HPlQpncc+VCmdxz5UKZ3HPlQpncc+VCmdxz5UKZ3HPlQpncc+VCmdxz5UKZ6kRxFIriKVOEMtwQSzuuVLhLKMEsbjnSoWzuOdKhbM0CGJxz5UKZ3HPlQpncc+VCmdxz5UKZ3HPlQpncc+VCmdxz5UKZ3HPlQpncc+VCmdxz5UKZ0kKYpkhiGWmIJbZgli2EsQyRxDL1oJYthHEsq0glu0EsWwviCWyhVk29Nw6+iy2HSBNn9m2I6Tps912gvQcUjYX0vRZcfMgTZ8pFw3hi0F6B1KGewF3JGW4J28nUoZ74+aSMtyjhu3r9z1Onh83H8qj5D27QDpGyhZAOo2ULSR1YtmukM4gZbtBOpOU7Q7pLFKGjPNJGdqyCylDmxeQMvTNQlKGPtyVlKGvdyNlO0N69xA+OmbxPUnQidSOzjFL20mSPLaVQxh2F8CyvSCW7QSxbCuIZRtBLFsLYpkjiGUrQSyzBbHMFMQyQxBLUhDLdEEs0wSxTBXEMkUQy2RBLJMEsXQIYmkXxNImiGWiIJZWQSwtgliaBbE0CWLxBbEkBLE0CmKZIIhlvCCWcYJYGgSxjBXEMkYQS70gltGCWEYJYhkpiGWEIJbhgljqBLHUCmKpEcQyTBDLUEEsQwSxVAtiGSyIpUoQS6UglgpBLOWCWMoEsQwSxFIqiKVEEEuxIJYiQSyFglgKBLHkC2LJE8SSK4glLoglRxBLtiCWLEEsmYJYMgSxpAtiSRPEEhPEEg1hGcHL0kbb1O3hWpI+82Ahc5t0b6hH/ECPJEkvJCy78LIkdLvzSf1J0gZtdw/edn3abgQE28DyGEkfTzZP79Gd/HrfIzLrcbMg5HU0vWvgPXHy/wWGbd6FcCRJHtvSseBwYuuCEO7dCDf+fx7hLmPm1nUsJBzYPn1+F/O4bKP7rPHoa47sQliY+61zjuxJ6k+SNmi7ezH7nbaLcwTbwPIYSZ9Oxs1e3cmvxw0y6zkyP+R1NB2cQ3Hy//mGbaZzNUny2JaeIycTW+eHcC8k3Pj/uYTbxByhcxvbp3OEeVy20XsW8OhrjuxBWJj7rXOOLCL1J0kbtN29mf1O28U5gm1geYykryDjZu/u5NfjBpn1HNkz5HU0HZxDcfL/PQ3bTOdqkuSxLT1Hzie27hnCTc9/+P+dCLeJOULnNrZP5wjzuOycI9R2ffQ1R/YiLMz91jlH9iH1J0kbtN19mf1O28U5gm1geYykf0nGzb7dya/HDTLrObIo5HU0HZxDcfL/RYZtpnM1SfLYlp4jNxBbF4Vw0/Mf/n9Hwm1ijtC5je3TOcI8LjvnCLVdH33Nkb0JC3O/dc6RxaT+JGmDtruE2e+0XZwj2AaWx0j6CTJulnQnvx43yKznyD4hr6Pp4ByKk//vY9hmOleTJI9t6TlyL7F1nxBuev7D/+9AuE3METq3sX06R5jHZeccobbro685si9hYe63zjmylNSfJG3Qdpcx+522i3ME28DyGEm/SsbNsu7k1+MGmfUcWRzyOpoOzqE4+f9iwzbTuZokeWxLz5HniK2LQ7jp+Q//P4twm5gjdG5j+3SOMI/Lzjmy2Ot59DVHlhAW5n7rnCP7kfqTpA3a7nLedn3aLs4RbAPLYyT9ARk3y7uTX48bZNZzZGnI62h6ceA9cfL/pYZtpnM1SfLYlp4jbxFbl4Zw0/Mf/n9nwm1ijtC5je1jO9mEg/62gcm4ivVinvZlccBfBlja4iFt6777LN6d/jxutk+oL0pD+gTLlhK+FvhCR88t/N4gCl/c5sH78DtC+iyHHFIHluEwpc9yoL8Rg2X4HTV9lgN+h06f5RAladTIkEPKkCFOypAhl5QhQx4pQ4Z8wpRB3pcEnUjtaKL+waOvGE+58wL2ZRBeJr7OuZQXYMkL+CZOGHKMsfidcynYdk6IH3ICbMhTwMyj6yxirlP3K+6nwaOv8YDtZ3ndc2T/5Wt2OnjN8sMj5P1YZznxER5Rko6R96R5vTnSQ8oyQsoyvd5HFklnk3QBeV9+gFO/DuN0ISlDZvwfzk9kSYJOpHY00ZhB7aNHkqRpPEMf0N+4y+Ll84O+TpI8thUnDDFzLK3xkLZz1uOHbN62E9lez3OEPvT4bcztbjPObK+BeNu5zsYYr491xC76+2Em2s0LtBsPtBvxesb3dYQV3xsjr5mc290PbZCmsZmuBwoCbdE5jv/L9Hru8aPzksZM9BeNX8UkHQ28h+6npOtS3HuaBJ1I7WjNDnDoo69YQn9zaxAvS2d/08+uSdIGbbect12ftouf57ANLI+R9E5kMpR3J78eA8hM9y3T19F0ceA9cfL/UsM2DyIcSZLHtvRYnUVsLQ3hpvEc/09/r66UmVvXUUI4sgJs2cQOGtu5P8P05b8y4pP0gL8MsHSe44Jtm/L9oA34HsvwdcHzXRovUxP9nIVHX/GL/s4w77qsKbG56zKtM1lZEgkDa6nORxrQNTLaiuxx8n/6+7zM66o+15f0t3id/aztOvs9Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7O9/+7NJWWwLs8QJg7n9lk2JuBc+Dphtbsr2eu8l7mufB2Xh3e/ZteckZxNY6N5z5vsGjO05oXtA0dZcYg/+n865PF4OP7gHNun13mfq7Hf2O/tZ23X2e85+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z7+z39nv7Hf2O/ud/c5+Z/+WsT+blGVuYRa6FyTHGEvXnpOwccBsc+c4yCc2RwNt0t8wNPdMri57gwy6Hd7nGHb1MT2SJI1tUZaYIJY0QSzpglgyBLFkCmLJEsSSLYglRxCLuWe2bjpLriCWPEEs+YJYIluYJdvrvQ80m/yfPrO5ENJ9PedSl+E5Fl+vzy0vF3f/H5/7FyXvwefexULaKwrhKg55L/Ul77ONu3xJ20mSPLaVQxiKBbDkC2LJE8SSK4glLoglRxBLtiCWLEEsmYJYMgSxpAtiSRPEEhPEEg1h4b7+QdcXWLfuj+r87jZ5n3frr9B1Mj93ORF8bvA6Ylc58Z+JdssC7QafTa1fQ5+zvc7r/VzhGHnNwuLufhgB/ZBD6qPXZCp57el8FnGV133gGMR2NEcFpKsIR39dD6tibafvNT+2tb7rYVuaJU0QS7oglgxBLJmCWLIEsWQLYskRxBIXxJIriCVPEEu+IJYCQSyFgliKBLEUC2IpEcRSKohlkCCWMkEs5YJYKgSxVApiiWxhlvV9J4L/ryBlgyEd9p0IrQ8/Z+Hrg9+JVEM5/U5kCKRjIe1Vh3ANCXkv9SW+Jwk6kdrR6UvaTpLksS36ncgQASyVglgqBLGUC2IpE8QySBBLqSCWEkEsxYJYigSxFApiKRDEki+IJU8QS64glrgglhxBLNmCWLIEsWQKYskQxJIuiCVNEEtMEEs0hIX7O2pdx1Cv+8DPkaWEA5mGGuTQdQ5jrbPr2ZbUNvQ3PZIkPYzYV8vK0vX9eR2pP0naoO0O523Xp+1GQLANLI+R9KvkJpHh3cmvPwcisx4XNSGvo+mhgffEyf9rDNtcSziSJI9t6ZjzHLG1JoS7lHDj/+n1Few3+l15jQFbhnk9bRkWYKbPxx1qjKVrr0KwbQM2N+k6aP9FA23mEI5awtFfezOYY0Of1x7p3MEjJoglTRBLuiCWDEEsmYJYsgSxZAtiyRHEEhfEkiuIJU8QS74glgJBLIWCWIoEsRQLYikRxFIqiGWQIJYyQSzlglgqBLFUCmKpEsQyWBBLtSCWIYJYhgpiMXjdb5NZagSxRLYwy/r2WwWvm+oyvH4Ztt+K1ofXTvD1wf1WeH0wSt4zAtKxkPaGh3CNCHkv9aWJ6520nSTJY1t0v9UIASw1gliGCWIZKohliCCWakEsgwWxVAliqRTEUiGIpVwQS5kglkGCWEoFsZQIYikWxFIkiKVQEEuBIJZ8QSx5glhyBbHEBbHkCGLJFsSSJYglUxBLhiCWdEEsaYJYYoJYoiEsJp4thG3SZwv9sqC7TRP7JeuZ7dB+HOV1H+uIXfXEfybaHR1otzTQrn7NSMKwjrDie2PkNc3k2UL3Qj/kkPronpixvPY06zoavO4DxyC2oznGQLqBcPTX/rUG1nb6vpaLba1v/9qWZkkTxJIuiCVDEEumIJYsQSzZglhyBLHEBbHkCmLJE8SSL4ilQBBLoSCWIkEsxYJYSgSxlApiGSSIpUwQS7kglgpBLJWCWKoEsQwWxFItiGWIIJahgliGCWKpEcRSK4ilThDLcEEsIwSxjBTEMkoQy2hBLPWCWMYIYhkriCWyhVnWt28Y/z+GlI2DdNi+YVofXrPG1wf3DY+H8ih5zwRIx0LaGx/CNSHkvdSX+J4k6ERqR6cvaTtJkse26L7hCQJYxgpiGSOIpV4Qy2hBLKMEsYwUxDJCEMtwQSx1glhqBbHUCGIZJohlqCCWIYJYqgWxDBbEUiWIpVIQS4UglnJBLGWCWAYJYikVxFIiiKVYEEuRIJZCQSwFgljyBbHkCWLJFcQSF8SSI4glWxBLliCWTEEsGYJY0gWxpAliiQliiYawmHjmdaPXfeA1efrMa2RqNMih60yw1tn1zGtqG/qbHkmSThD7mlhZuu7raCb1J0kbtN0W3nZ92m4EBNvA8hhJv4aLQ/I6feA1dWTW48IPeR1NNwbeEyf/9w3b3EQ4kiSPbemY8zyx1Q/hps+8xv/T76qw3+iefN+ALQmvpy2JAHOcMDQaY+m6hybYdg4pi5EyP8Q3zaw8ic6upOMN42Uz4Qj2ezzk9abGID2SJB3GEhPEkiaIJV0QS4YglkxBLFmCWLIFseQIYokLYskVxJIniCVfEEuBIJZCQSxFgliKBbGUCGIpFcQySBBLmSCWckEsFYJYKgWxVAliGSyIpVoQyxBBLEMFsQwTxFIjiKVWEEudIJbhglhGCGIZKYhllCCW0YJY6gWxjBHEMlYQS4MglnGCWMYLYpkgiKVREIvp7yc3hcX094abwtIkiKVZEEtkC7OE3fOov0fKLOn+fxuUR8l72iFN71HsgHQaKcN22khZK6TbSdlESHeE1Ed91B6wJZHa0ekj2k6S5LEtei9jhwCWZkEsTYJYfEEsCUEsjYJYJghiGS+IZZwglgZBLGMFsYwRxFIviGW0IJZRglhGCmIZIYhluCCWOkEstYJYagSxDBPEMlQQyxBBLNWCWAYLYqkSxFIpiKVCEEu5IJYyQSyDBLGUCmIpEcRSLIilSBBLoSCWAkEs+YJY8gSx5ApiiQtiyRHEki2IJUsQS6YglgxBLOmCWNIEscQEsUQDLPS7xQQpw+8PfVI2CdJNpGwypOn3m1Mg3UrKpkJ6IimLBvjo81vp95fYl5NIGY61yaQM58IUUoZzFdvX+ZxA3oP3VkI6CTqR2uFTFn3gdbhKUjaJpOsC/DnEvkmEs42Vs+tedMqhj76+y24jLNNYWbruRZ9O6k+SNtoC5Yzt+rTdiNc9hzxSHiPprfGDgNfTNziukFn3YXvI62h6UuA9cfL/dsM2TwswBftTz70pxNb2EO7hhBv/P5lwm5hXbYQjOK9oTKPzm3msdvqvPeA/zNO+zAz4i5+l6/73YNumfN++Ad9jGb6O/sZqDuGLGeacTjiLApz6mEHS+PkV35NDWGYQzpmsnF2xl3Loo6/YO5OwzGZl6Yq9W5H6k6QN2u4c3nZ92i7GXmwDy2MkvZLEozndya/HFTLrPpwV8jqanhF4T5z8f5Zhm2cTjiTJY1t63uxDbJ0Vwl1EuGcFGE3Nq5mEIzivsgkHnd/MY7XTf7MC/sM87ctYwF/8LF2xN9i2Kd/P2oDvsQxfp8dQdX63P/CIEs44M2df8Svu9WaJCWJJE8SSLoglQxBLpiCWLEEs2YJYcgSxRLYwy/p+5wb/HyVleF2c7vPG6/Z0nzd+r5BOyuhzMbAM17WZpAzPEVmkrJikUeP3bjmkLBpiG7LmkjJkzSNlyJpPypC1gJQhayEpQ9YiUoaslB1ZkV23WVTS2yY6JvD9SdCJ1I7OMUHbSZI8tkX3uJcIYMkRxJItiCVLEEumIJYMQSzpgljSBLHEBLFEAyyZwJPFzEPPC/T8hvGNnmvxHEbPtXgOo+daPIfRcy19HhaWFRDbsIy2h5o+ixLLsD16XsX26HkV26PnVWyPnlfRdsqUQdpJgk6kcviJBGWKhbDj0dc6KSPEFvr5NJuTOdF1nYuuT5Nez7UzahNrxRzijwhpI4f4ENPvFne/Fl+n++9L4qc0Ul8u8d2Xgffga7JImtaD7w2m6Zj3oE78P60rcwN8GeR9SdCJ1I5Of2YT1iTJ03n8enE3QyYvQxP1aRrUi2Mo05ztCTomcAwH+0WX5xnwObaLYxjboPH06882GPDJ6/QRjG10fUNjW9i8NGFTNrEpSfJ5pHx9r6HzJczGbGJjTsjr+vJLnPw/ZyPboe+hY9CE36jtSZKnn1nfJ7+/mh3CTGMxlm3MeRPPaVFeuxK21EnPs9RfGSFlmSFl0ZC+oNdisSyN+Bs13TcXJf0SvH5B9x2mkbLg9Qu6bzODlPV1/YKuEUysa7EdrBfz2Fbc6309hJ+l6/uFYNvUDzFjbW+8H4LXgLaEH9KMtb3xfghe9zLBsiE/pAvwAzJkbUE/ZAjwA42jW8oPmQL8gAw5/ewH3W7wsyfrF7J4xAJ1NycmtrQsb2ta7jf7SxJNHUvbWxMtrUsntvvtfmt7635N7c3Ny9tb2ts6lna0JTr8lubl/orWjuYVUHmUkfNJRq7f8nElYmGdQ8q47OdkprzPkDQG/mjImMgwYJMXaCfox3zP8MA30UnPGKj3WY9v8Juy+1n+PqI/zCPep3gwf0Lyn2bkfI6xrv4KfM95ZgLf8yTtAl+KdT4HDuWu9wVPduDTdr/A30dGAx+nT/srCDzlmQkCvyNpFwRSrPMpcCh3vS96soOAtvtF/j5KBAdIoG4/kcJxSpAzhdp+yNg/u6f1m/8SqVh9qhfCuZm1ncbovz3613+JzbX6R956ODejth8z+m/P/vdfYnOsPt3rg3MTazuD0X97bRn/JTbV6jO9DXBuQm1nMfpv0ZbzX2JTrD7b2wjOjaztHEb/7b1l/ZfYWKvP9TaScyNqO4/Rf/tsef8lNsbq871N4NxAbRcw+m9fGf5LbMjqn3ibyNlHbRcy+m+xHP8l+rL6Im8zONdT28WM/lsiy3+J9Vn9U28zOUNqu4TRf0vl+S8RZvWlXgqcgdouY/TfMpn+SwStvtxLkZPUdgWj//aT678EtfpKj4ETaruK0X/LZfsvgVZf7TFxqtquYfTfCvn+04d/LWNd9JpTqv7b3xL/MV4n8vdk9N8BlviP8TqHv4jRfyst8R/j53R/H0b/fcMS/zF+zvQXM/rvQEv8x/g5yV/K6L9VlviPcZ3v78fov4Ms8R/jOtVfwei/1Zb4j3Gd5R/A6L+DLfEf4zrB/waj/w6xxH+M5zl/FaP/DrXEf4xx2l/N6L/DLPEfY5zxD2H03+GW+I9xnviHMfpvTT/5L1XO3zP2BeOY8df03/hLaf/V9R7f/qsbGPv1DEv2X93o8e2/uonRf2dasv/qZx7f/qubGf13liX7r27x+PZf3crov7Mt2X/1c49v/9VtjP47x5L9V7/wNoJzI2u7ndF/51qy/+qX3kZybkRtdzD67zxL9l/9ytsEzg3Udiej/863ZP/Vr71N5OyjtrsY/XeBJfuv7vY2g3M9td3D6L+fWLL/6l5vMzlDaruP0X8XWrL/6n4vBc5AbQ8w+u8iS/ZfPeilyElqe4jRfxdbsv/qYY+BE2p7hNF/P7Vk/9WjHhOnqu0xRv9dYsn108cZ6zqD8frppZb4j/E6kX8Wo/8us8R/jNc5/HMY/Xe5Jf5j/Jzun8fovyss8R/j50z/Akb/XWmJ/xg/J/kXMvrvKkv8x7jO9y9m9N/VlviPcZ3qX8Lov2ss8R/jOsu/jNF/11riP8Z1gn8Fo/+us8R/jOc5/ypG/11vif8Y47R/DaP/brDl/iNG/13H6L8bLfEf4zzxb2D0302W7L96ibEvGMeMz+k//Zwu/eA1fA633nOmf5flOtAvgX4C9G9A6+NlJX/wup71RX+34Gl4zcvkta8o+aPX8+Dur1cZ+8vG/XKp+u+1ATjeXw2M99f6GO+vK3mjj/H+Onntn5T8OeS1T8Jr/gRaPxDxTSV/CXntU/CaN0Hr/n5LydtezyPKPA44nwX4V8Yxhf7B30woA7+Ug64AXQm6CvRg0NWgh4AeCnoY6BrQtaDriP6bkr+Dr6PE99zPOfwbX12JGqjnH0reUfKukn8qeU/J+0o+UPIvJR8q+UjJv5X8R8nHSv6r5BMl/1PyqZLPlHyu5AvwyVdgfERJVElMSZqSdCUZSjKVZCnJhh9/ioDfNEuW151/J5B/N5D/ZyD/XiD/fiD/QSD/r0D+w0D+o0D+34H8fwL5jwP5/wbynwTy/wvkPw3kPwvkPw/kvwjkvwzkvwrkdYLmI4F8NJCPBfJpgXx6IJ8RyGcG8lmBfHak+7c98OBe59I5k2q8+gdjXU8KP+8vX6GPhP8OU126L95l9N9T4v3XWbX/z9TragKb/fcY/fe0ZP+1fM3pv59aXQlis/8Bo/9+K9V/TT04/X9tfl2JgM3+h4z+e0ag/yau6MXpf7R5dbWH2Oz/m9F/z0rzX3sop/+fTa+rbT02+x8z+u85Sf5rWy+n/99Nq6upD5v9Txj997wU/7X1yen/b+PrWrYBm/1PGf33ggT/tW2Q0/9s4+pKbITN/ueM/vvdlvZfYqM4/S82XFfrRtrsf8novxe3pP9aNprT/6rPulpWbILNvv7gyeW/328p/7VtEqcfWb/N7Ztosx9l9N9LW8B/HSs2mdOPhduc2Ayb/TRG/73c3/5LbBann97bZn8zbfYzGP33h/70336bzeln9rS5OQWb/SxG/73ST/5rWpESp58d4buW+CTj99x/tGSfAON1Nv9pRv+9aon/GK8T+c8w+u81S/zHeJ3Df47Rf69b4j/Gz+n+C4z+e8MS/zF+zvRfZPTfnyzxH+PnJP8lRv/92RL/Ma7z/T8w+u9NS/zHuE71/8jov79Y4j/GdZb/GqP/3rLEf4zrBP8NRv+9bYn/GM9z/p8Z/fdXS/zHGKf9vzD672+W+I8xzvhvM/rv75b4j3Ge+Ixjxuf0XwT8VgP14b423O+G++Bwfxzum8P9dLjP7uv9d7gvDjTu48P9fbjvD/cD4j5B3D+I+wpxvyHuQ8T9ibhvEfcz4j5H3P+I+yJxvyTuo8T9lbjvEvdj4j5N3L9ZA37IUfxxJblK8pTkKylQUqikSEmxkhIlpUoGKSlTUq6kQkmlkiolg5VUKxmiZKiSYUpqlNQqqVMyXMkIJSOVjFIyWkm9kjGwr5TynAL5H4I+FfRpoH8E+segTwd9BugzQZ8F+mzQ54A+F/R5oM8HfQHon4C+EPRFoC8G/VPQl4C+FPRloC8HfQXoK0FfBfpq0NeAvhb0dQE/XA/5G0DfCPom0D8DfTPoW0DfCvrnoG8D/QvQt4P+Jeg7QP8K9J2gfw36LtB3g74H9L2g7wN9P+gHQD8I+iHQD4N+BPSjoB8D/TjoJ0AnwQ/DIT8C9EjQo0CPBl0PegzosaAbQI8DPR70BNCNoBOgfdBNoJtBt4BuBT0RdBvodtAdoCeBngx6CuipoKeBnk7s1XoG6JmgZ4GeDXor0HNAbw16G9Dbgt4O9PagdwC9I+idQM8FPQ/0zqDng94F9ALQC0HvCno30LuD3gP0nqD3Ar0I9N6g9wG9L+jFoJeAXur1jlM6HwedCzoPdD7oAtCFoItAF4MuAV0KehDoMtDloCtAV4KuAj0YdDXoIaCHgh4GugZ0Leg60MNBjwA9EvQo0KNB14MeA3psxOtxYDYJOpHa4Y9l/N4pRvhMMg/1eNcHeDSQTBroKPk/rr8yDNjkBdoJ+jE/pIy1cROd1BDhr3cc44A1Zfe4CHsfdU6umNf7kDy5THJWWcJZ5vEHqwipc7zKTFDSqES/QN9t16SkWUmLklYlE5W0KWlX0qFkkpLJSqYomapkmpLpel4pmaFkppJZSmYr2UrJHCVbK9lGybZKtlOyvZIdlOyoZCclc5XMU7KzkvlKdlGyQMlCJbsq2U3J7kr2ULKnkr2ULFKyt5J9lOyrZLGSJUqWKlmmZD8ly5WsULK/kgOUrFTyDSUHKllF5lkB6Gyvd/DOJnMnQspocNdHBkknmfrMwMkioW+CzSJ2eAF788GWDNZ2WxK6rXSv5xE8KSVD/Nm5AIP0siWrVs07bOURS9Ysn7N29bI1Kw9eTYd1eqCaWIh5wfI04opMSKeTMnxfJtGRIH8SdKrnFHp+SqR2+P0V8xsjZmKpx8vZZLBunw6ug8DBq8ngxnkW9boHVAbpD+wnPRi/8nr3VYSko/CaWB+viaynHjrf8f0435l9YiR2GV3IRsC5ugO/8LrvZl0d6d0o99XURoaFadednStWHMS4yF3NOLn7KyAlXEDqEZAOBgcf4gKSnQHp4EBAOqQfAlKCMSAdzBiQDrEwIPkuIPUISIeCgw9zAcnOgHRoICAd1g8ByWcMSIcyBqTDLAxIrS4g9QhIh4OD17iAZGdAOjwQkNb0Q0BqZQxIhzMGpDUWBqSJLiD1CEhrwcFHuIBkZ0BaGwhIR/RDQJrIGJDWMgakIywMSG0uIPUISEeCg49yAcnOgHRkICAd1Q8BqY0xIB3JGJCOsjAgrXIBqUdAOhocfIwLSHYGpKMDAemYfghIqxgD0tGMAekYQ5Ob2390e1eqNo9n9N83mQN6r8Hv8Qd0TmbKeyzJuH2oKdapO+nYCH+9xzEOflN2Hxdh76MewSkaqJtz71SqdR0fkT0udd8cH+Hff5aVbseJiLOv1zH2NfWfLTdErDN0IjrBnYh4O+kEAyeiE4WfiLTdJxo+EUn3qUcGMicnvQkiVc4JjDZ/y8LV/LcMBdGTXBDl7aSTDATRbwsPotrubw/g1fx3hK/mdd98x8BqPmcAruZPZuzrHAtX8ycbOhF9152IeDvpuwZORN8TfiLSdn/PstU8t089MpA5OemtwqlytjPa/H0LV/PfNxREf+CCKG8n/cBAED1FeBDVdp8ygFfzPxS+mtd980MDq/ncAbiaP5Wxr3MtXM2fauhEdJo7EfF20mkGTkQ/En4i0nb/yLLVPLdP8eA+YR7DyPnjiJnJK3mRcLrwRYLuk9MNLBLyB+Ai4QzGvs63cJFwhqFFwplukcDbSWcaWCScJXyRoO0+y7JFwlmWLBLWMHKePQAXCecIXyToPjnHwCKhcAAuEs5l7OtCCxcJ5xpaJJznFgm8nXSegUXC+cIXCdru8y1bJJxvySLhCEbOCwbgIuEnwhcJuk9+YmCRUDwAFwkXMvZ1sYWLhAsNLRIucosE3k66yMAi4WLhiwRt98WWLRIutmSRcBQj508H4CLhEuGLBN0nlxhYJJQOwEXCpYx9XWrhIuFSQ4uEy9wigbeTLjOwSLhc+CJB2325ZYuEyw0tEoJBNNW6o4w2NzHafAVjQOqvIHqFoSB6pQuivJ10pYEgepXwIKrtvspwEJW8mr9a+Gpe983VBlbzZQNwNX8NY1+XWbiav8bQiehadyLi7aRrDZyIrhN+ItJ2X2fZap7bpx4ZyJQz1boZf6rVb2a0+XoLV/PXGwqiN7ggyttJNxgIojcKD6La7hsH8Gr+JuGred03NxlYzVcMwNX8zxj7usLC1fzPDJ2IbnYnIt5OutnAiegW4Scibfctlq3mOX2q2fQEwQmkn5n3pdf1+8JaHwL6MNA5Sm5V6Z/DWKE/yt4Er2kG3QJ6DegjQB8FukjJbSr9i5C69oPXLAe9AvT+oA8AvRJ0rpLbVfqXpC7shNvgNe2gO0BPAj0Z9BTQU0FPAz0ddBL0DNAzQc8CPRv0VqDngN4a9DagtwW9HejtQe8AekfQO4GeC3oe6J1Bzwe9C+gFoBeC3hX0bqB3B70H6D1B7wV6Eei9Qe8Del/Qi0EvAb0U9DLQt4P+BugDQY9VcodK/4r0DQbn8fCaW0HfAbpYyZ0q/etAFJW8qLuL8UTfXyfnYZ6Zk/Pd7uTM20l3Gzg53yP85KztvsfAybm/fh+Hc3KZ5BxsCWe5xx+sIqTOe1XmPiX3K3lAyYNKHlLysJJHlDyq5DEljyt5QslvlDyp5CklTyv5rZJnlDyr5Dklzyt5QcnvlLyo5PdKXlLyspI/KHlFyR+VvKrkNSWvK3lDyZ+U/FnJm0r+ouQtJW8r+auSvyn5u5J/KHlHybtK/qnkPSXvK/lAyb+UfKjkIyX/VvIfJR8r+a+ST5T8T8mnSj5T8rmSL/RJl8yzAtD6N4OCwTvb6/37Q9lez+CuD1t+V0h9oPayiB1ewF78jaQM1nZbErqtdK/nETwpJUP8qVlLIL1syapV8w5becSSNcvnrF29bM3Kg1fTYZ0eqCYWYl6wPI24IhPS6aQM35dJdCTInwSd6jnlHuYFVX/E/PsjZmKpx8vZb7+J9hU6mBS630TjqbNffhNNdyD9TTT9J9go9+XX+xkWpvibaF9xLnKj9i1CH3ABqUdAikAm6gKSnQFJdyANSNF+CEgPMAakSJQvIEUtDEgPuoDUIyDFIJPmApKdASkWCEhp/RCQHmQMSDHGgJRmYUB61AWkHgEpHTIZLiDZGZDSAwEpox8C0qOMASmdMSBlWBiQHnMBqUdAyoRMlgtIdgakzEBAyuqHgPQYY0DKZAxIWRYGpMddQOoRkLIhk+MCkp0BKTsQkHL6ISA9zhiQshkDUo6FAelLF5B6BKQ4ZHJdQLIzIMUDASm3HwLSl4wBKc4YkHKjZiY3t//o9q5Ubb6X8VvKPOaA3mvwe/wBnZOZ8uaTgOj2oaZYp+6k/Ch/vQWMwcOU3QVR9j4yerci597ewqjscan7pjDKv/+sypK7FTn7uoixr6ssvFuxyNCJqNidiHg7qdjAiahE+IlI211i+EQk3aceGcicnPQmiFQ572MMyKUWruZLDQXRQS6I8nbSIANBtEx4ENV2lw3g1Xy58NW87ptyA6v56gG4mq9g7OtqC1fzFYZORJXuRMTbSZUGTkRVwk9E2u4qy1bz3D71yEDm5KS3CqfK+QRjQB5s4Wp+sKEgWu2CKG8nVRsIokOEB1Ft95ABvJofKnw1r/tmqIHV/NABuJofxtjXQy1czQ8zdCKqcSci3k6qMXAiqhV+ItJ211q2muf2KR7cJ8xcRs66qJnJK3mRMFz4IkH3yXADi4SaAbhIGMHY1zUWLhIY7e+xSBjpFgm8nTTSwCJhlPBFgrZ7lGWLBG6f4sF9wsxg5Bw9ABcJ9cIXCbpP6g0sEuoG4CJhDGNf11m4SGC0v8ciYaxbJPB20lgDi4QG4YsEbXeDZYsEbp/iwX3CzGLkHDcAFwnjhS8SdJ+MN7BIGDEAFwkTGPt6hIWLBEb7eywSGt0igbeTGg0sEhLCFwna7oRliwRun+LBfcLMYeT0B+AioUn4IkH3SZOBRcKoAbhIaGbs61EWLhIY7e+xSGhxiwTeTmoxsEhoFb5I0Ha3WrZI4PapRwYy5Uz50duMNj/EGJAnMgak/gqiEw0F0TYXRHk7qc1AEG0XHkS13e2Gg6jk1XyH8NW87psOA6v5+gG4mp/E2Nf1Fq7mJxk6EU12JyLeTpps4EQ0RfiJSNs9xbLVPLdPPTKQKWfKt1Yw2vwwY0CeauFqfqqhIDrNBVHeTppmIIhOFx5Etd3TB/BqPil8Nd85fgys5scOwNX8DMa+Hmvhan6GoRPRTHci4u2kmQZORLOEn4i03bMsW81z+lSz6QmCE+g+VfClTkS7dBR0GugcJbNVeisYK/RH2R+C9z4M+hHQGfDeLKwDdJGSOSq9dUhdH8N7/wv6E9D/A/0p6M9A5yrZRtWzLakLO2EOtPcEvPY3oJ8E/RTop0H/FvQzoJ8F/Rzo50G/APp3oF8E/XvQL4F+GfQfQL8C+o+gXwX9GujXQb8B+k+g/wz6TdB/Af0W6LdB/xX030D/HfQ/QL8D+l3Q/wT9Huj3QX8A+l+gPwT9Eeh/g/4P6G3Az59D/gvQY5Vsp/63PekbDM73wmtmw3u3A12sZAeV3jHa9dqN+TmLlHeSRsycILwAZ2LTDj9YwFh3r7boCXQnyMwlhe7nLHjq7Jefs9AdeA80pPNzyYkj6Dws55xEm1hXIlCXvxPjiW4u4yq8v35fJxXmFT2PZSG4RgISd1C+J2ImuM2DzM6bGdxmhtgcDG4zvQ0Ht7B6/l8FN8kDAgPjvGh3x+i8HhQzvJ4Hd6DktGNnxkA5P8oXGNCf84k/TYyHudGU+yd48mnl7J+5jP0zjvkSWoqTv1efa7/hfOLs5/Gy7A4enZcMdzZg94R+umSa6mJtHuMY54xnjZZccmac1/54xsvECUv8xzhPfMYx46fiv74W8dHU5m+vfuacv7swftgyaTPn1zwLmG3mPj/pPllg4Pw0cQB+pbeQsa8nWviVHqP9Pb7S2zXanXZf6aVYp+6kXaP89e7GeKIwZfduUfY+MvqVnnSf3qkqvCvCf/LYPdo//ZMq5x6WcO5pCedejJzq/Nl5ssAThh5Tur+0L/aiZw+PfwE5jnFRsYhxUUH9QQ+u+tc3LhKpHf4iA+OXm3EHS+bY3oychseTsb7a24LxtI+h8ST5w/K+wj8sm1rvLLYkdiyx51xkbF4usSB2LB2AsWMZc+xYX9+kyrkfH2eTrXNoPwvm0PIBOIdWWDKH9ufjbLZ1Du1vwRw6YADOoZWMc6i/LtzX8NXV48L9N6LdaXfhPsU6a8Ch3PUeKPwis7b7QAMX7vtru26NZyYIcnNWW8JZ4fEHK61zIb1KjbWDlKxWcrCSQ5QcquQwJYcrWaNkrZIjlBxJxmUBaL1NNxjssr3eW36zvZ7BUB+2bOXVF9eziB1ewF7clpzB2+4y3Va61/MIBvFkiD81ayWkl68+dO3ytcvnrV26auWyOWtXL1uz8uDVs5asWkUHAzaCgyIWYmSwPI04JBPS6aQM35dJtLH90AcyL0P6I1KuNrRc9Hg5mwzW3eNmhKMgczQpdHda8dTZL3da6Q78wuu+geDoaO9GuTc0rWZYzi2HnYVHMS4Nj2ac3P0VkA52AalHQDoGMt90AcnOgHRMICB9sx8C0sGMAekYxoD0TQsD0iEuIPUISMdC5jgXkOwMSMcGAtJx/RCQDmEMSMcyBqTjLAxIa1xA6hGQjofMOheQ7AxIxwcC0rp+CEhrGAPS8YwBaZ2FAWmtC0g9AtIJkDnRBSQ7A9IJgYB0Yj8EpLWMAekExoB0ooUB6QgXkHoEpG9B5iQXkOwMSN8KBKST+iEgHcEYkL7FGJBOMjS5uf1X4/HZvIrRf99mDui9Br/HH9A5mSnvd0hAdJulUqxTd9J3ovz1nsw4+E3ZfXKUvY+M7r7k3ID23ajscan75rtR/u0e7ZY8boOzr7/H2NftFj5ug9H+Hiei77sTEW8nfd/AiegHwk9E2u4fGD4RSfepRwYyJyfdqZsq50GMNp9i4Wr+FENB9IcuiPJ20g8NBNFThQdRbfepA3g1f5rw1bzum9MMrOYnDcDV/I8Y+3qShat5Rvt7nIh+7E5EvJ30YwMnotOFn4i03adbtprn9qlHBjInJ72fLVXOIxltPsPC1fwZhoLomS6I8nbSmQaC6FnCg6i2+6wBvJo/W/hqXvfN2QZW81MG4Gr+HMa+nmLhap7R/h4nonPdiYi3k841cCI6T/iJSNt9nmWreW6f4sF9wlzHyHl+1MzklbxIuED4IkH3yQUGFgnTBuAi4SeMfT3NwkUCo/09FgkXukUCbyddaGCRcJHwRYK2+yLLFgncPsWD+4R5IiPnxQNwkfBT4YsE3Sc/NbBISA7ARcIljH2dtHCRwGh/j0XCpW6RwNtJlxpYJFwmfJGg7b7MskUCt0/x4D5hnsTIefkAXCRcIXyRoPvkCgOLhJkDcJFwJWNfz7RwkcBof49FwlVukcDbSVcZWCRcLXyRoO2+2rJFArdPPTKQKWeqdUcZbT6U0eZrGANSfwXRawwF0WtdEOXtpGsNBNHrhAdRbfd1hoOo5NX89cJX87pvrjewmp89AFfzNzD29WwLV/OM9vc4Ed3oTkS8nXSjgRPRTcJPRNrumyxbzXP71CMDmXKmWncNo82HMdr8MwtX8z8zFERvdkGUt5NuNhBEbxEeRLXdtwzg1fytwlfzum9uNbCanzMAV/M/Z+zrORau5hnt73Eius2diHg76TYDJ6JfCD8Rabt/YdlqntOnmk1PEJxA+nE4X3pdv9Sl9TdBHwc6R8ntKv1LGCv0Rw4PhdccBvpw0OtAnwj6JNBFSu5Q6V/RWevxn3TujPZPv6bK+WtLOO9iDuh6/GCwvhPGxq9B3wVaP5n4bpW+x/BYudeSPrjPEs77DY6Ve2Fs3Af6fjJWHlDpBw2PlYcs6YOHLeF8xOBYeQjGxsOgHyFj5VGVfszwWHnckj54whLO3xgcK4/D2HgC9G/IWHlSpZ8yPFaetqQPfmsJ5zMGx8rTMDZ+C/oZMlaeVennDI+V5y3pgxcs4fydwbHyPIyNF0D/joyVF1X694bHykuW9MHLlnD+weBYeQnGxsug/0DGyisq/UfDY+VVS/rgNUs4Xzc4Vl6FsfEa6NfJWHlDpf9keKz82ZI+eNNAH6Br/ww+fxN0lpK/qPRbhn3/tiW+/6tB378NPv8r8f3fVPrvhn3/D0t8/45B3/8DfP4O8f27Kv1Pw75/zxLfv2/Q9++Bz98nvv9Apf9l2PcfWuL7jwz6/kPw+UfE9/9W6f8Y9v3Hlvj+vwZ9/zH4/L/E95+o9P8M+/5TS3z/mUHffwo+/4z4/nOV/sKw77+0xPdfGfT9l+Dzr4jv9YeASMys76MxO3wfs4QzzRLOdEs4MyzhzLSEM8sSzmxLOHMs4YxbwplrCWeeJZz5lnAWWMJZaAlnkSWcxZZwlljCWWoJ5yBLOMss4Sy3hLPCEs5KSzirLOEcbAlntSWcQyzhHMrIidfMGqG+O+Ba2ZGg9bUsrWOg00Cng74bXvcA6EdBPwn6WdAvgn4F9Bug/wL6b6DfBf0B6H+D/gT056A9aD8DdCboLNDZoHNAx0Hngs4DnQ+6AHQh6CLQxaBLQJeCHgS6DHQ56ArQlaCrQA8GXQ16COihoBuUDFPpmlj3fSJ4mXIV2Hw76GHIpqRWpesC1zOjzOON8+a+4Xxj1++vG/JqPd75hscI0m/uhrwU66wFh3LXOzLGN/hN2T0yxt5HnXe7xrzeh+TJZZJziCWclR5/sNI6F9Kj1KAYraReyRglY5U0KBmnZLySCUoalegB5JMBVABab7ILBrtsMtYipIwGQ31kkHSSyUYDwTWR7sGXjWCHF7A33+t5IyhTu8t0W+lezyMYxJMh/tSslZBevvrQtcvXLp+3dumqlcvmrF29bM3Kg1fPWrJqFR0M2AgOiliIkcHyNOKQTEinkzJ8XybRkaAVSdCpRuKRzMuQ/oiU9YY+nni8nE0G6/bp4GoCpzcT5+Nsi3rdAyqD9Ae+VA/Gr7zefRUh6Si8JtbHayLrqYfOenw/znpmnxiJYEaXfxFwru7AL6AhnW+O9W6U+0El9QzLueUruo4mxqVhM+Pk7q+ANMYFpB4BqQWc3uoCkp0BqSUQkFr7ISCNYQxILYwBqdXCgDTWBaQeAWkiOL3NBSQ7A9LEQEBq64eANJYxIE1kDEhtFgakCS4g9QhI7eD0DheQ7AxI7YGA1NEPAWkCY0BqZwxIHRYGpEYXkHoEpEng9MkuINkZkCYFAtLkfghIjYwBaRJjQJpsYUBKuIDUIyBNAadPdQHJzoA0JRCQpvZDQEowBqQpjAFpqqHJze2/Wo/P5lGM/pvGHNB7DX6PP6BzMlPe6W6zFG8nTTewWSopfLNU5+A0sFnKI0c0UDfnVoVU65oRkz0udd/MiPFv99jGkp/R4OzrmYx9vY2FP6Mx09CJaJY7EfF20iwDJ6LZwk9E2u7Zhk9E0n3qkYHMyUl36qbKOZrR5q0sXM1vZSiIznFBlLeT5hgIolsLD6La7q0H8Gp+G+Gred032xhYzW83AFfz2zL29XYWrua3NXQi2s6diHg7aTsDJ6LthZ+ItN3bW7aa396S1Ty9ny1VTp/R5h0sXM3vYCiI7uiCKG8n7WggiO4kPIhqu3cawKv5ucJX87pv5hpYze8wAFfz8xj7egcLV/PzDJ2IdnYnIt5O2tnAiWi+8BORtnu+Zav5+YZW89wnzA5Gzl1iZiav5EXCAuGLBN0nCwwsEnYagIuEhYx9vZOFi4SFhhYJu7pFAm8n7WpgkbCb8EWCtns3yxYJu1mySJjMyLn7AFwk7CF8kaD7ZA8Di4R5A3CRsCdjX8+zcJGwp6FFwl5ukcDbSXsZWCQsEr5I0HYvsmyRsMiSRcJURs69B+AiYR/hiwTdJ/sYWCTMH4CLhH0Z+3q+hYuEfQ0tEha7RQJvJy02sEhYInyRoO1eYtkiYYmhRUIwiKb8S6yMNjcw2rzUws1DSw0F0WUuiPJ20jIDQXQ/4UFU273fAN48tFz4al73zXIDq/kFA3A1v4KxrxdYuJpfYehEtL87EfF20v4GTkQHCD8RabsPsGw1f4Alq/laRpvHMdq80sLV/EpDQfQbLojydtI3DATRA4UHUW33gQN4Nb9K+Gpe980qA6v5XQfgav4gxr7e1cLV/EGGTkSr3YmIt5NWGzgRHSz8RKTtPtiy1TynTzWbniA4gfTjcPQvDzeDbgXdBjpHySEqfSiMFfojhw3wmnGgx4PuAD0Z9FTQRUoOU+nDY57Xl79StXFNrH/6NVXOtZZwHsEc0OkvYa+BsbEW9BGg9ZOJj1TpowyPlaMt6YNjLOH8psGxcjSMjWNAf5OMlWNV+jjDY+V4S/pgnSWcJxgcK8fD2FgH+gQyVk5U6W8ZHisnWdIH37aE8zsGx8pJMDa+Dfo7ZKycrNLfNTxWvmdJH3zfEs4fGBwr34Ox8X3QPyBj5RSV/qHhsXKqJX1wmiWcPzI4Vk6FsXEa6B+RsfJjlT7d8Fg5w5I+ONMSzrMMjpUzYGycCfosMlbOVulzDI+Vcy3pg/Ms4Tzf4Fg5F8bGeaDPJ2PlApX+ieGxcqElfXCRgT7AC84Xgs8vAp2l5GKV/qlh319iie8vNej7S8DnlxLfX6bSlxv2/RWW+P5Kg76/Anx+JfH9VSp9tWHfX2OJ76816PtrwOfXEt9fp9LXG/b9DZb4/kaDvr8BfH4j8f1NKv0zw76/2RLf32LQ9zeDz28hvr9VpX9u2Pe3WeL7Xxj0/W3g818Q39+u0r807Ps7LPH9rwz6/g7w+a+I7+9U6V8b9v1dlvj+bks477GE815LOO+zhPN+SzgfsITzQUs4H7KE82FLOB+xhPNRSzgfs4TzcUs4n7CE8zeWcD5pCedTlnA+bQnnby3hfMYSzmct4XzOEs7nLeF8wRLO31nC+aIlnL+3hPMlA9fMGqG+w+BamQ/6LtB3g74H9L2gjwR9LOgTQZ8M+hTQPwZ9NugLQF8M+jLQV4G+DvRNoG8FfTvoO0HfB/p+0A+AfhD0Q6AfBv0I6EdBPwb6cdBPgP4N6CdBPwX6adC/Bf0M6GdBPwf6edAvgP4d6BdB/x70S6AblLys0n+Idd8ngpcpR8FrDgH9MuhiJa+o9B9jXa+Neb0P7rF3YJRt7PkhuJtbtx8sYKy7V1tRUuer4PTXiPOzQUe97mvRGaQ/8KX6HqKvvN59FSHpKLwm1sdrIuupJ5uU4fvzCQujTxIGbhpMGL0pMALO1R14DzSk86+R4Bp0HpZzTqJNrCsRqMt/NcbH9RrficXf2ICUSO3wU2Fe0fNYFoJrJCBxB+WRMTPB7XXowDc2M7jNDLE5GNxmehsObmH1/L8KbpIHBAbG12PdHaPzelDM8Hoe3IGS0443GAPln2J8gQH9+SfiTxPj4bVYyv0TPPm0cvbPa4z9szvzYzNSnPy9+lz7DecTZz/vIcvu4NH5mJA3DNi9Zz89JiXVxdrrjGOcM57tZcljZhjntb8H46NhFlniP8Z54jOOGT8V//W1iI+mNn979TPn/P0z47nTpM2cj3Z6k9lm7vOT7pM3DZyflg7Ax3j9hbGvl1r4GC9G+3s8xust8mHcPcYrxTp1J70V46/3bcaJZMrut2PsfWT0MV7SfVqr+IYbOHn81ZKvJf9mCeffLeH8ByOnOn96WvCEoceU7i/ti38ELtNzLyBT+LajV13vMC4q0sAnwYOr/vWNi0Rqh/+OgfHLzfiKJXPsXUZOw+PJWF+9a8F4+qeh8ST5w/J7wj8sm1rvvG9J7PjAnnORsXn5gQWx418DMHZ8aOjiIvcc+oiPs8nWOfSRBXPo3wNwDv3Hkjn0MR9ns61z6GML5tB/B+Ac+sSSOfQ/S9acn1rC+ZklnJ8zc3LHjBdVHa8YsHs/4RuF3lJ1/NWA3ctlbhTqxfkFY9xk7GvflP+4+/lLS+LPV5Zw6i8ObOCMWMIZtYQzZglnmiWc6ZZwZljCmWkJZ5YlnNmWcOZYwhm3hDOXmZP788A9qsLFUX67DxD+OWgfZfO+BuxeacnnoDy+cekz9rW/Uvi4WarGzDID4yZfeJxYrmxeYcDuAuF2H6BsXmnA7kLhdutr1e8b2IOwSvj81vth3jNg90GWnBeKGM8LjH3tHyR83Oi9EB8aGDfFwuOE/v76PwbsLhFut/7O8RMDdpda8rlmkCWcZZZwllvCWWEJZ6UlnFWWcA62hLPaEGc0wJlI7eh8+AuXzUMssTnKaPNQS2yOMdo8zBKb0xhtrrHE5nRGm2stsTmD0eY6S2z+PqPNwy2x+X+M+xZHWGLzp4w2j7TE5s8YbR5lic2fM9o82hKbv2C0ud4Sm79ktHmMJTZ/xWjzWEtspvvpUrW5wZbPkow2j7PlsySjzeNt+SzJaPMEWz5LMtrcaMtnSUabE7Z8lmS02bfE5kxGm5sssTmL0eZmS2zOZrS5xRKbcxhtbrXE5jijzRMtsTmX0eY2S2zOY7S53RKb8xlt7rDE5gJGmydZYnMho82TLbG5iNHmKZbYXMxo81RLbC5htHmaJTaXMto83RKbBzHanLTE5jJGm2dYYnM5o80zLbG5gtHmWZbYXMlo82xLbK5itHkrS2wezGjzHEtsrma0eWtbrnt6fDZvY8t1T0abt7XluiejzdvZct2T0ebtbbnuyWjzDrZc92S0eUdbrnsy2ryTLdc9GW2ea8t1T0ab59ly3ZPR5p1tue7JaPN8W657Mtq8iy3XPRltXmDLdU9Gmxfact2T0eZdDdi8FDT+MLe+Nwqfi63vJdGfC/XnJP25Qa+j9bpSr7P0ukOfh/V5ScdpHbf0PNbjWveztrtMSbmSCiWVSqqUDFZSrWSIkqFKhimpUVKrpE7JcCUjlIxUMkrJaCX1SsYoGaukQck4JeOVTFDSqH2hRD8wuUn7WEmLklYlE5W0KWlX0qFkkpLJSqYomapkmpLp0D8zlMxUMkvJbCVbKZmjZGsl2yjZVsl2SrZXsoOSHZXspGSuknlKdlYyX8kuShYoWahkVyW7KdldyR5K9lSyl5JFSvZWso+SfZUsVrIE+mIS9Ie+f1DfT6fvL9P3W+n7j/T9OPr+FH2/hr5/Qe/n1/vb9X5vvf9Z7wfW+2P1flG9f1LvJ9T76/R+M73/Su9H0vtz9H4VvX9D72fQ3+/r77v197/6+1D9/aD+vkx/f6S/T+n8fkGJvv6sr8fq65P6ep2+fqWv5+jrG/rzvv78qz8P6s9H+vOCXj/r9aReX+n1hj7/6vORjs86Xun5q8fz/wHZO7hDii0HAA==", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_account_contract.json index e0c115ab7be..3f06e562e6f 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_account_contract.json @@ -141,7 +141,7 @@ } ], "returnTypes": [], - "bytecode": "H4sIAAAAAAAA/+1dB3hcNfJ/u+u+Lonj2Omx03t2XWKnkGwKSQghnRDSCw4EQmgJvbej96P33nvvvfdeDjg4juM42nFwd3CUv+TM4Fn5xRB2tBn99+n75htJuyv9ZkYazb6np3dWluf9HPGaUkhRWFEW5LGcbZRzIJ+9/mdN39epXFGFog6KOpLf4eedFHVW1EVRV/g8TD7vpqi7okpFVaS/norySLmXUe5tlPsY5b5GuZ9R7m+UBxjlgUZ5kFEebJSHGOWhRjlmlONGudoo1xjlWqNcZ5SHGeV6o9xglIcb5RFGeaRRHmWUNzPKo43yGKOcMMpjjfI4ozzeKE8wypsb5YlGeZJRnmyUtzDKU4zylkZ5qlHeyihPM8rTjfIMozzTKM8yyrON8hyjvLVRnmuUtzHK84zytkZ5vlFeYJQXGuVFRnmxUV5ilJca5WVGeTmUtX/QrinhrU/aD+i5r+e7nuN6Xvfz1s9fPWf1PNVzU89HPQf1vNNzTc8vPaf0PNJzR88XPUf0vNBzQY9/Peb1ONdjW49nPYbHQN96fOoxqcehHnt6vOkxpseVHkt6/Ogxo8eJHht6POgxMB1sPRNsOhtstzXYaBuwxbag8wWg20WgwyWgq2WgE60f7XsrQR/a3/7krfe5mncA3hF4J+CdgXcB3hV4N+DdgVcCrwLeA3hP4L2A9wbeB3hf4P2A9wc+APhA4IOADwY+BPhQ4DHgceDVwGuA1wKvI+2tULSdj26GwXfqgTcAHw58BPCRwEcB3wz4aOBjgCeAjwU+Dvh44BOAbw58IvBJwCcD3wL4FOBbAp8KfCvg04BPBz4D+Ezgs4DPBj4H+NZEN42KVnrJKQQ8AbwmNqy2trG+ujFeE18Wqx6+vKEuVlu3fFhDvCFe11C3XXVDTU1jQ21D/fDlw+tjw+O1NY3xlXXDa1bG1qftSVuxFJNNnDs4gnOVIzh3dATnTo7gXO0Izp0dwbnGEZy7OIJzV0dw7uYIzt0dwbmHIzjXOoJznSM493QE516O4NzbEZz7MOI0/5Pp/7z6v8k2wOcB3xb4fOALgC8Evgj4YuBLgC8Fvgz4cuDbA98B+CrgOwLfCfhq4DsDXwN8F+C7At8N+O7A9wC+Fvg64HsC3wv43sD38Zr/k+2raD8vOXHbcH/PjbF2gCM4D3QE50GO4DzYEZyHOILzUEdwHuYIzsMdwXmEIziPdATnHxzBeZTHH6O1gfb09XQdqzQC3xf4/sAPAH4g8IOAHwz8EOCHAj8M+OHAjwB+JPA/AD/Ka46RjlZ0jLf+3k+ut+GU4NFB3F7btTUW26612HadxbaHWWy73mLbDTmkzWOBHwf8eOAnAD8R+EnkN5Oi63m+t/7+pk7Ypq7DsZ5N6vDzLFKHn0dIHX4eJnX4eYjU4eee0b9OCeCxFFOO19LnxVJMWua2RA7PR96Qj17CPvrDz7N99EftgZ+jXYoVRX36ziGYEjzyxkNeckqQPPZFsUQEYckShCVbEJYcQVhyBWHJE4QltImxUD+GSY/hL8PNn2OsRn0f+kbq+0ohT31fO9Im1pURmbGuPeRzSV055PNIHeJuQ+oKIE/9Neq4lNQVQr4dqSuCfBmpK4Z8e1JXAvlyH3zUhvibBPBYaqnJhrSfBCljXwUEQ7kALHmCsOQKwpIjCEu2ICxZgrBEBGEJ+2Ap48USo77XI5hoSpA89d3tmLHoNkstyNduI+QrJfK1tSAfc5txei2FE2cH3jbrtR0qvN9uhw7EDh2Z5dNtdCJ9IS7sJ0o+zyc4OjHbLkT6xHaxTPH9VqwFDmGNOoS10CGsRQ5hLXYIa8kmxsrfb7zJJ9N+dWrNJ1MsnVmxrF9zujC3qdvoSvCjrIg9Sj7vQmTryoujyb6dvWSdYrkr6TeQn7XfQH4vkD+QP5A/kD+QP5A/kD+QP5A/kD+QP5A/kD+QP5A/kD+QP5A/kF+C/Bva58l8nb3VPWGdfbBEBGHJEoQlWxCWHEFYcgVhyROEJV8QlgJBWKKCsBQKwlIkCEuxICwlgrC0EYSlrSAspYKwtBOEpUwQlvaCsJQLwlIhCEsHQVg6CsJicR/SRmPpIghLaBNj8XuWKJ98HiZ1+L+XPj/UDfL0+aHukKfPD1USObGuCvL0+aEekKfPD/WEPH22pxfk6XNBvSFPnynqA3n67FFfyFeQun6Q70jqUHaqK5S9K6mjZ5NjHcrendSh7JWkDmWvInUoew9Sh/9FepI6/E/Qi9Th2OpN6jBG7kPqMFbtS+owZkRdaBmyI82f43fpmOjn0w7m6djGvhPAY6mlprFN+0mQMvZFn7HqKwBLF0FYOgnC0lEQlg6CsFQIwlIuCEt7QVjKBGFpJwhLqSAsbQVhaSMIS4kgLMWCsBQJwlIoCEtUEJYCQVjyBWHJE4QlVxCWHEFYsgVhyRKEJSIIS9gHi429Dvg/XSf8L92F4EBMvQmOXsw60W309MHRi+DA/nsSHD14cehX+fxyHYTi6EFwYP9VBEclL46m8/i6++CoJDiw/+4ERzdeHE1n93X1wdGN4MD+6Z4c5uuITef89ffB0ZngwP77ExwDeHE0nQk40AfHAIID+8fvbWiPzkBebK1ea/XDEhGEJUsQlmxBWHIEYckVhCVPEJZ8QVgKBGGJCsJSKAhLkSAsxYKwlAjC0kYQlraCsJQKwtJOEJYyQVjaC8JSLghLhSAsHQRh6SgISydBWDoLwtJFEJaugrB0E4SluyAslYKwVAnC0kMQlp6CsPQShKW3ICx9BGHpKwhLP0FY+gvCMkAQltAmxrKhfb34eR9SNwjydM/oYMjT/aZDIF9F6oZCnu5zxRdb0T2y+AKl/qQu7IMZr4sPInV4fXowqcPrxENIHV6vHUrq8LppjNTh9UvE1LTPtaD5c8QTJr+phjzd+4wvbqJ7n2tJm1iHL0rKIXX4giO69xnxUH0g7mpSh/LVkDrUQy2pQ33VkTrU6zAfLHTM4m8SwGOppaYxS/tJkDL2RffrDhOAZYAgLP0FYeknCEtfQVj6CMLSWxCWXoKw9BSEpYcgLFWCsFQKwtJdEJZugrB0FYSliyAsnQVh6SQIS0dBWDoIwlIhCEu5ICztBWEpE4SlnSAspYKwtBWEpY0gLCWCsBQLwlIkCEuhICxRQVgKBGHJF4QlTxCWXEFYcgRhyRaEJUsQloggLGEDC71WHyd1eE2d3kPAa+/0XgNeo6f3JPBaPr13UQ95eo8jbOCj90LoNX20Jb32j2ON3iPAuUDvJeBcxf5z4XvYdwJ4LMWUQ7AHbWZOm/ScGnrvDNdxeu8s6lNX6FNX5FNX7FNX4lNHMSDHzwtIHc6pKKnDOVVI6nBOFZE6nFPFpA7XZ8SE84z5na/VVG5Mrd0bpmcgtTUwanzM7/Ft8sNtDSxYxr6iBEORPSz10Q30jSlM+uZ+329rNmnrgyUiCEuWICzZgrDkCMKSKwhLniAs+YKwFAjCEhWEpVAQliJBWIoFYSkRhKWNICyhTYxlQ3v88HMa/5aSPHK8l0Bj4TJDTl2H92JoLFwOeRr3hn3wYSxD+8eYgp7diWt7GanDNZae+4lrHfavf1dW0BJr2Adrex+ZqA2x7wTwWGqpyYa0nwQpY190z1t7AVjaCMJSIghLsSAsRYKwFArCEhWEpUAQlnxBWPIEYckVhCVHEJZsQViyBGGJCMIS9sHSjhdL0+0OjNt0wjiKxo2IiZ5NwBwLx0IGjkrSLz2foYLZFrqNDj7yVxD5sf8OpA7z9H8Tt220T+9o2EPPlWMj9vSh22R+z16Tbel79g4ictFnnW3028Xot8LoV3+HPhN/EMGKv42Q75wRabbDqZCne2VxPND3JtBnpHBO42d436C7BdmxD50qvWaddyey02eqK8lvSons+J1zieyhgubfVfFir0O8HugLcVcRrD15+2y6rdrDa049id4w0XMc0U/gb+gzEPT5Whv+iuLA/itIXV8fnL0Jzj7G9zTOfrw4m8YfxREi/WJfEfKdq8nY8sjYsmHnfl5L/dFnxQfw9lmj531/Lzm1du3H4jOuMVsxxCCC3+98Rvycnik0iBdHU1w10EvWKZYHkX4D+Vn7dUr+Dd0P3tTPkgdnhQZnhW4MluCs0OCs0I3BEhWEJTgrNDgrdGOwBGeFBmeFbgyW4KzQ4KzQjcESnBUanBW6MViCs0KDs0I3BkulICxVgrD0EIQlOCs0OCt0Y7AEZ4UGZ4VuDJbQJsbya2eFlpM6vFZOz/HEZ1v7kbqwTx+/5WxPfU23b0HL/sI+/Q3ywWVbl7SfBCljX3Q/7yABWAYIwtJfEJZ+grD0FYSljyAsvQVh6SUIS09BWHoIwlIlCEulICzdBWHpJghLV0FYugjC0lkQlk6CsHQUhKWDICwVgrCUC8LSXhCWMkFY2gnCUioIS1tBWNoIwlIiCEuxICxFgrAUCsISFYSlQBCWfEFY8gRhyRWEJUcQlmxBWLIEYYkIwhI2sND7CmHL+GhKkLzfPY5gD7s/lmAPuz+WYA+7P5ZgD7s/lqggLIWCsAR72P2xBHvY/bEEe9j9sQR72P2xBHvY/bEEe9j9sQR72P2xBHvY/bEEe9j9sQR72P2xVAnC0kMQlmAPuz+WYA+7P5ZgD7s/lmAPuz8W29fCNwbLYEFYQpsYy6/t7afvpQobv9XXppeRvfj4zqkw+Q2+m4q+d6cO8lmkbhhpE+vwPVQ5pK4B8rk+WOk7r/AdW/TdWPguLvoOLXxnF33HVxzy9aQO353V4IOF2hB/kwAeSy012ZD2kyBl7Is+U9AgAMtgQVgGCcIyQBCW/oKw9BOEpa8gLH0EYektCEsvQVh6CsLSQxCWKkFYKgVh6S4ISzdBWLoKwtJFEJbOgrB0EoSloyAsHQRhqRCEpVwQlvaCsJQJwtJOEJZSQVjaCsLSRhCWEkFYigVhKRKEpVAQlqggLAWCsOQLwpInCEuuICw5grBkC8KSJQhLRBCWsA+WYbxYqul9EY9goilB8vS+Rp2BWeOrtaCrOgMLlrGvKMEw0CKWqE/fFvqpzjdk1qk1m9B7UnjPqo7gG86shxDpB9vFMvZFdTXEIpaoT98W+qnON2TWqTWbYP/6dyMgX0PwjWTWQ4j0g+1iGfuiuhpqEUvUp28L/VTnGzLr1JpNsH/9u1GQH0HwbcashxDpB9vFMvZFdRWziCXq07eFfqrzDZl1as0m2L/+3WjIjyL4xjDrIUT6wXaxjH1RXcUtYon69G2hn+p8Q2adWrMJ9p9P6kcTfGOZ9RAy+k+QMvZFdVVtEUt0A31jCpO+Exb04Bl6MPMUS0QQlixBWLIFYckRhCVXEJY8QVjyBWEpEIQlKghLoSAsRYKwFAvCUiIISxtBWNoKwlIqCEs7QVjKBGFpLwhLuSAsFYKwdBCEpaMgLJ0EYeksCEsXQVi6CsLSTRCW7oKwVArCUiUISw9BWHoKwtJLEJbegrD0EYSlryAs/QRh6S8IywBBWAYKwjJIEJbBgrAMEYRlqCAsMUFY4oKwVAvCUiMIS60gLHWCsAwThKVeEJYGQViGC8IyQhCWkYKwjBKEZTNBWEYLwjJGEJbQJsayoXNU8HN6lshYyNNzSMZBnp5hMh7yI0jdBMiPInWbQ340qZsI+bakbhLke5G6yZAPk7qwj2y4d2UsqcM9JONIHe7lGE/qcE/FBFKHexs2J3W4x2AiqcN7/ZNIHd5zR+y6zxsLWspEx8QkQ6ZYaqlpTNB+EqSMfdFzWSYLwDJGEJbRgrBsJgjLKEFYRgrCMkIQluGCsDQIwlIvCMswQVjqBGGpFYSlRhCWakFY4oKwxARhGSoIyxBBWAYLwjJIEJaBgrAMEISlvyAs/QRh6SsISx9BWHoLwtJLEJaegrD0EISlShCWSkFYugvC0k0Qlq6CsHQRhKWzICydBGHpKAhLB0FYKgRhKReEpb0gLGWCsLQThKVUEJa2grC0EYSlRBCWYkFYigRhKRSEJSoIS4EgLPmCsOQJwpIrCEuOICzZgrBkCcISEYQlbGApIJ+XkLqJkKfnBuIemDpSh3tlakiduR9I142D/ChSNxbyuMciOA/n17EE5+H4Y8kRhCVXEJY8QViC83D8sQTn4fhjCc7D8ccSnIfjjyU4D8cfS3Aejj+W4DwcfyzBeTj+WILzcPyxBOfh+GMJzsPxxxKch+OPpUoQlh6CsATn4fhjCc7D8cfSVxCWfoKwBOfh+GMZKAhLcB6OP5bgPBx/LMF5OP5YgvNw/LEE5+H4YwnOw/HHEpyH448lOA/HH0twHo4/luA8HH8sYwVhGScIy3hBWCYIwrK5ICwTBWGZJAjLZEFYQpsYy6+dtzWR1G0BeXrW1BTI0zOptoQ8PbtqKuTHkbqtID+W1IV98OH+ti1IHe4zm0LqcL/XlqQO911NJXW4/wn7178LR5s/nw71YfKbGZCPkLqZkM8idbNIm1g3G/I5pG4O5HNJ3daQzyN1iHE6qUNZZpA6lHkmqUPdzCJ1qMPZpC4B+Tmkbhrkt/bBR8cs/gbbiKWWmsYs7SdBytgXPQ9sawFYJgvCMkkQlomCsGwuCMsEQVjGC8IyThCWsYKwjBGEZbQgLJsJwjJKEJaRgrCMEIRluCAsDYKw1AvCMkwQljpBWGoFYakRhKVaEJa4ICwxQViGCsIyRBCWwYKwDBKEZaAgLAMEYekvCEs/QVj6CsLSRxCW3oKw9BKEpacgLD0EYakShKVSEJbugrB0E4SlqyAsXQRh6SwISydBWDoKwtJBEJYKQVjKBWFpLwhLmSAs7QRhKRWEpa0gLG0EYSkRhKVYEJYiQVgKBWGJCsJSIAhLviAseYKw5ArCkiMIS7YgLFmCsEQEYQn7YJnNi6We9qn7w/9BdF/gTOY+6V5Ej+iBpgTJzyRYpvNiiel+55L2E6QP2u82vP3Gab8hIOwD6yMkfxg6ePI9nXBPHWLW42aGz/dofpbxmyj5fIZlmacTHAlSxr60L9ibyDrDB/ccghs/34rgrmDGrduYSXBg//SsH+ZxWU/39WJqbY5MJ1iY7dY0R+aR9hOkD9rvtsx6p/3iHME+sD5C8qeTcbNtc/aXcYOY9RyZ6/M9mjfnUJR8PteyzHSuJkgZ+9Jz5Fgi61wf3DMJbvx8KsFtY47QuY390znCPC6b5giVXafW5sg2BAuz3ZrmyHzSfoL0QftdwKx32i/OEewD6yMkfxUZNwuas7+MG8Ss58g8n+/RvDmHouTzeZZlpnM1QcrYl54j5xNZ5/ngpusffr4lwW1jjtC5jf3TOcI8LpvmCJVdp9bmyLYEC7PdmubIQtJ+gvRB+13ErHfaL84R7APrIyR/Lxk3i5qzv4wbxKznyHyf79G8OYei5PP5lmWmczVBytiXniM3EVnn++Cm6x9+PoXgtjFH6NzG/ukcYR6XTXOEyq5Ta3NkAcHCbLemObKYtJ8gfdB+lzDrnfaLcwT7wPoIyb9Axs2S5uwv4wYx6zmy0Od7NG/OoSj5fKFlmelcTZAy9qXnyKNE1oU+uOn6h59vQXDbmCN0bmP/dI4wj8umOUJl16m1ObKIYGG2W9McWUraT5A+aL/LmPVO+8U5gn1gfYTkPyTjZllz9pdxg5j1HFns8z2aN+dQlHy+2LLMdK4mSBn70nPkDSLrYh/cdP1bbGC0NUfo3Mb+6RxhHpdNc4TKrlNrc2QJwcJst6Y5spy0nyB90H5XMOud9otzBPvA+gjJf0vGzYrm7C/jBjHrObLU53s0b86hKPl8qWWZ6VxNkDL2pefIp0TWpT646fqHn08juG3METq3sX/sJ5/goOfm2/Sr2C6WqS1LDH1ZwFIf9em76f5EQXM+VGDXJti/Tng9ntoE65YSfMfCjQvN8L5BLuAsgt/h8KPnBBSQNrAO77HScwLouy2wDu9R03MC8B46PScgTPLIEUMBqUMMUVKHGApJHWIoInWIoZhgyiF9JoDHUkvV+UQ2TK35eCozykrfKxPlxdc0lwoMLFiOEp5H9GQHS7xpLpl9F/jogd7Xp7opZMaj2yxmbpPOA0ytjQc6P1DW7RvXTttlbeMeIfJ7bBPnfS5pI0y+F/Fa9p3ltUzZJJ9D8oXkd1GjTy0b+lw617D/EoIth7SbAB5LLVXT+U/loynhIxf1B/Q9W3m8+JrmWq6BBcvYV5RgiNjDUhP16btgA3pg9okx6hOxbT0Ga8k6yeznavjn8vqYGeeDTgcRueg7jGz0W2T0GzX6pX49B76DWPG3EfKdBIlXRkGe7nGja3uJ0deG5jjdr0fnZRuSR31RH1RK8mHjN3RvJH3vD+4jTQCPpZZq8g0cOrXmS+h7f9rzYmmyt/nOmvY+/XLHlrRf/G+GfWB9hORnk0Ciojn7yxhAzHQPMv0ezZcav4mSz8ssy9ye4EiQMvalx+pkImuZD27qz/Fz+s6sMmbcuo12BEeegS2fyEF9e3ka9VdOdJJt6MsClqY1zuzblu7b/4rusQ6/Z653WbyYmh6Zpz43TPrVie5do+OBOSZr0o1fLJpDcGD/9L8Fc7xTjXYwcfjFPvi96AZwM8dD8d/yf3BD78jd1FiyBGGxGLNuNJYcQVhyBWHJE4QltImx+J1XqsdwKTm/E2N2ek2Mxu9Yh7E4vS6H/dBrYRi20P/n5n8H2h7VUZEhSyy11KQj2k+ClLEvej5msQAseYKw5ArCkiMIS7YgLFmCsEQEYQkbWDbk19B3+V1/oPFaG5JH3pb0h3X4f4PeMwgb+Oj9Buo70ZYlpA5x0f5xLrQldYi1lGDfUHxp4xo/TQmSjxrc85Ljy02NJUsQlmxBWHIEYbF3T2jjsdi+V7YxWPIFYSkQhCW0ibH4xd00DqaxNvp/uibhOkFj7dauk9P7TLhO0LUL1wl6T6SU5JHj9T26noV9ZGtt7aJrnBkn0bWLrnGIla5xiJWucYiVYkesiF332SXaUiY6JvD3CeCx1FLTmKD9JEgZ+6L/M9oJwFIgCEu+ICx5grDkCsKSIwhLtiAsWYKwRARhCRtYcE8G954Hui7Q9Q39G11rcQ3z+/9H11pcw+haS//TYp3f/0TaH3Lbe8voemnugUE8CeCxFJMrbVJ9hn30GfbRJ63DPB0D9H8r1mURfSOn+8ewHXpuDR0PZqzntyeC7nOg97Vai/Xo/30bPgD7wXbNPRNRr2XsaANL1KdvqoeIAD2Y8fKm0EOWAD2Y/xE2hR6yBegBMeRtQj3kCNAD9aObSg+5AvSAGArSrAfdr3mdgnVjBqaI0XZNbFhtbWN9dWO8Jr4sVj18eUNdrLZu+bCGeEO8rqFuu+qGmprGhtqG+uHLh9fHhsdraxrjK+uG16yExsOMOE9gxHUyH65YxM84pI5Lfk7MFO8pJI+OP+wzJnIsyOQZ/Zh6LPYsD3wbRjrFQrunenyD35bcp/LbKEbtLl2nmJj/IcVPYsR5GmNb6XJ8p3l2HN8fST5wfCm2eRoolLvd0z3Zjk/LfTq/jaw6Pk6dpssJnOjZcQJnkHzgBFJs80RQKHe7Z3qynYCW+0x+GzUN1ByveRAeq+gnRccBPx64TmcpOhtko9dpT4LvnEW+e46ic8l3f0v75yk6v5X2zyPfvUDRhT7fPQG+cwFwPeEuUnSxz3dPhO9cBFxjvETRpV5yMqOtVMcH51i7zOO9RkH36ZWDXiqAdwDeEXgn4J2BdwHeFXg34N2BVwKvAt6D8MsVXQG6ps6Rex5dztdWrBLauVLRVYquVnSNomsVXafoekU3KLpR0U2KblZ0i6JbFd2m6HZFdyi6U9Fdiu5WdI+iexXdp+h+RQ8oelDRQ4oeVvSIokcVPabocUVPgJJCoDeNJc9rLl9llK82ytcY5WuN8nVG+XqjfINRvtEo32SUbzbKtxjlW43ybUb5dqN8h1G+0yjfZZTvNsr3GOV7jfJ9Rvl+o/yAUX7QKD9klB82yo8Y5UeN8mNG+XGj/ITX8swH8xJbLLWUNGdS9VdXMrb174idYJjrEmXjSp1i8auY2tK2uJpRf/8Rr7+mpuPXpN5WNcgcv5ZRf/+VrL/aX3DGr0utrRiROX49o/6+k6q/6iSc8Rt+f1sxQ+b4jYz6+16g/oatbIEzftPva6vBR+b4zYz6+580/TX44ozfsvFt1W9A5vitjPr7QZL+6jeIM37bxrVV3YrM8dsZ9fejFP3Vt4ozfsdvb2vFr8gcv5NRfz9J0F/9r+KM3/Xb2or9BpnjdzPq7+dNrb/Yb8IZv+fX26r7jTLH72XUn764tMn0V/ubccbva7Wt2pUbIXP8fkb9hTaV/uo3Cmf8gQ231bCRMscfZNRfeBPob/jKjcYZf8i/rdjvkDn+MKP+IunWX+x34Yw/0rKt+O+UOf4oo/6y0qm/7X43zvhjyW3VpCBz/HFG/WWnSX/VK1PCGX/C47uWSK/Zpaq/nDTpL5ZaijNeZ4v/l1F/uY7oj/E6Ufx7Rv3lOaI/xusc8R8Y9ZfviP4Y/6fHf2LUX4Ej+mP8nxmn/7lS1V/UEf0x/k+Khxn1V+iI/hjj/HgWo/6KHNEfY5waz2HUX7Ej+mOMs+J5jPorcUR/jHFCvIBRf20c0R/jOhcvZNRfW0f0x+in48WM+it1RH+MfibehlF/7RzRH+M8iTOOmTin/vR+Nv0stLk/GNvv6a3f59YLeG/gfYD3Bd4PeH/gA4APBD4I+GDgQ4APBR4DHgdeDbwGeC3wOuDDgNcDbwA+HPgI4COBjwK+GfDRwMcATwAfC3wc8PHAJwDfHPhE4JOATwa+BfApwLcEPhX4VsCnAZ8OfAbwmcBnAZ8NfA7wrYHPBb4N8HnAtwU+H/gC4AuBLwK+GPgS4EuBLwO+HHiltz7hfkfcB4n7I3HfJO6nfBg47r98EDju18R9nLi/E/d94n5Q3CeK+0dxXynuN8V9qLg/Ffet4n5W3OeK+19xXyzul8V9tLi/Fvfd4n5c3KeL+3evBP6kl5y490c/6THeX/HS8+BON4/XD2F6iuSDB3dSbLMbKJS73ac9vgFrS+6n+W3UNLkiXsskeXLZxNnJEZzlHr+zCpE2n1H0rKLnFD2v6AVFLyp6SdHLil5R9Kqi1xS9rugNRW8qekvR24reUfQnRe8qek/R+4r+rOgDRR8q+ouijxT9VdHHiv6m6BNFf1f0qaJ/KPpM0eeKvlD0paKvFP1T0deK/qXoG0XfKvq3ov8o+q+i7xR9r+h/in5Q9KO3PgD8GQQMKQoriijKUpStKEdRrqI8RfmKCohHpIeKms6bHuAVInXUueuUQ/IJ4LEUk4XFIqYD5zwih2fIW+zZeOFObdLBap6hT1NvVJ8aKx4GuGLZ6tUzdl+157K1jRPXrVmxdtUua+iwzjaaifiIZ9bT8/vMdwxSM9Nz2kIm/gTwVNcUuj7FUkvxdPn85zw7vtTjxVltse04HVxRUHAhGdw4z8JeyxdNhYid9GD82WtpqxDJh+E7kVa+E9pAO3S+05cuuOK7rAay+JScNuCPXvNTc4Whlp1yX7Whkyi1J8hWrtT4U23rl7t2IfeC0Oe9wCFRh1QECi4OHJKbDqnIcEjFaXBIdBKl6pCKGB1SsYMO6QUvcEjUIZWAgtsEDslNh1RiOKQ2aXBIdBKl6pBKGB1SGwcd0ite4JCoQ2oLCi4NHJKbDqmt4ZBK0+CQ6CRK1SG1ZXRIpQ46pFe9wCFRh9QOFFwWOCQ3HVI7wyGVpcEh0UmUqkNqx+iQyhx0SK95gUOiDqk9KLg8cEhuOqT2hkMqT4NDopMoVYfUntEhlTvokApCgUOiDqkCFNwhcEhuOqQKwyF1SINDKgjxOaQKRofUwdLk5tYf3d6VqszPMLbVkdmhtxj8Hr9D58RM8XYihWAfaoptaiN1CvG325nRediSu3OI3UatvpaGc+9Uqm11Cckel9o2XUL8+8+qHXnIidPWXRltXc34wFm6FqKulhaibsFCxGukbhYWou7CFyItd3fLC5F0nXpkIHPipA9BpIrzWca2Kh2M5istOdGqwInyGqnKghPtIdyJarl7ZHA031N4NK9t09NCNF+bgdF8L0Zb1zoYzfeytBD1DhYiXiP1trAQ9RG+EGm5+zgWzXPr1CMDmRMnfVQ4VZyvM7bV18Fovq8lJ9ovcKK8RupnwYn2F+5Etdz9MziaHyA8mte2GWAhmh+WgdH8QEZbD3Mwmh9oaSEaFCxEvEYaZGEhGix8IdJyD3YsmufWKSbuBbMDI84hITuTV3KQMFR4kKBtMtRCkNCQgUFCjNHWDQ4GCTFLQUI8CBJ4jRS3ECRUCw8StNzVjgUJ1Y4ECaWMOGsyMEioFR4kaJvUWggSRmRgkFDHaOsRDgYJdZaChGFBkMBrpGEWgoR64UGClrvesSCh3pEgoYwRZ0MGBgnDhQcJ2ibDLQQJozIwSBjBaOtRDgYJIywFCSODIIHXSCMtBAmjhAcJWu5RjgUJoxwJEsoZcW6WgUHCaOFBgrbJaAtBwugMDBLGMNp6tINBwhhLQUIiCBKYjWQhSBgrPEjQco91LEgYaylIMJ1oqm2HGWV+kRHXOEaHlC4nOs6SEx0fOFFeI4234EQnCHeiWu4Jlp2o5Gh+c+HRvLbN5hai+UQGRvMTGW2dcDCan2hpIZoULES8RppkYSGaLHwh0nJPdiya59apRwYyxZlq24yvao2/xIhrCwej+S0sOdEpgRPlNdIUC050S+FOVMu9ZQZH81OFR/PaNlMtRPPjMjCa34rR1uMcjOa3srQQTQsWIl4jTbOwEE0XvhBpuac7Fs1z6lRj0xMEJ5A+M0+/tF6/Y1fzYuBtgBcomqHyM2Gs0Jeyvwi/fQn4y8BL4bdlwMuBt1U0S+Vn+7QVhu9EgGcBzwaeAzwXeKGiOSq/NWkLjTALvvM64HkD+JvA3wL+NvB3gP8J+LvA3wP+PvA/A/8A+IfA/wL8I+B/Bf4x8L8B/wT434F/CvwfwD8D/jnwL4B/Cfwr4P8E/jXwfwH/Bvi3wP8N/D/A/wv8O+DfA/8f8B+A/wgc6WfgHug1BHwO8Dzg+cAHKJqr8tsQ26BzfgbamgHfnQu8VNE8ld/W8KKSg7r5jAt9uhbn7p6dxXlBsDjzGmmBhcV5ofDFWcu90MLinK7343BOLps4OzuCs8Ljd1Yh0uYiVVisaImipYqWKVquaIWi7RQ1KlqpaHtFOyhapWhHRTspWq1oZ0VrFO2iaFdFuynaXdEeitYqWqdoT0V7Kdpb0T6K9lW0n6L9FR2g6EBFByk6WNEhig5VdJiiwxUdoehIRX9QdJSioxUdo+hYRccpOl7RCYpOVHSSopMVnaLoVEWnKfqjotMVnaHoTEVnKTpb0TmKziXzrAS4fmeQ6bzzvZbvH8r3kp27Tq68VyhbtZFH5PAMefEdSTms/dbGdF/ZXnIyF6WEjz411naQX7Fs9eoZu6/ac9naxonr1qxYu2qXNXRYZxvNRHzEM+uziCpyIZ9N6vB3uYSHTPwJ4KmuKQuZA6p0+PwlITu+1OPFmbZ3op0HCj6fDO7gnWg8bablnWjagPSdaOeHWnbKffl1CUNgiu9EO48xyD2fcXKnyyEtDRxSkkO6ABR8YeCQ3HRIFxgO6cI0OKSljA7pAkaHdKGDDmlZ4JCSHNJFoOCLA4fkpkO6yHBIF6fBIS1jdEgXMTqkix10SI2BQ0pySJeAgi8NHJKbDukSwyFdmgaH1MjokC5hdEiXOuiQVgYOKckhXQYKvjxwSG46pMsMh3R5GhzSSkaHdBmjQ7rcQYe0feCQkhzSFaDgKwOH5KZDusJwSFemwSFtz+iQrmB0SFc66JDODRxSkkO6ChR8deCQ3HRIVxkO6eo0OKRzGR3SVYwO6WpLk5tbf3R7V6oyL2LU3zXMDr3F4Pf4HTonZor3WlII9qGm2KY20rUh/navYxz8tuS+LsRuI6tPK3Lu7b0+JHtcattcH+LffzbBkacVOW19A6OtJzj4tOINlhaiG4OFiNdIN1pYiG4SvhBpuW+yvBBJ16lHBjInTvoQRKo4FzPKfLOD0fzNlpzoLYET5TXSLRac6K3CnaiW+9YMjuZvEx7Na9vcZiGan5iB0fztjLae6GA0f7ulheiOYCHiNdIdFhaiO4UvRFruOx2L5rl16pGBzImTPiqcKs4dGGW+y8Fo/i5LTvTuwInyGuluC070HuFOVMt9TwZH8/cKj+a1be61EM1PzsBo/j5GW092MJq/z9JCdH+wEPEa6X4LC9EDwhciLfcDjkXz3DrFxL1gXs2I88GQnckrOUh4SHiQoG3ykIUgYUoGBgkPM9p6ioNBwsOWgoRHgiCB10iPWAgSHhUeJGi5H3UsSHjUkSDhUkacj2VgkPC48CBB2+RxC0HC1AwMEp5gtPVUB4OEJywFCU8GQQKvkZ60ECQ8JTxI0HI/5ViQ8JQjQcLljDifzsAg4RnhQYK2yTMWgoRpGRgkPMto62kOBgnPWgoSnguCBF4jPWchSHheeJCg5X7esSDheUeChCsZcb6QgUHCi8KDBG2TFy0ECTMyMEh4idHWMxwMEl6yFCS8HAQJvEZ62UKQ8IrwIEHL/YpjQcIrloIE7neVhxllXs4o86uMDildTvRVS070tcCJ8hrpNQtO9HXhTlTL/bplJyo5mn9DeDSvbfOGhWh+VgZG828y2nqWg9H8m5YWoreChYjXSG9ZWIjeFr4Qabnfdiya59apRwYyxZlq24yvao2vYJT5HQej+XcsOdE/BU6U10h/suBE3xXuRLXc72ZwNP+e8Ghe2+Y9C9H8nAyM5t9ntPUcB6P59y0tRH8OFiJeI/3ZwkL0gfCFSMv9gWPRPKdONTY9QXAC6TPzfvLWv19Y8wuBXwy8QNGHKv8XGCv0pezL4TsrgG8H/FLglwO/EnhbRR+p/F992joNvvNH4KcDPwP4mcDPAl6o6GOV/xtpC43wEXxnB+CrgO8IfCfgq4HvDHwN8F2A7wp8N+C7A98D+Frg64DvCXwv4HsD3wf4vsD3A74/8AOAHwj8IOAHAz8E+KHADwN+OPAjgB8J/A/AjwJ+NPBjgB8L/DjgxwM/AfiJwE8CfjLwU4CfCvxj4GcDPwf4AEWfqPzfiW3QOS+C73wI/BPgpYo+Vfl/hNZ/97e8ziLlnaSenQXCM3DGNi7FzQrGtlv0RRfQz0DBnxP/GLzOgqfNtLzOQhvwfuhIlz8nC4epPKznnEQb2VbMaCv+GeNC9zljFJ6u9+ukgnllclrhA9eKQ+J2ygtDdpzbFwD0y9/p3Mb5yGw6t3Herzs3v3b+Xzk3yQMCHeMXoWbD6LIeFGO95MTtKDnl+JLRUX4V4nMMqM+viD5tjIfPQynbx1x86jjt8zmjfeYyX0JLcfK3sLnWG84nTjtvI0tuMzVdMvzSgtzz0nTJNNVg7QvGMc7pz7Z15JIz47yOb8N4mXi+I/pjnCdxxjETT0V/rQXx3Le3OOfvPxnXTpsyc97m+ZpZZu71Sdvkawvr09IMvKX3L0ZbL3Xwlh6j/Em39L4hheCWXoptaiN9E+Jv91vGiWRL7m9D7DayektPuk7nqQbnW1g8/h1Kj31SxfkfR3D+1xGc3zHizPbWLxa4YOgxpe2ldfGd4bG5A8inGdv6njGooPqgiav9DY2LWGop/r2F8cuN8VNH5tj/GHFaHk/WbPU/B8bTD5bGk+Q/yz8K/7NsK975yRHf8bM7a5G1efmzA75DT3JujDpJ9h2hMK/v2JBtUj6agA9ntatzKByWjzGSgXMoy5E5lM2Hs8bVOZTtwBzKycA5lMs4h9J14b6Sr62kC/d54eZ8cOE+xTYrQaHc7eaHZV9k1nLnh9ltFEvXdt1Kz44T5MbZxRGcHTx+Z6V5IeQL1FiLKipUVKSoWFGJojaK2ioqVdROUZmi9mRclgDX23RNZ5fvtdzym+8lO0OdXNnKqy+u5xE5PENe3Jacw9vvCt1XtpecTCee8NGnxtoR8o1rdlvXuK5xxrrlq1etmLhuzYq1q3ZZM37Z6tV0MGAnOCgiPkKa9VlEIbmQzyZ1+LtcwkOmFAngqXrifOYwJB2estBSuOjx4qy22HbSwwjlUKgglcGTVjxtpuVJK23AH73mBwgqwi075d7QVMgQzjXCzsJyxtCwgnFyp8shFQUOKckhdYBCx8AhuemQOhgOqWMaHFIRo0PqwOiQOjrokIoDh5TkkDpBoXPgkNx0SJ0Mh9Q5DQ6pmNEhdWJ0SJ0ddEilgUNKckhdoNA1cEhuOqQuhkPqmgaHVMrokLowOqSuDjqkdoFDSnJI3aDQPXBIbjqkboZD6p4Gh9SO0SF1Y3RI3R10SGWBQ0pySJVQqAockpsOqdJwSFVpcEhljA6pktEhVVma3Nz6q/T4ZC5g1F8PZofeYvB7/A6dEzPF25M4xGCzVIptaiP1DPO324tx8NuSu1eY3UZWd19ybkDrHZY9LrVteof5t3ssd+S4DU5b92G09XIHj9tglD9pIeobLES8RuprYSHqJ3wh0nL3s7wQSdepRwYyJ066UzdVnFFGmfs7GM33t+REBwROlNdIAyw40YHCnaiWe2AGR/ODhEfz2jaDLETz22VgND+Y0dbbORjNM8qftBANCRYiXiMNsbAQDRW+EGm5hzoWzXPr1CMDmRMnfZ4tVZztGWWOORjNxyw50XjgRHmNFLfgRKuFO1Etd3UGR/M1wqN5bZsaC9H8ygyM5msZbb3SwWieUf6khaguWIh4jVRnYSEaJnwh0nIPcyya59YpJu4FsysjzvqwnckrOUhoEB4kaJs0WAgSdsjAIGE4o613cDBIYJQ/KUgYEQQJvEYaYSFIGCk8SNByj3QsSODWKSbuBbM7I85RGRgkbCY8SNA22cxCkLBjBgYJoxltvaODQQKj/ElBwpggSOA10hgLQUJCeJDQNDgdCxK4dYqJe8GsYsQ5NgODhHHCgwRtk3EWgoTVGRgkjGe09WoHgwRG+ZOChAlBkMBrpAkWgoTNhQcJWu7NHQsSuHXqkYFMcab8NhlGmUsYZZ7I6JDS5UQnWnKikwInymukSRac6GThTlTLPdmyE5UczW8hPJrXttnCQjS/JgOj+SmMtl7jYDTPKH/SQrRlsBDxGmlLCwvRVOELkZZ7qmPRPLdOPTKQKc5U265klLkNo8xbORjNb2XJiU4LnCivkaZZcKLThTtRLff0DI7mZwiP5rVtZliI5nfNwGh+JqOtd3UwmmeUP2khmhUsRLxGmmVhIZotfCHScs92LJrn1KnGpicITiB9HM5P3vo3dWneEXhn4AWK5qj81jBW6EsOS+A7bYC3Bd4VeHfgVfi5orkqvw2dtR7/ojMvnB67popzW0dwzmd26Hr8oLOeB2NjW+DzgeuTiReo/ELLY2WRIzZY7AjOJRbHyiIYG4uBLyFjZanKL7M8VpY7YoMVjuDczuJYWQ5jYwXw7chYaVT5lZbHyvaO2GAHR3CusjhWtoexsQPwVWSs7KjyO1keK6sdscHOjuBcY3GsrIaxsTPwNWSs7KLyu1oeK7s5YoPdHcG5h8WxshuMjd2B70HGylqVX2d5rOzpiA32cgTn3hbHyp4wNvYCvjcZK/uo/L6Wx8p+jthgf0dwHmBxrOwHY2N/4AeQsXKgyh9keawc7IgNDrFgA1TtwaDzQ4DnKTpU5Q+zrPvDHdH9ERZ1fzjo/Aii+yNV/g+WdX+UI7o/2qLujwKdH010f4zKH2tZ98c5ovvjLer+OND58UT3J6j8iZZ1f5Ijuj/Zou5PAp2fTHR/isqfaln3pzmi+z9a1P1poPM/Et2frvJnWNb9mY7o/iyLuj8TdH4W0f3ZKn+OZd2f64juz7Oo+3NB5+cR3Z+v8hdY1v2Fjuj+IkdwXuwIzkscwXmpIzgvcwTn5Y7gvMIRnFc6gvMqR3Be7QjOaxzBea0jOK9zBOf1juC8wRGcNzqC8yZHcN7sCM5bHMF5qyM4b3ME5+2O4LzDEZx3OoLzLkdw3u0IznscwXmvhWtmQ6G9uXCtrD3wC4FfBPxi4JcAXwB8KfBG4DsC3wX4WuD7AD8Q+KHAjwR+DPATgJ8C/HTgZwM/H/ilwC8DfjnwK4BfCfwq4FcDvwb4tcCvA3498BuA3wj8JuA3A78F+K3AbwN+O/A7gN8J/C7gdwO/B/i9wAcquk/l7w83PyeC+xUK4DtzgN8HvFTRAyr/YNhLSmHm8cb5cN9DfGM3nq4H8qo83vmG6WFit+CBvBTbrAKFcrf7COPgtyX3I2F2GzU97RrxWibJk8smzq6O4Ozo8TsrzQsh/6gaa48pelzRE4qeVPSUoqcVPaPoWUXPKXpe0QtkXJYA15vsTGeXT8ZaiNQZ69ovD04y6itmwbnGsr31NxtRDs+Qt9hLfhCUqd8Vuq9sLzmZTjzho0+NtSPkG9fstq5xXeOMdctXr1oxcd2aFWtX7bJm/LLVq+lgwE5wUER8hDTrs4hCciGfTerwd7mEh0wpEsBT9cSPMIch6fCUj1v6e+Lx4qy22DZ9ra73IhReIpU428Je84DKIfZAO+nB+LPX0lYhkg/DdyKtfCe0gXborMff46xn1okVD2Y1/AuBcrUBf4SOdPmlcMtOuQ8qeZwhnGtcuT69yBgavsQ4udPlkJ4IHFKSQ3oZCq8EDslNh/Sy4ZBeSYNDeoLRIb3M6JBecdAhPRk4pCSH9CoUXgsckpsO6VXDIb2WBof0JKNDepXRIb3moEN6NnBISQ7pdSi8ETgkNx3S64ZDeiMNDulZRof0OqNDesNBh/Rc4JCSHNKbUHgrcEhuOqQ3DYf0Vhoc0nOMDulNRof0loMO6fnAISU5pLeh8E7gkNx0SG8bDumdNDik5xkd0tuMDukdS5ObW39VHp/MjzLq70/MDr3F4Pf4HTonZor3XeIQg81SKbapjfRumL/d9xgHvy253wuz28jqazQ4N6C9H5Y9LrVt3g/zb/fY3ZHXaHDa+s+Mtt7dwddoMMqftBB9ECxEvEb6wMJC9KHwhUjL/aHlhUi6Tj0ykDlx0p26qeJ8jFHmvzgYzf/FkhP9KHCivEb6yIIT/atwJ6rl/msGR/MfC4/mtW0+thDNr83AaP5vjLZe62A0zyh/0kL0SbAQ8RrpEwsL0d+FL0Ra7r87Fs1z69QjA5kTJ32eLVWcLzDK/KmD0fynlpzoPwInymukf1hwop8Jd6Ja7s8yOJr/XHg0r23zuYVofs8MjOa/YLT1ng5G84zyJy1EXwYLEa+RvrSwEH0lfCHScn/lWDTPrVNM3AvmG4w4/xm2M3klBwlfCw8StE2+thAk7J2BQcK/GG29t4NBAqP8SUHCN0GQwGukbywECd8KDxK03N86FiRw6xQT94L5FiPOf2dgkPAf4UGCtsl/LAQJ+2ZgkPBfRlvv62CQwCh/UpDwXRAk8BrpOwtBwvfCgwQt9/eOBQncOsXEvWC+w4jzfxkYJPwgPEjQNvnBQpCwfwYGCT8y2np/B4MERvmTgoSfgiCB10g/WQgSfhYeJGi5f3YsSODWqUcGMsWZatthRpmf4pQ54t7mIU7MFG+IHDMRONFU24ysVyh3u+GIbCeq5Q5H2G3kzOahSET2uNS2iUT4o/kDMzCaz2K09YEORvNZlhai7GAh4jVStoWFKEf4QqTlzrG8EEnXqUcGMsWZattVjDI/zeiQcx2M5nMtOdG8wInyGinPghPNF+5Etdz5GRzNFwiP5rVtCixE8wdnYDQfZbT1wQ5G81FLC1FhsBDxGqnQwkJUJHwh0nIXORbNc+pUY9MTBCeQPg5Hv3n4JeCvAH8NeIEe3Kr/Ehgr9CWHT8F3ngb+DPA3gL8F/B3gbRW1Ue20jXhea/pKVcbSSHrsmirOdo7gLGN26PRN2NpWemy0A14GXJ9M3F7lyy2PlQpHbNDBEZwdLY6VChgbHYB3JGOlk8p3tjxWujhig66O4Oxmcax0gbHRFXg3Mla6q3yl5bFS5YgNejiCs6fFsVIFY6MH8J5krPRS+d6Wx0ofR2zQ1xGc/SyOlT4wNvoC70fGSn+VH2B5rAx0xAaDHME52OJYGQhjYxDwwWSsDFH5oZbHSswRG8QdwVltcazEYGzEgVeTsVKj8rWWx0qdIzYY5gjOeotjpQ7GxjDg9WSsNKj8cMtjZYQjNhhpwQZ4wXkE6Hwk8DxFo1R+M8u6H+2I7sdY1P1o0PkYovuEyo+1rPtxjuh+vEXdjwOdjye6n6Dym1vW/URHdD/Jou4ngs4nEd1PVvktLOt+iiO639Ki7qeAzrckup+q8ltZ1v00R3Q/3aLup4HOpxPdz1D5mZZ1P8sR3c+2qPtZoPPZRPdzVH5ry7qf64jut7Go+7mg822I7uep/LaWdT/fEd0vcATnQkdwLnIE52JHcC5xBOdSR3AucwTnckdwrnAE53aO4Gx0BOdKR3Bu7wjOHRzBucoRnDs6gnMnR3CudgTnzo7gXOMIzl0cwbmrIzh3cwTn7o7g3MMRnGsdwbnOEZx7WrhmNhTaawPXyvSLwTSfD+UFwBcCXwS8PfBOwLsD7wW8P/AhwGuANwAfBTwBfALwycCnAp8BfA7wecAXA18CfCnwZcCXA18BfDvgjcBXAt8e+A7AVwHfEfhOwFcD3xn4GuC7AN8V+G7Adwe+B/C1wNcB3xP4QEV7qfzekebnRPAy5aNgi2L47l7ASxXto/L7RtZ/N+K1TNxjLz/MNvbiPnB/b9txs4Kx7RZ9hUmb+4HS9yfKzwce9pqvRecQe+BX9TNEP3stbRUi+TB8J9LKd0IbaCef1OHviwkWRp3ELDw0GLP6UGAIlKsNeD90pMv7E+dqKg/rOSfRRrYVM9qK7xfhw7U/38IS/60OKZZaiqeCeWVyWuED14pD4nbKj4TtOLcDwIAH/k7nNs5HZtO5jfN+3bn5tfP/yrlJHhDoGA+INBtGl/WgGOslJ25HySnHgYyO8qAIn2NAfR5E9GljPOwfSdk+5uJTx2mf/RntcyjzsRkpTv4WNtd6w/nEaefDZMltpqZjQg60IPfhaTomJdVg7QDGMc7pz45w5JgZxnkdP4zxaJgjHdEf4zyJM46ZeCr6ay2ID6c2f1vYmXP+Hsz4Z8umzJxHOx3CLDP3+qRtcoiF9em4DDzG61BGWx/n4DFejPInHeN1GPkzHhzjlWKb2kiHRfjbPZxxobAl9+ERdhtZPcZLuk4fULPwoTD/4nGEI7clj3QE5x8cwXkUI85s1YYmXDD0mNL20ro4yrhMzx1A5jMGFUczBhVZoBMzcbW/oXERSy3Fj7Ywfrkx7uPIHDuGEafl8WTNVsc4MJ6OtTSeJP9ZPk74n2Vb8c7xjviOE9xZi6zNyxMc8B0nZqDvOMnSxUXuOXQyH85qV+fQyQ7MoVMycA6d6sgcOo0PZ42rc+g0B+bQHzNwDp3uyBw6w5GY80xHcJ7lCM6zmXFy+4wzVRvnWJD7BOEbhS5RbVxmQe4TZW4UaoHzHEa/yWjruC39cdv5XEf8z3mO4DzfEZwXOILzQkdwXuQIzosdwXmJIzgvdQTnZY7gvNwRnFc4gvNKR3Be5QjOq4X/D1qoGvwpxC/3KcL/B/2gGvzRgtynOvI/6BrG/0GMto6fKnzc6IuCIQv3Zq8V7iciSuYsC3JfJ1zuHCVzrgW5rxcut75WfbyFDfunC5/fej/McRbkPsORdeEGxnWB0dbxM4SPG70X4iQL4+ZG4X5C378+1YLcNwmXW99zPN2C3Dc78r/mFkdw3uoIztscwXm7IzjvcATnnY7gvMsRnHenaS9ILLXUdPgLl8z3OCJzmFHmex2ROcIo832OyJzFKPP9jsiczSjzA47InMMo84OOyHw0o8wPOSLzGYzPBz/siMxnMsr8iCMyn8Uo86OOyHw2o8yPOSLzOYwyP+6IzOcyyvyEIzKfxyjzk47IfD6jzE85IvMFjDI/7YjMFzLK/IwjMl/EKPOzjsh8MaPMzzki8yWMMj/viMyXMsr8giMyX8Yo84uOyHw5o8wvOSLzFYwyv+yIzFcyyvyKIzJfxSjzq47IfDWjzK85IvM1jDK/7ojM1zLK/IYjMl/HKPObjsh8PaPMbzki8w2MMr/tiMw3Msr8jiMy38Qo858ckflmRpnfdUTmWxhlfs8RmW9llPl9R2S+jVHmPzsi8+2MMn/giMx3MMr8oSMy38ko818ckfkuRpk/ckTmuxll/qsjMud6fDJ/7IjMeYwy/80RmfMZZf7EEZkLGGX+uyMyRxll/tQRmQsZZf6HIzIXMcr8mSMyFzPK/LkjMpcwyvyFIzK3YZT5S0dkbsso81eOyFzKKPM/HZG5HaPMXzsicxmjzP9yROb2jDJ/Y0Hm5cDxxdz62Sg8F1s/S6L/F+r/Sfp/g46jdVyp4ywdd+h1WK9L2k9rv6XnsR7X2s5a7nJFFYo6KOqoqJOizoq6KOqqqJui7ooqFVUp6qGop6Jeinor6qOor6J+ivorGqBooKJBigYrGqJoqNaFIn1gcrXWsaJaRXWKhimqV9SgaLiiEYpGKhqlaDNFoxWNAfuMVTRO0XhFExRtrmiiokmKJivaQtEURVsqmqpoK0XTFE1XNEPRTEWzFM1WNEfR1ormKtpG0TxF2yqar2iBooWKFilarGiJoqWKloEtRoA99POD+nk6/XyZft5KP3+kn8fRz6fo5zX08wt6P7/e3673e+v9z3o/sN4fq/eL6v2Tej+h3l+n95vp/Vd6P5Len6P3q+j9G3o/g76/r+936/u/+n6ovj+o75fp+0f6foq+v6Cvt+vrz/p6rL4+qa/X6etX+nqOvr6h/+/r/7/6/6D+f6T/L+j4WceTOr7S8YZef/V6pP2z9ld6/urx/H9SYq4/LmUFAA==", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note.nr b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note.nr index 069457cce68..6d92fd93048 100644 --- a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note.nr +++ b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note.nr @@ -1,5 +1,3 @@ -mod filter; - use dep::std::hash::pedersen; use dep::aztec::note::note_interface::NoteInterface; use dep::aztec::note::note_header::NoteHeader; diff --git a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note/filter.nr b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note/filter.nr deleted file mode 100644 index eae38b258ef..00000000000 --- a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/address_note/filter.nr +++ /dev/null @@ -1,21 +0,0 @@ -use dep::std::option::Option; -use dep::aztec::constants_gen::MAX_READ_REQUESTS_PER_CALL; -use crate::address_note::AddressNote; - -fn filter_by_owner_and_address( - notes: [Option; MAX_READ_REQUESTS_PER_CALL], - params: [Field; 2], -) -> [Option; 1] { - let address = params[0]; - let owner = params[1]; - let mut owner_note = [Option::none()]; - for i in 0..notes.len() { - if notes[i].is_some() { - let note = notes[i].unwrap_unchecked(); - if (note.address == address) & (note.owner == owner) { - owner_note[0] = notes[i]; - } - } - } - owner_note -} diff --git a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr index d69e38910b2..3731b20dba2 100644 --- a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr @@ -22,7 +22,6 @@ contract Escrow { AddressNote, AddressNoteMethods, ADDRESS_NOTE_LEN, - filter::filter_by_owner_and_address, }; use crate::storage::Storage; @@ -62,7 +61,7 @@ contract Escrow { let storage = Storage::init(); // We don't remove note from the owners set. If a note exists, the owner and recipient are legit. - let options = NoteGetterOptions::with_filter(filter_by_owner_and_address, [sender, this]); + let options = NoteGetterOptions::new().select(0, sender).select(1, this); let notes = storage.owners.get_notes(&mut context, options); let note = notes[0].unwrap_unchecked(); // Filter is not constrained. We still need to check if the note is what we expected. diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr index 2b1171c12fb..a31b4cf32db 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr @@ -148,6 +148,9 @@ unconstrained fn get_note_internal( oracle::notes::get_notes( storage_slot, note_interface, + 0, + [], + [], [], [], 1, // limit @@ -162,19 +165,37 @@ unconstrained fn get_notes_internal( note_interface: NoteInterface, options: NoteGetterOptions, ) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let sort_by = options.sort_by; - let mut sort_by_indices = [0; N]; + let selects = options.selects; + let mut num_selects = 0; + let mut select_by = [0; N]; + let mut select_values = [0; N]; + for i in 0..selects.len() { + if selects[i].is_some() { + select_by[num_selects] = selects[i].unwrap_unchecked().field_index; + select_values[num_selects] = selects[i].unwrap_unchecked().value; + num_selects += 1; + }; + }; + + let sorts = options.sorts; + let mut sort_by = [0; N]; let mut sort_order = [0; N]; - for i in 0..sort_by.len() { - sort_by_indices[i] = sort_by[i].field_index; - sort_order[i] = sort_by[i].order; + for i in 0..sorts.len() { + if sorts[i].is_some() { + sort_by[i] = sorts[i].unwrap_unchecked().field_index; + sort_order[i] = sorts[i].unwrap_unchecked().order; + }; }; + let placeholder_opt_notes = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; oracle::notes::get_notes( storage_slot, note_interface, - sort_by_indices, + num_selects, + select_by, + select_values, + sort_by, sort_order, MAX_READ_REQUESTS_PER_CALL as u32, options.offset, @@ -189,9 +210,23 @@ unconstrained fn view_notes( limit: u32, offset: u32, ) -> [Option; MAX_NOTES_PER_PAGE] { + let select_by = [0; N]; + let select_values = [0; N]; let sort_by = [0; N]; let sort_order = [0; N]; let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE]; let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH]; - oracle::notes::get_notes(storage_slot, note_interface, sort_by, sort_order, limit, offset, placeholder_opt_notes, placeholder_fields) + oracle::notes::get_notes( + storage_slot, + note_interface, + 0, + select_by, + select_values, + sort_by, + sort_order, + limit, + offset, + placeholder_opt_notes, + placeholder_fields, + ) } \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr index 81c821fe4a2..845fd91d73c 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr @@ -1,7 +1,17 @@ use dep::std::option::Option; - use crate::constants_gen::MAX_READ_REQUESTS_PER_CALL; +struct Select { + field_index: u8, + value: Field, +} + +impl Select { + fn new(field_index: u8, value: Field) -> Self { + Select { field_index, value } + } +} + struct SortOrderEnum { DESC: u8, ASC: u8, @@ -29,50 +39,72 @@ impl Sort { } } -struct NoteGetterOptions { - sort_by: [Sort; N], +fn return_all_notes(notes: [Option; MAX_READ_REQUESTS_PER_CALL], _p: Field) -> [Option; MAX_READ_REQUESTS_PER_CALL] { + notes +} + +// docs:start:NoteGetterOptions +struct NoteGetterOptions { + selects: [Option; N], sorts: [Option; N], + limit: u32, offset: u32, - filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; NUM_RETURN_NOTES], + filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, } // docs:end:NoteGetterOptions -impl NoteGetterOptions { - fn new() -> NoteGetterOptions { +impl NoteGetterOptions { + fn new() -> NoteGetterOptions { NoteGetterOptions { selects: [Option::none(); N], sorts: [Option::none(); N], + limit: MAX_READ_REQUESTS_PER_CALL as u32, offset: 0, filter: return_all_notes, filter_args: 0, @@ -65,12 +67,13 @@ impl NoteGetterOptions; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; NUM_RETURN_NOTES], + filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, ) -> Self { NoteGetterOptions { selects: [Option::none(); N], sorts: [Option::none(); N], + limit: 0, offset: 0, filter, filter_args, @@ -103,6 +106,12 @@ impl NoteGetterOptions Self { + assert(limit <= MAX_READ_REQUESTS_PER_CALL as u32); + self.limit = limit; + *self + } + fn set_offset(&mut self, offset: u32) -> Self { self.offset = offset; *self diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr b/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr index 4baca73d2b6..46b4ce37d3c 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr +++ b/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr @@ -1,5 +1,6 @@ use dep::std::option::Option; use crate::abi::PublicContextInputs; +use crate::constants_gen::MAX_READ_REQUESTS_PER_CALL; use crate::context::{ PrivateContext, PublicContext, @@ -64,11 +65,11 @@ impl Set { destroy_note(context, self.storage_slot, note, self.note_interface); } - fn get_notes( + fn get_notes( self, context: &mut PrivateContext, - options: NoteGetterOptions, - ) -> [Option; S] { + options: NoteGetterOptions, + ) -> [Option; MAX_READ_REQUESTS_PER_CALL] { let storage_slot = self.storage_slot; let opt_notes = get_notes(context, storage_slot, self.note_interface, options); opt_notes diff --git a/yarn-project/noir-libs/value-note/src/balance_utils.nr b/yarn-project/noir-libs/value-note/src/balance_utils.nr index 811c15c65ad..9cac45acdbb 100644 --- a/yarn-project/noir-libs/value-note/src/balance_utils.nr +++ b/yarn-project/noir-libs/value-note/src/balance_utils.nr @@ -1,14 +1,15 @@ +use dep::aztec::constants_gen::MAX_NOTES_PER_PAGE; use dep::aztec::note::note_getter::view_notes; use crate::value_note::{VALUE_NOTE_LEN, ValueNoteMethods}; unconstrained fn get_balance(storage_slot: Field) -> Field { - get_balance_internal(storage_slot, 10, 0) + get_balance_internal(storage_slot, 0) } -unconstrained fn get_balance_internal(storage_slot: Field, limit: u32, offset: u32) -> Field { +unconstrained fn get_balance_internal(storage_slot: Field, offset: u32) -> Field { let mut balance = 0; - let opt_notes = view_notes(storage_slot, ValueNoteMethods, limit, offset); + let opt_notes = view_notes(storage_slot, ValueNoteMethods, MAX_NOTES_PER_PAGE as u32, offset); let len = opt_notes.len(); for i in 0..len { if opt_notes[i].is_some() { @@ -16,7 +17,7 @@ unconstrained fn get_balance_internal(storage_slot: Field, limit: u32, offset: u } } if (opt_notes[len - 1].is_some()) { - balance += get_balance_internal(storage_slot, limit, offset + limit); + balance += get_balance_internal(storage_slot, offset + MAX_NOTES_PER_PAGE as u32); } balance diff --git a/yarn-project/noir-libs/value-note/src/filter.nr b/yarn-project/noir-libs/value-note/src/filter.nr index 37c61151009..7849747f3f1 100644 --- a/yarn-project/noir-libs/value-note/src/filter.nr +++ b/yarn-project/noir-libs/value-note/src/filter.nr @@ -2,14 +2,6 @@ use dep::std::option::Option; use dep::aztec::constants_gen::MAX_READ_REQUESTS_PER_CALL; use crate::value_note::ValueNote; -fn get_1_note

(notes: [Option; MAX_READ_REQUESTS_PER_CALL], _x: P) -> [Option; 1] { - [notes[0]] -} - -fn get_max_notes

(notes: [Option; MAX_READ_REQUESTS_PER_CALL], _x: P) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - notes -} - fn filter_notes_min_sum(notes: [Option; MAX_READ_REQUESTS_PER_CALL], min_sum: Field) -> [Option; MAX_READ_REQUESTS_PER_CALL] { let mut selected = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; let mut sum = 0; diff --git a/yarn-project/noir-libs/value-note/src/utils.nr b/yarn-project/noir-libs/value-note/src/utils.nr index 905c2bc63ae..4428ac70284 100644 --- a/yarn-project/noir-libs/value-note/src/utils.nr +++ b/yarn-project/noir-libs/value-note/src/utils.nr @@ -5,7 +5,7 @@ use dep::aztec::oracle::get_public_key::get_public_key; use dep::aztec::state_vars::set::Set; use dep::aztec::types::point::Point; use crate::{ - filter::{get_1_note, filter_notes_min_sum}, + filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN}, }; @@ -71,7 +71,7 @@ fn spend_one_note( owner: Field, spend_note_offset: u32, ) { - let options = NoteGetterOptions::with_filter_and_offset(get_1_note, 0, spend_note_offset); + let options = NoteGetterOptions::new().set_limit(1).set_offset(spend_note_offset); let opt_notes = balance.get_notes(context, options); // The note should always exist. From dd5593d339aa3742ac96a58ffcec12de73fd9922 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Sat, 19 Aug 2023 15:28:31 +0000 Subject: [PATCH 3/7] Change sort order to u2. --- .../noir-aztec/src/note/note_getter_options.nr | 12 ++++++------ .../noir-libs/noir-aztec/src/oracle/notes.nr | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr index efb7b11d387..84e01b49856 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_getter_options.nr @@ -13,9 +13,9 @@ impl Select { } struct SortOrderEnum { - DESC: u8, - ASC: u8, - NADA: u8, + DESC: u2, + ASC: u2, + NADA: u2, } global SortOrder = SortOrderEnum { @@ -26,11 +26,11 @@ global SortOrder = SortOrderEnum { struct Sort { field_index: u8, - order: u8, + order: u2, } impl Sort { - fn new(field_index: u8, order: u8) -> Self { + fn new(field_index: u8, order: u2) -> Self { Sort { field_index, order } } @@ -93,7 +93,7 @@ impl NoteGetterOptions { *self } - fn sort(&mut self, field_index: u8, order: u8) -> Self { + fn sort(&mut self, field_index: u8, order: u2) -> Self { let mut sorts = self.sorts; let mut updated = false; for i in 0..sorts.len() { diff --git a/yarn-project/noir-libs/noir-aztec/src/oracle/notes.nr b/yarn-project/noir-libs/noir-aztec/src/oracle/notes.nr index 198c193cc4e..e37ae3894cb 100644 --- a/yarn-project/noir-libs/noir-aztec/src/oracle/notes.nr +++ b/yarn-project/noir-libs/noir-aztec/src/oracle/notes.nr @@ -44,7 +44,7 @@ fn get_notes_oracle( _select_by: [u8; N], _select_values: [Field; N], _sort_by: [u8; N], - _sort_order: [u8; N], + _sort_order: [u2; N], _limit: u32, _offset: u32, _return_size: u32, @@ -57,7 +57,7 @@ unconstrained fn get_notes_oracle_wrapper( select_by: [u8; N], select_values: [Field; N], sort_by: [u8; N], - sort_order: [u8; N], + sort_order: [u2; N], limit: u32, offset: u32, mut placeholder_fields: [Field; S], @@ -73,7 +73,7 @@ unconstrained fn get_notes( select_by: [u8; M], select_values: [Field; M], sort_by: [u8; M], - sort_order: [u8; M], + sort_order: [u2; M], limit: u32, offset: u32, mut placeholder_opt_notes: [Option; S], // TODO: Remove it and use `limit` to initialise the note array. From ffcf35e5e33d823383cb1747933b8eba8a8d91b7 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 21 Aug 2023 11:24:32 +0000 Subject: [PATCH 4/7] View notes. --- .../easy_private_token_contract/src/main.nr | 2 +- .../non_native_token_contract/src/main.nr | 2 +- .../pokeable_token_contract/src/main.nr | 2 +- .../src/main.nr | 2 +- .../private_token_contract/src/main.nr | 2 +- yarn-project/noir-libs/noir-aztec/src/note.nr | 1 + .../noir-aztec/src/note/note_getter.nr | 67 ++++++++++--------- .../src/note/note_getter_options.nr | 23 ++----- .../src/note/note_viewer_options.nr | 47 +++++++++++++ .../src/state_vars/immutable_singleton.nr | 14 +++- .../noir-aztec/src/state_vars/set.nr | 12 +++- .../noir-aztec/src/state_vars/singleton.nr | 8 ++- .../noir-libs/noir-aztec/src/utils.nr | 14 ++++ .../noir-libs/value-note/src/balance_utils.nr | 20 +++--- 14 files changed, 147 insertions(+), 69 deletions(-) create mode 100644 yarn-project/noir-libs/noir-aztec/src/note/note_viewer_options.nr diff --git a/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr index 107dbdbd7e1..0feb908d29b 100644 --- a/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr @@ -98,7 +98,7 @@ contract EasyPrivateToken { let balances = storage.balances; // Return the sum of all notes in the set. - balance_utils::get_balance(balances.at(owner).storage_slot) + balance_utils::get_balance(balances.at(owner).set) } // Computes note hash and nullifier. diff --git a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr index 905316567b0..f9d277c1b9f 100644 --- a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr @@ -348,7 +348,7 @@ contract NonNativeToken { let storage = Storage::init(); let owner_balance = storage.balances.at(owner); - balance_utils::get_balance(owner_balance.storage_slot) + balance_utils::get_balance(owner_balance) } // Computes note hash and nullifier. diff --git a/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr index 6b9ada87194..757172d569c 100644 --- a/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr @@ -106,7 +106,7 @@ contract PokeableToken { let sender_balance = storage.balances.at(sender); // Return the sum of all notes in the set. - balance_utils::get_balance(sender_balance.storage_slot) + balance_utils::get_balance(sender_balance) } // Computes note hash and nullifier. diff --git a/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/main.nr index c7b09851e07..b9dbbd69f9a 100644 --- a/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/main.nr @@ -205,7 +205,7 @@ contract PrivateTokenAirdrop { let owner_balance = storage.balances.at(owner); // Return the sum of all notes in the set. - balance_utils::get_balance(owner_balance.storage_slot) + balance_utils::get_balance(owner_balance) } // Computes note hash and nullifier. diff --git a/yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr index a2b256a3ad0..beda6fdd7e3 100644 --- a/yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr @@ -102,7 +102,7 @@ contract PrivateToken { let owner_balance = storage.balances.at(owner); // Return the sum of all notes in the set. - balance_utils::get_balance(owner_balance.storage_slot) + balance_utils::get_balance(owner_balance) } // Computes note hash and nullifier. diff --git a/yarn-project/noir-libs/noir-aztec/src/note.nr b/yarn-project/noir-libs/noir-aztec/src/note.nr index 7cf4148a79e..d76f7090689 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note.nr @@ -4,4 +4,5 @@ mod note_getter_options; mod note_hash; mod note_header; mod note_interface; +mod note_viewer_options; mod utils; \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr index 221c9ed7f20..29eb19d6c10 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr @@ -8,9 +8,10 @@ use crate::constants_gen::{ }; use crate::context::PrivateContext; use crate::note::{ - note_getter_options::NoteGetterOptions, + note_getter_options::{NoteGetterOptions, Select, Sort}, note_interface::NoteInterface, note_header::NoteHeader, + note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_or_nullify, utils::compute_unique_siloed_note_hash, utils::compute_inner_note_hash, @@ -165,28 +166,7 @@ unconstrained fn get_notes_internal( note_interface: NoteInterface, options: NoteGetterOptions, ) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let selects = options.selects; - let mut num_selects = 0; - let mut select_by = [0; N]; - let mut select_values = [0; N]; - for i in 0..selects.len() { - if selects[i].is_some() { - select_by[num_selects] = selects[i].unwrap_unchecked().field_index; - select_values[num_selects] = selects[i].unwrap_unchecked().value; - num_selects += 1; - }; - }; - - let sorts = options.sorts; - let mut sort_by = [0; N]; - let mut sort_order = [0; N]; - for i in 0..sorts.len() { - if sorts[i].is_some() { - sort_by[i] = sorts[i].unwrap_unchecked().field_index; - sort_order[i] = sorts[i].unwrap_unchecked().order; - }; - }; - + let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; oracle::notes::get_notes( @@ -207,26 +187,49 @@ unconstrained fn get_notes_internal( unconstrained fn view_notes( storage_slot: Field, note_interface: NoteInterface, - limit: u32, - offset: u32, + options: NoteViewerOptions, ) -> [Option; MAX_NOTES_PER_PAGE] { - let select_by = [0; N]; - let select_values = [0; N]; - let sort_by = [0; N]; - let sort_order = [0; N]; + let (num_selects, select_by, select_values, sort_by, 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]; oracle::notes::get_notes( storage_slot, note_interface, - 0, + num_selects, select_by, select_values, sort_by, sort_order, - limit, - offset, + options.limit, + options.offset, placeholder_opt_notes, placeholder_fields, ) +} + +unconstrained fn flatten_options( + selects: [Option; N], + sorts: [Option; N], + limit: u32, + offset: u32, +} +// docs:end:NoteViewerOptions + +impl NoteViewerOptions { + fn new() -> NoteViewerOptions { + NoteViewerOptions { + selects: [Option::none(); N], + sorts: [Option::none(); N], + limit: MAX_NOTES_PER_PAGE as u32, + offset: 0, + } + } + + fn select(&mut self, field_index: u8, value: Field) -> Self { + let idx = get_array_size(self.selects); + self.selects[idx] = Option::some(Select::new(field_index, value)); + *self + } + + fn sort(&mut self, field_index: u8, order: u2) -> Self { + let idx = get_array_size(self.sorts); + self.sorts[idx] = Option::some(Sort::new(field_index, order)); + *self + } + + fn set_limit(&mut self, limit: u32) -> Self { + assert(limit <= MAX_NOTES_PER_PAGE as u32); + self.limit = limit; + *self + } + + fn set_offset(&mut self, offset: u32) -> Self { + self.offset = offset; + *self + } +} diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/immutable_singleton.nr b/yarn-project/noir-libs/noir-aztec/src/state_vars/immutable_singleton.nr index 87a065f32de..7280b26b246 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/immutable_singleton.nr +++ b/yarn-project/noir-libs/noir-aztec/src/state_vars/immutable_singleton.nr @@ -1,8 +1,11 @@ use dep::std::hash::pedersen_with_separator; use crate::context::PrivateContext; -use crate::note::lifecycle::create_note; -use crate::note::note_getter::get_note; -use crate::note::note_interface::NoteInterface; +use crate::note::{ + lifecycle::create_note, + note_getter::{get_note, view_notes}, + note_interface::NoteInterface, + note_viewer_options::NoteViewerOptions, +}; use crate::oracle; use crate::constants_gen::{ GENERATOR_INDEX__INITIALISATION_NULLIFIER, @@ -40,4 +43,9 @@ impl ImmutableSingleton { let storage_slot = self.storage_slot; get_note(context, storage_slot, self.note_interface) } + + unconstrained fn view_note(self) -> Note { + let options = NoteViewerOptions::new().set_limit(1); + view_notes(self.storage_slot, self.note_interface, options)[0].unwrap() + } } \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr b/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr index 46b4ce37d3c..035f139455c 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr +++ b/yarn-project/noir-libs/noir-aztec/src/state_vars/set.nr @@ -1,15 +1,16 @@ use dep::std::option::Option; use crate::abi::PublicContextInputs; -use crate::constants_gen::MAX_READ_REQUESTS_PER_CALL; +use crate::constants_gen::{MAX_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE}; use crate::context::{ PrivateContext, PublicContext, }; use crate::note::lifecycle::{create_note, create_note_hash_from_public, destroy_note}; use crate::note::{ - note_getter::{get_notes, ensure_note_exists, ensure_note_hash_exists}, + note_getter::{get_notes, ensure_note_exists, ensure_note_hash_exists, view_notes}, note_getter_options::NoteGetterOptions, note_interface::NoteInterface, + note_viewer_options::NoteViewerOptions, utils::compute_inner_note_hash, }; @@ -74,4 +75,11 @@ impl Set { let opt_notes = get_notes(context, storage_slot, self.note_interface, options); opt_notes } + + unconstrained fn view_notes( + self, + options: NoteViewerOptions, + ) -> [Option; MAX_NOTES_PER_PAGE] { + view_notes(self.storage_slot, self.note_interface, options) + } } diff --git a/yarn-project/noir-libs/noir-aztec/src/state_vars/singleton.nr b/yarn-project/noir-libs/noir-aztec/src/state_vars/singleton.nr index d6eb1c7725b..c87506dad3c 100644 --- a/yarn-project/noir-libs/noir-aztec/src/state_vars/singleton.nr +++ b/yarn-project/noir-libs/noir-aztec/src/state_vars/singleton.nr @@ -6,8 +6,9 @@ use crate::note::{ create_note, destroy_note, }, - note_getter::get_note, + note_getter::{get_note, view_notes}, note_interface::NoteInterface, + note_viewer_options::NoteViewerOptions, }; use crate::constants_gen::{ GENERATOR_INDEX__INITIALISATION_NULLIFIER, @@ -63,4 +64,9 @@ impl Singleton { note } + + unconstrained fn view_note(self) -> Note { + let options = NoteViewerOptions::new().set_limit(1); + view_notes(self.storage_slot, self.note_interface, options)[0].unwrap() + } } \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/utils.nr b/yarn-project/noir-libs/noir-aztec/src/utils.nr index 83b9863a2e3..57a04bc44db 100644 --- a/yarn-project/noir-libs/noir-aztec/src/utils.nr +++ b/yarn-project/noir-libs/noir-aztec/src/utils.nr @@ -1,3 +1,5 @@ +use dep::std::option::Option; + fn arr_copy_slice( src: [T; N], mut dst: [T; M], @@ -7,4 +9,16 @@ fn arr_copy_slice( dst[i] = src[i + offset]; } dst +} + +fn get_array_size(arr: [Option; N]) -> Field { + let mut size = arr.len(); + let mut found = false; + for i in 0..arr.len() { + if !found & arr[i].is_none() { + size = i; + found = true; + } + } + size } \ No newline at end of file diff --git a/yarn-project/noir-libs/value-note/src/balance_utils.nr b/yarn-project/noir-libs/value-note/src/balance_utils.nr index 9cac45acdbb..7f202b87de2 100644 --- a/yarn-project/noir-libs/value-note/src/balance_utils.nr +++ b/yarn-project/noir-libs/value-note/src/balance_utils.nr @@ -1,15 +1,19 @@ -use dep::aztec::constants_gen::MAX_NOTES_PER_PAGE; -use dep::aztec::note::note_getter::view_notes; -use crate::value_note::{VALUE_NOTE_LEN, ValueNoteMethods}; +use dep::aztec::note::{ + note_getter::view_notes, + note_viewer_options::NoteViewerOptions, +}; +use dep::aztec::state_vars::set::Set; +use crate::value_note::{VALUE_NOTE_LEN, ValueNote}; -unconstrained fn get_balance(storage_slot: Field) -> Field { - get_balance_internal(storage_slot, 0) +unconstrained fn get_balance(set: Set) -> Field { + get_balance_with_offset(set, 0) } -unconstrained fn get_balance_internal(storage_slot: Field, offset: u32) -> Field { +unconstrained fn get_balance_with_offset(set: Set, offset: u32) -> Field { let mut balance = 0; - let opt_notes = view_notes(storage_slot, ValueNoteMethods, MAX_NOTES_PER_PAGE as u32, offset); + let options = NoteViewerOptions::new().set_offset(offset); + let opt_notes = set.view_notes(options); let len = opt_notes.len(); for i in 0..len { if opt_notes[i].is_some() { @@ -17,7 +21,7 @@ unconstrained fn get_balance_internal(storage_slot: Field, offset: u32) -> Field } } if (opt_notes[len - 1].is_some()) { - balance += get_balance_internal(storage_slot, offset + MAX_NOTES_PER_PAGE as u32); + balance += get_balance_with_offset(set, offset + opt_notes.len() as u32); } balance From 8065aedbf6a6c1bda1e4c8911f865e61dd806bc4 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 21 Aug 2023 17:41:29 +0000 Subject: [PATCH 5/7] Better pick_notes interface. --- .../src/client/client_execution_context.ts | 8 +-- .../src/client/pick_notes.test.ts | 63 ++++++++++++++----- .../acir-simulator/src/client/pick_notes.ts | 61 +++++++++++------- 3 files changed, 90 insertions(+), 42 deletions(-) diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index c12f96e5173..64c1c0eac58 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -142,10 +142,10 @@ export class ClientTxExecutionContext { // Nullified pending notes are already removed from the list. const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { - selectBy: selectBy.slice(0, numSelects).map(field => +field), - selectValues: selectValues.slice(0, numSelects).map(field => fromACVMField(field)), - sortBy: sortBy.map(field => +field), - sortOrder: sortOrder.map(field => +field), + selects: selectBy + .slice(0, numSelects) + .map((fieldIndex, i) => ({ index: +fieldIndex, value: fromACVMField(selectValues[i]) })), + sorts: sortBy.map((fieldIndex, i) => ({ index: +fieldIndex, order: +sortOrder[i] })), limit, offset, }); diff --git a/yarn-project/acir-simulator/src/client/pick_notes.test.ts b/yarn-project/acir-simulator/src/client/pick_notes.test.ts index 8f130706cd1..f95d4d628e9 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.test.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.test.ts @@ -35,21 +35,26 @@ describe('getNotes', () => { // Sort 1st field in ascending order. { - const options = { sortBy: [1], sortOrder: [SortOrder.ASC] }; + const options = { sorts: [{ index: 1, 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 = { sortBy: [1] }; + const options = { sorts: [{ index: 1, order: SortOrder.DESC }] }; const result = pickNotes(notes, options); expectNotesFields(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 4n, 6n, 6n, 2n, 0n]]); } // Sort 1st and 0th fields in descending order. { - const options = { sortBy: [1, 0] }; + const options = { + sorts: [ + { index: 1, order: SortOrder.DESC }, + { index: 0, order: SortOrder.DESC }, + ], + }; const result = pickNotes(notes, options); expectNotesFields(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 6n, 6n, 4n, 2n, 0n]]); } @@ -57,7 +62,12 @@ describe('getNotes', () => { // Sort 1st field in descending order // Then 0th field in ascending order { - const options = { sortBy: [1, 0], sortOrder: [SortOrder.DESC, SortOrder.ASC] }; + const options = { + sorts: [ + { index: 1, order: SortOrder.DESC }, + { index: 0, order: SortOrder.ASC }, + ], + }; const result = pickNotes(notes, options); expectNotesFields( result, @@ -71,7 +81,13 @@ describe('getNotes', () => { // Then 0th field in ascending order // Then 2nd field in descending order. { - const options = { sortBy: [1, 0, 2], sortOrder: [SortOrder.DESC, SortOrder.ASC, SortOrder.DESC] }; + const options = { + sorts: [ + { index: 1, order: SortOrder.DESC }, + { index: 0, order: SortOrder.ASC }, + { index: 2, order: SortOrder.DESC }, + ], + }; const result = pickNotes(notes, options); expectNotesFields( result, @@ -85,23 +101,23 @@ describe('getNotes', () => { it('should get sorted notes in a range', () => { const notes = [createNote([2n]), createNote([8n]), createNote([6n]), createNote([5n]), createNote([0n])]; - const sortBy = [0]; + const sorts = [{ index: 0, order: SortOrder.DESC }]; // Sorted values: [8n, 6n, 5n, 2n, 0n] { - const options = { sortBy, limit: 3 }; + const options = { sorts, limit: 3 }; const result = pickNotes(notes, options); expectNotesFields(result, [0, [8n, 6n, 5n]]); } { - const options = { sortBy, limit: 3, offset: 1 }; + const options = { sorts, limit: 3, offset: 1 }; const result = pickNotes(notes, options); expectNotesFields(result, [0, [6n, 5n, 2n]]); } { - const options = { sortBy, limit: 3, offset: 4 }; + const options = { sorts, limit: 3, offset: 4 }; const result = pickNotes(notes, options); expectNotesFields(result, [0, [0n]]); } @@ -109,7 +125,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 = { sortBy: [0], sortOrder: [SortOrder.NADA] }; + const options = { sorts: [{ index: 0, order: SortOrder.NADA }] }; const result = pickNotes(notes, options); expectNotesFields(result, [0, [2n, 8n, 6n, 5n, 0n]]); }); @@ -124,7 +140,7 @@ describe('getNotes', () => { ]; { - const options = { selectBy: [0], selectValues: [new Fr(2n)] }; + const options = { selects: [{ index: 0, value: new Fr(2n) }] }; const result = pickNotes(notes, options); expectNotes(result, [ [2n, 1n, 3n], @@ -134,7 +150,12 @@ describe('getNotes', () => { } { - const options = { selectBy: [0, 2], selectValues: [new Fr(2n), new Fr(3n)] }; + const options = { + selects: [ + { index: 0, value: new Fr(2n) }, + { index: 2, value: new Fr(3n) }, + ], + }; const result = pickNotes(notes, options); expectNotes(result, [ [2n, 1n, 3n], @@ -143,19 +164,29 @@ describe('getNotes', () => { } { - const options = { selectBy: [1, 2], selectValues: [new Fr(2n), new Fr(3n)] }; + const options = { + selects: [ + { index: 1, value: new Fr(2n) }, + { index: 2, value: new Fr(3n) }, + ], + }; const result = pickNotes(notes, options); expectNotes(result, [[1n, 2n, 3n]]); } { - const options = { selectBy: [1], selectValues: [new Fr(5n)] }; + const options = { selects: [{ index: 1, value: new Fr(5n) }] }; const result = pickNotes(notes, options); expectNotes(result, []); } { - const options = { selectBy: [0, 1], selectValues: [new Fr(2), new Fr(5n)] }; + const options = { + selects: [ + { index: 0, value: new Fr(2n) }, + { index: 1, value: new Fr(5n) }, + ], + }; const result = pickNotes(notes, options); expectNotes(result, []); } @@ -171,7 +202,7 @@ describe('getNotes', () => { createNote([6n, 5n, 8n]), ]; - const options = { selectBy: [2], selectValues: [new Fr(8n)], sortBy: [1], sortOrder: [SortOrder.ASC] }; + const options = { selects: [{ index: 2, value: new Fr(8n) }], sorts: [{ index: 1, order: SortOrder.ASC }] }; const result = pickNotes(notes, options); expectNotes(result, [ [0n, 0n, 8n], diff --git a/yarn-project/acir-simulator/src/client/pick_notes.ts b/yarn-project/acir-simulator/src/client/pick_notes.ts index 535a0ca1ffa..db62f1e8ed1 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.ts @@ -1,5 +1,19 @@ import { Fr } from '@aztec/foundation/fields'; +/** + * Configuration for selecting values. + */ +export interface Select { + /** + * Index of the field to select and match. + */ + index: number; + /** + * Required value of the field. + */ + value: Fr; +} + /** * The order to sort an array. */ @@ -10,29 +24,33 @@ export enum SortOrder { } /** - * Options for selecting items from the database. + * Configuration for sorting values. */ -interface GetOptions { +export interface Sort { /** - * An array of indices of the fields to select. - * Default: empty array. + * Index of the field to sort. */ - selectBy?: number[]; + index: number; /** - * An array of values of the corresponding fields to select and match. - * Default: empty array. + * Order to sort the field. */ - selectValues?: Fr[]; + order: SortOrder; +} + +/** + * Options for picking items from an array of BasicNoteData. + */ +interface GetOptions { /** - * An array of indices of the fields to sort. + * Configurations for selecting items. * Default: empty array. */ - sortBy?: number[]; + selects?: Select[]; /** - * The order of the corresponding index in sortBy. (1: DESC, 2: ASC, 0: Do nothing) + * Configurations for sorting items. * Default: empty array. */ - sortOrder?: SortOrder[]; + sorts?: Sort[]; /** * The number of items to retrieve per query. * Default: 0. No limit. @@ -55,19 +73,18 @@ interface BasicNoteData { preimage: Fr[]; } -const selectNotes = (notes: T[], selectBy: number[], selectValues: Fr[]): T[] => - notes.filter(note => selectBy.every((fieldIndex, i) => note.preimage[fieldIndex]?.equals(selectValues[i]))); +const selectNotes = (notes: T[], selects: Select[]): T[] => + notes.filter(note => selects.every(({ index, value }) => note.preimage[index]?.equals(value))); -const sortNotes = (a: Fr[], b: Fr[], sortBy: number[], sortOrder: number[], level = 0): number => { - const index = sortBy[level]; - if (sortBy[level] === undefined) return 0; +const sortNotes = (a: Fr[], b: Fr[], sorts: Sort[], level = 0): number => { + if (sorts[level] === undefined) return 0; - const order = sortOrder[level] ?? 1; // Default: Descending. + const { index, order } = sorts[level]; if (order === 0) return 0; const dir = order === 1 ? [-1, 1] : [1, -1]; return a[index].value === b[index].value - ? sortNotes(a, b, sortBy, sortOrder, level + 1) + ? sortNotes(a, b, sorts, level + 1) : a[index].value > b[index].value ? dir[0] : dir[1]; @@ -78,9 +95,9 @@ const sortNotes = (a: Fr[], b: Fr[], sortBy: number[], sortOrder: number[], leve */ export function pickNotes( notes: T[], - { selectBy = [], selectValues = [], sortBy = [], sortOrder = [], limit = 0, offset = 0 }: GetOptions, + { selects = [], sorts = [], limit = 0, offset = 0 }: GetOptions, ) { - return selectNotes(notes, selectBy, selectValues) - .sort((a, b) => sortNotes(a.preimage, b.preimage, sortBy, sortOrder)) + return selectNotes(notes, selects) + .sort((a, b) => sortNotes(a.preimage, b.preimage, sorts)) .slice(offset, limit ? offset + limit : undefined); } From b2da69941fed71a144b31523a343eed7fc7571a9 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 21 Aug 2023 17:57:00 +0000 Subject: [PATCH 6/7] Use BoundedVec in options. --- .../noir-aztec/src/note/note_getter.nr | 23 +++++++++++-------- .../src/note/note_getter_options.nr | 20 ++++++++-------- .../src/note/note_viewer_options.nr | 16 ++++++------- .../noir-libs/noir-aztec/src/utils.nr | 14 ----------- 4 files changed, 29 insertions(+), 44 deletions(-) diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr index 29eb19d6c10..6a107c873bd 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr @@ -19,6 +19,7 @@ use crate::note::{ }; use crate::messaging::get_commitment_getter_data::make_commitment_getter_data; use crate::oracle; +use crate::types::vec::BoundedVec; fn check_note_header( context: PrivateContext, @@ -208,26 +209,28 @@ unconstrained fn view_notes( } unconstrained fn flatten_options( - selects: [Option; N], - sorts: [Option; N], + selects: BoundedVec, N>, + sorts: BoundedVec, N>, limit: u32, offset: u32, filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], @@ -58,8 +58,8 @@ struct NoteGetterOptions { impl NoteGetterOptions { fn new() -> NoteGetterOptions { NoteGetterOptions { - selects: [Option::none(); N], - sorts: [Option::none(); N], + selects: BoundedVec::new(Option::none()), + sorts: BoundedVec::new(Option::none()), limit: MAX_READ_REQUESTS_PER_CALL as u32, offset: 0, filter: return_all_notes, @@ -72,8 +72,8 @@ impl NoteGetterOptions { filter_args: FILTER_ARGS, ) -> Self { NoteGetterOptions { - selects: [Option::none(); N], - sorts: [Option::none(); N], + selects: BoundedVec::new(Option::none()), + sorts: BoundedVec::new(Option::none()), limit: 0, offset: 0, filter, @@ -82,14 +82,12 @@ impl NoteGetterOptions { } fn select(&mut self, field_index: u8, value: Field) -> Self { - let idx = get_array_size(self.selects); - self.selects[idx] = Option::some(Select::new(field_index, value)); + self.selects.push(Option::some(Select::new(field_index, value))); *self } fn sort(&mut self, field_index: u8, order: u2) -> Self { - let idx = get_array_size(self.sorts); - self.sorts[idx] = Option::some(Sort::new(field_index, order)); + self.sorts.push(Option::some(Sort::new(field_index, order))); *self } diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_viewer_options.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_viewer_options.nr index f47cc24ac9a..b4ce1a9a6a6 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_viewer_options.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_viewer_options.nr @@ -1,12 +1,12 @@ use dep::std::option::Option; use crate::constants_gen::MAX_NOTES_PER_PAGE; use crate::note::note_getter_options::{Select, Sort}; -use crate::utils::get_array_size; +use crate::types::vec::BoundedVec; // docs:start:NoteViewerOptions struct NoteViewerOptions { - selects: [Option