From 8305d5cec0b1cf64daf65f0b474f66da69321bf7 Mon Sep 17 00:00:00 2001 From: captain-amygdala Date: Sun, 25 Apr 2021 12:56:40 +0200 Subject: [PATCH 1/7] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8cc3b4d..0ca026e 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,10 @@ Since much of the initial work and testing for the PiStorm was done on Amiga com You can now reach the PiStorm over SSH, check your router web/settings page to find the IP of the PiStorm, or run `ifconfig` locally on the PiStorm from the console. Now the final steps to get things up and running, all of this is done from a command prompt (terminal) either locally on the PiStorm or over ssh: -* `sudo apt-get install git` +* `sudo apt-get update` +* `sudo apt-get install git libsdl2-dev` * `git clone https://github.com/captain-amygdala/pistorm.git` * `cd pistorm` -* `sudo apt-get install libsdl2-dev` * `make` Next up, follow the steps for installing the FPGA bitstream update below. (Scroll down.) From c7665e5670357f09dcecbdaeb3ab6950dfb80d56 Mon Sep 17 00:00:00 2001 From: beeanyew Date: Wed, 12 May 2021 07:22:11 +0200 Subject: [PATCH 2/7] Update README.md and pistorm_banner.jpg --- README.md | 9 ++++++--- media/pistorm_banner.jpg | Bin 0 -> 48435 bytes 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 media/pistorm_banner.jpg diff --git a/README.md b/README.md index 0ca026e..5c6765c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,21 @@ # PiStorm -![logo](https://pbs.twimg.com/media/EoFm2H-WEAIxuTE?format=jpg) +![logo](media/pistorm_banner.jpg) # Join us on Discord or on Freenode IRC #PiStorm * There's a Discord server dedicated to PiStorm discussion and development, which you can join through this handy invite link: https://discord.com/invite/j6rPtzxaNW * There's also an IRC channel on the Freenode IRC network, `#PiStorm`, which is bridged with the `#general` channel on Discord. +* Selling blank or complete PCBs or derivatives on eBay or elsewhere for excessive profit is frowned upon and may lead to forthcoming related projects being closed source. +* Even with the current global chip shortage (May 2021), components are not **that** expensive that you should pay up to a hundred dollars or Euros for a board. +* The PiStorm is not a project for making money, it is meant to be an affordable way to replace and extend the functionality of EOL Motorola 68000 processors. +* This is not meant to discourage you from making PiStorm boards for others to enjoy, but for instance selling the product as a commercial item and then pawning off support to the community if something doesn't work is absolutely not good™. + # Project information * The PiStorm itself is an adapter board intended to be paired with a Raspberry Pi Model 3A+. It goes in the DIP socket on and acts in place of the CPU, but functionality can be extended beyond simple CPU emulation. * Hardware files are available in `PiStorm_RevB_EPM240_74LVC16373.zip`, but they may be out of date. Joining the Discord and checking for the latest revision/BoM for the PiStorm adapter board is recommended. -* Selling blank PCBs or derivatives on eBay or similar for excessive profit is frowned upon and may lead to forthcoming related projects being closed source. -* This is not meant to discourage you from making PiStorm boards for others to enjoy, but for instance selling the product as a commercial item and then pawning off support to the community if something doesn't work is absolutely not good™. * While the PiStorm should work with any DIP socket 16-bit 68000-powered system, the FC lines are currently not properly handled and no guarantees can be made for it working on anything except an Amiga 500, 500+ and 2000. * General Performance with the current use of Musashi as the 68k CPU emulator is somewhere around a 70-80 MHz 68030. diff --git a/media/pistorm_banner.jpg b/media/pistorm_banner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01d3349a6d90c441fc54f37a4e2012a3ad519767 GIT binary patch literal 48435 zcmeFZbzGH8_b9&UE&=I~MjE6`L`o#28)36)*ubV!K`|(4r6dLEu1zQ{-Q6i5Al>kL zzΠ@A=lfzx&Ut+G( zK@jHI6A*|Q|JPf}3~CCYRkegVLt&Os2U=bpP99noZ7X{-s2hwG#LLagBf`xu!oy3; zEhxexAi^sIPyvCEk`aEieR&B2B_sZ70~wTz^ec@(e~k$Op&}stF#*@PeoaEXF&9RP-}0ul%T z5g7#)4IKj$3s8W+0uexnNWXyiAOvItBt&FH6f{(H6eMgu07!s@eCq}eiqs<$LORE% zyr@LsDMk0_8Hm+BoATXp^6!&IV~kM$KDP~q@!w1>4q&<;sbMD5kmf8v(yuuW*(rI} zIN-9dE6W^}{=780X>f5bqpW#oX{Y^3Wp2|$vdo%9I9l_BG8gPvS*%>2U5j|WmF zg(4-g-)EG%&9}5ShN*pDa}o&Pt~y__rUwj>Uo!-*NP{G zQ{uU6(G#++@-5X9Y(yt_iw@&c4kh4v*^;e53(;oi3f}lzELX8p3iCK^+^~r zj%IYoV0x~VBcap?ArlJby4$*j#%H?oCO$F2xE0!}J>6~goD!loHg}l}T}EoF1jh_X z_e=KTS;|h&??insT1d4tN({eXDlAfzH69kpf;E-uO6&9Nm2Y+0Z)9EZn@IbXMvv#q zcVfOvke8bJa^rnje-|VbYQ!xO?W3Yq!v_Ii-y%)Tkh)0=4Qmt8wW2{UKm9|`-VW=#|-Y>2f69osFoE?+j3D#cI_b-o}2v!Up*6#)NRYM;Dw2Sg6 z(xfSAh{68&Pom109}gWeiv{AZ?vh~E=t*SlVHR$;uE*S|ZY{V!_z2-nRluX{}# z2L-Gd+K^C>K^~Scxp|Ip7VlQO*_RDfXS-gktR46@6x=%*30)~(e>!=fH9wpr@Kl7; zm<kG0_%@!Iq4#iz4zDg#*RYd%3zp+^Gi}zHCf|ofyvqG; ztf@J8*v{_7V~)JjB14N+pQMeRJVuGU3%0rf7vHCS#YLXwl4JQ545KYu;H9L*hf~!r z#%I!7xx{kT!bW@pMtD5)+_53=ZIOrz>RuLYa>6Vp);G^N?sd(4x9nPbzhE^Qz+b+U zV4=Zv(=K0}PVl5&&b8~MGW^WS<>uUS_&YBvNvozp{&d8(!}5(hDBM-NK5bvpw@2lS z?tu@@?dgoc=dLcsAC=mx{Lyk;aZW8_Mj%_b6X(yo@p60!vleEIAD!fd3^0%O>ISa} z=Tom}yCT3=VSf1?l6?gX?I*kYyLfb+2Ki||!bFwD?UTcZBe;4#ugfk$#=ez{gKM^H zBY{HF<@k*>BN@3xjJFzF(n!`rgrY=;QbW_*vkO0Sg1NB4=XEnM@>=FI*v2W10w)NV zICmxAifMcui-t{% z&4t|&8Y(PjC4!7byx3QE0p&W~WA%0z257Q!O3GeeGGru-h9aMBM zmOlC7K>E(LjXL@!+~|%?G)-QqGqZCr!M=Z=%EJQA%tG;KUYx#D9A_I}K4&hfR~eFKSZJWd>31-F6P3xactSHYlU=XIGbJ~S`&_=P3!Esc z$XPx`IimS^?_1GK#^}n>s(4a{wXv4Sg`~kr#|TGjcDqeu4jz6`oX*bL%peUoQSlO_ zpi(`Rlvtl`WVH`@Z+OC`>XS%8-YV*7F3VO<{*8lZ?B?LQ{_#7V30_OL^N$v*fZUwl z)$96}?YquERJ#I(~6Otf%?G$w+|=vpC>LN;8tHRQiSWR zPC7r$Rn^+CHkV}Kj^SPmkI?z(u6ooGt|b{ss^feZuIF6A|2|8)0G=>EIQ8i~r`uU8 zs&7G4Sv!~rQnnM9yCcbT3A&GHkK<@}plc|a<(BDEUv(nNap1!b6@I_Km22v$75pt% z^p20+UI!KO@N(5CoFdZb;KHqlQT)Bk(+lR@Cuql_e0P!k#-A^E&D8rY)F#V*ag@#I0M_eZ?GwAx3(%fr>8?{haaA+C$f$ zj&a30^sbO0+Z}v9^wNvh-QAi`gdd37p7w#iuJMitvZ?d zc|HyED~bkK8?cuzLyaXBp$EOE9&X>&yqo>tg|^=>v<9P!%3C%qi#|VZ?xmc?c%Lq} z#Tsj%w`~`S=Phk?s4%R&;q!jKNzywcvVIr*{@aIv;s?4HX^FU#hO_f3=W6%m5$``m zGul}=Q*%8Jc(3fMmXdp%o_RTTxj}gJ$7Y?6lN%&-PeBQp@p|8ge;xlRx`v5d7c2qs z75r-B3<6;}I9b^{tGGBjxHtpZE9(NJ3UgLBg+gtwF%;~bArN~PyDPv|`syuh>vWaJ zyRNHl<$i^6&&v6#&K39vO^B1Si5)~kMn?lE`q9{r3aU;}sJS}C*~LM{)EW!`u|cXJ zClD0)GY8Rv)IkuCGsp$xa77A)>F^sH$X%1UXX|YLlOt?X7b{z5EBkAb0372QTUtq1 z@rN`-uSg(r0MQ>kzVW9Xt2j7YLG57xoa72q+QHfWS0{i@nmYZ?s9C_2erKee?4|$6 z*gOA`d1z`2`wdaHaCZHjk+HMA|2qT7@ek7Xz%~{?1@S{lAT_yr(f~I|S1hTS(bAeh zT}IAduLgCHQTGP{T=Svn$iAUxf;yY`MO-y-S)29 zZ*)vo2-q3wbl=3;|c;87XDO@ z^Q&CV%EI!`0IXjCfVbcHS91kv;|C8vOiMuTewdmF*Yk+!8ixC`QQ#%{1oT7SaIVX) z%xt}DOtRm3>T9aI*LjTV7>E$AYXK(sRlxi?Nr2*O-2LlPc@USmIRLQ*V!&ty0>aOd zly`BzOL(u#^?>*n4*zw@mFE8}xu$sp+){{($_2S--0gxcVO4DK)<35A_g8n zgAnijc&^gqR6pc^Obx(5*9QL&X_8-MkraUFM<1@TAO!lKD3~BkkUg+cSOJeMux6M6 zR`m}#T;u&E`Z=+#%C3DN0FA$fKOy`E{IO(!>|JcHR<*}a5TPrXGre*u^YEmKmr5%)O7*Kozc+jph z3itoi7Mg_<)WzX1MW|3GD+{aN>!pnP6?K*CGJpn-iHkE-4q^{+GI55O0R4hePue;jcC z_d4Ky?3!-@J7Ew=8+d@7GvE>fNdbl^6l4k*q_lur%MwUC0}t#v1sL8SqW=Pe7BFJD zub-=}_VwQThxLmFn3upAFaij;Byecy?Cc=I#bpoUG`Tvq=LAFTxZF(~xOh0ZxjnmWX5w_({7T$P4$=@yD|t^Rh`Oh;2H4XEENn(6DM2gd zF5+(IU?;jwTFqgi_={b7Xi{&#awi>*C@_5;&j&s>$Eybsgt;{_CxdKUIJL{ym5|-PJV@4sL!99$t-K*F4y`c}2Lnf1oM>dSC`P z0{?r+P%|rYkN*ac|qF@hmHn9go6z+@D0iENt zvN997!!KxNYRUuQ5WFKG#369!jwy$bAlQ_{RLEQa!fgr>HZl3ZE>QnI6zp;}gum*W z{SWK^aFv+Y{;$*dJwzhcroIx?3=lKll>!6(0XUSmf&ruD@pDS3LmYpmY^`Xobw|Vm zeC4DTrvqP&E5wZMXR+1)vSfacbpu?h|LJ)DK!ZWeo!v~FAW{~96#q+o;sTiGx|)bT z`oZ=cxIkq)z73uWLntrJh7EWQfwIEfB6>(tl$23c^Hr_;P zTAJ=Bqt7+xT~vc@iIk~~3HD?VYeed8$eO$r8ne0Pk*SqRwclg(g@ec*E#lNQbep;d2%!^NkEzUr+PWGs>Z!W@lv0k4(&jvP zPim|0fPjq)aHCGJs`F|3G3<+W+uS1Gx|Vp-7q-}f5oph_u|jECNm+S?bId4G2s`h= z(;ySZw=WVeqK~TcS4GoXsyz1LM!}wEzQFy-rFwr>a-L2b))}QwFqDQ7_(+o97yH@T zCTzn5?9~T5R;mI6%`0qV)4&a53%qQXT!IO*sn=pL8AT>S=JnxlMY;mDNtg8Z9cv}I zwGss?ep7RYrv(eEI~;PkyJF*3K|ywT87@k>R5z>rLpG>}qn`HJO9W61nc1wa4DlXc zf);mRYLhih;DUQ8O}GxM<#6xY{j#ZFV+Z1L_{U{NXLF=OTf$r{URWE`jt*nuA$k`y zemx^Bdc7_P_fA&)`rUQo`Gj;j_-R;UpQx7j$jSZvo=cD%S`&`uyXE7W9pm~khL~Ae z&?f=Vz~V)BaeR_kM`pf<3Ny7Ax{kfU{4zHQ>C_0?n{(^Ay**eS|FXrMrocT?C5MXG z25pXwulsWaUh5sD`C4#C%SglcnA_>YuV3GFLT8?$6G^F} zAScHpM~E;ax1?e&ENPO&4U(w}lCn!Q4BUQZMou(0B$e=41M+F|A^Ws!Z-PiTVNR7* z^kE2&I!bHP;wzML0~Z#5lx2kEY1z`WZg<#$f73Ao9N zg<3U(#WD}Sh~)c44jL%|iIa$q5Fe!J6Iz{|FeV<>pL1^19=ipxzT$hO6omX*Rg4+Rcs4h)R{f=Cjm~$<@%TFe3Ja{EV7)bpV@}CFGmV= zeisq!QSESjfm2GYJ;px0wsR(Pa{M0p+}gVrYo+c6!woepWs!`0agsakC%A_l)EkF} zp7q9*t&{@=5ZlBwBk9$9o9bVb>WG)&o*zhezKjQ(CMK^}bR$KvYppa=R+*&VSkgdF z&dxvq4Xf{Gz5bkv`Sfl!+EWd@+vq8e)TLE0Q4#$kSm#DxC;JTAE@2TroH>$P+V0^Jm7}pe?!9q z=ke8^{0>xtJCbpjH@gS* zX^@A?xVyYP3K(TTY9U?_mp0W4kJlCGY@}CVnlEed?DWZrTUb!0eh_c_phktsK&uS; z%9!xWyV&u5yUADc9;}@lvVx{#O6lprQvy2>pJxIG*w5;@6N~C*=NLD#P+7=@sj3wU zk9Eivg$?A`DpX=2VAfK6{}FRR$D7^Dl=n!J6sbRLmr#ZvD=wS5CDjVG_W0p3oxgvP z;%=N#Piuy6phV0k))30^VOZ7;X&$ODQ)UDmJvcV$mIbU$u zZ}x^ss5xrv&gF9z82Rpqs}pL!f7yc!`(^+i`QRN;qn5mIG6 z$l4wTwZ88P5(R75{62R{23O}#RX*Q#ovIvfwV$cs*y?+=_jaV@V(59CW0=;o?187v z+tyP4&R2QnjWxE!I+viE;PmQz@=MSogW3-Y%PztK5%SB#5^Kh`p^<%T@tu6HHg99F zThQCox73^*?6037(kSCX&h9gi+oq@&e(AvA9lavH8zgppT>WH`F2HOjev zrXH12d>qDAll(3K5AV6AGR~>06tqa$$T?k&++(e{ z9|u87frW)t6ZxBNifX~5*cjZX{qt|{9nJglSc$Nl5LBh4SkP&c{eka6|4u3f%dI~a z`9D%9GU-sM2fscR80efWEjJ?!?`aU#2?|D9h+tX!U&8=^9M+`A3*pJk`x3Y9`M25n zWDwEs0zv8)GHqfOgU~bL*Hmo`v{A^!$Tyw{R|)r0aR}NeW9cMq-Kdq7sVyyrV^J7m zI@^NV7i?ILk<3M(tLJ_c=)bonrdj7OSvF{7duu{=sob-p)Q;wPL!M~E2-(`{w@zqg zgd6ckvND&L74zmg9vd5~qL{I;55s$g3lz}{)DOnYJ+jN@lO9g!(=8_gla8-={njdo zpe>0xQec7&T!LZ$;jzHM6L}ps@ly&SUuH?0+6AKs9_I-`7TyVg{o+U$zUh&6w>Q0% zhwf8hn8Untd5(J$jHc?;m!@CnG@)HARz+_n$a2QRjedqAlPWE4MiQzgw+~lgJBv9r z_b%(nmw*g*?wr;i3mZ(ldUtkE5L9N%?kCg26ex5w3Afl!KQ=wxznD2Q$f&c6S7G1L zpCp|^R!)*5iMc^m7w-y(%H$O2hI>1bXnNjybsTm63Z>F9E_{E=n%ysq#yd1p@4_Y= zUKO*fHm~3)s@z|acet8+Qm|9nfmtbGjT(|n)e+X|7I~~!S5l76`LwZ=-pu7|z?{zT zR7vcucg356kq%Tr?#wP?SY4TELe?2?B8m))vpXYJf)%1?AJ@SZaVTLV0T0HcOW18?{vm3P-VlPekatZthn0lRP1T7Pd%ZniT8oNe!En z>{Yn%#~%<1i3wh~#Te>VM-;yH06QuNJ5~qyJ-57lGn~RBN;UaSD-B}SV;6k&vIjXa z2PKn|CC@7p1fT9}aZusvXX;WhRSP9d^@R+ruu+lcDcRUEJNG>pV5Jofuw$uUS(!W` z7n_ry>QG`3;VHpKrVZ^?Pn42!WH#-PvG&JAzkNH_D`D+XxRr^U>nxo~WBYEQmyNjW z&IC(ov59Somes@)?YM*>fe`TnMHuwe2I&H2@`iTy2nZo1S**k9sfN^D7Ian?R!6DJ z0boLAU(cVbIrK-6(lL=hM${3&$?TR=dhiE=6bqYK2E6p2N7^gQ%g}MDy&Z)%PeD%AB_qb%#f8$o7t4KU@~osv#{aF0ZJFx0OR` zJ>jd&leIJUi3%2Hnic)DcrYTrVgt6bTjidmpQ9N1eng@`R;@|(Zi&c{!KvD=7_Mqy zLT?t3W-P=u-x|r)i=@0%6}4lot0UY^i?g;Z7H^PqJENEAV~Xzlv4D1!FS_aTG~0d= zD-^-GBLTcRnqq~}qCCgwD6?2??e7y4vXJOaoKT5-%HQQ^lUIrBGqJpro(~*j3oAV% z(?EKBr2j?OVBw3gw~SJO-!T!EDb)B~eLWu=4-RyzNT+lmXf%d-LN)jR4kdSeM zg-V3>iuKm$h4=Lnb4eElI4yE6;vKsW&l|94ABI`E7;KuO?ndu3mn^j61^8&Yb@&Yn zZRjR_iECfQq3xJGA_d#;N~wMlOBE})<+krxV^ABv9$4ebjJg9gEPZP_Iod@4UIIT; zzf*lQMLc@nj|;*vD8| zsp}H7X0Tu3?Rm1I|IYB!_oH;$Er)UIn*G)AvhqOz?T6gcWqJ9BqBaj!3>kFl2ZG&CR*g@FASJ^C7iGzpC&8AFmzvz{wA7k)!-EDkMVa|KH>jR>-Wv3jSQ8Wx&vmeB%K?@ zV;~o{G3WvD+~PowiP#O3@aO4X+4~~pvQum0v~P%CC%2(Czo&n#J6?CUEzV$t9Mo59 zk>^;~vDcAAewrVo{PkGNJ5)e@YN_fWsSRLEo<(4d&?wz zGVP6fd!p9-1bsz0)XsNSescVqa*+1;^E^~GCe-poPqidY7ctogg%9sq6pV~^Yn#q- z&9=#6guA-($WIhV-nyNBbP_%3rNW7Ac_6j547%Mw~=^ z;vX@mbSm6yT;8#1UtVYeW$SK^Pq`fYn>{ZE3z5_#9EytM^eFt_J6#~*FO`a-?*9!o z0B&LW`1w&t7!6v|qdveYcp1!=*Menp&P+y|nK!oCH1MsT0to?vp8IH)H4u0QFBP%om&QxU$| zjwJopYGgFxuDScsTMq(n&Q{pZ2yJM9t9EK)g*GUIU@Z9pcG;7!hBX{F^@8;}0(mN5 z=Z6RB_TH63wikU}!s%L3<(<(*@NiN|G+W@*CcPtZzzS7IpEhE0XaB(}ee{5YcmC6o zQfI?q%I>S>!l1O&i+ZHc4mHJP8wPh)Zr4*Z%amEbKTv<=JTbQF{kh5urrhw(BeG~C zd%BkOp|~gef!hn+cShQ0c5s0WMUpSYoxBt&?o{l`q4>zQUQfr#*-9Fe85%|Ead%&c zII%f$I*M|aB^OVn+tIotdGth(1ReOif4T4bKBu04Mz`gl#c2C`1SRylw!;Amd5z27 zIc%qmK@&1^Zg7y&orrXPV-mIJS?#WvGuTc<<@DyrA=}8w#e1&UuJfMp?TcawtAyz( zbKa^3?I59(TRjZ$hJ_XRt+761?U7gSE(%__lAse?c`3dbuERmJsI5uIR@QqMGH(2GTi^HOIDWC>0H`*q^LeFqZA^#cGJ$P zt9z9`YNA|_>_xcJM>fUaj#MkW&JP?PPlE*DV`8uA7-}8Dil3&U%e|S3K3S-V)-=g= ztLV7kPjM_f`dUDkJ%K?%Jny2fhq{B9RfV%%7NtP+JdCo{v`c7m!n#90Mqq|FSh&7U z-E>9!HPlIBDA2o3id_ySJCj`EJQ8&ODBsKI%La$XByK})|8_-(bJ-{#Tgj8}k7CLdunyK4MV&b0VxN3{}(AL?Bj$70BaZ->Qs*~nr@u5SHvCbhRz{<`w z4B@tv;jjn9g0!O0(vbp{pk!i6nN8Zw!^PM8Bq3HoQ}F2g^%8 zC_p|=rH25{ry}fKE--L!0Y7ZC)ugda)yA*p}$!%u%1-lE)qrj zjo6el7(0@Y0i9-aOF!h*Y$_ zj(zBWH^-5UNr1Sr8Pa%j2-w~iRrsft9%w62=Gks=wB2zS^)mE=fCI~R zW*}p3HkLYa59lB5=j(1S82JQ$WoIDO)qafIM5Z2C$I&6kc4tZlQfVJ2$28Pl?YZs} zvlwACJt?~u$riUFJj9f;kTLgl$Z`4%?9nw{d4etAD21(66wKX(`gzt^P;X=X+sa6{ z#rKXy9k(1l;i;PlWh>B^(A!HP<8x(YU->-6+#iNol5kNJmPWLARVE&=t@&ma>>L@_ z*WaGwT6P~Z%Ky|?=^op+u)@FTPtq{vSk^CkQ$XG3?xez!%(}wcNrflHx1Q$_p{?dt zLprC5c0}TpJe%@WWNqZ$c9M_C5TL-NXWG4u_MHX>-mc`^sA<1fQPw*)EY0U1d%>1f zWJpieo!V^AQ8hTOVZ_>UkQf*>=^=H1zu;x^aVw>CgTc@GEA{9i?&y3g?o;ZURT(e7 zsWpY$aQA$u@fAw76?&l;K!x|*qWMFvtdaG+Vwl9x2hZv@SA_D{N12hgMR`$~LBl&F zw$y7gWIK=8hx_bZ=`yv075LEJNb7-gs_h{r1GN)fTJ~|_QXlzGZnMa4z~7kZEDIi} z^AB&a6Q@8dXIzxo>f1g9@RiyP7Pd|Zrpi-hJMc4EF&Uas+4n;HWXi_TN|R^vH}mZw zyejlb3oG^-x(!)L8Yrq68X5#;2q?^+=u%Gon>Gr;Z~6*E51zlrUEUw7;cU{#BHu>i83fd z(M>Y#kbRqMX=T6gKz;4w+dFoZ5wo%F^Ygg7rJPB0mST!dc$dR}Gqo^2PWt2jO)v=C z4B38$e^F9n$)Z8@o-yroUp5ov%EuCFEGvjVYbJr|61F;vTra zbZ|;tAWOycD7GB5`n_)}PfW3S^T1_K(s*FuJf0hOpj{jD5H`mmTOrhmlFs;zG#|Z@ zLPb*YmD}FQSx)PzanT%&XcrFF^a?m}Ip6JQWPGn%QoPos%aAuc;LKt=+hijgBV%e|Grt6py9ZfJp7fk&GLL26;?RlYeI9-D z8xDO(Wct>4=Z}9P@){Z=SrA0m)H}V(4FBI{D^F2=G zTP&9hO$%CXrm<(mm)Y~#h)nZZk^mN+l^wCXAs?lSe!P(7y^XiKYt`)4x1Uh*2*yXb zSB+Rv@@Fc7A5-5J2x;0mN+7YK_Oa^Kfpimb*hx|7cZ*T)yM#$3$|}X;jzu|yq;J3~ z@MxY|xV$o?s(niocgtAF>5=1b;;smsNn^N;`tx__s^I5Y-JZgck5#Yxie*~|(q-^M zJT|90!FlDzmK1X8mdM(zMIPdDUOv%GfM;1O?hZ8^ew?y_SMj6v7XXc+HG zZEPjuG}cs!m1db1rvFLIdrf4iecH~^U~eCiS~H>M#wC#yTpIh-abSQvCqOAEFfk2d z!*QZbi`_ZM{qCf7kzO<+?`GC`LYY^KOu6x$9RZR^HW&c}5h4@1Kl_KvUA>kN#ngD6!_HXe};V6B`Nn9o3ft$>e-t|~R@PoNXJF52R+3iusTmhawWVR1s2ijDHKl>3(NNy4`U7j4mK z8yI?(*v-R*ZpOr88;twh_k4NZ_PJ1F~{~PpC zZn$yI=Ll4Ae=(l5YwkH7{)`$Vy!o-kyXftFdrIe9!FaZ}338(kOg&C-CLag7ys_}0 zS}p2!It{MgPW>>w#@uj1tvV7IF-U$wgh@oBGuP_6;Z;z&;DW0uVQgW-&@YXbsUQZ8 zEKV~xKu>w=>b@;E3{@7~<4#^Z|DSRC|Cc1BeoE_t2aqBSZa41;#G`CkZ*{KPC8}S) zdU>*{x6RbU%G(~Mv%=k<=ZdEo#E(G=tqMw1II#0U?x-1H;O?e=Gp*Fw$7^!6!_paH%t zc9I|3FnME~>wXw#PT3b;_HNm7S^XNm@J)oYsp;yr-8DERoblZgl3DQaU50>t%&uJ7 z9ms78LWJP#e|ocy|qJONK~tHwuSB zDa)`Z27C+jA=oDVQAT#!z%>9)r>xbcHd?>YRY28U=DUHnAW1R-0 zogO?^Pz6dyI`L zM)Wt7H%`_b6`!&nO@w{oBrlNF>E47FOk46{e}Jz}7}%fbI_CFM4ITLp%MW-&3bpl; zA1b-MisEOiZ$1yHtfoFqFBu-~-pnf?wLa@$Dd3JeIwlOzB%NyQeczsLv?Dc0_$dd zJ=f**s5pvn3ZcTs?{z+*@&#W=#)yl=EtT-4F&otQ^2#D!vJ%n{b$dafz29y`LZ8eY z=2=%LB$O>w9TKvhXGUD1>gBKRk}ZJs!= zaL{g6fuy=m63&-T+5R*XM;-*fS=X62K~;O9 z)p}>RAZ`)Q2}MqH&F`uoTvz>ggjRKUWA$ej-;EMA?Lveu1*H;~SDOuKuL46H z2(-kA=9gKC(44y;95X>1H;lHKblh1Ag3U&E#U6yGR=ay8I;!ba9af1kY&4t(y*{-q z_r$9Ekf3t565;JL@y&pia?)~*%Gv4q{)F-m!O0lm9XmL+jzliwZdK>T&PXn7}v3K@s1@z#omyJFpI}`V8ykD zFM#o_Re=rPIKkC-x9@wtShPC5p~a9}hzrT-S*tw#s4r1#*ma`o!UzovR6>)krXdTN6z98`cnI5(f!f|8!zGIm^6Nolq?}Ih z3QRJNX?c4Q+YNe{!57y3BfSw5sdh6m#tWY$9kVfSpNvhgm}{?KBxODh@-BZ_)52mI z+NycvfGfGh!=-m90ai9K6Rl9P46Gnf&eT@YTJ4NMfc@3SiuLg*!CCXe3bPY_&&r}$D^RsTaOeb zvpK3Xa+F1f7uar4tvmK8q2{*bxuCwU|B_#~;DI&Y{2-<}+NSk+0gn60(6Erz!i%L? zVV}JN!G}DP<84Rg7I6onSm#4CJgu7WcJ>dINupk^?--*$2Zz+;v-Q2*S*x4);H(t- z$o`9c+(huF*HulL;YXyxzVN*LoP2Oc^~@WLv69I6Gpw8*8#?q?4x>uIQZv}2AEbAO zC)37l$o&vFLpRpf;fPbxuMhVqt0c42uaB4$rG>KFQyr5 z`-LeqB4Ep~qy9MTT=2pQ?ZX@3I1I4F(K$M>om##wg3Uta!@z+|l`wqkfF3dE=2Z0L z=;WF>u{8%DIzr4k^Gh|d@u|(H{2DcYwNJn>w^^>cb>F8ss!_vu?mkCa)TAZLJ>Ei&{zw- z1D=t#u=7mI%?R8*yzjtK`gNd55_3AYU#ssYq@C-9K!8=@qFbgz)u>0hsK#BLUf=51 zx&R#VU!T<@BL0W#0x@9jNi9>KR^7L6cW!Z@P`FiDSql4DTU=CphbE7^`n|y-Wh=}F z;aE=H*haLnNN=%AV9YDD*M0@6)Of_AK(jHnoP2QmXEVSH@8)5{NPP@{ZFy|jn|Ka! zn(Zh3mg^mXFW{|X&0{6&iEOG4i8IboBAG$D#36$|fCD46uEt~>i$l-M(oNKuB_#A@ zktQW772}UHP=LinqtlsbajvuOm90FfjLoM7e)Kl)_PPe&+VW#RmQwE{d4ss@4wpZb z^;$VllG?a`B`Ewyh*`M zFT@p?#>-Rs_WflB9JcIc&dNFR#G^J9PP<;rhP8Tjc9ab)%ik7_lxj!w1_|a;Ac|JC z?)%1a1aS@M<5k)@Y^g!GA7$|IRZj@YbXKxHRoQ@%2j@j!Z-vDMO^}N=s?FaWca7fI zuY;ClR7T`4BX~JdQ}Gy=xrW+fY3T_}AJ3%%$95sqlH0^_>#@>}w|(WRmPzb^3CJO? z<3=El_S|EiI(O(2Brkf~at5&{NZUHu?2rL{tu3cqY4IF7!EWC+&6w8}o&Jb7*ba9` zx!;@7{Sa={W1J017{`3%RG>0G%Z77n6DB8986x|6PE<3TLsJ9!=HnN|8@CU|YMamL z^|ar(6PLZMNxO&MG~S;IU+uV0s2b35zQap8A(7bg_7e@gMRAq;^nFNi1D??8L;o$O ztqbraNa+$3C$*Y>!yo_prV09aQUe~A+lzjDt56nm{P98=$h%T=fxbJB@(3fxp9sUv zAIQZG(%g|+_x)Neg2h4akqvn)_^x!bqTl^1gi6YVA8c_nM`mg=BZz;_3nzW;|aMFQM{D`Gau zQ{6$^=`<0)8^^2NvhK!Hd7sl#s3^Ri952ap({d~RU093MzN)y}9k;H|)&<&=ENXb1 z=<+gn`;CtVo?#c&E{x}>O(GjDe>wEH>g|~sjV7wE_KalUAz?Y&Sp{EF$a0`JerL;( z0U2$?dwq(@fQ@P!bu+zK<^Z9#0{Z%ne6-J#_gyu}h4Zae`M>SF-F}rNkcEyewmV~( zb}?mEute5Ku`%AWkMDg6dS1Iy8WYeb?3)mvWYEJ==^X3Ek;HT`aw9=a;yJt~@Dh|` zgYPn3L+-X*yRtywlZ{q@ns{8`anxjN{dE0vrmxMkFAvFh@(CK6`z0vGkx!t$BX{Rj z@rsUq&kjUM-7GRTi+X399jSQSJz2yu63i>A>g+t?W;({F zXOtMbI_sPxDr;LOSS02qtCX|^u2oflYKLS zd^EuUYsvqUQN-Av=(_|7!hTfT__`Hebv^uY`O9HHM;B=XCg(lX>C20k9WYHbLI4C#_H^;$#GGO_g5yUOVT&pTEDv+&%HLbEd*2DHqjd18h z=PV|k?&lfsg9G-By^TY=XRehD&nk#TbgX^SNyJ^9{kkT9Dw~Mp^0LX5vQc#5O;LyEi&7wqiacE91>EdFUpcwe);@v^5?FCiC9R*yMS?{4k5F|P717N zwp_H-O6_U0yN90!cy3T-7PL`d+_)=ORK{pJ6h4FYpx#y5TXI}_Ut6a+yVY}pk4u}O zmd1i)$k1seJFj-B7~?>Y8BToI=c75n)2Im?W~;TiD9dpg9*fMgD#kO`)^|a4uQ)G zD!s~mjQlNy*};Bj@nG|UxV4wYA~HQu$PL38Tr?6ls(Vo&=5VIAAfet^wR6N(e7vP> z`o);+X{SAPa~Bo69MsTpp){XjgywX|@zGs^~^K+tf-3LT7lftXu<6QEiugQSf>}j@6Vx_?lQM z_6%c9=qYCb#_f&bp4orf@KS%51$j{r%Tc|FNj@0k$ zJu(mZ{LPEs= zo5O7O_^U4$h-~s6en@gImXM>dYs)`JKtPksb(xOrt8%X&d>8DBFBa24^Q!-W>_IC9 z(xQ*BLm67v`{{{ikHf>b9jH~yMtv%t(U_K0hi-ObW#x<+$c}-tQW_5Ci4QQb082|! z%ze@C5|qEz(|;qKQnNO%xv}w zbtnLICg(J4#;|%uTSs_ttZAKWA?S;3@vHG2Fu@ivOH?_@*8YE-0e`QOa2~#nCzd7F^Zx={bbW%lJZgK zHaUq|WMDIz^B*~o zV7rU8?yGu;tW?vGnnu0M`(^>9U#PaESqcBwif^A+gYD8|DHYfAVN6> zP=Wn&%6k&tI<@r3on(ST$bE4Rx@bXXl%FMlvkh>v=JxB3O}Y&heUDPHc^_a*?3u8* z85=80>rNOwLy{Iz)+MPZB=~kdAP+8Com(%~Pt$`<|h-fp1iUm)@7I zM^}I_eS;n@(<8q&dQPP*a*yeTV zbZ@*M`=kyo${&~ zT?8d5>Y_RE410Siv%*jxN<%|C-0XGjOK2HBJ3ItSBB0;&tZ2n3H_!L~2D_gG@x*M4 zJu2?D5%$zdY-{agg;ae#EW&+y`J~&fQM)jZ-|Se+^$0Fr!73rE5N&*##0oPz!WabGWJMZ ztt!P60fxg?Z__WgSP{N0OoiXE7_pDStvj1@&tWnpYLG0XHeHUC5lgCGub*0n;xEPX z;xXL(Pz(TvH1*O5n%15BDG9+UpfIlU}09u})bHYKRN#aCb>}OGr~_ zcW{Qo*gtAf^4Aj6w$u(W{-Och!V>;q2ttlj^=Q$>VumMcTe5U_x>F)#u$;RNAYT;C zb{VlNvbriVh~UjNizo0dFcT#jt4+~6X1qx|okugi?NB7S?bS>Hcl($?kVj#JCn4X< zO@dZ~lxh6mTx7OYtmzesYd*y9?o%#r5l4*QNSc>j3A?5PPp502jNzK@E%z*^PTaXR ztZGQeNEROTXk|tEXq*7`fdWP^7IP)uk4`C8i`wHmxbxVvfr( zv;Ss)s=ZV!^ETn1@cUmUs+36Gq%AjRoh_{@!@0rnIlFSIITlCBNK;7aJCZj}%S}@W z^+v8m=g*155kV^c(ZUtPU*@;xXMSn9X5hvzL(d)Kgo{PAZU!%n$2AOROt-O zzF~Jq_BWf4m!bX6jd%U4y+}rDNsF;@;&lIDxCo4lp^QA83-6Y~dD2bLy?uv)LFu+? z0{RQB*S~R;`9v~Y2Aw9ds~Q5|5%SCpYL^IYAo2!QB_7dgmyj@4T^!;+4PuLSre5&x zGdWj?Q%j{HjKp-@Wc_Sw_j&rNH;jL(ifmTlCB~_@k|E|>E7~7os4-8J1EQRTd5PtN zoQU4ApFV;K)9s9xr0V=$hVW|RWjw);C@m0=%#%&S^m6Q^cfr|jITB>QE)P)TQV1nE zWIM6Af992Elv&mzsQIYsHVyMDM%}D$db>=i8|=>{C7AkZ&4Kl*MOrQgtxAI3$FS?g+kKo&Uu-d1<#$R_o7Sn_q+Upz_y?k}uDluLSH#b%Iu}HHtI#$T*IwcIidNaMJ z&E2)H%TsNcaO!E(?Ija@KnZrILjpOBuE{mLaBljPtt)y?yScCFT;x2WH{1;BN)`>Y zJ`>*;KrkFp!O7!y?vJ=znI%nB!z674gJ6F!sQS@3Mtn+QFq~fA?JJ;BFFB%W6dXiX ziXE>0BHR0e(ZiVb>CUcgmDJKaWB#h$SHjd!8No4p8&(qLR@Ew8brg45m3@xFhN|Kc z*Pc&DK`B$pZV^1DZtXvUFr?ByK*kT&yO41=It$1O^n;v(evq%WJ+GYm1r2o$x*|Kc z`l~SxyF2i|GVBpix=Jn~-uM-p*LoN?++}?qPw3v2XtRNgq7_%TzhP^CFr4|-$Nf)F zvrn~ylG2$j-CZfg7C7vgRe6!}i}_#qaOX&$V=;U_s^E(f9RF6j&*0{Xlf)+g=})^mXa>B+u_kwGT=|;L zDOUXlNc8y!mlM)VrosYr$JT!fX8tz}$2DU_)bpBMX%R#_Te-Adeo(3sq*Si~4Gl#e z{vvj7HTxijoAX~`KdEPL>(u%CF+Hy?s9W5YS_ULOn0sm5e_04O5>0_fy%ZYRQN17h zA}yEaA+uI^c+z}J%NKmUcc&9ag_5iRcg}&e;mpMZ_Ay67Zb);p=Tq3Ko*+o73J{M8 zqWq~tOp{?1dDNTUre}6J?=K0p)vF&0;F~91Ry8w4R>idfW!$3fbH(YYR&Ia%du@IE z7#sb`ALZo7jBuflGgPx-NW(Z#bBLRp<*E7gS9^1F(uHZ@=a$@*vW(ce+#$f(V~zk) zgHY$;x9_lGTV+35iADQj!j|{5l>H@TywFR+`TuH3C{yk>lT-cy9kM-qvYW&$GH3gv z!WvXLlb_op5Nb(B#Bx$iQg2@5R5<#_9AU=ViS%&S}i3{WwzF zqq6*Nzqdf%h^12xbxQhn0f2zoN=R--J>P#39*jYQ@5pK*QM5vkvF}`SxbDQXx;Rqh zwCKf`I8Piw{6hWNsU5OYgo5VFf~PjkId9j^RU()B#jX$e5TZ!_Yv^<3Dwg}HMh4%* z(nfDXj{6^8P7EY=*1V?71#ubPQeHks7J5bf8xoH%%{NLM!#~gziH@Db61luvQ ze%40K;m+}kCbBr893x(1lWS^ea-bjYfATG~0)bKj1*g@k^9xIGaL^K>OUHj8qfn@2 zPzIesmiRk`jK1AI1g*R%7S?<8mN?&-N!XmT(WoSulJ!>v-s3RcGCvN`@ch(T$(Z2s z6Wws;c?y1;`d^@HZV95Ww9mkDj8fB`lzDRw z-Hd;7=~y==Z7nm`H6w-l^EAC2{t9mA49ELUq4lPEX__J;B2qZ8mW1pbVb{O^4L%CyhRXpr)Zpk1^J0_IE6X z7^Kqu$)r(k3hFZZk_OF(!rdG0-y8W$*52-s;4_uF8Vm=d9^~Kw1f|CbDo42ZtF7|* z;M61$hpb{1)+J~Zu2~~KGlE9%51~;7E0GhTqs+ z(4U;q{@XsJ{b*T$v0DL=?X`03jT-Dd`Ea?z0F`98KjXXm?AwI<-;)Chy_X!Fj);6v zCn6*0l+s<2Sf6x7e%(u@B4-ug5lfRDQrBz25%`88=tFloc6sjnmRLC`b#=^{sQ4c; zIA0&q)Sw3Zret23C<2SGe-+}eOa~c?1SsRF#q6-c{cYI#LJRFa$p*)ud6i zz8@WtQCRfd9LPO$=C7kJO^%#`4p}0^f4C$JG`Kl`Ow;z6NpqSu=U?sc#4s$?j+$e% zT%EX8mEr7V>kPWB=Y3y6ky{jTF5yX0>bWnxhyc*~5Ckq(=?g3NG*}}BC{qV6RC(pR zUcW^EDtWvvn$*F@*3PWfv_;jwJW-iahAkH;s}M8>*cQE> z%0H(_Tpv$HdQH%1*G4_sJTBXkM3kux{-^`hduUfYJ!@$KSwv6HBsm(U_a^RsbDWmC zO2ycit8(w{3@rGp5IHF=e~=t7ovA@QZ1fm(OSXD8{PNk%?5Sq8FGX43QQ*;c1&XXD z_6NQ{7+xVxQ(gj$vca|lBLyW~$sK6GzkE^WTwZmIJWka+(gbBZjnGC}FeS)85D~X|9L4wl*Xh(It#i&G#dB)~56QXs%7X#&hz=Uvtpy z@YrcExQc|XJ#y2GV)RYFN7XSlKlDn6fRm5Q5+M$df@Po;S+`zmW8Lbj; zJmmH)#J$DRVwvsfh2IwAUFSmvn!ksh|4skDxpzNom}TYt!PwjcY{WB+Ab;KzI_wf; zWp^=}z12`AdF?*+Fg4!x+t3gBTsw6Ka!&iL%YR<#)m;Z~KBN&Hvak7F`j_>~BVetHB3)Fuhi`4W&2D-4-hU~Yg#|G|KT^ojYPT6v$?Qu)8^^-ml0%AvyIx@A{0b+4lx_2CRz+_~tf zu1n*D&ko7N4imf#nA=hb(Q%_ta+D>;-0JD8^7KfBtdmz9T#m{;A#QtroD@8t#YLSj z8@*sb?VY)k24=t*-?DYY9yWK+p7&}w$=&+3-9U*(`F{^@3tSm!KrJlA0g;@fCj9F4c1z4utW;?S10?^#d_8K&{Xxk5%7sMBQ1oube_hKc z=UHK1zKzjkg;f(dd>^;{d@O`p0cGqw=mj|5j4%xrn4#8`?0Me* zm7IK?VL0^t@I~37P#U{%y|^P$^;f}{1xZkC6hrL{ zF#T;EqWAUr>c*vzfQ&V$QG|SN(Br(f`}>;TL}PAxc|ywPMM<$TTBu zYV1gf6qbU0l~UwPee5jiD+O?~AmCXG76POCvWPalMs3AP(cKQC^!laAHmm9d!}@jq zCp_$tcy&Sr)+`YH;FgG@ZSZf?x7%!T?p$Et>v23LQu#62Mmc4C2Ek{~KWA@UB$2vg zhS!Dee^_iCUIGV*$+dJ1^3tXnJa-lSz`99>x0yV~g?p z=sHjPAHIb9Kll>wYZ5ke5aaR(V@mPU;htwy*H%s|ZoK=uHMt(ESpk(aTCSGz$DqDVmtij2L0ckg z_ND&0I^1$Wq?~EAnHDvV;SB!>Z-9gcW&}{5)^Vygp(nwaC>Fg?lcB1aPMq~Tg(=V* z%)P?x(eO*$Z9`sa-;I;B2;p?2pYiQp+BSW!lJoCva=3&6Ptfh}fd80)REG)QjBeGBK-1QM?Vd z9~H4Bl)T0VeE1cC=k))|5&wNg*Wqr~=$~eTeczo*G0#7PQ%KlL6nT+`I!BJRkDwx) zNqF4_GC`5tmI8xkToYyuyom}ljl-^+MLg{38HG~W|3jFA9(?=Ez;YCnC70~Z2s@Bf1HvJ7zkztGI|oU~YQ{$FT@-NK{&Z0ZnNDQ5DU zdFFrJ|FqYZpswn#a!DBOSsOp7736802&}x_c5j{+JH112J6&1*GKW9fw2e3zlCfDv zluxLMckX?Xd%#{6_jFGrjG@UiU$WkurZ~=M2bKGA4oM}W;2EN=FZmSO^6$4(O0v*v zD_?@K7{4&=YZ1^l#Ypbj;YBO)KFyVOoMFM(NJ|!7dzZ${Zz!;(warp9MNT=B`?}~b zXzIz;FT~@M)jA=Ad#ClwC82Tnya?%jgU7bPnds^AL3_N3&}q=YJZ!7^#<-uucv(Br z@Gb0pqh9?Q3U6T@DA&8gNfVWHqQD<Ve~sS^c^Hf+@ITvYzUCz7I3rv zgK@NRJIEPWGL?J-bczUzKsPG96y|YjQtbNz+%NU4X!(P28JWVkXa9EwvD;qq;9Y_V zq^H)JQ0?f8oUvj0I+&*_Y{9E-&(P5`BTHA#YhMw>EmGo~ zZ;?W@&&#dWk1@xp#tbzJKTk%NB>*k60rK7C9BWA- zz9vz1N2f`)Wc~&*LkgOj95Y-kFNDXPXFXsAOU5gcXt|4xFekmYOnK_xId3R@Q7Y52 z(8IEG4_c9_*YKjp$_f4_s3OOc#Oz&okVJ)fg(4|06Gw*;qEYN8iU@*2&-6>NWi!b3 z&i^&d0bpY>F<~+O?Q8LGK>R;|AMUb5_6{#R_0m8I%)m(`#vqyw=-BUXH zWH6U~+41imi+&+tLJiHVok_xLRnrq7TvjcEoobz6PHO`Cqnz)Je=rV5ZM+lwYR`;D z!RXCB>;A1q`FGHSMOW}lG$h)Jn-836aT;1lF*pBMLO-N$M}ca&!9v87a5wvIe=_CL zxKIFbcgE*$?VCJ&8?qo`5*;TW#a6mk>scsN4tV#sUyXFg;@QQ}FaJ!&7Af2vn@4~r zxvFI{jn~^dw{6XhxLe7Zl)27@{SgSQUl!Fgr!-B<+otArymBR;;7K<||Q4qmPI_6rvRA;EZtqF7yYNuBhmXHK(+&DurU>B|yO>5SKF|#M!;)Xaa zfCReZu;Gxe#oMKIoTk{T{6r;zl^3S-&ERJ8a>>s*y{OlS)fSiSMvE@0_MGHF@ z<10XZXKmT~`1S$n0&@Lf$SKbb^Tgi>gYb%a zZBIwnaI>C*EG#pE9z&Mq>`hHmW)aJ?YH)NP1cJNygmgH+spP_}g6kWk&$3B7NH}Bi><4Ybu#;(8eB^ z((*^Q_~+U8+!Owb2Nl8ke9&kybCynj1^#Dos$-tbB z`er27mc7Nu{`MkwMSIv`M=Yp+)N{Q>flN@ov2CJy*A{*n?)DT|zjG<@n`)Py+P;78 zsc0obF$n~nY5A|?V)?Ns?DrvVX9->YnMUxLcfkJO0s-gt$2A)lf;7x|WRGw)-Fr7& z5B$E{$0z@W6+w|#}*73s^PV3N3Oud!p!ZIN@j&W#<0TAwG^L-)9EuElZx zUrrA2wStnLrQHx4pSn=+c#j`TOL&@vX{2nL((SC;Wt^!jV9UO~!n8rYH=xKqUMidv znUDHlp?i2+WoV)O45-rl)y(Nd?oy=-?U9DB0F0t#+>70Cd8;Y&PRIPr{F7d{h`HcY z0!sK4$M{=pvx|v$$$Q3n!0yri_HQd?b@gA@^}oLn|1p`e#lnOBEJvohLI&g8zQFIJ zjHeIWo>y4URhHbpRee<}u&!XSbZ#BoLcd539H32ApLW zEE`1q7~SRiHWVE|>zOL)qJHK9bn+HqG}&Nqou*m;45FLeN{xCG`+)o|&j_Hilm6>N zt*~g?im5*w@bj(n6U|3003E=*qk}X$rg^!0w=M#uXtYZhu?9QpZR3bwrUAJ?3+~q( zQW^Wa?Ii!cLK0njyu0nF6VS--Y_EZ1g>6ayFhf7=rzMm3Yoa2a`86OFJ0-d#N(y(< zj&=t(g3PP*X$%93q2}T!qPh?IL{CbmW$8+lp))h)?%V_2mWci_0_Q4IYb==Cfz3W= zWNz_z>b8b8EEDm%iBEowFmZ$`$78c=sOuKlmb^KxEu}EytR`(fAwQOGUJ+>U6>g(< z$>M|22fk67t_gLdIU zCz3X0UF+jwR!awI)(#i(rKdps1ICGmx&`79Eq1gug?}*WJ{37P66f_ZtOo8D92i{| z>BOYiWto@98$)qtowrSO-Zvr**;pEAuhUEW^9ARSdUSwvZ#4r8AhcHC?$__ig@~LC zZ3iX%M1l+HzdB{z9xwmbr86J63vTFr~ZK%B-YaoR<(7^O;N&t8N%wNKgbTzUatC$5gM7%&qqw(r4F+ z>a%7ybK@4&rf8#ni9zL!?9 zq=7?n=PRUc6-DJb{oRi+@mwjXarV~$@>}d&*U^igLws$+F6vQ?=@8_+cdIl&KnGo4 zd(l*vJ}RzH+3VPORM}??R)CO=85ACgv`;I|En1xEDPxGT)iyezi=q8A*#i!qJWs@a zc7CkH907Td)P7M5xrkb+7}oMbUpcwlGgSOasa=;Vi@}Or*?v^xVNR3NaN({q-iNZua%}lAa76rH$8Xyjxl^|?PvQ@9Zh2-7G<*p72Wtq2 zZ$NiFTPiR_kZIa_56`q z+ShfKYx&^BZJ^vFb-k`go{piRicsBeP%1-*8y(N1b5!}0bLY?}N}oypPWS(x ztYGl*{-(qK^AR1eZ-i%!4O4!ig4vYjgZGL#jkxQ1_CFJg6BhpQMnpS(qI-XzKYQ|M zKHxxWB+hYexW*+cwjIm%r+bGpMqci7@;XHhyw~Wjkk3Hl;wSBz34IGno%OBQlA*Ku zI#P!vdp%?7FEuGIKN@$3i+}?TIfeNTku-aD1f}I}!ouT^0qkE4*uYh(h?+|5BArG% zJNqs^w@4`w;;1Qum+46D!-^cDI9lK?fggVRtgOL@aYxL8O5;;Xr2@{x2~JpE;72$4 zR|gpb7m~E1V3yEdh=CcMX?+RF5j)vN^8GA`L!w2w%UWP7n|R8=;g*R$XS%^V5^-gq z(2VYgdYNii-h?!v!Zwx*B(5*{i-lN-?XRhww!G(Op!SkDA+V}!uw>fjCXjT!(8YBs z&s2f^_SN+aZG-2&4Qm@uVez)h{+r*KHrjSt+%73!;N0k!m$@k>fMsDoQ!`AuA(LMEop zA^uXB5PS<>!>Mz`Rj#KiRXaptI`7%O1=y74b2lG!=0Qk|mB#+TcuDSaZ85WesP#;* z=~|Aoyje;c^&!Gy;=p4rWXedGC4mOCH(SNz@P$TV_qJ=2PcG<~d#+0i&jep>}#oiPj02$IFQ8H9!-&Litv0$>cCn-QyDta(qBXbf0!X+0HQ&qPm2l^b^eh|iQK za}o+)y*@_QSC#)3wET;b{>@9DKosJ?DsKD}8UD{uU}B2)5#-=81=Tm(Eoyu3Z9@9oIyu@29?N_c`}e;yY~GsxrL2A;_3; z=327B%ZaM2{9pYhV#*s#R>MHtTLJ-@u!pArNB6EV zH4BdF_ro8>4;+j`a?^tp3-jE2N6QNyR8llf|6ovVF1P;0NVT?Avuaq8a$OIITQ-}! zT@GDY{jN9iY1}2;EWxY*)pxUG6nhyosPUXsy;4IbaZmVwUgS!IxhmZ}-iM{KVF-^C z^cJDaR4!&7_}=MRFHv`a7tuvx0dKJW*3%FZ3Bvfr1Nvf*uq0~i3(3T zaR!YTdVTSJHM_I1_#G+D=Ed>qw;mQ5okMh>Ji&$prk?OEn_761{``FCVzV@$6$g3C zoZa2nmigfuq&leI)D1&YvY61cp{KCL&eO?$uj|GG<*l?Pk|-V^5;&i{pJ zgU-JSz0JV~;JvoBcmMqCS1wy(nWeI+`s1O|6rN6bsvo%Gis9Ol&_f~pn9r~A(3)g6 zjAsGGGY-7`I{ZvEsh=u8!WOh71Hs0%^%k#y1kFpDDRy!xXRqkT!i@>Qn3PYKjm+%< z`l>`)O<|>8Rj<#?epxr#XxSQuTm{n=4-ADbEBU-9G(IVFO`|l1;Tm&(tm<*Ch5iD8 z;0+1-c_((cX5;A!*+aiyZ48Bf^S85qMcs9{G%%yvsC})bP?L8UlmaSR>#J&&s?+l% z-(Ab!yI6!pd@5S&O*~EvP&li|*46G-NqT8?6+`JBSzGlvf!d;6b~L<|$Nn3FVB zJgu>Cuygr6*db|VpHh%Nwwg17EkZ5ZW#KL2r3ocxYjL}eydV!EbbfD5MrYLgsK#BK zpgqy8bJYORC(_k9hTDPElp|Y!OE^LUEA2qkRoNbz6dZD5V$WAHii3}t@(wgU0bgcE z0}6jGcyxQI0>D{wFSCL?`pU`%G z)bb&M742o8D2TMdw^ap!V2OoA`CVu;6OLDnAH3#~Yg4Pol66x>l9}V(5N`^9Q(s2o zl)w1sGYZ%vn?u@dP--&xsqOd8KH*p<3@if~G$#Fe4{%JF(VNExYXu@dj9w&i>0^4U z%(%(MQl$26>@+x~q|+yqNKl~;meqYeQ{m*zcy7w9e-@tUY{9(r*4GLM;Rtp9pv-Rv zCP*_KbJg9VU+U=YTbQ>LKKnXDN4#OZ;F}N@;+QVW z8EofJfUx{A_SCQeXFloVc(u?$$dzmp4_I%jVE~Yndt2co``JwRdV#wdZpTZ*T5Vx0 zu$E{cs#$Kz5~+t987J|cDs6l(dy5+?)0;|5@ciN*W|I|BuUf&zoF+CQjA7jcF zE8jB;M6JZch_!!psWfpWj1XB=2uTf6-<&&)7}i2?4KGQQxWOfdq7^u05y5ys%tE*G zXwYfqp^w7g1&@17m#s04?^th&McnX~Zry3uT#ku&rR2qU~Y@Wg{!cH zy}P9M!1}?Vtjnx80je!Y-wq;R@k(tg*)v1%CLZ|Ls6#t;@bu>Z#H*Oq~=BV2xYR{7dE zRM+4~0MIs49+y7(_)GU#cNh*+W06Fo6PdaVR}ga>MP%BC_jaYcFJcw+g^e4qD){OK zUBzX8jyq@>>V_FmBndwjpVMSWwMXb@S+}6C z=2wkfWP%7LziqWtwZxc-fYO|x{K{Tk0WmutE*4~GUiNF#t(H~Eka2wV>}Fy{E0sAK zvT0)}5%*y&>UZ92~=`(xJenrBxmIiLjjcpo86+uKF0 zZ+j4{$lOHAcPhRkE6}O?BC4h{Fw!>iN-f-%m7-c22b6vmRI}e)R*w?XgrS6R#rbqV-SjntyXS*5+>;)Y;S5a1^OY|p7feH4H)I+pV(dNYvl8o$)`k6jkbQoV z{heCtG?DKd0npI0r7+^mv;oP1W8^gdwlYQUpz`c7{^KBvN!nKxZ05NH*4hW)Ms2aI zmXW|L;Zm4cLDkF5duQHSdo$N_u-vPEqBXMW4d& zS~n1xb3J(nZp6Y;iGto|tD6W+4p3(~a!<+tti{;=(SqKgUm=vd47n?Ogss zli$znsj7Aysmy#|-||oe)i!K(caqQWfYU*>sR>zZYt#s3KcYy#(WPK^Py~%IIOCgS zqy)Wg`;c$JDOuK*8<%;wT~s|+Ohv5p=-2Vf2pIk@*G0LsD@%wFF8=x!qW{>R-W1W1`XkD!rql@XacD&UOvCoTK3{T{a z!cg35Ql>|mvVO>4LcwsU4u2l%#&~V~c}@UMXA5A}8CNQ6DdpTA^LR|7L6`$iAp6t`k34#d_|tsGCCfSWL9^?rJkuUO zW3?LVKya1x6AgD|nsagkccZnbvf3H`IlbU)(>zbg4{<*tislT8L)VZE-Tf@4bC%XW zR?F?|a~FK$si?Qz8FbK^XMBox-_Ag=vO|g{@IuR@=R~=SB-qZs7wB9Fm z9n0%M((c493*q^eIAH}cE(+_4;plfwldd5Gs6$KoO>!B4kMq;}xfR&-zWFpkBdO z;O7Z3m&QcXxXTou7a3*UrDJL|h6j(Us(MUoj}DHR5IXKg>s(d*n~i2#Q677$?s&18 zieNodR5?|QZj$e;Xaq6vHVvl8y=_h8ZVrBG+_N%Gqdoir5V*9P{>8c?dtSTK{aLP2 zI?8bkslgJv&JH@1vewoRW8gtIAo(K%-rf z`7OA-G1f#XSvC~A3&kBO;k!q%ys|r0hb}_ABrcH=rJdhq!=r3SavPemsQR#G^&qNc zB2HvR^cps2naF0Xf%4ORG3P!cuYj%*cKRE2GI$1^TFh*^3N7s$p~Y7W5UZsjv3j$!G~%bm_H1c57S$_9 zVRPZ?!!T_Uf)hmxF)ibu39?$aXI&1siN3m*w=+Glb)Kbu8C$OnH?7a zDxMqAy00xk#Rp_6bU(`JUqT~ecd~AI>FUTlf~7)>nPdw4q8E-S5QLNlUQqd2nLqu3B}j2l;}g5K8kI z^LF)bB=|yyQo@58qN;8A2d;F{h8CkuVjLqv&}iHHPgmW4Ffc8z78Iq8ifS)S3k3ED zqxcVo9*o#6onLswd|M%WE0x#q6UcLBI7t&%lhs3NTOGEax$qWcVp>v#uxhl&0lSJ= z?ZBI8A)h;hxFVH=iQv^0)i^}8C4uLR|0z}cjPf79PAo=Fl)7B%>>&J;w`#iWcNcW2 z+;it7^0tCVIV2}({V;bVdjoYZe~!&3@zvCg)M*(JUb9Y*H+Ccaf~V(9c8dn|E5pl@ifR=}?=<-o$asUUfpzBvxh~l~1F~`6j!sKYv_LC5nHO zF}~o?l{l>~j<;pd!J@?{w*GX3YR<`(wR~58TAbs=&HnchXDQwEkFo0l92a&{0eat5 zStq-+$6Q}*^R*WgXSb|9Y}2-y1>|Q$%8vb?9B@bj78x%_Oz(z|jufTH63spyuYYi2 z1llx@Pt%KKGy`>Y-6Eab=-#e{*X7p5kuif<4(ZMblbD-^MLDzA8pazfid{Tia~DBr z%Cn}yUIGeM9XkajBihB2bV2z12B4Vj^tTgLx@MH5Y1;+{J4)usk{#r^%+6iqPR*jwFXzZt$338z60e2}Qa7u2`;dh7CvO*8?c+?ax+%@>-c*g& z3oFh@ltFUHHz}v7BOBK#LhD;CjEZX9dYpHG2PDkEqG+L$XxRn34bjD*yalvsQ`tk# zI3Fso(-;D47_J_(Mi&=|LGIjf`65m+Vztl0Y!ojW4@;#iO!i%6cW!|6 zZ&W-91Z-nhyPg=%zu)V@mtferiQgBgkAmBf(4lhgy=@%+VC4S6xW3$xayf`RwU*d!NjYvBbmQ}pf`SZL6KYHJRyQtEA#2o^)p6?Xu=+IC!C^}rSE)$t z)Sg|;^)F3a-$n!4gRa`z2YRmWDLt(O7f&zb&4p{=wP|lUUk#QiN_zvx98@3~I-mxe+SwVEUb4%2Q< zeW!W8NU(;LE`|~V`4Ya2l5tPA>3Es z&IpAHSmW{S>j{*`oRO}Id9wJPd#m)YXm%$5rMPh8Vy*!v-BQI&Hj=u_ju|O3x0`4| zs*+s8mPl=n6_HzRAo-DhzAiVPuU^TKxR{uxSKfk7U={ayS}{-A7wYXzvV_LinY!~d z%T59-Suba)weWqWlkS%08M0mnOv1Rqt={K$h&_;c7Zqun+dQ77fi3Fi3rA>jWUIvA#=UYna6Pv2j9iTRcXB zd`5Tnru71M9Lb30>wvW5i@B+|gO~leaN?BkEF}mgW2C`%4O-8f=MG94ar75IJB~-h zp{wo~yu1P`eseeeVu>Ss-?c&XsR|&8l;OXerB1FFpHtsyk6u$0Po#@Zr25Doig;$o z3Q9#OzxaYcTW73rFAR5yRo#aYM~RE!)HF})5u6@IjO1+&)iv}R%k*&NeHE)#KAGGZ z;%>CU{5kh9DI-&1TVCp5&sDz8XQ0=2WzQ^FViwU|Vf{5KyV1%`lFkN#26^D)G35od2CC`JR)D zgnhTUWq1f1H<6|Ag`FBdOSE_BK)TU0qQK($bl{ki_OyyU2wHeD@} zl5%eF=zMxaDCB`(oaD@KhFx!cv}HVlu32itKeC0mUQZ)QlTx zL)Up7C<4gVgyE5&qr+ z@Lk19`m)jxSZi5-G-m8T-qL?Ua7UtY=lbw8r|z=;dhsE4jXqG-WoCP%ZSZGx?A$#h zMKEzJnT8IC?0HMq9!2Kwv*XF;2*e+~bLkiAtPsjQYGd|dEd|?ysgSegY*1;U8f7Qf zN*Hdd+)RN-OGAR?%#9Iia5=5bpxYiHmfU>s9}zqjRtfBh5kW>QBET^3p0yMQ1LbJI^lZ7dph>yU2(v9D%B&&s&8B!NijIVHDMR z3)Q$|Db0ae!nSrGHH=l1{JFmkL~e0i@g(TQpg_|8%o45j+P8XcSgZL?&x~kuCBJp0 z#?!EpsAXfohLjPj^WMUq;u1seGO#hq8cUQKsQ*sbn8lgo%ZZ5k34!#ga4ZDSw6euz zm)?Lgepqk+#*3P~XV-+-o_{G&kdYR)8s$Y*_A+tvx*%7+SK1kz416P0=c>Q!Z8Hi% zHh*avpT71>7ti{+LAQju^{wa6}FuA%+A1+(~EgjfhjlRwmG+kj)eW}Ql{U;?*g+dOWS7jY2lg1~`N zG7tXwZ7S$J#B@zajGWY#6_@tIYj`GUW(3B^f%8Hs=H>b>x5DZ#Qq~kyUPUU>2FBEV zLz-rUU;_bAxF89kZZzCI)sp2+O8uyX$gnHoL|wu_KP;UnB*Ikb0MayMsqkwYFbOKn zns6xHOnNF@ynig0hDS^hjHqO}iPSMJelgH;zkIc zu6$>RYIcyrX=q-?zxr0@%Ao3*&tEY>ahd24=ze)Qy6PF<{6v*YZE;fww`&D?)^%0K zpcK1xt-bLF11``+WhtOPJk9?i(vyxU7RW4G>}6nIpo?2t<8hH0;}+K^D4ao=YWTY@ zWpHb4nw@_tyZ1+qC$snFE^P|qrc{Kz%=Z{v=_Q7F^E=OeSLAzBzYm3n_WI5{g}S>I z3w?7`3c3w^g7C3@X)!ajDHH^~LOF^ECSXRYZ_+YPTId7GK?!vB*=g zEIj%RkzW%4NxE@5^FGnsIF$+`4_kYd=Ey#St*1-1gWT{)3Vu&VSWS1s6OxiWA~CwT z!#fm>!>6tCRE@30Sxds|y3V;;oNm0KQn=o{3%qQ0yN#?#QHbUf+Xxr52IRPqCfHxQ zI$&=akx~x2mRE9+unG%~nsDd>#DoeBdHXb5iCnYJMY_kI;BpBx?d@2ITqbJtvpLG& z>dcYhu#AQ`w~@q5>(Z3MPp4DHn>qRx9d9MJEU49VQ#!F~52?`^6pN7Vf>q{cRo^dC zrcfoaP>^h$JebZR7RFUIJ8yyo_o8vTigwi4)z?`yWz2OAuK>v!yqJ7i3;p(PjW$y# z&4$XE&7M5h5Xk51(P8G2^XdR#an$hur+Y$U4k>@>L3`S!sKTp z5e%N)YMf0U-PT-ECSh6_ks3S&0+p`|QjoE_c~0I-D73yE+$7hPSre`M0!Lo+t})@b z)K)XYpTj-8bd@TxAjbz(TrKjP@jrC?j~^4D+-DkM@f~NyAI~R zVgDbEU3Xkl%eJN@5E6o*5Rm|eYN%3!p(p`q2Zd0TUIG}99%%w90TC%u1dcR~6bUFn zdRLKN0wN+UARSad1OzNc-^O$9JHGqwy}vtu?d&~C_N9F7`*|r+u}>_4K}1V0TdqUo{)BB{#c%2NAQQx0xCj$O91>8^5dlv&P4@Mi zt|RpXp!rXywG0NaOV}Gdc(ordxH&9guP+@q)0nwj1u~e_8hp<6#Z@vV#rGaEvT^&hbY6HXPEMf!H@z>)KVW9@ba zrO6btgHULcr30Z+GG`Z+I%~yufF*yypva=$$BMnr93F;uS2~-qA?_ZQylfj+^3rEI z&#EsBJztkwEp-mDjmTzF}ZO_D5R6^TSgFwhtQ-BSaV(V7j`E~MZ4cZN1?`}gc;)L53d z--RBQk3ZTWFEQ``gK27fh)?XR{`jq%`?VL&?u|`Wix#FQ&*eFtHw|75F`r=2VT%Dl z#)Txom&*ViZotfDeJ=T6?#t14jJI^r>%|I9V&mWyg}^fRhnrU>H}%8rxKF2SNj$4= z%m#eku0~aOfO<2n<0hMTv&r0=>zOpEXICh}Re5p1wMfFka1nhm>Ji#EXvt~A_2(2)SyJ8~wQCeRetLhQB zHw|;_@;Geb3Bt!8!KMp*TekAbUFUZmASJB!B1z}Pnj12MI}Mp;ylJ7n&(!PjUOMm{ zyYiaObHqN`Dl?B@Ou!!l6B9dg{5ckNoB=J5gkQ1|+TmeY6GrZL-ko{5GvJUmY46A| zMs_J@i7`gu)f4K5WfCp)j+*um#LFkJI7bOGkzu=I_)<`~i)B=m?mxEEKvgE?8Bj?* zS(u<~ho!Xk=>aLf3z>^_p8yxn^v0w`T-sVdnNvpY{V&l7N0 zQWmU!ZB>rCTZU8msBzOmf3IjHt8YHsc)t@)V+-+Qjk5*Ql&;#*#&@rKVMrf?Y+b^| z8$)G;=6W}?8Py9HkdFNQ#|jxI{84>Bm>P3UKfeKzR^O>zy^c!=DgU&%@OpR(F#A$C z;DQ3_;Uuxylsb+G-|%-`*cQPvZ^IXkIPF>hjK&&UPyf*WutAjqMt`$mWP4zf)iPI_ zR$^Gce1(d7#`E>z-UlOWgQ~9u>W-gEmsM{1YW%e=esdF6QjkqB-L6!feHoeEX>cl} zEGTL5Q_UYsk#`tx#x;cU7k5TLZd@FZ(76+^lf==AqdaCh*=@qcY3?;YiCAVXd8b?c&Ln;>#jGEEi z(}pnrp-;DqhE}#KP+h%2uWNf&J8qd#Nt%s4g$=c}zu#^ zPq`^=SE(s`XVan5-oE>@d%*bX@Vgi{1QZ$Mz?CKyDf*7s6qrTO<8%pCly zI`a_rGoE!B>dIoYqs~%1k+g}rBQwjE)YAL_&^?x3YF^h7sgb$NZlae(F}Fhnk5LMU zYdDQsFg3)rG=}#MG`Qq0{3*aXbzsjRwD)Za*bGG}r9uE=Ssa%N&bvMXJoaQs69*2` zmd61n0m4&m?n@2WA57iHjyhHtpkE>=B}9PLXuq(1>Pn2{V*>~gn)Z^OR%|1bup5nF zymXW$AYOsz#^H=pocd(m4tXchGcYiW&1QA6Dn>giTPRew0v8LcE%nNtgj z>-L;Lv}<0oJl(#Y%D13rp~ycll3`a0IbLL?hwR+uW1*DL_)zO2Y+Vv6-cRkeN0B>a z%1>4z+=K6FlXb})U{(Q0J1-ymDh@mgmJftNrMEB4Oqw{8tN*kKH(olru=l`sgA-pC z(C7L1eH(H^tIavqkn=DVzfW9~$g6}ESvR6rExO%mpHk>gpvTx)B2H5{1Mmh5TmKFV#boXB!vDlK9{W114cM){`GzGee zR+h&h9>22i{22j2DZr~dKG6&uDqZi{mgS*1#E7N&2gKTn(%4MC{0(0j*Bd7`AH~Ds zO2E8j!M9sL(K_Vcg|74Ii?6s!Ghc?&428%RXVWLn!FE(WoPxZ|Yo`sbSaQ)z<{d&Fz@+&B@i`0%s%rbEddm_QWu;6CzByA+H+i`T>JKr~m>H4DBXB2IpGy>)v5Ek#k%LEJ!1 zRE8etVQWU_K|h-tnNOZCRvc-84>zDKSUSqBrd2Be*{tI@CLQz$k{7b7Hy=93VV%Ij{4^`~d0%DynVuaqGMAwnA>NjA`!%dU6 zh}`GH22hz1{LdiF>ac5FriFg|p0&>r@A!$SniTT7OAV=o@^$a1{z>(&^_Z-DMy8K{ zm+wchh&Dig<%?qOD7)FD5M57Onxj<}hh_#lNPACMuJqRSEv1v!qr(P%FnM|mW&U8& zuD#hWBqa!;OlxI0zgBX^_`--!#-n4~Ob;BdCWmVWTY<&nQS8^imX>o6k#?R6Gn~}3 zt&lX}R)QP6HxmORIDMv_T0B-RC@WW16YJ{uyWa!-eO}Z~M&?~3i&)B9tHX7hP}Mrj zIm}X8Z4xpUbG_ldN72PqZRx%EbkK@SD~KvTIbqK@#VLDy`Is~8q;8N;nysB$bxSCz z`3>~0u0fbqbBG^e=FUYt*Px3R#H}opw$)FiQTbCa6etB43eXK0nX`{Gf9K<~ng^J` z?zNb`DEsvrdIujgjgK0qltkr1|#+X~dd*_Y(?M(I4lVa99KW@nxDy+*bN7K+; zFLu^^G%xzwfYm{iym)_UsyB|$Br(AbmXkkph+{c`QFTcT^VugUI^1aRq5`9JWGB=2 zde<^GvPZ$bHg!{IdnZ#LK5YnhuL{Qawf6IE3EZeWKNUrnyNVX^A}Y$YN|T{R5J3Fb z=os9yY09EN^o?9Y?%X?rWuXK$f@*SA1z&P8YInlRmVvyfaAEmfy@MuCC3k*5E_ zhPTIKgJG5`4j=;y3j|+R7fH4FQOFTQB_9B-yj~FIXe}S>AKN=zBm({}^ki<3*wxT~ z57o;5Y#^ZJqJm4)MI#NPMZ1~8H3m6X9$Aa3A5TuF)C+R0QN>eIq-#KjEiR`!)>YjN zvBV@UhG)vhTFW3&+IwMdt3TwE+jrH@Nv3JQu>4cK8?HTmj<*ktmEpJ8L<|D_)B; ztDK&s&*)0Z31ik`AX?-WdjJ(!PVI}dJJmdHXbk01nOzJUd*frQzy3zL z&l_Nx*EB-&$!R$`hdK6kyr_w!ij(~95_yss-{*1#0CMISY-jZ%Fpu1wQ(o)V1zC6S z43gOOimMa)gQwzTT0Q+wf~OL5A2)^6QmVww^^GNbS-Y`XHB|H%^&o}DFE4q8-`0K| zuXe!QW2m9Fdu@ircsVKB+r@RrVJU!9@y-l$bP&t!0wb;MUG@U=`572VG;XbXV$Q3^ zxv#Fdu~s$dlb@`+>x?%tjBrP-s^0H{$YzpO$6ZbtMkbLt;#f_>?L05y#do&4h9Yf| z)?dKgQt~DVwL7;NC)iYmce{K|MJjGhboR4Ki07n#faMhkM|9fgiLFG@AB%TCmwWid z&T~z^k^{A>$teED;rtZ7{fOU9s4$}Iau?VnR!YFhPeL%{`46VT@|3@ka)7VrC}sM8 zYG^-`k0H`F|clb$z zG8biOx+ofLlZ>U9{=ECl0cef3=m}m9bH2c?#*u?(pG-c2 zSx`P2>Eb-yJ92;hO&mNyOW^GXd0)ZxkSI3?%UumS#T$N8R~wMR)KGy`z`nxCVf{*rZ+$I98xFivm9 zi7JSn)w4)2Td7TP`doOz!{++ecb|vGGqugyrI^03)9uW^4=zEu#Wp3M7^9TbDYt`2 zTob~C=FoT!#0Epqy8Lb6v$b10P+R5I%EN3oj|=k;=)>P55*tWJV@$9$9nP8#FBy8! zK$pxK!^ulH@whzJ`sx-kRtBRp;hA-~4VNt;IGppFHDRk9wzDk&fmuGTG5g=0Om`A7lKwY(Uah2w3Rlg}6-2iZ@hMj7AN>-1PlZLMg!#w$E-#0IN) zO7pT_(zC;=$+hxMS^;`~e8gfN5D#95{_ETCe;>zkl>9Q3C5wIz*mMv}6p*Q~5QvQ} z)3CVq*6r%~5fcc~iiw)eLIFZsZX!AD70-wX{FaS!n+M+*GA>lBCh7Deta}8lea z{yF-ioOID;34lsg92EnP0!!YVUZ}oM`Q3UF!yo0tZuIRT0w$a6V^p#XM3T*iStwRB zXegOog4=x0_M^obrAx6-`1Pw~mQ2poI>kHodP0U={$P(8x23vGdqbN;-8b`dFjhvX zF)xshnH>Y`l%z{vpdpe}K5Y@O%DBmCgj=;IpC|kz2uW9PI3!M>no1nj&_`S#sf-3f zw^^yojN4+u=@Zt4e4&Ua{AoQ)JSB!3Z?`%br)fn)8X*y(#~Dk9GHdQnKOba6-?A|| zmiD5iHL{|jZ2W0@84k@Fa-9j7kU9|YV;}_C3lmx^6{sv%g(cKQ1ZHOoa!sGpNG%U) zuZ$mY;$d!n7)I84k)bY1m68DZCnfs-Y!LqYp82OM0K%LZjFzNIFriX_Og)x;#CbZe z7Mr8f$i4T_&Q6q!s}2WX0|_9OW}+1L5;rKla3mRe4TlESO2Ao`CT@-e>jWSr^SC?4 zXN*!m@nHdPi5+1gQ=%+EASepOi#(IKU056y_>|y){jTsOtRv_f)C&s61Kmi80fJa= z-DFW1!J9tbjdv^-WnqD!MXLc913df0I-`%=$O-xlmI0vVOCdNT+*v3zzhZf zT#0{s@4hzJ4E@t`mZ(BX(Fo4_T(##0?-2+DMcJ3g1PYWB@41$K=qA`1@Ti7B3&Bjk zrjq~12L1Cz4u}Zzz9{BTomQYJINe=JU*DJ8e|QbV^4s#ky8%^nV4eY6r0h0NRF0s< zQPh7(wjjj5+rJTjPJY!I0lS!?fr= Date: Wed, 12 May 2021 07:23:13 +0200 Subject: [PATCH 3/7] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5c6765c..a7f13a2 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ * There's a Discord server dedicated to PiStorm discussion and development, which you can join through this handy invite link: https://discord.com/invite/j6rPtzxaNW * There's also an IRC channel on the Freenode IRC network, `#PiStorm`, which is bridged with the `#general` channel on Discord. -* Selling blank or complete PCBs or derivatives on eBay or elsewhere for excessive profit is frowned upon and may lead to forthcoming related projects being closed source. -* Even with the current global chip shortage (May 2021), components are not **that** expensive that you should pay up to a hundred dollars or Euros for a board. -* The PiStorm is not a project for making money, it is meant to be an affordable way to replace and extend the functionality of EOL Motorola 68000 processors. +* **IMPORTANT NOTE: Selling blank or complete PCBs or derivatives on eBay or elsewhere for excessive profit is frowned upon and may lead to forthcoming related projects being closed source.** +* Even with the current global chip shortage (May 2021), components are not **so** expensive that you should pay up to a hundred dollars or Euros for a board. +* The PiStorm is not a project for making money, it is meant to be an affordable way to replace and extend the functionality of EOL Motorola 68000 processors and have fun in the process. * This is not meant to discourage you from making PiStorm boards for others to enjoy, but for instance selling the product as a commercial item and then pawning off support to the community if something doesn't work is absolutely not good™. # Project information From 349fece2541af79ccce5f4ba30b0c7454b726a01 Mon Sep 17 00:00:00 2001 From: TheRealTachyon Date: Tue, 1 Jun 2021 17:47:31 -0600 Subject: [PATCH 4/7] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a7f13a2..618681f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ * General Performance with the current use of Musashi as the 68k CPU emulator is somewhere around a 70-80 MHz 68030. * The intended Raspberry Pi model to use with the PiStorm is Model 3A+. 3B+ works, but due to component clearance issues it will not fit unless the Pi itself is modified (USB ports replaced) or a GPIO spacer/relocator is installed. * The Raspberry Pi Zero and Model 2/4 cannot currently be used with the PiStorm, and support for these is not officially planned yet. +* If you cannot find the EPM570XXX listed in the BOM, you can substitute an EPM240T100C5N or equivalent # Amiga-specific functionality From c7d20e9a1728477814e6d820edc31304f7adec2c Mon Sep 17 00:00:00 2001 From: beeanyew Date: Wed, 2 Jun 2021 02:13:41 +0200 Subject: [PATCH 5/7] Update readme.md with more specific BOM CPLD model information --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 618681f..3c5010a 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,12 @@ * General Performance with the current use of Musashi as the 68k CPU emulator is somewhere around a 70-80 MHz 68030. * The intended Raspberry Pi model to use with the PiStorm is Model 3A+. 3B+ works, but due to component clearance issues it will not fit unless the Pi itself is modified (USB ports replaced) or a GPIO spacer/relocator is installed. * The Raspberry Pi Zero and Model 2/4 cannot currently be used with the PiStorm, and support for these is not officially planned yet. -* If you cannot find the EPM570XXX listed in the BOM, you can substitute an EPM240T100C5N or equivalent +* While the BOM lists an `EPM570T100C5N` as the CPLD that should be used, you can substitute it with for instance an `EPM240T100C5N` or equivalent, but there are some things worth knowing. + * The **T100** part of the component name is important, as this signifies the number of pins, make sure this is in the part name of the model you substitute the original one with. + * The number 5 in C**5**N is the speed grade of the CPLD. 5 is slower than 4 or 3, and while 4 works with the current bit stream (June 2, 2021), it cannot be guaranteed to work with upcoming CPLD bit streams, so please stick to speed grade 5 for the time being. + * The letter C in **C**5N denotes "Consumer" grade CPLD. They are available in "I" and "A" variants as well, denoting "Industrial" and "Automotive". The only difference here is the operating temperature range for the component. + * The letter N in C5**N** signifies that the device is RoHS compliant. If you do not require an RoHS compliant device for your board, the one with no N can also be used. + * While the **GT** variant of the EPM240 (for instance `EPM240GT100I5N`) does work, this requires some changes to the components you populate the board with, please inquire on Discord or IRC for detailed information. # Amiga-specific functionality From 3203ac85909c4feadb96bdf56b373785f9c81210 Mon Sep 17 00:00:00 2001 From: Rune Holm Date: Fri, 11 Jun 2021 18:37:57 +0100 Subject: [PATCH 6/7] Created address translation fast path for code reads, separated slow path into separate function so the fast path is more likely to be inlined. 10-20% performance improvement --- emulator.c | 2 ++ m68kcpu.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- m68kcpu.h | 63 +++++++++++++++++------------------------------------- 3 files changed, 83 insertions(+), 45 deletions(-) diff --git a/emulator.c b/emulator.c index 8027617..1be7bcd 100644 --- a/emulator.c +++ b/emulator.c @@ -4,6 +4,7 @@ #include "emulator.h" #include "platforms/platforms.h" #include "input/input.h" +#include "m68kcpu.h" #include "platforms/amiga/Gayle.h" #include "platforms/amiga/amiga-registers.h" @@ -43,6 +44,7 @@ unsigned char write_ranges; unsigned int write_addr[8]; unsigned int write_upper[8]; unsigned char *write_data[8]; +address_translation_cache code_translation_cache = {0}; int kb_hook_enabled = 0; int mouse_hook_enabled = 0; diff --git a/m68kcpu.c b/m68kcpu.c index 7883bdd..4a4fc39 100644 --- a/m68kcpu.c +++ b/m68kcpu.c @@ -1208,7 +1208,7 @@ inline unsigned int m68k_read_immediate_16(unsigned int address) { } } #endif - + return m68k_read_memory_16(address); } inline unsigned int m68k_read_immediate_32(unsigned int address) { @@ -1230,7 +1230,7 @@ inline unsigned int m68k_read_pcrelative_8(unsigned int address) { return read_data[i][address - read_addr[i]]; } } - + return m68k_read_memory_8(address); } inline unsigned int m68k_read_pcrelative_16(unsigned int address) { @@ -1253,8 +1253,65 @@ inline unsigned int m68k_read_pcrelative_32(unsigned int address) { } #endif + +uint m68ki_read_imm6_addr_slowpath(uint32_t address, address_translation_cache *cache) +{ + for (int i = 0; i < read_ranges; i++) { + if(address >= read_addr[i] && address < read_upper[i]) { + cache->lower = read_addr[i]; + cache->upper = read_upper[i]; + cache->data = read_data[i]; + REG_PC += 2; + return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); + } + } + + m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + m68ki_cpu.mmu_tmp_fc = FLAG_S | FUNCTION_CODE_USER_PROGRAM; + m68ki_cpu.mmu_tmp_rw = 1; + m68ki_cpu.mmu_tmp_sz = M68K_SZ_WORD; + m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + +#if M68K_EMULATE_PREFETCH +{ + uint result; + if(REG_PC != CPU_PREF_ADDR) + { + CPU_PREF_DATA = m68ki_ic_readimm16(REG_PC); + CPU_PREF_ADDR = m68ki_cpu.mmu_tmp_buserror_occurred ? ((uint32)~0) : REG_PC; + } + result = MASK_OUT_ABOVE_16(CPU_PREF_DATA); + REG_PC += 2; + if (!m68ki_cpu.mmu_tmp_buserror_occurred) { + // prefetch only if no bus error occurred in opcode fetch + CPU_PREF_DATA = m68ki_ic_readimm16(REG_PC); + CPU_PREF_ADDR = m68ki_cpu.mmu_tmp_buserror_occurred ? ((uint32)~0) : REG_PC; + // ignore bus error on prefetch + m68ki_cpu.mmu_tmp_buserror_occurred = 0; + } + return result; +} +#else + + uint32_t address = ADDRESS_68K(REG_PC); + REG_PC += 2; + + for (int i = 0; i < read_ranges; i++) { + if(address >= read_addr[i] && address < read_upper[i]) { + return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); + } + } + + return m68k_read_immediate_16(address); +#endif /* M68K_EMULATE_PREFETCH */ +} + + + void m68k_add_ram_range(uint32_t addr, uint32_t upper, unsigned char *ptr) { + code_translation_cache.lower = 0; + code_translation_cache.upper = 0; if ((addr == 0 && upper == 0) || upper < addr) return; @@ -1300,6 +1357,8 @@ void m68k_add_ram_range(uint32_t addr, uint32_t upper, unsigned char *ptr) void m68k_add_rom_range(uint32_t addr, uint32_t upper, unsigned char *ptr) { + code_translation_cache.lower = 0; + code_translation_cache.upper = 0; if ((addr == 0 && upper == 0) || upper < addr) return; diff --git a/m68kcpu.h b/m68kcpu.h index 0be9551..38d6b9f 100644 --- a/m68kcpu.h +++ b/m68kcpu.h @@ -1075,6 +1075,13 @@ char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type); /* ---------------------------- Read Immediate ---------------------------- */ +typedef struct +{ + unsigned int lower; + unsigned int upper; + unsigned char *data; +} address_translation_cache; + extern unsigned char read_ranges; extern unsigned int read_addr[8]; @@ -1085,6 +1092,8 @@ extern unsigned int write_addr[8]; extern unsigned int write_upper[8]; extern unsigned char *write_data[8]; +extern address_translation_cache code_translation_cache; + // clear the instruction cache inline void m68ki_ic_clear() { @@ -1152,55 +1161,23 @@ static inline uint32 m68ki_ic_readimm16(uint32 address) /* Handles all immediate reads, does address error check, function code setting, * and prefetching if they are enabled in m68kconf.h */ +uint m68ki_read_imm6_addr_slowpath(uint32_t address, address_translation_cache *cache); + + + static inline uint m68ki_read_imm_16(void) { uint32_t address = ADDRESS_68K(REG_PC); - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - REG_PC += 2; - return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); - } - } - m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ - m68ki_cpu.mmu_tmp_fc = FLAG_S | FUNCTION_CODE_USER_PROGRAM; - m68ki_cpu.mmu_tmp_rw = 1; - m68ki_cpu.mmu_tmp_sz = M68K_SZ_WORD; - m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ - -#if M68K_EMULATE_PREFETCH -{ - uint result; - if(REG_PC != CPU_PREF_ADDR) - { - CPU_PREF_DATA = m68ki_ic_readimm16(REG_PC); - CPU_PREF_ADDR = m68ki_cpu.mmu_tmp_buserror_occurred ? ((uint32)~0) : REG_PC; - } - result = MASK_OUT_ABOVE_16(CPU_PREF_DATA); - REG_PC += 2; - if (!m68ki_cpu.mmu_tmp_buserror_occurred) { - // prefetch only if no bus error occurred in opcode fetch - CPU_PREF_DATA = m68ki_ic_readimm16(REG_PC); - CPU_PREF_ADDR = m68ki_cpu.mmu_tmp_buserror_occurred ? ((uint32)~0) : REG_PC; - // ignore bus error on prefetch - m68ki_cpu.mmu_tmp_buserror_occurred = 0; - } - return result; + address_translation_cache *cache = &code_translation_cache; + if(address >= cache->lower && address < cache->upper) + { + REG_PC += 2; + return be16toh(((unsigned short *)(cache->data + (address - cache->lower)))[0]); + } + return m68ki_read_imm6_addr_slowpath(address, cache); } -#else - uint32_t address = ADDRESS_68K(REG_PC); - REG_PC += 2; - - for (int i = 0; i < read_ranges; i++) { - if(address >= read_addr[i] && address < read_upper[i]) { - return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); - } - } - - return m68k_read_immediate_16(address); -#endif /* M68K_EMULATE_PREFETCH */ -} static inline uint m68ki_read_imm_8(void) { From fe3b4bb032e02148c44ea11a23129650eae7efd7 Mon Sep 17 00:00:00 2001 From: Rune Holm Date: Fri, 11 Jun 2021 19:34:03 +0100 Subject: [PATCH 7/7] pull the PC masking into the code translation cache, so that we only need to mask the PC on our slow path. Gives us another 5-10% speedup. --- m68kcpu.c | 8 +++++--- m68kcpu.h | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/m68kcpu.c b/m68kcpu.c index 4a4fc39..da93430 100644 --- a/m68kcpu.c +++ b/m68kcpu.c @@ -1254,12 +1254,14 @@ inline unsigned int m68k_read_pcrelative_32(unsigned int address) { #endif -uint m68ki_read_imm6_addr_slowpath(uint32_t address, address_translation_cache *cache) +uint m68ki_read_imm6_addr_slowpath(uint32_t pc, address_translation_cache *cache) { + uint32_t address = ADDRESS_68K(pc); + uint32_t pc_address_diff = pc - address; for (int i = 0; i < read_ranges; i++) { if(address >= read_addr[i] && address < read_upper[i]) { - cache->lower = read_addr[i]; - cache->upper = read_upper[i]; + cache->lower = read_addr[i] + pc_address_diff; + cache->upper = read_upper[i] + pc_address_diff; cache->data = read_data[i]; REG_PC += 2; return be16toh(((unsigned short *)(read_data[i] + (address - read_addr[i])))[0]); diff --git a/m68kcpu.h b/m68kcpu.h index 38d6b9f..21d11ad 100644 --- a/m68kcpu.h +++ b/m68kcpu.h @@ -1161,21 +1161,21 @@ static inline uint32 m68ki_ic_readimm16(uint32 address) /* Handles all immediate reads, does address error check, function code setting, * and prefetching if they are enabled in m68kconf.h */ -uint m68ki_read_imm6_addr_slowpath(uint32_t address, address_translation_cache *cache); +uint m68ki_read_imm6_addr_slowpath(uint32_t pc, address_translation_cache *cache); static inline uint m68ki_read_imm_16(void) { - uint32_t address = ADDRESS_68K(REG_PC); + uint32_t pc = REG_PC; address_translation_cache *cache = &code_translation_cache; - if(address >= cache->lower && address < cache->upper) + if(pc >= cache->lower && pc < cache->upper) { REG_PC += 2; - return be16toh(((unsigned short *)(cache->data + (address - cache->lower)))[0]); + return be16toh(((unsigned short *)(cache->data + (pc - cache->lower)))[0]); } - return m68ki_read_imm6_addr_slowpath(address, cache); + return m68ki_read_imm6_addr_slowpath(pc, cache); }