ĎkYTohyZ>lb3}';PNGm=(܂#/\Ǜp?aN^t˫gg OȲ zWU WH(kB%\>8p ۡBI$H-C3%O,!:c}7ݧ0 YT(I"FD#/;Hռba߹ ^BxY:V ByXES. B$"0*ak6!`}l%+ޕ:S^b.U#/#s|Ή?ߒFm`̴1>XX/IYL3m7h]Ji%PR6eG,'[Cnp堲JjT'mG8U"tbSS "rbY5qZ8`9aYh#/xpHN0-Ό~Uu.bFS\qͅ4mn8߮d*-K.\Axh.bpxL7ϧ31D2lzr#ϯE~ .I|S#/;<9JXR,`ȥkY44a2M#0\qP1IJ#$A".gܣ&.:Wˣ B #0Es)w|S.HEߠ|PN{;6EoAP'9-LYp8xv!cGYKݳ|iRspcd}EC4#04M;m\kVԾ&$"0(&IjDbldFҟ2U#0oE2caF}T|icTD$/g1K<_3p1X}S8Pe::䛛;Q,\f<*S'#/d]Rvst[FěQ[Ң4TB Y$`;#0VjT&eLUY:$X,6܉li7+Lsl3Rt#cS)}'<;r _W;fgnu_Yc|r!=^[|gr#/HK4M-߿j8ujB]/S=PGߣѠg%ݫ,k@Hen7%>oSC_#_~x:qE_ 匷q[$}PT=]#/&5#0PL3h\F=#+%|v}ӿDl>Y{߶ٹ~L#/߸am?߳kh#/##/SZp`\<`7{L0θ_Oo˫DJ#0:?%V4kM5P%$7fz<J>=oCWC#D|.M6d#0-SAͩ,$lbQ~WM^۵k-J#0B1%/J#/%F-qxx"I[\qpR`Lo{(A*UCҮ蓴5t?~Qm#/Ssk0>ھDeشb-Us_S~opŜ/=YRoRm$]6٫Z#0QDPOр~{pk1=.'1g\w-~0އ뷟iRV1ukG5e'?഻Y1__>/X_;`"nxiepz8y#+|P HMOHֿ|m#/ w@.w>7@abAU%PmWrVz!9ƒ,O:uEB'bg~_͡Wp`&, á!:mC?ć.,?dBkX"BDbHP=lz|$>-c|A?w퀏Kg־ntOi逴9m>FlKTL^~SqcR5} |ӣ/}Uor?#0:#+ʑn}ߺ.A@r 0H:;ԬŌ9s\|f${oJ?\vtoL LugW_|xIY\HYNrqXN%TມݷCPcL|A\q`@#0OCe(^u>Hw^[$ *G7ˊ"dr}v)>`Ĭ;.b;2}ȚͷgO@8$(*NaP>0LO2B{LJATM@j*B''Bѥ_r {B@f#̯!@Y* (Nҟ?;~~pB#QKpmhR3129ûЇ-\He$_ǯ͇Q w,[iW]͞n}C<,,$p_6A9įXTCA״==î]??7xE#0A%!.2wѻhѕѰD#0u.Pj"ZO&1qUwC,qN}-|^p&)]gW)~q oW?Nįep#ﯱOkzg̥~-vv;ȲSx{l~n}ߧ`߷6-y^z/XS]mZ>&(Qc~>.CiMZ:ݫۯէG/?qł2ѩzyNqw)!>rg"]ώJ{LRߏ&;WK*f~(̱ㄝˆ:#/hMsKn~l忓cf,+'wK#/ii뱣Ѫ(Ct 5b?aGo틠9S/3x et/oi<9v_Ih0vk=YwoEWخV5y6_gV[P[6w#<ӆO9Gww=!/2+D#//F4TտPTӿ϶(Ga2{NᯎV{m7oouϳ[o:Bwח#0:;PAOt'7VG?ٻP|~Wbz>3|prwbzzaU|4ne@'ڞhW4iG\dPGXo$i'V߾ϷN ?Q']v쿮)8WeRլGwF^Vť#/ڟ A#% BAV9~ΰ$gTN%i(>ʨ#+4uu^Ε]m~} ̄mGWfw !_XD?Q76\bulj쿣jBԉzOWeߛ1ogp=s%,{n{j(?Qe?FӦ?]v8f78nƣXNp5vL>/̾iGӀ#L8{ŏl#0~-O8?w>Ԫx'jG*Bh)CS?f~aB#+/]x,&o*i{׀g7Nmm跻|}bL'v4Q8%v-qD宋)clb^bV?{n]_z֮;B/;J|E0R @ J7NRUx%Ӛ..`.s'+?F5x#0<}$zYl7ZLG!! );HᲫ#Y9N&or쀱BGƊ8W;qe͝{_uÌ#0KlWpniW0#0ea'JN=t=NG:Rog0i҂g]<;οsnt,]EsJe$əl7S@r|juy'ys>oS?D {]RIkNB'i=ш{c9t~Np#gCy#+^ǰRJ1-JdS!z52JyG=`YG@#+\ۃPm/2VL42}?ШsVRYE2+D*~CY0)0!]#.$\#+)V-&LdVepsȲ+;|NriJe+\9jKpХ[.T2C=4Rm9w֓U!'ruǦEY%"KD rB}9kv?legNO/SyVr/OaD3l&R[c'S>_Ç&f7g ȼ("ba^ )eF*i[r[k@JlBH{v.ѩ4W~.f_'IFfil8Z3Y;UG6}+G͕_yǩVϿhxN_T]ѳI'\L_n>-2? "1lx[~,eVMqeo':|G#/q`pFOH8t;.GgjQ-$AW8#+flU7|\@VB:Nȓy;?{zsZ\y7Mj['owկͳ[Oԉ+?99[%z_XRwꈔs ІLM$gS0Œͥq\ɂSLGJLMe@b@E_M#/RC#+6#02"PILW))X02hKq^rぉFE#04T%KD߂haQ䖔i.1)J-thR0&ƞٞ/SEÀ#d5$!xTԳ{88ᙍi%@fcQhq5a^sC/#**_!dudzG6U$LTwnXBsE+/>D3?vuSg}9A;n5>L;&~O#A;nus$e1N 5hdG}:fx;s*!(M5\U.BI,ʪw#Bfč'8IP9/yC={I걇W/ɮI$"PGhgR3^</c&)5ɡfpclFDz;:|Vì~|8\S]y$$%tz`ۗ0'=W5#B3 PIOlU U(AbRʳ#0ZT[&X2m&8L.xpLԢ)3w/hyzƟŤoc>ߚWd @ł1{^[cL3/:|:`pijut*#/;-"N&nBXG9a1#/)( jphn鹁4He']HTp\2ӄ@7Q%XFaο`pXR̈,ftRdKRO`(`̲IY (sGH{1p1K)֛;(ُx7!=RA=8<vnJDgp8QTd}%~sN~[F6$ٟ6^]) pZ3=@\\PBiv[o#/Hʀo][3xC;l\<^8#0vgxp$vaIM]UV>>&eП[\Rnʈa=~?u߷?Ûю.u.Wx>GƝ`CX_d~(~m[<2fUq;oק4@PD{MF0}#0У%ck鳉}7eetJl3+-8Cс1VOeg6۴ѧPtOY5nj{03Kd,/{08rjOcrڌ[B_lhb9r$>삪h.5L+g挹q?:TD~YouUx2{ayVctD*<6z#+@m34kϜVi v*2D7#0GXŊ#0~"M N&(oLj@Li7t >Ec44Վ:MZ'fN {`ABg!m犆d'ƘWÍ`=\&!Ta\S|K7ߝe]ƭcZVd1DlykR>ǯ{?->ĜAy=e=7.Ns\Fh0Cn*6-d۶ҹH/Q#0:6K~6uQuvwPVM%*78(6]qq(5#/k[l:1]"c"tb393eI(ijkx٪]:l0Ȝ2SօM rI6A(%hv:0lܻmO$Ԛa69q4طͳC!(eݹuʟO0@QxK%6)9DcB17*jۡwq9"'aMmM?"wQ{؊VLüwP9rd(qCY|"eM^X-ai#xS#0HS#/HYwڦ]O*^a}:.?g7>MdUdBJ]tDB3LDMubG8AbP\|aJM.pli&8#>d;O5þQ.BI0qK2`s9>eGOY30ռ6^=A{Zl.CiB"C_t%utTxw}.6R7T+#/8ΙR}Cޯ@t#+\ӄ}&^t>QzWл>y`.tw12q$#ͺ) ~_=]q}rzPp[R뙌@%G7|~?|2Rh!SF`~3SԻ,/08'{b3#+Ìw¤2콵GE%dbI_~ϗCйN,y}?/)>v?`i̛= )wc5ۤ@9+ɋxJ>ND|Em8>5q$0L61W@8!JU#~Z3_θO2>'(9jM@yB0Lcu2ƓvIe2P VȖ`1l<EjX+8wqc뻨Rdx8oYL [摟#0ݮHBZIM+LP}[wknfew|(?S˫l2BJ=GkΈ<*Xƌ6ٽɁf>к.(tqDg/v2:m!A0)MM`Ròdzp=y5LU͊;odt$L8g&ϝuuvIIz6#v(|_e ȡ]jR5J9lTk$Fzd%4*gye N";#))@ICI,\7Io+#0b#/˷RZ z=M4 #bET25EH.T82{[uΌ~[ii1#aAIXI1A*ël9HZahJk2#x#/צ"!4~ks6FT[M/\Fd-t4W=(dkژ{lI#Y2$ЊR݆i#/؛\;pMyHT.6*7^o:hc^`i49}C;>k4ޝ{+L1QE-a IQ>GStO3\RܘrS:.>vrrOGo$Hx]E~BudajA,qV<`t׳P?UD=*AJ\+G)XRZr+DOS:_혗ߎI#0Cռ2M+/{m)OM+h5NQV#\npYԆ]JT2Ye:<#/l[|̉ÿi54W';(2{FH2*V8dem6/,BMCj"xշ,A>)p4Cy9-c栲ii]}rt!#9f\;Jf_`ƵL#0ghOF9;bOpoc'oH/#+ 40R2\H+9 _KVX-r}m#0AMeOhѮucd9ĨU=ʷ9m(Uk+iH1[vZi(-hW -Z[:-WssThW#0o9>po<_\h9֓n{*90)#0,OtlЦQbǞP0ؒ7_9o6N-Wy~JÌmV*nsu hӁ`(q'.7/8UEVfcⒻ8V8{CF[,Íe,.#+r>@=FV攨Kc||6ZgAvMI -:{ t.step{G9B/qX4تچ-. ًERt}v*[&}#0ʎTx/kߙf}!!fSsixЄBlEe\]+#]K?Y-ɚwPXvlh5qc0l6@KDmZ*)4fG\<ʪ~K$wIt5-8U`mȍFxyJ=5e|0bl"wn{n)k3tq0'H dJ({Ҵu>H)#čIY_#0Jp|JBNac5/ªǍtl߶m.;TPHNB@[J5ݺ/JߛcaeaTU,b"[:Ymi+#0pa$DI{7~NqQ2r(PEC7C|ߍ,x`l[cb#/.}/mGȬ 'ocYAMqCNa`l1kΝSI*mb$Ftq\hg]/qs'O&0Gl<ԨGu[DQ *RpbJ~ =O?<;&cť:<eb;LYoo#+{U`_(c!R$#/+R"9SMA_Id8Ïךv"ҴK&QSKXSm±$H;FS2 I`w.ZLC\vu4uNg2 iuMc&eQMbe[TCZnyȅ!q#0O\N;Tǧ>;x~6Ƥ̬*|/[?Ǥ6Qq^17Gmi]\ElF5Sde֗~4Y<.~7GDobA tNʔC&z#{Mҕ[úoS?J{ٟG@Kwߓݔi)Dl*`t0:>1[OS!$.$(ԘQh#/W+1#- pHz#+m4!1ﶰT&^<Ե%l\#/ISSBr[,YaϦ6`靮Ksظ?>֬(iF'sKzĠt>]-Ǒ&:qu-+単^:Bii5ʕ #011`iCJBE6ieŜxv}+R?*tl'K'_kIXt{\]V{;HɡU yCtkQ9i^!0VïhD`:qt2}^9Rxm߷y܁9a)mq$/FXu#0ҝ\V2*sH}ảsK&{03Ŭg BKtU?N@x"Os]c_tde>g19)#Qժ̜ů!wιm)?uTDž|vGu:YhGo'LGĢ9`QAƠq4,!/,=G>.zU">;f*>zmMh|*']hFE{3y̞_Svpb^r}[k]'湚-ʎ<{[yt_\)ݝlImtcQ\\&7r1is1ԡӸSwZdNz1wnީeGlaW5A77FFƤdoR2i4rZg`:79u\=y6ΟCFj#+?>īOo>`(ﱅuyuVugԨ&'aSIXb,4|ޡii S6zUL;*I-6o~ϛǽt:{"+Tېxrn=~^@v0[l!h;ݠbGl)9ʎiN)vL#0o9"ηI#/zn$jnu# 6})M9,*Xv#0~!yc4ٿhIS*GۆÇY0;$bCR6+P1yAg1E.;#+ˀC.ZJVz^Eԥ~mvo#0;s;DQɴeQ!fn?wݙɁ @F{#/*m>1Dp>v=@z|*!#+ϓ@ƇUn-Jwe!ľg;J0(=Rd!5xN=J#+l#,>xCx1嗓'<M6IdcvgY6d$(g>HHQ}<r#+`0aI\'ZuZd8cm3(klHlDDA &]|8uwL\nx |y{/Q7J[*wBզxyE˵1.7TFTD+apX.EY$6?0~gHyXuE5Hu`H^bK^EBsuˬP1L{Oɇ<٣xAL`<8S|; 8apHMe]%S1rsX6#/I{7N÷GU/.Gt,92b0!0ΰEŵ>#+!~rY$X!3(8f#/n\gkn%#9$9#/A2-'@^W"x@0~%,}\p/DlkaK,M%%$%X^)J}#0~ybvѕՈ;BB3륛C1f*0;hBHq #+(Rǯ\!!1Κ~95l\*V"jTS#X8GKzvGXu/f2<Ÿ#+ms+*iaX'!780:EHk\STaW5C\>xa\P)+ynH#t,~Δ1` ;t#/za+VY@c:Oxl[m#.zCF4<8z#/>ߙQψ틭1"v/pGf{6r4) ~҉:q̜lG tl.s$.[#056Lm):W&"ȍ)jXa7I|'͵IҠφ|wf1gu{oח~TߑjMNBCYy5[zwܾD@I#ȭbv$1`#/N(%oUac'~^w⺝]#+E=U#0#+-#{:q(Mriu#03yKiD>:/#+ɼj$xj$3ɩl>NLtwd:y"&ZzݵNG/+aI#+RL*>TS"1õ.#<}Q+iU5"h<ܒm@!wܝzD\(W#/vᅖ{4tѷ~)˿>^憃`:[3xꬺgU7Lg0i=GQt(3D/e[bнajJ!!;K:UŚK*LRib~>gEKmcY)k7i>#/Zxl#/p§l!Ɩ.VȐbDbB@NpE4UxTݾVP1Nvةv#/duf#vH HeƇ=fy]( NF3I#/\N.CXi43@H; D(<7 ;ͷU=TnQF衲'G>&Wc<9uNw;@hl<I80A9V;K],q&I=#,թ00a2S#+B;5-Uk{eY*6RUj[W2rRA,U/fقq2&[uWu5#0%uJoz>[Y,dse9䇾{:r&xٱcߔECc(=Mxt%%z)(,!e[o/~6:Ѡ6٠yn0M@'[iӮ]1L͊ɺPo¯)S/"qUGc#+iqEKlڊ,Q/S2,a]uC6&sьI coԃ% 0Clr4$m'(sYk#00IDJy>q#0Eih#V_eta@|,npԁ>[73M`rU@>YOu[ieUjeIX)v"g2"a 2L4[zN;;t9_c݁B݈D!f2)o~SBĔ 71qc%Ɣd'yj(^ZƐ\fM#/(G|P' HpA B{XQrldVPpujn2i`M%"hRwq͒$weKȲ:FPԐ!9Jc8M=FCnn{+|f0aOl{ ~UB'^CO+FǼ&`eam=wCyK8ɺ{}I3ڸyęԐЪ76N\]9v9%$_yUKf|>!MQXȤF!9=':#)h|faF$>$X:7h:+Kfta7Rc8M^0$XDN8xdjU"Q#09(JI.j}.(.X Fվ)˛M;9܉j2bq|蠮ݮg1LB7K#/ڿ46dW{`<$]qN?*%vv {r &Jh4ߒ'f;T##Džs;y#Y/18EyA.6NGЅdh~%N 0<(CM=A'Ri4lebMby~g&\Ro}:KeF̀$gCP#/n/OƼj15=So]i?CσwG˨'"h,x"jeD]"UC|*00u8{O2gz$^qXގNG`b7&$g/Zb~ >~u:?GlV=#+E0 F0e/]3nK\ /9'?W#/^j:?TqL7.C{T«Kw}&O}mJ s_X>2=ϼAڄ٨lI (YS9]ǟr죊\.z`(~h;TQ$Z ,ggEG>u0G.?R~Ҧon( hL?R*,C妭@qL/uD|B_pv;*4ztN>s}'AWA.Ԝ%^w#/S4P8IsA}]5ay\0f 5.z((HBB)ЮdcJAHsEZaM%v>M5π0C8cӒ>MGXqd$-OiPϰ;|AghvPD!#)(ub/|=^Xs1Qu%7u}{ƭpn+yP퇄LHw#/Z?߿D|d C%^Wm#+6@!M(yU/g#+x#0:&t<7;|o2ѷvqQx:9#+'4($vϭCsE|y)쭱d}O-?qv#+\rMݟTba.qft|}NQ!H?uP:Z{2ae@݊hĽOc32vT5:V`>{'ˠ/0=nLQ:w*\ۋ@<68D7,:9QPvдԣ-|'@תé:`Bj5bF[e3F^ٔkc@Pcl_O;dA^zY˛:M4˸'ʉ@ku_P/nٱe B Wv>gyA3 ADx[P+X1R99(>= cXqt+8$Vc uU2O@JXy+[yY0asj!Lvkeh<ؙu[ѻ|1lj`5g8/\oocxӢͺl [W0Ҍ-DJ{o8D:appa#+yO)3}H\GJHp|lhEx^=#+9ꗶG>kXkQ#0&Yw0I`eU, 21˃Պ;ٱvG|Uqws!|(Tpo]:7C(嚪E3&xJezj#/|[!zKG:^8~N{(VrsNeZԎ2]Mv)/|_%&M^qAdLV{t樎mko&gP!ޫs@lzOD8 Ԇ61 *VۯJRM,tngn^cҵ+&!U!^W%rb`BǔPt&1J1ᣡ/U͍_Zc2m1YɲJ\=]2^窵xb1(p#0>n|ȋO9w<-sލ|MLn><#/|K;)`j>I`bxӣ+7c5ǯ͙nP,gFL#/#/|O40/d)} bq2O;4|;2u,^yU@Ǚh' u\D8.B*k(HBQjj1H)ͣ{j@>{y`P#jp 6?lzu|FQDMb\#/RW˂?_ye8kZyvp"#GG,A'um#+Ir8(K`!,(DÃXSܡA#+C(ТJZL?h*qnPr\6(K%W:8B]ڢtS=^mj_G){˳2/r8zv#0vDN'<[)qROZ]bBIt-x} #R$[OE(xe*[С\.2?;]^+|0Rx.&eqOt=ןܡ"2R}Pp2~(gNIP)YR*D/au"n[RJ+Σhdn#0ǚwa˔=TME`i'}%#+*[rVm2Y7YhVvgJ/L}Ϲ#+j*#/ZuS#/^9Tp2c.'ﷅK\V<|"&zE&HO2ݶ{u(Cץ%qi"#0#+ g=,֮Iא:gRc*H";__Lf#0 4 Fd}w\S"\Bȅyׁ/RTy» T_Y e]pZhJ~)T ]bAr@W+Ưk.mʐ9IK#+'a'txKPc hD+rH]7LP/d>İ%aDHjNPt FB0cP2dؼ,, bf]̢ؓS#+匜M>ypT#Ћh9BY vz'MT~k˦~:]wv8MJWOt;FEy_FҸd:kx?0aIoljyZ.?=#x7\AR(~N#+)/=?fMfO#/6F! q,e~82#0lGHQx;+У+\0IϹtS04 ]vTE\e=Xg[d%!.x+v':2lYIR"ʌPXzuם$e2#=(0@3B="ˡt,2#GDhN:Q3&KK%inNke \ a֦b{b84]v'_ݟ=~.\7Au:D_$ߥe-@fQ[_-eALZ#/STEg*mnv궮\ȼco5ա@8u #0&諘9nA#0V#0lќ-Z$Ua(<@0Lel"CӬX_sEȃrI.t]0n\n@rWmrh\o5O'{x8 ]r;١l&ߠh]zTh@u*5R8v٣Bd!?(ۆa`8@!-~DC8!y<ո¯oapl~]%GiT{,R1jP)l,R/Z9@Dn̪e/Lnq$Qf2)#0%;-lUyӉ.J'K#0QeSWr};C}i>WkU/.(_#/~]+FH%&i"rj'WtDZ#/_Ԯl֥:3^!O 49V{ n(=9CM}uzT,Zۅ'ӟVWҙ#0Yr+gR["^?\v|{ɓ17ZJprs)r|<$"[yרlagy#00#0x|B&xVvטoIj@KGtmm˦fB#/꣐ߥJ#/}$~djD tB?ǴtA#0`f#g[>bLP7P8v$#+9LKz.klmd#[xx) a#/+b<wOw^#+z#&v^2-DGڻ߆0X<['$tvIAȷ#MU[%8Hb*)qIZdu?X:^zm_C4%Dt1blAd9U5qwuH@KB0um cn#+@)",]G"cDlTkc5oa|9_='s3xY|yd^#/w=Rlj#0`dާS@ݨOӭW=a<^qqmJZb/)mȶvqvIkpN0z[ʍٯkY7·-3[DN+ۤgr9y36L#/ٹvI+KP_V_B'ir>W$RrBƮ؆5rD79$ A.nW*xwZ*oaQBhixv)GZoyPyC 6fUfACЫ[nvgPZ#/dBDO=#pa81 "kH*OhY:[Ap!*SyVeKU\Z,ADǾ#bI~eUGDB-CQ#SEpMPE9%2ptVqrpmx!lU9Kg&O6ZX60!*m ^DSzp;bn[z2b}J"XvGs`*mK+Au~Oܰиwބ:òoxF!eY3䉔kcaFNQ^M>PΔ"o?oR4.b2e%kۡQ:Jt-F,m.#+䶐, ߥ t"qiGӝpvS<;N8yKk|{! ŸO/-}ʷp1!qq#,)jS/iaptHh4R-ۀamcܳݐ/<#0$Ƹ<-EԎG/#/_WQ5#0/ۮ~akP5ELSYAtq3bv"{|S!HW0Tx#+x^fب#+<#0~É˅̋{"'wR1˪V?rj4A}7H9)~~^7vcyGoƺ5r!3jeA1 1Pt#+KW[˒HFh`z%*:>+ m6O>+LYhT{*QFϷǰu>|=4pH("Y$!FC9ÁLkKQ~ҷI'#0iPe#/`C]}KۣU#+wgϬtJH-#+#/l5JCP{#/9I 6T/j9)?}(ZF't ID35\m/>@?}S9ۺH1*Vױ7{xa;c$ t60" $:G0괥H@x#/Sb{3;/PCib%BC}OB@;kdʒ|(Z}C/#0Mv6e^#+×>o#+{F`2Ьߧ}1eT5p`Q09FB> \Z,V1>-"옓32I2|Ҝ]%+?^P=7Q_Z?4zO&U_s}`]W;k3_B!mD}s)LfgՉ/j`$>d!_#ڛB_ʈ̃byt2S4oGC/7o_)TU0P<.rx;.@si:UwpSqAbiScLz6<:Yh<f3/s%joO>!Q#0NsdPKY<_@A#0b F+'!/>fHO#/Ь/ؖg/Pw0-@H@X#0GsQ@p*=MNLn0%!]^#/<^@@ ~(R~gszqDPH,sOVBtǰl:E$qh2~=qv{;Ȉd"h2~0W1~nn d#+Φb};U @]1P `dH)P|dNP|3oKGtBB5)R ,bY0 l%"7C=Qˠb?X_{hTuaUj퀌՛JĶYEr?9\:ZYvKg09LC_IǾs'y6qa`/-qmy6[s0U3y1j144;7qǭ(hz0l7,37:k\eT-beA>_XI$ PA*P=I_4dTgTnߡ9t!;Ƈ{zt5gy!=BLݦ#0"22aP7@!OڏڞCCpw\%09PGHBBA\8w52af#6@SV]`$ rPRmT2NƱGnUY=աR 0QuAGfuYil8leQ1黼_cb~s#+i~'5et9q7Y8l/:v&)$"H?EWN3v7J# FFgo?w~O{Cw_LDiA%u|egGpah$ٶ_J#/.XJWzolM!P6SA8nNUC@aLE#+əJH)̯xp#/#+lhn_DMŗ:Y)R @K{ڡC?0@ЊAFy}_#+s$#0Jj`S@0\ވ^ ūuJ!#+'>_=v|rQ_@z66ۛ\gI[^pj oBDEH;C'ѿ'G#+7a8zW(D@RAMh|q܄XƜ#+!>3*]l`~wڟQCvGS4#VGpDL)@]7/eXB`tSt?^"]8q"(Ȥd {1Ί,֪M]MoӑۼBqHt!ѽGU?wz9}XK=X[\W'|}j=u}U%ĭQ=fl:~x/w>⭥#+0>Jj[2I$0`ߴw+@]h#+w~ĊI:c+3>#]=d<Тw]8-Ѕ4GCC6!{h'q~h#/~RVG)w!OMA_rc$%#CjW"z#+su~BPYc]SBDd_3O;!ٶ"5Qɇ 3A2'kTO^&+3Q=x|QJ_@zI! HB>sm277ދgF߷ڜ|;H!w;s{"(I.YtmޜmlXġJ(~F}PpX7״@?Zyy=S)d/8t#+^t9@;zf1gؗd<#0wU(W~G_W2T!n7Hz Y=2o`0m܆[ƐYΚ X*ϗP3r#+L*$#0FGysմb;Lޢ!(TCwרmu=!qT!#+iT$|cbE#/:>xFl+K]}{:2{qьp!%Go Nq,(G&q/!!v3'=:. sxo'RoX%1#/_D#0B"#0maHItuL: CXh+/qEX]2i jh%R#+4`l ?SdE"9HF*@QJ*0HqDL^0Cx $fԻ1ۃ+38Ag?_V#0$0ň$dHe$xv(h\K:QGNZŮc֒&?!f+SQ#04hDf*5ʯJ]#m]!1fۺ̻Zyv+H;w_rp0eϣ aڽs3~B@%֤\n0ԑ2yM~#+hB&j#XD(Ԃdܘ:Ԇ![)D@ToRk;T(PFNi.K-#KuHټ-}nͽ!*0#+5J9k(]rg힗uhFՅ#0|Zyǭ?X?1 n=.b^j߰~X'+z55Qq:_jǞ?&Sн&2q^%yiioyGJI#sՃ&fΝ9v@nEJPg|#/v)} #G9G0pBux)eB;ĄG#0`:|Ͼ1R]#6FH_ǟJQBԓ뇼!CW%ң\4hZx2sH#/` Khl2IP459*~3?A&߸?V#+nB\Dg f&4;REDUiiiMFB%Ք"D;S蠚~K2!f!u;nn̐H$Rدؑ@o˚s{ºl`vH!C"a`UC@2źo#/S_Qj6Np@§*h9`e/vCCb#+>̱Ur( wmSwO&&Pcݒd0oe*#>1d#/^&Tvfyg_'낫K*#05=xk#/x-'xu!F3ܩ?wq1|EJRt8턭H$ùלP/y#0ɠ{0!k,<;x·HO*՝ti~GO4iI\"C1~2 3;٘<ֿӃggG@sr98~G{^;u̩]V#0 &tbàIc.עT~A4#/aD$#/!#/&BиuT/*XD'&^'̆?4VLwE@ĉ8T^ּé0L#0 N-Avko6cry.q*Bt^^%Ԫ$Z=wk+0C#/L]dfP#Xq(K'Q`.~gl-}1@DAFNe1)$?Jp`TB tfdF\͏Bwzj6bzh}AcA`Cޗ,ҝS|Ar2#/Lѫz;Nrb=sx}iרHII!\-t:UyyB*:ͤBHD+/Ͱg^.MĢ 9ɇ:ŧr\No/VuS),`,P̳"KD`b2#+=`i6@xT%4 H;1 'zM(Leҥ|Jn6r~G/|!?I@XBjEUz+ʮ=`#A/7pd-BD"0-7U.fSXX#/iW|ݿStU7C&_?vq5/a~Æm+%j!bO$V#+'C}(Qo!lK7?XP5_?p{1.=svhJU !8>'~H2^#+sJ8%ӓ7,?>zKW5X2efѱi/a\jFpkHQeiF1$GI(6)s^{2R[#0%UK4c#/G%+bdf"~zz-)waz2B^tk22%Iҁ1C3Q@xÌ&nF&kˉ`-#0='Lum &$:/n^A81/,)oVՋ#/$Agy[W?^-ͧiJ%bWE+ Q̒t:vNU+#/?Ͷ6|}|QK~P Dpn%đqkwlfuiWs@[Yrafc$WppHN%Qm~.nfV݊ߓQ dp(~ΗB'(EmFYANHv?bdU[?YjCh"-vj(dJz^"!y^ECpPyt=Zy2'qڪ +rp]9NCns`6ӯ~ͯ?S*dr[7+yMw_%31zldLҡ!P&1N#>|[0&r 7,3=#/NmNBU}`;lE0Nfps)2P7+;} :#89w=.h<|2=A>AFMv 5j`PGl]|\/TQ϶MpQ7l:6f\#0ɈBznos#+c(>b?'P|vv9 ?7O#0Z\cDP4Kx/dtq#0IaNO[sepkA:4MA{5VѦuu?jN9 Dj#/Q%unvC/=̶ b&͐8嚦[=GQe2X`.]4@¹^((R#0+@KRŒ1#/ëF48óe2vw]L0Wk8h[&b#+xiGgydim/OC_ZJsÂGz7"` #+!|}%|9pGA-c-Hy1tE/W}2+?8r{Y'$䴛4g_Mɲ>OFwspF{MzxnOrErϟhw0 7#0"*DۭD[t¾?vR; t߱~Kis.pƓu匒A!Pm<:;ҟgܝ]~`8숸Kzn7_=맇Omy\a/駑`Z>5{2yP#+]= \R&\0xDK~no#\09u}CN5lЈ9%avQ3KrlkODX*%BBh;5d0t%d^wf،OD92B@I˂x=ZMM|AoX'BΣJ/ps,g.Mr[8Q՟8]ita*fIPC#0ow4*id7@AzU8lkIb;-/F>teXBO7&nذL?~4퀊rxdo)'ߊY|dߔY0e^cɏ{;@1j_ªJcQ@tٷ8@vmݿ#/p2߁)٘~ p7#M!%*F(Dc$^ny*94$O(u:!,,g>4[je<0u#/1N᮶EWf#/̓#+w#X#/`[vPqi*BQT$¥afT̖g;M}3˙VչKC65`$3-͑b6 8_uA\ Br8uH-F+NvtyPA<2u;v]Nvpp)Tz~]܈hbjP(k4cl6,4Q98#/;>FHNp9D0#+!71yU5Atg+۪*߲vo''#0*6}zCz;Z?OKp2k81UE4۸A]HP^5U#/01ShRTI"m݃S/Ll0 LCpvk3Dm7;uw[*$FJZ04AJO!%]ܻ6:Hw#DRn0=LyDd>^ \),_w{w+n`krfz\ &plĹݙW'UQӤ%zm\')vv$Qe@Lm0ZX]:yw>Še2d=+R*Saug1#SKrNiv˺a9iitsCHNL#/BSjܨ{xƙ1:DP ꊊ+ЇeS+^Vnʽ%nT3#+2lr\<6tU*۶k3ʮ4E#+HSFA,:E;Zw([,Y`']L5m3}YRrnzM]84^1b@rD#sslܳO@S6~J~ɈNJ5E~'!މÓ#UuzlyM+&DLX(rHYG@5!hFJcM4 y`RHgVQ'S2Z"Hs& e!,2q!1G|Efr#/3kOY/yzԔl:ODWϬ9v3BrQb/'U1e,1ɜ5)7H/N<"'vm>T#/YI4D!#0fZ\0'T~$)](@Q(]i2L$ü 5 dz a[tx;Ȍw09:|)P]X/[Lev<NWpC;oL}HAF#0@qDY`9Y0UuħI]Ns17Hj^~Rdo2x!Pj`s8C}at_8l'(N{ț5T#+!o{ϻJ.h#+{166l tV!5JnBfa`c䯄PH 7UMKnۉP@9btvG`(?T0A2prR5UC[5.mDO9KϷ5>ݶK\#0pU9;Hv"Ge"f$Hvc=/1\Y6;i\&tch)ZJCPyY$D#+Y)Q/6BѯiRRTބP\I#K(|۪"R=!̳?'oAMhRH;u[֫OSԻJQl͓(ε!ξbP5#/^$vs$_AxTj%HBC0 Hiݨ%\%RoqU`@²n`T)O-X+=ҒcRQ$bvmAPI )kέڒ}H7B(vE#+H7#+:qI!6<9ta quO^#$!GE~,1 #+ $'y#0rdE 6B"@=]x¯/M**Ͽ&gucL>#0Hy,#/d,DaIF.zD [ˈfz)ʿu]Xzqyt<:4rP@{iyó!۶j^ Q,8a:HNH};$h32b\J,sA*'E~BUJ):~ ܛ(%C/W)D^#p5 ";AY#+*rWĤD\{@=LSC9xʤPOۿu-U#\sp_#+]pZû/0Ĩ/@@wm*#UBfmU 6jƒlJkkJ[kY3*l+"w`idVy\;9G_>H nD"c`(>3h(;mTZBxJ"-@{13#0h QUCk9rq9P&-5O-TjeEؿp~Lq_떁o3]Lf!t:TޤWc&^#+8'hǪR$0||:J5S=M_vب肋eALX߄S6hn8qLRjK7:wIQ][#0TpꓘW[ߗ!GĐgt>7nM}ۯf9D-9V~#+&5B8d>y9+%#/߮Ů~U=$64Į XwM;}'Onkk^#/#/xtu]$2C>D$(@G2s'x/E#+!`D0u JwW-VCD2?n!BljN}6>]ݮ#/#B9x^&"XP'/%O?Na#/`kAdL^כԘ#0f˦Iomʹ.#/Lȿ> @@䰂c#+#+o.L\]WT^0ܶc#/P5ɻ!P ̡qJ۾!@eAE#+-7ɇpKS[,pW!_d+%C@bؘ4']uc:&T#+G)w#sj_D-q-aˠ]7eeآ,yT_Bf[dF%;Gxґ}-h_to-\d\Km2@p&}7:דlAÐ|v#0w;60n1ljmϾ-NbdP>8>YJE#raNfAЊ0y9kf銏#a`Qh|19#+Ybd1@\{''j*D٥B8*XXl !RH}!HBa!*%d}Ez<ʏ_/DC<[lˊݪɁsݖ{bd6-&EϜ0b7PWyENFi^.?q/-gFB@#+dwx6un6>͉bN#+5I{6Kٟ$vxrp7,p 㪁GCq$:*ݼ=0NQO߹dFZ^-r#/EHgry$ZِKG#+=*O?b߯{L" #/HcI:t>qǿG'~=15^|K0#09N$"_ϑ'_o4Q<ڢD(_7RgQ=SR6ՑFqB'yG%N$fݵ,S5@1ZDdR\/u$>`:N@_XN&Z` t3d\Guv9!~T'ܤ)b5NK4vpDr&זij7!@2@$F2֙E[F}ﲷ_~0#0**2C4Ŝ{,N@Bu 㠂nre#+EV#??)mrA>#0- !CA6OmϥNR7#EUב ڪa Hæ`;tA#/iAhRT!Y=>%qVvZBH#@r1T:gLGg{#+^m:ݬNB{+&IŎ(ZAa#0DIaBXB0pQV0I2@дDJ,ʇ9%C((>$_yԆy"^lX6U0TAiR!l~v~\|c!wqG!&PYiCCd^BNa ᳩR&kw JXؙUU>m0{I$}s+Ed,ѻRF\b8$"S%< 3Kij Dfۜ ʶE$+՟$$06m .: $ 3Я#/QAT[fnnxհ#0?j^ #V%B#0m#0*[}W:dZR?s(Gt JڰT6}[IӮePII$NcJ%+P@Zp)s=CI-(@@<պ[@#+ͨC@FGpBAhp,#/FA@PׅiЗ9xTD,8|83E١&܄Lg\:]9MnIb2HS!XTC$Ji)C6o#0CNRqʙL3P#0sCBQ;#/)"D$PS8*Ï >-Ø(懍+1!NՅ2 6<96AHD*!zQEvq|Q /t3'ddC<.XYǦO蜐\UmռY`\^[kۧl@z:oK^KvW/N |bd4'6Nvh2\($B. ! f0T|Kb%`X,G$h%@O̖[j~iOvU2*1EXPFDʛc>FZr r,R(DOJ#0qM-_!N&HL8FL&p^|9P@987;^IWj01Z]_F}Æܪ)Q}>xiX_aVI:N2ZkM.M:Ro =#+9J{eUd022 .{wC]ȳtbhCo鰛zW8%kTC橌DTwai=f(a8Ã䡇iLp pf=PFdGS 3'baQBGmO4bɟ#/U09\aڼaJ8ɻD:yISC(Zhaq#/@Ww]iyoR[,l1EY ^|^:l XdWdQMV.P<05"-Z}ۡ,y:M:R$5XhY.H.[u:AP1yv#/Ůq!*wq#/ؿěd0tKV1K̀lh"HJI"XF3fE|S6an`cSS"CѵX |0U {%N=I;NyNꇈ'I*/NNJ(1#+ xIÀzWcvӳ_ZgFۈ DKa`ĜdNTLaI::bȂ[$UѴ|>|65(BŨ|"C_i@4#0@'2`3wwll$Mdowoّ<]Vqs6&'HL|SV7JcmPSB(K\{e6|s lLCĿ2sZ9ȽmJ-tjZ#+-0~-Dom\AB:q:}t #/scsiA0#+Q`ej`(Ja&:@?eN,!ʠ=(2n!&Cc)!<k{$@*l뽎ƀ|le#+!=S&PBD7NaLT9p9O sm38q-!ɿﰪ$z16[妘/H(A;WlQMUC3RPv,7e0$nz$&Ke#/N=26]6QL{} B H\#5k\mm\ڶ[j5rT@$@#0 H]G1C0#0YpO~?$b#+}&e1emzےIL-L$&-L&J)&m{rMi1dLfLL2F(Њ%(_7uIdP̌-A3#0*J(RE2VS JLhTf Am#L)M&|ݧu<kp90Yۋw_+^>qq?z̢O[y#/5ABaڒӻf*[@|p3>ݛp41PDeǂaZF4ֈdV#deJ"(/eÊ/Y&(iC4TnqEBѝ>CAM+'LY袾 !W#uʪ$c7--ߗxqvCiwS! 6_*syj]@#Jw9EXS+E}!EPӊ#0+G0a}kNo$-'xѪ5LD /mGNܯ|\DngNXb`[iOy]3kJ#00Nkyn:oM}O\C~h5^d!BCȌ9wY*{)!O4jjcӍA8>Q>4q9o[fvp#+j8lɫw_o_Soo5DDŜʼbLj-Y5ɜ^WWN,ΜLNven=V_͔#|O϶5~837oI :KuȔK/mLy348$ѩgF7)R㞗_<0!JGh8Z}2̓bQS>7M0/'aK\^kRꓹ&S[2hYCTYFzK+yƦ߈s,#0;#/,tfH*@ն+Nl(řr NNsb;#0u=k̊#0Ib'Y7<BO's\^=VKTash5 z3+9qyZ2sPmPo"hT$8&K`4,P!B#/υ9|&֡d#/C77 Cb,/IC)ы͆sdhقəz"FEB!6(рb0h"sÈ"Q@XTCQdA1B[A:$T|3Pplp~;}b ڛ1"h q03㴶Fk+{l;"LSp}&\aw#0IXC4Pf0ȬE@MFlF,AnC-[,rCp"oe?4?l%Dz!v#+R$[_ZfɼuڵM0j6-P;-̬/-Α0ȩ 2ZBMƗT"QK=>4#0SMӝWA\ jR`*BXJ[麠͒^jy~ȵ&Oxw\#0A6JbjUMn?bPL&<r>pCo"Q/Qz\ #+#/X.ۍLܯW{}p8^aљnHċd*#+H]9d%]B·#':"lIfιC%Á+n֚.W5zzku:JGa2],Y战C솑Ē >gʏ'$clmF֊&5i,m*ѫ_CnUHΦ\k`.tC>%"Ou\Bƴ`ԒLHxJp7A/ӵfF#/2y>\Tv'|&!U"wEGe )'̲)||x13Jf2ikz'xC\d[*G5#0D#/TXRtne0"15Kh9b3B+MId,j[6QB w3ʗ}O?G|OK#/QddQwhd40X[Փ-%Fdo9֎1Dt-GI#,`{ CH0\N7݇oh'~oY4`\(Y
@g#/04A.B"+<(#0#zKc`kR^1G^tש_e]iP>.%@{:u:ŅJ;[[umKA^Ҟ}n#ɭ3zDj"+#/8MKXȘ8SSD5K9)dǘh:XٰCDP摘m*j+rB]ᨇs D`5}pƌC3L[#&RdNl.iP%* ]G(u= /)ysh,;beXh(y/Q^(č('ZkDԾ9Yڷ4$>0CaɤC$ck5¼Xhz#+b[,I<:D#/#/#+`H#0&$#/"]6k%Q?#+ 5B'^uV>fe66=+g%p4#hlObXk1u'( X(npЖimd ?Xm6jJ֯mKJ!!(]bwg|v|BxF(#/-h⸚21edZ9l9VW"ɽӆJLVfeJe:^mCi_;6b!UUꨌxwK!gӦ,\30\y&K-P̽(rDMۤv%br"L.tDt8%^ݹAΌчg"]\u&ĚBcj"#/ԧ}*n&5IzdAE!gJufj,]peL"Z-bktM]#0ۭu#1#0#0H6J\3VV]I-DLEڐ2"[xVjI)D٬mi)ZVZY-gɯ50X6ЕlҒC/AG(Rn;%A*'#p DC#+ sH`C=7FCRãub_&!נ Ў'HCj35=0sɪk(/" U}u iԲ',Wd8_615~WP9Í--U(ZX&i#+(C#/7#+&VH$;.?R5e20hAGbb7%mYr4_X'I},#+Ȑ"a#/6n|4#/Nw_pg;O.1+1E{pީC>HNB'u+!*;^gءsDpaY+-|x 5 q$5lIOA..Z6~HAT A#+/{O1p"QY*WnTռix얢{6EQ-$ʣ$YBZ&LmۭkMєe,S%+LRh>ڳLȩbMjm'VF+ |Nj뱣SAS6J2&SF*U~uȖ5{I(KV"IMS[[ZEAII55u*%e 5amogj6m6o:%*&%x.%166! C|eNaIWlw.#+er0WEO'}\͗vۥy&MP|7~0a3d#+Z'b0Lj,DF8do}f̳m(@A#+xz#+vEb+fKkܶ[0#`!Q##+#"WJER*j 6"SE"Z#+Hmilئf4ȡ(m2&SE*SoܡIKQY%d4#/JiRfacba[(ɉ,#/#/F3YJTʔJIi#jQ#/՛M!C%&4IIMK*ͱ-H֊X&IU,L4VԚ^]kJZm%RK{k]6ljijmVC1YPSdI!-ڋV5jjVHQI;s~V.e-,TQ+c][q;Z/yV~;ȼ#/TKzyYcE};_zxtuǞ; 1_&5ճlf=Z]dlYdeXrBZ˳!V!o1o|MdE,-haڌDKX 4'ЁI_hKP|M3S@)P9T+uc!?kE_l|'Dm<(};5ǍiT7e, Сm!b:s\M%#/*>?#/R.{/Z*/Pd`^BKjr`3z4#/lU߿$mTypZV/0VΌ"otv#+8#+$d붟rP yw#+#+#0Ŷ5T`|Wu=Nӱ#06gʞA DdBA ;g>,-.QAŪԅȬ"פֿ-!5%:O" 48PAHq'H!Dw#/#+cn{zo iTrB|X^Md5-]*F#+p_)1)iy@"`Lz<-8ï\fl˶ȓCo#/%§tVκK̃ccLϗ#x]m.tYlD|t|Y#ׇGSI2d&{#/|#0fbb A1ϕ\n{: D"ԡh&K4p1p#/pEg9#+?t6ȁi#,#+NdQXNΒLĄ$zbDmy.6gvlfoƗF{yJ/:a/rx]G|QLyB5/|qCO?aaf@Ӌc1c"f V*bDÛa~I={U].ĐV1sk(ITŌCGqGyMV7;0őj1,P%^6$ݗkdIbh }nP9-E7`Y":Auތ1TkRxf0VyaTB[JjJsq0#ǙmF \AWlL-EFlI-RsE}3ͱDgVΧp3B7ͼ:#0zC=-2]EEHuh)b]9wX:na1Y\MIgP0;@J7lǝ;fg@fx|>!sPϳO-$!Lu9gX߮\ F$#"GfY4i>}..jI"|v0% $XWٓFfa솻k|E).2O"c"l,2vXCXI*MqX&:ۈr){%/2i-A,#+xxL$C+,μ]Y,(OctTwA%FzVCUc1UʲI:< v xF?F"IUUW'#++;FGd,Nc0[?UCu,j>C &7~=tzK,"B,>%g"#/Sc5ஷ(:#+q{#/Wޠр bf?Ŝߺly8n$$EЀ& "+pDA=z@DCZ%3o0_7ZeD%ᘆm|XywXрj!PSI冽\,BТڹnp~#']T߿^nm,c;u#+MB>a @AԯtI J*(DUYXDPEIj4l"5#+$A`$I#+*s?K:A#/7)5l^ĸrLt>3>ѭxk_|c ֞)J9{Zlok?NH#+!"4Aϩ?"$M^!;}}DBdKtl@ SCa4(oxG"i=zvkĈ;FcxyfK#0RR{s)Ձ$$))rXe\dIC- QT-Sf;ZRqgX` 4|bjQx6)ڰ@SX{(Jsd}Y'mCP$;@̱d7#0JlO>n<뙘5t@Cq>h'dlb8QD&fLCӈQq.0R,xe@r2vya| ,Xd&'J60_) ,5of[1sx-^4mb%Jc^ht:fłVc =]W]4f!j2ɡn|釮SY&*(bݝr.jһƢ[bL{jUq*\)dȌUDI xm'i=Y4MB!R8'oyq2{hb0.IiejE-#0#/3MC:T@*F$# rĽ[n:L!NqȌSu-ڤ/Msߕ;#0F##+5)R$HDՉ/#0JaX(yÇ6fN=y!Tg[#0WDUj7/5iSIhlnҢLvKTabEUu-آI$HB)D)av;#0#+ t " #Ng4h#+RĄZG;\ >C(''O5\/Ti"+E#P"$BdTC4TE©tJ$=WƲ|e#6ǐ&@3RO緅@J\Y-[JTUryfDQl+hlЪSX]WuEH.m%IHdB1)$ڤm!Ψ@P2&CJSiiģ%9%PTT#0H)pH2#+HN08<!RȂn?WCD"3>.lXo[H _L@לG#/ oDPFQ#0RP~_w?|is;MRbH?vaD3?p_r-V0sք>aWܩHҖ#0{vƚY~UҺ`&h)6ݕ}owdg#+5^=cJ#/0L,>ߚF#/Ndx']tĹ˿ãHsTLhATqpy0H;R(v>{9~99}I^&,071D=wHް1!ݻ! `xBI\pD#+I$$$QD8s.g0ςIK4z_Ő4*SFG8b%IRKer[~Ktrl昏cE#/Lnd|Jym-9aÅ4 {+n^Xuh"RcO<0L8C0Bs$jg(IgӸ}Fż4!X##/yKFp& #bגY0"G#/Lhx#/N:|5Z<'Й#0ݡ .;Fak0ajJ2YbښZbdkIeL5nmjlE3X%lSŶVK2ePmeT֙U&m-$`Hċ0@S?#0>'a{d9KtM\#+>QJ$m]NVkZfj#0~^mA&"t'1ϻ MkT\Z'Rm-mRA>#ABD0*F50T0r6fI&~uG3KB#0!)ܟs @@B#/D#+;2= #/a"Q+qTJP1tH@J4'\AXwCMysテK]YdTg$|=)pJmŰ=0o#0eIk20Q:&R=3@Ȱ%"Z_x#/#< <ƈQ9WwrutG-v||6zzKüK^^':)L88!- 68@&ipSv#0rH0amiVi?>tQE'Ogz$?0ȼ?YT47叛=PX=+w2V#+DHcℐ@@?4|#0#/͒T#+g2rM$}&{'?T.qA4(Ećc^7nW"ٷԹeI0&'\J9e"«,]`͠mHDF*~)ҡ̵bh/Oie(~4H4!±JmZRMLCY$BP68@άFs03g[nwM9IъmBE^M"&E:j1Jzc4R"vlJh"f#+#/RNg!MT>mʺ#/X5~ΕX,nld#0M<#+$!ssE9nO_^0RUB!IAdK!Osasy@8'pcsIKXSAG!00GD쪢F@$%20hUAt:V7*?4gƸsFנژp%|Ȍ%jMYqt.J҅=Uq1 * $k&ɫƹfW;fؿ@C@y* P%G4E]A@P!dvt#0 x7)ofeK'af5Y3srM[,Nr?XtsHV9=椐`MlVmRy/'Q"ܐb^L%7'Y^˗Z-1#0!.|J5U&22:"qYN49Pjafv~MD#/K嬧SySL],u:`biZSBgڠ TL7*Bٜ (`#0Jjmߥn=PRL|#/&Kh#+() RLi["[PwgL#+\][|?ʢ6P#/hyv\aG4y:x5&2 "o#/4r܊Ghʄ< -K*5&Z6-&QJk_rZI]uT,ȗ#0!~=a>9xS'SܑUvաP<SӻG9`#+Otk=h*`avT)mZ6U`bqˣKCc4dћʱo;`uia~kV/UM#+䠴(6$p@x&q|L.zG=!2dcӖ,gyð!"z=X{f[mDPGkR˽n}F c}Dnv_"Z'HyoI?ؚ:wkT9u]yk4:h"=h#+rլ|OLC|#0N݁!ɇC&[%á͏6#/}#+ oo#/%#/żt!;}d_Gͺpw8`}e.6NhD|#+raDJC튗jצZꘅ&Ш~d1` s1B,lԒ\h_nNZLET$B*7)h"CHr<#03|f*.5!,$Ne0Y-ڣt8#0 tr`ؼl"0l&KHPI"ntIF|8t^OV/#+ݿ?{`/Z$"N2Jp+h\zaRcv5z#bII".м#(pVZG.#0+X#0Ct<f5,\>rnNbM~y(˔'#0ю-.b:髡2ڌ&$$A`h0D>ޔMGTk$PgrDjDu8Bzys_S@JӍD#vlp`v㋜Ǖd tbHR5JTP;#/מ90?O/" v#/RKmo]tGRu'eg{:@*Ot-?HtWs8Y1\gAPr|W.T !ke#0ix` ҢW7FH* 0=!-SJ^P`+CF6Ne:i}aP;@9i7XtRe2~P4uBs&Ewy<0]uZi"ĥ::r`s4%̳ŶFᇸiy[cf"(LiPR/A"#L&fS72[Y9fcXlYbZD2B dP(Y!]QA)0&A!xS5:0{#+Y\Y#+BbX:#7!Be<4OOXkj!ˍ6?#0XM!a?+#Ú,wKM[2jnR쁨ɴNJؖ&vޟ.e1OQqu?SD:1Y:lw1wXE"#/l$.xЦ,>$vlڔ<3C #+`+A!6$lWkVZPx,E+JR;]K$BD''9fG1ERB`s0ą̦NiL(R4Z4!pn̅,0n)1Y@R.K#/ ^Op~1,cx(iNwIxH#0RΈs?9'õX*3ubyg&RA1B]Fyzv$)@A@#m&"UWWVoD';q= r#0!0>;alKE3C(X]lMfOW$lxt9;v?zXӐ_ Dy-]>ߩLFɵIu#utnn걒:gvΠ9B~/IN,Dp3B=#/kHorգ8bkiQ3GL#/EhōK-ز@dikqAduMW;P_"{^t靝)?Cwqa>aZaS52S}3_'@;rt5Wvnf)Cj@.CB[q@T#0e1lGxEއ7-#0X U`lJQe45lj% P"X+=]ᱨ_l@)>z(>^zcYzA?Ьk3U^ܨGJI$XCYbf + $$9'BA$,,FTɍ5ۆZCC̘(8LE]-Hp#/[Ċztɂ1) Cunmޔi"^4`",##Q4 `pfsOͱq#+=)X|(q-DHDcQa|3W`l&1v DAdX EXD`DCh 9TG%XXHH0A r;&3Fأ&L-F"I1BbK4Η@(#N0SK_ԞӬ4I3(q`h8zkT/=h@ Tk[ih]Y@nS,b unG1;Ry@<"q'9ƌ^y?g9y \ZaRJ!5ķ0eY4 lYI퀈`XťQֆN&"@HV19ir\p `6f&A*n2bPq$bP%NbA9(|8*[DS$+#0#0{=ׅC;*8L*QZ@1,g[ǎQ3ttKʬ`1B-3LA-(H RD*Hc fj2b W2n۶ Ə~T##0CV9_p#+/.d0qA@]{a q0AAH3Tկ~wmV#+,4J!T#+x>absb@JXP6AjB+-ČEhad"`bɾI1S1DO?VVۅU"NJ#/flj~~W'Ce<#/O9i4 "U,U\m֒!&2˺1vӤ@lơOͬ|cdPقߡ^e`bu#+Ѩk2:CA?c ~8Fʀߪ2.6#+VE*mVjoqjTDeQjnfT;]/+ܑ4&DG5{X+ @٣B%A:Ӭ6v9X8-WW6d~SՌeM$}Ԯ$s/jq'lc0U>rL#8US3Hy~*#>v41ͫn-94^ml}%ap#0`#5H`jZZ-qDDKh|0Pl,6q0ه'Sl#09wxUwFbGD&XqFW[`- Zv#gRٌ'՝0B oCrQEEnI-HOiah2(2L$BoaÌ&BuVS.fdbcQRr^"im&P)#0J3#e8asprU1ЀD1aI+\2B`cLLn"#V[ɂ5Җ(ɂ(0JJJU.aʋ4]Lt0Izݝ&:xK<_<'@&`ު+d!1crдKSh\6Y9r%gz{04eA߿16sbOaA©鱆ՙNa6TΥ~9qRMKio92эnGLҾvOK\;@sOPҦ4Is`)0`fY2R:/-IYtahMX4azjXfY 32CDjCSq!RUv8$(q$d#0Er1K@L &FFID4ґ9fnWwԻ5vlo2i"#`ɹZܽl*t$g{,,\CaDl'nSVp!$)TOF2RP24(,C"EXlhK!M#+E44Y% )"#+9Zhɺ$>*J%ŵYmF)b$.ТOQңM7%~#/ڢbi,5oX.Qz#+?ٮdfT0`zy\;7bB!)(+of{$`1F &,|dTcR Dtd)"$U&J5qHq\0dݵHEP '!U 'Z`&J(nsAf,#0xbAd0ߔצBCyl`ڜ~XDl,6Йgy,kfxfb`A{wKi&^HO<`̐}*G` no|+A+X("H9?%'c2dDylIYdu44uW>$+vŪ$EXsm5pӡ{bY9|:Cv?u0@/)%iUh0G|;)AKuAP2l<9QT*߉:)#0lֱiD.GVqsʜJT9ui]@'gyp=wʧn# K:XZ3a!aU?Oޟ*~Vx'!gG\h6D!5HvS"?VyÑOyYtù,d%5+$)lH'?(+dknķ.߽-plV4srM[tH[rUY5˛VNs\dڃkxWŝ!g-8Ho*A>Yl,h|aEZ#0HPDh#+#0mJp"K0vulUdPpwU@_/G#0\y( 4־JJ z:L$[`=uXTd%հ2#/-~?пݡ FE04#+#0[nMj[oF,P%YT3e$WZQH[llj'" ވuԧ2?^Ӡ=rYRaֵ>L]%/UT`MDAS֕d8o+R'0ňyE#+A0Os.MS3diB#/CIhllЭ%e)2JIhRmQ[j*2bciH_7 j+ݰ)]`U1BMEWrnkDZcMha7(0#0aWp$!L%c5ce0IZDȱ[B(`F))P!#+-y4cEPj,`şζ@җ[FŕZAhXjJb#/#0bBfjn#+nk,l#=9t3w]asфQRMzB#0Fv;&Pϒw_qp)M]nXC@K.-Imd(;zI@FwaT?_N*nT"UcH!PSFD PGhz!*J,CDk;ǙyTe.m\klZ-i **BޗeK})nڋ0YOaK*Pvo\%>?N+(+)*DON~龙p]N՜uq"R`bՃĦ-ޯ!쵑vxO˄v\O{؇r:!e#0ӥ <;?O(1mp&>,;v@ dtQ1ory⨟Oghl\1**<ݙTR!#+꼠Q`ϦfLSktoLK7/m#+A.mQǮeTk%F«(V1$']=2m{}]N:Q#+)ҕԵH$-kBLyyԛ]2LqGOX0gQYX/d$QMX$2;= MtPS=`#[Y}q<:ƺp3#}U ywyzPx*ޞk㍞#/a1U܈FG2*5UrZF#0DdeG<}>.Ή0X[7W#04.TWS*w0Ml7|zu#0Q9Xs,I oaa7:ySߒ<5SC#s,SHioi|1*Ov5v:yM1oG==*>K;QXPKjzjծp)CMkMiFF(5V))`VBZ{-GXdwXhBiVkQ$-q:fؼRȡ#Dv:em.V;ݫW}㧦9]WN9w E~:!{u]ʧD]zܷ2v2no5qwѺ2nyKTq^Rorhw7#/A%G}>S'ٛ4宅!b̞_Qᩁ T(E%2OD4śgS<[]@GP¡b,!h+`^#/G'wdY7'mᾂaKFυ5OHp.^[!oar#0R:}:~ܣ@0y,:E2_Zaa~}k9>C Y9dFR#ZFَ"Nfa ̐8!DUV;M{n&[M-ιѥs'\aIO=%9H*hTwx4Cͺ\ǜ2`g[9Nr'g.#YYK:T7&JL02iaՒi21bFR6w*v//#0#YkYr\&Ed0gD`x':.Og#0ʆ07.p2%DN/q?%|4hˍBb1\;Xks\,@ziTHɄJӂnВq*<-%(cc!0N/8#/Iw8{)iT䌝8uC3lfQ}svܾ:fL)l"3J#+N%U2i1RUAJ"3-ClvN7k;9~i FV7O͵~)+mre2Bh!նvQ|Nd)$<bW0*EUDJXWu݇g<+.lӠ*Nz(i^$ꠌ|4|2'`J/X&ήʫ/jf!ԣU7Ѭ*h]w7{WCW܍7tɄE=J$\J?`Cs!Zb}ԣ\SD=~c1NQ$qhm#0PzaJ8#/oRf%rovsT2tMSZ䥎#/l)z@0"@|+ H UHꈊ'@P: Brt@]"I$QCmK&Y%ضDx,$UkǥO]x$*}#/积gJ(m8"B2ew KO!*$.``Xp*AjJAT35zd߿QYX*.!~hi$$(0P㤈3]BO+ASt̄pTyֺ7wbphu"^R'꼏FˍSH(,P~Uv0Ey{8u)4.(Pqky -0ٸwp#&yKUQ-=')xı\u:A(2gxbycWsF<dᴠ ;jM|7Pؚ?N8#+"_<ڿiXX%MJ}ٟGQ}\4|&*u[cb{{Burڋ)M\\O#+4~<#W=A;i-'wy}ZʪL$E]%ǞvR+x ggz+SS(lΞmRʝ<=٣IJwaY&^x Q[#/G!" Qd@Sdݢ#/% (_dD@vd,T^,NVXA"*R$NPIP"#0#/9K@ʶ+(隱r}{̑@`O$]2f;z03J s^.(`2,H&)VDMw\9pGsQ>ˉ*"-2hD,wJTG/=rwCd}nrM,q0:yTZYgH#0 U)tؗ-%L'i#0#0C%C5p ITaf1;R`7mX)ʒ(LQ̴K*,uMlM ͗$rÇiO|dZ vk)m]Hg0-u8d.eψ[m0Zyk.eFM:-_w|XUw'7$[vLUse*{;⾋GܛA6bݳ$O%U*Īu~&,+HU>cCP#0XGH|ts_>kf8Th2Y8q85[gavJTa61:/OV`p!sb`3HIM~ȂaLgXۜC|yc#+#+En{jwHG+i:AD#/w!',ES֡2rUJEcD'Kz#.0!VM iVzHdE-;o7v6-dFBfe#0%lM0(R`FS% 7#Vޗ:HHuTMcwfNUb#/55D'z>yZyAqLs)D,q-uto aaRL$ᫎxsC3a!ܤJQ'-Pl(!4Sk 65SG{Yϲi($!juUz4~jCN8O3Kx@ͤLI2r]N8mauʮ1KbL̾j~1+6.17 sq>h/]jIzp#+#/g#0w-5Hѓ%D_jlZ:3Hȱ0Q1tv^0+pBS mmZ(ZҐj=h!a$QrEEpH, h!B2#+TkymIҶZh#0<0(iRL8 qf!O)%gcq) H$ cϝMX:@#+H&}NneVA\-@z/3s}O*`\ta(ʍt2h[@D!WJ7&0H`2ĪčIZوRsJl1d"#/ -QYm+ 3'M𡦦HMdAyh!M舞gg,`BJx>?ݖP};0OJ2P"'O@m:' 2f#+D{oaȈDr9~Ez7`{#/2dQ¡(#$&Tg^#vNp#+ЍK2gI~ڴh.OnWCZo4UvÇ#߇hٝ,:@-c9!XїvqАDMN iHBZD,Imǻ$Jܠ(bH#+ȑB e1Jh-mbbm Q"5ZMqqCFf[E;S7Up#/:FڢSot؆F~`#+1&ٰ&IE\#r|/w Az"ENzӔ$sծ:Uani(V䛑C+S`N&tcI{}/Xr8ueЭf\1չcㅊ`344bH+r1l̆P35 );qp`@H)4$.#/KlEW!$&F4bsYL@1. | u2,7Gk#+{#+O(pٙtoyf14BaHfSQiF1pfA#+K! O_#/rWE h#+z"X#+G#+! !9ì.|/Ľ1(5P$`A80r\{ܓPWoDK NE=@B3ZQQYxbaD`G#+']}OM(˳N::8/H0qCu#0]{wOpo|D?FmN#+Vf#+#\=4nk?]]9/.#0*i9@v1@^Sm_֬(̏QQIutTc>"+d*JL͵dRSbCQFy7s\#0,F*J)-$ HI h4T2U?E5 C[_PU+/msсa=F9C[oE^^6cMaXF̌V2S(X2O^wm&@"yRp1{?w~oW^YϤv+M4#/FRxU/*gb &.b{1m#/64]4_c_,,%@Y T~DmJB"X%?=vHvA$AT䞕h") DB ]6UcjgiR۷SQ04nլ?ńJ0)#+Hݲc>;|ş{#tϻ)M9h^Gdv03/EY#/&%.k[h`9=U{Sq]>2mqzM&Ir$Ds1O(H{K`t:"ݳI-6#/1LP"0Qo7u3*ݵsȲݍ4M&ʒDƷռfR&2iiC#0++o"o%i^ˈ֥4$AHB3) c4lRםܷkt"%QTᇤ螢!XLa<4h߾/Bb?EF*p#+d_~ƜY)8`3#/7(.=~2`T]_l(X<В!ŁyN12$6pۦ#0T!LJlj',N{Aa3Tč[ȑ#0Bd/M+?d(F{D1i@aCjIf6".aakWT>[$#+.\H$L:N5,g/5wUf:o qFUNw1>';r4d?M=";E~9+ZբUu4`)%0'ܦ6r5PI8ӓ!>=F9""n`qwmRaA%gh4l(q =|)M?&(sBO\\}Pr(,)g&rXVωUO>ϻ 5op;*=Aqijh*18LjY.!!J0x!T\8`5[>ąpHH/#+dBOSЁԭkZ+$gnǹ<|Q'|R@c#+M#m9R;?2#0+!VC =4ji{3#+LtY_!&Z[:HiO%X~S#+LS@>ϔBr`}E3pˆEdAd#0[|U$&f|%櫺v=JOf,)G!{:Do]uzǎi嬠<.ރ\_wȩI0ӣ-pgh6R4yꀇgtn=z4c2`*+P?>#0}-$1zx&M5%SEZA;ģ6ڡ"HHi2#0U$>bX1uɀ8,.vj##+/P#0F܍E|A90j5E BB24/h6lU6Me62IHH@"k)B#+8g 'L@7\}`ёv|R"D=B >"b<]^/wt2}bD:;|Nq#0ts=#0&kuP~GDBwm-!#/yfj0Lceҧ~!k^PJ=m20^0+II)WΏ͝f/TW2$=Yuȉ"H8#/QAsmͶ1^-V4VT$:!#+2-)ePw!Q;dP( m߂ (CXٰ"RNw%ŏihdLwPi$Y#+J<2y#G{a?V~,X ju#tu͕VKje5[Wf,M^կ4`pGbwgL␊;tr r;wc#?^ `#+y3''\A;~>_|> ']BCJU0
+#<==
diff --git a/wscript b/wscript
new file mode 100644
index 0000000..5d6d477
--- /dev/null
+++ b/wscript
@@ -0,0 +1,544 @@
+# This is the main build script used by waf. Many details of how waf works are in the waf-book
+# https://waf.io/book/
+# It provides a good introduction to most of what's going on here.
+
+# This script uses a few of the extra tools not built into waf by default. If you are updating the
+# checked-in version of waf you will need to tell waf-light to include the following extra tools:
+#
+# $ ./waf-light configure build --tools=clang_compilation_database,color_gcc,gccdeps
+#
+# Also consider adding the --nostrip option if working on the wscript, to generate a waf pack
+# that includes comments (or set your WAFDIR variable, see the book). The version you checkin
+# should be stripped though to keep size down.
+
+# Onto the actual build script! It's a bit more involved than most waf examples you can find due
+# to the nature of cross-compiling for bare-metal targets.
+
+# First import a few things we will need from python's stdlib and Waf's core library.
+import os
+import pathlib
+import subprocess
+
+import waflib.Configure as ConfMod
+from waflib.Configure import conf
+from waflib.Node import Node
+from waflib.Task import Task
+from waflib.TaskGen import after, feature
+import waflib.Utils as Utils
+
+# This will make waf automatically re-run configuration if the wscript is modified.
+# Useful for those not familiar with waf or the config-build-install cycle.
+# The biggest boon is that if configure hasn't run at all it will auto-run during a build command.
+ConfMod.autoconfig = True
+
+# TODO: Remaining tasks
+# - Move non-command functinos to tool, or make private so that they stop polluting the help text.
+
+# The following functions implement waf commands. You can define arbitrary commands here (see the
+# waf book) but we only use standard ones. If you don't specify one waf uses "build" by default,
+# and a few are always run automatically.
+
+
+# The "options" command is also always implicitly run. It's generally used to add command line
+# arguments for use in other steps, and many tools will require loading here to add their own
+# arguments. See the waf-book for how to define args. Arge defined here will show up when you
+# run waf with the "--help" option.
+def options(ctx):
+ # This tool provides some nice coloring to highlight errors and warnings in the terminal.
+ ctx.load("color_gcc")
+
+ cfg_gr = ctx.get_option_group("Configuration options")
+
+ # Add an option to set the board type being built for.
+ cfg_gr.add_option(
+ "--board",
+ type="string",
+ help="Set the board type to build for. Valid options are 'ASCII' or 'DOT_MATRIX'.",
+ default="",
+ action='store',
+ dest='board',
+ )
+
+ gr = ctx.get_option_group("Build and installation options")
+
+ # Add an option to install the final program to an attached devboard.
+ gr.add_option(
+ "-F",
+ "--flash",
+ action="store_true",
+ help="Write compiled firmware to devboard",
+ )
+
+
+# The "configure" command is the first command we are overriding which isn't run by default. It's
+# usual role is to inspect the host system and find all the programs/libraries that will be needed
+# to do builds. In general though it can be used to do any slow checks you don't want to run
+# every time. Anything it stores in ctx.env will be available in all future build commands.
+def configure(ctx):
+ # Waf uses DEST_OS for some magic behaviour. If you don't set it manually it assumes you are
+ # trying to target the host computer that waf is running on, which will do things we don't want.
+ ctx.env.DEST_OS = "bare-metal"
+
+ gcc_srch = get_gcc_srch_path()
+
+ # The gcc tool assumes that the compiler name is just "gcc". This is not the case when cross
+ # compiling so we need to manually find the right program. The gcc tool will re-use whatever
+ # is stored in "CC", which find_program will do for us.
+ ctx.find_program(
+ "arm-none-eabi-gcc",
+ var="CC",
+ path_list=gcc_srch,
+ msg="Checking for cross-gcc",
+ )
+
+ # GCC can be the assembler as well.
+ ctx.env.AS = ctx.env.CC
+
+ # Do the same for "AR" (linker for static libs, we don't actually use it but the c tool pulls it
+ # in automatically).
+ ctx.find_program(
+ "arm-none-eabi-ar", var="AR", path_list=gcc_srch, msg="Checking for cross-ar"
+ )
+
+ # Need objcopy for converting to a hex file.
+ ctx.find_program(
+ "arm-none-eabi-objcopy",
+ var="OBJCOPY",
+ path_list=gcc_srch,
+ msg="Checking for cross-objcopy",
+ )
+
+ # Now we can load the gcc compiler tool, this is how waf knows what to do with c files and how
+ # to link the program.
+ ctx.load("gcc gas")
+
+ # There's a few additional tools that are nice to have when compiling c code.
+ # gccdeps uses gcc itself to tell us what a file depends on, so waf can be a lot smarter about
+ # only recompiling the files that actually need to be recompiled.
+ ctx.load("gccdeps")
+ # Ensure the pre-processor runs on assembly files. Without this gccdeps doesn't work right
+ # (and also some assembly becomes a pain to write).
+ ctx.env.append_value("ASFLAGS", "-xassembler-with-cpp")
+
+ # This tool doesn't actually use clang, but it generates a .json file with the exact command
+ # line used for each .c file. This is nice because vscode understands this format and can use
+ # it to provide accurate intellisense/go-to-definition operations.
+ ctx.load("clang_compilation_database")
+
+ # Segger doesn't like to be consistent, need to use a different name based on platform.
+ jlink_name = "JLinkExe"
+ if Utils.is_win32:
+ jlink_name = "Jlink"
+
+ # Find the Jlink tools. Not needed for much, just if you want to flash the firmware through waf
+ # directly.
+ ctx.find_program(jlink_name, var="JLINK", path_list=get_jlink_srch_path())
+
+ # Set the board type based on the command line option.
+ ctx.set_board()
+
+
+@conf
+def set_board(ctx):
+ """
+ Set the board type to build for.
+ """
+
+ board = ctx.options.board.lower()
+
+ # Save the board type in the environment variables so the --board
+ # option doesn't need to be specified every time.
+ if board == "ascii":
+ ctx.env.BOARD = "ASCII"
+ elif board == "dot_matrix":
+ ctx.env.BOARD = "DOT_MATRIX"
+ else:
+ ctx.fatal(f"Invalid board type '{board}' specified.")
+
+
+# The "build" command is the default one run by waf if you don't specify anthing.
+#
+# An important thing to keep in mind about waf's build process is that this function itself doesn't
+# actually build-anything. It just creates task-generators, which are fancy collections of variables
+# used by tools to generate the actual tasks run later (eg. the c tool uses the "source" variable
+# to create a separate compilation task for each .c file you specify). Generally the tools will
+# document what variables they expect.
+def build(ctx):
+ # First setup all the special flags we need to pass to the tools.
+ # TODO: A lot of this isn't specific to our app, and could be factored out into a general tool
+ # for arm cross-compilation.
+
+ # Compiler
+ cflags = [
+ # Tell GCC to use newlib-nano
+ "--specs=nano.specs",
+ # Tell GCC what processor to build for.
+ "-mcpu=cortex-m3",
+ # Our processor only supports thumb2, so target it by default.
+ "-mthumb",
+ "-mno-thumb-interwork",
+ "-masm-syntax-unified",
+ # This processor does not do anything special on arithmatic overflow.
+ # Make sure GCC knows to avoid optimizations that assume that.
+ "-fno-strict-overflow",
+ # We are using C99 as the target C standard.
+ "-std=c99",
+ # Tell GCC to generate all debug info
+ "-ggdb",
+ # Set optimizations for best debugging.
+ "-Og",
+ # Allow "asm" keyword, old CMSIS headers use it.
+ "-fasm",
+ # Warning config. Turn on most, but disable a few that are commonly triggered
+ # by the used code style.
+ "-Wall",
+ "-Wno-unused-function",
+ "-Wno-pointer-sign",
+ ]
+
+ # Assembler:
+ asflags = [
+ # Most of these are just duplicating cflags
+ "--specs=nano.specs",
+ "-mcpu=cortex-m3",
+ "-mthumb",
+ "-masm-syntax-unified",
+ ]
+
+ # Linker
+ linkflags = [
+ # Tell GCC to use newlib-nano
+ "--specs=nano.specs",
+ # We are using our own custom startup code.
+ "-nostartfiles",
+ # Target specifics, see cflags.
+ "-mcpu=cortex-m3",
+ "-mno-thumb-interwork",
+ ]
+
+ # Now collect all the things we want to build.
+
+ # To avoid manual lists of all the files, use some globbing to pick up everything of interest
+ # As long as you organize things that should turn on/off as a unit into folders this will
+ # work.
+ work_folders = [
+ "firmware_common/cmsis",
+ "firmware_common/bsp",
+ "firmware_common/drivers",
+ "firmware_common/application",
+ ]
+
+ # Files specific to the ascii and dot matrix boards.
+ ascii_folders = [
+ "firmware_ascii/bsp",
+ "firmware_ascii/drivers",
+ ]
+ dot_matrix_folders = [
+ "firmware_dotmatrix/bsp/",
+ "firmware_dotmatrix/drivers",
+ "firmware_dotmatrix/libraries/captouch",
+ "firmware_dotmatrix/libraries/captouch/include",
+ ]
+
+ # Add blade files directly to the source to avoid compiling the template files
+ source = [
+ "firmware_common/application/blade/blade_api.c",
+ "firmware_common/application/blade/blade_imu_lsm6dsl.c"
+ ]
+ includes = ["firmware_common/application/blade"]
+ defines = []
+ target = ""
+
+ if ctx.env.BOARD == "ASCII":
+ work_folders += ascii_folders
+ defines.append("EIE_ASCII")
+ target = "firmware-ascii"
+ elif ctx.env.BOARD == "DOT_MATRIX":
+ work_folders += dot_matrix_folders
+ defines += ["EIE_DOTMATRIX", "EIE_NO_CAPTOUCH"]
+ target = "firmware-dot-matrix"
+ else:
+ ctx.fatal("No board type specified.")
+
+ for folder in work_folders:
+ source += ctx.srcnode.ant_glob(f"{folder}/*.s") # assembly files
+ source += ctx.srcnode.ant_glob(f"{folder}/*.c") # C source
+ includes.append(folder) # Make sure the matching headers can be found.
+
+ # The program() function creates a task gen with all the features needed to compile+link based
+ # on what source files you specify (stepping through with a python debugger can be nice to
+ # undstand exactly how it does that :) )
+ #
+ # If you have a need to you can actually call progam() multiple times to build multiple
+ # executable files.
+ ctx.program(
+ target=target,
+ features="mapfile ihex",
+ source=source,
+ includes=includes,
+ cflags=cflags,
+ asflags=asflags,
+ linkflags=linkflags,
+ defines=defines,
+ linker_script="firmware_common/bsp/sam3u2.ld",
+ )
+
+ if ctx.options.flash:
+
+ def do_flash(ctx):
+ # Input we would type interactively.
+ input = "\n".join(
+ [
+ "erase",
+ f"loadfile build/{target}.hex",
+ "reset",
+ "go",
+ "quit",
+ ]
+ ).encode()
+
+ # Actually do the command.
+ ctx.exec_command(
+ [
+ ctx.env.JLINK[0],
+ "-exitonerror",
+ "1",
+ "-autoconnect",
+ "1",
+ "-device",
+ "ATSAM3U2C",
+ "-if",
+ "SWD",
+ "-speed",
+ "4000",
+ ],
+ input=input,
+ timeout=10,
+ )
+
+ # Use a post-build function here for simplicity. Could also be done as a task, but getting
+ # the command line right would be a pain.
+ ctx.add_post_fun(do_flash)
+
+
+# The rest of these functions are supporting items used during the configure/build commands.
+
+
+def get_jlink_srch_path():
+ """
+ Get search path to use for JLink programs/DLLs
+ """
+
+ paths = os.environ.get("PATH").split(os.pathsep)
+
+ if Utils.is_win32:
+ # For now just hard-code the default install paths. Don't include default search path due to
+ # conflicts with java's linker. User can still override with an explicit JLINK=... on the
+ # command line.
+ return [
+ "C:\\Program Files\\SEGGER\\JLink",
+ "C:\\Program Files (x86)\\SEGGER\\JLink",
+ ] + paths
+
+ elif Utils.unversioned_sys_platform() == "darwin":
+ return ["/Application/SEGGER/JLink"] + paths
+
+ elif Utils.unversioned_sys_platform() == "linux":
+ return ["/opt/SEGGER/JLink"] + paths
+
+ else:
+ return paths # Trust in the PATH, Luke.
+
+
+def check_gcc_ver(pth: pathlib.Path, ext=""):
+ """
+ Attempt to extract the version from a specific GCC.
+ If successfull returned as a tuple (maj, min, rel).
+ Otherwise returns None
+ """
+
+ name = "arm-none-eabi-gcc"
+ if ext:
+ name += f".{ext}"
+
+ exe_pth = pth / name
+ if not exe_pth.exists():
+ return None
+
+ try:
+ ver = subprocess.run(
+ [exe_pth, "-dumpversion"], stdout=subprocess.PIPE
+ ).stdout.decode()
+ except:
+ return None
+
+ return tuple(int(v) for v in ver.split("."))
+
+
+def get_gcc_srch_path_win32():
+ """
+ Look for typical GCC installations. Checked on 11.3 rel1 and 12.3 rel1.
+ If your gcc is older this may need to be modified (or just make sure it's on the path when you
+ run configure).
+ """
+
+ # Extend with anything we find in the registry or at the default install location.
+
+ # Import a few things JIT. Some of these will only work on windows.
+ from collections import defaultdict
+ import winreg
+
+ REGISTRY_PATHS = [(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\ARM")]
+ INSTALL_PATHS = ["C:\\Program Files (x86)\\Arm GNU Toolchain arm-none-eabi"]
+
+ gcc_vers = defaultdict(set) # Map from version numbers to discovered paths.
+
+ def check(pth):
+ pth = pathlib.Path(pth) / "bin"
+ ver = check_gcc_ver(pth, ext="exe")
+ if ver:
+ gcc_vers[ver].add(str(pth))
+
+ for root, subk in REGISTRY_PATHS:
+ try:
+ key = winreg.OpenKey(root, subk)
+ (num_subks, _, _) = winreg.QueryInfoKey(key)
+ for i in range(num_subks):
+ try:
+ subk = winreg.EnumKey(key, i)
+ subk = winreg.OpenKey(key, subk)
+ (pth, _) = winreg.QueryValueEx(subk, "InstallFolder")
+ check(pth)
+ subk.Close()
+ except:
+ continue
+ key.Close()
+ except:
+ continue
+
+ for install_pth in INSTALL_PATHS:
+ install_pth = pathlib.Path(install_pth)
+ for pth in install_pth.iterdir():
+ check(pth)
+
+ if not gcc_vers:
+ # No installs found.
+ return None
+
+ vers = sorted(gcc_vers.keys())
+ vers.reverse()
+
+ # If different paths to the same version where found, using sorting to at least be
+ # consistent between runs.
+ pths = os.environ.get("PATH").split(os.pathsep)
+ for v in vers:
+ pths += sorted(gcc_vers[v])
+ return pths
+
+
+def get_gcc_srch_path_darwin():
+ from collections import defaultdict
+
+ gcc_vers = defaultdict(set) # Map from version numbers to discovered paths.
+
+ # Known default install paths on Mac
+ INSTALL_PATHS = ["/Applications/ArmGNUToolchain/"]
+
+ for install_pth in INSTALL_PATHS:
+ install_pth = pathlib.Path(install_pth)
+ for pth in install_pth.iterdir():
+ # Not sure why but the mac paths have an extra path segment here
+ pth = pth / "arm-none-eabi" / "bin"
+ ver = check_gcc_ver(pth)
+ if ver:
+ gcc_vers[ver].add(str(pth))
+
+ if not gcc_vers:
+ # No installs found.
+ return None
+
+ vers = sorted(gcc_vers.keys())
+ vers.reverse()
+
+ # If different paths to the same version where found, using sorting to at least be
+ # consistent between runs.
+ pths = os.environ.get("PATH").split(os.pathsep)
+ for v in vers:
+ pths += sorted(gcc_vers[v])
+ return pths
+
+
+def get_gcc_srch_path():
+ if Utils.is_win32:
+ return get_gcc_srch_path_win32()
+ elif Utils.unversioned_sys_platform() == "darwin":
+ return get_gcc_srch_path_darwin()
+ else:
+ return None # Tools should just be in the right spot.
+
+
+# This is an example of how to hook into waf's task-generation process.
+# by using @feature() here the function will be called on any task-generators
+# that specified matching values in their "feature" variable. The function can
+# do anything it wants, but typically it will either define a task to run during
+# the build process, or it will modify the values of variables for other hooks
+# to use (eg. you could add things to source to compile additional files.)
+@feature("mapfile") # Run on anything with the "mapfile" feature.
+@after(
+ "apply_link"
+) # Run after "apply_link". Needed because that's what creates the link_task
+# that we modify
+def apply_mapfile(tg):
+ """
+ Instruct the GCC linker to produce a .map file detailing the result of the link process.
+ """
+ # Get the file name to use for the mapfile.
+ outfile = tg.link_task.outputs[0].change_ext(".map")
+ # Extend the link task's flags with one telling gcc to generate the map file.
+ tg.env.append_value("LINKFLAGS", [f"-Wl,-Map={outfile}"])
+ tg.link_task.set_outputs([outfile])
+
+
+@feature("c", "cxx", "d", "fc", "asm")
+@after("apply_link")
+def apply_custom_linker_script(tg):
+ """
+ process the "linker_script" attribute to add a custom linker script.
+ Handles the command line, but also sets up waf to recognize it as a dependency.
+ """
+ script = getattr(tg, "linker_script", None)
+ if not script:
+ return
+ if type(script) != Node:
+ script = tg.bld.srcnode.find_resource(script)
+
+ tg.link_task.dep_nodes.append(script)
+ tg.env.append_value("LINKFLAGS", [f"-T{script}"])
+
+
+class ihex(Task):
+ """
+ Waf task for converting executables to .hex files.
+ Used by the ihex feature.
+ """
+
+ color = "BLUE"
+ ext_out = [".hex"]
+ run_str = "${OBJCOPY} -O ihex ${SRC} ${TGT}"
+
+ def keyword(self):
+ return "Creating"
+
+ def __str__(self):
+ def nice_path(node):
+ return node.path_from(node.ctx.launch_node())
+
+ return f"{nice_path(self.outputs[0])}"
+
+
+@feature("ihex")
+@after("apply_link")
+def apply_ihex(tg):
+ inf = tg.link_task.outputs[0]
+ outf = inf.change_ext(".hex")
+ tg.create_task("ihex", inf, outf)