From 66d9da23b32f724031a142a5bbafd3fa968c2539 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 9 Feb 2024 00:43:20 +0100 Subject: [PATCH 1/3] come on.. show it --- automation/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index 0a27b8b..9ba4afa 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -67,7 +67,7 @@ pipeline { sh 'mdbook build' sshagent(credentials: ['documentation-buildfix']) { // Deploy to Apache webserver - sh 'rsync -r --delete book buildfix@documentation.irs.uni-stuttgart.de:/projects/sat-rs' + sh 'rsync -r --delete book/html/ buildfix@documentation.irs.uni-stuttgart.de:/projects/sat-rs/book/' } } } From f3ca570e5331732db4534de53e87293889a0c41e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 10 Feb 2024 11:57:19 +0100 Subject: [PATCH 2/3] Update pool docs in sat-rs book - Add simple graph to show how it works --- .../satrs-example-dataflow.pdf | 1712 ++++++++--------- images/static-pools/static-pools.graphml | 348 ++++ images/static-pools/static-pools.pdf | 256 +++ satrs-book/src/constrained-systems.md | 28 +- satrs-book/src/images/pools/static-pools.png | Bin 0 -> 38516 bytes 5 files changed, 1483 insertions(+), 861 deletions(-) create mode 100644 images/static-pools/static-pools.graphml create mode 100644 images/static-pools/static-pools.pdf create mode 100644 satrs-book/src/images/pools/static-pools.png diff --git a/images/satrs-example-dataflow/satrs-example-dataflow.pdf b/images/satrs-example-dataflow/satrs-example-dataflow.pdf index a57550d..1331909 100644 --- a/images/satrs-example-dataflow/satrs-example-dataflow.pdf +++ b/images/satrs-example-dataflow/satrs-example-dataflow.pdf @@ -8,8 +8,8 @@ /Keywords () /Creator (yExport 1.5) /Producer (org.freehep.graphicsio.pdf.YPDFGraphics2D 1.5) - /CreationDate (D:20240208153304+01'00') - /ModDate (D:20240208153304+01'00') + /CreationDate (D:20240209121455+01'00') + /ModDate (D:20240209121455+01'00') /Trapped /False >> endobj @@ -41,861 +41,861 @@ endobj >> stream GauF[]96a;XrZ`X=6'nI']0G-Xc?4G)r9+Z>EKNG2R4%q0^eCF&Ru6"F&ec4BQ"pOe/h16:(d[p&-0iM -R9opj8<89"/O*Y3#Ch."r:0gdGZObTo#iqpb<5Q:*ns8CKnJ,8':s.;OT9E+^)s8Q;e -r9++WDnl>Ls7O/,aM7WLDu]Utnc/F"n6>@gGouoFD;Jt3gAG(frg14qpF?3tR.eLKCMf1E/rJd]hI+0]Xq54JJRl^sr%oMRkoH[Tc(Fl@8Z9pkV2Z0MAfYO,X[qi%`Gd4bFb -=KSY'48t^Vqiu:fHcg^5au[k`^K@Dm^]*8Q5%E@BWdPcQ*g/,>on`NHfJ,ED%VO=X%VKLU@NFeI&ObCIOn'>/J?L+qW?ZCN,D&FCelSgfg -o6]qNBj>G_ci!"Sph]Qid=+g?lO3Z4)eDqCCc0@ZC7fSIMUeJml=]@ri`D1E24RK,J_.nX#6t4/^9EZc -rI;jB_O\\Z9ejMUa(J^[O+g0#S]bY\^LA;$9,QB$Yh.M$hJr1d%+3EYORTl -5?G>*`353h&-(`NU[`NjB3j'nI.d/rQb]RjVh+%bd&DrNW"^J)TsgI$03"Cj"dNEOg&&Z93'YHW$L'WJ -"(+@_FVHk"]p?q,95tqN^qm3HkfljN7!e#ED5IDBBEJ]9bn@^riKja+$:5-m -p@7540@QMqrVn6G&6GY,?qL3mp%!1k>R>1Q5!sTejfTF!G2.aRruJ0>hd<@(IOW\]m13-f'e/=t>W_q. -g`3*g4')?=.a:.lF:G -D7i?&UX&2+0@@Mg5e4W!B=J,_LC=J&\5=2p'ik7g+pGZfUEgFk-l\:lGq --lGHD$WN/sBAI)\\E\kLo#6C+gO61SMf_O_Y];u8U]/[@lu*Wuf_SV%::k.]R%PU=PZ_oC-;k-iOq1&F -q<&,*eVn8)/Aj[SkKf:\-.k&$!Ptf$=hP`XZ5P-OnZ3]T0LUfmX#(\AVR$[m-X)SGIQ3ss@kg%U^OEp! -=b"3Cq@=G](k4PNr\LcOeS+$C-SC1p/t>5B!A7$;ld0rWd2)=:.d:FW(et*!V@A'WDZ1VWBdPEqI3k#= -SF;S"CWYcMH=Ut;;/s;Tp@7eJe0;]%F\r)YT2gF68EA5s]k>AHB!7oUp:A;ONYu@PcG??P:to\X26bIC -*5.DL]]KKalNMDml'hL)cX8s!e8p)T_pbQ,[L(<<`'2%@.9fT\l*!q^2gf.`gpf^99V]oAXU[aI#**re -%W087/RA-(EGF,S[CVV[5PD-=OapZq-Rf#LQ+PW51UbKprE:aG5AKC4!'QX -HTiR9.oH.M<;PkSa:[eX:cP#Rs7Q96Ps9C6nDbkGCh/^((ZO<>E7LJN>KH))ksd0D)HQul4d!R%ZVq@6 -[G/UqE0RU<]Pq@dnE4>oOPS0m_e-#9dU*:.>6apsD,rMPki^ef8^(qc]M1q3KcDX_?9Pp20@4ZIO(5#S -lVoBc3qdJ.hAn0WnB(q:(FH55YHLi2G0mkAb5(=P^"68EDE>JIYEMpPg$#0h`Qcl`p'emQ*9dN@G/Eta -Y<@p+b$(gNm!L_2fd0ts+(of\4g`bqqX6L_dQ_$6Mf`Y8B^7/b?,lDs)M4;gbSuhE]%pt.E?6X31*UD$ -HLl?hI>OY,ZYF8!l!7jR]g`)g_LP?r^22hd*d"AOZQ%0)H#nk?*UDPhMJ#PH:`_Ro,o_ha1c)iIq4nH& -qEm?SbYd]@qYsY2VCYu:/sb566b-Re/#4=\kPC:[d/%bJQbU4@r`Ai6J*h\FQSfgGfWt6]#>=DFmH][AHL4Ki+j -r3alA]rn;]IAPhD?J'(aBERAm`h0\HY/dgAd9\tP[U63!XBid%Jb/C`)1J\A^VQdg$m3Ug'bC(1^&A]> -<4I9DJ)7I)kE#5$UW;(pBANG&\AB$-osFm/^VPi^9%Z82LLj#:2`a -CJ;Y"3d0UNa\Z7[IhO$.g/XU:b=!h4EXcM.S+J\o=u3[LDs03rAng;;B>bZMH=QG4)s"#1].`*##0e^r -2gjo.edQqL4pP*JiNiS-PRJl1]euQLp>Q;l6g`7(#6354&Jr]GTe/Z9mAmUp=(e,Z0[8#k57O'U -RGF_Xm:HYhjqg/-n`tMrp1Ntsr4?<^e7-<1,=W/[lD-jSqTup\Mk?iRE]-o8* -UENI=,<#&.M.84gn&^#=b^L.m[#9SRqhng!E(Ymr-1!ej5rtBV@t-SJ -+8Tb'c3p>\KDH""^TamDXDOED>:R\ap[8gMYj+Y;Tc`Uj%_Y0#PA?EnSZC2_Y9"e8Ti/jC-uESb*\D_. -B:c:o6gu.Ye!h2$AGjkfY,YcsA#ob*hBib9oX:rFd@:%CN^&p? -[Lsea6.fapeDFa,_L>#RGJ%Lp3'LZX$=?W8+K6N'#'NiKK@7cA6YkmDPZbFt[uss>O+(BGMY.'Y(;Ph< -S,@YW+pSiMSJ9#Fr&$]._56tr66%*5p3Z^crY@To=T9BhXVpk\?kjU.G497t0qO\fiHqBf\Ot\m^KXt? -86*#&r#K-`.:`g)=S5IJo?q!D`(Fthd7dEoJn=oC' -9l[XKB"cg7WAuon1Ac.#R=dDK=b_!:"YlKs-q43L]e3u%S(]a"NM)5%ebW[7>fW#eY(>cRY(JZ0^P"O" -g3qoo?QJJ#&WugSR%ponqFIaERgt:$'NE4CH$qg>$];,rj_bMG^>s+Dak^^=/h#D5bo0j6g9_&cUC>Kf ->iGqIZ/sP'"\Q6]\B8Y=Y0=Jc`ii)5L$QfPZjt>!1f&bQMTDncqB:5KF$DPKgs;7:^OO:A%B`+rW3Dm? -XML108kk9oLGcTE\ZkVUHYm">n-aCsdjHi@TT'/`-^DrD;LS,NFV+r@UNOc>FYK(Tt1+n_He -kZ>k>%h/;a^Wd#Xq3/P_KGee=%mB[+^L0ImZ,="D[&mW:d6DDRMu:@(ZT^HR:u#a6=s36Ka&UhbJ!9NU -T.!&EUAmIa&4\uBTI&mm-@Ko>Tq\K1Tj(m_>IVp3%"#N.s!rk]d;e&8U)tmdLK6,L>lC<97E`S#*E-b -Dn<5uQFm8_J)AuU,Bn`%9"a!SZBaP23!n?RFXjPs4gN,#%q^d&U(hl#1BkqT:\D3i%pjcnYj;2c[QaDo -FfE-X9>FX-:7cdkR-F-G:V*W`Q>]G=`bU&7Wn:M%-hCm0X..7-Bc-XW`SCd(,]i^-E/#Kh6SaFf4g6)o -SlfqPb$3=YW7"9t=\87G0\]97ai!5mFrUA@L:1YocrSq0fWHiJpWNIYjk?Y: -j=4pA_(iJAN#HBFGCSR4jfcaVs6q%=[_k*i*=#B5Km0'SGQT[A\!Qj^XImt^ERqOt;52SQ`$S -?BTWd$91H8b3nFM]&FFF!g`]XU(=E\l-sF#=SjH^M=WXjh90pbNq(j9G -bDI4@W<`:\[Y/6U[.kKdgBhtQL,$I9=Bm@%-/,2HL0M2@/Pq4%S)6`ing0>]"4nb:[O[uGCGRW`eG>Sa -BN_heLfCgog@HV:ZIV/`Zeb412'^Y5An5P"dpQCIUsHoj=SRg^1Krjl.E[pD+9'H;I4*cTbWaHV2ojJp -+#Ec*0>CMt8r"t`&p2dS]VNs[c]E_tr%tehb3Xa]RoV1g+)OiEhNDQ"V^,lrZ5:QI*p?N4>l\58BF8:L -G\Q8@iMePYg6>PZF45/&8CD=@deEhr9+j945.Xa5']/0"3G@s=X41kCirAQONrmf5h^GnS3(L-Xn -N"boTEQ/;Ec8;6o48pT``!U\lSrYf$1ER&co$:/4*WL1f)]Rtt:7h$8;rkmS_L#9jepk_Hs.;8brB06A -b9Z.uP`Jl!1YXHj#CGR-OTJja=Ct.cUD8#.4I;#gO*ie0l1Gdt(HiilGDj(Y)_D$OGf%N>eh:m$j6^aL2gj/MhrB>P3\dgK^JlHf?BMl*o.+a#U\U.X*q3BMEm'YMGKi>-s*CBa7uJd'@a1**:0_AF4RH` -6r%`2N(1S#8C?j"LJ/V<9#ui%"Y]]j`CjsiYs]poYi9XKbt#EA=IBMrs,NAd&U<%m2!4fY$g41+ATF$2 -bf%D#-2#@00Joq+%eLu$3J8,[<;jTaifYr?\_.Fj?C;cZPq/'YT]):Y5`s/3*95A[`Bh90>HCMYa*a7U -U7?W..tS1WN@ZTTl,F<$%Xdtc#7Z_:+&oELo"iEmaN6U4P,It.T`V4bNsjBW<(?-_:p3U -RScJ7+7fl.A=g)t"Sip[S^u)B$KV4-Dt%O6b$Z5TlcSoQ7JV9X^U4d%,!NYFC*9R(jmTlZA%n/s;/+7q -UHB=GtZ,k_lR3a7qp,^/*Ltdj+BHAQt%.dsNX=3ZSgf_:&aTJ28sQ+%#H.],j9er+6_KStgN3@=ndda\e)EX\ -"KDE0kp@/&8cb6[qJT/4Lkm;IehlZZs,\H0NV42$1lM,n-uAIL32WG&Iu* -;Wg-j]i(Rgr(a0)l1.H;Z'DAs1,C=sTQPOV7+4aX20t[&qfqZBG>+9G1VbLe%'LB>,P4U!?HgSCF`;K, -eEO;P$2=eePregWIf;.WiEdsQU:aC`e&K)F@ZP=Y8WK*gURF[$j0#eg+Dp1%+]"H)r&?qZe#B\eV&?"@r;Y[ -3F^\oq<]Iq3t5TaZjJ[I=XD_AgMEIITK*e^7aSAq>[t7DDmi -ZcpgBl(W(Pj$WGj#r]'U_-M+$b)3%LNZ?qm>onbESb2kJ[52VZpa6obp"@t[N=4'e,!Mb$VADYsFme`B -W:V3%\B0Lp?O==)NKl507^:2BGLW-qJ^(JnMU>0CSf"(YJ'ZG5r^Qfi?4G,hFRu@7IWa"K0uan++H(t- -+E61\:D/)raXM\Gj9X8j#GV!$+7=84g9%#RpuA>l[ncgu)DVOLGt)l@:lS5HY$l[uIHK>rdL*rgVFtDA -0CtlE?leFS?;TZmBangIXNXDkqmpnM)Fl_!8E72q)(84G`fV$f"<=&Q\k85>c95)E]%?(c8CTF`RXH6-ng,i-VIW:j((TH -9]K[F:/g36'KI)_UPOr%rna&t*1`EGcFSd0aYhA[GIq-`M%tK?I;'[1f/T[OF,e)'W,XX5dQ!sc1lgcQ -Sas-u%\?b$[+!sS?*BA$GA%uOE$gS)L`46K?-2cQi9:NMFllj.*@bf/TK41_0J, -Y&Oq(Y&WY5UrF"0`Y%?.3H`?6_=*u]]l)MR`f\J:VlY\SJ%=aa9=H+)rPNp<2%I"q2%DJJ29r=2W,ZG) -cp=;\'W/?13Eknu7?5s8>eBASU\18nXM^4"^Q>3Zm!C@nn;]Y%Mgc`0BX+bbd5i[]3EkV3_fN0p8teE=GjIs\ -94$=_#LU_`Y8j\)8L-01*b8WS)+Zbk_NURiqjofmD_IO#P*3gF"2Z]=lQShlFA\'!@-jGtj)c3PWM][ZP,G&X8S'?IAud5hPK*i,N-k%>(JFl[3Vb\UI3L\:`0Mq5aAT4gmE -++)ZYGs"iLBWN]6m6mAt$sb[F_o80=s)?7PNn/iDl(d!to0OPTVEJ;Qf:+i^r-FKC>cl.HQCN5C+*L)@ -@=s7-eP!MtEr/50a[TXnG5=Wjg@RUE73m'lAQGLHBl.-ALM1o' -48A*(Q5pe\]%X6H^[*MY(L@ll[/YqBic05h99m_B#-4O@V-:d7q6.b+e/'^YhELRH8S?^OO*G,& -r^pYo=0aa_Q)4=kO8+b4/(k=#G$S23jlufXXb/YUV4HHPZYa^)/SqKQq5ZDSA`T>N(r0<_1_?duKH$T8PCECMSY>RU:\3X!GfDVEerKY@J$^k>6q1h#_]iYG!GOncI+r.\k\+%#R;Qf:" -:Cdn24?ScFJ_M&b>i&0E)Z5l[7/8?%)>G`$_i7N`(0P]cDuHSmCe5m';I]AA1jK_YHdI/:Sj8qh]a)f! -VpghVs0H]>o=Sl2RchLdlK;(Q&C9`/q_XkN1@Kdd%Pt__aLqh=#O>hgCd$e22tn@MS_H$j6.6n#]E`;p -ZV*J"r%5SeD%`XgUs<.dd\5G+FJd1UM1$e:q/0a\QQUfq]Y4HdK-s:kQ4l&KGAk8P7a&C!EoC -X40p)%]<3L%pF=eX148YH!7&iiD.):cq3+Z<*S2]5OI.,fl6B\ktgb6l`j)]s$NtHAJ_+`En<$*nu8eq -?0".^McQ*g%iiuDi&G]tH0b,!n2Y[\!Vr5AK/U9(`D#MYNc]=i8'lV0[+:0JFJ8GZ-QIO^e>bW4$)Pj' -*eE*ncu]nrZP72Npmo$SV0V15o,9AS/_S-BLGn7tUXV/;&%QoQ!OW!B#LjU_*o-VR+23Et:M4qOeMfSD -=nm")GK\^b*5%?00M>T`^e@nRF?0,@#UJf0`2rn=6.<(?a3XUCT[Jk<3Dg7CT0\Q&B+p+(KX''EaqV^G"k1(29lQ# -S]XZMM"MQ47L8o4f^`:]ID##Nj0c:Dg=Ls$8#tM]1#1!e\o?dk&)WGf*K$EF*j+uSXCHqu_e+=b%5Q6- -G:#$jODEJs2'26o2Z%*ngME,PC2'8n^r`n$\$X`l,JFC^u1Pr?YfE6SN^d'Z^GSLo4V=l -TRMm(.pp]*<\H$):g -R:cJ)ipA)*-oFb@\hqREGcUG:QMG1V\kW1iNTf1@cHqq!17M^eoL<]/Wq[P0e%F[`(Z.N4gg1EN/:)pR -2YIRQ(<42KpVbK`AFCEi("p2:X'p"*=8LO*L/q(/cFqr/"E%+%)62qe,OXma23`_s7fSZKd+_24om@ui -YR](cUfOFuj/=[^*ZBg/EK+H]&@f`JM>!1U^:gOcBq/>I -S#11;&Qb;aY&T8sEU8-:QRk3=F_Mi-.Es`q^j8bHK)UPFYuBRX$;F!L1Bt6!23+4dGE"BsooWsY+^(__ -+a/j_g=/(ank>$!L=*gpcB(4INPcf8Vm-3(EU:)i.,EB;(E\CO+^M$dVTG5_N[&9Y@VQnP[knTW3&Jq5 ->WGLJF"p%,)c%6fST88/c.@(>Gl"hbjC_\"_+&.D*q"2Kf/Upi-=s+3>sa -l_F8HlpS4#("!ThnpUR/^VW0IrP4%`A0)OKR;Gj/JACJq+/R1.DDsT-$>P#q,/$K7I#YnhWddNrDo"3Mo(]:QHceHZ$i5eYDF`2``-=F3^SIK0(!b;IC6uM@TF]C9 -[[Uk.SBk9#9l?e5ek#ldD:pQ:UHi:SFqAg@K.&6V]!UA1*H)HLO`HYM@Z6H%H%IW\j!rs9)WWWBH1nY^ -0=57so(:"g,ca:&Lfq4*p$SRQPNG%M7YcP.97e'\EE#P-C/*G -Z4Xo[NV[USMpfDu2s0Bu]Wc=m*1jRLK21&,:i>ZT!*f->LT"6$+qRE(%%\@;h7U,9ek7*Z+kkn"P2XqF ->1sUbYhKfOFQbQa"tNVA/WKqU*!on';0Cgi=JljS=-fYo(8(9bk:SbqPn'NSDT6?8-'R?i%4A,e]Cq_T -TsaXUQe&rF,&Su@7eRs1c^iu!J`c-SAD+9*\?Fe\?g\l03G?-rp5#)u?17UCX\-gd9))sJlu+&nF"Q2A:K.i[X=?`m?=R!Tf$BlJP+?aT]"4B2H&p)C"EtV -]^b?rl%NMND++'3"Ji79n9q_r<$dHJlQE+!^<:c=,.01@s3--IMSe_XfM42q=O!s4o4dO&>nB5># -%(&[,l^Gj6dX`HrVo^%+nJI7PG5<<-DO59^>kG0]0gq$BYfL_]-HC&m\M@J38@!#U6Q'i9oWZmlg#J'X -Bg1mNRL6_mI%)D',0*k`;h(kXC>WBT+ni;GrHlTMhsk4V]pfkEl0>p+#-oQ(TtoR&4'?Cq>P6mYfDfL? -l+%eX"s$(RM_4TSnIrJc7=dpdFp%fPNnKgX!`GSqUg^m'k -]eloGj/k07:T@ie?G#08.dN5<1*g#s@)`iTbDu7Qm<85>i2bWdZ:FI3U;'E'h*!rJ5a/TVq6mMV;>HN^ ->-G/efWRd5h6E\%?9N@JP4aLb,kPmE5VYU`M,fkV%*EES>`nj4L"HHR`/"Ej];=OJ_G.-uN3&^k+7D;B -G`Kq3NmTr -\\Dm'h0G'3csP?EpNZ$.e6h`03^%FRoIs84elpm9"OPZI6H>m -)^YH`Qm)-YoPfVmNY;3p9/jWtdoboB#o19oITA(.@T)L@5P/Rht -=W-d;:o`>Q0_tF8coCVg57TCFF84kTge[h0<8Inq1G:DB9AM:j,M/Ao_f$tCk)VM>Scqr)EM"o/fHGJ$ -GF4flm*+OaSfO@QKqc0:A]koIn(g:*g1WV\9VRO1djm^H8$KF<6pPg'Z'rUiKPt3is -G10'8FuuO:nLNElbI8Hkm'=X,DR8[]]45kNN]$%fV42dN??0C12q/2YA#1_5XPUF8JM"Jh8%XluAp9Tp -qUVq3"Pp*HF,c(Fd9/1+k5DR@AI5NiP5=^h?B&H*k39$L/KQ8CNjHC*gs#rPN; -P--RtW[#pGoc!-_XtgU!Ir4iZdK4>VU((Tp4?%D^Uj8(eGcHC@b)0bYa)$a5A2$2]Fn:#$`7;a&67uL/ -o:X]2Lt35Za/q;uAOjHpg\#nMQ=OB_(a&>pg#",JS,9spiaYPLO8oo2Z?UjLKDHZ/uQW6!aRru8^\+&QT -jIWnO_>U5AI7"IN3!*9g45Er"A*9fHJtjq]"3fipI) -0nRR(MnRr"?QNB%Dtg!#<].Kh)*Qt?-&VRL[WgAZ2Nu=6=mSP*Zs2lb^:nnio,\KL*&>XjKq>C1,A"J^ -#C_q;@ZR%2(O\mFcCGDRFi8PZ#$02\lOSC.QRB3\j3up9BJ371fr9@E0b*]Dh$0FW1>Dcp8^u\1$#)Op -[1_5PT6;R:el1?5Rl4tn\+-=iBsKgNJ[-Km_EOQ]IYV2ZW3pi>h8d!A`5lRkchJ8f>-^i%`e:oAs1UI, -4ufMgm1rMZ`.LMgm1qJCG1eJ7j-ihAj-j?#\CNU\fS-$nZM&L``tt?jo=X0!e38irYY -gj-8%mNM+TEle7g2rdo'2RRWTE7R4#"oMdV5c8MVcW0kbFX,]_NM -S&[4oX#.B39e*]u?#tG$>GTr.^q6=L@=JYrW_i-N0(:E/CTg8!3u203qA8#^cQ6]h5bf+QIJ;nEj]1$f -P.fOX-c#+"6Zg.*g,L$b\(![bgD.0/jg-dKh&i*Giic73^Q3cEi:"q$C%N+bFj^(ob)uUZI5kMmc6l>q -G_n6\f@p'0$>2b.KI/iOJI>\6L7A)JUoK\a2?r#_TZhD`+MW!*E.1lfp;jl'EmHhWW>,WoFJ-VjGj"\L -0@39ZPgXo._MAEJ]X\Dri.??W>*ATTon.2,gZj=B/D?$8.l\i1NV#R.C3$F07CtUHDYK0](\?q:WMO?( -ZI1*!g-ApVnFa\=3IUc'iO*[N<%Sj;;uD[R7d:/i9'RR2[M6k8-+`0Q2Y%KH9@h63/mfTh=\)[RW:_R^ -65>j.I^SpCnB5>%-+$=I]gQdBBaoLC_)$8HiPeZjLkc=,%\Bql8kPqf4`;71bla0q1fq9/^Kbs -*8>7o74Z=;G@A,43\5tCCa+kB22`^K261*qY#=YF;fYW$O"\XL=>>)B26lllZM*H"mF?]fb%5N&fWf=\ -)>H;_d^uFN>2j,HeFL!5MWQlWQ.Od=Z*UMJB)?a$2"4L/IYZH2^G?@aLS#j:!_06AB -.Bcn_-=:8Q+ie^fpI/)*-q`;*m6Ha*W60U);I5\jiXN84.Bg&O.HOQY/%k^,Y>sKM*LH=H^X_D7O=TCZ -rHB]orEct6FGi_9ebVidYL6T$j]1/!oLPQ;8i\W&*5@`&f.&kB@o`HRU`@mN*7kdYA%Pd,3jh2oTLuno -*&NnEP=$b[2uiB,cc$r(arQt9o1P>=3i,'\7<(nEeI#l.>d`mkPh42<'W%@@Cf4T/iem]3%<p`G>8j -B>15?mf0b&0Pn4W32TBV9IY?sab[V6i%i`f\lF5-ZA4CkWBHT"<^S48DN!=#?c[=,Z*U^%N7]RCQ]]j; -CTi`M>CZTjlnZH3PS(>l)<#dE7bEXYYBYfB=T*F]C$"29[7jlWMhd%a!uNA -&O_.R\CJeVP.OR*'tORq1ilt.ah$/EGRDY3nlD-Bhd!dEVF5E -];%B^J0T"NC%_2eJCc%k9qFbq8<]BRn.j0'gPEaQ7dg7S7QdP20I#GXQ)q+FiE5nPrtddN%#`-^nnsr' -B_Hq"l\=jtb(jPHc1He!drX0b6<6%'Ml\ba)hrPtPC0Y7ROGn-[l4u2W'&FEW`pN$hN%pGEQf#Es,O"l -$7Tl%omJ)SH89e@]iCY6_YE`)[mkZ.X\j#M25Kt&hd_>jf;kF5A[XdM7OM7'H[bdj@\uRq^m2ir0*3KG -d3_1aN@t_fg8Bc\2Qi/6Z(L_/j7"O(deEH.AZ2h=jA5!?6_=%$Te1%laAZ`C7:ojOGRK:9bC%-FaJ3Tj -h@5Mt2t&D]e_Te!Zk&-q^LXL$[gO\MX.Z,3FOQQj0='o*o1E9WG3FUM<;ChbHmMM\,JVadb=*HWDa%Oq+RaITR'mWCT=aZqmU9U!:/^7Yt"Kof=r/MYnjA!#234%7W21KN\rqFF!:uUr[M&a2' -8]2L6;9H.%;AD!\dqGJ6?KKCqi]1qQpH5;BR8(i]Au@(7?68XeU/_Gd12"jCO'N]NrsQ/``,.!S?G5o8 -?eXt5n%gjfZQnpOn^iD3NZYWX$fC$AhgKa]&Wst4'sFC^8W.CsT1R'ci`&:-el8.LTt@122Q#0+-'74? -NqYNLbYK5dIXfD"LYq/lrs;iRm4FO3]k%i&\'3fTh#>/Ak4Rj-Jq6bi+ -=4^4Bc0e`[drt/M=jGKtNm91g,0p9:AsP6&frpTl#?@ss%3lAd4_!gcqs-82p\:*VCAXXkfb"(8B/?c7 -AW!-fb]:.9=qBniF+R_&QF"9(EKF`l'?(6.R@1s"MK3C^Z^ghkAi[1fb]7GJEjr5u.o+')9?KUVpb]-j!Et)_!E."70J;c39c)ch1VJ!N^RaP7l6g>9H -bB"6_q880F3@WulA2tLC4NlD41*:@7f9ta50RD&c[eE]1/j'MA6gF%"&(=)9Dl/7eV@mEl=jD3ea`JO81aB>s -mJRib;56c/%j@^DOb8l;e0l&tjc!OVB(O_,+bpT6di2P$\UpKgG\3j$8*r^tM9+SL$_W"$$];42dMg4D!(jormQkl -F_^EiL?W[J2m]#uOn<1lgC,I$LP+`s/8+O_B0"`"\V$=3CbOh9hX4.*c7EUT6cXF#M5K3!bAUZi*K]/+ -,jhIo"RRg5,S?i;=jE6VAiWfPR%:a.TV/c\6F*$P832!]1[*Y_j\1ZM/E^6PG^`c+erZ?Ep[1(CfR42% -]#V"!P2d%,`,FeVFeB'uJ='nXHF48q,[j[E#p;a>]>l&E^kSL4ZF/F8rUajZh>:hKmG2R=noVSp:UINj -"Wm=3i0T[iC2\YEkt4s(J/!4i_hEcMpEQu'1?EU4a/qVDm44$^K"H^^D(l/d.IYK4S -_+^/jeYlj4a\J0R3K:QefmC5_XDX/Rk7?\G%HTrWrfT>[dY0CgHS+k4oVcb((VPMqNHnd;7^:cj(2KsV -kjcT]8ZW_DG^m>QIRUn5-R9\G=HgWjXdG)'"hQK5?gl;WOThdSAIFS+79X2"p=*'9;O&B@ON*Tg)6XuLUUI^a\eq1itV`#^Fh/W;Z4dZ0[OKmlk,b,.QN>=Htj -I$CHbMqKTBKCRBh?RFsS*n`$,h_DlGBT5?`.S\ -ke'@T4+6qGS^?(pLZlRQ5PFUsm2WJ.nnY"d<^&q3=!o6gd(JIkkf^0sWOIsPnW$!&nFuD(IJLr6kem!p -^np2`@^"T0k$uj7o>RPYqk(sKW)r5ZJ&M8EaMmB2bIX4CP]]5uHdf-3[]O5ZYlQYO$R"']^ktHo=F=lGI'ZL0)3sPQJ84;AhfK-WQc8iBT"r'g-?YT -p:)i#E[@Hnh=J2imHr-`mT:KtfBju\dj;*S0&(V@"FYN$GM?Q&=H?XeS9?^^[BAS*-JG3'OjS=@pL%;d1.XIt]$]F'H/7O.cg,J$jaB*o3qKqFbL8VX)qcg6H/23,^Nq'\2)m4)$$ND! -$(4_`P3a13l__lT]BHP@37`,8/m145Q@$WTRTnOjMguR>*e`jGYJ2?KZJORUlPZm.q&,fLa'SeLLo(#p -IJX8S'\c:KLnt)Am)8TZ(H+M9<\1)P'G1AP13UT6bg+juV3no6`DV41dK$@N$@\sV$JLJA$GNNB$@8LM -$Mk^HP\YZ**7taG7k=hYLfd7Wm/9g5`T1l+/7l';LntOR$aCD=4'L-Mr.q3-Q_GJRNEAecl-;S+`DUHD -CP39m3I%BVSXf5a@it.]*YGt3@_1p##dD?I%'RUjKq5V9a?84#%XB@]H.Y^LK1AkYi1SVClBg`##>ZO6 -BjjYl_Q:@T]@#$@CA74CO-V1nr0DoS$npAAs+2J]dd5/7V&Tm2I(Af3K5#"G5I+.qo6/;l8CH2:nA@oYs%,J/B-tuX]S1>O"6N*44C<68n,sZ/V1Zc -HRraq8#b;TZ5$"e4(q,8`R^$N=NY08&5*%]=GeeA.;!"*`DSDdLnuZfR8Q.Z+K7_%Ak+Bu;*udu@f,Sq -=GhA1[pgf7N88C_XH:itT)Yop8g+EgQ6KX1oNHmBVVaI[pcu*K9J/U^,s=5&^N%aYW@1MMe=BN[Z$*!X -fYDD5&OM^+Q82R>=N[;,.[Dh<`JC?aQ?LR/P+6jB^dcA3c+7G3^Ic)FK-Do7U.aK!>JKEs=A$$*.$c'Q -pkX4_[UL]JJ_l9\,Y=';UP@_AZ&$Y,$MiFd.>VL#LnuZ*L96@d`\4,PGY><+5u)5b'L+]"pW+C$mA?/E -nKq"',enpG8[4LOI?$Bg(3LR6HJ!cmcDXW5[UL]"/mS%WG0-SBoMds\Z_+Le"\LJ7Osh>o1W8-$2-l5@ -jBLK$@dgmt^1Jfp)d>b?Y;K7$JS4i;09%?:g,4o\gC:qaPJ1r(jmr0H&Uim1.a=#](4N+Um0;C]MA-!S -;'>;[EW2T*_(RZDhK@auTO4e_75a456a1 -fpNn89;6>mKf6WILk'?TU9+>c:E51Is1=c_"TQ>JqiW*NOjqPn,$HB/t_;b<4RiA%t0V&F(.b."o? -U/aW3dAeAodA$qpTs\m/)o)B/p_[VLnRQa:Aer,GHURA[4&gPK4)A]f>7eCWS8#`XZZ>Z,(f!ks2S!!M -AurK8nsf$i1X5+N?K<@J8TjEXckXg0:>g#%DjO/R6,+\>J"(mYS;5s@3d1p6h/o"G9ch4>%H)Uu*Klb6 -hp0_)Y(o!I^LB.=]!*J:9=`bm[2Z_%I+@;&I]u>NVJZ!mLh"%iZW>+!3nX9f23]hZ85 -)<)(1[[lgUQ>kTI^>o2[p4D-i472G3XX)KJI1n]Hd04pGM97t^HNW*fA>c1MX[SFu6T;\+FdR'mT[bsM -Y0CtOS7@>fYO^UiSkeb0B/*FR*&20pQejH,!FGfG -7\>*=`_,U"AF3&$!`sN*QBG/`SHaSt)IJ6/W[T8SKtd`IB>,InDR!8P6f9KNOT8^]hCae9[^Eb)b(\(h -OiL'dMj8uNrpa241&pqdm'2_#5,aYfs.3eP3-V`;p`?D8lPk3LX$o6+`>8Eb'X;:WYl6_ucdVX8?e1r@ -\TgF^l_6gjd5c-Cn(19R^H8E`f6p/jFbXd"<&uj3S[)FDP5q]3Z3/&O -(ACL^/OA[E;S+k&#A(+q2LK4H;ESh,BU:qV1T=a(?`/(TB&K`OdA-9`hsqVDen^5O:udECPq-r"Qfa3X -(Oc8S13EE_e'%EM1HPd>Nm4.I:Mb=p-^_;g^mX`[Gm$hsP'B<_o+s.Bms8!J=>7"s#j -7SVHnefE#jMGc*Bg-S3"Mq=e2a`b.,UPSE".()/o3`#'J0qO;X%QEY>=h[X#WAAaOMl"dtLf+U08hE]A -Ol#_Vo=QrVYB]]om/b5D?/)`a-PW>6dR>*s/lCl=1>BIrD,Yb=3.oa@Hd$;/4.(/PYW8G^A/Xe1LImi5Fh"ctLPhP5j;1tU -Lf2u"ZkT@F5T+a*Kj -R;!pr,7_IgP^4/m'r;,"'W%+-<0Z,!H7DNMa[83Q=qRSH0-a(Pa\dl6:Q\D;/'9 -Bk?*l)PW0fC-07Cr3e^c^)3^'R:X>^P`Sg5WEG]fl>;Zn`@*UY'.M-!rcXF5ejYqA -?ReZ2-kV85%n\s3og4Nu%r-X&K>4n12@"XJFd(e&Qg0=M.Sfnal=ECi)L5`cak6m3h460^;/4HoHBd,- -]>f3:.6\WGG#[0as4P(k8=@al%R]b5,4mljr)N$jaYt3+:sdri48%UGj?BS2iSk8srERS&+erLJsdqJ6*YP)%Fs2#B(W5$)?hH5JrY&X%K'.'l#qFomGF/:50AQc"W!./SBU0.%O"3k! -,l+0.'@8PCL$4G0=)#@L#l;\ES=jWH'>r.RQklB.'7J46W_P-Jr?bH^8Y]@OC\s.\`(co6[\]%&a^\E) -cLS6CX41a1ae+nZ2P$Mp**qN;Z#2C7e'X*f<1A%T:/Ge2R(*IPp7*pV!k$^K\d:2lrnu*QJN1)XPr?'M -G`O:qe\#TUFb36^1RCB$$*(udlNEJ,:/EgV22aTWf(-=!5'7MeX<.1f0nQnA[)b]ZmpY%m9q[oTI-ik( -F;&?![(&(X:/G6pk@oq"SW$_*FjYI]tm%G,odsh4l*i@rat'W0=rF --uRr]9=EjDnX]R.A*V%loO%64e]i8Z_sjP;KpO@4/h93BV%(fU?\PC78L)bNl+3,pGd&Jt@e?*VHPQ:D -=2R"sVL@j7hVYjc2[gYf8\7D$0g?N=1?f%Eg&i^`iQuJ#.+G%7N6(s*N[5Xk)tWo`qnXZioRg$'Ua7to -=ONo6;JadX!-P3_N7/]nc&"B[647TTb[J#?aa'.W/Gf:!'7SZO6),/qEioXCM -rJP+h8XuQScdE+`\*)N-nQg-dD`hklf"Y]_4/Br,(FD)Rknk&2'7AMV^a!*lB2=*<"CIFsoFlK8[oi9$ -r?mU=I+NcD-$PQTo&^B4Dr/;/k5BYIjY-7*rcrqh#;7d#9\4N?))tr-2G_PNGEh\nfn8dSYj'$iT#tKq -YgQHapN7NfHQ==)it9a=a^=<:B!`L10]T3[JU,9A]YEtrkd57Cll)>qc&H_8M=T">HA%V0.jB)!U1O>i5QrfqrK^f,Mi>+(!gN_Uq^&2&W)sg"U@5`C-K\/GQ -^eO8d;tRJ[Y/!_[\J#jB(E.ZMXq$F#/Y+:G7 -5b@TLZgG?)?=4i8EP0'qrWllGAO':B.da%d60=)q2VZbFQ$0Sf8ulJW"/-7t<)-X..Qs''YXdiT,]Z\W -A+NYpgQb`a.]7PHX*Z=/V4K+e*?fRSBO9LnajJ$7ba(Iko`F`Hmc.N=d!XXo"OMRAJU*E6H?Rft"_R:F -ik:$'W(H8Mj+D`Md5-&BTQ^j:R>kd(2muVm7:C/m,Rl]dRA+*p^Fb[:9Alm]Af3as`9sU8D0d[EZ1$%< -amZa;E`S0;It -Vp\=\*^ifc2#gU!:F19iYKRc&7%R04lCLUpZ.jN,JE"gufK>FZF:'aDKkl(l)lq9D=/mEi.Odm[<)VlN -Y%e=Yo_)1A.J&PLd/&$Ml -Gi,n-(5Je#Vlm07^]PQ.!lkT5T#5=H`'+7RNu)%?WVsV6q]ih)iHX<=rt\tUehfBWd/(W-q?LZbqKQLI -=s%ZaL=SS\ipBqLT^I.)TQ4aph!#TN=p&jcft=]k_:>qWc\kWc$Oo<`,2@IlUq5-t3LS7jq@9n3ksKHm -J'bd6^.'p7CCP,8r@Q1Y>5t7EBmmW1.BS*tiRtV&O_]ARB`7PGjkB*pH>.fQ#.6XohfMbnKpF+"lW%+k -GER^JdeYrt,H];`37Rdait5I%3;`Z)KecnY;J`trf6=%`eVhXUo3,7>hLB8<1V.ap%XrO9k5t7s];Fc[&mnL$*Fom4t8=+ni5m=nYnY$_k#X -phD7Z35(S\\H_&q<67=!VdT/e_na&l6,^$g,MH,RI=,?hA9(kD:Fa?!1a!4,J02\DOY9hhJr4ICr_r^,_@r[:MA-Ci$Yn3ei:C2B_3,`3]U2',MQP$ -N7,Z[/b-g&,TUES1o -lpf&hY0*!tKVbqp_G-HL%aP/.=iZJ/U88X1cPE^jDU,1eBAN2X+?$eZq08HQ;8;>/bB_h`7D,?6/^pgh -b.';;:.%U.'^7JDCLp3S^'P1LXS61tZPBUmC0^R0m?[ItWN$m2?$>dCiJFXan]V9WZ!A9F/FCg^/l1Ne -Rtc'3`#-*U]Ztin%lnCDY*'Y/(]drU?#4frZI;PdEB6fP -%66OWB>+01)%A2q56JsjY!JQ;JO>@FViOa.iZH*@k7Z\,";b*'Vo1HRZ"2?a[(?ImebWP&C:W_JHNVi& -@Q^,q3$VUp10,7hL0W?t.+U7b^0$.tMC6ehn0G^tSj\XXFgXE@*(EjOK4'@]"&r#7qR:g=dKSTO%. -q3i,jef2).4p5kFeCI%[qop2gc+29B)MV9Z[c=Ue)H?@R/9CDn6K3iEnFBn:@9_hb;lB`k>N$$M1 -Q@LXoc(iB:p/ioicd'%M(]+!EF&5`6\].j=g&o?_0mMXhJ$$$LR\R2.9<-_fit:)h3-7FWSa6GkmDAYc -_OM-.EqT/c0:gGslY?@V28sjK9.(j>m%rt'5M&WcP!/[15+$+TGQ2p5n!A&u>ag/V@=S<#8l&WMq:)1T -(JW\#E8u88P-n4qUb^8[4h(hY>3P3bcecEdZktGWhr),-Mm?!F)YiU8r#H9:g9L0s -T9Ms3Ma"PonN>E&'[k:S%-caP<,\8;GJtH$<*BDPbSojW=s705?aH_Yj1_BQ&8c1?CHPTteW$amC/;qp -G+6'%p=$+aY'%NrlE4-;2RST;j1k:ZI5$,L(L&88FXWff0$L3\Ms\rimYg*aS!l-*S,/^`8A[Wqr8kg> -Y<1SYPV%JG#i0jJ(CHXTq[KBg-XbHNj]8jD7:`?&^N@d1gXWG,?d8-T>U\H[b?UGJho*IUKU34G5P=T@ -7n_![HIVTX@AWDBbD2(lSK(kKIOQq=g?m>go0X5a*aSCa`I2Y*:CT$c4rhQINBX%eFk9tajHoZ4i;iW; -D8R:5lG=<5.96tmHjD5H?9Y`dZDNs!1V^Ns@V?]\Rc-hcpLA/CeQ^%%PLP)sG]]TfI-;Z4O?DKu]1;!gO( -:h#GYZ+:TgB%&gH+hIsB`K?`d!F3g'rt7GlFurb\IC38hUj?PrnG[TBQJCM1G0sFta,fjZVkNq89F=+8C[SNLk=1^AX[a!NfpYm^Y[A!Q6c=Zn9-:]'ZT]4:VN -G@p_(^H.F)o,[q+^T:Z-nQ6RBY?2[O`7$KB%:OY*QoTMue&V%C8)YoPAGrI&"ib22[+JG/kf-u`9=7j5 -@rQhhFWV2P -ht"+ri3L5kdbl:=iD&AUSX1*F\,='`h.Nl(WK3HK`fm3-o@.gkT!8^%Mk_id,>*a$O*O=G;"?.UaPQ(( -lB&F<=]YiNcP!;0hb&?3PeQ,NXrk#SI)k<4IDY2grpUt$VWUn;-a\LuNRJAC](=n&XEi/=o60HE5/`H> -LYef,/oW8Uho[f[eGT36'Zhm$O4,"1uBmG0pS4rUU9_CaT.)4M#/9 -%?7UK\=Hd5lFW(bH\[*edJhG]r4^2EpHLI`LS(doO]EkF'_C -dgV08ZO`!1C98K"4\4'3MHLbIHaon.Zkq`KdVT6"*omd%TbW[n&Z(,T;_AHuk*[%D,M^o*WAdjuFOjU@ -\:T)Y`sSloC>SB@B?sm%OQc?\lG!nmAd.2HC6Tc4*P^r+>jH8GT$6Nni>f]sQ^`JlrLl*+O\t*AIg*To -i%MFh54-glpfU[f;g^8pKHl:7D7,C9k#'[pQSWr8;$M==jP`BX%ak!t?N$d\^_Sf2*`":^Xo:G`Ca]CZ -Q\B](KDe,c_N4t6h/ptMmeX&N2LUhr?W$5[,?5-C'/J-l)//?k&?opNA9Ig%LRl*SpA2P^H03cN8Ie50 -:*\AYG:IfVda4AsB,:6eYa`RR,C# -RpoHWQ8*NiBK00X(2gfiGfQn(nR0_o>9n)V1K[&Zrdp'4ALq5s1egiO[r&\[]G0)9VQCik4bett]B_Lp -8s>hD_"5e!GLV,[6+`lIbQD5Fdr05R0E2f3g.-]%n)hRr3dCr^m#*n^2VKW,BNCNa;1njTDtEK>2qD;? -<5olR`nST3gW97TP,lQho5T9/Z#^B?^Z2AU[B`SSF0]h0##E$8atf^<\%`(/]PT"np<-)n=mXT0Dp=u8 -4k:XMRa]DXhcZuso-@`&(-d"]H_)6kqq]E!$kb?V2YR53!M?l;md*:b]p%=Vi"cOn)tjM+j/%Hq9AWF! -K2P+GX^+EV@?'Kb"R[Bp;@FUsc)KENVheUl#JH2sd3nfcPC[rj"b']'YP&M[@hHq9@nPSoSJ_ -pN1,s%7_5J(Y?gG[o:*T.s\a>N]l92IrIo?EOOctGKk[u[WIcMXV*)XDFdC#Y><^54dc7toCnSX=iCXN -ZVJ_""6O%Eq2n63QRp,cm&D3]7EqbHXtW*-'JUFs5R]Xub^5stUZ%dSG*b*/,R -Q@)iEFn;Zl;p!$-Nm?:iDAO>-hrr!ElDn26hEn93f:GnH.g@FX;i'OAg"j`N]5X^ -[&bb7/AcWh*U@AM,_s+#pUjEo.b;;WdG&m@j:W3\rEWdf6h3gPZ>#=`RE,#?8uFb -@-?XBlWPObd>ho2HR4tU^3T."!jUt@\Thie[!qCIK, -nJCRt*]W@b33uCso`'B0&*fb^[&)K&g/@;U;.0?HI+qQsMq_-Gd;>kkT!f@!^Z3M'3iD3g?^?gPmN#u- -FbEt573Ts&ca7\6T.i)%E[^M-`W;Y;RCW+SA3:XpcE-tEQ_e0HKHA6m6%U -@J0uX7GQGZRPLip49E%m\8s<u'EEP,\[0oF*i'c9=Y;&dEhoJ@Z\.=Q*F()eFo-SP&bfES0h'h?,Pfc:F0!%^=:A9f9"PNIU*aDnbpEJj%da-rB&C8]\bo3/X@7\a -@#a1$gQe:8-iR%4Y>_H&!jR[XhF -Jn'HMhGLHGY/2-.bq`MG'ZSmk#ES6$=ID+d!lYG!7C`J7'Q4e3:jiM42dc%/0`mu0X`r:_n_KK:ShN&#H`gEW#6i$JdO#BUIkHK]U44hghji*sKX7OnHE-V*ndtT#8 -:Pm-V'-f[80('ZI97qGql9!bX;*;OZIUd7SPl8U,U9>ZO\MQoqj^5S>\7oc.@r;@=XN.2`Nc`T4Q$sA) -_Y5hUbC&-a4)c,jl!96`FN82!&(M3ISOu:rYH-14Xt0$#h9E.!#7\#Sfsr5&,nTb++.sNAOEg6ciWu!f -9ka+>pB;uZrq[aJVWOOr`_AXDZ<*"D+suNMrUJ(V?]KS6-D+QVDq#f?@5BlJUV6NMRfWqBC;\aLhFFIt -Rb3+BdohC>U]*@#(WP6HMe1SA[1l360f'TMWLUH_-hfKV#L.%E)&;bkEH)4.ER$Wn1/sdM(aE6I$VOIt -PWUXJa8BN3]`Wn&RA*Q2ntmgAaH68anMH8u,a4P`b)>ZBe?F/]B\nuR3-,gQ'QBdJPoQfrFr>:<#'lEbe9BNp;P^^V0Wr$AY!e8FH,YHN-4VCgWa -r>cpsmF8HjQ2]W%kRd+kIOFZ'JU7"QU@4H.k>RUQr4E/DEai`oPSJ:D*be<^W\V_F-ke?(M_^df;2]\$ -qT*ila8>AV%]c'^)N5ABnh'7o>c>J9.Z/./D1B#FMC4^1Y'M5Z06+PJ[L_-slKncr$98\t.^U%5rHQcb -61H3RAM/Q49*q2km!RM%#mDF*r?]":1]%Xr,62V?CGt`W?dWafZ#W9mF7Ls@m-hUHbNgWPP],c\*OZ&_ -4iLKb1SGj9l#1QtefVQ)X0lge#tb -Zq_(%V2())oHWWNSV&?aZ%3k@'`*]9)#h6(B@?*aIjN^i1L;1]S!\-56A?GS=.*COVt?bn;pg99E;IdC-T5%"1%S1OCLT^9^Jjl"dpS=!XL=)aXT -lrO[WrC9&HfXCVQUtK@-$-m8n8=HL+]MBB4Mq&RjqQZ6/t/1V.t!C,`SG[f>3fi%BVKo7$(. -KX>(u0"ahc>l,8Dl["OtV+"#A9@J7VFc"2kV:qO,;Q\8fWRduu@/Y<9lV_To]#:1[?)mk6/oaRBI?&Y[ -,&NhtlaSs@PRNfFFfC8M913g./oeUQ?+T4fT0$o?rl/ZQp3*10i4o9OmGq-N?.qE='.kQ\/3Ajd>Bl\) -IRH6%K,4I\+$'^^^Drj"Op1]32tGq&"i]Q/`gG;c^GXYnp%[*JN3etRD)BEqq>"O7K_;`E(sVKKqgOg^ -6gb?>ohQ*225V5R"Q7ZAZWc&anbIl!YX^@&DpNK-@(C8?aXuPc"_ma:Aa)Eb!@]>4iefOZ^Jt?[dqJWjZ;G7R_)n)*)RtB -FmI_`H"f?tl27h66[MrXm#::YrPrT+pSlnE3_teWnKqqi7T',iVrJ"Y]:Jh;IJ$%bED"WR?4Tu5^H`Xj -)3%6Cdap-ZqFG_l]I?NRl?6s9.+mo,`H/c=l>q:A;L0>!cbLVadqH4S-Al#O@GVVB[.1=PWZ(J2RP8<->T?Hb?# -PdY(n94gr_[9bW;]6N;UbSa#qR1[jU$:AG#9?I[tFd_2i.5U<&V1SYgRGhgYMNLeK8-bJ!;Md.r$;tIW -o49`1m9iQ-N%d6`oW^IO^-9=+`S3'$LN@pRA1:)=0@4)i7aP>'-:qPJC?]L-4?.[Z.X?VD9]TB7QlLuj -P'blbo/=?Uc=`1d($r-I$qI'jN)[Op*MQh98REbIdA$qp6#kY0N?c6n.)%u+_r$K&V.0CIXST+97fg:s -MI%kE];dZ_MV)-@rHG@>=,Z@=>#ZStmCoU$Km+Mb4HIpa:R6@f\Dnp>K.HG,fq-YtHK(!,KFf%;P)`Kf -PL*7[Y3Idfg4lPUc(^gd@6I$C3Ng/@J_1J-DCk:`SSadI]#r;f3"k*TgK@e[ZCBCGG+Ckme\aPJ^Z\P( -;hjQjd-32QUJd&XgK?hiTkE-^+Y%WX72?'==mD`"c\NT$edSO$3Gj%7jd^7pmngb5dCVaB<9nO2Y)B/o -'LPeB[8Ebk8!K#QG!2+MX]f"'+$'+-MNFZCm22,1>U$H@20=;E8 -)9ke^ef44*38ZT`!^;u%cKdP]6!.XOspgC'DUOL92e\^;#P>)F#0eo2mu4\ZD=Gb;BG`@D_J7tkA;!!Mq11?C!@&*\fkU2RWa6_g>:rm -DFr&E4".A6N8oX$dJ,"J+1"+8J#)%n6)i?oB8*Af^C9E@n[CgKah+MgVD[L\^n0O$hiQMe/,>W#G*gAG\`t,Tm=Nq= -"a3>,f!,_Jk0CbR!hF#]b//#jMK*^BKk6(@KPhUufOu\Y*Tg"AnhF^mU_SQmQ(N\7;fh -N5"A%P:Sj.a(N_A[m2hM#'onM48o*QGFY'UpGj=W4hGZ%\Lk5JN4ii!\jk^Np&$ncCaoCFgJ\#?\"t(V -B(kEFES+/>V/*ct)`Mt)>]1Bud:5U^"9W.66e6&VaVl5O3k8-#=W#5&Y%-8W`%T5:[H"r^Yt6aXV4qa"i@/!MqV3J.;2Zu%N'MXZ=oQk#6AtTLIeKsggjS]6;)\Zt?$#C%*D"Fd1V*FM -L@RIqSJDPhr2YQmp)XAE%M?]or0JD&^GiNO^.Kl#O.:e\I6hjGQ+gPMr<2h:[d4"/s2M8*Z'#26:U6Zf -??k_-Pr$22RBtUdkDCu8Z]"%Q-4M,H]T?!=]*HSam/WZH;Jd,kG8D*MiCohi:"2e"\$TNr[)aQb+[K0J -DM(0XbE_l$47;_rgUE)'-NuXP7%M#W%P(IflB59f,Se+$@CBaE28f!Y7ZR,?jqQiaeW=";W5+R!IXu$4;3t4)J6h -XXIdr^GKkj>sDTX"8:uh=,Fpgo -E&tWCm2i/bNdGU#O;#.O8>`?QMi,hfMXf5e[fV=G0VYM -A;I[(V$/UeIFKqY%Ft=FjDXljYn]`hi>$'k4iHLCD9NHQL_B0AO",'fO1Rf7.W;H12dVb4@I)UhgG>8" ->rRB_^$NccXtUP3eMd,';[G`Uj!WMbJDW*!M*'F#HV3p-2,D/Ggi#YcApFbq%2cY -K_#Xklh$;U+Hp+PkqiV#L\.Jt@ee%'MXrLo7BY"(b\rC3U"0[&beUp13T)HnYK32d-0TAr^kbF&[sSaq --%'n-#'-4(caNckO28>r_"9@)>/CA?N]r=9oJ4lr\'2#r,HC!)B!RJ_\,dt[+fup:nW3?t(!)VpONRa_HspPF2K(`LrX/r7o_^At9JmB*cD4#>9Brg8,'NLX ->ne0oBj_VmP?&XCCoNWH71il$McT\EA9gmaD!H?CE=:BNfcTc^>8FYfONT]*fYtc^+k6G''8L8fK3LM0 -m#R7Bl>OaUNQ,0_;LZjS0NGm'WPgn":;McSh<0/o#0e.A5(]DZ#JK)co!qt`RA&3%&u)+4MrtpO;C-nn -UH-chXOB5?,5"TC[!456C#c8R$2$j1.IJ%\]Ao4cd`LD4es=$bUYd0M,O.,SDeM+i``kH$s/"ojmhM,_ -$I^d%?d^^!Z6%gWS%+.1p=1/!WBW(h:"SF*s8XN>i8-.:V4V$/[H=X\+K8u\'4JE=_?r];t-[QKApd:9h+bgohY!Q -ATOpeRaTM(;@.](_-X;5*;Kj[07PmFY`\S7i%KLYp6Bs"of_co:@E:"VmV`fqBaH\c[33XcrXkVN+@th -"iZ2-5:aG"CV2UiTWa5FlB,$7VCs@320N(_5Cl0XXr.*>LF(lGT#S1;cPj1;gAH+M@Xl3]4=OEla4A/V -=VGEf@0s"[Kf].NAVMM8A1tM?@,^!!/=hJ>iL"m6[fhB1GY$#%*.#n[s,PnJ=P^B(Vm"hI*d_2iV>&QG -A1L,sl+Jr'9jI.hF^_'+Un+a6X2[+AZXhlJ5A;"gHJGb8b_ttX?huLrqh&m8JZ$fQ[WXbLQ7RQ9Qk:n3 -ZWKJF;M=t_LMO"Y:Z617Il9o'*9jhmfJ-PihO3T4Q@5=Z4-a2$c:!^tEY$0mn9Utol\Jm'6nOgI.RnlK2a]6XFeei,`:>3ie`RsDU.8D,Bm__[-VNj*4U -UJ/PafjU/64gYIiJipBu<]_9In%?,IpL22<>.OK!]4bk$*\%$0bhMmQ+3K]4];:s=(9o3`1uffTWp>QY_"RHZAhOlhP+ir(r)Nn0u,Y3p=!tV)D3@rdMQR+/^XOs34%`3d)qQDs@1Z ->q-'0ahjp.L/`i@GTWnuIb?_d.`,g;EmHkZB=IL:&+CL8Fh#,SlmnX=G=b6@FgtC-PcIHr5a%"bcZm&g(c)Mupmb]_ -2/rL(h=_6C,L#eVs2($94Q?0\]Z`XQ0S0Z@2._O^5b4JiGWZD\jd+WC_`_agB\nnLr?+<&MOF)!"8?SC -=)O8EaS]GEn[goYbKYIO[dJ4u8ql1/ZtPd1Nq!q2l8oLPl1oOn["9@jJMh-X@C6'B.)iu]p#QWao&.^h -=TsM,HrX>7:eD4hRh_QLImWC\AKV4D39H['.?g:s!Sq]GBWZ#l_\u>R.7"^kM/, -Uh'4<%_c$<*`#X*VB(U/>jG7Q:1$8E()bEiXoFR149[3o]S=Xa7OA#aej8Qm!`/Y!$ubQb?;.]Jn/^9L -c%.e=-XCs+]LdH,4-d5EWmpt9HYuMpQ0`@9Lk[/8Z6=KfEJB5nCLtmP -%c+j_6<-fD9n(q.^[:[6B$CNM;jPm>[S-FP*^[IX)OF`JUFZ5KdoeI>>cl#93i3nB9.H9 -qL)$#H2H^"5tk<[K`8W[OaIk]hi?Yna$,(#^Z0S<=!aXAYl`F5&c]-^3F>Rn;Cm` -;`L.qs)t%F^M69UapZ+c50mGJ>+s4Nfq6(lq4*kl`a\HC\]T)[/B]a][T\66hSPhT=8js4H@,JE<12^j^RFA1 -:lc7K>J7enUKn,MA%Ye\q1MthTS$:i]',\-rISO!ZLR!oO.s&l?Rj:()&Nr5MB4,%DL*hRp+[\mZN/r2 -0`7&\]BrYj[)g'gHMC,KgghmK/^:\"]/)X/B`%pc\`Ns*IM<-jfKek."S."]U? -UQ*pY$D`Jt:iS24=c?r`efJ`"5Sgh<3. -j5R/qmYEfnPTkhOhL'LCe,Sd_'T)X[F`DPf/kj2r8?q-J$Y,BtA6%Xb;kTB2hnDDVc3S?-g?&itNBY#; -D>AN71%(G\b%4]EM#>Ra4Opll<mA+ -k2p7Bof!@4^):DPNoPEbhE*o)IrCr@=u,6>9TBQjZolso8=L.c:VYSY/>h[;-c`sc)'^p(QM%>`h>#Xl -`]u14RWGi/CMqoQ_:kj[Q4i/C\Af^\+'T87=AR%t6@UW>Ol@l/CmG_t6KGgR8T5\`RHu5#V(M>:Hgq9i?(RlK*\fG(@#6)@,S55Xm57L7!QT7=="k7pS$SB48 -^1_2qjsL0roFOCY7P!O=c,;d$ZHU.ue;/f"i^IAj@Io@L)R;XKGN8U>i6>RBc:;A[:*0.I.(Rs`631C* -9f%]61p07SAg35B3/2(:UWMS/'6C.ZhOX0`j9e#s_7>@BII]*gEhjKoW.,9uXChno1o55h[kq#mj3'E? -"!-2*h3(urL1J&;`[RsTMT66"TbWFUnKstM1I0:Wd`c?KJg]_hVLtc?+YY+>]5*q!nD;ZcgXlbT_"9fU -CFmKno=Cg0db.tW1fB?Rd8N*3JM'q8,h&[H0):ZA2=\+@:>?L+>gcJEN.qUs]J,)'XFnbR!(r"2T'Wjj -l6&\]A:sPVg1"-CF^D3*7chM]G08K))e>)%j1UG8[#g"op(4$X0V"Hd^mc*4jdTiWo]`7]OP'!/05LgB -e3ch%kn6t)'W0Vh9.(_5Vi_K9qtkKHaA*X9/)dhsI<)-b^)*r"YH4Uk4PCf3\m1 -7J;E6gcE^4r%1Yc8Jc-/7?J^!,#-+")p;'UPs+GmEn@X$3K8*6SOk2o&Tk^\D"2jo.phL;nAeGaI#o29^?eoUbCe)F**ruH$V;fAmr -n]b#:(mBG8MReNi5&)mL@)'Y_t_mo`K1MAP`-c*"O;o`e"PF+?35R7T%7ahM_nrl -k?GJAG=,bbZj(H^^:G8i)K;`bcXLBmI@Bk9hMYp[9;'N:&]-=I3*X-SN`jK]Mgap0Zdnfl0+k$%_)#0* -^I%WF*Ko:%`%UbkM%4b@h[:pMCLHU:guB*/FO>[jXNDEjRd(Kul'm%uYr<,4=PN``p$.o>Da+'P.rV8Q -T[gf"%A&Ac*ER$M0+J"E7O=&%Ytp2l.ahcD:Vsh2:kI&f[prB4e1\X$`S[`h@dh9;D9`gXHr/\ll2;>0 -]s$"p&._Ms')DU_!I@?9 -'m`#Y!=:&UFTk(GA8/4)E[/Dc$Lf"p%U6,7(NBDW%K97%gIhW;17<-)A_76=D$Hf8JV/Q)1tm1$9Kn -KZt\NTZ'a"Z%d6`C*Qp3-80Nr<0ecWU9E%g>LFI*`2GZjQ-R!8mA2gnAbr*(o8)'!GAd!$eVA?Ui>R>KaWSk=MI!^oFZjm$uJp -a)eq&"n!A.e_&V9T$._Mf;@a2M%9dbr,4\83F]L>2&UnWOFD$\fu<2CMJU:RMBX^]=jNIZV=&G_lul<< -GNo<7?@,N;:.B:BhAgZ`8X1k6KraN+8(K]Gm,?m5!=U9f(GZ[;B^8n8!I*gk94.DeaC^GZ=rI7"i2RD1 -n/g"$PNFjZ'Eo'`5RO+YiXC"uB9OlV@d(i>b1Jl2%3rkh#tg;:MnCeq7So.p1a==hrJ3Z+don^mqIQP[ -+7IIgo'o`MKR0F+"N?',NiHG]-J?dn6%A>jV&&BmRpq<"@V(%ML>usA[F%XG?YZ2Jn*P,?]0CnAlHr=5 -A>;p,2,`3b!tIu`Ki%)q2@%T?Oh<@t'%/N;C2TFG`KpY4eiA4/)bKK-$VFckIAJ",p/6CX14.u[BA)!& -e+LoXfcKUi]^4g^rA._B,!,Zk`c50oqP>`!^%\Bk'?s(E.[lKO(O[A>QXtp7\)[5rC_$*sZHQVl23DRU -!-Qlu6MCbA@0c%`ZB=e9i3/d^lmqa"lT6NOY1`&@.qb$2)/lrgI(RLi[*7mtZ@ulP.+Z\<<2=]t+1KI9 -A*0Kf3R=[Xq?oU*MnZ!3m\8/u4Z26GN%]!i^ts'5!Z+TiinUmJXNl"3W-%$b!-!!P!%>C\J"cENFq:05 -m>YdJV,^\#0B?n!lWI2=TVVaTgsQcA9-A24#8N*PETjrXgH1]I!)32j2SUS3TWm%T_Ro@28$a@c8CS0A.J[qE`\t#$kH?%d -P(W$`1rK_'c+:+KnaYZ^E>56+*:?$M[L,-r\.n/$3-PV/I7&mI9IN@.J:8pBediVT^05sH%IrOknHNQD -6nBBKNuht?ga.oZ/ZFmS+VfP].8cX3DL>$p^lXG]W,IcT[:ju'bu@YiEXL;5o-2>d<+Ij2De0q1Q\raP -/?)IS3!W?dOE2Z^$`.0#`UY>ZbPZ1kn0J7]S!5JLQ]d6-E9'p%31"OUF5KlXQ'5H&ZDs(/C!E:%D?.&D -=)4(;L/_\0RNiP_=<=,N'Al)*hXaA]Y,DWu1*8M*[==#,Tj*E':qB+QS4A(ao&\cbiEM4hObN+k056YpnQMQHB>ckTJ\ef[s,Q.8^UqC]97$Cs -]'(gIs1eR!oa].hO!H.lOtt>kIlk)h.UkUANoTqbndaPAhm^A4_j?Qm2u-8eYj%)Mbt@n^n.'9?ruE>h -5U&*]I)l!Qr8'NdpIpJsm$LP/G5`J*O3F<]iI8T39jI)Wr''W#,NIZg(h(kBZeK3t>=bDsPFsjhrGXo< -p`AsSId\c*1ZY'AR$RmW0rJ]E3*&6'3mHZQCD@;;%okMaD$s5*@8AX&,Q@+R7opA%C`\kM< -SFMJ>^t"%/2b]eklmLTa56hE&Y]'K"X6O"P0'%W$GqS0>66=33GD5'F8DX`:S#Eq.2+MmL4^+%Qc2Ph` -^UtDg$CYe5S-G#,paU[MJLYT1"?pn>rXp:ofmeiUS55MR(Z`dg3A[,olJqUVhjR!Z\C6IZ\j+YR -`n-u.WKf8'28bmQ1-b)mERaW?)&J/J(Hrg$[/-@RAm!Boj-Xi]#gSC8B0P?Kn+%?'RRPNsden/]\"o-u -]I(lX>&3sSB?"^&2)O@DsIb03.Bf*B-Cfk=UU.NY/]1`*iJ&)0Yhf.?@;V(\5YG@=d'q -jIKsF_R&hi?`d6F_Y0k;:YU5;9iSt%mn?V,H8.k# -GpG3B+&Z@WZF^lC -2e#&7OVm(\7k!Qh7g&GM*:i-%Ph -$DB+@\6G[^Dlk@^j-L2kK?ehK`JLe8R#W3oFl%@aI)a'^:@IuNHlG"6+Ln,j?@:>mj'0`6@&%Z9ZmNLg^J)uJQHf0pX-t4)aAJj(rgZ2@r`960/g_P53ES4P/XCa\)oE75CpDc] -KPN(*)ZdpN1o'OjT7p%n._[YMQ56FhVJ+o1fRNj_c4#2@p0.XqC1_S#H@ukuJ!9`u(`u8\E'5dt\1o"+ -bcqJC^md3UmJ"14?qJgZApuIm:J^6nA+-OMbUafl%hp6�Xq#;q_t%Q\[mS/F$s%B!oN2Lfpeal/qeqe,"l-,25i) -2q&E\?UXs4oLO&)rq[U!`lAZ9Nq/WKrZ^L7,O(]DZ1eVD@5eS.)&eJ+ju$0-8b%8_N&un/$A3'PQ]4l$ -HEThMq,]Z?>+rnT -N.sAp#ibb.`KS=GUIJ\!,+fn4P]?9pCGk])ZYgt[:MdEhjV,K0JI:j=?eAi'3`B'SjHqgS`J%I@6C1Y@ -%4Ci\BDdK"gL.A,BWs';rAVFgF2b]U_RC#/rC[co_V(`ge1ieud,(M[+!![AjPI`^,P0tfs. -\"@:@B.a_CS*Lj)7%05qqi7';]f4o#LsZra+2kS?#'f -f^le:&m$_>Rks`&ofimULYeqO;,/b"F-7kd2nbF42hAn4^?_\E5of.=9'XVrHsrO==JUH(:HZ-R9QjTW -6LmG%h#l>Wc0qD9il-6hd[lqP"L&4\I3<]+_"hj-cG1F9?VGKspOK$9oF-l`Ch?-=^MVcXW3gq%j2-Kd -F*$8RXe3_)'d_Gt7#$H&nqJD3fB(Z!hQ`f#C&b8J*&L1ON&@(jV93-l52432Lp&P_A.+EM3rM3m)fMo6 -+m.;!Y!IoJ4HkLc#q,l@_k_DZ5/7_`34;#G<@NK3@2sT&rsJ]\S#OIPMq^a@8:qt4n..N/f%M%R:SSL9 -h?^uG<6C*cX,3,q;lW/3,Z7n-Wu/ZHNoF);ZqbYMIQ8hr[$(Z)3!/%g/bbMnEn=c#(YBL/5tK9U3rYhL0S -1tNBWh5^,1hf34n4Muf9[rjhQ2''WAoibk"#.625RPa>Finu&k::,#4S:e-iXcp+IfeNfoHT?2uhSZ_1 -cNjl\A%og3rHaqtT@"E!rkY^q;6LQb\0>MKJ)a"WqP&-KX?8IcJtaYl!?Z]=%mAQR8Q+st9KB]h7s*c' -Ed'64Y2o!hhHS-.hIU`hrX98&n#Y.:6]dC0r[ach1`I&/pDMA#UXbtE^[V%Y%*g14&K$U -mOf8[OPF-2]^0Z_D9a6bY4_;NZIc[`0ZRAnBk7>[akbLHEF%ubXXM?J-,-52Fl[Sp1$.igZstP/Q_^jh ->?9p+\\#dsjPmSG;k1n[Ef0t#gSH[nZcM9O\\"'odnK0jLJ[D&pkQ?DAA>\1?/%kWEgLo5>ja4t&fnNp -2Ku'`Snj$"WZ4=8jR/JdR;-.+%)Def(4:h1M$) -bM>)-+$:U;=J'\LAbq2&C7q"*t,jY!_J -]A25%[&)Qc?E[#iDL!i_GB`5AJm>dQr&o:F&'fX2jq2X#=l57p[8<;1En=rWEd&&JAM/0KoCpRWHPO/6 -4K<\NLIY?hKnm)7-2p\bHiNoUrI%Yg`0lL0;%R;ZGs`UAiCc:QK(o_3.pj,@&&7UZ*oD=ba,>Ks&FMdf -j/%Ig!`Y\LG"EH@](g\B)(qG:bcFa8AEo([Z`'sZP:,s9!"H=f`^MXH-X*"RJuIDRe-Et2/Y!#DAcn/o -90#Oc<<=DuDYt,oep-Z5\W))]1<^qMoTkOfht0D/[-6IX>bV!Ih2B[GX0i6WQ?;*XI84C"HXVh_6Q[nSEoFZ@G/f[P*I8A8hT+%tFlPmY -Q#AUqMF(A#,OUc/^V5X"d7!Slcgc"7n,/D2r5FdZHol??.ks(% -;/AN_i,SF#W*b?n(-3ZcL?0&_CqRl`pW@\!?\Rr,`nS&D2+%+V@taF/"qE*'n\4$VlK'kA0nj88_XcLa -duS8$ccO4D[qH28Mr#5W7f)/@3-EK*`=Q\;[g_.G,1u>7.S_k(2T.di]bb>Fo\BSR7l\7!P4/+]G"9C\ -Xc6VBaHJX]ZfF`s+Y^or^0;^_:s6o!h^WXl+hioL>G1KAJnA78KBN)FC=\Q=?72mY`H;L/G8jYH#71tj -o\BRGXqf@'-//ubB?2srs"3mPQ`HC!KY7`>[?Gmp,0>baQ;jY_4(^>lWJkJrA@b8`(29)#pfm,Ve+o#O -\%ipUL'rPIO*"Ua-=+sq#BBSJ(!lA'`mLqT%LU6sNn8cIql8q=#fk)6lJqdaq]m,Vrsaj)*V-!#j:SB^I$( -"?qJds+mFtXhfd3@BBK&\\_Q6er.nn(WEGLN'gt%HN^rA`V7oO+2?$ta.a"8#P=L1=R/,3O7qkR,'U@= -!,qEW@[!kS1S31Z"`B^=61Q0%?4g?+Rd5gl -1Pk5OZ$ZiIm@naJT#$24?Ak#iF%hD1_sQmM3mf:!P#8knC\SHmb2o@ur!iTLAu&7hC;*FOlSX/HUZ&9P -q;_"oB>gWP'6PT_fWFnh*R4YX`!Z"mag%Dc&[+5jK?31E`]r9gf4k2=_g#q=Riqg -<3Aga!4c=BA?t8Kj.K]GQLu,.AqBdn,9:E/nOq![Z9L#"/\YDKgo\D@M@mSJ-d_m9[8uf<@rL,bjgts? -9(#a;iKa?2j<$gJ,=F2,07uD/EF04S0B\W*U3"q#c!JW2cI*WW(0M@L -$aI0ppG2(TdKC-M_:/iQ]cH,[7f3nLDY7>l-KX#V(?/32n&YW1Lo*UjKgbBQ>#>:G:h)]Sc;gY6ZGOdk -N;">DeW/^R:]AAEWT@FJGF..X$62pA#Z4+^q1YodqYae3iNDjlgr-H]Q(*#=4k's@LEh/SYs=LV)[g.m -N2TgD^=p`ugf^1WUN2Wnb55'PGC@h1HF@hunj[ED%@./SihdTch7P[VO^tXZ<8N]l54+;f2a7T."$6n, -'Zh-Q:L:,\AlL7kml#]NDWNXG2Igls5lmCU1H6f/)t=p#1"%V!6mHWkg3XcW6S551g4!hZ:l:`42O`GT -NphrrHD8sA8g.Ko\aO&gCLoBA":orMZ,M"cMI\P`k'A*0Q\$V$]@/V+k0+cJRAf_d]ZJNi9*SU'f#&I_ -`V]*:Vg#:V[IUslTr9+/OM=aGmC5db+O<%/>T3o*SUMZ>Lsj*p8;o=f_rjnCWq[4uN;$(-Tr@P-6=u@X -)qfHPo5]83VGfU>%pa/G#VjuCWT_abQ/%$0oYRjWe1?]eP[$1(0"gHJGf5.P9(Q@Z]VEkor8KK.GF&)G -M*lSZCWI4O,]CgFO:JsTaeb9;[-3g2Hst%Z6H\6#edl_gN\.h`E(qgKHdR7c`qUk*&(:>mQ7N&rgHj(o -quSOk+E-+)P"5/f7]@!gD4J_.FZ,=b#X(d=8fhj*H,Hg> -10ZjpY4i,@oMna[4j'@Qrm:C*ES^+R9R,>I`KuI'PbBC@_q^9t,$)e0JZRLgOh2\L,Nul8'-fS=rX)NN -H>cVW?_*-_R:1[9"#/i"s5,PuUo3^=*#n$ij>`bo%8]X)+gA0l?5$Y@$YZT+q> -ZHoeuri(%MNAHDPn(D;:45=`eFFGW -m+/d6KPb;!lRIfhXTWG21Y -@f-Q.lDJGq7V>bB4D/MFpQ`E=^^:PH`JO]VZt?5kA@D(rRE#+r/,9YYZ(!2DP&cZ-_h/b0QS`;=n*RDB -r2\=ohBV;Rn#spqFnV!s,=X_]SR$>6p@q_U.6b -`(7(ib)82+e@LibM-7N]pGY3-K]Q,KpJpX1:\qio["70)j)EJeA$6?]=lWU(:tQ5B.(tE -Z:#O0R]Oi.@<3k7*.f^R:]Blf%%1.7/#pRM\L*W:^8[`@T=5JF:.4Ls(?E`A;mJ&*M%R+!AkKM4F]%U= -YAgeUpK3[=#g=o)de2Cr/Hg\oQAB2Rs&i.fg>#77lnFQ_g`g6^^B8[gJ,UJcoDbVapn.$0hg1/9WsR7K -qfD6^[^9e#X8mERgN=-5F[YgRi8Q_Leb:18RT$F`8CQTGGAO2ug-X`D(`bJWFKm>)8H -*jP^5pUA8&nee!#R'\>N("[SXc3Su(n^7'r`6g77PR8\M+kd^.ZB]W_9CmV#*TAJ:-ql)P^D,f%hBdZD -Is"&,H&lq/3Vp?fTuKU4(#:OuMYop^mlU75>"-Sob$0WF_j&Y>&`IS"qr!2G/uK"j7clhdX_@6bQbUW8bn?Yk_iN?K'cgmoO -m8UMt28RFmMiNO8U'I0RZsP.&bWY:Se>Z`#m4N$&ImkCE+]hr\A]-W4$QGiak1ZcDTk#!'7U?+"KpcUP -f'--=[tef9'!#?-(V\mDS"l;I"@Y1F@9lJns[p"rhuS`FRo -i^Q&o1<>7K-1,fP$hM)3guZHMml.8\e0^WTA$EBR[H=rRW.EU0'80sP+32!YTKZeK5HV`bppE0K8Js%O6?s3kUC$ka])/ --A;,I0ac@\p/2pC!^i)3V@db/c5DkA,9Jc?`'\c)cO@61c@a?P!tP!?52uOXX?2Mt=<>farDJq%:r"[' -6]k@9&I*tN(67ooK7Jn>lj7a4o]/09jHi>/$E',>1dYX=ir#.6E`hf'$t'!6>[iX5WE-G'l[&"S5%rK, -jS.ZgT,S;Q:28:RJNK]6@Rch^R@6*NN+ls.;Q.M&L$[iVA#CU-4D1_:&Ppt'NKsMgLD?Z0/3oe+Ibb?,iL1>YA)jmD -'7i>*SmR\94U9t]jsf*F?D[1^'09MVB1er[*aT^$#69psTK`0^o?94;8#3V.*cK#gr^l,SR>;buOeNNE:k).=Qj2jNMRdbu&^\eXY\&C/g_,Z#lmtGM>eSjJlBe!.qlj1-i5Bp(nL*N7mNml^1[3`g'N9i\C -AS;0?T"_'C3_^T"Q]Lk.5;Q"C?_*H0@`!@Oo=SVf@tg1W-Zu0/[@32LOCaGdo8IUi(rLkX4U[Z\A^/XPR,cEce%_n$-Jk -8[WdQ,tPumkg2E'8"m6"G:0ll*:L!s(/!fo9;(841,rjZI>KWq>*K*1M#6q;m8#i -jFb3m5#j7Ok3'b6!eY[^"7OSDQA[)Fl5 -e$Xc22"sWn3-MDX;+AL3_CXbgC5#f\9;iRB,3i??b*F9ubj>4hj^ZR,E"osD_,6-&("We&dGE3@O_Ek' -$::F$*)eAdk.%e8=O'4TrNg3$:b2%2d%+)6d*W2]rptfO -]2b:3$ca5L_V]p^>1W<6fUoq8L`#LENPO_:B"bVL%I[EFs2uo@?[Y=nRFB1[D`m)5EHS7Sp'-HCi8W1L -@pn_sCJ=Ks^?)Vl[s`NU--&@"Qj6s<^?"O599M0G\(,8PY@ColSE.8_Ye2s)ICXOrU=d&!'! -WFM*%B9tZM[>*FQ?TN@%Z?(9+$I9iTICX(4LEp$Wjil^%d*Y>(13;3:CJr$L'uu.`8_2gKd3XY":p2$6 -C)qptV;cXdWrQoFWaZuXFKQ=i^ih/.(A]h'1U^%Ij,k[mU+ABa;tP't\X -k#10"!kUK@5B'.*s8>$N2Hds:'67a->%]ash0hu9o+=^M3Qu;=_En<@g;T8&\Aq^R9=EB.3p+uQR5R4] -FmrX61IBiR`Tr)DSiu]>(T2T*e#CW&VD]V'NSVA_Nljs"C8(BWcbEt>rnh;"5ntCC"1'VenD`g[<7^.8 -OEH>b>-k44F6fbE-FehhNA0WBg[-\2dM>]#ABuU7_fK"Z>*6K%=U_MLA53Nfo1"m=?.B&*]'h;3?\ -RC.[^*6JK&pR55i]arnE+<(T51cjs]Z+m&\rB?7]><,T!;Oe5lqq+H9d8ag;X#5H[T^QQcK0sl;l6MrB -*37qLE2NEULt]=]-OC(s4+#bN/eb!_(sUQYV1e1GVfh4:aBO:$oa&'db2V3jTl)>8:gg&BTgNbX`-`g- --.B3sHi$e9!I_AV=t+gJ#<@_@,ndogC#qmtWn*$qL?HGd&][3U4o&<)\_ALLNd9ZLFe"0#!tT(; -ms+gPqt#'mqMb'kGiSd>NkY['DciI;#PR>a2kE3NdE;>WHtm6aq0.5ZZ)g`<>#dG2\9bP;e5:O$#4Q5( -[B6(S=,naM)o%W9C!8.TC,hM+Ic%/>g`>A,Tln?*iN7rMql7N>jOp[C`kFW6@B_p,U$A=PMY\F\aH!X2euGn`]fk?@>_Y99EpK&X>g0X2YHuYG^D%'.,l3\cTk&Yj`ndt -ie][bm,7V*WR?1t,I0h)p,T9VQT(`_:5nO0U^U0c#7n^f'HHO$8fmq4D//>CB-7jti,[@Qsf"2tGIP=`HAlK!AKqG3_L1<8D;VM66_Y(p1<$NU"1$n^Xh13B_k24rF7V -e"[S]:!t#*`$*+8`EW9`[C9[K/cKS$a'Y2.pjk)Yg#@i9Sr@ZmT@fM -@t4L8=j#l6rYQ%`;3gM8pcEFfW`,sUe\?(b/dBX_^VJ2,fCSHU"g(UTrYOF?]:/\Ha511`rf6jEN&ImP -ftjXtqaF#GpP(gP0Id'0m1VXoTATAZ]1M$%?f,?(#3ph"CbC3T4SV@/O)N\-TIRi+:!l2+d?[7&De6nV -*%$*\C+I/_AV!CIMKZ(=B=L002j(4mJJuXI.6j<\7B3!k*BdlW01-CD=n@<5GoOKt`7'V[]ABo/WS4?R -.`qQUC-p48X.O'E1u"/43j7*[PS0+ub4TWLmsTR,Ep]N['^D:A:`'G#n]OONS"+u%iYA+D)p46jl=\\. -*iS$kUp81F[HUiH*Hk81p\M4lTk\e06RqD2hu#iu/t1dWo?Y61.*a^%&lA[%61KX^F`B]Y5NWga&=tKK -ZF=Gi:*E?NM8_=O72aU]$m)S$#su/[q=W*Gn=Sa%>9<3sIrWf>n:XkTs4Vg0M$E8_Y[=AQIS*)];Q^Z2&Y7>;%dWU)!^ -NSLLV*'hg8pR'n4`e`s>;TkMToC+:i&'sOS=@ArZVH#OrBn^=i1C.XiF+26KjsGRLlKslpnJU:X:V")H --9,Hts,I>0.PU0e)PT>26Cm[@4f;>t_>=VNc@J2kDFmPo7eL9%`Y1P+\_fAj*K8dpPe+q84/^peBl:I$ -.E0*A"4,,:,W'bT.e">Ud!C*!TV%g*_kd>,gO(D"ZWWHX/[4rbb%NgYQW@X9/WY(]>(>KuRJj!SKp17c -aJ]Hj-_*R8iPdfOD`HUorkIL:2R"`l*@$Y_Q1DaE6k.UJ__c?JFfck*Pfd*uaAAmHC:On"gLHl,G-h'Q^3h@eM?ab_>dN;-#10<&U -RUT#!;>W>=855Ub)-S.YXaD5,PZGTpnrsS]*b[E\[Y,Fc?V1^e -WEl+&5[J>\.-"s]rTIU%Ja=-Z>*3GSZp73GC=31&pQ(n-ZQ(P>'NuW`[(oB`A_&DqHo!NnhRdcW_`J>[ -:gCW?X09qQ)FnIlm'7U7+R^QL6'6V3JNRikOf+eqT_+>J2auu)54Q>(pXeFJf)c1)[GIE.['$2.1qtD2 -CHYiD]>fpJ&7%U1"I9f7Q57ge8dgk/b?nGG,cq6k=A_e554>hM':4]ZFnne2IKU*c$Y8$fF=gmqh4Xu\ -oh,ZPFtI+:9h,SI1=?5LatAqp&>aEkln&nEOTF'9eQT7^T`n'>fVA\.b?ei_EN6C]c,[u18a\rZpWp[E -^Z%>i+XF1kflRPAed%2X'\tSJA_pV%%$t1PW'9)(?3.M.gTD)SJ%tsc*p!.VI(S*Xn+>/)Y>/\;4k3J@\ZWTRY7^EF$3:m-6dO.1I&Uc'/\&H? -IUG]_,#Q!ZXl/7-H&'5F4aU1_@bK=`;p`$eaeu:*N9M$plli_*lY2qHq3t?)6/PO/.UYGuI.j(]T%,3% -"sV;W]3;]-Z8heG!11sjmcDAUH/Qm_dD],n2g<-*VfJCLKh5-XN[#E-r -n)DY#LE0Cd_o)(J&!8$%,GlRY@/>j79CVie9L!R#?()4EYMH;kAQJMM!;3AX87iO,DLEpWYKI'WL2BhE -_E7>]8%EJR>kK%_L

-UIl@PMAS6fh/iuEF#VB,57aKX<*SBQ67/%ofA`uWrk%j]94%Hb^6Wa;q7bfU6XJs[gjm=rO -S#-h?&'PWniB+-df#ntHhIfDQP<2jHmk>n\>'%BZ/BY^,JF%*W_]K,+fCA7QDpldL2^TMBUA5\E'?>!l -2-G=J,HdV05.1+>NG2(LD6;\n;7$Y$Cjo"=Xo3er6&Rt.2i6hO0#+qu;NgjI^OLGcqVNBIfej-9r#\_C -nULQi7YmX7dmSO?:/-FtYWr/Js2S'es1U\jQD#1AG=Fui4.aTMCl>:q(Z!=^9"`K?pfkb<mdKCW(^Ye9a`_C?H -bVQX)`cBYP0k/.jG\$<@2sr(i+Nr,3OV$6V6oX@MUL>Q/S]N#ZUX'$f-<\A[a1Q\'(qVW\2:kDBqi@h0 -L2hDV66EgbhS1\d&]Zs,C$jcGH0a5IVKlu/DggZZp=3p:0ntc9TRn7hf,Zci9l[ua>84urV;.#7OEd:r -_6N5O3fG4QGhuVroZuQ0\,,!)(Q*dod>Iht5o8=Q_,p2%Q\N/%'kri)d,V:1-%(5o#iA6H'2!pVM/8jpOR,AC=jMcOCr6H4P>X-T,YA@=HV@W -;"`T@i:-11.bY"Dj;4opmPKU?-!D\J4YEdCh%T=mSkB6!j#)\0?Z'JV3:_dt[1P_6b2?m/j.Vuh%0?=? -Z0KO::0^LQ0Z1J$p1pgEh?ms&8(EJU7$9>XQ!]XThZ;)gl5g'OdS_PFWejPd^lnBO.[r5EE[@]!-5IJ -JZb,X!8B4"WIDbo110ccIX/OB"qT8s.Q;QC'P8r_.(KSR5Cn,DHcL6odX%-+D)-$RpHZCg?05ii^b'(-F.a>l5M_(^HnQ+n)d8KoV&rY^^CSV=Du\2K>IiLp -c6GGqHgV^=p`&'E,V8JYhkK8^=*T?P%^tV>2Th4M-_q8aBQnmP.t?g;Ua%=7[)-eeIBf2!@pU(*=X-0p -ATQe2i9%[KSi^Pj5p[mrN$HWRhQ=8j8-`.5XV-4mTWdr(Xh9OF$DQce$VDZ,ccjlaCbq -2ehKaE74P)1L:U7O:,.XhCA\8]2&;KclZ/NUR9Q)Pdt;OW^MsXh.%8\%H4`jX).7MXM]n'6dr/1At"Ie -jA#>?gN?39J;lb^2R+r(.Pk1.78tPpX?O)fKIJjKkHVEGh8e@n82B,OPP=X/C`S_f8$)kLAmaL#R$95J -1ckN\R.DAcMW"RR#8PoNNYA`nBEsVin'6'iF[M3k1^4D';#f/WA%AZQLMcJGfK,3\gQ^=%iP#'0,!MC& -.6&T(b9-ZB)7QLp^TEILPC44c4&I0?9D722-n]d3/uUA_n5rI84Vf?<>,P#P`j&/d;sTCY*C@WfeU^]. -DT@gSg$h[DO8a3[CeEj7kha*ml`EQlnqKN3kkSTl(SC(Bj0j,Za9@S4?-[S6>Whe8 ->O(hDHPW-kRr$W*q4uo9@mFh01'9gD7):p_8E)Vk?#fljP"k^uK.$=lnYCKl>fZgJ:MM`C3h8X]$p'%u -'pU%[76tg#T(>CBCpnW;#_!7a7eKLtL0umgW`+Ko=S2V:$N^rK]2^khe!)A0:0Q%[?1&G0b]r"-rEa"? -Mm&!ce0CZ[pi]A:QtLl3IsX9G9qK%e?aZ0'5J0Ki-0fEM+cXKG3E#mRkRd4M^@")YB?eo#S%`8!W9oO: -`HLO3Z"aWO0FE:O>Wj_g')2@A_^kTu*'!o6n[sA?*UA(P6KV./+K%^;.m82XZ2(Y/%B4(9T@2PUX3\P" -oS@c&IpjjU6n\rB2Bt4Op4J"@iqr$TT+SF0n+[f0SK*3AcpZ1P6suo)"+>XWpk"pfq)=>srHn#.oZ1iG -dWdLQT5`6r4+2OjEaM:_Op-\MjcW!rP-)Dh+72<4a-(c8Ar*fARF0_b-HcrMTlDs_-JP:=B;o='N","\ -L2AQ_5uTPh0uQlc'(-B^mmng5S:,NjmT/#9_7C!=mt_Bi*0%FJUk>^@F;W]O7Omq'UJl--W6[l'8mYk> -o=(t!n2.nd\1:=EmhAd4`c0["Hi-`CN=*4t#4K3A*eTLc48oBOUKSUW]&:9o/L:"]^6QfQ;*iu^''k"/ -qEdJd@2,!u?ZoBkp%NL?E,ISEY;0l=T$?'>ZbJmJ>90UVL#RVN#B@$;VmM=r$$u?e3-Y/PX86YSTqXS? -^i5!V_kOJ;IkWL[$0,4%Tg>.cf8^;_\+%1O_sJ;BJ(EsJ.!mR"i'qL$300tWhHQ6e`P5T]/,(*i)MRpp -]%qLiO'13K+EsWAs2(Um^V)=n)RVaV^aun!%fMK-Bq:i'b;5O*02RU(=SB:SWI/W1n'jP:^H+Mfg>XU5 -SdG@$o&ffT([l`5%On@H^>hlOZ'6iMeoNO1i>D8F>:6Q?ar.BOp?1QX_bNkcgW9dY6;.;ma.&Kji6'!L -@V$\:WK!j?6>ltpZ_Br1W%fe:I[PW9`:EtI"o72FOs';O7Ob%7ifGm@,S^1l`hA1fP1^';]n[*qW`+a; -EXL[qrOOG<]dGDE<#fhB"GVT-S^[87-7^Kc"tW:!`5QpkTQ3kf5^7Y3SkP$foA8HZo^pZ7a,]mb'%/5s -noMZ6(9R5&q(K93NVAH-4+L\g^/R79jSa5&N/@J/O-K)rFPp5k9'h[=n>7ie^,!+&oD%e_2A]?=IiBm7jYZIr='fT#hk3f!r:chXOLAB?>9UkonCDC*]`fj -3[TpRQf<"u2s?pE-(ecg>KF&ncZ5=!k(hZqdKuF>un-'Y!>?_2J/i -3)r*S(H]U,a0dRD*etC\G^NAG`7dLr9WTe:iVBJe$4[[!MWHL^a8+T0j#_'?EbS1%JiA*Ln]CSn9^*(' -i=*caJO:+7q022Os,3;=[)VT)a$\FnmZ`=Umi0DSTm#:1fp\j.OJBWGXDQZ\]93N^SrM6A_*(iXAbXYW -aH\k8gqe3Wb*K<-mlVK?3B1[.8::cV=gr%+YKWWR$a'4R&+Gl#A3S9TRXB:_pQ\bkZ^1%EDq^en$K".n -QSN:nWhe&gs"[2T%oSs2D4>1dAu![;,>$K/D"cGWVf(S:J46S2gLPAlbLnb;%l\D0clQNNOsb"`@0eFK -5q6Rj[m\-Fc[1j[h0F902d"L7>Gm1pq$(/1-_#%WdaZL62_"9]_(0VVjm5OtRI>T+fC>l5;dlGG.fp[Z -9;8$U/#!FEd:V^19^Xj6B4&/eIhph#`7i:cVVP5"ZdNZT*"erK -M)66[d&/Y_;4=.1*i6+qQX_kb=V)ZsjrPgGkoXP&lN=8.tu,gMHO"C)$`$f%QGm@K// -qq&[NEh0=rkfB*oIhUQn2KkDR-+8qiIBcP)n@.H7;-N)9T7=oOr86[cQl5IffmPlmlRCUfjt52QER<3< -q9%'"$eSS_D.Zb,m9]J3E94El;E;Q'0P!b&'5S_`f=Y;:'d/F%GLf*n -&EIA0*,-=k)lW;?YE!eWpZ&SA!F$2M=!(bThcXC5qO?l=Q2V',@fhu$\fb\'YU+53RD6`*X.a,'D=kIY -:!3UHe?'VJVm@l+L#<[VN8)($ZMfq8p+e6q(r@/oojLuF=b6kl$m^^^qWlKIoN*Q+?2ui*[6Z06(9I6( -Z<4+M9:DC/O0h)edR@9+W?r"K)RdSL#mFTCD9W8T"$]?'*tEtf+XYR_%Rg0f*N^2KT:sJk\+kjEdb"fq -Cgmq@4@iK=/o7@US>+(0@gK_#f`D)DR)_YpSf>a_.P:Y*;-"X=`:0bZ=F2AjZpPWV'MjA[YI'i/VZiS+ -.DETa=B.[KgUV:_HS\_Kp`83l>MFL\hChl;fTO&t\F^553lcnqQ9qDAMoiUh,Bp13/#SLQ@1=AX6W*r0 -J\m&A[[&$+`FRlM#kRJcQ"gqEg4R6u&$C#EE@\rf3.:*6oA=uDe>J> -*E)?WT*ecr4M6D#d,DpUfI+)D^XZJ*G@ncD@Q!Yg3&AP=Ia)qbpBrK9+66>:ETIMVP>3IFB??BFnEg,o -]]eU>2n\0:Hd-lC3"j<69rU0FGFW#RQ#i2J8JooGK-O)!ja"t64=G:$g.pQg--RG>@P=N3L>I22a%EOM-X39X7RY?`"r/"M -X"7[q?Bj=9q\l#;G4Yr50DVtA6isX6V>GU!Sk8=[aQ\u9@T>7F2:MFMChjIT)!pM,oa(AK21noTp%8q, -=K>/;[tu[WDMGla<=dY?1;Ut6UU@n.NHJ!6SfBal8]f@i.pXPubt,):i+'i]JhrLsECB_Gn7He>/2/O1 -EG$l_Dh%aFf'.*\#Za=>*osnaZfY"kq1WIXJN$f0UFZjmR;A@]IIDrkl3<7`W946nC'AA'JdXYp&lGN\ -6Y+NMMbK:#7UL."bC2G94K/T+j0+\[:OLP#ci;"KQ$o7q!SP@=gs0ZD5JZ:)ai)fkXFc=f0uknWS[-PP -dOIlPI*\6b6M>5l*)\:R>4>NbO^'j^3hJ.^AG^5NQ@W%pAGSXCq]P5];6d@^nY$5\J&gcp&FRJ:4d2aS -b50,#K"+g>WOTZ1dAItbaCpd?29*L&=0#ABe7+Lc54jSZY07kUNW?o[etuCjj2,K -DY`lZS'Q<%e4i-E/QTJ";iqfhZ5C]GojguSZaK5Unums0Q!=4rRWZfg0$XJLs+>"\4/V+Hf5:?8osFY_ -\h3r^]a69?VNj0-InNS\^Lch+VnG>J2V<`ZMhSIh6H.a0bbiakJCs?*n";Xa/q'A,02/jN@o8e`esm;Sc:Qe&lk#Q@GH1X0he-E7$7eRgmK].Jb]#o.6-RZk$On -[iL:smjhQnLle`A`AHU*U.bH(bPt#=`#dKTOB_\hHT=GsO+h7DIo+G^dZRi6/Q$--nuqq)q(iHP=T2;Y -61\Xb93*'srjQlM0ta"7Q@B>oVRM35nio)_OZcdAMISh$J"qK&bF_(2/n5`KFX3'.mV:!!#Aa!a7E=ts -<,g$qTb+&)rX\f+/`/fgX<_KT[V7\ce1u!,bk:/VEL_&EL5"90E8D2:l&CW1IUK9g&YEWH_ -l_[bO(g,_%2ekfK:(GZ3kXN-o\SQf6LSu>^m:;KdBh`6Gd_Cl;Y2ntM( -lT=?_6l+^IN7liR&,,EQ9_)j=\".8O60_N%!7R:h(YjX'%5Xt/%UfD##QKJ"qGJ]?#Oi'GkY_5\%cn3=9I9m>:`!^j%RbYGHF<"1X65V>e8L`BlN$mU2d[X8VHN7Pl'2 -llLg_Bi360^e._s6't.DJBMQeDN5ck.6E8*"@qlGE(geZba`Nr&>ne[pE7]>r[Bs6.B08P==`[+Wr -?:\*V<^l"Mh1It?4:(ZQ$4k!A#aTfK=F'=Z&8(J*C)UKs/9],tX7&A'\*(HZ0tQEe*X%B`-69HcB(X_h --r-TDiPEQrgK'Mo4qU0r)d\]AY@"J%b9EX9VNmO:a"j&u]6D_?@b.CH547KY/rju@tpHN^sBDj+]@ -cgNOiYF4KdWqIro$I?irqo[Z]/+"?YmEcm6J7.qIdGA^rZuaTgWR&;&CDbIc5oJ70&gApm^?HsSZ[EH^ -f"j5:`L?,qWh(/u4?kR4^ep@Sin2;XhB^>Qfu.gEMf;2%0Z?HZDGs2)Vn>5'\_7XR>o -L=Ws2GP0_fY]-]K^[+4Fl^YT2(R>57L!S?B2.ZT\a*PW1glp/$5Pb\VZXff$lDJ"a:k6m,A,1S02mHLp -4*EGMOhKQE6&KJ`4a)^!>[l9O=%_'Orq`s!^*p9"DR[aq>tI3lfr0W18,\mHPoAJ]4D!ZI`PB -C=PlFbFjLE)cX[UK7`=7PJ3hP;HgIk\D(+W*qqtd>r\X9Sq"fNr9K>k3i*j:@-rJG7a1N-YLjGj>\In] -7r2k#7[UZM.t%iY&KBH/,@7qVfb/DaiYb.kG3?NiNb7B=RB.F6@6[,c5"Mte7r8-"f8_hpG/Wo-G/VR" -mT+_ug(@OB)T"l]i9p;XBd3*.jsV1m"c+9p7WLH+ROse@n2Jb`fA^.>H]&% -Ag;K;et]PV[f4FE:FVUAlN";PnAG`3<0e^$'LBW1.Z$Ns,C]1oGVgoh5WdtjL\jh^k*KOICoG])^lB6G -NubL!&j'Q]i7\dtpgu[keRcb%jMYh(%*HMK(d(J0@I#^^g6()$5PrdN6?^ph'Zi^h@c>c6";$1\_C/b? -ChEo@^DB5I7G:\:\\AlG(43$hGr0%o=&_jq83-VgkKU<'r+04,kOZAL*rl)s?ff\4pP:'`rXsXmNK7_m -($e&-%7A[ZmhU:6WR7J>6j=ZpC -^lk>TDc'Lj*tRo9g\?#&"m;d\^.k,"Tkp@*Tp3m9n;P-G`WNlQ)84>d]PaCV%r/blIGl'_Q>K=+H\k^\ -E9P!!Ho5%NeTQDI-mrG31pr]U3c`r7/fX^[Us'5<]%$ -?^ua`["35=e<%%p;5>o^^dKtk'\NdtV_li":u\qFgrnAP5DW+Mc3i(mJa'S.ltiWuCC'%3)1tb?]G/Rr -KU$$=L#EB\Z43+CA1=<8ZAgj$qY;+ -0!u3J8_e=S(ATbC>7jb&TZQ"2Yn`-H_hc^ld7!\W9-`fGP\Qi[6*DS --++c(e94Nbhkj3..dN5NmOLHK38&"9+,bi]rLb7=U#R -/M_d3K:[=kC@1k!Zi'afO]/JIB?#QU3%(pXRKpe;KI`\V02(K7 -_fnXV2_1t7ZS0fQ8QMb!bM?1.6W.]CM*6\n^YatAMuM7`1g]#`8)@Un)@_2\,NX7_*V`X4&pr[R]]i(H -UR83cKccghUi]`MS+.C#3N!;WAGWYD[hOO-S]C>\N:M/`h:6m;^UY`aPWii4pRD:M(D<.c.l;44r(>3N4MVWHIn%:Pf<(hY/?tMDK(QoT.Rkq4%QKaYSO"@C@LQX=P'0[bdOIAC -G!nDGY,-?bUcDCbL2YS4!lg:[+ -4"cJZBmAZs#LA7`&]Xas^93:D?0E:Xme*8tUf@25kT(h@oZF.thN>Z8>I\R8En\R=9ng2ARr]!n)eaF* -QS@DVim,B&_7*\u$h>JK]d#uqj?'^Ak/f^L*?eULcEb;&VI!BWXab]8H'%&Tmmmqk)ndI6+/J9q[^.:e -dTU)Q,gdQ#HJ)@K]d"D-S0>eMH8p5qDDa?`7liKYi2iS1,l -YjGGYCo,PtK=B]j]WX=f/%m1\pJX%[CMhu\WOl?(7dRf^UAaaGNbN.<*_Lkg_f"$Ej]=cE, -Z&s6uM2Z*9m3R(*;/a+sHg5gd*26c+P!;qZAW&23V8Rd.^nL&6_Dni2#lVRg%(dHiP%%(#1WCM=GWV"h -U6VXeLa_fAGdVELp-o?p]fH.;X:C8`:m\@=)#AZD.K%i>>WD2IPmhY.t_ea$^&9=U_hd_pHC!6fB^.XkLmQNJ"E>H -MC%K=^MdqF4`l.[VC2 -6DiudpB'#X>8Z5^.`EcEDn#-&Vlr6'@C1eFU)k/oXsLPB`A;lFQ8N(?@CM;B8\f,RA'[2Q\?VUuN\0+& -U$O.'h9U"oq\d(+d.6j)4+]\u2pQZ^Vpak^P#^1;0@+;d_Gt0A"2'a.CR9)Airo>#t@:;=7$-Y7X -:M5Zujk1#!Yq/[\dakWb43h!Nnm%!:V_B\u]5nA'PJ"hFGri^h/^Ia6LRN)5.p!3`T"Si\5\\\.!j4"K -G_Y>5l/R!2Z]d'*QD]fqc\6(Y?K=Mr:$OlET#)C=Wo8tLH$3@3DL$CRBka9tBG&DXm+D6XnoW0WgQiU" -/=e=f7a[+AXSia@]K87T@kKtK4=B_;eBA^SsFLd(d -\M,V]Kh\?8YYQ1pg-/;uB1EN4cp6YV\8Bp`=UrW]_\!KW"^a&kj7H"c,KmFb"K,Iq`[C4`H$8b!_X\D, -jk6o\Q)6L^['2Z>;44bDahHBn`SqY:TUmuppU.3QY4VqAFIptibHk!P(c(/CFXul8Nog)Q=p;>2T]^uO -/=;cfn"Z*B\*6K*7qQu]ouMM7FnK/5e7/'#&Se$sT6i8Mp(5_2'3Q@&"(ROWV9^D^66'i\07c"PB')e! -@rRnRAn5^FKtV\BYfjm$E):3b)�]mY/=2&TW2ma/lC@`l5/:7&KFm;%lW1]No%g&FYr-QA(4Ajp8"P -UW`AA@eJ'PpMVaWMt_/":Ik@&e=#1._/Ek1o8W33r>V$(o[7tO)a1^ATDOu*L5h_V:)s?7-dh4Oj6.#A -^NUZuZ>.!]XjX!.4W$Ou'^[@`>YsAlO-Xs^&E&31R*%jXTIKtWlWLF/BamMpQr)( -5Gm?l=&ds0(t[ueQ2rZ,n8`TuHJX=)^*Gl==#tF$=e3,&*1cofEZ"KZORCb0OnaY-jr'AlDE7>Qi^qu* -2?"K?9:"P^"t,bMb8l4/q?'q+h'da_3?c`G0cKbgd6PpG.#e1p5J\(I@5sj'7iJDD(o>7naEmWqShR+L -4S*l`,@7rr7@^po,2jT&+%;:m]t@%1J[WcS7b(K6F32![)a8/F5Kg@X\,rsFIHl+Foh0IVSB72Htbl;[Ps5Q$;lYZW^B9O!0eruWJ.94iBmXgI_ -f";(c,cu?)8"a'mo.J1X6Omh:6PU#>K6ar\+W"RG#?l37MI`@%5sr]W[H!9W?bYr)\aBEg7h-p3>lf^_joXJ,ocje6-7Zhd+VW`?@S23Ls%eRb^mr)p#J7TCd[*QsU]^AV,q7-D4IJn$Dcoi0_)7'k43jW%eRuq\Ti3mRbomMf!W8,QqN`>4]S(M;gEu`$[=I1X8FtgIC)%>YD`P(?"^QNB58a3gh%/K)&\lEfM$a27]phnR#PLA -edLYI*EGPbor[C+oN8CD9^H?1bQ>56o&+;[h(8MYD65Y'P5_`:e4.of;<;M/m;`NXn2Vkd;ncg -^FQct5Q1V3q__PeI!TG<%eKL=@?\TrmIZHF_/,lXEaLVWk6CN><8KkoHkn`g$M(.%5X/_m -biJHkQ[^#-rpoVe;>LlA~> +R9opj8<89"/O*Y3#Ch."r:0gdGZObpfj+Mq>To#iqpb<5Q:*ns8CKnJ,8':s.;OT9E+^)s8Q;e +r9++WDnl>Ls7O/,aM7WLDu]Utnc/F"n6>@gGouoFD;Jt3gAG(frg14qpF?3t)"tpuCMf1E/rJd]hHO']tADMLCP](!2h-Hu>T=S;^nf6/g>IE'n4kSO5A +XO^DO*WOBfrQ70n4lnhUAY&#A?`_`G?iTXcTjC,ho7!j@U:%Li>RUUq3O3bJA*Xe0$4.":CI`4L&QS>f(@'?d&^#S\_'?Do]]$S&j(ZhK5RE.3g7(".;t +#/5]GlR6f#HS(`7Qf:!'J:h3oc?I:HCff%HJc?MMSIFn%rLZLaA)5s6?iP5hC7Ri3hU):>1n:0YI4VS, +^A^^S./I]*OjfdZJ+!-k^O1#snoc00R)egK(U)B_TcU'+\WZ\'M"Jtig.VaccitDQRO*8m__2I6'SI7c +mGl=G?`#tlqu9Hn+Ke36_34FdlfI<`\J!K-I"q3Tb$?[umC3J/r]=0Z^V<\0r)0=Dg)m1U.oOZr\T[o< +\2d%WGHCXjDl%nSO3t;HOla'%s-kN]:-5($(-G19+i<@rZ6C4L\7nlh>&krCW[#g +fS?=7Ho,Fs/!Q`E3jHmFlH-ckO1Fe'g3V#7p&;AO)?Rj]I4[?1e6#a5lF+U:L[O8g +G+5mZ\BPT9^"H3uGb4U$qhNdpB2/&bk2SN:CRt3/Sn6.XAohk^IgC%qjXO!+qc[Ef8k#fLWVbBQO\Ykm +:bmog(8r8pcFV,BE7GL!jbjY5\,0?1(?puG@HE"P7fB+^g#"9tZ1Y0)ST`?E0L8(Y.'qbe9V`:\,Ti%k +o$8+3WYs@0=b_D1cCZ?A9<`.(!eOG&Z[+K:AMm:(j&nB3@#,Nc=(sEb9P55d::)'lrGXqpa's35If4^! +ZMor[Ic"'h-Uf:hkQB2%#g^.0JtMupmG@*#\UOO_UJj!r*7H-3%JS+M)YAJWrIg7N/np%k_EmEH(ic>W6`6k +0AN8g=Lt=:?RW7>RM#JuNdeskZ$tUF1]*oaVS9CFLU>We()Vs5f/3L8%Ht#.aMu93iu\5f^Vrr4epk_- +&p2G)A9&tgs,0K6*?R;9>ltG3ZhD._^U`p5%Kq79Umd9:EqD]RgE!Gco5b:Bh'q/nV*j985d2UkG]%]I +6+(l_=J#U\m`WlCs)^pPG/XX!R8Ze),"jX/]2tmIo:@)u% +1io4&,uDY]mD?K1V#aoU5iBM4p$_QRlH9Z`pK0F_rNGt,b0`q]2u%NY8gkWa1q^>DqV%Nl\TP/L8$1m%r[q,9A_YaV-c7s\lmoMX0,PCn/ +gf*2"(&`EuhOd$X?]H1CH_#kJ'5`i3QL2D:0,c[R +m,.<3%pLjZg%cUeNJGgeHr)S_d.c+Mrn*,N<"-0%^K.J-7a%g?@_ASd_RdY!P-(:(7U^Eq^O"K%K9GoK +Ar4UAbcI9TF1b*3)db_EhnS2@mp%^ld(uRhZq1IbV+(P]@0Bsk.mY$RZEDSn;(PPd7N +MIq%$B!e$Rr0Uj\7)uLsiS0uU4/0DAgc8#?^Jm:,oL8TIAb5+*`"ADM_e*VU'XW/5l@g^7Kq3_\L$bVA +LlR3T`K&Td$R^tNUqA)PjY6R#B[SLG?L0=o\\T^8P*N9GjB#'%`Wpj$HDdgY6l]FB9&[[m*#3Tr!-YsktuqgbmXChp##;*e`-@Kh(!eGZ]COSO(^68g^C,%/XP<46p\A%[oOIiDS?un`o79nT8DCt]=iYbj-ALuO[c],_s8HnU +m3>WY,4Kf(_535F]OB>T/^@"=SJEU>1$Z*5an_g[VY!rDm[K(0c)`)[8=;ZBJR#pF(Y0/sdZR'.618c) +VQ;E1VO;.jf_j&g]33r>%;)GSAJ&AMZ2^r48W+YHRBiko#o*@*)GU+u?bT!5e?72mW*QK0VAZL+6,AJn +?T5s[HC=G4';t!JFNa$seRf.5lD>P +^hEIr;g`_h]159G?Xf&8Id&)bG&KDel;:A,'BSoWUb=.1L6]A.B_[asod4m`dCPu]4#Ukn6#4pf>`CL( +CN,+HN5q5g$Pb)Gf&/$eXgg.Pg)@^]m2)oM/($C7CX>0Q:+INt#3gp4n]^s]Y]E$1#6+TB]/@)2mA%OI +QEUQpeg`O7VB"1F]&plL?gkCB[D4HFq+J$uQT1Vgi0&4ro#M]F20dG#r%>2OnYULnF'#:G6;H6)^@:Ig +-gX4MJ&eSh`t.PG?i06qh$Y4;-t[>/j&c39DG2WZjF'\Vj1o._5aeqA76UY'KA_/>T'3K_+$s"0hD^Z/ +ehrqpFEqB4)5Zr*AYTr'5I6r;3hgZ3f6HSE@_g$Z>_"oL`_Tj#Sfiamg2qC5r5>D0$qA"Q_.>$PhCrDb +"V]5u,-CQ=WlQ0'h2-Q3Vm9?KVebYl%lMqYF+1[GPY\R%-Nb>56tH33>`\h$47-DEAF>#Qj[C%JUYOWJ +,PJKUj&aI#]G0l'Dt=N]`t.eWrRg\?!6<ps8=htguhK0`Y2t*0g,*`(]T(!S];5p1=CXpn)_>j]f:is@m7E>j=?h@0@SD]fceS$!SCajuoKe`!-M]ML]U:?Nbb&Ps$$!',.a?IR`g89^LQanE +`.&?m57!AggNsPBm0]n9T]r>baU_u:[Nn!ojhlUt..f:%OQolG%k.%Oh(ml`9/?GOLa[5W6(1hPBenrZ +YJS7C?h,1&$]ZFW&Tf:G+'fe;haO-[XJ35f@>NoUHmM6iL_S`JBjlt=r+b<2b*[hVZrmOn+S9?1CQnVl +p""W686;uEX<6T.<6N%UbZq*NZb$!,qlMfrDHI7*DJN:>F=2AB._h1W.rP,ss,`#qX@#WBBWQp?l"7rc +ndI@f%u*GU+YVjrLXtDPhm'@P4`c);r'Fr5)G4r_+ +:jQTeFXV0&qk-P3iFF7^42PeiTd:59A(tkiQQ+YE=[?83K42C'bhXrDMia-qrje%24`nF9'\P7c%<9X* +]9B:om0C\mH8'*,!T3j0l]f..#QDVbN7e^(r,`o@JJR*^[c7h8bhZU^f<]p$+3.O9W^_hCo5>+LmW&aV +f6U$R>q=tadQms@2A5s)6^GZds(d9n8$q@S,bC=TF:e3MZX&qO6[pZM\$NFRiKsKTlPEhhmcKo6+6$le +HHdVmqhIpKRqT'c6+Om>]M%]0TRC>2PM6_=p!D].88fm&"WGDYemi^%OHaFF"r_C@]!O^C;Jgk)C!2i*rX<%mCtPn"Y3kfI$&N6HIkf@5aY6^j..j\:AE@?Ne^o4$Z7.a2Rg&#LaVAq'M.(\XD9G;8tc?el]+ +PC1U&@HVk^Bg(EI(9PnXYi1--KU7>C)r<3HP:LBqZu; +V;e>:?\PDX:g6ZgFAC3)qN.+`Zr3Qi\#_j$]D9WB:M5flfeeaIUa*0[')ML0V+GTj%Tt8EkaeR9VrT#/ +TQbtCG4RZkDN!1ugmpIfDJ\FtDJeJcGP_)pYdV@i,g)7lX-+-4GIHe];6+F(U/+BCCQplpR>8r:[OFES +8kk20p^<[sWLXQ3%le`F90C_gUKXoa>?ZB`4'Pm8Cj3.CcBh:]rUNed(!]tQZ!;,$ +M_e,\F2f(Fi&K2=qX=3ObRc;['mMprbg1Yni5e,MrHJ1cI;NejIlhqu1JX&GIgb^FJQ`!nHi8HRV"O>H +q_+.ps%ts`C!UV%N#h8MO%'J$NFJ;%OcNQ$`UI+fQ9Xrf32bA0b[0ph[+m8$k&%@#:X;PS>7o(s<`;0o +E8_U"4q45^#Fu\ti@[3a=r'sp=WRfZcN"OqN8Y'fB3;pU4c["`WSd2FMgg]tp?9H-P5S:@1jDI[*mD)Y +l!S$A^RQ)"LisRjSab0@VHa0`h4VY.%7);PH,;"TdFWKArfVMHjj`b9f(Lk@r#4b1 +UjpCN2DZ8s8l_&;9rpSuJabG.WF'+YMKUT'KHlkCl`^#u*[q.>MCUl9k+c1XMB:fEb"PXDb&OYhY0C+Y +*YCEOM(oqI&gKiW2]XYf#V$uF8eer%CD8G$0ujop*5[TRPr'TQ3alSLW;\kZ-:d!2o?`m)G:]8:g6KcW +Otm[]?^9+c=2WCp1-*^BaQ*n5S5Jq][tm\kOQ:"4TR(0iPZ4eZNe<(!EWANTLN&2:rtYkE9%ME9*SZp[?`Za9PM%+J56:O!#OoY6a\:;t:4b6(Uk`eF6]nd]-QKShID\lD+VHRg3km ++DXFY6%7$2Ac!;1`MSL_1L$[97I:MT +oR*bK:%$)VLRftW#WWc6UKqJ;O=nZk3BJQahg)(]Z:1kpq^PU#?6>gIAoC+i>]i`MjNN.'GdUSpr&HK9WqtMeJ$mEWfI3R;4*7Vh,4J$$<\6q?jc5\c+Qa!8DBe2>[4-;U/b,!RY-Za6RPYr`hEqgr.WhOesc];\66ADL\;+7O$rabc@ +F6@g))/$KBD^P)RffXWPK3/'-GIci-r.A5Ql-ZL]"CoGGP=_#*[g\S*RlaG'X<"] +=IWVG[R@=KqbqYLLD= +]i(cSSgE;>OB:`:;u$17BSUr2`/4%WM,,)b15e<$]d,UA?E$HpU"Nk&qs=R(3oP?5-:R[TroR>; +G7MI*oX#(o!pNkJ%^?:Zs4G!VliJorRFTfOphf1(fJm\)b#b%.,m%Z-t2P,\E(Ym=g`&Ps,'&\!Nj?2j%rW?B +&'m"$kG=*JH&iK`[j9VE[Kh$$D($p#C--H`ZZUO5L31l<&(St0jkub=bgpE:o/&'^)iFEHrgR4*l.1j;T5)Fe[,`+LX[=s,Q+D_;+nqCK5=d:=4..^\ +J\93^IXuX31ODEIPGL.8EO%>Y@INO5!GEJ/80EoP>%F9_>oH4:";5[$(@*GMXr)Ja3&pY+C$8luNmd&. +8'(E/NX+lnf/O#[9B4B;6B-%_GE$\?>9=brl)l4FS5"q_Q/DJDJbH3cZ8gGm:)6pKc_.oRC7Hhh0o_A3 +AMT7/Prh^"P>gOU=H=XeHMVu$)KKq+W]9;c:*nLO#N+olAL1CPXnJT2LgB&2gGB-bCe3TBrm3X! +^N@WIOu[bnV:&+k,Bpgj52;iOE5S)#N[&9Ya,0DT/rcVf(Ii0b-X4\m:cfG-)p4kTKsZ"%UR>M#skOhC`9.aMIq-, +,"J]l1]qg+%\g(&",3$P7ZQ&P:9Y4$UAdK>(:!>=fYT`D*%h#4R%qX71.UZ'FQI2,Y7Jt,3[f^UaQ'NM +i@K7gP9!%ECVFhrN[Kt=[!@a]Q"D0#BF.I\U@*Bji4Zg7-;-rLk6qX2S?.Vg/^[!I>(Nr&(.O>86/2do ++3#%EarcA'X5jdgNB;jCM`W/>FRrDV(YZ]fmS=t?,"LrAXEfnb7[]l#4P,^jFYL.9q&S/kPV62J6[b[\ +6%A64BB8SBnY*4f<4n +c0sSkRl1LtFO:m=YAU["p^e+P$Li2+4];\:"-5fG&\FA:O+-W/J&6Gr&1Lqh;Ub'D)V7flG/D^rJ;_md +<,`e(ho@8)044M=+_6tJMe0lDX*`3,nK"/i.Q@NQr3sRVTG2_1Z(ie--l/?Lnkr[<:V3,-hY+[$\n$^' +PNMN%BEkoc%"rUBBdrUdR9hH8lJr^f:$u`h%(Zq?ENS^.:KfKrIE%)*$gIR5Ioc<2#OYQ_oQF_o"WCG0 +TZ$BC=PPI(:#;XNA]=2?dRWEE;IY,Ca#qY;M>nHo"=I#"eEa!VOCif&-XQ7iQ#WBj^UmL@eO_5;-Pnn`CqY>k_\BkhOE]9o)d4[bemi1/#0X +=$/W&5k4>7C'8Eee8]ai`G=sEMA,*T'P64+'G!,lEEZntID,=sE\^3$,/Z)6rjjBA_Kkcua0W]E_/X3:e2u ++jVe:AFR)#*jeLTQ?^kQK=9Jlq5UqXB\ISUQHmk"9i2jE\L'P3c"IjumZOmt'N;H/u*Vlbho<]a*V:H4S`j:)5X^o/P1CSK'ra6.9!n7aQkG".jK(SPZBX>U>Ui +f6@F=mm5DoONpb*OlCTQ.[K4^kK[ka*49;r:EA/R^Q)4DYW_((]a*$ooH$h=d!K`tQ[ecC_EXUMq,cJ? +BP6;E\_euS2fnIPR_gV0r.[umJ_8=-AGHWLP9+@2o(`/?>e0-j\e>_ELpf845Xkg)fmP`[L)O-"I'pje +B9*s4di@EDH5dqh'5((\=bAGU>sf;N"C>=Jn]Qn4.GH`Y&C`Zi +G]kPqfcepRTGSjAG@8U8q=a?m@u]*kqIs:IMB&aI;oEW2qs)%dj#h]R)L!TQIXAHEHa&MF;@K&fAN%Uh +pYVCWPX)B[UXXP(J(a1Xd;H9fnuJnG=0l]ddg]#S;2hCnY(J#=5%=os=`[XG:6o6:&0rEaB[n`E6IMFZ7*YB]iS9iC$B!c'$%IYE"eib7sDVdV1Gd30bbrW7Ra-Qq^ +)\fJ)p\r\JNh%mgF,_5aS*;9s$a\5A +^C%\&ce.Op(J!.QG>XgN?Y4r_AGssd8CQZ;G]MrG1Aupa+.:27G-Q6/KM*(HHRhE5&rFDk(>E64sZe&"`C)QtG6:#NCD:J0: +FMU"/)j"6s_N(D2W*$`OrIY"-PcRgD&A,rMTG09/KKN2nN,>>4NAEIs2uX_RV+0LM=@TG1P:JC\#O@hu +):Ei\32;\;VJug9Ri9u%Y%'01S>%Zj4JWbf/R8\So(:@oQY$hNlEr:]g1KoB-u>2-N!M:_PM6a ++`EghR71@d!kH;oVT,npC)VjjUeY@u?/sRQ'2c??IkEnnNC19Rj%PXmBcKXm35j<+i,<iU@L6fX9C?/sT9"Kl`0(MOl$U#FEZUKQjPdMs0\a>FG^29q;S]1MsACE,qK2%F2X3b9jW +NSsPRPo=R4j&#/Lj+-"737Jep34F@1`Yl-H;MW70*0E)'r[kQ[*PSM(j!pcHo]?#ONdc\1cME(sV8tbOFu%gJBE<\9nNKR5:#'W,XqfIa\jUk*M"hmc&n$i+C'tQI!(#Dq@Fon/c:binCcej=cOQH"8L%^aV_A;b[pYCk.^PME+KRQKW_((tS2:O7$`BYN< +Kkr]kr]-US-C`d_]<%1t7,"qPn4/&J/F=SH6j?Lh]Q@l&JNM^0F<]fn.E*,KZ1A*&GfNguWAVb,2Y69N +K3r<6^?"O@eYL*bk7;o\?2GL;n(PUZXBnVoLIPX-?aY#q5pK9VLcihfUb=Ra`2N*72+PW9Af>b^N!l`j26k,p7,G:c#Ee^%NAX=>5YKA;F584k5L!uap4c$&J5 ++%'i4aY0cIQUKV4_MmhI\t2""%g(#%)9K0qKlLJ7429Q08or@,2sh23,J2h([B!tikdCk5c4b92d&OQ8 +fU9?:o*>E*,[6P$Vj6bpWjYO\.^a!nK(QS>C.oZ?/V'i +_AR$R;V*de3MZa?&l4]USDu=B0CABrT\V6XjLFDZH")RL4(+3,r(W4/giI&>3fmn(n:i^VQKVbZ8[?AU +/^o+"0f9\lJ+tonP!tD=TVh]j)q;U:&ju#$#Q"1Te\C.brd-RYACK(SnI/r$VF,pLKm0iTo!do!A$>pY +][a@f`f1f#c-^CU`:Pc_eSVtb_V^BS0^HJ`eN]:C%/tb=nq'*>Du\b0N3bE<]^#/GnD[)un;H,47_'\, +-@0B4?cH;aoUf+#-G=T?iDeAQO_%(hm_Oi.ns:B_(#/-Df>(Iu?Y#5Y9149!XL`b+oRJ9(Xn$=;rM&j7 +@C9EM'k^d2r^_Qm%nED]//uMmJU]f?$JN<]M'Y+>-o6(VhVDeU)DLFA;*/RN(@5?rf[2X3/%i9$4_83XL7`'+')3[K\% +LpAes^S"QfIV2tn*gaHH1e4]+a+iJL2U!7a0K]`9dc*GtR^#6J +bjR5AmFdoL6TmLl=UIT?_98-!B\p@RCqjB7N5GnE+MhlYJis.5mi8a,*&X&P7<&[0/pq)+H=2I\bkQ%' +cr54Ol"9O$*`RI\33Bs`>CpD>IWl4t:8X@m;DL`UrD@>*"%.GFR9jeE^\QVQhO56d&qAU29c)r8c:!Lr +ksdP2/i8+CE:^V7A-a**^9$a$hM)\,:YfW*Xl/[0^;r_a?tPLG'MWLiVp"%cknM-cI-qq0hCD@kP:Mc5 +,jhIo"RUA)g#?)ETpBUWWn:mB8_n"3>B\'JN#ZW[gIjKuik4?dC2TsbR)_g%BNVrdr;p2HAWCpY/'RE6 +Zh:G1`sK=Whrbmmh4q;c#0csSZW/"dc(;:D"lAn1J7F?&E_V_&p;B*RI\g83js=+$]p5W4X&oB5cUE\$ +0%4'/;2l?S3n*+f;TIQ,iiERG3@Oug[5T@Fi]@mMRJIET@=HQBBX5MSG9QfSC6Y0ZKIpnUNq=sO"VPRA +_BiK!^/[[t\*Gp&Kj815E<"YW"/H+WN'nW)G^+,k;G$I(J+-DBnWXd3qMs5I:W[!ldd#ul3/FVhq1W(^ +f]PQ(T+J+Pif75]pre\FF11E/BIq9@)DOG<8[?**OuE&=Ba3QZ:WYD,!GO<)%m2$$(Ar4L0Z6bKrg^r' +)cF8<;e#`Uc$$tmG3KT0P"q(*?Y]FQ^QN55#aFK>ZG):S.G_;To.R.`2E'lAj_j&' +S&da6NIq%%+8U^1BQ40^@X#Dc,0.u+]*1]139p79eHd.<2!Vhcf^RMehJgt7J)Bd-`RU3oa/eKBh(1%+/Gqtl7:.:Z>Z3%T8#`MhGoLiaZDJ:+p1AIk+$[Qp%cFL,6Bn_:*J3P2LAbF[p6qJ.+g9#PP +IHh#B4-_FFT#gdZN#.iVb;7T.m5c9_F\3AB'J9X7UmnmWNu3P,_]Bk=aMgQSSPG8&DN +P\MMQ(I.:\\?2[=)`DQ]c>MZ:S'khk!!?e$l@jXK3W0H"<`!T#34k5igPD!/B*cF49>%SElpD_3?2?(&Ms]*1]lo +DXe?R$Egf0)&1APXp@aJMujg(":[o)n;XKTj^ZD&2E)S7q]]h\@1%=qre(jmY'G()oY:Y+f[AYc%7:q2Nl3Ga6cGb%rMk=\'l+_[*flhY_-TTG/K658eDRKN#Xri09qboCO=np4KB%Xc+$=?Gk)A*8m7f> +d5\Sd.Z7>`am[)iVfc)KD:h5p?Y^EIi+lB0*aGPq(T6>aL`TofRBU/kk%\Ao04aIr2;5,2=I%(f*jB/1 +/i3!@i2(WnmBsmUZDlr"fbMbODCVj!V.4.@0?j.W<+t3jI/FJTJ+b)HVVdnAm[-mXg[DAB]J`o0`0Xi)/lh,7Qjmo.B0r)S(8;-p<;j#\mTL.Bc`p*65)STh.8C00-0[&BAsr.WoKUP!P@Z +90$Z6.49mIb&@:<)kW$OVNa/#.Hd$Gj`O1FN/Q\YnuLBm$KU:1OkQYu?!%"g*MQ=PXb):M))s:\;[X.`F&-DO0SQM1=F=YIqkC_X:s,g7dQ+.Q][SIrLl`<2B-4\Qnm)& +G9J:X/W4C(egsR7++0p6V4c@(*8@ksDqZ(sN&3sNk"S4b#W[PnEq9h!`)NP%1?-qsUij+W1=DVcFlVo? +oQNfH8-)6=1=GITgB"KL7[cGrP`[:GdGQOB&[r@-]8YPDVi5joHXK7W>q9&^^Vd>IU&H]i?5OH;^#e'. +B@6)Gma_j)NKasshO<[>CT$@"Q`Y/9ojBF3GP!@HK'u00q9esY,rK`QjPDFqm81A>g%I=0qO`+emQ7oM +TcQctd,0qYSo,'-Q`k0?VaL5;5UC\>Rf$RedaUEei5r.X9uRMR0>(K4%#]t57FuFSVjiPW]Bl,-^"r;/ +UX7KW;<[9DV4@\!g26EDmd>L(O,0=c*"b/oT>t,t+^@DX,BTf\--@RL#\Yddm10n#Dl@0]T4, +TR(_/pIjtr0(HSO>S2DT4E+D@?$c_i+f-ZpbCDCk?+faEJe,;6b:R>%_[()L+fVDeqPF=-fmrA@H"'lS";E`%+Th,LjGBY5E!$K@Etrr*p6 +Ihbl:DX70jMY(HORX2"sa+X!G>AoMle6A^)H>?(?B>2ClXfked4j.Yipl%tLf_>=7/f3[MiKk9XIS/?Yisjl!lsF2oafV\tnf^Qc`-5]?$Vk=,/p,rBa`>b`JaJ4H%Fr8FRB)`Kp=OiK-Ra +hRjdK>Ai;)+KN-9ZY1F!WIDro$Z?h\dT8_#p#r8+.:-Q:+m5-#i9ekt4/qfD7efTElplN(_3^'B%]lte +j"/-rY,`6uToPJj9>CAnFsA2dY:9**OJsi5l'`@rj+V2?0WW!R:SD.6pEI5kSSo:%7n$r=M=jDM'hu8(jZ^k3fh6WW.4fd8mJU$0'bk#TT +=g"oun=/7?S>Yc040tHT=WO&9c:"6+9[#&#rj#lY#7mh@2]G4-#^XGE'DC%!2"0rh"4[$/h6S:"$dWEm +lcKo-^R4,!n$F.c4m)s][Oc'<;r]"DE[HYU!])Wf^D,eVY%KcdX3>TrO-o%Qrd'kd8*F+$^r*K+0]%$/ +n!mMO56jW=i=ZhJp+0k7_44uq2@\df,P,Vo2DVRo#'6&lm5C?^BP4u6^6$/hYL:G%pgmqsC:?@?C,GH% +M*fF,?>hW9B=!'+T&gACQr=E=)pC6I[c\[&NP*Ki3LJj8biThf1>qpi#6>]P?CG"5^J)ssOYru=@YWAW +cBm]:h"-:=[<#6c[E*A8p+5BDHdBtgB7$cAe4)o$+cfQRm!RC#e'E%TKTeJUgYK3+GC#M-lHks\]PL!l +Z^gF=5O/tUd3I`6!I:!;@q7dWY-'S(H"$?:j_XC`**d_(WeT$Vb9*UDf\]@3V+`2V#.'ieoTSN#,%sGX +3SXEa-DO%s7NOlc8L"Hh2lKS'/B\pG*6dQQ=$dB=A>_Ar`,Z#IIIYNV:QF.cZE;PkBMPJKn184!ai*u! +o(a%o9fK8p11iN[H^6I'1Wu1<1!:I+3'>C;??!:!n[)F0R:cJ)ijZ8s8djCEIM2.Ceo/,RbLt/ERf''& +ea(`CR17X(jDSWjmiq#'U4:_\ACK\sDDpNI4ZZ?@-bLp4A0tlD6/tH.jp4eUt;A)^?M3d&1ZoT>E +:Is26.gap8P"6cf/$k`p8'H"NbV;2!kA1Wu1)K3?L/Ie!??FKH]DRIAsSXK_R= +lue@rnKc-q%#NlcMTP-[_):[I+l3aaQ;Z6;k@Z< +*t(3po>*(/+k>EN4joUqq>_u4b_HQ4BCA?$)eI1V@ZFZDK\KQ@2$J138_RP\PZ$A+"Z[mt?U#On,OsYT +ItO.?8ZP_'^6>*?=`PF%1U?ao$X):0$-s^9k8VR!Wr+/e0Vf(d,kbF*60M2+RP&moQQ#J*ClMo9k:G1b +]?oSp3KmPuf'rZ^cd3eQ74Dcu4:Xr`a.B"aUd%;nA7*R)9]DV>]'86]UT;'HE_-]1O@!E^/5K]U:%)1e +]$071"Y7bsp"qIc_XJfU4L+drd,0'F(m20B4dfHR[c6#H%6JRk3j/$C.2OV_*gH<$C`hPE*';=ZAfP$B +0t@@S]]#Q#Q#ZDfh,J6,*]#c&,mN$PMl"Kbfqb1E9/0.#sj/+^8ZH*,_Em91[SQ.#oku +&lE/d#BB)u?(l)"/T!5iV]'m#?=^^U:76YB;3PNeM3]XWG)jk\')%Wh8aUWL4[qrc(`e(Y)+d-+4gJ'7 +of06W-ETf!UFb-*b#X'&W&SrEh]\#N\2qj'L0\fcXSm&4Gk)C*fSMal**X8"m%bXT^C1"5Cm@_O7(.uK +!Vn-:CDO6VbQm1);nl#OM*8.E-GO&>Pp/5t(nDn2p?M[e,4c1#N(<$^/QIVO^Z4arI)kBm8%(g`0>C90 +QI0u9jELIkOZT8E[gpf<;1Irma'[)^FMg/cnL(.6,\RFg71X^gs,[rlJW-E^6Y +^m*,UBp)b=q$L%_Ap*4k6dEWsDJ%]q3?Eg]Z?bR-9BLBO?12B\G[9g>ALt;^>KpV(D,QiX`m>KF=L15)!>N2,9LQT&imtS]^E3Vb@B=L@:"/Ac_/cQT%EA^ +o"+WiAkfX$D^2%Ci:"LpDIeiNk&mH6h=J5"9qKtm#0Zm_\od(W,F>/M\=Gk5TN`aG3Y7XDFlka+[5^0T6g%Z.P_(S5;Zl?97cI/89b)3%F +5h?8dQ?)Ie&N`#5IE+P.5_$d'h^P&h"c!PI0S0Ip3pPIDWgDQeW?LO7Hb+6 +W#VXTZS$,6=O2.Bo&a;e)=ehg^*8k`bo^FEKef?(8te?rQ=>3\X]UJ6Q!:MX6loD\`HJ+_Z'<1m/Qr4* +rUs@9g5f.D+(Qmf@Wp+Y=Gj4">HsF7*[-gN'X8?\`)=grg5;_7oFX`!e2*qGbWo']R*:Rm8tq&= +>Hnn6&oPZdU`$f%*`sS\h*(dBZ'7Qb;Ck8LSER?b7npaBnF2!<.@FFm=A!mYe:-GVAPuBq_PfPok[NpQ +dBJ2Z(*\D[74`#S9X0gJ3E7VA:l5iXR4R`q\Ks9/R":6W0q3=-oRRamR?&W,]J+/b5.>+/CMC.1;AJ/1".Slt2'e=_bMf +VoZ?[*Q?lX2grqKX>[MEDI71Vl2o<(_-\*V'X_]rj0otXK-l$&i616P!@%BegJs[a^F]:To@j_cIha@/ +eY>CbZfCsJ7tY/`UqH$/ks3!IWPlCL8APOZrOtj*>C5["$0XOYK5b^Xo+pg)Y*e#EnWa&CD!IZ=9BALQ +j+E^XJClCFYo;ONIWrlijJX*h"EKu$+C71jRoa=_)SM"$eaA9K2#li,_glrFBm-p` +8[C39$C=0nI+lGXYd6PFa`NZ_#k-"Wf'Y2htB'>,iL#BiDHu[=EOaj?.b3aea!(KHnd]NjZ]@ +rm3<<7nC"6E;$K,)^1qG66UpO)ND7:qe[SNesEn)KN-su,Ga7MJ"<@NPr[_A4`Fm>mOHnBqFJ@2]s(eS +9)D:O/%)DO*jQi`R4Ygec[*ZNorj6?d%`ida6]0&'=XR[^/;MJIe6X`7.hTYhPQGaMR'qm.H@@b3ibhat?\q>H'7/o1DOuNucj)j]'ZF]9Qc'phMgDds(IQA`- +n\1Qn?X++]Edu&GKQU]rAsRJFfkNHh7JNn)nbcdUCe`[L0+l6JQY*@[?$*=DDlW48X]2YK>(;H2_g7l" +5;U4qA8OE_j"95u21gGnAX%`J5W,ua?J9F[Z$ld-,ggjGH'd+]g'I5o7WHXGmNh`RId\^+`dKK*Ghg+U-L`WEgP +NK$.!`f-28>KPTe*X&Y2*\A\90KK[BZo,Q+EE,q2E!h("^<_0kADL^u`.l'/\g%6g6G6YCqeU%nBp9!p +;^.9fPSPbWA,PAr3+DmS2qVUdpO#db62j$j!-.F?_=0TcXk#H)qH&T(?A^?2Gq!4K]O:\^I%R>*TtdZt +NH4QB4OurZNmp\#k^M)%lg];H]N^FrXS>mfe,/V;S+k.`e-mSI%tc>:>`7EidQ)L26Zn;=R-COJuEd)SiUGjn0S0FsL>1/9N=pOG'[g[b]>A0g\u2Wl`&aP6:l&7+s,=epibB)/MF1We^_ +an+UEB]Y%3b*JXM;r,4)QQG/Thm)>V+9K6E7tCC,Af^u"m3,2J<>s4aJ77F#@!YN?1IQsH)Y$;pVD^6DleT6+M^`kY+W8_ +UoXds=GQ*L)P%R[i[*"p>WZ)TSs0UOPZkRbVSsVU9?:?g[i?hh]cK4GL]/I1YI0[Zbp^!C4epM4q`]p9 +GO5\m-,]E!?P92Aiu&.MN_&YgMZgfTn^g4/s2;YMK.+-!h2Ea>E($O>pNPR:jZJlO:u\INQYaolh2U1u +2b#4-+nL*oGmp%,;/6*9qi0[iOJ:8"WhS!)7c=6)..oI3ms+MEc%sL$(O&R(Z1j/RC-/87;"rS[ctg=p +LOP4(-q4I^GB*A8EbO("eGQ>@eEE$he18m'_MD)/?4iI2n\4%/`AA1s%>rdWE#1s!j2@SKV3nL_R?ljO +[TcuK9f>(P.Fr>4bb^\lm6XmmX=!6_)RHVSRc!(=GS3g@Q"VU=D6)5ce.CYuQss]6PW"imXPgG@C3:aZ?EP>X^-##9cel4gLhkr&WAifZ:Pr')g,g%G*oq.r;[eW`bc54#;sgW?$2S2p-l@T1(NKipWa1cP4)kQ9sm' +bqda=r^IlVX!mWp8h*FB.OdtAc)<%uc1P&#HBO&0G-iGc/RCo2HBP$7NLc;07B$O&"B"H5F4>)'NnUqB +o$Y[lP;GZFUXXI=bP5q"UjOmh]edih7joOYN)Hu?UX\$BEJm\/IO@ng1BMH;GdsV&kkGq!*PIGokH8CBo?-Ir,\l1?p4(M(dBgRoQ!RldX+8\hrunn<:0fHFl7E-DT(`g%6]# +7C(&E*eZR>H=V::kXZ/VsW$d=l'eq:,cR/L]'3(N+Ykh(ki0$R5.+e/5hhdgfDf&,hh3,g] +Yaslc?!"#Mr/s8tEGR[%[5kh8dph-HfVYD]-`Arj7%Bq(ZnQJ5W9lTXg]VAu0m+.CVYn9&LQXiG.8UbUQ32eNP/f_gb!\7lVMFK$S$Xjt/F +pQo?%L:NrC6X)J^Y>/7aBuo=_:a%;jn$:ZdqI^k@WkID"mnlP=fQfh&Gfp0r?C!6&_e*9HJ(feI2fs(' +B.2L5F12J1BoRh]ebPbgkhX+A2aLXl-9ZQ4MJl!hC +s%qLd23r'tdGm=_XiJqL_s+r"l)L6?k_A%jI1%]2P$M+=\4[d8$bcsDBp(rcJ^SZk/+?q>[)D/cL\<4c +26VaS;GI&B?+n!o5Ah;rb`d4.*+F@Nct1W9X)X%F$bXkHF +m]iQTje^V*9*+bN$4o"Q+IXA?::$Liu=O`@ai%GgeAm:+,hDl[VL8CNO*K=Pg]ArQY66NltenWVlAap((J;2OU`HmlK.E?Vf;ou6."_RBt0/0Rpf*LC?B#?3,>dj1:j*LO/lo*LS,/\6fTEqfL +.Y4)G4#RProG4b"L0D6SCtbcN*G+im28-M75(aX>Z(gD2SSSVIS8:^_Ra'o#[2%GCA>mKUbePqSo0*)) +irs&49eS2=p(B#4g\TU_"_RBo0/2,j^?J'kN%a&2m7'%"2O7t)-f6< +It0ZG"_QM3=1uC3aQ%Mr)>k)\I`m8CoMjO9[tDm@3Gl4*HReE!>Ei11@Ko.@kc()\*`RG8B46kF;b?&A +9#p(nS@0rIoMeTW@TN5&c:U5u=?8e6VU<&fVimg3(RQe(V!8-G+l12J0VSh-33hp?YRR$<[4>Rr"oPSKACl?0g^.B5\Znk.g%XqV1KpKMWa36;b.Z)t[akHAdc=5\) +VioqW:Z\Yrh>6U^;Pr,sQhW#sYfL&9U.aZ&ok*OJDmS>&C%@m6U_fC'21Y+]/=7BJF+h8,?1[MaH7D5L +8l):Sj?/6ib%^jWlCLW=ZsK.PjG5ph_UUf7p0tN$?3/$7nZ[9g*U+8IjpK`8\i3Z\`NN6.oMe_Kkc(B% +l!;gT.-U&p(optRol]5jGL[)FK9Di$lEKT@01EKX>Q=>o9U"Y$\B7al'9H4c8muup) +U9m,@XphF^4N6'_r^#B5qEa5kqRG!+9!nle2R7UBrI_.dI@_7Kee]6RH:5:7Ue,^2O)m(Mp%9>=rR6P] +>5t7_U//BQclek61r\&S.04];SVIl9FEFJHIo4) +ZL/tIgSOR_mRLHQkAdHnEQ061^2WfC!=NJKntao]Xfq1al`1hi\)t*&m(EAHqIap;.NSHP/C'$RogK[1 +rI_OorBSn?%Ge2[`S[/_Ad5C"W*H*d6S5-oaj/pi%.+QTMB3-j"?YO''Ba;=&N0"X:)WlZZI)%fbNaUSR%A; +K\''/A_hSArG?PGUHV<9c2XG(o3(U>.Qn/>pG'_M)sfc#4m +I$a+en&hsejB/!Z\bZ+qVmW`:?q,;gO52_?!57FX);1$+hadlg%\D%ALVQ]!5'1hFH:G?V +8f=I`.pCqjPt=$Xl;%.hClDQVaoa@C)`Yj$a7"!?Eub,V48+X"4=SAfT?N46gis/5*g>UPDPF;R?`lEF +cPa4D-G:++`@<[LMlc7'Vj0O?`7&.fNaJa`'s&X+SQ0q0CSpE!gle9g8qqdBA-_*gpJ@\55YBAK(T^!=4RV*Jj=;=a6D%OohAMUoq=.!u[D>$:=56>%fPX4=`NS_>[_Y>\FYm^qiH\&&e]qr4"ULh"%R9Ng)Cq-BT3 +`A\7loS>5FNHh#eiZE3jMHqMa&hjC"cFVZZjEG=[%eY^l9,b9A#<@AqiAm]"aa=]Ztirh_Q0UU4*<,dp7Sa`rh)4WD=V4Yf/h_Z-FZ0[g=[gISP`8*b3f'Wc]4 +n")1E&/=PCpa.##e#BfC+7J9)W8#@NQW)^LWNpD"o,?%/fnf9IBn-&dMo&15(tVhNokNnLJtTV)GWY08 +dIK.V;Sk$&.^,K44maC=^.;h,-[TeIE4"!@e"47&s(F,n50Vf/lK,q-4_(#+9#&2d*uALT2Dt!SL\X"O2RR&T +rB;Zq-5V)FS`>!uW@4R5UD_M!"/t'7Fmk2D=K/Y5:7*om)72`AG.qQepVqVUGp(hj^t3h2XK!4HF4?eE +6gQ^RDsXB)O^7:'g!j<.!,ZHmPK&+>PPS\b;D5IRqW^m9Ilf[!If3/N1pu)7s6#.ckWQN@98`W'!hL<>^3ho!%iTj_"7*,)I)mu2jhh,e +e_>g9OO]%:TMhj4HMJ+Q7(dn\3Fto<+(ftEo>T"4D^O#:kTO:s6uBVbLmFLUCb_0F$d`q90`uatYd1E< +5-0fCN0Q%HMOe"cM.=YbD.BcMpZ+UW]9(U +d`[D;*+a6.\sN?&f)FV&,VR"3cnFL[@4jp[I$gmCasD3#IVQE9bc(7gbG@36VaKZ#C')*5WkFp*-H!7_ +]'(.q'E%iigL'^GiA`[:OhjEO)*DC:Zi3$erP'JekYLR"5KGH'K?3C5DK8C2hO3hFb+Poq\j"aH-I\&HYb`1WWoUArfnh:3e8_.do$$O1*09qJ5:5U#Bq1-g&1.+#\Se +)XechHC5;$SA"qs&`A*.GQZ9&=gH"Q]H-/Ue#rV;K0";9ph1-A9o_qgqI1CL]9rT66E6@W.IguGXjJ7#Q:DMb9&1hM@],:Kd>u.C\B4SE8ILL'&8ADQ;UCE<[$PO2 +G/rP9m&QKson`4I)(0[QT>+ro)=1N#05jAm,3.i3L#L&#biE6Ih`5Q\3]Z\adm@@Aj=+F%,l0hs_Hf2N +Mj_+#kX4t=\ac6LR3b@,oU74*>H/(4f1ikKP1kVUWLah*4el8F#-#egME#9pedm4&fs!Q%Nu[F+C?du, +BYNS@Q,.$ckG?!^35_6,5rpYN?>fRkkISuE-W2$BYDai#`TF/_*'@^K:)?E'c:=*/E?Fe8VP3'R1m#Dq +S(/Zte$H1elCK;&XhU/!dO9O]mp/.k[J5d(.JneGjo"(#PYBE$`(t%OPo?P@\od,QP?ILM9BPWmRsg)3 +_[jFN='a`^K"mRd[&>WXG8W@,_j@+lR8rf:b-Kp7%fY,[%e)A=rFYeVH?KW;?E0_K3H6InlCcQ,%G,K$ +8`j'6ONA)QZHjlPE@3sBGtfH'mE/o`$@7'`@S<(;XUCSec'>L)&(_ZC?Xe0V_X+!/gA9tChUtU#mr*]l?-?En,@SD>+P?Jtr:8j80Yd;sO((+j%]C=."-GV%Wr\+#D\hr;JFX1(XTNb5MOI/O3b@EVcgC2'-2?uOeA$[=,-K2#Q1Z?m!#X`i<= +g61aX6C2C7W9$jXpH_L`C^Y\,54)V.5 +\>Y?F8r^G[o]B]GljTJ9Xd!BbTl5Dec?\/&Ebt.GDur4CfA,&77!^5q$,A,$oJc+IN5eKu/XO,@ +%L8hdCg4N1`kr_BI0n[pGbc0=!1Qop$VqAH-4Y>DqkHU@fPCoCqm&HQPl50Ce9'Fe72?Q4J+K/K?TdGq +MXTfXU)T+FH7uFdK5[Z>,?FAYcQ%;GbPpF[,3*LSlgL8EEGXkh/QsGunD01j:cM.aTT`S4== +haP5:\)D*d^#8:roC=(JX2CmV2e"L3o7>=h?-K6&L1&+uk).O'R4ccEhR*u$Zli^u"hH+!q"r(Z!Q'P' +nXHnZW-7g8'J&o]BZG=B,)+ON0cU.s2e,qlfh@C+-,ns,*_F1VIbI +Nkir`44gl0Y+m#bjS)7tV0qmsh^%jUr;ci2nb1R(+*OX>lqGX0o-SOkXdK)GB!c7=0hJWkpqA+%9(Z7! +?fNfn\NFiXYAe*Gf]`A62BUF3o4^k*osCRL1SV\]n+a>fp_UE9fV7+uD*;_bepk`,/Tjh;9>2r%V;+/Z +0'`ePdY^A]oq#mXkWWEg!9?u;Vi:d@'/FY!bK4u[g7;CDX"I&a\-Y<]'ncM*]&27Z!Em--r3C>A]4\Z. +_SYXOXGaThf/7,;?$HKks)I4.eFpdnpS($%:oW8Oi_A=6S)U:WIcAtGf7IA(^!So!*3G>U)+O%RpACZg +M@m@"COYK67i&D>HVq$uL=/98,HX\9\?B/nU53-EjV?dWdH/cYU.p8a-f7'ZDuECkd3O!7[^UV26'bS" +QX7;hS%d)PWJpEo7"TtWcGnUV%X;g&V;lg:=co@m#2<%Yl+bn)(DI7f)8'c!FnMPeN9BjDc7['B[/Z,Nhe`R$j)/rjktJlR8$P +C`6b^Q>P3TlpG9#"li8?j#OlakrG@po3T1=`g8o@X'rZAAs>M5K_g%M#;Mrbk?AH+&bj'@?t!1RQ.PUVR#-P%9OWNe3sL]rYJ$B&p.e0s0+m\'C`.W<&X\RPb+,?sW8h;c*l/`>BU +2o\!KkM5b0%G#<+VXkUO8dBK+K6&Mk8\?,[>`CI4UPA@.E?B%^g11#"fBA7J"N$.ZIkJ\#i +J"+gGPOAlW-N*O&a@siEnVirbp11?D_aR8G9Ddb9S\H0CVG'1c,i5I]Gf+-4\41i,Z-b:Oi7hnRc1`MdllS!uL$^ +,$p(pVg5kEPdm[5]B<'&0'$10i(9I)O4$W1`@oX!BX^fub11.tW6hsa`ISs`8GPnh!NFo#'jk>8c:qNS +a87q\1>8^?;(DOXGL.Me*W/[lh#d97d7)qG`QtG1_>&9^b2gLhas\e(Zold(HrXaBqbSVKhA9`]f:s,O +>4n$FG)uCVWuY5"HScQgbiE!^e[\M/UJqrbIbOd=#\*P>_P\]aMP!*+VM,<=".\i``o%%>O^5S +D/?0.\iDFgQBa(:'dA#opE<4j2Y/LoE#[qSOr)mGDJ%PmN$\LUIGJB2GF["5:Q.$)'Kn7AQD`8mZI`f5 +CQ!+Her.s=K-nX\hCG*PmR:agQ.VC"]K'$,,c&_;D"[0NH[l.W?!G4jLk0[@c<$7!F9Ve&*d.q`u".b/EQnSJ6=?bp"N1$AMh +Y6\jW,$]AZ_RT:iC=i+s^IjEKejE#bY=l8df;2ZClVai\Xhjl&f[ltRmWF@Lj184eF'[dm'`/mE +\jY73:Y'N,/1DGbhs4/TYEt(+C0fhHq7:[oh`l>=Wr7q+$$-c3_:].;#up"lf+]F't&8&Ds)BZG:M@HBMLPGmi'i\]?&RfT&NkrGr.a\po3Z+$J=J +-'&]UZS;asok9m"knea,YhLkss+3>Fp]k`%^]'YaYi@M2P*LZ+_L%A5$t_;\@;Y+eM9C%]Gr9fZ:cY7@ +FR%G`?1ZKf'[ukh9nrAI51gb+q>-0"%.@-(UNE(K45ru]NfBe0AP^>WTQWEkhtlVr]&T$L8%ft@:k+$M +[PJhe@\g27^@[QOd!8QWW7:4c5Z+c?3K!!IS^loqihc9,JtITG7PR3adDiF$:*5g$JlK[)J@m:q:,6g[uVNRFC8>a\91G]k""p2(t,M'9F3#be0<] +PULCh4I=9^ctg=*VK_RIOdS"il7sT[)&.hLn<]@W[d,]dY>Sub,>&.:lS?B*W"^JQb`E;e1SbXpL(pH- +4Qah!YhR!YO;VJGkilT"mX9M4mu+Y^\.@d#DTPe>MI)slHAnN)-r#l=$ImMSmWidFP#UuTV3o?3'JVT^ +^EiQZ?0?'RQ(6/A;(C4*QPkfQV&61\#s(JdTT[#]$DL$$qL[_8!?4OZ[o%O*DMGnHqb"j(mo]6i/WKmY +R2!><*-P=p8/8D=_#!M%orf.]8%#9Z$JTu/q(`c9$n?3aQifStNdW8ZEm/jO5nD.4)B04j'#Bc<&NGp/W'=P6WqIMUd=m\8"n>h=k:4LZd +DPmon?_GkTN(0W\Bt(F#U-m8:"[Z2RQA[:$G-f[ehjtEAE3'pTm;gqOQHD5FADa)0.AD$?p8QX'^0DIK +gF.fR6>E8fOcCh12sbi?)dB_]Q9K?YbGq)M>UH=0=!4D"Z/n+3Qd*h'>J&en],Sl+8o"d?]L(5rN*gm-\;Ie!!GS1e$Co5G,s#4T(R5\530`WBM4X*F^<.Bs5<:`FmH]bJo]7"82%*5@7)u,CerM4 +cq<'I4MWP*=_S*epB8+-p;i7otn)U*"U\#gu98.qe7?` +;onA^\Z(>m?MMr4;O+)Y0:BG^VUUJrk?+;9hD+sl*09Fh8?K^ngUSeglNCBbNaXnq"0WX/gt,4EN@.eU +A$0,,3i0WpkgMTDiS<3+\4iP/c!+>\%::i-0".tmEL"os)D8c +hrqM5A(Ss(r&YBmC8H$S2gaTIcA1`168!ScW/Y1mXD5hFN?DBA_ceEh.O#6&\^#>V4.c3nH)l,$(G[m_ +B!sNZD4HS@I^3Fq^M`'KQJI-nXtT@>Trn8AT.T+\\8)MpbO\nEJ^iSmQrO)sKD49\gJjlm^Ifu$O%@)7 +ID9ZW6R)Hdf/9W8I#0r2@S!P+^G\2cX&tu5V'0T9"c2JVJ[):sRpm5f"V\(leQY,PCec-1?spn>7ieDQ2'nla`Y'^eK@@eoEnUG/4[F0CF(M=QrJm"H4c +A3M:&9#GN8#BmWj^OO:p?=s(XOlrO5B7m.hf@")=C.qng.q?M1/dt%\BkE;b#9-s\/E59ma[g.Hh3d_K +L&S>@[?$\P`"bGuQSHA>o/4Z$6u2`@>Z`"`mK+uL834h/-HFc?`%R5j/)I=?deG;0$$qXZe?&D2Lh"Wi +ZuVrUk9!HS(S]aG<5MqZT]!h]f'0fRcP'o6+44<%&_i(fi$Ve*p^ZbKE+`#[S?87aL/R^!8_3pq*-&'. +7B7H+nm7O5LBWOLd=4\>41nMY^HFZoa**6>*#/#\7P;gX-.Jj-G@XhsqW^?%54;A+o[:%[6l]EGVmT^; +%GB$p7@+G1G-&&97\Yq^Atbo%5G%dIs!bCnkV9^oNO">lI(YHL@1lGs^%,%^/adVFaAD!#(&>kMZ6sHO +>BtQBZaK+2d%j`K=jWHsb>%_0-ToRDpOn?'F[XPrhl!l&-M>Oh8N@Jh4XmCq@q[X:V_V-Ro):ZS_;^e% +4)KIce#_l9".$[qa=2A_pH`d)XrmR&/]X(>2R0hLOR7Ssf6.AHFJGqs7)\F8j1]M0N'MX`Z]-d_,MpV5 +:85tjc+`i/4jrV7MW]%)dcXb9gK0R:P!t&LH`MC_?Y,?KmuaC'&7LU=J'!i<]g2mOeZ$J.3rLIoAiGG,LncE@MX!=1TT_jiMoL0013F$S'V7t"cqNCYKYs-[KiK"kdQT,5?-2&(!PHY0qD@[Sh +aR5?)_R>-DDVdWr;uYIYJ)`7#QP5`M`_K0O@*6ked=P\:g?P""[:;T^*Qh(LZ-l6!>3p]ATgllk4L<\a +b9:$lVs]OFgYZa`*=\Ug4$M]`M9n=Jj/^K"Q"L/.TCMI,pPc:rN\iqQ5fX.l1>s,n]f+^c1R*.TA(F>4 +c^][4\n.us1mi@-lrchB52d>SPD4A#UG/Tir;I]qk&83V6UO("cW;U:P_g`4P*Uf]WKVf^:)qj(T`oK1 +n1TAgU:%k)j.,#J2oSR!GS2sn`&4>JA30^phQR'Lndohe^md!9%*.M4#K_JSTR`X6Kq#%Gim*rKBjjS= +G#6+0T!aJ#@lOpV,%K&9j-VE@;S"9n$\-PrT9Ch08W?GM:HraUH8,4`5&/9XcH8"TYkdT?AVfrWSG.n@aC3?>!^(H@\I-bq/jEN&c)0?g)W6eb-#F7>h]HrE4QM_R$;RSuOPe84Xp +UIhI2d!mlBR[nS)#?R^M.?,,3`?B)G_uVpT`>8*[i' +*TFc,'#3]GA<.f(-,mikDOJahgD,pW&[KWXXD55gAuA?hbA>$qka%X3i'h'XB)YG,AlI9U>@nP80\jC2 +,<1r9#dX?,iTB\o!a=iZnR$1C$bC]]LZW*>9;+Wok$JtCY`OEhs9BR[ABZ:d^J)IO6*7NBH2YC4*(0[3bDFWtGG_d^n +Mt,GG=?:6WN$Bm)Fehih^UVLl"IACC[fe8[H\SB'E$QDZ0BAFLn/2aNq2Rhgq=!4G>6:k;(@Lfp]A@&$ +CVTMu3gOU$LbHHN-DcRb]sTJ/Pao)oQ?h!t#@s.%Hfc\-,?p3jeq&)Y*qN#hVKdSEDD1M/=kqSgkJEAc +n..=,`I&F/BMaSJs7^K7K#uj0T<*GE[HOF8%;dBXeP=MM?.oW>J0( +dIA)MGk)p.V-s6#*D7k#DTek#HF@'.>-IDN!617/.b]\)1OGjOr8M.[cG;ul=^3GFQb(Zk(#cRg/eqkc ++VgX@bHhDUhkAeRJUN3>^@YdBZ@YS/s,NE`BGX-WJYAt-E!*&f1B`boiOR`A>C!_KXUr`]19)G7VdD0" +rd&3IL'2Zu7m+E#c.Vm;C!fcC0HBn2(3#O4!Xb56B>QqrN=HVnl +eJ#HsSV<SR15G5Cqe<4j]+$ +XUifuKNpD\Y:7cd +E+H(%qSo5`G>bC)M5SJA]A^5irn+=*i+U8RqTF%2+43GhG=1DrlYU`TT@QW8+djcfFO8,6qdafBm:'_A +0/R1BGG4@c41R_JHrK4b[1UNi:T7//rCD_]Z9C+jlKY0(&acDmI,E]#0A2;n5t?[YA`+&gThIV)kX2-0 +,d3J-MTb$8DNpI9TDR`ef#8A<-hBd)*0iDnkhfW+@*OC,bkerhas"IQeQTM`$6fe8pRCIadUc&Y-#fi! +,4b)_042J4#sE4A]JPGdb)4QjBrhnG.8Jci:"UoY7L.ojYj(XT53ts,[2s)48*a(I]g\ +)h0r@79ImNj*:RlX8qqfp[,.65aaS0AJNLdQjrYSRu9>,`eF6]c%-i/nN8">XLP&(U@8@C4T!qhrM2(f +RQ:;?):oQ4B&LEEW5GgmOg+Dn0WNIj(0A4fI".bce;2>V5$%MNKU&1aI$qDP:(R_d)Njja-@97_UV?j_ +:;`X:1GdDl(=].Z,"+Y"DPn5g4n,[9T@n8^,K&( +\FZmNqAn(\K_SU:Dt7SnJb'^seODa]Q8%Nqeb]4Jo)3U7#akSWBM=K:8ZCVorpHjM5OPI9Pn^o=-N!$6DTX8UD4f6kN`hfHP +CVX%TN3obKp`+`oEq,5%3X&;T?KVWT[qP&Q>)0R>qSANZiXcRlSO&>5jB%9_PEV)dh\?_ubclu&\U*3. +mk-O;kK::o/%7V"N@1Pn@D"Ok?0UuG]/2rc^1^eWh4tDlnJP5@\ELf^Ua]H3GlAC*AbWZPd(_BR)k=?^ +"(@r8YBa@OhFrlT-Aum^(-Ef@1D!?iX^KZZ://"CM3;>1'2;`H&AHl.\gK9<)`G8Q<8[q6agDtF;!2-O +^l?$@^:jj4i%qbLA#j2hLDR*&`!M2mR4\_Z^$+jcMsJ+H^j3ib +Ph>adcJh)ZpHl@MlDD3,G*6jT-$PS9f8![B@WTd8r3o*g/4 +Tt2UuD3m;>&eEZ'rKXhDd8OkopP6jYu\+`DZMD=[%91klN-= +HgM2F5rJ=3dXA\0eLcL>p=@XuL\>HC6co[_9n8L6dc5rq_I)jH5igS$JP +R52=2%uDMm:T`-i.;f1=>U3>5$E;BhGsPn13YR]2htt9gSc*oUhS6hJr:>#1jo:;f/,u*_5:US9gG!CB38Sq[3\fq\rk`C>VUrTB +%<^qF(,fUe"aoV"I<9IeoTcc9O3D?XDGfLfaYo^%)%ma+`RY1M`0%XfXkGkIQ*kL +D.JP]A1-PE\Kc;c@!f6bDnWlr)m^H%X'j7_@pseSp0QU6AACj2bmG'"1Ee_^^GLsRakr#)lbp-[pW5'# +V&mH/=1l:7p+.5IhTEbioX9SdGRr[>.`#n.mp4`/'TR:_Jh*qF)7Z.#&\[FuHi:3.%<>S*r!rDbQqhQ` +qq +hXp(2'b\3`eq'#UL)Y[RCg50K9jUHR,<-IJ31p+cO::S&X"I0@U*`k"o\T=Z$G9#Y+[FoG[RF/:?>W+m;MBJVA'$<"oni']A5p7H +;-bp>)fC>R+qC9b:nP"IEBn7`>1=lPFtcm],LW;Q;-k(]T48th +m-`K8Z#NCVq##!tGVXKUod(1dp9ToLc-D]$#[B<:9U5N[1#a&jCXg^T--'Q"M1:qMd5aEg57QdIUaj0[ +Z.A93dIYD"]jV*4*2h?>gGkeK&$a``kPpAL"o/"64;g.g\8sMFJ%^qmD%t[BksL>E`cI"]0==s/R!5Cp +FGfF.;e1+;"Bo,Y;"%.KEuEgSFa6QD/I@-3lU"+m3R7!Mi4/js-+t*M'G>*F>S.!\lB+_Hp@lX?N[@pI +r/fj:&fpH_dNOh:385,N&J[Pi`_Zt6OG\t/1+PgjO+&o1-6N2B54?s( +3'6tJVVN?_c+`c=s0AmrC+_G>%[W-/2P!6VF)$A8>Rf)Ob+Bt*u(&QL?H&+p_%BQo]!1# +?5PP^BWhDYf*=Y:#`)mol'J]Vim"-hTh&IM/RE/Y#:M;E79\TljjQ6cN)q,fPi-;1#9f=PFUYbs$(U$9+Ql`RBfeYP@r7K1L1Dn34+" +WQ4D-B%5hNep?l:NE4Pc$7UO`8s]t.9;@,m6*2K8omMq-q?RTYjjPlZEIl!=nb%ZL6hZV?+$qUCt5W;,EfW%mF'P]*PBC.@(& +3]o#0MiUt-0N^F +5HilCBN;7e.bP60a@\9Z.b:gd5h@?sK2fMHQTSMM&a3diAkGMN(h(T`4WlkTlR\WW@[nM&-Q\Z,,mfkn +O\R;]asB+Z'!#nA;6-*tB\noWA[gsul.=1Jq`2!*8SWfhm%g"H98G>3rc;JhDt*-RE]-a&S>l!@rr/fT +kbmV$EMK0+3?MLiD+S)0>3!JXVe7YF`IlA1f;;1GUN_XQM/#Dj!XcDVg\$l=pm*tCh,:..XhZP']3ma* +[3E*%UfM')PQt[2We:%TX4Co0UASC&F8HFnE*rMmT:P7#D8T))C54TMgS2lA/kUH]PU1.r\d\+38]!qL +c0Fh^Pme*R<.ZaJ[3`/E]E(Tcrj4bS!>reIYce88:QpsdEEcoAX`nKn#c82]glpB1)]+`Z?\5uID1n/e0X +b]K+TDnk?r7C6TQ:2id;DKM/SeqBLC]RPSI/Y/,o7,pD^;%F$Is$N"-bF9eTeKm')%2muq"rti +fOY"D7Ugp:Cn19\n)sM[GHC8$(0fEGSK@1r3URrV6d`gMJDm!-g?89[i2]Af^V;J>UoA"9eHiUF5fY3; +D[cO%HJ\-Sir/f34W]P9e'A^Qb\9:2i-5LHIc:e]S@K7cN9D;6^jQ,%HOnf%GPpYZC'u\0Oe77>n(59m +rnN!TS)WoW,M)Agb,5<*4&KDl1:4c(-*gWh"-12k\#e*U06: +]4liBGfFCp'-%_0D\NpU(c?825K@B^#1+,`=L.c@Z`uK!XtSP]B@P]P'!:HLRQh[o=rNNT\+MQgT0k(kSfigBF*4,08pqd,5hED6nk'6hR5!6.N'VdX[0X!$p(F,[f1bLIU,5ua;*u!7qg$1KT +ic>,W*JmhaC9=+#^L)dfNM:'dqI'1:T0_&"IEX?i!nDb')&EbieF]PmE6PhrB"W.r1um-,mk_[8Mk"db +*TqNoVT4Y!8*a&'B7+HK2QD1VP](SFNHO +kF?E],L(I-RU`_UoJt3Uf.:ZM`iH9Ybd_7]1OdZRAt35.g/0nKM?;(g')*CkC`eJLp)PsUnon"RT`Qn. +O\s!tYpmdVd<(%Sk@_M4V_j(o9llkgXghm8_Flr,XPI-JhN[QRrQ0sQ\8)`p=)PbPLo55M3SlSi"kULF +8Y,(a'^b%FbijOID2n4Oii)@)Y6\!,F?Ni>It/n^FZi_7CZ8Tg]SN%Q3cdCW8 +)I'mYQckI^2"9AqTOC."@crgST@/@A`)02-6'XK=Y/&T_DSE/HdZcd9(%2l_G7:pCZeIYgaK!CQiCu>7 +rUJ)!=s2Xc.C:%/',=UI#`c&Bg8k8'K.Y8m6_3$L`\*_Tg[QRInGGA.kPsf_`W+PDr>N$7BZ5c'Cg9S?<=lq/pJ:\W>7k5!8/Zm.7p`o.dS(^fX_E0 +^K:bZ=/;i-qEfkI,oZC+C-jt1fl/\0]GFeBpaV6ek`J^)NAnmj4M9nMNaL,AEFT-')sZdT75Ru>BjVNt +@/00@JO`"um96au-KR%t`U!adqNaomid:@AoR(T1HnW77),cM8F^!kPq*X4m76p0JZB:c3F^s!3\S&K. +*'qFWbABh\VW,<%:^frP$GZ.7k`i4/.hc?*JJrHa#-Np`f.ZC4nFpP025%-b7`VQ"(d[dQW=P'[EPr7: +dt3>odt,IXS"L)#=X2XLYM0)D1i6je(UNo/Un0=7h?q?JifX"$0g]0OfrW,mY8cfSL.p`3?8+s..Cr'6?j//\D/gjT1D_3cGS`endee`r +W>BMT@Zg,!%j'W-Y)iCLc"AW*IO*2oFgq,&2>^dM6uU=T#E5594V2:rIaa"uYtQLY(p84ZQLud_'&qr< +>\t8*4/@<%H+%\SnfYWVDXgAq)-Km\26Hn<*5Mp<%YlB3Gs?Dec42\+FP'/AQ-S\!G>gCs8d?f+9]5:+ +FfiZo>1A'chs2\1p%#CK;dW]-dr9EmI9IHKjO-1=Bu5&B48F:<8.=RkI``JFO\W$ScMYTs`lWm&qY0s, +K.FlNVr]6N+!f]+OM09D50>!S]Jh&%\Tp[FX)QJl@^cK1h_sm2bRscl,aW`d3,2(3+;qt,Ai0#3`dNh= +bGR*J>^.t^#G0NCRCl["@a.YYBK.M\8Fgb+NpZ-Q/"2guc\f_.F0s4pZPc`Br+4loSU?Fl)FI6-i&I[a +h\3Nip'MIB:>P7TPk`BWBc*(b,-X7)>%caq$rMgjlSD_0&pP23TdTQ;cp+k)MB&q3I0><^khudHOJ?9e +XeGVK)F<>A+O!?PXOt7UB_aE[.We!$`APAe&^9;aDC%a;,\QG0PHmJ9=\shtJ:8H5"kWW:L)fj;D_Ra] +6Ru**b3Jq6]RP+LA[_[Uj[GWNCVXRspJ7n5apVE30k5q\++4&9kb>J?X_k"j#3<*A^,V7?GVb*jjB4Q8 +fbOY$h(_9<4`SlO8q6g\=(]Q14@ja%f<\?'5s/AT2(!'7)\]>FZ`YVb5(`)g)s>='3;_)a8LouVF&9T; +6W`Y<9T/e,T\qln.kK>V\,#V5D)(#lgr^K,)Y&D0;O7;@DT&J,C1kB*K4?8WMD>q9_>!]NK,p7'jmKsL +ZYOMJ2]a,d(XqG;m]PN^V;10<-C;?GLZ+D=/ai:;mOfgep/^QK.0&6>KU5A/pA=7m]K;H +Q?%1@$N%DGFUjbM9ADuh?Agk`H$h3Q(soj".cW^NCgNI?48D(bjKLOh5CMG=q,11`jXu/e?1)U4 +!Qs4]BW8W!h8VA9j]=V$/X/$]rmV]b&eh*Fb>FfeY=5(X)$RFeRfW/pRkgSEq_;< +J$6=_Yrg"$R`Bf#I:e]Z] +BeX*V&37._K2bnu0TthC0_RD +\Zt/Y`@/7XoA)iRq5EjYD^8,:*\PGIWrLM\(gX[URh0%#(J`lNAu652#i!]4`9\ZqasUq9U;(H[V/%^/>Y5dd8E31L>GFrF_>S[u[HrO/lFpN0?// ++LZl#/L/5)phkZIgVR^Yj='e@"3IlpiNtf.Q^L^sH>iL*@XU-*PQ0(I-)RiHaXI(/WGphjTSSSMITPj^M".,Sn"OFeJ@42.Ls:/`-2 +GW%$&h^pP\W:p1[I*?bl`_a50D,G)E5>I)7fA'I:EQ3FMnD,:?m;B&c<9%^\lpK?NEJ@6G/J*8^o4oNF +DD,gM,Ri)SfS,,DRBo+NY!a62A*iEk"d0%sHu/__,"E:*bNQPA$K!FK`cX%]Y+MS'/_TB2igNkPQ]QU( +JJEHl&:m1*/J.#I&RAYI%8hA)>dOFe;U900:eWrQEeR27K=]SLAq7@LVo>=7GbBF=f:.2Hgb*!d$h@M.Xj!(#R]fN?57$M%Ahs2\)ojZ0;Y?6;K +V0,2pBZ4*<]6-0Eml%,1(fM]:OVjd5b88,LG#:-Gc3ufQFe7&8*55XMnD,9tP4jWBaRZ9YaG5;u93Ea% +BjH`5R9HcEHJ(EC5S.LmR%72+$r(!+%!VS7@\)',9)LI)BjG''L8eCRMIF3\Dh%K0MHeR#+Wst^nf\!+8e&5o`46m6+%"m# +OgV@&Sle1/GlA`,LCi>q>1`*YHjJrD32o$\KQoW7mLHB5D1X,Q`I#"I%j@lV0"T3_cp(u/$>$4!lbp#6 +o+s2$^=o2D4F[-c\26d[Yrm&L4PJu]I,P".oFr[#iTkjW6$5guE]:5`/E;#*@EDeEs16usSFDZQ21:5J +(/_*j]7$Anj=HlS/nm6h,1D[debUtn[mQ9UI`e4*_Yo*L>8nK>q\X\Q`r,d*,'D565=WDZ>CVNboilkdrVD9K,<$88rkA>BUi'ap-bg[WSC6$f\\Qs>PW?9o`)g18lH[06 +ot8$5NoTi&Aa`X@QGOWj4?62oXR`_f5pd4gTGa&p)mN9ADkG_&_'r$lTi0hsVsJHYXILlnoOT2l\8;%,&& +]Y/?BW.\B)ockl@6c>X9B3"9[Mh6F%p9sHsL7L]#!9-//H6K2qA),"Y?_Z8VhQ,D,S=@Ve4NdF^=b$k,[-4]TkhSua$K)e:bX^L" +C@kh5GhJ#F^4W99O^.J!h`*R&]Z^6@ZC>0O,75//l6nj2O>U.T+3Yn`[@WbT37b!J'2Pcdg4AO.AC!.L +BMrVU@B>G#oub]a>PXgOX&Eh6Xtit%?cqB2%pDQNsZ@GF"1ukp3pLYt>m+$m6)cF\RSWWI) +#@W!fB-EWdfu![/MfmF+8k&L1#11`!>isLIX:@$7+L?1p#N^4USc_&DRRN9Nj:,7=DrY]5jn)m6D_2i! +EV%7@Zhq`3]s1+([/*rTUeSp)Or'a,WLQ\qU[=%OLp)5j!?j.N9umt23L3`lTC;$MID4R-&a?XfVshC0fd +c./=;I;%r8FL4$RA-549pl+3Tf4[9[.9P!h=?X\bW&m!);Nj?!D_+K7<]6E8`atG]'mo]^Voq6HJcu1 +-(o6>W-O>/i5HPoc23C#T(dE1\rjZcX36P5I,jg8(ZLjn#*2<)dRW+\Gr,%4^YDPOZi]&Z(]c2tCbEJoA$eeqO,Z+U01JX#P!F[;SYHp;iBjf.feU^XPgIhOoM8.OqDf +U>SaQ;B0HpZ7#iN*jNI.8`$_X-j7P=bY[IN-F;W+Ea8/ph+L7?,]R?l0XQQZ762g3C"T7=o(U9IeP=BQ?"iEeR#EQX3SV097VM9)EA.->VrA\2Of-`nfh +2*o?Q6dL``CLDDb1F'T3X^VKW;rXBUO8DZG)LGj]>qXDkAu0ib^Q(tmLr&-mf>5\`NN8.bG3kTtKFW7# +bVrrG-hU=03EFft[19Zc-;iqhgWX;cgFZ_$WQa+Ydu>&c5.i;:k,ad8hJpcMSq"el,JSM'WB9[,IO.l3 +nYUtC*lG!@cWHc=gfNC_/8Fip?:_\3)t1im4s!qA`=,LhG3J@BAj17/!jmWLSiu\#)-tL`!,lg:`bjaS +i5Rc7/\bJJ59XD4PV(&AbY!oYX=`hRZI]4]Tcq0Q0jpO&m$+!`G$ZTGG[G/2hk;091PJh,%WZi>n7(^H +`pDm%?$;!QQ$Uc'7%NQ?Fd]nf?F#(!8-cK-M[mm%'iZ*1-5?[hq^_LQh/%1l@NM7fG0+,_P/(VlWkRNR +NdFd/0U2K&&!)HJ`MF6EL1QH2QM#RfT9[K75$"^=/cAV8iLb/G/3-3qDo^)/m_<;VU;,=QcUtGd39Sm# +=K&*:1F4AVn4O.W!3Xm[:$CX00@-m@H&h +g/BH?gNeO_r=2>+lQ31Wm@??aVV&4CGZ6W.7!KD#ZU=poQAE>t&qOC:QN`*bHGX8=Z:'6>(XHp,=1ZF] +QXfLN`0iuY#bt"UobfT&/d6kpO)Doone7G,!3;aPFdd]UJp,=2 +a`b'ElFlO!:=f+[M_Z9'fgSQFSpRl!@$&GBna-;5lR?/04/mfP-M!:'A?>9Ei%FBB^LMcmn+7=orI+Q9 +:N9u(@6/L[%UR/@<\9CJ^i!u#:1C8aB\oSCLepII$a*F;IgbR?<7]qUX:J@j('ruAk@!lnq(K!QNq[^B +\GWBJdG`q,emJ%J2L/.@j7Lm)6_YWF)Y](A^>^gAReh>25FYFI_k9h%hWEHL.btn)Z4GGeUY/^6`3W%&l`\?X%jO0n5eH +_lA7?q0LHa%rc.s0uI%2^>aCRE^n]jR'OY,Dq>>r3-$cj^6OT*+,5koL"26@^2RsHa(`LU7/V'J,DpcV +X4P=sHmr;^Q*"(]Yd38_US47B_58OGQO*q=cal,ZC=ce(b8JK1;$VHh>MWD%T?1'%,(@LAF%$9G6]hZ[33t(lSgJY^k-hNN[DkA9IAcm%AY68/F[_r!3,;^r +pD%$_q-'o1&J)G]nf`KS45K/<]It"Dq69kqNN2/iacr0^1c/A*6FKgnMt?-[KU!:!m3gtDP@jaF-JKBs +\Nj_[YI\h*Za/_@KtheP3C,SZf+@S;hf?)7n=,q-8TF=*fq&F?\dfp]59c.:m1sFXa4^,/ng/P^Oi8k)I3D +2Ck?8D1e8L*%S'rg8sJ8G3c)=B$[q5S2n3>\RUpNk6)^i#H?QfRq"mn9!@Pg,!50:qEg4-*;DU7oV2k^ +r=9l/V_+MIiI,-nK(QIa<6)/W:umXN`1+;Y#3G'i#7Wof&>%*%K.VuP+LCKd6Tpp"GeYru%V-`Ka)c^E +P[t(6E6IcJ,aE_0JYA*XA%^G:+QEoX_H\QRH-[u9V9tIC.:jW]:mejSs(/)JepBQtQ[]a:(o'U$.#UN^%h-I*N>)HrF@l7dT/qfq,Q.1%rZfkPQGP;PpAjo)qf;)j$J[h.o$FdNHBftR3%[bJ.dO;Y]B-Qjd^VRi +U./?4BZTjIGqQD5U@S5,ndhQD4JC1V5K)8mnVhd5(#\G*TpfNbg\>'CMNo&@68$XrSeS'\8E[&6[!#en +M=CZmH]LT5g-Ck"YGm:P'1^[9UV6QN9N/i1BB=u;0]();0:DN9@AVUJSZ$V3-KHObR:Fr5j'+%R0H^eM +#an%/>&dulhNUsgPHJ!LTMA,I;d[*cVol[hi3V,F'Xi1"(Z`:[@?GC!TlMIElu7qdVAJ_U@DUsi*3FEc?)&Z!aoa^ZP(qq6ZXL>`S57XD7$aDe,[;'tB]$>2)+R&L"iP?P8[hb;M +SLElPXP%/_/Y5<9;K2n%oZll%W3#FCaXoZrHg?cI1(#?$n=%sGa"$2=modOj-&pJND$Hj'FJqR@5#KE1 +g%OA=XNVRXi,>2_e]XEW\M:M-T\]I[41'V$U<0)D#""];q8U5&TOp,$b;d2@2A#=C'B?J\lP3(jiB56qgN)O=S"Wp"YXA)eDbAb[DH%Q +pTnKX=uisA:hU$Qe-`390!-gnF-(GBCg%A!$9W$ET!9f2p#7B+4-.rZ.8$^MiN;4i$57DEXqdHoW"gBO +6]PUbn'DEJp]s\*]_EPuZiYl,O&hX%&t3!4k"A&`3fYf-Fm.oS$\hh(aq"Y +[)/U<4JD.[Q"ItO0aEd/GMo]kp&$oFkH?fg#5`]kn9Ld3Ds`"k44a$'m1kkh5,,j:l/R@S*cdUW]$sQ' +K11!'EGW[=1Cu*.G +jN53",WiQd0hJ[W9:a@3_sOlc*P3TM3BU]'B+W+tgpH*/P-"%kB(6;nBHq&U\a@Qt.:Lbaj$]4ZCN.&P +P/M+6f8q8Yqeib'5Tr]=;j+4WCQ=Qg%JNF_2OegT9;DKk0C8o1[P+%9a'1L^@pG2``*KlG&u4Ej0:bHY +8KRg$V//ug[P&(3qf4(\'duY^r)o0L8UGhbrnd'o1Kh!6ASprGW#Y,=a[\lnZK>^!MDE5d>k0IFP),l# +P!&Te2)8mT:T`&.l#U9dn`Cagdkf:j@cX,/C]2WCZA2Z.S,$`$\`RhRZ_Q+>[^WR!,`[];qTT:fZR6,9 +k&bUb5%lHfWGkCZ?(I0$32DB1rZ+e(/7OSF\[,hK1Rm"a5,R?8Lo0MYAi;,I+b;Q=ilO@=A$"6-gM0.t +oBPj>S"At-GV5s5Tl%d.ofu6tT)&8I;n_AY<9Gu7)j,cmDI6k_Sb;L)hpK,d+%P@n*%Xhh,c"C+E-EGjZ12\d2YYgL)0 +Tf6t#^(L@-kumtuI4G,E^=lShPWe;aSAkI?M;J3*CRC[=@f2nid+0'UtA7M5ob$&r-E2 +I[NUmJi9\b4Bk%$uF-%?DbF_XER +ItA&<"9PV^-u/K!e9_da[f!]WS/hsd(ulg_Nppj"[FeYNXdVFQo,?3o<*?_emTDEN'k#l/.UM.?pl$SK +No0WQ0g>Vt8)iAposV\43I978FUWWQ[o:%Njn)9\JU?n&V:Du0psP1BYL]j8O`EhX=j0$/S^Xf$1kQ(A +Hd49ifY![&'oA3:M.;4@4sbLGRE-@&TDsTaH0W8J\=4b[==lGCoq;_mDDfYVep]0/?L&BoY:7OCI/-XaZAc>;E8qJ%"7pY=j9@^_b%-n\c):`]-3Gj54"^i6VBWXK!/=9:@a& +pcEG=XQSKG5QC1'Ab.R)$jM`j9(mH+*OmEGWE$q&?at+mKBL:I@-EC3q00K'WkulXZG#3baqQlukC3PS'.dLR$r'Q;nRc94rcbVIec8F2d;#s9TnV&W=EC"/# +jr"12Sh9`C[qOA=:-Dj=R= +DJSs1?_=8XmM)$W1BD78X>]U'?(JQ1PGj2+l6("EZbnJsNSdd=gT<3.Gp@$Bi>BmC:Uqel;Ff'Jj.`&4 +L'M[slmI:Bgo5H:5gJ]iR,I\XM!O"tbF3bKn16L/cg&2G7&3PS&NNX'hZ0^DXUU-'8ZSaoH;VcL[Nq[9s[JNm^`8PMcGojbPP'0_qsh`,g#N82L=]#[i4 +Vqs">DRg`9`PBFpccUS[1jHJZn/;8QH@4_FT:UPMV#U2DHmgMO=d#+'YkGoUBK@9&d0-dS*_?2T +4Lm!!>N6Q[mj4TP#0Q$)2V>THYG$I5dW3PlH!6-u0QWd_##jWf3\,d7%d,9-%9cNDYEZk"sa27(!YQ:L2;?hRf_`C9bnR +>#h0Im.SI^S6kQ4.VMp$9-)el-p':ik+sh$:!9VRNjEa)2mKG*EO01R4Y+Zu+&4cZ*mO'!90V[EQ[Gmk +>2?(5bbrUgAW=*3FAr!NBj3:snAWFFgO4Pk9>kghE\:/5(3W?h0eF""Z#iVaB:kBignnsrTosB/C_'OA +5F.+:Y,nNY`LIX:p2MXGS@6FnqS$[#"-GYsd#+pF\,Kjff\b?SL-P]uh%Hu2PPV,ISn7"$hYO?bB_K+P +,]$5BX^U7Nq%p1(e`ua%b#QhH.g'J8N"<>E:2:Y,Q3d(]?=]0'eY]\E]g`m9bDdD+$0fe!oF,0sq9JW_;/U]lYE+$Fg[3EeZrZp8#5JX]EWXB?hEAn9K* +GN8[WG8seZ\9;Xh?_mo_NmIj\AN@+_hFI!d,5p'oH/:S+:Hb15koj8LMUFk?id6ILYK&r3"V+:B]fBS9 +>tGE;ISZ9\HF,q\N?Kkr\qCh)/1htq/YG+g(+;b?^U-6t=ppFsU71.jhIf&#/fRmXnsrVU#TC8iaLIf) +>/3V>6OOarQPOQ,>/5TVNYW1;U]p=R>q.EK9')Gn>:/\]"0So/[:H[3$^@`t8IH6!^!Hi?<,$oQO-O(9 +gkX8ET7]"N`HQbu86T0&kn9)[%iUc`\nMAk]X;i!0"20bID"1F!c785>p4n#If0k'OQVPnm:tgtdoVIA +3gkP!4^-!Pm/%OZm4Z1Pb0%8`Y?u1h)Lq5,NeQ$L8O<%5VQVD>jY\NE'[O)G](4Rh7aMf!"B8J54\)^F +V4KQRi:?=3JK_:T7.GT2JrdP,*GW-dX880cOG.0Z"=kVs=e>o_sR8%q;oqC0S +/eckU[RhVLn&X*&b!kWFA7jtH5;KRg*^?r?pETRaoHP;!=/C>Zj*kOVp#>A^30<+)j.L#^1g,&Z?$0qnA7pf@r]$jgNc/ibP?+9e1#\3, +c-I5u3-Jf6al5Z/EV3#rWO:o,9Oj6%C]0QVU.t,fo2@D_m11HK>5VO:8Qs48?N&Yc%259Z`69)K]S#lF5^fUr1dCAL/uO1f+<7c'\5E/j;Ki(^n"3:T,>lRoP>B,C%( +nl]"LYGb<73:fmoAh.ca,-Fj8\)[3s7H#6!M)WF]S\mC3'-2XLlBCWhO.,uiZd?@&2iihh*JSkDlFbrc +'%$87Ut8:E@YN%\r#5pP)iui$&7`^;RTdeCRu'WD:Yt3ip*O__W*&p9:?F@!1sA +iQSps`bA+=J2pq$XfDu%(tgC93G<5p2fg$6Ekq7I'"\2UAg59lH,GW3Qobkn>"P(?R0tM/Jf#h2Qs>Qs +#URg0:joI=(Y+0Uee*E-qPUI_=Z*D&iJ#+h'p[C+m?fs+,:l?ZpGf:=lQ2W/XEu,*Ts*$@/ku8DAQ=-! +(Z*b5#dKA;1'>-BY*JP^Hej1'/+'DG@l<5\b\1RXg]lB(kB(ToP\#T-L8t`E#0a>8PG9dA(Jj_22LD,@ +P;s(4lSKhnaQAN?(?TP=-5bY(;WCBUTVN"SLadVkqohSPi59B<\H)'sTMl$ID>AKLLGH_OQtaN'iuTo7@7h`%_8`eCre +]!(P%]E$IR]K+CZ\W""u47ZH>C,#\`/<6)(!#d+L5t27)KM=+.9B8XB`Aefthhmd8rGX;"Las2Z1b37c=^#+7V\l/Tn+bb'i. +`+W#mI5I;)->tI!B*F8b:j)R3p>/.]ne-USF]I$'KcqpoWC6jgaTH=?4e`ZWT6fPHf[JVe.qPQWkH`'C>C`[>o%ni/;3.[B%>Db%G`gt$2)m>\_) +Rg"iB*mZCNfU@(=\Pc>%aFHF@9'kl)^m":*Ga`s7FuqLBQ7s3H*H?kl>$f8+*h2akl,e;J8%+FLl(chG +)+."G>Y.PSAf@4g5T^Tdgd"_JTAS'D>;HIgRE&VqJ3nR+Y&hohbUXUi\;Ao&a)2a;AW8ZcF8*K$RJ^4: +\l1-%F([KB+eXES.dr2Nr8S[(-`&XMQcqkn;k;oR4#5ZTf7#7U`@lLg>Pp+/D$7>4*fCY.Xj\T9,_B!U +]_mCD"D5gr87h+1r"tr`Wce1%5M*uR*/':N#opD16Cuq=32DH3rZ/Vb[g^jKDe)/,>qUOiQiEBJT#GhX +hp4mKQs;Sj`IhO-V*9sSB>NikGlnsBaAh;_=h1DakB,qC?^W0`e0K#RA(qX2A6)`\YOeQ>Ps":o'%a+t +cBCF1[8,m]jT(Wj>b:Umg*AEEqP)f,$jlZUOXHWH?6f5*R'hQK\/FuKqq.oIJg4BOdYGBc_3;5UkN(iS +A^-5tlre5X@qn1gu\9dgJoiXEj$ArcR`0Q&$Ip&/*616Csog<(t#!MF;1=XWcc$]I%UJ\']WaCVn +nQo'a?PNapURSu)n>P^_j4\mBNHmgPKi.XB?s)+)%6K%!0#-^)3,n_Jj*C[]44a0*)js3/\U1]fd\B;I +\`3lg@IF+n]%_5tq%o&41!ef3gq'LU<:4ULE=B25i3N.WrkrHfm/K/]7T`Mti/H$7#d,NV4,k*@o*`ST +ls`]gNT5/Ma+Q@AoZJYAjg$'KNI/2q,EK=[tX]Df$nd +Kf=.IX>@SiI<"F1/o;Qg9?HZcRXJ6*Wq'#1B9]6l]DOV\OpF&Egj_AW?/8rKL@1 +kX"[WI$tTFp8U;\EbMD3dcTddK68m3:H]P]fS"5r??]J84\Cjl8TmejaeA'gW@3XG:fs.&b]E*b**6H&nb<#8_^85su!b5fGggHclTs3m)rK:Jd +J+(rP5[S)S8+4h5obo[5pL51l^)`qtcLWQ.oFMHSo@WXQqPV^Z%0o3,.gd:IfF`OAQDaHL<)5`EXC +X\/CF4K3cU4kPsBuOM%r)+.QhV0G)oMrE^UIRYu?fHg':B&Fk +!tp+PT``'p<+:oYJiA+mDMhrm8II0da."B+'pi=Ak^(jF'pL]\W(_i%muTdZcl%CRnTm0_FA!k8gT*Gj +qJ(dag3Y(OknJ@;3AWZnXn8=_0=``qpPqs0J7$j@<'>9_r>!msoLg8Thg=S&Y<%s$,H'Ho?Vl,]C1l`" +`P&WjB]2j3bT8,/RTfo""cq]tB^e"/Tt%&fbWCK_"S%]Dj4-)%2U4%bu3QGcN2;43W\#]=k:e-2N13&#p)1aJ% +9"u(Ll+OokqPlMT4VAPm`LY&W06SDo[%5.qMc(hO%ZX%hAap2T=.N0,#dLR8rmH(^ml`eI_q+,qhBSrV +9j^eGEkWH1[3P:rE;U_91kD6Ja8Z!d1G]a.L&O!N9@goH/d2W(7:es,fm3I4["Xf$S8S3&):*01TCrW[ +fgngRgg_(*G!E*_>fh'(?!NG&YFVuoe]R/7V#Kc.jqpo<8cM7*gU^fsu]_r(DZP?`l::G?Yk +'5i:CPLX,X@CEZ-qR^mrW.dc4;JB#q0M5aac2qHKOJuu?HtArp?14/g.Q9M5*J\dYJ45l24B'k[I]R!: +o&8_:WTfr)\)`BL$dPJ-X!$b&\^\!ifpQ@%H]q[iFsb(RDM(As^]"LtFn#pRZo?p4.lF`f9,lE[Y`$Rt +J*@QjNn1W6c$+:Nch4be5SL9P0&TGl4o&/I(Tq&MX`jf1_4VbQG_mK-WC0VeI3glEk=h(Nkn_s7'HG0ECCus*i/R +:pSoU6?PWMi69AR8qk%[pt+grZ^h'RM2kr9@&Co(RG'X8;#B$-b[u6'p2Bu#_>M&#Pk;H6@J-QEZ:m>A +T#koM=XhH9M]"Wu>'?BCc5*mKq$Z<&a$&^0gA`%4_QBgS2rs)U5[9DcL(_b2MSA,Bk[XJ@ +q%&Y4rckljeKFS30A9HKdmAFN[/[Jre8[>:o0t[A.m:/t$+nNkRV0E7HeX!R^hTg>p4!8eP\04)[W%X0 +#QKj+PauMmIDhQh`T=j:Wd\UrA]JNbB@%gRAb"N5Vie19DV=Fs#_+ooVm*I2=sW_nI&(SYmrI.QHJNV1 +=h'K^AfduL%KA[RrT'Tg:N]UM+9On+NVd>,i;^R]RmmEqFO=f__J#I4_drT>TYha/AGSL)W60B[3^ij0 +K+=iIfK:DICK2(L)seF-L)/-],&bt5X@8Oa$Z<]!0>+tUB(u'rdmfHN>d'M!umeU-\hXU8g;I=R#,t&?5PV#XuE#%_*Roni>;)TFG:qdSi$VRNVtZaNLjf^:KUn1L&j*U +c/4&uXDb9W&FDG_eQWh^55`>TWKO1=X'8TB@%8oK^th5n3p!"_J/h_aA_H4MDp?Wb!G`oV8(Pp +l-D>kiiAfMJ)gPC/O'JS +-/mRR+Y2o(&1Rkf"pZ!F)lW;?YDsM>rp3CqE$`N\eAg2uH(l=jY_Zd- +m!iTZU#EA/diuaIp_'W"..c6f_MRa+>`mrgkWW5*H\gN3]@3u!i(CLt@E;(),T*.?V"]eh]JUobb)eW" +1/>4cU!e^l!q68F#?u$s5NI`n2pI<2)AkO^cEmh1B-(=T335#;\WR;4TT^mFp1\2Z?!5!@8#i[(G]93r +Y"@7Hp>4"OXZB_2#!Wj0mWj$dC!-u6k/BN`'etF#4^4Vi,ECcXBi"A^4l_.[e`M4m$bfocSOY$*pOL&A31P%5?[ +>N7bPdGBh=`N8]ai8Cm3Y.qhSXfoTK0$^o*]`h\l^MaMkDID7F_]3]N=eW*Z +p^jO9Xr5O7nG01p0<:bXrTm-"hI?LhfaL]h1J9DA1"4HnK?OjbhQ`N!SkCM)@QYcTY@^pU'Zf-B>u +edPSBf@NYP@')?3h'TQCA/Y5!<]sRFa93GtNReo2&nSp&2c#I(X/+h?nV`.IWJH1UnhFZA6/6b?\TssFP#-K2"5+XFHi%S/!FgKZg[j[oE>AX'r^9t%r)8_ +eq.uIL([@\L-sd[C!!+qKoEb*I[4/\e/@ok36#;Sc^sp++.iLl-Vobpo)[O^bQm&raIX=J3E^0;S5iCJ +N9JoJG4AX]cdn>5ms/bRaI]Mu6Y`am]qiT`eV/(<];^OSCqkt\19cX5^f77Y+,#%h.MgSs4quuImhe2* +_O\3:B@=.<'ABrk:kK!_.]tEP0>[E51>8O>NNnlKeZ+mNAMKTJ"K:P;d6fE?(Po8*c54jSZY07kUTH^3 +J)Xu61BF.Qr_+HsoA)0EPL"3+eapgp/sk#W1,I4&<>*"IG>R#QOd@.1hI,`hY=gSqB==6`j;]%r_-(YjX'%5Xt/%Oif%qqrRcBTLt_ +:>i'B^B8Kqi_*NtD&9PP]Cmbh([-jKWRg?\D_b^pB()uQ_s`u*0coa&_$"Mr +qtp';J#j6_66EY-SS**=ZJ)nf7f0c@OTWRP0AK*L`[](Gi/o)JM>Q8IGVLbQV0;Y:\;Ec_01=7c#KNUg +0GK;Tg@,#N7'j/=mQm5*('Qi,ZVZh6K.r>h!11sSh&JQ`;g&R4#`d\mi0YR=R5s$o+ACI@mQm5ZrDRsL +;GpA)c0FkM.qi\ce_2TsfKBMHF+hj;nHEoH6hRcK.?" +?BCq/B;X1R#@SDAQQCh5gpX!`_jW!mQn(P"kpl&GFGe#1V#2,/l6:"h=bP7 +mO.JiZ#"B*&>m+eoH;BE<]F,Ki`P#h5^Y["'?5f60;fIGDs=>TCRL +MYLj:pBYpch^6G`hO2.f]OmHg=L;EA<1#`rYcg1$T@!Q?=7+?Tj+(P.-AT:hAn^A#78oh,n('1efn2$q +$QX=5/aC(7-4[A1&oTRWCI!e8fa"%4)4EZP0tY4uPr7RRa0XVJbmN.CnZ>nj2SOllPWlh3>p"*79/;^k +ZeK3[N1eSHM=KQ]9!lSH@=6%>9]IY;MUe//NLT9U']U]]6"rH#]tEC#ebK&(55p79HlcUP)Em+!g[)=q +p%0mg,R&/e_J@*1PAb-:MgngC]akLEhY:XeC0]rWA\PB"R$XLY1T30Aqk_>Z_[>1_dM5"C$(S>4i^Trn +GC1gSkMNOl5K'&D/?p3W)PbA[me\+q2D08:780e:e6+5+/,8FkQ1@A+Q&nj>Cf9I>TCY:<>Mn&8]^ +.5P\_RC;i2J]4D!ZI`PBC=PlFbFjLE)cX[UK7`=7PJ3hPap>B+;S[0[-$e8NX`r`c,'s5/a7HJnqWX5f +`.>;u?5\#@*dGYaGhI?uOc:q/SptKF]Q0j0!BXaX4*JQcc6081n_tES[!(Up]6KMEA[6KtLA_P*qB3ns +T_Z7agX;*AY]dtT1j6g\:[V82kLpMP037Fq%Fs)C>Q)]B]I(Npssq:fN`(p(Tg19IbldYTnVf%sTo])F-CD +Q?CZ^sm7r5-N,/B3U'TX9>Tb9FrN8WD%g\>ADXjq"&XQ7<87h!PYNYjlP).DheBA/L%&O60=#Tc'C +0oG%c4gFMBO%oZuQnQ*[E=gl-J^LYD-con^nm7d^>EK])(ZZ#ZA3@n7cTnM*i],sFRf>,rqXaMh*fkgL +iEt]oVY>lknGX&K]oA(c`s?>F\MIP'k???>NGud"6&a9S%:jpJ8m@KQ`UaN1AGR1'c"#W&d1`&_$=cHi +^FWc!IrFT>rCj$4JC\>dGXIC%G1L#pY8C&4h"Gf:4L'M0djU7sq!^:Va-.\,0eYZL01BeTDB+ +.QSq;(q1TZFQ1CR:GGJ=*>$k;m;I6ih)\6"3*1t9Ab/fc5p(*`\OIIjc0I3B\'PPOm9V,8*-c3`7-_1* +=pO:LkXclSh_NK&QeCp5@37I!e#]X')Df;9Y'tCL[:0g+CVH68jBlDsl-;92s/34[aH@N3K'9pD;+H]N +#jE2>RKMWJ(RamOgj_-Ep>$]WA8V29dK57*"GYkpNdB(eC?)cTs.DkT$\(>pA'S2(YA\XlD7R\@1oa;T +jhk9,b7?Z5.;YGhaD4T70Zm\-A#3qX7d+I)JUDMLOh#\f):1W/Q;:[DlFJJe"4%<]SEC8"X;lW,NmA3h +VpGa:eW.rcBADk0Ksb_ue?2AZq*\B;.*8$b*SZ6olLogQl`Jj(-O8M#Ks,0h:YDeD +GQ,DOh"UDYpq,_Q$tWiNp'[+k9!h.0(EfZE0#;hTONsEe%6%ed0L_$Y-S>mYih#0^1TO +)JN;&L`!=X'(%4..V?4,;Z1i`^9iY(CHo)Ycd0AdJNrSgpL$MSPSLH*Hf44QX<%0PCGm3cRP>._jkjp?S+9TGRsGZMm[WM,\n(/A[+.%+O/WF#$fi,?rZrfC""ID#X^Ln>]>WC&SBZFf`"27,ho)-maia_-SQ_4;/4`[hjn+`S> +-[rRPk;JR/=/uJ[qZZRKa*dk,qt[I7pIB/tP0GZG&A@2B="!kIEPg3QZ$GbrAM$g_%;I7PAtlqfXDl)" +\"d">84r]pREPjOX0S83Y3%UjL#"K889"1N9ANp[dC-UB`/"9SBa_[N`g!3MVH$M?)@KPj'CVA3r2)Au +.c2iR2ZInq4$P$3$hfq7ph93>3K/4[(tHASoOa,X[$9-D^=\k2nHZ[:SC!^ +X&O!#M_%^\X'=AlHQB2L13GNc:XD"kq/4p8c[UpfI!:jsaQ5;)g@1tT9"q>HpfFp;-#sAWgQr[WJ@8Db +?eW!A[YK1=n^faBS2)c[djtC(;Gt +Zoeo`I)O9/Wak%E1V9Pl@E];kCZm(1#N0fdh!6$X43GnJU:E1=e3g!rd-W(=F">aN&^%L\@*)0Ya^&,r +2jRG:1Q6gCA^^P3-)(Sr0BhGuITRZP]Jpo"?_3J+QlG8c>qeZjUG4DGYK9?k!*K9n`#;<'!Sd,HQl +[3@Ybodn[VNie*F=VH4^r1gLI6f`@IKbQSE2leX6,E.gOTi8N(4;Z`=/Q?uX>M9RHrUl\u +4-l*4DiFJ5!T)c3\9jDA^G0eRqfR+a,<`.m=@Zg4e^Yj\)UWm0Oc":W1M/`?7dlC\*+eE:nm]g_"^.ND +ICP5[m?D]LCu>3!4)KOU7)q@:2c=3>NtJ?MZ&X?89/ioUL#I`>;uO`QDAPKC=@ZQj\mZUng5q>EMNp%o +OAUn^PFrHZoR2Fg3G]H](E^?lh[H!h0:>0qR%:9RI.LmG6 +GVh2,;%MGMXh?j@$HVf-/Ph/HaOfps6Reim,Xj':LPMd3WKhlXgcW9J%F&hI;1Q6 +/VRP;=Eie[L`.m/\ +",3@qQ5B2`bI,IAXD,D:m83Uj/*4OW74HVWqpOIa'6I^G'\8D;5cTl?@DpnmF"c(rU1<+Z/[44o!@cor[`J0q;&"f0/V8k2pchRsX#U'_nCdZHlchR>I!b +-)Cn,$_1:p7U7et^.5-)Ic`]``64Aag8iK'Wu:T#)2qcL`)GOl.T#re +LLpgqbbZ`98moq/R@Up;>Og&+S1b_(LN.*PU$D1+QCb:mfbE,lq)4i_aF?oJaqC+2..?.4C?&9.g,-It +%a@33fh1&.jVDAoV&8:9)?,"`2X^&&R.7saRe+)Re1Z*I8RH3?;]^@2nbu2lau]slr#%O]b\0)P]EmY"Gti`%Q*Zch-["jZ0qqBP>RLQoV61kNUYcWMenkq5SJPZ]sXk +`h1Cpi\-Y@e&][Q@?fqJ44/(-]P$>?m(VO#hQ`@/7!5:EqAcj4tceicUJ5?DgGA:'D6:nr/[>7k)d+fsakNfe0*`(Ii[&*/ldK +T:C;:j*iE&W[[^Hc96h-TW`$HP1QufjK4CuF-RUlPH%nQZ/EJn^b:2OeCum[ba>MF:bFGCk +B6RO*$0-I&dAtBk=C=6.,O7BllL]IE&TkPWL[tB2Ros4.+[%\_ge0l?j[XBWB_MnX#s)+YQT*f3iq^(Z +T/M+KHQuNJ$6.2k27PZS=>_3NGbqi]%IWXA"C-$69$>%FOCA%>i;E(S847Cnpf5rkmr")kGJ"OXe$rhi +^"I==QT]u-/^a_rKJp@/09B6gq#+OL:*3T^cBV",N9EWRqJPqoo(:Ja]qm?b>+LAfGG=N33QA5J26D:5 +Z0R`9lZWre-0ocO9ulq=i688EnXAadT6r +\\2M!dUCm('f>GH*i4rNfX#2S99eaFqAN+oJ+@ endstream endobj 7 0 obj - 68467 + 68517 endobj 3 0 obj << /Parent null /Type /Pages - /MediaBox [0.0000 0.0000 798.00 551.00] + /MediaBox [0.0000 0.0000 803.00 551.00] /Resources 8 0 R /Kids [5 0 R] /Count 1 @@ -934,15 +934,15 @@ xref 0000000000 65535 f 0000000015 00000 n 0000000315 00000 n -0000069210 00000 n +0000069260 00000 n 0000000445 00000 n 0000000521 00000 n 0000000609 00000 n -0000069186 00000 n -0000069664 00000 n -0000069380 00000 n -0000069419 00000 n -0000069521 00000 n +0000069236 00000 n +0000069714 00000 n +0000069430 00000 n +0000069469 00000 n +0000069571 00000 n trailer << /Size 12 @@ -950,5 +950,5 @@ trailer /Info 1 0 R >> startxref -69737 +69787 %%EOF diff --git a/images/static-pools/static-pools.graphml b/images/static-pools/static-pools.graphml new file mode 100644 index 0000000..7f1fe2f --- /dev/null +++ b/images/static-pools/static-pools.graphml @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + Static Pool + + + + + + + + + + + + 1 x 128 bytes + + + + + + + + + + + + + + + Group 1 + + + + + + + + + + Folder 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 x 64 bytes + + + + + + + + + + + + + + + + + Group 2 + + + + + + + + + + Folder 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 x 16 bytes + + + + + + + + + + + + + + + + + Group 3 + + + + + + + + + + Folder 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 x 32 bytes + + + + + + + + + + + diff --git a/images/static-pools/static-pools.pdf b/images/static-pools/static-pools.pdf new file mode 100644 index 0000000..3051aa5 --- /dev/null +++ b/images/static-pools/static-pools.pdf @@ -0,0 +1,256 @@ +%PDF-1.4 +%âãÏÓ +1 0 obj + << + /Title () + /Author () + /Subject () + /Keywords () + /Creator (yExport 1.5) + /Producer (org.freehep.graphicsio.pdf.YPDFGraphics2D 1.5) + /CreationDate (D:20240209121153+01'00') + /ModDate (D:20240209121153+01'00') + /Trapped /False + >> +endobj +2 0 obj + << + /Type /Catalog + /Pages 3 0 R + /ViewerPreferences 4 0 R + /OpenAction [5 0 R /Fit] + >> +endobj +4 0 obj + << + /FitWindow true + /CenterWindow false + >> +endobj +5 0 obj + << + /Parent 3 0 R + /Type /Page + /Contents 6 0 R + >> +endobj +6 0 obj + << + /Length 7 0 R + /Filter [/ASCII85Decode /FlateDecode] + >> +stream +GauHqbDmmZP2*dc,(JOJpjOd%&g0Gt.kP?b'JS!oXFWk;Im?:Y1FF&?pX/3EoVU?*%+=B^)P-:.4Rk3i +s*]RdT>/;PVD+YBq=ssLgOFU_/,o=0j/OX---Sln^>2M2IJ`Ed^O5qQVk*kY?bcTdDuVnJr7h6u29C@I +n%\htn,N!oI>bl:q_/!E8Gq*>`4k*>H&qp+S%%gYRm0Q`^J"46=8=LjUt,*E8fY3j6_j1O)dT5Rr;36d +2TE1sT$toUNk^6OlG0M$`a8\SDu][+2SjlHja.QR?iT*F^H[dDqOmlY/O#F`o1-puZR+(6c_!Z$9=T]T +3D@>hs2JCF[r;<4>?W&7(f(C?hGX+g+/RK5>#oRYmB]N&/Qlj"0&n123'X=7S:R]6PWlg21E6kE\4XeS +2\[`<&[K"H.d`i7:KfE2]p+JeNVt]"Y*L+:.OV5^Fb.U2n0a"#gC<8<]$kU=OJ*NV)=du!KCWJ.>a@;! +AiTJpf@'RJ7&^"(Yb"R/l(pRdQV`PO_WeB@PWi!pB+57FTapG>"eLU:Cra(k/I;;^ah +mAcX]0+W@c9"cLWCDs?VR[8F?6V[+c%pmXpGV6L..t<8>20'_?%rO!N4JZZYrn7!-+)W,<%t>ADS8 +/TJAA+-bJKcYS>'s3KC9l,0-0e5A(AITl4'3i\f46/U?l%$3[[D1-a[tVXHJ#qEt3?2Z8-=k2XWs.,17T[bN*>#j]U: ++n?FH0^6*EPO[^;:H%KH3f("]U9q;P]"j#B)eLQ$@1?"IBSn;YH6lYb&!tVhGK>8uB'7MF"FFfqpVGc< +e,4hFfV*0s,_P,I_QT;tW4=HSW2;Ra[gBM4`qdES$e#Amc(@.hj5@*2oF=>L%a#1\>#4"cMCBF9nZ_8(\3B3X.Ce5M5@GC=9ETuK##3d.F9`om9\CVZIc4fpE_>+:BO$E&a":@K&ZD/,"^/e9SMaTXR4:emV+:YVSV']$J([5Yf)XL^]K57i74uu_XpD*@olnX,&NO9ib +%&N3p%WmY0V3,o$NEeT^ebn+-?`G3[[)E[c:Y2<_OIriakDd!l>kAQ%VsAW +AF8/If$8]MoQQX3ZSq>[Jc02#p-mQXojmFp?*'U_akBmhOKg^+ZZ`MGY*I2DWtB:KeU(@CG1Jk?KA87s +@g/HOM6nM9!.9`I^:PQ:2.[P-3c2mhE-_@`J$@fS +Dr,`=a@ib&>8l*Uf6+&oBsDgN[$uSRWT9WU_`,ciCF7Mt7gQI=T/'sF(R6T"e#_EoZA5)r#HW*R#p`]_ +;dE]PNpSIdg\6CCQ:6F]TV^1VrK%68^6q0\hmJKElGB.7UIAF+V^67qcJ?fV+8sR\g-Z3Xb'QW-m65AL +UC0S+Tsnq;>ibcqXPfO;:H"8jre($\6sJQ*T!GIQ4Lo&VH+V6@U@aE[<9K#^&i7s"S2Z@R:6kOt\?n?\ +@p8!#:7CKqp!R+&Y]'#C/Qrg2RMVR=@b(t;`foH&?N-VC;Id]"Fln?G6`9P]52`L$-C<*l4plc.7 +4LX"1^:DU1!shS^`%C-di:.>MJtE +:J,\\RN)(L`nK=]CO(1Tdmj\N7gT%#Z1B<^qo0QCdR_QNI?m?+,6&K!4fE0TH4Xp3/#bs@]Ql.@WaMU] +BWhp*L`O1NZaDS.g0J?#[[Y>lJYclJ%HQ=qZk].NXgD>/K%5%VSSm3KlhX7(m +EbVLh^[9V@pJ^+\Sq#\_][o)h+u?TPo1!NNWGPYC7aKRZ"@1!5)Z=%7Gk!')(2ETj@O9&6$UQ$l,W5#f +q92>l8u!Ra*@P4\#";duf5O:q?Lihd1dQS3oQCa.7'^3sQ.A&k8^p7rB.2tdh +>7]pt>(T/ji2PU,j)3m?DJX0V4aUHr-0P!K!O@WDGNGfcFPDn8k +]N0g#G1lYPO'jlnkp+!`qs>Ub7G_G4*lj8smU>/I@Y3o^Fm>;3YP,@#_qiT]gE-XV3s"W]nb.bE*hXPKbOH9YrARdUTCN!PnOqQaZPu(cT3X,pj&";:8,VKDOZqD-aSKhVqQ$O/25[h-T_6]R +C9+8bQB+N5[;fCAnV-i0_0PGC#EHtl39hG%(g^PAcZlqVGQ/U8AnYrZ(Kg>P)i3=ig+4SW7aRXtd$=q8 +L%9Mtd$HV]Gf>!pdr-2@flXdJ(LPtj,MLHnp\kW*SaaSJb1esgYlB$7O7W0)U9S1#a./*sn^kcE-_o=M +I85TH:.DQ2I1D!Gi$Z1lT>/6I"-Du2cT.EHFQ=[6rO+36h85+pMnhi2=P5BW=f<9C4LP$c2Li\nn2Q>/ +86aIt6etQI5`[KZ2E3b_#L&.%$!kq/NSCgUU3Qm"p'\LpGKB":LoFAXH@$VMV`V[,8V9DI=TQ(@-18S2PtA +#p\$$-S5\jm7qD$]fs/,rG[Ujfqmc#bj$fCNm`;<$&dI'B'Vt#8i)P7BZhobd:A7W,=T4K&,FXOip8p_ +LOQ5mBJ%hI`BU#`MR>[AM[6@;S!hjY_\ScsBmPt3:"*f2Dc=`_qlG]U3EaMtbh9gYQsI$c->q1Tn^X)I?UQK\, +Up?#_#P95ma[2];_gZ=I=Nu-1=+4sjm!L#3.`Ou)]!rM#B/5^beuNBCAU0$?f$DdgQ%CA>f7M`$=0J%X +#SL]o3a$TV'C?#TA`hfd@]!MG@]tt`ak0Va-H6NQ)O3e[.sNgi/Z@KEodYrunT!k2)NU0T2=8&]Z&LD; +c<'Bue0,\p9X>jgXQ&<0+A6*E=(@bpE05=Rpg27[#Sj(5X\1A7I["a?*hQ&War9\^@fsYo-*5J)#@>mOb#;? +;rr^6]^*0nWSp=Y/`2oR4nkGg!L3 +%J;@oKhW'B3@QNd)%R?^]@8KY8]$ +.r78lfYIc>Z5b_;0L8GRq9"\nSE.(2XlM$>`^k0:f5@FBorM*W69'%!m.skVQ$M@lE?!AMY-NVO\nH:c +I]NFkbrYC#-2CHlUBd/88?o[?IRlfq>0bkMj&cg6/OrroTlBHl3H3lDAfm4L&0?Ci>16s["nQ],:-2g"!];L8L@r=lHRtr7#oB4OWs60 +q1)H*ql\Sf6AMaE!paTSPq]jT*IDlNbQDjG._M'_?Y`&ZD]98h)+.paUXcgoPB\@KipB8heU`Q9djs)G2Sq9W]T +;!cin^gFr9$)@J=Hi8H`c,WVn[9%;6O7i2O^*efCg"R1`h]1Y;,lHbK%)+[AqJWJ39CJJ9qBI'trTSA$ +SK+&//4\jh6tD.*^G[^]c/)S#$%)V_mk9Z2Z+G_DK;)r/='roX^-%4mLQ5c)]S2rg*Ui2]A4I`kOEEfP +rP96Qn+P%L+/mr]/_^N\Y.DO?ikpHkqrupaO,_jm?!tiu+:HrYnnnmO6a`q30V$j_(GT'QV)'H6A*ldc +]n+r.`R3,V1mAT'D>#PR[kEgOTr$k+/H):Z7Vdi2^R.pdMTcN6WlRK1T?9+C,m@a`P-A9`=38dnZBTZd +cP=(*]@"kFZb#iW6#VQ4_d\oA&(DIWh&*J,mg2-5Pp>"RL,A(Zd9eoZMUH5TY[Zo+774bhDLhCRQZiSA +Q=Qr+h0$%kMf@YrO7f&KrOCIsG@W80QL#&Cb?3Jf'#W#5?RR#ZMAYSa+X:q8PbO[]5KbWkHIi\YIN:MJ +bPjZfHf0IcRJ\7Ioj=lmHp7QL118I/*6;M[ZcG.!PK775p!*trXbdXWmgIVK1/'rqmlP?%X,0V!fFZaW +pAG0$FOWBnG[M7jBoj-eftY.@*`$C;leS_WVs1m,cMY1Ko"+c:%A)'?1\jOeY[1U.l-eL`?eCJ%D:aZ= +%1tOj_N@\O"pcgtpjni0>?sfuP%g;u*1LRhLU5?d="2]P4A)#?>K]bs8g?;P!F\B1SoqS!Vtd_+ ++KXRk,Qm>c]!^n6[9Gh^q^+A2WmWG)B=8a0?9-NPrM"IH^MUs9NV:R3Y49T!?k];[]8upK4&*tHAr[8M +Kda\eZ1(J+=fk<41YLXa_4(U?Q]QE![nEsZ0dr`,?\/(740cZ?,#.CFA2@`.4f3C`Wjr,m=6d82hPNFq +X4(6OR`5)FgKD3k_no,.?f(lZHhMh]P0Ni-&SjRBLJJe:Ki+JD2"tn,XDnjOEdY6U\3=gNQa_IoJ)fNp +/gPaQeORpaB,oM"hd8$^EQX?1bhWl3"R_K$o0eYZEl0WRKCRSNK`08#kG8R7U0(4Hu16/[/6NY1=/g5+-L:lnoT/.XD[)k8BfhY:P-c6]8?JgYLI7XbY6[[ +roOisYrC=ZUfPC!\L[[mk]nkB'!Z=8F#ELjOaDr?6Z^n*W*PkEY!n4!HXsJ1PeHQ(?uEmUNTb%kS2aE` +/00(-]8jqg8]Zs.iNL'iq(bpCX1H2(@*UT;Kd,9P<;4Njo>SaWsb]p65_n@Hn_>/B:iP%k" +QbUGtF[(CX&(TOH8baq85o.GU=3dT2r/gCWrFh]eS336gbE25d0bEqP?2/2Fb;^GYm!%J:bY6VTaImZJ +`@(lW',Y-"KJ/mg&R![Bb.B0$Fh>"V3TB#"-%$/O@-Ai_)am0X-r3]@m.FYVbb0d&)mYF@]7ornZ"^uH +*)62G&'m*Fj1F$!Yfg0c(Z.SELp8da&Ij(B"C3.n;/)B>>Vt0kcI?+-a8-aA?#H&WZu$DEPhBtd*\3/B +9TDO0^nR5b;=US1T1%]E(VK:h?b6/V@FP8.CHe+OalME4S^0%)k"kc$o>9/5T]71+Qam+?7[o;7;r[uM +IX9Gd"`tp-\DpHO4uhT]n?V):Xg!!?#;\0u;0Bh1.77$G#/0$?MR^:C9i[Lq1W),\Xh$k,]d(7=HbkN1NS'[uk?NA<,W7 +#`5Muq!/]:LCJIIghG0P7si>'2'O-PEC?"k&8sHOb0 +L4-7]P@lBsg(h*0d8sL]]4"5`Y`N"r?349-dU&1*.]aSICOB:PKi0r'mq\\;V*t"Y*ZX-D)kFP:G-PSU +^EaG5eQ;)4=88EUXhK,IYMS,GH1tWp=)[WZ>CQ8=*m8mOiudM;^3Y]eYdZi[q;Ucj/&Pe6N5s;4@4M%i +#'ed,roNh1=S;^$bh&I>fAFf"Kq.9!7,=GuKQUYDg:\jF]G5l=QkO])Q;EIK7#WMQD(NU;hm_Xfj_8mV +GHng4Kcf-fLEp&9WUV-WJZNb"8pu3L9d8P2[ji$J;-FHdSE%;#3CZs3Bt!*i*dSBu6VHOhi1XMmeKl=V +0QjE(U>DSRoi4I$B6LgdQAGmPb3hD;P1_g@`&[4C:!-?3etmbZl9$sb>KjdOZdnTk!:R9t&YsjH:ER1D +/Lu0Z[gCt\e9OCec8[X]D8Z.G@kD4MN2/f5e2BdV8k1CsA+>aMJs)e)nHU\*g.\*`TW@,gL\. +I\U'"Bb/2M!S4PL#LM+H%Mt\s+[k]H)eU!T\4h.aq+=HILYd=jo$*_IOQQC`]SXB5-e0KS@IRu%^05]IqW]Ik_YAoa6ruC +Y(<$kM-6I[1L*'"/tQttcaO_:[u9G(`UiK9oBkQ5G4Bs,nU.rn^0NkY?9I*tSo5Fk[hmB"Ms&j6oBjNg +mGdqbnU,]RI(OX;>s."niq`<-q=`hDG4BslGeUk9^0NkY/tQu7So5Fk[u9G(Ms&j6oBkQ5p>YmknU.rn +^:ed*>s.!sSo69RD\pa/Ms&iQkM*uImGds8iq[cfI(OX;]m.7s4Pqc_D_I]#(XKRKkM(pXgVrdOiq`<- +q0):U]6M''GeRHGh_(L=0:m(ucaShqgPb7L`UiKVq=YKJpWg1->U=C14-o2E#/m7[#'sc)YOFFY7JP-u +HBh2=THn&jh*S3M>YciqUiuA":/o"lc7VuV>3DHA`"?1kPKR:0\%=D7/d(kRGC+T&4Lr,Bn&"It/sNg1 +ai9l=m4&a"?9?gR&fphF`\V,&jHQ78);R9XZZfVL0qMQbi1"&`ncr#(3bCmYNU>F?CV\\a$aM/B:^-.=8'_eq=D8:Kj.o3UL);$SmG\BM-gQ9BV\/Mdn*6;(J2K-<:j`c,sj>.6pD-ZlO +f;`1a\-j7EL/sOB4Vcca2Bqa``Y(YL$+l[D7(kNW<-Ln1PTua5ed-X.82ua0l-%aS(MA$,IC3"GeF:i^ +*#TY9HrGhsbZBl)`Xff/;Z.D<2EPi9=VtE"G,s:m/EYarEV;@pSg)Qao7Y: +m1%FVp5N35in2CNg=VSEkVX<'Z?GMpfdU+Gb*jVHYTN4id-:,UED)PVQ.o55"((qj:WYa+)XmGjAtcGW +%?A4eOf9A0e+UlN&]jQXLLpb9./n+[h&JS#_U<*.q=,M.OO).[;hMhl_[)o]ZhJTpB#3=X%nV_7pZR3L +Wlkd0+gPu=5ku7*%,p]o@Sj4NGqq,-[1$o1[Lt@AP>%GXUAl9rGq9"&j#$ANchp;D^L4?/0NeR%%188c;K-&p-@&acD.qE'RmnI]9fVn+[\;XGtBuC +Q,XA;\,0:^<=4b)e$V%1QLHnYgqutDB9oNQ!,q.nMASbLEdAr3N2=#;^h3RH>R>@E:T?8($'+Y3@LFGC_Kh,O0.kp1&#qQjbrcNO%XTqU-P^)(\B5Y`R;B?348B +.c]<[;gs_RTlFVDdt*7d=3"D^b-Enu_H^Eu]OK->Yh'js;YD^Qjlj?VkP*Bt\o50TMQC2E'f]]F4'Ptf +nrGSTaN2h)\R=hj7aH)l*CPIsYJ12`BLL?A-'5 ++"c-sf0A5m;ZQ-uEVA/A+jh6UIEQR,N5P3M^L$IPG=gE7(NW`\47W\IbH$'+^O*&*pW.mf7mR*hfU's? +K`.hF_:h[jjk`4oT-pf8ASdc`2fpean+(iiDin.+1TR(GfQX_=+sXSG;!s44FLJD*Ye9PUXi/@RId:(/S9.pmbo_8aP]0Q"8+TtpMbdDZ1$2Afic#>a`]3'-V$7WKFfNW;V633 +2=XFZqoW#b`&Gnf6HXZ*PEkM?uX;Ob:Pr%;c#-V>2RC\#=heh7OB+@r;TkpP/GHW@I8G1Nhs<4>g\NN@A9 +ioX\0$YQrA;I'2JFGs4rRCreKoZ;>3f5kM`^fIdZfdH(][0=V5'k@4=9GPim%[rkq=>L0i6,)C;)s2a, +<_nrM'8=1ZG##F5M1P'`4bM@H7bBf)]^S',Q?sMEPkAYK>ALUEMUM3R^./2c)k,Rh=A]hkI017ctbjY,44q2:/hQ5SESjM93'PA=T;=OH?Pd"E`]-VO"/>ZZ&Da9Aj>lH(%I:$gNnU&JSiWJFn +^l:&f`kSA12b*02ijsWg`P*u`9.hUr(C&`O%\CVN]tqE92XBU3hW`SmhagF)\Q@&W4\ROiDj^:lJ/'gp +]n!tuXn^XeH6h4Dr.79#LI8T3Tj&r_Mqaen_bN;%`os?eQ]apr*_* +=W*u&]@^aF"'<6-mMD<5CF[j$hBkiMuCQi&CW8m0u_^p,:1R`Z/$Whj@(J,Om!MtZU5r4;^62;Mdni] +XW_V`DgPVn>M*)EWo&hh"tRFKO[UPA;,)@Zir!eCm_G[_f;:MlD`kI847&Q*>1Q;XVIT;7hiAaZA,(3t +i!/ZUEE=!#QV21OO:LV)r!c14)rR%\>#&'Y+#,7i==$b\PQcd4NRfYq9\fRaZ$SkhkOMY3O:A_jZ(!nCY\*D"j +;r'Tr,F;k(k@tI,)m? +&Do[H)F@eSj$srLMmb^cBP)bmn>6uD`sCcPBH_iW^Q&9OpeP^i8RATr]Y8RAZK;&i.\MQGHi*^P7lUqYf9B`/I\ +qZ8&2`u8jM;rLjE<=4aV*i+Z4\od.U6pol:BW7($Ur,NE1[b*JD)#'+91GP5KBnu9,J!g> +i>j2R^VA6+\`OTi[gnF[RrpflHVtto@Tle->l0J>$j)m_ArI._+p*8=1b\E&As5i"M58+"hg]%MM_N%=~> +endstream +endobj +7 0 obj + 11983 +endobj +3 0 obj + << + /Parent null + /Type /Pages + /MediaBox [0.0000 0.0000 311.00 209.00] + /Resources 8 0 R + /Kids [5 0 R] + /Count 1 + >> +endobj +9 0 obj + [/PDF /Text /ImageC] +endobj +10 0 obj + << + /S /Transparency + /CS /DeviceRGB + /I true + /K false + >> +endobj +11 0 obj + << + /Alpha1 + << + /ca 1.0000 + /CA 1.0000 + /BM /Normal + /AIS false + >> + >> +endobj +8 0 obj + << + /ProcSet 9 0 R + /ExtGState 11 0 R + >> +endobj +xref +0 12 +0000000000 65535 f +0000000015 00000 n +0000000315 00000 n +0000012726 00000 n +0000000445 00000 n +0000000521 00000 n +0000000609 00000 n +0000012702 00000 n +0000013180 00000 n +0000012896 00000 n +0000012935 00000 n +0000013037 00000 n +trailer +<< + /Size 12 + /Root 2 0 R + /Info 1 0 R +>> +startxref +13253 +%%EOF diff --git a/satrs-book/src/constrained-systems.md b/satrs-book/src/constrained-systems.md index 3580df7..7890c47 100644 --- a/satrs-book/src/constrained-systems.md +++ b/satrs-book/src/constrained-systems.md @@ -19,15 +19,33 @@ A huge candidate for heap allocations is the TMTC and handling. TC, TMs and IPC candidates where the data size might vary greatly. The regular solution for host systems might be to send around this data as a `Vec` until it is dropped. `sat-rs` provides another solution to avoid run-time allocations by offering pre-allocated static -pools. +pools. These pools are split into subpools where each subpool can have different page sizes. +For example, a very small telecommand (TC) pool might look like this: -These pools are split into subpools where each subpool can have different page sizes. -For example, a very small TC pool might look like this: +![Example Pool](images/pools/static-pools.png) -TODO: Add image +The code to generate this static pool would look like this: + +```rust +use satrs_core::pool::{StaticMemoryPool, StaticPoolConfig}; + +let tc_pool = StaticMemoryPool::new(StaticPoolConfig::new(vec![ + (6, 16), + (4, 32), + (2, 64), + (1, 128) +])); +``` + +It should be noted that the buckets only show the maximum size of data being stored inside them. +The store will keep a separate structure to track the actual size of the data being stored. + + A TC entry inside this pool has a store address which can then be sent around without having -to dynamically allocate memory. The same principle can also be applied to the TM and IPC data. +to dynamically allocate memory. The same principle can also be applied to the telemetry (TM) and +inter-process communication (IPC) data. # Using special crates to prevent smaller allocations diff --git a/satrs-book/src/images/pools/static-pools.png b/satrs-book/src/images/pools/static-pools.png new file mode 100644 index 0000000000000000000000000000000000000000..55a06577484bfdb82c3fb91ad98786fe5296b8dc GIT binary patch literal 38516 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 MwY{n_+mD|8H`S&V<^TWy literal 0 HcmV?d00001 From d017b9c17961a12d2ceccd17b49e876b3319793b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 10 Feb 2024 11:59:26 +0100 Subject: [PATCH 3/3] Refactored pool abstraction - Redesigned PoolProvider and PoolProviderWithGuards to allow easer optimizations and increase flexbility --- satrs-core/src/pool.rs | 287 +++++++++++++++++---------- satrs-core/src/pus/mod.rs | 26 +-- satrs-core/src/pus/scheduler.rs | 133 +++++++++---- satrs-core/src/pus/scheduler_srv.rs | 6 +- satrs-core/src/pus/verification.rs | 32 ++- satrs-core/src/tmtc/tm_helper.rs | 13 +- satrs-core/tests/pools.rs | 10 +- satrs-core/tests/pus_verification.rs | 31 +-- satrs-example/src/pus/scheduler.rs | 11 +- satrs-example/src/tm_funnel.rs | 25 ++- satrs-example/src/tmtc.rs | 11 +- satrs-example/src/udp.rs | 13 +- 12 files changed, 370 insertions(+), 228 deletions(-) diff --git a/satrs-core/src/pool.rs b/satrs-core/src/pool.rs index 0111d18..e34db43 100644 --- a/satrs-core/src/pool.rs +++ b/satrs-core/src/pool.rs @@ -3,11 +3,12 @@ //! # Example for the [StaticMemoryPool] //! //! ``` -//! use satrs_core::pool::{PoolProviderMemInPlace, StaticMemoryPool, StaticPoolConfig}; +//! use satrs_core::pool::{PoolProvider, StaticMemoryPool, StaticPoolConfig}; //! //! // 4 buckets of 4 bytes, 2 of 8 bytes and 1 of 16 bytes //! let pool_cfg = StaticPoolConfig::new(vec![(4, 4), (2, 8), (1, 16)]); //! let mut local_pool = StaticMemoryPool::new(pool_cfg); +//! let mut read_buf: [u8; 16] = [0; 16]; //! let mut addr; //! { //! // Add new data to the pool @@ -20,25 +21,25 @@ //! //! { //! // Read the store data back -//! let res = local_pool.read(&addr); +//! let res = local_pool.read(&addr, &mut read_buf); //! assert!(res.is_ok()); -//! let buf_read_back = res.unwrap(); -//! assert_eq!(buf_read_back.len(), 4); -//! assert_eq!(buf_read_back[0], 42); +//! let read_bytes = res.unwrap(); +//! assert_eq!(read_bytes, 4); +//! assert_eq!(read_buf[0], 42); //! // Modify the stored data -//! let res = local_pool.modify(&addr); +//! let res = local_pool.modify(&addr, |buf| { +//! buf[0] = 12; +//! }); //! assert!(res.is_ok()); -//! let buf_read_back = res.unwrap(); -//! buf_read_back[0] = 12; //! } //! //! { //! // Read the modified data back -//! let res = local_pool.read(&addr); +//! let res = local_pool.read(&addr, &mut read_buf); //! assert!(res.is_ok()); -//! let buf_read_back = res.unwrap(); -//! assert_eq!(buf_read_back.len(), 4); -//! assert_eq!(buf_read_back[0], 12); +//! let read_bytes = res.unwrap(); +//! assert_eq!(read_bytes, 4); +//! assert_eq!(read_buf[0], 12); //! } //! //! // Delete the stored data @@ -46,21 +47,21 @@ //! //! // Get a free element in the pool with an appropriate size //! { -//! let res = local_pool.free_element(12); +//! let res = local_pool.free_element(12, |buf| { +//! buf[0] = 7; +//! }); //! assert!(res.is_ok()); -//! let (tmp, mut_buf) = res.unwrap(); -//! addr = tmp; -//! mut_buf[0] = 7; +//! addr = res.unwrap(); //! } //! //! // Read back the data //! { //! // Read the store data back -//! let res = local_pool.read(&addr); +//! let res = local_pool.read(&addr, &mut read_buf); //! assert!(res.is_ok()); -//! let buf_read_back = res.unwrap(); -//! assert_eq!(buf_read_back.len(), 12); -//! assert_eq!(buf_read_back[0], 7); +//! let read_bytes = res.unwrap(); +//! assert_eq!(read_bytes, 12); +//! assert_eq!(read_buf[0], 7); //! } //! ``` #[cfg(feature = "alloc")] @@ -70,6 +71,7 @@ use core::fmt::{Display, Formatter}; use delegate::delegate; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use spacepackets::ByteConversionError; #[cfg(feature = "std")] use std::error::Error; @@ -151,6 +153,8 @@ pub enum StoreError { InvalidStoreId(StoreIdError, Option), /// Valid subpool and packet index, but no data is stored at the given address DataDoesNotExist(StoreAddr), + ByteConversionError(spacepackets::ByteConversionError), + LockError, /// Internal or configuration errors InternalError(u32), } @@ -173,10 +177,22 @@ impl Display for StoreError { StoreError::InternalError(e) => { write!(f, "internal error: {e}") } + StoreError::ByteConversionError(e) => { + write!(f, "store error: {e}") + } + StoreError::LockError => { + write!(f, "lock error") + } } } } +impl From for StoreError { + fn from(value: ByteConversionError) -> Self { + Self::ByteConversionError(value) + } +} + #[cfg(feature = "std")] impl Error for StoreError { fn source(&self) -> Option<&(dyn Error + 'static)> { @@ -189,39 +205,54 @@ impl Error for StoreError { /// Generic trait for pool providers where the data can be modified and read in-place. This /// generally means that a shared pool structure has to be wrapped inside a lock structure. -pub trait PoolProviderMemInPlace { +pub trait PoolProvider { /// Add new data to the pool. The provider should attempt to reserve a memory block with the /// appropriate size and then copy the given data to the block. Yields a [StoreAddr] which can /// be used to access the data stored in the pool fn add(&mut self, data: &[u8]) -> Result; - /// The provider should attempt to reserve a free memory block with the appropriate size and - /// then return a mutable reference to it. Yields a [StoreAddr] which can be used to access - /// the data stored in the pool - fn free_element(&mut self, len: usize) -> Result<(StoreAddr, &mut [u8]), StoreError>; + /// The provider should attempt to reserve a free memory block with the appropriate size first. + /// It then executes a user-provided closure and passes a mutable reference to that memory + /// block to the closure. This allows the user to write data to the memory block. + /// The function should yield a [StoreAddr] which can be used to access the data stored in the + /// pool. + fn free_element( + &mut self, + len: usize, + writer: W, + ) -> Result; - /// Modify data added previously using a given [StoreAddr] by yielding a mutable reference - /// to it - fn modify(&mut self, addr: &StoreAddr) -> Result<&mut [u8], StoreError>; + /// Modify data added previously using a given [StoreAddr]. The provider should use the store + /// address to determine if a memory block exists for that address. If it does, it should + /// call the user-provided closure and pass a mutable reference to the memory block + /// to the closure. This allows the user to modify the memory block. + fn modify( + &mut self, + addr: &StoreAddr, + updater: U, + ) -> Result<(), StoreError>; - /// Read data by yielding a read-only reference given a [StoreAddr] - fn read(&self, addr: &StoreAddr) -> Result<&[u8], StoreError>; + /// The provider should copy the data from the memory block to the user-provided buffer if + /// it exists. + fn read(&self, addr: &StoreAddr, buf: &mut [u8]) -> Result; - /// Delete data inside the pool given a [StoreAddr] + /// Delete data inside the pool given a [StoreAddr]. fn delete(&mut self, addr: StoreAddr) -> Result<(), StoreError>; fn has_element_at(&self, addr: &StoreAddr) -> Result; /// Retrieve the length of the data at the given store address. - fn len_of_data(&self, addr: &StoreAddr) -> Result { - if !self.has_element_at(addr)? { - return Err(StoreError::DataDoesNotExist(*addr)); - } - Ok(self.read(addr)?.len()) + fn len_of_data(&self, addr: &StoreAddr) -> Result; + + #[cfg(feature = "alloc")] + fn read_as_vec(&self, addr: &StoreAddr) -> Result, StoreError> { + let mut vec = alloc::vec![0; self.len_of_data(addr)?]; + self.read(addr, &mut vec)?; + Ok(vec) } } -pub trait PoolProviderMemInPlaceWithGuards: PoolProviderMemInPlace { - /// This function behaves like [PoolProviderMemInPlace::read], but consumes the provided address +pub trait PoolProviderWithGuards: PoolProvider { + /// This function behaves like [PoolProvider::read], but consumes the provided address /// and returns a RAII conformant guard object. /// /// Unless the guard [PoolRwGuard::release] method is called, the data for the @@ -231,7 +262,7 @@ pub trait PoolProviderMemInPlaceWithGuards: PoolProviderMemInPlace { /// manual deletion is necessary when returning from a processing function prematurely. fn read_with_guard(&mut self, addr: StoreAddr) -> PoolGuard; - /// This function behaves like [PoolProviderMemInPlace::modify], but consumes the provided + /// This function behaves like [PoolProvider::modify], but consumes the provided /// address and returns a RAII conformant guard object. /// /// Unless the guard [PoolRwGuard::release] method is called, the data for the @@ -242,7 +273,7 @@ pub trait PoolProviderMemInPlaceWithGuards: PoolProviderMemInPlace { fn modify_with_guard(&mut self, addr: StoreAddr) -> PoolRwGuard; } -pub struct PoolGuard<'a, MemProvider: PoolProviderMemInPlace + ?Sized> { +pub struct PoolGuard<'a, MemProvider: PoolProvider + ?Sized> { pool: &'a mut MemProvider, pub addr: StoreAddr, no_deletion: bool, @@ -250,7 +281,7 @@ pub struct PoolGuard<'a, MemProvider: PoolProviderMemInPlace + ?Sized> { } /// This helper object -impl<'a, MemProvider: PoolProviderMemInPlace> PoolGuard<'a, MemProvider> { +impl<'a, MemProvider: PoolProvider> PoolGuard<'a, MemProvider> { pub fn new(pool: &'a mut MemProvider, addr: StoreAddr) -> Self { Self { pool, @@ -260,8 +291,13 @@ impl<'a, MemProvider: PoolProviderMemInPlace> PoolGuard<'a, MemProvider> { } } - pub fn read(&self) -> Result<&[u8], StoreError> { - self.pool.read(&self.addr) + pub fn read(&self, buf: &mut [u8]) -> Result { + self.pool.read(&self.addr, buf) + } + + #[cfg(feature = "alloc")] + pub fn read_as_vec(&self) -> Result, StoreError> { + self.pool.read_as_vec(&self.addr) } /// Releasing the pool guard will disable the automatic deletion of the data when the guard @@ -271,7 +307,7 @@ impl<'a, MemProvider: PoolProviderMemInPlace> PoolGuard<'a, MemProvider> { } } -impl Drop for PoolGuard<'_, MemProvider> { +impl Drop for PoolGuard<'_, MemProvider> { fn drop(&mut self) { if !self.no_deletion { if let Err(e) = self.pool.delete(self.addr) { @@ -281,24 +317,24 @@ impl Drop for PoolGuard<'_, MemPro } } -pub struct PoolRwGuard<'a, MemProvider: PoolProviderMemInPlace + ?Sized> { +pub struct PoolRwGuard<'a, MemProvider: PoolProvider + ?Sized> { guard: PoolGuard<'a, MemProvider>, } -impl<'a, MemProvider: PoolProviderMemInPlace> PoolRwGuard<'a, MemProvider> { +impl<'a, MemProvider: PoolProvider> PoolRwGuard<'a, MemProvider> { pub fn new(pool: &'a mut MemProvider, addr: StoreAddr) -> Self { Self { guard: PoolGuard::new(pool, addr), } } - pub fn modify(&mut self) -> Result<&mut [u8], StoreError> { - self.guard.pool.modify(&self.guard.addr) + pub fn update(&mut self, updater: &mut U) -> Result<(), StoreError> { + self.guard.pool.modify(&self.guard.addr, updater) } delegate!( to self.guard { - pub fn read(&self) -> Result<&[u8], StoreError>; + pub fn read(&self, buf: &mut [u8]) -> Result; /// Releasing the pool guard will disable the automatic deletion of the data when the guard /// is dropped. pub fn release(&mut self); @@ -308,13 +344,11 @@ impl<'a, MemProvider: PoolProviderMemInPlace> PoolRwGuard<'a, MemProvider> { #[cfg(feature = "alloc")] mod alloc_mod { - use super::{ - PoolGuard, PoolProviderMemInPlace, PoolProviderMemInPlaceWithGuards, PoolRwGuard, - StaticPoolAddr, - }; + use super::{PoolGuard, PoolProvider, PoolProviderWithGuards, PoolRwGuard, StaticPoolAddr}; use crate::pool::{NumBlocks, StoreAddr, StoreError, StoreIdError}; use alloc::vec; use alloc::vec::Vec; + use spacepackets::ByteConversionError; #[cfg(feature = "std")] use std::sync::{Arc, RwLock}; @@ -476,7 +510,7 @@ mod alloc_mod { } } - impl PoolProviderMemInPlace for StaticMemoryPool { + impl PoolProvider for StaticMemoryPool { fn add(&mut self, data: &[u8]) -> Result { let data_len = data.len(); if data_len > POOL_MAX_SIZE { @@ -487,7 +521,11 @@ mod alloc_mod { Ok(addr.into()) } - fn free_element(&mut self, len: usize) -> Result<(StoreAddr, &mut [u8]), StoreError> { + fn free_element( + &mut self, + len: usize, + mut writer: W, + ) -> Result { if len > POOL_MAX_SIZE { return Err(StoreError::DataTooLarge(len)); } @@ -495,25 +533,40 @@ mod alloc_mod { let raw_pos = self.raw_pos(&addr).unwrap(); let block = &mut self.pool.get_mut(addr.pool_idx as usize).unwrap()[raw_pos..raw_pos + len]; - Ok((addr.into(), block)) + writer(block); + Ok(addr.into()) } - fn modify(&mut self, addr: &StoreAddr) -> Result<&mut [u8], StoreError> { + fn modify( + &mut self, + addr: &StoreAddr, + mut updater: U, + ) -> Result<(), StoreError> { let addr = StaticPoolAddr::from(*addr); let curr_size = self.addr_check(&addr)?; let raw_pos = self.raw_pos(&addr).unwrap(); let block = &mut self.pool.get_mut(addr.pool_idx as usize).unwrap() [raw_pos..raw_pos + curr_size]; - Ok(block) + updater(block); + Ok(()) } - fn read(&self, addr: &StoreAddr) -> Result<&[u8], StoreError> { + fn read(&self, addr: &StoreAddr, buf: &mut [u8]) -> Result { let addr = StaticPoolAddr::from(*addr); let curr_size = self.addr_check(&addr)?; + if buf.len() < curr_size { + return Err(ByteConversionError::ToSliceTooSmall { + found: buf.len(), + expected: curr_size, + } + .into()); + } let raw_pos = self.raw_pos(&addr).unwrap(); let block = &self.pool.get(addr.pool_idx as usize).unwrap()[raw_pos..raw_pos + curr_size]; - Ok(block) + //block.copy_from_slice(&src); + buf[..curr_size].copy_from_slice(block); + Ok(curr_size) } fn delete(&mut self, addr: StoreAddr) -> Result<(), StoreError> { @@ -540,9 +593,21 @@ mod alloc_mod { } Ok(true) } + + fn len_of_data(&self, addr: &StoreAddr) -> Result { + let addr = StaticPoolAddr::from(*addr); + self.validate_addr(&addr)?; + let pool_idx = addr.pool_idx as usize; + let size_list = self.sizes_lists.get(pool_idx).unwrap(); + let size = size_list[addr.packet_idx as usize]; + Ok(match size { + STORE_FREE => 0, + _ => size, + }) + } } - impl PoolProviderMemInPlaceWithGuards for StaticMemoryPool { + impl PoolProviderWithGuards for StaticMemoryPool { fn modify_with_guard(&mut self, addr: StoreAddr) -> PoolRwGuard { PoolRwGuard::new(self, addr) } @@ -556,9 +621,8 @@ mod alloc_mod { #[cfg(test)] mod tests { use crate::pool::{ - PoolGuard, PoolProviderMemInPlace, PoolProviderMemInPlaceWithGuards, PoolRwGuard, - StaticMemoryPool, StaticPoolAddr, StaticPoolConfig, StoreError, StoreIdError, - POOL_MAX_SIZE, + PoolGuard, PoolProvider, PoolProviderWithGuards, PoolRwGuard, StaticMemoryPool, + StaticPoolAddr, StaticPoolConfig, StoreError, StoreIdError, POOL_MAX_SIZE, }; use std::vec; @@ -594,13 +658,14 @@ mod tests { for (i, val) in test_buf.iter_mut().enumerate() { *val = i as u8; } + let mut other_buf: [u8; 16] = [0; 16]; let addr = local_pool.add(&test_buf).expect("Adding data failed"); // Read back data and verify correctness - let res = local_pool.read(&addr); + let res = local_pool.read(&addr, &mut other_buf); assert!(res.is_ok()); - let buf_read_back = res.unwrap(); - assert_eq!(buf_read_back.len(), 16); - for (i, &val) in buf_read_back.iter().enumerate() { + let read_len = res.unwrap(); + assert_eq!(read_len, 16); + for (i, &val) in other_buf.iter().enumerate() { assert_eq!(val, i as u8); } } @@ -610,8 +675,10 @@ mod tests { let mut local_pool = basic_small_pool(); let test_buf: [u8; 12] = [0; 12]; let addr = local_pool.add(&test_buf).expect("Adding data failed"); - let res = local_pool.read(&addr).expect("Read back failed"); - assert_eq!(res.len(), 12); + let res = local_pool + .read(&addr, &mut [0; 12]) + .expect("Read back failed"); + assert_eq!(res, 12); } #[test] @@ -622,10 +689,13 @@ mod tests { // Delete the data let res = local_pool.delete(addr); assert!(res.is_ok()); + let mut writer = |buf: &mut [u8]| { + assert_eq!(buf.len(), 12); + }; // Verify that the slot is free by trying to get a reference to it - let res = local_pool.free_element(12); + let res = local_pool.free_element(12, &mut writer); assert!(res.is_ok()); - let (addr, buf_ref) = res.unwrap(); + let addr = res.unwrap(); assert_eq!( addr, u64::from(StaticPoolAddr { @@ -633,7 +703,6 @@ mod tests { packet_idx: 0 }) ); - assert_eq!(buf_ref.len(), 12); } #[test] @@ -647,29 +716,34 @@ mod tests { { // Verify that the slot is free by trying to get a reference to it - let res = local_pool.modify(&addr).expect("Modifying data failed"); - res[0] = 0; - res[1] = 0x42; + local_pool + .modify(&addr, &mut |buf: &mut [u8]| { + buf[0] = 0; + buf[1] = 0x42; + }) + .expect("Modifying data failed"); } - let res = local_pool.read(&addr).expect("Reading back data failed"); - assert_eq!(res[0], 0); - assert_eq!(res[1], 0x42); - assert_eq!(res[2], 2); - assert_eq!(res[3], 3); + local_pool + .read(&addr, &mut test_buf) + .expect("Reading back data failed"); + assert_eq!(test_buf[0], 0); + assert_eq!(test_buf[1], 0x42); + assert_eq!(test_buf[2], 2); + assert_eq!(test_buf[3], 3); } #[test] fn test_consecutive_reservation() { let mut local_pool = basic_small_pool(); // Reserve two smaller blocks consecutively and verify that the third reservation fails - let res = local_pool.free_element(8); + let res = local_pool.free_element(8, |_| {}); assert!(res.is_ok()); - let (addr0, _) = res.unwrap(); - let res = local_pool.free_element(8); + let addr0 = res.unwrap(); + let res = local_pool.free_element(8, |_| {}); assert!(res.is_ok()); - let (addr1, _) = res.unwrap(); - let res = local_pool.free_element(8); + let addr1 = res.unwrap(); + let res = local_pool.free_element(8, |_| {}); assert!(res.is_err()); let err = res.unwrap_err(); assert_eq!(err, StoreError::StoreFull(1)); @@ -689,6 +763,7 @@ mod tests { pool_idx: 0, } .into(), + &mut [], ); assert!(res.is_err()); assert!(matches!( @@ -720,7 +795,7 @@ mod tests { packet_idx: 0, } .into(); - let res = local_pool.read(&addr); + let res = local_pool.read(&addr, &mut []); assert!(res.is_err()); let err = res.unwrap_err(); assert!(matches!( @@ -737,7 +812,7 @@ mod tests { packet_idx: 1, }; assert_eq!(addr.raw(), 0x00020001); - let res = local_pool.read(&addr.into()); + let res = local_pool.read(&addr.into(), &mut []); assert!(res.is_err()); let err = res.unwrap_err(); assert!(matches!( @@ -759,7 +834,7 @@ mod tests { #[test] fn test_data_too_large_1() { let mut local_pool = basic_small_pool(); - let res = local_pool.free_element(POOL_MAX_SIZE + 1); + let res = local_pool.free_element(POOL_MAX_SIZE + 1, |_| {}); assert!(res.is_err()); assert_eq!( res.unwrap_err(), @@ -771,7 +846,7 @@ mod tests { fn test_free_element_too_large() { let mut local_pool = basic_small_pool(); // Try to request a slot which is too large - let res = local_pool.free_element(20); + let res = local_pool.free_element(20, |_| {}); assert!(res.is_err()); assert_eq!(res.unwrap_err(), StoreError::DataTooLarge(20)); } @@ -813,7 +888,7 @@ mod tests { let test_buf: [u8; 16] = [0; 16]; let addr = local_pool.add(&test_buf).expect("Adding data failed"); let mut rw_guard = PoolRwGuard::new(&mut local_pool, addr); - let _ = rw_guard.modify().expect("modify failed"); + rw_guard.update(&mut |_| {}).expect("modify failed"); drop(rw_guard); assert!(!local_pool.has_element_at(&addr).expect("Invalid address")); } @@ -824,7 +899,7 @@ mod tests { let test_buf: [u8; 16] = [0; 16]; let addr = local_pool.add(&test_buf).expect("Adding data failed"); let mut rw_guard = local_pool.modify_with_guard(addr); - let _ = rw_guard.modify().expect("modify failed"); + rw_guard.update(&mut |_| {}).expect("modify failed"); drop(rw_guard); assert!(!local_pool.has_element_at(&addr).expect("Invalid address")); } @@ -840,13 +915,25 @@ mod tests { let addr1 = local_pool.add(&test_buf_1).expect("Adding data failed"); let addr2 = local_pool.add(&test_buf_2).expect("Adding data failed"); let addr3 = local_pool.add(&test_buf_3).expect("Adding data failed"); - let tm0_raw = local_pool.modify(&addr0).expect("Modifying data failed"); - assert_eq!(tm0_raw, test_buf_0); - let tm1_raw = local_pool.modify(&addr1).expect("Modifying data failed"); - assert_eq!(tm1_raw, test_buf_1); - let tm2_raw = local_pool.modify(&addr2).expect("Modifying data failed"); - assert_eq!(tm2_raw, test_buf_2); - let tm3_raw = local_pool.modify(&addr3).expect("Modifying data failed"); - assert_eq!(tm3_raw, test_buf_3); + local_pool + .modify(&addr0, |buf| { + assert_eq!(buf, test_buf_0); + }) + .expect("Modifying data failed"); + local_pool + .modify(&addr1, |buf| { + assert_eq!(buf, test_buf_1); + }) + .expect("Modifying data failed"); + local_pool + .modify(&addr2, |buf| { + assert_eq!(buf, test_buf_2); + }) + .expect("Modifying data failed"); + local_pool + .modify(&addr3, |buf| { + assert_eq!(buf, test_buf_3); + }) + .expect("Modifying data failed"); } } diff --git a/satrs-core/src/pus/mod.rs b/satrs-core/src/pus/mod.rs index 64a78ce..5a21d95 100644 --- a/satrs-core/src/pus/mod.rs +++ b/satrs-core/src/pus/mod.rs @@ -390,7 +390,7 @@ mod alloc_mod { #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] pub mod std_mod { - use crate::pool::{PoolProviderMemInPlaceWithGuards, SharedStaticMemoryPool, StoreAddr}; + use crate::pool::{PoolProvider, PoolProviderWithGuards, SharedStaticMemoryPool, StoreAddr}; use crate::pus::verification::{ StdVerifReporterWithSender, TcStateAccepted, VerificationToken, }; @@ -789,12 +789,15 @@ pub mod std_mod { .shared_tc_store .write() .map_err(|_| PusPacketHandlingError::EcssTmtc(EcssTmtcError::StoreLock))?; - let tc_guard = tc_pool.read_with_guard(addr); - let tc_raw = tc_guard.read().unwrap(); - if tc_raw.len() > self.pus_buf.len() { - return Err(PusPacketHandlingError::PusPacketTooLarge(tc_raw.len())); + let tc_size = tc_pool + .len_of_data(&addr) + .map_err(|e| PusPacketHandlingError::EcssTmtc(EcssTmtcError::Store(e)))?; + if tc_size > self.pus_buf.len() { + return Err(PusPacketHandlingError::PusPacketTooLarge(tc_size)); } - self.pus_buf[0..tc_raw.len()].copy_from_slice(tc_raw); + let tc_guard = tc_pool.read_with_guard(addr); + // TODO: Proper error handling. + tc_guard.read(&mut self.pus_buf[0..tc_size]).unwrap(); Ok(()) } } @@ -947,8 +950,7 @@ pub mod tests { use spacepackets::CcsdsPacket; use crate::pool::{ - PoolProviderMemInPlace, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig, - StoreAddr, + PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig, StoreAddr, }; use crate::pus::verification::RequestId; use crate::tmtc::tm_helper::SharedTmPool; @@ -1078,8 +1080,8 @@ pub mod tests { assert!(next_msg.is_ok()); let tm_addr = next_msg.unwrap(); let tm_pool = self.tm_pool.0.read().unwrap(); - let tm_raw = tm_pool.read(&tm_addr).unwrap(); - self.tm_buf[0..tm_raw.len()].copy_from_slice(tm_raw); + let tm_raw = tm_pool.read_as_vec(&tm_addr).unwrap(); + self.tm_buf[0..tm_raw.len()].copy_from_slice(&tm_raw); PusTmReader::new(&self.tm_buf, 7).unwrap().0 } @@ -1096,8 +1098,8 @@ pub mod tests { assert!(next_msg.is_ok()); let tm_addr = next_msg.unwrap(); let tm_pool = self.tm_pool.0.read().unwrap(); - let tm_raw = tm_pool.read(&tm_addr).unwrap(); - let tm = PusTmReader::new(tm_raw, 7).unwrap().0; + let tm_raw = tm_pool.read_as_vec(&tm_addr).unwrap(); + let tm = PusTmReader::new(&tm_raw, 7).unwrap().0; assert_eq!(PusPacket::service(&tm), 1); assert_eq!(PusPacket::subservice(&tm), subservice); assert_eq!(tm.apid(), TEST_APID); diff --git a/satrs-core/src/pus/scheduler.rs b/satrs-core/src/pus/scheduler.rs index 549c8cd..b05dca8 100644 --- a/satrs-core/src/pus/scheduler.rs +++ b/satrs-core/src/pus/scheduler.rs @@ -16,7 +16,7 @@ use spacepackets::{ByteConversionError, CcsdsPacket}; #[cfg(feature = "std")] use std::error::Error; -use crate::pool::{PoolProviderMemInPlace, StoreError}; +use crate::pool::{PoolProvider, StoreError}; #[cfg(feature = "alloc")] pub use alloc_mod::*; @@ -241,10 +241,7 @@ impl Error for ScheduleError { pub trait PusSchedulerInterface { type TimeProvider: CcsdsTimeProvider + TimeReader; - fn reset( - &mut self, - store: &mut (impl PoolProviderMemInPlace + ?Sized), - ) -> Result<(), StoreError>; + fn reset(&mut self, store: &mut (impl PoolProvider + ?Sized)) -> Result<(), StoreError>; fn is_enabled(&self) -> bool; @@ -267,7 +264,7 @@ pub trait PusSchedulerInterface { fn insert_wrapped_tc( &mut self, pus_tc: &(impl IsPusTelecommand + PusPacket + GenericPusTcSecondaryHeader), - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { if PusPacket::service(pus_tc) != 11 { return Err(ScheduleError::WrongService(PusPacket::service(pus_tc))); @@ -293,7 +290,7 @@ pub trait PusSchedulerInterface { &mut self, time_stamp: UnixTimestamp, tc: &[u8], - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { let check_tc = PusTcReader::new(tc)?; if PusPacket::service(&check_tc.0) == 11 && PusPacket::subservice(&check_tc.0) == 4 { @@ -343,7 +340,7 @@ pub fn generate_insert_telecommand_app_data( #[cfg(feature = "alloc")] pub mod alloc_mod { use super::*; - use crate::pool::{PoolProviderMemInPlace, StoreAddr, StoreError}; + use crate::pool::{PoolProvider, StoreAddr, StoreError}; use alloc::collections::btree_map::{Entry, Range}; use alloc::collections::BTreeMap; use alloc::vec; @@ -379,7 +376,7 @@ pub mod alloc_mod { /// This is the core data structure for scheduling PUS telecommands with [alloc] support. /// /// It is assumed that the actual telecommand data is stored in a separate TC pool offering - /// a [crate::pool::PoolProviderMemInPlace] API. This data structure just tracks the store + /// a [crate::pool::PoolProvider] API. This data structure just tracks the store /// addresses and their release times and offers a convenient API to insert and release /// telecommands and perform other functionality specified by the ECSS standard in section 6.11. /// The time is tracked as a [spacepackets::time::UnixTimestamp] but the only requirement to @@ -413,6 +410,8 @@ pub mod alloc_mod { /// * `time_margin` - This time margin is used when inserting new telecommands into the /// schedule. If the release time of a new telecommand is earlier than the time margin /// added to the current time, it will not be inserted into the schedule. + /// * `tc_buf_size` - Buffer for temporary storage of telecommand packets. This buffer + /// should be large enough to accomodate the largest expected TC packets. pub fn new(init_current_time: UnixTimestamp, time_margin: Duration) -> Self { PusScheduler { tc_map: Default::default(), @@ -476,7 +475,7 @@ pub mod alloc_mod { &mut self, time_stamp: UnixTimestamp, tc: &[u8], - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { let check_tc = PusTcReader::new(tc)?; if PusPacket::service(&check_tc.0) == 11 && PusPacket::subservice(&check_tc.0) == 4 { @@ -499,7 +498,7 @@ pub mod alloc_mod { pub fn insert_wrapped_tc_cds_short( &mut self, pus_tc: &PusTc, - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { self.insert_wrapped_tc::(pus_tc, pool) } @@ -509,7 +508,7 @@ pub mod alloc_mod { pub fn insert_wrapped_tc_cds_long( &mut self, pus_tc: &PusTc, - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { self.insert_wrapped_tc::>(pus_tc, pool) } @@ -525,7 +524,7 @@ pub mod alloc_mod { pub fn delete_by_time_filter( &mut self, time_window: TimeWindow, - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { let range = self.retrieve_by_time_filter(time_window); let mut del_packets = 0; @@ -555,7 +554,7 @@ pub mod alloc_mod { /// the last deletion will be supplied in addition to the number of deleted commands. pub fn delete_all( &mut self, - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { self.delete_by_time_filter(TimeWindow::::new_select_all(), pool) } @@ -613,7 +612,7 @@ pub mod alloc_mod { pub fn delete_by_request_id_and_from_pool( &mut self, req_id: &RequestId, - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> Result { if let DeletionResult::WithStoreDeletion(v) = self.delete_by_request_id_internal_with_store_deletion(req_id, pool) @@ -645,7 +644,7 @@ pub mod alloc_mod { fn delete_by_request_id_internal_with_store_deletion( &mut self, req_id: &RequestId, - pool: &mut (impl PoolProviderMemInPlace + ?Sized), + pool: &mut (impl PoolProvider + ?Sized), ) -> DeletionResult { let mut idx_found = None; for time_bucket in &mut self.tc_map { @@ -675,7 +674,8 @@ pub mod alloc_mod { /// Utility method which calls [Self::telecommands_to_release] and then calls a releaser /// closure for each telecommand which should be released. This function will also delete /// the telecommands from the holding store after calling the release closure if the user - /// returns [true] from the release closure. + /// returns [true] from the release closure. A buffer must be provided to hold the + /// telecommands for the release process. /// /// # Arguments /// @@ -685,18 +685,55 @@ pub mod alloc_mod { /// note that returning false might lead to memory leaks if the TC is not cleared from /// the store in some other way. /// * `tc_store` - The holding store of the telecommands. + /// * `tc_buf` - Buffer to hold each telecommand being released. + pub fn release_telecommands_with_buffer bool>( + &mut self, + releaser: R, + tc_store: &mut (impl PoolProvider + ?Sized), + tc_buf: &mut [u8], + ) -> Result { + self.release_telecommands_internal(releaser, tc_store, Some(tc_buf)) + } + + /// This functions is almost identical to [Self::release_telecommands_with_buffer] but does + /// not require a user provided TC buffer because it will always use the + /// [PoolProvider::read_as_vec] API to read the TC packets. + /// + /// However, this might also perform frequent allocations for all telecommands being + /// released. pub fn release_telecommands bool>( + &mut self, + releaser: R, + tc_store: &mut (impl PoolProvider + ?Sized), + ) -> Result { + self.release_telecommands_internal(releaser, tc_store, None) + } + + fn release_telecommands_internal bool>( &mut self, mut releaser: R, - tc_store: &mut (impl PoolProviderMemInPlace + ?Sized), + tc_store: &mut (impl PoolProvider + ?Sized), + mut tc_buf: Option<&mut [u8]>, ) -> Result { let tcs_to_release = self.telecommands_to_release(); let mut released_tcs = 0; let mut store_error = Ok(()); for tc in tcs_to_release { for info in tc.1 { - let tc = tc_store.read(&info.addr).map_err(|e| (released_tcs, e))?; - let should_delete = releaser(self.enabled, info, tc); + let should_delete = match tc_buf.as_mut() { + Some(buf) => { + tc_store + .read(&info.addr, buf) + .map_err(|e| (released_tcs, e))?; + releaser(self.enabled, info, buf) + } + None => { + let tc = tc_store + .read_as_vec(&info.addr) + .map_err(|e| (released_tcs, e))?; + releaser(self.enabled, info, &tc) + } + }; released_tcs += 1; if should_delete { let res = tc_store.delete(info.addr); @@ -721,16 +758,17 @@ pub mod alloc_mod { pub fn release_telecommands_no_deletion( &mut self, mut releaser: R, - tc_store: &(impl PoolProviderMemInPlace + ?Sized), + tc_store: &(impl PoolProvider + ?Sized), + tc_buf: &mut [u8], ) -> Result, (Vec, StoreError)> { let tcs_to_release = self.telecommands_to_release(); let mut released_tcs = Vec::new(); for tc in tcs_to_release { for info in tc.1 { - let tc = tc_store - .read(&info.addr) + tc_store + .read(&info.addr, tc_buf) .map_err(|e| (released_tcs.clone(), e))?; - releaser(self.is_enabled(), info, tc); + releaser(self.is_enabled(), info, tc_buf); released_tcs.push(*info); } } @@ -753,10 +791,7 @@ pub mod alloc_mod { /// The holding store for the telecommands needs to be passed so all the stored telecommands /// can be deleted to avoid a memory leak. If at last one deletion operation fails, the error /// will be returned but the method will still try to delete all the commands in the schedule. - fn reset( - &mut self, - store: &mut (impl PoolProviderMemInPlace + ?Sized), - ) -> Result<(), StoreError> { + fn reset(&mut self, store: &mut (impl PoolProvider + ?Sized)) -> Result<(), StoreError> { self.enabled = false; let mut deletion_ok = Ok(()); for tc_lists in &mut self.tc_map { @@ -814,8 +849,7 @@ pub mod alloc_mod { mod tests { use super::*; use crate::pool::{ - PoolProviderMemInPlace, StaticMemoryPool, StaticPoolAddr, StaticPoolConfig, StoreAddr, - StoreError, + PoolProvider, StaticMemoryPool, StaticPoolAddr, StaticPoolConfig, StoreAddr, StoreError, }; use alloc::collections::btree_map::Range; use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}; @@ -1088,8 +1122,9 @@ mod tests { // test 1: too early, no tcs scheduler.update_time(UnixTimestamp::new_only_seconds(99)); + let mut tc_buf: [u8; 128] = [0; 128]; scheduler - .release_telecommands(&mut test_closure_1, &mut pool) + .release_telecommands_with_buffer(&mut test_closure_1, &mut pool, &mut tc_buf) .expect("deletion failed"); // test 2: exact time stamp of tc, releases 1 tc @@ -1111,7 +1146,7 @@ mod tests { scheduler.update_time(UnixTimestamp::new_only_seconds(206)); released = scheduler - .release_telecommands(&mut test_closure_2, &mut pool) + .release_telecommands_with_buffer(&mut test_closure_2, &mut pool, &mut tc_buf) .expect("deletion failed"); assert_eq!(released, 1); // TC is deleted. @@ -1157,9 +1192,10 @@ mod tests { // test 1: too early, no tcs scheduler.update_time(UnixTimestamp::new_only_seconds(99)); + let mut tc_buf: [u8; 128] = [0; 128]; let mut released = scheduler - .release_telecommands(&mut test_closure, &mut pool) + .release_telecommands_with_buffer(&mut test_closure, &mut pool, &mut tc_buf) .expect("deletion failed"); assert_eq!(released, 0); @@ -1209,11 +1245,13 @@ mod tests { true }; + let mut tc_buf: [u8; 128] = [0; 128]; + // test 1: too early, no tcs scheduler.update_time(UnixTimestamp::new_only_seconds(99)); scheduler - .release_telecommands(&mut test_closure_1, &mut pool) + .release_telecommands_with_buffer(&mut test_closure_1, &mut pool, &mut tc_buf) .expect("deletion failed"); // test 2: exact time stamp of tc, releases 1 tc @@ -1267,8 +1305,9 @@ mod tests { assert!(pool.has_element_at(&tc_info_0.addr()).unwrap()); - let data = pool.read(&tc_info_0.addr()).unwrap(); - let check_tc = PusTcReader::new(data).expect("incorrect Pus tc raw data"); + let mut read_buf: [u8; 64] = [0; 64]; + pool.read(&tc_info_0.addr(), &mut read_buf).unwrap(); + let check_tc = PusTcReader::new(&read_buf).expect("incorrect Pus tc raw data"); assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, None)); assert_eq!(scheduler.num_scheduled_telecommands(), 1); @@ -1289,8 +1328,9 @@ mod tests { .release_telecommands(&mut test_closure, &mut pool) .unwrap(); - let data = pool.read(&addr_vec[0]).unwrap(); - let check_tc = PusTcReader::new(data).expect("incorrect Pus tc raw data"); + let read_len = pool.read(&addr_vec[0], &mut read_buf).unwrap(); + let check_tc = PusTcReader::new(&read_buf).expect("incorrect Pus tc raw data"); + assert_eq!(read_len, check_tc.1); assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, None)); } @@ -1313,8 +1353,9 @@ mod tests { assert!(pool.has_element_at(&info.addr).unwrap()); - let data = pool.read(&info.addr).unwrap(); - let check_tc = PusTcReader::new(data).expect("incorrect Pus tc raw data"); + let read_len = pool.read(&info.addr, &mut buf).unwrap(); + let check_tc = PusTcReader::new(&buf).expect("incorrect Pus tc raw data"); + assert_eq!(read_len, check_tc.1); assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, None)); assert_eq!(scheduler.num_scheduled_telecommands(), 1); @@ -1331,12 +1372,15 @@ mod tests { false }; + let mut tc_buf: [u8; 64] = [0; 64]; + scheduler - .release_telecommands(&mut test_closure, &mut pool) + .release_telecommands_with_buffer(&mut test_closure, &mut pool, &mut tc_buf) .unwrap(); - let data = pool.read(&addr_vec[0]).unwrap(); - let check_tc = PusTcReader::new(data).expect("incorrect PUS tc raw data"); + let read_len = pool.read(&addr_vec[0], &mut buf).unwrap(); + let check_tc = PusTcReader::new(&buf).expect("incorrect PUS tc raw data"); + assert_eq!(read_len, check_tc.1); assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, None)); } @@ -1903,8 +1947,9 @@ mod tests { scheduler.update_time(UnixTimestamp::new_only_seconds(205)); + let mut tc_buf: [u8; 64] = [0; 64]; let tc_info_vec = scheduler - .release_telecommands_no_deletion(&mut test_closure_1, &pool) + .release_telecommands_no_deletion(&mut test_closure_1, &pool, &mut tc_buf) .expect("deletion failed"); assert_eq!(tc_info_vec[0], tc_info_0); assert_eq!(tc_info_vec[1], tc_info_1); diff --git a/satrs-core/src/pus/scheduler_srv.rs b/satrs-core/src/pus/scheduler_srv.rs index 2225c03..3e9ab32 100644 --- a/satrs-core/src/pus/scheduler_srv.rs +++ b/satrs-core/src/pus/scheduler_srv.rs @@ -1,6 +1,6 @@ use super::scheduler::PusSchedulerInterface; use super::{EcssTcInMemConverter, PusServiceBase, PusServiceHelper}; -use crate::pool::PoolProviderMemInPlace; +use crate::pool::PoolProvider; use crate::pus::{PusPacketHandlerResult, PusPacketHandlingError}; use alloc::string::ToString; use spacepackets::ecss::{scheduling, PusPacket}; @@ -42,7 +42,7 @@ impl pub fn handle_one_tc( &mut self, - sched_tc_pool: &mut (impl PoolProviderMemInPlace + ?Sized), + sched_tc_pool: &mut (impl PoolProvider + ?Sized), ) -> Result { let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?; if possible_packet.is_none() { @@ -237,7 +237,7 @@ mod tests { fn reset( &mut self, - _store: &mut (impl crate::pool::PoolProviderMemInPlace + ?Sized), + _store: &mut (impl crate::pool::PoolProvider + ?Sized), ) -> Result<(), crate::pool::StoreError> { self.reset_count += 1; Ok(()) diff --git a/satrs-core/src/pus/verification.rs b/satrs-core/src/pus/verification.rs index ca7c272..36514f1 100644 --- a/satrs-core/src/pus/verification.rs +++ b/satrs-core/src/pus/verification.rs @@ -15,7 +15,7 @@ //! ``` //! use std::sync::{Arc, mpsc, RwLock}; //! use std::time::Duration; -//! use satrs_core::pool::{PoolProviderMemInPlaceWithGuards, StaticMemoryPool, StaticPoolConfig}; +//! use satrs_core::pool::{PoolProviderWithGuards, StaticMemoryPool, StaticPoolConfig}; //! use satrs_core::pus::verification::{VerificationReporterCfg, VerificationReporterWithSender}; //! use satrs_core::seq_count::SeqCountProviderSimple; //! use satrs_core::pus::MpscTmInSharedPoolSender; @@ -56,9 +56,7 @@ //! { //! let mut rg = tm_store.write().expect("Error locking shared pool"); //! let store_guard = rg.read_with_guard(addr); -//! let slice = store_guard.read().expect("Error reading TM slice"); -//! tm_len = slice.len(); -//! tm_buf[0..tm_len].copy_from_slice(slice); +//! tm_len = store_guard.read(&mut tm_buf).expect("Error reading TM slice"); //! } //! let (pus_tm, _) = PusTmReader::new(&tm_buf[0..tm_len], 7) //! .expect("Error reading verification TM"); @@ -1325,7 +1323,7 @@ mod std_mod { #[cfg(test)] mod tests { - use crate::pool::{PoolProviderMemInPlaceWithGuards, StaticMemoryPool, StaticPoolConfig}; + use crate::pool::{PoolProviderWithGuards, StaticMemoryPool, StaticPoolConfig}; use crate::pus::tests::CommonTmInfo; use crate::pus::verification::{ EcssTmSenderCore, EcssTmtcError, FailParams, FailParamsWithStep, RequestId, TcStateNone, @@ -1547,7 +1545,7 @@ mod tests { let mut sender = TestSender::default(); let fail_code = EcssEnumU16::new(2); let fail_params = FailParams::new(Some(stamp_buf.as_slice()), &fail_code, None); - b.vr.acceptance_failure(tok, &mut sender, fail_params) + b.vr.acceptance_failure(tok, &sender, fail_params) .expect("Sending acceptance success failed"); acceptance_fail_check(&mut sender, tok.req_id, stamp_buf); } @@ -1682,12 +1680,10 @@ mod tests { ); let accepted_token = - b.vr.acceptance_success(tok, &mut sender, Some(&EMPTY_STAMP)) + b.vr.acceptance_success(tok, &sender, Some(&EMPTY_STAMP)) .expect("Sending acceptance success failed"); - let empty = - b.vr.start_failure(accepted_token, &mut sender, fail_params) - .expect("Start failure failure"); - assert_eq!(empty, ()); + b.vr.start_failure(accepted_token, &mut sender, fail_params) + .expect("Start failure failure"); start_fail_check(&mut sender, tok.req_id, fail_data_raw); } @@ -1779,23 +1775,23 @@ mod tests { let mut sender = TestSender::default(); let accepted_token = b .rep() - .acceptance_success(tok, &mut sender, Some(&EMPTY_STAMP)) + .acceptance_success(tok, &sender, Some(&EMPTY_STAMP)) .expect("Sending acceptance success failed"); let started_token = b .rep() - .start_success(accepted_token, &mut sender, Some(&[0, 1, 0, 1, 0, 1, 0])) + .start_success(accepted_token, &sender, Some(&[0, 1, 0, 1, 0, 1, 0])) .expect("Sending start success failed"); b.rep() .step_success( &started_token, - &mut sender, + &sender, Some(&EMPTY_STAMP), EcssEnumU8::new(0), ) .expect("Sending step 0 success failed"); b.vr.step_success( &started_token, - &mut sender, + &sender, Some(&EMPTY_STAMP), EcssEnumU8::new(1), ) @@ -2176,9 +2172,9 @@ mod tests { { let mut rg = shared_tm_pool.write().expect("Error locking shared pool"); let store_guard = rg.read_with_guard(addr); - let slice = store_guard.read().expect("Error reading TM slice"); - tm_len = slice.len(); - tm_buf[0..tm_len].copy_from_slice(slice); + tm_len = store_guard + .read(&mut tm_buf) + .expect("Error reading TM slice"); } let (pus_tm, _) = PusTmReader::new(&tm_buf[0..tm_len], 7).expect("Error reading verification TM"); diff --git a/satrs-core/src/tmtc/tm_helper.rs b/satrs-core/src/tmtc/tm_helper.rs index c8a09a3..192d574 100644 --- a/satrs-core/src/tmtc/tm_helper.rs +++ b/satrs-core/src/tmtc/tm_helper.rs @@ -8,9 +8,7 @@ pub use std_mod::*; #[cfg(feature = "std")] pub mod std_mod { - use crate::pool::{ - PoolProviderMemInPlace, SharedStaticMemoryPool, StaticMemoryPool, StoreAddr, - }; + use crate::pool::{PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StoreAddr}; use crate::pus::EcssTmtcError; use spacepackets::ecss::tm::PusTmCreator; use spacepackets::ecss::WritablePusPacket; @@ -37,10 +35,11 @@ pub mod std_mod { pub fn add_pus_tm(&self, pus_tm: &PusTmCreator) -> Result { let mut pg = self.0.write().map_err(|_| EcssTmtcError::StoreLock)?; - let (addr, buf) = pg.free_element(pus_tm.len_written())?; - pus_tm - .write_to_bytes(buf) - .expect("writing PUS TM to store failed"); + let addr = pg.free_element(pus_tm.len_written(), |buf| { + pus_tm + .write_to_bytes(buf) + .expect("writing PUS TM to store failed"); + })?; Ok(addr) } } diff --git a/satrs-core/tests/pools.rs b/satrs-core/tests/pools.rs index cce2114..a091203 100644 --- a/satrs-core/tests/pools.rs +++ b/satrs-core/tests/pools.rs @@ -1,6 +1,4 @@ -use satrs_core::pool::{ - PoolGuard, PoolProviderMemInPlace, StaticMemoryPool, StaticPoolConfig, StoreAddr, -}; +use satrs_core::pool::{PoolGuard, PoolProvider, StaticMemoryPool, StaticPoolConfig, StoreAddr}; use std::ops::DerefMut; use std::sync::mpsc; use std::sync::mpsc::{Receiver, Sender}; @@ -27,8 +25,10 @@ fn threaded_usage() { addr = rx.recv().expect("Receiving store address failed"); let mut pool_access = shared_clone.write().unwrap(); let pg = PoolGuard::new(pool_access.deref_mut(), addr); - let read_res = pg.read().expect("Reading failed"); - assert_eq!(read_res, DUMMY_DATA); + let mut read_buf: [u8; 4] = [0; 4]; + let read_bytes = pg.read(&mut read_buf).expect("Reading failed"); + assert_eq!(read_buf, DUMMY_DATA); + assert_eq!(read_bytes, 4); } let pool_access = shared_clone.read().unwrap(); assert!(!pool_access.has_element_at(&addr).expect("Invalid address")); diff --git a/satrs-core/tests/pus_verification.rs b/satrs-core/tests/pus_verification.rs index 557a8b2..f299272 100644 --- a/satrs-core/tests/pus_verification.rs +++ b/satrs-core/tests/pus_verification.rs @@ -2,8 +2,7 @@ pub mod crossbeam_test { use hashbrown::HashMap; use satrs_core::pool::{ - PoolProviderMemInPlace, PoolProviderMemInPlaceWithGuards, StaticMemoryPool, - StaticPoolConfig, + PoolProvider, PoolProviderWithGuards, StaticMemoryPool, StaticPoolConfig, }; use satrs_core::pus::verification::{ FailParams, RequestId, VerificationReporterCfg, VerificationReporterWithSender, @@ -59,15 +58,21 @@ pub mod crossbeam_test { let tc_header = PusTcSecondaryHeader::new_simple(17, 1); let pus_tc_0 = PusTcCreator::new_no_app_data(&mut sph, tc_header, true); req_id_0 = RequestId::new(&pus_tc_0); - let (addr, buf) = tc_guard.free_element(pus_tc_0.len_written()).unwrap(); - pus_tc_0.write_to_bytes(buf).unwrap(); + let addr = tc_guard + .free_element(pus_tc_0.len_written(), |buf| { + pus_tc_0.write_to_bytes(buf).unwrap(); + }) + .unwrap(); tx_tc_0.send(addr).unwrap(); let mut sph = SpHeader::tc_unseg(TEST_APID, 1, 0).unwrap(); let tc_header = PusTcSecondaryHeader::new_simple(5, 1); let pus_tc_1 = PusTcCreator::new_no_app_data(&mut sph, tc_header, true); req_id_1 = RequestId::new(&pus_tc_1); - let (addr, buf) = tc_guard.free_element(pus_tc_0.len_written()).unwrap(); - pus_tc_1.write_to_bytes(buf).unwrap(); + let addr = tc_guard + .free_element(pus_tc_0.len_written(), |buf| { + pus_tc_1.write_to_bytes(buf).unwrap(); + }) + .unwrap(); tx_tc_1.send(addr).unwrap(); } let verif_sender_0 = thread::spawn(move || { @@ -79,9 +84,7 @@ pub mod crossbeam_test { { let mut tc_guard = shared_tc_pool_0.write().unwrap(); let pg = tc_guard.read_with_guard(tc_addr); - let buf = pg.read().unwrap(); - tc_len = buf.len(); - tc_buf[0..tc_len].copy_from_slice(buf); + tc_len = pg.read(&mut tc_buf).unwrap(); } let (_tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap(); @@ -117,9 +120,7 @@ pub mod crossbeam_test { { let mut tc_guard = shared_tc_pool_1.write().unwrap(); let pg = tc_guard.read_with_guard(tc_addr); - let buf = pg.read().unwrap(); - tc_len = buf.len(); - tc_buf[0..tc_len].copy_from_slice(buf); + tc_len = pg.read(&mut tc_buf).unwrap(); } let (tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap(); let token = reporter_with_sender_1.add_tc(&tc); @@ -149,9 +150,9 @@ pub mod crossbeam_test { { let mut rg = shared_tm_store.write().expect("Error locking shared pool"); let store_guard = rg.read_with_guard(verif_addr); - let slice = store_guard.read().expect("Error reading TM slice"); - tm_len = slice.len(); - tm_buf[0..tm_len].copy_from_slice(slice); + tm_len = store_guard + .read(&mut tm_buf) + .expect("Error reading TM slice"); } let (pus_tm, _) = PusTmReader::new(&tm_buf[0..tm_len], 7).expect("Error reading verification TM"); diff --git a/satrs-example/src/pus/scheduler.rs b/satrs-example/src/pus/scheduler.rs index 0842904..8ffe8df 100644 --- a/satrs-example/src/pus/scheduler.rs +++ b/satrs-example/src/pus/scheduler.rs @@ -2,7 +2,7 @@ use std::sync::mpsc; use std::time::Duration; use log::{error, info, warn}; -use satrs_core::pool::{PoolProviderMemInPlace, StaticMemoryPool, StoreAddr}; +use satrs_core::pool::{PoolProvider, StaticMemoryPool, StoreAddr}; use satrs_core::pus::scheduler::{PusScheduler, TcInfo}; use satrs_core::pus::scheduler_srv::PusService11SchedHandler; use satrs_core::pus::verification::VerificationReporterWithSender; @@ -54,6 +54,7 @@ impl TcReleaser for mpsc::Sender> { pub struct Pus11Wrapper { pub pus_11_handler: PusService11SchedHandler, pub sched_tc_pool: StaticMemoryPool, + pub releaser_buf: [u8; 4096], pub tc_releaser: Box, } @@ -70,7 +71,11 @@ impl Pus11Wrapper { let released_tcs = self .pus_11_handler .scheduler_mut() - .release_telecommands(releaser, &mut self.sched_tc_pool) + .release_telecommands_with_buffer( + releaser, + &mut self.sched_tc_pool, + &mut self.releaser_buf, + ) .expect("releasing TCs failed"); if released_tcs > 0 { info!("{released_tcs} TC(s) released from scheduler"); @@ -136,6 +141,7 @@ pub fn create_scheduler_service_static( Pus11Wrapper { pus_11_handler, sched_tc_pool, + releaser_buf: [0; 4096], tc_releaser: Box::new(tc_releaser), } } @@ -172,6 +178,7 @@ pub fn create_scheduler_service_dynamic( Pus11Wrapper { pus_11_handler, sched_tc_pool, + releaser_buf: [0; 4096], tc_releaser: Box::new(tc_source_sender), } } diff --git a/satrs-example/src/tm_funnel.rs b/satrs-example/src/tm_funnel.rs index 9069d72..5024e57 100644 --- a/satrs-example/src/tm_funnel.rs +++ b/satrs-example/src/tm_funnel.rs @@ -3,8 +3,9 @@ use std::{ sync::mpsc::{Receiver, Sender}, }; +use log::info; use satrs_core::{ - pool::{PoolProviderMemInPlace, StoreAddr}, + pool::{PoolProvider, StoreAddr}, seq_count::{CcsdsSimpleSeqCountProvider, SequenceCountProviderCore}, spacepackets::{ ecss::{tm::PusTmZeroCopyWriter, PusPacket}, @@ -63,9 +64,14 @@ impl TmFunnelCommon { *entry += 1; } + Self::packet_printout(&zero_copy_writer); // This operation has to come last! zero_copy_writer.finish(); } + + fn packet_printout(tm: &PusTmZeroCopyWriter) { + info!("Sending PUS TM[{},{}]", tm.service(), tm.subservice()); + } } pub struct TmFunnelStatic { @@ -96,16 +102,21 @@ impl TmFunnelStatic { // the CRC. let shared_pool = self.shared_tm_store.clone_backing_pool(); let mut pool_guard = shared_pool.write().expect("Locking TM pool failed"); - let tm_raw = pool_guard - .modify(&addr) + let mut tm_copy = Vec::new(); + pool_guard + .modify(&addr, |buf| { + let zero_copy_writer = PusTmZeroCopyWriter::new(buf, MIN_CDS_FIELD_LEN) + .expect("Creating TM zero copy writer failed"); + self.common.apply_packet_processing(zero_copy_writer); + tm_copy = buf.to_vec() + }) .expect("Reading TM from pool failed"); - let zero_copy_writer = PusTmZeroCopyWriter::new(tm_raw, MIN_CDS_FIELD_LEN) - .expect("Creating TM zero copy writer failed"); - self.common.apply_packet_processing(zero_copy_writer); self.tm_server_tx .send(addr) .expect("Sending TM to server failed"); - self.common.sync_tm_tcp_source.add_tm(tm_raw); + // We could also do this step in the update closure, but I'd rather avoid this, could + // lead to nested locking. + self.common.sync_tm_tcp_source.add_tm(&tm_copy); } } } diff --git a/satrs-example/src/tmtc.rs b/satrs-example/src/tmtc.rs index d173ac7..7ab891c 100644 --- a/satrs-example/src/tmtc.rs +++ b/satrs-example/src/tmtc.rs @@ -5,7 +5,7 @@ use std::sync::mpsc::{self, Receiver, SendError, Sender, TryRecvError}; use thiserror::Error; use crate::pus::PusReceiver; -use satrs_core::pool::{PoolProviderMemInPlace, SharedStaticMemoryPool, StoreAddr, StoreError}; +use satrs_core::pool::{PoolProvider, SharedStaticMemoryPool, StoreAddr, StoreError}; use satrs_core::spacepackets::ecss::tc::PusTcReader; use satrs_core::spacepackets::ecss::PusPacket; use satrs_core::tmtc::ReceivesCcsdsTc; @@ -28,8 +28,9 @@ pub struct SharedTcPool { impl SharedTcPool { pub fn add_pus_tc(&mut self, pus_tc: &PusTcReader) -> Result { let mut pg = self.pool.write().expect("error locking TC store"); - let (addr, buf) = pg.free_element(pus_tc.len_packed())?; - buf[0..pus_tc.len_packed()].copy_from_slice(pus_tc.raw_data()); + let addr = pg.free_element(pus_tc.len_packed(), |buf| { + buf[0..pus_tc.len_packed()].copy_from_slice(pus_tc.raw_data()); + })?; Ok(addr) } } @@ -125,8 +126,8 @@ impl TcSourceTaskStatic { .pool .read() .expect("locking tc pool failed"); - let data = pool.read(&addr).expect("reading pool failed"); - self.tc_buf[0..data.len()].copy_from_slice(data); + pool.read(&addr, &mut self.tc_buf) + .expect("reading pool failed"); drop(pool); match PusTcReader::new(&self.tc_buf) { Ok((pus_tc, _)) => { diff --git a/satrs-example/src/udp.rs b/satrs-example/src/udp.rs index 11f84b2..9e3faa8 100644 --- a/satrs-example/src/udp.rs +++ b/satrs-example/src/udp.rs @@ -6,7 +6,7 @@ use std::{ use log::{info, warn}; use satrs_core::{ hal::std::udp_server::{ReceiveResult, UdpTcServer}, - pool::{PoolProviderMemInPlaceWithGuards, SharedStaticMemoryPool, StoreAddr}, + pool::{PoolProviderWithGuards, SharedStaticMemoryPool, StoreAddr}, tmtc::CcsdsError, }; @@ -29,20 +29,13 @@ impl UdpTmHandler for StaticUdpTmHandler { } let mut store_lock = store_lock.unwrap(); let pg = store_lock.read_with_guard(addr); - let read_res = pg.read(); + let read_res = pg.read_as_vec(); if read_res.is_err() { warn!("Error reading TM pool data"); continue; } let buf = read_res.unwrap(); - if buf.len() > 9 { - let service = buf[7]; - let subservice = buf[8]; - info!("Sending PUS TM[{service},{subservice}]") - } else { - info!("Sending PUS TM"); - } - let result = socket.send_to(buf, recv_addr); + let result = socket.send_to(&buf, recv_addr); if let Err(e) = result { warn!("Sending TM with UDP socket failed: {e}") }