From 047b9599fed749e245c735c98c6840ad4fe8d422 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Fri, 28 Oct 2016 16:51:27 +0200 Subject: [PATCH] log framework --- lib/Makefile | 2 +- lib/build/test | Bin 67320 -> 71480 bytes lib/ecoli_log.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ lib/ecoli_log.h | 55 +++++++++++++++++++++++++++ lib/ecoli_test.c | 37 ++++++++++-------- lib/ecoli_tk.c | 22 +++++------ lib/ecoli_tk.h | 7 +++- lib/ecoli_tk_int.c | 9 +++-- lib/ecoli_tk_or.c | 5 ++- lib/ecoli_tk_str.c | 9 +++-- lib/main.c | 4 +- 11 files changed, 202 insertions(+), 41 deletions(-) create mode 100644 lib/ecoli_log.c create mode 100644 lib/ecoli_log.h diff --git a/lib/Makefile b/lib/Makefile index 9aeeae2..08a1b40 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -36,7 +36,7 @@ CFLAGS += -I. srcs := ecoli_tk.c ecoli_tk_str.c ecoli_tk_seq.c srcs += ecoli_tk_space.c ecoli_tk_or.c ecoli_test.c srcs += ecoli_tk_empty.c ecoli_tk_int.c -srcs += ecoli_malloc.c +srcs += ecoli_malloc.c ecoli_log.c shlib-y-$(O)libecoli.so := $(srcs) exe-y-$(O)test = $(srcs) main.c diff --git a/lib/build/test b/lib/build/test index 34b89acd1d6bc3223aadd48cbda8bda29fa99d76..2913edbfea5dab61b4cfb6a408acb65259c774f1 100755 GIT binary patch literal 71480 zcmeFa3t&{$wLX4kCYhWGj|4&>JTp83K?x*C5Fe4@5ex!0RipR}Ap{Z$NlYey_J?8v zY8q3a)<-K`{KaLZzW>~frvBp|q zD+sJq{B!UkCgy~@O))35fy-Y2|56z7^MRi~f(L&72p*O-LZ0!^;m(l!;=hQAYWT$q zH0gvEWaN+KDC?~z|JDnZAjPzXbU zkJHMgeK+>hNf%u6lNVXm`G@Go{=EpyfxTcKcMSN_W5BbI0sjo(1Mn~THxhu}`1Uyl z{G4OJA2eG2ov)2E64M@F$J|Uvv!k&SSs}j{*PgG2lN3JdA(IzfA!2 zrsrFZ0UvV=__kxfXB-25`!V1a`aw0#e!8`~s->y9t|7YIYKb;CRIh5Xnp&eRR&z~N zeSKrKRkgISIm)bPV|_itWvxwCWo1=MOHFgMa(Pu93f($N7xrP-;CiYVExggTZh$!$my?0^LOh-OC;nN z<{jU+df*v?p^v*gaE?LFZ;yee0l;y``E`5Xeg}wfp9juy%=zv2z@0Icc`*;%JKi4h zz{%VB9r3`Oxk2(SULpZ;p$PY9d*JCV6gu?4ITks;91py&14J11z|j!yFW&?2??NrB z&;xhckl8alaPN2-@xZBy=9kmq<;PEuvNBkchuk0UDo!L{iM}X{8fN@^6tVjBR7H=)3q#lV1EyO zd0%FlrgflO(qCYjCUs!9q(8?rP3gdPNq?4Un$Ur*lD>jzn)rcDl5S?2rgUJvq%UQf zW^tfN(o319=^R)h=?j>q$s8z`^jS>PR1QQWeFoDskpqR2p3O8(<3L!_Co@fxIFKpn zsZ7%p4p@>tj%jwa1BX5YAa4xQG>HTIB|VI3n!n?jn!tfglKvypZ2AN1kuLh({Pq_vDQkbNtnH0M<>$=r+P%FjVwH709+9AH zEP|fwH$NS=-pR8Qq&y>CJVKm#N*2kfikqbH?3I6L# z?m_*m)&UhL7;AvSE`BEUW`KN$h0|lZ;V_o9&9qum58jA!F0r>+pr`xd16QC7P_j;BqVxz5jv$PI zY0Qc?AlPR`&js-p(MpE+Kp;WNu2`YcJ#=scAv+3HvSy*%6}wJJ9xCgoz(0^|FGr6< z*b%YWLlyd|E9kDVt{0CW4RH<%soD=Ve zWICiJkLivI)aWJj@6OZ=sf4g^Wi5b%1Zpz)gPtC#g+O+cYEAAwg-Yp)J&jorrC)&2 z8R1*|OKIf2@;*uqXKKehQ-4$H29!dDT=~P0A4+K54`e7owArx;sR}@!QxQ!IB$eq* zJy%#u(`G+PJ!`{Gf!NZpxeuQw%(LG;*|Izcr&98GvmS!_4q4HOkN{0WzU5(wccC;e zwWSW3mO6AWxGAv-vWq^@}g=+;5j6J6n%$HGX()`MDETj?Pm zpohv%Dc#eI)-8p7cg4Pjjwt<#>5d4r&d#t10;7Cq@x{tjv>j_F8Np+bBL^oSv8SxF z+>ZiK6B)u>x?)RJMbscP2hFl?wEj45ae$)7w6|)rx8|ZOl8^7;Y149h)5T6- z4!eDU#?+c76+d_t%0na6jt&ud34o4@{blVxW6e+hb59S9BFOB6^A$;TRS4EpI_fEy z*HcIBkWLJr1rD*IG()e_p7q+fGt4+*v3kVM??rqO*b;gFR$tD|!aeaPSGeZ{G5fmd5H61Jd|`rc`=RswR%^Pb_Q3Nj(ou@Gsn`co z$poLP<9yhiyVR`mj=&Qud3@b*9cpB(#U9UsOUd8P)gf zcu@)cOvb~m*jp+pj17YzrP6^A(qS;d+|*A+g(bqwvJ|5$)_^{vmYPD4+b=MbU{voa zJpv}y!Bh+ZM=%5ku>3>LrqHu(Gngx^ZEa%`9V*^NINOdzdY<7tWp!IAt&ueFd!9Z-3 z!yIHo9yELMd&UmJ4s^%cEZ$kXmLn}NK0k#at(3z$M_LU2MH17&-_VjC`jBxVJlTh! zqGzxL=~}7|WSyy>5|LzVaOZE4>D+hB48VSxv*QDmCx$Vc@}y3tc&P(=DII2hj<SfY*N z-wLGnA6&;LHSTn9QGPTVU{njtWsseu>P37YLQVUoOY)j*<)2f!4!pc*-Z$Z2dA?sIe@rV`qk! z_Fer))4nwCoE_shn|2o4QxSkt-Xtbdi#(;>8U9q3)EPccOZ`{|k*?Su;0O2apRtXi zeW)Px80d-MZ_-x6pbm1UxCE^ZPUIuwy2CGkMYysOcOtV!+_KO5cIN#>Na9CkatG zjO<`WTj@I-4-z^2wxjeNci1U(Ckb&pFu`Dw0hjhC7(op1Uu|C<*El8iE=yre-=%=Xl`rQnf+^aX_RGi3NMx*6I$`ztb# zcg3znVz0YB+Jw%p}dxe=wbjW|O(&BGG8^0vWu!V%?b7;{#Y+ea@=XsE?xW2y4;u zIp74sleNvvBC-WC+&q^uNGrQj{U5=eK8(!J-8&kT#$Jxqpm7G)xy%LqL(;HxZllME zJ~+hb3?>7~!@uw8X{R~H)CG+lY?YN{XKJpnO&YV01G@TvJJu@C#fImr6TlPx53AuB z>7@bQ`JE{h+i|&;8e>X*1Er*C+!iSBD&-8sA*wHs=*n5K?>h4wJ<--M^4`G|@fbIX zbcmRJ9Aa=+dk*|51!Y<9&g{K1`4m6R09v_!kY%-(zSXwwEh{>5$92l%OM+AKeFRGB zA;{WM`c|m)14HE+rLx^nSt(Rv9O6NxU8$U{R4#L=Gz*oOp`wd|&f*qBV}j6lqix+A zq#;vTXK{woC~#>^78-9P(U@jvyq?9{?3dwoD-IQu`#SBfv-obHXbTPC4Cy-6Y@xH5 z7jL1h=n~pO6#yFD)(WTMDh8mMA=2!VeUp(pZc=If#L=mn4p`l*THh(c#j# zUTAbD(fER)F-vIdZCkgOG;UQI6P3p4E{!swvDc{$c+W>4gZ>r(MRof%xPM!zmIS#PGJD5-yJ}$?7@B*rMXk3xeaun+lSeE0I^~_eoL+FairHGQi%$cryMFM*9u!kolXXd*6G(=rzhCU80N+8 zrD?oVCviQrPJiLR)>&LghM?Ll((Gf2)&(qoh5 zBv_Txui1BS;3ft{Sps3jO5FJ;EUOLm01lbCNcMg)o1(%MACx`*8Y+zX2#+l=^|sOv z=m^rmI;Hf3H9vveuboP{<9>q_Cc^`78oxmxI~Hjh-^N~!D=a$& z)Pe4YC7^4eh|xjxLp`zzdeqI)D`>cD2D9T_{TmcYxA^+pxK^-v$T}#nP(bm?Yql5 z2R#iUG|ZTeDcxo5ev_?xEr;NgCU(!bc1*vB{fX7;AX#n}m1R7-yUd6GyEDFTWqf~k zo)xw%)YL4iWL!3V|EK>c6*Qt|2%iJjQy}g^#qJQgkZw`8j6A*{WIQ+!uIfhq0N)vFbm^B7pt^sz2yfcIRSdtctHp&@9-G zhIV&kO3C7@P6RuY{43;iN3Y0H!@LalU9lL(9kfg0@cuq1Im0^_)%$gb!C|;EGti3t2{X_#(O>apqp3F><_-H;Gtih~PzU;YZKF?SAhf{~|1)Qxmw)}Yx`Ss1 zdN~(!%k641ry-6Rs1!l$3%`VYyED)O#JWSVaun-0V$~C?Gxg~c#583FDuC(JapL6S zoe?k)x--#lSd5)#S|ai^XZjH2hjmSp{S6sOyJDH}dRR((;lF4`nsx51idpBJ&FcqU zrLUmI&`9w@NbnfrvG=9hKMB~WF6=)6d)Pa04s!T_Bc1*hak2$a>2U*Vc)Z>aPYsE1Ux zD3xanm5oAWk6A75R4R*<%C#<)>xBwdiw>2ul*$4_Wu{PZR*SooN}5ucjrn5T{k|hgq2RI2SlT{S*V#=1tLpvqq&)jLb)dGbs5J0@cC? zFSAv#Ms?cbL%}FcH&nI?6=#k5Bc-xNsod{Uc~Gcejp|VOky3e<0c5#As5qg>q_NU2vjd`{G58(W~ew8W*Hiv6B>87t-G5vUQilUO5-+{##W(m zw<8JkaHrVZD`lNE`!Aez(X5MSU1B!=J4?n+4qGv{u(JR+zMFgWm^~2~Ix_KiF?E2ecRrF5&|Vsr!9@v+#YVP_Z%@eksy!aR?(ac?tWetWFekh7wl zgfwhIc$)Z=>m9eNSoaQuVFILKqZCm#NG^A)x!2VvvaOAP$N3pA^U8aNwx#p60Dx_eVw2cd0uA%wwP z%AJ-)`@jPj-SgYup5MO5Y29mbU=BPH)lTWshQ)sax^}ENR;`Au=d>B5s z+^9p{1PrFQ4D^Pxq-i|{gTG?n_Aq!9yLYjn!hiyDAt>k15|?G&SvEC&Fay;F5WabP zY7r%Il7ghi&)SD~z6f94a}6#66{1O7(byGx+7~^Ak}woe3H=<*F=8}agzUrKTba%$ zM-nuJ#$&lX9=%_bSdn+J!i<%JH8j;eQ8aZ(G{t*aM?_OnCwKeSXbML&)Ko7Fj!$Ip zMKbuqPsrfoYbuSB^rESRb=D3_O+%FyED?Oy+@H=j6x7@wlw|y}ReS1PgqSnBgAo)4 z9Wnga!Kp~?cigqu*$Hge8Ds2H2m5-?Vo5d>9t{E#QW!w_#`n% z1;%tB{WDbsMlw@~wx=GRz#73E;##Lm($gAC?3zExPUxD0GAwi~xFzW2?y?i9)Z0jp z{bGSI=xi#K&>Xev{S$~C$xI}_h2-Ns?R)(}p33v~rf6Z?KTH*+oz1AKNO&spFpn@tBcl3YjX?(v|*sw`7c zA~`+Xn9{I;NWr+aAn}Qbig~{u8Zkc+Wn?1CKA=E;oq&_-cvGwu0>JXW(S_9ql_8DfYu zH)h%^_Qh`Q?&)#*Kxqs&1X=S%Py!8Ft{%*N!QqI(B{TMQCS^x$|FL(}oQn!PUyGdp z79CdGkuj~4Kz1JsOJhJwSCyUgM3k#Mg|e~nTTkea*!$139L7nW)dN8`&x}4IP8lkV z4R+EK|Bu(6g^t2<0K3wl4?q@r2GzE|Y~mAT?cJ_AB2WjqpL_O!vtdk(9gB7Y_mEM+ z6KFFuiE$nb&DB6a!LHahIacw|L~bCN+{G}{zl?+WRcvngKv4I5;xW`s3^0ryDj5%# zqvl+(ab5$}3>b@;fo_(eHROE4xf|E^Rzf?rFM83L^uZ;zBVULW=THI=dk;+@#AM_% zBJ#q@5y(Z-?Cp%BiS@E+N5zZk9K_8l>>7?(D)8NFm)w>#ckI+?HtC(HL#~>a7;o`m zHt-IiSR zsjM(ms)dSkhQC3n*h*!bOXX6b@_KnAk|Wo-R&bEBPG?D)OK=eg9xR4Q?vds;+srg8 zj0hul+@NwipvAfos6Gaxn8Ru-S&OX{?ludHBXUSO zp-222bC{<`G^9B_;$FQ0jH)aA+CVg2uieY1f{=r38m7!4qAA>p<`*3;HVj7FbXwEa-kM z_j+GZNe=?8OexAa7W6!M%e2%Li@?wy#;}ONlqF>}MP$9&&pzH=OR%3WfuhHLCZ{^~ zvr^Xq98s?o=Edt7psHWNJ)ZVbXBTEC*>o1q7Mzkx5U7B6?V+Zy3**=iUx@=^m7#K; zP;qu)b}5w)`Vgli$E9+KP}vrzvRJ8n+E5uFRPHwWFsv9ZQ+)p%US_D6u1iqa6s zs~j92aND~x^-dJUSOoM;q;Av{3SuG9nYuxf@FmMLMJvw6Q|hJ6G0t9R>P3=@*r))s zkh(~d9Fsg-OJQ*-Ays?DTR_Se+Exb=9gvi7&9pz?6L+SP(EmJ~az^ZA{J6J&loLY- zE#uqtgyCP9T`0IF+6aGwt8_}~{^-Eiub!scidNNzKR65i3fDR49S}+U){~*Fco#4} zk8|{PNcsz#GZmvQ`;_acxOHGdv@d!C)h^O{;6}?EP&?c;)_vU(PsQDO$o7Rg@}Gf> zSR(pZ71_>6@Q`j(pYo8jv2$-1*E7(n`t}mqQ|j>s$#?~Hc|pK^bo>&ptqxzvrLk@s z7<>Ln+5>jb)J;5Cjv4_28t-(y_+J30z4QZaKVF`S-L-?qgT!=_kgb*CIf!;FdW!}P zG?l6=R)JFSt+=b-+7BM>k4zHd`d(Oq|JvP{F1e7xe%G~e8t4@w2B|a4%oP~-LX6x; z=`?p%I?1|Yqss9d?D%CgZ2QKA0_9WfS&yH>808A!FzDRSCO!|(D@M7nM!-DhPV~g+ zU_cZrR*PfY`Rz|>;f`O?x>)!iJaL6hMd4WwVH&Y|JLdStFT@_r;%NX#e;*}dB~Rc! z?jKoKS`Wr@0NEe&*&n%@>PS5+n{C79L4(WI^E!<0z(=bVuQ2#2oF7r{HVL@^R9o*X zX#$4Uzz1GZ40s*d-^r4nbz#x(X^$bxUkyrTnI32P4(3eaZzc#~{!uLd%2`#E_W8%- zEOQ)|DASI9f!&ob4h3{vj-_B`iR3wm#I4o zE)P4V}&4?l_8k)FJ*&u={75C*@R>c;xI%IM0;_=HB?6*b}0 zO2P~qm**cBT{+RJTUL_SGAZ0ra%x`7Y3Wu&V|Z0nv>LC?BUatGs;Rz)pX7j}5>K3r zjMj!|NnUHXg`eT5X^HArGz^WZWy>TMUfx$|sif9Hj(U-&GZZQTze{2q86D=U0PV{OA|3#FG^Yb}TdIlTI+Y^k{naz$5$N0)@p ztXR0vs;;f8U*@K?K0vBOeO)bAwlq~$*PvV+(#Yx^lML(dkJNqb+O?EDS{JReqK(l; z3xuXxs0-*VwW5G&ts13LVh7ZJW3z~hG$d-NZEQu2sB>xb@X}Tjt7!?VJ$UgHhw$DI z6X_XisS!*k(Gp%$7p*mvW?Jonh8EXO438kRSn46*s;nf$yfmQ4&7oEFY&a!p3_ z`JtEmyrzk;-$YY#GENRJty&hAPs6~f8&}rV&?o2bqwt%e%??@;p7|CIc^-pwBHg3# zUD5_m>k&tr6!up3C^_*-oyO+N!}T>)XkK*l5@3fxvxKTK{j0fVMO{m@ra6qxXf&8^ zm6T}r$}5;!*b;7Ot*)+VX-NhdNgsIbr~D3VB# z6)v)h3at~DC;pIm6sTaTRdCYOsVAIp;?%+urq3vzcH)V}GYV$_wa_YJKZZzPZmp_Y zSz}#_K5jKst*WtVYhWqKf;O(iSBNAh92Wehs^*rOWon2lhOsf-AT&2F#b=B#t_}~J z!f%W%g6@xC^}ieOwY#tkK-lmI<^qHrkK&3f*7XY>>*>iycoo7jg#9th*CGsIcDWAW zBM9$C*bfuj9)#y1j3Imvp`Bt`gWV3~BFZDY4dLAgr~eG)5uSr{%oxH&IB~V%fV3dYM|cm8oXZfN z_%g~Pd;;Nh2uH%VxEtX^I3V7G@Xc3I9^qebZ7CDJXusFsPa#}@upHs3ulMvcAuPbP zxJ?K%e$&&l9pPDT_Vjck{8p@|=Mci211KLteSVAb2+u}Xj_`7XO$e{Udl{P$&Uy>w z5q<|@H^M(4JcQ7Py}L~G@IeR*5w;*KNBAEI(T}X3BHV;9h?n=aBm5G=ZiLSvJcN*M z0%u|^`53}Ngl{1%M>rPmUURuxjBpdehY)T@Sa$^F5%&2@PtOsA`3SkTz7^pTu9EP> z>4E%wSDa<})@J&K_f4}m`O-28#}yE3|HC~!$193Fd&jq|aR$E-8?x)^^!3l2*FWcs zj6Q4Z_14T`ryO^}xG^L^nsf2*${jsDBZ)Vwf95s*IsJlx93NOq{xX0+vlD#)p_}jD z$!y8r0Pt}1jcMNeM#+}^y8xep{2RRa{?EDPp91`LgLZy{tD#Zk&ypoH-8!O-$Z`cn}4BXYyC}ru{Xad zo_`ne-$(h)-hBV{F8!yFUyre4K0;T&fw`{!-vIn3j43q<<(IhSQ!p02jQkH0^8e)K zk3;^07=s>9$lvAW&qY4Rq-_cL-*EGnA^&ycA4$kR?B;Jk{!WZp+#GY|_iuCa??V1U zc+_EUzDIvgnfy|3zCYrYe*^iKq5PhN{3qS~6pW=qF-HD2A^$gS{y5~nj{J&*{Bk#c zF7oO97bNIE-_`#z5oJH^5=VcMkVAAb@S&U ze;KyDc|*gM-~WzFpC9Bb!3OGhZ+=z0ejAWK2l>+z=oh*4??V3hm|H&YE$?r4=|6@1 zF61Ax{>bO*^_cZXyR1U~G3$@~*o!?qlN02dDDsViOl;TpaGpB|eBAmk_D^YXZ!wjuv8^56F6``>c)uowAHy?pHaw~&7m z=F-;^%D?KC?~6J4Jj}6k66$%H+YXbEe+A~=i_o9kdIrw(lK|_t5cv;c=it%=`ZX^7 zdgNRCG500pA9VAtM}9Z*7bN7*bMv<$|9#|-_vU--XfN`8@Ch;!!0{1R{eTFKV>BmYmxABZrnpMGh?koE`s0DO*P zwmAs?2gI5C4C|S z+8ow!V4;RXXKNTS`Ih;yO8hyYaVM=Kc0}Mf;ga72Wf2L7YSR7w^Kg?6n{b#3AG%

MFce6g!4>zt_hc$aJ31qG2zW7{0|d8Xu@Yq_%jo}X~OqR z7))1wgH1Tzgwstp&xGfiaJdOroA4SFCf6f5Jv2x8{Mv*+9IEMLJSYA8`I^6IxQ2I` z{^R8TXtctebbVf8+JQS^$9T2v0s9L}Fxv$U?NAv}F@(d43nqN0f!3r{U9nqD}g zaH=&4vYScLW=*T2@bx~dS7{-)vg@wvUwO$}=7ONwXs)W8G^;JxO>TO26$a2j6M!Z+@hH_MYe9Up+4()V_ZV z{B*ReHjV9D1Dw8D7?+<$k=_i$&pE=sZw8(LJFSI*&%PQ30{*mls6ZekZLI)JN0gs#y>02R>$ZBFb-^B6x5zXPO2TWZ(`CH{2WTAG42nMM&UL@?Nmhf zrM^88sG(^PHuaB70k%SHs?9omr1K%;k@WM4WBHgUOW#SNK1r0PpTmS-5{uJMfq1DYzA9iZ zN#}Hz8uYC|qBgw`iP^rTfHkFGPHKH65l!c);E0{P=5?j-+X5x5B z+?{?M6O$ydJ^cnICi@Cd=ArbfNqUONwmbc1<`ntb0DB5sTFkoH?gGD@)Ge%Jh%Y>) zeuYshG@bF=SzSBSpQ3+tDZrUl&@KclXtM$PvOy_!ziSX7luaqn8y#qt)jtLC40edr zQ+$MH93Z_@HU4RoOD&Oj(B6VX+Ag4E{upAVe3R@muf-$fUWwj;8l-HKXeRuV;IO4A z(Dw--e29MothB=jGOt8m4Gt#+M*1~iz#JP8_@4vcw9ymr4B7>F4y0n|A(BOHWsz~# zBE&5JortE5`Ltl3hv%SrViDbo^;3wGHg=6*t;193-R5E@5w&Nccuv~*y+8=P4I59J zFal94w3G3C%3+5_LiV(YN|98p#_;rW|?T1<@`KlUlJtJBTk} z8>oa0&a~&OBiifCnxkl+mpDt?M5wskMW}cgQ7a?}75fFj4nv@P`yA$IOI47dB`tL> z8zM8Crg*tmJ3ld=L^shFc|l5UOcp>K5F^q_(;mXxpo-a%Qsib`!_EGYqsc+!N~Q^ z@UgQzV5o*&syDh+Pcl?%t>Hx|=F9g547M!xP{Oz6SHK>@za)WN#vy}>ly3@`t4PN= zB0+{bQF8cykYbLn&)|q~J|a(290NB%N#yuwOm3})xgkl$gB(x%o0p6kVpz>L#m90$^u66F*|j)HC?=O*61~K5 zsxhd(EepXZx1|XAY(eNJw`HoEC?8#C`SvTHS}X4qYU){v@XmmUP>>C8#C%)&W1z~# z0ONa>X6xTvmP^C+{XnTk!Zck?1vWo))o9VfUQ?U#nFE#F=|U9eT@XrZ@tjkO@oNpv zEQ9kq7w0F6v&0(ncoL4%cv15gV-NTaw#`newA$2Qvmxi(atUfMR&@S|>U_zV7K7x- zrSu+iWU}&j8^?D)(I*?!Vwc`GK`%Ut4DVN!K(!ckecw@)lq;_Xlvk}a;Wb*>JnZTPk_B3Wj1pf}V)Jd2VwUi*RaWPu^ZgvDHX4zX= z76eB(<4?ResU=qaIA-3EXNaER62(EQA$o%;85TO5G_}MUMV0zC{xl;ZWy;->_n~C2 zbnlJYyK7arjasE8)8dXJ&FB{)Kf=p~|%9HHQ1v_Q1Old4uipvc}D{nAMp3USf z{UTD1qVwn5@&tutPdM8&yLbe?3N5_kxB)D?B-d~q^EE>t(ZtHRWM?$c{6fuN0w<8JBiV>68nV(T zvh_MFFvYqF#$r}OUxvU>BO`g)`!tOI-?19fB~Z%SqadOzfl@q6pcKy%D8;h`O7Sd# zQanqb6weYU#j^xT@hpK-JWC+_4J2BzE`d_KOQ00*5-26bcP_-!B~VJxcM%f01WNHP zfl|CnpcL;CD8;)3O7Sj%QU>{!f|@RYQgVFk*17~r@h*W|`c1NzB~a?U66F#ob(=&zOQ7!q zi)$Y&fq2iwEP)8=bqU0EN6;RFrz}~x(A6an87C}(xGD+S3-KIOMJ#r>EDx40fw*1? z+RbSq%y{3!nW6f;RE(u|UMaXBNxq!iNfR7Cr=X;X@b~KD9*Cg^!}?!bj1#@M(7u zDxOBvS@`@==r{`>=9q;K37Ulu+u)-XJ|rEqS=L$jyhl2^@KI*E@KI*|E0|m0!-`_a zQZTW}Djb@2A^^fXR6GY!EA$n(R-x(A*+MH>=0sjy&H=9=!l2CpgEK>Np;_u4Dkey) z7Ah`5oGPL)b`yD|kG>7C>=n4ZmOh3JWQG2SXZl!sf-NTG^tfI4dE*Bn<_H8*CbsNr! z_$t~9T%qCO@2w}ce{=naTg`U+97FCjOyP=houXW1jre5}&QcerU2zs$BgT!02nA@!V=X%9iXpJ~|r1Elb{^;V|q&Q{Pi1kT0 zgRyMTdfluzbFC527#v6DlUnNI?n9{|#&xrtSK&PBRcDQySR_9UdkF48td+6JWel8|y}2-5cVDbn3n zStCykC)Q38zNH9vU1eFLcs0UTL)!@tQ(U=hgR1+sJO+~D4%V>maP21x9g~WP*{vWF zRv^RSC)U#Z;bexz6<+hQAvm(yM4WcWk%epn=NK3)d*G$$38T4l<6G>UBUK=mKi`%Q z!C}l}lykA#_+sIFfpV_3hH?AHH-lrVa~SnoEsMgJ!8O#vGdTRXl{iVOq?I^DNiESW zg;PlhRmvGlx+NTV{F}>%V`+XG=Q(=OW4Zg}8_yBaaWVI}ES25(1a=d=>?S(w#EUE8dNz~V6y9A6%2h~t|!oRD4|UwiaqWCZPLc#5OC2oZIBDTBxHwZ|+L%uDbb z)Iu!wwk!`89bbFwm4dYaPoei!7n1{m2VEUsd;Cv;Adas+VJxER_}clDLmgjxBDopI z*PcXz;`oLp^3Wt`A5XTj_aBpn= z%o7Pg^$$Y35fF8JL&c1X;~ScuPukq}4>{ZZ3y>*}Z|L}|5DnT7vZOe^p-UJS$2U~@ zx=2OGH{{v&51DQMfj& zm#Bj}zM-NhQN-~LP3=Y;jxYVNpiO*rd_yzOX4xMC9GXdmsN<_(dUb@s`I{ro=Qo}NdraYDy00+^02 zbvh&k8NPCAC=}Rlyw03q1YW%qcxR4_;0d1qa~prYE&Gu-RA%0*NdS}QP}zbrsmL%o zo^8a!JU)cneH+M~{s8xb-a|YT2%ixlIcvms#%ZKRk`PGzfOdC+3)-xMA#ue)-TNLEA10-LvAIYgvh&eGUN zymDAoljU3Sq~P9qWv+NDpP4aE$yzym$*O|Liw&y_!G=HImajUjDr7X6SdykuM%mFSEA)Z#J!kAI%v5eyu|7=smL&{QGEP+D9EcN`^n0FnW|&f z4pW5@l_s*#)I}SuL>moz?^ZghmSW{WX~rwL8quebk$flQ6}T^-cqLFw?_S9#n{T{- z@V{X5ZD0z!QfNv8s+09NI)mlQ`Zfc9)*=QeS?4mav%bzCGixq`aMlkPM6ym{uzpY_ z0^gu5c=`v`;+Zn&Av|s8a>M1I9kj2)Gn+l}RzwCDATpTijKSpZTyFT9VBUl0kVlC{ zbT5|f>^&=3&*Lfde&=E)5p{OaEbRcJ{KffysXfqR<~PJA31i7qlng zIpjp5@c{t2J3D&~0GXY=i2yr0dyf&t?CcE(3LKmg1VNkl>fqQj~BljwM}L?0&8WN9OU05a|N zDZU<2J=5wlo$J0#In(NM;(dT~ssAa2L7N2zXZ9&3RA&7?#RTcDMW5np5SQH#ggL*) z!?!~B1;S>w)g!8xNGueH7@!_ez2dy`lzc?BZ7CRhczgs;?B&2}`SWeL6YDJs+M1+Pz=}s4E zmm={9rraRSGVGplkseVb9>JV5Ig!#q7iq5|@d)P2Nl2Njs2sukNRe;^Gh%-dQn8El zoFd^EX2kd@iR>Q0yrnR;v0QQ+o~*AwoXh+PfKni7QCIDXW)wAjuA`*j#8K#K68*03Ur^L zbVp7zw$O?!{`5rSPW6^*X{I&`%Z3k2%7#y0EA0ftN4-s>{0yZio*0qR@eQBv0%3F= zyuHup#>aJ6ju8V}N6EP1lOs}J$mlad3hGYdeM zj%uEG#}m0X{{F!lm$0g-2jO#ltDep6`@3^FVz_`BSlJZx^^&OX#4;j~Y zTyVjQ3HO2*6Ruaygudf~3tr10o_q3jDH86<7p2vATyVjQ34O-}7rfRWq3^ihg4a?c z*2_CCxZqWXgudf~3tmm2=AL}5N5Vb%`Yh1&9T!~i`XUngjtee$F`@6c;DQ$u`i=`O zcrl^xxFlcjqHOw(3odwF13pJx@M0y+kr$)Rkr%7$xYH!UcU(>YENFilDH(()c0bx6 zp=?Tl-t0h=j=TtWj=Uspj=UHT+Ft{aw8s!N7re;cT=0_U9q4+g+a#(NyeL!Or-9|e zUJ1^*-eUoM$Au8{R*UCK7j+cB(nVHT^8j)-ev+?r5k1R;b<~wEBFL34!7NBbcQ$_h zjaRy8$@x~&l`d8Y+Wxp#x<~^rwEQDix~N;{g%*;@v68NI8BzYvUg;90n0Hwi52IcF z3s<_>AMEd8)Xxk}IUde{9*0f22vKu}H)Sc}*qSo;zL;a~ebow*-uq&+sE-^vu^n*w z$fOsvS%CMx2sQV~JTZbNzS<#AK(~B>WaVDk zAu55VLgLE4O?18&G<*?D?|)``M9N(1mgHvFu-avK1>!aGL`iGt&xm^u2a-#tDL${V z^5@%9Zey1QaUw)r)9k+Pu6)N92u=;qsmvNTpE>2M7cC-C3l%hUZ!joYsH$i z;1aD^iwX->2T%du>1?HQiXy`BZI>-yXC6U^^>lL^Y294C7@7V7;c;aHTwajL^H zd?`8RJFeepZv94z!R8x-g)fjwudx+-u*PdV5z3+0nEXC?eFmEID6jEf|5~);C-MT! zCockg@*=>${6zr1P@FbVy~axr*Goldvly2%x3t-OT}r2>v^m!!o;eUBM%vu9zz7fI zS~JaDD$3%`fBqZ9yg@uK!F`2W@Ub zW#{5Chz|hBUC-Rorko3qoVleH>e~stN19gj4Wh`ITiVnBP;lm!hahMZU(ejqW?sXx zobuCVQX%S)D45%7gbmJ2n{yx0cxNbWj-qioPMgEhyi}A{@tliLk&dxTx98F-G7)#q z+|tfrj<^nK6(nd$`<%-*$Q;Nsw=~bCqBQqX5lIJamen)2vOF;36i%vF`~EJ!-mZ5Y8*te^IU?D}~N-nf1mq>{hWQI&}jpN!+4 z_5KaelDpnN7Y*#L_vwMT>;0ubbJzP!xa<8UB;55r9TIoFe-0AvdjFFbx-!gqpD%j- ztH*J@Q_|;?J0%>C%?C3+xl{7Vosy4#r^GJ96p|kry(x%wF5lb=jo}3xD`!<5;$s7x zO>T`(x<%ufXvM4#jhf&$8za1AL^Dv z`iUQsAI68R2!l2Y49!e0CR7}Q^kRZ^-cK)n332)l6ms~DoO>(u63kZT5{xW(eoSI` zbIbro$eUv?4V@hUC2aD^lQZ;4d2?(vhj-_*V_Z`5=iBl+)`p|7;#>PUR20kZQCufp z&g(TeAQ*+^-xZvkxdI<08v&mo85~#SUT{i;6x{Q=-5{wbpH-BLtlX_hI9wYmPMhK^ zwsPN0!m&|b#o3@Z=UBOuPE}sBgd@J&<>G8qoN_C-DG7)B3rgo2#aU?OK9GbHb#bm$ zoH8r7{xsz^$ME`+i}N+&$O~M#-$_Dx)J3{Wk#KsLdn5_zbr5|uHy9+R{ycV3q5|u|Cofd#zoqtNH{&roiQts z(iRuVoQ>iHG55+Oq{m&P$CT0+ud>2V86-z=6?(TKY`O~PcV|Hd!FDe-74X!CB_=th!1pQXA9Y-^cIihAmBS+NtBP}FyOmDQ)Oc~5cn?OK;YjzS2$l}IGamm5%wVGdw>tS zTxPIcWVjrq&DGvmu9Ye^GK`X2X!CRjXmPmbq=;}? zXm|~mTWIB-NQ(PBvYM5bOKXn9ET8U0zHiH|5Nj;^`b1@HR6EhAcC2XgIAUREZumM< znnb6Pl!G<}vV5pciuL9Gu6tet6QFxOX?6t9_-FC1#aQIm<2Jv3YtFAHa(?{|onH^% z{C@f5TtGiL=hxFZpzy>t#ZI-OAPH1{TrS9XntJ@R2{zyS(l3CeJqMJ)=(~`SYJU?? zyB?1x@h`NV4~dPuNKEUGeL#Fws@c=-U?MKw8P19XR( zRfiD|Y`Fp*MiFZV^20!@$bh{ktVdZGj_{~-dGK9T-+82azu^)8yv~=%Lw1J+0fh(1?(lg^YKihZ&yhgtb)ND( z$I94E>F1F0C`0*1#QF1W$q3+F?KVMJ4*>L~l;>#5Xl#yBHX57jXiOxUN5arjR)iHe zUCY&4gB~Q&(|$KQf@}+a1x0_pE$4xw*5x!US*y~YraYFY#!gcn7g-tnj4g#+tpMya1w=P!oe+{>r-XUx&Bfq7qs~ruIE)&R=wXf$Rm`Z$g8Y-9ca?IKH<)}zQoNspK-I! ze-}}Cl{GE?Dr?#|DTy5Mr`;=29`UDblPHh)ZGDyXePGRIXU3i=0y*NhhZB;?KU!{& zTFOeSgHG&RLY-SHI?-i*4jG~8HxQ@NjrzZeX!`ND06l1b1F7#b#WtX$?Or{qZ>TNFduesD` zlDdEMMM`|8=zVkfP?DZWEVw8+n2=^s9~hXG%WP8R#j2pq_m+oEreG(ZV%Q9H*$jW1 zGE5SlsUU#}%6n3B5n zIYH}!f%Fy`NNWe6!F99qV({TWdiA`B5Oh8Q{FQ8QK58KSIT!dx;@PoBz$eT8HC zacmjPEQk*9<@L|%6X-v@{{Y{>w9FxZ54HmRPwsO{pZQqZ2F6)^`kaP*%pfKTmpL^9 zP}mm(Vx^6@7}#09K>t2{Sk{MRsGmz{2C&mjGIf3ylYJaEa8`W2`B^N{Z#3vkL1zCf z6g_n)`s6gFfkHEf5|C*C;H!WEqfzC7*}e%wl}1*o$TEl!(#!^1TdPC1gR^{b35QJf z%^WI~O=WRvAd+*-Y$*qyPIKmG`E#(R3BDu)L6{sCmy5~aUP4OdW+j6!xp~Wt^ddSO z4eBU2ug`>`2}E)Y5mcJo!bUWc9Bo81$uWJqjJ5i7mhbeLhE^2)g#9LqUK7$&_6%R znVz!pp*?-nR{Eg2Ao{=_bHZZ7|4U&gs zAYyATvDtGIn?3Aw-%ke0|Gx~B#$S@j+1n{cC-%iL?2BW)ebF;1C-g;3$-P>}Cry5g zCU+dUqx)R)py?fM6LjvlYEI`&?1Y#rofb(bl^ch9MokXh7-x-l>H2fZrtNDL3w5x-%49ig*`D>K@6?V&YKQYa_-Nqt3b%i_sKajLMpnb9PV{qiN3i zQdXvM+YG5~raLoxpTtFLU$aWZAi(8fzqpEYx!Hf3b-K6^wB3x4s2(nzdVMu~soJaS zfr+}yinAfzL0-BEqfPc?E3Qz@kuhbkw}hkU|6QX^ya}BpexlN{dsBh&yWq}wwLgUO zFqc=J!G*52CpqjGitg3BGmGF6$B^KYA>XS^$2!H+#ptgMld!0DHe1Y0oaA6zd_~i5 z{hVs`y^lWui9dpbJp|rc@J(rLX`WJFw{*&i>gp+LXH2i0KCPg>uAy~p!HR~~DbuIa zHB{HPE~~Kw&m@kg^3<>rNr5SqWL}fe=eB%u77%#jsI9dUrTJeSf{!0}wOwnEovEyQQ($6~`GUms7uc<{-fjItYn?X94&f-xW}0NQef;iS3*wE| z3&zK3w4!%K?r88nw1)wvn{xKD%D@KVYRf9=FT^HYfAinbXguy_^qCQ zQzx#(ZM%=`$ll%?@6&&GM>gHMMmoNyn+t!pt2>`q4@~eK-sm5fwe_&EZnX_|t`vXX zKnB5G3#J~vmL10LAE)YGjMsq1+M`!*Ze4S=f6SoPoonpE1w}hIh`!nMzTjcv7ufd& zLZ=>X+hE_fMxaXFYt-!63j=GGNAlgmevAh?w1^=xb$-!?HTHs5`~0nfy4gP^3ufWxjOLfw z%pbVIo-D?9MlcYfF*;-GXAw^^W9zQK+U0>hVNQk{0S;{D!+uz>&j{|4FtN|f-H8s< zx_alg78Lo<&)V)U7-XOSbN@ozKf99H{xdQI>9+@>n`UD^dy|m!iw={tOxG_t5uLZC z3z?qmpTus1$rQBhm+V33%dp5lPT{wH`)?Z-o2sg7{*EU9hdrEXI!)>*(b;jnU>O+i zduM|`pCjO%=lQ2_Zt1lZ7ZmTbTSZ~-@hH;@L2dt*9@6;tOe6o?4g%I**U_D0sLzh^ z5ttCpZ;$gGzDBxBzI2ynQRo@LpO5{vT^Lucu|@w0YLbrxE?*uEUq1 zZRLQD2+cJ}zr}ACEYzh!G`PZ6ml`quxa?geQ~#c#IyXqs!MjQV8I$e8N6@o&-m&vO zNb!ijFnd9fJq?}Z+dE&v^Fn&}eqFt63w~j2D`6s=$L&^s-yR)U`Ln>_aFM-Y*CY4+ z-GxCk1?wLOvGwQhlD0n5sxoE!Pk~6%OJynLk2vo6+Bq9m+Z*k}_W5@{`;vcbw*3xe z4O~vG`GVVmfj-gmFHkrAZJ3we`q96~$W~U?tZIs0{?9WstlnLh!g+x^FwXbx;np>F zZG2AAwMqKFYfhzECc!%+wFT4d73y;B+`6FXaND(Lnxbn~+dKa$1Mg7- zYA^nG5(qmx@DaJN31AOmpWSNj+JzB^(KdV6&Rtls{TD?ehvc<^!V<(y7DTy^`B!k) zWn2PxQ9z*o4rguhiVO{_{wqU+yRBxn!j76zk~YdP<8cOQ3r##Rc|#G9i`}`4ap zWz?#i|EbF6nyO`$e6gysx)uUjEp=DaAgiXjvZ<=MrDhp+lPkF?Y*n_@Ha16>wk~I$ z_JzvYs)l9tH7E;0Q!9(GW3&u=$d!@?X64eVmKv+Rv0+769<2>6bt@WbmW45zlL|;T z)U2^8D-*aaYhBgkDMZ}L%JQ>H&pGG(%6S!M&N*lPr_QXbw5HTHuBw@GMNMRFY`>+o7xU6)nAG zX&s;e)|kaBt6Q7Fy1o@J^i?+2FQc|w@CV>eKeHk{r>H1AeR9#{qVUwhqUnV*3a5q( zRz+JIYD(}rd`)v*HIh}$)wLx!7$}%NEnKi7T=1#FaKZBO`E!iQoJxtzKwgOkpuIF$ zsG&#*y)JLAsZso+L|#?XyrM=5&zrxnw6dwbwM9~En(Lx9VhYKct8Q#%Bea;t2YG&2 zNbDh;(5AG5ma5e?+VFVW1g3!FgOyfY!?GHZ5G78vDpxh)fCEDFFV;sd1J~x7)fQz& ztZp?$mIO+~Evv4f61cUM^;NJ&nkkp(Mkj7jnC|k{`g$SSP_tGEXw9T)K#l?#(?G0AM!Vov)=*P+olZQ;_hT&1DU zHItRMOmbT63ph}_g9eVOebbRlcSLPhN2`|B*EkmE(H=BinOLdiXcU-#Gqkz9s;)jU zQ~MB1bV5HImKJs_K=kO=@E_2(1HTgfu*@Qi0sx4UDvR}a`eZhfiR$@rXe** zu4D_fiZvt(S2aW7(dOz^O=tr4g=AbB2%0*9!Bk>JK|n%m7GjV!5Vl{mS$Yv6l4qJ( z&5+2LD_FXkV<@od8tS4-4kHE1SklsJd2v&9c;RxrW71}aw6YS%i`A8@t8@^=wyBpt zQfzV~4O0B3RXl|}GYiZ=dqs0qQ!SKtb_+M+7^$jns;y#VS>1{{cDb{c)>k#GWTdIJ zq1sgd@sp})_VR?3$b&M~4bkR$7GCSpt8ZK*(+pTOw60=aYg3a#Fknc77{$qESEEQ+4E156fznwyvmD+u}Dijb?R!!J8@lf?A{50AI*3-dwW+ zb0`G%VuO?lgVSFf$cS29Tf^~brM9V6v$hFSTa7jb^JOwtGSVYhC60!MwCMvTr2~V- zNe*Lh6Gq$W#>SO(y>N4CZ^?4jV;Y)P<1jjQR=jE-@yQ&q$`v(He!M^j#(LDuX?H(cuk9G1>pPAUznYF5eAZHBbg23K|BCg>nQhoM^9!@^;@Gr|CfZnLblNr0y6 zQp&`EV8|vCMX3fB6I@4uB<#dhSS`zL*%(C?S2Q`pEac;A- zXkBB2`c9P%RjbfnJjV^ap$d{x!Z6Xex~6$KtiKW-Gyc_7S@kumYs9d?suJh>Rjn9z z4E}QIYiuRD%GIKWxL|QBH0X^@RhP9IiQs%RTTqM6-@<8mWAmyim$s)Rmb*2tbjFj) zXw?df99)}CJBgRNUH>W%&oYkRNo9Bci> zz2OhF4w=`ay}|~pVcw)04_L$9xHl58MtGBMJYbD<QAYTzYV3a>Hn z-y-ad{t>y5(eJ3g_a4M65~QE}r|17{=qLX@`v4T;!^@ysja~7s9e;f|B!SMN;SovC z1zr9|82sG^KP*tbv#HeW$ z1D_%A49oeezWojS(|?1nbA(BL{4F)~Ez^%2J=FgVI?mCZ^XEz&{Xae-B6L45Ps?)Z zmHek!t}uMVNqnysc!t$|hSGt>%guWuN6mKZwt zpsD=sH*n|c?hgDJz-cGR-x&XifhT|A{Fi`#ls!26{0j`^KK^9Y8^qhAnM&`W&fCP}RlUyJVB;UJ!ZN0KP$75a^R#ll;`N~AlPd6@ z(54;&`m-jXTu72@|2f9+z!CyC!rJpRbRW5my){I@Cpvie)~dG)l) zQz*!ON;}_tcc!QW>LvY_c>EQzzZ2iSDO0)s=r&2-|IXq5BkRe?xTWmxUdmsfI152` zHRa<~-(*F@VgC7%8vF?D#NXkNF9;8_bAJu~wHo}n8vF&|;t#R^|GGy0FN%*=Rz7=+ z_{NJe9i4x1j5gMcbE5{|tN3X0Ed8WGJ9EH&pO9v4%EzC$_%!e>_%D~eIWKT&f6X0vLwPVfA|cpqs^Fax8_GEY1ww#d9ax&u-o9|mpoto`*8>H z7m-W7zv6TFZNxuBJMnjAW@_5gqI|rnXBW7%GoF9sOF2?+ygtY&;_=E)vY?>I#~(+0 zoOt}@oTrIjHj!zMzRG^dmy5*C9or1QoA^(NH{NTwywNC07C998P4tI`qDgWFxbG9v zOg;@H^7(r*EkDD9V|Y*z{D}(<|1t3$#J{`EaQ~X(&5Bbf$Yz0ypU2~Q5AA&Ge6zDo zoh9H6?uXguDDVHT@jmwV%Zi7RwlC`zO8dXg`aRl>MN_e$rm; z_xdLn7ZE7R^8*vJ`ONg~b0GB)_-CXv?=RLb!3lq{yatt^WbyS-)FYJI#tQ$K?!I=n zP!|ZL4VVUv|00?g5(TAzzJxE0;)0Y0Jcoz)y>74 zrozbhP(!=+>~%v3G{cC7v4ePX5djZ_(2T7H5$U4FB2FxCNHL_$;jpN07$x=yuxS^u zRx4UKvlQi&5GQPE1e4Typ6{O>KRB6B9@+)Pyb0zMy5N}+iSC_LN0TV*z!yS#4QD;e zZkd^GPUP36*QGMd65*FFGhS|hoi&TKd#Ktuc6L4p!?xx@$d~QHALXS9;W#z$Ts|ss zZn$O{%%|rLB983W-Q2+mx$5SGMkGTU$&1Sm!tfp<2e;5G3tE>*u~VNNg0g@dtF+B7Mn5%+ zI5+L87A%%Qy0cyc@V=#}!$!EoDsnzb3~4NY@!%8@53M>8+TZUUk9xgW;|rw$kN8>e zo6Ewq2w97(UrxgiIt}-dUYGB!$auC-tPL8x3llmxVSSk*7cRQu4MOMBt7Q5K=ojl_ ziDD66H(*kwHGY+aQ-{nR%9yEoM1g!=aeMlgxZ}KcxR5`y$Yx8`**W*c2js}Ax z%`aLbgQfhav%b<+;V;$w$h4V|^oS!M{li_1rGbkN`1bt3efcbJ=o5HvqlddW%#==} zy^a#2;d>JtN7Q5Yokb<>%N@>hOkAA!t)VtW$>iqUEKO}DByC3@DwhI|4*J6mV#F{W z`o3vCFEi|*1$gdGduz*JsYxRyL>B8Cy>{$-7RF8lO?14)x6>=O~?Hq530{2dU4ouaj(!RU^lgcv?j&*hB zOgngALZ5+z$Sz8zVNXh?;rpLxLk!ki%S&xk-GxDHQmw@-!ncwXr*v7~@JZ>PtF4uz zIN2;Ntt@tZzcoKEFZ=L_Qs3Oic-dp-|GgEyL>_VRv&qs(#@w=)@!{jJ9mMu>{NYiz z(7$vfLkTfbby>7kpbe}$F?n^=Dz4!w2uY}ea=WF!NEwNwds z`|&eR6CSfm=@3dA@#p%dMlzHV@S&O|^0g#M_<5@1h_$ceSrE? z6!iMz{(qkOP0Bf+E5H9GT}8v9kL4(_I;kZeKjA-QOekLPzOwAQB+&^|eEz?LgQ33j z!<*k_TBo7`cV5Etha-KD13Yw|>2LEugcb3dy__CJF|6PD=4Ux@Y(}9JxBnZ|_wjdL zdY$@*ec)-q$IlHu73n*Fy;U3=sqcoZsOOryntcyjX}^m(&;1Ys9ve6gt`pb4jsu(U zC)a=^kJCSLmz5iq728<<7dUbO{#@UA^Y2qXmXFK7fv&XQ^_^c|{~z^#2VLwh-+h3NWoeb2W*%+Fm|)77IUG3A0h7!`Hwqajww>!UDBoKn(y*v#{LIMQw5m}I65Kt(6ED#Mz%!7w5N)1>e zrb=zCRobGpx7KR4ty%$+LW*e(r;0F+Q)NP1j^eT0Aye*Nx2DbGY` z+0Oq%Yc1pbPgR8er$!`V!?}i@4Q;tkp&aG>dw;nGaYB9Fk|~oX)Ylf(*EO`QE?PZx zO3{?b#Vw7+6GeXFv5KdhrV6n72m>Z^B4k@K|GGt=x?%H++gD6FZOunJ&i=~uTOJv` zjb-gWME~yJ{lM(k4R%2f@WLM8%X)zK>H(hD1AK80@Hsue%X@%V^#EVj1AKK4@bC5j zKcffuEj_@Cdw@R-co_fEe^&s|UAtV}13cUVd`b`S>w17Yu+tiv)(Xs6b8|yu6r`$K>lzz`8A*_-!K-Onl&P;&9NB3%T_ct7;w}%W$x@5Cr2k1Px4}=lfCG~;xg#L|2O_) z&r_TX^s#{SGuyB8>gtYQ4}Au72>a5e>o7b7oEJ^HZBSi^99}`1zujk7Nysq-1-;*% zBzRvB>Np1tJPR=PZ~Hrx1UEyKW-Y3ckoX)g?9WYt+p&y!xk>Qk@xCAlo;==#li=iG ze}zeKJ2o?~Bnb{hc)zJh@N5t2IFTec#}50eOoI2eK!o#?;C+(di<00uN${#9xNSpb zFHeFe_q(PfIL9peTb%^&Z-EHcCBgHP;8!HU2PDBO+h2DpH)h^(df2Jlu(Q?QwWqTE zQTGw2tL!#_y2jj&XU^~lVoWb*$^HAf@Edb8(=>_wdnA1W(=>(sJ0<-^rfCBE?~?SD zOtb0tZ;|w6OtZ=NUnA*@nPyY(Unl8irrE^%n;n69C4D^8eVBG6J&|cP-Ts3g0WjuhrrBis_epvr z)9fny_egpW(`>r^J0;zZX*SvZyO1t@V|K?gpRVlqU1j^r2j`zTd)LmpW=5RKT@OVh z*fk14SN^cm!p=K6!)H3q)~s`?oQ0J|4uZ<|Lwzbc{;+cJR#1~>>U;i!%;?&;G-vpF z0-f_8VJj^yw&@3$zp(Oie-r`_eG~wJ%8rAT55=cd`W~-*=A+hpk6JHFEoV6BfF$^@ zD}Ms=J8gXzqF}rM3ON7q%zFXyy)B#`JctESW&1RzE%U&&DCZG-iv_y&oWK8Klwlke z7OCu5ySK8VZBJ##!rhg-D&my5vVHCDoK?dsJCC^Qc*of`j-bx6A&6IYmWL6uj>jLQ-Ng%;-%)YszzBlxJ4Ptv|MECcuqdx$d?gAH4k3(# zY20aTK(NqR6^Ldu@=BV0yUZSVON*bLLl2Jv?g1pvIe{2U!9Dw zGxM!^VKCLweWWzYj8nuL7khb6uX zrGcp}bzcbN4g%FVkn>;|L3}VsRJKcV?k3aYqRIe|oJV232rwDY6c@e*(4Tb=@ zcSUjqLmLQE0){3N0aR+F**FIwmuaN=?ltGz&Z(9`ODg@CDWeG|g{R1oubO@eR< zgr7}F5sq!U&uPmR)$V_qMK)HTZ5Hl@spNvsp31OQ0{iD4+FNgBqI1NaZO;m$vQL8% zbEj(cVS_S9z#L$6otd9cCA6EUkNjCw8JA&t_qOMhP`)AbriuzC57bYz2c7+qj^ zN2sWcg!+Vyau412eL6fB^Ajo@5nZgVKKxva5iiaD;f8g|VP> zJ_nvS8$cREs++TZlSfPdZ402)(o?+V;rI;MkO$4yy=ROR@+)-PTP)sL_M=j5rcK2R z*=IOTbLhlqUMevi%?&LXskWL`K~nZXsOWLWNgu2_GrvBIBI%TBCuEW7o_EZU&VE|3 z?L(F4C?k(sMDa4Kx+xuIjaDU>4sZLbmfkPMwk!VRcqu(HskAqpm$PI6L_f5R4nFAM zho;n*P%2RYurZUl^obBFyZ=g-Xy^F14C#Fb*7C_w!J8d9K(ywQyet4@)^pjK-rUG0 z-)GvFb!XEf?5C}d7_~2YzUQxKHp2i$eXSPU6%SGhpn1cB%1XI%*8dur2hI^H|F~S% z?hca+)q&Q-YBYO^g;=7Z^tzXeg&kctX|fjn!fp?*haHizfW@|fO5o7T>ey;|gKgUYGis{@JFzl5v}(6( zFp`RL95-5Sj*ro)Dz(DrDsdTJlbAdN@Lr?BOSGJs9yz(7qwI=bg2lN`F4&FPaa$Dh z0aiQ2O6#Fg4t2u(H=PZ8s$c!Iolg(de=2ekI)xA;q+kZs03xIxT+bZRG4@U^d{n1#2 zotbB)m68Uy$d-z4Tdk!oHKlf=lr)Xk0`qrOaE{?1R0kw3)|~hc?M%kCCJd^x{8Pw_ z*MaU8=bc4zjN@bhils}I^sr=;)Qi&TX+bB9{ydd3cSNz>P zO7e31+LuYALo-(@jcYv`_Xv%b(`ejaXnbF2?Bi4i8doZfiAv*ikH$qpV_%{+!v&+P zfC1X-LZR|f``VXCWusDg9sUd`Hsnz`MyR}Gsi544Fcws(4^XsS26N`~7Rzjx`#>fB z%`9~HH#7zcji=hzK1CW|Q5rWWjURb5UO2$oJY{PGE!+mXgGRRlMK$`w2k9DJhP?Qt zD5;kICZ}5V>(2ZQLci=12B7ujzSQV$IH@SZ7L{Ru;FM27p!HZNGVHc8bmmV}Dj#CV zB9+sH%A@UTA0?HWl*%4vc9y?^K&j*il}9ZVl-mbuK~3%fiq@oyd+8M0_!{!!_q=9n zB8vvC$)!TS>~032b*IR%vwiJO%5a;?FjsKO>kz068$oGf#ZD_jXa4t<${mJEolx1) zzIF$xd{?OimC7iON`+9_k)Sd`sl3kd46=+8DqGvvZY7o5mC8;T?8<*-N3VF-e#)}d zP_aFKjFIFwxonxc+t=Pr8h0p-&nk_tdNj5Rjk~QR;C+?Y+=pgt>@0ucxUds%%E8>? zEiockV(i8yX(wy~Ay%x3xdrK6@e|oD=xCS&_Ig{!S0I8};Beu!kfkwUa~{~o`E297 zcPbzHZ2McD>t@D#(g}pguVZ6j5f)k5e&H!lZ_x) z&F6Y$?}2{TFrYL)hp=KL-n9XrF!*VbW}9Vk$jxpGDmJ`+zjz{Dz0Y!oB7EM|t|IH7bDjuS2yZI=CY zB$Zm82~hmLKTu=nZf(TsMXb*&*7J(>8iM$>#Olm^X-b%;Nw<5OUGKN=^mUlM2A!4C zBi|u9HwEL3Z4-(60sCDeD z?Ck#-h|nW_f}{Ycz?N|#w3A~ zWuqs99W>tzIla*~`n6Gts^%bFD z2Ah6qgY`q)sOeG9wUkfCYCF20#DS_avzj8ShGtxX?7d;Czv#ffYX;g?3hFSvccnE@O>vu;jrk`t(Ep?v=yWvU$9IRM87PWj zYTMV;WFBEx>nwi~LHyX?ps#u}&~e22x?+7zvF;>RUt)D;o>L;GDKk(JOrHxUPA1QtBO@Lh$ zFF^o~%+CzAdz(?*wskxL*h3yH2eA8m#O(MbPxDzw^dJA79uDiuS-cllqg4F6zd{3H z8tvM@Hh@y}1a{_MgdC8)fB`D|5OO*y?7s3om1Csfl%I=08GH_uWMBD`p>m8;Inz-2 zj8NHac81)YfW=FL7?kIGR89~o*cny*mV2vnALU!pA7 z848tcz!KFN8gKboAG@>Lp_ykWjg20S?+Xp=>{Jr)zDz8vtP?1r*!WFY;LoPZx9k!R z)+w;Z0BiJMYXtTvV0j)a2AH;9z=M5?Fx)JJK1{&0!XJ?X#;-C!9bS;S+x_T|weDvLPWjacRDbt?(#8txM{O%y zr&Mk>RIU{&c0bBhG+5*+mDwJZMxlcJsHGB9D%FO{JfUKDq(4zAPZp3^dBCGGPN-l< zYN-rSDnkvGETM8&``Wv>uhpZ=vh_;kegs;h-~W;|x+_6tpJ0@|z<@RmjdfJq-oEyB zQh8csIZ1HJS0UI6h!g*sP`TYu*+v*De!ZcwR%qPXzV=qq*rS>6bEN1jpXAY4EHrMl zl7RQoV)HLmcE-r=THB%*;#j%zjSoiiNoZ*&9+&mc?X2~zXOJjLOcY_d{&Zl zujVQ=^C3V|x9V6p>763%K-u-NoY(_ofMscPF2sR#Vcf$%h_`E>q|K^37bEd*r!8c6 zuj7%1KXQzKTX6z_t4gxL6iYAas$+cb-&4om4X|}w1pJSw z<9-iu0ufCer(q$sv7(zgb}W1fI9Ph`oSfWf?JVm}OxbqLd7vK1P$(K){qOOO3!gGh zcR*nRa+nq06)9YO)?|A6v0SB@!^ZMIUnr&)2NF$fwIsRkqNyRsTxt>8cb0%TW=Hx? z=IsR!VCim}->2oqdgc1F91SmL{U1a) zPQh_9l_tf~znt>(Dp(qg_w#K#?D<7kSNt=0pf0x@g{pBCpr^4|H_L@INH1Wp!u6V$ z?KY(CaI(*OWY>`FXdz2sxMh%<-N9z{tQfK(q6b6yZ*;C5jzG&EUfgF`7=L8GwTZq@9Gp7`6qD;~oG zTKU3Q(aJ&53U4zV60Jy0Jg2JB3XVjml~l6%9@!d_?IUFWeyt23|8BIBvitcCiPG4l zjmibzGuh|H7z%2#k4X}nU@=()nLi}NoQNHWpfKo&@x~8KM2d!|bN!4IHtbMwc8deO zlgo$IptGJUMS3XEi~5benH3j}>+BgXKA zzGrv*#p_-)ygIVpgnU5BJQ@+njcmzl>9u_-N`0b)*357)}gv zx#+#%nQ*ooE0u$b^0_2u3&t{YrKDrw-uTPUKw?!VniE&(sK0rn0t=Os`)1ThIbvkU zjsK8Iaa`@|*>Pph`L6@z_~*c4qtkw9WZQU<-OIwFe`x8_%HtkxyzXBVx-yXj&9Xe3ln|g^t1s0K3GX%iTn+#JVo90SU1ou>;3-?;EOov{<<74{5=3Z`h@y+nHd%q29{ z*fs2mP@t#gDzi|#4}v+{`0C07jOh?~G)w^m&5oT1tuC|>U;eb+c6=v@>aaba9~=;& zW``I+O_#h2hq`wF{yC6D=61m;{{;dau1*4_lml>P0r6==WvWn#n*;F6luDaYxyGY% z=%=J&55OVImy}AUq4Fnm{KOG>yHc5;R8IA%{6MI@oOYOYx}otsp<$1}*DH+!eJE{t z(4)~HH0%+$-7fSoG%gSt_5gf?()hO0co>1|?W zkH#xMp+*u1*k#qGcoX_AT67N@Z4b%4^qi!3!vL|yA8t?O`zgU9kKmU<@IV=ia!s1mRCnM(mo3LZky5;}5H+4{UkO4@q{1a`@x-V{4!G0(>;-#D!=W;T9TT#E$yPi-hf&Xp?@)qsmEbau;L}fbV>kD{FLsj)ySYot_1AI} zymDVbIcvsmk+)1iyW&e=hxcLefPs@GW#mL;om$Q7yylf+HBWM(aWsgj)m*5{bdH`6 zAqQ5ojR7hcImni>E)G&h=32oizaD|=*a0PRaagOlS*hG;sJxF;@Pv!QxXzAMDrb09 zwmm^Ax7!N=0|HdD?x~!Lk%QLG+9-`(euzt}JuzG%E<>;^CTA zr2KPR9J|4Nt^MM2c5z{feymM)U^-SL+?JqEKqOg~9gl%CVfbd@WzVncEERnD;WOy|#eW=GBmwp>{0DSogJuk}B@iL;MF6e^>l@jNRDP`5*)qOz*t{kk3t(vG zz3{DU%lH%UEY0qC)C^KMzf-UDQ(ociC_H^D1}CRGf3*8+sij$T_XX+eQ8K>ZF&ruE zMHvVihb&(KkZti1x+9db58!=F&qHUFcxTx{gR+$%WS!3GnWxI!FNojh)4))n`-8kC z(ST6`adJ7skhngL%d0wK?*q!4nJUN`hRc2lleruMhI0AdqX{mqFHKJ^w&WA+mC?khBsQnr7zm@b30y}+wtB^Q0VIaQf2!izRKf%)%F_SH9q%zbrnyK zK5|Xs{nfW0LG4IS-bUuT=YEkRR?}Et7j3<;7_Z^iT^tLaR32v7xU}%-)(giub+zSV zTE>T4%1<2Aa#FU_&=_7(jSmMfQq#DisXitz`-4&CIIXly<{+zLiveyAW;n@#*B__{%u<(xfV*>m?Z>-OBW=LgSx?wQN*Y~OPq z!h6W7r@Zi~jmsNGI4Hi5S!n&C>(Qf?YMB!N#QX~*{S*bzC_`erg2y|q}r0rI6l0j zx;89dq<~d7URW0cs{B3!mQyvRe>KOJ)wQ(7n#1UfMuSdyxpuEHMH5R}!YyqzHL;eK z>@=|LdkNdd_d;OYhxOZ%G^tX0?!>YwPRZ)hk`kw=R3fELxYQ{vagJS@`a|YnprVOR z(Qy+ePMUP=#F9x^SxU1_!ge?e%U{~nJ5Pu@Vzal&j;ny+4d=}x)5N<{|1oPSs zgxe9mgz!a#A0o`fB49{{6qv~i*OERr_Bg^W1`!Ea4W)>5Z;B^ z?L&koV=f(nd94QFi3o2+cpkzgY*{{w@EmMoHY2_yanOU5k89W z33!@bM)(rK4D|97-a~nW4G3o<{2D^cKh94Pu18pn*HLdlcpbt=5&93IJi^Z-%)rJm z2fNDg2*)GjK6Ep}FCoMm9rE*Ce1_v&o$DLiJIlSsmz7I6u9`T`{aszh2!=ko$9J63 z$R_@}?Ok2-xm4?uJF8E@sX4t?x$B&1gHAYl(&&+-K%ANQ_jS-6O1$ZPaxeFvd_*u% z-~(&PuLbx<*!50?UcP@jvn78$z$d`oCnx7OO19+R0{H33zdAYJf2CLcQNSNS{s$@f z?|Jzz1O8R?qnlFlH+%URkb4mNS5N%;_FyscPfaOb;gz3>{6)zBMoRt-UVbg|pGST; zIsaVA*7}?LvgG`xME)(ve;wsFCFlFE^5{Q`{PQs$%tq+xH!#!F|I2`1j`1OuQohP7 zpMmk@$H@OMCI8P}{%GWX8{^4CDfv6R{F%tF#JF;MO8&RKe2!z!A^%WH{@Y&udgR}Z zap>BV{4aR=NB(Om`G4^8 zMB} zA+Pq2{8y1bE`|PRkN%^`KZx;lV{&=_<(_;mBmZ2uLeEXfKg-L{$iO&*{2No~U+2*u zjr_iFfelN^AL!-JM1Bs=r~Z;c{~eEhE%M{YADf(Cov7b>W}p8x4_WBL61LR}T1i z^3C}|pflsD%=Td5U;vV`o$GydvFa6LL}5_-BF`Bx(U<>Y+-Z#+Fb zh5XYn|MisrI`aErcfB{I{Ig#9-k4XPL_S|(^7seBUOS9O{?nLOk4Jw>Z(HA%lB(XmHH!p9PV$vkdptL$Nwti{|@z_+Pvq;3`FIBMuT9SPC&uCN$iD~qJr=`v^W?8b{s63#Hl*aQlYI80 ztC0U0Ad9bq2)b^}-eIm_$rcUouGQCgXj6PxD0e?mxSJqKOuwHZE z6Q;SR|K?{$1k`)DhHHv7{M9rKOH95X;lV2LXT#o_bPC*v#Bkmtzq@BfBpj$o?|Z3( zO*(ACK_-kZtdbb@!XK(Gzjr_Cf(OHKs{9c=6W?&XHAB-hQU2EXBX~LvmX`ASlL>p7 zu)u_(YZGUHDMfyJ&#sct>S&*-pj}tOiM($KkCx@ z?9Pk`yvwAmKH)Bt`rcsj1?j)>VZTqC&T^J%-?L1()PyTdc)1C$GvR-j@Lm%>Zo*%f z@D&rjXTo48A}j}(aI6WZm~fT}&obds6RtF2y1aiYy<>p#TYsd64FwwZRPK)zntyPh zhQm#NvG|o?h1>M2qf*lrZo}Xh%|CIhhEJN%=BI~`%u>8HM{8*F*DbEHQ3pni*H+L zxb1#v#gzVeM_GK^YM0w?-7Wqta5bttR~1JDV`WwvqDdq@hti*QhQ+^eMno{a)`Nb2(p$gg41C`z;Pf7X@$@ki z>8_#u9NYbSr{WoKvsxJV+$&Ka;Lkc80tGU%RtqqAl>jq;f*>O!lRm3}n|Uisz)~ZS^}^WV*6zL`D&ts z@(4e~cy8!)P|f%Y;{_q^b28p%JRIr=0vR7LUKo0p@edg<3032n@mI#Dh8B>{M~p|Z zmk`JCF;SV#g?)xk67#dqXTmRuMcFf@ioUaeU6q|rT0!4=NG#9pMPjaR31Cgxmyud; zNwjA3I6R||uL(J;v!hJ(^UXqHUH0!uEzfr*5|?F{;hE9jM?u=N+eo0m*Notb>_(Ou z;rk2_uF3u^#Tn=8MB@7Fb|#LN#Fp$UnK(ugw`Ol*V!R~o%D$e7VqX!;Y|Xxsq$h}M zJF~yRoKoLvz#esa1t`yT?k?~v$k@zEhTbIh*BEs|(-{9ctLui2Be|qKPvVFMDnPuJTlIkhnVBP4biNTvjlT4p8czdMf7B>*T5)i zRJ~v|<0Xn|aJ665)eO)ZW)IZOumb+wLLMnbNWbrLfD zJIH-pGonHFdn|c90AcsM?;sx93o7pUFN$a-6z$VgaBk=XK-?(F6gXL{f!Xh2Joqm~ z9_ILe&T_{*i)hg0*J}E|Of)_Kpa^aSFbdqF!5|vSB*)^XAcGTnfbj{-h!WaDDkYqJ za-A%;T+k)HJBsqS<#Sl}IbxPmD^BPU;tSXXDq#b1-RaFld!1R+740h$XK9xR3$FDL z7Ceop6B2|4KNkcy41o&WGnk_-wSWX2X{j^W5V`q0l5-b|W)wepn zlYJ!R-?V%X+sijo%KJCff;C(8$YYS}o9bg{IonVT3r$kJ!lQbep}O1|d_0Qz3Vn~} zM+8rHeu()tKjvWd4-4k5$g8& zBs**f-0l%Lg9Q4pHhxQ>ppnUdNzPY=WP0?5)>2>ZNApychdff3fYdP2-up&*&d{?- zDqho1aX<8Mc|b5+6u;kyttIzs$@$?1$9I53hksMmh`pxxY*Tz>6WipiPRU;GIHOJ_ zmtPb8qrMSAipdku&D=^4YbixO8w>gw)-usc%n#Q&zJ1DPxik6%YU&A!a8It%5l1g* z`8NNNbTF3qo}h*LH&qU!jryKcs*&NeQcVRmZM`%sdU(pzX3R5&+$lz^?|_)r;-|J2 zV~#VTPd7L}@o=71oGNF;WobA{<2lV=gtLTO**4p$($R+HCPU7*`6P_0BSq);tIn%N zOiq(a={;y=az^v+i0}JEe={c{lsIYg=i7WG=nX%L48N}`fod_p`hK7)nXkO=R$j}U zv3~{?-*=e#w4oIiN~E=owAPW$dKHASxU*<4VVoHhgUnCfqZA%FP8y5q! z?>Z~MNhEkZ%YtCI8Gi-ArmCEyikNxzD}5p&#HpSr3p}D%o07wY&NZ5WS)sB`Jh?DjlMM}e!~fSC8qRjzY-r>t(`;x?L02~$nn}P;-O%(a z0*L?en3uYj;f~(!Wf(VmnE{}ex|cZ)nPxAu0@0v*3rm{44C7`m^9)OddfLnM+X_tn zOA)070JDvG0#PjD@$COgqVWL$x!Y|_UvTJV8?%HcW*hSW;@HOQLlAU{Z?`eiSys0( zREXWi5X@~1Vcf>>Z?TwdjH2l_M$x#9>F^L1Jcg*<#{5|5*li4R%r-{;xQlLM*ajcB zjUnlv%d&PG^B(Dl(2JFsZex_0|7zwI`LI_watS1H*CHJbO+FR?VIC?w8Br(nRpL$I zl$IM>$M~`Q<7oxp6+{?xSzthJsEkmld#H>cty-w89C50M!nhmABYVV+faNd4ZL92& zY#=9;1$g!-t`>6h`In=zN6$mNz$y4TGJKzAdxQcz7gYfWFs1PQklaIoeFiv?2dKWS z_DCmBFag;-=n-aomQ}QVZ0P_<`!*ksmEmAc#Fx-surnAeOS(&m?cY>Cq;yaOG2EDv zr{kQ2DO^!LuPEm^Lsq5XEb(xzP@F~1koygeotQ88a5@y{OlOF1a74IRoZCE{D-~zH zGo-@cSb2Wx;cQf#xz3O$(s2Id;e1JPDxD!YLzI`LGXOgSt=E?oXQne`p~1289Pi;= zr#KO3$XC;Fq8`pyh!fbf<5FkH;GwC^ctuN@ZBeAHK&nnd;(kVvZc?PXf%Jzoq@Q|7 zw<*$HKsshvD!aEmr0*)y?LfLH4XJ>JAZ>rUBHenaGxSFW$!b6m?ofnVF2!o^KWJOE zw4F!HS&G~vLDhYm9|XzaTn^Tn<=}AH%a~L|%x)=>u*n#Vb>cFbKX(;_K+d;v?Le)@ z(4dJ}DGFq-y24x31>FnK6GqSv<2&0P=_~{-{(PH10*8?=P|mZ}#uo|a#mafPGl%hrCx&*NC{Oc7)81#a^UfAnm-u3 z@A4whtuLCvDZ@&hK{|>+X zrQid=H}3nbi24UW$l&Qb4G>R$@HR>!p8ViS> zkga&~L(>=+Pkty;jIqe9ZKf|qTo%5e85O|Lg>T4s^7~B#i2w4KClZ3{n?k!05MB6& zCNVAx-_Ybj(xwwXWS#hPkSPn_(6~zx4Z8QTq%3?x=P@n|-_ZHL7pb`L4JA48L&k~U z?@3_tUy3Lj0FZ@m=$ID~4Z6R@v;XTv;{yP4*M)DWXcRce!Z%d>Yt%vg_n`@`M3IGW zsALb~Sor=4LC__>E__4f3s{zG$WS>Iq6=RIb5%ze7Jt((CK~Ps&OVfWJ zT5zL>u;6(_&FXN$uLMCCzM(UiqifFvBq;v-(3xxlUHFEQ{P!Wxe^1gumt}R~8(Qq5 zo2bx>mDwYdX0c($m1sD7)Nw%4Md)ZM%L(lRJbMhmW)V7e9>84aQm01_LxyiYH53Xs z=Egz6WCB081b9!3jNpki0p>RTe4Fwpe#f(yE=wzzm$QU;$RoUB(6FPMRcuZB_- zk5DRdUlf#lo0npJI24BKt6|3tY`Wr-VIoY7LuExaPV0Tw zr6SESN_75_vb-2iI%v5gUt#l@RAdnMD83>NUs%tOeX+8yRdq}+GgTP!OLJvruBnSQ zTDdkF-0My@s+Qq!TsO`)?u{NpM*1}ko@RcsDuH6UUzPB5-CLFLB>P{tD*5C#L5^9D z@Rq@U^=*QF8SF}-2@RO3@?Jz|aC~`BF!1LsV~~;8#K6sakU?%9Ujuf+d0ezRkvzUO z?5yj*27#~ty?FZjUxsH!|DWOM+N%m{WG259&wTbo&dCFc5E;OI#sKoSp1p4h=6CQs z@&RHIJsImY3=dhOo)E03@f3P*c$jHK?NxhXvN-EDYU z&mQ9idP|{&vrREYKL z5zGY+VFTgW<384S_7qJ$dx{2x1)LxhVZlhLuplfb6uYyYJ?0qCo_OS>ea>VX5bw3jP%3Bx<+lgJjw)WI?QBhRZ}b zj@^Ksjmr&ZI~xv?B}^GR6_!AF&cumZhI1$8L^B({0m&XiM*1bhARH5)%!W`*_p{+A zd-Sh!5B$j<-T7pXj*;k-J^KH&Jvwip{o{LdIn(M@bSfr|q%*Bvlh*+t({8V_s}R*Q ztzJ{O@6$7_UdP@6IJf$zBMiDMFd(;A8KE+%_bMYuy%xR7E=OFv9|#LRz{9sx{Q?o| z7my>WUyxWRP-TF6MD?P5+bI2rN=_%dR~=xr{P{NDgngfQ?C;R6Z$wWazPALq{!Md- zym@qlh~5#^+0dM#+(#5Wf+;&DLL3i?Z`mu-HbvqQ%xBV&Zt{?}D-w@j9x_PNg`VR) z?jh|^Bp$(RA0LtIlMNDYz9_pND-w@jd_}29xvZ!h!91l%ID#2+N*Yp`hx8Lg!ZFN{ z&NQTRJfxp0(iR{+n}&3$hxD`}ZN`buz+#oj)=uTwqX^gY#HSop@m){AoNOC)$($kU~h=tWofjE3_G!CCI9X=-`CluH-OX&{1(=cd57Jqu8 zu|-!)%W0;b!-pls;nUm6nuPeUUKI0UN^#dw5heTSREf%TryG&?6Z`N z4xa*X_^f4VI(!Dx;d6;~_>2;V&lk&#aL%xyWK~b(g@#qa;lmHT39EXtqGO9buLe~C zu2YG_=e#G!s)!p!P-=2AmUpVj^Hh^s@Y6l%MBg5(ONi4Cfc5_?QZ~&bL0M<*Z|o*0EM~e)2e@r=howiAW8bO+D2zPEyOD zS7{=uo#EUJ?VEMNhp(gU3n=F06nziH9u=g%zv4@NaRqG*lW7;J zOQ6NTdPb98RpI?J`>Kk>^$i01#tP3+%o{7yNXopiavh@fjTOf28!L?4H&z(8Z>%tG z-&kSXzOll%ePe}j?~N5Eyf;>u@K)7KcyFxKLOjpMbO92ckBQQHZ>%uky|Kb?TX}D+ zEJ4D1W2FuW?~N61guIilbx3$8UzY*Rdt>EGNO*6oFyXzi!i4w63KQMGu|nCrH&%G% z@31#kSV?o_#i%{oLiXm36^ZH_D-xZ;0)r@1@5d1J!B>KFuJ>4g=Ul za`a@2tny|7WF0^0@2C(xFA3{4kWP6=g$VMFieMI{qFcw$fBGGjfBs4rExFK1yVAu9 zLEHLz%HO`yMH+ZL<)69IMcvxhQ%I)3NxRZzMEO5^rAw4z-b`UUjCT1?T3mgm?uvB2s(yf|biS$r#39|O2uggl z%n|8)u}Ol|3(Gg(Qk9N3rF_d~p=?1&E?F;U_X~%3tI1bKcp>B^pP)-Z1?23jzJ-hf z_T}LLxxUz$fJ;?;F%^YX@x@e>fvZ_+KNUN!EP|)wydY0NH-C|2Wzm0tO5mxGEM;FO zI^Xgcyo{w^dSY@!%2dgdB_9BM(DGWmkeLLA>v!dKL7>?v_ z;>(@kACW^niF~mnBINhVlXV`4g^bp+UgfJ)F7?VKqFm~=k~>T#8P};~Ww$k?|DBG7kwl{+95H46}ncGN1xkvHMvRt|M@ttBdJqWAh*?Re@Y7p*o zovLVyl;a#VgnDNny_;C&fyIqv^!N;CX)km8K1n_jCH^# zZ#Kge{#U-)%qvG(N9mi*pGI8I+_I)IE@y68k!l!#PEA?UuR=VxA4ZI<8LNR2?#I1m zmbp}v$5)y8uRrtp^P~my(MZIDE^jdDnOoK*#{2QiEo<_*q}>l&^(=d-=n`bgnOoMl zA4tjlEXjkzaMpQ@%b8o&`En0mZqsKaT`I~lmx}WK3QYb>5oId?a^{wGOdl`~y8ZFY zAC5c zAjvAHLUhVkFx_f|4am)!eh1NbsVHl@qH#LTn$FU^RFt*gryjzBY>Zv%p37R0i#V1J zVF*;1bp~@}>5#R61RZIgGuZ~Y{dne0OLN8Wk^oV3F zR%S;Y%b8&!s~QSyv0lLG1Wuvy=1qx!b@G|pr64yDP3x1Z^_=zxiC1A1t7-?_IZ}vY z^S`%e-;|p+wXsJr{sU`7b^5lNv}`tlyE#YpTGFzPRS>CO8)*kCGHYTA%&q4*I;v7 zz&E!-BY6SGDOgd5_$Yq#CbwWk^=c0rBF=GD2lxkX=TQ&imPA&m+$D1BD!X z2j|{1^%BfZGa(O_4bL+qhBwCyaEQD)_6z&*zr?ZJPeoGFT2Bld4P z&l$ct4Ts;hP@Kz@%pzy_18F!e>Z>^IigTtjJmYxfHC;I3gVP?)dc~RV46jVXp?^W? zY*3uJ&hV?!a9TZ_%N3{68GihU%Ijpq>#H7)eBp@B2Yinq4e0?7>6;{k!zUm;o`&>$ z59t;~!s+4g-sP$6T(*a3`acv2r-#GOFi5ukJa$o}TNMeXhr^prN~Ls$hh)x1ae6rX z-ZZ3D9+Ej5#p&Vj57Uq~dq_K!9ZnF3&oG}OvwC{SLwZ1wzI3S*zQQ0`!Byx772%po zaj3@car&0CuiZXXZEMm11(|FO0JxOa3Ay-<85SyXIss_tZ+R54* z=WC^A8X1PkEwl>t04)mt_SlGUnQM3rmRo42cOuDUxHEJuD_=--yI_{D(jx8Kd_BY( zMW0ZiGB&C$G^!mX+8jqLc;*Iwg_MrrqLP$@E(LOYs7{8nv5&Vrp92$k3>oQPs%yen zkC$1wCcBnQklD>-XV;jA!YJe+I$k z3tsv?uPlBCD=^{~WMsOx;px`n@d*Bf*6|^+6A(l8XYkCrjV&?qIRX3<&+Iqx2(eHS zu6z_KFzS85a(sp=Uz1SGb*bpR=(Z{dj6EF)z4z)@cX#Ocio@PWc75OsU=b6$aQ zv#YlYt>xE5K zE{ynsbrPT7SG=eur?RhjF)v`%VZ{AfE{3O45tsMlw|`cU0eer*n{4p&n7nOz1W$Yv zTAt)L4ca2V^9(=bVN&yz$9c+QuJHKuI+TUs2#=`8V7MBM50+F3@zoI!wQ_D<(51B_mJpG-!~jffyAG0^V#62bva2(E?4PKQXW;R zv6Ga?c}`A{WRD~2Wro%Sp+s8W1TB^KxOD(hFVe!trO-Og(#qdXnI@iY=uGnH4CqHD zW6lP^_SUGE+4lpM8bfm>gI6T=grutaPGiBbG+8>-ov&bM&2XN}@dkky@;M0HI3t25 z{-^}3lfU`>Q9^s{R3yz;BtJQ!x8IcHS(&$E|Kx=JNEmv?%^VW{r=8IMYkaLVhe9XK z*UEDd%)WoGuaz`#%>B>!T4z!5@)gFcD9IE!X}(q?%Kuqkt0+Z|xwFn=mw4`IjJQB*!hk4)d@f%v;@j<1l;SUOO#bsMJ+)A@sV((OB% zErT^1qJ4d1`sDQr^cmczudiQL?va2GZ~}df?{z}2*;tYVMmxQForHY!G!w;0pP2(F ztc(G%vc@_L+&o{PPp@7q>q9bhghyy9u(M4vb9Nq+y(}9ncYMCtc`R|n2+-l5o9&Z_ zq9+c-qGqzvK%r>^3CJ}7@Kr$H5vX#%eBV(6l}28s$kLw>(#!{2SF1y|1M++c36CuH zO&chc&17+EAX4y^8B(qw)8p(fz*Zc5Nd|&2IVd3)lY^59DVgh(%#h?9%fjRh_40Zh zH87>rFfcblll*Wa3o6ZI*vMj%BYL3~c>p{zp&O!&Dn@g#=7-g7bTZ>Kp~fgRs%~s| zXhuCpCFi9mt}wwirB3)ObSh3?%=Sl9)Y*BH2U5`g>sFZWu!S&yrncX}VxzDmJL+-hmXX=F(@7fx=j5ecR#Z8|d5FuSohnEEFToZ7AhAJYf} zQx(c#CaF!>!d|a2?TbBpYQqgB#*8fN0ZtWb7i+JH9P@NYALRlFwUCgq_>{KYUzK`c$zvU z<|Uf6zmA?Vo>CL3t88`h3ek zZYX6dny}4~+Ge($*?Xn#QhS?iDJFC7506L~tL`uROm86ZP`Nd8`p_(IO%7Ek&R?(k~Hdw(WE6gfJ7Fig04ja%D8+)^u zOIzDH55ULhm&@-y-v@n;aPX%f=&Z&+--Nc7<_Yz6OC~IXhh|$wl>b4Q;E7 zmNm3Zm@=WRp{BmAHs%PPNgR&1q^`9k1;r`GUxBV^tgpi#tS_zsFQ=uowl=o37+1*g zvelZVSPP6Y#d+%4yr% zwwJnj6Sw43KYVy?`4jFkR^DG@a4%k5+TOOZed4?B-Z`c1s=96}(YDfE z_Pse1t#Z4=*s@(nYF3I;KNh|__{8>Ab0%(IKjCb_b6HgM{OX*E@A{|Yx%iLu^97Z( zD9&X(BlytKpL3VHqoyhA?$npsV7?$R{Y7ru^mp67*jA?vvQ0QjqnQR7;U2Sd$DBly zb%XKuG+C({MQiYm?WO*a`Cy|huxe?f&@1f6V4&lQ*dbGkOV_V*=d^9#B1ryG6fEGSc&$m|=BCVD-{KuP|r94FCr=@!{Sl*rx_}NSNARW^PAkX>p_Ie|l+C!_^Yn7c&6c*M8j#qu)F0{e>L; zZaUjPf%8hYtvIJ_yW1uTdxz&`P6%rIx6C1p|Hu^buk9dUoxEoB<`?SIeh-5E<#OpR zh0=3m}}ibPKTdh{u}l`=_@B%wtaszaFnmzKPfNbPQ&`0Ya5QYZ5+-Kp|J*KGvF4@ z)jdLMaG6=dFm~sT@`?X+$v{rATXH{o)%I^}zXLMd?;qQLPN_TD-FxTu=iR;Ma!K#k zjm+)AFOF&hNW@B7YU>)`9TB+j7l8rcQg_*o`|tP%i-KeZc0Ay}LF=ajvZe~Mj^ub#1frMtm>d;6*#Peqb#IMr-)9Sq_PzUd+bVZ?Vj3APTaoO4*EE7ZwEVBDa?cJ0Z*fI_ z-A*29^Rm5pjCsVJc87m#KIZ0|JYx>%RzHY8RSIKlnX}z&$4?Bp&7I(G zD#ha)5%&W1slZJ(;f_`ACOCNJV0d2U-ogB70)Tk|Q0G2D@6X;jvXbQ0aKGF$|L(=#e*U`Cfzx5S+K#)f5Kd9*dO)Gcd>)rR@E=0OFd8)B=R zXf%aeZQF{bq(a1vM(3YVapsweqq7#CcJi6CPd_ahbtWutToIdaajdyyLQ`|&1+kje z7P^7Osu&@In#L7P^|4m11^$|?)l~X7fqQQE?O2YI=v)Zv~>RLla0!3r9@^RUx)_aF1*1(4Mjre zb!l@fruc`6ydu`TEGC6#&7NBkZK`i;k<_Z@y4IMOLb~Q^8r#qaEpTZ=M6`B`u>$bn zR|CW_!YPeQgJ`K<8B+_uOH#0j`o@|Iow|nF7#mcyInjx(XoPDX(l@rXI;|IheRFK3 zL*WstTS?g^p|)yFtgayn+~v{wYM3SMmHSJh9Iq&BcxhXGy%24PtyThBMQI}lNP$c* zpeCGXQzO;q`TScOFT`ty5FybM@b*6XNnJe}Sv7CAdL1-Olr{?H|MKQqDqoq~&gfOj*^vTvWEOV?b*-Q`& zbk$6xHtD=us9|i0P`J7o%5QD1S- zL$h=%A_{_OceP8Fz#KvnH5^@mRo770sx&c%po}9;ucnx=UCR)6lC6!4->n8}$4OaD zbY-;;k8s8%^GAv{V5C8cU$97|kZ0zH*$b96S2rz(1{bu@wZuquebe%4Mr!Mp)v*sQ zSW;iza3Ld2Z4EV^7Koo#P2-&sQX&t^)HJj<*R$|yk6wM_Dw%-5s-bNK^V*u46oL^% zTE!?%+&7KMx@}b5V-#y9^W@n`qoQw@pDhv)Xbz~!I&GHxrtP8bGo!IIoOnNbG4Cc!;tz@K&uu2>r z4QbO6OiD)zhtnShR=%pJ zBV|2mW?P?`LZzXW3lYyc0f(hCm$OX6ir5O7)Xf;z*5Ij577#ira4AtE?cv~D*bX@W zqTAHAH3`sET}qia5DeK=qA1nCVuEWGNWwO*!fIJ|%f?nzk?TBp=weS+W<5Uwbffzt zham*8LLJgAJm8$zEj+`i>K2~qtm_sYbZ*UvIO)HDljYoy*&W<OYN_z}*!Puz-wL2vz z{9qa!n@xe2WJeH7{AMERa}xTY9Q-Z7KVLWPcroClKR=Dm<$`~>J$wuB?&@`y;O98= zD{l0x70=db+e`Vkw^;LMxz}SXf6VkToH>(z`rlRk zi=m(X$65nWh!3xfd4K5G@a+Y-=y_m7AolMU4>9=mZy<*aet(0X{>P9<0RD0E+p|9V z_tLDK>3@)|#PD?%R|!X6=;d#!z;hh?C+qqs*!k4o;A_vI$dA7zhJHAWe*NE|W6xgf zx45nT(?1Jt>y`f9@rw=LNE+YI2|UNKUuHi-#dK`Dq<^&Ewo8?v6E^s^UDE#ozzsdr z>)S@2b%qYU)+N918@T;+sf9ldIPE0;1Dekoc>3o%e+~G@*@N}k&M|!7G<>(D>E|y! z&~fFYU&HNaMGtfZ=4Yk z4R|jTBGnz8i6VbrXXir2mqK_%1b+Cq%KYx=%mqH)-#ctx<6rgh;a$h{`D>}cPoE#x z2>kGQ_9~%s_`G&A;QdhFyUcto#UaTL47?;KLcyGG$P?c$6}U+x1uq%=^e>aVVc_Y1 zfau?j z{;2|f_M3W3{~W{Ddf?P|6=Ye1AjDM@vk-bw@bSpzCPsV zExT)9{#jkhQ`1lBd}!!=-oVrUq{UYae83Tk|AE2(ZV&VyH27~Cd$ym?;Csm3$+O?m zpP}?O82az^fX~lEc1H(q6H2|(Kk8i61OAL2;MG0A+W=>~r`zpiJ>Xv_@FSedB3du| zxs00){Hgv5KV<6rqaNt+16pjavyGjE4gLYZZQOt)c;DcsfB(2|5aR%@e&4#NDjD73 zU*7FbpQXf4+FzhK|AN!k(m*J#0>lffty59un6{_i}9`SoT?-!zBp~@q9$Bh8qqbA?n|a}CgYqS5$HVvU{O)~s{l%$iZf$98Te=jUkZAPOlh26GoxR{poZi5( zYaCzE))mnj91q2C3K6Ysj4rEhTvA;ht!-^=Zi!a6txmX4i>DlS>~Y;A!S&lv7p-n? zu3m#9nAYYsI75IhmHz1!YfvO9rS8&XRO@gO84o*XDxOp_iH>Txh!Wmoap%D~lj?Qigl}?;w3Bhj& zBI1=yavypQ&19dVag`-G7(I@j+mH7-jEB&uL!EfZPCx6=)6$;n%p8tJqqEMKKCdEL zaoS9niQ0^fi=*4N9FAaSEYoEbfH`V5?Yp)Ae{;WKP$6C0vmHqp$ zU|R>WoP!y~q`6mFpVK_xv(b%9|(Q~QtZVoLl#J4n>djr%{ zP1Bl$Y^68?@*?_aa@*kKt=Xmc2Ym*Faq~HPX!aaO^;SE zP9VL4$>%a+c&51yD{2MZYX?@xy&pGT9Aa@FxZ8pZHoMqm|62M-Q0Rxc?7 zj3QBL$cr9um~IlXt9s<>S#${pxCHJb$0=@EvjV4=2w{N|F1IlZw6W$Ur?{c9HC8-* z#_Xcj>SZQ{Eohkjm4OXxC0OW61YH9!OP>J@c0VBH9U zcoYj4r3iy@iZOVt;Pr@NV|2~c4a?A?CRx|8w9&?^mn`8;36mqogeDGs9loCXMy6KartQec*onu+Hq{KL}HD?h{^K?;9q#t;lkD)F%UC=1~y8I#MO=#NO& ziKhH$NhKcXd zr_2=l^Tu+*KNgf-r0)sRThu8x?|`<^k+2f}Iz{B7&t4m3I)tGL5i>g=Mf( z1Qjf_un1z|%+7p=&95sS*vuKud^6{^Tg*UKG66TlaRR!3m%>vY9Ss9GlLct}iJ2|g z|0nPDIKO-Fa z+)v_j51wqS8J{|Dby#DT^O$e&$XDU12Tzl~n#are!+!`*er|je;3(&hn;xB%pC;WG z>o56-<1pAvJA|&s3%wp<8v|tWee{$}2idU>{ibO@`Fj}@b)nnBFP?|Y%L89G_0%5j9p7)C-f!_Iele|W0fhSFtiJ)|uNpZ3 diff --git a/lib/ecoli_log.c b/lib/ecoli_log.c new file mode 100644 index 0000000..53c3acb --- /dev/null +++ b/lib/ecoli_log.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define _GNU_SOURCE /* for vasprintf */ +#include +#include +#include +#include + +#include + +static ec_log_t ec_log_fct = ec_log_default; +static void *ec_log_opaque; + +int ec_log_default(unsigned int level, void *opaque, const char *str) +{ + (void)opaque; + (void)level; + + return printf("%s", str); +} + +int ec_log_register(ec_log_t usr_log, void *opaque) +{ + if (usr_log == NULL) + return -1; + + ec_log_fct = usr_log; + ec_log_opaque = opaque; + + return 0; +} + +void ec_log_unregister(void) +{ + ec_log_fct = NULL; +} + +int ec_vlog(unsigned int level, const char *format, va_list ap) +{ + char *s; + int ret; + + if (ec_log_fct == NULL) { + errno = ENODEV; + return -1; + } + + ret = vasprintf(&s, format, ap); + if (ret < 0) + return ret; + + ret = ec_log_fct(level, ec_log_opaque, s); + free(s); + + return ret; +} + +int ec_log(unsigned int level, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = ec_vlog(level, format, ap); + va_end(ap); + + return ret; +} diff --git a/lib/ecoli_log.h b/lib/ecoli_log.h new file mode 100644 index 0000000..f46f6f2 --- /dev/null +++ b/lib/ecoli_log.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECOLI_LOG_ +#define ECOLI_LOG_ + +#define EC_LOG_EMERG 0 /* system is unusable */ +#define EC_LOG_ALERT 1 /* action must be taken immediately */ +#define EC_LOG_CRIT 2 /* critical conditions */ +#define EC_LOG_ERR 3 /* error conditions */ +#define EC_LOG_WARNING 4 /* warning conditions */ +#define EC_LOG_NOTICE 5 /* normal but significant condition */ +#define EC_LOG_INFO 6 /* informational */ +#define EC_LOG_DEBUG 7 /* debug-level messages */ + +#include + +/* return -1 on error, len(s) on success */ +typedef int (*ec_log_t)(unsigned int level, void *opaque, const char *str); + +int ec_log_register(ec_log_t usr_log, void *opaque); +void ec_log_unregister(void); + +/* same api than printf */ +int ec_log(unsigned int level, const char *format, ...); +int ec_vlog(unsigned int level, const char *format, va_list ap); + +/* default log handler for the library, use printf */ +int ec_log_default(unsigned int level, void *opaque, const char *str); + +#endif diff --git a/lib/ecoli_test.c b/lib/ecoli_test.c index e3942c6..3f1c4fd 100644 --- a/lib/ecoli_test.c +++ b/lib/ecoli_test.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -57,9 +58,9 @@ int ec_test_check_tk_parse(const struct ec_tk *tk, const char *input, ret = 0; if (expected == NULL && ret != 0) - printf("tk should not match but matches <%s>\n", s); + ec_log(EC_LOG_ERR, "tk should not match but matches <%s>\n", s); if (expected != NULL && ret != 0) - printf("tk should match <%s> but matches <%s>\n", + ec_log(EC_LOG_ERR, "tk should match <%s> but matches <%s>\n", expected, s); ec_parsed_tk_free(p); @@ -83,9 +84,11 @@ int ec_test_check_tk_complete(const struct ec_tk *tk, const char *input, ret = 0; if (expected == NULL && ret != 0) - printf("tk should not complete but completes with <%s>\n", s); + ec_log(EC_LOG_ERR, + "tk should not complete but completes with <%s>\n", s); if (expected != NULL && ret != 0) - printf("tk should complete with <%s> but completes with <%s>\n", + ec_log(EC_LOG_ERR, + "tk should complete with <%s> but completes with <%s>\n", expected, s); ec_completed_tk_free(p); @@ -123,7 +126,8 @@ static void *debug_malloc(size_t size, const char *file, unsigned int line) ret = hdr + 1; } - printf("%s:%d: info: malloc(%zd) -> %p\n", file, line, size, ret); + ec_log(EC_LOG_INFO, "%s:%d: info: malloc(%zd) -> %p\n", + file, line, size, ret); return ret; } @@ -135,14 +139,14 @@ static void debug_free(void *ptr, const char *file, unsigned int line) (void)file; (void)line; - printf("%s:%d: info: free(%p)\n", file, line, ptr); + ec_log(EC_LOG_INFO, "%s:%d: info: free(%p)\n", file, line, ptr); if (ptr == NULL) return; hdr = (ptr - sizeof(*hdr)); if (hdr->cookie != 0x12345678) { - printf("%s:%d: error: free(%p): bad start cookie\n", + ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad start cookie\n", file, line, ptr); abort(); } @@ -153,7 +157,7 @@ static void debug_free(void *ptr, const char *file, unsigned int line) } if (h == NULL) { - printf("%s:%d: error: free(%p): bad ptr\n", + ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad ptr\n", file, line, ptr); abort(); } @@ -171,7 +175,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line) if (ptr != NULL) { if (hdr->cookie != 0x12345678) { - printf("%s:%d: error: realloc(%p): bad start cookie\n", + ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad start cookie\n", file, line, ptr); abort(); } @@ -182,7 +186,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line) } if (h == NULL) { - printf("%s:%d: error: realloc(%p): bad ptr\n", + ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad ptr\n", file, line, ptr); abort(); } @@ -211,7 +215,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line) TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next); } - printf("%s:%d: info: realloc(%p, %zd) -> %p\n", + ec_log(EC_LOG_INFO, "%s:%d: info: realloc(%p, %zd) -> %p\n", file, line, ptr, size, ret); return ret; @@ -222,11 +226,12 @@ void debug_alloc_dump(void) struct debug_alloc_hdr *hdr; TAILQ_FOREACH(hdr, &debug_alloc_hdr_list, next) { - printf("%s:%d: error: memory leak size=%zd ptr=%p\n", + ec_log(EC_LOG_ERR, "%s:%d: error: memory leak size=%zd ptr=%p\n", hdr->file, hdr->line, hdr->size, hdr + 1); } } +/* XXX todo */ /* int ec_test_check_tk_complete_list(const struct ec_tk *tk, */ /* const char *input, ...) */ @@ -239,15 +244,17 @@ int ec_test_all(void) /* register a new malloc to trac memleaks */ if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) { - printf("cannot register new malloc\n"); + ec_log(EC_LOG_ERR, "cannot register new malloc\n"); return -1; } TAILQ_FOREACH(test, &test_list, next) { if (test->test() == 0) { - printf("== test %-20s success\n", test->name); + ec_log(EC_LOG_INFO, "== test %-20s success\n", + test->name); } else { - printf("== test %-20s failed\n", test->name); + ec_log(EC_LOG_INFO, "== test %-20s failed\n", + test->name); ret = -1; } } diff --git a/lib/ecoli_tk.c b/lib/ecoli_tk.c index 6683af7..e814b68 100644 --- a/lib/ecoli_tk.c +++ b/lib/ecoli_tk.c @@ -113,7 +113,7 @@ void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk) ec_free(parsed_tk); } -static void __ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk, +static void __ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk, size_t indent) { struct ec_parsed_tk *child; @@ -122,22 +122,22 @@ static void __ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk, /* XXX enhance */ for (i = 0; i < indent; i++) - printf(" "); + fprintf(out, " "); s = ec_parsed_tk_to_string(parsed_tk); - printf("id=%s, s=<%s>\n", parsed_tk->tk->id, s); + fprintf(out, "id=%s, s=<%s>\n", parsed_tk->tk->id, s); TAILQ_FOREACH(child, &parsed_tk->children, next) - __ec_parsed_tk_dump(child, indent + 2); + __ec_parsed_tk_dump(out, child, indent + 2); } -void ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk) +void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk) { if (parsed_tk == NULL) { - printf("no match\n"); + fprintf(out, "no match\n"); return; } - __ec_parsed_tk_dump(parsed_tk, 0); + __ec_parsed_tk_dump(out, parsed_tk, 0); } void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk, @@ -293,20 +293,20 @@ void ec_completed_tk_free(struct ec_completed_tk *completed_tk) ec_free(completed_tk); } -void ec_completed_tk_dump(const struct ec_completed_tk *completed_tk) +void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk) { struct ec_completed_tk_elt *elt; if (completed_tk == NULL || completed_tk->count == 0) { - printf("no completion\n"); + fprintf(out, "no completion\n"); return; } - printf("completion: count=%u smallest_start=<%s>\n", + fprintf(out, "completion: count=%u smallest_start=<%s>\n", completed_tk->count, completed_tk->smallest_start); TAILQ_FOREACH(elt, &completed_tk->elts, next) - printf("add=<%s> full=<%s>\n", elt->add, elt->full); + fprintf(out, "add=<%s> full=<%s>\n", elt->add, elt->full); } const char *ec_completed_tk_smallest_start( diff --git a/lib/ecoli_tk.h b/lib/ecoli_tk.h index 167a528..490c5e1 100644 --- a/lib/ecoli_tk.h +++ b/lib/ecoli_tk.h @@ -31,6 +31,8 @@ #include #include +#include + #define EC_TK_ENDLIST ((void *)1) struct ec_tk; @@ -71,7 +73,7 @@ struct ec_parsed_tk *ec_parsed_tk_new(const struct ec_tk *tk); struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *token, const char *str); void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk, struct ec_parsed_tk *child); -void ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk); +void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk); void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk); struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk, @@ -112,7 +114,8 @@ struct ec_completed_tk *ec_completed_tk_merge( struct ec_completed_tk *completed_tk1, struct ec_completed_tk *completed_tk2); void ec_completed_tk_free(struct ec_completed_tk *completed_tk); -void ec_completed_tk_dump(const struct ec_completed_tk *completed_tk); +void ec_completed_tk_dump(FILE *out, + const struct ec_completed_tk *completed_tk); const char *ec_completed_tk_smallest_start( const struct ec_completed_tk *completed_tk); diff --git a/lib/ecoli_tk_int.c b/lib/ecoli_tk_int.c index 41ed54a..6296b8b 100644 --- a/lib/ecoli_tk_int.c +++ b/lib/ecoli_tk_int.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -123,7 +124,7 @@ static int testcase(void) tk = ec_tk_int_new(NULL, 0, 256, 0); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0"); @@ -156,7 +157,7 @@ static int testcase(void) tk = ec_tk_int_new(NULL, -1, LLONG_MAX, 16); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0"); @@ -180,7 +181,7 @@ static int testcase(void) tk = ec_tk_int_new(NULL, LLONG_MIN, 0, 10); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0"); @@ -194,7 +195,7 @@ static int testcase(void) /* /\* test completion *\/ */ /* tk = ec_tk_int_new(NULL, "foo"); */ /* if (tk == NULL) { */ - /* printf("cannot create tk\n"); */ + /* ec_log(EC_LOG_ERR, "cannot create tk\n"); */ /* return -1; */ /* } */ /* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); */ diff --git a/lib/ecoli_tk_or.c b/lib/ecoli_tk_or.c index 9276c70..b498dcb 100644 --- a/lib/ecoli_tk_or.c +++ b/lib/ecoli_tk_or.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -179,7 +180,7 @@ static int testcase(void) ec_tk_str_new(NULL, "bar"), EC_TK_ENDLIST); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo"); @@ -197,7 +198,7 @@ static int testcase(void) ec_tk_str_new(NULL, "titi"), EC_TK_ENDLIST); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", ""); diff --git a/lib/ecoli_tk_str.c b/lib/ecoli_tk_str.c index 41f99db..f7b18fb 100644 --- a/lib/ecoli_tk_str.c +++ b/lib/ecoli_tk_str.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -129,7 +130,7 @@ static int testcase(void) /* all inputs starting with foo should match */ tk = ec_tk_str_new(NULL, "foo"); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo"); @@ -142,7 +143,7 @@ static int testcase(void) /* all inputs starting with foo should match */ tk = ec_tk_str_new(NULL, "Здравствуйте"); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "Здравствуйте", "Здравствуйте"); @@ -154,7 +155,7 @@ static int testcase(void) /* an empty token string always matches */ tk = ec_tk_str_new(NULL, ""); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_PARSE(tk, "", ""); @@ -164,7 +165,7 @@ static int testcase(void) /* test completion */ tk = ec_tk_str_new(NULL, "foo"); if (tk == NULL) { - printf("cannot create tk\n"); + ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); diff --git a/lib/main.c b/lib/main.c index 059515b..601508a 100644 --- a/lib/main.c +++ b/lib/main.c @@ -56,14 +56,14 @@ static void test(void) /* ok */ p = ec_tk_parse(seq, "hello mike"); - ec_parsed_tk_dump(p); + ec_parsed_tk_dump(stdout, p); name = ec_parsed_tk_to_string(ec_parsed_tk_find_first(p, "name")); printf("parsed with name=%s\n", name); ec_parsed_tk_free(p); /* ko */ p = ec_tk_parse(seq, "hello robert"); - ec_parsed_tk_dump(p); + ec_parsed_tk_dump(stdout, p); name = ec_parsed_tk_to_string(ec_parsed_tk_find_first(p, "name")); printf("parsed with name=%s\n", name); ec_parsed_tk_free(p); -- 2.39.5