From ada144ef743660fbf3a577830ffe9bb4b1256afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Latner?= <matyas.latner@nic.cz> Date: Mon, 19 Jan 2015 16:45:40 +0100 Subject: [PATCH] Rules for generating creatures lines. Game data loader implementation. --- android/assets/badlogic.jpg | Bin 68465 -> 0 bytes core/src/cz/nic/tablexia/TablexiaLibGDX.java | 174 +++++++- .../nic/tablexia/creature/CreatureRoot.java | 86 +++- .../tablexia/difficulty/GameDifficulty.java | 71 ++++ core/src/cz/nic/tablexia/rules/GameRule.java | 380 ++++++++++++++++++ .../nic/tablexia/rules/GameRuleUtility.java | 191 +++++++++ .../tablexia/rules/GameRulesDefinition.java | 212 ++++++++++ .../nic/tablexia/rules/easy/BC_1_BCRule.java | 129 ++++++ .../nic/tablexia/rules/easy/Bb_0_BbRule.java | 40 ++ .../nic/tablexia/rules/easy/Bt_0_BtRule.java | 129 ++++++ .../cz/nic/tablexia/rules/easy/CACARule.java | 63 +++ .../cz/nic/tablexia/rules/easy/CACCRule.java | 70 ++++ .../tablexia/rules/easy/CA_0_CC_0_TRule.java | 108 +++++ .../cz/nic/tablexia/rules/easy/CCCCRule.java | 94 +++++ .../tablexia/rules/easy/CC_0_CC_0_TRule.java | 59 +++ .../tablexia/rules/easy/CC_0_notCCRule.java | 148 +++++++ .../nic/tablexia/rules/hard/Bb_1_BbRule.java | 40 ++ .../nic/tablexia/rules/hard/Bt_1_BtRule.java | 37 ++ .../tablexia/rules/hard/CCCCnotCCRule.java | 126 ++++++ .../tablexia/rules/hard/CC_0_CC_0_CCRule.java | 123 ++++++ .../rules/hard/CC_0_notCA_0_TRule.java | 71 ++++ .../rules/hard/CC_0_notCC_0_TRule.java | 139 +++++++ .../nic/tablexia/rules/hard/CC_2_CCRule.java | 37 ++ .../tablexia/rules/medium/BC_2_BCRule.java | 37 ++ .../tablexia/rules/medium/CA_1_CCRule.java | 58 +++ .../nic/tablexia/rules/medium/CCCCCCRule.java | 115 ++++++ .../tablexia/rules/medium/CC_1_CCRule.java | 125 ++++++ .../tablexia/rules/medium/CC_1_notCARule.java | 73 ++++ .../tablexia/rules/medium/CC_1_notCCRule.java | 37 ++ .../nic/tablexia/desktop/DesktopLauncher.java | 2 + .../src/cz/nic/tablexia/GdxDefinition.gwt.xml | 4 + .../tablexia/GdxDefinitionSuperdev.gwt.xml | 4 + 32 files changed, 2953 insertions(+), 29 deletions(-) delete mode 100644 android/assets/badlogic.jpg create mode 100644 core/src/cz/nic/tablexia/difficulty/GameDifficulty.java create mode 100644 core/src/cz/nic/tablexia/rules/GameRule.java create mode 100644 core/src/cz/nic/tablexia/rules/GameRuleUtility.java create mode 100644 core/src/cz/nic/tablexia/rules/GameRulesDefinition.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/BC_1_BCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/Bb_0_BbRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/Bt_0_BtRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/CACARule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/CACCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/CA_0_CC_0_TRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/CCCCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/CC_0_CC_0_TRule.java create mode 100644 core/src/cz/nic/tablexia/rules/easy/CC_0_notCCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/Bb_1_BbRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/Bt_1_BtRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/CCCCnotCCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/CC_0_CC_0_CCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/CC_0_notCA_0_TRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/CC_0_notCC_0_TRule.java create mode 100644 core/src/cz/nic/tablexia/rules/hard/CC_2_CCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/medium/BC_2_BCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/medium/CA_1_CCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/medium/CCCCCCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/medium/CC_1_CCRule.java create mode 100644 core/src/cz/nic/tablexia/rules/medium/CC_1_notCARule.java create mode 100644 core/src/cz/nic/tablexia/rules/medium/CC_1_notCCRule.java diff --git a/android/assets/badlogic.jpg b/android/assets/badlogic.jpg deleted file mode 100644 index 4390da6e0f6d041590c6313d2b4c978abc00a342..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68465 zcmbq)^Lrgmu=k14*yf3?6E`;6*tTsowrx8(v2ELIY&2}rB+c9J``r5%+}Y>ZUuJe@ zHH**Aey)G+0nlV6Wh4O*5D)<Ae+lsU7l0||Y-Z$YW=iH^<!VVLC8O~Da|<B$pUD4- z{!{XQQt)5l&wc<pJOls&00lt-fJBFYLWlSq29N>(5YSNn@d5us2mm;EL>SmF&`^;7 z2`HldC-AQc@DLEtkjQYz02nA}SU3nscmx0<ItC^dHV!U18y*Ff2muhElA4xXNm<j# zDKTSJH83r`VP&0$gPTWGO+(AWv!(UdKYb+ss__2}{;xd%02U4&0RjdQ8WQRsUjqFf z9|8&r5(W|q1_}WI@UOm*&@iw7ICS`b*2odCDcD4ClqijyaDnWJzo<k5sX0MB&Tb9O zcjC$_?jFfat^1#w03;}ge~pAf2M7Tm1o?*qZZ7<WkUC0p1Bs$sKV<PXsO%1ffuoxW zYnLbyr{$wqyQKJ0vG~NElNHc*A$qVQ`N8(*PT*1uk4{><tFW_Kw*AM0`wl8Q-A%4- zm+U`_H78x<3;1V|S7p0D*2(JFnHbF#^dt_+3e&vdT?CF_f7G~pKsi4T#2{h~t7v*r zI7cund{wF8@5F@q(NlcZj^Q?iGf+TNUA3>7(ntY=-`zO+9n1HCdK=ttGSPgaMd6-S zdD9t!!mq@QU~+7or#N{(H=pM7;_|xVqVUz6-6>kx63a~pF9x#nS|XSp{W{tyF1i)D zWLEYLZuF;RUKcVXup4ZtEP%y7QBtTp8Y{F|N9=p!Grl7w(XY~I?E7k@k<((`AuB}| zD|>DD>ry4@;%jVuC=HzjQuNT|48}Y7J3WtvC0@mWX)9Lo_;WFu9(aqXWm=c#UE`}O zKS9)T&H2Vk<N}vkyy6fO+I^+RZpFGA2S1uVgqfnDy>^HV1L=Id^n%^duZb`*^oS|5 z7}x}JPjN<Zg?51^y;X%orH#GI&ZLTFtFe})cKKZ}SZk~Vo>F<lgtcm0L=d5q4|wEH zju$Q&j0&x((hxTmEt42FoW*$F6<<?6>DEG%Cwhdz$M<8C92%G21hX`J=^${)m_$*( zjhrE|7!h$VU}ZA8W?09}6gonXEaE$Q#FCm)tb~a%OcocF#LMI9SzY4anQBv`<D{?t zM_%b#nKme*((}O40Q5rh#rA1PtUq=Ucd!Q>RMe}~qfRtNL=#xWJ`?(*o9sgExm&%d zp8&{TEs^Wp(vaWa+YeLH?M7|Pg4Y~<Ai0{$p!idtLJpIoTRn^>3r2s*c1s_tur+8m zuhMi68B!nqA}*=Gvi>u?>@(xrx|{qpN2+vP{c+oVob00C$&ejN<IA+-Psz>oN%bF> z#$;A1A}3Jg#U)ATaNo7M?3&H>h7##xnAe>^{8$`Qxo?<##lOohsx)g_AqU~VmO;zb zkVe??Y_{;f%8PkVGPBLEvi-I#x!_Ai2lj2lkCz<HOakqr#uYQD9~bKC@b8b26F!hV zexePoaw?`p4s*h3Bc#$niK=inQP~y^>`s{0LS@je(qSUk<jL086T~sw%Z}30iCziw z2&RI#pSYt3e&dQuqAHrk9#VNtidea*1g>H0FWaKb3XLx^+*4}mmQ6^gYY%Z_Hs^_T zeC$aF^KGZ3c}99vb)Z$d791B*h3>9qHmP4mj0EVa@7qn*#A>hxiR{^qiTs4sQLhWd zvxSc;ZNp`WmxT$;kSYz@<p7aLL%Wp4HCuGxu)KHgNu})!79}1O7RJ?J*k?u4PudV$ zJ5Jye{@yTO6Pb;Qc3(o$uc$(Zw`Nmav=1A%6f<Zyn!G4!A}YuzHL;bFvvQ4c4+*M9 z%``!lRPI$Rr*RJBK$9JzkDa;iwsmeGidzmlZ!<P}g2^RCOz&tXSr>4lZiqC=-Kcd0 zm$sVXkrfwV6l|EekR>OH8I}~_8%d@)Hi`x9Uvkf)li+db8l3GYt6VV!vSyNJDY)Y( zc;VFU;F{C9YO|#vGsAa-4Xq|<6x0BSY-Hh74+K~5i4<2Gbp*`6@5MdF;0g9Hchj9y zP84i(l@Ui=DRD#8d+5Yh3rrGV^mTory$M8P63!2CoU4TslWzvm@0K_cMl&-fJ`lwH z7GHkz^y_eVv4^TUoebkDHBm)~P;6T6yC%O@0rOPg%UoI`PY>t%@W#5{KP(N>@8bW; zNPPm%1ROpAj^4J$4pyfyjfQ)f0^_$Dl&DxJ32+R=n~zqaaBP!nlvzho^eq#EMJxh} z)t`XS8Fe~yYx(kO<fu`w2`eyJDZr85hZRLQ%u!&T(T-9M69uk$z-4%uHgAwkcZ}ka zt(JE%{&n=_yLk6edhs6n0_34Y=v+b9vNL=GezlP|dd$%J*zSx1u_Kui_XhKg^E~{% z{auk$@He71c1T+nAw*}@-mC%}uM%cm=gUiN#eXBz`cioT5wtY7w<__Zp}tUiIa3Tn zI5mcw_F(n9Rp%gV6U_;+QL_BYDnCWo&0j?!oLXMKvz_&`tc2A@Y)&QhH<5hq_;i~T zZ4>!!3sSqZ=^c<wStPjk6JX&ur}i{ieO+}~+t^MmXt3NZ3Go5kxcdI6n&KWnSXIlx z8gU-^D2r*-x~>;b_+ti<-P4@%_dZn&0xJ_PLst|7R~l9rKiYx)g{XvGl)Zwa0@n&m zq=|%Q|Lb2B7s5qpo~+#i41($vAg7&_;Is=M08?K*bP%0ny{+#9^9D3#yti$s1&iC+ zr9nM)Y_N&5vGcdEtSV2ro{hrP))4l>d72H5h#lI7pmjz-_CX8LbzSL5C|!fnh1DN5 zT%T*cnqSU9F15wROfY?%5~Wa<K1KK_-_K^epQqvha@{s+poL6XgE_eyc-=Qiz|6c; zTnc2{d<=DhVm3Y5pb{cWZ0;qIwe#$g94$|ShOg`IHpZPD-CvAQ<phvfko|H|#-C{+ zL`$hJX)lS?<R9G3GHL}I-+cnat0!}VfhQll$(+~lljH@D$#0kR8^F?wiG>KOFC!s) ze?ou%^tvB%{nG~bWD~2()O!151>W+-v*YcRn388${+`Dge$KOU*f+kM7ijGyrE_(+ zd#D@YEbsFi5x?#}PS&L^B)d;jyS5(f##&5s+qPjZZfjo4C?aR&`ILmWn^uD8f{YmA zJkCzz5>A{aM37iaa~B0s#f7lDT3p_fRr{0iZr!ZxWKTy8&$X3XsKNtwqlGK!Cm<nY zGinfB9Nz;2!+6S+eJU)UG0=i3gy8__-2Q=zwlDcqCzNyA!5PdhdH}TE7OSzL?@A=G zp~Ne|QK)BR6ehC6bJe@A%yc8gu=3LSEzQ(Hb6<|YYmEe5*|WdP%oQtNxMK8taP)|s zOBn88TI@MgChwj0CEU!|9r}g^_q*__Qn+VAAfZ4lW?U*QdW#2}H;QrP0|d-e<ar|e zZ=Shq0WaiGRcD-`HHD^?@BxagvmG~;*UFMIRroxo*7L)|u`c}oJlnTMKLAYi-HR2# zN=xLsk1ltC)!$wKxW!8o<Le|SLqIWHIW&Lk5rH=FEp1s*m*o+$!x2$aQYumSs73x! zpk<P_V*dm{YLjyelQv-p-!+l)!PAGOsqEsh$s1Puc}Gzik-d+et-1ejzfI}&{J@8y zqP1aiFcxgYPNKjJ0Matp*d1mmc=x)V&4O)H$i+y+(#LZmuceIr`UN)lu4c(gygsJ? zvS>X~Z2v;NRkx}*TD8ZD{b}id?5MfepgB#zQxv$FY<k=dVWdMnQVb03U?Zo<?%=hc zm^&dsNbjfr8W^#%dM%~a)D^qbnuF$-0XdX4VVpHOs%XSv*&Qc_01G4zYA;uYUp_Bx z__nV|j2JUcu{U(_a;68V0v_qbkEw+L(J~8oXSiS~Vlv~wkb|I|ygvabZt<MM;R;XW zWw3oZ%3W5yk+s2g1l=#qT41*G=~OS^nat2j+`SPO<lR}IRZ1#6t#>OgP7p!n+*kp- z8dt(7C0!(ur08A2FWUH7Okr`mW=l-G_Jrcis)gYnHi_d=|0v&8Rn_1mDyOLEV<CX< zw#uJ22c!L)6x)o4P1bX@?#g@dW;cWG&!((@dDM!ys_ODgz1LwR11Z@e-=YF_0P!gv z8v6roF|buvBIU0l2wS4NIeTqApD!9Vu28VG#7Mcee<EwGR=kig1KFD%A#H*y=DIO0 z*0Ux}yE&%i@)ZfPw7$4RVq?V?_7x02X;b-P1=W6tad0JbB`Tf)4_(h}vP7eqA!b(A zpQx`t?Hv}x1y}W5CGS+Vq<{KC#DfgJr<OCLm$ee1J|!-ScKtGJiaJ6yzr~j;_))Ir zRw8i+i{xfzN>Gc}c?4Hsbo$&@BhS#}I~!}zaz9Lmf5I?HU*JfKgw$o5`!!DIF>95@ z3GGgFi`(x*f>TxQzkYwO%yK8%?3|_!l!P#QQ_Lt(@WZGZ(&P>?cQ2kDrDO?xBX;*0 za^jvT@oqG?fa`PNK@RGRLpvECBG<&o*5a<yX`On3N2GAZQ>l39F8GMjqJ=r?;^e*@ z8Dt$%Ya_{wh!d!`7t$Vxuzh^gGA7c(6X#Xk;)@a*8dpq)Y~ia5xS$Zl&Oq^X`PTWN z(kui_kn&>kM{3q+yvSvT97Kq4dq7Qwz<liYJU*N>?euXcmMd#lI~iSty+^_?zV5fd z>(32N4JHX4ekG7x4IF5b35_7AeO^2u^q|CZ=c9Z<wnS<s^8w*sgHfSZD$-9t!Cl|S zz@_$P=t;F6a-Nzq4*Dw;^+jzVJXSnIw^4j{m^3d7q3e@bR_kD8MV3!lgv7XI@7DhP zW<^lv>rnSX|B>GfRqDdvjR~<4MSVyVw)fq1IK31lUXEiPjx=SeUr4u&i`B2`jwXze zP5&Z3{~dusfEVP@`9p={ZA}I=Mm0U`n6`LAK;;e1wCS=KCc%pDkw)?N=(fGDOg=uY z3a&>IgVmzlCR7*xmev#|C<@KQ3*U$r<F4Yy>_x!^w<Mb0!<_1rddw+;u};ke#m@KP z;vx+qJdx^hi5(8<6sknO3p&5nXKdT*ZY%vU=0J?pv{KiR8vV<u?qWEr&XJK*>72AY z(i}I&Fc9~Bm2qakN@T)v18!^Ji!$%3U*F<8x4Dc;n&hQU$nYqmI~Kuk3pw9333eS2 zyO6+e`@79Ze)Avl_-aZAaw^g5RJ~}!2g!<drKlolyXWfna@{A+sCg>F>PlQEIRY8{ zoc0<stSfypP4V*joWw;!P{;@s(-Z|@50=KXh&_y`6N&<knw`K9N1WfCX@mdi8SUCg zvc4{X&ha?1ES`+{7GLrc@XtRfii(O_u6(pb62bU*V=XhX2h*(Y*$@-<_3xu;{({LS zOEX$73g$5JAn19=I&`h6jJpJT{6iTCWE@*DNK=kHx?ziHuerEclOQSILiG|SbLl!T zXTs#xS`)-bF*$uBdIXE*!znA4wgjp=NL$lbh04lYcA8ZwXHo!#aozDlgP6fn>Qw4C z3B#VETG|@X08*Rb624yU_HV7MAVMKHK3R5>5VP(o2IYYgE3r=iE?wj+H%NEnD9>MD zBaM+r*m&SjiRs4#5T=yUXh-5W?;u2y$;p9kQ*nXDh1SMK-NH&kPQFa#5k*reTkn!i z<`|h%HCnHR$JAJ(tV4n8?*)11MNJtyxXLP3C^as$)X2gZooB|Wn%Ep;W5v~U#e$HZ zrpT-*5xIXVc2QZmW;;EIkC9W?!jv_-d_qcb=wJyi%aFRrEs^1R(MC}`J?XXb6A&M1 zwt|gpULGLKM-f|BCN4)3%b?K{rkkMOnc6^#9?2SAN@MM)*eoD3P)WB@2pd9#>r1Pu z$xhkI9Powzn8a=_-V*t@0c`VQTYy7Tt?g+t=3V&rnQa<WZW<NY8)g(*f$_vGvUWRZ ztTefjTbWL~`>?2JZp(8S6n4sEeJAYG#S{|Ww_JHKMc%k%9_c5IBzBHQO;4*m_>|_# zoNOs((}f0*>3%^H0k;e%=hxc<`!dHo*JrC^0?#`3Pk{Lc?_ut9;79h^-={y-yy^aO zFB*IKjh_Irx3#`!q0LXgun^@RgW%iz0|SvepQK02wZZpeup{~iQKpxw5#w`mWlyZX z+HdWpp@pLUNm*;_!$fmw3~-Rt!GPWfg||>I6(pJ&B|itBj);OHA3cLc<Y@4f-na3b z4XnZr_SK?cZ3UGUvAOMU*v+QsF5<+}g)E1{`3HQXG}y7Mu@cVTZs}n$WRBYZp7Z=U zXe@1ZUB)9;b~|P^VLcttef$LEy{>bz@<-y6K?kZC*d;?GO^XR1-cS5c(E_#3P+_pC z<q$WBYT1LUZAh(JW0$rNef{6YCKX~`ltrx$h@NKe;QIw?Gcxh0R5H$A%;9B1WoK+K z8Gg6r+b)VeD%;N3bfWmzsI*<RylT4KomnowoyS2OR@68Y?){43{KLY&pMAjpO-ubt z<rXhH?mDmx!#Zs=2^7H>{lyCKb$2kFoTfGdne|1^Q@o_a+^k^(+Sj%uqyIjB+Eot$ zSfT6E-i7ApXQYf)%>-_Ze0k5a>*~-#An3X=jZtPmilc0;$!d^jA0ShaRxwR7KB`Il z!+aF_8~+oKb`#P7Ib^cL6RZ9Ni@DB}Xv`~F8yn3s-#B?5cTn{0cFA~)gUz^X+UAv> zD!b~%S-HqX#<x)?I9Y{X2HoM!W!(0mwtC!D)Jk>{EtXtbYF(-%b;l_qC$+{J#Cf*h z__NDz;~6Wm^cC_52e&C8R+$loe`EG*JOQoc0?H-dVt6yvF4xg(%>}c4xQ@UdLL3`{ zXtjfehL~UvIIU&oQ&iLqXF~XWx-awx2!z7J_fyH!k$lsBO_>O|HJTSI_*|>MtlzwE zR)n~Yt=ap2X7FD?NUbJ%eu(yvOqyt7gz1+t$(pZm>-YZHQ16|$RZ*3coi*cV>%m2n zyykiN=qZ%rBl!MZqUY`Bcy1e>8KCQrPI--`QtBq2EV;Qp&h#dQQGb$RHXB2;yB0k? zTF~JaHt%4KH+D5ipjMXxc9QFcu2ogWwf+7247=l)@FRaP7i)|5eEIHHt9D5>T9z5@ zVVE04=#dUz5Zt%BW?{xvv?DpJUohnSG+-FZ4JgT&nz8(fYW~SNp)Y=F>WO$%#p;ed zKTguYuqWgOB)RL`BEs5VG{{Vbq-}ka+^_4sgi*wycvAkVUs&GNBZ#UD*_QBquyB93 zGt^C8UILq)?AS`F=c^8k_kS<TSj1Y%2ULbFn$d5hlvNhysj%JOQo8#!I1i*GNj}13 zc=iAZAk3R`Z{ZqYWrjkRwsJ2$_@W_t_;8EtuuSZ;WQ`B5v!kZ->Y-m>j)<C)po}<^ zaINVM_ffLJ+vATq;4_;PRfXAW^)-H;rntI$KLfp3#wo<dOV6HnX6h6zepo%*?LuY{ zt6Qq82+yuLwJDPYQ;}@V-Q^CXX<lH8(pEX1P3u%`?@25+=j&=#oR{%E$~2dWej2IN z9RH%0l(OPM!$ZqbF_-G(h%yzvdZk*@!Equ%FGYXO6T$5ncI2LfbN<O*yqd8&oANy- zwwcir>88yi4Bgw-M@-!{;h(-oSDGi(tNiQWkIX*10CS<SPk{0Vj_26NQ+~WZ%%Aw% zPrz;XJHu1@i&WJgnJ&0-y&-qu=qVQc%>12ssB7_6s*>lPYL+H)j8uiTg@ivZnUN6q zs`_HxiPQnotL*!M0=Y7+<5o#@l)1jJb^34duFB7q*$f4tkC(>hz@9isC*#Im^h9QC z9%}*ykgFO4Hb=G8iY#sVum-d$VwGX?tmbX8LM%Z&k$c(c3cr6(oXl%yFz{Ou?<kC5 zz9@=#1RR{=I-E64)7bDOUy%@H>;SoEe!LNG{$DDNP`Uk}z;DY=Y7%?D*nc$?0!--B zP*8a2o%61jGNG^XG$R6KaIc^KWOVnt{n0io!#m_>`~;{|Rlo3gdB^#Gug&}5$niDP zKGdDT-q4p;YPLY7&Hh=rp}mGr+O^JN-DSROB-knsB`WHn{2=A{ih;oZU*U={Ib$jP zr;H?CJ|`xxx;Xq8S1Tc1Yi*=yku@@3blTz>CPx3FhAUa_8bKh+jF0{ub0D#yk~B$< z6f+?~la<^Sz$Tx3+=d7Ieuw-kni^TBxO|-FmAH>??hWKYI^oCW|MT+oFXyrCL6tpt zhl0L{*&&Led|&1C=@Ss}3Fu77{jmbqSCQ4Rq&Kf`EGOai6K_lRGU3hQb<`;*0DqL@ z6CmmIZ(Lb)>`WZ)*Z9BJw~bb9f;St@*G3Zf4&oFI*|M?jUFF%aW$B>5e3>7uz^q!y z&9AqA$FDaUEp!R`wwLfok-R>b$ic&Wu~Dzx>pZNZBa(3%gU7Gc-y=PaAhooxS+UR6 zs-RRlY=7um9AiRPRkV3t_q%0D_mtl(=kJ_v@+V;1Dd59><)1Vxf({Tq^pY-s)84 zNChYbToYJ%sxKLKCb2r=7*)|8p{UkWwIV2VK($FEI@(wN<-K@D==%FG;J#;U<Ts%? z+oVqh&p73(*(+E<E&=9Ab45aChrPEAvNwV)<(IT)32~yXW(i>)YmZt4*Yw0fvP>X* zjggEb3MiGiMmQt91Sda5HxlOsI`H&rrzwtB*kM9U-R4K^nES%w4UU1?;!oW&sV+tm zDzpe)Q`T^cvPB(H5F|Vvznwk_t!XE4y@b;T_;EyBCT5mhKcp^G+j&A1BIoMTJAPX{ zrMuSrE@#1@UQiU9OBNTKn}o4XNi}bMYkMj=tHA3j-Wr>Gv&HWln)hB#4;p=4P}sW6 zC7^MEU9PiRSlhWI@uMv$WUpr!Q^N-9(V%k9By(pGQuAi<@i`02*AgEyE=)!VQjDwU zh1tp&dO^iAt@?JvX+X}#Wqmg{!s;O2kq{4$@bFU0C<v2h^ah$^7uiOZ#^69w$b0wl zmM6x$Y!3)hIW6TWEO?0PytjcGemhV3QW<%+R2ex@YZ-32XzBa>l9@5zQh=wL02pxA zAM5dD^}u)&NkR>x$2^GezA|j+-|YUtqA+q%q>nQUPhTmHL1q8YQJ<AbPO{_N*lob$ zs3rHmt+#*aa{qSCR{FJ1$xx;qt$MJ|<o>e#{mZZLSpV<!b#za)?z<qMEaRb33{q<B zKy?#F`mH2VBxsQVE50K$cDW{X{Fh?7_5|Zf#gJm!)VEs8<zSzD7r`l*R;!Gd14Laf z&xwffWKl#E$K*8B;UuC!h++J8IezN><W;$X^Xib+4XUl0tjgQguFIUow@r$(+)n<= zN=0UXgPC#vZmq=@(rCBb!5?ab9xGCuyFs4Um~Gk-1j<;=ic@~;4!nhO$kkUPT?b`; z%9S=vLB%HyIQWSN6}yw&gI0Af61O-bPBy1ijYFO}-!0i!oD<Wlx*1NT#S-LHUrFF= z;F0wy1(niam-|$gZvg&?O|Mm|*_s;ODjzS6cS&~F8~jshECm}H6qLCvIuM=m7wt3~ z@gtinb_H2+MX#H-1Nk@AJS?n}0WR<j=Mn?(4xBA1Uet=Ia#ZunVRLZ-d0t5sDaG}t z>GCYs5+5qxhI%pY1E3A^MBU7DEJqW2Dac-r*KqBqo4NH0lDa9B01idiMFUJ2B^3~w zWLtd3Wf}Ixgx*%rg9W+hDOb_+B9T^iRCqi##4nr1ehn8HNg^(vDPiDR-&V}Gx+_Q_ zlX~f`Brx(Df60mm;W?#1yqf{)cFHwj8>c)g-%3Fwf;Jgf3W+~L9%MyE;0R<<!+L)q z0mYi|o=kC9c(%{hm^)D%*3|oXPbudb=z$)F0j9f8;ka$w-z05qSyNN}`ij0kF=OCl z7ReY9%PSKX{g`r^WRi!8ZRfx<@!4saMJet)zz;-f1)6-8X8oGvbY)z}QUtxH{t2*D z&!lq2=RKqucw&sU0jU$yvNOz)DdX#8>1~s+X4CVp=~!UcNiOxuQyAC%F)wYSC&@Q! zH=1GE1S6PA9j>Msv}s{)wq%Y11L!6^IxD!I;mGEszLgIU<GFM>zA=Z6m*fF_h4dQS z9XyVHDB;dR?pK_{SQu_PS_Ic0^3{cJ#=wDO={19VEci-pWJq{(mA8(438`Y;R-@BB z+n)W%AjiWkg~dDhMp+z1Q_L^v(r`NEwTacBiOFLeI&gw=7?0CxIbUy(<4B8b5BU#& z2GpVI#c|Yo;nX!W?{v9{1IRWdsj%IC3f~9nR8Y$^A(>5;lZsDoac?52ZDw^jbDZVz zigbdV<5F|);8VL^{P_bN^44yc_xB#GCwE%sh9b<lA0b{-X(xTvCvCl>X$KP@2sEZ^ z7-9y;_|MHK-*SN!>TtC^d8J!<1&s(RTz6)BK7H`~9l`RhB*r}WB3K(-z8*wKBAqzm zjf@fqcoh8=J*Ak#po$giZzno~1{|I@F+*Txzg%6#O}v&Oh@3&&U?myhfh>|l+D;j% z=!l4sSS~!OPH#5z<%di*wZ(4|`MK_=Csh^WR|RFJ35b9BiO>|q$OT=+L<0e6E{!LO z__R2>!<vDRniTtYqNe%G!PHQh+<IGUHYFR4^flltJKH*IxKBW}gvTe~GF9gj@PHzy z-udr}y99?9@V0;QZ^LUAd;;<b?@Yf5t<ThKGYyQFpJYmy&F+5!T9_lar_%}2uvIIZ zO2^?t9w>PA$B24mP;A!P<E|Z04CL!gB+jA0>kZ=T`|ezA@2r+RwaTQl*40XCp6`y! z`<U^j3Xq|?GDb;U82;Q&G(p{?L=i~<>)sjN@?Vu<$0qkUC<L{2U3_+36u~P}elB&> zVs?JJO*gj6%w~~_ka5VcX|3+-!8EKQ<5FUlPt=tlx0J&OyLzYd6b%iO+y<PT3?e_5 z1xqM#irNgeOG1a2{e#}S@*%kMPDE5bP>rSKox6$1rlj4=BI6cAV&vF0&+S%OEgZ7z zsl}$GZn_s5#Xjc}KMCX938!+-u5?dYUf?OUB$GZ>YRUycWp?OxZw)Fp7GWU;q^rc_ zALcnERuGL7w@tBvif^-82%qU*pwhJPDy%k{{17*k;a@sp0SDy#GvAN+jp<pL9d(`# z(~5`s=q8~Tk}ML#d5K8udme8-kdlE6@y9_lj_oV8h;^Nr$txGqdK)$f6G{8rus)Qp zQ{+H<O)kn@Iu=A3BA!T~tAb=6PmhqYN4u&1@`k>N+f^_I?%1K}YPOuU9lLn4X>!AO zH7WnGbxJCqo!az(7nMlSC6U9WC*fhp(`AOW^ALutPyg3*d&Iz8sYeAPS9yi8$apUM z8sBq@T9;W=c_4x$97UQRSac?o>JQ1*HJ$qX@{qotXnH;0cFeJH0U6JB!m?*b!2lV; zJd$i@3(llWA-fyz2|KHuM1<`p`I`k&`U)2Tzl7=6+(mj|)`Wc+x`wW88rMo^U6)W* z2fK%(a7R-Ki#I!~_HI6(wvgHmj-E65odA|JyF*@cq|7k4zm`Z5O#FKCwYvX)7p%gv zb6Ev>SrfPI?51xM-;lAOfdZ_lj<u5q!x$1sOiVh4rsKvrym<lb>y4tQa);W9b8WC& z53&bGxqY&Cb|)UD6NkL^DfBkKBv%kfgBv+*9jgO6VJr@Brk;N7XO<H>{y&!zfg;3c zMl$NVdsQDcadpFM|LR?7e<+B*y?Eo_x?EqG(8dO8+4k=#fL~R6M2ch^j$JCd4!z-j z96RAsdC?oA*U!bc=*xwctxYysayG6%J?8lYbQPif>CNZ4o;7Vd;Is7lgyj+hSH zaHNU?AJb15Xk5cG5kika!K)=$;)H3YGc{;PX<^B5!p!LTc_FB9Pbbwj{ShME2%4MV zlfR<yvaoE4!oFFAOiE5K6sCGox1_sB!dJpa=SOyq*`;+C{Z%!2qnZ`xqBfSm0(4#R zi$GRc_EXbYYoI<FXA4_hTN(HgA)$?zaPw>Et|6nOT~io2Y6_U$1H3NAu|iAASK8`X zq1AE2^>tIvN^8ilvthWiFy(NPS7m#Ht-9Pb#V#FZG+JSL{Sj?mebdCwb2TbMo|;QA z%Qt5|*lkKcV=%VI7TOYlnlK(TUQVB$j!u?(%%R3zSg>4dEn1qWhUq}`fx3jzRe7v} z&SKNrVY6;G#2qIq{^(-ZIb+;kEQp}Brd!kEkEqCA=O4J(;tM7)f67eA{EC8xvUs2I zHNuyo<IH~yMpRUSGm;MzxswHgOPmuuloMl+v7$f8eg16EI4VKjgq5G$eB?g9**IFl z-7TaoZv3&%@JH#aO3d{auUr&GQP%FPN;CdUa%G`Z9xV#;Y0@7ch7zXjShpgD-56?V zzEHJY)*bii>jW#?<%J@*h54u=gFyi+>UfnF7zZi@U$<HXU~)ffmIHOOq=*d(ZYq4D zR`{`UrBx+XIR-zUw~o5WPuP%=J8EwV2!znlXK@OZ{|>JqR{DjNc#B-DQGMC3Ka*<- zNKPSChXOZ}tV$yVPG7n>*r#4-LCX9I0ir7&$UBbYMCn9{L!`#7=nTb_zqD6d$VvOH z)7(8$=|U00FiE1WDq-L#75HAw*=?%sSXA<5aOi7Nu!kt_!&w(AN?462X>inV5y}Ld zvoD5_Gp|$DDSGratu#`*0l6dYbsB5z)7e$~U|X-vd4fNVG>5>#sAo`NZL#CI;dQBO zqH2m+!V;5568)Ro<M!-D2d8DNo0@^>hI2kaqXL6=Kn}TkpJ3SHwAnYKX>C^C1jWNk zZNKf~jW<3S6H*!q3!VN$h3Prl4b|o1?y+pXL@fW2xLD=g?re=axc8-bQ-y~W1u3Fa zl%J6g#{#8p@}Xr@{B=iMYr+YQ)e}>9!BRx+vnwc8oq%3yoZ{D(30xPaR3}44g>$P> zE^APof9rj)xw=xq@9T#(m#S9BvNDrFrc3X$G~qJ2(QOWun;}?*qY#rMs(yaoG2cGx z;1TE!&$WP@9Su4Q&+PdR(iNO;{jRv()!H`0QF8R-!4<Kq$fHS96k_ZJ_5STJ@W$j9 zOe2E0vSzgmx6n~cV=68aJIR}$dchRICXzKqNA4+?I=toaI*J}C$DnTKtaz0qD2J2O z4T}TD^q!6taq9~Hv<hh)W8P|7U}xhz6cU#xGbG~+Cee{++PeME%OlCuON7|t5swZk zj1(O?VcLk|NGF6+7xI9XThi%H%Lu8NwFE(&EyM9Kb-gaQtE7l{65ax!ibVK4(zcjx zo<JA4EP4?5ux_)wHG@2O2nh|DF;I@lhH;6(P_qm1C3o$+m1@#J)hS0t92m&jE?A5g zHf0txn(an{B*XLiv$cuag8rEp+hWA(%^jINazj}XG9olsP)uX-36ovn%qT`Z4na3C za7+(}=q^a9NPc7dZy{$xeXgtflm~3A=HhMCxZz)=SE))qYhf6i#`XYIR4y0AayB~n z=N$;dgH9AW@(fM5W<CS+Y~eaG=BQcIMXcXMBh#J(?1*1&H|#XVHX@%iOTCz>H~k+^ zy)`)UI<ir?-r_I?n=Uu4)ksQ2*T#7pmNQ9B;e*`eP;#?I!W?K;MVY2I<al7w6rD)F zzL09~a&;}j8EJ4uPQJ(F`I(KE{95Pqug&bQqk%2^r7;aVN2V=UO0^2#u!;q<p@f&O zQTh`#TSPkpUQ`>v`e3XlXz_S>(<fCH;tZaDxG(_5j~!eY)*`@qzrmW;!X@BrY^a;1 z$0Lcb9c?CX3TK9i8Be$PUMOF&Q$$^jFH{pu?NL?Dv3wLV4P<On`z$Of{$UtTBT3_A z{i2-wg-^xg5{?o-znsRNnV6!UGHha)4E75S^re^X=+~X#ebYP+;LPo5vB&p13X-oA z5cTVIcB(7a5J)$44|2>{-wWCa|BmNQ>Pk{SQ!LUTq>d|o*H5iG5gX3-))&N%=c_c; z=ALH^60Eg~^Sr-0Vm^~#Ef6U^Z6&hcu;j0pDOHoVc@@Wpb+$MvF9b)Vob50__r-C9 z%;ILwCD#Wa2N@&tEn2&OEuq#baPK@iCMhbQT1>!PsE+r-sFT<{Q4CBTr9tyuwHONt zAgPDeN}z1?K9T#9SV<Eb5+_rv+ywD$s)U>zlB6di)fC1>GSbZl=rzE`JR37{q;Q`7 z_#~lAMd%B%$K#AhfqQoSzWt1gpEMSKDg{$AGbR-&5EV%kjG=jD`zx2Q$F6IBM1tt8 z{6z2DisRH*m8u!i$(l|4;rvq}-Q-u_MS5m_EFp7Q>GrW@%*=Jkt#KM<i|Cuq%!H|# zQ;Tn@S{^t1A|~Q-d^^slxNaZUDPuD#wx0lkL*AFBm{XpYhq^wJPrxb9?^C?FuI2U9 zS^aEG<@OemG*~izEpc=6alXnPN4=N&k@<kK3;QhXW~(HHgvlDW!P&3CbO{X}hqmD~ z4BnP&1!Cv}9YrK+`B-`^HToW1FRCarys&}#c%PhDeT}w;$eZ6>JZg!8%-8Ds_GPyR z3D0jhO%q2Z9<Ewkmxe&2sH&*WzqM5Bv#B6)%|iI)8XMR$Eq0QgL}8DX8QZ~*3wZ;O z1*b|j&OA;USACA23L^JVtrUew9GBMG_=fnC3SBAqb?IkrL)pKF_g9&K@S{pc#N>^= zyMF5SC?qN!q_kvP{IU|@y>rQK-oF!w>tB;WQ#I)z<Rq=F*c2W07#$GFgkZDfNVR)K zNm>g>!+}Z@+$C?U6Ad<Y+NyKUvC+TT+d%!|Q!U@-kY6gtv+^yy)unZ_GC$nbV&}t8 zwoLHn@pl(hEw1yZOUdiU70%`vhu9`?)*->+zYfm6ox6((Fi=zI!;AZ4PtDcVLdf0w ztF;Un0G>)z=i367q#9YVZ^{@?0;32b<5D2j+7;kq8AfrtXDz?SyQHmjZl4?Y{bs3T zyyX~t4w_>gz24uys_TuW#IynWwxO4R(}^P;d=M>l2z<4~d<0oDG+N-n?5rsGN;d`; z44Gp?(sLapcYGw{@s~+Oilg5MeaSVDRczBL`T*~%u9k85+>S}i6!9jgOJtWfB}BL{ zM5sQxQH57wBT-r_RC~OYS^_BQ{w>)zc`?7n=jPj$n26i-!XgT*SM9gzswqseKx+gI zXl~KDKWjV3r*xody9+k@*P^BQCP8St0>_mWiBV_PX03R~*jYUiRUt|)A=s~SA7UOz z8aN6xcG-S(VFXvLTSJUY2uI#$hYyX$7_Y7w)k|@DSSq^X=J(~1?>s7!TfC0v6+KvT z7H05Y{l(m?czhd6^b>qXf-Z>@M%(g&zobXm&t9oJkm$-qg<n5LCH~wnbtRz`wDnU| za#GV^I3B_HGN6CXA%Rth)d2be(BLN~y^4Erz0Nu29ep^wY!T$;fScUta(p0)$EK!C zhLup3tciR7+In-GrtyX83jXwKjbt*Q6^lHTu?@L4-AD+^5A-*6|H~h86PXPznAz2t zE_fn|-Lq!vuYA})tST+y)Rqo@o@ZyJjOUuErFwLk^Ofvy-LEvl7eQA~4DcVUp4m@k z6&)vUr8!zz?vC7N#fxeHuvaP;-UMx83A^q4J?9(7Y%Ie-JIj=(moY{L{&&Vdn3kHV zS`RBI?i(DVZcG?B?<e2-fA@KE(FtrD!%3Xw_jk@buOzrDAQpjR+(o)(9!F=18QR7( z7G+CkAA_^PF!b>Lbi~HRf>?{)IHlb4)#vW1^gv>6DYN(Fp8yYuo2-g5cipP3E3ivW z<+&zt$!P1ED|a!yTP?d8|4Q0I>#l+(Qq7o?IZ#fgamw+>YDxBc;N5lEXv{gYtM`#q zd6L*jN!`$IBMt;DiE`zEEu9WcW~k6pjV@vd8~Sb)m+tZ6){?PmhSfnGtXObmyqzk4 zG>&M<))YZC{F0Ax`@vf9<2%uz>h6#DO_+_^yZ1IxhKD0Ux|HP|Dz>64Wi8_StjdbC zf1dv4i)huG`P&Zc6f?R5i>vGN9HRT@@Xy<G^>M~n*IyxjZ4;6_MdY)op=cInn^J0# z>MnxNW?ShQner{DE)&YQ>?}NK&Bc7(b3e@4S3VOl7!1elK~wQ&)?g;_gpIsEn}pM- zQj$FBaq6vmTnPwBH=-AU_~G#sW4!R0uavRq5_cb3yv7PjCL5NoH&+rYg^+V-=H%R> z%Ki-vv2o}2&W1W|ZCge%&7srboew`TA;t}FOf{V>T3YREee6US(5>jHhJ7?;_7jfb z@tzZuQ8;hE)eIdltmbX$Z5#Upiv=3<s`K&0wHMV7FcCQd$A$BW7UVFw6LDO%g!vJ0 z#3^&kC9Wkz*{)<025)JJ1F3xwjVcH3Ibo|53>OPfA$Xm~)X-%DQUZzHrb5}mWvaV$ zFCS9vQgbY`Vz)Y!D9o<@ErxmT4eOvWBI$8XBe;gVYTM-uwNdo73nFgo<zHCtT7uhs zI#)<xz6dv6s+*NxlF%fYN+z#5Da2C<3z&T3FnzX@G{4|WBUOh}7zLBE=>g_kJ*yH+ z^C^1?S&Eq^G3+|6z#nCs-Q;Bmm?Ep{TYmW><u>1{8N%{2T7GP<Sm9oV3LIBW7X0#p zt)i%3y8x|75pry)k+7<PF?O&=NqDj{W-m&?v--z|?dE<#X4zUsCID=oz|dZSCGQPx zu6D48surfx>p(NMJU(VYl&>Ll(xH0sUp+e>*+pb*-8cJ_)hDi%aCx?Sy}3>E!|b<K z!r%u+k~{#zIkmZuSHeJPe1eGV7U3K0;x~&*-*YtEnxgSU7Nj4e(Cp@X{5Ag|5iC== z3>&qqb{U6k549*00tfKMZ_~ytpO5t|-roT}e?9?Us{?>rdQ7|QKWz^QF1Ox)wr>1e z^lfT#Z(MRt-y32~c<0KTzpeUZ9uYT1-R#yEyosMrV2MnKYyR-x*cdWVAX1BdOqrYw z=q(a8C^&U(#hMdez`YkcwtyzOIMbd#*KKJ=z9Rc|wq4fObl`3%T1vq9S|xr!m#S$G zvW{~~b)QdewdW{%9n>k=(F4u(`T0?Tq|D3zJ;Jworp+CDAtO~!W+QE?rEE6NCh9?c z)zH$pPtU0fqNMMJ-+;CRSg?L`psiCg=G+0=fliJE$)1$8W9XM}c4TY(>l}g}RsbFH z@1mEC<>LbosD>b@<Fq0!FB#((QQ(hMz<q3#f@^E}bhK=5?5RiX(<lt*-)gFuxB9UB z*?_+HfNw7!l8UES^w~L<=U1y%Oc+2*+PBj>T*oKmuf%Rk@C8A9wq+f9m%pvs47rjF zFq43KoFo%myL=+pw14?K1j-Q!BGLp|^eHAf`3jN(z)ra>-}IcoY<I^7{w_CTPje3! zlv?v|TcvaHNl(8e<(Of~bNvQN=#tg%Xl=~0jr3gInpn5$4YR7)w5Dj{H(-d#rnpqU zVX&O?|Ea5?+%MpHoo6Q=-`SQ}FR@YIkgXjyHg(TL&d8)(rgCNbR$NmXBZF)ax<oyP zN6D}$@ehJlj9c;h;^yS_l}i)kZAV(^qiIu9Of^(pQ56I>Aq5T3-xD&h1BiD;rK+kM z>uLXmYCua>tEphiPw%eV-^N9x_<eU@L+<0R-#XJVNQzj`Bck0;d)47*s9QvokSc2G zwBZ%O*>4_=uFmzCD`Yc`$n4zdsc>haK*w%3Rp}6?mzJk&*gN)aO6E18?1$8`svndC zu(WN>v=BV)4(ieG;0CauXx}t%cCkc2T#L-lBUtkIl4U|9cJw4fG~OO4;eq2-OrP2t z7M#SVbBGo?z1%-E+kbBg;lve-8I~ckG|45td@Kz*BrwZjAEII1uvw-+!EW?>mLw6< z*4jB)K(e`YU0UZR&KQg8R2tW7nP9k}kSk90ZOffws7PO);aky`Ki9TzZSj{*O6%kc zS-MPT<My-%<5Iw~iCA%UIklv?9fwS9$x(}Hx4S@VsMUDCS*0FiBX){rsd-OFQg!Av zx(JY{vo!9|U$@$*q%B`ja~lh!bJV4<D<5xVCXPolA8~?-g5%WOv?Pqh)3K5?@jV(D zw8bzgF8+kS+}^X<Jm}8m)+RI<tZ`)#L!mdADJR0t1a6m|x5r6kH8-c4iy19uV1Wc; z8pw(#;oS-npQ)1i)5;)Z+DLd#R+RYVirb~YHk*l{%kN85AYRaE)RvVi320z3_67>M zge56HIT6LbQaCWEnXot#r<w<A09OW94+PvbJA=PZJh*wh^YP=Ytueoxtm?2nMpSAu zyt`<P)k>7K#~i)hwuw!X6*81eav!O=z}laj4Hj^o&sd|TFh5l0pnMi$5nvODu{D~K zj5gU@(@Xmaf1Y!=1I`ZkdW|{vPGsS5L-X#de=YdB>a^D}OV!~Si{cTq+dttXkkzg3 z+Qv0<FPV;4RqLX=MyWucYr@(<GmyeMQ<sB)X8r@?FoUs{jx8SPI2QN~Ver@p_Hlp4 zpfiAmYrNv5qpH?Njc7%^ihesk;aCUx1Z<ZG)pTgYt5|n((;W58$R(%DfsZCToITq~ zCna{mrSnQVgjq?|_g%ijz7uRfPRQEaC_@r6b{L<?qJimyXIo33UC4NgRS#00S>!;i zu5n|EK=Sh{LFc4+q;GzE)tQiPpR$5PNs<pLArb(V9jc}!>qwg9mmDh<Z*sw=S|GSx z=Zj{a!AD@}sSj!^M%i|C!FIth^AXfx(0*k9gT>3sAg|>p=yaet$44TW>d4tMrm+-5 zCgkK`jo~*BTP`sZ-!K}A_dR?s;5ed|)!Cq72h1>lZb-WZP0e3;twlkM(P5)A5Y7?o zUF6h6Ow%5I8^@?!MnhqdJnA;TRubdoo*gD1@U{5Af(~P1UT#h{gT5FXEXTAX*2zj4 zV<ll!6j*EVGJiv9l5_*gK6FhB4l5)gQ(R0lo<h4v&u!V!nRiF45@XUFF@Mk9u?8BJ z5+L?R$)$U71*T|2kx~gpNnE1Y1wkb6E_=2#e|L|`48(8ptvNn#BrqCkEWt*cefM{l z2K!;oA5m&I*T@8+vdH<)Rj-s?6*|*pcb@PX=9F(ut+pS!<)nE|S%%opB=p0qHR2QY z7eP+s3nh-t(_Po|;5Hd?ewUloAdzXYl&L|Bo6TCs-sq5bWhwwRTujOc)Ii81Y^s$g zj>99rMm-xC4<0l`j@O1^M5Z&3?{P!N5;XMbkS2|r^uWch-*x2L`9JNjYK#su5$a<z z8Hadfz80w^N8P|>%Al^YbuLCE_gC>|tB9IV6j8;BG4QJBX2sl0va<=?s%d1ly21%> zf!WA`f0HUNH>O9X2WhA%drGVE8`>JiY6o&D&hxG$zj%esY&F_L^E@j+vrd8jAe)`3 zKe7Oy`WU4R(HZ`tGF6qhjFU})xQQ|?Gdf@s29prP)jBW>JX{(q1F=jUE5AECMY@nF z7tD!v3^>N9s1<=hd9C}3eJAaV-a1|*ZYa<TMR&x{M*MX&%tgtbF9p=I8tR4>NWH4s z`As1aNfF+P;8wiB8cBHYCCVWJEn}mt0s+6D&3bpRIo*OX-&<i3%!EhjvB8WqfC;vP za?|-rb9la|TF}EIWwDtxq~np^fZ7htnj=qVhkvG+tRxMCA@J)igND3LwNHVUdiEJ9 zaV{I&xpsJ=>#?$K*{p@u%0gapw0!>G=qx%TQbw%M<JlH0)H{!L_*r(Y(fcd87FJ)K z+JY@8OUHr;i}^efS>;6K>bTy52mBQ^p@>yId>DI>6^VXoiUKCty7ScdY>)#<<`|`N z#d}s?{hZX!MUK9CzpRP&go(2eh8f<M;8BTOgGW8onY(HX7+1NvW}8?t$xDnzDKwSP zS}mUnS59e{2hU})=xe=%Wp8Gr8i*eXxq=#wb2AVMF%gBu;`#wb&ODQ=ok#1WhASKe zH1->Awd8%%>O16!HHK`S@3?oeCqncQe-l%5fu}02^VBsFx`-XwBGpB6MJD)~P4g$_ z7*V(Wt#!MCv9BnLSNO|rE6J+6YN<b^<xHQN;R;%LWe__$*d-<}*Hw5@`xI38r|_h9 zv`Q?lDY+se6EgvL<o$KOqX{|iq`P4nyVar5S`^J|E;^IOYb{nGE@G~mKWf8uMK7yS zK<h>xgp(Z15hXU>f244EKyonIQ5a7f&$XsQ@FT^iCULNQR=Y2=xm?$9L`nB^q0D=L z19p5faGtrg2Ed4opmJrwOp`}GMl0mwNETHuEO`=J%#wq*(n%OgrkM@uW-<Q4a>2}E zTcA+ypz|cxe*Li*{Ue_xYSC^{DI&Ha)sG-ozw~zsqB98sOWgrCXCurPFTCKeOqsMF zQq($zkNqX|&6%b8BZNAJ7QNoIFwOdD)qBb(O%>eys?65QG@`K513z-{cs=ye7aE=R zo%fYqmDvi)neUyHn1PAwuP$8x{qJXJdh#GN{(&vsHJp<n))sP{@$4vEGfDS^A!>*r z>7tva=fS$eq<Lq{?!+o+%6s_j5S`Xn+vLXLXedg;q)7Vn!caoiINi(HHVv&EwNC*5 zLpPwO&{-Q68v!9CMAb*bOs|FLae{_f2G5(5Ot=sdnc7>7TtMCs?-zPVY&Ni82hM(h z)7r;#?5;JSxrC;?iAWGeTw_+rSm|a)mP>y)rPFrbv~VG5{9>cZGE7YUs4PTV=zD~F z2>?YTt$IR<9(bevb+*m`A)-MUY8|C;e$kp)kqs|l5q+Zp;zu51ao`)RYRycN%<;YK zQT!wUrwvz&TX9cjoAbUaIyf=)J;^h>4ZDu&s_v_5F36=a)#kNgOnZR3HiOT71oKQ1 zmCP92d>EjTgp4N>&XpXbrm%a)S*AL<@nnZetiQ6NBj^ZQcTWgKEKjP0j0ZZS?=~9Z zQaPn1`|Zk|qakhWZUeQkTN{qDT%%;QCuJd1arff=mvO~|(fYLZhudN7bjyr8Gl;t# z?+ZTh$>5$zN+w7~0v61XN;Nj@>>W*ggu_8Co2G?vH~6iaY*9dDB@W5F;>dmH#*Z3V zK{|sg&8lrHW^4oHH}BZ}*0#1?2>xtbZDq7g^ybPGww9oPM;_A6crhm%aS88H?zKh0 z!p+Uk*L$RY0bGx`p8(=N24}xL9Nu4H19rT>d;;P=^n!3%L)P!4-*0+SMrj-)4O`0& z9`Kw7oGqIZICj38u=krn=zYb|wJG@o^zQunZBNKlcc0Z|g8$U?Ueb4D^Y05=m8#Hi zbme$Br<O#2u}qAyR5IS1NUM>6OXyz?zyLMHBK#mF2|H4(&FJ%UN5x4M<!ttApQ5;n z$8W!ts)&lpo~@dSii&?fRx+cCipo3beVoRwZ>4ZaW<LQgm{R7<U8RliOeuejYdWfc zg0p>0de~!A?tDX*cZ?QxT%#{CgPvLfH$i;_^mJtp0V#r6vN(-Npho+1&e^wyEtcYw zGDhVLPev<Pu$rpN{@xaKUUiq{&vVYfd#OdiB>y#NNkjEF;7(8VU*&*%u73gdYqxl# zLS=06e;RHcvnP5fh`$}BG@fN<_Ky~RGYRE-F=vP}N;ZRzwUHxwxQo)RER9ods}BT* zBV7F<8L{s82MV6xxB52-8CZCoxR0Yq4d6IrA7@4sqW8RGkTu$58;y8-Aq@2|bO^-n z|5SdEkAB<eY-sL2eNJb6?4Wlfj!|-HgjYhG){7v$t;1FuI-UM{$N*UAL?PyNzr(qO zMRy&T`n|~p+=;4WwO<V=-r4DUIQkb>>~_ZTm+#3lro8Ounx4x)U~%o?nCcTiY49d! zTkQ`dR_Lz<g9ZQ6Io*$=Gl+bBvv>b{zuZ9f!>OoMuNKVBJZc3E!D{K1ByT~fvnxgK zQrpVbu~i<j92Jbb<F__!X_6%$v8)L`vv^ryG?C{onF4A@F~;?_@*j<R0f`5qM(FYm z5_O-{v>hKvn+h$U&o;r==U+2u98oJuOw7@F950sjoT=!9En*}79{`X*Z@-8r_akLz zny#A?ESQnqyCI`pK6W^MuZcKdio@I;FC#uUp<Un1rD!=J0swHLLmq&Uht;mc<I)gr z5`G|~WZodVX9()y474W2O%vFFhlCiQ?SqF1kZMzKo|^vvO?AiqZ(px=Gmmz0jN|?< zck$_~&N{;1T>Cu2HyZ0J9DI{*UIJl{rKhE#uAz7)ErVSOqME)9Q(j4GrIP1ES4;L} zr7+r!M0M1e`7MRD#!YK;lU&}t33GLlT-sz8R%C2(#AD~%+{>F~EyIc-M-!w<BZd)- zY*w|6M5Ak8XHT}H$m%3Fbm38rGxC}2U!7woNNV3qV?=atP{oMt^R+ZfO*P$RR>#cW z8>{eXo%4+SclLU_v0XM#J<2;8sjk{*I&%~uE%A-<opYTPN_nEG?e5R_R8MVG({Fa# zXB%S~#p1qFfATf|0JGBhNq@-K{?AVm{7X8Rd%MeFfE2D?;uxDvwl66js*2)0>xrwJ z_b)2vDyplva<4jZ<8N;G!iF07d*{9pVMYTZM~NGGw?Gj=9Be_10E`^5k;DOwsKy0@ zXxPL?wW!oY)emAm%$HHt?#PpYb|#>o$dE%am0i(+qzIZK-P`9WKhc?62WIRro*yWh zDEu#7qq>ij!99?DmTmXH^n1Iv{(OT!?!5*70LOl=`t`u!jNOqW;h6E`+PHfC`{mJS z$&)6C?%~tNj+}0q4Vtz=H5YK<Wi&+;Q{7cJ*G+cY6#Vkl?L5G$4dk>Jj%QJuQp`;! zLZm%7wxi^AG!^D^yJb_V#;Tj4R>X;~`(uP9Z*sk0!DQH~#kG*p<HQBN+auLyUwu$! z?8Ua?zYxl8SJOK4BevS@xk@Z<y;Y$dhE0*o#H2P1K!i?gNXW8mW->pcrmmYHV~VMY zt>xT}v&X?rk8cj`Vp#M-%rqJtYjrmcinWp_OD%-wL8qt5p+Xs^&XReP3OMZZOORP| zh@~kC;nmXqF6>@AjwdMTk1JJ0K*iHH55x?VbKQUWY?Z4`l+n)d7%<t(`J}%nDxS!# zq+|(Qkz3(OTqm~L<28@BZ8Nf?#>F(Xr?wO=BChuo`a~hD1v4%4x}PcgxBxi}lrVkw z`K~bCu7+Rbvo*AAo?2_J?e%qF6~AwJL+Op9@NicrUUbEf<rn20EbxS|{)2wxFdnDn z(xcB31p%)k&ddiE>P;#y8n0n29gb}5kU@I4*G`3ABK?y-apeT#H+PT)BHdTftR1RU zO<>FGp7RxC;RnoC2)4mYiws)om9#;Nm0v%f4PjiNi3@=3>jI@C0jx4t`?7mSnBetd zm%16vCg5fV02V=LcIO4b@#={UPV%yulvFWqrK=p}2d=ZV@yQUzanx3o&l)wEw^5tV zoj@%u_Ui7f)d^ATHC9c!8TL;OP~X~)Y?v3B6#Dly=+^fS(!1N~bKZ!Hs$zK4@C)Qa z$>Jd9^@VcMqvtYimDhfdy7zw*uZgr`^>#$Iu0$fq^wQUMn}!9&H+>BN_7v7iDa3MD zIElN_MNxdbwD_*My`Fxg<SSC2=qDC4Nox<-bseqv<9IZXeYZ+43`*CJnT0cwNs-Js z<Ee~fsK(CBJZ54eHGf~5*!q#fC!}3+TD5G&vvy3IpwXK|5o*z+R8wx*t7hryk`3FS zmbxT@2qmV8B8pmSnrZ8<nrp7Q;~1rvw%mkEZY1OPFCUpsc9&EWLO3lAP|SJcNqUlE zq|y0J_Gi1C85&`<1-Knje%TF}mXYPdH_B+)Veh>75N#mMtFnn2eQlIUFf1TU2;{_@ z3SeIzTuE`t*NQ}WARz*9m97~?_c85rT&S#rNcO#?Yn<1y&2t{r?Q<N(MQXKEj@4?S zD|q9DMB_z@c~$dgmre$Tw6o#uq!lkp)R22xCzn44@`~0)D~TX-F)NFgPgGolo<Q81 zaLZ>+@`_J1)YM?}LJ^}!LXhRR<U4}x?;M>wHRkJQ88fJSwl`nc>_Qg}7`1ET32NjF z$~U1@z1hw&vf!m7SidyVF*Xk*i)e7q*}mxSrT2n~An8|$4jU*ehNPP|sa?j@ajsR{ z36X})<*@Su^Od#Ne~3w7PlfG_V<~I1JnDwqqlEX)7tIfgn5UDDRw)z`%vi3Dt2HMy z=ee@U2xPjFM8>*F^<^WFJs#!zO7_IpEt{D^o6+d7lM9GT9qjQ4%7Vyp`_cDR#^|%D zoyOTbqRx8k9Np2&FxyC$B_TgU+f(GTG5XBZEGt}4G*RG&7Fq##mTht}d6^<@ED*iq zzN1Wro+XG_)U<3MNMf-#^(-J-SI1TMMde(s0<S%;`cYA&a-|RadiPW+2IjLZb<G+F zTa+owDi>8lTgT+@PTLrh$*zkMB^_lUYKd6bCpy`el$Y~qB%RD%tVRIEk@%21T50uA z_p<1@?pP<|&oGU<FP`yd{?Go<Ijl8?b@n8i;}tFh{;b&cyrufnYfodi#BVNkpMIkI zj<|c9cM+X_{{V{4$m6moJe>SSR3L<MSrIx`HzWXAx~z(WkO6++S&+oqD~%Rv{Am`h zSiWqgHBlD`s+Rc1+UFjM-37t%%k!RISW!-ahvwPRyt8e=)GorN3ZH#k)5u5(SZg?! zCL8eq6ELxOHH%@V4<PkDUssUD44`ucq;Y7;exgEQNDz(!jNmxfV3;py1Yr@V@svbj zxr7-Q<a-{+D_+${HB}WCOv<97swyffDx#vN3W}b}ii_@wi}y_xw>_81;cFw8fXkp! ziz;!%RBtA4&3J`agQoF$onKH?oXsMf9IzZkcc)#}ui#X!w!C%Jc5-gQerj$WrZZee zSPYO_BXTznT=HDvAJA5qOa3>s^RcR08kliRxr5s%oS{gFw>j?NwI=pl-)I-$(l|t9 zw>2}3Lw2aj*mJ84O_IW1atT_Pi<f~p4VRaXsRcnp^Y!43vs}-_Uk7Yh?jw*ga&kv& zIR$GMq-Eve)+(kV;6R}%P%ZBhbg1}&iGbl-=<I1@O(YG81Q{YM?-TDUx>($~3&tfS zw<`E0V`g5oaG=vhXKKiOvQ8o%I`0z00a(PPrDG=S%AzY}h6eXl;*(1SfFTOY8iAG> z3Hoaqm-qFL%up!b2G|wnSabd1D&(jbxT*Tm4<GATahYkfdncoM9TyQf6|KpzD04{D zc%8Qw9#En4LJzY#-avqegn_8>u8lSRLAoE7wdZT99ZcS%Zu5OR)m8rhLg+k2cVWQY z)3A!357A;l#q6!8;6jNZWy_0oQHGDhRORg2?j(g!_1jxgTAbik1wihi;1k^ECZHqE zuDY(v6MR<;EMRkb?Bt>B2rEUd8&;Jn7@^rrQYzuY*u1i&k|unpfn;LpC5>H1k4Xdl zF?XAtmExw)j`Up@%~3lJzPV*LxcdFnE=O3BlRJPGcV$Xm#v<%R9ht@9g-9Z+lv&}? zjpM9?ZsE$?gnDoiOe7@@8lOD}<%5`RwzF5PYx`z7DC(Pz0c7=oH!_%kaiGLU%@UPO zK+xg!jg40hX7hPb$#Cb>vb*9KK06YFrKEuevPo0DcJA^$$)fCTJiU3&J#uMla*3)F zAlchlgSdqo2S%KIF&63mu{BdOgJh*Gqlvj_l8KDKTo~61=<jBGVS(wtAM|+1&lL#f z8AXF2j`bZz21ob1yd-uGK`HwEGko)@6_$=b3Rumd(8q475y#pG(pP3265Ol&s~|R~ z(=cl=&iJC{3vx*quereOy%dtidt#O1Df#=rlp<0JU~iz7pNFpQD1Zw7FAyPI2Of5m zwAGu`rsOuu;Q|WRxR2ZNx4X%Hh|#8EY2Lg%SVdh(!eIRa66eO2B-Y=v9vha|^4nQi zF^GndO8OZLRVd76Ev#Mu*h@dVNlhn%leZGNJLN-0bO{?5wp#G=RmmH5*lv`mVOJSJ z()fj?TV3$U!KhGokL#;Sh;z=81~t5rJ~-Z?q|Ym<Z2e~EBtZ<a2_;r8MIhyxG9W$1 zI?>_Y8ZR5IuIjn>N>|h>w?u-Uvd7N$s_sjZ=^6xOFNMyagQJY72sT_xBTErsDy`&F zAD3F59L2zUQr#aQa*R-L`55Nf@0B_N$*k+*5>pXi8%7z&AImoxx#xSIhyy(B!5_3U zU^O3sXXG|&*|T+aXx%2PmUuyQmngZTQ40LB+S%3-B7mI9HiQZJf?%WN4p_J-FbCB* zey)q)Vn`23QU%_UDymJiQ{??_t+#aV>Gg5Fr~Qi<j40od+vZGYsvAuqd~Y#z2#c&4 z^MxEXIc`&-Wm8771eMfiwc`yO4UB9d;wrm3+Qe}1e#s>sA@SD7hWU7}UUXbaplF-l zvTVfUwruQkl$t(g5Q`5{^W@krt1>uDnbJE7iiT6|&r(Rq@$0=!5y?Dw*t>fx-5j4f z`IDnU79i9#d!r&2S2jr9KYYM?Ur{R#gxU-*8xT)Axq5Qht}FQX_6=OJe(;Gls54RG z+iD<|k~Tw8Ga$Fc<I5RtsH-V0?IJN+=R}2&$h(hJ;wmckl0)(P7kHeFdqlvMQCM-R z?2S=AJxmL;0nDzmn`d7L?nOjAnt@iDax;`fa|GLHZSQKTE8IqVIBrdKQs}N@=kB+x z4pSW~Q9>?i&P0yskc!R2B1yUn=UnQMP>=P>CF3#{J7)_DlE%mhkcf4zj>VH^=`_~X zguYolkC~hYL$_~>GexY3dJW7Pk#en&d8*bx93<tz4N#>guM%R;d?69*U~>pO@n%!T zsf9^Kv#U7tkugGgC;DEude-ZThZA`w?;jFY+=?{>BPfZo6)04F$;)>zL#<+uO^kNY zxzX}S0qqAGucxUdH6c#qfYXl5nWWh<gj~BCnxd8HVdEFgw<Gy75v+PDK}vI>M>g4M z2S3;*25ljDiU>DV(Yn<7KS;vKjHIH<psLInij@r6qV8l6@S|J`eolM&NAQ8f9#tZR z99xifwdX-3DXR!?P}f5l4z(ly0Bu#a<A=$!jJFwRM3QdXaXUrlNfN-ZBno~OQXFy8 zN1F2l@<HNDySzDEK+0L7&LawKGamMf>uQb3)^KC85sNvHMU@pSVf2P88)R;P-55?B zZOExe_h3nyiMx@;$268aft_0XKDJ+~Sd(uH2sjSxco)#_Ed(JUY!1dXfd*w#H^z^X z#6}EZY@?Dr+%Yg?g=#pgBr~b#vYQH5G+oOo4=LRcu3i|N@~a$+%7xzQy{L*ODyq4P zyg53_`d+Bp;v?FEU7jMG>*U0%m&on5!D3y0)skDdZLW6H?1HbT*k&ng<+@3H(Hh$^ zmTQpPWWlXq#~&)ZzS2tXarpolXb_U9sj(7hyqG}Q1ae6qB*@4a023^bBpld716Fc4 zuyVtkwtg_12M!rOWZ?&GS5*a5Q*K|nis^%Qx?jv4iSC9z=%AGO4#zUe#Vp)QEQcNa zu9rn@;DsJWHNzyTslkPHT*F6og>+WPj^ezPH!v<i=Y(G6YA2Wv;im(YKf+P+zRT{7 zdsV}FqV_%9FByMJ()7JYy=`>8FH6$&Xwvl8-4{(&&ee3%>APn@YkIo947ura#z^OO z<3+GXZ4pT{(m^*5$`&N?X2O7g4$Oh+8MmXs02oNg7A#ydeUaQe&%sqG8;_=Jp)h#* zNWV@sAJcS*PV8fhkWF1;wah^!lP4)YzU~>Mt{dS1;L&!Gc~N-$c^9S{^EdMA<|gm* zk!j^OTNbUkf(~6*6%7)JKbqY)2&CzbmMxI0J+);evdS@Z=_Hi*E*=gc>xkS}<JsJr zM=hOw7<4JP-C1POr#u!oj?Y$0<0#xS!&Z)3M<WtOKZiC;JQo=ekyK<eT58G>s>`-> z&FE^a6Il*R5{xR;RvvrX{1}MucJiLZk=yPuC$ge@JgfANgzkGJr<wl%JyxHQ!mp_+ zPgx~B#=(gE&&Aesn<=&6L4%bx9VN9D8mfu1jy1*+c^|8pzaSBjEp(8{U&#)#jb<d? z_<isZ)}B~ot!0fHl%TmVdaf}e>4}6mfe|OwZmIFP14~DqK8+!5o^K-n<P4#}i4!>N z3vFC0CNP=228+lIcZ2@`WfD<vY6GZzq{d{G?OLK?j#iwT_4x%pv)B?IINM1r(o`u; zWEFfrM$Z1(ioGm?wu%_R4W&+NhB4;i=e-jmktnPVG!7XDjK|@S_{i3wqj5-}VbR#s zd^;4iL6D$egf?a@NY-fUsx4TsYTc`Jwbe9I(@bL+>jP-Edv5kC2C3VvvBx4~c+E>y z=n(Q*wo}U1B)f~N0`n@?-g1qLDs-|uipB;oP%z_0j21$C`F2uCE@50_6Y{>zV^jPi z8x!eZ+y3iXh@7gqd2+c{7w|WYem?Q1R3}sNjaEJ)gUwJ@Wnh}h2km<-nmGOn*b~Lt zph(WzDYB~%2-884DE?eIMll@-(QVu2czRx!r#D_bFI@FKx88zo_I<*9sxXdpbsLCU zodq=$mh2S6mh)plE1JNLj<;#CMww)#e{Qx>yI07tBZuiI`J<Nt$1K;OU#>k~Z2Azd zl>Y!VmYWJq+eu(kHno4p{O`MBN|g$2oKTwz(Sd<w88O>s<CB{>gsyZob}Ss|fSFP{ zA-P|ZhwpsTCPl7?F2ZzyM1=-1=1i3#?HD6Pj3=5zgAvM&7=ji&gnN}5#x>4WL`BwG z*FDW^QC#OLHLXPDT;*O75kD%bsED7wuJ!Effi)cP*TtjHihddMffq^S8Io$VHwy)n z^o_?Sjg?Im^wWLV9gde2a8s>ulwS)X&Fg*CZs9HVHGZ2qR<RLDQ*|vfAKe82)OC~& zu?f3oc^unu5E!Vapv{|)+0)&ap_W2W$}IMJ^JdBXDD3IRbjsVgp14=uJkT4FySu5l zkwNKWXS<J_W|8A^_4MG%a(hd_gOW9bUkK+ke36WL_Wez3xkQqXBdka;qPcsPEI84X z-rni}FiO74sqfj(vZ{XC=gsX@_}ODi-0`me0IC8v9ba@wtzs8=aUz>B9UZ;d3SIEo zulkaRp^a`B(6SEBYoMf*+IJ9<%1#<AYQ@zimHOgNu4l|7?KjT?zc^B7P}<d$Ib8|2 zW*Ro)?5^Z=y@+Jf6$iX>Z&j*!#K>?a4BZFWgsI3m8pIcD6>!D+vv-Fm#d~{^Z+>8w zAj2tIP(ov4M9A*CP2)BQ&z5qzmh9o9XO9umF*h0r%bYc8<ws0fI$)z$ZJn;wZaUKl zjFP&U%3yOr3xk)zB<A8Wz%G<-qmc4Q!B;_!h;Xw-T(wbg<runVvW=HrzRDxE$f~M& z*L}KO_)c{rD|q%C`)!lhI%aFKM6So!c_nM5+2B*cb;IR9m1zn}W<i~dnOHX<p;c2F zNy{#K+~$Kgs7m`Zm=<=&u}76r6Na)=6+J_LWI}f|$;$h=<VK=3ny@9C*!&$L<H!{; z85_}>&+Dn(w`%|{cWToyhtpe<8P8DzqRS%3e3eQvAvy$eu}ibYO1RkTy&dBiY>soa zSpHEts&igV-nFl6(HCz;*R;h;(FL5#BIK*q5lX&mR8A!)YH(>s2AxJpXUgb`!dHfJ zg35`nlvZyOAGD-Npk-s4OfQ4Ec5lxm1IOLlAKFqK%k}S5pP3esL%&8G2RMzwZ8x=e zn)#d$794!^W}&j9ifLrMv!sKhHk^J#3EHxbL(B}c1GC*>#6104Q~bkc(z1J2Qrg=a zJyKrg$&AEdtG6u#CI~Cmz#_3(H02@VzUbiI8a^XFG~~#=1H4#lW#`w9&8le=r_ZE% zyT_Hc2<6DUcy~;)+J%h`tKK^~y<5J<YjWKaao)31ZM0*yeni<FE~DWi2rK>tvY~{y zE1!kS%wfp0{G9S^9?0ZN*PP?GHf-KoUXm0wjjg;DSb5mBIzXh2tCx9-@ArhylaOcu z6<g`<6{wH9{{VXq^3OiDi)+O1JS?@LQBoxAmiJ#TUXX5hxTMy+rYh>JwB;q`1u7YA z%CiLwt{BVenD8sC1GM9@xmnwQoVKYjgt(l74>FGLUCSd6d2q)rSF~-DJ?DoPOCtR3 z(D80@w6?d+z|JzVo>*}UfczfIug5}SQFj%4U%2y)xYk=%$qn0zf@FHOP%XPGUox+t zG;2ZV4=3na(2A-t9OViomMKgHYZ|I-N|r^}Z0GPe>Na%d;#gQG)*n?^@y80fu&k+> z@5oL?%u9x3vMi(WAnb#LZa48~d5F5D&LQui72Qoj$^%?rx*|&~q+*g7;p-;+ilLOD zw!FP5WWsO&Nr*eA(&Er~by^CysNw~zO9|w5w;B06l#?%gx6NF<3@=i^0CV+k5go*r z{c{0;&7xaM1WYYxi5V>7y^#U5O}&y887VVnGlDa<!<}RykqEQlb4Ji~n?Xvh95h+A zxbvHAj_dK^U&LyWbX7UhNph<hgjOphmB=;#KIXQzkIM;ZFR{+bq(qFj4qZnZ6f8$! zs4meog$M;5Y&-zdMxkYa<xTwP^b1m4qs{TEswXL$&q?#_9CiH)r|0v@;M@!&E}4Ek z&<rg^T*uICEA{kR32DLWdg-{FgoQzY#$`4jIixM`&dgJ_Ef%&j+ES&b&gzEvkSSF; zx|BjxzN3Q(7O94I{mpKq!(d}V=-Gy`Tt<_1_3u_VnTHy%S%JK|V%+67rfP1HKgm^H zcIqk76Do}DOIkg!U~#J!ziSJOPliUM4v5On$q|*-PmVbVT5=`hS%K*6!YtZq?a5IA z%ssD%Xf%Wl>KlwzaUKa0g@==*93);k{INjs?F9%JJ@|I7<OU=%7dwwC-Sc;Q$d4M3 z;p%R5I#_{iUOQCLs~7t{lnCGzC9l$Cn`1Ir{HryTVa8r)rtD!*<OY{CvJKj)@V3m3 zSV<=DQz?z#>-a#&EL*T*^JgZ4Z&i$%a3_-qgs!pOxCtFM&{5uirkp6vWrYkySqPhg zyJ?gZcfRF^NAm1+c$dWQPq`=|`VKW}qKh^{<(w%}=8faNa;z0@qapw*$mtX8RoCFz zl)7S?vx%!uhd<76gu+U5OmCcPvbe|1+eG%?I%+t)-gxqu-}E_t)T)GTW<$#Xh7GsD zuwbK-<!MvTPn6zV%PktJ<;pcVhQtiWkXLNCV-Ax@r4C#%Wfymcl-;u(PuE84H*oGU zdy&M$_fqNj9ZcDBdmzP;TWuPfZHo6QD8$<qg|zHrdjQJ}kz|y}Hki+_9oX7&R`k_~ zumNCguy9sg&Tox8r#3|43nGk*?B#Q8EMuJr{#>!^7$jnS4QE0w9_xDZyLm2#>sr5L zP>Wr)=xJi0lOvML!li!(<0qBbB6%JwQYLGuy9op&xdcZvXh4V;511vE4qB<atM$s4 z*}3z`myG)ir!sW;a!)vl<dC9YQ>d|cV5d4-Z}wy{YY1~jYHs=cXD1wr4edC~5yi{1 za3BoQ64??g<`Me~sNG#_R#$WqJ7`n31U}HNWy}#N8Js}mLgg`Yj8@Yd=(yuSojYRV z8vI`Z$>_JuZnnFi;WU;{boIF%SN6C608PcaP*wNkZ84{=h#Y3jtLy--W78N!yjybs z4+?eg=VTqUajt#^+pnT8M?Y<{1O*ao(3r<f2()bJCm+)EXxB4eIsVIB*OA#zde_Ip zBlc%5hHPG8V$qKsy^&gU2qacb)8a8Fu6K57)T$%RmUO$fPn36JL1QDeCo6e37{*CB z94vf8`Pjd_X&w(+Of@NWap_aob1SM|yUOy~`3L&$nJFzAV3YRDfs{?gTbLmQFt6bf z?b|<RuJFkOfqCfO!yc)Z=bzbshV_cJUuEzBc2It+F0N&kB?yC%vD&u#CYFR8$s|!- z7i`U(67H5Nt4Cy>IV{2hJvPyDvKF9bQb|1M%XhkaQMcRGh1%`@=3_P4RxNNo4+e16 z4HipS_Q$iTnk8h)n`mlBJ{6sL<IIfbJH}*d$k%$|PL*9Ca-o^vFxT15UuP%fk81MQ zjofhNJr%3@PqvOPGj$ya*p(nV!<+25{iRzTRdz`m2fLJA3Np<m%aD!9!4q!8{8COe z7p#|m9g&O}VY64m-)z$?NHKEd{{Z#K%g3jYo~rR1(g%-2h8IPOXB32VZ!}n`nv9B= zX%#H&acJzEGuF5%0<_^T^)AvkE!aNt7&*Pl2{0h!V646uBI<$3T}x8-mps-zD@m7B zqz2B9H!#tw>@-OHV8U71q>dFVX35j$qveqEh(3?V8Z~<Ph6u1(z>*~dIABTNDBW{( zE0%PNlSZ_!l`kvV+@g6R;yHQP6tb?KfqbRKve8BuV}k54#B)KP7$L97Ax1RFVTUF? zja75qjpU%c3z+t_764*6;7)rU-ci1AD)Oo&a-unoRd}4J*DIQ=d*pAZ1>}#&Z8zg% znx!|*qUoV&9_^lnsA|NDq&7os*t@jZK{0V^WxM6ahHS3rkeSM`G=q4Yb4Mg{#Gyq) zgD)g{FQO_AQKl!C{qHeh1*_|j`xlWNeetTU*->Pfj1C-nIN9N;5%P{%g^vOrlEe%c ze9ePIwpDz4xlMQ1YjkgyzSPXcDBQL}`e7z%S#uvgMH{}8zlz367}1123mOb96;_Z= zWe-<u{#sd+KdO{VUoVzTm;!197=4Gs^P*c$tF!W4<l&uJve-P>rOa)H(?@<wVu~ps z!D!|;u~Ka4>e&~QV?9epPEnOy3HEgUe~hOhWgJvsRj;s;*CcVT3*m3NERr>O`dYrj zYm<VJ6+PO*aL{#sSana6zMgYv+B=@JZJF^FkxK5eufdxrHZmbst9~_CRFGCXnk<mE zi@aA1hqu_YhCp50<EO|Slb0%4_dw4AKFoY0jdid47rRCYvHH(&_&E!s-k>1$W6k7> z>5ZB`E~YjjKF7Jj4ck=kX*G6)Kn}hq_>);d;8ANayqNZVeV<rgj7V7Cj_BdB`PX{R zqv|B-(n>Nr8s=!x)>%Z2bzKohE*KM^6JX&{wso8}RZwz*uOKiNnS|y?BeN{|>#aO< z9HGQ0YB79XqP~M2ps$TpOG{N0Q0uEJ;f<k<5+q=?qYy+kq9Qdpa`N{pp65AO(-^V} zLl}=KO67S7M=PH9xp`MP%kHYHrRjQJm#x;nJugesU31;F7dqCmn~L<Y;uS?<3LLRX zG}>@&m>@$NC8pbGmR!73OuQoZeQ?xJb{aY^WP+#-62<8UE!!(x&f@m6ykB!fG~0fA znV9Vhrw!I@0u@(+l1D4C<yR8SsHgLLf@TCfcUa2$J=LqVYbMrwje%zF0~L=6T_=uM znl&T6q5l9Y!Te(I^qsUOMw?Eq=;0D-!=1)3f0nWcqR&PB1j6!5<?5#Gn^cSoGa?Cf zl2yCg1dK3ahRcg^T~>6n_E!9SI=%Xk=WWi!yZu+nt0*eJQDify$z}Z|2%>F}(Pdkz zgVbvHac$*=8#i66@sepJVoOyNXS=5BLa;GEBOcPXf1IAn2{}=+&YL%t&m0Ultp&;S z{*N9y2?mM}!pb0q$v4RjVbF95=4EF}b~P)M7*%Dbli|G^IBSb3t^wxQCp6L`@`Q3I zf}|u;SFPHmC9$Vv6K|P4g)wr~Juvn_eRj>!(;IA}0RWE&6%+CRN5nI0QlAvAu`%7L z+N_6SaNK}0H*az)8&7o-x#(lz*e$CZ+o@Kk8~Y$xWOa&4intHvde_*>xJE`8tIs8M zh0qpk(OJk6q!^F#3C~UvM3yh`(TJ(b*cbl*5${i@y^SB#s`PBS^t~@j*DhLlw7qjF z_MbT{M>zQ=FJ#1+{S-&5;Nz~<(AE2A2(z-aC`u`3Hf+yzb}rR2<pPVII$8Frk8oOU zO|VCrwH~lwoi)8x1KQ;0@6Wh;l;{z|)OKf{uN^{@b*`V>7hc^!w+eaMienkhzdm~p zs)y*Faju)?@5Pldx=E(3iF__MSo>ww_6b~BZv`Ib#<bgep($0OF|H%}>}7mPs3J)H zSy@XIPj>|vX3A(>s#l1qOwtNWp_KG*C5Eh)HRF{;8@o;K_eAhKj$S>LTHaIJl&4Kc z<R)_f=Yw>ZO5U*+VC-dub0WP01eG<q4Avt~qakZwx+D3Lwc9anRAdw(sVIunZIva3 z0ApRq=Y=cBvKX<s33~ZM1#nUEDqX)Eb4_N(5wQ%wr7#k`dhS~Z)<Gp3CY2^1_Mcf< z(F0maR2-m!c%DQidoT`2hGQ9z8Pr*kk$Zq*@GA^|PC=(pp)dDiOybgsOcq(|bFjHR zdm|jx7R)wD>I0pDoU)cWh#nYSqr_Gy`Y1?t$Q%wY3z0s`qi9t*<BqJVmW~5bIG78x zk((kePd1o6mz#wdjK=hlnkzIuYb{)r-IKS7f{L+>#Kb21DG!g}l7&o~>zhngnM;Gq zmD^{<u*tQ5Ue+@iOtK?j+!pmtI(rnfubUPaEoNcowpq8f0nkIFE1P^;!;m3TMrz3P z%GNHmp)&&^or;T|kG0){<eJ9m%G+xFdWM{-2gzsOw(U2y3{FuTdvw~!fqNYlJ+Kp! zO=bbbxs8vI&s2#*>VY+lPZ4`)*)F3s*qx<rv`FsVT#w6>5<MA0G^eY2Y&RhFm2E@U z_e5nQttL~LF}n(HP8=g@laNWD#-@hs0kCE_kdnHM8HnrQ6IL+I7}q7&5D|#%n!lU2 zfZDR;c}Baf*z#v_)l>+mj1Ao0Hd4-~WFUG$+>#Mx$j={;mMuDq<C<fPpV=)Mu$Sc3 zt1N#b(ayhy3Ib@*lbCr4?<rtPm?X~EoXA5`k|?yYzYbyAM2CcvLzoK@3o=Z5rpq^y zkct8Z$~zWXT9LhgMpJbg4~Af$k{;{De0d@5Zh;vSh}#wcStBT!pvR+4wgnjw=s{3y z3XTl32jBq<CfOm(PZQCg^xf*gEuLY<tv;b9%Oz+pAVO>dpe<m=W2UAQ`F@O~1$dc= zxQd}Vh00>&o)cwXM!7N$*jd4oI^gvTya-hOB^L@}1tgw3uR~qJi1Y*4Q$?d^TF_GQ zeTm~n?(O;}QC!evx8w+g{{SYj=u(u`G}}j(IY~Xa046+iA{k%BUS<Z`Zfv!48X6Vw z@C=Q+8y;xUin&11pe<zi74G{6V+OG-J8ok#l-GmhL*eA)Dlj(OI<to4QJj+dOV%y| zyOYe5D&bjdppf@+i5lsPbZE23A;YZ34po86bXQVWG5Je|rVie>>_9w;*=H`tGAdfm zu?I3P;G3{${c{Gdo*Qth*CG)5wy7$jqtW@vqo=D{c3^(XGXtkubnGs{u=~{;-ry-w z#OL+6%XZ2mOo4~AJz_eHS6PkAfylY!6wqM_4MT+EgsCA61leb~$41eCmZQe?((zXp zcQ5h}%i@_gXz6BixAL8ndzA2&jiAvP9M$WT@~*q<^^BQE+&mxd#uUr+8(|&OTj1YR zZsOg)8QbjdBpG}J$MD>q?S}91cwbdXI(tjxMMWQt(b4_rsoBSODaMpog=22A%wC=B z@-o{Zq^x-R5S{IxWg07)*r=%f<SMtZQBmCS!t<;9Z@$~_w)^Me-+i{<Z2Pf~e%og` z+dk}L7{|Xk&VAU%F^}@bG3bzR(g|%Cus7dLclqXopr$t08*92rk8_-9wz<Y}w!iBN zV>;*GjN@$MIQM7J-SkPgV|{ZNo+t0e#i`+2=O5>dR35gv=l-naJ+Y7av+I!k<>fa1 z+qaZYQCH6%-pOSbkN6{zyni%JTVD98{{Uwf9CPm`r@Q&5%_6VA^6o_c0FN3M{!u-g z?o{sGq?XMuk^H~Yu7^BbIRsE66lxnJ_7ua!RJEW&*`TX(gw@q%4(upW<Bzx4qVfqa zJ0ZZ<0e7V>*U27Xd^Ht*bz)s9%+Z-D?gVD)=4*;(9<-GwmyQu;%(a6~$yl}!^x9zZ zR8&gA%x+rjTQrC%8$~v|{Eo1mzAhWLcHMT4&_&BvNUGV>X9?)DcP-b`WR^j6RM%wI zMP&BbHBwVuv{OyC(|vQUbB|7kOkWfI{ORrmekFbBw|{P+sD&1TF0h#&BBg>MxNL)s zW=v$+P@%OvO%xlN?1ls|0g>wB*D>T*S0&CHS8Deheb6Plm2p7UsEFlWdyO4?TIYS$ zTsMjCRaJYR!g0^njD4~H03Z}dArRiBt!qBa04Ys$)?`J-^tI6ChBBH-u_r8sgfU+j zOnXGMO`G?1GICeWHgNJuBs%TJTqb&HA8j+objVoruPO_usToquaIq~T;vg3E1&aC% zV!G_w%9%`Ia}o;fT|z_HDy3Y(yM`?olzgDING>d40lj=Y_`>M@zJ000)LP_seB_g} z_55jiT2fi_&Dtp8$?0t@`o5D$ciU!2V@w<@Lqv4h(rD_MZ=UMlYgm5Dhl;tXn(rG! zqpB@%lXUWxcW|>Lp4+0crBquvwjp+c*j3(+5^UodtExJp#jed!Y~y#X9$KCs@u2Ch z;y4+X;d`rwSiAmmf~ug&X+z4YCx*ri{5x43B69BRc0U}VH^1M6RE@p28n1#(84Ub# z@`Q{1Sm8N|{J1N>pBgMsKWU4?J%a6+@%_Udk3N3w!!#0}RTsn&qI<S!m%FU++@h}; z9vsm`wb?fA$QEjYmw3YzcirlVH{NkqK2`i>TU&%}Uiky#X&HGQuQm%9OQY&h^GCly zqs5+Uh(T#v33GK2Y{A>@(sU68e%yw{ai&=3M;lX0!}d8TvTl^#r|vs463Zostc!aN zn2TBtv<9lGY$S4zBXg>OB}+0xDJDeDtWjoBT@+cc5c(;rbfW}^*yg(%B405+-m48R zijMFBITb@Kj3P-L7vEMJm|SGOU$`|Kw!&(=Nt1aFte4w%=&b!cFzHDJOYuSIg5*MS z?>bb-Cu%w!)(g0>N(FoS8ikUWp{rNlhdIHXRt=v~9K=Ob)e{WJ#;g9%@*;hlIWZiI z$L!xaKm6F7{xoYnpq~uf{{ZC@1uyJA29#3r9@?pcHhX1(tmUyoTlB<DyB!*Vjmq4D zlk6Z(umBJO$=0%xV^l3T93?u`;T1%Qh>(Pa-(&NoB&;nSt>bd!3Al_IgA3^Bm{&Q@ z2F9eZ2^4m*u^hBZZM5AIa{<#j-4ZG9qPbPP36@j(Y_@UrOs2la=WFL}ako!$&NcVr z;?BEUdu@$<{{YT)*EQa_+c?L+IM+LCjOX~y*#5Y%XNHdgQNI?m>0S3Oy-8e`jLx_x zS1ia3X$XyD6^a{@MI|NEV$_49Qh7XqVvvw}w2?Z08e-IH#Mo~WUCQVaZyP%B>qn#A z)9HJ2cKVBSDl=@SB7t4{N}`&VA(1F~6<y7Bt$gL1CYn4dpvH7J`l(VTMpHv1m_kVl zDbb6!#&PTTS1{!k5hDOjf1HFMQK}b>?0b7!M>*>5<n3xTcycw%+uPibv)cqQC~L?3 zvK5PxDMQP2X-ASY5YbEwbaX{+BGxOZ1+~-Q`h=Phl&U?dien4o4_s=Jo3g@)H=fOH zVd9I&y*H<j?#%8UG9TA7;i|W-tNe7;Yb%>`-8(O8C@vb4sH0__%mrPumB<pz^$o?y ziNI^E#)EZ;Tjv(Y)olL&+Wb>O_x%MS=RS!5{KOpD5r@VW0P(P?j3QbSE;S7@gdB9h zq5-6X+r1<=4i_9ji}0n)f-XFWQsh`Us`T&J+<=gj6L(qn)WRbRRc!1UKRf4OwltxG ze~WL0B69fs#a4<gwl(;1mD<6=X`QjQ*l&z&jdf%`9G!o3+p?PhU$ncqkXYbX`1V7S zShCmjrbUp{<Pk3{lFl*OY)Yo?z&0`cNo&k0@B}8tuZ%%WA{DX2vdb}hdmBg2fF?>2 zL>4PN;S0p!v$0cykZe{j2=rDtSC_dJslvH!894Ti{3lnfm^(e+HOusfuB&$XLE!g2 zn&mYSPgOVB`zqSBmOK=O+U<-a=$Z`MI8z%Wf~qT~`fCbpA8Y>r!?Xh=u@gPg7ls&+ zL6cpo>NRmVGTCiDB?}Gx(<i7lNPAts+Sg3RqKfUm^4Md9{{X+}4S%7ZkN*HM{Qm&l z`yc#LdU#+S$5%g%$o~M^eWh_s@S6K<SMUnT6<OuuUv~ch0wezbA~$UPwR~qfXJ;;c z?4H=yd||G+QyV8d>^>?z4nmCM#@+eW<!?MguiI_V6qoSTa(2Gk4y=Zpsv{G=Q$D9B zJT)HXrdfq#j&dWQFlfK;K4c|C`+d-I9`DaS&0n(qeYE#nUfcy1CBvjS{{VvRiSu2T zc8emH6~hmxoFv=nG|LhWfI_0TYHk<$?YGs~WTcIg`b4x*6TdmeQ*0t{zig|@1(J)Q zwA2@yImCL*9Jg#>3>ejyI%f6Q)tTgu3fXcaP<8S(;<^_M(OTQ&Ch@W@&Hemt&KWLu z>tAJ0#Y`2(i%J=ERm`5QHeY6zUBrO4>Ls#SPYn0ko`_WL@ZU}I^Yz<DT06?P#y54c zKJ;@sD(?l}B<ct3$wfG7pf2f;*5w^76($#Z1u{Xt?ObKxi=t6J5JTWiO}AyM<}NfC z;~F~|t2ap`wv47v@t)~|r4B525#8*rO9tmhD5x>ITB8%S-J>L{Jgv51MS3wD^rJUx z9Ot86=AhlM4&Pjpg*1o&Z$9XyF$jsua;Vk=v3<EzMJjTs$0^S`=BZ;|en>p8TjIn{ z=KU+$mZHi#BN~FR(p5fb7(;gK+LwP1ts>1fh}U4SgI2C&F5^+S=rsNXOBz#M_jL1P zd*h$kXzEM8P7-z9J1NZ6i$&FP`T#h<a`*h_R_e6+W(=7yOzc*;21iZEYVJWOenMEu zRtUChT{&i984%8a^_@vn($SP5ROMq{)X>(-WmeHD&KDbj##^hlF|Nv>1}ZdAq?FFO z>x}N3O?J*T#xtLGG3mnf1-HlJExY-w3px#(!l|~Rx^M{*xiyUE<(aTV^eYJ}u#Ssc zK}#f}dl9JmtFyv;Tv(P3I*7nh*6sWV?qO^s5_8(U-WE5(8C5t`N1{39A|j&y0KPPG zdpVqPipulfI#OJzR7L3yd#+=(bzu){hT)?z*6QO;*WX06cwo^-t2;F%k`>t<92}HL z$d!<scZ|F&P2-)mS1(tk>3XMYOIth3Dfc&4Gp+6ICCHy=YiTY-`x_b3%Hv9#I&`8I zOu2GQ_muJ^6oxSz=aKGnl~sJkFl=bX#*A!gHH>3XtYcc7HLYt=8rGsBA|fIpC$c7& zrRp)e?Cx1((!)6E)!zqCr;M^tfa+ThoGUb4no#043X5#fCcCz8?u3eeCc<u=qOQVG z)y}$S3%A0ubJy={L3=`#i+M|JOqX>rFX@)nx@B@((NB4q2I{e91SvkIYvV{{OBkM5 zavlRTCVGkJ+%Tgre~gSLjE)gI9@qHF&K2W-YOiS;jzx1F!<))-iOOku7oKY>)NUUX zo!t^$xc4cEpd~hz6DIhe=Gv`BF2d|=;Wq*F-P(j2Ij@p-A&R)bvV~A&Fy`rmctd?k zAEvJLguJq;8<M#k(0lR|`l`c(v0z)}eW~loR7Aig%?bSU)<^B`R)3-|esU_M^xLcR z6W>pMxl!$YOiV9w_U|$Yy*Y6#>k`R?e=38(N*nt7QJc<+iXRiABmAhSqwViSMQ=L% zW(6d~l^s*L4;bNA@y{qxIf|TqdG6zn&bY%@^0_ovp$tY}ziYAaJA^XLlcx>RG9yA_ z&uTP^C@7wf*(6{Xg8DUcs;H(!TL=0ltENqsNSNGSPkWZ(thT7^+ZFlvF&weZ;1-KR z2e<zKRXjFI-)2h*jWB#O3LXr=g83Tdo*ydHDLc!AH(eda*FR=6i&Q3M*-KE^2|Uib zEti_5sk~S6oW=IvW;w#T>#U#b`S-1#pvSx3Q~WpT{aP2uH#T)+jxpow9_8j+O1WuP zjI)DI%Dd&K)MPfjK!n~K46e1B3y;>2I5ai<pH}g}qKZfd3n@A*vn8CpI&_xKUH5;e z(V(4b_XlfRwY(OxvMm|Z!UJEZHAvK8u|*uPX5d_PoInGjiKmShIQ}~j9E46P{zj=M zv53AMN8_uF5b^6L9_t&)-*L&y)+Vf*nr|s9QM<u7E16rCr@q*2K*51Jk&r;MH*KVn zvVi~q9%5H0M9hrSK?3zGQSKSG&X#5EF!q7CmB12B96K+iiuC0?C&UCr)Kv-8Dp6dK zDq)R98RVElaYqNt>w~=Fy=*4KiN^w%g-Ivw>+sjmqFom9BGF+}=W>AQ0c?4;@VKap zDz_S1fT|&~2|=n5tu<e^wI1m_l#_rlVmc8EuOgDXwrX(ZD~R~uu1AhyQQJ7{QOq3d zfulp()8XFds36cQ2FI!F2;@r2cr0XC$q=qKZd{?DOyu#<?~`wZ+>0+LixWag5)yp@ z<YjTaog0m{CM~1qXf!s(8`V`j)-_*S6}5p{&W{TkSUg5+5IGN+EFi<T4FfygGI4<8 z?VB1^mhJ<6Qv^Ql!)7H%YUFG74%}Ivt@;O@CdzbNt^?8)371{f($zG^sgAHWB^pwd z3XINUIU_H+oe_($6IyRl>tGG6(%G33Z%BQ7?9?YOV4znjX|}!R)V)j7-a0zAMbLD` z;wp%fa(XuKTI#^kd0><$T39da%LKy1h_Pp}al{)3cE!Yj^X;@CeDLHQ>%ZJqUsFbb zJ@LeSzd{y=MlGs(!-|=(Qzf)WBgp%=ZlolDk^4-D6DH#{eTAj*g1R?jDv0lmWpQ^- zh3I@h+>#mfUk?ulMMr#(b72E6zKx@Y)?g%7`gcx#GO~(d#*Bh%^4Xx_U4FRPaqP0= zboFY}4nC>!?U^Fs%0=$&Emp;8YSWw|J!whU_95HC%)8s#F$sLUWGWL8X<3Mhi6bGI zN+PlM;AZzDxU<D^5=F9-QB7m8geQ6qBO(wyXcXcpIu&nnb5WNs#OyF9LBIi+Fz4qe zEg1QEgDA1{Xztx)l=n0UN%=9$XJt`M!Y!6?+2egxXuEg2)la?JZP26}Nb+3m-fL9G z1yKy=*ke|48qq4Sh=g;Dh{aKn5z3sg$@HqbZ|63%Ji=_AtZOUs>~3?MPE=^vmoTI` zUWn!@u@Gvm;q6}Dey07?p~tEF!en*P{gfwlHqOo(MToXb{{XR#S*&@p)iL~k!rL#H zYoC69oN14CKaBc-UZp=BpVU3d)PDQt8cHL^!fCE^zsvfBG;bkIOye2&Fs2g(x+!d@ z@sFt8Ju~sCjdtYYb74Be1Ia+tRdC=oZ?bZz+SwqndZ+EfBD=X$-?O<tI=7wHfa@K+ z%44yr=MKHIy_1zj)yj`%MNiofaUa~N@7dg+ofe-<()7JSEmy{urRjQJjT&B;rRjP! zX?k9lrRdS6>3Uw5qehpd>3Uv`8eW&B>3TG2dR~{Pq1HXe$~-#?{PU=;$Zb?D$}SZK z9HYfZ&86G6+eFrF3xNbgl*U-HDyoWZ_5>B{VY;oOg02{}#_lxS<M{4DmR!KcacVn! zlK#}~i&;rSTQc6-#!Hb^poLukG9}6?qAK{p7rV6;+;EDi`IMpn-cyia6BD`QE7~!! zKX*OKjcR{2RMfBZ4}80My`a2g!=FQdIgQ-CZgHcgkxE2q=FW71ICKFL!RGglf}Uzp zDG|n{0T3A)QDHLs4Uq)(itfldW~K4aThd<82X}cXnh@ll44mC>g?A&-al~yw;TcFT z2Qi{reVNf_$+E#H7dppqqy5uf$vG>2To!g3Y*fO$Fx%#6NW67>FjY4yw32t<m|F}_ zPg>BZ+55UxS2`mgmDKP8kmnoE$xSTDnc^%<bQGnCFd5kJ891iZZeBi;h%7$Q8=zTE zw`tM;0KzXOxv{9vx}+O%>}(HY*t<;%b4iijD|-nUxoxFspBjR!h^XlmHPX+0A&U63 z4M1VNgl_M%u#Jz4O1@JsEp+EIfQ#_H20b||)A0AT1fI@n6&KpPKF^cev#`ADY0|em zjzcZAA+bJ&y{&_0eub0Gou7xhqJG@Cr)x0CU|>mGpri5loMe6*#Rd)v1V}+~P|ILn zNe@)-_Evz*ZwbeeuOXHmiYp@MTh#zrc$0;))k%qx@|(Wi(Oq`<Q+THDtlITfZZ}Uw z+NGD6{{VtReRa5psHO2$%j+@@t}d}^IM5-{Z5|DSZG}8aum&}JIF+@f$;)37G<FOz zgHt~%nNrxoV+R}1_y*RnZB1_QkUUgFF<j>obeS_q=c>8xbKZeRxy#C`k$`LYRaIW@ zSKU`j)(%l72@8!#rZQK#9UO^*Ehdl<!&i^8z#tLs3Ke^XLz}xG^DS64U3@iS(bLBn zPvtdkvis<s+0Rhd$fcB>JHXweX611RJBM=Z=2Rw!wR5<4(vQ~iCea}T6J+I+#gI8C za3nrZYW0(q_I;{IJZh%;uABhGXp59(c*ZgY6o$yM8d@N*3W#@>-pVz2*cEWfh*v&B zAk{=vN2)4~>GZ0k#Xtn6UN{JdRp;%%+OPNbPj7F3boTtFxbVfBk#u-^0&}*cH`#xt z&Yu4OiyLUwefRf!zn}hVRXzUz^n3mP0LQ79XHnfxQ%5V(mW5|NuL9W2mn&SonnR7m zb(e!}qZ}(CiT(6=<&MVG$u{kq$i(R68|PSh#hdlrk0OI+FPw}=<JMwlBwO#48AT@T z2eQ?oZgqZIM-?j*WvYs*s(LZhUJt7w)z`~%qKbx1f(azM)Sfl5$7aW%MEL`rTs!K% zd$ebCyLt0za9HKEw7zInDYV`yCMKM5CqmM2eGoC^nkw}@U7@Hr*fnsDGJy13<Gp=G zJqcSIiF<;nuj|_)eN#{4aLYl!h7l7)0yxWa1P{m9%A-PFq=pxCD6Fa`QM8^QB>QpX zC9#zp9gVgqC9B7XG&dJG^-LOL8>?-Ks=$HH<f2BB4GNk=PQ>O;L>hSEpl4e}&5s`- zZrIwaw{RQkhokpq8!;+7S3_U0cH+rB9e4BWn@*dS!n#(YIPbo?vbwQqILk9qVTI_( z^ScIdV>^*uu1Llhh^&>S5wXS9DP@5Yj)-N<^wbk)&;TkHH|n!38YYzLZyy~~Fz6~y z?+;8p=783~$OQiY6UpPVaA|pY^y)(7bK%XEE-}V~oFM8#?c$k!e9+`vrl#Z+TSG>G zmq>W_x;e^QM?=X<VD?En(z+32!nLEPLhga8w<ToQbt;h*WOe@L;__*j+2vs=1nr%C zZfFV8`Y=c|gsZ13wrcd<zACNC#AI>XJFbSb72ekuL)b|`Z3USOq%K2@6(9l;ZcS}K z6@_phanyv(^$~7GCUY)-d5XTze2uxVm`P$<N=}CBz9?fC<U^D_rF_e+9!rOhhsT9m zoXuOopi@;)>FdLzc99&ALc2Q2lE;!`y~dPZ@lo-UTbsmbVt<)OKKY|idE1M+_+oAZ z{2CH>q(Dac8>M2s7kHkPR+U_g?MJP954b|YE6SJvi>fX<@6HSKO{%Q2#F@!C^Y4QL zSDS~d;%?BBHz;V(*Ry<d-mng>1Ieu<kh>0dBV|$%kI3uUi*q%hkk?IV2)5!fHkJWI z0fcW6WeJ}LFDjZ7-Gn+e#gW6V&u<eKw24voJpk^cwWJ_|OTx(C!6m9{B5w`Eg%D(& z345cV=VRHG$D*<<G|H)><&veNf?aQobyqC3Pi-@`iY@N$;`rZAP+c8ON$*P?Xe<|< zsyX};&84fVZ71*=W0`AyX_K3X&f+~Oe(r?Aa2gOy{CSDG`*3g)XGh?hn-!P`OeA2J zt(B#n+@=Z8l8Xvq0w%?yq|90HD9vpv$sHDU*Jh3)(K|xk4uTCuHxiy7Au(Gd9p&Qx z0B;|sz>lw&v4mrWMz!pFT*tBPM=|VjD_qw#$f)MI6;aJpR8#=ZKrp{mMNSu4Yn;b5 z>~giuRC8R_R=KWf@{Ve!3W|z|sHmu@smg1iMQ1!6YF5?Vq8Yv#hO*$0`v^O2RdBwj z37bbo$%ZAW&ln1JuDUTOhBZ;xv97n*7}>z~OJ{b;JJ6XTu<3+iRE{^>X!+5FR7pH* zo!mBN?Im6`$Hn}6o;1~Vn`ar<Y-+aI*KKz9ZGgey8t6vV;aH4e%f>3mX*oomu_)Os znV>`MTD#I+6d>qxY$dWx_XQ_F3nE)KPg2ffWYkr|(yfa)*u80{+wZQLW8&X^wbNXC z@sEDnXBgKW{O1_Qzd6P|`OYzq^Ug8rmW|rMe?o2seYev@<&Tf#H<V05E5E$e4oSrV zM{yNiqn%dx(wO2Zy+(Gq{{T|1uHO&4i=5!p7i2~l874gp^F*D!s9BKOI~a~e{V1W5 zvLg|#<q^YjC$eh64V)nDx(?ean(dsTlZNZ1wl+y*7SmM{RXwrq#>uFj+V7^=&T+Q8 zV>r%npI>i6&&FSpo<{BnTl)5hyTMpC6+RiBvUtAW=8)+QknNsiXbC9Lb_8lHP~av> z>@)$Qz}u5#7{a3vHn`QKK#_h^JywQ$g5^7HmRw=El?CQAeNQ9DBC8^)pGj!g=4(#^ zS!=AL#+D$@gg{M-@&&ClbBwH2W07@UGsO}-`O%=*Lbiz(WT?^XtEESq3TS|5iIQVU zib8;+Gg^;DVIAAu+U^{Rh`ldM()5qlmrK(0y)Q<MFH6$&y&5#VFH7B={{T#T{SVup z%GZs~e$a-tpKJ5Df+CwL?2KwZV+F8gtkBRlk_58661rMfGu2W7)o$=Bf3ao3@2g_m zDo@=$W`gQWV+_nQY0FoJVwomgW{AaF>|%=2{&FE4ts1OKsIufDJ;<$MsQ7b{QM{@y zzavNlW_QRqK+k`y#9*22$3Iit)b`~$_xz@a7p3Z}oeS-1@FjEi5wtC5c=UnB*&+7w zzi1mz*5vTp@6DKJ@)?@XtR`6`_;@#1`Sl*(M;nm+#ea%ICFDbKt#|q0^O11QscPDr z<j`DB->a?Rl<zPTv1;RL%xp=Vf@nSl+!S`f=!U_nxzZ6yF|ZN&+@uvyzzitCfqKl9 z0h8fasW*1d;fK~f<hTZQ+B0ve&W&H1?q$4OVFTQ#oF0ftWtWXw)mOXzO{yXyx0NRh zROHOcf*&dC7E{yx$YXJpf1ww$I{yIolUKPkY&2|B<FXRt0E8HZ&WRW@{iv~H+i9J3 z*~8)wl|iFKHQQ}<*;Up}JZEijoxS<Tyc>15v}xl10GCIaVgl$(rmRLIwsI;F&S<AQ z4o%w1s?maOZLL&mQZi%pX>PG)7)%YF8YLwNwvClp$Z_R|EJxW|@@Lv8kCORN@`8IQ zw=toy)pTsM`=mD%p3MG6+BJDLlGjzuY;`=oF5enLV)JmQv{U0n+S`_TgA?_~{>?9l zemzuaq1@t^L{7!IUBh|*09KT3a=p$KXQM<@+P_#x8bvi&Df7sVCf2HMZIMS9dWlRb zJU`oPw`e{JSVd7|S#N&n+-1cX1Y%<t6c%GN?oqp!#hZ{?e9q#=A=Bw1z^}%p4XUUq zO?L!DeEr0d^j23w7!grZ%_+)ad;VG`b`6eC$8*fp{I~I{z$xXA&u5n6o5XxuafF77 zs81k4x>o~GqvShfxa}W?lb}ziE^%<`5<a?$;dRCVh{s0R!io)a(lsMEO^(^ojPRM^ z0B4n6r0u!)k;~@Oy2SDQ$_kb+YAtCJmHz-~3jjHJ(8*RvThk?6TBz2*#Y1DO337la zx%p^$(<K7Q;;*A6NA1xwrmcAIBXTwKbqyUK0UGB1d$MdmpwkkXF{TVEs`R<gQRZ>+ zF9B<?+-eb!VbS3ags9;yn~4_TlBze|FhT5)(hJr8AR*RSJuso}qP*_AxRd8D9=bH` z0g^N+A={TwfaYtVmnl>W8erWAhFG~~YeVUg)#2Cd8Cy2dboa8G4_orhrQ3XC3uC~@ z(yVLYdW?d|Bkfi)-zTwr+=}5E=A+t{c9M~=S3RiLIaN^e?QCq{-#THWaH_3i-N2Zu z_fdt2(GQ=p_A$KvbbNWYl{v?cYhm>lFw*t?BVG^rDt<i!0Mt+2Un1EipL&y)_bPH< zByimnlYJ+Z6Eh(r^7Y;MH#_6v^cg*<j<jpbJ|M5K?8@YP<EUT9xqcFYP7I){*7g#P z%Gt>+uqSL?=)-zuFJduUch1p|ID9~0bI2HEU-83s8}-e5&Ua23^C#xVoxEVw=8C%K z?tZyHO-Yvm(d)mt*!d`nzO1s;VAWPC7Hv?%VnyO%b$X(0#cv0m91d-eS+nPva`HTa zs}sksvYY8mgGY^1T4Wb9UW%-TRZRr;HZq=x?yZjwF^c3*bw)0{VG#~d08Q>Gh`|l1 z_i+g1V;Y~;%8CB~9aw+BPc~<nJXUh}7vtAqDz&3-`U+w7P1-bc<b}xV@|e!fTQeX} zR90bIsRjwQ9Xd>w`ia#-g8-1-$PtE1*MLx=V1^9{5NiOzL$GEjKyggljut3b_UW`9 zG-&pTqS1>6EfGblHf>T#yJqPof+^^pn(L2$t`_%0JhI&#$j>(-<GHq3)?bk2a>TCh zNW{Ihm12;_zh;6HBr+s+H4%dVMlrRlYf&VeD9nWtEJ6POf;4dftNWms)^{)ScOA;V zbyZbgeJ@r0_L}b<DZdjI<b4+_GBeN?1y@FbcHMV~E258NpR?qxafZT(pt>cXRcyQ~ zv<SKe&t^ni?wM5x=)f_10eYb?wgb|Q<QFF_@^Df^+$UQ><kwW`vro4?a)J9CnsHcQ z(r$IpVgcWYkHU`_`#!6(`r&g?1&FhFj$_VS$&ZJY*^_j-z}b420Zm<u<gDCFhpSxR zf*t}V<k3A#T8rEXw~#6-m5)UcNnkM<JWqbK`BcP(Lt;c;9$@-Wr{!HKP%iEMZ5!VH zQ{54YsqTrYfJ0-XWDnI$es<S(`la#jr@!B>S63QojBSj2v7F;w{{WAFzc|Ky*v>Jx zxV%_iE$#R<9P-Q|YSqT1u=v$&HnwPhM`o&Bw7e$RP<uFRs>B3h1QHRJTbYr;BND){ zO9FE+tY#Ke1{Z5aVG`481Yr?5x$ifHsHWxYIgOPZxKKLzXn07~Sr?hYWy4S%ANvC- zT-3$u1~CBDi9O}JF6<3iKXS4!S#GLtG4flDGBz)fzDk?d_MC~LmqQD`sVk~Fox4LX z41w=c)-jkA{-Cq0X}wT$OG9aun08+>=i1q5JPKtWs|Ubi2d7b41&d{tMn6B-vRyD5 z82u09?(64?MHdn)D1%uAZ))H@lMB|2o(a0esDV2s#HiJXBPOpDITe%522ZN_P$!J* zvy)&h+$O;=vNFzGuGOyF*giPy&S|XkV7j=e+i-kxd-{&lWl+nd5?7S9uBZpHAy6v; zSsW@J9IL4t2>kUpoYJT*XH?SXwSAJ-F=3Y4D(iJ;75&$|QraiTavCDgzNL1TCqswC zW5R9TVy&Q1DXOV-{o~R3keodT?F%+Z97%@vDp7C6N5>7QZ}FANeq|iV<k|#kyTiG; zVtqx~HU9uRqjWtj(H##J=-W#c_*f7&Rja!4A#ebLR(1I(M7mJo(QSe~9d0_7+A=_u z8s}L7t&<H=MAz0+^~Q}ieK+H-zk|-XDm_5jW$rM&Jy?mDhmc8OI@S6%mAvSiyPsc2 zn+R4@FkkV;=V~0h7bPh0VIt#7XiSV^FuvP^WgsvA02$o16$<dZQ*+qwLeu>p0Ol+H zQ)1VG#52^a=v9>XO}|<Jipk^#Uqhc_in(8{13aQq(1OLn6Hv*5($Y*K?bk(lGpB4g zMIs)q=AEheeE=1dX04wOwk7h1@%Z`{^^bQhf})KLNO>Y^&h0rvw#A(13o&Vt?Gr^! z8RI+ptxqjb3rRuZ+;YSo8x@$_!mpl$i^C?C8#HbUKumgC5MtwB9xotsS;FJ4EQ?5_ zN+B85#zSvo9vbx7u|uM*BgTzuGXDS=FwOhUx8;iF+b(*xu;QHQJRfk&tMubWSU~Q+ zcC30B<e;r!E^Q}G5>V*W=%&fT2iOGFEVwiTp(Xl<+P%^~_x}JP)3r@~S6_VIddf9X z*i!38xLkF(4lo*X9h_9n>tm88i|q|IbP<5hA@@y8ZJAVZGj_&|$|E~7dfqP5Ng|c^ z2bLIVTdI)1sorr1R@pTBDtr#BmYhqhIK;{mN!3ugY9R@fMv34y%7rHaf{F<-RCz`u zWKA9y#*YUs{{UAAG94A<0-?P^#_I9B+8Vv2VXSQ;QF_!hgE~6xy^(FB7G))}4NYYZ ziX1XsAl3bE8DcRshKt00zK!8@SCFWFL~PNmtHBRQsZ@1I8dSpg)+Ny3b`Xcma^WP0 z*f6%l&&1yRy>wl=x)KzmqBpu5B-v%i7z(}!q>BYv5V^*i?WX$grhXmt+g<g~yBYUw zu5q1n?#?re`?HK^-JE9`{{TE^9=Vi8WU@E}wmmV4mUaSL3y}$vMoy342|o)Wj*@Ov zDRwGtuKMWgaVBk^wcl-b*Hw{EZ0oi$?$1N+K<QYwTl39xc*a#6i<vNVTFoQl-0HvK zmJp=UYcq*BMMrMPG)!rHDC8E!@_`cZH__=XTj<Q=J=CU;i5Afsr!Ju08n}GbWl=$n zWd#!)tp-U_2PIUwPG6;~ZA2!*3ODIR$H=7N=Vy|{`a93ZK7!Y8CrJMNMsnOzFpfl0 z)6Oe>bZ|HBzJkr}l0{#sQrW29SSNPVp8e))bA-H!27puc!kqf-#MO!ZalS~{#H*pv zSVe&O_z;g|c7qMldlqLJ%d++5ha@wg!8t@(!-n*42PuLJT4Foe9@J+8w*v?2UmQ|i z!is`zx=trh+Vqv5I3NsWil~FKc9$s{oWe%xkhHbKlT*s+#F5?*MdXdr$5bf0-G9nQ z2BF)uUWr55k4pQi)OdQOB>1MGnV3!fS>jb+7<%JX2ByYX!GmRkJtM0m#Y@D;)o~yL z8hI?)^zQar{MQq?;>|o;b}5GO&WoWzX%*)qa+KS}4%rozcsU?WsYBtPAU#Fx`dD~% zHED$O{DNU!v3B6lZDbX+zF97jn>rnf>yK%wLA_WeC7x%vOenbSPV1N<W=9*w$qj>j zS9=JtvN$j@Fu1bhtSRu~CFrdLDDCv3F(Y>O;1?S~oJ>k*N{NeKl-79hgsxbu8{F5+ zs3Tm@0-mVPK#Xoe5o@0W#Cp8XYh#1oYOQz-NeM0W;`gU29J(=(t=v77ZoEmu)!RCH zHG&e^m0er>;}2PnB<~`03zf8NJ=260c#;k_MaKUCOUK5?{{Vtr#s2`SS{MHSiGNp; z^u1_peiI!P*p&$n2+HVKk1M@BR^a7E610lW!K<$)+@G)=u0bjt2;?LD<T9YtZD8}9 zg^9zY0KUoYNTEgc`>*htH06Ij+<wTKp$y;J^5&;2y=6dgpG#V#8%4?=O^n>M2DV=+ zN0}ErC{^lkr}u*FV)59JmE@%)`k?D(Oq!Qih-L!?Zdu31CG9iyUGy!V_EYe;(icnF z3`NlZCZbZS9>W);iGmA`KD#j0$21#SWf6%=&~i1?_Hsze;|MTa7pTL@Dx+pMgy?9& z`LzRh!y;@pD=C)K_FQH(Ge>NgZbm?Q7HC*zIzA-nh~`_nB<Zt#UB7zGlWmm3&Yd?y zMHSExdneParQQ<x(m#<{9g4ca=y)!#F#iBAGJ8@NblS}OuFdkvuiCPX)-J&QgA0<v znuftotxqJfIfmY&;aAZOV8GcsRcU%qIbO1D_Y-iML$C1FzHroJ)i9jaIf~?CA~BEh z5vFMe*v5PlHpt$q+caWD{0<~VME&?u1djLr0JOYu?Z+#~gVV?#wEcOp3f_(I><Xw# zVmQF2WbQ~*;xi)*TMH2yk=^rfTXfi1PQ%q{yRnH`5odx5ZJ_cyYDghAh&}e9$6nY+ zN+i)aef!S5geaqJ-Z_srk<((-0Q4i(+cj?PO-9xC#Lss!G}272jfBjM08xvi8yCQr zTDcV7_1>4KyA|k{q?|RweJ4+QT;hd$gCh4Bhn7hb(a83YQgXDqkTS8zio&psBR<S~ zQB^gqK1X{alqIaxMf;$P;5AeBR)fZhpSmh=zkWH_GN=!O?yu_q04(#57+v+`rslHO zsyN(lQJ<ePlvy`3V(4uzgGInsQT$x;*4v0|4nu7^l43^mBmEa{Fp%a^u`i`68wX{2 z3)vI!^-p{bEEsj=)5LM{Erl+tkhn3e9_{u$^ihb47=12+%vr7__RNOJR*@v5c_Egj z)Hk9a_6@F?8z8K`uPB?L5?`1*qI^-gB`6oDW=Z^r_)7vz9lUFI&eSBj{{R%Gi;m22 zWL}^i<L7A}Q8kAmMN@X5^(5-*Drn)3x{|KCp1ew`C^c}SSHlv!gjF0^f(RI@h={7z zCp;%VWY(eNd0ej}-bb(9&vL!X{aoc$U-Q&H=RY5OJIJ_fuQYOP151@_y2@fz2dpB4 zXKs{V2h;e8*c%O6ZeuN)N~A)E{nkMD?O@D40z2tKtCko7K43I=Y<ckZdTADLane2D z68?+5_Hs$shbS)Cdl+QEgXF}VY}tz^^{XC!T5=qk1s$1qS7w?=$2C42Ud3%+>ZzCJ zLs=fze-I2(SY_&b^W$QDE@K!TUpWX0#hJP3sHvpOh;-f32{|=d*fG+NR27kgpX7Wc zSHzr-5rJ#$b@8iN`d*i>E9cBbvUo_F#-oQ0YT@w*@0=vjlNK!z-NUz!9WT0QHfq%b z)LFxYl+h$o({&WzT{X_wG-|qD)ptUzLwIVuf{$|9k=}}&)tvMh(}f!4O%agD_OK=m znlXA9yHZX{*A=YLHdEO^?uE7@;zTUVa^V;@c3?OkpVZ|(BIK@acFhJxDNc8&tGP~% z+p%k_xvX*y6_n(%t;QFS4N2L_hK9_))N$iXKDGOdvn)lnQ+Bl$J**EZG`B=s{AtQO ze>R5nX(|HDcXe50Aqus#>mv5E)c^pg>cGUJl1HIuk^#*zHqywCvk*t^yUOD6VRBaT zKhNVsEOXEF=akPW^%P3P@+oGmz<ljJP~m0xQ<NiiT|d$jSTfQ_S^$W3XF%9xl(MVz z-T-0tse}fU317XP#iUCsAU6qq>1cRUM!fz~{H*NO4bYUA7tdWXPJ)jWGv0l<4^&gg z7Z=yUQ}-RLYpG-Wtr?zob*Arj)paRSgjxH@T=qtR>GQ~jBX69GtiQ5b$Z5)LzMS#^ z{w%ak76ljdJs}^_RmuZIw8W74wTqGEj5={5aN@X&kAcL75`3%8O){RyaQ)K7MX9oH zN3^?kSCPeeTiNaLw_U|x%zrnpj$3t2S}7>dkIg2^2vUZu4lLhfbu3is(p2utB+Q>A z-xVVIw40ldJTak{8d^JtIXV@?yrW6-><{F*7ga-9i!gB}`!?QPHX^FV=d(vBsk*A7 zw6bDI(cM}ovf7Po^|+?{;hPrvX;VKJKB0lOI|ePGrk2*`JJ@H|$za~qJ!S<>CM3L) zYucUuHM*1NF`zKxMoWV__>qX&6{@XVV3kWU(Pxpr-RqOR6;s*rh}SeNPv6Gg^D3h9 z*EC3}!}TluFH6$(%Wj^HV-1=W8w_4Tb@Bqj0T}$rf=;&1t%r*i)mOwHINMxpwx~2{ zg3GJ6y6v1Mp4rB^&++Syw~&6aJKUX{fAsN$)ok9*p1xin9Yx)`*adb47V(PWKb0N) zJMQRQC^$C6)<vlH&rD#0_Tt89?+j4BN3{XuHK#Fgu6arUC2ZR7>;})H2AGe2mJP)@ z*{<6mWgU9i1(jWkYawhSQwvDD6qrfl<?Q{#J^Q3F)*JJQjI7bA!Ovf%h1xQ5o3&Bf zUyDU@hTj?~@2-ElzMCzC{xtT++Ha;d*L`-=J8Pbfz6`xSNyc!D)2Mugy+J>49GG?p z^Ns8}Vf2%H`4ylQewV|)$s@#oB~(H+_>oA@;7VhN({2r-8cb@TKbFN$Q6&*mk2zbw zSih8Tg06c06(lF+zQodP!*IB#Bl8{m7_v=E<Tn)d>aQ$FoA^c|<7?SnM-Jxss-nQ0 z+D>WI;gi-q1lg<Oj=@9qY*-t{1H}>?i)jH#>1g<{qGDAghAK5<*d;nAohr(f+r5RF ziO0uPZ-ZHKdcGWd6>4dOl#H2k6@13?tD=q`9~6@d3q)s9!CJ*eg#;=_%FH~B&@v8C ziSyu|P)HlNOoo3sicYn+ri301uq^n^KNXrt+y!zwL8O{J8%RSk$O_8n%xd^0x=N|_ znZ}=MH_Mu{nvCRCr6CTCTULA?w5@MTuyMJg!*-l9sUs6BA7z+{V^3mnGE#!|y;mo* z3xj2q<&!7_6QWXywLdHnZtt|*Y4hm66`c89#qAK#t6IT*X7ZK27^k{-64+oykXKKP z7dZ%(%IYVe<j>>}gV#2MNW@t|Qc-9WpT^F{X5zPvD%kW*kmT|=$93l?$?I{IZI*W1 zh)-&Wy_Py`dJ3Ix;F>a$C-rTscy5x(y5d-(#B)qFP=t-aGCJoZ-;ItqdAw*u&$T?f z3AIElfsS*Cg)ePdu#0D{B;e(9)J$|ic!Q^eUkyW7<;aSv#?NFDDU{}WtUzMw5}uh5 zR2E~A=!iI;j2DnD_N6+;zpdlZ9&Bw=O6!0zI7pdWdp=n(%Ju9_WQns_yMU({w_}%X zh?!tbc^0buexGO6mWcd^?l#oXqVL&!L&vcueJurpQV7DGaQ)8+u1e1%wjAu7&!OT? zC5Gw=``P*vg3~(w4>^!aqwS~hBb9UlFB5?=Dq;g6uk6(o1u>6COH+e6#=`B+0;p<; zWR8}sI<2=a3OL=|#al929A5OaF%K$fSs{SY@du8C6j7ha`+Pnh9U|aTE8;RUcdveA z8?ro__NAB-x)o%b3n>)=lE9`T+nT4Tw|dN_6_j--d<^B-s+Hf*=;zUxhOS~Gx9DXp zEin@@CyTA3pe6F5=5Y77lYXYXo4^IllB`8NuHHx8!Hw2j)6G;&+Bc+Ku_n>cA*>2A zpspv4BH_O7?cn%oa!f=Um`q{)LH+O$G9yhIBo<vQ#uM7wu<4+@uZo%sCjB>8O=%jc z>#!VeK7|pBG@Zboe$u*7yGq38;hH2`H93(7imwWvwOC0=m0?m44qItXyCUJPZW-j- zX<K5wAcYBAR+g>ay=dNGX$Nw^^dBJ0`gomq?soU?XT&$NiC1o-2PGpk!5G6CL*nsv z4Am4Ua!_i+@`Kpc9fJe0Y-KCCQJ5hq(fIgNT;I*ED`ygGK|M6Frc#PyYJ(K)`gu7~ zxX03a27LpQP7Icg!_B>rs$vrkd<(;1`BLl)67Q|ACuLy~+ls9=oQ5ekttc*hrsNA0 zPwZ(Tq{+oWRKaw!n6_yi9w~@>IVp%?;MFt%fcC*<5^?4YXN6y~D*ph(T0fB*78Mm? zOyAXoa2BMC+#w|_BsH{5#O^~4kINu(hX9u|5+!BI=X2H}BqCgd`ndeAZ7_N$^H<~< zNmLIa85)Ydz7)HCzd2qG=<5WUO)5L|h@tIBzIBGop;oF}ram-zcMe?W#fUjOHI$1< z)!7YH%gtfMT@qp@Izcya*5mDNg1k-?b!ZBJpUEn#dSGZ>D5@+(IuTuNQFG~rscX=c znA-l8BF;kiw2*wZp^L&M1Eg{}e1Vzt49z9)P7W9BT#j_BM@XoOspmfJRo6Ogoim){ zUA@`HJ^0VNIQQfD#@O3m>x}w9?tb0SZpI0b;29v*)tL+jNA&}1T_U<@p2;<~u{)I$ z)mBdwd7*2S23HHhWOxcjIa7sY*0>%~PnA=<wrxzNo5J;0iezWCMKT1A5m&)BDGMB` zh_7N3$TewL$2X^EpaJDq#`MZdDHYpXY9#2+iG-aAF_=eSt{o#Jl$41s!R%_st;Miy zyT978$Aeh8dN@MpxtAotsUYLrPSA3k$8_-F<Yf+yfHUVyl1`TQ^=cg!u~LSd>8VSK zzY@(~l>H}aZH<l3AtRb<-eIEu0ON;&B+78AvIoh}iU>J=x%-Jbb$UA9*+U-@G8}O3 zjVJ_3Kd19NVq@AttD4sV)2QwOAxVz(b7VlD9g4n|+Og~fuO2oH)Hd3M&;IdKa3+`~ zVu$9q<=l2FUX6005;dK92=JAviYakQ<o-Mft#Ma}e`=SVIx3?fU3ny&!ugk_YB=j0 znX-@PV3n6ai(;Y!9?L>7U@11xTRpRt8}Bu&P)l)d_EE&fy7@8e$RRbYi|YRXBmO>a zytPWD?jB39pFB+^QVka9N~ElXJT33}X}pc0D#_vQHuq=!Rru!4asFvz`1Q}%$tQ}V zmYmJMTXCs8R-G#wE|lc(kS1S47n{oCo8<T@{02lD<SPxkP&&be`V_;k!lb2CX(xVq zHz^)e)Url+zw=YXSFF{i9{J?so>q5xwU#@B4D0)cm?&04u^`>#g%{$wbt6##?W$v8 zpJ*l~KFp1WMmM&ubSGq|2}~i``K!^`t^UEc>lO{>F)VQ|qX0jtaVb&;`;2;H`D55t zqeinUOjfyT?SLl7m=$UfktVWC7}bfn`%{zcW#KDsqrCN|DLzen0X?<$(b|aQaNMfo zk1%X=Qd|PPOB{&hV~-iZl5T<0>u#y9!KWvlS+(>gHn8Gm5s=HKamd&;L<Mi7vjtNu zWRoTvjS|sB-4lJQjJ06hO&4^kNo}s#tOv30Y}RKyQ?#rF&SOrjcvnPRt>o}+i6Yii zFYf8ar6V2vk>*>!ekJfCjb1i5EeF9=Su#T~L+-&1upB@v?`K28#n2hfuK0$vjD6(< z9I}wqGCAF7<+h4$le8WP{2E#)9#UC6YmIeKW40@{S8aYq`faXpTR&%8!M7K5j8CgN zKEplHqb#m}?+fRcYLc~;=_aUNMqn@)Bn4y&qav)3i%m9`$r#!Pf=XYfCqPT^t(mZ9 z403KwWV7R@%UuIKFG1xm3B1gf`g{5x$ug*GzT584e<YoSt7Y@HHP`*O2->MF{A;c; zjgnbC^N-_gw#G5;$T;wI<M_Heqc0oQ6WpnfcI!+$hj-}}H~yad@2gIg9){V^^v*U% zIR10)#y^j7qd`}*dt;LM-`c6?OD5;&3f2h&gm}#%O-^NR&n84H64WzkbS#u?5_a?w zWfO!*97oLrGnTTvht&b+0IuOguyj5jSrzA!-yMSDG3n{9?c@mbLRcY@=-JsfM^sU! zW`vPLR}7sn!Rc`2*7}6@$H0aW!=IV&Lu7SdU6aK#ddI-$jvC9)uZzA%fYs9Y?=|$@ zdwE#4%~7?VH<2(hVvvN}c2H5RWis;88RH22rQ}cqZeqm=SJk?Vv~ZXrG4rpSo!aA6 z?~896)Cw(isCZwMVXv90vdBoAQT6#bmUmgouKml+&Vwm0bean+r_mzl+Q^SbI<{h) zcFCrWhK)q~3(x-mjELJ4$W*rE+pwo$bwe$x-Z7^v&W4xBH&N?W%c3OYQaGJl&t^>* zSi<Vb>{#nn#;|p$=MRZ)#B<tf^1pxiD)LR|deZV6<42d_69r(f7S*Jhr?BU72oSPd zps7^j09Lc)Qn|Y&+0TtTW)@E2O1md>9F&P1ic$GoXkncsT`*ZOWHqC91DUm8#iCju z(UT_WHE7iY@$S(U?U2zlQA<pJ8YZ5a>8?MFV;J>Qp9O-UQ%^KL(Y?7I68WCdj*+fv zG0#4aVMA3WjN71x+iCqGTH&Mj&Sy1%vVU>T`#e<#nIz*~cRjv$G-#kYg?Y@ru<--; zUkP~li4e<oL%&Q{HXm%>;oI%~<;A|1+-@lfMX5bgQ)E81y+<<~-O>rY(?Tt`P<DMS z{48^=j{TH_xGp}Z@+}}}QKX5uZmznFxub(fk<mQ3bsFXRjjdhJY=y46dZ?I*1$!yN zNv79Do;y{V4mB|Tz7Cx>V%fvjt`KO=q6<29?b6A&Y}K=L_EmQd7guc(K?D-hbyitj z^-VPO+kN)eU2~ioHA`+t=UPg}_OiNUttU}cRh2X2yOpAm;KHkTyg&>;_Pmm_ub{{_ z2Mmq3i8Y8648qQ`W2?Pl5>~`|wUVuzxfbqD1MKz(^8Wzj>ay`s#*@B+l{pe#)G*cj zE1WAA=(&ESmvfUE=XmQvLzt5a_eca&Z8I&iOeSPD%whuG3=BnSsn~!sb)xWN+B7dW z&^~57+jSJ7j7k&J-RCM59?`pE8%-uJKxrno<CU#Z2|VRj56a10Uz>)F0&O)Unhl}_ zolVI`Vl}y0dNr}=KOiBz*?A|8T%JJfX1wXguty7N6sg!qjG1Q)t4ES%>uTa9wpMSI zEc<Kd*(YY(tpbfpRU2f}a43t5!5|3e@>}?LwFSmSIz5!gw6(JAj|!T)RlU5%L<`I5 zD(c{jvg|A+Ij9J5z{e6qf(&iryOjOo$0U-lBkV^J?P55OXvW@E6S?GiqguxE%bct9 zx7~DdJ)2$<ux~43+Ve5jj8v0YH!QZnEkTkqu!VIsDw)dUX<e6w1Gh<MK;CF&BDK^3 zJ(n1ZVJ~b2^a8l$;YN|U=cWUhXB8agk*f+(4Zt#{_OBsYRb%3;6BQR9Tx%K`h&w3Q zv`}n-z%8R6Yd|>kn>I<1?He{t1a(UZYX1QG;?Jus^UZpO-%QhRvuIMOBsy#8=&?CY zD!UHGY07BzSn9C6D`rPW8eP#^IP95!GS+({#B8LD83##O9;UWDNbYG9wF*<BC-;L9 z5ngX^_gC4YMO9XbtZJ*fc~$ASx9zI_hpVU8HLD|I60WN#shO0*LPcFuZa5$|YQ1%` zdS^J@+vhk>R$|7s!jFoRaL{W696fg31sq-W*G+cceYMj~HO|}bzHzR)>#j4Mw%csy z7}s5KjORJdag1Xb&U5bd&ZpWy^De`#=UZ`KFV1jZm@3n#KD1`>hnoIBecFN)&dr&O zDA#=NB&usSe-@!v(M=;$N$O4}Oq)mpMQa&)yMB;*T+2GG-O8*Mm~x<EweOE@xOr;; z=S9YGh8u%+napq>dvW6>emh?NUoLZ>B&=;^eVnMj7uN!$t|Y=Ic^tkNqW=KnNOM(M z)nCIHh@>mO3{Dg4a~j}t<d3+fzC=3)*y-7F3y2pcC!iY29IDDItO})!?6CM0S2)@0 z=Klb8Okcd*!O-PU7G892Qh0j-txBfBv*QEgsB?}HVRpWbztYAbf1?Q?X~}nP8savr z737Ve#zAyJlM(n&ZJDh3XPOl!m-;yRa!pt(k@^epZPdfGNN&q_jae_Eo9UGPG!#`l z<8;zj8*8?TY4Lm;Dwf#JyXl;1zCHy%lE%}?Pg3p9nCI5<x+fJ*p*0Jm9eCT1zasgV zi+&r4XY7nnnX>-?Xy68ZNA7>je{W!xb0fs(5?^tTU6^86tp*K?<Je{^S_+JB6{fDB zqO6RI;e%CG5Ky5<YPnqUD8LpY%vU_dCvi;omG64T)10zQSqFNM$0N#DuiejkmCjY; z**R5S5jaFoWJE;cMF5W*a<bI{`ZQ%MFkPQt@ZBBOiu9l6mMJ;Zs%>Ud^(RcpV5ckR z5~S(YwW|mv(~6op(mMtTVGlP53vC&(<V*@kYSK|3u=$^x#88}#XVP^{j=ffVGS5zR ztg^{k$uxYN5ZDO%L>DgFB>|2OX7R>_iLo3K3Mo;@7r?S)<hu-LPk4@V$roA^p~myc z**Z>Z27tswQ$uJSde(6M6Cav9v166#n~9`Fy~`o3qf^JbOd~a+>G?YTIV5Bd$XMG4 z@yPpud*#FA$E$8?gk@JVk5P$1hwY8RHihxOA5~?eTPSpVmG|K@3a*5OOyGK&E-k9E zJz-K18p>GZ;8`9D11MB$)egTc6#k#%PC^DFsGtzqF*r;93cjON0ecEPVowRpI!-Gd zoXBYV2;G3za$09zz^4+~lvNud9$Kq_Mj{p1^F`~q1PanqU{hcs-^%3&NmXa*Ba{tr zUbBVRoc&)|&Ld}L&#XgDj7nZe)^n25*J5LB3cf{)VeA!h5+x1{>*%ocv}9|CPVla+ zKJtUt_5fPmHDJg9Nrl(4D*jqAnW}o3bNQT>t&E`xug+boZ(aRQNWY825?&lRUWr!I z*AWu(XuA5W0$nN`XG81%03n?N)o{41CgK@SU~EG{3C5kmIdhk(nHaIb2bUZoHri)Q z(^d4(Fm_Fj5LGJuQ|iHYCHC`5$5b#783Cq^S~I>Yf0-2MXyf``If{;_>6%h2z>1+w z$HKIff|NU%G>pS5$uKCmvzEki-=o4rYzd1^Oh~^oE;1KCD(N{al^3#Dr_kK(6g%7g zHRach6BDK=+a+E^3v&*S)odurfIAtjs`d4l4-BKhBXQ{CkHnRd5iG9T;!5ELgruim z5-;~c?g9Oe4DuCP!sz+kp&#gITp474BIlWm+$E10i92ua1bsu)ypa1=0UkHkI>t>d zRtWV}w9Y^fRmL;0)w87Cwr6e;%wivUN^Z4Uy+wr9G#1Y>H{FZI+h|Z=`EY^qw;xR9 zzEjxP)^Y|(D3)=O>`{6AJxd0SKNhjxitC<<uteU509EDaGS6a;p@6CC+65p4Rry!0 zUqjqSqtPhNjN=i5gUTi<E^V{WFqX?H8i|Br+^NTYyu0$V&E&16{{XinX`N)~bGD12 z7l}4x+i^H=sMHV&-GX5f9?dq5o1!m4*c+=<bZM5EZSPAlzT4(b#-%Jkk1e{s{-x~6 zu!dy9erXl3YYD8VBlR{2#GrI!!h{<#B!bL05Y&Lg+zx!<ip-K(XAPB4M@yV{xBy<# zs0FT8&q#=>&B<3$OCYR~SEC;}l0^Q6_Q8+*l^LqIm%lNSotkQ@%pdHtb+>5uUyYF5 zxY_k<E%I87v{0#`LkWjcm62RwxJ(d^)RI6QOyd<_AqrJuwIAR{BShCa(z+nJ=@T}Q zw_7E+{X5RecP}W(Y%6AN2{U`qS4w2*GNsj=l(4MonOZ99_JXC*V2tc5q5RGAUn0Ul z#PXA(W~OG1tU{Nx!Q{=Ok<So3tZE<iI=l{=2?}_kIt|sD?#Cw8ri|S#*+tvon?IDM zzewNZMB7uH?HdoHpp}COQdT_j?|R*|Y4g!+Ly|<s>R^A&Jj4rSwM0f!XN8|0L856Z zq9uy1(MKa+WzN-nJGhVE?qKztj?K%bK;yd$ios+OCh9zV=@%JS41)+)e7JPJ68QGj zvs|pEb=!TuKX!BJny(;TF6#L}3>G<VpXh|k7LJbuHI%%~zqEy$5-kmbVjY8B=1LxH zHK}%F#iG+<ZJD<u*~%%Ro3!!i+jx2Gw$<b}d0?z5>?<29<zFp|!uQJq2oC8Z2plH? zUXOEzuR?aHm7S#TW|ysOkEEP-MtQTFUDM3`GjXuo>O~Lh-`4k%YtlA9Xn2;+6&%Ye zLCzJp<B~7|F|kPx%*pJP<&2S}NBF#&#H1{6(zx5xa0@QEk~SzU-p#Ve%z8o@&J@#E zL&&$?J+hj*Y=iM+*{;d+UDsemqn1t=Zl&IQZFwbw_Y@!OC%)GY=y-6nR-M5STV$CZ zWR}Ra-g^Sk(#pAc8F=MXbSf)#ofC$WbcnKxJYetv^Yr8$QS?7g*w0wPptd#DY8Gzg z_Tk~cB(@~pK-3V8ojP)u;H?avD2QMqcU^aSpt3`Q57}o5AU&Q{L8ysKtm+QV8!C#D zlGb*$XC-m;&VHT1c_dy)9m9de1(X&=zPqNPd+PKohCFGKjb61-h%<wnGjQ>mi4LVY zZN@r;#ZoMl1wL;~1G^K-kV@x8Bl#n$ZJIPv%c7c8PcYFQcm{W_f{IU38e}xtz2m#u zYsENFmKfEE1l#I0dLkW-`VxEvdZQ!SMq;mx>a7%^r=^sr-wC7iv-CZ?o5uwQ+`=0@ znc?gb+5|OGkvoDe-3JEPvchjRXbM&h%FS3!;w?!#)TV)*I}mM>$vJNsmPQdYe<a}V z8Tq!Vt!mwHy&(J*S#-n&D&(1W3pNQ|*u$G`qDYsGJAOe;giCX-`e=3(>wM_(#&t0d za`lU{G1!AkVELmzGCcM_%+$oT(Mh}2$89Ef=Mf01YGZxUMdpNEu_L}4ZMN*!`DT)i z@3TigF-Hx)SNG}*3+dab{10(uzZa>u!}44{N~5y2SVOCzNap3OIIpaV3QH=RDCq9! zvR+V30+J-?env=&%NUoqJ5#wh{dG@b=K;%F(Zj?mDeSNESyG0rS4S2*O&VqB?4cD~ z!C^*HfSrepAz0v@*=}d=Z!o^kVFB@D!#3&;4Q(Vvs!-`EbJ7~DKxNNr`Qu97Zrf5) z9$uEplrB$kq7H?31T!ljc0h~<#(FS={{Tkg*-h;pN|4yTOv8?zL8&9%GuuTi&V8Wl zdk8B#DgALXAtPQZ7zL^08<C%zjizv1Xph<694O?LxN@#n`rRBYU4k9^-lYYo-0clh zNX8ORW`-g!<>Ou^_;Z|Yi`E1YEcL{3(^n0)-3JIPv-ayEwo_5Foi<e*!09tC61@*5 z2Gy+WUme!5(yFZ9X&4#%5{G$(wAn`*pRUR|hq?}vry8))iF(|$J|z)Elgzn@NYG85 z%`KyB_lI%;P}tkEi`3msfX8~=pK5Jt@|OBwx0lYe!fUK$<n30CgdvTLLcJWK_j+2W zL+ld5z3b_>BiqN0@-`#67?wR`@%lKMnS*6mlLlj}IE4!(x~GFhFsyM#&p|qD8+iUu z1c8`WILq2U()G;mnR^e~Iq}&M4JD-IsCh!<{S#uSgphY7>#)p#?j3f*QE1#zAYEZt z$A(6m4lE%Z^&M1)#s%t%MA7@O*9HcI_Rslfp?478$>clpm?i_ht(hg_Bt+bR2NPh$ zS2;#NIKbMLdmU7o$m-3I_K^8XjGsSbi8rYX(dov|&Lg;3E_wr>49ju+l_EJuJQWs^ zCC#imUD!yr)$Av)shB7K01WW#qeYYgax(>wMQ)=M+UfPCbbAPLVHvB!jz|a>`=U8G zLN&aiwNX)1lvGqyUKdi&$N`Z6y{BIWuZ@)&9g@_CVh2UpN6m+}RJ4YdyMO=|n(oy_ zB?z24OlVN-bl)yXmLSAyB$s&Y1XQ$ETqBR;Dr=1Y0Mnmb<-E~(xa4cQxqMdjZxXvh zqhy?+Cg>B#+s5J3SVXo`#zp$Qopl#~nZytzwYyXd0I<ji8u$yP#UM<HwxTf7NY&AA z!~Xzj6UsEai=#2lWUHXD*IKi1Bs9v)d|2v9sM}0B(d&_nf~%^!yG>=Vi`dX74O_Wv z&*eQ?vzLl)EpjR<G-BLa*H-xv6iuBrG*^{7yLkxARuHI*%Bqd7Mx$J=R76!p_5rhd zt-6GgEx6mf(>L@^?3`R*7`wcU0p2t!C4|bzGNM3NG2`*JVSwViq8QQSDBA9g*i}8h zoNuqY{y%;({{XlD0Qd3gtbWWl<+F_WiRhU}<E?hN{I1`)bSy92+hv5fPFqf8xI}3m zt;-np*|q~Wk6}pxf_r6|Hst<S(lvTeI9DFlCrDGy7&hx3OehhyP;j=B3i@WkRsfMq zIbCsrloq=r*@#PanxNV8+Raaq`RS_lFq$@Tt5&cd!)Ka17sj6);)sNDH1fe|FtsK( zF`2MQDAsIbhNWSmF;pGs(6Ww{X_j%Q9B@C#Wrkz-z|20wKe;_7@#*@8i_r$h=QUn} zL)3BR{KglgJJA(YftBa<<#Hojs?m|oL`79kW!KAgcXi*ASmCYPT>JHHL}tvk#n%kU zlOn2!_lRthWkj_}YXUonVGW0s3_^Rz#<l9NZ#_wIwz>W>wlkmlGmQTL?DPoy^m$h2 zE(PM-`nxx4M;rB3+ecY28X~6_;i=ieayisUv{*%kdOVnUD^M`#qk?<LQz1DR!ZR*- z7kHaTi#mF~TGRusJ*Xcl_Tj)(zdymFJZ8?*B-RZcoS)bvmcStTLTQ*S9iwAT8nLWv zq*QG24G6l@I^@I^B5E9OJ7}wM2bt=PJVsDlIZc)F4dwpZKhicM^5doZQ;^v?X)w8D zo<ik{<AvB0NnYWmR~+!EXW7u;RwUyv=8Fy_`1HbM2-K-o?KbN554PJ&9~%wK`Iq@F zZ#U(578QuZ`Swqm+NqfxAyUQx83m1Of(#~~Wj+OH3g(28(nH1<=qBM=Jx#3oTk2aJ zcFL&+>sWaN8FbR?8elR|mTWr!N0<dHVvazV_~`Nkj58Xdaz8?gns}4Ed$X8hrpqTI zhVZW-L@k*dHcWU!fRMwdWG3cwIo8#XoTNRaqhm;9z|w|JtRxg6_)KOo4~@ypY?M+L z4j{nC?aBqGI5>zuCKFo+ddf@}M!UmKEdK!VH=)Zm9F`4f98rcB+1rM=(e_E<1UAm9 zZsk2w+ih&v8`>qAI)noO2jDr3cDg`AR*^{LdCW#N92Fl;ENC^LAPj~KU@$(7u%5!( zu^!cr(B-<UQ~E^_+h)i8nxjgR!4)_P!BNi3VO;O|1Y_oHzsK*!akf(axzG9M-~9go zpZrj_`)2B^A-l-UxE(#$Hjo$f^YCgMYkPM3l4T4k!Oan(WR?@6-M;q1%(4ba=Z-39 zv3)3G!+^y@obyv*p>KZ4CP#6DZ1vtynf?hs6P+t9*}cZdp!}-&@MW^w9Qi@0haPKL z7*2sSr?ZUkneTLSBZjQAKZRCr+W7F~th~`pbzhw+7Y)8VXCD()t0=my_SfJ2blDx# z&Yth%;rC}B$Gg!_lS*UI(C&}P%d!d~p18`-9;@(ao%Y7rO#~Cy8?Noz+1G7bvuKj; z-0zQ;-4#^MHOMOBk1n;v-O1pt(6Ei+P9BV!6EHelV0#GM6l5|*B?v^+qD!2!Y_lC0 zN4Jx@-3&Eg&{FE^MBw$>INw^n`EB#pKDo`vDXwFjJ=iiBGas4VqrO{I9en)k#n>7v zMvk{`7CWPCDue4Y2x}yfJi-p5PZ+Qi!ec9@x-N@%)2UvhHx8)Sv+!ZJIKPpY%CL|* zaIs${yrq{M))7WX(q1yOv7rzwd2HU#Q(p>HHk`q3!BJa5iq~big_p{xCPe{hVaGue zBFY-!4dZPsVH}>GF$Ctkww5X=aYjLrt(NDE1ehLreEpJ>x0`WK9-LH2*GQ9!UG{+2 zDQ@{DtLeKFRp<xJH&q0Ute#gLD0acZ=tYy=(3G9KnW(na<x4q}o#vfGa>Hs!a!%SL zaI;OO6D>o%Fc!0cw_8=_He9ntSx@O=uxRQ;q{p4Pbjh+K1-emZjZ)Kf(`SOk<Z?7i zx&#QZW^v{y6p+3iJ=?ZG20A3fD^e!ipo)#fF>+*}!0nwrQ3PC-Bs^*xsP*eq6_GXA z3)&%A*b|t8Nw8|kx`4%5Qh^O5D8o@)iq8^@3Y(c8kJ!*yn~%7o7!+;BiV=79$cRD9 zt(<GOOdUIP?YBKMZQLEc+sf7iNTZpM-$)yNbClhvnlsy4ofYqLuL>wIkdKdD5gQyG z&Ql!mw<*cx<u*Q{(Z>P^JH=O19q)X4_|9@FqLiExT*G#?^Jkq9(n!{#G!a7<EMsv1 z<@pi66t*DY{OZ|7;k`l2=VI1anrlt$X&g#dQ}<*09npI|oOfw7rW(kUe!4|LpLN<5 z8*n&7reenyEcxk4`Ch=jmz1mMAj-lx?~RQ3@aW5OeLmi+jJOcLO96@9i^gS!?v3L) zkPWj%^(0n~q(d^yv5^F#ibLxJ2W=OhIM!2Hy7K=3?WtsAST$okyI(^awOl%EMouKa zVJzDzu2NW5s<|-AIN7?XubikcMVn<rH(NPF<?5=K*$}R~L4+a9HJL|RMIR7OM)C&U z#Z3_IWIHry(_#*UY(W^x=Fw=)qb<p(w)x9;C?bpXP(`+VI<^^pFH<AZS!5K@Wpaq< z@~q(i?B|XYp()xyH{bk4Ya8so{Bo$^;k`O<w&2tLpu%>Ca&nqAW5_FdEFUMdtCiTC zxsYrjRhk_0asL3b!aRfWtxq2=L{k3%)HHmiUE}AFWv{uwGz)s}<mzaVxl}riLJCaf zb{eMO_wf0Bt0@~FXku<atc2x){hZ!#RHBM5_`q-u*nt?(FxjWk^~1IK_WXc6ssWGX z>hGO74Cfch7*z4F49wY+$<I1B8uAZk3ycprKbG8;JkO`>D+F?q18ycVkTNsU5$Tz% zMly_6636I%(~U*cf!WjR!HiAYO~hnTX}p}oK#MjiCfn_p*)t2rp0i6SC4||hyOcF= zvlWxmEnK!+X6T*E(V>~cEBOqD$^<kDn@C`BbMIs$hK5j^=LH-Xi;8%<O+~Eqp6=c_ zd@Z^PEK@HxaJFAzY-ej4&bng&NRy$;9Hx=ci5^f6$qf&0nZS5R_L-vZZ<R)_LGqpI z-cytf-Vd2$Qf*=67_LW2E{KqWcNXG~)~-!4tdNUbD`@r+BObK22qO9s%@`jq#7|Dr zc;CV1@)t?ir`q`Vwi|M|2pL0s{Ln<2ApoE>u3*Hb%zJ~b;?U^nn51q#EdsLH3?Nhp zTeVE6`g1yJsKRE78z@%<-N(;0bkwYNIoj5DLx-jV%6aCm+|bx1IL4l>1kTSbH9kr_ zDm@;L0*;L|rinj%<)VqJBrEi<&L4DGvV}^xjJAotCeiBptFSG{eNY0uoTw^oPt5F1 zt+24^s=+?mbWFOolF9JU9HBtpULeCM3{mU+jmyzw5O#)LvsqR<pk@8BGjAKOFO#=n zCPmR7F^xwo!jqNRKS5mz2^%d8GE~0J-J`N<92m&^6ctN8^6XG~@59uw?$TFQeeBzM zxsX2TDRd*CX_-=8dDC=k`;!Mox(c<)>g^%LWQHMAn<cq9ppAJMN<z1miJ})TaJ#HZ zKsF>+I|{@4UOhOP$68L0KN*De=Z-G1zwSy}>WbE;IUT=37K!ywI(1!;RKyO!b3L^5 zl|$=$j?A$o$h(b+Fp*h-VJ~4v3=th3eJoham{TGk7o#|1ra6XJS3>Oejar<wAq*@y za|q1JCt&5&b^PLQT%ePekOQ(|%%n(5YspAbu_sRxlYk^YaWVlyjHcvkci!#sXVsNf zVN6S!flN$DY++Qffc4#@4xGHL?&7GSyLyVsR2g>z;xiwp$x*2)>FUvPMIzI7A!LNt zgi7@eXwhk$nwCH!boD?Ftf{GQRl4c>it2>jb-!xVnF|UG{tPU9&cZ9zMr~NEQl^u1 zDai72Cc!0h_?@#daSjrltrUz*3e}+{&|9V(HU9u*4(Bq$UjUu3lu{y2G?P~rm33}` zA@HAwg?qD!O=l~Z1W2x=!@k3zugRig2xX}?S^c!2$B$rq<Ab`Q2h;J+O(rF=TdqR2 zR@fANB{_sl!k2M!!(r3d2ij~1yp*kSOksH3?l}8-D;aB;qcj~X@yX=Iv~c@JE(b@* zC?2Xc3y{sL>kVggQ3GrxRg~0J?k+)x?Iu7s`3424pOmhIz!CTxy>8KWEH+|knoa_j z6h-TOx_|TsCjS7tpZ@^m7N!S5AN9G|@BVa&{{WVksRhcf=7PML$I3#jDD^_1&~OKm z*<7Oiuer=R_2$wMOeVlxO>CP6w*+~yknfakP5{)=BC?Q}DTL#Ng|ID_q#KtaQ(9BZ zSc_Ia(wzBSR_?ks17+H?c&~r*bb1>m=F<H%CRr$tNF=e&h;9;k&DiKJl1XI_o7n{A zHe%wZPuB^zD-U)=Bgm-f_e6GHm6depK*J<r1B#J9B#;b=#UinY*iw=iT)tZ-GUcGa zQJAc7VKb&*xmzmXn-v?5YCx-oBi%Zic*N=it?jFi${=5F#c8$An{QhpKl*EGmmd>< z*ch?$?*cL(C-L|%+kM}Z{?GSSc#r<a_r<+?Hs}6>;{O2mC1?If8cy}0{{R4YK#0Fu zjr#up>ZWo30PI#8oILXijn+;2*P0L6eCrpuE$XVf-XkZ|s5zbeQ!0%{ENJ|`X;BgA z*sZc=kpNOoh=8*FA=9fKI~g=awPMK2=C%SAly*$d_17oX-EVo@6FT<z=SB=_`i8iL z$!yd89Yeyjwy(-#kYTZDp;(|>X2^k9cC=FP==cfb23&ySB}cqMcGk(0zHF1DC}eUt z<cY}sikVYW`Eo3Dgas8NbtHtH8zvPl2_|g7lt|n*Mm5usM1V>_lV>0pUtBoGj5bZH z;mpcz;j2AV7dP1MWfzbpQqb+e(xOHhIV_VMXCGqiq>+}yB7+*}`O3?al^t#GQKV#6 zr3hsvCkbz^0e~z`p4@pYIj?2oVwTt3!hkC&5qxG&$fY2L*ZEXvCo5cd>h?5>=C(kc z!t&&6bvI<U9=B>S-R+$~Ky9{Dmd?Vd@())5-lqP(EXjt9up23C0wM~o<+0?ND<hcH z^Tv;Fj7n`+pZUSfk2pNeP_h_@z)L7HMC=hZB}YjOHFB~)W&<V)@z|1M6~kp6IywM@ z_WO!eio=~JsllX^l~!L=!0F}pud4W<!!Lp<hR?JemVsgc71d30<(hjBM}3HsPdciL z^wCYDW{%d^E0J{hyWy$ql$r@ZxgErYJ+pmFYX_fBm3yX}V@EO;?2Nf;tDQ7oe~Cfp z3m6$~l2skmNLHI?R_kYN6NGi&B3<_U0ecz>C=pQ`$k@cjwkI%-0Y5dG5@o4f<1mqj z$&Ym}JivQ~ixgrn=d97;h}d8D*$l!cDC0c>v>T_GWXH%zbK|(3lGD^tw5E+1@`B?I zU4+yN#8<eF2a%2L863k51y+hXgj*!bb4zZ5I&j$Py`6_oRlMCo;X~Z5#NAWZS6toI zP*{SpT?QYGI?6QI5rq;psza1z1gJrkTQbrJ%{t&S;1QbDpJm(C!+S=q3C-4EO%_W- zF}QS+N12EX)zpHh4v{t_c`<QP<WL>Dj2Rqvqr4*RoArm~hOX5^Qv+hfZdc`LJF2#K z3$dCtTMr?!##?K%jkRI2%aMz}bb~@{h-kwq7jKkOZtW2&ra(bL?GbqS0app0*|eO^ zIV=uQF0Cg()NsdgAjlGq8*8rHYMB7!v`2Q!EWzFr`eNY;B&z}q{$nys+&A4sc91sr zVbAY{VY2%YJq=pfuFH)g9?*^oN+eXn7VBu`$f-aOx*!0OYnIWuR$pdm9BLIs3!*uK zZOgh(8aoZ3zXj>p4lX!KDGFm!U(v0GIhJC!DctxXpA3`b)8utNL>Qz^ib|Vswf*3T zXR%yH=WRYC8=GA!12-Qfy4+l1OXJt>2Ht12^chwynPTQ}g?6>GmYy}vJ$T3~CPjQ> zt)&EsEMTmFU=c>r+vAI(?Oq}2z#RJaXm@J9z}SQ8noE+~jC&n^o{mVq1e@l|w)qJZ zQ59Og5|Wy?aC32l2MlMKOXO81K5aXVQ<Pvjx<^>kcRjgneI<QdN@ul9Hd#4|q^=*J zvDm?KA~w)@U`-_i#>QW^%TpqxlLqFSxp0<FBKRb9<8%eKspn0dAT~t-x*+6$7h6OX zRlm(DnvR>NtF69|8gArpvhFgwcPa0HNv5J7BV~6@{Oo5+%DV%bkuLKt2ZgMr5>U+4 z+g;l(LF;Tc%a-}~<2&uLE!e-+M6<rT>M0GekClZp>LlImh8dUdR@ZMer6dKoi$|DT z-}-3Yh}Rh&1r2QB%u~f^p3&X5O*hVfHx4wiiolWvs%I;neeUV*pA_E<j+-f&7<krM zoo!@IzO$U*S=wOOhU;ELr?IS!GH;S<w-m4jOxgg*Jeek}6(G#%Mpr7uSnO`E<GSfN z9H(T9%!*|OZ^@2r^(GDzQ!20aXxb0fLkvQWM`bp4@m<F1`8LVCCyYK=P^6@tF;REd zLk3b^39P9q#xT1w4}`Y6<!8g5B%4=%DYJB24{*urW#1*f*khAGf}-z64oYmZQN)7% zR-F)pM{Q2}q#^Tn2(KE8*N*4H!am!5nZJ{5B_uabaz5>}%E)RwVXR}`juqZIhO6$n zI(;Ix<A=pShX}=>_Dz#RMyX>MO+7u?$H9;1{tj{O&;Hzd{{ZRrqv{KNOSW;SUdmW` zR(YAh{YPVWl8$7$x~k&Ll@=9cU1WJsK=OE^p-N(@ffbKrIDs2R<zv&IX4(EZn`FBm zu^Bt|A7=JSR9qsCmk6$@TillD6?K+3nI=(nWfsQ7=aFMRKw06F8da){w>O8KVL9$) zJZCeDI+B{Use2Np5ePz9)pnxgq8>ApRuUBQqDVSw<<4Fj8MyD3x>zcjrJg(yqrs{l z4#-h02_*2Ics9F&NQ(&u#R0ImvGc8C!xC;0j>v)*^tMK|(W_0{4AIWbwnyfq#a$ch zu2%YGv#wLzy!lwAE2+ma*)C)am^F3^G-gmJrs*ZB!i>g-yDB)EOJN09M?_R_vLrIs z8o6{G$sxE?<ULy(0YHTwnd9fA2(6b76rv?<)n9z=vWsDiIJ*RuTYa|MbzCTmWcP5k z`)766%8PHD@4kI2HrFw#-K-xT%fn9Gep=-q#`2m-C7hIU<`g45Yg&QIl_pFtQ57Y| zmlbA6P&{HJa*2jfwdd)NeRoz&t>M7;6Cj71<rsd^+-G<W=E<a_hm}XGf<i{H$1((o z5s>X8!?%%1X;gDWYosdJ3e_j5<2+9_FU<Wz+mk8*`^XF?o1lL&f!c<rhwVsAoXe1m zR7A6FgGa+T+FI0^IQa)j3m*0$)g4JJj)zSMY4r(a%HC%wu{~SFh*VVssWUb-RE%Cs z4V#fAnt~+$H1RE+2p~Y1)X>*g!qp+82My79%VJtFP3p)nQOfAXKOTo6aDFMJW)oxa zsBCa`L0m3YQ7bSmIs|fh!UQg=#7&rT$ZI5%MI~2NXHJsQG*VSv_tiZ&+g&#Q0P{J* zl+FkU4K^owN*Uy{PqR~^Q#uhM3~_{*{Z#bJpm2wQNj%$aH7^h|Fi{q5+&<8AofI62 z7^9xtZvN%(_8B*BFgqE)*dAeSxQ$jLMPo9T)+LyWGG<q4YHM;i^M?*3c}10RTNR;T zM;(#gPp-Bz%F12Bad%6oJ>Rjm%CfpDpHV)<_`W*yhaL+>4i#lB9X)Um5fSBhK~G!< zJkB(uAxiVT!H)pDjy@eVW&D2O%l2qzB}y^4tHF$1EvLnm93V3;4ldVCwZ=1)zT)@$ z-u<;x;oDs`{ZqCxi$XJrBe?Eju8=-d8=%`4Oy<Zr4DVK}?UD%(7?PRUY;Ui^n|-v` z;P>jXxZ4@SAJkrEx<jB+Cl;>*fakaYTq4~@Q3o5Ju-0je{KZgrW<Fps%N0~}gq2K$ zE<Fn*k}cC`mx{MshOe?*TfXX3Y?M=Nx8HemkA3&wZ0)}L?D;LW+ikYabGF-OInLW> zInHyO=Q+-E>Uv7Ub6VZMHb=PFUKNGpQ!VSo3ab&f$ZZP_DdWv7(AzqF<-H>erWjfP z)0RjCF}YhUTK@nOXD33vTy8e;^$rcUo4Z+N;^7sWdyv@`*+wU~l+KlDQ)7%ntD6?a zgAB*=sZJbevprF+=BZ|s{#jAVc6r=5%k*WuMvIB_zOu(dDk%GcWK@X<#z!`i5q~Hn zCd0XM=<oFs91ke#RfLavrbG=@n>WpeXjLu9EA8hlZI*PT&oMas%A&5BwMnbO^Bb<% zfmBfuqm?MYd&domPR|7Vkbu_jRWP(_Dv_y6(SzS)Kw>X-Y{|=)&D=kD^)yz-msNp* zlLt;#bDLgrv6-YUCc9{i0y8<B$aexZS0D;ja&;KY0$5!blo^bQPN3jq%I+&b!wL{& z`tpB|OUI?g%#TIo6}@>Dh!~7S7L{8zR93Bwm7dMjD~N4+1f-q&BuGimF^@@&?TvLv z1aJgwskwRB;OsGQ_H@=&Rn)R$D(m6bwtbZQS;-DCqx#EB2@X8#30@{OPcm6oyz)w~ zDL865>ejUro_ksIr<yCLOOY+nYbxMHSq34!JQ$EbII#iV=OCkie@KGP(X*E-H5JZP zCY;ki*AdQp@*y6pE^2d1cFV1lh)`lKp1S4gs>Pk2hjz~~P9uk<wH*54gGl4^MQFGT z@V4?}aCqnkDWF<87bL5K;X;rVwLDr)(T#?OnUq-`f2n0MCoyPHh4p4WQ93!WY)GUe zHerpBBJ_|T@vx?3db#_mk<igd;Fo$d9lNHP!(18AacZvZu_oj|S3qhLQz$vX)-0@K zNcrm$6(1^kQC~#kB-X*XJf=Fxa!JUVFk!nW`4f>52cHisGKsM=;f_se-;JBPk1CoE zvsCDDCweBbN}&2`%TmtWC%&$>TkDvrd2N}w%Krc_M-7{)qhy*VqXgUC*2t`CDl2N~ zWGqW;n%*reX^Gs|LllKnkt9S!Uc(}|A!E~m4W}W5=9ElwPH%_y&EZ>*xVffvxwQ?* zw)bPU^B~;&ylLn%hbEm$!M>uFY*H#Dn&&l^R&szud|76zhg~>EgFZl?;WyHZQ#_?- zM8#t=7cuk}X|aP6SiA<a5{TB@@AP8|7bpxXhUsM$Su#sfVVl2jhto&0TUFZbrg^lh zq@7bs-HA&0w?M4WUq`TaHc19o6LV?FS%7aJZ&JLMAviO;(a+n=5the<7p<E{^nQUk zxcOLu@rDh(3FCtOx9CT=6eP`f)uQqF%(gFIlCh$JZEG?&Sg^r+DoI|zAHQyLP$D25 zvFH1_(KhPI5{1phLJ^c6hR8#Y)a-5#=~~8vh4c)qnBnz}ifyn+Ys4o|qUTIGU9q=& zxOWQ!A}KG5ut_jZwMFF69BmUj?~F%sYgR?~8TwXj4hsq(#A<=rpS7+$`x2b;rIk?? z<|pw`Bl0_!DC3AsPJR2G+~xCUKM}60vW$jxjc()2!K!?Z4NfJ7LaV5u$E(=xBUVG= z0cXx^F*TuV%UQEz6SaF(AncCEeyZwM5}A<59O5R7OxffYRz6Tk#0?81zMCzb2f0lY z{$RHoqS<Yd*;kG?T}+{(jT!3Yw(H@05vx@frrfQB^jQgMhRHeKZM4gDUJYuajd8ZV z{OhWUv1h*fV_fZwx6?ZR08HaP170{fiW5pk`b2pcKF_1^*nQ2U1q%i=;@^zca#M^& zMC}uGzOOevIvQ}f2)6AMUB2X$1u%uo9|uAQDitPQLh3rxsn*R(dh3bBVIpJ#o|1x! zi^=2i9o*{S0GpOJUr<sRE3i)8?BRx5fRefzXlTUR@34F({{SY8rp2_vq})7zAjUu_ z6p?{7_EFYZ%J9lqlA{mOHbaVMj$%q1UNt+01QdrVwT=*8^-lPO*lvGEJHfNN<7Z)( zZjIHhFCPfF6%AB4wp1g?s4nI$`RaiJwmi&ilv2wcV`~{U>u*jXZ!(v5#U-hO^-0 zSahtiD}PgRL^~I%DZ3+(LPvT6u}(!-3~M2l9j|3}Sm)DWNO9tn9a}F4&&xly-d0a5 zth^~0faH}Q8=1}{`CEEh3$ME)$A?#RRm(|S(U=Z-d`;|nG1Z*u)Yc=pJVIbfXJRcZ ziq`iXmtslK+&JPnEjKD9>@2x=!$CZjEM`V2kpOpS__pdwo(Ue97%vDi<ylll2{ngA ztf;Jxb571@p<Et>M6KAX5_uyBGbCm*M9);+>bqF<k|`#I%$-K&LX?m0*IWKSdfv0T zE8csUgiXz>VYQDqjKv~z7>$X$m8D0X$7ACXJ6|7@#oU@AL66JWQ1j1TjBw>4CQ=%G zu^|j!H2Wt%wyKqW>-f=3=^NjV;<1h^m{eUErL$o2Y&cv$Xo)(iWe;O9c9&OQ-4pku zkCJ%014gqQZixcrn(6LA!?8pcYn&vje0tcf{;J`*P+5I{T;7v+0D6C^;2jw_lFce* zgRetIYxsTq!ZQaXEF7{xt&KEPk4sAi%SgqxWfw<C5EAj%<kOcv85dxBU&ItPoCz>t z9_U47wgnAfLaQ#J3n8paLm{<%f>D>C%o~8sMoXus?l?RG#SCJ*m=n^sujVfZ>KaR2 zz$`dPGLkslc((jrzKitFHS@JYY{%}B9Wc(K#d|So4o_diNSnE)D?;JTQr2kAq^+Pg zPqr5AV=`#0RI?`JmPnLYii1?$&U9)}Tm8S!(Z1TFE-DP2iO@NN)O_n!Ok?pnxS*4* z!cyF!RP$`a;CvY^jJ_a!2$`uoVXm!|WIsjOG?G4QqH1WoH>?qITcJtIm_+TM(cP)H z;1w%p*Be*+xI3kY#DWbNHg6!6uv10A<(u3kvAv$^??VmrZnH7T5qYkq3p>gayA0K6 z4n=?StfETJB^S7{6l+_YF(8hFOscrn8tzLjDiBlr8F;u>a!2fmoR8`*K;e{LLf%mW z6Sm1ZYC#W>I*Q6Ds{|a4mZ)y*IR`?JeBW0sQF`BH5zg7pxK*QsTxtCO04b@a-{<L& z+_^dRlP$5Tj7U>yro#wFY?e`4Vkuf8oyi!70)@dcJ~{}f^>Po+k5-k9ZKZTUOVTD2 zCvLa5ar%j$i*8;olGs^H+u~strLKxN5@kfI0WP6dTC&JiHSUjW`Or!R3DZ7U_{@=C zAcf10ot>yUg20x%t!;T!B7I1gtH~R#AdY3Ph3_B;<5uKHw{rXta*7Q!+*ZU!s(g0q zjmzW`dd=p|*3wXK-+OHf%{#9@bocA*@qhMR{KGV|SefL<_R0R;nUH=diPl44Zfzg_ zOnxuRvg`04_hI(`0LXvb
Tq2=M{#H!Mq{{UmLu>;B9LkYv&E-5o?WkX9U3HTQc zGq=T|7N!tba>#rA`npea{r>!W{e7F?(|2xWtlM+Vmb0qmhQ#McXsEoY79Xs#KLy#@ zjC^0}sN!KNjz@F8eg6RBh8Va0t7ACP(Oz!F6+LY@Fc`)aY&h`PVp>FN%Glyyn)kJ{ zRjqTH&RmW5MPF}iI-9Sx-w$2b+<e<|Ejqlot(}_W*EuYj_?Q+zXwXe@Jk!e-Ig5=U zN)V9mVBS>kR(7ks(^)7)l*ID$luG{q1+pS>LA51w0gt`0q0S-&jPDe0q9k4}$48~c zG*!tJpEztenZld38<x5*>B9Ofw)o%^8gmwhSkzZU*o|%ya%-ID0Ol;BE+*}CIbGIM zD9ecHkc^CmAc)fOyI}bw3NYRB>70*-5W6<RjXyXWGVa{8*a=wc&Ste+hi)Jd<%p}1 zdbLb6nab@W<aSfy_hG4LEtf%(pV3tk-x&9My=oP=9hd7{hogzuGA+5<MgyFU^c8(y zOyZL11g_K@TJlt{qETQG<alNwk?_(A+P!X9X)Lx{9phxC@dcxCiLO*Q+%LNatjuO^ zEw)vXW9dp6*xFYj4qRyh^M-8~jg9fhDZ7at5sIqjqZ6@FT%5HPDb+@C({4M_j@)bx z$?pp8ZH_6uOPCe%vHQAd=~HEmZi>v5M4L|nzrhmIB(8!ni0_d0$P@feYfScNe5E>y z77Z?-iK~~aM?IA36+qU_+bt=9nqAt@7%bJhrF7huiMoD3qgD=g(<})qyL@br=g#w- zuMOEejXbPENkq(So??MpWG$gMh5;OEP#BbndfmLOo0Jt?b94wu8P>3nT5MtKNdExO zLsP)g+4_g0uCX+?1vi#eQrrGza}uS4!>mZ{eP5gj2zy`}KVrWcR!-$-%!W!M4x(^q z7*TAC%w?%8c3*{LG3Ir(ab-HvUX)LCEk5Zkf0|m=CHqa7m71VsGDvNyFRpaSeIm-j zX9?EQLeex@ps1aPr#5sxIMDl-F%Ztmk_I<iZuH|79BnOe+`ACS?Q(n~G;5ms_qI*$ zH6-ndS59iZ&#<nLN3o3|UP6$J?r|07DAF{hI0+dGxBJV}zfpTHfow-qcUPNhm+dT4 zQf)r?QdOGv2=QXJC?jF{ojfS=B@z@MM1u+(g$SXxJ$xB%x}rF(Uw4X-++165R`&dc z!glRDy4sU|LmiBOsfwH}1bd|3LS@)!{H1ato4M9lJ;3(OkZ4qLe;ek^i>ZxUx>+d4 zLh|vcyp4pOT^=nLuLe47LqW16vY9!GiSC=m%+X}KW{y#hIc%aIT18a1P19u+WF6y| z3cGwJWvAA#H%$jD$}?+|aA$NIixS2V>2gHfxNwV1k7149CN=ZaT)5G?$h9Q4o2`wJ zYOAGpLq+k7RqKw5H4=eUb-J|jHbhEWD~QRak6pDlD;*Kic7l!LOC&p8!>=Kb*Rn`3 zmySjKv8=7COB$I(KqN@>4-xWB)XM;Bs=P7Shp9!6Chp$J3g}`Ya6&^8!GLEQv$>2Y zBTjJDRqR0#7*VOJwo9OHpRMb2{QIeq^%?SK4(69@_TvaxBFO9^xrB!cB%Iu<E3E~0 zsYV`6eYMsw8H^eNL#9Mo74oB(Y}$<EW<*uMR@M4ZN9vuGIBu@4QPlpem1M+TyCuHZ z!@*765zwBS;Z4(aK_*%HcTC=;v_`FGr0bc)I$xa~xJE2nb<`h~6w_q{lhH;;S~9|$ zYLj)|j&$uE6wbdZ>Q+rv(_2k<(_$So@!mci$*}H`7k5WzW+fIfHT0SY1}QmU_6}`u zMdWI+lF4QP;{(W=ZaI+0Dj^7GF^VdQ-7u8hLStW#%#$<Xb{^J?Sg6~?fqs&Y^X+xi z6DmhFe&gW7DjPsVUUwcqCFJgZw$ckNg)?DScLb6g?y8Q&S%5rl9v04#TCtsA2Hbpq z4XUEWLyDt4Tt7)BJja#2kDB@HD<_rcj&h6CA<Q;0q;iHjuqgK<IapV`JxS+Vv%j<V z{KalRlQScwyv5@|B1#S@98}N?i9w1|ge;i)f0e<JCR5`9wsvVUz>$Qq+$OcQkQqF+ zTGOGq;PW>#*go43jy!1PG|`dA-{nM|kJU%YH*T8jwpfc-f?s56%C#bVW91Vji$*@S zDA$}W=d0MM7L!Ej;>1v0Wi{T%uIHnUvPC>-!z1-VH9d$m%VzGGI@=066}#<TsQDG% zZjvqAw`t}TZLPyW>e)O(e;Vj2g5MZa!b~HqCqP&WF&%QzjF?bt&*HI(8$tsL5Zqhx z&Ek3sEbM!S2s1V%xO48e{W_*NE!mLM3jW`MNTY9e7bFCJ4*3UR%c8o?9gTW|EAIJ= z#x5J>yT--`iguFu!Wy?zbk@RAyDHkC3}L0qwx*AFs4EnV#_Z&@W4^3{X+)Ij)0k1D z%Rr7qf)xfR=^MDEaL?j$M~h=_&3bO?%E_Ck&Z8!Df4ujQ;16|ii)wOQ?dDB+TU!#e zc}6yAH<;WJK71GhjAWCM{Ke@OD`!(A_8R8*S+jdDwtR&%+65sU5`<R8kzu5mj6NoG zByS8E64mzW=tfZ_k`^LC(wJ=DA;XzR1Y5OD72C2GvDfOn)9^#16fE*KAuZ7s2A-FP z9GaWqMRjI25=o<foUSxa=P#6z*Jan+O?O>v?zZ^&_uD?BMT6JUU6{5?yR77bl`zwH zY~>bP6v7TojyG`CVhoyS`*H74MZ<S`>P^A@2ee#zy1QogPpCl$mq|fcuPVr;M>j!2 z$0@1P*Za0dR_JWL(Sy2YDIu<Ns(So7YyI43IQRSW{(h78n7rI_9wZnzRUY1AA;}}M zyBVo?l<u&UpmD6MlubuSkU&CgW*SNa!x&n|$7^2V5>Irp{+#jn9YA6GZMykB{cfzS zpT4=w_eRo+O+Gf<eyTL6aPf>#Qw&c@7&EU2Wi(Jva0${RAtYWE&|<)Z90|WZb5RW* zzARZ0gIX{YgU4>(qBWMNqlDTp(ZY%(#h#w+eiTr`NNJ2?KMpaE<M1{*LHVJ9FvO#$ zq?{m<OaTx3>7`Rsd}Dv164}CAy?KPSS9DnA!)?~xJZrkBC%4YjtHSsmzm(U!v2DM; zg+i)p!L+I~G@ngib6pmy?5dU@U(78SZt(i$y`LnTG}b+8Rg2cru&vn&n3A6jA2CL& zLOnbo6W1jC{{U(6XK8eeO&5!}y;;zcYnr8)90oh=?;OYKn-GLdoq#!;mqgYG+0%&I zQoAr+(G(JBK|rqF;l^2*(q!0{Yzld1r>+#);EGbhu0skCq{#Pr4NUf+hva&>>gRSN z-l~fBEBo8e-VIfWWP6E@)NTe<Cl14`?;yj;GQd>I$RttJkc=Fe?5c?Lmp8yPM)pTT z5KL7&BTDf4V#mtvpM`*%#>!6Wo}-yW1wW1vI3WsIQ7cH2Me|p3KwnPUaFXKMDAQLW zhm}S`<;%Qd1lArecNiYZZ*pi7@v5-_#{wIUy4F`Aa+vuTmthI$#doQw(RJ89*Hu#0 zRDIiHZFW^G=Nn-)l*YN+K86<^nozxZ0Dm=FZp~X6V~W^nI}6>^&m`uitC9ZzVNc@s zy!yG!bmUzhhdB7li+0=krJUzo6VdXMqRtu*LD-~3#=hJ4_wAet-LRj$INhMXtW)B~ z68h&U?u&nazvEL};~&%1a?RbknYB7o%)!M7ZI}sYU|B<Z`@l0X8QMvx-q#`3RetHi zc>Aw6S<>S=1?g{cpSd{iRa0_Vq{l5W#jLi%GFXv(Hj=8P5=x#XG~=m6>Y=ra{{RA^ zh_2;Py2EhQv_qO!D)M_wbaUn3Qr$mNB-SHMDsc?wp{OgCmO#3$O-kZQC!~2xNdqgk z(W=`zNOOkiE2iotwq7cqs_A&Wa7Uc)<~P+b0W)`lwWGEY^s_PrABy}~q&{#R+)?#} z9}SLuxj>Ji3$r*#D#XwrGEVd;@(3Ois_k>xTASWCw>DZ>Je(&sLV~lnzpT~?ir4oR zWm!w&_x+z0cl){euYbe%_xkU<;r{Qa{{TLh*}Yd8Hvz5b;z=}&uyJ8cO`9kaJAjQu z^Nop;YKw&$V?`O^>RDfQ4xJZt(N{xR3vq{P?S~SBC)~+)@S@t_(O}k|M-yf;+A_K* zU&_4fXPoXTjaRv$Xw~KR5<Q&vwioW!#dI}~ZRSmRxBXV$WqG|-N*5Z&&$qX29zkav zp%iMf$@x`apf+n*q9vK7GCTxxrI0dOFHB-z(0#|uUAbCctn9gLnwFCm>fXKTSa49# z{b#IY<NDY&cZn@`v5gOa+BYSMlBMC}<0Z*3bO6&yoP?p5p;U?v8zmpS*Cq#VQimyt zBb+2=JRFQ%gLIVBFZYc-`K`ns8>;&5lDmjmZCGP%G;)I{Oa-d>JrgL+CEhMS@u6N_ zwV+wuzkI)@Tw51Gj(?)q3aSWNO(ixoS~UrgO^Mk=8BL+?>k7^xwY^FWe<zLvw<kr` zu-&+c)e=NuGE60ujCh~3Lgu@CKG%6y^o^x($>~}OwrLq}D<3PFM+^spJVL>-1IsWP z1P)0*kSA9~7Z4K9$zyCz5u6ExR$q_K<Z7(%5&dCG*nyMiEg;GTojm>=sTRgBcZo`j zMJI%<d&Wg#Il^*`?HODI8`xfxdWl|~cR0BfogeDl4=JIw!M7h0?-<E_hF>T>dm%bQ z*%h{MjTSW6gOcEeXjw9#vfv8LlR=|U9T|1<1lG9ConOi(v5F40pFt{PHTYKs#S+?5 zPTQ5o*htAdeA8AUaXYt8J|N>nkT%*p(IE_Di@Dtr$vG~%=aWovKk3)E36|C#wkG#t zU>2$+sx$lgb-I!5AXz%yb%)_aOk)i-k>lbYt9|hIcG}|`BZ&PL>1!}7d1Dr(D=m8- z4)}0$HYI*JQeYbqG&I==*z%2>Z-GLLNEyZCWSKU5Ct$HQVB{|b2TcGZ5JAU7tRM^M z+dpQrl2ypf%xKkEIc?nNITlNibnk37-NFhsWXY?yF5Wg>!xWHc<<72@YL3hLL9TDQ z6zGvHw&1rC2g7}R9hx>Ij^CwBf)pEX8kJMO#`i~X)p+m?9F1(TA4?qxZb2WA?f(E; z(Dvq@TZnJcd#QuCxdk$nL{`?mY}~JJ*)_H8BF0IP!)_U9-sW0MaETy}1kcDY>F^gu zX^0J>C9~$-k4^Hii09!6=>Y-yilwUg{nW2XlUW<Wg<6<_Q~+fg4^l1{Mlxw>W-p5| z4;5zOPX#TAh4llfqH_8DqoH);h8AX(aN|aM3j&Ot;*MUo3Pl$iH-7c%&C+m9pyB9Y zzM8vu(1WB|ZnCfBldf>uJjzQMr!7*V3KBR7T#8B?5s0A!k@Nt&EHHe59nZFY_(1s} zQU%88sxR0eW<9H<Tj+VCgxMR4vFJJUQm?jc5@Fdutc~OfLL#xpB{IZjVZ;*}X~{9J z8+|VC(r`^yX_8I(r;ifV!b!SrJvK<Kwx+h++=|+~(rDsg)Dfhi><2L5v$L}kd265r zsxdw*9m+Y<7A!Zl$kGhtYh4(P=H%`7LmM%-`Gs{Z>EvBXZsp}Gt1$U^-A$ekg5b7B z@fDd>f&FygUdRt)hAMVnWHE>*nk34ohA=K78Ovk2IV!^ib{ZdS%J!W1mqJ4<yLpLv z#ZlmSxC7b2`##fOVhrV_Us?~EPo}sX0BIT=#|2<e^9AIaf|SWaMuzTICunh{FM05{ zN>x{Di>Ti*tIqN11O<A|Q3O=Dx`g35fmtgl3CAu+q}}W00)e&_vRNmt#&SpE`2(D5 zv`4i(IgE;nlf~-$h@G)|Qg(zkljyqD&3Mka0S&XIFCN5*Fsp2%R#|pd)LtKN2QN{{ zWYQ?zJneIt2QP<5rZtfhGibJ-(f%)LTHY<O=m$|Yn2)b-*snKqEQWPaO>20KS2ml8 zmX(W6VyniA+tbTlmwts)cPhE|wY)mx9@4SbcXS#=rtt9u9kl0!=kLeA_0@PU3aY4_ zCo95z_)dM3pU)a|FTXE!UEtP6;YtQm5Iuj{kP9cTP6@hM5Y3>xY0HyR&~%W~w9y7! z_Qt`QnUL5|oyoQ6N0F&c@sY88hSs4E*Hc|`>++97KAdvJzt0qXsaITFutJ;K4<WO< z3JrI|UWlZMyOhOsF$Iru)fP>8I@0X`5+HY3)+37t7EBgkd0gXjK&8)L`0eAU088o> z1cc7w^4=@Cp|!P#J6?9uP=)0iAtaDiljDd)-NnVVfyo$8BF$t~<1vNZh(;SGFC3U) z(a<8~#A6ky<D;J>eWSzFWfrB260G{CUUM9gt3bqlXEzSw_p`T$sBFTqSj-+auHsq} zV&%9IL7O7Uqa=m6Gaw+FsWEKp8qll{B3z#;-oCEm9KmJRT;d{oG_&Vb$gY$NAhTsM z$rv3##K%SMiFY@f7Y2aVEZMMU8jlvJtSNc%Po>D%HcY(vXmpyp@?X8T!Pl=tvbYFy zH$%t76%_TX>Lw?zD%GErCeS2c3^nXJOz(xZYY$)@pmPgL1)Pf54rUIF3*0G)3P4^V zB!BF_THz^-2BGK}eOYhRbz57!-8X2#N7-O(NvxJDh}g-@CTSLt$e{qlgRoo*cOZ?< zS-ckd6yeaQ%z`cqKCjLN*Gnnm-=73|Bb3sbj-G2l*EQvla1#jPQX%DwB8O3&r6}o% zG*9!Cq2nX%rIV(R60v0E?Q7<M!j(Rm#;|P$vC=z(S>;pgs-N-JyFBs-#50cLJJ-Z{ zdi-asy2qN`vReJ0TUL6by|*m15VD)N2Pa>LmB_lhRvk!zIDo&6oR*Zs@MTf8#9#pd za(z)>BOJ&lp>9d6Z=CF0(j6IHNg)??Qzz(1$;s3A=WL+&Ao&$xamM+&3M#wSBWA#A z8ANb2j-RxXahO5CQt}emwDITw(wLtS@dU=v<jJe39mQW${Vp;=6Ej!9EO^mbL}Jv6 z&Qz}we-^Q4wej?sKxF7Vib@D0BZo}nF~bif!x-#jJ8&B79JzyxIc8(!9UfY`z}n7g zIe$kFqT(#;88mh|BW6Nbct`7q+tadHY+hoA;~@bPBuwHg0V^Opvj$<u6^*D(X()_v zpR#|i{S*AOcRT+8d4J7y`P0h1R(^dy3ooFGzvhW$WeKVP)6r{9jB3S#gsasO`n{6| zy-QUSCdKR)=2#mkHYq5m%)w>Yp3O&utzfL1RtZ(xv=7R6F{5}|cRh{G7HKCkO0r|m zwY);K=}66W7_KN2+^SoRBarfn&H0Aylh3B`dP(s1!z_nVDB>q2;Tp+hP{TUDEHUd# z#QdX2y%*5eUF8ZhWW{M{q&q;Bn2A!bM5Qx}I#|jk8RV8q&^dz5VsSA40F%iV7z073 z4oO(W1#Vr41<z-BPp^;8HB$NLs@?c&n=Og)jF+kTrJ%WdK@=eFOL*>-cWiP$aujz5 zc=E(fB%09*@l7G@Yn`P;ku585L?Z-Ji51TY`+u+WiJ?_j?yA4ldDLO4e2ViNIi-hJ zO?k4$v$@2@nHsg=b<@6!6B4l^l29X_0yHjFa7DTCpy}K;!;d}4S*W2^Wp^oPn26*0 z)^l5wZ!38<-XeZYxrRjFtYtkF&zBXKZ1x_~+}rZn>!j<7dMJ+azKgCpVdMA=4nxP+ zQ|PI^r!|<7PF<Cp%ET`gF(6>ZJ}KhkNDJ`tH!kw@N`s#C7f04JD~*erhCNJ1AyF$4 zI?HJA+(ybyYzfN7a}$*=PFRq}k=W&UF~S<fnK&&dIV~E01HlVb!JPQ-=2#?m$`xuy z_H2gv<4FvywR<oeS~3!=As2#nk3Mq&MWj&WV`Zg=B{Ei)WURv#8O)==;?0M!)p63d zgtD}J))7@b(Rg3oG{?|hN~sET3}s?G<W6-tq3l^zo67RncFQoM;0Fq2iHMNfsw&E) zcE<jXSF`Y7tbmL{zoXxrJ+zWLH!CQuOay{Na}`&WYTgS~L0FZd9hknU7(Jy~P`3jc zGwe|qgfh%EF_t&pc~3d7q(8HzwanVnwx!kS<Sck7bstOwhO=U}j4~K1EapV<X9M!Q zwz%d9WxEKOO6>0Ey3EuN+4woyQIPa2Eu~Rfk_{tDA^5pWSOnbJQx~#%`1592FmVBk z2aQCw10+6HQZ^^ac{iIMc=(oGF;MnuSL_F(Xxjc{K&klBwR_lQ$p!1FTM_XXlL)#} zW~T(}L`2*glAW3mW<hfgg$j!XM0Ul`;Sm$;h@a6BHT37b+;=(7<L%t#UO%TR?X8*b zkd8og$6IsG{PTR~W%r-h`q+Qkvbe-^_a-a<0K>IC`rkZXl9{WpQ$KzEW&1l554QgR zx!heicmC<|>M`YN1p1bCFl8eAFGa{`3ip?#_jcB1<shW0I>=072^?H480G|$fUK9) z)qP#m5=m>DT>Me&d<m&&I@UL8NwGf*p-TB9oF8xnd3o2Otu$@LE*5p2oc3cNjJbtw z=SX?EM*3HAa8Xgl1dZ7h!s<YzvRx;7P19_oFjQH)M@mR$VIBzN?WrjxPQni|Ykonv z+LG)SH+s{wmySq@*|mL3e3z@7))|ZaFxZgls_JPR8gZPJNlt9|8b{r}S{p8N7y+Gp z>In2NRK~h61s_53{UbhtW(F!;TtSO&?}gkdG7T;{se^BfIF9qRA~WMf`&?+zT!-Bq zTdLiM+Dt!q-A`GNtuJP53+pSXxYp8>N?g4oHJ{mMy23#*n3*E=>-VNeuF}d93>($l zzg<it2m=%vg1Ak~Vd%WqE;e{3o;-!J<B2bjK60JQVg#yww~ccC;HC`49sGn0qm%hw z!)Bws87R;|Z3axI);ph(pmRAiIM{@ps?3-S6MEmhqkF+?)_u*8m04PML^8vh*Mnen zojWg>nU%S&q@^RXBh7xy#oGw{bOxg`P>Fd{;Or1)<qa_Fb@Q@#ZF2x_Su6s$jI4N7 zo|&jtSdL1}S!hS870S>YN)I1}1>;sZ9Hv4weupgE>AugR2v~iSdX1#sI}GJ-3a}4_ z%cUMT+<9TcNUR$PX;)y&KV9<=n0mC32LWI@8Ca_%Y>hJhYq+fW8VgJ1u()g~7VX(K zia});1ks?8jkZe~2@<WmYDpsc4N}!yv`DPTt6{5c?q<VOS6@$GE}O8TP#WleKS5lJ z*sJCuqtBbD?XS8k9%r*%@Ts?Z=$j-A8Nxbz{hs`{m}=$W=Q_4k$j5GH@edbXW+YEU zuscL_WO^p!47QaKuV`luB%;{vwm$5rhD_gnN?4%w8Chm5<Ij?GN!ExrVA*H8qmN#` z6cPiDrq#veN7B&ya_^U#pU}c-{*|WezKF07&&4eqo(Pvzw53{=acCiFfqFQ#cO;9j z)w@P49}3*OkP^>}9LA2b2+OZ6s%^Il=Dt`cq@?P)N^m@JA33VmGF^d*9y5rca~S3Y ztvg@BH_Q<!!gpIa>X)ZItK0nl0B?Fa+g!gNwcTn$;@RHlZat_a<N(DC#T>kU5v_%9 zbO?j91erjUW>ZuWH@VwiVK{YG6*^=x-mfu6QIVtE<9EH}YFKrbBX)WhZZ-;5S#4Na zKwvfnl;-?7%(g9JCK!;~R<?wWg0QaKv<svuWn9h($_~lSl*(H^O6ZcEi(+)VPn~Bi zqFokN@PE+NyqlsTHW=BvTiofxvQ{-Ui4f;1+4WiYxq~_xg%K_`+*zsU{D1QOCb2Ba zp;F69$0c6V{Pa@^LSs7)ERiq0uv}D1v+&bhfMd83=|@DC3km4Sq=w~c(A<z=6XaP< z&bC#^hmBW^IBpz(%@~iLA{+$*J1pT|vgt|*-7|S~9~ktV_1yG4CA$i+Y~J<dS6uP{ zY?Y`cXvzZBayyOX$j=tv;;mgL_Lf@}W0&)--N{P4sGK4qeUTAA%T=J~E1a)iyOmXV z_V-oi+d_`9@<GhNI!1%Ii_j+<K{*wjPT!qseLC{DhsXv#t?i@N>36qu>RZk-wQWtT zD}HG@m7Hx4g3@S)8!6T;71Tt05GIV;h<8zQwO=EjvSUP8jyY=buiCM95t($X2`d@t zs`_D-8QK+JM33e8q!He+sZdhUr(%|(><EjY1!aK>pzc|uMq>!HcZ$B6lyc7`cC2P6 z9gR&nZoToj(>_FN9(%E)kkShcnliGlsI{3^%&dsqLN0F0ttK;ChFatf)(FWw+BIHE z!oUg3r6b}3R@YtRKKJPx2a-IPSRG2spZd~ez!euTT^w^5vboZei`5+McGzdSwyPFO zxD5xb1s-7vfFlHiW;ut%9@yH(MjDQ?o(9@V>H9;3{geHF=%3}RcRTlA^IZT2J>y8i zFDnk+ytyvh!8yelAgXF;3^x4}P=<wa<iD3>99a!-hL(RUTr&GW%toHeb|CH)&IJ;3 zbsB9Ul*Ub}^q{xQk1}>=6jdazucqbBjh45yqmx(&lw0-XTm@K#VJZ>>M~w=-Q-x1A zl1~Pg5@?>Y*6kuOeS;Jl9a_aFU>?ZiN9U`_TK&`G6Rzc5t7vP`_QxJ{pN{FzH`{B~ z^)**5hQ@nuZhwec6{5)1(HQ$TwfU%R##u)opKko4v%{i<WD;2`h)iYEA;aSb$CM=s z*Q9&a(B%7LxnTU8Jcm}a-x5>xq>jzsr8<IB84Evb`tlncjY)`W&s5ZAX<NwU5!Ug! zNZAXskDp3I$j8TqR+bKUPuu-}q)iH{zjamqs=8n~tFIyudf@xqa-{O;sHn^Kf6+8C z@YdPAMO0E!(I__a7{@?Zb@eXlFLA@vh}IMds{y=8w>Zk#IDkGa6P4A%r{{zrg{=Iu zH-Zg`%&oe0&CPI9mbB97=PPU-o-P#-idphkBjxQMS#U_ja(G3(7>8Rz!rSq<)M`^u zx>U->qEi_Z!m=g~7Z<P^J;~=CNUejmyLWwEE|0Yb`f|AEuMO5PPF)%>RJtT7XaGpv z!@$;+-n4D39sHeG(G%9>G3yZ!@d&v?Q^#;2oImM)YMJ+kH{D%V(|i?ZaxYhLpjb@8 z_`TuWiFtE%C*3@-`cU9ilQ@*sc70AI=w6cM$VQp7WF=!HWf(CR7a$Tm(y&!y@#?VF zG#cQYvBrCH+`pfU^Cv*aq|=FQUu4MV0s6wRjg3ZePD8H<lwo-EM4u7N9|VItXL`vW z%A*CRQZu9+0ghyR@EUE&eZ|GD`jjL7av>rW%m${my>&_1{PU+v#^t6=Q*nB}T^TgS zX!>niM{4rG9@^0=HpZ5~7|l|+qVZ_lRMc*BB&<tXQN65FQY*#>CV2Ee()^~ESvDdr zyJgT0qBkm*q@o@(ou<>{_08Wi=Nh>BYP1afh*L6Jk5?v}%4LURHjJGyHLJLLaE~0T zCOC83{{Y%EsxVA_jScE*f#6}T7)B!eTgKd}ee$eTQE!ba3XH&`FnXh_dK~p&{x%#u zO|z*K>JKuB?pS#V7*HsTT^IOPwSCnQSNBv!*VA71{{V&VZ~d1lf8eRAw_4q8#F8Fd zj8JjTeYcy+Yx!lNWq`1B?5c9X6qM%Liqa7IE2&f}H^xz?<{%@qqoYqFF;TPlxyBCU zGDL}32Q+dwQQk}MyZG9B&GoH0TJweZ2Rl;YMWhN_H0s*o%MzM%S!lTgxjD2(J;jw1 z=}yXyX8c5LNc7qR_BXFt8!4=z0jq*7G`yJi>K*Gv(RAg%&9VC9vH9BK=qLR#Vg;uJ z(P>S!u?0X?f=%64XWqKE;q!ZTIe<oOadNgp!a1Bk9gqm|_`C)Q62V(M3CV)0ySlWB zLFPg(PEMsMn}T6)lb)hvExh_`KBDW3COL}x5pj(nqeV-4Ha@**{BgH$kcU@~lA3EG zk<9de84(da$cg<uwS`q*byZdU)m4A-(+hBUjSD6pDV0@J@hX<?yDb=H*U=VJs}ZG) z0%K;yojsPne^*w<t5FQ9XuQ7OFkan~#$-}Uh0-SQ4j~SZ!|O5Tp>mym?ecrg*6>B4 z$n!Mj4-2&J(Kr79OAC(lTW8W4<k~Y9oW~(SDXAp3ijuOVE9irZcI7HKJkl@Fvm)7_ zBEnf>Npy%toU@gELBL#f6_4~hA`J$gMW#GAd&cT3B7W+2&Q9L>1FXJFQ`oXLu?JCc zZD0}x)(klbEpEVRhoVq~%1XwjTOB?CY@nM@FY%Yo)85$P+A@+>#fep&Fdm0nC2aF? z>2&OBmkj;b1<Dn57mLE9TQ0$irfM_@C>ltxZqWg*OGt<&?n+xa#-e?j<>R9*0dU}R zxQ$x%A@kTRk6|p0T^trt{{WR&EVmUAb9<N;*_nF<vjLCft;n+7@YE#F=2F>2r$bW` z{{WFA`@a0DT{ixeAq480imsH?g`p)Yx#dd$RueXkAzx@yc$hKgkuLE>L5Lz#Q*D}P zj;=H`EIa*OYqK47-cj`YI)k~TzA|MEs>-jNA=gJd2HwYGQ8jrKjSglXx;pBZbv1f^ z%s*kBAtYyA*Rj+~&aBBq$fLXgXzD;k`xZ&HN?rCvdk7y|S@L=JCel^!_Gj-J`kJdE z(du>8AkuMD6o+2LEgFW=HC{b|S$5iRo#~1v1n078)BcHxr*$8AcHh*kmkuT*(V;Oi z^3QV5W_6)CElWae9Ip#bWhhj^X?Vm^tCi1ek$MQ2*fThERS>Bils{y~G>D(|wxD8Y zL!&HW0KkrD`I!ubwdIcco?eybKr^kX7zLRIa$R){LMs8R8cx`q1STp(1(pQL$3aeF z&LU%7#T`aWj#Mc)#EMW1!!jeyx^J23C8Fq?Z_5uq19MSVkq9-RQ*fn@>X@#>s|~LX z&Mcl7=gVcqbPNFJ`y5PNv1-T_0{B2Psn`;Sa~I7)N)er!X(H1l(Tc<X!1*_+ERI^| zWUQs_4y1&YuA9=0DH?*zuWG?mnVOzwE2$_~bjUK!qxMy^azei)j;0VK`+86u63l5k z%qGVhC^Tq%4f5Y}ZFWR02UR5)Lt5Sv&J9=AD%As9Rn?OwlH_N*orpw+IbpJMH}h2v z$%@O(kT!Io30#FYuNGjawqo`mURmu3=S?^1!2I#fOl=kpW5)$7jY<9#DsdT`kgx|? zOa<(7IwL$%LirrLH?pcE<%odIGS6KZXLV;lu6d`2d1~?+COcHY3^Sr^F7=Yp)QiY~ zGj+?ubyVWTP9GZDs#$`<Wzh=KEX0KAt$C{jqFEJQA*|RL`m|iaC}vXPi-Y}UI#)dB zP5%4;0ApwO&+4zyP`}jQwtuzv_GtZ`{g?j$9{o@9{{XR{`|1Ax7yJkHKji-a?}7Xy z^}qNpqeg)+FDCZ1Cfb?LqV(+~5<fnJC0@@d#HzvXDcNjsnE|IpC{`L-%l+G(4=V#4 zmxhxDC@A>31blkzh@{10gUIf+$Cx{|Ct}(*sam#?uqPI488AZzrnO+#xC0H9*5xVl zHS9D<S3rS8EA6V{?_eY1AqF)N5-Ie-LLfbh7HFVcLe_K`j_j^uQr=^t3K!^Jbb`+; z2s!9c5s~_C!!=QooRA?~)Sx6W*c2}l=3=8$&7u=XRK6H2EbV1#xV#<;RvIiIweil4 zR7%6?`od#LRTekq9E;n9flFt>q(>z6S$dm``aau_o~zp-DIW+GCUG=}L<y}blS1Xv zfEbI9*1a<bRE(i%38PI_P30!(t)zB|D1})_KZ@AWSls2sUnZwx6H3M<K7?e3km;-@ zCn;`SDEYt)j>$vi52<ttL=H@3G{7u~cI=xm+G_s*EtdUp8nwihr>Q$IrOctM+S4mi zx>{i}pCWR?jN0#+N{=dOqNG~p!-hsBdSfZ3zuiPOT}9Q#Ro8i!!Vm$lE^eG$b&Um8 z^d-JarE6NH<WAJ2Vto`OWH_{TOCyd%1Xt29CvhGveM-hZivCt5vl~RCI4h78oW>48 zIr{P)#=)w2z7jXg_dmkvnyBzPQPi4AOI`(1KQFexMPWWhd0vZ!2#U;J%HBg6Mv2z5 ziAsf}QMg#?q~r4vNXX{rA}L2>flV44RNs{zim4$7qL7%qa-jWX(%I#5XuW3}KPRH4 zlc5d3%Z<`fVvO9Ef;uiRRBLoFi>Jv)4#VQJD4Jj<f_0HAn2LE+okThKtpm3{bFp}N zw=vRZNS>;)Mn-Z=4h=j35|)-TlW66{nl>uToHP>u09NT}hNs>9ZPd@p&V{4Ltq)qO zS8;?p6kS(nLHgIAY#Pt0XOmi@BVo%R&^E8(aVawhEuKgl*#|p5rRnKePL0-21Then zh$2XJg=!s@RH9;WK+sT#8lq3*I?rjXBUHzy^=Dvm(4X7l0myc?rGst?m%GkMqms!K zf>3#bDAN^cr~@HUI1nf-Z-2zbo{|TVP8KUHB52bSk0}-w+{vDCZO?r1h&}^-9;WrG zv-yAI--Uh&i!Txk8^+(VKH2^ui5^<~AAJ7+68aB+`&M+q-c&jf^$UtI=y)?`FCo#2 zz_pUryNx!vPt=g(Ef2;jlJ;(_Ga+{h4p>B6X2@YwjVKZm3WYi}yb>}pFo~hBXsX@6 zJi+Ql^fgx@r>4F;It!$wmxJn>CRWsIc0nN*4E8G`718a&X)}t5k6+cLb<3MqK;;7K zB211JttBwiSB%Jv(eVEO=*aC$FyT%xk;kb@s<x8|zxwK*k;&j8PqvcU17H=02ulRX zEXf3_Q7tnflWiikr-f2%#qd}(XEH(o>*!Q2H<W^;Xw;YDe&?dPA{EqJVb?}tJb_Pk zd#Z-bt2!1B5^j}k$^C=R>x<q4C7Qts?(}w*1-Bak8i38@88F!~BjXxIOS+ARnk!+! z=gg1Bf1253f~m6L)I0*wTn<=Gz;$N?^!*QAV&PxuoJ5k8YjxuJ<;%RQ2_#ffN86Jf zmM)|%C*+IE%@na0I8i2U+Myt=YHpFM!_n1{I?J9p<CpBNeYm6bL{t@zHJi?+R3vjk zGW+NNQL>Aye?V3i)zNGIGbfNAi8%dyB1=XCfY$Z%=<a;|Ayh+o^&a3-3snH6;au^3 z)fHtbdbl2Pl-l60#mTKv&>;b{2u%0ZB%-w^3SRLuZB&?ddbpgJdQQZUGfC9Kw3fyy zq~AxkG-!-ZY<{fq@4%ix5b_1pXK8!)r0NcNg7Pmr67nB?bstW!pGQnshpu^4T_Scx zn<uLn$^qIi3i?J~tgwkg)z-35<gCa+B;v&6182qb)mt8$?P~LfUx2DSu-LEau+%fh zvnb7HIh%1LZH!ID(Npq0v1YL+9*T4fg2>uoE3sCP%Yn#b!cN6yql_}l14EIR(L1K7 z`#ZaQe#XneVfA%w)cbP;g7<F;a#A~@!tVQ%eQiTTCz6wLIlISN3M5JA<`c<;pz|b| zw0KnG><`sVcTSQM7a>blw~h139P<&KfazNzuFWpWifuvHvj})tym;(_6D+T*Me8{! zvQ$K@!x+xfR_B>q!qJ<v19Vt(SBgOL2+^r~BJsK9ek+*`h0+l?=P*=F1&~UAeD^<) zp-do&I+hh6<m9qrG^#p|@3y2<g5--nAejw}1~~Ae)`Fu(gzD5vW2fJc*at=u@yFw% zzPY026WjG~C306?le{_#;Ce<RM&GV(nNK<{N$dLWu4LqARtSSI+SbI1IEKw-ZtQ6@ z7J*nrlz%uq6&$cjIaI{wepQdajzUqi5P{Z~<$+kiW*f-tG)!4=UPzl>^(}BTaq?x) z5fMGSz{BG2VDabeO3qP`Ee{s9gw8ZqUqRa9kYix*Z1%$CerY8(=wyokokZNzp)082 zk-OYPYv^_CItf#$S`Hs4c-tpJj4UCWdX`9Tx69H{BeJp6@-hQPi+_nOc<e6V<liOt zR$=vkXtzrE{^<S%=FySaEqNIUivSx5#2v6TAW;XT7pr3W%?c1z(JAU;<`S20NZKa{ z5N$MLDUsoPanrY-PeA<k^FRvDzlU@_)n^h_D%VWqP?caP&El6QYnph)NvtINx+M9N zrl{u*O0p!bc3*AUJZ8=6E4NG|(zLB=zeo8MD$<auY&j(l1hpph3`SW|LF^zJNE&qQ zKUN$l?gn-`Ts)+8Ye!G5TP>h+qR2+0nSeE#NkzVg!%dEHBnDC3?8~((>i%8J9Pml~ z=gts0l)fB(wN0q%R&H9YDPlc$Tvua>2#dl006cEMEr6s_R~C{)7!0vqkgVen*pY~P zFs6+WjtZ}OGqSvR`Fn*!VR0!BMKJ5GI3Pm1Ju<7tK-4|R-2q<9EJ!;kylz19oZcWb z9WNsZ4=Em#VgOP;+zv#NWDV<O5FVaBJd#QyF>cM{GM!L2#{tfUoklJCAEm}CwkkTO zs^ELV>2tKj(rPBkdl`*T*Q_oz4P@@@9W0K3t=EASk-RG`8cbNVVV@S&ksT=Rleq)Y zH5IRBKy7|zt>bKLS~|SC07Gi4HJ?EgpUKdG&Em3nx(jJJtm!JzjHtLrW8-PsuA_qW zV=taWiVq|c9&m$mgRYT3&b;qf+0&f$To#&hR7`4M*VszRIVFi7lC4C>pi*J-GVupf zOCbpzK7j|zFMJ|8t6C8Vuz<{1+Jxn1jZL?-U$p3#)+rt})3%U>nKUC3pVPg+$Y*M) z(6T|96cTnZAhImFo^h}u3OmX=JS$p{Q!Uc_g9J*mU9zjQUHMq~T<6X@=rY~i<))yg z@h7I{f&g)R$DrhP?b+1P*;!>Pf_0dI5r~vC0T;6(uBC_sBNC0>0S3NYQ(5Ua9Ce)P zX9*wWL{-#h`!94|9UW&GiSv=^#QvDEAyca$ERQT>z3IxF#S~Ld!{>r((gO)pvhvPf zNd(vI<udXnbRuq6TsXL(pc{7rQ5BgO2Np+%P!#;C6V>;$+NbI%<En-oA(upJ!DL|( zNg(hxcA(WeOB1GP*-3te{H{7yJ1!FJ$~Fb6c2!k1k4A=?HHq<GL)TtZwCKKIx$juN zG=i^r&OvO%$O30w2S#&m29P+0L9H9jjOjP-Eb8i?MsRB<;zFIon3Zil%Tp3zE*1vo zNsnIm%JcWm;E;jRb*D!Q3mq{OI~SJnuaa=_>M-J9<FN+A6^K@rFJ@JdcM#_+W9(x~ z1+Y2o%8p~qbR4?pMQT0ApvveKO(XHeV!Crf)6Fazf35k7KGM?OFj&=#BpY?rUC$zy zhm(<+NTk6BiE5=iTnrWh1ssBd%XonD(gA1YZw*R{Pm02r02ZBvL1S>o!>Kv9j_!`= zxrD+VMqM8ky|WdruIXsQ8=H!k9}pPTE9MCS<`U7yEEvX1B3F9E_;NQX-^v#>Yi#n@ zDnDIu%`p)2A8uFIAD8HNLd~1Ql7&m_8w%#5cp!yxl22+L#g<l3VX%o4xAs%TCiTl1 z23|~t$R=Rqb==|Bz%1Xb2X+^fK9HQ#4JuM$Anh0~76%fR*dZ&J*h@;zh}DUr*0qe; z6XDDdF)0lXU^X<(vvsyXNe0lEDOsBGbI|DVb`n#dqjfZoh4~6a4y7uZn9_X-)-^Po zm1YRQhqf^K)~De47+Ea+;kgWr;i+ST_O$T2`!aAQC?Q!J(U9n*RzIUq$PmtkqibQ5 zS58(9=!&o{QO>;c%GPZIbpolP0IbPm;&nae_`aoO7w}+AWLHBw`mDHa%X<--S;-_d z&egbSRUsaM*7dvS_oGIGy@Tb$p=?mF;1gJlR`muG*e#P{xJIpwiZ9TT%H@vYqED~W zV%sw@VkFFK=_(~#D)e$vqH{@fu33Y#Q#(l#^j>~m?pq;BoU1z0o2sSM(Ku-e{&Q8p zHik@qvw<XA@p$_~T9<vcBg0=6`@(E;-{yVXV27D?jIzdxI{rXZs8wg<($$Ic^)Xm5 zn{v*_<(0K;DsC1BBz+3)p2ezKIFLUtJ&;<5%9(@KaX=DDdHX!1__JY%DVcH(8!%a$ zLFLRXbE$rCm{*lWaZWR^IdZF=lZMrS2nC6=Hzjo_di_S2JZ4QPC7p5dSt3qdDU-=m R9L<YDCy0F-DqzvC|JhblOT_>H diff --git a/core/src/cz/nic/tablexia/TablexiaLibGDX.java b/core/src/cz/nic/tablexia/TablexiaLibGDX.java index cf49398f9..2530b284e 100644 --- a/core/src/cz/nic/tablexia/TablexiaLibGDX.java +++ b/core/src/cz/nic/tablexia/TablexiaLibGDX.java @@ -1,49 +1,197 @@ package cz.nic.tablexia; +import java.util.List; + import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.utils.async.AsyncExecutor; +import com.badlogic.gdx.utils.async.AsyncResult; +import com.badlogic.gdx.utils.async.AsyncTask; import cz.nic.tablexia.common.RandomAccess; -import cz.nic.tablexia.creature.CreatureFactory; import cz.nic.tablexia.creature.CreatureRoot; import cz.nic.tablexia.creature.attribute.Attribute; +import cz.nic.tablexia.difficulty.GameDifficulty; +import cz.nic.tablexia.rules.GameRule; +import cz.nic.tablexia.rules.GameRulesDefinition; import cz.nic.tablexia.util.Log; import cz.nic.tablexia.util.Log.TablexiaLogLevel; public class TablexiaLibGDX extends ApplicationAdapter { - private SpriteBatch batch; - private AssetManager assetManager; - private CreatureRoot creature; + private SpriteBatch spriteBatch; + private ShapeRenderer shapeRenderer; + + private AssetManager assetManager; + private GameDataManager<List<CreatureRoot>> gameDataManager; + + private RandomAccess randomAccess; + + private enum DebugGroupColors { + RED(Color.RED), + GREEN(Color.GREEN), + BLUE(Color.BLUE), + YELLOW(Color.YELLOW), + WHITE(Color.WHITE), + PINK(Color.PINK), + CYAN(Color.CYAN), + LIGHTBLUE(new Color(0.569f, 0.612f, 0.976f, 1f)), + LIGHTRED(new Color(0.976f, 0.569f, 0.569f, 1f)), + LIGHTGREEN(new Color(0.569f, 0.976f, 0.631f, 1f)), + LIGHTPURPLE(new Color(0.969f, 0.569f, 0.976f, 1f)); + + Color color; + + private DebugGroupColors(Color color) { + this.color = color; + } + + public Color getColor() { + return color; + } + } + + public class GameDataManager <T> { + + private AsyncExecutor asyncExecutor; + private AsyncTask<T> asyncTask; + private AsyncResult<T> asyncResult; + + private boolean started; + private boolean complete; + + private T result; + + public GameDataManager(AsyncTask<T> asyncTask) { + this.asyncTask = asyncTask; + asyncExecutor = new AsyncExecutor(1); + started = false; + complete = false; + } + + private boolean update() { + if (started) { + if (asyncResult == null || asyncResult.isDone()) { + if (!complete) { + complete = true; + result = asyncResult.get(); + asyncResult = null; + asyncExecutor.dispose(); + asyncExecutor = null; + asyncTask = null; + } + return true; + } + } else { + asyncResult = asyncExecutor.submit(asyncTask); + started = true; + } + return false; + } + + public T getResult() { + return result; + } + + } + + public class Loader implements AsyncTask<List<CreatureRoot>> { + + private RandomAccess randomAccess; + private AssetManager assetManager; + private GameDifficulty gameDifficulty; + + public Loader(GameDifficulty gameDifficulty, AssetManager assetManager, RandomAccess randomAccess) { + this.gameDifficulty = gameDifficulty; + this.assetManager = assetManager; + this.randomAccess = randomAccess; + } + + @Override + public List<CreatureRoot> call() throws Exception { + GameRulesDefinition rule = GameRulesDefinition.getRandomGameRuleForDifficulty(gameDifficulty, randomAccess.getRandom()); + GameRule gameRule = rule.getGameRuleInstance(randomAccess, 50, 8); + List<CreatureRoot> creatures = gameRule.generateCreatures(); + for (CreatureRoot creatureRoot : creatures) { + creatureRoot.load(assetManager); + } + displayAllCreatures(creatures); + return creatures; + } + + private void displayAllCreatures(List<CreatureRoot> creatures) { + if (creatures != null && creatures.size() > 0) { + float creatureScale = 0.5f; + float creatureWidth = creatures.get(0).getWidth() * creatureScale; + float creatureHeight = creatures.get(0).getHeight() * creatureScale; + + float borderX = (Gdx.graphics.getWidth() / 40); + float borderY = Gdx.graphics.getHeight() / 7; + + int creaturesInLine = (int)Math.ceil(Double.valueOf(creatures.size()) / 2); + float xStep = (Gdx.graphics.getWidth() - (2 * borderX) - (creatureWidth / 2)) / creaturesInLine; + + float positionX = borderX; + float positionY = Gdx.graphics.getHeight() - (creatureHeight) - borderY; + + for (int i = 0; i < creatures.size(); i++) { + CreatureRoot creatureRoot = creatures.get(i); + creatureRoot.setScale(creatureScale); + creatureRoot.setPosition(positionX, positionY); + int groupNumber = creatureRoot.getGroupNumber(); + if (groupNumber >= 0) { + creatureRoot.highliteWithColor(DebugGroupColors.values()[groupNumber].getColor()); + } + + positionX = positionX + xStep; + if ((i + 1) % creaturesInLine == 0) { + positionX = borderX; + positionY = borderY; + } + } + } else { + Log.info(getClass(), "No creatures to display!"); + } + } + + } @Override public void create () { Log.setLoglevel(TablexiaLogLevel.DEBUG); - batch = new SpriteBatch(); + randomAccess = new RandomAccess(); + spriteBatch = new SpriteBatch(); + shapeRenderer = new ShapeRenderer(); - assetManager = new AssetManager(); + shapeRenderer.setAutoShapeType(true); + + assetManager = new AssetManager(); for (AttributeDescription attributeDescription : Attribute.getTextures()) { if (attributeDescription != null) { assetManager.load("gfx/character/" + attributeDescription.getTexturePath(), Texture.class); } } - creature = CreatureFactory.getInstance().generateCreature(new RandomAccess()); + Loader loader = new Loader(GameDifficulty.EASY, assetManager, randomAccess); + gameDataManager = new GameDataManager <List<CreatureRoot>> (loader); } @Override public void render () { - if (assetManager.update()) { - Gdx.gl.glClearColor(1, 0, 0, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - batch.begin(); - creature.render(assetManager, batch); - batch.end(); + if (!assetManager.update()) return; + if (!gameDataManager.update()) return; + + Gdx.gl.glClearColor(0.7f, 0.7f, 0.7f, 1f); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + for (CreatureRoot creatureRoot : gameDataManager.getResult()) { + creatureRoot.render(spriteBatch, shapeRenderer); } } } diff --git a/core/src/cz/nic/tablexia/creature/CreatureRoot.java b/core/src/cz/nic/tablexia/creature/CreatureRoot.java index 88a32f055..ccb3f0732 100644 --- a/core/src/cz/nic/tablexia/creature/CreatureRoot.java +++ b/core/src/cz/nic/tablexia/creature/CreatureRoot.java @@ -24,8 +24,12 @@ import java.util.List; import java.util.Random; import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import cz.nic.tablexia.AttributeDescription; import cz.nic.tablexia.creature.attribute.Attribute; @@ -45,7 +49,9 @@ import cz.nic.tablexia.creature.attribute.head.HeadAttribute; */ public class CreatureRoot { - public static final int CREATURE_GROUP_NUMBER_NOGROUP = -1; + public static final int CREATURE_GROUP_NUMBER_NOGROUP = -1; + public static final int INITIAL_WIDTH = 193; + public static final int INITIAL_HEIGHT = 480; /** * Creatures gender types @@ -127,17 +133,23 @@ public class CreatureRoot { // } // private boolean isClickable = false; - private boolean isRevealed = false; - private boolean isThief = false; - private int groupNumber = CREATURE_GROUP_NUMBER_NOGROUP; - - protected List<Attribute> attributes; - private AttributeGender attributeGender; -// private BankovniloupezActivity bankovniloupezActivity; - - public CreatureRoot(AttributeGender attributeGender, float pX, float pY) { -// super(pX, pY); - this.attributeGender = attributeGender; + private boolean isRevealed = false; + private boolean isThief = false; + private int groupNumber = CREATURE_GROUP_NUMBER_NOGROUP; + + protected List<Attribute> attributes; + private AttributeGender attributeGender; + private float x; + private float y; + private float scale; + private ArrayList<Texture> textures; + private Color highliteColor; + + public CreatureRoot(AttributeGender attributeGender, float x, float y) { + this.x = x; + this.y = y; + scale = 1; + this.attributeGender = attributeGender; attributes = new ArrayList<Attribute>(); } @@ -160,6 +172,23 @@ public class CreatureRoot { return this; } + + public void setPosition(float x, float y) { + this.x = x; + this.y = y; + } + + public void setScale(float scale) { + this.scale = scale; + } + + public float getWidth() { + return INITIAL_WIDTH * scale; + } + + public float getHeight() { + return INITIAL_HEIGHT * scale; + } /** * Returns <code>true</code> if creature is thief. @@ -408,16 +437,41 @@ public class CreatureRoot { // scene.registerTouchArea(clickableArea); // } // } + + @Override public String toString() { return getCreatureDescrition().toString(); } - public void render (AssetManager assetManager, SpriteBatch spriteBatch) { - for (Attribute attribute : attributes) { - Texture texture = assetManager.get("gfx/character/" + attribute.getTextureName(), Texture.class); - spriteBatch.draw(texture, 0, 0); + public void load(AssetManager assetManager) { + if (textures == null || attributes.size() != textures.size()) { + textures = new ArrayList<Texture>(); + for (Attribute attribute : attributes) { + Texture texture = assetManager.get("gfx/character/" + attribute.getTextureName(), Texture.class); + textures.add(texture); + } + } + } + + public void highliteWithColor(Color highliteColor) { + this.highliteColor = highliteColor; + } + + public void render (SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) { + if (highliteColor != null) { + shapeRenderer.begin(); + shapeRenderer.set(ShapeType.Filled); + shapeRenderer.setColor(highliteColor.r, highliteColor.g, highliteColor.b, 1f); + shapeRenderer.rect(x, y, INITIAL_WIDTH * scale, INITIAL_HEIGHT * scale); + shapeRenderer.end(); + } + for (Texture texture : textures) { + texture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + spriteBatch.begin(); + spriteBatch.draw(texture, x, y, texture.getWidth() * scale, texture.getHeight() * scale); + spriteBatch.end(); } } diff --git a/core/src/cz/nic/tablexia/difficulty/GameDifficulty.java b/core/src/cz/nic/tablexia/difficulty/GameDifficulty.java new file mode 100644 index 000000000..5c8b74259 --- /dev/null +++ b/core/src/cz/nic/tablexia/difficulty/GameDifficulty.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.difficulty; + + +/** + * Game difficulty types + * + * @author Matyáš Latner + */ +public enum GameDifficulty { + + // TODO use string resources + EASY(1), + MEDIUM(2), + HARD(3); + + private int descriptionResourceId; + + private GameDifficulty(int descriptionResourceId) { + this.descriptionResourceId = descriptionResourceId; + } + + /** + * Returns id of description for current difficulty + * + * @return id of description string resource + */ + public int getDescriptionResourceId() { + return descriptionResourceId; + } + + /** + * Returns string key for intent extra + * + * @return string key for intent extra + */ + public static String getIntentKey() { + return GameDifficulty.class.getName(); + } + + /** + * Returns difficulty for integer value + * + * @param number integer value for difficulty + * @return difficulty + */ + public static GameDifficulty getDifficultyForInt(int number) { + GameDifficulty[] values = GameDifficulty.values(); + if ((number >= 0) && (number < values.length)) { + return GameDifficulty.values()[number]; + } + return null; + } +} diff --git a/core/src/cz/nic/tablexia/rules/GameRule.java b/core/src/cz/nic/tablexia/rules/GameRule.java new file mode 100644 index 000000000..f6833dc4f --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/GameRule.java @@ -0,0 +1,380 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.creature.attribute.Attribute; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.hair.HairAttribute; +import cz.nic.tablexia.creature.attribute.head.HeadAttribute; +import cz.nic.tablexia.util.Log; + +/** + * Abstract game rule class. Contains common functions for all game rules. + * + * @author Matyáš Latner + */ +public abstract class GameRule { + + + private RandomAccess randomAccess; + + protected int numberOfCreatures; + protected int numberOfThieves; + + private int groupNumber = 1; + + protected static final int GENERATOR_TRY_COUNT = 10000; + protected static final String RULE_LOG_PREFIX = "[RULE] "; + protected static final CreatureDescriptor BAN_ATTRIBUTES_SET_FOR_GENERATING = new CreatureDescriptor() { + { + + addDescription(new AttributeDescription(null, null, HeadAttribute.class)); + addDescription(new AttributeDescription(null, null, HairAttribute.class)); + disableGenderCompatibilityCheck(); + + } + }; + + /* + * Map for special creatures contains thieves and creatures which is important for thieves to be founded. + */ + protected Map<Integer, CreatureDescriptor> specialCreatures; + + public GameRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + this.randomAccess = randomAccess; + this.numberOfCreatures = numberOfCreatures; + this.numberOfThieves = numberOfThieves; + specialCreatures = new HashMap<Integer, CreatureDescriptor>(); + + Log.debug(getClass(), " ------- " + RULE_LOG_PREFIX + " " + getClass().getSimpleName() + " starts generating creatures with seed: [" + getRandomAccess().getRandomSeed() + "] -------"); + } + + public RandomAccess getRandomAccess() { + return randomAccess; + } + + protected void incrementGroupNumber() { + groupNumber++; + Log.debug(getClass(), RULE_LOG_PREFIX + "GROUP COMPLETE"); + } + + + /** + * Add creature to the map of specials creatures at specific position + * + * @param position key to special creatures map + * @param specialCreature creature to add in + */ + protected void addSpecialCreature(Integer position, CreatureDescriptor specialCreature) { + if (specialCreature != null) { + CreatureDescriptor existingCreature = specialCreatures.get(position); + if (existingCreature != null) { + for (AttributeDescription attributeDescription : specialCreature.getDescriptions()) { + existingCreature.addDescription(attributeDescription); + } + Log.debug(getClass(), RULE_LOG_PREFIX + " P[" + position + "] SPECIAL added: " + specialCreature); + } else { + existingCreature = new CreatureDescriptor(specialCreature.getDescriptions()); + specialCreatures.put(position, existingCreature); + Log.debug(getClass(), RULE_LOG_PREFIX + " P[" + position + "] SPECIAL generated: " + specialCreature); + } + existingCreature.setGroupNumber(groupNumber); + existingCreature.addCreatureOffsets(specialCreature.getCreatureOffsets()); + existingCreature.setThief(existingCreature.isThief() || specialCreature.isThief()); + } + } + + /** + * Return random number from interval for thief position. + * + * @param intervalStart start of interval + * @param intervalSize size of interval + * @return + */ + protected int getThiefRandomPositionInInterval(int intervalStart, int intervalSize, int minValue) { + int position = getRandomAccess().getRandom().nextInt(intervalSize); + if (position < minValue) { + position = minValue; + } + return intervalStart + position; + } + + /** + * Return random number from interval for thief position. + * + * @param intervalStart start of interval + * @param intervalSize size of interval + * @return + */ + protected int getThiefRandomPositionInInterval(int minValue, List<Integer> bannedPositions) { + int result = -1; + for (int i = 0; i < GENERATOR_TRY_COUNT; i++) { + int position = getRandomAccess().getRandom().nextInt(numberOfCreatures); + if (position < minValue) { + position = minValue; + } + if (bannedPositions == null || !bannedPositions.contains(position)) { + result = position; + break; + } + } + return result; + } + + /** + * Returns creature description with two random attributes. + * + * @param descriptor random creature description from is choose random attributes + * @return creature description with one random attribute + */ + protected CreatureDescriptor getRandomCreatureDescriptionWithTwoAttributes(CreatureDescriptor descriptor) { + CreatureDescriptor creatureDescriptor = new CreatureDescriptor(); + + int randomDescriptionPosition1 = getRandomAccess().getRandom().nextInt(descriptor.getDescriptions().size()); + int randomDescriptionPosition2; + for (int i = 0; i < GENERATOR_TRY_COUNT; i++) { + randomDescriptionPosition2 = getRandomAccess().getRandom().nextInt(descriptor.getDescriptions().size()); + if (randomDescriptionPosition1 != randomDescriptionPosition2) { + creatureDescriptor.addDescription(descriptor.getDescriptions().get(randomDescriptionPosition1)); + creatureDescriptor.addDescription(descriptor.getDescriptions().get(randomDescriptionPosition2)); + return creatureDescriptor; + } + } + throw new IllegalStateException("Cannot select two different descriptions from creature description!"); + } + + /** + * Returns creature description with N random attributes. + * + * @param sourceCreatureDescriptor creature description for generating from + * @param descriptionsNumber number of used attribute descriptions from creature description + * @return creature description with N random attributes. + */ + protected CreatureDescriptor getRandomCreatureDescriptionWithNAttributes(CreatureDescriptor sourceCreatureDescriptor, int descriptionsNumber) { + CreatureDescriptor creatureDescriptor = new CreatureDescriptor(); + + for (int i = 0; i < descriptionsNumber; i++) { + creatureDescriptor.addDescription(getRandomAttributeDescriptionFromCreatureDescription(sourceCreatureDescriptor, creatureDescriptor.getDescriptions())); + } + + return creatureDescriptor; + } + + /** + * Returns attribute description from source creature description which is not in bannedAttributeDescriptions list parameter + * + * @param creatureDescription creature description for select attribute description from + * @param bannedAttributeDescriptions list of banned attributes descriptions which is not selected from creature description + * @return randomly selected attribute description from creature description in parameter + */ + public AttributeDescription getRandomAttributeDescriptionFromCreatureDescription(CreatureDescriptor creatureDescriptor, List<AttributeDescription> bannedAttributeDescriptions) { + for (int i = 0; i < GENERATOR_TRY_COUNT; i++) { + AttributeDescription attributeDescription = creatureDescriptor.getDescriptions().get(getRandomAccess().getRandom().nextInt(creatureDescriptor.getDescriptions().size())); + if (!bannedAttributeDescriptions.contains(attributeDescription)) { + return attributeDescription; + } + } + throw new IllegalStateException("Cannot select attribute description from creature description!"); + } + + /** + * Returns creature description with one random attribute. + * + * @param descriptor random creature description from is choose random attribute + * @return creature description with one random attribute + */ + protected CreatureDescriptor getRandomCreatureDescriptionWithOneAttribute(CreatureDescriptor descriptor) { + CreatureDescriptor creatureDescriptor = new CreatureDescriptor(); + creatureDescriptor.addDescription(getRandomAttributeDescription(descriptor)); + + return creatureDescriptor; + } + + /** + * Returns random attribute description from creature description + * + * @param descriptor random creature description from is choose random attribute + * @return random attribute description + */ + protected AttributeDescription getRandomAttributeDescription(CreatureDescriptor descriptor) { + List<AttributeDescription> descriptions = descriptor.getDescriptions(); + return descriptions.get(getRandomAccess().getRandom().nextInt(descriptions.size())); + } + + /** + * Returns attribute description. + * + * @param attributeDescription attribute description class + * @return attribute description + */ + protected String getAttributeName(AttributeDescription attributeDescription, boolean useForcedVersion) { + return getAttributeName(attributeDescription.getAttributeClass(), useForcedVersion); + } + + /** + * Returns attribute description. + * + * @param attributeClass attribute class + * @return attribute description + */ + protected String getAttributeName(Class<? extends Attribute> attributeClass, boolean useForcedVersion) { +// return Attribute.getTextDescriptionForAttributeClass(attributeClass, context, useForcedVersion); + return "POKUS"; + } + + /** + * Returns color description. If there is no color returns empty string. + * + * @param attributeDescription attribute description for obtain color from + * @return color description + */ + protected String getAttributeColorName(AttributeDescription attributeDescription) { +// AttributeColor attributeColor = attributeDescription.getAttributeColor(); +// return attributeColor != null ? context.getString(attributeColor.getDescriptionResourceId()) : ""; + return "POKUS"; + } + + /** + * Returns random color from randomly generated creature without any banned attributes from parameter + * + * @param banAttributes banned attributes + * @return randomly generated color + */ + protected AttributeColor getRandomColorFromGeneratedCreature(CreatureDescriptor banAttributes) { + AttributeColor randomColor = null; + int tryCount = 0; + while (randomColor == null) { + CreatureDescriptor randomCreature = CreatureFactory.getInstance().generateCreature(null, banAttributes, getRandomAccess()).getCreatureDescrition(); + List<AttributeDescription> randomDescriptions = randomCreature.getDescriptions(); + AttributeDescription randomDescription = randomDescriptions.get(getRandomAccess().getRandom().nextInt(randomDescriptions.size())); + randomColor = randomDescription.getAttributeColor(); + if (tryCount >= GENERATOR_TRY_COUNT) { + throw new IllegalStateException("Cannot generate random color!"); + } + tryCount++; + } + + return randomColor; + } + + /** + * Adds random creature which has not thieve attribute when there is creature before with "before thief attribute" + * + * @param creatures list of creatures + * @param lastCreature last generated creature + * @param t1CreatureDescription description of creature before thief + * @param t0CreatureDescription description of thief + */ + protected void addRandomCreatureAndCheckCreatureOneBefore(List<CreatureRoot> creatures, CreatureRoot lastCreature, CreatureDescriptor t1CreatureDescription, CreatureDescriptor t0CreatureDescription) { + if ((lastCreature != null) && lastCreature.hasAttributes(t1CreatureDescription)) { + creatures.add(CreatureFactory.getInstance().generateCreature(null, t0CreatureDescription, getRandomAccess())); + } else { + creatures.add(CreatureFactory.getInstance().generateCreature(getRandomAccess())); + } + } + + /** + * Returns array of strings with parameters to the rule message + * + * @return array of strings with parameters to the rule message + */ + public String[] getRuleMessageParameters() { + String[] messageParameters = prepareRuleMessageParameters(); + if (messageParameters != null) { + for (String parameter : messageParameters) { + Log.debug(getClass(), RULE_LOG_PREFIX + "parameter: " + parameter); + } + } + return messageParameters; + } + + /** + * Generate new creature on n - 1 position without before thief creature attribute for special creature on position n + * which is not thief and has thief attribute. When creature on n - 1 position has beforeThiefAttribute. + * n = lastPosition parameter + * + * @param creatures list of creatures to add in + * @param lastPosition position n + * @param lastCreature last generated creature + * @param specialCreature special creature to check + * @param thiefCreatureDescription description of thief + * @param beforeThiefAttributeDescription description of creature before thief + * @param beforeThiefCreatureDescription complete description of creature before thief + */ + protected void checkBeforeSpecialCreature(List<CreatureRoot> creatures, int lastPosition, CreatureRoot lastCreature, CreatureRoot specialCreature, CreatureDescriptor thiefCreatureDescription, CreatureDescriptor beforeThiefCreatureDescription) { + if (!specialCreature.isThief() && specialCreature.hasAttributes(thiefCreatureDescription)) { + if ((lastCreature != null) && lastCreature.hasAttributes(beforeThiefCreatureDescription)) { + creatures.remove(lastPosition); + creatures.add(CreatureFactory.getInstance().generateCreature(null, beforeThiefCreatureDescription, getRandomAccess())); + } + } + } + + /** + * Check compatibility for creature at specified position and creature from parameter + * @param creatureDescriptor creature to check + * @param creaturePosition position of creature to check + * @param isThief <code>true</code> if creature description from parameter is thief + * @return <code>true</code> if creature description from parameter is compatible with creature in position + */ + protected boolean checkCreatureCompactibilityForPosition(CreatureDescriptor creatureDescriptor, int creaturePosition, boolean isThief) { + CreatureDescriptor specialCreature = specialCreatures.get(creaturePosition); + return specialCreature != null ? !(specialCreature.isThief() && isThief) && (specialCreature.checkDescriptionCompactibility(creatureDescriptor)) : true; + } + + /** + * Returns array of strings with parameters to the rule message. Specific rule class implementation + * + * @return array of strings with parameters to the rule message + */ + public abstract String[] prepareRuleMessageParameters(); + + /** + * Returns list of creatures for displaying in game. List contains random creatures and thieves. + * + * @return list of random creatures and thieves + */ + public List<CreatureRoot> generateCreatures() { + prepareCreatureDescriptionsC(); + List<CreatureRoot> generatedCreatures = prepareCreatures(); + for (int i = 0; i < generatedCreatures.size(); i++) { + Log.debug(getClass(), RULE_LOG_PREFIX + " ---> [" + i + "] generated creature: " + generatedCreatures.get(i)); + } + return generatedCreatures; + } + + protected abstract void prepareCreatureDescriptionsC(); + + /** + * Returns list of creatures for displaying in game. List contains random creatures and thieves. Specific rule class implementation. + * + * @return list of random creatures and thieves + */ + public abstract List<CreatureRoot> prepareCreatures(); + +} diff --git a/core/src/cz/nic/tablexia/rules/GameRuleUtility.java b/core/src/cz/nic/tablexia/rules/GameRuleUtility.java new file mode 100644 index 000000000..2da7c97ff --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/GameRuleUtility.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureRoot; + +/** + * Abstract game rule class. Contains common functions for all game rules. + * + * @author Matyáš Latner + */ +public abstract class GameRuleUtility extends GameRule { + + // TODO sjednotit s GameRule + // TODO promazat GameRule + // TODO pouzivat nove metody + + private static final double BAIT_PROBABILITY = 0.3; + + private int thiefGroupSize; + private Map<Integer, CreatureDescriptor> globalCreatureDescriptors; + private CreatureDescriptor baitCreatureDescriptor = new CreatureDescriptor(); + + public GameRuleUtility(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves, int thiefGroupSize) { + super(randomAccess, numberOfCreatures, numberOfThieves); + this.thiefGroupSize = thiefGroupSize; + globalCreatureDescriptors = new HashMap<Integer, CreatureDescriptor>(); + } + + protected void prepareCreatureDescriptionsB() {}; + + /** + * Add global creature descriptor with offset from thief. + * @param offset offset from thief - 0 = thief + * @param creatureDescriptor creature descriptor to add + */ + protected void addGlobalCreatureDescriptor(int offset, CreatureDescriptor creatureDescriptor) { + globalCreatureDescriptors.put(offset, creatureDescriptor); + creatureDescriptor.addCreatureOffset(Integer.valueOf(offset)); + } + + /** + * Return creature descriptor for specific offset + * @param key offset for selecting creature description + * @return creature descriptor for specific offset + */ + public CreatureDescriptor getGlobalCreatureDescriptor(Integer key) { + return globalCreatureDescriptors.get(key); + } + + /** + * Set creature description from parameter as new bait creature description + * @param creatureDescriptor new bait creature description + */ + protected void newBaitCreatureDescription(CreatureDescriptor creatureDescriptor) { + baitCreatureDescriptor = creatureDescriptor; + } + + /** + * Creates new bait creature description and add attribute description from parameter to it + * @param attributeDescription attribute description for new bait creature description + */ + protected void newBaitCreatureDescriptionFromAttribute(AttributeDescription attributeDescription) { + baitCreatureDescriptor = new CreatureDescriptor(); + baitCreatureDescriptor.addDescription(attributeDescription); + } + + /** + * Add description from creature description in parameter to bait creature description + * @param creatureDescriptor creature description to add attribute descriptions from + */ + protected void addBaitCreatureDescription(CreatureDescriptor creatureDescriptor) { + baitCreatureDescriptor.addDescriptions(creatureDescriptor.getDescriptions()); + } + + /** + * Add attribute description to bait creature description + * @param attributeDescription attribute description to add + */ + protected void addBaitAttributeDescription(AttributeDescription attributeDescription) { + baitCreatureDescriptor.addDescription(attributeDescription); + } + + /** + * Returns attribute description from bait creature description at position + * specified in parameter with probability from BAIT_PROBABILITY constant or <code>null</code> + * @param position position of attribute + * @return attribute description from bait creature description or <code>null</code> + */ + protected AttributeDescription getBaitCreatureDescriptionAttributeAtPosition(int position) { + if (getRandomAccess().getRandom().nextDouble() <= BAIT_PROBABILITY) { + if (baitCreatureDescriptor != null) { + return baitCreatureDescriptor.getDescriptions().get(position); + } + } + return null; + } + + /** + * Returns bait creature description with probability from BAIT_PROBABILITY constant or <code>null</code> + * @return bait creature description or <code>null</code> + */ + protected CreatureDescriptor getBaitCreatureDescriptionRandomly() { + if (getRandomAccess().getRandom().nextDouble() > BAIT_PROBABILITY) { + return null; + } + return baitCreatureDescriptor; + } + + @Override + public List<CreatureRoot> prepareCreatures() { + // generate thieves and pair creatures + for (int i = 0; i < numberOfThieves; i++) { + + int initialPosition = 0; + boolean condition = true; + List<Integer> bannedPositions = new ArrayList<Integer>(); + + prepareCreatureDescriptionsB(); + + while (condition) { + initialPosition = getThiefRandomPositionInInterval(thiefGroupSize - 1, bannedPositions); + + if (initialPosition < 0) { + throw new IllegalStateException("Cannot generate creature serie! Too many conflicts!"); + } + + bannedPositions.add(initialPosition); + condition = !checkCreaturePositions(initialPosition); + } + + addSpecialCreatures(initialPosition); + incrementGroupNumber(); + } + + return prepareCreatureDescriptionsA(); + } + + /** + * Prepares all creatures root + * @return list of all creatures root + */ + protected abstract List<CreatureRoot> prepareCreatureDescriptionsA(); + + private boolean checkCreaturePositions(int initialPosition) { + boolean result = true; + for (Integer creatureOffset : globalCreatureDescriptors.keySet()) { + int positionToTry = initialPosition - creatureOffset; + result = result && checkSpecialCreaturePosition(positionToTry, creatureOffset) && checkCreatureCompactibilityForPosition(globalCreatureDescriptors.get(creatureOffset), positionToTry, creatureOffset == CreatureDescriptor.THIEF_OFFSET); + if (!result) { + break; + } + } + return result; + } + + protected boolean checkSpecialCreaturePosition(int position, Integer creatureOffset) { + return true; + } + + private void addSpecialCreatures(int initialPosition) { + for (Integer creatureOffset : globalCreatureDescriptors.keySet()) { + addSpecialCreature(initialPosition - creatureOffset, globalCreatureDescriptors.get(creatureOffset)); + } + } + +} diff --git a/core/src/cz/nic/tablexia/rules/GameRulesDefinition.java b/core/src/cz/nic/tablexia/rules/GameRulesDefinition.java new file mode 100644 index 000000000..502c82b0a --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/GameRulesDefinition.java @@ -0,0 +1,212 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.badlogic.gdx.utils.reflect.ClassReflection; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.difficulty.GameDifficulty; +import cz.nic.tablexia.rules.easy.BC_1_BCRule; +import cz.nic.tablexia.rules.easy.Bb_0_BbRule; +import cz.nic.tablexia.rules.easy.Bt_0_BtRule; +import cz.nic.tablexia.rules.easy.CACARule; +import cz.nic.tablexia.rules.easy.CACCRule; +import cz.nic.tablexia.rules.easy.CA_0_CC_0_TRule; +import cz.nic.tablexia.rules.easy.CCCCRule; +import cz.nic.tablexia.rules.easy.CC_0_CC_0_TRule; +import cz.nic.tablexia.rules.easy.CC_0_notCCRule; +import cz.nic.tablexia.rules.hard.Bb_1_BbRule; +import cz.nic.tablexia.rules.hard.Bt_1_BtRule; +import cz.nic.tablexia.rules.hard.CCCCnotCCRule; +import cz.nic.tablexia.rules.hard.CC_0_CC_0_CCRule; +import cz.nic.tablexia.rules.hard.CC_0_notCA_0_TRule; +import cz.nic.tablexia.rules.hard.CC_0_notCC_0_TRule; +import cz.nic.tablexia.rules.hard.CC_2_CCRule; +import cz.nic.tablexia.rules.medium.BC_2_BCRule; +import cz.nic.tablexia.rules.medium.CA_1_CCRule; +import cz.nic.tablexia.rules.medium.CCCCCCRule; +import cz.nic.tablexia.rules.medium.CC_1_CCRule; +import cz.nic.tablexia.rules.medium.CC_1_notCARule; +import cz.nic.tablexia.rules.medium.CC_1_notCCRule; +import cz.nic.tablexia.util.Log; + + +/** + * Game rules definition enum + * + * @author Matyáš Latner + */ +public enum GameRulesDefinition { + + /* + * Generované atributy: + * A - náhodný atribut (generovaný pro každou postavu zlášť) + * B - náhodný atribut stejný u skupiny (generuje se zvlášť pro každou skupinu postav, která obsahuje zlodÄ›je a postavy, které identifikujà zlodÄ›je --> v rámci této skupiny je atribut stejný) + * C - stejný atribut (generovaný jen na zaÄátku hry a pro vÅ¡echny postavy v rámci jedné hry je stejný --> vygenerovaný atribut je souÄástà textu pravidla) + * + * Konstantnà atributy pro komponenty: + * t - skupina komponent TOP + * b - skupina komponent BOTTOM + * + * + * + * + * Gramatika pro sestavovánà pravidel: + * + * s --> w + * w --> gx + * x --> e | w | y + * y --> _n_w | _n_T + * n --> 0, 1, 2, ... + * g --> CA | notCA + * C --> A | B | C (barva komponenty) + * A --> A | B | C | t | b (komponenta) + * + * + * + * + * Ukázka pravidla: "1.1 Pokud po ÄlovÄ›ku, který má na sobÄ› nÄ›co zeleného, pÅ™icházà ÄlovÄ›k s hnÄ›dými vlasy, tak za nÃm v poÅ™adà je zlodÄ›j." + * + * + * barva atributu + * \ + * \ typ komponenty + * \ / + * CA_0_CC_0_T <--- poslednà postava (zlodÄ›j je vždy poslednà postava) + * / \ \ + * / \ druhá postava + * / \ + * / poÄet náhodných postav mezi prvnà a druhou postavou + * / + * prvnà postava + * + * + * C -> stejná barva celou hru ("má na sobÄ› nÄ›co zeleného") --> barva se generuje jednou na zaÄátku hry + * \ + * \ A -> náhodnÄ› vygenerovaná komponenta zlášť pro každou postavu ("má na sobÄ› nÄ›co zeleného") --> každá postava může mÃt jinou komponentu + * \ / + * CA_0_CC_0_T <--- T -> zlodÄ›j namá urÄeno jak bude vypadat, jen poÅ™adà ("tak za nÃm v poÅ™adà je zlodÄ›j") + * / \ + * / C -> stejná komponenta po celou hru ("pÅ™icházà ÄlovÄ›k s hnÄ›dými vlasy") --> komponenta se generuje jednou na zaÄátku hry + * / + * C -> stejná barva celou hru ("pÅ™icházà ÄlovÄ›k s hnÄ›dými vlasy") --> barva se generuje jednou na zaÄátku hry + */ + //TODO use string resources + CA_0_CC_0_T(GameDifficulty.EASY, CA_0_CC_0_TRule.class, 1), + CC_0_CC_0_T(GameDifficulty.EASY, CC_0_CC_0_TRule.class, 1), + CCCC(GameDifficulty.EASY, CCCCRule.class, 1), + CACC(GameDifficulty.EASY, CACCRule.class, 1), + CACA(GameDifficulty.EASY, CACARule.class, 1), + Bt_0_Bt(GameDifficulty.EASY, Bt_0_BtRule.class, 1), + Bb_0_Bb(GameDifficulty.EASY, Bb_0_BbRule.class, 1), + BC_1_BC(GameDifficulty.EASY, BC_1_BCRule.class, 1), + CC_0_notCC(GameDifficulty.EASY, CC_0_notCCRule.class, 1), + + CC_1_CC(GameDifficulty.MEDIUM, CC_1_CCRule.class, 1), + CA_1_CC(GameDifficulty.MEDIUM, CA_1_CCRule.class, 1), + BC_2_BC(GameDifficulty.MEDIUM, BC_2_BCRule.class, 1), + CC_1_notCC(GameDifficulty.MEDIUM, CC_1_notCCRule.class, 1), + CC_1_notCA(GameDifficulty.MEDIUM, CC_1_notCARule.class, 1), + CCCCCC(GameDifficulty.MEDIUM, CCCCCCRule.class, 1), + + CC_2_CC(GameDifficulty.HARD, CC_2_CCRule.class, 1), + CC_0_notCC_0_T(GameDifficulty.HARD, CC_0_notCC_0_TRule.class, 1), + CC_0_notCA_0_T(GameDifficulty.HARD, CC_0_notCA_0_TRule.class, 1), + CC_0_CC_0_CC(GameDifficulty.HARD, CC_0_CC_0_CCRule.class, 1), + CCCCnotCC(GameDifficulty.HARD, CCCCnotCCRule.class, 1), + Bt_1_Bt(GameDifficulty.HARD, Bt_1_BtRule.class, 1), + Bb_1_Bb(GameDifficulty.HARD, Bb_1_BbRule.class, 1); + + private Class<? extends GameRule> gameRuleClass; +// private int gameRuleStringId; + private GameDifficulty difficulty; + + private GameRulesDefinition(GameDifficulty difficulty, Class<? extends GameRule> gameRuleClass, int gameRuleStringId) { + this.difficulty = difficulty; + this.gameRuleClass = gameRuleClass; +// this.gameRuleStringId = gameRuleStringId; + } + + /** + * Returns difficulty for rule + * + * @return rule difficulty + */ + public GameDifficulty getDifficulty() { + return difficulty; + } + + /** + * Returns game rule class + * + * @return rule class + */ + public Class<? extends GameRule> getGameRuleClass() { + return gameRuleClass; + } + + /** + * Returns game rule text + * + * @return rule text + */ + public String getRuleText() { +// return context.getString(gameRuleStringId); + return "POKUS"; + } + + /** + * Returns new instance of game rule class + * + * @return new instance of game rule class + */ + public GameRule getGameRuleInstance(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + try { + return (GameRule)ClassReflection.getConstructor(getGameRuleClass(), RandomAccess.class, int.class, int.class).newInstance(randomAccess, numberOfCreatures, numberOfThieves); +// return getGameRuleClass().getConstructor(Context.class, RandomAccess.class, VertexBufferObjectManager.class, int.class, int.class).newInstance(context, randomAccess, vertexBufferObjectManager, numberOfCreatures, numberOfThieves); + } catch (Exception e) { + Log.err(getClass(), "Cannot create instance of game rule: " + getGameRuleClass(), e); + } + return null; + } + + /** + * Returns random game rule for difficulty in parameter + * + * @return random game rule for difficulty + */ + public static GameRulesDefinition getRandomGameRuleForDifficulty(GameDifficulty difficulty, Random random) { + List<GameRulesDefinition> gameRules = new ArrayList<GameRulesDefinition>(); + for (GameRulesDefinition gameRuleDefinition : GameRulesDefinition.values()) { + if (gameRuleDefinition.getDifficulty() == difficulty) { + gameRules.add(gameRuleDefinition); + } + } + if (gameRules.size() > 0) { + return gameRules.get(random.nextInt(gameRules.size())); + } + return null; + } + + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/BC_1_BCRule.java b/core/src/cz/nic/tablexia/rules/easy/BC_1_BCRule.java new file mode 100644 index 000000000..9c8883a4b --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/BC_1_BCRule.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.creature.attribute.Attribute; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class BC_1_BCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 3; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected Integer T1_OFFSET = Integer.valueOf(2); + private AttributeDescription commonAttribute; + + public BC_1_BCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + public BC_1_BCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves, int groupSize) { + super(randomAccess, numberOfCreatures, numberOfThieves, groupSize); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0), true) + }; + } + + @Override + protected boolean checkSpecialCreaturePosition(int position, Integer creatureOffset) { + if (creatureOffset == T1_OFFSET) { + CreatureDescriptor creatureToCheck = specialCreatures.get(position - T1_OFFSET); + if (creatureToCheck != null && creatureToCheck.isThief() && creatureToCheck.getDescriptions().get(0).equals(getGlobalCreatureDescriptor(creatureOffset).getDescriptions().get(0))) { + return false; + } + } + + if (creatureOffset == T0_OFFSET) { + CreatureDescriptor creatureToCheck = specialCreatures.get(position + T1_OFFSET); + if (creatureToCheck != null && !creatureToCheck.isThief() && creatureToCheck.getDescriptions().get(0).equals(getGlobalCreatureDescriptor(creatureOffset).getDescriptions().get(0))) { + return false; + } + } + + return true; + } + + @Override + protected void prepareCreatureDescriptionsC() { + commonAttribute = getRandomAttributeDescription(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition()); + + addGlobalCreatureDescriptor(T1_OFFSET, new CreatureDescriptor()); + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + } + + @Override + protected void prepareCreatureDescriptionsB() { + AttributeColor commonColor = Attribute.getRandomAvalibleColorFromAttributeClass(commonAttribute.getAttributeClass(), getRandomAccess()); + + getGlobalCreatureDescriptor(T0_OFFSET).clearDescriptions().addDescription(new AttributeDescription(commonColor, null, commonAttribute.getAttributeClass())); + getGlobalCreatureDescriptor(T1_OFFSET).clearDescriptions().addDescription(new AttributeDescription(commonColor, null, commonAttribute.getAttributeClass())); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + for (int i = 0; i < numberOfCreatures; i++) { + + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, null, getRandomAccess())); + } else { + CreatureDescriptor creatureDescriptorToBan = new CreatureDescriptor(); + creatureDescriptorToBan.disableGenderCompatibilityCheck(); + + CreatureDescriptor nextSpecialCreature = specialCreatures.get(i + T1_OFFSET); + if (nextSpecialCreature != null) { + creatureDescriptorToBan.addDescription(nextSpecialCreature.getDescriptions().get(0)); + } + + int lastPosition = i - T1_OFFSET; + if (lastPosition >= 0) { + CreatureRoot lastCreature = creatures.get(lastPosition); + if (lastCreature != null) { + Attribute attributeToBan = lastCreature.getAttributeForType(AttributeDescription.getGenericType(commonAttribute.getAttributeClass())); + if (attributeToBan != null) { + creatureDescriptorToBan.addDescription(attributeToBan.getAttributeDescription()); + } + } + } + + creatures.add(CreatureFactory.getInstance().generateCreature(null, creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/Bb_0_BbRule.java b/core/src/cz/nic/tablexia/rules/easy/Bb_0_BbRule.java new file mode 100644 index 000000000..c892b25ab --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/Bb_0_BbRule.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.attribute.clothing.bottom.BottomAttribute; + +/** + * + * @author Matyáš Latner + */ +public class Bb_0_BbRule extends Bt_0_BtRule { + + public Bb_0_BbRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves); + } + + @Override + protected void prepareCreatureDescriptionsC() { + super.prepareCreatureDescriptionsC(); + attributeClass = BottomAttribute.class; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/Bt_0_BtRule.java b/core/src/cz/nic/tablexia/rules/easy/Bt_0_BtRule.java new file mode 100644 index 000000000..0783fe686 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/Bt_0_BtRule.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.creature.attribute.Attribute; +import cz.nic.tablexia.creature.attribute.clothing.top.TopAttribute; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class Bt_0_BtRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 2; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected Integer T1_OFFSET = Integer.valueOf(1); + + protected Class<? extends Attribute> attributeClass; + + public Bt_0_BtRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + public Bt_0_BtRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves, int groupSize) { + super(randomAccess, numberOfCreatures, numberOfThieves, groupSize); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeName(attributeClass, false) + }; + } + + @Override + protected boolean checkSpecialCreaturePosition(int positionToTry, Integer creatureOffset) { + if (creatureOffset == T1_OFFSET) { + CreatureDescriptor creatureToCheck = specialCreatures.get(positionToTry - T1_OFFSET); + if (creatureToCheck != null && creatureToCheck.isThief() && creatureToCheck.getDescriptions().get(0).equals(getGlobalCreatureDescriptor(creatureOffset).getDescriptions().get(0))) { + return false; + } + } + + if (creatureOffset == T0_OFFSET) { + CreatureDescriptor creatureToCheck = specialCreatures.get(positionToTry + T1_OFFSET); + if (creatureToCheck != null && !creatureToCheck.isThief() && creatureToCheck.getDescriptions().get(0).equals(getGlobalCreatureDescriptor(creatureOffset).getDescriptions().get(0))) { + return false; + } + } + + return true; + } + + @Override + protected void prepareCreatureDescriptionsC() { + addGlobalCreatureDescriptor(T1_OFFSET, new CreatureDescriptor()); + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + attributeClass = TopAttribute.class; + } + + @Override + protected void prepareCreatureDescriptionsB() { + AttributeDescription commonAttributeDescription = CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getAttributeForType(attributeClass).getAttributeDescription(); + + getGlobalCreatureDescriptor(T1_OFFSET).clearDescriptions().addDescription(commonAttributeDescription); + getGlobalCreatureDescriptor(T0_OFFSET).clearDescriptions().addDescription(commonAttributeDescription); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + for (int i = 0; i < numberOfCreatures; i++) { + + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, null, getRandomAccess())); + } else { + CreatureDescriptor creatureDescriptorToBan = new CreatureDescriptor(); + creatureDescriptorToBan.disableGenderCompatibilityCheck(); + + CreatureDescriptor nextSpecialCreature = specialCreatures.get(i + T1_OFFSET); + if (nextSpecialCreature != null) { + creatureDescriptorToBan.addDescription(nextSpecialCreature.getDescriptions().get(0)); + } + + int lastPosition = i - T1_OFFSET; + if (lastPosition >= 0) { + CreatureRoot lastCreature = creatures.get(lastPosition); + if (lastCreature != null) { + Attribute attributeToBan = lastCreature.getAttributeForType(attributeClass); + if (attributeToBan != null) { + creatureDescriptorToBan.addDescription(attributeToBan.getAttributeDescription()); + } + } + } + + creatures.add(CreatureFactory.getInstance().generateCreature(null, creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/CACARule.java b/core/src/cz/nic/tablexia/rules/easy/CACARule.java new file mode 100644 index 000000000..96f880bec --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/CACARule.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.clothing.ClothingAttribute; + +/** + * + * @author Matyáš Latner + */ +public class CACARule extends CCCCRule { + + public CACARule(RandomAccess randomAcces, int numberOfCreatures, int numberOfThieves) { + super(randomAcces, numberOfCreatures, numberOfThieves); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0)), + getAttributeColorName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(1)) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor t0CreatureDescriptor = new CreatureDescriptor(); + AttributeColor t0Attribute1Color = getRandomColorFromGeneratedCreature(BAN_ATTRIBUTES_SET_FOR_GENERATING); + + for (int i = 0; i < GENERATOR_TRY_COUNT; i++) { + AttributeColor t0Attribute2Color = getRandomColorFromGeneratedCreature(BAN_ATTRIBUTES_SET_FOR_GENERATING); + if (t0Attribute1Color != t0Attribute2Color) { + t0CreatureDescriptor.addDescription(new AttributeDescription(t0Attribute1Color, null, ClothingAttribute.class)); + t0CreatureDescriptor.addDescription(new AttributeDescription(t0Attribute2Color, null, ClothingAttribute.class)); + addGlobalCreatureDescriptor(T0_OFFSET, t0CreatureDescriptor); + return; + } + } + + throw new IllegalStateException("Cannot select different color for creature description!"); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/CACCRule.java b/core/src/cz/nic/tablexia/rules/easy/CACCRule.java new file mode 100644 index 000000000..fc43e6e2c --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/CACCRule.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.clothing.ClothingAttribute; + +/** + * + * @author Matyáš Latner + */ +public class CACCRule extends CCCCRule { + + public CACCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves); + } + + @Override + public String[] prepareRuleMessageParameters() { + AttributeDescription t0Description0 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0); + AttributeDescription t0Description1 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(1); + return new String[] { + getAttributeColorName(t0Description1), + getAttributeColorName(t0Description0), + getAttributeName(t0Description0, false), + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor creatureDescriptor = new CreatureDescriptor(); + CreatureDescriptor randomCreatureDescrition = CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(); + + int randomDescriptionPosition1 = getRandomAccess().getRandom().nextInt(randomCreatureDescrition.getDescriptions().size()); + AttributeColor attributeColor = randomCreatureDescrition.getDescriptions().get(randomDescriptionPosition1).getAttributeColor(); + + for (int i = 0; i < GENERATOR_TRY_COUNT; i++) { + AttributeColor randomColor = getRandomColorFromGeneratedCreature(BAN_ATTRIBUTES_SET_FOR_GENERATING); + if (attributeColor != randomColor) { + creatureDescriptor.addDescription(randomCreatureDescrition.getDescriptions().get(randomDescriptionPosition1)); + creatureDescriptor.addDescription(new AttributeDescription(randomColor, null, ClothingAttribute.class)); + addGlobalCreatureDescriptor(T0_OFFSET, creatureDescriptor); + return; + } + } + + throw new IllegalStateException("Cannot select different color for creature description!"); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/CA_0_CC_0_TRule.java b/core/src/cz/nic/tablexia/rules/easy/CA_0_CC_0_TRule.java new file mode 100644 index 000000000..e10c55d6b --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/CA_0_CC_0_TRule.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.clothing.ClothingAttribute; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CA_0_CC_0_TRule extends GameRuleUtility { + + private static final double BAIT_RANDOM_DISTRIBUTION = 0.3; + private static final int GROUP_SIZE = 3; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected static final Integer T1_OFFSET = Integer.valueOf(1); + protected static final Integer T2_OFFSET = Integer.valueOf(2); + + public CA_0_CC_0_TRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0), false), + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + AttributeColor t2CommonAttributeColor = getRandomColorFromGeneratedCreature(BAN_ATTRIBUTES_SET_FOR_GENERATING); + CreatureDescriptor t2CreatureDescriptor = new CreatureDescriptor(); + t2CreatureDescriptor.addDescription(new AttributeDescription(t2CommonAttributeColor, null, ClothingAttribute.class)); + addGlobalCreatureDescriptor(T2_OFFSET, t2CreatureDescriptor); + + addGlobalCreatureDescriptor(T1_OFFSET, getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(), 1)); + + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + CreatureRoot lastCreature = null; + int lastPosition; + // generate random creatures and add thieves and pair creatures to the specific positions + for (int i = 0; i < numberOfCreatures; i++) { + lastPosition = creatures.size() - 1; + if (lastPosition >= 0) { + lastCreature = creatures.get(lastPosition); + } + + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + if (lastCreature != null && lastCreature.hasAttribute(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)) && !creatureDescriptor.containsAttributeDescription(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0))) { + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, getGlobalCreatureDescriptor(T1_OFFSET), getRandomAccess())); + } else { + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, null, getRandomAccess())); + } + } else { + if ((lastCreature != null) && lastCreature.hasAttributes(getGlobalCreatureDescriptor(T2_OFFSET))) { + creatures.add(CreatureFactory.getInstance().generateCreature(null, getGlobalCreatureDescriptor(T1_OFFSET), getRandomAccess())); + } else { + + if(getRandomAccess().getRandom().nextDouble() < BAIT_RANDOM_DISTRIBUTION) { + newBaitCreatureDescription(getGlobalCreatureDescriptor(T2_OFFSET)); + } else { + newBaitCreatureDescription(getGlobalCreatureDescriptor(T1_OFFSET)); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(getBaitCreatureDescriptionRandomly(), null, getRandomAccess())); + } + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/CCCCRule.java b/core/src/cz/nic/tablexia/rules/easy/CCCCRule.java new file mode 100644 index 000000000..0c85ff12f --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/CCCCRule.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CCCCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 1; + protected static final Integer T0_OFFSET = Integer.valueOf(0); + + public CCCCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + @Override + public String[] prepareRuleMessageParameters() { + AttributeDescription t0Description0 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0); + AttributeDescription t0Description1 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(1); + return new String[] { + getAttributeColorName(t0Description0), + getAttributeName(t0Description0, false), + getAttributeColorName(t0Description1), + getAttributeName(t0Description1, false), + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + addGlobalCreatureDescriptor(0, getRandomCreatureDescriptionWithTwoAttributes(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition())); + } + + @Override + public List<CreatureRoot> prepareCreatureDescriptionsA() { + + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + + CreatureDescriptor t0CreatureDescription = getGlobalCreatureDescriptor(T0_OFFSET); + CreatureDescriptor creatureDescriptorToBan1 = new CreatureDescriptor(); + creatureDescriptorToBan1.addDescription(t0CreatureDescription.getDescriptions().get(0)); + CreatureDescriptor creatureDescriptorToBan2 = new CreatureDescriptor(); + creatureDescriptorToBan2.addDescription(t0CreatureDescription.getDescriptions().get(1)); + + for (int i = 0; i < numberOfCreatures; i++) { + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, null, getRandomAccess())); + } else { + + CreatureDescriptor creatureDescriptorToBan = null; + if (getRandomAccess().getRandom().nextBoolean()) { + creatureDescriptorToBan = creatureDescriptorToBan1; + newBaitCreatureDescription(creatureDescriptorToBan2); + } else { + creatureDescriptorToBan = creatureDescriptorToBan2; + newBaitCreatureDescription(creatureDescriptorToBan1); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(getBaitCreatureDescriptionRandomly(), creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/CC_0_CC_0_TRule.java b/core/src/cz/nic/tablexia/rules/easy/CC_0_CC_0_TRule.java new file mode 100644 index 000000000..b27e3022b --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/CC_0_CC_0_TRule.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; + +/** + * + * @author Matyáš Latner + */ +public class CC_0_CC_0_TRule extends CA_0_CC_0_TRule { + + public CC_0_CC_0_TRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0), false), + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + + CreatureDescriptor t2CreatureDescriptor = getRandomCreatureDescriptionWithOneAttribute(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition()); + AttributeDescription t2AttributeDescription = t2CreatureDescriptor.getDescriptions().get(0); + addGlobalCreatureDescriptor(T2_OFFSET, t2CreatureDescriptor); + + BAN_ATTRIBUTES_SET_FOR_GENERATING.addDescription(t2AttributeDescription); + addGlobalCreatureDescriptor(T1_OFFSET, getRandomCreatureDescriptionWithOneAttribute(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition())); + + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/easy/CC_0_notCCRule.java b/core/src/cz/nic/tablexia/rules/easy/CC_0_notCCRule.java new file mode 100644 index 000000000..dda608f47 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/easy/CC_0_notCCRule.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.easy; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CC_0_notCCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 2; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected Integer T1_OFFSET = Integer.valueOf(1); + protected CreatureDescriptor t0CreatureDescriptorToBan; + + public CC_0_notCCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + public CC_0_notCCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves, int groupSize) { + super(randomAccess, numberOfCreatures, numberOfThieves, groupSize); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(t0CreatureDescriptorToBan.getDescriptions().get(0)), + getAttributeName(t0CreatureDescriptorToBan.getDescriptions().get(0), false), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0), false) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + + AttributeDescription t1AttributeDescription = getRandomAttributeDescription(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition()); + CreatureDescriptor t1CreatureDescriptor = new CreatureDescriptor(); + t1CreatureDescriptor.addDescription(t1AttributeDescription); + addGlobalCreatureDescriptor(T1_OFFSET, t1CreatureDescriptor); + + + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + + + CreatureDescriptor t2BannedAttributesForGenerator = new CreatureDescriptor(); + t2BannedAttributesForGenerator.disableGenderCompatibilityCheck(); + t2BannedAttributesForGenerator.addDescriptions(BAN_ATTRIBUTES_SET_FOR_GENERATING.getDescriptions()); + t2BannedAttributesForGenerator.addDescription(t1AttributeDescription); + + AttributeDescription t2AttributeDescription = getRandomAttributeDescription(CreatureFactory.getInstance().generateCreature(null, t2BannedAttributesForGenerator, getRandomAccess()).getCreatureDescrition()); + t0CreatureDescriptorToBan = new CreatureDescriptor(); + t0CreatureDescriptorToBan.addDescription(t2AttributeDescription); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + + AttributeDescription t1AttributeDescription = getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0); + AttributeDescription t0AttributeDescriptionToBan = t0CreatureDescriptorToBan.getDescriptions().get(0); + + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + for (int i = 0; i < numberOfCreatures; i++) { + + CreatureDescriptor creatureDescriptorToForce = new CreatureDescriptor(); + creatureDescriptorToForce.disableGenderCompatibilityCheck(); + CreatureDescriptor creatureDescriptorToBan = new CreatureDescriptor(); + creatureDescriptorToBan.disableGenderCompatibilityCheck(); + + + CreatureRoot lastCreature = null; + int lastPosition = i - T1_OFFSET; + if (lastPosition >= 0) { + lastCreature = creatures.get(lastPosition); + } + + CreatureDescriptor nextSpecialCreature = specialCreatures.get(i + T1_OFFSET); + + + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + if (creatureDescriptor.isThief()) { + + creatureDescriptorToBan.addDescription(t0AttributeDescriptionToBan); + + if (nextSpecialCreature != null && !nextSpecialCreature.isThief() + && !creatureDescriptor.getDescriptions().contains(t1AttributeDescription)) { + + creatureDescriptorToBan.addDescription(t1AttributeDescription); + } + + } + + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, creatureDescriptorToBan, getRandomAccess())); + } else { + + boolean hasNotT0Attribute = true; + boolean hasNotBanT1Attribute = true; + + if (lastCreature != null && lastCreature.hasAttribute(t1AttributeDescription)) { + creatureDescriptorToForce.addDescription(t0AttributeDescriptionToBan); + hasNotT0Attribute = false; + } + + if (nextSpecialCreature != null) { + creatureDescriptorToBan.addDescription(t1AttributeDescription); + hasNotBanT1Attribute = false; + } + + if (hasNotT0Attribute && hasNotBanT1Attribute) { + newBaitCreatureDescription(getGlobalCreatureDescriptor(T1_OFFSET)); + creatureDescriptorToForce.addDescription(getBaitCreatureDescriptionAttributeAtPosition(0)); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptorToForce, creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/Bb_1_BbRule.java b/core/src/cz/nic/tablexia/rules/hard/Bb_1_BbRule.java new file mode 100644 index 000000000..f1e5ab333 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/Bb_1_BbRule.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.attribute.clothing.bottom.BottomAttribute; + +/** + * + * @author Matyáš Latner + */ +public class Bb_1_BbRule extends Bt_1_BtRule { + + public Bb_1_BbRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves); + } + + @Override + protected void prepareCreatureDescriptionsC() { + super.prepareCreatureDescriptionsC(); + attributeClass = BottomAttribute.class; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/Bt_1_BtRule.java b/core/src/cz/nic/tablexia/rules/hard/Bt_1_BtRule.java new file mode 100644 index 000000000..0640db582 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/Bt_1_BtRule.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.rules.easy.Bt_0_BtRule; + +/** + * + * @author Matyáš Latner + */ +public class Bt_1_BtRule extends Bt_0_BtRule { + + private static final int GROUP_SIZE = 3; + + public Bt_1_BtRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + T1_OFFSET = Integer.valueOf(2); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/CCCCnotCCRule.java b/core/src/cz/nic/tablexia/rules/hard/CCCCnotCCRule.java new file mode 100644 index 000000000..7eccc5374 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/CCCCnotCCRule.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.creature.attribute.clothing.headgear.HeadgearAttribute; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CCCCnotCCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 1; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + private AttributeDescription t0AttributeDescriptionToBan; + + public CCCCnotCCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + @Override + public String[] prepareRuleMessageParameters() { + AttributeDescription t0Description0 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0); + AttributeDescription t0Description1 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(1); + return new String[] { + getAttributeColorName(t0Description0), + getAttributeName(t0Description0, false), + getAttributeColorName(t0Description1), + getAttributeName(t0Description1, false), + getAttributeColorName(t0AttributeDescriptionToBan), + getAttributeName(t0AttributeDescriptionToBan, false), + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor creatureDescriptorToForce = new CreatureDescriptor(); + creatureDescriptorToForce.addDescription(new AttributeDescription(null, null, HeadgearAttribute.class)); + CreatureDescriptor creatureDescriptor = getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(creatureDescriptorToForce, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(), 3); + t0AttributeDescriptionToBan = getRandomAttributeDescription(creatureDescriptor); + creatureDescriptor.getDescriptions().remove(t0AttributeDescriptionToBan); + addGlobalCreatureDescriptor(T0_OFFSET, creatureDescriptor); + } + + @Override + public List<CreatureRoot> prepareCreatureDescriptionsA() { + + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + + CreatureDescriptor t0CreatureDescriptionToBan = new CreatureDescriptor(); + t0CreatureDescriptionToBan.addDescription(t0AttributeDescriptionToBan); + + CreatureDescriptor t0CreatureDescription = getGlobalCreatureDescriptor(T0_OFFSET); + CreatureDescriptor creatureDescriptorToBan0 = new CreatureDescriptor(); + creatureDescriptorToBan0.addDescription(t0CreatureDescription.getDescriptions().get(0)); + CreatureDescriptor creatureDescriptorToBan1 = new CreatureDescriptor(); + creatureDescriptorToBan1.addDescription(t0CreatureDescription.getDescriptions().get(1)); + + for (int i = 0; i < numberOfCreatures; i++) { + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, t0CreatureDescriptionToBan, getRandomAccess())); + } else { + CreatureDescriptor baitCreatureDescriptor = new CreatureDescriptor(); + CreatureDescriptor creatureDescriptorToBan = null; + creatureDescriptor = new CreatureDescriptor(); + + switch(getRandomAccess().getRandom().nextInt(3)) { + case 0: + creatureDescriptorToBan = creatureDescriptorToBan0; + + baitCreatureDescriptor.addDescriptions(creatureDescriptorToBan1.getDescriptions()); + break; + case 1: + creatureDescriptorToBan = creatureDescriptorToBan1; + + baitCreatureDescriptor.addDescriptions(creatureDescriptorToBan0.getDescriptions()); + break; + case 2: + creatureDescriptor = t0CreatureDescriptionToBan; + + baitCreatureDescriptor.addDescriptions(t0CreatureDescriptionToBan.getDescriptions()); + baitCreatureDescriptor.addDescriptions(creatureDescriptorToBan0.getDescriptions()); + baitCreatureDescriptor.addDescriptions(creatureDescriptorToBan1.getDescriptions()); + break; + } + + newBaitCreatureDescription(baitCreatureDescriptor); + CreatureDescriptor baitCreatureDescriptionRandomly = getBaitCreatureDescriptionRandomly(); + if (baitCreatureDescriptionRandomly != null) { + creatures.add(CreatureFactory.getInstance().generateCreature(baitCreatureDescriptionRandomly, creatureDescriptorToBan, getRandomAccess())); + } else { + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, creatureDescriptorToBan, getRandomAccess())); + } + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/CC_0_CC_0_CCRule.java b/core/src/cz/nic/tablexia/rules/hard/CC_0_CC_0_CCRule.java new file mode 100644 index 000000000..de19ee6d5 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/CC_0_CC_0_CCRule.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CC_0_CC_0_CCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 3; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected static final Integer T1_OFFSET = Integer.valueOf(1); + protected static final Integer T2_OFFSET = Integer.valueOf(2); + + public CC_0_CC_0_CCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0), false) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor t2CreatureDescriptor = getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(), 1); + addGlobalCreatureDescriptor(T2_OFFSET, t2CreatureDescriptor); + addGlobalCreatureDescriptor(T1_OFFSET, getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(), 1)); + + CreatureDescriptor t0CreatureDescriptorToBan = new CreatureDescriptor(); + t0CreatureDescriptorToBan.disableGenderCompatibilityCheck(); + t0CreatureDescriptorToBan.addDescriptions(BAN_ATTRIBUTES_SET_FOR_GENERATING.getDescriptions()); + t0CreatureDescriptorToBan.addDescription(t2CreatureDescriptor.getDescriptions().get(0)); + + addGlobalCreatureDescriptor(T0_OFFSET, getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(null, t0CreatureDescriptorToBan, getRandomAccess()).getCreatureDescrition(), 1)); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + CreatureRoot l1Creature = null; + CreatureRoot l0Creature = null; + int l1Position; + int l0Position; + // generate random creatures and add thieves and pair creatures to the specific positions + for (int i = 0; i < numberOfCreatures; i++) { + + l1Position = creatures.size() - T2_OFFSET; + if (l1Position >= 0) { + l1Creature = creatures.get(l1Position); + } + + l0Position = creatures.size() - T1_OFFSET; + if (l0Position >= 0) { + l0Creature = creatures.get(l0Position); + } + + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + if (l1Creature != null && l0Creature != null + && l1Creature.hasAttribute(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)) + && l0Creature.hasAttribute(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)) + && !creatureDescriptor.containsCreatureOffset(T0_OFFSET)) { + + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, getGlobalCreatureDescriptor(T0_OFFSET), getRandomAccess())); + } else { + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, null, getRandomAccess())); + } + } else { + if (l1Creature != null && l0Creature != null + && l1Creature.hasAttribute(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)) + && l0Creature.hasAttribute(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0))) { + + creatures.add(CreatureFactory.getInstance().generateCreature(null, getGlobalCreatureDescriptor(T0_OFFSET), getRandomAccess())); + } else { + + if (l0Creature != null && l0Creature.hasAttribute(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0))) { + creatures.add(CreatureFactory.getInstance().generateCreature(getGlobalCreatureDescriptor(T1_OFFSET), null, getRandomAccess())); + } else { + newBaitCreatureDescription(getGlobalCreatureDescriptor(T2_OFFSET)); + creatures.add(CreatureFactory.getInstance().generateCreature(getBaitCreatureDescriptionRandomly(), null, getRandomAccess())); + } + } + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/CC_0_notCA_0_TRule.java b/core/src/cz/nic/tablexia/rules/hard/CC_0_notCA_0_TRule.java new file mode 100644 index 000000000..869b1a5f5 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/CC_0_notCA_0_TRule.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.clothing.ClothingAttribute; + +/** + * + * @author Matyáš Latner + */ +public class CC_0_notCA_0_TRule extends CC_0_notCC_0_TRule { + + public CC_0_notCA_0_TRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(t1CreatureDescriptorToBan.getDescriptions().get(0)), + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + AttributeDescription t2AttributeDescription = getRandomAttributeDescription(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition()); + CreatureDescriptor t2CreatureDescriptor = new CreatureDescriptor(); + t2CreatureDescriptor.addDescription(t2AttributeDescription); + addGlobalCreatureDescriptor(T2_OFFSET, t2CreatureDescriptor); + + + CreatureDescriptor t1BannedAttributesForGenerator = new CreatureDescriptor(); + t1BannedAttributesForGenerator.disableGenderCompatibilityCheck(); + t1BannedAttributesForGenerator.addDescriptions(BAN_ATTRIBUTES_SET_FOR_GENERATING.getDescriptions()); + if (t2AttributeDescription.hasSpecificColor()) { + t1BannedAttributesForGenerator.addDescription(new AttributeDescription(t2AttributeDescription.getAttributeColor(), null, ClothingAttribute.class)); + } + + addGlobalCreatureDescriptor(T1_OFFSET, new CreatureDescriptor()); + AttributeColor t0CommonAttributeColor = getRandomColorFromGeneratedCreature(t1BannedAttributesForGenerator); + t1CreatureDescriptorToBan = new CreatureDescriptor(); + AttributeDescription t1AttributeDescription = new AttributeDescription(t0CommonAttributeColor, null, ClothingAttribute.class); + t1CreatureDescriptorToBan.addDescription(t1AttributeDescription); + + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/CC_0_notCC_0_TRule.java b/core/src/cz/nic/tablexia/rules/hard/CC_0_notCC_0_TRule.java new file mode 100644 index 000000000..aecee06e8 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/CC_0_notCC_0_TRule.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CC_0_notCC_0_TRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 3; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected static final Integer T1_OFFSET = Integer.valueOf(1); + protected static final Integer T2_OFFSET = Integer.valueOf(2); + + CreatureDescriptor t1CreatureDescriptorToBan = new CreatureDescriptor(); + + public CC_0_notCC_0_TRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(t1CreatureDescriptorToBan.getDescriptions().get(0)), + getAttributeName(t1CreatureDescriptorToBan.getDescriptions().get(0), false) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor source = getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(), 2); + + CreatureDescriptor t2CreatureDescriptor = new CreatureDescriptor(); + t2CreatureDescriptor.addDescription(source.getDescriptions().get(0)); + addGlobalCreatureDescriptor(T2_OFFSET, t2CreatureDescriptor); + + addGlobalCreatureDescriptor(T1_OFFSET, new CreatureDescriptor()); + + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + + + AttributeDescription t1AttributeDescription = source.getDescriptions().get(1); + t1CreatureDescriptorToBan = new CreatureDescriptor(); + t1CreatureDescriptorToBan.addDescription(t1AttributeDescription); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + + AttributeDescription t2AttributeDescription = getGlobalCreatureDescriptor(T2_OFFSET).getDescriptions().get(0); + AttributeDescription t1AttributeDescriptionToBan = t1CreatureDescriptorToBan.getDescriptions().get(0); + + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + for (int i = 0; i < numberOfCreatures; i++) { + + CreatureRoot lastCreature = null; + int lastPosition = i - T1_OFFSET; + if (lastPosition >= 0) { + lastCreature = creatures.get(lastPosition); + } + + CreatureDescriptor nextSpecialCreature = specialCreatures.get(i + T1_OFFSET); + + CreatureDescriptor creatureDescriptorToBan = new CreatureDescriptor(); + creatureDescriptorToBan.disableGenderCompatibilityCheck(); + + CreatureDescriptor creatureDescriptorToForce = specialCreatures.get(i); + if (creatureDescriptorToForce != null) { // add special creature + + // Cannot create same condition for T2 ---> T2 and T1 attributes can be incompatible + if (creatureDescriptorToForce.containsCreatureOffset(T0_OFFSET) && !creatureDescriptorToForce.containsCreatureOffset(T1_OFFSET) && lastCreature.getCreatureDescrition().containsAttributeDescription(t2AttributeDescription)) { + creatureDescriptorToForce.addDescription(t1AttributeDescriptionToBan); + } + + if (creatureDescriptorToForce.containsCreatureOffset(T1_OFFSET)) { + creatureDescriptorToBan.addDescription(t1AttributeDescriptionToBan); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptorToForce, creatureDescriptorToBan, getRandomAccess())); + } else { + + boolean hasNotBanT2Attribute = true; + boolean nextCreatureIsSpecial = true; + + creatureDescriptorToForce = new CreatureDescriptor(); + + if (lastCreature != null && lastCreature.hasAttribute(t2AttributeDescription)) { + creatureDescriptorToForce.addDescription(t1AttributeDescriptionToBan); + hasNotBanT2Attribute = false; + } + + // next special creature is T2 -> T2 will can be generated without T1 attribute + if (nextSpecialCreature != null) { + creatureDescriptorToBan.addDescription(t2AttributeDescription); + nextCreatureIsSpecial = false; + } + + if (nextCreatureIsSpecial && hasNotBanT2Attribute) { + newBaitCreatureDescription(getGlobalCreatureDescriptor(T2_OFFSET)); + creatureDescriptorToForce.addDescription(getBaitCreatureDescriptionAttributeAtPosition(0)); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptorToForce, creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/hard/CC_2_CCRule.java b/core/src/cz/nic/tablexia/rules/hard/CC_2_CCRule.java new file mode 100644 index 000000000..9651d5320 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/hard/CC_2_CCRule.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.hard; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.rules.medium.CC_1_CCRule; + +/** + * + * @author Matyáš Latner + */ +public class CC_2_CCRule extends CC_1_CCRule { + + private static final int GROUP_SIZE = 4; + + public CC_2_CCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + T1_OFFSET = Integer.valueOf(3); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/medium/BC_2_BCRule.java b/core/src/cz/nic/tablexia/rules/medium/BC_2_BCRule.java new file mode 100644 index 000000000..c8e6481ca --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/medium/BC_2_BCRule.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.medium; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.rules.easy.BC_1_BCRule; + +/** + * + * @author Matyáš Latner + */ +public class BC_2_BCRule extends BC_1_BCRule { + + private static final int GROUP_SIZE = 4; + + public BC_2_BCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + super.T1_OFFSET = Integer.valueOf(3); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/medium/CA_1_CCRule.java b/core/src/cz/nic/tablexia/rules/medium/CA_1_CCRule.java new file mode 100644 index 000000000..6d7fa0e84 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/medium/CA_1_CCRule.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.medium; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.clothing.ClothingAttribute; + +/** + * + * @author Matyáš Latner + */ +public class CA_1_CCRule extends CC_1_CCRule { + + public CA_1_CCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + AttributeColor t1CommonAttributeColor = getRandomColorFromGeneratedCreature(BAN_ATTRIBUTES_SET_FOR_GENERATING); + CreatureDescriptor t1CreatureDescriptor = new CreatureDescriptor(); + t1CreatureDescriptor.addDescription(new AttributeDescription(t1CommonAttributeColor, null, ClothingAttribute.class)); + addGlobalCreatureDescriptor(T1_OFFSET, t1CreatureDescriptor); + + CreatureDescriptor t0CreatureDescriptor = getRandomCreatureDescriptionWithOneAttribute(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition()); + addGlobalCreatureDescriptor(T0_OFFSET, t0CreatureDescriptor); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/medium/CCCCCCRule.java b/core/src/cz/nic/tablexia/rules/medium/CCCCCCRule.java new file mode 100644 index 000000000..0a73ed666 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/medium/CCCCCCRule.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.medium; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.creature.attribute.clothing.headgear.HeadgearAttribute; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CCCCCCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 1; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + + public CCCCCCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + @Override + public String[] prepareRuleMessageParameters() { + AttributeDescription t0Description0 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0); + AttributeDescription t0Description1 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(1); + AttributeDescription t0Description2 = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(2); + return new String[] { + getAttributeColorName(t0Description0), + getAttributeName(t0Description0, false), + getAttributeColorName(t0Description1), + getAttributeName(t0Description1, false), + getAttributeColorName(t0Description2), + getAttributeName(t0Description2, false) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor creatureDescriptorToForce = new CreatureDescriptor(); + creatureDescriptorToForce.addDescription(new AttributeDescription(null, null, HeadgearAttribute.class)); + addGlobalCreatureDescriptor(T0_OFFSET, getRandomCreatureDescriptionWithNAttributes(CreatureFactory.getInstance().generateCreature(creatureDescriptorToForce, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition(), 3)); + } + + @Override + public List<CreatureRoot> prepareCreatureDescriptionsA() { + + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + + CreatureDescriptor t0CreatureDescription = getGlobalCreatureDescriptor(T0_OFFSET); + CreatureDescriptor creatureDescriptorToBan0 = new CreatureDescriptor(); + AttributeDescription t0AttributeDescription0 = t0CreatureDescription.getDescriptions().get(0); + creatureDescriptorToBan0.addDescription(t0AttributeDescription0); + CreatureDescriptor creatureDescriptorToBan1 = new CreatureDescriptor(); + AttributeDescription t0AttributeDescription1 = t0CreatureDescription.getDescriptions().get(1); + creatureDescriptorToBan1.addDescription(t0AttributeDescription1); + CreatureDescriptor creatureDescriptorToBan2 = new CreatureDescriptor(); + AttributeDescription t0AttributeDescription2 = t0CreatureDescription.getDescriptions().get(2); + creatureDescriptorToBan2.addDescription(t0AttributeDescription2); + + for (int i = 0; i < numberOfCreatures; i++) { + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { // add special creature + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, null, getRandomAccess())); + } else { + CreatureDescriptor creatureDescriptorToBan = null; + CreatureDescriptor baitCreatureDescriptor = new CreatureDescriptor(); + switch(getRandomAccess().getRandom().nextInt(3)) { + case 0: + creatureDescriptorToBan = creatureDescriptorToBan0; + baitCreatureDescriptor.addDescription(t0AttributeDescription1); + baitCreatureDescriptor.addDescription(t0AttributeDescription2); + break; + case 1: + creatureDescriptorToBan = creatureDescriptorToBan1; + baitCreatureDescriptor.addDescription(t0AttributeDescription0); + baitCreatureDescriptor.addDescription(t0AttributeDescription2); + break; + case 2: + creatureDescriptorToBan = creatureDescriptorToBan2; + baitCreatureDescriptor.addDescription(t0AttributeDescription0); + baitCreatureDescriptor.addDescription(t0AttributeDescription1); + break; + } + newBaitCreatureDescription(baitCreatureDescriptor); + creatures.add(CreatureFactory.getInstance().generateCreature(getBaitCreatureDescriptionRandomly(), creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/medium/CC_1_CCRule.java b/core/src/cz/nic/tablexia/rules/medium/CC_1_CCRule.java new file mode 100644 index 000000000..d0982c089 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/medium/CC_1_CCRule.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.medium; + +import java.util.ArrayList; +import java.util.List; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.CreatureRoot; +import cz.nic.tablexia.rules.GameRuleUtility; + +/** + * + * @author Matyáš Latner + */ +public class CC_1_CCRule extends GameRuleUtility { + + private static final int GROUP_SIZE = 3; + protected static final Integer T0_OFFSET = CreatureDescriptor.THIEF_OFFSET; + protected Integer T1_OFFSET = Integer.valueOf(2); + + public CC_1_CCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + } + + public CC_1_CCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves, int creatureNumber) { + super(randomAccess, numberOfCreatures, numberOfThieves, creatureNumber); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0), false), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0), false) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + CreatureDescriptor t1CreatureDescriptor = getRandomCreatureDescriptionWithOneAttribute(CreatureFactory.getInstance().generateCreature(null, BAN_ATTRIBUTES_SET_FOR_GENERATING, getRandomAccess()).getCreatureDescrition()); + addGlobalCreatureDescriptor(T1_OFFSET, t1CreatureDescriptor); + + CreatureDescriptor creatureDescriptorToBan = new CreatureDescriptor(); + creatureDescriptorToBan.disableGenderCompatibilityCheck(); + creatureDescriptorToBan.addDescriptions(BAN_ATTRIBUTES_SET_FOR_GENERATING.getDescriptions()); + creatureDescriptorToBan.addDescriptions(t1CreatureDescriptor.getDescriptions()); + + CreatureDescriptor t0CreatureDescriptor = getRandomCreatureDescriptionWithOneAttribute(CreatureFactory.getInstance().generateCreature(null, creatureDescriptorToBan, getRandomAccess()).getCreatureDescrition()); + addGlobalCreatureDescriptor(T0_OFFSET, t0CreatureDescriptor); + } + + @Override + protected List<CreatureRoot> prepareCreatureDescriptionsA() { + + AttributeDescription t1AttributeDescription = getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0); + AttributeDescription t0AttributeDescription = getGlobalCreatureDescriptor(T0_OFFSET).getDescriptions().get(0); + + List<CreatureRoot> creatures = new ArrayList<CreatureRoot>(); + for (int i = 0; i < numberOfCreatures; i++) { + + CreatureDescriptor creatureDescriptorToBan = new CreatureDescriptor(); + creatureDescriptorToBan.disableGenderCompatibilityCheck(); + + CreatureRoot lastCreature = null; + int lastPosition = i - T1_OFFSET; + if (lastPosition >= 0) { + lastCreature = creatures.get(lastPosition); + } + + CreatureDescriptor creatureDescriptor = specialCreatures.get(i); + if (creatureDescriptor != null) { + + // SPECIAL CREATURE + + if (!creatureDescriptor.isThief() && lastCreature != null && lastCreature.hasAttribute(t1AttributeDescription)) { + // T1 SPECIAL CREATURE + creatureDescriptorToBan.addDescription(t0AttributeDescription); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(creatureDescriptor, creatureDescriptorToBan, getRandomAccess())); + } else { + + // RANDOM CREATURE + + boolean lastCreatureHasT1Attribute = lastCreature != null && lastCreature.hasAttribute(t1AttributeDescription); + if (lastCreatureHasT1Attribute) { + creatureDescriptorToBan.addDescription(t0AttributeDescription); + } + + // BAIT ATTRIBUTE + if (getRandomAccess().getRandom().nextBoolean() || lastCreatureHasT1Attribute) { + newBaitCreatureDescriptionFromAttribute(t1AttributeDescription); + } else { + newBaitCreatureDescriptionFromAttribute(t0AttributeDescription); + } + + creatures.add(CreatureFactory.getInstance().generateCreature(getBaitCreatureDescriptionRandomly(), creatureDescriptorToBan, getRandomAccess())); + } + } + + return creatures; + } + +} diff --git a/core/src/cz/nic/tablexia/rules/medium/CC_1_notCARule.java b/core/src/cz/nic/tablexia/rules/medium/CC_1_notCARule.java new file mode 100644 index 000000000..6fa6f7601 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/medium/CC_1_notCARule.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.medium; + +import cz.nic.tablexia.AttributeDescription; +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.creature.CreatureDescriptor; +import cz.nic.tablexia.creature.CreatureFactory; +import cz.nic.tablexia.creature.attribute.Attribute.AttributeColor; +import cz.nic.tablexia.creature.attribute.clothing.ClothingAttribute; +import cz.nic.tablexia.rules.easy.CC_0_notCCRule; + +/** + * + * @author Matyáš Latner + */ +public class CC_1_notCARule extends CC_0_notCCRule { + + private static final int GROUP_SIZE = 3; + + public CC_1_notCARule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + T1_OFFSET = Integer.valueOf(2); + } + + @Override + public String[] prepareRuleMessageParameters() { + return new String[] { + getAttributeColorName(t0CreatureDescriptorToBan.getDescriptions().get(0)), + getAttributeColorName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0)), + getAttributeName(getGlobalCreatureDescriptor(T1_OFFSET).getDescriptions().get(0), false) + }; + } + + @Override + protected void prepareCreatureDescriptionsC() { + + addGlobalCreatureDescriptor(T0_OFFSET, new CreatureDescriptor()); + + AttributeColor t0CommonAttributeColor = getRandomColorFromGeneratedCreature(BAN_ATTRIBUTES_SET_FOR_GENERATING); + t0CreatureDescriptorToBan = new CreatureDescriptor(); + AttributeDescription t0AttributeDescription = new AttributeDescription(t0CommonAttributeColor, null, ClothingAttribute.class); + t0CreatureDescriptorToBan.addDescription(t0AttributeDescription); + + + CreatureDescriptor t1BannedAttributesForGenerator = new CreatureDescriptor(); + t1BannedAttributesForGenerator.disableGenderCompatibilityCheck(); + t1BannedAttributesForGenerator.addDescriptions(BAN_ATTRIBUTES_SET_FOR_GENERATING.getDescriptions()); + t1BannedAttributesForGenerator.addDescription(t0AttributeDescription); + + AttributeDescription t1AttributeDescription = getRandomAttributeDescription(CreatureFactory.getInstance().generateCreature(null, t1BannedAttributesForGenerator, getRandomAccess()).getCreatureDescrition()); + CreatureDescriptor t1CreatureDescriptor = new CreatureDescriptor(); + t1CreatureDescriptor.addDescription(t1AttributeDescription); + addGlobalCreatureDescriptor(T1_OFFSET, t1CreatureDescriptor); + } + +} diff --git a/core/src/cz/nic/tablexia/rules/medium/CC_1_notCCRule.java b/core/src/cz/nic/tablexia/rules/medium/CC_1_notCCRule.java new file mode 100644 index 000000000..d3a070108 --- /dev/null +++ b/core/src/cz/nic/tablexia/rules/medium/CC_1_notCCRule.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Tablexia + * + * Copyright (C) 2013 CZ NIC z.s.p.o. <podpora at nic dot cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + ******************************************************************************/ +package cz.nic.tablexia.rules.medium; + +import cz.nic.tablexia.common.RandomAccess; +import cz.nic.tablexia.rules.easy.CC_0_notCCRule; + +/** + * + * @author Matyáš Latner + */ +public class CC_1_notCCRule extends CC_0_notCCRule { + + private static final int GROUP_SIZE = 3; + + public CC_1_notCCRule(RandomAccess randomAccess, int numberOfCreatures, int numberOfThieves) { + super(randomAccess, numberOfCreatures, numberOfThieves, GROUP_SIZE); + T1_OFFSET = Integer.valueOf(2); + } + +} diff --git a/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java b/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java index 0406619a7..786b5017d 100644 --- a/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java +++ b/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java @@ -7,6 +7,8 @@ import cz.nic.tablexia.TablexiaLibGDX; public class DesktopLauncher { public static void main (String[] arg) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); + config.width = 1280; + config.height = 800; new LwjglApplication(new TablexiaLibGDX(), config); } } diff --git a/html/src/cz/nic/tablexia/GdxDefinition.gwt.xml b/html/src/cz/nic/tablexia/GdxDefinition.gwt.xml index 7b654cd16..7cf8cb092 100644 --- a/html/src/cz/nic/tablexia/GdxDefinition.gwt.xml +++ b/html/src/cz/nic/tablexia/GdxDefinition.gwt.xml @@ -6,6 +6,10 @@ <inherits name='TablexiaLibGDX' /> <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.creature.attribute" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.rules.easy" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.rules.medium" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.rules.hard" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.common.RandomAccess" /> <entry-point class='cz.nic.tablexia.client.HtmlLauncher' /> diff --git a/html/src/cz/nic/tablexia/GdxDefinitionSuperdev.gwt.xml b/html/src/cz/nic/tablexia/GdxDefinitionSuperdev.gwt.xml index 72da7ba33..183aad47f 100644 --- a/html/src/cz/nic/tablexia/GdxDefinitionSuperdev.gwt.xml +++ b/html/src/cz/nic/tablexia/GdxDefinitionSuperdev.gwt.xml @@ -6,6 +6,10 @@ <inherits name='cz.nic.tablexia.GdxDefinition' /> <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.creature.attribute" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.rules.easy" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.rules.medium" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.rules.hard" /> + <extend-configuration-property name="gdx.reflect.include" value="cz.nic.tablexia.common.RandomAccess" /> <collapse-all-properties /> -- GitLab