From 7457da0d94e91e22c9c7ece33394aa32577491c4 Mon Sep 17 00:00:00 2001 From: Colin Roberts Date: Wed, 18 Dec 2024 14:29:05 -0700 Subject: [PATCH] release: v0.7.0 (#81) * Update CHANGELOG.md * Update package.json * feat: optimized `HTTPVerification` (#82) * wip: better HTTP - Trying to reduce file size and constraints substantially - Also need to make this so it doesn't matter if there is padding around headers / etc. * WIP: improving HTTP digesting * WIP: http rewrite * WIP: almost working no-header test * WIP: working start/body * working tests! * cleanup * Update masker.circom * Update CHANGELOG.md * feat: hash-based JSON circuit (#41) * feat: hash based JSON verification * WIP: save * resetting for clearer approach * good save state * feat: working hash version Though this will be too expensive, the idea works! * WIP: need to clear after comma * WIP: good progress * WIP: getting keys also now * feat: (mostly?) working tree hasher * seems to be correct for spotify * perf: first optimization * wip: brain hurty left a note to myself * fix: tree hasher seems correct now * TODO: note to self * feat: hash based JSON verification * WIP: save * resetting for clearer approach * good save state * feat: working hash version Though this will be too expensive, the idea works! * WIP: need to clear after comma * WIP: good progress * WIP: getting keys also now * feat: (mostly?) working tree hasher * seems to be correct for spotify * perf: first optimization * wip: brain hurty left a note to myself * fix: tree hasher seems correct now * TODO: note to self * cleanup from rebase * cleanup * WIP: seems to monomial correctly * rename * add in value to eval at * WIP: start looking for matches * made some fixes * it may be working! * now i can write tests! * more tests * more JSON hasher tests * cleanup * remove excess stuff * adjust builds * fix: build * feat: manifest digest verification (#83) * feat: `PolynomialDigest` * WIP: working to get through NIVC * feat: HTTP circuit digesting * feat: ChaCha circuit digesting * feat: JSON circuit digesting * fix: `JSONExtraction` * IT WORKS * feat: TS init digest * feat: separate sequence/value * cleanup * fix: builds * fix: warnings * Update CHANGELOG.md * fix: PR feedback * Fix/http verification (#85) * fix: `zeroed_data` for `data_digest` in `http_verification` * add test for 1024 * cleanup readme --------- Co-authored-by: Sambhav Dusad --- CHANGELOG.md | 34 +- README.md | 12 +- .../json_extract_value_1024b.circom | 5 - .../target_1024b/json_extraction_1024b.circom | 5 + .../json_mask_array_index_1024b.circom | 5 - .../json_mask_object_1024b.circom | 5 - .../plaintext_authentication_1024b.circom | 4 +- .../json_extract_value_512b.circom | 5 - .../target_512b/json_extraction_512b.circom | 5 + .../json_mask_array_index_512b.circom | 5 - .../target_512b/json_mask_object_512b.circom | 5 - .../plaintext_authentication_512b.circom | 4 +- circuits.json | 23 +- ...ha20_nivc.circom => authentication.circom} | 39 +- circuits/http/verification.circom | 115 +++-- circuits/json/extraction.circom | 127 +++++ circuits/json/hash_machine.circom | 431 ++++++++++++++++ circuits/json/interpreter.circom | 474 ------------------ circuits/json/{parser => }/language.circom | 0 circuits/json/{parser => }/machine.circom | 4 +- circuits/json/nivc/extractor.circom | 32 -- circuits/json/nivc/masker.circom | 136 ----- circuits/json/{parser => }/parser.circom | 0 ...20-nivc.test.ts => authentication.test.ts} | 85 +--- circuits/test/chacha20/chacha20.test.ts | 131 ++--- circuits/test/common/index.ts | 345 +++++++++++-- circuits/test/common/poseidon.ts | 2 +- circuits/test/full/full.test.ts | 363 ++++---------- circuits/test/http/verification.test.ts | 221 ++++---- circuits/test/json/extraction.test.ts | 194 +++++++ .../test/json/extractor/interpreter.test.ts | 445 ---------------- circuits/test/json/{parser => }/index.ts | 0 circuits/test/json/nivc/masker_nivc.test.ts | 171 ------- .../test/json/{parser => }/parser.test.ts | 10 +- .../json/{parser => }/parsing_types.test.ts | 10 +- circuits/test/json/{parser => }/stack.test.ts | 10 +- .../test/json/{parser => }/values.test.ts | 6 +- circuits/test/utils/array.test.ts | 8 +- circuits/test/utils/bits.test.ts | 25 - circuits/test/utils/hash.test.ts | 265 ++++------ circuits/test/utils/operators.test.ts | 3 - circuits/test/utils/search.test.ts | 39 -- circuits/utils/array.circom | 3 +- circuits/utils/bits.circom | 19 - circuits/utils/hash.circom | 90 ++-- circuits/utils/search.circom | 36 -- docs/images/v0.7.0.png | Bin 0 -> 329524 bytes examples/json/array_only.json | 1 + examples/json/{response => }/reddit.json | 0 examples/json/response/spotify.json | 45 -- examples/json/spotify.json | 1 + examples/json/string_escape.json | 1 + examples/json/test/array_only.json | 11 - examples/json/test/string_escape.json | 1 - examples/json/test/value_array.json | 1 - examples/json/test/value_array_object.json | 1 - examples/json/test/value_object.json | 1 - examples/json/value_array.json | 1 + examples/json/value_array_object.json | 1 + examples/json/value_object.json | 1 + examples/json/{response => }/venmo.json | 0 package.json | 2 +- src/main.rs | 4 +- 63 files changed, 1669 insertions(+), 2359 deletions(-) delete mode 100644 builds/target_1024b/json_extract_value_1024b.circom create mode 100644 builds/target_1024b/json_extraction_1024b.circom delete mode 100644 builds/target_1024b/json_mask_array_index_1024b.circom delete mode 100644 builds/target_1024b/json_mask_object_1024b.circom delete mode 100644 builds/target_512b/json_extract_value_512b.circom create mode 100644 builds/target_512b/json_extraction_512b.circom delete mode 100644 builds/target_512b/json_mask_array_index_512b.circom delete mode 100644 builds/target_512b/json_mask_object_512b.circom rename circuits/chacha20/{nivc/chacha20_nivc.circom => authentication.circom} (75%) create mode 100644 circuits/json/extraction.circom create mode 100644 circuits/json/hash_machine.circom delete mode 100644 circuits/json/interpreter.circom rename circuits/json/{parser => }/language.circom (100%) rename circuits/json/{parser => }/machine.circom (99%) delete mode 100644 circuits/json/nivc/extractor.circom delete mode 100644 circuits/json/nivc/masker.circom rename circuits/json/{parser => }/parser.circom (100%) rename circuits/test/chacha20/{chacha20-nivc.test.ts => authentication.test.ts} (67%) create mode 100644 circuits/test/json/extraction.test.ts delete mode 100644 circuits/test/json/extractor/interpreter.test.ts rename circuits/test/json/{parser => }/index.ts (100%) delete mode 100644 circuits/test/json/nivc/masker_nivc.test.ts rename circuits/test/json/{parser => }/parser.test.ts (69%) rename circuits/test/json/{parser => }/parsing_types.test.ts (94%) rename circuits/test/json/{parser => }/stack.test.ts (96%) rename circuits/test/json/{parser => }/values.test.ts (98%) delete mode 100644 circuits/test/utils/bits.test.ts delete mode 100644 circuits/test/utils/search.test.ts delete mode 100644 circuits/utils/search.circom create mode 100644 docs/images/v0.7.0.png create mode 100644 examples/json/array_only.json rename examples/json/{response => }/reddit.json (100%) delete mode 100644 examples/json/response/spotify.json create mode 100644 examples/json/spotify.json create mode 100644 examples/json/string_escape.json delete mode 100644 examples/json/test/array_only.json delete mode 100644 examples/json/test/string_escape.json delete mode 100644 examples/json/test/value_array.json delete mode 100644 examples/json/test/value_array_object.json delete mode 100644 examples/json/test/value_object.json create mode 100644 examples/json/value_array.json create mode 100644 examples/json/value_array_object.json create mode 100644 examples/json/value_object.json rename examples/json/{response => }/venmo.json (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ce1a66..27f895c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,37 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.7.0] - 2024-12-3 + +### Added +### Changed +#### Circuit Builds +#### Artifacts +- **Circuit sizes:** + - `plaintext_authentication_1024b`: + - non-linear constaints: `383,102` + - R1CS file: `123.4MB` + - Graph file: `19.9MB` + - `http_verification_1024b`: + - non-linear constaints: `121,376` + - R1CS file: `80.7MB` + - Graph file: `4.4MB` + - **WARNING:** Extremely slow build with `--O2` flag. Need to investigate. + - `json_extraction_1024b`: + - non-linear constaints: `452,683` + - R1CS file: `90.3MB` + - Graph file: `13.2MB` + - **Total size:** `243.7MB` +- **Circuit param file sizes (SNARK):** + - `aux_params`: `62.2MB` + - `prover_key`: `50.3MB` + - `verifier_key`: `415.3MB` + +### Notes + +--- -## [UNRELEASED] [0.6.0] - 2024-12-3 +## [0.6.0] - 2024-12-3 ### Added @@ -21,9 +50,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Runs with `512b` per fold - `http_nivc` replaced with more suitable name: `http_verification` -### Fixed -- TODO - ### Notes - **Total circuits:** 5 - **Circuit sizes:** diff --git a/README.md b/README.md index 1c96613..ce212e8 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,10 @@ ## Overview -`web-prover-circuits` is a project focused on implementing parsers and extractors/selective-disclosure for various data formats inside zero-knowledge circuits. +`web-prover-circuits` is a project focused on implementing parsers and extractors/selective-disclosure for various data formats inside zero-knowledge circuits. +Specifically, these are designed to be used in an NIVC folding scheme. +Currently, our program layout looks like this: +![v0.7.0](docs/images/v0.7.0.png) ## Repository Structure @@ -94,12 +97,7 @@ npx circomkit compile plaintext_authentication_1024b ``` which implicitly checks the `circuits.json` for an object that points to the circuit's code itself. -If you are having trouble with `circomkit`, consider: - -##### SNARKJS -Likewise, `snarkjs` is used to handle proofs and verification under the hood. -There is [documentation](https://docs.circom.io/getting-started/compiling-circuits/) on Circom's usage to work with this. -We suggest starting at that link and carrying through to "Proving circuits with ZK". +If you are having trouble with `circomkit`, consider ##### Mocha `mocha` will also be installed from before. diff --git a/builds/target_1024b/json_extract_value_1024b.circom b/builds/target_1024b/json_extract_value_1024b.circom deleted file mode 100644 index fffbc10..0000000 --- a/builds/target_1024b/json_extract_value_1024b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/extractor.circom"; - -component main { public [step_in] } = MaskExtractFinal(1024, 50); \ No newline at end of file diff --git a/builds/target_1024b/json_extraction_1024b.circom b/builds/target_1024b/json_extraction_1024b.circom new file mode 100644 index 0000000..890a096 --- /dev/null +++ b/builds/target_1024b/json_extraction_1024b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/extraction.circom"; + +component main { public [step_in] } = JSONExtraction(1024, 10); \ No newline at end of file diff --git a/builds/target_1024b/json_mask_array_index_1024b.circom b/builds/target_1024b/json_mask_array_index_1024b.circom deleted file mode 100644 index d2793c8..0000000 --- a/builds/target_1024b/json_mask_array_index_1024b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/masker.circom"; - -component main { public [step_in] } = JsonMaskArrayIndexNIVC(1024, 10); \ No newline at end of file diff --git a/builds/target_1024b/json_mask_object_1024b.circom b/builds/target_1024b/json_mask_object_1024b.circom deleted file mode 100644 index e91d812..0000000 --- a/builds/target_1024b/json_mask_object_1024b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/masker.circom"; - -component main { public [step_in] } = JsonMaskObjectNIVC(1024, 10, 10); diff --git a/builds/target_1024b/plaintext_authentication_1024b.circom b/builds/target_1024b/plaintext_authentication_1024b.circom index 5b82c7d..89fde4e 100644 --- a/builds/target_1024b/plaintext_authentication_1024b.circom +++ b/builds/target_1024b/plaintext_authentication_1024b.circom @@ -1,5 +1,5 @@ pragma circom 2.1.9; -include "../../circuits/chacha20/nivc/chacha20_nivc.circom"; +include "../../circuits/chacha20/authentication.circom"; -component main { public [step_in] } = ChaCha20_NIVC(1024); \ No newline at end of file +component main { public [step_in] } = PlaintextAuthentication(1024); \ No newline at end of file diff --git a/builds/target_512b/json_extract_value_512b.circom b/builds/target_512b/json_extract_value_512b.circom deleted file mode 100644 index 600cc0a..0000000 --- a/builds/target_512b/json_extract_value_512b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/extractor.circom"; - -component main { public [step_in] } = MaskExtractFinal(512, 50); \ No newline at end of file diff --git a/builds/target_512b/json_extraction_512b.circom b/builds/target_512b/json_extraction_512b.circom new file mode 100644 index 0000000..52b216a --- /dev/null +++ b/builds/target_512b/json_extraction_512b.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.9; + +include "../../circuits/json/extraction.circom"; + +component main { public [step_in] } = JSONExtraction(512, 10); \ No newline at end of file diff --git a/builds/target_512b/json_mask_array_index_512b.circom b/builds/target_512b/json_mask_array_index_512b.circom deleted file mode 100644 index ec72dc7..0000000 --- a/builds/target_512b/json_mask_array_index_512b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/masker.circom"; - -component main { public [step_in] } = JsonMaskArrayIndexNIVC(512, 10); \ No newline at end of file diff --git a/builds/target_512b/json_mask_object_512b.circom b/builds/target_512b/json_mask_object_512b.circom deleted file mode 100644 index 3bd0e31..0000000 --- a/builds/target_512b/json_mask_object_512b.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.9; - -include "../../circuits/json/nivc/masker.circom"; - -component main { public [step_in] } = JsonMaskObjectNIVC(512, 10, 10); diff --git a/builds/target_512b/plaintext_authentication_512b.circom b/builds/target_512b/plaintext_authentication_512b.circom index f0c99ff..30388e9 100644 --- a/builds/target_512b/plaintext_authentication_512b.circom +++ b/builds/target_512b/plaintext_authentication_512b.circom @@ -1,5 +1,5 @@ pragma circom 2.1.9; -include "../../circuits/chacha20/nivc/chacha20_nivc.circom"; +include "../../circuits/chacha20/authentication.circom"; -component main { public [step_in] } = ChaCha20_NIVC(512); \ No newline at end of file +component main { public [step_in] } = PlaintextAuthentication(512); \ No newline at end of file diff --git a/circuits.json b/circuits.json index 8ed4b53..06e5fd9 100644 --- a/circuits.json +++ b/circuits.json @@ -14,29 +14,12 @@ 25 ] }, - "json_mask_object_1024b": { - "file": "json/nivc/masker", - "template": "JsonMaskObjectNIVC", + "json_extraction_1024b": { + "file": "json/extraction", + "template": "JSONExtraction", "params": [ 1024, - 10, 10 ] - }, - "json_mask_array_index_1024b": { - "file": "json/nivc/masker", - "template": "JsonMaskArrayIndexNIVC", - "params": [ - 1024, - 10 - ] - }, - "json_extract_value_1024b": { - "file": "json/nivc/extractor", - "template": "MaskExtractFinal", - "params": [ - 1024, - 50 - ] } } \ No newline at end of file diff --git a/circuits/chacha20/nivc/chacha20_nivc.circom b/circuits/chacha20/authentication.circom similarity index 75% rename from circuits/chacha20/nivc/chacha20_nivc.circom rename to circuits/chacha20/authentication.circom index e969b9d..973feef 100644 --- a/circuits/chacha20/nivc/chacha20_nivc.circom +++ b/circuits/chacha20/authentication.circom @@ -2,11 +2,12 @@ // modified for our needs pragma circom 2.1.9; -include "../chacha-round.circom"; -include "../chacha-qr.circom"; -include "../../utils/bits.circom"; -include "../../utils/hash.circom"; -include "../../utils/array.circom"; +include "chacha-round.circom"; +include "chacha-qr.circom"; +include "../utils/bits.circom"; +include "../utils/hash.circom"; +include "../utils/array.circom"; +include "circomlib/circuits/poseidon.circom"; /** ChaCha20 in counter mode */ @@ -23,7 +24,7 @@ include "../../utils/array.circom"; // | # | N | N | N | // +---+---+---+---+ // paramaterized by `DATA_BYTES` which is the plaintext length in bytes -template ChaCha20_NIVC(DATA_BYTES) { +template PlaintextAuthentication(DATA_BYTES) { // key => 8 32-bit words = 32 bytes signal input key[8][32]; // nonce => 3 32-bit words = 12 bytes @@ -33,22 +34,22 @@ template ChaCha20_NIVC(DATA_BYTES) { // the below can be both ciphertext or plaintext depending on the direction // in => N 32-bit words => N 4 byte words - signal input plainText[DATA_BYTES]; + signal input plaintext[DATA_BYTES]; - // step_in should be the ciphertext digest + // step_in should be the ciphertext digest + the HTTP digests + JSON seq digest signal input step_in[1]; // step_out should be the plaintext digest signal output step_out[1]; - signal isPadding[DATA_BYTES]; + signal isPadding[DATA_BYTES]; // == 1 in the case we hit padding number signal plaintextBits[DATA_BYTES / 4][32]; component toBits[DATA_BYTES / 4]; for (var i = 0 ; i < DATA_BYTES / 4 ; i++) { toBits[i] = fromWords32ToLittleEndian(); for (var j = 0 ; j < 4 ; j++) { - isPadding[i * 4 + j] <== IsEqual()([plainText[i * 4 + j], -1]); - toBits[i].words[j] <== (1 - isPadding[i * 4 + j]) * plainText[i*4 + j]; + isPadding[i * 4 + j] <== IsEqual()([plaintext[i * 4 + j], -1]); + toBits[i].words[j] <== (1 - isPadding[i * 4 + j]) * plaintext[i*4 + j]; } plaintextBits[i] <== toBits[i].data; } @@ -130,7 +131,7 @@ template ChaCha20_NIVC(DATA_BYTES) { component toCiphertextBytes[DATA_BYTES / 4]; signal bigEndianCiphertext[DATA_BYTES]; - + for (var i = 0 ; i < DATA_BYTES / 4 ; i++) { toCiphertextBytes[i] = fromLittleEndianToWords32(); for (var j = 0 ; j < 32 ; j++) { @@ -141,9 +142,15 @@ template ChaCha20_NIVC(DATA_BYTES) { } } - signal ciphertext_hash <== DataHasher(DATA_BYTES)(bigEndianCiphertext); - step_in[0] === ciphertext_hash; + signal ciphertext_digest <== DataHasher(DATA_BYTES)(bigEndianCiphertext); - signal plaintext_hash <== DataHasher(DATA_BYTES)(plainText); - step_out[0] <== plaintext_hash; + signal zeroed_plaintext[DATA_BYTES]; + for(var i = 0 ; i < DATA_BYTES ; i++) { + // Sets any padding bytes to zero (which are presumably at the end) so they don't accum into the poly hash + zeroed_plaintext[i] <== (1 - isPadding[i]) * plaintext[i]; + } + signal plaintext_digest <== PolynomialDigest(DATA_BYTES)(zeroed_plaintext, ciphertext_digest); + signal plaintext_digest_hashed <== Poseidon(1)([plaintext_digest]); + // TODO: I'm not sure we need to subtract the CT digest + step_out[0] <== step_in[0] - ciphertext_digest + plaintext_digest_hashed; } \ No newline at end of file diff --git a/circuits/http/verification.circom b/circuits/http/verification.circom index a88b480..6c53dc4 100644 --- a/circuits/http/verification.circom +++ b/circuits/http/verification.circom @@ -1,22 +1,32 @@ pragma circom 2.1.9; include "machine.circom"; +// TODO: we don't need this if we do a poly digest of the plaintext in authentication circuit include "../utils/hash.circom"; template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { signal input step_in[1]; signal output step_out[1]; - // Authenticate the plaintext we are passing in + signal input ciphertext_digest; + signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; + signal isPadding[DATA_BYTES]; // == 1 in the case we hit padding number + signal zeroed_data[DATA_BYTES]; + for (var i = 0 ; i < DATA_BYTES ; i++) { + isPadding[i] <== IsEqual()([data[i], -1]); + zeroed_data[i] <== (1 - isPadding[i]) * data[i]; + } + signal data_digest <== PolynomialDigest(DATA_BYTES)(zeroed_data, ciphertext_digest); - signal input start_line_hash; - signal input header_hashes[MAX_NUMBER_OF_HEADERS]; - signal input body_hash; + signal input main_digests[MAX_NUMBER_OF_HEADERS + 1]; // Contains digests of start line and all intended headers (up to `MAX_NUMBER_OF_HEADERS`) + signal not_contained[MAX_NUMBER_OF_HEADERS + 1]; + var num_to_match = MAX_NUMBER_OF_HEADERS + 1; + for(var i = 0 ; i < MAX_NUMBER_OF_HEADERS + 1 ; i++) { + not_contained[i] <== IsZero()(main_digests[i]); + num_to_match -= not_contained[i]; + } - // TODO: could just have a parser template and reduce code here component State[DATA_BYTES]; State[0] = HttpStateUpdate(); State[0].byte <== data[0]; @@ -38,46 +48,55 @@ template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { State[data_idx].line_status <== State[data_idx - 1].next_line_status; } - // Get the start line shit - signal start_line[DATA_BYTES]; - signal not_start_line_mask[DATA_BYTES]; - for(var i = 0 ; i < DATA_BYTES ; i++) { - not_start_line_mask[i] <== IsZero()(State[i].parsing_start); - start_line[i] <== data[i] * (1 - not_start_line_mask[i]); - } - signal inner_start_line_hash <== DataHasher(DATA_BYTES)(start_line); - signal start_line_hash_equal_check <== IsEqual()([inner_start_line_hash, start_line_hash]); - start_line_hash_equal_check === 1; + signal main_monomials[DATA_BYTES]; + main_monomials[0] <== 1; - // Get the header shit - signal header[MAX_NUMBER_OF_HEADERS][DATA_BYTES]; - signal header_masks[MAX_NUMBER_OF_HEADERS][DATA_BYTES]; - for(var i = 0 ; i < MAX_NUMBER_OF_HEADERS ; i++) { - for(var j = 0 ; j < DATA_BYTES ; j++) { - header_masks[i][j] <== IsEqual()([State[j].parsing_header, i + 1]); - header[i][j] <== data[j] * header_masks[i][j]; - } - } - signal inner_header_hashes[MAX_NUMBER_OF_HEADERS]; - signal header_is_unused[MAX_NUMBER_OF_HEADERS]; // If a header hash is passed in as 0, it is not used (no way to compute preimage of 0) - signal header_hashes_equal_check[MAX_NUMBER_OF_HEADERS]; - for(var i = 0 ; i < MAX_NUMBER_OF_HEADERS ; i++) { - header_is_unused[i] <== IsZero()(header_hashes[i]); - inner_header_hashes[i] <== DataHasher(DATA_BYTES)(header[i]); - header_hashes_equal_check[i] <== IsEqual()([(1 - header_is_unused[i]) * inner_header_hashes[i], header_hashes[i]]); - header_hashes_equal_check[i] === 1; + signal is_line_change[DATA_BYTES-1]; + signal was_cleared[DATA_BYTES-1]; + signal not_body_and_not_line_change[DATA_BYTES-1]; + + signal rescaled_or_was_cleared[DATA_BYTES-1]; + for(var i = 0 ; i < DATA_BYTES - 1 ; i++) { + is_line_change[i] <== Contains(2)(data[i + 1], [10, 13]); // capture if we hit an end line sequence + was_cleared[i] <== IsZero()(main_monomials[i]); + not_body_and_not_line_change[i] <== (1 - State[i + 1].parsing_body) * (1 - is_line_change[i]); + rescaled_or_was_cleared[i] <== (main_monomials[i] * ciphertext_digest + was_cleared[i]); + main_monomials[i + 1] <== not_body_and_not_line_change[i] * rescaled_or_was_cleared[i]; } - // Get the body shit - signal body[DATA_BYTES]; + signal is_match[DATA_BYTES]; + signal contains[DATA_BYTES]; + signal is_zero[DATA_BYTES]; + signal monomial_is_zero[DATA_BYTES]; + signal accum_prev[DATA_BYTES]; + var num_matched = 0; + signal inner_main_digest[DATA_BYTES + 1]; + inner_main_digest[0] <== 0; for(var i = 0 ; i < DATA_BYTES ; i++) { - body[i] <== data[i] * State[i].parsing_body; + monomial_is_zero[i] <== IsZero()(main_monomials[i]); + accum_prev[i] <== (1 - monomial_is_zero[i]) * inner_main_digest[i]; + inner_main_digest[i+1] <== accum_prev[i] + data[i] * main_monomials[i]; + is_zero[i] <== IsZero()(inner_main_digest[i+1]); + contains[i] <== Contains(MAX_NUMBER_OF_HEADERS + 1)(inner_main_digest[i+1], main_digests); + is_match[i] <== (1 - is_zero[i]) * contains[i]; + num_matched += is_match[i]; } - signal inner_body_hash <== DataHasher(DATA_BYTES)(body); - signal body_hash_equal_check <== IsEqual()([inner_body_hash, body_hash]); - body_hash_equal_check === 1; + num_matched === num_to_match; - step_out[0] <== inner_body_hash; + // BODY + signal body_monomials[DATA_BYTES]; + signal body_accum[DATA_BYTES]; + signal body_switch[DATA_BYTES -1]; + signal body_digest[DATA_BYTES]; + body_monomials[0] <== 0; + body_accum[0] <== 0; + body_digest[0] <== 0; + for(var i = 0 ; i < DATA_BYTES - 1 ; i++) { + body_accum[i + 1] <== body_accum[i] + State[i + 1].parsing_body; + body_switch[i] <== IsEqual()([body_accum[i + 1], 1]); + body_monomials[i + 1] <== body_monomials[i] * ciphertext_digest + body_switch[i]; + body_digest[i + 1] <== body_digest[i] + body_monomials[i + 1] * zeroed_data[i + 1]; + } // Verify machine ends in a valid state State[DATA_BYTES - 1].next_parsing_start === 0; @@ -86,4 +105,18 @@ template HTTPVerification(DATA_BYTES, MAX_NUMBER_OF_HEADERS) { State[DATA_BYTES - 1].next_parsing_field_value === 0; State[DATA_BYTES - 1].next_parsing_body === 1; State[DATA_BYTES - 1].next_line_status === 0; + + // TODO: Need to subtract all the header digests here and also wrap them in poseidon. We can use the ones from the input to make this cheaper since they're verified in this circuit! + signal body_digest_hashed <== Poseidon(1)([body_digest[DATA_BYTES - 1]]); + signal data_digest_hashed <== Poseidon(1)([data_digest]); + signal option_hash[MAX_NUMBER_OF_HEADERS + 1]; + signal main_digests_hashed[MAX_NUMBER_OF_HEADERS + 1]; + var accumulated_main_digests_hashed = 0; + for(var i = 0 ; i < MAX_NUMBER_OF_HEADERS + 1 ; i++) { + option_hash[i] <== Poseidon(1)([main_digests[i]]); + main_digests_hashed[i] <== (1 - not_contained[i]) * option_hash[i]; + accumulated_main_digests_hashed += main_digests_hashed[i]; + } + + step_out[0] <== step_in[0] + body_digest_hashed - accumulated_main_digests_hashed - data_digest_hashed; // TODO: data_digest is really plaintext_digest from before, consider changing names } diff --git a/circuits/json/extraction.circom b/circuits/json/extraction.circom new file mode 100644 index 0000000..e5185c9 --- /dev/null +++ b/circuits/json/extraction.circom @@ -0,0 +1,127 @@ +pragma circom 2.1.9; + +include "../utils/bits.circom"; +include "hash_machine.circom"; + +template JSONExtraction(DATA_BYTES, MAX_STACK_HEIGHT) { + signal input data[DATA_BYTES]; + signal input ciphertext_digest; + signal input sequence_digest; + signal input value_digest; + + signal input step_in[1]; + signal output step_out[1]; + + //--------------------------------------------------------------------------------------------// + component State[DATA_BYTES]; + + // Set up monomials for stack/tree digesting + signal monomials[3 * MAX_STACK_HEIGHT]; + monomials[0] <== 1; + for(var i = 1 ; i < 3 * MAX_STACK_HEIGHT ; i++) { + monomials[i] <== monomials[i - 1] * ciphertext_digest; + } + signal intermediate_digest[DATA_BYTES][3 * MAX_STACK_HEIGHT]; + signal state_digest[DATA_BYTES]; + + // Debugging + // for(var i = 0; i 44` - - out <== isNextPair*isComma ; -} - -/// Returns whether next key-value pair starts. -/// Applies following checks: -/// - get top of stack value and check whether parsing key: `[1, 0]` -/// - current byte = `,` -/// - current stack height is less than the key to be matched (it means that new key has started) -/// -/// # Arguments -/// - `n`: maximum stack depth -/// - `depth`: depth of matched key-value pair -/// -/// # Inputs -/// - `stack`: current stack state -/// - `curr_byte`: current parsed byte -/// -/// # Output -/// - `out`: Returns `1` for next key-value pair at specified depth. -template NextKVPairAtDepth(n) { - signal input stack[n][2]; - signal input currByte; - signal input depth; - signal output out; - - var logMaxDepth = log2Ceil(n+1); - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal currentVal[2] <== topOfStack.value; - signal pointer <== topOfStack.pointer; - - signal isNextPair <== IsEqualArray(2)([currentVal, [1, 0]]); - - // `,` -> 44 - signal isComma <== IsEqual()([currByte, 44]); - // pointer <= depth - // TODO: `LessThan` circuit warning - signal atLessDepth <== LessEqThan(logMaxDepth)([pointer-1, depth]); - // current depth is less than key depth - signal isCommaAtDepthLessThanCurrent <== isComma * atLessDepth; - - out <== isNextPair * isCommaAtDepthLessThanCurrent; -} - -/// Matches a JSON key at an `index` using Substring Matching -/// -/// # Arguments -/// - `dataLen`: parsed data length -/// - `keyLen`: key length -/// -/// # Inputs -/// - `data`: data bytes -/// - `key`: key bytes -/// - `r`: random number for substring matching. **Need to be chosen carefully.** -/// - `index`: data index to match from -/// - `parsing_key`: if current byte is inside a key -/// -/// # Output -/// - `out`: Returns `1` if `key` matches `data` at `index` -template KeyMatch(dataLen, keyLen) { - signal input data[dataLen]; - signal input key[keyLen]; - signal input index; - signal input parsing_key; - - // `"` -> 34 - signal end_of_key <== IndexSelector(dataLen)(data, index + keyLen); - signal is_end_of_key_equal_to_quote <== IsEqual()([end_of_key, 34]); - - signal start_of_key <== IndexSelector(dataLen)(data, index - 1); - signal is_start_of_key_equal_to_quote <== IsEqual()([start_of_key, 34]); - - signal substring_match <== SubstringMatchWithIndex(dataLen, keyLen)(data, key, index); - - signal is_key_between_quotes <== is_start_of_key_equal_to_quote * is_end_of_key_equal_to_quote; - signal is_parsing_correct_key <== is_key_between_quotes * parsing_key; - - signal output out <== substring_match * is_parsing_correct_key; -} - -/// Matches a JSON key at an `index` using Substring Matching at specified depth -/// -/// # Arguments -/// - `dataLen`: parsed data length -/// - `n`: maximum stack height -/// - `keyLen`: key length -/// - `depth`: depth of key to be matched -/// -/// # Inputs -/// - `data`: data bytes -/// - `key`: key bytes -/// - `r`: random number for substring matching. **Need to be chosen carefully.** -/// - `index`: data index to match from -/// - `parsing_key`: if current byte is inside a key -/// - `stack`: parser stack output -/// -/// # Output -/// - `out`: Returns `1` if `key` matches `data` at `index` -template KeyMatchAtDepth(dataLen, n, keyLen, depth) { - signal input data[dataLen]; - signal input key[keyLen]; - signal input index; - signal input parsing_key; - signal input stack[n][2]; - - component topOfStack = GetTopOfStack(n); - topOfStack.stack <== stack; - signal pointer <== topOfStack.pointer; - _ <== topOfStack.value; - - // `"` -> 34 - - // end of key equals `"` - signal end_of_key <== IndexSelector(dataLen)(data, index + keyLen); - signal is_end_of_key_equal_to_quote <== IsEqual()([end_of_key, 34]); - - // start of key equals `"` - signal start_of_key <== IndexSelector(dataLen)(data, index - 1); - signal is_start_of_key_equal_to_quote <== IsEqual()([start_of_key, 34]); - - // key matches - signal substring_match <== SubstringMatchWithIndex(dataLen, keyLen)(data, key, index); - - // key should be a string - signal is_key_between_quotes <== is_start_of_key_equal_to_quote * is_end_of_key_equal_to_quote; - - // is the index given correct? - signal is_parsing_correct_key <== is_key_between_quotes * parsing_key; - // is the key given by index at correct depth? - signal is_key_at_depth <== IsEqual()([pointer-1, depth]); - - signal is_parsing_correct_key_at_depth <== is_parsing_correct_key * is_key_at_depth; - - signal output out <== substring_match * is_parsing_correct_key_at_depth; -} - -template MatchPaddedKey(n) { - signal input in[2][n]; - signal input keyLen; - signal output out; - - var accum = 0; - component equalComponent[n]; - component isPaddedElement[n]; - - signal isEndOfKey[n]; - signal isQuote[n]; - signal endOfKeyAccum[n+1]; - endOfKeyAccum[0] <== 0; - - for(var i = 0; i < n; i++) { - isEndOfKey[i] <== IsEqual()([i, keyLen]); - isQuote[i] <== IsEqual()([in[1][i], 34]); - endOfKeyAccum[i+1] <== endOfKeyAccum[i] + isEndOfKey[i] * isQuote[i]; - - // TODO: might not be right to check for zero, instead check for -1? - isPaddedElement[i] = IsZero(); - isPaddedElement[i].in <== in[0][i]; - - equalComponent[i] = IsEqual(); - equalComponent[i].in[0] <== in[0][i]; - equalComponent[i].in[1] <== in[1][i] * (1-isPaddedElement[i].out); - accum += equalComponent[i].out; - } - - signal isEndOfKeyEqualToQuote <== IsEqual()([endOfKeyAccum[n], 1]); - - component totalEqual = IsEqual(); - totalEqual.in[0] <== n; - totalEqual.in[1] <== accum; - out <== totalEqual.out * isEndOfKeyEqualToQuote; -} - -/// Matches a JSON key at an `index` using Substring Matching at specified depth -/// -/// # Arguments -/// - `dataLen`: parsed data length -/// - `maxKeyLen`: maximum possible key length -/// - `index`: index of key in `data` -/// -/// # Inputs -/// - `data`: data bytes -/// - `key`: key bytes -/// - `parsing_key`: if current byte is inside a key -/// -/// # Output -/// - `out`: Returns `1` if `key` matches `data` at `index` -template KeyMatchAtIndex(dataLen, maxKeyLen, index) { - signal input data[dataLen]; - signal input key[maxKeyLen]; - signal input keyLen; - signal input parsing_key; - - signal paddedKey[maxKeyLen + 1]; - for (var i = 0 ; i < maxKeyLen ; i++) { - paddedKey[i] <== key[i]; - } - paddedKey[maxKeyLen] <== 0; - // `"` -> 34 - - // start of key equal to quote - signal startOfKeyEqualToQuote <== IsEqual()([data[index - 1], 34]); - signal isParsingCorrectKey <== parsing_key * startOfKeyEqualToQuote; - - // key matches - component isSubstringMatch = MatchPaddedKey(maxKeyLen+1); - isSubstringMatch.in[0] <== paddedKey; - isSubstringMatch.keyLen <== keyLen; - for(var matcher_idx = 0; matcher_idx <= maxKeyLen; matcher_idx++) { - isSubstringMatch.in[1][matcher_idx] <== data[index + matcher_idx]; - } - _ <== data; - - signal output out <== isSubstringMatch.out * isParsingCorrectKey; -} \ No newline at end of file diff --git a/circuits/json/parser/language.circom b/circuits/json/language.circom similarity index 100% rename from circuits/json/parser/language.circom rename to circuits/json/language.circom diff --git a/circuits/json/parser/machine.circom b/circuits/json/machine.circom similarity index 99% rename from circuits/json/parser/machine.circom rename to circuits/json/machine.circom index ff82988..5fa147a 100644 --- a/circuits/json/parser/machine.circom +++ b/circuits/json/machine.circom @@ -23,8 +23,8 @@ Tests for this module are located in the files: `circuits/test/parser/*.test.ts pragma circom 2.1.9; -include "../../utils/array.circom"; -include "../../utils/operators.circom"; +include "../utils/array.circom"; +include "../utils/operators.circom"; include "language.circom"; /* diff --git a/circuits/json/nivc/extractor.circom b/circuits/json/nivc/extractor.circom deleted file mode 100644 index f2de60f..0000000 --- a/circuits/json/nivc/extractor.circom +++ /dev/null @@ -1,32 +0,0 @@ -pragma circom 2.1.9; - -include "circomlib/circuits/gates.circom"; -include "@zk-email/circuits/utils/array.circom"; -include "../../utils/hash.circom"; - -template MaskExtractFinal(DATA_BYTES, MAX_VALUE_LENGTH) { - signal input step_in[1]; - signal input data[DATA_BYTES]; - - signal output step_out[1]; - - signal is_zero_mask[DATA_BYTES]; - signal is_prev_starting_index[DATA_BYTES]; - signal value_starting_index[DATA_BYTES]; - - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - value_starting_index[0] <== 0; - is_prev_starting_index[0] <== 0; - is_zero_mask[0] <== IsZero()(data[0]); - for (var i=1 ; i < DATA_BYTES ; i++) { - is_zero_mask[i] <== IsZero()(data[i]); - is_prev_starting_index[i] <== IsZero()(value_starting_index[i-1]); - value_starting_index[i] <== value_starting_index[i-1] + i * (1-is_zero_mask[i]) * is_prev_starting_index[i]; - } - - signal value[MAX_VALUE_LENGTH] <== SelectSubArray(DATA_BYTES, MAX_VALUE_LENGTH)(data, value_starting_index[DATA_BYTES-1], MAX_VALUE_LENGTH); - - step_out[0] <== DataHasher(MAX_VALUE_LENGTH)(value); -} \ No newline at end of file diff --git a/circuits/json/nivc/masker.circom b/circuits/json/nivc/masker.circom deleted file mode 100644 index 97fcf8d..0000000 --- a/circuits/json/nivc/masker.circom +++ /dev/null @@ -1,136 +0,0 @@ -pragma circom 2.1.9; - -include "../interpreter.circom"; -include "../../utils/hash.circom"; - -template JsonMaskObjectNIVC(DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH) { - signal input step_in[1]; - signal input key[MAX_KEY_LENGTH]; - signal input keyLen; - - signal output step_out[1]; - - // Authenticate the (potentially further masked) plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - // flag determining whether this byte is matched value - signal is_value_match[DATA_BYTES - MAX_KEY_LENGTH]; - - component State[DATA_BYTES - MAX_KEY_LENGTH]; - State[0] = StateUpdate(MAX_STACK_HEIGHT); - State[0].byte <== data[0]; - for(var i = 0; i < MAX_STACK_HEIGHT; i++) { - State[0].stack[i] <== [0,0]; - } - State[0].parsing_string <== 0; - State[0].parsing_number <== 0; - - signal parsing_key[DATA_BYTES - MAX_KEY_LENGTH]; - signal parsing_value[DATA_BYTES - MAX_KEY_LENGTH]; - signal is_key_match[DATA_BYTES - MAX_KEY_LENGTH]; - signal is_key_match_for_value[DATA_BYTES+1 - MAX_KEY_LENGTH]; - is_key_match_for_value[0] <== 0; - signal is_next_pair_at_depth[DATA_BYTES - MAX_KEY_LENGTH]; - signal or[DATA_BYTES - MAX_KEY_LENGTH - 1]; - - // initialise first iteration - - // check inside key or value - parsing_key[0] <== InsideKey()(State[0].next_stack[0], State[0].next_parsing_string, State[0].next_parsing_number); - parsing_value[0] <== InsideValueObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number); - - is_key_match[0] <== 0; - is_next_pair_at_depth[0] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[0].next_stack, data[0], 0); - is_key_match_for_value[1] <== Mux1()([is_key_match_for_value[0] * (1-is_next_pair_at_depth[0]), is_key_match[0] * (1-is_next_pair_at_depth[0])], is_key_match[0]); - is_value_match[0] <== parsing_value[0] * is_key_match_for_value[1]; - - signal masked[DATA_BYTES]; - masked[0] <== data[0] * is_value_match[0]; - - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - if(data_idx < DATA_BYTES - MAX_KEY_LENGTH) { - State[data_idx] = StateUpdate(MAX_STACK_HEIGHT); - State[data_idx].byte <== data[data_idx]; - State[data_idx].stack <== State[data_idx - 1].next_stack; - State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; - State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; - - // - parsing key - // - parsing value (different for string/numbers and array) - // - key match (key 1, key 2) - // - is next pair - // - is key match for value - // - value_mask - // - mask - - // check if inside key or not - parsing_key[data_idx] <== InsideKey()(State[data_idx].next_stack[0], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number); - // check if inside value - parsing_value[data_idx] <== InsideValueObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number); - - // to get correct value, check: - // - key matches at current index and depth of key is as specified - // - whether next KV pair starts - // - whether key matched for a value (propogate key match until new KV pair of lower depth starts) - - // TODO (autoparallel): this can be optimized i'm sure of it, running without it saves 110k constraints on 1024b (553k with it) - is_key_match[data_idx] <== KeyMatchAtIndex(DATA_BYTES, MAX_KEY_LENGTH, data_idx)(data, key, keyLen, parsing_key[data_idx]); - - // TODO (autoparallel): this could also likely be optimized, costs like 140k constraints itself - is_next_pair_at_depth[data_idx] <== NextKVPairAtDepth(MAX_STACK_HEIGHT)(State[data_idx].next_stack, data[data_idx], 0); - is_key_match_for_value[data_idx+1] <== Mux1()([is_key_match_for_value[data_idx] * (1-is_next_pair_at_depth[data_idx]), is_key_match[data_idx] * (1-is_next_pair_at_depth[data_idx])], is_key_match[data_idx]); - is_value_match[data_idx] <== is_key_match_for_value[data_idx+1] * parsing_value[data_idx]; - - or[data_idx - 1] <== OR()(is_value_match[data_idx], is_value_match[data_idx - 1]); - - // mask = currently parsing value and all subsequent keys matched - masked[data_idx] <== data[data_idx] * or[data_idx - 1]; // TODO here - } else { - masked[data_idx] <== 0; - } - } - step_out[0] <== DataHasher(DATA_BYTES)(masked); -} - -template JsonMaskArrayIndexNIVC(DATA_BYTES, MAX_STACK_HEIGHT) { - signal input step_in[1]; - signal input index; - - signal output step_out[1]; - - // Authenticate the (potentially further masked) plaintext we are passing in - signal input data[DATA_BYTES]; - signal data_hash <== DataHasher(DATA_BYTES)(data); - data_hash === step_in[0]; - - component State[DATA_BYTES]; - State[0] = StateUpdate(MAX_STACK_HEIGHT); - State[0].byte <== data[0]; - for(var i = 0; i < MAX_STACK_HEIGHT; i++) { - State[0].stack[i] <== [0,0]; - } - State[0].parsing_string <== 0; - State[0].parsing_number <== 0; - - signal parsing_array[DATA_BYTES]; - signal or[DATA_BYTES - 1]; - - parsing_array[0] <== InsideArrayIndexObject()(State[0].next_stack[0], State[0].next_stack[1], State[0].next_parsing_string, State[0].next_parsing_number, index); - signal masked[DATA_BYTES]; - masked[0] <== data[0] * parsing_array[0]; - for(var data_idx = 1; data_idx < DATA_BYTES; data_idx++) { - State[data_idx] = StateUpdate(MAX_STACK_HEIGHT); - State[data_idx].byte <== data[data_idx]; - State[data_idx].stack <== State[data_idx - 1].next_stack; - State[data_idx].parsing_string <== State[data_idx - 1].next_parsing_string; - State[data_idx].parsing_number <== State[data_idx - 1].next_parsing_number; - - parsing_array[data_idx] <== InsideArrayIndexObject()(State[data_idx].next_stack[0], State[data_idx].next_stack[1], State[data_idx].next_parsing_string, State[data_idx].next_parsing_number, index); - - or[data_idx - 1] <== OR()(parsing_array[data_idx], parsing_array[data_idx - 1]); - masked[data_idx] <== data[data_idx] * or[data_idx - 1]; - } - step_out[0] <== DataHasher(DATA_BYTES)(masked); -} diff --git a/circuits/json/parser/parser.circom b/circuits/json/parser.circom similarity index 100% rename from circuits/json/parser/parser.circom rename to circuits/json/parser.circom diff --git a/circuits/test/chacha20/chacha20-nivc.test.ts b/circuits/test/chacha20/authentication.test.ts similarity index 67% rename from circuits/test/chacha20/chacha20-nivc.test.ts rename to circuits/test/chacha20/authentication.test.ts index 70a743c..972abf0 100644 --- a/circuits/test/chacha20/chacha20-nivc.test.ts +++ b/circuits/test/chacha20/authentication.test.ts @@ -1,16 +1,16 @@ import { WitnessTester } from "circomkit"; -import { circomkit, toByte, toUint32Array, uintArray32ToBits } from "../common"; +import { circomkit, PolynomialDigest, toByte, toUint32Array, uintArray32ToBits, modAdd } from "../common"; import { DataHasher } from "../common/poseidon"; import { assert } from "chai"; +import { poseidon1 } from "poseidon-lite"; - -describe("chacha20-nivc", () => { - let circuit: WitnessTester<["key", "nonce", "counter", "plainText", "step_in"], ["step_out"]>; +describe("Plaintext Authentication", () => { + let circuit: WitnessTester<["key", "nonce", "counter", "plaintext", "step_in"], ["step_out"]>; describe("16 block test", () => { it("should perform encryption", async () => { - circuit = await circomkit.WitnessTester(`ChaCha20`, { - file: "chacha20/nivc/chacha20_nivc", - template: "ChaCha20_NIVC", + circuit = await circomkit.WitnessTester(`PlaintextAuthentication`, { + file: "chacha20/authentication", + template: "PlaintextAuthentication", params: [64] // number of bytes for plaintext }); // Test case from RCF https://www.rfc-editor.org/rfc/rfc7539.html#section-2.4.2 @@ -54,18 +54,22 @@ describe("chacha20-nivc", () => { key: toInput(Buffer.from(keyBytes)), nonce: toInput(Buffer.from(nonceBytes)), counter: counterBits, - plainText: plaintextBytes, - step_in: DataHasher(ciphertextBytes) + plaintext: plaintextBytes, + step_in: 0 }, (["step_out"])); - assert.deepEqual(w.step_out, DataHasher(plaintextBytes)); + // Output + let ciphertext_digest = DataHasher(ciphertextBytes); + let plaintext_digest_hashed = poseidon1([PolynomialDigest(plaintextBytes, ciphertext_digest)]); + let output = modAdd(plaintext_digest_hashed - ciphertext_digest, BigInt(0)); + assert.deepEqual(w.step_out, output); }); }); describe("padded plaintext", () => { it("should perform encryption", async () => { - circuit = await circomkit.WitnessTester(`ChaCha20`, { - file: "chacha20/nivc/chacha20_nivc", - template: "ChaCha20_NIVC", + circuit = await circomkit.WitnessTester(`PlaintextAuthentication`, { + file: "chacha20/authentication", + template: "PlaintextAuthentication", params: [128] // number of bytes in plaintext }); // Test case from RCF https://www.rfc-editor.org/rfc/rfc7539.html#section-2.4.2 @@ -108,54 +112,13 @@ describe("chacha20-nivc", () => { key: toInput(Buffer.from(keyBytes)), nonce: toInput(Buffer.from(nonceBytes)), counter: counterBits, - plainText: paddedPlaintextBytes, - step_in: DataHasher(ciphertextBytes) - }, (["step_out"])); - assert.deepEqual(w.step_out, DataHasher(paddedPlaintextBytes)); - }); - }); - - describe("wrong ciphertext hash", () => { - it("should fail", async () => { - circuit = await circomkit.WitnessTester(`ChaCha20`, { - file: "chacha20/nivc/chacha20_nivc", - template: "ChaCha20_NIVC", - params: [128] // number of bytes in plaintext - }); - // Test case from RCF https://www.rfc-editor.org/rfc/rfc7539.html#section-2.4.2 - // the input encoding here is not the most intuitive. inputs are serialized as little endian. - // i.e. "e4e7f110" is serialized as "10 f1 e7 e4". So the way i am reading in inputs is - // to ensure that every 32 bit word is byte reversed before being turned into bits. - // i think this should be easy when we compute witness in rust. - let keyBytes = [ - 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f - ]; - - let nonceBytes = - [ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x4a, - 0x00, 0x00, 0x00, 0x00 - ]; - let plaintextBytes = - toByte("Ladies and Gentlemen of the class of '99: If I could offer you only one tip "); - let totalLength = 128; - let paddedPlaintextBytes = plaintextBytes.concat(Array(totalLength - plaintextBytes.length).fill(-1)); - const counterBits = uintArray32ToBits([1])[0] - await circuit.expectFail({ - key: toInput(Buffer.from(keyBytes)), - nonce: toInput(Buffer.from(nonceBytes)), - counter: counterBits, - plainText: paddedPlaintextBytes, + plaintext: paddedPlaintextBytes, step_in: 0 - }); + }, (["step_out"])); + let ciphertext_digest = DataHasher(ciphertextBytes); + let plaintext_digest = poseidon1([PolynomialDigest(plaintextBytes, ciphertext_digest)]); + let output = modAdd(plaintext_digest - ciphertext_digest, BigInt(0)); + assert.deepEqual(w.step_out, output); }); }); }); @@ -175,4 +138,4 @@ export function fromInput(bits: number[]) { buffer.writeUInt32LE(uint32Array[i], i * 4); } return buffer; -} \ No newline at end of file +} diff --git a/circuits/test/chacha20/chacha20.test.ts b/circuits/test/chacha20/chacha20.test.ts index bfe5a38..b16a739 100644 --- a/circuits/test/chacha20/chacha20.test.ts +++ b/circuits/test/chacha20/chacha20.test.ts @@ -1,7 +1,7 @@ import { WitnessTester } from "circomkit"; import { circomkit, hexToBits, toUint32Array, uintArray32ToBits } from "../common"; -describe("chacha20", () => { +describe("ChaCha20", () => { describe("qtr-round", () => { let circuit: WitnessTester<["in"], ["out"]>; it("should perform qtr-round", async () => { @@ -10,16 +10,16 @@ describe("chacha20", () => { template: "QR", }); // Test case from RCF https://www.rfc-editor.org/rfc/rfc7539.html#section-2.1 - let input = [ + let input = [ hexToBits("0x11111111"), hexToBits("0x01020304"), hexToBits("0x9b8d6f43"), hexToBits("0x01234567") ]; - let expected = [ - hexToBits("0xea2a92f4"), - hexToBits("0xcb1cf8ce"), - hexToBits("0x4581472e"), + let expected = [ + hexToBits("0xea2a92f4"), + hexToBits("0xcb1cf8ce"), + hexToBits("0x4581472e"), hexToBits("0x5881c4bb") ]; await circuit.expectPass({ in: input }, { out: expected }); @@ -34,17 +34,17 @@ describe("chacha20", () => { template: "Round", }); // Test case from RCF https://www.rfc-editor.org/rfc/rfc7539.html#section-2.1 - let input = [ - hexToBits("61707865"), hexToBits("3320646e"), hexToBits("79622d32"), hexToBits("6b206574"), - hexToBits("03020100"), hexToBits("07060504"), hexToBits("0b0a0908"), hexToBits("0f0e0d0c"), - hexToBits("13121110"), hexToBits("17161514"), hexToBits("1b1a1918"), hexToBits("1f1e1d1c"), - hexToBits("00000001"), hexToBits("09000000"), hexToBits("4a000000"), hexToBits("00000000") + let input = [ + hexToBits("61707865"), hexToBits("3320646e"), hexToBits("79622d32"), hexToBits("6b206574"), + hexToBits("03020100"), hexToBits("07060504"), hexToBits("0b0a0908"), hexToBits("0f0e0d0c"), + hexToBits("13121110"), hexToBits("17161514"), hexToBits("1b1a1918"), hexToBits("1f1e1d1c"), + hexToBits("00000001"), hexToBits("09000000"), hexToBits("4a000000"), hexToBits("00000000") ]; - let expected = [ - hexToBits("e4e7f110"), hexToBits("15593bd1"), hexToBits("1fdd0f50"), hexToBits("c47120a3"), - hexToBits("c7f4d1c7"), hexToBits("0368c033"), hexToBits("9aaa2204"), hexToBits("4e6cd4c3"), - hexToBits("466482d2"), hexToBits("09aa9f07"), hexToBits("05d7c214"), hexToBits("a2028bd9"), - hexToBits("d19c12b5"), hexToBits("b94e16de"), hexToBits("e883d0cb"), hexToBits("4e3c50a2") + let expected = [ + hexToBits("e4e7f110"), hexToBits("15593bd1"), hexToBits("1fdd0f50"), hexToBits("c47120a3"), + hexToBits("c7f4d1c7"), hexToBits("0368c033"), hexToBits("9aaa2204"), hexToBits("4e6cd4c3"), + hexToBits("466482d2"), hexToBits("09aa9f07"), hexToBits("05d7c214"), hexToBits("a2028bd9"), + hexToBits("d19c12b5"), hexToBits("b94e16de"), hexToBits("e883d0cb"), hexToBits("4e3c50a2") ]; await circuit.expectPass({ in: input }, { out: expected }); }); @@ -65,59 +65,60 @@ describe("chacha20", () => { // to ensure that every 32 bit word is byte reversed before being turned into bits. // i think this should be easy when we compute witness in rust. let test = { - keyBytes: Buffer.from( - [ - 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f - ] - ), - nonceBytes: Buffer.from( - [ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x4a, - 0x00, 0x00, 0x00, 0x00 - ] - ), - counter: 1, - plaintextBytes: Buffer.from( - [ - 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, - 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, - 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, - 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, - ] - ), - ciphertextBytes: Buffer.from( - [ - 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, - 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, - 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, - 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8 - ] - )} + keyBytes: Buffer.from( + [ + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f + ] + ), + nonceBytes: Buffer.from( + [ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00 + ] + ), + counter: 1, + plaintextBytes: Buffer.from( + [ + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + ] + ), + ciphertextBytes: Buffer.from( + [ + 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, + 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, + 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, + 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8 + ] + ) + } const ciphertextBits = uintArray32ToBits(toUint32Array(test.ciphertextBytes)) const plaintextBits = uintArray32ToBits(toUint32Array(test.plaintextBytes)) - const counterBits = uintArray32ToBits([test.counter])[0] - await circuit.expectPass({ - key: uintArray32ToBits(toUint32Array(test.keyBytes)), - nonce: uintArray32ToBits(toUint32Array(test.nonceBytes)), - counter: counterBits, - in: plaintextBits, - }, { out: ciphertextBits }); + const counterBits = uintArray32ToBits([test.counter])[0] + await circuit.expectPass({ + key: uintArray32ToBits(toUint32Array(test.keyBytes)), + nonce: uintArray32ToBits(toUint32Array(test.nonceBytes)), + counter: counterBits, + in: plaintextBits, + }, { out: ciphertextBits }); /// decryption since symmetric - const w2 = await circuit.expectPass({ - key: uintArray32ToBits(toUint32Array(test.keyBytes)), - nonce: uintArray32ToBits(toUint32Array(test.nonceBytes)), - counter: counterBits, - in: ciphertextBits, - }, { out: plaintextBits }); + const w2 = await circuit.expectPass({ + key: uintArray32ToBits(toUint32Array(test.keyBytes)), + nonce: uintArray32ToBits(toUint32Array(test.nonceBytes)), + counter: counterBits, + in: ciphertextBits, + }, { out: plaintextBits }); }); }); }); \ No newline at end of file diff --git a/circuits/test/common/index.ts b/circuits/test/common/index.ts index d65d7c6..045ad32 100644 --- a/circuits/test/common/index.ts +++ b/circuits/test/common/index.ts @@ -26,7 +26,7 @@ export function generateDescription(input: any): string { } export function readJSONInputFile(filename: string, key: any[]): [number[], number[][], number[]] { - const valueStringPath = join(__dirname, "..", "..", "..", "examples", "json", "test", filename); + const valueStringPath = join(__dirname, "..", "..", "..", "examples", "json", filename); let input: number[] = []; let output: number[] = []; @@ -62,6 +62,8 @@ export function readJSONInputFile(filename: string, key: any[]): [number[], numb } import fs from 'fs'; +import { DataHasher } from './poseidon'; +import { poseidon1 } from 'poseidon-lite'; export function readJsonFile(filePath: string): T { // Read the file synchronously @@ -90,13 +92,13 @@ export function toByte(data: string): number[] { export function hexToBytes(hex: any) { return hex.match(/.{1,2}/g).map((byte: any) => parseInt(byte, 16)); - } - +} + export function hexBytesToBigInt(hexBytes: number[]): any[] { -return hexBytes.map(byte => { - let n = BigInt(byte); - return n; -}); + return hexBytes.map(byte => { + let n = BigInt(byte); + return n; + }); } export function hexToBits(hex: string): number[] { @@ -178,26 +180,26 @@ export function binaryStringToHex(binaryString: string): string { * BE order. */ export function uint8ArrayToBitsBE(buff: Uint8Array | number[]) { - const res: number[] = [] - for (let i = 0; i < buff.length; i++) { - for (let j = 0; j < 8; j++) { - if ((buff[i] >> 7-j) & 1) { - res.push(1); - } else { - res.push(0); - } - } - } - return res; + const res: number[] = [] + for (let i = 0; i < buff.length; i++) { + for (let j = 0; j < 8; j++) { + if ((buff[i] >> 7 - j) & 1) { + res.push(1); + } else { + res.push(0); + } + } + } + return res; } export function toUint32Array(buf: Uint8Array) { - const arr = new Uint32Array(buf.length / 4) - const arrView = new DataView(buf.buffer, buf.byteOffset, buf.byteLength) - for(let i = 0;i < arr.length;i++) { - arr[i] = arrView.getUint32(i * 4, true) - } - return arr + const arr = new Uint32Array(buf.length / 4) + const arrView = new DataView(buf.buffer, buf.byteOffset, buf.byteLength) + for (let i = 0; i < arr.length; i++) { + arr[i] = arrView.getUint32(i * 4, true) + } + return arr } /** @@ -205,24 +207,24 @@ export function toUint32Array(buf: Uint8Array) { * LE order. */ export function uintArray32ToBits(uintArray: Uint32Array | number[]) { - const bits: number[][] = [] - for (let i = 0; i < uintArray.length; i++) { - const uint = uintArray[i] - bits.push(numToBitsNumerical(uint)) - } + const bits: number[][] = [] + for (let i = 0; i < uintArray.length; i++) { + const uint = uintArray[i] + bits.push(numToBitsNumerical(uint)) + } - return bits + return bits } export function numToBitsNumerical(num: number, bitCount = 32) { - const bits: number[] = [] - for(let i = 2 ** (bitCount - 1);i >= 1;i /= 2) { - const bit = num >= i ? 1 : 0 - bits.push(bit) - num -= bit * i - } + const bits: number[] = [] + for (let i = 2 ** (bitCount - 1); i >= 1; i /= 2) { + const bit = num >= i ? 1 : 0 + bits.push(bit) + num -= bit * i + } - return bits + return bits } export function bytesToBigInt(bytes: number[] | Uint8Array): bigint { @@ -233,4 +235,273 @@ export function bytesToBigInt(bytes: number[] | Uint8Array): bigint { } return result; +} + +const prime = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +export function PolynomialDigest(coeffs: number[], input: bigint): bigint { + let result = BigInt(0); + let power = BigInt(1); + + for (let i = 0; i < coeffs.length; i++) { + result = (result + BigInt(coeffs[i]) * power) % prime; + power = (power * input) % prime; + } + + return result; +} + +// HTTP/1.1 200 OK +// content-type: application/json; charset=utf-8 +// content-encoding: gzip +// Transfer-Encoding: chunked +// +// { +// "data": { +// "items": [ +// { +// "data": "Artist", +// "profile": { +// "name": "Taylor Swift" +// } +// } +// ] +// } +// } + +// 320 bytes in the HTTP response +export const http_response_plaintext = [ + 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 99, 111, 110, 116, 101, 110, + 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, + 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 99, + 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, + 112, 13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, + 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 13, 10, 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, + 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, + 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, + 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, + 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, + 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, + 10, 32, 32, 32, 125, 13, 10, 125, +]; + +export const http_response_ciphertext = [ + 2, 125, 219, 141, 140, 93, 49, 129, 95, 178, 135, 109, 48, 36, 194, 46, 239, 155, 160, 70, 208, + 147, 37, 212, 17, 195, 149, 190, 38, 215, 23, 241, 84, 204, 167, 184, 179, 172, 187, 145, 38, 75, + 123, 96, 81, 6, 149, 36, 135, 227, 226, 254, 177, 90, 241, 159, 0, 230, 183, 163, 210, 88, 133, + 176, 9, 122, 225, 83, 171, 157, 185, 85, 122, 4, 110, 52, 2, 90, 36, 189, 145, 63, 122, 75, 94, + 21, 163, 24, 77, 85, 110, 90, 228, 157, 103, 41, 59, 128, 233, 149, 57, 175, 121, 163, 185, 144, + 162, 100, 17, 34, 9, 252, 162, 223, 59, 221, 106, 127, 104, 11, 121, 129, 154, 49, 66, 220, 65, + 130, 171, 165, 43, 8, 21, 248, 12, 214, 33, 6, 109, 3, 144, 52, 124, 225, 206, 223, 213, 86, 186, + 93, 170, 146, 141, 145, 140, 57, 152, 226, 218, 57, 30, 4, 131, 161, 0, 248, 172, 49, 206, 181, + 47, 231, 87, 72, 96, 139, 145, 117, 45, 77, 134, 249, 71, 87, 178, 239, 30, 244, 156, 70, 118, + 180, 176, 90, 92, 80, 221, 177, 86, 120, 222, 223, 244, 109, 150, 226, 142, 97, 171, 210, 38, + 117, 143, 163, 204, 25, 223, 238, 209, 58, 59, 100, 1, 86, 241, 103, 152, 228, 37, 187, 79, 36, + 136, 133, 171, 41, 184, 145, 146, 45, 192, 173, 219, 146, 133, 12, 246, 190, 5, 54, 99, 155, 8, + 198, 156, 174, 99, 12, 210, 95, 5, 128, 166, 118, 50, 66, 26, 20, 3, 129, 232, 1, 192, 104, 23, + 152, 212, 94, 97, 138, 162, 90, 185, 108, 221, 211, 247, 184, 253, 15, 16, 24, 32, 240, 240, 3, + 148, 89, 30, 54, 161, 131, 230, 161, 217, 29, 229, 251, 33, 220, 230, 102, 131, 245, 27, 141, + 220, 67, 16, 26, +]; + +export const http_start_line = [72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75]; + +export const http_header_0 = [ + 99, 111, 110, 116, 101, 110, 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, + 116, 105, 111, 110, 47, 106, 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, + 116, 102, 45, 56, +]; + +export const http_header_1 = [ + 99, 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, + 105, 112, +]; +export const http_body = [ + 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, + 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, + 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, + 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, + 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 13, 10, 125, +]; + +export function strToBytes(str: string): number[] { + return Array.from(str.split('').map(c => c.charCodeAt(0))); +} + +// Enum equivalent for JsonMaskType +export type JsonMaskType = + | { type: "Object", value: number[] } // Changed from Uint8Array to number[] + | { type: "ArrayIndex", value: number }; + +// Constants for the field arithmetic +const PRIME = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +const ONE = BigInt(1); +const ZERO = BigInt(0); + +export function modAdd(a: bigint, b: bigint): bigint { + return ((a + b) % PRIME + PRIME) % PRIME; +} + +function modMul(a: bigint, b: bigint): bigint { + return (a * b) % PRIME; +} + +export function jsonTreeHasher( + polynomialInput: bigint, + keySequence: JsonMaskType[], + maxStackHeight: number +): [Array<[bigint, bigint]>, Array] { + if (keySequence.length > maxStackHeight) { + throw new Error("Key sequence length exceeds max stack height"); + } + + const stack: Array<[bigint, bigint]> = []; + const treeHashes: Array = []; + + for (const valType of keySequence) { + if (valType.type === "Object") { + stack.push([ONE, ONE]); + let stringHash = ZERO; + let monomial = ONE; + + for (const byte of valType.value) { + stringHash = modAdd(stringHash, modMul(monomial, BigInt(byte))); + monomial = modMul(monomial, polynomialInput); + } + treeHashes.push(stringHash); + } else { // ArrayIndex + treeHashes.push(ZERO); + stack.push([BigInt(2), BigInt(valType.value)]); + } + } + + return [stack, treeHashes]; +} + +export function compressTreeHash( + polynomialInput: bigint, + stackAndTreeHashes: [Array<[bigint, bigint]>, Array] +): bigint { + const [stack, treeHashes] = stackAndTreeHashes; + + if (stack.length !== treeHashes.length) { + throw new Error("Stack and tree hashes must have the same length"); + } + + let accumulated = ZERO; + let monomial = ONE; + + for (let idx = 0; idx < stack.length; idx++) { + accumulated = modAdd(accumulated, modMul(stack[idx][0], monomial)); + monomial = modMul(monomial, polynomialInput); + + accumulated = modAdd(accumulated, modMul(stack[idx][1], monomial)); + monomial = modMul(monomial, polynomialInput); + + accumulated = modAdd(accumulated, modMul(treeHashes[idx], monomial)); + monomial = modMul(monomial, polynomialInput); + } + + return accumulated; +} + +interface ManifestResponse { + version: string; + status: string; + message: string; + headers: Record; + body: { + json: JsonMaskType[]; + }; +} + +interface Manifest { + response: ManifestResponse; +} + +function headersToBytes(headers: Record): number[][] { + const result: number[][] = []; + + for (const [key, values] of Object.entries(headers)) { + for (const value of values) { + // In HTTP/1.1, headers are formatted as "key: value" + const headerLine = `${key}: ${value}`; + result.push(strToBytes(headerLine)); + } + } + + return result; +} + +export function InitialDigest( + manifest: Manifest, + ciphertext: number[], + maxStackHeight: number +): [bigint, bigint] { + // Create a digest of the ciphertext itself + const ciphertextDigest = DataHasher(ciphertext); + + // Digest the start line using the ciphertext_digest as a random input + const startLineBytes = strToBytes( + `${manifest.response.version} ${manifest.response.status} ${manifest.response.message}` + ); + const startLineDigest = PolynomialDigest(startLineBytes, ciphertextDigest); + + // Digest all the headers + const headerBytes = headersToBytes(manifest.response.headers); + const headersDigest = headerBytes.map(bytes => + PolynomialDigest(bytes, ciphertextDigest) + ); + + // Digest the JSON sequence + const jsonTreeHash = jsonTreeHasher( + ciphertextDigest, + manifest.response.body.json, + maxStackHeight + ); + const jsonSequenceDigest = compressTreeHash(ciphertextDigest, jsonTreeHash); + + // Put all the digests into an array + const allDigests: bigint[] = [jsonSequenceDigest, startLineDigest, ...headersDigest]; + + // Calculate manifest digest + const manifestDigest = modAdd( + ciphertextDigest, + allDigests.map(d => poseidon1([d])).reduce((a, b) => modAdd(a, b), ZERO) + ); + + return [ciphertextDigest, manifestDigest]; +} + +export function MockManifest(): Manifest { + const headers: Record = { + "content-type": ["application/json; charset=utf-8"], + "content-encoding": ["gzip"] + }; + + const jsonSequence: JsonMaskType[] = [ + { type: "Object", value: strToBytes("data") }, + { type: "Object", value: strToBytes("items") }, + { type: "ArrayIndex", value: 0 }, + { type: "Object", value: strToBytes("profile") }, + { type: "Object", value: strToBytes("name") } + ]; + + return { + response: { + status: "200", + version: "HTTP/1.1", + message: "OK", + headers: headers, + body: { + json: jsonSequence + } + } + }; } \ No newline at end of file diff --git a/circuits/test/common/poseidon.ts b/circuits/test/common/poseidon.ts index ab18924..ab44b05 100644 --- a/circuits/test/common/poseidon.ts +++ b/circuits/test/common/poseidon.ts @@ -105,4 +105,4 @@ export function DataHasher(input: number[]): bigint { // Return the last hash return hashes[Math.ceil(input.length / 16)]; -} \ No newline at end of file +} diff --git a/circuits/test/full/full.test.ts b/circuits/test/full/full.test.ts index 507fa1f..13ca7db 100644 --- a/circuits/test/full/full.test.ts +++ b/circuits/test/full/full.test.ts @@ -1,7 +1,7 @@ import { assert } from "chai"; -import { circomkit, WitnessTester, toByte, uintArray32ToBits, toUint32Array } from "../common"; -import { DataHasher } from "../common/poseidon"; -import { toInput } from "../chacha20/chacha20-nivc.test"; +import { circomkit, WitnessTester, uintArray32ToBits, http_response_plaintext, http_response_ciphertext, http_start_line, http_header_0, http_header_1, http_body, PolynomialDigest, strToBytes, JsonMaskType, jsonTreeHasher, compressTreeHash, modAdd, InitialDigest, MockManifest } from "../common"; +import { toInput } from "../chacha20/authentication.test"; +import { poseidon1 } from "poseidon-lite"; // HTTP/1.1 200 OK // content-type: application/json; charset=utf-8 @@ -22,286 +22,123 @@ import { toInput } from "../chacha20/chacha20-nivc.test"; // } // 320 bytes in the HTTP response -const http_response_plaintext = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 99, 111, 110, 116, 101, 110, - 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, - 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 99, - 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, - 112, 13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, - 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 13, 10, 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, - 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, - 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, - 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, - 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, - 10, 32, 32, 32, 125, 13, 10, 125]; -const chacha20_http_response_ciphertext = [ - 2, 125, 219, 141, 140, 93, 49, 129, 95, 178, 135, 109, 48, 36, 194, 46, 239, 155, 160, 70, 208, 147, 37, 212, 17, 195, 149, - 190, 38, 215, 23, 241, 84, 204, 167, 184, 179, 172, 187, 145, 38, 75, 123, 96, 81, 6, 149, 36, 135, 227, 226, 254, 177, 90, - 241, 159, 0, 230, 183, 163, 210, 88, 133, 176, 9, 122, 225, 83, 171, 157, 185, 85, 122, 4, 110, 52, 2, 90, 36, 189, 145, 63, - 122, 75, 94, 21, 163, 24, 77, 85, 110, 90, 228, 157, 103, 41, 59, 128, 233, 149, 57, 175, 121, 163, 185, 144, 162, 100, 17, - 34, 9, 252, 162, 223, 59, 221, 106, 127, 104, 11, 121, 129, 154, 49, 66, 220, 65, 130, 171, 165, 43, 8, 21, 248, 12, 214, 33, - 6, 109, 3, 144, 52, 124, 225, 206, 223, 213, 86, 186, 93, 170, 146, 141, 145, 140, 57, 152, 226, 218, 57, 30, 4, 131, 161, 0, - 248, 172, 49, 206, 181, 47, 231, 87, 72, 96, 139, 145, 117, 45, 77, 134, 249, 71, 87, 178, 239, 30, 244, 156, 70, 118, 180, - 176, 90, 92, 80, 221, 177, 86, 120, 222, 223, 244, 109, 150, 226, 142, 97, 171, 210, 38, 117, 143, 163, 204, 25, 223, 238, - 209, 58, 59, 100, 1, 86, 241, 103, 152, 228, 37, 187, 79, 36, 136, 133, 171, 41, 184, 145, 146, 45, 192, 173, 219, 146, 133, - 12, 246, 190, 5, 54, 99, 155, 8, 198, 156, 174, 99, 12, 210, 95, 5, 128, 166, 118, 50, 66, 26, 20, 3, 129, 232, 1, 192, 104, - 23, 152, 212, 94, 97, 138, 162, 90, 185, 108, 221, 211, 247, 184, 253, 15, 16, 24, 32, 240, 240, 3, 148, 89, 30, 54, 161, - 131, 230, 161, 217, 29, 229, 251, 33, 220, 230, 102, 131, 245, 27, 141, 220, 67, 16, 26 -]; +const DATA_BYTES = 1024; +const MAX_NUMBER_OF_HEADERS = 25; +const MAX_STACK_HEIGHT = 10; -const http_start_line = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -]; +// These `check_*` are currently from Rust to ensure we have parity +const check_ciphertext_digest = BigInt("5947802862726868637928743536818722886587721698845887498686185738472802646104"); +const check_init_nivc_input = BigInt("10288873638660630335427615297930270928433661836597941144520949467184902553219"); -const http_header_0 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 111, 110, 116, 101, 110, 116, 45, 116, - 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, 115, 111, - 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const http_header_1 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 99, 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, - 105, 112, 13, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const http_body = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 34, - 100, 97, 116, 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, - 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, - 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, - 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, - 32, 32, 93, 13, 10, 32, 32, 32, 125, 13, 10, 125, -]; -const lengthDiff = http_response_plaintext.length - http_body.length; - -// Create an array of zeros with the length difference -const padding = new Array(lengthDiff).fill(0); - -// Concatenate the padding with http_body -const padded_http_body = [...padding, ...http_body]; - -const http_response_hash = DataHasher(http_response_plaintext); -const http_start_line_hash = DataHasher(http_start_line); -const http_header_0_hash = DataHasher(http_header_0); -const http_header_1_hash = DataHasher(http_header_1); -const http_body_mask_hash = DataHasher(padded_http_body); - - -const json_key0_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, 91, - 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, - 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, - 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, - 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 0, - 0, 0, 0, 0, 0, 0, 0, -]; -const json_key0_mask_hash = DataHasher(json_key0_mask); - -const json_key1_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 13, 10, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, - 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, - 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_key1_mask_hash = DataHasher(json_key1_mask); - -const json_arr_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, - 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, - 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_arr_mask_hash = DataHasher(json_arr_mask); - -const json_key2_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, - 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_key2_mask_hash = DataHasher(json_key2_mask); - -const json_key3_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, - 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -]; -const json_key3_mask_hash = DataHasher(json_key3_mask); - -describe("NIVC_FULL", async () => { - let chacha20Circuit: WitnessTester<["key", "nonce", "counter", "plainText", "step_in"], ["step_out"]>; - let httpCircuit: WitnessTester<["step_in", "data", "start_line_hash", "header_hashes", "body_hash"], ["step_out"]>; - let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; - let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; - let extract_value_circuit: WitnessTester<["step_in", "data"], ["step_out"]>; - - const MAX_NUMBER_OF_HEADERS = 2; - const DATA_BYTES = 320; - const MAX_STACK_HEIGHT = 5; - const MAX_KEY_LENGTH = 8; - const MAX_VALUE_LENGTH = 32; +describe("Example NIVC Proof", async () => { + let PlaintextAuthentication: WitnessTester<["step_in", "plaintext", "key", "nonce", "counter"], ["step_out"]>; + let HTTPVerification: WitnessTester<["step_in", "ciphertext_digest", "data", "main_digests"], ["step_out"]>; + let JSONExtraction: WitnessTester<["step_in", "ciphertext_digest", "data", "sequence_digest", "value_digest"], ["step_out"]>; before(async () => { - chacha20Circuit = await circomkit.WitnessTester("CHACHA20", { - file: "chacha20/nivc/chacha20_nivc", - template: "ChaCha20_NIVC", - params: [320] + PlaintextAuthentication = await circomkit.WitnessTester("PlaintextAuthentication", { + file: "chacha20/authentication", + template: "PlaintextAuthentication", + params: [DATA_BYTES] }); - console.log("#constraints (CHACHA20):", await chacha20Circuit.getConstraintCount()); - httpCircuit = await circomkit.WitnessTester(`HttpNIVC`, { + HTTPVerification = await circomkit.WitnessTester("HTTPVerification", { file: "http/verification", template: "HTTPVerification", params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS], }); - console.log("#constraints (HTTPVerification):", await httpCircuit.getConstraintCount()); - - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints (JSON-MASK-OBJECT):", await json_mask_object_circuit.getConstraintCount()); - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", + JSONExtraction = await circomkit.WitnessTester(`JSONExtraction`, { + file: "json/extraction", + template: "JSONExtraction", params: [DATA_BYTES, MAX_STACK_HEIGHT], }); - console.log("#constraints (JSON-MASK-ARRAY-INDEX):", await json_mask_arr_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints (JSON-MASK-EXTRACT-FINAL):", await extract_value_circuit.getConstraintCount()); }); - it("NIVC_CHAIN", async () => { - const init_nivc_input = DataHasher(chacha20_http_response_ciphertext); - // Run ChaCha20 - const counterBits = uintArray32ToBits([1])[0] - const keyIn = toInput(Buffer.from(Array(32).fill(0))); - const nonceIn = toInput(Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00])); - let chacha20 = await chacha20Circuit.compute({ key: keyIn, nonce: nonceIn, counter: counterBits, plainText: http_response_plaintext, step_in: init_nivc_input }, ["step_out"]); - console.log("ChaCha20 `step_out`:", chacha20.step_out); - assert.deepEqual(http_response_hash, chacha20.step_out); - - let http = await httpCircuit.compute({ step_in: chacha20.step_out, data: http_response_plaintext, start_line_hash: http_start_line_hash, header_hashes: [http_header_0_hash, http_header_1_hash], body_hash: http_body_mask_hash }, ["step_out"]); - console.log("HttpNIVC `step_out`:", http.step_out); + it("Spotify Example", async () => { + // Run PlaintextAuthentication - let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" - let key0Len = 4; - let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" - let key1Len = 5; - let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" - let key2Len = 7; - let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" - let key3Len = 4; + let http_response_padded = http_response_plaintext.concat(Array(DATA_BYTES - http_response_plaintext.length).fill(-1)); + let http_response_0_padded = http_response_plaintext.concat(Array(DATA_BYTES - http_start_line.length).fill(0)); + let ciphertext_padded = http_response_ciphertext.concat(Array(DATA_BYTES - http_response_ciphertext.length).fill(-1)); - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: http.step_out, data: http_body, key: key0, keyLen: key0Len }, ["step_out"]); - console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); - assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); - let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); - assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); - console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); + const [ciphertext_digest, init_nivc_input] = InitialDigest(MockManifest(), ciphertext_padded, MAX_STACK_HEIGHT); + assert.deepEqual(ciphertext_digest, check_ciphertext_digest); + assert.deepEqual(init_nivc_input, check_init_nivc_input); - let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, data: json_key1_mask, index: 0 }, ["step_out"]); - assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); - console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); - - let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); - assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); - console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); - - let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); - assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); - console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); - - // TODO (autoparallel): we need to rethink extraction here. - let finalOutput = toByte("\"Taylor Swift\""); - let finalOutputPadded = finalOutput.concat(Array(Math.max(0, MAX_VALUE_LENGTH - finalOutput.length)).fill(0)); - let final_value_hash = DataHasher(finalOutputPadded); - let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); - console.log("finalValue", extractValue.step_out); - assert.deepEqual(extractValue.step_out, final_value_hash); + const counterBits = uintArray32ToBits([1])[0] + const keyIn = toInput(Buffer.from(Array(32).fill(0))); + const nonceIn = toInput(Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00])); + let plaintext_authentication = await PlaintextAuthentication.compute({ + step_in: init_nivc_input, + plaintext: http_response_padded, + key: keyIn, + nonce: nonceIn, + counter: counterBits, + }, ["step_out"]); + + const http_response_plaintext_digest = PolynomialDigest(http_response_0_padded, ciphertext_digest); + const http_response_plaintext_digest_hashed = poseidon1([http_response_plaintext_digest]); + const correct_plaintext_authentication_step_out = modAdd(init_nivc_input - ciphertext_digest, http_response_plaintext_digest_hashed); + assert.deepEqual(plaintext_authentication.step_out, correct_plaintext_authentication_step_out); + + // Run HTTPVerification + const start_line_digest = PolynomialDigest(http_start_line, ciphertext_digest); + const header_0_digest = PolynomialDigest(http_header_0, ciphertext_digest); + const header_1_digest = PolynomialDigest(http_header_1, ciphertext_digest); + + let main_digests = Array(MAX_NUMBER_OF_HEADERS + 1).fill(0); + main_digests[0] = start_line_digest; + main_digests[1] = header_0_digest; + main_digests[2] = header_1_digest; + + let step_in = BigInt(plaintext_authentication.step_out.toString(10)); + let http_verification = await HTTPVerification.compute({ + step_in, + ciphertext_digest, + data: http_response_padded, + main_digests, + }, ["step_out"]); + + const padded_http_body = http_body.concat(Array(DATA_BYTES - http_body.length).fill(0)); + let http_verification_step_out = BigInt((http_verification.step_out as number[])[0]); + let body_digest = PolynomialDigest(http_body, ciphertext_digest); + + const body_digest_hashed = poseidon1([body_digest]); + const start_line_digest_digest_hashed = poseidon1([start_line_digest]); + const header_0_digest_hashed = poseidon1([header_0_digest]); + const header_1_digest_hashed = poseidon1([header_1_digest]); + const correct_http_verification_step_out = modAdd(step_in - start_line_digest_digest_hashed - header_0_digest_hashed - header_1_digest_hashed - http_response_plaintext_digest_hashed, body_digest_hashed); + assert.deepEqual(http_verification_step_out, correct_http_verification_step_out); + + // Run JSONExtraction + const KEY0 = strToBytes("data"); + const KEY1 = strToBytes("items"); + const KEY2 = strToBytes("profile"); + const KEY3 = strToBytes("name"); + const targetValue = strToBytes("Taylor Swift"); + const keySequence: JsonMaskType[] = [ + { type: "Object", value: KEY0 }, + { type: "Object", value: KEY1 }, + { type: "ArrayIndex", value: 0 }, + { type: "Object", value: KEY2 }, + { type: "Object", value: KEY3 }, + ]; + + const [stack, treeHashes] = jsonTreeHasher(ciphertext_digest, keySequence, MAX_STACK_HEIGHT); + const sequence_digest = compressTreeHash(ciphertext_digest, [stack, treeHashes]); + const value_digest = PolynomialDigest(targetValue, ciphertext_digest); + + let json_extraction = await JSONExtraction.compute({ + step_in: http_verification_step_out, + ciphertext_digest, + data: padded_http_body, + value_digest, + sequence_digest, + }, ["step_out"]); + assert.deepEqual(json_extraction.step_out, value_digest); }); }); diff --git a/circuits/test/http/verification.test.ts b/circuits/test/http/verification.test.ts index 065ab51..ce97d66 100644 --- a/circuits/test/http/verification.test.ts +++ b/circuits/test/http/verification.test.ts @@ -1,6 +1,6 @@ -import { circomkit, WitnessTester, toByte } from "../common"; +import { circomkit, WitnessTester, PolynomialDigest, http_response_plaintext, http_start_line, http_header_0, http_header_1, http_body, modAdd } from "../common"; import { assert } from "chai"; -import { DataHasher } from "../common/poseidon"; +import { poseidon1 } from "poseidon-lite"; // HTTP/1.1 200 OK // content-type: application/json; charset=utf-8 @@ -20,148 +20,127 @@ import { DataHasher } from "../common/poseidon"; // } // } -// 320 bytes in the HTTP response -let TEST_HTTP = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 99, 111, 110, 116, 101, 110, - 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, - 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 99, - 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, - 112, 13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, - 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 13, 10, 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, - 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, - 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, - 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, - 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, - 10, 32, 32, 32, 125, 13, 10, 125]; - -const TEST_HTTP_START_LINE = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -]; - -const TEST_HTTP_HEADER_0 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 111, 110, 116, 101, 110, 116, 45, 116, - 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, 115, 111, - 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; - -const TEST_HTTP_HEADER_1 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 99, 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, - 105, 112, 13, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; - -const TEST_HTTP_BODY = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 34, - 100, 97, 116, 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, - 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, - 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, - 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, - 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 13, 10, 125, -]; - const DATA_BYTES = 320; const MAX_NUMBER_OF_HEADERS = 2; -describe("HTTP Verfication", async () => { - let dataHasher: WitnessTester<["in"], ["out"]>; - let httpNivc: WitnessTester<["step_in", "data", "start_line_hash", "header_hashes", "body_hash"], ["step_out"]>; +describe("HTTP Verification", async () => { + let HTTPVerification: WitnessTester<["step_in", "data", "main_digests", "ciphertext_digest"], ["step_out"]>; before(async () => { - dataHasher = await circomkit.WitnessTester(`DataHasher`, { - file: "utils/hash", - template: "DataHasher", - params: [320], - }); - - httpNivc = await circomkit.WitnessTester("http_nivc", { + HTTPVerification = await circomkit.WitnessTester("http_nivc", { file: "http/verification", template: "HTTPVerification", params: [DATA_BYTES, MAX_NUMBER_OF_HEADERS] }); }); + const mock_ct_digest = poseidon1([69]); - it("witness: TEST_HTTP, single header", async () => { + it("witness: http_response_plaintext, no header", async () => { // Get all the hashes we need - // Get the data hash - let data_hash = await dataHasher.compute({ in: TEST_HTTP }, ["out"]); - // Get the start line hash - let start_line_hash = await dataHasher.compute({ in: TEST_HTTP_START_LINE }, ["out"]) - // Get the header hash - let header_hash = await dataHasher.compute({ in: TEST_HTTP_HEADER_0 }, ["out"]); - // Get the body hash - let body_hash = await dataHasher.compute({ in: TEST_HTTP_BODY }, ["out"]); + let data_digest = PolynomialDigest(http_response_plaintext, mock_ct_digest); + let data_digest_hashed = poseidon1([data_digest]); + + // Compute the HTTP info digest + let start_line_digest = PolynomialDigest(http_start_line, mock_ct_digest); + let start_line_digest_hashed = poseidon1([start_line_digest]); + let body_digest = PolynomialDigest(http_body, mock_ct_digest); + let body_digest_hashed = poseidon1([body_digest]); + // Use `modAdd` to get back a number between 0 and PRIME + let output_difference = modAdd(body_digest_hashed - start_line_digest_hashed - data_digest_hashed, BigInt(0)); // Run the HTTP circuit // POTENTIAL BUG: I didn't get this to work with `expectPass` as it didn't compute `step_out` that way??? - let http_nivc_compute = await httpNivc.compute({ - step_in: data_hash.out, - data: TEST_HTTP, - start_line_hash: start_line_hash.out, - header_hashes: [header_hash.out, 0], - body_hash: body_hash.out, + let http_nivc_compute = await HTTPVerification.compute({ + step_in: 0, // This doesn't really matter for this test + data: http_response_plaintext, + main_digests: [start_line_digest].concat(Array(2).fill(0)), + ciphertext_digest: mock_ct_digest }, ["step_out"]); + // I fucking hate circomkit + assert.deepEqual((http_nivc_compute.step_out as BigInt[])[0], output_difference); + }); + + it("witness: http_response_plaintext, one header", async () => { + // Get all the hashes we need + let data_digest = PolynomialDigest(http_response_plaintext, mock_ct_digest); + let data_digest_hashed = poseidon1([data_digest]); + + // Compute the HTTP info digest + let start_line_digest = PolynomialDigest(http_start_line, mock_ct_digest); + let start_line_digest_hashed = poseidon1([start_line_digest]); + let header_0_digest = PolynomialDigest(http_header_0, mock_ct_digest); + let header_0_digest_hashed = poseidon1([header_0_digest]); + let body_digest = PolynomialDigest(http_body, mock_ct_digest); + let body_digest_hashed = poseidon1([body_digest]); + // Use `modAdd` to get back a number between 0 and PRIME + let output_difference = modAdd(body_digest_hashed - start_line_digest_hashed - header_0_digest_hashed - data_digest_hashed, BigInt(0)); - assert.deepEqual(http_nivc_compute.step_out, body_hash.out); + // Run the HTTP circuit + // POTENTIAL BUG: I didn't get this to work with `expectPass` as it didn't compute `step_out` that way??? + let http_nivc_compute = await HTTPVerification.compute({ + step_in: 0, // This doesn't really matter for this test + data: http_response_plaintext, + main_digests: [start_line_digest, header_0_digest].concat(Array(1).fill(0)), + ciphertext_digest: mock_ct_digest + }, ["step_out"]); + // I fucking hate circomkit + assert.deepEqual((http_nivc_compute.step_out as BigInt[])[0], output_difference); }); - it("witness: TEST_HTTP, two headers", async () => { + it("witness: http_response_plaintext, two headers", async () => { // Get all the hashes we need - // Get the data hash - let data_hash = await dataHasher.compute({ in: TEST_HTTP }, ["out"]); - // Get the start line hash - let start_line_hash = await dataHasher.compute({ in: TEST_HTTP_START_LINE }, ["out"]) - // Get the header hashes - let header_0_hash = await dataHasher.compute({ in: TEST_HTTP_HEADER_0 }, ["out"]); - let header_1_hash = await dataHasher.compute({ in: TEST_HTTP_HEADER_1 }, ["out"]); - // Get the body hash - let body_hash = await dataHasher.compute({ in: TEST_HTTP_BODY }, ["out"]); + let data_digest = PolynomialDigest(http_response_plaintext, mock_ct_digest); + let data_digest_hashed = poseidon1([data_digest]); + + // Compute the HTTP info digest + let start_line_digest = PolynomialDigest(http_start_line, mock_ct_digest); + let start_line_digest_hashed = poseidon1([start_line_digest]); + let header_0_digest = PolynomialDigest(http_header_0, mock_ct_digest); + let header_0_digest_hashed = poseidon1([header_0_digest]); + let header_1_digest = PolynomialDigest(http_header_1, mock_ct_digest); + let header_1_digest_hashed = poseidon1([header_1_digest]); + let body_digest = PolynomialDigest(http_body, mock_ct_digest); + let body_digest_hashed = poseidon1([body_digest]); + // Use `modAdd` to get back a number between 0 and PRIME + let output_difference = modAdd(body_digest_hashed - start_line_digest_hashed - header_0_digest_hashed - header_1_digest_hashed - data_digest_hashed, BigInt(0)); // Run the HTTP circuit // POTENTIAL BUG: I didn't get this to work with `expectPass` as it didn't compute `step_out` that way??? - let http_nivc_compute = await httpNivc.compute({ - step_in: data_hash.out, - data: TEST_HTTP, - start_line_hash: start_line_hash.out, - header_hashes: [header_0_hash.out, header_1_hash.out], - body_hash: body_hash.out, + let http_nivc_compute = await HTTPVerification.compute({ + step_in: 0, // This doesn't really matter for this test + data: http_response_plaintext, + main_digests: [start_line_digest, header_0_digest, header_1_digest], + ciphertext_digest: mock_ct_digest }, ["step_out"]); + // I fucking hate circomkit + assert.deepEqual((http_nivc_compute.step_out as BigInt[])[0], output_difference); + }); - assert.deepEqual(http_nivc_compute.step_out, body_hash.out); + it("witness: http_response_plaintext, two headers, order does not matter", async () => { + // Get all the hashes we need + let data_digest = PolynomialDigest(http_response_plaintext, mock_ct_digest); + let data_digest_hashed = poseidon1([data_digest]); + + // Compute the HTTP info digest + let start_line_digest = PolynomialDigest(http_start_line, mock_ct_digest); + let start_line_digest_hashed = poseidon1([start_line_digest]); + let header_0_digest = PolynomialDigest(http_header_0, mock_ct_digest); + let header_0_digest_hashed = poseidon1([header_0_digest]); + let header_1_digest = PolynomialDigest(http_header_1, mock_ct_digest); + let header_1_digest_hashed = poseidon1([header_1_digest]); + let body_digest = PolynomialDigest(http_body, mock_ct_digest); + let body_digest_hashed = poseidon1([body_digest]); + // Use `modAdd` to get back a number between 0 and PRIME + let output_difference = modAdd(body_digest_hashed - start_line_digest_hashed - header_0_digest_hashed - header_1_digest_hashed - data_digest_hashed, BigInt(0)); + + // Run the HTTP circuit + // POTENTIAL BUG: I didn't get this to work with `expectPass` as it didn't compute `step_out` that way??? + let http_nivc_compute = await HTTPVerification.compute({ + step_in: 0, // This doesn't really matter for this test + data: http_response_plaintext, + main_digests: [header_1_digest, start_line_digest, header_0_digest], + ciphertext_digest: mock_ct_digest + }, ["step_out"]); + // I fucking hate circomkit + assert.deepEqual((http_nivc_compute.step_out as BigInt[])[0], output_difference); }); }); \ No newline at end of file diff --git a/circuits/test/json/extraction.test.ts b/circuits/test/json/extraction.test.ts new file mode 100644 index 0000000..152df1a --- /dev/null +++ b/circuits/test/json/extraction.test.ts @@ -0,0 +1,194 @@ +import { poseidon1, poseidon2 } from "poseidon-lite"; +import { circomkit, WitnessTester, readJSONInputFile, strToBytes, JsonMaskType, jsonTreeHasher, compressTreeHash, PolynomialDigest, modAdd } from "../common"; + +describe("JSON Extraction", () => { + let hash_parser: WitnessTester<["step_in", "ciphertext_digest", "data", "sequence_digest", "value_digest"]>; + const mock_ct_digest = poseidon2([69, 420]); + + it(`input: array_only`, async () => { + let filename = "array_only"; + let [input, _keyUnicode, _output] = readJSONInputFile(`${filename}.json`, []); + const MAX_STACK_HEIGHT = 3; + + hash_parser = await circomkit.WitnessTester(`Parser`, { + file: "json/extraction", + template: "JSONExtraction", + params: [input.length, MAX_STACK_HEIGHT], + }); + + // Test `42` in 0th slot + let targetValue = strToBytes("42"); + let keySequence: JsonMaskType[] = [ + { type: "ArrayIndex", value: 0 }, + ]; + let [stack, treeHashes] = jsonTreeHasher(mock_ct_digest, keySequence, MAX_STACK_HEIGHT); + let sequence_digest = compressTreeHash(mock_ct_digest, [stack, treeHashes]); + let sequence_digest_hashed = poseidon1([sequence_digest]); + let value_digest = PolynomialDigest(targetValue, mock_ct_digest); + let data_digest = PolynomialDigest(input, mock_ct_digest); + let data_digest_hashed = poseidon1([data_digest]); + let step_in = modAdd(sequence_digest_hashed, data_digest_hashed); + + await hash_parser.expectPass({ + data: input, + ciphertext_digest: mock_ct_digest, + sequence_digest, + value_digest, + step_in + }); + console.log("> First subtest passed."); + + // Test `"b"` in 1st slot object + targetValue = strToBytes("b"); + keySequence = [ + { type: "ArrayIndex", value: 1 }, + { type: "Object", value: strToBytes("a") }, + ]; + [stack, treeHashes] = jsonTreeHasher(mock_ct_digest, keySequence, MAX_STACK_HEIGHT); + sequence_digest = compressTreeHash(mock_ct_digest, [stack, treeHashes]); + sequence_digest_hashed = poseidon1([sequence_digest]); + value_digest = PolynomialDigest(targetValue, mock_ct_digest); + step_in = modAdd(sequence_digest_hashed, data_digest_hashed); + + await hash_parser.expectPass({ + data: input, + ciphertext_digest: mock_ct_digest, + sequence_digest, + value_digest, + step_in + }); + console.log("> Second subtest passed."); + }); + + it(`input: value_array`, async () => { + let filename = "value_array"; + let [input, _keyUnicode, _output] = readJSONInputFile(`${filename}.json`, []); + const MAX_STACK_HEIGHT = 3; + + hash_parser = await circomkit.WitnessTester(`Parser`, { + file: "json/extraction", + template: "JSONExtraction", + params: [input.length, MAX_STACK_HEIGHT], + }); + + // Test `420` in "k"'s 0th slot + let targetValue = strToBytes("420"); + let keySequence: JsonMaskType[] = [ + { type: "Object", value: strToBytes("k") }, + { type: "ArrayIndex", value: 0 }, + ]; + let [stack, treeHashes] = jsonTreeHasher(mock_ct_digest, keySequence, MAX_STACK_HEIGHT); + let sequence_digest = compressTreeHash(mock_ct_digest, [stack, treeHashes]); + let sequence_digest_hashed = poseidon1([sequence_digest]); + let data_digest = PolynomialDigest(input, mock_ct_digest); + let data_digest_hashed = poseidon1([data_digest]); + let value_digest = PolynomialDigest(targetValue, mock_ct_digest); + let step_in = modAdd(sequence_digest_hashed, data_digest_hashed); + + await hash_parser.expectPass({ + data: input, + ciphertext_digest: mock_ct_digest, + sequence_digest, + value_digest, + step_in + }); + console.log("> First subtest passed."); + + // Test `"d"` in "b"'s 3rd slot + targetValue = strToBytes("d"); + keySequence = [ + { type: "Object", value: strToBytes("b") }, + { type: "ArrayIndex", value: 3 }, + ]; + [stack, treeHashes] = jsonTreeHasher(mock_ct_digest, keySequence, MAX_STACK_HEIGHT); + sequence_digest = compressTreeHash(mock_ct_digest, [stack, treeHashes]); + sequence_digest_hashed = poseidon1([sequence_digest]); + value_digest = PolynomialDigest(targetValue, mock_ct_digest); + step_in = modAdd(sequence_digest_hashed, data_digest_hashed); + await hash_parser.expectPass({ + data: input, + ciphertext_digest: mock_ct_digest, + sequence_digest, + value_digest, + step_in + }); + console.log("> Second subtest passed."); + }); + + it(`input: value_array_object`, async () => { + let filename = "value_array_object"; + let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, []); + hash_parser = await circomkit.WitnessTester(`Parser`, { + file: "json/extraction", + template: "JSONExtraction", + params: [input.length, 5], + }); + + const KEY0 = strToBytes("a"); + const KEY1 = strToBytes("b"); + const targetValue = strToBytes("4"); + + const keySequence: JsonMaskType[] = [ + { type: "Object", value: KEY0 }, + { type: "ArrayIndex", value: 0 }, + { type: "Object", value: KEY1 }, + { type: "ArrayIndex", value: 1 }, + ]; + + const [stack, treeHashes] = jsonTreeHasher(mock_ct_digest, keySequence, 10); + const sequence_digest = compressTreeHash(mock_ct_digest, [stack, treeHashes]); + const sequence_digest_hashed = poseidon1([sequence_digest]); + const data_digest = PolynomialDigest(input, mock_ct_digest); + const data_digest_hashed = poseidon1([data_digest]); + const value_digest = PolynomialDigest(targetValue, mock_ct_digest); + const step_in = modAdd(sequence_digest_hashed, data_digest_hashed); + + await hash_parser.expectPass({ + data: input, + ciphertext_digest: mock_ct_digest, + sequence_digest, + value_digest, + step_in + }); + }); + + it(`input: spotify`, async () => { + let filename = "spotify"; + let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, []); + hash_parser = await circomkit.WitnessTester(`Parser`, { + file: "json/extraction", + template: "JSONExtraction", + params: [input.length, 5], + }); + + const KEY0 = strToBytes("data"); + const KEY1 = strToBytes("items"); + const KEY2 = strToBytes("profile"); + const KEY3 = strToBytes("name"); + const targetValue = strToBytes("Taylor Swift"); + + const keySequence: JsonMaskType[] = [ + { type: "Object", value: KEY0 }, + { type: "Object", value: KEY1 }, + { type: "ArrayIndex", value: 0 }, + { type: "Object", value: KEY2 }, + { type: "Object", value: KEY3 }, + ]; + + const [stack, treeHashes] = jsonTreeHasher(mock_ct_digest, keySequence, 10); + const sequence_digest = compressTreeHash(mock_ct_digest, [stack, treeHashes]); + const sequence_digest_hashed = poseidon1([sequence_digest]); + const data_digest = PolynomialDigest(input, mock_ct_digest); + const data_digest_hashed = poseidon1([data_digest]); + const value_digest = PolynomialDigest(targetValue, mock_ct_digest); + const step_in = modAdd(sequence_digest_hashed, data_digest_hashed); + + await hash_parser.expectPass({ + data: input, + ciphertext_digest: mock_ct_digest, + sequence_digest, + value_digest, + step_in + }); + }); +}) \ No newline at end of file diff --git a/circuits/test/json/extractor/interpreter.test.ts b/circuits/test/json/extractor/interpreter.test.ts deleted file mode 100644 index eed2ab2..0000000 --- a/circuits/test/json/extractor/interpreter.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -import { circomkit, WitnessTester, generateDescription, readJSONInputFile } from "../../common"; - -describe("Interpreter", async () => { - describe("InsideKeyAtTop", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`InsideKeyAtTop`, { - file: "json/interpreter", - template: "InsideKeyAtTop", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, ""); - - let input3 = { stack: [[1, 0], [0, 0], [0, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, "parsing number as a key"); - }); - - describe("InsideKey", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`InsideKey`, { - file: "json/interpreter", - template: "InsideKey", - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [1, 0], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - // fail cases - - let input2 = { stack: [1, 1], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, { out: 0 }, "invalid stack"); - - let input3 = { stack: [1, 0], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input3, { out: 0 }, "parsing number as a key"); - }); - - describe("InsideValueAtTop", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`InsideValueAtTop`, { - file: "json/interpreter", - template: "InsideValueAtTop", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 1], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, ""); - - let input3 = { stack: [[1, 1], [0, 0], [0, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, "parsing number and key both"); - }); - - describe("InsideValue", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - function generatePassCase(input: any, expected: any, depth: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`InsideValue`, { - file: "json/interpreter", - template: "InsideValue", - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - input.stack = input.stack[depth]; - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, 3, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 1], [1, 1]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, 2, ""); - - let input3 = { stack: [[1, 1], [0, 0], [0, 0], [1, 1]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, 0, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, 0, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, 3, "parsing number and key both"); - }); - - describe("InsideArrayIndexAtTop", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - function generatePassCase(input: any, expected: any, index: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`InsideArrayIndexAtTop`, { - file: "json/interpreter", - template: "InsideArrayIndexAtTop", - params: [4, index], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [2, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, 1, ""); - - let input2 = { stack: [[1, 0], [2, 0], [2, 3], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, 3, ""); - - let input3 = { stack: [[2, 10], [0, 0], [0, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, 10, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, 4, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, 4, "parsing number and key both"); - - let input6 = { stack: [[1, 0], [2, 0], [3, 1], [2, 4]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input6, { out: 0 }, 3, "incorrect index"); - }); - - describe("InsideArrayIndex", async () => { - let circuit: WitnessTester<["stack", "parsing_string", "parsing_number"], ["out"]>; - - function generatePassCase(input: any, expected: any, index: number, depth: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`InsideArrayIndex`, { - file: "json/interpreter", - template: "InsideArrayIndex", - params: [index], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - input.stack = input.stack[depth] - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [2, 1]], parsing_string: 1, parsing_number: 0 }; - let output = { out: 1 }; - generatePassCase(input1, output, 1, 3, ""); - - let input2 = { stack: [[1, 0], [2, 0], [2, 3], [2, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input2, output, 3, 2, ""); - - let input3 = { stack: [[2, 10], [0, 0], [1, 0], [0, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input3, output, 10, 0, ""); - - // fail cases - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], parsing_string: 1, parsing_number: 0 }; - generatePassCase(input4, { out: 0 }, 4, 2, "invalid stack depth"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], parsing_string: 1, parsing_number: 1 }; - generatePassCase(input5, { out: 0 }, 4, 1, "parsing number and key both"); - }); - - describe("NextKVPair", async () => { - let circuit: WitnessTester<["stack", "currByte"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`NextKVPair`, { - file: "json/interpreter", - template: "NextKVPair", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 44 }; - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], currByte: 44 }; - generatePassCase(input2, output, ""); - - let input3 = { stack: [[1, 0], [0, 0], [0, 0], [0, 0]], currByte: 44 }; - generatePassCase(input3, output, ""); - - let input4 = { stack: [[1, 0], [2, 0], [3, 1], [1, 1]], currByte: 44 }; - generatePassCase(input4, { out: 0 }, "invalid stack"); - - let input5 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 34 }; - generatePassCase(input5, { out: 0 }, "incorrect currByte"); - }); - - describe("NextKVPairAtDepth", async () => { - let circuit: WitnessTester<["stack", "currByte", "depth"], ["out"]>; - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`NextKVPairAtDepth`, { - file: "json/interpreter", - template: "NextKVPairAtDepth", - params: [4], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input1 = { stack: [[1, 0], [2, 0], [3, 1], [1, 0]], currByte: 44, depth: 3 }; - // output = 1 represents correct execution - let output = { out: 1 }; - generatePassCase(input1, output, ""); - - // key depth is 2, and even if new-kv pair starts at depth greater than 2, it returns 0. - let input2 = { stack: [[1, 0], [2, 0], [1, 1], [1, 0]], currByte: 44, depth: 2 }; - generatePassCase(input2, { out: 0 }, ""); - - let input3 = { stack: [[1, 0], [1, 0], [0, 0], [0, 0]], currByte: 44, depth: 3 }; - generatePassCase(input3, output, "stack height less than specified"); - - let input4 = { stack: [[1, 0], [2, 0], [1, 0], [0, 0]], currByte: 34, depth: 2 }; - generatePassCase(input4, { out: 0 }, "incorrect currByte"); - }); - - describe("KeyMatch", async () => { - let circuit: WitnessTester<["data", "key", "index", "parsing_key"], ["out"]>; - - function generatePassCase(input: any, expected: any, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`KeyMatch`, { - file: "json/interpreter", - template: "KeyMatch", - params: [input.data.length, input.key.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input = readJSONInputFile("value_array_object.json", ["a"]); - - let output = { out: 1 }; - let input1 = { data: input[0], key: input[1][0], index: 2, parsing_key: 1 }; - generatePassCase(input1, output, ""); - - let input2 = { data: input[0], key: [99], index: 20, parsing_key: 1 }; - generatePassCase(input2, output, ""); - - // fail cases - - let input3 = { data: input[0], key: input[1][0], index: 3, parsing_key: 1 }; - generatePassCase(input3, { out: 0 }, "wrong index"); - - let input4 = { data: input[0], key: [98], index: 2, parsing_key: 1 }; - generatePassCase(input4, { out: 0 }, "wrong key"); - - let input5 = { data: input[0], key: [97], index: 2, parsing_key: 0 }; - generatePassCase(input5, { out: 0 }, "not parsing key"); - }); - - describe("KeyMatchAtDepth", async () => { - let circuit: WitnessTester<["data", "key", "index", "parsing_key", "stack"], ["out"]>; - - function generatePassCase(input: any, expected: any, depth: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - circuit = await circomkit.WitnessTester(`KeyMatchAtDepth`, { - file: "json/interpreter", - template: "KeyMatchAtDepth", - params: [input.data.length, 4, input.key.length, depth], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input = readJSONInputFile("value_array_object.json", ["a", 0, "b", 0]); - - let output = { out: 1 }; - - let input1 = { data: input[0], key: input[1][0], index: 2, parsing_key: 1, stack: [[1, 0], [0, 0], [0, 0], [0, 0]] }; - generatePassCase(input1, output, 0, ""); - - let input2 = { data: input[0], key: input[1][2], index: 8, parsing_key: 1, stack: [[1, 1], [2, 0], [1, 0], [0, 0]] }; - generatePassCase(input2, output, 2, ""); - - let input3 = { data: input[0], key: [99], index: 20, parsing_key: 1, stack: [[1, 1], [2, 1], [1, 1], [0, 0]] }; - generatePassCase(input3, output, 2, "wrong stack"); - - // fail cases - - let input4 = { data: input[0], key: input[1][1], index: 3, parsing_key: 1, stack: [[1, 0], [2, 0], [1, 0], [0, 0]] }; - generatePassCase(input4, { out: 0 }, 2, "wrong key"); - - let input5 = { data: input[0], key: [97], index: 12, parsing_key: 0, stack: [[1, 1], [2, 0], [1, 1], [0, 0]] }; - generatePassCase(input5, { out: 0 }, 3, "not parsing key"); - - let input6Data = input[0].slice(0); - input6Data.splice(1, 1, 35); - let input6 = { data: input6Data, key: input[1][0], index: 2, parsing_key: 1, stack: [[1, 0], [0, 0], [0, 0], [0, 0]] }; - generatePassCase(input6, { out: 0 }, 0, "invalid key (not surrounded by quotes)"); - - let input7 = { data: input[0], key: input[1][0], index: 2, parsing_key: 1, stack: [[1, 0], [0, 0], [0, 0], [0, 0]] }; - generatePassCase(input6, { out: 0 }, 1, "wrong depth"); - }); - - describe("KeyMatchAtIndex", async () => { - let circuit: WitnessTester<["data", "key", "keyLen", "parsing_key"], ["out"]>; - let maxKeyLen = 3; - - function generatePassCase(input: any, expected: any, index: number, desc: string) { - const description = generateDescription(input); - - it(`(valid) witness: ${description} ${desc}`, async () => { - // pad key with 0's - let padded_key = input.key.concat(Array(maxKeyLen - input.key.length).fill(0)); - input.key = padded_key; - - circuit = await circomkit.WitnessTester(`KeyMatchAtIndex`, { - file: "json/interpreter", - template: "KeyMatchAtIndex", - params: [input.data.length, maxKeyLen, index], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - await circuit.expectPass(input, expected); - }); - } - - let input = readJSONInputFile("value_array_object.json", ["a", 0, "b", 0]); - - let output = { out: 1 }; - - let key1 = input[1][0]; - let input1 = { data: input[0], key: key1, keyLen: key1.length, parsing_key: 1 }; - generatePassCase(input1, output, 2, ""); - - let key2 = input[1][2]; - let input2 = { data: input[0], key: key2, keyLen: key2.length, parsing_key: 1 }; - generatePassCase(input2, output, 8, ""); - - let input3 = { data: input[0], key: [99], keyLen: 1, parsing_key: 1 }; - generatePassCase(input3, output, 20, "wrong stack"); - - // fail cases - - let failOutput = { out: 0 }; - let key4 = input[1][1]; - let input4 = { data: input[0], key: key4, keyLen: key4.length, parsing_key: 1 }; - generatePassCase(input4, failOutput, 3, "wrong key"); - - let input5 = { data: input[0], key: [97], keyLen: 1, parsing_key: 0 }; - generatePassCase(input5, failOutput, 12, "not parsing key"); - - let input6Data = input[0].slice(0); - input6Data.splice(1, 1, 35); - let input6 = { data: input6Data, key: input[1][0], keyLen: input[1][0].length, parsing_key: 1 }; - generatePassCase(input6, failOutput, 2, "invalid key (not surrounded by quotes)"); - - let input7 = { data: input[0], key: input[1][0], keyLen: input[1][0].length, parsing_key: 1 }; - generatePassCase(input6, failOutput, 2, "wrong depth"); - }); -}); \ No newline at end of file diff --git a/circuits/test/json/parser/index.ts b/circuits/test/json/index.ts similarity index 100% rename from circuits/test/json/parser/index.ts rename to circuits/test/json/index.ts diff --git a/circuits/test/json/nivc/masker_nivc.test.ts b/circuits/test/json/nivc/masker_nivc.test.ts deleted file mode 100644 index 0d9a265..0000000 --- a/circuits/test/json/nivc/masker_nivc.test.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { circomkit, WitnessTester, generateDescription, readJsonFile, toByte } from "../../common"; -import { DataHasher } from "../../common/poseidon"; -import { assert } from "chai"; - -// HTTP/1.1 200 OK -// content-type: application/json; charset=utf-8 -// content-encoding: gzip -// Transfer-Encoding: chunked -// -// { -// "data": { -// "items": [ -// { -// "data": "Artist", -// "profile": { -// "name": "Taylor Swift" -// } -// } -// ] -// } -// } - -// 202 bytes in the JSON -let json_input = [ - 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, - 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, - 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 13, 10, 125]; - -const json_key0_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, - 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, - 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, 10, 32, 32, 32, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -const json_key0_mask_hash = DataHasher(json_key0_mask); - -const json_key1_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, - 116, 105, 115, 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 34, 112, 114, 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, - 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, - 32, 32, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -const json_key1_mask_hash = DataHasher(json_key1_mask); - -const json_arr_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, 116, - 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, 111, 102, 105, - 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, - 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_arr_mask_hash = DataHasher(json_arr_mask); - -const json_key2_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 110, 97, 109, - 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; - -const json_key2_mask_hash = DataHasher(json_key2_mask); - -const json_key3_mask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, 105, 102, 116, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -]; -const json_key3_mask_hash = DataHasher(json_key3_mask); - -describe("NIVC Extract", async () => { - let json_mask_object_circuit: WitnessTester<["step_in", "data", "key", "keyLen"], ["step_out"]>; - let json_mask_arr_circuit: WitnessTester<["step_in", "data", "index"], ["step_out"]>; - let extract_value_circuit: WitnessTester<["step_in", "data"], ["step_out"]>; - - const DATA_BYTES = 208; - const MAX_STACK_HEIGHT = 5; - const MAX_KEY_LENGTH = 8; - const MAX_VALUE_LENGTH = 32; - - before(async () => { - json_mask_arr_circuit = await circomkit.WitnessTester(`JsonMaskArrayIndexNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskArrayIndexNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT], - }); - console.log("#constraints:", await json_mask_arr_circuit.getConstraintCount()); - - json_mask_object_circuit = await circomkit.WitnessTester(`JsonMaskObjectNIVC`, { - file: "json/nivc/masker", - template: "JsonMaskObjectNIVC", - params: [DATA_BYTES, MAX_STACK_HEIGHT, MAX_KEY_LENGTH], - }); - console.log("#constraints:", await json_mask_object_circuit.getConstraintCount()); - - extract_value_circuit = await circomkit.WitnessTester(`JsonMaskExtractFinal`, { - file: "json/nivc/extractor", - template: "MaskExtractFinal", - params: [DATA_BYTES, MAX_VALUE_LENGTH], - }); - console.log("#constraints:", await extract_value_circuit.getConstraintCount()); - }); - - - let key0 = [100, 97, 116, 97, 0, 0, 0, 0]; // "data" - let key0Len = 4; - let key1 = [105, 116, 101, 109, 115, 0, 0, 0]; // "items" - let key1Len = 5; - let key2 = [112, 114, 111, 102, 105, 108, 101, 0]; // "profile" - let key2Len = 7; - let key3 = [110, 97, 109, 101, 0, 0, 0, 0]; // "name" - let key3Len = 4; - - let value = toByte("\"Taylor Swift\""); - - it("parse and mask", async () => { - - console.log(json_input.length); - let extended_json_input = json_input.concat(Array(Math.max(0, DATA_BYTES - json_input.length)).fill(0)); - - let jsonInputHash = DataHasher(extended_json_input); - let json_extract_key0 = await json_mask_object_circuit.compute({ step_in: jsonInputHash, data: extended_json_input, key: key0, keyLen: key0Len }, ["step_out"]); - console.log("JSON Extract key0 `step_out`:", json_extract_key0.step_out); - assert.deepEqual(json_extract_key0.step_out, json_key0_mask_hash); - - let json_extract_key1 = await json_mask_object_circuit.compute({ step_in: json_extract_key0.step_out, data: json_key0_mask, key: key1, keyLen: key1Len }, ["step_out"]); - assert.deepEqual(json_extract_key1.step_out, json_key1_mask_hash); - console.log("JSON Extract key1 `step_out`:", json_extract_key1.step_out); - - let json_extract_arr = await json_mask_arr_circuit.compute({ step_in: json_extract_key1.step_out, index: 0, data: json_key1_mask }, ["step_out"]); - assert.deepEqual(json_extract_arr.step_out, json_arr_mask_hash); - console.log("JSON Extract arr `step_out`:", json_extract_arr.step_out); - - let json_extract_key2 = await json_mask_object_circuit.compute({ step_in: json_extract_arr.step_out, data: json_arr_mask, key: key2, keyLen: key2Len }, ["step_out"]); - assert.deepEqual(json_extract_key2.step_out, json_key2_mask_hash); - console.log("JSON Extract key2 `step_out`:", json_extract_key2.step_out); - - let json_extract_key3 = await json_mask_object_circuit.compute({ step_in: json_extract_key2.step_out, data: json_key2_mask, key: key3, keyLen: key3Len }, ["step_out"]); - assert.deepEqual(json_extract_key3.step_out, json_key3_mask_hash); - console.log("JSON Extract key3 `step_out`:", json_extract_key3.step_out); - - value = value.concat(Array(MAX_VALUE_LENGTH - value.length).fill(0)); - let final_value_hash = DataHasher(value); - let extractValue = await extract_value_circuit.compute({ step_in: json_extract_key3.step_out, data: json_key3_mask }, ["step_out"]); - console.log("JSON Extract finalValue `step_out`:", extractValue.step_out); - assert.deepEqual(extractValue.step_out, final_value_hash); - }); -}); \ No newline at end of file diff --git a/circuits/test/json/parser/parser.test.ts b/circuits/test/json/parser.test.ts similarity index 69% rename from circuits/test/json/parser/parser.test.ts rename to circuits/test/json/parser.test.ts index eccbc99..0c525b0 100644 --- a/circuits/test/json/parser/parser.test.ts +++ b/circuits/test/json/parser.test.ts @@ -1,6 +1,6 @@ -import { circomkit, WitnessTester, generateDescription, readJSONInputFile } from "../../common"; +import { circomkit, WitnessTester, readJSONInputFile } from "../common"; -describe("json-parser", () => { +describe("JSON Parser", () => { let circuit: WitnessTester<["data"]>; it(`array only input`, async () => { @@ -8,11 +8,10 @@ describe("json-parser", () => { let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, [0]); circuit = await circomkit.WitnessTester(`Parser`, { - file: "json/parser/parser", + file: "json/parser", template: "Parser", params: [input.length, 2], }); - console.log("#constraints:", await circuit.getConstraintCount()); await circuit.expectPass({ data: input @@ -24,11 +23,10 @@ describe("json-parser", () => { let [input, keyUnicode, output] = readJSONInputFile(`${filename}.json`, ["a"]); circuit = await circomkit.WitnessTester(`Parser`, { - file: "json/parser/parser", + file: "json/parser", template: "Parser", params: [input.length, 3], }); - console.log("#constraints:", await circuit.getConstraintCount()); await circuit.expectPass({ data: input diff --git a/circuits/test/json/parser/parsing_types.test.ts b/circuits/test/json/parsing_types.test.ts similarity index 94% rename from circuits/test/json/parser/parsing_types.test.ts rename to circuits/test/json/parsing_types.test.ts index 88d892e..a803fc3 100644 --- a/circuits/test/json/parser/parsing_types.test.ts +++ b/circuits/test/json/parsing_types.test.ts @@ -1,7 +1,5 @@ -import { circomkit, WitnessTester, generateDescription } from "../../common"; -import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; - - +import { circomkit, WitnessTester, generateDescription } from "../common"; +import { Delimiters, WhiteSpace, INITIAL_IN, INITIAL_OUT } from '.'; describe("StateUpdate", () => { let circuit: WitnessTester< @@ -19,12 +17,10 @@ describe("StateUpdate", () => { before(async () => { circuit = await circomkit.WitnessTester(`StateUpdate`, { - file: "json/parser/machine", + file: "json/machine", template: "StateUpdate", params: [4], }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); //-TEST_1----------------------------------------------------------// diff --git a/circuits/test/json/parser/stack.test.ts b/circuits/test/json/stack.test.ts similarity index 96% rename from circuits/test/json/parser/stack.test.ts rename to circuits/test/json/stack.test.ts index 860737e..6140d64 100644 --- a/circuits/test/json/parser/stack.test.ts +++ b/circuits/test/json/stack.test.ts @@ -1,15 +1,14 @@ -import { circomkit, WitnessTester, generateDescription } from "../../common"; -import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; +import { circomkit, WitnessTester, generateDescription } from "../common"; +import { Delimiters, INITIAL_IN, INITIAL_OUT } from '.'; describe("GetTopOfStack", () => { let circuit: WitnessTester<["stack"], ["value", "pointer"]>; before(async () => { circuit = await circomkit.WitnessTester(`GetTopOfStack`, { - file: "json/parser/machine", + file: "json/machine", template: "GetTopOfStack", params: [4], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); function generatePassCase(input: any, expected: any) { @@ -34,11 +33,10 @@ describe("StateUpdate :: RewriteStack", () => { >; before(async () => { circuit = await circomkit.WitnessTester(`GetTopOfStack`, { - file: "json/parser/machine", + file: "json/machine", template: "StateUpdate", params: [4], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); function generatePassCase(input: any, expected: any, desc: string) { diff --git a/circuits/test/json/parser/values.test.ts b/circuits/test/json/values.test.ts similarity index 98% rename from circuits/test/json/parser/values.test.ts rename to circuits/test/json/values.test.ts index 069525b..f51f43b 100644 --- a/circuits/test/json/parser/values.test.ts +++ b/circuits/test/json/values.test.ts @@ -1,4 +1,4 @@ -import { circomkit, WitnessTester, generateDescription } from "../../common"; +import { circomkit, WitnessTester, generateDescription } from "../common"; import { Delimiters, WhiteSpace, Numbers, Escape, INITIAL_IN, INITIAL_OUT } from '.'; describe("StateUpdate :: Values", () => { @@ -8,12 +8,12 @@ describe("StateUpdate :: Values", () => { >; before(async () => { circuit = await circomkit.WitnessTester(`GetTopOfStack`, { - file: "json/parser/machine", + file: "json/machine", template: "StateUpdate", params: [4], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); + function generatePassCase(input: any, expected: any, desc: string) { const description = generateDescription(input); diff --git a/circuits/test/utils/array.test.ts b/circuits/test/utils/array.test.ts index 1202a47..2b88325 100644 --- a/circuits/test/utils/array.test.ts +++ b/circuits/test/utils/array.test.ts @@ -1,4 +1,5 @@ import { circomkit, WitnessTester } from "../common"; + describe("IsEqualArray", () => { let circuit: WitnessTester<["in"], ["out"]>; before(async () => { @@ -7,7 +8,6 @@ describe("IsEqualArray", () => { template: "IsEqualArray", params: [3], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: [[0,0,0],[0,0,0]]", async () => { @@ -61,7 +61,6 @@ describe("Contains", () => { template: "Contains", params: [3], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: in = 0, array = [0,1,2]", async () => { @@ -102,7 +101,6 @@ describe("ArrayAdd", () => { template: "ArrayAdd", params: [3], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: lhs = [0,1,2], rhs = [3,5,7]", async () => { @@ -122,7 +120,6 @@ describe("ArrayMul", () => { template: "ArrayMul", params: [3], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: lhs = [0,1,2], rhs = [3,5,7]", async () => { @@ -142,7 +139,6 @@ describe("GenericArrayAdd", () => { template: "GenericArrayAdd", params: [3, 2], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: arrays = [[0,1,2],[3,5,7]]", async () => { @@ -161,7 +157,6 @@ describe("fromLittleEndianToWords32", () => { file: "utils/array", template: "fromLittleEndianToWords32", }); - console.log("#constraints:", await circuit.getConstraintCount()); let input = [ 0, 1, 0, 1, 0, 0, 0, 0, 0, @@ -180,7 +175,6 @@ describe("fromWords32ToLittleEndian", () => { file: "utils/array", template: "fromWords32ToLittleEndian", }); - console.log("#constraints:", await circuit.getConstraintCount()); let input = [72, 84, 84, 80]; await circuit.expectPass({ words: input }, { diff --git a/circuits/test/utils/bits.test.ts b/circuits/test/utils/bits.test.ts deleted file mode 100644 index 30dfdc4..0000000 --- a/circuits/test/utils/bits.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { circomkit, WitnessTester } from "../common"; - -describe("ASCII", () => { - let circuit: WitnessTester<["in"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`ASCII`, { - file: "utils/bits", - template: "ASCII", - params: [13], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("(valid) witness: in = b\"Hello, world!\"", async () => { - await circuit.expectPass( - { in: [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] }, - ); - }); - - it("(invalid) witness: in = [256, ...]", async () => { - await circuit.expectFail( - { in: [256, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] } - ); - }); -}); \ No newline at end of file diff --git a/circuits/test/utils/hash.test.ts b/circuits/test/utils/hash.test.ts index c62b969..3c8718a 100644 --- a/circuits/test/utils/hash.test.ts +++ b/circuits/test/utils/hash.test.ts @@ -1,184 +1,141 @@ import assert from "assert"; -import { circomkit, WitnessTester } from "../common"; +import { circomkit, http_response_plaintext, http_start_line, PolynomialDigest, WitnessTester } from "../common"; import { DataHasher, PoseidonModular } from "../common/poseidon"; +import { poseidon1 } from "poseidon-lite"; -describe("hash", () => { - describe("PoseidonModular_16", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`PoseidonModular`, { - file: "utils/hash", - template: "PoseidonModular", - params: [16], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - it("witness: in = [16*random]", async () => { - const input = Array.from({ length: 16 }, () => Math.floor(Math.random() * 256)); - const hash = PoseidonModular(input); +describe("DataHasher", () => { + let circuit: WitnessTester<["in"], ["out"]>; - await circuit.expectPass( - { in: input }, - { out: hash } - ); + before(async () => { + circuit = await circomkit.WitnessTester(`DataHasher`, { + file: "utils/hash", + template: "DataHasher", + params: [16], }); }); - describe("PoseidonModular_379", () => { - let circuit: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`PoseidonModular`, { - file: "utils/hash", - template: "PoseidonModular", - params: [379], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); + let all_zero_hash = BigInt("14744269619966411208579211824598458697587494354926760081771325075741142829156"); + it("witness: in = [0,...x16]", async () => { + const input = Array(16).fill(0); + await circuit.expectPass( + { in: input }, + { out: all_zero_hash } + ); + }); + // Check that TS version of DataHasher also is correct + assert.deepEqual(DataHasher(Array(16).fill(0)), all_zero_hash); + + it("witness: in = [-1,...x16]", async () => { + const input = Array(16).fill(-1); + await circuit.expectPass( + { in: input }, + { out: 0 } + ); + }); + // Check that TS version of DataHasher also is correct + assert.deepEqual(DataHasher(Array(16).fill(-1)), 0); + + it("witness: in = [1,0,...x15]", async () => { + let input = Array(16).fill(0); + input[0] = 1; + const hash = PoseidonModular([0, 1]); + await circuit.expectPass( + { in: input }, + { out: hash } + ); + }); - it("witness: in = [379*random]", async () => { - const input = Array.from({ length: 379 }, () => Math.floor(Math.random() * 256)); - const hash = PoseidonModular(input); - await circuit.expectPass( - { in: input }, - { out: hash } - ); - }); + it("witness: in = [0,0,...x15,1]", async () => { + let input = Array(16).fill(0); + input[15] = 1; + const hash = PoseidonModular([0, "1329227995784915872903807060280344576"]); + await circuit.expectPass( + { in: input }, + { out: hash } + ); }); +}); + +const padded_http_start_line = http_start_line.concat(Array(320 - http_start_line.length).fill(-1)); - describe("PoseidonChainer", () => { - let circuit: WitnessTester<["in"], ["out"]>; +describe("DataHasherHTTP", () => { + let circuit: WitnessTester<["in"], ["out"]>; + let circuit_small: WitnessTester<["in"], ["out"]>; - before(async () => { - circuit = await circomkit.WitnessTester(`PoseidonChainer`, { - file: "utils/hash", - template: "PoseidonChainer", - }); - console.log("#constraints:", await circuit.getConstraintCount()); + before(async () => { + circuit = await circomkit.WitnessTester(`DataHasher`, { + file: "utils/hash", + template: "DataHasher", + params: [320], }); - it("witness: in = [69,420]", async () => { - const input = [69, 420]; - const hash = PoseidonModular(input); - await circuit.expectPass( - { in: input }, - { out: hash } - ); + circuit_small = await circomkit.WitnessTester(`DataHasher`, { + file: "utils/hash", + template: "DataHasher", + params: [32], }); }); - describe("DataHasher", () => { - let circuit: WitnessTester<["in"], ["out"]>; + it("witness: HTTP bytes", async () => { + let hash = DataHasher(http_response_plaintext); + assert.deepEqual(String(hash), "2195365663909569734943279727560535141179588918483111718403427949138562480675"); + await circuit.expectPass({ in: http_response_plaintext }, { out: "2195365663909569734943279727560535141179588918483111718403427949138562480675" }); + }); - before(async () => { - circuit = await circomkit.WitnessTester(`DataHasher`, { - file: "utils/hash", - template: "DataHasher", - params: [16], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); + let padded_hash = DataHasher(padded_http_start_line); + it("witness: padded HTTP start line", async () => { + await circuit.expectPass({ in: padded_http_start_line }, { out: padded_hash }); + }); - let all_zero_hash = BigInt("14744269619966411208579211824598458697587494354926760081771325075741142829156"); - it("witness: in = [0,...x16]", async () => { - const input = Array(16).fill(0); - await circuit.expectPass( - { in: input }, - { out: all_zero_hash } - ); - }); - // Check that TS version of DataHasher also is correct - assert.deepEqual(DataHasher(Array(16).fill(0)), all_zero_hash); - - it("witness: in = [-1,...x16]", async () => { - const input = Array(16).fill(-1); - await circuit.expectPass( - { in: input }, - { out: 0 } - ); - }); - // Check that TS version of DataHasher also is correct - assert.deepEqual(DataHasher(Array(16).fill(-1)), 0); - - it("witness: in = [1,0,...x15]", async () => { - let input = Array(16).fill(0); - input[0] = 1; - const hash = PoseidonModular([0, 1]); - await circuit.expectPass( - { in: input }, - { out: hash } - ); - }); + let hash = DataHasher(http_start_line); + it("witness: unpadded HTTP start line", async () => { + await circuit_small.expectPass({ in: http_start_line.concat(Array(32 - http_start_line.length).fill(-1)) }, { out: hash }); + }); +}); +describe("PolynomialDigest", () => { + let circuit: WitnessTester<["bytes", "polynomial_input"], ["digest"]>; - it("witness: in = [0,0,...x15,1]", async () => { - let input = Array(16).fill(0); - input[15] = 1; - const hash = PoseidonModular([0, "1329227995784915872903807060280344576"]); - await circuit.expectPass( - { in: input }, - { out: hash } - ); + before(async () => { + circuit = await circomkit.WitnessTester(`PolynomialDigest`, { + file: "utils/hash", + template: "PolynomialDigest", + params: [4], }); }); - const TEST_HTTP_BYTES = [ - 72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 99, 111, 110, 116, 101, 110, - 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, - 115, 111, 110, 59, 32, 99, 104, 97, 114, 115, 101, 116, 61, 117, 116, 102, 45, 56, 13, 10, 99, - 111, 110, 116, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, - 112, 13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, - 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 13, 10, 123, 13, 10, 32, 32, 32, 34, 100, 97, 116, - 97, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 34, 105, 116, 101, 109, 115, 34, 58, 32, - 91, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 97, 116, 97, 34, 58, 32, 34, 65, 114, 116, 105, 115, - 116, 34, 44, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 34, 112, 114, - 111, 102, 105, 108, 101, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 34, 110, 97, 109, 101, 34, 58, 32, 34, 84, 97, 121, 108, 111, 114, 32, 83, 119, - 105, 102, 116, 34, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 32, 32, 32, 93, 13, - 10, 32, 32, 32, 125, 13, 10, 125] - - const http_start_line = [72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10]; - const padded_http_start_line = http_start_line.concat(Array(320 - http_start_line.length).fill(-1)); - - describe("DataHasherHTTP", () => { - let circuit: WitnessTester<["in"], ["out"]>; - let circuit_small: WitnessTester<["in"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`DataHasher`, { - file: "utils/hash", - template: "DataHasher", - params: [320], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - - circuit_small = await circomkit.WitnessTester(`DataHasher`, { - file: "utils/hash", - template: "DataHasher", - params: [32], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); + it("witness: bytes = [0,0,0,0], polynomial_input = 1", async () => { + const bytes = [0, 0, 0, 0]; + const polynomial_input = 0; - it("witness: HTTP bytes", async () => { - let hash = DataHasher(TEST_HTTP_BYTES); - assert.deepEqual(String(hash), "2195365663909569734943279727560535141179588918483111718403427949138562480675"); - await circuit.expectPass({ in: TEST_HTTP_BYTES }, { out: "2195365663909569734943279727560535141179588918483111718403427949138562480675" }); - }); + await circuit.expectPass( + { bytes, polynomial_input }, + { digest: 0 } + ); + }); - let padded_hash = DataHasher(padded_http_start_line); - it("witness: padded HTTP start line", async () => { - await circuit.expectPass({ in: padded_http_start_line }, { out: padded_hash }); - }); + it("witness: bytes = [1,2,3,4], polynomial_input = 7", async () => { + const bytes = [1, 2, 3, 4]; + const polynomial_input = 7; - let hash = DataHasher(http_start_line); - it("witness: unpadded HTTP start line", async () => { - await circuit_small.expectPass({ in: http_start_line.concat(Array(32 - http_start_line.length).fill(-1)) }, { out: hash }); - }); + await circuit.expectPass( + { bytes, polynomial_input }, + { digest: 1 + 2 * 7 + 3 * 7 ** 2 + 4 * 7 ** 3 } + ); + }); + + it("witness: bytes = [4*random], polynomial_input = random", async () => { + const bytes = Array.from({ length: 4 }, () => Math.floor(Math.random() * 256)); + const polynomial_input = poseidon1([BigInt(Math.floor(Math.random() * 694206942069420))]); + const digest = PolynomialDigest(bytes, polynomial_input); + + await circuit.expectPass( + { bytes, polynomial_input }, + { digest } + ); }); + }); + diff --git a/circuits/test/utils/operators.test.ts b/circuits/test/utils/operators.test.ts index 67c0069..1635a10 100644 --- a/circuits/test/utils/operators.test.ts +++ b/circuits/test/utils/operators.test.ts @@ -8,7 +8,6 @@ describe("SwitchArray", () => { template: "SwitchArray", params: [3, 2], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: case = 0, branches = [0, 1, 2], vals = [[69,0], [420,1], [1337,2]]", async () => { @@ -63,7 +62,6 @@ describe("Switch", () => { template: "Switch", params: [3], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: case = 0, branches = [0, 1, 2], vals = [69, 420, 1337]", async () => { @@ -105,7 +103,6 @@ describe("InRange", () => { template: "InRange", params: [8], }); - console.log("#constraints:", await circuit.getConstraintCount()); }); it("witness: in = 1, range = [0,2]", async () => { diff --git a/circuits/test/utils/search.test.ts b/circuits/test/utils/search.test.ts deleted file mode 100644 index d05b948..0000000 --- a/circuits/test/utils/search.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { circomkit, toByte, WitnessTester } from "../common"; - -const data = toByte("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum"); -const key = toByte("Ipsum"); - -describe("SubstringMatchWithIndex", () => { - let circuit: WitnessTester<["data", "key", "start"], ["out"]>; - - before(async () => { - circuit = await circomkit.WitnessTester(`SubstringSearch`, { - file: "utils/search", - template: "SubstringMatchWithIndex", - params: [data.length, key.length], - }); - console.log("#constraints:", await circuit.getConstraintCount()); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data)", async () => { - await circuit.expectPass( - { - data: data, - key: key, - start: 6 - }, - { out: 1 }, - ); - }); - - it("data = witness.json:data, key = witness.json:key, r = hash(key+data), output false", async () => { - await circuit.expectPass( - { - data: data, - key: key, - start: 98 - }, - { out: 0 } - ); - }); -}); diff --git a/circuits/utils/array.circom b/circuits/utils/array.circom index 87baf4b..10166db 100644 --- a/circuits/utils/array.circom +++ b/circuits/utils/array.circom @@ -265,4 +265,5 @@ template fromWords32ToLittleEndian() { data[i*8 + j] <== Num2Bits[i].out[7-j]; } } -} \ No newline at end of file +} + diff --git a/circuits/utils/bits.circom b/circuits/utils/bits.circom index 08f2daf..f847aea 100644 --- a/circuits/utils/bits.circom +++ b/circuits/utils/bits.circom @@ -2,25 +2,6 @@ pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; -/* -This template passes if a given array contains only valid ASCII values (e.g., u8 vals). - -# Params: - - `n`: the length of the array - -# Inputs: - - `in[n]`: array to check -*/ -template ASCII(n) { - signal input in[n]; - - component Byte[n]; - for(var i = 0; i < n; i++) { - Byte[i] = Num2Bits(8); - Byte[i].in <== in[i]; - } -} - // initially from https://github.com/reclaimprotocol/zk-symmetric-crypto // modified for our needs diff --git a/circuits/utils/hash.circom b/circuits/utils/hash.circom index 54639b6..5da3c12 100644 --- a/circuits/utils/hash.circom +++ b/circuits/utils/hash.circom @@ -3,67 +3,20 @@ pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "./array.circom"; -/// Circuit to calculate Poseidon hash of an arbitrary number of inputs. -/// Splits input into chunks of 16 elements (or less for the last chunk) and hashes them separately -/// Then combines the chunk hashes using a binary tree structure. -/// -/// NOTE: from -/// -/// # Parameters -/// - `numElements`: Number of elements in the input array -/// -/// # Inputs -/// - `in`: Array of numElements to be hashed -/// -/// # Output -/// - `out`: Poseidon hash of the input array -template PoseidonModular(numElements) { - signal input in[numElements]; +template MaskedByteStreamDigest(DATA_BYTES) { + signal input in[DATA_BYTES]; signal output out; - var chunks = numElements \ 16; - var last_chunk_size = numElements % 16; - if (last_chunk_size != 0) { - chunks += 1; - } - - var _out; - - for (var i = 0; i < chunks; i++) { - var start = i * 16; - var end = start + 16; - var chunk_hash; - - if (end > numElements) { // last chunk - end = numElements; - var last_chunk[last_chunk_size]; - for (var i=start ; i_+gf^v%>rAWv|MUW8b21!9cx86&uJ@J(fg;e+el{NKSEEHALvO+o}z*8F;AWLGCYNjTmpZH;m@g4 zXW~zvIs^ZnMt&BL_K)BG@i6|(KfXubLN07hUU+co6#uCQLIU#krx%7D`Zc;L*jGYS zP?s5n{3%}GbUS-~6jv9NTue%rznIj`ZG2IwAgLg|mb>?n!i#vu+K0xs2g2`rGg7>Y z3r7WW@Qo(z53RQejtGscyY{Y^b2#NxY!UMs$F2Ve+8oXpj%JX1jfr!e|M{uYXy_;T zhTz86N{@P-+b4R_-!FEjy{`Sq^W>k2jwv7g{JD>Bl+|R5+fO>Q$j3agL_@npViP@QDjY24p< zHQFuiGruuF{B`Fs!&8f?S+1XK{r&tX{^}R{CtkVm%2f8#r|}5blFkYJ#;Y;ISN`~| z9Yb|pJ7GMz`}uFILAc%66K>F-0~9}wj{Z=7=q)kMZ@d~dDbsIkv;S<;Us@gi*`)tw z!~bWK{>tY2&nEphN#{SA^jC7+e=_O6$;$u9q`v}0|9^qIGyS(P_1dMZlAT9xy)ydq z@A1I>BhA-rr=X9V))TjWC6K~3?yBemLe;ekt2rr+7$!>1D^LFkgymoGHv}36T9RG}JG-4bEgM)XEa zEoU?AS7rsdX6g-p6jr#wXpx)h&THItA0?)L#?AGI-2Ro{;O}OTExHK zJM2eT$@ z=~AiTrjvb0erK#gurR|7Ch=1D|8g_GHb?x=`6c0|StNh_>h*tpv@CU?p?Bi=hks{j z8C?K6X^8Ur>l^;!{ToaI=T_ZCpX2?FW%)=hUbmH&<7IW1G+&HJ0C9-p_EL=PfME*C zDVuk?CF0FMp)s414YT$7fdS>-%2&ZlNqM>r$xlO7ZkZMh+m@*1>$gkwX*!uk^13(@ zbK6_Y_2p;@4r^#<2a#~x3%JIXE#jtAS!%Z&>$ou!eD04cciZc`W!JZAFvt@J&C2M4 zberjl9^T0+kPToYxZ0uD(pO;E)yX-Z`G$4K;`4YX_p!hJWTbKS117x|v5T8lv3AL- zXWDtT)j1anx;piuOhd6bXX1^NuJM{SF4s&1@x^M|kG<^9P|7K2rY~b2+Ht#c`v`jR$# z)y%Wc+|m))+ntV!8?m1VI8c$!x3Zay(2spU6>V{!bAKU!ef+2-J<~nP>k@hFtBcn{ zS-(AbBU@eDohE0sZ)qII>oTQcA#g^+xOeiMpjYxr27~ZQt)iM~NFe*TcfrYqsA9th179v} zZZZ)?N*}*y><}f7(R5y|vp!gDV9V$UJs=yhYUi2llwgp|$oe?YM|PL7%C%wceon?= z9g!9{U0&_w*&Me+W9)-(aNT_R{Sz%L{%e;FMqkzM6=H7|PXsm#{PE_NWTgI~x3)j2 zZ9fGMjD~}kmqYKPmr6tMu-!%Gqn%o`Q_J7-^~r3?zwz28^xF=ac2#VT45BViWeHzV z%Y2PRUwj=yVgcTcLpi;UCi}VXRKv2e%frn=a(BKMF1t1^&+`4HvQ32v;*)Fv{%g3o zpKF~XXBaAXbYhF}&9&lqoVK{lQ!3AuTF<^VE1gYNf6}9%l$A4s=49%5kyWf{=$S;o zk;_UA#w@JKMy?kv;f$1|RxOOP?igfZtG4?k53oL!w@M!0nH||4b>oY%YU4`b&cP%C=_m`s7N)ERMySSFinaEYU(NA(S)gH9kUOpw^F;xeX z471r~OXA45Mlu`965rM4AF%j*u?ts}B$!a;NwE65aZW|(t3R&3Ms}++uTghu!E~%s z@?@wQ{oz(om8tx^ZoPlwBKO|Rd+Md-o(v_k`DwmmhXLy@Nh{K-{o&B~Rf zNK5fJZivC-+53{>P2CE(!icK7zZRzHNL_b-C4hC{_F`e5W}zYnY!&P3(-=R5r!mN# zEr^*79;K<5R~&m_(Ti;l+i5w%Uvi_BF8NC6q_uI~772?vBi|$2 zn>=b z$w=%s{SohpEe^X=HHN2bwfa>|=V?^W77u3BnM>Svg-IEg z*@i3x9bp4l9ZztPR*|l{Xt-?l7#nj=*X3{Qj~??L&TAcuPt*rU7-!~**m5r9eqLL? zZ_36xWk<7=(SEzKVU?>dd^E4VfQWaDpj~vK-g2pAI{77$W^wmnv1_-CXi^a05jzY7 zH7VT6tUptmLGB^uGavnh$uKRcFfCUH&dIlO&thOcAMoveYk%f6MxuH7Br7Td5byx^dft3?Su(X; z@>^fgT!Di+o%uIXoYV~5u5j;b_tz7?BH8nj+s1ox0+rUi@}s@^_3R6iY)A^k;Gr#@ zNtpb$%TD-G6h|OWg(KcH2lt6HOAZgS%0~(JGcV4PP1F0P?ec$d?-GGbJ+nR1w*YIOvBY>-w*57gZh7)h&_WqRa3cPO()zFt6BDq~>nboZZE} zi@RO7U8oDxV$igxwXgZuXPSv{pke7O+*aiHGNi;-UH=#bqkXc6QLJ=zc2u(HlESBC zgGZc}E1b=pi9Y3MRk_wBbx!ZBPFQJ+ESSh9+J}xa#AZa9m8Rk6;`T+YaS=?;Gx=7E zYKsRO?UNddJ3TIM@@nty8s|j7VuzGq8B2Gc4`wg>*bBU8!OBA<=ErW3qphOyzH<=LvE3rT zYNb?0E%|Zky4%sdA_sI8dH3;s&96h@r3nwG+hV$2OVEFtsp=nom(*1{pRJaDk5He8 zx}LD+a^5L!k5jNXW6O(=zfcCzo>fq{=~1{@_G&6CZIj^eHZQruk6;A9^z0Iqo$d~a z9I!1=pcM}qJ`?LWm$uRFcEl88)2rf;t<&MMkoic>_xh`T%Nw@1-qoIh*c>;6`K7qI zAX=F09jv!Y6xFp|&chQ#AFGw33)8Sw!6x>;?u)v6%j1bz$z*6J&m;yeZQj9J^K|^n z@CHm*pN;LRV;;Bcq7lc!rCuDYZ9i=vOndJbS)H(8ls%OPi|cN)))Xi49+k&U9kv%U z>+?BPu}25fd?}a(-i*SzqPzBfrQ>$jJ#LP(QB5s=!eXFxsnVVH+R?ZzEx8**Q^gRN zaqVy;h0k=wE;DVhj_Csg(COrylBr1i)11NMMPuWB3~dc+W+hLt^$eSq4GxlpeB+~Z zME%)=Vra*6)QZe3Y5vKee}xGYoIcImprIC+RRyx8h$@)Ke&G%i|%d4And92@#8CQy0Yag zd}tUb;pd{XJAwFEKOhCo6+miAQ8pRvFZiYxm82i*kepXH{h$QFdCQtOSbJK428Qb2 z2k}OZnvheu?R+NhBvdnzG2$Ye68$dnm{@=?%H+d?*sjv4ERM|(;)8Yp+FEldBdNi< z>|3k;qPfE5-}qz~p4~&z>$ne9vP!<*WXuhnrDi$w>VwT3H_1Dhx%b;fAo;JalW=j? zR^$l^+Y9^hzfF@%nfjiH>8ot}?Wxs~tOQ+1cJa6`{%92{SAT!8sNL^}mHY8Q7XbP4 zD8T}iSeSW+>MB-M z!elh6bXyG>VuLUjd{22{;`@*a>hS8e=@z{OWNBLhHQ3t#*loltJ5x=E9OISw;ZxhH8Qd-ua>;uy>QZJ| zn|-b@X{ta2UBDS~qeIF|=ap18R>4ygnNB&ot)}*L{m7Lw0bBIRklv>_5%A$t}0SpZC zU0^P%k}JF#LX$HYU$R(tP}hbZjGDPo$+ld%Z-#B*P0EC_c%Md%W=ja5(pham9d)uz ztnqUbFX_sdCt}_P;zemxu@C8{byxVCDi+J1SFwuyVz7Eujk8oGh`3m~9WCjZ8Un5< zT|mFWZlN78p!0YSXsg_S%sUbH5B@r<+jAK?u{x*SHt{F?Ue2s4?$#$_Dn~&4*7cpb zhl~HU(6~<|%=}?Zzh(T)GA!vhb03W}sN1L`Sn1_9d{cMP&T2Z&CUrWCjM=*qi_^)B z0!Ru6Fi^%Be1Ln%?T0Y z(_r7x*r_9_9zFSPjlt=m0wS)dA-ho*hlYUhA|_Y0<}-Rm#`%@yn6=)^n!Dw_N+T>M zQFq*%@KZ}1EABOX(|J$hrn~zkm~uYL?qFwiQ!{5-r#!}OswJXCjJ7j&G|k!WdFja7 z2t-;Dn+*GAxAs^bV>)v4A3?^GSi{D2J8>=cQHRp5Yj5^^&E@7hDNbKY$=<**el_BW0LmX_u_-fjO0 z%`<$Ls}+zOxznsPs zK0IFMJC-A1ooAY&M!VHCU8q7(;&T$=C|&_Uz~dWrY9o|&*IK-QhXu{=r3iXq+h`cw zb?Xo&q6?uODb;KWzl1Sq{tcK#yRqr2A46p-OO>M@EwhBk!D!j}GM)Zs2ekXI35UrAdU*I~2X_47f;A zVC`~|S!wc_)!@=#k$EW)V5{qb3#TlP54Tegq+7Ryk!SC+T(K?1HtKA(mvg+AL$ery zaZbME(PHAxk+3bgUM8T39&vddQlOYU{tWFX{uD=FQWjrk(}9BV+zl1m$1rWyZRPM$-oTjf_*iL`7}sG=$?x0}!WitH;Jec)rn+xdEfs zH6L!)SI!)50FbG~I^C7kT~MgbVcv(^JXzf_q5v z)_H8RtG3xZ4}w%PWYIi`E=h7y97zYA>f{YN$JrWX$(X+0MLU;>nNvk#Ce1@~Ec0mJ z19qNWZ6KEhiu@pty>t&X^Tk{or?#kaGi#$;PCBIU(eap$ADyC``z_5F2sjt^#TXl| znHI?KR*t>8CJyK@;}Zmlh;=_V)SvNUV_zQ`&F&E!*(#lp%0tS52MZBRgQ_#B~!~>ww1+cd%J( zm0pchI8C2=+21n;@FHDC9~XZe^p2?*t#r3#%G4QAzC9VU_3AU19wJOJfU}8dyiAUp zZE`oK>d28-14vkNev~tJm1~M`V5_7P$OC4+!w*rWd3A);Xr{5Qd$ZP%DN;UP;wv{u zco0`dQeQ59vUyU9cNrvgTo>WB_+IU-OWSnR6?Y{6{x!m=5p9zrTnGNXqY)%L670(s z7e?Q0iDMoX6muS>;dZ#`5Nzwvp={v>7UKHR_ag^PFgJ zFi11DDfbVBR<<>?;9>ert3gIuu)s4J2>QJVb=9Rm8 zBf*qyQ>@wvJ4>vacIhH1=})^ixq64T5cL?SSEt+Ywp$A5JFG6#T%(QC2*Y%oiqK!P zT$R>XB9LcT?< zqP{ODglPyD8_X`e7Y(APo1x3@+j0OwV|rnAq9KJci2Fl<7+;&)s-IROsMu5Uqx&P< zYx*4`(Y0txw~4TlqoRC|s(`6b@7;6R+fY}a6$vbwX%A<7FQZ_d-^x0BZFEP3-U%pL ziUfVhjh71SB+e@}3TWqv6~?&fH$c;VQgzqA3emMSK-c=_+$G5-S%*5X>C<3arg>zo z|Ltj5tCywQuGwXnnzWSINQ59I7=*k$`rEX!+#|whHRQ5Y_rbT?2mV0evNPtj%UyYi zaXRmeaAJ)o#&rACk=2l8!=xJJDgCO$tvfDZH_U2B4>MXkj=DmcPhY4?{KrP z{i&{<=NvWRYJ;<=?{j~*g9-9ob~G)W2LJF;FlGhgk?!x2dOdz0ma>3u7`V*6ZU1Uw6sBIKOwr~tfMIgz+OVB zQOEf#hddYBPg*e8ovx&W$71nc5;?UG~t~pDTxU=7r;~L_+*A>^R z=;G$HL$H|Iilk9H=U zRVxSYTe`TqRRZHQguInq^bL_9>##BEV1XTcCO^81@wN8alI~;MmL3R{(bIRz3ALP8 zH-Nc3$w&3yT*@#WiB!|-<|sg?IcV+@7=ln)nivO z-G;EygDE!ZO7qpsSJEx!1xnmyjC~z?x?NAhG(xMC@+j-zgWkmX?HtuF;lUm-G+`+W zHC|el&k6~7+6((UdJCm}!?wp8zY3$y3q2h-GrYZA6G4ZP=y)lU3Z-4 zcYm{PAn!Tvh^!WE?;!}UU9~=V8Qp4w572oIKt+~B2;d0ac#o1+Yt7}=b6d*t>a;fk zoe(uecDdudXj(dEc6gNaLSDlZTYdxDhB66RnPlx1ov|I@FugPB``gQLb{gIqcXWz; z+G4m;V2g1q<~5Mb0`6nz!SjnID!`x6(DAvs)`sF*ERfUu!Rx%UB43f?dG2D908QPe zWh9q4)s+i9m!w@9H7i?OTUi33rt|K6WKl_4PHMSxhg)!8ID~Ri0e%=l7vJG?pG?}K zIj9NCMOOsS&mQbF@U>ZywwrBsce~bak3&{y^ILd-)c@`sW@x`je(SUE^{|kYjFK5Q zMXQB2xNM&~z~hK-6JpF~=1XCx?!Y+2c)rwe1(8KLoV;StKGDg1EkWH`X&blE7x?#{XE4{$G^Z)IZ#9wdjpv<*o{* zIpODzIprZGEMJwzcH&Dtb!k&g} zvr(^6wCo(|ap+SwgPVzKgQN`ve%cUZ1(TQ2)D9ji zDL;Oxy3eiG65g482G<*h>s-N<{El?^U5aIA9IKvij@wHayyn8La`VRLKTmz+0Vq_? z)tLC;%^E%4>TtLcb!=Au`I|#~TZ>ViOp$|%3s;y-`g02=0=beAF|f@jSu!eg(EqzH zrnNVJ+ACRQD1crk@*BR1%Dv&rrc)H$FN3n3@O~cP5UfK6qG!(|a^gKws}5WJ~Us84u)I`ck7(SJ9Euqo_u=2-2QIpD$_@%0*e~-N7l{o^D=4yRYjknYQjRq@mX`XeKqXlD?E82PSYioh$Tkg1HitqInRffRG1w-QRN#*yh-%9%U+^2pdLwy1r30Zc-yET_w|7_!! zj;3L&TcT*b`ata10p7eGHL+PBG4rY@Jk&dZ{l$AAlaHjdmIX% zri!FydyeQjN^kfMXQk6X@|z8-I(Qla;gc6B+N#`Q8JcF~uq+H_Nxeiq#OT)CJ(Dcr+SRSY3{>M5{lKjH;O}=F2#fjLT z4otZGLboeRZUEZ|dut?1M&tVhsIk3SPFsEj^y6k0(6rr)E1>U7lDi#Psv;7dCaum0 zRD(gYiJ8mz#Dcaito`mKp*W1T4iw-$JHNgY?3zu98$m7F&U~dXE$9#_$-Wt;{y}(7 zzEKJ74VAPMR1K=AaaUy3jM7f!4$Os$p2Sp=t9_v$YW=C|-Ll?i6_JO%8HQ`82PZEK zZZF0WRz4AGR>)4)I}g=Z!RJExKZcmA(32lVytbp987f&nFp}l6qR_6KLTk@LSItLU zNS#|}s)z;t=8RHXH`s{z)$vnRuExfr`y;)y{(Qe=f~AzWiwoLtsm=Z#ao@8yXIqrs zG!C68>e;(*5%AqVbD~iBcaOpV(o@39HhJ#hNyhPScSoZI6m_ya5BKuFH$42e@Zrvi z^aHd?mYhDhpUAz52)6yMmC1`=-1dLDyZBaUxG=DiGpqiM*RCNe{)prn#s89h{_;8h zeJ~BIz+E#i^!D1_lfO3A8Qer6d<`OE|NUM6j}QF&ul_T=zdXKuWx7B}k?|+N^|7!$<;B0MTMQQfwIgr`94XDtTlgC10#CChBLr$6}1Uy5sG>rBu-xW#kGJ;FQ8lmk7f->A$8B4O{_|=W@mq!V? z^|i9|+!O9XEPwE8xa<#(N+FsRQrb3Vxbe$Q<$sNpy!Ug`TXPX#5R`@p{qj11lxRqc zK6(NtxLpAkG_OaK13@is`;qJAYnmR|Q$@Chf zZ|B09^rZ%1tU5DQ@}G?$+7L)7VcCElktLAa_=YM4OaxSiD_(pLxt5A`XDiu@!Pe5% z$~LOrRJQU7s|)2vE6Z7Re6-&Ml@kR{zUA`uPQ`rBneuM?d;I$zf9#XrVIl~$mw$tSzwW&;#sLalXO`w`5`qa-`W>S z!_LG9yX8tbn$#Wyyt_Z%bZ%lk@~#5Q*xg~v22xP*b5bd_$HB)!7vlHa3$e+yf;{+k z8!^W2I6(!x6F{(LQxL!Z+R@ulyqERRX~| zD9)QZi~ZtV|7B^%D_kfr52?_s<|HlS70MMt%A`SLJn0)tP$Lwh6!A}et>pR)s=|}n zKK)M<0JKkrtt}DanlLiR72G*dS@fs>!Cf4Bi97Bym3B#SCBbCS2axe_l0N%FpDL}gmF z*hImouewPgiZq7`mkw?ZFPwZoU>2ac2WG_wVL20pDeL%H_p0b8feb!bNoHA#JBt`Y z&T>KlCa;Z=wsL3OaOUef!?Bk{ZBG$my-|xNoe0~2E3OKbj_y9^dS)qxU< z^kcB0%$ZC^jUMPh5&t%5cW+am&Xs>q&^7^f#cqezvnSu;UqhjDwxHT%d#2;P2%Sc$ zHB=hZL`=80mWIp3JI>?XlILKM(rb-WAem~v%A_aHVR!%J<35lM)Ppd57c{ZH)Fh2E zTb4DW<{c2=jGut1?x|Tp<3G*<&{tRsRe#nZQJjwItoE#KAOH}X-?~zN1Oqqv{0RXgR)5YLe6DtQVQf=;^`Kcu)C|= zjyp@v{Khm#!Zg#K%C~`9Z4w5V{q>)ocCZJEA(3oz4y>Ni;L7SbbL9wvZ(@Id4rJh2 zFs(WT#L$R`I6Hi;aN6#ieQ_QSvHJv%ufOvm6Gy~wNAQ$%5h$t4(By*{gcW|Re)*FE(SVW$DZO=qc(%l#?gy24nsJ?tX+*72 zGq11-IpB5KOVm0TCz^$cqwA45)JDn@dB#Exs!xK2e`e17rUtyLlZOmd4ZpGG3@)NA zPB}-Y3W`oA2mMU|)h<&P-mg6D`V{7GkXs7Me-flrHs$QJvwC3h{5W8g(P;{$V+l^k zVO@}eJFl6S2kZ2CD=4bmRJf#ldw3uyPNF3z>^XK3F|xe@?h@c&$0(}scGh;m9rqFt34`9(fW-9s0hru@Izw3rwexy zS$dV<2WGUk2VUes95b?Kq3C3Le?Sli&CA>LIXRggbq{)$x%V=_Xl=H?!~NB0 z{#O>(gPiqn#!~#(g3Et-vI1Ag|8AIABbZ2hMOu~Gxwig4JxUcYdp`@(k{}gdB;#g> zu{Mw07W|EKKePq#z`Tdm{)MTX`;8|Npu4V5EPa_~Kt7NlG7Hre8jWa98zWA{(t89+ zSYj9Z7boB^!XdvJ;t|AZ+d?+9ZU190{4(xZ>`VXHoF^Hnl}$|0%>=d~wgMO=%>2-( zU^Cl!a~L`)b}IpN7dCFQZNEaC{}q7J(!g6{2yG;WW-LpTf4QN*&e#93Lg-Mi4ur1| zMTek_MyzzITHSz#2;EDHmD$ zzgMx*DM5{fVjVDeUjVMq9@QRzCtas8Nd8Qgj*G>HP{nNUHD0y^Y2wkas5v_etuYcv z5}E^}($7{FU;|-4-IU;$_~8VNBIcn>mM0%Ebk+BOrOxTmq1~_rD+x0cm}DCfSLV zC}kZ;D-V#q3plxElsQz3?1SOXcfr%xq;WLb>(l zsiOa!SJ#iR=|q}akk-Ayh5kIvTHI~n7)Z*>rBGGt{9fbP z1*qj&u8@mOvB*g_!r$gb_03Oio&~LEQ}Hi=#U>7#SMkundMH6`>4yj+D*$BjgWnU} zsMJWHH-r{2x*o!YpLDaF1LLOyI}o>H321CIp{l_<^;Y16F-YSiLM%iSu5pP0MBphg zLAU=|ziog<1WCj}GvKm4+yyR_&eYO`ugJiVT$gqI9L}h_HamKJv@P$V6!1oxmm@2$ zo_Mm3^f&Z%2O2~m7$MTMr_dS(4-CWBH)*gloVRAXQkonz zsF2+i2F4f_<6x;6&ZOckFzEF;Rya-}2CP87qaB)Wc()#cd-Iw}u0VjX!Uax>lLw1+ zf%rpbgZB!oc{2%qp?ilQHG~FE_to5Mrj;|AgYjV?4I>8uj%YH)hK!-)$Lrkz#HDE* zf%(TSXT7qq{*&LR_YgwxmBG+ipvn7sA8RrLTDvj|yAihtR0YGV=h9Mo9bL@sAyx^b zH!b7#sA)oZ8@Mtv5FU%za*Pq5V!mE$x(xjq!pJDK&i$7p{!2l~APbRf!b_0l2!0M8 zEhJmXEqrpaZU5setk+y%$lx40HdL3@gn5l5VzCBi*(+ zf#iI=q|jnB3sCfS%<(u;l^C)@rvGL*%cB&I9s+|M^->f-h05M&q!lgBc@O|*bOHm? z6F9wGb?o{R)`N|nSYZ)SSSnWo%zu19yz`|$UQ5U>NFhFLYiPwwDO)PdklE~3nn6@C z*wjwG(kJo*|7~kJ5C2rf+##%S6V%`!9#~bYR+cWL$r`coY(Rzl=4c7H+mgU9%}LGx zK{E}g!|o2!M2T2l${uxh2~~t8EP{Q2JFEnp3(xlR)M`bpnZ8BRb(38|YEc3ML#)$M z34;GQzKkO+W&=;&NOmIK&Sn*xy-4SF=b~g98Yt*;du z1p4svppm^p;LVgwa#P?h%*nhTq9IZIGFJkMwrIwQn=X!)m6fF<((K$DIi;Sog_QUcC z(}c03#KCsWZdB88Yo8uTk_pu*!xEkb^8M_$$izxdqE2=>J z=SK}7`;*zYH}h6eCv2cwqjIAcQ=*@VBbx_I%^NA@`Lz%@qC>&A6H__XvK3zfFOIx3&HEd#)pjSCDX!i!IX%-4{j6QX zcB2~l(xo=@p-8KH0VsjVfU7Foo?#8V{2!QTj*Nyg1es2NzFm;W-yj`6BEw7!Scl8U zN9K-T%liqc5gB#Erlk+zDS+tSfQB1__&*DVo;9~NQ!rTAux+cPn_idZJG3TdF_K5D zaDaef#DzryNg@zUl#>A)DbM`nERILhRzt5{Xa{1o;*fS~#wsr>*7r`fSd@9C19qr) zr7P(=3p90G15wdWKRVnmDtYcR#VgShm&IO%G}$BmM(ACxpgD~P#Y#zNnty0o^mc8W zs~9|YNtA)?s4Q^(CLORFH1aB@*^|X0-OU(i74X{K{Ex|~KfgoSOA2uxbHeU6zSEgn zUSH6Y>PxJ0d+MI6TO05G0?AD0S5q681~c$(TO-b{oe_m+)k1O=#A}($j;2+sbi0Q> zqw|<6KHooLM$f>6g)A{!SBO9UpS91O><&p~f4N5fY_%yFkwZ=5QL;=a-_pR>9 zGvB`X_VPWJV9l4WWl_xD52eJ3X|2&`XJiy8gd^;b6FvSiY4Bt~!rTr`jD23xXmCNZbesz@Aq%*W3<0B5`4^JM*r9Pr?dfXy_ zlEImr0Ew+}iwH8@wyHo46d5Qrn?W|rR8D~IQpG2i^R)f_?FW2igonOi@<+0o8hK+2 zytt-fjpjwnP)kRr_K_JBdA2hc*bl8%^VYhen!Dnz3ZM4S9qsIE zPCl;ax8j$OhLj35z^YuNKDjpMWmIMt>GKjv)Wt&MYo9LZo*pVPSo5?sKt)FxRA#p${ zPp9r)WexsEerq2kO^3SP{*R`EFO1s)x9^PkwbbH$_@q1@iz2p%O6o!gWio}4M}Fp4 z(Y`QwQ!V?kv)A5@LG#Rm35(ct)(?(6NfKcn+jG+uGW0gH_2!R~9FOoBG>1ey1lW=G zndHZKclcV*<6eeO(1Xv`(^_c$od^3l9N5xmzITH?_G2kUu{|f&pqZ={(t9f`PC>=| zBPbHIf&sGCm*7qd;BRB`x3?eDD5O78EiiZt)FM0?1FEAbH57Y*tqUf>)oUl0tDv#X^10{4>EWdG+9;H6jwsGgXH2sq2S(K zmp$vjBY5sV+CCH-_1r_8<6;rtPum2N@eCkM5wGT-KD8dmk$L~hvn@#F0hGPrZ0z8wUWE;)F4U* z>nt!VrT}7=HT^*sA#zeK+k*WejGbG}p5m9UYPoI+-FKJ>V52>*^CKFx^!f8uWi$v^ zdb?|rdOyAd>(zLi)!W}%wEbfQ4)&RXBMb6ers)Qh$D>nX9h(rgss|7CDiw2geVPph zfHl`}pdd|2n#R_f{S%2Z;OhnU8*At~z6LId8dF!-O*iLy^q}i38M-c}n(pK<1JLnx zfS#O-2`H-im2IYx-FlAIwpp9`-Uv_#RP~~ZtY>8fZ@h%|z7CNb3e)YSVb+9m`$tYS zjG;{*Q-h{!Aml%t8H7?!eebW~h zDR)?8{}AC;1$WYnPpkYDN9Oqqh0g$VSee%1#-1(kgmbUjTB13+qJim5L7A5o+948m zp+IUn>hq*}9f!*Cc>T+$8EU)RO*3KNpCz_ueY(A9dna5sFwZ|+i~e;-wfh;&W<&8_(0?f@M=A#BG;esZ6izbLIQ&6N~5+&Vi&(iKO75any_WmLW4Q%BW77Y$% zFdmv)fuvju$niR>o&7a3;Y8SD8}C&MjabROj9y&4vbY~Gb1}1bnT_O6sPJjX6P?-BH$PHQwiw5=v%Ls~Ii_-;xQ}z1RipPpklw%9a9Ts(goaJ-Kvw>eoCH)|EH!rKAn=1%WZe zCWWqh1;$5{(bT$sg!QCUM1EW4PE714doxL0e+`02^DN(4dQRmqSpj-jA`Jsbe`Y zZidIk=2pHi`sek_fo=AhE8``0&@g-L1s?Zu7@gXbuktIB8_mrMZ)cczd)B>Nfl;?# zk9R-)DGXrHH=A}d-AOO}UiaTzH?ZJ@DE_1rkNq%yvVyD=IY@ZQt0uxnVdDx>fnH>eUt$G$Gd}Of z__CSwYui7*NX(o&_+&)Zp~_>?YB{HLjwb34&v@DKnmP{zPwTXd`;xdiXrbeAxC z4HM#Nyx}vUX0fQII>c*--2V-3>=#pZBX4g`InHqJ<%ja}_EJA0T zC7wuiT|&pzkG6be8aYGBed*OD@+F%|XnxAw7c!@~=RPX?jWB_RD)hQzL#oXC1*U*~ zH!!sf=;89OsAK7S6X8VRPQ^;jL&lm83Gznz9{0%IZ`0dP=ebkjEIbXI;S7(~}r>GYoyo z2}0-RxupvJSa@~KELUo&MxnY55rKN^Mn88_KLk!x#m3TJsbIjs>Cm=4euxsopR{U#uI}Hk2C%ocNwL z;a>}>nVh&Q`Q&WN`8(=lgF^N^o^eL5<(oLD%#MT&b#YS4@p?}10i2;&k~;MC_= z7xQJ#V3V-pFn+?gk4vSfZNepL18bX%(c_x&TdTmXA1Qslgmgyx!pD`+xtiL8JM7_& zNfl%Ln$)x8+2n`G2;-;Cp)B6$9-%GH64p|9=acPM$3Ggzp7FkYFg11h5L=aI&=FRU z$>tD~&}I4rto9h-mfsi!p1hiD4#OyW9E59ygNyMljA@61YqMLfB9)DvE<_ETnEOpM zV`V$vvGbkMNH+7>+3vJAt>RO$rJQ)fYwG+rYLzKF|7chB&l5@XhsxBKySBRzA3J~g zqC#U|;t=+QX{3;R=oXXPfz4ZbjR7*0?6_5@OK-`&yfqDuBH_fk^_~bnR4wB~wM(q! zLEP~{!^YBZlt#qwhOKG}DSi(hcJsR#E}~4)K0etNhQL&bRk=wl>f4?cVIyN|(HO@bI@%We?4 z)-%7KrrNW(V=-v{F zws_;olv;w-Kp}ydU$tk6|I4T|X(oPRtnBfWBhS-DEzI;|QQ>P`$@|T4(gL#(?O1!W z|6zQ!pObpYv!{2$SNN1(m!vdq9fSUzoAS}11NCGnSUE|YfJwXh6qoH`u~#|+OTZ9#^Y5PvY-gYNBaGxj7Jy|9g{YpwzAQEUb&F2D$zx!W z{XNG%r}(cyuDAAj5PMKCN4F-d#H@o!`K&NEyBZCxvA(q%Fj2qwQ$l*TMX+(JdGihp@;vX)q=9aA5Z&%@(9 zo7d$CbDy?Z3l~en!H=d^WwC-KVJq8GG=nrs+0kP!S6POW3n#J?eLug1`=iL*s^jSp5pCY+3>U-?lL=j5;#GHh9m982DjrHZOZp1$ zVQtg4)R7$q<2$V%bvqkZ+Zn!Cw3ld;auWV79cSOb6uXN%&EtZ|V%`J?!DJpi z3nLYS5}zE{qQ~wA;qi@Q78!9%#dIZ0GJ%ULO68+T1dk~ovffp^Y3b-*44}_-cuz`G zu@>5+Io?PLy^j@}LcjJy^qIeY(r$doywDHa#vun#XQBwqaWp=w6t5rbW|ItRxgGY9 z)lV!$s%$rp@*VSL%x?qu7r7*GL!jVK;N|_rPW(4~EC?AcHNTSNPhKDgIB6D+36ay|d710K#3HgSqZouLH~o)r z&!5|mQ}TV~3pgI8j_cWalf;e_Rfs8t;@oIe6_7>$RX7Mim-epop~o#ZzJ9*dT0GAO z5w;{|WF7X!`V#lHnIo{quFk(8UgiG$+K_U9qmg&wb5F#=!D`>6{`c5LpC9|pAAnu< zdEKDE8Dqkm@6UTrRMB{AM)J4lKd|KQxfDPuqKk+vg_zxia*3;EuFse(G<~>SX@yUx zoEtCkF)#+4 zyf&5o5H2v&3}t@<@v>-n6eQH3Sjv$6e9cu zzu?LAwGQs_n64Vu!v>*c3qnJ(#Plq%hW6iPD-bOk;!0?dPnU1(&Qj|`&O*}L+nCMf zGW>XzrLvRxZQF|{%Z3T9doMZY=cE&C5>uQZ9$J{*Lc-y0Lyntz+0SffD*Stb47}<( z@#*t`uO5hMM%;T^p05&cO@AUj??Z{2Wpv0`9-L~V`VRfhff59pw{&W~LvUm$t85LN ztknAa^cmnw7%gBb%+&U9Hkt3unu01H=AF4}chc!D*(C9AAI3&3j8Y_P|Hu^5EVEr? zt~gZs1i)4?WZ7gn!G5P=xH>Q|%s5eV&3H=H^55eG*Wu=0T(1%TYC%nJh zAwQs?n&&f0ILup7=`I81-Zc}-ZxdimbkaGmXm1X_Au$C^jA&uMN8g)j%WjG{gBGFh z$JA@wlTNTI&t`sm1so>fb3GX;)Md{mo0tuk%7u`ug=`!21kJk*;l^WA0_g+yPi=xw z&>xB`YC(>BdbhQ8UVcQ-?J%M+u7yW3*_^uyq5ZC)$_Q?FTGa2{l*RE#2e;>oJFl%( zktw;zsrTdNy`QsUUTi?0w{~b_sP((MgdZJ+`vsR;aCVmR`I%HJG*U*L7Zi~~UlE*t zGX_pfvL)AdMByQ%22bwKU^a8jE(9`kay9TBA23~$gZx@nciyf$RmOJo_@iOhEj4l- z0D!7H`S-Vcc*o}Mhr0`Y98L8yAQH%sP4bmQ@eLWR1DV?B9A-H;@4el>dINQ;FG^fu z%T;*(Oah+begn`ib8qG6+CM;t3bIvIcevUyT1*`H{_BUQ%_h`B`~rFC5O7*nj4VAU z7$_P^qcdQ_=Y$!M!++#0vD@a&%K6q?m{=YCs%Bw_g+pIOL)???VGf^`BB5#Ki<4hg z+uwhyYT}(0GPMZ4fa8r$r(kM%D23Sp>x)^(hsC&8IT(MD>e;1388eSQ!t&4-PN}Kb zTU~4~=!H~jaNeVr)a-*(^&Yv)M)2;K7r9A^{F?aIRdcS(_7b*7I~kS}Vfs3tG#;wh z@+rDT;=TPpbnAcjtH(%&IVYa}dZ}VtQ;ndl4&*LoD6)QR@WzF+yY)a6QE(cH7dV4R zcx6Gkrzs;p10TtJ!_$zta|Ebj0280Y3fmU&HF8DqgLNi zt9(eL+XCm`e+CiyW}dN2bKN4j?gV3Qk792WoJ> zJ|5jTbfE{xcJZkMjv}(AFfF2`)I4wk7O1F>kAKlp@!mRJ2Ztn=5UN@+N7EFC;Vwo@ zi9@das!rGsQ@NhdGB5cSrkB$}OsEUjD+kK#awNrnkd@Al3oTK4q|5uosq;+?-?Ea{ z80PNtIrU=Z7TH9JujMebEv%yRk}w7Oh`i7M{lzxwCj~VX{ZxJv7(#6s&`O zDIA+Iu(7RkzNr4b*{4;c;|a_z5==IoZviGj;i*O~IGUg%M%yD~2IG$_+NvK-4Cfbs z899JYV{vZJEaVwY6}UGL_BvLGXNE!b|44i5uqxNB?OOqL(yf#*nUo6B;v@u=iJ&Nm zN=cW1gdl<-B_Z8Nmm;DFBB8W&NlJ-yNhsY7@3?iXwV!9L{qE!Y_WOs&fi;=T`@XMh zT<7?m=NRNG-|Zlw7pw_nks4Y*Dc1?QWpBR5i-C7y3$1dfi#yn{+(x$y)pytYs5mTe zBm~sBuX-xGaG{3~kvK7`EB{{iTkpsg8)n@PreSa;6>qNL#7@I)kHCkj$6IA_o)H&%0)<2kPwAF94`B_?Z6O6tFvk>nzBMS{SYi;k&36A7 z(D7mg4C@>`JWZeaxw==2+gf}M=a|fG;w3)aS}031qB|iKyA?H^kVcKDuye#=Midum z&fIRu)GF#oJ9n?E0m)@o6~;ZoQ=NVUYHKSb_pd-_kP*bb+%vb|=&|)5-Frp=Uh6BGc1J&io>=bFJG46dMN~j=c?b*T#c0P%ds2~fHedN zl8+?>Ja4#Qm?-Vz=z=IAKX0~h$C@~&&Ro5_zd18TA1oRcA{DZyzE!zgX*i!jed5T< zL!SS8U+X`w57wI$H@y5#ZS*bpGQCo-;Yl#94?bxQ`5)%NqLXxtIr>n3tA3Nl5hi#+ z$g3snN)z4ghO5Aw8mQ$?IVYGxAIzLv{ghT=w%K6uM{NOdxBcBA(abjozz}NG-%2Pg zu;?{NQ1`GefsO?d#+#kt;1s!A0$bmPI@fZk<4T_|9WMSk3wCM9aVoKLY<&}2A~|FO znad%zqGVmZJl27A7ad@GNUC5{zlg2F7K zHY#!(Dj&-Ln*)sKv69ETJu@9COY%x?)gLGNND6`qBzgkaB*u0cYs1vE?8JtA3Yx=_)=tm+b0z%;h*_33G2mrlFOYotUTHH)^dtVb-PCS zP7EBtHbJ6{Z=KDF!3kO(n^|RHt9heaUN(0kOuR9gZ=p@`hil3P_swxE0rklzr3CIgK0(Nr#!ST$EoI0-|nfe@hehlq0bPR_#XE?Buzty z$@0p>O+gXG5Jq4?Si^+-VSSmMKE(lTN+;=Ds6f`6_VyieB5{VZi+wAlaTT9E%8cI~ z|GWr=$`TKb=9vmlnA25_7+8$!h{mZt9X)TNU$N`ETH1`#ffLB!xipjghYLf4mpxdo z9vO>&4t>a|o+W+7kp;)XmGH&`=}paNDtg=g)l9y;|6Pq$p(O1=C`CGFLX78f5d7`p z?I)m_#Dm$znV${R8T3-st9) zlo?HthbbdsH9Tz0jPyUA-BPqs>9fq-4XqNRI1IJL3!DGE!u;RsUxEjRn_0`+7QXs8k9@ekCghiRcGJmse3K z!kIds`YeV@dxuJ(@u;2yeQ{oZ_zt8_2h7q!=M?>2nqL5@37(FO>I_EQzO?+UPmk?x zz1R74tz;8YsTna_?Ar#JsU2|8$2~*ey9s6BwHrJa4-6(=FEiYZ{%;?hiWf?t1C#AJ zIm_#?Dt^Rrv&lp5(6QXEbFFdbnvhC(<`%TIo1yD^{V5S`sqh?=GagEl7eEUn9Nc^E zT9#H(=88xdQ*KHQ)d6hK=K0W(nFIuZLb*XOx}xeSaSPIG4+iM#n)xOmaKiXUN#qMJ zU@l#Qtf$cxOk!yB?nNUHhgnEV|6rJ}SLwmpT@NktOngdf0vi3QurI3rRl$!Yac^E( zCh05;$DuXw-f0%(x6VSRUjT>SaJ6+TGfpQ{U0}vn_vK~M&X4A5ejMSS+UXsJ;0;>b zZA~x(dn3J&Nh=ehHlEx(Z1b@Y!C4I;5QoTP>7(|n+A0tN-@iKB+ZlX-)FE=rj_lfN zKfc!xc4cXcFGX}X)M?E^wZTdLFC3MOmC; z^#35@%frRPq$poj<;s4vpi|AQlq50f%NE@5U~q3{LFK)W?Zg((F?770DdfOMk`EGrq)H8=4cWxptdJ}a^#qYo9a8|sKL++Q6PXPc;h6l*?c~F#sUZ(p0(FTU+ z2yN1ufPDDaRleJ5r;sY=SXc!T;zXgT*7+CC(;HR+p@H=0?m5|)a;|Coy0g*dRM_mP z^M>mSO>v30-v1^g!a1#Ll;s#BxF2;)vApHF%1=4bY6aT}0vS*$d~b>Gp*eM<;`V!; z!DnYw&KMMBM!83P0g|mH*=^qphOFo*icUN$EXKl7W(BbASZYOVC74p!vup)(Z!8Rb zg77KxX2^9g4hDmVE&n|9;P;G?<_s*^CJg7TEEFY{Y645Y^Qb+_H9S4=lt-uZ8;^Ez z7t^Bwn>3{R90qQdIFM!?>aBd-rV%9wsSN<35E#QM8nbBk$9}wEJtBR({wZ`S1`xV* z5*#Q(US1oS<=|k*eCQj#j`qS`bub<{lsjr*%pluKsNCy&3~_>Oq-C ziT%5G`!J7$A4)tSIhMVR=pawioVsgoi;vH*pd)Q90XIWLtu!dX5oFk`_$0!gT>XPR za(5%l)GZ%!)up2N>sd2|IYSWhi#h)L%FxS=KqFj4+K*~2bQ|WN0;PeGG|Cvz4s!8IT(03~JmOM7;>;(J(>c`pD9URjC&jvu z_;~k@7e39ENdE*tmR_-UJGQra<=j5e7qz`LM7aYL%UD9%bDV4kj+_M=MGs#6`1&sX zY%Wwiop~loCAzsrpDnmzHlYPxYGMVSIOtG#FOW$&`d{B^o_JtRbb{9cs74dnhphCm z4=W@_djYu%(WF$qEW-Hfas-)(8=$?cQCx6XrG6lqvn)e2^Uvq#KmQ3Dl^c$ z@;|cxobw5&ZH5MbGmnQZDfjgs$*$X14996%`lfasI4#^|{Bt^jYZg%smVO%RmY&Nvq-7O zx$MI_b{43;&NrpaF-sn>CnYD94%qChhk{VR8pwS`4(ci)H?Y_FKW0Z9RIa1p7St`N_W) zkUzh0e@4|1*3m~+-3U36SRwma^Mmub{VPrkmPQ|nLLw7j?WD3o>prhd@I zcja4Zx~XdI^e(y9+UXxlzoAN}FmMZp4>7fd6K)t`Y!i{oLzgSv>yRmutxSOAI0`F% zProO#mdcTBJEh3D<;j%Lxu?u-oxd=!#bP%JDJgpJa7O2Q$VhN>+rEQ7a~hb|RZ+_b zjrZcjZyK*IgylX0NB_V?qXw^>a)c&S{=#bVf3Mp}p8}Elk|Voa&6x!(uOY&IV!OBJ z0J0Z`UBV|_?LFxJx4eju9=;=7+P&J+J&;m6A;DNE4Q#P#P#>j1pYE&Kv+fT)nHuAf z#Pg-lN(ZJ$1b0h>YNATV-e(^?*Agj5SebW zCH@4@@dwuuGx3ll+K4|^`qKWYJI$=n5l?)TQm7o5ij9HxX7*8_>UN*}mP1IyL(6hQQTUj}xh zY}I*Om;79H{dn|auiJ~__3E2yIVXy&ICk>MrK4nnsrBH@_Ow(%rg2;`{Y9t}j% z!w!_&b}7m4gqF3tBb*DG;qZJst1voB{(!DOo9W!WXO*l;OD%aw0_ZR3; zdPn%+mG3L)KCSU2U1(%}jP(QUwN3MNcAw zC&s&W;Yu^=VB^Lm0_ZAx|K#v&uGsHD8Nr}~_39)~cq))kU~{V8bof5*zTQXIa z`isNvIjgk3?za7dOS26&j)_+}o_V}~>A-M&=$||Q3!@J93RC5esiyn5%EL z$VOLOS%(U9(S+ke^4lF+i)W_CK%Nu?>+2`GOnb83{Rc?%b%1+bbVKlh1l391{d{#& zHzX#Nma-wvV&VoyXA-ALq$_&!G?%0}YtX zyv|R$Z>m08OJUZ+>i$2`c$73YfuYs(ZKRC?uIesQ;fNo6U37d|KV(IGWe$ES z^4J|e9csJfYb9VJYysbvHnn}g^kD(AHs(pmwh#mqH5tDFsb#4pFnJ=y_2px$(1`nKbr|cq*YJB*=T?#x&ASCf}?-Etg z*;0qgNZ|b>I6Lx^Nt>e1uH3V|L|Ak6M-EPk9Mf_xiA}2>mX1&Jg;S*CJ~N`$BTs1i z9FFV{UNnt?_D_=@R4|heMoV^@>VIzC|G9MecYjMJjwec1!rl6WxK6oSG->?XH3EE+ zdTWfthmhPRhnnmTN{Mw#W3T*ZrA3Ieku3`c_s)Wg+3-{#fhfNv2si z5R=%@a4x$CxPF1wi<)dz|LvjodgB95m{WTED59hC$^80wjJL{NU2Z|`U$QVnH5%5u z`Cu;FxLHsK2Amkcusw68TLdfsb$sx61}Ej3p%Zm6nxe@&R84epTH+o@=6@jF&OFI> z2KnmCAg}M-94zO|o0DG1kV#8FiovZj4 z3EI*8DNc(Lh)UKI3EM@*JhlD=0KH2cp5nf_kVasHurERg12%EAojUkO=4^;{rAA6m zjiYZC2)@(IxCeUI1SNe%+$pa=ok|kwyZpv8#@&R7>>$C@*VhC?d8Z2QLEANS3>Lsc z%Vgh#YC4-XT{X_3vzI7Hj_m_^^YlUsVN+GhUN#p_K6My%lR|+)*{6*#X-4V7+B2@_ ztR78`k=*a5Tcs|?bOy%55-EOZE+-;lO9G|Fy^+v{s-YUNO(KO~b`rLbcpxs$S)HhG zCrQH5;x^H`Ujy|AL`468TJTO);Sx3&NAV!=Scbq|hKD zYxTyjP?}(mSuwq^sj;_*c@449{MY>7oSz3j{$+JIg1oym2L^tVBge6GNswzNLe8aW zQmJyFUEF{7>)wO8tpaNnNE!OHfqhFISxK+>1*ck(kX<#AbKOf$aJ*^wxIqw9L%loK z#T37zP7SDYh7)8I7!E{3nGp+vL1LjM&^R_FPbo>^kIlg|WYqT+O6aC!E6llE1ocw! z?8Ey|&E0#-j5XU~qw~s$nLdtGy1z-k*276fs`(Zgo+z~G=U+|NFg^bhd{*(3qECFQ z?prZ`Sum|z@iHaK(t>KH1?(yJ5_^j3B}(*?o6oh+6Z4ho#ZM(+!mY>Mr*48nU^a$T zum(PfPgWg|lAhAFogq-AoBGlNUX>WWvdt<`>Wy}$T1}d4iy$^>KQ(ndv4K7AMlB&H zEb|e!8RyxPSbe+bqES~Jcnt#;k}^(cKMYIsao*>TDk^CG_K5PS)}0j1^K#U1=k**- zVIa6ghewWcq1)I6wf{phxvzhU21wMFA|9NQw+5$D#JND4uaBDIQ%>BiqpRNJA-+5@ z-JKDgemgz9eDmU>b43&J|@nl`|$vR+{P1N;HPT=Pew;o55YBX9|L5u@%gk zI6hN)ogp|4YnywuKqx_(^2V2a?MH(X;h)YbE~13hYZ*o;3=Fb9G~p2x9->FRf6uCVU_9Pwxf)XX3DGOCp(wa$V6 z0}}+W@=)ecr7pa3y(-wKM~guYHd73Vmdk}35KY$8N*Mo8^&VF)ifn(;4qk^0gGZuF zI^OB0rB&8H_9h5*)V&spiUoL+772T>Ra%`l)~q`=E~ARK0icXpvW`2{DaNq z5hab*W5E^DdTX8`(YZdN0@;yDtvZ92!;_iR3WdeHVYI&cPdIF^C&;BTG8Irhsu;MB z{U8)Vd3)<*aUz|^k`fJd`I1%%;7%lM3gsOAQf?=q^n7{1|HCEeqq=qJCO7*wLDW#r zocc!uA56OW2;_Q;?-X@KQg4YI)3c4F$g4gE@gE!4sQ$PaWaHVu8>LqjWJkd5D^G#H zbrv8(o+-I|IB&|z@0Tsdju%)fzu4XCJMoJ`lULA#Vr~)&`5b!Z zjWuGo&L~y?Kc$yHH92-A>2j%Xlh;E3iN!%H;~gwGCQrwnxi3qB6RTilc6x zstpxO^dBX-DO+;_pr>zVX*lRTrO7DK+pbOQ*O9jne$dhf*f9OCyKKS z`inCS^L#W9r#ageY8IHDU3t`+jBR3uX}atjM!5U(YkU4(hf}VNl=_< zC~{6j88tp7-oI$l-95YD-Te=Un~&LhM(%^k+MXSv^ATO9IEmOcL_7|+GZ!8})koyF zTTyuZ6>Eo{q<(u!=oh}JFN&*y*4~TwCNAYgqR$!-aEWev85b#W9^rdi8`_ zyPtU*NzHf-6a{-~wk8@Q^Z2|@`{oqZch%+vF8N6ltPC4+-5edTPQg#|yQq-wmc?Ah z*4A}9hMG_|fO#}aykmtw$rT-FLwOSuq;w*kHEEmbY{cx;#X|c8Td8D9*PLYTrZv`V zo0YGxb_$@FTqUa}(fyQ2OQLj`2}T5`6HxcglfA9}OHW0<2z5bCZ^*3| zsr^j<``z;|myYy07lO!bEP}43$fk;#+Wqmi|C3We|2f%!<7?}C;@IZ#ia>1DJBEn(ao7L^i#zET$mbUC%4O&#wu6gD-Qo9_<{x%zJ~Iu8f%###c7M!HHOF?^ekGrL zwXq3@!?m|4pqOJ(oC&nNTHofpEkeKy9%@Jy{tGh|4%(&~@ULeta-3))>s=!bxg>~p z4A@Z>^xc1PjB?9#+|7pNBYvw8MVITh8K`e%o26?MW^rI4<5n)qIF)s+RI`5ILO@mG z)Ut1JMCOtNClS%{wiVu9drV?9a^bfJv}_F`^ynpzeO?Kf)1#NdukX?2L>2*qlPTg` zL2bGO)V@0&j{6TZ^bY{UCI4}B?06ZY9zY$dDYttGKK+*)#S;`AA?FwqfiGJMA-hNS zrtGncCI)Izv>y{!UJn;VsbseP;QQ9n?OKHzJ#E}a3 z7vHF0ecYV6Mm#F~Q`#@Y5xeT+YIEQ35~3a4f)=VRSiEAvid{0_ceaf_MG5yl^(SttNOV>Jzo=# zolN4Wi*!^o410!yQpdEk5o5rgav1vfVS?9+SSCdY#u?{{zc*W?O9@tY*mQ25;rdUM z#}DL5+@|+__u^WtppF=~#rQQQVO7OP8NTDU{pX-DPsCx}1(scp)0+92MWB3Grh0_2 z$;Cm0gSyWcFbW!#1Y6%g?`k=6LW@GR%RTQ5*{fGqBXfxD{Jqo*9P&kd;VY7!PswjggXBG{rs@w zg(m8$(^Tz0i6)J4Zl0FxP7;u~q{LI%I0fwvl5`@0&^$c?yy&FnD3!5fr+HDQGlrkQ z&PkbJv*L{hG2Bnnp)8Ke zoA|O7w)uL29puvivs#8~i+?4e&pVM;PRSOUToc?|*?e0KKuhG;aG^Fp z?S!zKOUzIhq8rg3(pbYxY8BLyO0uL&73~$Vv%PJe)}%?0pEU__ZMl?8bi@}&nZr&} zkY5%$P$!=%W#E>&GuTM|2MI3au1>kLYy6S#@0aWc>+@ljA1_|p{>PnH08f;PJF8=f zsv^Bp)IOL_0Fx;*4Y6XMeuC-Vq9jD4t{*^Y4FrdEu%3IdL4iRIx$n zT1B~oW9s7fx=w*HqyK|h#5-~USdP!`YOwBLbBc>8?v8}co&U+&C;J8Qg+?@xXK^YW zC9B~b)Hcixb_hACgu%1^l>Px>TP4wAthtB20)HY?gGa!IrX@1wPbO)Xj42Wk7;^jY4JImA{B zhLLfl+@1M^UxaI%_k-`7Q|+_5qR9_aI0~onQMjA>u&g>KP#`9Gvl=Q01IfXh*`6w| zhk1W-bIZ``xjzJeukauX#OTF+Fxrkz3#Z|Li&>36RH0Qv=hlsju&K&H3{1(9UnDP4 zVRH3Qw{}Ucc>A{90m3!SvYxf6m%Z15Fe&ea zbG|WKWlrGujXOeoJoU5^-f)n1q6KKRE7=pzel;`ywc}blQ2MUz;4|>7+d`{^VZWfN zN|2}H0r(B$AXv?fl1+))Z(#4JA8q9BA|@+?_8*Re1~P(0A9^^j0UCWZYSv11K{v`P zO%d4#q>r;MhNxK`|Iz&7E9rh{(5S=!2=oi&->_X|j3UjY+dnfz%Hdd=2DO+yi#~qc z)fsT!=PIr<<)!SvsoI?FhIO;(H#o~!B$(<$g({nf!pC^MB2i{F z96Cj@S0Xrz*zYSk5GvchA*b|ox}GT3Jo$Et=Tu9)NgL-Kf&*cH<6r=#0m_4< zjIT=!uOHROUTmjW;}9CAO6>d~^YCzB_XZ``zgW*_S(bu5-{%EL#|he2KGPr6cn$+^ zW7z>2OWILE+oJ>&h3G!8w-uVDV}9<~yUo-^s1gWpockI?PZq=WOd%wj zC$cynp{QKOo8-zZ+0;^?e)<_tIO}j4!hoZcIq^LcUC!TKS4li)Zw%E` ztx4qYre)2PAt=OikLYT?q=I>%k?8c+P}{i(_`@xlb4L`h`v1AyXzRma`?()BdndzmU)MA(Xkl~gs zkcTMv{OPJnZ1+xdSw?3s@{m|hQ)7RADX;N-^b|`ZL zm#nM>Rp!^rFafg$a<^%9#7FI|OZNaBe^)&PnvLbKO@&s0Rib6QO8wy5<#}f>iVqlO{wTXrKP38)Zs{-4mKm{NtvcNSNC? zM&}U#mf=_=hQUf0=+%*g5L4d<{LJEHW`)VP!q*UepS3r|bnsB-gUX9bM|Q}?x#rPC zM3@tf%!r3@-%yA`Rbyt9j`4kX4+MoJr1GT z6+u@cX)`6c*o99nL2;9mTVZ9l-q(vN1V(YS`Lk}$N*mQ|%{$K4NJ!xGmM&h>JlUqb z?aohlk(qDX27uVQPOUh>&(6%L>EDM5a0F0Hexk+e;F3y)Owc-tbEuWJk8VmI8Iv|* zs9AdPhcz>ub=$K`tS2Iw<3(-L_FkXc^*nxh0r;u)x+5w6MuA(SxZ9r--rN4ZWyjbm z9#ugE=4a|@Z}EUONQqh8k12 zhEbZHGBz}Dh z_XZ%ZFoN+9-74}Jwty;mS52b$!s^J)8Y3OU|+C-^pZ@AFqcj zZp(uG^KKe$k4tyDlBf6lRnBuS0eISfe0*Q_!KU4sSBbZ&L`UbawPlg3SAU&m(oC%e zqYW`)-VhJQvgng@>zy;}sF{RO64h3F_X9^A0(VppFf4Pp)X~gaf z2zqeL6YouE)d{p~#h9ySmjSFPXv^^8^Ol<&o6U+IR1ib=YMKvsXee7i@|i`5qbh9cZ74M!WqOzn#7Ct?r3)$Z{6n5m z*AA$P_Vt|FgDG7owDArz7}6>SP%9u_rcwm?NR3eRSCt)bY<`Kf?=iCe-*!I1XoH>D ziWSI8SSav+tVZ7xu=yHTI^NHcKA(Wq4M+68Ye0{@<3FT72mX!!vp;o*^Z~4ZJ9!`eQG~*`CZt3^5G%g|Mj8tkPI7yv7z*dPu}Yjic^~8|n7L#x zR*!vzE^;Vl)1gozp9lRj@JQNH&x1O=tWCeg6rM6)@H?%PiY>mcx*SNS@6x^~tAFwC zak`3nPE#Jd*}ihv6Fhs5O3_ERVX|EV3fy??wQ~$)J*7ATEdGeC$t81V+qZ9!3biYa z5V+7=?)t8GaG&Ma91~ac`K_eHBmvUeH?)-aW5;T!GRv5o)a_1kF{zqNkq<0oJ_*Y9 z5V0P6B|*0H8B4|%H4=coHcIjRgdJ|?yju;|y+eu}&WEq0&6%#POuU9dAz#-yy@K-m zOP+SH5wJMhu!$XNt@_VIaXA~Im#w#wij&{hYOJia`Jk4P?^@tJD0Qhoj0wc6T&T1dTy!QnSpU@7oeYOX^<&jJm9i|FhLwE-|xQ-`TJP7ugSH$_! zciW!s%}L(?{8(lYV|N8Edpf&xm!PC3zhwFQl6kTB+tAK;#Hb{MQt%l#OHy)B$f!%g z8WTEfi#r%2f8YAe4Tj?kyvYA!*$aJz0)CBJ=X*a89qg;(k_y_sV!vXwdcCAmr>s(k zS$NLa0+ZmR25GiVoe(*=5aaeE2TiGLnK){F$;jj{H;eQ-#}oeWHxqQkG{vV@dN=&L zY=1A3v(h64!D=xsx-R<5l3T^1xz3THym<~n0o>y&l&zb|^Z}QWA>vX;g!oOa!@E4B z1yLI{xFpBoVnm^Zo#`)lUnvz(i_<7P7k52Yuof|u@IHWd-Vp(&F#x90>}4iULQg3)vCuZh@#il!LVKDxXv%pUHa}{AW)0) zl!%DqW0Ka)yLs2e<&5K#nDI{5#)`zrST0g+8H}pxlTXTu)v%Lgyf-Ikn>%d0+?8-1plL0@NXrxonD**<)GJtSvZHTSCV zr}VePa`|v1=~tPzG1_2MTtu>tuCz~HOhH^qEmB2QdoPK(YyfJXmd>WQvN~Fx=CDEi ziL*~J-z8z%k;A}moiD7I`mBQ2q5T~CCJIuDEACTjf(C>?Lms)7IG)H*^83!U<0#FT zS=T~74U*2CNVi2-a^~H(6GGeC={H}6T2aa#p*-RUK{AA&$I<`Gigtx!q$G-3!CEY% zk)U<~wIgrqrbk+kqDXaphURZOYIW$LF!tR^3~PyS3OO$5)YesUC&l1|%qSNB z76vj$)X`&4UZ3uwp|GxEPLZQ{by$VJ)p`KI%D>4U&Fokpw@LE2d+X+r))fSx5Bh#d zT~uS2U{l}{djd`u7a{-kMkV#rm%wCwRt@WN^wW9Co!rP`F)xSIgl0(c(h49B{gEXa z96l^*_e+<&KjlN29=E%-;-key$>E!g5YD!Zr(b)0x1so7m?b+3?YznuR$fIPwwFLz zd+B%G{#W&Z#`{cx+CO?)4S;?HEOtB!4!XOGxHksEG#bLzM7XmseXY)r$UH*W^`c#tF_v>SS*>*v>Z=D^p5PMhU}v8QT%srr=A z*@Omk(z^06_0RLPb?1g*HozowfeQ4AwWlw+4Z;(3e)rotV+JkaQ=>V3ll{Bn&&Ha@ zM-w0ZI99u_QjL_94pXc=6)F!cfgbCq|EYi2$PK9Aa|g?hd0hEk_~iM$qf4D%{u%2a z{rFcosY45+WAgVMK?wK&Mk$!nQnr(YV4@ckpQ1+r(ibk>jRK^S+k5f#)BgKkGh^4- z*h7ZvdBSHlIJCg@kEmaTx5gC}Qr(bYTM$Yp*P*2}5S0G>Hz?~(8LEe={_=J#ko^fm zM0agHK*#0NMjR$K3D1->#{NR`Z@swmG_dAHaRk~Lii3CrH#SLftb-WN`peNH#8!~M z)(o8;eO`#$e(0vJn4)QuTt!ZWV{vXry1{$7CpSL(*i<4}M_u49(Z}P(T&d#Pcfq5y zaWKxO>_wu?2+zm=EQ2KR`qt9~@{k4+sr~ecN@1)?<{_A>tfyWDvLgeI5+2p_^Ku0T zmkcI$n(qDSjp>ki4iGBm{h?Ct>?%4pH0ScOgS>#Y0*D}c++vh3-(jvU{>N_g=QGfo zB+Z{f;8tSQn`_))2Qgbtto7TZR30+N{`L>yw?EKehdIpHUa6uCKdG=QBS0DXTruBr zjRW?iG!{29#id>rY&ve8ou)<(mTvZGv&U*#Vmsb2Q2sg|_+EiNYK-q~G&j{qz>(H@ zEcXN?DJ$6JK!uR(wck0esVXWa7LA0#LrZ93eeuLU`XInB^)H3>id4b^ZyYU zDdi4Siw`c78AvgGffG}Qs)l#dU=DI()dKN;>s+934HBm0lREsM=`62;=Ko&J|M(c5 z9P!wg?FF{*@+J0{@?jVqNpU1{UI~f-h zJEa^4hD}uF8f&H3%NKw1!%2rqgI?AQ2krZ877;#%a=?0BhYp_QcX7;s==ee}2w@L= z?8PAz23hq=biqIbbmsK*UxoNzU!ae>BPUg~m^9YC=+x}~iv9e+52+6mGF1B)HsJ%1 z2_HP@yF}ILII{iYZ7n*`_rLtzW2}H1Gp@xo;eCdnlNg!055NkY^-9nnQ449&i_qvWvNX zNz)jOY`YyDceh6%OJC0egxbk#S|2!1^%;84vu1J^*(g! z5iBmuu=P1j( z^9c2wx1ifjf+^20Bfxg5^&>ak(!>i;MQsuz!k)qi56c@)k`Qu*%$NLlrmeY5*V&8# zvQ~Nv?kAf;l9MP@^Fqtvd0K;?gI`&n$OWT27nZ6C|O0&$vcii2%bE`8OEzgLrJikXdL#?U7* z*WG0?fMfd6!vw+1knPAWo(X3I4vS){f769Q>)@$r+eOl!w@P3g6GO(@K_ZfbsgR_S8yk?oUH>6Cg3Tt5R}9L$xwV6beqwG2cE~s z^NHh+v~3}V*S*?d3n0W*4~;h7es`z)8Mj*NNrseKwi@fN1^0DVAm)wX=Qjw3Q3x&! z>MjS0G9ElUPCZ2~JN7d@bUBxdf8VY~XOJM25zbNpmcSempSw(ATX;91S*Ko0{#a5! z7onwh++`k=dJx`DdV?UlOsZ!HyR_aP?p9D);wHwjrYznS-$boW+Y=MS4z_fY$y z<1}|}r9*+Qw>xLo!w>P`=@ot$Df;buas81A4LN!HGdpxQZH_W8$}+Kjfiwr|r2wG= z_7X70w*ZZI9a0Z1?%OX6S<*H#J>$_3>?h=e@UasMu}vYz2|1}4jhd;G<{)9H@FMP6 z*l(xNZ)-~cifgldt^kribN@hDDBK-TT5w!gqEXO@O_2?_yqgrAd-?WnYtUcMuXGf9 zXm7dH6KmLa;^7^bTw(tC?4OIvSB!PX6|Pt$q!&p;JNnvFYM*}Xa+!MB%FetBxVZ^c2oEWvp% zR8a2#l+KTeqo-~>%l32B{Rk7(sB10oM}%|NhuuK}J4Vy{ZEhqkooC7z)0_$A2Nk9;m=GcxU(s8S9CuE4!#8=8_km(#t2JLr`oyse=ai;lYAkg zJiAC-t@WW+{y>v$xdz<6`rtY+X=6Pzu3?gB+*fe_K7yONtsP}W5pQ=qO3}p{x_^h| za!{uYDOLBrc(}Z@$lSNFf~|ZOuW0ie1hiG1`(vw@K8~i?PLDVu_DrP&(Pwt_8D?32 z)*zM?*d6*pZy|Lk^hpShH{GmmycD^5a3b+de|`p*J)bJbb14Djtx?;jIPIO=y)e*>N6qJ%o8;wDdz={lmIc9dRh* zyHVOw(dj?i%YT$)SP4R-^#$@%+{HDcqF*0&|NSC`GUKUasGi&Wp^wn)+Fi$oNpU1$ zBsK)fWC+wJV%cZ3=#J#1aRoa-=Y{mWwYR*xEv0a#Wc3Lb+#lx!In`7uhYl5z^mb^=o))vN-w4Wo76blwoz-lt5pLzA0WMBdm z`dTXWHq7WUL9k`W;}_1e>=(&{LjU2{n5EZwH{I;*h>U63H`=@apynju79V==#V1Iu z)IenD=j3ntgzvkTBHK@5N`@O}3^iVaq?d8V8#zSsMAHN?iZV}o9ZoQ^EnZEosV>sJdS~a8owmQ?E*MCUznAzRG z@?3}a_T{;x6M6sM!pDT_6D-yTeEeeWeU4eKcJt}h9MWhCu-Wd+?Q;c<<{B{Zd3OrB zSdiDm&LRbmhi2=U1(?SZZ16rAL6hzkqQTaPZ;gf zfuPNbDUeX4fRE~H8vL7Tn zcvk|qF2DH*2z4w3X#FZ5vqX?`A>N?YzcP<0gj6igHDLcEP{ zgZ*?o=OA?N%*)=5Vd7xV%XCFZ1q%BC;77}Jw>!X2cOE8*+ho7Fp!hvb>xcy35KvGV zvv(t1pN)A%Be7J7;f6;_?W-j{aUdy8|EVuc(R}w2R>Kzf!V-*rf#2!^lKg=j`(Y?y z*=L|OSbvhFh)jNm40VfSC4EM}@abeJKgp7m+l=P|Y(Cq%K=PQq1e0yEK>k9r>?M=| ziqQAL_e?nTr9lhA8$~j(vZ{_rKGr_Tu;C2ZV(UrPZG=t@Q`BReuB9o0ya?s>Oon1ga22@>jF|b5GxRoKVchqNLWp8R~pXhb2~%5}&NWbq7v@qvsC*DPv zL%QDH=OM}9A6E1fbGhJY=usa#lRqN1D@Pfo zjBBKjAs0gNb)RZ}Fb4=n9p}|Dt-XM~vO`LFL^sosH5BNu5GnD&owIj7WP1>v8M{-+ z61FWL3sB`}G5x%Sz%Qny5Flv=1**l>$TJhUvmy{1(~yv6bs#YWX)zZrJAV(HIyylo zm08B}nfdWF>rR5rR(AbX;+8i>jT9p0{;UyYW{n(HPF_Vqw~447*7-MLXS_;m>q5@V zQ(s~+@%`+eESbR3DfQEbBY3kk;S+*$gg+5iG@AK!KT(<0N6PY7yLhAv{qpWmc~guM zB$N6YBrFZo{*LMH5@~Pql(!9*@w*l#!N3VRnzf5i=O)pXRvcO)H#qTM z-$bB$RHuE! zwFz*r@(LWe`@3rrtHq|WmrHGP!NLCVf=}cwU_UZ5p^8qrqEx`Jl#jomoCRJW4M`d1P+qp}z6Xwf2m=RZ8W??*Oj0qeGMImP&wVQ`*n?m{egUXPEw zhhyi)!YOiJjw%gkAB2fsm!iOppp*_qF6;V|jRu+=zU)PtLW&c_X*8dn=i7+g!deYr zWxS|Uo>LfmOc6vO4c8QIP~D4TOqyBe0svEoRPb#`8~?GR$;Nx`8VkRbU?Yaf$K!iKZd zTi#1e10+O%L(64o{vj>>y$tLWe+tZauhwPtL$xL_;CdFX)o7 zEhMPq2>!E5jgzl!xytljS@%^`I)OH7KjDz@!X~cv@X6{hnyGsxJzBOw+9z3#xhAL} zl5H)-niak(*D{23v|jM~?yd4t zsn++R^k@{l$;Mt`){`zxiNX?RZ7*~Tisa2lo41ue-GQ+l@4moP*3%+qJe%qX;~I$Q zHaJZE7Ul0cZ}rP$y5nEiV665_;0ybe+TGnRFpn6Ao58f-46dEody8QhXEe>l%qIf* zl-^jGFHa)MAh%m#;)G?*iB)1QOE&`io-#Luhr}sQkf|B=B$JJiO?QQQ8l%pdQyeBZ z8@n~Bx)bt9aU5xp0PT@bfsN?R{X_8!?W%JQ>E2Bq{% zY|u~!F_KF}Qz-G@^(D!H(&2sl>dA|!x;&zbG z)ak(;zvgZuhH-ii`5>Dsw;9eW(MS8T@)l2H#9Oy^^?7XXC*~|*h>AYo3ao-Tm*HL` z#hpVMZ5k*EiZ%U#71;UP{qrbjWf7LR-vZNv?yyY`m`^yHzWV;pEC6-L)YVKX$Js42 z8j_6X@z6zjnu>$JWBEkS|KBaQ;v)J<8wv3vF+-cbbi5iFSQQ;k?P+sP>(NV)n&?9e z{Ku2ky>8&;v_ClbCQfcG-gs}XZQPdc4EjN>(<_B(+0#W{L#)zxtYIk>(s+a?BXy3* z_;^vFpP^q6P(8kXQTnYHjAvsll7D2EXy2MveCmFk25{%m#bO!vq2CvheU(41x`rLRJLRZ z*g|bIUg(aG8ZTwGaQuTH@mwBSLaH`qL#&Hx^fn`xyO4<%dM(9A8&be}X-yh4J8rq8UN;_c$`@i8ORPbu8n8xHSBZM-&&PZ>9zNE3j8 zeT&)Qd!?2iE$#+)!}c@qA~Aeuqio~TcgShUe$4z><#fCn)BD*Cw4#rpuPADPVV;BL zCn>5mv%oo7uprL5_;e5Ui|B_v8o?bJN4HLbfkuT+xlTg|kvyPer1~)?~*hM<<9IUt>$vxi5;tZ{0`lO)8h-IuZM>2&%B*# z@7b==ewtBGd}i5@l$y;q^C0hQ0RUwieKrcZ86i4A>i>F$!|?XvWDXft?6M;-i2T+c zgRa6U*LW|){bP^J&pNIF?&x_CLcUF}G{(kPrii)bnt6LN_ zPYTOp_#tb9gt!D|IdXs_S{IB?(l!iLHE>$8njpciB^uNsj@*nTd2q3v_M*nR?!lVw z-otrI?j$wUNr%`c{D;ksHtXdr2O>7P0FTJc4^9mMa=qKMQ9ZO<)waW1t&e8;-!Yvk znhLw`JkEHT&i&yN4BprNrS*yxH-Hhu9b6AZoH-JHbdE56>Z#WQQ4M@0lo{TVr(f}n zQc_y8`?CEHV{}UoU}EVj`^Lx`bFP$=T!mh*&G32W1ztB_2&;n#OLM7b&e_dvLY!xZ zjJuRjU_uQ{OuaM^lX^*g$S>#F+2q$UF5eUHd`$fqmib7ny_B`C(C1m^_Kze6|FlFd z=iY^jclze_z3$`W*H^L!SO^&J7r06e@aBIr_*gAmg?l;kvBCBc=s7)=9fx`rpHw>e zKN^GGqpP7{wn~a*+dXl?&MpUC{aAttiyX)|k}9AL-bO!F58McwxooDL9Ll zHFnqDyPa!u8j&lfBXMF&8_>O=zbk)13{J>*${L>9_#mWS=~*%T6g~r;1;^<)ieE1e zB$IZpl9?_ILv$wh&ha3H&N9}=7{yOT!(SuYUcO)TE7?xeFm}!K9NA;2d@ShYH+1J< z=cEC|~}t6-T95!B^B8tk<_XBX;1x=yG1e^u^PAJELSo zE2sEnf~_-_LJ!Xujt3ioz^H`8m{sOjyFeC3ANi{_z)$EMJp$(K-1ngN3AvsYsu+dU z_ngu2U*Z|6AKTDSV(lGwfle#ochXYx!qi&g_fFV+E6U->?P~KSSG5c8vAR-qV(bwb z148VCrBAOVOI}zqd1ALM{5b&3OAN9<)nZKE7%?T8u-vE4p~;DZ`6q3h|A(!&j*3F- z{)YvIMmnW?kOoD%OF&A6p&5o05Ky|i8zhuQM5ICKkPeYj0g0ho8l>?(bMN(8>$~3H zpDq=JIcJ}}_oqOvm3;7eDhvcHFx1N4$*o*Ei+g~4&z|ybbeD=*qk*SkA-HV@e#!Xf zfRR344EhZjUAL*3iN&e?-sQl3weLXW2{NHFtj}sU>MSwyA9ueOWD_bCI{LPK%!^S+ z?U!?VQ?Um=FiNfsK`l=H0`k>9kXVwB#Bj6|5h3fK>6W zk@QHz(-TSlHq&^PnZ)j8hT!OKClLqKC)-9G?#X#p&qs(M_;ySx+)c^>BS)`rn?chE z6zP9{%1>DnMWjE7C*%j+a>Wf!5>6WZ ztp6-Zto&tvG-s`~nSNKsiN-MMF;XZMchcz6ac5uBo3+m5df36uzx9B|sulZUyww_> zcl7@_4x@JW2pP5Kf*qIqTj3U`8&4A-4 zNNxQ3xC6L|rJ%eD$)f{KO3i5C!P_{yVjz6z%M)Gf!4Db@yw%;Llp;GsMec`|^4Qx; z+hw(y#pd}%9_{^pH){{tt3{#W#atv2daE&snvz8GO%yJi=4a=3>#TD1TU!E-3mG#H z`x*b7sT_U$EUZw|qW)c-yKN%+u-7Y93T%V7?JaR73%e;jmKeEjrbS}xN^ zK64EiYko=w33}dZ*I3EgP~>ixP0QAY(mO7Yn1^95BiynUeq&x3^4b;qse7s5nU4tb^#$4+NY9b~(-TyVJDtEVR+b+lK zj)@j``Y-S-`a#cg| z<2WnP+EqyS+z;&1pVkWPolY^!24U!@_ORYMjgfbGs{7mP#}~$NT(Wg&5GXO5xD5DAu@1m) z@}yw32^^2LK~a@FK;bcjs>%u)1mgqhixV#eC&3TR)LFU4Ww4s9^y2>s1WNXfoV*Xo z$4mCWV55ej_E-W{((Zyw$Pqw*0*c>Tp$^KUcQ+M*8{~LM(tT-J+CV1Vu+&D*eHWH) zkaL*cZTU~WrRtMZe&61fkVHU(lV}7_UJ6k3PQ+gW!REs@qnR`=Gu{_Ob3x=GDrrDm zFdWGR)+y!@7X-g~#^rin*3j=cr#B$a&Rb?sXXp6AjDs*Y_sG?|H_z3WlEZ|67302u z+x)ip-bfgw;rquK%99dG{h~?AXJ2qWeEat!991Vd18-n5s424-Tquk_P7LHg8`Nfv zzzF0e&^ze%{E3}N+EC&fpBm6?8nw@B4qqc;T>(#l6SzHC9D;^-`Yf^SHgZa2&h;^o zwb3CGSTGHhE&vT1scJupd)Cv_JPU{b$+_3RY$jATh^wP81{KdYW?b51cxocO@C%*j zPM2x47+go?Ca@)!B3VfztMUbQrG8a){UXol2M=?OF?E>T_ZiLrNgCOHcMHBn=Idqw z|K}@>gI(jr&PB&H2a@F<9e=n*Nxsv_v_No0&L!3y7^}95o-Kq(KPLl>2&_c~wf}pWAsZ@VKh}D|Pcr4dj_?@)@(dbk1ZbUC;;vZlu)(0s#1W0P!J!Obpn)%~}t_m)EUl_{kQxCN8=O>-@G z__atz#%=2fEu&z>!(0@dWTN;Ql*>&yN2${OvyjH`A1*0lkDz=10IkOSSqX9*oRWag z;NP^Ec7VMMeqwj5J~t6q5=u%Ux?{W$EuZDW>F+;#@-^|1Y1ZKc`(PO7v)D`L1klI( zcTRI6Z_(r~&b<*^BwNZnzL0G5p@4qSQzTy+fw zuN4xX2th*YETnCG|F^r%j!&=o$0xp|WqaN!ydRRYg!jLi_`k9w`xG>zIuyxVn^l3) zqz?wWWX=b)96Bj`EXpiQUB{FLK$x>lwaC2h5k!d&!cRiXpbn!ywR>QBEVz+-`u z33G)IW5W*<2531fGBy-5!+TzY-qSW@=Boi$aav?MVVjr(%73tL9aMl%)=<$x)@M~f z7WR_dK|A)m_d#0{YVM_s4O{+ag7;UosciinT}UPF&QA};6fkH7ELO_sd8l*d`cwW# zsZKh9)TmHgYhp?Vx%N1+A|)jd4aYL7KUbX7=N(zR8bz)&QywgW`eb-9i_-$p=k}1_(+gxF@N2+X;P6(wCJowTsw2Hr6-zBYP0X<^|dN_+3ko+yeL%FvA z^2d3DT;2PbBVaRd!FU8YEwefk3Slpwq#?BB1n)pqt9|DYrNFvbCg_dELD~M4bONhF z=xl*NLsii}kElI!)jYMB5i!d8MDRGZDs$A3ncduPVhDdUqq2F_Cv)Rc9#<4LCid@R zwsDQKaDWrGH%fcQlp^A72HrnTuRXjhKu*Zlf zOwklCQPx#4z`-O7Z6jA};{#7p{Az-Q;HrXPlR?n;0AMuf&QvetzoK&POSjB`zWL3| zEKBei5AifT8TsgD{h1*An?Uq8Rf%xAAo#6|Ea?h%IzNlHd1m+@REA^lLqqWcv5U96 zXjKj^qK{-Mn)n2V^Ph)%CR6z_`9nvKB(uB6U%BCiQII2v^>2udWWe61%$IWEi%g{K zRffz$n<4K|`_*x=%zdSL0sdaYD^$B@Z?-^ZVO%#H?p3AL8WswX8wfifmg%joehc4% zGd&U}BE}14^p73WjxAj`xEHH`@^1n1tZ(YT99%}sN-m#!ulCWh?9FR?whP7g-jd@n z$T+%rXBxrA+Y7()WK_t@^M@bOisie^~LPT$XqB5Q8cX| z6)Y2tmlin5wciScAc!Ne`O18B{4c~3%}5Rrb3B!@@jsuHmaFxZrV}lr5B4<-g|#uu zTp(jaLJPM>KF;0(k+KBehJU38briwN@nc>49HtfaYPqO>2hOw1xH?svCDlpw@D9B11^+SC#mDjuvImUZt}s6rITtK^N*uLnXru)iRv00~)4$Uv{^&Dyjz0?-I9(=Zw!-&8T3YI_cuVErV+zuSSiMQ^OIeDda z+rRNusEa=!t64VD$W5-cROmjWA1<<~51 zPS8P@Z%oQXjJ?;8e95UGD})X-iO8u)3)q#MCwAb2U?p2*7Y?Pifw5x#hqBaj2Fq19 zz&^-i*Q2D+CRm+OY+Y-{85m)Au=kHIZ{Leb;fSj!?!g_=$vwBeSW@wPbopQZ;z2CC zI5j{Dy*ly>QuUcIu%W?C!gTI$$64l8#q^aSzR2r#BMSCRGdJ$>$lb$Vmb!S82)&w# ztI<$ps|#(r3gHQ&(C9?05?gSo(Z5xh7kVO%ySzHr*Lee~s)Hr&U_^x6Zu+4p*EI?^ z5Hv>KTXv2Ui0+E$i%rqd$g5QNgI!uNE8L6Clqx?f8-=TYW_G=$Z?ChdFRM9nbmYRG z^rg4dif-qLLAvT4r?85Qj_cY4cB2;DyavqtG?z!yQ+Yq!xSCEhBcRrcnO2>lxXNXs ztErElA?}wQ2}g`Q>$u=N!IbN`UF5Zu$XzdI5j-`fk^Qv^J9YEm7P@}&!Vq)$Dg5yUUePEsugVIQc&45NS(wRwNthe#-sK#4tbJ zTME3#ef~#p<}+Mq)?x*xdqjEmX6^3mem&+rt3wFpeB$kWp_vw#I+T$pjdk=|GmR-= zt>!3JN-~y~?k+9=PR=!*pJ_j-r%qvRqz6PqJH<=921FWC8*RcVr!Y6DmbVF zr5~7xGO*oVlH<9WsBg1+D3lg_PZpLMyP+=F#?76`zTq^cRV1@}KFSy(s&&2*vvfd= zNlWeRg{(HP}Ju;1Mv z7wCJa36yeKI(_0VJ#foOgeP#;v-Aw@*lCx&rj%z|PU5QD-zPPp^(_LtJP zaW#4K*x^)6ClQGE-sgF;tERS|`U-mTp6=9W<~L|XyitEwku^BSMbfOH^C(N&yn@`0 ztimrKi8?m)b3FyCq$lTRGFKX|nfg2jYIHvc% zApakjM?@mo$g9-MKRDmYEo7XoD+|ikc`JKuy^?fA{}w(!Y_!;^f82-8aBhRX7 zqCj;2SHn#Oolr~ze;85d)h&b0^2*|l&~XesRUKq6DRVT$GyA>G_3J3=)MlMEW+HM8 z+=LgJWmCZ1<;WUI#rQOpD&xE2X7F*9!*0w0V2OJgCZ!au-Bm$^k$)-m&B}c1W)&%l zP8N3J9A>+y_S?m{pAkwaAf_yxuavv%X$qD4(M&a%z)lLm48JEND~zfbafh84ifMW8 zDdz3bttwH*w*H zSta8}P9BA%-^wioj(4=spvr=(=7J&K%FVJdZsOpJu7&0M<;YH4o+#^I37i(5n0f*-z_3(GuY#!MDvQ! zZMVZ$3JnwUzqwwRku!>(-+n6wNCB)Afy{32kscgcG|~P<_@?)_46s6A)G9FYh|w<%80?l1C47Se{O>r`GAr79eF~<1kklBl%(*wU485$;!*r zT@1$KncKVlB+Gs`-P`8v`8F^uUh>Ap*1iK?AI{)nrQF;DXX+2KxI^V{FV4MZ5arM=8eo-6Gr=b^yLgD^?9#XPxY!lMd~HUbYAM@iYgYKU*Db2Ec>QSWbm@!YeeT% zk|6iVeYRH-@NlrYi{c?M-5b7cIcfh{mvhQ+U-?T+YUkgTCjgiln5|v&<>mBALg1dA z@+!)QT9AEY#H3p+W@D9q1ll$aJew@2VOU%jdh90H+0#TCz9g#L9_buAWOm#cNU7F!NRojnA0fH~DWx3-5KV2}S zqCgfiCV-z(O+Yxz&Q>Wns0>>8S$LWXpS*qtGi0MD4^ZGP@mdx-r{=y|iF?CIM^>V7 zPaZ0#Lx~xo_i$|el^$U#v2Ta8UZN`g{7~cF!5NJk7vn7!MMnP}D6FJtIpXAf#(O!H zzVe3?_Si}@V0jp40ek&|TFn>stIv=N&kDNmgk5Pbs^!aC0;yCxi|$8XrSa!aVX7FO zOAFT&q-xPC>Ggg-&D_cEg;iGV*l)Lyfv_yZD7lPNSub-cEq8mq0JO`SZ?cMySiNxD z#giWYzm>`Rh+BibiFOAQ5h@b?iKaSJ5e?}c=meyYoC{*gDdxytQc`r-+k`%?e0eWw zDt00qGEGmMO3)sof8fS|JKlSQ3I|oRY0hqJ)3c;eaYflKbdzH4wDA_lA4D>S-Ppt-PWRo| z$4mwj1+Y-rP4-GzbcLj0%o^$(2jYsb7-pp2FN^s0-47luPCA~7o@TwBowr{)c!BSP z1D+IdpvohOomyhC7wIDUzn@CKd>;P^jm|IGvx+92JZh>7qF6U-?9tO5wR|nrfZG@r zD{;EGeb5crTfLE*uSe6v8nX1Mo#ZW`w3VjPp4k!rcO8O};(d$t*uU2SOEWWFC1re^ zN*`dpz~gu$k#$;>fV|rYvFEaL8|q^sPNKy{Sg##^gYZwEOvH4GZjnXU`c}^mO;rqf zaO}KcL|~J53mB`;+1!Mzk4)hVcvF4aer=OKDPtoHmvFC!4;4NT9os1e4@@ZdJ4 z75vz`@L)M(RqF1p_v65Xo61y#)tiQmK&QB1q_4O8-y@BWNE?FZUl;6YGK#`Xx zCj@m#fFcNNY6MO*M25BcP?K5EJqYkaC<+@FV;)t;S01%&%^vM)~FXz-zljvNg~C3}VF4u}QjB-jN!q=GYD^#qfW54Ie$oTo-%4F#kc z9#|GIZ+ZdqK!a~>fXp)FcKR#wqY0Bx*lzJGZ_Zs}B?nI+gD4&zBAT zZ9|o#HN#2IshS>_p2oNS;e+~H3O<5Sj}M$CCh1$RdMdrLPY`u>DJzR7o{Zd$b_~$! zteMDP3(*Hk6gSI4sZz?Dgaa%YkNKuu(pcix@!_4A1*)&#lE{yDo{LTEKwFwUCz(Cz zzLq|*At`9rYwIc~6Q>K`o8cLvQC}zNll+~y{`F+Q~kl~6P>LU0NBu_kW zExV$POPAn;Tz=AXGN=#oj4tX&fd-L#$IAi}ZoM=%Q&S;rDI+hvy&@lXZ*kcZ94kP^%Z?^j$80OwQf!F_P77 zBH|<|BcGP{C(^?zHiH)sG~5YIR3h;_^NBF&O938JXB}(Xyi-@}!Z8waayyn3@V0iW zk52(=BElkcz2hBRj~jVo_x95J!1WQT%NPZbI2!k2@|HZr(0SAtf$(DhMPF1?2WH&5 z>FN2V;ZQ5tEoZpU+4sj^EB-TD(tTN+v9ReYpc$AW3oZi_ojc(ZQxC^#W$5JVshwAFESC!)9TJu>rD_Q!!q}DPoCSrAOkqt6*rp8Gvg~g44~>w z5~vzAIl0Rh^B)+Vx6U%Ee-SH4tM0vn+wM-) zk{X7X&`VDj3>~qziFFt)k|E#rHfA~SY(^bFK2vFpH(GM??>>b@B^)wyIoDAB(o|(Uy=zX#% zK};+*f7hyy&r5Ys@!#>Mi9V?9yNxA*e0%oZOT*mA2omqLf)Pr8pXL`=at5#m=F((^ zCZ6Ip1f5fMAZPD4VyIu#33w4}?)RCS?IrHpdp0CL6_zNa~{w zdvrhAEfcAtfISZp;Tu)%;smS4i6KuB-klF4`J*XC-ygH_pF~L%{s3JKIPeJBer=pV zIMg4gb$sdZw)YB!?78VlpDl-2&v+w^?EmR#1oy7Fv;J-s+G1~EHKU;2!SfA^>fPQe zi5z^Gf;w5-$WVZA4%~qZj}0?&!PDG^9!Kc8WZn7C5r1neF)0T40nf-Z>4lG{!W8f= zAtUg9hl}<7Ip~H$56Ay>mkKZcw)OPOEc=l}zg`z;6Un=ui_dlO`Mc7Tu*f_?XfE;Tq$a^Zg7eLfB(}H2o zjl#y5%2>6Fa{z$~LNrT!ok{dL5uM@Q(n;1wSFt`r_Jfj{-D_3?{ISqF*`H7ZkJ7ds zof)d(B3D_+HAL@Oz8g-wAp*$|Q29v@imY~h%I7R_`m8_5D@(k3Z1s@TczwwPJs+co zzr1#$0ygGidDzDJsO>84FRr4#%deE+ z-=|`>sS9H086?w4@3$$TDLp`Es-` z^>{>9Xyh@6{sa!Q_I5R>ASreflo9b#BSTD(X^+i10@5aF9-KZ8s3YkMC9#*kFZcIh zuUvkbhun6U(Elxg6f_|*u;X9saGDWO6Ch>wt+oZ1~vwVh0ZV$>go*@o19h?M+eRW7sx~cM(Gv> zooeTm3Sf#G{lvh=?*&~a7TI3np+f%kItiu0dwf9j5bBg!&a9I8>a|;B@>aDK{}uBa zKdnSc(Z#rM51tVTx?Q-as?@|WKA7B>jXZ`-$Op*W7OwAGBp0_Bg zL%0d0qH-dvzqbB7P)_e2mHYh*9)_#1@ox@4>cEg)Z+xe4RY~oCkIOM1WJ9Z31nXed z3MF-9a0m6%J)`zy+kr-1*7;icV#O?nJ-c^~D3Kd$R-pdt(N{aN<&-bH>p;^ z*)21VK9s4$D%>z@0cSg7scxR%?PMW@sN&ICAK7}Sy_?Bl&Btx`lt&^ZUWmZ=p;oMr z9;%iefrs&VJWFn^gW@s8)cT4Y5_$Z-iR-|i{IR_~-2+mm`o!X@CyIv8qoOexrV+xy zf@qY5XVvquQ56-J^bzky*jdn#IdP*!@yHCL**jqeEkR!x3%uee`fJxU>*U-U& zKaVy|x944UueOSl1pU9_L+}p_eK6Wb3iitmhbTHtUKbfijoY!Bw_R)asREoE6O}3a z@WI2% zxCzr1%B9D>zoE`#@~EZdspAjM3cLaS@sh3VsC9d)$g!dG25l!Aqw|c8b+s$+!t(l3 z&-nK`ExQe-N=73_&*R1pS&E$h{l79nyou1U>0J|(*kNDbrmq?u`j4m^;HDHpex`CI zz>jemM-tck>=(*Q%a75hYArln;Iu#~Ahyx`!g~exAp3qf;3f?8%9jNR%IwL{(-)v0 z9_9XNdDlO3_6$X7CA|P?d$!B+{l{QDc@x$nOWJpHbhTqK$awvzDu^ctZY=pso3Dj2 z&z6V}(6^es=s3l(FjXavW5W)FCdAIdRw7b=>1xSAT}F;l!`zaU?eT|VSQF=u%IK>& zY8Ha=4e2I?$02)!WnOaT){g>hjPz!wNS22``s5EMF@`T@oT^Y7SSCT7Y|HB9-6J$G zbS(PlJw9&N&$$~hCnQsrESQaX8wz+~QlZP|5u*RmU4PB@cbWHh#AZU_ZyP5#c^M(& zGI$cOq(<=X4*lSJ{$%b0Q;IJ$yptEPjN(94e9U3G!_??|Jy+wKZ0E7=8~{L{0vjAX~^=O;0+4! zoj5;pzd|daVkbW||0N32$G=e8-w+#KCcoD*p8HmDnB6$0O#9RLcFv}Nc2y@Hcg6!9 zC;r`6WUSP%EUR7CgePKYLn&s$@DCaG{cqa;FV516f!2?kcqikHO`LtvE4>=pkOsW- ztb<(IoxzuVyK`A?BK;7)UkZUmS`jsudPa_`>B)c|J$Go})OwO!jp&;g7G58s6Fh3M z$#zRC>Vx5;W35_9HUawHWGBLs>v%y0cHtXap9pB`d38D3F;8qFd=AfdjTzOoKB zkK)}zfrr4)!J&p&LE-aix5bQ;eCyDU2HbGpVNpLo(yKrBB)A{u<;4&?lO$=0o6vQ1 z18QY5PbUP?gECOBzuhtzf{o}EviDD=4KX0r6!=&-EWYh2=%6kow~-#+8wsEsO^LmL z*wYeW&*odSTP~t1i;EwoDa(tWu9mujyP!(ym7&f1f3C;BzX+0!yJd-8_FaH^fQ?;G z)imJR?TuvE$G{$Ho=V_+adkhdDn1I+C-?gm=>PQ|W65ovX1yGK*mjh?2fG7Pb*bqF z(WDM5vA~XZavaaYx$hDf;m?z==y=LCrbii&N9vil{SdG%@f(ckc?|~fnQlJHsmxF% z=3L*5du_namdyBPc;`8YVDH`%ZHPU9qOHz{TObOtcG=6F=|$-9EFQr0xn z@^;5742YdenuZIY%07j3IQWo6c1jah9V2S=gqF@D#m(rZ&&`-U^gMWoqA%r!t54Sk z-q>V1D{axc-6F+_QRhpfeVqit%{%+qd3N`aJvBmZgi9I>>5DlJDBm%qR@;V#@l!r# zO3z<;*y>`3J=DrG{V#P;c0?|(@`UDKG;oQ)kLtn_%5wBoJ79Z_KRYlEF_g^oDP6-aL-|33;--QZ9fbg>PgJ=tgWM^&`m=*{QpJ0sYVbFtdNQ z9QZ+SRhr~bjf~O5(nKrf+b^+`s5eSgh${es#OCVs$}?pnHq(F0n=y7a8||;&8PtuO zWR~bZEA{5dOnOxO&1yS9*s=97^PQ|w>T)#MCZ7N33VBq_3lQvyjw~J$B!l7wcGlDr7&SS<}P4@CnhL3x) zgmR!E7w`sq@dCKaa?Uu^#=XJ-h^BD0b(DVGRDX&LhGh5(1>>6wLp{0?DY;nSNuY{L z{7^n&%;n6x@6XNNAJaElp9M^z$4B%Yr-~$|38w~?KP`8g_?J!{u_^w%Dk-L*k{iGU zXIJ*+$68ZDdNtk#k3mvOGXrWXU9_0jQc7o|Rptp61SzA>PYQI-8FTD|jzREjZJ3{Q z)*LVFfz{%h0bc3Axr3GsD6ohbNX-CL-6xScKj+S#CI$R#N==kmu=fmnMU9HKXECB%8Pde^d~akkC_m*8NN3e1x>VoH4MGCS|U+ikXK zywv~5z=y0+9T6oTp@?nYhsud9?OD=Q_6w%?^Q;{qI!RxEzjU#55;~yHQ-RP4Ka~6B z93u={j4C2gb~!`7Fm^L3Ak0(jJxj5{{QX`1Li>dLfuTvd=WkCA+%U1^Gh@$ektKYR z#dE#g5QyyZ8)<0eJzaF3N1K{c9&jV>Bbb!z?ynbqj9)-0hEop zq$Vc!9&|fgxuo~aMYgR7KFm@>bF`Z{q(a+o?GA2sNO%7{`=#LTqr(HaP|F?59n@9leFYQ@lMFu8>@195r!2#>r1+NVriEC zT*H+VC+(Sa4D$i4h`6z>{6hP`E!s308u``OVl<|LY(84SS<{Gz4Glpl)dS5K1ObVh zg&$yQOPKtAna?TPg4rwyk~IfXw4^s9vg^t|Rar-z;sLuq8DM<-4Xq~x)7#!NsX~6k zgC)_VmY`6K3nGMVA77s3fmMqVLrkc{Bs%ahjutn5RY?zclaJhSDF~$vt4+Cm1C<%y zV1SjPMgvE`z(!w!F~NGXC$Jc$dg4lwq4i6{&tOSmVJbyUiy-HsBoG?{@N@4db(6*I zCW!=U&7XlT!_NV{YGCg{8D5*<2Fhk&x2P(!i2?# znc+)7E&71U*3RXM&XG9ya|br#Y{^RlD;lYGJ*Ul3Ify(-oa1YODEzLpFzl%|oYSp6 z9*zX13{{1S_1rIyWj-{iV9^Nhe|-3dFsOMyPqnr1xdK6{t~M!8Odnt(+ajS=zk1{iu4bze zW3`|2ymRdVLKGgW?QL(|i-P0I#xeRJ4v{l?K+?U*`+UP?cJj5RmbXOsqHP*TMO5^tr4 zAvtDW!t|t3nIh4R66`EV2)vCEtS%(%iin~;t+ z>Gsl@RXok!^%7OPK(?@?K?1$Rgrp-K5Hy72+VS0=JVVp%CQeHUkg8x$Jiz{Wm8d}Y za9DIX7GiM((u<93hXXAIDdUkO4AWq>?5`ejwClq1n=eR?&DD4A5&|dLO7m$yThg$< z`SShSM5nbvA@srtY zblAo6GQqde0X&yMZ&P3#@h3wQAv#6`zojQU^hBJeO6hzos7KsNi*i=4YhlhJhF8dG zxf7rNUJaxoq;~3OW|CXJ3TtAq|M6Q|NwAU|TH-_MzCS{(ej}D1G$EO*2>*Vz$0QIY z?KBb&HyRc2d9wz-qARIG#U)N=9bG8fqe4~u|w zZ^0%ocxb|Sr*`BJaXNFiw9Mi()Mi3~Na{OJ%;FNg0{!!n=vzFaJukyv1?PAF{Rcnd zqVJ4zJ|h!-63ani8*yWrQa^gQu@jhd(fw6w4S9@w;^$Do2d(@2=;TD+>eh{&=pFB8 zN*Z}J!KzqQp}pswu?{qA@K9V=%YEXJ5lpAaL@3Vk()r8SBxdr3S_tb$KH|#*hg)Lk zl@L_?6zJ`ioCNbkF= zJLgOQczrGe4C7{&?4GamC*dNcJe7$J_q9D&ja$1ubhkQ&ZoVonhToY+4U3W}g=u#@ z<_2(*ZGUWQdMGf*;C}}9SwzXU1^_NS$z?2&y`ZqCF<6ksHM1z~+y~KF#g;h>YJB*J z`>_)+FgTs$TW_l2D+hLi6M}Jj*&?DK#`36JHev_t4C;qz-_pG0{z9Ez{;OIzvv%oQ zP*(xFn%Zn7es(?A<9F0SY;@#jZjL_K=y6*r`m^j1IoLFT{F_%jltx2XYy{#}%FZ2_ zRIaKuV<&_`ZvPCipi9q7VAAexR=~lXcrxhOjPq^Oe^34vi%6PJG+qv;pJ~4BYz}#w z$$p0|WCe#nbwT&F88p_XI`{`|3;oBg%iC0Q4QB12cT5K1KR@}q-}sfifxBt^kAct6 zG|J~!&=%-s*3jp^vG+-0_}{bfBl-VzHa-``@EINnXurKmBnI32O${dq@c48gCB-;= z8%O04Nd%oIx^u7J_4B@7tPb-e{*h~^KmI}1`-Mqb#{+9{otu9W^<0ALH?_MCHWd6T znbO19LP9GTu70B~>PMf0I@lnX0j`!!3Ifh}aCD4E8&<)LSiXYJLob_wWl{<-j&6QF z#@Bj04mlKPQq=6MpoQ-$?Vh7%5&*npfj5l15hz85WS4lSwB7}Ibj~38%Ww?Exb3VTCCk-ceDkXlXGc5T^IamA z^EbCqIc$UC+wKQIn0h zsD`dRZ%u7@KV8)p|JzM8;iFxY*_VGxvl?MDVKo4F;MZ^PLgxdwGW3T)Hm$Txdh&JK zl*Dr1bCl{WI0(^XIk$m+kW`pBP~AS~1dtJ)O(axhe9wM+UT{)jI%k)DN?Xxi%>z;c zMo0s$x6K^$qhC_H1}Y+{TFSor=r#Q(!k4|2h40le?MV3p9TNsJkt9AjP{2%BllfH1L1T7^X&|4-Upl?AkKq zqSmyJJAqC44_>a+OOmyXBfO)2?(&bihv3g=46`EXEILH_f_2z>Dd(8M+@5BoezS`i z^eM{3{U%qMnFMfG7`EUx4R2S z87TlTm~>5mQYl7j`=2(?|75<<6f{8B?FTt)v{+6Jdn;6tcVuo35+p(+L|*`S!b7xA z?$yc1$4lbOkWg6#lz16OXZcoD4^YS|T#9y`Eo0tkI|l##r#|^z!9GB=5F6Bo{T%#I zG|g*zf?4k2jiD0i!upEFz>xQ5;dXEW24B#4XaXnyHNfSJXwIk!s0BV#C&0bT(Rabt z?VYn97#rMc1iZn@&funj;}Ew^>h}~Y@0V$@amAm&R=EWCG{#5sFv1RJS?H?YIRIpm za64v8q9@kD|Pd64qHO%E0 z57&vPbiT{Yn&(F@>Q?fR*Z^%KE?@12^8!T>Aw@P_70R`Q^YH*>0;_A{rh_(7_A8^x zSW69w!q&z37)=p14p-mI*@zCjZ}+}Fvqb(@X7HLh4!E8SUT!vZFwa}@;g;Gvt`Z{oPt-gFgDRhcfNcZ3+l=~p3Yudgx*n@nFUk_pT zl6c=XqCxEK+@chl)-}|KaGG=H1hlIf=Ay!ha{y6FX1v*tD0$fVv6q5*ZwZ)>)+%HO zIYx_j*59rVhq+iWbEGOyc2%KXqJOkOqhutXpT!wT3_SMdnNbauy@R^QN2FJ5n>ZiI zq+{{tY9VAhSH3PBt;Z%Fb+)ag`Zexe?SdX3fdKAj!eJBsp|{oK{l7O&3iF@4xK&{a%9wD32?QMP6&!>v*)i3%D41(@WHV$L4*~wG!6bNOtk8jv z*Lf{Ze1LHEBa-+f;PVcCrhNHabYV<|@xH@cDVDg$!U`l#AY16Nh!N&=Fj9#h);2b7k*Yoly`1_h` zBN@b9ZFj^gLL-m1&HgmG$J3|2I?r!W6RVPp+|QTKr;B<8KR|wt;3H4Xb9wj?Y^1}B z?JuG4QV1E#w6#0eBS-~ylL1wNzL_91_+Apqr+&}|+w2B_U<$avlx|iZx@&^2bWo*0 z7CumG_Twn}s6YX03=)PAe{L6w%k%!I%yUihi}gO#u)VWI`@M?Tbl7^|9zer{-tk)! zibMEZA!2>C#~0~O({p?eAF`fy(^IRGyWTk;JCA%-AXQmo#KDxEJqf2VHI6M>5f!^hxad#}TIYMYx8N56pk# zntm76w-DY^-GrNT>o5_YjnDu41Eh)#Tz6>9;NRc; zPo&p`fp!wrjN!JL85X#OpcMKayq0%KEK7wmf=(UUvmw-Ue?ualJDlZG@@NRL5~7{^ z-qa2^L7D~27@?5U&AL-wH$8alI6A4w(X7J3?^H>G~%!L~uRZeR^PgjYtU1E8ioMVFk5MUDWr#`Usf`3G|0uap94H# z^_ykzGjc!9;rz;Q^Lwv-R(?`YEM>V(7~o>1jNRtG3upoAnvw^K-v-!sLE~fgt?%R` zQ;c@{XiBH3IP&e-ky1NlHct+hc!HPJh}7xFruYM=@m}itNbdJC8*~W+GiE@n~ta{nK9 zZygr(w)PJLf()T_NlSODq;!iQQql-09nw8Ww@8C@Nq2Whi?no?NQ0#MuEFg-y3c;j zInTL%e>~Uw4;L^qYu0zIyW?|1$2Ppvt6tNTFe*3^dbnYp!lmsA0k;{$Qj_mi5q0S5 zi!VwpU3@|z_k~Q|DlV5tDQ&I2cwD7XAw`*b$O@nXQpkt?Sw;gX8aX|#`y1v~e>h+J zg3Lp#^w(a)0w>sv^R9gK51*>I!5ZI|TArjk8tA?8>+QB9Ii&@R_nF~RElE_aA`3g~G0b(BWdBik0F#$gz!kR89X zjvg_ZOXkKm{paz|Wa>5)Ym2Z5>jZx9e8S5O8Ig+3^dB4nK^5TW5UmS{L6f<{qj&9`4F zES#pT3kPkAeq79NA)`wQUlfsy2vbO${>?=&em13Z>cW8k4Gg?*`%;ud&{qGYLNqoH zA<>m~wD?%-Q>A_DrmTjU<=er`2EEG)T7(=1J`A-W8XUo;1treXRAZ-|fwfR&1s(|E zZ*_$dKV$A>zrmhX4lmga=EJ)yPYD9V_)tCQ!7-?7u$oX@vhO*sIX?zCe#yEuNRE6` z0DTCvb0i6&pwucLW}Be>a}yHu5IKaWPJ{ z_#zlTyhRaIOda$iK=yFL_QHe{xh7cqk)1^x4tH)SwqyEQ2eRGZhpZPg z&TOx(hB8DrQtXD7MT)yakzL~oSonM{*(n})Y_z7njH20yG$y(n2zptRg|@HFJ{8== z_^xhfIrH{C$iE82ayKlWZ|YB`;~<+{UoL@xzlq{1rIb48{ZgioJ;#lTGhoE_Ljbg|16mn47#uHwCbV}da z&@Rj0I}MqmQe3;K5d((Tlwi?!fBztcalB%tsnd(ez2UW2Hu&gZ_1ZmvTN#Wz)XERC zDMh(^h>Jmc9%R|1ZT`z%*KY2ORI(K1Pza=6o`Y(-iT4*bi^`Lj7uWUB>OR=mK&id0 zi)WMtH}gP?&2^znJ5D|QrAi8F`5H$QzFWW@`iv{cMrO377DxG}dhgnUF267e)XfC| zCmFtc9HDUgn9IYG>?X}K2!!4{gPI)eW6cMY{3p5OqwCz^w8;ddcZ+vNHRBpE-{-}9g~fuCeSt2~pxe+T0aXxPVuwOveSJ@MV)#`TAYTjC5H zW$=q;Rg&4~E6O$-iEd~9fsu)cAczcqE>PNJI5(VO<nMX#{tB~DkmIP+ zpfz__mZ=aoWydZ=M={x&46E_s(Y3x_0AOq;nbr4hFvy=QIedbMDQhwOrW%#ln8xOX z^HE?7h+f|RY@_+9*Rko4^g>0&>4^SmMz{0Gd(DT3**UNx978J5wRPvtjp99}#cSRO zY_j|Gm31w4b_7!LE!i?)l31vI7X|q^1wgwDk<=pB|C&PX%x==#QR}L?cT^%2mP$eP z#O`FvT)%{pZ2V^WedcB^cxdWJ5;Stu9Z)6K4+ipj51R-N@jRdq7LN1MkmePWDUT#) z+~@b}060=%624#6jXCS_2ALXSt;yMNFli|Uyod~OcD}}FT9)cLu}RnaH#kKV>gp3| z?+XY>J%f{BLMDAHfN+S{27jN{wRA7M8aeqptj(hJP)v*bAXAqOo%+TU&ZFWNQng71 z(324EwDtiXd-^%Qpo;2r3%-7~Ie+)<$XIqI?(duyd?a=)6$-8dPW8snJfa_B^>_os z^hyjwL!@!$%v3OGlhmcA<(?*Swa8LE%8Y*7&)bX)A>yzJI675WeN|?`s6f2Nw;Nmn zgywJU)PDhgyed(sph6%-Z%w?{=B5VF;HFCB;*CU!jE=OdDj|nkI~_OwUYVZ_pY;?A zeAAGCU8En82RoFtb;10X~e7xfJa=Ky;}jo*e7e6p9G#=epmONyfaIXd2DoVnj3vHVqgkC`|yS4l-lk(s~@V9So&XV>Tv{tNe^W$@g?_-FV{811fTeH(}ods^}CbZM*3#nCd&N+i_E~H9gxi&S5DlGi5>tp}1$Tk#CG7HvrQ5U&!>m~@N2?)D^evWJ=6f8VJ0RbM^kdbYr z4NGREcZS-<2TZzWvSq*!|5!{MoLO+SoW)gMi5zVuzy&ezUcBPjC|<-eyL#J6_!t5j zvtoV7>UXe4SHaxnuNalwC;jxV!U#ETw;qoIP`@`$0#Wm`=?_`bp64XD**-7)mJu!# zWZ+>VokNA+JXmng$5C#PezwgReS{(1=b=`IMy5l={zUX3Qz1nCW7q9|fOr!3LFOg< z;!c~YmQAO8^%LiP>zSVV=U)#FvYl)8%m&PrTIN85-fN&CKj0RY?s)TfG(?n~df~YW zWLJo8px5ig-8mFX=g}A>&KC^r#*WG`PYl{^-LhAoXlMWT_K@(r zIGiuh+Nn}9N+6a~+dHv)lKrqi&qUoV%5iCReo-Kb&x+pboS{H>#4AlV7G(hlSu`CF!-H_>(osh4uPas<{QbK^-hLA>$fBABcb_kl2qZ zp}07?Ywt9k=!|el=)STsjfcg-7!+dLJ#ukZn*j%ID{F($`_EvjCFdzfvjW72jWYo{}@vQ%V zniNNgyPN6FoR$T47IPOsB_7&QJT9KUe*PsP`QUPL!aTQH>U|-w><;NbNA{^7BrIP z%T+cO(m!w}v;V-Ed|OlvX4cIzG<7iz{{)xaa}goVC|tEbmN?w)y+b z?Kk;zNgXNofMllp*em<<`iUvMny8y$fbj3E2yx#*n9sR3c!TKo2mLEoBIRg*qE{=D zLyJe73-XPygeOPvgxFvyB`fSwEs*Z6R33r2*u|3zs2VZ8Hhy7e+}` zA7GuLxYVg}%&kc3g{%sM2g_xeQMrJ>_YzJbLHE+#Xn_@gAok_lqlYFo?gYR2odcMF z*aLts$&<_6!<92($ZUo_uG}4ko71f`_Zz(Lp%HpZlQATCs#R?YtcJJaHl}b6q7!U` zx~(!JSXCk&M=8ip%*nvg4K>fR!UV}bje?Nv2ZkG;7C|1wZ2Mh`yXw~sT;8t0F;&e0 zQIU@|0BVxIGmhKjQO*k!x?W&zvNXL08QP*Zw;R=OX@|FOssC|Ff2Ze<5E0`DI-aAx z@Fko#@Zjebz@5Lg#X)}w%O{4I76ON@2e_+|{$wunH=ppoYu^TeP17@2S_GG&+bZXc zgX|8l?Vi+F``6Y1kb$`6QzvB<)%Yb^wR2L+SjI1Ye+jC-OOl+hnfk>IOW zgVg5=tVyxm!NjJwf^s-5tduo?z+qhX3(yImI-g9YFTK6CVbx56IGqAEaAHx6zk_`S zM5^Bafcy^vOeG-h{gmlANjvj~QWJ2M$9nxG7S*M<0Qg>RWBr{;!`CZd{H(OP=DNW4 z2GIH88TM!U;5H3*8$fa9^o8f?-XaW(^^L~OInr1F#@Xh2G zYh8EAr04gq{F^9FY3f|pnqkES52NSs84~9bv-DNPe=>3-0u&61yU6B}NeL@u`|AFR z#-%f3?7@|;ts{YVj(bkIBCpOR(&f|j(Bt5>A+Tvtioz+V*f+h1^$=sz`dI4=wz(EB zLGq4T{TNK|DYqCt0+nJ8-qAL=YVoHB_so$o$jouf)sJZ1!nhX;wICJt^P5y56=F=SlZzEPPb{Q&I;Gnu!=TAHYQq*;t>`P{-Wgef);n zG`6?m?UR*S{^F){({1AQ-HU(g2@1kPl@)k9$6q!S&^M;*g$`c=9MX}Vr#uttjt7;u zmpG)}V?328XcsnxG(t0?!bMo4l*K5EL8!FNgV5p(U=b_T_b1>=*2I;+(7*YL{BU0b zpiLBz*Os!5S5Q2lC{WQChM1*G`10H#Skrk53$dBV&KJz?o2dpF98W$=p#jY}mF5~^ zs73%$Skez=5Eh$4xj(L>s8ziFKqzEF?F+}uySmmCFkN7ZMLFe6sX4w_R}YG0Iw1tc zU9GfS!zdWzZ)OK$9(>3xFvOhbGwY*F#5x)Q_Z2p}@R@VG>$nw8ER9-Rs$1b!_*^XN zWtH@_k6jxdyI-c(-iPJu>qj>sV9^Z8dR%IHQ|a*Y6r`WAv^HzF13P|dh3Vg zyWHd`CVbn@1y<9UBbpLkr5la7mJ?Orsr`+xB!L#6hEulD%sWpj zkvr9C@fAaE6t1wtL$kLo2AemA>3}yFXbsT z>gZCFxUo%OnsT|ddVlNf2ZBU*%;P%g&{-u)?aC&N6KUuN)BA%7g48KQBff)3&@m#@ zcX~qDtj!((#%g$<)-7)I-I9brDR$1-2I0G0rcf{-Y$Vj1ph;)VnWq@RR zW5(%mQFVI5@j;*K4PV#hXZT#>I<6M^QYEhOhB`1He|v`HkNL64h)DqSb<~4-?*nZ~ zRU0CwsJ0Qp6khLEmXxMXw-39`x0mFXEuS_-kVy^g<6VM%j+=fk7f$s8r1wnz=qX+g zQlB8i0z2zm5(EQ_%tu0dlN}m2U^eVZUwz^oztfAv6Uto<+LUrc3?_BYWdhbG#=g%M zBPEo&jhO{Lcs%E7xS%XmLZ+AsCBNSkBi?wfgckL}zseSL7ZNFXBhgH?!lI$nH<`JV z$PZ-W@8D&B1=+z#O7%>vCE&}B4FBvI{yVE@0|g?C-J;C1#oRB(c|Y_v4{D?OAbPaP z{!Gg)%)>Ck@A?*jwHDH-niiGOv#jIIVi^)i9rw@yu(%o*LEsR<(!$#oL04Vp)#x73 zf608~KnMU41A}nlGmP-FojiaB``DnJd(Q%^>5@rP=;1Xai*7h|Hvf%xLQy!;#_|=7t8d8XYR(< zL;n_GOwn3W6t?crRuR1C@vIQXihwX=8dyz*&kNYJZ94HP4VK&!FAjKA#={`tr9vT= zrSIG8(FZY`SXHj8K}edKdN1f=U}=?Z>?AAW#(Me5rLxn~xx_G^KT!#OF-9Yhp~WjG zqiXH!@xvjhkYLUeFgsx2@Y*nmi^3J$-Ble59L#J52}etu z7xD|7&Rv<@uQOQXNtR8CI!&V*;%g32%mfrtk9vJlnMz$7Dp+v#U!87XB$a}t+SrQ6#TT3I)>fcjb)Hy zlfYdkbhvXVT=Q_@Y(M0a%#`40dq(_0_Nq#SxyfSfJPhzw(o(-I%0=9x=5;4$@11G$ zr%I(xc)>V$uqf>yT0Re^t2HlLk3Y&Y+KNL|Rv(SWOSQu9C|Qr4Kz?j|T$)ay7^J2~ zvMCc%OLn*6gb{8_9m79(jD(&}5`-Wk>GO*#8yR-8h** z$3wk=;-NrhO(lm`s+x&=KqvNG8sIazQ&{wDDgDV2JMgm$fb)MpIE;$0z5oyyraU{oU!`03?37s-I2-XovKYGF@AsK+!8$ zje8o#fq@l8?z{a#6TuL9%{RW>54V*M`*5n?Qz7YIsj-g_?}L+wV9~-sGtT+IbQa0l zfR{O_4V$+Mbe-?vhPdw}AG1VRQ`+n02A6TtrO+Dn5@ff#;G<4PNKx3;+&yNOPj;t^ zkI(@VL%f~mjWd~5O`Mk&uUWx^F_@W!_9f#8P@l8s_l^Ez!rPr0kbNMTp_quM;AvjYA3<^mi21B-XA~M-C14<>V?Vmov^t}9v_}2dt zv)jA@sI1XPax`G-JxEz@5RD`Dkv-$R(mEM%9!C zdDlNJ5MkHw?o4IY0L^rvaV>~^&U(>Fd-R{XPzxg{%XZKt%yD%nAFxwOyU2U+zkP{v z#I676YQUO|6SEe3ptn@OJ*y?o#mMOU6Q$WmV-x1{`(Sfm%Th+u{`#ph)f zzd)I8l||67xZjQ7d8WqgnT}^N;?vbj*vt&(t1#(IopGKhAH_R2G3$H=jx7qA0!7B6 zA2Axgx~&|J^s@%Gw|%1*4Q&?*>ph~hyYBcxXR4VjU_dIl^I>rNesWGB40QF&H>1+_ zX5NZr^)L{>_tB*vs9-1{7r9&}_L0c?kGv~bi;J?rmxH=C=B}oumL|>4t`0%%fINd3Ouf8f3m)HS$L|<^Wfb`S&c=zGzP-oDJ1{7NAQeM_mL%hB}V1 z+Ql&=*mu^*qymsUMlq)P()`J$7$~R6{Cw0WL`6u$Cjdjd+q-m5|FENaAt*K_D1L*E z;p~ia^{~b~-&9OL;dA*rQq*IdCA=*Z1x3_if=QrJUghBQt0x8uj_&nqG~2X^C3BWZ z#^RCLA~Y+i%R##%q}W3Ui+vR(=ZYJ;-d2xN2AGmip)r>T=iE#3r}yEw*DdIjFWkF? zY6B4^nd;6Qw}J)C_} zG^JlsrJ;S z4>GYR7lfZ?K5rY3KE<0y&4Qst z&!T14|2dTUXW^JIKh=WjUOT79mgamO>CzcI6cMUsjYy-48~xO#xH72=4&980P)T$$ znVcGx`Qy_Pq;}2zm*u z>(XxD*R|8Uo?jv0bVp&XJAqu%hTQjD;A+B{fc+D70rpYN6Y1cQycY$>iJ6m6ss|F;0Xzjwwy3UB2q@-HAg zAnSaAWWf+sapLSGIJ5p$b~cE{{Ch(V<&O-GjjqX{cQ9-a9u{o?4z@#3LzfKl64JX0 zipfQyPLPI}S$cz7LyRORZpQ z`4NE}vC!ruYecHgefM)a&4zmbb*xZbJ*&q|B~yDRqdN9w=j~*?ppWt{OCm3OWSC19 zzIw~(FrQ%%-znHm^&)x6v-~iq<=`NiDkxJcDA8*jRSnWc0E#N9>#g|Llwt7xSxbhs1f=px={OPVC7H70`2QrFr*|oa&xOD7TR*_L>HhtXhAkePJwST zv#L&;xeW&Qb$jzC+!u5?jQ@Q%7IR3FZ7;(Yv|ztg=BS$K=nd~+6KOF_+LBM+G_(W- zAK70`zxVF)23n}H_AG=uPa9HSChIljj}lJTx@vtmBsqG!lB zBhh><;63He|KdDS$VW04M!DUw)H}a_W*pv_3>%o&0}TBw+I1hVGK+4UK~pIcGR5Ag z!9#sb6=Kv8^JAC`Vq&Kw+EPld^d>4bSsU~^uw^VseHt)-08-$>I`e;5!b zhO;80u@oX0<6)4e~=$$r|e4aT=XYThFO!d%7m*4 zfp9yvr4&A#cUb$spLX3(7{i}=Qm$CBT{TT>R!}Nwe7V!qavKBn)9808GUtw&g(VKS zyYJOKOdMOcf*zjZGvq%+CkPw~DycA;`KYWbn&zghEr}0LFQ?Q>B_91K`++`D;GJ#+ zJnGc{z{Ze7R7`#Ljlim$UIhkKJYpew(`hp+wx2$bX=+J-vIkpD$JwY1bi3FEID(SG z(J=R>7~Y5PVSS``4aDU?K?)aKSISloPgN}A&Fq{3!AC-`A)lvN?2~xK>iL`<8E2xa znw;q)_V_-FtGdGhiaaoet@{MKPG;F3-9^kDPJNiX#Q*-qTE9%yjIEreTHtb;b$I$I zwj8rQ2zpTl$T+e4<3g(gxv3OQwsYmrmJUuTmh+}CPX^AJgT6X>Ex4~`5_I_-Hi%7& zT$19(`kt>Zb-ac3;KSehgq`fZyR+TWV~BJnjivi4%mf$f><8AaZn8S*4( zUc&L%rjVE(1&s7;{8MhbNleErZ7Y9QRiZz2$v;OVg!8dla1hNfKqN4aDDoDstzp}Y z20e(SKjE}l66g0VWe|`mQHAQ+(a_3SlNqTKR68|IndVQv1^J2Tg5alG^ti)eS>|U; zc6s;SMc@UE6gPi!@$OnuZ#@~;v?^pE1%IDEFwy`j9DU!ew3jiT8isjvjjR8}Zw}!e z2sNMNNQ~7YK)g5*Y9ScQ;1nJGKYE_FlSf)qO}=Z$-!oUb$2Q`po@BwQ z)7QSn@M|z&P;R;xn(UyZLcG)jhE$asg3ut!F6(%z2N>06@AY)1#)dR3kyo0E1y=^6 zt^a6qrU}&a2prqwycWr4ER>%=ATOSqA1Et)!usaF<V*8Prvsrr8Nx3 zXFC;Lz;rZsW!7=Nav3D3`vc%X&s{C)GK#~;P=wE|#I z027rb9_bw=OVv=$b;kEt4|uOe-Hz%Vx%r zqMRK6wEyA)q)(#H`Z+rrV*AZSv*S822F-E81r7o{F88He8_xzC?tcfh2_K8;4y#4W z&1E&T2h2*JRGNMFtRq`@HGEvdEr9h^F5R57p zRKF`IIO}0Pwbw7Hzq@zhnYEd+`|X=n6G)*Rfl&B!*idVOZeptj{Xx|xlM&i_BCh3k z0L4RPjaJS~MX{Y0x(u?Rqo6t_+ZT;sYNu&BJ~$v=CYN!7lIn z(XEWF*im@X)cY?C0NMg4mr!PQ_9u{a9ETN*>&lyTg^|v&CTgg_#(`hhn9PY8OC9R) zaJ9v)yn+FWaKXi$q^vhS3(IhxKZ_YY8g%?_t@UNywY$Trp}2mBk6)>+q04=Kz0!2- zk*sXcz~iZtSG;~}YvEg6zdbdk^UPR~ zy$9z8@tuliaeLH;PL8LpX_;S{OfJu+nLd{iMVJ+hT3&BVgm%bVcjk(`&AD`HCk>-HXwW)W;x?Im^Uo-1pA5Dx$aeEymdqKu&k*EQY#||NK zvoyBm*cIfu78K6`8-dE0>&j^I9pRXaFQGVRHu9VR*G^+jEZM{9lf_7O=$p?^BhmWJ zacCz~Rq|CGBBAj_ZOY#JLI)KpAHJrFygUL8xzi}-#`x&3AxfnN651~Yc)mPSTkVZL z{5)RoXyxiha_FoV78-BTO+6pC-5(+fy33nD33}|al(L$HAXYGh(8~Q=f_9s-zQ)Dc z+pZb^-t}y&6m`kp7#0)q0N$Uc^XcB2H4ELfiFZ7F)>~<8Zf^#raz9Pa$0$F1j{hfr zw^$+Y@=keL=73^D&yC`5+nmiR4b#`?Tl+om0$&E`&%)Trbe^L z*-PwbK4DUR8^4(0usy~3@(UWHu^%SaRyzzucu-yO!<_=AcrRz&I3g~2(NJfLyQZVv z3bc&5F=Y+@@?{+fJZ7J%bKbw#WmqsKZzATYZ1O0F*v!Gckw!)t6dct2u%Aco%t&o+sC?qwo3j3jUCs@Ho=VhqqUY zbn+OBLsjGx-@}{v2VI@qlA*ZtPb>g$stB$vexu71vd&~a#b|P8-g}{bN=&8tqiS_Q z|AtXV(Wt4ZKVD-DzNUX2Bhe841(ONK%Wyd^VlkO>wPB%XL)RBbm#o@#QHHUPtiZvJ zEC5r3?nTxaK(LhspagEoLUBIfZ;{Oixv3jH$<*D30Z+Y){?{ z8<+gH4sPu7!f$ICoU?I%oc`d9zH#*FW==}j=?ob3D0WRE1STlOyu17H^&`n-AN9-Q z((Y$dXK@!9$51N6@D#jgf-a#%uqz4BRf+yi;D73- zpIQn^0g21cjm?fjM9CS^_^hqX8rvT|CHF+0IGe>2j|*;!T0VqKa7w{^b0jA`Pp!BJ z)Nx5zHJxP(@V#aTpXb-^Hdr&p!&QGaW6^MibchK5ERn2u@>te7hy z`|K&Z+I9*6_dOc=3kZN%%W&r+G>!?p^c@_yye;ro#zcn4 zrfplKACmh0IsatGpO2X?o@&$=lNDt5`D1BkvU58(yX}hf4N|^}4vXVYV{%~kMu8_x z=KfOT?xPA}AL|{90pLB+#aew~ZQdntZOJ*+-kod{_oXpl7Mw%`3dLFAWzRObyYkBz zjOHpO@H-Z{_cdG0H@P1V%dxHM4lFk#%{eXKV9~A{-2(Y6wQjfZRW>)vHG)Ns-xa>_ zJxByQ)=jBEq1*q`7NEeSK@fEPQc-NDGi+@JXeM17^#5j9&elagCoeCJ$7)N-0)l~4 zt<@8lQ%3+{=lRxnVNhV8QY@>sT^kDB256@p12TGjkoGN88bz3KiXFehhhRi>FCvAsVFyzS!8<+|~=if?)I~l3(k( zF_gJL{O1|}pdE+}xDwGzxFNxRcO^0l`Nd7BvNbTnwx0!87Q{Uox#ViJSmQO#nLT@N z_&&u6bBBz(c7H@HFH8^f9oZZOn%HW--(hlcl3E%UDQ1_KYdS1`aqW2uKRDZ$%angP zTXo1Di>5jWEnncjW^p)#Aqu_g9*M+A@QAW(m;?lB=WjCX1~X{nd^pik64Tu5Hi&;) zTJal#+lcD7E-$iwZNdGESG`h@q~rFu=*KAk^}YYkuL_@`0cQUH#U>2CYUy^Xtt&iu zRjc$<1i>S=X;IM8^`tTA6MFgdX~xc= zZJGn&2F8zfP%=ckdW9AFHC_2P`&u{?B0hV!d?!j!w!T6tljQ!=Uqm0hZwt_DJZ`6Z zk3RRX{{Gn>q&ZL;8MzB4fB)rT5!G87!_gFx5&Kj4P*cF z1;1j8*xyaOeP8kN&KsTi0toc?002UQ8G2BnSqA)-*$XK433J~-_^b?LiG%zrD zoFyAgQ7OswV}CwXUhRvZS$>!we1rl4kx{LvASo#c5&))s{CI2%bp$-d#}HNJikC1B z!CXZMGu;n)8*(rq%mBRkHDP||+v5Y`&Zjy8sDYqeZ}PgUuBxb|U#un~5VfWxrtY;XNV z#{KOUetS&tC{SU@%F4=f;O^Mg&pI3f#dqtDxjIEcx&k65x9O64peV7ozn__XZnoYLD5p8bJzmw@UcxJ=;BafZ zV!8ow$|6O+em&Og>8TBpSW1k-AOFf>e_^=a{~V&-1Ae3lsD_pB69g^Bg<7>`-4;&R z@QAnNynF(?`I5z9^xeJfz(hkMaq(qa?AkwB2>%c}|NI*?fS|j(`$GU0RoJa(mX<|+ zH%U#y%lSXOGY8CzMJe1SE>0rp{WsSqs=ELH*@r$)mfM3P_4jzT`MZk3goDPgXnyLz zdHA^SNhN|Jzsm0yH^jsaAmV^s(WnmR`RyzR-#V_5%SfFtHkW?k$`|lY*F1OM*FSt0pc&9f*V$iDi5jHV)3V?x%Fk zmm9xI!M}==zbDvq6+qw51rIuae8ghXJ6L$6tZbA`5F8#J{_!3P`rm)(p9%aQ?}Mfz zO2^U5`mg`1H~r)7zyC(@8Bw)Zr;tUnD)&L+9a9jT{dk;mlgi7>6EW%ATfZlNyC(gU z1%Ltes92}*2!!778Y%yxFtHd*9JZf;CIu^51%2u{}@(AoTR~e44H<1|gLtiYnRP zt*(D(egEJspBQ2D=l1?{SF$}yr3FZ99v&4N8ylm-ps)Ws)_}-C?^sOb>Nb0r4rj`! ze@RieB0^wrhf`Jlt~-8wH;Kdoh^LQ%aC_lL^`=NZRJ?~&zsLY#AJhuV*{P;I6;V-9 zA4zHT-=u-?1|$hc=PT<}yxOb14!f4W4kdsLP*wmlG&7U>1|hp}U|?VZr;)57k`(uE zAO6qI23NU7qksG3f5Ff{$s0lpGdb22hm`(ns-rIgblVwi05d25hB5ww|NTGNgjc&o z^pa)2!__gSvFQnoj|>m5Sl@%G&=0%pg8zlFMga#b97MQi#{V6e{dnTkOGMQot+yZw zmk;7`reJQ?nY|AP`lo6kC9O{Jh5kxNKW|$+v<1|3rjiM|Y=9o!kc2oC+@BY9wdfw6 zdZSC_+CX9sAfNd$=D)0gD7*mjGh-l~#r^Dk65OZ)%t~Vg&*0PdDm~?&=}R~c4fxfo zD=XbIAYuQ@-9ew@I)OPIcAz%kInZ81ghCvD`6?KQOUaX<^N!<|2LbsS*;RO&oO;PCO%DGXX=C9-4X4JiXhV= z*4%#dH)hV?KF%-ug~Gw&j&P6j{*E;M?S~I=)Il)tj^#}5m+k3%5O-XizTio;| zH*U3WWc=r~UOnpwc*c zeu2{b=^e1B28`Z3aIE{Xj*{H@BHmSfqeY&^Sk@im5lgqamC~TNnoRdX zhyMt@D$z#7FOL`5RXdPbGx3hl#7>hMA@~G??-Eb<602n7dt9BTY@ZLTF>fmDm(;X> z@E*M|a8wZ#)qiHihp4P6=p=}h3Fyae2^dD+zPUoJiGs~AZc#k^;zaXWkk-&kkxZ}? zVO-QW!$3xkvBH(Wggnz5+4l1t6IAZEdXV@s`-H%r6jKsm=g7!*H^qWR z!n{0^s!H>O|0a!;;dW#JqIIB%puXL`O-9&>*up=P;9dG8jrZxv$#LO@SRig#@AgXW z&_se+lWfnHA;ym_rwg~N+-IJAliyiiww)O;yUDs;g-!iMy*d-Udbs>vY>;;>JS7NY zMWH>ekW`?3?2ua(EufUsn?{ZLT7F1~QgW8~9Yffbg~SECbgRhvJy=NHa``oSjUd;x)HMo&b$f9D(*!lQ%`z`q` z2hynaCl9X(7-9u~@{Pv!@qI~KBh8d;B30WN4<;qnp7Y5P_W8S7s!8MP&E@YHY)ARj z6t-v&%b`D>Q5YA^P~-K^z-&U{TjFvaSLLur1swsGS*A#DV|bjZWN!E~cJe-^l$?rQ zQ~ml$%U7ToFC3f|)EY;a+3vE1gIYg4Ex2-uiN!0^%igDU#S2@)s|@1letaX zEcpt{k;2we*T!w$Jco#kCv?1d710^Ca=h}9;^q%_4}ZL0JkX0@%5qCUGM;!vL6_wO zx@w#C_3Xr4ECy;1#gwXCUXj1oC7XJ0{@i(pQC1Iv1Cvt}Q%H{r<8K>V_KqLjm^`;P z3*#)q2(Ea$te7vJlQ3qRtKZPB5R_{`Bd>TRZ_?#js7JSFcE_t8SKrC1sbuXb9COv; zdrqSghi&$icjMzZhr>Y!(Ewwvj!NXl&7QscutSAISfm1S`;>&q-2DiI^w)l*{ z`9n}+c|pFvrrLCQu-HJpx!`F@V&&m!pS@RKF3zQq{+1lqhZcX$3=;~;p(#M6m^ zBwDji<2yd@)*O%-?39fJen>Fph6Z4rT1bV>smHzTUnvK%bDdP~ryg3M_F9-v_xwVK8_U_$Og3krK@FEh1V-^uQXQMo2nBKOAM zYmtrG!1LJu@bu~=A~4yx6l-4RXx!IrDmTvfsCUw%^tLwX0eQ7?GNGZMaqdHD5_&$Y zeT2SPwuxjx*HMu49($`yx3o+njOfi$Lfe_O*qm*)W4vX%sQUK#DpKLS2q~5y_XsUg05)LX$r8Kr|?iX6t|-xDUh2<0O^7}uJ`w- zgbNi}5QgYV4!tzlz9*;cjvMwFg+8?)+*NG8qi}3O+AfbhbYe?k0KTVX7vX^!?`VZ; z2&>>7$rpEOxS!e=sct)LuJs^~7TSc6ebSMzFx@|)Y;ITnBcVv+ek^ss{5Afv zJlo1$4(&_G1jCIY<@{4JETX$2SB?jwbc_85*+{2$*%&8@-bp$sBqpWwZ#?6n`PxX* zNv1Hdol9Un`niyBYi*`ky@)iWH~QeUZOj|0XN6n^M0Ck98MYU>cM-0<5DEdr;j$SQ zGn?$DQzkhL-bWd?ZoV0zlx)=Ge9j{fM$rf};o2Uis=dhRx7b&Wr7gDJoM5S~Gu-mH z@f zN`ygPz^fhHwY6}1yi>64K+O?qSygoDp3xB^q3>b1DFjXvlMEs3(|AAj_&}{yQFP5o zSoA%P*#vuo>?C{EQsX2-+RhGtDT*VIlmcR#5lKkHLD7m;AonZsY#uh9wu@-U^@`v? zSv2pf5*J95@Pwp7{PavHtNY=zBEi0)kmJd^0%fGx7Y0V1ukK=9z7!4qLqOdIqM4Gt z;E&Q6=m!GzM81dfRxUD=<74V(Dg`-~_Q-h}m0@Y~HZE5Y984Po9>!7C6u($aE;+lg z;(A&$*K^ZQox_Oh+>M%r%dQey4Tx9P;{pbJtnFPv+KH-H4o2^vxUZPo){{ghoM+g6 z`eBf!iX#9?jAu5h#V@41vo^6hb?iHH;i)2D&oMrjtxA&@9Qwn}gH*J%YHhyKK<2h6 zq?5B` zi2d@V8s$bC=c0|?#<>5m%pOoUHrr0j=xKMl`mGe`X}4Z@Y{||Mh(C$?VPj+ZA-q3V z>s30$UA1&m+HrpoRbEkSFzrSm6)L1pctiW@@B_r5vzwM*UzjGS?$|J-1&K|lm&+!7 z^pSItS}LW5S;7=Eh^#x<8AUhVoI8nx#cbPdM%rBP*b1vuKGge?Va*?NL~unO2Z;B~ zLI66kI3TN4Se^)$&;qr#4fL@Tm(qCMHby1~+4>3P%V;VAZwt6?X^WMKXOfvO!OFVY z)KjGzUyL>HSLP8aOT2Il8_EnF?72h-9t=!`E(q1kk-3>h(vXaWE1Ty$l#W?2f?nCr zj}VNjGCn%6F=g);K2pfDRn;;W5ZE`CK7RH7>Z9U0EyIGfb)&anpH?V~q)sLxlqwUq zYx@6qy6Uhdyzeat3ZkH-N-EMVDUFCocb9a7bdHHiOLq%MclSU-n$gWB-HaY=Z2YEt zzQ5<;A07dB?>*<-_q^vl=aT*_qTuNTV(^-;t7HbokjD@2IvI()P|}#O4sihPJpCJO zFig>3Q>~-2UBwi`iirCM2jehuk5InAyYmCjYcHhA7esW%m|4dU_i~4UXi+eo6Uv&|Q+9^GEM{>zms$Gg=cmck~VdvKElvI>r||Zns4W?TMbZT49m1 zS0l9b#5W7LIa+D|oDh!zYj)IY|5t(Q7IVQsrmH{`V?v9p$v?dJm|3$kvs$~^9_`3* zU7kn}N;g{!VC-ciZxK_$faP)Qzlu~04^oB^acdj3dUE)h{{>U2PdK>HSvk>37V~$N zoOhm;LO7ZPn7RIyyaJCNU)mQc&;tjw>|5&i_>b^lH)FPys;aqWf zW+c6ySuc90@uNYL3V-)5u!_71xQV4?l%Ci0bjQhFJItIij{V8Z{e;oKzputz<&kYr zd7Y7WQ0!D+xi%%crAcr5@`1_y+niDrgq4i zUPC9S>>#bqB_)&H#bMR!d(&KS*KWB&}r@tqMdF(OgXsqnBomZJ=@cb*aGnEtB; z#{8`uwm%EJo1bdl?ODqu;Vnzcfd4HtoH(>RXU?;7fmgAK$Vq#Y)&4>Uo&(E`Scv?u zAj=%lNg46_z#>e(dg3l%^+OUf0VDF?o+qSBV(w6}IVSB$d*M2>Mg{2r`9^Cc)<(i{ z?pya$W5&22DUJJE3{%%n9vU4DzlUkgr?8u?FoN{4(>->=#-xyu1~&<>-H3`5x{7y= z;TfL@0@1gcgc#W$2FtaU#CM1`3+&s@c}M>%CA`$>%xsWs-aD+h``z~Zdj>v=UQqX? z^gl%Ik4d$A8vtriyL|?{N>u1)6jy;H|L}^W51!&;OnD;(jpld$k`2h@>Qqieo@k3y z`fZTEl==!Tq5Wu;8es~EQdFn=ACdQk3A2u)GFyC%ap8qaV#JXA7X6P~%Q4)y z{jV>$QntzOA0IV-HsDl(2x+q1Z!9$$iJ!`YG^3rqApY|T3at1$b090hJ?kYxCCFKZ z2iXgq=CiNw{{;zb_LzF<=F*A;!fr`J z&=pCA*JX^;3p?N6>m=6;U;M)-l5{_D(zIYj%c<%0EC*bc8;3flyG-9SZ?+%)J$%V$ zxQ3~NdORNvzk7t+y4Pkrs$ew_+P@`gCGqfu*yd{$o8k%w+P%^;rlaEX)Jq@l(iz>R z{?>sBij5W72?c$0KJ9{St(b&?2(J9<^Oh{8v9KJyV8P?V)G%DN2!SF zqtd$YsLrt4O|-*(u4$Wd=mD+DI-q6R9S-e-_CoYH?R^v@dI@q{Q1nXJn-Hb$3zEST{U6Pe`?#_`)2}yCuE_v zzS-+#>^c)T%|z_1(9yBmv`Y6uN~vAPwL!r$yi_GrE7LBj>ibuW1mW+gsH$U~x`7kG z$(FV{!jp;#Q_%;v2${K}Gbg*LcRB6kyQ0zQ z7RSX*qqU0s7%?Lx;FMP>{k6fepXYQt99s0W^d@19qJLmuJbYtsKkE1I-$j5B?HuS1 zwr|Q!eRfikai@0KAlG9h*rH81|BVah;o7(GbC0(NX#Fbdw9SKSO~CVI?Iojm!haEu z6lbX!!>pt%$EPsfJPe|dQKTLAG1!D|Ig+vU6u*z$Wr*TnV9=VMfk6sh>2CQ{SBHSe zB|gzf-=E->H#CtF>Cy9;so5obmzj0p&mp=e3g4ufsWXXl(*=WqmYJAf8p=);D0lz! zk`m2gGt+eP=78Bl3)pF5xp0YrN07P?VBH!KFbLkAJ{1zX{1f>)Nha|b@21|?a<|3k z6(AzaZ8Sp$@-56|&3Zd8`gf^TDWmW9uXIfez=Mv^+cp0TenKYt%NsYtgDZ~BrzKHT zNcOOOa=mCCilidAy?{v>KG7|fdy&)D2{y0KgM$+rePZyqbk0a~DsDsSOjAz-}bZgKITu=n=46~bcIm1cvA4hUU#YP>j{H?NEei_q{N zNxKqc8DF~wunvs!+s|I?`FxaHuv(QXzlBfVt}Q_yL&U33R{!rhx>TU!w@*fYz!Vr<_&wfc@}jg3 z)b@NXe{J!fBeMyXIe$Ozbh^hkRi17`WI@Z<)Y0N0A+QeeHf%P_eE-m|FUovibz>Kj zSE?*lZjj@0{B9dB<)i~p)s?;^f1 z(>G2W>F)iDlDx+Abdy@R8J;*e;xTXFe|m1e>p8)5aWcOJDdD#lAgi$+(9Zt!mPzTU zpn71@i`!4 ztA$?*=#*{X5+v@KnN>QoDlPb#e1xp%{w$)dRvmTlBVfmBG6MGg=a1 zxl8KYuCwfe5tZ(7!q!&VhcmdP=np%?HV3DX7c^y3Cy^H=wxuZG#o~`oVS0+TD#7w<-SWXsVeGRhH&A z%?r)u(dcXQd=QnGo{kBc>s;i36;-`HmfV{&0nQX5GV1+3nY{rlKW4vo05Q~a8`?aW z`S{#xY~i7%^sn!hXB6=#-;OOoeLh+2A@_gPF^3#sPguB&yj=kpXn(c|uP@VPn7?US z0Ib(ksH2B2h~#T17yn%%35B28G%7~G^J1R_+CZXyZx?a#ej40e6dNGE$|md?wh1ia z1$GelWteAnA6AW;ChKlhWgBdfCmZ@kD~oTia&Y#(aWFGeqF&6;Y%C6gj-HJQtQhHi z531})&9W|)+JcXqHnq_@G`9H<)mX}8t8|LX? zCRDjYoYX}q+xz<#_$te?rL(n0MN2S9X0B4NXdhRxX;IGy32gd5MFDLYVRy@3b&Ru@Kg5RIID@ zK}_wTjH{*{O;d2uJPey`b+yc`xXT&zDDBs=j3Xt5-*yK3V-Lhdw^wt82indF^Whqizc2lCN66V^R48xzbmy4F%DYkQrcJyBm90}EpD3RMEc**@6gb}~JbFG=9j!2w zq|~-ZQ*I0keo@2SpGNl6x{{4=a|jl-kQeuyrv9w}o*$O=*V2QhhUr;}hWES0X)yW& z3^>3m>trK%?LLN(zuv!4)?&WYS?Kiqyr94yV~@(Zfr`L{UJm?F?hY1iuvR(WhngI; zdTJdY&Nr$?^ZXTHwcratiuL>}4N(+$F`>;~C+mDus$AH^eQBU@`{$%evMm#EzTGjM zreo**$mM4GwF>ol^;P=tP_!s}GMNrDDeqUKGLI$qWm zz1q^{$R31BP-O>FSZN*WhZD~6$umS+;^7E82?j3z`}jwdohz{(=y?7t*4{?u?Y#ev<2YlRO|B#FB^smt`u^HL&MNRRpQ!{0BBMocbXYTsg~`9pacmJ za$Ila=%+)`=v%?3RYipTf@LgMh5$3w+-K(F{OF5$3E?2gVjNfXgw}I1KOO7#A$cua zk;LrIr8hDrsHIoWhi}e_TE9{}+%23n2AmaTK6;ml%kR5T%(PRha+=l6$Z#+{<0!)K zwB!yr?)AE0zi(yYMu_Z`rk`r{8W=TIdfOSV5?L45LiC6V@w=qaq=N?6qp;JXHUObi zppxaf5@hX5F1-o4Hb!@!!TFYjvkx(#t)6Sue_@y=E-r5O04XDm&j3jjColn?mw+qCK-k0lkGg=Ve>=NB~KXkE~_&iHI97B>|p0>Ne4w>_!6}rgkC)jwT9Ag8B<<4us z;B{vBUo|2dh8#Mh@q2koi~Lx^je9L`ruKgU8DhH-}9l%?8sEw$)x zQNYoAzDC@agym;%LI8UQ}jY_}ytwRm&0D*mExM z6XeyAqxP4QfUT+ObMs0qt@2X7GX*S~8L9qiQB~mjMc!r zh*HzjO&LdW4=_sjG^8kEUhq%cZ)pGXP?3~hO`vb=$!~u+?>#M_kI#eO^uIFAB@NjB zA}NJ!o#~NuD^aB-lP^w-vh;H#x4m)e?GZ%7 z>oDz-+si)awqD4_2R-h)R|@(8DK6VWN$wqA8U%U$60DD{*=2ffNH-XGzz)wC zKlgllE*qK0PMI(ZLrxZ4!KgZ#j%C+i$liMV*#oL$rhc{Z_$9s8b!CIc6{cg(e>W)b z&V!T=oZ*E8^Ttp53c=+#F$*xQO2ny(bLKMgf`d=5t94wBJRnO{k1d%>TxVydurdpI zl=n8C!M~I@jO2#qDj4xdJfq0Lsv||vJQ!vb#F-s%=mXiRdChx%LLZ&5=yeE*`Zm{f zO?#cqz2cd8?Hr4?U>RuErd#D=O_I!}Y%WXHWzOLmTSPSL=1t`2F~;!@!kxErDrJcN zV@^PKc>jlk{-)=hU~GF0BBP)JrN}juq1(q2dq`WgF!iKz#|U+8TBAI4w^u zeLu46v-_H8m@fX=q}5)#SH}dbgBtC6eIO_SKAo#w8>$pzbnBhGw(Jh(Km?qq=r_36 zW9Ho%H15YV%Ug#KmQUrF+lzR*X-!`DHi?~ImO`d69ad8)A~G>8S4>+Jjo%qVet!NU zlHWmhw&6sF9WqL4Zd%75@vSh!bvI17!TvtK(?q8@nsYB=weq*WHP~)-zMu-3$TnlU zZcpo%9k8+?OGcq{R(W}KKttskvD{GH10}bb`3^0E59J08?a!t>`#3cx3@XGq$nf9 z5L3h~@;$dN1%%8z_a3$Vn=ucQ`4g~OUJbJx?B(%Qr+v%CU$eHE9`w*}?&@igB4h2* zGJ6EU0O#J562@0HZ7UToNGB{bKW3H4JVxnd$4ST462byt+1=g60OQzBQj?WA|M(I zh8dhjS#WnJWXTD1Y?kS5W({-0<=C$ZfYMr{2-~_40BFWuIRXhsAH;Xl zVM~+Kwbs8nVCew?yiRH8s%rr~D2D^2&S(G#>=?@dD0u8l%(#l0SP6t)_g+^x6B}YC z|0tk#-J)&~{ouArS||WQb=3r?!f=b+(on!i%^ObW_w<|%?F=@>vKd8YGB(XB5P^*? zEzGlB|h&(IP6$SGqd*kjX*%Hh|gcenbWRfG`C=6sxYrOpve< z1tlxd>-3_&LJq9e;0ux5XPr&co59E^d8U=w4J`LDU5yw{(gj<=Ym4>GayjRtOuNS> zM_#E2L%{4Z!lesm11~l z(NY@J$>=+q)f8Lmp=pI=yRD>=g=)))3xjj*5`C?a#RiS^(M%6aBWwTgy6RF~om*i5 zhTWjlshkMbnz@=t<9F4oW|}H3e784K1Gs-qBc$5r4s*J3?4>pCD# z_LgU(Q)LazmDNZrk@x)nfiqE@F-e&}jh<0zb;!FhXtE=Qa`R@%+c+?7Q-?|^AC?=T zpo#CWsfdzib^VK7-^X~7>GoQDlb<|Fly|T3$pV>G$W&58+9wKJX5gkDCYh1@* zkLh$6BWimY6`aob=A~(uS31MYXRLVcV+poq)1FhzP}%wn$C>?mn-@di4*Rn$=x*%I zQpGQd4eF(nqp#q-y-ES+kBkK5Z)^Q)=-M}wL zzbP>CyzF?VZ;jufM_RaC1%hS67}oVLiw4H~vG-vY7^geN>gs`3^%V4IlodqZMA5Rd#t~_Ur1@7hyJ0j{#&W=N%bG7ylMYqoA z8-_Y^*()iaEpIp4|11(sc6@;}f>2ow?R~U<>oTd};A_jhnatOXK^QhK0?cT42s2NN zQRM|&p)dah;GflLuS#xos}Gmc)0l$G${a*q48{LEPd&f-C~lC(=NMxx0=*A%M6T6> z8xJM9X3JD{9+lKhU7UF=WVb6!uRX{L5XTJW`X}cJ?7}r<(IzfiWUzjF(^^mX%-&ZgR$tfC?Dxny!yTY=$H1hC_ zt1RVJ;C30>F9MoSLuVMDa;(&|o&ipKce~48e3q;57?OGG}gX z4)YHh1?W{&=0!q$G}miWv(-l4^RbvOKq$1vvT*nS4o%*TS7EX{?y5Y!tZV?8JQZ+A zNSso;gcF=@a>X{c-~19<_JW0uGo@^QrWt@@^6co3n1rSh**_0_ zLdWePokT4YUBE#3lol%|1b~-VLIuK`u*;rjlqZ>6ebb@)b+yskOU$QJ??TcA7H-Bl zWxu2g;CfnSYu-@FPuQwwq2H(1Uq$Vq*h4(>?D{76-sd7}@!%CcjBw_Q-1j1V)DiBY zK&4SBk%_-lhd!@9>6zDL9RO)TtUv6y%0xT#YQPWyyxB6a3>>n$7e8C}^KmT@U1Pte zow|4uM8JO)0Y0B!@+papp#%0fFFg0}mIzl&NkO6Dz6TOFGw61|Q}>Zq#HsJdRB8r) zg2gALx!Qjsl%f;^;QQP59bNL@x$#L%&@e{;H|DZkLeO+J?n4@sHXF8+=Mhe46fGOE zvJw87mxn{HM>xKGNDf$9Xe*Pp~ zcJF=+I783M^1*v1;ojEoxmCnbJ*5jyz1pfgyf$s9O>0P@@*yDCsjA}0R$kBiSX+NM zs9HN$&Z%MuA}kI{LuC7exBHLxTKm{nk!V}p90I7yaDjRcX%QXtaSRW90jcwZhc~mp zdYA5*m(pi_d-*@^y7xWf;Fv(y*d=6-!8V!};*Hp-}&u~S^r=@+kR zdN1Ek{s!G%h7(kh72h; z-C1M!(USqjJ&oZ5gM;j71t+&R{(fzcH#y@3pybN8sIUQEP>n z+ifj}KrVCc+Y7c8&+F%c&MOBs&AzDY4m74%GZExSd5RX-&cHefs&}dO$oGfVcy#+h zLvT51>xe7&1newEdOmp<2=O9+mCn#zd}6=xUzM9~jFT1JC@;*OI6PPsBRXA5Hy7MI zXl&n$61gHZ`qcgCVl6yCNa6#e)&Mx1UCHDG+6l!l?|G4Ff^hZ){6}sD%3`aq0x~uo z?RtM+x^>+xe#T}qTdZ0mZ&to7{l9!sRx7dsJDx#w(dV#Lw^kv=0$=0$Nk<{1>rhGk zHxSmg7HSbT*F+DF)aKMH6B(7jywI$|Rn{W9r}Vn#bViW_Mns#n<=^nOH(YjD(=?9X z*k|1|^&6SI4SwB+Pep2vLdczlwB9R2ekPCYvb5heW6}BJ2q7P4o6D&DWzLE5AJT~G z!VM-JF!F<%cgSiU>|eyX>2}17Wdy@odymT)Q4^!#8zCLsc1u5xO4De|tJhSve_}XH zT@%GO9xWb0!?RF-_1Y~!F#`}#2u)TTbB_4EhX5MxQ*(a=&H3$y%|>ZER%d7182y?g zb+f#Pbr#Flb9=uBCWG1+d!%13GiRDHka~wV#|_0tx3BuxKqb&q%lg%x!2pG$=9=ve z+Scw?$Z1=%po?#K>YJ`%_CGA=yR$RtFws02g^qgj8^AG+*wwIDiRR8H_1~c@u>N7= z6@wD3(p=2zJ(%|s(5U-->w%^|pljYmYYVEWuW<1#CG{dbHe;|st+w|)lVk>RD4NuI zo=O&~$2lt2k*)YLkcGp5f4bU;sDpNRpXL`Qx+dj(GDjjN1s>`HK=Exwyfrb|WX-)Y zF#)+C_s&-h3Sq83APRq^+T6*jJ^5Ob=*(5Xf^C5dXybMJ&GDy^E61_`BOzt;zK&uf zO`F`N+eX~b=&{pY>z`;a6|i00AGy)$U^RYeH@s4+k%|*}BkEEJ%0>sCBT{pFhZt?o z=4L%sWbU@LViH~ZP!E1X-VbF$`DJ~rLXMYilwfdwJ(3VCzXnDW->QTjVqPO?z8Jx% z&fPE#H=NQk`{9@##w27$w*be+8wX5{U3FPF#QLJjv{!{j5*5<8OQD)c)ZT43yKE}s z;GwNaHB-6O_2c?FQ`9V<<1XI7+g@H3OuvW2P*P-()5R(7;hqxC^ zQ&*PWctYGHAtB1i=DIat?a^Jj&oQqA#6!*QG0KTbyt*O9=3a^9512&p~16dWSp3UczexO z!>vuw+#ZKkDOEA`S&L74VKRjhX%hcB+=?EWB||xynJiut`WcBDOm}8oaTTTAKukHz zed)QLWnw;k-LUXWn;1lv8_G3H5aA33s*s`1v=jFPot0mB?0&FxS$KxQG7<+6X&{w^ z6dMtB0oi>bwT>6ki2^6chMSSpybAR-XtN8wBTBmC870)@uCZ?z#HcPM3AQZDMo9HD z8hDc#teEl6&c<}S;J6PPSJo)uo$ux9ZJ0M<>nyf7^*IKO0lR#F>Hsl*=UHXB z5x2ZbE3o?L3dHr<`SU->DY0W3};X@vj2|M*2RgpgXX z=j8*O@MKB-_ryjDqO!)y0qYyv25phmKQ260dy&&@PvoPr+6gXz4M&rL0|x96_$gd% zFhQ)X2>9C|ueajJ%k~`BB15qSHhN)fc(`2z{KHlV2FC_H&juU|G&k*f#nm-77GfwR z`H1RlfGZWX=%=@=zEDVB7nMtRToP^C!u7FaMjvP#Zi!l?LEvVNm+5s5n>lu!3ZzY!d#afqfY?}E-`&mS6Kh1;H_ic)f;fW7AC>_+m>=;R zk@nquks|q?Rpapt1hd>Ss>TK&t_;pp7dKsF+}Drpr%mPQ$ch!>3yQLAdqwfXh`Jk& zy(kSBV~tc}XaUHz`EtLLuGk zqGof@6P;hN2XFnWm8ipdPq3-wi$b}|6%?>yWxt7nP?>9IACKCUFUv$UsHu2;^pQR`|bt%9a{$RNr-OI zcQ{2rTgv9JfO8u-H}(d=uP{to2Nr(LSHyy^cJCpTEb>N#lixAgJGc{`AY8s=MO7}{ zS@4#!_{VTlqy?oAL^vpy^fs!gt9*2`Nt+6JABb>~Erw~n*_8~DrOEM-;K=67AbX3`rYE8(ehzZ zo<55{pT71R@kpP29(e_ZrvM$B#;B<6Fq?jOR$!2DBUKu(U-^Eg*8A9;z4PcJNF z#AyD3R#P_m=qqdW%j$N&{Jm+fqX_vH+AU0%L**{Vr|*6@cO$(6eda8{z^U1Z-@j*y zgx<2ub&~k41t$db_k{6%>KRI#+dbd49lf&H?TQ|lTr`*@fAb_l*f@(v8t_Fz%1^?6anQ~j-F?3eUC=0bL=(8m$#Wh>s}-DjzJWLV#-U-v~#N{DV; zeqx(y-;7pr-!V&3U*7j(vgsj~|8{hQeI!e>SB6uLHm`k^p^9B2me)sEU^PO?`s;KH zprFGUqOirTs@vcmNen-$jaG-#93-6PUR<}B<*8d92v7eMXT|C|4Q(p4h#+api(pSu zD`a^TaD`TnV0gG#4(hlB4$rk4J%vY@imW%31W5_{Z#TZ+`iqrMlk0ojl!acd*sukV`jcN>4?ldOOiw)U~DyfyWMo^Fu|5j4QnP3%hwbh6~ z-n`xim&+qthC>&gLbp%-&D*w#Rk@xkW<_y_D7afTWsU9+*c#$WkPERTbLi8&(tUsP zvBG*{A@f>tD9@)Rc~uFY)ha48e7D8!uDj-D_#Wt$?m95Vr9N4r0ehKZ33Bi)dA)8| z6*V}lxmEv9ci9x>i>C$2V4pS#1qX3c`8zzOZRgn@{pV{b@t-3#xaWm*a?1QQq5_A3b{$j^*#`;EJ?X<@FeRKh0B#kA~hz}@kL;~KJ zJN8(pa!4hfMeY>tKwHmOW=XjJS`% zQPg=XO!}6`G9-cVX7s9169+T809N>W3)T19)%2nl_# zJAW?ooM-=$yxjN!Yqw9I(o^}iKkZdUANWz-MiqOA^QWbn^LaXcCC1BV-PR3!Ii54R zuSOLu`(B3JHxP_fiKIbZOiKLRkdgRJ{_fN%nHKQ+>(Y{8{_9I&r2y339ew5W>l`z? zCf`Wbx36*mm)3O?Zy$V*XjL-MLeX*;c}1m(iY*r#z#HT*n1UqqPO9%z#bvm^lcC zkVfsIgw4N88E`5?-YHOtbY7KL8VZLCuBqA-8;VO z>5vY=gMvyBI!M@)M)7Ni;^eR?lMWx<#O~wV*SzkPANNu1iA- zuhXWi$-yWuBv;YtqlcQ|p(Hbp*gftVKbNY1zAL!BP`l&2s$%Qb&?Vfn9!(w>k)A%~ z-hf^6@#IwtC9O)fVtN54FNp0QnzSa>htCQ3xtW{P+Fb>{XxZ9u%@OQ@mF9@FSXUDF zIBtu7{NZZ6MANWNCqjPd?!B&d#W%YaUm2yj`ug?jZA|fS(8npOLCjZuV|UsuBB^VB z;@d(ouHx>e%ZTVZl%LBs%oXs9_1uLJ0mu9}{9h%X(N+1JTG@(w{<$Mi#CA8C#OO|- zKS>qXOW6YF)_wkZkUw!#;&aZ8GY_8jj}qCvTWpI!Wc2vg5oBs&ayjYuXM%HOb+}6F zD=Y7#q6ia`k~qnFBfgZcJQpa*wB~`3vBlKZ#@F<3dR{M!o~|d-8P-3}Y1So;PbR1! z{vp>DVYVw+l#jm_&#HCTc1C3FRSr&ewopKna6K?Mj@V-}VZLX-O9lFhf`TcEle}-{ zrEW_1=qMx#u~GA>=;nuUol7?%%Q7YbaNq94x4ZhdqaQk3J-N%%RKhZ zInNZqC*NRs6b3&Kc^{d6#$Q?tmViHfc39%9{r>AaRQ9$q?dXlvgLZcoL*0ihl953% zZx5#4hR2jhP1RV^d(^G!5EK|RaA&=jV;2?O(r9JVp)WG+&Tx}{qXg}1jSFd2*5nFF ztTWdw3djk7y?hFznAOd04k`JK6zlPZLcSjd&>t^-5%i7e#a;t7|cb)PmPjm_y}AI+kVwk}u7FiKJj zZQ~o(<__yeMe0HC!D$@$3{6!8Ov+v)@q%J?)%c7L(9( z8(G_2ks^$WO2|rL%#W>%7nauaPH`RV!jdgq^%E@Od$mYXT;o4cV6RgP37T>k`~0Ou zOQT12Q#VDG0Qhi`F1z+a*iE#aYWHD9RSCAv3EotZjr3L!de7hRp4d~}BiKOPtaKe7 zj^v%cU*S=A0^}m1`0cR&=NkQtF$n=7`;OEDL*td2JUf_7EHc26o8NJ!)9zsNzK>r| zMO-phklOb2UQfjP+&m|BdDjQ|1qE`ndhDk4@-k9rG{}m~nv49xVCdLM>dA_lyo&^v zNg>|d1j)P63nlkuiz&1yUy)&dqd9{`-Pm*^4%8Falm5hG>Ue7OUxP%0uLzKajvQUk zO5#irxA`(w9dt|e6h0$1_JaT**#+ulH&@gRZnKky?BPv49_mIx)pF0@gnZU3su*Nt zVPS`O{?rD7>b87MF@N&ipHE9it{qaaV2H`#s2np{j>XAcQ&+zU{WW=Jb!^)fnNb1G z`tUk^&G%E)(rgHyEB^@9jE=|hMlFQZ%qn_vOZf_vX>>j4k#qxVLgcrq6FLIMlyO@7 z20I)Q_8%W#1nmp8^Yoc7b5AcF6iQD$W>6ZFomy)sJ3i{xY*`IAzqe9y zEN-C3R@BOs#kEhYJzXl!Hk>X^t4I6+%vpddJ> z()CzPb5XIdVlRdWiNbI%bDG4pYb|&yeZPP=vESG-69yOXwXNj<`<|718aJT-@J~vlVxAbk$id2 zwio{Ugj7qnVB6q~ANBi#T?DgF{V$bJ8;hK8{(OmraUDKxisYl)KbZ>Tr43z(V}M-d z#2y{lz4PQ#kN(HNWZuCc$wxiNMg1>*8N{=&$k&j6|ME(B3npc0>N%^zZkC)eHy!N7 zfobWGn$HfQaeCjD-dw-5+zPkpJvpy)*m++4S;~Pxt%tMo3+}*--NFcEb(#$4fE>%} zN}1CvvD@As8JdEneK_M78X&tfQ|`_1%%H}5C$TW`boHnzF_bO&oFL>Sz4KTM1!MYj zLWclaf!DhIeH*2XtqYbFr#jDcc5ahN6MFU1gnQcg4JRWasjf&)oaiARP%Sn?7QlW8 zqw+9#h#FrNQEdQqxg;6J-yuup<|S9vQ*SU8i8x&v8i;m!6*7q$)_fu4&N^D~!|66V zV~oja|1+5{?2SP@#4%e{ZM>z?(G<85S8QPOuU}Ec2i+rKUfYcYrTPpp7**1{`$SoB z;h3g(k&z6ZI0r|^pKj!;Ma!QJ%XXK!Qz#k3d|m+AU3^9!+0T^O$+^g62`qeUa}Epb ztg05Bxv`xW)^D?TbZl7r^No{+??uJ0C4mT>iIU?0rimb zlHS>)e-VjJ1)FF7OBkKX^3&JghaXh!@S2)h)G_ScPa*=wB>%e4%GdDh3A7OqC3DbI z2!KK4bw7U4lHqotpQvNjAF$|hqgUrj!Fzzu6FcEP#hceRmZg-=yjtV5R_a))qfsbJ zn@3J9{NY*coT5C7i@6mzXAKD_A&{`p!C269X7;b74W)+d!ShkMXf{)LhwqxzB@7|$BAU;AFuOwX_@k#52+Mb+@4RYE^i)sXGb`wY6lQyY zT+WP%S+Gnq+~7f}f1y^g69)^AQL$6%_FlqVO`p&4UlsJp1^EhFMUa%4$bjS>Wmw-%gp!>h7*Xq!~Nw z+Qk8mlJ8-5db(vn!1Cz_F!n>~2&yo6T$mTPtGoNylt}`U1H;RXC@*!R4o@~Qq(AhU zJZHdqShSikkWAU|v`KkWQ;if((3mHLrWoDXPxFdml#e%ObMLZG&0}}Hf!`mv8QJ#7li>^-DY30AiZwOEeG;sBWW{*&-qK3x9n8fel3kHFKc}t z;>e&37cIz$a2p^`h44RxZFyx3nxg_xeG@+PU<&NJ0A^L)n^Ow#v!&W>E_M=1LDG5! zVsgIe(cEKDd|ur2_Z3htJXT#uG)SQngdN+?q^7U9GV^uf_BiBm11ZB=aI?`gJ`zK0 zWYllzBZ-TkWzX6>ELZ?<_8bxRy$={hYE;B$9x#^d2937;$mX~&B(&T2S^hn*Xq%q| zS5mT(YQ0^}>?(bu>Ggd#+lfgPHSK~!pL1(o=+7I}6~+IN_7zZdE!&m}fdmPz!QC}L zaJO)9cZcBa?!kgP!QGwU4#C|Wg1fu*&P{UPd$<4Z?mv2rj57`=d)KaAwQ9*+vuf4X z)kmhFmQ<-NvcfQC6NfnJzeal(g^ZkY{pr@g+yXf{dB_#LPd7+(gi}HXoz^IL>pC~q zFW(FOS?S`ONU42!dRWp{%J_X?bQkzx<3~gE30slQ2Y=_(sF-4k<*53|JJmVq<(0Hy z{x)!>50JgB@s<9$m19&FV1KN80HE@^J8^1$VwJoZ$jUSh4RzEG%}&5JPaHV(OfHS9Zx9Z-@flIWh4@5DnJygHku1e#aj$-xHJ+OejUQ@RNoq@5;VZ2^@#Sg@{#DjA(u8xtjJs4#IBvTjQ71isIY#U zUK|tneo?^gm)2@i2Rri_0Vxld(pJiT4MYDH?!K*|TLd5AcocJIeYmFp5)&opIq<*m zrfdffDIZB=l?+w=)~}RCm%=SUofM(LM=fskj{45&!N0xQp-;D<_iH9l;_HSWG?j~E zB@?b7o$#SkHyk3GY>bQGqjclw`L^+?4+N9$ot?c^#Z7&vt#C^rq8O9Wm=CV&le0^{ zn&YNsBv#LLxT+sfz<@|=I{q9Lj-KV>XfpbCP;EE>e7HIu84XLMEXoFXH@VkrCiDl? zjZ3vj81<@mrFzwB>ttSNiC_HETj{e1Sn z?UvDmoIiZQJZ~Bwp2(ve-IYU+J@;|S%({S)gqD@m*`_(T&naKf8a6YB=K=%~aX zjBfPAem=&gvy}RglBsXl$5pt6BwJFcE||#CFuU);i0rQo2KU!`Nxy;8H-I7S&5%81 zc}?@en~-#s=DURkd#$3$(l__kjredkT{;J~!+R%mlF*C*8rVvEp*fApvqfpzT4KDp zLSd3Ar!zLu_U1OOG6EkSuwh{8$!f4IeuhmmCvT`15c_o&0`7| zLS)G#j6Gk)oR@f3bi2(#GAuCMWO<&@FHmj#w#CUqMkks4@n!p+^-fyrgLobsE`A=8 zeodQvtH<-2D|?G&T9h9RbFanF4E+OfV@Z({D$91cF(#?$15g>%OV zP`3x2A@P<&L_ninex+Ip9yfQ%keB{~3r|Nkw78>KeQPdvot3Vet}EzOcrKdmQw7^i zvQN#lSp}&NpjJPDs+R}|;P?q`=6|KYe!5-K+2BVx`_$sBbM+|3%_KRMdLko6N$-v4 z2a*Exl0I5@grp2a0VOqq$5Zq~s;OfF-JB#-ns{N*AJR9>7FtNmm!FWQ@(UQZ2jSQ9 zB$LIgt!rbMgf>;`0c=-c|ARzl1V+eEwAF55^h11JmEAEU2rO5rQQ(MYQEjh&m#)nL zL=-eMQImGTp0E-o-4}WhCX=Hhu;I$q7DmOTQJ9JnBsW}EZD*$~1hu;z!C9&a+Ow8u z$|wQrryeQncc)M70(pZb!c7>*TJ@QD$3@PG3NMgi$-&Mna|zk0Wl99}c+-s_om^eT z&NJX}*ij_>^C7@NNxLe^jipo9vUwLO|;kO&nZllZ_^rsFN7DM>@l z>V6}w*%v~cx-G0=y6exG2aorm=%}&Qa-wFm2sGb@@c00N^2-xP)}}(fmaQU}uoTP_ zzeZ1a<=yd5{1fy<-twS{b%Ficvh@?cbgszrEs;w+(9%qir90ZJu2Bf_3*B65F;A;l zMMC{_oWAnz>B_uBMXU4kbV*s7S1N$Nd^1}%Pw4t_zLAaM@>t`z^YnNxs|n=Xl2|+` z>+4v@e8RhZO)DBH8o#ov?}SpElXzNqQtygc802?KrLsyHj_lwq!?_fOv(IO*jFchS zA1w-tR(TvMf+VL~KduI@QqH5puIXk(QN$Ar%9Pz5TFQyWu$op$Lw{?N0}=`lQ)
B9$^Cl9G zHs5z{tR3ZE?A9uL-Pswd>c91R;zIGXNPS&cu`s4*xO*%Ck%qOUs3Zzo7E5!oeT9Rt z?k@0BQ1h_GhJ-&l+abjy$+k0^M(qmo^*b)55L)GGZP@D_qLdh2IH-1T&odjIhkTr4 z7Bgvwo_psCa^%x9%TF%yi92xYFTrjJ5U3r?ZTP}%^uW} zo(RCrP4#_Ekw_#UU_9lxLa|LU79Eu=ey*984q%M~uggZhl2Pl`jb=mOLA3{@Odi~P zW!a5p$xS@)aq)=2M>|qm&`^SUS$EJx?fX#cu9hkxtwzh{zJu^C`286*Z*1HAqvcFv zyexZ&?;s*%iCU%KxU6i98}r_j(!)s%JlI2H--;DW^!ovkfH5%ya&Ry%my3ukJ$UE} zQf$Bp~+irYH3XOv!9+qIY zZ+39&SUl2cLvhc2qD=3no2wu4YWnLldZJn|wwN7SY`R~Q%uYVXL?b$6+Wb2>JMdFML(a;2?n$7(U;W^CZzUt z?gUZF#Gz1?{6;dG9qaEPM?{g@{HPV+sfVb0kp6yo)ce8urY)uPm(arQx8;a~iqbFB6X8c0721Rl^AO7tGgbrHd$z>?7W=BrM&^eVFbFX zIF069iN1vyCGOZTGlNWtnNrYff$tlm4zHJXhkK|b)GQ-Iy&sd#1}E%R({MmhfZY_f z$93XmtNpx9LeQ4Kv7Lva5CL%mBJkh2-CA{F zj62UZe@Q`2uPQa%Y*Okj7`kW$*Gi03YV4lt77ROvu4;1j~naUrx1Qt zvs0hj7)n9nTkGi~&j9Z5h|oQa-l%Z&sDfvTmYx~9dr@PTB~pn3h++i_&i;@df_umF z&*kIbZ+>GU_z|993Bg-wI5xl748I5sAYq>vDvJAra6*thS|<*k;n0I$R8%$m?t8|n zooxW)+6ZKc#jyt2NDj%{>a@Z#0NWOOKxN~IyZIO2|Zn!gDjYgulL z7sQ%2&zcb)$qnaz(Ci~~{qWo@Mnt)LFX*_JHD4b!5sG=w$u*jtn(VKfZ4D%QZA!0{ z$IN`giKAHV4e-Ro|(M?m-9-0QAJyA%;WAMyxGUExXS zWX#xBKOQZ)R$B~BV?UGq(#C*mCN2;FFMn6#xgz88Y19-2HL)3AA&6kU@t*$D^#WB^ ztvZq0wpy4o8>C6v)OUR>`uMSL6lXv%ZxrgM+XJ`>M=O06Tn<7sL-B~_bQs<*9~-e~ z(jAZCJ`K5obuU^yus$x*ix0wbIO6bQeZWY=A`PrxOR8DeiH)o>Dn&qwhfq@ba-F8A zLaQYe)(DNQc+@Mf3l#oo&Ir1ikyLA``kZAY-SwD3x64|XNJ&E^Yhz5 zr#4?|2!C2~9#wuH(ov`cpNmMh>$nMkSmaz|p438^?~ae>?Gs!somCi@(=HX~aF5l% zt71rpL7Zi#w~uEeUnq0pVTNA+OqB2wS&=DRFS5hIaKnUJ>!1&Y?5CN{`7FOX4sE%%t1)26^Aw)zI)G_!sYVQ`6qvy$ST8D8`m?`=_@?q+@so^NWJah!oCz1 z%6w0xHXQ-8)aV>7EI%q_Wws*noa#Nn#bv@Y<(?jt?B9}h|I%M;Tun@g(2uO#L}Bxy zEeyv_zt+Cw6{c#;jmb1MND?Hwr!N(Uuw(h)%+}0!rckxTOi*Jg7w&y`4NLZPA5O}B zODyzx(~Tv;>6-RXxi${Xvzk{f&rSF6>5W2>u+&=|N^~i*tK+;r{tH`1%I(*#BG*S5 z6_0mO^OZdV6M6Bwjs(ycPE6p#D}yn^mU(+&NgtDcCL#X%mmrbuW^rit0hjpiJQO)K zn8j79zk*#5ZLP}rXZb2cNR5_kSMnYh&&Fy`N$R)80=v7{-2!bW?6zA`x)5#M-9gwm zIJ?6*DWloM4y7YRDF6lRYfkQ|@7x-lWGpqs$#5nd92^RoLkjo(5A(v+O@f?vlxU*G zYK^hOX^n&_Jv~d2;E1IbwDMx*YeHw%ga^WdG{H?C0?r7_%_1BU*Ls#Y^yK$!6alhxEFJUAhi6w2if_rSaGHq9^?aWB-8*k~o{er_%xmj(`j1R@#1UVEgG?J?7?PtiYiryn+YV&mGF!eemjv^{ORd<@Gd!y zMneD=Yl@)d^_tJK|G84^k}8$rS!UgA(-5gzw0}iQBG#vp`|ia%=%`Zqgiu#^^2f*R z)_%vf`l|Q>wY=?|=V+iZv$U`tO-Ar>3LEwXRd!$(nUrc{OVA_2*-8Yfr5P3=m?+`|vvw>F1YR1f44M4tybGUxZ07j}v< z)+^VY@nHxTyB5nO4^6ril~G)&ILBbB}BO9CKg zpkX!~!Jj9km3acW)PaSLZfFdbJag{fgLf!iq-Y+sw`zTTPA8tT+`JGS(1^vxIxprE z22im=nku(%wg^+-J0}pgu*N@9uO?s|^DG{*6{^)@Dh%TuYt_-LISqg^n54f6|Okyz^-ykE1WL|>JLJRkZ;N^I-n33~R zI2&$uKaPAePI2rwKxxI}kfgP+7*{D?ecJu<4y3t~j*oeJMZKwhb>dnT)Uns0Opv>} zpBNX#k0+VHi}(E0h;eROV(fsR8v-E2Vk*wb+_pFLCJR|)^$m^D%}#GHNCY7#xbMGk zQp!h!)b1#^sxTH3mePc1&sKcYc8VXq(B7u~feVU03ZUwc6}_l2mE{c4tqZ+A>iw$n zv7POyiQauRr6*)$%ffLXFdD& zNJaROQNPx8TWnKK)v?k84Kl`VUrx={5(gmeMs4@= z_2qi}c1NXpvQ~RB@nfpLvxT?w<9^l#0=jBh$fRl{$%=DxN( z=_YpU)@nUx7w{7ka9G&#RFE4F;jxcF2WT}T5x8$Kokg-e)am0kpA7EX9jaDin_U=5 zpb1maGmc_jha@VXva0CNpI?@I+<&?Y%au$PF|+4$7?WZ78EOFubBZr5mEAE~itfVe zJ%br3&$tl{-}x&U^XNc$oh>#iq*AVln%L}Z^w8VCNB1u@!(Y5@diwJn6qU>K{gzS= zDVj9rgB9Z@CmnqFKc06ItIt}EvAow{xj zOl1g?p8HdR4JYo?gR0!ejb=9}E-sVjWSL-~(T38b=!(G6vBwJK41ZECah7Yu zKs}cSPips)=aTAXEfC0Vp5jTZUZlWAW5P-u7_6^KkEBz1Po26!wJlG0hlu=vJW3Cl zVf|~@SC=_-GbMT9xss8^ti4bc73m^wgZBPoo@noeo(&*|aCpK120I0_KZJ0+KfNE% z=dgFMDV&LSEv#Mtm`^l>@)~@as9%0?3?bO7*KgA)2fa?8*}LiZA0Fl23+sdRM2g_?{SQvmgr5S*6Ce;BnjCb zM^9@N9r}uecMPz+PcY^aSfXy8 z``l?GguqO(1_vgW>xY`%X^9FG?F3=&>x--07GJGwyjmc~k6EtZ+oV498kU&qjitwB ztbR9sZTFLUSYsYp&GFLLPoB?QLmJ-}%_{t&_mP zaLM*QY(~l>n^PrJ()%p&U`O$srkY^)JOlbiL2IV-S9 zrVxad3dc0C^Jr5f#m2T%qyXx<)&?+gzv`F8wsDk+@r}c zp8iHNWqjr}X7}0KtYpnMhi5F1C0FjU;gUE6!aa^dbXBYL(h90 z36;8tJ!a-7kBNaE5lBV$F~g!6X<&DUL<>wGovZ!*V6)~P=ZWth_t}frm{6NYJhxq2 z&bUF>i0b!<#@K+FmbOR$JlO)J*bMoprD}xq7{{sNtrZ~d1fn|%LQYvE*vTTLiEO8~ zV*U^Y855JF$+YtFeOW3e$A@|Q!pN^`%kU}AWP>5wWk~UB#9d@ffyxaOxh{9RHttf|9j1M*R$9Ny$ z-7ou@E7k$xrIZ*M-l^yJ#@otSN;)Ns6*m7lrIz6tf99C{UaSsKXdc2B`MhA%=Ci#| zi6P;2j;T+4KEe?y|r27ILGRku@GH+-(TPXf$m z&1T`XHJPpsWHjXjr1S(zv9R@uCj|!dx2SjyW{6o~3G0oG+gv^I1N8PArbE;4M8Lf? zij&BMC!pB=6{i)HtV*PK#4ALD?++k{sb!J{uQ7uhwVgMA&4-siIN`B@Y#A!l#`-4# zyla3pRpH-FSRV^nuAHfr^|@;rdp6W<-`wTEAKiu~WujY9aJ1R4F~*67&+Q0F?Zru% zdg6nRZ(n!Ks-Cb18tywxkXgG|3H!+zDH@HF!dXUo1cGk+3-vL?k75!z`Q`M%C_t~f z39=myIlCF-s_A!^xe6YPtSy~goMmcUF0->p3^wB8j`Q|`!ytz8$@`N0YY~WVz`>=3 z2zu#zP(M9e0!$W$nKCi+^L%OV!l@FfrTwjH7~_6!Z~y1zysR0<-HD^pNjC7-G=t~h zKMt0^&|?^CW4U3h^d_5IklH1 zt#XP(j4ap)0JM;;esqWQ*SJkV^3v-t$B^fvAP0toWC2BflptSF$@YZdh*?XG+9CAv z0OWzQky3ISO@tA%@9?8)^d8#*cm;r^7LsA!`;}~==X>D;g=~cY0rm-L)lu#tEO#n~)$-TjWT!J7_@D|s6xv3uf8=S=7w6Nb7 zd3O+5X&hh_MSbhB_Va%Yd?u^TnM zcjbN;;kl{3iH-Zu7bHLY=@1_(AsqguQ2)tK{ofz$%?YU=bmRG8H)<0cb;z5nMYZz$}LB|dA4F$mf>5WjwmaR*zLe3~506Pr6GcY*v1 zhLaA4)R+0bSqqYJ9h3j7cM!-Kz>l)^$Igh}k>qj-EkzU; zQ`_LNt{Bzerl!i5sW7UdZUH-1R*W$J5<*^QqS2yKoT+?$x#fn?r$2I;NCb24MoJ7Q+1Xd>hI1N;Mi2VFdA*^Mw~nKgY})NfNe9T;G%HIY$A9b6f3@<9fbc*0>?Z{DWd9EZp|t;> zR({``o{S7gW%A049qvD?zZ$0?YtscX-~aWc|8MP* zmw}rNnD&fW{x_|7XA)WMj*|eaLsT3NhvFSdA&K9s`CrTdFvza&-$CaYzy&d0)9FzE z+XWtw*gPKUN#Uoilt6F2&%}T=eCB#MX8T`1l>9wd06bo9z3uimaCUS^v7|ispRCBA zhmv^n>g#7S;oSj82ZQ)+M_>Q5C2|(H1wpc4#pCh-iRw#g>Q<{#&v9 ze~Dpw401W$=Ap>>f2@r*U9f;_;_=%F3i+Z`WUkrvr5_KyfBO8-VfjD*E`0{YOD}U) zhN$|>76DgFi-XgqiDifx%AFT;;m>*}Roe_P;vgxfwLN(rjiubYm1r-u__lGVC-pKG zr?+S2#_GE5$hF#f(|m7op{mU%=>EEDXKAKP&IE+kd?{*RW9^T~G6c~M^=~rITY-49 zS?ko_->=eK6hbpqye3#YG*ktV9 zv~?y7y4>#Q7;&`oTO!|XY|^$708Qw>knVI+2N5R)ayq3}a8sOI|JIq-a5i_eyahx&`ziY9BTIpz$3teLp zsZ=t*q0k67$F|As+1PTf1quxZPP&oJ?NM#$q8?t)3X0i1y)d>`Qz>@Q?oG zeD*p;)z8VjH6s7lprPP;`!*sQ&&|}H6{ibG!2|AKItm@yI}%d;s8Hpva%^1;;gee; zWe*H-w2)$m_4O|Bb)zsu?)iPb{$xf$by30re%;UxdEumT1K%v_nR_x%ip4WIY8mr= zYE!y~G6xmK)n(^(x@j}W|0U*tfaf-&3cY(Ltazi3TwYt7VVHK2dz$6m?c>5p`Jst{ z`}vL(ha*y4j`U{Cl*k=6i+Nki!!|k$TP#;}{lQPWBmU|@Dm(F5(0F{qe!QrWtj2sj zuFQ=(ft5}WQ*QaoU`-M<>Vc6q4_(rSF?jw&bqaz%?8RRz#||8B=-#XHeYfwOdU8oK z*OXHe9y9ipY%0uyEk)+w>lId;1UR|`5nP4B4FvJ7G#-&R%P9i2bQ(;{o~MKbM{*<5 z6V}K!UFVmqjdlzvPiq|gO`bd=oNwyx-bjB{vF)ujX3RP@jHAx1W6aB8ZTXz*hu~PI znc-`@LUi39E0N2niU{@}%kKp^2<2rHP~9>9Rp?))cpvcws9Ce~qdSDjXcWItqw(7% zw6N&UIgNk^W7G^yw<4gnvZ~IQy5HN#0-sPZVX?}^v`^{MrO#a8PqyabOvxl1-$_

1I8I=YLAG^Zz!(wEI zGR7Je^?HFu^mp2r6}LSb<@~2Xd`pU*OgJMv8jE&aeOe1apBP1bMsHCAzy8u zj;aaBPB3ae!#^FX5)Q?-VjU^%L#DWz6r~uRT1lg1HWNoRna=()DKF~Pu1LfB95z-4 z;*a~>DY8K>g431>*NR3%0)qr>{QAdq^y9uf#7eB3;ko#0TT4HUceCsDIIy`i-~Ijy zFu4njFK}uG9(+k zf_$ej+(LRE?kGyTbN)~pu@@-sq0*?#UcR3ypIdO_`(Fs_wQ@>Cx}P_ zU9d+^lN26;4$_Nl#7q)C9uCQX|MaGie~kvxJM3^Nh{q(JL>H1nSlHz4z_Sc+Se7lZE({8;f`E-* z+QXKq5Vg#C(921)hyAY2d<|Lgw})TZQY=z9`SMzx6_ErsJ{kL*=X7@Q z2=T`IPrH`>76^PZ-)hR+LH+rUbSp?s#!MuxyBLf3;YE|cM*Fm|L#e1tuBL;01r8P+ zXZ+}4Ks|&Q%I+u*x8AheYHzLa=6zovpMY(Q+-6U5ZTN zIS>xhjpXLAcSoh1mw`d-IZ{=|#F=#t*DcMHn|QNC&L(R5p~0NR(Z&XiDpx*?=6y0( zYNp@K>v_3#v{E}|W%fGcJT+;Bs#IkENt?`kQve>fLegN5=l6ICCogr8r&E>uxQ1h@ zL>D60KZw$8wqm8k24ArGk$Im@?90`oZ8&YRct)uI)-Bbm@> zIVa3--#TPdGGq5GYpT)CB*rC?T(%E&vZ~kPDmkjz*jL5w)nwz?U|IjkFYAE=p%aNp zo9TRYL4}bY;C7aqjI`?FIj?jN z@K94E#~5}uHuR}f_>4%lpv@55N0;iH(;SY*LJiz0=j8It#@Y-R%H}G$ya~J1Gt~^? z_o%^#4x+j-oG0SI8z{HvlV_&7KZ7}k$;>3;BI&tY-l&#_^t1+q5l_s)P}uFtQaVHG zxE>~jP0Cgm6k@<*vDb$Y^+Xp4sIlygkNGO|%BCjQCZr9!l0}3CId8GGhnBH`BX91) z@oN220Ks2*fm0uIZlw(>Rxy7@5*LV87bof5RL}US(n~FNk;Aka;%jQP#X%+P0Dj1d#TJ>iJEL;sfS0$9zV^Q=`z14S#40bN@8MH9EOEf zgCJCfQeXR03TKf5S=yVV2(<`Br=i_r^%lXkg>N8(fQua=vpIs+qbvV&S;du4L!rSW ztmBOq&Dh;5^)~*c#cEXkGwxT;ChQLCVNBR<=KE)twbjnOFyr>@S94^Oj{)7pnv)wJ zwQ|H*f@fP|`Jd-MD!5)`w|#)${OJ3OrVaSz-j#e_D`Ef?m=ByS5FZMcfexsuTfzw2 z8ikf%KGJ^~`4=xq5j@yJ(OPgw+O_#Q(5d)$nnfc~DA7(a8iw6DjUS4=uwlGPL;U&E znvo>{2LkI;@I+kAoxc?K6I}Iatzf{Y zla)>Zxum;|w)bluS(nF~hD7LI?9kmyfq-gMmoMK)FWHW&@X|_xHgQCA7UX zC!OfQfGP*)u4v6PArKW8_X^@7)R2aGm*V7ktSgh?lMBBy2uY7bDb<`w}783RZ zexo#_QJqw`a}zT~g%cu-Sv#Xgg0gB~PS9X_KerxVL9T6g$pcHVdFW!HiJjM{cd$80xsTyQh09D zI|`K#5fk!ob`d`}DPr(kHt1jShsoioSTQIKqPy77gvZZeey^jL*$G6*!D4^&1`G4P zF#P5Q>E7UaJ&N^iH49_+q9>=K`l1nmAZb+9Gh!lclW4>k*KC&(id6Xl>~8{@v>muI zIRkLgb7m0&^G^i>_i`D(zyZhPVUIjin~(w2#3(AMD2O1!a~oJ{p)9o<6ePT`wy`Ne zLn@I$snKZsV}$yS4~fxA`#dPRuU1rUp1~!%+$>`uFqnpt$D|rHd-Q@&~MG`{79}R zw>3Bm1^3}%vtQ}9S4&;#VjYy8;Rcd@hM%gHkz8gQ>tr9%HJK8-zYm9DzQvJrH5AXP zt1=|FImU%HS)dh3oqzR4R5#9v;0G(ywfo-Vd71ukp=VwU(JQdOZ83<(8*ny$fgt@X zFCV`apAEfi{x_hp2wB?{OfMCVkuq+z-{HYI{zK_xl0_IA8my-42Wq7X@a-b$F-;_~ za;?KzpSF8lohVi6_EWQ^bP?bThwN&xgVjQZroc4x34l1!Q|-)p#G_NAyNngd)`f&! zYrlkZcZ!^{<2^DLLhdm!C zByUFISHer5HAQIA+3zI5pvy>_B?)Jk@qOR7lQ;y?Od->p1>S_F-(U?!4cO!gp@tWk z(yTn&eOl=s___nBuTz6F27Y(O9g1PtUiIpd255Je{o*2`*r=Q&$P#@q{TO{YA_P@8 z?!_4r%?BZiYx&^%&I|6w@E!K z3E7ndo#1;3*S+QkV6ee=`Cl}joPWJoc1vO9j}I|=<~w}&k)~d3+`Bt)cB+|a0oECJ z@=x&UOr)*ZhMvu3&wt6x`G-fa=HyTuz74XNRcJx&I>}l`3RS~U!j~FCv-6dULKS@Xm`X< z%grr|^bJyX&>-;XTM|RGvUVg2a>;IO#RcR);2!cNa9|6Mofc0u?oY3*3vBr<2#q7I z4#u`%tAWGuNZKEo4W0k%SG--`^d_X)$}524pXs?uV~fE#AK=raOQaVjgxmz#y4h*b z6*4P@Es4~)x+7=taQLlUHQlvsD1*n%&6hR&U=}0<6FJj2_n9`N8?>f0o`1hy7;s|K zaj@QkbN6P(1_cHpsm3}BwL{jgDe!qT)wN3(3|%S3-x_E>CU zDp(;JlJJLPbh;*I>Glq%b5#o0tEpvt%tVio3p9AnJyS|~cTfzzIM!Gj%z{Bsi9f@q zzVX-Bku)sIKW0sOXA@seR;4{P#{0vR!PS98b=$}Bc)G_X;q7uuwXm~X1E1x4LhPP3 z(YP*UNp^ARi^CykD|-#@9`Hq_3G#G`ka^tgL#AO&->Dl;B}qnEeR^1U$+TZ%dU3qs zNWuWA_HOO|R8I%hzf5MxW%#1wqsHUbH-S=Qk$*G3-s3`ELa%BSY+p#}cn_+PyoY;h zm7e#;WrB{Meo<4|(^YwpV)jSp@?%i7$&k4wJaIkG^m49aw{rYBmaV7d*r8uxSkaET zRBK>;M8ngxt|a{l6kP)mbzKT;BL7$a%b;AqyT+MfeQJi!BB8>tQIWuG{OC+bG(jRG z+=LKWrAGXHMk?4@2-v`^Z`tEn)7yxMalEJ7 z!=slP90jtzpXK=`sT$X{+-OzWBSxsEE%7%+gTvzHV=0&Msv2(=%H$s-MM%UjHET?x zvjXx6=TA!Il#)$L;s-VpZ8vO2XjKIJYAwcF5+`=ID){8D6Ak-lq^~`QYu_JfOsFti zKo-QQA(_`X)vuEZ(g0VADiT*mHdK9yLHY4C>FGhAf@t1Qedh>ZIByul{sD)2SBd~& zW2K|S7!lxi*$CoGaDH?>s^2Dm|31p)`bc7g`<{AAn(Ib3OIxS=3Ltymo^9IQT^M6B zo1nnru*;`_0|@~j(WK6u#{a-z_n3N3Di>};HVB1Hfs zNjXn^)>_{!s%My#UL<;cuve-y>bUOPxPBFM%<=ED156FR45a?dqjSIy|EYlJJh`24 zdsS0MbN_s=Z4wg}^GrMmw;?4YQ1675J1RA{;f^LHzKqaVYk7Kx+{h&Xxx(gU z^f(q>KL}1&>l78~f4Nz|P+VWlald^0qeT_yg^OC!EUl2ZA1OgkIDSQ~ zJeR89_?4aV`TK{(2?HFLTrQ657(mM$@pM#Ai=523`(ia|Zo!MblwykbtT<}E(j4D7 zWlEIrD($TzeC8+xRee03Vh|7ssM*aFDp`X zkpqrQDv|xunJM%_Q_z8idcNv0H|X8%snt6iG!OnpQmL3?_Hx$sABC|fC)%ckQ=Ts% zYWCCDdhN5jx}h=xES`4J5R4pZEMC5}+h;|*UP{oT!au--^9(9|tnxkj>_6Uqy^@j2 z^T_WY$;N`hsQ9|$KhzC?!NI?rC^`g5@r=s;RHo$d;L6~LXlSGkUq-T-O{f1lPc0(= zH_8wBeFRDc$M;Huft?vG&z$^xa<&A10RdDVPQdf<7im*E=%23-*K`{#F9<2u)TUBF zT~&1^7}2PJDXdk-wmURQ0?Ju9TF(GtTB%Ai0dK5=&#*n94Gq_4e445B3>~cPGcZpB z9NL=hT_Sm~kin8+MkffH;@5`Havg}kQr`XAL0wC#LVM4&;s!WD5v*eJRQJ&$Tp@xx zZfo~ig5OkXqs5hyZa@qLkO4pTU^L6XVEMKbbp&L!t4sP@GdA;R5`@y}UV4h)F} zXR}eh3^Ro(92MF>reOyXtg-mJGnpK?Qb*NFBKBAJXJmh#zby zhdd71{k5iI&&T&$gpaZ8HU9%Z1JQX`S5sp$Ym$-EANYqLpi7}-nhGfKDTl7IiREL+ zX(Iag-`w2CQ1)97e3K{33rE#ESxm0N*r$7D@H0`I88+ApvTm4vtly=rIkt{eUOWL% z#2*b@oEM5zw2-HD^9pb_>E_RS{ws+tzRt3hRCDX<+&bQ`VZhI*kX9=^HP@dvHmHMQ z8$!D`Tj@&YY&*Np39Y|`4nzndRaiHecA3_3Cm??e#oY0~?VggHg!zvwO^!eBr-s=R zkg_2C)FHBg z9W=A4aYyOltfXfu4sXqCZc%33V=5JID=SB(@x|ss)K5Pl;>l$$5N8PSBrRW)XB-X; z*^M4ekHO`W0f~lky$@~ijgazkVBXI2l~@`G7HiCx5#Wo)l0cz(_6{Qv`1*b=eSX)c zTG65&=cX_7vFIJ6@qG~yv2}OB@so(e_b<^|e`7VjJpyu~pF{;Bbfl%9LY)S#-bIW3 z>J40WER_=IMP+5B(eZNgI2k>C1SXRaukF@ghQ99`J_iQ}Oc|lu>;O$)0Q|*-tng)M z_oPs4X%7P3ZJc;ulO0dv?0i2s(*+VtX$D3`u&Kj1A?QsQ_HMDI8nX=xFqQd}bab`_yD(~$FX(|P=q zhO)!D(0$(UPRWf1^7^9VcK4`A+ERAB|5PCRdu^h8BY&}%xl9G8)1 z-oZVfQkKkMhA)ci9f~>b1GfFchV7a8w7Q9pnzq+4D8LDRc$#$3UX;ZS%f0^Qb~CX% z@AQ?t>nc9MkDJ)x=QBoy-T4&CY0C&hZsLDrc*(iIZM2q@T<*N$ezHe+>q+TNCdmN` z1XlO=?OAUMYKefsr{wSX^l+y);C8O+KwEW311!p-b8upj^ zg^GEhk7hv~vVbfZTFfbPFN;TdUD;E27GY z(i~_yC^hRJsubRGFf^2Gm`ZVXRElVFv|*aA6A%z4@(@KKA=|lIp>Z5m_7bO8;*gMi zq5ylP=Pcp>t`S~5XM~DY(IB!zadl*Hus^bUNWk$K1G%-_D6deN*#0)z!dkUaomzW? z9OdPI1ffY@;pJvMXq!G@hXp3(L^Vc7pb@TJbGw6w`E1i_fkE`QDa|Rc6%em%HDa~b zZBf46l><0Q5;s-w)3S|{oO&e!gXi6p1UseQmRM^UNZqiw-Ay#Qy%$RDJ9*i#;iHK@uH7UAo|?Q!9w^fzxVtSyE8u$5r(Sy zDw7!j0g(dLYo%@Gi$;jo?_P^;Q~Mb`kCEBww+GlAuHYmwnf3h`%)}#?41{N=euy#a z5_Ty#-GYIwqt`Q^k=M;ZR%>UhlQZ14b>HTxK0Zv0A_*hHqf1W}^NcgmX({Euh(JLW z5JiJzi_*=^dBAN~7&I|oR}z^3oN*FU{5Q+40WQ=}qGXfwR4hpU;4{S7fjNoEj+Y_K z{{<5{BUqtt$&-mE@LB@SH+E4)aZ5`Jlg-9QJ(-_zE3lC^j(UFE|JKBjLy{_8x@U9C zP{xm9CMylSj2LD<$;gPC zA;5Hlp+Kw`%=+My&;;7`wAne%c$T?uC%amRkI>gl->V<7xdQdX=T~gEov)hrYiCN6 z%u`Pe;ok}CLLsRPdJf|GzG2T&Lw9XDm3$xPW|X=)2%LH3)cXD$d8B4w8NR!{^Y%tt z1$w%4RsxU0p39(Zb`9;IE$HV=!u72Qg z1nBIXFOj@g-A5o>oA9=+l^L^wo(N|S{i1cdZc>__Pwz5~1y608(`&HG(8_Hy?___b zRe0T+2}8MNEH zFmEM)KpPr9jWr3E*C8U;b%8(le(_y?UjEebm8xD|R{c6fRy1Zz3mlE&o2L@(553@6 zIrq5Flwe8uYZ>mZy&+QY5Hev(WVXOcjJv@M_+MqhdX0ZG-CKXHNI8H{=QFh1!9_?iRFmM>hm7~zqB^+L`z#&fqmK{OY zYrC$1V?W)2dAJ?AN=>7~Rf1+ZoO!G=#$gdu-T7ETBjd_VbePxGD7OheTmNgsj7-3+ zt*vdis$DMkavl7841w`NghI*ABO?1>WW8lrT-(w$3Z!vsBuEJE9w0cuEw}}D3GVLh z9z0kB0TSHZ-GU^zySqDgWuLRpyZ3kb%hTO!%~^9))u>T5IaCQdr4Aj~R|oG9@VSvF zgu_;9l}jzZzbY?VdUv^{#{vUGnn_!dsr2s?VRdG)V_5$5io_ zq^tY1|K3bL#2P%9bPnq;2bI3hcZI#TBQdPNvYdj{-%XqXV)j4pAeaFDGv7$x((#*i_V;Gc{90e477tmm zUnd3j-MJ}ZZa+~sRWVtp@Y@$O&oib^~0R)V_W?{W=rIs++p4qjo;+d)Gn?6s}N$_A5ljg~8I7>6p0Y#kB8 zZ!z$j=xKoo>~9Hw5+~HZ%vA^(Of{ODmfx&(XT2vTc1rsF=J^a_s0bUHEnKIw&MaDKWom`+9h`z-&pqnfbLT3Q<=;Fy?u zM~|$Ry?U9q7;`f<1+PC^4j1!0ukFaRJo&KZ_Gk)L4j}L@+LabM(5;k~Tp78Z>_e%k zblX<(VURk|^Y(MifvFm#Gk?&lTfi+#fHRrbL&?)7N-?$h7;KB@fv=yUsv1+LaKzz~HO1m>y2(glBntv4|Jdjh%OMKRwAk62u?FOyuNrraw zVGrF^UIa?RP`lEY$Lt&OE>Rq#CmTMCqL`h1btm~4e1K1+`ARQz_3?FI5xP>vdMU-_ z{tk^ObI6#GvyYkgy3zjt7eJ~%3m7;cTu>|DF40D=kmvZ_G~naH5c$14HsROZSAyl3CqA@FWaHAj(zt%4+^~H~jx=hVT4CNc4C1 zk>KT-*&*3M@a=l8?2;pKKIare!noY&};LeM0ywUYnx@IQteOG+2sN1z+cOd!-9HEQ1pv27swuqawi|+$W zX0I^a-)c6AUOlYTDIa9-I)Bj)h_m|)JgNhfVfHZI0k$D#DFOY0S zT(s{eRIj(mL;%10=JAQA^=euR;7P>9>8;Um3nG>kuNgel6_@d#_xJ>ie(y%h= zqJeA3r9JI3y!J5)vmW6uQ7AkUgIh0iBrnlb)sopW4)Rj$SE0@NFJ;;oJ)c6&DtKh{ zd)(AAxDwHa-a8BjRqsyBVEpK+hm{syT`LtC^O0+~$6@wjX7!0nHQL#>0)ZAfKLS}M z_F1=N5q}(`=;1Hvfbb@*43Rh_h+T|c@037Ye%j!{nPgI0EEV3m5@ zr=8GW@a=5>^?iSx{u&|}wnF!TLv&61o^WM2((YM$?MiD?G$dq#?Kv(*q%A6F*_ zL3;_P8mFJf&byYM?$j?5ga(M1r_nBphFE2$30Q=+M*wj6Z&39=*NOs@Y5O%g@T9fa zMONqrdsF`N!8#e})l&TF4N+}d8~h#ZASC6--Q{6$MdilS`Ze2Uvb%91ZS{Ip#$jnG zm{z*#^$hJ#3_{jOY;1~}3Q(B|$|fl)8d)T)>KQLrrW4!jv|%Kb@U*8N4;3_lEBYkY zzqGyFq-qElY*2+2Y|Xy(3A3zVlbWT{FL2#GAm>Q5fxUOd&Q&BGi60*$1L})41lVa2 zh**$vjQU7DHbTC>-{JUwk5Ua3jB|o_yENAZH1Yo9dqOL$V6&~=_B)4^g<{*Q zE;d^@awX%N3e4Z%50mNlN)J{e<|rxNr|}Fc$D}ZW=sbfVYma-vc`o&1XT6cqBH+0} z-CN_}+g-AZ*SuF>)Vn$--gNgjlBodlONZgf5~4iOZIq#iT=wm^!J;aqo#Nm)J#*Y*@ZENvRrtVszOBA#GfzZI#mcQ^i{@U$Q zNMP1{+cOF5N8{5F<~%sH-a=JC*i3cwBibceaf+QIWJ~eW&yoG2Cb_h{IkA6)RR6J0 z!BRwZOB@x|uN(V3`+NuDPVE;qX|ILMrM=yqk0L6G%fW_z{YmQc%Ioa)06M0sLP2Cpk0@<&g}q&zjK`9vfVl5%_&|mMH(QH?UXrWyhJwb* zOFFV4ZL|;GpMd{w4E*anLd38tFp&;J=HN=ijP!T@$^c3up~9&+Y?n*qEC#<&;;|Zs zd5pr#Kxh#k-JZEcO^ADX#uqTQf7K3Z-#x9f_H1SeGsp6|&8M9h&l|_2p=2a{iuiVm ziLv;~?RIx{+lDFkUE??LLeIMG)m{nIIkOP$wSYTYkXFm}886fNY^PVP%~dwx>M^Yn zOC-rNMI~Et9s<`nYDMj3Yl{aeVPd4rZ+kL`0B0de;*}sh1mf}4^74+1wy&ZZd@E|r zlw?wnLZ&$KQ~KS_S^Z;RPyTs6Nju69!+IT$8}uqzL|z7skM`VOdPkcmV(e}v!x^wS zEEH1nuWK2Le-PImr7W=dZ_ALhN`{Ky%OSWN`wbern6s+oIm#JYUpfReU-x{9XXZ#F z=6i?royoV^9tuhj>Z7QT3bVg$+Z|ja4r5n|M)f<_G9TQI`|H6OHva+=g_eE^zQyD& zmkt|@j9)53SSB>jo)xKWubnZ1&w)A-9QK?c*p;_Jb1Z%Vj0aorKmSi1wFXVu3hX5_hvCQD4Xw=0na*NHo_yHBg)HG;A(e1Z*Dtoh^ zaV?RgkdgEC130Q3(2$a0kYw43fy|}@v@fPS$wlD3n6SgW=fZf-~!l1q&t1WB}RDb>}zo&=6 z_Np-*Bih{BGB}*AWJoqsbq&olfT<-H>^w_?9hfPj7O}+S@oE_7>OF7R>%*r;DWw<4 zl>x629@5+DD~VJZcamX=nTTH;&M&yZFAU9dxNsv1?@qmqVii;Al|56Wb{R)SDa|PV zRaSPwewA1Dbm9E31Nbw+FSZ_x5vgW`Z&JPcOCx)$w9W_!p(?;2(GWMeQj9Cz7YE^EE68QSQI za_Tu*rd?*p4YFnt+B)k2aj9I=V)5qDYdpI~>A>h- zLYBYt?ii4RgF{?aRt(VAH*Sw_Ej{Y;5fS_KYlF>!csm?{?UVW1gD){Z1H<`1s)qGq zoy$Leq8^jcbmoQd%CYkPEBa2Bhd>}u=H})Dqoc`|xnD55T>}|?T^Nnve*F01@L}`l z=;uKWRg;OFoSdDrbCM-l6MBvKU(ARBLdMe>e9sA4ylA6W;RpuBz^>boGb$U@P1k?J z83-(xW^7oeTzYY}&s&yn`6 zwLJ40GEus~0Q%rk=P!&Vy6e)e2Nl=jsD$tfh%;d|7woh5Rrw>)PgX3TTsd6BsZiR_ z&-+fQ4F`$>XB%-EuW|o28?!UemoH!JZchy|xa?tQX}4bpt>P^P{-oWsh=$tksT;3N3wl0wtQ09P=@X`=(ocZ7GTn^AGWv--HlccA2W z;qm>)321e9Hw@^Vg?Qc^JLvSRhZnR{9|{dq#ib;M&9>KlPk@Y|0~sewY)s}PEB}A8 zOn|p|gP3Ug4dV8MPBZrmFE#e|)sU3d#(S;DjF2$=ab#RqdlVhV)^r}NS*L?nOQ+!# zglw-U3iOR&P-XpKu~20bABL9-cA$8y#HNfNKH|mzveu$jHdv0XF~ue>Id8d}{w#)*308L|Maw>C)MHTjE3+ zOrA_MfEjjh_2%W}RUm+eUv8}Y&%;9b~k;e+A=q7mO?L*vN2$NqR6idZ8C6AU}x>y9S%yi5jc#onv* z<0t*!ZRyWz<&3Or+-&|*2#LKJ5_>qoq7OtrIeqfR{<#L*sN!w+M|rG-g(!K1f#-NAiT1lTc)QZ}VTCMOIvYXEbxR z#vDsZT3Sd*2pHKf_5j@czC#UK`r`z?gJ=YI7aJXw)B!jNjum*udwRI(2PjVsg>Oph z|6Q8@4Q8NOniJBIeL) zK5^{Nj?wymF-*)72>-PKuYlu>6iknkx4ScC=dp*SE@3xa_0@3G<tY;REHD3W!Ud>tG8tTdCrD!AW4$5i!p(X@f;C{MWPQL5WRLE zpw+4Uo6o7f3?v_XdU=`XOMdBE<@@5(_=?3O1Cps$-u~=?hG{{|`Q^#@{~}C5SpTDi zdg(JacXw_;bWNRowVM|EhhB1o866!3I%}G}GWpywJ+BWtfw`^uabDMlbEoI$tnFda z|H>BU`TTRU`6br+%Y_c-DPb|2I`a&UwCcH{IM5TI-$64%$A9c9Fhakhi{uXdqC=pF zLmb`0J=3*z#t9+dkX!f~n@x7}ega&7 zUN&r&%Mqe_qkEUjqRebe{s`t4&HWl1cFUdd5$`(vzaB{i1{-{NHKQk82|}cxl1cT; z5ecnQ7pCk10%Z#rpwXr`3ZHFtZH?4b}X3BJmGpOYw5Vh%GfLfZko!vVnC8f#s zQfYRM*zSKB3m;-)ArugK|CWp?$dwGdDda7|G#5k^xGbav^?_l?f6YLY% zQoCfnd}%SjDW*ic2fjuV+P^B&RI%lZnj33r*W53;X#b=>PqyKaMy=#*4ev=gDL5s=}Zf3qQ}(cg(J@U z`uB0sA7uSI#sK)T1gO$bDJiM(QY}uvlpEc726b70uhYM^!-&iKy>@%H5f&b9Zm?Y4 z{IAcU%0f;zW)yVe(9@Y(4IJlILyofmuPy_51Jh)%VL*r(etwCK?fs<4UfTE-QAG}T z#iZ)BH^7mWLBMA6RxC1cekC!4f<-muH3Td-A>wXGOmI>&u9Q5X_~5au^I{IrcGtxc^6sLHI$2 zMn)#8?>s#{QQmS@@avq_0`Fml(9qbJ=woKTIM$W{{=S#by-EgB`fi;&e1 z7#+PQxdhp56!a00CMmQ|c8-Ip*vmu1>(Q9Po_}mxA8Cc>jm@0>Sk?yuQ>f!4#2Nz_ zpan3wTEK4AZ?U!kHE;FDKS(}^2Ig#|W8o!m&U7oPt1XlHtCRtp$Aq-g12=r78IbYw zx8=(PKK+$4{k;m`sr_?p1tx5n7z{m1v={g12=oBU5!69chY#rlus99q5}si`m`Bx{ z=|im0&yDtla=Vv-6o4Y?AF0ykof=Ups>}CG7Gr<|{|2*SZyC3uQfP0m8;GV$*FG&q z{bRYUQv{`?B1V|jj*rpiQM3O*L^Gqhqb zczspsnakHKP7blG$!h$=>1)3B|8jJnSj}8vV9R22xYELYEW+!fU4DrfP84u>vvD$@?6~2a1E%w zZ{79*`vJB|szX>^U7etyL)jE2TH3Eia$;hF%jFP{$MtxzA<+KB`ir2P96rZWQuJhv zQWXAPK!w7^QYA9-@Y%t14J{-s$L1_4JDXaR` zMADHF;MOyFV+lP`Aq%>U$EP)-IW(L2cz~#SZ#f40zjN&8FSs{IPBSJIS}PA#(&B~s z+6ypFpbS|Nvx`8_3!j+9OZ&o6y2zK_gHBYlg$YD7!>z7|+*m;5F~qd*n(*yX{12ME zM}sczQ1Am`QKMDr=h}m3nr5o0k?gkJa^{?4SRY2zMKJwC*j)>Pmio`I(VY zuo{UdCknL2roq>crbhafy`(^oic$x4! z10t1A1U0-IpCg}@?5BQa;qgwja-=wD{U;nU6aK3J?BshU!b|`h=V%eZy9X&rNwW;- zh8c14)2)|ZQ*D{S9d7rVL)nfSSP_+X*h;d3u+1+qgHhh?I5`RlyXJuyu&071Cax&q-?%`M5ocaZ(aJDqNhRT;OSFE>JOS>?C zeGp_x=Uf}8ik-OYn+wa}%WrHReg;ziaVf;aEG`mLDkFEzy|?a~019DLAfX7|1+&rc zdV@HgLh9e&%&kyS0e+mS4VsS+%M1e)fuyJ#2TyOR*0G!;)-WOmxNymi`QH*vI>}v~ zl0UbekCw6`KN0V~x}d)p1cucQ&baGu|J1E06$ROEtNVMnm(2=Yb)^YA9Zowuzr5E0 z4Q_r;8H_@sz%-{JN0Zhqdb~JZ{~S1xuw-}eiho@|Ao|8=a(kuPZq16+=YbkEu!_%PaJ?fy$SU@ze!3kLMX7!h;Nt) zp{h77rT7-MQYgEKwL9#8FkDdLSEc zEk#OObCYe5MjvRus%)RGrzEBT1P5Mx&tb$wP4)MLm(!1l;R%IEl@88tkf~}&{v&`G zmjqQ+U8YwzG^;U1SbfWB)S?&8*w$uEyS`G@n8P5Z?cM5ycC8qv7jqIq zhY>a}BtjGhJJp$gvNp-7msip-U^qsRg;(!InGqPkFzsltKnAY0VFWnD-n5hU(iHt% zZH6IaHn!DOQWuC#gqZt6lQkdkc>4&6)cwQUw3U3NHUWI3RO2v+>YlfdC=k{lBKV=Q zip5_O!>nbXTC=e;8h}KzQP7Z5!sRhH7rQCv94FQIIU?8oOW)9M6n{EKU!_uCICEOc zTVdnqhLa|m$L4-6tpL`C93vEgZ$Y)yBB4x-5)49)sV^&Lk2m`lZu+W;tod->g(uY1 z+FML|-TlqEp2QNf;W{RcRZ?dcYI~`!uJ5HH7~v_{gUAEL8#;hGVM;9fVqwVc%@5Dq zv&B~|s1u)B@6DKeCM_|&SpHa02Mjc&-$G}O$&>3;mr6qz;(INan)IU5Qbr*A--;>v zIj!h264jA}g<=SUbXgdMkTf@c)#v=Xti{PcMN@#+xk6&h2Ch=nM+pD=DcyAQ`ZQ;> z;fzNfWp^j2xIjmhVG=i(x9V6AwKXk0$y1S(0Ru z9nP1e=;4rzo@<@tnMiRgtDuAf+wiVKUgr10V|_X?ghw!(q#oIESji7wk{=5Hl2_T>qofUzdUc8BHTCgxKMqO&Vk$?V^5N_v zej28@>ps@H3)E^rC~rZQnP?n_8{#`19epmr54NPBfKc?%OmIISxY!|bL)HGYqXjWfiZymNM3`t#~@bL5h6rj8iWagQPP>o@SH z{Svqao!yn{=bu2rWKpk-Z5mhLu}quD0j&dJ6Hm=|R2ex!#*SXcWY-7t?+?b-*1_=E zXz%u!=&P}_+Y+Ks4O4#oCKKszB4%X~Gd?#%A>dphytI%cC;geW0lPcdY98p89!ZQk znEU`dogX3%C?ewW#hb2BQvWa5i59fCuRKhD-cHod5hsY^wRs2gyUeM3M^E)IjLt)+ znH0I&G<*qLmSJBQLoS2W*qvlTct`G0uJliH1c;Xm!~csCD)~iS_C)FipuVQ==fLr|OR{a09JxTnTYK)=#@d zr5lY=cyLv3^G?;KGNw=X^vPUla|5L@91X%znnIF^0MF*@eRm_`%f}OMGtLb<>;lt{ zVrksGr3*(xBSGE+`t9X1Lh;szHV2Q7E3|n%d$#TIMjHMOOX#b??$U14PW@aEOUJ`~Ehh`e4OmC5WZzqv|$#<+o$aQ}R1~F(7!O_bSmHWDEld;LZh-u5HV9-Ru z9Pt<7^|}**=V$?nmyD%N)GJ&EP2QH!3&yEp`detNV+HGQK-?GgfP~Ns4Cex{27W#e zB)u}J+-2`Tcn} z8S262cq+o3P}Bp;9OG?dT5!?r)*^L_iq46%ii!8dv5k!jk{G?_q_dE=o5&?~OY&5R zUqR2TAw}=&Je5kao67f+(u6?~ud#(0?RL6_rEF&7tF?O-TvONwvf^D4-5lr-bME6-kUal0be*5@+r zcW0N;p2U)YVvJEG*Hx{F7MhaM)rQhG?0I07m=*3pu8!}{km)AwHvEutXx-6Vb#N-j zoQ@8CCJTnm@A=(kVzzJ1y6gBKWcfraqk~Xl46XCnF@wyiRf0fshNpt28Q`(y_L83g z)d}pMWt=4xAf?x=)f`@-uuA|FEIbNx?6~ESSsT z54~;l>nQ@qDF0h>*YGghQjbTZ*L(K$G}38b-7KEj$U`sV$(tNvt>*i5C(iy^9cDwlWvic9c<;H+BVEFBVqkxCbwE!Q)U5jsfVFu>7Jd_ zn%l>T52&~Yx|la+GgC=A{ab&q-G5rHV=$a8u>RU})zTK42_=tGV_xSxbx?}#k^>r{!5K<1ji3Q0p z=8ia(Pfdj8Lpnp1>kZUhZtXaIUq>HBBt4?A(t8cMj8`yg3x(ww!@beI!aKWRr)OAe zn3=LN?-!k;j9!)lWMg5K) zMrVJzE_^&pqp#aVBHVGp#u&Um z@A7z}4+mTWY1g-GKHBEf-C0C5T{yUcr|Hd>rf2N3N!%x$3DcR$0bh@J?z_7|S3||r zB-qSb?fJ&WLDnMy_m3Y3q9etGG{2Su~h4wNEHuT;_! z*m@J${CLnzns6=XNdaN~_y{*4^eIz8HI!I2-zep@Gf`UI)06K}+fQRUH0dONb*KE7 zkZ^1xGk%Z1)Lq~h$Pe`Pr2Pvd0tcIT*XQxZUf|QJ;2f8(8<%(l`}d!X3Be6VL)B7_ zBbd4Ab1zqlV@9GCW4Y8D_I1JxIVw&^M`4Z3a9w&~d;?*fdG*?Hyobxram;0HQ@6-g zn64v@dja51?3{Y=@Zv>-Z|S2#-i--hK;3)pMSoe%B-9dDXVsg`rYLpIEH;ZO9;CpP~SC1A&#|5ss z4~LT6eQRwydVnEw>pvdc0NR*`2QKnd6n|=xe&E^UNT8*D%wULSl4< z;3Ji@`E`m3SGr{#>?qw2y|_Ob(ujE7#ReHLk}sr9{oyppI%~Qxvy-b2k^9G}8AjhrhQZxt$b}FQ3}`SLu5Q z(ofpeKzqOiO&o^Gfo-v)NmuiAD&Ti+6$s+>ouh@>qU+1;CInl=LqV0Mofqem@?k`h zk`Pp)LWo!C%jD_o(3suxO!gN0rTmTtXIHT&y4B;!QV|r{=L@PRtx6?pqrDEfFj8!C zQo&N0FoGEGI^njOx7LS8fIJd@d~g1M@pJwk3HoSCz}@RSOEa{1<%0EkOVh4qQ~9VT zw_qhkQ4sa%&XViEg=PIw70m$G%L4OkyBkJJlgsOiXYE#1qRC%sn7WVeP00S_^LxcF z24l!$5o2>`ajU{Cm;&0@4+V=@40^?;xEA-biGG$ZP>TC%zS9j%h?w71Xv&P@^DM@N?5}QJQt&ikYTKPzKNv;bdg2S#`MhHI9tDwndc~z0 z+$}0iI`N%S+TeU;?V%tvE2;@cH1^ol0WFTUgV1ew4ztseP9k0nG!G_r>hef9iNFEm1hKMYK zo^gTtsbopKdO(%1S+%m+10vFI_%Y?VP-Lvi$5IM5MZaHJFsIoKT8GbhgEoS>uP{wj zsFER;w2?v;c%iHx&3ZAV+LM=Q*+R&YAs$0Wic@&W_uosR@Z!xetyQK~lC!zA{Ynq2 zg8an77=w2GM8W=~9yYkWF}3CVM4B$;?Kp<~hMJr}# zFx3U&LnIcPU48cTYyG*RMf`fGNmWs+%Gyl*Imsl36!Be z!NodsuEsL~{a>v_xG?FVqF^TM{uOn(yensx6rey_jXfvu6Xy z{ZEg3^(*XEf=4aokN+A9I=WJi#)WzD#)&-NrrG> z@4jq*F>YxYIOQwRE^c`Nnrm#DHUj99Ar7|XMK`B8hu8&x5eRH$PQ!C*Teeg$Fbg-7 zv18Ibo)y~9IkSDR(=JJ(SqL$N@4aWN#uRG&6;frapo&~|6O2GEVeDEwDk;ip6Ghs* z3Kbu3^vjL&D!;_u?CIt#LWMRNB7=(+MB_O^qn5T6vn}XMuXf;?`l;`mGyEI|X;7;7 z4lHdl39&hfhhp|pGdIMtx2adB1gpmAW`E)opXqfrHgS?`z88@8-i`%M4B#HH4Efn7 zfln^M{9m5vs=WEmWHKDWCmxn=B#b5&K9W>|ep)x(YTq0llT4eMxLxOiT23tj6g~M3 z{;w+ZX8}=#I#l?;&CZdE^?-Pl)iFqEccL#cSR#O3fX{*J1X}d_Cb5^wU?XPQ$_3Ob*G$A$Kd=02wF4PwwFcOJ&$fA?Ww% zz>Xm5OCAbkBW~HoZVTp;u@2P9U+D7xT5wVtJU zZ{hb|z0fXn%%7lcaPw#cR((*2d#<~h&+<6L_6}#?124X{R5#&t{D;okOh! zSfHr1^_aI93{Lmz(AQQ!g{U#OMAGoS$F!jpSm95i;~%N;2!ZfuryE208z_~cq`RQR zD1-u_dCJR8A|d&Ko>z{fXCktP5%fz6WH9yOve#gs9nmAehp(>=pqNiw&%!W(w1QGUSrndRbJRg1`(3+&Tae<6T1Cq{BkRLcrUe% z#ly*d&-#=n_VJ5#Y+H<*hkeCRlqjbB5?1tWs$q#6HNJdHQM=Ey&ho9RYZkcp9J@PvZECHFPb;o~4Ga?XQVrmfFY>@_DU6_?4HqZw`G%#&F z5Wq3et)hQ+-UZq;@9Aq5qYAVvI~UAQ?^c)&xkT|kg)yllA%#I?k~zxu{rSoOd(Gcm zYb&FQd(kTp_t!7!({!*1Jr2?5P>gQvO>^F}Ls|Uy%Nk#EKR+xmY^TsqGmRR0i`FUg zQPcDP;)dNx@bhDxhzA_Jo6y!VyL!6<6)Mu`ie_6v>byjF48b?uB$Z1$;+dO z{frOwH$kIO?>0P2Ri zXm@>>eAw}3^sLp36}#n^k$bDgl+IcP5+z!8TWF)Jk}k2b2hmp$gFA$dGRx14m$Ou!To$GWo9q<0!(n9OV-+UUXsM?j&=Xj>B&}e9TT-O+fW@tq4vLM=`R@x5X5gzT! z4v?oHyvBb|BLWLMouDWVheR~Pz3&_O5u4wlT1Y`0B^HfPQB|8F2;QbBEO6*!m_nv= z>y-=3OueB0b)q$-f9VE+w3|i&;%kEQFr(V@Tq~xE?&+L^;-ogOG#%be>`hYbSCh{1 z>iB4Wkna3s9R6h3T@fxEBXULYDevy-=@+uNcH;B?gD$RKtZ- zf}k(9hugV-uhr}%dQ$>je-R{o<=T`xKrR-3NJ%S!*6rINs4;o4{IK=#)m{z4Kn=h7 z3Q?*?HT}6}=Ik#L_wUNM;4lT`kCYor zk&yaN^Yx6DQPiZ;!r0Q#yhL6Ro(^0`k<8=dCzEdm$!j@C8KnYfwy`^*rZo2Jfo0`jlFE6snw zG#J_=CX)`-8xfzXzcBiCO9hE)63hOb?C<1&1@jr-UcL`jr@uMl8@%gqw*`)4Q$+pR z4QrNfMGz8;t2D?U-rdYc_UkKUxBJy$MPCD0DO>2O3gQKYEL(#c(uek(Z;qBBRw!yw z?-0N=8yz9CZ~`@k$orw9gvKt0Pv`Ap6UDqJyuI4(-Z!6M`vSdMZ%z>1N#}@aob}oGXW#2GPjdg z&YWIFc_lDX1<*Y8#z&$YVTgKO;l-Rbz299|>L*1R^Q_RGh_m4_Y0Q2WTdHZuIcJ(K zAyE7J0`=b_j+`h|`-K;!F(VFw9vl_PIm&?&>m$3~2V%(Zq1Lxuf0!#v!_2aD%KrR1 z4aJ>G$7jArK5teu--eoBBXAPQ-W1KMtgp=a_dJHJEvSMo+MjY&b#9FaX^dVmhQWV$ z%AiAmz)`^Mz4Rzo*uTSlC?=ddgD|yOgp!?wsWJ#T$MCly;FYvX%;7Ryq)SgoY&TX{ zS)C#?zX_-OKF&>pKru-g`8rMbmwZ-Sf8w4Hy`B9zdR(@A5e199Y?be1z5xB%tC`gu zy+jQ*R=MoHcoX7C8OpiYhoQ({YKmq6=1O7?V(v zO8+mt0sEFlM?4D~*P&ka-Al{0$AK`~S>7aY@+-K}@U~%HvPNU8Kqp0jD3s-02V4&>BD`!YwU9dw)0 zgNtgysdHjJnM8IDVGm(dvw&c&pWrK_`rj=z^Q`{pe>@v_)dtM^DB#>5=t4wn%=Tmz zM3NAXkinpUlEj2Lp(Lh4?tC!!s$l4qoVCe`)Wk)_!lxdPL=jG7k@=|=wrcyDEIC;} zkvo9ZD^*h>e(fED=*wIr?%XwY9yhVT58SjB5)fyBxMfRQ%HE8UscaBVf%RR+zj0?W zSa3JBQaq*CY9f+?W`GBvGc5?iF|-3vI~US+uKW+BUS%ST&zO=xq7b##Ffnsg!lO`o z2QcQK=&A>3m04DQ6q>leBl#6VPD5BR?aUZGHpJbfG^h>htQ3n&oOyy`v%hC~IvoZr z-v}TewYj2|%)x15zw@2Tka%~U@EQT{y*knxBqe2gtF6M@qxoWc!z)~IGAv9x;|y-{ z{`apj6-cjkmRbu-#@fJ?D|^ISZ!k3)LV}C8hWs5pt)tP6>9-%JM zDy(Au{^U@iIDBoO2Xx|QqHzk9{=gd$6y3Cud_VV#>dZ)qFXQ9qV|uI;`Ss)xNW-To0}PN_G#ymK z&|5qaFk-Fy%ao|Ka`gt#Qv?d03ty7YoX`b*&nQLU$qD&*)~kNz!m8?<8i8N^!G7sT zx5BmI^6UIlvqSVF6~@q(k&Zpk>PXTlY#qhQX{C{liutBT4A;MhL@aoVW}rMRuGfiy zxP9oPFnvH%C?N5i^1^@FUtD|#jkzFBQvk&#|J)+rtzIZ^Ndm|#FI zfiR0sG%8{7)gY7O8cEG9+{y>l;OU;r;Og8?8{0CvynVQ1N3VdCyc(OCSq7UdQQPY| z++9J=d1E`gcIaz1Yo)C(5luSCq+|fs1lEvHImvm?7(Em0Py<3PG0Z%qJ^tB?C)ivP zfpefsS=`5lyneQBiTL@q%-A@+Yp#)H%Gp>6In&=s(|^U*I0$a8C!`=~|AFY(l-fjp z{~pkJ>m-B>oseyLcRwRlJ@3LBS&xl}^TVKYSg57hck@a`c&(?VilFq*IPzyX2s5mWx zRn>qXk~iW(fADaT4#c|E*KWJj69Jp}PC6I-+sDE1()t1u>ulqjeZiEW2&mgMjsGA^ zr|E0$1kPk(`)POrn3~@dcjm>vW}{!<#OP1y@XMS)jggAW;qF1Gzq~+XyPl@sBzfrB zj!u0yKo!=s?^}q5wOOWr_?GifJYviA4-F~6z7v7Cii+G9;jaV!2RUY)pj;Ujy{QO- zqOYoj$7l$+&E|ARth_ox2ABVPdap}rK zhOwkfrorJYV{)UwakOdj19)`nhA zEXKv=p#`H}auArjueoRmHhAt0BHbj?{~9^|Ya0O_lk}*(aRvD)>lNT7o2BHusvH@_ zf;1W>WmIS^i*7o!B2AGXRb%w;>*qXbiqoM4W$d71Y$X5A?DVR$bTF>vQBzt7$Nc&I zTV?T>e&Vz4W{(g&$8|Kz1L>LaiFV_qezu-&Ot>B8#W*f{5>tDD6bD&m|CU-s`^(FF^`D@OsYJ_izGeO*t3Hb%%x^A(I??j^6G5*4WQ3V$=Ik<8Q2kiz2>>`#Sn9s*SW zpN;63XSBsLD~Vy2mzolbcCmucM~gvGyM6Kg5W7=!{>1g=HE*uX>p6UJd3$9h^Gnxz z*6S)EvIX%EM+v1A9trPUKI%(jNNl28v8*sCuDUQ! zdNQMHeY%WY%cE}oXb@IVG%qrgde(UmLX7-pyov9yGRuL@iADJq+<$Z_|Fuu+SSUm) zVDdt)oEMN%9M1lKTz!LoUTw2=)S$6#+fHLAjh)6;V>PyI-%+E+XspIg8r!xTe!I`} zp7)&JcmD&~*?X>Q)~uOX%g%%8+$#e;FetjdJR}q+FAirv@T9s-0Hv_p-?i4rv~c-{ zjlk8!42Jq+hn{Km%H2;RU%_?0Xd*KvJbRjwFJFFKElC+2`u(9TDoWkF@M%dWsoR_D zV;aEN>Oz(XVw1lG_T>M>J)8J@Xr68+c+2N{D)4gpRrl!hzZ6i>l|@u%?m2+Ew%D8B zO72MlKK>my{67!eJPXx35c?}aJ+I;y)#)pK#QUlGWQW(Sf0Cd7HwFGxevfY=aH}Pe zK#7dae~6!ZGdF+=l;lvRuc3T?crSFy6bt4$cjk> zSYkBEsH|rX?YhG9&HYwvn(BQ?5-1f7arRQZ_?S{50uhy&UYHhV``t9J#s$%=p|k?? zJ3gB|jnC|y=H9n&B{2x)bxujd`2-zzHw@D34}%TF)IDtK7?Sd>XhFF?Jq@k%2X{x+ zH2nC_*vx8!W08DuCV7>@5B%pUqt;HF)A@x%@>g{)W7)4ph!frql>+Opz4bIB!;*tG zRTVPa)>)zFif8G_{}Yz~fQd}Zzrz+4D?Jnci!B%;RcRWHIVntvJAe_3|%{lKAN0+MY?UwVw_WuO;+(6h zJ`)psN51EEFRz)eYJYGdQ$ds4#5at};P%=ED7HsH1MUmgBAnj0Oh0|=PhbZBiNt@u z@>DtOEym;(S*ARv&X(d{VfVxEvZ_7FW0BN)7@dtMW-f2sp_fNO#7LfU(1D$UFRaGpUn{G(OaE zk+0s_`(qB$4>Gkcvlu)uI9%+iBhKjCDPngWRh{L8vs>MiJmUH(nCck|8- z0Kj$g_Pw*J(NGk(IsaMp>Hq7`M$@z(#qrPR;qE^C;#-N4d~s*(#_-Pu44mW~sV-4)A>^lD#YYR9^r@z~Y)p z9UAMFV$#kkMD)iKllXgNRK?A&8JvH2&Hv|4ntFnj&oTAb7t%~vi#3-4KT_pz9T{tL zclEER*lOY9Yr+}TjBJeBpKcNtI7sB#im=!g9{g;@t!IxSZ_|&q``eX$oZZB`S>Qt< zRc_C2#pIS|twMSA9(M9pkw+6X{FJFA$XN>Jb$PRo_SaLy$guIw?Fo+swGB^1TG`wJ zH%vl){OJ#^QLejBY&p8F2MxF)abLfQJhl-R;rQH_x22x^ABz8PauY*?#b?(zV*tn z3v1mw=<nkC{XnzE7lf=nKlvGiJL4fvSpX zbHcfTZlD*k#CP`SSVYA8WiMs@lh^P!wA?LtZ0wZeO||SR zY=x~(K?m1anD2CF3^9f1ZJI7{^A{KisYy{hNf@d6OcSuzY%gHdw`NDL^4?@0BV&Tn zAO%*pb~NsgE~!m+P;(Ng1{Eg8LQ8Pi`&Q6<*7Xlj4q?1>b>)7k>!!vhL?kopfSG5) zk4OC7_{cqigwsLGz)@TRcHRkBrqjlI+tzY=Z; zvDFCk zH>C{;7hq4scZaeCQ-n`KnhAKi1Q;z89s@HZJOAGd$!Ei5Q*MSoEK9bDkbUgMU3q^r z`_8{|d01Bw=Xy`ncw z`u@$XRttIR_31V4DS}s&em-7XySR>d1WiSE6#XInrDCjI0I@f7WO=snWy$lc+1w2S ziEw!E6SBn495%$(nb~7|V!XxL6GJri17&+CKKAS!b|9?W75V$TiYKtO?$Vr{tL8fdP_qUBI zNanGjbK~W%G3)vAe4jO>C<9*1fk4bH(or`lhHUcN=Yiz4&+#-}2>CDV>V^Ev-XWQm z%=`okXsMF2DFqLm^bW)fCMXJufAtn{6ME(dW%iZpkfKO^d@lZw0==*52F}mTov=p+ z4>WPb`ub!*-JW&5(FiZE*AN&7`y zZNp5F&Q9@eFX_9dUfRS^h;0PEuTSJhc|MEu`$|+iz-(*2V4c7@K-o(3dc*S8);=D@EU+FfVVioIy%!M(_;Xx&g2t$q zCm|xf8ow`-F+1BVOdL8LfJibhslM$%yQF(^y2OUcpSd1QmOB62NuQ1PFHUD{o$VJf zg}%QjYf4L>PnCPf^cl7KdP5>SI!Tys#=puxm!9$VL#dpu zS)mF^UwLKphDrCdm?-&&cieDCk^ZoIUj=kA0#fC=FHb~Ab0EF`?zYjB)%>}1Tx~JU z=*L|XH0R09Qokd6Z6ox$nk~1FsWQ0l&cRt}Yg5iBc6|A?T4OPNQ@1v=!EL-0$|$*T z8wuM#c|*)fSMQRjsTDrV%p_@48!kG(*ycVt&=By{-}N1b*BJc$b;3uh!?h%1QEVkv zoH*&}ZeXnEm8B->Q8dOkq&k1?b=`@e6UAiqDJ84AKZZOMC*=wbs1sbtH}?vEF(N-2 zM#Dyz_2+%J^;!|@1dV~|sIsGlH(LJ~QW9n!5v|#+fPH*CF=Tdw^HGC}Y=06bU{kq! zH&9hmi)9}~?1i@TOO5@VC@0LUO70j+Rs(9Kuf8kgG7M>=KoPMAs;M3u4!W?6bu7V@Hh zxzqO}b)3(u>Qs?1`M~dWJDkHlW<8(H);!V>pZ5u zftVx%aYj5u$P%83VtZinin_&2Q3=?FaFN$+h!)MPq8|ih!2zu^_OMpbVN+%8tkzUy zqQhvfi|ZbkQI(=ileJI=(#6`OhsbnFO;cQ3X2BJP^iq1W|L+RqgP_23fRAGt)k5KN zYwwq{6TjR6S>z5XpzcQD8BH0=28&K~i!zMzvUGMJ^&U}Yht0zz0J z85tl$*PJBZAnHOSI)#tHINQLc&M@{X%l_sO9KX9eMg-#f#~H*Wu%|IkC}1tn8XH4R zF)$ImqDy#e|8qFzHY}hGxENV`t(vIb^wnsq+%OP|Hf`J!qb=9-<57vi_Cf~xCeu>` z+Mf2oWFdtR^0{d9-;rCs*n7}(j=LPH^m1+C_VN)h6N}nUb^{K_Z<(vV)*5syU&+*& zd9R%1+-mWz%cF<2Nj(JLV`935{_!<>C-(_(}bszIo}fR zy9_CmCoU6dKADXq(sdG=NS-3vmsxQZ<(0RQz6rawV2_Z+-y15EUgs%-(*OlSgmbz3 zdy(q_l~m;qVSrfZNAPK=#`RnOU>1rR-kM#)zmv?v8wQbfG-7Z*Ofu2z!r?3pSX|}; zD#*mCWQlp-<%2iOd=kC?Eo_bf*nbl_J7xo`F z|3rCgWf42x8b@o7f4b*ryH!%-*#3dLeJ{CSqxukjXtNh zlc3}FOSCpqEi7jgf)x9f^+EN;~h{iFNILz115c$36G2m-^SQA_W`p_s?v?$n&#+rxa+;o?k zx1aZ**%UUejbZ91-a=gs`=!|dT%+pCuuqfyM()D#4*@ZMQY8e~_>thL zaMP(f!fB243F68Do>Us3z~5brPD&|fQN#*dg%f`OZ8zdJX|Ph}9fRF5p>mEhS5&J8!WAjFLhoFvQWh z97)GNUbE{iwoee2lcHwd)BRbh#@XrIUBIl`Jjz!b{{^|K8m}VBlZfcVo*x-nUbnP^ zwt@YjCDiHlg=Goc?d2R?ot_-YL-om6I3O%ewZ%sG<|MWp7qh+YfLb%Jm=y{K0s%Y} zObo<=V)&fjE1c3ej6$>Y&wCj%T5J4_Z43|qf9%Q*GvA~2N{QyBW~p)8VsFfJ%@ROab!TK9r#g4 zy}YlC;1G|r41!xtoQ(7uB7w4$*eTKerxCly197Qkno#N8oQGwLF{jiQP?~O$ny@&m zbx<T(l|^Q4ov z3ghj#k`);#QLp{Rb~uwH7nihBIs{_LBpMbr;eo}E0_bZGW8Dfam(?cp>?{sQvZEsL zU@=i)Fyrz;RQ}+F2w0&U_fzQVxMv574`j0OPB2?Crf_5l9&Sh9uVAldh*0(GFqv=j zr%zkRLQs$6G3ZAgPW$hCoTo)Sf+z^`r|o07X zx2pIJay#j7k46)uN^=k>x}XeNpd6X?9VD)Q=hoP{jiDIAvOsZ22v1l<9e>~4FuYbC z8E0efr+`u4+k4vb`Na?&15&1BmYLgeCz77oMT=c)VU{`9=xU;fnI-fc;Jtft`~Z#I z`8N_%hOzCL5(&P&Hh-B({SLQ#BH^pwfn626!t6sS=rwW{k2Yvc;pdXorH1CM)naRu zo7egvy_F{!oIGP%?D@6$h|ee7nf3*) zdy$(&Y6sH$Kg%2H8kYK%Xtr4_I%aS4^=XFtv0V~>oIavEy~1Kr9V(h6(cVx%Mess; z{kr5D7eAxVi{7XqMAGkKls*4aP4(m1IGE;a^%phE{X%7Ya3qE&t1*s&0UN&}no-UH zQvfx%@xgmus1F2W7WatULUHG*ktvs7qi=J5j9z?{^!p0Wy=I?`CXT zM+fH&1yz+VyZuHKGg~?ObYvm(cD4|N-?T~ofE6ZeZ-As-3_YJnFx_CuJOKeuhyXa{7W-wt~e1bQ(+31URv;@{6x>#usU&Z*`Ab`H7VO7xe*SU3;{cu1}pC4n#3{KstA;gU~$A7kN5i&4)bdU5o z|G3d{`X)yVw?R@I(y@sNBtpevap9IuY(|}6Sy5UR+eMaW+Z?ggB>K^rhB)DkPM@BI zg*2P=%PyCr#Cv`t##C6Sx5pi13g^xMTGj708_R9k?U z7{SL73QdPN)iPPy@xD3tw`RgWC11U7Qy=IsqDWaD5&Qbh0&vRqAEKIBkaB7e_Mn1Q6l@7sFHg{9m#=PTU=!I$6b z_nOP}lW{OWCMt7IjH@GuGmtiv9wNZ@`9yaR@*$AQ7-UI4gR4O2JK}E>#n0k!w2n9M z!ZJ3b#CmmrHeE=zBN|hX!qoL)d3A6gYywFy*Gc0s(ZIA5@4W8xhhDR^8GO-{@DBB$=jWJYXq7^;tJ1Xv@q zf;d`QfuxBz;STu|Y?n)<2@ujg0ka50-fnMj?wU+6S$LeFwWsmxIY;!A=n;5YRMhN5 za9ZQt{%iL6_J-;&sj!eTq&@K&_t0ajYtH>4u+(MK$^@PP=Tfa$A6V^vrmbkL8>38k z2pPnJ{+Q0g8?~REckhHxKFUl8yV_*|wq?|M>FTUkdhvbu zrnNWYf%$-aQ$Y#qhowD2<)?<{3yZDj=G`W|up$OBl=Q49$k9?f$C2ns(wza%sT07{ zvE8PWF4d+rdos0V#z1vY>=UyhkgS@|x!FnZ)N?&li&;n);-wkZ-NAdUIOXw0I1DnO2Sz?&16&(*5O&LzqL*7N-MrPkwvb|9VNpJ812 zF(;yi=E7F61eytg*q!Y6GK8`ZrEFv@IBCD5ONGrov6frwN56D`S(l(xSDz%0vn#hQ z0UZ@}DyD53D9`S3JqG|I08q6E`&XLryJFr1 z?^C?$y%e#J+M-_FJ-mPSuP|gx(+CKTU*&87?0|rByWmBVOML@RX&>#GEqf0-o}+_x zk{cl9U2G!<$Jymw?dKb!pdcMf$0o!31*YbtYLU`@(?ng+G{n2nuO0VXYNN{(H;Xb- zK?;Q4353tbUzS3fr$vK49}8a#tdoZJ+I1wA?}nd@fNY8bAra6$n#OF@7mkW!`wMI! z1|R0rw_BR4Nv3=0Bty9py5NX8@mnXCMW2IO{ zm^uIiNU|+dU{H|J6i8&1WH1^R^7ZNNH;cpPtx22viLR|pV= zaY~BbaqQ}?!pJ>!h1*5DvQ}{k3m8=3t26Vv0J}nP*VFj%lm1;%5APMJ4EaItl4!W3 zteom@zQO%*UdWEV;R+hZdDNp^@soXR)vp+)5#C(N#uX|1Eh$=4OWhoj!i@_#1D|UG z|AmW|sOen?#3aU|M!FBsjg)#{{O-|=lM*S9ynFXbCMlvAOdx$MRaFT9fu}PsvlUh; zxQ4v2hp-!=H?U58-vIv6{hlfrgWmV$Mz9fb{KW#+4ZT|LuAW2UH&kVv4(Q?1I#dEe zU51-2e#EGlFuAzAtCG{_Phuogd`K#)ze%{bzC@FlswZC++?RRpCHfKtcebpz$Hdl&>!@o1@HKyF=&+ z2?-a!rsVo@OiWBjSy)gCb1T+QV5z@7I-H|T_g){z?y#1VltoS5EqqtbDx)Lvx2Y$d z#}X6Pg@u9%OPV4OxbsAO$LB=%)oF&?-f=DnwW`RQnT^eR$Jgqlg4kz52+_#VcNl?u zc_~+C4Q{IZh((%YALYXigyp}lvj&)HqnRwql{&fhyxH$5$@Bfltlv&^`c?b+0)=Mc z73C~w$dMk7eA4FkqOWw8WnI%c3>4WVF4)qJF1OKq_?Cm=Z%OGv_qZ`N@^~B!*f=ix z-DIp-q{C5K?#p7vj*gxdnQ1BQ{b!4ffBv99@H%J^pbquKjg843wA(#c5r_o|0JTIl z9KF4kaTwo#ng^#X7>`Ca&VcXg#p0qLiGEDP4)4;#Aa!2ggLM(|)33-MeB(5Fa5vey zvQ|@jw1dmefoaL!QfZnoKVj%b)nvrJd5r+ z<)8o-r6vruMXGHH<>gL#?vKT7pi&&rAB+;r`PE2gg&!9)LBd)UFN3-9Rq%_;IVVak<#0=FM3W$wUb0tHf1V7`^%ml*>ewD*cu(MI$SuFSF z)v3v8e~uSY_x`L7L&6zy##^n+S|X#z>O9&U>gCuYc3hR)i0sb~+py%L zNJK&SlLkS^O&Jl3iL<&n*F-D@cFvZed%LHe(m39CD;i^>iiz&~feThQ&5D0ir`FF{HPU@Wx6#fe8lEom+Ou_wC zkSpK-q}Q~XY%^$L6xibZJ4^CQe6$2HKO|>|) zKRQd@%Vqrd@$+(Fqh#~6<>d12k#wrq**Tg?Lq$s8d*|DB(nmQB(|1JF*g!QBbDxVL z7WBa0Sls`dI&pHPpI`MHTwI{Y5|aP{J!EKPA_Tyn5lROi_@y0Qb=e2e1BcIOZ)fM% zSwuL-&C{JtzwciNJ(5BXW4GK8An5ZnB$;ORod0n4)ntc}4hnC_xtJfD*=fzJsN`2Z zqwZ!`61CA~usuk!P*Q?3`k_2e>jnST;g@|PYtl#YoU0A66(t#v5!`={?r9!q=YG!V-x){BN56EkWPtfj<4$n=<&Ci@HT@M$Cm8 zLJMY<~nQXp6EY!$jWc_2C-0zUi^;_^Pg_*+TeZ~Jc+s(qa79q8Bl6c zTdK5>$%~&NDi_O5$d0V;4h+oTK!k*Vk;`LX)&0-|(1x%L?3B=X=N4+gy#_HaoDV)X z7=Ki+UJcsL?ShGgxDUFsMl6d+6bmnz_`{QNaU?nSdF1krqO`WCbn52sKlX{RC*jwY zAyxs>(U))|zO-VmQ(E+VyuI%lcK+ebP|6Dp;WuK%5tSCq;KS9^WR;;|YR9TA<5TG# zj}1QbU;L}E?<8W9W>;t_in6^fq4p7v;33T@7DNlIqL&hkAHj=@D>Mi^i3p$_WfPoK zH;Qi5ji%qoYu+AtW1$M9z1>l8^T2LVbwnfE<+ExK_?f;zxwyK56uV+CPcm~NC)kxD z%n$Oywr=qy_8~ zj&0RPxCsxA{U^5okPHu%IN~rs z!&Zz>&^x6*I2Z~vS#L3Ec(XswV%QCq&S8Zn;P;lT`sVTHy0~ar_e&p52|BCj(xF5j zAQQ_2L%JtGW~Y>Q%jnm?Oj99p%SBXenQ44fx>HiG*c`sIqu1$0EO%% zSumNy@6H1e*66xkhynL(F^CY*D++Qdc2Yu)*!=lbNW%q{kPx}vygDQZX0kV#wh-ja z>q(YS0KpH2zEfA@odC}v63EB?58nKn*4vq3r*u+bhX6|eC4`Lmx|N^yVM&LV{Epk= z6A}6e!${YFgwT1I^yh6r*wX**WWib7X-@`lfdccXGU!5*iX+;)HxLH_qUOkO(}uv) z5I`Ms*n>CWypUe!%s}mlgT9Sk4{wNcq*fYkJ~|qjrJ>g_l~D1ck%4SX5fCjVpr60p zg$(~6kWmZ~z=o4x4uCfnzc=rGZ_AiYK&q3+c^^SOodvwr<)~nYehdd&j z?4U}x64kgDDnTOH*F}w1P@AA3&7OveRa+%h8o3>nclRV_h0=^BZ{3deAt^VbU-JW* z8qGnHUygz{VS3xM{~?|-%c0bp$Z8nN^6eZ=4QJYuW@>T^E!8j*fUy1jA1j?vU4~l! z@>e(zo)U(laY&#jW`y9>buy5yZISyPzfT{5QY-Q9|>+hjomZy}On8yd1d zX2^$5)tZjas|e~a^cn4Qz5QC^Fd@J3O>^BVE$ zv@3f_eH}@X3pRuQ*1mU3sa+>7vSM}@MHF!UX=R8`COAx@2U#_(Cs`(nltK&7r{Pd4 z^EWxIRUo56CL%i3cDMnVAq{7p35jCJl2GRxDLiYrmYP~ipQo5lO&6NAc zE0eztBn;Z3El9K)@%1>o=vKz~++Tw!4J+ym;)VoFL=&s>#goa@`G$fzh7u!ex!Wt}OU8A#g9^!9KX?<`=+ zR~q+|+Z!pFa1Yk<-5E9io$kS8&n>Cg*5kR}M>Ex>Kw_-|TDqWC_d_5dudcZJXPOL% zKD@&8G^X(2Ia>wy!w$2%HJ6p6dIaExX1CV7Pk zKZo{mk>THdWuT-aTGSPi|b!qgw;{2q_Dc@fksYc{|KtET{~GorOau6Kv^Gx zntu8svnQff=1=Xrl~BiMIb#uJozlIsq^x4Vn_gce430hoqnL546i*dl$ZoOV+juc> z-f-jopF{Laoe)8AW687QbF-fOVG zCm08obX1nY8{5&1CMkofC`nW8G`n6_j< zeuduC|+E5*lIn5>op@FlrqaUs|hK#&aq+N8^h$I=Uq(UB2(8PHBs52(D zz`;okk*t*8I?0G-@vFpVc$`C|Vsr?6|6Bt}rk2iHAWmukKL58r@%L&=#(C@aWaQ{er#G(PpIvkir;|SH6dnEx7<;6%kT{e}q)vrxQ&ZEbZ>eMqo-nF?h@^sU zg+?VB)i6>0Ydix3!xf}B$aA5}(A1cY|7JGXbg|wXaqQIvquqnVCy!pYESXwI<2H1_ zd0*^g?gVtT`a#KT5q9cl4b5KtL~bsipEhN__O0~O`3bUdr)}bYf-pYFKOg}7_Jmro zu1JO3etlPsW`46ZV0P`}C|d0qZAV)mT&$EOZYc+k{iINDktpx^ys*3nNFjDDwJO0F zEy+}!pp~nX5pO}POL&?$XHh#{WF=Fb@@QH1GA1643Rdy+Q&ERz+P9g9gibnXoMpWF zrj_a0hjVQQn(WqRrIoe%d!XK=gy7Y0zu3E60s*))02w@h;tP%MS_kCm`^9(Zo`Bs_ zb8^+|i?SU`^0l~qZPP$h@(IjO#zJlQjnyp z-hzDLM-?V=0zY?!T>Lx>az@SzZ~apzr;9VAa!O)uW=%$?ibEY>l~HrmcJZHlkQm~UgUdGk)t2-;YCn(F)6s^uWGN&k>ZspyVk5PsQ>U5e{X&S za5xCmHyIY6H8z=V%9KT>6rz^07;kN!_*FP*>zoi&OlK|=#(G-@~(2X#o zL%DoNLz`G>vV#|Te__`QomWx|m8O-7B>*QY1sZ5S+%MLrs`U6TZ*GEsO2x_Q<^A^V zZtJ4!eP6M~o-jam69CHrWI(Aigj+5B#*AR_Loidxyy)t3{svx!_35jWyyce#4T#mZ@ zvCcg(5XA(A*<79P^q)_)r z8P2FIHw$5+>u7f-zRtQlX>OJN-qs%rmF>wFzXY;!w zae3-mKVLB~n30vkuIQ#i{-I!8XGTJE16a!m_cHZ6I;UU1Wp$pH=emUzv1gzHBz*!! zyOANmycU;eo_Jg@P)+H|+!k(K&{OhzojM)Po47)bN2#U0IyBTxH7iov$n^{S2?9_! zQ)x|YfM8zH+=U1up4h@u690SkPP}6w6UwtSj?BNcM zLXzR_Ib2+Mdtt{SUn~c&;J(pQMa%j3K90670=TF@D%GOTKewv~)Vir@U`7I|{OKHS z&hkU#fY(6^@oASE{5S4I*_4QnSer%sY$hpi=oaTfTUa4{X7xE?(t4ycbds}CA+@aW z(P>k=SP{t=Wc4WM^YrICdxfD6QCz+R;x5e(d|>CD_d7|=_MeNlM#yyC2m6>Yqb#{~ zZ5AUA#=nolm_akpx?@lo_5LBemxNY15NHjZnAa%a#p;(4-PcVh)Kb3HCh&pk{w;bm zKQ#rm^k!wf;(Psw*$^&FUDA8dRZ0jmYWi>b4|sqK*nQ-7*vej9YV(lHg%Cv15YWR` zuExTXtRpY^=Cp2+$_*7A9Zi85J|r9~w(BpZ>?$B2U^te}ntj_)Q^Q&nbCi^vOd-D? z8=C&)ulvb7BH(jSM6+{r z1Sj6C)#cj(FaYO;J5Z?hyBLh(AC@AZz$2}*)6;2W-dWJ2H$Fdy&X-&qAA^*$N+!RU z1jEI|8;AT)m4f1NgdI1DZ-B{;b4wDNOC6O*i+ux<{qoSjgjE%`2mJ^jsZxWk%k_w% zJ8is~NE;#X;P2Z`;1P{1Fh=yZ<7CMEu{2Oa-df zKp<3;n@O5Ik|pHr)%&p(mY-oyZ)tH+SWPW?S-aEs6;GdEGxXY8ZVwpE<1gqfIn(W} zih36jHf<=)Z)tlEFjsFE(L_m?RRj4`f5(}MgvA{R2v7w1&07%a(CTPTlth1(Jw^lA zI&nxd=K+$|5G!9cYZL_y6|~@TRvsOlA@e_lP7-FC7EA4cRGA=VbRRSo70S;kjH+A) zZ&p5;9RAvnf*K9n-&OG`dW(Kt2MuCcxi~x*Gm8&U`&YKO1ub9aU<|B2HZ5_B31`8w z^agWHo7(*aK_P))uVM;ZAW!l|w{y1mWB)1Nw-Xi@QLG|XS(_^;Xd_>dI4jcKJZKKuB5dUUy^HvCEq0jJ_8)aa^B^&f2HoesO$lGPg+vVpO( zORgHU<+e*(!+z~Ai4+uRM<6lHib^WIB%FgcpTJ>HqU5cebF9PO=Cp zn@nIUV3RP_<>yzb!>LP_F@(Nc=kE_DqsnPBAH2AzCDU3_K`-ESFP}h!fzc=NZRE3Z zFa}F<pyHlCV;St2k>q$7%ySZKxrkyR5e!q6{>KbDFO?{k zVR2vlyM^y|dA!u})A>9pzTskCL@lfMBrNUz6aK=qVjvrQ?$Wg)&DwD~_HB~(m<}kj zGZ+!=3Z{P&Mr~Xivh8Ax$Qg^w=NQ-tQ*kKs@4OKGjl_wnO{HpOXg?K|*U_hOQpOh+ zGTtG`1lJPjv8MttcT0jsz|!YqON6g3s1iRONo?Kq)Hd zu%4r99FGsY4@V{M=6^(zx>eKVA7kSzj@K&Bp;@#@vnO=%dk->P&ycB_ZMQkzVH_(4u@?e^Kw{Ml2ni|cLk48I(JD$n80}B=0IK{@!&Rg&?K^?fFHBTC!^6Yl zXNiS;+bKRX1q?_Q!KrjAS>)#CCfWklA2p4QA(xi~*Zi1dy-32K0Z7pmnYixrZ408_rXz_p|2IOT+k;o76ba&)YIx@* z*8iMJ7AQ4fn%4*#GbhqsG3m%1yskG!ZjMk5qUF~I_G%Ma#J!TwS>N688m;F7%T!B5`y(+) z%?1vvNB6ne(Sxoo=Ucvhwmdxhu#g*}ew0egheXU>4l{559aK``W6;dSSrM4fDOl7# zObQFD4m%;}5h?qj2tL)sb;N6^oP@^^#J;yVIDH7CnZ9pq2Nwq!D6U5_Lc<;Y5mrIk zPGkc1;$e8i1kBQm{0`w-5g`HtISBhjM_UJavEy!gG zgX7bAmTnW{ElsGH2hGx9%&V>iq#H#iY)!Fp8w}~g%}mX(iufv?iAXQETZC3yY2R5^ z2j)MTPvXPKY0B>mp>>GUAV<;&$y*5Xy9k5DWB?(SfmAcJcrO-= z*JJmdZS(E*`SR@NMsJ#dFB~iD2Td<{1ccz9_MGGz6`3L`iBB*mPmf9)t6zNMjLgg^ ztx{pp0q&9#HQ*ISK`b&djgQmD<5yE9{AL!MSOSBQ7FyWkK;M6wd4JD1ILcpIQdWg0 z!5^DJ3(RJrYCJ{yi$7`dQ+a0 z1<@klX=Ms3egSG~ zL>LyEBIRucpJh3wpj4eb2^r{Z}~vcc)4KU=eW_* z5r;BAH}9y4D{GEhF)Je=J{mbPh(4KbG)AP-I9ep_u0Fj&B4A~os9_rn5vI~{);=!B#gDK|2!us9EHUExb&XUXl?p;0g>XWCzw8x z3UnFJ9#gQ)KSXy?o9#8Dko)4tlqyjOv1W!r`xwdLYevhavx{W89?q;%&gOWs#*ZwH*YBW$pCvRo zIsdJ0fu6!O3dzCC!DPSqE|=Z11JX0nqf=If+u!^F$6>pOqL3>92UPNq#Kgo)NYZx3 zfSD7E=@812_h+=VwY@zbfOAKLhE`!~`I6PL1}UBj=x=|pu{jd+FIUP+2VNQfvE7rF6CtwJM4 zHLT)GOWpjF5uzEnQt~tD@ibttTBYAX7npZ1)A8*Nt+9pL9I5_F)3M zmmpy_KkH-~H}TK$g(q5VmBeJ}dEk%~=k`&c+5UBOJYSll#GV>Z`#JA*o$*+L-uQJyHr*@Q9PH^Sk zvjyn06~&{C>hT<{Lcq91&%l`4O!TVO54BQdSo*Z&7P!Gapu4#&4pg`e5mYu&z#F1r zgBozP3yaD=N&K+fYH~eewTy!!6UF$6#MjCZfb**!Z?d!PIU%?lxA$npaEf#woe(yo z?Fo9J=DQi}V^7bIQK`#279#m|&R&PuG%`O~Q8TwLg6Zp#Ap;HsI{~v> zLfXZ#RVcxCW3b!9Iq1lsSLQGeCl##K)@&$8R$Qg73|gL6mSGFtY%QH(3B!wv=|_Ao zc)Qk2?Bmz0)XWclb}>C0Ou~~Q8iuyLP*<|&dOeZ@C{s)j$i(~7&#leP-Mhm{`BtiT z$Q+IQfymXIgoK2Lvt{THEpBIcFHa}cmzzD1a41eziK5nM(gT^WAH^+E@OWtx(9@ev z_eRsudd1b$FvKNg3!zwhgPW8r&MeUbV33`qO)%S64UdzRmD=1W?c9{fR%GSJ0@<z0 zA1ICTD-NRLkdR0KLbEHSd#VqwJ>+H8K*9f`>Ybu1 zjhe3Q*mlQO$F^-79dyUGZKq?~wr$(CZT`DoJ>NgZeURhqRclqvx@MIC`mxh?JtvG( ze0`3TtZ)<*s{L{k4WC6_!xFfKHr|cEFqist75(hvNnzv0dLo$ccB>zefxOZy4g7{Us6fr;l@B1weiO8n zXfwu&MsT;i&ub>_tU)n_JEkM|uT|7MNgQ8`A67wJ?)cb-BqZL zW&|JtSh7q1aKs*@5q^*Y;@LJQ3&Oeqb$u@~B9PAVth^56>1 z3TCr2tHjopD<|{QE?jFzVES+08tD+Y7oF!E#{mX)S681fUoHM@xw&+eK!8;)xP=sR zewx|eLH=r(>FT%H_8;&Cnqg;$Twb!WzofY9^$H!fJ2wJCSXQfapruzQJh&rs{aV%o zn8r>6$YsE?ctH`_t3sp#f(2TuHV<+P&Hn3E+6fTK!How8WJDvCsQ(JYRw`{wNDh)U zmJt4Feems@P~!6}e@Iwp)P>vZV}~U+N4YPR1K8rRG43^CfI!O#D<1N{vjBDvHZyii zRi5_tO&DCBfnRd<5v$-^-$YzpcQAWi$4-y@I`&M>fI-vP<0BW@c~JPYJE4<&xWFbN z3;4(ns-O3}gyVBlu&{efF101+DrF0&MVdT3vtqF1;|8sI86>GZ+N2Ecwpkg0^335zl_(96zVg$ zV~u}E>Vgjs^a1iVj^`a{9-+FSnk89-sh+L8w(Ip#ZJiW&{aXB_FB_zVC&%L>4ySSJ zP{E?QI@W6P=n~B-K|K&FfR}-@FRZ>1{U2)?|M}hb8X}*VuIzSYOy=~9!*L%0PVmSM zo!vxk@<8$zQp@_Pe{nFAB{jFv4=r(DC=^%>@BBw+n_mT!m*)kFVL^DB>t{mC@-(^6 z3KlcUg8r_z9O7(@&?F^qoe}}zs)gyy2JK|09OTrX@hEjICEp?_vq{JZ2xP>xv1URGZt8^^UH0uwMMqp2T7x&$mWn96E^~_B6n0PBt~Va35aLfm=1~l{ z81#ZVmgE{5r?%Z;AJLULk5XeCFkFag*+e}g3b{hyFMulTMfpir0_tDCR@t5KcNm}{ z0xYVy7nQdhj~!S?CEnQB+^kO57l+bhxeB81{YrLXAVM6zfQF3?BN9ktF<%rF$YA&O zV5ZUO&WbrGsei+iJqEcG@c>v4+Xrac{Mzbp!=_SH&=eOJrz1`X3xm$!bbtWB^x~6Y z6XWC3WVOO7v4A`?9LrCOwbNifcvb7%X|~Qbbij${2l%{sBp8$j_p5lXNR>tt*D=|~ zvi=(S4}-n0fQ(KhAt7=euPm6xG8`(~6fR~Bfcpj9J?~9ZF%2=Eom?IfLN}AC6@@(X zMDX{myhRwf3>ukt1^xeY_7$Q4mpD3&UWbMga8f=x7(icE>2!C>@lxU7QoT~QF+T|pNW6pEe0tURD6UseEMf=pFlA#YzI zPnP1dbK$rIo_IXb;Akorn%o_BW00QD$XXgqQ*HVJ*AVz}WVVgOIcf9>-3kZ;!pyM9%5xOqt{Vw%VOyAM!|3R@K&c|5FU&qkuZua{#uX)dz;qsRw!Yp5l`m zeU+s;_utVPv9a;@8EUQ9Vu>BTXbcOh2V1(k6Q9F56)!cf3*ga6vv^*o)a@L8t+mJ^ z0~A66#%MZjcNrwA1H0RI0F>7+5sp((HyhQ%**{>}Cg5&GexIXlS|7qIeIdmBB;Ul$ z5Kdk(Z1=4`x#qiDyG}Oxas%OlW`fi$%U__!^N5Vp-;&?u2Sk(U1h{n9(*?R`ryX~8 z=6Unq#0OnmWL$4vXKeDvGmy8owi{wnIRBZL8r@2B^L3Is*w@j|YAaXQ)Y^5iG#{5ieN-_OEh|^^qRCxifK)4z+qn);#&?b1c` z&*ijFd32MY-1B265Bi}h-VDg`N##2(k&p&C`j7nc=uBkt#5E%&o0H`6#`O6@9wqY%V+=NPOK_Az{HY#pUL^{zpG49#DLya6 zKp*;@yHG^$)$YpiYEfC$O(!L5tED{DG7RHlJMXi=C!typ7*@_c^n|$<>$&Pr!Tg+5 zuz4g*JDez?DErL2J5yM$_VnNw`#J{;(2$4V}kb&Ui!qDKcesy2 z*2D7n$SpJhScJU$J|4S%JHD+u?&Tm(vB{>g1k^w})a^vET&;i^Tx?G;@~J5SQV1n| zN*D)=b%ZM#eHhJ`ijnUHs*;uF>@jO2eV$|7k5XUp;VJ6zTDVChTeB@(;;RjiHVE)q zBo&2Lj#C`dMtk@fUX{6v3w3<~Oa63S`b##J*PoQJkYazRwpb2S+jxjk$McWD z;{Lut$_c$A|HFm!BMHG~ZsuI#7ZI?{ud6^pjmCLY9o|7|xc;Fvq2etJB+S3i=w(<* z13)zXsiBD3yi$iFD0?cGS&6jT5MA0k1)E~h1{NYyZnvb5ol5ID7TnftFGNC~I^-W+ z#2|8CsKap-(U&m+)+KXFSW8{S;4|Xs&Yy3xuZ7Zw)W|3_?t^ZOwFr=egQoiA1T zJt-bfWun5TLhS)0oqfK%NFfe`_go>ML{?36WWu=se+IvLI35?ZB!)OFEZ;H&dNd9s zv);UpM03wuvV`kL#sY&_&hs%W-)Lg2&ia8I0m9!vTQpa->d$=lQ4UJ9ufff3JET zqdf>xP>>MP3_xdlX6x8nr7EjA~23ai8OLGUquwWpRY9O?(XZL(*G)GNRS*^@h z3v34hEIpciU>ToylbN46+-{u+ysA^+DVmPU;;}HNDx?9I&qld{u7=kEDYapTGQmFc z4L2<>w<}h*2=L%Ys6t%2lYoqi?uWcm1w$3*q@8JbQGAzF{|4z_LufcZ9e{QlrUPWS z`tOX7ivQBezOucW>L(__ceGH@CNs$6J~A^0B-9|pp0PB`fc#XpJTctf%3Li77BRa_ zcO%Ah9v6y)Gv6^Dy*=38?5sku5Qd@7$^onM$;D}~g@?F*1|;qPFscYlg^1yX8Ruk) zpPTw;96{BugeBRNm&~+`&l%3oNo@^23N#EG`w*tz4qB~2$fx^x^>|RAUfTlq2!C?Q z)9-iEo}^u>$^5SGS)gD?dqP%hddI{tE%BWEB=|c{agyRh#$w>cfwCc~cHW8M_l%f( zS9PdT(HH=JKgD!g+S)~GH&4E$Neh<=v&=3Tx$BAQofyZ3D!;A6AC zFeJG-(`}6A>wZ}hx9n~$=6XCN$~WC>b2`%fwNPJy#4FzE{J1m2e!f)wL4rd_x5nlG zix(|&i#y8UxV_PpmO#-rfb)?V1YRiYYRe_%-UZ%l53zHSN8yQCfW@?l18t}2S~=#M z>NeGQI6ry2cG}&pUNWgZJ=e3)LDS-TGCq}Q+wIJk&LH>#Qw{nVoDg;OL&=0lC=pdm z$XPh($F5EG*!*=8l!n;Q@3>g9&S;h3>yYjxH$2G3-v4f09H0Xea{`zSP>D~$)qnO1 z4)2c^;?w*bQq`dL)Hn!@gUm6M;t?j6Bk zHMsB(=PE9jp>!;F&DvH9`omfXWN8laPYS=@@7vDSHwDlDY zzW=*4VL*Ycu0u>CVKHcSo8u&R`wM@U7ArIerF(=!J{^V8kINCD8(;DHSY zDKOlLX2Lod9a)lV(tx1;=#Z4?`Eu%=8PjT-&?ZF~==25;^Yh!#nHW!0-=WhcN*-uf z!3uRNev@)w8Zgli+6PQqbkv_~RBw79-LTjXnOND%dM|n>r{%+Uylp$nZ>y;LUD)mC zs;_^APi7w#mx<@%19R=r<`Y1#w^LR`v(^k-h5$%s2WvWeTmhP|%hcZ#=D)DLZB$Uh}YmPc1rSlJsNFDz|{`+A*$Dj)BX zKHVkwpL&Nf>)m9ne1Lw&j+dw}@i(INB3M&Ks|u+yp(re@%1}gqxA@o++I@urydY{l zD|^7^w%1@O9u2oEu4^Kg?AcK>9QcqfO9#JWr8;bp^(H8w=2#pE-4Nh2RDO2^H3B_t z3$O`Tz&k=X>wnGcbSti!I)?6+EZtB3hWEERraL|x7keasIDvw!-VQ!sxn;IBNN>ek z*G%!NPfU~|5G#{kHokwEZUO2WyG%T2rHV<+WCm*p@?9tw*QTup3>WzKY#|fvSXx2r zJDP)zBmU+WQM^(UKg#v9PwmKX5k(Ipc*cuo5R%L*cjk=gU;#&0h`;D*fUemc;B0xj z0Ovu337T2qki;2Ssf;)XZ<1g+@sH@}V-of%4e&L<#|>v0Oj{Yw=WYttEUCHW;XuRF zb0E$@s(&o6y8K7UH&`|&G8TORKI%@gIOHRrvs%$1#_7BI%<0ax}!DyZNg zT7CgkwIG}F#RxVA%%$uU?Y-U4*Jq1TI*0lhVkkqg1sMx*t7ESP*Pn3E5X8s*gEB~*FDk_KC9%F; zUPgffh&sN0tDO~n*Jua)w?f(ng5M;TQg)tC5J&cXT*(HlKAc z36h`DWK1s7d-TFUjGwoKzD$!kk}Ml-#LimYHt;Gvvx7IRqxXpz8MtCN!$v0+%+roI zhnkloHV)$yLYooV@3-eL%fk+Z7er{8rIVQ!=NJkUwgLLl=ubS@a?C)xL!S>oUr=9S z&J}l+x90o5oRI+c&)f4g;?T>?``Kc7?86nAxt#S=9CFvi)lwx695xHohDygm!!Tww zplL!ekG3@q^dCo%syEmF*;t$~+VL{&|Z4ts3 zFYTs$_&96%{j`7)U?FaIA(@mDKMT*?PO-k{<-ef2PrA2jsbeR**mk&8!oyw$6!u;E zwQL~P8)M$BY&J!xEFwzI-ML*a>l0f6u_T`zKUOW64K&T`e>*5!U-BHC1GR*L!RE%H z3Y&8oe|*HHgipP6AR{-0pzInw+QijZ=)>uQ@!^<(I+_3I9}e*31cCmI%ZZOD z{zY9)sf-5Mpr_MH=l_lb?9WbI@54WeFNV;lSb_Q4@s6nc>+^_Gj#fk?3;VE4JKn&7rcULi1=_P0;9I zBcwNp^o|YEDbzz;B~pMBX%fG0<$Bz`c9uz`07%;ci)mDg7w0gVxq@71n)g+3T-)j4 z{{S6pA~`M3!VnM;49*uCCmXHI6`J)BSv+nayCB2LyE>b*tu+7^a6>$W&Sl~sF4^g)s0f#czg*zp_5;7VBotir91nyK0W9CkgZ$~-BO?s zeol>Nwr>&B93aqz;DENkCA&?oaN^Ni2l&ZeJ+VF3Grt{NSu`#g6^`9A!f}iIkE~3t zpLYPOoriP(x$w7y1fdAW?Uymo!kc*qO_;#!NP7TQcCqbQ{kNUTC!Jm*8D|HdJ(M-Q zF5Hr8*-l4OczRFN#y&rr1HmrqVsG~~Yxf6C$NM8@sb}a<>1mXY&z-YK0uBmygDR`2 zv>DSU9tO8(+=!~pQAHAt!B{P$VZlS9{=h*_p~*00;kX{;9%MVMO0Dt3?QbXet$_BP zd?Sh~UIVhWW`ggoAJC+$({L|5#2YKim5>CJDd2qEF1F7MoQ;2V)43z)hrE33U$H~D zAEi@}{lr&8Srpwy6jU%?ML4DHvyv_FV!~T7$z=un#Tb_5Xv$de&Q?`t|1^Gk!7TFQ zRB|M9k4(3)cK+%63JrAd>g9pra0n-Hxp6Cyn12|~zIA!xe!=60p-rydThO5FF1c1E zhW?zdM2-J*k$XSIYil(n^O5fI0psrSOby_p1etyvBy3wrd#l{?9^Z4~lR*LQF zqLMul5y!v0LU)-X+BkOeehPcTg7k?Y)K6*-w@?&N$k|Y(n0Oz=%$~%zJR#jpTdp3A z>OkJ#W>mcUbq?f;j{;**yJxa}@O^Y>j0j+X7=3Moa|k=qG|sVAcUCGS89t}Gclfh0 zu|CL--KxTJfmK{wf+S0-W^;r%p+du#LK$`eogMK%GJ#YQcP+Oci3hyt&{gzl>g9pc zN~-!6W9!UrG!vVjh#wy3_yeRzJn|IZylu{?9!?N<{mQ?|oUF@+#^-*3fQ$NeI#E*k zSNzL|b5y}3?8jXC>D{dVrX)YiF5ImnHeOp=fmbinFE*6xj3ci?RxV z{Iy1~?odisbnL09LF{T!TD7pu@kpYaNMA@XAgk?pko@mshQ;i>y?|JTT%8bp3W~?p zZ7@MBv9aSQ6(Z9B(Lku*4$jkdj^9p-Sh%a{^Tqa>_DR`ynm`}n1t5HPyqra-iUR1G z{%eHAc9<8(H(46U0R72pmy^oq#u!?P;t=Rec=c9WgQ9zwr#t-U?vjC@a1cQ~Qb=l< z2sE?ov9^qZc&-y?l)*&^skly1LwUdl$591w@T5YdAcxD?lb^8! zq4xRNbm}!T!-ZOf@t{gJh#F$1EP@kPFhdS6GC=-|!pStxIh03Oty_~#GI#-Oz;u1C9kMc%>D2lCuCch#8-{@9CT@UAXrfVzgW?y znLR_iDNip_BEReYDEtTK_hj*RBN_I2H!!H942g`SVt|Cu!+WbEwO@oc&wlcSsk#WZ z*~%OmG;A0yJ_|&gd5Eua9S~lBD43wwp#&}Y2z_RI(|K~B!}521*ptqeIzI>TR2Ndz zZ1(aeF2XkL2$Ay)>q@8yeBD-mMJ|MxU6&WD=DwXR`s(+8Wx&2benqnBAYM$jq9#aU z4-o?r`cyA-(FcB)4B@z56%5$$^f)vn)SRS{SpcX)n5pZ6d=QG5D#frsRLP#u5F`%& zAW{M?021+tZ^6ctGJfdx9^x4sK=KOADw@HK8N;?Vy)=kK4v2jMoO)63VEf}rZ%B3l z5(Iz#SmI3^4R-Oq_rYC@QD0D_N1L;IKUc92jD;u*> zXoN~&bytM@x{{(#i_JA=;BlZq{+wmZqL5bjfn)I)Q!pB)mr9en!B$BG`BZ=Kc6^Vp zyQVFXLiiZGUpzoR$aiW5EpJ;XZjRHj+0XhL_e!58A++4n+rZO@jSVQe6Gt0VXP*A@;n&A-Cq%Bp8qkz=U9PB^?8RLsdRa|MPJAcH)InNyMb^~qvZNODL*jIGElQM z_C5&*f-ndBJ|Pp{0m-N2ECozuqjJI&i-_5dA$v|Iq5m`_bwd0?v;MBb()(zXx2y6L zh&!5&`~jcoa;ZuQLYaIkY!4hq>{LiA6GiD4e>9(Pec)o>-Z?%>)0>j~@ zB$7fXe!3HJjQ;Alv)YI=(CJzQ@Y!fR{2k694(LiVp%r6mz-1m?eOs;K=WIk&sw4CtU5}K35*31?B7M2|K$XeJ$RUnHzcXy1S2D3* zO)ioP&VfB{F>hkEup7fZAeEcCbV;H;%y^dk6h@8caKW7Nxo0&lh^_NwT_Ke8*E@<$ zgD!Q)CE&y2vf3WqHBfDZK?2^{9eTX^^;x~M&;qUDddT6rrQ7LGA{`q(AkO^fXB$Pv z0nN)DSqFczt!4qXVbB4R5+@-U8gb)H23(~ThY)m}u0Oplm=aqqC+s5q$tzJD@RU5( zFjdHm6FG5gZ9YkHir|6&0RtRm(cX{TyOlfp%6g``)~<(0Swf6!NiSxHnre0VSyF?d zsXOMY4jtw$n>KNIFRplHz>r9TCDn4fa99zIaPJ2wIUhclv7_LajmZ%g-);Lxxu}2R6&zq>PNNV_p z*`&oA+e0+W65hMRJJ=X7{g2o*(AS>XkfRb=W@e_qQG#QnlM(hP|Cc!zPDpNB(LJEo zpu=GRh2h}mCHZ^LNdpW_bkH|F6W-OJt!9!D>n4>i4J*oQ+Qo>7iWNQ!3<5OHXu=MG zEfhWu7l3SMl93jJl#0+`%_YBsiHHdkqOd{j+dny@Y;&qwB@VQfV*ivjfkHzAe(Wyu zZ<;#$pSdprS;#d4OEk4|()F{j&RdZ;L;||>@?R|a+aks@tRICi+SD(C`RR?J?N`F!lq;D8 z0wI)q6xfJ4Vub{T^*9ynM^8T@_^OG1;8}eQnYJl=k7aQ$lA#Q|4esJ<`b%K&{}NFl zCcVK3Mld*%LJ)SOZK{a&J#&isH6~;t*Xd6$Z-r#wkNZTB*N?p5fpr?T0edzfQ&AV~7-T82uQx@iOj))AJmWxl5pew(5(l9X2C$JSK)H>eK%^ z`m%H;slWp`vXz(S!683fU@e%QvjSJ3~Gpn&lMDC$c<80hZB>IzfJ@!LZe50NhDGZqcX0vSy&I{#`m={&{))V*1{?Jvj$(| z9J-;eVn(VylEFT(PCK~bOUrlkf}r{_N|=WJa!~RD4$WHxDsH^6dvQ}DEvbytmz|2! z{wNBLTD#ye0_VAnQl>@&O$JFD+?mNBmH3U-^Qi&wDTgz0=L*qmGJ9X>2#TPq?v%ca zN`v_FTQQlz25VKwbKesDRk&MG!Jpm&v)-HOIF7C#v+SFg^+zGLu56aS;L?{57Ye=k zejJS>vtkg&`CQtoE9!C)k-@c1C*_@qe)Dm9NQ{x7!_@J0(ijZpS=uvY&O3R&(ZGY6 zcN{*ECk*|kdJXaukX%Ka-7w`>1;8OEtePIwCm(P48Gky1-uzAUflL>;# zAT~&+vyZd;JnxQD6DyigHfKjN`i8~Z9*E-DF>65Z^lSu0$LNJ$DT=U9q$8VNoB@g2 zB39UWCzV-8QArp{Oq2NdybYBi03T%(_l#ZPppb&RCn#*&)*P4qn={s>4~(AyzB_;} zLp_!(?W+L_ny?a`Rnlp%*XEqVU-lKhvj-&1&K&+aeH}1O{9OJZ_D@6-H3O+XFjaW0 z@Mq`Z&)nM%g4QC5M3RR!AKcVE{>ZOw?|BT$2!!~AAyfx!nNLBoS22#P_wyy&Vn=zl z3{LSl(Pxm&c1?)}!aJc!Mx)k_?)Bzi8d8-REWqQTmQW0;BrG|QLsK9#YcTFiNa3-y zweyMkdIQYC@)9bq^q!e)VWl~XbHWuHKAw5lZA%KqwY+f0bLFYSj19Y)Zda`bGFiF% zpt(b&AP?Q?4PWKSA4EcI%4ID(hW?-zC7vf8V8#!$Io^RRcyZ$E9UC1!$j9A8btOGk z{2mM?oLXAC@o3X#i=5(-v|ny7LJSHQ->)q=Jlx#h^$+lQh6RQRm6m&bppqg15f%KL zO&FFY4VIzY=gBRFcuLcOlIoXWKas#4`Zl-uPgE-#HC5 z1v;o>!uw+p{td1Z8v)F~*FJq^(2cmFU==(_&*y zMkFbRX-T4LCvzo$F|T`Oq;?B25o&}oygQag&<%Xi8K!58jtJRFonZ|ZS=Z}#38hm8Dx0t%!c!^yByf_h!nCMfjzg*y} zzVcS+#?V|8qR?&fBcUq&<=iuz$kHQe`>uh23a&h8N^z4~Ij@=wQXIun!JzYsCL^a5+O-<(~gxKB#t^8*r_tWT+Uq zk{HVAT}*Eix9*96A;*(Z-u{ha%W#L>yr)1s;`m;)F$dXvGuiKOHoy`Q|I_oupT9es zi6-~C*G`b>i$(`%{Qg&o@;|sMEJ(xBDIH-yO6tyDqKGJ}ND7h`qTuRs$$>N0a(#!U z=2;Ja`*`mN(b7%7F=Pt=c-Zvb6V9;RW!V%&&i%Kf3W=+GG0eqBzp}0(p{RfM5l3$e z{e{S(IZCap@)#{X<@eMFubQ!=q^c2exY)G-z;A`#g>3~X0+Gw-{Ebdx-VYZ> z%3?zVm=f;T=ftB+z|>~l@#)2Y(PuX)``k+}frJq+6scekWs6p(c=LGj4i?WPap`Z_ zr{STftCWz!LHE9f`@tTq9JB*N{dxT^iGWfEhQ7OaZcbSWJhzpDU3NU{^ylAX&Hu;7 z0>Go4!EA{xmzp{au?{xqRIH(ReAME^A^Ym&o2+*;LSI1^`9E>bWYa+OI^F-x9ubj3 z6U3wkBG}BNul~^O@{m7iv4VWy^upJwoN#tlr|Zwg$+I{4997O8yNUBedA5o=pphz; zF9Z(YZ~{}J-l1itg--;dyD3I;Wec$s3@e}$R8x~D(5lviObmewILnTLu#a9ExHw-N z4!vJ}hf+#K(i&MD|2Da%>B(>DV)JHevvV2V#M9CVSEdHI5>&ofyV?|U<#bCh&&1HR zC~4;~OmFwBB_%@JJ-R%u{`@gvPp^TN4DC2}V`Fvzup1se^{~wC$DP&GJ)s#an(fk6 z^&EoaoA>>)sw=Pt5-TaS_CM+QrbIgO7R*KtdkYChj#hpP{!H5GtGcgBhJMfB!0&up zcF20VIEqqY=|f)yEIr~d2!Z$RwykLi#v|a+=wUFPWme*dC(F=VwelAw;m-CEyNXHU z$`lfhi90_AEF1eXbTkvL=9)g;D+K0Ut${<r?$mS+w~(ZIk+ zK>zzOpx7cYo0tb|!dF07V)>n~uVJm%vP(zH$un{>45UFbJ-BCP%<84C@-Zw>?)-`a zcxJ?}vdE+}n4n?HE{t7-^>!Fdz;xioa)wpHL#=ef>f)8jdHb+(Y3I1C%E;ofA?bb-%sh|>-Br~LTPvhn6;$XD zetlDz4{>eOoX`f=9$0fT$fF_C4}u-dGHEj1k@e~vmNLkG6u6rvi?lq;<2sS)fxYE1 z#;S0(VcVST=wg7GQjC$2D2LW@UE~qOTOtNlxG;?JzyEI_unHoEOO$z!`0eE%@jvPY zKfjkQ#hxLZW1tY3VX9+b)w!)~<3AvXW`4VXd8?*uI%ifLb|vCL=(*8pv~jnzt(1&@ zu05T%^EFF3mf=>1^1Se={P=mj|9+b~AIXeuZ}^pu2sXp(@}{V<=#@Pe%qp#Zd!e#E zUK)H1iQ$CH`3H$uhfIX@sQ0<)^9}3jP~J@B{^+q`orVRAXNGWQYA$qgwbIY%7r%)) zf$C@0vTo@9FjTUzbgf7BZfCEh7+fXY7k-Z2a=qiFS0KkX7g1F$+J#2%?Z$Xtrcle- zq2}v{Whrff9}tx9|9t{RfaQJMQw6Ut-SEWFa!qoppV@6Os1v%vk)wO7v%v=jh5ng( z^c&DCxji@b@T_eOwe3QBLX-aIC8hJGJNYq^E|79u&Pb9c@aQx?)<@h7hwE6qh*btt-QFM35C~w1YfUR4Ok` zUFx6$0tWF9{f&&ko3own3M}=w&%5mT@YCg=v+Myw8pNoo>{7i?VmAPtarHurU`<(! z-;{A4BOw1?K>o$cC!jQD8+}Cx%T}w`vE?!ldrM8EZ5^_mKF==d@#Gt1ohIaCw zFgSaiWlrO>PsFY-wymWtSCsEeF?fmPe7x>zsJoO-3BQFOXCXY`f?& zchLSj4C!Zu!46f3JjbLmi!)h6(HlO%Sz^Jo6i+b8?e^PI%IW)Wj^ z;UstS>Mk6@l|7`+!LI?+T(+v}hT&sHs%i%)sP5dXpg%9hZf47=2KoYIeGX;{$}}zV zMeXDF{xEvC9TG5@yJvGmkTN00{YpsG6B~stTGrymzkeLy5Z+8EP-=6p*d6z<%7lqy zDFSO=7bFccTSr7_{^)vyubI#^JJ%WC)V`N3tLZTv;9zgtgCH>M71H&`WBJniD^0^D z5&Dw|NIzo_HBm5KROlt{ql~0 zrsN*1=*TD6GVca^+#C$WefweW=yJ(yZM~5p?qI`0-b8sEg*r_-_PMt&Pcg?F@i#&D zjEQ;Nwj0Z3=>#M9!gx6Zz55Sx1eM_cuU%40GY!ggOi<9`wdQ_#bWGV{R{E-D_zH8d zLpJ(!L?;AJJVC?b7@Tf`=hXedsy`>V5#7I`gPIVLn*%F zr;g1jgTX1*|38L%f(Uo!J0b0qJiHC_czC%PYElH~#-rE=4U8yK9O>!5Dn_5Gk}=XP z({0d5$>Oy&Qrv1ctoeG+crD}r8v6uw(%^a!TgJk=x9&qL8 zY0ntV$BTn6AES{d15RA^Pl#h2_9>1{O)L+mCZkiMrCQvq=rt=re>a$;adSVfyJSQ7 zUsL*q<#VEwb?NZP&AFzOTK{JA!@FNVuiakECwSigRd$>4)!r0-R;;2?y_x?U5ONAD zYWtrM_s(6dH`U=NOJx6_@aP1*>zg)4u1khm#eK_8pQ zH%)V-(tl#RCc5YKH@~I}!UD+uzRf^>YO;hwmQSjcExAp8E@xH6p-<7~hM#{J*Uz71 z-Rzr|>X?lBV7WmlCEo`P#pd!r=IQgzxgoF1OQc?$7uIL~+62vbMEo^7*LNciv1=bs zE}Fju6>Tt;gsKhAZ4D8}L(Q5~hKE*m;++~VJ{q9@!{uHFS*evJd9L=S+&`>)8Eb=V z#f?OY6jl?4qB!kGd+Rz>FPNfp(XBY9w3X>N8U@%_l~U``+9#>p@g8|m1^VuRrN$o< z?7t%`yZuTvzWsWn_sL0E+kcbJG^tThVQ1%UaJ)};9qJ_p=GX7sXz;2NZd>(TDgB&7 zry(J^SzTXO;`C#A?Y^V&Xv*%7{nty+J^W%yY3Eq0$StvqPPr(Tdr)kg{h)1*C1~Jw zu^4+Ro8}D&{`353i2h1z(f4}JXVGLA-q5$7UW+te_062@{9)oay|Z6cg2JY4o=-K7QWl8kDc4m@ z+k9g>JcWq6r8iW4B|Y$YQwh6QFcb8A>(!K9jaPdgl5X3+LV~+-2P;!8sI|!YaL3Zr zKWyHw4%J92Y8b!E=_h)U^fq$+qcEFJbsA&M`QwwOdEDuxCA&K;kG^{{N4{$!=OhK? z?WkSm6`Ox3O3#x##hhEu1HU5R|DIRC9|A_GfEQM8>S+3yYHBQRB43=+Y@Kc2Y;e-< zrN!>dxmDtT{wIqUzM{)gjgp!5ZgHteWkA3YQn~u-4?^=bIIe~Z5;qw)N$5=Uyx0b> zcbT=&45mfn_AZ?801-LI1|)$Gx=r+z#(?Rcc$7mpxRec-6xOfFO|FNlfy>WXJSVD8d4NKUtw}zH+Y9bgR`glY9s15p%JD#{jieP z`$paxQR{KZGI2r?B-uXH8IoVbUF7Y0o>@=b&uowF$KGXwNL%+<{ z`?>yegccG7CcAYO8p#$Q{}YI8627SF-X9Y$g_tBesqdB0+}wDb4|W`zF1j>>5v0fn zS+x2%UXblGpN30rWE_Ios8jV!kPbO!87C+9uWm;LDhjXc5$SS^T$6L zL`hN2y1zH;d9&HVe|!wfI92C19w|>qaydccbBia5k^Y*zJ?5G&kcRh%mRmbMA3?yt z30emmZZS*RBy-g-Y6;%GbgOhXRwH9~TaGt1_D+yb+#gDzx^ldpA9{{-YO*brgt92kH&jS{C3ochJ^FKpkytC6IYEUL4`t7Y)8*I`8vdWm6yw=@NhO-z zD)<;aEJAR?tUhGfuybopVVo~ECn{q>aPdD$ilmhb>Peh#L&s8uk;#6lbPn|f@Q< zbgjo44;L5|GVX76^{AOE+Z$~RFEJQp(7}2==3|!w@axlA<&r^2pcDIqax;!$A;-!|%GOJRAGwHhH3_Nz%?f z&UvSM)wambNpBX1J4R3I2&OV0=L9?I@!&5Ss!K!Y|75XCC=7ojG(Eu1{->G{z=Mjs zT1~W^$f_Xu{5+chDf1V&CsT;kC)&hTLXlpSv)>zzja#DFuR-lyWrnB~F)aWU4gGP% ziOeG~fworPjp}r&>h*+Gm7J(plJyrgmM%-9IrU_9b8iNgVb^T8u{o?$0ShM|W&IONH*g~@8 zxXjLIFGVIk%3jXt123@K;#c~y60ZBH{;P*1S~?+ZP~;kvx2xR2 zsoB--^D$pb;1yWHawmz_NKo1wba zcd{VEO|$K^#N0;zRN9pw4T~v4@3P+}kw$~J#>Thi&lHXJUWTUc%>&`)iE6%i6U#;B zLg&a_)ji$AHj8JfbLcb^O+dt562mWl-yjFvr#kBkSKYsx9YCqSYPE8uU$szV?M)}m zaWQVCHik~))FGO}{?DzUg#yfj*jP{=)YXImqLGQ2SN^#laomw$X5s~5=<}UY}%xxKgDyhcFHYY;gC*nd^CqdUf)rD=#_+1Cb z6EA^MMxG?O=L}W;kb;a_b)isOqr|ai=f`KgTo#8-FIc;ft#KwtZdU(VqHaWXvHyWF z)!Zr5Gxpl&+E2%m{X#SjQ-;@v6EiF3A@{vp8rvJBSFU<%S}QL@BF2FFbathIK*=F@ zwW`{l;6WUkp%vF>-30Fw!pxVebq5%7>^Cj#Ro%w5);Ha3iz25G15Cuq8Yxb@EF^GE z06nAExWInTv>dCTnSkoB=BeIz2?!=tZeW;yGEWXVDin$wpEATl5mOXi&EFPrAwX@u z5GAlbHhaE=xd8EBZ<=WkSXGxRrI+oy=ilX)txfG+3C4mZ0YbXAz_0aqd7qCA*>OGj z+;zGL49Q6d3gF)#_ab=?wyJw=N^0}*6uU1^`HrbNlTN`g4*B3Q;B%RQj!)k(Ly@7!E0bY<0bGy+rhK<3wJ~83 z#iweF=!!i%MwdF_9O zU2FG#8>4NE#x|P9wrw=FZQG4)vyE-rW@9$C^WVAme&2WRo!|Ut&YanEGMRJsyWe*` z3(tC%5>){AuAbQs3rOK^LWQH^!!Beu{3O%0MQiK?TBOY5!^A<|`p__n{hfdi1tm3d zFy=A)#p_@8YxKN5Gz{zlU27$$A5Nix^x+6;c$}CwdOlxSi9<{Th|K-*jLUd!0nfz-lF65B` zm6YSk+4nBHZwM222kc`@np?iCLMe*)nMqkgO%r|Jztd3(kkuOUt|}UK$v6~b5mLVi+1yg> z@ve8D*o}+Q6?T_gOxK7b(9^8AQ{A@%nkO|22MO!)6; z6b{bSMGa(y(2S_l##N^6sa$`EO%qsbMY$F>3btP{74>XnRO8wV1V6_b9KOs$Ze6jNz9&{`O5%zWuk| zsLFb7Lv-4UK|n7}nyS_P<(m4hQdD*erTy9bQYxMP#4A6@k((4trYobt8VB)5E_$+x$vkSY>esi=lZ5~koY@2a-;57%F$cdca6@_;T1Y%jGC9td*CF+8 zX`gu}z);;nVrKHB)I@_m`y;hhij;B$8!tTsc4B!lf5i09M4@R+-9VS)4-bi9`iI^n zi+qi%NwK~5zke7vJ*KEMy*|*}KX1!3cny(1Z2wf)RQ(+vj2d#K)s`v5JRV-)5-T;? z&77J2xR)7C^H~gAlcEbmQ(679bNbe3VXX0zw_Xk)?Y2P~s2Z3Ann|fiq*;l+(VZx- zfDpV|KWNb4CNdgS_oV zHZ1jHWs%`A48QGT!@;c4;q1-P`U&5|1Ane|;H`ybqBs@TMiQAnRmQJABF5gIc--~A zb>>AG3q2s;H9GxZ7^*E`} zp4whGVj0H*8wmTdSgJHZCHHufi)77*l#R3T$v*uC`? zaU90|_%}v5wP^Ow<;&6?^y4KBo^!=9n^5bVGK*ZU{{>b64lzLZ0AjM#Ouv^)nOW~K z+TiAt_Fa!1wh^&@pc-VdiMDIdrOu6I3jelh^YKh)RcyOyt@a0!qKdyYisG|$x(656 zuI?irH;Dy6GO*cF?8CrO9@jMZSS#szpr_n4y%e8t^q( z4MPy8`W#kWMP}K}R$Ci7CCAoq#UJ|mTe@~61;r7;+M1aIv;T)GH5g*wn(7_aa)xV+ z*ySZP)2vhHY8A)jKEi|3Mz=zm!2?xXW)e?-+jGhfn^q_sF5jm|xTxb}_Y)Ix--(R4 z{=^0c*mSk?YPFG1q(>y3llLW!+w=9A>bPeUxp}we2z#93udNq3RP6J(hKW^=?WSFD zj!y&95^+Ip0-ybnTC!Ub?=j*~QeFZR>a1w7wO%9{adrd+?H#Ars;F-%5CT_yjI!jkqeyLCi1d@V(`3hAPbb7O1q;(uO z!FNs@6>0(8dV}mvQ5ULv*dOmz<)r;l{uk<0#PD2eb^qXip9Q>$CHVK>{OU>wR-@3D z1BD{8eR-x4$x2hMGYjtoYREu-wK+1JN@-zGBFg!@{haM|DA!sSE)P!Lsm+D~6F3=C zrIROXU!c<-WRBj()E16##caAQ#&hK*(lg4(j4=}vqXE{!69IWXOHR6; z?+$bgC1TD$IgSLI*mCL-hlH1!GlC4s`U1IW7Dt2FedjS%*_=UQVz`LS-R(E`8Y9{N z33c+3mSh?(vmn+hs`W@ZMr1A~Jk6Y{O)IXA@y2$OO8UV*g!i5O^+N27>`1~l6&2n} zKB}Ji@^Nh=a%YnxPwPiCY3tZe#H9Y+LoFeNMZ(;qVrZH9g^B(#g$*a}oQC6<1-RVf zSzgTBQwi<1fh^q23VQdPBzaWuD(oP4g; z8Pp(9hKj0vbQC2n&csd)Jk3Y>^l< z&pLc-&4A!;3$6?9aWyD-u{}2*9lRN(Td4d`QZDvH)i#lA6lv3F6jag1k;%rEqnSqq zQwI z+0o^+(I8=*RxLtqi7n(yFr+}x*Gc%@Hb;8+HspIN=SSq62s=T*HX>8s-y^}g)N#EO z*<0wyerRs7Z+;2HkRI-eYPxBrnU`R-+1@Vh8N;IzT6{hnw!aD+A7CX*3I!uXoo9gr z8+z5Ef_6w5c2oQ;E-C(UoBR3q*#j#(g%VtYx@Klg+V3O7z&JM{Rv88SD9648J!fDvmMpO{u{vrLpw+YMvD2 zCsKk#gM||KoiP;mE=h_&^;b+$_h`2g$tw4`5Y%Ew4+il zwST=`))?p25I(~pqEl%PVjb#T$@iom=#P4G>XF|qJ<|5mcVro?{lg?`jLvzxk`Y-A z4Rf)DHBvJfhLg;hT&vh^rj#tsXTIV0Trb@Fq*JRCE_cFR|l|o(I(6^Sk;;T73 z+f*R)ST`Txbd{lhCVz6WFFX9pU#RcgGgI!rCac;pS#hSsabqO0vb#QP1;}ff4P)Iu8M8^sBQqrrJ=haAa zHuCIXw0RF?;C&{W5>YRrJ2oxGsgTa5T4gCrbDec~%C;qe(&pEb+g54FpSu zaEeHF-acEkV)1EFhed^)M{H`2a4ZS4PPIDS$NKGl?rMq1-=nx>8>;)hiz7o`?dZ~L zK5b;ebvj~_G5hJ1OaRm)09`diywFXBIH72mC9dvXb3%^F{fl?o3z2UVv@%^85~08a z6^3@De|3Xa8i_v@_7bK#@!j3GfTV{L_9qeA479s8&pj`2IjTv)6|1s4rclcatGko2 zUq_$KE(Dw&4t|pzPKinz7{p&-QAM30kHbiFql%QbqZ2ffa&6A~f-_+%Ic1rZUyxYQ zej7sJgLdp)Z>v(tsb;y|!N7N{g)k*+IJCu=Lj&0lANi`Q42|kqq2dcp$UJ_Vjn=dM z?$11yj~$Y=4V}bH=dCI5flnXd`YzDUu5mxY_$ztB){gXT!9=^V_4;NOETleVv^+r` zvOL;GUs*M1%`4S8SmR|RbK2XFT3CCe&lRXIdj~kAUu?w&c15xlAAM7=muBIp}U#K7D9Z-19{#EgTusEmwkIv(823Bds9QHeww4KmDu&3W?Wh% zihj15Cuf-P(zr*w9Hx_>^jxF$yPzymVybZea9I`*Np^LPriGP73inrb1{BSW) zQtZir%m~SR?6jy->B`k`+thdaglcm3P?nHxTIz zbH{mHlVQO(Yf#`*E^BTTp`Nm?5lJ!O<- zFA1>&q3tzc)--0@^1O?3dw-c$7)uE?!h~X|u{da-3Xp0z4OiSxQBLBR#G1j&~M z4Q!sssppHAj3p-3w7cLYU2}U_7}CE_LA+_S6w@U~2~kzR##`jzfafT(erGHghs=Gp>KwWcN&2M{(?8(!OfqHT!TqP5-B9oKG;|^eWO9p@Troi2 z`tX&0D8wl7`l^mt`F5$C9=ERy5oIS{4q1NMZD6V~B`17sZKYjzLmQEVi<0U?lT2qO zZri68ec`B-1=~#dUaFC&#>=y+*vxT&UuM#8ZoysCuf6IDl1%Ja!#$kLr_MGJclPZE zcZH8x-wt*zqs=f`*H6;XP}c&VZ&r1^oAo@-rn8`?C@7uU@3Gy1a#ut zfMUATiLN6+&uc9Fd|PAEtkk68j-W+;QVC(XHR4ym+2~paL$TUP&viIZw)d{KhECZT zaq`X|acHazj~Tz_8l~&Fz}BF`P~9w`dH!R4x@@Tw#;KI}8nk@j1IA($X72|cf2E$mWn+dJWC#{We zrFm^S;S_-AVFb%fJ_O|CXiYIBxAV?juiDK75f#cy4G7 zQPsys?keaMx6URFoJR^pB3jbr0i!{Zvk2I^$T|B>VC>dp0`)iJyR(g%R=3+Z28M8O zuoM&@tG0U~C}F#UPDorL(&(fx7H$ye&D#LcwcVKVun5geos=sNPwM&O{p}U8rq_A7 z4H$LaZXx8k<8{}$-Ot;sAxRo2SHHNvifYb>3s@O3TjhA+v`AxX><>&bxSxw3*4>NU z9LV#H;CqIJ1~aV9k}dbDCQps>oNiG9B3+jkETVKkv%r}EK#*Kn!ujE~msstDh4#~lR3Lc+R@^r9?r0cyu$ zng)Ua+XU)}H6A~xXcIqCQ597<*~CjBIoM!NW)y19t7(oSllxXW%)ll_Myd7Zq@B7y zXzZDhJR~JrE3pMuUBtAZazO^krOXQyqprSW57FRw}BG5TIhW~W~C(2!9117C8Sw-&Af(K z^o66kw}nRWx@TJah%N32DqOc7o%I`U!WAm6OpA9X$SL+ETY1p4hF5#ZRVXN$fyw7# zt&-Vsd;-W+@Lb||RDW%7kuh*Aa5jh<>;4jEcX@#43Ig)ek0<}`JcfVIDruwAAsi;R zD5Rrr%}${bY~E!*K-<=a-gB~R@P;bq&Q7sT0)CH;gWf~369i(9?6*IRI0d4FDxkN|I9Gd1#1~lGJUO3~|$?J4>nW|9JDmoV27{8y4(ZFbk-b=0T z4#0Dt@P4tuF9#c2O@YoU#9a9vH~!5GhqBMn5`^mLBbu&8)sGD>C(!RIgjy_KoG%hN zgP(Vy=4+RHu@O`FE8gK>V2!JZaW~SibI*`2H2SVG9%53(tSj>i^4HJHJoCL-X}k$J zC}#y?M~YiB>io5RQm7gtklx;2pfnrd1}|QdM>)^&XiA&rbEJ`zVz9@8;CWk0n|eiU zx?~?~arx1a$9Ty4>I#tnNnW}0lCAwNyB8>>wjEA?YUXGNoTHj3H%mRL=`1e@Z_0>W z#bSB?ORmDXAo~~6b<^C1D}+dPVE)Ujf+N>+86~$Pu?QSh3A%Twpxd9)sR>6V7 z8Rq-t6VM{_VYZUsFp_UjB!>`iwY(i-ASmZ_RRybfWYa$d=5k8Uf1E9;G!uxkNH~|| zgxoD4s@*FVP$aB3X}IY@P*PX#*0gykzkjY}6Lvh9GE2P?Ki=(m@A1aE^(i2Fo9egJ z?!`?^L?km`rjdFv!-57?^BLsnels}KG(!~IVwX=l3l+L2gFHJEVDhD{*gjm>V~HVK zf{WRomK0XzVt5Hj?YOJ>{>cg9kw;qJ!;k0@knhx%zXja`^_i34alr`<4mKX`?patO z^J%F*M}F)-RY*w`w!xeW`Ftd=fCxw=$evYf95N}r6^-8NMn4fNetShHoht~V80jrh zfP`bdS*@Wi_YG~=1bbJ~s^ghz)$5PxCZECZl8iskL$`wYz)E#^&LEQ~k#V~Oo4Z}L zuRrrb@?_N_6pe`Fhvu=2l0StobEM0NldD& z{?hIX)BB-#NxR=ye2k92q>gJ2GqYomQ1Ig6cv+UG-JMW9si!s^e%_=x@|vxsNc*ThzINQ~?!#Kgq1+S=Ns*pv_uAZVc-z!0^a;%55; z+w3OqOJAN`gaI~}m`|QpytOwL{<&gn;I{+Y6Q=C4z*+d?WfAT@wj60rz$PO&0)5UV z#T1>sg#P{m8dwUNPbgB5evr8v9DbGHq1$B>8+9&omk9RzxBuKD(Pnl=KES$Gu-VO% zIqc1Rd^ht}#6|MC0A)AuXy(oBNsPKXZIn7wGv1L}y|#bse!snLJhHjr{|KbckShKC z{380KuCo#o0ujmyQ{a4ptU_|#%D(4IC+5isseN{FUYyb^hu9)qai>85Y#H9f5cK}F z>!vCWB?ZO)*+%zI_ZoB@CR*<}IlQU*cKu;=FI5;HW;(blQ37LN0$8PqcF zKBzyo3J-((o%IqR9-Gc$!^Z^&4i5ev7BEeq2r?N#zz|Gf8XEX5CU_-=>2Rn92uS%m z{}6?^3@O(QmF>lB!rDx_Ff0y^6j|Cy6nNujFn70`oQq9e+lx!9XTM%3-mCz`igtUh z_@^uAcwt=PZw(SP6Q#kH^$;K&2sVOhh>KvtQLBQnYTZ#^0%3XH`G&y0!!88#Nf7He zKU^-hAGM|6_J}j@@#3rFgshv%&RWBp_yHAX`J!>tuhV6acL`^y>*HK09I76jA^7@&PD`S8wf%(5kIY0|*{uuSj3QV8FZl9FOD znWH}ggPvo% z=bxKdtBVpTtllJ3c<*xv_T{IA0|^;m!;3<^8=&o5wnQtHh4a0h#ZYVtO-n*-fqSKd zjZzCBshH!~9l zvWHo?yP@kUccQK%wy{FF7mo2{`uXU_-;j_UU&k@d;6@S+e@<*7|yB z;1+cVAn+13(Xiije1X-e0Kz9M!!^8A%KK}x5*E9v>=Ym>o7jblgT6Lf{Pi=>ZYK8f zGBawd_va{Ghxh+}>bg7hTU|R|SyPmWiK#}f|I<>v)!IE%$QEzbD57>H*tpCHoxu>Y zE*csD#D9X1SQi^t*7eEeJE;#2@$x*1Dv&NsU&XKTcPvFUD zfy9HmC_F6NQY=5yMz?~pQoF|j#(k!q6$|n&ix2z^;5z_aXUTLn#ZZzut2LTfe+mkU zB@VQA?|hoz0fFd5iUeQ|1=uw(D~cv4m*#Ib-T_XqesUsZw>yFl2*k75ZbSW4tquex zM$yPvS*yVtCxb=caEi4*UBIHCqRIt*!VX@g`i~9%6LPZPCtU8LF71Z51&VfrZ)FD~ zapetML#r@>mH{6K5*Zt&z|eLr3X)4ML10hft3AXGbXNL|`|d7b01L3RgwpTKn}rXx zZ@+!jv%GD+^HV^#)qdJa;o`DT0l}#RUriVj@SCB7^IEGozZGqV)#n|m?`=rZlzZ^k zb$$Kt2YUVWB&OUspF{S#=lq&T`M-q6?)WO8!yYFe6m@?^DnP-!HN(c{4$ zgWb{m7*gjyknpw@c&Z8DQBj4MSM8BpTwG+;)v-KoSDk8%#&G~_w@`W(FyhH-L=X`Z ziz!1)WwOW_8WO|caISc=^wIeDnhG{>0xc8QYMd0jKbTP*X$3kEEissMye z7C4Z2)?|eyn_AwuxM;q*bhnt{$5N3!OlzE${eRo>=oqfUu0lbkAvLT;45S-W}nz69A(2g~s} zF!seKQDkptSxhKY=YQM1BYn8wfdN7gAUt_l?MV_+0N7UATd3#IB%v}G#6uHHdr3kN$fWQq}DMLU)B1Ge&T~=1c z0L)!JT&y-KMJI*$`(vG80kbEd9lLLhS9sb*`dZv<-Y-P4+^9<8uqGj~1FXgv zZ-?aqi!C-ojF{(xzgQa*lgJ&$&%`YH;Ogn?ui#wamCfHA{_6#{Wx&00w(2HKu zjn7xCM@MJz!C*ez7J=_ziSInLl#~p=8p6TBVQ{)K01zaeByuQmqXYUE>ippq8z4;l zzGiT{F~{I?X93Vl3Pyj?McQU<>yZ-@5^~dxUs$+5fsy436>QA!UHjg#VAuD?-!NW= zfuFD`v|4cgzLtQeN02qm{uX`?Y?Le)-L)DOo1ZdKa5qV}eds?F*(*XrDnTXCI#K^p z*$x;?Bh>D_o-gMWFkN#IM}d)~&(x6}ihKdS@qq;1N8W)1A&xv*)JPRbp>33w_(8*# zIT!rRMMtMVRHTijXqYc=pcz2~`dC@_1Ywe@mk7u8$(6uKdZPtV!jZo}`gve5?-JHD zmFJ7;|B%C27X+K#k;v0PUw>dxQ96S|ba8PpE;ExBsc(3AIJH5T1sh7;86-YFe*5Hv z#t7ALFTPBpSxyE%Lzd<#o)_*fr}{0L(18YnfS9VC*QCt!iojwe07rT1#;<3 zQh37NJl_a9)<7E?8bp{wDk{F*b0B~I{018q(4c)Vf7{d(JYeQs%dyk2nKA}aB=Ht6 zenT(!eiUPU!N*i3R1{H0ylv{BokH|KV}STvlW*^cLS40GfTYE5ptRZFT+lOpY%pIj z0?n`K42W79&gS27zVn&m=W)+AUbc&JFTO+!(GMSbQm5-1nxmHr2Lt5E+Qzf;Szg?M&zQxHbeB+?c~A0HP74~7Kuk!l&{y%b0nRhPw%Df1Hx95#8*=(h_p zh6NuINozv(Zw=8596Ny)=f`kUMR|EKG^q!?8#WHwudgOU~LRHyP~$I}S+7jnhm zS6V_6Ns{@fsJf4!xqlMYSxDcfH=`{|ClhL!?!@SpP|>BbYORL675PazEUAe|4u!mV zGj8g?$97RqUQf?uEh2I~~i^A%ct1Ct35=!NBFr1rnqPPIrZ z&%>dIb|6dp1B=|=D_z}#tawrOd(K%yVUfAqyQ7NIGtYskMg61oCCe5r`FO0!F?AL{ z13ShRld(8C2M5EN{_eA7+2xl%+k?9)hakaCfhuA?|xhrd7r z`aV|Hy=o7qex@d_4Y#!&4qy=wJ|@7FVsJVVpyRw#@rA~{{2pzu+k)l2KO|{Z_X#y)7<1$!OPdFbN4Vpx8iYtT(`8Wb0I)pO$7@RXaO5 zQjD{-O0DZL=0Iovq)*4nvcG@TY5DP&(b#gMSTF&LN=8h&hLq@FevOkCemaYy#5k2y z&W|6quKSuSb|NBop#NC-pWZw`r%L`)ec0S+rtq@+(dE6+~iQK_yjZg*j-AoZ1JfbHN&%|KR)q8LBu{zgKy=P8gk#WiJt_!}nvnJ@a=yBhp^xDCWg z7YpIVt*R<9HpiT#3=g^xCaXbZ;q&KlRR(?*k?^JgMQU+T>Rid!-9Zb~clIYmg&C{Y zhn||n$kpDq>AC%3R*Lewu}e3$5C=9-)h;KWC!l|!xiGeO&em@D zAb35IJdKPk?7X@mAf0jy#pNEwe%~5lXD2c2_ol#$XWzM5oDXTev8d{jvzV@dOENhoWR6l{hkgB@Bl3q~?j!YP zzv?pzr~k*6{Pzy6#_tF@J3>9bCXKeA_c*W7Rjga87tWN(qxQn^M^PW>3T?*aC_QPn zEUOn8fs?C`3?X`T!{MUTK%VKsP-02eLXZenM^bxGWox}t`-*}F8xWxSMyO28gr!3; zvgUhzdQH!6XZj3=Wf(Nzo}}ZaVSK+AJ%zBtuD!!z~uMitNxbzyN@>3W#ZKl|7PCQxhd54I!eSYlA#JF9fgu9Gexl*?) zScQN#S;8;VIW)rSmipN16kGN9&T05yQ+X{5U~|TIkC`3pALQedJ6y}aBzH#`p~^1# zJc~uES1shtA3MnfiPO@PD>JE(b#8?{n)&HKc$Z*XZXhr`-S_HKqGRN33!voZ*X))I zhX{V=v}*m{q~YZ^6+Za&=5|d#mF?TNluFZ&CXbeK2$=uEax{N$L(g(pThBD)|DR<8 zA~1MuNWUOKxi+T8mvHM~5piWXe$!KA(qkDVwLjP(%<-s@D zL+?RKIGoQn-!k-T;4iPwjyV3lwa2tTthX61-=hodSclHk6F?$upLl}k;(~IupCh1l z<}LdpCoK`2WSW*+vecgtLO4@X%KqSkG{(eua*ke@Nr82Z_TES0yN9ui6MW{x*CYdi z3Yo*Ri$bjrUCDI0>i7v0zMX&Td;|`f3IQHYk?X2sPzV`*rUt>+k2IhOpC%L1?>t$t zADoMUJMR6I;0yllNUb9ppu(D!r<%!9bw09ozD`s{8n3a7JIjCf!)?>5R`E3pfuw+R z@*~t9Nm&C_NlXb*mE>+u=*T6P+Gh11-I?O*%(1ca-2&^V9S5~PQ6*H^*^+qS-#}q= z3N?vW==FHfwu=BvTt2s8by`~TYzJlyX&bMy#N}VBP4Yc?;sfP zjk_cPsU|^vuJW@faGR7N@kwj*1Ebpbs6Hxu;t+qdUi{aUo8W*#FRVAkdFG}4U(oV5 zNc-=HDZxC(6|MHE3(adu@V1-!boUQwkEL55z4qi*7UgOSWBVGX!^R9 zqI7?2rIS(hL_OIlKq0q1G0Ag|&GrT^9A}#uaXw#sW3pIGpuM%3dd=C3_1EJ=kB4;% zhD*#Z?XMu)@@alH;Lg<(>>3VKCy#2-WYM<%fU!;$@SgkUh+Hpd9p8w}HA>%SvBw+7 z7>8zu$=IMEY6Bxo0mLKAjSWk9%>kIbyY3fsH6Ot?_?SE(-KjQN2*)KAD{QB=x)N@2 z;f#Zn6Ybjtb2!@_lF)`E)X59MMfK!-+s&XxwZh!+T3z5Wu^*-}tLa|L;TI8R*0UKm zj|wSX>0foJ)p@eZzEvb}#fxdT=R8@cWgv5ujJVWBpBebUcJidazejGVuDjzoRGd@t zpAj^$s2yM5CwAcJ)`x_52hG5+PEO|Ce&t9k3P4o?$jYs1B}i~AXzeek_qV^LC)>;N zG-#=nZUrUNr9g32Mbv}z)|SPKeoWjw?XK2h3QA@0fs2YFw;rNVj4?rFt41L(8k8Jq zq}F|i)l-(QnT zCvMRV5P=%U_`rXf1-yFmnqrqK^|$~`p4pP47n!&Wl1KX=CF7ieTE`mS#|1btR?FL{ zSe+dX#0XK_CC1*r4`dQ>6K=Z;ziEFhJMsb=x&VS>($Y&Y3O9llp`$PQ(?YBqRrZm@ zuiDr;4nW@)w`S6Emx}Ft>o(4bDMJMhP!Y*=WJVz(l|Rf_t)j9WVuh;GeZSpYA;d7RK>r^MXW zwkmtra8~k5hu#6#dQqLI1E)f;K!z5wgq{#atef**$(r5%!nrQpryOQ27};LLmdN3g zhS@~NWAZEquidFlq)V;!QEm75 zr77CFz2%EUwh`Ocn9NI~+bZV&ausGII*7>{QnY;o;A#a;G;ww^LKI7#9S;U}MGW#_l*MT7DMxClnS9!EYodElfj<{XkXT zGP0kL%^8JFPSwk3_n~^_0yB4|Q?nZ#RhGT#i>C@e_cOCsJ&P58JiT0%x0{U~;6TZ~66SSBo) zYAL6+s4Wa5KIyreU&V4#&fUw%6s#KOdeqa2KxdOfp(%T#^S2i2H=_U`TZc}Li#p`h z-{frm3uphmpn>wqD*C70!@QP@<;ULJ}jVnDRMk>yA8Wq1F7^-N;iKAP?I9aAlh#7zr`u z?KyV%QlM6e#25Yga$s)Tw7Ds^)I_LtCYp__q(Ax4Zfi0cdQ*Z<$Tru3Cr1cEXToDn z27-WNWUdbFV16oM!{?ptU!?^!O!N9Al;g6?QMq!3sMuG^1+(mGn!u}9&_gzBSgW%x z&s6f6ApK1t=@0uk3|8X{QMQ4FZrqqtFw^%d!`k{qu1Z}$`;>jR z+g6|xKe4I3SV;xz>+}4Ygp{(T93Oe}Ypx%z2M?W@l6+Tts!3O&7JRdd^>!~NOG98_ z3RdB&H7smwD%Gb!cDIBT!dx=$$pQYwa?Zf{^rvT_ch&K3!KUVRbiRm)IdSaAH}PYm zv6!8s5&Tt}9;KN$6VymS{C^%}pp5V?Cui#y5Tv$OIckLDt@3KPO-7gP}wr zfXlk@ygr)9H!xrLz`^5oi#BCor?;Q^vw+@XZbCm7jh*e#ct)`7>bf6c%7uWkIn7hc zOu|)coGjME+JSKl%j_39t@IXGZ#Dt-sx{X9^$pX>JkIY!Q$lRk8iSUTy!!0L>5nH! zYcEm7ColJj=8a=Cn0s4O*-XKIYfE~=LP9W>&)lRWOZqjxG@4S(=W7rc0lK;}tGG2g z=8F^kGlM6Ch1Y}V7QU`m|1gbmeHcCcjDwj{g9h;etIipcbo8&`Z{%``pM&5gGwWCR z2AdsA4A5+Q=Q@3S13%=;TG2$0AyMIltliZw<>yd*x}l*lO}-D!4VnZJ{zYU%UoPyf zDyUHRm=>eEITl0-bvKEtSX^gm4=qs}tN~C_uuA+?OZVen5X6AtbJ$MBxKupx<)2UR z-+`?3@p&44Pw;m9TrZ9A-w>@*kay>AlZ!$)}8t|!{uXlkh zT^I>pyQ8`GuC69Pz*!?iU@q23HAt**tO+}YtP(iBDDzO|6_Lv^ZbEr!bt~Tk8IJNR z`maOeL=9}rj`d{ZbiooM%ZAD!Z&Ed!k1#uoX1F^dluDn$kgOBG6b4xQV>1?|cO1lX z%j>A6s0{+?*p;rX*<*n4+#w^YCd8iMA@)-##R}P*y`fn?v-u?w1QJg1wiyf)3pLIc zAYzl79@-mJFHKEODkBlbRWE8{0CVQ~sQ$RSYWVXkLve4WV z4S0F>hR7Ju`NwNUn>{+egnzQ|0aQq*-yR>v^;%@p(gnvJ4lVJH zEM;X)t-%e$Sc*t>L)S3blG?HX=`33ELb8>-0y!ulR|qFqR7$L#IYoVCX)Gq|L+)LC z#|Etv+TAhCx?^!ro&Gl8Ovvbp6;yxL9ZjjymP509|3Kyg=GJJ0{9a!E?e7<4@>Q|c z@4pWDL=m9N=#%?dM$;(ehF*Uvmw(a`<0{$USb?6FS2k*31P(uwqvJLfJedHR z4l%4tvc!b^{Hn0$EJ&Vd8cB3V-{ z>blt=K~k4IisU#&Dhhzw!;w8HoUuRmPH*5I!O!ME>G>0T*BzK4E{~=@dP8B%G;Vt) zrfo!IqTh{R7zr)Wm}sP`smwA-G3J_imTontJY1Y^at}VB_J+r}$X~4CQS$Pjgkjut z-+%ZECU^7oRsW*}@E=bh>mIR)>sjIQn9>#EA4%zdd*3o}Ao&LIJs=@(J#6*dBDt7W z-28S{!TBRpx!t_hQJkFj*50!}m0`Yj0m5r?0YIrto}_VlcpL%<9>J#5>mSsR#jUsa zAsds@wz?yy56pc{Vz^1q+aF~yeyUqobCV%Gx9??FU-dtz&vN<%z|CtMOY*)i$nohS z$ZhsbETl^g>P6&!N&{LrxYmH)UsLX1S_wkABImHdPDvf#C zCfLF%ZMHZd~qctaqDh?mk3MeSLzz^ z)FZ(5vRY4sYg;0wIuq4kL3!+Y?m}+8u6y!&W0a9oo%*7*illNku`x9aq%x%~B9(_i z!*eVl;c_d|m%po4t7Vkpv4(t&z)I)`-2QwoT+b-aWG2;&Tq5TAyw=M_ZOHIA&SnE7 zAe~Su>EduqF;5SOFG?XDei|Ku-X-vj)We5?td{RVD)iDIA0Bz_fx#EBnAF+Lw{=>{ z!~{BtT^n&Y+`*EYU1sJWZvGOj`HxWtxO6NM44igp2>;njJn#dwW({D-?*N+V8%P5z z&8&B?Ms>TxVU@r?*BFEJxwKd{Wn z#WA+rK2y81=a%oNgZ9Ks-yanGVR`ysUpJK94Eb9{Za{nHxtSFgX&B;L8WL<14RT(i zkwYx4JTAkFRTagP(1t0s+I+Zkud;AHvZ=q+#HnRT>y9^(hwHR*C=ACP&C?Fk+3o%E z`Avh+;kAj|?f?{@rhq!o>+(YVQbaG;+maQ*`3yY~Dh7Ri9WRn* z|EnaCWq>5}f+jL-r8+Jr(aONB1w&-o1XB0u6T^NbsbtRw##zN73-j;e)V->zH4jy) zQ|Z3g2rPiy%K+!s&?U)Ksp!~3#6xudgXickdFlTtI|BxJFQ1s_2)u?jce*vRrK(K7t(o*Xb@M~>SM z=V5-oBOcH6*ltGWk=xH{Rr`(~Z}xeQjYboeukYo_k?#XcOyVxqXxOgK=_eH4WMDA{Jm+JOyFwQqAw-+m8S4Q<#o3}rT0aB_fhWMdOZ=qqZsAg8f^=}{z zW_3`LeI$KnRE<8aJXFwYkYtUZv&%|1>6^Z>_!U6WFbCN`c!wW(*Nw$yC5VT-@;*+I zE&b&x`Y?%f+=0zOKt|&KxA+Kb-`1ZxyO>7oe(6@zx9^O={@Sz&f*pfnXI_PRv#;6I zrMLUkZ$1ss%2;=zJ0zI_jCdrzpRs2w2nBoS$AQV4(3UR@OgW_7p#o94<9WAAj`&jB z3H|!j-=+5;3GrU789#CEWh%oLFzvAz35ol)DE zLnJnB0_`yuswtHxn@A{9+=WY*&!&0=LSrLJ37|u!H~$?-YuP$fO3`(0eLu8J(uj{V z>h#}i>Reta7smaNg^ywMam>f{bX2D4DFuD0xjl*|*&%dEkWDNxD3>&poV0)a$!7YR zi@`aIo;kNKZJ5L4J~Fw+NDH6yMuDL9Q75IvQIy=ko}|nlBw#DBIyNGvw=RDI_NCg$ zd4g0+Uq)6o068hVX@N!jXTF}yA7HV^&$Bm`OmTS=<^_*G#)ccgg8F6))Y#rT;k)mi zIa+Fb&eYNClRa%ljS|5F7f`g?vA)C!qXz~Vl)b>5`&9(3oZH_7_bk1l_zhTvY#qVcHN>xr+e7TFj&J%$%e zT82+F<}7WTZ6&=igYimHoAC5JHJ`wP?w%PV;8-s&=P0ElOJ1-zLo#wRh6Ot*BMO@t z`%@z*3{7qc-#BO*bgSr53ORk!y)i0C${ZbUDc~E#xc;N=$##2Xb!n#wb{9`MQX{Ho-0~~+oT1H z%jO{L)7)}#QB|86d3!5jWMJXa1)e>qs_WQe>bxg8d!}U%###@ei7Z`KnpfXsit}%+ zP87^UW48}qX>e{R4ZCs16No((uRN)fLQ%w*Vt zYV!${V1{N8e&$?BZ<%+V*W7$3LznG?m9l-~vF@brMYb=SUBb|WM_qeg4=S^?wj~05 zXoGgyU8nMl8>S2PI1Y;RvMMb&4Yc;-Cwt%8b$Gfy+59ZzAXBofHst>WolHfAZG?A_2z>K zVc$m5D9=K%rH2LkHLBN6k)Pk$Bj_@<=&mjc8=IU8g>(@*SO7=&{D{DV$-7(5fje+f=D+~o? zoLZjc-s)M(cUxdMfr7fN8oSc7GBG)!ap0enS)xW<9O1nm53VCgx#J;79HyIWnGiPF->RGxBspE3uJj&ruvOnGliIf-{IN|sQtXeq^*jXH{l>9MF##15H*->K7<(tQX> ztd~mL@&{|Rym3O)o2trp^Eggnf2z*Pob9>l;70n@ZRk2n^yU=76N?q$Q|NnZ=+s&- zo16R9FZ&v4<*;gO4U1+?c-7>ebNjHt?DYkmv}A9`+;SQ16iKTRX&luCfO@s=m!+Te`lkFPnyz8Lp>A z?ns@9%yJ)7*1o*nS!%3c%XklWAWDr&i!qCyZA>}1_G?$r1=tuCi}Sm2<)niBkK~M( zwyQt86Q?UAuD%Y}17gJrLnkM~`5f9&QxlLH5Kp(dyTR!eHPPcf=}WIXF*1KHPeiY2 zpQEFTauUAVQ85&sR4_-g-6e1me}woq&SeGIgrVi--j{Cc;=K2Xlinf(6jF#`Hb3ax zXm+JXx^SF|@+|oDg$JaSm2R09r7*)Tuzk@z(tWKjZ>|b=D|`$5jAG3*%BH;zZugVW zGS88(Q&;h~NVZqhY>JAiu*|mzC=&BaHvPD^lt}4(O)r;dCTD8QHRVULJ8kfsm=hYU zsu@xma?4^V@4XF8@EJ72qn{Pb)L3(x8dp=^;oWVftHLctc^B{pOpu^9hGRvol{Zgz zr{f|5q38><=uE6b~Nu2S|sOLvX>dW zR^3?8!6EW72AeSSDxzv_VBb?fv_)Zr`&b?RHCz6N1gB`GM`2o1i>WBeGIfhtO~Qlg2MW146q0BG!>eJ* z>)|0lXAn@ooik`^R3gB$c1JDJ(JRvbxRMvM>uR1RY3bUVC$LsOvDwwcJgCVSION`b zzPRkYp&E&n5A}ncDAJ|!a!oa&*?4lYdoOSJ-Fyf!$FfZnRt-<|ETYVvqi}&Q=qdj= zFXK#C-W9E)h^mpv$^o63feC&a%yp1U6?yH(Oi%cmX#7_s^NUOJy8+n&$-F%Qvdd zJ1&0ldlD>fQCv#RTxP4JGq}uPQZjX$hlSAal<&>hJTz;yki=9;-xPDy9z39oAvd&b zi$2_js&$-adsn!aH?hz1Ce_DH(^-+RY)|${e^)~!N%=u)TRgNmHd$6#qPxHI!j{tI zJWFw05AY)hep0tSu4@e9D{D8*)?jwYeV#94nAn~5wympEFM3zmPIS;a>O) z81__LI?44mn~7{R4=!{H9Ry*TJy0;|ws91c5d!nD!Uv0!$4o;=if(hay- z26{cmyk{GAWx`O|c;qJh5$y#dqHL~*(pZw0#Ed=M>vW`-#+w5CvdiBwa+~+6UJ7K1 zR>>~UyJ|L=BZw}V%7q%-^p%JW zK`rVOwoN!EV;mtbdGB*Dd}&RHc8sCrrg~?z&z@-4{M!2#LpNrNt;!m`HN60f(COZ{ zl*^f4EpM&&u>i9^RQ2bm*2eC@AmP2?>VuV*$==QW{xd|^88x>$GDSxorPOlh@S^0> zKNHfL$d_-raH%u;q3>z9S%eIoz8p5mCn<0qZX-{i2;d}366-<+VpWQroX+{%W572& z4#ivh&)!C9Bt+QZCs^S^6nh3WFOxNEDxBRjF^6(Y+1If~&7+#hecE%zLY>^_f~A+4 zvn&)E?ByoHQ~BBp+sZ_hku4`TBL_w-Ft{J`ip_FA#K=r)r1>#=^-ziXpH53QHy%Rd zQLRbxqgkF;8)BUWcjVqctfY=6!eg1g3Q%Ekmy+%h6Gu%U-|MOUT5Sw#;UBa8kE=YQevn z^6t#ciKtsZgGj>6zkY7H8`do;-f&2gKOdbILOT=;NDEp7$Eup0Hp}d2tPo{samaMKf>SGkuGX&$*t>`XqI8vf|N~K_7fs z8xiG;Q$*S7fS7@qFF%1;e0-Vy(L(Lj8~htY&*2>ZBmy{&MK_U|KKIDW9FJYUb&P0v z|D4%QXBRsG?{d9tu(AFJDoAWET3!@OKEb8CE@jKq2%ha-(SAR--`>G<#4AbI`IFUz z>zUmJ4?<)5#1W#5VMd^mWjs@8y_x-0h8d2WoHLBZ{iEUDvs&{A@|N7Z)e~NaBVS}e zGDcf&+SbKB{=_Ts3N9FsEY!ra={_`Gjt0SxymZ4!5Z3;x@^E;ET2m;;)55B3YeV@l z#I(#Pjfvyzcq51M#6`oJyEgvBEYt%0c=J6;gluEX7FN8&w!!jCJlo?u-@ihZ10M?$ zBov#b;#jqNVqr5wKD#n+Cx(D0MVz8*UoJw1j{T!dMqr252x8yg1o<7zC8UBPHVvS;0owttqb9+ zbn&z#(Ssc|;MZRf#B9Q3lxYeMr@>QD)vEpz!5A?Lj@|Z~oIPtBFXR<(QX+ zeEgrGWvB?S##x4KRrhUZZX$M>oE^%^=?J}{i9NlBiTf>i_wRR%(^DQQEJBnSKINL} z21(u7*eSNR77w&+-<*TLnxuxkUi))Zr^heQv^YD!xg8sUV6q@gy^r+CYxa+Wif(mv zo^aTlnHHbc`8~-y$0WUgl6!=3F}|ZwUFXW!Obioe|M(4i+(SADT##dJ(YuO%^iQ`d ztmd_!u?89}-P2f#I|vWgAci^3Dw z`pOzwh2oxv0=oJfV!uX?DM0^GWtt6aY!Hfv@EiQy*YR3hAm7j$#+AM_PP~Yba zb#+tKHagS?sM{hy)`xhfpTL<8B;-j&J0%N4je*8roOVK!XyjW2ZD3ThVXUeNKrieQhaoz z#rw-IlYH)LOQ3^mHaHRNVSUkcB0L4<(YK*%Y>|ncx2G5Gsndp(t&t z0e*ZT8W#id8@%I1%dJ>kW;9kjI?sCR_-T}yrV+rwSIn*GZEV$G7b>%#@yl;h)spY1 z4g!cm60r22mR~9ATL_r-9=bj7ESy%1o^Ze>=JNZ3r!;V$N#N9`TQZ1;6|QZFX6(He zYb7vv9uhBs`}hVNtJo5>WgZwAPnIBb#nEtg>5bV-sG~;9$-%djcpC$JZzo5I5s+TJ zrQPvqBqnm1J-?x$I>N7zS6h)zB(drVH$n;_v6iS34jZCFm6?P`4<4b3ob6|+<{`(y z;xnkxGhOgK>0zN^6&H48JVq_Y*~cB1psim8POP^supZL|Z~qLtEXx&Nq5)334fGv^ zBPVh7*~K;3q~>aRZAK9{`=}spUBzkPfFwnpj~4{wPr^kQQiY)(dSFS}S>GM-T8qhE ziw%!n4uF7vZ}_Cg8Q&p+mWw=%Q~vp+s)TE_y!T&B8+21CkRV**t6~)Hn)R0CytWWD zVJ1Zc+;aOU^Jf_kuHjN5geKVpHoCqix2xYsKl-J^{i@0P%6eO2pIgQLsU~W5=ezM> zX51uQ>TZ%CZxUs@oJ#%t%6qM(bsFs&+{Z3BwInvV6>EYPl4%y;Q?~Kdu_q93 zWUPx^F4sxI7m|s3N@iXudyw;!x#K%Iu`tegyl^)18EL{^xZFYfFr-LAym(|xJyXBh zR_6vd)I^?TYKN1|zSp_~o8plsu#l%?V|g@FQ+;;uFC-Qm_kGJ6C!RUqxL z=`M=xI}ZMWKWMfz==xE=Hak5p|R$&530XPAgLs2qNcJ3%>9qxL-9L;O%Cj-T& zNA{I?)>2AEP%&nsD!j*2M|TJh7S?5$_x4$Ids>70$~T_=0UJ5pUp`&^;o4HLo}gUG z4ZquP1?NKl>>_^n>6ojlff~z?OJ^iafz6_QFh_17>qAR+HD_+Vv0AxoyR>%Px^!BS z8oXqAX6g=-6Pf<6jaBtU%JMfzjS>D17d30*HN1uE1#G?C<0Cu)wp~(#xU_OIC|#OX z!mm`Q$lI#@{Wqr^$`oY2cs&83R6iRFNdVL5>Xy-&k^4K&r|cV~N^T?6gb~p2-Xi7{ z2&5syPf%4!YN}s-)FPb8OY?TQt9fwKqeu23MCi2Zj+&6K9|^blg4<|y!_wS}d%>QI zC2;oqD@qwGJ@c3tMu&AW{a&4{CNPwXM@Vc8hQ5d!Md>wL34P^VZtIzaspo=rAbM;< z?d{{K+#1?$Ig2i|yZC(Rv(`YtM?qkVnh#J0e3+Tf+~HYz>ACvl@}UxH#)Acv>1&@M zdsfLpKJ7m~=dJ0YJ3)lvM*G&fE@*S$9LvC~;$n*uO0sY+QxCT?N=WPh8ZOtVJ8nUG?a*h!SiLzszEeU^%yDuwn!w$YD>8H~4qX~p6u$~m_c9@i zvZ;)yh(YJi16Dic8}m6sAZM{Hsy!D%V71|G8c)eV;eT;dJZ&#NO&KoT@epSPqk+mM z!c&u)i{yK}&oWNqY)ZloHZvLY#y{n{7xIa7Sa5+)B!dk%Qb&hmUrFQNUdK$ZY@N>pD?+7-R(1yI3B6$|@hsM9gkVmQI z%^ra?OnA<|CdjVP@niebFgEoir-REg2v^iZ16a!R1Jv3Wgi(6o1yOJ_y>x9l=O(8E zb9stX9PTOD^o8ycCrQ_t5=l+gI;_TGPHxL(tR+I!!oLmlpu+O%y(zS$&0K-$u+_N<0Tjl+p7u7^sdwte$&>81f#Wo}!{ zLfOxO`+GqQtD^X;R+xRn?Sa=UYgS*25DHTj$8q8PNj+OhT!;G4)#gq5rj+-u;a)DR zD9sy#0=ef;J}$^hkL+jqfNe%!FMRW+K~@I zaDiKP2b@(YuZGHZvi@%iM)uyS!uuX!}WgeQ0bFKA9Z#!V&w zc7jlAYkGq!((Mb$bVkv3XTe5UjmeYS(ZE-37C0#JoL>vP2)#qY#36aX1BTdh*1$A- z?T^Zl$?M$fC1QYshLdA@|8VVDgTutAsSEEl+2Q(1}`Ls(RE`t)4I9##xusoTpc zzk2RK)=s1sIq<1)BhDEZ1;Ezg3lBmDa(zmV^weooV)m0GW8#J)bZ>n4TItPM26*#P z<%xnI<`|4&`D0vde!P_<4*RYWFnReQBf$AjpGIedJ`vQ(kn z8)yZnO&x8PbI-d0vi`#RlIqa?tzv;{Fcna=;~Vxh&lzm2Dw3sk+vKHPy23jT5w5U6 z!oP}g{V*X+)#ux8iEXoom7xE**A1u@t)#FXuBwBsimXmZV( z9l^r^L4ZnW5fgkj3rLJlB@tGS8&eke{Q)Z@tj!&`IIzOvnQZD`wC7GNFI2LC-a-wZ zsr^MosJ|(5Kd19hoZ0T~31K`guB{-Zh>AGFXs?-!-FpGmE}I#Aqw_+8?eTh~w}G>L zx_{f2J0pC6l=>9y(g2<+Re5iaA7UfpObVSq!`m}VH9VC2*iaM?Uq`)5f+Lmi#72Kk zfgulM)%tP+M*HiEwXOlOje6&Tn!+K6h4>{8)BX0*QBpCu8n#f~ZBxm1x_60tn7rB-thUaLMXh7j0r{ACo5_*HqG@3weFl?!wQ7lKdrtv_gQam+n)^GZD|8~UNSUe zc4_G>4P>|q%{uae$VQuC61qVgwAVf9Yw2Unl0fQ1m)Qqn%<{tCJc+8VzVpgtCi#^A zZo_M!+qY#X$}xum8u?g?ii@24rw9l&i6XhpCcn)|rWNgTP!`WXJVRZ!@^s>Z(?XTn zwWBn1HwhqtOMDX3k-fG=$sF8R(7pNjJ)7lT{8Cav`DDJ8tyF9$>h)fpN?}6vJcZtd z25C08>anoEGF8=6bE{hpEG7KC8^cduM_qsW_zxHs`snp*NGw0~Ak(!&& zwe421D*s!sHQfCGiJr0Bg*WOkhVzddZTFt5qc4&kBxFf#q)NW5I#iutahqD-!-{dfy1$qmQx(;v zMW_)K^<*z!)6K4AM(?0tj|g}}K)Hb!YV)qMrdl>7Avu2u+aPCdmIJBrAqOyKvmgUs z+sp&hj1kHku3aBN+!ER7um!2e)Lax8r^E1iR^3MCNv&qznftL}M?@V-HedEc}54OX*k z9yNSJRyWU(UZ&N@S1I=j*RcTyyL3_F3g`m)pVP6!DNu?cikE1>o-%h!NH|#mPG-c)m1VT zI~yHgF9rGo(^(!z10lcHYH&?`nFluS6yr4;v~b}=N~E)lzDP+{|4saJ2o=^{3ULs% zZP-#A>l`2uAMH*S8msoKW-GQFJ*;+sgu+(jJwfO#(cPu+3?mb zNqL^Bm#bI$?OOKQ4XKM6-Kg>pt&^fB#G-9?GGcE-&4*T16L-yH@U=?Z%?X(>Kmw43 z*-d{vbiM4_pqtn&vsqu>jp~fel@harBw8q(M#+>g`nzKzpLuMB%Tz|XPuqFZni$O| zAUxx7TJ0xZ%Ms^V5W5)oKIc`23i+XX_1Chj+dg#XJE@k~&lblOf`f!iu5c5Ip`xQJ zn{!Dr))0kMW2W_Hc}#Vj|1~z<;R45%v8JkL)hz<1vzHOeUI!Vxnbss5_selEZu-?P z&)eZ0yqUIsfdjj98fft=A&mDfNn%Wr@l&KqJw+c9iCaLb{}XVD73A6y+Phdbiki|1s6;5#X+SPB3qMkrvejC=~{Xa zd<9Uw29bh}ZHZ|wkM8s{YCWqO5K0ve`2+X$uHn0P2q?S>!-n=%cBjKF3B73(&o~*E zxb!-C(_V$%rG*1oiYN9o8fVQzoxHB1E>L6p`K0qMId#5M%b;Bf*9jCf*bccPm5lpF z_|iDb!MXFmWQ$Q0kBLqdPLBr8s77AciXyOUW4_DSBAQo(h{pv89d~@I3pU3>h_17G zF_2ICFANSUso3c@xwJm|16Gb7X7>@>s#B|62%JAZa2jVap@Lw;uEu@8kb$_h zn4^3(B5^Y`o-jF$(PUf88rW{|4Cv=_o_w|sAkr3!sLIsGwwn%E+=pu~&DEtS%N zIc4ndIIQdAg3s)y)D%AB9>jJLK0TJl=r@1OP-No~7WK4h9Q5Ebb@l@N)vM_55h*G= z%u89a8oR4ZOlGt_~NDlUQ8VlUz^R7P+K1}buuITS5-27k{W!0fKz~(B4E5w^X zD-+eJ5?F{40XNDRiq9c#T(s2R(retPL1H7_YzqN_($7cFVU^)+WNzy*&W1g|Api2x zXk=2?sYi^bS07g#Y;|i17g3oN;iu(l@4%Epxv1V=);MuRt2SS^?L%@CXXWY91Il&s z?FiyJ%?LQ*n)P7YujJh;GUHqZ>Dz+o%E$*~W1=p|_MZo0PNb7?uaZLwEs{74*RUT6hm-8kX~7rIky zs_z3+4*PV$C`ESULl;lY23bEo;ZXUt43{{*`G^=lctWy9)0ZiP#jol ztKo@@EmNDRk2zF>&X8NK%l9AaLNvz5sdNz}kV^*=o?>S(e&{Ed+}2iXd%>%>%`@ti zCsbuF2_*{1j8bwe)vq)iZ9ZQkte_$3CnkodtVvM5eN#+Lrfz4-|8_dj_DP6(4!6IA z@(pJ#)d~l7V*d_R2{!s_pwS@-r}agm&xe1p^q&pFigQ^K21&}eTIK^KRnDcdT3@JI zLISlWf&{EE^_uu86VcG5CoWwCRI;jC7wz!MiNsgF5QKO=Km@U!sLSO}JBvENm*6;6 z=`i0%R30{PQ7Ei~fJY#>GV*MiPpIr2UU^d?yk($iAX#W+_agjK$v;;=mV6iZnm%!K zBQ?N1x(6TcDK9#K3$rhxW`e3I1$kfTb9(Ejj+OiejK&~`jIizLrO3e?XQlqa-A@HV zrB-XO4xSpykN$oqJ<9l>o+Z*a;e-(g-%VGAL4Ia@sXKyiG>|J_l)H;mdX33yb<&~w z3-us=cx8fpLVY|hoGskIqYu2eVQCDj97>ek*tgaX)wnQV(2Z*@Xa%+R#!RI%T_Wp>6xj!WBLen%tgy;tBrdAt&iQT zpzPV4Nb|G$$f04?Vy>}NEc)DWV716`j*}<7v;Ewk`fw0XVfUuIad{f+sy`aPzYTS% z>n^et_DbZ{e@#p4U15oVkc?)A6Ao6Z-qIi+h|pS>(AdQ_O7zE!tri#YM&@&jMh1hG zt8S$pC^|};U86|MB|EQhiacbncAAi2oY!3!SOG{O)|hpVqsiXmCH+1(w(`BKn+4e6 z)x0L{##Zfz}$j6B)y5?Y&bt7-huUMg=5E`Pc^u*4m*%=E>nY0@IL3oqv9pV;>1#x z>a2wUCHk>##EUOPlPn;AAY`!ndhue>wUw2ye(MKPMm<8+JhA~d)^2SZ$dw|@iV~*T zq$;7$^=MzTDJOl49qN|gImWSTu^Cr11||uXmf04(Cbo5y!i!%cIAM!YS8+w2M?gbE zceXT8W3#F@Z-BUmpq#lR=!72iMQ3$=)d2Ar6sWDUWvWnZh()5Wx(v$WQ`o-73iOp_ zJE}VGUQP%zCJ@$|yI#di6;CT=vYs(8KX>^es~}VJj@b5g@v3@jfm=Bu0)@o3qMap{ zCk%brkDJdl>+3V$habS)RLzxLjFoAXE`EuP8PCICdL-5@jbDDshH1YH&xnkjrdl=} z_oImaY_ZJR?O06IXw6_Bk5(m`d94?I^vV`YLA6O-#zu7e6N@L7CXD^2J`$%=$X`Kt zS1@86G3%+jC!Hh^8w=<~9hg}L-vxVqeA(OqGTHQEzFt0M%Pt~r?HEwnVH3f=ME()o z*Q>KyzD059-JT7IhJcZ^N9DH97wwxM$Z}q3RVg% zI0#=L1l2k+^tM?XMw+2%m@e zf=VtMAy55`@61;VFPBi;nvnT)BJ3&MF%FUYx)Pvo^RdwLVmQDYNH`hYc7w$>N}Sr9s%H ztI6ALiadCQLDtqbAv1?Hj=J=fz0Jnc2+ly;In4f*w!GB|Z}m%C^RIG!C{`lyiR5^a zjH2*FN?^I`{KeNfr4&Vwt~k%UP+^~}=QiI1^(ljO2Ln6%DCN9JeZ4c<|RP;5}`Ly#D$x_ zL@z3nZ-lP~S5B_Zz^JE32u7#%v`eYHB*H}55b1ANGzMsW@(R*}Z$lsi5%`l5G5x)P zEOBDswu{ubRF|*x0bMk{uT$?1XUgv8=V($9hHAQ4&_EBAb5|I%R(1O9PR1q35wXR| zQOL&_S0b|Ds3{7uE*h%5Su|8`QQQPKRGQTIN>(}o>P&ondX?WP`|#e8yJuPrlv zg)fEA5aCJx0mH?}NsuLNBD}*mR}1=$3T>-;aZz=|;5%Yc0k#_>v(f(kG?o)5cd$_+4 zsjfq$5pgwqJn|pgDij(jpG1Cq_&4K`UL`XFL({<(^X{-q2Eo7Ip63qu7J3G0wjTh4 zd0*&$t8=S9oP+)Xld58i6Gk*L)KwRZOidZoWtp_fO1f{692q_^1L!Klm%@M2L-8wM zAnvF67b{L$RbMo$Ec_bXr*&&G6nSQ)D-Qh({c}IOY zBzTKn0UzowyhU2^_*HX0N_g3vjO9Nshb$(CQ^8uXfb8vE^89T!BY`lf2UzZQCgrF) z^{=LgT?GMwgb+H_F&=-xb^T^+Vc|7{`mpn()qZ_Gnw)Us_6-Bb+-Z=C%XuKc<-9uC zE2&xi9eFOwXJf7DbnL-2-^PCb=%4?P<3PC^mK^>j+|D#*#^QvGm{*Bl&3_YTw z+7EnBz%X%mSL!*aLq7v<6X2xd{3f^Gx&SdO-dMWw9YI*cdEUL%Hd8ufuiukExjmHd zX<7NF$aw#9n;zp2*H(~p(2$&*doh&d`|`j2NAd{(ITvf)9VD^;JK03$TrM5xeCRY# zFZ%_|v7b;?RaHkSPM-5UjYp?=&!83A#6b=)&yaAZ0c`@*%|5Bv!tpE;G;notTaP3J zdAZ~FKcfHFG0iMMpG*?ojru*pBPlpAQvyD)4H9m8h-5Z`ikGQjneKZtOSzeD>AqCB zhdqx!=Zv_S$gOX80U&b#^xOb^HX3q~h#af>qi*R43gQ2IyuJaNEDuym`(&kL+jTds*RCfgDwwQK91Xq@RT@VqsnTjtdUtWN7$5E3czy!8@{_Tg` zTlG)Gez}Au2LEdFt)=~qav`{FSdGi2Lk2%t14d#|@alnp-BdzoC-bBF?^{1b6{r{` z+03zDO^wXzAICtO1|}jLxv2`U-&~n5BAzf zqEyB4m~GKv(gjD+16xF^(C@e{FCY{OkJzw}+S`BUi{mkq%0N-7!C>2f3I0ipo~)i>HfdAZ~_ioxp9Lw3P49FYL+q(YJw|G$s0p-NUx;#vB9omnCk#|C1aAi2^@|?SIJ-I}Q9}#eo+R zh|?WE`KmpnV)*^z(YGJZ`s}UuW#-|A9yJ3U0#Rfu?zo7vWeAMb9>9@TL*JN@oH4P1g!!+rcTZU~ji$Q9TCn zA7}y*22pbIu@f@sx(2Vcl?tdB!l*r)TreY$2td*@eDt4)Y*OtR@0BJYcfy$7qXwTNoLOidv`O=TtO|4S>^s8im5A1cL(~YEfIf*!l3n}>v_HcU znIIJzsM8L)ZGuQ}naB>OWjA`OGZTsjwQDZ3Bl$1iQT^XPezLb93#c-Db2)=t?T9A8 ze*y(?@BZayS3ZXQ`Ck+xPB)zEE>%fv|3PBp{DF`1$?9(9e_44p7`WA?BW;MQ4St5? z<=l#Al($Aasr@~{4<3eG#~(coFhG_%4pqee(!GLcVj-xja21ovF)IWJK*6N5?J?a?9Tg{ohyJ@Cukq<+%1SG@v{835zRb=W$2e47B0-^nk+alx6@fBiYUPlAkm>aZ2!FSZQ9RLDilG_`!@XxHUBB6fW-sYveh zGt~IF$V+`v(5~_($kKlQi0GQNzSK+JEdIy%h>j2h`mj=*w;w7shm8>>ub)BqLUTA! zl*}u@b&T5TJsRN)L89}>go}NIYEiZ|0es~E_uWxUZ`I`ENt~I1g86#a|2LWRgB)JH z9b0yD1fLEGmp#VC!X~#2)|()y#ve3~>^A+3I7icglN_LBXQ&(F7_O@~hhHejyz%5k zLw4$rRyrPfxOYGaL*Lo@*--`KZwCJCRWJ>pLXd%E+Fxh=+2Fs7fdl~0W7V_n#$TTQ zK&oHtZwM_s!}Gca7k+okPshA{4ly+~z2r0&$mX`a8YP(h_=kBlRkYia<$>Gc1nJ`{Ft^kD(YIi4AP|gtxdVT38?%}!G z|J8JVed5dnS^_oOjE|1=An%cXB+QFcU<$0GE?WJUIH(kUg4pyr_HXV7WV*tv;pv$S z4r=CKNC+fW6vf=!9A4aV1Xukz+m<~3ftcE<70ctFvAPsiCK_%X*5%;uW3K{@sW_e^ z@hbz~?q3lfAV}X_8l5~FliaQH4B+1zlRkc@N>I+D#?Bi+#h%r`vK0JO;pSu zQXc;V?GgUn0P)I3y7gbeOhD7z+e^%0*ywwa!$484{pN9z1z6H4G?4%@je_V1PUAaM zkI$d@jw}ocZ}R9ow>KU156a^QT)uHdjve?cFMJ1)GF?9%_cKC+x+F+Ku-w}_j!(el zLru{2Y^%>u!=w>&+HyZtIYQoR*`la9RuYJH=<(A zPmgWTUl0O`%@$E|Kle=!cTe!kiOKG#K))Iip;HuxJJl>fp-IE4ia;siRnB+F|8h3* zH#qbCQw+sd5I2Ge8d{`^EY3@PxS%gccB~_QPG=#O4X`O}u)t>Sr80WT$v zl?2gA`nPQPfdvTpy_^UbrE5ZhXrlbL-+F^@|MR*KH#YR0gV_P}7fKyHtiu8iRnFtQ zeSF0t>T2&dK&0nW9b&}DrYprsY^ob4;-{ep-smd(dg~I(pS-~6<>`I-&e+C4 zUEx8Lj=}I*j*s<=v$;=QrkR_pm=>aY7MyZ_Oq(E48^_2D)+D&YSh~MG^F}h1*?71D z2CmK6My5cs0h-|UWIU(!SZz-8O{|16x1GEmD`KK=`@Uk9f#PH3?9Qy;Q9tqjP&el^ z3?pQ-rwJO;D0HyP%|`YZc?iVjG|&WiPJ(u$emvaD&wG#cU~?J@3SC67njSL9$lv~4 z%OjwN*kITi`HSQnUc+_x=rbYjTDyV`eQHXID%5c8cXxE#c^pDPtmMgQ4$hH=w1=bCn{mM*xlU=y*%`uWvA_(61XP_S4^9z@Ho&2(iN zlicC^CNqD)?$O9`trfHT^ma0SfA}x{h!sceGoX(C8dtU zY6I5anhK*Hioz~c4{hrAJeD(LZv2b^-@t@K65_D7Ops@t_--J6_tQUMJ+eT&W;g2n zewnTN^_I(V0;DwG2fqvW4U`{Ajbqe@q6fd9QE1=Mc|2ITcOByQ?M6ieE&Ui5zj%;O zY_+RdmUh%~r5?Y8e8vGdu}44F{3R;b;0iBS$8F$~1TvQ_emK=RjA#q}25x;cimc$4 zezfd>>qh1hwyk_gNlEFI;rnHM z?8n()cWEiKGCmgc_vcwvCVJahv2{SpUl}F>s8mVP~ZWAD#O3){?#q*DN{nMKg&fPM+e_VMsyF zxkLK!RP+Odmt9TjXhY3h9&=C~Q)}q7qV!(Iv%gvW*ROJDVfN<6tkuWi{@?Aozu=1j zw!%Ii(&Q9ayUU^FQljK;oWB`+V*pcm)?63=6q41dkiz2MUHoV~-Tr1PDJ8`uaYo@d zw*1AeI|9NW;o%v)>^oY0|3Nq)&oMB>|Izgag&`Vti*M;>kxR^Jm}_~G%7n&%gf5`$al{2GyTY-Z08k?t|b!}nDo%>>z4zh5^TA@0x&l(GM z@V+ql?t>b=LQzsEXJE>)Ec&$<{WtV9dIl*zH84(hte=qO?QcE=uOL_#fO>vJ?w@g- zJ2jGlQ3vp|lUh}t7soA{Q0)3mDofKgzj|}^E^;iDE;$T*9z4dDBC_z`Ozg=80EMzP z%==$Rks|}-B7LQB3LJUxc z(kx}0x~keRv{rA149}yB505xxAg8@L*|SejeacD zwt9Gn@=v5aS$NowXHX1S16z38uF16-oF53$PP^EyAUnR*F0{WCP{eF?98Ez|;c}2d z9@F^Uf%(b&zmlcg)3(WTvB)75@H7ph?Cz4;0{;};oIw3+!XPgb+i)5f1e<{NhsTPD zQ%W10YcTKjoBvJ5K(O$Qx=?mrOa5yKfa|evTo8yUxLW)kz(1-s)i@wQA)AV;UO)04 z8O0yJI7SmE>B_pl#tB{S#$2$zcF0CnOOFiW7AN#aa7MsRVM^`o zzT&j|6pCHaXAZQYEi8jnP=+L(59l5qs&> zs|1b@+F!5EwM#5m3!Fen7akrWy&&^BJy$29)x2)CqEJFKA><@#S-y$~XVWDm z?1DBX1W9AX)*(r$b=?ixMztM> z2gVusp*+`8=aAlWzHK^NBzPog_fbes^}k3dGP`46iKtg{=2n=5x<}K=7*F4AKgz&@ zXLEcG5~Y0krqc#T4^>}2JlM%C5RJR_A2?l6k7*m$gW3Nr!)ufb@vtXVh>=O0ig9Z`UN89ZMR+LRz$C}jRH4YFd@x~g*X3|o$Vs%az16%^gHwpe0HizC zLc^%-%!ayiQ;r;0qpL7<5gC(|ln%rVsi>-cKv3?kB-gugvP*#bj)$&E@0mSdm`b+*h9=e= zYu9Sj2~{d*PSng6{#A1|YF@FEI`LLdzPXv=(?c)jDxQ&Y&v?dvk#US1SD<5=4lYjp z&?}52$iGq&aA@RS0mL!itN$mX|Nj>LrSkX*&Ho>%e?pX>`D_SX{r{x;m!$cb_4@y* zaKX+pmHRkRKkutnr{=5@RVp(F9dNwSKRp;jQg_4z4JX!ug;DWio zsJ{PW)5zcI(J(fcJ%@dG>i0nrlEY;?^O7^^`I^^f(z07awV*xf4JL?d@4pZFyFYTS zoVZBW+dj$(Zsr2xSa&dO=licQ<#p@QJ}jJwNX;4O{>_UAQn{m7!w?wJ)TErI@ zjc;r?+NK7I67w=$D?Af#|lRbO^eWKpUb$r2(E#^%%xT17^yoI!`6E zInShr>gp(Lv5X|iL`AHFcbxY>y>MN4uXHRNa&uh6UZ;L5h$z6&nDV53Glcr*U?W^;>p&#<6M?0 z0Zr1zO#&PB#Vuc*Cc^23%jdy42HOrL*UPrN(rgb7;Z&@1Z%$6*Dkfz0p|Le1p6??K3+XkMPXu)8yKAfx5FBy7@^p)uW; zZ)r;IzmF6bG(SS6g2Y`8G}ql+{9;^1pv-tSce<(WIeikw+kkh&kFXM%HHyZ}4}Rpz z3KsC~p*BoM@vt-nD-bGhJm_4o$^LX|rbJ(Wz`BaJR*vXYZ?37g_7hMvO0yM&Qj!Y= zu5V=&&wqN4ZpDs*N9H&TYqdMS_+VqeAxZo>U9i8vaxL{0aLH(sd!mBOwFFy!6t+)0 z3Q$>f{PI;6p#vbBuOsw4XGR>YG26F2tZm@Z+<7KGTWo5W0Et=;>90Zj0hMYi>`BFnAifO>2KS^bP?CaqpB`{t3^W zw~_BJdf@laF_-Ty+k#%HiL`U_?-#%x&Z)Yf#<@wjotjZ(()fQEd+UHIx9tm55fnuc zBoq+PjdV$u)Dch`=?3Xmq+76Pz4!h(fo%8Q z>sxEiF~=BlE)#3m-{~qkZX8>g5TIw?V==d?F(uu zgbiT;2BGS;cnzn?P|1Gg{JKl2t;7(0=txVCk)J{zFa+S2*S9Bvrq3ZVWYKz;WcaAB zx;s@N#e5 zj~OZKBajyS^u>`%mCA#It+9@Nf-@>=hM{Jjeb%>FXWb5Wrt2xo5B1z}i5B&kGr z=R}sE-m2KTp*G^fc_P*u^$`t0Lej^1vKMi-9dl#V(h zv6QaORO0gBv6a^?!SQY#({J$qsP6`8L4N-r?e>c!CVkrYiyQ_5O4?hGS{TC%AKkHE zPLFe@d%M5d;#7UfBV5g`Af1j49##XB!7rifEyQ<27TpL;Q7xR3VN6c`SDYmN?`PRcWE`dq3pA?J6tRd-#fUvp1AYULVpHH|b36BivDKZMjnPfkBe*Wrtc z70o$pQCI{KKgF(3jd}qh9c`CNII|etqF=|A^kXc#(8M{B)6YL(^SxG_(RNu-Iu}7B z$hGy^CcXB_nRE!5%ooT7s%+iz^CtrN(hA#ovx~TC0>j71_i)kOW;4^3v7UNQu&DSv zUR0e|2)X~^xze1<`bv1szM(a*N1XkTY47eOKYNt!ID}}~J6EkmoY&g8B>V525Z&Q+ zfH-RlF+ZKV8lqN;BZ-A2CE=-h*Hp*KStPhL;`BFcDye9NKA|$J>}UCX^3aD$gj#9i z+%^Zhu5k_MKDkxnb82!e@p)@{^ITv}tOewUnU}Y*KiWjdKN+)}ub9i7@n>t#;Jj@9 z-IeaJ51+Z;_p+vRBx`DqlmQoW$3rsVHQZYd1e8z($2Ry0PbvZvzMb>YA>xxildA@< zcPVD*nHzP?gA_Km@4?lNcA<{u=C};^H1UY2n_DvOB{w_FeU9U`GmD*`FfchX(MX7u|HX5F-)6{<@&6!DXK83l84oi?qSOXSag2 zl8k)bEos>gQr45Gk|ck&?UwHKqMXfUBP8r4V8Gp~|C|o)fK<9T_uZK;dy88T)O$A< zj;D}>w0EuT>5H&~Y&(U|NaHc!E_{CY;lfPHE19f8gD0DUd-H|1K%Mmt$ygFZ$@Zp= z|7##Xwkfd=h)EOCSwEFjlUlS%B4S@F#8_W%^ftbDWH|XwklB_iq=(*3zt~l-v-SCq zUkK9ab~PPF>=X>@Gjb3t18kI*>C)RRnU#`$=&|mxkNku9LV2ow!y~%NIqEopU)!0l zrJY+g?z=i-S~9`sj&6O2)3=GeKk>tn?6s@YDE-^|AsqdhY{qZsFJ6Io<|aTGxiC(> zOTHEZqV}5}1OMp={lJfE2jguyl8nWQ0+($-axyh(YHhH`FN(G zEiJ9+Y**dZKRJ0SRc&mHx-3Z_LF;czcKfg_|AwNkZFjz^`0))hiMbCgbj>H*KP5L2 z;?`aib%LC}7Jawn)OBB*6(XDPCXsxIP}3hE+L`;ldzw@ieecW#V#RsRZ8p|{dRc?O zE6}`=ON~Z_G`yJE$;5E87{8>!7CS;U@e!U9^{KAf95P3u3N4d3?yXNb8l~%>Z8}mf za1LBE9-)anZrnKG>5Oht7T*!$%FR8mfhKT)lnLLy8e8NWfTY7je@!9 z8#D2~mu*E$d?TVS5V5A%-Y#5>5@Z&Zl*_+4KyiVD zlL679oW9CeeJ!rK1si>`vg8*ufHNIYkH+t^`I_)regm<2iesV4Jyho|@Xd_&={uTs zy-Jd`m#kR{w?mBI?t#m;3rV1DZqjzw(7N{4XB4soMqd)U@qT%HstaBd8x(#x3)9Scx2&v&MSeZI8mC0)@m%v*C=xl4u*7*?`}(=%QxYp&VXLd{d`lrqoI52u zim&j@|6nXAfjOc)NAeTUd+z=){ZwTbBeLUr=-Z?ajhaeo1^t-)@%`dM z8Lr8i{-_!hUitMznqa+(DoqFwGh8)0(uY2l#{ie-6oK~_&(#w%_6tL)AO^QSq;}qz zRazJ-tGT6nT_%u>zha1EV*%eLdN((6wEV+G!Kxuj+;z8pEr(Q6`+@70Z#Vi(zjr3~ zwhtfM;E#oFqZ7Lb5O`?NGKaRNjti`1KH@*Fz~Pt-qLHfGZ>|5bBy<*_Bjpx?ic=k5 zeG)v{=`efnfPenY2l-$%z0B0GtiBb5yQeL}5v|z6)bXn(hX+d@HTxld#23XIodau`k&%+3jcw_4&aOza|32P4`=AhF8 z@G-;eu_H-)1tr4-i!?(mxFbHp`)i9LH6ol?Oxw7~)%c@*2PRm%AdbQRtiCRlgvAN1te=^`ezSxKF&zifT=mBXb@77W*XB)(g7v{z%+2ps}n*RypF=wbn9r1F|s?JvI& zl!D0%_lrNo^4dx0cpTXM(4?SJioq7x{=yF7U8R!Bek#@hW^FQ!N3FUyl+W zzO6+$g~BZ&ja-7k;@`{`YW5Z@dkenyD!rKaqtvJKj5rk<-gH`9dv|L|XDAlH>5e8H z9bocb3up3XB1i%gN*iH1)EUNWGM~@Ni}T;+xh` z+-Sq$-cmf9cwJHoWcXCWaIKP|zY`1|3VGUZCBpsT_!nta z<9gyi;I!L?LZKT@O)Mz6kzuNOK8pKZZvnc@luZOmHeR)nYUjm;A&qycK60S3&Ys&X z+vwA1iO!e)9SVi$@wTC9qANl8Nf$Eb1pnlD7HXP{da6JqNK*Lnh&VYd6!&+*-j272 zQVjmMk=(;|XGXoW(taUo)Z^&Dm1)T5-8@1exB*oc_jAT-G z1+!-q*sU(n%UU7Bv~+LS`4JB zmxA2q?7aTzPB$PPm7Lgy7}NCha*aA-RFXlF8fTIhM2ReJfH2h@69e_=89d~P#4X7lkpjaioz z7lq~GYlf0bq=EjbkKnTiAPK(+XqS={dah;=Xzsf}M2ow8u-d{L&J?gWLEW5{og0M| zq<}8DCgTCxv28$ZJ!5?|r*k9$piO(Gx~$|*5Sf!88m(TwTu2#LJ5o|OjS2q8-eb{k zNP+EN-Zu+u&}7m3bMztYZS$^K`;%(-O!qI)qqR>wQ^DPLhX<7gNvPX3>xR`IRGu_F zIIm3IdVi8(>`#QMGS^{6%~r!u$s+qj#jN1pE8)B`@jGF3QejL%BwvRR*T-AZ^t^P? zC_1#gK3Wobl$UM0#Hm9A>&0*xaIx(AAhNL=G`%#NZgD`Jn1GbaAgDOK2{qI!z?}j6 z3hws|Vvs^xl4uPjDdt4Wsv1IGcx(%v@N6KA00N zz|OIEhN8%qZp|27vPZc!-AuvS|2X>@K)rlq>>8kw9`!3-w9!3;%3zvnmEAsh#cysE zzZDMl1K!O6eUi#ZHEo^!ah=~^RS29AD4fJxRyZ&{c3HMn)q50=6CvZ%7K{-@Qs~|5 zfXxyX2&hY*w7vl$;81HHpuCJkpr{5T84l%olT-*{gP4n(J_Gl<6DSeI-ocNrX z9v3CUGZ`Z9V%-Myc$~6^WpP!4NqVfk#6^K^U1C0ai(;3F3e{`taQ^|rg{$0eY^`39 z+TYz8b$JkV%juEtiI)Q^zrGW)DR9s>+Flsh|1jjFK-(4X+tp_JOvhlw)&RYBJe!y( zWYLV{-Ryax*I3?Qhp8E$-K*2*ue_{qSh5mOO4$D6e6e9Fx^dyIOMEqY+=u>yguJ$_ z<2fuA8zbh&h7rL{Xa6?jZgXxA(3=E4Zo41#;|^&8Fl3HWfUR$vRKO@?VOwZXBdzaRhO zTqVeOe*EAdqaa8U)8TOCp+eSdfp}~`?~fuifceePWPG}h!lA}eryFm2-~vfaKtrxI zY$jQ#rY$mu!nK`gJCso7ItCSfCl=%QU1adMwJW}Qkg)N^`#SX?vA6;PBOo>oX_qMl zj`{^85DDpHSvahfv9A^$8SzxOP0M6DOjqb^cMVu({}X76@PYhRZ+_MJ zw2cif7acoiLTu+4iWR$0=gUUiOdK-lgBO{45oBp~`Z^$Na1WH6%D2$8ew7DExhvES z4l)yUo#Nxs^jGre6vIG$_yB3B*CN?({=!N(p=8^amnGa{`o})+mm@6pX-zuyfE^7D z#^BUHIJ^^{72tpBv7GpMLEv#>2X^BuJ`^OEXK(dip&n;UbXh1?$;?73kXYznOg$(m zVwsMyDM|f$<+yvf8`lx2rZk)S*4RxWCdnO25jIpy1*e5fjoyIVDx3Xi;=nmzM=lkHWZN| zu#b4#IO;uXfWboq3nvG}ivuAI$%sx@@BP!Wrkx4G!Y$I^JH-U6Jw=wc`RCgmU&KFlU}qoTmZD;6vs?fCSm+7H z^9v+lfj~&DL&?Nm7C7Fps_O%+G{YImo={4Z*L4J+Lhhk3K^4%&fHZ(?oEhMO@21DQ zI~SX)kGIFzv`1Q1%%puTj?&L6ssWTHjZK`nUfodPu3S2%IwAM}(=>^0qyjZ`;oK{( zpY(mg4IDL68Qz%`TW~3-&?=;*0Mf>9Bvy9^^=n$_MOlr*(kPE=641y5N?hRh zU*S#pk!pk1i%i>Xqt{ow`3YqhoEQ8-3PN?0MBh1DtM8yIVMlC(^79Di4!TW`3YAPu z1U8Jg#nv0ZVt|nCc0}5 zH}ddnuL4RG2iL47l8C#2l2)y7U;XxR271O!eci7Pv;3eBbnmZq#P3yumJ=EX6y)9vJkyU8 zB#83!Dfy1N{h(ntnag}ICs2}IcBNzPF0^a)CBs(H_M=YIUF8FyTAk?{JKQXFwLr*< zWU+v##La9az5m}@t$GNYbixg8+n*hd5lU$Jaz{wLdg$|P2X|Y}l=fnn_v5D^R#dCs z6i(d`eF=i$t>6b5aJ+4%{APMrpuYR|?rE77d{wEunnUNAupoh5ni1k8u%6< zBCR_jUm}qzZR}vtVUQ7x1L@oRyoj(LSDW(T<lK0mK;$0TVj%C|n zW)8DIK=&Uf`9HR=dWujb;UInNuSCh7EYuiCx;B2)6oylKDKrd*#H78F72t`56TH*c zBySCG)A8_)h=GSAQ2T2gY#p~=k$LQ|*aEOgk>(t{0qDsEUL<2$bFi6Rq`{+#D&P{) z6*hS8&2TaJ0t)RsD&h;MeXmQ~FB8QLYTR z0a8RPVVIA~V3oRIf>C^<`Z~heN&Zm3H;_~Xa~YS zn>ubDl0<0l?HK*3)&8Hs5yG?|At-yIf@HBj)t@LyU3h-EeTwM9ttLLYK233QAxH2I zJlpr724lqT-6O)Z-fMDzCI^OgJg#5Rtx7Q=q?qrK4Rc~aoE1q4QQM2Sqq)XYc` z>HN#dNB22!8Jy%%+I@cG)$d(F8K%dO#GgjJ(QhPmXssmo*tf>Urfnw$vd9#~Zl^7T zvw+e_eN-Ev3$MSpDz7>9<2IUqg1x8MB}e#V-D<|Mp@{GO}wUSaJLL(R~zN$ zW1t!E*wiAv38awk0s6~18X>m2{+47?t1tpBV+ICK-jx+Ru;m3JynFfUhi=daUp1D2 zts*oxdQ=RzQ*NySQ^x!CIiL*9+7x;>lVw-ftUi|^8gDu-g;+{3#ho;W(R|OG48pzT z#W@3kJWV%7)Z*O zhD^M+gwiQhR2H#Y05EQ67rtJ9a2&julp&MtY_4rW?t0l=xIE&vH8OM2WBWEQjB@XW znPOebr=z~NWB$Djm0pB7*h>}^Ku?LzNPVuPu}D0Ke$1y)_)17JUba=Hp&_VVAm954N@NM-h<3*xuBRgo zn%<$(@h?bztFWDspPyO~aNGSRg@b!7A1L=U1XRFb<7VDu*5Zy0z(mi;VE~SLXBois zqc^t=3^H;=qJy=@A9(C(&>6$@$%=xG6EHAY zv4KZas1~smsy;-}?KMC$LHmxV z3sMLrRow#Am8$E*O-3YufP-&2uO}sbi#h61Lg@R4pft(+C@DdCjDG79Fyd|yjm)ST z0-sT|8w2q%N&)QH5wb;#)9G8s76iw{3V>o8V=n(cdQ`$EjPc78D{R>kZKai)^Mh>0 zM%C{#V;5IA#@EQU~3*YmVpe$%*I+%r8fI_K$Fhc06C*DP(RN4xzstN9Q=??>6x zdotJTvqE^ZbK>&iM}$pwFhCKeuT4X1WvHOvp%UNVQ@*z@TkW2-_epB;Km(p+&k=po zM4wmnHv;^MAS8#hdmwHm09LJgxCVG`7t<*Mxly9mL~qC6%RG6EdXKsbn2D^3LpJVK zxsQ5A%}|4t2ShZx z!*lmX=0UG>9!O0{CM~@qlsg7tUYhzA5_dQR>2FyZ)^mpqr`jB^?=uP zyv_${mXiTE*w&GulBeCBQ~0+ruD%av(%5}6;c;AaGX1#Vc^_+8ZqYXf@{){7ZN*H~ zjlY9gk(j66sGNe zBg$)VIKWu-%f4vBfd*C@GiNZrto{{_OuW@XG)81l1^a;q$W5zgnd2h+<2!)PWRaSt z0v^oTS5+E>Dj*1N?VNsd|3lYV>X?`A0HLQvZ{_Qn9UW|Sc;fIouiu6Jw zrqhDcI$e$9aIsw(1%c4g zT`YIMUi63v>hE{Y)aU$N|FO$mLw1L=>r$TD_};eg8PX8M@wi?&cEEJz)Mc2v>93_d z?&8j%?z1$F%YHR-+}Gk^y&WzM&X^0Zi`%ZSy{1T4-f~xST?8l`3ziR_N==4GKC1{P z%lswCIlbTg-n73v;=9>#aYVlv5B9XwVc!YFlsOCjz}?`h{lH5d#@RU~bTw7N z9Vj|)C#iKlLR4tDqkHg9Uc^>Nyq~cLM8LGM{V6UU)tY_HfjHp5SZ6|$2mTc+P4Lj_ zs}iSN^~9#tCNXgh+z@9P6xLzn?ZPcAFSfzmtGVDfkH5fWJIX5kY>d?8?$|`VGSn>( zX;qUl9Ey9DTh?BKnKX%8ao2xG+5j#{6KRe2y(B!f;_x~megvFaJ4=*M&bbSadQN}| zN_sT#^++*B@)$%Or@+c_U-~rAK`S##*40dPjQh9?avE*i0EgRf$^!mB#UK0_z$qn?MM&$zW_uhC zdMvUGn#4DCh1wLlM{1CA12GGZG4O(m^C|=G15Mv~y!^8C+yW>Rp_QQ_A2j3%ux#IeIwJjSbq{~0`JNk73`U>~ZW05xqfxm$9 z(Yrea%iaRH;Af!CJpv1Ya=lu1YVuPx}%?|fi`Bc z>HuCXqDVWn4cqA2;X0Bj-^ax=)bo@@ClGlo4u>jb9)x?RQM|}SJ#BnpJj6W%?vJ2H zx-I-$pI_zp@{+7FoQAA@N|B(&;DXEIi1C(K$;Q5a6569X09vx-)FvPK2$}$zuTB3O1rmsM>69;DHA79v5IUw~?=dq(MtAiB3{S@&GjI&8llOhe9}rQQ9f-9y&qY@H3DK4LUQJPl>UNuI{!B zGmnZXx(fu>C*>f}g&E&>PJc!99?Bc##fyr#;l-`@RpDNe4$Gll%t}eh_LDp76S5w= z3bX;Xn&en-5NwwQ(jw2%{p((|sO*OIA?Bgg-%@shyr*i_B`l6{K4Sx3zoi*bB9N?{ zVH0)#DEVos`^9`t%wj4Ap2rg>xr@C}Ks> zECww#uWYs#_o>r&XrZ_(XzDdYAi7$+>AQ(_t|5Bq6CqSYISqBJt^6*iq*15tqF#xW zYpD|YX`=4x0-wfU)lz$n#lf2a8^VnXwku6+OuHDmSPWc6WeT2c8Z9E5mk|ziY(C}U z3?Xz9x8p<&X#5Mn5i$90FDVz(j0gs3#K{t_WsPgPiiN#YQdXm^Ia|V+?pSEvnyg2b z{=0}aX+aBZEqs5y+Pra0NKXLYL(;p|8TTP6CE-Ei)_w%FXvwpt_gcfZUSD4e`z#dT zLAT(t&W!e+q7yY`&C)RglwB?d+VaE_Da*8ftLw^EW>Q_uO)pBl_D2XyP3rJDpF31X z#_rw8GvBW5ch!mwn3(AJrO|T)PQ!hV6so8xzu^0~(5QS@7b};PTi*98t~Dj`|9@;n zGs(-EqxGtFmjv15$1g9gC}`7_*X&nIl;{gfF%bHe);C0}QktJe-wfVR{6hC$P%e`>ZMl>+#nM+pTt{vD?pgt!%6ME^B%FPj`O)m z(tK*fd`NQ<&D$O7Zz~>MRLMkJ!sJOjkL?fS;}6^4-|HR+hF+R$#8#o2x?s6}Jc)=A z@QD++&dZotwJqM%o}K{>H-m6Mt4FQyfLnX4kY+SaolRB1>jtX(j+>#g3>wvJx6Lp6 zlTbnqrXp{LZ>ybX+A}D;D)AX`$ymsJctp@yMU+c1ALcUZCc(2Gs-j>QA~D zO5EsIH(oC0lOFJ5k#oLl8*U(=mlVg18oZKTU0HSS zalSuTTM;K(MZhUxaMp)w&>g6CLxqB&_de_eIGw5 z%kwxoET$7VAsiB6-oqK5WjiWwPBBLMx@f8X>LYOKF&k1dN#Pd_0YOE)7rYCtEqk~$_Ji%DOS-&+FMd^iahIKC2NvrKZVp@&G*te_FVQF7& zSa1cEMY9rn1ow{)GjX)*bkL8rA{P5x7kC8G&+>O~ydbCFabmoI1^t ze95nx;yNvRa+%h*(rJR9xjCoOP6v0J4?7)mqeiKKwQSAV{AaJz@4^x(m^o3)^_O*0 zkn%U`Q=Nvu99D!k34rhPDx5<^9r+=(fQzaNOscPB_&0j020Y;F$E1z!Vk39_ATD+B zPw?K1D8lZo*v3P%da6P8g_ zh|S|PhLngXBoNeuP6$Y?lO02cv|cF_pAo66jWS@zt?KXU%WLtN-!d#0@dg|Gc4ULa z-&}ccJ}H;yo~kVni+vWv-RG+tJcrOePW=6Ry|`*tB0vz3m+PMYXO(qEE0cLAgPkkK zZB94mkZB^j#tCPB9%@f9JQJV-WJazM*h97bX;$g@pxy3sb!h%g=j94}O24G-4}sX5 z24$gO{rgbND(`2j`J}akxZ7`_ehJahp0=+dSo@(}y*`~^M#IYR8g#4Fxrv+{pj8Y_ zYf1uC<+}fF_FqqLqQN}~MoPVJb4fiX^e~YY7=V6AL>dYnF|9_ z+|hb5BU~=hQ}Jy9Aw7p4ruCPWl~sB4T9y1BbE8XmZXPsZo^I_nCK1l3k+f{Q9kXLK z9?nqeb%WnU+1Msn=?zUW#!arxtremL7nUQRYko~KTokEQN4WdxeR~ zqRg95u{O(crsPd-shCy4jK9g@xmj7K5$N_%1;E!beB2-R?lsJeVwsEgB>NSPh^4QM z;;+Mq^yE*o3da}J4$F3?i;@&f`*u1vpBNJY{jjrA7hE?%uthwiUxRb9``Hj?ThX}jiKPARlfpy;^pXG0g|qM zGXljjJT=1PD&Up6-xj8}Qlt;xyZmcaAjjYAMq4ndI8AWuN5}LBnCm2x@Bt~$=Q4LV zTOl^`k>^>m$mZXqEV$UyDulx|0?&VEG;$}sdeb;wlm}jbVfwMD$(CvfxlYRHQX)=}O>EM9hR&m2@=ItAC*EGG2`b91M$9zj zI*8VY{kom6dxv_K&g*P02sP??fsYr4B%B`B13#W#euMRf*kcDv$Q3y`aYX#e1~fiW zeuyIbwzN3J$>43Q?XkJWo?#}}mkSi^^+v%%7Np4|RsX_BM&7~m zzQKX5gDI|>k4n|Bm;PaPsu3@t{exzIk_&ExD>2WZXG=Pvu`}_u!aAQs+Y!~O@Nq@$ zB?eurF=JsXt0}a{eB3&mHx`tf93-Zajf-*L8y-tTda>dKfr^e&EbpqmQ_~N6%V&fZ z)r-2e6M=;omw8UzcWS)Izus9zvepb5V%5GPwj&LiNLK8&6*a52$n$y{06aFtTvnQ+ zfgXBfyKC`BRYUn*AD1`*@2v9D4UPhJ-2Kk;)EXng_c#MpBvE>&2Ds3bb@=|_fyGaq z3^LjNAPQJLr!IOvC`ios-(&k2b*>S^W2YEatJTH4sFEgx3PJCP(h}_qJ-j*j_rM4 zqvs1v!u1K_`QOtMQ>!;2M~-%yk!(~$dCX`09aIRcM=zU@ni%onvV*O{FdAXI%HO&l z?1qlM9?Bry&MkOj)l^spjUq!En}2_{28!YQB&F~g82Q|NuAEuaz^1Uqgw*fD!kWI{Ljd2K*R zOhbAZX$wA!zH>Bq>AhpPz6T8hQi$n8{a162{FuX_VYuyw3tTCft>9kph=qVugjH@Ztpj=I{h}1LQCsX@$LhJY?Lr>5RB1~|iqyMQD zJWEi^a0t?Xt7ok-T-Q0;RnZ^{vu>S21C2Yj4deW;No1V`7-7IsSDEO8_xz)uBr4)M z;Wwl;mDPvK4I5^34qe*>mjJ#Wuii={V!S7V@VpM9;j}rg!(t40AZjM-Z(4sDaTsfR z(CT06i~MFGc8?@>{yv?GlV<~6URB0NC)ubft7dPuSKP|Mf6DBrsv z9tugOas$g!&gT5*0)Fs!@z;A?Ua{{}t-^o6AE4`lxyg+*v_J!NAI*Wn*?&D#o+Wgh zFP)Sbl7eb*7eM~Z1PWmW`Y9!X7p_lfvOMti$HJW-?SW7fbO^`o_K!|$VX|QU>jew- zS82Q`!?c}euAY}4-NGj2{dOLgrPTj~ALeWC6|r}9r%5cprz!%rf|dugmW?qt3#{s5 zrXj<3400vCCF6JgcH$Z4iM(v~lsvm$4vNNpRsDcl#)xCrCPAbsLHAoz@XjPU%XDD; zDr@$1@TA-EtSHnC&e76{X0xoce5Iemx#j%cStiTKP}E$B>iFdx?R})QMhcWpUKdd8 zp(Os$$2Ly%Ovs$jn+y9QF*{97Y{?X=vhNm?8}-e~bN<9zt`&CQmR6Tt9MmZ-$ELXo z>7Q8x2-i)+_~jzil>Ns=dgMTMvzwqp1S5C_o_L)GkA8l0k{?sl<)(fW!`AzH`FC6! zqJ{MHC7fV*y_9e1E3vRAO{|{=44oIa>|NLtbkP0lhL!d66{;vX30LdT5~t`cI1%Cw z;64xz_;TooWwy>kXhjP^Dq;kK>f%3xZH&I({F0{FYxrs~wr(4w0+`pEt##-W#XVUg zjXjcXGt2E)lSJn5+4_g!3K3Cwq31JOjol!QfIuYdX@sOSbcLOfY=yMkJ8Kyj`+Sps zm(a$i>E;z8ED9{$wsO6;!$$c;%#t7{1%ou2DNEQ=_P#(4%RxYYN#gE;v7)U zZCUA+I;J}58u$4x*L|jon|pc|Pu_qeW;EuZatFm6k*@-La+5dj?74y@DFpX8$2|7h zW966HFSsO1JmLEy_5-+fqM=7E<=tk~eN*u}PbV;9)sg&-`c8d#0>`80w=Yh;M2Mj$ zgT0BP;Kn*Q2-`jF=K2`xWfekaipLZeI8#PdX?h?eKL0#Kv&H^Rt?qr=_U{+NO+*?A z)mvViun>%*B|cz;=pQj*i!n7BOEwQ}rv#svJajkEktu!d2RFpN!b;mwWnxz~XHhKF z?iZC=+tv7kVj}Y^j!gsx@90ykzT@6e7%+-sT0-$>pZG6n4oS+EN?#yYx7?ls0z!i{ z$@=%0IVeDcD9$zA{Nx>x^~;my9Oz9&NHBOzuZXFI)j|bv!2C_13uiO4gqj5Lz77RHs-E?`oQ{V^O$dho17GB%C?$P{?mO=YJi5l1ER8dEsK~C&&K4~6kZJ>60uA%p z;}ie=kC$iB0Qmat>G(fDxb_k-1ng>Q;|iTPiH`I8A9wG4IWpc)bv$?G*AG2EQ!hh= z*XW4j9|>Pl&;JfNl#`qx-)YUL5-JMIp(0apU3~6@c$kkd3==l+rTkTv9}AX3yDwA5 zHP=L{F8XC5ylG}ws^!Fp5{HGMNv|umt3UwEERt8td0yH5WZ=5Nr`gj1+F}!QijpWY zYgY}dC+ofh)5;)N{BUnoqEW0fkZ@YO0a^1CT!u%Wnf?y4LaCIR&I)p&SB zvzz{%_bBh2VrK`;y;y+B1PLi!nToC{>GZ|U6FnxHoZ=@E0e1;8PV~l^C(MbG-g-#*5zMM_hrUo zs<=JfvpLm*;QqNmKO+cT<+bPzZo+wICxJM8(jt`DdI@^Bia}-*!2F9FQpW;}cyJgY zg2v(kE3mGrFsc4^hTU3_U$mBZ_f9Qnwe!#eQh?l@URLVG`d;{C^D20GE|$5IftQO@ zuMRVsMgKYCYqW=kopLLvp!qg|_M)Eq+v|K^u9i8p6QyF=Ug38xYWXVxFSJ%@?<=cG zXTmkrBmlQe=AK@dAw;)D@iqzOze-j$99B5$5MVw8b1!#zav*OrfA(k##4IMq4g$F( zA)L_li27kJ5BJx7=Pd4>#?%2oMik9z=v!>^>Alj7+r5&rhPOZM@w;w63@_0X#$OmJ zwwb2s_8C2DLQxyie{#C4`Op(!BF#35&#iE`;~V|=mPh`JRb9xB#FQl-K72itDcIq( zyva+#E>nj!$wzqKJ*4sfcJnNeGm z@No0G(HcL8H%J_Oe(U1U{nREDZlxZE6g*WzAo8i&&80Ml;hf9ny!G&5 zI2x-WOr^2hnC)HbJ^MC{PN|tnDnb`D{vy~T8u0>dQnlykqG<9yZdKE$>Kz>(q@BOg z%=8fW|8ipixC1~-?84iu^JKRM;69lNW-RRoRV!jZ73{qRKWbl=68&WhxlDOVhke-B z=i9qQ+{kSc4{t$0SX7(q$<&AaA$wEp2t1nk0VG@%{&*|IXSn=qCP4fyhUBbP>xH2u z)Cm7)>CB9@*(tp9WM!n`Yk=7>S}ijieuXZzGx@428FIB|y;%gB$qQgDSI^h0*NpWt z4r%+#BWSm>Z_J?l(WK_`6E8#8m;PuXA;mWeX!v{%s|g&FuVKYML#^K0{LiTL=fnCH znSQLj=R68%KYJ(Y?`M9V3WM^;1(-D7gxSE0u-EW^62O|{f*48-L7=eRL1W8~44-4=}Hb7;pYe7Lt_(P$Q{9(}kZ(~*_% z^5MPZCvo=-VGD3R7_C~qU+M;>6lHcY+VNQM$0GdqA2hY2?G)Nfe<%4BDscSX!2_Ew zI3>bY3iXav=z&QiYA(d`T{tm^Swu(Jm$~(dhhP6H&3=9A)amn>=Xn7m4NfwEi^Uiu(1Ssc!Q*hBDcdt!sxi;R4f_ll&A@F@Blk*ZIK8)&(TaQS zksP6K&EYQnM;?%7N>HM{H!`~eYx=>V^F&|Z=Iz1r&0&lrJ$nIkN?A9~rYu{n5btg3 zxhbUuLE^9I4h^7CpXtq3k;^#|u^xeOp}rh9$WB6<9#e0)#B%Ws8g&?h+TZg%FgXC- z&iUf|L79-yaj;yS4=nWjKLhW7|H0LBXy{T`&n;bY6Zt0(dMaYD&$xk4`CbPP1Oh$m z2)R=NLPBcT4S}TQ@a?6$7RT%To*W=OWCMXE`M}O4sMBv}=OBJ$PPn3RK*Jp8`x?4TUnI3bsG4W%WPZHxV5q3vtqeXjP(D?|UO%q%ugx+ddCG z3f)@Sk9|}nk{a@hNCoZ)UlVvk5muer&)~Y`STd0>lR5J6@zXdy))Q2#TMR=le$4`? zSRTs_6g5imz7_xf665}B$6Vt(2VsnKj9~Za&y}%08^WO0m8FzTxIv6TS*H$%*btoj z1<(%DNyw;ffNbel@DeLmyY3|Tz-KSFl)gp|K0!HhOA1!U1Q>*~2>@*vu!U44rFw~l zX?MD;L-?$!7(RwkoxH)6Bsb2x{u!l6N=~cK-?R2@UIaB(XjM5{J7jfK1^3w3hYeLuYp>y8)K-tlrJafQyv{$!oTZpK9;I3SDAk;~%L4R+zCvSJg|HVe z2CBJBe}0dwC412UnBK~*>oK0!T^GOwEFCE_+n=|Dc40r?vGu(tn=|mr@1J2&WV5>J zEO~asC4KRMfnC&}oR52Ece!C=j}lS zU;&QO+(Q5eg-_mkc?=d9N(<7#M6ADCsJ`0&Rf9|h(ajU}BdoQrB7s(6>+q&|0EOcA zJAlQ^1P|6<(Rz!hk$0KL%%7%J{C)s?s)Uc%s5RmmcU^q-gE0XTfEZX0)r!qR*Cgs% zjR)i^!P*f0K)~?;oW4&M)~%jCVGH?K7w(0Dr5-@c@p%yvuFXU@?U`!TkRwo74~3hU?9a$FlTfQ^do+&RJV}{kSEv-@5p^>-iO$2GYm1J z46-j4;--WOUr^?0)EOP8i_LIZ(ai&xCaGm7Hb;Cl;Z~$ndKcE5#jvso7 zs@;YyOUpT-K$Gp}Ke*v+_!jQC$^Z>eV{x0vI0jd$L^cI4N4>Z}EP%LNl7sdLUT;6# ztiAG)I(`7!g_uk8gw9IO$_80i*#mD{Sh)rDsWg$8{rmv#{1|k^q)A<(J7;!JyiTh2 zra;T{(QY6l`wR&O-`szKbPIC2?>qL}i|xxdoY%qkPMTg-V{{$cD0KxIe0a7udn6O; za(g$pGd5*dB`g%wuRSBj-|N_P<0MAA0NfK47JRZOvZt3lnv~VR+l4T|r=Y^XSS5gK zJq{jlckKX0_S-VSUn%Oxf&!!^_n0}t{SU;&hXtW3c8qlQ`OlrHMkQBda6K)gKYnFmLOl=*sfx5~8ucsB?e)hw! z@9m*jMOT9Q^)-h{=d}S4e`*k9%W2q*A8vP@`{h}ZX8T0l)1lDkSRwS1({d<+^{?-P zq4$L&DPbPOV!QZyI4cigccxOnIBUB!Is%P7B7D$Hr6u<d~{j0!ovk zR<;gy!;7kw_BpU!n`2c948$t|Ln*}Cj;2apcF1)XH44YXzEKt|=y7PEVzyf8MX30` zQE3Z`uVEMb)vXyfZKCTm=xlsQm@tqgkNl_;eN;g@+(i$%~hH;SwuL(*= zEkevODU?x#au~=DFR_X~ReL>Lul_zb=CZ`^@SxX4(2`m&XRf#+56#(i2aef(TFccW z0?U?AdgJEh#Pj$9h2ChQAqzq1?-N1(KQiU!C}s!^*{l=x3RAs&CcbAp?@9M}M*b1U0LDtR-;~d^w zu7(*I$~jScJ{voDJhDbg*~-!z@`gPoqg75>(+_d}J!8M#>{q(=oTqx@ykWKn7(#k5 z$L7&T#*WBWW4Gfj9DhXtv`69%PPipp{(0hFe!u`}fgdSV+#nMy-U)I+z`x6^bTsE6 zG$t5ACM$q&OU)-E+Ke`kYViU0-vjA+`!;f!_a-R0mGe3r=6(KA7!0f8K&hBRXtarJ z4WX2-{d_J#I)`R%_-{%{O)B011=~D05s_%F3iJTpiU$jg0bUQkhE6nP;7NL9WFJ{T zll!8&5|S~^mdgSc2J%0Igvy?*K3Afw2IvKuO~Q107}8G6)LOaUUp3=)(sg&-6ibBo z(+f&z^>x*STW7~%RwUpC_dn7ry6EjdXA1#bNAg{}-Nsf2l{kTyB z4ex0+l%c8}Hq=LBJHTDosclGvGcAmo8}hFk!bsAz{NejANR8kyr{u|O(ggwHs;D`6 zz$o`?t6{t8M4B2 zE4Rz|E1=nDl@lfUMCA2*F^5!#Y^4PczOy+=h^l26CNuN|6J>B<-(9eAld#-%cAHWW z^u5eXW-zqbxS#DMyzc)sKVEQ32ajlJ*Ze>5#Cx>NqiF_Ls^Q-;^(@vcNbI%Wu5ok$ z=<61Nc2edbn7pJ<9rN(7_pc04!>x>a1CwD6QPV%ml9T9{TK(-O=#F5=YxB@uMirTnJfZGs2Sv>$+!IDs zF4h(bEWOUz56?B`o#2<<5AunNuquha1r7ru(L17 zKUk6jciSyg#Swv1-`wuc{(7C|mYw($smD6JRGVICG8 zLm;3tygMuajJT#y5Fzo)GryDJiIZnrWBK}-%D-K@d?MEkBgWj~Ys=%4r{I@t}ie<}D;Mgk=D4m6jRLc8WbXrH!l9sbnL2VLKqU$()5G|O7>qC?!EiljQu z^54^ogoSJJ(9v}l_h0_QQwpc^#w%zj_#pkG7f>N~`4f~9Qs0FaO)gb_UJ+Oe`L(Nr zWG-z(>9qhtp&ec$fnv_<3(Z#&rLeR5>GqKOm^Pb0sVs-ba3{Cgv^&j;qZ?9anFU5v zS#qxs3>^&l#%qWZ!EK!seKXmdPWiP7ylZlc|1z-a>cGisid8|Wai-t2{u4MS8l|PW zBr=JI6|n*bBr;?HMy5qrpoC=&!P0Ued|StT0#~iD?&BJ*4m}X4vVgIRn`Vk zk#hh|$xbf5=&bL%ZA7Z5`SPX@p_byX5AJc$unns@F0cA53vB6{ClP4BCcWgnLIeIA3Db^ zjVwbsjD4H+t(q89@c0PIR?ZH#G?uXjFFwI-I$t(%iu;g){azolz_?kkv9sUVr^MgH zm9m2|?f)VzFq+^P-BCQRN9vfP?`UMv;g|u?!nVS~Iy59@`uM7AE&Yow*@r2wUcVf6 zT7`34I`ItqpzPQso%_H0GE`!eO2BF9|9Y#%gQQF<`<=c6s{09&xd{-~tOMqQ-q(`LzFDj#B1i^;SEbMxI|qY7O~dok zx;Ocad>6z6x-MSWLCqYyQPbKjZtE>jkli8PL`sP>vz3c=#{ozto{DjrV&onf&|8Dr zHk2-ZX0WnP9g`D&ETQHghLj;!b4yW;hZI9}XSTOXmaUy<5{$X`XMaB)ZV0uEh(inH ziH)gHJz{I0ZV3^ZXXNMYM+GYB3Ebe@2XKmHK(|=M)R=*Ln&e2lms%CWYsu!|bF#H~ zmmeRxXvE~5^rr9j&{ybz2MEfX+?S{s*v@K6O$%&UtYsc`x+Ytoq*(V9RWHy)UI#A| zdmLhd{p}Cfw{)wauOd6AFX|!61e6H-fRX+~)mYhNO(GWPcC4{Fqp>18cu$x^`L*tq z<`Qj1W|}D<_mc@_tM&QkPBbnNNq?3NYTMqqtVd>8cf(bjomyrdTvQZjq39pm;p(Ju zty33X0b)+VUKy}j{ScLP?-0fz_09LvL0x~TY9gxnn@SEQWY`sg%@g6l6W>k~b#_Hi&YKcGAD@R^!TC6Iw$tJW6Lm2LvX z&e9#`ha$NTm;xV;K)SH6r;`mg)QY>PRXUwr&hlIze@Lw&dvTqC;c}9g7g6mQM)%uy zqhXN7cr(=hE_}3Z#?V-(owA|$>sL))U>rTJC z`Q9eAscQWG*@|yK37h5$0eHf!JA1i{bwkXlUP8p+g85oYds9V<@K-Cvdqs6-OxptP z0?{qY+u`1BvUe&X+O}c^u>*61CRCJTnX3UQBL6P)e!eS@%aX#H_ytZThH08Flc6qd zRL#*TW#_4|9hZxMDA8BF@QU!hQ}uK1+t)(!L^tx}%34Cs$7p+~bg$9wu`s*gQ|-WW z?{d8hFVqEFH(#g=d8I-06qsy7as|aGlC>8hA)~5WOE~#9P)oT^oCQ z>Gh*+OINxVAYpjFWnmVin^kq36+mG-cLyyi;biRAn_Y`GxTP`8M}l*&0wVxQ`Ppb~ znn)BbvCE>tL$P{^swfRT(h{9S$)l?j{rk>rn9<8en?pxyGr9*;SFaTBn(g zd(pDOb=YOsQw_sqv5n*yQjaFUKJkAq9=oPK{D@!Gs}Brar62(p8k+2@)*Gn_zE>AR z^GR4V^WUt@579&>xXN;>Q}9^D4ggiD_Cj^u_1AlgOF`+aM_O@9wF5kiOY{k{)~l^Y zuW)PLgbK2j*X^{6D!-^CvTC;U?mpNiIsJD)rTRX7QnduY|lT}faI!pzbPQ<*k$qfm;i`D437HX$+H6U zNQBPlCi4shff-zl#gwfp&(AYowFR$JxB=X{KvWq2ha%bZxc`R(_ov9iK&N-=_HdEaXCWJv^Fe+67&OYu044?M2{ zIu7>zSVDsRJ_9{Q0A7{c8>f2N;9%$z2PH?I?=ZHU?<+pvv-OOW`Rf#PAfzWcrnb@O z&~<$>C0njLm{GY7$aTlKrLHhXTlN*51N)4cgO_E`E>Y%~ow_uo5yGmQ2{U9a!-gYhX!t%_u+I``cg`^I*I|<$ z{}7e1A~d)yZZQ_qB(^cz_pFPz@O!ds#7$sMWHld%vtM>&q7@^4Q)D?XC9}D;nZX{6 z25UxaKcMHyf|`T1yb)@euW}%Fi4Y1>|8urIPB1M%+t&w$ddSQq+K_T*pN!$x@iBlV zdVyFlStkvXXl@KOLyb<15y;b+R|T3{zj7$1o~j&8FqFKYg0Liv463G*^&Neb)iX7& zga2z(xmNw_v(H%~3 z7bR(NRxAak3+lW27|M#|u4=0x&u8)Gi77+3ShL*Lw3F{dtKFOJ&WX|XQX}pQTuy{? zcALHUMlK!jDz_{kfqwwvsW}MueF;NbZ&jedYCsFgnEc<^-Oz)q66`2?PsOmaZ|ICI zYOHX4x6RL&r~q3O7H4;)*8uuZ45)dTIrH;c(YEdE%`H|aXvx{) zGU;y_fC_%D6=fWPnYh0|*O)nu5k-gm&A@ltk(*HP_5u$z6NcdSzyK||poL~6z}rwu zlzeXJ7pOXV8q*{MDD&LQqQjvI<0>?Vp31e1uNxlTkQay1k`BP<83|POVXW~OFM7T~ zA17j_T_a%+f8oJau86;f{=$AxH=KU-GJl9MyoTL=Mq||$*a=3}huTm7xs?!;B$Z=@ zJ#cH8GEt|jO~sk@41pt%HH!JOU@20goVvn&H7XyL@Xc#^H^kMqpwPKOZNK66!g;I~ z>Yb8w03t(UGD+^r+4snI(kE><%X%;}L1`g7S#YP@_)azPWb3yt%>zc^BxDvhLi4XA zs(|SpC;39cg%xm+FhX~jztDMgj!{=s@b~M7N?vXlkurXE+mp7|B`3UF8WC2zih|)R zplHQVerm!XF5Zn!ZHS19CTS&d#8}Q$TT_6BSE`5C&3(}^fw?J z5gu+ODS_#qZap9Z>fk;dqus-~c?K~{MqWRT&>PUpSl+1FCo9tf12wBM&$GaR*MeiD zr$9c~dLalqtgRS#%@8-Jox z+|oq65A}|!z zX)XlkA|_3FcgZFeQ{SFCcm%dAt9TYh`&EhW9FXoVVcmxfpv zdAeHG6y3!v;BNs)Xar`j6%Z(xzqQ}5ih1IPtIT-??Y0=OH6`tWPNN3`vd*3+fC|6X z-3|M}=C#CsdLzM0?@LpV?R<4z7$|!~O_hS{TEb5xjiO~x`Ks=&G=Z`(1c_#gY0LvS zbo)pS)_qB2h~0@YVTo@UqCAfBm0G+QK6$|a_=7yC7h)V_`&O2*({aB)2~I*1GzUG6?F|?BRz?tUJ8qO~D~kOQiK)&mbD8`|VNbT^g^&H$Xp{ z3*ctiy?wHdZO0@>gJ76d^6n_g%poQ>6iOJ53;dPoFyPpQ}lo2c}foay+RsAa7LIYk59NWkL=8zVZU^Bns?xR`&t)V(2jBY zAm{-#p$cHgYp7z_7f!i#$W1z}S75;P!uxc9-Pf3>j`ihjy|IU| zOYbB53CDgIzZ%?W`9w%_{rK;{YQXbYB@;9uHJyzAB=H=PbHIAL7PC#d z3F#?WT%{uqt2DaF2gA)1&-X8jXHQ+kk<#mg(WYOrl*s*UO<9$UJm8Zx7cluM9cPvl z)uacJ=_RxFL@!g(=V~pA`kqhoMQe>#RA@ud1OK;Gk?oCJ8(jySx4$r#?% z0C|Jf1+F$=`V}U8gX*yiU*-8~_k*Me%d*BS(TtjdS%K-}ZC7&%7}`SmfA*yw_vv#@ zn&r8yN4Dl3sXpZ@`kp@MykPku3bK{Q3A)_X5aQVy-_p6XZ`_-;-$>SnTIzU5E(GPt zX`X;O{uY6ZLU4IQ&Ay#TKJ~DZOT2oc_o32RzkH!`O3TLwaL>@sf=ag}N11(Yb6&Vc z{ADXKD)2+g({(YI!1uSeH-E4iJg$?|I(Jdfpja%L|G68zO-yHYTRd)4S)4a<6Z=uK zwon}dTTDy^fG2s^>h3}{-i)`h-PU!;JaQ_UZ^zo;oV*uTsm#54G%e3p8-Ae9)idY1 z)Au;c^{KXpi)J5- z^~|0pPRAu6 zP-si%1G$R&g1FO9N^lP#GsW6eDgmBL;?9t8b;6C^WnVu!IIz4iXla~PPcgR*_b_G);U4_SHoWyRX zH-glBmji+k^QEe$3WRO_S91}Xq(ft8vK|nCJwW zDEdEe%eR$!BSGx`%40!u(FM{#!iHwq9n%hZ0da#_q^6o9@_Ehp`)7nu_2zVJ4FQIb3~$pg24?wvhzzY(x|jmO;^rjjZMaD~ zxes#WC+&b-J*VJDE$FF_@19-tZbkEKAdwc%k>}zW2N+FG>Hu|*1dov+>CVky=yNf( zMBA6>BNuikgbTFJVa21L&&b33NGnq*qJTGR#Ao_wMTKC6Wnp_V7!Tc_j?Q0CQh`F@ z1~|Z$^Uu6=OS!|kjP+Px}T`+}HMuYS}4vb1NJ>&Eu^A$x__fAG-X^Wi)~7VV;UKJdXe zZg)&opaD|(8U#tMbDY9|J3nDsenM2>uE5{)LVrGTZfr|YMIaQ=}zIgaQ9B<(dq@nx{*=UK;)IUh7leSle;Y*(9 zIgmQs+JK@!=Qt{qK@U+H16j5gc63+}L`!Bp_~#5DCpl-rnBsL)oW;nN&uS?OKW+ka zLx$Pv=EpNc?lD$0&`yvK8vO~~zt~zH4=||5MW$#krV$AXa43TpeD+u+dxI}7bOu%L zLod9(2F3u#FS(R#cztYvo~#Gx{I>}bWB+zEI+B@BCD$YL1O2evbn&Z=LZy(0*2J;?sjVs+1^=x$WCp$oSu_EX&DeSJV? zpaR-C;^}ArN6xko|M1^l+R6kUak-KYn6B%+a6{blbv+f}7H7Kr_+}4fh<3pa4waU? z)a~89W8_&N41aJEx=Z<=pVKBu7-rtGLSBKuBq|a15`9R}lUGk|h9;o^lfOb#B5)+h z1&T$dk=+^q>q-YhQD zbQnV&x%&jW2l@G;4pDeO)e`FV8(BlA>qHYSqRYZ{E{(bTgLi@-t4)MtqK((E6QVt6 z8cqBw@Wm5M5L#qe_N2(u^p!i@wvrop^>7vdU+WCqG#kjUwHIPU??S;Zq6^&ZENH?k zcR;U%G!K~i%|~ifpacp)<$u-YH)%bp3XtGu)D{hC6qr2Mj+5NLlW`>d9~zNgXAnE` zVx2olZNLi)e0Y9S<85+lP>~cZ*Fy!CPBTjM88_ffa+!Z(Q{GDugh0c}scx7{&lT;g zjUGm279zh}?ttpYHiua~y8xK#0;xll&c!}7LWAJRH|Yx!jvlRI%h{sW)o`4RAn6d` zatE{OPUY*)^cA-Nuh73(h?V6@0l1k7 z!VJLJ_ziR+w?G1dk4ruUxZfH5cwl&b5Z9z9u~Gyk>jqd;nL*Q3M0g8LQ@6&2cJkmu zYC`Zb2YtLq9llYvBbb=IGfsPgM-7*<639@fmCyzN8jRE6@FdR=1INctAnJb{7_7&P z^{M|{9!U|1%#1Y(KELYi(#yiNhd?8q2O}}ZNdFjOmqc}x?OAmhCX!B61Glp4Slxl>C4tVa8d=ha9l zk)c;zWieRMgE42&h==2av>@8>Mo!7MENpH52&ivo%Dv3W)aGmKNN@7r*)spzyYVVw;C*aULeL4goO(H>Tp8qq-M&*@6` zghpBWLm=GIWf0PI+rp2_qVtyP_j&l8YyOoH|MlC)4+ffX9fs1` z?}r*(Zmz9F71WtP=9izedb$jIlrL;yvseDNcl+-@qqPPiDpB$1)jy9WmT+dMdI+L1 z@v1ALLc-D)js9-) z96NmouMn?64PXJH6SZnLS2GBxE7P=syW={$VvU~{lq`m@r|`oYeyYf1hnY{;Vbg-A z>0$ggL@6)xIeyq zfvPaPl%5sF+2QipwwpgpqfhX~!7+~$&r!JtrLbv*($rN2A3GST*W=`vPz0#}(`R3FYYa7{V8J0ZW{ z1~#qIKwC~^j z@`Z!($KL1j+Zy~nG=D@RCrA*?m}0D*Ui41`RG>V_i8u%9@5mqTT6toB7k9zXS8?oiKV1kEA^#RimS zXe3S1o(3tn56m@g!7YC858wXG|NiY+MjyxvZFLUtWYlv~>?{>L!G3f5$K*UVOTXvc zz4c#yXxeE!U`1a)&TUzslyntIoGc)%uK=s52MA4B5H{2@)Xp`>2rcH^M#ZIe*_|{5 za{(#M0(k3rpllIy)sHF%N;)%~y%)~um!Ouk2b8XCy3-gVnh8K9${B!Ka$s~GJc~8} z=_o>2`XHwPn8nWH^5&?724H~qU90mf2l##>eyT!UepW!o^UKmL|ELPugb&M%E;@aH zX5_*3DVri7W#VaZ+&J1pw}E}3ttR$oYUI6g+u3qpR*Zkpm8scLd1d8N@Z!^6u;7yK zPom6tP|rzemTLIbkrifmbJTEEZAZ`ebU`vRd;5&sVcB%6{gcUuNZukCqw)htKd{zb z9M)S%DQ~KiyaD8%7S5HYY9v;tBz!nd*WcfE!GxQzq!aOeSQ=m0t$92lA`=SiITfQYRGRgzEF+pM>~wksW8>Q$$+FTf zF2E*{NNs! zC4_MX!Mnoac!1T2f$<`n{jKi2NO}%v;kwQThYyHBhIziYAgxo#Q8O-1g zxw=9bH4DBrHlwO~DHn`^DKqeC8JHXnqhjtXn|zl2Jl)B4aY$%En7yCIcz27z^9c!~ z%&q5k&4T})w9;!e@-?7`G42<0m%YI|ThO6Xlb^J3;To) z`xF1>(iNg^0LZN~`KR7RaJOKLGTdNp%msqeRUOLvNf+f>$J~6x0frd|xg4j|UIChS z(G;V+emVO1M#c*E`+W)n!xXmG;k&~9m+-H95FF|$wPa3^+%0J5GuHzYT<+i{a>h^9AYtGFti&0tfoGtF z^rIXW0>OrZSDj^(n8@yYlCK5HGSh9}zjPLV!tj_DP8O~c(((%L6MAk4OCjw+A=v}w z4@jR-fC%>xx`L9QtIfN>9$=YT@^e}R`{}aHq3Fw^<1?r`079HQFYbA99^V?rGx7u@ zVfq;`XgMI)J(cBV)P^M6p!LBZv^T;#5nl?5LmOg?&9TJcSMFRS$Ku|RKnQvXNz5pVe3qr*{xN$SEO~59MZu0`B{O}2$R*W>mCmjlQ65*WqypVh) zhSQHcj|Eb(Z3=+U_7P!ltA^4n)3I0NMzj^cj}5?+nFz%lB4vw%CcdYRC z&>-@yqXnuJ2?${L?o14`>OmV9!AUHwy&VbNIzJG;rjTp_QB_k|G;(Vy>(-}XM8sv( zra%GC$H2UDH3}>NbE87j06N)xlxSw5neKslOoy!j2G4rVAO(~4pxxHVdX;Xxt1J_q zBT~3hWtICN`r7C}dL(SmHP0s0+fE@qx$cp>B`pNQXi=zcP@NRP)rBvJ$BgujJ~%vsNCkvUbZSzuOb;EEQNxj*i zT!_`abgUAHtBg14DqxjG{}0=*@9^vH69}(zjqC}C9dYLhe11wxv4}7T@w8=5jMxS? zii&qL*ndDJDE$ibb!g9}1)q+_NvDP8f)f-OAd|2NE0`jM^qZmU~~51>|8Dmjz#V%e4Y0iR}_1~E^iF*wTFbTc21J-mkY1axwx{Q_ct z71H^lC{iknNB>Q8*uS!BAT$yGfY#~t*fQ9PX5tV7Wm3+*GKT>Qtv($j$NWqtM8NX{oRpz3mG59Dp_BI62`ys_zm&EtB zrgVZ(g|;`*CL-i>wAc((VcI?d7XZbR8&{rxc|a`p1iWe!>Y1LqN|_1uI=rhUp_`D6_~Uwq)8RI=9V*U6>jr&At?2HPF|EaD4Z_1X3xAVb*cER$+EW$Xp7LMgX!NLVe z44_7X7q+kYn|vpvL8>~C><*JphIpgqPq2?VALy;V`BxeAZ$N{~<-YBb0d3`xPjdG7 zId6W>QhqlahU6#!HS>!I{qF&2*q^BNX&hQPShijPDXLiZi5ytfDYz)#>`bDJNEFXZlE zU0jdZ^)fEvLICI5I?;4Cq0aXDeLx-_Io!9vD6P#L8M$x+Ml=@ChhKh~nLcvc8BqW3x7`fl^AcFkQ7Ud3$n|q*;rr`^a-JQm! zA&t3`Py9FB!Ji)!d|uBIYDJ6u$Le$s5j}Gqye;VYsWs#5Ri2VCes(+M=MIzn=c-{v z?nuT`1WqjH5xSYbVWQ;I6v=BlgSLp-3nV=SHb&pl36Njgg)t(iF8}5PHEd>!vH$`{ zW0L9e>BhzxZ16xh`^Xar_;BcrpKBfQlxs*`)H&t`Q9qWv+m4lDU``C0AeBuaJPw4IWGgopRx= zu6|xE>pQSAvi1j}%D^J{KEMO+m%STIRY{wUJ*xcM3*bfh+h5FqT>cEs2*VV4JF+uca{4Lw`@kk7gkg8acb z1j@|2h%DeB2bF0;wDehQ=z-Qh2zTc=Uv!Y*@F4cl#|{dtqzuZ*-shm&DIhS0j4@ys zfK+bK$VE0F**_3_B$XwI4Iw@mXQ=0J$vP?0dSrtVABcoy_?(Ct(&>HJl#6;CA4al; zFpuej>@ovDQ4!2n2CoJ(jCh`bCUag35p!gST?l@rtwN({V)ry*kPx{AZfJVvm8_u7GTo#vCPg4Ou)YPFKVnG<$SYi$Tddbp;3nq zEY9pLfD%`bC(~%151O~!8I1s`TST2zm0_pjhhlZWmz0Gcdk*RWnKABn14-=)qF z5saZ#Z<~{IsuXJ^pIRZVA*~c@V3Y4T`2@ji|1fu5yO+9-^+T8l2s9R=;>IYu)s7$; ziO#!@FO_KweVC%q3x0;$pTM0?URpA)?8_H+G{o;})yw@7DIrm#*mG`}pQw6Dd2 zzuDUE3KD-xvWEA#@GM?J&U`QXR592KjP*+N@ns(%_Qa1p_f4*Z9~+fk{QOpzpMYHf z6$7qt{F2QNLJ0MVFo*T^f*lt}rZ<}|3qz6(~17n_Py3JG^jE+hCi+l?KP?DjA^riM&IcP9}SdYcd zfJb~nd=`6_tp$tS5J%}{xD&6S$G!zngq=YO#M_@LCn(;e_69~T>g3mLrzz+^V&4l- zsK@6EXR`8<3S45S&GkVM_na`$uc8P5{}nh)Wz%r7jKNr<7@W^*I~{x~!A$KsR8mhX z-hCTyxea_5tCn=y6(|)-rb#vj4(39|I9JwS9eVqn-`fIrSf5zJwRK_lzy=I* z{KsP$mj3BU;#m4Kl&Pw5enwsJFv7TO->iyJtm-*?(GTt>(fWmUT+P50W>0_9 z;pbgOKl`7NWM<8vP+6~skFsvU55MDPcdr&SemdStiDCed5$G%O8|~*ehLmrvFj`{1 zB{{91v}S`B0?6v~qi=9F~(}?LwDb0A~RB*ic!!k>VCLmaf;|7;gYBcOPopU=lqN!Xog9tjE*hZy8?k zN}&m}cJIZmMm=Wek2Ld$^e~|LtMWL%M&51ByTZGI7A-yg*w;lJz<(?tBB{j+;~+c> zZ8L-Uomb@2$~PA559j|62EL!iZ6?3p_Bz;q3y-Wvdl;4|v;B|J&!KZ3{Q}V_n;gpG zem1!KLG0}JC-xKiJ)-~jROnA!{jYz~V2z|qCB=dJb`NKMKZXBNpX~a2xO8jBcm2Vx z$Mpa489YwV!~EUXS^6&R|I7cj>vPfSdsgrIga4;b^Z$oO;4f4!c=Yg}gE4l)12PBz zUq5W}_W13ZJmn#3`)h=t!J*Cp?P?1^|0K;ukpWV;NTcftmMr!VPBeig#6HQ&`Nz5k z-DrxFHI7WDNjS0()+tjMOG#s$z%dmZcA2qGhv4yF2f;(<0Fo8i&uZ~o z4GZ5KV(MCXd0FVt+to|_B}wabHh+iGwCeaLp2nngeBWyn(lXi;M>AUQSBy|9wBvip zpSsiR<^4VpSA9#YZ(1Wl1Rs=E#P(M@01@{~JoL6;o`3h|Mfq~9M^5Yi78l$IbHQv^ z8~SiGu+Z#}cvrmzg`_3WhYDcU#rOSoa1&MjpAY!0$Y%eaqfQ(0>jRSg`hZY~7b21< z*xGblc2dZBf5>v*vPUTeR*}3~JyGi`acbC53-Y-a7HJ1vt99Z5x-~=9YESJs=^d*Q-alVexQK{{L`XShA6vN#b<3eGG^&^!S77R?omKc2k4>6> z!vvQ-Qz`QI7@_ByJ`h?_L649j=yl$Kxz}xEgNgieVS+n@1OWiM(%tn1JJwG~*Z@zZ z>>OBv0{h4mj1!B2cdG&KI1{jekKhn?7Uc-?f-?-Srf!WuC9cn!8v*x<*xM@RO`W`F=U%>V^i=ATbrejI@iyTmd|^9I9@g&QkXg;Z#G$OUE-*vUPZ+XySEqHqf*I zskPYkJHfT_t=ZCnyWhs}*Ava$ft(NXW?g>~17!9AvxySzv}*>OdSgVIH%hDP9)b8W zA7+vzUE-(vTC1vCj!K-kjwHV@EX;auVn=!Z7Rwsaj3`P_eTmkdzkBO!((0gILRGUn zv=iCy^NpJMjNJv2#)Ic)dR`8gQij|*5vkSY%4zx0?(Ee-tJU^UE*wm^+VwKD@uQ z!zYRJLmTfpP5iajXOqU|npyiF6;a5GKgCu})zp%%?d+6L^>5g4{|N|}F(fS3VDsM# z4DlBQ8Ru^;C*U()HOQ!W0$p>t?b6#R@WeI%+~TT@4;}twa~ta8zmqB;IOD8~&+Sb_ zgaW&#md>j4;b#(PFrrKILqo9AHCX?~GrA=tb=y{P7=*g~{uT%dO7WFN-U=Nry9uPs z?5o6&RXBMYx=pKLjN^nQgo45pg!VW5aHEhEz9W=Q2aH1I>X-;3KNXk;!0m6K+6MGM zN8i)lrIOChWTrJoPY6{-vIbOooZD@JB%A(9prVOb2K}2)m`hF32XH^AK+@KaP%jyV zOi}-_`8e@eo(JY&v#{3CX7mt7V(s%rx|<8QD8tm&uLq|0GC0&s$erUjv+0Si_3X$H ztGd6ERkw^YG?ut!ixj?}1WhUaB}(!pE*-FGKZu-}1~kke<0O*`8q7+RL=_ZWWL2iE zp!>KMukQtO+I~#qTG>K|gR<^gWp|b58MJuf%&1_OL@>By@R{l52s`^cbOrXR(8vQ~ z^9KKuYG602_vPBfXlhXCZfr=}497%)!)z}iN3O0WR0qAYdR9S?J;av0x2W=YG)wBj_p2|uVWM$pg0L5vhBWeyL@kUZS_$sLQvH{4!x!Aa z4i_(AAn2s1M=$05O&A)oN?(SAp(7Ebc}i<>ncz(888ROO@QIzpWrBC;C_-@>a*8oH zR#d^npF@iyn?`F^sg?pcn>E{TgY%iPe-Yhl<|jHmOs~WPHZNL>C4p*^weQ|s&W0&b z^*Rz7Ip|co=yjc!ZBoyD$Zo`t5L0*gmR^f1%y`SJLpqWttK24v3-q%=Q}`)B^^OqBQX86_uXDcO|TJhR|zgIqEQ8z9}wjRnr<1-Kp-L zs~0U*+m30B(qR(iqxiafJXC;*=)hg4bW>RGb6&?q@05xY*!k{%kZ2qB;AHKYl7@cm zXST_Bbc;v|Qk2f{17GHd`{%>)MxS|}FeJWF1BWzjYw`Mmc(YU86V$hw z_eq;5`QviKVHe;IlMJ}Y*(N5g$2a|~XF-hCVR*;Q^qX&0Vpm8$koD3dS`*J_T+EXc zZ^`a5u=4{VTUi+t2w`+hYw@nTjI|82?$xnqom7t5x=7dRN8`s}B8szbU5Cc3?SVZ8 z*CcYJ87|#8yC8$KhuVkEH(*-oaWs509)GQh!M_5gJgf#Wy{@q4YU?C7&j(jb?##N6q zO$KBN72mp@$2Q_>emd=O0WqU?__nwR$$DS=P<%hB%4jp7Ju`4`Z44~Cj0z&E4`aVz zF#b_d|eZx~P^4QxF|0c#ja)SU=(&#%N@ih_)dmoBdeM%MX0a zFmUz_0qPPkWWUHQ;|yAk$LLkfH|;qJVbt1aLYcOh{d5JSob4B9a)7VnAo92p*jC5tqTyZiFVTx4Ac=^7kDCZWj@MZr+m%t zuUP=7fUcprqx<1MBNIb^;WVYBOt`lzu(VDCx|ac_ko6n3z)`HF;xw%%$FM$VhABvY zdiuJjO2#uLW-%VyhaY6eD3cZslFMpPfFtih!X6(hDN~{VwZgW$Mrc`;Q-8gEu&IQ8}FSAT8x#3$O}3|@v$ z`VTy8kL3(ydN0Mf?b=;wwi8p?GB`d{*}}Ua6SM3zyTXwElvZY)W18#1%CgbSl-!x~pN0?^eCG{W-l_lP8YB9!9%VI|<>Z=}%U4u;e8 zimAtPXXnz@h4Z5FAQoR$c@IaE^Zm*7X9`AHtr<{xvYI{2=RRZm4s!hK57od|>tI&X z1e$H9u2cTOUGsk%KjiX#qN(V}OpseS^AmnGeBYz-vax=4I!=8CKIEJ@iNJA8u5yDR zucEvn3?x$ff<%PHYssoIfs}iQT3|wL-(l(#b~f)IHVYkkil73Lf7dh_N)GXEi2V7vYbFXW^FOc$@$F1zVuZjiqt z00KOv1D~Lx>S6pREYSWDS}55+MQaZN4~l7Cuq+wbt4wyqh`nt~Ir$AZK$Rb$h`X|DWL;>8f$=kIMq%cU>iRcRoD%1-D#FK&`Qa?H06|D$a$IIfne#P z3N%=~v)Y3%odoRA7%}q+0g?L3Q;=LdSkKCvf!1>3qwCkZ)f^N*ucX88#sbcO4Z4z% z)%%uypND+mSkSG^oxin}wp0*-h677WWJ!&#vxVLL+4?mPxcXts2S`x(QCkaTBXi)R z?ih*rCWS>*ik~a)|I9`2rokns~F?q~IjVr(32f!@z zXr#J2Mgrme9eotKg0dC|VUgK7tS z89n>9@>>|<>;zACkYiHzaU5HlrKmLSyyjGIT(pHod541)_%A;?kcSwHL3Sp*&qO=V@fK&+&|(e&jK}}HLy`P%hQmQNM9tU8q~c_ZCxeDd9xbXkDVeSs z-IR%SKThcDUj5_iadMTcJPG^YnPc*d23ug?C_^zpYBhKNgB{g6cLg-3$@q>f-c+M$ zGn)^rEU|9WXW}P9aJOzNq{o#kLMkz&2*1 zk0sa%{!o$UNC!^?XBgTxZ;4mZxupV8pF7RqPG)p|LgrBb=3c7l(hZSPTaZJ3~ySO|JcHqKH zUcT9@2joq{K=lpe%rXl%tq_KEpU`X>n%DO-#qEMCu$kb_Mt7zr@ylq>3F32L?HqG4fwnnAy=@1i@{-{h{<)IZ)OW{@lHY?t`u8_{ zFN9~|{UO&@w8O5{T^iZj9KSp{Gy_U7Vq5PB3V!!e=xXrhv4G3OYq3^S5sBiz-zlvb z2JQE-e+5FPk055EUQKNM5XB$CuCNwweuyAkfz2cO)D$p|wPzx2Kjgs^?30aE)VfZ? z62}MQUg@c0R2jlgK=NVQM!Fma$hSQ-(P8Y`3>u>1A`~FubS_Iv)_wa#2n;%id*h|J znsVdrbX^k6ZQnm_ny{T@x2v8Ri$vv;PHd6Wk#`6D!>G|hw5gFxM}$X-WD{G=6~C4n z`1008T?zZ{*+b9nZ0YXO_~PuqXTWu~l3ShgXMqgXmtFdml6$V5_;O+9HZ$86%#P7? z|5E28J;@xJDmj69f+=-PX!xN-W_o|Ji8b!h87*q3iIdz_s;#b|kdPVu1nLvjt7tddZxgU7sJ(*uf7uKX-wsTu zS=fb7C%B2NFn@FcU8Jo1^{z_Q*hh6~RSXL55UH=@Y`E!NnMb<>GU99eP~l<3foPzB z@N!Q*IE$HM?udVyf6L^RaxTLYy?S37p-TmtBGhFeO@>EV2!s{2nVx&_Xnr9x_rre8 zo={DCQjRoFZc)pln98rrg-`0UgF2&Nv{ozwR13#f2i!JhEwvZ?me!AEhP2t(d#7w_ zT-Dq_*_NBDeeKG5OsE8N1N6J9L)t-}Dt+g_r8s6HXJvgJ6T_)L#uR07Ox-RA6 z$CtDTrh0&IQ2q#hiHdB%{@a=DELp&Pxz}DO3b|Bz556=I=mL!ZEJ_Py)Q%oJ{j9DPOcw5R zPw%)Y*b(I^yVfZyVXMAja{kJ=<%{p7Hp1U$iS{Ipk+K3?Eugw)+yi$4CQZ2sh+6ST zgxbD$lsT%jGRbL5dU6xdo`CquB}2;h}&@&mB+DzVmBII~!kGfZq` zrGU)*(EQVpGUT}e1!Z8N!e|aS8Jyw7XNY!t5XBM|gba|85TP#f8<1`DGP3sI$?_>3 z*#h8T1oy~|C_2Y^(zTpMDWXUq(vn%CoRWm+yRKKaRO5$^(=&K<&L8Xl?V|*;DWeC69}>%xdk}4TrJKeeu?#z zgoObx-*Y-Qv~7M-tPXFzm>!cqJ=7Z*rCUo_8*e=X#{8eDN$eq0Xu;S_bZ0O~QOI+= z(S-NqDC3rM=y{MmfEWLIsXo3>T;SbSV}s874F!50hnk3TgpUf%wJ&;oO1m`5$cQab zZJ@$^xE;F3kU-{=NO`QCP0yAt}sGZuu0>dB=l233qsQOom%2(nK(rd*L%n~O4Lyjcc zV}ZiY#*6x*w{|SHItIUFIj$V$ASzSAT;+%+pntZy>Igv7!pr(dopMnZl|2pgRh})uo#)=;}LELYK12 zVpiC+<4&u|v>~GXpFlH~xQBwyMk(g^43AbCk5lUO$3$NiQ`(qlu>c)xPXby96iXWw zz%dS+^QLR-PE|bJF)lTR7jB-T?*nuul@X59i4Jo!w}y%-di+4v91$%*DX+NlxS<9& zN}l3qz&RMg**q?~)zu{X&C8zJh)Mt^Di+92hxU{fm4&kZgKHF|m>RL0FB&F7C5yeM zUef&SOgs!R$K;cOem#(ab8m{zemaaf#8AQ?{rP3B#K-sV9ItBj1O+J?)!f5TynnVp zJ`5ieH#4qNwwe2I-@qfenvQL0YomsG`{fk7Uoo!%*8?;a#u;1nT zdoHt&ncmFXilfj!<$>o^ohtX>RcKS}R6Cl*^1-P=fvygio$6dcjyVBNSb?0@zZx&_ zTnn@+-7x~H%x9U}MAp5_2z3C`_c<&QZmZRVG?RVEmB((ac)CbA< z{sX}wP5^T={bMhiElI%re@oVsQ z9W*J6E&6UYhx{M*zA~)Jty^1=B?5{;i3(!TqLR{xfS{yEr_!mC(y3SoN+?KogLIcc zmo!KyAPq`4-;1DY+`wY3=XvIwW8CA8^ErsTy~_r3?K6xgm3na{ z{{~_pqmA5V`oCY+-$l6a&!)@#&HHX1G`8fACn-W!-0jSaPeNI6bG=ZqmSn#ucA zm*e(&7I-c3#L}hjVZZmOrf$w;12#bc8YkU-56aCz-4b@%f)B9!OO%amzwZYtPax`( z*J`EQ->>6O{+a+55iJ-%Wf^yVQnQ3a68w%$$@qfxD}9L*DJ*=ki~;2l}cK7dw!O9|!^Vch9N{GGl|(|Fs(A zX-)an{y4tPBVOP#sV0xy-RWY=OJR&ewldqB-7w9)#7swCRmtt-m;Jsszuw7z_fG+! zzPuBgr#5?JQ-0HFZk$O2-7d$nJ&XtF3@>hS_~19g zjG+g$btu{Poq!%Bw4%u~P@I{K?Hm;WNq$nW)fZZDB7JIi2v9>Bvp*Mm*AAa!Iwh*0eU!GCulcUdLSx~_sM z#u$osu^^W#r!Y5kY(X{E4F(=b&_2IV)8r*1IJ3H3nY_r|IbQW4hqfmFp@hGT*{Og1 z0R87ibqZA*NLLbOfgFXy#ab==+ePiuY0XM}TcgA_J5r#_98Z8y**4jVvq<|5i<4QIRH z&FPB@JNA?R<`N!Mg9S6fWc(|F%mw>Y8W4RD8fFaLJ(BC%4f!b`r_2Q??v(&0LcIA* z6uO2yv<}M@!F}e)bc8Zg5v7wBA&@vbHs|}N>*qUBvjmi#tVtlNARo)FqnGY#b`Wj4 zt=mDI2I}&sa*_Q3NLOwniNJNHy!Q}^L7bHbW70e{$__uLn%k)6)0Gbc!bx9QNjwS` z@Tj!|rp6?Qn~?25C&X|gtHQV7N|L^E9r+PKcfgIprx+#+fi$pT`8+cnJAkqg zJr_AxDMRU|#?9476Ka1Op_@K)D0!mb>k|e*z&AIJdsfWB%1T2V1o%MO;EL)NpA6)f zZb-_~MU-{QV*aLH1(0l`#~g92CjC7^3Y~y@+69iBWLA}E6zYOYnFc2Znh5B@Ny6UK z4KtT|@`rL8eb)*XZ?+aSz>aM?9Ay3+&DB%R&Hq4#Z=nxVO!GbuzL0)m)?q z)(Nwh5KRE^Cog3ufOpt!X0$;~m5&H6w=6BzA?Q15ReTLdX!04l678`_&^~VoodQaD z=7vbQch6UW5Mcsda#O1rw?E*c#u*{f4kEw+J|?fg@T0f+KHrHKG+v92iJ@b&0HzrO zAa8{x0ITb<{OeT^Tz^2UjHMIVdmq#?^*=fbbeJyaWCA? zF;bAp+%BQ}whC;j3FPmONR&y>slSa!SJfay2aQ)I4=hZB9Z^B|2_ES(3fmqlu*@ke zbHLx*h%*KcG+U;UPvZQii^$T%g{UiDY+%fXx_o@71~?oO)E`$j0F3f8{aViSfok^a4H98$dNem#KtBZwuJxRrY&dg~)`yT2tFf zSq3e3=36F0B-kdiL!12zFZIBEspFsA=kHe|arzynRTV`!Ofv1k80h$Jb!SDC9+7#{)vZ*ON!1`D!k^u<)hP+@$*`SlE}Rol?OOKmF2` zb1ryZxQx;kR(#zZd^<18R3sIWJt&@rOvGc_fp+($SmP>%<;}Y}XJ>61rtB!%F3bPk z*8lDEv3D;qA!Ej${f}553%cIXjld;@P3AN13QS7D>kpimq**t@&SIusnt?e}05<)p z(Cq0&+&;gmQmHOf3--)_z2#@0&w#}m1tvMcxay%q|3Zb)j6IYz#-Q4O;+F9kQumlu zo;1zDCUtc=gl{XYi)A9a#|4nR*IiArqYlo_)K83VJEo0X(n%SC!~-?3u$VHKMV1wD z!3r7GYSkYW!M6%2uzl#GG*i;dcu3Lq4w2ggAos7?EhA8H<`mlL(M6KW6Q`y-Q? z_yd8v_zXUs8SgDB;8q`QMo85_^gv0 zKP)9f<({q&;Bv)i5dPsNJ#d`2T0j&g&BvAI@u}7CBc`7)ThS6d!WN%X`=lo(9B|&Z zsr;4Dlz~X-0jK(YJCQ||_IWR-wRaBfEyG}9|54|%%n6V?0jUAjSGR+;>#%25P^C3f zz_?67K7X}fq$Xa^2@LNjSBzBX)XMRFg^ydMO4RxSP&8C>^|ii4Fc|1SFwQFpkuuSy zYs{gG6UFUKD}O+}N;T}2p5(r~6^HFZwXKaq1G@b+`IhZ!5iFeBFbq3%{o&-VGg7)A zhdAv5nCXz6kp^!u@MB6wmc{j#rP|wZoczFB`!h1s^q=?eXZw;1bI5R$CQ^XwNdtHF z0Uxmdo?x|I?jeJYO~Pb(ctc#0KCK#1U$Vwtnrpn$BeaC*IiTD%gjSecLP)+z$WkJ3 zQ3v^ZzAQ|+;u8;r@nFc2K5#jZb-oI=PM-&jbgn;Qtac8sn#3<}bhplfxd3NMAhRhN z=}a8NFvX!!71&$9PIFL}*;NU=Uc`R@aW0!3xK0RO#v0p%0_YQ)oSp5dk|!y^MUk=^ z{uE^;G1aDRJ^up?AYt;p`vyWC7(~iVdZ6;>uOEh7_l1WyxTz?8C4fw#~1pJwU;Y4 zJ?4z9l+SX#jzx)1OoKWYRjE(t;&M>W1YiGV+v4wf z+ILw{xR1gCQdx*`qKq#z6+5Mv`SQ;NG&?j73t_RZsMEc1XC7MGY!jyRuN~$kS>#F& zP5P;&@z%i1bqkke<44pQ375#c0=?~ugxI#}EIddz&cXP+^=syDX7F|bv928R#k(xrd7PD#Tah*17LJIiAr@Ag#l_KPn%pselE(0K7}`od z+?Sjvp;I9JxRxp01jb%wKKWV48A0QHH<3$S>YG$5SXwYz?639>kENT0aSg={kVgZR zI>g{q4z;(QTpm<<<&x1!#~{EtqB|SvuEyfpUfE#LGM2Iks#oC6l`BzZcQlDewauL~ zlr9QLyWz%E#m`-Jd;`veeBCWO7w{uMVC^1$dfsTvn>E9Zf`-5dE#h6oj9m3j^Pe$};1v}_jV70YZeK?n`_{6BQ{0tpd` zyc{{r+9JL2RbM}JpzyJvfJ=$cJWZKWPgmVbl-`rVbTp*NdeQz0BbTaee?Qm$O7QnNo8%9L^*!zfS!)d<4AgQ-#&UZbDzMAJy zU8z*UtJL!wd}r;X4gis!K`lR%Uu~qPPeH=CAr7%qbdJdIp3pzUBZ5T$Y|%oyh&y-f zGIdT6M;V{Yk9{E=N&~~&=3IN3gYUum;4{brTS6<5m0=@w0G&RK-y&*XbzPD2#b^J0-<`-T7*e67S{p*5O0y#9T_O~iPtWIX;L2ESELCaeY}a(<|w|Q zXsU2la{O~%20k&pj32T>d z3h6TcAn`jVu>n?z$_-$x^J`#vAqE$8Ls$1dYUM=q z3~b@``|vbV#MEkWd0?Aqt;Z}*R?MdCyH_m_vBgzseJ30X9Icm=6jmJK!wlD_ZfaUa zXa(M1x$@@@q5~RWrf0F)c_kIPJbwIq4XQg(MeR^9(CE~w3Ha40PzhrP@~Fm22FE2E z+;%J!_F0UC-a0$C4i%1{$_{h6Fq6g6(tbg*{F=8LkJxYV^$K|QO zM?Me2#U^1CW+@e;pnK-Kx8-jyfX9FYc7TVSn&sqE`P%{XBW2T1Ik?|L)@2eHhBI|n z0EbY#bD!@ILE-hL_bFh(!l}%WZla<)Z6I$UPBeznzBSfvcN9=Ze2`@&m-Lxo3pl6T z6qQ%m;L9Ps4reacJ4Rgm+cRflrwlIiQyt;?vKnoz)AXIN%xGWRkD7qx`epO?vnh7T z6Gz@oWfaSjW3IoqQF=#!n7D339^MZg5>eUVU*L;R#{|9(A?@GdsG6Z+)^~GYlL(t zXm&5GixeQMqEf@S@)HC|aKE2|i}gA-hwJcmJ|7m&ObX2ISw70zEY4nU*xvb3%>&XH z)%(WGqhg?X1jtP)V}dahSE0W{MF?VSmNNlj$MYUW2*Doy^GCAyAyGD`oW%BOv~Gwp}TB^U&=} z-px^I6WRdJz=GJ_<9L;v4pMGX#%(^YfB@mn>fj&H(DJfL)-Pk6o2--0K|!}ZXf%X4 zd0Jijpj_c%r<19rV-K0c%V&%$royC7s;4&h*Noax*zEsZ!l>X7XLh0}Q6<5W9xuo} zAyZ7=fQjF30{t9V=d+?MGP2pOsN z4Ui}!DeE^`|0dgHg`ti!1+NKJfgu2FCS2JpjbXV%Q>4zaz91g6)F=0%VrBC5)#nzZ z)dEf6#jsc)Q_?*614c##`=I7sR2}^C>;3(PjEOaQ=KJ2%-%r@(xRj^;dnZTxfT(hR zi5KPdmAiz0O7$79Qm7Z3RiB02h%(+oU-o#tY~R5$nw%KU%bHhUU;Z3O?RE9dL}ZvV zuxSdaq@7lpL$R+?XUE~m1`b9s-zs-+jJo4QD)Gb?rtv-Rmp~1=T6eE#)e-UaP-?xk zI8YkS$?M`v6yBhIR2kvC-w)Js?&)stnOlDVcO@NRQ%KF2Cd+2}xx?OyV12;3Vb5WC zy4xT49XNVdN$=h7Fie;-P>ejpU^ctn=;LvkW#5Q7$t0yv(8uHuaQvH6GpMDJ2=tA4 z!u(8#G zfmtt8b#1_WVzkZ=aIe<$A`VjDxL?)Iqy8_&q348-++)TWuUOjBcTTz+^Qlgqu>9W< zBAHzgEX-TonP0uc21{;L**p2X6>C;v{|Q=p*I@Y8=VZyKq`|y~tda-DAhM06P^C<} z;>>LV<*lF~QMwJY?kIo3g zq|+X`)@%5`AXtyngv4z3qwvbU!_2woXe{zUM9zz2h+M z@K&FV8{776Lx3s}N`$7H9lu4!7P!Co{Qog?M*X{kqzPjz`S?f6J6P6Pl7mJ#sI%7*8 zfFaTO%pxcTZv}7&a$^$&-i&^{6qp;$NC8tTFM|7*08r=|bktz;j}N+2Fv+d}o=cWf z`4%B?(7s_lm86_iJtt%gNPhfq12GG``YMp$~6< zU@O*kdcL#C$5qF_me+HB`TP3gdCGCe@mZ&jHfDbjec7_&U?JzK!kQiws7xt(cXj4=5(bI9oSF2mT zW_-k%Hiwq&X0MU;#kHTJ9RbQijnik>OXN1C6uw6|X6VGw-nWA>?-Vg`>#v#9XGQll z(66i?PZrvvw8RBom~RQp_<*QO`@L(rCc#>VaaL)@br^)oA&A;!a^o)3&TdbWhh&2s z{xem!eLe`yg9Hpb^y!VSppyn{cChKfY6uG=aI`!vnpbmEWaxgX@;s;k}fo+dQ>q*)0z zCzPFh+yMEgEj&dkkjLZI2QS|LuDOV#;8a|xwZ5P~&1*Zi*QB1dz#W@@?u?y8pnU&( zRC@~1ZV!g{9*qAJQYO)CjB!t3ZBN>*D~sCe&sM&2Cnu5WtzDGq zEf_VpIrb{_$P~?!)fMt08gnTY!gY_I6dT~lOSu<(^1$=Rzo zmQY96fiO@z#hFr~Tw&okI^PiHmZ$_%y(=}!jl+{b`LbFRRZ{k?6Iz#+Nqf#Lu_R{O z`jq{C{6^Un^;j@H_qd(y1=p#besff^7+)-UkhVY&EQ-qcD28 zM}8JmrWApSC&a>H$E-&h%Ov(G2snqVP)apveB+0WAVzEmX=#k6f#S?6A^jw%F{!E= z22EFLo5Ad`3wbcSUPWcW8+H6@X_YZ8s6swvMkXDw{U8g9;cp4?sXw&KrN6l$pXc?{ z9w|ybO@2D3mBkuv66LZPXix^8NikALbDtohOGq`Q!Ux+Xcj_nOs)33z3Q1-#L3^X# zbnVpQ%?iC1d6Ct~`O8?l0(Ye*Vc|c2kwsnQM=MhK{Q_#Z{};P+<9~@6VJP8 zDr@6d>|-z6mlm0^VgN+e1)uM7ker)MA&UO0UO+gD`xE-1Bb82zc0GQo24wkuri}?> z3-RwBwl_jy1(mn5$7W36pra!AM zHk~ryLXb9b>D=(2suS%Gs*K<=$}{V9fP4ZuB&bsN_h(n?e3achUw(gV^PJ*NGnl`l z$(k4dB8=gVfwxoG6YVF@A$+me?yR}}sS17940R=$ISV^Ka9yGqv;foRkFEB$G5Gk6 z@9*++@}v-bjEiy-svL6?6&>RByr;ypbS2>AOFFQ~x<|C?EB6)Ei9|o#hGparlBnqc zJ>RXM+@B3^8tM(gZc?MOO?H93!>8qsb%ivo*H=$J>Uz3pU#0HVB^~CjUge7v=^(oq zclAbvkQKg8*K3rQ=-;bH*VJH_FlE{CA?+tsPJo?YghM1VtgDhy;%$BtaF|f|VhvAh zDFH^FfgqUKo$kn$fWWVGWqm7vuEfykvo%Fn`JH4^mJwkf3H@EODx_miaIdtw;J%|PzDc)EtfZP1=b%^(5slQHh>fuyyl;& zeDf-#3u7d~e|;au+p3KUFanhz;zrBQZY(}l_2FTiVX(wB>Mazo{TT`(@C3)#<_oxw z8^x%|ev1W2J-@F59ZP6JjmmoforvEj*B-_tJbpKz=Oy0jNB;5G$YR7*t7~H-YRPvH zY6PelaOSLELR)(wq&kVJV*4cl*h?eq?na4F$~J$M3~bvm)NL6-W0t_}M}02~?CvvS zhn7^S8{s^FajW$LE+IpXs8W|BbO|VPP(yrY9wWnGffwE4dt0_mrO} z{QXXfW4)k9**@Co7sZ1vHBp>cu7D%7Ck93j(Py~TwO4m^dywV;%$_G#A9MWz$A2|} zWiZQ)(CoENIr?jN-Jp?%Ky(fXjee%A;hO$aA5q?|aDaWN-ucFJR6;!JEqCY_=-t42Y zv!fA^1Tl2Am_ye#Sr*hIGcf{9g`Fn9o;X0KwLOtQ!x*OhO6KYI_M{lm5xTj+n-o$= zha-OeS}zeTq%T6t}fB*9Con#nFFI@o0Dzh?>EU07{zo3Pa_Tkmd`DkO)WqLVFab>9}kdzp80A& zKE_BD0H_xpX*-OX_C~1!&Rbn&@Ye&s1qaT8Us~mCjyJ&{8o-Uyr9xvZmxi6}$A9|nuf6nOKs;5~l58?oepbGDCr4$Q;S zP$K5s<|HU0J^+hN2^Q^yk#I{*|hz;C-3Kzq%fadagVzTwLj-NBU1hYpQc8 z{0<%BJbA&SPFkgCK(^iDm9ks1RURp4)Ba!Pc2rV(lRB64B-D7{&u7VZerwBG2)2pn zvp_L^m7aeHziJG>2*1y*&0+V;HXFLu4W%ElC{0jEonjV@YJZCw937{|0%m^S^BR1H zmOA*WQ0b}O{SfX!X^7xqA}ZkDkQzbb#JvGCk4%8Y12*y%rHtkJ(BY0K!nTg=KiO~I z*IXQGY`e-#?i5fzWe?JSK%Xh4Gn$n%ixBRV2QvgCDk z*VZm@58omnvswNQcfX<3v{IX)-*7nfy-zY*g%;HbJmR{m?d8#bZTLICvJnv=4>`pm zrrlzr^CS+euSHtL1Imeaz0jw-8RrcT<>_y?0(~=qo&9>%joVj7@G{lkc3?1#|9anW z_FEk=3#W2v!Fj;@mVkpQO~m1yOf2U^7s@<-HVZpSz@HB#6_X2S))YMmDZVDCfCmv| zoEWHD#{cmr+j`f7)-H&R16v76yG}1Whix#x$sPL}hg5*d0Y-?Q7H^&3`3C+XfR%3I zpmG9*WKrUb1^OKl3DQ1??(V?a)w^ypE9z- zobhQjzXDuL7pBmlv-4!CB0%Bta}hi5#oj1H3~sS)-q~sW+~c=qYz#QyZJ>*`5eGV% z2%(e_qToMkdh39nafPP7@b0UT(>p%@Q*h3L<$ zzj2Bkx95NK3jcWzKkxN_uET$>!}bO9pXcE}&%=M7hyQwx{bybLXI=bfUHt#ME@%Tk zwdwEs7wySb-$JEvfTFFVb@!@}?`gwX3-2aW&Im~8#NOVB~uAR^CC z)IS&Ie=UIpddX0hGJ${PszN!*pOSy;2jfZLy(-^P{x!q-`GT$t0uLX%f-{HNj*9>j1#z{$)dw4aEb%QGWTGo__4qya)?}4-FlN#RySe9GpJ3dL;#jA00W44i_+e7D$8<9|~QlxydvnFe6J4Fk5y;8LJ!v zZ9o?wR=(31=E7#u)slQ3kPI}UISwXxx)9cLpj8WN`^~`5E(Kw(2?*y*gFu&TyOm=J z6GTa#A41$9Fwy#YhKui7X7N!;ZJy|hJ-8?A`&aD18%YVk&z>2S%>gPv#QRf%cJ{NC zXW|hlPRfm)jas@I)nv&-9XlV^|GJuf-o(KZE(KHhHOP;n8`8mAo_-Pv0OfK!@=!`! z54>OwY?^L>yx(Q7`T?j1_Py_tpns34Vnrr~pvI_}CbT;b-8ev;T^sAuP9E6|VYg~u zUz|FQ{7v)=G%kI6t%VXJ_hHzUCK21t0kYLhEy4K+85oR%4NzQYU}0342k4KQiot%z z>GgPIN(C83qvrEVm<7^@l}@4gH!{q6y_K&4ihE_`gJyY{ z;>1~Hjs0g?LX_X$esFAHbm__g-WIiX2#C=}0z3A+h|(3f{460eRE0acW;%G(UD@@q zx8JL6E2=UF8xV;7nB77JqB=&>R4(a^OA)a#gvT#kAa?K1!R>>9#KDk+1e13j2fWA` z!`DHznh6tj{fjqIE;#dLAp(EtXkZhmfcJEdtm+k9VMg%)<`0NR+a`r^27LA+qvENr zX=$yJauPvcbXPut+4dDnHv&L5mF~8l8yAZoOLb)h zk4R%Kk89v}qFAGQz<>@5} zYxotLRKNllYhHN+anAIpdo&H_Ol8Y=cqlD*Xbe_i`T#Ilcp(z~^R(EXPirR{_+gVYXO3 zDS!7Ph_pcf*Wsj=G>!zu6qYSAG0%441 zc+Ca%jgmVIp~3_R)?n%8l&nwQF%=&?Ni3ey{~h+bmOEzTt7z`PQ7@)#@7p{O53!7& zJUb=%mbJMDy|1A7;+Ttv2jUx(b$0A+2P>^yIySNWCncJ<7c$$=4R3xNaAF!rzd{@N z9!aDMtfvWe)W0j_0#Tu4gqhb}enas!sM6>%gh1M;=KX;Af-m5ra!uMtFY}Y#}$C-O~@D zjPP6SFGujmw0`l%va}p@5_-T+NKrs z!S34Wx}E*X7QT~j?<`>KQvTNZE$%-&@&Z)6F6cqgv3W$w7#{ohBYpJ}&~(q|G9G$i z=^OkNSS}d|yN45G*vfjmtu1-S`gfKwRM#<|PUz?w z$OipWomI(?4LdWd#CN**=Ap7+*Lm<=*o6d{$)MSuPPDWpO7dGXwFBSfB*<$C zpRarXi~6c5eli)|jWe0G*gJ|TZxU=G8p%wgZ?vGti0z}~=|Ib@d1(;NPK!<&L6TFX zUtw_f?rU;t|3cDHsf+$ID}Ot>IMLj-ex>=B%wqd;LyzE~3>M~0l3D?Ki=D(n8BJHG zCnK;YU0MC4atZ1U6CmVggWvZt@Gqw`dT<^;<~tTqS4@}(>@r;>3aYnYW}N{s)D@60 zG@g(OLIo(uzF@PVNek(P@T#le?DiwJE`1SXiVx~7VVL#m(CNt7vWJA4JN5?rBmr%I zK2JMfq?66;-6QMHF2eYpn{USBgG%TRU$TLnqhw&2KbWo1xl8i*5A&kU7s+`8f5Xr5R+hK>q2PvTI9`JHr_4y&Z97YU9lZ_VHYrKvt7DP~F^1_SZJ15Eh+B%E*&m$d?ZzNqfY7n~~2hY>cdc(s9=zP={rqBR|`?^ETwt z?*pQWBTw`_g;N8O;84IDzGC?7$IYXTzj&{|KfjH#v(t;}<{Yp3orT-)Cj`c|C^+&~ z-82Zj91cxPhhCU>as6zA_H=1;9W14 zyPhS+xd$u#jnh~Hvl^|NFi;Jz3^%_;j%>&b{Fkb-vHlF1@6f5pbWl?OUuO(FQd$xH z{28GZ|MtZ_sO19RdVpQLu0!A0je9*41VNZ*s}4=Q1F)jC29g`@S3mu+bILk+0EQ_u z6%K>++sm0h{gD6_E)J|9J;-T|Bss6n(~|E>hBCijsa*~riSUE_r3`hLAQoX67pe!) z_WAKSg%L82BtHq%B+GEY9CI=O+87NTzUvy;L+GTx+|&p}om%24;=njQgRk&jOFSUY#4#X#yfdTJ{5o zXbcgq%-3n15fx27To6;jJ+Tf_vXm(}(oA3opAy0>isQysPWVVsMg@s`fQXsb{}g(Q zf+~?ituK}3`YhHBue6^yM|B$(VoDK6obuVBl_FvDJ{?bZ_aORM0>z|%?2|tJvQL_w zpEtXQzGq6L|Kqb&cgAK((MqPZ4TJibSzc8z4H!9tj1<7NunL+%UHsRNVz*iVN9_}4 z-S-nf>}mz$d=V?3U)uXmdw&mbvwsb6$-51_JGNGp_cZ1<|53(14KA`jQtX{g{N6L? zw-PCKxePW)r+H1Z#QVVE7^8Xm?)>j{2PX`%v6?*m zzq6Io$e?DCyLSFx5B3DI_tMIiL-!MSZkTB=O)^~h%emqyhql)s5qn#}=d49sh80+gnE;7aIHBJI*RtdM>_ui6zAtSae-dFLVVzj>Meyoa9``~R2g5Tpw> zIY@qt3fe4@zBzKVtmEV$;dNx4XXNdg0 z-fC6onm2GdsFPHVHK?jvhV^Y*nuAvnX`}-HF)fr^ib%f8KMpsmHUp3(cvti&$@coh z`zRdSHwMJF8(sdjj$t?dgbkc-VEM?=8O!NA=%V+W{SjwzE+m@$yV8aG;Wiw z#72RxXMy(-?R^~|q%lK)=XA#KAI6TyNq1<7ruX=5<*>DxNzY*etJe*jjo*$CFvT23 zihd1;c|XJ({cv;llWmx^<|;TV-Ci|yN}=3-F8p-?p2%o|Kp|VR3>zFQ`~V4P245Hs zBS;?>^mK%9F=R{B!%h)vZr^3uuC{)A%^ZrOY_Q5gu0+VX6^K+iP#AkoA7C2kKw)fv zG@XxoD*Erri9vmtH>cUCH^5C99rK0`LFYB~J%cT!P74K83N>ahGApd6Hs6xomX zS(E8COdH>QL-U`bFlp5KiZFsbcAnpPjkL|<8zA=Xs10D*vJ3SD1E$w^LS(uG$s(C= z-U-+Qq+?3ivJUViDVt-^ zzWF9jyzb~rg_ZTiJ~c;ZJF<}~!Tczze*aWizm3c^XRF+N5NIUi;-t&wiW(nf*<{&J zPm<3U(~H{e;oas!zn4sO*nxgoyhs-GP&FoP1uvb*uJJMD76Wc=T@U(FW4Nu4LubKg zDsW-6=sMP}YbXE?F$}By&%K%H5ne{hcHRO|SJ#(C9QJQcHk!#OWUdpH*C z@^HhUZL56yBHe{8200lGIjHl6_;H_w*OTD=Z}ovhp+lHVO&ctWG9VG-HCH69nt2@? zUIoJiL5fQ)bXO~o`N#rXZJOhe&uKszlMdccXTvi*xSnPLgSX`ea)Ppg2BQl+{RX(E zXx*T7Oif|A$~8no{Q6@x+)yn*Q!<0$`CI^E=EsKb-P0gVK|WR!$l++*n3$g``))N| zYzM?ZkWWVue~u-j_2QX%#0yHjnEGWtU<6ie{P1$Rgo}A3BsNwXl`XAO)ftN@oeQH- zwDk@0u^12pF99{Wrd1_4(N%2Hy7Ht)2f*XLiSPWnHs;$kasZ-gWxZ{1p=x1sV|r7( zjAk?{tZ1e+Z|wb$ERfaIR45=mdI50Fz~>6MXF^*#<3ML^HQ%bRD)B?gGin7;%MPH> z1vD~oX{Ht}q$B#Zoy_=X?<|)*g_rO2?gKoU&~~)M+`r*m2Yc`sHqF;#S_CrPvctM& z8akgs%52l0{Q(ZWm8p6b<24D9trs%%r)2!Hm<1ga?=ZbL2j^%flC4@de72>Y6T|96 zzFOROkl_!grMIF8O)*N=kV<`yq4W~tK@@vtHtmM;B*Cd?*?1sSX8fqVf5RZ}7%V@F zh8cKdZ3+pM8|}&vwg_Zp1$#T{hL1mdb`xwk+dr8{0+a~P&>~AlCh1cV?kuqj5 zXHw+o{s4~H15@Xg$9h}Wqm-_<(21LbKfj7EEz{^31mN1ByBVud6~L2Ur_N_Rof5YE zc;lE6PB+q8^g1l6ZCRBEa0J^)Qe?HTBRdJ5s#q`^N#V=CV|kwAiRa!oK@r)p^jm&gU{^VZ>fvyn4WRlg&u2-MZRPsc}_(AK1M5G zlEhy$ZSb%Jx!e`eBnFd+UUXbraxcS;$b8WyGQDQ&6bP!4H=I8juN?4HP?~l;v%SWm zwTIFMzwh-w&6izrow)|%G9Ge8#tl5+dcB$nV501>ndjHkC~{KYmP4wM>V^*=gOOXl zNtu)HE0J}GrpV`R$Gs8PTqJ@c=ivoL;WRknOS5duB_d~dN5b5UzxS8L1mM`uoR0ja zP|VM#f<~_yu)p?UTqZyk`NMcRcYtsenBAk;qO3k5jgtNld371POmY=}kBpw9=Sm;I zwC#teLk#!`#xz+V4;5LF4qP>4$HfrDNo@Je)5rG(h^e4R%wR_p0;oi7uRbQk3Uf8G zwHts2mvC;x%g8Qv-{B`KJ@_rE$&kc7Qj&j^y5~)Pg~j<1#~U}oo=joXQnAg6sUkW> ziM=B-@Bg^X4T4V9;fr;mhcnwZP>v2J&|d6887(N6mM!NxJ8Vp zmw@EACsd?V?#3`XrXud#OWBr%+QH)LOkSVy>c8+@0aF*+X<06n%XlEk#kDD#9SIi5 zctJ;}SOm_pQ|sax9i!wOG)4UJL`5NVY>@#W1`Y_Z?lCvM`;o0Al`1r#t@Rc8JnyyX zWB8xt)7*QLSqZ|hsqK})P^$cyWdP5y)xuBf&$^072NSL2OV{sJPz)2cbEoOrx76AM z`bmmSrUqdAhzG;0ubIex&&7UEQkhDei6CryWNw1NP>! z(}DDtBmq0m*=+~#AWfL$)HODvwoIresE-#nOLBK!tT;{-dh66JJwAppV+6<+5DsoM zg2Jr{(IVv84jXptjp>R%Bm{C`|AUNQW@(>GS-L7XU%9YXV1CQsx3x(>w#))9L4jPI zruXMtn@CDRA=`3NH28Kz6p<9q#gmGH!-gN9Mn31N)`@g>A0*B?xArLQs156DNM!7H zFBGAuYoJSVEMtE8io~Md?amrs>v-wz19OQfkzNP<8%64#+=CrIcRj!1r4RObrlPq| z?wWWMr&W4puZ?{sIlH{j#&`tWtR2c9r3MC^mGc&DS(qCV%1g!n6e6?l60!i_>fAag zF%iX5@jfNGL9$~2pz#Oamleu9Q6kR_s`E8a zbD)SQzDnn;bou19Km(>DjNvBxkFusgm1NKqEgs^zo;T_!V$x?ZGYRx_c+m$ z)hL0ZkWylT|5B#3@IWbH@c?nAr+vWA6Q~JNLuE31egA>^+?^)?%mdZoDOBd6$tr60 z!k;X4(!-pXgJZ@~@fL6dtb#?#7f34DJx#kH7*SO?akm%OB<(rKW-ZoeXSZ80&T*{g z9Dbj(iosy%Q}2n6!@@xUj}6pcWGUwTT<1kEQE8u*Q;BnX{t}ynRZBQ6QeKq(hlJUu zN6}SuezG(7ZjA#yqk*I{a)9_*Q15<>QiAHFg)J@F(G;+@gfb~yf>65Lnw`>PBabpFstC4J@6)L zO0Qw0I|t>lpD%7W4?A|(IVR8<-MKc-a>+;VI}SgKU>c>PQ%iO(q@nl3Eib)5hWNY1~H?eCu&1IaN@r`}g$1X(qCYY=__7PUu#Idx&lvlO%$y5U@ z{SJU%Ar?CjIU4YvZ52QKWA{ta8vzfp^kNp}VkQG_%E|w}S}r%X3~`!g@0jKHyAlYx zxvt-n>5HA4h>u!~Obgq^&;9zj68JHXpGh4S2tCSSIzdLnH{bhe(pOB)%~EteDMhQi z_rRLDC09dB0N*j(@mKX`EejGH4TA&3g~`s35uGT(8fWu4k^L}({;{*|ZofTDx0Wj{ z>hqs`4A?<7_zPwX^Tk6A4>+mksVYRjxIT;jx)BdSAme*Cp|I})|8HYpEp6!@0Vh?{ z+k`XXv_i3s$!lOGpg^1$E;_mR8y_rJ^dZ^oO|ro9updm?-n37h>Qew!o2bqnJ)1`3 z!?5kwSr$)E+yJ_h>gr6_!7L^yqsA7%8VF42-WdbUh8+~KvbfCaux;LBha-@{C^F8n zW}IuC@5H74b|3!8J#$bfoNO&^k2-gxrT^>m>K+aojk zt@}X!!TFCs%Ed&jAIXjYLiv{e49$7TFN70C6iO}Yaar0Pu#*BCt!K;Dn4+t62J8Z% zH;VXCC=c`x9=;h%%d_wJ+$g@gt+K=$eP5$($mhBPdiJR~i~3p1X1q?vVKcwIYedlw zyJMqOYrkCADwiBd;8fER*AFsH7&Ct{!VT0?;mmbbS6yl>`^g3&iDawu6VG_ zV}}sncJiw(WMj0c&pGk4rTgDOSLZ9qZkqi7)qb8WsrABvx4uBp{3tY0Mg>}m!6n-c zS1vriC|^kjR~B*{J>erDETfY?qe54bk24-FqrhT9V40l{M5JVJg>?ml15?>~w5BWWINou{#i*S4WDf2{!c zD%%9has~K#)+r@mk|L6y20d#hgnMcoy_E&lq*I@viH-{PsPE3b7l{Cqy8DNK!$D0z z$|%a6YBFC6)A9ltNx4lVQ|@3oeas}ho(CdIqTZMYVzFIAcm}|X1sy4gRG3v;je8$R zOk*Bvrn%454Q}k)BWe%xDonh3$gu7}F}=xT0L>BZKYPbsYzU00oo9+(Oe|XHVi07~ zT`rPBNa@fb^uMvesk&EY#WG4BoW)%Ch&CIl{=k8&C-U^pvvV*)J(GJ>1GfDiJ}ipg zUA~R-$m$JrUUH-V)?FMhsN`+_B;OPNhC==JYvQsAt=tcO0{`F7QIpbTj;QyoIt2=(_;=G z0c2GM=B-8GkPRgW@EuEc&@dUF3^+hm@aGcUCJ~+I%K}@20^7O}UhYXM?V%wzJdtNd z4%w=~xO0CGWsv9XukRn{J#R90<%_#yqepEiQGdERKeX;j#$iVolG=m>PU;Qt5D;_* zBsg3lJl7%-kS&9<-in}-!)>-Zyd#w12~wp+%*U|)K8SZbN(VdYF)@I@P|aE|l<>SXx!+ zmP15yBtO`wg0X2`A2%!~v+|-u&But{l5N^^R9Vq1(QcXRB8Lp6f)}AFMx; zGAA2d@S?4W4KjOzG9H3~NVN8$cx|R;X*6LGXr!7b=*(Va3)N^=ebiNKp!+849ka=4 z{_7#wy0GY8WvzH0+J?XHjiQm}D|&Yc|8LLjpMO#v!yelOU3pG7tZ)P5o$e`+50+}} zRVu+1DD40oPDN?QVD?~n+A(2w4b+EvxRm$9xb>F4e@T(8gNEof!0^@-jew1*cLN+N zaazGp9@}!{J}hDa)+ajZLmqXve&@iFsQEDk3mfW z%zBTWILF>C=VM82auKH5TkIP!N1O_2oWO^Pcsd}c1@wlxuE1nt?ruHza;+Zh&I*9| zU;@HoQ&Mj*>&P#~tMiW-=K)Af?P}6s^`LbFBpFrB#X3`2%A?e&48#igO3~Ot34;Og zdah5l)QfTkrVXO^kN<(Kh+PG!r?;YPP>vGo=^)ocHWioN4=pwh082A9T0u-#7V;ia zAAl{g8~p3_@o!H-sfEntnT{wh(h)%iKRZo`4$zyr$&XpwK(vm zC;B!wa^l^*K0#J@4{g{{x-9GIUZxTRX9XwDvWVIEg-SZcS4(8^2J^goE^{>o%xZdD zPKwzi`gmaMKt#M4FtQ$iZOyVhc8&Fz@P%mLy@L00%&u@mawzmm z6)Bf1ZG21>S|*c+vOI zP^XS(lZj7U=Dc}GYp21EU?fhT8Lr|C-a6w3~*VZ>>B8#1s6Af(LT|YpC%pg zSs^-)m!RgA{UOn_X*!Y|HA*Z^lT3YIbr@u4J8pWUZ^3wB2XVR%s2MpKuSIzQ`;1NK0~#2n*e)5|6lnR|A_8w z`-Zm;+@XN7?Y#rB?A!nG5-EzxDkYWdRaqe` zC1meCDtlyI_6SKO6iGJOTlO9aQTE<4!ewP%xQyR%cHi}MKcCP2e4hLJ`|IwGu5q5{ z`~5zS*YO%s(Kq@*iDU^Zw>*H~E%PWa&|?ll17QTxk%%Zb0PCEo5bhdKBQ&7_UjV0^ zBB-Y*%-n(q*;y^3U9|^SoF%G^3Jo;TfBL(bP<(Ga2?g?d#EK5wN^}O;!{&aMcpb!* z%sjv$^?D#_>cjv3;Kn8pA^|u^Y!M<9k;q2dt5=oSPM2<+;V_h%oQna9>hW{e+kp2? zwKWuE=Y>OOM+G)U3>&7Yo#AL3BYo53haqQnE837ISfrxOGKa%4*H97gnOL(WL-RENa+xR}t;Tm(a6w080u-GBC@1?N*^V&&$jYq) zo{y>lmKquWPAiV4`mc)X1Ot&L%%N-OWFn2J-PT?KA}e!7RUg{3AK6zDZuNsB(ITs6 zf#wA+^*qPufBQ5q4Ln!WTLS0*_s0^h=*r2{V48+7$C*?zi~+8-&x(hP0DUO03lI=v zLGh6fUnsOx>^;TS_su#Io~0fV)tLpe<$OFs@;)&1)@~s8C(wYJ`*rez_%AtMLfNz_ z3wbN04@0l=JR6ILO4tIfwK;^9TXJ>+6-0Au)aY8uJiwH3a>bWlJXT_MM_99LNndx2`F; z?ExgnZTn3MRH6k~OHT8?D^qUct54DK*X-EScI}pozn#QupImoaF(A7gF~^^@RJuqu ztZ6E=E0YkhhJ80m<3_yh*2RSuR09?aA`S!kquf6xI77FY}p7` zEGlj8=$<<=)2m?_&PAs=qa9>0=>hG=#i{Phb_#SDsVuMlpBrl3r5y031W(*d7m6n4 z8LcI0kQ$Z&|Ax1h!=bd5HkHi^8vYF^49hTF0)#$^faMlHG82f|bSTZ4xaQPD{Q1sc zhZ7x!&6!7hedk+D)mqC$jDtZTh+{BpK|7HlEqS@o{ou5>IKpdJ&Mvx6^d^4YZl%+D zHoZLK*{!Jx_2qs4JD+R()RBFU(C6vguYVx{zt+ef%gG!c2lhKF)qap>rh}pI2eR}- za)AB<4)44H&ri5vEa1foAH*YJ#S|d44H^E0{KvKh?*f((CIpf;mPB-0kTG^_%$vB- z_q_8b=sO*%`rXL$zdZhe!;JWbp&VzRmmdjKq#<& z_`LOo!F+BLWG`P|1Yu~iN1-3wfU{~4;^L+kiHC#HYm>q55A9kJCJdXgctd*dYgw?` z-Hjhj(|c~3W#1`~(c&)It7R*Fg`WcVvL-F66tT@lLgvIbqdEn5lh7_{)z9>vJGbJt z{<7PbeDY`yqr1c#K05}8)Uo41U3nkDD03>>V%^mSz^l^fI;ohD;B2j$Qs+QLg%c(= z2RsXr{HsOYOyIP@fakh}q_}*{I*E*o#j%pm|{od7Wh`N&6&-@Ax&RUtR8&li$9}B=8d){SUA5;KE z2(pf-E-|AQUG+gsW8I2&zC-^T%~VbSDZLq4MFjr$ZCS7Egj}+V(EVzdNr%pbbJ-+! zz(8>xVg{|FM!T0CfM{exV6H<)i0>xO^M>d{%&eS{m7 zcZ5Ow76-j?A%2YOFjs^Z-!q23n^A8#2a=lFkAw;u+>5tGQKk9uc`-21NLGJ@Bg=ek zrrpv`6P2TiPu;8%>mvM%x#CJTJpCs(gah@w{b@d0E|qu&2<(vH6Pxd3 zq|w4j0rTPd!cj_H>hnlQc6@#si9cTfgVm+CT_@2n?n7;vadtqO;&mRB@Yx%VR>oI+ zg{rO$Hif=ID@M6;J~vx&5FI^>M^Fy)xuX^_&jKs&5L}b*U?JRYVR)$rXuRc`%5bPY z&0z}I#z)%RQe>RBi538VS#)o6OC(ae`-a6j?{>lpp(W-ZK_JMt=RPH2g{w#?O)!XY zF6Q-s#?-7}$J3AK$BFG8LR*t0JkEJIAzkD(OD;;b{*TjLG&!VFWVT!I?j$R_OK!8J z?2^sICvdkdMWW-09JlxI`BzH3@9p2JFxqkYIe!*zJSkVb3^I%1`Fqai1;0Kfu~A-x z&*X=X!~9*H5p64xC8cP7#9oV-|FXFUUF){K6V^gLx^ex>1{7uyI3;8+07VPLnh)6~ z;;4nJ-N@8)q1~^XQo-3zz-DBqgU4)|(I+G;#UUM-Z=BJ=9_-RQRh!Qk$=?;CN?T*~ z>kL+;q9w3%ys9F6;dnB=$p;})2ZuBx&LJ4A{JDBvP-<=k(yjfo`FGOnF@x(mS^GM1 z4wsq@Q>PzR1kVX5h}_<`tOQbrC3mS3N}vB%WqAPSHq!|g5t?65{%yMNP38PH=Of$e zc6W<6@-8uldi}8i`pEIVWnypaRYlx)->I@#K9#}&FC%vkm)oQN;&fo3S!tCJPYY|0 za~+@8t%Q9Il(+AK$l=VR8IGwF)3Gt-h|g5~@g`r-YxL zo6qP&CD>+8+0FO0F9iBm#*h%wJzZiK4_lVH#PX4Eqs;jupEA7agND`@c#_2nD^5Sa z^MdcNTbH@Lm)VD$;4jaX2z#`r>-glSKJp!?!(e@+EOxfuw_~)oAdaAF^!2n+#vz3r zjeArQHus`hNdf{+Tas6gekE5 z&B1!H1I+-H`teW0fe+-~9hSi<9sdr>cJ?s*>NecvK{bkHxi`F>t&acP|) zW#covvCCZ(Ff3?nUwSdX6GfVVfsHbPgplA_4Efyr>-eSAb88fYD^1Vv?tjEI@JUX6 z#PJ*w9L|PUFKNM4J$(P@>E!%S=|0=s`KSI@qDbcQ$%NRrnWbgEW0l%m=%TL@*0JR{ zZG`P(N0+-vo>vGeAw_%N2=2yyZ+IlP?C$guhPBRR-6+!fiOUAUCKP3UH~m1MXy(lI zx9 zs$$mWg`jECBeS`8@aA&qT(n|Ths0I^Jl@2Xy=7Z4r9buD@A&tZB!sb67E~K8;Z|3G z831`-Rby&O!EXW$}mS9`8u zsCM4T!ViyM4QA-W7ZL64S^o}d>baeHa;{ugs|06@ACnV?aLV?TIttyjOHSiIKRx3KZ`vUpLm(2U++{Tw7duEvH>q`i7;IGU&bI_F%M!jcWDb9ga zx;0JCw%dE6aeJt?;d3Qh^L+LkO_mL#f{B)8mwc5Q1nY7R6H8Kha&GM3-PE>xLf9-G zCoc)?&zi@%h#Mr5DFAbQT6b5gxGRH9YBFh4YSSEks72X6svS#Q>0J?dx1BG9l%8B~ zp#h&Z%>Ew#^)O~@>VxH~+JzU)X)w0yfv#0I13QF}g5TZ`kZ^f&)WZhp+Ox_QbJ5-D zSZT|(exTT1sm$uvUK^YWHXQj*!#}qtDI?z;+)Av8!9*L@v|&WnHza6q%?zV*UN;Jm zydfU^^Vp4b#B1T3V^KX=(Q3Srt=D1h?i{VM(y+Dbv#d3~Duc;`2TtE$bNU^_lI;8H z$D3vEMjAK=9~+*;LVYxx;TVp3hXj?@(V8=V%CosCwy)i2=zhDqM?R*J!(tzdA$Vz< zubm`3Ejh+N{*-1&%Jk@2KjYgRQV2aRF5jDo?^8vC=>*gli-wtZuRr=-P55?&6L5!{_vHTre;b*@4YTxNy2@>{J}hZGFKtfXjM>pD!xTf zlHihD!+Rj!B&W%I*m!5W3Wt2LuqQ&cy2ru)w(8+2rc>65u!Wa+vA_25vU-iQs_*+R z57~UDMs+AC7?s&6GOg~kj6$znXZX^}7fDXvqKeKDioi(Stk3xKvI)N;U^rb2bg{*f z4X_)y%fQc__o&V=(q;)4tracPv{rICsysMwxz)Viv4{N=#};eR(7pF($h0nOB18p( z4dqg3A8(El24#!Rg$XkIPAQ+>@(BrEC=A#}PEh6}4BVP=Ws!PqZr``><$2?(`kAYH zGU}(opoWb>h&%pConb8@|6_~a?kH)A@YW^vS2(}n9{)m3K$53$AqT8-S81FNv){=( zpaquKHPS~vSLRiSdA73Cwn~l#Vy4p$dC3Bk;JcqC_p?pOj+?;W)tW}b<)U5KYBha* zEuPZ29tZC>FvV**2Yn2=zng$8YPp{n$yNgD%WBzpj9}jbFke}=sPUN$JFrt}-sfmL zH9PlpwH3HelpZVAO^Ur#=68f7_aS>Z17M5Bi^sFP%)Ch4ZQQ|z zz3a`7lJuTZ=s4C0U=JHnA^!3FQX*t9npsUQZZ#JQz5F2ho1{qedaxhECyo*veX!ubQk6o(=gn-JWt2PQ=7V9prFRh zo2{bQbZ8k*p*HvpojHL-MyJ&L)gbm~?+^O3q-q$6&BGD>8I>(oBYiMV)usL= z83+dbA*wnirX;iriulXOxF+nR>m3GiGZ_a)a%KsXnD zkc97RMqZ1}K@y;Wpr~@!iIU_ukxD%@2C1BGgyOEs>JSl*bYBe<#L!Mtf4Tb^;Ef{V z_7Bb1t^x!U>Q>5OQ|x_z|G{>~e5>r<7Zvy0!#z-LbC`JSx6oxPE!7an0ilcPlp%@K z2J4IUF|4u89?<#h4w9tqm5Ht_|86fY*N1@jg;)MHMEY&zgFr5oRBl?+KP@b>OZ{TD z65wA&{88!zUL02*Pn|i}UIBMxS(GyRaYTyj8otG6dZ%!ZNmZYbdvcnRv$^Ze?evLu zSb^q<(g#51(P$u6DAH#fC7~N1myGz7%cZEr8k3I=1j{Z@vS zM*EfCcoBavM73pjA!GAwnOAOT!BMm9ikqJ`!DMUjysJC0z{@{X_&-h;(pLah-^P`` z`jy^@>%DwHm zeB17sa!BG@cBx!Ua ze;{!7oBkC3q07*zl)+!=Z~emjp3BBUah_Bqr3gw~X^vhKu`76fOnNsZ2E9Fl`rX+W z!Gfy1$r-cK+O_Qe-iP+?8(h_i&;5>zt6^l5VOn{uCMwrxE7B3Sxe8Go&?arn=e2HM z>e&0Tk!O>%Wl)ycd3bZlb4vh$CTp;F58l*2NJ2o$7?2O)NNx8*!NUV;9u#(M^uX`q z|JS&lxwLVoy8d1H{&TF@r-N$`Iw*%!^!&>O`3s;Fo?B75Gn=yp2=R~lh^_gS9H|7= z+qGo9r@+tq7{tGd>{JER?wc2TuZC;?pqUj?*lSKP^InlNZ4;oNpL&>;g+Ka zLQ=J|g8#5RfI}rwL6}2nhDx;c7{VoTX>Bhp#8(uFzU#HMIi=^jo?~Rtyb^-u6^v+g z3lj`Brb z#J`*7c-{jS^LMA)7?J#d-z%X%|F=-r^AOSXYV93poGrnl#6aaD8}QQ<8^VYMH>(kw z5TFVBPwxX7+t1ajHPM40p8V*P_;Dr!6dxjdW1H83h4g^;0!xCO0ESlE$L_Dlxi5!oQWrG+!XF)BS_-fnKuM^nID>% zKNU*3J>WrjcQyRLyR*f-L%;SX5)R8RS-j&$5mZHkK7aw%A8(d<7po#hs#!Uj+6O6H z^8n(XO#6ULpF%COU_%E)4(5aaV z#{+J-R+7X%gQEt=0^@9ns7SrwtdmxrHg3_D+xC~q5_U)T6&t$NNrZ2TkXR5!FOt_j zWPT2TGMCOb=`Ov}_e^gzxZ|d>!QnHzdk=KRjs5CfJ2nO<2IXEBwk)0D%qah()gDO< zS#!N%H`Dewjo~_du<-cK08QLWQsx-fm1hFqs}EVe5%+kCz7FvgMb4m&AVupPs+1D^ ztr!-+6YI){Z~eCv17UkyjeO&;e0^YXR1cEHcvtTu?_N8%iQt#0pX2M*hn3ZJ0Ou>FS%0aA=d*VK*PAeUKv53DTp3P;WB%(X+q@932_W1{76Op4Q zvtQloeiaYnr7Vtp=u?Mhq5Sm^%nggwOG=kYt+#-1?ck#HtT{*B5DXzo{GZuV>(u+VN^F?cGmlj?$*eD?gV%eiy z*z;S7ZhRMZK#UxV5JEhp7Z1g_({%Bg1GBzG_@G9m?YpLIwfFbx*Qam&xi0&-agpYk zLTcVyydXM~U_~n^GE`SpFAubPkr_rI;5}MmWQ6yS=@C~qM}AA-_R#d_W7rqlQi4#e zIF1#dzZwZCji6s=pP~EVTqKnldl+vbSyDbGgv;vD$nEtnX_!Fhp-V9L@cfuRT{d;s zUuS|11_K+64m_Y?`H0KI0u&{jc$S!j!Cpk-M)4ryk;8GiSO-r~v44#5sYQpEvsP`0 z3ksTRFI^;*?l4pKPlxGaP;UsC)Ap?uq$ zl~7#`pcoXA-;Iqztk`&iu?Uqg=}er=9c0?NwK`oUgNE}P302)jJP)j7N}0n3UQqG( zbe++hO$e5eEGm8x*twn>g-nlOylO+G%Q^Rih0~^T09?u}mv^}M=BxI1A1a>kL0E>` zWoDDR5WiDK#DY+$S6`c4K_Z5^4ZoaLywD0m=E#D9JMrI4?fQW$+eVc|wE1Us;04t| zC+G>0lu45WJ(Ntx7gmBdZ4R?ATStu1k}q^iUgt55NY^1a*XD4O3X<|TKt;%t{(^5N zwKHgdGlFscym*L5(zm81u*l1Y^;UvahQPf-P+i*Jlt%`3gvZh#a%>k)R!hm005g&oQSL7D^x>5{!}gl?9v5m87v>y$tvuGNnm@ipDfI`G}I zhGAUAHpA`cYQ>AT)%`w{Gi4XkxSo-4X7V)*3ONs9 zFVYk1K8pBKD{#hA|yX=vFhqfh2s9ONX@BIkG1G`>Pw_uvcHk6 zViS(MekLs+si?pt`f~sjyGHmT$|Jd1lc!nRI8@9nb2(t)?*46CpFhgU2MkyCd)enh zoOXx${nM6=w9k%)>&ry`02^}*>OJ4&nPho0jM}G#q?Q}Kf0uH97372y=vX2)N_~z& ziTzmzFnq|0ui|5xhxvCu+q-5#?SA?w{LeJoq_>SKB7BC z;8r0RrwL{lBp69-yLB<~Vi$Un z#ZshEqv@+Li%!FNre_sqN&BuPM@(ge&9G&;`h{jnHQ&EG?PH@1*FyLxnX!;v=I;A- zp^ylB`Qw9eR@6QO(ic0YgOtcRTzsNQx~;Y27nXn^kxC?8A}~B%`T7j5J!u1nQ;ACk=^?9Y)=0X1Cfp>KFE73{vxfU`6VD!R}P@0jGk3Mc#d#cd^bDJb|aL zUg}_RL~bx&L5AK6nBx^UhhJ4Zc%@0Sb;1S|OZw$9jnlb66{@5ENnOms$+l0o^f$c> z-KQ&8{GS=p&t+oA_FEO&yF-4S(Emng0kr30?5k0*i8JQ$s|Jel{LX4?5#o5YKEO$k zz}Ninb37lDurSq?+^BbbFU|`Lz_K9<&y2escrQL#@3+7E`OdKM_C@3U zI8A5LPg43GJCiG*_`1)m_Xtwq#ir|m#t6yIV|kBCy!XF1TR#Dm65#KBviR^9L$2RS z%GfqM#O@a};*wopG1vo8l>E$;ys(`oNJuoGiCzF6fxQKp0DjAF|LEUu8GKv@8PAnE z_3QtZNc69dHkc<2m4K8-LJ*@B;y(dEhos?D3fXUSvVZ;Z&p!!QA}&97KOX$~7r$D` zpWp7t8}<60pI!jJ1H(UlQ@D}Dc(k$tO14J8$yHNA(&gg3s2s;UvtB^r5xJ@QgWo*( zgt?I`l|<+CYf|_3@A~VVZeP9vL$^zeNQN3W*z8?m^t<`nP5hK3+;46urt@FC(%<}w zumsWyT+YWq{paidAAahY0lMB-$}-pf%GUesWB!MK{G$Z$47vbDqY}n==wH|U*A@7i z&;38{lsXctlpguu?`A{)_Y2aB0DCg1jo@z^*Z=El9K_9Kg72Zi+xT}TvH$lgNO}ox z1<4)#M;F38{Ris~3Roo9I|DEQ+Hcnc_jhce9>JIw4cq5I9aZ+RYp(qcbpgnm2G1Bp z>O+IWa&`UPrNPhxn6De%BU-G;QmNixu0BRG_;Aqn7jf@@TwV-)wH9@6 zoc}<1<$`dbpuAjg81+|Y^1puqKPl=p2GLq3>;O~ps{7EVS2V*b0FfEOwbFFuCwzuO zz{v>2IfU6}ednkyut{IL0aFgaM>L=wzUyd_s+07?cniwUl1?DZDN*5o+-d=xye-r@2PDgU=ic{8RO>~XboZb5If0Nj`y za5pZFLhc*9Ssx%JmiybiRr8=8&Ig|3mIrN5VD5N*?hq8M+Us7g(_S}i=u@T-v79-|9WI|w2v}~ z-<*Z&_yzu5$46j7-vylsFBagUg{e^8LImGgV(O0hA=?3I*amQ2`(YwxQZ}FKhv+v+ zmBxb$iKzvLY;0_#8qA&$#XzO-#wug9(zKfi#&d5pExOY}BHC-02;EJ&9|1|;x4cmDD+WpcA%Vf|8I}>1Klq>i_@8Ff@SY&tPs@#0i1WNU z*C`pMk7V6-$-w=*?tAz+i24!YCmRpqMQb zLD5-OvWg@b&V2{X+yGbP|}o5+eIPlKcu(I%K)15Lh(ev^13l|ya9`f-Lf2GlObSE zs~Uk=ya*TpUFw>fkykItjo#3uDzkwiMDq{)yi8CDExKecd2lQ6RWUbCfpuHmE_tdO zkbqzJfS*j}7wE!VspcRhB*@9=gyyEn}UMbL*=Rv(^ zZ;(o|2ih|SMS80kP7Uln)?>eQDlCnrSctnjnSBCg*$$}h4XG0zztJrR0MN34LE<&k z(1rvR`eDVo3eYV(cam=I0%jgW*oSmrkrnJxHRlmuUd9}HmQ?ReSo$Ui1)VXahCYl6 zm;f!RR86%(S?UWZ0o#J9tZXHdrx4BKE*)m;3rA}o&=01(9w3DMG*ue~Z6pr__%ZLb z!FLYW;Z>8OE842~>j-Q%;y7`yI5SFQFnc#pA5{6#8mp4f zCq~Xv64E4=5|gEL6g||9xZz}zb+6lyV5AgC6{j|4ox2PHYP;K)HTKqHXM)-uq`UOy zz0cYA0l~Jd;oQ!m^}xu2pF|m;-in8>Pc?Bq5QRshrux`0J7PVCWkn3;CV0_hv1YSS zRvDjoS`Oz*_+zZfv=+Du*!QR#^&@Ge2q&llWU9+I;@Mu;W3Qwg{28VEAL;i0<58j2 z(F2xuRsdyIpG#99+BPBh(J~Ckh?#5Hqnq|SakA*$56+%PQ4lx0wbtA z#Gc#fJh%1ut+J^%nnPESloy2g4%0-bsIhK|O@!sgaU_MLLTsb=6PB`3ho(K9CRdiP zH5rQE0jKFGqwwRxdBmR-qvDdK!p8aR;WS#_09{$}tFc{P!RsQPXVKTQh(?i+nustx zSSOaRH({j=;+YS@(Y}{29#i>ZGMJOZGf3>6>K$vm&zxpGUpN)^f&aZQ5h!HOA;<9Y zCdUojY%bnx^UNw>>{%v}@FMvYY!^iG1dT~|k+_rQfD3_>3F?YnNs^rx0nO1V8qk}kT3H=+ff!KiE)PL~_NS|+TElk;YsCu1Yx-t!62R0Ft*>!%%AQe!6Y*|G6Rkc=D>b>BjCTsNPuv z9{`^oov45i(#x>{#ROU6AzkX~RDPWjXxAmhr0G;|=hCS}^!3HL*w(#WY?(63Q8mX) zmd~LjlGpML9xotMO@J>lVv>ol=;EyP$%N`7C`%Rm?+E3Ev#H#R`E}Q9830yU!G&Vk zs&{rK6Hcyjk$eEK_A8&TSydJW*ztK+@7MP|JxMcUj)&;p1-Y2#(2-fMFy5YY1i8E` zpJ=qLs)hEqTHBnB62A-6m14R~wCaKMZ0%ylJ_5v9OG6+1+9xIbhe0UNx~UF_Kse!> zw%xS;b6$BT8IIhhS!15L>B-60)7lkB^cCzY22C!zPc00Z!wzBj#1~9H>OZ%8@%1u~ z=>fpac7TRO?;fyR7b5{TD?RY&@v#myCrCxo%6V+a=L80?QX-UsjNiqn<~w)UW^N1% z5nPs2sFnfO*Wncet9S4xxZLibBzQZDQ}i)9$xQixFOIz{$R-L1Pw>v?)b7wxkiP3@ zSmVzH%d)6gfd%Q2kKf@8Z zE3zV;8+O#>UC&qlz}p!Xa8gGJ?qWl1-Tu4BE2CxQ|!3!r%sSQg_xJN zO6ZRUsmBc+pJv}ud%9g_10$KTq4l!U@G~)OKb-tEmmP4YtT&6ps^oo`;R{;Q9L@$0 z0xOQZkFuYv^j%7cIWCX?=`>Mz7Ib`t5lP=}{x)Ix`%3=+6t%)M-fkk zAzby&@(0Pv30IrF%GE9K<_dNoYbxb?%B)ArJ6j25fBIm?8DZCsr`zFFqKwM1FAOh% z-(t{1dRDA!7dMPsx|1H~PXzD}z=0o?Bh8E)I)o!_FAj%CU3`mZqL62agDw)RL~FE7 zSm(4JQq5OW-`D~WkTC08*?iS10gi+WaC-b6cCfJBj)K|Wn0qj3EN!+P_HlO|KJ9F| zQeLJOP=Xe_fGF+T@-a@Gg%f+nrUN4@!Yf&MJSed7p+M786D&2uw0H%ZoS?$gVX%1= zVy$1YW}S8zW!k(vU)fzUo3yYXDAnsT@ke{tr-Rq@Fq@(U^-Dwif2=FgifY*K%7uOJiM!Oq(yHGlS<}j>6#-}1#KgL9iCT9l++*Qt2vIt>%i1+;l;w}qkb$I2Sy|R=EuKV6W z1H4X8@QY|>W6blduiPytGL$F=&iMjzW+MT1oO6C&x}0TVHZOhmqo;a%m_#udi-D8E z3FSMJVDj}Le-Sf=+MHsjVrIG{!XpXd8)PK2Wj-E*WOaS6!QPx^Oe_`3XNMcPVW*f= zt~50{by`J+d#N^Or~fB(<3kT9%GdrNgq{9dIsZTEwx2&04yp#Vp)ued(gUVF&ElVJ8E$LcF zno{bxp!fb`i&ZSwz48vY3FABlyBxtSyNw~A)<%wfoACD<+{q;#Kgwrph!f*#<*Q5V zzU`(zz3o;rv1`Lb(Y$vBOl5dTYM{6?0z)BAymN@R#bOs2dSF>DxgE|SjiAsdr^2lyb)ajB{gct_QL_DrxE0dJBpYR4tB7k{ zYR=+jbCk3Q3bQ%6l+INiqoQWvcXYQN@vU*r`RP&O!;ajyvxoiI#31fIgR_L9(RfMh%xO{6K~;(S`qAPFU%9&mh>;W9=lx89#$gL(N-UhZq%QBhy>hC;?Qww)A9t3#PP2+&+pazjzPzxKxlj6M!jY4EO@94TzD-tTW(#+p^sLN9$ z{`;J4o`Z4zF2oiNLJML6Q9v3R{QwztQT;H?LbBOccI@abt8V2Ggn35fc9v`~Lfp(JH*^eQtuloScw2Kk;FwCzX|@~$TIU=N9jRU( zC_H)YKeL}HQ?7J19By)rdL4)+BfoMo5*m%fU<55ytbSHG2nsv@2xOXaIO)J+J8v%~ z8Sa7W+1sXuxOi3!FA;@H~F;slhg zz}qkp+O3BQBV~=fGubAvTQ`=C&k<6vy!=YICL z8{N+zkorFo6Tn36H@r9#oG#~oX%Fn7N){+@ySqq3Xx4kg9Y)*Ts>c^NN+lNP{3;lH zYu!M)Kks+*Q$M2kdY*rw!IHKob`B0^QDD;74x?A2FLUb*aS^l zO}{Q_Hs>z`ZZMtp#+_s5p;K0riRGA}6v^}2KkEb;kOTI~P=JxJ~l)Bhsr z_$6#Y`(_A$Yeq1>U5%KCL4vZVY(8DI+(kMsgq&6>O9)d$dk&WyPz)a(^kzmRClRzY z4;6jg{PVN>3A;+R0T{%TNv<2^dVA4km7S`e>lg%4ZBB_j zZW;r|vrLuQFtxWlj6ZxxRmUkYBJsnL5sb}Mg_E+)7sjd-5kk00(j)L{XaH`{ zD_7$LRQK&!g!%-wlJ%@u56*}>==@~CfFJ38z6B^ZxZ>R_U+>Xel+A0NanaS1s9{3v z(;{{+so~?rr36UUEa`)jl+-9!BBI|Vk8Ho~DHZ-q?BF#?1TMj{G0>gzXxFg8{@laSi?!F;2>)CWCzxLL51GWNzyC{Q z&)>uQK;5CQ$$(Kc06SJD3h* zT?Af7G&KnGJZc5CKzVWx&h0x~X+cg}CNw5V{Hx!C3qJ34-(T1h&_~vUJeWJr|(xk%duT+l)1u{9tFNiE<+;T_?l4@}ad(|D?!5g&oLVN@9fehcS^ zqS|esOq@qJJt65b`$%>qHku9gQ&ePc0R+I&UaY36@?P4JZJMmxsB1I?A%6{ffbCi#R3fz_uB+0DRw{5{Yhkm%j#gQ_>L^U8 z>>!my)bnEL=z0X1{ix}iNO%$pg+nU@hJEq8#*vY~9{-8WsZdlQdYbF~^n2;|)1#&; zMT;^jna&{#V@)Nu*kPQd<0bpQ&%po3`u9A=9{Xy031XOGsfW#-$dV~QKOQQy(BxSu zr>>~@s4ISuIi;l+(&2)7jV2ttK-+;u9rSKinl;& z(BY5+EkE0VTOy~@d~v8rS>ndR;zWJFg})cAkp`3{BUSrz2(uC7?^Ud}XAo=?5uLgA z5l^3V3bmOF+rdmZ)a#`esGFnXmQvi=?Wmd5ZdUP^7NN9j>^daq`{5+A9WEj`CqMSa z@EDWv0PG818rBH(CKryU!lG-jI?aj#4p0k>UK()jQq+&o>~Xj#n^f9oEqH(nnW83b z%V$iL8_Tb$yE?^b{(YH({h$-p+o~-SkH)I^*6)W6 zl;&$u|41hyP5jf0Y=3m5qEg(x$LYYn@@V=tABTWIa0&fI!=5A7y?5mvC@aa8XMQN} z;1TKFIru#L4W7X(H}>M#TX-Vm$3D|BY+kBd_F<#Mxq0vMS!u&-bR1F9(Uqg@F3}t< z=B4SSWoa%gk(7i<$@p6KS(rqrM{7-!PF)awB%F@3wA=oGC3EEM`p|@Td-n*Mpe{i6pywLv z&g|J{;+x9P#KLFeCf9_w2L?2BMD9I!aM|NXS$khs=y@{9?n`v^^zq5b^!q)qD<3gg zn2b1IC`;UvY!?|m4VU?QS>=c~bf^;=9UDWwGQ z`=SnoO**{G3Xd-N91~o571-rg*(s1rK*D$>h)LiEV0D@1?Q4BvG3yb*og<8!FVmb8 znpkGt?tV>-(nyCIt&zT;HB|m>YHF(drZj;^!gtYajBzsNMp$C2 zc-oDiZwYS%eMh%@ipB+&oMZvL=HLk(?QC_Kvh8E~FdYMNB=kKiCaqdCfwtaQA;%uH z0Hy4s1D*@GI<8;Y)xSHGSbqBcT`!W?r94Zwp@Ok(VE<4B&+#F$Kkkk2qXU2chiYvG zD=r?+YkB}lJK(KiG@*c(-X{-M#C>&hO+ zq^GV!*%$v+dR+h%j9bOTu49Lm-v_#7e2s*qTZbLNRBkRj^oYQBr6ejn9yRF3ZcTs} z2~))>ZH0noDx-OZJpG?X2Q2qD6pPVAqiKDdE>RT~6|d41&3j#miaMR`bJ^9x43}m z9X<)0#IKw1cYo;P!I{0dNFU>BGpf}pQub1JXPjago)(u{3y%deUB6b>Zyaa0Ezi47 zG3!2CV@h}XN~rr3S=GzIF*}#t;Tun8i}kMTVXA~GF%?TwBG1L99R@?0tfXXRN5kEr zbu0$pD051fdP~>-24@!q71aWE zw?li>g7n1OV*j^qkgxjp>+H`TS-r$nQ1*lhoCU$3z3m1a7Agdxby%L2_28qUqZ{g3IB}pnyeYX30`VJR2H~H@FZa?!_4qcEz_%;sL%VYZ-uUM@t@z-R!Sot z?pbFQ`{NRk(&wxs6TTN*Hm?+E*owJrFf&nSVQ7Fn?WAq3riE zIXXms{IiYp>YsbzXP0j`JtEJV4`zp=OOa3WNLU|duQ&UO1|i9R^ECbbJJl6zv5#x^ z+5P2;cp2^Ztt`_0Ol7^TgY? zZ=WqMH@=O~evz0s<$CMkhTeXgoNoDYy_#0VH60!^8yoHpX0|Fang*hV#^73Y|-u>sB3rWQt&FpRv(Fblvw@0}W}v7q zJ{;;_S%ej+IZcY6wj9U7Avt^f9P%{$-wW}#->Fu?Q4Hp|YVBrNJ4<@OaVq4qy1}!O zFA-va};iP3P^s z>l>1D%p@E8}&{))s!I zCo)+gm>!gG)fcEFnV*he($Xrm<5E%W9q(JNJ=?QVhwBUI5AQ@d@jrH?? z_Ackc^V9{T@y9z5RMpdlO(uXr!W$syJrAEHPj>U-Ggi{^|;Z*?v zirw9Ug*QW;B|bih;$I&}X=rNFrgbmQ4329k+9RS|ClebVFVGSrbXI#f z>gkf;RPgWJCp1;!|Fipt08P6T$Lprja^f@N+?iOj%_43rF4}%mEWE2XtzReZ}P6oEU7W~l>nlGA_sXE3}!#}2W(nv4a?rtm9 zq7+ciYidT4dL-hW?d_Qk_tn)+y$xez<5Vd6sy%e^iZw-*6I;|jeN+ty?NF#i$D@p# z?@JPeZ>fmi8|>-VTaZjFZWvQlRXwZI+MZE*i`l~2IqU29`whfA^P_3DlYOtABqt>s zo!yulVvrl6H<%C%`0Z@@FRx5>G@dU$3bED=UADa$4VzvvcV?jfIh+ ziiPEB;Y|IM2iE#dgHAFdCyaM2J1+jC%l^kN@6qLmGQNc_3W|H^;4} z*%XQt4+?a{%>TH|w7H$H|5pX-UvHkvsq1zrLIZgo59MYKrf`VimovWz(Wo7*FJ({{T?<`{jQatcu|KU3R@lIvr#%5-I@ie}aEgtLa z4?p(x-Kw?a;a5}}A2(CAJa4(_G{5=vcmq)(`ApyTYmWc&#{K@(R9oT(7}Y#kHVb~A zpP#D_7=yD`sUugGQQXr#&ykdFXILOD^{fp;^EdxE0p_3Z@(`zWXF+dM>NGP=1XTt9 z0bc2UctFC@r9mdHOxF@s#tt&*^(TtS$^B$4bn-0x=1VE@&tLTjCv#h` zt{=ooM^IHR6bC1Zt(cMy64}^zKO*>lDu3WCr?;Bld^Iya|MYHXRy|yx&xESE9j8F# z=SNfP&Dtt3LxM|3v`t^V`%jDOSP9R#xIHyZ-N62^Ej2AIOBg+ zJ8Z$)8&B8zk&ze$c6}n#R2xYhwR>UlAgI>$K1_sHXCOgxW_pt#`~`3#xJx ztQ-GV)G6+|rG1+hGL*z2aKoKxz2BO*i&qzFg8jEZ2H0jVy7Sfx5>zQnnmWK5Z!uD# zd0?(s#O`nLNbL?zl(v|K1ye5j^RT;`B&Syag@OQl>LM@&W4(1e7nm!@a>8%-8T-uxZ}b zN#C~VLZp#APeeQ}5NO=y6t-1^EWIwk&=>lcOGa7DA)*YdSbJ87lA5DHX-5cHe|jC+ zZc2um19}<`xEQVrQzb2wz{$%C*!R#7ynl_HoMi~iSx0w7O(h~m&~v>;AaJO_r6!ux zvL0m4QP9ZcNp)^^ Result> {