From c6a7ebe8a3c078f7f4c7e3d960ac2d5099ad448f Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Sat, 4 Apr 2020 21:13:25 +0200 Subject: [PATCH] hw1 done --- a.out | Bin 164324 -> 0 bytes hw1/Makefile | 13 ++ hw1/readme.md | 18 ++ server.cc => hw1/server.cc | 404 ++++++++++++++----------------------- 4 files changed, 182 insertions(+), 253 deletions(-) delete mode 100755 a.out create mode 100644 hw1/Makefile create mode 100644 hw1/readme.md rename server.cc => hw1/server.cc (61%) diff --git a/a.out b/a.out deleted file mode 100755 index 21a2ce90d6bca6786735e1397e26e5411c4e74b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164324 zcmeFa3wTu3)jxbf2!@*zr7CLGs9Z%MsL>#zK^Yw{(Wu1IDh1@O2o#87H4;olXL1-! zRW$X|rdDlQTTQLeXblWVlX!!uw5DoxthYTCHMM;q-pKd+t$p@6XC@Q0@Be%L-}`*e zs}E=PW$m@sT6^ua*Is*{lkH!8yk{TF%F4E^%6^t*4a2`&6oe~}M9Q)b#=j8$&6-s@ z_3Ypef)`)N($xR5QnMLz#IqV5%$hYlIAeM$h_vrYEwh|_4vP5?B*}lXX04jPdX$htd=KFi#%vAcbvu3SaRer@vw-;)kL z=KcSrSas4JmqF`m_OXXsqXqQLEnl%@{E6d1)#57z1P`{G zfq!nhY+9uKoOa9R&RH^H+45Br7Ot4He9_{$E3cljaPi!$ggGEN+bJ!P(sAR)PdwgW zCti+|i+7)Vu#}Zb4_i15deff;%}<5D)`sn4_B?) zfXa!lY(kl}k)}i)4>F@U>wvSWyC)Dnke$Y+>`O#{2J9vQn#ESTLa|^csC$}*Nj-+5 z*5F_J0r<-|kiQZ6Xz#d2kOR#N+2-FUw5QYpNKHj@6IZ8buu?5Y1~8WarqNP6 zkZTJ*lZQ%s%3MuP9Q1&LXQJU7dU|@)M;O~^aA#G;PKa={?qM8zxD9RXDdXA0+kn|b z&Z6PfY%>^Dl2;cZg@JAiRaG=v?hsgPe=&h%2;M|ud+zBByMzi<~#VQ&?u>%f- z0M!WqjfPhNbut@|1%V@`Sr+v-TJhD)X9Gu6qHD>As&?jwj0)ROWgDtY^@>&~3@;nKm$Mz22~rWwvs=UtiWw0+!?*$DDmVH5AGL)JES)pr&02B53Y)EpKWvc z9gYh12y#Dtikh|ib4XJ~4@}a9X$|&RN$ze%Q@sbuvuc7pBeDWd#Cr=|0^eMG7U&pGDURJLB8QOdeW0(DmVLUq9#t6k zSYbVOmud|GDQc*MU8H_!D#NV2LRWUOrMixpSj&tAwE4`bk}hWYdraFE31GY!jV8t; zn=x0mogWKVqWb(;>>B(;V%N4H6Wv@AZLbM4ttPOm@Ny*e^p#{Zd@7);Xg48AtEz=r zD-b&xnYQp4WGLI@0pCU2mqXET0ZO8=WARL0gfgMSF7FJ*Hn7)FEaw%BQ79J6V=mgV z2))6MhoVihCDj^=ZkR!0uE=-B=BZj}18A29wr*f+Xj_Ax3~yH`hA;@Fu6P~=XrE4z zsXv4De>jxXO*!gql2ceh%{li4q@&?dBY{w?d|SwFVP1{bbs?{=@F;R(x3EYBbak;; z-9%xdnnkJ$Jpyx)S6%o~r?h5~dRbQ&c-2iJExUz9>M>nC#;Yzo`YS=sBDMQV$}pVo zR?FBoiC(+`E+gS1OjV5}xp4iGqlSMOMrbA}i^aO%Cfb%fwACY&D=ChUg_Me8UnCgJ z2uTB5H?W%o+SZ^O3QT9Q7DB0bI|}mAdz#K*grvTn_4^${Itt%@jXy0E=hL*`>M+PU z8vg1TS5KLwrKv_Mws=fhRBTfpLU7S=w+G3jK>m!7lv9dsu9b$dgyy^pz?yRgmH|1t{0bpkYs8WxBHwxKYq-O!2K(zVLXq%xQ&uBM4nBAP$;p^kB7#`BoealBV=&@z zG@utWVTwz86AcUIumIWuq4JI-_DvpkCQk%Z3!x(6jmWA)fulx}ZoeBdivFy>kk?qF z7JZ|TK(o*wDT=T2WAp-g_$@DOSr) zMg6@8WvZ94??x*U5S3`?=*rP$@A$mOMgybO1F*`S9-8em}}nB64M_67m{ z_!y5DLaE_>^CI=#ThL(fcU)fRYi!(qH0jzv6^*p3Fh(vKJ{Fysd9i~#vsg<$JGdTB zno};046KlpXHNnQ)-<=7Eol@LkzJ?tb?6>xS?Q+g7Q=P5hH7F??Jklv(4fK^h@@+d zW^)4A8f`S3$L4mE{5Xh*Ys7h`J%E`8DY*ddLurMH*EfT?^WbHM+QJrK(UVK=Q5tLa zTf&WSum*GjYnLw4HBHQ^Lg64_D5wcD>2gqvVTBafKuv~801nH5hGGX?gPj?w<3wvW zu||zV=SJ$%tiNv7{YNuOc9`ifG7Ffewj=<$y7zG|268(T!g~{GDM9>Lye)of5IR}!*9BM(_$B55r~A}Fl9B8 zbjJhJ62ymP$&7{@&=1DH5kDw*JBl691u;&1t~j#osbep&tl~)1>%bS?Ruks0xS00rZI z8e^@-I9dQ3(*V^VDgLb~w!=(D!w*1YRV{pC<@=Y#(a4!YD{2?nF&1Nat0&}kwPTaW zqRybeI)BMFXES9BP{`iETCnvVV58wXT+m*AG!p;}m^Rxyo5*{!ylIOM3Nn}GrT z6MS~{ghn#kg9alSxz)xhuEVMa4xtG$5V{LF(3L{82E;qB97aXH+ME z71bK5i8&Pqu1NSGgQ`Z7u916=vqv{jttSYMTmy;~l4)5zB(SlbqhDI6L#DF%Knpa_ znL<%xnFn#n6)5U$#)Yk)JPmgH4e@%Mu6wk6Ju>a}IGR1ab)v6F$df&`VM}OwM2RCs zdkUjV82isrtwcW9H$H7v!>SgUGJ$GLP^gB`3nX0xkfK;lyT&U;#0w~Sli#1j_bEiPCNKIrK1L0P?o$kyfx(&2=SitM}6Km<<5Z%*k7{L0@f?8ieBMW}* zE2u{S{3~f``^pK3a#pJ_%0We^O9i$PEMG|YdhnGtLdnkt^e%fPL)l{)$`G4K#|O@& zzuiwFa2sYA=_v;JCbb8`^MC>3WPnNi8eV1SLO)zNRysnQ+1LL2tqz1_nd;VVdyOr0t*-!tEUU9bB}DN5eZH z{6KXhXb}o+DX3Ce*xpOc5$QGkqTv^%=5E&f0S~Y*!@uqc2TAfil%}zfCg1)(GOy8U zu$*Krr)1FDm6s#OI4dW*9fZAZKMUmL+z-pBj&N%aPp!RywOMYhV86eomm8Nx;T8Qo zLGFN@p{R>U#5OaSdPMDtPFq$C%;%HZWX;~#))1yuKDdmAw<2lOLik(T zB;7Ro%1hBD<{^vJ{-$SibrAMSkb4m+dSI|8F2_Dg`6*x-R5yC)!Wvx*i(n;C*+9f+ z(vWLpD5_`CI+B6~mFY^RV})0@3RJ#~MDH%8yiIdZhh`3Eh2z)^feB(dM6VdNUUiE! zJ6w9uTdQl11w5PtGVW}OUL7YzdAdl~G%=^5sELGcHTY^I=`I^xaBP5s4b-j2364qw z3OC_-Y!*@7&PXF19ujyRIyXZi&1UFktKDXHm}zIPl3>$VlVHGJGf zOsJP2LTD(GhJK<^TQNZ$5nylgw3h8`7s?JZ4ROZ-oLsl3*Q7{hwmwA^=^~ArI;Ad0 zI*EHL>C+y4%Lt#!`atjcKJbfpay5QRSAF#u+GEwsfM580ll6~s-ir(iU%>pJ2M>q& z50Gp$e7VPSMW>2M*$lVLS<$}uJrKZqOD|WtJY>r4G90J05DbdLQdOHzMLgR8fbB+# zqO(k?O~EG(5(w?zQPy z%bj*CR!>5rE%}0$5!K<6;-({yh(5=%D*E}96Sb2Dwr*f+Xj_AB8}5KYeuPq=W06v& z9A^l^dHfWqw1uV*jS>`35XDdz#bH?OF@V0!0|r+83Cl+$9PoH;($0{CEeY^|0PO1l zK%q_rQtT{DnMWc-$c?P}D@UA!qkwy6wbNI?eTzEC&;-`N^XI0}tF#0@sjf6xDHToYud?R6$yt@^al`wXW7sP0XorsELGoo^oso z=TprFW_NALip2IH;Y9a~$XBd|ZPlnTLO_>kMc))@&s$y!E>z=Kq9%$OdAc@x0#NxP z%-E`@53u1O`3NNN0~Z_#(!fB7I)e*_!`^_AoIyN0q`R||L|6Nq8WvQkY`Dr&gZ;jh zyp@l@yCN>Z_Zi4A_?{Sn%2IY_Pq|oD;llf|C09SDNI5UyRs)qf9J+>lC&D?*9_nU0 znZ;cLSo7$1IAF{!mRdchvww%<_QA4k+tAL+dFVYbctNe)PtoW3IK#)8>`UkpCa&aD z$!&6Sp9D4rKdtH>sxKEH^GQ|rpg?#aNalfa67*YvjTN7Sa1}tEi;j^2hVm|+zn_9U zkE^4>_fk)$&H4V?oq&Lb@i1Q>!K-;azW5;2(n?;=i508pP}j)}1F1)WxM=WR(O5fp zFR9)h*!XhQ7pDZOZxVun+j-5S`eZjVG*Hda2Lq@X6sSH-G8Nm^Cl3=>or9}R4ln5P zk?yu2Z&Kpq#93;B@o332N#1@5Y%Jd{G>s%p(O|8#*N^Xm14)S>uYqDkgXl|9q z@mlFPA{Cqrb})j@BPF*4s*gmcEOMxovY|pSsUI5H0ETa=3Eo0IzYD!V=G$ceo|Dch zb?>plLb~j+ih8vjBuk;L;c&kN#n5+9q|BDa?$-$Nk=0Bq~gKO1>F z*vxr19e^qGjs>#KD3zM=Xp;=`@$0X(6Cxug)LQI|+O+#OsE0QsdhDv_+O5>cna_gm zxN7}1MtU&*KO*hEie1sI>?uIx+*X<9-j}f}zN-4LvIHI=y6lh#bTzRwl z_h~>C4R)$SPbW@P*yYXe&v($G;yT#*v0#V#HT#Rvyap4IGNl59g?D^1Y=o>WRa;9l z+=s#VX?atAvBKBjC9Bh*PnfsA&x(}n4pifemz}b9BWv?@EoN-xKYIXC6Wnbs=-`@@ zH$X0b`QSzDF@A9;DG2Q-Ql-Dr_kyYq1o|ZYp%1D`oI|9Ne}>X)(A=ueVdw?|faWU+ zwM>C@fnWe#ATD2ibS@B7cuVEqvm#|Z?(ER_xcvI;>Sup&`}9LVB~zj|KgvcwHMwSe zxlek99a`lSV+BF(X5<1J%RZ_40v5(Gd02ix?*ykoP4JUQ@MCD*$13U;eH!5jbNNnn z4T^+ykdr#G)2^WD^^bE$=FOViP*ofJn(p-bZr*s?X9Fe!c98ZAf4% z0wdnZ9m%XOsgW&GWH(9Ci&)E1%?*pA!IDN%qabV{CUwPw>`@x3K?9^krLNXcP0Xn{ zaE-`{gxiqWB~L7b=Zi2~2&a138BYK)r;ipiZ7N1?vAaQi@&E{1JpEeaqOo;&hTw6s zY2pD)v9F;%;BjBg<7`%Q{KD;I?xrvN%t_IwgvY+u#~jlrTCGtNg$e_;VeU9Bjv2aI zLp3p{-UY6PtVXc62`B>Lk(w`psL>u@Aa5<4el-t88ni|lxV|rT=T>X@Z8WozyRgga z&94yE^-J(O6n)C5xYFb+9XM|Zu{jB_B^jD5@(WarWp%8j>uric%0lBb#1tzZRZ-co z25#ODZJTvTxPj8)f}7R?aU;sgc79?V=o4b%PF5}&Q@hW2kVwO&tg33^4P;vYW`3`N8M$6kJ#m{S*{*5O56Qtx;?muEbix!b}Qxfj_CAaxY=nOke)%QM6cg{~BV!I_(?zJMFHq{Pn*q2c5 zdD3&saQSIsPQ8v=gLn@Q3LN^P;RxERFXil@Nm|$~g3{i=8p^%kevx}F(dpjRd0%+x zHK3CQg0fE5VhDPXSm}^B(j&2(MeacobLwOtiI=62xSG{7G>Mj`LQvw6Q!sBL4hhaRSq(z7IC0M&i>V;ZHS~RK%K?Q@;TdZc9BYaO+fBZdXUREkDsMr6ShE zoLY{SdSYbNhy@7QLyv_!60!$kLFo=ndN~qa2*5!2C=70mq_tbJb}N?vy1y;8AXRPs z89iWiI(WgR(OvA!{>|(k&HZWIQdY>))%G zPxasZ{+;^c$iD0S^qz3AWu53=yQWv?`A2Jac7b#({PY17-c(40qIe_0E&df{CnN^j!4B@Cm$$34SzyOl8Oqv>wpi}<%};f&hK=Luf7}YJAKQKQjg+zXmUw?U_EfNE!YYI$ZPAu)?s++z)yoZRCp-|7+o4rIxdLH7ESGD zbrv)Y#r42sc*1z1s4R}=wXnd1RPSHJvU13w4AjB>$*ypTj;Zm?gO`I;x6QBf=XkoE>@Ltz=L(H)zL8H;DDP#jC z6mZ7AGYvWcsdvzOfHDbM^(sFDwb2+i#isr(){jEHgTSR-JplCuCa{NpYqwHgW%?6` z`qSN<_ntoM{ZAJp(xoQ*8)~P&5BmV;krSXyp&k0+T*sd4VYYWn!Zc@oi$5NO6YlIE zjDNni%>r|ddtMC^9r*uneih9TUcLGC;cOISo?k;239Qk@zUS8oRGI$)^UGdHI{KVn z2@K`8m|x)w1PfIATg(ay6UHbf5UdmEe zM??SN{CZh8Px$B8=|6RKzt{Zw8|uDce*Fw)XK(ZCM%HJXU(>K>?{j|5zbkcq^{xL| z`9vezQ&0b!YxCg9ttR={ud%T+(V`{qosXq%3_S?MLO5SJ=WG<)$l~pq2Q4c&@ws5+ z`Du}kY0=n=xCJ#Wvf%~%s1D*|3!Fg%Y+8*J)1m%mXRKqsL3O{>*wJjY$ zF}1lTz~(KD$b@jc9zW+tThF({OkoM-tu7plV?ImD4)e#M9>ZJ5T%<#l8}jX##?(?P z?GZg+hlE);X3s=+nyp8GA^g=WdQ@{b7Df?75?6S2F79y-27qMk;@nmw9dEP}#b&&V-SP9BN6hDe z+82Z$8F;iLflNEx5B$TV$sQDn4nhu4aP{POV5n*{;y~NfLek+nSmCMcKQ^V9l08b3 z*cqx?L(&*~18G3AI#)fv!O650W5j{qk&t_AIcmUsd-hk&-t8 z)i8vDF0c_XP%E%uOQh_Ln&2C5G-L_u*H$Fx>;|f|2J7JJhd*&tii%5$1jTVCmh0rl z2daml9MhH2~~aW4pNJ7R{^TmR=mkiLIkR)NOtf|>OKdqnFyG{56X8$gI^`7ji8=2 zcJM0*n#$`sY;L^Pjpyb-C*G??zuKngcxly6Jsz+p(X#h29G&a|9CU^zLr_&`6MF?r zKVtIPR0SyLII0HD?4MT?K|8ds1G4GB-g6*;C02WY#sOa*O|V=gABF%kOf{EUa~=ae zv#|c%2DB2d3_V0**av1>OQL5F_RnGYL0po#wr~f2D6>$ksY}uSYaME!s_?XF3bRA$2|+X zJ^&9;p@^Blh#4Z8%tJc4m}=vzvjr?<5B(AGxm$O%X-1nsn2o?6GjQA~ikZ)<4d{;^ zyS5)|cgCUbAv*h({`J^Ost|#Ex8r! zAB1ihqYTzYOV+`wtW#wy-oHQQyZ^HTe*}lvp;c8xAOje7bd*ACJ9kU5*m9w%r5i(| zZ>)DoisULu#W-rJ371g}xdLl937{=dAXlJn-Q|+oLd5E62q}3;D#f~{o;5SGg{)?E zFJ};LQjwUd7XCn?G7vpM6J4r_?sSRnaEWf$M8`?AMWXM}G8S07NdWB)gaXk5_4JZ)sX-&43n!^q9e&iIxH4fzMqu%dB&+d`B!0l8 zK>gRhJtm1*<&%~4k&&7Kta%nv_bp{X0#>=D+6->;S}qXzUual=!)6^SK%w$LAWN zVb(0L^$)(5!C~=z_(DAh#`_wRyYH4U$=74D2#EA-nJp>KmKlG&tctf-#F-<-#;>8`XCMDF{h!ta@ktMSOs~6TvdA3W* zi?ArNUxL;CC3XW(wS$23V>u5XjU~7d{ShJ>d`8_S=_z-?)C0H*00^R~XTX&<`X})c z(|&j$49?GfAYfAw2ddL#XI9oI`xV655I$4CC9W8}IP3y~52!-{f-TxKwBrVupL4kr z5YgZrSdy3f7jM76pJ)6}HJB%Tjz{VFQ(pa{KkU1n@^fM}Dtoqp^V|iqzWC0=)nvGa zz5B~|{a2AG;=_|LYTzaT|1be*bgP@@q2SxchyS(w+r@{kUo8E=HFM&_hoto5o!2rp z1viU(6S}NX#vSlaK3P*C?(1x#;(pbxXjf~ZY4mS_Z{W}`&TBQa#r0n`|KMGnmrhTO z*DinNvkpCghwp-;<7gRGuv?P^(il<0g{rNhyjmh?~St({P?rPR3B%Hv3y6qOpKq{zta9@JJa#BRVk%en4 zxL*;)*JPr*>F3!c4Qd5iBq;=;p0Qy17)v#tdZ_^|S-bF0pKp4Le|xk9C(nSMK^(&b z2Xg1Kt<4YJY@IE$zg>;JnbRJ@_7r)0`aKyNOG;`k^%B1?tj2Gz`H)ZjjF!s>O+xlQ zV7goVh>)^dWaJr<_F#M9=Ak;*4jhprSkhI<03?FKX8Zzakvf_PB^=NE z@?6ZZ26dV)Yy?mvD(hv?Vik>Qq^_vLn0A3@R@A9dp{WcgG054Mf^Ph?k&jY&f|bC+ zSaBt&NY^({{^NcOI;x6ri)3@r@U)HWJ#G>N2 zZqwZPTMGKXGwgz64?!BpqCrMe+&7v|Wr2Dc81J%b> z?2BJn@^ftB4f#HMk;(r2lC44U%xl@Fwm-j@H0bf$pHj6GqY#SrAEBN?!t5V4J+vfm z%rJEL`OU|DH;Nl~-qa;G>79A?cp2-QgX_>@Zpl~n^vJ2vj?mE<2n=m;U_)zh<*pw2 z7b*W#u56<@45<5xf$34&V>8}#_KE~hGb)##irO$8nujhlD=fEC_PL?Iqp&}TbaQ4%R z;8(9=tzT>_^Jt&F$wOe&VB+g#uRZeVRiu!B-BfEkU8~fQCWbG5ugAGObE1L2#5{@buyk0q?nm)>PcPK;VgzIghf?9 zLa8a?ICkj>?$ZR802rEzS!%|vJZ=0v{_SjlBiNybve*2=eYRW$C3OHyJxNQkXX+0c zhPvYmuo!#b^>-*H0(r{jZy)-j?*sVsL)#n}5~bv$J&uJ))&IW7+vp1qKK#^q?a7Zb zAFzJxU!Q&Fm41Kt4JrsQ?QOpK;jgC^ zPt$kdKLx)xe)>EW3R$K?oB!TF6g%;@r|B1{qwvt`CDPW)lu%b;&*RC^$R`~i#)4}d z#>Qd|U|{JWg>2W?J5Qiecwa@}lCJIc|=y;r|K;IuDJ)gP=MQEn#i($jfjU+DM2 zhT?`R3ft95y08NorQb(@$we0(ycGCrEwN%UWyXj4Z0N&T6Z{OBfA02julhmV-|Kv( zJVjT?H2XqcwvZf2H6XQ=1h1e%~HK42IwS?xlafeU|d#=do_Wlo8hLK&A-`O^Qz2Hpxhk;~7LCbH{FaDTFy-l4?*l(~unbybN^2ihYCH>z9e(lbB_DnRc$;Q-)VY=UW zty!g*`vmhm5`0pYt(xGIu8gnb{HH~UAqX(Gzhr2xsB$=H#HV1n3&Z{vRS23%dpr2R z$VPNq)tw&*@5laWQL<%Gsxw<>s#qN=@UH|2v4&>h6;_xd`}mN34RW992uUrDNU*&w zt5jdY--?9SV75swAfmZOveN<^VXWlhO)aoRup6yZQ^at2?@l33&VvK=8V4_Nbr=YC zx#aW*E$AGxUA}L-5gS6t4ex6MPWqFV6XkrQBU`b>+(oa(n0AKq4)yRVMqk9YkSlL$$Y*}{ z!aGlN_2tmjAS=`QRnc9ukL<|&KAzTRtv}Nu?ZAQ&gDr4EF6ZMIF%sM^4!aXJ(aT16 z^6#QD&f()&v}DW$V)+us8^|<6(9H;`!~^TULmBJS>*ml{9C?&9YxOX%okjMrT7 z3LzAb&OS8ek3=I2F#;^nmeryyZHj-R0o{OXr>Iq3B%Jitt;xaWK=lbkpGHGlFajd1 zB)u~kRriSPvy~`rK`}t^6QhwuL?mtKpsX3ht6$7c<&lYNWafeR9m~Cu`9qrt5SRxYJrJFlsmEqf(uR znT#(~6Fe&5)DSzuhLPt38=sf&Q^V!*)9=s|sye-|_X&l+X!*Z^w%acMxB3%$>CN3V zM;->BefIEF2A%b^*Zz$LQDR?E^?qPEL91w&C3;F{qZcg2>HbuHq{B!&66CAIf&jYy zsk#!J>PF`L-u2G`rY@saK!j)VcQ51P`d>E=M^B)OmH}zFNq(M;znVr5mJ-IP@u6}( zI>KB+=-aYYF?|lA+#LY-bo1y~i>EEV;n&}i*Iz^vw5b2D{)58I)?x0HbV&5Gf z8E=ZUuk}}kBxSra>>oKS)Zc|ThIiFrS^C+;9-VGVfRAg6jekFYZ)FeB@v3QpVGaW?$o@r^MM~{JLu9 z1LBXcaCZ4ulgqmU8QvdmhT-c;-H#Xh?*oD(ya5ObI@D8FlYAtmlMigCgdx6ajM8?s z6s3`1o8}U2R1->Sf^C6~ad28Z^I2IY648=3iBa8!TC_{3$CrqaJ;JAtcHu8>Vi%n0 zP|Fk9@m}=TPcK$}z6KqDS?sx}NcSxk(CDu-zl?pmHh(Zo+*u?htq0fN$Tx)G7ydc| zXwFC?cQ8dER!i1g#5lf}WPq&_fHU{FNx8mp=M9XqvXJngN^r3pmxser5CL zS)sYkS&kP@N|V3fbo$?nFnFX3i-9^ARMeDwip{KM&A0qI`sC098jSzfNP){%my$uK z0OxFQ{@Qu$!-a^q6=LOa6j!QWUqx8Q!?T%eYz;oj@oJWXsPNq~dhl^4aFxXD;C&1X znaRUh6t7C><*k$QN?dLbU(A*(Mdw80>Js*2qf@$Ngo-xFZIGz;gtutqXsC;A=bezv zY7`stzC8bWheKYL6nr9W${XPjMnpN~V+d+Di{)jYvPXe#25B9}vm&Tq4c2D!wE{2x zLH!UPLtTcg587gYTh-5@`e=jTn*Qq=(_DSeBZykVb0|HfQsM{x@qbug7~5{!3w){c zZ#;D#D)OKiM{K8Js)6NBh`n8Xy$Jp3n}D6TY&srGzL}=&>NYKl1Ry&R=|G42v<+9$ z)Sakv7px0pIC<_>1SI(;2l^cOc7SJe$gVo&SV-rgIs79iwC$|wPCkdG$p@r8h~tej zw{KA~9+%^#BAoVJ3h|IhAp#d)NyT>!5cOB60QrOm8E2p_ zNhctc%nqp}c9Bu?HMwyELiK)_1|NH2mm4HG&ZVgfjJ9w3?-BWr_@X#HWwg#Nfuisb zADhKsy?W$BJzA~7*F+ZjFa9*-k~SPV#!BK7U(v92n0mEpqtu{1-}bW0YSqWO0MZWv zDJ~>IAlD5Et8mqO$j#{2lr;xEj<1^we6M zn+5W5%iy(Mw+x!2C68l>8`L$_yaRR54Qdf`Ah;g$if*}VESgn(KG(dA@iJNTeEwB> z-tTWPUXA-mB57(>8+LK*j>$7Xy`(X9Y3DA@lXC7bqX&wdOFGpl`w|2aq_!U|@GxZ~ zoKjS9zChp9eo{p1R>U%u#r>jZl{Pm9_WGERUKPR#feyW>Nhm6!r&&2IHw4ht5O3#a)z991;dK&J$kTT zY&HSy>X5hnn*c|?vw(B(bs^_UEbaOXcjIqgLz+keU?)qCN0gMm2piE;JEt5{`B~8 zKBl~+K`xUzCMZmRO-!rLLU*{kGc#5NM=6ngLJonl2-#q$sc(Dr- z?N;1>yK>Q|sIcWwCx18_Dhu@$X&8LQcFNp?FJ|wL!BL^f2L^642dpXf#!qj${dDHP zh``wIRQ%3-LI53oL|3H5(9HaE?T-r2hPq_3CwpB_z4m?DBVT*i2Lutfh>rPf1ivk+ z``%0Z3LlX0B3RC?p$_#p7t_A>FME^U!)`pedAus&^k zGV(_s9}`7e989W7TLNNMLa`~IEJZ}?3@C5ts*0{sI*FG0C9}N*sO<~&srdx`U$%dO zr0y>_s0c=R+;@5ou0 zvT639!0peq2h>vu1gkNW0M4%|O}aA7Yw@Q<%l?V5h}JK$mnrkpQ25Fap`0EKwc4De7oTC8#v(Zz*Jt0i%H>!}y+^>@dxO z#aJcptkYh^RR|#);G~IYR_Eyq_=aC`fzH6=aKae)lc2O01GGS}dGz@+&@+rlihU~K zn1hCrX7w%({*Xb(!25w@ETrkobUJzXF7Rwn*r4QyOnVkS?KbkN+F7jo0y?6kZpEMr z0ZmqMW`6`-)8mk9=4gjBKk?z{kGRw+_(`gPhYUqN2vCUqf(<#EeIZCe{dj2x)8NJV zme}s!fmd+?`_h*@nJ=*4rvE(uena%1w!M%062>0vwS9^{x&6s~qkXiT&}U})(&wN1 z{Z&20bXj%i8B*+mjW}z#^QtY%%eo^aZ|k!_h^I>p=F$S?bL?%fqb4+5ZrHwE6MWk> zl0WCFNANe9FmY(gSN#JeF5L0rECNo}SDe{8XmM12zi!!VI>G{nuhAfI0ryS8>qV@T zgQRv9564CyHeGjkm2TE(nl++#Xl+SX>(t?h{-CRKG(>}eXfP1?whiL%{FB06`~c!b z!;w;Kmc%;;8vAh$@s751sjtXDG+1wt)oWzvMqTQ(`Kt!e-e_o0C zmZwgp28oa4n{S-oYcMZU_QYxRa0P4}l}#>kZ#Mb89bbP1#-0Etl%95;|4zqfV$QD4 zm0ulyM0}Qm49qBo@%k|&uen5pQ-eNv-z7Q~zpzmY!K*tsdg~)|1USwC2U+q-6X0a8 z=nj{%4$#6+I6{`lp$bL$c_{Ww+|(Q-%ez#!k+WW7MZRU7>K!bfS{`OSmjM=Ix82E$8r^@)|&@*hara& zRc+3PV9@J!wGva2y*qyUa>xW_`{%=h#-gbi25)sS^z0L8)JAM64&ztpMXmTbI z<5}9qc+xcbl`?**@bG*3g2(vb0xkU>zK!7E?*qOV!{ETvuVPRc-=*up`|!xLb0#|N z>6`gHI^(Z$7`xF17Q}2e;6HDY_H<&6^KA6v8|Oox^GC)bZNKX1J?&+xId=T<-tsT# zO)u3Dr_>A$QuT5F%ANRhac_S`^b@K}CQ)#PC0oc*RFEAVLK zkwy={CrrP)9J2scnIGNIH@-Lr59VS`x4Z}LKcO&XN9r=6`#D2Pa+6GOG4B(J) z(?ZL+8FHo<4`a}d`;^V-paW zd2=+W!^-G;M*O|U&+V^od(HWg;wz-u3(g(i-m5SDhmNZv4r^cW9A`fSUOoKA-f&5S zZ=v5mqfH~P_^2T^KKj7ejfc4Wi2Qo5CvJV;{HCr?qF?Nv{?skh44*&M%l_&ymiU0J zVKEMVeu`avO^YX>yhF~SVZP#80ij*`+u5@i?fP9+#m%IJZzRCP(P__E% z2z91Gt=xt|>4`H<!8DFpzsEZI7`PG)V(J-08AhLyQ-#s{Xhj|4TC<2y7M@_O z>Zhr%LxWm2=!a2v7Du!|PjalleLZ^r@?7Jj@YeBb+FxDn-0zWNP?m4feKxBdpU8kOIWo0%CbB6Vb`lIQiIhXNlR|_B&NEP(LLzx^*1a2OvDQs8Av5LFd zb-ZFDv0I7XCPJG(%?eHG4&3B~>l3K#PHN5ou^D&%_3;nSc9d$7L1i!SFz`=;3?8@c zdXVqxn`0BuIa+Y(DTB)3+ZM0tG0te8{PJ=2RjEb^1#>yxt#-&~lxgoy64BY;gUrMu z%cUk3B0?l$@XGjMvGt~ycNuh5p1Awl)Jju@*89jkBnlV{$CV5qNZ_bdU7&%$1@1|( zz3d{CItimDWMJm}SYY60?FX|10i|$g)+_W%c~D<9RGPgjaO>~k5Q3(a@*C_@ztIU! zMns)3CX+spA@y$u*l&S30_;==;d4%z?vMHXw|^0B8nvGPrpJ@?iVN&S{4(qhGObtY z7T`{`f8?J!kNAx4H-&%7rY(+%fLnx~a{2A2Pkw#0r@r;IUNsXn{#)b556NGbUOycj z<$2aDd?d=$RSwj7P@vtJC#@g|SUPzXC;C|Di9#)wM2MulXVM zclD|-NRjXVxAAotp*GBUPE*+4v?=tB_TRtX(D8a2xb*!-hVj6fA?t>y_KZdiJ$w&BiFp2jB(TBVaDp)#Dnc_=^6zD0(k!Dvw#NC^*6lnrH%biS_7Jq2FOdlivxu8 z-3Gw$E49@D5rg1piw|G1OS*6UTrO8}Wp|TMbG=Nbx<)do`=K*DfOb`;0ou*>hsQQY zvdnClcppq}gyKA)d7lS2Y0iOXFQ88;_D1w8#oyNR+vtnzf2c2f!9@OAnuw)Q?k95{ zIax%-m=L}(M7gr}_H#k#VYUd zm%d-w$MKrTLgxKS%J@@b_PT%5@f6Gssx#Irz0XD(=W3Iu<^`%xAyM3G$HYxyFzUj* zP|tIrD1PMbWT$%UpE8X)>Fr;Nv@9RV$FVG?O6m2d{V@PXULL(#9^k87>F-0Fi-lV+ zMPg?-?P#ZN2O7_x02My_4;P3-HF&eI*$x6bprLX8S&ng2L`fhOtgCl(aOe^9gEuk6?7okJ;KX<^vbiB^TBKx? z^BKGov`pL8Ph~XGwf;g*Bl>Jm4@jZD?ZjDrM`usZi9M0vrkdcUbQdCl?%b32b{!A# z9O~JApU1Zza_&=q_^-TMouK_^$jt8{8T(c2%7^1`p~Zzqz?DRGt~R( z8|LEZEpL|>6Fc17`}W+gAS8BjzU#D<`W(Pojl4!BVD7FMB3(gFaSq+n0vivtKFniT=+bHBXVQ%Upe$2JaY6QFE--jIh34mm!_3QuajQ!acp)K7X z{=>337H^L;cv*(`&bjj_!_+T{OE>bJ<1>l7Gi_R!yI@NPJlK?G1xkZiDBU3;NVeDfXzB1S%3;$!SBYI*Q#G7|mv$VA0>(?n?ezW{TWicPG5zFI7Ke zKcne+MjS8paxugXTh6h=U)|fm>$ftFxW`D$6YB^`sR4x*$b=GPv^E zZ6B)@9#SsSlMd38?b8-@*U4shF$mds$(WxHgHHKZ1J6H6?T`9;!XJfQ$|s>l>5SIb zgLMX-YJDB3SDL-*E2IeEB8yKz1Y;>aj0}vbJd-iD6o%rj^-_86KGzx_y~pZb^HpMFKiV8)Db1hvYKIUD89UMFRLm8S372M|T}#lM&9 znb(27p`=?BuTyHp@PzKzZ_*3Vf@_&0v@2A0`ab_7;7f1x>si%a;Zw&?^8*`-KcT1BvqHuh#9hP?nDwlKfl3`O$M}?Cd}M*h<$87^yW@H` zS-;~^oa)b|%8&EuSuPZ`Vw_J;=!~9E&vChDz}A^h=V(uPuk#7CJNBOo*SE9(__{f` z04H1zTGeNwtHih`hILiWUC+|92(#bu+&Llew=VGAa)*2|!Fqdx zM$U4j!JP#=H~HHPi`JJzQ1^+s zVh=GrOuRlXbw05kI$uuhg=PTX(L^qLAkVmZ^mU0#pJ{#Lx`2JR_#TMATn;oz{KMR& z>5u0*@1={X;ZGlv58PHYFbGi$!ZE%~SNd*W|5-B7$RfRN&^dvRs;2*j;R82brs=00 zaLyyr`19;vnm(#GNSnybzuvj{aAqK)1DQu^F1koEjBf_%c=B-D>-#pn;uT)~c`l}m z{qJ?Zr~g)u-{;W&BgV4N@e%&Zz|^<6e=czp+&!20mt)qh()5b;H2n6ZucA-%GxS=l z@1M_wDsWvkA#K<9_4wZ_KE^*eV;BtGtG=_}%=={%zoV{45j;H`JQ*cL@E$pguKA-u zd?mqrn1~mW^tPpR1w_ zPpeuiY0NHACWlgvHdm4j-~P96dGw}N&lfG9ggP7Vw;B0JH=}@A3*Yx@il#u~6ErlB zJ%l)++0S_R5VGZj3RJ@_lm%N&GKsvu2~)5^@YgZAWOT?|4x{pd@fLLhw-tKWJ$>=V zSM8J4YBxmT_FwGTH=~c-=uocs!KDK%*mDdW!|8jF0I`=f=ujL0$APqQ@n8W!wLoO2 zEkfvwmh3=_xEk0XBzLOQ#`O7qPH%m9mA&_2Z{@s%b`{s7sv*r#E8&Y8vGN^cW1x<4$5otvwMckFMB)!POoQMWL(x2l8Qi4Y zXDx8~kr;=wMKSixuV4H=G3|vOE5CkYY^WlX3r^wZY8Z$h)B4GKCK>g2ulByL^Xp#m z|J^co`1h1SO9C`;GU59_T5O%vc4vKu9nVA`Y()nDL)))!Yk#$Ve0ej7=p)!>{0Spp zzkPfc5eoCJbslxE8pONy4C6&pOun$8Ab<3{b?^##T*j#)ud?HSf>SSFVS&D*0;bdO z<%xcBy%Jp%)=r1 z^Di`$CAHj{{dF!}TI@JUHk-%5^fCR0!s5jZl9J#POS{}i8 zRjTtgQc3xjl2KrnRkDjF0`rr87qF5YFtb)5`LP)c(;bq5m07#B5`A(&`D@}sA}@@A zo}X)XcAzRnW!zWLcvBwtPVpU{ERu|96)1_Lk9L)>dEl*@c6BD!z=o_w{B`yOd4xG|*V|hd5np{gI%ge~&N!5cPI# zgBw6m1JF0B^(??QML|)c`aQ5~iWUk*&LLl=$|XgFit5ktGz*$Gl_%sdz}qr|MjcjQ zrqIIn_;c!by0iohEi$Z!nj9lWyyHaeps>1=_i(Y~r;6OFW*F&Qsaqp;G(hYW3~fA0 zMBJU6FEuE+oWWTwIr)=bOC%;BG%`;bp8|+W*FfDJWdz--sMFUN253RmODB``G6rpe zM)9*nGguJA9|?(-*Q)E$ftK2Z!0#K!S8)1^CLG6lNUm6VZz{r%dQGlQv`CRHMO5j{ zXb=e#ON~5T8pWjtPihUBk+)pJIy#22b;ZP;wH6ciKM*0P?UPX%Wwr zb5pMIWgQc7a17Y81_pR=AM{#%rV1UvT~NEMK|Q1kV3na5&SlW!#h~hgp-Xia=7lkc zYLzhR*^B9zdk%Z}xWs{It3QnMAwG=rVXqJ4w3|P_GZR5%@6YdCC?RE-k1GDS$TPN7UC(GNEDkksyAUa^jVwvi-1P|XY4-PDgzeLx^Y91@!}_@}a^6s@ z@nK-F%6RxV9IlEu`0`WfgHuKy7rw4KPa{dt9y#ah)Uk~I?6;lIDeq&MInA&z_s94l zxvlEjLu7b5poYU~BJcsO;j}}uQ10k1RZBL*3V+HSBzLHgG{QWbh&LevgSEYJZDpVK z0YeVOgMKOPdN}s+Ee=R;`|FH9#9-{%Y-un1G3f)cB z7Ha}vR)q7}eswYY7Q6g%KeU(oJv;v(>?ShZ?+df z_j|xF*2It6K`_6*=Ud-W)}L>6e+Ke_9!Ts&uZL7>_4b=Gv@ovpu%N9!qy-XVgUlS< zNsxi(5tRaYmFYC6c0yl!`=yi^aiq`BQg^)ME(hjz450dR zFxm~o77%|z6LA~$>)%U19ja1O*KSN|r+SN?z73-Z1bAt~j2tD0=FsjI0bqEih-KcZ2bLfwreo$8bAmP1>Z+6Lw6U0u>E1~JJ}^aQ1MPy zq~tZHf5c8d(7nMz3Jbs~EOe<7;B{GW-i!x6mxUz438WJ(+R%T!`f8I9QfCOM18}|b z?l{l`mK$X5_<*K}3i3LnWS~g^NG1qhDB!@zH$`DTbuVxS*oON7Y2!8oQ-mjDlG2A} zVFXef@*p*&E%^*)^_$oYz*Fjm&b+LXxZzOk=u4s%U(iTCj&gq&Q1)W*Mq!-J{T~)G z{TYe*x{FS>k~#4?=Lr6Ox1p^THGl_#w{=a#si}ylSK$_;s+;Ke83aQxXPYjh$VB}* z1x6Ir@gPxR2@TcUj_GO<*ZwApmKxwuk4R0*bWKX7A+i!3CLnoS@Wn?zsu6@GLgz~v zDT29^dt=`Hod^`JZX7EOQ2He|;QHI84sQLa4Eb1zd^Pv3>qhSUc9M~2KL?kh2$sa&-lBFr?v%=v-BLh`W zYXl(=L6~Wmy}NaNu~#pF1hpO=fZA@+gUPFNGwBj17vxR;@h`J3{l$p3FWEPF6l*!> zYKj=zFydj_Xw)uzF~-v<9A;x-Nztfj+LyuKqyA$ijrui8A<+UKdZx8yjE!M&Z;fIx zzNR8S;5X@UMN8jn0_nI2?&kZDh$2DE(QkQ<|2w#uD+O1q6o%MEu#Re;E-}zaA z_zQjPx4L<|j?2uY20gg%Qd2=mrv27Hp)m7)3(fxVlweCZssSsbO&cQ&aPMW|z{SW{ zaW3Y?lk#P8r#3Sl{@QM!AhA&{G;FB1C>i_*b=9qa72nS9Ul1P_7vP#q?Ij*TV*K4a z>Cf*^t|Z)E<1LtJ@FxemaQ^-@zP{>Ze?i{*xL=)l{{+Et|AZgR772?p42h@g(>A zW*jz10)F6L{(it>N=c3k=zcQU*WVBL^p_&v4%ocaG%*uoW#d7({`&z^-{;>C7|MQl zHj?@82i)|4Ag?qh9p2v$_<%=I48*S?h$c_}{eVZL4Ucq!5iuDGOM^0SEJI6 z=N4c*KnfQgo~1dLUvUg))<3K}-h9yaHGS}92`#U(%-@&1_6xEH-kk4C-gO!BLXx(3 zd$EtE|CIS?Y-eBZ6ZeJBx1N~w5qLALkHxNj(njm`r=9B$mPqOb(yiYV--Rp@2&En& zRA~Bx9Q*3efyWrg)j0$nC-^#Z*7M@b?ejf)ee2byqE=LTb9v6JFC1?@AA~o3|DzQ8 zfWGnl-wnbf1{hZ=&y@_R!k>683fcTN6L#tLjd}RRq9;B_LVxd=jqhe4OI$x+{9MyV zS<>J8mF}oZZG+G1ZZR)1r8D$?0rcT@t?Ta)T9`?wAF_t`U}^B2MgI#loA?}JUtE6g z1Av<;trJR8T%ca@a%X(iT&`_>`b&QLm3(i&SWTq{`k5GKWcVx`mDb>Hi<2%^zFQrK zwZ)+f-}``!oR1DdV$A}&%K_b``uRa^Elx0@r*A?<*TB(Fo4=YqiCMy)8l6RK=$r1V zsxL`!Mt{0n@Nm3F*Z77>@5NA>#lgT3B^gX;K8Sdj!!NXm4!FYKdrfsf-FUl4uc5VS z8xEe}W4(dMp(s_fAicG#Pnh4B27Y_w;nU|cT|}V+t6#v{86)VE;+Z%4_ao3{?T_u% z-t_Iyd+lwm&@kmyi9K4Z{^?$9&d&pmed|aMS$g^3VPs{Ted2Wiqp6|)?19>WW{zINS<@t#` zyX5(qJpV1vUGnUf=NIz)N}hYrBmK z>Qq?# zY)Ol$kD1y9gSTjZEQ86NOr5~g-SNb>u-i>5I(o~eaQjbMt=|KuS|J;78SQ?D^KfT@2n_0`u%4dnQK#?&aL6jK-k zEBO{v_YrOfQ>U=@d8SI3iZiu|1-Ne-WOx?;<9aHx*wVtWpFjdXeGV05Z znYx~-QSZ| zm}+I}XH31p)E!K9F;&CV*GyG1H3(m&NM6I#Axte{>NuvZVCqz+W-wL4)CEjk&eSxf zu4L*IrmkbEfT;*mqnNsjsqZrNE2j2m>T#xWnR=F~J&5vhpq>9JFD;f-<)v}{_S{pS zofXZtDlDsFbJoXM*0cRa_4KoTp1rvrGVkY%`o#ci^MIeS=Iwn(-IHtmG52O>S_d9- z=V0qsgT^EM`k+xy47T1Fd?%ai8anE+eXUpay%Ooofl*%vtOxSuAsyRq)N}h;UHcUx z{hR%VeK^e8wf}=`P=CNAZ2NCHFc3Y+dgj1gIVgJayQBW~UF+$??$1W%o%~^qM_Io+ z@+M|p8!_aSk=bg*kPk*?e?DT!7bCN4Mh;s)D(C)@!|orI(=_rCScG>+<@{lE_UEI9 zw2jWG89nTc(K+{xUSnDJj$v{4m?7)O=2VY8-Ljq?%Ys+N4r@Fn=hLyrqxcucOtY-_ zk6DA_ z{qF^@tUJWQF6W|Q|ID)HJ&&SC`VD(0+uGdk@0fy8pJ(xJmHn#!82m}h?fq})v+Ohr zbvKM^%ChdyiUQHY{YHJ*&w9Dvtw<-bN8Q`sy1D-*r2mvNYV82)qnuAb?q739Z5U|v z#n)w0%Q580A!)n%VxSubSgyq}%bkv#%J5`@IrleM2!3rcGH1v;U({q7ba zO5gpD8W?nO_hb#Rj<&3$kCoChYY)H@=i#LYIU;i`%Ok9zR?W$p7;)?Gs$-Pd%hVJ;r=6AuP_4nN2n z2hx#gEWb1KSc63R$s1^=;PA=f?8Vp2&tJZ5#j5-{EAtmDUa=C16$|s{ES;CX`06!Yf<0B7gJ>^t0^h(bmfOE3TQpB7Y^|=da3Nx@=Yc+!gcZteQX1 zDi|;SXMnf@2C}5=FXkJ9JrS(p1*XJwQ3Ri zn5TOpgA3*?UV4ld}w@S;VTW2lZcmDjP3s)_&rUPK* zg83_s3of0zY#u1E<}NB;KiGJoW}{E;h>H0`Eew|xF7`K#uyUNvFSs;iew z&Y!zz&We@uS4}BjwcxlS4Y+jvTn@r1pnciO`6xT}$Y~dzIsN;k!F;wkZP2OuCqMtx zMgLEG-vZcJRpx&?3^=$h8&Ozrb&V)*k)*HbxGa{L2~1|nOlSv17rjZ-bQ&fvlC(2} zxCTK*MYpKz;`%BqASg-|ba|~C!3W^0E~xPLRiA(Mf!pX_}^; zj811xPk;BkU*9?BJKs4U3U%hw{rEW}ohZgCu^p$PJMMJ46_dqO;>_a8hN@Iia1#me5(7jm@E<(9V#7 z+D@TI=-!ka_e)Iv(aCYtl~wo0_e~m`P(sw2f76cb+e4dn`p2{RJ+XXZEN^Vd7K)iz z8vRx3$DhdOvw36Zrij&V&^cL8bUQz@JCog$@lPP2t>zt7>Q5Aku~BrF3A9k&*kc?Y z44{n$0s*n`H+*kIH_0b1o`hHQv`oS{H?(uhj?FLi8~*c$hs25u@7TFx(+>Ij+*k@( zPAA6vQk#jqF;Oh$43@?iwngJlPa;C(x)@7he2o^esmWqOqV%6soJbb@_#gA<^4Y!n zPBu2~*!)VwzCG)=`i-t~KgLmQmy4V=JQCV$oUOXFznJy2>JunOA(zdd`gF}3oAdxm zW|Bq!CM0c~nvGk&`4y*_K^_M(@oPe$>u@J zjO;vX=lLUWvMNOelO|55UzAIbPMw~^C{z?nYViD_A=McW4KlDhk;t7EOMwhZ99H2F z^|`TK$@uP5Pt|l#nh7MTP$d+IDl8PT)`Yuw-4*wPgXz1#B6xm@)?O;rX%~#gE_!L?nLuef)izVa)sx?hu>17xwfShVgCK z3z(}GVEeWi#@Zjj9sy?(_U!qFaRKZA=DZ2m^A{S%Uf9!d!?+Um9P)NAY=6oy9)Z08 z`$w>ijA8sjz84VRk74gMjALNWV?llr?8xg4V*qyGa-;)$?oEbqA?(>V8%7TH%v%iO z3fO~JVXY|cuy25!n>LI)VEf-~7!Qd3Uc-14_Tc;Q3@hw1?5D)O)iBom1pXoIbqwt3 zS)>a)`f;Qy-|t4cuovz{y0B+IZ5S!or83rv^8J1+(O}Pi7AtJn{x87~?DCgkVCTMu zJi+!og7OOfCdw=LF_icJ8gl*Dc!qJIajBk|yUJ@(rsIq*{|gcBc%y6f6vQ1cx{Pk% zUZX3D_6Q6ZU8O<96@tA5b{PKA9_4NDcdoIQA;4G05!{*AETgt*W~3vYpqHZiV-zpLR7T#?*6jjq7; zhB13R{N8}Jxe@ui3HiRs=$eBa{SdyRT^44M&rcxi?M9dX4*0*r=vsh8RrFK%ei!m_ zH}Z*gn*I#py$^AsO-lD8?C0V30P5&Lh=G`S;O&4(%7wehKXX+8b#P(SAAYDD8`A7is@3?JH@&llJ>)-$Z+s z_T98UOZzLdAEj*^{5eyw38Dl?f*8s`<(se;RwLOhvF>S_iYOYTY*tFVxZ z#S?@BrU^+=)OIqhy>E~Ys{XAn+qdbq3wDpj3duO~kVoeT$G4A|!Jvp{n#Fu9SuCKv zLio0!BF-frLhIw%G{h4VVe!7+9)mfROza8AN4iaTQy~)>2p%TP_S$KVY|~!)7(*g6W-4zgARAA8G0}+-I;^@4NeR1XhqiI=I7VzcD#=yaDM*x} zb|+A^wox~MUNrzQNmB$PZC#3^xY7oYuMXF#+z8qw6hfo)VHjyLO9Jj5@xfr?Vl$a3 zs*x13Xigo^J&Ei%GNgy4l^rJq>5ml(pv$4*`0%!PW1o7?2}Kt1XAvOrIMQR1%vm`^ zM;5AJ<`e1cRHAWxOtC^Djso<8NasNAO)Wnho*1rejv&aa8WQ=*c+rd%P4wOR`B!ueoi;x%&DSNf| zU?N@4l-zHdar=?y?Z~gh*PDwa^WkkH{U-hkc?%`?hIZg@M~$y)>cg^3v6sC==dU2v zOEQI-=sB^Jp2&t9OdY80rLF`kPBc~wdCyl3CP&P17`^y^ zAk1Ukpxp^vdIZDBB#qgf*k|Ixv*KqglWyt0B?N4#Q^crd8VIEd{83e89kTUDRFgem zm|0zNLO2g~`=vMOT54C5dDEItYuQ>O5t9t81E()K*-=X#dk4yTv=7Y3LPFL@4cbo; zYO8r&Y{>(GK(AM;xa>YX4|x^DS&I5BL)qjB56r}K4Z9Md$OQJy_+Q~jb4}eKf)!zM zsda~wE7ZT#JS>;9wX{4)Z_7;J= z66ZsT-yQ6;c9YoAsM9A|o^Hq|@OXwWx3IG3p^z*ukj|bws#3y)Bf=op2SwXQHk#qc zHhe&6{9kgpYJ1lHD;M@~%@qtx#Z(M$#h@-^+sSEC>S-CLV4+Y1?D0+R^8#C1ZBA;V zv$awMz4L8~of#K)I#_>lc3_>jY5LYuG(4#AIHS%FDE8hepG8|D35ak`Pgk(e zjY6c>NeKnO=>msSpL#H)R~{6Sb0MP;^>FUnlgGGK6P(HeBm#`Wgonp|ygq^#N^qQL zo$l21=b+b-bhY&UXiT!O*TVzqN3n9M87*~rdsD@|(#z4Rs%bCB z*od5N%bv$5TuTqzD7T>!?UmP6bY;$Xx%czfOr?Kwmlok@%L#udoyK@ledA7Nyxmx` z>xoXC-GZE_)7eZ|orQ}V9-hJ^X_q0<1$fjMO}{*rluB%v1b=KCJJO;|g8@?ui5P{) zoxTT>*@8;0e^;W2kUGi*dXnRtR2JPu%dBkbwmSXIYb>c2urq_LQAEt#@_dj)sj6eP z&2j2FZeyfrP%xuVZbyukuR&74e-Y8YU=h_mdK4z8)040C44N-2WtocGJ&iOXP zsmO^O!XuB5w;?`@v@EnCE=`Ga-b#l!294|R(EFUR2d9#{rmk!ubl-RiOKd%+r&|c$ zU%)F~`F&Es5DHM#wDnl5YMp5zic}#4Q7ofyb8BHQlCV#$wO2pMq?M`ip?1d#RTS|m zyr~BYIW`L61suYwRdy1qLI^`BimYq*0q^jA@l+y~52^I$9bPt6gtS6xygsE}M~WM; z`c5Y^c*amoJ~M~O>I7#Y6T1t=-R4*pR9<@qlqb|@ZZs~$!Z zyOJ3k-xuT9lo*9Ot1coyRQX=6ejgWc4@YzlR2@~hC89Z3u$WcNx-5u}3D?S7aZ=ft zNr(Yr)_1zdL?fSPoS*r)oVeWVbU~wMb1KNJ%K=A2>IFfBxwGO_kcT5pP1Pl~vdcwP zCz?sz9*{ze>1@u)--*3CbB_ubuM~D(!Lcl63JLbOf@(kuTu=~`wj!fXDU^nI4t4fQqVH56)QhANLs>y9u?G~YRP~&K#XKwNQ9>;7Bw&?28_9N*t1qeV1IXnu|{tV zjmx{ZPBw0QfpJ(%J4NFQYgSdl1h01Y8{atGwhPA_+(F}8&+0b5b+oZYmOl@#i5qV_ z;*hoT&%uL${l>qp?KS@2+JN!HLwnS#qO7z+1VTQAv%^EO=2oKIEC+T}t?sfQy|#TM zXi3M4H0*Zl$+3;cHwx=05jWY9VNdpkb=}5q*Y%;(YQl)eT=6bvWJ(Hg^$|hiAC4Fh z8UdOrui2XVfyqj?u~C4>NZj}_8dR68+EK(M7|iA+AbZYQir`^7)PoGtVc$FA5M%ba zc)yTupH^MId#G@!95M(-}gj6>GW#qb`e61w{0Iwkq_Khp2x_&5>6 zUQsF)?e@ev8UK`t{}s}kA47WO1R_`%hu=y|qm&+XZ_l%;dgDunEBZy=Eo25y|LC|bk4zqJb;NcSqme5iD>&m2+2 zi{&XjhejrFQRJ~B)*7X^OQ<>h8xQ@jU0Z&qe3@6j7v81f{CoLbni1EzTjh88HuYQH z%RQ`#lcyVwY?u6i@zG<0#*@$K>Fl%LJ5OoH(dt8|EdS*48>g&YJ9~$8iS~2dzy7Qh zI5oKb1oW}HRKGIaGULWKj|v*U|MQllsXulC);>z+Ex#lY>N`%TJzYapx~^Gx%k>-Y zIJt#u1>eS6b#dwVw;ql1P+;BoD3)+8IdtQ?qm2(84XSXDjMV9Sr3=)PRsZVIBJ%!q z_@0G7gi*d%Mqd1>KVP1wf)Agj;Xo4^4?>4 zMdi9(6Pwe7Zr7UOx30OJu51!)~vA1&cbuNr9#^!6ZAM} z$=vr)kVBRz25x-nx!{Bw_dTx@1cT==ycU(RzV~?;<4ctmS&HcTr%{)sAF4hqH{{fH zAe#iRar0lcPrUGhF91OaE-F%N-1~fMx3%&zo}ZOgSVhU(_q@P+Y^;dH^iR>aGe1#u z_ur+7`;G4$SGzg(+UVHl6*+*kh>u$Buj-}QzXz4;(4EH2i|X%>?DrjS!QLZi{Om=} zwb)WewOoOuWS?;xV#LbRc1?HsggP{B8OgMI1NM_AVgmm!>2@Wk0z()4h5VlTmHeK4 z(;E5v?ecr}@4)n0vxsogwI{YLcJu+{V_`;8nz?CB7ledvlJRh}d??>7zvu6j40uY3 z89zO-j`-P?CwuKAn~@y~RW3?We(Mb<*Y5LLis)7pY~g-Yq|Zu`YInLzi&kIcoH=E= z+0*fSLgtt+NbaT|P?i5R`CWQgelPr&{GNvfH~jqz`91fBL-4zNh5Vj>lll#ozl|&3x)#5$!td#$%7^+Q{^&wiVE(U4U9*S!{Q-ZV+*Rs|&UX1{y5#TK zXADAPkUubYXdvM8&mHRXFB}qBSQ9C&SyB+1fr52{`q}Ae_${wZaF`k;6LDt;FsU$_m$TA{pGa* zxTr(|gGdSiBHA^I*nB0V8W@bor@)|Zb`7kVL&|G>K3};@;zGm`A417r(fKZTgx83C zM#8?pU?AuBNBy}d{)+elQQx3%FqaER{t-F+%pQiI^Ih{O0H8lN-G%sk2roHN=_3m> zT>t?I0?*wNA}Q2@-#^=xi_CQSd^yP?>dx;+O(I74 zL1ExQY!o37$jx;{q~1|gkz6!_xO4c3PkvOkK>SDTmC$;K1xcwikWwImWTR-a0RGQN zTloCQ8lsG#R!}_O^kLI$1mnk#<`0NR{EtMWf&#t;RYZJ2-pfb8UGjt|P)@WKej_o| zJ?cG|%c<7)OWh){N-*G$qFxauV({mSry9l)m|-J)*YUf=v&7GRv38#$juZR;OutXK zhd3J0_+H`};;z$l_yyu2Vt-Kkzm_=AtMTWEBg9VJ_d7}>ha?73g zb;QPb+WkplKe4}u`6GTm@LzV7j2!XNs0T@Jn)n*xIbzYZB<{wrj{hFw0P(f`3{QO2 zdX3A(IbzYtB+-0{*x0FYZb17F5I<{!#!=!^iA(2e|F;l}ZYPQFke6!zb9^s#8?o;d z+WnoxgTzk&OZlgX4@J95`DTbuC!Xbdx_?7FPkc48@0B|K+ldE>zfK$_J`?>w#ZNp6 zEa{htzePMxeA!=XcjHw${u9sC;pd4TCWhW5RsJ`kpGf?E;{HL6BgFR*mxy0|mUb5& zz0}_c=tmNMj`#uM1>*N?()saSsQo`d93Vbxvkspl{xETg_?aQ5N4$qvba6@gzatL3 zTH_atBFgm(f&7{!}y8+iFl4U1zl89z6Ih>6C0)ue*)fD7Iz=aMp{dl(;*h z{m&5>h!==IOzcnU_`X0qNPH;hqNGt2#LovER{19`5|@b|AvP}7;lrTI;y*zA2I2^@4|G)A zqebn1f*4{xD*sOqmx%j87sY>MQoH|%I7fU9=%BdI5)Xo|37#YVDzP!8!|wx~Qt1<) z9M!l){IA4w#J?t66k zSVS-bYKxV7bf3m}j!ofN;!hGAmuUB&5$A|c$1$)L{ z;#uNf63-EzdYSe=Py7R7<1IS;-y)wXf5ayvUxEX~-y#;Brub|Wub}%|H9q8x8b^pf zN<2e+5%MkZ%@TizxJu4;1Wyx-9#6q#;#-L4iSHv` zAl`^{#J}$<9sf6p1H@b4PuxX!D=gy*;xh3=#G=zx+>d}Q{v&VKcq{P&@jHn9@6hg_ zCmtmJsTH1h7~v$o67eMQH1WrYXNiABJV!hPTf#38UqbBrJDvWm!~x=;5J!n$09&O` z{A%JE;%kU!iN8ubM|{k*4lfdcQa`(hBgEGcM~VN#a=%*pKOVNEpCi7IxI}y-@eJ`% z?__z2&m%TqOZrz34-(%ETlQb`#6Kf8-mU$g@Gh30cr)=V@#VyG#P<>}5YH1E*XZ~L z@m)b2CHj}e!N z(>F0a;-3=xkS|FO`jmBj5Z_50CH@KVG;!c&?Y~UCmpFiYcOky_Ss3{ceE2Qee}uR| zoFjhghqe1W@twp0e59`4;zoBlaPmf?sx<4j&-Cg*ZZd_^fuHBYq{ZALWqn4-w~xpZ0O> zzeN03#AV_ru@B{v@NXpc6aSt#N_^EP^mr=~_usDLpC$e*u;PaiXYSDMgQzEof5Rs= zjuJmXJWYJ(r?mSV@n8J2#tX!E5&KYY65o@=0pgxJwf_k5M~I`u=3UyoO#EKrIpT+j zeW-Vd|LVK7e?RfL_b`6qJ;b8hUHsodJV*QpvFI2V_oMFB;eBW)!7nF{5?@PPBEExI zbjFMS?*gm&g4p*jI=(@)lenKvEbS`zeqiyxK%D+G%Y$|lck^F0o+bVcu!^7f&1LOg zLc5Cp!Ov(sL;Q2%GV$Df+I@lemisj}&<`Yh;jw6TkQK+I@!j ztS@LhNBn7G1N}(in|wgK2Z+ZW)VM_a?1wa-CBC0{p7?WL)b4}mhZ5gKU(z^&ekOS1 zml+@0RqzAE)5N*2X!kO)|En4=5I;ohM>|URSI;qi;`rAXKk*CyP2*YO9}>?Izw2Sf zPyFA+(`a{z|CC3xdzttt;sxTzzs~f~FU0?Azrpl~zezlZej)Bhep9>Wi2seaOnm#J z+TB;y{$KH!?oSco+lWiVPy0XG{{r!?#JEG6P9{o)42Z?>?XM#`r zj&=_a-$%Sae9d>Y`z-pQ_&@G@8kf<|fXM9+TDkC7WZl50P$nQQR3sjul<*Z z-$^`U`6n(DANK>skA5TZ-#|P_e8La4`!sQpc!s!4JV)H~Bkg~l_%h-E`klo8AaRuV znLpP4XNhkjE)z$7!uW`PLu{bmN_^e_SGy0Q-wM8wcozLs@X3#B_cHNw|6St%`l+}F z{zKy#;-~$m#y<2@asME3g!tnB((WbVO;2b%M|>CYyygB=?QWo-OMD+9_7gw%zqNaS z_;TVX@qZA{5PxBT=@H-XKN|ZmP9**#ex~st@nyub#E)9;7&qd-=jYmgj`&hyAI6cm zmx%|7|Ku0if0XzF;xh3^hz*Q03IFt8YX3gsZsG{>2Z(dTKO&wc9(YoRFB5;9*oSc{ z@&88fTElqi`x-y*SHOoF#&3yFC!Rq+75`@u-%Grc_}j$0h!==2Azq7qE8*WxyoGp% z_yXeFi6@9ZPrR4-G2$zUpCG=Mxa%pM|3`?ABK{Ha$;7`P{%hj37&nr?^N5cjP7t3& zypMQ*`0d17h_55Qkoc3tIpPP2uOR*o@wxhpbzMA+X;v0zvi0>laLi}ao3yHr^oFe`u@ukFv|5}&lD&pr6 zzmGUbJWCuRE)&0!c#b$t{3GJah<`zR4e?sgH7V~cf}f5*4((ES4gUNyI0R19?tein z=j`JDe&U6V8ov-9#eeB+jn5#ChBZEqc)Ca9Hxtj%|Bb}6Om71+Ao0zeqy6t7HX<5N z5|_I*zKS^VXBuBm>lptf8lOpQ>7l)pxO9tlf7;>N zzolpPoy5M^X!oxXTY6`okG?1MZRwxgN*tj7w-8(UXdfiD^wK{4PjvX{xQ>4}v8AW> zpNTDfwLQ`on!1{|fy~u%*}bWzW>u(rh$g;j-sA1EREj~Tl#g+@QZ&RT(o;cFxv1Lq)!(LM!;$G0|`G$_jPp7 z0^>VIjsCgZh2NzyM!o*|qzix9g@53}zj9&U3sicQ_!e4jc-@5Q~UZ~=)gzt6Xb6xl!UHEYq?s<_jzSq0(mt6RmfDg`abhGrfKnKG%g` zqwyN6eJ5S`9SWBYvD|NPg}>Y7exD0J=ECzX{G`Iw@wM(`Xa0|K;XW5W+l4Q5;iL<{ zUgOGmewz!w--Tyg_#PL&--RD^;jg;z*IoGAF8pJSyR7+n;Y(fk3Kzc0h2Q1E?|0#wT==6de7g(ZySybtDsFf%aM!CVjX zPcS#Y+z4|M%!goZhPegi!!RF#xfSN4Fdu`t4Q3YR<1n9qxgF*Xm`}od3g(|-?u5Au z1~+w#dthYG^)E1=hWS^RGR$XS?t{4>=Cd%LgZVtn7hoQMc@X9ym@mS73FgZ%UxE25 z%pA(Ym~oh0FcUCIn2TU`!=zx+Fd3MWVX`o%z?=&6VwfDvX)qVV}_CJ56F(*sk4nS_~w*#ol|W*^MKKKqB)XZ;40tp)>Lukt8|1K?pEmCqG?n@8dg zdObm+9Ne#v$j9y_zonx>)qPG!Ts!UAD#??&ifT^SUV>6z7kvy$`Kr`WBc?Ku2$Q!jytyUCP}9~=H${vd;ny)b8caGer2`qKD@oG&E3hD5c=7`st)KT zA8WA(bw2!3^L$HvuYA^}z6Yn?;RgO}Pr%goWxd}Z&tNN^!#1xiJPl+E-TJFU?YUgu zmaMerzPv3fEvN~W<($)_b+d7QCewv25X6dm5`6!3yaX zwk5FaN2987t?Ik0>UGKel(u@{vYK|Mt~HkUnA8eC%=8CWUyHtV)%hi^v$$(XVO^__ z>vVoCVSHEAV=1kq;bm&&T#>i2{-En|HD5G4a4T~4UYR=}>ZpAW{dIhC+w}^t_gjAL zdgtF{rUp8jCD7RwlF{jK?NZ#bIcl8&Y~t5sg!oujGrWU+XCGwfS(U@Adeu`Oxz-<4QA74OzKR5k7@ zCmw^DaY}Z=_t;=B=VXvZ_^AT)oxl(xuz3*|$=y%c%#f8LJ9* zbt+&Mwn1BO+BVo*lP|EcmbTN47NfH1(p`2Tt8ulVj8uK$B#x~W(xEnYxuvY=%Uy0n zZRw>I4Y{`5EJZc$QiD}=;x09yOBrs9!QFM%R8f`s+odLmKo{8tYHu96=0c7SS?CtF zedvpeIyY#uQ@X;d$=OxqR=-wgTyr{dJpxvg<5t}qT5<8&sSXz(c80CVeEln8`Ajmi zOO>Gdc|*w3flCJvT?c8E0`Gje*VnO>K6e(|4I2AzAut=gVUi|G+!t405YciG}lK_Pxlo{u9 zhNYX=jEPcS`JFPf8eZz(Rf{gDV>CQ8?%F;nRl7E9>DaY>qH&i99wUS(OTxmx&$1SzE6@9oSqQUEzVkPif>tl84ytOI2wY1z? z>TOL#C^}h{4TZL1D^0fYhp4c%bk~|x3tQ1ZOKr6ktkl$2kkU`971Khwv}6#!l`2}h z4qCIImCu?5OY1C^cw%X+^vs$C76_ViR5oFYN?EjYUg?t6N@OkVu~Zv7wl6gXACsf1 z%@cVUCPNTZ&1ZK*TWBtsOQ2I!g+ZDnTamLxbNEQFX(u#8z3A(yu(!r@QJrcAUGeWU zcLtz2b7Z}#^VMzc7#Z0U%Y`$=U_UCnnz5EvjF=G}5+^N1k{g1e_T}d!yg3sRiKt~q zHIU2ZptwA~+fg=~{!_a?9c;Wqy-V@DrtgK|R5%Cvu`#vQTAzmg+^6Yf4-k z8WvT3vNcG@a{8FqOsZ{XHZQ`b^|aMUKW&?mQBmw0kr=_{QkwXb!mE)DCROa9^Ka4F zUiE70!DwY4V%nWvSGl4yzpX90`{F_}9iu0M<&kP6r;H^O2ipe|cypo9sOnX&locJ@ z8I-o(1})CEF+L=sTAxX1S|5afu+Vxtm9IUalYzb;=(|I4yocWSW>{b$jA3NIH0VJrUeOtkF)p9+V!Z7|4_RP#w|RkSQ5@$|c0x9%1*}DFmAiVBd~>%W;SQC> zardasyggZ|OEz?eRwl9~ifj*rc9%7(Fbi;2p324@IS%%#Z{X$T!BmJPiv?K%+LjtJ zK|2@@YQ{EAwevI8aX`~^c+kYr0ed(*INHW^H_D>8 zAG;G^Xv_9fWkO}UeQWXcvhao62Kd8ZzUILZ8n9<#zt>tYFs2#5m`#v5RMN;s({Uh) z8(;BkI+w@tJ~3wIVoAlQs%&B8C_(X$)UudEOm`9?qhaAG$(CTHy25&^D}+$f;QvZ$ zA)KFq%V2Sm^r}tT+f@)VkxHajx0?}R4vhv->9s?Q7Yv#n*7iQ4$2ay{uDPZ?aXM$&p$)OIG3nshaa+Nc zk!>~V6{E_@0B#>$LB$9)6|zFsnT@m!t+&L)P=@7KSfw-|4YpKPh_-`ysM}tWRn)^l zqavtLJAE1oid0;3G@i?$^KuSKAYj_=D_DD@Sk98ivbHcLU;ij1FOdljM_=w(hU9)N zIG9=RFO>%nM7-i*W)gcsI-p59zm#&u=tR>T}6N==YfkZ?m19|{I4 zkz_#($a1z8*$3h@(l?&W7n}<-7pYj{G^m-^JX*A#O=&bSEiwL~WB{`Zh_PdKu{vda zS>j&l^Xw6e`*v`ftoC(oqOe`dr9wE>uk25UdgIxgnpa$VKX}FNF%%MxlZmQvb)4pR zpxf+n&9#Zh9<fAsI&p9) zY67adlT#F1W#jBfj%2KZAxFG&GUMujwF!?|y@4DrM+_1*_)Yc=GB`W;PQ!FNCf8{RGO93kftstL2n9c@r5fBpxyw3Dd?URoky0obtik_ur-jaR(46J zcycynzmqBE_r<419lc#Tdk)Ot81`roz{^b*z4@S>iF4bv}- z$X*k>SNs>TnTkwa2%l}F$2%JDY=b0wN#Mj49kCC_N@9?xjO{8oJM0F1bdk&!>XZ)W zbE%Xw%u;gMKORe_63)%!qG=95I14gy*i>u5NH%A+AbXNy#R+F?^;OPbbSu;;PG12H ziM8prxP2ySjkur%+8`HQOK08XY(q}FT{&GLY639^*`I@JVV~cye{eGoWT)6#rQ2v1 zc-kJRtvvPGv&=ZsZns_AZWs#%n>_vObh zLprCED!KD;Ts%h11&NG9qH}1&WFcXW$Kr{i(3y(3ys+7}LHh4FZ?UfMJ=$&P<;i%Yjh=t5on=?D1pH z;QP2{tY8)=a}XBP&nUH4M;JJA2+_xwHs^N8o-~9558K++GtoK$x#+ce7}{0w${b=| zZIkFytWa5RU{|e@(Gt4@6gzUsrwpxU)rA$E=nm$RiFjg95)`HSFjW!dLLI2}cYi)1 zmkO|>8c*aCnKkdg}NC^!Z&{wo)oM6AkUJcYFz9P!H`17Kh0 zHauYglXBQ%23s`DvzAu1Kwt;C?iX}yx2Sje<+1HbOC7F!<*G+%?7gMhp_eSguz#~# zVGQV1vvb_(q0oA_3|V8x5=6GTf7@p0hUe+2I($UkV6dL}3t3A!#kg_ak%_6(>8!n5JD-bv%s z$2$1Y`??|Rij07asXGm6c%|n)IgGRBK-RgLLiRCihc5Gb3((`VBv<_gGx(xv36d~Nhu(NZOBS^$LdEuv`AAt1<{tud0Sdx z8uHru_p?0aKt&cu1jFpzy1^D`r5eXeU{p?@kh4+Sg0_=4E!Bew5z&;63d%E<$f4ik z@UJ33D=e1kz7`%*36bk5jN`%p*3Tj(d4aG#vyrG*~4+>Bu&R;Kb@>AsyR`Cp0RORa{`m$Wt$?V0n?*Rh%&KCQ3Fh^S6x> z4atck#TqMwv?9{zd}c;392nT;q}Bztcsqsm;yC6&qP>-4+Et>xL%qU~4GVX6KeSl4 zC4##Flv4}v3)$SECY>5yF=i9ZT-{+k8&QA3ruZA}T5;JI3pgOOT?c7gZ8knDCROQ& zBWI(awfrrwQ~!=DL3g7P*p32LDdP?K@K}A=`0%=$NdNY{m$6D2t}LQ)b|`%TYV}Ou3?n{e4(A?apo>g7kPvO`XyYJ0IN<9+nP{gV}MFr{z?Ix>900 zlD0O>9vrz z*6+89#E*lM(xEx_I;>${aJr=~qYG&ixi+12C}Q2Ws6YHV;3(KZ#dJ>V60vk;L*voS4}=}< zQVP3D(@n!F?O>L1?hejsAMW2n=1ur(w!Qa$m^!?Uig2*&%2?&tasSAS;i9VJ z7*;RhtzCd3n>h6m+1mCBXD#+r8f3=Q*1f*WSaor}|8v`rSLMY-sb+q7v|(WEvTF7R z)(&ntD{-(!^!+6LJmAi)-t5R$2-{w3+g|l5ui#41klxg*J+QDGc;%PWv9f7e`O;y# ztT+Dqp>*xr63SQ~sAbbx{ZKlqW65fBaNa))dcHq__RxZyOM4v3zNgT~0wPrBzKBZ^ zOlvEPwbK5R-{+m|jPp*tU9?8Jd3&ovuDlOh;&gfdG-7ng+s5F;iv}TC!PdzM+p)(;QT12JYLdDI5bKP=+U~_D5U9sn;#>zlNpb5>(tNSc|tFvCPH#3<|HU#GjXf#;ySAo7y#-Oh zCU4!<3oW-8ItHeB4{QIwP`w5rp-`q$3w1a=RBcF zxV4CACUN)fh(ocNpfaxN@D7$8Oa0*^ZzJ1|G#up3Q6rHSYNKXevZ}IK^5`HH;IL`mVX`!Q?Yu=TXA+wq;v`?UCb& zd2WOT#*%nZS6(OMHZa&{3EyC+sWc8Dv0&d=a-7eY=_}3H%nCdZ3!tg#V+o~5~Q-{7iIIi@T6rnuh|e26JC4ySgaY=f$B)s#(q8a^@UhE z5yn*qb-O`3w1cN1k2O_!2sRD@&PySGh3k&4H!AQrzhXm(c5_wCMfwIR$m!p+QVRJ> z85ODF4NO(FqG(w&;~bUJE!>VO`$bd~;2p&Rbed?shdfb5-b+N@tI|1a6Ry3N zV`HFH9CTpbn(Bs*1Ds*>y81_aO~vOvq|#AJ%Pe}t-r$rKoHI#nI(*`11{CD3xmtg-ZxEg_|*hF7CmBckd|ozSaZGmPr9k*cQRcMcSk zx83AGMY(KpfLPi`4pf%B$ia|B+;z>?>y0>gwCk#gAU@Q;W1+KpDpDa`;NU!aGQp(& z+qMU-|E8m`A{}ex4&|b0@fe55_$ut(8`K;2m5>`z42dnDK6{!E2Y=gQsE#tdkfz4n$E*g0veP}ysrp>mhlqxW{gi0f`J z;;M2Y$%bnZFG;$({jYjU5mF$@MzSf2rL^*Md;>mn!%}-)6RKNk8ASWFD7KLZa>RDgFYcaT>mCXqIPG59UyxS@_FPY7VY(951Y~T*9V_AW!w;O6NOL-ljOZ9g8 zCJaXgng@xZ6>ud0vKexQC7@MeZcbx(pKtzLaM+zD*9j?rwZ&?Xm=tJO_J;@+|5U-cQj zH!gRe?ECnN@MecgoravR+pgZCi0eQ(x?16N;Fjt-5Tu(Au~?!w9o{@+2}iGLM@`A7 zZ0!s|olttn18%5PaL&4+tB++nbp?ibMejnWQ$Te>i&LnMh%3S<@)U$ekt=f1N;Zg( zOaI&oA z#FmQ=9RxN}dESqxGXPY5we!uA2Ez$mQ`LxNci2@WY;Dx_bud%v|B{wNPY6T~4 zL$kJ{t#W5qL&56pOTW^vpYy-$%M6_`Fu=iXn&jxmY-H-rwqnf zWW0YgIhMo=8AWg>p^U0Zot)y$tI}Yya%nK{y4LO0elD|wt)DkbsgW5N6>Sr;Ljzlj*Q)9+#pDseyG`S)7=#P#(0AOPc-8rfBi@eOL00clb@o|{V=>;@S(RgzD`Lh*V^P36m=;26;F9(+rctuEk-S(%?DhTl{YW~?I-3|Ty@R^TbkRk zyv-+aAz8OB=XezN2pS$?wv;#QQ?cZ5zJ#+vWry?`l9I){S|v3)(_g6^KxtibIdJiK zZHK0EJEYNN6O^y{_r6dO&ZsL5jKfD{wYyg2(0byi^_3>FFM<0T>85mCqHb-7_Q!If zZdtmQgRRh7Y#8u6+7eHr_j{3>;H0!(YJ@zHnJ>*2TrFZ(Pi5u~krQ4- zB_*<69q($mI~7vec0$Wv#4A2hcq{X@{}oKOr$o>J(lI5fQs-rnWDtINLDgd+CM2td z9@{i#E-TrPN_2?|Go6<@MX*EZv8iZBSw@cB`ZBG>^V`4|Kh1{X=q=hgo+S`iC~R zP5;pH3RhJ>wEBf>+W-?`*8bYvWNRZ!-mh0r@#t4_pl-WQiAs12x69Fvt@pQ>B%X(h zqc-w*KzPj3Mq?K}X)#*4V3?gs@Vy_hf}}jl&aua>u|?OH!d!5?a;x6`jXR!hZ;2LS zkLJbYYALQdZwj{*m+)Fe!DuR**`+kGEWfBtKNjuayf|t-;;eCx4Q|VmQe9r4p7!eQ zP?4Y`zjauF7W=a0#t=qrr7>1=d`S&9MK5gp8D|YN!&GsM`4|9)k|I> ze(J0FG|*G?X+v#X z!JgXO2YYK12=>>e5M1x!Z+&e+g9Ekcb_YD_sHZk;caMiZj|%AS_Xz8e=kE2j)za;i zzYVoz>j`?aSa)|#HTU$@rqR<^TL(RTwPouK*81!1sg1AKqh5M@YxC0E@6n~!dwd(H zEnDwEZQtnK;PtJx9DRY>`s)kSmaVV5wrqXf9{zeg{Pk|YtUI #include @@ -14,7 +32,6 @@ #include #include #include -#include #include using namespace std; @@ -239,7 +256,7 @@ bool is_chunk_end(vector& body) { * inspecting the HTTP headers), false is returned, otherwise returns true. */ bool fetch_body(FILE* in, vector& body, - const map headers) { + const map headers, bool strip_chunked) { bool chunked; size_t length; @@ -265,7 +282,7 @@ bool fetch_body(FILE* in, vector& body, for(size_t w = 0; w < length; w += r) { r = fread(buf, 1, (length - w) > BUFFER ? BUFFER : (length - w), in); if (r == -1) return false; - body.insert(end(body), begin(buf), end(buf)); + body.insert(end(body), buf, buf + r); } } else { // This was implemented before Prof. Carzaniga said chunked encoding is not @@ -288,7 +305,7 @@ bool fetch_body(FILE* in, vector& body, break; } - if (will_chunk_start && is_chunk_start(buf)) { + if (will_chunk_start && is_chunk_start(buf) && strip_chunked) { continue; } @@ -298,9 +315,13 @@ bool fetch_body(FILE* in, vector& body, will_chunk_start = is_chunk_end(body); } - body.insert(end(body), begin(buf), end(buf)); - body.push_back(fgetc(in)); // \r - body.push_back(fgetc(in)); // \n + char a = fgetc(in), b = fgetc(in); + + if (!strip_chunked) { + body.insert(end(body), begin(buf), end(buf)); + body.push_back(a); // \r + body.push_back(b); // \n + } } return true; @@ -343,85 +364,27 @@ void send_error(FILE* in, FILE* out, const char* protocol, const int status, } /** - * Parses the HTTP method name given as string and sets cURL options - * accordingly. Returns false if method is not supported on unknown, true - * otherwise - */ -bool set_curl_method(CURL* c, const char* method) { - if (!strcmp(method, "GET")) { - curl_easy_setopt(c, CURLOPT_HTTPGET, 1); - } else if (!strcmp(method, "HEAD")) { - curl_easy_setopt(c, CURLOPT_HTTPGET, 1); - curl_easy_setopt(c, CURLOPT_NOBODY, 1); - } else if (!strcmp(method, "POST")) { - curl_easy_setopt(c, CURLOPT_POST, 1); - } else if (!strcmp(method, "PUT")) { - curl_easy_setopt(c, CURLOPT_PUT, 1); - } else if (!strcmp(method, "DELETE")) { - curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); - } else { - return false; - } - - return true; -} - -struct buffer { - size_t size; - uint8_t* data; -}; - -void buffer_init(struct buffer* self) { - self->size = 0; - self->data = (uint8_t*) malloc(8192); - if (self->data) { - self->data[0] = 0; - } -} - -size_t write_buffer(void *ptr, size_t size, size_t nmemb, - struct buffer* rbody) { - size_t index = rbody->size; - size_t n = size * nmemb; - - rbody->size += n; - - uint8_t* newdata = (uint8_t*) realloc(rbody->data, rbody->size + 1); - - if (!newdata) { - perror("reallocation of body buffer failed"); - if (rbody->data) free(rbody->data); - rbody->data = NULL; - return 0; - } else { - rbody->data = newdata; - } - - memcpy((rbody->data + index), ptr, n); - rbody->data[rbody->size] = '\0'; - - return size * nmemb; -} - -/** - * Converts url in a zero-terminated string for the host name. Port is retured + * Converts url in a zero-terminated string for the host name, copied in a + * pre-allocated char array given as copy_in. Port is returned * as integer, -1 on error */ -int find_host_port(char* url) { - char* i = url; +int find_host_port(const char* url, char* copy_in) { + const char* i = url; size_t c = 0; - while (*i != ':' && *i != '\0') { + while (*i != ':' && *i != '\0' && *i != '/') { if (c >= 256 || (!isalnum(*i) && *i != '-' && *i != '.')) return -1; + *copy_in = *i; + copy_in++; i++; c++; } if (c == 0) return -1; - *i = '\0'; + *copy_in = '\0'; i++; - if (*i == '\0') return 80; + if (*i == '\0' || *i == '/') return 80; unsigned p; if (sscanf(i, "%5u", &p) == 1) { @@ -436,7 +399,6 @@ struct forward { int out; }; - bool total_write(uint8_t* data, size_t n, int out) { for(size_t w = 0; w < n;) { ssize_t written = write(out, data + w, n - w); @@ -461,7 +423,9 @@ void* forwarder_thread(void* data) { } if (!total_write(buffer, r, f->out)) { - cout << "Closing CONNECT forwaredr" << endl; +#if DEBUG + cerr << "Closing CONNECT forwarder" << endl; +#endif return NULL; } } @@ -472,9 +436,12 @@ void* forwarder_thread(void* data) { /** * Returns a socket file descriptof of a newly opened socket to the given host. */ -int open_client_socket(FILE* in, FILE* out, const char* protocol, char* host) { +int open_client_socket(FILE* in, FILE* out, const char* protocol, + const char* host) { int port; - if ((port = find_host_port(host)) == -1) { + char hostname[257]; + + if ((port = find_host_port(host, hostname)) == -1) { send_error(in, out, protocol, 500, "Hostname parse error"); } @@ -483,7 +450,7 @@ int open_client_socket(FILE* in, FILE* out, const char* protocol, char* host) { send_error(in, out, protocol, 500, "TCP socket connection error"); } - struct hostent *he = gethostbyname(host); + struct hostent *he = gethostbyname(hostname); if (!he) { send_error(in, out, protocol, 404, "Unknown host"); } @@ -530,7 +497,9 @@ void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, fprintf(out, "%s %d %s\r\n\r\n", protocol, 200, "Connection established"); fflush(out); - cout << "Connection established" << endl; +#if DEBUG + cerr << "CONNECT: Connection established" << endl; +#endif pthread_t ffrom; pthread_create(&ffrom, NULL, forwarder_thread, &from); @@ -540,29 +509,6 @@ void handle_connect(FILE* in, FILE* out, const char* protocol, char* url, pthread_join(ffrom, NULL); } -struct read_buffer { - const vector& body; - size_t index; -}; - -static size_t read_buffer(void *dest, size_t size, size_t nmemb, void *userp) -{ - struct read_buffer *wt = (struct read_buffer*) userp; - size_t buffer_size = size * nmemb; - size_t remaining = wt->body.size() - wt->index; - - if (buffer_size == wt->body.size()) { - return 0; - } - - size_t chunk_len = remaining > buffer_size ? buffer_size : remaining; - auto start = wt->body.begin() + wt->index; - - copy(start, start + chunk_len, (uint8_t*) dest); - wt->index += chunk_len; - return chunk_len; -} - void* request_thread(void* data) { int fd = *((int*) data); FILE* in = fdopen(dup(*((int*) data)), "r"); @@ -583,8 +529,10 @@ void* request_thread(void* data) { send_error(in, out, protocol, 400, "Bad request line"); } - cout << "METHOD: " << method << " URL: " << url << " PROTOCOL: " << protocol +#if DEBUG + cerr << "METHOD: " << method << " URL: " << url << " PROTOCOL: " << protocol << endl; +#endif if (!parse_headers(in, headers)) { send_error(in, out, protocol, 400, "Malformed header"); @@ -595,198 +543,148 @@ void* request_thread(void* data) { " URL (this is a proxy)"); } - cout << "BODY: " << endl; + bool has_body = fetch_body(in, body, headers, false); - // check if Content-Length is present and read Content-Length bytes - // check if Transfer-Encoding: chunked is present and wait for \r\n on a - // line - - if (has_body(method)) { - if (!fetch_body(in, body, headers)) { - send_error(in, out, protocol, 411, - "No Content-Length or Transfer-Encoding"); - } - } - - cout << "PARSED" << endl; +#if DEBUG + cerr << "has_body: " << has_body << endl; + cerr << "Request body parsed" << endl; +#endif if (!strcmp(method, "CONNECT")) { handle_connect(in, out, protocol, url, fd); break; } else { - // Delete Proxy-Connection header { auto i = headers.find("Proxy-Connection"); if (i != headers.end()) headers.erase(i); } - if (strncmp(url, "http://", 7) { - send_error(in. out, protocol, 400, "Protocol in URL not supported"); + if (strncmp(url, "http://", 7)) { + send_error(in, out, protocol, 400, "Protocol in URL not supported"); } char* host = url + 7; int serverfd = open_client_socket(in, out, protocol, host); - FILE* in = fdopen(dup(serverfd), "r"); - FILE* out = fdopen(dup(serverfd), "w"); + FILE* s_in = fdopen(dup(serverfd), "r"); + FILE* s_out = fdopen(dup(serverfd), "w"); - fprintf("%s %s %s\r\n", method, url, protocol); - for (auto i = headers.begin(); i != headers.end(); i++) { - fprintf("%s: %s\r\n", i->first.c_str(), i->second.c_str()); - } - - - /*struct buffer rhead; - struct buffer rbody; - buffer_init(&rhead); - buffer_init(&rbody); - - if(!rhead.data || !rbody.data) { - send_error(in, out, protocol, 500, "Failed to allocate response buffer"); - } - - CURL *curl; - curl = curl_easy_init(); - - if (!curl) { - send_error(in, out, protocol, 500, "Cannot init CURL"); - } - - if (!set_curl_method(curl, method)) { - send_error(in, out, protocol, 405, "Method not implemented"); - } - - curl_easy_setopt(curl, CURLOPT_URL, url); - - struct curl_slist *chunk = NULL; + fprintf(s_out, "%s %s %s\r\n", method, url, protocol); for (auto i = headers.begin(); i != headers.end(); i++) { - string header = i->first + ": " + i->second; - chunk = curl_slist_append(chunk, header.c_str()); + fprintf(s_out, "%s: %s\r\n", i->first.c_str(), i->second.c_str()); } - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + fprintf(s_out, "\r\n"); - if (has_body(method)) { - struct read_buffer r = { .body = body, .index = 0 }; - curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_buffer); - curl_easy_setopt(curl, CURLOPT_READDATA, &r); - - chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked"); - chunk = curl_slist_append(chunk, "Expect:"); - } - - curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_buffer); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, &rhead); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &rbody); - CURLcode res = curl_easy_perform(curl); - if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - send_error(in, out, protocol, 502, "Request to server failed"); - } else*/ { - char protocol_r[10]; - char message[8000]; - unsigned code; - - const char* image = NULL; - const char* const PNG = "PNG"; - const char* const JPEG = "JPEG"; - - { - cout << "RESPONSE: " << endl; - FILE* res_head = fmemopen(rhead.data, rhead.size, "r"); - - fscanf(res_head, "%10s %3u %8000s\r\n", protocol_r, &code, message); - - cout << "STATUS: " << code << " PROTOCOL: " << protocol_r << endl; - - headers.empty(); - parse_headers(res_head, headers); - - auto a = headers.find("Content-Type"); - if (a != headers.end()) { - if (a->second == "image/jpeg") image = JPEG; - else if (a->second == "image/png") image = PNG; - } + if (has_body) { + for (auto i = body.begin(); i < body.end(); i++) { + fputc(*i, s_out); } + } - cout << "image: " << (image ? image : "NULL") << endl; + fflush(s_out); + char protocol_r[10]; + char message[8000]; + unsigned code; + + const char* image = NULL; + const char* const PNG = "PNG"; + const char* const JPEG = "JPEG"; + + fscanf(s_in, "%10s %3u ", protocol_r, &code); + fgets(message, 8000, s_in); + message[strlen(message) - 2] = '\0'; + +#if DEBUG + cerr << "Response: STATUS: " << code << " MESSAGE: " << message << endl; +#endif + + headers.clear(); + parse_headers(s_in, headers); + + { + auto a = headers.find("Content-Type"); + if (a != headers.end()) { + if (a->second == "image/jpeg") image = JPEG; + else if (a->second == "image/png") image = PNG; + } + } + + body.clear(); + has_body = fetch_body(s_in, body, headers, true); + + fclose(s_in); + fclose(s_out); + close(serverfd); + + Magick::Blob output; + if (has_body && image) { + try { + Magick::Blob my_blob(&body[0], body.size()); + + Magick::Image to_rotate; - if (image) { try { - Magick::Blob my_blob(rbody.data, rbody.size); - Magick::Blob output; + to_rotate = Magick::Image(my_blob); + } catch(Magick::Warning& ignored) {} - Magick::Image to_rotate; + try { + to_rotate.magick(image); + } catch(Magick::Warning& ignored) {} - try { - to_rotate = Magick::Image(my_blob); - } catch(Magick::Warning& ignored) {} - - try { - to_rotate.magick(image); - } catch(Magick::Warning& ignored) {} - - try { - switch (alteration) { - case FLIP: to_rotate.flip(); break; - case LEFT: to_rotate.rotate(-90); break; - case RIGHT: to_rotate.rotate(90); break; - } - } catch(Magick::Warning& ignored) {} - - try { - to_rotate.write(&output); - } catch(Magick::Warning& ignored) {} - - fprintf(out, "%s %u %s\n", protocol_r, code, message); - - headers["Content-Length"] = to_string(output.length()); - headers["Connection"] = "keep-alive"; - for (auto i = headers.begin(); i != headers.end(); i++) { - string header = i->first + ": " + i->second + "\r\n"; - fprintf(out, "%s", header.c_str()); + try { + switch (alteration) { + case FLIP: to_rotate.flip(); break; + case LEFT: to_rotate.rotate(-90); break; + case RIGHT: to_rotate.rotate(90); break; } - fprintf(out, "\r\n"); - fflush(out); + } catch(Magick::Warning& ignored) {} - total_write((uint8_t*) output.data(), output.length(), fd); - } catch (Magick::Exception &error) { - cout << "Magick++ image conversion failed: " << error.what() - << endl; - send_error(in, out, protocol, 500, "Image conversion failed"); - } - } else { - total_write(rhead.data, rhead.size, fd); - total_write(rbody.data, rbody.size, fd); - fflush(out); + try { + to_rotate.write(&output); + } catch(Magick::Warning& ignored) {} + + fprintf(out, "%s %u %s\n", protocol_r, code, message); + + headers["Content-Length"] = to_string(output.length()); + } catch (Magick::Exception &error) { + cout << "Magick++ image conversion failed: " << error.what() + << endl; + send_error(in, out, protocol, 500, "Image conversion failed"); } + } else if (has_body) { + headers["Content-Length"] = to_string(body.size()); + } else { + headers["Content-Length"] = "0"; } - curl_easy_cleanup(curl); - curl_slist_free_all(chunk); - free(rhead.data); - free(rbody.data); - } + fprintf(out, "%s %u %s\n", protocol_r, code, message); - { - auto i = headers.find("Connection"); - if (i != headers.end() && i->second == "close") { - break; + headers["Connection"] = "keep-alive"; + for (auto i = headers.begin(); i != headers.end(); i++) { + string header = i->first + ": " + i->second + "\r\n"; + fprintf(out, "%s", header.c_str()); } + fprintf(out, "\r\n"); + fflush(out); + + if (has_body && image) { + total_write((uint8_t*) output.data(), output.length(), fd); + } else if (has_body) { + total_write(&body[0], body.size(), fd); + } + + fflush(out); } } cout << "closing data socket...\n"; fclose(in); - fflush(out); fclose(out); + close(fd); pthread_exit(NULL); } - -