From 8d1714777d2d1435c89a99853271051d9830d71c Mon Sep 17 00:00:00 2001 From: uohlhv Date: Thu, 16 Sep 2021 20:44:09 +0800 Subject: [PATCH] Initial commit --- .gitignore | 4 + README.md | 12 +++ archive.bat | 8 ++ archive.sh | 4 + compile.bat | 10 ++ compile.sh | 7 ++ manifest.mf | 1 + res/410.png | Bin 0 -> 1552 bytes res/420.png | Bin 0 -> 1366 bytes res/430.png | Bin 0 -> 1386 bytes res/432.wav | Bin 0 -> 1360 bytes res/433.wav | Bin 0 -> 37960 bytes res/434.wav | Bin 0 -> 25711 bytes res/icon.png | Bin 0 -> 3718 bytes src/BestTimesDialog.java | 150 +++++++++++++++++++++++++++++ src/Board.java | 170 +++++++++++++++++++++++++++++++++ src/CounterDisplay.java | 75 +++++++++++++++ src/CustomDialog.java | 154 ++++++++++++++++++++++++++++++ src/Digit.java | 49 ++++++++++ src/Info.java | 43 +++++++++ src/Main.java | 5 + src/Menubar.java | 118 +++++++++++++++++++++++ src/Minesweeper.java | 151 +++++++++++++++++++++++++++++ src/NewRecordDialog.java | 98 +++++++++++++++++++ src/PlaySound.java | 64 +++++++++++++ src/Resource.java | 42 +++++++++ src/Smiley.java | 64 +++++++++++++ src/Storage.java | 178 ++++++++++++++++++++++++++++++++++ src/Tile.java | 199 +++++++++++++++++++++++++++++++++++++++ src/TimerDisplay.java | 83 ++++++++++++++++ 30 files changed, 1689 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 archive.bat create mode 100755 archive.sh create mode 100644 compile.bat create mode 100755 compile.sh create mode 100644 manifest.mf create mode 100644 res/410.png create mode 100644 res/420.png create mode 100644 res/430.png create mode 100644 res/432.wav create mode 100644 res/433.wav create mode 100644 res/434.wav create mode 100644 res/icon.png create mode 100644 src/BestTimesDialog.java create mode 100644 src/Board.java create mode 100644 src/CounterDisplay.java create mode 100644 src/CustomDialog.java create mode 100644 src/Digit.java create mode 100644 src/Info.java create mode 100644 src/Main.java create mode 100644 src/Menubar.java create mode 100644 src/Minesweeper.java create mode 100644 src/NewRecordDialog.java create mode 100644 src/PlaySound.java create mode 100644 src/Resource.java create mode 100644 src/Smiley.java create mode 100644 src/Storage.java create mode 100644 src/Tile.java create mode 100644 src/TimerDisplay.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f58cea --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/bin +Minesweeper.dat +Minesweeper.jar diff --git a/README.md b/README.md new file mode 100644 index 0000000..f55e823 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Requirement + +- Oracle JDK >= 1.8 +- Add JDK's `/bin` directory into environment variable `$PATH`. + +# Compilation + +Execute `compile.sh` (`compile.bat` for Windows). + +# Archive + +Execute `archive.sh` (`archive.bat` for Windows). diff --git a/archive.bat b/archive.bat new file mode 100644 index 0000000..3a3f20b --- /dev/null +++ b/archive.bat @@ -0,0 +1,8 @@ +@echo off +cd bin +jar cvfm "%~dp0Minesweeper.jar" "%~dp0manifest.mf" * +cd .. +echo. +echo I +echo. +pause diff --git a/archive.sh b/archive.sh new file mode 100755 index 0000000..6e82083 --- /dev/null +++ b/archive.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +cd bin || exit +jar cvfm ../Minesweeper.jar ../manifest.mf ./* diff --git a/compile.bat b/compile.bat new file mode 100644 index 0000000..39a8442 --- /dev/null +++ b/compile.bat @@ -0,0 +1,10 @@ +@echo off +if exist bin ( + del /Q bin +) +javac -d bin src\*.java +xcopy /Y "%~dp0res\*" "%~dp0bin" +echo. +echo I +echo. +pause diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..2983c11 --- /dev/null +++ b/compile.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +if [ -d bin ]; then rm -rf bin; fi +javac -d bin src/*.java +cp res/* bin + +echo "完成!" diff --git a/manifest.mf b/manifest.mf new file mode 100644 index 0000000..3e22e7e --- /dev/null +++ b/manifest.mf @@ -0,0 +1 @@ +Main-Class: Main diff --git a/res/410.png b/res/410.png new file mode 100644 index 0000000000000000000000000000000000000000..4a716a4b8973edea859ef80a76e387d171140b8a GIT binary patch literal 1552 zcmeAS@N?(olHy`uVBq!ia0vp^0t^g{3>?frR&Nhm4Upn2@Q5r1(jdUd&{8Q5S60HC!|U!lTh=_g!gJ~E>!@ai6UQ1F-Wb0QU~BZ_ z+^%T9cH8%}xm$AYz9~zU<7F`Ee-yIs#3peoKG_B5+RrfibTaPi{%p8)pGCiBLOjnC z_9fgB*Br7>R58ri*gA>n+OvZ%dAb}JJ8CkSmR}T_o3UeCT*+~7n{%<<4ijYR zs99;kv%)muTFJ^=VW;b&dF5su7d6Zh;O$^@;jTIPTfuGO+Xnf!OB=pc{&D}nEA*!1 U*MS200#F2dy85}Sb4q9e0PWHK82|tP literal 0 HcmV?d00001 diff --git a/res/420.png b/res/420.png new file mode 100644 index 0000000000000000000000000000000000000000..a04e84de5f6c268d4eb3fd76d421be0973a33f83 GIT binary patch literal 1366 zcmeAS@N?(olHy`uVBq!ia0vp@3=E7S9Lzx0@!38rffQ$fM`SUO1_4HfmP&CThnXS3 zC&U#f&;Z5_V5$MgYXE@*2M+uPivMT$52k=LkOc%lu~9G@0>dT*B3L+&fbv91kY6x3 zfg=&a#*;*Pr0&L!H9(~wJY5_^D(1Wmy~uZ1f#Zn#zyIyiMJ{gE$PTtLm8^cDcZI2( z!zJDOr}}?Ul?E=MgT_-I_t)sCO}J{cZ$U-+e9f@L!`=DCk}~PJ#gS7Ex|Qqg`uuPa z56ecmiWaXJ;ruJjJw7siYuD`IdNGavmA9W>wNXaV!Q#N33AKtmQg@|$n@ZT#UY(uj z@_YM_qjF~$_dP9|dvKMr(gly>H9w17zt^_drB8lyvsv44$61-2T~lZKr5)4bzbrdr z#y-zO`5)gue~`kaTvZUscGg9(d#;9QgLPod=kM}mKkLQIa~D*nhwn9FKOT8|CeQOl fMF)TB-Fw7e*rWEr|DDHsP%wGA`njxgN@xNA61uGQ literal 0 HcmV?d00001 diff --git a/res/430.png b/res/430.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c66dc048edbe46937c8b963e74ccc582848336 GIT binary patch literal 1386 zcmeAS@N?(olHy`uVBq!ia0vp^5AaNs{s{6E8gFa@N6EFb`ije^k-7&ajg!NPe2lqX7p{DQ#= z9Elh?}iMA|w z5ZwKt-Rq)ZS7x3%qgEPYpx!YL2j2G{jdJ-*7<agL^e7xyx1Ja$ivAfFjsWB z>!d56p4F}W^Xk{%iVKdsdBvX{x};~witsa@5o_2N&+hEX(qo#EaD} zS;iY-t;@D=SbnEpYTrJlFxyvhE9N~t`#0+6)vv!3t!K=6`S{4=^Dn!y`i*9~owd@) zzG=UH605*enJc1aHhPE0FIXM0%;RfX+|y@U*Cia6E;;&2((y)%wA!vyO6v;aPVz0* z{=pr$>(_*JCV`U~;{$ILf9mdKI;Vst0DXqG AzW@LL literal 0 HcmV?d00001 diff --git a/res/432.wav b/res/432.wav new file mode 100644 index 0000000000000000000000000000000000000000..b44a95ae8fba0028029adc99e828ca25b782e82f GIT binary patch literal 1360 zcmY*ZYiv_x7%mzUO_Z>>1fy|oN@jvCN>nm4P|z@tl(7xig~8amu3Ojj-qW62&*{1J za@wBLb9&jj-qx{8w{_Buk+1;%P$VG+H5zmz#7iLjG5+BniAH=+aX);THaU5}_j#Y^ z`QFpc&stlLJfqQcAM840FuUq^Xf&E_@OiyUQ~hq!JgdpML(O#(gJ;U7Va-ym%KJ-2UP+i|gwb*D5QEbJJ->U_54B=cga;*}bd2?$x@6#-_ao+s=$(!Q}MP+T|-(uWVde zEzjoCskkhOq9{pXG#uh-%wf`>>pj)crqybX9Y4|AuOG9cG#{3elbLKbGnJl5#^qQ{ zlwwM9VyZARQ_N4r!#=lZu&b^0KudFTbIZqvw5R$<9i(4O<>yMv<&~9{@=|I3{B(9Q zAxjY<=;wT19I=h*`@7nX9)WexcJvGwos^Ks&9AJkUs|t}OEcLCB^qQYk{}3@q8XOw z{eGTfC;~+smT}{Ven_X&k6ICu4M~Z~OfHwrOoA6N5)OwWQAtju(wS^#A}$7L)IK(J zw&zr5dwa);?!Ezo#Z3jIiTv#1N~Ln43~6POlE8x|48w4O^m@G{=5|`gM~8KTI{k>r zh7i7>7@y4Mr;EixHl38CAnExxlw{<141+=%U~|ZQJBkS8XeXT=?z9RLUAEc zNu*K`ngsa<162frp^y-QCtyKcHnY*7*9{B|3=SD!7Rg1FbpHIp($eBWF&&Qve6ad< ztHolqJ7E}vLDOCW$50Od!$~jAaQ>hW6=Sj@$HYj;&#ECg?KYdu;l`<|I7N}AaDerq zV9PjSFpL;Y7KaD2i%7Bp#h3)ah2UlwAG~U6=A@T`w+>f{tmbjkxY=TNp&A zLZJYgBS&~IhB#~%v)OF1IS~{GEiA_aIF4m}G)3aLnkeN{6^0{WAr#;k8iGbqh?-P` zi@+*LQd9`AG>N)Fwbg2~0~bki0YQ|Ncp@HGVz4&QNfF@M?Ljd$1s}rz6-nR#bp*>p z2;e53NI(M+azKc*MyhoHsDnFEFA1O$0jgX;2GRIcz#hYRkPab$_Udt% e#;__NH@aGUqE0o+LMx}181)bF33c@sp8f^Z{F!0^ literal 0 HcmV?d00001 diff --git a/res/433.wav b/res/433.wav new file mode 100644 index 0000000000000000000000000000000000000000..9cd1e9c41e8a0a3c30159ee9ad8ade908a34c857 GIT binary patch literal 37960 zcmY(q2b3h~aUM7lPof09M^YpJk^s0c3#>P@J3BkRy?52+z4yMdyvy=g-h1y|cUOCF zW_r5E&(7>D)?%>$77G%99*l6*;f^{T@8%MqPVe;BE0dXjRb~E>5%ERD7pTdxv4P~7 zGx$N=C{L>X)?b`CbLL;ckMH2l{PFp(&iuPG9HyH24S0_2e;(F<8J0f|@c%#HJ@7Gj zw%u-b{L8T0;Z1laeCU77{FiV3aqb^}>c9Uw{GI=A*g(i=HaYYxu??63ta z9%s<%_WB)xV89=Y`2)eY)9-TYZF;jruaFBABC$Xw<4fdHof;L5}ru~KVNnQicCxGgrj-{f)l%#h8ab689og9ebvHC(w^&Qb^g zj#>r?^$NAZXwc~4qjs}H@3unvAm{@97Kg=a0bNd;4L%op6!Lr0uBbobj)yYtWIP^- z$HT!$$`cMnZ4oGJ4!L}$umiG&TyAF=vip4=dkFG?5vvmn8XYE&+N8J2bvm^a(8{DT zgHWk32=o9b0`+FV3EE6vm(}KV=pCR5u&6aW17E_{Fhv{{Qz%k#WJ*A)Fem|yO>WRT zWHy6K0fA1X2efJ3Ro6H`a(Pq==?Rt&IsnDpcd>vrs7!?MVS*B)NMM^#>kc&+`g;Fn28FYZbsW;hu zIu8^!#@tb3+8wqOTp@eT7JyQq&l56vd~Og5+8n+J7z`#X>0ruU48>hlZ`56~g`uo5 zGdGrsy6bRfR5)8>I814R%EB@#72rire#}I8mU{SGX~6{*Kc>k{T^@L z9SoNo=~&fONtRsAc;4L!WIRnM?kij3{){2+gRjU7fe{yI_uF+I2dMHJjcPw&)cA#< z&Lf0OZgI#20co?>ShPeu6)+jfn&Q5IHfV?M7_~&Mm#~#`K10VBaLg>J$U;-e%v6)y zNU@8x42ZAdxL8Voji!|8sTzfnY1AmhcB9hlvl#*bmo?+{+6rcmB`LQXyljiYfH&|Y z7%h#B*AUrsElD8O(&ZX8-vBBVcB|6lvMb$AyDDt4s$*KKE(+g-VX@Z|kVNf4b>0yI ztM;&`YK@1AmSiGf%Ow2HOwi#@K&F7tu1nY)#;nm}&8tF=l04%~$+K>+DdyL@-By*= zBQxq;1P9NFa*Gr^qlRq+JcO9cOUEEL?CMm1SqEi~#ozRlR4 zbu&;k*R27U*CF$%L2is~mnS7A$f32StTsnZXH7y5T~!;B^_VefgBsRGs9rOuvien^ z7t*?eW}h`DNvflqw8AHd$W=z8iVNSvL>G}mQKCp3J_f6yvN;xx5VQcYsLUxU@;&k_ zJ)n#T+#slQfC`h|BrzFzTA6|B61XTSo}C{Tnp9qe$SYT~1AMvIOW`TS41$3~!E0uz zbP1VZ7ir{4QPR+rS3Ffq-5>L1)2>X^V^4-aw;Q4-#12f7VWyWjc6-Slu9QRZ-9#?4 z7E5$1k-&mGY42#F2^2 zCRsm667pyik4ERnS>2g*%-yvo9Tj!h6qR`F3cV6m1*U$?gkg^>(0GcTMYF=jHW}20 zvr%OW%8J%331CGX(KS`JfM0F!=``A~8jN~_kxs0WISA~R)+6iXQnFRF)O|Ts)#;WN z)JnBoOwlOlSRIclw42!(cTBqq)l7$uQgGE>NR@rjipS^ms#PW-iy;|gOt3Goa6FVl zDb>27va~-TEIYh{3@Fq4wLHC1gf&Q!6e{fkc?|cebX+p+?g;eq-4B@q*VZv)9f@;)dv`PvwyS)-MCF6cgFs5)geC(jeJ?|mO5bA0A zJbQ*D<14_ZD^^-a*7u8z=3cl~T-8@|SwlRfQ#;&vtx!8IVpB%t0)ZR~8se2gc40Z+ zYA(Ci{S6Der23-73feegC2gL_?H|KqM`v|ZmMWtNgqBRnR@t6u`nLQZMGtRLsT# zs09*2xzIJwV+y87Y$BQq(Co&Hy_&D2*Gjo&Ipr()KrjTGBm*A{60ozt)#-lrEB)j1 zuOiqCG~ku%<0*%?9C7-pYM&)8_UIwHLoVeixI`YCgchNRBsq(3ajI=)C>Uxx-HD9G zk^mKo1Vb#bBX}J70Fg0$bsp2#kHn1K=bS;&P@fDzlr% z*8^mtfr#hXcq(t%5!|fh>!;Ob`#4goFZr_dv?G-N2s!^7*v?afwXwG{D|V=8MzL(v1ISuuSSDWJ_uK$RpJg+kR_5WbLL zC!32kqRB+T8T4BKorXac5=L?Ou@M4qmZ>+=9DX}I-JnfF3Vj&lxV;Lo&B)^Dgh&n# zH%Y`z&M^oKnOG zx|l$~Ee{pKzIr_xZN@{%LNJi@cpQF%+h|pq*;0-G%NH=QG9iiW(n(?9XlZ4g{jAIP-#8Z0#u1LGV#@TBeog;gU5)p z@~TSE&y3rNB9(GjqC^sfW}GUjwL3fdU?mc=t=J-wOu&^0I6|rzd|n`*#H6ssX`Cqv zLxokwBwlC(D735Y>Osc8Tglt^1MXPP!;h=@Tse1~Lz+S&c_R{rQlSi)v-W%@9!oW2 zk=0b$yWCKAlVu99JTMArcLXVo=rd5F@~cAe~2EG(g^%PalmbyoLl0Qi^bN)gY3F z8yFQ&PB8?W`LNnxh{x3RSlPSS$X0r}W?UfgGdMtq zqRG9qfHG%J=9TqCM^#)e_zJa}X#tFxsxp$xAQ})8DuDDiVARC2nLMMqdCY_q$jG<;U#1YUKnrlEwdnr_opITOm?*>ZE&0;i_jm4B6 z*amPFB7>Z45vM3VsBTWBTj5*YRr@FDV(xGisxC%hC@ge4xg@f4YMea3q;1Zx zmR-qIO;!|E$bN#3AtF(y%mmG_U85D4b8vL&_Bk2~XQph?B&uwiC_V1R3r9u7;gK(D?~i$v~TWRhvG$@xSKUW(M{1yWN70CTHh zUw0$6p1I+F&}d{97QB|CJIJ?4C2}->M#jPLuwk-NkaXB|3$Bjw(6CnO1`0bZYb{fg zg&>7WCBxILFQbV@ z?XwO>n4u1(4d&dUw(Q%qb+QH5TA)l{27*|hN=1>u=1xDU78o_cKs*p~?nhQ5N8Pp6 zgX&KAzJGbC7qPWNc8y&xGDzkGbloshFB3342H4$)VdIbvb(;<6p>I!Jccqjju8J%h zBJ_&~uMK18`}(z`z^sdCQG}=-M~zW(tSO^uuQy^PqO#-7U3FEqjcHq>z+}N!}^0`=0a3b8WEed>NbR$NE=K@dRfBOq1W0ufA)h~k<8v>}ld-deSs@K)k}v}DfFW!rXr3QwMI;n^Q9=XO2CkEZCa}%ri_#WsZ^z&Z8kHxd@^cr zh1edQLMT?rC`h%0r6K!eUY`k;WU-T9Jj~zdbPo%MnS8Y5bU7_{fy*y7^IUSi$f*!P zJiXZy*9Md6T%;Z?hgV#IkjbQCo5)jS@*H-GJ2o>qk0H#=(k4|hx)RVrA~zVY)jVNu zv?S0t0XB(yc`Qqv=V_-Z`XkSKtPy+$T6c|5+&WQaz* zwbXWMVR?Nsw_aXyuNWOsi$NhZak(rbk|hSjL^q)IT9fWbxt5KcLN{Sa)@vER-{aFu zggT6nju4|@;4(^PQus`Xog0zmm9ca&R9*3|HuITays9!;d^EF2!xU@DG6~-(H0z_P zZq9y?JSv{Hk2iJ>_SSl>jby`P&g+zb9j{@s`Dl)iDx|n@5a1SjTIyP;*~nHmi}7~P zU2L=lH77OrzCg$v(389Ib^4P-3rAOJ?2ij9Uk&cwvkX2h6CrLsAyrB~~!QE_22h z$aeGHdcA%-aGHpOTR|@%vvQ17!&RD`$em-&=yghRZgf|`Y}oI2 zGnhKOnuzPC3vg({um)kLbA^!G8!xMxw@W*b`{9owyY-}H-7gLS22PPl)agiezKUy* z1%eX0KUgb;>+yF|58F%Y)jN%vtf@qO(n6H|~3zQ5IXCm$a1xYZGKU5wj)}Cx0 z7f%}3yJce(Mu~DISs^x~kZdi^Nnr6Iy&>q;ErqJP-o@Ixj@_jwwC(~dG8$bnj=VIE zo9-JP9lL@j4^5B=AV;F6mmM{Bx@cWadZjt7&!QaAiP=ozBwfLuan0ZyT0cHQDF&8} zxm@(1x|-iyURqp%vS2gJ)PV%Pj5#yI9gxfsuL`Gy5&~7{N7gKmY&D%|mkq6S0nR3? z^#Fr0K4==jzlIv7Ake5QLXK`0qH2AOka{V;ayt=PuH;LbG;c5{3Qq_KRtkbYASX+a zrWvZurG+!u`CPT)+Fx$0bhlN#g`hsFmiR-#l&-=;YI(`K z(LLzJlc93TFO^G-Mv>`FJ28Y3;SfH%P!blF^S)TI9C&{xx_Eu7`mkkME)=YJik})5 z$Vk%=(l`mCrF@^jA+?60tunB=(q3Aw+3!Vaz9`e1kO(Q@g*=^%QDQlM1zT(iH?79t z;=*EU+4k|;t^86oUtes{Od&7q5&JECCqYLc+g)s#f|*RH=f9=nysVb=z3L9liIov*MSmU0 zHj72ieoz;vi-m$5jVKe%&U$SZ`wdvw3k}VMyiq*_bS)c)Eo1bZa{dTTkheoTl};d_ zNeFnF9f`e~qDWW@J~bN(lDDkR+GjP%*144xZyu8@w z$ES%5vY(+%si~ZeXx$R_F5J5fM|t4*K!6YR_G&qJYN6j_4)}wOCy$Ro$)=t9i z1SQG%JcsN8X+h$AMqu`8rRJpH72_=}6y30*US(urh{hB1U2Mb9{7+n9Nh4gDeYUA)B{F z3&lIjc2Qd$tqDnZ1;`@^$jYl?GMyk-3{QJ7ESu0ew{Rt1Z@%!!hvNmp9r*;!63R*xFLINdB2?^T+O5Gw%s)LMa3Y_yPN zgoH>cLy7sTk||FHN|`sJi}lEUd^z6D7@(LWDGjROs+q%;#R{~53btKvRVV;iimYm6 z@49hyd9U2^IRYE{pim`J#Bp4#no6bhsm2jR0&en(OQRY^cm>O5NCG5cDlc6Gu;t?l zjEX-66681tuCB^yV$jd#JDCk-!q{%Rv&nWgoJi~PT(j72BdO7RX4FGM@wA|l1dz-W zSUDZKfGZ0@#a61Lb%|>Uo(}nkBJD60FJh4AXR#qH?=rxlDJ6D>T<0t`z>H@(8>rgK zM!kgsm$UdJwuob%2WU1NQpI%$%p|fuYym8bkybUf6gf-;>oQ21^>R2|9>np}IAmFr z#h!)CS|(i+NF}u9d}SlQ-t~4eH+}AmRpa%zkdC;>Lyu!1PedYeL1vB1o^gl4_WssV z_~y!Kxwcc!q!K>6V@(~Q*PQ-L2$EUCHf2_><#q}Zw{AVM8}}4ePqS%TDH{N)6hLTm zjk@t5O9tZ98l7CPSL3psv{<>)SPL#UYPGdgsakW2GE^JIt-?B3au!!>GYj!bp~}J2 z$>AJ_uO7FiQcK~8y6ulKi6TOXq`f*q8j;cm2a#6PIToFS6RD=HEQPaawYf^`jkaMi z+}7BPlz>i-p-9Pc0E?yT^g~7&pTn>SLV69iS15-zJINEzVtEhn_+@&ol|+^Bu~Z^n zqhVj3CrM>qQhCQSfDA-6jH@Po56Ot#RfY9sRQuBd4)*No{$l|BKfG)U>A8p znxegxYE^obWFrch-JsSYU@}ZHITv7nicy74Gi~6gfTTfa^KFKjsqW&!W+5Kf3@ZXo zhs>)sP~>b602+`yVV=k22I#S%#unJE?uJtbn99+yo``?3 zdvFX_c-}d%K;}dtB-2Y(yfoDyW8n3kX*wss5ZP6Jbt<_L^DXsyYi(=(5Yi}u7893< zP}3=FE^UlIh((iT805=yI4;Pe35#||WIq=#1cE6KLzVZF*>lPOn}IP83#IZ2jEun$ zkJCjRAtZ_?s?o)xc)n0+R)b<|+pHGD&N4JEHz|=S_lg-P1`EeRjw{9FK@5G4B2&CX5dc0PQ@s^Tc53O>y^x_8bi?3H3b5G`n}lS+ zOT<_KV4~6yBn2_yRN`!F*^qrB9l4b>`-^;4%g7S4jW$1%CDRjSG0p@ixR#~jNy_U>2M5(w5?FtA< z46THx;CL)tqyRFC6-bjXVYRCY#Y*FPu->^DDrnSTKrzfW(T6DL5f<-J~3PB@)n5IQV7%~e(5zR~zW`{3OS!c;}I5NaU#_P7qO3t;t zR8Lou%v?)5s4jqf%Ak!0;&~FTV%Q&I8FU_Rsu;h!ciOu1gXYHZFA`hpv4s=AH-4O3 zkNINFy@0A)4^~#o!H1pF#>wHW8zx40ME`Q_NGk^2i^mE_*+bhF;XZpT7LZ^IX zSWMJA6|-oAiZL_5e918J)nUxQ+dS%3=I{(C5x)@0@^Of{ueFThV`e3^(KW7lKK*TH zbp^_N{OUD>1=Ql-5#kF=)D=Uhti?NMEX?)KpN%#o? zxn4J=XOejifNGBpZ}|C-#v5Yn}71Zz)YwAG5*6JKmF;MGhcf3 zdtZHZkp4VdNT=GUbBe+&Bmn~s6-+nESoI5ATG73=IPVhc(aEQYl^g%*7yr-Gr`?Y} zc>468@9q8m_F+Bx`Dajl(RbkRwoY{cvzP1U;MqPE^>ufg4c@U!oSxe6AKdf0Z$COZ z-Smh8=>u;Y6NuVo0ujZH91RivGPbFtC!pnmL}_LUq9_-Znv}T z@85J6j`NQ?5$nqK&PjW(wt4HuR&@XHy&GG-I|sje|JOG^i#&b$^q)TX^bme~@1M4B zKYjZCQlk3a-~aYw&&Q3`%F_Qf< zUq*8$&z$)Wbi}Lh>VNsq{wRWf5yY8)3vav#Q_ue5OMm+3fAiJv{F|?wx%AiYuD|&9 zGyndt&iutQ&wlC5H{bl)Yk&8xFTXkUwKHGEzc{BE?c;h4&Qx^$^dAnk-}&(7-lre` z{PfZ0um9`KjrVUo{rvZLe)p4K|MNfo?#Yv<|J&0qe)X%TPk;a4;FJHK#z*khZ=OE= zFTeSRU;p1vpH}yN``-8OJ?)&PfB36f%YAcoBav?UV-VNx%ec145I^BDfuql&Wz-8- zFaG(NzZ@Jq`&Vbqy!67C{&*b&|N0MauYT#z&z!mR^?uHk3zKJ&GR2!OJu~(7?|kXY zUpsT=yZ`Yopa1hS-~8)8JNK8&um8=Pv=^Vpyne;aP)&!G=BA*q7Q0>FeEcBOx$8`~ zjb(E&1Ez24u2A|Br|LvFifB(VigSC4< zUN6`84v&}X!FatazgZ!CO0UueWgG5-cWCrd9T|Ev@5e zvDc=0nlGa-Ki{Vu?tAv)+VVSkcrZdUAYJ^sNi{ z*CwzRFaFuJOXsg$`p(tMGg1c=OEZ7k_WC82qpcj|a)h=vtNOgJ=JdABESV~hG158u z{G!=!_Q(pgqN%ajD;+KUc=PV##wS1c8MLV=iwvat@YWG3q~5V zpS4%kx~oUAmA#52?`_1b3a&}1kW*1y28K%?#tu_w`;ZLkrFpf?X`l|v^kyez@+yw% z;D7zaw??Sa(V@4$e3>_T{x80CW(aro%jduSmsj4rc>cRzo0uBEc$LILT*Xe3sKjUA zBJ_QOe)hYUE?=3xaCPd))IT~E%hqS+(yZ>7InK@{`ztvwAx$WK0ey2-}~WaJzePD*tBYOerFgU$yF@7 zjE9<^6JQ8@{3LP=LEv5-=d$ry0Wo5g7;K?*HSN>cVAh33#*qYMIJs;FK}5(DaGDm! zP$?N>V|0z4ryLchTgd?Qz?TJ42s zG^OD?lC5qzQA#~Ns&#L5^4IrvmebDk=29U5z+x}^3_O`V&!f}j`^+nEzI^t(ul~n>{nGh!Q^;4& zDG(SAW{xCaiBTv_9~w1-x_0S%_%ZU-SN`M$=EaHUp8fI+_Ud=O{?~8!VP;-CizTbg zYKz5CI4-9W)#m2vif_GF&4sg-Lemy)1e*~lRBs2{*@&ysOD-++I(L8m;p3k_z46Om z{r*3H^24A0rw@Pr?ycMRcNahW*=`}$-8tA?(Pg`E0>z~b-Dit2%w(7F4StV6 zh(>Fibi@puL6!Goh6vLa2j&J*m^elRdi}}=M&EzgN8l_l!<;Lb}aB+KQ>-estu(EN#lhrC)cebhq znJ(W8It1LXCp*xAjxp49M zzq#=CSH5-e>e%4-zCB1rQr;LvVY#HUbEIL!_PO^voD^-%+FkW^_iDuCSU(I zUwHvVdGVPu=aHz3W8*KQb@OZ$g-SKSv@54Y6|VU^<$$W%bQK-eu)o|X2HQpN%|kIb zalU&<&jjrnMJnR-XRYxK-@?{vrruj`Z#5PRYfHh!JKKqsjIFx1)>Gu40L}*$WeMg!!?- zv6lt}l#5rN`x2UY`Fq#C^Ua~j=g(dmI6vKg>B5-!a{nj+!^08gP*N&-DyWcZHCk%Y z4uWQtCD#k;Q;kHg6%B1gb5Az2mbHT)zS9n;Km6T;+WwQ1U;p&R&F}x_!O8v8>$m^+ z|Gc&J!L4_H`G2k)J$&%^!KbI4`=8z0Zyr=muJ7fVdpGx&?rt1DI>_%`KX~%6>)5;Z z{z@^J+E|Wi%n2Ja0#NA+xjLa68It%M^r?$9RT6P-1ScV>F~ifKXpYI6=J=&}k{Cq; zi6b*S%E-k0#c4F{)xM#=t5f5zOij%oWhBfv*`%NnrQx=RB97nQ@I;-NrGun$G2aLs z#>}O?()Lct3_Uqs2*yI?$DhD);FFW<*Q>GeXYce@VMl-cM!FK~cC*=1-np5yS-ZKc zMrlrZ)e^PIqT^V+3I0Rr;U`M)j@wEuaKA5vk@y4J?xmxortrux*Vz$O80({P1IM4I|tp3$inLGesiha zXfExoE+4F|u2x{{-1BZV@0gaYj#h~sNn?l2iA^=l1oU>Ff_*ig@(7aB}` zXJLm$#tm~u`zNrYSD17CS6{t+W$wbop})H}JVqS9bmkJz*2v_G1AO$@H7Wr$L1K*#PN+OKauYj5w?qc1+YzWn|VPk->i z;m%Kf`Lka%;}4$xxZ7F1`^)Q3mJS}aHs61*x_xW$tX(gD#w^n+VFi$xuvLF6N7g zTCZE#ybX&b@}qmn;{C1a(Vg4-OQnP3TPy2ZkLvB6dM#B?Y&IOl#Zao9@}*LqTG;F} z`;!8_ktvi2jVbaK6ilO*Uh12nkes9!U+kwjh#2JH#59wvJ@>tF_U!b~-@e>;b_6qg z?(855F>-!>aD1SzZ{XasV~Fz;gzph2`UVMu*QSsJ!gJF^M1LQ0l!=<6(oxgXmkG4~ z$@#%47L$YFqqR&9oK(!vNRC>um{fPtx!tw8HM?;AaAj$+-q^o=>rN8by?5{Z8;gra zAN}Unx0dhR_{A?jc>nR^&Ch@O+fO(4Kl|v5&+l)4{L3fr-aK4*@ZpWyt@g>@&Qay& zeyV%-)5cP~vA@?UueNGi+wHEmwNUlMBHlP(2`0>Z0)Yh=OEsuDo!KN2;yGvnh9Qt% zot$IQ$)xjh^SF5t=E}&(JPSpbx%$!|nKJ)3fBGhpF>v9pUKkmk;S5~DlcaJ!nxcdo zF4P>HG!pmnOx$trVf*5ljnzq8h9ZM}DLyw)i{zVqayx3+X| zZ|AVr&i0npyQzq~u;U9xGl_^Fbh_g~tCXNL7CAh@*@PiIyOSi8t#N3IMjqY|yQ`~%zuf@YqY9ruu!!-&& zn`>8LMJk0{OGeJ3=u$O-IEo+}^cdEdT&G|XQ6uvt7I%E?THn>_$>D+V{+FMh8hGWx z;9Jj-SvU-(f5u@jvLqCO(rFN51onVh!=dP0{*;QN$mQw@oh!OkDdgk%=FZ(myK9S^ z$2UK?w+6r7xqr7-Z69nMUQfiMmG!Odg_Nzn)M}MMm$$r74XL1*Bb)#Q0wSKQ;4vxq ziAfrVH9a;p!=xb)_$xy&y%y6yMwq}(^bes?B=WVlE>H;LSI)iBfAy8uzWLnS!)MQq z3=G2V0Lhb*M#m8Zj$-=a)zK-oV&=-F3AV<9dG6UsnvlU7eqmB1A&`eiR;^H=6|f0P zyIyPY>V=M6z0eHD@~f*2m^T{hTwg7gbJ^ab>pMrg_a8iY(AfIozdpG4VEu#N{^O&Q zdyn7$#ZQhOJpTBHAD--OJpSS1`ugJ^Kl$XzO5ynQXLol>`I8^~uvZ9Y58rubNykZ6 z+6yVUG1T&9!Ulb+6b-}zIjdf2^;_(KUJsM@ofIOA%GFFi_u^agNYuoOuOnf8(ZCyM zHXxqAGy+&@BmEbK`CP=gbK^tPW3w;4JU2bnKifA*qFopmnv{SH5?5jhRy`b%KGyEa zCD!oaQp0Sj_O^OmH?*+5T5mNo&C_mT;r@-yM~{{k|KZ`z&VFO-(8(V>4F=2T%&qn?v}~F%e;SN@Zej zhy!zp03AO*&$b7#ufN2zIl<8>G!S?48M7q0!>i#*?U8ypTU_0|zOcHt*gd(q+uAxg zy0=@59zQOcWI^5s;%@+S4|3NxfSsN%0xT}K^h563jmA~DqUrea-{?c zQqM-pEMz7_Mx&BRR|Z5Zjs%aIrjhB`$x##?Pn&*Y9)*5u265q=vqH+i^yPV>06k3= zu&D;;?39QrHvvqh+D4x@OW6`DpQ7_QYtzk*_YVu3ld*_Z}Wq*L!)mFQH!S zEPGwml($+hMl$}|!g1Lg-(Bl$HzVOxs8-1t1-h8qCXx%30v2{^0!Nvhn!Wh;=#}ZLv=U=+U;LN`K#_N+fn4 ${UD&vOa&ND5XZz;oPj*|or|*67^Y?aFKKh5x-dV{vAAR(&Oaq2G9{l z`Uy@41|!B|#3~7w#?x9r_gaXkkQ;MRSE_NI-+-ZB-K~V+^y3 zfyOfwLOdCLxo;jdNx1aJ_$&h3e|e0eqTx^st(-K09-pV+&%H5?hb2K1FmWsi2Y}hG z>Z$(m;d$ERFmHBFLg6c=Sggz>l*xn~qgu*E5t#-RKou&DfS4=PDK&D?;E9-_4xBjH zDy?nQ3XPj5yO~mV_0~Z-uyvT}ttYar`oem5f2nf&z1Hf7+t)w-;PjIZ)^2`&|N6o0 z$M3A(y|K5~i542!Qau4h@`<`v8(XL(+P?Be9R@aWZ@?EZM4~XevtW-oxIC{CB?bj_ z? z0<92>QtQ-KF;6BkhHYw>$(;pt?wCDlQ!7&rwFj*l?rgUb?M5=+j24>N+(ylv$+nkUA(&*Hj@U&4IZH;zlkq$$qMty=&=n*k8r{#8 zATFWkEG&{n;G4-Lv4Frgk&$RVO3ELB`(wuEXUEZKI)3oNYa=|yrB|+uOiSz}1b~#p z3^Qbl$!XHh5G8E6QAwHRo0t>4IRtxnjIWs*Bnw4Up~{+3$c=@()1S|zHhbPoHM($6 z;G46FY|R5k?E#qi74a93cXn>9Z0|n4dFNJVVnWGfUFpkhS!y*h$A?bZ%bS9I6rSkzSlcQ(J6auA+f@gE* z$prj7i8?b+$Ih`7Oe9k;(pbJ zh5eJ`)x~0~ym4zU*IFy@?d>i!dQ08g_crRi?$Yw+R(Wl$+S^%Q*JTDdr^@KqrpTH!|P0W(e!%PuthQ=Y1)JB!fPS!dz zc86A_w5Pm)MCO9hPJuj9t(er-sJ&26xh(!OpAZ_EJ6=PA+eBGtuhO zYImhpDmTMctIHMlDJV3hQwM0tREy85HOhoei$==h!|lpy4uivB&eJ)UOuoq}os-BcCL?AFPZLn42F7O)$m!9c0Thu;VK50gEqR&@ zD*zV{Q&21x6}=1Y@xw-6;WnjDhJu{prRrQ_xh;-Fs(=w)C? zZ!&6i8j)5ilxk_yQz!-zGdy-_f;2mh!3-fdMgbW;OV`Q)4qmKM8x3-^2{Q04dACuo zR>+KAtI@2L!pvNg7O)jF37gDUsbr#FS8DTmAsx%MclWv>e=)tdocB0Vy{%%x>q{15 zP&#KfX#5GA)gc!+-C@WH@})4T6)xP)A&n+F3OPoR3T8*?3$91yW=|~bHt5x+%3@rO<9bUD3w8o-anvHmF+{*fzBYoM zWebplaC|MIQc)C(g*G_Dbws7}SBWNznoXVje>;26CP}jEO!If_U)WD;J3}r>kO0`- z)uKd}$V#0VT5BylwANZ=L}X^9)}mxrO8_LWAb}xgcFe~1!_KeS=Xh3w;0jx_^{$Ro z5$@OTQSW)rxz}IBXp1*%%{j}tgYCg6>u=9T`9w53 zx;v~YrRnkcVYPVt;qBeDzWeLnzS+-|Di=RqkHe1K;hy3!I+SMI^2ibQTeVx7NZGe# zaQo9)zsnv=#BrjJ-Niy?{j;Ah8jNdC$b5htj~;xsYBX$V*DbLiAd-JQWbODD&zqX#J1e}}J{EUucLs|*DJ?qa_HF_BO zNZ9W1*!}%(iuLxH*2yqiIXbxe?$ycRt6#l;_x>n9xwv|D)GCgz-d|3-hexN^r{nqM z;oEnI=Rf}XpT2v4`{7r=`)~j9$IGkV{o(7o)1z14e7!$v?{rJOdcM@}=9}GO=U`N* zmnVnw?LxLT+a0!J!B8yjc1NN#ygPygqOd#UWtDp+>9;uo{4U%f^x@k2n${AC+pO+byPODQqPb2ct>iQLQZ~va5}6?D?3HfDmGD?w zlZ+=8txvmUeDLns;cWZn?C!gZ>$BaRJ_7+DP5DZrm_LJZn!Lt(cczZajXj z4H#B5POT$meqpmM8lBb+Exie5kA;|TbC|Zi{Os}PPb^z6t(vu9juV+pdacQuh;1%< zYr}#s<4X+oyw0Ro=@xZ{OtsX_yS(k=BNo8+cmLt{CkIF8|LgzppI+Tw0hxYx`|6*5 z`0mFyd#5|Iy`%l3-5xOU@~VIFn}0Yuef9e8w;yhQe0TKroA2Kb$2V6y`-4(i28D)JJVgk6E0jXuep} zKY8JGuV_}Eo4v**gT}CCbeUGxSD$a{RzF{j=%3iEi>zDOaOXm)-ZU2LZMQn~5e=`$ zN^RScn&wT>QY_a<*u&jneY?t{)|*!sxBJKc{J(wJIX}Jo_HuXk_2FbPrvbg0k2oz3 zM>xE?mGEf%p)HHowc*J7*6miek_q{|vdq%HvScwXEG#aryR6R_HrBWN_UC``>9WnW zwy|N#MlG&FbUj^DEMd>8$NBk#jm^&=u0DJG>64d_H#J{8GDmG%y&;^5**BWaM2zOi zQa)t&I1M_db7{%6`p^{Hcxkn6CK4O#v23a~?v@*;H@6?AgWKPIySF`?Zy#UvhqKA- z?yTFKUA+Bpd(=Pw{@umh?|wVK{qXf4|I5wJKmF^w_uu~N_3K|?qc>}xE@;tox6Ksv(CMtxTTG^~mAzG*OP_7HR-P?B_~r8Ei{;0U zK3}pqHgI)%f62SH>5HX(0RUwwUG00fV$DLx%sOR7$)$?Ta(B{hkE`XQ!`W_o=lbq! zHof@q`>TuV^Xu2&zPmYmb@~3sSChS)!^>~pPG=Wax8L7gfB)k@{_fZR`Cq>I?#H)p zuipLecHHdEPY!C?a=td1rIO`pYtY{<$CS$6+k;eYayZ$awaPtKwPrjfZ>E@t1L{-R zkYz*fbi3`3o^HHYHydAS*Nr}-W_4-PwDx%6!6(lazxs>+@V5^ZmKPs?_0knntQu>z z8cye%{dkyF(!F|ayI1cw*$ReEW2IC``si0JCmqp}QtA!cweEEL?BZrNIzPQQJ+5_k z=F?88mMhe&*-SbdNTk8aR;S$>a&H+evAWL`Z&nKID^jn;Jr=V+6^R<0@usz0r|KB@!WfCLfPRoOXlJZqe(XFY0tFPnRCA>0W;RWO;FYb8GF{hR1C)nyeng z<4Xo@7GK1vH*GFi%&SXFTL$B^=c{_-)|Sibv$Ls5HWp77GreA~TkX_xEov>@a%spy zkZNK3{OI^_R-YeT+`hiry}W+&?RP(1Uf=%u55InMa1PmVJl&q39v>0l%hO;q#o@}R@!KZ8lP zS1;Cw+l{Q<<%|S%&mVmGa%u75SD$?H_kaD#<0n7=pMLRp;n~v%U#u*xKU>?fYF9RG zdXvwfbF<|~Eb0#{sa!f0O@)+{%M+>eSa(*aPI~=jr9BypaXYpbJ1#XRtwN?boQ}ui&Y)K<2fcQSFBq^GmN(5lzk_WhB9Txq7EY#;g={KQ%q8-< zRJxdO*o+#3-SB+NWjBXBCZi1tvFU9Vt96TEnax&qdI{MrTAg8i;px+tPo8}FXlZ?Q z^~J)fd1+arf4Sk+ZW*mh?qrzM(qi+F?OKCjo55jq#FR|J?+XEYBhe(AA9dP|0=)po zhkHAxESuPyoZgl?dNI#W|dmO23CXtNg>#aO~ zCK`^%SyQfK4+Xn<^(j_vFu!>C@X;3!7a#uBfBgLM(`V~X|K>BTc163gu&mV?Jps4I zTOZWRxp=TK9hb{~Yoy*xu^m)6-vz1_ip_2{Q)+Zu^-i@z3)f_KcYi*gHS_s$&hLpS z;aJq;$@IIWL_E>!=RHTT7sEk+!aXY!hWyap9ag5{}I+o!zwZ z$=@vMHH$Ak|K+0P<%^fAT5BNSvDzH5Qbln(Qq@egoMt10Qj2jVORV&(*NfFgr7{|n zE6pbB{f-aL4^H2H{q?uM`Qg_eUjOz#{mZ+(o3FolcQdVwF0QZ6FZTAYuCGpy_KvS^ zUQs%G{pRhfSMT23zPp<2-1S)>o-6P6lS;jiD5o9PP^nc&_#Bnjcasr((6=9YxmvH) zYs5Wzt3~57Eq(E1W#P%vlfV1L!%zP1(`U~={o9}Y^@BD2(iabweTDSaR}Zx=kLKBy z&cF&3XD}Mf))aR@Q6k=8AgC0gsd~B88P$s@d#{&Em+Fmvv)b&=cG|^Eu{+3zf^0>W zD@4=va$`_!4SO~Ex_jA}&+YU^JPx-*XUila0Uhoq84d-MVuz8r6V*bkly7x&rB=$r zUQn)p%i;<-v}S7L8lzqpif-r}gcqk_-4^!w!ZwTE==7LqoZd7TSD&wI9s0Gk7Y|KA z-LvJVkEj8B`fO`c=MU)Cy|H98V0dZC_*c!A4NE%Z46-^fRjL-_nNpF4DbOHBf^YN(D$QNpzUZ4DHdpH=jl~lcyD(95SXj-SoHK?Q#9uK>8 z#G^hNL`M*|AAhv+<-_I0U;O1?J@{f_;fufg>xWAV3r~Ok9~LwlTl$5sw3%{Ni8|w* z$*_^Duq#{19qYBSDJ7aJH;VCCmO@q~ozB*pMYc^DOsDO9WjNjLH`2*wJLQjfL)A_> zp%ki(UOVOvvvFKD;#LY7UpyO06yt$JxmiUVZbv|gI1F2^Y&nx<^P1jvCy#AZ)3Jyj z5T3}eCqg==L~Rc1%A@6#=UT&y#}B`FVbU!=eqwYQSJrh-FYAGx*>?@yr z^1`_F_ZsPP6HUrU6lt;5TfaN(52y2U zV(!i5+3W9rc>m$;yFdK*-@m^50b=mYPIELrnD5eBaecEpnM@9@uXkrVr`PW;j(5(# z|M9!q%U3`C@ZrPlv_IPEw~Nt8s*s15N~W_>4=}1+@8p%%sFjXq%8kyTT`6Tt#ZpAC zw{ET)UOsyA_{-;?{^j5P{K1nifBrY0K3xUjE^g>7-pxmkH_V}saYN&dry>!TTS+T^ zx6#0Qaj!oZFXyA-QnyVL)b!x`;^g|c)|d^*G-H`UBjHHo{o#sYrwJ++w`!cRbTOCC z#+!#bt$L|g?>4hRPcT_2CmhaHqua?jgQPHFugTz5B36gZljt;piAte0D+H8MJ{1c2 zojxU%iaKqfl+S1~+YDB{d1Faq(r*C3gRHKlB`;*#eDP#aV{^Uu{OQuNVg2!=rIi)! z+E+hcG?@*X%gbBAOe7HXCGZXrpEp~~1bm)My{IT*C7VwxiEt7ul&!SJlj(SR_WsSq z)z$UeHOrx>HFJ*ozY-^ zyuZJ@-5;IZO&g8D!P#_FD|V*cVm1rZt>=e(l=t`Fge9 z&PM9vB0CPo%e8X7)vc6zlUgpDOczSASU#T=PhYQ-d=96>Y9^UahY}f|k=#2M^s>cW zDVr|jKm;jPk0`}_A{b+dTA|!5=UZ(;i^rcxdIPbTFHuQ^N(Chz2}R;5uh|o#FT&#t zD#>s%X4u3@nN~mfVtM81(?@8(!?CsQ2zfjnht}kG*=)KEz1?Qm(r-Omv#mdR^!%%* ztE&r3R;$@=*1MH}ClC#$8}$+^e@O{u^Vw*yd(ba5XN_Wuy*tq1VYATO-kl8^qr;=K zi{rzKyRU!s58r(EyZ`dP|JOhK>btMszd2={|BShB59h=Fe9|5t?wwpr;OCCV(^0j5 z`Tq1^_u%;YcCX**Rg2w%C!Eh!n%RI-t41SnC8QLoh*WZSh+qL4`^LspB+sNHz_ z$tMfTU;XmupZxt-i=Y3;pD#Us^zzvkOJ>c6(PMVRve|SZs#Hg$INlkt`<p$wp%7d@3A?_&mX|*Wq$GA~BE4uOutz zN^dsmbK~81F%=6(Be8fe8V<**?3R>BCG%0UBNX%oqG4~mIUF@BxmLI6Pj$qpn+4pM3RPzh!n%tz9uC+%L?buq$FSXubB8XS%T2pkG~N$BgF|)5FJW zn`>JdR-8BtmSC>ZE#&i+UV}Xv%l&S#wGWSQd-vh@zx(Y! z{r>wO|M_3Py*j&j^X~TK?D+P>-NDh-#p&%SuDQ?{bUL*X8plmW;q=QMU&B>oh&Mqa5+){opQd^Xg4eQ1UqH2%-$66uYUQn zXMw!;#lx>O7O&wi{)hkZldYA{|L4!1>&zSBme*gcH!3Bcl3_ah!7y#G8FqV2Bs2At zCmix;3sIND6-k#%$yl~AM@uAVH>$am5=kUtE@wQENXPB2WU-p?I|7w_JRC~oo1IRn z)SB+>Zg*R=*`VLg#Y?q9EaGq~`KZ$ph@}!<-G;jW3F9zWQ$+x_--=O$Y-W!?5_K5e zUV~Pv+0<@5d+>N|b%Epg;>yPI%8Tb~dV_(MxJ{#RV?(pHp)r}QhP8DQQ{V|kq6*u1 zrBg~8lV-a&P=BL41@$CP`+dLSKAiO`*=+mu_ou_z{NU!df22r${p%C$3?8B>_ai>M6Vx^pJ4|)k- zwAC(F>g9B;SB)o>U^MO4Y3!s%nsr?`r+C%)@$|{! z$_nMog=ecq?Uoj{BcCp^m(K2F(5dE%HT-Ncma5iBBy*K=E*+0XBR+R13K8rM*NXQ1 zZnJ){zkf9A6U8cZGQ~`luw5&;^p>F8VKi)L9X_AkXtf993bbt`7)lo^^-k+(R4)%l z?MfgK!++=e4tpkD@LF_cN5E&auIbIRZa-%OGPhxCd4-nsjN58+rE>0#%@?HQOP?>8 zY^%DhO)un@adq9Md%m{tT)Sb^E&Sr)@{)FOae2$51j1Y{S*=yFiEOgiWZx6EitScd zp4Tf^%B@zj1x*168h5*c-RrlnU){d`@%O)ZefR49tM|Y8;m2>kzrKF=<99db)9KBJ z%TcG+**=+6YNh7hH@B~DPv8CV46)XLAtC7t&Th(DZ9g3Io zMN(J~1cp22^~MWXC0kBMbA@D-^^AVMn~d11+0d`87}j2V`RLixum1kCzxvsypML)6 zt6w}?H3d?Mq!LP1vYARYz}h#P#pQH|lyDpxG?-@R%5>c0iz(!VHb*cKN+gqsG!xrt zC@HoYV0(oG+l!KjDlsKlDip%Lc(GYY2R&g}e7`%Kijq#I@|8la$|h*roocnz8g-lO zU0apl8jYr7!Dz(equ^oH>&)J;j~3!kGSA*Rr5u0v1(Y~z_zYXCn_4zG*j(3WR$i2y1yPr46cV9;&ld=yPyx1Z ztGDaj(P;1N?EKa1tDD!~eDlqli;KH&zW@6D`&W1GUSHkaogMAY_x9(zgJ!+l?DvMP zQg1dpzS`eAdGpQp-~I6B?Yj?O-yZMH=C?Ov*vHY{w26-@Wk^%ml+cSN22&}hfJiJ~ zR6L;qi4J>}CQErGXxrG(t!=KqAOT-keDJrQe)h@d55HX0=-EKR8qHVoS^5VD-F_*W ztk8ep1=?G5Mm9~`)NgH3Ro}GQosncLOk6H^`pv=7$>GuQ$;o_gP_Or@>7?J|_gSqL zo7Lg=lBfB@K5sM>P9`(O0xz{*r`_pPY7=&FqZg~r=9KYtDxFJ3*&#I^i-)55a>xX3 zO)7Sc#TN=iLRMp}kccMfCohB@UZ+;?G_I~JuWm@?k8TS+)u|1gK|>$m^48iKUd(DX zn5<@tKOSKdWZJ)cF1OF`4=MqBIN}Ru6gK1u2Gf;Xv7RS=ZNYT*h8I_d$CpQkXP4(U z*L(fh`N{s-`TqR$nq_2%?239wRjNImj|Yb^S!ZV_w{P$6-hcb%=H0u?t5>JHXBYc> z$49g2q}}L&11jW{jc%Q^TdA~?KD1j&M?I0CD_+V5!)RP28VqF7^>{20X0mXptJ-J3 z{PfY|Ckvnd{Fl!+RyHkWYa~teJD13{YuQR3%u|R(lX1V34U)r_Rh><{%(j+G8%BdW z7Z`mAnn^tSF!Hcv$wN7>8j<8uXQNmy{IsvnrI=kDh)!Bnyk2ge`8%a_z!f{4?rpaZn5e1#}xUHA@yCZvUx)xughxCn!O(FOKM9_vsSA&*{piK4&aN1m`xV9 z$8K{v9aeZnlhI;P;fMoB<@WmURsLwi>u`o*fk0Tv6e_h=e>@sa*^l*bHrw0Zn`}>} z5E2|t(-asf|_r@bmo6`rW0+{jp9A>L05OCqF z!odh(Igux;ZuhqLjt?fI=@jCh7R)^IEm1Z9UK#6GsFkgy%1ZzK>7a@7bXTqss*jb^Lc z?~k{qQ}V!*6LD4NH#f%zM<*9&hr2tw#}`+p^C|n~UG9#z=O?G!}x>DK2yp> zVwpJPHnpc*A(u->Q{7%ZiDecGeyb~ptOFJ*6@IV7Y;gE&28%_@ePAU#WI%A1cpuoe zfK96*f*6dttu4K7!@%ttke`=PJG}%vw>QiN|B;B-9hN|qP;#YwrCupFX&9${pfzac zi~a3kuiNZQXt)^f&JRydk52Dy&ri;&%7Ufl+g&`-Y(R9_KRKKqo}HbYo*j}Ro?M(0 zWG-$_clM@ZI`mt;UaK=4)QhE3snV>Za1zOUG3E=W*hC$Th(y9cKikZNJWe(ca)HT- zcz)s`Y99&nhqw|A`q`&fVF|W3m`q0kPA3@wjUnoXLr$wF=yjR3I>)9x4SVCRun4RFzN=9noBlpuizt0D930=5?U<7KcG=H0kvgs|nxfWT$K` zTdP|w^p^O8F1y2G^+)_pSVDg!XtRaG9D8SwXYY@3q^_ z-jMMR2b10Xqk}y*4?jDYZcq26>_O}pZ_n8OZZw$A4-OCKJ5$y(9`A1tXYjr!$NPt; zCr6mf{^{At`T6Pb(b2)~-fq8EDW!>_et*ad!gM(uGJKCqzPGvD4x3fCWw6-LcRi0; zkQ#KV+9>95*HxYZ!5kz*URZCZd2>^H++O z!r-1-DOYR_M%$zQpUR>8gSF(4S5L* zRv(2ZjmBWInATaHX>w4#VsoQtL{T!O5~O(?)+~%15}Bymg?jRcj!2@wfJ%kha01?` zw?~tH8<~uDdJP;FFt^#p+0WPscuG*%?so^%-6@d-Dr?psO?Rn3b$Y~#$q2th$$QZ4 zjoEG()_lA@p6(qU;op$O{{F%45TH_Tcbml=mAPV?L@TIduz!Dmc8@5P1$Lng+YPuX zqM?=SEuB>&#a_2jD-|jo>P87AnM?X?W;338i{=d7+QL_#KX|UtHokA1#3v<5x@)|P2tSYCLxt|QynGFaVMh|A@P#>2s&->2jd1KUiqTXQfJ^bwVk zxeDA7dqB^3N8{=4@#Wck@96CE`r`QD;Na}`Vt0FXczttBws(4UalF5`4?#uZ2Nk%_ z&M0##e7h3yM|4+?#@#l=RDZI&Gs9?h0RzJhRjX<$7V@~*htuJ-Qi!ozF#>@WCX>TM zsBroi9H#DxlZ7~(!3>(3NJIOMn)Ma}?*KoGWMj0|ps^vJ8!F2UQnA=wL`_cOGHEPC za3|6-8tpFNGl@WgiOkp9?Q$+xsyAz8te{#gQ%+51av&(Mc9M&H9hh!s9>B7<0>@mw(j&6(!2aUhw3$O7Jo0?fACyn%qvVX}oX$$&Sc zchC9cy2a&h@Vf9uiru? z0=G^NNHo}$_F#T;dwaSAWS-0*Ps-I!9}HbAR~j{lq--G*4S`+aAwPEkJ>~Iv-9aTn z0C9!l5if;?G^LPCmOVb{`HLmcEP$XZ!jE+XMkwQe63!jSt476T)|&qzBs4Oa6ITV zyQ49io6n}R-MtwtwDY~4aeufyBafmeHQ$-c=6eTcU?=js(*uIW{=t0QY7QpjZVf(& z!-3>^{1OrexROJ}Glg6x33~^46|m}aQF3s(-A=2`6AA@G z(l>`fKpWus0vXDy0nFm3*f=%dls;VrfEr1pGtf*Cg|mjE3EX5)GDJH*qcqD%#2%22eBuTT|0J+6>vU#HkEFP_mRLv>cK(V0MGpcw8m3W1U3SzNe!$cOtVz3m>hOO8~c^P~*IW&L58Jjd?#1*JknCl&MnX?q044o2}{UKJF1@cw9# z&uMo@A^SjrK>(gZI42^$8#8djejo#@(@R~1+?7-M)!Pk6Npwka<=J4OcVuB@o{dF- zN)nTTa5izqnJJVYl=3lisT5vcU0$3WA0O=Rj9QgkIzua(H%L;)1H=HelIGAK5=~@MxZn)60bzlB zAiO|0EZ$3j(q!AYLXqk-0!pE{5JnjVSpj%pJ2N>F12+YA9~HALoyDTr*jU>%nsgiM zn>rF;yg~pLE=GQhH8I_tZo5r2t=r*gKfop^z;Gm<#3~@4s%61cP5OH(xe}8`u z2gWosa*Et~A_Q+6;x4g&;undJ6V(!h1+7r5sMed!ro^W8*Bm#__y1Qv)XfcYouiTcSl z-7bQNmkbcbD+I>!h#C-C+R-aOnf) z4l8vYh1aY%dc9_|QKiP%0faaEoic`AX*8~>qtCM3$3lpC24rL~2?!=|XBtBSE8&Z&lVZ=25FVHbv73!7RntM(X>@uc4=I9_ zG?<7=Fc-miD#z#ZwH~EEDReX|Kq3X}30Zm@r%6^RXA}{8J_W!f z8UWYq03k4|$p~^KNwq-4xZUJ#foKBnim3^M73Eoj3cQcs>2UkKqI8}B)exVTggzS$ zL{fCsC6xpjr5uE+6jBc}Es+>LN))ch*2VQ2$;Nm9fa;C>Os63Dm*ww`eL#+(j4MKXqUFG42trmSw5~YZ& zQHVBDPXe|d7eLrR0euQVK}nZU-zqD$83No9!^0hWso)7W!j0f$3KdD)P+$TKxmg@$ z!fiL|^aj0VePwlXYjbmReO+g9xai#TgklLbRuuRQMn!5>7VwmdN8=<69+x)&&JP5L z;Be{uD>MDsT!{w_7R6YqrF2xu<GLZa#cZ>av2Xo87T2xdr( z2_5kh=8=>S=EE0ayUb9WHU|j`v0M`o`PbGn{K9Z}j%jN-Zg#9F=M1)MC*=^zW&`m~0*;=$sR42|s z?-GzhJ$NfChhh;QZp4E$(7>P{P-DkL40^rZXrh*6p&sJE=X)u1#_~Gz@*n3&{-9lv}&ZP#D8IJgC3_1$hNt$snKdRI-AE0lY>T) zrw2hDNl+rJaw-l`Vus1zC4xJg9C$74SbTsy*b_X5iIYLV3>VNV)j;?eK|pN_;1K)Z zflGNhMBvm&m?g&$9fxA8FuY1JU#y|s^=4ZLlL1{;yVNm&?NiK2auA;SiF2z`reby7 z0Q(WY*6TD0pnR@Wtk$cvvP#Aj@R5p=^YCgVVM4crLC)eVn|u)G)~xc7LdKnlgraok z2(gK8i^V1Bk|}n?Hmqjhfq7j z2nbh(N_GSDh}-lt^YWFBEv^ALgXra+W&0%Fi^Kub#DFg<&-TKPCgDF)1HOh#zuRjlzhN z+(^(gNA(~@0 z0F*+hA`XICrPRXBf~%;}^Ix@$h#K@tgLcGYVF{2>B-rAka7AVOTeVWIwE&RqJ`Lv> z1t5!b58{WbmhVkb0yS(NZiitrI8++F5k?d=s}7Md6biT#Mg$F%0EOUMm1L6s=@cd* zG#<7K3azz!?J5RKb0U92%Os}{6U!;vK$hU4tk?yri|Yp3Fk_@Pf@TSlG#EfBGQmDE z8V=k&&@_ zt5+G4Iu`|`BoI{WMSPRUf&~~-(U%B=K{5ADq*h1AdDdJ-z&o&%*`i%lvK;&*-ipb^ zyi<7W9b$0&vH2e ztH__pBP|vbO1wosVjwxPCJ#L-WJgjq4a;+r0R!lMkja$+6AxNq1=R|$ zoc}p6B=H*5r$|ze4WM>BzKm+;jle^y0KpN#+#a2gR58VfWD_9wKnIe|{2 zHyO6pcy0yW-bjat)OLmBP~ilO1I!_}oF!;5oREZj)d&Jn>FT7KgcOKXdC<8?NS>mN z&Lo6p=YGV@C2e5O9}nIaT<9WY$3TI!#6~hHP7C(|-o-e@SdbFIk2}N{;EwY6BRJzs zI#YKz0gQ|Eg8-i=$`i#9O@(xv*wGN>{5bKTqkIWR2PC28swDH+?cigHEO<0p zbcQPMB9zcuk6Mvq3l9;)72thD=}-|O9r%b?E;JIcj1IEOy%I3#+;4_pn^v&~!U0&M zlGv{>B8t!>%pbicfYchRU(}?vFVP8<0mUTfE9i5Y4Mu@gIxWkH0Y4hO#byIEK(I=P z5Y-lW(8h@bF-A<0@*Au#_GT+ncd!u2{y z8gtCmKy|`d3eGAKHEIO?7AX^u>b{JLh!8D_D~5&}L}v>0$_z%ZBRjj0S-T`4y>1J& zl{OeU3A{cpB`>FhHP|+B7*Q}ccE}@uaXBJ(3bX(T07YYKJiP;dr8*a25dK}J8$%Gc1yM`F zPQ;Mb9Pz6tzCZ_DJ$_5Y4tSb0#2vl@dEg(=2YieGDSRzp&gKw=h)X1VBMTsuM@}#H zBgmR$Pe2m(r4AKgsHy-;q&CTWRQe3(#YsteB^JONQ1%1c;q&E-AYGz4$q)et%|pgS zL9tszjguq7gQj|<8U$@AGYL_(%@hf)ZP0ijkTM}fOLgAxHbDpmsu7u+Oo!)@~sB6f?u171l@ znsOrQn&QWSMto2-ON|)ned0gS1>t4Haf&Bn?#Zczn^E%%9H#261m__Pu@QvHK*g7e zdxQ}XK8@BDSQ!?Lkz~&IrkF^rTu4!>^3WtkQw#~(`o@-qLvJF6!!i+KLCSC+oDA>n zm$b}oF%shunimDc)0Ivc*T; zqkc6L!6}KwkoNIeM2WKy!VaiRri#39Y<$IIlY+xC-pf&}NqiVIogil}!~H}60aAoMcD$ng6jRwQ%&U8#&TP9Z` z7L*P83#B2rA}yE<1r^`LBoRuGhvcl?0m=%I2vH*Se*BYoVGyij7We?tHpzNHlZ;9Y zVM5NxeW{0pY{5!kX@Pb8!#Q&nVwSw(6$F`sW#J^5{8nSUyT=n0CVM-R0gV)si4dCr zGS*@GVY3_t3cF0S353f8|~=#Ee(k*)81U6aX_!pXpQt_;^fJv z0dRu%#RhQfH1%+Z4ymaTAz38@=&d0u7AH+Zha4ED@R^t$MGpz!cqixu0n0*!2uM}k zfcPfvTs=4~A_h+&fBJjld5O%-sN80S5KNr{rLHz;i5IuXN5wLQ#*>yKtQNcv90kl` z8VrXLAG9ygR}#J!h!a*3ZBn&dVSx;p9-_b%1M(#aQu81@B;J!&KZ%Ay>xw1uDpJ6k z5@@K(Nn#E5in6#v97YzCXtn!zr`e1sAs}HkgO!02kQ}otQAc_^l9Z?Egu!7GB5*_` z9#)FYI3)JZBzo}AVh8pTY+bVKh2|^bi^T=sA+=Mg!7+iJ(j3g(Qqy7}B&#Ysl~97; z2M*`ZL3mJ@pKZGS20~9)>l7rD_+{{%$Q6Kq33~3?1~_YcB&9%RQ&=69h8CDfq>>;L zK!xNWkb<1V8RK3A!eb5i81ZVv8GMtd2_NSa;wyNgOdea)_lJGq4g38riTMzlg3@Y| z>lK-iB!UnEh(mY)I7&gQs5|Hkl1!Dc3foB{aFQ6FXp2Oqdp=W;pMW&gB(Os?1~C($ zAS_Ang*oFJ7y%{%s(>!FGF3%UVe&ql5CBSmjf-zdjy=R}505KF6y)YYFA4P3X?2*6 znig8YTu`j&F@_+7CejDLksb)pA;$5OFar$e9`A_mQV^x}?|vAaresObk&;QkPBFbg zFdzYZ0rCUVsvlR~Ho7J>9VmtvLkE=_^qC}rIXWr`_1-v`O^FdOCn~JL8i=4WKT!Q7 zdXn6cQ3&&aIjCa8y#ag)9Kz>-`1mX-26B_!_1>z$Z``2h+kFwCy;`Xe`Q6=mV9WV~pP06IWSr_XA|k-$il z5hx=$0Vskjg}fGJK*Exx(<_HSQ7^z0wkhK)`BuV+`H-%bI6I3bc3OwNk83A{vdLf*# zP){OeUOx&-y>GlUmlUcQs3jDEP%vCg+l%hEzwl5O#+!HgsLc_BdX`;w;cQ) zuP*c|(M)E9sT1VF#0h;u5sZV$W-3&*m(!{6QKbCSSmp275oW~uFhMfhd+#IQNEjx0 zkr;}Ka>Rm?gC)au=?`KFNj%~F(Z})Of*hzP<6|A z6{L)tl=PTJ1!?W0KuynrBpMgF$6w8IUgO3x9 zjfa0kmPDOb#ry}3`^jQ=`t_}yuG)nNjS8g#TH3o1ya;5vBi(<(; zFbwXLfvG`4Ji|R-CID8h$aD*=lJE{cpb7;m;Uem71HSQxNJXYb1u1eDays=y+$ADM zx~dNlVneci;)lw$iq}vjq53kBh^XehW(t47Au*1#scu%>z1*!Bh(K$(;>Un0nVU?8 zXpqzp@3jU&2pAMimP3p{28UD-3zy^cVtFDJv`@}1pO-oPsP?Ld;E&wPy)uY9xu1G< z68VhG|DS&m)G3!#2O%+CwIdn0xHb+oSCki38Dy4JF@Mwt8HC7N4t31xt9+*d2l*w# z`}igmH=vi?EpitxDShSKv}(E%{qL`b{QvBbdl3gK$|-5J3R`}{6zZHyEnLQ@j#box zh@-l^&mFY?zve*-h7o=g4uar!0*FTL_MIZOGcCS7%CjP%4=$~HIySNt$-`-0>os^H``RR*H z!=I*E?){_ci72>~`ZjqF2XB+(r)#V4ynnyE-XBOn9m4%t{xlMc@P0WHCshCN zlNkQp1%A2|Uw^v5{ntPL1=o`a`1q>+T|KRw_@}$P|N7@6kURN!VbOwn@qDzPpM)TP zm-pQtsuPfJ)sOw@MSgQXPI>*PUmt(LPk%PU=D=KEh zoD=4pbA=AKd+vliv$He1JGb|t@0>l~`Of!xO3|u>sItFPzQaruo6_1yY~h6Wyw*T9FPv7v@9d-uyPm%On2iM^35qyOhO zzk!$f_XA$@&){24H{Z~hcyubUgqEL$_A~g(xZ|Jy`1fbyJ+qJh>zDtZ$_I| z)vq7_;WwXniXZ;@-~Kog9{lfLe);1MN86VtWE*2w7lSun{>88V`TxG? zzrXgcuk`Cn|LL#)^!+El{Y(3n-~Y==7d-%-OY_mEi9~k>62S~OF}|u z5OtuZGM7>(Zf3X3WIX~-B~x?<=laVp|NQ$Oe}6tu7~|_|XB&`2ETSaYefpa}hx7f$ z(q8XB!72Xxss7(9^zZNB*Q@zwpZw;}+}qFp`yc=HmtX#S6SaT$;qT!o;WGRW__86q z{N;~uAAb3tzx?lGNr(LO2jx$dSLm1fp+?2e|Lv!r{_x>wxVl2T{_^+#@Ijj389|pS zPWMNfI#=HRkAM5O|MgzpGdMFhE}h!lUy%(DPcE#@^$P`!O|2pkuMlPT&0qZHKfZFb zbtiRnuvzS!a4(au{_>OG{Ks#<{7l;$m7IW1^fc1e_~skSI7%@Al~O00Xe7rtYJK}! z+cuibA)^sq&MscDB~9&Zjhs@Pzm193>u=s@nYacK!#)6w6-Wzbn{PKT%@DKWRKapS|yVsE=-Qa-t`|M1g4{m*~>$H$YiyZ1l-^yB-R z`|p3el!?10CI|aE`)0NknB;7>KfX(I$N8Vm^nrluyO*7G*wj%J>#<|#TaC6^H4XJ-P+zgcky_+ zw=N%*Ep8tkZqEx6kmVC|1LD@Qlt^y}D^o+0P+Dan+RwpEPgC`+x{+HFtGNUn9TA(J zOC*(1a|(DpZFFK?cUyChTygR6;rs8u`}qF-hYwHJm**EZ_xHDV508%zw>S6CFV7EG zXXlqE8)MSx&4bOp{2*5(u?Qb*q-vfwFi@B7ZEm2e{^qT^fxVZfqq(V-vzNP#zJ|WN zPgpDxg^F~tv^Li_^vV&=$fssxLQ;@3rfW%|*xo%nJ(7zmsfDGrtvw=kHo`NedVaP9 z6&f0YtD8Mv8SEZj+CA7?pJ=b9l{8H3&eCH2yuCc!T!I)A`*UTUS~mGiYGqq%1%=wV ze}AhOs?EnDynGSp9HyXG+B39%dA_rAd~$Mm`|x;wEaMGqtaMkGGjd$iwe>XAtgwBD z0(`!BdaxX6p<#(+Hqhg2U;ou-=809p7Dl9J7>+ICBp7RZgvMYCs_Uz$Mfu5Yny+=O zJxPNHyMwI4+PUev1dF%k8O=OWItrD|s36&vu}*E@yPOFA`qRJG&RqKaHN(rn)-@_M0dA1iTTN%e(8cZcL<5!HD6R?7u*Q$v z{`7~Re}6xM3(67=53b)GO}ACl4xfJa{_*Pk?z^AfA0J*nKHlHnTtEKsywSyJ9NoQG z6c;AM<#j5~H)ckpQyV9@&$s8tyUP;;T@7?3?rf(Mz9_VDM z`}WmaU8lJ0TtXp(!K|om>>X*!Mn+?(b-ckyBeJiq__AHILQe>|HTXycSIn`M{ZD@tu& zsheBty;0FJvUc(IaW>P}*3!{Y`}#{2Z9N^eZ@+o)taD97mvY7AX5t!Dx`}}yezjt(gb^G{q zcXxlaKi@@1`GgS~B3-Q9V=48*ww9I_UNw`No0Uyww)72jH8*unpFCV`j&$_Qp5CpG4ajyL zK0fU)EpHthpPXIYobIe`99~}RZysD+U0hroE%$Z|PK5mC|6QIWAJl%i~OR8%~cRM*+nE);h5_3;a{vx@~2imUH_{`u!0UoQ6)XOAC# z`0)d*`qTY`qqEzWm)q@`iSg-;^QU)@m;1}pvuis$+dF$3gJsDv*s_MkhFUr?6&)8B z9q43Xtgrd%vrj+!;_Gj|dG+S?x35*yHFfm#jm^wVOs!qKe0;p!9W2c(>_c!RHC#?@ zgJ@8;w6#9M%}dJ@&g?)5KR7yu&wGlk^*M=Ta&CF+@Z@-Zdwpqcc4m5RZDnqHZfSL8 zQ9e1ld47L9)iu6-aC&*Vv%0Xbb#QdBJ=MnPTTvWeUYwpC&$c&IS8;fp%4#mV5EJBN z;~3y$qpPN_rKt*w^Ud2g-@aDY*HKqfg$F9CYFhgG+Ugow+S)q0I@+3QYI>$tj?Okl zI`EB=M|>tG*vSJ$s_u|V_%s5M*|WU0JT<_j)r zdU}3-dU|>P?&an2_Uiif?)LWPWM^Y}ere};ZA3cUTTi1Dk&`2W!jp;l1f;K*e~`DM zjkS%Pt+|1=rUsmdp0T;5g{gs#j*hOOg_Vi6wxN-sp0k+m~=Qmd6{k{D?ZM-@zx1zA1w3^3n5=%PRnIX>Bc0olf3W?b< zt2jE@-BKJ~TwYv1-khD^+}_;Yo+>uhHn!I%1fJuN8(mxYZ-V)Lu{0zp$- zXPab7N)o?l$qzqmL(+?pL8S~=Pr<DwNA*%NG}y| zvcr8{47ALBBEkbbEcFdcEv?Lr^$o1u`~&^`LSvE$rPb6}kI*97@x|%(L{k}~XY26r z`26PX;r;uIwRy$ehv(b-+vBaxngpGrQ$uxC z+ZU%q;)s-|2D->SeDmA5JyT3Wg$Hcl?~rux=C{=UA!aTs)9IFZ}cS(A;a zUfSE+Jv>|;Y!Gw}Pp>Kz8|%AU)6((9wbkvDtGmbNcOTy0-#@1A*bd9a;UH!tN z5uSD~?k>*W!GS)ZQT{eMDu7$wKw~v9v9PwW(AU=1H83(VG_|s^wKUSv($>|})z;L4 zb>SJ{VPj%q=^T`vOTgo^vh%2PdLcd;lUpO%yT4Y*`Uhmw-OZwI>B7P3?)30LclX%( z$<@Wq%F^cUQY*pFA(+zI)jd2V$gdpP-I<$OSl>OlxW2tUSP+s^lCUYL$Pgb_XJ;30 zbj{4pSeLLeB|NA9XjO!BGt{++lw4nIPYMVj0pz+$CP&;aW+p^N1P3S48!E!AtjzRu z^bHM+Y~8#)T)iR^BK`aV5pgM*sR%cpSQ2k^ZLT_>#c!%-71OxwUF~(`4A_7qN_ofn{lkiENpW)b0kCCvb3>!BtD})oQr*@+ zG9er5>5@pt)@|oGmo`%ZG`o6{e>!v0=f87*t$jR9eNz zij)@N=8M8p@IhtI=F*tvCv*wM5}IU;be#TI9nQ-xrax%S{MNOeXFjisbgqj zq@$q$jZad&&wTdOHpYa zE)$j+ zT%G9a>>iq%lW=L2yv+Ep2mmqM(u{B?N3Y-zA17--&susW*3RAmz7A&kTB<7QTKW!t zfu6P|Q0H{@^mU;mt81FtJK0-V*tnzcm_P@opd?Z$F4W1+Jt#V*u$Y8P3it7iE$^L} zk(4H)GP4NO%+J%y!^zGqGOLh?O~T~zWSeWlz0&E8L$nK*zw$ z!c-e7#~W=UBLfR%D^^w0(9qIUQ-SxOtE;63->Jib(YCa=G1k#kd#eJs!qPP)Hq6Gv z%E3Q{jE|4Q5@^-6r8)SjZt3)zVrTF0{OacB<_b#m?*8uX{?XYDkc5}#vnBcZ_0#>s z9dsG!a0iOz=_%Rh;ONT!*~!-QV0VY8fu0c;8Iy#^B}N4J`UM7r;_@>hf+G@$9dnc2 zoV;j90|OfupU{}tP!DS}Q!@)YkKl+vH_xE3AQux&ZF|4a5I=Vpw-6L2H7zqc8{?w( zRzu(11C>`+&8Fh8smam4zG!AEuPB?`x_N%Ov(!WO_NZRIJe*`B9i9CV390B1H*0GY zOC;tMV}jg*GdN?Lds~ZxO}y5@#e>^-F9(YwZROPJzNNk6y_wdcbb@eZerauEV|}iJ zFCH8gQDegyy~7KKmpAuUbHg(m2j>^(w-18^KhKEF!orM1G#X1{R8`V4Q}EO>2A$a| zU)$PP=&wja;_^$lBm37!(}SH{Mp<=z>&S?>t^!0ES^=3trI*q3aY!FeL}GF*B9c(c ztD;eeDPfKlE=Wohr?xE4K*hipgHQ6&`0RI|saX4Xntk)tx3Ax785-(nXsEq;_3fKC zZ&cLaHfm^SXd0NB7y=%%bWLyQ16IDdv9`6pyEZ$$a(MgnaCdXQzrMJ%cYO~l|6*_J z`1)*Tb!M=+Ve;nvhxaenTO)PUGSR}x-P6n6-qyj@?e)d!?(Xr~@!sz7&0z*cX(#FB=hyc`0VT9AV$ejXM^0d>3wx;q{Rb5@%+9w)~MkWKttrXF;~D*{XZQDq zfIa6cJHDd?X4LWM_vdD@^vcH8u~ZmI1a~URXPNyj&E~NzA_Gseb8%Y@(l6 zl%9^uz+%!#OrdnByQ4?M%&niAo1Pf#>Ks^DpKLD4CDW^D;dT}-!O?L@sN}HlBf^3M zy2P};r%fWA+C05|{`lih-@hnZ`pdg_FYlgj4&iDY zJV32@dAh&3yu7`?yScf&0|EhXZ(26m(&K{ob&UWVd8gJh~39;}E@wGQIHZn3X(uV@BqOND{ z?Be2NYwO}2MrxLC@9(V0r9;D`6Y`mv#e!Nc9o+`-veS5;MAP17zc4WArfuBK}2oCL zXLEmI^SE3pZW)~4K0MxAkxz~e4oxnugEH4pUCr;2El%?ieVyGy60*y>Wb&!8p2n(5 z;mp?V#@4hkkt8N5$SW$hS~xJ=l!J<_7w-0w>M`yOLJQnw>QVjW0Gz`RYe7>l$3<< z_Vfu3kBmm4LoBr3zIvr*>J}1>!eBAUsW>8qO2NfJ(E&>TM#sw4%gfu>%hkmz7~yB< zw$zcMrSZ;lqzVe0&F>_vZHL-Mfd2{jIHo z%lqf2o71BsSd^fvoNi2r>p68iKEI)s9PVOiW(zGbGt|S*%s>xxgtuziI$CNfZ=tfi zdIda96|@57p{1p+2A?zl6d1V0=hJf&5PpCNP@2}5~4}pj7%nykmglDffhSY*vy+0HU872yc;yA8!U{pBxVf>hS==uJ z{o(5QDm!rza=3Kr(>3-M_p) zQz-WL6`O100)Fqp#*7F6Y$Q{5xIe{1hZ99}^Mg%Q#l?kqES}D(EliE|wYRdiGBY(d z(^q@-7Ue9mB<2koFD?ON9KoqSORTCO!iln?eKt#Fg}#{`H%?^PRQL{nLxvtKFHQ z!HL=VxwXT~)8!6EZh3bvpPG(Fr{^FXy|E=_#7GO+QC{BuQ8_)!V|5w9AOmZC`_&hp zfAQ6;H$Vkp$*F1UssRLe3osdUVRgWBN?fN0FkeqcTT4sF)D008>};y5Z{gzYZfEC% zrO<2JN9WeIHrKb0u9YzO>hu_{#StL=^_`RJyZc8#le^2ai`ysHw^x@pPv8Cc@$vfM z{dXT2dmR5GpuP)Ax6ic$yn&tDuW)yF?0%x4|CMh z(lfL742lSIG1Sr4H8itz_Kk=N_VNmei}v)6O2iT?x)#okH<#89&QEstj?eEv13Ec4 zyFA(3+SuAVzPP%+y1Y2q+ul7mJlqEwGcmh!ehaeU1z?$z!~KIp#loPlxkcP7l`U>e zx8|ec0C2jx+L`LhL%dvEeGy^70bb5_cJ9$d zWrS!SFGL!>j*5+qOUYw#%TwWc`MA3HVHu6xZ3W>zkvU{S7NLOM)|!I|i;4(vcXIU$ z2tXiHa3pF)+u+2MY^bTEsCVb#`Tp{7rM&=;?0e){DoMHWm8^ zJ1b+tS~j<>dth{8a(Z=70gBw{U|)ZK6OD+^A(KfIc70`OX+>38J_d+vM6jEck*>C$ ziItsucyeN}hl{&EA_C!MrThBRzy95q-+cA?7vH>9*8p)uRTDUh>YLYZfZD18CsY<# zEq!A{J$)ln8xKTGkc%&-vR^JA8|>~JnAtwNeYn5927&kn*xk+L`N{s?$;}h2>+Pk* zm6fUK&GWmPPufJ6{^-0PKHPSJ(^9u{{cDA+i2#JbB_&M9#nCR;0 z>FHVchK2b#S(+N@X>04-gy3s>r@EOKe@8p7htphmY30_4tn^{`XAnG2ThjzMu zbSSH3HBB8{-#^~0j!MRsb`SUW&rcS61fq%U%ex2AN%zkmKRjL?DOP7E#-=xR_xE-{ zvz%X;8RAn=f&MA9{5VG=5S>hvI}!9+XD=5sZ5?wLPiJF&hbVkOQ8A4W;p^?|5hnrMP(E>&YlAEKipfN8EoU#)^c0=Wy`zgPv8Ii^LIBhb)}UZ3&+>jJDp4lt(xD| z#33bw1_mLbV&gGsDRIGGZjQ$4TBe?f%>LD#If;N>SugCU$;l!WQ8MD=a~TzN%_4F4 z$aHs2X?eY{y@i#Rm4b>6MKv#R$WJW1I(!)wm z)6~XPTSZ037LgudqpfA^6p>xSW0w$60j^H&UcMp7v}}BOdNwJafby|625*)=wEz6! zgc}!=$?BY1+dn@&y?Ot`$A|03?|=OM!^`vg@4kPz-kF=2JA8Wg@_4$rvax%7ez+zd zlP&L@+}z(?ZjUx|8ppSG73;G-<+vS9Hc(}Vd z-CdH6Of2o6oo>(1E-6m0uTSRNg+pschiju8GKt3Rl=OCp1vTY#YALU8dTD;FN7UNX zGBCHayncB7@NzfZ-Z^vp`0m})`Qg#!-P5~|ACz$E^8D-q82`h~8E8HrwH|COFD%ST z`v(T46VozDGq0|)oXx4sPY6eZhK2^XDtEg!h{ZZung(WOhT3W>Z$RjQEv;+>@P?I& z&z}wr&0h~K*bUn1s!GLM8@ic+tyfrdsH>T-u8Au$Cl{BQombNbtAB5Ib6zf=lF8(< zp?X?*i&Qo>B^#G7t#7Qaudl5vudMGJ9q%ko&Ma^29A7^wrA{S~0)-PKa1g{nKmmC2 z`26y8cYbzxb#--pbNBRge|fOBu)GZj@c#CE57hmskzP@gprx&`rn0=Wh(s)?71U6( zl98}i%}p$v{llW7 zp@^x2(67`+!Ib*-&`^1!qG4#~?%`x*VxX&UW@7_FyMc|Hn}dy&nW34Jw-4xc-XL~) zg~X@hv-4=>HI3q)-X6)&@WlMe;{4wA^~K@Z?99Td;_&$J;N%**!}0m;)APgKiYUui5Gz7uP(p?^m=%oAcF1f9qex{O-edDx_bILc~opPBFOL8LJf|C z3KU*VxP`!NOrSjJ8Jb$yxw^YL*jPISQM%=GlJZ1fN3UE#|F1q@5tEjk5E1O{>=vGk z!$x?yIvHu`7~6VZ2rTqTsjlB&?M^_WGh+f^)R$X4#JGU}DAQCip%hnGsZg05Q_(96c<;koeg!oMs6uFhepi^ z_pmj!@OCz}@<&Fy8>xTspa1H!FTQxCVd)F$4{V5wweA}g1E(N_pNo^5S70b25{(WF z2oLoO2=TE}Rkc8*WyA-%`(h|exRrgw(=usaPv7Xm7O3^BbJA88DT~>?te6$jQ=_t| zc`0!SSL;~|`sqF4W#X@IY8)(XF zM_1RUi#^>_M=u|rE){b5<~8iuo0~I`a~B8uBwd5EYa8qH{cP&c&U}4ln1@$RTMHc% z5eY!c(F1|25jC=S)B9(;)BRoD{4`HPJ^SdQ_VtBM2HH_W&4E6S?(gq`T_gkctKdkwZtm`G4#q|%2HN`8E{}_sr zA6`G*9`0;yZ7X(;Zq7HR#wKNhEfuUvRz+O{n^s!OE~Qsil8~7Ck?G!&XjjLO%(B+* zHV*h%EP5%85FZ-gW?^pc?&0DZKoCwWZEP?1ltlUZ`FS|HM-y1BgX5CshR(5GW>#D* zzN)3UvH%z9psQ{aQr$q!OpFB4*)}3QJ;uw%+y;>v@22wx5VNVhoh1+;)i>XK`PHk} zP)k(x^tF|I6Vx;@_b(5Zm%wvC_P%=pfO)zsX%(-&{P40j$gS;K zUl`~anO%@cgdJlmOWj2=zCmaJIiVp)VnuFJa(aTdiK-#CzOReND$cN1)zCBd0BJEQ zz{@KrE~BWXy`!1SX5?q4q+*k?S;U;IEJ`5`2!&r1CMz>FIXNXQEj3plosf3a7vuAV zbEmMC4`;=oe$E}geE06=@%x{Ce7QbS?A^Zq2!8JK{l($V+WbU2BQ>*0DViNl)}q5u zI8uHwr+;mIqNy-BA{0p`V`D&(Fi?H1W*(Nypb-<@)IR^+XPnISJz;~JU-rCU&HC|pI%;F zo*nJ)ZY|Hv%uJ09O|BeX1G+liU6BtDj!Xe>8JF~Qi3Ihvm8?p3Ew_$Un1xA9Ca^?O z+00l62l_EOwUo!NuOuhwDu%sN4JNntLzTC%vk zJvZ8~JPlrZkEnrFm`CGHo!p!+i;7Z|@w_}rDW|24Q&L=3D-iee@bd9^VqRf+eQOJk zMZsay^Qzmx?HlZEZ>|IGw0ZzbN@?AICh!CpK7l`VbEcS)wARcV6Xw*VW92th<8=9JZOh(UHHwvmN`u7*@^3nMe9$b4}tEz#e_#TOBsMy;u@rU9HL z=h z>g{T60VW&NE=a_X!1@Tp4R@o7_IVy4c^j|M|yvk07)GaC`(w^}7#G7iR!Q9-#~G z92}pX9__A94^J-d9&9g+_H+!-EX>c!hPr#D(*E{lUQHF`EXSnHMM)t}Cc5gX>RMoN zzSc0dv9qzVFjW8cD=3L?!B7XkQxo8nmXR?C(qOHtf<&TeXl3tUYhht&Y2^}$r&l$I zpjTBedBbz^&eG&y|D=i*hys=t;8P1ZP5i2Y)Od7SdP-7qMs9vSIlr)&US7$flW|FL zu}P_zgqR30^jf9TUQtVH=g{Kz`s~ES+}Z}v!{uF&w83Bh`0@Gr^iVN7s$`CLPai+t zUz~#aaQAS3eslmb*!KSU&FRXBWO#C-gGni5i=|`Zv$I2ug-OxLMIxz0%&%eOrKbT& zA*DrnIt8L)yv!i?p<`lcZf;>|0m7K_6Zm8PS-B`rQ%x;%kBAs#A}Yku3`mg~;4{s) z-@MT?wKO*Z&CJx)!ph3V!QD5&+s)C=!OcG;(A(P&5ucn8jU<-WRpusRaw^)#7T4ET zS0FETcYArXvwM8|aJ4%>HX>i$RctIxkB!YL?%|fbf4aLoKi!(0m|EW1TN~;cUOBzH zIb3KfD=Fi4%jV<*&AbLKlZ?k<6S28;7M&35U}zOg5_EAhT`cXObOgm`v+8Qu?7Bt) zJH^K@4o@wm7bd%z=;&Fv_yzhvu+K9lkIl*PwzP1INWtMSkwJc5P9XC^&crR6P*Orh zI~f={N2ceqTAMhv^}Oc3k#>GlBbO`a99~$SlZ_5ZB$9#QvGMWAx%K^H#p=@1%KFCg z=+M-vVtZwNX@75$U(Ov^+&$kO7dN*{XE!hJp!IF9$od+pxLxv>L(fmHX|@BZd@fAiN6?1a40S6@Q4G0+DouVcZn_GKF+cT50*~O(92?G=9ZD->ig)491R}rJUeG!O|Xbgcu!h}Kw*}>J* zCmgQ;p10th|wWYCvF_`hjW~PSl12Bs~`UYbNWE)L&@Wg?@8ba{Sz}(Ko#o7p* zWm`LIGl&f-`GcjUt(#w1Tw-z(8WrIWPwwm!6zJ{c8x$519_$+wgUQGy)2PWIA&8hX zauK~=)HSlOzBVsy;I#IQFKjAy_Tl}$`{DOLeD@uMRzG}%^v%68*92LX+XryJl!WIJ ztZDH7;YXJzumeH!2QEJ|zY1A~?X{()RiKdD3tc=xdsk~6o6}fbh();BJ9>n~ArbD@ z=2rG#W!c+Uni&~dx%>JDhC$99lNbZCo?BonDk?S^8z10oYhi4l13?Q-9k>W)=4QqQ zkOqLnmXWo+otZY6v){bYHn9LDQyaWAHFe-ny80l}Lh8)g!6PIomrkdW@hQm22y_ma zm{V9;&u`-M+q!!@g`%Fm-oD=UCcc1QR*+9E;|TkD#cfT^T_cbbnVFuJ%Vg6t@|iig zd}(WQd2xDlU~p76Jv#@*vu|Sc@aElz4<9~$_u*Mdc|imNrmJi%muJWOduJDCr)OuU zkn=b^+}qth*jgCt>y^&!oL^roHsmq95h zDM)mKyjo0R3N{JhVGDQP*hoiR<@KvK8alcfZ{I?2Lrd4l+}Oa-#KcfvPgfV>8=zen z+SuDWI@y}&Y8f~Oga-S$JKESfxw^W#d-?c5X>xY3fu>_>2}?>}S69!-##x!hw6b(` zb8)bDaB_C__793q%`dMLi26q43!sLh_IGy_iru5j>q{ut5ZP((mo2U=EiA4boE|G? zd+J$bmD~pKe;W9esQ`G)^&sbAf~T=Z48MNVDg|f8R=_+!VRlkTSxy_BNUVl zeKQC?DveQ7Yv?^@IuMz&uyu5C55^SKbq>qHlmjtta&~EDX=DTeN=%Of84r`5nUN9~ z9vl*dPEJ7h_=ZHIQ}M){-24IxrJ#sLFDWT4uWcQWFD|cc0%%(ssmRWu0mM5zg{!`I zc(l7L8yOp)kj<^_oj=@N9Bs`=+B*h%h0UUY$=T(th2fsQ;faai&c>#`1!a_Adw@s7 zV_;^2-6Bk24u-I#`-pSXtY9hlGX%`guZD*T%us!wrOc9bFTb@Z@xCe2|O1lV3c6#vo&oG6=ZD zXhbL~lYqmZ5-_-I0+EzoP?(<<5fYvV`dm#FjhLF4fQnDRrln_-DP%G^mq;Yw(y@tg zG3eCvR7?skuZV=lWu%}Jl5mA(AgtB!+uHj^CPw=DWcwc=g$nWOtE1Hw#likI#5`A* z;2r`PP#hj8R_10FHjnSFk2fY;3*$r5+h%tZ(?SNhqE%3yn}$u#efBMGQ$-~hA z(qwv&7c;W;j>RTIebQ6Y(AG1ya&mLBb8>TYw6(Pd9O4%efx;D)vzR3mLPln8RcmuK zHJ4OSQpRMKF__i-whqZ)C$F-qp<`GkpP66Vzk2sGr2Fn6?{<3e{NvyK!{7hm_uoC9 zA1J^#xPAHf{^5LIv9+X zhALVfflMpHqe6Y%VF|l{mS$(FqpoFWW^N4A0?Htz3M47@0W+vU1XxWMtWP~HZ3Bxx zwInM@44B$MRdlqqv9YzbvbM2t@bC{!%qgNX!MX>w)hFre619msJK6+%L0ix0Kr5TU ztg5PD*VNQC2pV}c%rbVPsH3B^r@yCNDDIouK0n!5oSqni{O|N4V5TkL{D)xef~Gq( zD4m>^kM*~=aEtJT+@1k3n}kln7nIP*>2Zk2_~bMkv4FuYBc~xFqY~0{a^WCT85QOE z8R(dZNF*kcL@leTt*hfg8oPp?Pb3wy`7NS$Q5#(5zMlRO+04SiST{@$wRZMNq~r3% zwe^+x8Tn9WTSGZ984~3M74>``ud%t2TU}XIFP6^E%B0;b+?v|P_8w532YZ`~l2Pb1 zVnGpwn2{6%@lOXE<>*Otu&bHY8>Q5&%+J317Lv2S_F+g8g2NcHYh zm!{>DW5bg6dTJJqNULe-mh?12`AUk7L1mZm+9i?>eii6OJWe&IsdGTmEoy40t0>M+ z$5WUbfv7_$;PYzBX+^~>rIN>BmeFz&qa)*zQqxirqQWDPskt;3JRLSAlU&|3(9^`J zs;I24W>)Z8+khEWR#q?y!QSQbt6;n%JTxL9gTkz27E^MwGVmlyF}*ksmztJ_O~E83 zCSkJ+ii=1YP-KzFxCBfp7MqphRtG@S5&fVI8e(4f(9lb zBP%zbQdG*WWwRJ1)FN6{O?d$h9Tgr&WYyHN3UFyzG!9?T)Y{QEFgT*pUFlafs?EF?p1r{v|} z(y(a+I`~N)t>wflJdsjT0TT^PO|6|0>F7Avgxy`Dh6+j!F((5R8HL8@k#ixM>1pQ} zMPSv}kR$EQoDo@-E#l_d{P-X*pYT*Fo0W@2MutbB((@^#Y;3rTnZBtHGCdoQjq&#k z06#h5z<0%BJLU`P?!%f{K-y@qwP+-Y#KNBacO+GugaWp@5l_ zmYfh985ZnrVQgX!6N~nC<_2nC{O3Q1Y0cmM<)^Q~qE%H>0qXq?gc8(MA&Q`DU~Fn( zZUSaLAYF4Pw9XE;4jw^%?oM_#wk|$l=!{<_zbX!kRtTv_Rtw~}7WXnGI{;u()Kz! zg<3PR27${~4!edg?i-cQ!Z8i5)tGcdzO*#Ivc0F6mk8>*WXtPo%d-=b)>=9xk4%Ar z*~qJJ6!r}C!gOSKM0`qG3KHS%WDWW%M2&QfEbSa@&EXC?d;0l#I@$o&cDA!Lvky-% zq*L>Vd1WwdQAElm)9RXFR-#G3uY-ZDHles@cw$K0Il8iYu)8Ad>5~jiZ5$sj^ov_N z<;O2D4fx&ro6R8}oyzT#&rM1?giW>8{QiY4klR~32FAum1|{A6+M4PL7DrHx=#oLyGOt)P;!;{9A5UHoHHuu+~6Gzg1~2#bt~ zLIij^S;73VjaLXFI50GY$}Fdmva$%U>&loFRh7&#c=G9^cR&4jdvdLujs2HD+yd1& zJlNe_aB&`DTA%sJXFYbV&hRvR5Ez6?b-ZbqaYLu0Yh)Cm9@<%Vm?3 zlM_RLb0y>Qsgcg6CeeU=WqoaNtiP*6Boqtl${9sOTv}pGcr-FTE*6=TnHgyE`twh} zP%(1$a5U8dJOC<|9?)l7D`4A@{Q2^;&%V|G+0p>!g1}ldRYo37jhy3C6Z|bTUVWwE z7!(x~9Uce@rk{_01S$~~8;%Hzh*UznsD#9Xcw}63RAPEYdPY`OR&Ft~x*DE4?Tt;v(cKUK@K68vQyDqpgm`WL4EP z^v*1=F3F{RebQm66rw7VP&vnkdc;Ce=fK$H#Gr^*Tf?rZgn!KD)RyLE69~BE7(_@6 zCWp$P7m&zgA|X2~Ehzzwg3A|y2nokz6L45mRCst?W&x93$8T+Kre(yzrH)P{GHbZp z+A1cayb@gF;=+Pow=kQYpM%f9W{~JLu>H6UYGHAOpdZkcY;>Tvr*BZwR9hqHomQNk zA00s`a$`era&>jKx4yCoAx${lu`!u^0=!BHqRB?3V^gzpQ+@UHGC|kC&_H)Hn;098 z%B|vai(@^U?Cl&~94%oe2QsCOt{%RgHrikOr$7IzZwxFgARumJXlQ0_WnpG!VdLcG z3n3$4HycBBeJe*t2l&Tcej!o7_Ykl9Q_V0fB_;Pc4 z_^0=E^9WGt-Ob_p%;flp1ia7fosH=}L3Md~Er{0T4A_S(fHq}RA~qhCipzu)t#2R_ zgTX>Q&dx;p+8Dy@g}#A_otu}N6|5c=Z3B=Ap#fPrfl1-*<6xkn{^r$d4L#7+ynTE; z9Bu4js>|Qo%@xppWE={JUu>9i4gnF9m`=!}6w;t|a|Ocw(Q!yGNhRHFO|9*{5=ozA zN;%N8I6osB9iLX}X;;@r%hQu%gS|ZiQ%mbRd)vVErl%J+Kq;M{on7BmERGFGB!g26 zb7MWN^%W%*^-ax!`tm$fXmlox#VE*5O~GOkq9bAwuvs~|q&!kqattbsR8mn%2ii@+ zV=-w23MCC06@yAZ#w6wzm(mJIz)Z1;iI|j>)XZ#RE`*k|QqXBRIXOg9ULGks6^qLy zlX9}NGV%GPtjd~tf%2C*@R~$Dz5GfL{2GMaeFH;%&8)&gWEUUC4@sl40q|s}Cn8Z8Jf)ZDA3CMG^IG$m0^FRGl2lY|96AMq4E1*Nj|6OhjEPCYCL)oToWjEN zh@ilbh`2;dLM#ePq*rq}WsvU6hHy2nfk}Y@{Gtk8LsfY>t3pZHx;jNIf`+c0+a&;A~Yl{0udY>78xGkV5o2I8Wb5F9U189;^G+)8jdcg=G9fusRj83bbx(h zkX~l7Dk_*I1;h+&asvDYk!%tXi$cP_jEx8mjRvI^7+oHXUQ8j8ORALv(v@uZg(Yoc zOREbL5^+-_pI6Tp4NNTqd|jUC0p~%~qjU&s!B1w_^J>b9;nZ1x#s!UBcC85d+x)z2 zuw4XmqT^FgZ+lu{29@6;>>B86sVFL-u|++d;ubD5KLZ()ltU{kql4iFqKI;kBsC)= zBQpz!MFx4edHN%wVq(!LAQ=?^A;<)ZLuGO5Ipr*N6@x;+=T#{^N@i&ZgC}g|*Dwon z@Wp({Sv7%MSX5b8Uk7$CE*XtNCgoN(iQ4KbsCZO}UofVK$to=*W+X<&puq{wE1*#8 zI)c4qd9ROELyEac6b39W3`^GKq-GE-2%Ohvi_~@~bPDG*U)# zGBz_Ozp$u?!4*r#2ZdZ#0fAHk9a7ZBt*UJlwzt(Y^MMLw;&2&hsVPb5L@cOzBuaiR zE*1V~Q6s&m%JU`f2nwy&geOxj)G&IoJ%ICs6 ztZt~UVb^f$Ynk{k4+l^Hl*k_PY9S$^p@Dt@fdRfgenE&}9|t4#w`vA3Ob`_4<7B31 z;u;hKjUzTDGCD2}l8Eu~7$OyZvrajT_@$=ei#e@AKC^&K%A>Nlt-YXbbhdJtlniWE zL1l|%Y((79*wz8?uxE5?YH|#IZO6vO@`8LETF%7SC@`EEXe6@>&}yKag1A39Hq_TQ zG&a=6VbW;j+*YwzEE2W~I4nAN&186qrWVk0YMBLKPR603!~$n8E6o2tm7G^|Tt{}t zzly8ueUZ!BAZfKL$&x6Eq?SY=2?8LIXD|pegULDPoPh}#fXE~O1~9BBQY1uDRHo#W z)>YnzwRi1us`A5r2>(tGKx$=|UFt$%?(LhpPwLbEbGmJ_j4pls!qGk!#P^+iQs@9)gZ z?5xmOQMz`Mypv{|>(z2G?I9%Y_W9f{CV;u-+Q!;)Eo_~hoN=&5dv9m8QOppY+Pb)k ziL_eWaTemI0uGbO6^eyDcBelcb!mH#9_>2E9z2Pld8GU8H;$4hNiuiNWJ9up;~jXA-N%{( zpPj_{!AY~*>oks!j*l>Pdh6(UXPmIJ*Xar+*e1hZaRoD3GD*W;x63lEo3%KsGv~>$ zJ25y3ia$0nEg*>7;c$hDE4$ZrmjY&YywpJD!0@Y;Tp|*R&2R4AxVll#CG)lBVhb%O zHVC3d9n-^S1}02_T&z&?Ul-#!@{fnfMh=_?TD0CL9acWZUNmo+#(e7WJp0FiL(0vbZ z^9HLq1kl{uT`Y+~tu~kEQ+^!T`O9o4)N~DZ9X)zxF2Tk_wJh?b>F@69pK?0KPQLlh zfI$Ety>__o#2YXD?3JT^8Z(er2rou&awmYXTCK(9_05&6d2$T1;LL5@yv-`WCB}eE zjbPsP&gE?~NAihCytsA^Szk!|toB5GYwy;L?d4)57{ULnHwy7M4jXR36=0qH5BKlA zw^?6k3iO#yrn31QLs~iGv(1hV_Vx9j?LL0wmp}cz)=PM#Uodm^aO%y93qWBmqKC>jYz6WLm8k#?kFBy}>!iUF^BJWe?1i&Yj%te`1X zib3w`xxJ^iNomt<8<9U*G@E>u>jr*h2w6W@7lzk_j`aozWZg z91f4oSY2+f*B6XsDlp~J(tK5*%WBGF(i?4&66SjA($-2fL!`iNa|MD9a@IoOP=Iy2 zp#<>*Y|NBy*6NFAbFrXb8je#J3wo@E>B-TFSr*3Hos62}r`~w!#aEA=9qd2bKQN@3 z(Vg$>#S_*U4M4oz?=nFl3fk4JmW3WUc}{0Anau_RMsb^UN~J3HO%-~aP}{MUc}3wzT1!yo?b-~aUwq%g>Y{g40nyWf6s@8*@u*Y1A#Pk;K;A3wR$ zuI5se^~+bm$?~y8sWx9@%QsvJkSUAV>SV<3IdbIP-hQpoI5XONglO)IuO4}utn}x8 z{4#;dpZ)b;{l#BC|I4GjeZ9xYE`+%x?SJ;!qubl<`tt23zxnF%dlwh$E4$Zk-y_ZE&ii*5 z_-^02etB)NIbTRd6XlDy-@ClhYAvzJg7~+qt7}`!wPG&jGE8cWu3$Lice{N~8@a&+ z+@Dq@n@FUK3vJ-=G?CFruC>0sy;h64Y{7K7T1-X#ZhxGJUp(yhdVJwTu2{?l44UEd zLnEW3V`C%d`+H9uKYIM^xK4Bah9?u)#=SPhsz^aG>}~&5{pNDE|)jpcgz_*$pxaE zWK892?TzanK4E$0KFEm7>323{;P~k4Z@*zDg-<{J=;N>d{@W)X-38|aBzkoJ-u}an zKYjE87}D)K_gR?o_|ZOy;nlTvy_89pFWkD%K+~uc*<^*+*U|wSkdDmEOwOR6xsDE7 zG&MWX$IcxuzIx*9K!0B!pv&v8fT+Co@=yQf`Ip}~Cc(aA-DK*Y>g(@6-F13&&Kq=S z&%ATwot{y1Aj<61ZUF-I1|pgAe2dvaYd#YV$BBjFi?ndk7D{=z0NAy&v(cP7U)moWc zYph-p`%bJoQCi#GzEI7?*_a70b$NAtjXA*L+U~C(eogZF69lTxSXb#-DZQG}`vT#J z*BwD4E7_=B%gSP3dVZ;q@>^#$BSYh!+RDZ4&2}m3B1%voj+x8m3OSO^tyXU&iYr0G z9E5j;qUh%+SA(jpg zrYA{eA&xwYmmA4tLzdYYX3@r(8RMMMXtaBMK97r$+aHN%3T(<)ip*hBoXPnM8!L+o zRaqCkc=_&w{r9$;nOJdY=N8KyR`NcF!xu}ZSuC@-xVTV=I_u57lNODii&`1&!g!!)bY%~%taawceHqQg)a?V$PEBDo3HM0UXK)w~-vnYlJ2^UV`izDINuODBZct+lr{Z3#(O`AhOh$5d zQYnV3e7;!9M$yPvJQntO{E(8tzOk^le)aCdhj({d`H)RNt+yqcD;pbYY(Z67#`$Yv zGOBFp1N{47|K@sY9*;enje8x$Xd_9+?OZ;ajE2MUj7(Kn%MUtE0-xRPjLo0O=KQz z4g`F}l`Iyg-)G0vPii$<-4sC|?W7LGf1n@qe`tJSY>Yh($4O=y>F@12d9t^!?@Vu3 zS9fp!xK2BA4y!*fcy5UFA>Gup5s*1kUs-Pi=KunOiEM?fHW$~nuUy@`!(!ma``Gu- zSl9K{mtTJU&9`5Fx_{^W+jlp`~>Ko`kb@JF-Zyr5CGrLcp9Uw7e z^z6x_?3_p-*D#|UJ$LHecgb~PdNVSvnILJT`$W&#b8KBOGBOJC$)tyggm%j8Ph@aV z!Gmlb5&Bd%n~D3KE`Jm^d9k@rF1I!=Uff(2SMlb(hY#Mrwsqmc&W-m!c<}hs&pvsy zf0qf6*UX*Ho*ft-8zay;G9e=|nd4@&1-xg+i7>W{ZW9*GHZgewRLjH z+W-_IR;7FfK&QRjWGDg?K#Wl|T*G>;QYz%q(Lh)nyj;GJjRgWxa?qQNYEIUON#a2j z-(#ViO{R0j>O#FfU&*DjMLe&i<>loI_&zJ`g(41Jdv%?iF&WCsX1rh@=BCJT3oIO$N6kJ9tnYrGd&=?2NZj5W^(l05a1)wxt2vYLqj9l**P2z-Nd*? zs~IB(F*H0pJgPOA$c91KH6x=sqj-IGphxo@YdZarXqfTWV#2CJL$f&I*i7UgoiA1A z7r<8L>rG0X@Gj%`+Um;c=B0~U>%_X*By?%1-69IrX!Bd2UudpwZf&fuG0UixS#A&1 zc##CSdNG}dC)fZb3mTlvR$5CCvB>fYvNU4Ra5NhB`+dx{?RJMS-exD5Yl6|(R(vk> z7jV_a91HI>h{&K7b_61Tx962iA1geyJ8?qsBtl^jdI;o{q8vgtON63KEZEynMg^~h zH(5PogGU2A;r4|y3>d5jgC?FZAU{x+QwTxCJxuVA8MM{r^e2#EY)+Wx3JZ0d|1cO# z#4DkBmOi9X@d)>ZqH$0_K%=;z-k7I20zmdRhJU^e#@B8yHX9_O6>=aJ;=)zu8vuW6 zYpcucW}S0x6A@WzHyJMEHY^(({L1#eXb=#Z(*fTYfQ%L*-=M?{vN}l!7#|%SpPUhT zVKNbN6NP0NHc)9im@rHZk_Dky3pr?Li~v6+g}k9w$dhT&P;=eixeP7 zJOm9>YBO=9 zCWeQgHf-izk}T>?#{NdF46`MBj?s;!raYfc(x-5Q-qX(l-U_Gz3=j@5e(E7kr4|O2`d7?E}?;-zt}5Wu2Q*N%x9<)xAJYfep+HRaPTZn~N%7|!}ki0A=t>jw}keO&a&C;|&7Ey_%MV;8` zx>hYARZx)&IfO|hkv2;UX)CfN48lp^B?ryLGRe-`BBGE&>KUN&yp$G78-sM7?gxTM zQ%9;g^yyqh4PXc}1v(XAoF=Y_u|kp14Jj=2quwWqba;f22~%*wl~_RFuoTrj+2vad zM@JLrBfX|BEFd8-pba5d$35KFDIHD;YgnF)*%7iITvirH46HCxxGl$=i2er@J>@lM zjHptF26@CkEyc4TS#;)@Ud3F?EQ(+9g(ok%Dv-;YctTioj6eZl~|x5fHIC zio>X4p;$&bu&$U1k#^MqF+3s}sz~=J)QRwl`H><=2o5)iL}StqN~bSMz(vR*C|sd2 zqEkX_>5un71SIoJirdv0kVFjRvg&|vQZ%mfth@`JN#R=vs*pFYXk9oEXw_b6b&`8J zMV^O)m=`4qFjtBYymLWV3!gDtqQiVo*pE<(Z4}K`k|}~E)d!NU>Qx(I5Op%p(j$7J z$d2>`8R=wvlV&J0O{0Zw&=y6bT23h)-W*U;Y{wxDpY~HUnm$5$d6_(?*r|FbZ&qKC z$DUFhWl<6g!KF?ZAVtV04B(kgQBSDvse4opMN2zFD&gyl%fcS2b57Y@@C~*`k2b1xgzFUMwibzz-0ZJ!N zi0*ZML~tnb6=4SChWLtE9Zm}?RKFBYlw`{VRjI1@*Ws;tQmQ&+Q1p;9p`9T7a^ZkR z>W)9V?V#rHae1YDMzKZOrKq74LC!k7?a)R2SNxN>Y{t}2#3Jyd6%%j&78H$ScW-Y35Mx$j+4RCw0!AA0oci~sZJu$Mpd voj>6IgO475>7X-*O?g_~sW^D=v#a0#kX-rBGk-?4!>9iL-|xTme?R|k;^Xap literal 0 HcmV?d00001 diff --git a/res/icon.png b/res/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb0d73f1e59622f8e66681d9003e3ed03e79576 GIT binary patch literal 3718 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 literal 0 HcmV?d00001 diff --git a/src/BestTimesDialog.java b/src/BestTimesDialog.java new file mode 100644 index 0000000..0f7379b --- /dev/null +++ b/src/BestTimesDialog.java @@ -0,0 +1,150 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.BorderFactory; + +public class BestTimesDialog extends JDialog implements ActionListener, WindowListener { + private static final long serialVersionUID = -459646110674871028L; + + private Minesweeper main; + + private JLabel bRecord; + private JLabel iRecord; + private JLabel eRecord; + private JLabel iName; + private JLabel bName; + private JLabel eName; + + public BestTimesDialog(Minesweeper main) { + super(main, "Fastest Mine Sweepers", true); + this.main = main; + setLayout(new BorderLayout()); + JPanel panelTop = new JPanel(); + JPanel panelBottom = new JPanel(); + Storage data = this.main.getStorage(); + this.bRecord = new JLabel(data.getRecord(this.main.BEGINNER) + " seconds"); + this.iRecord = new JLabel(data.getRecord(this.main.INTERMEDIATE) + " seconds"); + this.eRecord = new JLabel(data.getRecord(this.main.EXPERT) + " seconds"); + this.bName = new JLabel(data.getName(this.main.BEGINNER)); + this.iName = new JLabel(data.getName(this.main.INTERMEDIATE)); + this.eName = new JLabel(data.getName(this.main.EXPERT)); + panelTop.setBorder(BorderFactory.createEmptyBorder(15, 10, 15, 10)); + panelBottom.setBorder(BorderFactory.createEmptyBorder(0, 10, 15, 10)); + add(panelTop, "North"); + add(panelBottom); + panelTop.setLayout(new GridBagLayout()); + panelBottom.setLayout(new GridBagLayout()); + GridBagConstraints ct = + new GridBagConstraints( + 3, + 3, + 1, + 1, + 0.0, + 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.NONE, + new Insets(2, 10, 2, 10), + 0, + 0); + GridBagConstraints cb = + new GridBagConstraints( + 2, + 1, + 1, + 1, + 0.0, + 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.NONE, + new Insets(2, 10, 2, 10), + 0, + 0); + ct.gridx = 0; + ct.anchor = GridBagConstraints.WEST; + ct.gridy = 0; + panelTop.add(new JLabel("Beginner:"), ct); + ct.gridy = 1; + panelTop.add(new JLabel("Intermediate:"), ct); + ct.gridy = 2; + panelTop.add(new JLabel("Expert:"), ct); + ct.gridx = 1; + ct.gridy = GridBagConstraints.RELATIVE; + ct.weightx = 1.0; + ct.anchor = GridBagConstraints.CENTER; + ct.gridy = 0; + panelTop.add(this.bRecord, ct); + ct.gridy = 1; + panelTop.add(this.iRecord, ct); + ct.gridy = 2; + panelTop.add(this.eRecord, ct); + ct.gridx = 2; + ct.gridy = 0; + panelTop.add(this.bName, ct); + ct.gridy = 1; + panelTop.add(this.iName, ct); + ct.gridy = 2; + panelTop.add(this.eName, ct); + cb.gridx = 0; + cb.gridy = 0; + JButton reset = new JButton("Reset Scores"); + panelBottom.add(reset, cb); + reset.addActionListener(this); + cb.gridx = 1; + cb.gridy = 0; + JButton ok = new JButton("OK"); + panelBottom.add(ok, cb); + this.getRootPane().setDefaultButton(ok); + ok.addActionListener(this); + pack(); + setResizable(false); + Rectangle screenSize = getGraphicsConfiguration().getBounds(); + setLocation( + screenSize.x + screenSize.width / 2 - getSize().width / 2, + screenSize.y + screenSize.height / 2 - getSize().height / 2); + setVisible(true); + } + + @Override + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("Reset Scores")) { + Storage data = this.main.getStorage(); + data.setRecord(0, 999); + data.setRecord(1, 999); + data.setRecord(2, 999); + data.setName(0, "Anonymous"); + data.setName(1, "Anonymous"); + data.setName(2, "Anonymous"); + this.bRecord.setText("999 seconds"); + this.iRecord.setText("999 seconds"); + this.eRecord.setText("999 seconds"); + this.bName.setText("Anonymous"); + this.iName.setText("Anonymous"); + this.eName.setText("Anonymous"); + return; + } + this.dispose(); + } + + @Override + public void windowClosing(WindowEvent e) {} + + @Override + public void windowOpened(WindowEvent e) {} + + @Override + public void windowClosed(WindowEvent e) {} + + @Override + public void windowIconified(WindowEvent e) {} + + @Override + public void windowDeiconified(WindowEvent e) {} + + @Override + public void windowActivated(WindowEvent e) {} + + @Override + public void windowDeactivated(WindowEvent e) {} +} diff --git a/src/Board.java b/src/Board.java new file mode 100644 index 0000000..8ced168 --- /dev/null +++ b/src/Board.java @@ -0,0 +1,170 @@ +import java.awt.*; +import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.plaf.basic.BasicBorders.ButtonBorder; + +public class Board extends JPanel { + private static final long serialVersionUID = -8979636904753517635L; + + private Minesweeper main; + + private Tile[][] tiles; + + private int height; + private int width; + private int numOfMines; + + private void addMines() { + if (this.numOfMines >= this.width * this.height) { + this.numOfMines = this.width * this.height - 1; + } + int nextRow, nextCol; + int i = 0; + while (i < this.numOfMines) { + nextRow = Math.round((float) Math.random() * (this.height - 1)); + nextCol = Math.round((float) Math.random() * (this.width - 1)); + if (!this.tiles[nextRow][nextCol].isMine()) { + this.tiles[nextRow][nextCol].setMine(); + i += 1; + } + } + this.setTileValues(); + } + + private void setTileValues() { + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + if (this.tiles[i][j].isMine()) { + continue; + } + int mines = 0; + for (int k = i - 1; k <= i + 1; k += 1) { + for (int l = j - 1; l <= j + 1; l += 1) { + if (!(k < 0 || l < 0 || k >= this.height || l >= this.width) + && !(k == i && l == j) + && this.tiles[k][l].isMine()) { + mines += 1; + } + } + } + this.tiles[i][j].setValue(mines); + } + } + if (this.main.getStorage().isCreepy()) { + this.addDuds(); + } + } + + private void addDuds() { + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + if (this.tiles[i][j].isMine() && Math.round((float) Math.random() * 5) == 0) { + this.tiles[i][j].setDud(); + } + } + } + } + + public Board(Minesweeper main) { + this.main = main; + setBackground(new Color(192, 192, 192)); + setBorder( + BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(5, 5, 5, 5), + new ButtonBorder( + Color.white, Color.white, new Color(128, 128, 128), new Color(128, 128, 128)))); + } + + public Minesweeper getMain() { + return this.main; + } + + public int getMines() { + return this.numOfMines; + } + + public void setBoard(int width, int height, int mines) { + setVisible(false); + this.height = height; + this.width = width; + this.numOfMines = mines; + setLayout(new GridLayout(this.height, this.width, 0, 0)); + removeAll(); + this.tiles = new Tile[this.height][this.width]; + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + add(this.tiles[i][j] = new Tile(i, j, this)); + } + } + this.addMines(); + setVisible(true); + } + + public void expand(int row, int col) { + setVisible(false); + for (int i = row - 1; i <= row + 1; i += 1) { + for (int j = col - 1; j <= col + 1; j += 1) { + if (!(i < 0 || j < 0 || i >= this.height || j >= this.width) && !(i == row && j == col)) { + Tile tile = this.tiles[i][j]; + if (!tile.isUncovered() && !tile.isFlagged() && !tile.isUnsure() && !tile.isDud()) { + tile.uncover(true); + } + } + } + } + setVisible(true); + } + + public void showMines() { + setVisible(false); + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + Tile tile = this.tiles[i][j]; + if (tile.isMine() + && !tile.isUncovered() + && !tile.isFlagged() + && !tile.isUnsure() + && !tile.isDud()) { + tile.setTileIcon("covered mine"); + } else if ((!tile.isMine() || tile.isDud()) && tile.isFlagged()) { + tile.setTileIcon("misflagged"); + } + } + } + setVisible(true); + } + + public void showFlags() { + setVisible(false); + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + Tile tile = this.tiles[i][j]; + if (tile.isMine() && !tile.isUncovered() && !tile.isFlagged()) { + tile.setTileIcon("flagged"); + } + } + } + setVisible(true); + } + + public void removeAllMouseListeners() { + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + this.tiles[i][j].removeMouseListener(this.tiles[i][j]); + } + } + } + + public void checkWon(boolean expanding) { + for (int i = 0; i < this.height; i += 1) { + for (int j = 0; j < this.width; j += 1) { + Tile tile = this.tiles[i][j]; + if ((tile.isFlagged() && !tile.isMine()) + || (!tile.isUncovered() && !tile.isFlagged() && !tile.isMine())) { + return; + } + } + } + this.main.complete(expanding); + } +} diff --git a/src/CounterDisplay.java b/src/CounterDisplay.java new file mode 100644 index 0000000..7e6f237 --- /dev/null +++ b/src/CounterDisplay.java @@ -0,0 +1,75 @@ +import java.awt.*; +import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.plaf.basic.BasicBorders.ButtonBorder; + +public class CounterDisplay extends JPanel { + private static final long serialVersionUID = 8590228173889847000L; + + private Board board; + + private Digit hundred; + private Digit tenth; + private Digit first; + + private int mines; + + public CounterDisplay(Board board) { + this.board = board; + this.hundred = new Digit(this.board); + this.tenth = new Digit(this.board); + this.first = new Digit(this.board); + this.mines = this.board.getMines(); + this.updateDisplay(); + setBackground(new Color(192, 192, 192)); + setBorder( + BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(5, 5, 5, 5), + new ButtonBorder( + Color.white, Color.white, new Color(128, 128, 128), new Color(128, 128, 128)))); + setVisible(false); + setLayout(new GridLayout(1, 3, 0, 0)); + removeAll(); + add(this.hundred); + add(this.tenth); + add(this.first); + setVisible(true); + } + + public void increase() { + this.mines += 1; + this.updateDisplay(); + } + + public void decrease() { + this.mines -= 1; + if (this.mines < 0) { + this.negativeLoop(); + } else { + this.updateDisplay(); + } + } + + public void reset() { + this.mines = this.board.getMines(); + this.updateDisplay(); + } + + public void clear() { + this.mines = 0; + this.updateDisplay(); + } + + public void updateDisplay() { + this.hundred.setDigitIcon(String.valueOf(mines / 100)); + this.tenth.setDigitIcon(String.valueOf(mines / 10 % 10)); + this.first.setDigitIcon(String.valueOf(mines % 10)); + } + + public void negativeLoop() { + this.hundred.setDigitIcon("-"); + int temp = Math.abs(mines) % 100; + this.tenth.setDigitIcon(String.valueOf(temp / 10 % 10)); + this.first.setDigitIcon(String.valueOf(temp % 10)); + } +} diff --git a/src/CustomDialog.java b/src/CustomDialog.java new file mode 100644 index 0000000..5418eb5 --- /dev/null +++ b/src/CustomDialog.java @@ -0,0 +1,154 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.BorderFactory; + +public class CustomDialog extends JDialog implements ActionListener, WindowListener { + private static final long serialVersionUID = 3593586540539735229L; + + private Minesweeper main; + + private JTextField height = new JTextField(5); + private JTextField width = new JTextField(5); + private JTextField mines = new JTextField(5); + + private int hValue; + private int wValue; + private int mValue; + + public CustomDialog(Minesweeper main) { + super(main, "Custom Field", true); + this.main = main; + JPanel panel = new JPanel(); + Storage data = this.main.getStorage(); + this.hValue = data.getHeight(); + this.wValue = data.getWidth(); + this.mValue = data.getMines(); + this.height.setText(String.valueOf(this.hValue)); + this.width.setText(String.valueOf(this.wValue)); + this.mines.setText(String.valueOf(this.mValue)); + panel.setBorder(BorderFactory.createEmptyBorder(30, 10, 30, 10)); + add(panel); + panel.setLayout(new GridBagLayout()); + GridBagConstraints c = + new GridBagConstraints( + 3, + 3, + 1, + 1, + 0.0, + 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.NONE, + new Insets(2, 10, 2, 10), + 0, + 0); + c.gridx = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridy = 0; + JButton ok = new JButton("OK"); + panel.add(ok, c); + this.getRootPane().setDefaultButton(ok); + ok.addActionListener(this); + c.gridx = 3; + c.gridy = 2; + JButton cancel = new JButton("Cancel"); + panel.add(cancel, c); + cancel.addActionListener(this); + c.gridx = 0; + c.anchor = GridBagConstraints.EAST; + c.gridy = 0; + panel.add(new JLabel("Height:"), c); + c.gridy = 1; + panel.add(new JLabel("Width:"), c); + c.gridy = 2; + panel.add(new JLabel("Mines:"), c); + c.gridx = 1; + c.gridy = GridBagConstraints.RELATIVE; + c.weightx = 1.0; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.CENTER; + c.gridy = 0; + panel.add(height, c); + c.gridy = 1; + panel.add(width, c); + c.gridy = 2; + panel.add(mines, c); + pack(); + setResizable(false); + Rectangle screenSize = getGraphicsConfiguration().getBounds(); + setLocation( + screenSize.x + screenSize.width / 2 - getSize().width / 2, + screenSize.y + screenSize.height / 2 - getSize().height / 2); + setVisible(true); + } + + public boolean setValues() { + try { + this.wValue = Integer.decode(width.getText()).intValue(); + if (this.wValue < 9) { + this.wValue = 9; + } else if (this.wValue > 30) { + this.wValue = 30; + } + this.hValue = Integer.decode(height.getText()).intValue(); + if (this.hValue < 9) { + this.hValue = 9; + } else if (this.hValue > 24) { + this.hValue = 24; + } + this.mValue = Integer.decode(mines.getText()).intValue(); + if (this.mValue < 10) { + this.mValue = 10; + } else if (this.mValue > 668) { + this.mValue = 668; + } + } catch (NumberFormatException e) { + return false; + } + return true; + } + + public int getHeightValue() { + return this.hValue; + } + + public int getWidthValue() { + return this.wValue; + } + + public int getMinesValue() { + return this.mValue; + } + + @Override + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("Cancel") || this.setValues()) { + this.dispose(); + } + } + + @Override + public void windowClosing(WindowEvent e) { + this.dispose(); + } + + @Override + public void windowOpened(WindowEvent e) {} + + @Override + public void windowClosed(WindowEvent e) {} + + @Override + public void windowIconified(WindowEvent e) {} + + @Override + public void windowDeiconified(WindowEvent e) {} + + @Override + public void windowActivated(WindowEvent e) {} + + @Override + public void windowDeactivated(WindowEvent e) {} +} diff --git a/src/Digit.java b/src/Digit.java new file mode 100644 index 0000000..f4ffafa --- /dev/null +++ b/src/Digit.java @@ -0,0 +1,49 @@ +import java.awt.*; +import java.awt.image.BufferedImage; +import javax.swing.*; + +public class Digit extends JLabel { + private static final long serialVersionUID = -4719882476458914430L; + private Board board; + private BufferedImage image; + + private int value = 0; + + private final int HEIGHT = 23; + private final int WIDTH = 13; + + public Digit(Board board) { + super("", JLabel.CENTER); + this.board = board; + this.image = this.board.getMain().getImage().getDigit(); + this.setDigitIcon("0"); + setVerticalAlignment(JLabel.CENTER); + setHorizontalAlignment(JLabel.CENTER); + setPreferredSize(new Dimension(this.WIDTH, this.HEIGHT)); + } + + public int topMargin(String number) { + String[] numbers = { + "-", " ", "9", "8", "7", "6", + "5", "4", "3", "2", "1", "0" + }; + for (int i = 0; i < numbers.length; i += 1) { + if (numbers[i].equals(number)) { + return i; + } + } + return 1; + } + + public void setDigitIcon(String value) { + setIcon( + new ImageIcon( + this.image.getSubimage( + 0, this.HEIGHT * this.topMargin(value), this.WIDTH, this.HEIGHT))); + } + + public void setValue(int value) { + this.value = value; + this.setDigitIcon(String.valueOf(this.value)); + } +} diff --git a/src/Info.java b/src/Info.java new file mode 100644 index 0000000..00867d6 --- /dev/null +++ b/src/Info.java @@ -0,0 +1,43 @@ +import java.awt.*; +import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.plaf.basic.BasicBorders.ButtonBorder; + +public class Info extends JPanel { + private static final long serialVersionUID = 3806487248823604535L; + + private Board board; + private CounterDisplay counter; + private Smiley smiley; + private TimerDisplay timer; + + public Info(Minesweeper main) { + this.board = main.getBoard(); + this.counter = new CounterDisplay(this.board); + this.smiley = new Smiley(this.board); + this.timer = new TimerDisplay(this.board); + setBackground(new Color(192, 192, 192)); + setBorder( + BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(5, 5, 0, 5), + new ButtonBorder( + Color.white, Color.white, new Color(128, 128, 128), new Color(128, 128, 128)))); + setLayout(new BorderLayout()); + add(this.counter, "West"); + add(this.smiley, "Center"); + add(this.timer, "East"); + setVisible(true); + } + + public CounterDisplay getCounter() { + return this.counter; + } + + public Smiley getSmiley() { + return this.smiley; + } + + public TimerDisplay getTimer() { + return this.timer; + } +} diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..92e0e57 --- /dev/null +++ b/src/Main.java @@ -0,0 +1,5 @@ +public class Main { + public static void main(String[] args) { + new Minesweeper(); + } +} diff --git a/src/Menubar.java b/src/Menubar.java new file mode 100644 index 0000000..da68123 --- /dev/null +++ b/src/Menubar.java @@ -0,0 +1,118 @@ +import java.awt.event.*; +import javax.swing.*; + +public class Menubar extends JMenuBar implements ActionListener { + private static final long serialVersionUID = 865388774192274414L; + + private Minesweeper main; + + private JCheckBoxMenuItem creepy; + private JCheckBoxMenuItem sound; + + public Menubar(Minesweeper main) { + this.main = main; + JMenu game = new JMenu("Game"); + add(game); + JMenuItem newGame = new JMenuItem("New"); + game.add(newGame); + newGame.addActionListener(this); + game.addSeparator(); + Storage data = this.main.getStorage(); + JRadioButtonMenuItem beginner = + new JRadioButtonMenuItem( + "Beginner", (data.getDifficulty() == this.main.BEGINNER) ? true : false); + JRadioButtonMenuItem intermediate = + new JRadioButtonMenuItem( + "Intermediate", (data.getDifficulty() == this.main.INTERMEDIATE) ? true : false); + JRadioButtonMenuItem expert = + new JRadioButtonMenuItem( + "Expert", (data.getDifficulty() == this.main.EXPERT) ? true : false); + JRadioButtonMenuItem custom = + new JRadioButtonMenuItem( + "Custom...", (data.getDifficulty() == this.main.CUSTOM) ? true : false); + this.creepy = new JCheckBoxMenuItem("Creepy Mode", (data.isCreepy()) ? true : false); + game.add(beginner); + game.add(intermediate); + game.add(expert); + game.add(custom); + game.add(creepy); + ButtonGroup difficulties = new ButtonGroup(); + difficulties.add(beginner); + difficulties.add(intermediate); + difficulties.add(expert); + difficulties.add(custom); + beginner.addActionListener(this); + intermediate.addActionListener(this); + expert.addActionListener(this); + custom.addActionListener(this); + custom.setActionCommand("Custom"); + creepy.addActionListener(this); + game.addSeparator(); + this.sound = new JCheckBoxMenuItem("Sound", (data.isSoundEnabled()) ? true : false); + game.add(sound); + sound.addActionListener(this); + game.addSeparator(); + JMenuItem bestTimes = new JMenuItem("Best Times..."); + game.add(bestTimes); + bestTimes.addActionListener(this); + bestTimes.setActionCommand("Best Times"); + game.addSeparator(); + JMenuItem exit = new JMenuItem("Exit"); + game.add(exit); + exit.addActionListener(this); + } + + @Override + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("New")) { + this.main.newGame(); + } else { + Storage data = this.main.getStorage(); + if (cmd.equals("Beginner")) { + data.setDifficulty(this.main.BEGINNER); + this.main.newGame(); + } else if (cmd.equals("Intermediate")) { + data.setDifficulty(this.main.INTERMEDIATE); + this.main.newGame(); + } else if (cmd.equals("Expert")) { + data.setDifficulty(this.main.EXPERT); + this.main.newGame(); + } else if (cmd.equals("Custom")) { + CustomDialog dialog = new CustomDialog(this.main); + data.setDifficulty(this.main.CUSTOM); + data.setHeight(dialog.getHeightValue()); + data.setWidth(dialog.getWidthValue()); + data.setMines(dialog.getMinesValue()); + this.main.newGame(); + } else if (cmd.equals("Creepy Mode")) { + data.switchCreepy(); + if (!data.isSoundEnabled()) { + data.switchSound(); + this.sound.setSelected(true); + } + if (this.main.isGameStarted()) { + this.main.newGame(); + } + } else if (cmd.equals("Sound")) { + data.switchSound(); + if (data.isCreepy()) { + data.switchCreepy(); + this.creepy.setSelected(false); + this.main.newGame(); + } else if (this.main.isGameStarted()) { + PlaySound play = this.main.getPlay(); + if (play.isPlaying()) { + play.stop(); + } else { + play.tick(); + } + } + } else if (cmd.equals("Best Times")) { + new BestTimesDialog(this.main); + } else if (cmd.equals("Exit")) { + System.exit(0); + } + } + } +} diff --git a/src/Minesweeper.java b/src/Minesweeper.java new file mode 100644 index 0000000..61b75e2 --- /dev/null +++ b/src/Minesweeper.java @@ -0,0 +1,151 @@ +import java.awt.*; +import javax.swing.*; + +public class Minesweeper extends JFrame { + private static final long serialVersionUID = -711696178703199107L; + + private Board board; + private Info info; + private PlaySound play; + private Resource images; + private Storage data; + + private boolean gameStarted; + + private final String RES_GAME_ICON = "icon.png"; + + public final int BEGINNER = 0; + public final int INTERMEDIATE = 1; + public final int EXPERT = 2; + public final int CUSTOM = 3; + + private void setLocationCenter() { + Rectangle screen = getGraphicsConfiguration().getBounds(); + setLocation( + screen.x + screen.width / 2 - getSize().width / 2, + screen.y + screen.height / 2 - getSize().height / 2); + } + + public Minesweeper() { + super("Minesweeper"); + this.data = new Storage(); + this.images = new Resource(); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource(RES_GAME_ICON))); + setJMenuBar(new Menubar(this)); + setLayout(new BorderLayout()); + this.data = new Storage(); + this.board = new Board(this); + this.board.setBoard( + this.data.getWidth(), + this.data.getHeight(), + this.data.getMines()); // must call setBoard before create instances of Info + this.info = new Info(this); + this.play = new PlaySound(); + this.gameStarted = false; + add(this.info, "North"); + add(this.board); + pack(); + setResizable(false); + this.setLocationCenter(); + setVisible(true); + } + + public void newGame() { + this.board.setBoard(this.data.getWidth(), this.data.getHeight(), this.data.getMines()); + pack(); + if (this.isGameStarted()) { + this.info.getTimer().stop(); + if (this.data.isSoundEnabled()) { + this.play.stop(); + } + } + this.info.getCounter().reset(); + this.info.getSmiley().setSmileyIcon("smile"); + this.info.getTimer().reset(); + this.stopGame(); + } + + public void delGame() { + this.stopGame(); + if (this.data.isSoundEnabled()) { + this.play.stop(); + this.play.boom(); + } + this.info.getTimer().stop(); + this.info.getSmiley().setSmileyIcon("death"); + this.board.removeAllMouseListeners(); + this.board.showMines(); + } + + public Board getBoard() { + return this.board; + } + + public Info getInfo() { + return this.info; + } + + public PlaySound getPlay() { + return this.play; + } + + public Resource getImage() { + return this.images; + } + + public Storage getStorage() { + return this.data; + } + + public boolean isGameStarted() { + return this.gameStarted; + } + + public void startGame() { + this.gameStarted = true; + } + + public void stopGame() { + this.gameStarted = false; + } + + public void complete(boolean expanding) { + this.stopGame(); + this.info.getTimer().stop(); + this.info.getSmiley().setSmileyIcon("boss"); + this.board.removeAllMouseListeners(); + this.board.showFlags(); + this.info.getCounter().clear(); + if (this.data.isSoundEnabled() && !this.data.isCreepy() && !expanding) { + this.play.stop(); + this.play.win(); + } + if (this.isNewRecord() && !this.data.isCreepy()) { + new NewRecordDialog(this); + } + } + + public boolean isNewRecord() { + int seconds = this.info.getTimer().getTime(); + switch (this.data.getDifficulty()) { + case 0: + if (seconds < this.data.getRecord(this.BEGINNER)) { + return true; + } + break; + case 1: + if (seconds < this.data.getRecord(this.INTERMEDIATE)) { + return true; + } + break; + case 2: + if (seconds < this.data.getRecord(this.EXPERT)) { + return true; + } + break; + default: + } + return false; + } +} diff --git a/src/NewRecordDialog.java b/src/NewRecordDialog.java new file mode 100644 index 0000000..18f83fe --- /dev/null +++ b/src/NewRecordDialog.java @@ -0,0 +1,98 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.BorderFactory; + +public class NewRecordDialog extends JDialog implements ActionListener, WindowListener { + private static final long serialVersionUID = -7317311608209462993L; + + private Minesweeper main; + + private JTextField name; + + public NewRecordDialog(Minesweeper main) { + super(main, "", true); + this.main = main; + this.name = new JTextField("Anonymous"); + JPanel panel = new JPanel(); + add(panel); + panel.setLayout(new GridBagLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + GridBagConstraints c = + new GridBagConstraints( + 1, + 3, + 1, + 1, + 0.0, + 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.NONE, + new Insets(15, 15, 15, 15), + 0, + 0); + c.gridx = 0; + c.gridy = 0; + panel.add( + new JLabel( + "
You have the fastest time
for " + + this.getLevel() + + " level.
Please enter your name.
"), + c); + c.gridy = 1; + panel.add(this.name, c); + c.gridy = 2; + JButton ok = new JButton("OK"); + panel.add(ok, c); + this.getRootPane().setDefaultButton(ok); + ok.addActionListener(this); + pack(); + setResizable(false); + Rectangle screenSize = getGraphicsConfiguration().getBounds(); + setLocation( + screenSize.x + screenSize.width / 2 - getSize().width / 2, + screenSize.y + screenSize.height / 2 - getSize().height / 2); + setVisible(true); + } + + public String getLevel() { + switch (this.main.getStorage().getDifficulty()) { + case 0: + return "beginner"; + case 1: + return "intermediate"; + case 2: + return "expert"; + } + return ""; + } + + @Override + public void actionPerformed(ActionEvent e) { + Storage data = this.main.getStorage(); + data.setRecord(data.getDifficulty(), this.main.getInfo().getTimer().getTime()); + data.setName(data.getDifficulty(), this.name.getText()); + this.dispose(); + } + + @Override + public void windowClosing(WindowEvent e) {} + + @Override + public void windowOpened(WindowEvent e) {} + + @Override + public void windowClosed(WindowEvent e) {} + + @Override + public void windowIconified(WindowEvent e) {} + + @Override + public void windowDeiconified(WindowEvent e) {} + + @Override + public void windowActivated(WindowEvent e) {} + + @Override + public void windowDeactivated(WindowEvent e) {} +} diff --git a/src/PlaySound.java b/src/PlaySound.java new file mode 100644 index 0000000..742beac --- /dev/null +++ b/src/PlaySound.java @@ -0,0 +1,64 @@ +import java.io.*; +import java.net.URL; +import java.util.Timer; +import java.util.TimerTask; +import javax.sound.sampled.*; + +public class PlaySound { + private Timer timer; + + private boolean playing; + + private final String RES_TICK = "432.wav"; + private final String RES_WIN = "433.wav"; + private final String RES_BOOM = "434.wav"; + + public PlaySound() { + this.playing = false; + } + + public boolean isPlaying() { + return this.playing; + } + + public void play(String filename) { + URL f = getClass().getResource(filename); + try { + AudioInputStream in = AudioSystem.getAudioInputStream(f); + Clip clip = AudioSystem.getClip(); + clip.open(in); + clip.start(); + } catch (UnsupportedAudioFileException e) { + } catch (IOException e) { + } catch (LineUnavailableException e) { + } + } + + public void tick() { + this.playing = true; + this.timer = new Timer(); + TimerTask tt = + new TimerTask() { + @Override + public void run() { + play(RES_TICK); + } + }; + this.timer.scheduleAtFixedRate(tt, 0, 1000); + } + + public void win() { + this.play(this.RES_WIN); + } + + public void boom() { + this.play(this.RES_BOOM); + } + + public void stop() { + if (this.playing) { + this.timer.cancel(); + this.playing = false; + } + } +} diff --git a/src/Resource.java b/src/Resource.java new file mode 100644 index 0000000..c1127f5 --- /dev/null +++ b/src/Resource.java @@ -0,0 +1,42 @@ +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import javax.swing.*; + +public class Resource { + private BufferedImage digit; + private BufferedImage smiley; + private BufferedImage tile; + + private final String RES_TILE = "410.png"; + private final String RES_DIGIT = "420.png"; + private final String RES_SMILEY = "430.png"; + + private BufferedImage loadImage(String filename) { + BufferedImage image; + try { + image = ImageIO.read(getClass().getResourceAsStream(filename)); + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "Error: Image Loading Failed."); + image = null; + } + return image; + } + + public Resource() { + this.digit = this.loadImage(this.RES_DIGIT); + this.smiley = this.loadImage(this.RES_SMILEY); + this.tile = this.loadImage(this.RES_TILE); + } + + public BufferedImage getDigit() { + return this.digit; + } + + public BufferedImage getSmiley() { + return this.smiley; + } + + public BufferedImage getTile() { + return this.tile; + } +} diff --git a/src/Smiley.java b/src/Smiley.java new file mode 100644 index 0000000..3374919 --- /dev/null +++ b/src/Smiley.java @@ -0,0 +1,64 @@ +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import javax.swing.*; + +public class Smiley extends JLabel implements MouseListener { + private static final long serialVersionUID = -1028805830774712972L; + + private Board board; + private BufferedImage image; + + private final int SIZE = 24; + + public Smiley(Board board) { + super("", JLabel.CENTER); + this.board = board; + this.image = this.board.getMain().getImage().getSmiley(); + this.setSmileyIcon("smile"); + addMouseListener(this); + setVerticalAlignment(JLabel.CENTER); + setHorizontalAlignment(JLabel.CENTER); + setPreferredSize(new Dimension(this.SIZE, this.SIZE)); + } + + public int topMargin(String state) { + String[] states = {"smile down", "boss", "death", "oops", "smile"}; + for (int i = 0; i < states.length; i += 1) { + if (states[i].equals(state)) { + return i; + } + } + return 3; + } + + public void setSmileyIcon(String state) { + setIcon( + new ImageIcon( + this.image.getSubimage(0, this.SIZE * this.topMargin(state), this.SIZE, this.SIZE))); + } + + @Override + public void mousePressed(MouseEvent e) { + if (SwingUtilities.isLeftMouseButton(e)) { + this.setSmileyIcon("smile down"); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (SwingUtilities.isLeftMouseButton(e)) { + this.setSmileyIcon("smile"); + this.board.getMain().newGame(); + } + } + + @Override + public void mouseExited(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseClicked(MouseEvent e) {} +} diff --git a/src/Storage.java b/src/Storage.java new file mode 100644 index 0000000..d618351 --- /dev/null +++ b/src/Storage.java @@ -0,0 +1,178 @@ +import java.io.*; + +public class Storage { + private int difficulty; + private int height; + private int width; + private int mines; + private boolean creepy; + private boolean soundEnabled; + private int[] records; + private String[] names; + + private final int NUM_OF_DIFFICULTIES = 3; + private final String DATA_FILE = "Minesweeper.dat"; + + private void open(final String filename) throws FileNotFoundException, IOException { + DataInputStream in = new DataInputStream(new FileInputStream(filename)); + this.difficulty = in.readInt(); + this.height = in.readInt(); + this.width = in.readInt(); + this.mines = in.readInt(); + this.creepy = in.readBoolean(); + this.soundEnabled = in.readBoolean(); + for (int i = 0; i < NUM_OF_DIFFICULTIES; i += 1) { + this.records[i] = in.readInt(); + this.names[i] = in.readUTF(); + } + in.close(); + } + + public Storage() { + this.records = new int[this.NUM_OF_DIFFICULTIES]; + this.names = new String[this.NUM_OF_DIFFICULTIES]; + try { + this.open(this.DATA_FILE); + } catch (Exception e) { + this.difficulty = 0; + this.height = 9; + this.width = 9; + this.mines = 10; + this.creepy = false; + this.soundEnabled = false; + this.records = new int[] {999, 999, 999}; + this.names = new String[] {"Anonymous", "Anonymous", "Anonymous"}; + try { + this.save(this.DATA_FILE); + } catch (Exception v) { + } + } + } + + public void save(final String filename) throws FileNotFoundException, IOException { + DataOutputStream out = new DataOutputStream(new FileOutputStream(filename)); + out.writeInt(this.difficulty); + out.writeInt(this.height); + out.writeInt(this.width); + out.writeInt(this.mines); + out.writeBoolean(this.creepy); + out.writeBoolean(this.soundEnabled); + for (int i = 0; i < NUM_OF_DIFFICULTIES; i += 1) { + out.writeInt(this.records[i]); + out.writeUTF(this.names[i]); + } + out.close(); + } + + public int getDifficulty() { + return this.difficulty; + } + + public int getHeight() { + return this.height; + } + + public int getWidth() { + return this.width; + } + + public int getMines() { + return this.mines; + } + + public boolean isCreepy() { + return this.creepy; + } + + public boolean isSoundEnabled() { + return this.soundEnabled; + } + + public int getRecord(int difficulty) { + return this.records[difficulty]; + } + + public String getName(int difficulty) { + return this.names[difficulty]; + } + + public void setDifficulty(int difficulty) { + this.difficulty = difficulty; + switch (difficulty) { + case 0: + this.height = 9; + this.width = 9; + this.mines = 10; + break; + case 1: + this.height = 16; + this.width = 16; + this.mines = 40; + break; + case 2: + this.height = 16; + this.width = 30; + this.mines = 99; + } + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void setHeight(int height) { + this.height = height; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void setWidth(int width) { + this.width = width; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void setMines(int mines) { + this.mines = mines; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void switchCreepy() { + this.creepy = !this.creepy; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void switchSound() { + this.soundEnabled = !this.soundEnabled; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void setRecord(int difficulty, int score) { + this.records[difficulty] = score; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } + + public void setName(int difficulty, String name) { + this.names[difficulty] = name; + try { + this.save(this.DATA_FILE); + } catch (Exception e) { + } + } +} diff --git a/src/Tile.java b/src/Tile.java new file mode 100644 index 0000000..3f0aa05 --- /dev/null +++ b/src/Tile.java @@ -0,0 +1,199 @@ +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import javax.swing.*; + +public class Tile extends JLabel implements MouseListener { + private static final long serialVersionUID = -6873580061751396083L; + + private Board board; + private BufferedImage image; + + private boolean uncovered; + private boolean flagged; + private boolean unsure; + private boolean dud; + + private int row; + private int col; + private int value; // -1~8 (-1: mine) + + private final int SIZE = 16; + + public Tile(int row, int col, Board board) { + super("", JLabel.CENTER); + this.board = board; + this.image = this.board.getMain().getImage().getTile(); + this.uncovered = false; + this.flagged = false; + this.unsure = false; + this.dud = false; + this.row = row; + this.col = col; + this.setValue(0); + this.setTileIcon("covered"); + addMouseListener(this); + setVerticalAlignment(JLabel.CENTER); + setHorizontalAlignment(JLabel.CENTER); + setPreferredSize(new Dimension(this.SIZE, this.SIZE)); + } + + public int topMargin(String state) { + String[] states = { + "covered", + "flagged", + "unsure", + "-1", + "misflagged", + "covered mine", + "unsure down", + "8", + "7", + "6", + "5", + "4", + "3", + "2", + "1", + "0" + }; + for (int i = 0; i < states.length; i += 1) { + if (states[i].equals(state)) { + return i; + } + } + return 6; + } + + public void setTileIcon(String state) { + setIcon( + new ImageIcon( + this.image.getSubimage(0, this.SIZE * this.topMargin(state), this.SIZE, this.SIZE))); + } + + public int getValue() { + return this.value; + } + + public boolean isMine() { + return (this.value == -1 || this.dud); + } + + public boolean isUncovered() { + return this.uncovered; + } + + public boolean isFlagged() { + return this.flagged; + } + + public boolean isUnsure() { + return this.unsure; + } + + public boolean isDud() { + return this.dud; + } + + public void setValue(int value) { + this.value = value; + } + + public void setMine() { + this.value = -1; + } + + public void setDud() { + this.dud = true; + } + + public void uncover(boolean expanding) { + this.uncovered = true; + Minesweeper main = this.board.getMain(); + if (this.value >= 0 || this.isDud()) { + if (this.isDud()) { + this.setTileIcon("unsure down"); + } else { + this.setTileIcon(String.valueOf(this.value)); + } + if (this.value == 0 && !this.isDud()) { + this.board.expand(row, col); + } + if (main.getStorage().isCreepy() + && !this.isDud() + && !expanding + && Math.round((float) Math.random() * 10) == 0) { + main.getPlay().boom(); + } + this.board.checkWon(expanding); + } else { + this.setTileIcon("-1"); + main.delGame(); + } + } + + public void uncover() { + this.uncover(false); + } + + public void toggleFlagged() { + Info info = this.board.getMain().getInfo(); + if (!this.flagged && !this.unsure) { + this.flagged = true; + this.setTileIcon("flagged"); + info.getCounter().decrease(); + } else if (this.flagged) { + this.flagged = false; + this.unsure = true; + this.setTileIcon("unsure"); + info.getCounter().increase(); + } else { + this.flagged = false; + this.setTileIcon("covered"); + if (!this.unsure) { + info.getCounter().increase(); + } + this.unsure = false; + } + } + + @Override + public void mousePressed(MouseEvent e) { + Minesweeper main = this.board.getMain(); + if (!main.isGameStarted()) { + main.startGame(); + main.getInfo().getTimer().start(); + if (main.getStorage().isSoundEnabled() && !main.getStorage().isCreepy()) { + main.getPlay().tick(); + } + } + if (SwingUtilities.isLeftMouseButton(e) && !this.uncovered && !this.flagged) { + this.setTileIcon("0"); + } else if (SwingUtilities.isMiddleMouseButton(e)) { + if (!this.flagged) { + this.setTileIcon("0"); + } + main.getInfo().getSmiley().setSmileyIcon("oops"); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + this.board.getMain().getInfo().getSmiley().setSmileyIcon("smile"); + if ((SwingUtilities.isLeftMouseButton(e) || SwingUtilities.isMiddleMouseButton(e)) + && !this.flagged) { + this.uncover(); + } else if (SwingUtilities.isRightMouseButton(e) && !this.uncovered) { + this.toggleFlagged(); + } + } + + @Override + public void mouseExited(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseClicked(MouseEvent e) {} +} diff --git a/src/TimerDisplay.java b/src/TimerDisplay.java new file mode 100644 index 0000000..f509aad --- /dev/null +++ b/src/TimerDisplay.java @@ -0,0 +1,83 @@ +import java.awt.*; +import java.util.Timer; +import java.util.TimerTask; +import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.plaf.basic.BasicBorders.ButtonBorder; + +public class TimerDisplay extends JPanel { + private static final long serialVersionUID = -1661506846325986431L; + + private Board board; + private Timer timer; + + private Digit hundred; + private Digit tenth; + private Digit first; + + private int seconds; + private boolean stopped; + + public TimerDisplay(Board board) { + this.board = board; + this.hundred = new Digit(this.board); + this.tenth = new Digit(this.board); + this.first = new Digit(this.board); + setBackground(new Color(192, 192, 192)); + setBorder( + BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(5, 5, 5, 5), + new ButtonBorder( + Color.white, Color.white, new Color(128, 128, 128), new Color(128, 128, 128)))); + setVisible(false); + setLayout(new GridLayout(1, 3, 0, 0)); + removeAll(); + add(this.hundred); + add(this.tenth); + add(this.first); + setVisible(true); + } + + public int getTime() { + return this.seconds; + } + + public void start() { + this.stopped = false; + this.timer = new Timer(); + TimerTask tt = + new TimerTask() { + @Override + public void run() { + increase(); + } + }; + this.timer.scheduleAtFixedRate(tt, 0, 1000); + } + + public void stop() { + if (!this.stopped) { + this.timer.cancel(); + this.stopped = true; + } + } + + public void increase() { + this.seconds += 1; + if (this.seconds >= 999) { + this.stop(); + } + this.updateDisplay(); + } + + public void reset() { + this.seconds = 0; + this.updateDisplay(); + } + + public void updateDisplay() { + this.hundred.setDigitIcon(String.valueOf(seconds / 100)); + this.tenth.setDigitIcon(String.valueOf(seconds / 10 % 10)); + this.first.setDigitIcon(String.valueOf(seconds % 10)); + } +}