From 66291a0efe01e4b95fb1bc7c35a23b0bf6437c18 Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Sat, 23 Nov 2019 19:12:58 +0100 Subject: [PATCH] C generation --- .DS_Store | Bin 0 -> 6148 bytes c/calcwit.cpp | 155 ++++++ c/calcwit.h | 61 +++ c/circom.h | 56 +++ c/main.cpp | 196 ++++++++ c/mainjson | Bin 0 -> 584640 bytes c/mainjson.cpp | 47 ++ c/utils.cpp | 25 + c/utils.h | 10 + cli.js | 51 +- doc/lc_example.monopic | Bin 0 -> 1301 bytes doc/r1cs_bin_format.md | 489 +++++++++++++++++++ doc/r1cs_bin_format.monopic | Bin 0 -> 28845 bytes doc/r1cs_example.monopic | Bin 0 -> 5950 bytes index.js | 3 +- package-lock.json | 51 +- package.json | 3 + src/buildwasm.js | 52 ++ src/c_build.js | 377 +++++++++++++++ src/c_gen.js | 941 ++++++++++++++++++++++++++++++++++++ src/c_tester.js | 119 +++++ src/compiler.js | 300 ++++++++---- src/ctx.js | 171 +++++++ src/exec.js | 227 ++++++--- src/gencode.js | 32 +- src/lcalgebra.js | 41 +- src/utils.js | 55 +++ test/circuits/in.bin | 1 + test/circuits/in.json | 1 + test/circuits/inout.circom | 50 +- test/inout.js | 20 + 31 files changed, 3295 insertions(+), 239 deletions(-) create mode 100644 .DS_Store create mode 100644 c/calcwit.cpp create mode 100644 c/calcwit.h create mode 100644 c/circom.h create mode 100644 c/main.cpp create mode 100644 c/mainjson create mode 100644 c/mainjson.cpp create mode 100644 c/utils.cpp create mode 100644 c/utils.h create mode 100644 doc/lc_example.monopic create mode 100644 doc/r1cs_bin_format.md create mode 100644 doc/r1cs_bin_format.monopic create mode 100644 doc/r1cs_example.monopic create mode 100644 src/buildwasm.js create mode 100644 src/c_build.js create mode 100644 src/c_gen.js create mode 100644 src/c_tester.js create mode 100644 src/ctx.js create mode 100644 src/utils.js create mode 100644 test/circuits/in.bin create mode 100644 test/circuits/in.json create mode 100644 test/inout.js diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..35ef5ca06f3382f223579796404aafd6e64d3f02 GIT binary patch literal 6148 zcmeH~Jr2S!425lAKw|00n1usyg9yP1xB#LR6H*7no}=^pvrw2(g`Oq*i=A3+-_X<| zqKD_O7wJS~4L8cp!o(E$QU)2NzYUN6I*xZMxh;}bfOj(4&uxMVPys4H1*iZOn2`c` zkgqp0dL}*!6`%t1P{6(q1#Ya#7W7XCf{y^;3S~E}eU<==6~LNoK~!KGtzfjOk0Dm~ zcCh4iHQ9pEE}FxK=AG517??)8Xh8zg>R_M(RA8dOGV;#O{}cS%{6A@7N(HFEpDCcL z?q#C-LPM50oG&-q5|WOfXl!@1%9f)3mG;M AWB>pF literal 0 HcmV?d00001 diff --git a/c/calcwit.cpp b/c/calcwit.cpp new file mode 100644 index 0000000..d1b454f --- /dev/null +++ b/c/calcwit.cpp @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include +#include +#include "calcwit.h" +#include "utils.h" + +Circom_CalcWit::Circom_CalcWit(Circom_Circuit *aCircuit) { + circuit = aCircuit; + +#ifdef SANITY_CHECK + signalAssigned = new bool[circuit->NSignals]; + signalAssigned[0] = true; +#endif + + inputSignalsToTrigger = new int[circuit->NComponents]; + signalValues = new BigInt[circuit->NSignals]; + + // Set one signal + mpz_init_set_ui(signalValues[0], 1); + + // Initialize remaining signals + for (int i=1; iNSignals; i++) mpz_init2(signalValues[i], 256); + + reset(); + +} + +void Circom_CalcWit::reset() { + +#ifdef SANITY_CHECK + for (int i=1; iNComponents; i++) signalAssigned[i] = false; +#endif + + for (int i=0; iNComponents; i++) { + inputSignalsToTrigger[i] = circuit->components[i].inputSignals; + if (inputSignalsToTrigger[i] == 0) triggerComponent(i); + } +} + + +Circom_CalcWit::~Circom_CalcWit() { +#ifdef SANITY_CHECK + delete signalAssigned; +#endif + + for (int i=0; iNSignals; i++) mpz_clear(signalValues[i]); + + delete[] signalValues; + delete inputSignalsToTrigger; + +} + +int Circom_CalcWit::getSubComponentOffset(int cIdx, u64 hash) { + int hIdx; + for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { + if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); + } + int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; + if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) { + throw std::runtime_error("invalid type"); + } + return circuit->components[cIdx].entries[entryPos].offset; +} + + +Circom_Sizes Circom_CalcWit::getSubComponentSizes(int cIdx, u64 hash) { + int hIdx; + for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { + if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); + } + int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; + if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) { + throw std::runtime_error("invalid type"); + } + return circuit->components[cIdx].entries[entryPos].sizes; +} + +int Circom_CalcWit::getSignalOffset(int cIdx, u64 hash) { + int hIdx; + for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { + if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); + } + int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; + if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) { + throw std::runtime_error("invalid type"); + } + return circuit->components[cIdx].entries[entryPos].offset; +} + +Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) { + int hIdx; + for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { + if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); + } + int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; + if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) { + throw std::runtime_error("invalid type"); + } + return circuit->components[cIdx].entries[entryPos].sizes; +} + +PBigInt Circom_CalcWit::allocBigInts(Circom_Sizes sizes) { + PBigInt res = new BigInt[sizes[0]]; + for (int i=0; imapIsInput, sIdx) ) { + inputSignalsToTrigger[cIdx]--; + if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx); + } + +} + +void Circom_CalcWit::checkConstraint(PBigInt value1, PBigInt value2, char const *err) { +#ifdef SANITY_CHECK + if (mpz_cmp(*value1, *value2) != 0) { + char *pcV1 = mpz_get_str(0, 10, *value1); + char *pcV2 = mpz_get_str(0, 10, *value1); + std::string sV1 = std::string(pcV1); + std::string sV2 = std::string(pcV2); + free(pcV1); + free(pcV2); + throw std::runtime_error(std::string("Constraint does not match,") + err + ". " + sV1 + " != " + sV2 ); + } +#endif +} + + +void Circom_CalcWit::triggerComponent(int newCIdx) { + int oldCIdx = cIdx; + cIdx = newCIdx; + (*(circuit->components[newCIdx].fn))(this); + cIdx = oldCIdx; +} + diff --git a/c/calcwit.h b/c/calcwit.h new file mode 100644 index 0000000..259fe4d --- /dev/null +++ b/c/calcwit.h @@ -0,0 +1,61 @@ +#ifndef CIRCOM_CALCWIT_H +#define CIRCOM_CALCWIT_H + +#include "circom.h" + +class Circom_CalcWit { + +#ifdef SANITY_CHECK + bool *signalAssigned; +#endif + + // componentStatus -> For each component + // >0 Signals required to trigger + // == 0 Component triggered + int *inputSignalsToTrigger; + + BigInt *signalValues; + + Circom_Circuit *circuit; + + + + void triggerComponent(int newCIdx); + void calculateWitness(void *input, void *output); + + +public: + int cIdx; +// Functions called by the circuit + Circom_CalcWit(Circom_Circuit *aCircuit); + ~Circom_CalcWit(); + + int getSubComponentOffset(int cIdx, u64 hash); + Circom_Sizes getSubComponentSizes(int cIdx, u64 hash); + int getSignalOffset(int cIdx, u64 hash); + Circom_Sizes getSignalSizes(int cIdx, u64 hash); + + PBigInt allocBigInts(Circom_Sizes sizes); + void freeBigInts(PBigInt bi, Circom_Sizes sizes); + + void getSignal(int cIdx, int sIdx, PBigInt value); + void setSignal(int cIdx, int sIdx, PBigInt value); + + void checkConstraint(PBigInt value1, PBigInt value2, char const *err); + + +// Public functions + inline void setInput(int idx, PBigInt val) { + setSignal(0, circuit->wit2sig[idx], val); + } + inline void getWitness(int idx, PBigInt val) { + mpz_set(*val, signalValues[circuit->wit2sig[idx]]); + } + + void reset(); + +}; + + + +#endif // CIRCOM_CALCWIT_H diff --git a/c/circom.h b/c/circom.h new file mode 100644 index 0000000..d81400d --- /dev/null +++ b/c/circom.h @@ -0,0 +1,56 @@ +#ifndef __CIRCOM_H +#define __CIRCOM_H + +#include +#include + +class Circom_CalcWit; +typedef unsigned long long u64; +typedef uint32_t u32; +typedef uint8_t u8; +typedef mpz_t BigInt; +typedef BigInt *PBigInt; + +typedef int Circom_Size; +typedef Circom_Size *Circom_Sizes; + +struct Circom_HashEntry { + u64 hash; + int pos; +}; +typedef Circom_HashEntry *Circom_HashTable; + +typedef enum { _typeSignal, _typeComponent} Circom_EntryType; + +struct Circom_ComponentEntry { + int offset; + Circom_Sizes sizes; + Circom_EntryType type; +}; +typedef Circom_ComponentEntry *Circom_ComponentEntries; + +typedef void (*Circom_ComponentFunction)(Circom_CalcWit *ctx); + +struct Circom_Component { + Circom_HashTable hashTable; + Circom_ComponentEntries entries; + Circom_ComponentFunction fn; + int inputSignals; +}; + +class Circom_Circuit { +public: + int NSignals; + int NComponents; + int NInputs; + int NOutputs; + int NVars; + int *wit2sig; + Circom_Component *components; + u32 *mapIsInput; +}; + +#define BITMAP_ISSET(m, b) (m[b>>5] & (1 << (b&0x1F))) +extern struct Circom_Circuit _circuit; + +#endif diff --git a/c/main.cpp b/c/main.cpp new file mode 100644 index 0000000..9abc482 --- /dev/null +++ b/c/main.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using json = nlohmann::json; + +#include "calcwit.h" +#include "circom.h" +#include "utils.h" + +#define handle_error(msg) \ + do { perror(msg); exit(EXIT_FAILURE); } while (0) + +void loadBin(Circom_CalcWit *ctx, std::string filename) { + int fd; + struct stat sb; + + // map input + fd = open(filename.c_str(), O_RDONLY); + if (fd == -1) + handle_error("open"); + + if (fstat(fd, &sb) == -1) /* To obtain file size */ + handle_error("fstat"); + + + u8 *in; + + in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (in == MAP_FAILED) + handle_error("mmap"); + + close(fd); + + BigInt v; + mpz_init2(v, 256); + u8 *p = in; + for (int i=0; i<_circuit.NInputs; i++) { + int len = *(u8 *)p; + p++; + mpz_import(v,len , -1 , 1, 0, 0, p); + p+=len; + ctx->setSignal(0, _circuit.wit2sig[1 + _circuit.NOutputs + i], &v); + } +} + + +typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val); + +void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) { + if (!jarr.is_array()) { + assert((sizes[0] == 1)&&(sizes[1] == 0)); + f(ctx, o, jarr); + } else { + int n = sizes[0] / sizes[1]; + for (int i=0; i(); + } else if (val.is_number()) { + + double vd = val.get(); + std::stringstream stream; + stream << std::fixed << std::setprecision(0) << vd; + s = stream.str(); + } else { + handle_error("Invalid JSON type"); + } + + mpz_set_str (v, s.c_str(), 10); + + ctx->setSignal(0, o, &v); +} + + +void loadJson(Circom_CalcWit *ctx, std::string filename) { + std::ifstream inStream(filename); + json j; + inStream >> j; + + for (json::iterator it = j.begin(); it != j.end(); ++it) { +// std::cout << it.key() << " => " << it.value() << '\n'; + u64 h = fnv1a(it.key()); + int o = ctx->getSignalOffset(0, h); + Circom_Sizes sizes = ctx->getSignalSizes(0, h); + iterateArr(ctx, o, sizes, it.value(), itFunc); + } + +} + + +void writeOutBin(Circom_CalcWit *ctx, std::string filename) { + FILE *write_ptr; + + write_ptr = fopen(filename.c_str(),"wb"); + + BigInt v; + mpz_init2(v, 256); + + u8 buffOut[256]; + for (int i=0;i<_circuit.NVars;i++) { + size_t size=256; + ctx->getWitness(i, &v); + mpz_export(buffOut+1, &size, -1, 1, -1, 0, v); + *buffOut = (u8)size; + fwrite(buffOut, size+1, 1, write_ptr); + } + fclose(write_ptr); + +} + + +void writeOutJson(Circom_CalcWit *ctx, std::string filename) { + + std::ofstream outFile; + outFile.open (filename); + + outFile << "[\n"; + + BigInt v; + mpz_init2(v, 256); + + char pcV[256]; + + for (int i=0;i<_circuit.NVars;i++) { + ctx->getWitness(i, &v); + mpz_get_str(pcV, 10, v); + std::string sV = std::string(pcV); + outFile << (i ? "," : " ") << "\"" << sV << "\"\n"; + } + + outFile << "]\n"; + outFile.close(); +} + +bool hasEnding (std::string const &fullString, std::string const &ending) { + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } else { + return false; + } +} + +int main(int argc, char *argv[]) { + if (argc!=3) { + std::string cl = argv[0]; + std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1); + std::cout << "Usage: " << base_filename << " > >\n"; + } else { + + // open output + Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit); + + std::string infilename = argv[1]; + + if (hasEnding(infilename, std::string(".bin"))) { + loadBin(ctx, infilename); + } else if (hasEnding(infilename, std::string(".json"))) { + loadJson(ctx, infilename); + } else { + handle_error("Invalid input extension (.bin / .json)"); + } + + + std::string outfilename = argv[2]; + + if (hasEnding(outfilename, std::string(".bin"))) { + writeOutBin(ctx, outfilename); + } else if (hasEnding(outfilename, std::string(".json"))) { + writeOutJson(ctx, outfilename); + } else { + handle_error("Invalid output extension (.bin / .json)"); + } + + delete ctx; + exit(EXIT_SUCCESS); + } +} diff --git a/c/mainjson b/c/mainjson new file mode 100644 index 0000000000000000000000000000000000000000..3809f76d371668c01064f7db079c5e42aec9d869 GIT binary patch literal 584640 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 y7x*jL`UAOwh_<{oB#3W69$RK+6#;Dm z$3)tlwfW)^0{rrwp9nqBFPkoLNczL}0l1@3^FNz@(_X*NVzter48yh>da~<(3jThv z??+%85|$SyURwTWs@v2=JwmYT0Z($|5B^`FnJ-~;Gs|VX;dt?V2!y3Our`=odAKNbjt=80Mxk|t!{$d1!msnswDGmu=?jq z0Y7N-Wd0Q|K!{V{7R)e$+R5eS{KbA2c;LOf89GnQgg4WxY|}8qUW)$%_#t@v4+Jlp z|JlzWdAH&>7e;99qRX*Sfi5T)OAB}S{Y2Tv=eX+k+5D)A5dsXj-}fzJH3RuD`#s|K za{Yl3;PB!+oXz6BebEHA)rk!lz(MW%W>IUbuOK}HxkyB6WByg480Tz#5PD%h5O&U~ zL5Q+jdaP(m)GBC^B^w|I_F#whQ}@GlS9$kSC!k>9{nX2(Mt}RM*Rj;wPrXNKX6~o{ zLdqd#i{wy(%+~vEUf=g@xY zeh5I_?tbcMR0{S}UqKW$yu}W+RRCu1r{1!#pZ!!L5B~lJ{T3PucuU@VC)#Z6f4qB< zo}g(Mx!%s)4@tgDzKnTt4J9xCen=y$nEjBk9jwp2G3se*H?M_4=~?PeKmH2J6cgl{};{piTc9 z*OxOi4(PI<_2mf~uLf4wgiuQGW_B=N7W?%1^AFbN@BWdrQ0P1h?)e`(zFs^GuPN)D z<#qtV2kXTNk{4PpPL>ge+3RP$IG*L7Y`s_}6EA~5&0bY#y=M^~%t8sjWwD2I(lflw zy*7*4`;)ieQx6bZS?mS&e1Q37d+{RTuiUR;`u>Ws-~Fu*&HNSiU%mYnzzAl8eDZC^ z)A1YtNV(?##BbtESf%`#5C#Y{A#Ya$!D4{?`M*fyqrdg7!H?@q`eSzvJ|4e0RKluKdSuF4o*h$UR(~ncK>Wfo&vxp~2ZHE5_bukKCkt zxXy&Gz$3d#Od--UQGp%?D}Eav2s!5Vv1#!^{Suv9#C=r!>_>5ERT1*{2Us7(yJzRz zCreih>u>JV;R~u~Kd(;v1+}rVz3q64J|~OG&`9V=WlAj;{Atiy#h()->3{aRSRTN{KWg8^9iXRc{1`r z`LpR?O$Om03n!`nDI?Ki&n(f6bK;R-gbSvN0{srp4@Q5WDC#tEuIRb7sviI!wH3@j zzy;jR@?Clkc-o};}`K8_o?A7wd0qnqc3Nr3YA<|!{YqIQ= zdx7VVBScJq1h)VJ4lV>p&~h~#j*ATCdVeS$R&9v4(3coS*QPX=AQlk#F7?{4uuu>5 zOL)b#B7LzOTggZbf3bw5Su6$ZDSMggZ>+YSZt{R)d%! z0)<5M|Gp{huTfCgaYJ#>gWmh5Mqe`IgE0HmFO84kk*rHGfU<^xal!i(z>sP{&G2kn z7xnJ~|I~h<^D(hO(65^X3jB@jzE2wFPmh}Uyw4x3z|zmkjO`PS`=D0y?Ux!*XwHvH zfIP+-pZLvVBcvpnIFuZqdphz`eVZ?&4Wc)+RYH`+G|$6tg5dl;l3ori@FW=x9=n7# z@o$hg6<=CZ%nK=Bk1p3&0!h{gFKb`vLb67BSp?@b94$Zl^?GgWbuKG^qE~Xtv5NXy z?5E=Cn;^Elc`tfvk4CJJs_0;o-rVU3?6~ujegl7yraq+qqSGUo{*zAA#Z9l*Y2Hx9 z3xZjn3*t1FQ!K9jw?_`3`W$$7wZkuWKiQ}))>kf(E5nF&8u-~P@~0%f%CzL zy2`78m5t{0Szg9bCS$snu^%#kQxsomSsS}UuLmq|jx+-!!!A33%fju{`F=m;75(Isp1r-Y3HS~iO#i%^ z_Cf16?dM*Im7Vr3Bq^G}O|M$;h9hs{lgX#1J%*fQ<>qKYuBf8^cVCF=>sXyX!?(FM zwwZVI_nG%(lzJHzxIL4(D-)hCX>!L>R5fGO*;w$(bWh4Q2Y#93m65wFrdCQAHkg!FX8vy@Dk4ZefYn1y}6-u zyif|aHJ&P=);QM{Van}LN287YnJz@m;@aR}N>AD*MH6F9E5{lSKLt4A+jD$P$L*LW zpmJe)%Y@(FeulitP}$?042-e7SUYS=3&JW>9|#<`i%*h>NnzP z%|XSm7SF&IXe-+m>!1w+1|5hB?uy369mLVInm&(40W%N0)acsXqf~dp7(tOFrv*v&=BNXdM-v-e_P$N%>%T)>T-hoM5!#MMFsiia>BkAc3km-Sf#UJh zU+uQIIs=jUjK{YVv!tK7s0@HhFi!y>OM-rM>$No1>S2IL&t_#W_k8C5kh$LosF!!}kF11J<#@s)Iaz`+CPv$-vXK$*!kJ=JK%yfSV$nk;v3ocl5U7Aezen=0#YH+vFDk zJ+|J5j%Z`zz2_%aoI-Yb`lW|=If~=GRkSiLOKTJSoAEnKDWc&)J4Vp{TfF*j10eh^ zB`X)hUaI`7%5|RE}(mk2z+(rj=834Wl)PIypCYW0*e>2eF1Ppeybd4Mw``clW zm*x%z=h7aJex1L|^UdSeT(`5IKE|JXHsbWKLV9KzU$ zEOde&SptkR@E|aD8r_vq^)L+sz;nUu(jWZZa{>Q94ai+bi*u<(4ru)arMj<+zof4t#4m>kX(+p)t?Z)g00Do)K`|q(oMSb`}s?Mr%NBt zU;0B`x;cMowJzN?zue8$rPK14mg~|5`Af&?(jVk69jZ&8$X~jd=F=VeLH^Pwb?LbL zMon(!a)(yrFLia>>ine(b?JloOTVd0H{~xqN|zSopR&g2(nIr?ZlhUuhn}6k^aWjd zOa9Wwbm@cnOYhO8o%u^|)}@2RnaG)DFVv-n=Px}$m!6Zq^Z;GDJb&qMUHYs1rD?3f zz>OF3mp-jaha~f=+Jn0E@cgCNeIevI`Ae_SrMKiSJ%goAVgXF6vj{$Dn@XGo8*q$n z^w=Vx!;`7DSSNB&Q{r$t&8&9@>eAqctTO!qcrmgN-wNZJ?#3Trw^V~l0Ti!TAgC0# zI}ND9fkE+2f%K0xsA(Eh13)!-pc(+G$$)CE91yE{1a+1MHAsW12dGsZsCs}}Wk6j! zFsLyEHA;hOTPVD$1E`fSiX^ZOpjH}C2MrABDKtr^*v=h#hXz#xP)QF|4L~IgsF%(h zkieS>s!D^pP(bM`CiJU_8erohjJTzLyW4wa+lYgYc2tmkZ8M&f8WoLB5UAC2!>_{jO!vhFUJ&0zlm+bBa$8-zKvo7NS( zDecb8BD*D?KFp47z>E0NaOm@?z$!e=~4Z}*@(Tl6F=qlI;i>}8{7fkgW1I&*@8{i70 zDjq=~eRMfiW(L_wRbzZ*5xpSE}i#`Atp!=;rRy_4AH*1c;7}nXb??!Julg-?rqXoH&y3iht zPi&N+*2tWk(e1Wb$oCFy3}aqr-v0v3^uN(J1Otm#-TOwA#8VwI+R5mx!c~+BEgsH4 zXJc=>Z8ctw%I4ttbm_^#I4XjJEgkXnNISONuBeIL!h-;hVav(H#Erl>L)eggiGFc6 zx;)>Y9>nhN_UQCb+KqYQIvk!wPv0qe6c4f8C1|5B@QN;{0BbblhtcEeFgtOjV6tCU z33)M6zY3gR$nHcB*+Ld)9v9shvtQqo%c3dt^U0!lsOYgfaWVVP%kfDB=W+Z;dBDAC zWM`KUIPMwd2lw}r0qzed77hp=Zz2o6Vi!=3sLN?An2KQcY-lv`DpHhXY@OmDyG?C= z1dbnet?_eBYeu3>twaMj`EcrEU2s}au@w~&myno)Ues?{KO>v_jH*Mj_3a=9tyn^^ zvNfegZ`TC}#;^+Diy_L)-ySza&Jlff%P*;u%0STj8!X*1P{eMQae0S7l70SAhjcENTnf7 zKgmCA82s@Dbg49qw_v<@z1?JDJ6y1BW*P^+hz0FZ9Trd#lEG2Gb_r|0@N1GB&K}R~ z_a)n9nn9{gf|U_U6Fw@){5kbQZV;+hT_sef@wDbE#h~?7yT_1J&*`;7=fDe%smFg84Uy17_p`eQ=)};(1ed-t(qP1CQrTFaoFJIb+%Gsp$q8 zzS7sOkWqXbPix}E7{$NQ=%9^!1!3k-{Y&Qlg+=0?mYx?=OQ;@q2~(9+ye{QsV-uM z?ET_FrcPuKc^s9|LhyR9tG^pQt@PvJNe}w=@%QOtc=B{>0$vNrh?mmu_evY|*lRfm z=a*m%#@AwivCSP_&WRL=b*Znwj3J?{J}59lH1HDe0Xk3UdJ+|duJk%;AOScPpt>B4 z3nTxqW8RNPycr+`{Y!+IQZ=R{8!yZ*4jwwycjN(Vq-`S#xO?Vw<_%_Nf>XOH4_c(u z7OVw8TgtT1TS*9*s zDb~X$j{DKh)^#B$q4=KA`|9ENZHX5`?8lGR~8ocFmYDqM%{VYfs-gwt9Z!_Qpas=_;q&~uG zS<=q+&>|d=j}XxVsk}aECoPm6Xxq+k?$vC`7hDEQ0bK~bYOY@+Opg(`;28BE>=ON| ziow!(5yblaoa&FA>W}eOA7aun#jziL-pal*_!-EzACFEmRH>As>q5@M@(}PVt3H_4 z0WN@P?JAW;D|az9;(^Kp_BV69vgB`3#`uVRSf%Q)Z>CKqew%SOOkP%B3QSr><9dhg z8|hfR+J;R!*dYAi1~1L6swd-j(=IFqk?)o8eT6nPmjK0B$Li$120W}pgE}@C1Y>6A zlMeR8O=jM$iyqbH6U=18AB@~Y*zwG_8koOM_t~VHrs-E2a>u8C{mtYL?K}0gpYbjM zNhoKiJ>T!3o*~V<7395gj!%awHbUjyr!CJ}uQ=o#pKv^@jDIEI)9S);dm3!2#WWM+ zWla)B8Vq(|A1OZ?KTdZtp6%-PG6*(oJsK;C%J|L*jbXd0U=i0Z-{mlC&mXD+1#Nk^ zz?#wGT?wOwt5yiwhI0qw^Spnf z0ZwS84l=KS+0CXf*Zy9iYh}zg#-9Ms)YBXn;B=pS$9fb42*H0UV~>oMCm zeoKs-)2VKaV`aIW`S?C6=hL*t>x(cGszV145M7_sxhp=bF10Ju&#_;7yTr0akO z!XGspxMbQ(_784T2SpD-Ibd_A$baL{6JTgjtV>=Rhk&Aqs6&^*An;c`{fACtG;t{% zz)syGdV5NK$AO(M2k;DhsiQsp+LyKz6c=xShqW~iz5TW)FZ%N@ng|;IZr1OcTN(b2 zr&Hv|KB)6)_!0IWX^%u-D}WDQ$RCSs21M3i6y=ugO;}!b()`Jd8kP8}Xjk82alE<* zKdmOGMYJ^QbrTFhoB9sZc#%y)_VDU*3tFX&yr!T@?V?Eq@ITRed677~4j<7RUNSt( z9|*XLCd;N-oSikl1@f6SpPKssvgTj@zFh9_@4hQ!(3OJomNWiFUdO6~w5}L=#drW? zU!KRRnK|VpzCF|S9=y%`z0%!R%G3$YwyFisG7Z5MD<$5zcOQ&g^wO&RKhbb)Po(eA z{1%>H!tYD)Fh(Rj>;18CeV>2O3(iM-X?HB+KDf6L`J@Kff@Kfp2#jr;{+;X#nCWSI z4Y+Ci|1f{>`;|VQL-><_{oKb9;;%ZSS9$>N!~WE4pa1laZ{0%FXfR?*T^~GjDOW#q zSp{+}5n6%cZR)I`4*X4Q%cFHiPzTc4rj88iq*P2lU^!&qKroRMD;*3R7(W3&e2+MC#*)+LaE?4_Li;SN)o|%ryt*?I{hsVCQbe4| z=oFSo=4ytn`F6_ITG1pJb<0 zf@N9GM<5T-hYb6Ws~;s9@*?X?%1eAYEZ8wZI@l61ZUC-$B&+yh#f>b4|Ku4jS;P>t zPIV+pLep-CD!S3%4+`Yp`F5fCz2T7k2*$_PKW*35TN-S({mQ_f^CicVB;;QY2Jku0 zU{D8KA8Y>u>O*k`9=z~?J|(vyrj{2)mw!XEs7t*pD+9QZ&S^zf-;hvCw z2C-;c-}QX|^dmGu8C-hv`tTl%xBnC1tN8)Cs+3+Up6i-*gxDFX9qrV802BDf0l#@4 zS+>0i+mlf^zym^A_M{}>FI<$Ag-48kn;JcYoCYiOrWz!nOX>T9W6D`tq%JSj!Q2Ss z#%O>)V1gEv5Y3%x>vf{QmLYAd(>Q}wa=VoPZpuJ z_$P>TMgXfsIwPwgbHnzPi_zXK-F7y=M)PUSV4TjW50CaYY`ZbCC>%No`_+_lo-u%C zWFgI!01Ts=$x|(;tvsBoA5vgTJ60VyocyOq2hO<)?TW`yr$HTjB%mPy>~L1OI{Mub zU8Mo9=S+#-wx9QeUCns9#HoCoCwR{wCg-`=23L05mEGyvgZkwetxwEqeT=mJDO>;4 zZ+%+O`ofIXmu9s-TUyt%b-mx(JA#1V_N8wCBpJ`(kI)@Y;nv_-dwLu8Doki=ce3K% z=xuaM8I0VANKr)e#_p|+-8(7p(!5RB*nAn83lI^7kvS7jYxd^IaKxo636Ayx-xuZj zC$mLY_50ObGH1wp)Y#&DQPx?#gZO&W#^`c6exQMWLgx?h@@2b>`48y)VT^*V*jO9e zn2YSIcvS;p)KDqNzJaGTM-tgzPcn;m>wte+jc0g8WcIijSmCaS1Q%@dJ7X49M zS+e@E+Sp?mTiyCq5+A7*=pZd`R=7idhIdC`*gD{H&g0D<>93k0#=v$$&pEK2=@>>o z>lKsP7zXXX82?Fpc+krERck#LhbR4a$SW8AGxr13X^m|IPk1i3O_fh1(YUjpgW zK>U#>1}wM6wt7{!sy)J0z4t>gKNw4RSCtr-4F9zl#sGF7A6ON2P#QMRTrPXAOdgzV zQ1T#30?Z$Ruce?Vg6=@rs$xnfy z=PSy$dKaAJL}1yAyuA@qzsS(1o@O0+Wu#5tpCPtA+n?9`2*YoAqo6F=gO^p64G6Ur z@8;Wn@%^cwzfl~etob9?-|*|>x@gsoD-CoLPkzkU^ymKu<#Jg-%jQ8=ft*2j`1s{B zGcM!x{Xf6FAOAWi&kx`1NBC=I&NUd17z7coKgYT}k%{%bA1#V?AuGcZ>QuuPXU%s3 zKWsC<_Hcf+52rR_)#n{rF*E~$*`v<9*5{eO+vL+1mZyB z%gggUc11U^kRpLc42}l|dGsAFBV-TP7aeU-HT%`7gySqeS>Qh&sw9to6~M1oA0w8^ zpVDXKu9wsmWf{LMY5b#{`vtU`$OQq>N88nzXy(Dq<=3+ABE0EAw0#$k8+>+SFLu?` zb>%cS8?^=7ik}OKCeD|)jS?(&tdc(5>K;#z#;=R?Aj5XM@i%(wQp}TZ9PWi(#hU{x z2?f2tdunUt461%N0UlD~EfmWL)JifdpqP6Iw8aSag>j0c_XbQEm=qj}^aSalS#TYF zFrq~ge>2b=Nyd9eMH9!Pp_sH`(&6i-N^OG4tPXk18t!oQp6K-=Ox-vJXFu_!B}4RU z@fmN%uNKqEHGtHD&`!48ih8`U)rm&p2xHCWcHlu>157QaS<*)^Z7151?}=fkeRYz1 z0H>l#ZdtR0A)t61A-JUvozJi4v1II#-!{T811e4p5p#{>R7Sl`7-cGDC?Hx(Rdw0qs zQ;+47DL2AFw43Vz!56EQcu-%(hyqzjcWNT)OgCXt-DbsOG>Fa?)XF1StGwbT3B)a( zhu4C@;HAh_ol64Aszb&adc=?n78=RA@<0RCZB8NINS1(gT{csX?(f%GA=tPss{(zY z%V{L$>ih#JT(=n_Y9(oei}jU)eE@C(a}MeE@SLU71g*-DHuCjXIJdskq(6y#Nq5(U zx=RapG+SQQY3c46GPMrYCuaPx!vtp6Ef;H4N zmx6vsJ_dKpmAW`Wz-}XJsaxty-!RC?U;AGq$6diXs%2l(v%5mDfn8=>T)QXyY9!|B z!u>e#a}5!-k~E^v`ll91*9K(&Cb86(}HJAr`e5~g0xYCO_=2ZHJA@Vf~S)* zo(49$g2)C8pF!l$WWI+;yG{!tkL$D`(m>uW1O}E8z-q*&y}I`9l* zT4vY*X0ZwzvmBO(Md~6{OD3k9TD6kQlC13c{SQ$L=rUej~+zx~j34t$v6AQh6zD~d#8-QVQJ7D_YoTVE*FqteZL2FKLJ3+9( zKKQ)))knp%QmWPZ@wt?CJ%$zeCYImOcf%o-~R#4Y{$H)Y%yQ={&` zA{e(-$XG-BgQ1gv8_yM=8VpNwC+e7?6R@t!W-75)Fm!^A>#{1)7rNk$lcGbu#-VF7 zM8F$I(hMEztKZTUb(;m|LC_DR1<$>7nxIt_X)|;WB1rtx4V`png}Q4J?&$7T>$G%N zPo~aAKi-wP8-WzI{wgjEo#=a38$Va6mw|hry3{&*G7|QRCeVrDYcP~!_?Sjkjc_U9 zRY>y5ZDyw0DcnJm#1m#~`uz%RIYbyf&AuFI-GU+8igiMjd!wcutOBH(5tY4nEm)y;IO-DZLLuAr;& zd|jsrT5Uqw2xt`!nm(Q0NOwh{?rK8aEeUnE0O|BW=*LLpsIQ2#Z>WH?kEF=$H8NRi zx&1q6#j86(Ehgi=`8GB3FF@Nl1n|Pq%(tft@SyHO|G-7kXEO~i+;o#E7YzcURV_xX zJaVzfE4B#4E&cN;{Ay_YK zuyI{h1^Pl4?yx3BFQOK_a6<&Va3qafu)eyCeyrOpFgFRh8qcS7nxNG>q>Wr$059>= z$%S;+3qR3xw;E057D z@rutN5V!OMp`bZJ3ApIOKqAK?V~w0dxGoEgL~h;HK!szDd?S$p7F!I2Q?`p=XN6#c zb%B7;bUBU0T)lx>$wVLGSOv>kNg9b{eRVDRhlmKw*92XS=kq#E(CR6qjYKYhTYqUyURk|orkoX*NRvyn}A>QHNVTSYy*!ta41TFxeO&1j+s?WlyT$Vhvzd2 zpVRO;4&fh<;6q35!ngbS?!Za?H8{6<7Dq(k&sPy}6gqF3C+CgkJj{!iY%QNtuyt7- z=q`vZzfm@`VqMmJgbH7t+9&bWH!Z|Hwxp*csEXc*662 zf3kbx@5lkPU4?r_N63!S&`AP1bkFFz@#s@chk4S+N{EO-Ox3GfNp3%fS_UXi~4}24%WIdJaqRg9Cp?HQmGN zj0O$rue!mzQgck5Zh+rf^Bdfd(O{K&SvP3a4KC9SR;g=Q&7F46iTo-(sFYu$yN-s! zUjZLVO+YcDF!XC^I0l=?V7SN&*b$qGjr1$=8Hvw5_~`h29EEW}W?#$JKN;Li!;(tW$4 zPR;x|RXSFuPd&XLn_YV`d?v`IR6nF3&iJwQs+2kt8NU5{6Qjuzbv1G)K3Q9otXvme zTeWV=d(qn%RS{hqTNm%$Cwd!Yvo+SkH-{CHXvDBK4rWrF&MxqCaCoRum3W9gTComW zosk%rxwSmW0D&6Jo->juRR;5|-vrk-jR78lulz`It2&Ud^sC!aA$>SH6JsF1gv_7w zytfFtdnK}oC_vY%Wy~Q~!5<-Nga(GSL0|e~3?bNuA6b3{$C4vZS(=`Xrj|4Gp|kmg z|KRl$+-W&h%E9Di8|smSHDEB(4WnoT)akID(NQw~%eo^}DZAIM`WV4vI2Gl)E~Ovg zr4+0_=AdKD0^{WiOQJ-vq~u^tJ$@dJL@PhGT=_j}*yXV(R9i;-Hh0XE0tI|^ownQUVH$4 zk3-87&5B)#P(H{Lgt9fZ8B!+aV-TX)9fE?b0I&5Pfg)** zbQ^W+6|A8S^IN-PR!tK^e8p_}mftb-&m-n;PC#~IrB95D!|T^I#v(17bXuT4t<&sK zt#{Vbi9?#pyqx}St}`uhRn zouwtJrcjvP3%bbkf1KshUV7zpDJmjI-4(2%zIBSP){TkU~mi`Dv( zK6Ldc(&FrUYND%2bk)MiXj z*qZj$;#aKdXmww`rIwPNV&(C0AK`LF;;-0oI~_k9gGODf43|$mC*_QTl2#1S;&0Mu z|4GLd)=bB{|G^7XH6T9c{STE7f5c}c5q`wz#Ht=HI^G2a5~l9OGj*ulsfRlB*=LUL zj}IKr^b2g@esS?kGcjVHUp&*ap>(VUjAy!IFgyG|9?$e+U<&c=!0DQr%k;qUOgEv5 zHW3*+G8T;t?9Um5;Fi8}48L@!&_$;QMx_MR%%3+lgn2 zgCdMbgEfu`FcTPShDRVLf>W zqr>d{c&7b*8OSJJ#hCz-^&vUome$D{Q3vi6&JHAtQqUxyB{$5I2r@l5Z19Ekp8X_POX>0Q(sIG(8*I6xNJ zFMgZMM^P=)X~DBfr`e6V9BHElpKCnRma+hmAt6M1p}jy*5b4%wL8J@mPZ-ZcZeUCq zv}Dw0HqzPgOg;Z3(>_}~)AIu3v&1tc1;S^JXQ~h|pL;yhvHt=qgLtMVKO)OM_jsn` zfIJ3lY-qs3@l01pub+E7)1?%XAfD-i4@uh>AJ6m*iS^={ZqtOTUSCqf=B3^^pERE7D_|MM ztpj7FHbGV(u@CKUqA}B~$Ys;qGxTrLMG6B3?%Cg(n@)#8DQ>2_NAu0uagkH1SNYf^z6h9rfm3 zrnei<^cZU8(HjXog11#iAa3dP6GU$$p6T8b0=;1nQNDPlqrgT_C;E+Ns{X*QGeA7k zGSnJ4p6MYRa6(szirQzJ=#AjHn@&qS({QAX-h9S*rm|3X4Z84*1HDX2F$ zP+s0e+Q`KPpDmtge5kvXx(n&qArQB8HQuqn z&`F%o{?h{yYeF@%$H79g$I%218PlVXZ@eu5>%}t-de^VBLa@mj&om6R299T%!~h#F z!04xfuEukvP7}2HF49KCK4U!7?^V!UX{fsiq3-rZIwPJb1u8yeJX7D>WWcA4XPSf4 zk$mw?BgV;OXi2cc=$-MT^H%O_;euJWn22E;L-C(h9@HO3_Ne%ZKyuy+4QEE`T=mz`g z22UJC%y6XsJgRAws3SpxRjNog_)uz&`ET7|mHHX0xzoP8uW0+Z3}tag?}q428ha7%tyaCrc<9Suvvr{ah{@S}7k(=@JpmAcr(MHOps`*h z_v9Rk)7o_hN}|D|4^bxnV&}XfX?LLxH$aWvOcl+(eT}%=HJLFPxLetp(i%-502U97DYI~A3V%Qt;a-1I7i$xOA!=1~U@J4L zpek-Rt=$Ecla(8l{EDF+>%w@dvf8SRWi@Z`?cc7l=%ZWJNCutbZbu+l=HE{l&^Prf z`S1_QN8!GmT>3)g#6O4rVk5u!R%)idKf$ZH+Ry@R+R7*iXqzfRxLc2;U7T-YHXf%Y7~q2-{2M^3@k_-CggBPvd+Z4^ZtSP2m6q9A5SJfx6KID zCLcfBVhEuC5iV~jYg3GmGKv&p=Pri@_tR^9K0kg|!uA<{o+D|^PlT~kT5|aLN%;}f ze?azBCabuwhq>dwteb(AnJP(J$Xl@)YEh?t2J?)OTS=At&XcU{RM)9{36r6Fw!ZY^ zA$jISYrIM_DUp~@OaG8tL|>}Al`&avtU=eRgRiy}(A6!}Xg5|LWG`a&4<#GdTsn=c zhTs2_>^T7>7z!dY3ptXQ0)^JY>Ef3Y4*3|eK!p*D*lt&B0LGnacV>?uA>ed>|>Nk6;n1vuP0M1vI`&0u~j2EGdY;e+3N=))}5s#-KW zkWtC@7!iDDsh`k`d!*33mw_z21+aH(Y#Yoje_MVJjVGYe!WLPhMq2hr@0NO4E-}&X z0mmY1981WUObmnjiy0u(vUyn6oxz6RMMQvo%l*oDUCgtgIpzJ|N1Sn=Y$m*eIKhZb z&V(1%Z~0YKsT1aKW;{^1{x~0IzWOCXkFl@fXwaBaj=IzxuTxkcTU0KQNnX8puH+(M z=>=+lzU{0_9jX-(1JtH?u_4-ZS-1|j?L<9Wh}{NQ{3geHx)|D60%A)-_o;^Toh+t^ z5WY(rL`|m6ufc|{=w&TzwTPfrKy|%-?t(~msJ;2XpZOeoJYe9XFHt@~%L!tvRDp$` zkH&1Aw486E_)R>&In0{U5nX<~u9U>@#}t-DxrYo;G1M!x+Tc_`iT4U+$pEu%KUG=(^~>_e1DMZw7hkYw(ARzW+MK?_ z56b36wqe-Mk$l*&BJq=Gm+&hSgY`oPTOMO-{2NvdTErUd>OK9?&Kj4nM!)tWcYXzZ zS|9t@HmTrg^*Lqt==*yibx*KQv{4^1(E`2JGar6|0s75f2)b3A7ZG6m1cQFSG&WMU zRQxFmu1zoiS@#EG*9E`lfZLke09`H!^zCil`_7~O+N0m~iOe4}{dz|JG(TYc6wY9L zkIV2cw0@EHXX`qU1!=Et#WT%mW_`^sy!PeIEkQZQzX?3&zkTx1AL{Q@>6f{?KXd#< z=eXq2@(D}GdxjAe1CvmhaUc522pCcCAHo7yx0bHKP#0N;stU|ET1qng`yH?c8S+<# z$p!sWWO?B@zWDPutx6mpti)j7+Ep=Gr+*cqOP!&|EX%|3Z!+S9Jq zU@F1<0%p3fK~KB{=a%mxpjrymlIk?w22&DT=;QT6y#Oc;0Hpl6s2%_iBPedJnUaF| zXAUPm7)JVS@{1;Ot)`Lx8H*);lu@1y%|0Mxb5kAAdgz!Fdmq1 zz&hD+(5{Zw56@nq5FPRNNzf;LHtgS4%fAPsJ51-*y>J>Zlm-80sZOKZri~Ao*UJoql|7+4cp&;h88)z83B zq|Cqzk8SJG5qf&wdhU%G05StqAHuNm53T3kwDx@-NOjQR#ej_CuSsCXi1)n5--m!; zz2qEcjoZ_*_e3TNjL3xj3TC5I$kzl&55-KfP!m50KUmy(vKo+TqTjm$3`RF-17iUmTZ3V- z3pC3Qp{9dzDPi1m3N4yY7if4~Y6AEMfNjdhB@_f)>hUN}qdW8mDWLZ8{1*W0;J4Kv zKP+-uewTGOus&U~X3-|fj{f<0+`T5lnP9lJ+F3$MxRk2y#jg@97{XrUm*=${m0dI32F~PaI1RNS<;ZaQ9ulzie4>B&>sQUk2G!3(gYR-($wkmsS|wa zDEInbLA+-iay*1G_6M*5ZK|3ekbjuLQLKVDTg?~i8q~7b_^^WlNkh2QyXR*qDuFJytGq9cI z3_od9Gpb? zIItDCGJ)KH#j92r(7C|X2qhSnDU@I|R^0I(a7&nrpQ*6Md71}Ig(mDwmfO9v2FFsf z(E2$w%Ne9eLR)3G+1I0E8DOqjw{PhjVbFX1k>nU($(eLu*)(`-P zui35?eTs7#9iX+dW$%pqmCp5rHq5L$2fVXj>K*-d*mG|PVkIYGsRt_f3JiW~1HW{} z>~T7~YNb=XnsW9|s4hicl|fdFpayiLr4OwbC&RiLK0>K7`B?8$P^7J3Jt(Yms#e?Y zBT)mv?1f;~sEJ~tBj_wSuwbs%f|(2pCORS4XjMJIL`I!aD=-z=qbRS)PU`Gd&Wc=Y zw!8+(DY9&!mr)jfZMxVO3V0=O!fZEz_8dGBb8y=K$KIR3S6N*D!$Cztk>0pdwHlWq zZf#s5C?dgf<+?;s8c}hfbzfSk8f&#^Fp1`JjZziCsx_@v^V6!RMI#CZq)8N)C@OKO zUYF`bsitZ%Zsh%b&zX6)``nO#{r&%+_kCN#edc*)&YU@O=A1KU&ddb3C$7~=AQa0z zv(Qy_;1>495X({B!Yv}mtTa>6l$lRPF*|+1Q7cjjVvXV}Fkg4)KZpDcWSu(fx$7Nv*Q28{ZqI2i!C)k(Az&%?CdpMh5$JZ^eVeD6)O=Z?phJFFRlF{d1-=h z0(&5`r;iEQ3f_8Agg#~tp^6AZTQP^By)OHz0St;UIBLQ{V*QBL{{(b48WV< z753n%R75SX!gAnQ-ysy0Z(jxbC)!_<29c^;$EK=3Xtr~qD%9%iU*bm%kk$UAjh3ap zqoAzcr=_g!OF43kvX};S8uuLv&QQ&s*Dq)f`t9}R3up-EvvxjH9Gvgi{=w)bFG**r zya7t*hq_4H>&{k-**#db)R7&HHSQ3|{d{2hVF?=306kAbS3ii86i^UYFkAC8GjH{#GJZ*~z%e zWe+CACIdfscRO{k&QC31DG~a4bG*3wqg6s;H2e>37Y^*|Rt^sgcsQ&7#&r^V z!R-j(tBP`wWTnuGyFhx{#@>3T-yZ3w$~D~&#rzmC)P)p0Seq32*o!_z+XDRJw|7nQ z;+!30<;CBMLh_;y{YzOwm!3Dc{Qhz0wJ;0CHq{)17^Y%Ej`ib0G`3D8C9JUBFy-0v zMVN4zWL0V)BMv}`?bCN$hi=pYs-gfF850S~AV0SvF0MVk}6{gi&*oP-6WRP`v#(0>XDj0%CN z)zwp1e>pnZT|pt;to537K) zy#vec#TRRFcY-Yf*m(maLIx&d15&bxIoBNjcP?V$|Jzyr%Z!y-e3c<8Dg;`XOd%(K zP&Kq}=DOt#=F7-gCde}tl%7a3$;^g*kwOYCV4QxkgiASIPC#o-&&INQkGX`vFdND& zWai9#zEpl`0>5xG!EXYUCC1fvZAHW3RIsFPmCQulb13hmJ#P!Di?w zGYehf&``oOV~pVbMes-*oNo~Jk1)c670yveE!doJQn_#hpKYNOeF6yR!vNZUCAr!# zsz}FO$d6%ieGBM1z&6VLnB_-|p_9P3-lmTC0-YgT(Q29`Ux{#I@snslxQ?5=&vVV! zOV~j1Jj^vSgK)*>CO=<-x1`ZhaHUr(r&bZL2RX1hFRF*rC_R4!I+dJJ3cqR!Css0v zGYI)pugjCQz#wqv6>ChPCNM-Xa&?yRA5<0?DOsdsq-0GA3M0756RB1|I)8CMo>EQd z`sh3~1~Lslm5qo*g7(6hJX6@5WTTFma{NLRQg|ijngy8IrI(Crf{O@wrq4~kGCsWo z02)jq@T^PD5%gvz=TP##g%2!E?tTjp%oVMcR{ubjGN_4#Rop_|}ciTBQs_B5mWKY!-5(WBB2p_yA(Hn`@fG zJtX#$KR-%EbfVfz{n3Y8uR{0aXu}1N6(GxEvjGH5tV--e=RqZ|7gmYC22pxfiTChe z%z#QfOjcsoMkQ{{k{Hfuj=_Ga#N{$X)}RviMJDa``qC=dV#9$BmAEr_Sw7^b#G9V5 zMXXBv$KdsV+vbc1I(iM-JOIe!gZ+dg4 z^6>>&l`k+)fGZ@LhLJRh+A|$kH#)N%o$q`?miJ(py$C3soaYASJk@zw^CT{@=ODqy zM)UZ;FrKz_)a*!?za-=5FMPcnRDdhZHV{RV0oTN-s)uFYOzF+<5%|y}uzh7g3KH4e z3X%tb6cfnlV1PIvzg8f}D3G5c&VRun1afQyh+wkkPdw@h(4PaS5(r0|I=V~F6&N#A z9pfVJ6R?Rm0%m~gJk_#IB-4kYK#}j_LbK=sUlB;qEV`+~?E1LK7~h_@@&!BFCtMu1 zxSju{2F(p9rL9bpXm7E6t0GssAMYBWRez?1KgEj|Bt(0t}ujqsh7kt8S3 z=Kxz*w8Oj#%7N+Xybu_X-3{sTTRPEiD#@7w$Y%3bW@bIN<00pJhq+pSVVJ%OdynSl zc+X!|g2wOp)VOpTv?eAeXbOFhGEt%Fhvk_{Oxs)NVF6orm|X}8jCP{pk1Q?b0ePm& zUW1vcfS}hOZakaOXrE54L-ph83G^y^tqXN=+DE5!mwE9qPhdMmWWm=Eyn|nim^cL? zsbv4C&j z*49GGA@O9io2NCA1$TFVpWA6gY=L)9M3m&>1A7yqTB-!6S7xmx2sV{zd@&5+ZumzG zG(>ogYo{w8VJ85l8E?JGpP?TjwO}U2?%U85R(RAB02&Ket!Bl`c;?ZpSYJdV+RVcO z*b|{Ufbm}4@u`qfQ<$_(<|I{?5l!M@c8#9s zn6B*rs%AaZ(o%aKq%`NzLYEB0RK0fq<^6MU+khRCu5EYp07yQI z9aGEbxR%% z1hunw`=AzW3>4+Fn;wxUn8OuZnSxtHaE}t)LA`_9^98nfc9k~$;sEx1MuWr+kg3-Ua``8Q7+;$AapVoo zAR>u8kpmQ;H{ZIma8}7z$O#=ASk#fRF^s?d*x+jrnQzS|U|&b%N14TO+Qkz^*ZjL@ z)ndS-7}Kk->&HyumW2A!39kwrvq&vi!iFD$#kmmEQtA*s@GoSQkRzKi>Ey!2m|@T7 z7t`_pVcA@@(?AIG=-U(|gYY%LXDC3KJ)f^>_U#0`EcPPfYEWpVT@6I686=@~9{vy& z9AgBsC#6Eo9mmz7d5_$2n5PUVS(Hm($2Tw3n?Q>^CNYo30;9QvJ$ z3=&IP1x!494#*Qk*UUjUX1x%MIb~6NQ!J4Sg&4F4ix&@chkCQ}syM%vX<_>=p_aJh6 zqBuO7dM1`QqhuoR^6ej?Um$)nn#Ow26HrG5=IZ%qT`Qj0Y;Z!dTjQTIrJv(GnN(); zd*ug9=vBxWXm63U7e=_*jb&xxdMTeAP`8Wc!v3=|eYqT~JcMd|7B z>!8%=2{?n+H(UeuYM?(HK0#|8Gi-}`kimld9*^H>Du+1yrgvA39T2p(tI!h;UYWTYJpgy8JfN#ho}D~+N?wq?!O=W0AM^whGhi6&zx+ty z@Q~#4gabMh!T|yUu+Wiz*J2%%q{}HXWfwrsd`RR2DvFg4@$@N5**lLI6`wyqHGjrjnRd^8z*91h|z!q{=MTJ7&pJPYQ_0t-Ya>2(OnrgZt=Shv}h z?|FsFibnMSIe7tKq%q_@ym6K``TLuBtt<`FI-oyF0Iv&qz`)=kjt`A%13$qj}N`GvHIjVmvQX8ls{Wa~`+0IOeTEZJvDWLwngqvO&O` z;_DOgr?!uLDf^?^%vA6)ItA?oPmE4xz0HDcW)FVKU?z{dG?@o&<{u2S#h(mF?bn^S zLM;-yb6}nbC78qQH`Ohs#@u=?B@-c_x5Q!zal2g~vwazghuI(y4-=GM9FJnp1jZPm zIm~h*s)eOXp zNXX>B;QyRU7|bVr0LlMY_lg zH}V-azRWYQHIBPhnqB`lgR|SP8zYs$e;9p>-`OBF0C2|@;SX%fw+N}XZ@Ea_WM&KS z@}^Xp+IV7){j2;CXWv@;Jjx%j`}ICyEy8R0?eXf?VH)2U(4S#`8`f+5nX^AgO^#ri z7?_}5xW0@~P#P!N$umTuNCBBTwcGeuoq>vdA|ohXe+T88*uSg@Bk_6gvkE91QS9+^ z4E@jt)F&T_AOn{BElFG{F+TNU%AXogV19v^6^JnI$HNV3c0b-iz7&~~XFS6`Dl}34 z_2l)S;9&FhZ-Bn$oNlxsM;=Uc@<_(h1hp;D0K}i}?V7{ZQ=^0&h0uKD;%>pI)a%7kJlKsUH1H1b@fBqK`y}b|q>i3F}iDQ?r6U zn^855h*mQeu>oj_0a5u5;vJ};t@uH^s#S6Kf0&77i!i#8uc-4j@1M^m-`roAC7-55&CexK>0sen+fY+EF|hkn=(~S%?IL*#jOwf z$qG}@Nt@bX_R=TLG9=0kIZihbv_o7Uoqn!1f_rA9CoxF(Z2mx6vBUwV}`u? z%ZJZ4bM{t|(D6T1k{OCz5eEmNQ3!yB8xX zekHJ}!)%WT2z(Qf`Xdw&l65}h@xEFg?dGX}uI`D-`~Kp~{1#u*0J66C_5n%uJ!y>o zpYx1JO)!+>rxNeG&KIRGs1tMI{qMoLk}^Zcr1~7IQi1u1)<@b?e?{eQP`)nXMxPw{ z>eIvNFRQ%FGHe5g`VZE1{`?!|xd1&P^(zkve_k5PpJfsH3C}S<-nYB?^E_c&-*+=n zK|xCREEy{=^2~>)$%25$%tmucJLu@ohi}lj8X@}{%mjYRgy+MXs`>%L`}5(kl8=lP zGaudrjO_@FK0W$+X_||L*y40s20hO0TDq%FR*p7fzWO(|LwpqbqFvy^@OcMIMPJfCxGwY2|Hk9S;QHQt z@Lst9L^uUKD*?6XJGl^~qfYt%b-)L z?Bjf@xs_c(DG9Oqke}!x2e^U>IR^OwQ6 zcRk8~e*4yB?@wVZIpfDGZ|)&&a=w!u-3-RYEen8S>+zOUWW2ibl$52!3o^TTAH>+9 z7w6fKB^ye5&Qgfn`qCR10_x|TtAfo5{sijWBV zM$+Zooqs|4iDLX?c0&aazb(nfaA0-m6hVW|eQp|{rB-LYe%<;f7QI3!^*m+@_qmR^ z+G2*HfL(gRD*%+)e4zZ`wA`-W<9h{4Na$;Gy8Q7@$_+0CYrV}p21Hk(YTFxwSpkpQ zy_bdUf?~IK3KKpxn>T05L>IyTHOOt(n{dCeh!=1vqZ#lwdM}1&|GNkOA!-g$eiP|7 zO3Ri}7w4FsKMF5x-G2itCCM;UE+kn_lAO)WPxag#zOY0dd2h>S zSpIC32f!5Z%1C3(vNY?E=b0NyU)}^tGTu@6 ztF{PFW-b(1)IV_u%-$OYl)r8TqN%_ z9Put}LQG|56Py=i@YiylUQB+pIGWAkPhWjb!YvCWP%AUXSz3(h|pcI4a!yd#nqA7`ViQjjT|> za{(BC4scQDAOO~3urZjAohM=4Sklvq(hCdND9Q#2W;T~$Jf`YpzdBXKv(U8CVd(I) zxW@)p^|F8sGCu+y3;DcgZ#G`H*aD|+tZ$pYT;)1j>IA-}@4q1ZeUhN z?G@F>LHlxVD7>h$4Ex6^t-3^7i7%GHuA%dJk3vI~mJCH*{ut>_RVGg74)f0Acp)Ai zd@c3z2E54a=Dz1(T6((L^Cw&1H7pb7Kbt7_mcz%!Llm=0H$U0bPjr~!OvKDjK3*U= zg{B^ivU^3|%S@-)4E76S%}p1JI6KC9b6_DmO=&wkgJt8(ST1h8IELOB!YRuss(d&=2#Mvj;PI)>qwkE<@hO3iXD&_PhS! zd?G_y_o4r|{*$l&?D)~KOMh!uYV^ne<-HN-jW4gi&0$b>AQlFHiy2D_>KsT|HiR$Z zk{plV2*^{ISB-oRyf063$AewJA}{6S58;nG(g)JpT7?=ken<9DvThMIz$5ZKNYBGO zyrTRKOAPd$BHx>fIff{xy}=L|pTfU^__$~~SRd!8(f*VCoG*@zguGe$=fVRz>;i3{ z*_kj!2=lxvNx-X))AC)UG%Ca-H6%ajd&oB)oxIWY2o*EZA9?4y-);ZdcmV7!#F&Q0 zz-hX8F!)?-_ET-Z6{;L|ZW8 zq8?F;>FI4`*DOVa?6SmM<*90*E;BhegQz!-mPWZXpU`|n;(x(g0$XyXBs5>NR7f*^1Nr$wi_rAUoKIPcOtOO;0|H=CDP66;r#B8SK` zRvj5xV&4q}yGe7n#&xDUg;v?GEGQDJzAFZB9S@daP#D0#F;ieqIrew*$(>&k&?mFG zQzJ&7JpOE0pL}(BoIY6vH?va;&E}37gav(aGakbFv2r=_@F4n;zf4tk7D``ZT`zIfg_Ixl11}db0)O=>o7JTT zEa`a%?@s-T@KATB2*vt=7cx?wPB9Up^#f0G>Cp<~FnUS&U4&l!z=K?RYyG~zOApcX zJ~mCAf>?xWV9)*$fA`^U5&p15*zYNO&4RVHCqK%B#BGfOk3N?Z6sc(6XN*;Y{#}l@K#L z+^5|fr?|EoiT{VWtn5sq|A-gJ?ras*QFo%2J}_y7tSljZZ4b#nxiAWuI?OKx)+l)W zFj>%7ueB2fo+-;)O!;N#3#G$E=X!54wM*zBb>lmrZvhGZPfU=){a5VC3(aWHwbtW> z%D@Affb!f4!iR6rX<&Cw0P!cMFj==A-Y`RRr%q#;1FP|Pft=0w#Wo-t5L`Vyi(36+ zWza2h@F9M&KtBx)^gJKsid$CVTr!8Cfp7u<_UL4HqGm_=h$6ovO%UK~Sr%t%@s1{} z%c-AVrge~CoSvdIfXN(io+;IGjjmiHs+pHcqby^5GDicUO<;L+u*#XKVc6bOSH8m5 zkC@8$9pN(41TZ!ho6$AqUc|(EO@Jh0t$@d6LurDXA0_W7xswg%uPA_rxek%J$lRca za0e60qpWQ@1`!6(@j%_>Mh=i#vM}E@zu@*g?-EK64rQ1zqepoNLzv0* z6&;4}!hU!}9${1*B8Im}WeNm`ns)a>$pr((elIK34EOs;vc3+Z=MN;S9FkS2Fbm3K zL9QGO31LkLS#4s7FgJ=7hb?Ho2ZcP|*j)jfFY$8rv&SOx@+hJnkN zdm1!n${x(l#ZAWBYjdUhbK8UCf$w}4R;uVAD;+vaGOl2g)3wJ2GV)n#=6d-dg)QT3@86?&={vNQ%CU{6_F~vX z$Afb^Cx+PPeA^NQ2CT#jttU4+tm&upns=yHP!_0w&t_j#0BpO3ZlfH^F0_R0 z&&x})EFqus(0;y;u@bzA4T?GQ(Q?!(kjCdI5qM5C>rj)mOxWs%11p!Kj#Ka@euL%g zNR^EBBly}fNY>{lz6M9h4>`(j6_0Mq89-w^ekv=}o(M41(-&EWdS0}S9#n_|XuUjp z40XSL9~Qur&$$c*ClD!C6v)VDpP>eO{3I)4>Dod+t9qO#0I5!Rp{ikX2_ zVBG@#TCzu%xkl&PT)dHeCR?EcC-Ot@4z@xm%3pndL%z#H6{{-S4Wsboq3IEVkf=iFm z=8?O8pqK!#7$*yX#~K{dpW)$jA7Zi9aj2MsAZgrvmQ^Mgw=R$jQdCw(r&DOSGWy?(d* zd5AGsZ&%7@t^?s_n#HTJl?yU3vfo|lElgy#7Ew;7qHI?OK|UQA#GTm?U>^q8XEeE)AjVtD>l$N#L~&hN~VVueVXv*uw<&`gH? zstF7^&Z(D}A22P|IDWJG12V+Y+xC5a|80>kQ%1`D&8R7sWC8yfaFzM~{|SF@q`!JU zAO8vT6enW-t}~pEuP;Hs7SrTbX*(BDc8k)JX(CpZgS|KLK`&l!Vu)Yt`eD`6wju~d zbAg}eFt0p`FERVYj*v{~^}tpzt{?8}7j8DMF7^tqY5nj`Xl>v;F=xN2PcPvw^ev}f zHHV8dg_q)=TzKSa7s%1+7BA_tz4J`S1^EEa&24ijEjW&vi!6hHs`6|)?^N311!)%Y zH;L>Ctas$d6FA^S@4>3bd;m-`vCj6uc%eLmH}*U9_dki1{8VP(U+I$UufPAUkBBpL zeUa z3nyC#-}xu+fez3rTmBQj)H1?~arGDP*&G}}EgPaT-mn1MrqZNaRHM9iF2IwlXDFLO z{NWbg)8(ZxPm?oM@_P$@-uh#45W4af_PD9ZJ0>-cARxOSJQw&-e0{q{ex-2&{U`p- z6{bx%pZcQ3Tz7_tl@HJLf3Sa!WIOWeqY(Zr8{$qt2nin3qo?r-pP+uoJ@lV>!mBiF z4+QJ$ZGAL29vu&&AI$BiIzmPFUr!bKiXR&b;$J}Z3y-9y8=S9;IJ<#ucmw%?B@&>? z?MY3f&LZu|CQ~ZPlBz#B&!jX#7MsUDX+titBoOk`Lg8cfMUH?eF0;Y_mozuVDG8h?6kl zYE9fFJB-AM=r1SV*xz!V551u7xL}t# z54AUI&m$ST!putWM-JjpY(Jm2r<{jrD!t zelKBRlDXBqiq;F~Irb}Yv-NgU(b(I1QNH~eGTtbwaXD{gm#)iQ8q?mWzH#@hlJ&6q z&UFDCO^9v&Z8FUkHsD1<&3Ij9zJ`cGJDbpE{PA&KOY(k>%qBgq_7BoX2)iD24Y$L! zbunn-(hxR!DUf`xM=UfVp%Bl>JP3rGh94eEa1-mnVm#OomH;EB<*G#l8`CRmuA{e> z_ZjI8j4037Jgxa$7DNGaEwd*pLMN)>Btuh=7mWTLo%}Cl05;Rb8KfoPJ@DEAW zWYh63BMLX}1@<47qso&PElA}rLhjn*) zu>J~Hqxz42b@)i=I>=yeQ+l1dI&hq`aBuv@`I3EjI>u}|>&BQ(*Ts*qF{sbMYBWzE)lybCfLDdd!dR`4kH-~=VI$|n zWe_+5Uvoj{7FsjT+g3BC!MlV2O>Z(c98XI|0#nn$Df&J2(= zp1ICgVm>{I;t220dYg;{(cXfM5BTBqGdiA&(0RZYV?HC1;bD8p*(1*0`2q`S%7&CF zIA4zVuWQ^z#9s07{aPxG;_H8Zo!`NU)%?vn zpYZa_di@|ZEMxVlvya4{A{(P)dEnDeg{fdCSg+IiNIM%61Yhg<{zuY27=H`~gUr4M zX$KcXiP|5WBkK8MX!9rYoGp^SzvKL&QGO5FFM0E`|9bV$;ye0O`>9$u?`>+GL0kDti1>?=89=?k+ByNQyJcwhsTjF3qf`sw6LB3LrX zmjJ5FnKo_alG}nlNlWjkfCregImxHs1IC3=-s6e~0WWhp^DN?MkZy-M?J!-!iZoIn zZmRi3Csy;!!Nf|>L~KL$Ml*kFj@csQoQE13&B=n{((36;Ar#mJndH)R@|(`l!X1D= zI@y+}X23^l5^;!d`fnfnA_slp3#uvTgwSLz{0k`Gps`bPTEF+tA38*dA%uIg50n%=MrbW?GpSltH1;>})p2NI?LHmyU>*t5Q z;u%@4QZ-s=jX@*98ZzBtiLm?UnU6HlA#D1wCYnKtCUgsUwY-t0@aa0K1!G0!li5wo zE=LA8UW)`DG}?^j_rB-hz^TEXCG@^iBprpN4&g_{iT<3mQY z8_d0}CLp2hG!9W{f2diPpB#-GP=nfH9kKz`4k&@E)9cpqKaow%VHRO^B~K6sd19Zb7@ zbVYYv`CFccq|03TCg=iYv$K+9JHr$I-GfXslW%!**xM)&IsHCdv$wfPOq=;0-gx=; zqO@kdoityw%hzl+(Kk7vl~_;`pUt^4fRjc;-cFJf0KNVX!Ec_!Zyt~ZmzHtib_mP+&l0{LwNW z=`x3CmOzMQ6r-IrhaZ9HFhb=@p1}atc_@h0S>`DA=^N6}I#+WY0<4NsnZX#1S+yu? zY^<7%3Ov;{qDf0uxsp|Z>KLWbWp0!l!Fx$HD9|DvN2sh2>Q-0BPJrO`@-FV}feM!% zBwM+L5~?G)%j|HJrP=11@ytL*KIb6%uh;ofZkToe)yw4dxzg{EiJ|DLAAXBs&TB*` zNP4z7l`gv>X!{22jed{EweeTZVhhFFVbs8+h=K)rvAn0Oa{fvYpOA9qTZECR`e`*1 zBo}e_I(wtUli$!^s}3&2%(&9Hb0|4~9!0Ll36#Ymba9i zevPKxd@eel0-&OJ`5mB_8m8{NoRGQi;w#i2g8t#ACH23rA%7XjZ1Yo3Q5|E0)RFJA zH+5H&U7yRNU)W7fcw5?GewmQ+L1V=Af05+xMW28SL3`QDFB3dDvbV)#IVd9}qrFRI zAvZtbLeFHEe{<*Qi61ASJw8d)(ygADxikJnmVsx&|BGM5EsxlozTndnuRo2vZHd{< zi9akZY{PuO&I8)u$Afz(-))0F{e>Ri?fO5W(NdX#ORs}O>hJo0>($baSpP3)>E74> z5%=e^IQyip_Z5!C4yVxB6S9s`KW6lFR9j#AlV9;?=>ACQeT91h9VaHcSF*44+)w~}@_Pq#T;BT%kDm*X;N4gF#y}`^>|LYTl*RK}+*jCnX&>$@eCCkv z^1i|w=k)ZryT@|xD{QJnBwNgVg$*d>(dc)STimpFH{Pb)RfO`iw89oI2h&3alC3x8fwKI5#W6ptUNF9*+i_Z9wSHotiH6%Gd-1*`b` z3h%lOxzn|C1EBeAL7PUD#^+gq&wR$KGFk?*FgE{4dDQy~&p_>ton!7R9HrIO1>o_S zM7SM%xsT7(66ae#<|A%Z!2PFZ@n`5*?AOry3g1SgMm(`ckzx($hC)cp?M|znCq?5thxR_Z1HQbsz34yb$ss zcwga5)AHO`_)APUqW2Z9yM5KCc(2bfB2%1>Ttym)qoKu&0X}>-uN{Pkh=Xel@m^yE z&X{9o5(LepCFT_$O3?oC?JLiJUxEBI$XA$d3>MfgL?de!vI7K-V0p2h^fqi5U1ArR zT4EkCpPYRr^?CVQ1`U!T7}|($7T%&2%AFW+2hocAhgWO7|0J${J3k0nyq>?yt6M5Y z3a$xn{?k``ofVcL@Jr|K`orCQ@pTECOGI zM0?n%xOb+Ig*J$*lh3SkBf;37&=q5koUcV214a29Z;xya!UgP+8&_DlxafjBY!T$z8@*IM~;Go zjVHF)BSkYJ;>p@08!5N~1$P<2i9NDj@8JGDnP{(-J#uGN9(!aVK1d7tZ;!l)PIE-= zqdl_ec|ylQQ-zKVNU1$C7=f=LI?^5?e255Vk1S`>$r0ZkxpEX?h3t{vp4kU`8Toq7Nl#KlEyU35azDT>GQ()Oh=2 z7D{%<1-c6f!MOJ27kz(v@~rF$CP{)TL7hdw?9%cnJzuxcwzCAkW%~O zKn&54C=c5oduW|;_Q%!Oli~GdjQ#N`v?(as7(kcL@%G2;8h-KoAzOfsf>pfzF-Jku z=5UnYv$H?uqIAFPkIAUrbz6-6F+!`W3slEv68?JdWnkc2gW>fvM4mi!VNrT-(bfiT<_z)4!{+Pt1lOw+Uv0({eh3tLaVq3P(EeD8Lb3M8i3nS-}wGwJxs(@*#BA#BBkYe=3B^o9BJiT%<~%K_I7j~M-Q2P}+r z*H6z~=2sGZ9w0#6`v{S{s^{SgMJ#IrJDk!`OMPiqIB>2sZl1zrMFBH7GH#v z>Zd<~FG52-te@(!76h`y>8F+0Ug7m-jD9*=i#7((<#W7#`VTC}fPT8@GE1R&{q)5p zg4NsrXg)jr)Q!^p(oc_|cE=kr`l(K zbI*Ll7X8%q>xg)=`e~)i4@Yk^88hKEno4=%)`RO2ex_2GviUVE0hNshyKaAts$1@%7W`yAW1L zKOJ{mAN12w48EX#+6jeX_0z%;x%%mU$zMMnWJyK+_16O*yo4WnH$3!jzC4!VHZ!L2 ze1g#V^6oyAKF^oCWw4Y0i>%pfR}YI|d5w1n#)m8;-VtwoB;LRV&vmzKI1uO|L=mmr zM&`*9P>Xr8-H-hfuTpP*F7X(_`g+@sofGR3IUl93_DAAZkpXV)k0CNKF708oLjBP1 zA*J@m07w_%bH~Wm{`g`%M|Qyec;%M_>`CKZ?T=k)VtV$+EzKM?8ZS`xM9fk>(Su`PyXNR)@|kD*#;oc(bw>hyXu#{PKmd}(ZB z09`)E+aHyc{Nl}zS0O1_#oHghQP8wG93}Yd?2n7l3;nV`Mxr{`Z87#op;lKHsE*Gh z`~~34z`(Z#!(%d&ExrE`A$H<85c?6%>mGnijVHDk4Aahvh$jo~Tm?5(!M%x;+8@8@ z9o$i6B*R+S9~%ObSo`CL_#iFlzx}ZnSjiE&kM_p}GBGYaBPDb!V8dm8d=>^vh>o;B z2p=NC&5!qH(#a9u{&>Gw1c~O-c!5_Z_QC!b5BU(ZKkh)GSo>oPDp=e3@p)%N7{KbM zb7W#%dh!IJ!`Vowe)>6vpc??)P!?I`8Z$kR`+;jO27TFmQAI==Gs)3w_QTj3iePY3$K zT!C8pp`RW?S%-3reyV|mvF`fmzVrM_V)WB?T1gwwcWlLH3cAa{)@zs_zkRNt*c2$u zXO=!3rF)+r*U7}V^mmAefPVTTQmUUW+c7fK!}{r$T4$VodS<)c_0wKjv@w7#pX2q@ z%di{+`soH^jAnS@^szRcB6 zTg$|_H1Sg*_IXIDe%cs=FeFz!VvBxi|3ySRS^e~kOpHsL4-#+(5}eGBmu%lFxCizl z8P-ZaoeoT5_0x2GkQVe`KV1iYa76B-ep)UQh~((tJugX*WJ!0sVBQa=%XKtEm2 zq?04QemZz7!V1lg_dB!?`soe~U5h=Z6J`Sxiq%iI{vcOB{V&arcLG^b(fRRjfe&69 z^F3_UUc32m9b)L+{CE=|N^pML>w0px3>KXqe?|K1EIn90cYgc;@$T#Vc*EZ3#|a$D zsg?eB=ErgI0n0g2&x?O>@6Tf$zYN2ZIS)#`qdN#4S^0D0pzO_C>J&dxLkD!h1Rw9?p+dMn>4!)4%uYg_(*wEWR)TmCF9zg2JL$&ctx{*5$+WR>2}Zw=(feSC7id$>S| z{&C}JM^w_=eQ}6E$-Cb*Du0n~8Vs)T&-cn5UsHyO%!nP20#E7#&ta<@j;g>(9Z`PP z0YUEP*-zqs(=&#OWiwO_5b*XR=hnY2{<`4)H%9YvW0Z7O`n$P*4gNqvOm}0*gX;Xd zs3_HgvlGkbfibFNW4PVXDaU!4dq_=erx5oDHlSr@)08)Voa`*&`px&(Z&~cdZZq>| zUbe19Qr*;XYc%OjxO;DNYs+sJnIl@(wlxk>^Y%HcgU;}#iJVCdg zj2mjvP4*5sY?RCzyMLXW5-9G+Q|Kiub1fuHhrGZ_?0Wrj{X zfh@fk!jhMreUH13Q|Ut~jZ4VARcK`H{_-i)xql1?!?+XkRjI9Uyk77-x9=?2g2;Iy z6Q+h6sPsus|2#AOb8^>WT>XWi!N7E0{j~uFP5r3cMNuuI>p>7+|%G`*ioU#jUnT>2bMZ|~AmG`+b?AExQS zEuQg%$iei+x~KK~Vy|8#uwRb zNfEI+4%<)6#qLEHUPM-CtbPu|n~Vb9MrA;pAZdyj&}c)zG-e-t1^pwh1Zo`q6jB4{ zl4f$CMXNdNK#m2m7N&9&(WT{HdKA--?aaF6dok1Z_~}CLdv1JV{xeVfgNC!_vf%^{ z+0}Y*F>oqqIe0{YJriXYrHs(S$yY~Wv|LXsZb^Osb%U$!k*rUCfDV{NbLR)&7v?b_ z|6GVqV}@fV!k$mnJ&k?(T|IRb*CuMXLspuVDW3%yfTr*ix+-(^3B+iW*#LtIW2!2( z-{QoaB`7j8d2J|`=xqSdo2w^p%Gz+J{q5My&t)kJeZ7X7K=o+H1)F%Hy7Y6IxI*gJ zSIjf_9A!oRqPa4fdEdRPJD491wM76KxRm~!-pS17>&cJ6H(wDdPaW`tacA#>y3IVo zhVeG>`|z*|IEU|~#$r*Axs_mfn(4d&dVH4C4j^cwSvG`X9RJUIf7{NN_4K%+5tBcc zzrD^x?-{cZ7MIAwygUQMG}lQ#&|*Hg_<;eqb13mJgka>pf!_FIy%_%Z5-kuZ>iA>B z_4~>n=N_;8@g6#-kNhzbYHyAF@dvcis`AqJg8Y#|)R}z9;g4^>7v_&~6+~(CcYekn z<&W10wSW9EhhvBQaSa~w@W*t5&C4J63|#AB`qkE_eYQ zm`%6mlb_KTXB7X!3=J1Ixy8ft5mwup?7~0*Nl^V`Xj!28HI{el%`AKC8p{U96GW{O zcKGE$IBXrtv;H0XRldxxpK6BpJ9Oby7JQ6h+F>fin*_l@`c=gcL5!c*(V@CBwySTQggVSxvUc9d=7{=na@M_NOnJtQD_XxKz3 z$t5T{v9Qyg!_j44K2wUJf)+D`Ls3pC^8Eu-fh;N@>p&u_vOu!goN!#g=Y9|or!Qz< zyhW`YiHA$ff+Ix%HbV=b(>u&ggJeLUDxBu@!;$V|3BYxCE)vrV*B;8@tF5N|7~(a` zJOOHp`#SkZqE<{6-i>H8jj);SM5emrBQuka1YD+e3C0}2T1($RL;(ELtC3ppdu%8) zZ{omol@kGgE3o3hS`U$0tw29k8t2#gpkzXODOqVjG6VQj<-qEH_pDm%6p{t-)@UKb z^4*0H=Muml2;gPNa7zeuU?nC_=)g91;FoH_paU;1Mh~``Ukqef=-YI%!AvQ2Jva@6 zjLa?P+`{kbq$u*Ny4`L-k!6 zhb~SVEhMFQYc!|qk3;5>ofXyDh&JrE5XD4WXo;Gn}nWMTrfnz52k zM%FBI1v`uiE<>YeiP-^~-Ej`YrW_XB4*E!y<{7Y#enlPT6#}nbI?c`p<(yl-U!;{b znb!41#@qX|^gNa>v=8*bIWpo0;n>5ooqF-S^e$yJ3~8L(0*t6ZPzxqoIrKu;Sb7Ql zD?m4H2f}$Z_Xv;zg}ok%hvtN{EWQ2yli7H#{1Pbn<(GU``SqcDcJk{>d12+(H{7}s zkY5L|O_X2nN-j@+6@}&3-?f;?uLK5;vW+jleEfUizp6;x{pG(RqR7c4`R_9_v(JCy znRNWOLK0#Adsj1r`0p)_LY3^Z%sZ1Lk(d8K5uRIW`R~V&vOfRaNh>gh|E>}15T~0? z7_b)nH&HQKH~t%9Il z-i7t&b~?668R*Z)g))7VU%vwP`SR<10*{ej&uOJi=BjUaJB}~!F`BKs=uLke{}G{`SAMOM z&nmyp7QGRWU%!kYDX^u%q<4$*+t85&3llob5|It*H zZJht_>^{cJukwT0M9lxc>_vW!u$k^erhM|t$b7f-jUURmUyYQV|3h&E#=Xj~6-ll2 z5UDkf{CZF_<;btyCbLEH^6PTHh`Anwi z@>%8A-R{}hUysTQE5H7VT?HV2uKc=Pa^;g>m0C>X*Hh^AwUS>Yk-GaUzuJ{0RDL~l zIQYZ2zcygf%^&ATB5Z%%t{Fn}$J+?d%^$D(nNX&W^6O)8pD({oF9)C)`|Ak4r~Df9 z*;>f20>xX1VU6%JpCVK{Aap!%+D?K5ec2HB~0Sr9YE+jiG-- zO6Auv&%w=vac0IT* z@~cvWc3$~)k$hJ9^`U!q^6N`^Vdd9Gf^3ZZdRKDglV2~lNUw?f+L_{cZS1dE3dED0 z{gq!uMA6M3KbwGrFTch!>Ezc6NrdIsyP6>+zuqE`Ir;VJ-zCvU`SoLPpD(}eOrdOy z{JMtkDZeIsycY6ns$#Tm@@s1aBKFsIeD0t8dSh&y{MxV%fUNww`%1RapFiI5uYmlz z^@oo8A)kFQB4_`gtjuKa3{32^BRj8TC93n}aW zf>sE$BftDQSpiH^04oVV{a-!+$gdepP5OkzW-Q&ub&UiXwIQSAI=YmQed^ z@1LR}zWk~=NZMunU;GxCKkg{+!t=-Nglu;Hc)oOF{`I3GaHH?P{}s5;mtXG_c#Qmd zPAi4~3witP|H@WNo7PQ!-K;=FevQ3C(BukIBz|wI=Z}l{@3+Bd^M<(R{~G>009pC9 zE1v`M>pc^YU;h~9xIbQg4IRb8@PA>*`L)|~L?&K-jrEI|Nfc9Y@@p$w`P>iVkzan@rU0&20J{@_`oDYtoIgGb?5zAci_by%wZjJi`L*?yt_Rmee*H&; zc3%0lNa9AmE^6UG2 zFaEFh)JG4dGAj>s$?3|D z=G#lj-3T$ga7S0fUz?AOC#}A`uz;l#HA8jvu8S*t<~p(_iSEBmW7UIL|=m5-iuE zN5A9n3=-VMuTQk`aQ^9}b&IPy89Uoimt0X-{z{@|H#Agmn3-I$`+9ZBmlHLUgRj=F zOTLt-;Wf9N3rUlD;Gae`7#0!d(2pT^VwV6d#F)Br?j^2F(7>>J55PVK!a#AO#hXpj zm|*c{)0kV_Xz^>tqd20jSsWvPwKthB@zPbqv3cAt{6H6sHF|ZkTKsZsQtU)1upQ}g z;hsQ29PVek@P>IuFZ8L4*Woxq{M=7jtB$q64ut&qZ)ap!ulYef#>k)>u_wmeUlfXF z@$pf9)A7*N@A1$NevTbaf%4>XvqGk5l(Q{nXYyjs_$c$~hj=GmTZP7E6Ezo*io*Hi zl&pcOW#54W*wVrmkIM@@yn7nH=;Rzk;?QYkr$A%1nk`S4Z|+V!T~RPEpoBFEs21GC zSo<@xs5kBEHd8o)T^)+oAn5GGAJL6&V7 zc|-|)5SAh$_b-UNA6vk-Bx?2*QX}Jj?xA=e5}W)sQYecaF}Lg|??^9zUt+f56u_wz zj5HfhrTjO@RHZBDnK@Y|D(B7Ia5Wzv+E!ug;^X+#^wssHtHM+? zf0{2j+B`sqhO25ew=I<%&0Y@P)QY-sXID`f_kuK;$8VJ^OU@DQ#P^o5KenEEkw>v1wvsy{>TL~23(XjDG) zZCgGuM21^?y8Ib*PKUv9bOoZjb#U_4Myy+AdbmX!$F{RO8?}dkU%R>QH5!IK$#V8P zMB@1jwqjd7;oC3OE6Y6kM)Ko*yNf?9Q|f?4HFmm7L6rr&I68jKlud}U>ssv}kwt;~ zN}arS_SXcIardZ)7|0v{$`8^(7^ck6I`o=JV@5LF3T*kBqCB#H!_|lKW;f=|(I*O@ z_;~aHqcE<0YXH^m5vVHTvt}nObOh|xnDQFW>+~J;Zjk;ZVft5q@m@jyvidBTv%{Ra zhp;fzQHwcKo*{F%oRNX|P+0-6PfRABV_ z@|pMoIpza`BIEHKiN7s^{J=L#KA^Rh@wdyq6(FEOi@P6~Hp?32kI*Ax-TL-TnMZH0 z{fyVfQTjYp2r;6l?dM9-E+aZZO@l6j@bCf<9F4XOhFmeH2bcoGK}K~)y8I=yzS#`^ zLdjs(gZ2oH)d0T~`S@7-4?%8j&;)wG>Bosc5m;S3ZdB@z5aMn`ULIo-tGG$X)onlb!(BiOJPD3y76pe2>9@| zet}P!MTM3%Wr8y7ERhiqBC^IP7h$)U9X&jK<>AIhu6!o`mj39o6=VVSu?p50{`By7 z@(#HB@=o9r9=Fa0O8f0$dF2lo|M25k77D2Yhp&_8LHpw~v@f7TBJu+CBAqBZMSgJ% zA&q_6lwlYd2I~*xV+t==3E<;{Bmhb_Z^5NNyZ1SNwEp!?5LGgejs+fWy!%K-u&IqjyV z!`0+&;x^iP^jbZ|Hg?vg7n@gJks6x8F!*C-^W?F5R6(Nl1j5A#Fn4T#hkAdt;X#(7 zM9fq)%lmX?9r&Tj-18gsOJ@2ke5}LADprwUW)wE}@gpl>;%&(ZBcI%Is&2>V#x2xr z3mJyLD!-%SYsSiUe2TXBaISZ-&D_;nUS)o-;d^Kl^b;op#fPeqClNMnJNEz+5>)DfP_5- zH6WnRQ=QNVj2ZzRdpH>djcEo%={)l%Xl}*m48drBhtaXbh`G|Wpi+-HR=~8HtVAnw z3@+q*>fn0?7nYw{%YQvwk`5Q?RvKl38M!TuZPC=v?E3D`n}rF9u=~`cVIcT+xqPF5 zWTl{012lt_I!(Ud&0jAPTuC`ZNcNZmd>ol3j)Q@thZnXrIU3Cc$hkV*xKlN0gH-Yq zBazZca1%JHe)=qPEJNSxr#FCVv&=c)II0~9_#RdU4$Pi2WBiK|8tBu`(~Ou+=M1hhUPHY1ttzOvFs;+ z_Q7WS0ua>B=qCME$OD_BqJ7V&ByUAy`e~GCFlWd&K*&_05fzQ*MtuQs0>-eL*><>u z#Guos)eI+L5R`8l08(8j^zr4zQuL_%+GI9F*_N`x0X!dI75);nKVtJ~hl?%PmM&ik zRGZ8~xH3A$G-c|3IyN#8AF_0b3~lDkXTmn3*h^7)q52Mlq5ZTICk7?x&u;U)#_&-g zK#%zP*6By;kIW!ZQ)uKkZ4y`;uWT8$FZBExe4vRdW?YwfS8`KnLeY8VoXcM#K&g_d z$ND$M1H)0~5*Fl0oGcJTd;lz_ZCN-KJf^g^i7{W{E%Ij_^JI}Qomk31Gg0Vu{p{|o zhk|xoBu1B5ffeoMhRp)=F-t#Xb>|I7E8r6$Vp)M5nva4DJbMQjE4$Xb)ZSaT+C-h!lYn-4y{)Yiq{O zhr<2+z;QxC^k8m(mwD~==DXinMx6czhjh?R%ddz041b63i zx_KB`1m~a)qwqNH>u;@hRX9=vfJv9X2Q1r7qZ9%k{|8>A#1L!GJKK>oXT6d0-vi^< zOraHE#Z*E&fHq^UJ<72TnIQh#h&<>`o~SBSd7@)dOx}<@i7yYlE&hS=LfirtzHk3{ z_9m^8*!GeZUFM_n&|U~PQv6ywP71y%Olvm+H^ZE&f$t{jpyyvxNN){IT2qJw|^A&x4D| z*Z*~Y>|tP5T5swav+{?$9@2jS{s4cEM47-`+8@x~d{Fs8WEW%`^Q(m@a@y?7bSs#U zuh-y@-I{rG#;?zB9{r#Pdhy5Juu(w&_eOs!AK{t`j-L{bzg6F042S)(`zQ-z%(j?O z^8Ek%W7)q}Ux)aI!o}H7vHGBTggQ?i7Stg_u_MCGV6oyoGA%zERpkFI0vBt{wV~Oiqx%8Ml`i7#>ljw z)g<19T}EFc7;++nEfx5f#WKJn`j-4cUhgt8-^}s<@jKc@{pjn1SrD}jH5^HXdN@qV z;M`%2IJvboY2=x9H5J8?oLr*is0fU=MA9+JVD4b@en_8%>lb*mpHwfUmI5r5%ziD2 zD+jZ3u8eObZ^6|d`!QRHh5{C?=J+4VGu|Hz^BL#L;y>WG_=62n1ElMSY3=4cJ$pWt zeoiqRB>-m>qo7d67a&ewmU;Byc#{Je%K;42H_Z9U+sw;=Cp}E}5>`xsZks9NOI=?8 zT~UtCdzrK@HhNSc`fC|8*=RGTAK~{ClgUp<26>@d zDzd;GZN=IR=ZQ$P^P|{b5&r2_|AOZ@e*mCf{IP!jd-R1I9-TCanuE1+QUDkgpy5EW z)l_dr;#Q#1iZrJuD!jp%ve3rtg>s%{y0G)FL?P0-f%SoK{|4xZ>daws zH!vSq>-j~M!oyHshxx^51(IdoT>idwwVv;u3MblAeE^XC*Od@5JH&eP0vERoXC$dRxA*nxtId`n^{HVUwqUL znco(scIi$n?gpHN%#hlzHF1>}Fp{QwS{$GV%Y!5>Zxa6+j~^qy?(%7B@mCw9_In|5 zWf>b2s4;U?D9bJwK=2_kyhIM1ecsGb6p@D8Z5JY+waEXEfD#$nn99r-_v@DlqKzsu z6+nT*516s_16mz|Y4t6p@uHqyM)S}UK#Aw@pDS&KL;ZFoVgpLIL$EX?uA&PJDZEj7 zj2>5*s1~1rt6+V6Of!Rw`797F|;sh&qU62{iy_DzwgZN z!|~nL!M@N|*Mkm#geKx|#?mbE&<pnB!h5Pr@c;lN8*04e@~L+lvUWy3Dwnp*rm#?7b51!T&b zfk>NZ+3G3iIi#AYS_`!)_SzZJZvzM91C}7jR}=;I&)L`akY0V7Z*_qtSqvW2EhH9_ zBi&*yRuEK+&Ymj?(N7%s(D4-==5Vk&u*qsya(Oj{R?r4`-V{ko1uoJpW+Kg9iJU_o zZEX?8F}iXwVDMLZ@B!^XXd{39pe$eg=Xz$%(dBITI+PB(Zwa2Cj&wh9ISh2zbK`>Cj*^-XfjKZH$eIJxhIv+>tt^e093_0N3v zSxJ~5!1t35^XQv32W!HBGZ7D?39v>bh`GcJCfe2_ck|l_JP7B}2#c@rA~LI+(Jx%; zXf>A%L`4$8*J3W?Gvi71JL+qN!O>w#9zqq82eW})-i80TQ3kb`^k8g%!jy+TVSHp< zTnXun;R7C}#9R6vNJG1u)h&K7P~C!e_=QehG3>z!^w7x4L|3PbEnV#ijIZ4O3D+<3 z(#X|EG5NLql7kP)xg( z;?$n72&UO=_c0GUt;*DMkSN%}CTbSPpn8i>XN#nfB28xS20}No7?2)>afS#`j8B}P zxh+1WlXpn@O!AH&%|o@--NlJoZ->SD=rUL-ot(rACB2`cKR&Uj4c*y@;$Zduf~+3f;9 zGz|~X{1(u>R$i_+p>hb0Lr{6!qJcuUR`Va^69ApZ^z^s)lrJMqX5#0m?9m8iwa} zvZU>K+6A1tknAx8135vk-?NAE6Ks12PNvH2x^@iG@ zCd_bQgza~^&ji_UiHVs{-pFa4%WvCo?D)#85`WiBa_62lyh6m(h@bPw( zY|q50sD*}O#9vul*X|(HC3&rd006IlV)jR?v{3wf=dxiaiF!EF@eFMn#L?QnQTP!3 z))|_S6CVWGtkl;65frIU&mTq+WB-;PKIf*61gBVeGxe6LA|`Q)>pFw5x= zHrx3di-PMDKK(}o+vezzp8gFuJX872=*sRq{aqH^pC@_`G7&>$%6-6_W94VsfHoPB ziA9xI`9^fgukf}m*{Y+I8)R++ab_l46N{SBGFX@*7P9H`Hy{CwnL*Ogmt1(a465xs z{wPXiO5gsRG-A)9nTs&&00PbQrMqiS3iHb#zL4}u;FG{G=s9YX)*YgcUGL@nJmlx! z6b}JQ->Cfh#QW?XdB#oOZgewAvtdWQfL7z zg2bYBv;PjRqF{SH!W_1f|JjYd;Cl8sG2dsboQUyT*EX*1MS%l89ar_vfbn$|pX@ZC zF8T3z%YZV>4G^teJkA~iK`xAn0EcZSNW5n zSE47fV+wn43xJ9zwe}$cWyEh}wj_?3QGhu@K*Q)QEqDjZufP%?YWcPY$L;?b&{rit z8IY)%v4LOu)g4{wVz2by-}X!MElOv~-&?=ji0P@paRa9UJT35Hhy}v%!)n5Q?c);H zHIJ+6>XE-y&F=7&gA@^Ixt3E$S8B#$g+k+I80s<0HiaTxoW-1LA=8+VEht7|v+y2b z2?pS9`2k8p2ZEeT^Wv9kS>UlmduIohQ^(tk zR>h(gMstrDwTWv_W+7k5{<`@Ed=iHipFj{t{hI_3IJR{Wo(g(4Nzwj#x1^w8{LJLX za8r z4ry*)M*sTOiAKOSX>@1zPlzDxL)-l$wW@ijsu@+yGj}3KZdKpYs?OA^wr5o>tmBr0_3elOYkd@v@~pE7S-7%T%ZHvK zm+?W#7#T0~2(A#pF^~=z|Cxn+ad>7sP-k4vByWgZBxQvz(@{y!CY}FUkJTy)$I4fV zuSS&SIJ%UWWNMit0=C;HG9Nu{t;q&tK#pWXVAMAdmu={f(NWK|jQYY~qm#2!$(@ARvoLNFb~ROhc;#QH(N(hL8k7AjyP8 za6yAfG))^tMLeQ)I%Y|dnE#?3du!KS5FkIH^0}#=CxX5kKilkAmqqd4p?|q8l z@+F7Mn2mvvxe;*6F~63pk$DYJL(EF6s)yf}s)|w7N>o*>cSMfnRpkS?ry}V6`Wsi{#tQ4#Oy@Y?%kR% z5UuWF(Cn^r0P^JB)o`3dRu!zWDtL(;4)F5;Pr8eqrda<`9CWbgl#U9*PUTYs4#&c5 zL61}U{hxq77%wPZ##mtKe+tmlR6YgMgo#CGtMm-3^h{f6#-g+_l~>%15MbJ7Wz6Om z;bf0blKvl0=+jW0{#yrYLTA{T(2vMyGKTj3!#mXQ@ZX9HKobPuTb zc|=}q@OUcJeT&{mv8Z}T2&Q`HSWk;a9&4`m5W6YuZLP&NA~EE3`mHGnSCR)lVGOm| zG!vCr)34B}#TginV;EwWKE3J}0#_Ji3r2?gxTcOR-5RH=G`pHXTfGsg*#i;luVYS= zPVEM9h&3N%9SF4|X+BQOVLV@fP-TY^7-S1D=NL1s!lmx?Fw}9O3Vj$(x>&s6+sQaZ zogVbb3`ifbG_e`;(;rQ(BoEX^gFN)$1Nz?XQdcqk>NxSrJusRS2)}?f-68q zb5>$R^I56B2iq;P($!!V%t|XA7A5q(lFE??lbDE}tJDx=P{eP8=%SxMfd`w;K%_;4 z{R03;?OKCHJxEfl`?-pr#=I432eo1=LwYt+EY{6qMJiqY9trX9ooLpW|4-Je$k9oV z7P=X;Mgy=Fy3s?4sWv`eRG8?9^t*|U*?%u%pEMjd?fif^C7tmqe>%l{2ySwbo6da9 z;wED(kNWYCrW0el{pSG2SK)Aup?|OwFbwKVjOl^keA(71LnSvmr4EU<`G7&QQ}Sbi zW^Yd23m#%Eibnp^%o;0Y?)Pr3WsNw0SVj+OyijU%Hyp#26KAP?rS+_oW&Jg(evsr< zkfajpDO6C#Sd0cg^iiw68>})_R+&{SBgSE08Dm-IeJMjC=39!>OAms&m0=Q|Vge>O z)M7qAVKgt7DR}YXjAi|5BSF#VHLJ`PtIRih1MOri%RnOo zJB-@^+(C&ys`%4sJ2PHQ=Fm1EV);IGMvm8REu zV0wXCQm>~A-msk9Opn?lv)hMULG}llx{gE7(e<~5GZ@~lzqSrVWwVJEwqSdv%bO1L zn2*+Hny-plavc=qC0$4uKN0c@oYOOvAXyG{E8$0j| zoN$c_vY8(}Nh7`$+$@JZuxKszG*-ekUp~dV7s(w_(m_vw0l|s~P`+KMej8`zwuX>FAa8dTBpRubxqRows)sHXC>5 zE{uf)KlT9^ENd9JD+aOpeGDqwtaW(9v~M@tk0pHaI?hLKA`zur2)~BnbHe-qepBZ; zj3%DIUUzn+Ne4RxO?w^bf%XTOU5`}x!Rg`h2kP$t8a1b{m5xIKJ@oDEkq3;^1c{~c zHnV4&;|IUG{w?!yE0n?%;g1-u2GtpjIMXC<>wlnWr>9jvzK(0w8AwOp2jwR(?3koFWIHGYcw7g&xeP0XF39@* z)1iMiDR{&W8!^DlgwOt>G(n#cC#DZ`}<6yura z2(as(r83k~a$c+Ihzq>8&@z6e{U5y5>i1Jl)ZXUs;uMaMJ2>!xm!ZtjRSYam{tobi zL7yP`99o}2TN}M+gMOej$45~EHq5Y>$P2fyvSUvZPigVs%JVQgdVHOJ`-~lcvqy41 zsk7XAllxiNAHRl#qurBSJ%LsnjEWmnWGxCH0q5r^3s)i1SJ*+xLi64A~!IdmE76pf8}jG46-u(XUP`1hrqy*DC*}-$V$5LH6tCD>;mfvC#Xn z;6H=+$kTG{%;Y~yZUn}gT_5PcWpp!m#1}k7o(9gfe|1bQ z04kYn@)wPQA|BL#L17!bmiFh-(Sh=|{PNO*$Y&6>T0c`r4wVo7rn^mK0xfJEf7#%N z#mAohCS_R5^HbRJ&BvS7@%ko<51Y5w&aaPK`2wwLvHv-@L+{)3RivjP@!m>Vkj%m1 zPE%um)((ovdS=sm_A?aC=@o7~Sxno)`%_E@?&w1WFSPw;`RcZ46g2nAL{Q@ZQ2JPC zemnhJqn{!F|KxtpN}1l&_!4s&)o&bV<$4)o39>5=htKdlg*suzgBgndDAA!0uq`1o zYBPGa`aU_AHdn+@T*3ls4YHQ#6Oc!t`u?Ys;lb<4Aln5+1mu+Oe7qu{d^}W-4{&py zHXe!-uX-CcSODA3qnLf#!u#T--Jtx+u(7jmNO?QI8}lnfi@kuUuLs&|>KA4M&>W)y zCAaXU^CDc)>qH9DlH*$%qyNSanivGJ>dy~7UveSOr%+`&&NGgBnP|pp`QueuG7cxC zcmSAJPE(9uu8bItGkymezb@mqhw&RLza>@Ez+W|b*9sKE{QrY_vek+@(?9m&=B0^$vIP9Qn7~3{uqX6wps>OTCI2aQkD_LL=HXSXP6 zt6F|nogZ&^pZB@;%NLE*F{dclnVxbWY$1ArC#_5MfcHJQ-E(u46}9XLG9E zHAc8fe!W|D(evfNFJ@*rOQOHeyPv+D^-RJ&zLMdz`3Ujx=H%+GV5XSzwB62a>ARtV zehU>+*Z*1q2G~|xTIId}5Q+sIfMtXnfaO-1vvf-omcvEu$X>d4Pl-RqTXql$-ilgD zeiVo)?vv;ey`8u0ElJ@nVo*wZZ&{6`bjL6cO6lk=s6j0lK`EK>sB9=K2S;2I!Dh z0*#V<1^)NYk0+(+M>zK1n&v+z`TF{owFc;Itpqw#ONcO4F)&Go+F+>Vz7s&`Rc^Hg*@4O;@R;NNsR zOMyE}_TpLi^g3_Zi(qxXEFNuK2Vmb~iZX!h@wZ>TrwXed1r?gb@^6~Jr_1+i7>aYf zKc_mkWACDRm(1A}-JX9*>T(9^>Zt1CW`O^EL7b8eLgZ3RVkETQN+2s zy1e2!6w^lnpB3UQkC7p6F9dui6W_sH_cnHN;?OtSxszj4ub}ly`2lt&gxdy2w_yR< zf7;0~&elS4Yr?fQQ&!5eSD2y=S?TYMy+NZ=UpZ&Ove&&8>rm8L+6UDca)%L3H6?n4 zSB@_^Z)=O3{_7y?JQeN@yFfPV3ZYq$6yCCx$n34S6Rv(7=jVLl<<9UJg4S*qs?|?HBx>GY zb{@b^hWTBW>4Mj-ZPBm8QOP9;>~6nNh965sgpUUQHTw zn;}1fraq6zbpvCI60+8tw#vT>?F)pmfhXirkZXzN!%I<_74ox{aVpU;k_pL=AJa)!>!C$)XIEm zk}q5C*6jX~ov`dCHorp6w0khqa(ev`_8Q0tiVLvqhvjA0lJc=AoQii-;ZH5scJF5K z@vSO8m&M;j-=H}CEWVS)n{I4P?Kv!duPRPIirXm%3H2lr!%L{|)gdI+K9Nu}2rZih zl!RjVq!Nmnp1J#<`69~V#QCHA>GaZL*!}M}5;7oyyvUt)VXU$sVZ0CO-ARQpK4spd z{{<`h6&3WBLwL(QZFGfO-JC!KS(_16{%6oM=Qj7ZC5@sD|I}3cQ`50M<`MMC^rex^tYFEa(D zKw^)Tl!uwJj4&(Y*m{W2jzcDI#Spmq#J4E4=@p^P6#alG$vf$X&~`D(r!JyWujbJ# z{d;D?k$Cu(koAe*xeW)(yA}V9CnZwKk5BPQ>6G%FILnJ$3D^YL%Hk`^7}mGk0?}0# zW5Q4({yapAh(C^ad}k$TE}%imHzEjG8w-Ahu-6#ks3~iNr9oe1N?lVVOKzW>vC_X@ zVvuQn8DWCXN&WT$rmx#;d-x;3^bZK)Hqb2~S|@?>fl#QRWfl6}7?{TdtjQ4IcnjuD zCR&ioL|mVZ?EX_wiODA~s5478K51ZkhO}cAETMfn84mCX*F0v~CC$q6+?C!CW0hst zDy!shq7A?Z0gw!G@=O$n4r=#)9^(vx9<`LoNvXiGBO<9sSY>!NN|pI}3(8O}KpDo` zj_|BQ5}=NGm_MD4K7x!{9K_>pHu?mIDY)vB!xU@v)kR!&kj_3J&iGw%2?@4I}JNE84(c?~7{_%UJ*ixxWa0%>QpI@fsx1HN(B z0!Zo#!a-l}ht7auSEQ$wr{Ewe%Q%ruUTp(e&xSvIUO&Ef2b0dSy7tc7{;aU;Y+&cz zgHIXx(%u5BSIPhAIfy7t|4;_QxNmo2s*DY(zI+;LXNh}|$*lcJ_`~J&_mT>^w5f`t zqR*D>MVFu@>3X>bJcBNM`X6K-oChnZMpxm(N!J6MFYO>m#A97NKaGdLc|6#?0U`!N zb2j+gzJDv3047S>j-50RcIcxdT={1BDTMaZPs*|zR)vuuBf5KKrq%}sjHZkBE z*8@Ppvx;J?9mr;O>|5}M&l`rVcE7B!v$54ed;Pbn`qv^`IA&37HQHADRQSW?Y#m!o z`#yxNdIQ`^*~)f$E>$z_|8eB6pPgO64lttP^K9e`?8kiew?E`Y+F)UGL>&6gl!J9@ ziqz28#%W%69p^`^bTkEk8#<@ufn;hE$Ij0f1|~nlX8X}6uw_P~%4P;$6Tg&z@f4<0 zST%p-d8%{rM1T4ZbdWzG~C1 z*6TjxrzrV4q-4n*1?s%b0{ACiLr6K;9fFsfJuL zR0o@UIvM`v`AidjH9%U2_hA^rphc~JhVIWA{a7ZdnCFZb5vw+R#cVI_{aAO9!DP$a zAn!-<5J9Wn&mY8^Wk#1GT#Fe` z?js>ESV|c(@o@p4K>uuiLX0U>PXC1R!hvYoIb z2K*$A6ecvrXb}IZ`V_t7jKm0#4!KbYPQvL*jX?zIB%?tpE4JEa=O5O|$KfK!a|5-d z_u+`2&_f^0(I3+PcK&c+Mhi_h`nKAAnA!llxV^K4jO244_PT%fL&K8TY-b6j8Dd2t z`&}NR@xaWhV@+U7i(sMgEQGY!0YPbzOzX=u=myk^b}@rejda|%DcKW+ojU&#=rBI_ z@4@P=jh}a<0E9W-o72nTaj3`iWPM>zZ;d=DIWmp?P5G~@agQ-BhiPi5(biDE5+3K- zL%x~>HBa6@vL+e}X~U0o}C#jTL6cBM$2iGgA=()FA^NRQWZa zQ*(a?Z`dgPXIhB<6DRzL@kku&Swp=(Ve=nhZgDMs92Hh1JLG^mi%Zyz=$A z&S86;Wf!81bHxR4o8^pa7Bj3_jFAT~>pVq{rXtA;`gn4tq_KqQ&3w zn6!2KUDDPy2vrVeTVGmaw6)rOh%K?K=ImpT4!ePP5CgB@eK?={7l*nyAE`FEBNkPA!(8m$_RRQP+e@D0DO#!EBbt_Ol_^6;9rGTarXexoWF@XlR{InKYUZKG3 ztdN$UOE7MN*}c$QeFqV+dkbJDDKOV7Fi8Y6iC~rnz~B{}qC;5Iyu_wX*uj?SSI$GV zfi-QMFl&&!jwQ>89@VIiifZAtdQ09me=p3&<};rO$L4P+%wM@v2yn*+U|s+Vh`tNs z%?}(EKby?CCQSF1D+o6#2+I+wTucZz2SI=U-=g1oEo$N9Z5)6@A623K8}N%kjsuhY zW{|qpyaT^$5r*KvdrxYcrW~BS0hhROu+qJ9iZ5o0w_`tbcs#WqtZMFJiJQ_d){N|- zk7SMJJ4k^QzjYpe8s&kv=m-{Bke+xyq`qX?Va>TNOgleCuR*G%+hAQ7;J6Bz2 zP)eTBT_2|8qpIW#Rq|Pue48a_nk9YiBcdxF!7FQA=(-P$ao0KT26tf2s2k(1ciue< zevqNTlZ7{E95rC1!Rd!QS$GFU84>hb0gM^2yf4|Wd9n`dkBSlLAQ27~A;Li-A`rpH zH2DPATMn#as#s;kUu;!AB7Q+-eb`mn>#FCAR|rMEWY2%gcHIVPAiN{^q}5TnCde^5Gfi;dmtVZzyYK+aHyH7Nj>IuYmYTy+F$OzsApF z0GLn(>k?op7UsKQc0f}o@w|Hnr`MJ2MLU1?IDQh2%L2u`?|9w&^eIvcgs%e>!OsK- zDuR?O*%JZ&+Lt=mU3Xy?SnnNWpy6Aly`>20yKgW_91#iG7ocIepl}F+wF`XGQ_4Kv z;GYzTh%jn#_|gxRdm8z1jGsFK5LQ2`JBQ46CY;PfK;KcLE!Gu&*ysdFtrpI^3Bi4*zH^9_xxmqr=${0 zqbV}2%ge_4FHeLMGS`c7GwDhY2}7svIxx!L;=w3?!srx6AySPe5;BPjLN^7W7ebXU z5JGnoLbdxS1TJQ%hT#yC)$St)cuQjkqVO-4WRcmvQU7I*5D9t%j4gZgM5NSucAyFP z=hQrBBbJY;lq{4~7A7jaFVUlC_m}W>M7SaIUE;FJs&aae1!iIduOPJbCM&qJRhP$S!z& zj?6L*u#UN(14{h`B{0UG`UqN8aI&n#AAx-3sMGs~&XXp7S0EFB8JP&o$mBpKPy?XL z<^ctGH^7@OUU`t&C+|Y*f6qidbxRQsI`Y~gKvBSgFo5mV3e38}bilsd-UIKjDU?*ynq6QBzL!#IGQ;;k5n zA7iK2&|Nl(VKeDr9C-uhc6tbWmq-z}9z#ty7dWvnUpn{6Q`=)Mib-*%TZLr%?^I)o~N8ZJK_rcYll8j<=f~@--2{p$VJ>R z6}Q%#z5!W@phS09(dAygw22OfkipaB9%BO^TzX6+Y`io=HbJHe>3{Ms^}qP{2B*WC z>#p<0Lhk55svhDQBgyC|^DcfdC_0;Ua;mmCflQ$|L9v-vb*4{on(^UB^`tsZJV^Np z;iBd}wV_RIH?2kfHHvKNWe15)4!CG(o=TP`pQl8YL==||AUM$Q|)^dtJS zB)Y8f?e-M)US7Rg-q%BB+9!XJ3l-xkVAq1$a8(I^I(ZSQET`nU8gfWD$k{=D3~qu_ z4M7ZDU2~T8RK0;1JY@v|20J=lh=vK>e^5~uO>qAjp~{Dd`=gn`xPzwP2AB-%J@41! z4lcF?-zR(Mo-u7`8?ak=4YGI@=u`#zK7w9H(38T0USWVfEG!OwoPw=3REy3DY4PI6 z*Cfm-@3JHKIt|Y#VpSi54p_eINIx7dat6`IkPc_7 zM%=nw=rfv)cryWwSU%gJ4+fkIBJx&F`D0DD5+}uz)M8__^(hWsTrj> zA8tV;WhgXWE|xa<5UPBaXzavbGI(-a?L zc>my5{&b3EO&_o(&8!K7JrWeGN_nZCp!T$|ew(S_Y*TO!BUJez;q17^A_66b$!jKm zS?etfLdwD--PeW>0C0y5{z*|1s70XONT?CNkx+#Ia>Bsjd=764@M4&RtBmj#gi+W^ z-)Mx*^bJ1uD^kN+Ou6D&>2tp*o^ps@@f7>qo9WpqQz_pO;5VOP_e@SOU*jXb`zD~%Y;!eL0L;~#)Pm>g3s(s<{IpD%VG2T(m%$>V z{}XE`gOg?A0L*&lBf(P1;HNeU#9tMNUIa0nAhrZR$n%kyO&j!gW}qV2toTg?wU9+; zsbrsghC_cAId~8deSyhYW__Xl#c%cLDUm1FiFK%%9 z2Jd^6rayRp_NK4mIN>7`B|kbmeL(-B@{(n%H0PSIZ5e%^kmIYHg&bK3RnB8u4qs)E z!?$b|+EJ?icqRAhz$nEyO$e%%?4*mQn1?}>_}r`F-#cDZs`NgFV0vWue)2(y9HwiR z;#}Q=blG~ZAaS)q;_nDm@*A>xhKWRcm9K)VS+Xat9CkZQ8Dt>m1aA$OK&jYb&-%5z z>v&&Cbbf(cI)n&6#2attGgcjzN7esXzM5I`J z+cN>1;l8b+{f*iW!dIshAIHW#7AR$yX{@thV^vj$ZeRE1UYf;8+c z@qKo@x~>R;6TTHL(g-}~yI*|oe+SAay$z3)P=J*D0Pe&4?)Q6`vt%a|+c{Ti3XQ)bRC!$b-$VnvF2DoZ-a>ruaU2fzj`n1ISl%%fd88^lf#=&w0^v}gS3I5t z?pibfE4T&j9rU2bKsWZl9YPIpwxDNxLRqx5&evtoUT+up)}pZ~Y=Y>rY4yH%biC2! zZahP;z6kW}EfrvYBe1aq zb`ZnAIWS8N^4(J~qCAq?AUH^W-ep}I)9}V?u`LagsjR(g#Z#zx# zbwjnraJBn)^0WVJj3s9I@|WnKEC?e@J7%Fqk1WNj*J}1G3?mB_9sg%=kR@fJGbjtg z$O4r`J?Dfh8*X<5WnmauFvc`LlrTb(trr`*3?qv$Q=!TtJ2$p03?mCx{F?t#I3>#( zamXdmVl42Oj$E1_RA)MlnFP{F3ZzFcy$c*txti@}EPp~ab%g&)j-+tC!uOzIz{F6l z$E7$t{-0J`vh1iMtjhYDn5dK9x?Z?oA3~KqIUoq ze+J9nWh-BIg7R)veu^r870dTx`KeZUvAl#cG`CkpyQreWSoBO5J=H8K_=}N+tI{zz zH(LTFZJo|t9b-#=jZ1Of-@?2&UaaLw?jq@i zg$PxSU|S|b+L+xC0GF~NF*c=me^W|%B7`BZ#RU)uyE?y9Brp#JkRRlG&31cTbrsUF zIdAH##(pOFW%;tBJ${D*70z6Jmcs2Ba5|)pi@2>x1a6x^Nx=<;h5f@>$-fjMchW*t z_#X&Wu4Um|voJVQb5>B_imw{%KI(PjEpskl%}Z5{`yE65rx*kc?2|R_*9QBTy#dGJ zu*(YVTu2_2BM!#mlD%;$<*+4lm2YmcHKvru`M*L5l*L}`W$U=*RqNaS(Hzn%(x=O=t%3)WaDDJkU#nrHMcw;*zyAOES<5WO}3i&&s)MU!U7 zU#$DIv0~q#VFSl6jEBUzD#l%)OIR4%`eir}sy4aYal zexpIzM-WwSC@aR)^syH(Dw0MP@TXG;*aRxq_5;(5f+Q7=3(Rx%_{htOE~W34r+;C5 zUW2V(;r?O>Y^I+(OM4(BMHm%P?*7bKdM=}~;D9MuoR5|3@_MUb29kNxJ0ZqT#;|8P zeh)~2Qx%BAA0}7tgjoMjGZSA~lHKiUecr{WqHCChbR^gkC-!1m`z4oh1F!lcc{HHr-|MH}(%@~_J?zrPruaZS+uDld>MC?#Q_ z=6IKF5NU%qi(bCpyu){p_*ZZf0u~D0ZIBE_(e$KVT;SoJ2$mB_-=J>+VE<%vCsvTy zyuiz6GMQT;NQ_$jCP;{5sMc}9k{l@fQNPbibp-!WE$sUMb*_y>{q;W&8$&ZDS zftg7DK*m7k^jH7DZ3<@QtRv0vd3r!I=eiP|bRqp)&{%|V8v2z<2J97X>k>x3-1Ml? zH(vn5F>ZR;&PST#)jt284Q^`b{)T;K8B^3?`(}>$UV@Tec6c&TwkVI9=bx_Tf0uo9 zn(~YFb8O-pLfp>|b6+CP;$Iw|)10&o89gZByUr3SLY%+=2ZrTH1B18jd?ZW^EK+9_ z;TFn&cs}y!*D10%z))$J^Qz|gNVYLpezuf97Wpii$k46U?B2*rt z2we>sWe&NOB0H&@-R&$r4}2jBE8KTeH@hon@ZHV9SK%z>;PUhJTy)Y(WAFhC%riG) z{NbhCqc5w&yg;xR)=FJ}0TGGK&X}F0(EH_DLGQCAK<_J}cN_yOfF1`oRNY#_l*a^d z_=Oj6t;*Ht4Ar4#x#cSq@f#t zg``|{zSYq6Z0OxyX=t+i2pHW(L}#GRmK(Z3{~kymbFU9+DACYANk#cistx?29tVsF z=qkO#cqO1$@}FUkiN&3$2P%O@MbgLF=>5}?U7rmYp#Pt#iQ|G*MbZ+<(QU?ze>dsZ zA`wS>!|Gd40|VF=E%?ii6mzIRNXUECTkB!ie2I$!5Uq;lXYX;`QB@C^=%bmnVrK*6 zF;_zA(M!;wNTxkh2F30;qPGVlpuCI^Fi7MI@s^j>O2Mu2qrNYrPv%(h%F_y}JUdr^ z96djki;Jo# ze6I5-_}Q%8*XhCAS>v7&r~N2=G>)uh7%zEcD#V$NZU5{xs531=NLeGt^Wzif7KIl=(XVXnHXIR zg`eHV!%273Z*`qLKl=}Thd*?c-d*ys&v5MjHwZ7J)bkt271Go?jtXqS>*ojH0RcNa z)qi$MROMT||9`UiqZlqDj(mV)WAg_0%y;A#lLmt>O zIh1@?#^9h6myW!oHxR&m=||6&wE7N6yD|nxlTlxYc8@7b-~s`5&R!CO2UYF% z=8*BtzJQX8Av8I~lCfuS7tBwPf)rE9{^}*-em63NJhV zn)EEGZn)b29qij7^2SWJzG-^3e;=*jy~Ei@!RSvTQ8<1rrUi4j*yN1~PwJ}#*Pgt- zRmc^tzOeVtxZd+ck6O;ks}$?Wm{#iq&MRc>YJD)aGQj`hUqpX14l(b4*?^#ZyeuT` z+o8w_xfdkw&GRi7WEAA-4c@dPI8g~HkPeAdFylf_Hp^{$ul4`OX_>bIX7Wyo+zr`4}_X@4cYv!L1>wIdN|8^gEvc- z9f67#n)|&N~cRM^x@0BKu{c@Swn&kWEJRKwhtwo!i_1tG9Es&89w z0RgvAF!<7r;L)eFC!D220fj;dcswD8ur@eL&k2gdg{^hY(#4Fs36A-!l)pp@p@A`M zVCf*H$q|uiy+mpy4e*(e)he*kGYBXxtMm7>W&ETq3rWUuy+UOyH#7EC8S4S1&L2vV zDwOoAmodQ;#$FN58P{QfEk}+yp5)+sXvy1I@?uJ6$z6Iwa61Ou(0iHah3&ox1kwgT zr2Arp0``)Q7E88e$+u96L3N9OSgj}m$^)F_wqkuI!I)vSP@BvswwKYq3ul0Q#W*a% z^CkRV!#pJ0aJnKCsQSQ4-ypcM)LJi5Y5``Pb^^FRNi6v)tq$i^z*ec4i|&)yBH#c+ z*N8TPcMVj~4X8~fGn@Pn{SqIR;aTOPMsGT{!Z^;9QXzU1CZh<92JAv%^NVv6bgn71 zB$>l*FZimqX_^Z^^%(Y{^Cg(wnE!l}XQ=%IlqCV{^&6svfcRnxzR+q6QzTaFvn7F8 zpbQA+^UN;!GN$BLaPq^7W|GaTcoO!;$upcKkdPWPgBnH+b^3NygAuOPc_u^BRo|d7 zINt_Jz9aEeqN?>Qt8%=+dXB21MqZ}uW!8XPk8 z6{DOf|ME!>-1ni>!>nVF1jC3Vsnh3134(QYk{}V^8;}Gj3yLHX_pud+hiEsefSigf z;S+zpWk@jZ6H={4Xno4t6Zo6Wa zKoeAlfl>-4V^*t~Th>>l{oguB!n08H@yxL{3dHl%Ev3K&ur zv~)|J8zjHvDc4_7dCJLYWlvB7BA1PtoKf^V)I@5ZXOz@O&;wy4tOuUjpv!tz9hNg9 zd3{ZexbY6AGDmLk_@;sNAoK4RYszy1ri`-2C}do}s9=;TS0!j;`of+P8aM=~m=$cW zW;HoBuUE+sGR!FZ_2meL$to6<*Vs~ZY-)!`SyiyW=ZP%+69t8Ss>nVPZKsDJAg=Cl z;EWg}^ha9YDI)6PhJ9< zWY+KtEES-TXPe$y4^WN-7{ilzUV`lD|$<+gQK%SsPt@6TeLC)e+EpU}KoUwnf6f%d@1x=9$31x2Y&1E8?wMK^l`#B%ZtiMSOszT8;A}< z`GREB8?^pGr=gC?jBid)zzeKbkSor-z}F)ET_OAP>WdQCiZ4d@>K$;BOBw`&iO0K! zap)Sh#kPML=KD|P!h9qOSi<)dmge$0lOAZ~{dt9~;5} z+6WO*44>5vv4E`Kj+l~$CRk+r(BPmn{thoSFd>dPKJhJ(l=5H8)0)cNf56&=mr$1d zG3pQ7E}KR2fV~N)yV(l61>q`G7TQN9{at4N;I~0<3lpVup)24SiOa^Ex0}Q z)}KmPA?TU=huB|J-&<*rch0G@T@vRRb4fC&fg?mN-~*cfsK18IR;49%fhLC+elMFx z5!?^yEBHV<^`}dLit(K2pX16Sq+A8cA)`_~f>_4HH^84~@G(ChP_6$Xw6jcp2>O2J z_hLIpiBXxG!+Vp4hix%?e#Ln~Sa^enXb`;`z%3v(WFKWFEtTh?VOBq>UZL{ruJ=P< zW~ZYFmIG=@fOeVmH2a70m~t4$dnrc8oaVf@O7@UL*8jHgEOtnA0OrXq>@i>TC;99+ zm?gxzW*!&`kq0Rjx2rnA7i-|yJOQydau90=V^tTI6BGQ?7Y$%sk?y^HC4vfzX7CJpDV71KYW+Pa7M+*N zGQu*52Fp~Z=w}m-)RMw&It|u%Z~pA??X&S?3-&UX&{qf#d5Kz0MnPy4YZAIizo+Z^ zs67h?&E$b?eDyJakZ^ALLxh8!-mzQ_C{|Oa1DBGQn-wthsguzUkRYpr;G59H z(pze_&F2OtE7}^uB%p!?x7RNJ{~2~fS@vc21+JCZ=lZbt0Z-h>!uUmj2H$paC&>2{ zA}m2E8Vpi*xsa%zfi;VB7iCd{SF%gLm9t>^8_r#C$PNz1xt%|Z_Q^qsRi?yjPA{9h zxSuP#X5C?qKNFsBa(MmQK0ZU`r!N9cuBYsT2HiAmw&E)wQ;HT?{Ol^Pl^z7e)f6fM z*tskHM;&%zq9)UW!5_rOlm)(9AZ{V2MY_X}A!_dgvHt_V5co=nU@uJHB=esL`+BMG z3XJrS`poltR-K&T+sghLR-6z+dJ>W3#Kty>m=J>rXH}>bY8=<$U76t9CnkMc!SCcR ztOUZZUvR&|{=GLejyqnMvh)spi4HuMD+JZ6*xYhNY>f^%r_71rF_x&)11;l={7 z3YZ5?M@)?;X*dDxI8#kPw(;sqx@R6~pa!{~3+Vt5Arnv_za8IYjq)KNC)m8{(qvV) zaC8WLOnzPB>VPe#NvfZMYOwSX?5|>e;2ta+s`gmrx=IL2GTwvp0+(``42wY=8Q;O_ zYS1FC+D7Jtt1u=e{J zsK3G5Z?kr8p@=Pz1R4v(+9`2o;cMw=9{^m5EraS5fZhPbWUc=OhB5O z`lLC&Wc;dfdRAM>AH+VP`8mIaTko0hT1q$NC0|{(V-w)#xaRGl%>kFQY2i()?d=3TJoS4cBmp*I>bsjt1@D(5exKxq=U)m|oqx6}Qm>!RxrTQknQt=# z+*4B@S=qv2z!Rt0DpMT-_(R6WB_m34Z7(?O*LO>tQRB}DnBupA_oUR3S>z><27NX$ zrP`h&i%0tH-E^<1S04_ z`eIAO;Qu;msgPFW&#?U`{9@Bj?DHwdgy>_|n6M*c_9y$l5p|+f27jMQ+MHxO2>+_b z-*tXQ3cW(IfJAyM%3^Go`cO0Yo;`Tafimz%{RVuRbw%2b`1(S#>MVN23Vy8bVt&X~ z$X>1gNZwEqIaD7I`r;ZC_(~Rz)$T?dKhpd(MFo1XT0bNpU^x)-EYrKI@6sU)BnZzc z;Fo@$=dcd-2PkN^kKcR5rQ#48u5S^)Kzlw_bOx>L`d)K-QA@Z)zOBJkOFrp~v1!)d zJb%dnAdfO$~>xBKjxCKsxfJ*Xs*pWT#{I zaIf*Tn~HJIViQpBYjV<_dJR%XJ(RvojZ$fCG5kT}Yj-Rn^cm34m6XDOqh?zz-#a!$ zPtvOyWYBKe@&i?AGP28l0S_gh#r67m1VGXibfp$$Cs4?EF~+n0eovGL8jp(qg2p>= zGsco-&I`#s{WN{#5myu)jEVS~1_5Yknae*YThr zL_8#9JRX%WsEE%v4yS5k)1GVf3A6s)Wa6XR1ANGb`Wk;Ydmt|5X&nDH`!wHLGbKXM z_-js2Y~Y-Lo&kE?Bq~@+ki4|y2x!gu*elkIVn7VyCsSU_`d?+l`_t%abO-vN<@bus z@xbpj%BkCcW2|@L0(dn(uDQH6)8{qTpwm-=R*Ov#HgV(7qKupK!nn=U>G-J$3!?QhDi%) z_`_>tS$M!|&sTVV07rD**~Qa#`Z*{WFh=Z_0gQ2D=Z6HrzzBA!h@GQYB~*o zg+T!sa|^BRYl)n2Qm{N~&QDo9$s4lz2pON&`lbg4D(y>4fYoH+ngU$Yfa{mQwT4Y= zniea%pVJ%n7U+Rq5C&J|kd_B}L0@m4^bKh(kB-S~%8rxOOj^COw4>Rb zkc3@OQspo+)L9uY$gA~ZILZ?|tgplA@_-C9_*c=7@@BB2aM1j^{0Pk-WO0(rvN&MP zyZqZGq?PWQau(VRg% zzINaac>F)f6MQB5ezhD_5sAigmr#6l@hq=VA$k)p-r> zL2S{fUnq%JQB(sKE7libw?tw93%DdL!{Q3F$yxG)R}6o}l;NL&Vlt&{#PKixAU2qn z*d)Z=7AwSx^lgZOXN&$UJjZ}y@NKqoeLZ3RigHG89~Ry|?B7j}Z4Ehme~!UPhp<$; zkgT=Nv*5iR7-c0l#NsW;Sr*wkqhd;(ilqK&^r>4bV3JG>bww9n(oHjj0=?u%eG~8K zsrELi%P#uIi1Zsg9li&HaPh^%u)lmC`ADuwY}5~fkL4blZTht4V~nT9_}At16y&L# zN`-!5or1#GXo~Qr1vUntXz+l}Ahdw&zNj6sr!i)~{%7%X(ZN-KU0(d(#?M7$nU?vv z$AJJp&%78}O@4j{9HaWpfDyeZT_`X`eiT3VL%G11HTbz5ThV%c_V^~m1oLy( z_AT=B|84vh4aNEd{I>B;i>;Er^GNS2`I!ORZ7{zL#bQxn41ODjNgw?7`E>q(-(Dg= z{%7*@dVmyuTLe!ye#;=t|Cjg;M;in3^8naN$H((qdi3r=Rp9%ctfGO3rl@2DE7ohkElRTpDAUc? z7t~z5TocjS%w01oMF5HKJ;^<>1Nv44C&b?4GL-G0@;BJZ(rODW2Zs1U0^qVx8yg-wGoO2C`X;~s4wvzd>^mn z-!9r+hkPP?RfQ7D)wQ3B-JVDCvg>17~ zJ}gjK#$%P?TD03USE2qw)-Qb7)W63RO>64kQ`}zSo+YkJ+`i)W6Zaf(2a0>HxI@Gp zCT^U#3F0P-J3`!KaYu_gR^0L8rieRH+*ENViR%&fB5|jPJ5}6i;$9~1<>Fo;?hJ8f ziaSf(Ys8%`?i_Km#hokeJaMlRccHks;^vE6Aa0?!*NeMU+#AKcS=?L1Ef)7SaZAO$ zUEFeUSBQJ3xOa)WQrvsRT_x^nao39bpt$SAeMH<1;yxzs6XHH4?nZI{BJO5!|0?bl zasMXni{fq*cZax@;=Us8E^({G-7D@sarcW`BkmjGz9sGfacjkWPuzpzekg98xSxo7 zNZilGtrzzzaSx08jkvnF--&xf+#kek5cg+skBWOt+(vPK6Zdy<{}5M8Bi}}d8zpWV zabv`7FK$P1JBu4D?kVDS756l8dx+ap++O0IC9X@{zT);1_Z)EtihHiOL&O~>Zk)IY z;wFkaLfm9=M~gdF-0|Y3h&xf-RBk;=Nai@qoRorRfUMBA4;$9){3~^_QJ4@Va z#GNhf9C5S7oh$Ai@Q|Z8^yg@+*`yg7WX!BOU1oi+;VYO zh|0eE> z;%*anhq#sEz9Q}}ajV4LEABpV_lsL2?i=F1CGG)nYsGy}+=JqNC~lp&pNM-%+|R|W z7xyc14~zSaxVpICiF-ucAH;1C_h)gBihE4lMsa@=_jhss5LcTj{4Z{lxNXFZ5x2d# z9mVY|ZmhVch}%`%)5Pr|ZclN0iF=l~E^+&c+fUqc#2qLuEtgIGhlo2&+&FO)#7z`; zgt*D#juv;UxZ}l55qF}vsp3u&*CXyl;!Y8Fs<_j{y-eK8#l1q@8RE_qcb2%gB1Q;`gHoT>1&5QXa7w4uBLAqeY~6HpG03oBz$A(yMn$1`u;-SK>GN! zum3FirePb%-<7@%^tGq&2z?rT1F^jFAA><}-dy^Q(Dw{|U(xp?eSC>zUIH#2_z%#R zOCKK3Lv8d`()TTWe8**8f0zgSPtnJdH-0|DGH)Gy_tM9g^Za~3W!_=>ZlSMV419(3 zO{VWU`mUpIHhquMcLjaB>Em}c=6y!rMEX*=B2A`m7Jb9$dw{-v^u0r0Px}1y#nR_s z54NH2Ec$+j_BRimrTKrRuaNn4`n>dgPG2Q`2kA>-i8ttbkiIJVUZ4+OzHORUMc-!n z-ly*|`o5xXEqy=Hhv)Ku0akndQu<=)yOF*=^ySkRN8eof&ZiH1p-uBHp^thqMrMxjurkX_I51#xpgKNA&zELfaW} z2h#UNcH9)DeGu98r6}!($mHrM?Ww5wlJ`vQOQe74IQ9KVZAC=*L8d)Lc8hI+6e7F$Emoe_%}!I#t7|0M~^!rwI3YYfHZJ=sFNeAYizPZ zfn<9!wR;e_#}W7UDD6GR3y!jA?TN@!ABfgoiR}Gsv{oP4dr!1h8rA26XzhVEV~~2V z&04@Z67zzise`tw{i*kL)IMzA`{|C_Z|!@(+);a^L!Wm#YWH;-gVY0^Y7N{U>f&f~ z!KaQb5oXOopVPG40qXXMGd_#Zo{C8LK0>RDm}#`9vj*v%He~}oisFD|k^JG~u*WfD z+H(#Z1vc}YuHnGT$WB`vT3RP;tCl!U`P`x1@0d$4Y;#8q=akOu=+*{}GHBAPU7U%T z(CCbz`9a|;WAcK+{o0QT3Wt`D9d&t7`hQyfMERQ>y|oDtvfU3lwAt;xa%j0-8XQ`w zqx&BY?IFiQq&V6bb3ycU%`;g1XRUI4>{uS5{TvaCFO}_z> zv?`RWa-4<-pFR}6XFU03VC)4}Tbdjl${g*$op(6^TBX}*(c}mZC$wCX;}q%NjwKFl zQ4Bb+XrkbO`l4f|-s>6Bl>-QeoN8Nj`I9>Z!_daV+*UEY(AoatZr#{n5`=Mv=?Y*>n z&*=SHFKycyectb-Rh{`9Yq+b=sbBWhp6b*4$G+MdeR}`9ul7TqKEAWH*U#QX{GRH6 z>aXW$yZZOOV}SNm|K9fx&~87c&*KBMh5>@U_uNwt4b~n#xA%90wb#z=-8fkDpW6p_ z@%9bb!Nxyy-l;#tX)m1D`}a8Qqw{*Nh}ZsgUZ1t`+PXMS;liUG-f`qV6rt^o__GSf zYm+r?@~J;XXc^thBDGsPJ`ky`baZ_-QhUbHbx)+W-_hxVNNsyWuZ>aK`w=`-smjgK zuGF+EV_{2M*mb`{D|5tRC>?cNhKM&KdOi}R{Sx8Cm49z!Pkgg}V`TT5CuJ}=e&Wy` zb#y^bzv}3C%%Q#G5H%wF_)ng0jin|>`}w)wIkb-)Dal4G5u&Y~2 zP}n{enSV;h!k~0}e(DD=V9t6WqUXj)?Y)Su+ak5^Ba-(;YL7?WV93!|(EYDCVj3OV zK1V$?L&bBaX`H9Z9s44*e>nQT7opu7QEKuDh8bXPi|Dy2Qu`pH>r0rhBa-p?$)_xs zPa*45j+l=f+Fu=f{7%6<**tfO=0#p_L_@pVBeh>USbV8u;xGvO&HsT+yrkoT6VT;< z2c}&vH#ttz-hkfyM&ucfMrq$gCOj9Vt&4(LQ0RQV24m~heb9yyNAdxO_OgSArk;-M zvm#1+J2H7~lvWnigw~g~b^g{?Tidp0d5pHb?RdP&^Gn;?NO<8b``ppwI2k=poDSZJ z9@*}>z&y~!(e`u4nvTzPHpwP+Mqd_P63Bxxm-V|R5Qd&Keud+GGeYo0+!&wZ-Jm$| zseRrh-`d*}%Ez1sL-i!)3DsNddPkEZR-^9ebIicojbA%JZ=uqJ~=ga?Ad~a=xrj6+iW%bIg&=i-p11sI`=<=IGTVv@{y`WH2 zKkxZ;g!ZnZ>(&VEJ4f=X5!z!BYTTbJz4`bsbrbtI{BOmv-}3K(A`;SXSNC0KvYnE} zL3+!{d5XF=G|Wre%4@3=oBw9Nbbu;UZcbs!ZyAL89 zgC2|cI>Pa0!~{*dGqU5}NNsH-wqf6ljQ)G1qc*aiJb1`jq>Wv)m5@9uBb;>++WLqG z4SCJ_`?hmi^|PI4YueepGqj1LjdDuPJ5hY=33Tvwi`!x0c{4R|gFbdy0J(W|Z-+YdWI-%8qB=(OEmxvFH7rwSRT&`FLmT z!A{+u@2qX>G=6ty?P#a1Sg=3S{n9&6*M95XThkusG5EpLwby%$-*~!q$LU_kXTbsd zbH<&HH_c8o@QOaC_j)r*`Z?joFN4DiKMD$;+xs4q1)Cl^-Qm=*W}Dmlxd=y@gG*-o zFaHGAxxIg|$~HN=Y8PqRMQ1$f(5_3sVsM?~0LU)u^(TSjlaYPOqtIQ+tE04%C`z@v zqWk<5t-TnX+!U=HiO!I`PHmi~jr)dk^y3i#$MRh@oH>v>a`#p5ca$-JczCP{IJ+KA?yyyurf3dZFpkcG< z3OT*g(RDRfa6_Mn&`Kg8(zN#@Pea@NhA#16&nrX`r{Px957Qa{-6}4ArzYnv%$v6; zGdFicc1~gD{DtxHd4=h!|l85!{jaTytl z=Vcb;WM||TqUfUhg_&777d9)K5H~+Jzo;-{PSM=Cs3J2vGrusWz&&+(#;DAN3-huv z3-bytoIX6mjepH+ZlQFTj0vh51Aaz+L0(~AR^CD&tQF&LH~uylzr`o`U5_*~edP)A z5uTaP{(EPE+!Cw^q_%8*2&FB=LkOwN|&CMvt%)K@Tq)=pzA2}y8J7aE9ZWhU( zkp-HCAyfQ_`MK9;E}Wm8F(1SwNyBA|E4(2;$L!=V7{upi7A&?h{HOgK5B%BDiwg^K zG8dU0ePNb6w67Ce>g$#vG)FdJxKUkbhqFQw`M>%P(j(|!yO4ivPx3D&CgOzu+DF>{ zMMXw-Xw#-mbWGr%=7@-lj%f=VqM$2=`KL)78y-JAVfgUjiNlkIj~G63c=GU3iE)YXi3y3r6B84Y5=SJC zOiWH3l@ym0pOla^JSj0LDQQH~$fV??Q6u6;#E(cAF?>Ygh@=rCMvNShJYv+yxRLQA z6GjdnnK&|OoPeS-8!dqW|>e;(D|M}regnvi)P2Ue^FX_APyPFV> z!sN4P`qGqpE_~~+s}b&q@RbL)U46qTV{dyNVea{iyy9PJBUZ)k_kAbfPq?lo_}bNdE9FO-Pz-#4GzeQo>1ACnLsi|}24 zOFH*o*CzjM8p5dvk2!z;dtV%^DaFerO;ZrAeEa>L15!VGtqkGI5nlaz|CbM}UvS?B zgl8dK`sAEt{T6Qiv=U+NaUJ_4qtlGJn;!oF;e`mF^V6%J-`DunKYv8H5aAugO@G<= z?AERA(e|4W_FZ)I!sv`Scl1ZN6yfP{dlF|iz4H3`2;Yft`Z<;N+*vkt^-P3UA-waJ zLHYfb{Q3p=m)0SC_m02sSikd&r|w4h34~WID=dE}-U!n;Xj1G&TnWXKX1L`-&yb<#^3inyWE={^Y>S7f&U2p-YTD# z*Y2%X?tB3Lqxc(=bNW{^x^I8?1^9o*pAx|->u@x`$(;LQpFF7R2y;% z?*II~dTm{d4ANYq4LU9YlC^T<q0mRI1h@y$N%>yVjmiVa7Tn6?zryJe?1iYZ92kTnSON4 zoR3`tH|HbV3*oYNp1$##i&Kkz2=_yH=x3WFQx5mp%_YYWgzs)jz2>}i*WOiya3aDJ zcHFt{;qJo^euD5=gr7O%>lg3+^z=u5K{yp*Q>99tleu_)78RBGxz{Rn<-#l|r19}t zP-rs>3o_>yE^e;4K(U~TYUpK2b|6r0TMwbV%XJg}T&}+JbNh~V^~DU>7vW{?HKn}e zOeiSO7G=)Qy>4+{?y#);0l9Dn<&B;kf%pM*;Vs8BK5eakVCd9jj4;wiwPRoL#R+yum zSG2g`JZj<#&zql{wXi5V=R9+LaGszr4=Ci#xh^NG(A8(0E4OIjLTLP&rM-{6eEjIq zMkq%x%P4f^4ss319pK`^At!sWYfi!-wFatr5QTa;I{Si3f-Fe5uBYyP6lg&FyI z^U)ws-cD9Sk#|kJByEgqQPJW;*PI+z+*0=>I1?w*ndF*3*LCgu>vM9o!h)h4ZEohm z#W@ih0+9XI<%oQ!j{%8#WBTlO|0H3n@6u ze+WyV#A=d_Y9>yaq{S_bi*t<~=gP{<&XLY@W#(qvLP&~R8XpIYCN-;XZeGEh`Ptby zxh@Ks%q*8%A6?;1G$5>Ly3;#&(S0e~)_(K4Wf)&d&t8t6U|py90rln6kVT;4K9iLC{c z1VB?SZ5dEfYXOaL4V-Yn#VrFG(ON(wT>~e&Ptg4%TMH-|fTp*MP%@?5tU0ZPHp(^7 za{_{o5@?03g*L%8aLS~Xaho8}a$5^+qHEw4C%|oDYvEkr8aU|$SY04k&225TRM)@@ zE^E1ssRFH_wb0xg%q>H6w-(MMz`3wxIL#$ncqtVRDU~|K-6Ej))=H^(NU78d;#&sP zS}7F|DV2IbLd$?!E2ZKgrBW{#-ZG%pN~w5AsniP+TL#oxDHRVXHFZME!X>`7QYs!& zYWkn1wv170rBpnml>73DEdy$;l!}Lxx?sWyFiLJEW5+{4xzk!kXjE(AKr~HHKS9eT zv=$Jgl6(3EEo0PLu@q0S)UqItzo4}UK_E>&0i4v;!OHD~jSFiqcO2r@1Ja zzi{DDC|Zl445eQ_X=pMuN+_Syxh<6~NP#UHAUa(uv^vr0a-k1r5G2+k%1*C|wSMt1 zu4V=fqVAkPsog9#F>LGzrCH||Et-=Pkn<`y25YB$EV#@Ye*bd-t{>JbFoTragT!QivijIZE@z(47F#0g;Y*K zZstN+>ntwB5@E5m%8_NA0a)Yu5(|{;b6mz6k%)|TY4f1TFU(QPM**@RCnq24CFtfB zpn{yaMhsQEf+R@TzPZV_|gp6MT>J>Xz^kW zz$Nnw=ee}NK9^>!TIb~DEzHTx)w1VftyGYmlWp*ojUNPUF-w3QNMwo7?7MQBZG%i3 zn?AVzu*4bTRU|OL-l>M7uFOI#pmTFv+7K)a7Zxqbb!m%l$SurVs`9wBCG+Ml%&{0* zb7`>MjB#NFSO^x%%pMKiE`q2rMn94Q{;@^5^K<7H&c|NgjXBxl#Q7dFq&?{-_`hAhQHDH8!|u}EA3Tik0(t?d$De4C;|y`lae5r7T}`X z1-W@ka@AP3caX`HS6!|8C=+(1ML7lYvs{@4*TM(GgX+7RmT5P&*I*aZhP2nRix%Z; z^9^Iquu#6tQjEE{Fnjc9ispgyMFN9mTFTmYw070i+EwjkJZl(6##($bUYk|a zKQ3{p@nZz~4@;O~aY?0~&r*bNrD#*%Q5h{lGxIr9v4#cPFmDi4?*6q&zxE?FgK zpbViwn()_946Xw3+4ylTMK;w5Faj-t!DZ~Eg?X8Um&3jWiylmN8Oja=RsH|4cOC$4 z6xaWsy*rx{ibCk2h#J#^?tFK)2{AIZfCFR1*%$)JPr7FN>?_JO+k_&zDF%T97!p8) z-hv>6UPLdZh!QXXg6Jj~P(ttj@0<5s-AO0e#yD`t-v{2O&(6%7vNN-@v$JnnFmHj` zjc*r5Ds-O+XY5-yD=;g9J3&Ri#8lwyu$^Y?+uSBTkQupQe5csHO<=@TZKifKcXn6k z9mzY|i|J8Zu5R4x>)X5A8ZrCW)QM`-fr&erxt#UODN-$cy{AH5?WVD*rK?T~*Jp+e z6EC~&>b2*#^Nt?v{=y9sPUue~E#0_F$qlnL)Y{x8kaM;NY{xEj4bx)LKxnJ z>YLl@I%bE^E$Gd&v+FRh3+EpkJ|gm(ij$gZ|rSV*$#DT z##kFiP@-^0GiJt^mdLa^JK<$rk=7l&@~^tm%-FN8wbf>|p`V+Uq*k8LR7_Lu>t+?H zQKh}7kX+SeBIUN&8zsU~CQ<>iWhXyzYFMEwYR`3}jZ{}6Kep0thugr;Uewvn?s{A% zTfVbVl5#l^|7;XJ6WAda)>dttFPD2mmqetIb~N>+E=-=zu*t)y<`8KOsH4A=8t@C> zFN_R1>)a(S2A5JU4NBFAY5ZCCx6~&I-)8C}5xKeay>_^CGHHiPhh)p_9mX=DX7m-N z6C>C9rm4+s_7}prU8>YgtiAENH^xrsnH!sBiH&rn@<@&s2)LHU?RbCv>+H`Rb}%y3 z>T~-9qSTNL+<)74;+P?;I~#C&jFvG{>YN5|xJ^s(p`Ui=cIB>XS88p7cRzR~WZ&80 zwTrBmdPT}6(=@U_&7kRE(Nwiq%2`6Xl$>)pIC3mwOL;T<7;A!CA&!3Mm~g!DEczvA8w zEBKJnE@S3H`g)Kb$lzi4j0iG=?`{@CdZRF;0O>!N7b0IDfd695hLGt?QT~vz zE0I6Q%yq~gq~~wQpPYwm5xxQWgY@5w{6VH6{|xE94fzv>yd5%gJMsq^T!?b~5c&Kk z-tBz^ei8a1lds@9LHfRezmJh`yaiqaiG?QSQ%HY_V^;kH=T~*ihLG_M9WxBlzma1` zLdGEXf{fw?;6ad)O&v20(rkv6!;oIDW9CB!w{lDZ(zA_Y9)9j)Lz+pBxdAc*c^_nC zvSXfs^d5xI0wLoEJH~v5bc7r;4l-Him`RYHX^!cF^v!V0A0hp%&<7dsa?H(;scy$S z1R3jb%tFWrUJfsY^vs67&k-M_2QvN#$9N&VM>)m^8OEnvw~PB_NIzs0t2Y-zda>ZM>i$ke-=HBV-tB z?JpKS3Hl&o^PmqhdM@-q#{X1eUWZJd51sg8B7Fh;LVB@)bQoj`3*IL|`maFxAd@#D zEMzo^@_@|TQ(~@$j6YCfZin%b1&CWQFe%n_Lf9SU(!;v=h*TG8TL|~FBQH?aB zpN@|*jt^_Qqr1RAq-R&?@f#B!13hD*XAk29vCufR55l28PEJ7DgE+rG+z*ETLyQwg z|Ld)TzdCR|{7pr?(~RSpj(DcS{|v-41L zhxD9h9N+l}kAIo-@%sXVy#Qe@LfjW4eHTM7`sLWA2!9#!bs5544tY1?zZdDbA9;Qd z>0N;QJPLjj>01Q$GaHuEQZc^A>YIK51{u$=;++k$`L zIGOF?X9xJLa7?_yae~7glNt_L39f{D6}TF4jY6EeAP)4mvE3ZU3s?AufY9PxW5Vax8RP??NaaH z{Cmjz`$$g){{G`Q=D+awU$}n={U5Xgx>?Af4_??rm=gYE|q*Tc}e0R9U6B{2pShjg=Jr4N0Na6GNj?4al0C@Hn)ll98^s?aX1 zd;WRzYYjIN3!+5tH1f1vsgE*BnIHbs(dutQh6_?pldYX&I_l|Rz%9!!Agu3ManaXNEv%s#+X{9jAccJXQ}@< zo^gbI)FWd~;l%R{_XXWCW|Q-N^dVOMOJx#$hH&(4^6M(i2R#2J8GV!ZlQE#kB-#Ix za+>i)dEW56pPYI@{Y9hn&vNu&tSS0@kEsmfdo1BN#zrfv6WsEBmSc*B9k|&jM6=Q9Qi2v=lNh3uTYdNRSWO*N@(lcLW{8aLZDuc(WjG`}=_66JtSmCQg`US(pO)pBU(WkqQ7O;#!l?t8 zzwOjtjP2HkF^ISaN2-isEFkQ0`)@q6T8`@Z2+JqK_8n*WB-y@GU#kB&+gUQLY^W#5 z_9@T8qBrx5>h-eTB;ESsrJgNR%Gh80%d>zD$9_znErnByng7$s4=MkX=U=CcpQ7&X zk>wdz!pk$P$l&TK<=Njd+smi)U-GW%U4wFcN-yR1l)l3>yv#+29+|TcDbGwI<(bw> zJWE;kHgz``;|hmy4;Ja?`QR;jK6#+ZU`)e%=&zFTj;6%@*@oYXTub>|$|p{%G6pKKDe`{;~Ad+7v&;K&rj7~WQ^u3=E@#D|6lt1 zl2V@iC0+7tDpH=^MW&BX8C_S;<6BdEUY_~IU7n3adQPUl<9QxqI5{7jt}M^m!b5rg zOmEF_zf>8;m`>bfjzpw9!`tw$sg!4UVR^0%*V!*TT}j$awO&MltDa)+W0qCIiBYy zQ-)oCes#}mrsFTmn2$J~9fkcY=iu*@aVqCe<}Srw{@a?&$|ES} zP@X|~ALZq2x7SnNPWb@kR;klpj-?_cfoZQ?5(78Ram_3d&t6lbEZJ{NeFm z{~R5^x#*rx8$IvM8&A69Tz4GppUiTmboIF55`se)AvpH zW_js${S9-+!}y>?{3j{Xly3emVtAJiC2z>^uD*Qsu>ZqbfSmL+^7+Bdx2yL!o_F=R z(tRFqpDTPLwB5MwZukrH^t$dzrqg|1@$o(xVL7|uA1D&ueQt4|i{u$v%F7M!#^XN6 zxX(%6^K<>V@w{0i9`|`Dp4RdTKam^WjVJ9s&rH(#8K#U;y8e=6H{PLq{&3x0Ig-yg z!QZI9C}ol|P3h{HM?Ef2ArH%YUdm@TKF`4#kC!s)I#7oF+MY6a=9O~xU8^!ecWjSp z|FZu6s_tR>i_+bdu0N0KPC1|H4ezG$Eu=Jze;8$uGC}t_l#3WXNf~AOmL~G^QOv)a zepeRtSIi;rysO8RdCpmM)0aI_)q>;_v?mSchBE*S>~Mk_K%yck((}Y%lV_Z^?v7bJgtP4C9tvtR+hlZ5?EOR zD@$Ny39KxEl_jvU1O`J1xLW`XhP19sSpq9dU}XvX$Vy=4^Z$?Rg09TY$`bevCEz~)yYKs5=^0aaoq&7Z_2y^<~oGX($K-;$Qs87@wl zri9bVzm+AhvIJI^z{(O>Spq9dU}XucEP<6Ju(AYJmcYsq_z{)BPq$q4z}+LB$-5si zX5yIIag)Y|=aqoN8;^;2YR62n|3y}fcqWaBtXgaT;pmyTySS;l9>vcA>c>;N`$YWr zJ72uS`WzcAT{RN-M?Cm%L;PEH;+Tnni7dl){Grgn6ZYXoBcrnW?9FVdn*l?%-ECdv z*nv+h!@*P;>qQI7#Yy($#SCqgw zpJE+@7u}R5Pziga4RQriB{{{gjKQm#p}Pr{4twTQ+l^zeUtx41GnIEumQ`oBSof7Q zja;52Rl`yq@*4;?w7_)IcS=e1tWGqoHdWTlkS%er}&RsV2WWG|~7Qt}m7d zyyW(UZXu&9&hBD_?5r1GsI6?$Nd% zqJ86pJ@Gl(h35sdJFhku2%GuLP2%RHJ~zkSFtw~ zi8<|t4l^fN&qWGOYc^7+cdC)i?VTZXgVGszw2)ks-BzH zR$d*-<|iA&((gMrZ?gOf3iZB|dVHa_ipp$SmZ^2=EpV2mWVsZ4i=-^MxoT4Mj#wlw zOHr^aNm;fIK+}@W_5lUUXBkx$N>yWB5cimjY*#3MPW)5-fuA<2#um8epKPmZHPKc3 zot@d5?-Px?E)?nRfFb$jj;?OlqmM?*q#29u(9~HlR}Y)4?J!i|+%-GY<3soGCgXQv zKNCOJ;ylba&j?NJhM{t_#KzezjX2$1FJ^xmVF}u%vv>dCa-UXx**?wf;D@)?MX>E| zd8oPvTL@q`VEJ8Mp&r%lv@}GV>%Zk)dEbqh?Vfk_vt~C=9D(W`DzB_-YzbjUHZ?%r z5eSs~Bwn?fKcW#fb358+%Z9()S$c#uJ{`hsYX6S;r2{JE!(mPrhZ6G;z<+04q;xz`h0pF-;;;i&XA`s$3o#>29iB zvqyb%Z{DhH5Nt_~jFk_!5Ng6+dtIo+wKlhb`hk_nYTd^X*QX*>GjUW1iIn_RwqT=t*>4i;`V6Sn@EtRThvL0utMLJ!yWzNO za?Nm&w1N$ei&7xjDDuD{D00;Qy=%vmhxU=%+W@Z~Hm%ZP2X0d9Fm<*20P8!NX9ZgO z^=5ga7j%hTcIIVy2Sz=C5!iEs1FultK&(8}Zxn_WZpTtpp@}|R&suOGFm6&qYeUO; z%=lq^RT0{A{C>NS86OHw2$j3a1A!?KJnnUN499i{fe|p%KNCa48uZt25Je3=J)&+> zXum>t;QU)V>py<1EIfW3!#vmj06A{_L37;r1LSzt51Qjy zKR}LW|DZXZ{lCvKpQy@xy^mk$!18;YzRh=dpXNKfK=Z}9{>^uI;pRK4@Z+C60Lms! zA`Wf_ zYzoXCG|9I0hr49So2=bK{T{FeYBj2`Y3CMQHM8^~vu9GjvC!a1|Lnn*{z@r+sWRh2 z_4U)I50V;>${@Ru25P6(PM=mZ&Gv1s-Bgf|!GUIZ;Z|h8T2ZJgujtp67mKaDy=xlw zoci9P_}i`-Vq`zXpOro8Y=D7mUaC0Dh~ zC0EgRf5@C9{BN#Qg}axV+@x^-myGfmBs8Th5U8>fu6P3z{~|lFT=fEG>1gk2#}1u{p#O}k+hbSa`r>7-t6gTzzuSey!GKE@j) zIgx6WeLMGK$&|jJ`EgvJTFjLFNOFQ1updcIFtha|$q8nx25nBb12*TJ?0vG>6T-ml zjrF$3u}Z&p6$AdhSjmgP$&bLSL3ahJn1k-N&gQ9YO^wB;%m!*D8jgLN?V^OiR`#eo zEiHp@fL`s+P!xFGInW#Ii2C;SmZrM4{;O98ddf%1Go3y@^jogQv{(3=X5rZ%>*{p& zzN1@Kz157*8RQNR1V-7peQ{mNd`ESkS0~j4UY+1v|5qo~{br5q+upIoUY!Jb@XA&m z@b(Ig)S4v=~1@@|{oF{dL2 zZcg1HjvZ$%DVvdw=2lE$_cUea;6hy^@I^|f;1bhppH(Q>C<#_%73dNJMj}P;rxhb} zrt2E&T3YJs8fFZ(dAmW7jqfmlHyCoaEHin7ARqmw^kfBqu8pmihvGm0^Lxc!LJztO z<_v;lG4PK#uQ~zv@<0=Y(u1zlN2qnGhUQkhk{L85Ke7$4 zkwW#eyD*X47V4;Lo7xnBK@zO6#Oy9?HXMpI(k-xTRnt81EB^4h#>PN%k+(?$r+rHE z90ZNBQo6!Hkj|=(CcHox3<>Q<;~ESJm63E;`;5frIjgCTEAc^Vs3nXIzcE>K^KR1f@1GD=2UcGOt3&AYY)ma^{U`}kxS zi>LUZp)B#(+jR@I18-GQ*p+3Qe!!k%~9Ufr1r%ZuS zV1&cp(t}miMIy4qu4z`Jy$y!0B;e9RRWpr^%~PAZV2oG{rq(v&-Llx3s%mVWJtY#D zSQ*0q%b=^H$=)R+9kTePxvR5gHcD(sRiRI=M>e##;tRbd40%vmbsf!3w!9@7u*i}< z2X#wN$jB)$u@`Eo>zE2lc6e@`S?&u=uPydrac?4qS4$7vP}eX`zBg>2iRVOI3o+PN z*D<@dV3%I3T5#nRZE_{$ffL=jeBfLWTGp_`Tf18{#Ih8<#y7mPyZ+mT8I?_90I6GQ z(XzTMe7u3IYYA@vjHZ{m=B$t5z5$Tj zWmxMruoAq4HFizEx6dsVzCw%o0_cnKt7=PUpw|7CmG-TWe|<3wJc+^W zJS$T^*UFTy&x&P)&NFFc`(=Dbilu+;4Rx|My4SMjm?G?SlNji%781l5xA^5pMwmP z;u?vB<$iWBU{cnK*@XdlF-M`y@;<*GD1|0T%X{}WV3KByz1X2j|89*B!+q_cH1zaN z?)By&>#^4!NQ2Be<=-;;_S-Ag!k@&IXKfIsD{3c>&6+uMAL*CFpy43MXx6sjk2{+f zf~(QWA9pshRt$gK+02?QT%p-4IM2Q0zUcdyd&JuW+y<7GzBnlUJzq43{xwvEwBQkS6;FKlwvy>l(SyA=v{rFrCOJs6dfiFyt1|nO>BG4 zzCRocg*{R#HLHlbc6l(Q+rDXHy0dl@iY9zu&ED8m$%7=VG~+i&QrlQ)R)KxRz^Vh7 zro(J{z@3fjcmEz(scnOi(7}`1NbhnUckjx)Sx6cFKYbwuAi zi?FLw)65!qktP-qC1g`uU408y>rJUS2iv4o{JN+HKBNa6mSse;tc2_f15z-Bl z)Xb%n%5oJ{px4fJ-qfr+DV&`X?%jD{!o-n<9@1@bmSdwg>>S0!xt9T9(PEHF?kFRh z7N}+H2@|WZWr^MKLw2_7Xm7_z&1Rh&z`2{4avQ3er6d>&f0n;6vb$8_y4&9S9Z2kL=msMU-6uhhjwrG;-*w7Ma##R_GJi?b4G}?+v>hAi4tu|QC z<&50}s(1#)UTe-SYyBG7cg&z{|AR>S*V_Ua+yfazL#^Xxi?W}cPpgNU%f6;%^D|Z9 zQ!BW-NWisg3p@Vht#vb+LK?JY?{RIl`?R7y;U%(c4V7PxDzweJqe^6;9VC}eLQYQu*GcF)V2V2^~y z?qXGWWtDfsD=%;QJ>C&vy_Vc}vgH2xb?JMiqU3*%@Z;tWg?9%VTo+~gAYFM(q z;Z0ce>JC5)Ymrx8Fr5~t#g$yLvTEI1T0SDlZIO8ycJKY-5$`Nrvv`H0AJK;Ujil0j zJ5O)Rbu+~km1X`lLA)5n70w-5RGS$_h?`c|c9m4(rQi<|5LdJ%z4egQHA*>1!V|6k(TEcArH)t`OEmai(v81MNn#JuP zT_6S@atp5x9VEL6xhFA1z)inE3OXbB8i?zQmUc7mO`uK2a$S^wy{V5Z*88Jvk3{P2 z&9Z!?6cCJ}i*>IMRzZpF9kHQ2Hm^P6LfeAumR&f%x1!A51$sniToYf#H;u)Qrj82i z2He<=4c*<-A=(|bula&Kc`c#80^AW0UTpgWa7W0wAE0Dp=oxBhn$m?qT321y(raL@ z1}L{0I+~|WTXq$>Z2%kOVrx{al7ijyx(2L?#y+CI?`~>qz$VpFPxE>L)ZRi}w_Oy5 zetHDf(&65eTP#wDHl6i#Ep<>Fs+%J5G`Go%`DJQ!ealV8F!mW_`KoS_A*7CR*>nSF zdA5qn=D{Nh-TzTC9ClaZwm$(`mL$3RI9AJMk8&~TbBo$i4&j`8w9A@Dh8ItlIkM}=ZX8n zhF{(QX=TahjEk03eE;8-oxT6K_bFSA_O=VVD#|0xO$|*mn>+3F1#e_sa`UX}>W;KD z)xe*vQ-YJn@a6RgR!+=&f`|2QD7~Y4gwC+ zo+QwJy#Hgb&c!Z?+s$GEM2v#1(9%BO|L4-yJF-4KVcR&{_x9^um(Z1?M@AFC|NlST z?sxdLGjVcAhARJGUWqEZMZLYr zxi`OM9OAJK|NqpHjIg)<_SxF+y5-e(u#j6CJx$h{c991fR7yMB`~6Jb%h(26oY__E zP1sJzoxo>*GoX@+;g-zy(2ztBk81Krk$w3%5R+VB5~W5GZpV+yKPR@AOvUFutGkm| z1EN;Rb77>ra~h^{VHdfxrF|wo-tL-KV{_h1KxSh}J zz=g9r+u}um3}9OO&yVvqI51Xw6dQxsS6FB)#YQ0mJN5SE+(1wJw{H?-(avQ`uwZj2 zuq-G4v8C^OCU-blC|IHKxJ=QYoci+APnR(E`>y!HK#gLS<89a*@Y7f4~HbdZ>h z8@|jTMu>^Bjvje^Y`}X)P>5(a&M9Wq9mecgyg2Vk3KP z3We#rS3Cke^kz0tdcER-)E1UqsE$e{^Lf+h) z$dtZ`FOah$E2B^@U%T-ZOKL^&^++Zf)s4#w#aL`dauZE_>Bf0o(MXrHW4MWaT3R$@ z-|eKMi#~H>x-p({ZoTPtH$H7)<;%MW7R4SNnx_k^c^k7U@N}_)iOxy835d_hUK~a~ zvhVU=UF=nOwE#NByk*3Qe^F_&#G9Lh3QXDdE?#pVJo`6|B9$RG8uWV7+nQ)HTZYRS zTk-mn7h@%3%vLJcC#}%MRoaeCG@WfGnwW{bQ!Its{UVln0gri&y|-2tRh_d1l8Ii< z%3nZte)InHE4LmLRbHrV2aEYGatTpDdF{D>+LqX!=M>FSMe+8$@QbBou42i}xp=HO ztvQod6DPVW(7r=6PW{9!Vz$bH%{cl=ehybi8(z3dZsh-)2Aui0aN?Iaw&iWW2lqD4 zyd}ncKhysn%&Sy4U?nXUhRHhQ8d=0BOOngo#YZw{WtY&~bCJ5{j+%YclXQTAfGkD` zx~~8O6ZScvB{*^KP#}bb*z%S(8vQh2t92F11{0_%emP-R5pjdc+$ z4jx-xgU4)L3~$%n+nW~$O}c8MzFC$VVW@9gA7)2nd4J-kMat&e8->ItJ~PHz(~&{3 z9NCFy>f8#|SSR23Bz_uqZ=&BgHuA<6oXJv)`6F-eIHy@O*~HxW^(&J0xq+jM6RA{SuoJj zG^!hmE2m%qRhKL-_k}8&8!?4vI?}nmM>e5Q=z z`c;eR$n<*1EvB*Mu9r`j;AII`Dhrqcl;rn&;+2cFmR_uW*9wWieG&H#(=n%*pK;}y z)#%!;61kSk_jM}f&E$g`$vG+_B3*$xTQR4FDz_pus_|R*`ovePN}KV^SA&@z4s;=T`BBxw>eA6PvrZCO8Xx zkut7An@74}*d>2mI2_-;1Z=4+T8_|FGdu7uOKNG06hvk@R8)7uwsXg9DNj3FZ#q6* zel2b(Mm;$lMSnx41xgW?Pw~MXI)vp53q#nZBc2-uJUrHqp78-4)-cK%R0C8fNmVApZ2{d zy!E+PZ2r&sI%e;5!_m>(t>^0+<;7AR1^}{vvbho8Pr)j;+^sbo@xtLNwXe4&ba`Pf zRSn2fM*!Be(SPN58I`?!g(r6dZq9Db4VJa-pcN`v%++?o3v*l}Erp}Xoo=;8a&ao} z4ro6@n^cbH9K2hu#^*mWBt)*#*(iGF$V+3qK^~mr1-vB?)?Gf%8B-CTc`V^(Q36Aw1C zv9qQPw;K~b%PEn8{i-<+1!tC)`^>qe6U;|t)y-Xd!1_V+K$(OLnCn+R zc!Ei8UNxnyr@YRcyI#HzFwK+4IU{P?_QT>GU$DG#EEe#zw}$Y!ZNq_RA6K5}Ofol~ z=#-YFw=<@s+1yoH!<~9U<^8=UPDELw<)Yb+>F8(}#A{OFr2GcTM=fYXL(u_S5ou z^X2;X;~JTh<#p;~B~3yGveRdKhRku3OUn|wq1)->Nk&k`>+Sb4n`_SW3?N&ZX8zc6 zbM&|hbHQF_Xx7TxlOCEVe8H2o|CjbyvufWQkhNU*x8od4b@rJ1(ZQExc0*l=`*BFi zAwCv2`%&h_b<53B8@LyDAe8<&n+%-NH-Ge1m`nYxx#I!wuED%BrPy9k>8P{xtwnCZ zeYt~-GR@@#u4-U)jk!9YDBF}b1mQU8t*+}MtW1T+x;9MiEBso^vM!=X= zhMRLYE;mnYHc-t|n^X6$FfRuCt#jecG|;?+N#bQ3Oq$at`^h~6S%?w2*t}6=j|~mugFUiHS2lusJc`O0-v>AGoc$*6*d%8|$5Vaf=CjeL z#pCguQfQZ%#hc`BjdS$g7$*D<-X}~n(M|1JWpnXnrewL6c9_(r1r`gK&o?zC$Vc`q zwfSh%e#;@uM;OP&8u>YeX8A9b&4+Es;57Jd@0x}g zDm(wMBHPGqoA+6;YUb>T*rp@4-e;qiy{w^l&GEgPlM2Wu`m#@6D1yw-Z0~3^r_9Bp z+Y$y@-^0T}cEJDP7VZPfv)kD!c+8es1wa19@>ap8w=7fzuYkV36|4WkqjR_FS10p4 zVTsP%!^_H2xSg2Q`kU1 z3@SpQTIDVt!U~qmFZ%UgtW~ZjtT6i95l|TuW&L_IdhWBJ=k8(oU0j|Y#QJ$#Sy}u% zNn_#yQL8tVjyl;dvmszk-_Et}vy4_MpFhM5sW#VdS8i_GnZ_Q!+fOcSo0%C9jo)l$*b7zXFy$oQ}dOSs|-4zTUw%u+|cpf1T=}kGWM!tMBkA zdp}`^Sz*53>BniJc8(8ISIcC1)||3)@x`?HW@-zW2rObv5I2gfb=Ubvni9;Z5B@?3FjDS{dng*>#i@M7f8G)jW%hI(YI{_{#1^s z&!HIen2-4?v8!PlM#868jO?7z9Klw$vccEc6~oPW6;REcvO7wi%;_&Zsu}7wT}o{ zOVIK)l%DCk=4jbp6lR-q-axFMwP>umwR8Gan4J5cm}578Jjj$4`kKvLJEFi>eCEY{ zioOE+KCQc$%O(zx&soiXC*j6c*eZzo1>xM07`%MD55(PX1LuuI?S4$^W$bCx%hGD| z_Nd%B+H76ot)X`|Zy;M+pI?iYDxJOU?Db#$xZ7FYwg-1~7HoBW4eUQLx*3aY z2Siiso212)21cvwo2CyAK->9;Z9$7{|NgcdlX`qtey9E`$N0z6?~m-nj;Z=cFAKUm zVEfrlPMODc8!x+!5PQCe&+0ro8o6Su}jqZ!%u1jOlpkJJUUgzE@$s<-&xd3q1+jS zg{a2tp1G;ui2C++ECOi@)SLJAujD4bAMP)s85u3uK*!gbA?4b?DnxY z2N9&T-WqVWYw!cJ%;)=8>SgaqxA{*V* zx79on#MtcWQe%eX?=kn~Si6Ut`PUwWH|mPk7TE~vjM{=5lAVVEPc(s;N_^(JK*6do z04{6Z-iXicgJNy(#F!7SY`b*N*@b&xylboHl(vDfxvaUc5m(WcZQkZ}NAJn1GNq;6 zu2O#%*E?l>=1di0QH8HJpI9XAPCoaW&!{Rip;47TqY*Ik_A0N+YIG~Rt&TY{nX{!@ z+)yfg)y+~lmfWEXyc+UxO~LK%`|gu@@?><%cS{!2_L#g!ekbomcF}wMWAEPHz|{mK@_v1PdO7-{ykYIym+ zKb+x@zanYzlgn_G5~tYXX>v^cQIh$6??CbHemUlqmNGCx199!@OIzvJd<(VSevLP~ z)~eusLzr(^rX431;ITh-o)lc{FDSTDtvbB5wVLaLIbBnu4k{My&pjVd6}p>h%=xvb zVYiEtc+y^j2jrM}*s6U*j)}+Z`KRRCh>@!HDf+mc)4zSU*LvpF{gL=CeC=Wls@hSL z42ayjKz1uNlax8G_|uZ2__K0M+hhDW``aGl3*~px9;46O-}adLrxcRhud_>lcqdLSg;DroH)_iIpGHDryhjDs-F&{ zrkEhOaAJ01;cRqOsf;9~!aP3_4fb%%c*v?;#DuC-)TGp1M_?&g;U`7AI>uU?d4AHj zepW7d1Qj?ve>$agng{MaFb#58!cz1$q%o?ZA?aLWy`$86p|Z1})7t^LJe zsMF8b8vIW=rrxm^^j$e--jiecE4jEuhmyFv-DjPW@lGpU}`2WNOJ}A zohv*~=gg}ALGx7qKgiQfvu6FEd4iSF6@Hywm^J$c%@YiluJAm4BV(3tq`$EDQPuCZ z&2QB*-YcU}|IUDLHY;toqy&_s(+7JRp$xcx#qx9DyfJMg%E|pak#8>^!25i)Gh2?36J+ zXAEmjnTBtNS}}tHEAaM(9Q=g3%xA|sX2@{t;%SG}64btRD!xRzx=$xsU7!=ix&EDK zb>U8QEZ#X4`iul)Ia^W_V5)tj4vIrv0rOtlhyj^UNoKkGh;L_jB(+z~svNMX9mUyD zN$10}ss?O2%d2yzT_wHm&Z-``=^c?bB`gU(U1n#F8j68f{Af8QPmyDEuC&~5xo@0F zw&PjJJQ~46PvM=4VB!jcBiRJ*fe0Gc|8kePqp(&j8k1aP`wrcUPPhLt*Z+RS?X7eZ zUgRzRenS6~UCFNNEWDG>irE1zcTcVpP}K2xQf*>q*@|?Itvt)KG{D`~)^_vX>z4L6 zclUnYzFeEwzjhpEb)x5Mjcdhg7Hfq7Q!}mR#UW}=qSi-9Pn;g^jn7BcHr*4vC^kz9G z?J;_b{cVrYTkUTg`^^H%)Ss9>fAY{;bM_x(-p@UA3!cG~w@bj(-5L0OOlj_ zsmj%V*e;7`sf4(JSolYvq`^LyqY?S4E-cy??muh(hllR@_EF z*BnuFZ>0OtNYfA7v@Wozd`gaqr{$Qk$JmSZ_rL7%WjQ9_vcEr)W8zcEPo>yy6MIMF zLiP32r<*g5EH~#LiQ3U?C(Jw)l`iWutKi(#WL#kWex%PDebYCFjphQZ3NNu|%#%l2 z;~XJ1{T7&Qo)NbuETfAwHA+moV{-caBV~1gn2R$X9SP<4idy%P0+o1P)N!9DK<7vT zGOw@9D!uU0YX8y)~T`F#nW5vG>G#I%AI?+n}GyG4?qk zEUTW{(cIZxVg7oQQ*Pck%BgB>o;@XE-af_|ZeMFRSYu;YG6-v9vZpydC1|Vbm<>Y$ zk@hy29Kh+-5NzKbgIRQ(Hh}N4;c=X zt=NDYrc|ahbs$JH{>*JhJ0s2AM?2N#tYe%CO(8a;?#9=`@G%>I=B;C$DmBN{n-sX2 zcaMec_|dD|K~F1g3{6-diGXz-%}t$>NSQgqlDq7=08)F>F^=6F7+ZEs#ZIS^+j3uE zdhK-cil|G?SzQWzt|;wjvTH&juybO+s;HR_o%;Ou+A$83YOi}}YExVBGWdrmj-3IO zrK8%U3|hpz5&DFugIRlH~LaxDniZX!egD`<{Al?MmU82qZ|`wNwQkIThyDB z?-R#5o!#}l{DKX0uK13hXG2~l$LJMuOkZWsBxxWTJE#Q`{fva2uG88LXL@rawhh<9MkrgI{hd3ojL0#c)>f?oOQfY z<*vni^mtUqg~vPN%u6RYSnhFxGs-NSgL(!7YQ3fiWSbS3XLtaf3!HxHcn48miYQF- zayh21Ktw~Tv7lrsn%&s;)@&7i?gXa_%Rwh%kN3Kk{iaNj1)&M?nLRyGY;MTe z2j(~x*0Rd(%~NaIx;g{FX7lJAr(CR{WKUroKc-JZV%r4I$9QUor>Ev1LD4Ib2xOzj zyn6zY-D5sDL6V8HWhQpDxRpzk-Sye@^`_^BIgYHL?dzCL)vcmD0R@QSdO2oplwMUpSiM=Pn^a^VF%% zl0LLF3nlK)5qDYHMaRf7eXJZ`#}VB_0lWNvJ=OV6*7whjIm`R#5isY)klN#plN4TP zj}O@68}|67Jsy9&xV~wR^G=W}o^yM5&47M&DlYCZr$OC4)>E!kS99-aPR=bqP*I6D z#?4JIe$*LT$5-dd zagjYPJX?OBH(xT*uX)`YbDP(K)6u;8wyb}}khj-kXkKrh0rl~ZrDm0zi%!pPWbe!? z)X3(ZncK+botfXr?ms=Zk)3lUqPbb3`4-LVo70iX|IGWA&Fi%@mQdRZH?IpMbqha{ zLMYmZUY_R^X?kzWTXF-sx47ETf@5U%aRXablfYR()ReeJ!b52{(Wnj^mb{-n<(}A zVnf2dR9P@q=J)xrvq#!Vl=-|tpU>xyukH1EeV$}V(3dXFI2k8e5-suJl+Wk&`MsX7 zHv;MRg*|?cALsn=9ChIA@gpGIaUR}19xsH)D^4CCG>cXoRYh-bZy2r!n(G~2g9vY< zqu(H)kHR2Q?ejoy&;u87@Ob67*Aol|qmGR(81#Dm;*>1&;gl~JK^9|DhF!E?;<_)rAUi8#HsEIj!0di=;A&LY`1>-ZUwjC*`Y zPSE4=`@_CysSjHHRuS}sp+o#byD#o|lhEwL5o*102gwd2et&wEC@w+9Np6u^JA_tVXNvQ^<_=8Bf=z?DSL%^sg z2_o9E#L##tM7#_IQ-W0D4+kleNPNwN^5VmUlG9;n#(q?S5_{=TfYJtVEujRd^m!6!{c&vngA0;$ymB6yMi{9fsNdnV zTsl$h$7PjjfOFC}L?S+0)llw&(@DrC$vW-L~OZ;K{h?aVTLDcM0pZpVFet*(QmIaYW{7_N0JU_frujDV{ zM}Z(J{P}PdaP`C9SSij#^9m3ZU;dZ2jfA395CD0WKa`m#HZ)e^!S6V{z*{gV#Rrc* zc$ELN@cV1UHINPfyx#O?-mu^2O_wa8M?_}f6)n;O2^IE&Be{Ml38@$OANABSE;njZPEUyZ1rwzn zTom~B#Wq2BC_~`*kaStZha@9M2pmKapgg2bN;l>7n6RNuo48M8aw3;r9e3-N>GJ@P&hDu(M)7`d9+?~iW&a! zhg6rK;H~~-Nzj8+xZpT#&moiEa72m_^%tJ}$QB9#J)bvI7S5E(e=#&$KMDj53}uwY z=Pky3SZ<8hl$nE$G3HALa-K26hLoAe1;(Ut{=PBNWbD}1>o-z2s*8Gi}*g$#Dn~Yft4ymn`JvXa= zvyJjXvX|U^i@Hb1=aW<9>9;ccwi?NOZzjBa#$^*(Va`Zvv1bOU3%1N^4VP)?~)&Bz7Pj((*c=A@{6nQk+jMDJG zA^XW!EYR>#@{NyDANk(Lls&s>`0E~5_L9$gLOD#nHl-XP-}R(&g8bZ5%4zcTPb+(1 zzE7@a+cU~O^7g3zQa>YP^Q>OK82P_oaZi#TdQRO_-_%3^w;mL{j7@mCI`^rgjTSnP4M#KM+>?i+|oFE_m zAN8LikNvN***fL0&-i?4kNTCVR=(m8t(Axn+oQoO}g2L2ewX?iuoCt0;T+RQ=bJ zz2q}iRd+x6;MJ6aWZ&w_QS#b9QI3s7LGmLTs(Xxl^+wc3K6PVd?|2PA#|L>TV`zeB-uKj*>Up zn&HWxkkjPWZPeYfpN4;s942qMt-5D|>fQpD@rh@Dg@|k4+Wc7cW z>!188crEk?G4dyLPmnj>S@oyLzb2alRbLn^;e+I>$Z_&UK6Ou%Pat~_((s>>gXCSx z)qjLM87%cHN4R0@XJpSI%D=B*{>W#OljK*)8S<>*>firc4Zl^T#-AWh z1518WLsVmAa?NVY2W4)cqB5n7n;8(?>p&oFG3*PLe+%dqS$OX@rJPgq1HM zC&{mnQ{=rzs{ai64sx(g!|ydp-J|3^cAYK2Kx_iiXk-g-KJsF-nne3aQ;U6N0$*b(8{uAWu zz|vkaOV#vPEL?RVDX0LPLf|Hr^%xa zQvar1<2xHH{i&Dy1=&wN=r`&fB;Q7kkcS_v?s4*!30Q};NztX?@q zo=HxVw`)*$PlxL7A&1Gs8r3~Pew=JN)qg{ix(CS*lEdVUr|9*IkV9a(ehKnCa)x{l zIoPH8za*O;<+iCB-bYT8Gvv*tsk?us`hSodC4WIqkauoY|7Mo@f1T_jpEF(EW8_E3 zNpj~5bq~(g@JVu*JiA5RljNJoDe@Yv>YgFjkv)g1zPV%{c_BGW-l|Q*C&&}YDe@6y z^9R*;Gg$fqANkmJ4Id`gMU-RY(Z5&!!NWBCZXN3GIb8V$u;}xWPv}&RlDF?tj+4Iv zuZ8O$K0?Fq*{$v|atm186XdhVDe?>C*pV83n;s3HBJT~B@FuG6U1Tr$QgW317CAv4 zHk09x((v_UKlw73FI4wu$zk#;vow5+JeKVFi~2v2>?Pks_LILLC&?pbtG@6>8vYOD z82NAH1o;JWlDylY8a_j=C!32^-}z)O`E|0NJn9dOpFEWuC7(l%lbd zJ(pVL%Hs?Sf3k|X3N$Vu{QN2vc4xt5%~O!dtrr^)w`Gvqao z)bO6m)&Jq-F!>g8guIxXAa5Df`Wd`J!yinJT&a92Sn6wrd^Op7mAXGd4w6?pO8rO3 zyOU$&Ddaf$EOLf?BiVbk>RlB481$#L@gG|!8r6RwSn`)7 z|CyX2zd-i>RsFAbEYm~YpByHiMNX1mBd5r}JWj)#YgOMQa+rKNIZ9qgj+56tp6MkA z$&rNW+x-M}Pm}K=`>s>>Psu6ru5;+0JQFPaWrlne-NV;w_}9o$@-I%*@CkAQIZeKT z?D?C9U-KmOA0t2lhPLsDiS@rpEQTOA>5%P=V7}IbGeuuPCRC~A>i2x5ywx8W zKY61w)jjgHy5C5Sk<(zQUqQ@+BbjFPv*@3E897ECcec7G$p0aG5L&`tGhf~POV~mkxhw){{z`WzJ?qwRrl9i_cCSA zd8#i+K7gDcpF>WOA0lVSrRQsS&k)tO3)xGaPWF@Mkt5{0$-z}L{QKl6`R5lfeXFW_ zh#V%LOOBG$i>eACi^Z`|2}jQ(tZ|_gXCeCF+b!ka(X@We+JpJzVfYP zFZti(2zm9(sgFE~oFbo3HXEqEpI@Q=gXFWxaq@fQ1bMqF)qj%QKu)>g$rTzllVjvlu2y|%@~^I;zKu2fBCzz&=I6?Zzbbpl z`(LZ~zh-NR)6 zjmlB7a})J#s``>-ANhit8J_&>Ta+W@G&xB=`&M;NlPBLs|J$klr^xZ`m3O*b%h&9n zJP9o2o8D3R7_!+(`4O^@`~^8&sqPowq2WDM%H!@-PLj91OF3Ar?yDq~!{qzP5%POr zsZR;A=WgW`xq_S_Pa^w9sQw;um^>dW`HPar+@qWzpG8iRN8YRMY4QhPJH8_yf1kR0 zM{0b&`;{Z)=g7WMOwR-A9wcw^pmLP_2w3!|$iI6?-NUm(pzh{Zs&B%h%0BW&k5M0a0Xa_YdR*NT};ihSUc${F(5 zrb?Lh^}**? zZePgw$=g1!93ekXj*+kXr@AM|`@W!@BA30WoFU&!_KeZ^X1=8Ee)5k0QVx?}B}d7B zdYSnl@0+Io-BsTjuPDdJ_mY$3nXjsQn!M9%%4V#FUrY{@uX|nHBjm0(l;h-e-emZ3 z8vbFjmptb!b@!7;FH#PZ7n8jK4S(0$)K9+S-^v;Cw0D$ad#L}-7SliZ4RVrv+`H<8+eAph}0$Tu1uXrae_svXQlcE5 zp#1Yv^`9m`O*Z?f`w3<0?j?tZDErA@k;CM_4^{UlxqB6jFHRn|s=7yls(%qVPL5-} zs`MWz@&T(WXUJ>(MA@^yhJTbCA)m2^x<|>A*HliBKO%c-HT*Sesk@Kdy0&tVytPL; zLO%Vc${BKO9cBMS)wk=nq2|50jJRQ#Mfd47qhf zhCe{{ZL<->lV2hy$QN!*|C81K**{lKkq_NOIYaK=RM~T&`k%d-vX4AwbLAj;qE|UW z9=(NfjQlk@LC$Qc?kVzXTPbJACv2_dOOyaUEQ1?4_Qg=W3 znqMkM$mi~?94G(9r<@{RS+1NRpIxEsX;l3O4p;V(cdAqllV2o9$aAaIJxV^HS~*Ux z7@?dbze7%uFBz%so+gcd?@`J=@`vOw`RrZPJx1Q;S6Y4v@-%Xqd=}X^MfKlJ4wDyy zrN4-i>vvU7k&pg0(=%1Wj~cBk@4@8yZ?l`mpKfOQ!J^MhS5A|C^ z^7@lk-(NXJz7#C+d1kA=u3F_Vxn-hql)T3zflb`>c zmQS4Q{2$AUydBwlgod9$4w5^`5%OjsmOuFpa`;FM|J$&p$3&H%0^9zM+)<~TA+J-f z{=G-5|LO+jhkP43PCmX--IL_6$SLwani&5vs_&vH%6{^UsmfvUY15SB@PR(1Crr{TXQ`^XQqse73Gr*`TiH$;@<TY$ig*#%6{_Z^OS?+9sZ~sBcE_4!=I_)FFi{+LO%X% z#R*-Jh& zuIwYXUZ@--PyLH>lDyYNbpMm;+vQ^AIC-~AloRB`$Vu``K?pPdCTjRqvSimlE3rR$dg<;Y{o zkCEf#<{Q*KNuEc}knbdWAJ_2jl7r;+|IYN0{p19BI@vs-;ZG-r$v2T>BkxNNl20JV$XA1l%wPk_tO7c>i%zXl6=E`>YiDo?ibvz?0;K%-v^YF?TcdsZg`mfGs^2fqU`^Va+)0ZukwNg>YgOeew6+{QuiGnQ#Kzf ze@ym$qWsF^>K-MZ_5}TZuI}Sf%1N^4N#)EJ>i!kk|E2OZPtpI^%HgM#qu(fR|BQ0N zl-TRH-anL$qkJz|>XV<`{j74BywP*YadMcPCeHy&{V^q~Z~ukLUh?+OEBnc%|D=BM z0@d2@s8?Ct*%_RSlRqU`FHOs2g$#APdP%~^L^zgIhavS zkoWtKa)!Luf0aFJsQ&XlP!5u>{ZKhdzWXEPGOV>z<7IgArdued$ZwJ}L$21E~F-~y%u z98jpHA1&b@Oc33ag#Yi&d-LtgS9ZVMEBbbY&|v-cn{U1;Z{ECl@6DT6KaBCVd-MBm zeK_~ekl-ggf}ii-#?OxqF+M7|m|(mn`1~Z}f%|a&I}bA+6#OT_Q-Z%U!p~O(e_)jH zF~Qf3F<#U8$ECdca``7F7*_>dJdZKiHE8{~_xbX^;NJ^AD)>8TDNpbRb}~L8 z`0sWxo_R2r_oQjY#{?HHko*tj=Qr8Sc;I1-*91=qUfILXtAdAT7@vGN=l_x5!ACHD z$z$dD5aTD#GM-8>-Z{tksNh@dWqeHVhXk()E?mgZhm!pM-5$sIxZsZnUKL!pNb(PJ z{uc|L61;yOKVKc?=dT4Od0S<^1~vKRL(vsNj3&r98o} z5WFUMXn~&(&Tx6lf`#9}s`B$S z!T&4xq~O}6{Cr@JzjxajF68olCU{ElW0&}ORq%TR9~1nt!~Fb&;7gA%9(){^_ie#bf*-al)<$Xu+l;BIA%Fp); zJ|TET@Xi(P-(!NW1g80RLh!)T`1wh}^MZ#S&)<8c;2FVR7rY|)-cRTER|U@sUK9K* z!Gjlbc^?wIP4LeI4+*~SGq}7N!50bMFZd&Zj|txPO!>axX9!*syar6|9e4tN|NLh$ z-X{1hf`$BEHo?CWJS6y>=gId3 zzgX~o!H;}CKVK32Il)H-A9?{lKQ8zVFJ!#!ulf5Q6FepOf*0}gs^A;GSjrdt_kxcL zo_h)R@4(-1d9Mbh{+ts06Twx%k31^lA^2f0mGAB6_y1Y&ir`-fJ}&s2m+|{21;0q} zP=??C9WZ@=M(~GTF7+3D(^oJ)CipXg*DCz}>fiG7!7AgA{T<^e!4JNIaaHhV1s@f> z{P+BPRq$Q^f$>SfR|y`vl*@Ns#m{F1-{94Z*OvJCd4f+KW}Fv1c!cq@1#c7lX2C;( ze=4{tc~)L>FXQ)L`FeR@ z@a!8Tzu=z>J}&qbZ{+7E1&{p`<84pk@-7lQB{(B^@X7rA={mpQD|LRs|0a09;QuFh z^{M>+S^v!68+<0?#{(<<(eoHTL-4>07{6We?|(Vt-wLh@e)OB9J+I{F^MVJiVEl4m zDu3`F7@zfK#xsKdQ}D4@@$;i^;pc0wW<2#)E`Q)PjL&?V^q1gkfT{c`!G93EU+~+m z`G-X{dF3SJXD^%j19=7;$GnYS{&T<|f$Ul4p!@E-(kdmHD!?T7jODZ!5ud{pqF z;8nq&0H*#vso%ef-#>9Bmv@oifwwb$t>78KpA)N)JS6y?g7*s^_?VO@cuw#!!LJg$D)%{s$S~`{UAI zf_40^lY-BY=i5HS`7akdCHRAa_Y3~D;1$7RpOEqeHw2#)d|dG0hq?Tp2%ZwG-b|spWyf1cx!@nJhEegbv&{)!8#t<;MM%Tjz=~mSjTId60GC3 z?H8=|FIB->-*Qy2*0-z**7}w;!CK!k^GW``*0)pzYkkWx!CK$4Dp>1V20q2_YkkX* zV6AW2FIekajtSQK7P52FHbLuKwh7kymMOtn-?A!L>sw9=*7}xhpW*V(`wY{=jNo~} zD}pZIs$hM7{+M9$Vv)&@ z1?%{bM+NKnkZXc9zd9+{?@UsPf zM)2PY{*~Y>1tWyL8lR5|o)G*+!RHJ9k>KNkuNQo^;9LC%*LO|uy#)VCa6<6Sf6m|A zA^0AGFA{u~;7bHg3%*?N69pd?Ton8U!A}jj@D_~yUl`aePNT?AJIpCR}eg3l8CO2N~D z-zNBpfDELc)pDg&l1iw)59|XTz@a?|L?YUC${RCencwF!`f_Dl2)vvfcj^G>r znsHt5S%RM<_>F>JCHR`(aQ=4+{;}Xs2)F7;5~v53eE~XBKWZ2D+Iql@NvQaDEJz|?-6{R;7<#_@%3E)ZwkJ@;GYRT zOYn`p%JrWS{Fj3F3qDhDRq$g3uLzzKd{poO!EY4&B*E_${1U-e3x0#(FAM&F;2#S9 zoZx}qaeKZic!%I$3f?RDW?$p>Gz8yW@GAsALhu^}Zx{S8f-e&M8Nr7HUn}^jg0B<& za=`f^Yv#ZqHu94-|Y*@S_C3TJVhE_X^GnzFP2Qg1;>IC4#RL{6@il6#PNK zxBfq_|K|nYL+}p-PYAwV@KM3H`4-pzje_qh_`QP11z#mB!}(7NeyZT9v-tgY3cf<{3BlJ2{=MM4{1xZF*LS(RDZx7guLv#(ezV}u z3%*|Pz?#(m(Olk$;1$775q!Pi&j>#MF`WP5-{bdJ1;1SI;1oaqo!}#aZ-_n9?XYn= z@k6Gk`)T|p#v_8){(|F&eO>U7=uhv1cj^7=-6Z~)#x6Z}HKCnW#- z1kZel^J92beFvrd-|FX5pF!-MZU_DC%#Aqz)q=Ney> z#O)bZm$-hB)q<;+GJZPfkot45!FcM&Un9^w;Ff^<72Po@f#JqD!3?k z<@NmhRf4x|C1Z@Yy`OP8IJ5Wj!N$1py5f5xkVSFYgxDo^qA z)#ot2$JvZeJe%=%1+TuB@k`F(=YwD2@*cZg%6|$!zsU|M@BNJF-Y3=n^8R9q@!GTa z`Q6Ty=TBq2DtJ)xA2^Sn&m80Dw>_WnwhuG@h~WKF-hs5_{}w+#YbWE??=imfF2*OX zV*ES7QkFnK(NsJjdnApIChl(U4kjjAYo?@KVK7me481@1492F z7Cd-4)AN4`Ui(|d_joMl-}W@dj}<(41>Yt|wUX%HK=7s!xPj8|nnFJ%~?_#>D9ka@{3>sdzd z>KZ?PP?nz$NPWI0ct+OK7v%W)j68o#p7BXJPxvdr+l1e|b%CF+3eFs0ynh>i?^XvH zAG;6Z4+!4&M(%H?z|YtIk@2lAVSEznD2>+#1aI5N{pB3u=L0Wce77Rw6JlS=3qJNj ze*QNldHxv2H!L$=+0FP(f@f~Y`0Ij?zE$d9;ruhQK72#)(3AQ3RaGgk!T27RG9JRX zQT;C$JaqxL?`AcAeqxcocaFx7RPf9rxIXV*HM$*Q+@AwnBQL==JKB+_{87w^Un%idkW*{9pU^d zcjEjvxQy|@bNTtBp2Yar^B7-)aisPg{Y%b2fpv@U;0yS9<*AHUp3V4AE0X_?oc}pb zXFMbEdEWgD#;Z5s=O2A0Dn4Sa<3BtB>OEeNymIIbZtB z=koIzIWK$R^Q1gE?|J9vGd^)0zyB4%gK{4B6)%wY<-F=Z{g=B1kXTjCwjW$E2Mtd7ZBb{_|_Oy+3z0_JR$mr*9bl+ z&p)oQ=o@}4cvbKn{+7!-L-3T~3DFPK1m8uTzh38;=U)}PO}>A<;Oj*{@R+~j@>k^j z{et()^S27VR^GqWD>?s~)W1sjCM$3!;Qi7o1g{M+{-EIhl;__OoD+QGEBO7_34XZX z%S7MvM8OL;;__ZB_zm*>qk>;9&wn9!K%U>}@45VY-kRTkg5YP#_ns{H+FSASPYJ%4 zy#Jto;P-DT<-d?H=F`j+kN4uM7@xcs&$sNW8CTEe=MQ;}V4?5d2tKx(pTGOH{CrCI zLFpfX(VySHDc9$$V~l5S!uXc2V|+Jxey!k-OZ{HFu{8+|k3tp4_ zy9wW55H;oR&&%^cdA}(5hmwDZ@NEYM?lRBiEvxt8zb5nXslaIWjZ}g7zn3t+p~i3b z;Ojj2q5q`bck`D#_!S=fZV&#P2mi=}|IdT(#(c*8-l7M;%!9A=;NN-hjyKu$KkC8X z_TY!S+0MV{!5{bFTQMJW>nr!1xcFI~=O6OmpLy^DSuS$lpZDO`dGNPA_zrKg>wlgH zKiPxd<-z~u!S}q4fA`?; zc<^sL_}1^VznAjhj0a!t!Eg8At3CLe9z1^B{@%0)|Fs9d)Pq0i!N2!lxtGPIr@430 z_f}k7P+^?8}+`R6_OmhZ8@cb*47 z(}Vxjga6Ni&w8(2-en3m`|If*{Cp37sRv)7aFhT3vj@MEvD@B%^F05W=lOqo@E<(* z_V2Un{{Rn8GIrO4M=_?QQT<7K@I@Yc$b%0vcI*El#%}rl=)v#y;D7Ppt3CJ{5B{0gmPj`RtntC2p5 z^l7BeApINCXOTXKbPdwKBYhs}3rHuB{sZZYNMAzwGSXL&zKZlUq-&ABj`R(rZz6pQ z>Dx%(LHaJz8q)WWzK`?+q#q*v2b(tVNchjf3W2OvEV=|MQZiS$UMM5q!iM*NS{Rd6w-M}pGG<# zDUGxfX&2Ho(r1u9i*yarzaxDf=?h2~AniulgEWKmSfp8`Ii$Tv7a~0l=^~_kNRLOl z80iGke;_>p>5E8TLi#e&SCGDn^fjbwk)DY3O{8xjeH-aJNZ&>JKGF}6{u=3Tkp2_t ze~^BLDfrnLHae)Z;*bA zbUo7VkbaN!T%_kA{Q>EZNdJrUW~8?uy%p(gNLM1g9qHXjcfL935$S#S_g(PcyCU5U z>F!APK)NT=y^!vWv<>OLNcTg!Khgt`9*FcHqz5CNiS$sUhao*2=@CdnNC~7Q(lF8p z(kK%COd+j!)2C?e;rGv>K13_@?_c1*zeIXI(hHDYi1Z?)7bE>G(v48wjk(Mf${!`& z+>`$n2EHZ!eJi9}Bi#n+o%qIaq<0~`2k8v__7J2oq>lstnHT?=7e5$u@DQXkksgZl zFrym;Gy<6N8=N|zh?S~*j65;KXB z?S)#lQgXIuirI?_4bD&~H=IVrIha4PEI;6dOe24GtyY*R?4BqWD+f!Naycr;ZmlW+C7(a#+LHgMy00yok()VdZSh-A4q5Ec_NWLn5j99TBgvb zr?V-QaWYdZRfdca~I3mXst{btxP!nui`g zdlnncP~dp&_6}kqu~5tB&nXx8+G&TSy-s&8=)D;KokcKlJX$RWZnWYPYe+gah5X0#r$|K4??XhgCjU&xqKs2D2}TKPD4%gNDOET>O7n; z=i=3iqx1O#g>ua5gr%dN$MT@ZaWf>&%_!sF@TKiX5$G zYN+?jt}Is&bwwS|1(!}Z6AM@(8U?I+=gt?JEgMs>)Ks$)!wNY0C2%wl?yPESYCcX) z9Lv`7Sk^H%Nhduw>7a_#x{+eOUMEaz^0;_;{g?vU0R~z_Bwm~tF5=q^DQfFZuUluZO}--HVD7@w?QMp+n}?h#q(R<-rOl| zZ*I%md*qb1_sEvFclngIcX_khD?6pcP*X($w&mqD=CmC)rtNURw8d}!X*(P|Z6`yt z7pcThZn0E#7K)WjBbBq+Y)@2q_Z<3R94fK=ff{sX*-E+I$dnuD`RVxt*4W-?Q8HUu z#5N>XH~?i^iZwQ_v>w-CNGi(7*Rz>wK9_==c#h-QKE=D{ie~b)^by`bF75S5J-t!; z<=(3O2oVht%MNFL{*p_2VtRrQvXxvuHG6ROl7k^NZY)>xPQF&F)MR^`D$MQ*6-y(k z*Mq;6s5A~jL$gI66Ez97EHPTG)C;6nAx$+b1sF%A`X6$C_i6z397-6)SRDkzf%$fe zJ{t{M?nZsfU2vZzE6~qZ7Mxn9d?0UCAY|jPt`SON32MObq81~p^3+J#UpNcpRBBYI zOGDPC;rT*2Q(JZp*GLf;0~sNkN+eNxHV1*s)7k9w%n~UDvtcZAxKOU5!!x-|6>Z2a z>4`8@hfOJ;bE*w$*pQPctNaeD z$*mllzQXD^Rw!e13ps~Ik1S=IPHmG)HDAvhadNN}ijFfDq9qjYPG$ZQ7#hQRE4Fnv z8CI&Kgd1jdllddre3h7B$o!3Olfac~n3T0zX4$Jz(X%VIl}{eblyk*ATcFZAz(i*t zLhK1+Kt0k9;(@O1tUsE>hLnC7oLT6&`l21sUG+sfpp)v0c0kwEqwOd!mgceb5N(lK z6@%sN`0`&~1Vt+G*cD>G3XaGCi0UGBq{n)HRO-K2uERwMTB8tES6sYXO4{fG##I>REqgb+3QUb_j*s#evP*W>}cmzK_`duN3g3U-&CdA zAa6yuf=*jv>~JbI={{|vz8Eu19Ag0{4*cdfag6zNKFSumJQFlNbMVmW&5aglR|gvYTjsUo0k}~SHE>Nb1c5i9QQ1e>uTqCeA}so86{1IH?mqQ zl%RB8%DWmhr!fxiT_?c3)1AjbFHO=*fgYGGU#nI_R?g&vrFhH2J$pWrJ=9woxE^Rk z*Q&T)Xj^-oTo1Iuubd;RJo}{1(^fZ?f~GFmINWp1vxFUT!R_0YvMR5i8wd?wKQ|AG zzkY5W^nv}{Jg5o#t9c^Vw$&c?!jcd{jo1Ut&?0ziePRzZB%)$5{w-;(VT^zMTd5l3 zU;DN?$M`p)jq)-64QQ){94+RL#KJKO&eJ$~tbO5vRi-hjYyzITWrr8x5S2#kYAZH? z*!OKx^=(o4d=*nTlv>)2V{_#7cPL+W$T>9FTPQ{yK1{Ssey-ID#DVw|$Y`@~opPp> zhp^mZJw8r74&UNJ2?muO>Gg>+OhC^3as%qvGP~2J<{AljJwivzkw2Vbq25Rr;!g0x znOsgnS$OSS@tKu0DPunsM~L~wzLr)9k@$}I=psDS<3HvkDK{z$so5MByP276phHA_ z=Fvp`P@(F~S4tsdszXD>!EJin^)Plyi1d&-Kug<@Bb`awbW5%X_ri)(qbA5doezPK zvVnXE_+Uh!tB*1nAiNZg@&^)DFSM-9POFES$e~tJ^RuXP+=qi=K_NIAr0$TJuFvAP z@l4r@!?$p3lEZt-LB$uQMaS=O7 z&mxEsM1>HBKACG&GAig)B6*-zs4pg+8jeKg@LpjVe*)Q#@zOA2X_PY9m@F08jb^GGn1Vyzy?fFm_~Dj<%Mc$Zp6Xgwk6f_ zY9*}Jz_I2j$l@~kDSYsa)=nTKB+kI)A<&?YGPOcp^)Xceu}j?FP*}T4Oe_@80mV%1 z0Ajjf4|+H;l)7X#_*ibU0>fj(WwV*=K|0GBW74f$3iWDJEg_C>NkU$y>9VA# zY6Kz8fHB37X!(-jn|hExGn~jZR>3ouj+<+x#cfayN~2h zkV{<(9LFZmVm&phPvj1BRM`r)iup{5PU_+ywAY^(;f~;%OMJ_WRXe0(E)5wT!g$*g zs8;dapXRTcu$J6dcLiG^R|Y5^oFf%6+SkREYuP90}7N{ z4#y!_&mEh}jb-YHR?~o{ZwZSGqN>EKf+KY-8ZoQWI0n=>ZV{KUoItfq*Z$bls|3A3 z42N+N{be0pk4uM9#Vo5>Y$~QgpeS*~%f>{0Gb4Rum$WLbS${WMGgd~Hv_#&;!Q{~! z8{3Y)<%zS0NEEXa#9YGr>CJe@f&6-)nQlzKer_a$YYx=d&y94W_w{ol-H?47*vLR_ zbZZW@6`De5{K58B#HRo$QTS%Ch)xT?dFaK*huY|=d!+I4F*QMf1?7m2h~<+`Ww2sY zU!}~kd~-wA@3_^O9Y8{aq4@Q)a`#Yk*tP4$zoRFJn1wjBmvH=Rt*k&&Yd6+FNVVgo zhf)5&JyBB$V%HOO&H1$i!XM%_`cSq(|D9r;ns23!S6#~ph}kQ3t-6}4uwa3H#UunD zk0x)N%r1yusJ5iz=9O8_QXzjhO(rgiTu5)`%b9tED=RFd_aWRnZr&o_+xa}jO<00T z4R#Z3a(U@$zPuN&%d{$_MwHhmy7+7%2dVm~`C-_*NUs{D_J}!O)6xhRHRj-YuRJ#g zH&DqPJ`~}RO7y8aqkJS4ddY}Z=(_scW(@t^xI!#o+pRh>F^Q|OGF7RZ9ssC?8|&yy}j`7rYDfHeVR4|AH}V6 zFv*}0IG8E_WkN)N*6#8&5j=Mcq{t-aOdxY!k^wH;*o> z!AJbG8qmCR(L7Ad47QfIJSsKALV#|e8RXU5pyUuod}Twuju4wlB@(5~p}fPdrg!cr z&+aOLCScg53yka@+<@}oiO}r_5)u{`>=afl-2xR9*3$?W!f@dtvunc$=I5hmD4IIz zZ)$=$v_nqU=@}|cc(zl9qrU3=^vn{yjk~W#tzPn2rV@$#rLg0`H;T?8h;M`pm@g}q zCO0d4c827%;sT2^b#T@sM4N1@vWD~UCbj6uQ!O$^A!t}?79-cHps`}Ue4ufV4q=${ z&QqFR%PAYIh#Uwmxa#9&tRYl8wvkJwu9ioP9y!XVXViU~9w{M-(T1`{ZiR89oumz^ zU`eC`y60=s8g57!w3a)ye5ta8YtdTK3L@Qmh-C!wNu|2%zzc)IveEi4_k*SbSUZ+l zivCQWz>9EQG3!dt_Oas?a?oNt=Io;zZuE~>?6G{CLxV!@11tba#69(ac4(fZfDKo zw%B66mK=8w5gG?f^v{mO&{gKPnI((n{jY<+<86v+Mw z4C**l!}&}xgJPY`0)3@WCS!PqQ;V*S+IVrAB~yKcFJ_pMHb=06j|Z*b=oJx^$FOkk zMsul3`p&>Hx>%6bkQ8p(n#C20#$fgP76B5N@_+*Y!66;J2V!Z#JJD;zr4?}~p3vlc z*mI~C^**#cDC1Mm|O0_-V#T)AgYEgU5-X#c}}*RBmMe z0~I3GBuo+}Q9dS%qI~)t%L;!2@gI4a-^V;8<(1d_os`1{M6*|@DkuQfhW7P^r*B{L zD$M&ITv?`gu8*s>VBz4zAbMG2Fop;2Pm^+?+}dnBDUa zCUjyXdK~oCC$#VeaHOUaTrxspR1)!FL@D#I-%dwhlPx*<-W4a{8smtDIl1A5hwLJNi$Hg7Aslo zQ{~zl;WDwRCWI@}+(<};8EnaD^B|_cI9517Es~~cD_PODe|4hSI-eBg=5AaoqE59P zMD3BOCDq0HL8x94>9=029LAyM#zDT~eaTi-$E)H{n&>shQ+FuaA)GGxrvk;exl=e!^g{Av&4TDCz(=?R+w4j%~ z`tDeHU4%&+%J_sy5-e}T!($|@?#ieZ@0xc$6}Dq`laeoB8U)x++iyvNUJ8=8N$CPs zW0_!K%_bY{bct-V>lDUes+|a$+X3|(A%+Ou+Hl1Dw5?V1{KmVIb>&*BcMSH#k#TqMzc&JMg~kmV-zi8y+x=3_8JCtk&_WX z3T_~LphOXEP#*K1@$gK>#onQrtlPIkbNOyg4$B$hLqwew(2iud!%o;6VYgC;}c#{i!6hnN5!@ zy-V}cT*#=|#e;ni)3T}>`2*nt?fJ+^^CNRjwL<9J2*~4~8$p?Tb0Z*Az}yJP6*4#c zIYW9`b!b5D@Gc8`qvhNP_(I#c;eW?FH|92GZn(vS%?&rhy61*2DKhB>dqsN4)|eX| ze;|CIJs)Y#jfCs$AQ@v>cv`~Ai2PI2bcrqRt|C2~fA?f_SzC^JnMm*$HPC`Q>}-jtQs6VLHZjCl1h}>OK;3 z*M96tB#gC^*lm}4lkaWOvG3essjBbWP9;a+A6&@8&9`1CAHeY<1YOHj7IDysR%>Ho z$F(_0)f_oTn${5yvENA~RY1Kuor;>A?8(;Xh=@Jf8juVH|4+>xoW0~=YIL!&Fp&!x zhhaX#k;!GMP^E28K$(_hk8kBzuGUx)+1P<$zCd0#5MLDEfKq{d*Zl<97KC8WeR2dbYb~0g@c^U*B48QrR?5?*#5({ z#d4!i5_Q4I;e&9yl2gCZ&+zD$9pK@7<`CM17ZNy;KxfBu`C=Z`qqCxoNu_ltlou-a z*u_*hG9^ezX0@w2&_Z2Os+7~}JRd!49IV02%BMO+Wnq1uv^?f!w&McE$T^^xpIn6N zMx;rR}sYxecsCA~X ze|?3OOodsOMR816qu1Bb#%5U?&_=Ojlx($Nm#u{Il|tujK!+K6+4c9nB5BXrq^{2Q zcxhBl;o)Ku9f~sGoXCzLcN(fekM>e??so7}GVn{4mem^uS5H}e9O-P~=;0bHUPREe za$GD6bF_1bV|BIu(6HEw{f=G_8I0Dg4H=9!F9i=q>z5F+)H>N0saNq52c?!JaD-PN zED@bhSj4wHt%~@ThsK(UWgJ@#jT?{}sV|rH(k5+-_~vK<#X^82Z(>?=IiQ{KVUyc^2{Gll6m@!=+4lxx2oHaABRD zjri3ap4S2eIT#pg5aMvq+adAJ{!q{xo>E634>n9n7|oI#h!fMUgvAshMB`x>uGlpU z{)z#Htd}E$X9kigx$71n*rI|;O0??czBs~?hS@>xv(YSCR!ecjbFRjuJC%bCA}LS% zCf!IL79TNwHdp^@F}PG)4NH0#<+Nb0e(KQT-UL(|@Lw3ip)uJ>?S^dah6LBuBY8Vt zDBv-f7L?Jnux~RGyb2(yr&NAVQQZ5N|DUo0h@7X`j%me{S}q z`sH!EDUe9^$dSx^VJVTo+0bkeN72@u1K777x`u4N+9*_17WJf&KcbWzDxV5M2}^V%dr-ehr(mrg z7AS;)ubk>)Esr2cwFb`U>Q@!JC!hlA(LWB9s+VEHft$OC_*{l>DhL<$mwXCf!>?7>6O3KZ0ro4*`bM8x(1+?+8F#SQBZuo!{Omhz=+ zsmlMYLPP{6zkc-(^|g8#k@U-rg#ilx1TBF2Z=-_3fE$$}KBWG!h=1jli#edhdAeJJ z6*z{{?9^K2+-2Gg@p5YG!+S@|6|rYS2ca!HXd3C=TF*8lhD0JA>r$<@m9)`n_rqxL z6xqpoJ#PmzBWZafO>Mc^3-#Qy8w!WSP}8vp<~XQi!@N&OSRQulX#&fuKQNa%ip}nW zG423&+K4P@^@F$G;ho|Z<9#Jz6T3g(DQD%RL&)VDSa;nsJ+vf4^e!Jz?re^`w^1|G zZQ&`dd6IT*0X2`!vYi+rI~2#A!#wMy+J^V7OcQ&v92gA9zs-jIk`BOWwYp14dR;JG z{oIMdA2f_9D7UjvKSPcR85b5X6aGy!G;9|mZ(tSShXPVYitvNd@wz@f-i+{*N@2`R zMMz>yNS%_ntXUwE&qfwiNSZT(X8BK!}xZTlCaB%UmJ=(NC z8%9>yOc7cE@q|zk#R|;j>4rln@s+xQ%BSE~&3G@`JnPgE1}TGpMYGT??Sl)0GGiBU za2l$$1r8c$NI?BWHIwShKLvM7OW!UL`M6$Bs@Ythgq|+<~1IBabsVO3!bv5T5W*eMtxXu&~>(xl~2$whXCVqrd8t-1=)(Jvn z4uT6G{AucR7c!kbpomxf#UvpP!C@WpB?(3_I+BpMXYK-LkG`m!iB{RhPM6L|w&{%N zaS7y{R>3QKiy$z(dmRYz;!O2GTB%-^Y}EiaZIk%Bx`D>41zdNWZ;uYJx9VBZ!%Z2?J<$~8_`a4sTvX7^H5L2?$&H$;LS{EFQmw{+2Y{R*3nvD z&uzsxCQq|*O!~($U_(TssAJZ;f$v*}XvQ1%T4Bc|S7f2@PEwOJGNIszG5c0VpA9KC zQH+DC&ked=0s3}6nQv&|EfY&Xmz1c&@bL3rZ5FvDW)C&pMXg@JWbA--8MA&exSgn* zVT|Fmo*G?HvsuZ>o-JXYGcxiF)f8c3!m2Cmc;QjlCfphA%VYEmi`?YLBqj5fOQ$+|DS_^W{zI z!!}L;L47D(nl=U@0;cLiPyK^tWk0P!$rfu+Q(uE)=q>bGI99=Tt{Q@P=)5W!GcjFg zsUxCU-XBYStKREKFVr_(VsNUo5`uh`kQk{}NKxXt*C@faBSr>ij3Kv>3Y=TUtesPU zcuD=+*(dPECh@pUmAFS23bncpM zg~NujhHLMVfRXH1W0Ey+IuJx38W94=`E)SCW|!tI2{lLpIW35rxl*Vg(R+Om%)_{u zr-hr8K47blCY}z{c@!%u)+>0H8Vlp;G^Y_;0A{Y7#nVD3bzj>(ttCySeII#|Cx)6g zCM!pB3Kyz9ugHhWmXkX(p0(NVdpyWD&g$8jflyT^N0pF1ckfhB*+&{u z0Y@4rLaJdx<%O`inrI~-X!H`5Ph!R%++FJNfC$?o_he(qBf3>%o2EA9^d7G^wlw~o z--+>$bawG-o2!#kPV49Pj??;x+RZ2*b=lSUozm4r!`wPA)G7VEPDU?I%9*Im_c)zj zz)t6u&uA2<^Qc6-*&7&-Q@QM6XoJ_vsocB6Vck<4r5baCwjLFYstugkV8| zd>4ZbkH8t(y>rE*1&LSPY(bV{%Nr5njl0I$xi%Atb>|rF>NZ09(ba8uJa6c@r%_ir zCFMr9_hbzg6(T#TZbjQDRto!l+GnDApz6txsyAg83InrI{z2_7VQoqfeB_`jm;Tl? zY03mU%09=GP~!!vX7bdHr$3*jGf-WKvk~f~mER3;b8F|@X9rIBrfXsw=Z&a*G#>gk z-qdvLoDr`^x`c08s`NPZgI+wUb49$yrJd40fcPRfPsFQ@!L%3b91*XYw;P=qy2;M* z20!l$-IsQ5un+O}k(R1wofkUZA6qOxx^qI*skrGIW83)vJ6_B>)2wUCKAWP1@`*oz z!kJ}1_c#~qXi?#4n=f65ZY=ZBzMw@=Pt?G1tLk3f7OiMgcve>N4)jer&STgKZyoFb z`GW4}q)>o3RBYMJFX-BCzI(&$=FvLN7!y-}Vm1|K?(t}5?r5Kk!&v!j+szHBzJj&I zrWDsT`wp#eyuRM)fk2D+`4KGQz0<@nwAe^y z-)M!#f#nzh(l&j02$7<HHFX+7Kn*U5+m-ri{;S#?{r&{&Yj z^4Vp>TIyDDTeoi+3sq3AqZ01+T-iy-d&N$QxL#rM9zuMH<3U)wwvJ5O9SE!4lR`_q zwL33cx7lM6-OU!!^R43v5gd7=5wjthdQ6v=bV@za%7E#WU4smm(JJJwo~EQcY7mJh zNR?K8_BuE2STh~1JAI3?%O@;-g6>6+3c1T~bTHL6YF`*tZ@jfFTF2^a(L)4fahDAX zCWm0HZkL}p1=P^y99!=+MC)%au(*G(^ST~Y+P0BZ+;!XHtkE^K(Wuf~ux*tp)?jec zaFuGb^4;~}?dm&YnJV3SLb2&a*IybsVvjCo zU41{2%QP~ch!0)0Z=_zh%nrIWO$VcJ4RI}V*pWyf>0MAhBT^}jk*N+{SJlbk3gIer z*&ERa962o1adT$*z($monBWRhc^g?vIvGg~$L-v>{#3fwQ{jMhrt7T{m|`toO@ZE0 zmS`iR7rG^0?+057IKBurAT3WsnuIyeri}!WQXb}^ z4P46A)$PV2w}C}N_EH76UfGk)mED`MdG|Re*j@jmCA^hB>l_3M3%}8W0A6CvC6}f%a}dTXa-SY4=Z`dKeg%yUZ%vr~G7D@6ou+1$7-2!u2OQqc@Q?y z(M@(5nFA)pHO+wYEp2&0aa7&0026J&UnrjT`dCa??NM~l!pR1M;ImFPdqYiy4&OEw zGpaF~-Ms1C$(O3d40voac6)24$ov5$M}IuWxHj)Y0lpT^MZ9^ba4rvp6E0V+)F>L~ z23H4aK9XMe4_ZEpn8>DT&+Ear?v6GaK$9GQX#5bkGNi@0)R+7S=ucCko54?bt*dA@ zbfuHJpqJWmpi;>>H7s^Hri_hZmfy*8sSD^ z+4MC+b^uMI&K8bI600IBEY->w!7Q}H;;I44Msf<Bt&8lh3eFP*OpVS?yk=m>px`q*KT&S;n$EcgVLHMC3yy=VdF4 z!PZ6~=ibkjk!aN*TaDMktY_(@w}w03E3>p=-nqxDL^4q=1?*(kLhc0;pQ6|)m^NNOkjkN!ck5__DT`|4FSM`_xUzYbT4ZpXyu z^^|R9g_c&mx}7I{BNO$+P)QexTZ^pssn1YDn(tO9_&QjNNLF=2FsmNU^YodD5n!D zJ7+_v%wKJxn^RnEmx8E2U1CW3iJ>__@(NvqTx$77fW+G^S5_hbdTet<0K>saQ*YN3 ziik6UQs5ku$%k$YyX`LC`l;|!y3Z7kVwHafGE>lcK-^jhQKl3X(1q>{jnpCH{v+~C z*mYV_b!X;w%w-jdPs>C^&vqg^M(+nwPb-$Zp7m1k^TaT(gZW~)^*x!i*R(Q31flisxw2p z(SqG1VDvy2Sk^mNu<|olUr+kRs>xc7ywSG5*f+XW@x75`#{lt2ajLaSqmr!@T~8+8 z3xTGr1Xaq(!uutYCC3(ayNdR%yEBTIU2k)I*+ZHVUVhjMpwOq1EgdAHxacPv~n`_6r~)v%n1= zVW_>SwZS879;+b9YeUsl(#dpUh|CzdU4VoemLWQiG;aZ($t*XRwsSC~BkD(0c&WjAo zSo`C)ov`{4>0e1EE#2Qy4e`dq_?uq)L5}d~2FnwEHQmJGY1NLj5o}(23Wrvfv>)aWWHR+yGJ(?wbhx`|{!@n%_Cgln z^9UFyI$fdiWa{<80d?|%op|KL!jh{)8KWa61_O0#3B5#+nHGe)p_L+8##bq&#I-rqv>>|M`9UmA^&~vWFg^Nq5lNu>rKId9^Y7G}(48NQKM45%<2XtcqUUDfQSA%Zuy# zfseK{N5EmAr8z>6PB+#FODHw15gS%$lVkYk*svCewzgZbkSq`zC1LuD3S7fUUy;j2 zTED}ywpzOj2v1`K3&mRHB+nS=^PlY)EVL%k1nYrGv?fI3Gz7p zD}ngwpWPkOPpRONXXAWT@Vz~WVO0w!zXSmUPHwYwtp%y8FjhNFIfTw4>gEu+sN=-y zmo|+m& z;@&n`Y)rRT4{W##%1pr23$ruf8ry0O(L(Y$P)(uckbfP?@z$rCQJO51OZ$Ny#wiAO zpb;jgQ8=(zSyT~o8ks^F64lJECGt{Me^u|cFEk+jW{XKOknJAb79UGO9X)$?I_;!s1DmPm&t^VSsbPJ_?r7Muy+vXqM(F+QPMWovn~*dAkU8hI zJdRB5)&151jILS)MSiYQwj;y_>EYUv5cg`w6ttefP`kM<2E)FVLB=Bz-}H}`s{^C) z3O`mG6z9lde|`eNYG8b>JOnike1GRob8DqLE5DfNZVX~ zqP*wsF?b}Wu}?mdM$om{U0BVaZ?;Or(?U7)X{4Fdj1hsE=m``HCSqKlo(@=|0+-{& zNO`e@4R{tts1j}3iz#Y_y<~IEK_!?mMJ#6N5=EBdW~!A%Ph&k&&1~>_z{w4}CnB|# z)JpDkQf&y-+Zh&hH9O4`Nuy45dtq<4SVUaeg<)XK#PsJK1a)_O&_ED@MHmSFfI7g~ zmiUu?;tyO$11An_8Q5*9`R`%okw&>09E&8(jwfyiNk^FSAuD4rRRp!1wpt-AZyr_% zc(E0yL`V8;1)-~oziiVOf*I#KVrNeav4ZAPCCG>-=ZiY{_RJ8Hh630lfw9QjqPCV) zC4?Kb4ndM!3t7P0808>~H$1Cq~ov$apK-BoPw0n#)wX@YX6d9@Uv{NT3m}RX^dFGBJAG{AiPT;3EpDP% zPiGMit>eU)y5K@xQeX)cT@661%PrPbSFkFoD_@%7udMGr3Ga0hrZ&JlIRK7^Wy9ky z7C~KL(GKW6F;*zU7{JCkh^qBQ`jXV>eEvY8+*G^-W*Vk_m@97wWGSRfwP^6S3Q@jQ zNEzSqnhD}#Ve@zvwwS=4O=YW`o)xD37SOGQFf-d|>g~OzRXBEj2+a%nyp>K)kgJ4K z&m4hrrvx2gu}Jm;XkW#rA`ZsZ*|{CCfBTHqLyqopJoh;%Af^x&JhoqZTb)RVw??g2 zsks#7%@zN?39Wi!(i+y-jb_NO#I@FLKWnL`Z=85~nln(;)pc?P7D)7}VR-EaI$Oc7 zhUDw6#3FX&p$Of99%Q?5KqZX}G{CbwrhQ$xdD?M`8UkU@5iP%ioGt~&vB9yf96Tf} zeUC?MXh$*_G#NnB7_5hMCc;T)0;HqdwY-%L+I_{W#vOTa#H{X}JCMYn0q&XJVAuLk z4XVw4Hlrap$w>Ak=9CGLd$2od)Bf)vcY`}_M)maVtjZObR)RoA?meU4ihX-nOTcU; z>xI!QG9=-+3$9Y4NNcbn8Va2tWqi=<$>7%`jyr0=igOjg%3_UHJ>8)Zk*P&Dcr|J5 z-v~Egw)o75&k>5WAM>zv;s{y3mZ$rtn%p`au-xK&5n7FVe@w5~7GGqY5d5IZxJm== z7j%~@E(lUs6twNziaJK}+z1%zAa#G}Fqd4ufG;A7kTtX|8VRCRLWz~%Acc7%SY_pP zkLwyl+oE9hps>80TI9C$EVhsnFp`E6q;1~ln!RZAw&jKa z>UE>o5)CFK&)`rZQ8^G87+8Cd71aI|E_GV(r@-t&KGifk`uez~e+Eo7(XEcYqTS)c z;){y;jE*fRoaj(<56w*qWs93IEw{CS&?*vcN^VgFix+kBG1oQ0=ZVqcYk{1_=Ydi3 zdtgNBfDQ7PD5W~^mPCC({_M+1kCh{gO@LXH}GBwE^>8s)v)%{;Tj{6vkg;o$C6tyoyoxxDhPNt3OxQ<(KlP7Pe=BA{i)lu}l)5yNy4128 ze8YE`Pezp7=&IhID4>_Hy9!k1bewr zyaPyuwaj6C4Lq&d^@!i$KmZrAszsVjvo( zRg#Y9f%c=FTjpEAtVuq;(cdO1$LH6fqI4TwsC@h>a!fNQn8)Xx7Hs$dgDUuD&|t59 zkAYvi2hZT`_Wr?^$A*42(wmmsW{YV;%mlX417+}Ti_NroNAV_X(X4m6+qx<0wJh9N zHap(|Vw%sC%wk%!z_lTEATC+n80svE^)+jmw(oafA`zlt%&l15sb^oa)%w^5|Uqmrg0i>$o?LQuQ9HYKu6Gpn!| zb}sJ%gdn|MK{2T2Zpiv#{RtWWcvre3&%t>0x3$G>w{@S1LET%ac;ihamaknzQED?f zJgSK*Wyxg}4Q2)wT2p3>cYg=#-eN5T1^Ppy(~X^0TgBihB^iCBnz=cSeS&Cg3tzkQ z7N@lOVC4FAxpGEW!W!N3e7U!I#=d4V8WPcbt49IBhqs%w6OYW=i&Y{?hnosz^@ZisyjY!Vy&x_Iq@$|=fuziyQ%)6> z&30Vd>p*3^mu~Ev*#!mi9(~lw>j#@iRu&shWdT~s@`1eTtmWCG1z1_FU?p0D?n>j* zbW`MRZlQ2#9rL6e5p9hw#E4MN@>?+) z2!GxM6{G4Gk7{QR@F2m2A(}J8*e%? z5;ov*sw$k{f*5gJrZvTlv~D%^Gs%FJp)K>WE?D;$>EUG?9p5?Zh(%&Z9j8-E94&Bd zn{l2gP{xd^TF`%UeQ&oGqX%Lq8G1FUZP@k}G=UW#>QI-@%)!htR=m4iG&_$1yPY<2 z6Z$`@z9wY^NyGknCzA4@0qsMjY6MFY5#6KM-h`S53r%4R2iq;O>Zw`>s^Wv0Y`6Te(VuCVGqw9VuW@COM@4Z3=`}} zNJq;^N)FPS2BCRs3l=zW5|OTr^*%CiH_+CvWfNv!RBj7Ts7^u?+d~nH z6}w3)ZiqJQ7Zbg z|A?X(v39@hs5=INbF1xd%%u-(dwud!Jn6%h@+j&!#R2r2vSYnuHqTzuKHPHgi?>`I zESTOQbrv+^P2 zP7LzrSNDDGaB$Q=jgaKFW9kS62}s9aer|At23o;~zJ2Va=QGbIDjmM(*%`@XHSHg0yd^ZaVPPvjllFe5e={8l}0_8YI z8cN_Uot(PQI8#jT%Vg-9o#Z4=ui$c2<#DZQ?q0Z4m@nq7(=184ZHIyzH815+c_0|M zGaTyH6waEsuHAIZ%{Zc`eZFGB9;>~<2-&sI=G{T+ix^Ofz2uN@ALNj3eET+|Em3L3x_QSV@Oljdn^8}5 z&P4FHHTyi6o5#G;A=->UADo!=x4NJ)gvO2CLVWmO$9slQ-VU-e33W3DChCN>Jp9gW z>EX8-)r`3B>CDA%Gb(D1SBH$nUiW$3>?zWS>f{%*eh<)ewY4U0MiZh=#Z-vn94rL^ zE@_p@v~w}|Ncb^#aXL$pp9|e6LlIY9?-p|Bh1Othm+QMyuMLxfOQTj;Dqvf)>;$;O z7}--x;?YblE_2iLcNWPo59%wAHlt5FoQ?tg2j3rRZa^c=2(}4C!R0)edL6g>WXLH< zEm}U8KHTrIlbat;{R6(n2WmZRPE}Gc_O;v%?$NPv$19H!t>4P z;q%;xK_g6gxSc~)%&Kd7RB825%%%5;PDwHA>0qB8`znH%cYIhA!q-#REvZLH%eOJq z_3i=fhb6d4y>XpumF^Anhj9&x;_4F*LVPEAJ=04A!o;g!uXGLJctEsQT02IH`Ffph zBqfnz#Gxv&X9)$F=WsW;e%QSc*wRtbZJ4#Zx`#cHbetuQDZE^jU*G% z(7skjv^~(E;*wVC8F*sn*3~^))D9VLe2VCZ#?c+~3GS5yS~nToD>FFuW;G9H3OTwW z#M$QqOT)g)ij6wk)dtoNV#{&Jx`Di$2el|l;_ZNLoT6kc4_H6i z9D-i$lH0h`$TMR?Mfb6A#-aojYjXiHfW(v{t@(4iO?_NX?J$QSi;3Hj&=;u_Y2#)M zN}r5WwPCqfl_6?IUw^tMMYUZHjn$P(&GQrieI2ez&#ME&dUt4Z*)}!a^m(sB@dnV1 zRsA^hYc4ON?Q#NHP!nUqZe1ex_&K^iqdBbucqtDb)Cv?0n$oJ#dyKP1=P4}C1Ez~R(G z{3F#$p-el$MlDll)FHaKCWG!plQzNx3U(FT2GNIXzY)aPtz!k3BZ#}K7A!Tv_w?-b zh>#wI#+D33JL^)4%peEy4Ys{l67Te6CYP(h@>E$cEKXZe>j>nNf+Nu^*qzDhf~fvf zbh=Uf5Tlou`t3sx{jqjUFkzLet*9!d!^6~Nx$x&Njl%{|`Q?S}0cmTPa?-eiTtooP zO=Gv+!kw0Nz2l1Ej+K~VDRYSRYu+Fq^su@2j>G1agkRegCVo|fh$2;Nzr#j*3NyR1 zinT|`o$MsHdzEzig1ydY?GD*RUK+Kz4eCH0Nrt^U5Y1Ov5mlS02btVIjQ_PTeCaAYpkaUu$qA!Zf+*xWNduhj#Gf9csYy z$jR4gm6}J5*49fta=VS$1*4=2WmZ|1`9+1ax}wcH`#eqsk*o{ag~FZNSU^V2DV+pu zDBlL<81L#8m6@Xl6%^E`zU>-F0vc&pJQN*>9MVq>50-BGT%||@Sj(&93(7Z3cJQp5 z(NwMc=`jAJP&PPTpLY#yWcuA-%@tNK<+TIq1ap5CWIOGVUC5J3F}g$fWyABd9$!wE z!iquKkZPj_os_*R?pxrX0ifQtpR%=YDQ07vFY%M3($(5&ZWL~XJsrg zb_P~X^TNV@+K0e%fv8zCb=TT&tB;s1lnUvY80bk+wNz@y-cli3%rzFO4x6$V3<(ma zIjl8JLlLP{Nwa!hfPpSnO6;-heEvY8Y|WrpRWR6T-wMPpK^kIUoKpr{$gGe)aj%kf zF;A>IwcWu2>0T}OTBIF^X_+!j%2LZ%b?~S;tKwKekI|bnpvmIkYoJ)z=QM{I_z zN$F9kZ$~#KH@oUrOmpfV~SzhhFBZ!z+&VJcSbQY>CKGSV~1#Iwdhgr zQT4^q<$`t*gvPS9JkAP}2Mk@_Kv9Iqy_N64NnKc+p`V--<_bmEfzcjEz-TsM>CEM; z(6f>roBVdDIkZh^HV_$#c{*lLUnrC__{0S$d>`#}X-i+kF=e<5EU1@FSAfm&^)bRs z8ZFf>b;gxHdJog9BQ*>QwY57pIE6Yt-JNoL8^lWskM>!Y*gutOW8 zyrp-P&8?1^qnBDZUc+?sI#wrowKX0EbI-N|GU}EwR&ZwupGK#4@;O-63KaXHYjZ)D zb2P|a&~6ce-!rd4jhYUKb&=OY@cl*;j+p z;~O#Wv7=s<-$o&YV54FO6zO$Bvm-V#rS;EhhE2O~Zj2IW!ilxQhU4 zgzg0nED(5kR7#=+iPnrcE9M$J2K^rmd2z&CbWQOIUr8pag?u)DxKPhGmrbXElJM0q zfn_8>U}=_X)P0@3(6SN;oHRl@7gKE#SP8VHWkHBEY7`WojT(hgX6TW3*X z+r}*hDvW=&NXDHp()L&$5@y^PrQ4BV_Br&c2r%N(-+vvGqK+A3;pX(1;&hZlyY+kM zJwUHXG^?4reyjD_4ZPt|cUaukKMB+?Q6|);9tH?fJcMpJI`0*-jH^W@K==>Zt@Tl~ z?~XQe)U%te_0r88c*dUd^;6xl4zJ?pCG1n{`^m zJ}WjNUxp*Wm~73dI;OTaft`r$u#BLkp&7!Lz@crIGV{&3MbpE>XU5 zvntL~A%8fX#UU*0o~#>$0`moZCuN>!)a?!WNbt)DXrA#XB?BrL_%8fJ5HH9)BoV#R z@YV9Z+b^e~n>X0fSt7H0T5O?BT2Y<7L8^hxJoZg~LTKTx0!X)JC)KY1$QGA1;a43X-;?=5TrNY>1oj9M1talh##D_d~MQRLt9@v5QHSw zM7vXm&E=vrvx`N5rh&s%4|7B+!A5E0#S)rdF#IaZl&h!~ zyL^Byr*C_L+`U43qG`{Y?XeDMX>o)+X;>VaD~QK2(SfgOi4}GmB{7YjJJNBP5&Hbl)vd7Sc#40umlomV52RcPNX5s@O zK00`$_t`tD%13B77;bte0L8aA9b@9!zMa!080*`#liZLz4aHApOKDD!rHg#8aQS1d zkj>ZAJNMPAO2JH>NcsoDN_iXKo=LhRf9iW?n*4*(G(hY1W>bD-!#p}9)8M#Vn)GS* zxGI{J6>?UG!WW5{{F&6?;`Gjfs?&O0%ak$C@P5+zr_)I8?#N`?W3sm^f=0C0_E_^U zYg#A^4FA4PjkhgIHTMm~Y&S{@+f)^VD{r3WbYRW(KHY5w4e@E9TW@y~Vx#7%IsZ3D zZxETQ$)O3-&>8~#Dd1h3xr2m{h^K)p!4vN#L6<@WyP*K-$9U>QeM^PqubT|>*JU1M zDT?}})h*S6LHeO)C(O>bd>I=XpK?iWn${yLr*zm0cB@99d1KaX&S?` z&8+0uM0s)996eRrPO^9po87mSt;5ce_u8kRbsM*7gHjn3=+hi(I;2swEX>9O9V3dF zORNGPPE;#ZXFiiX#C4x0Q&_PupRHD%0>zC1r%&fnI@=wIU`XYSk^7 zidEg9@|~TZk1e&uv})FfCQ|I&7*A?59WM>Wc%(NO~e3C>hf}INj0Wb^N{Ltj7il~H!Tn+aA6MO8K_HC$?<&`c5rqpbWTftZJl+jP=?cY zA?NB{T4y)H)3(l-s5A~DK4gT-TFp{%HA9*;nLm=vR~v;&8Amr-wB9VxmGS2q-q$1b zUCR&o`>thnv+r7FwEE7>DHc7w%cDa-h6e;`Fk1zi56C`@1C-Xz5}_S&C?=&tCPLBL zj7?3pc-Ze1$!Xi7m4V*O*>_%zW@@#}aymO*noOlejFUc6fc?B)xXgaNJGDo3nojnp zdNRK!!%njuR89BBx%OR3FB^Blw<#F2!gHUM@7thWJ4^mj>U4DiOAeJ;?@+&!u4_2p z0ug`9%- z1a3x=8w0&#n4D12pzE0GcY;@FcK!kDp z=07Vr?B%80SCi^|)kr2+#HDq$0@ljQ@-=i$$|Wps)f1Ce)#FoRS~lTQqu0; z0o)5u8sc@(97SqJWOsi@?#7yuMi?k`>11`Wevnm$d+fkaZJj9FHK3cxqfKFI&d?pS z$)NgEyWHXIQ4JNNlp`q?YHWugMasBI}|aP)*|E)apdc+=+t;(#HTdJ^kpF_X=! zIg#E;&GWBUsU;OmtrH4s)4DC2EEo%#RY7ecP8BpjZ8^cIY@28Dv}j(t*%aJ(V>WF< zGrO2f=gzl!k*LHbBSBfCo_i|(?9cs+tYiq0uCBIJ}XoU`ejzA#`Mvw zQ0?itS+S$s>$8Ge&?mEk8`D3tg4@$`vtky8-yUBpR15lKR`782&#d6~^xmvMNW7k( z7wj|&omTM1w8wVkv(lVCnj1o7y*E4Hfzjh@hH62-%na3-KAIP*J@%~V8G}uziD@i8 zMkTk7Vrn0%AI#L~4m!F9)!Wm_WT9MzTX!axsnYeK)mo)d$ySQ3tZBp6E1u6yEG(9@ z5Q8*NfOJJj}&7#6>sC3T-FOmK8_8fT3d|UC6x_Q{8fG5^=vmV9Oric6AkSSOebg{bc`iTo%z4xK zVGFKT_fk+hgEqto@?hcnI?UM4VZpYw<-N(#tp>wnh$6K!4EzUN3w_WPq~tAQ+%Q7+ zDyoT&UWDK~${Y+a6o1CmwL+EU^xRJHGVFJDkrlEd+p1eLWBs$LFWo_2VEAV=rwZL8 zZcE|A668yPe9h)G8$(MD8gp(Jjp>zJ<=pt zxi*FT6#@g)Bd>93%5FFtm;^iKAhtYHt4pppS1pcIO-HEc)6M7k6xIyo1?0{<+0% zHXQip>cPLPo^MCA#tKH%v<_d;2`qepj(WS{7cKHjFV%H4i&y|P+4hDF^cKtLi7^j|D~b1Mm>olMCc)NiSi0ozg07ZT6z~}VyQ<-_(a1W+K&$)~%Y{pEU!hX@bt*YWmfvgQK@5X*L)}hI#vzc`2WO2_4HB%f1d9}Bf7{WRWthS=Cvu@Bjz>xU|jR5N8 zH8*U4)x_M8q}7fujX9PIJP_Jhiz4qmHph~plqx-J31X#{Wy$Ju8v~EnE|cB#6vZJ1 z4#FZdXd6e@$im9cr^nrRLh1?5l&j#*>R`F`sOjsZ?gyU}DDxjqM@VJ*1bTL?eQ?VWQtIhDsrbKH*6>3q}S7b8CSH!*4a(KLs>ua(Iwp*sT+sG8kaLvqCs>?i;Yq;|j9+qTI zusCzj)t1yC9myTBrJQmlhlo=2s}P9#h0RTTrzW1+BE*LE8T9X+2K7&IpHZxmbA$T~ zQJ541LTFPGpsB}+h1K)uxt!C;9B}Ui)RCo_0@gG5W(RfJqIP<6ZUM~2#JQO=N&bfm zZyLTSa8*SE4d*G^!qY2Irzt)FSI8qLFCqrh98bNETwbf(VIiD|;tQCBEq?|v(CXIMCa=o%VM#3|J zG37CV`GmcD^JX)ud1}t}+WY_QU0ZjfMiSm%v`39Vm&as=Ogy7AA zG$;yGMyLz9=}#mJ0oF3NE#=yjDFv|e^zQH)HKa;U>2;8rCD}oebVR6@p6U9YJgwZ? zjg8193H4j9U-0oDx&hyNah4#lspuW+muh*IpJb;jmqDi@2vKP^sD<%IhqhukXnqeIF4vA!7zXQG z(mrvCxlKU+)XpLT-{W$AtGYPujn>q7AICz=M3e}-^3sTi7m8h)N$RKWQBp8hxKSv( zN+wd#BU#qbv@V$nKcX;Lru&1sf)x?;lEb%&ye!I|KiwO`@O^K;)WF`&?ibsHyc@&= z=%vW5K_ddq4fXDL-^{R*k%{+P!)7F0m3bCkxDk!f^hGorDd~{nmR)tbJ2mJ%W#tF* zOnK@`RMLbh>q-=wwca5w9wYx@p#s7F= zm5}LtSf-m8N!Z`8csK1r>JswOT`4s`EL^YTU*iN+?J2bi!xCMlE+YNoh*Rx8`h{6# z6#RD;*VnEe(axh^NHjUH&UPI)HQIGtFUqyraa=EYC)#aXFJf9djf>wcjwF4ur>~HB zaPNwHnH;^ic<6HdhJ2-(?J}+xV`_&{g|VKE)u&buXc^3VVdM%J=?gSwprCN^jm2Kx zl$P7L(zZ%#F|L*dg?1L-L^}(!ZnH*ZUR_SVw618zstt7!5~wmb%{$s^%A~L^%;0og zG#hA=Doov=udS{SV|+Xq{39{AvmHfUh+m}Ftq3^xw->KyCt<*MI-8};Y_`%1hyiN_ z{Z%qYR*&tpGO^CyP+bPSBDaO# zh=c9MP)Pq2b*bM}Oj$Z+oO)pQ2eO)d%j>}&dT{<`X?@W?-aI7Ha=ZT#?-w_> zP@;LD98R{65mKR{CYzbmy_U(kg7g6j60jlt=&g)gl<1H&uFAG_PhP$3WnyWwP7$nU zP@?5IHi-8$H&?tyeH@tp@7z%HYv3+kX z1a%@jeubNMOZpvhUS#;&=uS`;{=Pyq1#ez$c)O9`F7sI#;cIae>u%kP_&d_)aIJ;A z*69s0o4Z%}$|bw=_9f*G19b1!>3p>~E_abn(|khl9|QScqH>+wX+QSp^hI?{DAlE| zRA2w~dvwD)(rc*oitLW+(_X>HCc5SwA0uiSvxXb*S0gvakrn^yyo3I2M*6$yvKTGX z)hgPcu=3RbU2`UfKUQtiK+%Knl$ zKNN99`lYPokyOY&7A#ls!$Icx%Rf#9g#b?pc0Mt=`I{zCj+Sw{N)|?O!O3q4m3j`u!r?Cqq=mZCB99PF5Pp^m#Og5oTyxH{e0AG7NPk1?fFz3C!dFTp? zDwI{=GFolt@hTB@YLbDo7Xy3E49FrwWjD%bk)T!giuvM%qisjLBdZQaj%Rq=v1#}P zi${?%o;4MQ!z_;{-nPzXpw6cS#Q;+P(s-5r4-nAS4FpgBdDw37-+IdVP$iB*_zWEp zbUd@699mHFpx~6JRr~Q`g_y1SJ_HP*z*ip}AbOI898EchyrD_0Xt&=UxAW~vvWe=^Q3S44s5R1%|MZ_*iao9~HnyOE@3UOMNZ9U!nOwCimV#RmfVx zQS*4{^qcq?+UC>=$jiwdW_%=faI7?~M*C6Gu6uOC`V&oN^DT;!^=^ebp%M3pdFLc% z@jnQ$C+&{b7yYx8Bbm4IUnF38^o`kaF@FJ&;8uas$?+G8 zBKSvlx)vuUc0vdJb^&|R*NMdCn2!MEMD3CqYoWh%iG9CO& zBH6Hxs?~-HxmFMY7edn7!QLISl0ubS1U8bhA^GfOFVi1M{8x1Ro*u&gY24I10u(Md z{fKpc8^8h+cYw0Bvm1c4`%ah;2Us5GaDwiQ(E+xDao<&lUtL~z1&?|0KvV4f#gk3c zz4*l=b*emt^@aDw1FulO4E4X$nX87wvn(&56F$~?v4!qHY{mmZbyHS5I(}z?P31(T zU~3T_DigaDkt;(rP^YX=4e_jVw(TXMoTYig9d zRjp%Hp3sXFgZc!0ZA`L+63XNKRj0Yqpi6QPFU70X1ksEMBNe(l?X)=|XZ~U=}D``CI8?dWo-6px69rM3$NH>HM-JuU=~| ztW+J~*0F9nbx6+qDmb48XmWiZghH#Cn_YcD*aWUGQ2$6SPofl#Ns`2TQY#57MAaAR zJUQHao~>zAr8t>qke7})U+Obdp71mMpZlvJEtk-y}n;@Y!7UrhlTW)ve%qV%W3E%$ODc{ydCg;+ZN5BLoI_e+@`|ailD_gqbG#}_#Jb$6(gdr;(|wKyEXFFZYa(L z&=uFK3ty^TRNblVZ7%E$k<$8@a3N!bJ7y-v^*N^vev*^wa|&WW_>RcxDdyzxG#5Ly z;4}qm;#j0t1E_hnMRTaFFI430WN`}XN2MV(7W~+w{3W8K#CVR3DVfXFV1-d(g##t! zi6C|TRWggQ!B3R=XZ@stMCIS9`cdhZO6i)F8a4t>#hCA(nOYXdf z%YK^;7D<*GbPIFQNXD^h+DIko+$$yXp$fHX6J1TXtS0MVtjkiJ0vCj}d&l*;G?yfJ zcuRw2Oowp$L>5yB8#q{3M(HgBRhp6 z6p88>l$@XjmCkX7!F!QVv+R=<*tgF`D!7fhIM`SX-kZ49}*>%YRA3?bm?P zGiRb_J14a8(`J3dK7pq>){!fKS7(*od;t~n43&FJ1;0Oit z37?U9gB+k+M7LKw!b2ekz0?l1YN*UdwOYDCU3Jd-l$jul?r1)M$OXZ_(dt1y|9u~) zM@;d<8!T9)%Vn}pHgh>Ro>N+ih+cInGUTB+37FZ^hbC5`n!SPzG&@vbJVS5k>CdUv zlTj&Qw%FiN|TXwbM9ATG?(j~)_nw=3*(tG)|`4swC0^PSJu0rSGJ`mg>X zKE@^xh2Q&D4UOFdz|I6ExtKWvcpZEOhhmskxS|c+T&3^Hg(SS+XKR0eM6>KWLKL+F zmJ-Miu8w3MGf5!1qUE2aUJO!CB!S)vu`mx#6#5)kGXkK#a!oeC^)Yo{Tg4V^pNxyz z=qA)V(1kDdcLU;aym*Rn6{=kCt5C1b*Djv^xGPZ+zLu&8f=OpkL;j}OK1NMBbT^?^ zIcbIi>y7TyMY>Ps$8@_veRQsm#Sg_S@2gu zkAKrUj`mSec1#uTpVG8jNxe>9c0Gh}WY9zIOYlwr zP@tebg|js?)C%)W@lrwOD10VYv1a2#`mniAk2ecgjy#LWv>u0t;{yHq57Bb9jgRT( zL1-X))0TT>J$n3xM8QrJt{(^Y7FsY5M~iQM2`Uita3$I(gno1)?*5^SFlZdk$)>$&CIP z!maphh%ygqoupOqWvZdje^8`H-yG|u?%F9`UwJvkYy1Bh0&}tfaFL`vgVZaBRE*Hr z>&ihdf-7b(ALa|UtI}UMh=?+B-<9zYc?M_%^C&z^{I!eQENAK@g^ner2GE06(s^H{ zBA0uE-JS$eivGB26QW~=Px1A>vYLw6C>!_Yuo+euuLHtm)pbUgQ0$9xsDRuOtencdT<#7DWroy?LLSdGr3}0X;Ct>B>KEe9w*uheT{(Y(BkbC!lyK&s%te=UQjOM%7@DrSf-w(BUK zqcsH5B;czMK6=yD{#xi#uT|$ftZ*m1j?w)2IeJ)a?-3_>!T^GFlOEwe`!xIZ>n}4j z&wad)Zjk$wZm3E5KjD<)&NX=?Cs|K^c=kk>XLnnEP^u6;h5jyj|BIzoW#b8)J?_=q zg|TQGk1mxdw%|C@gBw_p)L^^lQxu~L$hQh;^0_0Sj(g+Paz2H5HFV+ZOpY`yfu3XS z{5}3_;l7kw-OR_kKSJS(l+?0|QXSx}P$u~sftdBS52?mQ2V?j>dFEuvU*Uh2-bZ%E zuE1TpH`MWS7Asc!wQ|Ym{%=X!cJXK}SRwXVhd<+UiZs`~lTi&XjP-JVpPQj#ay-r7XK_(}E zZI{dNS(lmoDMH}J9ixqqX+}G~+HQLwq3 z8C>PuOV8X(*E{nk70_(FYub)W+1N_K7-2>-HPsgNVG4>?OHJnSE}o}ZErlhrD|rc} zk%F%JSg9F>e7T-NLy}ta3ZIHKmpwer!jU`~`B z%9^!{%`T6Ep_A!uMS!Jskah)cEo-9y#7QdqWFB6gWS()ODixXRF;G($ibYN+R zszyIxT@wPWYb>RI7u+=jE_a;Zy5xgq_lYd#;Vn3gLj-d|Wib1E`+e)o?ah zKq~TVY1%A<#Ihqhn zdx1_Vu69)@aI1^kmMBAI$krv5LC1Q=P+NJ{{(>L8QB5ywE7?g9Vrb*T2Hsut`(q<0 zGix1(OC8=Wg`Xz=C65#xTDT&hcIgahz2Oz!piFA6w3T|%$f1gM5xg6vaS)4ZlfFiV z)Ta+0qU3p=>@dhU#%MfdJsDb0M%I(5^@Q0AvA}+7VmX2Tpf_%vXS^&EQ{3?1+dZQc!h zo2Efv;~R|aXCr3gJ95B0a=<)t?B&P--^jP|82R>IjvQxUfoF zzf2r*W8#pB6UP~xOdNPPWX@!2(`w?N)zl$#rk;HUr;fXB>e%0DVDrn=A%~_8naBpr zCLkW#(6E8y*sy`)46}hlnB$=hB^x+c4i9ZQGQeaBV8$FL01xeB#+ZY?__YIf=8y!8 zxzJ<|S;bi3`nrQl0jAAXP!C)nIRrjq4sK(fOXYCg>CAHoOXfMG7V}(adVwvEKx117 z;GqLe&vDG4201vyn>y$@bnW}lh0)Npn?v6gIBe*Ul6dG~#i2vKfNLB_W;k`=?ou0= z?>Y#+i=MvgLxDqFvcPj}M=*5Y9=NC!IMibnxCj!scs_8jxBY2{OmW;e4rPfsgeZiB zEh8KkEU>WNvsurvp99T~o3W{5AQVq2x%+pXR4&Wi7~3Adqu?sp@3;H1m!`r*LwT`! zLl~8{yV?#!KN*Az;YL!E;mNh5Ifvl8p|}BI;(*h0FH!ckCq5W2;vJQf?e^Q_cD`My z)ul~5zK<8t@^Ql}rxD&*WiJ#H-q|SKpyViBWGP>2DeKJv&FrbBC-b)GuCrZ6@MAnA zr7N*ryvI;4V`~}`zPx8_f%twU@ynMf+kmP*a`HEF6V6Bu5tO@ANe*YP^r4HDc-J;& o1*EbF(_M#ODMpbx{s_+s!c?C^_FVpze=CCJ5w&LFvhW}O2hY-o@Bjb+ literal 0 HcmV?d00001 diff --git a/c/mainjson.cpp b/c/mainjson.cpp new file mode 100644 index 0000000..b711e1a --- /dev/null +++ b/c/mainjson.cpp @@ -0,0 +1,47 @@ +#include +#include +using json = nlohmann::json; + + +#include "utils.h" +#include "circom.h" +#include "calcwit.h" + +auto j = R"( + { + "in": "314" + } +)"_json; + +typedef void (*ItFunc)(int idx, json val); + +void iterateArr(int o, Circom_Sizes sizes, json jarr, ItFunc f) { + if (!jarr.is_array()) { + assert((sizes[0] == 1)&&(sizes[1] == 0)); + f(o, jarr); + } else { + int n = sizes[0] / sizes[1]; + for (int i=0; i " << it.value() << '\n'; + u64 h = fnv1a(it.key()); + int o = ctx->getSignalOffset(0, h); + Circom_Sizes sizes = ctx->getSignalSizes(0, h); + iterateArr(o, sizes, it.value(), itFunc); + } +} + diff --git a/c/utils.cpp b/c/utils.cpp new file mode 100644 index 0000000..45124d8 --- /dev/null +++ b/c/utils.cpp @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +std::string int_to_hex( u64 i ) +{ + std::stringstream stream; + stream << "0x" + << std::setfill ('0') << std::setw(16) + << std::hex << i; + return stream.str(); +} + +u64 fnv1a(std::string s) { + u64 hash = 0xCBF29CE484222325LL; + for(char& c : s) { + hash ^= u64(c); + hash *= 0x100000001B3LL; + } + return hash; +} diff --git a/c/utils.h b/c/utils.h new file mode 100644 index 0000000..e2d72bf --- /dev/null +++ b/c/utils.h @@ -0,0 +1,10 @@ +#ifndef __UTILS_H +#define __UTILS_H + +#include "circom.h" + +std::string int_to_hex( u64 i ); +u64 fnv1a(std::string s); + + +#endif // __UTILS_H diff --git a/cli.js b/cli.js index 3aec47b..86c7cef 100755 --- a/cli.js +++ b/cli.js @@ -30,8 +30,11 @@ const version = require("./package").version; const argv = require("yargs") .version(version) - .usage("circom [input source circuit file] -o [output definition circuit file]") + .usage("circom [input source circuit file] -o [output definition circuit file] -c [output c file]") .alias("o", "output") + .alias("c", "csource") + .alias("s", "sym") + .alias("r", "r1cs") .help("h") .alias("h", "help") .option("verbose", { @@ -63,11 +66,49 @@ if (argv._.length == 0) { } const fullFileName = path.resolve(process.cwd(), inputFile); -const outName = argv.output ? argv.output : "circuit.json"; +const fileName = path.basename(fullFileName, ".circom"); +const outName = argv.output ? argv.output : fileName + ".json"; +const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp"; +const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs"; +const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym"; + +const options = {}; +options.reduceConstraints = !argv.fast; +options.verbose = argv.verbose || false; +if (argv.csource) { + options.cSourceWriteStream = fs.createWriteStream(cSourceName); +} +if (argv.r1cs) { + options.r1csWriteStream = fs.createWriteStream(r1csName); +} +if (argv.sym) { + options.symWriteStream = fs.createWriteStream(symName); +} -compiler(fullFileName, {reduceConstraints: !argv.fast, verbose: argv.verbose}).then( (cir) => { - fs.writeFileSync(outName, JSON.stringify(cir, null, 1), "utf8"); - process.exit(0); +compiler(fullFileName, options).then( () => { + let r1csDone = false; + let cSourceDone = false; + if (options.r1csWriteStream) { + options.r1csWriteStream.end(() => { + r1csDone = true; + finishIfDone(); + }); + } else { + r1csDone = true; + } + if (options.cSourceWriteStream) { + options.cSourceWriteStream.end(() => { + cSourceDone = true; + finishIfDone(); + }); + } else { + cSourceDone = true; + } + function finishIfDone() { + if ((r1csDone)&&(cSourceDone)) { + process.exit(0); + } + } }, (err) => { // console.log(err); console.log(err.stack); diff --git a/doc/lc_example.monopic b/doc/lc_example.monopic new file mode 100644 index 0000000000000000000000000000000000000000..2293d99b43ae8cd9dd56a4f77922a2db094a6b0c GIT binary patch literal 1301 zcmV+w1?u|$O;1iwP)S1pABzY8000000u$|9>u%yY5PlWp-&Bfkx$yTq#!(f8#6WgK z%t=Cb_f)+5+DXQQgzgd%w+N7`)^+XicrM>uOy7}QeiLz3qQ$!&z7Rc#WnPKA3YVG4 z6Oo`rRqVwaZDk^|uo6Ejw5S)m45`^&87^g!h$4(-CJVG+#Pf0BIKDGS!YfQ;!UJz8@if8{C$0Hf1#L*^7TH8iuM$=;B&MpqOAy{Jl@D6EW`>J!s>vQ znfl0ZSv04fOlD;>naTLOzTPUzO2tPa;|?uNYLh03$jySd+7xoX-k6DHq}Wzdc@kE? zcIrapWKQJznnr$Av_=bcC%rUG)igN@NUm0;&~kO=4uboY>Hmr*!oi%XxpKc$i`7=e zqq@MquV%A32l#CD*CTo&gQ7emn5v!3)#-X0nK^9cV8c)>i(G2}AJ3>amLPwkmdYYs zr@7`E&tC$wx5o_ZKcn+g1-2};S55V9k=rMi};LU=s?x2V+ zS*t8sE5EgGqGw2bgp}j>t=N&o4seuAj;BpzO8S9HGaQ|<`;94 z^3#p^Jxzqc*v3Bl0A_&80|HA~RdUvGmFgTErzWl;5UsCqeu0f7O1tX!A#D|21y+et0BrEHYjOQ4x&iRC-YeQWq= z@8^vPEacW&tmN5Zoiwnp@vRg>2CWqO`QZga;{-$F1Vg|f5OBzYwOPrvZB}ltmBIpR zRg7z?-gc*GrEq&SXRWLr!u9a%1NazcY99oPBaf#J;daoWK>>ip7IglJ^0%m*X({ww z`}Lga{@`AJz?VLlw(pBjUA0yTi6}hGAPADpPanO01mI_(Y8VU$5v3a)>nU)MF>#ss zHx`!}f5zpB3qF2vL}u=w;QNAz%%Hqu;APCX8TgqplZT4P%)2ro`(sc6-&z|8Kifc) zq5>VCtz$OG*7@gS1El5{QgaMofdMS=gY|;&wY?yWtu@Cnogniij=jfIZt3NY*rAI( zdrvsnk|@~ywZYi%vC*|x@H%%VK+l~)2r{1(2&{n+@$L1Fi8ZxTZV#0;!WKC3^ zvbz-jh53HF6h-agZv7|L>@$S571ee3NnCc&>%pYxwxmtHDc(Z^OYQzCLLDDfyE`|Q zrBm;jrB9fpcTw` +discussions-to: +status: draft +type: Standards Track +category: ERC +created: 2019-09-24 +requires: +--- + +## Simple Summary + +This standard defines a standard format for a binery representation of a r1cs constraint system. + +## Abstract + + +## Motivation + +The zero knowledge primitives, requires the definition of a statment that wants to be proved. This statment can be expressed as a deterministric program or an algebraic circuit. Lots of primitives like zkSnarks, bulletProofs or aurora, requires to convert this statment to a rank-one constraint system. + +This standard specifies a format for a r1cs and allows the to connect a set of tools that compiles a program or a circuit to r1cs that can be used for the zksnarks or bulletproofs primitives. + +## Specification + +### General considerations + +All integers are represented in Little Endian Fix size format + +The standard extension is `.r1cs` + +The constraint is in the form + +$$ +\left\{ \begin{array}{rclclcl} +(a_{0,0}s_0 + a_{0,1}s_1 + ... + a_{0,n-1}s_{n-1}) &\cdot& (b_{0,0} s_0 + b_{0,1} s_1 + ... + b_{0,n-1} s_{n-1}) &-& (c_{0,0} s_0 + c_{0,1} s_1 + ... + c_{0,n-1}s_{n-1}) &=& 0 \\ +(a_{1,0}s_0 + a_{1,1}s_1 + ... + a_{1,n-1}s_{n-1}) &\cdot& (b_{1,0} s_0 + b_{1,1} s_1 + ... + b_{1,n-1} s_{n-1}) &-& (c_{1,0} s_0 + c_{1,1}s_1 + ... + c_{1,n-1}s_{n-1}) &=& 0 \\ +...\\ +(a_{m-1,0}s_0 + a_{m-1,1}s_1 + ... + a_{m-1,n-1}s_{n-1}) &\cdot& (b_{m-1,0} s_0 + b_{m-1,1} s_1 + ... + b_{m-1,n-1} s_{n-1}) &-& (c_{m-1,0} s_0 + c_{m-1,1}s_1 + ... + c_{m-1,n-1}s_{n-1}) &=& 0 + \end{array} \right. +$$ + + +### Format + +```` + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ 4 │ 72 31 63 73 ┃ Magic "r1cs" + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ 4 │ 01 00 00 00 ┃ Version 1 + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ 4 │ nW ┃ + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ nW │ 01 00 00 00 ┃ nWires + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ nW │ 01 00 00 00 ┃ nPubOut + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ nW │ 01 00 00 00 ┃ nPubIn + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ nW │ 01 00 00 00 ┃ nPrvIn + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ + ┃ nW │m := NConstraints┃ + ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ + ┃ nW │ nA ┃ ╲ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ + ┃ nW │ idx_1 ┃ V │ a_{0,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ nW │ idx_2 ┃ V │ a_{0,idx_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nA ┃ V │ a_{0,idx_nA} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ nB ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_1 ┃ V │ b_{0,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ + ┃ nW │ idx_2 ┃ V │ b_{0,idx_2} ┃ ╲ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_0 + ... ... ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nB ┃ V │ b_{0,idx_nB} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ nC ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_1 ┃ V │ c_{0,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ nW │ idx_2 ┃ V │ c_{0,idx_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nB ┃ V │ c_{0,idx_nC} ┃ ╱ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ + ╱ + + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ + ┃ nW │ nA ┃ ╲ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ + ┃ nW │ idx_1 ┃ V │ a_{1,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ nW │ idx_2 ┃ V │ a_{1,idx_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nA ┃ V │ a_{1,idx_nA} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ nB ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_1 ┃ V │ b_{1,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ + ┃ nW │ idx_2 ┃ V │ b_{1,idx_2} ┃ ╲ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_1 + ... ... ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nB ┃ V │ b_{1,idx_nB} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ nC ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_1 ┃ V │ c_{1,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ nW │ idx_2 ┃ V │ c_{1,idx_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nB ┃ V │ c_{1,idx_nC} ┃ ╱ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ + ╱ + + ... + ... + ... + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ + ┃ nW │ nA ┃ ╲ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ + ┃ nW │ idx_1 ┃ V │ a_{m-1,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ nW │ idx_2 ┃ V │ a_{m-1,idx_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nA ┃ V │ a_{m-1,idx_nA} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ nB ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_1 ┃ V │ b_{m-1,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ + ┃ nW │ idx_2 ┃ V │ b_{m-1,idx_2} ┃ ╲ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_{m-1} + ... ... ╱ + ┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW idx_nB ┃ V │ b_{m-1,idx_nB} ┃ │ + ┗━━━━━━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ nC ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_1 ┃ V │ c_{m-1,idx_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ nW │ idx_2 ┃ V │ c_{m-1,idx_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ nW │ idx_nB ┃ V │ c_{m-1,idx_nC} ┃ ╱ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ + ╱ ╱ +```` + + +### Magic Number + +Size: 4 bytes +The file start with a constant 4 byts (magic number) "r1cs" + +``` +0x72 0x31 0x63 0x73 +``` + +### Version + +Size: 4 bytes +Format: Little-Endian + +For this standard it's fixed to + +``` +0x01 0x00 0x00 0x00 +``` + +### Word With (nW) + +Size: 4 bytes +Format: Little-Endian + +This is the standard word size in bytes used to specify lenghts and indexes in the file. + +The format of this field is little endian. + +In most of the cases this will be 4 (32bit values) + +Example: +``` +0x04 0x00 0x00 0x00 +``` + +### Number of wires + +Size: nW bytes +Format: Little-Endian + +Total Number of wires including ONE signal (Index 0). + +### Number of public outputs + +Size: nW bytes +Format: Little-Endian + +Total Number of wires public output wires. They should be starting at idx 1 + +### Number of public inputs + +Size: nW bytes +Format: Little-Endian + +Total Number of wires public input wires. They should be starting just after the public output + +### Number of private inputs + +Size: nW bytes +Format: Little-Endian + +Total Number of wires private input wires. They should be starting just after the public inputs + +### Number of constraints + +Size: nW bytes +Format: Little-Endian + +Total Number of constraints + +### Constraints + +Each constraint contains 3 linear combinations A, B, C. + +The constraint is such that: +``` +A*B-C = 0 +``` + +### Linear combination + +Each linear combination is of the form: + +$$ +a_{0,0}s_0 + a_{0,1}s_1 + ... + a_{0,n-1}s_{n-1} +$$ + +### Number of nonZero Factors + +Size: nW bytes +Format: Little-Endian + +Total number of non Zero factors in the linear compination. + +The factors MUST be sorted in ascending order. + +### Factor + +For each factor we have the index of the factor and the value of the factor. + +### Index of the factor + + +Size: nW bytes +Format: Little-Endian + +Index of the nonZero Factor + +### Value of the factor + +The first byte indicate the length N in bytes of the number in the upcoming bytes. + +The next N bytes represent the value in Little Endian format. + +For example, to represent the linear combination: + +$$ +5s_4 +8s_5 + 260s_886 +$$ + +The linear combination would be represented as: + +```` + ┏━━━━━━━━━━━━━━━━━┓ + ┃ 03 00 00 00 ┃ + ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┓ + ┃ 04 00 00 00 ┃ 01 05 ┃ + ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫ + ┃ 05 00 00 00 ┃ 01 08 ┃ + ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫ + ┃ 76 03 00 00 ┃ 02 04 01 ┃ + ┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛ +```` +## Rationale + +Variable size for field elements allows to shrink the size of the file and allows to work with any field. + +Version allows to update the format. + +Have a very good comprasion ratio for sparse r1cs as it's the normal case. + + +## Backward Compatibility + +N.A. + +## Test Cases +### Example + +Given this r1cs in a 256 bit Field: + + +$$ +\left\{ \begin{array}{rclclcl} +(3s_5 + 8s_6) &\cdot& (2s_0 + 20s_2 + 12s_3) &-& (5s_0 + 7s_9) &=& 0 \\ +(4s_1 + 8s_5 + 3s_9) &\cdot& (6s_6 + 44s_3) && &=& 0 \\ +(4s_6) &\cdot& (6s_0 + 5s_3 + 11s_9) &-& (600s_700) &=& 0 +\end{array} \right. +$$ + +The format will be: + +```` + + ┏━━━━━━━━━━━━━━┓ + ┃ 72 31 63 77 ┃ Magic + ┣━━━━━━━━━━━━━━┫ + ┃ 01 00 00 00 ┃ Version + ┣━━━━━━━━━━━━━━┫ + ┃ 04 00 00 00 ┃ nW + ┣━━━━━━━━━━━━━━┫ + ┃ 04 23 45 00 ┃ # of wires + ┣━━━━━━━━━━━━━━┫ + ┃ 01 00 00 00 ┃ # Public Outs + ┣━━━━━━━━━━━━━━┫ + ┃ 02 00 00 00 ┃ # Public Ins + ┣━━━━━━━━━━━━━━┫ + ┃ 05 00 00 00 ┃ # Private Ins + ┗━━━━━━━━━━━━━━┛ + + ┏━━━━━━━━━━━━━━┓ + ┃ 03 00 00 00 ┃ # of constraints + ┗━━━━━━━━━━━━━━┛ + + ┏━━━━━━━━━━━━━━┓ Constraint 0: (3s_5 + 8s_6) * (2s_0 + 20s_2 + 12s_3) - (5s_0 + 7s_9) = 0 + ┃ 02 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┓ + ┃ 05 00 00 00 ┃ 01 03 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ + ┃ 06 00 00 00 ┃ 01 08 ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━┛ + ┏━━━━━━━━━━━━━━┓ + ┃ 03 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┓ + ┃ 00 00 00 00 ┃ 01 02 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ + ┃ 02 00 00 00 ┃ 01 14 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ + ┃ 03 00 00 00 ┃ 01 0C ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━┛ + ┏━━━━━━━━━━━━━━┓ + ┃ 02 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┓ + ┃ 00 00 00 00 ┃ 01 05 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ + ┃ 09 00 00 00 ┃ 01 07 ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━┛ + + + ┏━━━━━━━━━━━━━━┓ Constraint 1: (4s_1 + 8s_5 + 3s_9) * (6s_6 + 44s_3) = 0 + ┃ 03 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ + ┃ 01 00 00 00 ┃ 01 04 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ + ┃ 05 00 00 00 ┃ 01 08 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ + ┃ 09 00 00 00 ┃ 01 03 ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ + ┏━━━━━━━━━━━━━━┓ + ┃ 02 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ + ┃ 03 00 00 00 ┃ 01 2C ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ + ┃ 06 00 00 00 ┃ 01 06 ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ + ┏━━━━━━━━━━━━━━┓ + ┃ 00 00 00 00 ┃ + ┗━━━━━━━━━━━━━━┛ + + + ┏━━━━━━━━━━━━━━┓ Constraint 2: (4s_6) * (6s_0 + 5s_3 + 11s_9) - (600s_700) = 0 + ┃ 01 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ + ┃ 06 00 00 00 ┃ 01 04 ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ + ┏━━━━━━━━━━━━━━┓ + ┃ 03 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ + ┃ 00 00 00 00 ┃ 01 06 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ + ┃ 03 00 00 00 ┃ 01 05 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ + ┃ 09 00 00 00 ┃ 01 0B ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ + ┏━━━━━━━━━━━━━━┓ + ┃ 01 00 00 00 ┃ + ┣━━━━━━━━━━━━━━╋━━━━━━━━━━━━━┓ + ┃ BC 02 00 00 ┃ 02 58 02 ┃ + ┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛ +```` + +And the binary representation in Hex: + +```` +72 31 63 77 +01 00 00 00 +04 00 00 00 +04 23 45 00 +01 00 00 00 +02 00 00 00 +05 00 00 00 +03 00 00 00 +02 00 00 00 +05 00 00 00 01 03 +06 00 00 00 01 08 +03 00 00 00 +00 00 00 00 01 02 +02 00 00 00 01 14 +03 00 00 00 01 0C +02 00 00 00 +00 00 00 00 01 05 +09 00 00 00 01 07 +03 00 00 00 +01 00 00 00 01 04 +05 00 00 00 01 08 +09 00 00 00 01 03 +02 00 00 00 +03 00 00 00 01 2C +06 00 00 00 01 06 +00 00 00 00 +01 00 00 00 +06 00 00 00 01 04 +03 00 00 00 +00 00 00 00 01 06 +03 00 00 00 01 05 +09 00 00 00 01 0B +01 00 00 00 +BC 02 00 00 02 58 02 +```` + +## Implementation + +circom will output this format. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/doc/r1cs_bin_format.monopic b/doc/r1cs_bin_format.monopic new file mode 100644 index 0000000000000000000000000000000000000000..b49bf3a54878d46be8c89ade509bf6b5acb6d4b4 GIT binary patch literal 28845 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 literal 0 HcmV?d00001 diff --git a/doc/r1cs_example.monopic b/doc/r1cs_example.monopic new file mode 100644 index 0000000000000000000000000000000000000000..e4aa83ba6c882927080c12ba4edc6362d9316de8 GIT binary patch literal 5950 zcmX}wbyE}$v<6@rsinIcBm|^Ox`d?!q>%6;sW!=3Z4*;xXyW-20sKWclzuBjp#Dp}IivSgMr@ay)>?_(Q!49O{4C zw)euYdJe|T%Ir7`8zszg4Qb?t}B;e4~UM-!M_McZ>m_B?jLS?;n>KDgv3?g|GP%ZW&=Na;4D#(U(Wp(oQc-+WPcwG^^yr0n zaQXd9N^zo0#?df`$d1x^Z2=ci-_}cCFn09$~bQo0k6hk@!o${+yg9{=t=2pT0bS!B27{D*38w z+yZa^?5LLQ;H@Tro(?n+BRj@FWit%U>3i;THQ$xDhqJQ>3Sd=UlY>B4cboEvgPrLC z^FR)fpYsD=HwSJvaN`B(TSY|6&v|%9$LId7HFWP)6oL89`mayI?WSCX=x`!e|N#WVabcO!qdPI&`Yo`MXYU#OOIUYdC@Ev&ISXC>^9FK5LQeoQ{ zznRdNl;QHV^tPVQXytxVBDd)FCu^{M>Jo#j9~lixn5+_}8U^jBN|kZztabpz91F#!8s4y%0mlWl`q$;~(gao-HX~gA%>{URqDh5Ut#< zTc?O8lkoh@nzW#v=fL_U%}2OAqVCrzx$CXP7$NYoRCD#^8q^kaM*iLUYtZfK#()dS zk9g}Io||`f?CFWe{x67AuZ<#5P$95q`1yLGlDN~*MffNF!<$=a84NM*s>IAO!^g7L zDa+3e{%~)YB`~{YNwc_~zje?q^!+bWTs|aB3imxW6e&21@0KjA4J)(zAYh88e;?19|=AoHpP7^8uqN?Ua(>j~xQLfQpx zhHryq_sK)tjWbZU7&_1*sI@gYna_DUIFr`i*%s5! zYZT~A>CNM@w~!ri>^(*e zh}^m9r;y}c^b|{~YC&OFf}J9L#zj@Aej~Qw1T)kXPQ)<@EwgH=4PaDFXyjAU5;MP5@evIHoIB`(za*>uS!-ca*WV& z^ylL7$3^er)y470#CGDQT^3g9imptFX%>@!+OEdMwPmNX<0fx96_rAM)vbM5Y{ucsphkDX z=_`ovC0cyT^^$yDO~s}xZI zC+{FB;fILdRID1&R(m2T-@Au@)3>@CPHJWrU?_FZa4R-!M<+)r-qelKk@-4XCKr;E zC8n_c#wJKsz@d2v*9HT6|3zzyW`fF!Y%c9$Q2h{gT(>-;RktV4s+%RP^}$fL7s}Ei ziVCb3S1$(;=hQ~*Ru;wMvHfV~W87(-iom^&7aSK%R#_H-By~g6@Q|>v7E{R^Mr5q! zOGZ1`hLk>zRzw+oRm2j0IurmMih~a2K!<7|abeE4fdv`Mv!@Ews7K*nz!!MUuwnjl zJT%d88|$g&6{z@tmi)p^IUA=-Fp+=>O18s;l`}H*2bLWqO%mlSWAik_h7vl7En?4_ zN0Nc90#U~k-KP=U$6e$uLwAwp_JH8n$8qK74g>U~x;|ktWbGhFy(z}v>6O)$sUQ<@ zStf9KVI@EX@SRx&qkj&LXE<6@oxD=?mu`EcTO8U;C2^u{u^jod0wu2l+}>;3fuOQ)@dK`YYqiTF&&# z_0vY?_bg5k8)a>C#%!6rGI$eKc_uyQO)oBNl+|1s?l6e{kvVTLDY}@7Js7+&MOVxZ z=*4&hv=^x45R%`sg_fY|$u@WZ;>cQHDOb^0nu4Rp_Azu9=NL+gfX)$Wx1Yv#W8ExU-Zx94rq^(h zL)k`21D8SO&C8jeZftW$nw`HK+2-1lkcF>A`Ap1o5apYwdE{dZoX1&kG!dB+t*g_p z5Mz!FqL%msr`4zLmv}}4%E26j9GjUt;J?7C>1+wDD-dK=6m=+A>}-7#>)<)GL7TB8 z2uUkHO=}Ge_4wuP>Jbi)|I!q}adeOVh-S~vC^Pnv)#R)c8%l0QP0A;5V2Zp|3|_NE zaZ`ti_JnEA%4+Hi^1b<(Mb7;zd};#D(3p%>P`da!$cHDc0cXGccyStO2r^si^kFO)4Kt4{B)i?qs|C`k@8psB0TjFO>j^bP*Ot&l_~INtX`3%+p;ITDs)fVo zv9142gVY0byc>GCs-g#60X6? zbnU2(U2ce`*6&5|8=b=qi{v(qqQfF~3uBZ6%Me3tR6tEGgBtP7am{};^x z+mmF`G`NxM8?WhmTd+=v?>j7Ca51$cKsU3HZ`hioq>}ERl_aTi+=XN4%$oNjM2#Qg z0pMu!4DHfI=yqlGcy+Nne|}E!fnH{oorio*f9Lrh+T8KNW&^}qi{Ob!a*N3Zqg=O- zldX@L~@q7Q|Tt!f`$;D^w7;vrmi1M z_ESo~+^>tR^Yf%c-aN8zttdes0 zXocx_l!9)d-5QIGLV8q+Gvvo=f!cuE=)DAZ&+m4Lv6K~%G~i8uDH1X_>Z0XeW(y_f znRU5U9eOL;@5wXEvV*)Rp!c8odWURBCmvm#xWh^dNH)NJN`{u%Wqas*k+ZmI-_`8wGs7-zS9?)uh4jVrqvFl!3`^nWqysYzX5~Xc{#EX zBtF^J)^t8gsQCWt8};aPF0?*Xgta-B-9?9K=33Wt<>EU+AM%N9V$<}>#cfHUK;JC7 zxfMX^oVFs?c$4QIi4JB^)+x#KGOkR$Cl!S38OXLheBg5=uTg|VB^A8yC(~R28H`{> z1$v<2<%Be&#x>BcD|K7z{Kc!x+zg#BTMJax9yui5w%7T9Skh0t=tWc~{7O`cn14UL z;*D!B(aQlt#;`gJ`(Yb1F<#cy*g#+Y)n>frwFG^|9x?TUWC(ptyGzOcOVAL}F+Nfv z(sKHUokvl;EsQbXfqbYcprx1HQCGDNEXhVKXU-4FnWX7(dz3L!grLE&IF<@f2MD#q zGA+cfP}8=bipj-+;&MXrO+!eSv~NEces+#$4TKdz3lK0|JAnuKerePO6zJK4W=`hGpv+cgvVY1G0&+`VQl7NOaJ<$`LjblM^o5^xFqw4-_v=U*=k_lvo zt5HijF=uB|pp(WprkB?R()D#>wPP2511d8m%F5*QmwcCmX;KubJ8cm*uU>ZFD1FJI z8p>X5}|EOiMmPWbD5} zrZS1FSicYgj_{>HN-r(N2??kN07EZb(`iKg6*0+w^RbgdCeQ|)+2o{S0;#7oz}hZU zXg{)}Md?xnY8;F`v#8{HL?ancfo8uVk9U>-)tdH#>9q-0r$cs$+U`QOHx1X^TtWKq zYy@rgEv4cII{=VWmU?=p+&h|S2*;Gy)1kmBo;S0keFux#w_l}zFNHl$usJN*h&>L( z*GHaLHYBWx;kipd@IX_Ns`?2Z&tqnTF{f|NxaOcOK}quvSLP?{VL$PBiJ@ticNKM4 zol84L!_H%VbU}j)M_;!>msgFMgu$Q6@-saT=PGKP>fCOb_mYfVm%$*BxoB;Maeie1 z4B^BO5|a;Zj$)4GvZ%C`O-OhvD8Q4kR-F1OC71pgi9e`qcXTZ52vztkgQ_Py5P$GL zHqPCcGb^{fBoxEk5I&HJc?+Ta6bI#Iln1kO+N9&zxmVZvNj@**4Q{9Dk&k~&r@mw) z>7?b*g_nD$=}1J2lT#?!_<3kBFKt)@86zYTr%2MIH5pv|7g(*<5F75a*lW9G!dPk8 z3d&$IIPdJ$s~r44HqKDJnGi?4ZybzW@+8}#94xn&$yCJ_oW*Do#k~m}QObaeQATTd zl9HxWrm5`^ZMk{0A9@f*D0I<~NI^v?kienvQk!E9M~gR*CciT@#eeOj0_a7>{t#2k zy)_Z~WYGL6634Hd#a21??^phsX7(#Z5|9lzOajkhyjw`p@pO3qmB0>*( z5TiUU)xMD+u5P*TzaK<3o8}~jx7wR|osO7LY8c&;2;8!b+3mzdW_M=c1zqB9#NM}V z-Z;01zfMhdhV@R3cRErBb_Z|Sx`i$r&eMkH3rvm=rqcKEqE2-_PMEpHD`nbO0Rkf6 zEK^nL6yIc#R|%N3O3TQ)@sdR z!a?pqA17rUAMUnFY;I@v}SI8Lj=TfSLi z+Q^GR;f^Z!dbn;&q|ZSvi&Q?1+7$jI{D+(E<$nG1w=kl2>?KzIY%;UnlvZ+mwNmLw z(7$Rl+uP_;f2}+q1`{%}C-6*{uP^nhyu8B74)cB&=8ch>^lRMu9kuSw59t{O&xrj& znChP$Jx$@+qiZ&0iXg#6O9OTP71V^z+ef@`hoc5+t z{HjH%x6zn@R`qt;X4o>qBeLxESb#0(3OkJ#`3QUnFoaS|7N@~%Xyn9_yD68$^u*XO zg+7c!!{E)|i{u>l$>#j^s>C?AIY(o~tiT49?E(urt~G#go8BOXa_)%tdx_b8A_ zfI=ba>|WI2mPui~EzM15+*XzciNsVyozjz8n*G)NwS{~jyz{xW4}|dgyp__hH$n|{ zwd4%POLMi1#xDWddES#{3^#|D?tQW>tfR^Oq+aeyo!T9<^3+THZ>g@21EUvc+=&^A zb`?Nh*c!#sm-Bu)TkEzo?p45OBcrRdz3nZfaEQ^(ixo1pHz%*Wy+!OIBa4SMebOz+ z3Ay~_s+O=6o2ogWri%Omj&enxP*F!fq;uUBo8vNi?m--k?e{l~s;u+3_?r)y|K34& z&$7eKK}k1e0y!WZ?Z;FJ@9G=$od-pghxd@OEXZmo3nrjl#*ijl_Uq3B z0;XiT_#z~~_n{^9dLiK7GGHajL`O8B(l-G$CY~MFbnSk0hVV4)=Szp#k_4SpT_8iD z9WS?a4YxHfk97@?wY9Ep^Iiof{Xi*+rLe3F7kwHIKJrs!2~I94@_p~CsXWWdAXtI& zT)9|`ALh!mjBE$JDq%+X@W&Fg_f)ik>i{MR>p(l2`@*lxn;s z(9s5rcF+L!!aA>kRBgVpeJl@6U7eu1ZW-!sY8iU(ZCr-aA#A>69Z#7TI-^VIW2Lwr zJugmQX)B!&M@$3rYN}YKXkQT=2{+)05DBmC3bN?`zuRK_hW(v}naz=5)}v(owfcBa z)I#It&bA)H@70kZUH{LqLbgc#{$OGoA&iPq;go%W1M1uPZMm-}-TAw>9rMM=b;g06@l6*%R0RC={IH&(+4pIlHabF z=Oo_gxOIT9TK`vVM4!O`U-NH#M;M|A8}}1sQI=J!EcFK3ibetFRL#bC#SEwwSy+dy zer@b9YnAbuL?UQ^x$!8b-6^#luj*?as6H VJ?yWMbkK9q+4 { return ctx.c.getLocal(param.name); }, + setter: (v) => { return ctx.c.setLocal(param.name, v); } + }; + } + + gen(ctx, ctx.functions[f].block); + } + + for (let i=0; i. +*/ + +const utils = require("./utils"); +const assert = require("assert"); +const gen = require("./c_gen"); + +module.exports = buildC; + + +function buildC(ctx) { + ctx.code = ""; + ctx.tmpNames = {}; + ctx.getTmpName = getTmpName; + ctx.codes_sizes = []; + ctx.definedSizes = {}; + ctx.addSizes = addSizes; + + const entryTables = buildEntryTables(ctx); + const code = buildCode(ctx); + const compnentsArray = buildComponentsArray(ctx); + + const headder = buildHeader(ctx); + const sizes = buildSizes(ctx); + const mapIsInput = buildMapIsInput(ctx); + const wit2Sig = buildWit2Sig(ctx); + const circuitVar = buildCircuitVar(ctx); + + return "" + + headder + "\n" + + sizes + "\n" + + entryTables + "\n" + + code + "\n" + + compnentsArray + "\n" + + mapIsInput + "\n" + + wit2Sig +"\n" + + circuitVar; +} + +function buildEntryTables(ctx) { + + const codes_hashMaps = []; + const codes_componentEntries = []; + const definedHashTables = {}; + for (let i=0; i0 ? " ," : " "; + const sizeName = ctx.addSizes(entry.sizes); + + const ty = entry.type == "S" ? "_typeSignal" : "_typeComponent"; + code += `{${entry.offset},${sizeName}, ${ty}}\n`; + } + code += "};\n"; + codes_componentEntries.push(code); + + ctx.components[i].htName = htName; + ctx.components[i].etName = componentEntriesTableName; + } + + + return "" + + "// HashMaps\n" + + codes_hashMaps.join("\n") + "\n" + + "\n" + + "// Component Entries\n" + + codes_componentEntries.join("\n") + "\n" + + "\n"; + + function addHashTable(cIdx) { + const keys = Object.keys(ctx.components[cIdx].names.o); + assert(keys.length<128); + keys.sort((a,b) => ((a>b) ? 1 : -1)); + const h = utils.fnvHash(keys.join(",")); + if (definedHashTables[h]) return definedHashTables[h]; + definedHashTables[h] = {}; + definedHashTables[h].htName = ctx.getTmpName("ht_"+ctx.components[cIdx].template); + definedHashTables[h].htMap = []; + const t = []; + for (let i=0; i0 ? "," : ""; + if (t[i]) { + code += `{0x${t[i][0]}LL, ${t[i][1]}} /* ${keys[t[i][1]]} */`; + } else { + code += "{0,0}"; + } + } + code += "};\n"; + + codes_hashMaps.push(code); + + return definedHashTables[h]; + } +} + +function buildCode(ctx) { + const globalNames = ctx.tmpNames; + + const fDefined = {}; + + const functions = []; + for (let f in ctx.functions) { + ctx.scope = {}; + const paramsList = []; + for (let p in ctx.functions[f].params) { + const param = ctx.functions[f].params[p]; + paramsList.push("POINTER "+param.name); + + ctx.scope[param.name] = { + type: "LOCAL", + sels: param.sels, + getter: () => { return param.name; }, + }; + } + + ctx.code += "void "+f+"(POINTER _ret, "+paramsList.join(",")+") {\n"; + + ctx.code += gen(ctx, ctx.functions[f].block); + ctx.code += "}"; + } + + for (let i=0; i0 ? " ," : " "); + ccodes.push(`{${ctx.components[i].htName},${ctx.components[i].etName},${ctx.components[i].fnName}, ${ctx.components[i].nInSignals}}\n`); + } + ccodes.push("};\n"); + const codeComponents = ccodes.join(""); + + return "" + + "// Components\n" + + codeComponents + + "\n"; +} + + +function buildHeader(ctx) { + return "#include \"circom.h\"\n" + + "#include \"calcwit.h\"\n" + + `#define NSignals ${ctx.signals.length}\n` + + `#define NComponents ${ctx.components.length}\n` + + `#define NInputs ${ctx.components[ ctx.getComponentIdx("main") ].nInSignals}\n`+ + `#define NOutputs ${ctx.totals[ ctx.stOUTPUT ]}\n`+ + `#define NVars ${ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL]}\n` + + "\n"; +} + +function buildSizes(ctx) { + return "// Sizes\n" + + ctx.codes_sizes.join("\n"); +} + + +function buildMapIsInput(ctx) { + const arr = []; + let line = ""; + let acc = 0; + let i; + for (i=0; i31) ? "," : " "; + line += toHex(acc); + acc = 0; + if ( i % (32*64) == 0) { + arr.push(line); + line = ""; + } + } + } + + if ((i%32) != 0) { + line += (i>31) ? "," : " "; + line += toHex(acc); + } + if (line != "") { + arr.push(line); + } + + return "// mapIsArray\n" + + `u32 _mapIsInput[${Math.floor((ctx.signals.length-1) / 32)+1}] = {\n`+ + arr.join("\n") + "\n" + + "};\n"; + + function toHex(number) { + if (number < 0) number = 0xFFFFFFFF + number + 1; + let S=number.toString(16).toUpperCase(); + while (S.length<8) S = "0" + S; + return "0x"+S; + } +} + + +function buildWit2Sig(ctx) { + const codes = []; + const NVars = + ctx.totals[ctx.stONE] + + ctx.totals[ctx.stOUTPUT] + + ctx.totals[ctx.stPUBINPUT] + + ctx.totals[ctx.stPRVINPUT] + + ctx.totals[ctx.stINTERNAL]; + const arr = Array(NVars); + for (let i=0; i=0) continue; // If has an alias, continue.. + assert(outIdx0) ? ",": " "; + code += arr[i]; + if ((i>0)&&(i%64 == 0)) { + if (code != "") codes.push(code + "\n"); + codes.push(code); + code =0; + } + } + if (code != "") codes.push(code + "\n"); + codes.push("};\n"); + + return codes.join(""); + +} + + +function buildCircuitVar() { + return "Circom_Circuit _circuit = {\n" + + " NSignals,\n"+ + " NComponents,\n"+ + " NInputs,\n"+ + " NOutputs,\n"+ + " NVars,\n"+ + " _wit2sig,\n"+ + " _components,\n"+ + " _mapIsInput\n"+ + "};\n"; +} + + + +function hashComponentCall(ctx, cIdx) { + // TODO: At the moment generate a diferent function for each instance of the component + return cIdx; +} + +function getTmpName(_suggestedName) { + let suggestedName; + if (_suggestedName) { + suggestedName = trimUnderscore(_suggestedName); + } else { + suggestedName = "tmp"; + } + + if (typeof(this.tmpNames[suggestedName]) == "undefined") { + this.tmpNames[suggestedName] = 1; + return "_"+suggestedName; + } else { + const name = "_" + suggestedName + "_" + this.tmpNames[suggestedName]; + this.tmpNames[suggestedName]++; + return name; + } + + function trimUnderscore(str) { + let p1=0; + while ((p1 < str.length)&&(str[p1] == "_")) p1++; + let p2=str.length; + while ((p2 > 0)&&(str[p2-1] == "_")) p2--; + + return str.slice(p1,p2); + } + +} + +function addSizes(_sizes) { + const sizes = _sizes || []; + let name = "sizes"; + for (let i=0; i0) code += ","; + code += accSizes[i]; + } + code += "};\n"; + this.codes_sizes.push(code); + + return labelName; +} + diff --git a/src/c_gen.js b/src/c_gen.js new file mode 100644 index 0000000..d7945b7 --- /dev/null +++ b/src/c_gen.js @@ -0,0 +1,941 @@ +const bigInt = require("big-integer"); +const utils = require("./utils"); + +module.exports = gen; + + +function newRef(ctx, type, _name, value, _sizes) { + const isValue = ((typeof(value) != "undefined")&&(value != null)); + let name; + let sizes; + if (!_name) { + name = ctx.getTmpName(); + } else { + if (_name[0] =="_") { + name = ctx.getTmpName(_name); + } else { + name = _name; + } + } + if (typeof(_sizes) == "string") { + sizes = _sizes; + } else if (Array.isArray(_sizes)) { + sizes = newSizes(ctx, _sizes); + } else if (isValue) { + sizes = newSizes(ctx, utils.extractSizes(value)); + } else { + sizes = newSizes(ctx, []); + } + + const scope = ctx.scopes[ctx.scopes.length-1]; + if (scope[name]) return error("Variable already exists: " + name); + + const label = scope._prefix + name; + scope[name] = { + stack: true, + type: type, + used: false, + sizes: sizes, + label: label + }; + + if (isValue) { + scope[name].value = value; + } + + return name; +} + +function newSizes(ctx, sizes) { + const scope = ctx.scopes[ctx.scopes.length-1]; + + const name = ctx.getTmpName("_sz"); + + scope[name] = { + stack: true, + type: "SIZES", + used: false, + dim: sizes.length, + label: name, + value: sizes + }; + + return name; +} + + +function instantiateRef(ctx, name) { + const v = getScope(ctx, name); + if (!v.stack) return error("Using a non existing var: " + name); + if (v.used) return; + + if (v.type=="BIGINT") { + + const iSize = getScope(ctx, v.sizes); + + if (iSize.used) { + const labelSize = iSize.label; + ctx.codeHeader += `PBigInt ${v.label};\n`; + ctx.code += `${v.label} = ctx->allocBigInts(${labelSize});\n`; + ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`; + } else if (iSize.value) { + const labelSize = ctx.addSizes(iSize.value); + ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${labelSize});\n`; + ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`; + } else { + return error(ctx, null, "Undefined Sizes: " +name); + } + + } else if (v.type=="INT") { + ctx.codeHeader += `int ${v.label};\n`; + } else if (v.type=="SIZES") { + ctx.codeHeader += `Circom_Sizes ${v.label};\n`; + } + v.used = true; +} + + +function error(ctx, ast, errStr) { + ctx.error = { + pos: { + first_line: ast.first_line, + first_column: ast.first_column, + last_line: ast.last_line, + last_column: ast.last_column + }, + errStr: errStr, + ast: ast, + message: errStr + }; +} + + +function getScope(ctx, name) { + for (let i=ctx.scopes.length-1; i>=0; i--) { + if (ctx.scopes[i][name]) return ctx.scopes[i][name]; + } + return null; +} + + + +function gen(ctx, ast) { + if ((ast.type == "NUMBER") ) { + return genNumber(ctx, ast); + } else if (ast.type == "VARIABLE") { + return genVariable(ctx, ast); + } else if (ast.type == "PIN") { + return genPin(ctx, ast); + } else if (ast.type == "OP") { + if (ast.op == "=") { + return genVarAssignement(ctx, ast); + } else if (ast.op == "<--") { + return genVarAssignement(ctx, ast); + } else if (ast.op == "<==") { + return genSignalAssignConstrain(ctx, ast); + } else if (ast.op == "===") { + return genConstraint(ctx, ast); + } else if (ast.op == "+=") { + return genVarAddAssignement(ctx, ast); + } else if (ast.op == "*=") { + return genVarMulAssignement(ctx, ast); + } else if (ast.op == "+") { + return genAdd(ctx, ast); + } else if (ast.op == "-") { + return genSub(ctx, ast); + } else if (ast.op == "UMINUS") { + return genUMinus(ctx, ast); + } else if (ast.op == "*") { + return genMul(ctx, ast); + } else if (ast.op == "%") { + return genMod(ctx, ast); + } else if (ast.op == "PLUSPLUSRIGHT") { + return genPlusPlusRight(ctx, ast); + } else if (ast.op == "PLUSPLUSLEFT") { + return genPlusPlusLeft(ctx, ast); + } else if (ast.op == "MINUSMINUSRIGHT") { + return genMinusMinusRight(ctx, ast); + } else if (ast.op == "MINUSMINUSLEFT") { + return genMinusMinusLeft(ctx, ast); + } else if (ast.op == "**") { + return genExp(ctx, ast); + } else if (ast.op == "/") { + return genDiv(ctx, ast); + } else if (ast.op == "\\") { + return genIDiv(ctx, ast); + } else if (ast.op == "&") { + return genBAnd(ctx, ast); + } else if (ast.op == "&&") { + return genAnd(ctx, ast); + } else if (ast.op == "||") { + return genOr(ctx, ast); + } else if (ast.op == "<<") { + return genShl(ctx, ast); + } else if (ast.op == ">>") { + return genShr(ctx, ast); + } else if (ast.op == "<") { + return genLt(ctx, ast); + } else if (ast.op == ">") { + return genGt(ctx, ast); + } else if (ast.op == "<=") { + return genLte(ctx, ast); + } else if (ast.op == ">=") { + return genGte(ctx, ast); + } else if (ast.op == "==") { + return genEq(ctx, ast); + } else if (ast.op == "!=") { + return genNeq(ctx, ast); + } else if (ast.op == "?") { + return genTerCon(ctx, ast); + } else { + error(ctx, ast, "Invalid operation: " + ast.op); + } + } else if (ast.type == "DECLARE") { + if (ast.declareType == "COMPONENT") { + return genDeclareComponent(ctx, ast); + } else if ((ast.declareType == "SIGNALIN")|| + (ast.declareType == "SIGNALOUT")|| + (ast.declareType == "SIGNAL")) { + return genDeclareSignal(ctx, ast); + } else if (ast.declareType == "VARIABLE") { + return genDeclareVariable(ctx, ast); + } else { + error(ctx, ast, "Invalid declaration: " + ast.declareType); + } + } else if (ast.type == "FUNCTIONCALL") { + return genFunctionCall(ctx, ast); + } else if (ast.type == "BLOCK") { + return genBlock(ctx, ast); + } else if (ast.type == "COMPUTE") { + return genCompute(ctx, ast); + } else if (ast.type == "FOR") { + return genFor(ctx, ast); + } else if (ast.type == "WHILE") { + return genWhile(ctx, ast); + } else if (ast.type == "IF") { + return genIf(ctx, ast); + } else if (ast.type == "RETURN") { + return genReturn(ctx, ast); + } else if (ast.type == "INCLUDE") { + return genInclude(ctx, ast); + } else if (ast.type == "ARRAY") { + return genArray(ctx, ast); + } else { + error(ctx, ast, "GEN -> Invalid AST node type: " + ast.type); + } +} + +function genBlock(ctx, ast) { + const oldCode = ctx.code; + let res = null; + ctx.code = ""; + for (let i=0; i1) { + ctx.code = oldCode + `{\n${utils.ident(ctx.code)}}\n`; + } else { + ctx.code = oldCode + ctx.code; + } + return res; +} + +function genSrcComment(ctx, ast) { + let codes = []; + const fl= ast.first_line-1; + const ll = ast.last_line-1; + const fc = ast.first_column-1; + const lc = ast.last_column; + for (let i=fl; i<=ll; i++) { + const p1 = i==fl ? fc : 0; + const p2 = i==ll ? lc : -1; + codes.push(ctx.includedFiles[ctx.fileName][i].slice(p1, p2>=0 ? p2 : undefined)); + } + ctx.code += "\n/* "+codes.join("\n")+"*/\n"; +} + + +function genDeclareComponent(ctx, ast) { + const scope = ctx.scopes[ctx.scopes.length - 1]; + + if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); + if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); + + scope[ast.name.name] = { + type: "COMPONENT", + label: ast.name.name + }; + + return ast.name.name; +} + +function genDeclareSignal(ctx, ast) { + const scope = ctx.scopes[ctx.scopes.length-1]; + + if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); + if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name); + + const res = { + type: "SIGNAL", + label: ast.name.name + }; + + scope[ast.name.name] = res; + + return res; +} + +function genDeclareVariable(ctx, ast) { + + const scope = ctx.scopes[ctx.scopes.length-1]; + + const varName = ast.name.name; + const labelName = scope._prefix + ast.name.name; + + if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); + if (ctx.scope[varName]) return error(ctx, ast, "Name already exists: "+varName); + + const sizes=[]; + let instantiate = false; + for (let i=0; i< ast.name.selectors.length; i++) { + const size = gen(ctx, ast.name.selectors[i]); + if (ctx.error) return; + + if (size.used) { + instantiate = true; + sizes.push(`BigInt2Int(${scope[size].label})`); + } else { + sizes.push(size.value.toJSNumber()); + } + + sizes.push( size.value.toJSNumber() ); + } + + const vSizes = newRef(ctx, "SIZES", "_sizes"); + const iSizes = scope[vSizes]; + iSizes.dim = ast.name.selectors.length; + if (instantiate) { + instantiateRef(ctx, vSizes); + ctx.code += `${iSizes.label}[${iSizes.dim+1}]=0`; + ctx.code += `${iSizes.label}[${iSizes.dim}]=1`; + for (let i=iSizes.dim-1; i>=0; i--) { + ctx.code += `${iSizes.label}[${i}] = ${sizes[i]}*${iSizes.label}[${i+1}];\n`; + } + } else { + iSizes.value = sizes; + } + + const res = ctx.scope[varName] = { + stack: true, + type: "BIGINT", + sizes: vSizes, + label: labelName + }; + + scope[varName] = res; + + return res; +} + +function genNumber(ctx, ast) { + return newRef(ctx, "BIGINT", "_num", ast.value); +} + + + +function genGetOffset(ctx, vOffset, vSizes, sels) { + + let rN = 0; + let rStr = ""; + let iOffset; + + if (vOffset) { + iOffset = getScope(ctx, vOffset); + if (iOffset.used) { + rStr += iOffset.label; + } else { + rN += iOffset.value.toJSNumber(); + } + } + + if ((sels)&&(sels.length>0)) { + + const iSizes = getScope(ctx, vSizes); + + for (let i=0; i0) { + if (rStr != "") rStr += " + "; + rStr += rN; + rN =0; + } + + if (rStr != "") rStr += " + "; + if (iIdx.used) { + rStr += vIdx; + } else { + rStr += iIdx.value; + } + rStr += "*"; + if (iSizes.used) { + rStr += `${iSizes.label}[${i+1}]`; + } else { + rStr += iSizes.sizes[i+1]; + } + } + } + } + + if (rStr == "") { + const o = newRef(ctx, "INT", "_offset", rN); + return o; + } else { + if (rN>0) { + if (rStr != "") rStr += " + "; + rStr += rN; + rN =0; + } + if (rStr == iOffset.label) { + return vOffset; + } else { + const res = newRef(ctx, "INT", "_offset"); + instantiateRef(ctx, res); + ctx.code += `${res} = ${rStr};\n`; + return res; + } + } +} + +function genVariable(ctx, ast) { + const v = getScope(ctx, ast.name); + + + if (v.type == "SIGNAL") { + let vOffset; + if (ast.selectors.length>0) { + const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name); + const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", ast.name); + vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors ); + } else { + vOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name); + } + return genGetSignal(ctx, "ctx->cIdx", vOffset); + + } else if (v.type == "BIGINT") { + const vOffset = genGetOffset(ctx, 0, v.sizes, ast.sels ); + if (v.used) { + if (vOffset == 0) { + return ast.name; + } else { + const res = newRef(ctx, "BIGINT", "_v"); + instantiateRef(ctx, res); + ctx.code += `${res} = ${ast.name} + ${vOffset};\n`; + return res; + } + } else { + if (typeof(vOffset) == "string") { + instantiateRef(ctx, ast.name); + const vConstant = instantiateConstant(ctx, v.value); + const res = newRef(ctx, "BIGINT", "_v"); + instantiateRef(ctx, res); + ctx.code += `${res} = ${vConstant} + ${vOffset};\n`; + return res; + } else { + const sa = utils.subArray(v.value, ast.selectors); + const res = newRef(ctx, "BIGINT", "_v", sa); + return res; + } + } + } + + const sels = []; + for (let i=0; iallocBigInts(${flatedValue.length});\n`; + for (let i=0; ifreeBigInts(${res.label});\n`; + return res; +} + +function genPin(ctx, ast) { + let vcIdx; + if (ast.component.selectors.length>0) { + const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.component.name); + const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.component.name); + vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors ); + } else { + vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.component.name); + } + + let vsIdx; + if (ast.pin.selectors.length>0) { + const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.pin.name); + const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.pin.name); + vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.pin.selectors ); + } else { + vsIdx = genGetSigalOffset(ctx, vcIdx, ast.pin.name); + } + + return genGetSignal(ctx, vcIdx, vsIdx); +} + +function genGetSubComponentOffset(ctx, cIdx, label) { + const vOffset = newRef(ctx, "INT", "_compIdx"); + instantiateRef(ctx, vOffset); + + const h = utils.fnvHash(label); + ctx.code += `${vOffset} = ctx->getSubComponentOffset(${cIdx}, 0x${h}LL /* ${label} */);\n`; + return vOffset; +} + +function genGetSubComponentSizes(ctx, cIdx, label) { + const vSizes = newRef(ctx, "SIZES", "_compSizes"); + instantiateRef(ctx, vSizes); + + const h = utils.fnvHash(label); + ctx.code += `${vSizes} = ctx->getSubComponentSizes(${cIdx}, 0x${h}LL /* ${label} */);\n`; + return vSizes; +} + +function genGetSigalOffset(ctx, sIdx, label) { + const vOffset = newRef(ctx, "INT", "_sigIdx"); + instantiateRef(ctx, vOffset); + + const h = utils.fnvHash(label); + ctx.code += `${vOffset} = ctx->getSignalOffset(${sIdx}, 0x${h}LL /* ${label} */);\n`; + return vOffset; +} + +function genGetSignalSizes(ctx, sIdx, label) { + const vSizes = newRef(ctx, "SIZES", "_sigSizes"); + instantiateRef(ctx, vSizes); + + const h = utils.fnvHash(label); + ctx.code += `${vSizes} = ctx->getSignalSizes(${sIdx}, 0x${h}LL /* ${label} */);\n`; + return vSizes; +} + +function genSetSignal(ctx, cIdx, sIdx, value) { + ctx.code += `ctx->setSignal(${cIdx}, ${sIdx}, ${value});\n`; + return value; +} + +function genGetSignal(ctx, cIdx, sIdx) { + const res = newRef(ctx, "BIGINT", "_sigValue"); + instantiateRef(ctx, res); + ctx.code += `ctx->getSignal(${cIdx}, ${sIdx}, ${res});\n`; + return res; +} + +function genVarAssignement(ctx, ast) { + + let lName; + let sels; + + if (ctx.error) return; + + if (ast.values[0].type == "PIN") { + + let vcIdx; + if (ast.values[0].component.selectors.length>0) { + const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); + const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.values[0].component.name); + vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors ); + } else { + vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name); + } + + let vsIdx; + if (ast.values[0].pin.selectors.length>0) { + const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name); + const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name); + vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors ); + } else { + vsIdx = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name); + } + + const vVal = gen(ctx, ast.values[1]); + + genSetSignal(ctx, vcIdx, vsIdx, vVal); + + return vVal; + } + + if (ast.values[0].type == "DECLARE") { + lName = gen(ctx, ast.values[0]); + if (ctx.error) return; + sels = []; + } else { + lName = ast.values[0].name; + sels = ast.values[0].selectors; + } + + + const left = getScope(ctx, lName); + if (!left) return error(ctx, ast, "Variable does not exists: "+ast.values[0].name); + + // Component instantiation is already done. + if (left.type == "COMPONENT") { + ctx.last = lName; + return; + } + + + const rName = gen(ctx, ast.values[1]); + const right = getScope(ctx, rName); + + if (left.type == "SIGNAL") { + + let vsIdx; + if (sels.length>0) { + const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", lName); + const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", lName); + vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels ); + } else { + vsIdx = genGetSigalOffset(ctx, "ctx->cIdx", lName); + } + + return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName); + } else if (left.type == "VAR") { + if (left.used) { + if (!right.used) { + instantiateRef(ctx, rName); + } + ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`; + return lName; + } else { + if (right.used) { + instantiateRef(ctx, lName); + ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`; + return lName; + } else { + if (!left.value) { + left.value = right.value; + } else { + if (!left.value.equals(right.value)) { + if (ctx.scopes.length > 1) { + instantiateRef(ctx, lName); + ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`; + } else { + left.value = right.value; + } + } + } + } + } + } else { + return error(ctx, ast, "Assigning to invalid"); + } +} + +function genConstraint(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column; + ctx.code += `ctx->checkConstraint(${a}, ${b}, "${strErr}");`; +} + + +function genArray(ctx, ast) { + let S = "["; + for (let i=0; i0) S += ","; + S += gen(ctx, ast.values[i]); + } + S+="]"; + return S; +} + + +function genFunctionCall(ctx, ast) { + let S = "["; + for (let i=0; i0) S += ","; + S += gen(ctx, ast.params[i]); + } + S+="]"; + + return `ctx.callFunction("${ast.name}", ${S})`; +} + +function genFor(ctx, ast) { + ctx.scopes.push({}); + const init = gen(ctx, ast.init); + if (ctx.error) return; + const condition = gen(ctx, ast.condition); + if (ctx.error) return; + const step = gen(ctx, ast.step); + if (ctx.error) return; + const body = gen(ctx, ast.body); + if (ctx.error) return; + ctx.scopes.pop(); + return `for (${init};bigInt(${condition}).neq(bigInt(0));${step}) { \n${body}\n }\n`; +} + +function genWhile(ctx, ast) { + const condition = gen(ctx, ast.condition); + if (ctx.error) return; + const body = gen(ctx, ast.body); + if (ctx.error) return; + return `while (bigInt(${condition}).neq(bigInt(0))) {\n${body}\n}\n`; +} + +function genCompute(ctx, ast) { + const body = gen(ctx, ast.body); + if (ctx.error) return; + return `{\n${body}\n}\n`; +} + +function genIf(ctx, ast) { + const condition = gen(ctx, ast.condition); + if (ctx.error) return; + const thenBody = gen(ctx, ast.then); + if (ctx.error) return; + if (ast.else) { + const elseBody = gen(ctx, ast.else); + if (ctx.error) return; + return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n} else {\n${elseBody}\n}\n`; + } else { + return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n}\n`; + } +} + + +function genReturn(ctx, ast) { + const value = gen(ctx, ast.value); + if (ctx.error) return; + return `return ${value};`; +} + + + +function genSignalAssignConstrain(ctx, ast) { + const res = genVarAssignement(ctx, ast); + genConstraint(ctx, ast); + return res; +// return genVarAssignement(ctx, ast); +} + +function genVarAddAssignement(ctx, ast) { + return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]}); +} + +function genVarMulAssignement(ctx, ast) { + return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]}); +} + +function genPlusPlusRight(ctx, ast) { + return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`; +} + +function genPlusPlusLeft(ctx, ast) { + return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); +} + +function genMinusMinusRight(ctx, ast) { + return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`; +} + +function genMinusMinusLeft(ctx, ast) { + return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); +} + +function genAdd(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).add(bigInt(${b})).mod(__P__)`; +} + +function genMul(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).mul(bigInt(${b})).mod(__P__)`; +} + +function genSub(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).add(__P__).sub(bigInt(${b})).mod(__P__)`; +} + +function genDiv(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + + return `bigInt(${a}).mul( bigInt(${b}).inverse(__P__) ).mod(__P__)`; +} + +function genIDiv(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + + return `bigInt(${a}).div( bigInt(${b}))`; +} + +function genExp(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).modPow(bigInt(${b}), __P__)`; +} + +function genBAnd(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`; +} + +function genAnd(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `((bigInt(${a}).neq(bigInt(0)) && bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`; +} + +function genOr(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `((bigInt(${a}).neq(bigInt(0)) || bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`; +} + +function genShl(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shl(bigInt(${b})).and(__MASK__)`; +} + +function genShr(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shr(bigInt(${b})).and(__MASK__)`; +} + +function genMod(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).mod(bigInt(${b}))`; +} + +function genLt(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).lt(bigInt(${b})) ? 1 : 0`; +} + +function genGt(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).gt(bigInt(${b})) ? 1 : 0`; +} + +function genLte(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).lesserOrEquals(bigInt(${b})) ? 1 : 0`; +} + +function genGte(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `bigInt(${a}).greaterOrEquals(bigInt(${b})) ? 1 : 0`; +} + +function genEq(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `(bigInt(${a}).eq(bigInt(${b})) ? 1 : 0)`; +} + +function genNeq(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `(bigInt(${a}).eq(bigInt(${b})) ? 0 : 1)`; +} + +function genUMinus(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + return `__P__.sub(bigInt(${a})).mod(__P__)`; +} + +function genTerCon(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + const c = gen(ctx, ast.values[2]); + if (ctx.error) return; + return `bigInt(${a}).neq(bigInt(0)) ? (${b}) : (${c})`; +} + +function genInclude(ctx, ast) { + return ast.block ? gen(ctx, ast.block) : ""; +} + + diff --git a/src/c_tester.js b/src/c_tester.js new file mode 100644 index 0000000..48ee424 --- /dev/null +++ b/src/c_tester.js @@ -0,0 +1,119 @@ +const chai = require("chai"); +const assert = chai.assert; + +const fs = require("fs"); +var tmp = require("tmp-promise"); +const path = require("path"); +const compiler = require("./compiler"); +const util = require("util"); +const exec = util.promisify(require("child_process").exec); + +const stringifyBigInts = require("snarkjs").stringifyBigInts; +const unstringifyBigInts = require("snarkjs").unstringifyBigInts; +const bigInt = require("snarkjs").bigInt; + +module.exports = c_tester; + + +async function c_tester(circomFile, mainComponent, _options) { + tmp.setGracefulCleanup(); + mainComponent = mainComponent || "main"; + + const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true }); + + const baseName = path.basename(circomFile, ".circom"); + const options = Object.assign({}, _options); + + options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp")); + options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); + options.mainComponent = mainComponent; + await compiler(circomFile, options); + + const cdir = path.join(__dirname, "..", "c"); + await exec("g++" + + ` ${path.join(dir.path, baseName + ".cpp")} ` + + ` ${path.join(cdir, "main.cpp")}` + + ` ${path.join(cdir, "calcwit.cpp")}` + + ` ${path.join(cdir, "utils.cpp")}` + + ` -o ${path.join(dir.path, baseName)}` + + ` -I ${cdir}` + + " -lgmp -std=c++11 -DSANITY_CHECK" + ); + + console.log(dir.path); + return new CTester(dir, baseName, mainComponent); +} + +class CTester { + + constructor(dir, baseName, mainComponent) { + this.dir=dir; + this.baseName = baseName; + this.mainComponent = mainComponent; + } + + async release() { + await this.dir.cleanup(); + } + + async calculateWitness(input) { + await fs.promises.writeFile( + path.join(this.dir.path, "in.json"), + JSON.stringify(stringifyBigInts(input), null, 1) + ); + await exec(`${path.join(this.dir.path, this.baseName)}` + + ` ${path.join(this.dir.path, "in.json")}` + + ` ${path.join(this.dir.path, "out.json")}` + ); + const resStr = await fs.promises.readFile( + path.join(this.dir.path, "out.json") + ); + + const res = unstringifyBigInts(JSON.parse(resStr)); + return res; + } + + async _loadSymbols() { + this.symbols = {}; + const symsStr = await fs.promises.readFile( + path.join(this.dir.path, this.baseName + ".sym"), + "utf8" + ); + const lines = symsStr.split("\n"); + for (let i=0; i=0) { + lSignal = ctx.signals[lSignal.e]; } else { end=true; } } - if (tAll == "error") { + if (tAll == ERROR) { throw new Error("Incompatible types in signal: " + s); } - lSignal.category = tAll; + lSignal.c = tAll; } } function generateWitnessNames(ctx) { - - const totals = { - "output": 0, - "pubInput": 0, - "one": 0, - "prvInput": 0, - "internal": 0, - "constant": 0, - }; + const totals = {}; + totals[ctx.stONE] = 0; + totals[ctx.stOUTPUT] = 0; + totals[ctx.stPUBINPUT] = 0; + totals[ctx.stPRVINPUT] = 0; + totals[ctx.stINTERNAL] = 0; + totals[ctx.stDISCARDED] = 0; + totals[ctx.stCONSTANT] = 0; const ids = {}; - const counted = {}; - // First classify the signals - for (let s in ctx.signals) { + for (let s=0; s=0) lSignal = ctx.signals[lSignal.e]; - if (!counted[lSignal.fullName]) { - counted[lSignal.fullName] = true; - totals[lSignal.category] ++; + if (!( lSignal.o & ctx.COUNTED) ) { + lSignal.o |= ctx.COUNTED; + totals[lSignal.c] ++; } } - ids["one"] = 0; - ids["output"] = 1; - ids["pubInput"] = ids["output"] + totals["output"]; - ids["prvInput"] = ids["pubInput"] + totals["pubInput"]; - ids["internal"] = ids["prvInput"] + totals["prvInput"]; - ids["constant"] = ids["internal"] + totals["internal"]; - const nSignals = ids["constant"] + totals["constant"]; + ids[ctx.stONE] = 0; + ids[ctx.stOUTPUT] = 1; + ids[ctx.stPUBINPUT] = ids[ctx.stOUTPUT] + totals[ctx.stOUTPUT]; + ids[ctx.stPRVINPUT] = ids[ctx.stPUBINPUT] + totals[ctx.stPUBINPUT]; + ids[ctx.stINTERNAL] = ids[ctx.stPRVINPUT] + totals[ctx.stPRVINPUT]; + ids[ctx.stDISCARDED] = ids[ctx.stINTERNAL] + totals[ctx.stINTERNAL]; + ids[ctx.stCONSTANT] = ids[ctx.stDISCARDED] + totals[ctx.stDISCARDED]; + const nSignals = ids[ctx.stCONSTANT] + totals[ctx.stCONSTANT]; - ctx.signalNames = new Array(nSignals); - for (let i=0; i< nSignals; i++) ctx.signalNames[i] = []; - ctx.signalName2Idx = {}; + for (let s=0; s=0) { + lSignal = ctx.signals[lSignal.e]; } if ( typeof(lSignal.id) === "undefined" ) { - lSignal.id = ids[lSignal.category] ++; + lSignal.id = ids[lSignal.c] ++; } signal.id = lSignal.id; - ctx.signalNames[signal.id].push(signal.fullName); - ctx.signalName2Idx[signal.fullName] = signal.id; } ctx.totals = totals; @@ -225,6 +233,7 @@ function reduceConstants(ctx) { if (!lc.isZero(c)) { newConstraints.push(c); } + delete ctx.constraints[i]; } ctx.constraints = newConstraints; } @@ -232,10 +241,12 @@ function reduceConstants(ctx) { function reduceConstrains(ctx) { indexVariables(); let possibleConstraints = Object.keys(ctx.constraints); + let ii=0; while (possibleConstraints.length>0) { let nextPossibleConstraints = {}; for (let i in possibleConstraints) { - if ((ctx.verbose)&&(i%10000 == 0)) console.log("reducing constraints: ", i); + ii++; + if ((ctx.verbose)&&(ii%10000 == 0)) console.log("reducing constraints: ", i); if (!ctx.constraints[i]) continue; const c = ctx.constraints[i]; @@ -248,13 +259,13 @@ function reduceConstrains(ctx) { // Mov to C if possible. if (isConstant(c.a)) { - const ct = {type: "NUMBER", value: c.a.values["one"]}; + const ct = {type: "NUMBER", value: c.a.values[sONE]}; c.c = lc.add(lc.mul(c.b, ct), c.c); c.a = { type: "LINEARCOMBINATION", values: {} }; c.b = { type: "LINEARCOMBINATION", values: {} }; } if (isConstant(c.b)) { - const ct = {type: "NUMBER", value: c.b.values["one"]}; + const ct = {type: "NUMBER", value: c.b.values[sONE]}; c.c = lc.add(lc.mul(c.a, ct), c.c); c.a = { type: "LINEARCOMBINATION", values: {} }; c.b = { type: "LINEARCOMBINATION", values: {} }; @@ -265,8 +276,8 @@ function reduceConstrains(ctx) { if (isolatedSignal) { let lSignal = ctx.signals[isolatedSignal]; - while (lSignal.equivalence) { - lSignal = ctx.signals[lSignal.equivalence]; + while (lSignal.e>=0) { + lSignal = ctx.signals[lSignal.e]; } @@ -296,7 +307,7 @@ function reduceConstrains(ctx) { ctx.constraints[i] = null; - lSignal.category = "constant"; + lSignal.c = ctx.stDISCARDED; } else { if (lc.isZero(c.c)) ctx.constraints[i] = null; } @@ -332,8 +343,8 @@ function reduceConstrains(ctx) { function unindexVariables() { for (let s in ctx.signals) { let lSignal = ctx.signals[s]; - while (lSignal.equivalence) { - lSignal = ctx.signals[lSignal.equivalence]; + while (lSignal.e>=0) { + lSignal = ctx.signals[lSignal.e]; } if (lSignal.inConstraints) delete lSignal.inConstraints; } @@ -342,8 +353,8 @@ function reduceConstrains(ctx) { /* function unlinkSignal(signalName, cidx) { let lSignal = ctx.signals[signalName]; - while (lSignal.equivalence) { - lSignal = ctx.signals[lSignal.equivalence]; + while (lSignal.e>=0) { + lSignal = ctx.signals[lSignal.e]; } if ((lSignal.inConstraints)&&(lSignal.inConstraints[cidx])) { delete lSignal.inConstraints[cidx]; @@ -353,8 +364,8 @@ function reduceConstrains(ctx) { function linkSignal(signalName, cidx) { let lSignal = ctx.signals[signalName]; - while (lSignal.equivalence) { - lSignal = ctx.signals[lSignal.equivalence]; + while (lSignal.e>=0) { + lSignal = ctx.signals[lSignal.e]; } if (!lSignal.inConstraints) lSignal.inConstraints = {}; lSignal.inConstraints[cidx] = true; @@ -363,21 +374,22 @@ function reduceConstrains(ctx) { function getFirstInternalSignal(ctx, l) { for (let k in l.values) { const signal = ctx.signals[k]; - if (signal.category == "internal") return k; + if (signal.c == ctx.stINTERNAL) return k; } return null; } function isConstant(l) { for (let k in l.values) { - if ((k != "one") && (!l.values[k].isZero())) return false; + if ((k != sONE) && (!l.values[k].isZero())) return false; } - if (!l.values["one"] || l.values["one"].isZero()) return false; + if (!l.values[sONE] || l.values[sONE].isZero()) return false; return true; } } +/* function buildCircuitDef(ctx, mainCode) { const res = { @@ -436,6 +448,9 @@ function buildCircuitDef(ctx, mainCode) { return res; } +*/ + + /* Build constraints @@ -485,5 +500,96 @@ function buildConstraints(ctx) { return res; } +function buildR1cs(ctx, strm) { + + strm.write(Buffer.from([0x72,0x31,0x63,0x73])); + writeU32(1); + writeU32(4); + writeU32(1 + ctx.totals.output + ctx.totals.pubInput + ctx.totals.prvInput + ctx.totals.internal); + writeU32(ctx.totals.output); + writeU32(ctx.totals.pubInput); + writeU32(ctx.totals.prvInput); + writeU32(ctx.constraints.length); + + for (let i=0; i=0 ) lSignal = ctx.signals[lSignal.e]; + + writeU32(lSignal.id); + writeBigInt(lc.values[s]); + } + } + + function writeBigInt(n) { + const bytes = []; + let r = bigInt(n); + while (r.greater(bigInt.zero)) { + bytes.push(r.and(bigInt("255")).toJSNumber()); + r = r.shiftRight(8); + } + assert(bytes.length<=32); + assert(bytes.length>0); + strm.write( Buffer.from([bytes.length, ...bytes ])); + } +} + +function buildSyms(ctx, strm) { + + + + addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent)); + + + function addSymbolsComponent(prefix, idComponet) { + for (let n in ctx.components[idComponet].names.o) { + const entrie = ctx.components[idComponet].names.o[n]; + addSymbolArray(prefix+n, entrie.type, entrie.sizes, entrie.offset); + } + } + + function addSymbolArray(prefix, type, sizes, offset) { + if (sizes.length==0) { + if (type == "S") { + let s=offset; + while (ctx.signals[s].e >= 0) s = ctx.signals[s].e; + let wId = ctx.signals[s].id; + if (typeof(wId) == "undefined") wId=-1; + strm.write(`${offset},${wId},${prefix}\n`); + } else { + addSymbolsComponent(prefix+".", offset); + } + return 1; + } else { + let acc = 0; + for (let i=0; i1) { + return [o, o+l]; + } else { + return o; + } + } + + addComponent(name, sizes) { + const l = this._allocElement(name, sizes, "C"); + const o = this.ctx.nComponents; + this.o[name].offset = o; + this.ctx.nComponents += l; + if (l>1) { + return [o, o+l]; + } else { + return o; + } + } + + _getElement(name, _sels, type) { + const sels = _sels || []; + const s = this.o[name]; + if (!s) return -1; + if (s.type != type) return -1; + if (sels.length > s.sizes.length) return -1; + let l=1; + for (let i = s.sizes.length-1; i>sels.length; i--) { + l = l*s.sizes[i]; + } + let o =0; + let p=1; + for (let i=sels.length-1; i>=0; i--) { + if (sels[i] > s.sizes[i]) return -1; // Out of range + if (sels[i] < 0) return -1; // Out of range + o += p*sels[i]; + p *= s.sizes[i]; + } + if (l>1) { + return [s.offset + o, s.offset + o + l]; + } else { + return s.offset + o; + } + } + + getSignalIdx(name, sels) { + return this._getElement(name, sels, "S"); + } + + getComponentIdx(name, sels) { + return this._getElement(name, sels, "C"); + } + + getSizes(name) { + return this.o[name].sels; + } + +} + +module.exports = class Ctx { + + constructor() { + + this.stONE = 1; + this.stOUTPUT = 2; + this.stPUBINPUT = 3; + this.stPRVINPUT = 4; + this.stINTERNAL = 5; + this.stDISCARDED = 6; + this.stCONSTANT = 7; + + this.IN = 0x01; + this.OUT = 0x02; + this.PRV = 0x04; + this.ONE = 0x08; + this.MAIN = 0x10; + this.COUNTED = 0x20; + + this.scopes = [{}]; + this.signals = []; + + this.currentComponent= -1; + this.constraints= []; + this.components= []; + this.templates= {}; + this.functions= {}; + this.functionParams= {}; + this.nSignals = 0; + this.nComponents =0; + this.names = new TableName(this); + this.main=false; + + const oneIdx = this.addSignal("one"); + this.signals[oneIdx] = { + v: bigInt(1), + o: this.ONE, + e: -1, + }; + } + + addSignal(name, sizes) { + if (this.currentComponent>=0) { + return this.components[this.currentComponent].names.addSignal(name, sizes); + } else { + return this.names.addSignal(name, sizes); + } + } + + addComponent(name, sizes) { + if (this.currentComponent>=0) { + return this.components[this.currentComponent].names.addComponent(name, sizes); + } else { + return this.names.addComponent(name, sizes); + } + } + + getSignalIdx(name, sels) { + if (this.currentComponent>=0) { + return this.components[this.currentComponent].names.getSignalIdx(name, sels); + } else { + return this.names.getSignalIdx(name, sels); + } + } + + getComponentIdx(name, sels) { + if (this.currentComponent>=0) { + return this.components[this.currentComponent].names.getComponentIdx(name, sels); + } else { + return this.names.getComponentIdx(name, sels); + } + } + + getSizes(name) { + if (this.currentComponent>=0) { + return this.components[this.currentComponent].names.getSizes(name); + } else { + return this.names.getSizes(name); + } + } + + newTableName() { + return new TableName(this); + } + +}; diff --git a/src/exec.js b/src/exec.js index 92e6a7c..70a9439 100644 --- a/src/exec.js +++ b/src/exec.js @@ -214,16 +214,38 @@ function getScope(ctx, name, selectors) { } - function select(v, s) { - s = s || []; - if (s.length == 0) return v; - return select(v[s[0]], s.slice(1)); + function select(v, sels) { + if (v.type == "SIGNAL") { + return reduce(v, sels, "sIdx"); + } else if (v.type == "COMPONENT") { + return reduce(v, sels, "cIdx"); + } else { + const s = sels || []; + if (s.length == 0) return v; + return select(v[s[0]], s.slice(1)); + } } for (let i=ctx.scopes.length-1; i>=0; i--) { if (ctx.scopes[i][name]) return select(ctx.scopes[i][name], sels); } return null; + + function reduce(v, _sels, idxName) { + let sels = _sels || []; + let sizes = v.sizes || []; + + let accSizes = [1]; + for (let i=sizes.length-1; i>0; i--) { + accSizes = [accSizes[0]*sizes[i], ...accSizes]; + } + const res = Object.assign({}, v); + res.sizes = sizes.slice(sels.length); + for (let i=0; i=0) { + sDest=ctx.signals[sDest.e]; + isOut = isOut || ((sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT)); } if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice"); @@ -1029,18 +1098,17 @@ function execSignalAssign(ctx, ast) { let assignValue = true; if (src.type == "SIGNAL") { - let sSrc = ctx.signals[src.fullName]; - let isIn = (sSrc.component == "main")&&(sSrc.direction == "IN"); - while (sSrc.equivalence) { - sSrc=ctx.signals[sSrc.equivalence]; - isIn = isIn || ((sSrc.component == "main")&&(sSrc.direction == "IN")); + let sSrc = ctx.signals[src.sIdx]; + let isIn = (sSrc.o & ctx.main)&&(sSrc.o & ctx.IN); + while (sSrc.e>=0) { + sSrc=ctx.signals[sSrc.e]; + isIn = isIn || ((sSrc.o & ctx.main)&&(sSrc.o & ctx.IN)); } // Skip if an out is assigned directly to an input. if ((!isIn)||(!isOut)) { - sDest.equivalence = src.fullName; - sDest.alias = sDest.alias.concat(src.alias); - while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence]; + sDest.e = src.sIdx; + while (sDest.e >= 0) sDest=ctx.signals[sDest.e]; assignValue = false; } } @@ -1095,10 +1163,11 @@ function execInclude(ctx, ast) { ctx.includedFiles = ctx.includedFiles || []; if (ctx.includedFiles[incFileName]) return; - ctx.includedFiles[incFileName] = true; const src = fs.readFileSync(incFileName, "utf8"); + ctx.includedFiles[incFileName] = src.split("\n"); + if (!src) return error(ctx, ast, "Include file not found: "+incFileName); const incAst = parser.parse(src); diff --git a/src/gencode.js b/src/gencode.js index fa3d683..0688345 100644 --- a/src/gencode.js +++ b/src/gencode.js @@ -188,26 +188,28 @@ function genBlock(ctx, ast) { } function genTemplateDef(ctx, ast) { - let S = "function(ctx) "; - const newScope = {}; - for (let i=0; i< ast.params.length; i++) { - newScope[ast.params[i]] = { type: "VARIABLE" }; - } + if (ctx.f) return error(ctx, ast, "Already in function"); - ctx.scopes.push(newScope); - S += genBlock(ctx, ast.block); - ctx.scopes.pop(); + ctx.f = ctx.module.addFunction(ast.name); + ctx.c = ctx.f.getCodeBuilder(); -// const scope = ctx.scopes[ctx.scopes.length-1]; - const scope = ctx.scopes[0]; // Scope for templates is top + ctx.scope = {}; + for (let i=0; i< ast.params.length; i++) { + ctx.f.addParam(ast.params[i].name, "i32"); + ctx.scope[ast.params[i].name] = { + type: "PARAM", + sels: ast.params[i].sels, + getter: () => { return ctx.c.getLocal(ast.params[i].name); }, + setter: (v) => { return ctx.c.setLocal(ast.params[i].name, v); } + }; + } - scope[ast.name] = { - type: "TEMPLATE" - }; + genBlock(ctx, ast.block); - ctx.templates[ast.name] = S; - return ""; + ctx.scope = null; + ctx.c = null; + ctx.f = null; } function genFunctionDef(ctx, ast) { diff --git a/src/lcalgebra.js b/src/lcalgebra.js index 0aa52b4..d039577 100644 --- a/src/lcalgebra.js +++ b/src/lcalgebra.js @@ -60,6 +60,7 @@ QEQ QEQ ERR ERR const bigInt = require("big-integer"); const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +const sONE = 0; exports.add = add; exports.mul = mul; @@ -79,7 +80,7 @@ function signal2lc(a) { type: "LINEARCOMBINATION", values: {} }; - lc.values[a.fullName] = bigInt(1); + lc.values[a.sIdx] = bigInt(1); return lc; } else { return a; @@ -163,10 +164,10 @@ function addLCNum(a,b) { return { type: "ERROR", errStr: "LinearCombination + undefined" }; } if (b.value.isZero()) return res; - if (!res.values["one"]) { - res.values["one"]=bigInt(b.value); + if (!res.values[sONE]) { + res.values[sONE]=bigInt(b.value); } else { - res.values["one"]= res.values["one"].add(b.value).mod(__P__); + res.values[sONE]= res.values[sONE].add(b.value).mod(__P__); } return res; } @@ -278,16 +279,16 @@ function mulQEQNum(a,b) { return res; } -function getSignalValue(ctx, signalName) { - const s = ctx.signals[signalName]; - if (s.equivalence != "") { - return getSignalValue(ctx, s.equivalence); +function getSignalValue(ctx, sIdx) { + const s = ctx.signals[sIdx]; + if (s.e >= 0) { + return getSignalValue(ctx, s.e); } else { const res = { type: "NUMBER" }; - if (s.value) { - res.value = s.value; + if (s.v) { + res.value = s.v; } return res; } @@ -297,7 +298,7 @@ function evaluate(ctx, n) { if (n.type == "NUMBER") { return n; } else if (n.type == "SIGNAL") { - return getSignalValue(ctx, n.fullName); + return getSignalValue(ctx, n.sIdx); } else if (n.type == "LINEARCOMBINATION") { const v= { type: "NUMBER", @@ -362,7 +363,7 @@ function toQEQ(a) { type: "QEQ", a: {type: "LINEARCOMBINATION", values: {}}, b: {type: "LINEARCOMBINATION", values: {}}, - c: {type: "LINEARCOMBINATION", values: {"one": bigInt(a.value)}} + c: {type: "LINEARCOMBINATION", values: {sONE: bigInt(a.value)}} }; } else if (a.type == "LINEARCOMBINATION") { return { @@ -415,11 +416,11 @@ function toString(a, ctx) { if (!c.equals(1)) { S = S + c.toString() + "*"; } - let sigName = k; + let sIdx = k; if (ctx) { - while (ctx.signals[sigName].equivalence) sigName = ctx.signals[sigName].equivalence; + while (ctx.signals[sIdx].e>=0) sIdx = ctx.signals[sIdx].e; } - S = S + sigName; + S = S + "[" + sIdx + "]"; } } if (S=="") return "0"; else return S; @@ -437,13 +438,13 @@ function canonize(ctx, a) { const res = clone(a); for (let k in a.values) { let s = k; - while (ctx.signals[s].equivalence) s= ctx.signals[s].equivalence; - if ((typeof(ctx.signals[s].value) != "undefined")&&(k != "one")) { + while (ctx.signals[s].e>=0) s= ctx.signals[s].e; + if ((typeof(ctx.signals[s].value) != "undefined")&&(k != sONE)) { const v = res.values[k].times(ctx.signals[s].value).mod(__P__); - if (!res.values["one"]) { - res.values["one"]=v; + if (!res.values[sONE]) { + res.values[sONE]=v; } else { - res.values["one"]= res.values["one"].add(v).mod(__P__); + res.values[sONE]= res.values[sONE].add(v).mod(__P__); } delete res.values[k]; } else if (s != k) { diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..8ac8473 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,55 @@ +const fnv = require("fnv-plus"); + +module.exports.ident =ident; + +module.exports.extractSizes =extractSizes; +module.exports.csArr = csArr; +module.exports.subArray = subArray; +module.exports.accSizes = accSizes; +module.exports.fnvHash = fnvHash; + +function ident(text) { + let lines = text.split("\n"); + for (let i=0; i=0; i--) { + accSizes.unshift(accSizes[0]*sizes[i]); + } + return accSizes; +} + +function fnvHash(str) { + return fnv.hash(str, 64).hex(); +} + + + diff --git a/test/circuits/in.bin b/test/circuits/in.bin new file mode 100644 index 0000000..594e923 --- /dev/null +++ b/test/circuits/in.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/circuits/in.json b/test/circuits/in.json new file mode 100644 index 0000000..7bd9486 --- /dev/null +++ b/test/circuits/in.json @@ -0,0 +1 @@ +{ "in1": 1, "in2": [2,3], "in3":[[4,5],[6,7],[8,9]] } diff --git a/test/circuits/inout.circom b/test/circuits/inout.circom index cf42e36..1ac591f 100644 --- a/test/circuits/inout.circom +++ b/test/circuits/inout.circom @@ -1,18 +1,54 @@ template Internal() { - signal input in; - signal output out; + signal input in1; + signal input in2[2]; + signal input in3[3][2]; - out <== in; + signal output out1; + signal output out2[2]; + signal output out3[3][2]; + + out1 <== in1; + out2[0] <== in2[0]; + out2[1] <== in2[1]; + + out3[0][0] <== in3[0][0]; + out3[0][1] <== in3[0][1]; + out3[1][0] <== in3[1][0]; + out3[1][1] <== in3[1][1]; + out3[2][0] <== in3[2][0]; + out3[2][1] <== in3[2][1]; } template InOut() { - signal input in; - signal output out; + signal input in1; + signal input in2[2]; + signal input in3[3][2]; + + signal output out1; + signal output out2[2]; + signal output out3[3][2]; component internal = Internal(); - internal.in <== in; - internal.out ==> out; + internal.in1 <== in1; + internal.in2[0] <== in2[0]; + internal.in2[1] <== in2[1]; + internal.in3[0][0] <== in3[0][0]; + internal.in3[0][1] <== in3[0][1]; + internal.in3[1][0] <== in3[1][0]; + internal.in3[1][1] <== in3[1][1]; + internal.in3[2][0] <== in3[2][0]; + internal.in3[2][1] <== in3[2][1]; + + internal.out1 ==> out1; + internal.out2[0] ==> out2[0]; + internal.out2[1] ==> out2[1]; + internal.out3[0][0] ==> out3[0][0]; + internal.out3[0][1] ==> out3[0][1]; + internal.out3[1][0] ==> out3[1][0]; + internal.out3[1][1] ==> out3[1][1]; + internal.out3[2][0] ==> out3[2][0]; + internal.out3[2][1] ==> out3[2][1]; } component main = InOut(); diff --git a/test/inout.js b/test/inout.js new file mode 100644 index 0000000..ddb563c --- /dev/null +++ b/test/inout.js @@ -0,0 +1,20 @@ +const chai = require("chai"); +const path = require("path"); + +const c_tester = require("../index.js").c_tester; +const stringifyBigInts = require("snarkjs").stringifyBigInts; + + +describe("inout test", function () { + this.timeout(100000); + it("Should compile a code with vars inside a for", async () => { + const cir = await c_tester(path.join(__dirname, "circuits", "inout.circom")); + + const out = await cir.calculateWitness({in1: 1, in2: [2,3], in3:[[4,5], [6,7], [8,9]]}); + + // console.log(JSON.stringify(stringifyBigInts(out),null,1)); + await cir.assertOut(out, {out1: 1, out2: [2,3], out3: [[4,5], [6,7],[8,9]]} ); + + await cir.release(); + }); +});