From 140a0bbecc144e554c1954f594a9f0d0b2276e9c Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 21 Mar 2018 12:29:09 -0400 Subject: [PATCH] interpreter overhaul, should be better --- Makefile | 36 +-- README.md | 33 ++- builtins.c | 225 ++++++---------- builtins.h | 11 +- memory.h | 8 - old.tar.gz | Bin 0 -> 46683 bytes ops.c | 236 ++++++++++------ ops.h | 11 +- parser.c | 780 +++++++++++++++++++++++++++-------------------------- parser.h | 38 +-- script | 7 - shell.c | 40 +-- shelpers.c | 64 ----- shelpers.h | 62 ----- stack.c | 38 --- stack.h | 16 -- stdlib.h | 9 - test1 | 13 + test2 | 16 ++ test3 | 25 ++ test4 | 6 + variable.c | 135 ---------- variable.h | 23 +- 23 files changed, 785 insertions(+), 1047 deletions(-) delete mode 100644 memory.h create mode 100644 old.tar.gz delete mode 100644 script delete mode 100644 shelpers.c delete mode 100644 shelpers.h delete mode 100644 stack.c delete mode 100644 stack.h delete mode 100644 stdlib.h create mode 100644 test1 create mode 100644 test2 create mode 100644 test3 create mode 100644 test4 delete mode 100644 variable.c diff --git a/Makefile b/Makefile index b4a7bfc..57f022c 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,13 @@ -#CC = gcc -m32 -#AR = ar -CC = arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -AR = arm-none-eabi-ar - -CFLAGS = -Wall -Wextra -Werror -pedantic \ - -Wno-discarded-qualifiers \ - -I. -fsigned-char -fno-builtin -ggdb - -FILES = $(wildcard *.c) -OUTFILES = $(patsubst %.c, %.o, $(FILES)) - -all: $(OUTFILES) - @#$(CC) $(CFLAGS) *.o -o shell - @$(AR) r libinterp.a *.o - -clean: - @echo " CLEAN" - @rm -f *.o shell libinterp.a - -%.o: %.c - @echo " CC " $< - @$(CC) $(CFLAGS) -c $< -o $@ +CFLAGS = -ggdb +CFILES = $(wildcard *.c) + +all: + @echo $(CFILES) + @gcc -m32 $(CFLAGS) $(CFILES) -o shell + +arm: + @mv shell.c shell.c.bak + @arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(CFLAGS) -c *.c + @arm-none-eabi-ar r libinterp.a *.o + @mv shell.c.bak shell.c + @rm *.o diff --git a/README.md b/README.md index 6084d7c..7ef1f34 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,23 @@ # interpreter -This project aims to provide a very minimal scripting language for embedded systems. Many other languages already exist, such as Lua, Tcl, or BASIC; however, most implementations require certain system calls like a read() and write(), as they expect a filesystem. This interpreter aims to be as independent and portable as possible: parsing script from strings one at a time, having minimal built-in functions (so the user can define their own prints and such), and only requiring a few standard library functions. +This project aims to provide a very minimal scripting language for embedded systems. Many other languages already exist, such as Lua, Tcl, or BASIC; however, most implementations require certain system calls like read() and write(), as they expect a filesystem. This interpreter wants to be as system-independent and portable as possible: parsing script from strings one at a time, having minimal built-in functions (so the user can define their own IO calls and such), and only requiring a few standard library functions. -To use this program with your own device, you need some malloc/free implementation, and string functions like those in string.h, atoi, and snprintf. Some of these functions may become coded in so that a standard library isn't required. +To use this program with your own device, you'll need some malloc/free implementation, and a freestanding standard library. Newlib works well for this; however, functions like atoi() and snprintf() will probably need to be rewritten (if you don't have an \_sbrk defined). -Only a few commands are built in to the interpreter: -* set - set variables -* func/end - define functions -* if/end - if conditional -* do/while -* ret - return value from function +Interpreter features: +* Variable/function definition - in C and in script +* if/else and while loops +* a solve function to parse strings at runtime -Other features: -* function/variable defining in c -* expression solving +Inconvenient features: * no local variables -* whitespace hopefully ignored +* whitespace sometimes ignored -Soon: -* error messages +Some TODO items: +* fix all memory leaks +* add better error messages * arrays? -* maybe for loops - -This project is still in heavy development, so don't expect much. To include it in your own project, just link in parser.o and use the header files. +* for loops + + +This project can be made for the host system (```make```) or an ARM system (```make arm```). +This project is still in heavy development, so don't expect much. To include it in your own project, just link in libinterp.a (for ARM) and use the header files. diff --git a/builtins.c b/builtins.c index 0ab6f3b..ea1cc95 100644 --- a/builtins.c +++ b/builtins.c @@ -1,179 +1,124 @@ #include "builtins.h" -#include "stack.h" -#include "shelpers.h" - -#include -#include - -int ifunc_set(interpreter *it); -int ifunc_label(interpreter *it); -int ifunc_end(interpreter *it); -int ifunc_if(interpreter *it); -int ifunc_do(interpreter *it); -int ifunc_while(interpreter *it); -int ifunc_ret(interpreter *it); -int ifunc_else(interpreter *it); -int ifunc_solve(interpreter *it); - -const func_t indent_up[IUP_COUNT] = { - ifunc_if, ifunc_do, ifunc_label -}; - -const func_t indent_down[IDOWN_COUNT] = { - ifunc_else, ifunc_end, ifunc_while, -}; - -void iload_core(interpreter *interp) + +#include + +#define IF_SIG (uint32_t)-1 +#define WHILE_SIG (uint32_t)-2 +#define ELSE_SIG (uint32_t)-3 +#define FUNC_SIG (uint32_t)-4 + +int bn_set(instance *it); +int bn_if(instance *it); +int bn_else(instance *it); +int bn_end(instance *it); +int bn_while(instance *it); +int bn_func(instance *it); +int bn_solve(instance *it); + +void iload_builtins(instance *it) { - inew_cfunc(interp, "set", ifunc_set); - inew_cfunc(interp, "func", ifunc_label); - inew_cfunc(interp, "end", ifunc_end); - inew_cfunc(interp, "if", ifunc_if); - inew_cfunc(interp, "do", ifunc_do); - inew_cfunc(interp, "while", ifunc_while); - inew_cfunc(interp, "ret", ifunc_ret); - inew_cfunc(interp, "else", ifunc_else); - inew_cfunc(interp, "solve", ifunc_solve); + inew_cfunc(it, "set", bn_set); + inew_cfunc(it, "if", bn_if); + inew_cfunc(it, "else", bn_else); + inew_cfunc(it, "while", bn_while); + inew_cfunc(it, "func", bn_func); + inew_cfunc(it, "solve", bn_solve); } -int ifunc_solve(interpreter *it) +int bn_set(instance *it) { - const char *expr = igetarg_string(it, 0); - int len = strlen(expr); - char *buf = (char *)malloc(len + 2); - strcpy(buf, expr); - buf[len] = ')'; - buf[len + 1] = '\0'; - variable *r = idoexpr(it, buf); - free(buf); - if (r == 0) - r = make_varn(0, 0.0f); - iret(it, r); - free(r); + variable *var = igetarg(it, 0); + variable *value = igetarg(it, 1); + var->type = value->type; + var->value.p = value->value.p; + ipush(it, (uint32_t)var); return 0; } -int ifunc_set(interpreter *it) +int bn_if(instance *it) { - variable *n = igetarg(it, 0); - variable *v = igetarg(it, 1); + variable *cond = (variable *)ipop(it); + uint32_t result = cond->value.p; - if (n == 0) - return -1; + ipush(it, result); + ipush(it, IF_SIG); + if (result == 0) + it->sindent = SKIP | it->indent; + ipush(it, 0); + ipush(it, 0); // need to return because stack modify - if (n->valtype == STRING) - free((void *)n->value.p); - n->valtype = v->valtype; - n->value.p = v->value.p; return 0; } -int ifunc_label(interpreter *it) +static uint32_t if_cond = 0; +int bn_else(instance *it) { - variable *n = igetarg(it, 0); - - if (n == 0) - return -1; - - n->valtype = FUNC; - n->value.p = it->lnidx; - iskip(it); + uint32_t cond = if_cond; + if (cond != 0) + it->sindent = SKIP | it->indent; + ipush(it, ELSE_SIG); + ipush(it, 0); // for ret return 0; } -int ifunc_if(interpreter *it) +int bn_end(instance *it) { - int v = igetarg(it, 0)->value.p; - if (v == 0) - iskip(it); - void *arg = ipop(it); - ipush(it, (void *)v); - ipush(it, (void *)-1); - ipush(it, arg); - return 0; + uint32_t sig = ipop(it); + if (sig == IF_SIG) { + if_cond = ipop(it); + } else if (sig == WHILE_SIG) { + uint32_t lnidx = ipop(it); + if (lnidx != (int32_t)-1) + it->lnidx = lnidx - 1; + } else if (sig == CALL_SIG) { + it->lnidx = ipop(it); + it->indent++; + } + return 0; } -int ifunc_end(interpreter *it) +int bn_while(instance *it) { - if (it->stidx == 0) - return 0; + variable *cond = (variable *)ipop(it); + uint32_t result = cond->value.p; - uint32_t lnidx = (uint32_t)ipop(it) + 1; - if (lnidx == 0) { // from an if, have conditional - ipop(it); // whatever + if (result == 0) { + it->sindent = SKIP | it->indent; + ipush(it, (uint32_t)-1); } else { - if (lnidx == (uint32_t)-1) { - // script-func call - lnidx = (uint32_t)ipop(it); - it->indent = (uint32_t)ipop(it); - } - it->lnidx = lnidx; + ipush(it, it->lnidx); } - return 0; -} - -int ifunc_else(interpreter *it) -{ - if (it->stidx == 0) - return 0; - - ipop(it); // the -1 - int cond = (int)ipop(it); - it->indent++; - if (cond != 0) - iskip(it); - // otherwise it's whatever? + ipush(it, WHILE_SIG); ipush(it, 0); - ipush(it, (void *)-1); - + ipush(it, 0); // need to ret return 0; } -int ifunc_do(interpreter *it) +int bn_func(instance *it) { - ipush(it, (void *)it->lnidx); - return 0; -} + variable *f = igetarg(it, 0); + if (f == 0) + return -1; -int ifunc_while(interpreter *it) -{ - int c = igetarg(it, 0)->value.p; - ipop(it); - int nidx = (int)ipop(it); - if (c != 0) { - //ipush(it, (void *)nidx); - it->lnidx = nidx - 1; - } - ipush(it, 0); + f->type = FUNC; + f->value.p = it->lnidx; + it->sindent = SKIP | it->indent; + ipush(it, FUNC_SIG); + ipush(it, 0); // for ret return 0; } -void iret(interpreter *it, variable *v) +int bn_solve(instance *it) { - switch (v->valtype) { - case NUMBER: - inew_number(it, "RET", v->value.f); - break; - case STRING: - inew_string(it, "RET", (char *)v->value.p); - break; - default: - return; - break; - } - if (it->ret != 0) { - if (it->ret->valtype == STRING && it->ret->value.p != 0) - free((void *)it->ret->value.p); - it->ret->valtype = v->valtype; - it->ret->value.p = v->value.p; - it->ret = 0; - } -} + variable *s = igetarg(it, 0); + variable **ops = iparse(it, (const char *)s->value.p); + if (ops == 0) + return -1; -int ifunc_ret(interpreter *it) -{ - variable *v = igetarg(it, 0); - iret(it, v); + variable *a = isolve(it, ops, 0); + free(ops); + + ipush(it, (uint32_t)a); return 0; } diff --git a/builtins.h b/builtins.h index 5c8e350..7570eab 100644 --- a/builtins.h +++ b/builtins.h @@ -3,14 +3,11 @@ #include "parser.h" -#define IUP_COUNT 3 -#define IDOWN_COUNT 3 +#define SKIP_SIG (uint32_t)-5 +#define CALL_SIG (uint32_t)-6 -void iload_core(interpreter *it); +void iload_builtins(instance *it); -void iret(interpreter *it, variable *v); - -const func_t indent_up[IUP_COUNT]; -const func_t indent_down[IDOWN_COUNT]; +int bn_end(instance *it); #endif // BUILTINS_H_ diff --git a/memory.h b/memory.h deleted file mode 100644 index 546aa2d..0000000 --- a/memory.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef MEMORY_H_ -#define MEMORY_H_ - -void *malloc(unsigned int); -void *calloc(unsigned int, unsigned int); -void free(void *); - -#endif // MEMORY_H_ diff --git a/old.tar.gz b/old.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..0a2e13f46fb45bbc7d99b6cde2ac47320668fe97 GIT binary patch literal 46683 zcmV)8K*qlxiwFpghO$}!18;0(E_7jX0PI=~a9q`OzHj%fv|6oX*^+F@KkzL7Nw!v6 z{aAKwWQ=X$I2c=FTeXRCmeuZC?b@qdu|M(;aR?C(Ho^>s0TPA`DfyX%pO$IBFhC{- z6EKvfG;PK(3Do(aabve}gG)*4!9C~R^WMAfX|=Y~0n!dnqdoVW^WAgLJ@@~<*Pl-$ zbBR>8CBiWeWG+wxJ((?TAe&AO7e~a>nG5MdL*Y!Wy#UG=NvEB88IGu=UiDWt)4Mox!XN)-0nFgs@#)D;~m}JI}3AT(? zRba*g@}6r&899LN^5l!3mH7|>z<9SDh;qA`(c)`Ft!oR-v6 zfB+378WE2Qk-I-1168A7ng+wkWIED__yt-!q99XbXm=yPnl&RQFk1nFJ#t>tJWBw1 z+PLugAWDbBnMAlhscZAOf6+AN=Z*m$?Zh&=-bm?0Olt&KH#qGpE5i(f;T?JiY@`~4 zP?eUTfbkgvOk_+0JO$!>CZz?P5iBsjVEioCQda1!m|5y!hq?`C1@3Iha#oZbXfsuT zWy9fQZugLmn2nn@tXa1jf!y6jJ}~Du2~b{d8Nw3fEZVTim>R^H8f3<=bKzP4B5GZ< zUN#4>?pwFg=~^NeSe8sBqPwt_vO5w(jeH6n&&vWUiC7OOy7~~VKqjgco%fGRlBXO9rnta z^7e7$ZI0kTG$SIKxVqTlIc|vdYB;e8yxc8Pa=#@N^^TNW^#X<)&F-TGAW*!Nf^F13 zrj5q7+E`3S@rL|koA6Ji5ioYJ#$>meQQWpQxJ{0KV;-v0(H_b*IePD(TyqrKlJe$& zAfZ>;9D3!Lqk??u6*bg&t+CE#l_}KCT1wxQ!$oapA{U86EfC3L9tlG%1MN$+)>aK- z1C|k5$OsP@&XcHLMsAc@@seXr#g+AE^ze?QMk#H)lthe2o{XXd(i$x6(L^qhPKA?F zzNj7x=aac5zVQm;6_HEYJAQl%ZK*FZz_PcwI97#*33yGhlH-Kd#BO%M0;8KFa%O?a z8!V>5WM*dqLX^nO%W6C0;ha9KXReexPq4_;J#Li?98-9O$CxpLTcm#$KGcjiVK~+< zDK-E$n$a0HJ{`<7r-Rnkv7Q=E+WLbrUY(;gIHo${a8Tg%)vQT-A6_eSteBI#HDK2D zUAv-Z1Mil&!%gJ}`*pFyYuM1U2{yOpeuZz|?BhV}i_FZ@zLhc?o6=$1PN~qK5Os6( zf1^KxQVOOdEwD?|=FZh*EuTG&?rPt^IbmjN*e%;Pb7fM? z?8fe$l)Dgt{zqa6~_kSPDGb<5; zr7ote=v%XP)0%Y~L!SxxW`O`EH=9hl|AP%!R?mprKSG)}OWHz9W?cel9T&RT;n!9d zIlW)Z1=rGxyPN`3vtZ{2vnwp*a&5eYEEcsE?d>cf`5mtEsynjpp zpf*M^m3Aw34x%#3V`cAP-tFh@JnsYJdNSMLi89ucLjBLX-DMME5CQ@Axx^VU3b0Drxs%WFnXDg^@bp))WioPu9F1t%||5etRRUtr)C z58K5ArHl8pDpA)LPPmjeM%gGkcn>;wsWCX|6r8@4?jy&57wg}51V#s?1)o-7|x_p?z$9Lwih2rXmrBi<#i)R zlmjn9dVg;nwnJ{r__L1$XS+B(604pEm%`CL@92ga$glzM2af(P=7r)jf^Zv#0<=D_ z3dG83sIZ$x;QZ!jn{fEZz9YGokq?xd=U<)|%C~T;RcQ%0IMVD`!%ocr44;nG-m%)d zc(Y6gqc@6_Ig2+49&&=R)@1CnI&}HzvVVoA0-m+cKe|B`BjJ_h(+dWfH;WM(t3?Ve zW>&xo?UL+IR?jg!STHy`utbbS(~MuQu~<68;LyVGvXb%Fpln0WCN`?hJ~}#m_R-@W z##C-WRdBcA?*#v5xrEUldj)kV-UNtUuF@YPQA@um$V9-oe}U=QYdNfBCot|SQ8H%^ zN?e}(K-^&fx*CVD6x9O-EgQ4BpZaZq>5@h(|3^9}*^i3v4N--Glg3 zcNPBr4$GN}dtdjvXti!5CLaK)I&~)`y{gCed!S`8<|*fiA?ESF&MTv;lK|)QdPv=Z<8K>ce_RE7%X$Gv2U55=ng36z(g zgI}-zZt%5)SHth$is=d${8srlBc>ANHGUt;Cp-%2I{!vYSE2Xy6R;DMOho(Bq3Ew+ z3F;7c!;2^tHE!H>mrS|^lO>3l+yuJPdJbsCqOc8@L1H5QfUpwCq}lMZ3I3})cwkCb zLAvIP7?KJUd)ycdj@o0OTEqPAh{R_-xTCF*zJw-)qFc?SzS2z?NnTzT+SkWEhH zK#pa*4zVf2OgVvWyACB;-2(_Z_VrT6&T#k#2K*SoCj=UWJi0_<)M zyVrnyi(vKtit8dRpwQcSP)-?zZkGDQ zbw;7#%m7oazuySSVYK&IR6YjaC^vAKhYWnyFaX}IH9A!-c1C3>W|;u$uk$S1j4Vr~ zEZvj^%U?zng*ah}^D%o6QvbxWKWk*4Z?q%MPfGJ$E)kui4(0-)3ehS3`504Lz9!-` zCBu|&iS$|{)KYvlD+OPcZu(`tEnMY+Fx zaXFvP3?Z@=s^YF(R*vS4Y?Y0Gm=3xLmSu!i)hhGq*Hj~9qKEr2Nl^q}Jrnp=z|?e_ z)~~F0)xnT!QLd~PBFv0+UtV|Lih9g7*<;#A=#)+yTPNqV<*T;}LEzMaK*pwdY%n&R z&vblsHCJk5QN`yFwxt-~%70f@z%Re{z~*etXEUvIzuDTK$YoiJbTh`kjKw!0cu5ZM zY%U7RY5@LIHbLH!7}u4+flJ1PDcW(~w|ltD?&*qmruXr&e+dw`daJ$Hc&i^j?(IH4 z;2rT+AHQxZ7Y7H1U-iy(&8mKm3xGZToX}l2a2ztte9v1gSOB9H_ya`)=I{=`Cj41A0o&BqG3uGm&_AqHA%N78n?a_G^JyHZhRWqXGT~E)Ywl z0~BtCpZ+jtpT$s&`NE!=H^(d+PiOF&7@QDqy%^p@Gx2(jnO|iw@#>I;LdH96=J+sy z;oD5c-;6Q-?JPj@R4~3pX81Lkm5E6=-3&iNV6kL6oWo=XOQur;8vjAZ%!Jf2g&$}e zdR*4*c8tGTWzwxT%cn$a_}6z#PFtmz7%auCpiRoF#H25_nDosbMbVZa6f!E0W!ZxU z`)2b6Avw#&I?@_X59+P_`n9z;lOD)~2L}_WfmS(k(mQUb8(G3nOGNpiO!M6X%V+f{ zv%V|9Xtz^KF#a6@Grsm>_$>rut5>dEqBXA4`xD`m=#qhjO(KE&K$>BcJsV(&_bSu; zs=6O$0gYxQW7%L=ReJZiR#bRajkw*7%8!l$4l&E6HA}|0j&lgN6P1=l8|GdMvtL?m zZJ6sV%wy7$Zo_=p!n`5vHEce2SU#VXHaj*u=PWz8-!S%6Hq3~Hxk9lvYc|a77Ul-U z+V{zr?E=Cvw<^}=(q?DSvh!WQ7<*P5=A?yrU9q;oGG;fGg}2LR=z`o>XHcfP>@w#g z->IwY-_OfBIH@o@?{V-Y4!+dEmpOQ!gD-dReg|La;3qivi4MNn!Ph$Y$qv58!7C2l zWqO3jiBLbZVD!^TfViAleE|7JX7zRC@%@C+ACX_itUiqVI(7(d0eunzLXVx5m{M!!vX$SwF zga0oFFTK*?e3^rtYz7ph8+ur zy!7x@)UgQ5E1xvaODn&$U`Pu?D70&FSIdB&3k|`BB%V+0XzAa@LaW!VUvbsi(E6*d z-q^D#wCSo9YkNY{roj46US7|nb=znimm!6*Fb}9YlQFzAD1!mG zgybtpz8?8$jQu&uLnPmUJPfW3$!{Y0ZOFsaa3{&{C;2y#hlTMGl7FA%KSUm!dYR;Z zNAjN`-@w=}Nq&mtcygf3 z>_((>8QX^xg7H^KVWK&Lw285wBb_hif7b#im*i7i!tM;0usa{9+RRut(WFb@o+R9} zgnNbb=aB|r47!E>GPlq#a0`8pTj)0;g_B7fX)9y9h#nyNFy;R)<$sFu{|(W1i2jc3 z;9`YzBGE=wl(SeB_HH41i0H#azfbffqHn9B++V4p+%u{uNA(E1wM6FUruJwrg zgFwsR2)B>;dx?IB=+i`x5&eZnl=mBtC=ajC(C#dvJw%fw0+%TfxI0PyAkiO{2tR&W zBJ93P^h3-C8#{L?jgwL#50(mhT_j&wD(bnpRM^vr-a+_p6aG=czf&su<8M&k#@IRH zJuom;SlCv0ML)UME6RVsEAoBME6VwSSM)o4lp3+uP+)xFxK<{MwN05q^M9RK?-Upx zcsf?5iM=RZV&HB<@e#g)@zot^Em6FiR-jMLMCxaJtwnh&(JrFhL{|`9PjnN}Fwq#% zT}1a0y@TjIL?0&l7}2MRzDV?MiT(#smqPv%)rhtdy@Kd!qFac5o@kWlcA_^Dy`AWN zL?0&lmqec>`ZCd<5PgRzuKP%*68#*}7*g0eeTn!xkV3HUC!XIb!vAZ;zd`&Th{KaOT^zv^g*JJ z5`Btrr-^@`_{%+lZ}JHK^TfxAzm@psh`vDb*NNx-w~YEZ$iGTd!}Sg5Dxz_scMyGo z=syzufar8Z(B(ve;Fw$3bCWI1 zHiz;UC$dTQqm^lI0pTx%>vY(wDHHwFc#QL6(Ba>cmy0y|S1S3pn(Vm@`(+}pv)uKR zE+JsF%zidCa625h_&B&xDUDAOa6j{m#ogwp$62Vy5tpckU#iFb4tuNN$T=bjjO6zm zxYw%e@iTPac9i>M1D$K&e}Yu*^A3Bz1<<_(%6-OR@1+K-|4o$a9iu!(8{9kz_AM^c z9HT2{_74u+99V2;u(7zGJN#Q=KU$l*GtAx(RspU?D%WVk(~f$)-XPXttjA=j9GR1x*TP9NhNs|<@VU_U|BJdh z%7tZ)*ad9{^7)Yg4dO#2NCjtT# z8OnD@(izx>1O_|tl}tQ8*bkJywg>>OJ08wNQ2@Z$&~RrUI~0hvb@^tIZP_H05f zR0L{@L`B4qpGlZFBq5oJXpK?>DouGc-uisK<%(Lhw^rJ|-qzY;`@mWO>+7ZOatl;? zAN4{dUr?!V@1;uRt+n>v=j?OlOnwyf-S><#`>eg!TKj+Pwf8xDt+o!Ms6EtJ*BT8s z7`ORTi*9ahD{2gPHb54k#-jDHx=6Sw9O~$##KkiQc>}~>5&8YsEM6MK+;a2p3`ZJ~ zkuiN{LxKN>niW=3dtJ0MR^J&lrp|0AgrBxTh@|9#0>2-MIUit2QQ%Kqn45pqRRs{o zD^mb0+l-<%11+UQAbCn|{-WgtMu!mz*Ynp5GwTq??{A2N>RRUmN~mFNn~`G}S1k=L z`a%vwbgYB&6C>iHlKTBnr1@AlmGCM9|8k7nN|yo^H9$NTDR-g$Y*<=txtL>YsQF)3 zM)SXXR!MnTS!oHM|DWCe`9%KY{hwvQWj8EesowsvV)(_J>B7o}`f{$ILZmgsrxhA* zm~RLxyk+zNz z5^NYTMd#X)Q$$8c5n4Y&f)RH{^GFFI(a?yq7%4^TND0=p4Re6_`GtR=>0Gt=hUyz_ zhR<@Q=M)+_#rQK7e`erM5&l$G;_re5^jwuw2)I0^ihl8@iXOA+cN+fOjz9P0kfpS? z_E1M1+T6hVt!?f2y3r+nIiCvUG%1voE0puOP)^fAjt)brP>#kz*+253P&U6nZWb}2 z^@XCD3+41Gl#@W9wslas6UmYewOQ*_pq{J+beKjNa35g-GmLr@P^?76NuH0&zbGMp zhn)JT8B9-@fnBP7RQ|;Y`P*gSi1_EzhOZ!>tbiz)P2+Y!>QxIGYL+&UctLW!XNVj( zT=*<+A0kV;7{4G{E?6*Ro{R{w*UJ? z{^a=&>W#|bj{t|T`eG`ZM(G^CAH_GaqS=){UC~bqhN(!0Hbg@mt%kckT_KZ)QhaU4 zN}?j4b~FE9`-k)YBAR}ozai|u&z&{9+_L||&wooG>a+R(3H%LZ|K&%McsPXp7v&Z_ zT_Eobro->Q?CuTfhi~ycy!w}kar%dWvu_wUe^GIIP6nK4hr2&a`$_P_9|fAW1kW8_ zckYeVXAiIYu(#$cr?+B)XS4Tj37&a_Oa>sweIK7=>ILUmdciqv+5J!NZ@Cy;-*n^Z zYLtLm3YZUEOrQt=G>h=Ev^tL2h? zmE-6>PIoRlyJi13{^KuOYHYnZofWgGYz8Z0m6dG40#;eYAgp2wSXC9vu42>J?d+aG zWDxd0eqVy$aOpy};H`Z8-UPor!B1fDdleK#_|1#~|8n48?g(X_+n=<}uw1dtfV=~E zOZ*p75{j>BJepoe-vFk3RU@MeZ9Je41hwS(5P0#Tg=vtXi&<6}@Fs|9h2andDc2Bv z(gzH!Fg!>(ByUG9KVxWq;X3?nLUOPlQT`SBb1lqTjIMGx)F7x)I1%;$RzTTk~T z>-g1sKYp5?f*;4sJ-ztxyl)JCfq-)Sn3*&RuXc??3T?cwZh$!2r5wn>WNrO-0jR-(Z95HcW(P!J zcAh?#S!X``GV9G}on^ds2Wi8Eij<^hxPmxA&dh4LDO@*0y8?=5PJ(5T9CqWr6%T%=GgQYaUhlwU*qO1xjf zDd+k)Wu-z{sZds$luu&|&3)LUTrVi+DwJ~-%DE;beQjSBVO)-B+rBF(%M{8og|f_~ zL^~c@(RC)}aY0$6P!=haMJ6SENuQrl5+eznCBE`QXNKp+T=otU59o?+qPPjd4WBB3%-!pJF}k4rf1xiZ7!H4PK+Lrx~n^qF`kbMY(`#G4_I z76|CoiHrFGZfQU{5;3g}h&N!upn!N2;;<>ePl?5#5N{Efn%ZeMF~F@0$U_&#-vNx= zwt#$jmcYn>I9g`ngx1Zh0JkQS zkFWU^-5tlYN|BZ*{Wkb_-5}|xM@I%p$9u?fH8RsZUmyfb$M4_Y93&mTKbI@0TlzWp zC)Z{xeYu&AD%+6+=?3F>vZOv?yMy1&FW4gwyzeiy6%(h$s^dmTmwJ$y9z60httgl7tVGJOuS=B2bBAjdJn*D!0`OM3!xj3JEi za?B#UnptB^+82;x7GW%#oCgSZGHc8sd^fY^F~avVYhEIZb`joG()*P5!u$5$R$v@| zKewfiqWdUny0r#$+T}aRX}R!8iLA;?Tw~go^~cRKQ;paJztG0)9-u+XUP%;CBREp>Y`R z4f&{Uj=+Z!1M9mU>@LmINagk_sn;CINmN1-!I^I1U%8pVY(j<@U;S7D&RW> ze2;*CDBzz682>bJ&VivW!hi_VMVKkVED=r?p&`Ot5$21qP=qBSEEnNC5mt&2=PKS; z#yfg=Um52s-dD!<$NS3F7)})ThbJ+13x=2SH4*PEufgzh!kXOY`Tb7qGCt2WgZG=3 z4XQ1M;+_-kS#ZtNaxeV7=c`4yScEr;uwI01BJ2`jw+O!?!mo+&Z$&8YIsc;w|3!pv zi}0KX@rVh-Oc72M;S3R$ig2z7uNL9mB79VYXb%TBA3w%0)4JD;>!T*_xgz|&fM<$( z$mQZ*@>&763iv4j|Gj{Z2>49_j~DlhCyRT=)dIdrz+VyY!vcOqy{8QDhXVGAd&Kj^ zz2XG|?hx<>0Y5L`9}4(S0zN5VL)<5xChiwI?-j2XA&z^xA1uN(BHSp#Cq%eQghxe) z%NT}+=6=6;lL(&{;VU9MCPK6+gdrO9#QVncKJtBIak1ET?^s+q{(tzgG1>=7bk`UU zXyqMZC!TuOI8VWIyKAf}bW&?^-Zef3a|;hhhq`NgwL>|S{G4}<6XBJJXODt6%>}R0 zkuTok->BdjBAn-_$H_}LVU{S5tjAKpPu?MBNzC;Q@mdF-F9F^|$}|4yfOnJ2UE@v8 z@{Q-ZxAU&?*B$(Bhc)0zB|<(v>%e1%dryThPCc57>{;7lCu2FWoNAmH<4t|p- zy5BYam7tOD#j{3p8#F3E{I}nMH$Kh%uJK_<`DWSGdNb{9W*=AOfOoaaUE_X7J#r^< z9d@X@#v7oLXpwcOyT&@qqu;xf&w1DQM-#bCASd2ufAN3fv!0831!xHWKXXgx%;w*J z%qgK~y#H4|_p|RmK8Zi;wvYV4Yk~UJ7v4Q>4|UMZAS>1~Vyni|nr)AYzf;tJr<$0F zdd;XY60Wz$$!n<#+^-{)|~FA!8((+0p9GwjYth4bdsil0&!W-XkV<&jvST-CDLSb(W5 zl6R`pE2tg2f>07TcZENPi&hbV?`t^7{je7;z*B$4b#QpQ0^!}(l3|vAXyYEj;rz{EtFW)dZL>^qTW1Ol?x&Iqeyox*C8cNZVRWc%rIAw- zZ`R1$GI1D%2IWRwC4B2nQx`lyv5m0d7be@mhK86JUG~W>&75}TJF^xpfPp~HAMy{K zni^lzDg&z+X=@GTQ;jN=8g=oZWKcb99)!g==8mpH2JYSD^e;WqM(M)2;jE?F_;D4p zxkJx^Db5v{#)6!<@#b6zh8SY@817Bp#UJzF!&r1fE`l=PUms$?~e&Ai)k z@}S^&SA@?YBN7H~brC3~Ne!x#tPa_X1|b(}i*PoOwz@!BJk3bSy?8o~d>M_N?nyl7 z-F92v^kS)hkl+lpMNM*J2H+J4mBA8S2tiR-+;H^`vb>}+ps8z0q>4ge1q-2@P?G>Y zmzJ%3mS9$hQ)q~C2_+2K4;M$SEfd0)L2AOG zhA|(jWT7*3WHzW}4JpkmKAiexE1qF@olO|+;hQi3n()L@NmSlHo-2NDP7 z*lKHQYU<=$(n3Rh#tQOnD_SqI_N-1hQj%9-AL*!U)<^1E?+_yuL`I=8jkA`LlQ{4w z&Spv;DAzR1 z)0}me6+;)=QRXf=f9>(g&Yh3#qH-!la~t$nQ(ZVh#jqq-YMZUi<7!YKTQcd`6h_&@7rP8MU@rux>F8u}USYEj=TfD;jp{vZ1KC)&k>AVaGL;xRT5o zjF;KC+3H9si0=}d$dR_T_W8;;d7gUYT2=ms#Fcj^sRy0523W! zj_yRqQsr6*&$XE3G3O**SB#Mq(SmTqRMJ#hFb(DV*L?~+;+>g)u44kW*| z#FolZRT$1GQzECJ`#h>JObMi{7Ye#<=Singe0(^SJg(!(BlkEC)(Mq;)ewGKO!;eS zdd}J1VW}`CPIm%HQRS2r_A_$l0#o58xrBs@JC_iI6$Z>5I&7s;P5xudO7QN-EBIXR zwlH1$b*ID_9N{GFNvaV1!)U~dfLr1*vwJ7By z)~t*vXHq*`+hH3NZOX4}Ei~rvGw`X6IfdK~M}C+x<2@wLjd^vQhsSYe$8IO=n29=O z!p_m6oZ!Zt2*;l}aE5k9O>vAGLrrzDNOZm z40EEGi=v2yC=${09k0iz1&3M-&B;Te9#w)0+j*rQm$CWsTze2k!_e!oR|MxKnxpnp zB%5>_&i;uv8MaI59Q*QM?V)VZO00dWKm*&TLl0i0)h1rIO6SBcTqZlvJq_4mL_?kJ zbq%4RcVX6cB$Q}761M@#mm3hXaOw+A<-j7$hYr?*WU(p3D-3J@g9AztXjYbCM{YRB z6df(@C`I5GDEKt;c-d@kyOj4#Huc`jqo_!x`fV?x#1V^CbUuGU{8qD@y&^lGA5E6f|GZjaXT+5U? z!ZVXZwQwG$Sh-cIjZ2I_v1@#PJs!?Y4w0e4`9zHa-Sr(-_DGB=~)D`NuOC+>) zfQr`980rW$8ufQ!#o9Web*&8{H+5#PZbaT7U10!s5`8ChjuBlOvI-D4GFrHX)S_xg zEi^ksUt&u)8FetFK(&>F!P-eY?O2M%>%xp*iz^>&>4u$W@b{gumCR;BKrS7BYH`LFQm{0^>1*Wu6?85YFl z(B;TMP*~zOTfA^CP=uxw?q*fR-Y(URTm4A5)l1byMzmOPx3ynXS}4>Bv&ktz^PPn# zSzTb;P4KT9T(M;FO!c;eH(PP>FjRFu5E0qx3j5fD3gQc|d|vQELxz;b-*Jiaf`n7a znH>&c$Z+sZrCz{dsl6a56ThK`T|$@J1_6l%dryt&j{N~db>pw{>zn@J>8he&L+Pn*buvrb zgeC5BoEr?Ip!`fD(dLG~5Vvh(l=t6*zX1OjZ@>qCt)1%jT6=`=wH;k;y}Wk5%yzV) zR6)%*+8mZg8>LD+!ou{J8~IjZiDepDx~v*cCNYoD+rj0AsHefgtaHUj5%=935Sda!PBb?vv@F(QT$|18#o`+B^^L5ng#f( zxAq`X_24K;L!xo|8 zb5@Tg^_-|sQi=1i6A~Jjt)kCJoUO`Y!29rk_Ha+|l$IDD zD)qIwfbPVw6(x8^`*Qc0w_rS`J@BUw&!68DJV`C^Wzhn_@8s?`z1n_R!e~=`bY-P4 zI>9a4h)uRdI~syY=A%THlAY9gx=%KwJrEOhVDY4JF?w7~x*FqVEIX*Dy|8fNrd=Dx z@yD#5y&GvxK2$xCTbaHIMpAnGNE%os%Wn;%=xk>kO!)J$fNJJ@oM@6W)Fk~6;LL_@ z=;=Pw(6vL1z=5>_>6ESUW6NyOC`_2idQ0$RZ}4Q=3+X+tX%Crgi=$y{IUjQY6Ezty z2hwo-^mLzU=z0WQ#IvoTv#V|wcD2*37TOa$M@7o-tyz6s|h9;F-h0^uxCxqY-e)5nNvLJfs#g z9iWksTldxkfQH6FWlro%@VvDeW`2NT(tfc^Z5kLQ ze(KKtJtXNkYWkLRdW4x2=-H*&OwVr#9-`VDYOxlj-~npXLso+y=)Y6rBULF)T;6G$ zs^O96f30TLDL-xV7HTwKOF>J%Iue7&h}|)Fc2QB4bJRS?tg47goR1w-s&SNJj;hr- zLe)5GRpUti4|wk#erIcA?zzL0b5-UpSt291oDaM^u^hPPFS1!g?t4HiJV^4_79fZz?TNiZoX)nT#(WTd@eX>HIRel_?m8@S%3zu~{@d}%M#yvys=>wEa}-LVOBt%W}3Yi$_py2fKDqE`rTt>R zPys-X%f0XNm%FD6xaa77QV$rI00n!83ii&%?sq(C4@7_s)Y{~IZHHWmNgbozk_7Q-X9BtHZ#C zxLz_yNp3?XZSzV#_2N=ulj0`i z{@!%j4NbO>(RN%nK^Ph!5glyoGPGyi2~a;yu-Nb9sOFod^ZTi8dwaU~vM6lF_V(9$ zXoSN!aj@urn?&g`T6~}2>keSSP6PLi)h)?egFjRx^s%_sS9S$jGzGT?GX`#sL!_d? z{sovRnGej2Lp)4~Vy$wZ!w%pW^u)0W&@=8|A$9#sM~!$>pxOZ~n;Adzh$ygm*Ik*` zKJ~>9aGszSkUhbp)D+KBk&ec77Va&U9oYRxkG2k(}~W^-NL1bl8l%U zmlUV_9d(WYb=zKRk#RYAn&$oKjoqiyx{l!pAas}2 zq2B;;)BET>)cs-=1$}EjF@BHr5*;n3CkGagvUO4*#XwOAzDN1IH*lGnR1izw*!>=h z&Lo5rh=3b11tnfRcp6)GFa)7Lj7H&0g_26FQxPHse#PdEzzWMvxcx<1Vzq6*Qhm;B zzoJ#4K!_T+9jMt)Yz6WOSamt?-!gH!Vv;!+Zr!{A8{fe+Z4)WyloqGV?N>4s7|JjO z>bn;G$LbTLl!K$dhb@jYiqeCFqZ-5Ly-USo75d~4vJVV zkItwa^tx3o6m&h^$I`mKYE^3#JYr+fcI;!;YtzniVnIIxJ8i4Y)^G_(&tvHM2uZ{D zXo?@fl3=lqLh&zuIc@Vn9*x=u2wix!1P?&O0U5y$88xf@ zUXe|E6q>fT=0NXK7#=l;dRIKU5vut`&^}+GHBB%j4Rn`zOfZH9^DcD(sCk9Yr~|`6 zKOp50R6#!W1dqTtJwlSzgNPt$d%9tvd*H-}*s>dGq0(Ju=UzxO^8!6-qg{ONway(J z8{$2|L(Gzwq#hq~RgVuTdzc&rbm`~cLHF^lMgJdrf(L}YWliua0T%wA1!`XXX_{4PacIy-O?8UY z!Zjp_PstO5W$;Wx5sH2)(ILPQQU;GWYDGiih?(zWG!jl}3jcUPfB%cL4SAZ`%a|Wq z<$eIbXFnEhux-6t!OV?4tv!SF`?wED0&nfPQe|RouF)79Lqlu$Q-(jY@TVMqX5-Hs z{F%!X<28(KXR)cB2AkSsFu&=5?dj2$1GX>1LtripweK+g_m>Gg^l18YFF9cId&u+J z4>Ss1hQRwxM93v$?ppF25O~p`yXlJ!txS7&BXvF*g%@tw9@G@KZ2yyj6f_*}t;2-5 zXm_7%i+a9_%ACiSl#O})7Wr&NkX zeOWi+<9~rz-=sU?QTHYJ(dSxf6H6LJ5A7_8yw9Oan!RZHT~A8B4H8D-{7y4D73e> zJ!4+NVvU*S#rHej-=InCT~d{ z2c{qnRU;6tIlO9L`-pOMyJ~MC)#;3gw&sl*mKBr^pC#H3TqAYnV@}CS@qbs~* zUmq2t0I__S;=KnS$32CQ_4qjcdiYJ5PYBhR6?QUiSjOTHL>5CZE(kv{_?JOm?N~|( zo-^M<%F!4t{L3NMHzk&brSu|J7i5((=9?y#7tO5e`b(7K%kX>2LCg&cXZ^5oSp2sn zuQWCujlS!CL>>3vaSVH{Bs8zAk9v<7qC%W98pjR}-_%2hGT~>C^mYHgeG8`t`q=XS zJDI}{kkiBuFehICjl=uT;j%ZX$V;TZk zS$7~KjeyBnixJC1fRTkQ@Anaqo3#jeB@vLHbqX^{CZI6u&oo}OHvpj|3tvR}{n{S^ zD9^%ojQ)Uz1)i6+4AIgFsLX1?lyMqP--TH<2#nWolwO^+23b$ga7tg3Re{{Hw6}oU zwOQmkVY2og09=>#5CT)R9e}Vji<~YLX(*&tWTD#ZpGm+iS(ykF6L4GBr3jP|uqG=9 zfif)%vTMw$L2k3CY-_Xd(8E7l`>PMV3{3n!CjIRM^w1daKY^7D{2Gh+BtEhL+H3be zh1K;1euvM`A`=~Y^EsRuzA1n^4&?(Dn>rn1u{SApbdre8W0MX*7MG&F>V0aMo9KQ;(9Q6=Amch@cE%f*S7IqRAWLyUDSV#UGQtFWwJqQLa z#hA}+M$`HysnTD9VR$cE?BCXr%-H9{QB1%&}(8ZMr`rTAqL)BZvkd-@uubb&1M;KcFt zt;zi#;~Duixem&KAAB$^)x&wO%{d5Z%iwtm8j#n*30NcjHWV&p+Mk%&huaUK$f<98TdJQqXeP{1AeuSJG zWVLytG!p3TJ9Dq`J8XtS8n4yD+*msIUg}N3udkTati4Hucd*>wK+>-PD1sydrK8p= z5?c_nO=Qu?avvWHSio>SGJ!_hDA-@e8}!SfLD%HG4~V!^S^s<1KPJzzbOJ(==y>uVepa9nB<>7r(9prk2dxY79YNK*$xs7%8?^7cJ&J^NRtH#HK!r1K<%XUQ04}p`>jq7$pb5BentXh!_CVsE;2(G*6$N z`xPL>w}sCE+kBD|kBYI8^9&??3EQ5;$~N94)!09O$6Ex}qTJhI)Zv@CqbB_`q8@qF zl;06D2Fae|WGh(CTR`<)#yk6aJQnZl!)*P&kbZeIM}I8(A?Ico;1z=4r$Q#uih-F; z9Z&NaqbDYF*G1a4`^~ zlV7)uU$^A<4T3T>liz(Nzt?c)tVa-CD}R~zT^5l1*4y~4xA7AY@#~cQW?-bYmc$qE zyMg$HO@3yQ1%WZObLbZ6A=)2o_dC+T7(S4Zr4adCP`INRzhZ$6eOY99I zTQ>9ih?2h-wO<<(T>$2)i(BOSb^S)36y9sRv>53ggn$JcSv<7RjZ@ohPi?oSwr$(CZJpYuw%tCpZQHinx4-{~ z_qt|xCdnkbvq?T|GWTSaI9g`RU+iCNm0b?E* z<{UoBigf?qrmb}t2#&Cq2#!(6o^#phGcLAuRxnO(*))jAH`i7(WFZXMW_>+|gZsN| z1an<+Mm`*LE>v{L)%3Qu=9F6ucCwdQcLn0Dtj#~W9;~W7Y6Z+GOIL0rTWEGG4+GrE zcDnap5IkD8Sn(C7O&IDdp&2_^MsI(dYtJuPMmFiV)*eZ{ zhCLlwB6Y>S+=%#AxqYu?yRd+7wHlST132DV$VAWfJt0uRzhJM|^Ud_~F`l81yGP?W zcYSqtwq_v@!T$wedKHf5SsZ4UypQ12g{;kK!~Cwu2#MOe^n4QhTq;*7Av)V3Q7OW_ z0zihxRq<5k`Wl9H3(@nnj^cD|abus=edcuwZ@2h_;rFX|LEd=T@?y@XvVg9W4XagY zgD2~(x194P_tzQwY@;mXRj4Ws+>gp560Sp9XSkj4lHDj5(MN2yA9!tr`}VNI-kHZ% zap7x`owyCD0za-@nDRE8QPoVqNP6;k=nxEEMsJospDLAx7%_`vuwUK=S`ZJn$o25>U5ia zI50_ek1U1l#DQDgF!C*?=PZ?5?fx9i&e?<8Qi-EDUw_;mcmfY-S@$~h+R~ZesAk{x zEb)zZ^IN3uB7OR&F_s(2)O^CNdPb9q&(nSHp61wb?$9f8oeR+g1S&fnJhTCA^tdGS zc6#Xv$JN+oxh?p)qu6zz#hs%LVUpu1L7?17x!)=)LRUL99D7as`1Qc|>2a+smvc19 z(9HihC-t`0-Mu%sO{4qa!@Hi8+UB#}dwCN#RNQjtVWQqc`RaY;;B(A(oo1w*0PiVV zIey_SCp)CX=;L)S=yQ0hB0tk@`nf~h#i9C9!iT9Ug|Kzj_4D^c>2sYl{75#F{!8gd z$G}}m|Cc@e8V#=mVT`5KdPat2VWsOWd=p-N`_S5xdDvk?L$iU6PHW0;$m<#h`&`q3 zWEu0g5x7cEC z7C0N!vO$=ZKV=zxwTw0m*g!7!=bn*!fDER3kKt;Y$OTq6rp^lUC4^Bc97DV&c$Rx7LZb8M*)dfS8c>gs)jQrwi~t99%c?lz7} z(E=-UdibSgF~e-I%~hn>&{C^gUsRHPMbc8Oe6u`~IuspTqxmLEQH)V?5kgoNS6vjGgVelup8(>q9rsu(i>@gXeCL|VJDKy>9qYd7nDUq5GgG=RM<|H zO_rnCwobzbdrKG|XbZJ8rMDJZwA1$SG{`R#9Uu=`uy6Y?P}tyFQ{6Jiymw}J@}YT4 zaP`TguvZowOxcM^#-TgX>Np<8+!>-E4|&oiEsd&HW=x{x%!;S(Jk1}~xu|k2Wjd;OQh~y)@w9<1k*G6$ zr(2Mdv}t+OOCzz8W&hLvOZt$iK1L5?npx*5p&-L(14%6FUQQ{8zB}$g8S>&G{puls zZw;8+=U)l;jswEVDd^@Y^X93NjuQZ%ny4Ai5qo@#JC|z5-yc38%7)&jV7$j6M_IKD zpuTp9;9dl3>kM$0rW|Iz>q*jZg5UMReF>*H#wzAFr-_^Tiq*J>`@vDpd~X0>I{;o- zQ?vZU{jxNipm+J1t*!{82`0wd0__t`k5kY5nQ?ExAidK;>FfawxHlk>oxNz-g zrxhuj5`0H^r*0fOj|eZeklr<*R}KI@2S6Ohjve)Vj`te(94*>_=DJE#q?Py8SLh~Q zj}xfEgd@T5QUs=nNj^B{q;`1G`sS*G;h=v<0{f;ug9SH7!j%ElQlzY9xllgaf=6&Z zf3A|j31@}?}>vqnn+tje|R(=WQ^hXg`Z{ioS0Z6a%;TkLSD)D;v!#s zk-o2qw<>O5{D<}_EO~r0!s*d(Q;2=*!u9C(tVFzp2fhiOs=@fm&o;JyCz(Kz5<&0C zg-D4LLdl}n1MT&Z6LUk`+Q21E1gEF{T+s3D0ZPf3dxa-8Dt@Ie0CY4>YE=xrzkbkd6zK04{I`|SH{pSI&1ucLRh_;-?nFM@+F zmbM<@tD1y&I>#E=KF59q3Q9M=Ec4dCDM|Ju`C+vjV7Ewp7|?FNz5;HX{=7U|-Y|%8 z;{SQXjyx^Pr`(3OiwUC{JNJ)>bcC`8>ogs^dyxQd9?7dr5(fSnVSQf&X59Wc zE0AwzwrOF*x3Yv4g4`J4Z<&OXZ|>0E!krQD_TjVH%{;N^#e*-fHoI9P@7K>X?vBH5 z;1Sz@_XV}vfGCjCWjjm=Gs>}-peavuXr)Z#JFg;@`fv}!Ux zyuc^?ET%8T?s2e@;jin6eAn3CJG;o<58IgDkK$oNUkqeE%&6Bj^r*)VgWpR|GXl|e zD*~0rqo8#;7)kF9pb9-HyJ^;{-2s^2ge${lj@Z@*N0eiegmGrC#IJnu6t(Z(xJT#n z9B^)deZ07Fmx`126T%{|9QgC^vG%GU#afB}_1wVYS}FdAn_2$1wo(B1??nGYID+6q z2Dm=YDX?@}{bGbZ_ba^M+iJ|8WHLA8FN2%>J{up41;LpSVjL(Y;AMm^Q| z(QnfUU*vP&tfzj`Z+>Kch_C(S%#_H>`huSc71#^`zu3xyR7lKlzlGK1+>>v>i2OcB?7<8mc8&X9gI|Nu z`y~6qpw&=RQK~7tQ*LDXH2dVBo{@YdURVt<3^W<`;Deu0_#j5!j-p8IK#hHFSrd7K ziHH{Xf+d12f|H=^NG3?MrPU={1MOLNJ^L`AT9B_uz2ofZcMbaXgSU}G!-$7a5GYuF zZ3(#J>=O6=`NO>n8mtn`PqrcbLcN$k_dqynSIKU7-i?!5vWiq}HU?#GfVMQFT0?J2f@_ej{<-^#-Qg$l z6Sl=3d=q)_kBW)gl4%e`q=|Dt$8W+qNi-vE5k&0fkiWY0#X<1~-`K;X6^MPpB~m2u z#4+UF@ZI?(->CFGk9BvK^uBpq-=PX^OK6Hs)SiGP9b+CiN|;Yid( z94H01Qwpctv{No*3OLe@l96_ZyC!|0^kIznQ0xu|`;mO3Cz8Au;%*WgG6v5>U6X4| zwuV0B624+3zWPvsG==va`T7LCm0rY=% zTlnZOoAu$Q#+Xv;;`7G?%#pTnj}(Jo*~H<=3&%?_VX|e9%*B9t-~tE^Js*sw6L=Jp z+G-6Y0v1)R)lNFR{hM_ox}LWJ72QqKwT1vTZ9sbeE_4j z75E_6zj~2TVy?}~hur!t@wojhGzrH`BUWVd*^*k*ec-7}J z(FN=}DIuw>F56bSh9L}D%!zZIOENiXz}5?bDuA2hv%i*rg~c4qL$QSgB7_=_R+2U@jmWa zyi5#^s=-lCB{osD@>f0~)5 z@Jx9e?+Muni2*p7v)7y@DOE#eLzCT}I9bDHiOHz!?6;%(xK0*B`X&xdwA6%nmb|Jt zTlxg~qQk&2l}f(R?u;wsuuou#e< z)i1hICGz8`EYBdzI(kU9&^pWX&C|U`WYgAZVuPSF2KuU6t_jP8bXx36Hc8cxY=aU_ z%fqK?qO#=K@>x^GSFMrcStBCGzholG9p9$R!Y6xqFiCgcgr1b!gbA0KQMqIA+k}tYi<-S=s+-GwAn@+T zlT#lN8R_)#{w1E84JSQvHDVR1yG%E#oX3ZT|5qV8BYdufqpCzv=enQ(&P{Bc;Jz9h z!7~g_@Zr&3q@t?S5*ZtJ1xIOV^guxEZS8hh!;OOaI@$B$tF7)ZfmzAids;s9e zSI>6?S#QewH(9HGA3#g2EXMi?luAD11>xxZ(Ykr=ysa4a1s?Z6!%_)$7LgLczXkQE z_YW(tjB5Bl2JP8n?>1Q9!##}H@91u{>HRaS53>W~+grq|bn|ZyZP}-kTR*C5q*?*T zR_ZZ}bjkg!O>GC3e(k*Cn;rpzArBt=z@7c{ic&1kB%SFp(3mrs@`Mw^7|VJtgT~Z{ zs3Y`icD@FnlE@rPlW4%j=o`R1OD_5s6P_@VK9d&d@49uF{=qEgHk#}0ojz3pH--5V ztB;byywB(8tck1(hjfN7=K1;R=x-^9UZCc33s3c2t$=^%Lp$avX@r9_4X#=U+E?Cs zZFCcdjcHO+^p4ox;btb__}`~koTsblnqOfL6O}ak--_Bl;x8@@xa<5~o%to&lbo_r z$$yCjq%;yAn+nAb3PCp{Ta3NF>{(P81S{+qUdM)hdff%Z`(e2&v4Y?H(EFZB9f0cX_G z`A)MF+w^{dFGz>`JrK04yEOvvvK>VI&s#trW)nKXE|*@*gi|(Q@jbUY>|$;3H-wVOOYB!CiO_J}g%`Wokp|W~ zM+sTwo66FQ+`Zdh-M27~J13JmPlAL*Mu@-btcY!+bbH zMp}b^tm<9q0-q*_woh*KN^W!6dXaYTB#Tyb>F}BlN3?ezo4eGrbc#{h21SZoOP*gG z1qG2ltZVXW{goqsBbY?2itzK$Xd3*cY+j2lS|ae6roccIu!VWC?9Pk+29wYFIyB2Q zo5al|JZz|jY%Q1lLfBDqp#}=^4iKOvsdPf%jKq{R97@@QJ@Ad#g<3% zbY=L2H(*8oJ=*)R3`2Rk0(l%PAG@c9?4U}MRW09~km;0$ChJUXmxw$5DfHsO8gJB! zJ273=3%-xMb-ajjMZqKO9z7$p@@GYIMRbL(7HGCHZR;BOE6pB$SF_J0SPqF#rZvEx zWY@HhHdqU~1*Kc|1$~!0xC8q6SGU{?k^$asF7!F{GYURAkLU@JHIX%$HHkIF#V^lF zzP=UXMHtMf2cT7;Qy}9YGE2rBstDlVd!ne@iM3w>wSwRy6=h&K2o-$zw zF>M1s7}SPP8Mh&vK4#hopuHFD4jKQo0P<9oG1m%5A^1B=P_+$CK_gEtb5Is^chPTghddF=W#OiXF zmf-Gnp5LWk^R8;%kDj#_ZEwt}_|}nhCvR}liGe2Lm9H|wC7>W>?vRTaLzkS!(c zju^S6)S@aKT8#X4`l?Qlzp;2Ax!NM6<;u;~eg>8ZU z%wfs^-%)LD3x*@Z7ccyf4`1Qn{Nu%z`+ysa0Ns7nD0P}-xkiy->6x8-lNf7iXn5vPEUiNi4ivi8dO}`Rx3lwX-N{PQoe8B%N|LWrbZ&u zA;j=7*@7hIflUHEA{|Ydc5>7wItpHXrx|sW75>VRe0uB&Pt>>9B+JsIv=a&m3d4Pa z4KoTXri;KuxF;?@_;645`(n@6yoa08IkcHv0#vQ`X*HxcQ92ZZ68QA``n-+pLW<-^udMdQCozz@r3;50+N?J}4e)mwkiF#Dj8pWNTtRiScz{aN_N1p5odl1sfJeWvJ`SwoQMBTda%xU>~lLnK$wTzGM z0@F||fQkjUR2&6#orj-=2mpXT1XP-Gcmsq6y!bf5P14xqGBBzoF1CucFzGOi$L&3G zoZ*2QwuGJg&&F_OJ9Fwi5ak*jstF_R6jN%sdw@?Qon-)|gFK%aVjBbzUMuUK*7;WH zv3U%)uewzw+_)^`tiR`qUM9JtC<>xGZJ~7orq5WvA8swQNsj4nlmS6>k>$FWkt6}) zOrO-8QJg1Ve8XzPl_Fd69orL6ZkD!s`lC4JAO;4dULLWfiD##b7uUUR8jkR8A;jEy zkbkGz7d5lV`LnC?j26zkcS;%{oNa#ulJi>6J4`{Fc(tnC-l-Gz61Q%A6>Zk8!u(1j zJzp;&4YS7rSGa4Z^esMI>*eeHARxmJfdNc-#;bH61V+)PU;B0%K4-Yc$VQ%sj9ZY5 zat!xgVPjpKivD5FnW}lJ`D`tj350FQrg~k zuUa4yNn`Ik?uI>xku5&ebGVNT{~UoOm%JWQuX7*50zoN;C!gy$&T4_;^WtR|N3DUR z`C|d*69x$FeN-BkE{pl~tU0^)OyL(%v-KP=8lkHg;iX=Xs{>#K^sENt(>jKa#u+Tw z{xnm_BcUTC=%^DdFek@jX_B*~tNbcmX!XL z4E&=s*GZpx=MR52a|wv=1x*B6ORUnW0q`upy*_zhimcWwWdJ|-7Bkw-=df21$X7mYa>oW;8zI__`zUys zzZm|qJn(Ss;=e1z`RPCyjw`T-e-tITBxto2hXo42{H`hPJ13bi9QZ2J{xB~C5~@PA zZLU+w0HM{9hnRsbT6w>=d1LfV46fuhCp+G<#mH znlsA}LyM2A&QgCjR-vv9hR4n_|DKrrL4H{39j*P+{g+bzUTc4?Vh~#kE|eb_vdEg5 zGH^a=7T3;r=-L5p_dC}*b(P?4E2BBsdYMYE527su<-67|^XlRVFac?nRL(Hi-w z??s1%R-1f3rOtWmyU?jM@O0v#2rTsj$6NqW`T+}{>WEY8Q{A?z+mJ-4zG^kP0X{3_ zftOo%Bi@Ps<62!ve$%D?a=7n&iom(i1*;MTAXBhJEnB7jh;Y+ z$^b~nm#y|Jc(j||pV!F#JQN320QP%`(=GGQ<#w-D1}MEt$gyLD!?X_Zekq+vYZ3oo zsm0UZC4Q`YQTj1TjoSC89}%Afz@;;OMpbeUMhuKPHmS>QSMs@Xnj6~VXC6q7m%wj* ztBsD7`(hB;O+Qs-K%{&Rp)%l{#Jm!$7{u364^bIVa}gGC*FJ$?>R;4sGe3LRN>9Dh z@~7+4+f*5_n9zOP@?-71zR1q%>dDVsaW#tj>FcnlQz0qvtm4!-La?82d0;VV(K(|G zNE+;$mI9A1;#wnA0`{Aop+K{@4Np6n4u^SBNwAeu251F-5}b<+*`_kNt}u7xV^HsG z_HMa8D+0$IC!An=a&#~?BYAEwIiI50n3O(5W-d`7q4gX1jr2s2-<9f>4dWh$!&gSS z=iJC_xY54qlCd@A5o}I%{av!UQ)cF-TJWiCva*2G6Zvi5B7IkB^TPjB&BIkrJ-My+ zSgxoXDH*K+6Rv0+K#FXfB!WJgKu9c(4QzyC3|nC!hbyeXvf}@1jj&k@*9HRjdG^#b zJtMhHEYuoYp+V{Hq{c89F zJiZ5wyZpUlW)m`f46eEipL`J2oUtChH3$}UF%wN;GRR0ENY&50<}e&fQ$_iZ%bd`> z67^vbKP+!~5miH}v+bYnw1L%USFz^}LYduhk`VFtT;8(qLB_zWA>ZhaHwM|`Hnqq4 z;(QmbW!|&;^bBOajIc?@;!2b;{?J8T;-B0dC-&UgN= z7Y*jq16p|o*8R*2Rs6=(rq)l%WQ%+`bsXsSbN1gwn&|Juo(f<1UIB3)`|ta2O1T>6 z@r+%^nY_u|%(Av}6-GiUU(*GB(oKQl9&KI^5C-#xdE!7ftK`8mv&LQy+HKJ;~S-9x_=!*D&8ca`RKqb0OQlRwd{q$mt0d zYdc$gy&S+Yj-&q(08|V&oG_oLZR5#Jg)`ESc)B?q9vc}+3hrPe1aVND#<2PYgAAho z^3>d`v+4WOH#y{N|<)ZV^>Q%LTD);mOi3$OIkrIw`NHu^qHoE zXc>sq`(mm4y#OhCbjs5TCciE8D^BXeXfl!lMfH#`!XwdWBW{#y?y4|JFT;_sf#y!C z!XcFA`Nqn_NsZ2Q%&e_Af(Mtm1pxb*o|E#pO*pA#QPI)2F@3yP^f{L2BcNFW&C!6t7)~{~6#>upcO|r{9O4|H-ux<90sKkZ1 zZ|{8pavs;YlL@uf(Zc1rYo~13VPiV3P9y#6vX17NS8U%FiX-x-!TC6Pd~k3kbbQ!> z>fuG_X>|>~p@th@1Le&)r}r9o-Q!3638>clon6C<4k2t3>FcCq#fyXY*je0 zXo0^g{fZsj(VdRKg^BI)mOqsXf`C?cb-(<_t2Y2OB^{k$z?ed#O94COBT0Djt)XM( z%?Kp4?!!YL1 zDF~fCj}=;sECjD^JMU4J##TF5G&xHwLyC^y0)6YOmZQsZj&ZEdD^Vs;|1oXTsF8%~ zcgh#KR{HstPQeqFYtLAn=AigDk3V?hgz*e#dPrTy(h5^aL>nM{QHkuuIMjFB>cHNsa7-3>;`U zf%^o>l&7&v+>jPZ7z*EtD-c$rw(Y?vP`*8(eZEI^e}d`r&+0v#Q>;CrTn^go+4h3M zz08O3>%7j#@Nd34q4{~`V#R^A`kMgK_i`cSr*20$mQ^Pxt#im5`#MQ z;H&VU-DoLKZ}L#!W~X#RfrZ|&0VseD(--ACf$5Ba@1oBx(*#?|KYL3Opr-Ti!8;=G zOXGlSA*{iJBD&R7LEji0F?tKmpU^2 zVK~t2$&S)h{J&w04ov`?{@kZMSk22=fJUJNaj3YE9?%QeR)Si%+8e6{jGdL9{B9tn zIHGO;&z>k@Y+!Z+;}XM*l&nZ$PvGizKIHuC00JNaU|bh2`LPV%fbOyLq{0vV*pI;y0jv#bE z+TiZEHzoir25L9ZDXuU_km^C80-E(CemN)ss8t0DK@Q&Dud(P(e<$UgN zgYLM0F2sk=txFHXS*lIMQdM>q%Y31UH_S^Hz|D1!rojDd=gsuRhHrs=((;c8Sp!G!Nu~Va0(3MDHi>a~mOc>^lVQMR z6kjccQr7V&&T>*$b$Lh9W_9`N72gm#VU#gl_2OMvV9O_ag1ANJM`CGpI(&v+(9x26 zMrOfd4?0Uz-s#T2bj-^nKd`R^JGzY$H_&fs=9eTu5Aa8M+LM-TiyieE=`qLAFs66g zX7^@54F`TnW>onmnpTuGR#Bb?PzIfB2G%Uk1f(z7&1KdLqrwLXpa!HH5Rr>J*dwR~ z{=z5w!7p{qn}Uv5Lu{B$-W=xMgrYI(F{HJB~Fkoj{J6 zTT%%jqd#VHTIoS(_I_R5*pp{6m~s*}PXj9B!CeO>`V9N6C=Go5_fHrgrP-T`gQUE4 zA7W%IqY@QVxZh3~;7NW)=-^5fyzCJD^MRZqy`2HQv7kZOVc`AC;7U==5J^$Zkf0*h z5I!Q;V2_;~Ky0guBaS(bKDXC<+k-t(ei+|$UpgNhFK)Nj-^bh5E3O9GtiVJ^y({C8 zxJanPLB9Qo!I&{tLXHo=xvo}tPE>rI|2`@5VR`tX`Vii7#vEtd;+9F{@wxCZor4Qy z_YO6I<-iWdt+s_{T9i8VnHy>1cNTr8I-FIqzs)LswWVCAE7r7cTa_~p{XMzAa|g`C zB|ybl-)BP}IJttwzlKQgRiN$?0C9iOpPTzpfM?o94K)onh#+bQ*~bjAVlCrAkCmKX zBPSzvEZf@*KVnt)LyzTFV5G|oFK#{GTii}m!hT)~`&{=m;VhfAKJC5HYwPWBg`Zn# z`}M2DonN=c?ph8!;#DWL;)@p93_OBTdvWY^q8`>fDk&Rs?sc{20xF)ZrQPUppo?qJ5Y2bd#A zk5={luRul*9{n*EUhmW0zkCOG9!Is~$DAaBe+Z}+`&(@B=dJk4gr5YgL9RC+P|gq> zispU%TdF(;vNG{kCVx$%Ie&Abm`{>G`xFmP9~Pr0g-|GLO`zuh#OfJ}M=wu(bBD*l zPcQUb&~l8I z6mF2lpe3iv1yA|uOJ!Z1opLLey)eu>$>*QLy1K7{LG1)#-L*EzQjnVBm#58{0gJeH zhA6&10fcgZqUwHv;Xmj$3Mb+4qHVIN8Xxw0+eqiz*sy<`vi{10i; zPf8^QvvKPe%0<#48MTV7WG{EAm?N3#5sNt;wl_8E!L&O{Q<8;6QIB`BKY*5p`HvBUA!`n+q9KqlJ}ZWI9s=|p)VXITbsf& zU-(>!3UQ7_ho#66ULVJZb%!O5@QEOD*YX>(3qq-a+YqszTvAEU2d{{2B+IF^D~Zw$ zi#(ZzX9w%JC{0L2-wWa#VTfwx%*Ifzig~%XmI!bS)5vR41uDZ7@=ZB9;hb!eHSZ|L zrMQ}%3!;YcIjcs6Pqd$G3F(|ELu-cMloAcuyl#|5)8N3AInPVRRL;XtxzNZ~sxVz1 zl&qKcrNM%Zi6s&&?qSC|H9_1S3p!sVSfk-E6MC7vM}_Aedc_P!LUTfI#GD)U=Y-_$ zv_>BVSFqe%A9FFZQGNM)85VO0qsV4zg>Z>wFZHYiwQ@0XcJ-ekV%n6EOse>#x6gXT zSj~v7ixZR<^@!M9ZV^lqL@kv+e#t|>h%MlgrGQht8vTj>0v*_vE|$%ex<&IDYk*JQ z1RG-+)jc@WKFt4??&+Z`6{j(a1UL3W3hf0R{rWrjgYGK~qg}oQPA$jF0kcFcCr&n# zF3tEIEgM(x3w*L0}K+*Y# zh9IaI*Kj3`Gu0Ffq*+K%L*G$nZkCccxx{m(ixSH*D&+qt^B&DnHZOls!tqPjN!H%} zKdR-VCpk{La?QxKnqoxwAF&-z9{he>vnXyuGb;;fSm@QTbSQQxXOuLDkZd_|>1Q>I z2x=JU)i5m4ke$LYSC9RhMZ{wK=-l5;eIxubkzB_dl|k8Xj3qf~eoiD&+Ly;`oo&vUmj6Pb8Ii z#2oo*I6JsF{-d?5=lF&jgUoxojE0$Bjgy_Bl=0PWDF{S*IU> z;SqdWr$n0d-jvIovF6r+x4#Qi*R9r7Z$(;GDmJSGPM^8h6IWQ`+l%+Qj$Nbw)OcyF z;V-sgJe?PL2$My+ILl*E+`svoN+aUYn>zDFd?xbCEEH0)nnirX2hoAc?_wj;a7aNU*i7pcbB|h4-mIG&1nuY{=cvHhhk*=v)+B2fY(we_uWPe2_=`HB7 zDt=pLtWpiWlsT#|Bo&~$s4NtaFYY5md73N~_--_p9^xL|+aywT$80z9O2?!}eTAc% zeutCMNc?j`xPO(%_yd0JD5j9r?;Wu%5pX@m1AO|0x{K~5k=QF^Z1q|41x{$sYyWj! z)Nl?!kALwqmNd;IWCaj%bQIiWJZ;j1eYAzT71x>2r>4DhhlwO17av75YCzPk3KD8 zc7eYwlbw=~#elX+R!|nqY&qWG59AG+ddDv^1nxqA;o5@+gdpAtFUktyMSRE4vl&-H zH;Jutc>;njYgjaG$aNz%7_;$>`W+QDr1mn(C-IGHK<-Z z6wys>xXN)01$IoMl-u7%8291GpOw9cT8jos_YJkQ zEN1>G)3MRpa(Hmyn(;YU`NbUmEy zDG1}-y)zAQ6Qf(Avc|cf1iN&gl+)H`)5;R&B{-!h6zCjd0}`2cabX0DXlM5zD`2|B z)J|F}&+mith}9murI$K7njMfr9Zb4^!6I$sG1m)5(T{6F!Lj2RkDC>jG}Q)-JP&{{ zU`P5E7Sm5=s0cI#tem=6F4vJXETK}eW3KKCb`GAAuA=<%)CvnVExg@I@^D+W)tpH5 zE)}x-eRLzf3v{?vvXs!)uMtfuqq@n5 zXZ&uhGI>8dh{wlP*qe&smN#f+Jzs%@*Sfj%La8T-mrjA>8wQioxNq?^R1*VjKK(H~ z^0@Y*<=t`O5o2Io6qq-5!skWJ1qBFuSvgbR8>r_!rT^-MV>xz;B~ zo;9$I@_2AOcqc&t(&h`k9T(47g|ET|ZZ${AnnXku@je5r)bTJ6~>04&23DE44eeC5y zbvCn*$z<{>@rpLwBs}Vlh^vT9GC zmaV@&sY*nirk9OHyj))+)HSNP+JZ4pI>1$Zc4Tmdcc$E`u1M?I@0;^@OKJ^9yAc>> zA;NviZ_4lMKKJ_vRD7G`ReE^?O!vSyg%bZRLB(!n-4<+!7`V}@+8*Qa1TVG~#CnIn zaQBi~57}Q#a!n+*MJYPv5Rb8hIYjc?PAKWGTc_yOEw)Fbp@#|WH7^0kKB=`6#whp5 zU43k)1eqOVN_w)%2hQ;F$o6Qjew*Hte8}(ApnpR8?RHHDAIW62T!{#a=C0xv&27?^ z2gO5DGKyPa$-|g9+v>D_Rgh%_OXKr?)qlrP*6eE*Ah)9)_tJVi?BgB1+H?iqkMYzE z5z8%Ox|adP41hLTT+bCGfk@2Ayb~W1hHCa9C0T5xgk=hjgns~ z6^oW#3S%IlO?-4uyZq#7e~VV4(aj;ugzQ%wX;`GVR^{Bfd_7gn?CdnU2Mt)fL5~x# zeI0RJQuks_R0FVFVu2EF5xG2mt@OhyAwYm=%Vyh57;f%Dpk1uTM`Aee^G9e!eJAu{f z7uFmrvDc(M5?14K_=Q8rh%Uo}Q;a|Vg!!QZMgs3CF_X8-Tx&WO!(k&Z7$PVMyp(Y0 zFae&wi31`r_X%-*Yt#tfF%2?dm5$hJLd4i#GBAHmGE}nnd#yZQ@#gpg)Cn#n(5?_1 znHtOW|=__OrFY|sg4b#6!n1-DF%od{8QRG z_J`r5t)K%d!$731ApI~HX4q2HA70G>>o56JRX+(j#7zt+CD2CtBH~AzTiW}&mj9;_ zWqGRqziXSU{ZDyE69ukC_X)!G7Jrbk@!pY`jTHo z{WRv5;on>KlWiaGk{SJzu3_e%lpj5V)V25^u5$rq1^;#@D=gl5trV5%h1Gy$1<$48 zD5ZKCY$Q^cw-uF%pA86jPs3n^e^EKheZgC3gefhvxTb+L z4zu7g_?Gd^#tudodU8sZTreT{yuL#t3Jh#Tv2wFDr{7a`-6KtU?q=TL#vb9BUgw0) zu@nc?OMM7fA#L%qMGc`M(js$@9*ZDh#mv=rF*SiR2-IN983VEUFs+@*@8rrOwE1Da z6Wos@K3d)|Np6C3;^@8p&h8BFhYgj?cJlJ$#P?vD$2)^I)PD`xAd?;qNiH!{M zk92(S(mGnz2QIaC9WO-U^`XervfjqcvA%p~@+WM5KvA#8o{*|Mkg5fbE6UHh>L>*4 z$&G+3k!HX6&_=JgW*MA;m0zT&pvNpZ6WOF`#W#5g_|bf$9w@%jiv82JSFjV&;0-$` z8$?^wwmJP1>kXyNf0D}IXqNM7HrOQU#F{H4wKjtn_beq~ouhM|L~Aimn_uOTxiGtZ z2M1H>EsRx$M~|8T9DftmuZ?d4T3&g8XyI!V1n$x-^)A`Ky?~jfp<2RgK$!F!z zc`+YvKKeZl=WgaovNy_R7qDxahde*{IT5X<2lD!j4!*hQ`S=8R?%(%y^S;%A&p$ZV zf7KEeQwCDif{<6!%#vb*tFfVV@S&|5gZ&9QI-dvv^FbrN|5P_+A5L&Na#Id_28Tng=>TO-1#Xul+L* z5n6lWBym2>ouby5hwZg%A6=|DCzs-gZklB8rWc!SMF=$s_6bsLx{w4LA63BKwU&w8 zTRG7MWO@e5*Eg^PWI90W$>E}#_eW$66@A`4Unf&N&}%ERx!63CE)HTFz_K$QfLP1WHnJ@N3)bEas}MQr*faMY{CE>(G!E`a3p=K*#k>q4ktG@TkWAL zI@zzzLqA86wG)2kMa#L)VY>(~8aMjjhdlk+jMJs)S!JHqRjyj8(CXFGxll=rX@;d_ z4xa$Hyx~s!l`;jj!?myDCe!Fv2leP+CZ9(ztaXDxuLIuFb?y#L?=M89Bv*>b81}Z0 z7T!#fHNqx*sh#LkU-PINs*5MuYsw6o>VZu%^u?nKdk&Z`O;Uo*VjIVrcnT_IM_N@@ zY3_*Y%otP>ch{14<=Zzm=8zFIXstBYCSwJ(F#eK}psq2toUA*g_fzRJ%@Q9Ku zQK`vKDM+)Y5>VY&1r0c15+bV26b8$LmpZAZ>C4HIZy;eswM1YIaSd~ST8<#h{48Fq zX9v4&S088F15}(>RU6kfSFzNb;v)nVbp<@0Fvv)Rd4t~FJJY9G>SC{?dlfkju;jELi$g<>~v|AUQ3zrpUBwQ@$P zK93!b?k-q5$sdo|`WLeWN8`jUj?-d^(_(?s;$_nrhP_rd-kJiQpT0X@b?af#Jf-PW zqrKFfKoj}m<7&7`k>EM+7E)%awyGjo1EHbO(hS9Ekyb!iXPVkiEK)hRWRPui7djp~ z>bYnKU%$=9!T};6>b4lqOM@D5=xsC-OxnNFSRp!KnvSrmwPoOKTZJdEynxVQ)71Z{ zsp0^IW`~#_)=s#`tANDxF1tIf8G|6}OB>7sMUBwK7@38T_x@aMoLAzM3^ z(Jgad$f(AJjJy<$K{So^>f{pK9v=;@&nqtXDwLMapae}T_$^hd8=7XF)gq(SGGguZ zlI-g~$)iWwn$6&4Tfv%5RqavRe9aD49X>{u^N9RGyQQN>N7*3P9Gc9Qt|e5wrX_@* zC|<|ahtCkKu^6*bkpcZmd>$K{-W^5hd@|l0K+#AI<3;Lhxf82p&el9yRQo%}t=W?* z^{;7EB;TTZC=>(VqW|M4Xii&7sz3^ z?}wGGa+GZjYx@FLyKke($y3}3lpe4mug{AN2=&=JD(1i=zN9&V=P+vUUv^q%Sd5k$SfyU}EgV(hR$#%X)uifJ6>ul%LLuo~k%9baaW5s!t6K zAe=*l((SQDv2-32ORV~+W#4W!Q#)p>G#nRZ=Y)+^nqP)8r;k)^F_Iy%Ba25do~zTd zv*I+@@K!)9oM(d`9pi+H0cr;oqwy^=bK-PA#fHR)ePrZ$D<;zOP z`^DUt7#poF&M#)Uwo~Vn6!EWHsTauML?;<@o_zJln__8J*wmq!p@pibj*9+g=g!|j zI&WDyLk;Z>FA7%qTGv13o*%Vden?!j-s`)@w8GKZXI^2hM$iOzd(z{HJ!5y z)mi#u-?Z+(=yB_pw48P4#QcKQ@)kGbq}XUrJDpFH`ZKnerIliA@hB-elM&UUB4)=f z&5&D-RF7CEZnr|>^$Uw)ggTQ_c3SsDt$uO>IhD$J|ARd5cbM_9iS+edc zCt~F1V;OOa__OMwv}}m%_+xy9XWV&pGe4W6m@Zw-q6)q66l@jw0)klW@&z@esH|Hm1eTjG3A7pZWWg{o#ut^%iP=t zu6hGet|XGje!E*b7zU3%R#wI09Sbx-1{Oq^b``S&OLI1DohYFFPR8dW<@h;c8gIiDH9y0PHO ztprqwQG0fDF*DMCnu;9|w{2!W8+qQhrL#K36UaoVFqPzsd*c;jI-i)LQGWB`JMS`X zJ#Z-c{(%AchJCbmYH%lgRP20uD3i{oOW7omiBfWMD0}_x>!ZDyOlmyZJ5kPN^66A> zaxzgODqrYT1KPOd(1G_GS+0jK2+pU{`AXa_(#R>4Dp5Renoi_kVIzxYig(|0*YJT` zRSDcJeBjU>H{E=f5s#yP26vLSGH;?#ijx;rcA~tUmX1le$pYU)tXSk7!V|edq9QL5 z&K2^RD1V@84@Qv{>?R4hd^UAbYnm#Y$QyQEwl9kIc|8Ym2{~{9O;tcmX|G;rMfg* z=BXoDva}VoJQYtCN@>F`r?p}DN@l)TS;`~bxyhWFoiMV6VmwpfpgdXPFqNI=kW5;j z2`^E}7V>e$VvlopvLIP=6$LY7`5eMBJ|LbW@$_*HrtDlrRhE_sg%pR0ybSX)Igv^! z$!Tg^VPb-6jt?IsOHt#Bm68#sjv;3&XCFu-i;ay(V`PmJ@w`1XPUb>^o$-M<4R=~E z;!G1yd^|zM$Y%4|iZKDxd-$?>V#Aft`GQ-YbYqg6KJLrHIjQ3ikyn&E?&&pWu{J)vXwM9HeV>& zd0zKuJW{*LXen6AiRrX#j)N@XxdJ(*)N!W)`(mV|3O3n2RY;#KmOR3t_Eh3nI!^N+ zC!?@3HIy;p#X{M;;2KKvGK9hP43B@tGwDhk6U$|ZdU`eD(-nk{MO@31f^j2TK9()g zv|#61_Cz9^Gsu9Wa(qJDf-ad)pR7pNxPF({IoKMGZMa`x_MI{ql))|;TxZ1XJVwb* zL;8s9Pa4&B(G?_3#U!+HysTU)(Ev3{=`x&JZ;{}U7->m-OdI8Rkt{z2U!C9)oAT}; z(A@D{B7cnPFVV79$fL7LIwBWd6r?ET0xE33;k%3E(j1`~r#Oj7Dx1l2iqwoEi5yjfNV%9uroHQGrF6>eT$+}% zDal`)OmLnv67S9xPRPhfDL<7?W~UN4$NkbyY{H4g&+*R`c&Uw7fy-mku4_@ZaK^R+s7Ar|DIabm(pwNoabt;r(av z4NqQrZ5_R?j$U6!Z>XcAb##yN0Qt{v{Nz`#@aOc^I%H2+^jjVp4@aUwmwvC(Uv5KJ z^GgrfUMATKw}liv{HF}pz9!lC3w8BBTSq@vNB>0~{na}9>vi-$*3tFt#V^o_o3%b2 zhEbP)$%?QawPZMyA2KF$JZ|H92#c*j8Zze)YShvwglzn_@$UaQBHeEf=(ewhU{?udWbBR>ek zsPWK7bepeM-bSMJ0W_4y{qg!ZC}BRmOxMW~oLQf&K*1r@_$uFw|o2p_Fhjk-UDdj{#a>j zx7@>ukcVrC^g%t)`z-gK9nc4@T7SIPa*t9YKV`Z1t+o5QjpLSkI12eVa(s5T^xt;U z=u?*amLl?>^2mq&e`>kMoRI&#CGU{Y?SHY3|8+~=xz?xh->}?koIroKj{oOGM@gTL zsQiFm-rJ_je z@XPz)rZjZYk}##IiGkG3 zz?hV2fso)7k~(7zfsB$e6HnCr?f&<@eed2$@+V|QZ}jxP-Tm)>KizbgXm6Aj^&OPs z32AfjYW7Ib-js=OJV-Sjn#0FKe-pI9a)pE{j0m6@BuKNVDkA;yeB_6cz{RITye}l9juyaLe8eGIh{4P&}I%a zInc)9@%Z}f9XH3~u`TQ3aiI~=65!+Vb+>QnxOvk}&JZpqgL%}3ExY2ejU-{?y6r5! zVe{6t9h>7@*RS6Z+Zo^4v6jzGIpaWbZ+E;qn-@jZ#^(;z2cN&pal8I^-h2~kf2W)##`mvmjbP?D)E&?D=Tmn^_R<8Pk zH9&k)??_4MAGArEP*B7ZJzcpj*2^DzR*Mj&`4cu@D20Y&o>Ovmt8^mT%*WEG*!lxC zOYt%Xd79 zIO>6#g02N~O)_ah=~BkU<9&nal#I>Wot*G;k=b;-zbn-rNA@ zDtjI+Cho;`5A9jJcPQR}R|yRXGHfY2ltwHb-<2caqZg#N&zy>u1n1+dFUQ@$4I zCWRu<*0qw#O{pd{B=-)LE%su3WZ)g&fi|u@8Gree5r*5XSbj`!>LHpG&(u77*>0Bbxv365KuB(q+ zeW`o|-EmJtvWE#*e;051k)8u7E>F^2MuzO;9da_Aaya5VERz@jpZqbzYbhey9ezgo zc;!Zf1|}l9(MTpOx}r#;pS}_OJsI02qsksz#!$ZzOC*pE$)nl53p*VCg zxUbT})f8$GzsraZIvU)j#;1mcQH>9}8{CUM_}20JSL5Sp@Ij~Z_arZ<@!{UWq>X6s zLDz#@SYxHUfd`rt%z^yG2OSXZ`P%$X{lwUOoYIAE2zNwF*Pt6FGJZpR&>7*zN~E4H zE-cqoP#oxzaKkROUJeYA3&gjUNgWgJ!<6o|8s7sXAL(GMg?o`l{r#cF2b~mdQ!8&J z@qR($gRTm9r6#YO?k{V67}Mik+vt>s>oJWFb6ebVHF+w3UtxB;!W;nidmemW*Z82T zz+G=&z=)56`86Z7$i>$gkGr%R!?nS{ilQ zD1I+*WzpuQmgd$*KH24b(P(o^l$ni_i@xwHj{&f0GO-vw0pDcdzopkA0C6FVbiz@s2`yXZ@Z^&tHzVc~A{9PRHpR5ATARw4 zwaHvf=np~_YW8c^?lV`LG##l<=IYJHnzm3yve&HM*RX~lALi=Sro?yDm^^NUoMBa0 zEs6A2)tizppNRA#<{=Z46~Sf;;ekUC(pba2t?1gJ&sB(8ftWhOk}MZrEx;A-I;Tx~Wv>&1C|^&Kf*3JBZX*eQxh8E=S+a)c_dW^dN^@)|P5bhcVB zM?34ys!Wx78ogA3j)Y2_ifyMD^-fXfUaD`9g%K%OiVo$=6Bns)Num{@t}5)R<9X#3 zU!enKOe~@cSvgZKuXBf(37gfVNvgg9|Le^gz*=wi4%MLc8ltjPwNj%{EqRvSky={A zlUaI4<5F1$h(u#m&)3Q+Jxkf*h;O00wOL1mi`tP~HB=u`nZ)Z@)CHeY>vf~Iv(oRs z?Ell3w2zs%|Btq`@;=}0|64`>-`YCe|6h*lGqKIe8L~oN;5ib04*nytQ-wpPSng^bFrGg(QdpoR+_+i@8vcm%_3;tD1vp4e3hHYie?cfxPm=ld_eZJ+OTpKYJ-6`yUN?;*ps&o}0??eoFr`Z?L>t2He9d_X2# zh<(0$4ck5+>fPHu-%6itpATGqC}&p zKHsl>nti@{pJtzLo=>yS2W*68pAQS}mVLf=e42f}RztJT2i>Y=pHCPoRQCB+`ZfD} zfH7G1`PTb2`+R;wv(I<4U$@WqBg3-Kx7iT(`MP|zeZF5AwtYSrpHlYuvc?73=fghK zkDO$-eLi9KknHne72Cr;AFQvDeLmo8$UYxz!jOHwCwwLC^TB=&+2?x$wrPYJKA<@? z`+Q$Bm}Z}^Q?M!feCS+C*ymdZ3ATMcSmn~}^Sui(Zu@+&3n}gMF*XJJd>`6vTeej!;? z*%#v6;-c?dnab7%DY?wtI)RJ;+TvMVlWSg)gp-iMBl3ED2DHroiKi`+=1*T24%a+kZ@A(wlm%YB8* zJ=^8J(&e7xa#ywKJkii8c|vk!XzQEkrwsK1}p6qE8Tgn&?TQ zKOp*3qVEw62PK_HbYW1o_eOHBA-b7pAJKh8?<4x>L?5U4;=L-9eH`2ie3F{z2MpPN zfZhWN<_U0pfWt{_od$nX06PRkygNvV*eeN#vqLTHob6SFlC$7;0#C>XHw|(SBI4M% zzP?O4Kg6bf0e7T-HL(VOJ{R9Z^)1A`K)&ME7agiteFmw1qJPFWwVmA0%#rvS$TOIY zCt5;r6qcmQIkd3k)iDkKGXY;C{WdhdtsZEL`&|r3b#d3WMl{i<&>jiBnVgbK{~G^K@VG;QJshr-hkI zb4`l>i8hJ#-=@Zv6^$*;tTEcu*xER~{(Ctt4b-Dr!c=fQ7F8XJ_LP#Gegx!S_Z$Q>iqatB6rw#KY8qkuEWT_@Foz23}f2nXRM&@@(NQXaXf zHdV?=@$7>Y{(K&B<8_`$^kKs zc)8+u5Y}B|M>5@U5|hWNvEzt}qOBV4iWEQ6M5RELjGQ1Un2nN?=;pakirgEb9UshWiGHXq- z?<#BN`V(efa$h24$`3@nDZ9+2{I}U9s^K z3F$Gr(?bV%;IfH7I&G6>%gm>8$pOt<*t3~hwq&@>m)xsnrh7%wUEMkU8l6ueCjD6P z5~(6>7ZS5(DxGS$JCRAFH-vaA2WB!W@S;g0$T#Aerf4$l+LjH2;I}@q%$Y5@w4CXFk2C;WAk;R6)^T=glqFg5IT&irY z=U=KUHJn^`KiVPBhMvn5PguQXiAZ0>X5<-5q_PvW=WGIt8yZ8J7`ie!ArLxQ@Y?BB zi!_#2^RJO!ctqnFt4E{Hdd8@s7*s9v(MtEKsLnFk`Lycj90nrxW8ReN&Lp4{$*L6X zm%c=Tc<=zQiBG@D2P-fLmW43Arx@fVPiCEMz+JuhtlnAhk3HImjL8|G-iCQQK4Q$J zhqClA&@wXAHglQ0E`SPvG%WZ#PbH~}Xv$%Ql%s0yVvJ;Xb>e_}p0j1k93O)Z`lB^{ zU9`&@|6M`|_$2u6X!D9jiT`eDYFXa6LX7`bOyj>V%QYGPdnM`I6#n~KHqXL;gF;{C zfdfBO&hljfNqlCxKpR_-@WL@4_s}rRV*#cVq7h{`TQr<-`2<$=Oe_m9f!$c=l7VabEbtvGFseBkXj(@}5KE zELSHuPJ^Ss12vx6-?p&cJYTuLKI1#egFNyQs~l#$M$c4<$YUb%Dl<1*cUI&V7x-_@ zi;Kr2;T1l9lGi;?;h0DPPvJ=A(G$mq1B;IX1pWz2yB-h?PMj3FjM`p=^sk1mT&&I- zW$!S7{{FEf*ZTw@JI7sqahRV%enYRXkl$Eew~*iW2vYW}h#$nkiPlMzX#Vn~NkF&h zq)9AZI?nc;fmNbaFZiZ-wl9vYKlihJ#ZrJc+ZT(X=XkcSIFNC&vwcIpshsWmI-APb zzA&Oy>TKT~$c#AK7t1A6INP@p5$v;lJK+>(`!eQvwy)r~&-R@@-f4p4oxCuf5p9X% zl3Jz5{|}c{`il(z(jaj*5K&pVQ4ln56W*%cT0XzJ0t-JIJe@^SBt#IS;^D6zf`K`Vec6g5n7wd@hu~Y9P{H}HRxi5WeR*b>( zGpGAPF?SU%w;OX8cDZM{+-^*r8*_J+%k9SK`CM+pN>SS9Qx<~dHOD9ym;iMl^$wSN zqszV3<-V2K?F#buxWe%)RhvTifFu1fh8m246l)`Hs{-kMJr*t%iG2m1_2l@SQf;sZbIPg<`CWv2YPZE;4g9uleoK0 zOyb%05MM9xeU8Gv#3X(W`y!3&7<-1oe?;!L$SuA`{IewnPuEGD9sF@{Jp4Pze?9qs zgZy74|L>Fk#m3LABf5#`twi?{O%vTm^bpbei9Sg5FNr=$^eM{6n<{^VOH;Tcg@?O~ z+>a1FPV`M3&xTEMgfCk_w8oJB?c{djpE{X0{;8knVWM9p`tL+f6BR?=pv3i^7hb9q zPKvk2-*ybu512QG3T+V9$Q6dl&9_S9o5MQf(N%H)xG}bCJMXXgR zK83YX7^+MO4Ao{A-@X!j1KMv~cLTfSQQm%6dEW@jZ|T+KugbgMCGP|exZVTvbia%5 zr$KM5)#qL5j$I+&E2JCN(tX4wZ^jIXCw9yGl1pA-mfa3!Y4Q{{O6kac$>sIB%7Ocz zTztFBy|GpbL#3|$&Y^%6_A+zgqrg|KMO4r5MOQh(v*foI&1%z;oD-*3$`}?&mI7_~nPUx5GfO41Ep`c-P7}-@bcSsMT^E3F zn!YB!=&iq`X-v}pH@3?DzXe#Z6)U2m|6krb-Tz;X%ff%{?6~O@4)B-q(Cq%HZS+(8 zMzl@z31~Z)?!E1NyYaRQ?U38fziR}1f+|zR24^3l*PHumOo6*_3r2_occGrcrFs7H z{r^DizeNG|cdq|On|YTo{r+EuYqItKW2Dkm>;KpA8JyBTV0~U+FD@UxtsMW`!y_B9 zBz)xK;b%`7BXj-3vG5V&=x*0~I#{<^5yttCBOAlg$)ovB4!alNWmp{-_8l;93m=_8 zB4-P7|BvaS3Zs>7X*b5g83Gi{lfVI58!tZ+J3Gw(+5;zwqwXpn-X6YjS2z=R?H%uU zuOS|mx)=EEWo~Si61L9%j;eSeQNvd*tdSXIumf)d$~qtvfUdxMcFGw}na z%$^e24g_9d(v;Z}&Oh@FA558j4b2Fq%>KW1VtUFRV;>(gblFSh6K?mRT@9A5l5{37>7ZmjO~oz)OM7PPFs{#t94pr z7?tTCWfUEhjAevYoK~mzcka3GD{qsad}w`lCOPlid+zsr_q~1R+~0vnNmQ{BQHD<{ zC8fjy%4{3h1oZKy2;)<4NjW|Mhv9)P5&Xfxh{ z_%fgyMdJr?O^u7kU&nRg1p^RVz`2T)BR&(y@#{!(vj9NZUvZs6o6blmfHIU1fHLU( zBW5)<24NBt#OP+KjXJ8KkXFE+a95pW9%j zRtaNV1Eq9}avb9~Mz@620rUncp~Wg;w5x>CjuO76ONf{_xnBV&dLxZUD7Ge1IgeW9 zq+R8txg3#(@qv-RqNLB@8+QXC4Tw((oq>*ZCv=7iV1XG?=q~^fRzsOS(wU;1No4R* z&7dzawIo8xVNR};%@5ztC4O;Hq})hR<%6j3lWuc>l-nG@S2NFA`}9DI15T-QTO4G3 z1%$cKwwbOSx9u8J|w@Syi?fu+`F9z<8SLg4=-8o*JzgMU4#pN-q8kLX7kV_&R zinwrfPV7kK#F(ency`c6F`X$1nu`vKiu{))&Vh&EWh>;YTf z#)JCK#%zRSCorn93Z-KP-@tr3^UIlE$NYNcpJx79=7G5y$|%1qi2oPICk+*^b-knm zkFgFs#yaqrM+aWYI`A0lz+y z@-g$kzXd&qX%*|#8<=lm+QGD&(|eiUz;rXy$2t84=3is_caA^C{HM&*JVtDt{k_6p zXTOB$T}-z!{UcM@BtchyLUr_C0zLd6gufoXQrMUd#js4AFH`!`t6whwkB7?}49nzZ zj{;J&Uj2G8Ij?>la(;UAd5&uYAm@$?50snZ>Bs&u<$D_a7~$y0LQi>jnF{C1TVCEH zx2uTWyu(xPFIjJndSi}y*Luo(yF~fd@|L&8Q{HbA_WU~a@au(JAO4V>=p&wf;O}Q1 zxx0(#%^&l$Z%Yxq`P0I!>)skwd$taG4xjS$V`oA=r_c|r5BJlXKU}JO$l+ZnDT?dO z%`)M#S<~(F>dlYIdSCRB3&Q_b(B61XW*tN6f9mRLwf~Q4_!eAUQ*&WWaQ^F*1Y7@e z#hj*DZUvBz@%QM&he_FQErX;i?rE!X{YcENXkP91VAR&xwW7JZDm!J$6id6J90&WJ z?wvHLHNT|L-KCu#HFtOB+^TH%F;%P8r+Z|-9Kqqz`=o^-?*FN^)pbh$TU$S^zIrO1 z|Evw{e@;oTmAm%WyL0?izVrIp5Vlq zQrG$H^lUK{DHPkm=tK&TD6c?zsv8`bJJsU}mZ&P*;fGB$e&NFL4%{IbjnY+8UZM4r z=5Ojy08n{y0>-F4PA_v>1f^PVM0P$Wa8%x7$7J~{pWra4smiLYls-vXW;v@YJS14$ zIOHvyt=#Rca_7|v6ER4uCeOf!Ivys;(I;7(wcP8mcRec>wmLBX!j;30r%3Zxx|{Eu z=u_GWg{|-GL_t*}FO@&G>^HI#^e5Db_R>?W%w9r84$;{*cV{&K12xKFIRJ2olhkjb z-o68o-P?1tVdxIE7N0#JrJSnC119}|sk7$Ff(W7}c{_!Bzq{+UMY?Lzpqfi<7nzzxr38jHN%hGKb(ix(-SN<%CYjV(mCYel zMNg#d(X(|?RWsBrl#_SLWUEZa__OIt(e>mS{Z&PWeo1RfPBvVRC*_rkBDchv1basO zCd8V8C7sru&tpm=Q=GfLu55)B2E)Io+!tJ6Kf@;Kg~#nG3Unx6+J`as^lFbvc-AHFobgzxh* z^+ak)TUToOr#Qz!`@~i))MmX6OFEx@1?9erR^AGnm zMir#g!k%$`jfdCIGpv|=PZ>dY^#j5y*4ud4I5bk{=$m`AZ+^e=ij-RyLXv``vWmNF zXU`TpvyjvQEoQnfz(h}4HnSso-!8kQFeXkulj?oz({(9*`H6kGtM`>Car+wM`))8{ zQhZ`dH`k?l*ThA4nnpBkWqsjL2`oSa*+F~i&A9Ny*3CaUjM|gWG#>5UZ;)Yi?_0+D zcv>~4^c7cgQpEMmPYtNl^rEz-sJ`RrYj$1A+soqJbJP?g^X>QkNec?zhxNMZYm8(0 zOztU@@$krv^+CD&MBm)Qa&WM2(#hZNG4{yCvO^?y>^u*e)4O--LLWgTSa9Yr^7ihJ z%ABwFH6DHb;MvJ%cFKj`yXL64&Fo!qSgz*7-ur;Mm%?J5+Yf-c=h0Dl@0izJYY8Dr z{yR*o7p2`XLUJGNJ`|S3F)HU48I@1esG#>RHXf0e{jQOb-RhUO3sq0|+LWFQYFQnD z^r6}EegOnrmDTh9BBK_?sCA!l=iDQPr$~7RZaQQ59}vBBt`UcJnyVk063 zqkFTISTiKb00&?u&`48+VH9tc{{`dlL!teLo2gkcIsuDvBe4bbCAuinS+v`im@v#PbQWrz835iQ(`2?o75#E{87r_Rr=}Ko^OK$^C@OX{7 zSSX7}3|xu_PJFHd0ZuGG=ShI5^CUp2^CUpb?<7E(`y@bopg-w^_9tC#8t#-NrIcu} zKK}y)6>j7HwEO%(r5h12<33I>vMA8ss4@eb@IMr=#bGGch?!JKMMED7aQkF-tBePQ z|8sv`Vzr@a7kf^Q!*lXGJsaMMj@`bL@cV9$&L+gZA4I~X2ewbYDO%Ys)3(2{!M>z) zAOMD36-0HAV>umvm>GNGtaeO z7440_{IXqccZ74y>3MX{JMC9h_sVQnN3T4WunVtxGIU<%jp?Bh>$t+Art4es-CfIt zr5zGvK}jxiPw*iI=)1Fka>U^(_j-l) zB`-*?z=szkyRy*S(n?;6iydWf9bQo9796X^eQd$`ok7qi>d$_Xf!bPF+FTUt(EbJj z+2x(Ls*BZX0Ql3qu)eBTS8YDW9;|Oe*44^k9fiP@bx|L13Id;05Yu1hE}0d!4D7k}BhDqW*p}Jtc*Hto!sP}D zLFTCAf$x$zQ_1*YB_giM6Xy-i-?m?6{6wq=;0=y)qys;(%E6=dSsuR0!_O1;+Cq6Z zy2=|tHqm-rAsy!e^cn&WJ9WKYz(3$AALj-1T0#0&Px`MtJYG2Ux`F(kJn64`c<26P z@7}|(Fd~|J&ix$z7bJ5~O4CzP+j*cx&Dcb}TZ0M2~rx91EC0v$gq8gLVI_YctmLMfEN3dY0%%tL@RT$p z7xIt5kNx7~KEA|sFVnY~e#jJWVxZ+r&tN)|rmLCW!So)c z>zO{x^bw|;nLf_+H%xzLsPTJ~`FEKfWjcm&Cdc#Hm3ro{V0s(VUQXY{{C1{0IDQZF z`&sk;;&@>TTGid{z0Z*{L5aZS>ca=c|X%%G2P4b7*oQ%EK&0k z;9t7KVEC7##fibcbpEcU-+Ek@#0_Zm4lWI4UK>KV;On5BSK$#@h{&j9VY%|W_b9Q$7H4^pLz%2Uyd9e z{^d-0pMTSFAclX;4#2;>H!(c?%dH9F3Odb;e+juu9T|(_Uyd9e{^kC1HE%=VUn21} zpY{#FzZ@ChUj`uvK?p(+f)Iot1R)4P2tp8o5QHEEAqYVTLJ)%RRSW+EMWlNY0DuAj DL`mvE literal 0 HcmV?d00001 diff --git a/ops.c b/ops.c index 5267b6f..0d6b292 100644 --- a/ops.c +++ b/ops.c @@ -1,117 +1,197 @@ #include "ops.h" +#include #include -void iop_add(variable *, variable *, variable *); -void iop_sub(variable *, variable *, variable *); -void iop_mult(variable *, variable *, variable *); -void iop_div(variable *, variable *, variable *); -void iop_and(variable *, variable *, variable *); -void iop_or(variable *, variable *, variable *); -void iop_xor(variable *, variable *, variable *); -void iop_shr(variable *, variable *, variable *); -void iop_shl(variable *, variable *, variable *); -void iop_eq(variable *, variable *, variable *); -void iop_lt(variable *, variable *, variable *); -void iop_gt(variable *, variable *, variable *); -void iop_lte(variable *, variable *, variable *); -void iop_gte(variable *, variable *, variable *); -void iop_ne(variable *, variable *, variable *); -void iop_mod(variable *, variable *, variable *); - -char *iops[IOPS_COUNT] = { - "*", "/", "%", "+", "-", "<<", ">>", "<=", - "<", ">=", ">", "==", "!=", "&", "^", "|" +#define OP_DEF(o) int op_##o(variable *r, variable *a, variable *b) +#define OP_VAR(o) {0, OPERATOR, 0, {.p = (uint32_t)op_##o}} +#define OP_NONE {0, OPERATOR, 0, {.p = 0x0BADCAFE}} + +extern char *strclone(const char *s); + +OP_DEF(mul); +OP_DEF(div); +OP_DEF(mod); +OP_DEF(add); +OP_DEF(sub); +OP_DEF(shl); +OP_DEF(shr); +OP_DEF(lte); +OP_DEF(lt); +OP_DEF(gte); +OP_DEF(gt); +OP_DEF(eq); +OP_DEF(ne); +OP_DEF(and); +OP_DEF(xor); +OP_DEF(or); +OP_DEF(set); + +variable opvars[] = { + OP_VAR(mul), OP_VAR(div), OP_VAR(mod), OP_NONE, + OP_VAR(add), OP_VAR(sub), OP_VAR(shl), OP_VAR(shr), + OP_VAR(lte), OP_VAR(lt), OP_VAR(gte), OP_VAR(gt), + OP_VAR(eq), OP_VAR(ne), OP_VAR(and), OP_VAR(xor), + OP_VAR(or), OP_VAR(set) }; -operation_t iopfuncs[IOPS_COUNT] = { - iop_mult, iop_div, iop_mod, iop_add, iop_sub, - iop_shl, iop_shr, iop_lte, iop_lt, iop_gte, - iop_gt, iop_eq, iop_ne, iop_and, iop_xor, - iop_or +const char *opnames[] = { + "*", "/", "%", 0, + "+", "-", "<<", ">>", + "<=", "<", ">=", ">", + "==", "!=", "&", "^", + "|", "=" }; - -void iop_add(variable *r, variable *a, variable *b) -{ - r->value.f = a->value.f + b->value.f; -} - -void iop_sub(variable *r, variable *a, variable *b) -{ - r->value.f = a->value.f - b->value.f; -} - -void iop_mult(variable *r, variable *a, variable *b) +OP_DEF(mul) { + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; r->value.f = a->value.f * b->value.f; + return 0; } - -void iop_div(variable *r, variable *a, variable *b) +OP_DEF(div) { + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; r->value.f = a->value.f / b->value.f; + return 0; } - -void iop_and(variable *r, variable *a, variable *b) +OP_DEF(mod) { - r->value.f = (float)((int)a->value.f & (int)b->value.f); + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = (int)a->value.f % (int)b->value.f; + return 0; } - -void iop_or(variable *r, variable *a, variable *b) +OP_DEF(add) { - r->value.f = (float)((int)a->value.f | (int)b->value.f); + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = a->value.f + b->value.f; + return 0; } - -void iop_xor(variable *r, variable *a, variable *b) +OP_DEF(sub) { - r->value.f = (float)((int)a->value.f ^ (int)b->value.f); + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = a->value.f - b->value.f; + return 0; } - -void iop_shr(variable *r, variable *a, variable *b) +OP_DEF(shl) { - r->value.f = (float)((int)a->value.f >> (int)b->value.f); + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = (int)a->value.f << (int)b->value.f; + return 0; } - -void iop_shl(variable *r, variable *a, variable *b) +OP_DEF(shr) { - r->value.f = (float)((int)a->value.f << (int)b->value.f); + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = (int)a->value.f >> (int)b->value.f; + return 0; } - -void iop_eq(variable *r, variable *a, variable *b) +OP_DEF(lte) { - if (a->valtype == STRING && b->valtype == STRING) - r->value.f = (float)!strcmp((char *)a->value.p, (char *)b->value.p); - else - r->value.f = a->value.f == b->value.f; + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = a->value.f <= b->value.f; + return 0; } - -void iop_lt(variable *r, variable *a, variable *b) +OP_DEF(lt) { + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; r->value.f = a->value.f < b->value.f; + return 0; } - -void iop_gt(variable *r, variable *a, variable *b) +OP_DEF(gte) { - r->value.f = a->value.f > b->value.f; + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = a->value.f >= b->value.f; + return 0; } - -void iop_lte(variable *r, variable *a, variable *b) +OP_DEF(gt) { - r->value.f = a->value.f <= b->value.f; + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = a->value.f > b->value.f; + return 0; } - -void iop_gte(variable *r, variable *a, variable *b) +OP_DEF(eq) { - r->value.f = a->value.f >= b->value.f; -} + r->type = NUMBER; + if (a->type == NUMBER && b->type == NUMBER) + r->value.f = a->value.f == b->value.f; + else if (a->type == STRING && b->type == STRING) + r->value.f = !strcmp((const char *)a->value.p, (const char *)b->value.p); + else + return -1; -void iop_ne(variable *r, variable *a, variable *b) -{ - r->value.f = a->value.f != b->value.f; + return 0; } - -void iop_mod(variable *r, variable *a, variable *b) +OP_DEF(ne) { - r->value.f = (float)((int)a->value.f % (int)b->value.f); + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = a->value.f != b->value.f; + return 0; +} +OP_DEF(and) +{ + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = (int)a->value.f & (int)b->value.f; + return 0; +} +OP_DEF(xor) +{ + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = (int)a->value.f ^ (int)b->value.f; + return 0; +} +OP_DEF(or) +{ + if (a->type != NUMBER || b->type != NUMBER) + return -1; + r->type = NUMBER; + r->value.f = (int)a->value.f | (int)b->value.f; + return 0; +} +OP_DEF(set) +{ + if (b->type == NUMBER) { + a->type = NUMBER; + a->value.f = b->value.f; + r->type = NUMBER; + r->value.f = a->value.f; + } else if (b->type == STRING) { + a->type = STRING; + if (a->value.p != 0) + free((void *)a->value.p); + a->value.p = (uint32_t)strclone((char *)b->value.p); + r->type = STRING; + r->value.p = (uint32_t)strclone((char *)a->value.p); + } else { + return -1; + } + return 0; } diff --git a/ops.h b/ops.h index 5c7832f..8296cbe 100644 --- a/ops.h +++ b/ops.h @@ -1,13 +1,14 @@ #ifndef OPS_H_ #define OPS_H_ -#include "parser.h" +#include "variable.h" -#define IOPS_COUNT 16 +#define OPS_COUNT 18 +#define OP_MAGIC 0xCAFE3900 -typedef void (*operation_t)(variable *, variable *, variable *); +typedef int (*opfunc_t)(variable *, variable *, variable *); -extern char *iops[IOPS_COUNT]; -extern operation_t iopfuncs[IOPS_COUNT]; +extern variable opvars[]; +extern const char *opnames[]; #endif // OPS_H_ diff --git a/parser.c b/parser.c index 886d27b..a2ab8d5 100644 --- a/parser.c +++ b/parser.c @@ -1,478 +1,486 @@ -#include +#include "parser.h" -#include "shelpers.h" #include "builtins.h" -#include "stack.h" #include "ops.h" #include #include -#include +#include #include -#define MAX_VARS 100 -#define MAX_STACK 32 +#define MAX_VARS 256 +#define MAX_STACK 64 #define MAX_LINES 1000 -void iinit(interpreter *interp) +char *strnclone(const char *s, size_t c) { - interp->vars = (variable *)calloc(MAX_VARS, sizeof(variable)); - interp->vnames = (char **)calloc(MAX_VARS, sizeof(char *)); - interp->stack = (stack_t *)calloc(MAX_STACK, sizeof(stack_t)); - interp->stidx = 0; - interp->lines = (variable ***)calloc(MAX_LINES, sizeof(variable **)); - interp->lnidx = 0; - interp->indent = 0; - interp->sindent = 0; - interp->ret = 0; - - iload_core(interp); + char *b = strncpy((char *)malloc(c + 1), s, c); + b[c] = '\0'; + return b; } - -void iend(interpreter *it) +char *strclone(const char *s) { - for (unsigned int i = 0; i < MAX_VARS; i++) { - if (it->vars[i].used == 1) { - if (it->vars[i].valtype == STRING || - it->vars[i].valtype == EXPR) - free((void *)it->vars[i].value.p); - free(it->vnames[i]); - } - } - for (unsigned int i = 0; i < MAX_LINES; i++) { - if (it->lines[i] != 0) { - for (unsigned int j = 0; (int32_t)it->lines[i][j] > 0; j++) { - switch (it->lines[i][j]->valtype) { - case STRING: - if (!it->lines[i][j]->used) - free(it->lines[i][j]); - break; - case EXPR: - free((void *)it->lines[i][j]->value.p); - free(it->lines[i][j]); - break; - case NUMBER: - if (!it->lines[i][j]->used) - free(it->lines[i][j]); - break; - } - } + return strnclone(s, strlen(s)); +} +char *fixstring(const char *s) +{ + char *n = malloc(strlen(s) + 1 - 2); + int j = 0; + for (int i = 1; s[i] != '\"'; i++, j++) { + if (s[i] == '\\') { + if (s[i + 1] == 'n') + n[j] = '\n'; + i++; + } else { + n[j] = s[i]; } - free(it->lines[i]); } + n[j] = '\0'; + return n; +} + +void itryfree(variable *v) +{ + if (v == 0 || v->tmp == 0) + return; + if (v->type == STRING) + free((void *)v->value.p); + free(v); +} + +instance *inewinstance(void) +{ + instance *it = (instance *)malloc(sizeof(instance)); + it->vars = (variable *)calloc(MAX_VARS, sizeof(variable)); + it->names = (char **)calloc(MAX_VARS, sizeof(char *)); + it->stack = (uint32_t *)malloc(MAX_STACK * sizeof(uint32_t)); + it->stidx = 0; + it->lines = (char **)calloc(MAX_LINES, sizeof(char *)); + it->lnidx = 0; + it->ret = 0; + it->indent = 0; + it->sindent = 0; + + iload_builtins(it); + return it; +} + +void idelinstance(instance *it) +{ free(it->vars); - free(it->vnames); + for (uint32_t i = 0; i < MAX_VARS; i++) + free(it->names[i]); + free(it->names); free(it->stack); + for (uint32_t i = 0; i < MAX_VARS; i++) + free(it->lines[i]); free(it->lines); + itryfree(it->ret); + free(it); } -void iskip(interpreter *it) +void ipush(instance *it, uint32_t v) { - if (!(it->sindent & SKIP)) - it->sindent = it->indent | SKIP; + it->stack[it->stidx++] = v; } -variable *interpreter_get_variable(interpreter *interp, const char *name) +uint32_t ipop(instance *it) { - for (uint32_t i = 0; i < MAX_VARS; i++) { - if (!interp->vars[i].used) { - variable *v = make_vars(&interp->vars[i], 0); - v->used = 1; - interp->vnames[i] = strclone(name); - return v; - } else if (interp->vnames[i] != 0 && !strcmp(interp->vnames[i], name)) { - return &interp->vars[i]; - } - } - return 0; + return it->stack[--it->stidx]; } -char *interpreter_get_name(interpreter *interp, variable *v) +void ipopm(instance *it, uint32_t count) { - for (uint32_t i = 0; i < MAX_VARS; i++) { - if (v == &interp->vars[i]) - return interp->vnames[i]; - } - return "(undefined)"; + it->stidx -= count; } -variable *inew_string(interpreter *interp, const char *name, const char *value) +variable *igetarg(instance *it, uint32_t n) { - variable *v = interpreter_get_variable(interp, name); - if (v != 0) { - if (v->valtype == STRING && v->value.p != 0) - free((void *)v->value.p); - v->valtype = STRING; - v->value.p = (uint32_t)strclone(value); - } - return v; + return (variable *)it->stack[it->stidx - n - 1]; } -variable *inew_number(interpreter *interp, const char *name, float value) +variable *igetvar(instance *it, const char *name); +void inew_cfunc(instance *it, const char *name, func_t func) { - variable *v = interpreter_get_variable(interp, name); - if (v != 0) { - v->valtype = NUMBER; - v->value.f = value; - } + variable *v = igetvar(it, name); + v->type = CFUNC; + v->value.p = (uint32_t)func; +} + +void inew_number(instance *it, const char *name, float f) +{ + variable *v = igetvar(it, name); + v->type = NUMBER; + v->value.f = f; +} + +void inew_string(instance *it, const char *name, const char *s) +{ + variable *v = igetvar(it, name); + v->type = STRING; + v->value.p = (uint32_t)strclone(s); +} + +variable *varclone(variable *n) +{ + variable *v = (variable *)malloc(sizeof(variable)); + v->tmp = 1; + v->type = n->type; + if (n->type == STRING) + v->value.p = (uint32_t)strclone((char *)n->value.p); + else + v->value.p = n->value.p; return v; } -variable *inew_cfunc(interpreter *interp, const char *name, func_t func) +variable *make_varf(variable *v, float f) { - variable *v = interpreter_get_variable(interp, name); - if (v != 0) { - v->fromc = 1; - v->valtype = FUNC; - v->value.p = (uint32_t)func; + if (v == 0) { + v = (variable *)malloc(sizeof(variable)); + v->tmp = 1; } + v->type = NUMBER; + v->value.f = f; return v; } -variable *make_var(interpreter *interp, const char *line, uint32_t *next) +variable *make_vars(variable *v, const char *s) { - if (line[0] == '\"') { // string literal - uint32_t end = 1; - while (!eol(line[end])) { - if (line[end] == '\"'/* && line[end - 1] != '\\'*/) { - if (!eot(line[end + 1])) - return 0; - // TODO string breakdown - *next = end + 1; - char *str = strnclone(line + 1, end - 1); - variable *v = make_vars(0, str); - free(str); - return v; - } - end++; - } - return 0; - } else if (line[0] == '(') { // equation literal - uint32_t end = findend(line, '(', ')'); - if (eot(line[end])) - return 0; - *next = end + 1; - char *expr = strnclone(line + 1, end); - variable *v = make_vare(0, expr); - free(expr); - return v; - } else { - variable *v = make_varn(0, 0.0f); - int inc = try_number(v, line); - if (inc != 0) { - *next = inc; - return v; - } - free(v); - char *name = 0; - inc = try_variable(&name, line); - if (inc != 0) { - *next = (inc > 0) ? inc : -inc; - variable *v = interpreter_get_variable(interp, name); - free(name); - return v; - } + if (v == 0) { + v = (variable *)malloc(sizeof(variable)); + v->tmp = 1; } - return 0; + v->type = STRING; + v->value.p = (uint32_t)strclone(s); + return v; } -int idoline(interpreter *interp, const char *line) +variable *make_num(const char *text) { - uint32_t ooffset = 0, offset = 0, next; - int fret = 0; - - if (line[0] == '\0') - return 0; - skipblank(line, eol, &offset); - if (line[offset] == '#' || eol(line[offset])) - return 0; - - variable **linebuf = (variable **)calloc(8, sizeof(variable *)); - interp->lines[interp->lnidx] = linebuf; - variable **ops = interp->lines[interp->lnidx]; - - // step 1 - convert to tokens - while (!eol(line[offset])) { - if (offset > 0 && line[offset] == '>') { - offset++; - skipblank(line, eol, &offset); - variable *r = make_var(interp, line + offset, &next); - ops[ooffset] = (void *)-1; - ops[ooffset + 1] = r; - offset += next; - skipblank(line, eol, &offset); - continue; - } - variable *v = make_var(interp, line + offset, &next); - ops[ooffset] = v; - if (ops[ooffset] == 0) { - fret = -4; - goto fail; + int decimal = -1; + char valid = 0; + + int i = 0; + if (text[0] == '-') + i++; + do { + if (text[i] == '.') { + if (decimal >= 0) { + valid = 0; + break; + } + decimal = i; + } else if (isdigit(text[i])) { + valid |= 1; } else { - ooffset++; - offset += next; + break; } - skipblank(line, eol, &offset); - } + } while (text[++i] != '\0'); - // step 2 - execute - if (ooffset == 0) { - fret = -1; - goto fail; - } - - if (ops[0]->valtype != FUNC) { - fret = -2; - goto fail; - } + if (valid == 0) + return 0; - if (ops[0]->fromc && ops[0]->value.p == 0) { - fret = -3; - goto fail; - } + char *buf = (char *)malloc(i + 1); + strncpy(buf, text, i); + buf[i] = '\0'; - if (ops[ooffset] != (void *)-1) - ops[ooffset] = 0; + variable *v = make_varf(0, strtof(buf, 0)); + free(buf); + return v; +} -loop: - for (uint8_t i = 0; i < IUP_COUNT; i++) { - if (interp->lines[interp->lnidx][0]->value.p - == (uint32_t)indent_up[i]) { - interp->indent++; - goto cont; +variable *igetop(instance *it, const char *name) +{ + for (uint32_t i = 0; i < OPS_COUNT; i++) { + if (opnames[i] != 0 && !strcmp(name, opnames[i])) { + return &opvars[i]; } } - for (uint8_t i = 0; i < IDOWN_COUNT; i++) { - if (interp->lines[interp->lnidx][0]->value.p - == (uint32_t)indent_down[i]) { - if (--interp->indent < 0) { - fret = -6; - goto fail; + return 0; +} +variable *igetvar(instance *it, const char *name) +{ + if (isalpha(name[0])) { + for (uint32_t i = 0; i < MAX_VARS; i++) { + if (it->names[i] == 0) { + it->names[i] = strclone(name); + // default to 0 float + return make_varf(&it->vars[i], 0.0f); + } else if (!strcmp(name, it->names[i])) { + return &it->vars[i]; } - if (interp->indent < (interp->sindent & ~(SKIP))) - interp->sindent &= ~(SKIP); - else - goto cont; - break; } } -cont: - if (interp->indent > 0 && interp->sindent & SKIP) - goto norun; - - ops = (variable **)malloc(8 * sizeof(variable *)); - for (uint8_t i = 0; i < 8; i++) - ops[i] = interp->lines[interp->lnidx][i]; - uint32_t oldLnidx = interp->lnidx; - - // eval expressions - ooffset = 1; - for (; ops[ooffset] != 0 && ops[ooffset] != (void *)-1; ooffset++) { - if (ops[ooffset]->valtype == EXPR) { - char *expr = strclone((char *)ops[ooffset]->value.p); - variable *r = idoexpr(interp, expr); - ops[ooffset] = r; - free(expr); - } - } + return igetop(it, name); +} - if (ops[ooffset] == (void *)-1) - interp->ret = ops[ooffset + 1]; - - if (ops[0]->fromc) { - for (uint32_t i = ooffset; --i > 0;) - ipush(interp, ops[i]); - - int ret = ((func_t)ops[0]->value.p)(interp); - if (ret != 0) - return ret; - ipopm(interp, ooffset - 1); - } else { - char an[6]; - for (uint32_t i = 1; i < ooffset; i++) { - snprintf(an, 6, "arg%d", (int)(i - 1)); - switch (ops[i]->valtype) { - case STRING: - inew_string(interp, an, (char *)ops[i]->value.p); - break; - case NUMBER: - inew_number(interp, an, ops[i]->value.f); - break; - default: - break; - } - } +int idoline(instance *it, const char *s) +{ + it->lines[it->lnidx] = strclone(s); + variable **ops; +loop: + ops = iparse(it, it->lines[it->lnidx]); - ipush(interp, (void *)(uint32_t)interp->indent); - ipush(interp, (void *)interp->lnidx); - ipush(interp, (void *)-2); // magic - interp->lnidx = ops[0]->value.p; - interp->indent++; - } + if (it->ret != 0) + itryfree(it->ret); + it->ret = 0; - if ((int32_t)interp->stidx < 0) { - interp->stidx = 0; - return -5; - } + if (ops == 0) + goto next; + it->ret = isolve(it, ops, 0); - for (uint32_t i = 1; i < ooffset; i++) { - if (ops[i] != interp->lines[oldLnidx][i]) { - if (ops[i]->valtype == STRING || ops[i]->valtype == EXPR) - free((void *)ops[i]->value.p); - free(ops[i]); - } - } +next: free(ops); -norun: - interp->lnidx++; - if (interp->lines[interp->lnidx] != 0) + it->lnidx++; + if (it->lines[it->lnidx] != 0) goto loop; return 0; +} + +variable *isolve_(instance *it, variable **ops, uint32_t count); +variable *isolve(instance *it, variable **ops, uint32_t count) +{ + if (count == 0) + for (count = 0; ops[count] != 0; count++); + + for (uint32_t i = 0; i < count; i++) { + if (((uint32_t)ops[i] & OP_MAGIC) == OP_MAGIC) { + uint32_t count_ = (uint32_t)ops[i] & 0xFF; + ops[i] = isolve(it, ops + i + 1, count_); + for (uint32_t j = 1; j <= count_; j++) + ops[i + j] = 0; + } + } -fail: - free(interp->lines[interp->lnidx]); - interp->lines[interp->lnidx] = 0; - return fret; + return isolve_(it, ops, count); } -variable *idoexpr(interpreter *interp, const char *line) +variable *isolve_(instance *it, variable **ops, uint32_t count) { - void *ops[16]; - uint32_t ooffset = 0; - uint32_t offset = 0; - - // step 1 - break apart line - for (uint8_t i = 0; i < 16; i++) - ops[i] = 0; - - // skip whitespace - skipblank(line, eol, &offset); - while (!eoe(line[offset])) { - if (line[offset] == '(') { - uint8_t indent = 0; - uint32_t i; - for (i = offset + 1; !eol(line[i]); i++) { - if (line[i] == '(') { - indent++; - } else if (line[i] == ')') { - if (indent == 0) { - break; + // first, look for functions + for (uint32_t i = 0; i < count; i++) { + if (ops[i] == 0) + continue; + if (ops[i]->type == CFUNC || ops[i]->type == FUNC) { + uint32_t nargs = (uint32_t)ops[i + 1]; + uint32_t start = i; + i += 2; + int32_t j; + for (j = nargs; j > 0 && i < count; i++) { + if (ops[i] != 0) { + if (ops[start]->type == CFUNC) { + it->stack[it->stidx + j - 1] = (uint32_t)ops[i]; } else { - indent--; - } + char namebuf[6]; + snprintf(namebuf, 6, "arg%d", nargs - j); + if (ops[i]->type == NUMBER) + inew_number(it, namebuf, ops[i]->value.f); + else + inew_string(it, namebuf, + (const char *)ops[i]->value.p); + } + j--; } } - if (eol(line[i])) + if (j != 0) return 0; - ops[ooffset] = idoexpr(interp, line + offset + 1); - offset = i + 1; - } else { - variable *v = make_varn(0, 0.0f); - int inc = try_number(v, line + offset); - if (inc != 0) { - ops[ooffset] = v; - offset += inc; - } else { - free(v); - char *name; - inc = try_variable(&name, line + offset); - if (inc != 0) { - v = interpreter_get_variable(interp, name); - ops[ooffset] = v; - free(name); - if (inc < 0) { - inc = -inc; - ops[ooffset + 2] = v; - ops[ooffset + 1] = (void *)5; // - - ops[ooffset] = make_varn(0, 0.0f); - ooffset += 2; - } - offset += inc; - } else { + + if (ops[start]->type == CFUNC) { + func_t func = (func_t)ops[start]->value.p; + it->stidx += nargs; + + uint32_t sidx = it->stidx; + int ret = 0; + if (!(it->sindent & SKIP)) + ret = func(it); + if (ret != 0) return 0; - } + if (it->stidx > sidx) + ops[start] = (variable *)ipop(it); + else + ops[start] = 0; + ipopm(it, nargs); + } else { + ipush(it, it->lnidx); + ipush(it, CALL_SIG); + it->lnidx = ops[start]->value.p; + } + + ops[start + 1] = 0; + for (uint32_t j = start + 2; j < i; j++) { + itryfree(ops[j]); + ops[j] = 0; } } + } - if (ops[ooffset] == 0) - return 0; - - ooffset++; + // next, operators + for (uint32_t j = 0; j < OPS_COUNT; j += 2) { + for (uint32_t i = 0; i < count; i++) { + if (ops[i] == 0) + continue; + if (ops[i]->type == OPERATOR) { + if (ops[i]->value.p != (uint32_t)opvars[j].value.p) { + if (ops[i]->value.p != (uint32_t)opvars[j + 1].value.p) + continue; + } - // skip whitespace - skipblank(line, eoe, &offset); - if (eoe(line[offset])) - break; + opfunc_t func = (opfunc_t)ops[i]->value.p; + uint32_t aidx = i - 1; + while (ops[aidx] == 0 && aidx != 0) + aidx--; + if (ops[aidx] == 0) + return 0; + uint32_t bidx = i + 1; + while (ops[bidx] == 0 && ++bidx < count); + if (bidx == count) + return 0; - for (uint32_t i = 0; i < IOPS_COUNT; i++) { - int len = strlen(iops[i]); - if (!strncmp(iops[i], line + offset, len)) { - ops[ooffset] = (void *)(i + 1); - offset += len; - break; + if (it->sindent & SKIP) { + itryfree(ops[aidx]); + itryfree(ops[bidx]); + ops[aidx] = 0; + } else { + variable *v = varclone(ops[aidx]); + if (func(v, ops[aidx], ops[bidx]) != 0) + return 0; + itryfree(ops[aidx]); + ops[aidx] = v; + itryfree(ops[bidx]); + } + ops[i] = 0; + ops[bidx] = 0; } } + } - if (ops[ooffset] == 0) // implicit multiply - ops[ooffset] = (void *)1; + return ops[0]; +} - ooffset++; - // skip whitespace - skipblank(line, eol, &offset); - } +variable **iparse(instance *it, const char *s) +{ + uint32_t ooffset = 0; + size_t offset = 0; - if (ooffset % 2 == 0) + while (isblank(s[offset])) + offset++; + if (s[offset] == '#' || s[offset] == '\0' || s[offset] == '\n') return 0; - // step 2 - do operations - // for every operator, ordered by importance - for (uint32_t i = 0; i < IOPS_COUNT; i++) { - // find instances of the operation - for (uint32_t j = 1; j < ooffset; j += 2) { - // if a match - if ((uint32_t)ops[j] == i + 1) { - // find args - uint32_t ai = j - 1; - uint32_t bi = j + 1; - while (ops[ai] == 0) - ai--; - while (ops[bi] == 0) - bi++; - - variable *r = (variable *)calloc(1, sizeof(variable)); - iopfuncs[i](r, ops[ai], ops[bi]); - - variable *v = (variable *)ops[ai]; - if (!v->used) - free(v); - ops[ai] = r; - v = (variable *)ops[bi]; - if (!v->used) - free(v); - ops[bi] = 0; - ops[j] = 0; + variable **ops = (variable **)calloc(32, sizeof(variable *)); + while (s[offset] != '\0' && s[offset] != '\n') { + if (isalpha(s[offset])) { + size_t end = offset + 1; + while (isalnum(s[end])) + end++; + char *name = strnclone(s + offset, end - offset); + ops[ooffset++] = igetvar(it, name); + free(name); + while (isblank(s[end])) + end++; + if (s[end] == '(') { + uint32_t argidx = ooffset; + uint32_t argcount = 0; + ooffset++; + end++; + for (int last = end, c = 0; c >= 0; end++) { + if (s[end] == '(') + c++; + if (c == 0 && last != end && (s[end] == ',' || s[end] == ')')) { + argcount++; + char *arg = strnclone(s + last, end - last); + uint32_t parenidx = ooffset; + ooffset++; + variable **moreops = iparse(it, arg); + uint32_t count = 0; + if (moreops != 0) { + for (uint32_t i = 0; moreops[i] != 0; count++, i++) + ops[ooffset++] = moreops[i]; + free(moreops); + } + free(arg); + ops[parenidx] = (variable *)(OP_MAGIC | count); + last = end + 1; + } + if (s[end] == ')') + c--; + } + if (s[end] != '\0') + end++; + ops[argidx] = (variable *)argcount; + } + offset = end; + } else if (isdigit(s[offset])) { + size_t end = offset + 1; + while (isdigit(s[end]) || s[end] == '.') + end++; + char *word = strnclone(s + offset, end - offset); + ops[ooffset++] = make_num(word); + free(word); + offset = end; + } else if (s[offset] == '\"') { + size_t end = offset + 1; + while (s[end] != '\"')// && s[end - 1] == '\\') + end++; + end++; + char *word = strnclone(s + offset, end - offset); + char *fword = fixstring(word); + ops[ooffset++] = make_vars(0, fword); + free(word); + free(fword); + offset = end; + } else if (s[offset] == '(') { + size_t i = offset + 1; + for (int c = 0; s[i] != ')' || --c >= 0; i++) { + if (s[i] == '(') + c++; } + i++; + char *word = strnclone(s + offset + 1, i - offset - 2); + uint32_t parenidx = ooffset; + ooffset++; + variable **moreops = iparse(it, word); + uint32_t count = 0; + if (moreops != 0) { + for (uint32_t i = 0; moreops[i] != 0; count++, i++) + ops[ooffset++] = moreops[i]; + free(moreops); + } + free(word); + ops[parenidx] = (variable *)(OP_MAGIC | count); + offset = i; + } else if (!isblank(s[offset])) { + size_t end = offset + 1; + while (!isblank(s[end]) && s[end] != '\0') + end++; + char *word = strnclone(s + offset, end - offset); + + // bracket? + if (!strcmp(word, "{")) { + it->indent++; + if (it->sindent & SKIP) + ipush(it, SKIP_SIG); + } else if (!strcmp(word, "}")) { + it->indent--; + if (it->indent < (it->sindent & ~(SKIP))) + it->sindent = 0; + bn_end(it); + } else { + variable *v = igetop(it, word); + if (v == 0) + return 0; + ops[ooffset++] = v; + } + free(word); + offset = end; + } else { + offset++; } } - variable *result = make_varn(0, ((variable *)ops[0])->value.f); - if (!((variable *)ops[0])->used) - free(ops[0]); - - //for (uint32_t i = 1; i < ooffset; i += 2) - // iopfuncs[(uint32_t)ops[i] - 1](result, result, ops[i + 1]); - - //for (uint32_t i = 0; i < ooffset; i += 2) { - // variable *v = (variable *)ops[i]; - // if (!v->used) { - // if (v->valtype == STRING || v->valtype == EXPR) - // free((void *)v->value.p); - // free(ops[i]); - // } - //} - - return result; + // mark end + ops[ooffset] = 0; + return ops; } - diff --git a/parser.h b/parser.h index 1b0fdd6..57763c8 100644 --- a/parser.h +++ b/parser.h @@ -1,36 +1,40 @@ #ifndef PARSER_H_ #define PARSER_H_ -#include +#include "variable.h" -typedef variable *stack_t; +#include typedef struct { variable *vars; - char **vnames; - stack_t *stack; + char **names; + uint32_t *stack; uint32_t stidx; - variable ***lines; + char **lines; uint32_t lnidx; - int8_t indent; - uint8_t sindent; variable *ret; -} interpreter; + uint8_t indent; + uint8_t sindent; +} instance; #define SKIP (1 << 7) -typedef int (*func_t)(interpreter *); +typedef int (*func_t)(instance *); + +instance *inewinstance(void); +void idelinstance(instance *it); -void iinit(interpreter *); -void iend(interpreter *); +int idoline(instance *it, const char *s); +variable **iparse(instance *it, const char *s); +variable *isolve(instance *it, variable **ops, uint32_t count); -void iskip(interpreter *); +void inew_cfunc(instance *it, const char *name, func_t func); -variable *inew_string(interpreter *, const char *, const char *); -variable *inew_number(interpreter *, const char *, float); -variable *inew_cfunc(interpreter *, const char *, func_t); +variable *make_varf(variable *v, float f); +variable *make_vars(variable *v, const char *s); -int idoline(interpreter *, const char *); -variable *idoexpr(interpreter *, const char *); +uint32_t ipop(instance *it); +void ipush(instance *it, uint32_t v); +variable *igetarg(instance *it, uint32_t n); #endif // PARSER_H_ diff --git a/script b/script deleted file mode 100644 index 35497fe..0000000 --- a/script +++ /dev/null @@ -1,7 +0,0 @@ -set x 42 -set eq ".a/a" - -solve eq > ans - -print ans -print "\n" diff --git a/shell.c b/shell.c index 8704db6..ade66b9 100644 --- a/shell.c +++ b/shell.c @@ -1,27 +1,24 @@ -#include -#include - -#include "stack.h" - -#include #include -//#include #include -int s_put(interpreter *it) +#include "parser.h" + +int print(instance *it) { - variable *v = igetarg(it, 0); - if (v->valtype == NUMBER) - printf("%.f", v->value.f); - else - printf("%s", (char *)v->value.p); + variable *s = igetarg(it, 0); + if (s->type == NUMBER) { + if (s->value.f == (int)s->value.f) + printf("%d\n", (int)s->value.f); + else + printf("%.3f\n", s->value.f); + } else if (s->value.p != 0) { + printf("%s\n", (char *)s->value.p); + } return 0; } int main(int argc, char **argv) { - interpreter interp; - if (argc != 2) { printf("Usage: %s file\n", argv[0]); return -1; @@ -33,20 +30,23 @@ int main(int argc, char **argv) return -1; } - iinit(&interp); - inew_cfunc(&interp, "print", s_put); + instance *it = inewinstance(); + inew_cfunc(it, "print", print); char *line = 0; - unsigned int size; + size_t size; int result; while (getline(&line, &size, fp) != -1) { *strchr(line, '\n') = '\0'; - result = idoline(&interp, line); + result = idoline(it, line); if (result != 0) printf("Error: %d\n", result); + //if (it->ret != 0) + // printf("%s = %f\n", line, it->ret->value.f); } fclose(fp); - iend(&interp); + idelinstance(it); return 0; } + diff --git a/shelpers.c b/shelpers.c deleted file mode 100644 index 20ec0cc..0000000 --- a/shelpers.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "shelpers.h" - -#include -#include - -char *strclone(const char *s) -{ - char *clone = (char *)malloc(strlen(s) + 1); - strcpy(clone, s); - return clone; -} - -char *strnclone(const char *s, uint32_t n) -{ - char *clone = (char *)malloc(n + 1); - strncpy(clone, s, n); - clone[n] = '\0'; - return clone; -} - -uint8_t eol(int c) -{ - return c == '\n' || c == '\0'; -} - -uint8_t eot(int c) -{ - return eol(c) || c == ' '; -} - -uint8_t eoe(int c) -{ - return eol(c) || c == ')'; -} - -uint32_t findend(const char *s, char o, char c) -{ - uint8_t indent = 0; - uint32_t i; - for (i = 1; !eol(s[i]); i++) { - if (s[i] == o) { - indent++; - } else if (s[i] == c) { - if (indent == 0) - break; - else - indent--; - } - } - - return i; -} - -void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset) -{ - uint32_t i = *offset; - while (!cmp(s[i])) { - if (s[i] != ' ' && s[i] != '\t') - break; - i++; - } - *offset = i; -} - diff --git a/shelpers.h b/shelpers.h deleted file mode 100644 index 7f2ad63..0000000 --- a/shelpers.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef SHELPERS_H_ -#define SHELPERS_H_ - -#include - -/** - * Clones the given string, malloc'ing a new one. - * @param s the string to clone - * @return the malloc'd copy - */ -char *strclone(const char *s); - -/** - * Clones the given string until the given count. - * @param s the string to clone - * @param n the number of characters to clone - * @return the malloc'd copy - */ -char *strnclone(const char *s, uint32_t n); - - -/** - * Returns non-zero if the character is considered an end-of-line. - * @param c a character - * @return non-zero if eol, zero if not - */ -uint8_t eol(int c); - -/** - * Returns non-zero if the character is considered an end-of-token. - * @param c a character - * @return non-zero if eot, zero if not - */ -uint8_t eot(int c); - -/** - * Returns non-zero if the character is considered an end-of-expression. - * @param c a character - * @return non-zero if eoe, zero if not - */ -uint8_t eoe(int c); - - -/** - * Finds the matching end character in a string, e.g. matching parens. - * @param s the string to search - * @param o the starting, opening character (e.g. '(') - * @param c the end, closing character (e.g. ')') - * @return offset of the end character in the string - */ -uint32_t findend(const char *s, char o, char c); - -/** - * Increments offset until the character in the string is not blank or fails - * the given comparison. - * @param s the string to use - * @param cmp a comparing function, stops search if returns true - * @param offset the variable to increment while searching - */ -void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset); - -#endif // SHELPERS_H_ diff --git a/stack.c b/stack.c deleted file mode 100644 index 8ada8ea..0000000 --- a/stack.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "stack.h" - -void ipush(interpreter *it, void *v) -{ - it->stack[it->stidx++] = v; -} - -void *ipop(interpreter *it) -{ - return it->stack[--it->stidx]; -} - -void ipopm(interpreter *it, uint32_t count) -{ - it->stidx -= count; -} - -variable *igetarg(interpreter *interp, uint32_t index) -{ - return interp->stack[interp->stidx - index - 1]; -} - -const char *igetarg_string(interpreter *interp, uint32_t index) -{ - if (index >= interp->stidx) - return 0; - variable *v = igetarg(interp, index); - return (const char *)v->value.p; -} - -float igetarg_number(interpreter *interp, uint32_t index) -{ - if (index >= interp->stidx) - return 0; - variable *v = igetarg(interp, index); - return v->value.f; -} - diff --git a/stack.h b/stack.h deleted file mode 100644 index 18821a1..0000000 --- a/stack.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef STACK_H_ -#define STACK_H_ - -#include "parser.h" - -void ipush(interpreter *it, void *v); -void *ipop(interpreter *it); -void ipopm(interpreter *it, uint32_t count); - -variable *igetarg(interpreter *interp, uint32_t index); -const char *igetarg_string(interpreter *interp, uint32_t index); -float igetarg_number(interpreter *interp, uint32_t index); - -#define igetarg_integer(i, x) (int)igetarg_number(i, x) - -#endif // STACK_H_ diff --git a/stdlib.h b/stdlib.h deleted file mode 100644 index b87a823..0000000 --- a/stdlib.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef STDLIB_H_ -#define STDLIB_H_ - -char *snprintf(char *buf, unsigned int max, const char *format, ...); -float strtof(const char *s, char **endptr); - -int atoi(const char *); - -#endif // STDLIB_H_ diff --git a/test1 b/test1 new file mode 100644 index 0000000..1d8588c --- /dev/null +++ b/test1 @@ -0,0 +1,13 @@ +# test1 +# arithmetic tests +# looking for proper basic function, respect for order of ops, +# and respect for parentheses + +2 + 5 +14 - 9 +3 * 8 + 3 +9 - 3 / 2 +3 * (8 + 3) +(9 - 3) / 2 +(4 + 5) * ((9 - 1) + 3) +5 - 3 + 4 diff --git a/test2 b/test2 new file mode 100644 index 0000000..f836124 --- /dev/null +++ b/test2 @@ -0,0 +1,16 @@ +# test2 +# variable and function tests +# show variable recognition and proper c-function handling + +a * 1 +3 + b + +set(a, 5) +a * 1 + +set(c, 4) +a / c + +set(b, 2) set(d, 8) + +d + set(e, 4) diff --git a/test3 b/test3 new file mode 100644 index 0000000..940ed6f --- /dev/null +++ b/test3 @@ -0,0 +1,25 @@ +# test3 +# verify builtin functions, conditionals and such + +a = 5 + +func(checka) { + if (a == 5) { + print("a == 5") + } else { + print("a != 5") + } +} + +checka + +print("Increment a...") +a = a + 1 +checka + +d = 0 +while (d < 10) { + print(d) + d = d + 1 +} + diff --git a/test4 b/test4 new file mode 100644 index 0000000..af8595e --- /dev/null +++ b/test4 @@ -0,0 +1,6 @@ +# test4 +# find memory leaks + +x = 4 +y = solve("x-2") +print(y) diff --git a/variable.c b/variable.c deleted file mode 100644 index 957a130..0000000 --- a/variable.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "variable.h" -#include "parser.h" - -#include -#include -#include -#include -#include - -extern int atoi(const char *); - -char *fixstring(char *s) -{ - char *n = malloc(strlen(s) + 1); - int j = 0; - for (int i = 0; s[i] != '\0'; i++, j++) { - if (s[i] == '\\') { - if (s[i + 1] == 'n') - n[j] = '\n'; - i++; - } else { - n[j] = s[i]; - } - } - n[j] = '\0'; - return n; -} - -variable *make_varn(variable *v, float value) -{ - if (v == 0) - v = (variable *)malloc(sizeof(variable)); - v->used = 0; - v->fromc = 0; - v->valtype = NUMBER; - v->value.f = value; - return v; -} - -variable *make_vars(variable *v, const char *value) -{ - if (v == 0) - v = (variable *)malloc(sizeof(variable)); - v->used = 0; - v->fromc = 0; - v->valtype = STRING; - v->value.p = (value != 0) ? (uint32_t)fixstring(value) : 0; - return v; -} - -variable *make_varf(variable *v, uint8_t fromc, uint32_t func) -{ - if (v == 0) - v = (variable *)malloc(sizeof(variable)); - v->used = 0; - v->fromc = fromc; - v->valtype = FUNC; - v->value.p = func; - return v; -} - -variable *make_vare(variable *v, const char *expr) -{ - if (v == 0) - v = (variable *)malloc(sizeof(variable)); - v->used = 0; - v->fromc = 0; - v->valtype = EXPR; - v->value.p = (uint32_t)strclone(expr); - return v; -} - -int try_variable(char **name, const char *text) -{ - if (name == 0) - return 0; - - int neg = 1; - int i = 0; - - if (text[0] == '-') { - neg = -1; - i++; - } - if (!isalpha(text[i])) - return 0; - - for (i++; isalnum(text[i]); i++); - - int o = (neg < 0); - if (neg < 0) - i--; - *name = (char *)malloc(i + 1); - strncpy(*name, text + o, i); - (*name)[i] = '\0'; - return (neg > 0) ? i : -(i + 1); -} - -int try_number(variable *v, const char *text) -{ - if (v == 0) - return 0; - - int decimal = -1; - char valid = 0; - - int i = 0; - if (text[0] == '-') - i++; - do { - if (text[i] == '.') { - if (decimal >= 0) { - valid = 0; - break; - } - decimal = i; - } else if (isdigit(text[i])) { - valid |= 1; - } else { - break; - } - } while (text[++i] != '\0'); - - if (valid == 0) - return 0; - - char *buf = (char *)malloc(i + 1); - strncpy(buf, text, i); - buf[i] = '\0'; - - make_varn(v, strtof(buf, 0)); - - free(buf); - return i; -} diff --git a/variable.h b/variable.h index da3badc..4c7b987 100644 --- a/variable.h +++ b/variable.h @@ -4,28 +4,21 @@ #include typedef struct { - uint8_t used :1; - uint8_t fromc :1; - uint8_t valtype :4; + uint8_t tmp :1; + uint8_t type :3; + uint8_t unused :4; union { float f; uint32_t p; } value; } variable; -enum valtype { - STRING = 0, - NUMBER, +enum VARTYPE { + NUMBER = 0, + STRING, + OPERATOR, FUNC, - EXPR + CFUNC, }; -variable *make_varn(variable *v, float value); -variable *make_vars(variable *v, const char *s); -variable *make_varf(variable *v, uint8_t fromc, uint32_t func); -variable *make_vare(variable *v, const char *e); - -int try_number(variable *v, const char *text); -int try_variable(char **name, const char *text); - #endif // VARIABLE_H_