From b179dca37fb5a8854d24b366f3a52ab7052eb9a4 Mon Sep 17 00:00:00 2001 From: Adrien Fryson <adrien.fryson@outlook.com> Date: Mon, 17 Mar 2025 21:51:26 +0100 Subject: [PATCH] doc, authentification cookies, fixes --- MCD.png | Bin 0 -> 58758 bytes documentation.md | 21 +++++++++- sae/WEB-INF/src/controleur/Accueil.java | 4 +- sae/WEB-INF/src/controleur/Auth.java | 39 ++++++++++++++++++ sae/WEB-INF/src/controleur/CreerFil.java | 8 ++-- sae/WEB-INF/src/controleur/DeleteFil.java | 3 +- sae/WEB-INF/src/controleur/DeleteMessage.java | 6 +-- .../src/controleur/EnvoyerMessage.java | 6 +-- sae/WEB-INF/src/controleur/Fil.java | 3 +- sae/WEB-INF/src/controleur/GetFils.java | 3 +- sae/WEB-INF/src/controleur/Like.java | 3 +- sae/WEB-INF/src/controleur/ListerFil.java | 3 +- sae/WEB-INF/src/controleur/Login.java | 11 ++++- sae/WEB-INF/src/controleur/Logout.java | 10 +++++ sae/WEB-INF/src/controleur/MenuFil.java | 3 +- sae/WEB-INF/src/controleur/ModifierFil.java | 3 +- sae/WEB-INF/src/controleur/Parametre.java | 16 +++++-- sae/WEB-INF/src/controleur/Register.java | 14 ++++++- sae/WEB-INF/src/controleur/SuivreFil.java | 3 +- sae/WEB-INF/src/modele/GenerateToken.java | 16 +++++++ sae/WEB-INF/src/modele/Utilisateur.java | 12 +++++- sae/WEB-INF/src/modele/UtilisateurDao.java | 37 +++++++++++++++-- sae/WEB-INF/vue/creerFil.jsp | 4 -- sae/WEB-INF/vue/login.jsp | 6 +++ sae/WEB-INF/vue/parametre.jsp | 4 +- sae/WEB-INF/vue/register.jsp | 4 ++ script.sql | 9 ++-- 27 files changed, 198 insertions(+), 53 deletions(-) create mode 100644 MCD.png create mode 100644 sae/WEB-INF/src/controleur/Auth.java create mode 100644 sae/WEB-INF/src/modele/GenerateToken.java diff --git a/MCD.png b/MCD.png new file mode 100644 index 0000000000000000000000000000000000000000..aaea7d9bfa73d7656dc306a42810c631ce4c8409 GIT binary patch literal 58758 zcmeAS@N?(olHy`uVBq!ia0y~yU{YgXVEoU)#=yXkEG}llz~C-c;u=wsTalKTlgglK z><nS48X08d7ni6SyQmr&B^DIurDP_i7bWHv>*b}Es2Ulm8W|*}r{+Nw_~ut-=Hw)* z8o8P38K@c=X!s^3XXcgU7iXv%JE<BOc;=O)=BOGO_$DT+8X5Qps~Q<Zs2Uj<8t56C zLR1u$sTw;P8k^}EXsQ|+xThv(=c^jIfs_~+8W^e?8MtK@rKaUqs2aI}RY9CkoSc}G z3UQ+$L?kJ{C?&NBB4hv&DoZUY&dkq)h#8sb8R~)68oR0*II0?foU3Z=4E3I>kwIQ! zF4V|?#Pn2Muv#O7%oK=zi%=8KEEAu=Vn-)~%0lCmRO2uckTuAr!OYC9a4$+M$neci z0ee2B0%C-rkr7ynkwHo&M8v`nYD;<%%pN3x;LIwhgAAcQN-xb!NiBxxg(@t`&(A5z zEI<`Z&d<wBO@_u1RAFLKQGPk9vb6jhsPCX^3KG*{HiG<SWB?Kf#t3VWXn1ByNe09v z7N$_=fy6yhGt)C*HX9m1WpWc?ilG9<8Hp+R<q-W~A<S@ug=SHHeu*kBX_%ti3g^@u zP)dV^BiK-otQ+Zi;h|9kPw12w=UEt$6IPa*lwo2NQe+zHnwyts2}@pOi8-avAP+6c z%*iZHEJ-abf&_kXNhK_i7nf(|<|O8&sv0|`<>!?ILuCw9jh&J+GILUV5-amdL7`q; zl9-$g<2hyI7iCuE=anSps2aN%sv0{Lmn0UIK+}~mNH;=7Fi5AWu?tAFD784VDm5Sx z>VJ?<WFg-~P>Mz<^hpF47$AY<{G6P`g5u01u**Rja}$fwGxMDCOG@%{p~jbIWR|1` z7bGTwd|qCZSfFa`lu?okb0oy~1u)xHjf|iXQkGg&k_xgKCWJp#fMVYOT(G&P=I5rC z6jiDk89=ogLn9QL5#b579FeRIO`vKrkdrhlttUdWQaapdP|>JrL^!#r8o5DJD}LvL zN@TP|jWs11LBb0uC8-*j<&>xzJEdfnsT!H3gP1U(QgneNm_TZ7VrC9ZnW~W+Tmnf9 zL$|7t8x~8j2qhK4>_IXPi#jBsy!>3E)xs2#VNGs+iA!ogVsUXQ%n(|7DkZTb)ibX+ zxhS)s1XMRcV+!3$P+CID{w1juphzq(Day}Ib<WSp2UT==`H=D;Gbaa4C^0899aQb* zq^5zifwE0za$=4nR5&*?B?Xi{or()UwRO4=Sec6nsC<Bk1Z6_XaF9@bS!z*Q4!Eq& z$V^E|%~LgYD#*{wD*<N!QzunZCj(U@X9GP`RZ|yLBWG1pCqo3^)CH`(sKhxxuehWr zF%#T!NKGs*DNh9z8cs#|C5a`8km3SVfRJ1^V9gU$EHI!Y1gyXySU`YE9Z>WQo&v%Y zqkwSB%yCI|$t+GTEe5xcz|A_O^fp@EfMO7oZ>Ut=m>63^A_1D33=N@?G6a*88N?@) z);F0cNagKFscb;SzjIM);%M0qs+ed~_Cs?PHF7UBw-Q_STS6O*gQw_+mO4mz)i<@c z7}U!fE%FWM+QTq`wF?NA_!fgM6~TrdkdhIs>_%#@!-O!(a(J%+rO1bi!t~+jb6~Ln zix3$N|K$9<lGHqqGr*lC^d>mYE)*G7fr|Zr(xjZsWV|ImHLV1V>iL02v~ct=sA*SD zCa70Znpc7pl_+rpYE2<EFGssGxQ9Bhc4uJ4I2Fb}NUYKf2j6&yp)r;QC|U|j&B@6u zC<YCek=&o8V%HHm)?{R24skIw><ulT!@$T@0jzpJ9&8$fH38J+C^Z3k*yp7<g2tLv zja{Ha6i8!xMfs(9DXE}QXHaK9HLs+oGD6kZMb|*jz`$75*a<8W2^uHVGcpGaAA$v3 zKp_d&-~tLqI4>ZzC^I*;1U&W+5`+XbmbyJP1!Zs>|KJ-aIxxl#k>U%MEs&!NCRUW1 zlUR~j1{&Oi4OAK#U~3Z+;{=350ziW<h!IRfb7(sO6dI~VM)1i6m`%m`rA5i9P+g!n zB0M+=u?#|jh99AtVS}b7#uj>}=9UNm32V3mjP+pMT$me55{uGPOQ6P(;s#@9@GvQS z;1+*SK~;lCO9`ojj=dsgcCePXu>LtxLU&98&8p;rrUcL%&(I1DDV@WH;F44Gz)8~y z)E&V(2#2kJLd_+RP{xv?L1t2EfWpWet&FmS=5(YqZw5_p$Y~zdHG)O>zz>HTLOp^M zbD-we@QyuLO##n}LpJtcO&!F%7-%#ZG(8K+2AIvrA)M>b%W%UXo9jSz2B>^T%5}py z-i*zm$rPI3hH$*Wn!AYnhLO)wNodejWR`&1bD-HEW2e-L%o1>04%D!#$SgrL<3Jox z*x_xkK^icSH3C>GX=o%2vxc3er5;*`!5EgiV6`kHWXNb%feeB)YoVH9O*>3WjbP1L zn59FuEeC3?p_NUPq;ZH|EX}cDmJZP?CsR=30fi$hK~O&xn!-jJL1lxgkr9TKLpKc) zGiX74Ig2w5LgEBZnF(8hHp~($!IT3D7-*>nO2riShS9AwGKS7P!Sct@O{`FlAT{P7 z2@a|8O+uppq8Cen2??Ol#EMbOjV4w|BLzI5Ltvx^R-oZctb=Jd*u(_dZiQBICa}&s z(ol;btgb~KYk{eQl`rW7zw{7uEr?@5L1Ix!=I|UPGePV3nOH(gN~EY88lz-Jn4@Hn zVw&znyamMGVb&f2?_B^jGoYE=*cjT;hGkyr7xCy;nm{ur%tlCUOGXO_I=Vh!WAR4N zBr<eLc<4YmH13Top>dB?N(_|(9$Hl)1$_W$caXEOs-vYUXnzRiUWK7Q8G<&mW^4e> zNl5WGG)j5c><m)$!Io$st<L}r)aJp&(U-x1$}prlVdzILY*z;?bHawXhF;`COBKSA zYdBIP*BG`UbLd4bQM-CTId|klF8Y9^$<U2mY@>k~EAl|GJ95fpQv+yQ16DA@3hE)3 zcVV+PC<QZGJvzu1s6kuU(4fbXuZBo_)dcDhyg^U=Fgtkh8E8IpbbT6VKnlEN9xDUO zVlhK=X!``3s0?9^QCNSJ`aNJ1V@o{i(+rI)htK*n*cc*GLU%4oRUO{_G9z<n_J$=X z*zp2Gu8J^)<_)Ci1J(A!c9|2@yF)+TFq`Gjc!T<ISap?+VKWYcFy6p}k~oeA0n4Er z!h*ag7%U4r_5~sV7J{CC0~R?arh0;bL4m>3#WAEJ?#*1z8=;SX9g8ns$>TcFsCAKx zN82Qoxgk;=e<m7wy37=w+SMbe?EFkoRi@SAn2}0~hLOr7wW$k(EPnj9eZJ=XoA=r8 z-`_qQRlR=ex4$vh_wCEc-h24(zTdImtB#fa`xQOMg@c1paRO6g=<2YYH#ev6Zsiu= z#mX%<<(E#}o*Qf9_TI9~zP3j5>-M6jr`826_0s#O|9@TR>S?QEcbBa^e=R!yt&~Z| zgH<6b7nKSyIW0IL7~y_o$%*oYW%?{a0zW<+=D)ipa<f<Mv-9)cm)*`aR~8cJa0xnC zKV4P+UcI`q_5|_%2UAq7=GT1cyqz{XH)gS0Z_ME~UT?eVHyhnsu62ChQ>tVV#~aGg z!p|r;`NP^yHx-soZ3lM0-}ic%&&)^5{N`rWuMS`TPJu~)xnJSR`gr^N$3Nd}K7Z%T zOk?j3L6^**pPsIB?G{^C`T5zm%v)PB?;Ts**U}(x!k$S<?dS0rTdu|?C4<68F6L!# zB97nRRr-3G&6mm_*H;EFUy$s5%~DF*W3u~#XJ=<Ww<>${qR;Y~#Px;F?H78(nT42~ z6wFy%e2NbHmvc9IC>Z44GEr8pd3AMlI{(+aySsMIGR<~N`qSAQvni!h+B|R0+0=7$ zEX~C2&dxIJz7u1Tps2ud&CTJ+k@i@{)tmSgR&m}Je6aBEkH`JDng3jmuix5U{{7wE zvnNgTnu7H{SHIbK{EnM+Zc4GuuNRAZYdl*T1Ul51l+-T9nD<6;sJJFPJvH^+MR)nF z?O)mDYZ6>q+D+4D?ciP}=dax|zb7-O&-Pkw(AKOw%h&znY>ZG;ND^B8^h!#XC?m&7 zUh_K%^S9;RzU90#`}(@0T<x<B5}PJYIXPK<_rJftZ!cfP;dSvHyRS_YN5>48?7b#Y ziUC}WqS|3QCMvs2DO$c-vG@(6Pey)akk2xArwIqs{`~mZ=DWY{Z_L)Lt6RET8U#3` z8fEyT1Sc;LcYn*>*dWj_fk)CvCD%#lf`QV-93@9dlZ*+1BAo&POb=Zed>l^wkvg}P z^X-Z$Iy*Laf4=0czq65<eV6XG8;5wM&CY!4^SI>Puty_dd(KUx!|x_I^Lf5^i&bT5 zakwX7khF;1_uhxT8u!<0HuFiVefr$-h{eOiEa3pd_cxo*?|OK+eYdcmg<{ubj-xZ= zYd$zCYrMU+wKzPka;fUH$sCM|0(>kkK8H5)O_Xfy@JyWcYUlHL#e1v2n{DP@(sCif zGmk^SiPut5{nXp-_w!U-l~`IF9tsK=YW|UO$zoAb`x(FPU^Dyfi;LZFAKqO2{M=7@ zhcneRuU0Pa`SSJE)zghzT{t)z4=E`m1x5T(zFr-f^y&G1;|TMj%^k-Y_WyooU4AQb z`OGqwAg6;io(3EN0Rlx$Vo%@ge!nfLNk~zFg{!%t!!xm<KWF`=8Bfw*di1%mU7qY` zb@Gpw%1=jz`pLiF?LKex?A^}i^M1Yz*~`JG7{J9SD4g5TBOqXSl4IQ(y?@vD|4Utx za->7>-IvS$=U4IGonp&Wey?)*?iY)?&wPJ!!I}T;KE=D5EG-UU933-KSffAQQ%Mqf zb8E8SKKFjPZ^!N}^`4$!9sF8Tu;SB6^<Ejf4+ogv-PnKmmNzI%$%C@gVJk7)&KWG* zdn^*2yg1nN?(L~8kX`w7i@<_!e!suHm0fsru2remYq?kzmKKM1933;B^d$yvRY(## zQ?&ovt?YHBudlgz@maswkYJ^`JhW&Ds1&-oHro98ETj0^uTxittegZYdhR`cSl+I` z=R=eApAUy+J>N!c%XwM;Im@4eqfv#!rEkWYz2EPJ8Gdcz*3+1IuKNAn=ihFo%YXm- z{eHA;PrH2GjdhNzLRLQ7_u~=w_Kb^4<xeKM-+Jin@!)!VeXd{LOs=@!alfVW_Y^MM z?*8wWLMLbE?W%8YGV4TtzuTSvWTRI(lYH%$i4!N?&f9(V4Es-!pskZvy#4$AzW&Q? z`S<s|+x2=~v2@M`$79Zw-|v>|&VF@eWpM1{W4*@v?0d`;!d_oq-am2jg6C75D+QbN zZr{J4yZz21i}QZAU#}SGH69B|;c%HWBf#?OA#Q!0NG-m@%Y0|=QuUs;<LkBP^H)~{ z9u~~nc{MEhCL?EN<DLc6{{DPE|L&cg#kx8h9GlrB_099A#r-a<P(CBlu%P4Q63@wZ zj&us&l`X%M7}cEQS@!k!`~A^h*i#y8q<&6W>OFmzZ26sw9h?_6Cj2PBS9$#JWBLCD z&*xRI+x@6Z+eq%5Gr#SVvir5)Z!A5j-hbw-`TaK?(@wQ*NaaZpGf(*}-83Pnapnnq znYzLq(>NNPlm)Dl4oN>>y?$R-zM0K~f|%+j6Wx1yDvmsvSN+bA_tetqajy!B9v^7j zF=5ZEYti|ovvW3e?sY7RNKSA2@?mlA#YL^zS6794{&w;I^YOU+yE(<@HojjGS@iX4 z_--}dSv$<{*Icf9^8e3s``q696_0sWGkH(FT>XCU^<&JHQT2bn>Q;t@sAwcLO?$F@ zex1?s^CcZ8XPIW-ab%ZG;V)iw{L}sEF-4tE|8`7Tps3`}`CIS4QOSz{cNVT?(~q>j zz3gxQ_QDc}f8X!d*Pnjh$i^x!VKV9DH|yl~D|71q{d~9iyj^kb?QL8C@^$))Y~i!` z;nXBo{l;*03y<X5`2G80%dUooTb?+(|Nr0o-+SY#-){X@d$aJ(p3mogww<0^dM$F> z`4h#D_CHyrUAQds%oFn?GB?WS6wZlPpI@`7qw_!aYO&1@3S~!9j`c{EY52`BIOuWY z+3fsxcK`nrD=WzvF5IPYq=Eg`wCKD{e&==8@ArJZ)2Ti$<LO094Su^H3C6kw4U>dw zo}HQb?x=XYPNw{A<CN6RXU#S{&v6zv`gEAze#iEERj2v7^7sF}Hm!BL<h`!vXJ#gA z9`$TJYoTb<W2_}4V)*eHzov|JSx&3e<oLRuN9FQ%zuDC7%zIYK$s&AxT<$;KzzK%Q z$7cLw3yR@z{M_+NZqXbc1$F_k6C5qgf4l#CZ~EKECdB*nX8Qcx%+Kq0K9joax9{Jt z*Gp$T+kWIU(|&E4+MRiKORt+=`uy>@d~}6gO6UFL?Rj^5wv@cNvGIz9g4^u8U73ms z#WN-uzMfNbN|W`a{anAxe|c569p#q2Wt{1A$uZ(OORvM54$noJ?aWi!!?lu}N-w_M zcKe)Mj>@J(K8KrmgAOrreSF|}Mq1@n-amPMm-ADcw|Sg#nK0+=_WSqV?3OvV*sXUH z^M0G8rfF@zEvGD2NmN$T-~VTm;BHavuo=r<U-q{@d&*_{d(#=V)!Q<!RRrf=TNAl& z_x67ZlDpsSTD|+_ve~Cp)da-r<mc&!Z~Du}xc}d;*LU|+etu)#e2pbovwF_`7Iis8 z$IlJRI(~1vTNb@N>#ElGv*!0DR<ig1{QO+n@L?*`Sv8iE((aB2e&sK}yv)~FJ;KN8 z=8UG#hGl}2YZk1rYjRO2I>NH4Avq<<m-~;$g_sZ5wiP`+CG;pj&`{Bxv0XF2nWJ6d zRr-}96S@_h+h*M7$`@L(`?Qeo8RL_4L_OvC9(t;%O^`M*oOg^R)Y5ND;N%U0!ZNeV zZ)K`CPu%$Nz=0)VWsNUBB|Kgjt#Qz$`Q*pL{PsGgEZ@{xI{$JjKG?5lpd#bF^?v%< zSyQjbw2CbWT<o^AgY%ix`t$bx|6Kla=z_r{HaQ!P^RC{_3yyy2=rr$hdieBf_c39n zo|BqALS{*a-UlhM7&(G`F`1KHq;Jx^JEhlS-yM_AFOli%JhxI*P}qYbKcmH?$RYXB z!}}J0KW^Cl|KIPo3T}@N9bTtncyLRzC7bcY@(D&}9-MqT_oNE3wk(*M*rTNOH2-`F zf9Uxs%!zjr+hvtpeGKvwjwu+enb0K3xu5e}{@SRmUTsb554K6?Wu&QfbS`gIDlxlS z=g!<AtlGkMaOL#-?EfOSJmr)UR(fS4tUgQGgMUAFopS#EzuPjkfAW63oqc0NBBvqe zWHTOKO?|T;maV>*{_?8!S$hQgUC=j9JRJY{BroGP?<XCc=N7N1D2!4qVpb|RBIv$@ zPu418;b!^zKNsIzmg%zDaLV|pKxKnGXa3C$R|T~dtM&K)DGFA9Jg4g>+iuGz?4_Uc z_x}yMWY=zKr)BXXvHtk~mck3>ej6u9ehPl@p#7Kl*R36%X-8NdH8OvknLaP_6{C1+ z(xJn$_B?-dxHR9SZ!vol?BRHJmT9lZ1BWy38Q4F$Bsq!ruljo~zqNAXeMRLzY6@oa zn#+|84<2V>Pp=aekFVMIQ>0M#-19$alHBK>|1ta7`>EPT#$D0SyGHVnPE${-?<t|l zA^Q~tCvR9g=NL27L=`ojKbubL75`|jIMn##h_Jr|r{jrPoim@F*57Y(wtf0>7GnXv zN&$g4H=h_j^koz^Z8wq<dvn8u;Xy(BVXZ?CJyQ7lDrdy+`DW?!G2?sDvI5<SHZJWC zEIjHbh;Gq*Qs%Ih*YKg#y?+6b?!HZRzcs5@Y+{>W%aOk5aI#iXQ>Vg<7~!33Bvrci zdb4;-u$;YDcw9C;>fn)fy(dSC>s(hqbUo{!H0f>myQ6QKoGlN%?|dQst#*+^je%h3 zx|o}1mXyA_Vt7{N`of8g8x#c;>g-*59VQi6`O3IUY&g86N7!25Epbvwy>n;sF~M2W zjnCxNd0$9xyZ<<}y46)-(-D>%0iw<p274>grnp!bUR+@5>8_xe;dH7^VNu??xV^gs z<+jMyDCm16{oYggNT8#4PtN=mCo`1;=gvJh<4~3FK7Pq-t<CdStgyJTO7W1u9Rtzl zhcl%o^{y1^WmSCh)U)#UT$T12`jv_vVzR7;je8yhH)(eN6OujfQ8;=-LZjv6&G)t( zf6s0|Wdr9$=OsJ}N;+qPUfd7ZcfQA9ee1C>L#BypYNG!B;Vg{~`}k+Ryu94nhojJA z2b<^9#%}o#!!+JB`>G=<I#P>c>Xb9yD)<VlIdWog%q^Zr_niK>eX31kX<T^g479~& zX8Ur&$vREXpf*dT87#3k`?cqnKN4osJZNac*L0HGURHmTK40;tYCbFDKW--X-geG7 zQeDeDb1vV^H;Jmxd7rQ>_w%$7P~hSWYFgi?V##D>yv5ka(cy@S@RpLbiVK|8cK1Gb zdi`L#laM}(hsgGvo15mWHagBd_5WG7bhnsrvl*40Ggz9l*F;}coP76_&|KFfJ^l0U zWouuoGf-+^>rpAly|sn&@dqwDwYie4@l77Q4o6giPK)*(d^O=@o~*|$_bc844`<x$ z^(g<@%J7nrqh9TPS4u9+r^>Vs(%w%a`aWCwor?R_q1<nCN$JFi&Z}FquTN?eep-2e zk^M&g)J=j<IThb`p5)v)&BpHUudkbD1#m>3Dx9EZ>$<Szh2bTp3Ql`&)4q~lqK2OA zs<FXbjWu#cg-!D&q|2xtp7vSEPeMFP@5!=*3vaGgiCa<FvNitx`5ycK^D?`HlH=-> zopyYD=_Qh7H1U4d`;)zoMN5}HSnVFPW8Ry?Yn~gQw@JQv#B;(-uZj!KWf~8>Ub0TQ zIdOXXqsei(>Or0fhjdeNRWC&c?9bZ&_Z#<XGfl~Gg(E88AKhJeeC-PM7rzyQRWjr% z9yCtlooa6Axkq5Z9M;Tll`lN6xhc#~Z*%uqG5=V;UZ4W|jN2a5I3qQ@eNH@|tf6vi zi3*bnYc6-_TEnB0G=IKYz1}Rh%iZVHwHHd98d5?<iGg3|{5Jf)aPGny<|7?G$5jMW z6y;8uuZ;bA(Ov%Ljy68oSKIDYWorj`J$-v?Yj(7(g^=K+l1VHrJ&jyX&+H6eA9u|z zLjCu=e;#i*IhD07Z!NgE*gg86o{8p+nLDQoac^;5r}(LCA@7q`t@%P6h9{r19J&{7 zdBpCGv%lrO8abnhtePheR7OAQt(qQN)_Hl0$@Kk#3fX$I44e+CK2%T>V9qkAWSXha z9<WJBb>6WhI))27v{f3qE=|!;+^M$p)`h+v3ByB^a-7O8%$TC87Gj%!ch}b6FPG0> z6QJYL(Qezql*`v?adJw{qfYgxoxEAj6CchpsESKCG3QL}mzP(WKc8AVfk*Jr;dzTK zbkdZB%#zk6@}1nL{&;8lsfByEYMuSc?$?(8o>!-+_~5XlYb3`p&XtF3rs+f`1ysi# zQPD_AzLTe9__6LpXZ_{Bd>uQ?xUT;;3|kfN?6YUfub1bnZ<apoJ>I{uZR_6+=X!m1 z$b9-CSeeZ8I^y!(^1647CVVL$?k08XGTBSo_I8FR9eF)rmd}#A=UZkhIJ@AV)KMwJ z{|<Tz<_R2<3z=-6dQK9YENPs!WAC?Hr%kl3^gN353UqL&c;U?AvE_ub{3FMotltFx z8OC^rB_5m8HKStcTSd<d%M<)8FCBwj%3f}|pFHVP2j@}|jmJ%4Y>BlBi8HDWum`m+ zOFP;ny6o)9@{ebPl7xQb1+s5+Y>-#encsVc%}MD0vfp#d<3-kePhKNZ_T;U~&6>X% z@vk?0i~Aycz3W=<_QZQmTluorGauC|6nc74a?6zTQy>4yOX>M&i_R?i_5FQ*<nooX zj~(8(#vy7~$;(MoW-K`A(9LML&`dgoxv5#~i1#t~{~<ftIX2WQuyr<VQ=K@Y!qw#B zj0XkPuU0OfWzT(XR|reHjPR~`Z>rDq${9B11T0@0yxi}atV)}aq=0e<=edJZrhNET z6qy@vAzP!@^8!cu?Yez3rJG*3FPrm5Z0dGbKDkw)-j7-tEPXVJPBc4jGGp2|U-Idk z=sH1R6UjX-yb=Zne4H{Q6pZ6y%}hix?En4we16Fh7NzF@Z2uJH3>#Y#{w>@m?b7)E zr@5WXkG_Eay;h-Dx)y2V_RHD!%&2fVc=?cn&kix6L+rxmBGc!lO3ggXXRY({`;{f1 zIyi3$bftcKdHJ{)cN6QxLrYi<Kl->Usr@o_XJfq2Kl8*Ho9&IKj;omeIaIT~#^+T0 z+?sikI|YQ#yK^*EUUU`T*~%?GYqD18wu|2${Jyw7KYq1Dzdc7(K%9la(+>gaRqX7c zKFTgn3-q7K^v?)bI&Y47hQf*`XTHZA-n*swvevB(lY9Z?MO6lWo%+t%{mv=gcl0@P zl2P6r3+)^)*8Ft~@8;dzB^l`T&GyMDWi|7=C6lXvJZxW^Cwg`7#c2Y1y>0GCRL-dP z9-AfvE(D|4T%R7vH1$638ff`YQ7ukxa!R13T;|75Gag)T49?hOqvmo(;AxW@kEC_k zn%DRCR-bg~EI1fx5-BI_W0Ik~=g?vS0j(RtOPkeLgC71o;9%Er<*?$_)fRqoBI{aT zJlKBZ?+H%zISFbK9h_IUeXO2oU%xN2P|7?n$1W!$Xj1L}f4|>P7Z5hF&uHjiaC(vd z=t$?ZofeXYKR+DiU;DSF)5r3sla<@wju|Q2XPio&B%2qw!@JVwkh4$I9sM5(541O( zHM<=V;=7H>^Wd4ypU+uO&tiJi63>}<sPj;H$8(GKf9;i;40an#JM!w<%6<MhlP4rT z+w`zadY0wM&kIkL`PJQ1PkN+2%k|Q<4$m^~wP)7fd??nsd&<wP79E}<-;!jGX(S1? zho1Q?<KnZ4Ic96oro*~i<txMbK(d)3Ala!?xh`6``fQ5k2^Bxbw_W4T(pQI+)B<lT z50qTo;h7Px)opRl=B(=xmFfkBUc2AzdVQujPKckyBhW9dtNebgxtuUpf|!*t6NBk7 zUom;Z&g8xyHu(XvMmL%HG!<1ozT5ropS5=Ex3@3OeNb@V<8nH<cS+<!$;b+~MaIfD z*@CSTMdS@T53Opc>9I=L6t8gTi^nY&tydvSZ*I<yEq^A>xJYAF`1-u9UP6nNKH2td z_`cj&`Hi;7x{sn$W=!B{d)3;aJ@Kud5HCx~i6`6qo){`DoH%{6!uD$=<%)s}=5a=v zYnG{b_BNd3dE4hBprK(n(<rq|RDMx_;K{6OvE{Mb@7Mj_x&2<1_GHT!w``ObIIEc- zI9ciV>P7jzO7-n+CFKVN7f9SX(8#=Y)@qfkBQ9lsH@v&qBs5un|DQ{%^d@beujDyV zN$ufRU*4MaqPB(~AKECtR@$nik*C(F#+33(#=dUPY@5m=6ZHwl1I7Q&oanyh@rBUV zBP~~UD!cV;*s^^}?*5<8X2-t0we{|ci;H#7+qE?9UvhluCdK^bJDb1XtB&r9eZ?JM z`SH_f{q0UJHT7>c9*@e3y>w^Nw(mb4_m}Uj`r0LC*m?L>x+S};Q6$s!g4?gx@6Ti1 z^}%<7i!ftN>k6^%YvDn5pyrUXk>i4xB&WaZuc{}s&yV>f&=XsB^Jrk`L@6c_87B=U zmO{rpr@FPn))a`xRV;k^vwhBo`!}v>>K)mys43zxNmG6DQ?BD%ty2C(vY)WLDD!8U z%0;JyA0Hly#k$@V@;u7XqItLS=;EuQt!@mL{4YF;uRk4?e9)4A?Qv&*+mvTwhaM@2 ziMUrio0;A-BjDzT6UzN2MNWpwMel<}GW%`670k6N-Bffc#Q9F`_q%uftlvJV`u^_i z2i=2-Jj=rcCp+agp7||qcv5C_O8JL`>`O~JtDjB{KeOFSh?ixV@9bw$+j25RlN6^- z>Jq##Gtkg&*Q0ulDXR@L@9x@~>3Qmua=%SdnnVYu%Hqn;&)i&Agm4^mtab`i(9*H{ z`{i<9(E086s<Kz6x%e#F&0Bin$M&-1V?BoU+FtX$7d0|G%ka6dd`^*<37bq);Hxtl zZ<Jils&0x&YSQQUr~LhX{r;In8tT3k`p;y9Tti)aKG<8nTr$~b@uB_sJ07x`7d`PX z&$^<K>BF_#zxY*byN}<8wWY?hPIyh#TI+i6?_1ZkKN}B3rq6x4;!c;^PKhJy*=L>W zNxGr?@9f5yB&Qxbzm-eQACv2goho!X!zFL$(`j2eIKMxPZi-yt+|KuI$KyU@d10<u zf$>huWd4g8$LqeF@KOBb{rdlR-|l=qZ(aWVec!4lw+J)J{44x-yk+x2HtCk)35v2) z&-F~u^YLg8)ieD0xZnQH1Vv{ZCiee=PwrK}H`V3X>3(6xgZ!rE9HZbq@r|4R|NA|A zCi}rX#+jE?c7JbR=G)*Q|J0E4<vR~U9a*D)>&5r;`z)VPs_<zNgWw6JJF{7`X5`0J zy;Qxvqwp~UyZHHKrD;csW1DA%wmv*m!sF-|yy@+>+q0%AOaFW}J74EaM84F`1>)<f zOHQzCmRrB~+pLL`)92S-lP$ZEc(7zqn6cY~R`IxkcKNy;6NTo)sm@ehV60qxrt4>4 zQKzS(^PWkroT8tdS~K5Sr8GtJ&N*sWzbMpYwuYt-Q$~xT>J#mkcXk#hvI{@FSDNNh z@sZ2m%N7$gR*C7mcnq1WQkr6AoIZH&Yx}vtd%E7ivSrtTl|DR~>_01#H^@n$L8Y3d zBrT;s*6^NYQc%z8d5`Cmo_NBMAhliC@BZ3o^Up_vHtsiJ`215y=KsgqW|^RZz)8|f zR>nn#*WY+2W_Ysf=-;lzr?>rQy0_d}&HjP#--FWD=bkaM@tp8q{^}@K*S+%lwQgP= z(<VLXb692UEc&eYxLKcW$BZL|q0I9pcX%FPP&fI1xBPzOvD7)|PA=N>^;-1v^`Dhq zcM3_SEK~D8dAI!j+if?~W-B=>?0C7%%2-JIOmOzvHCI-Jo;GT!|NVCRL0&)Ic0NYI z$rp4zf3T}0P5N&tWmB=C^{untla`nE|NL#gPMIk5=|scUBk?Rjb0s@PpY>Zj>R585 zMPFP$?#=s#D^V*11q?aAerhQ$P*Q7+6n_=+@xzhtDK|DGMz+5bPy6!ljp$nrSCQlW z^7%{F$L=nBD3fu-ed?<-9%~Hhk4dKQ@VEbaWp42~%WvZCkFDSBI2^hzCh~~Nqu29a zesJ|Ma`m}xEjam5Zqw7#(`WDJRADW0%Gju4&9Z`rM^jNoV*e!2RMzzg?^X#kmiSu6 zEjl;LG<%xL*C+Qc%?RNrT%#vo*m<?+S-O#u+RuYK_rz(evn+Vv5Wd)rS6M^m#iTC+ z4|HYUOw)_ax-s#JpO6mIO95doqX{jWeP^3ZJKlc6#A9)X=Z0+IW7k}L4(-rVl%L$; zSs~W3XvUOYi&rZa$Nc~I_io<qw_@`Sw&tjSrUylZj^-F=Tu`{aK7Rj%UW0vyJ=<pp zFkanTU2dLqgrgkPHo9N;`|O#iN@^ePimyylOA4yVp7*)O)u*WK!gV%{E>6dX3$>dz znQiH8Vfn<SxH4?*to7Loj-7H>kWF&RHGQ@2VRqC0^WX2+=Pz+NvgAkE^bXIDYb(zg ziy5AjJmer1v9oCDL}9z!+uKTy%M|y#zO^-5q1JWbMNVP09UGI6?>aeIeYRPr|J7BY ziw(Zq=rxp0YKqMLeAayXtIrue8tfmAN#}RWIFe@`VxuTHxy$g9XsUpKA?NpL4GSh* zo7ZmSc`KmbIjC#lH@-^48RqhT@@AM{lvPq`y}NnkIi3^k;feEX)Rz3W|9C_=cSH5t zt<z`Q*YEoqeQteg?EaeXdP$S=k0f81-{DyzHgVO1d(E>hM95tcn99a0<&rKW+EeoF z%}ul8$K|Te)CkQ`mMngKb+!0xOSf93nR6rsvd>uD&fmY+mBFhEG{^cV`tzLhIVTk- z7pG?(Fb5UzVNO968J`){)w#_6tT;JI)%(tl!pAvw#m~-c-1#B%+M38K%YsB6`<AAq zIN5|0?$g-T<r{QlNyW8W+h=yo_`#NXP->P%;Ue2BKclzj#a`c2Ssc9b^UC1meg}_D zU6ma2Yer_k-_Pau_Ehqvd!F!U=aY3ZkK<io0;)EZVWSASoU^aq_U15mp4O_m+<$%^ zf6e=a{)-I%7)zPuWXyN#mD>61>+9#ahvwIQn>pJwd)jQv;$?qT-*a?6Rqz$iu=Aa5 zcJ_9~l|blxli^kYUeMf|_oh69)03V?%AHA2y0nUKW`|D5w8JeN4jg;<SsIg?o_HuS zPW!%afx`c1`AfZ~>XcU8+`l?}eOdOkHHE4FgADQyHnFP8zu(XK);0O@M5XuZg-)dI zoT0eWH{H!cOiAf*2b*Ch$Bd&!KC(tfH(mNa`}wNS)iQp|QaM?lG<9%xxEl#g>RIza zHZ)n-v(LSt;MCfnrCuKyWj;&3KGX4&>9>uopm0~T*c;edfccENZO=+hh#c0+?sGa| z&r*{1qdnDdi%L=u&+0dyWlB%{;8`(Cn90!HA>Hka_>Jc;r+WL`t9&k7{`c$k*?YgQ z+x>3ShC`qktGC<l*S+hv|5u=LMAEiu%T*JLcRL>6`S9?t?wRKcn)x>UmorZ5Sz5R6 z&!^LO_kO?kTEnL7gkt-R?<<N`FS<Ci`<Pt!T`b1b>g15_ws1m!+Wx0P!mF%<UT*ZB zuJ`VY@%fTwcK)*0>vpfJ{`>WM?}|C)_bT1MeP(4P^|>XJc0ZZqea5Y4vCQ>;DbrJX zf4y40F8%zxb+y00tt)<hZW>3YfxV}R;E87wCQdFixgNDxjHymx!r7S*-S=lH&*E6( z>a!x&!Rz_+`StgVv_KuRy!*A^w^qqGxASeCdB67i-LR)q0_;0Dm$Vf<;<x*;;Pu7D z?RT5MJ?T*H+fc1(t=Fl>WR<dLXP(qn0Syr*D`T$K8k65^C(KyD`SF#=o}bTVhy9%> zBL<q6n%L(z*Xrh(_^Owx<u4YtTkZL-s1{%IvGsQ5^0_+J%Cm%>_ys$7mnoj=^Ip{1 zz&A5v-E22q7OvKYb3IOq@@MO`Rn$OpJHNl(&d)9DJhCKoby!%^UjO-a-~MX^|NU~= z-&(86$!EpIjfeTHJ7%~P$4{}&k~K1n3GwyhVCiT$*TZnIH}P_$@Z{NfyH48v`EdA| zzLS&67S$;c_J6-zcJ)cx5h%2LiL=@>?lmtt8RrXLnEB9nfnmO0cG9Mdi%Opjf4*4U z&!ZIN5?sz4Kc&k=ZOIO`Aa@~OmXZ@L#dl4z6azF^O43BQer9}|9V{p8)b{+`+}CDz z3Y@iB+>$5#05!+|Wv`LsVzdXDtUl{wzP5UjP<@5T;S`P+6E5x(VA`oHkifa&4*T<B zZY$#&Hj`&(J7*lJX>6V`k8dVdfbKGNKLKf<++%!<b0s%MUvf}aNfOf7^D!r;-N)v7 z=w=}%N5uuk${Hz;Z?5a`w7G72A@bz}PLX>TOxK+{v@m+o30{wMw<puqEMOKh)YSNM z@l6aU<>}51tpD+_eHxG9N8|c`HQI)OyUTL7f4vrcJO2IQ`tVgDC$r+G{@q>mHEVm? zS*h@E?+>+d-)&;$p7VWr{pX)gCi~wpyPfm6<CZe#;_o+;`)w~t?pnub$Yf>gw8uhG zW>$wMhq&q+=Szyh-$cFYYu@ksy>7NqYS(P5(p7)g#_iqJ%;CUg(-g43?(Y}rGatRY zqRz~*+}tAJIAxlC{JW?v84qWf=jX`>341I8C4-E$;S1fhlY(A|b|n0_N>SR8!Rf4a z|H6%p$-3_a693(Ep1)tk+vU)c{oTjdE<F)kQTh4V&OTY|D8&nWvQ{qDhFvLNR-WSt z-Jm~-cfvyxS05vmH5&T*!BP=NRH}9-+}e`q=Jw;t>hSY&ukP+DEjG=*)^jHXG!V5^ zZ^r34mc==GHJ~c{`OXz-WxE=dTN#HOw2Niwer+W<`B7AUe42LBBkrC?^Fz+RKOUFg z&i-Tl{(o8g@88|sy_=0!isfGUJ}b~1*xCL|64JR_CZ3(>v~YsHXNACuju|VOYAdd3 z@hA%#avs)l$>C8_dl<W6s&@D;clp{Ya@XW*J~Rpn%3Yh0`ABa@mCag#I-@hcZzT6` zHIkfkNGU+hFp%~4p>@6z)#8Snk5{$S_$aA8j8=dwM3K*m_!zKkMcPKL&~u8Klhysp z{{H^Hy`RJDVVQH~5f{-n+}rgM-$ou$S)(2NZU@)vSsF<~^L(4RYMz{!=;qO9^-80f zLHL&TPkyErh32zAK0fB1UHA9b&aA7eIOo|YPv8aFZKEI5u}j#H^J0=qs)mx<!w5}| zlM@u3T|6#D^tm({Wn55D)|m815u*6dTK^kWLWZ2TyIc}%l+;>dmrReVI>{?zaUpl( zQL(%m8xp6LyG)W}dg98sJN5K5$+C8tB9AKbSF7d-ocMMofc5vBg#I^YmDDE2?mEP4 zbK7}YfpVYwc@-&XgM^0aZ#UELet3BJE~ok&f&R{)w%sO+Dlpciq;xwRU6wjm@@7)> zobN~H%ve(BB>H^UbCYaYBg=!+ubw?``+d&qySul~%vDfrIp$U5+#ry3g3~fEZ~xyi zWz9(m0vBcq@~kV&HGOtOW!>qp8<j67oYemZDy0{@_it-Ye|~Q6=i8NnU%p)l_LqG5 z`s(WG%-Nm)IbNLkAb;6nyGD}G^Q*iWc~&V*Oxt`m->>~X*ZS?2%RbgjnhO)=sYtMB zXmD6Mb{BoWTOMub*jW$K$A3C0L$e_1(^>QT7Oxa1{F@bWX=~P1tyXQ;ogXHs3kJD5 zF|IeiSF!ks(W|OCC6_$kJ?hpk3tbhm@<rL-`uPGE6dwyucxvKYWMVX9)Bcaz6Q8g% z{_%ac`@P-i8M~j)tA4ipveFCJbT>hrP5r?<b7t6lK4bjuPVxDzv&6c^^~<7jw@y`F z)o^MlXu-(t|Nnl2RzEy^xA%LTb<1htj+3C}0B`?(y&m7^wL~|1+ZOXV!Tz>a-6O7q zRC2tSz*$xwV9yd{1Zq_Ndbyna_ROew?ndkPdoIV8Ty%X_UG!pMJC~xoz=fF)nLAvs zxa>T_;>)gBTK#_ScH2J}^BlM;ntwm)){nWrulDZJ>2X;Fe?QOvUjkZq0ICUeS>A)z zJ?#JgZ};B~iVE&>l}mQN-FCZY#s{+*5|1iwrcS>Z&GlXB&ukgql+8B(ems`_U;p>( z_3e|MzrDSEd!5ZeNdd*iOTXXm&zJkQWLer88NE2IcdOU$yVWaceC+S1)B0)NX?J|= zu6{rB_s{3^=AWF^e2)b$cI#ETCAD(-DrdDFxeiu8<!q~NNLNqSi*0)Cp*y|%z+`{B z%qJfj+2uUEXKP!Wc3&{#JWp#v%D>kd(`Qsnl~)v9vcvB6n$2fqiXZoyNBK_>IdSB? z{r@+hw%32(+`fg*?Yltpo|hc&*L*%(W*f+QBX_dk<mvHsH@D{9y#=c3(pFji`EdB{ zzS#1+S0}F9k$!&OyHBU}&66%I^OY_?$SQ8}=(eKL6noHI`rBE*zP{ew%x`z&pKqZ4 zuQ`^*%VtjMvv|bu{mW(l-Rt-NyLHcLrgYTwl>7PH@0OXJ+kD>c_9BIKJD*9-e*Aj< z{&|*%4EHRa!9P=By0E&B2j{~BZ%REA1s|}siz_;HTbI5HxpB~CPx)L)!T19<{Pwy@ zo3gHIZU1;odiG8h-a}Vb2H%}u|L^6s=zQDnx3bso1hq5vembT7ZteDan;rb@>v z=j7}?HLK`UmQUK584thR%GNjj`rwVbW|@fzM-<-{sV~vjj<@{pKP>fd^6dP5J0}Wy z@J?=OneaUE>#M7L#X|Y^GbR|YPGl`Qt-F0orONMlQqmLVR(^gK8U4lAHB9D-g3eJr z*Wwc)bLJh~zV^U-jv_uy%QqVi*JN+casHF{b3x;jke&nF`g;=6xzgFwl0C~fM9$8f zC~LE8H4l@h(Bvbh`ZEM9E*NAhfZ8yRb^8O{wkTd%;-J7RFthxA?RDLV4GWx-m^wj2 z?vAfN{(L@vx|G^h-3t*8KC?`-pPjS$?DPA-z>Fii#6b%sMDAvkmfb0IH&!&9#%p%t zfQRTmotS>HXRB7P+mz9sazB~rkVt5l-M=5npL;dSIA2Y0Y;N7wy?4X=eZR$c&&Y!o zNeTJP6-eFBQvCAH&f>e@@7Kpq`p)v{+`YCb$3ul=-~FAToVL}j_LqcZ=A9iI<$c+% zxkc1FJI<ACWL(+C-R01FL}lYA<s&Wad)ystl0H3~oj>b7N1Yr8e?i>=P&<52VaO80 zhX()NZol92<jwy7|GuR)y=43Ouw7opRQN-&=d<KT3)_p|`dPnCdD8q%!CdByfG`KY zN(;Z5j8D*yb05-Xy{R@)ov|>k_G@UiT)d=@(~q?|J07;N#%?eukvpOY8g(%*eB@Hx z;+7qtb8_8{XqWm2>s#MXj%T|0@z0J65@jzg9Gs=cmNe-_!F%y}dukHnp3Qm8!?U>M zr@6?HnS#emFU<JkctAX9)6KNmGxOWirH@;dURx9SOyG3?(<#Azg-=oz*s(4X@R}6N zDEd6i$IPbZUiEuh<L3`voRa3sU3mAw+nq&EPw_23@Tr5dP9-Dw1-p8v$CcRfyH5?A zKZ@52-?~w9**AAhi~izEe&1}Pq-Ej)*E_qd+xso5diK)Xl?Ud|++Jb)IXEJ{rf1LA z^&K-DstiwmG-%iOeE*HLPh+5viOYn?DN?&)o;h;Z&SJi$X3k!HUs>%(gX5P<!3V5O z_vL3f{MmLv<&(fOSH@h;w4iI&qSyYsGpK%)eC$1suG;>of4|*6|I7Q?iGT0w|KGl~ zxYlRupL3OhibnkP#&e$koOj<=U-kK%;=a8q4qFUfn`K@)^5@v3uijQoF74ItQ#HkP z_EuLeOq^etmS%tJ%jRB#|7}ec#($3Z<+gG+>Y#laTxJ|9k!a^!#KQBN>f7TNm^l zpK{odsq)~=H92y^b4~|LuHsjklUBIxX@ipjn~dJ=yxqAwkF>C>_H7VQWYIkf8hvaR z;a^w#?dI{b^X=~+JD$js`6$=)=JzXSE#B|>>}BFCvrXoW){n3A&q_a0Y!>5_pWoHN zc`@|Kx|^xfWAEs0zmwGR47_|Ta;ewULtnMM4W;Dv*&I=PTF1p-=d;?z;d*R&?B!_= zzYa{huVLBzWACF2eaYs_<l<Bm*xpp1IQee(`@AEK0(BhmT5AkBA5QRN5mXB^T7F5r z@6m*RDSdBTc3+g!SC8rE6nn(z`PfEbx9($?&nHi_r5|q<kIPsl;<V!8q9irHYx@84 z%<q;2cOJIYx31%A>HFL@eeDLXxH@OaU-7J!X)UF)ChOh^elYFlR7pA7CAuzdZ`D#0 zZkZ`I210)wPe~i8G;g=P_od>4!HJSq4aE*tcKLks8jBkl-1CL!qzKDK1lRi4%iNgJ zXdvkNG;z9~-_98ECyJ9_F63&=y}D}ZTkChAg8Xct<(sBvi<Y_UM*Q*iti`F<*Tv@k zUnF|u{_BP9az=|D3JUkHs8EwX*1XwbmXnDV#}T&qx^wpbv{gMUwTa)6;s2`8)w7gs zTA1b=DBYW6x#{s6zv>?0`%;VII@}(~o#S}-cqv=ascz;vBhZ*c=F1;%ol-8;EPG|n z5!|=k4zyS**jR0D&$mdqWVgdVq`5ww`S5xB;%$c-8`d9DkqP!n7pb&Sy(H;(WF6<H z2`9e<sLtm*BA6JHs=V(Im##_!`|RoLC(ajsn(#capV@**@wsAurAShf+rjPykC!se z=lmx<fAx_I5hfxTGKTF=Dw7g<e|nZoIDY@l0cL&^p^2v^%6|4qs#Y;_E^fNU)_5a9 z%4zYWGm<mD{8>}Es;*f@t%v`!7>mRv@hvGUW^8!a^3h!6$xOj7QY-%cQ4UygMCHH3 z@s-CF_-Fd?hsy1;ezU=ONe5>d-w9^R(m!JU#VwWH?AA^dHg@3xOox6cI$Lxr$JhN_ zdb{%Z+}@f5H^qGZWn3&w4J*aw8+5oBtx;6#<onclL}jY7^-30@+up7|JLGx!9)H`i z_Drjd^AbgmtN9m>u;g5LFrkJwe&z;GiF#+pd6M82OtOrElkXVn>=J9TNjW9A%7*77 z`=NS8L#0!n4Lg+#A0~1$9$0=T|DmqjngWyWi`)xRKvU9Z3Ppm|?9@`sa_{cCdcSnp zzsW~uzOXdW<hTE`Av1J^bL%#i$pU^;ZwgEf>3j2oX{oc1g2xl-LqF%NSSlW0bMa4V z#{}i&0a~DvQhv&2tG<0d_6hD4H{*PquW`ayIp;^V%}!;7q)Du8NAoziK26Z9Uh!$d z!^D<glRDOUOO(|1c(z+!XHn@6C|%^$G@<^_WBFx_j>(fW;)-09yf4fU5Om)sZz5>1 zGO5ndm@)IvdzOPA=LqE0xK9!k-mt7Ughg?xvbD-er6i{*0u!w)oF@C;687?Y(9>P- zwW>~7_T9&RPOlHmk`@IEejaJ@JOoZ!9KzqEy6rhSX8dSQ4%|BFymQ<3TE05Dc{42> z+e;lk%ybYAeDSEp;^?CguPxC@aePi~Kjq$rfcj#`Y{cEm@_7x74b_x-FZ@`dJk#pV z^2=#Avo*f4J1QyZoDpifAE1`bmi>JDvTn1R&MrOI*2UgdI<E52)!~TBo^0V;6H|*$ zJhAG0d3pKnrQXxSB<$v7+yC4l-^;R(^YnE6?H-bzTLc}l-B}d&IVI|a3bx%3*p<$f zX61BM`_$wXO`)?If(xE<wzPaG*H2Wx{z#;6@^?mdnFqJod}R3h?!4hF`r)z3+2M$a z^_{L?>q_`%E@IO>`DFd>cUG&FMX#~MMy)?1sIXA}V(62!iA&rR?iwq{COK`gJ(Hnw zO2?n0Tz!vBy@F85q<@Vow2WFF|M0cgEkDUZ&ct}h!V?;E?({nzS-~qfSwc5$-?B;X z6eq9$=(1G4sK~+3!$YH!o$1NK#wim%_)d~FY&2PLb%BPCr%vIeZzgIr{m$mI_!k{3 zXmL|+oG-?AONI4_$t<1222U9NYY0g`>VLvHOV5M%B(q_xQ^*Nb7yBQ+5C0#X^=N*} zdC{#8PpI`RF_tSTSSWjRdiRE+ITt+_aRe^Z{j*c+)Qp%n)t*O|+$eVt`wW`LGMVFR zdB;LW^`le6mj5n}9|fkUxGP+pdC*zrvsz$y%GJFOnz+v_luB|sYwE$i&*q2NLfM5i zOo<;-MC?8u5q`U{f2CGrTcXk_18&u4_cg7pHcb@%<g4WWORd@>&GOLe&N<4)MxFmT zKKhs2Sj<~&s#w%rW8IT@pn*~Bpz9OqSyD1*f>V9Uj>^S;{I1kF<Ause2}Z%mJ&KzH z!tb5gb7;cM?F+0Abuma8-0Q2n;9;b!mSK~(=cC)@5QQr}O(G6H7t8|c7;@Pp+Z5F@ zeA#%VQc5S=1pBSxIh^5TaDTyGjcBf;(o5ZaY(5=|SaHxrG5nn67PSm34*ztWmp$zt z9ep%@J0v;lFE*?dGIZ6|I`kkoRqvXdkl{tS6HJVPlg~Kre$=JCMu&M-g6AFqg_@Ze z{VwdME6y5xzq!Q9_(X%xNdf&mbEo_lX=s@d5XW+;eetU43H?!ishysycn+&PR^Ftu zao09;;VqH^a$d#`WeWTpOEe-KeYdDC(e_BUkuyA);_RBGzu54t^OOrm1o-A_6&JqC zaNp0G>9c5mTjl)54$o&3K8Lk0PPtJOmtrS;H&BeR=<<ULXW~86q=e@Lubk_$G`oeR z{<wVo9>K|=zWw(5b+?87O?-P@J2YV0j3uWG-iY?Aw)5|koj2jDgfRC+;|w>UPEJoo z!<`kge7W{Mn&9m>zgusY#@de+M_TS%Th6$!>4E*>ISS@iCLcPl8Y(CERx#6O3;QMq zha)P*7b>a`6`nsYaP*A(LhB}n29rNO)c1TmChce<-)(l?%J^S23&-+AnK;eb27R_? z{AcFb9I0FpoX3=V3e-vSdmPg1{=37TYiC2%*H=%2QYDrt*`$hoa8|s|Q>QT_<-(<e zTa7%4r#w~EQXGyw{JQmeoUzfN{ApYdK>h5{y?&qoQ#@=~m%4?~GAS<Pi&`wh5%(i1 zU$0F&rXptl`;VW~5tZUS8-qW)^-i9v630>V@8|PnoXR3GlV%=kajDO6npg3NbN9yJ z<$i8K3ThKr&d71tNeXbE(Ghv2qHK^B$ico(3e*V=-S4I#;__>P&4diOGx`=As}6nr zF<;=Sap|j&?CZu)3wWO`lFr+4P)~i1L=$tRSGi3_M8PZ7AdVpCZK*ziS2i}S0WH{m znx=P6ZqhNAY6Wf<o1{mrUsV73ez)HB^p-}<`{NPOTQU-l9PwT~|J|O+vElbB{zzm; z+~$9M=Y-E`=Sk+3`8|oU*}Hz9dvDvYa`m1inKMGQLRW1GTV%E9hK8ZT6TatsuF9TS z?U^iRnfI%o_hFKJP<5jIrq0C~egz(?ud}UgHot72qducXV!HavKJ||gOHG*1?N%uZ zPCEKU&f?OHCGC^fc{v>TeNp}Q?04lR>9gOz@BjY((?0DdU+ccSRqf-FvbH}a^}LiL zD{oKY=Vf!x#qm|~v)rvStL|x<Dw<k+RZ*M8hQ-Bai@1@S!?HO&ikn~UYmuw!oMn{n zSl%MaSTsXG(&;6OXAw(DT1I+GQ$vTRTE@#;lgyp={!Q5?`6PLgWL)5`C_6RL_0u{$ zk4n7k`mZ>_(2#S{r^R9_Q5-KOoUGX^GIg?LTHsFSKugi}Q_l5(W{Dz&CYNyQERFs- zv0%Mv_O%`Cauo_2Ob@<X=`~gB=`z)2#WKrR#5<HZdd*Z<+s~O(AebA`?(>X$xsBS) zWU;B%Q;sirH1!gAR$eI~X;R)(ccBXpp8BNiU(ixu;&e!3LD)QZlbej46V-q6aTb1H zS72V4lFL$ZB4wZUl%J->XBHK?&oSEn&wOvk`wOqne2~2qVIHwiQ+>s${@3gG?@K-O zrGxV;vqzG%hxo@wDi;=-n0|bnk>K&xyVY&d9f8w+XBjWCe1CWMHkZ;wmGl=E7EWVm z_i3o{R}Fu3=jV4&(>$elMu~|=itrK%5!Z#_(Py!*SHt5YZT=h;kAJgn&nGYQ#6v8r z?L0LU9{+y3{l3p+r?bKhi+>1n)_pkP{`oND(K(OwtWu2P6R(~+DYJRSorO`bu;Y5y zwctfsfwJE887z@MC+-sJJkpX=xhHheB8fv6mix>9p0Jg_i0Pohzc~|Z)~`~@>^jNk z@iS}F>xn$<i#8r)la6qb_6kqdyH)jitt?-b!0hCH+iQZmt}S-w_ujSn-LBVCnG0Vj zv(A}U{m!zx|GSUnm5>GgCpc$v{+#zuK~X>^>Dfu26F)rWIonP-vg7-MY3mAfUr#tG zQynUP4(!fXhv0FXIjg8?&7Y2Mi*yVtpH2;5v&Y0~W=4l#3j@=k!}3lHnGYWJmo@j) zs+b>gX<pX)=|+aHf?Chq*S7MLU6Pv0nh&=q1*Whs>75=|werZ6$uE*Oz2Emcsw?T1 ztA_|nWzru3;Z3~TvaX)m^lRbKg-U9I5`|*2MmN{$J#*Pou_w{{Q6t03qm_(GTX(6L zf+pRpL2FfdJts_+_hgKjHX|T_)2T70_UqL?ugNolHJs1(%O6Z}c2whFR1@KFS|nh~ zVz_YAlXbh_?GiI=d{Lpg?W4V7_JipBy{VF{U>7poJiy)-a*~6EZ8Lw$vNgfF36u0B z<!4)T^UeGeZa(#qNRZR5q7!T5C!N=@JTr@9zvRh!fd@Q~U5{ALZ}EoZCWoCzR8E}g z|1n{Ts@jhk746&HeGHa9=<)iQb?B49&ky<Umew&|mH!y7m}~e|?1OsajEY&^o1}!h zau;ekR(LqX6;v!WDK$!JGHa>goiSCQ%PH_Q;~^G9$KvLAZl$D2C$DMm%NEy-N?Ez} z;;)}mXGuNsQQY+DL_yM#NUIh4k(-Wm%_)6zV`IqCn7U}t@Zw*#$67DlM2zasiCtPe z*-th`Wu>5i;l+0+SQ?8uJugg^zpSXn%+6<W)qEC57H@&ZBW)%_h1qH>Z1aWxI2e3% z$T_8~_G5<4?>C#*rJkPl?1`7528ZC%b(-sr><>I&WvBLIUO<<0dSsW~Lfx0QwyyrU zu46{ZrmH2o90418Y>)i==zK|0ty3`l<rmAWD;mFZ6XvxndGNSZgxS#3e35{Sf$ZYg zqx*e=?3m(a)jU*Tx#ZfAq*|~3=}-3B*UjtxoOsAH^FRpGLygsjGwo`3g?2tMkT=hp zW4S$V+s(AJcMEH5Zi&2aSiVT*s!X9<>x>1wioPXDa>5;A*TdJv+~kYtV4G;45qDvS zN#>;^x0Wj{ardb>ee`(C3Hg>fHNQD8R)wvdHDyMETGpK%g}ZLJf3n*9H)Vg$lRXk< zIWwM~Iq7ynwd9=T^N7F=@9yrNeRxN@oy+9*o5G);CAP~xbL){voS4!nnEq$p3+c<u z*EeoA>{VNK>id?N&FuVU_qE=evl%M>wc5}5%Vn`si;UmP42{B&=Svwcv*k_->Dwm} ze7KGG?e|mpGwzEo{PEQF(M9&pPgEH<9pL8J?|+Ng{@4j`j{WW?bAK$U{diOyv_L1! zSIpD&e8^v+pYFHkaL+M(5H{~Y{jqLg%PbWq1!<OwcS%xDBegYq9lVkr#fp_YJzgTl zQfkuv=A8BWm{&y|$Nla9rc5*!<&5J06ZAnd(QigV$ElAj)wV939rIicZtE-7O*}ed zV%OZi-7`YATt4;x{{+S}%`WY!T3=sX-F*MR%H{L2CZ^=?`Pep*#b?qR-$i$4nP#W) zXPsbJ__k9p{dUgg-kGwXg__dL6ElBQSNc5{;92xY;oXlT7wjq<1Ufha^Cu|QS!ZZo zloLAZCK|Tr+6(cw%C&VrpH6psp=o@7skgYY-UQjY;xE&+gx+sDt+(0o!=!?Tt>Uxd z#Z|Z`>*<Tf&HSC*XL-!)lyTUx28SSntDlM{WzAdpYpJcwtGz4iO*XA$nZ$ZBd7Y5r z1YITpp>M06@1L4$UASkxQ<Bhh&*~#8x3^#2@nFJh8yBA<=Lzjb4_{4q?8DN_Amu2t zwKC(}48y~3w_cBP^HEUE5Le*(^Iy9y_F>u{^TQsli!|HWEu?s4&PKX#QOmFp(~HUA zFY4fZyYOb^@3-4^)diNw+?VL!{Li1%U!f-NBl-5$R^z6}6RUiDGSm#19aRjt7p8)m zJHE`PwhFYQOsoJ+6t#53?cWn>WcF+E8QZs&7b^rzo*l5UP5*X1uKMiW|Nnk#KJT0# zv8m4R=CbTljQmDnlTUjnv21c>aB^zV&_6oq5{C${p<)nwkdwql6>pY**DTg;zGwAO zBeC!6q`UD9ijR1m9?X=zB*|1+bfKVPVunnXMV+%)2DdTGEG`d*XB>y#oE8!`QJoQg zit8lT#a&m{#opf1CctGfWk$~l!IqcoNlc2LoSt7?W|DvJ4hM7YBZqgK_ZLshys{#2 z<tILi4atuha~ymoxjuTx&Q__ZEx=`B-1$^#2ERmtm6O7*gl&6ZYXMw9i-%NGeN6q& z99pTwa9L3;W1)d4`^=42bN?>LUew>v;rYr`M=D9^Z>~(Aq(}0k-&P+I4yQMne=qTt z7f=H2bD!j4qR*&wq~(Rd7S$P6-|iIqUk;mKu|dc1pik3J#<yHfA<}i)Ke8O8I-DN= z|GdFHgPE6e33F1DgMdKIu46rt$t@i&?K7e_On0`rkh4Jc;FYRRC)KCB9Ga@Cc2eo% zIg7_UpKA}EKXUoNhakp_huXC_+IDcRD)8CTd4we<_^fc!#5M6Uue6oamKYo;yr<l} z^F7PffHNEmG!H(Xcz@v%6DB3KTY{2`3Q3a$V>I=jE$ma);9LBXLyE^lY>Kx+6Hh$< z9H&Z;N9~Pnt?cFxPs|AW(AgB?Gs|S9$|Ihl!_M->>?tg{9LWzHc@=+rJT8B>{E)DZ zlEth?+D&OJ#q9ST*)GI5cziHDSUGK*!P*IR^7XvO7#UAZnIZ7D=~&yhg0!W!zZxA9 zi@e%r6g*fyOI>Py$dQ(vkKTB%>`XcIU%iy!hj)v^It~Yqj(1PC>k5K8PmGL$lVuKQ z7i%kio?_sUR_1YyTXI5Wgz^j*1)dC71s&a}Ee8LETH4k57H9ZXtf&@DpV6owG_S2u zL-LjT!mSS*j+|-aJSMzFKE=JQKqqd`4G)ovMI0B?Gh7R7+V4E*=xSpQ7E<YKH-ETg zrhu@%P`^RlqCT6(o<O!mIn^gk)LhgT{`55SSNd?Oo8d_1bd{bTX9F^A0%yo?-CIyI zm4ne<pkcy?*@^L<E<Rh>i$I+l_7A7-oRSt^CVs+g)%Gu&_Ugv&x}tRP#Ouitifo+< zkqUh?XC&=lTg$oX(I&xk0f`PaJL#F%$`&nQP80Ld?)<wr_n>-f;m?T<eC**e37slR zDwfhG)8=JV8MvyZ?Pz@<=+{%ml{?Xe<3}SyOUvG4`Cdv%i)<$_Gl>dMW~!R{%wWCK z-L7lQ_XW4`ot$IGZL0V6w>-;*c?%j3#fW{EagF-?M~OkPvE*@q9wdAlyE;Ajdc|L^ z{ZZrKcf!l3$i&k^pyFYxxXyOYB`nLsI|V)nGjeeLi?rzUM)u=Q(fb^SIts&%#=A_? zWLkMjJ?+-H`gO<4*@K++O*%K%I{kXbJ0Yg03Ji(|FG_D->T<-TT7eyOvIE2VrszT! z)t^$&m^Ur;;%a873@}*j=yhVXk|2|#0)yhhglDIwYBy)tUCPypvAA@4`u~I7Gg!JU zC#t)&2ynd#-?%@)U1t3?&hTX&icdBys<QkzYiHWzd=>>2m#u;))h2>EN)U_m&qjCt zd(b;q=V;3YuTRYki6>S1nx_cpstPhWDk&sQl8U`NgN1Y7tv-3CldA%c=TB>$E9iOP zM6r`D@20iOf>&(Xpxl@DUL{X?v+l#$A-ZZVkxDF0ZVbMh)xEa@9XVL_Dt9VoE|ORL z<Je;uI{WpXzY_!vHJkbJSE}q&Tshf=Lqv#C>(eB6<{~BaGb!2=XJ6LdTB@M>WFljB zr@#quCIKO?f=R_E{12|2CdB>2W1{6u8RsY7os&9ds6^^^t)9pkob^Q`_vw$muREX5 z+uW|cPyNa=$8M#Qyo_6v|D3Cw-STDPG5h>U($i1fHn<wNfy2SWBZQ;yL$H`m#Dia7 zU#EXveM(tv&xZvwRVOMg{5U0M$Nzu7b%R!1P)eGV!pg=clObtryz*bvi`J0;AKe;y zmI$PJa6M_c@F-?!MDW8v$r<;}9v=8HHDrC9ZMa71et{Dbj2tKVtluQCC~+*zvhZXK z&h*hZ?{IdlqI27hyJfe}3UPkg`RCK=W(hyH+^!iNGg7uBmJ}umE)bAEGV_R!fQZ&3 zuS?DiO6>{mQS}>?SI%|eSmLG-@rqAzW%&AeqI-CpE-9*oJgWQq_4?ZCxSADFejCp@ zb$5795?x?p^Qwr?uv36TnMv8bZ;QEX*SoLp@87>yp>k62$CJtaYYG(8r0)p@7JDo8 zIBcj<%s=4ZQFgB~9keOV;g?VQj5D*%&)=<nzxSHGCf73G*=heYTg3z?t7tc9btlCN zh;#~YXfsuObq=U_(Y0XBUN6X6#)B(kl~@inFtjYG`}=FzL2i)ye#{W)R7(;%!u8{h zT7GDVIB)aXv(Hzq+$o{tV8?QTbN;s6+q*zDf9cy>rftT)`CfZI_R3mc^POjNbBkvU zs1bMX>@F{kC!CBNC)e$M_i9CxY>SGr+Kf!lre^KxgT;PFR5+e6XHDMVDAc*JKuA$Q zltn>f$=2r!eI{*tcXzk6r)JwN>)>TR8!JB_eBV|%*)Og|MQiu=AIBt33};#vFS}j) z{jRP|<z!zo!-md1nU|OKN*gA*1SJ{O{wgu96pKnZ<++JTNv-wXv{&}wEc<@FT0M!~ zbm2yu6^dHCQYI(1zPxb9zWQ6v?8nLdwrO^WXD0USv=H%XakwGq5PWGvqO-fwmKx5| z1qv><)!)v9Pmla6ER`g*OsCXBbW*t==k!gtf_G`Aa6Gv1EK?Y=ywU6IEK_H*OI_`U zEe-STSj;{TUqci2@$4=qjusBaZ$?tRN4v$J=Z4ta{`KwcYqR?`pZ9#7>Fds_u9kQv z$UWz~eEpxqKz<=b0d*ENzd0HFrT-?CZmRtJEbZ09;N^aEFZh=J`}32}`0SOH!Ef~g zS!AutOpGqUkCb_-#GrWa&5n$Vi%Rk}XT9d~^EotQY2J$q3*UXeU%&l{v5=xbILik0 z&j-HC{Zf&7yufAendO0t-NZ~M=z~waSrfTgW?SLEN#!jQygY<iy8JIM^Zjfp^HrIJ z$(6zB(h^T$_qA%CnJip>K6@T65xzBLy-ul0{2@Jl$B7(`NsbIk42mD@1X%WbJ2^3E zciG!X{H&}$^Z$jd3OTt+WjfNbD*bi?edT+{f9E?@U%XMV<izjQEJa5*{qD-2_ojAE z;7?tTPYyntG+8I|8J-NEW+f>6*Qez`y+Fj)tf_}jZqZrzz`#|M_oIiK)1--_`&Ngp z4%3|USWsq8(Mo?+L8eMa1s2a+KX?~1w*2u1nZsx)n>1;?PU+!x{_Tgwnl^1~NpMeR z-tbP4$;p8uq{G2%{Zvu2Ros(61$d^ky_V;aj+6iERDSxfIVbAh6H(Lv9iGzCARxe0 zr_7*uv;P0zyW8*Ay)M5zF<<|Rom%UupmNaB4VP-215}(GK*u2kWUxG1zOrqCOvQsn zu}n42mB&<kB43^8a^Ggd(d7bCp}^A8aG#@N#u7IZ6RF85&N?9=Z|<*e0v$oZST8Vv zzr)@_Y@eu!YRjSe&u7hB<$X@L31lS&t<Wi*QvdH^yZoAY4M-+Acz{kY+4t{P_Ws#@ zHPs8%)LNas&&pm`IAuxO0uQj`og6rR^fI)7))D5tyR);-T=wTT7oSNw54T>A%U-%d zQDf2u1p)i#+czkzF63ZToKVlApt3f4dzr|cKm8|sp091{@SOCw;%@2n$WIz5zHsok zwIwt8sD|oNK><TS!;AS!t2kb;YOm5>UdYX;tO8o`44Q|!paD96W|D5<->=uBx$;cZ zQGzw|`ntKGbuWMNtUkT%oS_nV2sB>!O56b!rV1=Yt_#*omuXp2`}^Cw&*$yWZ+&^= zu71*_6i@d)nas>4MU6=_loaA`&Cpx3OqFF(BSXuQ<l}vyV>h~wHGH=45}d4(aKGYl z@3b#$O-kUn=U`NPV9unZwo*{kP|)z>@9)dLK|*Q)6U&7uC9kfWJUh=eI$|nlEAq){ zJ6<lEt@Dz1mN4j`A#gnJ7i^eN^77Kr+Fvi1BZBj+`Td-QF`%MW0F=Nu7(vQpDxXYz zH`(9r<L;LywyP&iO5x1k`BaSiVG~;9L~qZ_yS640VcOd5_p;_)LN~4WjA7ohGc%#e zTzr)FcbYOPDzLOTToGuPAXEKj<GaWG_I<Z5Fw3v+@D%FE-~HCC*u$w9+1~<_9`{+F ztNn7(9cs)Zorfy|7oT~@?l_SHY*>T92Wdu*lbq^v9@zc);0#V#N@||dK76~KZ~j$^ z1$2NBC|fuk$Y*i!2~yTdQc8OC{k`v7S0=`(YJEqHGAC?wW$-=OsXp(8-H!*&H_jQ} z?(CeQ;`px5`kld7DYT%RQ}gL$-mxA@gmYe8T%5ZZDFys-Ye+w{a{0Vh_v-)Gf}P{) z=o7X!D)lRem|n~aF`bBjSDPz7CT*|!n)Q24<mO}livH&B|NBfUeBB$Z&{ZL?^zUC? z6?*#Wy4c-U(qFILUdAhBQV_Z-r1Q_R3oI=Tj)D`Wu3Ye8_2)kd42myrZeCvfe((2B zmlIp6I%N$HvN*f=K1%=h=V#vbyJf~ojEx>DqJPRGKRx_gt`zyvgS+0gDR|n82`BSs z=WZ+Pl`<{jl{VA)`DWvBIl)^(QmX{OseuKQ1H;$Hy}Mg}pLf@4o9+Lv-~YRIa`60# z>S{W#rf3G=0Tt}|Ute97bzw+)AlL$0m(CKTW<J?)+7U}R!zK;g_<eV_W?VdEnt$&O zcwzby&sc4imIi?ibEcj4r<L0I&#$|;w|e)>%gf#K-Z=7GOgfVC=tyVYn;RSZ_LsiC zrd#>q^N01p%l$6QNWEhxg?v6)#>)=tk{1&St9Lm<%BV#k*ZR-5dpEcIUgtL#CW+dV zj+0w5FZc9(0JUUnuV^-eY)(7Nkifa^q^kF{9fgmN-Hch0bSCD9N%l3J8+})+4hl~A z?Q(Fs1G50rLI(z?qHj0Tt>@)Vy2Q~kYsQBQb$>n{f6Msq_4@s{4)3o1{_a_dl=wl- z=|641-AK+`+-tVUQm*#PMYny>VpV{b#i;gW!-P4-=Pcj7-G0CC7|UmiQx^m$BbJUH zsdRR!h)7=6xjW(2$1P4jP8#HQ*@Ui*GJO|({SP>EyS9Qlw@>+a4I3xiDLBmgE%Wxa zwYF1sm%WV&kv1*dB&_CRFv+O$Q_A)I_4U6y7KpqpyKtnnLEr;(qt8{Tx-T;q@tUaq z{q?mtfA80@hP^JEUp5I(#yHJv{S$i*fhHca$H)84b8eitx++xI23%$+3M8^9s63xr zKCk-oS#xEZ?u53ufFveGNu!hw4o|7<*&YF)DLHuFy6D2-RCJJ4e24kH3gubC90gZc z71i|jewid~QLx~4Qn&7%4T*<!-gl_jvYhB<Dmy(**Z2*e<&z0t@~(tJEtFzWP!W$U znfUZUSO1S>?bF(ZiWhG*Ff!lSeBSPL8^8QJKZ}PgKi0U<OaJtsnP18gR21+2bV^%y z;~W;2E`#97VsRWCjVBZt6n8$E<gK%R>Jk&CN@X?BveDF?hx=KAoHEv^n6q#!Y@0Jd zxYg^#1n^O8P7WL`@{AlOL1#9_)&Kqaf#2-B@)>SJNt=odi<9*E&!3xX{k*d4<NJ3j zm(Mf0<bIcR!!$^-<FG@pVM0vV&D3{Wug7tJci=YI<<NPu{C@3oKkK(9m-`&NG-jxC zvN3XTIr&{!1ln^L<`V!qON~X~!*Lz?#?GvcP7VhTj+Bb8SHoF-Bw3i0)l}S-n_qgW z&rPXQo%BbcVgJe6?|0KBi@)C~KL4j=RU9~FI4LNDim}6@9ELwpPddxkSW@_o<4)!C zxzFDAzCXFJU2ax&b6}R^zV(4oYyb3x&g%U0XzjgIt_;4MFOA|VpNcAqZaLOc^2xU9 z%Lemrda=7iI11)E_}l$lGVw6GT*ZM)kOR+H80RX^T(C6T*qy=2sN_Y!_fMzw)9Z@Q zy#ElI+$5~Fq^01&v$M00%k28#&%gftx3{;goj@xPMgB2nw}9fdQOOZB@T66_S7oW- zhu#?p`q_7PZJjvjFrT%LMLSEQcwEIn*}5MOxBZOXmLoYSFjE4o>ycZ7@y}JO*A?xs z^I%d?1Fy1!9z`~(K(Qfmt^a&GH$N%!JehR|Gflu+lt8KQ>(%hxpi^Kt(&PV4DZV!2 z&%fXA#r}dek)K|y$f?fsWa7@B&t}VB3<8~9X2HHPkP}pkbg?jUoZNan?)8N%@0x2f zzP!14`O}m;Rj=0`GJC=?r}SE6-q~5E)1JF1fy*#?ri+}Xn<vE7|NWZx>B-5D(QPv6 zQzjovIWxmBZC~a4z2A#u+VakeGl7=N&Mft_d^)A3bY&eR`WEmo2~3)(?7r*y{Q9^X zQydktlZ>jr<y>FlDSSHW`kKhi5lp*5l|#}|uI-ootdFMEfz|_o4o~8hGU+(G$3zfZ zgH91>m~f}$vTvVN(WFZpDZV}{c+NEUD!Kd=bDF3r`POr;RjJP5H=yaIRUs=UeJt>J z{O`kI{@tK;@4e>tZoK>da`}AFIh1FzfBksee}2bVgZmC0x0cVZdnH%(Vxa+laI!F{ zU2sH<QE>7V@7bb;3x5dw^a34p)s!OzUS0g;obC6R@7Lq&cb>QVeP#>855GB8uU1O- zgAb#0>y_%eWw$l^`nKQqYd-sKPdPd1hM4S~y5Dbge@a<+L4rbIKgR;iolmDl>l|%c zV!{+DI2qJkTij=L>fw*5bu16tzm(5D8*Q@vNaFOEB2UlnJ?xV9b$c?ILCZHk*E+6l zmVJMKnSaZF{|d2vhWr0~>UI@e_|fvo1m`m<t{S?EG4+2wwp%}+Q~YMP?YA3;-yO`E zsxd+A*PB~gSBq-66r{Ymu(0_r=*Wz1|JzI^UT^*KN95Y>@As-f=gjr8tlj_bS6Jyz zfuifN<&t4Vd$d@7y)wSTq47F<$8~kN#my5QEVj(Nw4}o4#PP@!AD@3e&)4rtJlwXk z{9fhp<B2KPM5HF0<=)!Ct+(TV$C2Of_rJF)dz0b9;LB&HxcmLS-J<+Y4tC4F2c0qG zRB%MlT_V%rwzI5!$BBOXe=iiGh1GmEq@?IZZ7G<YyKUy~4~MvQzq2oS)GlAQ;l0gF z`}%#WqqncizO^OO^Mv@D@|&AdmmPihKeq1Y(`WUEEu_qHGFUi`Pk}a-+rPTGCF`oz z=99lGzV7?|E<2eK)-p_Kb|}k#ARrW%rS3OphVSx?`_z+@oS00x4vTKGh>w&P4qH+F z{@%9>$9Hay-Cg$X`TY8_tE)mcAHAJ2+1JOov90N&vzb9+&8L&<d7wqU1?lIfY%X}{ zwEeu@Z;8%>cNkCJ$XdPj&WgarcP6^a?G!Vte7$x%C;_BjckH;(@nCk-HrCuz-|yGI zU$^5CmwECr9`n*yA=1h}U0$T$ExoS$;@P4b@<)1Da-a?H6Y@*~Li4=O+kE!<XVvTB zFDW?LwOj1wVX65%=RLOwd~TVspz}aX^OZG`n_F5cI*+8CofT?ivhMgBP;EY&|J2{_ z_w%pMulaQH*&VMu{{9&cLT2k!>z?`6V|*^6dxlQzt}E|cZF0T;|NHB^x@B403b{GO z+i&OX7D{4LJalv0g(l0@RbO8%vuy$&N(wr|Q=#seDF>%o=^6o026XXRxBH!y`;3Bx z!X=I-r+&?-xO~V^+@9Y@|MlAK^D>Rh?v@01iylAD{FX!BgjGeR*<k_a$BvU{W*VP8 z!^HX7L{EUTgY}lEzfG{;qO{gJ&`R&{)nU4qr|tRuZuc}%@l9V&DEGJY%`ljL+0Xjy zpMrDt|7-r5LGzJ6hl9tvozLZpbtgP=@G&TK@Z+=l@u2BZgq)$GtDQ=7$o>p>kKfg2 z43E#4#_q0cvrxYFOQ5p$nZ?oD^ZG74KWl#fj-!`?sDQvb^|N;0olAby|LB~es%G&Z zX;tN$jmOu>t~<QGmG}F@cKN9NGp2ziu-k942m3{ssGVV*EWCt8NEOmkX#_P%4}ST7 zCD{Mz^1~coCv7{H^7PcyZwJ($yDwa7lXU2Yf<lJ#g^C2PMwJOKr?g~F(B2~Z$9_>k z!rB?eHv2^vr7rWCnPll}v-8s_ZEshGk9(IJ-ppRV_sq{}-wITYCYBv+VtwY&UC-&X zEL0}r;+%wEidioXvdin3^r-$_?06`1d)C!e3neGBL5gW(CIO*4T=Qx^owV>bUcGav zug?XU58KX5mx;7^NS`>|XZ<eXlssD!XexeY+mbc$tk2~4xq}+&d>dxe?|Cou{H>ty zFGWe|sA;FBYEO@8;><iZ$MV_a=F7U*7npkPQPZ(lWT})h%R?R7*J9~+xYFTix3}h! zn%WHQu=R1d=N3)+pXs9@<MP)f(!kwu21h=u_3(jXfu>`z-z+ZAOqNS(YEO0@2n@2+ z|HrJLrsUM|`|IoUSrat4pXtcVdMYdTH1x`i)&_wNAtnK#MaJ_h9(5jQn;Y9U^+4O? zvcs9e!bZy<2~-_mWM6W3hh7gG(~|q@k+DgC7iRRtEEWM3;x3>8<3@>;2h&nk8Y(WC zV*V<&?53;4F`mZr_W$pgB(^kxPBs-_a#E;ZQBX-f-dFngSTFa!%^hDSY&(|Ht-Ec* zF8w&8jU8u$59_isDiyuDzCK^j8JaIS<QO?P<x}s)Nx$CGdD80jn&gwGR6e>myp}#+ zdUZ`pg8+v*lYr0}%M4$YrGg%_XLuwF-CwKR>sfO>%vhMoNns9Xdf|+s<#HA8BqjOD zKk{UM&Nxz@Yig{hz;dXQp{3=`dW!>In^e@gPIbP&78v4(tWo2MyR50_v?DH+K96>n zPC2f!FMIV&PDVumH<o{YqJxdXj;I{HwB&8_qBH9g@7(#<<2f__@4>*e;1=8^P^WK+ z=VYCevsAo$J+EXv%~*KZ-C=9drQ=@VT%bn59|r~}r>(!+<*H8fKTEpmc1voqL8y4& zRj!r<qg8q`O|BONS{ej2v{)2WCae4Ng)aTMLC4|Nkru}Ho6p;U&qswUJh-~(y#4>0 z@9%cMKbGt?s}<D8Qeff;IKc0Hgqhz)pz-3f@(xKsVGqvC)0#ijI@y^-(o{rbilE(K zaHgt!xpexSzu)iApU<a!#oO&j%Ed*ldB5LoFF!q9zZ`UiYs<2g3)P$-OpmWCyt+EP zJih+#*4tUD*Lvx7X1RK;-2}E%i^IVK)b1<4U;EuP^+cs~y4#VKK-t<a7vEiQ<}Y17 zzpm;Y+seKs#|P)E-<SOVb$x%xYDI~Pt6AGPIwaG(=e+9{U=o-Fnq&lx-3m&T*0s$t zG*o<kbVK6dJJ#>_Or9^eYWe|z8|C+F?}F-{O&g$NKcCteT2f9;(abwD!|>;86D8YJ zAD<cFx3}fq4Rn`%TJ`OX<iyOZ8L5IhUa#9Nle+yQ*K}|UwK&uX3K)9!mWLgA^7VRr zxoy=KgZnI=CV~gTIi9a>=Cjh6C46B;E2wiX=*HlCQaXRn!*@HM&*M0+G-F}9tB=Gf z(78GnWv0hfWf~|4uWnQ{sQFRQy-q2{7hFIHF#U9AaQbvDI$!gYDd(3+VPUx(-&rPx z>mU97c3c1d>Q!=^of2+s$po!lc-PEtXON@`E9aCQZt<Q=KJyAx^!xf`u!Ua9-G2Ak zz3TV252XZIzTK<NzrNgGzWkKta+j1NQfYyTAD-Xe9J_r*+M1JMnoI(dKu6gvQdYGS z5}u{x7{1hN>YcUQ?`h>Y_kj=UsQddh-0;hU^^@DwSy~+a2sTXk5M*EV<;4$wv%`|l zmKZKvk9_>by72XJl4a{pe{N-%{r}nQd^6#5Y|=Rs*5_UA7wAxBO7z~U<Qn{Cn`HW@ z9!cXnvgLOK_a0=oc{Hb!^YQN&i~D0<Ut4>2jWd&(=MI62KOc{ut#SVK_*k!Wdv<|T zFDTtC;1Fz>Q1jzq`@3(q^YstioNk{Q-@zF>;UHhpr#G9=?*cXC9grIGZe9gdQ=t*~ z5Ty0b$K!cdRs@1a2OmfqCdT>O|J~9m=s(Nk<kpOfN-4p*`yTqtwYuuT`P0j){GE(0 z!;;y4#d}#oW;whxQWOB?ugz&^jl7$em@w@V5}sA}<)XXpPpN0kda=7W-ZLqFfF7q& z^k(C6u?&${VUTfwNs0<dld9r>`1!o(I#d8!upAy=yS3}D=mYc4?ca}z$LBnm(9{hs z#vJSfCj8T@opNzX&99fsyE1&4A{CCb)OGxO(EE4EWWOS2HXe`qttF{`95Izor-r#n z2RUt-0!`e9+8H#>?0&y7E<dfiy(PbZRW2~$NK0ky_q*lOo~JDCH8VQ@c<uIkyAE9L z&Hv6Vu2-_R`ujE;)fACCX|r=5Sx27r0XbKokVQcSwDEdrA;($~4^}Y^!;c5#Y$`UW zPHddxa*oq@i}ka5=4#L}+fydEv#n8ea^MhQWMZw#5MkU@Ia8@6<=h<0cgtqyo${^^ ze5Im)gv9~0W~;j5QMFOd4TH;zJc^tdP|nfVX}V%JIPW+q=yN!DJUch{b>5zj$M$>? zU+VYC&4(fN=clL7@|ipv=LkgUoaAHFVs`f8U_Z8gN!8a^H%*u9hPFN4b2xbH`}s`T zyy(e^J>O-&@qPC4u`!6N`<ZH906QrIbj<yYLawtvPKa=nc~93fedCd(4$Vp#iVTWB zzunHi%WHl|U~S{`#4W6fYWMa;%usZG`SJ2K*jj+L9iV=}*Z24Dzuk5_uX09_$!^e0 zQx0?THqgQ9udlC<H&I^{$PFsDyO<h3&26wa&nd9;->=u*Ouas8kpW4E9KzQ`B(BmC z^JGbVyVP4nWr8_}=hm#NMv=*op(z2TO4kLCjQW+-R*ElqaO8;ety5FAd*^%r4ZT=D zn~@xIeO>J5T~iNTx!J-geCNi-<hxH!PWGLBWO>%rRf$rIjzP<mNTr5lEhhY+{W8;Z zpS<4I<vH!XGAFO0rwW02qa*Kg*M9?tYO5=Q)251#N#$?1UKcA<P<&%sazsUN@%nwg zRy}d_&Cub`>hNl2<8|UlEpwh_TfOb<$BoD3HVb4u^Eh^=>g%i2>kHlqfhvBE#tX^} zia-DTet*~WdW`U|jnAqZ7OJUrCiu)YTidea!-Z#zetuJCnPxwe-aO}b^d{&L{_QN* zXIlL?r=2azi{^!9<R5|!6Lg}toyj`o>7^_nnKa4bO{cK>E$6wQ(Yn&Jv(3$e`R7}e zzG}(qeSUuadxOiM4E^uiZ1eM_Z*E+KpLpQ`O6wE2nSOrvI+41ib*H!!_|#@WWjB#D z2E})#la8neo_~3H`EBO=)h{Mz@ci#-<CVSzn*CW<_xD$2G*g$+*;%Hi&(5*D44VHr zQZzx0Lu5Yae5PERS75^xSPr!_v^-fpzpf}ewlwqyTlfP(*LgFh9OZ{j`y?I3nDz-> z7gM<w>C}ryo_iAxHcjgPe!u10qKzLtCVmg+e8RQo^wqtf@=zg#!@<L2y5qAv&rFsi zcb`eR9}s6=Fs;w%a98^I;osbzH6LQvMs4+)DAWJo!IbEwUZQUe!CiMoK@A~iuOr<O zP97Czyz+K?8md+2#EP>To)q~7YLL}97@S6#3~8C3;MMKX6_7mX<)V7flCIj{-}o?Q z2c{lV;WPtHVPs!lH@A6#M~j1oK*x?-Rw5G5N(Ee#{7z~w`}m5-m-FY&Ha=OY^_@Qr zqy>cqh2^(RoCO~A<!JN~XqW&RE_v6bz3#-5ZHsn<9Z@-HH2F(Um2HL}baYdJ<&PVK z)2HL|^*a=u+kV_Fd2(CW&~sDEl0*5Im-VKmLJR%|$e?_D{oki-{Bm!~FHg+(KcaF{ z=-gcE>!9tjj-UyXce1ybq4PZ{b4#xkHnZ`5g3mnc|Mx5V`l?WE^l|>G*K42a?f+A> zA2frcq^8;7`Feln$vIBK!j|9M|FJLQ1Si-@iVTW36PkJNq)v}jYdEE#kTfa9yXNy* zb5LE*ceWE+c7vw396Zc!WhjFRE2xp4(<Z#yFLD<YgrKGc)P*fV>Y$~k_kG>>*$Pfp z@&564`~6+a{5BWBUI8U*P|!FWQ88Vlq~^H+)JMNv|NpNne2f${|8QYSz?aek4UEvq z1N148kkw&lV~b9z21-{wcr0q@$@CF4o(RgH7v`X(h?L8|=B48CH5=j1*^zLN>H3z; zVD#VuovyC8>xB~BZv_tzwdTFw`@IZpw&u!;z{9Z>4_l#5o22t_k!yF%WHnzI6dx$4 zMCa{Xy8A&BH*^lHV}?tea5ht+tHa9v$GbMonr`eAv^q?;{NK;#+<itI9WzvJ3W4^k zSHIcV?u<6Ivv&KvTXW0rRU+)1r0RX=-R}4A6u{G&mmC~U^_n<bQgwPz51NL&#|sKt zP<a-6xQ!P*Xmd87HCtEz{~yA%OG~})f@bw0rh$vrI%NjMmC@VRy}rJFJ|ysj1t*`# zPx4ie;`sCPyTSF|V*#dKiUJl)0+T>TuFtK0x6|&6==%8S9iEePH|E?l3g2H>+x`qP z5-7j~id6*_>o*&kK_gAjFj0v-^z`)f-E+(D-9$+p3{FAo<7}^Q&yR;k#|O}m4lgrk zX4*%fW4e>+<e9Id6ct#E92uMraeug(K7a1XT*3Wjdq03u-RVD%`|W3S@uFmY0ihVS zb5^f)z-BH~RBL%QujG<v-k%>I^B(t_`*G&%y8d*Nk&@cZ1<R`;75)Mx(CVD}Z!a$| zU*z5W?!Wk)8Gk;V*3UcC!uhU|U9LcX-;YJjA^}{x)-0)>E3f_IvcLVz?Iy`66K<S8 zH-X0Cz?QPAtA%_}&EeYYS$Ra|?(07h6X)0eyZPv}A~+U7eIy2^mphe35)%HEXeLdP zI^HBKoSz|I|7T<NogIZ<y`IaiKiyOswk9G`@+V4MH7sknq`tTM`?uYh+4`sYekiGV zZaZ>ns`lC)LTIT{q}%p!k1;g-p=lC4D7-?EK{4~vlFrvxSBGC|llxKO>NCk<Pu5i} z(C`X+Jc0&nt^a<x{1-I8+d6B8&7Tj4^KR#EFV&6OqQPht8$Tr`tc_!V?)E#E90QWx z)lcR2*%c1S`<q-CoGxw248FcO{k%?e$NSucifYE`=S<ucloHKurU*OBnB83FD{Y>1 zq+^n(N7-Ea)1U3RHdTGi3SaET%kIe8-J#H$s%pXqt|H!XICy}vy`S~lEqA25Be@qU zs+}yT{d7`&?S!~}lBp7%o@c(zU8W2gjn>FwQBe8)e*b>!uUCSN4=A46X!g?I_{x!# z6B87}9%OtzYwlm~W*4(F?X1*mVbp{(2~>W~EjpzM&N5EEK3uKu*6;t9bu%3vbD-q} zpru)Xf|FHl{P}h}e_hnpEY!*;!;9mM#m^^`!GYE}LnZPMsCN>&GUzB;;=i;h)muAG zTeG*JqqC#4P8b|N0ZIbTGh8@4SBI?y-Sr^h^@iJ0LvXUni~qmx|1X=W9bSf3_gval zntgq-J3lz(fhT%Fr#yiUZ$U4yZDQ5u6g1uUZC|qYjq_|*&?*AZu?J>15}477Nl#E; z^y6{)_wb79-`DH$d3(QJD@H3Ow`5;GCtH4}5FBDIKIkR*mi+to{@(xpHy)hSuK(Q4 zE;C=%Ng<czf(Ga^BLOBSg=!WB6<O=DlH+pKIp2DZeDPCOtGaNcq?CEaHLKTa4!3bG zNHx_2N30xZqG$cq4$qH&_-baZ?C8`tSOpsW?~-9OQJrg5T6A}Jxqgw#wR!tGI=8vF zadgZ`VVSNc25R}KfEL0m^%gHbV|binA*dM6@J?xI=<swac$uWAz;a4S;Cab9$u(vz zPfjTJm$=K<mavtJ9$%`Yc68&peP@G?95L6pIzd2y$+d@}Wl8k*yl<V;pPaLC^?9^a znQ4A+hvx%<)y#?tEL{wY9Gp>;7x!6d6>UCiw>-NlSk%yyUp@9~JZKk@DCou<X(mT| z#?NLGw^}z%c)-wY=^iA-C@B24qX%+hkBt7gSk+mN8A^5w2rw}!GAJsZjJm!qmid+9 zuCrY;T*}{a85IdmZaT2e4>SfQ$s{23>Z!m?<<8Dyp#2y{%jehalD4VXAZ?NnaB@x9 z`nb1d_bQUZ*G8Fs|9sv)dv7i1_NjD-t8+k}=>*NHruMHn_5?J-vA61Lk@dSBi)S0B z`<>)b_nVWEStppP@%8`rdG<+4#%=#sFBfZV5a8fu%JA~D`RH<eXYun5JenqtJ4_6B zzFao@j{5wXN1!za*LM^qGk<+D*}rUa`uVc_{eR0i4R^lZ_xsL?iOP3D#nq87sncVh zU5l@;{r+UK|E}5j`)=<2ey@6)W!~PeVcSot&0g~7-{0@|%RzTEfsSIzzO`i~=(?hq zZZX|8_d$p6Jv`jL`_xqJ*=GxGZOH^plYjdk^i_UV?1Y03pWJ<nB&O(zg5uqUhjE^z z&H5Anv^0AimUM#8Z<I30cu;mLQ@#A>)9JfSv#;%#Wtu%J^Ev3`l%!90iqG#n%x`~( z<HWk%@3N#9f(|V?V|=~@RLfWY`FQ*;r~z@#`n^r^dfTcm9=~e;|N9&J_t)3E2ifIw zzT1Dhk$mmjnVH6SH>I9_GcSAH&SRkSg1{%;%$Q=Jy7bljk8Xi3K8to_No^JoU`ljm za4LGWa``UhJ`1HBXYC&qO1?gB{c^dt_)Wy;*M6Hhv0?K$tJ5EAXPf2r%-HZ^f~W_N zQQ8@aa_Fqy#oX<8%ic|k&MO2RvKGCsX6Hms6S<T7+NU_UDOlRfnP2xSvpD9_yyf$% zPT79B;LK+%RP^`j_1%ijZ4!o_SM4A7E;=%Q#t{oU!!BvPZ^_e68h!JglhkA*U2*bj z41bqsd&=iN8^g-KU$4hrT@`xwxP1K^(5BSz-DSDgH>G-mPDqn7YzzP`$Y1*Go#inn zg$rvG-rnABUVQ$X_4}M7N;khRcI!1dv@zwR(C1vxq4Pa6zP!AA+(cDCjwP7?t)tJW z*Y<a$4SzOD)+Y(Q3%&RPv?PL^NkHh2ign2gfqu@P7TqU=h5tC8n7943-foK;KhS{P z_s9MA(*!2}{eJ&`M_0NP=-`h#i(I?!e7l|h{zv)UU8Q$t=kLpWCjYPZr25V8;W34+ zGkf0c|6jK{m*FPp{I8xF3C|*Tm8_iEI^pBv<GX|XERS}0uKM@=UUk0wbi;bz&KXbm zv%jjav^dlVHca^P?(XflB-N#Y9ju0u=6Q1_wpx|G+5tMYYkGX$&XySouNn<Nn|j2Y zd^!xD%>vDE{c*MX@qqbqor8~prND%g`_4I_+H2qMch;cVtsJzT!f9Ig+Nh_XjhdHd z+5G?W`I?yY+iv}R21%1v{dbqIHJMZ$ctmB=>1B@GjEVwAEERqq?i{dn5E4#e(tPmw zob`JN#v3J<eeZ%!i+DB#bU4+dYaeWH2^+m}3=>$Cc_AZb_uFl5X$q!47UXQZnfC5p z_4`tGnF5DP?=RLYsG4n(IcaP0yPeN>xyw}^;Sh)tSyY<0`>mPr=PkLnubrJ?cvv@X z&yG9)7VnUBMM<oOxbt?Gy**^MrKw+ilhkCN35TygnVr9{aR0wwt7q0!?5H~QegEHY zvwu!g@mlqM|KD%X;d`q}!<TxAb~8O<W{liXurT}Ho}F9&K4|8jmXVpUdCx!NneGzn zbj^~Kt{*XYW7X@(afF|d<D}*DIgkH+?5{tPUu1c1g+_;GpG0WI?>jq-&$bvBJa8y( za;+``Eo!^scW23s4$nK+{67maIVs41TE%hfg2MB^z4-F-vTn>z&;W3|Oi_n5=ro-y z%b2qrGg`83O{5eRSQd3M%$ij9_t(sq_BBBfu^T%)f0Vhba92qZdiC_;15iTbU=k1# zsy_Br)ogmIfZ<8jy-It+k1XL3j|~=Mayn2BYBaV_;t4@1zx85uK$Vq87eh<Snx`&h zUM`4*_a&=A{pAPyIUGFnc0LihzN<7lF^G*Z(`SpSk(0v_73Ccz8$l`*KtrP5`g^Z5 zsj6I>k-`6@p`pW*@4?G3P-Eyoy<o$H36gt4SBD*PkrIB}7z3&|SZ(iu*AxBVXA%(d zS{T6Os?^*0&4CYe*BZmTJaA$7M;tVH9euFIr|E{~>wkA&%y%?dW5(UZ5IXZ@i8gfn z>5ZU6uu;khf$N|WOuF;s+@iYPmxtI)bu)dMoWkC6F)9Z5a5#8??t|d7da)pBR#{ZB zsG%pfTI>@=g``D$L2D!hPRKHHoc!?caBR1jZc)BYnr_F8BRP)E^ZGhGFL11`1yz)c zj2tIJ!(&rJUxHU4{`~*#9Lt^6nSUR@_B3~07O*74V7a66Dc3f+DIS3>Mlm8rDX)}N zMJAO@R&j1qnH1eN;o&qMPp69sJt50h@Ob{My;uGH=lo);{l(w@&Aq>&{e9KE`^8qz z*X(UOe{1>QyYH*6|9;iS;o@*eML;i9j8RaaQHWE)qm4)MQPlQ4U8kcQ9y4A{gUGLY z5_0UaY=60^pa5e$i-5}ZdsVBgUo2>@x#}OJ$~jqOZ5i9MS(=H9o=32WIs0}raJWok zXi5Ps*FC_@-}6T151-A8|KEkw>Q1hjCwO9tfuNtD0HdIX5hKe<(8K^EyUc_X9@TTP zhg`P1C@=}BH5RPg#L>~fF~x(y(WvG}0jQTRsO9E>F7GjeWe>ZG4-=DjRVnA>CHEO; z?dRxlP~%9@lr&6g$-cQMRc%&xsI+G5$u?f;JKz;`p{t%~g{_fT?U`-#Qh0)a=lr?r zL>gBJD#Ua0b51=Y>@cB6#_|$q%=vS#`<|my4uS3=6Vv(*I_OEk;HY=6l&Q}ao!DI_ zk2p;JD6pvbG+hXa1$jneCPP!ol@)=Y3pOj=MZR3|*~UI6XogPYrXyEmBnA4d-|Y}; z<+P94nB=<c_=<1NE(+C$T;8WCMy2t(vbZRmW)V<X?A~7n8oDa-znE>e)L^E0{yfle zcCYX4-EIAT&*wYt^0iNXeR-K2zq|DHvv>P`=YdKQ&dD#<R_=70W1ASXF7ag&$SEBn zj4UT-7$(PDUgoQ8`Ywj&+V?QO$H#i_g4P(U3Sa*&Y+X!d^5grPW;{undFXO`i)Y0( zCuKoK!45q}mXn}S%YVP$%ir}($$YY}<)o{4?31i(YhL!*eDe5y#`ydWP{}G=e8x~n zEi!6~fw^{~(6g%-Z@4(HEOKISEc*ZV`))PgSuUw3ETxz0Co=6=7rT4c!DjZ|+UxgR zS{uFnT<*S~&xF)0qnDj23z5t3Q{kSx!LlRu+q!^kB?YFPDhG<c9%Pp<dE>T1MD>C9 zjFJ}@4jL&u%5D<>xcz=z_9B;P%agn3PSWw2wEfnsjq*%FYw9#s`V}$>sjYm^8Gk6{ z!UD&<-EX%QuMS^t)(x6Fzx#Uqe!av=2lktCPG-^DwM>UeX+j}WgqK{^3&raz0vGpe zm;K5X%q4u}_(6907=hy{cXkxM>oGpJ;pd|*pRb0;-`xN7kJQ&_g&RLqeVRT7<$?lO zqm!ZO$wYU#LSAVzkp)RCOsz}eH>dUHKEARt`1qzXt5o_MT0B2pi!l~s6g*+W$a3<> z$H#Z;e!rdm^O*9zB(Fpvmx`P_9o9>|gg88As3cA`br%$9%n^2&;4{PEplQYhg^F;) z@*J)dLry>c@FTqphf)s5JB57Pv}5g>XUa@U6TF!?CUpv{@2dTN*L?b2w?*qCI3|CR zsqa0a)tWJ3(~Oo3LlY4}fyNU;4ijvCKAD_1zxG?_8<|a}A0jv==N$BO+U=;@B&6oK zL)!#qvCY>j!Jr|Zb7kQZv*Qn`6nRg(&*(kl$@KkI;*FO$Pt?gwwPtbr1Uh+c@3&jp zTF&QgTB!OIwOPr@dd@hKENjXwDA4#v$YFxdOrxWqL*IYOdT>-vH{g7@sHM_FNG&l= zw%3=%ML~;2#V2U}lorpBcaJ9Y1RqjS;SQ{j*mSSGAkaibP-8B`G@(h4-fcWC=M>u0 z(9)UL>A<4m!}KsHRZyUjMId5#+1lSf9{1lhzhCosnr?L16X%jI@%4YN+JWlTiR(dK z!O&G98~q>FUtbY;`0AR-%_q{I&n-7|zp1<Zj?p(4RiC8&M`q4l(Bhd^xyn>fpfN*m zhI#(H+4l8y6ZtixEdF)RaBvV26RmmQ+4m^kTS&V@-2Z`yxD~gUPQmUso4Q@QRr$KU zcSg4*aZbMQ-?!zopMIjyFKIVs5k|oi3XPzJJ)oAtr0buyg8IOU4H_R<ob>#!>BQ`~ zQ2XOyJL@5ig<lTy+ehT>Hp{(rW4UX$n54>t-^)~diq6|yvh|wbQuWiMLQsHFo&|KH z@54twqjs0QZECmU{~xtA>t}}I_RtMC6lU2letkMUeixst)sD&jb~m@?-?!V|e9|Fb zNKLX~#u7CZpGjM8&05W&(tZH6{XD6~|L?D_Zx`NM>Mb6=x9aN&N6-=8t-I6p=GT1c zJlpEOI&7_yp*ZJc51rr&HqAt#d0Q`dxHzz!a&Kt=_PF0ZkN*Rxw=Q=tc6V8Cs7ctI zqM7%T`)!|@-LEO0{TQ?s@sai#*F!36w1qDfdd_GmNi@*`*Av&)L_R*&FQ3o<`un}= z^DP|w+1oN7#oc)IaSdoa>-)UByLPS$UEP-TN=R*CRNn`Fw?is_vX=;UHE`s3F*p|e ze!Knl^4Q&F-vZuUSs9!Z=sU~gq|2!-nV0W?j+30ffkT9I@{xPfUi!uyQnAh3<;CKn zV9x^T-L>&br!_4petzy7!?TR_r|LNiSR~E-Z9cYa1g-nL6BeC2HQYu>t@5b+-gBxx zi?*jpZRAjy%FvW@pn*|H#V)Vm5Yy87|NqniK833Id~&s0^w(>KOUXl%96=9(M$kb- zpia!&4Tt&iE-Y{qD_5yZJscmrPN3q}5!Xi0$$t57Zf(nz-qHIhZh~>*rz^q!JKcJv zT5k#O*kdrcp!Q9xXI1@a&xoqCfh<n`4GzhmHMr;Pey`d6@tE}8%;j^%ei^oxHt^ei znZP+^alhTIyCs)>#Uk{=Rnrf#96hCCDZWl9mT9B7+QnF@UYk4?l}XHNUlgCWeGXdh zb9<ZPlme5mr8O)TPG^f}&(Hw%H6~8#4q9b!Q1aRQ|9_T8Z_S!oX>h;jw656a|M&m@ z+rInPtJQZeE%iQo=JWdczo!>H?3J^<Rr~krb<mE3V*NcInzFC0nOXheAp709<@Ykx z6kpw`|Nr-0hjL#5zs-jROO=P3clTD8gC?SOeSLj>_x}HX-@m(4eBLx&riksr`J3tU z-=>|N1sdbesSS>+|696yp5dw=Dia$2zfke1*%SuKhI0gW{QLF#?a#x9KmT~#e?D@* z=gW*wPfn`+sxUijbz60*fudOb;Wl31kO|Xv`p>shlbdChn`OzQx9>-i_5a$#yyi0s z9@dyJ%UKjGu#|rI_0I0{{ND;$pj)cTLFfO+?X3b`>3#eAmc8fge(#uPTfM9JoaOPa zZ*N~WQlG?Eb)-X3>_^(08ylzfew-Q}SNQ+OaeE)0Ko9ZSi>~64A=Xpx2u?6KDVzOO zg-I#EiZQOGvhb)?lZImAJg+j22>}9yO`=clRlnbw(sWZxvz2oi*BYV!KhM{%c@L^8 z1?%fiPEu79x>xa-_qS!>Qvq?%9BwB^-SgPPaq{-{PbRvb`FY~@Da&^|9_yUZpS<`^ z`Tg3w6B86cn_JX;K+~k<Hxk<|`zmwye!cc?alf6Bc2A4vwmjzlZ@p&xNMAZjNrCC6 zvO|H1(u{8}E*}2l6;kBPP%m6&V<2Oac}Yck?lKXz2ulI}2t6+Gy1t;K)vZmY$=$l! z3Q`hMX0v`gRL0A?(eWQ6(@qgFwUnfoEg69m%Ph_J*8D6IRs#*ogVrMcoyV?d{$Nw; z=`N1R%jehKIu~;~Y0}i+N~w#5)OJ3dd*j}zjc+B^)!gZfJ-Ehij(DmI=k4EnHmrIw z?SSp~JC8xfmwdK8XsUc!b*Vw3_p`g@_e<aC2HvPsY<~FX=VxDyihZ)6vy$g-J1Ebh z+M0QGbITGTHFmj*1=dd{ID@XtOwaxQ<8i;5*M>a`K6Zb<1cz_WyX)J+d8*=Qm*}@* zmdmo`cN7yRy|iA`^G(I4h$rT5X9I_bqJzcH%l`Iv@7?gXc-SIyY2p)Ip4pSPbsR2y zd@M5Jx6iaGhgi5d`qoxhz2E!&-n$ix`-(uf&U8+2=C{4lm%KIe^07I=g4z+@9H%CE z&3M4kz3FHrTfAtV)~y3Uht97KS(y~=xUz+l-(`&+=)#bn>lJbYoHxx#`BbK{TbFb4 zCdrj;932j293K|-XndS!fAgj5+Fz;-`7bvfmwRmyb!TI;`~K-uBlVXW+}x1ZZ2fx8 z<{bUbOADRZg@r97K|`+7Rtf|*E|_7I+68LKb{=B!=DsHSjUj*E&$R5vpfNf1c@>L( zP6~+Hl95=-(H1<(K=A>05=;9{&@pqrTul<!PBhRg?lq2bJfyPN;_3{Jjs}0GJyYcB zemqq3st63@WM}ky@F_=ag)CdM&lID_GX(zTZa!;P3_3b;;=d0+4_HpUa#B<~?2D;b z(|yp?$+dgOdZo`Ait)$$J^XOsbMTE%iWj_>dQJTk5<Ztl_{27Y$el$?EjKHMe2n!9 z{d4W~hc8#>aCA7xaqRj3@3)$lTc1qkZT3Vx&pRIuJ~+S`bA)rZ)>GY7uF0Ru7QBA! zst|qX$@KU-L-ovW+8etHS!4yH_xxBZuK#LQFNezX1M>BM9)7!DUtg?xK-58X4oio! zGlxJ;!2fUC_fO59Af)zmiQ?vT1_s&Ro-U3dho<l8-mL1g;lM-_F83FgS~~Anos5<| z8^Q9(vq2(!hk(F|VAVS;dOIF4eg6A}@4yo4D9*_xCsn`f%Hb5|UtWGnd+Je@jJ+*- zlb7i-ZB%gR(cYH-?95Ez?w=}&LNX<Z(a+BqpZBTWC8U<Q*!x+lklM+Z^0QGaMZOIW z=H@&U*z&o7neRmD_gDJ9Oh@z%b57Hh_4~3cSjFek!f6k(ReXf@{Ft?i<H-bunT?ej zCa%}L&iee9lxfzD%n*J1XuV?x8Yh5`@|tv4$mQLYV1M0?yP{j_`KAe!&b?x|R91!K z*1Gw>R036!ejnzyf3y6TTB(Z9r9;#1bgTGG+Wl?TPL3yC44J+i;h%m!pZ|Q-X{EoQ z4D@c*>UEnYFYlNlTYkq-{jtIqw#pYA&5ir-9%|*jyiKf-tL*pN?b~l8nPy)*bMgmw zdC+n{S?e<nN%t1G9#YZR*mC`RyMg1^_q$%Nd-tH3UvI(t>*7nlJoS2Xa9_*)1GDN> zI6$M`rSI<CoV5Gd;s@%EMGiujC#|@~U2R|TB0yL>CwPMXyBCZ5w@ucts4=?dH`glC z$dRk`_V)bz|7xvV_mxdL4mxSn2JN1(uhpiYgZ<L(4ZKcIiXYV|_H-;em+8u7c(jdI z`WdK2v8()jUZdCb_3`=qb$;3t)!GULzD(ITIse_&@c6BdcSpn*sjl1eRmwQ6r?qy5 zS#Hz=)hPy?JvukVQ=(^7M6Rv>^-|sYfyYC8&ZbWvkH48Z>6L1As!6qA2Rq|7KhTbq zXsMqXIgSDsguPGZZoiv$GAI4qoJ?oM-JqRLx#}$^ezqwnoVImZRQC3kn9i4L(fOq; zvdXz!g$Fur9)0g|@Y1SKZEmw$3mln+C37k#+!0f3TiW8XZAp~kBP%ifeC_u4oJnmQ zN~PZC=h^yh0aZawlZ3c?{&lE3v6Q;-g{j|iy&*8yRDR=rjy<RTc-)a*;xU6|;nH1V z9R2oNV#JD!YQEnsudJ><^)%+{bPkod42)Mic&4v^Qp3Taqr|ZUbTjzG+q|pUqJ=qx z|AEfFzHKDPIQNHaONx6<g6qM+>Hn2IUAkRU_W%86e46#zl>GgFuT5;{V{E$NI77h< zv`i;_p%ZKOqIbDZMZOt6Jm?n``(8qC`P37x?$#W_i&i8n9-MWUTlP`cub+2LHS(YQ zH-o)N(_^9mr;~T-XC)st9*Kl})!Vt-=Y~13xF{TB>3Gx2a3E?zcDwI}e?Onkf7ai4 zv~g{J>FaBepQ6?%M5qg>^>pV-cB#jFXidDc$3c-zBf{cF-M%lEyw5V3)chzA=G&Te zwP^R-ZPASek)R7<R|W-f3a>Hl7Sq+*^l3?2qxhkekB^S3wP@_IQCcJ5^;1lZ<%mj< zbq#1d`+oVlmd^Z;RWI&-*|}{-#~zLj2P2LRrH2e3eqwv!HC=2PuMYnY*NT;4a<yLq zH@8e!BbMl-5|v+5^Yn^9VVD5ZywukJ%AGN_r**gAcqz9=RpnUjr6rw_5gC^^&-fvz z7LjYw)NR_{l&rI;C3kK}XZ~RY9|`S$dUMt}-T0|1q*mv-GOkf-y1~V>3QS59c$v=5 zHaFkTXLRHF;tv9<JCyxq$5np6TYmO@Z;kDoYX^5Vezr}#ezR;<`1*O4E0tIZY*JUZ z>B{w4Kjv;faqxX}%9e<xf*D8eGjBW`=9ifG>5TFDhy<fKiGrT<`Z@d7<+M*YAmGh; zJ4WTg(z_vtSXT3dr5$VV_uj|#*<p&pnLlEj!uywm_#bll-oVk}aE+tjR?AxUNBK_{ zZ+Lsax$e=C&ay+twD)urYJFI<`P`-%N<WG#Zfp6@Hrx7kI<K_Z41<T&Ej*7Hm!H>O zx8u-6w`N`0Ki(QHu16=zpXQ9V|Iz$lvC~35$EO~%ypKft&rq0FuwiLFm*2LI<+5cr z7P=%haXd2dn{AeRrqVp#z0J05iO2!L9a&db?VA>M=!m#l=qHXRhku5CadlvM<li6@ z86i+{m@hj~oBiT}X<Sas2b~V`vnDn*JaAF`rx{_w)h(Sg`9b?3F~QOevqaWCzWS8I zz)r7Y_950r7Y4Hy>E#7K_U~A8$gnlEKKHlCxAV6@TtBZhr8KdvzMr*6SKlxEm!^;! zXxxC2kyH3C52*d5a6pWMA2e=jDSbA5iLd_*5&6aHK3wgVCp_8>Gh1}^TxL914!*WU z#pjgLlKbL{3W<xPomgBHq**M4y8GQP%n-jR;l0YNQ$1*BQEKr7-5879=Kq|Mmp%*X zt4!y)^s;;LbqlWFyzliBC-FUHiC0bxI`v3<LQd0vBa^S6gfi~#+A4e6_QitcQ@5wA z<CkoV+?=-awEq4(e`5cLa0=T`30d9%>JGDk#t8%-cxdKd`Qg9fNH@c|LlK88xZW*i z5mK{wT9Ll{ugSb#s|x$iC%;>4GTg4QMKe*THMHx!MCz2T_qU1;wZs_3HEjBE&ZN@# zu?wH$Ba7B2%YTTe#pO-floTOgHz(Qa>+9?KTkGFTOb+kNr~qyII^rsG(<{_M-fte0 ze!1hrsyV99Ux*&x(B*#kGxOoqlTTi`?D*@f-`z965`KSVIe*UP&$g`XTkfA)rOu=z zpv07F8{frmy7~X^Rt^`QcA+Or%^n|GQuz2-S>0~$>3XSL!kd&Pi8ss^T<VizEt6uQ zKd;Z=W7E|FHJOJ_8|IZ9l1exFT5{*zdIj_FJI~hr>}cRf>2J_cyO})u{WRk&L&XN} z<BQC0=NMn#mK*IY^+YqO4zz_S`c|ru_@gZ@T^U7834awT1v_VWd0jnY#v>-Y?y<zg z@I4F6`0aiysI>K;XLIwDm_SAQzs@f6+FvE!&b}&kb^WDnIsGbLpISIM`z-W*Z^R!v zWMkocR`N5buYHK+ab#?eR#uU+!MjO8{*&DsE0ZTKlslOJVsd-wsw<a&?o%|nyT8SA zS?4NSK><dN6USBdeRn)o<8$Mjf&|aW%L0rQS0=GZB|2He$=yrgQz_uSCU}H#<s#3R z5~QBW^ckyWZa%{ye1!S!rvvIyaqWDvI+j9-b(~4f7AvB+ujAzUrC24qat>%95VUuU zX`<r-=}!_0b2#2xr=5|weTtFoU<PQ9kEG1^8_E2jg~sj`@xL@QMNOTWQ@mA|&Rcf( zwBGJBM>unpd~Vb^#Vqx*?Pcf+o@mf{IV(%=AIFK!N9C7)x_W8loKGLQKVNn9ds<PS zTc6qM`~AtriVp>9TXb3X_i^j*xzNH{C!->mb#>KL*FDZN68^rpzkk2>o~e_yLXB^m z9j*0w(fq)agZYyEbXA`{4rWjE7x?d~-Pj`{t`^~Mv8ZLi!U;`3PwVe5IWAvcb1LM@ zN+X+XIX5qD&Axt4$4q3~+!HmYYl4=}d#0=4=XyxRZ}rNZ9S#*7E{c7g6&bGCDw5sF zPE1Ni4t5AC_ke~vp7L2dU=UXGp02lbtzeDio((%Agu1vVhpe1c|L<qIuo{Q7j`oyS zS67Q~X?>xg<MZK(>XG&7h6fipGO2Jyd#VIKs@_)F#V!0NHski}_U&^bf`XPV@>BHz zUGhA;_;{b}TFGCBi?)=#y)|X!azWohEg`kSDBrWLEQg#GxF*IQcGljmthxTILGr}- zjVx#8T3`QTp^*~u=HA}joWhH4@BR5~_B6+dJZ(AM6ZUS{Vc<D+)y%aEC)N1aT$yJO zxu;?y=p2w-85Q?WEu4!w_ApOT^`3S^jQ3H(jSY#jIVOL6eEhcAM05Ua(>HtyfVk^J z^+EnN6`v`Ai`{0<Kefbja!^{u6oZp*<tJ1LGYWR7HEKLL)v0##Prp_2&LWS%p2M2_ zaep*FynJxXaRz7=LXG_frw<pF2m4)LP$4M0B*pIgo#M087cU7p+tGTdg|ima<X;!R zziwM?OFYNRx!k{J6zG7il->ULD8~#?PwBwVtsD9|mD(!>yk_K1UEF7N>Xypil2svB zRtEVeuXJ3Xc%op{(Ws^!iThRt`FqcJ^1t6nS%6WH!@jX5UHqKP!cVuvjm#%)*fM3~ zn?o#yhlM^pne2b-&W(KzOBAF881HdPZHp+VILiKX@ArGfpzX}h16VlEtyNu`rKX&m zd8p-|fMrC2MvnHz)}R|nhkSdC^`bpH_+*xQbtQuqQCZiWd8xp~x2=aaagvs(>7mt2 zu3SDnUEf?@_)nC^l6mv2N>?o{(({~Av2yw0qT-Y!nOmn$vbb(lWO}GJVZFPyq8w=Y zuli<aCp+UN*Y9s{Ur&7VA^KELGN@gB`{J#+Ww%y(%>I!9TJq}m?!$&hDLz}XuD;1I z<ge9{`(r&f<ZPUKgtf+&&^-!sKx@Cft$X`DBU_8F^swI-U2m{0WaWzBrSqP#2>zY4 zqBGd`A-_eK*vy3e(+xO}d2e-fVEH5LFr{EZV>7GPM+Ju@w=!)3^*ZmFhmPbsubR%o zB&2pSBK>R-%O^*M)h7D8_uN?~EMqL695#O?Cup5k+J*xM0`KeylrrZOz8l)e;W2~d zkm!!0eLgQ5*;jG9D0s6JC?2Tizi&G=Ls;ROq@q>9e2yT<WXA1XT(izQfyVPcc`JBX zrgl_1YP4^^UuV7l!j<ZsoC3eQC&(UI!3kB(DSVe%Nr5R+{eU7fUj%4Fd*pj>*_3vM z<;k2?R=Kyf9FX;x!QwXU4R?y6=eJ+k-;^eBGr7D1-FSM|+);HF%Lh>@^Sn7vCvr!r z_%sQ5SJZM&Zn@7eYahpx4u(V}i?fanzEd*<6}Iv$U(NA(qTfUV&-SRM^%D&|KRn8Q zr8L2r$>v6f`qxw1>m#g0re+8z)Sgvrmq{u-d+DsGdZJM8R=%?usy<GeMWi}7j?825 zjBxLhc?s&u{oZ*jwaKMkJ@@p?^m#MCO;Pc=<Tm{bx2n&io$qFC<#^J~z_+2rM19u| zuN|B*1qWIC9;~+5H*LAcj4ADLOzWo_cs^K^eM)J9J5&9ikL|fHCp_+v$<cbKVo>!Z zqx|{Y@>^nk^E2KoJ?nHxWlpxttw7HiEoGS|27(>BjGrb?+%h#+mTAMvmTm^dD>wFm z4xh}vvLbLNyLw_!UdzcWheIlnuh-t}a){vA^X*o)nBcTG?^8O%IoTN}{hD+_Jh16< zwpv$<r<#V^3SQ31EV|p4X)!4(JG52z2`c-Y;9EZ_o(Z(BEYNAsq{sdCcFD~X4Ngj& zN-<GMoYYf#O~+MX4a>29`TT>|Z`fHpY!N<Wb>>F@>y^vrZOS!u@!Xzw*T^cKb8^q4 zp88}VwU6=1X9HLc`86CVh}~6E=-kE=xM{zQj@Zec>vp};5^m2~pSsIqM#`*=Gq)!j zbpB+@u2K>ZWSaBuLGNDoez|q=`|AWHOTV;NUiLNL3EDF5;yGE(_tNYD$;>ONK9>&9 zTClq7nd(#n&kL8bS1Ab;F@d%vS^s{sS@+z@6@iQIoU?u}^GUG1q#~7r)$Q+D^ZPqK zpSQpNXv&@H_j~iE$CjPEm7?Oasm*L2ulI~2#j&Q^f*nSUuh;LtC+N;xILTA}jE3>a zCpXmn=jAMFu`t?ju1qs{#+tajw?J#pLf1qX-cAnuEvTT7DAeeBNx)U1kp;dbBIAO> z=0z)}^fO!&oTOp*@rbb6uRgn9FFu*R`1~rUmGc#c`gDG~9|xLl`^>Sp7`h_h;M|Hw zoq0#QM3<HYE_UM$-<lO_UjMHqd}mSWYVV+BpnEq!7f0m1Uc3F9rAsKcFeB$=gSBo> z#~vL%Ge<yZR+=PB-H(UtpUoYYDEL`Kt(hdpXvD1SWx>}I@3}SWYLLm4pY|7~9BMH* zFjXtGX#M_wyFfFrcR<TJW-<wC9+#_L^ZV!X`KLwHw8PhxnBOUA-u-M=_L_H~S;KF4 z%i}pGFUpgCdDpaZm)9W`{|8ssa&$E0GwJXDv&pu6+x@y~VU1pC^KZ4em$X4k@^93B zzgvEcZ?VfdZ?D8lD}&XKTRvUpJ9`&sq0zqD-@6!@*=8tc>iB#(Cu^27BYJaMFKC)_ z_qSWwxwqN7J=^(Y@7&m!e0P$ncg){kU(E&8SWZh?m8^)~QLxbU6KFA(<&_QLJ2EaR zeSf?Ce$=UKoAvxQ9~^@7r`*opfA^S!=hgakj%rKoIVUe!v*np4(?#_In>(L}JwG=W ze3z8|v5&e>s~^X1NNBW;zPat?{r&qv*C~E#(^_gU(=>Y;==gx@Hye-pBwSe=eSKR| zg+b*ZmSV{?Iic?xTrY1<_jgx2@p|3vb1j@q%?TFS*VmN>FZa_`^0{$uW$f;4S3&oD z%)BpUl98aquEEUCw*`FK%DI){>*Mb7%G=%9`{PkJXt<#iG=Vbnb<o%O=8Fv9M;ual z#=Yicr^6YJ2kIw_Tif%DSiCl{>gad~<a10~yX}@%gtFwixj{1?d}*q1U;tfM*Wy-~ zSahfG_{@X{F9e?M`~7ZngL#C5P2#0JmBqpelhu4TtyRd^PXGJstD3=vGYOK89iV1~ z;3Kg_r#rR(d>5{b+go+>{PQz2A7>Qb-BtSR^`uq*d5VLI|0^pbPI|U>!q40rChUt& zn<)nD6Zd88<zQU%t3%lC?X9iFpc@%&>nBB3sBM-u%DrW>S?%LNeG{IgF^5vt@BOw( zclsgLrAN#9)qN~>9W6VnyZz21(7xMif^*_O&Pe;urOnYLcKSr#?zdqIKKp(=;=a9X z;RXKNHZAhUj<>#P1ucDfE4}QMJx{@73pUQl7VB0$Q(-!(*x+z*(s}2Z3c0bn%S<Ou zYPn-=oOWhI<>!Y#PwwGVmltz<bhq`XklK&h3BD6_#ZUFy|9b(tPjHrLc9_eIgu59x zHZ06#UwBSHEy5*W_4_@a`&|2zZ$H22F0U(~#&YhXjv<Gzj$y}~Lx-MhILzmLv%cux znIh|8&dGN^h2?`fdCDJNE}t)Ev*M=e1IONggS+IXAIgkq;mDJeV40y@H~UBJvt2(- zWu|-2c<{n2;uh%o=Wk0suqr;|%-XWyXv@jRM{aG)jegu<;8^lNqMO~oeUF9wS<MCJ z_bLu=%lX4GSvr4@Ve0>#Z1bl4Q}LO!>C&v_94g(Qc4?>r<l<O0u6Im<+H*RNer0lO zvSurOc(~71#LFwOX)1GR>!Kr<9{!vmaGa$*cw07Ti*cQt%-Ka-GA<snsVcu)dfm5$ zbHDx9E5T>AnhXxkX?w}@U&!nIy}h}+*-mpVTC&3+QF}%5@jh0u$)MYRw-pC{m1q5N zQ)Y2|s#FP&keXxX%6%Li4p%q|BAVN+;y+HzxxB2`cKweBWdhqiT@8=7+?M&_^pn@q z<Lffp!vvJy-rmlCyWq5p|ICT;r?V0tAM53-7dVqp{ch*-xwk$>?+`N$2MrJ=^&}k3 zYPxzfU(^48-S2?C|J4-|7wvXraZ&JONjpC;mmhRJ?E=F;#ul!p(m^9m_9tRQ`KAl( z08N5!S$}UG^CC{hqwLC#Q@nS!dQMSazmZ*CAyH_~%yj~cf*t&fEeuTuek%xU_)z?4 zOWN64tnxx!pKRkTAD-ea|F}NlukGvlhwD|&L~qN9Jb3)~yv2JXa%=*h)b>U*SaMGO z@n`Ro6g43=%Y$qDE-6e{`}VX++ahlvw}yyVi<x5LA|2e9wktSz2`Q>}iq^Hgc1fK0 zm{Vp>(e^t<r*B-IYS8&tD7~ynNNwiRmDgMxSX>-fx`aHuXFPd-R;Awd^|7D&prHd! zB?Tr>!cv(q&EVv-hAU+|I6Y>xRM(nVftCq$ST#=I7LN2dRMzY{qb1kXL=G$}-Z+7K za>c>E!#OHGk2ZA8Y6h)zX_?;8;#qNBZHn?_1J0+LG6Fy*3rI5wscnorb;rl$kc#=7 ztKA@#DpMO;JcGjR&Q^NQSi<Qyy|V!%`a?+}@e%iAtx6UZpAvnSX$>_mm3Nm&Rczv5 z5m%G`#}uL%Il<&MB7W>yzI-^z|NYK)shAm0>Uv%oy0EDDIBk)T>f(6P)8OKGE?~8? zdg7wl3IdFrlO1-1M1n%VML~g)b8^FhNpZ1<R9==hJd@96`gFMS>nFF=A|bWF$d%A3 z{e_7gpfM&NPLCN!N)k7l>T*ubnHaho<Rt|rfe8i|YXv$SZnSj9d}7j_uhk7w`-1aH z2zZCVyKen`1=jC&EWVxCF6+ea&U|MINa-~Xhy&tSg19EnG)~_o>~C{%ZN$byvGsqy zf=*E@Kitk=emigX+TRb`<?oc;&iyXVS^s{u{l6cJ!HZ`e_uI!gfG!7rx9|5m&>f*? zECP?5zn#DT?XHrSlRj>nd~ZRE=cV@yXX8N@ZSq!FYB19<xy}09jpV!M?f<_4HQ~Si ze!qV=Xv;>+Nzkbjt3p>l%TAFt&np2fr@Or&v02(YZ_euQ_47d09B4x4&iwj+FF_N3 z@o!mHnxvi*DgSs>e7C>dPn8p?t6n!Zv~==&tWsiP<a}Y^<B+gQE}Lmz3wQy}r>Cdy zvWmw9DEJ6yfR<GL{nN-UXRz_oa)0^nuU4<$b*xt!v|@D!Xuap&Z@03+yR$*NC2nW0 z-^-P7Zod6}&@}Gdn$Ks~6+J!mZR-2$Yonk0*?tWvf81+6Ylh{U4TtYMIXU_4rcG&Q zr9i_cprt)CBBZQJR%BmT&?s%3*0VZp?=ES}q9v;X7q?kI>QKJ3e12V)*nIVQ6-w8* zXS_b?IpfK!9lwM@3&&CfKdAcr`u;xODd9+mpqdY8S*I|cu)1FfXp10d0C#QF)=l?g z3y+HC{rd7U@56(GeY$f%_iz{5Mmw$KI`nAMX+7gY&}o&zYPMBh3Tl6U+iE5#S^D}~ z>FThxn{=0e?mN_t*l<7=bpBk6uwTL6s;`^gF5?o_+5x(naNC@BJ0A0W2Q5`z<~v(0 z+jX-|H0NX;=CIG8L^q*;DU(z9kE>ke6G8LxcQK&-Ip*o-WI%Ut3+tD@x>A^P|IL=m ze(%=pepl2jrfbyAb=!QU*Xe1xvUcjAmQ?6Y(4jA&qo&&B>mrsJMDDHHx;kp>D$Yrh z{j5%Io3~}^<h{G24yjb<Tm`RN>u}IK-pc)ZhRF6A6%RlKVH3+~&P59<Bu%rXaCYb2 z-Ie=jdQ-!W=ku!X%uJt`ne=R7yIhg1b=elR4Ldf-Hn%R>aFoTHSG~%nn{%4zd7<W~ z%SvBgQ|sEK?eoX-&#|x1CK+_TK9v;*@|yr3Q)VROe(T?Fx6i)Mu{>TtD8lB0`OU1= zYje_aw!YbRJ1_6%rqp$wlhyJrE%Ds;_K~Pe;>IqWxIH&Ohbn<?n_dSx#wDBO>}7xZ zw`x8!5)QRkfo6RpGj7cK*y4G9o-JsBz}s1OI42kA#O!lZOq`_u>6Q6wmPvolO)TB> z%7Nt%sBC=j!pmpUt*zO!I~+n1PVV@6E&48K@mO5VN7w87YO8N|9kdk9=DKbB_;`Og z=v=voD2tDWukrG2{?W3*w8ft5pH_soRq3mg{kPL*=f>=>`+KKVJTBw@<BsTQ1_v$0 zym`KAg{^rpz4g^k1%<>%%#&7uN|^?ZCB6%;Sg3*SqW_t*VXAY^ghz!w1qFLwE}Q)( z;@xTe{cm=ay^S&usH^*WHT?GXob8}a>b9egL|J&Qhp!Aes-qhbbFcn??eEfVG2J_$ zQ|p$T1szRLe=2kN+_Y%BR8HYFCUZCr-3pqO?|tjapE!xb#tlMhb>i_~A@#x~#R(Tr ztk1r_&XoN|Y}w7H^^7;V_&B|}m0E<&qH{L7PK+12+>)&wx+-Owgj_@1&zH;RznLH5 z|7RL#wFIcUlaPJ#ed(%jD^QK1sHDL3P+8#c_5&Xr&)w`W(()-X%PO5>&LpH(>Ab$r z6*Q?L$fDvSwDHW$*-KhHpGB-v1=T77jlP^7GhVENtk;CB=VTP*@NhV!qOf5}_;dr$ zU$P5+f{WTRPLCNW)AQd%O*iPgJ1NTvoQkxVFc#r-I85R6nBh|S^^-vv=VTj)@aZ6x z6BL+))HtKw`1ph#QW14M8hGN!-=${YkT~S>-2o)qSg`Vw8jH$<l3>shPCte6LoS?~ zk_z>Y1<rU8DA^qyJh_8~@$XjGq?w;=PTb*~Y~ybde)ss_^Ll-URKmZv{SssZ`AB1S zLyPClo{+@?jXhk#krzwyAvK+da>5~(5EliG#$M^t(<~2{?gBYWf$1OTANe`0?~N{V T?y+NFU|{fc^>bP0l+XkKME$q( literal 0 HcmV?d00001 diff --git a/documentation.md b/documentation.md index 9d969d6..f12b992 100644 --- a/documentation.md +++ b/documentation.md @@ -2,11 +2,28 @@ ## Description Générale -CampusTalk est une application WEB de réseau social permettant aux utilisateurs de créer des fils de discussion, d'y poster des messages textuels, et de lire les messages des autres abonnés au même fil. L'application est développée en JEE (jakarta) avec une architecture MVC, et elle est conçue pour être responsive, fonctionnant aussi bien sur ordinateur que sur smartphone. +CampusTalk est une application web qui permet aux utilisateurs de créer et de participer à des fils de discussion, pour partager des informations et collaborer sur divers sujets. Tous les fils sont ouverts à tous les utilisateurs pour favoriser la transparence et l'inclusion, où chacun peut librement contribuer, apprendre et s'engager dans des conversations. + +Fonctionnalités Clés : + + Création de Fils de Discussion : Les utilisateurs peuvent créer des discussions sur des sujets variés, allant des projets académiques aux événements sociaux. + Publication de Messages : Possibilité de publier des messages textuels et d'y joindre des images pour enrichir les échanges. + Abonnement aux Fils : Les utilisateurs peuvent s'abonner à des fils spécifiques pour recevoir des notifications sur les nouvelles publications. + Interactions Sociales : Fonctionnalités de "like" pour exprimer son appréciation des messages et encourager les contributions positives. + Gestion des Utilisateurs : Inscription, authentification et gestion des paramètres de compte pour une expérience utilisateur personnalisée. + +Technologies Utilisées : + + Jakarta EE + JSP (JavaServer Pages) + Base de Données Relationnelle + TailwindCSS + +CampusTalk est conçue pour être accessible et intuitive, avec une interface responsive qui s'adapte à tous les types d'appareils, garantissant ainsi une expérience utilisateur fluide sur ordinateur comme sur smartphone. En mettant l'accent sur la simplicité et l'efficacité. ## MCD -A FAIRE + ## MLD diff --git a/sae/WEB-INF/src/controleur/Accueil.java b/sae/WEB-INF/src/controleur/Accueil.java index 1524c2f..0b92841 100644 --- a/sae/WEB-INF/src/controleur/Accueil.java +++ b/sae/WEB-INF/src/controleur/Accueil.java @@ -13,10 +13,10 @@ import org.apache.commons.text.StringEscapeUtils; public class Accueil extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - if (request.getSession(false) == null || request.getSession().getAttribute("email") == null) { - response.sendRedirect(request.getContextPath() + "/login"); + if (!Auth.checkLog(request, response)) { return; } + HttpSession session = request.getSession(); String email = StringEscapeUtils.escapeHtml4((String) session.getAttribute("email")); request.setAttribute("email", email); diff --git a/sae/WEB-INF/src/controleur/Auth.java b/sae/WEB-INF/src/controleur/Auth.java new file mode 100644 index 0000000..e4301b7 --- /dev/null +++ b/sae/WEB-INF/src/controleur/Auth.java @@ -0,0 +1,39 @@ +package controleur; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpSession; +import modele.UtilisateurDao; +import java.io.IOException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public class Auth { + public static boolean checkLog(HttpServletRequest request, HttpServletResponse response) throws IOException { + HttpSession session = request.getSession(false); + if (session == null || session.getAttribute("email") == null) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if ("token".equals(cookie.getName())) { + String token = cookie.getValue(); + UtilisateurDao udao = new UtilisateurDao(); + if (udao.check(token)) { + String email = udao.findEmailByToken(token); + session = request.getSession(true); + session.setAttribute("token", token); + session.setAttribute("email", email); + return true; + } + } + } + } + } + + if (session == null || session.getAttribute("email") == null) { + response.sendRedirect(request.getContextPath() + "/login"); + return false; + } + + return true; + } +} diff --git a/sae/WEB-INF/src/controleur/CreerFil.java b/sae/WEB-INF/src/controleur/CreerFil.java index 45e88ce..e5d9fa6 100644 --- a/sae/WEB-INF/src/controleur/CreerFil.java +++ b/sae/WEB-INF/src/controleur/CreerFil.java @@ -28,8 +28,7 @@ public class CreerFil extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } req.getRequestDispatcher("/WEB-INF/vue/creerFil.jsp").forward(req, res); @@ -37,13 +36,12 @@ public class CreerFil extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } FilDeDiscussionDAO f = new FilDeDiscussionDAO(); String nom = StringEscapeUtils.escapeHtml4(req.getParameter("nom")); - String createuremail = StringEscapeUtils.escapeHtml4(req.getParameter("createuremail")); + String createuremail = req.getSession().getAttribute("email").toString(); String description = StringEscapeUtils.escapeHtml4(req.getParameter("description")); UtilisateurDao udao = new UtilisateurDao(); if (!udao.emailExists(createuremail)) { diff --git a/sae/WEB-INF/src/controleur/DeleteFil.java b/sae/WEB-INF/src/controleur/DeleteFil.java index 08d5ac6..0a192c1 100644 --- a/sae/WEB-INF/src/controleur/DeleteFil.java +++ b/sae/WEB-INF/src/controleur/DeleteFil.java @@ -13,8 +13,7 @@ import modele.FilDeDiscussionDAO; public class DeleteFil extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } int id = Integer.parseInt(req.getParameter("id")); diff --git a/sae/WEB-INF/src/controleur/DeleteMessage.java b/sae/WEB-INF/src/controleur/DeleteMessage.java index 74aa1e0..d457cb7 100644 --- a/sae/WEB-INF/src/controleur/DeleteMessage.java +++ b/sae/WEB-INF/src/controleur/DeleteMessage.java @@ -12,16 +12,14 @@ import modele.MessageDao; @WebServlet("/deleteMessage") public class DeleteMessage extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } req.getRequestDispatcher("/WEB-INF/vue/listeFil.jsp").forward(req, res); } public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } String email = (String) req.getSession().getAttribute("email"); diff --git a/sae/WEB-INF/src/controleur/EnvoyerMessage.java b/sae/WEB-INF/src/controleur/EnvoyerMessage.java index 8b67344..e5dac2c 100644 --- a/sae/WEB-INF/src/controleur/EnvoyerMessage.java +++ b/sae/WEB-INF/src/controleur/EnvoyerMessage.java @@ -25,16 +25,14 @@ public class EnvoyerMessage extends HttpServlet { private static final String UPLOAD_DIR = "uploads"; public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } req.getRequestDispatcher("/WEB-INF/vue/listeFil.jsp").forward(req, res); } public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } String email = (String) req.getSession().getAttribute("email"); // je pense que ça ne sert a rien d'utiliser StringEscapeUtils.escapeHtml4 sur l'email qui est en session et qui est censé être safe vu qu'on verifie au moment ou on le met en session diff --git a/sae/WEB-INF/src/controleur/Fil.java b/sae/WEB-INF/src/controleur/Fil.java index e53e86c..4f65d34 100644 --- a/sae/WEB-INF/src/controleur/Fil.java +++ b/sae/WEB-INF/src/controleur/Fil.java @@ -11,8 +11,7 @@ import java.io.IOException; @WebServlet("/fil") public class Fil extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } int id = Integer.parseInt(req.getParameter("id")); diff --git a/sae/WEB-INF/src/controleur/GetFils.java b/sae/WEB-INF/src/controleur/GetFils.java index 8ca4d28..1834b01 100644 --- a/sae/WEB-INF/src/controleur/GetFils.java +++ b/sae/WEB-INF/src/controleur/GetFils.java @@ -29,8 +29,7 @@ import modele.MessageDao; public class GetFils extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } diff --git a/sae/WEB-INF/src/controleur/Like.java b/sae/WEB-INF/src/controleur/Like.java index 113c195..b7c4dad 100644 --- a/sae/WEB-INF/src/controleur/Like.java +++ b/sae/WEB-INF/src/controleur/Like.java @@ -15,8 +15,7 @@ public class Like extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } diff --git a/sae/WEB-INF/src/controleur/ListerFil.java b/sae/WEB-INF/src/controleur/ListerFil.java index e4564ba..5e711fc 100644 --- a/sae/WEB-INF/src/controleur/ListerFil.java +++ b/sae/WEB-INF/src/controleur/ListerFil.java @@ -10,8 +10,7 @@ import java.io.IOException; @WebServlet("/listerFil") public class ListerFil extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } req.getRequestDispatcher("/WEB-INF/vue/listerFil.jsp").forward(req, res); diff --git a/sae/WEB-INF/src/controleur/Login.java b/sae/WEB-INF/src/controleur/Login.java index 6b78a5a..7e31967 100644 --- a/sae/WEB-INF/src/controleur/Login.java +++ b/sae/WEB-INF/src/controleur/Login.java @@ -4,10 +4,12 @@ import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; import modele.UtilisateurDao; import jakarta.servlet.ServletException; import java.io.IOException; import org.apache.commons.text.StringEscapeUtils; +import modele.GenerateToken; @WebServlet("/login") public class Login extends HttpServlet { @@ -18,10 +20,17 @@ public class Login extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { String email = StringEscapeUtils.escapeHtml4(req.getParameter("email")); String motdepasse = StringEscapeUtils.escapeHtml4(req.getParameter("motdepasse")); + String token = GenerateToken.generateToken(email, motdepasse); UtilisateurDao udao = new UtilisateurDao(); - if (udao.check(email, motdepasse)) { + if (udao.check(token)) { System.out.println("Connexion réussie"); req.getSession().setAttribute("email", email); + + if ("on".equals(req.getParameter("remember"))) { + Cookie cookie = new Cookie("token", token); + cookie.setMaxAge(60 * 60 * 24 * 30); // 30 jours + res.addCookie(cookie); + } res.sendRedirect(req.getContextPath() + "/accueil"); } else { System.out.println("Connexion échouée"); diff --git a/sae/WEB-INF/src/controleur/Logout.java b/sae/WEB-INF/src/controleur/Logout.java index ad2c43f..a6ebe88 100644 --- a/sae/WEB-INF/src/controleur/Logout.java +++ b/sae/WEB-INF/src/controleur/Logout.java @@ -5,16 +5,26 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; import jakarta.servlet.ServletException; import java.io.IOException; @WebServlet("/logout") public class Logout extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { + if (!Auth.checkLog(req, res)) { + return; + } + HttpSession session = req.getSession(false); if (session != null) { session.invalidate(); } + + Cookie cookie = new Cookie("token", ""); + cookie.setMaxAge(0); + res.addCookie(cookie); + res.sendRedirect(req.getContextPath() + "/login"); } } diff --git a/sae/WEB-INF/src/controleur/MenuFil.java b/sae/WEB-INF/src/controleur/MenuFil.java index bbd05d1..592467f 100644 --- a/sae/WEB-INF/src/controleur/MenuFil.java +++ b/sae/WEB-INF/src/controleur/MenuFil.java @@ -10,8 +10,7 @@ import java.io.IOException; @WebServlet("/menuFil") public class MenuFil extends HttpServlet { public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } req.getRequestDispatcher("/WEB-INF/vue/menuFil.jsp").forward(req, res); diff --git a/sae/WEB-INF/src/controleur/ModifierFil.java b/sae/WEB-INF/src/controleur/ModifierFil.java index 9ae7d8e..c359801 100644 --- a/sae/WEB-INF/src/controleur/ModifierFil.java +++ b/sae/WEB-INF/src/controleur/ModifierFil.java @@ -25,8 +25,7 @@ public class ModifierFil extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } if (req.getSession().getAttribute("idFil") == null) { diff --git a/sae/WEB-INF/src/controleur/Parametre.java b/sae/WEB-INF/src/controleur/Parametre.java index 90d984b..b780740 100644 --- a/sae/WEB-INF/src/controleur/Parametre.java +++ b/sae/WEB-INF/src/controleur/Parametre.java @@ -3,9 +3,11 @@ package controleur; import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import modele.GenerateToken; import modele.Utilisateur; import modele.UtilisateurDao; import org.apache.commons.text.StringEscapeUtils; @@ -15,8 +17,7 @@ public class Parametre extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } req.getRequestDispatcher("/WEB-INF/vue/parametre.jsp").forward(req, res); @@ -24,8 +25,7 @@ public class Parametre extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } @@ -50,6 +50,14 @@ public class Parametre extends HttpServlet { udao.update(utilisateur, email); req.getSession().setAttribute("email", newEmail); + Cookie[] cookies = req.getCookies(); + for (Cookie cookie : cookies) { + if (cookie.getName().equals("token")) { + cookie.setValue(GenerateToken.generateToken(newEmail, motdepasse)); + res.addCookie(cookie); + break; + } + } res.sendRedirect(req.getContextPath() + "/accueil"); } } diff --git a/sae/WEB-INF/src/controleur/Register.java b/sae/WEB-INF/src/controleur/Register.java index 4506f6a..65ff985 100644 --- a/sae/WEB-INF/src/controleur/Register.java +++ b/sae/WEB-INF/src/controleur/Register.java @@ -5,11 +5,13 @@ import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; import jakarta.servlet.ServletException; import java.io.IOException; import modele.Utilisateur; import modele.UtilisateurDao; import org.apache.commons.text.StringEscapeUtils; +import modele.GenerateToken; @WebServlet("/register") public class Register extends HttpServlet { @@ -25,6 +27,8 @@ public class Register extends HttpServlet { String email = StringEscapeUtils.escapeHtml4(req.getParameter("email")); String motdepasse = StringEscapeUtils.escapeHtml4(req.getParameter("motdepasse")); String nom = StringEscapeUtils.escapeHtml4(req.getParameter("nom")); + String token = GenerateToken.generateToken(email, motdepasse); + System.out.println(token); if (udao.emailExists(email)) { req.setAttribute("error", "L'email est déjà utilisé."); req.getRequestDispatcher("/WEB-INF/vue/register.jsp").forward(req, res); @@ -33,9 +37,17 @@ public class Register extends HttpServlet { nom, email, motdepasse, - LocalDateTime.now() + LocalDateTime.now(), + token )); req.getSession().setAttribute("email", email); + + if ("on".equals(req.getParameter("remember"))) { + Cookie cookie = new Cookie("token", token); + cookie.setMaxAge(60 * 60 * 24 * 30); + res.addCookie(cookie); + } + res.sendRedirect(req.getContextPath() + "/accueil"); } } diff --git a/sae/WEB-INF/src/controleur/SuivreFil.java b/sae/WEB-INF/src/controleur/SuivreFil.java index 80db439..02bebd0 100644 --- a/sae/WEB-INF/src/controleur/SuivreFil.java +++ b/sae/WEB-INF/src/controleur/SuivreFil.java @@ -11,8 +11,7 @@ import java.io.IOException; @WebServlet("/suivreFil") public class SuivreFil extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { - if (req.getSession(false) == null || req.getSession().getAttribute("email") == null) { - res.sendRedirect(req.getContextPath() + "/login"); + if (!Auth.checkLog(req, res)) { return; } int id = Integer.parseInt(req.getParameter("id")); diff --git a/sae/WEB-INF/src/modele/GenerateToken.java b/sae/WEB-INF/src/modele/GenerateToken.java new file mode 100644 index 0000000..7171f08 --- /dev/null +++ b/sae/WEB-INF/src/modele/GenerateToken.java @@ -0,0 +1,16 @@ +package modele; + +import java.util.Base64; + +public class GenerateToken { + public static String generateToken(String email, String password) { + String emailPwd = email + ":" + password; + String token = Base64.getEncoder().encodeToString(emailPwd.getBytes()); + return token; + } + + public static void main(String[] args) { + System.out.println("token :"); + System.out.println(generateToken("utilisateur3@exemple.com", "motdepasse123")); + } +} \ No newline at end of file diff --git a/sae/WEB-INF/src/modele/Utilisateur.java b/sae/WEB-INF/src/modele/Utilisateur.java index 853c966..1f09127 100644 --- a/sae/WEB-INF/src/modele/Utilisateur.java +++ b/sae/WEB-INF/src/modele/Utilisateur.java @@ -7,15 +7,17 @@ public class Utilisateur { private String email; private String motDePasse; // HASH private LocalDateTime dateInscription; + String token; public Utilisateur() { } - public Utilisateur(String nom, String email, String motDePasse, LocalDateTime dateInscription) { + public Utilisateur(String nom, String email, String motDePasse, LocalDateTime dateInscription, String token) { this.nom = nom; this.email = email; this.motDePasse = motDePasse; this.dateInscription = dateInscription; + this.token = token; } public String getNom() { @@ -50,6 +52,14 @@ public class Utilisateur { this.dateInscription = dateInscription; } + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + @Override public String toString() { return "Utilisateur [dateInscription=" + dateInscription + ", email=" + email + ", nom=" + nom + "]"; diff --git a/sae/WEB-INF/src/modele/UtilisateurDao.java b/sae/WEB-INF/src/modele/UtilisateurDao.java index bd5592f..b1dcae5 100644 --- a/sae/WEB-INF/src/modele/UtilisateurDao.java +++ b/sae/WEB-INF/src/modele/UtilisateurDao.java @@ -17,6 +17,7 @@ public class UtilisateurDao { utilisateur.setEmail(rs.getString("email")); utilisateur.setMotDePasse(rs.getString("motdepasse")); utilisateur.setDateInscription(rs.getTimestamp("dateinscription").toLocalDateTime()); + utilisateur.setToken(rs.getString("token")); } else { System.out.println("Utilisateur inexistant"); } @@ -50,11 +51,14 @@ public class UtilisateurDao { public void update(Utilisateur utilisateur, String oldEmail) { try(Connection con = DS.instance.getConnection()) { - PreparedStatement ps = con.prepareStatement("UPDATE Utilisateur SET nom = ?, email = ?, motdepasse = MD5(?) WHERE email = ?"); + PreparedStatement ps = con.prepareStatement("UPDATE Utilisateur SET nom = ?, email = ?, motdepasse = MD5(?), token = ? WHERE email = ?"); + String newToken = GenerateToken.generateToken(utilisateur.getEmail(), utilisateur.getMotDePasse()); + utilisateur.setToken(newToken); ps.setString(1, utilisateur.getNom()); ps.setString(2, utilisateur.getEmail()); ps.setString(3, utilisateur.getMotDePasse()); - ps.setString(4, oldEmail); + ps.setString(4, utilisateur.getToken()); + ps.setString(5, oldEmail); ps.executeUpdate(); } catch (Exception e) { System.out.println(e.getMessage()); @@ -63,10 +67,11 @@ public class UtilisateurDao { public void insert(Utilisateur utilisateur) { try(Connection con = DS.instance.getConnection()) { - PreparedStatement ps = con.prepareStatement("INSERT INTO Utilisateur (nom, email, motdepasse) VALUES (?, ?, MD5(?))"); + PreparedStatement ps = con.prepareStatement("INSERT INTO Utilisateur (nom, email, motdepasse, token) VALUES (?, ?, MD5(?), ?)"); ps.setString(1, utilisateur.getNom()); ps.setString(2, utilisateur.getEmail()); ps.setString(3, utilisateur.getMotDePasse()); + ps.setString(4, utilisateur.getToken()); ps.executeUpdate(); } catch (Exception e) { System.out.println(e.getMessage()); @@ -85,4 +90,30 @@ public class UtilisateurDao { return false; } } + + public boolean check(String token) { + try(Connection con = DS.instance.getConnection()) { + PreparedStatement ps = con.prepareStatement("SELECT * FROM Utilisateur WHERE token = ?"); + ps.setString(1, token); + ResultSet rs = ps.executeQuery(); + return rs.next(); + } catch (Exception e) { + System.out.println(e.getMessage()); + return false; + } + } + + public String findEmailByToken(String token) { + try(Connection con = DS.instance.getConnection()) { + PreparedStatement ps = con.prepareStatement("SELECT email FROM Utilisateur WHERE token = ?"); + ps.setString(1, token); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + return rs.getString("email"); + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return null; + } } diff --git a/sae/WEB-INF/vue/creerFil.jsp b/sae/WEB-INF/vue/creerFil.jsp index 7a6faf0..ebce9fa 100644 --- a/sae/WEB-INF/vue/creerFil.jsp +++ b/sae/WEB-INF/vue/creerFil.jsp @@ -59,10 +59,6 @@ <label for="nom" class="block text-gray-300 font-semibold">Nom du fil:</label> <input type="text" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" id="nom" name="nom" required> </div> - <div class="mb-4"> - <label for="createuremail" class="block text-gray-300 font-semibold">Email du créateur:</label> - <input type="email" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" id="createuremail" name="createuremail" required> - </div> <div class="mb-4"> <label for="description" class="block text-gray-300 font-semibold">Description:</label> <textarea class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" id="description" name="description" rows="3" required></textarea> diff --git a/sae/WEB-INF/vue/login.jsp b/sae/WEB-INF/vue/login.jsp index ab796dd..ed1fe4d 100644 --- a/sae/WEB-INF/vue/login.jsp +++ b/sae/WEB-INF/vue/login.jsp @@ -48,6 +48,12 @@ <label for="motdepasse" class="block text-gray-300 font-semibold">Mot de passe</label> <input type="password" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" name="motdepasse" id="motdepasse" placeholder="Entrez votre mot de passe" required> </div> + + <div class="mb-4"> + <input type="checkbox" name="remember" id="remember" class="mr-2"> + <label for="remember" class="text-gray-300">Se souvenir de moi</label> + </div> + <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-lg shadow-md hover:bg-blue-600 transition-colors w-full">Se connecter</button> </form> <div class="text-center mt-3"> diff --git a/sae/WEB-INF/vue/parametre.jsp b/sae/WEB-INF/vue/parametre.jsp index 1d59232..f9606b1 100644 --- a/sae/WEB-INF/vue/parametre.jsp +++ b/sae/WEB-INF/vue/parametre.jsp @@ -69,8 +69,8 @@ <input type="email" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" name="email" id="email" value="<%= utilisateur.getEmail() %>" required> </div> <div class="mb-4"> - <label for="motdepasse" class="block text-gray-300 font-semibold">Nouveau mot de passe</label> - <input type="password" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" name="motdepasse" id="motdepasse" placeholder="Laissez vide pour ne pas changer"> + <label for="motdepasse" class="block text-gray-300 font-semibold">Mot de passe (ou nouveau mot de passe)</label> + <input type="password" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" name="motdepasse" id="motdepasse" placeholder="Laissez vide pour ne pas changer" required> </div> <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-lg shadow-md hover:bg-blue-600 transition-colors w-full">Sauvegarder</button> </form> diff --git a/sae/WEB-INF/vue/register.jsp b/sae/WEB-INF/vue/register.jsp index a21a7b4..0ab1eb9 100644 --- a/sae/WEB-INF/vue/register.jsp +++ b/sae/WEB-INF/vue/register.jsp @@ -49,6 +49,10 @@ <label for="motdepasse" class="block text-gray-300 font-semibold">Mot de passe</label> <input type="password" class="w-full p-3 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 bg-gray-700 text-white" name="motdepasse" id="motdepasse" placeholder="Choisissez un mot de passe" required> </div> + <div class="mb-4"> + <input type="checkbox" name="remember" id="remember" class="mr-2"> + <label for="remember" class="text-gray-300">Se souvenir de moi</label> + </div> <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-lg shadow-md hover:bg-blue-600 transition-colors w-full">S'inscrire</button> </form> <div class="text-center mt-3"> diff --git a/script.sql b/script.sql index f8cfeb3..a47436d 100644 --- a/script.sql +++ b/script.sql @@ -8,6 +8,7 @@ CREATE TABLE Utilisateur ( nom VARCHAR(100) NOT NULL, motDePasse VARCHAR(255) NOT NULL, dateInscription TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + token VARCHAR(255), CONSTRAINT pk_utilisateur PRIMARY KEY (email) ); @@ -50,11 +51,11 @@ CREATE TABLE Abonnement ( ); -- Insertion des utilisateurs -INSERT INTO Utilisateur (email, nom, motDePasse) +INSERT INTO Utilisateur (email, nom, motDePasse, token) VALUES -('utilisateur1@exemple.com', 'Utilisateur 1', MD5('motdepasse123')), -('utilisateur2@exemple.com', 'Utilisateur 2', MD5('motdepasse123')), -('utilisateur3@exemple.com', 'Utilisateur 3', MD5('motdepasse123')); +('utilisateur1@exemple.com', 'Utilisateur 1', MD5('motdepasse123'), 'dXRpbGlzYXRldXIxQGV4ZW1wbGUuY29tOm1vdGRlcGFzc2UxMjM='), +('utilisateur2@exemple.com', 'Utilisateur 2', MD5('motdepasse123'), 'dXRpbGlzYXRldXIyQGV4ZW1wbGUuY29tOm1vdGRlcGFzc2UxMjM='), +('utilisateur3@exemple.com', 'Utilisateur 3', MD5('motdepasse123'), 'dXRpbGlzYXRldXIzQGV4ZW1wbGUuY29tOm1vdGRlcGFzc2UxMjM='); -- Insertion des fils de discussion INSERT INTO FilDeDiscussion (nom, createurEmail, description) -- GitLab