From 8b9fcc31c244816c31ecc035314dfb9e597dc98b Mon Sep 17 00:00:00 2001 From: Fenoglio Date: Wed, 12 Sep 2018 16:35:48 +0200 Subject: [PATCH] last changes --- SpeedclockNano.fzz | Bin 49392 -> 49783 bytes server_client.pptx | Bin 0 -> 36165 bytes speedclock.h | 78 +++---- speedclock.ino | 505 +++++++++++++++++++++++++++------------------ 4 files changed, 349 insertions(+), 234 deletions(-) create mode 100644 server_client.pptx diff --git a/SpeedclockNano.fzz b/SpeedclockNano.fzz index 9f54bdad57ee81a034d1be02c56864e3911c0ed6..5dca05ac13c839957b591f60b14bdcdcc04b003f 100644 GIT binary patch delta 26183 zcmagFbx<8m^eq}B0fI|#cXxMpC&As_{Q!fzySoO5;O-8=-6gnduuH!8dv)Kdx>fg| zRqL$X-7{xux_YnfJ(qqE4}lOhTTloj!GC2%8NJnaj6Z$)QI&8Gg$ZPx#N!Ml{pnKZ zZ-)rRp&3IKcimt}+=CA-;wvH-LAK>KLE$<*u&y(&%8DB`$XqG!9EWob7&UHI5Lx@wmAts)(?!#7)&BB z+A4bb@uFfBz38gTfv1*S>@kXfksuIDYn%6Tzt7+9x91lx?sT1v5Q#CfFK^>|dOlZs z6Cp<&1u?tJCszYr&d>LrFRwQY?>l$>Xm;1XO`%6zRfhQYh zAHK$tj*cb<-KD-$nZ1#%zCFjc^9TxT2dbjhW)Eg}j_h`Cj`y7~!T43+zO3HS*Nleb z<;9lWn+Ioo4e^}Z)p|`^+o6)-Zs6PgsE^seprz;>*MiYNp@;IT;dW(!702&sEuKuX z`mu+E)uRLfegN>iUj$jL)xU#y@N`~YPX}&yUMC)1eE@U>E)ZX5+T@UkRriy%rw+dj zP|byjgU3T}vJ<**l&bz4%`BH|rSh|9(1W*od+dzZntBzuDBuwBuo+dBgKQ=sA4# zvJ`OV_hG@&i3Dz060S#K-Xd5oT%3icjG?%`)|=UDm|BbZ6jW4sUEiPyue=8B&O!cT$MPYR&}6wqOhqXLajFrU-k4r6bg(%wO5 zzIRr3Vckivc8XrB4B4EXRXCK7) ziu95xM(1(f=L*FdB2{1pUKYe^i6c)UgKUC6#jrwhbtBRI(Rk0AWGD1c)g^eYP7?%< zdzuPXsh)2wuTL)2s?nrKX{ymcIFI~mq@C&7t7Ap&SNZmRNx17ewApy7RmBstqSYh< zh+V%@F%_z;(o@FF5dSKfUlo+@NNfue4MgY#>x%}(uJZTBY^<+W71w9LGP7gJ&R7Cb!0DS)h>mK zQG&`!Ig)hDzXk7v;uu9Wx^xfN{VlmRdgE%z$!sH=@w)fX_Cg_I^_u(rik`ZXl-8yn zVFtXOA0PWzUy#|V`p^=L_%uI07~7kqkh~3&y1v<`Bs}vxzrF+BFAkRv zS3{#6=Cipp1)HvkpSvqNyk*U5Em}S1^siF16zTEppHB$x%dOwIL7^x(L$6g30s>la zR^=A1J|`hY&R2U7^jcFlLK>)TL0e0a^XiV$^k@UuhNSRj!Qth4hbwpq>Bo3Z5%zzn*GT)~Z#wvn zE0TLoo2$`t>;yR1qrO?`$QqNw)VY4WNo6VA53sF#OU9-jK28en3pxg>mqwE;D_oO< z1Iy?6l~Zfc=`~CjMbXMH<<2~Ny;Xo4XSMt)?Un^WX;hUCPnb=&r}G0XgcLi6?|g2e zcYBvDO^?3|&ci^_<@jwTqOdZvj(q54U{z;}0D5J<)U zQ!$&CwiUz8G8)9d|D$cCe)+lL{j2f0*OJCnsY%f0DIL2OO|?ScxrRsIx5T_8m&JihBayZ+ApmofbYb>!V@k!^|QN=-5InIo< z8P#Wp|I`P%X*#v5%!sANsraDqj61XB4x!=aD7MB@mpQV=t z9rah7?*!YR5r63mu0+T-$rJWvFgS!RVJ0K>lFu8?=K&i0`{d8=3CJT(jKpqD+S?iQYwphx+rwN=`L$}coREMjeeU*s!Uo8N$p5-8>xiSc=B~RL)BV-`J*m+`U0c`S_$S}>zN}m&Y6T{ZO=K59oweS{pq%|Khht&4HpVMLBP23Ep0?u> zim^h1$OF{xcF7Q$;%W);*d4*gJqlV0Tu08!^+W=j`27JtiYx|`qh-4%HCl-kSQ?#; zV_UR5Q$%e-)ar2BkA=RQ{3tcGK7#(0y zs^B^Y)PnxKokoaS?Nkd<`oHl>DJgsK@w(nZ>zUTW2pS{8VBFW|Do{<*JY!RHOHTvK z+ERhk8e2;#e7x=F(0YfNFwqu#QZmY)L{voV@#Ly%BW5lLO4t0c0n)+tM=9N{momI7 zBR!#-++2)e70!-=-ChsE*{Y(FjeaINh^czh1n?o9Ri!c3!1Uzjg9{Y=WzCiozbBe> z5-l1xdPX2+%{*QHM{V30!^&Om%eSn!$|Rr-Ke3CLNuK??_8t58Ols24S5aiY1QP|v zAFB#HaacO@cuDam4KwFcDgw0&2( zsrY$Z90@F*4~12mmqgO7zj9uEdv$h<8xvTItg6=2U3Ho&UL-if%8oe~$3W$Ych3MU z#Ip7{x#OSmdB+%bM_Ygvw*sz0JQw$_XZ{F;Y232+CqU2U#gxeL+@sf>OGKm{7d?~` z&+y7F?2^^KscZ{p; z2p<@@C;1DHCYZ?1T5bk{+d)9S`VUahw7NO>Q=OmNJ&3ViL_y8=-Pjbw`n>bHxZ4y` z^J>f8k|nS=snmYr^|ETr%X9d900vrFnwbkfUU4NV*InRFBKz#7{#CCW`lqA|{R%~6hyw3UWLQZ7Qdx=77eD6UKyfk1?Q0+;`96i8 z7$X$hI8x71u`HH-wbwXQy!gS7Ict@4UF^)dX>Q@cfyZp0I#S+6X2Nf0(a_I!@jCz1 z>U^abZ#sI88UjB(uLY`ZY3ir7SsI?;$|e`@U9{?Lly?GT*453au-PDfLnu#^RdUtN z%^t6%?MUl@o9ejW1rO*WlL7vvGW3HFX5YG&pq>x#j&jcHgZ5lNb>Tnmi8#I-D3^Fp zj!~59Xkh0oUo@ZbeJ6N*e?878L7GNbA;_BgO7gR`+-kRTM{Tj7>7nZPgllt4pYEIG zMe9RA#>k!bbXxcdpm2(N`_k1+xaR%xYwKjF7v7b>uDElJ?G?v44mf4rE#_ir`A(1% zpSlA3`?HhX>G78NbBK27qht^c`cMc`Kc_#Vin!Hhg=!MXD~bq*Kt{h8gLA)u=)~hI zTp~#1XS><|tll$eItisc3o z1Lj7V1C1VX_8vLMlYtEO2}Hv68PhDr2l`OjAExw}Qu!0%Snj{rXK8EMVI400iR4)C zgm%%@?**8cHGi0rr6Zt3Q9`27y$(nl-4(`L1Rwi?7^Y?}!pumf{Szdn&))E~9Yq4L z$G&0G$pjvogXsH}FZvG(21R*FKW)!5(rBuI&tKi^Iu&jDj04}@!?@W8WDU2!VXA-U zRNf%jSI2M=r!o$NYcni*`6*{_(%Wxa=IdfMhwO48=nRiltx;mn! zhy1W6w~pAh>>8l_lac>*Zi(=_(E5ca_r>xhN{geCOy`#G}0!yWeua+1IW-M@!I z`EX8pZ=ozZD1+?<;n2ow^y=Re41|Ly3i6>@7A4SGHN=58R1PjS)agkZ59T_pgN@Vb zvvIsL-&9zV)oByXTWNGnLV4i`EkiVAa_r4h>TCnqfInJ9WtYgbV15g{Qi6pIpW{&1 znfrPg621@-E@fj^tcbR7IF$FE*Ym9JP-|82#e+oqVeD$;6_1!I(US)=6$ zHmC9BK)wZ#N{ix#rJ)J_PT9g;xTd>9oQ`TZk2aLbpsETPz&Yk%8o;TABLfS^rQuMF zLJZlD6^gn;ANL3@N^Yit&CCFSx<6)S3>)p2)sBHvle#`9dhk#k z8B-V8*;(F?mtfxd=G-9A{lVSxNy=2n#R116ZqE9YSwaL?Yo^}cT>%fC_fx&~F2KRe z4XVW~yz4Bz`ek);I?gU@XY&s6ndo9IwXfwYhMiz@vag(!7o^(x>hpHx$(sta(`;UB zcml2tKo@^-n*dxDMZi0*mpeyVOvnRz=59$q+p_zk0ekDS^`+ieT=usdjqI%o?xmZf z{UM<%M@}uJ9XEHjy41JFTQ>&N*^&LNkm-tfX=eIetcvrUf-0ky6xrp0HAHYwz_-qXHAuG&?xA{R3FeNjEAdWOu@Y~ z5oGHrFud_+E?Kx+<-Asu>b1L@BWfZX1U>b^`a`+7+9HbAUv0gHY{X7y$=$dvQO`HZi>EzwX+^+wdfoSp>G`b0e9U5 z8(t6I9)#FvT|GLk;!k6TyHDe%XOGF+zKZ4L7+^{fuM_L814K2qHs)TB zi%}gm;RN;-y&^SMV6u}~YRk_ny;*R<2T2;ae87rT7`oNfeUXhz;b0m4C^t|T<(ua! zWOoOK=?UTai3`Z9@6=-QQQ8H4N2RByS$$opdG67&PkUK&*SYH z{v$}a={s+`2-D4ouQC#;h=f5Ia-a0sDTMX5CkSB6T8Fa@g}R5&`z&DxeG^0F0OXBUY>z!A{ zCnr!4cjryh_1nqSstBeJN7mXTfnx~eh713j4Rbc0^Wh2%rugV**9G_Vsi}KlF*pT9 zddRV!XM4f@wg?^u~%4V+WPj$-A))>daXEW|&T|VR=5r;{|04md_q~*j!yk-8 zxYO!)bQ`ifr~iv0hyQR-)aC5sU(de=mu0`({E>aU?*Fd#ln_K1CHzHRDkcECdHahD zNlXnC)~vFn#oGp9#7O9e;wY0f3;AOV1yJ<7V{b`OB0wngE*KFw2gu+(=;3j?qqydL z;)TheSi2=H{kw}?quWn{1a}3^=RkVPrn3!pqWCRLg0OBVI?$3Aycj742~dfa`5n!J zLRex@O(Jx#CF#!BiR(p;wYn|#c)Yy03C9m)MKL6_B0Uzv3XQzABBjz;V|14MYA%++ z=%sF^+iB2{vS19g+(9|*4%!0X?TOGr{9p}EY7tu-EbNJ_Jpdon={6)d1|8^otJ8OU zL{1$6ZRplAeMp2J=+|o^^Gl+~2ouR7^)DonD|!Ur`<7Ud`n8|<0}nGCwF6w&LUI9x z#gKn{pDj&)){g`g**K9*w?#wT5e{ZguEwKWw)q}&-qGJdvo_B+ZgHkJ3$HJy7 zM+;ta{)TIJ#Dhbm&Rt5S2WmsgAJC<@&~P1+pA)*euz=@hvWim-A}qJzvx(qV=SVS3 zuuA_$yi%G&vPthP&UGOSL6cVAQy_2_kw<=>j=}ebHfBoLl4P@%?L$9?5FC!uyGHb) z_JC3pjd?gJ)A}1sNSROHPHONXM)2LQFMAM$0uNX|xKg8H&GU+dq1LKn>Q6iJYLaPr zN$}ti=!KDSlD~gz41%kM(HX!`g6BWrhuu*}uHQ<2r{7VzlMJ*apzN!9eRM|TDLcD4D-S*jv%QTjRk&`%~G%4$clWv~hYsvU)?I`B)i z=+nkl5+h6pis?L!0c|0?ceC1#rL#AIFlvn!ZEyoI(Vz!cV>4N*t3(|&K=nvU9TK3> zOYnt1%pUEL^gbt-fj>+gHU}W_LV?O;>dcnX$zy?H2%S>EMe$4hDupJptR)bt`Bw)4^P?$bR`P#jYQS@i!NPHxylnTpd* zDB;TC&H}mT@j+hy9V?4~m2QMQh2P{KOM-?<1Jk+OR z$7|?D**xkl%18HW-OGo;p&Rpq685W7!n<$psW!3MfDICPSz5Co@z8$(-5vk9$ zxanP$pG>blGh`3rA+wyZ1Oz(_V%;0eCNZ`hQxF{eY-Jcbiprr8rqS!=dU{e zI@esb*$$DGOa|nvOcPDZ3PziY#u~T}p`;!r(^m(s$ynS}{F!Kt5dA`_2#LYPBDIj7 z@}IW#AGem@Z;kX1_p~jkgaroWH6kyU=O0%3WmQV*&H>- z{w-X)9vK>7%tK;#$W`}Z{PCUV7RTjli}Wnvs$<5=NWZ8{KLye1LK}Bxt~Ch^fDB$& z86%v}eSjKg6Bi7>97~#KZPYN_xKa+yuh=+UWKBW@AKV7tNJ(T6LT5X{Tdk^SNtdeS zr`#7#m#m@u^dnhmcuPc8Bhg&61-vMEb56dP;3o+`Oi{65*>oT@SkZ#SnIhgz7$uua zy!6@Xkyn%QE+}!O^3@kldcvC@Fwk;NhfROmrC7X~dOI6%o7#N2eI4t`*?ig0=y?EM zuQRH15c!{mo{wJYx0jb=PM?;SBRCjd%2f@rvN~QCy08&EIdV4n_;{W#w;}#^|8~B= zKb<(KUu4KZ+?=qh;^J@1nIgw+_Yzr7=qW}Neg@(2DPfy-}Jz8KN>qb0S{@<7h9ik zy#AgYy8Z>Ry5HFHasqZxE+B!A6_P`s{bhTie$npBJv-au_JrH!f0iT5+xcT1%>-~| zlS}MF0wd--*>hSIT&6m5OCR~p(Yqp_*^&iRQVs5f?VUR5fuOcl1Wk%&*M0TBF5sx4 zmiwr9&1257z3Xob>wp+NrqCK0e>=^AzjuMK`qrbrevG)~Tu@ z1SRIZJW-SG%n})q#G)-GGIbz5hFvDfnX1Q@^r#J2UO`nMyNY}{#6<+pks0<#Hj~)! z_~0U^P7De{7^sRgfyVEc(JpREJ&_8st)fW~Ek8CX8XQ-e3%DT_6Sj0&dcCA}$t1IR zN|xkK_BAW}oLVULR)NsYa9$J*L8igztJ^5SD?FkRm99Q=6cj&8ohV~3-9{}{7z{CZfOt>H2?A$f^ccwDBjX}DKTVI&!L`#u&I$O^^=#d#DxfcWJrnu2C+RPV3o9VuZlRVSi{ zpb$K+6zw*e(hPiL!G^pwdU|L#vVFmpfoL7P2NwL#MinN`_xh)SJ@3i&J@s)mdGPeE zMZ{9(9L6sQz&J*K6tzDmtX?dkBsLhx-ZufS?>xl%1YnodOt6u%0B?o2pTP=n!=W4z z#c`>0ibl7Y8UB?oSNgjngt$)xt4IfdUJj}FJ4ktl`(Y!rvz>JWYZ*pJNldPASo`=( z<-Fg6Sl^kmE!FEGeLJ6ugQx&BMe}V!o8mbMb*-P5RW=!t@G`Z8JZLeBq6hl05uFo! zI-$J40`McFXxjegbq0n1^E$mS7MAAHR#Qw~Je_zS6ITSZA>uiU?xk@X=KWvtmiEuK z3@WIYLIMv5Pi~t&&(}{GDGXn7CI?fx6c)LY|B`L|w*Mm!J21i~GJ0w|-C8s$VsH6W~F)X0bsR|Bs0F0j^byB{% z;kni{oDDoLTYK>UTN&YD9j{G?%6eM8afur)(JR>YiMkB zrHaHY$5jaJEgS9NQh6GS6vQ9NwxuwCqIc=Q+r^ddEZ(LCS3q!m%Z#ij|AbCEhdR|&&Q0Uo)owl!q<7#rV z6zB*Oj})-P`kSj;-hWvG_bn8q?>o+zBCJB&J>1>LywWTetDc{Cp;QXJ&0VwvRCBW| zezhX9ZApgmprB3m#9fvw1MXftkKc!Nssh6awkvt~izs?Td118gmJ$R{uOl9*mA{*V zbZh66^wo^seup#oAuWcYXTrSw`D7;SfXRv4i2oehru}OdjT7~YhPYJX4KAK?;kg}rLz%uq1W}Y4fRKcvk8jAnXD$1qUY!py5$M358s@JYc=6#TOr7Ux@ok z5q%4!bBR6Zo53Zgr|R}9e?*JR=#nueRkjpWH zu2nXHh$9JA|JGUZ$)HdAR=OZ~?!)CuqRgIYaLTg5w{3$%%RQWS$fy7p*emnxmg=+W zSitTIJx08#`F=om{%0wXNFicp5GkAzMk%I~oPD@3TE zVY7ch6Q$)7MXjB`pIyF}-BHHU!gUAyCJ?xGE2n6o=5v41>V-N^s4eCGX;V~960S4M z=P!ApXNBF4FN?S(iXVsZNn3r!!xnrQZs#`qcF7(bvimk1R%<97_+)Gqj|lZ15X-Xn zk%jKQm2vAmhCS&*>ptoR!!cFDKkDXFj5`c$+HA@M*&^O{;Mxy*dqLPKoMLQm0cTX3 zTAm=wi-m_zb}`}ZAZ>K1s5r`0A=1$e)PrH4%X{aIRn!g%s^#1!icYBOLl*xgvrik@ zQ6%vmpkb;OkhZAh(Rr;W@(bVk^~0$Vu>O|qy(gdnAac=##Jn2Hgv1nmbN6b@W*qtf znDO#IKdN>OnGtNuPwv*2uoT+^Y7f&{Ol)cvJVw-dDxxGdH3)1xMMCM}cyy)qS$Ir0 zhy3%E_mK`E_GUrm7_#^j*9As0o(sq-e{-#bwQEH$aPTbKBokOS!ZI=CwTp8LVCF-a ze&#ZmPKx?Um!Kc{BZxBud6~n3T#56OP|;HyZbJ0DooD+Jd$^(5^_>nJm?TBFCx+%M^U&Cu{9$eCAg#Ke;Vt^Dw29VRr)*!;Ws4$z zOI^4pGs+VdSp&`i^=s!vtX(Eiz-NuBmQW`mKhH4?@*3ntYDrD>v8U1|#my{xn!^4! zzGhD$@SV!f@!jZa$L5;3QYW5VMpp-QVKEqX`S;3y5Yg;Bb=sL|flBuXp0SiRTd{Zc zSQ{?AikhPZ{}w7q_6m_|O;RayHg;C*IAXv%fGAKBgbNExmxsKYyTqKiG(!4cBE4`p z64CGpDIaZSCUB2+9EnA#Qk6kiu>4Mm^ZSq&F>_RQq3p9O_a@!!{aNk$3gQyc?AjmH zTCu_wuO$H=M?T>FbW_*s;blT$vkUj-X+p0P%j zjy^{*?|Wx2^?=L2q<0-}FPrMEQRZLHD#~>xjr-G{H^@!8(6WV_P)zMj~| z^XfPLFWhlNyUypg6oL(2(9NCOCOUeH*3#gzkwxhx?5f9Mv9?YpI7bU&tK6705T9r) z8AMGglESHA;qcJmyol-GHt9CNa5aF6&rnw(8}w->~Nvfsbmm7&{=Rs!AO?mbFUXTH~f$(s)r5 zv65P~jNj@{;MX>n{%=W%W9f#%z>njvOCuso-uec9bNl_RKXz#l)%fU8(p#~FV%u6s zP6VXoj(?tE&G{1ZyZb6dr#_hC?7pqsbwpR~3&%R;he*@IHO#X}d9Gn=dd-WSQ7F;v z7}`x@hYQ$v86NyPl?@fWPu_qU_4(W^;10uCn2cW-8EwzDPicdhe1AI=1h{-_CdF0S zC18UaCz^+|=y)t{eJqaXRm<1>JK9;SEXd;NJUBKxiB_;Ov}*e~e$V#IdpwBN_uH!Z zPb#Tt}&GE!PRIg;iKxO{8T z2Dibrw)cecn>YtBk;>_MD+fsR|G^Q=!c>X{hdXVgU%7j0# z-74ddA>nX1N1-)0lY&BZ>L`}MP-JI^80=9b6DB(T<2m%)1CdPx1voh_<{*(YfB3TW zc)mK=^m$*^Oc37XoWz>^<;qN!ZprE0&*%W1S#`Mz(eRZ>>nzXj)UW{W=vF|8;vu52rmX(~3y zPP_NFV|G7ZID+I}@c@ZCPZc2OqVg6^kI1VDSE=Q_^O+Knzf{Ca(Z$(WU>NFdzTVEq z{i!d*tomcWlCR50K>p~X3@e&)^hXSy(#*FXaM6?|cFtbqB;opgm@Gde(8T@yNq*i$ zmr~OIFx%y9H9x<9^^pxA`D)~Zl1-`O!xyaG0ckJhvSyISjR_#lO35^x-IfbK8S5w+ z&VCcqE+>C0Wpi)hRcd|A2FF!ui$0Dau_RdUp_?P$UUhi>frS`dDuSz2*MWi)gh=fX z2j96JXbAbR1oI;-*f3L=6^%2`Yps;23^c9=wLwGi-5C~6Tez8)5{9109>(Ume_RTN zKCh9`qmCXMKLS8^Bw}^s0Q1}~z)HWA>yfJ8E!E|*P<4luPiId9InpNx#8g#xYSV(6 zFd&$Mtoc`zu5I_7c{0fcgbHmLMj&3v3Y+n2#ZX~vQ>&%J@lq_>L#?lUZ}0J-w)34SQ))n zu3kpxk^)Zd?@J6_Fhg8J8!u?{kn0Vuc~0t+5j{De23959KjZOcugvTd+|d^$K3Ewe znNhDz(E%VQop_#R;51_@aPOm9(*^XcnZM&k_w(D5gPj{1xdx~$XFyZVd1&hdCHpFq z?4{f`fTt6LzH7w(<-%26VQy>WqHM($6ZD2|-Q&L2R~^!<@P z;5f#1=v1L@+jtHtRJXl9cgR$?Ek1WjRCjGWcZ*cFJvavi{-=BWr#t^^>0zzzdT{Px z{GYDIHCO;$N}y@1@gb9FKYjW zxK;ZY+BJ5vbE#T4@h30yWrXmS+RKszq|d(EZOv4k-jhb#Mb8Je4{hr`VYN+x>0@cO zZ4&7}VYOcf>HpIWK6u-d-v@8|lc$e`-TtRX{|Wfl;a^|~%-{q65Pe|#kkCJVVPNpD zo8Lb^l=mO@{HJgK)2F};KL#2iGW^$4=!1V;;2;0vXZSJnssZ1#@IY?g!97Ao@f|`2 zYY0LHk#jWi^SpNb?g5VVjC$Onyq=M=39!y}YS)3H9UnI5f><7~5&7kCKKy%lg;qL0 zNk;@j9pgv~<4sE8D!6_CIjxyhSANGexn$a1)b)>FY4&cFbn3DK2Zm>6)0Xe+wXW7s z3dSAmPi4F4F@cas^p51CQ|qo<6`&2Ku@)hTMUrQuS*_BF61R)qZ&b-jU?~v;Il#1S z$nODKdAU=beZ#A+JNt;Rt<=!5ft_m4$%C6p=YtU3E1QPgL6>sLkAtOHG;J{^|vu0%>`J_;h|?J;E+jT zQSv#>IH-M)$!1gJ?$jVqOXGSr0nXj`4#X{G7WkLD?hv+HE^eLq(#*YKs@x}8pK4b# z?oPr)Jwn7^=4>2VIv*#sw0+hc?5wR#@_$%vj%?88&!46)5#>?3$g!1p0CAiJpLIzm zk;Jr*;YcTW^?Nex+=}r_CiYB^`6)i|q_bpv&-8+y;sa0kOU8`NPNJVTUCGA&3ypq+ zIw}4ke#yv3mrjZgyyz?${!jl8ONRdALwjZyx+4!!bE#{m>wo%F*R0q7{7QWRtk=(; z_c{yzsSk<&VPNXZ>3W+@W|A|e-33H2WDDcaLGK=W11J+FA*1X$8!92A<2mzlLPq6t zHpB-9WrHPTv^;0O$N$q`^YR6kXbYyD9TRv=L zdS$)S2soDs|EDTM{D+Yv(>ooj#~M;m8tS}IMh|>k|8eIuxXSgjj=wrEEdM4i)jzzDVzHp@H$f@YO0B-6>&R)HoK}=Qr8vK9YF5f&~?)FcvlEmhX+2107oq-jTsnU+RbMYHD zJ>LJf_WfVMm|MZ}%LalwJO8u(X5>e`yVm=>K#sz};;umJ)ImDnb3jmqSI>Vu06Vsf zHU&wo`Dk5l%mx)oZ&uIo+c5T`Xjuc!F{cm)c89j` z`~Oo^c0RL~&9;XCdOG>|_JCkbw(6`Wkyv`2`H!I|Uqj!!p4vbcMZnSep&_$dnxw*) zKO|PiV>&6_4o8yn7Vm^Cw&^UeoYaGk=Ywi^t`rj;KD%bqNX@oQzcr;Icms)n;#_Er zywEMBaHOWFU1;I?-4P*Z;(jb2Ap}n%CVBa25x6Fc?w95`Equp7Y#ru1ded9t&mJ~X z?$FGlesCMu%y7yyR`Aj5Ks@R$w~%Tjez4xY!@zi{4k&WfeCr8>4G>pVOhV8IQU|4$4RC7l)?m1Nq0^KpIidzBw(RPl*+@oGd#*G7W;uNG6h;e*$FvP=j7b zew%$tsN6jdQ9j|6UWvC#EHQ+UWb>7Bqup@GEL61N=h!*KW0OUJV*lE;hLT8VG|qo? zz&?vMf3Nqch^%~&aQpfzz)iUmM;1kPDIB{SS6GOwrKNm65-}2#NN2%W1zT!QhHPR8 zmb7z$_eK~*8Uo+gt_1E7;~Tedn<43s{M(k!9@3CVO~R>;Rtgp22y(o3C(1C36L;p( zUUIxbca{j-j|3GFrDTSh_n64S1UJQHl%1NM9yeL2aUgn~+4eIN5NDId9baqpL%M>0 zRBBMnlK|;n>miZJ__B%(eHt3a0a8G)j7;Ipw*(KNY~>4-d42E*7*VXv3`8#> zjX|vR0@4>M)RI!BuAGB>B7wid5Q`L?jY;HG@v^GnLHaw=MS|&?;nABIgIH=ZDZx6n zNR%aMExd`c9a1?=QdO5gp`HF^tKPQm7W)BVUgC%@9nY0$MF_u02S@x~0#xlvfx5`* zh2xrM;??YZ>q~88oQJvz^FopS_-7JqX*@51Wa65nFQ1l~fK#8)2HV{Ny4nSH0l{oA zL2jcc9y8sah{x5GHCO?G7FmximiVH-w_c zlS`u!7XkEWlQNU=VcRs%0#@7WDySC8Uo{c}w9@_PxM4*7kQ9hwfyg6+B95ZS8j2PZ zbr9hAtKEZA02B}N0ympr23sV2sH-(B9@3F|njih$@uPnXwL_1@MX940pW8(;Jd7c_ zks+^h?e=Fpvhudu-ACzoxCNE`ag>hSQDFa;J7 zAzO-%af)H~%Q`bQr8dY8gPn$@lufhHD%y)_mB}y^JVca@4l{BJa_dvz*!0}#rp%s6 z$hCF}@Kmcx_Ui8MoGQbyijk5A{Zha1yJHD$3&$Sml68WKgRhWz!N3-ITr0QJK_T(GAFa7n@5%IM(~5jwh`b5GQBA<&e!J57O9Vlq zuLTh$YT5Po&Nc7kDw>m$h*SSG^1+C;nYf(B!133YghD;C=pCSs-TKUz%MUcJeezqt zW|8McVHSP+sV1Zi)5DlV zLJ45vjfic3S}VTBB`lZ_Np-pe`$|HDIuC9^89*9qHmG5j6{w|4W>%tm;yOU_=uk}( z1ObIKEdEg%qCBmM9VDM%&StQ`(hTQ@sJU!;Pg_-+w@)fdXi7K!$nEk++pgCStEtJm za>2kzs#_6X-d#dYG7@THLquCrfJptdC?iK+2t(P7ZV#?yQ(nNOQAir+5WX1OD6V0M zg@LP$sdS(MVvF~W<0L7o3po-Svl@giZvc*5$P-Tk3m>OHM;U`gREO3vkeeo^$y)s7 znsT>#i*W`b*iwW7Rp@qm<{+_(Q}A$L)Dne`e7Z-f93Dja@gNftHoRoUQ55YzC7i3j z5N39hucb5e%qh7CVy3J1elwilYGv$|X28{%CSM-l&-{5mJSdSk8-(&E*U|zhuLEdx za$j!HaOQoZY|cM~RznO5yJsX)Cy^zzXSPc0{-SM#$z^gDEJhvbYiZ?2TyxRLogOUp zab}I8LTz;zZS%)*2aTh8sdUqU=Gub*0Olg)(Qh7kY^uSna=gpFRUx5 z57}7LnKg#vK_PBOW;yWEjCc;(%nu+M`?)5n^!){o<|Npmh`MPYTmYqCGn)}C?+c+t zrI4$1tgpURDkF6bgBl+4({1K4L~9aPfR_G&M_6VUfl}W8)K4 zlocZhiCNJk@-$Ca7K}1+#9k;Zv_!E?6zg08*JG>>Sp44vZSc04*W}oF%wPbAUIHJ;sRu_G8<8Vh$2;Ug)ET$pDl&}}?a^PD%;8Wq35s>z+`s|=C+ z@hYwtOQkDHG=+hjOG%{K-2n97#9;rVo=Ez3LTA|s#+hCf)DFSIvX%yHQND9-*Rf_Q z>-?f?vu{_EHDL#WJ1LqXKbT4JSvz(h5s9QRZ#AnPeQkcR4?E1Pn&;&xj%|H%SzzSS zC#azH3}Bnt0KSV6rSj-VGC%wnVo#WJ^Xmh2}sk z{dJ%LE?r3%nOUdVCrnxZE!l|9`0;YcCHgvld{OkhHQ0-F@W)F2t9oz|I*Vk=^me?a z5;|Sf$qq7Skx3Yt*eT%WqKYClI)ZNjQ#QU}moS#J8lS9a;7{Y1Xga2^hdSk#J3|LK z$_vf2$@F66$Ne3AV|j-lozX&&u>P(ivr-!8|3tQE~0=@Lk8Ye zRWk}RKJ44UiiN-vb8m!BC=d7>*OKO{Ym5t?*$9qC8$9UgReahnybD6;iJu`HZAK6z z!o4EKZ}Z4CE@I?9khwrr;x@PpNCS_zUC*MoawsXG8;UYH^p~MDjF`u$g+y~uZ>9hI zOO#AJaWOq#cmNm(DnA1Eq<1~tUX6Bj{Yp96VZti+)b+gr-;+JpT53WH-4IjTOE}b^ z#yXEX`?@%m4UaxT0;LQ&PtlOjDpSzoTvcht@l=DISw1|G5Db11Tq>9M;s4okCo<=P z*`US!GphW+jo|}HP9h^4RkQp zP80#WpXfyObkp}TPm>!%A3ILR=W2+WOjsoXBVy$j7p%*8shguu{k*qEX8`{^+a9)UhwDe2EhI zPIi+J)$gRmlrL-9Q2JO2Z}<}Gv*YoD;xG*GOb8dD+;5zoyV!}(9Q1#!_cN6F*5x1> zZ&t-x{g9$!xTtI`Lo%LpPVG89KxN&vAAyWyT}iYj+D8FXOa%rmTxsC%E2;HSG>qm~ zGm_8D?Y15kZ967vvePKLfyciGzMbEvTq@YV*T}~X%n28aka$K0h+7rju{oQBM;8NN zDo*V#Gkd**jjhZ<+z=7irce*6evX?Oau(*JznGGPdmKhNk9 z3cAYBZQUJ75uQ4%nq%jZ7L+|uJ0SyR22uOhGW_WJVTS#^5{hEUn0XS`T>-3C$pkf4 z3)npJnmI`kaqP=r#}x+d-NDNrYxfsu$zOMc9o*QT?9;fJDrrYWWAhw|W+{!dS{V$) z8WxCpr<;8xM2Pt4$qbtY zuv4XA`ut+9`Viq75<-*3=I6?Fc3;QQzwk2Yi4=tUpD5RBAA2Oh#G2sXO=RbhpwgPt zGGKmyC5jF{Qc5*ShomkY{;r8AqUjYG44wZh}%?1_JFxTgI&OpKIw>g!Kr z&dk92^&5=}v|}Z?Q#FPW3UTldYGg7kY@34t(m|&XbVDKKTlB)_LXf~ZMJb`)9{k73 zN(ffFfGsM|C0tiQpAiTU5zb);Lqj*rPqV_IghpuBk4-bn71D3$9hK_XR-ak-m~wJ3 zqgm8le0(m(J={?7sjP`Qj~8qi#;I$xmBpMrywdsE{yW;dYf6oi8^)B~r6`e9cnYr^ zslW6aRy`ydj(s8DGWo0@q_I{XDcJHy`jAj0)r(EWmKblWecTVQN%N8wCD}#NS|#e& zlKHQFyG=2 zsvMOK8#aFU`F+3teEExW;2aLT->>Jn&wcK_Kn+u7=wG7!3|&`NKo*6fcejm(0%S5h ztUl=a6-Fia2}sK>W^tQQA&8<^E-}ns7j3EIwx#jgtG1A(epN3=i&Rbuf?`gn4Pt?xD z24vF+2gLa_?83ImcR<|VBRq(3~*{?b~^t-aS@_e(ccI1+`zb@ zWtfl5TX;FFCzOwNplm-Y6GTVbNm%!S*JMPyLe;LVn9(R~`}Q1>kQj@q=|4hbUZT;Q zs~Lay>oW-g4^P;pD@`i8aPaRE9Tj_c987*vFdb?qX*rL7Fa?IJD-N5(K0E5!C#0Ca z?Q84~Ys8Go{kVvlCg8@B@7Fp~Us36`)fVh>F8**#T?kQ^mSI+uDy6^v7p2gKE+-H> zNgT=A?UW^IOp^(D!1Bekb71E%cyAN=P?(}mI8h~yDkZgDRg=K6seHdz{u^2 zFfK51fefTtFJgv$KGs*40a<%zmGxmK%TcNQr&Ad1nIl*|v`+ zkx9_LIN2(IyR$>sQkXc((a zt^4IDuA>e=5tY{RjJ>qloi7c0N7Fg&*LieBF0RMR>tA2Gj93jyvwe{V4|eI4%9xMhK+P(ezy>Id+;N3XTvCK8mg^)bqTnr91CXcXp7k+lH$Q*$cu<@UeO4NzNvNucfFV zl3k7I3J$d|%*7PG<{`zp3BFAMzQ>GC^_qL?qsRpe6H7^`+Mbf(oyjia#*iSrj+$TW z9txqm+Z~rCy{qrd-x9{wX>%3nNOxFL)3sUJH zX>kQE{-!>Dd5L$j8%Yrao?)Xhx~cJpy_92M!BlA+XrN_qlp`Q4@UM-WL_S=Lrv zZfB%BG6|Pl^lRy~klDbpwY8X}joRI~hA?T>zTle2A5y4GTg%4{qcopRfaX6AD#S+| z8od?D6%#0*U9*zRQ_5F@I4iRbit!K*8xAG6PHc@J0~_5pYjU{L4Czq5Fpo?xnf&Y4 zXRR;8~oBdY*6(LfO(Y=X&=xC3{q@>o(#f(`G$q(+Ia`@ z_qd{CBpLhbbR*GXG*}1oK<)X-Dv2g$(ST9_aDPHigCyelgMNUS5kZv4hiP(KAA!TeH=h&Z@)s4c8*QK1Rs>?l zv|?`gRLdSHrAJx$WlPGUW)pESJUo8fs=&cT=1lOK=}z^1cK?C9qs8Q4h*6JJA?1b= zIa*o9TB*w)EuTAHThc00*V?USX!1e(Kv`ctL66}tI<`LcM^XO?5pbS7>HGZpe$g4P zJk6p{pRU&?-B$YIm~0~4wA_>c#;UX6@YJ+&AQ;rnqzDF%aEvLyy!XtG)g z-g}8tRbem!kMmH$*|lJ8KlxFdwdJLEYApc|n7y9kS8G{8R?%WfsZWtZ-85d-Qi()F z7NqU)^RO~z6`8W0)`Se(RhP%hWknpImV|v)0P{n*rGTL`^0xriCUyBZG4}TwGYL~3 z)^Dt8FOlNPZ#IC9^~=wbc-eh|Vtz3vHgo>f%G+~V0ds!qg3gMS0IsxfM zg)+R8AMOX}X6eN!#ZdtS&mM@!$LxMkelomhO5_R15L1`FWoJ#T zgSJsBTG5X!#g0Ke2JRRkc#Ci6TZ5jCzJ`=2!oR`$qTD0m6#NWY-CXD6B`#QwSPm!p z)46D>A<`+^{f8yXZCb58BZOK_ih3at`Kxgk?`Kb+bRSVe%-h78)U@yp@ba?C@!KMV z`FTb}WSKa{2shfD*NN4r#jzv_CN^a%QZ9guAc4+zrooWRKxThI{Eu4gX2HU?hUrS% z@5z}{T9%?e5{SFYr3%6FDSos*5pCTlWSmqr< z-?!A%NP}hdh42cCRnyYenlh6CX~IFJX*FgWcem^o%lWX%s z^u`4P2ATmZr@lH%sSRt4JFU6==}Q!SbI$9)LouYsv@UW)X-s+M(NiOIlcp_?>Ky^t z9!fTJW?+0NXzTCf-tp_Xnf@U|f=q>ZV8q6~t4ksX=-jF5-Hbuaug;_S(hYm;Vm_z< zDm56!x-hGZyS&6aIXizF82mbI4HQVr z_T?iwIy!2{N;}B%52~Y0k(dU5QHwvkU>li_xtS?0oM|F#Po)jy1QG|=5x4D}!{oq2 zzd7E&{i+lfW$DK)A?tP{E|LE$OVF&c4yKUFGrPxO*r?^9Yu4Ed}A{r0xgKW5%_>Q&+M$=ZX9`}CxG&AVLN zG*f)OZSEPnHQ!B1Ki@)--evfUTO1>LDLTY#@EeJ~tziV<$>IWEzr0=}C6gudYn%J+ppw?OdPSeCFTDc8PyUL1JL$r626wIWt+PXhTiXQu3XTlrqd3 z^cd$jy$?q+szjSYmeN2z!9`^?77D~BH7wiHE-L}CW46q}|?kWh>Go` z_u@2i0wzM9YdqG`Scfp08v?t=d{LDq`zR;7X}q%}^seyp!2ETRAZI zMk9o=p{SLwRx@zgrACaRWj&OT{mQHvJ|-^*kt^Z-z7m%|1oA#IXdE#Cs0LsQe)45h zcb|mG+y_S=`-1%sq>7okj;BpPKHllKT{9IgkBlhde=wE*8Bt!5)2-@Gbf1>rt1RTc zmtu+MF@(h$;dlpA(%LNAGdMk`$dCB8mSm%Cj^z_YLn*p+mv-l=S$0twush%exA&0= zr9c+!mr_zA|})Co@~P=yP{A10q6n; z9}gKtnEu z7pl1THBOtlWc<>c9%FahW?9i{xMa6rQs)F7SGK+)hQhQslyThJsGYNuCN=FXz0HjdqK71-Id$GNrPEW( zaV3@uLaF@A4>W8mZ-}Z8me)9^@w@YnVMr)$mjhQAGS|Ac=m#yWCDe-Lm3Y3(90a!^Ob{U?-yz>I-3 z5bojTlY*q&Y{h9&l|?#g84d3kFOhEe*0wYM&Cih#v3Il>`qQ@bsN6O;X~d`>*+t6t zdvol5l>@d0WswWY)lZ)C8HY}ZtjR^obw61-DSch}f(_^`F|N=983gb+5q4A(&FN@} zHeRnXuCAC4eyNXGP2;3QUl8L>`x78m4iG5+S9)XoRE3+o8>^Xru4VG6Nj*YyuIOZL zu8bDyY_ZbCeK|#EA@>Dv?8lgLHvMh%pzB8Af%HSLdsRmpr!22}6(~4aKi&rJ6m@*) zxcd#m3e-C-n5o9|BLw3z?sMwFVi*1Q1nnjkWMZV&xfKqGIYEhH-f$AB{1eyw!t*;4 zasY9{ciUD9a<5Spyu3266-vgGKFTJfnLgM}#?3k}Z#?*sTbQ+CBe28EWfZ13XlHC< zt1DSP*dQVFApZweZlw0g7oz~AC$`309MHY&5y#8h_5)?sur`5%;i(vNf*-$@&w`A% zeqz)WzdSgPHKp^veU`6(JQZTO)ym&2xCn>vC_*1!qbZ-5S@LBemC07di{P>4KgqKhPEobxb{ zm=@(JmpahNla)oSmzgK=O$7BHZR#$UL>1O-_)y5Vdgy#-f-Y!El=e3^uqb|6A)(oc|v+wh2Gr!O%@ClM$@SL`rrOwnMH8@!@4Hl!A#h`8W(% z7SzpB36K`~*@d&d&(jVPAU1C3Ctz?iqSh4IeQ?|R5VhpML!P3J4KoM%G3Kc0QlCI^ z5)XXUx_I0eQ;FJx8*&fHf-i_kB>8l1ZW%xt3|$O6-zg^=I4IXOFK={CNac&&UZHaC z6oXd`>qqg(N03St=fZ1rdy;a{+IA3HH%R9s>6< zAOP;jOan5+++kQeUe9)3oT376KcHC9nVQRjbSEjIX?Oxicfg$u!bq>lW{jCyx_?nr z&zI?c=c)>OA!azuZs^n~W*QY`>X!#= z2$>Z$!W1zGpT$uV{1&b*2zoL)hn)PO2DRqo&0kOX$7PzrB=$bt%jsLAaPJlynY=XT z>QK`Hshyt2eu}-8W?nV9r+rqC5;!n8WO7=49l43c$^E#mW_4MYVV_snazzR)ZiZ=W zW#OC0AJq{I>rV&&ZZ`uT>^+CxY@^OQjX!98r(RBcrq=kY1t-xebnyMjZw)6TjU<>)>9J{rxtm(E6KJ%Ht zWtQ++WzEY53{+SYJO!;$#W%qr9Pj)2VuUx@zv2UEH{+!nW@ZJAEpK#N z$i#xY+XdwShXMXn;KAx_FQ_S}x4mTu)_5?|CxW|_{HnETV<~jil}2=R*lmAik*`g_ z%P{wu>4|4MfV(~ZPz%o!bxt9}M7aej@#QM-AVqEpZFfRgBsOnDC10+lC88-APsSxH zPw&1s!pyTw%Vg-1MV!Az`eaF{?iO~+`<^jFnDxypz~u7F|KFe0S0a?FYm2Y8@h6Eg z;&=HxLh`v#&DDna-Pnb&YkWzav#ePLm1}V|b9M#fZe|QwYs9fl!L!WOu7Fn)MY^Qa z>$q=boJW?Vl+oo^q9cuQV1-v=PHT#jR8t}B`(|4-JXz2B9}<75HN|%GwuPGiJ)T zSSM$d4KG(RP?`NoOD^@X>wdr12i5)-~}g4lu}%t?zdbq@GM&j6lR?nI*Rr zg~)X15sogx;sGMO^Cy$LfK%o#b~-=&@brwLOW7B%>kFXSXgU5MX(2&sY8Duaq&*` z{t6{rYm(G}>uEa#NA<&7iCND%X}8GR(?eWGHsPox&(HJiBa{T1e|cMYzFhh_>0Kjc zXU6+Z*d!r%Q(Q<+a4uBKwZcWK16}nTK`i-!HC56`ofnJgYsEk^NlcU$EyE-Gz8zu2 zz1I?t6O$bg{P~dJ1enw@lmuXnG9gr@2c{y9aqY&NSCT0s-~}J3Bs8PkIoh{oWLY!| zY_3;W7EaML6P&zYB&o>>cs>+{O(y}PNq&Mdutk?+BR)?}AGCV?A9`^Q&OMz@>5=AZeT!VX$>oJmyEDQ7y z^phlHz2d2$^JvhuC!^{aA~>n^g(i;jSw$=bQ{Bp*W$WOJg979k?uk)Mm6gR~7;AQ$ z$XQbocdHbN1QCKuO13iIW%=Ki+Q0G7P|`rCm_wMi98uq#6)F?9n{y*^H%_#qh_KW) zi6)Q>o3_nlVz_BM0!aRWRE~Trv*fT;wV<{^(FGS?%O6cGWO z9aCcw;1`W3TKSJ#wM5F>WQ^A%G(Nk!l98vU6TKfRC5l)}nM{?BJh9l^T>esd_0@}t zz^kPNj~r=!HSg=L(0&Fov#mi=vGZEg|B32Fyjt=4y%bE+?d!ci9*TYFSQapOoyW~b z&k1m-te3bwtru$Za+3?a~4byr=GB_6z2tr*BGsvTuC#}~X#wN%Pa6a$5 z4DyKozLlV5ZdQg+IHmGk60dT@A^l+_>yIMNi%u$x*6(M0)8hy$tE0O&ejj9x{{1gC z5hy>@J^u8e#gpdP6K?nVv#V8fl3arZJ9_yvLYpKf=T~1v&c;$a65Vk-=a$}HJ>0{a zTx?A4N96XbZFfkN4N9QDci#QDoSFV2@{%^|Qn*}~2KV<`fQLBju%R+l0w(Vrw8UiU z?EwL2SAIwSy0Cfs_cgMv*27bjeJ`Dxx(D|?2?>?Gb{~%I`G5=#(BqN6R%T}YgnhVy zlj3;!`OU;B4Q4Jdg>s6{ro@b+cC`q6t80F%S>kl)YRqZb@7E7@{vG~UfBn((=9c*N zvFtbPJKOWW3W$HzQI1jXc&opte|v=9p4M zZ`G&$hxzNh4?((v0`%&}lQJJh_SXK9RJ;0ah5NraUvQDqay3jxUaa%wLQZewF10-) z6zE33`jgwmXNKm! zYCm2X4Yp@-^2ba++e=N3{H{v-aZ50AUAJ=X%jD8Z|9qHj2;^$$_lUBZ$G$!A(&bxP zM@gE8<5O#Y7CN<$A~WC9CUgYxZ<`#IP9~?Yx36%;gy-#07#uGrpYcdm!DoJY-=F_z z7|{<^&7Np9UPX|3Touf?&{hlUPqV`Cw`8@HqjgdDa zuGVHVuaBIGK4yNDb0A~-&~Dej_G++85#}=&PdO9g=;k3|+q27@c5|?8eoNH$@6Rdn zz1};1nSaQW5KytHxb?gQm#Gq1%7UKN`1^2|nL3d2FRyjz8ZVh1pJw54`a|ZWD6Uex zsfBf!+STG|{w$?9ke%2kFXj@zcum`qHtSW0OXQm%9iiTybwix&o4jg+fvm;SaS6FM z5tK=!e40H$GT5Lr^FycoW3WqeLafbt_fe+81@vn2*$jm??GJt49S;fq`$V*uTalr! z?G<@Q?0TeIgPRPmt2$UV1~!g)%z7a-wOc}@ZXL~J)XK}iSk35H9cwf<)|7Sm?e3+b)LK6Na@U12K#KVOcL_~%;a!Oj^qvx=Xf_lyg$)Y(- zeaP_Cp(fx4%A-K!tH_0#xfnCfmqzxG`%_OmqP*B3;ZVM$Y6SnBvo{2|ROczdlVBCb z2U9wuo$nd*bp7YUaJ#W*M(vYE#kg0^)5Ya-`hAc127Zzs5o*^c9xkz0M(;@T2;WgL zX}eF_kNVQerj|8g7_K9qRmmzSHz=6Mrk7V!I+E_v>zF+KEker$>1)iVU?kC?lvi_W ztyH38M;|InsJe9~SfCtpN~Y80rrn!%K0!)O>rk`x?TBdJ3iAa^swpqSzM(%6W1J^t zL(&ri;IutHre7b|_II72yyF|H>z)@PiuWp<FNjG*EC5VQDFZwYd7B!SJufW_37W3FfW2(tH^7wmg*EHy15W4!iGb~{mK zRoAF9Jr_;D8_!!4vS=%pULqv{$qcq+%&8@&JV*viY+;NKte5ATy1kD({op%f$gFd# z)d_uS>XeZw)+XuqSC*L^>nwPcMJIuR=AMa_FI2ZGXli= z$3`D$hi3|_e$knDf7`aMTHUeYUD!;8ZD2#Z6);_aO}_EPl_jq-V}~m_-|j5y6sWX} z_pRJfZo-?ww--DbX4?Fj1mw>bUNoxsabs_@ZdBF)6yFxKn807xs6fX5ct*LS4>V}- zTE#?jYeeDv;OWwFU~Gq=H$XJ-NW)uFMkCkeaBDL7%sMlH&kYLNSE_>d*y5h(=Qhye z3y-PfZcIfQk?W-F#IIj!S+;!Y_+~jet>dc|s}=|LsN%9e!+jjd4oQdX1Np^Sm<3l? z7}=oJenr&H;Gm%2u#93KTzpeZ$lWu&`?DopJJM51D=3guG@VoDG>zOk(lE(&OQTBa z>b*M+=I@+6SRFjmr?Cm&5pb%RYWGh5>?K>Bprga%- zW~wC4RCP1K@;sd>-5;4k+>KN15CqHenQ1~iCfwfOPOr;RJiYxu+D{fq6$U3i6}OoP zjwr)6$nsFm@Sy!k^yao{-JND@Qc@6;HFM6xTye#VX}x#rm=hTV8G~>@6J90*U}K=dC%dSwH2{Sx;Rq+O z3GBR5jf#NQ994_UFBtaJ!Zuu;usnF>fRnn5pj2(r57X`L|au_ATiC(`~-& z_uTsb{)vlr?*+hHA}zvCoOYt0ht|<60+=Jwh=Bx}R-Zh8D~eWpOX$B>Qu{;zn(?%; zSZ5mRLwSH8orZdd0jy=y0v|>LhVRha^2C_$lLs6W(ozaMX?K}VB^zlY{gUjvy)4Yf F{{vqSa8&>R delta 25769 zcmY&NI$;sKt$=roNp9ex$ufw4X$zCYTPJIj2HHCnPcS$~l!v#8yk_ZMd*q z@Q~(hZ=&m|X#%h>PCu(04F0uX_L}{2EHdg~WQHanok3xe&^#%n$6m(FOTs38ucfE2 zmm#l6)k&zo5q;$%#+9ZFn~Zp8?&|Th8~Jh*_;R=K;L6$7j#`y=hV-1+)%yHAe02B6 zL5gIsPID{zVgGjQ=Kg8V@Ocb)+#EI%&NPe{0WgGpJpiFBFwe5mu=_Q+bbG;C%PZ4&0g%D0y*to0&mZeqDf1@ZAG1PkR=1h^RYd* z9|yt8GU_R{yZy4Bo>K+O4H#=@B&W{Al#Be3@TkUQTCg-n>;7@IZbZg>$acbc!&?SQSY1|;zq4?@z65mlc+aTRxNuFCc zdqS$|4reQ}BWI>7@#VR$&T$gFkaEScc0XtK><@lEjqN$vA5c2;?WpYj&g|TRyXD#V5?GqAKw@w4V{Zlo{NBL7Kt`T7p`}sFK(_oUPgN7k3Kecc?xvmjnUvl#sMBqohL)(_a4`YaD^UMr7s%~ z_aZcfT}oAhuT5Xp0CR_qIR_e?w`QWXwKi14cJJ3CAZF0x_A0fe%Ca!}BHrIk{nhLo zNI!d1!)wx;o{4_d_VOq%54s!!``ugnHk^H_|1>yfxMC0|GEX4ubYteoY6{ zxweq*x`Qy#sj_?-eUU|>{ql2YmE;@*)ZBj{LpOXF(t`$IktHuyuS>D-x9nX0KVnhIxSGHFzFC;sB zSM%E?DQ&d&2IaT|#zqAmX=H4mrDJ>ZLzCuP^{-klw_8#=2{PsQVmeIMqJlXZoyhqOkG|6XhYhNNbs6e!rj&!x^BAP;F%S2@+Dyp{7g|jI zYp;&2d-SufDCS9|Hb1N5_&(_f?++j5mTZKTua@#Im%PSRESCZUwH8(~&AKNHp?EeM zY3AKmf zDNpe3LX>FPdO8Kx&pP7&P}(KmaYS7ag5>P+B#B3)t}|h z{M2~%>hny^rA!!SsL-EH7=L4FYEl$)lF(7}>DFQWjK7v%?tDzTbYNZBQ1k3S+L1f> zd@g`}AWjEFA;VhzJ^G0due%|WhdHxx5AD^iS3d2fafO3!b*HF*j9l$q-$LRg5hSqj z7LobG6h{j|snzIE_+B{V>TuWLaNc`p<*%ooz#o3IVSCXpB!s$ZgMPXw|8*1$((nKuDnuPrN{3kHc;o&PiDqsRBk*LmeqfW8`|_UMO|v9Dbf9pP!{Hp*Qnz$?_#%w}i&1MAr);et+!3*_&%eW^eD8dL-e22+)AELG<*wiU}a z>pNIcPPILw?M*$S8f0`4Rq$0GfC89;43F4DJIpHt=@H(v(kIp541%Q>5#3nDDHm=h z{@0fXy6*-jiZNIPXRtTA!WE`_)D-X5l#OJwcUG>%>lth);pw(MC5|#YA8eDS1I>8) zhF$HAgE@*-B8wD)BrCDZ)b7+5tJP8bBTlZASCU>ShJ&f5Z{BAXE;6XV!nvP^aCBoO zVd>igU}&#bhsJj&Xx{z}{=!*{w7@kYvkstNwOuC6ml>^X!Rf0^oK1wBl8-(eX`<2~ zXZ8cpH|#NnlycscrE!s{1(h&w_Ti+C<6WL)UY(v}y_mS^3-3q2Wf@FJJ2V2NpKA#b zpFGjZT>3xpNR6XeTKE90Pn$<`TRh>SPb;p@0>Dsk;r;Bxebca~`{X1TG7Je`3=0oc zmNrmwnP5qOHlBCW((*~Utw+BV?fX|KcUML%VKmQk zWGYhO*c31um-O<{{Lz284ySY#4;)_3hWSciYPj`lN!`JU+I zPG&g}qytBFpug|s9F(m+rEq@0DQPkG$3^4|N>hjE&D7f(91dY%gnQo0lCF?A|H3X^+E_XNNEVgR^^m~^EFIi<3Oo*vR!>T|8 zwos^uj0^?xsfFKoC9$eyLU3vrb_k}=!9+MffT?>;-Hr*Ke4s0WRCHiKM>MF(qj z#(?h%=|{z-Jvfb+PKzPP>!!$Cu=n6EmVa2?0}L6jBdLq_H$53?C_-ip9{0tHkT`PX ze&adenHrQ75aR89h<0XIC^;W0q3uN5xC|Mz&m@o@BRW}4LzHUl z8+F`IWvmzd7J}W>Pg|tG*}d>turC94M;9O~JxAAqf~oMLgv`~}C3P+!M254XK@Ne? zwt@WA9XLxJ2Vtmt$)%}($-8tZH-0vDrLul|emZ*i`S!Zm zwpRtbzV577RlVJgtv_`E7h{?ea9wYEZ3oYPHWn7*j~^BmqUTtie-dug)updJD);3z zT|KP)sjIs?TPwUnQnYj!H|XN`xdAR8&QG3qv$pD<9&DZ2q|>kDMPBb5c5`1(J-VKF zJZyRTJD6V^bvrK|+Qg+hgQMQYMNX94-8fLB8`EutJHLl3%X;3GKR>=aZ{2vZzIkf; zuld~^Z@&7w!FmArddjeGT%K?4>?EjXOkd-2QBEzkHl7ytPyh4)>2-n({y^39Mctvq z#LsjRIPl^1Z_25sylPz0`8BQd|{_G7+xFz?Q+u!c5R3Uj4*@K|MXrB95`x>S=qr*y$EdI!4G< zE^Z2bDo~H>$cF91fIbd*a6M0VFnk_<^>E~9yv6msI1W$mdOd$!II8M=x>f!K{dOhk zwvJlW_0&li0Sm@z9{o)T5cmm_psvQlHJSRr^4!kWJ93juz~<^HzXEKHmgmPaM~<+; z7tfpVU%jxwhW1!Y>6*{fam4PxuNFyeTKaq`_t@FjS zD(NGNlE(R@74biL*XB3m*zAF50n{#0)+ zeyx+)*^_cc>$!44k(158uGO@VUqhh*!QI8J*q(b*=ICx_$WttkD`}H6vHpD;@ea*( z6n9+&Bi9-u{vvR8r)cE!zxtu>(Am2hP5Q}v-UnXdA`Q){_Xl8MzR4`*e)jboosYBn z#(HyhhjAAv{P)T(C7=v8`g!EuD*QVcF&MPt;{jbMBZ`i%1`f823$pJu&ZpU9q(e^nINYsK~*b zzcf3qnz|8qIz)Wx3RZ@}ZsGx!o4Et2J0G8#f|bWlxR-j|>qjo9;CKER3y(d3JY_)pt)3^gi3j5eBu1d<8rye7ld~G|1Hdx;GpD<aOgufu<`s|5B~#r7Ec;`{5^?hfV2UAm#+jtk7%3wsW`TgQm-uql@fMj?eb| zE#F19=~MyVBj4vGGeLo``#y|CQjPxefs}RPSOqlz;cE#;X_S`eYzjD73?JPC8u1aB5(J--Q4S;aaf)&;tyJw zLJbPG7X8k6d!l(lzO^Vx#?p;7pqzIr4 zi%YL3I>M0qlv8N*p|gfMhTNxLE(G05Ny~hfoQ5P4+s&hB$2UX~PK-H0L+|vxo#6>q zw%8giLV#LGK}$KV3hCCPYjez*?&Z>#1O4i@BQwZOje!j=VaC4-3VCmd3 z58snB@OtIhy&)?4`-*r3CMsHII*I;$*}Vc@q=KId)62~(SzBs#in1aK`Fn? z8G}MUOrjMSj##2D5+IA^R)(Eh`--$Q4X)6Umf*vLX!A~zjr90>3+1%5F#ipHd+6E( z97bSm46nkq9*BQrkJ`N0cqA_cGVIvVwBHjC&SL=!S=_2VPMvTfI3bKj02*&iH~Dp; zhf43XKYCJc__DBV$!M`|2>K-bd23)RR7d|X9Li4tT1btw(LNMjzpgEn6*WlOB+C1> zL`T%+)0zP?F(d-jH)Cg`*f6&SqpjdHvSe)QkycE7{fN?8W1f;O0fT(*8CaTEPa~&&@k3tEQ-VHRTjr6LJ zgep`fWg)Pi3!d#&s1(FMi&vIm3GgY~5QK!IQ_8@}u|^VFB%gD7xq|y- zNK}};*oq(;A;FsjjUV=uB_Sp3C9aSJM zWB?AL7{d!j*Fq(g1_57Lllz%y&Xc&J`JYiBJe=|4mpad;J(g$AAIH^c{wS=CF%R5X zVx8=Eyablmf8_r?ACIS5W-nWmM-;x!<8se5x{nj8^|f8RWMx;NW;0lNH~#fa*c114 z|9m#cNOgDh`)2xFAu97Ia*@SNdlu^+N4qNGrr;OY;Mnc|GEVQO$ zdwr~5KXd8SZhMyLyqvlF#|FP506UG!!mMHNq1BPlQK6{CQP$zB>OT{HaU!=fHT~#V zwSn-|J;QYtZdarULCdpaG6GFD8YFLjvm*Ev+Bjn%c^+6lW;@N@^F5jgA#vR_I-BF? z(r3ue(Z7q+fAbQQHO^b`{a8M!jS+_>sU0nlpcuhoZFv6D2vyw3pZ@B!=?i3J$-e9V zzyI{Vb;m9kK6A0@&x3vOz#VIY?h~{?M%I&GZ{s;94%f@xn&E`V%N@>|5b$z!#{viV zy)-$%uD!iPJ9K&r-@k~gDemQ>OpN=RO-zg%wEJ&}G{77kAMZ51{$bre@%6vEK0bbV zy4x4}^k*TvZmw$Fpu<-fcu%#o?A{;y3uo*7p4xeyj(>Z}e)!o{_x3tQv>fZ?fC(%y z89p@W7f|GWJnFhuej;#KN$JZ!;mVG8*xOLYSQTRE@)vpY6e9jDvYNW)VJOtr++~>E zyOIk#m)rv&uXcU^J@_fzOTeGMIXgD|%(Ade8SbqkV^8}cdS@aR`25pbxZ|0ZRv2ZF zK4>CblOlSGB=>a#Y|Gz5_{`ec@%HI{`#m#tU)sU|*GZzh+WuW+2RA*pZOz+T;QLBU zrAX}jvHi_gp2CIf;S)#U4xgwqVMc>o<-Mzeu@T+5tzQo#1a+H3V1YhhJbZ8NPc(o; z;|{;N=pn)cb%etLoaF83b=J=2j;*eYox%NCI*Jc&JMcsQBZ4~y$FjeESD4+VyaK?n z%&#XqNH_fvDd;(B+Uj`_5GY-G>PesIeAw7Qt;+527OIZ_+4E2J`?F@n!a1D$I=a|d zf8H{x6$~N3uvdFp@ICaO>9`9j*tA||s*G;K9*xGFP3r(4mvyS-e>!^1h&@5i851FP zi5NktR``ZNd(fe%H4nc2XlwaE5z!VC-UODbHq-zi60U)c^QB_tq_eX4izxJc^n1f) zrFl8?jpl8{>~o9QF3%iJ7g)(PK>GHJywZy&r=ntV)v@=XQqH^zWDxe>U?XH=9hO}+ zB&<0k1#kc|`0yAZ&FJCOO?OrYvfLWlVzlGw6{rHVP)2i1QcB32QjV{#k&`@Q$+JV>lp?6RcXa}iIhPCgFFGe%;y%gIbN^(mD6~ydDP7P54Q}_) z>`hyHNV@!?5dXl-3sBNc*>O;oZ8VW2?CBwogm-RQ(s6pywLTa1*FZL3K23gy<3-HV}>T_z3Q!BoK zoyfOYf(8c6ZUS3^AVOxn3)Fy*de+;_aZf{3MT@T zK$V>vHHV<=RGO1L-L0!=7)bY59ji*RX%x(g-qrO5Ubr( z--us%*SI*lXkC)XTIuCIwHQTj2HInCZNyizPEgIiY!&^zqLrV`#N9f*WG#bxM=|Pg z+^NC4e`NG&DcYlM;okkVn*|He=c!>|jYl`IXi}IovqjKo1zem{iO^{DHv|*&NiF(i z?;@a&Xltie~@R$2qjOa_`hA{y>8dX>+cVqr7o&8--{`?0D8JmWEpt`jcl?ow| z*j4M~5rwn2s||&Vl(Ih*Ce#HDg(~OispeNQNOYz!Ku#x?VhZQ!(ETAMxDoJ2g`x_)&k#ab9}D!$l@t_=kiWvG zc`(+)D2d7Mho)6eRUBLc^)T2)Fl~7KWa|Mk)(&YaziR7Dpaw0_wZ)p5l`#85Vm$Kv z&_9|GeHT^G;zA!5Q@HPaJzM`6=wSuF*5&=shpHsY+Z3#h08dX&snxlxOV%UIfyUjN zOUorQS-}QBFrVlvDWf8z`cp6JcdNr({ZDP#n#eBr@}_#fc7mpnnEd{UbE^n8 znGmJ;5VAw4G1F<7pF=kXkme>QICYeWx>3&C&WKI<3hx44tw|Q?j#V;DZn~K@aORS^ zae}vWu{k!=@xxoMUCfD6WI`ybYDaA5FLYXOQiW?H>16^t6PuejJqVf_fV)RDo3=~W z`s31KdsDt*wW3{+T-#M0F!w`|HQ14A4YEG6JrTDaev(==d!COG+D^Q5(E1}BA)DGT z;@^Z#r&1+ZWOUE`FeLp1R7kF(BWsxt+{8s;gpTcgc}}&5(fn*Tq3fZK>}C;GcA|cf z#H_hOfZ^YCgmxhnKfd({;0XfdI%ghhBkwL{jp-(5QTIk@-MF8^JARa+lnwg>M}*{p zPq%M1$u;q$kLcL~U%7q9F@Tx=+#FzWTI}o`QAhomM9(NVy3n*RNT% zX}u1WOX)rZ` zd?L0V@vYSTpXINo_f?jJvWhO0w)-7>L!>{Jp_^7VqhEu6DZ4989ByssS;Ub_lN7z}DI`XpxQlJ_;eu`m?Qah<} z9)eLDA)`5Od7e~*$X#O39#A0u6`YQ&)(GCwI8R_hB!_e2lhc^@MIUGCB%Jz2*sOQ; z6-ux2GbNo+SxdK!4JUJv?&28eryh~SmbC;%o)eQO{ABYCuuu;{BadUj9FUaIQ>uge zP4@TtS0hKYtJ?nW48-G`wAwokw^*M=*J|6%wZ)lLzq_85=<4mujiuG)JCKn_li7=( z1rlAya+p<%>H1h{Kni&|3zbwq zPFd!1O60H<4p6WAN1J_o7giD{;BgX})qZ|2Q!SlKY@E?_`=)|mg2~3`^F%1Se}a~g z4`-xU+)_G@65j4COo~EHLwx}PUA%~Buvba`Yd^0_Ba$Zfhmn8EHgU^$UPlzI0CRde z%&uea98K+5>N2i+bfvIP>AIDHTSIeN;%xpQlxgz(vroX>pa&v?Q_ufM$q5e3_%l%qcCh*v{ z2E3fEE!V7|-L>8?**}bQogfgsZ<@Udyw!_b%#QIAE*R84+`AJCQ*Er&T^`+C#m{Z^ zJa6eg_}$IaML#{w;4QycISS!D&#k{K4f_hZVxLbTzV1-Q9h;Vip|Yxb6$VC*dAMY zP>*wZXnCsm+4R13xc~S^F?gkd_}GHehogmP{HKTV#Y#B%=<2{%xI^3P$lI68(984- zVY8>@{lvrhv$yv}{6;@>m+sT)Ps!fv|J~yLCr@AJNDM@LUS>Sjuy31nwSWO_Q>$V} zyOT#3`3mOLZl=TFoQc{b5-L2k{I8>vKYpw02)ePXbVx3Lys~p55(av=sH|>TleUZk zYFzpT_tN*we8GcJky@Ci5MQgT>ax z3CW+&n0=iE8BPr*qtCbdCtJc09oL*@B!WY!V%EB;2d(<=QvH&-m2 zAU*hEmA=sY#z!hy)TS`(pRFa2lw~`*$9>v&oyUJ#muJDX$_!r@GADuCW2O#N+9xc+ zi*=^;1f6SAbG?vX)Y4XcMpmdS`l6bU=^+%>&%eSTU1YdE>9CAz;8?cOdQp{0RvlZ? zfA}gTZP_k#;*3{@)qe8j891F?4R1jcuQef1bVH_U=2ea4X!e7N?3e^ysSzg0j21MK z|6O0a?ZXo{^`_ST?s*1~%aGsG;!X)souS5(llcZxM8}pEfNa_;FktcvV&-Sup?^{J zCz>JCeK&4eVZ9UPJ-`9`8A-q!(@nvU%e`x2`@|-t3}2F>Z-l`<&Fb15I09>N>JJZw zxqeU2J3P6+2h!;}Mu@F5Z6wD#Y=Uqt&=Z8DR0t~>qLyI5`4m8|t*V5fTv4?=hFxb^ zr=K7$wYUg#UgdL<3CQlL9?@qJVvO##ix@O=XzqPech}twk>4pa2 zKf?DjvjWfP95hF$7xlj;`Q10ZO1A?3?xhLRo_D0sG(PEiT~B!}9PAReX{+HQO!Z8L zJ=^|t#Hg!*sG)$niS$r+VP$jDN*s68@6vCN%e=Y%Ud1E1bi6knF^3K6z=yTAABa2l zCw{nVa%Z<#DRAhAXy|2e2B&b5Du%*OyW!~~?f$oiH|xn)M;==#a+oVB1tkeWUkZvC ze&VLk+T{lM{=$%~7LCa)!w5~x%agcKi?lYxH^#58npXg_7SBpL!(s&`B9mzHB@QmH zah_C*C&0r6HF{ub^(?!|KsrI{BZN@JKd&oylgS`;Y3fyB4o6u%D zIn}@(37w1mo@fOq=mlmzRNM&2^j?X`wPfOKCf&-FF-X`jbr1N_DBc@(jciv|QuX!yclF z=8f57aT1vPH)v^}65n$YhbUJ|AskU`ibO~%-|vA|a95mL(Lr3#9Gar)V0$gst@6~5 zNg^BRbe`yy+7_+n^f>5|-H!quq7QV`4DN&LiO8kBoNgw@ZktE20Cu*XC359g=lpv9 zgIHvQgPF@ODYg{}X`v0K$jhy!C!n>Fydo{PO@gJK`LQ{xV1|4bsk5s0g_Kk9;OU|s z(ksCDMWUt-Rx@T#!80e(U`k$5a@=fB`>mSttm1BhXzxnZJ(DZo^YqrAa@APaa-z4+zUtJ?JK5iD zE_dQ$U#5oKabb|@VP9Q#}hI2JNgh) zre(MI5R(7n2}#p(E852BZbQR&EY5P^!p$vD?J0&kC##o#uWWT!A1kbERaXPYwksl- z!(P8u?h>k(k5{$=s+Zp@9RJ~+(SMA}e~joq++(d?wq4mH{fAp<|M3w2;d#}2?bUkK zzei728EBLWGM^$6fSwoGZxaIzAFzauo%S{T2Tpy?HT|*AeD43D7lf8SEO6!o(t59O zLDPzxJ>~A2$AL}D1^W<#((?bUcb~+2E;&5ogL~LH-Q)Xu*z4W@`!XJDpL#Fr-ud23 zj(7eau0i+xV?Oo$V}k!-Zr?lOo(tXoj`5%R|KtC|zJE9Y4gU9J;1f8nW%qVBtN3O& zi__0#Omd%);`Xmz?$*GQjWERuY<}}xKJczjXL}+r|mN#nx_S%_VFfC_VJ)m9o@W`uBGvS zgZ6CCbNQKb`nf}4_89Y?#Z6ZpTWy@iO^EOG%3s{x8fnAU=bSaCeA{&q)g=;rG;I21SD=A$)u2T(hCXL5vj2=Q|UZAg@~ zGp#Zp-C^U@JaOYhzx_SwFOLl`9>VXHT_gQwlGp$S4)kl$!0crldnOlEvR!DBW=#3d z^Cv_j-meH2d?F0FZoXE79_xHZHHIGTm5RP185~vb&J#)-1!pmf_A1{*<}2hz>i~MI z*%COP_h)?pP<$Q2z}CB>wlW=l^L`ZWOy}gK0koUb2&AR!toX54b_Y{?DMA0nTS(Bq zk?Hym_ssq=cN#(OBlb?>Kji#}dzAn2m_g6SD<=&dEP8R5ZY1`sVcn@*g;=TNiXPtWp|IiX)+w#o7_)aQE z)c*F=DNWSA_|zxvU)d+@AG-L9+Bcp$x&O!8|HoU1`rn>5R@oXF{CCTj|EiQk5q!?Z zK%k4)nu#xqY=2YGL;*4~QsG;4c*utag##BkQUBRfCpFP`hj7yQhb|`n7$0lVe_rGK zAA0{om!SXnDA73Vv)jkjbjpNW@Y6Tygxm(79NL83o~Io8{}{%1<|&7{y4n+a;50i( z4W56@!Rk)PoKz(Gj?aoz#0Gdb!@mn5r~lB6R66<&p^qmC?w>RLfqQq9wU40p@|yZT z%uRkr_xL}c|9JTSczEY}&n6-3r=)+E@qgg|t3sI8@^z5wkz4IvjF=dIHD4?DKdY-7 zK6&wV^5K#&>KKf;UBTdMZ|k3LU6oOQGVGtWDX`gTEoTnWxb*Db^fvpzEj6yP z(N{5xWll?MWeRYCD`z?iW(+cs#Vwp3&aV)OMgCR<`U z!AQY>M+|~Z?{c>zoHBN}nKDQ$wx#>YOQx9KPhKG#8K<%`^~6~k_gB|5{+5Jlt|Pf`p>ck zL5S#nSL~ym_BK#T`>UX8Z|#@>pOluRsyqhT>-5ZUuV)w;b6hu9AUE_V=Qc@$Cv^{^ zdj>X}uca0V`+Ug#F8lkHw4RU3nR1XNIjG`D2ei5|Fu>?M-SKqm5@c@(_jm!rvtD<> zMQ((0iv>0*MZFk#))3SyHJ*bTlpk!asD$F&ON^6vD-)ki((+*NOm9_r_T<$ymH&4Ia=^mSMk42zsb|bS!sz||iCjl2baN9(dhnXS zHEAd%92|k@@c8>nyNQq}X^5Wo%b=*c(McU3C|7FkdsLt{5@yQW9zAcRYLp03==^vo zEz+tF(BiriBjF;|t>}nvNUgjG)7>t)>6w`c8KE7bV};r=AU62FtUzp%+pxC;0nI}o z<39gFs%no_^?`(*Hg0VR3fq2k2q?V@uls<2q1n7GGiY+JrEbXW@(K)N(R3HR^HI!qviE3@4GtdFVL_u3d#>Oj&A%8S&%v58I_w&ViQ4kX1@;9x=8; z!Rc8Q@-#TEwhWllqXHV_bUPSIKvZ`T=-by|dNPGdAC8buP#MSH+$V4snQ8f~q;+J* zWkM)L7a-*LP0xe7Vf3t0MP+D+Nk~AEANQ)946|YpHJSQ9nO!u=t1O}0kS4Gx@diQ+ z!Q35k%#t`Bhx7oy7uH)QxlgUKr)0ttsP3dWGx)!XU`uwV!a~%VF20aj11n+ivjxPu z1E_hH5TxJPJe$ZU6(RlAK9y6L=a&63#IFB3N;$P=0jXRX+KP2IC*b`*%ldJ zK@?+ky+sXl5Rqq38R%oX&`}AxK(JgM6$z4`Q~0tp&0qUb_M=3Y!HzqHYHVgSlDdH zR6Y2UW6ASZE5crL57|BCCGpLemwpvh?>``Qy}8WtGH55q$`ZP0x+ zB8+B^slcm~EAw>(HQa!GO;GHlV`3JT2F(f%#;t-G;cOxza^WTfE*?S=2-^Zr z){c{1>irOAOE1WgJs@Eg?)R}$DA@u7tD-mqD{`kQPUSx^9!5VI z8XkZ`(u1-XBU9|DIA-%RP(X;g)nH2ZkBcmk@3wRc@X-$Hwd__Z>4@fiSTg9sh-n~1 zZqClL%>uR0OSA%UM5?^lo&*qb(#L+R-@etWGo|3j22*#hLn!@APCJ>4|J* zlk($-(|if3ld(jm^688Wg48ChY${PPjv`Qn$5TGrIG4F@)}#f_nx<-js#dDI`7It7hD%Fc+uF@u=%L{o%AS&yF#LSci5pIL4 z(2dx{pPl?6MdODwh{r93m@JI?7Mw`xW*m}gAfrFUybwyG^Z^PE{B$KQosY%Z#01n? z$*f}Vx^;yplo0Gb=hGGl#h{g=Q=@TYGNnM+*kDO1Eu4h4$c2)3&*6umuiN~pvx1cC z-uME)p322J&^VyDjI-pzb?9d&$?PC8I*n_k_P7v+EvNWBc9xm>nA6kQ>=?%Do=?q> zE*oO+u>NU$RwMreO5Ft)gVanrAse8Lis~|@T4Alk+-@w{l!nrVW?bMt@&DL}MagGg zE0rPl?kMyBX9C(^)EN!lviY>x-#{kWK(|yqH!b4r{l`a zm62VMO~7v|FxSox5}7Z^V%$tIg6^nMXW7%=hkUJ{P1w@#F;!240C)ltxR40f#s0;v zb;y$%#AKtecuNz7#D1|j>T5Q5u@8$g0WsbaX`#++?8W0F&zTS=G!Z>4f?EmO@7?L` z_y0G?o!3-XnaDlJK|snPI7YgCV$Wb{B}11?2y=dcpcW`zLA9Q>qqSlZQT);OU(otD z(QQyFRu=+S^u$ERG8jG+zIoFs)$CbQV4U|ch#pZtUm9sZT2$Ing&!hxitqCkPamGn zddWgPxP{Jh%0y_U{gy+6Dy+Y-SX1I0tj^Vt)Vgq{lYlYZgY3r0YM}Ar$^pJMn z5Tt+oe=%cST9 zKDfM(Kj;E7?Xnd)N?WrcwPdWgX&2Ns(9r4a+H|uYVzEszGrwX)O37Jc^9O1LQNaj^ zZ$U=Q3Z_9Q+F(g5rIZ<421(FD`Br?ug&c3>&&JM!@zk}#E_Fp-_!{%8f9KJB-kL4g z6~M!1rt1~d!I%S+JIakh$w$oxy3L{w!_c&WDad*0QWw0rTb5gxoZzvrn=xdp8e^`x zE?_|PD^ht1LDfe@>Qr$;=&3!ZaEP9tJEL=ZRe5iM%_Qu?Ej03opxE!wTLwJ{qUS`FBF?(D(rXPZ=~$Sm92 zw$4sa&oWLI6D|>V#C|i)ctO;MByd`QiMcVXoP#AY9cdo)w|X#(Mnp;qtm=Rp1ZFS# zUOAR1WY`o`K|oq3f3~`0YKU`dxulY^ZVUk;2{Apqq;1U;IX0vuA)|ggl#VzRAeAzg zl`9SghcfI#`7(3gl9|LreU2K(q<){+BSxo!0wK;Mdv=4G<@G(qLB`dS;%#GhEher*A?1Tl*{E`>BnZu*9E+r#uO2P1sMwIZ4zYRn@CQJ0q=OVrex_E4pB6$i+poEHgkr{k&w zOf&@0t|z_Ey2Ax>t%-I_Do?0+A2D`oFzjc6H>8Onfm%#b*aqHA=b z18xqzh|YG-;r!Z<$D1}uE}4Ue?N7aX?!$)ID4d=<3RHC&1aUF&d^jj{jvACEy~d(= zC}7@cm?6UT;mUW3HbxXfO>>fk2v$l8fJfsKO+M9nHWGx~Tkhpf`h`#E;@+2-)|ZK< z`Tjd0#l`WL7}{hVCIrCWCK$IWwPPnReq|HG%ujM!i`BKbd!9+X3bIgx5Q@&P=Zrlm zsb!?yfc5us|;S7e3&&S2l>gU}%h!kj&3$Q`oI2AdlsRAHWZE(d%y=$2;A)On` zBgge!3JSB?RWqCElGFRb^+@$NwGg->GGe?J9Qmw!rnb?U1_FUXt|@}RtqM$9W#8k* zmV7$(DP74>HRxz|3%I*4fl+JP6?^o)qGo0`lTHPxouicrC!4S;wPAtKQ2zx{Pf6-G2|IfPhKZ+?XQi?o=`d{!r#9+k+OVJf<|`BdBZ$LwX+DX>iv_YoVqqg6lnZ0*thz(6W^Qxg zWVXnOkwc&B%Z+MFD&@_8|A3Y_;Y}7POq@Tn4LaojHmuFnc`B*M9l~W&TaUb$`xW7O^t8~XtOIFICx+qxc^m;o>`4hNB;~u4 zklB|FkXi&TuXwZBr)pY_a@ajOH7<2Eu3*+VNb!s}0Udu`oHq8{oFLy=o;+(WD0mn^ zwh@;6r^26+&01Mjn6Em0q)>s0?=c=%CZMQ-sjpBrOGdXXcU?~TWV)rX4vql5c;8>m ztl6q4ri6nYV}G%-=154%`ShFCcaJx`?A2Cx=boWPxrg)uRB1^?I}b#GnzrstWI!UJ^LagN8DRrYGFy>kzcIQx}A9*$CU2}1UtW~zqCSn>`{!l##IXLj2} zpdzOF@xvj8ks-yXhRT0=<|^I%w2I25b-Y`K)S+#FIOmb!^IymmIw|+j<;3GPq_Q5f z-qq^u{Pje!`guh@WIYN)3j2?W-(r+*3XFI@%COPi=5l=#z~%?25+DE@ zNZC9(-R!SW&;QfaSB5qHhwpA<;6_N-KqN+obSq=T7&$^}phyl!Hwtdx=ng?fNDB%G zqeBFw1q4)(lm-z{R4j}$e*bgMb*{6Qd$sGc=lgu_c%J)PKaR)Oppfp1v2YT&s)*O! z6mqe>FX6atF&oBk>c0T!`=qJWtV=_5cC*|4b5F_Xx^jcLeH6Djb;PROd6e`lYuX1L zkd`Wa?R2I!OV?P_Ox5;PH|#(^_$AZZ~^dct;eA!jp4O6rmdA%S03 z)useeg~50dbkNk3NjUTU9E@0`c>N2nuk7Zz=@u>kn6iAf%#;W~VK;G);-#`ll$H}C zdFG@(D*MldezPb$p&7)pz%(84zfzl=sMLNdh0m2Meami9viR@ zzJVXWUs*nCGgiMbepJ2jC%8bLr@PAWpo_)UpiZ>0tOo&VVl|i1L6+Padzne?Ht9b?rrA1yFM{ZE`72z~mEs1$SjvOnODV%@< z??PIZ=@BeVhIRFMkGRFW85)S*^G`s^k9{9lJj^rczi8e#uIG^~ll61Z65MK3 zNQ?UJbMdkqu7@4aTBtNWZU~@fH81G)Aa`n*IdER)CUX&r zykptkF?h7|UyE`Hw-a)W!X?jVMrO;V6Yc6%7&T^6bArBS(d!b+R2YTU9L`X(JZMbp zUbS&gdbP1sU>QJ2tx(E)gDf?~a2SQ)n_hwiT)Z@9L&98@x8%g<5_X&N8%@O>qCO*<34X)1&nkbhtBsid{^^xi^4aUAg zW0G2PjiyN=eM^o2Hr%7vV)uz&zG&|PhV$Ba-N!8+9Zlb~WE*G|NpUhaNs(DWuoxp> z-87RX7e7O`v=3jK)9x$!eWcxzRsDttOj&=eaEtl}7x#=s^o>ZesXYf3jS>Q`y7CCC zS3Y8zeX`+P3N&w>18i3QED$0a~~Y6IsADBsRkd2ItXU1u570>*5WS{ zz%QGWFOQ03g4G?G)d`@YI_fbmAW+2|y2L8#A@|LmJ+P@%Awnssyeob@U0X%BLV(Y? z%y7(!8MrG|!Nz;Z)gYFiwV5XWM33=`unBi8KVP4r0aI@HvT7l0LUwL4&29TaGjJpi z2m7)B*OLRq531Se-_7^QyuNTlR00R{p(Ic4U*>DUB(jXfpl{ouYdg z7xGiyYdFiv#@-sNFuWlUX8T+E_)N5m;3*wzqYg8sgz}jBvuqw-URvW_5$jk6hqf}&K{ky@edgy(0;r)OTK2If z3VVxdVKpb0#GsmA;Up_gvO6_Tw(7p*#{@h28?k!zLSvSe{<7z#z}85;4&^LbF+lzc zUdz5GbhuetI`U^xWW1s9xKqtC>RpI~BKstvx8}nC#;do_RDyD27&m{t$lt7jK{@pY zk4)5=1J}!Z-DP09otm9xMx)bruo#13Ju9#8Ev7CM_8wP0Qz>J?zky3Wu$pRpgPU_j z&?GDodIFZaCYmRhPOG{pbRIJRRvdmqrv02J9uEk_GwGOj`ap!lpizLUcmj_OkqStv zZ!pG43FE!9QQgb>`%=PXEILYwBw^uHq58J%kBXE!xYgFjM{b|P%kqr$9JyG>q#13+ zSHsJ9Oz44@!TM?bd7?pbQM%yKL1y!!SPvK4K=#3*nTd9vjgpKi>LoqmF zsiEmy-q^ic(n90x)JTn^(5ohzV8EQ1{EjefB6WC&3)$B>2a76Fw0`bXjbL`cF+D%` zeXEAR#NL3?#er^|C{fsPR5KJWtB?TD1sWVzloDVQvphD_ES zl(34o*mNz`EQhmVT6ci7doUvUc9meHu{uy-9#jIzKjT)e#;|$vm&+F(Q1Uvs`5t@L zF*)>rE6agAoWk}2w!tSTNaV80x3!&I`uj_H3$I=LXjh)Np>J-n{E+wH1ti~RbHx52 z5N`@E#GY$xnImqxpSpbbc7uk;;duwp$0t;k$?aUopq%M|f<{RkwEPuCz8CpCakv3C z$|V)w*k7IM>pn7Ovu32Vq57u^wa{5C9}!ws7Ym5_-HaIhYS{2hFGu)+PTmK9OjV)m z3>}UaF!s&+dn)-bHtSV-xN;FiUBEsJVIPOB)kaU^*hi-#d>e zr!AM+8fQml4PwK@LP5|^?Od6ap;Y=i6)o=1hXaBAhE#JkpZ%WM7SJ%~`;lmXb2NcV zbq&eVe?zrn1}lkx3?pQtQDc7>X`-D)?l1|6d8F{Yu@9f^iqQygG3v2o??KfqBc80AAOCPYo_ ziSI>WOQBg;hHDWVZS{KDfq$~b>CmZq4^{fIqrV)f`D1mnt-}bttmUtO&}mgfHkB?5 z$^hrFRnKD{3Hi;=mJXWDMU@xAIpWGqi$p|lEv0^=|3s5Z%QxJ8Nr(Tzm!W;G=(l?T z**&FEp|jCmcq@7rd`bO{k6!Hj`8>#41YAH|qjEepA*F%j_;+mns~jYTB2wQ!;%%)= z23;l=sW1{QVxrxtrKSgwZ?3XI#A%ci@RB?Jgl6_R?<#Lf|GLz8>Du%=BPm{4NwR1l zW7N$^pgWyF$$sT2a;Bv7wkWnqo;z>&&0U}Y#?nwh1EFE~8Q3-_Lk3`J;NEGJz$`Xn zVwXxP6&=}n1ydrjt5cuVi3rTXJ^f7$HQl?72q@SS5nd;JLsSxNv*xR}rE1?Ani9h5 z+?y2Ph-I>68wbrh$FarHn-8&Uhj}gf)TYxpKqucaC%9Sp$9sFKB61KQJSXoCU_EQD zjle4{$<9Vh9=|({orWJomW^jgrCzP7Hfs4i+h}B#gTz^Wvs3CgdL(Q&^lVFT0eXk< zNyh7>QuFXHyCS)ZDN>F!F=C<=<6eNVs#z~|K?XQD+p-#=X&?(qhrO?q$Zgcs;IFA< zFaTuA#8Rn5rvuR=KCYKB64qzBri5hw?)<#$Bh2oFa3(3(hGRD)pKaYVhjKx6h|Sy5 z%N6#TxU3Qux_Z4^V2iafHFAoA8Yi3;j1`y14YSXGHw!STGClNg9z&}XfE1%7zuhov zzG2=<&N71j-fti#Y^wX+mM@LDc|qTLt_w)}{Pcg+#ez6dpRFNxGk{u3My`sxZu#mJ z5cZ28bZ*n2AO5~N>$mhR0U75DY_%WY!RQ&vW2!xI#ZGDWV%+D?R|wOFZ$pR8>{rRc z0~J%-l(6$$Mr0Aq!QCP8uFhvG?bQ~o6Op4Iydw>~T5AvYx$y6@<6W0t>~(GCm;`Jz zihb1MPd2!Q4$<>Sew{;M0?GwhBtB}Ml-2<1imi^bT-}`qhw!Gjh%2Ln);nhPv{Ge%Eg}1f1?%f|% z&Th=}RtNj3#b(ul3$nqep1X6)utdjo4~*`ItVD)g_0zqSWC9E8inq5PE8M3oaWD}_ zV=C(%M&HVk?RAFB^GV{f)NtwFyqSrBW1WS_z?oju3)rb^i^&k&?Mu$PLQc<+YuS+M0X zU_x^lN^6x&d+LVbuCzE2^Y}kt>1bX;9|;EMHmR(`1q4@NRHzeN|zvTL-nb$p~$x@JZ9#L$6`jB@<8Ep zxHC$VD!vwlZA!CAf60GAeT>uM#dami7%kySh1D9e3?m}N@uV6+txyo9h77QgYnGs` z<)~~Q@_fZ;<)}=g_{WUAH>eVO_>kL7N_6)4FP;n0Vq3|03&!TDnxHyC(EwJ^6}>E51ri zmLt^FI3_C=`^|IT-Cv|SbtwvXJ0;B-AF%c|?0V&yBEW|+HneKzor>!zSX-FC2Hl9l z2ga1ScyPvU+>7@#A;M30R{Vdp#S%os%~o1WX+@|42=De*xh% zh{m(3cawvUjk&hccrJ_<{$XHs@|tA()N=?sWr;C)C|7P-9C3YgNvT}%j{5e%yGjS# zPH$n`)0tMJqpx=kvV+4am#pDsgojj2z$~pkB~wic-F3}$vHCZc&`Dwhs;EZYYuY-~ z6avonnz}%_UGYdUQ--V#fCuFEMk4MYIxv^shU0I>tcI597s{KCHZ5_3jJ=(vh0vtE z7bZFUvReJJVP#d$4{DWK9@w;>5c2km^!5$5b-J5qng@PcVck_+7=I z?KZ*l(- zxott2r3<4ktS4Uux$!munYiMkFpvoO8-4S;W3nE1j1M6ToQTCs1kIM^F2ljBEqRBG3**$!gz`&6~~l?~bb^uVgt-)I&~J)J@#KJWkX2 z6JBXo(Cag4GdSgGcNV>GlUlQc5UTNsP9Fqi5byN*fki-nd(@|#fv_#szfqj+oOWU+yLtJPpb`7Jag}ca+NvF)OAW;KnpsAikL0e?Ck+E%^MuE@&3}@NXV-m zpMil&T02WG+ak%oqUXlVKPA^EbF*W4txC@N%##z>tk;9C92DJ=Hsb=Y#5(u}_d6Rz zlA*o7_0*xn6fM@LGgAoj5{~7k&f*hb@hwgtmH5Uz?XAGTsW~c=zWyJ{pS{)eQah5& zqGD45*Y=Hot5%0}{=5&C$>Oqf3XxAV_|ueC5nP5+*5D6Ik*a%M=90PG=BvsyC=4kf zL%as2AfC(v86M>_R@n%9_clRLOPvZpW4qC4V?6v}AG4qb6AdJj@@9dc%qYyl+Uc3U zS>UkPmF=-XJv716P_A!S#LQw{h$qp{A65%vpDkIpRZ^+|}?@RIQCxJPO@b1VM zzxmfqKW?*|I)!{4;IxoL86%ti)d6X193Q&`EefdQoHrphwF1QY7SH6aQet@hVqkZC zSEjb?ZE5KsCAW2pUqPmNDfv#m(xoPq93BTTBEhi)slE1MPIJ%cKb@NIR~6LHFL*Z{ zD1UU_OpTYOdSaa0_hq!CgeubC|Age$JA4In&B20-YP^{6#Q-&83DvnoOrG(d2%?^E zYp6cc$~@aVljXIZAX)?uYt+mgrja+&cUjdaGH){=qNo;?m^pmfiHfDdY>uQhRWfDW zCX9!>f}fG^vcH^)*B6wGlhk@5>E1SIX`R+`?JL^V2));xr&821aq*GT5wFQo0{r2D z4MYDGy>b;rzl?QhYb6^Wb@DJPbu$@&{@_%uxx3ob7VQE$-^#g!akIIgkX8Gh?|Y!B zljPQE&BAwDL&xC{-?dP%ux&Y-=;s_4vk0>c+oyafS6Hww#Vi^Rdd5`Po6?~R01uPj zX30cxHs1H|`6?LSOOP>YMhSUnu);V~X8SVNH~Ku{gZiud8dtAlaniXU17cSzKx8eH zTDlAvP)R#|{k_(RRW|O}*H_-yiBQ8KyF*laCqEkA6UBS9-brm#MtxOY_}aY+Qnu}jkQvzMCbd5g6mug~Tbp^08 z8M0dykb_fU4VfDQvufvL0%c~hjmyTDInokcG1EF&IPm&e2YYl!byvb9SqQNRqhtNl za#rqwz)MS%`oZIq-+>#kS!H>0o;7>=hii$!+<;Ee@7!+Qb~FU2iD^=%Bu6DvC_eN#k-oS8=N?=3k!G-xx{FWDXc^6&TM*N`BwEYD(Ay?FEGQuOJ__%2 zNsIE6V8fM|Ik8uLl43nFC1#y^aJSPse{X`+eNRIY8Mt+0V0GJ3u(Jvvd(ViiNdlZ8 zIxu}%YvknV9XS^Gf_8S1Vz{)mJ3H_{$_5^QFX^+d`E$N|Qd5@GCZF^i&b{!=0|T15 zf)I+$NEQ@@JLkd`8UX%j6O&X+h{nCWhA?Po1hQrk>hw@$s==m?%t9=(S}#M4xymdI zSk+T#?x!4Q@|V#7eeql-f`$|oehu#_TQR@N0ah1ZCK~7ZX6v30xz7MB_1bRrKY-(;6Vq0Y$t_Dcylq~TOcb#koi_LcG}MyknXC=!NLb|&t#x=gRx z7CCEZk6??F-vpY~7$ip!?yCg8=~9q#N1-HMCbD9o&Tbk8GDPI zu;$?^g%gCr9|4(qy-!2{8|Kt|M3)+rC)h7B|^o=PS zoWVL2PQ#buKie$;7enTQ{p!7YG+O^Gtw!JWZ$671I{MT7ek<%Ri@RiR=#{^|iX|76 z2_c67ut>Z?G3w`m&%avLzn_v+JU)=5zvzCz$irJaFI-P(xJHfUWaL1lvcFmGkJoqW ze);vMTJl2cCGYQC|K{}#Y@_8kY023VpVljd!2s*>EGh1}Z&$Y;yrM?+Zk`z z31dTb`J~;Bcd82RUJ+V8s{D9k}}A zxhX5R!A`3HGBl7};??0*(7*$tITz$biqAd&biHmbmqq(nKA1v%wyGyS31+q)8bWTJ+*!v<7?;u!VxRg8FSwKf7~07O^lCZNRh4 zx~m)7-&3gN_l9MlLo496245d#7`M8ii)Bj{p(cm6AXMe!$b6BzimE>^`PGNbU!1WW zXN;D31gXE5dDTXvx``h?shlBMT=vAFuzNFtFzdLVYQ!Lssr?F69+L8M+vjt7g|V=? z*H5`ODgl~t*1?+3{*)VE`t=LuZXxFg60&(DLVw!dx5c*HsMD1mm&K==N6q18-j5kA zk}YA#VnCE9J#E*!1yoG+t5r70nk$Mkw$|^02nz-R#JhJ^xViG1pMJR!s3=qfh@;Vd zPe>oqN|$)g!><%7uWogF`X>!<(Gv}Ws-{XAupf@&{)#QVIBt^T{G+swurnTu>-ioj z5bi^zm}LPvUcSdp68s7b5?PD6Ny&q25qNH&b~HHOcOXeHQE4rJD6X}$!hC){P}w`} zc`Ydb#80J~T3jF1%PThndeZ5)l1B-H{8J+`MnhSwLf2MXr_)bf2k^^1 z#L(8cHGDDcZ^Blm4;SklA7?*}qX#1e8<6K~trFkk<~z$OjTCfWG>Rv&&QW({FXw8|6LV3)bYo6$;%MF2pLO`pQBZyVJRu{slSqMEh19h)y05$urE@5 zZWQ{6t^x3lZ~83dqyFLn4})Y z>mALCyE}rpB`XF3jKo3j@!_ z8crq#H*s|dqlYg|CeIAo%%JKRcJ?3q*gJQ$h#AgOe67RVMYcjPvoANiq%^2ui^H$) zty?%?wfVw~xa0>2xstchR+8mI^jz}7nXEgB{7!-iMEHfK@R7hul{v#405tPIZM0|8 zK0CD;+HiBtC;stZ(Il!a*zv2lob3w6C&hMz$K-A+B(4n3@CRCYiZE{VsK1s~Ddyqh z5;_pQ?yIv?2lv!l3PG^>S;o-9sZfePjRUeIi)NW8@Zhj*5YQWQbC|Z{=1m#sEr1=K z=Su0s*qEM?X0q5mj?qiswViC&q+XG5LUJ1jy{Im{2e4mIXqQ?Dxw9Mm#CCUuJLsDX zKE><#lnsJ4Hr2(0Tl`d4dnQg$=BdCIi-FJ>KO+!DqrIT{@lIoFdIcIEk|s`K7xX2H zuQU-NMp#8J+_r92e+x%XtRmx&%So4#ytslZYZ**GB?WKYA9NKAFas;-sm1*8fhBY2 zXUf`HwPUsiIsb)?VUGTWrWFP7qm@xMH!Nkra%EF!+YfwQP@jn^S`LjvM%64fePWYJ zs_>d8o*gYnkaaEGtR)*e?Ze?E9s5u9j|tfgk#byV2`v>y&}Rq21odg z@A>SjX}qphe#2x3lLyYtY3CwB$LCzOY)+xMvlcKG>Q|s-M9lbqY#mb?G`8q;G=E%Y z_Asn54g*e?rj=@X>A5s$lqNGN^Fc{Nr%<6~YIvo<#a*0d@RB<_|Ci%bJHqaY))d#( z4xWf*P&gJz@8z>F?9Ephkmj7Vgp~H8XJzcq21sb_t|%R~F`Jt&om8`xLj%-_{|%QR zfXq&Vswx2*#rI#t$+!so>N$)zp1+R3$%H`jC~LueJCy9}d5$z4Yvs+6J!8+riW^p5 za}}B}NcHWK6F35ffJI_0BfBA1+Cam3Dr2v`VU-#2*oZ)Ts)Odi~s zcgCFuu`<>b|F~9!f;0#yDgYb+2><|y06UYIkJUf`fEX+QfC7L7))Ka}bvChe)>HPd zH*wOTbGNZ3EC2J^#P2|G^QMOx2R_XFwgR_eK5vnm^V9P?9GgJXPb4g^Qag&KTSO&O;bK9B-E0dIosP3`357%=H`ZC}(Onriso&)0+Za@R+n6J`{)kT|Jm2v9ICaeag z`})UC3LIN*Nb~yH0eng)&~8<`_!3;^UzVIE4pl_j=Zhn94FnE zDKDL2XqiGn%L%N2SLBUAi_4H@l)^>gXLz{`d9w+|oZ(pnT3Q}~G$#Ry3QrAgg{g56QLUZ%qOpB#^{&YgwHY|Fj0oXy7_}!i@;m0Ei}7y{QKBk9ml={1 zrlsn$%>`2!70VKdet}8T-j^Y->)}fJuuLf)nSo4BqjoLCd#wbv+C=EqA27H}=g!r@ zgxtvo@2_#c4b#>XH>8PEVHbH{U8iVjkO-v9U2e1f^WNjou|mLp^?Vit03ZNB0{zwd ze{|d4(ZuNs5Dc6x>}>x}=f6}0=!+4)e(*p0Rh1|x_caJapCvZ?GI$-7@`TFd*dfbd zNI~}iWa*^nu{ItuL@gth`J^gnE1eQfCC4D zppLNUl^3S@6--!7^&4V!OpiS?aMU!+Jppx=Apc@&E=IEIC`(pve*#;cf?RA19i^cQHN{!2Rj`=NA^ zx)odSMHtuY>2Btp+zyB$0wi(`+*S<{nQ3!A{_wcTGL%KtHPZ{%7S;Z8Z0QiYu}{Be zR%*$?OlL|H5=kUfl!=S~EW{%tY9wPArq1(c4iV;ySdcjmQv*@*1{KWQhuJlHYDy~* zvMiiPF+?kTPnqvpeq6j)ZVpQ*FRcI%Xtwz#UE)CLrc1Y`2dn2uj|opwYaEg{t>-(` zvu+y&t6OoQVE87D2(`JK|0G&nGj~=ia_;J&m0&2YPOy!7BKqy85SMeT4Ry|^sZ`MK zWcuXp4I^Yp8S&qXL~e7$D&JTS>)3*B(v-Kjlmsk$r0FKVZY& z>rp{!ViIHnwy^wlVAI=~jVp$3E$!Xm5W>jJ=YkJbQ8(}F6>xJECyt@>kB#y;_zWgS z2!?zYLE4oZ{D<)bB;!}lyaYlcK~S6g0|_H8wDKT~%QyraAQW(8-?-cJ_W|E%35830 zig2jlXNy26utz?=Z7J02)#UOsc5Uc|zw&>Loc}1*Y;l)Pn_vKd0097i_Ag`WU!?l~ ziu8qsp4|o;q8~xsHQ|Ycm%gkL@;59Om=7D6pH{QR=gcH?^$h9A6l5-%sH<+P?3?6R zl9H~tUJ(lgAuZp4NF&?1@vnWKxdVLPyql`3smai+xM(Z^%|#r|6Gg^xn!BB3T8qcG_G#70pmY8UFWwIMe7JH&% zBr44!jGr~+=tGVfOH$h+yzL`?nDW&^r?3qjB{;0%AXSwpd2G{GG~-k^g{fPCohM-x zb{)+#H#P46q>{C;Z+%vYiNaZ1M$h29#bBjcarh#`p(IH?gM)a}9^VqfJ zAZEj3Br?Q!=sLv;p{Dcd@MN*L%=D?0XQV#$h;DQVvX#MAFsqGdv>wHHbq3`kenu1L zhXqj@)I%k!KH{3>d;^up0;|(&k$H-6v-oV;Z$dZ!XxE3tV`B~}2hc3SNdL@3L=lhR zr8C7W6VAcef!r`mirkTowISoxySnGD)Ad11y8`^iT7j<-3WMGzm<7HNwpBzP(K#@vY z8tBY7GF$Ce~kChk3V zngdmvH!*h&`!TC#dD~T+6VE_rAPaIwRJP+*)owLc(Cb3WlHW7e^E%a8B5k25-=deY zd6pu7<+EZG3!cOH3Xcj1l)YwHYSLgyFmF&%6S04z$TcY?hhNrxv_B78&&0i?D|fG+ zFD5MPQ@m9IGc*lyFl?;4{llcT!L5aLf1ElN2wkawQOscN2RJsk8cHSLXEOMB9LXIy zH!8}Tb6HLadOp*Xfs9$`6WdVM=9}!#v-n8rmXY)2+rH^EJH|t)(7JYTXaMRqi0Vks zxnSsWE0T%Rzv|BlCKQtd--IM5gzo|jB9Y4F9AY_k+KoQcTytIZKE%fP@NSoQqPEiE zmgf-S)|@{6I3p$Mrmtv>%&@`&~C_`G~@0e1m@$m!uDBs zcy%4m&8g&wU>~}`BS07)Pxg!&!~mzX8{z=o#R7>N-c8g-0vz!yaTRyitrBjRabIEj z33IkFLOm3j3%{6fvS;H8CGP6c7c6#QCzDkP(7uDQ(vUnio~~Gjj!m*RoCzUSp6DZu zL)|NrPAj{X+ArmN>K~O4d=Ti@fDqr)tO&aWH7PsH5qIb8z71pdd1#@vPF#*T&FnOp zIV+K8sFG>9j?oD=I@hvt+9(6usK(0%^72FURYZ-pO1%JcCzS@F18t&wXbPG>XVB zXPMT}(cJs7{5{e>Ct(mGpjO)+Nls8E0XL6hLgB20A$ALb#a_Dc2hd=U{Glzn5a!#9 zD-kFnxbev$JQUtY(n%_tBiE5^P5hDSj+VjB`TDlBVAuV z5-)W%cNgU3qbK&mmMcheA6Q>CX@QU7xEqqii7moDNMq278~`3L@r<;JkpO;#H-C7+ z?jCO+=%vf|-`nYfxbwuLE6w4V$LQ)!%okg8n2^dUcdM9xRATzJEMP}D=PT|cqwV+G z3B!fueJqGz_j#iIbHxP{h6lgBKA*zk6U#9u2Z9Jc@~dtenZ2}6>)RgC7a3hmnhWUT zhJlg`!Wtg_>Xj8H5aGNPxZ@X7`{qG9Hw1bQm!|9#K0uh$@}w=~5jzf}m&K*MU$b>;)SZp&3Be8J)u_nL45)E+GYL2GVQfiQuSqn`tdF8d>+Z@6= z^Ex)0q8QP^`m~`S$BCpQ;ifhmhi+(WE&fqmZ8X1ZY{g?~mDNyfIIo&yjq$ztJ-L4E zUd#6@i2o5w?FLJJRD%KlHi!TK@jpY6za5)@U^(O8k)2eZvfX4u?8Z3ZhHPJ;RzelU z(txNWKnJ@sTC|1lnnPZp7V#@?&2$L_cqHv#r-P`DJ;t;(z*!-g7xzQG9@z6?|dfoi^NCGe`p>t87McdKP-Px-ZQ2^IXPz zQn?M(`)PG#jw9rV{IphpEzI zt+lXwQ@lrqZbG}rrn^S85S&CwS=-|CU1jYtvB{ReDjT(n&8VrzMN-F^OEVkOMYBSR zCS%|EoJ&>L_5tGr{}lC*TxE}?a~a0&r}=A&nh=+!u<~>}W!Cq471g?Hxne}qWozFb zTas=x)qg6d>Yc~?S8*;|8*c|FO!YEjvL|cGbLGGLw(5+pM|1H{yIxsh(oZ^>F8@T4 zc2vE=>uhQ8*VyhY5L$(E+GwkX2N;l_;165>QcOXjd#jM0^mr8VJr<*N@nBsk2V z?+IRqVT5SL0Sx=fB1|M5FVBZxJNQE!i;6=GAO&YRs(PAH`Kwts~@aCo4dg+FA$ zQ%3-M9->mNE`$fe7G8zTCOU@LyG$Im_QBjH+U71-TD7N30Uecr9@l-HoFuKb!-6O@ z(7biLia5PTE$lZIv```EY0y+NA$peKAfkFQB`fP@r#?>?_VeEx>ZJo$&VKGa`^npD zg7V3Jpv9mNm;%6*y(|L$WCnnKju?qv!f58t+gCG%ZZZDLZP(J@0PHu^t-gMShx*Sn znhRJU_9YXujiBW979R-@ACSz<4)&LWY{p;4W(7!I>LSltGA8Bt`g1)y`#@rP!x>>AZ8%C z*dm1~%{!|`6--Sixk>-%RWowM%1ORmlC-o|MG0zKJEfjWXf8k;!MWlzR%sm~%IiC> z)0kg}e7ELGi=k~?Bf+LM`m8iVlx&m%Wv@m`AS5F&aE4(*F=Bza z!J+^ELkcvRny$RVZ;BP1> zJ^0kG32wFQDP&Du?B86=nHOjT2t-d`O*BnmE5xkiK$Z0dN@H}<*8tUMD>G}_B*UF-hvCC2 zjgS70g{$DoNAXIOn&gn5?CWzew*zG*x|zutn0mB5X(i5nyvI$rMD**PB_Q57uPjBd zS+jS7X?Df0`!7IS-h%kEY$b5fTAAZz;Kx^CM)G^G7C+XMd~u%)@65+0(*H0{T&#Y> z62qEAWHX933=~dUlM}G!m$n}1NU5Z?<3E-mdaz<-oVvTp*GlEIdv~RKx@*R_V5*1n zZ@Pi3dbl&P4*g-{0SeZfO?a^mG|7Y@YHO}(iu&%ms~rag$SqYAHHf~A4UiXj*fPlU zJ83Eb%OkA;v1P{wNprkFC+QHOq+&aRBUm!dJo*7;6VV3xj7RXWpf97D_y|P zuLYQkVxkhPTHkESw^-%|Z@)eLlz5{FH<))sTyXa-+#MZCVjsdap^FEFw5EOe4mo3P z)}_en{Bpl^R+zOQeYz~zh_KhE!8w7v@~q^K8zDk)7mQo?wm`_u2i%|5q+u4vY3$}8 z(RYU^O8Oxb8m>4kZ@qEU3u`2PTgLa_cFdo#W2IhII`8EXr;qP+5fwau7-XpMj-A~YEO@E+?^Ow9U+V^g}Qfhd@G6N&o?(M}UDMWr8 z8wI0a#NzCeQH1*>6jMqvQ@7>N;e(;cB(YA6M}0FJk@m=Jl_#yP6;)zf-%P6Ks2kvA zUJX))(2@#3fPOCF$j|!Ynj6b6#NkG)-TeFa3K})_@+KLcZ*ftS_k{;rJreF4=-z4w zwJqU0|Lp<8Pa680&Q$U(?VA7>KRU{vXnaW5;%^`9;m@7sUhL*AXjw{A4K-LjAg%A3 z@-Gz4S)&kX1~_FMi{d}f+D2iCN5Zazaewmz;Q6J+C*A}nmmHoZr^p&6LCxx|88spq zh$x|tz*gXtPU^}{)(o5%{t_-s!gi;)*SphelJ4iD1^$^?!$pPv*-Ol9n!3Qb}crgSg5qR7`iL7;n4(yq=ckt`s5rRZo-o zDy9+rCye&@LTFNb%XWhewVR;M4Ut9PEm}14ZQ=~|?Gn7mqTU&ySHhV_#;?$P#X>R9 zuHksKuA^Hr*ElT6m|J$;Lks0)xTtJk;QHp>-T8!Ep54Wys_kT=IX&}bkO^-4&_H=&hJxT&N9KC%y4@$h?Fgv*~J* zFWr~dW$o0I$a1NF8#A*F3U#||Cms6$$Kr56zZ+*NmHw)JD)p3ixzQqEZM%S~0%&u~ zeiU`OQt5770jI)BE0C-Tvzccuxc<9u`htY^3;lBl8-ND|V9d_?NdpzBWg+A8l9 z*b2>uvW(@x6<+8$6Nb$W-J#_6a-lNW5KvoM>>*W>-PUX*F*YYfLm*&|v_T=BgU~&9 zxH<8~6?@+8037hEd`WR~*nOmzocQgkbIR{BrUa}2wHCxqD=I){$#p`}pdks3;4(C| zy>a8ni}K0lf*ZtbwGnvc$*wVm7J|EmbzZ_d%)R-UGCk<}O4+ucxm9tYHV+J0BavQ< zBStM~p&~W)u4KQxr{)H-d^ak$uhoy4-Jn>KN(*FZCv&x&fLFe^D6;%P$v&xQ0Q>HO z^ZXlzlB6j|{xF)^e&m2aVHO-HY%F(-Uw^gmYXj+JHK{=u*C@JON>$(ytYgtWEX6QU z6D6@NDv{IxASB|baPnKtapJ1f{K?)>`9mInQuKo$Mrj10%*s!)aJ8Q1f}m<{25O-! zonz&-(i(d7qN38Qnr`>L*zEE&MZwB_t3^e_*hJ+NLKHKO+Mr4UjNF;om_dWh5%V@H zd%I+Y5rdSNU>H(7ygN+#YQhiEgWJ zs5z`@5Wc^Xh5)7(m~-Fd>E>-vt;5yZ9c>h;wqrm#yw>USc29*+ymK30H*Ot*phbMB zQXtm-15X$1>E`|^?XL&z>cUoBIuCg4pbtMpBZLsZH>h6xiNW{`^m@edzsDpnv{k%+ zPz~|TQ-$o3-qvYO_p=q~!m30@K|z0KCqjbCVvr>0mZB^we+12JN~=f~B+R8%dl)*4 zVh!<~eN*q1l^4%!W09s+iD<(YWpUMpT#WcZ;9-$MYLT$_vgPbVlXlop<)Nxu3+h*| zq}JEb!1Sj1_5Vz%`rJi>lBf6qYh7NGf?={;%ibnHmB7!E@BgL`bRz3BsYK}M*)ti+ z^qHF@LDNY=9BB?he652mP~6RrFJhAl930NcTqSM9*L8-W1Yi1SHjGCcB<=JoOZ<$v z>89JbO0gMD=(JFEnHr+)&nEe{IZhk~$|#zW3fNl=q3$>i4M)CMYfjWe_Xwt0P#YSm z=uUOI1B{Uks>(D<6sOS$vdE&K#!rgI<|?quGLQ+j%Chl#KXWj6+Q+`W{E35cxV!zx z)gu}@F?|cOT6f#RSwayFkT&EOLMp*3h~TQjicjNYD|R>xtIwu-bWYn=L4d_C$*J*~ z5?x7olNYp(0iH(#fd|I01zucXpG_ZTYtl;Au6W6>9&}pnQnyN9d~+f=&zF;QV%SPA zTP^hyocZU)tT2omAJs2}l>b7=|4fVjw&o_)CcX#~bqnK!A9CG^RBF*G-XRYo3J`0v zXp6BmhdffKTA&=soa2B<=$CM9KBx1CR8J`(fyd!uII$nRlZf)}j?aC%t4OzNo2{un zzq3}enPG2|4Q@QLxoUN(|MwAa&@79mpt|H)%3MfWVb|;1$q0e2%Y8Rp+*pkcjPRNM zM;6UwGUC=|!<(Tf&iu@JEK^&vwTE!9~YGstE! zkBTGg%Y}Y=sHWtt@OzAFkTjuX0djK@;RJ;J(45vh%y_R8odWKx8K@={%jiLe_>P zqDMenZX%FM+g210&`Wl|&-a~Q_dv$+d$|1}wQ%O8JvO^7R>hN}^pu4V=Fa#lX}40| zVPek?F+Hkhknqdl_$%T39|I{n3a>trAtgoQ;p*&ej^jT0oJXOQvG%(lsAdgN3jk7z zDZz{W&A0_fFFNl(6`IhmQf)te#Cw+Ge)nM0HkD5>m-g5@H?NPgw;e$W{{R4yUZWr$ z>q7UFjyj|qVTGQ)pWZ4U3yLl&XzNsS^6FHs^!X5D`H;+KAiHJ`?~g{9x^g6n<6TjH z^O;tGk+E{b3R!Kj_sD{rS`Uy~Vu6MHEYm9qz~t@T^O*n||!Bf&SVn zR|gkgxovBk=Fbtsi&+}b*->~5q5bD3t11(Mab;x<1tSx4ow7fIijf0^Vul%!a}`22 zjfj7S(7E8HdG*0XMJeK>kM-AmSdZMx#n&}AZ}7zS?KFK_Cr<2%RPvC!9F!&i5+q3! zD7^j}$b*|OiOe9Yz0FV_V$SDjbZlUCp=l+_&8GMhCZ8ACTzK(-5LyWGV-`v*4?N|f zOJz2<^2J2&zNLtJ%RGbSZ7b=lTu#vmaVzRelnD0zKi0LVE}U-=Uw|l%{GW@`zj%0B ze~Hou{VXr!Td8=FL?pH`?uiDfeO8_;I-xXfoI;nB16eZ&$eQHJ+#gqR4M|Cq@RonKkn1-Ey5HtjDsSZ8xB~kS!H+zPYy1IN`Uvw*QL36#%VeD&N0WGg*;0-x8kv!b314)$1@) zdhX~3#Y%Jwy0Q@=3gvYiQnHS9ZI z39A}r0S7`}Y}=Tn=@X_#T#Z^2Go`j{J?fE~Efw&~L;b4GI%hlS_y-vC<6(W?+!?jo zJIw5Q-<~IPWN{{4*_Jfm`nF^tWKYw$)Z2N;VheTUkg7%7>iA13p(PUx<16rc<-!Hi z^a+YaO`z`PA=@4_YeSuLU~Dm8o6?fNPVw0O!GcGEUo1#N=0ZtKgdee}=xge*kF-NV zNXh}q5kPqZBI6Ii_-KgCNPb&00$i3>x@^pdbB~9T8-CJJ$oARQlA(%J?1AUrkNCBz1Jfd?m~yGb>XO>ABc8aO}S|btJlq zp6dCSZiyDBkyxwwc#{p6ra~`&Xfh=0_q|U}zI+-7rDv~YcVcHz-><2zeA{K!Jd69m zje+aKr~%nhG1@yPp%4+>4b-wRyGVx!ZOW%FsaoS#j+n)y^~89?d^_3_Saz%uF93k>&(@UD&W zpYh>i*o8W@PV&*?LPM=FG!J5C-C^K#5G)DYS)P`8#Cnl3FZ7uQogrrimik$}(BSQh36r*fhqFoRky}=sp`#AGsX=y8}o4NPoPTBB)>QkAnE-Jq>_cHP#+s`wEN`fN zKP2r>-*WkD-8F7a)tq0FBc}%>N6QNOoc2+784CO<#X$lviUuPX~f}aV*Lq;I4P1Z`-to6BcRrLgX?Ty%cR4UjD zBCqnl?7<1Wk^SBC)E>QFLm6hDTX`4uE=690lkceYh{1@J5NuDph($^MNv)XTL@>nc zb7!Z7-Ie&PFAR^)m*jNq%`AT50%oYQWR<9b-5|VSFALHJh+}N(Q@J=3`nweJuWC#e znp?I9Z0Oy3dDnz5%?dP9MZVDv(2^0417=3o9*My3=pCya z-D5ms_(}=1sETaTjlq8H=|xo1L43|0rSN`~@$a`=y49r@%@*eDZKrlIE`_h<@%A8J!A zRNUq(N+l{eDg~oGJ*A7ktLr)bm^yT6H|O&+bfV4H2}*_q0fNAz9HW_Rbro&A)o&LF z+B@wqnAnUx9B_I3!AvGTwDjEBUN+t4IS^Lq1kWURC_rrv|C9{8C^AuE8%52Ex$WUS z2X}hnIql>Dc5j|Xl;=*uAC@p&6OzI*Xe=z7!q3;6NmB^X8ny)!+Lb!4!aBaC7rRD# zY(%B53dGYQogt}a0SiHuy;Shsc4*;t_n3nX1bIk3&Y;MMq}LPCKt4`(B1VQBUUuS- zC|}HlVt;!7#YfdWukp?Rw>*mO@{x8HsmV5%+_4{kwZHmVGQ`gnWCuovWKkITool$c z_FebzbeVJzojBlBbdSE8R^a%mLY2`vb$dN;pr~eg{IFp;5}6?pksYyy6I=VJNz-z_ z1lTD;*|_S+ifl>W=muiWl@^0Xtk79IbZfxoVP? z6BB_$Iv6-ow+|X;Iac&^(OfBJ&_!X|mh>34#-FbU+1*#;ZX+P2i~j7kR~U1kBc#1= zkZ~{c*{np1nHXk5rj39WIi4AxG>}>c8dBTu+qlQNN=sQXfA)+I;6R87ggMlfgrSa#E?j~2CI=`L!DUiqC z5piVb4tQHpG6e?|87I1kA?@dTvuxTU&pLN^IrQ~O(2{;1BtZV!iL37<04-3B6t5Sg z8|%{Aq8`0+GqhVMK>(Sj6zrx?K)?AX%%59H=!F7G>Qxldj5z768)Y8hf^moUZ-01` z$=n-6ezy+3w0xr7^AhK#%GjsMkSSN)wdcxJfyk1V$PzzP$y=SYYfOzk+7;4TlP2h%0KGm0I9Ia|7@2oAWsyK4?5Q(W} zBHhY1g;|9+mRiHg`~)SnkRwg4B&2L~MlaQP62PIU$t0663NfdEXN<1-q0P+hhQm2< zC2P4#H6QH-UE!Z));PRoh%@qI&#T>zTYZG6-i4o7p#zval04BIndD@hD>pANg2l|C zUESg7pdw)37T3y!u0MLtFk5t}{4^W$3d+5`BjTiO6W5;}wb5z3oMkrK`o?QN+xZs1 z*7yA}r5KC)jWG^^(wb)YcyuzoBRcad9<0PJ2{Q z8@TKax-DFCQJz=pw3lcvpuM9JU3VOJ-DscpLjJ78uzTUz<-t-%s^ly5ZwU5N5!$#iebkQ-M6)fEbJT2Xj4xu^+4XD@Sbr@a zEsKkV9|)kYxzF38O|33RaQC^g2#!Adc4@2LQ-LKu8&i3jIR5nBCD-Hoe5OX#a5z8 zNMbM=Fvq%}I3xFX#>g3ks(2qBm>cT6qJ(%oH+0dANeX(ZKCB0p`90ISmGFt!ln2>i z1heP&n!$ICD3Q4NEKK4H{gsA#h&kp2)IYu@O0%}Q#3a=RDwiMlx{C)Yw0-!xjU$!F zYxugABb9e^__~`1O$2-2cy*7FbUQ{Wr&*tFxOjE1k#t+)LhcrLC$)NAh7R~{_BFqy zYQ`Kn98Y(Jfxn)TWb1A=b2g7vQk64#s)GJj%Fdi<{4D4SDgQZ%x_3N-WwHD_aeSV0$*p;p5bK7EqGIsU? zsM2Z6EB~X+&!zb7bp4;a?X}l3q%PF&eLOujA5tpaUJ8dvxj=)a3-G02q|OW#+eq*b zl!`4HO=_>6`a|Cqhhtp4bChP=3q&;rstvG#e&S=+Y!Qf9CPx}$E$~bkcK`(&OL|NV zwj0W-5hEX!x+w@dfwWyB7yqXA&%#CCr%wTN z6YnGcLU*tV;;^=$wYVoaoC(&(y6h!Nnv|H{yPnaeZlvA9ttDn&7lEJh77vhu`}lzq_Av z-RxLU&@8yn$MvFuR@}BK4t%`{LbT?T>hkMTz0r4*-{yH+@0nMr0CAAZRXG3l5z?+& zx8?{ZnfZ-u)1Efvp0bnfGMnxZ8(#+BH@`1m{y!px4p$KL&o8&g8s*<1#XmMwIQ`=U z<3Dcx-n?_6{;%Akg#?Pog6P#g1>`7zB<`Zczt}~!N?G;UgaUtxcIFB?eoJ;2k$&^o z7vFct0M#`nQCd7Y>f$+8Q1g6v=`7EVi5FgKg0QVS?ua#ys;OFE0C`SLg+*M!Lba3D zb*tvErytzqjHBL0KV1#73}mPPlbiEoRxYRG82;a0e6j9gJ!+x#s;Wd(t$-3Q&aCnfmh z@N_qJLi>qJ^H~))*Xx!`Rrcn|k6zxza*Pp|)1RGlAU)X;;~w)h?$yCQY!CFsh$Snw zz6l==pF-=DGwk$5-;;-jSe713AQIENY}lI*bTWOp++P2@DzTL;Y3*eZv|`u8I6Y3L zaj3~L!lQ4@8M-(}+0>8Q)j$0L>qJ0j)%e;qF9R`s+F6xUhSw;_7F!yWL83Wv*6TBc zS)@3PsNW6|FOQVRDFp~38Z($w!rW&!b@hLSp`@XZA5Yf?>IO3Zj@E$FUc64-ZfZCz z!w_TQPevn~RLh(}J}d9oE0G2aT8K#Mkp+zXPGJCQAhMQe0pdLAWYu_6;$1puMi~0X zLhUyrhfQe!Q)_Iij%KueMzh{jaD_50S;uYurL~)fVE|XDj)ws{=Ug@3;rnA=?2;($ zg{&PN8*F(%S=*cyr9evDZpDC^w}KEA$hd^Zv536~@q>U>0?v09Bz3cGS4F$f_k+AJ z<`a_pFkR}KOKEn$bplJlR|&cRZL9ALI&vmcibisLoHdzsLlhXDLkv)i1RljB1;i*S{$)kM%(LI8ijE~KsF0|;w5RNwSJMQqL>$7#NLlr5 zNMltBr(L`n%iFQ8DM^j!JJ?NNXy4`9&EGmfhMD!(KX&x!MpU3*h80EOQ=O*KJzz=! zJ&|;A&41$;#YV(5VSrtrc$nKiPqZyR9Bt=c(I%jFB-_SQ+3^W~Hkpg1pSwDf`gz%I z5!?yP;hX1wjP-;BjV1A2&u`6S5dx|Jsh4t69d|x{_V65pZ}I5f#fkct8!BwB%PI{p zzi4y@NvH|n$O9aClp$Oq)IJ9cNCrJMY)V0`csBgXd$`l@{n@GQ`OhW4-fnpP)Ng6y zZMTigRbh)j11X9;AVcgPQgE11lHLNu{G|de0KK`~1;s{s6Io;eS4cAof3lulx zz&5Rv?8JeLflv|Td15Kng{-p#nZI4MCd@kd*VQvvnr)>n73|75Gi+sLuI}|320s6( z9=hnuN~3JGm0eJq_2emK z^IQ{^3teOMBaFK!m6r)r(vj`RUWqVsa=KTaF9T7gEwl|QW1?LrG$D#j9b?md?pe`4!4>cJfp9X$5;Wfh}g{bRk?}=>hOUlW3D#mjnBj zU?KO22RXF#b!`2C%SH@3t#LQ|E8@r~xni_nl_p?=58O9c2azO9JbVbq@kE>#XMRf= zT6m(;ItinQor3mWdD({d+;zSk_a~#2Og+?XZ%OkVNVLyc2M55R*T&x`9N-25Dg+7D zRF2~n?}N)Gu*RbsgR#)J(|7wLyxBviw5LT?g}Q*Hme($o#FOcyh8}~;Ei9_ zsA&R+@>lEx2m2;xl7L7}0-Q~O52kuBJaI7BO4~(#=GN6_Z6gfthlozha>7=@Wo&zt zP+F$gCnj@IL92u_-6$wzq3@FIr|i6|kZZ;jUse^$k5QC-E~+lm9*=c)5H=lJ%ZpYm zx#{ApB(E6g%jf$dg$a$52MhAsn!3!}|{V>knMjsr|K{)Rf*R*4gIC>h{5;lp6 zJ*@{Y%CI`M87X}!-Drp9^C*&$5OXaL4awwbtK?02&rwB-k}jIO4AbNYZ<_=KT@xyT z^AaF++%n;j$??GpGuAqv+IhHTA%3i_P7y4?95f zQBOogKDctHPzZbwSzt>bD@kp?Wff3LRiEQv3>-qpk~#>DP9O1L`C47r-woA$Oc&Nu zt7Pgiti5+=Rl}P(4RCeXR{kz4`jiGcBI(0t8&-@43AMT+aIHM$EfT|2$~}H`!$x$z zDyO8IHKj(!5hVxyYiYrPklMJ&{=AO^w1#I@JDH7b33l9{5jh-^!iU%S75%p3;L?g#8mZQ1#7z^`v^>!0BA}M~06tWF=N6JEg43m_ou85)rT@un(&W+p^#D=PgU&&X2Y zD#0~?SMMe2<**OHX@%vOL|7EAl^s3k=4wlip9*-}4fdASXiACCov1i&uoS*&V00fS z(n?Y@Oy!$f6-^r=Iv~n3Kn0n!#&~f>1s1QCcE=2*u*dJI8*lHf()3~o{Mh)VWwhD} zyTdeVD!S~2^Bq^b`4~8k3D#bK;)WO*aMefwKR^*}aO2?JmHRFGBn&b(E-(rs_tTsHPDuH@ zz(`)%Il4UyS-$#;*+m}|6)06K5)J1q-hN*Iov-`EG<#Eda-g=8peydCn||Z!+lI@J zs0z)b;&?U4WBJE}NIWJfLxREhvL&53kQq1S5X5*2|A2!*L|(oI<1tx&N34@U z2{90tfRS!FMh8gyqK1knLuh5qAr@#Nks7yj>vdwaZ`BR98@TsJ3wjWa#}lPJJ;ITU zskfDft=A>2WnV5pB=8jofuW03a7F9Ap_G6OuFBQxCQOz@Wof`miKp_h>zTzFGf^hj z*FrL%7t%Z(^#g^07@h#8Lzk4=i1o|p@^PU(%q-&6#!gNuv4)mWD@1VkiJ&&c5D5Nxv@lL{Mph=q*J0SAD z)u@&Iky6B|1p#T3oSy4`BIEq4#KBb$gBb$%Vj>A=Hv0POonyl7+Ad>#-HB0Ir=xyv zyoq)jT}Pv71?T-)8k%?mo775L)s1#%6@qW|THg21sZJ06*&PVCbK%cL{L4C194~T{ z9@nh=)!R_G%9`V9%?;NA10|nGt5Vd9#PyDHycw7Jg}RESWB1#v7u$|%=p479)f-j0 zOh{ek@;d@o6@HqI$C`Sf&W^OhQg zu%(4{bkt*3jSLT|fljd;#i<1)^lh^ZLOhn55@BAUD7~sAiyt`l^o&^+@f=ofTq;M zjvWjTrbde?+FZ;ed0Gfi04q-c9KVAq1sV$Q@)PSyFwcy*abfSf5VaB=tvDiK48}p) zR0uf>wO{2k52?wC&ijGO>VC}b2*>H$f7_AV#@_07VW9Yf%# zGa5XE`5-%hUIg|dtmeh2Ze8xHz>)3V@tiigXw>6HQMP8M$&zT4Y=$mYwx=-DsvioWPrCU$DJ62`s5sEKR#Zo3TNh)rf2j)E8_2ta&7ap98nhhdZg&Kl$( zs-^c=s_^x!jIZ;oMETx=AoqMF3R&$A!JN@t6jEzpUr_ zjN6?h=HU8s|Cpl2YDW+`?N?YJy+sJ8jTxvdDdUnI@6Q5d6d&RnT);E)o6y5&&Zam` z`T2M>m}-T%^V<_x@NE>%BL5n)6pq5ywr zTk1aM!p$R;ntbCzy+?x6HCl!&@D}WxatmffJW4{)Y9S`5Vl2ZL(Zl{>_ZqB=isR5p zqt|2$y|Ac}F|j!)~%*0j-co@H1Uy_hg0oC^5>krWleADmA}1N&RL{7+BM zaQsSftlZL^?)O2_9hF~TFk2b|UaEH1(S;1LMkg~ovc#NZmFYdRH%sbKaaH^qILR!( zuKActbg7*jdE3oTCZawL_5LYzvcjJY$A8JgJJf$J4}Tx4omBl-`+BFBViL+kmji5R zpgEcqO9^@uQ&P%ILQoVViZ|jm5z`pj8o#Bh-rW|I|a}u?>1Rcv< z_Kd8;J@sA5R$864q3x%3Y){vAl*G-flFKVqc%I$$^4<-4xgWn5Djj&69yz(;yetG` zeKi|nx)L3=xu=yc-A78681C?MY#`I%MVY;^f@T})-AF_ zQTgj`ovBX9eOhGse=Js_6UW&2$TuinKrNgfR=$lbK$`C~Rr%Rzt;^!}?yi~ncedMF zRhr>pPIF?cv&Gnf9b2vt_#z!Vx_|q5KC~yLE?X^>inyVHPh+ z&DA6XQFSm3ULbdNMuEdGRhbd96x6h?!?&k(IZob*=j4Asln=e6y=lbJ9q^r@?Yabs zqIIiY)zP4w>@;JV+@fM5%GAiOXmO@L!BE5?tS-|aDValX5kcZ~gylKtL{8Let{qwX z{?5wg;Yc)&<1#}EcA+l0(((k|0W$_D8(;TC8O?9fK|(?Z`S5^Htd)W{37K6?R3Vh( z+2RoGc55ECY^@4Aq)}flLti3&_&(p0U*iK%L>X%af6Z%ZxWsjZF1v)hU8W__zg|rR z8-8O79o@Li!%#;dg5Q|WS1!EMR}o{qC3mNpqgi7o=CT&Z!m5dFpxJH_I8QMQd2A3o z&oqfNwx575s-ZyN!z@&re%NrzVPpFgsCQLdq5xRA0q-R(qzvN(D0)t^Y}$h zom!Q*B+_JMi@liVaeYorwraOyoQ}g|nFXF?RP?kH2ot?~@+X(y&ST;3kM!Itf7wYv z@Gu`7a?&7vIGsF$RMf1vqF@8*1O-&Y^M`0lvZ3l0ffrexj+i^yKa%;tt2wNB&!^{_ zi>{lP=S2{ToI!G)c>Moq@2lgY+S-4I4rwV-Bo(9^$w8#MQ@W%}q(ee!1Vl>nf0CL+3Q)kpY?pPFoxHjtf$hEGN7Vz z9*IePiMYg6MC9)!xY!o&z1m^2Q0VJn?iuz^MrblpPl89JK^1?MTC~dx7Tmx?Usq=F7nHTd9`49(-ET zXy~^kpBFxS!?eGd)*Zr~mo%r$Co5^H$vSra)q7?3(qWtGpOl?wdK9V4*GFalL7-HT!?s$;IU z>RGnlZZJML#W;N7*7#!UlbKSjefb-MurFNnl#J-?suN+UGNJeBg>0Fe6DeN`%)_U` z)A{y*Qb}9yOIW;VDU0_ldkW5+#-HkgADeTI3S%i=&FfbYei)Y@+fkdFg%}d7;FGE0 z+w(><6Z1$t+dVceB<}lc*|z2L zTz=>t)<*JX?4)}oYTTv55x)HzGhEPa?g|}`GdZJV{+5v`I>wUQF@;yP<8GPx zF|Ak876YZcz9n@vSELoTj5Dw(LaB;PPae8 zZs@3o6T~%|Bo$UU{*W_DoPJEjZlJTd+u?cGxNxivnW*JN`DYHzwonjL0#Bh6F%N7* zv!ia0!zMB)(&7tnc8vpgJ2ds07)H0qavU3!UXDHqx2>_Ar?J+xpIx)g$z zd~dk>*xt0lw^=po9uQ5)%}MtOKY{mP+QfQO*l*x*c!;O{pddh-i%E-hX~GO^+(5F< z630VQ5>I%=Wfh<7)oEPj5zD= zqBv4;VY+?v!!rXu_~}u+!gPDTu&%c$;-vGQ1SPgdDcl);PUI0GvSqwHf-CU0mJmfN zS8|yGnKQ6cAandBW~Y0U31wQdyP+H;Z2zz@SE4nS=#!oN)Oh^7Nt|jbvSQF<{1kCq z@=YdhwMAECq;SdF@k12xkNgG8`zk7>=k1=%dFuylE&)vIcEeb^An|re-`Q)PnLr@@9%bDOV=dB}z*|OZ={0O~{p>qlM{r=-) zsWK$Rp8N+0{HqmXXOl{45_5Ow-GFwVy25a8t^Mmq_P&K2m)=|Zh4vzgzIq7`Ep-7t_??$M%!y!#1Klyd=jFxSG(z_~V2jX${JbZ8 zPiEzL3}H~|K9JsP+@6%Beu84lgaNnwMkaT7NaM83CCQfasH6vhz*2EFtl>QuFxSgA zAS?D4kJ$>g-Bz~S%0s;hAOb&=+~c;Kp(~Z5(b|4GHB4iA+;8qrba6UzvHREUKfIXq z)f=GwhyMrd|Bv_}-DLw@qGs6ozR-F>{0|YTiR0$-yd}MemunJv`gK@K&*GBm zs&PMTs1%D`jx3e10_C9csOtGAdh2IocDD z7gIfw$U4<#ofd_eaF))gQ&UI9p+k8h)Rzuptm(6^j@~krfDxB&uP&jj?(#{B*rfIY zjYi;pvqxe&^^3@NUP`4PTS3?+-&0cIm9Q6WBNFE(j5Ksx}KG| z^F)g}Ylfl5`ldhjGh9?sJ^QFYg{mM3l4Mdzb!9-lV+eA#jXUReP-r`2V(`j#c8OE( zZaoYA;oepZ#IE|&y-iaT&2ZhMoY3!qr1~DS)#(5mM~)j~3);nfgV#LsE)sdwh6W@Q zzO}D}#E4CT$J6ZuwnLYs$MMU#FC_Tz{D6%P8l?yYh~3%I1p8(4>9yIjYI2P$^;xr! z1R_hHI*k6Uyk;5C7~bTFY$;cX#wQ=p4BCfO)fp?_YA}5%E6I0ym|wB}oNc`D63)hC zJ#n2w@vMw=k5a5wl*b5r2Vecu>*9XasE4gFEHS!R1I;k-21tbsUr3)Y+2Vxx23N^4 zN-sHAeT?Bn(Rrsb!wN=AP-Rj!Fw>W#lU?)h7~Jnq{jt<|0Ba>jsf zg1K|P3|-_A@krdm34st-b4K3gvOTtT|2LdY{FH{)yu_8QL!=bAcO^W5S>&oc)d^*WcCibe-if4UvC@Ri^vGx@UB2e8Tb*;_xFe8 zpsWqP2;306ddK~Ar^o=Q4ELpvVa!5B{K+F8-#COWrO?B}sfBT!U8GROHZundbZR5# z$M;B&DZoau*8US77Ej|f^3PU7Rz)$a7b~VK`bZwvGW+x^4?uG`i4?h#IGczWFKn%S zd8XY#*1m6!TeTYCoE8{nVQOp%c0tn>x12!M-w@o!@3PmRs_7UUJM}4PZtWJtZZBrr zK8$v#-^y8xJvYM=<`2|@)pwYLp$z83daMUeieZcE3&bqEJgn1b=gCJ!S|%w`wr7Q; zpT#nYkk~sga~4ZK62DEg`$T{bR%}rLi_!{SZS{faJt|w&RLr4}`gY1_qn@FCmq(`? zpX$11qM}B|ShAf)b4RFT!#x)ZDN2VeC>|+)nG3V!Mq$wMfNT&m(oS0h^}460_`GdK zF-C5tGxBnZ!vf1Z@y7|)Pw72ia&sBz`9uiJ#aR?zlRlhtU&%kv@pV)yt7V_GRNhZl zA7v-t@f|Xea9ZWTu%|%9!KaDdBZH?yrAFpUEM)Uf3QEbKswoIOFmh*HnQ?yO`tB=y ze}EW~S&+DaKm;Wszr-UOb*bk#PyH`-Ex&uy9mpw{7qq#Zot{)aKHuLg5oUj4Wq^k?+m|3~85Jg-c8_64{f)B*%!hdOzVbiSwu`31|+<@xAd7ewba;<(%DfO`Q75MWb)hh+NiZhauRUp zY=?tjW3psvsJ{f!Bx@1-l$(WM(guR&;N|p?><%Aa?Z~s*mqdCSgbJ_4z7=(;N|YfO zBnHdhE7^4Y;*qSU8SLYP#uT8}r7d8rGkJAcoTK~Z4U_l#w_#r~o_{46;xn>Qx z-%8AJyyT_tA}Q0opFYamK(E=&^pNVQQ>W!ExYib*_gV@h)fKL#75GiOq8t=ss)?Vz zDd_U%QF9Rmk9vnLaF-ry)Who5g=~ztmTFt($-;Q;1Vuf3_9EdZaE0#k9l1fa)$P&h zk)qdqs|8kbllhlJyQuHj66oFPcRq1+dqt#I`#JLT$f%AL2#6P#`4vP@Xl3Nj;ZZkJ zf3!-Lw8~r0Q>lI}g*?sL6rVp-p!$9nSGikAm7L_DMlGlTJJ}sZt{3563%*YGEc_|# z3QVvFuKEQvvhZw=fK&`2gR;bxg0fo|ShVz=Xd?#voi)RD6V0a)VJ&Wf#x+JWxEfn% zi%UTSCSi$*e2}Znj>zJ+dWMzh_mgn8Z=+nVhB%>@yPu9utig32=XrPficVGQ-Hz77 zz)(rPvFGk5nWIx&+qHc*F2r0pxOm8P7PH;~0JLdN#{NTmxJ6e19A#bcHhphMvny|`OpNEs* z;9YV%J<#ryDA^j=(CKTmW9SOlo!+D4!0Cf+#!hmMvz9%2yB3hjz|u;4oS{J@tYoFZ z8o)z0I2xUE#00OQ*1^x(w&86CagF4AXc#*E1hK9(SZveUBA%>a0^YO%?Nug=)S8O_ z^KDt-#g_{D_Nm{5W=gW|2Hq70f`8l7CWTD2T|F-CL&|YssGIJPd=#%NbKk1CY!8_@ zRkprl&D+@xxy95@{p&Lo4rp8FLu;_kC~Ndlw-MjLzS8Tz&?dtiBz$ZJ^cT`onSdJ}v$h5)>cBG7YPKWe9h9J}Jp?4!_Fq+vIG3*pl z?_|x!Gc}`h4pzN_BM0o99jYI}gJj!;&q|31T8Lyt%#RL&Ba$VrW6UJDts zBnXWNq|_1dzVX%g>R0%jNR2J+{2Bhb$r_&RV|4-TfNGg0G2eLPwa#j0NqLh>+j5;tr4^d_BKAey>hfhf^`y>@e+7nd$IdlBO}10Ez#)2e~v8c18R$uvbh|aZGx`J7z5$L3J*X4^K$hKni!Q|K* z>YTHWmsIkHmx#dfc0Gd`CR|664lEy}lKSjL0LP;D)XehNuu8k(gI*L3yG%dVSy6>en5|v$kbIF35u9|$S^B8S;J_0l+C8yM$mO~Z05Ex|5E}!tO5`pJsA7cuEC} zC$ba@;=lzkL&YHln?fRd(epKN7_e2J=(=p1<1tJQ4KY%$L$k5tA&d%D#9_aHN zEcLDQOf4A9Y>Z5x-;DILsG6DiTJOU~b z5+X7hDjM1?)LXaEF>tWZF|aXi-NM4h!oH1*hlhuTNkE8?ONfJuhx;7_1`fyrkAQ-J zfP#yD3mx}=oS+RLY-G?|7!Vu`IS3XT1`Znr+6+YB2f-i!(ta2CUkL^lkP#6H83pwg z@Pkq;5G)KF94tKCcd3D2y93{Y;IR>K$e5oX-j>%xBDck5c@>_FOd-Ymy%WA z&Km_4pMdZV(SwIn)Q@P`*f}^Kb8$Zv5*85^6PHj_QdUt_Q`aysG%_}MZfa)#!r`T( zle3GDuixu8{sDmzk?*43N5{m*rKF~PO3%p5$}TD{DJ?6nsH|%G(%jP8*51)MI5a#m zIyU}wVs3t6acOyFb!~lb|KRZG_~i8L{JUP?_53saq1X+*umQbb;o;%nk-qB%1M3JJ zaMth(f`tu#2Z}H-L&y$u{?3@4IS0H2Y_YdH-)| z_HV_m^_lpFjH)>cJ*aURK$@6>nOk z)kRErovK0xO*a?u#^6R9*nH=V(-ZH?0tz}TLfvj?Wo;P@jv9LB$!0&V8G=$;o4Dxa z4h5mx?wLbgFGE3%mWfc%om2?X!u;43dJh!jJqd=eYCjS7=(vjahJq5Ap`ZrUGZMI? zT+z!*Pgg$A8$T7jWN&LJIKLYY1tFAqUK&^EV4U)?Z-KX{B%;qeu`gLJ6jWhbs;DtnJ_7^%9YS! zjZ?;aXwba)rF?dRf~KUu0wTxW)6eQ^;TI*(_K`Hs@#|y(#XX^*_UZ-9^Yd~jsQ-Rl zVL?Z6pv|YS98|LoP2ttB@&*aTFM$(LN|hlCx2}0ZxZmH?mf|+)|-nHqEQ6Z=uWeRv*&p z@H}JB78P8JdA{sBxn3|T1gVFvYV-FM$y)Zkcb=-a?ajYa|LM82Hlnsv)zJQ9mEe1N zte3?0%N~-N&U@%r31yjXjOmi*2i;+o$O2~}p<*hlyaNqz%VD6`=!!j#^VK}#v2L`V znqQnDN^vxZ$by)8_BtBj4YpU3*c)l0BTb>8#rCyey0S}5j!GtHn=_`K+q&;fDbenJ z2<^>9aA0f zfqgZnpK^5a)+O(upwHvQJuU~$P|)mlkAup@2s`c_u@4bNMt{K_%Zl_>ZQk1FPyVa& zj0Efmu=ah1(=U*^JfMOg739+HOC3N&*xgkZ!^*qrr}VBIfHJM282m>i``rR=mTskN zpbq9%-6JOgh255=;WCwzR`Q_+7>BPkVoaF#-ofqV*AR;hG!JF*rBcpx#Ha>kN!WyL zf!i-LQtG}zL9gLz)B0%NAfwB#H_>^Yj`kPVtI0@3^|GE9@)wIyzR8E^{^su6%iUC1yFm4A6w2KtWIt`A#r+V|@k+5^yMXTVk0R>UI8)Ll7><{7E z_6F)D_2xe+Ioe(~>5HeAyt^-}9aGKkQ-*dalj1DmiDlsj|`7{!v8$m%|R4!?t zpyVo&OZW;X2=HjUhfgCe!In0(Z^F|oA5w|P`i0=R91lFt{wYid>@&~3s#Jn4)7?QRs2i^3mL8E< zN0la5P#wzMckrZ-X1$#omxMLC_N*aV!1aUiTx86X)3J14oh;uC3*K^gW$U_7$pAMK z)M#L;9|$jiz?8{#hU(4o4c5`F&E}A#xXZDp%OVWoB;o|#xeo=&AX%ArSwcZ(vc6@V zLLPMfx4W22E9s^eWA@FS1E&l8?AkNy=zWXt!5mA5)}L&LW$BL&16RPSexG0zutV;P zf%VQDB0pu+Y$jYZ(4%2_ZRcU-h<4hN_dCbVYKyZ*giugPEhH6bI&*{Q(^lxm<-5w} zJ?#`K)>Hgya0j+N-cFBK(#;9lbO?FLc6--HXPT=zP3^VFBJiFYMY{NSdk8;X8LfPI zl?}lyin7LUdNS){VhaVeZj=!|lUBV8WZD;8T(wdGvJa(sWO7v^j6bn{J2E z)8?uARIW`SZ+EIaK0I6rKFIL)dqVUnCr*XYQY~WRv69Tgpv_l{Eu1mP<7pog8N1bO zBTwvS;DGLKF0&4Q;=p_XSr7{9L!oDQ>4DVM2}zwuG`P@oqp$Y+D2wAB9`%*CGLNdG zk-}!eSNG_C+gomBD9B{~MClW7g^D~%pISMbq>g76JOCPbh zkK`brTV(;dRh=`;4K{Fs`|43PE$bH#%Ap#qk;r5y#t1&m$?4mc%!ap#<+hNLU zIJ8h#l*JW`3Yz95r35}gqfQ9~{kP+C;3^BeSm#s^scwOSQVa@c3Y7oj%oHHN2{(8y zY%#2t8Qhk&4h1o#RP~UzHE|M2SJn?(ZL#Br_y%Tbugw&)% zK?B}(%E4q)wXq@?9Qk&x7^z_{SJ4zuP`CqQ;&PvNcm4Fr{$+U1Ts_*i)0E};yXt!W zjaac0`r{LZVy6=*y@n)S>~-}h4kmRG-CEJ_=t8!a3Lt_Ziw(FMoTxoP$u~YqyaRh4szY%t(Kx{7x z)yF9W7d$HVhmq!xsmcz*)-li6w!(?#`zaAsd}eK5R0byV6SKZe;SAj&Y3G8YT?)x7 z@pPrUJ^5;|vU9_?a%9thdcT?^-LshL@~tNl6f~COx!P7BSHO4`3tsd&1w(2zp&$`H z7e9|XAyAM@4ut9~F;x!=^1&27L%@}PCMqB=j0^fN2h3UOg@R{?+n(o@BVcbrZQ2_7 z_#BEvpDpxy?doN0`)XaHx5S~K2M2(S98EJ`-6nQc_E?FAf+`1q2HTU;!!`iIC#!mv zz#qAwG{nZ7Q5I=xOG-r`Q(x064wqrscZ3GBrn-0XdpIu=Ib}P2OGq zNqVAoCXvxzZim^>1W(lSjAIC3C^=0!M@yWLV7&bjdtSXJ9#Y%VvJX~wdNIr4_6xq+ zfzJpO&L9@2bX`~5o{SyDCa)HUEi4NdEK3NF;$O~|_!Ek>bG6N0@wI(2@5wX2uVmXX z=juoQ@U-TgUig8>R-IyaLUSmF((S>DTE^zM^q{+$``FU-so0stjjUXo1I$ShF5b z9QGX>LO~Ijvry3ak@Xef(K_A|6m-+Vnr-WMls%iFAl5@(@UGr!J!wiHt^expdQR4S zH=eZV-h*eRFYUVlYZRv+h`AESBe*1YA-RGnfr2g(!Y*kw0_&U|31~I}8JehoFT*%*wgk<;L3CF!bxM44$cm6y_no z0ssr(bchYimcR4yeWy?RvC8p%S4-}oy!9k07HIZF`~nky2cC%|H1BZ~@jcVQ`{~(N zFzu}hKlUeJYB=&DaYdQ+}+z#7=AJk{?dw~>RNqF;IOlt0Y$>uyCq$*mL=QbZ6q-l&kalukVXA+o1*Ra_M`4E9v zT=Gh|(n?ok2#14yrO-0op;s-?-g_q44maZworu+l=i)$#Zp)0n>qp0n^f@fYY7Aqp zE#1m=c;j4Y)5#WrVpisY^HiI;-T;W}hj>k{vZk&%^f>4(w%XSb=8IemGoce3;J7%CRgyqsIP7v8OwjOtVB!GJarw4 zqI|VN955e=I2`b?ku%$yG^L~=qif0ER1EH!3tOwL(&$KK))ft%hd>edFO^%V^Yiux z43qvR!+dFK!Gul3d1E3yGSN*_o_L1Xr>Q*j)wLk5KqijYPlue z3yQt8Bk@ltzBSdkgN< ze$Rg|m>O8y8GX0N|Ig?Nm^+YyBL*bCFyVgZ#Z6wUlOB9EDLDD6lc8C>F<@RxtglQr z{vBohJ3@Nm)?T9)XA_*bm`bFRHLu5Hd|gXoC&K8 zZkbp3AI}Nw4yVDoM2uB%xqI}tDnHM-DBt;)o+1$GNftMAy zA2LgMUwqL=$hOEK5ANA%*BH1C8;wmQM5N6Of!D$SLIeypY6T63npkHK9*<%J+oOuH zMwkzx=EieQk5S>6VwIli1ar80!`1N>fHp;zVCXyz1qGUoHPFhF!qGIckE4|WRPv%kzD zV{(cdH=}Pb*t@^C$I~3GLeYnYatKZAhY!gLmfeyGXFHwzzz9mPg?4?ukjBhAvE&)c z^&Hd=TUJ=;ozpCxMGT7QWtrIUC_5~I^=ZC>jLdAPK6EI!7`ru{bhf>dJ-d}?j=0w8qOQF691ve)`vx#T2& z1^AUd{yHlNv<&q6Kat7b%y^SS`#LKTz^?LljM_KRe&wXT#sYx|0Y(3Yq53A+O+Mml zI8)%Z;-ACopNXz-BHU!1y+&vOF7!{z{Rrdr!|&!M#7&Q-YlvYWvf{rX{tVvn6YuyR zr>=Pm|2gsmFa-U3daK}7!q`I-alcbDT= znGx^)6Xa`Nt$&V;cJH4cUvpL6M83)RbZs0s#6Kbb8I|v+TKH3JzQ4TAH_48!k!^u! z75`xzKN^ZZYW5%0M>i$C$tQA+r%mxUct6-hZsOex^nZc5Bk(HY%@`|rJSxAtGa{nQ@(QFpJsifn~RCpAeoMTi1EwP;?3+g*R!s(8#@0>i(gl_ zZUWp~Gr9(N;_?T;FDpnlv;Vqwah(~6*5LZnHTZKS<7W0>reegE{o0NZnw82|tP literal 0 HcmV?d00001 diff --git a/speedclock.h b/speedclock.h index f8ce06d..38ff40c 100644 --- a/speedclock.h +++ b/speedclock.h @@ -9,6 +9,7 @@ #define STATION_SEL1 10 // this 10 for Nano typedef enum {BASESTATION = 0, TOPSTATION} radio_type_e; +#define RF24_IRQ 2 // this is 2 for the Nano, ?? for the ESP #define RF24_CNS 7 // this is 7 for the Nano, D4 for the ESP #define RF24_CE 8 // this is 8 for the Nano, D3 for the ESP #define RF24_PA_LEVEL RF24_PA_LOW // sending power level RF24_PA_LOW, RF24_PA_HIGH???? @@ -20,83 +21,85 @@ typedef enum {BASESTATION = 0, TOPSTATION} radio_type_e; //--------------- define the structure and type of data that sender and receiver will exchange ---------------- typedef struct transcv_struct{ - unsigned long topstationtime; // the top station sends its time (millis()) continously to the base station - volatile unsigned long topbuttonpressedtime; // the top station sends the time in millis() when the button was pressed - this is already the calculated time + volatile unsigned long topstationtime_us; // the top station sends its time (micros()) continously to the base station + volatile unsigned long topbuttonpressedtime_us; // the top station sends the time in millis() when the button was pressed - this is already the calculated time }transcv_s; -#define MIN_DELAY_BETWEEN_SEND_MS 1000 // this defines the time in milliseconds before the next set of data will be send to the base station - except the button was pressed. -#define CONN_TIMEOUT 5000 // if there was no data received from the TOPSTATION for that amount of time - the connection is flagged as lost +#define MAX_DELAY_BETWEEN_SEND_US 1000000 // this defines the time in micro seconds before the next set of data will be send to the base station - except the button was pressed. +#define MIN_DELAY_BETWEEN_SEND_US 50000 // this defines the time in micro seconds before the next set of data will be send to the base station when the button was pressed or in initsequnce +#define CONN_TIMEOUT_MS 5000 // if there was no data received from the TOPSTATION for that amount of time - the connection is flagged as lost -#define KEY_BOUNCE_MS 50 // the time we use to avoid keybouncing ... +#define KEY_BOUNCE_MS 50 // the time we use to avoid keybouncing ... #define KEY_LONGPRESSED_MS 1000 -#define KEY_TOGGLE_MS 500 // the time between to key actions ... +#define KEY_TOGGLE_MS 500 // the time between to key actions ... #define BUTTON_NOTPRESSED HIGH #define BUTTON_PRESSED LOW #define BUTTON_LONGPRESSED 3 -typedef enum {BUTTON_STOPCANCEL = 0, BUTTON_START, BUTTON_FAIL,NO_LAST_BUTTON} button_number_e; +typedef enum {BUTTON_STOP = 0, BUTTON_CANCEL, BUTTON_START, BUTTON_FAIL,NO_LAST_BUTTON} button_number_e; const uint8_t BUTTONPins[NO_LAST_BUTTON] = { - [BUTTON_STOPCANCEL] = 2, // stop/cancel button input pin - [BUTTON_START] = 4, // start button input pin - [BUTTON_FAIL] = 3, // stop button input pin + [BUTTON_STOP] = 2, // stop button input pin + [BUTTON_CANCEL] = 5, // cancel button input pin + [BUTTON_START] = 4, // start button input pin + [BUTTON_FAIL] = 3, // stop button input pin }; -#define MIN_DELAY_BETWEEN_PRESSED_MS 500 // this defines the time in milliseconds before the button is expected to be pressed again. We do this to avaoid keybouncing +#define MIN_DELAY_BETWEEN_PRESSED_US 500000 // this defines the time in microseconds before the button is expected to be pressed again. We do this to avaoid keybouncing -#define PIEZO_PIN 6 // piezo speaker +#define PIEZO_PIN 6 // piezo speaker -#define DISPLAY_I2C_ADDRESS 0x3C //Adress of the Display +#define DISPLAY_I2C_ADDRESS 0x3C //Adress of the Display typedef enum {TIMER_INIT = 0, TIMER_NOCONNECTION, TIMER_IDLE, TIMER_READY, TIMER_STARTED, TIMER_RUNNING , TIMER_CANCELLED, TIMER_STOPPED, TIMER_TIMEDOUT, TIMER_FAIL, TIMER_WAIT, TIMER_SETTINGS} timer_state_e; typedef enum {MODE_COMPETE = 0, MODE_TRAINING, MODE_CALIBRATION, NO_LAST_MODE} timer_mode_e; // compete - full mode with false start detector, training - no false start detection, calibration - parellel wired connection between top and base to kalibrate the offset calculation of the wireless connection const char timer_mode_short[NO_LAST_MODE] = {[MODE_COMPETE]='F',[MODE_TRAINING]='T',[MODE_CALIBRATION]='C'}; const String timer_mode_string[NO_LAST_MODE] = {[MODE_COMPETE]="Competetion",[MODE_TRAINING]=" Training ",[MODE_CALIBRATION]="Calibration"}; -#define LED_BLINK_ALL_MS 500 // LED set to BLINK will change there state every number of milli seconds specified here +#define LED_BLINK_ALL_MS 500 // LED set to BLINK will change there state every number of milli seconds specified here // READY_LED, WARN_LED, RUN_LED, FAIL_LED typedef enum {READY_LED = 0, RUN_LED, FAIL_LED, WARN_LED ,NO_LAST_LED} led_number_e; // leave NO_LAST_LED as last element - its our marker ... const uint8_t LEDPins[NO_LAST_LED] = { - [READY_LED] =A2, // green ready LED - [RUN_LED] =A0, // blue run LED - [FAIL_LED] =A3, // red fail LED - [WARN_LED] =A1 // yellow warn LED + [READY_LED] =A2, // green ready LED + [RUN_LED] =A0, // blue run LED + [FAIL_LED] =A3, // red fail LED + [WARN_LED] =A1 // yellow warn LED }; typedef enum {LED_OFF = 0, LED_ON, LED_BLINK } led_state_e; const uint8_t LEDStates[][NO_LAST_LED] = { - [TIMER_INIT] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_BLINK ,[WARN_LED]=LED_OFF}, // 0 + [TIMER_INIT] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_BLINK ,[WARN_LED]=LED_OFF}, // 0 [TIMER_NOCONNECTION] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_ON, [WARN_LED]=LED_OFF}, // 1 [TIMER_IDLE] = {[READY_LED]=LED_ON, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_OFF}, // 2 - [TIMER_READY] = {[READY_LED]=LED_BLINK, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_OFF}, // 3 + [TIMER_READY] = {[READY_LED]=LED_BLINK, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_OFF}, // 3 [TIMER_STARTED] = {[READY_LED]=LED_ON, [RUN_LED]=LED_ON, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_OFF}, // 4 [TIMER_RUNNING] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_ON, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_OFF}, // 5 [TIMER_CANCELLED] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_ON, [WARN_LED]=LED_OFF}, // 6 [TIMER_STOPPED] = {[READY_LED]=LED_ON, [RUN_LED]=LED_ON, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_OFF}, // 7 [TIMER_TIMEDOUT] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_ON, [FAIL_LED]=LED_ON, [WARN_LED]=LED_OFF}, // 8 - [TIMER_FAIL] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_BLINK, [FAIL_LED]=LED_ON, [WARN_LED]=LED_OFF}, // 9 - [TIMER_WAIT] = {[READY_LED]=LED_ON, [RUN_LED]=LED_ON, [FAIL_LED]=LED_ON, [WARN_LED]=LED_ON}, // 10 - [TIMER_SETTINGS] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_ON} // 11 + [TIMER_FAIL] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_BLINK, [FAIL_LED]=LED_ON, [WARN_LED]=LED_OFF}, // 9 + [TIMER_WAIT] = {[READY_LED]=LED_ON, [RUN_LED]=LED_ON, [FAIL_LED]=LED_ON, [WARN_LED]=LED_ON}, // 10 + [TIMER_SETTINGS] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_ON} // 11 }; -#define MAX_DIFFERENCE_OFFSET_MS 100 // 0,001sec is the maximum offset we allow between the current offset and the mean offset. if it is more - restart offset calculation -#define REQUIRED_NUMBER_MEANVALS 100 // we need at least this number of meanvalues to be ready to start a run +#define MAX_DIFFERENCE_OFFSET_US 100000 // 0,001sec is the maximum offset we allow between the current offset and the mean offset. if it is more - restart offset calculation +#define REQUIRED_NUMBER_MEANVALS 1 // we need at least this number of meanvalues to be ready to start a run #define MAX_ALLOWED_FAILED_OFFSETS 10 // if more than this number of offsets are out of the specified MAX_DIFFERENCE_OFFSET_MS value, offset calcultion will be restarted #define STARTSEQ_STEPS 4 -const uint8_t STARTSEQ_NOTES[] = {0,392,392,1047}; // tone frequence -const uint16_t STARTSEQ_DURATION[] = {0,200,200,100}; // tone duration in milliseconds -const unsigned long STARTSEQ_PAUSE[] = {1000000,1000000,1000000,100000}; // pause between tones in microseconds -#define STARTSEQ_LENGTH_MS 3100 // the length of the start sequence from the time the button was pressed ... includes the 3 tones +const uint8_t STARTSEQ_NOTES[] = {0,392,392,1047}; // tone frequence +const uint16_t STARTSEQ_DURATION_MS[] = {0,200,200,100}; // tone duration in milliseconds +const unsigned long STARTSEQ_PAUSE_US[] = {1000000,1000000,1000000,100000}; // pause between tones in microseconds +#define STARTSEQ_LENGTH_US 3100000 // the length of the start sequence from the time the button was pressed ... includes the 3 tones #define FAILSEQ_STEPS 2 -const uint8_t FAILSEQ_NOTES[] = {49,49}; // tone frequence -const uint16_t FAILSEQ_DURATION[] = {300,300}; // tone duration in milliseconds -const unsigned long FAILSEQ_PAUSE[] = {400000,400000}; // pause between tones in microseconds +const uint8_t FAILSEQ_NOTES[] = {49,49}; // tone frequence +const uint16_t FAILSEQ_DURATION_MS[] = {300,300}; // tone duration in milliseconds +const unsigned long FAILSEQ_PAUSE_US[] = {400000,400000}; // pause between tones in microseconds -#define TIMER_MAX_TIME 99999 -#define TIMER_TIMEOUT 20000 +#define TIMER_MAX_TIME_US 99999999 +#define TIMER_TIMEOUT_US 20000000 //--------------------------------------- function declarations ---------------------------------------------- -void receive_values(void); +void update_offset_values(void); void false_start_isr(void); void update_screen(timer_state_e state); void set_state_LEDs(timer_state_e state, boolean warn); @@ -108,5 +111,8 @@ void start_isr(void); void update_buttons(void); void send_values(void); void stop_isr(void); - +String micros2string(signed long microsecs); +void nrf24_isr(void); +void handle_connection(void); +signed long calc_mean_offset(signed long current_toptime); #endif diff --git a/speedclock.ino b/speedclock.ino index a264034..3376637 100644 --- a/speedclock.ino +++ b/speedclock.ino @@ -15,49 +15,61 @@ uint8_t radio_sel0, radio_sel1; // code of type of station /* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ RF24 radio(RF24_CNS,RF24_CE); /**********************************************************/ -byte addresses[][12] = {"top_station","basestation"}; // Radio pipe addresses for the 2 nodes to communicate. +byte addresses[][12] = {"top_station","basestation"}; // Radio pipe addresses for the 2 nodes to communicate. -unsigned long stats_last_plotted = 0; +unsigned long stats_last_plotted_at_ms = 0; unsigned long startloop_ms = 0; -boolean offset_sync_sequence = true; // set to true as the offset sync / calibration is not done - sending data to the basestation is more often as after the sync is done ... +boolean offset_sync_sequence = true; // set to true as the offset sync / calibration is not done - sending data to the basestation is more often as after the sync is done ... -boolean blink_on = false; // set to TRUE if the system clock cycle signals to set LEDs in LED_BLINK mode to be active - means top be switched on -unsigned long blink_on_swiched_at = 0; // the last system time (in milliseconds) the blink_on was switched +boolean blink_on = false; // set to TRUE if the system clock cycle signals to set LEDs in LED_BLINK mode to be active - means top be switched on +unsigned long blink_on_swiched_at_ms = 0; // the last system time (in milliseconds) the blink_on was switched uint8_t *leds_states = LEDStates[TIMER_INIT]; -boolean time_offset_ok = false; // true as long as the offset is correctly calculated -uint16_t counter_time_offset = 0; // number of used values for the mean value calculation -signed long sum_time_offset = 0; // sum of offset values -signed long current_time_offset = 0; // current offset ... -signed long mean_time_offset = 0; // mean value for the offset -signed long running_time_offset = 0; // offset that will be used for this run ... -volatile unsigned long start_time = 0; // if the timer is running this is that start time ... (use volatile for all shared variables that deals with hardware) -volatile unsigned long runner_start_time = 0; // this is the time the runner left the pad - so the status of the falsetstart pin goes to high again - but this is OK and a real start (use volatile for all shared variables that deals with hardware) -unsigned long run_time = 0; // if the timer is running this is that start time ... -boolean warn_during_run = false; // will be set to true if there is a warning during the run - usually an offset sync error -unsigned long connection_last_established_at_ms = 0; // time the last active connection was established -boolean connection_available = false; // if there were no data for longer then CONN_TIMEOUT the connection will be flaged as lost ... -boolean keep_connection_off = true; // if sett to true the connection to the top station will be kept off for a timeout time to signal that we are in the init sequnce again ... -uint8_t failed_offsets = MAX_ALLOWED_FAILED_OFFSETS; // number of offset values that did not fullfill the MAX_DIFFERENCE_OFFSET_MS criterion -volatile boolean false_start = false; // set to true if a false start occurs (use volatile for all shared variables that deals with hardware) -volatile uint8_t startsequence_count = 0; // shows thze actual step in the startsquence. Number of steps is defined in STARTSEQ_STEPS (use volatile for all shared variables that deals with hardware) -volatile boolean startsequence_done = false; // set to TRUE if the startsequnce was completed successfully (without a false start) +boolean time_offset_ok = false; // true as long as the offset is correctly calculated +volatile boolean new_current_offset_available = false; +uint16_t counter_time_offset = 0; // number of used values for the mean value calculation + +signed long long sum_time_offset_us = 0; // sum of offset values +float sum_time_slope = 0; // sum of slopes + +volatile unsigned long last_top_time_us = 0; // current top time ... +volatile unsigned long current_top_time_us = 0; // current top time ... +volatile unsigned long last_bottom_time_us = 0; // current top time ... +volatile unsigned long current_bottom_time_us = 0; // current top time ... + +volatile signed long current_time_offset_us = 0; // current offset ... + +signed long mean_time_offset_us = 0; // mean value for the offset (we have an linear sync function to map the TOPSTATION time to BOTTOMSTATIONTIME : t +float mean_time_slope = 0; // mean slope + +signed long running_time_offset_us = 0; // offset that will be used for this run ... +volatile unsigned long start_time_us = 0; // if the timer is running this is that start time ... (use volatile for all shared variables that deals with hardware) +volatile unsigned long runner_start_time_us = 0; // this is the time the runner left the pad - so the status of the falsetstart pin goes to high again - but this is OK and a real start (use volatile for all shared variables that deals with hardware) +unsigned long run_time_us = 0; // if the timer is running this is that start time ... +boolean warn_during_run = false; // will be set to true if there is a warning during the run - usually an offset sync error +volatile unsigned long connection_last_established_at_ms = 0; // time the last active connection was established +volatile boolean connection_available = false; // if there were no data for longer then CONN_TIMEOUT the connection will be flaged as lost ... +boolean keep_connection_off = true; // if sett to true the connection to the top station will be kept off for a timeout time to signal that we are in the init sequnce again ... +uint8_t failed_offsets = MAX_ALLOWED_FAILED_OFFSETS; // number of offset values that did not fullfill the MAX_DIFFERENCE_OFFSET_MS criterion +volatile boolean false_start = false; // set to true if a false start occurs (use volatile for all shared variables that deals with hardware) +volatile uint8_t startsequence_count = 0; // shows thze actual step in the startsquence. Number of steps is defined in STARTSEQ_STEPS (use volatile for all shared variables that deals with hardware) +volatile boolean startsequence_done = false; // set to TRUE if the startsequnce was completed successfully (without a false start) volatile boolean failsequence_done = false; volatile uint8_t failsequence_count = 0; -boolean topbuttonwaspressed = false; // set to true if the stop button was pressed +boolean topbuttonwaspressed = false; // set to true if the stop button was pressed uint8_t button_state[NO_LAST_BUTTON] = {BUTTON_NOTPRESSED}; -unsigned long button_last_changed_at[NO_LAST_BUTTON] = {0}; +unsigned long button_last_changed_at_ms[NO_LAST_BUTTON] = {0}; uint8_t button_last_changed_to[NO_LAST_BUTTON] = {BUTTON_NOTPRESSED}; -timer_state_e timer_state = TIMER_INIT; // current state needs to be initialized to somethin different then new_state due to the fact that some pieces of the code check for differnt values of state and _new_state to detect an update... -timer_state_e timer_new_state = TIMER_NOCONNECTION; // next state - in the startup phase the first state - will be TIMER_NOCONNECTION ... checking if a connection to TOPSTATION is established +timer_state_e timer_state = TIMER_INIT; // current state needs to be initialized to somethin different then new_state due to the fact that some pieces of the code check for differnt values of state and _new_state to detect an update... +timer_state_e timer_new_state = TIMER_NOCONNECTION; // next state - in the startup phase the first state - will be TIMER_NOCONNECTION ... checking if a connection to TOPSTATION is established -timer_mode_e timer_mode = MODE_COMPETE; // mode of the BASESTATION - this can be changed in IDLE state by pressing the CANCEL button -unsigned long timer_mode_changed_at = 0; +timer_mode_e timer_mode = MODE_COMPETE; // mode of the BASESTATION - this can be changed in IDLE state by pressing the CANCEL button +unsigned long timer_mode_changed_at_ms = 0; transcv_s radio_data; void setup(){ @@ -92,10 +104,10 @@ void setup(){ // Setup and configure the NRF radio // radio setup ... radio.begin(); - radio.setRetries(15, 15); //the first is the time between reties in multiple of 250ms, the second is the numer of attempts + radio.setRetries(1, 1); //the first is the time between reties in multiple of 250ms, the second is the numer of attempts if(stationNumber == TOPSTATION){ // Attach the STOP button interrupt - attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_STOPCANCEL]), stop_isr, FALLING ); + attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_STOP]), stop_isr, FALLING ); // Set the PA Level of the sendin TOP_STATION radio.setPALevel(RF24_PA_LEVEL); radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses @@ -106,8 +118,8 @@ void setup(){ radio.openReadingPipe(1,addresses[1]); radio.startListening(); } - radio_data.topstationtime = millis(); // set the current milli second count - radio_data.topbuttonpressedtime = 0; // set the time the button was pressed last time to 0 + radio_data.topstationtime_us = micros(); // set the current micro second count + radio_data.topbuttonpressedtime_us = 0; // set the time the button was pressed last time to 0 //initialise Wire and OLED Wire.begin(); @@ -121,8 +133,8 @@ void loop(void) { /****************** Shared code for all stations ********************************************************************************/ startloop_ms = millis(); - if(millis() - blink_on_swiched_at > LED_BLINK_ALL_MS){ - blink_on_swiched_at = millis(); + if(millis() - blink_on_swiched_at_ms > LED_BLINK_ALL_MS){ + blink_on_swiched_at_ms = millis(); blink_on = !blink_on; } @@ -165,7 +177,7 @@ void loop(void) { timer_new_state = TIMER_NOCONNECTION; } else { if(false == offset_sync_sequence){ - if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){ + if(button_state[BUTTON_STOP] == BUTTON_NOTPRESSED){ topbuttonwaspressed = false; timer_new_state = TIMER_IDLE; } @@ -184,8 +196,8 @@ void loop(void) { break; case TIMER_STOPPED: // wait a few millis and ... after that go back to idle ... - if((signed long)(millis() - radio_data.topbuttonpressedtime) > MIN_DELAY_BETWEEN_PRESSED_MS){ - if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){ + if((signed long)(micros() - radio_data.topbuttonpressedtime_us) > MIN_DELAY_BETWEEN_PRESSED_US){ + if(button_state[BUTTON_STOP] == BUTTON_NOTPRESSED){ timer_new_state = TIMER_IDLE; topbuttonwaspressed = false; } @@ -198,8 +210,11 @@ void loop(void) { /****************** Code for the BASESTATION is here - the display and the start button is connected here. All caclulation will be done here ***************************/ if ( stationNumber == BASESTATION ) { - // receive data from top_station, calculate offset and set 'last connection' time stamp - receive_values(); + // update connection status + handle_connection(); + + // calculate offset and set 'last connection' time stamp + //update_offset_values(); // update the OLED screen update_screen(timer_new_state); @@ -225,7 +240,7 @@ void loop(void) { else{ // if the offset is claculated, cancel not pressed and failstart not pressed switch to IDLE mode ... if((time_offset_ok == true) && - (button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED) && + (button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED) && (button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED) ) { // check if offset is OK - if not .. set state back to INIT @@ -250,11 +265,11 @@ void loop(void) { // check if the FALSESTATE button is pressed OR we are in trainingsmode - somebody is ready to run, but STARTBUTTON is NOT pressed ... if(((button_state[BUTTON_FAIL] != BUTTON_NOTPRESSED) || (timer_mode != MODE_COMPETE)) && (button_state[BUTTON_START] == BUTTON_NOTPRESSED) && - (button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED)) + (button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED)) { timer_new_state = TIMER_READY; } else { - if((button_state[BUTTON_STOPCANCEL] == BUTTON_LONGPRESSED) && + if((button_state[BUTTON_CANCEL] == BUTTON_LONGPRESSED) && (button_state[BUTTON_START] == BUTTON_NOTPRESSED) && (button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED)) { @@ -277,7 +292,7 @@ void loop(void) { // now enable the interrupt for the FALSESTART button startsequence_count = 0; startsequence_done = false; - running_time_offset = mean_time_offset; + running_time_offset_us = mean_time_offset_us; false_start = false; if(timer_mode == MODE_COMPETE){ attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_FAIL]), false_start_isr, RISING ); @@ -285,11 +300,11 @@ void loop(void) { Timer1.initialize(); timer_new_state = TIMER_STARTED; // set the startime - this is the current time plus the length of this sequence - start_time = millis() + STARTSEQ_LENGTH_MS; + start_time_us = micros() + STARTSEQ_LENGTH_US; // call the start sequence interrupt routine ... - Timer1.attachInterrupt(start_isr,STARTSEQ_PAUSE[startsequence_count]); // startISR to run every given microseconds + Timer1.attachInterrupt(start_isr,STARTSEQ_PAUSE_US[startsequence_count]); // startISR to run every given microseconds } else { - if((button_state[BUTTON_STOPCANCEL] == BUTTON_LONGPRESSED) && + if((button_state[BUTTON_CANCEL] == BUTTON_LONGPRESSED) && (button_state[BUTTON_START] == BUTTON_NOTPRESSED) && (button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED)) { @@ -306,7 +321,7 @@ void loop(void) { failsequence_done = false; failsequence_count = 0; timer_new_state = TIMER_FAIL; - Timer1.attachInterrupt(failSequence,FAILSEQ_PAUSE[failsequence_count]); + Timer1.attachInterrupt(failSequence,FAILSEQ_PAUSE_US[failsequence_count]); } else { if(startsequence_done == true){ timer_new_state = TIMER_RUNNING; @@ -318,15 +333,15 @@ void loop(void) { // check if offset is still OK - if not .. set warning warn_during_run = true; } - if((signed long)(millis() - start_time) > TIMER_TIMEOUT){ + if((signed long)(micros() - start_time_us) > TIMER_TIMEOUT_US){ timer_new_state = TIMER_TIMEDOUT; } else { - if(button_state[BUTTON_STOPCANCEL] != BUTTON_NOTPRESSED){ + if(button_state[BUTTON_CANCEL] != BUTTON_NOTPRESSED){ timer_new_state = TIMER_CANCELLED; } else { - if(radio_data.topbuttonpressedtime > running_time_offset){ - if((radio_data.topbuttonpressedtime - running_time_offset) > start_time){ - run_time = (radio_data.topbuttonpressedtime - running_time_offset) - start_time; + if(radio_data.topbuttonpressedtime_us > running_time_offset_us){ + if((signed long)(radio_data.topbuttonpressedtime_us - running_time_offset_us) > start_time_us){ + run_time_us = (radio_data.topbuttonpressedtime_us - running_time_offset_us) - start_time_us; timer_new_state = TIMER_STOPPED; } } @@ -335,39 +350,36 @@ void loop(void) { break; case TIMER_STOPPED: //calculate the run_time and switch to WAIT - delay(KEY_BOUNCE_MS); - if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){ + if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){ timer_new_state = TIMER_WAIT; } break; case TIMER_FAIL: //fail start case .... - run_time = 99999; + run_time_us = TIMER_MAX_TIME_US; if(true == failsequence_done){ - delay(KEY_BOUNCE_MS); - if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){ + if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){ timer_new_state = TIMER_WAIT; } } break; case TIMER_CANCELLED: // what to do in chancel mode ? - run_time = 99999; - delay(KEY_BOUNCE_MS); - if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){ + run_time_us = TIMER_MAX_TIME_US; + if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){ timer_new_state = TIMER_WAIT; } break; case TIMER_TIMEDOUT: // time out - run_time = millis() - start_time; - if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){ + run_time_us = micros() - start_time_us; + if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){ timer_new_state = TIMER_WAIT; } break; case TIMER_WAIT: // wait until the chancel button was pressed to go ahead - if((button_state[BUTTON_STOPCANCEL] != BUTTON_NOTPRESSED) && + if((button_state[BUTTON_CANCEL] != BUTTON_NOTPRESSED) && (button_state[BUTTON_START] == BUTTON_NOTPRESSED) && (button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED) ) @@ -377,16 +389,16 @@ void loop(void) { break; case TIMER_SETTINGS: // switch between the different modes for now - compete, training and calibration ... - if((button_state[BUTTON_STOPCANCEL] == BUTTON_PRESSED) && + if((button_state[BUTTON_CANCEL] == BUTTON_PRESSED) && (button_state[BUTTON_START] == BUTTON_NOTPRESSED)) { // go back to idle timer_new_state = TIMER_IDLE; } else { - if((button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED) && + if((button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED) && (button_state[BUTTON_START] == BUTTON_PRESSED)) { - if((millis() - timer_mode_changed_at) > KEY_TOGGLE_MS){ + if((millis() - timer_mode_changed_at_ms) > KEY_TOGGLE_MS){ // switch system mode ... switch(timer_mode){ case MODE_COMPETE: @@ -399,7 +411,7 @@ void loop(void) { timer_mode = MODE_COMPETE; break; } - timer_mode_changed_at = millis(); + timer_mode_changed_at_ms = millis(); } } @@ -408,21 +420,68 @@ void loop(void) { } } - if( (STATS_PLOTS_EVERY_MS > 0) && - ((millis() -stats_last_plotted) > STATS_PLOTS_EVERY_MS)) - { - Serial.println("mean_time_offset-current_time_offset"); - Serial.print((signed long)(mean_time_offset - current_time_offset)); - //Serial.print(" "); - //Serial.println(millis()- startloop_ms); - stats_last_plotted = millis(); + /* + // ignore the first seconds ... + if(time_offset_ok == true){ + if( (STATS_PLOTS_EVERY_MS > 0) && + ((signed long)(millis() -stats_last_plotted_at_ms) > STATS_PLOTS_EVERY_MS)) + { + //Serial.println("mean_time_offset-current_time_offset"); + //Serial.println(calc_mean_offset(current_top_time_us)); + //Serial.print(" "); + //Serial.print(mean_time_offset_us); + //Serial.print(" "); + //Serial.println(current_time_offset_us); + stats_last_plotted_at_ms = millis(); + } } + */ } //####################### HELPER FUNCTIONS ########################### +signed long calc_top2bot_time(signed long current_toptime){ + return((mean_time_slope*current_toptime) + mean_time_offset_us); +} + +void nrf24_isr(void) +{ + //Serial.println("Got data from TOPSTATION"); + bool tx,fail,rx; + // wait the connection time out time before receiving data - this is to tell the TOP_STATION to resend offset values in fast mode ... + if(keep_connection_off == false){ + radio.whatHappened(tx,fail,rx); // What happened? + if ( rx ){ + // check if radio data is available - if so read the data + // read data from TOP_STATION ... + //while( radio.available()){ // Read all available payloads + radio.read( &radio_data, sizeof(radio_data) ); // Read the data the TOPSTATION sent + //} + if(new_current_offset_available == false){ + last_top_time_us = current_top_time_us; + current_top_time_us = radio_data.topstationtime_us; + last_bottom_time_us = current_bottom_time_us; + current_bottom_time_us = micros(); + //new_current_offset_available = true; + Serial.print(" last_top_time_us:"); + Serial.print(last_top_time_us); + Serial.print(" current_top_time_us:"); + Serial.print(current_top_time_us); + Serial.print(" last_bottom_time_us."); + Serial.print(last_bottom_time_us); + Serial.print(" current_bottom_time_us:"); + Serial.println(current_bottom_time_us); + Serial.print("current offset:"); + Serial.println((signed long)(current_top_time_us - current_bottom_time_us)); + } + connection_last_established_at_ms = millis(); + connection_available = true; + } + } +} + void update_buttons(void){ uint8_t curr_button_state; - unsigned long button_pressed_at = millis(); + unsigned long button_pressed_at_ms = millis(); String state_string; // we have some buttons to update that are used in the sketch ... for(uint8_t button = 0; button < NO_LAST_BUTTON; button++){ @@ -435,7 +494,7 @@ void update_buttons(void){ curr_button_state = BUTTON_PRESSED; } if( curr_button_state != button_last_changed_to[button] ){ - button_last_changed_at[button] = button_pressed_at; + button_last_changed_at_ms[button] = button_pressed_at_ms; button_last_changed_to[button] = curr_button_state; } @@ -443,7 +502,7 @@ void update_buttons(void){ ((curr_button_state == BUTTON_PRESSED) && (button_state[button] == BUTTON_NOTPRESSED))) // the button has changed its state { // is that bouncing or settled? - if((unsigned long)(button_pressed_at - button_last_changed_at[button]) > KEY_BOUNCE_MS){ + if((unsigned long)(button_pressed_at_ms - button_last_changed_at_ms[button]) > KEY_BOUNCE_MS){ // settled! -> change the stored state. button_state[button] = curr_button_state; } else { @@ -453,7 +512,7 @@ void update_buttons(void){ (button_state[button] == BUTTON_PRESSED)) { //check for long pressed button ... - if((unsigned long)(button_pressed_at - button_last_changed_at[button]) > KEY_LONGPRESSED_MS){ + if((unsigned long)(button_pressed_at_ms - button_last_changed_at_ms[button]) > KEY_LONGPRESSED_MS){ button_state[button] = BUTTON_LONGPRESSED; } } @@ -461,101 +520,143 @@ void update_buttons(void){ } } -void receive_values(void){ - // wait the connection time out time before receiving data - this is to tell the TOP_STATION to resend offset values in fast mode ... - if(keep_connection_off){ - if((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT)){ +void handle_connection(void){ + if(keep_connection_off == true){ + // Attach the RF24 IRQ pin interrupt + detachInterrupt(digitalPinToInterrupt(RF24_IRQ)); + connection_available = false; + if((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT_MS)){ keep_connection_off = false; - //Serial.print("Connection ON allowed."); - } else { - //Serial.print("Connection OFF forced."); + // Attach the RF24 IRQ pin interrupt + attachInterrupt(digitalPinToInterrupt(RF24_IRQ), nrf24_isr, LOW ); } - } else - { - // check if radio data is available - if so read the data - if( radio.available()){ - // read data from TOP_STATION ... - while( radio.available()){ // Read all available payloads - radio.read( &radio_data, sizeof(radio_data) ); // Read the data the TOPSTATION sent - } - connection_last_established_at_ms = millis(); - connection_available = true; - current_time_offset = radio_data.topstationtime - millis(); // the offset between TOP_STATION and BASESTATION - /* - Serial.print("Current time on host in millis:"); - Serial.print(millis()); - Serial.print(" Current time on client in millis: "); - Serial.println(radio_data.topstationtime); - Serial.print("Offset is: "); - Serial.println(current_time_offset); - Serial.print(" Button was pressed last time on client in millis: "); - Serial.println(radio_data.topbuttonpressedtime); - */ - - // offset calculation ... only needed if the variation is bigger than allowed or not enough values available already ... - if(counter_time_offset == 0){ - // this is the initial setup to start with something - in this case the last offset value that was received - mean_time_offset = current_time_offset; - } - // check current offset of the TOP_STATIOn and the BASESTATION if more than allowed ... - if(abs(current_time_offset - mean_time_offset) < MAX_DIFFERENCE_OFFSET_MS){ - // if the current value is in range - decrease the fail counter by 1 if it was not zero already - if(failed_offsets > 0){ - //Serial.println("INFO: The last received TOPSTATION offset time stamp was again in range. Decrease internal fail counter"); - failed_offsets--; - } - // the offset is in range - check if we have already enough values of if we need to add more ... - if(counter_time_offset <= REQUIRED_NUMBER_MEANVALS){ - //add the next value to meanvalue calculation ... - sum_time_offset = sum_time_offset + current_time_offset; - counter_time_offset++; - mean_time_offset = sum_time_offset/counter_time_offset; - Serial.print("Offset calulation. We have "); - Serial.print(counter_time_offset); - Serial.print("/"); - Serial.print(REQUIRED_NUMBER_MEANVALS); - Serial.print(" values. Mean offset value based on that is: "); - Serial.println(mean_time_offset); - } else { - time_offset_ok = true; - } - - } else { - // the current offset is out of range ... - // if the values before also already failed the criterion but the max allowed number of such fails is not reached ... just increase the counter. - if(failed_offsets < MAX_ALLOWED_FAILED_OFFSETS){ - //Serial.println("WARNING: The last received TOPSTATION offset time stamp was out of range. Increase internal fail counter"); - failed_offsets++; - } - else{ - // if the values before also already failed the criterion AND the max allowed number of such fails is reached ... we need to restart the mean calculation and set the timer to unready state ... - Serial.println("TopStation and BaseStation are out off sync. Offset calculation will be (re)started. "); - //Serial.print("Last "); - //Serial.print(MAX_ALLOWED_FAILED_OFFSETS); - //Serial.print(" offsets (last one: "); - //Serial.print(current_time_offset); - //Serial.print(" ) were to far from the mean offset "); - //Serial.println( abs(current_time_offset - mean_time_offset) ); - //Serial.print("This more than the allowed: "); - //Serial.print(MAX_DIFFERENCE_OFFSET_MS); - //Serial.print(" compared to the mean offset: "); - //Serial.println(mean_time_offset); - time_offset_ok = false; - counter_time_offset = 0; - sum_time_offset = 0; - mean_time_offset = 0; - failed_offsets = 0; - } // out of range counter exceeds maximum value - } // time offset of TOPSTATION out of range - } - else{ - // remove the RF24 connection flag if no data was received for longer time - if((millis() - connection_last_established_at_ms >= CONN_TIMEOUT) || (connection_last_established_at_ms == 0)){ - connection_available = false; - Serial.println("ERROR: No connection established to TOPSTATION"); - } + } else { + // remove the RF24 connection flag if no data was received for longer time + if((millis() - connection_last_established_at_ms >= CONN_TIMEOUT_MS) || (connection_last_established_at_ms == 0)){ + connection_available = false; + Serial.println("ERROR: No connection established to TOPSTATION"); } // radio available } // keep connection off +} + +void update_offset_values(void){ + + float int_time_slope = 1.0; + signed long int_time_delta_x = 0; + signed long int_time_delta_y = 0; + signed long int_time_offset_us = 0; + unsigned long int_current_bot_time_us = 0; + unsigned long int_calc_bot_time_us = 0; + unsigned long int_current_top_time_us = 0; + signed long int_current_calc2real_offset = 0; + + if((new_current_offset_available == true) && // there is a new value + (last_top_time_us != 0) && // the last top time is updated already + (current_top_time_us != 0) && // the current top time is updated + (last_bottom_time_us != 0) && // the last bottom time is updated + (current_bottom_time_us != 0)) // the current bottom time is updated + { + + + //calculate the last and the current offset based on what we got from Topstation + int_current_bot_time_us = current_bottom_time_us; + int_time_delta_y = current_bottom_time_us-last_bottom_time_us; + int_time_delta_x = current_top_time_us-last_top_time_us; + new_current_offset_available = false; + + if(counter_time_offset == 0){ + // this is the initial setup to start with something - in this case the last offset value that was received + int_current_calc2real_offset = 0; + } else { + int_calc_bot_time_us = calc_top2bot_time(current_top_time_us); + int_current_calc2real_offset = int_calc_bot_time_us - int_current_bot_time_us; + //Serial.print("Counter:"); + //Serial.println(counter_time_offset); + //Serial.print("Calculated bot time:"); + //Serial.println(int_calc_bot_time_us); + //Serial.print("Real bot time:"); + //Serial.println(int_current_bot_time_us); + Serial.print("So offset between calc and Real bot time:"); + Serial.println(abs(int_current_calc2real_offset)); + // Serial.print("function offset:"); + //Serial.println(mean_time_offset_us); + //Serial.print("function slope:"); + //Serial.println((float)mean_time_slope); + } + // check current offset of the TOP_STATIOn and the BASESTATION if more than allowed ... + + if(abs(int_current_calc2real_offset) < MAX_DIFFERENCE_OFFSET_US){ + // if the current value is in range - decrease the fail counter by 1 if it was not zero already + if(failed_offsets > 0){ + Serial.println("INFO: The last received TOPSTATION offset time stamp was again in range. Decrease internal fail counter"); + failed_offsets--; + } + // the offset is in range - check if we have already enough values of if we need to add more ... + if(counter_time_offset <= REQUIRED_NUMBER_MEANVALS){ + //add the next value to meanvalue calculation ... + int_time_slope = (float)(int_time_delta_y / int_time_delta_x); + int_time_offset_us = current_bottom_time_us - (int_time_slope*current_top_time_us); + + //Serial.print(" offset is: "); + //Serial.print(int_time_offset_us); + //Serial.print(" int_time_delta_y:"); + //Serial.print(int_time_delta_y); + //Serial.print(" int_time_delta_x:"); + //Serial.print(int_time_delta_x); + //Serial.print(" int_time_slope:"); + //Serial.println(int_time_slope); + + sum_time_offset_us = sum_time_offset_us + int_time_offset_us; + sum_time_slope = sum_time_slope + int_time_slope; + counter_time_offset++; + mean_time_offset_us = sum_time_offset_us/counter_time_offset; + mean_time_slope = sum_time_slope/counter_time_offset; + Serial.print("Offset calulation. We have "); + Serial.print(counter_time_offset); + Serial.print("/"); + Serial.print(REQUIRED_NUMBER_MEANVALS); + Serial.print(" values. y=slope*x+offset. Mean offset value based on that is: "); + Serial.print(mean_time_offset_us); + Serial.print(" mean slope: "); + Serial.println(mean_time_slope); + } else { + time_offset_ok = true; + } + + } else { + // the current offset is out of range ... + // if the values before also already failed the criterion but the max allowed number of such fails is not reached ... just increase the counter. + if(failed_offsets < MAX_ALLOWED_FAILED_OFFSETS){ + Serial.println("WARNING: The last received TOPSTATION offset time stamp was out of range. Increase internal fail counter"); + failed_offsets++; + } + else{ + // if the values before also already failed the criterion AND the max allowed number of such fails is reached ... we need to restart the mean calculation and set the timer to unready state ... + Serial.println("TopStation and BaseStation are out off sync. Offset calculation will be (re)started. "); + //Serial.print("Last "); + //Serial.print(MAX_ALLOWED_FAILED_OFFSETS); + //Serial.print(" offsets (last one: "); + //Serial.print(current_time_offset); + //Serial.print(" ) were to far from the mean offset "); + //Serial.println( abs(current_time_offset - mean_time_offset) ); + //Serial.print("This more than the allowed: "); + //Serial.print(MAX_DIFFERENCE_OFFSET_MS); + //Serial.print(" compared to the mean offset: "); + //Serial.println(mean_time_offset); + time_offset_ok = false; + counter_time_offset = 0; + sum_time_offset_us = 0; + sum_time_slope = 0; + mean_time_offset_us = 0; + mean_time_slope = 0; + failed_offsets = 0; + } // out of range counter exceeds maximum value + } // time offset of TOPSTATION out of range + } else { + new_current_offset_available = false; + } + + }// receive values void update_screen(timer_state_e state){ @@ -567,7 +668,7 @@ void update_screen(timer_state_e state){ char string_to_char[50]; - float curr_time_local = 0.0; + signed long curr_time_local_s = 0; switch(state){ case TIMER_NOCONNECTION: @@ -582,27 +683,27 @@ void update_screen(timer_state_e state){ break; case TIMER_IDLE: header = "Idle!"; - content = "00.00 sec"; + content = "00.000 sec"; footer = "Waiting for climber"; break; case TIMER_READY: header = "Ready!"; - content = "00.00 sec"; + content = "00.000 sec"; footer = "Waiting for start"; break; case TIMER_STARTED: header = "Starting ..."; - content = "00.00 sec"; + content = "00.000 sec"; footer = "..."; break; case TIMER_RUNNING: header = "Running ..."; - curr_time_local = (millis() - start_time)/1000.000; - content = curr_time_local; + curr_time_local_s = (micros() - start_time_us); + content = micros2string(curr_time_local_s); content += " sec"; - curr_time_local = (runner_start_time - start_time)/1000.000; + curr_time_local_s = (runner_start_time_us - start_time_us); footer = "Reaction time: "; - footer += curr_time_local; + footer += micros2string(curr_time_local_s); footer += " sec"; break; case TIMER_CANCELLED: @@ -610,12 +711,12 @@ void update_screen(timer_state_e state){ break; case TIMER_STOPPED: header = "Stopped!"; - curr_time_local = run_time/1000.000; - content = curr_time_local; + curr_time_local_s = run_time_us; + content = micros2string(curr_time_local_s); content += " sec"; - curr_time_local = (runner_start_time - start_time)/1000.000; + curr_time_local_s = (runner_start_time_us - start_time_us); footer = "Reaction time: "; - footer += curr_time_local; + footer += micros2string(curr_time_local_s); footer += " sec"; break; case TIMER_TIMEDOUT: @@ -624,8 +725,8 @@ void update_screen(timer_state_e state){ break; case TIMER_FAIL: header = "False start!"; - curr_time_local = (start_time - runner_start_time)/1000.000; - content = curr_time_local; + curr_time_local_s = (start_time_us - runner_start_time_us); + content = micros2string(curr_time_local_s); footer = "seconds too early"; break; case TIMER_SETTINGS: @@ -721,9 +822,9 @@ void failSequence(void){ // first tone if(failsequence_count 0){ - Timer1.setPeriod(FAILSEQ_PAUSE[failsequence_count]); + Timer1.setPeriod(FAILSEQ_PAUSE_US[failsequence_count]); } // increase the counter failsequence_count++; @@ -739,7 +840,7 @@ void stop_isr(void){ // this is the interrupt routine for the topstation STOP button // this will save the time when the runner has pushed the button if(timer_state == TIMER_IDLE){ - radio_data.topbuttonpressedtime = millis(); + radio_data.topbuttonpressedtime_us = micros(); //Serial.print(radio_data.topbuttonpressedtime); //Serial.println(" ms <- current time ** stop_ISR ** stop button pushed: "); topbuttonwaspressed = true; @@ -750,7 +851,7 @@ void false_start_isr(void) { // this is the interrupt routine for the FALSESTART button // this will save the time when the runner is really started if(timer_new_state != TIMER_READY){ - runner_start_time = millis(); + runner_start_time_us = micros(); //Serial.print(runner_start_time); //Serial.println(" ms <- current time ** false_start_ISR ** false start button released: "); if(false == startsequence_done){ @@ -773,8 +874,8 @@ void start_isr(void){ if(startsequence_count > 0){ // play the tone ... //Serial.println(STARTSEQ_DURATION[startsequence_count]); - tone( PIEZO_PIN, STARTSEQ_NOTES[startsequence_count],STARTSEQ_DURATION[startsequence_count] ); - Timer1.setPeriod(STARTSEQ_PAUSE[startsequence_count]); + tone( PIEZO_PIN, STARTSEQ_NOTES[startsequence_count],STARTSEQ_DURATION_MS[startsequence_count] ); + Timer1.setPeriod(STARTSEQ_PAUSE_US[startsequence_count]); } // increase the counter startsequence_count++; @@ -791,21 +892,21 @@ void start_isr(void){ } void send_values(void){ - if(offset_sync_sequence || topbuttonwaspressed || ((millis()-radio_data.topstationtime) >= MIN_DELAY_BETWEEN_SEND_MS)){ + if((((micros()-radio_data.topstationtime_us) > MIN_DELAY_BETWEEN_SEND_US) && (offset_sync_sequence || topbuttonwaspressed)) || ((micros()-radio_data.topstationtime_us) >= MAX_DELAY_BETWEEN_SEND_US)){ // store current millis to be send as reference ... - radio_data.topstationtime = millis(); // set the current milli second count + radio_data.topstationtime_us = micros(); // set the current micro second count //Serial.print("senddate_to_base at:"); //Serial.println(millis()); //Serial.print(" -> topstationtime:"); - //Serial.print(radio_data.topstationtime); - //Serial.print("ms stoppressedtime:"); - //Serial.print(radio_data.topbuttonpressedtime); - //Serial.print("ms offset counter value :"); + //Serial.print(radio_data.topstationtime_us); + //Serial.print("us stoppressedtime:"); + //Serial.print(radio_data.topbuttonpressedtime_us); + //Serial.print("us offset counter value :"); //Serial.println(counter_time_offset); // send data ... if (!radio.write(&radio_data,sizeof(radio_data))){ // Send the counter variable to the other radio - if(((millis() - connection_last_established_at_ms) >= (CONN_TIMEOUT-100))){ + if(((millis() - connection_last_established_at_ms) >= (CONN_TIMEOUT_MS-100))){ connection_available = false; //Serial.println("Failed to send data to BASESSTATION ... will retry"); } else { @@ -822,7 +923,7 @@ void send_values(void){ connection_last_established_at_ms = millis(); connection_available = true; // check offset sync counter ... - if(counter_time_offset < (4*REQUIRED_NUMBER_MEANVALS)){ + if(counter_time_offset < (2*REQUIRED_NUMBER_MEANVALS)){ counter_time_offset++; } else { // offset sync done @@ -833,4 +934,12 @@ void send_values(void){ } } +String micros2string(signed long microsecs){ + char buf[32] = ""; + String bufstring; + sprintf(buf, "%032d", microsecs); + sprintf(buf, "%c%c:%c%c%c", buf[24],buf[25],buf[26],buf[27],buf[28]); + bufstring = (String)buf; + return bufstring; +}