From b83ab41a5abaefde4431ccd47e0475459962978c Mon Sep 17 00:00:00 2001 From: Stossy11 Date: Thu, 2 Oct 2025 13:47:37 +1000 Subject: [PATCH] Fix Localizable, Update TunnelProv, Add fix for Duplicated VPNs --- .../UserInterfaceState.xcuserstate | Bin 43819 -> 63234 bytes StosVPN/ContentView.swift | 356 +++++++++++++----- .../Localization/en.lproj/Localizable.strings | 3 + .../Localization/es.lproj/Localizable.strings | 3 + .../Localization/it.lproj/Localizable.strings | 3 + TunnelProv/PacketTunnelProvider.swift | 132 +++---- 6 files changed, 318 insertions(+), 179 deletions(-) diff --git a/StosVPN.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/StosVPN.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index cad3d9339b78f39c63894460e387af49cea23d35..c3edd96e91193b31d9eb18054949c3068e538637 100644 GIT binary patch literal 63234 zcmeFa2YeLO7BD{d&g@Rxnc3aYYv@JN8=aSeAP}-4y8!~Cb43vZ3-(6I zhOSsp5U`-wP^_pZ7VN!?KD++Uo!QwWY(RXE_xb;R-xD|4%-nwZx#ylcv%0dvABc~C znL!L@ScYS4jGf^bX;ROH-Wq>}uWE8nPfgjJ3izwIXTVoIsi$w|TyI&x?`F`7jipX) zY|&_MowqzAROm%UV8oK5fG6P9(VZ?^4I?uSrY+NsY0nI1hA=~!Va#x51e3vJGFePE zlf&dPBbiZ59&;`;k(tiSV9J>}Oa(KasbXpvKeLEg%$(0GV+eB*vx2#lStENqMy*u=oj<{ zwqZNwv4EY}h26LV?ua|#-nb9$i~HdioPZN?5+00);7pv0N8-_V94^5V@DyBw7ve>D zDLxvVGZjHi1oKlh|Z-2s@N5VJEZau^zU9 zoy*Q+{cM1(WiMoxvzM|f*{j&K>~?l1doTL{`yl%edx(98eSv+AJ;uJyzQ?}L{>uKz z**TumI49@g+H)Paj$ALU9~Z-=aH-r_u7E4##&P4hBCeP#;U;hsxk=nKu8b?^yxe@Q zit}-cxW!x@x176}yM$Z8UB+F(UCG_R-N@a=-OcUd?&0p`c5{2U`?$T_K5jqv5cfFu z1os^GJof_k8h4C)o%?|Mko$=HnERajn){La$>y}RvURj|vh}p}vh}vb+mdYqZ6j+H+y zm)KX>FSTE3zser8@37xyztg_QexLn8`$P6a_Gj!b*k86EwI8#;Wj}6z+y0^bQ~PK3 zZ|vXNf3*L^3%tlnyv#dzg;#kuAH{d%JMo?QUVLx951-Bt;s^6X_@VqTemFmZ&)`S$ zqxkWB5ns%g@RRxJyqBNF&*taw)%*g!hQFAC@t5(d`L+Dj{H^>tem%c| zZ{WA`ck*}fck{dXJ^Taw!~7%sEBsOZRsJ>p82>u|2LC4i7XL2)G51J%xxzf5Qm7I9!XjabpbJE}L|7%P6|NSp5v~_*67Cf467Cju3HJ#1 z3cH0p!hOPCVV|&HxL~#27JFj1%L<1Tj%OR~#+oi(|yGVu4sF zjuXd=MPjiyN30O%iu1%ualTk3`owDSd~un0fq0>)ix-QRh^xgl;#J~W@p|zFajUpZ z+%E1AZxe49cZzq2cZzq3cZ<8khr|Qo!{Q_2LGh6Il=!rGSbSc5MLa4V6JHlU6F(Qf z5Wf_^62BI|5q}eZ7yl6dlo*MVY?2^}k|ec}+Dh%D_EHBaTIweClzK@?QnHjHrAlei zKxwcvOd2kYltxK;Qjt_Fl}Hn$iBhRlF3piDr1?^nXCjBlWnU`hRAv@((ayz-b+(qs#$I5YXyqq8>%ERR0@(4LY z&Xgy}6Xi+rWO<4_Rh}kKmuJZ3vR9rf2jp6Lp{&b9zDQmnUoYPv-zeWC-z?uE-zu+@ z*UQ`F?eY%!Hu+xp3He$1Mfnx^sQkM8hWw`df&8KTk^F`HrTn}6hy165aUchFunyVb za43$}jy8_Aj((2*j&mFX95IeqN1P+xk?a`k$Z%vj@*QIwV;u#KBF98WspC9{$5G*! z>p0(`J1%ux?zqBnqvKY`M#nbCcE?V~-Hu(3dmQ&U9&sFUJmq-a@si_Z$19Fwj<+1| zI^J`9U7nk&Qxcq zbJcmOPpwv0s;kt?)Ya-5^>XzJ^-A?Bb**}}dcC?%U9WCXx2oIJ?dsj?F7+PuLG>Z^ zfcmidn0iQkL48p@qQ0cQrGB7(rhcVDnM|ur@>+stwbIYa_G_EmOcI`44a z>AcH%w{w^C9_PKz-OfGE`<(YX4?3TA9(F$CeA)Sm^KIul&Uc;fIX`lK=KRii!uh@P z50}j)yEK>6)ymb*)ydV_)y>u2)x(wM8t6)Q4RQ^34RH;14Rd9bJIy`No$emw9_$|O&UKG<7q|=EliZWtW$tpf*FDQU*Inga z=w9Sr?5=Y!cVFhd%6+Z-I`>WPb?$n1(7naI)xFKV%YBdgUiWVI9{2t3hujCdREm|R=&h2jLK+?lZj&5OdMMjJI`C^p8~%_8uNsnWtASkKghTkw~lo- z$h2Zw>m0!s>MKf}t@5&SCi-gT`Kvu;-fUl4?R;-lpw!tjH8UwADN=8adLQ;BidQwJCZgNVp)pG}?KQrh~r^a+-Ix(G@E=*S@n(4-LXL>L_nO;n9 zrVrDX>8IOtyUy!^F6xpl>keJfRbA7ax=VNKQMCFw%m5~aiDlxLcqRcpNlY@60)MA5 z1DSNam3|JvLkN0IAEqxMcsTtrg5XSoi{K%_WdxV&SLwq`o$bbZ%U~8cEKhA^=$&CN_;Y|a|xiCR^~jKkG9m=_T=e}_00Dg6Vr;k zl`s!)d3Yr8`5u2D%QwHe(hH9Zse$GXK+onQ=+%l+vy$jPI?zTTJNs+)O+iF z_5Lq0lK{6TGgFwU%ruJKGoibw@Vmxa2@Ai_t226Ay-lfe%B+e?@1VH2xDr1MFwP(F z`TcbX331uph2BbEwYMg&2p&x+92@?f?<@0ERxB~V7w4^tt*i!E$5~Hd>0|wYnu@B~ z{v%8&a~|ViW==6lsS1{AlKIu^FBw||*b{`;Ws}Ah6&O}((?QQR2H3vTnfbQ|Xn?XR zFrmV`DAvEIVpgDOyOl<}9ZQ}0i(?j-`O3X9{<8ToWpgN6_+w_9_yX%uTDl0x8>Ug_ ztFHUY#cA5Z0;7k{|MAjR1WvuQP5WDD^w;%2?$7H#v;LME{dFsKjy+?@6xUW&c`Jb@ zEQ~Akl+E)78Xr`Ydut-0q#J$oD0OC>aUUn4X-0K*WV4qT&GssF4*I*z#u~UnF}>;1 zUuLw|r_`Bt#_bs_4O%PnRn4lH-L$bQjmG+wI?p}h#zJ#$99$e7A#kDC>Y0n_SCa&< zX08DiKzUzXkhz*Evjos}%tmI=4(5912IfZQCgx`57UouF9kZUC#c^-PdyU^X$EnJvs#W*f7e*`cTEBXqBRx4v87N6>WyJw>pC;67BIvBu6ABkMWDh{d2*eY)72?7 zhud_7S*I&+6|4%>_$sNo0sJTn_)(V0t}NMC>P$IZE7{)4fCuEz{0f67dc(54)Y>H6@d zxPQRF{eh*<(SH~BK~PnDt3byntMK~c7FJi4&i7P#W&>04SUn$P9%lvxnMaw&^g;UI zAoB$Cq&`F+YM`hkw5_G2VvOn~{^{16LTC&`8C4aZVJ2+U`S3vt1TQsINKoyYe3Xtu-Do;&a1H3xQlua93)cDLA+iT2Q%%DxoG3IsV4dzWf zL(kH4^pTsGr_^8~ny-F!%3(w8n`e;4B0Wjtd=1;(xF?u1znl8Y$N(=Mzii%5fvh#`y#+Mf5WnM%&5!j|gE}5tZfUo%Ro*~I z(X+mS72vI+dnqR`~Rrs}iwIYBfX z&CuuSYn!nkRAvz0>{1tNv-IfszVceblo)F+X^ypy!z)3#t_3za)D$6>R4e!9hhD@M zQ8m4{-;mrfl$?jgfdW@q5n{%1W<`KqTu8b1H!)BO!J+|kalSvUqHvC{%3Dwb?9F`C zq*PJ%=*9vG17j0o{pIuGOqC%nzhY($aO$|+8n96)KKSEKo<-~|>s{O^uq>&uG&Tq9 zA{bB=Xk36Vv2%JG=0;4oWK6XuFvmaiWb?u5t0q}T9wee0oFsUrJ%qMJq~zkW_tre zJvH-FlVc3l5L4mvC#1&4_YU}cm0%WDRQZQC;TwV2@bg#$Xd%Z)6TyV$7_?DQ>cYb! zXv0AClDsTmjrYvSf)dC7km~Ov`~Uq&WvC=*9$E-?8mdI|Q5Eu`YP0~=AU_JAT78~g zsn6G|be~?WFVJgrzaH3u7J(BG{-LGle6$RHUkGl%T78M}Z>hdoUjyGRH+_B`8kwZ2kngxbROD*}El&Y+#g7LIGrHtCZ9A6D|6#1H( zsky$&aix@GEMKzx4d}!IU5YXjR-MB(u7_t)3T4ur~bTzsLKG*4s^u_S0)BC&J z-#S(2D8bTYZbciIHbJxwt=G@jmj%&ARIgv4UrPPV(IDLFX4m*?tIEfF{osN1=Qm#+ z!#4}|oe8~@URoV&K|7c>4QMOchPLY$>bg!E&~4~;v{S!GzgWM7cGNp!Y9K?K^$bdL z4Xj|?X$ltm>ar{Rv?3ML6hht_&;uiC_`&Nl(^C_>sG>YD=Lot7been7ZZMEyYildY zXVwM0{sO0SedW-@j%j&MJ)~?{a!bbCe0{m8`QC^2P5|#=NnUmk-N%$2LHnWp{gL%w z8+qP&RZ~aqx#QcMebernzDZx+V?_BzhW=+-Y)8?7Ahpb_WqJfXM&WP}J*uzNR|V1I z%oF-$pqj0iQ6BQ}=X=q$WkH+A;J2rS;d*8|Y2+7CMgJM(?0^(R=89{c8Oh{aXDx z{d)Zd{YL#J{bv1^9q7Xlt$&I>L!Se!e+jgHYlznC^_}`1@cqvJ(Ympx5$gx`b=GM8 zS4!)@>FX?7{}X5(GZ?{#)z|AA-~-+QSI=I~p3Xrb@L~}=04uPBWj&}j1hIlueUrYG zQXuTHoQjUmfDc$5MBz3R?HeXC~7x$fQ`8D9f`z_Cy?F0$y$ zNfliF^&@*-+46SW(I?q38vY+@PoMQoXo_;wB*E?jHJYjnB_5|2*Lz83F=DFP=Y2CR6$T(^V!uJv%4P__iy`t zGRn(qyncU4prX#V&l0{(}Bu5bwr&^dtJwvnMF-#}Ao;;z1A;F9q=d{ILGA{z`

Uh32zC-vKDl(qJPvgV-tNLsDu?DmgKZlL=zaf1o%0BO z1?0fdNIB5q=zY_>?;3mQgE!Y)yk|iEJSsAdLDAPEi(dKu?6sFK%Dm}@IqSzpJu*q6 zBBPxtGn{T~72d}0nG)k&kQi^DdJ(PipWqXJi(~BD^?}jM$L;WlL zYxw>RrC0+>ECXo9BK^G(nz0<98Ea$h^rOG8e_(w2ySVAj_Ms863hRU!uqvzRAL$u_>dg=7b*mC_x{ih&1i=D0itp9e_*a%z6`se~Z%2ojz`Gqdf0$8A5BNoVc z+#1qCb_qp@!<2XE$0+Y;V3z_yEYp7ng!qFZgbq+9kx-tteD?c~{GOe2>%pI&x_aH= zEQ$~pL(xkji@uTb30-R(tJpOrXjki35QI)WbgRPE z?7F`N+w~#X21Bsj!lV<#n!qK zyO#oY4|^X$b^@CQ>^^osK>|VY*`wbB?4u_A0>CJn*I#X5A7dX!I|&jAlBjiXgnbI2 z@N^^;((>3DYxm@LTsic`QTLTxe4GO8St$BkWYGsF?VDWk<=CZL>n3+ylwZE8k%C`j zUp6u9C4Ch^4hpBE`pX0<5jf_;JFTU8gFS8n_bm!s?KG9F8XvG<|1Ic#6N2vdA?W@@ zq3g1s+scA&=SJxMMxpyVLGBQAIbheI1#p;t^k)fd#u-2QJG+Gj#R;4Y)8Ir-BB(V% z@YTU71hplo!&xI?&ds$p7MN>A7q}g)71x$7aQnyw?gA%t4BX>7anX_TpX<)`&@UmV zBSD=2Ex6u{#`TGWb=2}__jc_!;(}}J+b?+Jg{Trh3l3~Nt_2&f{gtjVTjh^WEXn`i zB1*Wcq3D{(qB9Cdt|+)|%;60W-G1oeZzsJ40{Fl;%>*!a6?ctE!B8o4H%KTe)@IdTs-^k*nu|TmwOX1j7j$K@d=LCP7&QWfPP`P%c3ucW|3S6udn| z!8<7hkFqFubeMuC{*QvszWK}DPbv5Tg7Pd1K0qn>Ve=nB=Z60W)fHR7ev*5dQt%<} zDT49|8WZFWbI%YomY{KGkAh$1Oyz_-C8U z#M=}~ty3&&ovwdH&@3u%XNQ$5n+s6P<|YudVg~5hS{urhtu5YeYfJU2Y37gq&VHd$ z**e=mg$dfa*uc>^gP_u&t(y%rfb$4Mx125W*Ve~&j;SXd25Se5U$A!2PFsvEmg-3! zf@XrAWJ_Q)TVf;#qE_s7-G5!a_p|TJDEd`3EMi%XKzO;7Ebt4aKJht|S zd3=}W!qBp%+lEkRJ!%_FWmGxnNw#5ByYoh1xU1KLPQhB7Y}-f!$hKSxL52>^LfBapom$g>EVX92kafNYyhf0u;_Ij3P}*{c*c zu7RT0MizA)i`upN@M!k-T6zD-fn~MSlO;40#kL!5x0ukrnL>Ns4>FWCUOFC*ykvqwV5Y;T$*^adrN)gV@E$Ehe@6G=jxwOwv|-}W((knIE8 zhqjLh0^GflpsN~epV&U7vUn{)SO4R(*!B&O<+qV!S+V}kz1+B*kM8<>NOY_teKV!t z@1f`qkwx5v&<$t(fRy1jusiG;1ee+syGqba1l=68JMAulZXxIpwVb2o_}~af zxoIYb5AP*Iw6w7~9vgWEB4kmP*LY^pvvzRCVGQiDj+rc5Qo}di`Z6v6kpddjFTkO5;z3~Ai*4_^v zAZQZ-=Q5B3P}LLQ`-JA(dJW1o!jm%V8c#q%JQPH}gpNb{3ufgko&zTy1OB`!It23w zUJ&Y+DucirPc)xm?yR?i z7ve5D{J-2&v1(V^tEq0#blb$f0PVDc5_30I4|c)8>zIa~^!cm3i*xJCmPzIOkUgLbv>D_6zL9;4F5Xa+Z5RB{;-w4_Tz?h(Y^vC@KJ*2O&+G?=CCTiSHQ3IsS0~TuBWueAB7HT|bpvE~?2Yc=NDQfH^=s>+4`hNItp~eBb z;gJV}0zC3yP=H6?{+QkH$Uj2RLBk_&2amkH1&{pZZ^RRa0$F`_e4G_`U?T_cK4J%t zyuAgFd`?#82DC0Gc-7##0XN?wyaGiHN_de@7r4U~z5k0)^A&;~H^S-cui9UOxV*7& zwmxWo72@)Y(y!CfZxHmP-oMAgqfD(698kFxi=!>(0db%MqD!jFfv%&?b3fKPy<>lm z^6qyDdb-~JK0(hkmsOvbvg&ZDv(AdKF%I(@VjyNAuvBl&nH+5%UgM?lsJ^O31~N1? zIUy<86Yoh%Or!tOlRf1Lo>WhwH_4keYhbEpU~Y;3*V5iCPCj*y6R?~_F7Ec&h%95$){xDsH!E< zP9>K3EbUes+=Rq}io1hbaTP*Q?`FLPfd_TTFe-1x@kKto^@KL`* z5McUy1OcXhK+uN-eYBOQ2_543WcZ{~JLzMSX?;SO7Tx%V`9%gLH`#57jIO3JkpGPs z?a0vSvlMMvXu&y?&jzl^XA$&iJ)c7m#15RfK;`rJF(6R+bNSIccoRP-2uStI27WAG zKrIEJ*suR_OM#!jX#B)TA-(?j(lzIe$|%`&ys~o_^wd7!#QYQ}IyJKB%W?0PoEUO$ z!wvf@pGkgsBowt)ZwBu%gc^Sy6>8strNEa_?(kitc{TchQfFRRrnhuJ`?SZdTNdnm z1z$-iXf8jGAmDfZ3i9(Q1^xJMQIMZsN+~G7*YXSbMf_sEjt7ePiJ+ee`h}oh3Hps7 z*lYd6qM!?bf=Ckz`V%M!^Z##9kc9$k_$w#@T~07l&tFL}`db8a4SxeAplkW-`0ELV zM1?HDTmye2e-jW8wh?Uq=Lu*dP(^(tRowF1`fg9Q8Z+aX^STY{xILG~A@G}^=;p|x zYrXRh4qrL?%?F-dySwX;J0EK#pl$qZCIRgL0>T0%pq)TKSd1i~Ygtol?V@7q9sc6RegxNBsQ|S9);Y4_P4~e-V7Kz<-cG z%naJbKgvJGKh8hFKgl2BpW>e;*h#R9U^l^01h*o%HNkBNZo7?thJTiSj(?tifq#)d z!oNgtJAyk9+?n7m1a~Dkn&4gp_cjb(%V^Dm1PqN@lz*z*O^AQOe^$?bN^nPlJ3-x8dW0=enA;|ll< z@G$%SkO$!t>Y{UAW?oh((LzCJ4vmY{V?^b{2I^RF{FeW&S>!eU1OFpMrGF9Jt)Bmh z;O-P8ns;%v2mAr$21v5a14{gF{2%rF?*#WCxaYW7b0{APC`jiz#RLys%1~DVC)k>G zB?y89T`@&^&w4>7xGzOo!)_N;0S=XK7Bs;rxCFNVxYUo}{scqzsR0DXY!+GzZG^T$ zJE1+nu>{8v98d5df(O&Vnprcfv=XNMSV*;UU#&lsYr=e(MRRhMItLiispay;#+lB) zEM62!*A$WY0diEe(0Zx)jOIEpn}!YgQx|JG25<*8E7-INxA~@NaRZNp9>6(-o&+c8 z{a+UP2z`Zqj3)FK&JhL(F_Xjk-Q+;Ue8{EcnO{BC3hIZXN(3hpoJ4RU!Rh}|s+%4e zPmYY*_Sz#CS};x!lEHf?Bnr@a3c;yCAw@_fIE~P#W4ITGgzBbz@sSI7s!D2yg}XuU9o zz=@6()4`iTb9+IO7+^w;0|#G_Fdl#dN#R(UX3IqW2?FeW8PDp4$pmMF0&<0Eh&M|X zSS8OB%0Y?>9$}^cnb)!i&L%jgLGTK*gxLh=5_~SfW2s!GNhTull9{Q){6@mDl$Hw6 zlw**|tGs#MvdlWOqEWAROZA$UryW=Wo-g=dYC;vkBkP4~f=B7Y!>b_#U^Qxmg*3q! zMMVQ))-Q<4BRJ25@nWG4d;)Ny-5V4ZhfmrGONC{$(enu&T`ycfaDJ0Up~;Jc<-*02 zp;0rF7{Oy8RZTqnml~fG9}^#+ker&34fc8BK=__jY8~t@HO_IH9j_2B1s>SQrVTJQ z2rGn@M#3=@tkxVa6W}04P*^RjA-I6x!k}=40Q%85g2z+tbjDqmI){`m3_x;;iZX8u zV5FIk0FH2$dFQ~PKW|O=IQ}3wBxyYikN=3Vp4SQsjdlEKkVH4A4yKswetFTU3FKiGt3iU!zXdt+l;1Yr-5Im9KNdyB@P9bB1H! zUf3pV7j_7@3AaPU@l^y*r~2>=f=dZLk6;hMGpTMorNW<6SuvX))dgu5FgPn@Er994 zq>Q8srOq}@ALsceRzQk5aKVGfHeW#Eg$bUT3J=YX*sKXF*AB1>vt-j8f0M(NOP#Ho z_5f%6y`VzS>`o{33?j3v22$-!nC~g``4>+LqlL43BUCDB_PQ82(O+E~0Pm3TC*5=? zF>q&^RVNWr08AX?DN9HhkZN+|1Bm8cu@?TI@Fe8z5grvD6CM|yAlOUrEP{c8=WG%V z2~P=63x^4=Ab2jp^9Zh_SkwmSu6e${Vw%?m@-9Zam_Ty{(gY-tuL`P-^hBl3_=sAt z{XtU=LdBxm`ST&2g^A=v-q|$Yp})k)4>2Jj4GwoDJ3ljL^$Ow}grmZ%!fOQ2C%A^- zMU9huLwFm~l?ZPNZwbc<1`gmOxViy-CcG;g(n05608^whqa3CA%$oIFSX1GvF|sD4ZDq;9)ZX zYyFUpw4KgQ%JNi|0jZV0)Vht@wtYuB^m)y5nAW$`x%v)}K{N`Oa4sClKH8;gbhqwm zkDk4H_vs7IiYk_Pp{rTBm7dvtnxM)HN9HT4Vfi5w>L?EoGpOR!sSA>@$B5ph1>;)j z)Oi82lC}k;js*qR%Dh&RNBhVGPWO^}&VZQMI8c4eejD2j<8OzP-!z$D8@G-w=5&G1 zEFq<1Lt;|0ZlphLNKG54(-f$!^(Z6R7VVHuB3v0fLSu`vis|!QuZN};1>GF7jn4Kr zDbmg=Qj%9f_X@+Wj$>I3p(1C@wiU%~SD&@c?Th`gr*BJg~LgO^~hJM8n`rsNTYJMqpe_ z2c{>}k4c1tvw3j*a~xB|_?TMeeC86k{oy7^D!7i>0NDcXWbR`QGLM0O`Vidr@C-zf zzr%dYe8c<>_c~~(9o*>98FfL?s5=^rGSM_t2l*>>xVd2!x*T1J)nTOdus z2DBS)VK@QzF8qRiGwxjw;6$|pYjE#E6mAW-ER4YgaJ#|;?1A&8i|`WI{#%J}fLj$B z;2hn4{49O}zmGq`U*qrak8n?dX5uwQ=5MAf^gHy61wDMBsa5M7zj~0{pZ?uoJ=^N_TU zj-};yY02@~si_$WG3ja9xiQJUrq2eJD7BFgqR^_idkZ|m;<01 zDUPDL<+TL=Krpx`!13@0VHtoK%MxxZg_jdnqX@Pn#(EZ3%r@mdeH8wadLtlS10K;6 z+i;HEYYHW^W?q%Q+F-$r#lkfW*)@#@7#NwbASEP7j4|H%zM8s`khNt_<5O!4;U3J! zO?%d8IU$YOgN+X?94--OP#m5hP827Jlf^0GRB@U(o#5*TzMkM42)+^Sb0PR`c%JAHXNqNFx#$%^V_Zk@c7k^hyocb&2!4fN(6m0L3)9~)jA@2c(=!%Ap_07V z@C;+K%sim5K9)Bl{0=0;NJtw~ZN31V5ESwr;U>rW0-(eDscYZ-+N55ma4F-p1(#T3 zy+FL4;&m9MK|-FQNWO12jN(*pb0LeFwXO?9$au6#tP%ZUK&&NrJ;56Y-bir$CUKFt zSgaEl5ga5K44qBzg|1ht+=@!j=tD6#)Jia{T^F^8!?UB0L1`(0+`BCmZfCaPEicJy z-i|dcB3{I_fgB8ApHtPmS-V9(Ku^%Rt+Fe`mEcqmFC}<$y|{{C$iZ=%T1Oa7yj;9O zyb?C_V4sq*A0rJeWCn+H1)#qhX-Ns*M)1}G7vfJ=PMv_W;2R5MlmT490YF*$I3SEMXcxfEjGvrpJhyhmGewMy%dz zd=XqdV~30`E}1yZGtal^^7@7?+jrgn(356mWJ%_>=HKC;FBoE3yjr{lSaiPnMw z7t{u5iXJ)`!=_wFmoo&@2Ju?)I_gq7!}6uhnWe>nky#TGQo*8c>;s4+F}3l}CS6jw z>`x1IS304nG%2C6oB@s^AgZd_jmlx^-y(Ml!EO{cfR-WNB;G9EBHk*l6M;%@BlvcL z!8W^t;5!MvYm2y1tQUh~12CS=1m8{YE`skN_+EqW?52d%tz~L8xW``*y;;U2>t3g8 z29!uM)iUTSrz@A|_t(;-V2$~VPs#kuz8eDqK`@+>IhkcCgMr|f$vnktols4Frtb;viWX z$Nujp!dRD035iM3e_0BY(Z*(q>H0Rd5c$qnd!zMJn2q#0K_9b_Sq?_yoy-f6 zrj2IKehrdizs-Ecd=6Iveh22F9WDWM!4-gA4P&tnq~INdhJ(qNjdIZ_NS1gxWZSz3 z?M27X52m098+OTI!C`#CuG0u)i_1PEK5L46>%j{m1jE;hFB1Gnz4#Kr2TzOsmRtw_ z8i?*k3!J-7CI;a@k=#$bx$^l3qVL_fF(^8MlH5ethPIo7irQnu0(0IyMqK`|@y!yp z6DCjdRxMa!z6}f6kU4BVg`ZXkiTH*H;doobH^sNa~k9uc9>I3*s;Ju+~ z7Q;;~{t8ej42%Na-ZndPWLV(}l{fV{s)|`{!bV0Fw3i8v-Fbd$_Jzzepbqdq8zlqa zW~9E-5Y8J2X#w|J@n4kZekYy~zZb!1d4}L;34V^?=QoKzig3nX{Dt5b2!4^y=?G=H z)ZjD*3{(`}Z-wFZfah7Yu(Mqi$oJG%mCY$KNo+jb?}l{srh1wHrAB!cLN-AoMOS5= z)k;=jiD{tF#hC-w;6NQ?CCr^6<6U#5A5+M(|OBUnLlD`Iw=H zOHqw_`0M`%^>C@9)EQ_{>O}Ax^->pt-#il^5lY=51jUui4?7)Md zNarq41ROU=iw;#yDxg)ncWIF29$+yVTkhUP(IM)Bg1yWJ#(nkb8YtLDsh8m)+*d~j zv|;G9_3-c<1!@nNG8XF5M5*2yqkVW0r@%9q}3g*0UotP9)% z5oIk2;B@#lA*2m58@l~kacun%XliH_GzELet_b5JI3g>Uk=cYBMw{F$n4Qza^jLGF z`IP!Fd%}fTLzvOvyqX72s#@kk5JIcrT9li?cXum{RPfJ8vlg_R<8NC^%FZR!t5;#fM^S;kJMM{C-s-kA^2^A z-ys+{@_Piozgdc5;-xqVVn+%7fU@Ba3I53RkhOUH!}KbFk{jl*hR&Q>XBg3N#3IDo z!b%5lIO?8kTB8Z4H8_<~m9oL6g-k8Q)H|$FCRa)~xRUvO$Z0rKLgP&a(g+E*_JdM} zlu7U>1b-ToviSspKcj)NK+^3O)WYpwg|MMCANB=n{1i{jthCc-84iF#516qvRo1GW zD?vuZ25GdEFO4DibArDh_{#>VKq{2R5&RXwUlaU2ZMYLPwR1fFx?-QnxdYyDw5w2f zireV72wYQe@tK*!eyZ_^?vl}cJt{OZJ%KVfx>HqN33Mj_W~+0hd8Swj&&jCRYypB&C2gLD zHJqkY@hn)79wVwp7$|SSrCRb+FfWi`fAU9ye}dRMi6+{>KT}}zfdH@?U|nV$S=c3L zAaFQ~bY3=KY`115A>ztA8@z!{%b4i51a?KGrPBG*GJ-+g|4Q(0^sa?Q(~f$^!W~)d z!~#}>cWH3gz&zP@jjYkE1dz$eH}XW*FfLRY<*lp^^D%3YE|yk6Ooem_!GG4%J$;$wLzfP)W2HhrIFWn&BDBUF8EZrjADy@^&OB@YBz093vpJ%$}+ZEqCk-*{`Q zlGkI*!)Vfq4VCsw4^ZT}pRmq)=|RG}%tf3~9A3XBy5%E?4@w86M+xgDY`bv0fb@g} z89N%JC#6HuQ-qBoY%9XHZjcT$>C&@=Z38MZ+ZH0L!0v3crKi!q8uu@p@F&I5F`n6= z5!aS`C&OgSk@py}=DcQH;T7pvOWnN=-MvZJ_Ov@AOO|G=2V8~$TL5$|dW`Ux4Z)74 z3HZ`{@2o(vZ+ykX=vOOii9{a?(E_ zR8IPnu)QEwPR23|Q5LBpT$(lsm{Br@}ZaxHZU~MW=c9E#tfzoyu`c6 zkWJ$~iwxQX!QY|z+feAQp-zEZX!g>m4wu?BhO9vSHqD9{ty9g)8f%uE58Hrpwwxp9 z$|L1ba-MvyJesiSgdIfK!Gs+`*r9|4Sv8!nBVa4r_-7nP4GUX1ZfpqMkl>}EQem&T zbwMHJUZKl_%v)|P!9cgOTP#iY>-{u9xOw^hrz&5Vmt73+Oz&q%>I^tl;V}@-Pgy|o z;uNu39t*5k^P;C5c2Vt2zj2vk^YWDcwAeJnh|_H^8m82|#wo{cDQ!)QTi`5}Js=F_ z^9Y++FV7@w)@g*HJPU-OJX@Ya*lfa%3=2bfo(zdmBZQ$`&7{jUgw3JSDOX<+rjZ^a z^uD18%K1h42s?s zd8NEczD!;%uaQCF%O~s@!j2_u0bvUXI}Y4;@>TL$_;(GZFT#!|Y?1MQu}Np00r_hy z%P9#ILU_e^FIXeSEyqTT;Z&+6j0V8~wqFx%YI>t0l#m2WGL(M745bKRnU?1_{|@O+ z!0fEXO3msZna$7lcAC6Vu9t&^Eg|d#!cJ_EH_4k}Cxo3u*c;3|3~nlBGyJ3A z%n0cDh6Y1b+7S7}%SI^#8_0zfaFbVgv!~{%2^mg!Z;^M(cgT0jcgc6ly9hg(us0DF zG@$nh=OA2~-v5}qTizqzC-0T_fq2+2-!DHPq{Pw6l_u!G*z=lcFY=S}Aya#ipCRlF!cJ|XRG8X< z{2XWp^7Dk9c9M1wRt8Qhz)PL!uoG?F=m!QFFo)3HuZEcqp%RVTgVvp?;iMvG3B=%J0hW5w@JL*Hg!2)LGAJB7ZD@N?Ft=g!R_TpAmMJ!J2diNI6cnJ zC+xLgV#Dci_B!+Q_^Ho^|Mj`@f9UjhX#Nh)!2^ICHV4?6RfP2g9fAX_&1%A~qyYM> z+$8^g-V4MGpgEj`T|n5Hpu_C|1IbTV>Psyv2qO3OJqEO-rZ41)~@2Pkb9)H{X~_CmT;XPUgl zk>wZ(vfGjE$Z_NnRwpbW>_rWZQI0$~D$6b>>_30$mZOl-9OEL-zve_{{csdR(UQob zk-0>y)tls)Y8;hyOo5}a>G4;>=aaH z4R@Xc()ex#YHHt}smA6ZUfY<7!GzCbli3*alkK z8VlQqg>B7~1z7`F>9~wy8w~l1ddF(QUir7M?Mesa(T&8mYaQ27Y`coEYw5x4BaWK@ zj5kMuv4w0wj&)FUePq#7W(#uEJK!J^+;-+@pb)|TW~w}l}#QwdF{jiJF9QN&@p z$3(HGnF$S!!;WVh&k}YWVK)-CKCDE+@LrTb(!pRhfJX&Js z4vK;THw;R){Lu8BIF3`_31J%y=SitEgDR_Ml3mBT9Lf3}9z>J7ksKcyseIVYXQN$E zxT>k427gRbbod~;^u=^=9J}Z~=DczKwluJIU^netX>^>?N7XX)xye-8VRevQG zSi5qLGC+wTEO_T1Anbz;N}Li;S^GnTJ@Aj`+)&aOO&J&|E4sY#boUo+8M`+xc|Ych zz|HlLb3+*nMTbNd-8OOhSJ$q~K5^?-ZE|k*ydB}38_IAc(-1341{EuhoO;2iOh`<~ zPDxM7jLA&Ng2NM;S=lie>51teA~JKcGZGTAQW7#-;Ok1Ba;`F3$ydh62jP36GLEoM z681U5zCc(oe!z|cz79{oihaHrUssBh;zqvyG+`fa!q*Kht-$p>4a!tynlhcRPZ0JH zVV??fX(f+3!fDggUkY4W%Qz`-hvhIoQx>hvH(B)I5Q{zwnL{Q)4vopo6lSUtFgf(I zXCWa8ctM&O?nast@Va{{BX>YgV$;SFf$xqMwTPrnxd^??#lO4wJoDa)0Ml}q^Nl}nYC$|?nv!`BFVjIeLeye90Mgnf&! z?-2G~YEids8aLnQECP@4KaJ{*>)hnQ?9IsbEpLv_EMT-eVlxq*I( zi80B!NpQPlT4n-JX(rHad}?Y!LV8OCx=Xo7xmVe(>;VGZrR-Do6ZT`meofeK3Ht%z zWP?EA$(Mxvra6H=pgh<}pq~@=!w3R}bjS_LW6I+SQ0GU4{gkkuH4^A9{de`L$k8-Wtd!#>*?x6aZ?yzu2x(Yl zF>|~gBk8P}!sTyjSIYa!SD;-fA1EIxA1NOzpD3RypDCX!Unl^~?+AN>u%KrBK-hl~ z_D910MA)AR`wL-z-JyJKYFEk$Q@c`rq}tVQmUi`rrCo92|Fo;KpGI7@fp(<=ZTue6 zu2d1UtCnx{2yq$JsYZb;S6!-`uzwPc397Bs)`UZZW6zp~rFKvuFcdT_wG(Jq9K^Dm z@;(o1SUuD}pkk>#)n00E!f}MN5zgMA_Er0VipBAS6aH}(OO0nVH6c=OYT-5yH5rPg zL>4{eZ64}Cb+Dmgse?ep;-u587_ji1l$5Njgw!lx+@NSBr{^Zb3{20;jLAsO&d5$q zjn7KVXi3LXGadWXY&A#Cl@F?;)I6}AIdIWzAzVAcDTGUiwnr!)Y%9hUoCZpa7 zx-2&!GIwI@Uo6giuL{>&HmJMRJ?edgizQqf;o=+Aed>P7nG*;VEn3&L(wN9i*Daj?k|{@{lq0dyuD)XqRG#MjbHUC^%;{h zAEul+`810L=12g}y?84jZlcN?7~}CnJZ{gVocPql#Dtuf)YP;zxXpba=-XMjsWB;8 zX_<)$iP@P+iSaGy+v>~eE9z18RrNJs)-S7XsBaQ(FyS%@mrb~Vgd1ZpYj`q(a9Pdt zZS}bNb|bSMMmW&O`Wta%;OI207WG5QtUppeRzD%!Ai@C(3~glAFN>d0&N~>63K{x# zD=Sh8VjF3yBqPM2WiEUgMO*#JWX-UP15sb4&YUx5&7tls$7O7@VKm{$f0`UQ<7~AJ zk)@6H@nSd)?rqj}4CJtelZ}BoBN-;dKZgU3Tk>ntgqfxh9il6Z(*%f~&}^Dr1NA0{ zaJhsV*}y!ZNt#TFaunh6sKG}=wMz^0^NNZ~bF%Y_3&xig<>cpN73UR{fCmXgClH*gs9?eWkjTtyFCov;8Cnqa0GsjxEXblcs+@^KYx@$eOo?0)h zx7J7NtM$|RYv&NIfN+I`8%MbDgexLkG2u!G2Rg|_!c8LF9Sg!$6Pp#Jgm#3MF*kUNNmQN9Ej5d~V(+M{- z94n=b(@H@0Xydga4FEZVaHWJhuR)t&gfep;8h!O2gfd%0E!E0e>ZRO>VCKqbFD*te zM+OmV^R!CS(PEN_kCH_-;bu2Z$*(Pe7!WO>)oKg1McQJmj=<%pTm|9g61W)xm`x*wwiF&dcn(#rd^?3sa>V51^#sn^8`r3Dj@GB+kD`wYgcBT!)!Jn8Vv@! ze-JuvWSMPRgK+C89|YHY3*u3`-my=+QM*aISw5)Us;$%36Kn&h@_MemEZt50490m|64x zA7jqn7&GD*dxVAm%lm+cCdg0`&4?C6D+r4OVFy51)Nh80D1uEa8!B|#9sP@;ep@K_ zPrE5%_^X@7{NkoY|FoNaQ>^zl%TuAqXp~1B3v?at6c# zVa5OU3&4Bcm32Hl;~zZYi)qyYD$AV6a<#&@|M|-^1gHUcsE7{0 z0+6ypX?ArjKv)*}nq}LB%8dSuLk9kqLtZY&`QmPX7Q`9@+JFwA3+Ms*02zcqiFpeM zgS6)v2p0pP(_8O*05APgcEpcS_Lf8t629kBS_m6|{p zwBPe3XOn~gK9^3tk$9`AT1}OMyvFz`G+Wh+X7XeV2XA8gr zih&ZK6et7AfeN4!r~;}%SRV-M2VnysY!HMEfv{l^HUh#%LD(1w8*c%=RGaeQfyS>( zh5*z=5QI(q>X=i%Eg3HT$1%UZV*&$^V*=3UGWm;R0wezjk^!cHW6LHs1I&Uj$j4@C z0S+(+!l3Us-_0q3CE&!e=uZR3m)8o9L8AYUAsOHtaB0~k&jS~Liy#boKl31Lp$@nV zTv>L>MG(gQ_q*gR$og)7YkhwL$pH7DOYeVs>0d%Jz$4)4SC@RU?2^2{9x!OR<6nei zfLDTa;Ah|s@D@_nSHK70BM5`m=y)LP3J5z1!k&In*E1jt`T#EfA?X1=Bl&(;*Yh9@ z;xYcHuE^Dpx+2#g*CN+}u+t#yEC@UIySl#mx*K!m*A1NiF(iXTe-&2<`uMUO_&p&R zq|{e!z4Tom8O%Rg*ZUI?1}TSBgFqOh{F)i0A`*jCLMkIwkg6c;>M{re`vHVq17X)e z*bNYN6NKGrLSm6PB!10tq&kv_)IgFz7(`Rt0b%!+K^WM55C( zke-4)NN?nJS$ z4ZvV+ZjxW>k ze+Pp>W_+EPZ@)7J^DjX!$ZRAFik6T$$Xp}?$wcNM^N|I}!^lEp5eWML!XRz^1j0Up za6S;e0)(#w;j2J641~j5ki}ou7m(#&qa|cD6fMD5{}L_1*ZvwU!G-@5Eq(uJ3AtRP zfb0a}YkrBAkkI*V{}_5f4kAY&Z$=Iwhe7x{5Wc<^If@(u;rt+6@ViA!$Z6zqShivs zISWNhZ~-U)fE*Mm-Lw5BP5vcbM{kX*k&{s?8HaLMJ26fOh8#X&e!TUHFh^+CAQ-)E%ASIF1D$u)d42$%Rqu0Jfx z^+)6Mj4se-nB^0bjHmzU3F~ z{_Z@=Z_o=${EL3WrT@2}7nCGQ9@1pg2GmB>Ce&us7L*i98YP30MahA1Sr87r%7btP z5UvQqF(6zCge!w^6%el4f>QXZ$tdNonvB9OYqHv}nhc%ms|zgx#ei_#|7h~}*JPAF zq{%2U2*>`S$tc6Wf?j^nJ`@#2hvq)Y97O}+co0sgMOmOMLAW{y*Z6LdjIu*HevxF9 z!?Gk3A%XcT;N{o1<%aTtBpKz7@<4fla1sdD1mRkBC~wsEWl7cs;X40zNk#?mAy9$e z>g=D;E~wqmrNQ4``j@l|YA-76izK5$mnB*6AB@*6!aHu z1>wdZ+~hZvM#X%gU7(wNSK0+t`Bjt6e$nLbPP?EQzDlwA_oH3@Nq_~_jB1Af7E}wW z71aj9EkHOleXSsX1=Wc<3dKEeYY=X;oTz;ZpZxy@SWx{CUw|4w4T5l65N`Jiz=9h2 z9biF0=gQTfCP29T|02Nh$LDqyb?o=&))j<1ee>LMm!I1u6b}Ujht42;8whv#?YaHC zP33<&;rrtT@~`T56Ls%Pb1Bqq)E$2L<>pdwcM$FYwV0|$-A6rGw;J^bghRTxb2&hP z2QGiQf8IXoZ#qo<`n#W_pbE}<)C<&)sF$dpK)4qO_XgqHLHLgUbDgAw`Gi+O3l73i z+UHXv45fX(%YP{n>H+p!qpUAoY`*Nv2(N)2F5$Jp>p-|42>1Vu^bi&h1|Tc>dw7Lk z?rZBI+%i@IwI2Fqc!b4-p~}Z^uZ9j;65a%jKXf%bASq4OkfHsz{fUI7g_WVjCSe(2 zSz$S0d0_=%MPZCE6c+`7@LeE$HwX^~;d?-M2ngQ`!uS2B=hc7Ns_Wm=^XgA~AVTf= z(R?y|s$UN7GJsBWbLR8l^Wrz-x8!%_-@zZuAI=}eAHyHV5Avt*r$HU1s`!ubpXUDw z>LBxm{~iAa{!apY0xO}eE32VCE9(UW1cU?tsNo4wfFz(LpesNYFc8=Zb;mFhpb1zC z*a+AQI0?82xCwX&91u7RwGx;VxGx9@$_Q!;Itd0rwS1+5ZGzVXUkiSQDn`VFB%mUX zjY6A+q=aOkstpCGQbSotOUOXTLdZ(UM#xU6L#SV9N@!8&Bm}Wu6M8K4ROq?Tj|eS< z3Bn9vj-W&2P9vfT0%qEv?R7Cg0+0kY0?|MkkO5=@*}zrcA@CS@3Ot8aM7JW1k)}v0 z@*uQCQvfZ`u%HC_2jq3+P2_D90i}yFf?`QWR1j)6Y7Z2?grdSxk*EWxXjCi|PUNEw zql!?)s8UopsuER$sz)7x466+_hx$<%C%i|vM);(NxQLBNj0js~Qe;Ntn8>`yqR5iS zC6Oy4KZslx#fs{Q8j2c;nuyXwEkvzEZA5pAMvEqkriiAB=8EQt7Kj##vP7#z`$R`Y z7evpCUKhP7dRz3a=zY-_qAx{XiT*75R`k8tTCw$F0%Ag9Hew!PUSiwDc8XPtwTpF% zb&2(euMig!2gFh0BH|w6LE`(w!^9)R_lw7iCyImODdMT(jp7{fhvF~AUyHvHeLocqMxB(pkJb2p+BKNORkVyFDWRAkVHxvOL|J~ zlH4m9Dj6;rB^e_bCz&9bC7C11kj&duy6MQK=1r}e+P6I0@<9qIB`hT>B`$@Q+90(_ z3OWl@N>)l@r>iXvqwWh7-HWhP}VMVGRavX-)y+9Q=MbyVt<)NARD(uUIB(h1UK z()H3uq?@H%rP

(&N&T($mtj(j4gpX|6O+`ndEJ=^N6wr0+;SlzuGzRQkD$unb;? zEMp>LCSxu`m$8#^ka3dPCgUoTEW?&LEAxZQBbiUKe6s6g0a;Pm&9W-86j?)AnykI- zHd$ZUAlcordt}38BV_l>M#-kj7RVOM*2vb&cFFe14#*D4j>}HUPRq{9F3Mh#y)1iQ z_M_})xfOD&NEsQ<0`p-l2*v%1QHtq`hZR|hC5q*W zm5SAh?TVd>U5Y)5uP`eyt1vLkYK$;O3?qTrfZ2rEf>Fg_F?ftR<{%~ylaDFD6k=*I z{g^?_FlH1pj+w+vV`ecN%sgfha~*RNa~pFP^8oW0^9=JN<`w1*<~`=4(t0HUB_Sn1 z$zI7@X@`=JlAlty(zw#3(zMd7@)~6kWhG@5Wi@4-GC`TBOj6cT)=}0|CM(-3J1RRX zyC}OUdnkJ;Z&%)_?5pgr9H^YCT(3N*{7^+mMMK3!<$y|&N{`Bj%DBp;%Crhs<*dqi zm5VBuRj#UBQ@NpXOXa!BE0v#B-l}|3Zcl^ z8n2q5nxvYd%2Z{kmZ+AgR;bpiHmWwMwy3tLE~&m&!>AF|C~9_U4r(51L27Yo32NzT zht!JH%G4^DWG~pcK0^t(j7U3@80pSthC&EX3M&rxTp7pNDiv(&5A+tnx3r_>kKFQ`9K zf1>_Q{WEa|5k_1`-3=v1vAZikIh!mnB(U@pTbR_N|?k7eOV~BCY1Y!~~ znRt+xM$8~)603-{#Cl>Qv5DA9Y$tXSyNGOJA8~*n&yv9Y1n;OqZD@iaCk|aiwAZ;K?kz`2nBt?=Y$(ZCqawmC_ zc948Y0i<1|J*0i4aMFHK7Acp+B;}J1lUSruQaP!TR70vGHISxAH#FgzikcRhp_+x7 zY|Yb}&o$p_e$f1^wL)vXmavwXmW0*@txZ~6w4}9UweVUbEp075EkiA1Ei)~1EkCUc ztwOC*t#Yj@t$M9St!AxOts$*Ztp%-J!`h?T$FxstU(mj!eO3FW_HFHZ+7Gnf=)iR(bvEfp>B#CR=qTx^>foT( z6C@pN9V;DM9eW)|9cLX^9SbOm*Zy4!U3>lW&E>kjLV z=}ziS>vDC^>R!;jtowuR4c%M1cXWT${aN>&?nk|qdT_n9dh7KR_2_!r^gQ&u^mgd^ z>jmoV*4v{Or}(vQgVeh>X+)5>sRU5=pWS|)jy?wM*p1t1^r9nY+CWr`|AheDwkQj96)6gtI< zVngww?4bBi_E91!2PiR=L<&ebNJ*mwg&bFdkyjpstoE48V#BaIt-2)^ceIS%ouPC&KO)axN30C;D*6{gNFuB44xbO zXz<=}t>Fg4O@<1FL_;$}b3;2rFGC+gKf^%7J%)P?!we$~Qw*7g4TepIt%eEx@mOJ z=z-B=qZdXmjb0nQF-a^B>U$yJkUCa+9YO?6E5O$|(qOifLxrtYSJrje#mrm?08rl9FT({$6rrYzG^ z({j@)(^}Jd(?-(?)0?KB&E(BY%-qca&Gwk>GYdD1GK)1!FiSEUGP`2-!0f5n3$vfh z-kNQ1UJHGsN{8cYqL?xTiNBdG~gkb01s zMrBZosio9%Y8ADHT1Rc5c2j$)1Jq&a7G$-0Nnj6iN=1mKxh0?-l`)RSXcv>P2q%mnF zv~pS%t%lY@>!J11`e{S75!x7Sg0@6EK|4)5N4rS7O#4LVr=#d1bTPUFeG6TNE>Bma zE78^I26TJ6Bi)m}iylu;q-W5x=(%(zy^vl^uc0^5+v$DuLHY=NjLxCor@x}Vp}(hp zvRGlU$^x)JS%_GOTNGGSThv)JS~OdHfd)l;h% z)_m5htl`#ctk+u$SR<^F*230!Ye(z-)}_{i))%Z_S--YfWwY95osEDE!Uk!hVYAi7 z+{VJj+Q!bt#m3#n%VxXHPMa*7QJWuZ?%DigyT*2%Ey{L_t-7s-?N(beTXS0rTU%Ru zTPNFXw*Iz3w!OAfwjA39+a=pmwr6cG*j}=IY`4-5VYk^%+D^_+(N5V;%?@uzv@^0Z zwWHe6>@4l9?d}~Ds?IZ1z?GM>!+cWI* z?Mv*-?W^o-?Cb2g_MaTKIA9z|4(1MY2M34k4&e@w4#^Jb4u>4F9r7Fs9Eu!@9gaA( zIP^I5ISe`sJIpwobU5R1-r5MsOf0z=;*l3(aq7*al50BqrYR2 zW3XeqW0GTvW18b3$81N2W4>ddBg?VNan$jI<0HqnP6AGwom8DjP9{!f(82chPC-s# zPKTU|oXVXVoSK|kojROmop?@XonAS8a^`mya29k%IB#^`;wWx82_MWZUy?FSosNS?vP2NV+JvD7mP*;9S&Q_PRv5 zq`G9fRno0CS2xRPP)8sdE+YKignd<)psSk8n{}zTDe-g+PZqW zZg=%@^>+<&-R&Cf3c6;x=D0Fk^IR)kYh3GG8(o`STV2_%{jP(q!>)6#$6Zgko^`$8 zdd>Bw>mAqot`FV#-HhFW-J;#%+!EcA-BR7s-574gZq;thZf$P8ZX<4!ZalY>ZfD%i zyIpd-;&$8ZiQCU^@7(3xvF?WMRCil&?w&h5Lp=9;CVD1$CVMhGi#^LcD?MvG>pj~&k9zia z_IVC^4tt*QeCD;@i|l3WMfbAwa`N)<^7h*4<>wXP72y@@mEZ+>9rVib%JE`)6?heT zjd?xxmhhJJR`kYt6TCINwY(|bTfI%Zsopeidv90oo!+~AqI_a~4*KN#l=xKpwEGPC zjQULYO#2-3nfKxPT=co(bIs?b&mEupK978!_@aEZe0TU}`R4c*`BwSX`p){E^1bDI z*Y|<%W8Y`KKl;A%edGJyPry&e59ufDC+a8Rx500d-xfb0#|4RQJ|6czA|6%_z|4IKDe~$mWKiB`b|4IMb z{yzus2W$>d4=@OD3J45{4LB4~6mTSYj&e{Z`f_J+hTXb?u)^z zgN1{of@Omhf|Y_*gK@#?!3M!b!KT6H!4|>R!FIt8!3Tm%gQtS;?b))&XwQy4iF<1I z%KfERU zLC5h)ajj1-9!kCcqu7^xL$7-<}77PT@85hWS5DM~6zHcBB%DM}+sD@rFyKgu9# zYm{-6Th#uj?5M7&^HJBMZbaRRdK~p6>RI%Sq-F_;*&7|j@+82uR2 z7|)oUF)=auF=a6$F_SSjWA4Q~kNFt8G8P`YHdZhe5sQiyiKWEujNKg@78@BG6&o8H zA6plDBTgVrG)^W?J`NM75~mi2i?fPzi}Q}#8Rr+bD=s)LByL|^MqEo=e;hCFWZap! z^KqBruEt%DyA^jg?m^t+xM%UJS&EBhf6;Ceb(1KQTNpJ+U;g zBC#>CJF!1;I+2%nIq^#3)x>LwHxl0^2_|h!(nz8v`6T%#1tkS1?M(_xicD%t>P;F* z8crHbT7bH@UQYTU=|L{r35&?#CejwuIHm?;%09VuNY?3DhLp_I{-iInM-V=3oTE~Z>g zxtek<KS(_oaj@JBdr7NZ@r>mx8(~Z;J)5FqZ(=*bu(sR@E(hsMz(o56J(868JAg_N z79oq0Wt?S}Ma#0zvdePJa?Xm%>dqR^n#tm1Eo2?fI+b-c>wMOOtk2m3*&DJqXG>?x zWh-VYXRBr7vkkJhW}9T2Wz(`PvaPdiv+c9@XBTAmW?#&HlOvv^kweZg%rVX}&9Tne zmgAb^p5v9XJ!fam-kh+U$egI0*qr#B>YVl*c20lJP|j%1Ob#b!A%~m8%lSE1DVLt> zkh?uMJU22oAvY_xGPgRnJ-0iTo!g%~k~@|=kvo-pk|Dv6XDBn&7ALe?$J}e5ri3e0)AJUo)SUZ;|hk z@1F0Ozde6X{=WRM{K)*|{M7u6{LFk_{^k6u`PcGq7AO?x7X%kX7vvV?6&x;L6_gfK z6jT?~6*Lw!7qk^j7R(eJE0`--C|D{uQE;l@Ou_kriv^bp-W(P`tasS+FnIXL;l;xb z3)dAY6ygfi3rU4qg@%Q+LW@GHLYqRnLWjcbg?@#Bg}V#)6^0k?FN`WIEF37DEnFz% z79KA=Q+TfMLgA&t2ZgT-KNj&7ttwhwBv=F#2^WbLi5D3bg%uSPl@~P^jTDU)af;3q z-79)f^t$MM(MJ{^3(i`@TF2sNNwT)G{8>S)VAft%7%P$$#foJmus~KRtAbU{s$(^> znpv$ZHfxwQ#+qc!u#T}#v(B+DvaYb6vfi^k74sFZDh7&$i$#kiisg$j#VW;W#rulm zixZ2%;)BJU;#(y`B^ydqOK>IXC8QGV61@^i$<`8+5~mWE6893Xk{u^S7O7@iO zEjd(DUeaGOTXLb~Vac1)6{V|6SC=A6QKh1#5~a9On^KQb&r+|_?WKE4_mzg1?k|ll zjV;Y7Eh;T3EibJqZ7J<99Vi_v9WK3Dwx(=-nP3@ECR`>~hA!J!wxvv_Os|YmwzbTp zj9Nx7vn+Ee^C}c6&*+kh?*=*UVva@9u z$}W{FmTQ!2mTQ;mm1mTfmM@f_FMnMAto+CFSLJWY-ub%&BBn7E~5iR#qOVY^iLo zJX+aP*;_eP$*EkZT&g@(dA9OG<)zA>t0b!wt5mD7RfHr6s_LrFR=uwJTrE(&rCPdLxmv55UTs}hibEH8MXPfg|)@CWwn*HJ+*zc1GPi7BemnTQ?)a-$7<(m7i*VlAJ(m_Q>(M7 z3$H7w8?C!i_r6}DUbFgEZ(MIyZ(dKYx2$)q_p0Af?^_>KA6&n; zKD0i!zN>z$e!70Pey)D0{&@YV`ZM*n>hIRStbbSkv4O8)Rm1uQ!3LlK)gaP9ZrIzv zY$$1HY#3}9ZkTB}*>JnzZo|ulHx2I^J~pmwgf*^dT-PYksM2WPc%U(+F}^XWF{LrB z@la!SBcn0Dv9+yUpVtgd)Nb!-#Svsg2_d1LeDX4~ci%?F#ynk$=Yn(Ld7 zG`BRjHy>^8Y3^$tY#wPo-F&Y3Li6S3tIgM&Z#Ca-e$f1=`Dycu=9evNS~ObBTI^aP zTC!WZTjpBMx4diJ)T-R7){1W>wraL&w_3J3wYs%>wr+3T*}AuNe`|DWTx()$TI-?K ztk&FCW@}|@YwK9+T$=l*zw1@khpx}v zE4$&{0^NviRJTaCShqoUXm@^hS$9+SaQA5UvF_8|cf0R*zv_P1{h|AF53FZ(&$=G| z9?2fH9>*Tfp2(h5O*p1z*No*#Pd_59THbI-e;k8D2nD)wsj zTDBS+&nB`-Y;Cq4o5J48HeplQ+u1&Be|8W%n7x-B%8p@!?1Sudb|yQUUBWJBSFvl^ zo$PKlo88ZzVRP8?Y%cpE`wIIS`$q5DUbS9)FR@p%SEpCM*Pz#^*RkgBL>BCmTw!`+rg~PSO^}~(B&BKpJ#7E>tNF&-KdLxvP zts^EQ)DilK)ri-~juGFHfRSAzdq(z+gpceWi5kftX&9Lp;f>rFc{#dbbp5EnC}LD% zbi?T8QRz|bQI}D_QUB3^(V)@&qtT;rqlu%*qX$QeMyp0^M;k_)MteplMkhz7MrTGJ zjR9lAV`5|Iv5jL}#$?9i$1r0mV*!&oG?Bdv!v1?;D#XoSAqx zxp|U2=`k5SnLL>~nK79;Suj~XSv6TZ*)Z8O*)rKbIWjpuIW@_dT$o&%JU;n&3Nf{D zN_t9mN?}T6N^J^1r9QQF%6iIa%4N!Z%4^DRDsXD|)SjumQ^ivYQ;(*8nqDz2GA%Z} zWm}rG=cg}Cznp$O z{dW4p^yitCGq4%K8Ic+B8OfPVGh1dGo%^&8Sj~$Gk!CHGvPByGbuBvGZ{05 zGsQDyGZiyWXWq|zocTPva@JvX`)uTF)NJf*!Ynv@a5jB5b2ev|Ia@H>G}}7cKHE9l zHOrpupBbssx<>^Vn}BgR2S0eA9f(e9!#Q{OJ6|{Pg_n{Hgh~ z^B3kX&;L08d12)OY+=oU$b$F+dST;&(t_#&Zh^26y^yw$v5>itvv79d^P<3_@S@lv zdU4~T?4tZ4W>IBPZP9u$bTNOiZLxQ8XmNCLVsUD5agn>oTRgvbY4PgfH7=5?&9&n? za<_5axSrhY+@0Lr+%Rq=H;Nm}jpt@^bGS@y0k@i4$8F#?aeKJ~+#&8LcY(XaJ;6Q2 zy~e%IeZ+mreZl>S`*DeHY1Pu|rFBdEOR`JYCA}q+CF&A=$!f`V$#uzn$#cnjX~&Y! z61Y^kG`VzX>E6=Ar6)_zmtHQt;;rMMc;Y-s-X`7_o+^*X)8y&!^m)cSGoCrmf@j5Z z~vME65lF&;C$pV2S8?p&a(Yc6VK?Ms|kR*r{ zMMXtK1jL47LB!r0R_q1)|J<3~bWq>V-}}Ay|2#3t?#!Lr&pF?7?m1`XG}YHRTddX- z3}P_DG91G*0wXfYl*q;QW@nwFacX3BbItrZ_*NO&;%J%@>6o*?Uen_AV$kZ%Rpxv@*+><;?la1Sv;Zwc^{4?gqQz(lT8dVp3(+cc5xNAeMeERdbTzsO-HbM(P3RW18Er$` z(GIi|-Hq-;d(b}g6nYjthh9J@&==@S^cDIVeS^M5-=Xi(59mj98vTTR!yM+ZfIaX) zY{q_g2=>Q8I0nb!I2?~HI0dKT5?qSQ@Gv|akHF=4B%XjPa3!9IC*jF>ITV{n$V@l8s`c z*%&s7wX!4Fa&{y;iXF|4VaKxL*zxQ+>;!faJCmKoR)7?|c6JB5lf9k2gWbj6$==1@&F*IJVee-Tum{;E*dy$d?DOn#_67D$_AT~p z_8s;E_G9)d_G?b&6i($#+yKsl8_1bCPtJ?;<_2@YTnHD+#d2|6JeR_ya%o%vSI8A{ zHm-~-=g#3Ka8tP1Ts1d`o6ps8%edv-x!if&3hsRF0&W#|5x1IK%U#1=%WdGUPA8;RWpL3_UFSswc z@4272pLq{{AaCY9c`x3Z_u+l{LA*a7%1821d<-AU$MK1LDxbz@@!5PXpT`&R!}tk& z1z*WeJizLvN1bNNQz!8h@X_-1|ye=bk>mHdVL8vb&AJ%1B_Gry7F#Bb$q z<9G7A_`CTB_gayJvp&Ei(^HgTJ{UECq=7Vj7Li3h}k;v?dt;$!0D;2k#`O->hwX{aMOuAB9CtWMuAl)e4B;67aB-dQ>_py&#>CUXhG zDrri(Qm7OuHl6?dWrku`>Xl|?v9d%tS2<77lvT<_%0^|Aa*MKAX;a#j z4rPmStFl$OP1&jJR`w|mD*Khkl_!)V%9F}7%Ja&r%4^Dd%KOR($|>bLV}N%hcuS1*)bJb&YzZx=vlMcBos_Th*=VZR$34yShW&rQWALsP0!ESD#Ri zs86cTsL!jfs;{Z9tM8~Es2{4It6!<#so$$VsehOl6K@)5GMhY2UM6pok15y`VhS}y znyjW|Q;I3olx8Y2*-XWz5>u&ZifO88nrXUehH0j0mZ{1#+ceiS&s1+(Y+7PkYFcT! z(6nk|WMgZ6{R_+h#)BEim>F+o(B!cdmWB3Z&S~)1CGRIi*3?%!o$ZV#G7Kwp5uTGm2AfCCM3CiRmT7k`vQxDJ6-v zbX$62a%y&3cB-vxSXz3TyJdeSj>+1^1TcY25EIOVFriEs6V601kxUd5&BQRV8m|eO zs7acvDVnO8v;mrjHc&Hbo|@M#CY~9}Bru7Lg-K$pOfr+gq{6p!CWFb;ytR0O?j-13 z?RA27YxM-(L(qK$9fwNMKQbo;tdxO2o9AtbQ-|V1Bslwh;UJG^B&8@RH16G1rnb6u; zYInBOHCDF(!qTBr3zTeawoj^a*3GG_uWNx~1KsUUu4}AyEP*a~mo-+;skc|oZ?;$0 z4zI4Sw>LvMf8)Nbxw*P=9(16wrPMyBbzXVnTt}7J6WS_qG`856wirW$YJ80T_3TBJ zd2sJ;kF9R7>m43gVXue&*=sv{VjW%WY$`jhl*b6?z(CdXwj=IJcr+yD0V(oE#&y8Rzb};44NM;l>ni<24WyUe%nRA#4nvXVE z8=?hhL0X6wrbTE`T8tL=0y7cz=_F<{GliK-cj_EyZaVyJw%5aiF1BloHc0cWGLM{F zS8vZrN=lmOgbpS-TO3a3vgG8XQu|_iy`#zAoKyjqCXFBK{%cuUg-D_&LwqoTe{cVsMj0#UzkewlqME8*VWF0F(rmQ?Ea`$~^Wj_q(#S zvC&=+w6!>Ce09x2drQ}aI$D39F)Y>F2(2>P{&E|=wuP;!sc*F_^lHPa%sGFz+OA#J zeJWP!^+i^hNB!mcx<;PV_0d9EO-sGb2b|p-Sfe)(U1iSw%MG~afwB^dt|@k}aIIcp zY?Zm_Z&zq@I_)h^m8Q8&>_(M2@oZ0zH=6F=TFKeUy9+k9G&}04a0V(Y0nSolFdnybsWQi& ztrmT$N~&9`>mBo|%$Y_}{dX!5p)TNBn<$6xJ*Pd&xYu$ga~G4fg}I%%gW1L0sikV^ zTBer0g}IyA&D_J>tL18C+GwppEA76~9?&;hT9vurFK@IidPwSj^B&Oa%=qW1;Ss&U ztbZT<9?=`fsWO-SmZ#-w1s%*W=6UA0R;U$e zHcC3dKr~h3N0(PrR+W{OSB{%dRZ%v&tfaDh+}Ns7WmBunp?wNWDz7Ln9$hv8N*P7^ z)=@TPylrfSs}2JPyuws$*5Uw(oO`Y{Av7^1Yehonxyh;N*$JUpX{jq#7^U7|-fCms z)QYtd40m%OpMznnU4TPbrvYC1B~KmtZrV` z!JK41W@gVAThVpRy=OmVzMwPo8S^=FN*ksP*GAA8`il7)W~f{n`QJ1{y=NsO1*WLm ztemE^@{=~oJuAQJv*I4ZABgQe2E-vA3ECKKoHkx7)u$54Ohp?~w6Sy%l4=|cmg*)z zc$Qi>V6rsYTU;2${Sknry^$IUdv`EBB{Ly3J0;DvY-k|!Ry#5yPwgCSf~%9r$F+2z zc%Z>B0KM%JSEo?`3hBEwQ5Xt`iLcZq(uwc6Q+mw_il$A*pjd5^Hrd_e&~8myXp>3W z6s_d%57*tvRFuwSwV^a^S{usHX7u1(C|9T1=~bRA?}mO2j@niom5w#0vdleyh4p|3 zTdU{U^9>&BX5Y2;(XJbo3X0F7ow~S5q+B3B39w0hU5&0sIFpPAVa?pA&e;v?jt6i& z*U{YIOsX3{-_d9vR{&nUlvvk9r^MlOb#1b?6fP1+cJ3zpDI+_T~u zH>`EOdn)MSyDqm>H_x-TKdK--S|a|rSrN) zUo@BQ>?WE5RL*4WK!vCX*-$YmL8Yh+4MW4x2yLb|ORLgmYt`ButwyWW?AqKNXe21~ z@DGhevNVpZ+|j`t)N-b9K{bs2M;x z<;t_EM5xy0YjMW+TBc$PvZJ~1GheII7QoL!EzZ;HYqN)Wgyddd2Wn;pwWB7qNNdy_ z?Z}B*v?gsCwG@Q{A6hoA+0oiqJHhS*dx~>(&)Lx}E%hzc#_ILD>26>dTEPtJK+Dm& z=saza)~q=@(D~>Bq-ibMVr>a+D7w$kfZg?I8DLQ}%wW=43RXInmDV}wgH%tZD`am5 zK-A|6C+MDYs+%oK>S|l&A4jWU=GLH#0Zv$2TkC4)ENihl$C=HW>hq79W|Tj9V8AWQ zZ?Y{It+nc~1YL?Qn*=t5iRGp3=u*Hc=yG`eioVakGJN*z#_7ZN?E1Rwff@JD+@iHc z6xD8K=zj*j`50Z*PH~KTnyx|D(RH{MZP1o$=eDEknPb{{AU&7Ps&(1uM%x?bwalMR z_ma*g?QpQi9cYLs3e>A*JiR`4SJsBM(8}6Tho)(yojHcChpNugmQI`t+sWChO4Yf7fUR^+5RAnx7%STW%z!YN3D$6XhmK7(Kresu11SuXl0Ro3-uQ4sAbtd+7f^ z{u&Evk-PXDk46p!mj5|6<{vW}Lf2OSX7wrZ&EB>9b;y*A$f3zF5 zoAjSJ^Dc9YYdc^OD?qVW!m_qe+tiL#Y|?JgIw*GpYxbFV>|fx~?gl)u4{g8;_{(PC zFW46k(%Q84KK#Y=8det{I6&9%+>Zz2aNy!N1c%}QgSh`mFYv_BwoijD?G<2qPL}#ZhZQ!VSlU{cir|`lPvcFdo-9M z1IN(rSvZ1^8dUleQ0bdzo;Y{;=kXhqN{{0g@Cp1PehI&fU%{{9*YNAw+uA$YyV`r& z``QQEhuTT)BkkiI_)Qm;zKh?}sq{mj(obAe`kD5lPNk>+k4p6uaf=hg$v>rA;%_OH zey4rvrqUmQN?{4~e=zOFKRE8yfjs`5MU+DSU>WUm?NmF9SyuZ(`;Jn%Y0RVe~eT94Cuxqj@yySBgGde6xLyC~Uy2t`l!Et-A9 z(b4`VOV%C;UVGf<^wT$Xk?kk!=LXq+M#(mXirQzjb~aZsL(~WoF9-aH-xcp0gQ#9BI?6x19%)~jyDf?tu+_MMZ)gj z!np{7N(d@#=b|_u-!cMcY9P!05qlpul(Wz+xPeQg;&vEF4$ex&?eIQZ&{MUzdzQ{+ z1Kn~NTqXw_t(>5d1dZz8a=2Vdx1$Lf^B)(tTro3{E9py&=zTnS!l@C>+v=rg75=nm|xRJ2#V?MG&Afjame~=R3e5t=2H@bvg*A zftg!3_geaTfw`=JwawLYsXuQ+UCS6atALYEcVB8aJM@LCC1_$BHneLEl~TS zyZ8cb5tuW%g}v0QadKVD{9$#?PVkO)HaWmS0FL(pmyOd8V9(IDPYoOcRyTo*bGN#6^ERh3up)$8 zNf0bb74@Qt0q@?>#89^f)>3-<+SHGOag}+&pOsu%qq|%*frow4(wbKAX|AO%5Kfm{ zGk8gc8;8oqZ6}S)b1&8!?h-JWa^NC4tBt#qz&Wqmn#x_yt)uMZ z3hqjR<`7iV&aLOJA_%sDow5_}PPd<~IRKA!z4k5-sw#7yZc#py*JW>q#zfbexpuC* zo7Zz-o4bv>fxD5riMyHG$Zg_oAqe*3Jc8yER7cPPf))}~e;Z@v+Cg$3Y?lps0VN;&q&R4!HNRzTCU&(vR1kOdfN`-IE`S z(9ZXoL>c`HQ1nFKqVI=(RPS^6Lg+_XwQAforKf>u@HmP&V5Kd6=`iBQ%>>;_bEZ=6Lf(V z7jbCGG2QSIQPgsm{$YZx);;lGaol*~d1l>r`O_cc$b~EsDaINm*F3#yr-S3TF1x{|RwYOB))pz&G@M~(e z&xI2yd#&M~F&ccjCsTinna&#Uk)tsP)ewRL&l)u)Qm1d%rGXIJ)G`cwB52?W6q-r> zedvj>e*ZW>7$Q!N@k3@gnn6O?YmFEWCxt#&=!?h)@DL^8Q#z^A<$F5LC|F@{*}@0$ z!F&ia`waKNNyPOG6oya|_^odNK8%lOnB)Tw+C7foL-^! z=ni)iLFL8eB`$YudOk6@K)GLJZMuJ+W2IGuA@sb z(7v>(8f0Uwz9glFYY?B#XSVSf1YJ+i4d+;lu7vP8?R2cujOC$I>24~YFX-8njW3}n zXPg$+#+MSbu@mL+!}-zRCC-oF%lVP~D1tT-1Pp&OL2X<3G5lD591o8Dz{@%a+CtDS z+C{^2-tCfZz!UvU($VU4`KcQhOK22Zl{rBdO#PRy)ZN|ww0MOpD9Y_fKN`*_se>cb z9^FsvRmQdMmBVK5QINW-8_l{8cT>9;H@3x8;4?fRsav(U6Z}km7GK2-$}(GSsg*Q;2zp7d^=s@dcF-7m7sm?dHqggxexiJ(65CoM0YgKhD3v zpWt64=qN!?69k2yCFnVVjuG@c<$gKo#n~AprDfK{)Qpsj#I%&uVToB*_>@wXU1Cki z&MbpbyE@~nYiI?(Z%4B+YQX5Vi(A0Mzplof2&7^-hl7)5jeS12_1T*{eWP>04bpwF zYha!8n@UGtl9HZLlAK&>E$KVIe`6_NM5)EuX{n{9w#4GhtgOVe^o(p6QMNU)IIA>s z*s%1n^mJ>=nMR~9`CnO(Ds!A`cl>GZ?Zzg3Ti>M5h%*nY0ljs`;jq?&gFB1gt z^i_ghBk1+*Os2rlAAuD(ffvBQNA)CdM}c1iy-Cnp1iekbZE&TwbXuLWtiEm@^=}3s z(xQt;@XCiB1N%e|DyT9K>VCQ0Ik^s^alw)RXv??(fd!MQo9n=-r&kqju?b?qDA_$8 zdTQsxRc7DrEl{T-K!4P0saMN@c50d-DtSsLb(>RQUzdQduhHkk(vpnQ?BZc1iPo|b zTVlE`B`YxtJW3O-ndzBjS?M-wN{V%&&Jt$0>!8l?(+tu`PEAPFC9&YAhmyD!K?o2+ z0kjB#LXZ$Fgb)Oa{sBQB5_EEl5GI5R5ke$E9})C1L7x!xDJ9!Mz<_&(NmtU)O$bBp zb7PW`ji(Ti5<~m2S9_K#v>;;P<%D2MaRNbueEOXr1OB-!Ws;+OfM-=H$mtoEc zb+1v0FucFcj}Xd*kpz815GYUIX{8Z`u0!q`CNv5&p~r=B%s^qha1NDd)aWwKlT+uo zQzs$Ja=ak^*Hb1*a%Ho_(E|CB%tKU@w@+YDT)Z_WH!mXJRz7mn=rI+Or_88wWoa1T zG0^Pk1!3l{ff_OBphMVNKvK4D{(|oykHJF%Xx|t1%<0hP zr*UomkX6AOr13CtaDOQ{Bs47CBO)>?IwlsbRn#rFLtAr))mP7R(%?8d_04Mn;Q^T; zMpOfpgL*}kSHMRRMbXB5dtPkTLu7|a=C zD@rQq^TcDWw@G z+J_CNNhoNm0Z_ZUW|}p@(cGoP!hk#PR)Y6>*Bvus7LJb{H~yUd5)9Cp?+jIJA3vcp z%K$u4Ik9)ZW96g?u-1C;BOn=LtaQ@#p}-SUrvX#$J-hAGC-id_O3$3-+8gaNC&1U) zpg((c+ikVRK5U-@kN0z(ksx1)KV9crWt^{!?9*|7FN4yu}t(nMx9OdUH|Ya<*?yrXN7cw{b?cS78Hs(drh=ZMawcO znf|0?CBS{XWJHl76EeOzm|CV9GQ5St?-uw?leXl* zPkLw)WPfvqH3*A@;!H8f?FiS8;Fi)^Ru(*w}3g^LQ zvqCYA{sr4FmH@}VA1ETzPjvcxVbDfGlXB-Uu)b9QY_K=Z>b$B)If7*YE&!_=Q#TJJ zkiAwHEzV)hj)t)naApAHO+$@!6FXgEL+%;XR#wj`u5O-O?bNfn)Z6JrOlrnJH?i@@d#OXnRQn|Y?29W69&u+IuQ_?a*Q?s%{lR=9KO}3_GhFalYN=kNG zXmVO=dZ#?SLb#sE+AdrvtP|D?R|!`O*9g}N8-(i!RtQ!JHW564U=M-^5^N^elVC3j zJZ}_k5^feY3Y&ymV3pbcb7F6TTM1rF@Ct&@Cs?D4bs=3PGYo+`v5&1@TsO~v0Q6Gl zS88H{11Y#f18nMA>g`!pOHsO9@uke7dPk2z+FFYh1AUKfV7=mL7P9xYx@C1Tq5NxNj5U<-p=sAiz^h}RN zn^Z~Y8Q}!(1Dwtq z7JYI+n08j8KkZ&4{h(3b(e9vvzBP}Bie*F367*@oHITJ z#suMA;XUDfIJ|`8LCQ|_d?b)K3F5{8r|VWlf};tJ8s~|8dIL{0Y;`bdw%7pgK{}OM z%B`o?(Yz$|tZ$}a5;SbL&RKxp;Pi65!wHn)XiNpm%-xyq%(`lGn{-@O)Pa>W6nm;3 zC_MraHFcNJ6?uuC;{*Hc}Ed@{`iJb**QI@Uid-wIBY)@>S+JRh2EnOC}{}fHv9H z2JHKkjIOWUnxyjAndxe-YEng2YI0XOeQhd$UK;0hfxxQ2Md&)nM>v`6pOkgJ z@h9YNlrac8>TJ~jSTqvg04_OOxpJqom4+3icNRJ$+cVnka%=$pe@3=sl%=f29VgY7 z@wgbhB*g9E}MV}>Re`tgf~ ze(dezJIIx=a0X5EMsb4yhkaWd3+<4*$zJa|#MAK{$joLv@t?u;U1yBJc0Ju*ZE zLs8Ma)w!tPP^dpPqAdbDXydhLR|L(fBy&x??v z`BmmENY4Bz^Es${zd}};0lLCxsC&^U9c7~e$P`fwSt8~_>gBa)J=%?)HJE>=QkK#w z4D=7^)3Zoi_ZAKnA^x;Y1mIB6CPokpf$?W~3gomHBfKYqSI?ix>7sGw-Mx3a^skBO zE8l&2>NA@+x67t>MeRqJ4)EwEOfNsAPl8*RPMSKy-neMFF+-g~bfEFQ^Y?}BX-N=M zL7<313#kdxwfkJ8HW+T{T(%MtRyykd;OLtQ*!JMk;^CdZiYh{I&wy!qb)W@|Yph=e zCsd6fHj5!1bfJ@~YcBN)@>|kVL)x&bq>f7TM4OQKOs~z%xd&Myj-Xt%R4fyRiNgsV zN$@CwM-x0|i&!p>gn_~5u>_B!gMtJ}hQ6rx8|bO?G#q*z0WFrag5N=7%joLX#+vyR z2C+?`-U#-_8UuVLL#Ywfiy_MbATMzBTIQ~$Wc)DF4Yf(JK&di`u{{nXT&)Y=+*b-LBKH$}HlgBi|9sFiG`3AIu(Qy?)@ddi9w z?zxyDR@1qdDb5nB#MuN_5L`*{M1m&)z!q!7S_5EDCV0yK2!Jg%hz?4)jRa3^6PpO0 z_NRo~0))Hx&k1)r0PM?pQLcZ;zec%tXXF%3-zp9;d-?bsmt@7%3uL#cZisDWjw6qO zrdf8n!8-Z14$=o681eu->}hIORVd_ba$OCogsZ-T+toqcPGG_2f;@(}i-a_^1wf&| z;0{#{0!im01&WG|w3YzTLnGS5!u#PWkx_lQiq704f%fwtt41X=ote$p!IHBG>^SE# z8YEl09xQsBAv^yr<{rq)|1enfj_9oZ73K{{oAwQ4;6IHJQh?15GMG;%6L(pV-7E=( zxOeC>@d766R&lv_u6UlfLIexJOoC?-TtzVK*XmnEjXJE07mBM0o&y{RtOqp&*HW?t zS49`Oc8W_NT51^qEZ50xbZA(-OxF`BL3h7rB+fNtsZN=CDQbP|UaA`x>MC?*Ur}+b zi#A;;%(~HLa&i_Br$NE%x}PzLSBo3qEL^-syq4g(1kY<1uM@8)cs{``bf`lXwL(VV z@o-eq00&^r&MsTh%(=RfJH8rpx8_FotZo$B;5bCwB;F!!Cb*8^1q3hb5ZlELaSOpP zhYbWfX~lt5zbvbEE~|7H{Hw)&4sFWiOyi}uTLG39NOEjA!A#dL(eodg8IGFTimO{{ zz}2>~wi0|t^`}pWJH^|@J3y@NVkV1siFZ%cAF8xBH%y}mc55pj5w3ljeo=3UU`R+y z@FIen!8uR7N4!_OPuznaucYaXr@+V>D99riID*4HE4f^Hg~$ zZ2hnvCBawBJ`YS@-OCtT?|C=|6pxE9h$jeMPVl(|pGOnrbtyK~`XW_$K(@h;I;lK^r~Nrc)C@@qm*; z2N#V}*5`8Jb3gZ<_#vI#_r(tgCIqjfZp2_Xc3Fx$D;NzatnIZ1^Z+P6WkTm27gwc* z;ZBpSyYkP)(~y=&JSBc1ekpz>el30@ek*<_elPwY{zx#etcwU=b`uEaETXui|gw@8Ta4BOwV(EWuZTODSGY@Kpp~P4G2@Z71w)guREb z_Y(FP9eAi4H+0!5E8x_!rJN?h170v6>A2>~c+@~) z16}M=*CgOLU|RQ^p{_5G(yNXh`O${pke8l18%ex?e0uf6jr$^+jB@VV`uk=eJy>`9 z7YHr`CV^d#R!!FsM(9c`*Oh_1=TorVy@4cMrSuA@#dg-1>ZOokWI3=H-5*}^l)S(S zw-7%rc|${xmef5%Mt&>+0Nt+XIF{gbI^9dY(jZ7a-uXbgG?p}MlkI= z%?uopxh7+@eQryoV?y1$`G&iv6bK$-5|}ox?L2FjLZui0;!>CtE=5R@Qj`=;@CJgf zBN&+e4Fumv@J(B#SSe15hu;Ylh~G@`M#4Ji2eysw-X3e@irX*_CiJ1h{1~%70-Rxi z4ZuY})iYgd36|63)S=TU+8hNuNtb&;u;p9pYw5-x52q#*?7*M(T=2R}L1*3uDN};P zHXTxylr7~Dyoumj2;STw<>}{H7<|a!JWD^u@}g5?bGka<(!I^@tqV8xxdjt;=`xTC zbv5oQI+v14nToAanKVoqE{%}NC4lkm1iwY_H-sHX*fhdU)#6@}#zVia>d|aUGs)fb5Q4#VK^6 z#4&EJyUwnA1n(sHR)TjCd^f>cwAUd)Nv9m>F|kIiUB?8ShCyRd7cdna(n6_T0syj= z;OzwO02fQCNm>M>t7IRLTBdciI#KTrofL>@#oPKrxCW&zkwCo<1a{D63^q=$^$NyU z*EP3G%cy)lYZ+HJ_xv+AcvB!TxUnERxnrmrGYnYXbgn44>e;2)?t*oZ34BYggt~mv^o^-zvl!0c)Uf zOh!-EOIJ-d%uV{X>5#6Lt^qFC?GjMPc$%)imTs#uIJ{bBJh?%-4#YjINssN(wLm@T zrd_(84(ubIR3l6#ofkVgW0*av!zd-b(a{IZkD!z7?(Cmo1|N$ z%~G4xE_Fy-q+6w}5)kBl1n(jEeuBXY`vAfF2!4>@{RBTm@BxAk?v%DuNWoa8JJ3hc zoix#&v>T#o@gW^$0N6gP!9IV6=Gr6pH3PYvCC&$SsT()d+KmzD*;)R_CNuqCm26LX z7(BbB!vsI^5rQ9WmySu#6Z{y#Pf*juKN5W_ zy(GO#8+jRm=JDftx;;qe+15`wPj|20mfi;!bLk!FUFki7j}Q!+!&4p72hxWSd5ez{ z{Pcf3@>cpB7}BY}QC9sV*^|D4qF?td+BeCbd;H%?zfk=2z4U|hqjXyON&1;!SfJ+! zK1MJs&vAlZ*ed-Bl=!>!2QHKm!6zv7y-4uO8c_196h!~yS@!-cSDyP&9F)1m0CJs{ zznq7!ca}X_l|5j`;4$(54Zy-n?cnw_4wCHM*DE=mYrbS3c@UV@WM6_`=`V+#yI6o6 z*dz6x93q1q9WukpVGwJGUkAk$GU*lelSvQMRB*BZpyZM#pft^`o7W2GGoVt$!r`*Z zTQvtV&48vZ$I0< z68)H1*El_SW)fH?jQsf1(`V}7MlJx>B7@rgUMHmC>xJ1mmY|>*Z}Yz3597ZV3;@B@ zQUIaBNt=!zvSFTR3>Zz!4+?l+myoW*Q1`n&dIr?Wqvdg+?8;;0u>^la@W<`)cnlr- zM7y7Ec<+Bah+Li|PXVo51`zaVn>>}^&uBYm3?i3j%C$hZ@+`SZo-J3)b7ZjPeNONx zg1;d6OM<^5`0K6AF&V*o7!u*<7`1}DN~7`4g>6?zEB{{@Lf&WF%1*gOZj~2HQ)DMI zL0(Sq4+Q^0@NWcvtK1Ya?YVEylUKNLKfyl{{GEH>0vtE?--Q6KQlCCtwsgk=be2#X2J5|-O0 z-zIO9xAT&`Q@&lkL*7MLp0EO8B^t@f%7j%2JAkkrbPt{>k`?r^|48(zD_j)<*W?G` z&`91-SnVxKTcS+O+G?c6P=5GLrCSPyM>VU z4H=c6mya7&_a%)N<(K4_O~#<=nWu_^!msWJUzfcS5ICxa3O z078MKh<52FN)+fO{ipSEt+bM$BmqKG5)}(!V+kAAu2_|1!p0NUO7)XJP4RG66~^62 zhLQv7hLWjdDcOV_O4tO#CUz*fN*<^iEVP{TA6GY&5@w)M+E<6@n|15BG8~GI=v%aJ zE-&}^M=3O?wK5v?Gd5XIYQ{i-X8f5IG^J9RtOI9d5&&m56@W9O^a2>uH>Fn}4yeqO zCMs3RY-x%zhZ#dTU=}qBvIT@q*E!%64UEY>je^QtWnLEt%p+_@Zw{z500&eW6^GJ9 zSRiRw$J|a1sLa&C0W{|c73XIB*RS>Fz+$7(C9mGzYUtx+ykE>SL3E>qSjmn&B&S1RiWTS(XpP$vR1Oh#9AU>3 z_M8sou<{6HeG>><@t|!#p4kOq#r^{9_0(`OHtvoq> zPkEFNm6OUx%E!PWKU6+bJ}2xMP=P)wsJai;DQ2Zs?pE|l2w<%|6)O#NOoIHD>U9I@KP z5&x-oKz6=KSskb+31VyhsrO65(Q=oXrXLsdn1Mt%JOIbsmSuVt9$4hgb0X?h(Ay&4 z^?Fv<{!x8YKR8`febqrKAo+QOoln?0crT;suLghwWfu^3A=NvmtHr|-p zueT7Y;qVqhHA0OfY&~HcT<;-NV|2$JT_acH;pkTdywvz#c@d#eMG~#TO4uf-Url8O zs%dIE__Ed*eu;g|XM|lu*v)-F1vQkZ*=kNNLm9h-u+5ZW`Z1KLMXHU`i=3l^gj`Hm zr<-2hA*_)aOC1gzTOC2zmQFJHI~FhZl2@ve!D^*WR3{O3DPfnjt5YENA-nwFmithh zrOpOTR;?oJxov7SVb7yG>WpS9)vnfq*-D+O&Qs^Bb?O3jAz@b#_I$!#Kv>{%gs>~O zstsx*HCw5R035Ox5_Yw2w<7E<|7#6b#tu9eGM1_5sW9MGguUp0dhSDYrMe1i-RgPJ z-8S_i!mjDeeW+fnUIwyBy+pl~uon~dl6G~idO2a?+a`(_`X2T7mkrUqYp+sogye2EtxO*tLX(O0OX7m4pSrxgL@isyD+AWXx7KgXv6bYv`|= z0ZBsB{V1Q{hVf_V2aO0Y-4XB4Qw#QOqHlu2{!bqNsrN#tJ1M)kov>HC0G@hh|C#jM zQ@lsrOPBI~!d}~^K0w$Fe+k#QpMFTC&`mv{9#jtz_Bz5|PuLqe)WfO{-EJi8P5*J| zrUGd>uSJwcJ!MnGcR9?FvXCW`zQ(|HU)NFWe-WEJ0rEL@6(eW>XO;_CQzf>IjPFH+XKw0C)JN!!s#=@ZY3=E z%k0vfQ$RS~YINun-EChGcFVscoPJh+rJ~{&!ftC*ebhx0A3y1b1|pR3_5|HsxIqiNM|o3CW<=F7KBa z^jlX{w;8@t*SIm&^B~ZmwbnkhbKW9~E;TY4xK`feYk~-_zRmeVb71M#wXLwMB z+xL!o&qWk1*xcPS)f8q5?_mNqMVaCupuiMuiZR8S;t1rRXZH{m2z2ij(@;}_Fxv#y zAfQx8arP@=pU_IDP+9Q`!SaFjDV59#W6&Sa+>pL-zbrX1Q_hAGpOWdf7M zKEggo*!_fkXbULn77(|4|$dfe0>cQm(jr7wZ!2lXhT*G~P$+U2uA0zDJkjp^-2U!e^e};_##z9?EUGAwgflj9bRV|#UIvw=o=k{vX z8>c zz74kz-#8zh2bTUUef~LZX%}fl6kVC6R{;D#Vumo`Oai3d$YBa0Im;wCc%LP4k|GV3 zLcp&yS;_z(&K#*wvPq@jW;s(@C9RisNq0%RrF*44(q3twv|l7|Ct)eKAN`_LW zXkdxkq-<8&l`YCvWt*}?xn0?%+@uRi;tmdg@>L_)*Iu#K2 zd_ddv>VxVL^(pmf^;wg*Dby5hiUbbiG-;-lrd6iZrk710m`<8LHhnt4G9Y(A{(!;( zwgKl4xNN}X1Fjsfe!$xUJ|FPKfUgF8<6-s4_bBwRd6amp_PEmHI**$@wtMXL*ypj| zcYFTqC3<;ynZ3Nce7pj@g1kb!!n`89O1ng8nymoor@3qfszt;h; zC%le$J>~U+*Lz-{czxq7c@Ojs^p5kkdZ&1&d1rX%dl!1!yi2^xyytpf;=RNBQSWEG zk9i;WKH>eQ_gmiYc%SnA&ie=N)80S(ARpF;_Yr+$A1@zYpTRyud`9`$eHwk7KCM1W ze3tpF^tsUIBA+XK*85!TbFELi&vu`kK6m)s>9faYug^Z8{XPeLUh#R?=cLcaKA-x0 z?(@CR4?d@TkuT>f_)5MxzQcV-`i}M;=X;KCh3{LAO zRM3|}Uk7~~^nK8eK|clk67*ZpAHgWtFW5ggFgQ3kG&npsGB`RoHaI>wA=naZ4IUF* zAG|JjckoNWzlOwwj0#y0a!JV6kUK+mhuj;oC*)wrk&vfCo(_37fXAwP!tgl2}8hL(qp3LO(VA+$1dQs|V>d7%qJouMtEi$gCAy)<-f z=oO*sLaz(GA@ruujiI-M9t!;=3?j0_lEX^FhJ}p_n-S&+TNJiDY)#lTVH?7(54$n! z=CDm+o5Su1yEE+WuzSMp3%ft;fv^X|j)i?0ZVHbN9~M48d{OxM;TMKq6uu^WZTJ=8 z>%y-Jza@NY_|EXV!*_=t3_le9aQGwP$HHF-e=+=(@YllM2>&Gf+wkuraD*5kN2n3z z2(JjAh(Qri5h)SFBg!L2MU06U7jaHRMa0C2$q`c{rbjeIG)J^VERI+ju{`3ui1Q<~ zh?NnmB34IqL>!Jd87W03L{5lY9C>Zzy^+sHz83jrP55PKl@Q0(E@M`J&Vr@*cE=rz zJ05o;?#;MQ<9>_#Bi(G$l9_7AGuCxHe&L!ea?fB|M$*T*8Tjml9r0cs=3Mgi{GWC!$0yQA|`4 zJrjKr2PY0m3`i_ZT%34a;^xFV5)UOFPCT0UO5$gUrxJfo{KJAQoCQo_77vTr5@JcP z*es=%;g*q>F_!U`3dE zwT`hiSyxzBS}(G$v97gVXh{##srRMcpSmw~f9iqML#c;TpG!TF`f}=Psc)ygm-=DqM`>JIOj=r6 zc3N&)L0U;#S=xxSk!e%YW~9}nHKjSz7N;#s)6y08scrQesnFa4qPL+OvD zA4xx&{!IG&8U7hD8Sxp38P<%{jP#81j7b?a8FMr0GU_uN8O<5387ng`%D6b=(u~V9 z)@59kaZSdajAI$6GQBfXGRre3WKPbUmN_%CD)W-eAF|jiAxq9OWev>o%nHtm$coO2 z%d%u8XQgFjWR1?6m9;TzN7e&b`?C&a9nN|z>qyqotY@>{%z8WPy{r$iPG)_Q^;y;z zSzl!j%(i4t$aZ93oqb>S@$9#=Kgd3r{Ymy0*JZ+YH|JT33Syw!P^ zKTEtzbvN9R+t4JW#N|;9$Ywg2xJ;DEP53x^QCQ z`GwaP-ch)x@PWepg$D|sD}1%^{lYH`zbX8_@O0rXMOj6*qOnC4MU#rA7R@TEE~+h> zThvh0Qglht`l1_)_7y!`^ls6QHqOS|1e;{@wfWfsY{9lLTZApymTfDxmDz^d%59Tu zQ*G02vuxG28e6^1VOwN#+BDl5+oiV4ZR>2;*>1FLv~9Mv+a9s~QXE;FT%1vyU7S~J zD~8ks#pT77#WRcT#f`;_ikBCY;?>1h7GGa{Q}MRqJBsfrzNdI^@q@(&iVqbZEk05F zR`I(frV`(hm=a4#W=T;=Nl9bLxh0pDTwb#7|J8Kg|4kcc7{CdevdSpC2_tO6CAA+-1-Ui3O~6Rt zTi_qSG$0QU0%AZ8zO7=$fVfGF7Lr!l_7H1S^ z5@#A`I)}yKbBZ}qP8mnVfjAW$3&+kuIUbIWGmo>CbDGo0ZOQG(?ab}P&EgK^4(1Ny zj^Iw>PUTML=5je)kSpL8a3$PgF3#P`y~%yVeZu{d`;pt2myy>puYF#pye@g&^LpfE zB(JOvNtRq(vLI4{Ygc?@qZZvk&HZ#{1#Z!>QzZwGG|uadWqcNc60 zjsc576{rDCpc8b1%fU@x6?gzV3?2hdfTzK8;6<! zU&3F`U&-IW|Al{@|6GtE=p@J%OcDSBp+GGt7w7~=0V1#p90HfXD@X~_g4u$3f`x)5 zg5`oA1ZxEA1eXO*1n-4e!l^=~Fd$qe+$h{3+$F3ORtXOXPY6#5&k8RHF9~ae&xB2) zUZU|LP*f_CiMl4p{pqFzPgi>4K^ir7VYMKg=QB3;RilKRpXrL9Zbm3AoYT-v2{ zROy6LVX3&ZNZL`_M>B9h@)u?8 z%Q}^HQLI#KR_syiQ&cMsDUK?RD=sN&6?KYhikpf%ihGK8%5KW|U~ z8s%E$dgV@KrLszSKzUSoTzN`)M)|9MHdi^%3J#eMnjV@g%@ECS%_z+n%{YxjGf#6+b5e6fb4_zob4PPe z^8m_#Izio_9#C&66Y38QgtDP2kQ_2VI248AP!ggc2AT^kfEGi`pq0>SXfL!MIshGp zjzK4&)6hBSB2)v_LD!+1P*eG+@~P!{<;L{s+v4g|Gxx z!xgX@j>0s|z;ogG@M?G~yaV0^SHe~B0r)U{9=-(E!dKxN@NM`md>?+U&CvGL4%Uv- z3bZ1vLJMp4T9ekSMYSF+rVVOw?E>vaZI$+z_L8<%dsTZwds}-?`%wE>*G4x;$I%t* zP+d~DK=-q5k8Yo?T6aiyRCio=Qg=r8NY|imqtDWRqX+c@eSu!0FVV~NWqL-xSpS25 zjefm;qyFFeO8rs&Dg9af1^s3H6a7m=XG3?xc*8UU%K#X-2C<>YP-2i7^ahi`Y_J-3 z8x9(-7;YF|89o?W8QU7$8>bs*7z>Ruqt56xMvOlhcN*^)-4kug$zWpksM?q@;78MG6k86Ohb5x5D_CqhzwC6Y6L=XWG%8C*^TT)s*pp- z5#$(h9Jzu#K%OGck(bCDb%#(c&6!2Htu z#$0cHZ~n{NWNB{cZ0Tz0Zs}?1W9etfvJ9|Hw1_QM%UsKL%Q;J(<)P&_%QMRh%NxsE z%R9?^YinyaYY%I0Yd>qIwZApTI@$Vn>lEu$>-V3@0ijiFEwM_ia;xGqKefoZ%35iy zw$@tft?#XWS(|LlZLMr=ZC}_r*aq8%*+$w%+s4_xwN0{B*if6thS>tPlr3$WZJTFX zZrfzrY};zvZhK+-Xm4h3VQ+13Z|`LP(%#iR%wA?U+7Y|e?y$S;9y@JcV*k;;$-c$D z&A!vV+rHO++G%*BaMa*Lv3p*J;-|*F{&2tIl=Zb<=gn)!_Q*YIJ9~Te{o0+qt{Cd%OF&v)lvS z+3s=fZ{3sJlih{xA~)pLy7g|8+vCRE0XObWyJx%Sxfi$}y6ZhHJiR=9J(->Xo@~!h z&j?SBXRK$uXQJnO59r~0gq{MA#8d1k^~gL5kIJL*ggh%fM?H_dUwFrQ3%oY(Z0}Fr zJ>GrZYVSesN$(|Zt@o<;hWEDjuJ^h3wfC*J!TZVA%-6!#$~Vjh_=LV}d^X=w-#OnOz6Pun)(h){4Z_A^EDXSem;@`qq?i)ZVC9$=L$L@(Vo8j~=3w)% zh1gDv;9N-=I)PZ1NMc_!_(Pw*nOi&cG2ASZN&nGl{gZqOA zf+vC(Kd(R42J3>?J~t1)2A_X^DE}td5d0Wy3^fZ43QY^~LIoj7s3ar{X+m&FA2Nn2 zLJLACLr+6*@Md^7{3|>YABj)Jr{O$Yh!@}zT#Cza1+Ky^xE~MWQ9O=Qcp7K$Iru94 z4E`K{iNC??@%Q*&cvHA}xK%haJRqDM9vU7I&IykR|1JE_@V~-9m>ZrEmV`^fvalkI zh9luvm<*@Fi^5C8%fml}w}iKacZPR`8zb!_9V4A1T_YutSY%tII&v&>B62!%E>at* zi(HS~irk4diw=tBM&(gBYK$ULYt$aaqW)+wN=8%Bbd-r6iJpm`k6wz_L~lhKq93D; zL>4iS7)%T!MiQfmam09H0s#^NqJWSPC4`Jn5IVw0AcTeR6Col(#E4nMGGYa>idaKz zBX$v$L=|y}I7%ERP7-%wJz|4mLt?{Yqhe!X<6=Ne7%PjZVo*#QGsG%lmY6>libY~X zjEtpXbZk~^d+bc?w|M9H=r|Au`UxVoJyQcTu59_TuEF_d`z}Yc20IpewFN%%t{VS z4o(hD4o?b`k>uLsmgK(Vx#Wf9wdCXE`{c(|+f>I?=Tz5J&s6VJzf@)_CuK}IQl1o+ z3a0Q>GPOGOW9ne)QtDaiMe0@R&(yorhtwykHPw#lKy{+}Qkm2MDx1ooCR0J8BbGjYf zf$mIqrF+x;=uCP5J&2w_Po=-7XVN@6pO(@Pt)&fg1#O`{G)4#MFip^LnxU7_>*#9w zG+jg2(bwr)^j-Ql`WgM4{)2u+ze#sVk4_8H`ZSu3r;}+q&7|k17o-=bm!(&xx21Qa ze@^dCSEl!+_ook}52cT!U(FgY3!H_``f=7(<_qRKhRx(LGnsrw$P_SI#= 1 { + self.cleanupDuplicateManagers(stosManagers) + } else { + self.vpnManager = stosManagers.first + self.updateTunnelStatus(from: stosManagers.first!.connection.status) + VPNLogger.shared.log("Loaded existing StosVPN tunnel configuration") + } + } else { + VPNLogger.shared.log("No StosVPN tunnel configuration found") + } } else { - VPNLogger.shared.log("No existing tunnel configuration found") + VPNLogger.shared.log("No existing tunnel configurations found") + } + } + } + } + + private func cleanupDuplicateManagers(_ managers: [NETunnelProviderManager]) { + VPNLogger.shared.log("Found \(managers.count) StosVPN configurations. Cleaning up duplicates...") + + let activeManager = managers.first { + $0.connection.status == .connected || $0.connection.status == .connecting + } + + let managerToKeep = activeManager ?? managers.first! + self.vpnManager = managerToKeep + self.updateTunnelStatus(from: managerToKeep.connection.status) + + var removedCount = 0 + for manager in managers { + if manager != managerToKeep { + manager.removeFromPreferences { error in + if let error = error { + VPNLogger.shared.log("Error removing duplicate VPN: \(error.localizedDescription)") + } else { + removedCount += 1 + VPNLogger.shared.log("Successfully removed duplicate VPN configuration") + } } } } @@ -148,11 +192,7 @@ class TunnelManager: ObservableObject { return } - // Only update status if it's our VPN connection - if let manager = self.vpnManager, - connection == manager.connection { - self.updateTunnelStatus(from: connection.status) - } + self.handleVPNStatusChange(notification: notification) } } @@ -178,35 +218,61 @@ class TunnelManager: ObservableObject { } private func createStosVPNConfiguration(completion: @escaping (NETunnelProviderManager?) -> Void) { - let manager = NETunnelProviderManager() - manager.localizedDescription = "StosVPN" - - let proto = NETunnelProviderProtocol() - proto.providerBundleIdentifier = Bundle.main.tunnelBundleID - proto.serverAddress = NSLocalizedString("server_address_name", comment: "") - manager.protocolConfiguration = proto - - let onDemandRule = NEOnDemandRuleEvaluateConnection() - onDemandRule.interfaceTypeMatch = .any - onDemandRule.connectionRules = [NEEvaluateConnectionRule( - matchDomains: ["10.7.0.0", "10.7.0.1"], - andAction: .connectIfNeeded - )] - - manager.onDemandRules = [onDemandRule] - manager.isOnDemandEnabled = true - manager.isEnabled = true - - manager.saveToPreferences { error in - DispatchQueue.main.async { - if let error = error { - VPNLogger.shared.log("Error creating StosVPN configuration: \(error.localizedDescription)") - completion(nil) - return + NETunnelProviderManager.loadAllFromPreferences { [weak self] (managers, error) in + guard let self = self else { return } + + if let error = error { + VPNLogger.shared.log("Error checking existing VPN configurations: \(error.localizedDescription)") + completion(nil) + return + } + + if let managers = managers { + let stosManagers = managers.filter { manager in + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + return proto.providerBundleIdentifier == self.tunnelBundleId + } + return false } - VPNLogger.shared.log("StosVPN configuration created successfully") - completion(manager) + if !stosManagers.isEmpty { + let manager = stosManagers.first! + VPNLogger.shared.log("Found existing StosVPN configuration, using it instead of creating new one") + completion(manager) + return + } + } + + let manager = NETunnelProviderManager() + manager.localizedDescription = "StosVPN" + + let proto = NETunnelProviderProtocol() + proto.providerBundleIdentifier = self.tunnelBundleId + proto.serverAddress = "StosVPN's Local Network Tunnel" + manager.protocolConfiguration = proto + + let onDemandRule = NEOnDemandRuleEvaluateConnection() + onDemandRule.interfaceTypeMatch = .any + onDemandRule.connectionRules = [NEEvaluateConnectionRule( + matchDomains: ["10.7.0.0", "10.7.0.1"], + andAction: .connectIfNeeded + )] + + manager.onDemandRules = [onDemandRule] + manager.isOnDemandEnabled = true + manager.isEnabled = true + + manager.saveToPreferences { error in + DispatchQueue.main.async { + if let error = error { + VPNLogger.shared.log("Error creating StosVPN configuration: \(error.localizedDescription)") + completion(nil) + return + } + + VPNLogger.shared.log("StosVPN configuration created successfully") + completion(manager) + } } } } @@ -233,6 +299,7 @@ class TunnelManager: ObservableObject { } } + // MARK: - Public Methods func toggleVPNConnection() { @@ -248,16 +315,14 @@ class TunnelManager: ObservableObject { guard let self = self else { return } if let activeManager = activeManager, - (activeManager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier != Bundle.main.tunnelBundleID { + (activeManager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier != self.tunnelBundleId { VPNLogger.shared.log("Disconnecting existing VPN connection before starting StosVPN") - // Set a flag to start StosVPN after disconnection UserDefaults.standard.set(true, forKey: "ShouldStartStosVPNAfterDisconnect") activeManager.connection.stopVPNTunnel() return } - self.initializeAndStartStosVPN() } } @@ -266,11 +331,44 @@ class TunnelManager: ObservableObject { if let manager = vpnManager { startExistingVPN(manager: manager) } else { - createStosVPNConfiguration { [weak self] manager in - guard let self = self, let manager = manager else { return } + NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in + guard let self = self else { return } - self.vpnManager = manager - self.startExistingVPN(manager: manager) + if let error = error { + VPNLogger.shared.log("Error reloading VPN configurations: \(error.localizedDescription)") + self.createStosVPNConfiguration { manager in + guard let manager = manager else { return } + self.vpnManager = manager + self.startExistingVPN(manager: manager) + } + return + } + + if let managers = managers { + let stosManagers = managers.filter { manager in + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + return proto.providerBundleIdentifier == self.tunnelBundleId + } + return false + } + + if !stosManagers.isEmpty { + self.vpnManager = stosManagers.first + + if stosManagers.count > 1 { + self.cleanupDuplicateManagers(stosManagers) + } + + self.startExistingVPN(manager: stosManagers.first!) + return + } + } + + self.createStosVPNConfiguration { manager in + guard let manager = manager else { return } + self.vpnManager = manager + self.startExistingVPN(manager: manager) + } } } } @@ -340,6 +438,62 @@ class TunnelManager: ObservableObject { self?.initializeAndStartStosVPN() } } + + // Check if this is a different StosVPN manager (perhaps a duplicate) + // This helps discover duplicates created by other means + NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in + guard let self = self else { return } + + if let managers = managers, !managers.isEmpty { + let stosManagers = managers.filter { manager in + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + return proto.providerBundleIdentifier == self.tunnelBundleId + } + return false + } + + if stosManagers.count > 1 { + self.cleanupDuplicateManagers(stosManagers) + } + } + } + } + + // MARK: - Cleanup Utilities + + func cleanupAllVPNConfigurations() { + NETunnelProviderManager.loadAllFromPreferences { managers, error in + if let error = error { + VPNLogger.shared.log("Error loading VPN configurations for cleanup: \(error.localizedDescription)") + return + } + + guard let managers = managers else { return } + + for manager in managers { + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol, + proto.providerBundleIdentifier == self.tunnelBundleId { + + // If connected, disconnect first + if manager.connection.status == .connected || + manager.connection.status == .connecting { + manager.connection.stopVPNTunnel() + } + + manager.removeFromPreferences { error in + if let error = error { + VPNLogger.shared.log("Error removing VPN configuration: \(error.localizedDescription)") + } else { + VPNLogger.shared.log("Successfully removed VPN configuration") + } + } + } + } + + + self.vpnManager = nil + self.tunnelStatus = .disconnected + } } deinit { @@ -390,8 +544,8 @@ struct ContentView: View { } } } - .onAppear() { - if tunnelManager.tunnelStatus != .connected && autoConnect { + .onChange(of: tunnelManager.waitingOnSettings) { finished in + if tunnelManager.tunnelStatus != .connected && autoConnect && finished { tunnelManager.startVPN() } } @@ -541,24 +695,24 @@ struct ConnectionStatsView: View { .foregroundColor(.primary) HStack(spacing: 30) { StatItemView( - title: NSLocalizedString("time_connected", comment: ""), + title: "time_connected", value: formattedTime, icon: "clock.fill" ) StatItemView( - title: NSLocalizedString("status", comment: ""), - value: NSLocalizedString("active", comment: ""), + title: "status", + value: "active", icon: "checkmark.circle.fill" ) } HStack(spacing: 30) { StatItemView( - title: NSLocalizedString("network_interface", comment: ""), - value: NSLocalizedString("local", comment: ""), + title: "network_interface", + value: "local", icon: "network" ) StatItemView( - title: NSLocalizedString("assigned_ip", comment: ""), + title: "assigned_ip", value: "10.7.0.1", icon: "number" ) @@ -589,7 +743,7 @@ struct ConnectionStatsView: View { } struct StatItemView: View { - let title: String + let title: LocalizedStringKey let value: String let icon: String @@ -620,7 +774,11 @@ struct SettingsView: View { @AppStorage("TunnelFakeIP") private var fakeIP = "10.7.0.1" @AppStorage("TunnelSubnetMask") private var subnetMask = "255.255.255.0" @AppStorage("autoConnect") private var autoConnect = false + @AppStorage("shownTunnelAlert") private var shownTunnelAlert = false + @StateObject private var tunnelManager = TunnelManager.shared + @State private var showNetworkWarning = false + var body: some View { NBNavigationStack { List { @@ -632,29 +790,10 @@ struct SettingsView: View { } Section(header: Text("network_configuration")) { - HStack { - Text("device_ip") - Spacer() - TextField("device_ip", text: $deviceIP) - .multilineTextAlignment(.trailing) - .foregroundColor(.secondary) - .keyboardType(.numbersAndPunctuation) - } - HStack { - Text("tunnel_ip") - Spacer() - TextField("tunnel_ip", text: $fakeIP) - .multilineTextAlignment(.trailing) - .foregroundColor(.secondary) - .keyboardType(.numbersAndPunctuation) - } - HStack { - Text("subnet_mask") - Spacer() - TextField("subnet_mask", text: $subnetMask) - .multilineTextAlignment(.trailing) - .foregroundColor(.secondary) - .keyboardType(.numbersAndPunctuation) + Group { + networkConfigRow(label: "tunnel_ip", text: $deviceIP) + networkConfigRow(label: "device_ip", text: $fakeIP) + networkConfigRow(label: "subnet_mask", text: $subnetMask) } } @@ -690,6 +829,19 @@ struct SettingsView: View { } } } + .alert(isPresented: $showNetworkWarning) { + Alert( + title: Text("warning_alert"), + message: Text("warning_message"), + dismissButton: .cancel(Text("understand_button")) { + shownTunnelAlert = true + + deviceIP = "10.7.0.0" + fakeIP = "10.7.0.1" + subnetMask = "255.255.255.0" + } + ) + } .navigationTitle(Text("settings")) .navigationBarTitleDisplayMode(.inline) .toolbar { @@ -704,7 +856,29 @@ struct SettingsView: View { private func dismiss() { presentationMode.wrappedValue.dismiss() - } + } + + private func networkConfigRow(label: LocalizedStringKey, text: Binding) -> some View { + HStack { + Text(label) + Spacer() + TextField(label, text: text) + .multilineTextAlignment(.trailing) + .foregroundColor(.secondary) + .keyboardType(.numbersAndPunctuation) + .onChange(of: text.wrappedValue) { newValue in + if !shownTunnelAlert { + showNetworkWarning = true + } + + tunnelManager.vpnManager?.saveToPreferences { error in + if let error = error { + VPNLogger.shared.log(error.localizedDescription) + } + } + } + } + } } @@ -939,10 +1113,10 @@ struct SetupView: View { } struct SetupPage { - let title: String - let description: String + let title: LocalizedStringKey + let description: LocalizedStringKey let imageName: String - let details: String + let details: LocalizedStringKey } struct SetupPageView: View { @@ -1000,4 +1174,4 @@ class LanguageManager: ObservableObject { #Preview { ContentView() -} \ No newline at end of file +} diff --git a/StosVPN/Localization/en.lproj/Localizable.strings b/StosVPN/Localization/en.lproj/Localizable.strings index d959e2d..0d92c2d 100644 --- a/StosVPN/Localization/en.lproj/Localizable.strings +++ b/StosVPN/Localization/en.lproj/Localizable.strings @@ -43,6 +43,9 @@ "italian" = "Italian"; "settings" = "Settings"; "done" = "Done"; +"warning_alert" = "Warning"; +"warning_message" = "Changing tunnel IP settings can disrupt your network connection. Proceed only if you are sure of what you are doing."; +"understand_button" = "I Understand"; "data_collection_policy_title" = "Data Collection Policy"; "no_data_collection" = "No Data Collection"; diff --git a/StosVPN/Localization/es.lproj/Localizable.strings b/StosVPN/Localization/es.lproj/Localizable.strings index a115886..b5a6f44 100644 --- a/StosVPN/Localization/es.lproj/Localizable.strings +++ b/StosVPN/Localization/es.lproj/Localizable.strings @@ -43,6 +43,9 @@ "italian" = "Italiano"; "settings" = "Configuración"; "done" = "Hecho"; +"warning_alert" = "Advertencia"; +"warning_message" = "Cambiar la configuración de la IP del túnel puede interrumpir tu conexión de red. Procede solo si estás seguro de lo que haces."; +"understand_button" = "Entiendo"; "data_collection_policy_title" = "Política de Recopilación de Datos"; "no_data_collection" = "No Recopilación de Datos"; diff --git a/StosVPN/Localization/it.lproj/Localizable.strings b/StosVPN/Localization/it.lproj/Localizable.strings index 5ecdb67..36fb7b9 100644 --- a/StosVPN/Localization/it.lproj/Localizable.strings +++ b/StosVPN/Localization/it.lproj/Localizable.strings @@ -43,6 +43,9 @@ "italian" = "Italiano"; "settings" = "Impostazioni"; "done" = "Fine"; +"warning_alert" = "Avviso"; +"warning_message" = "La modifica delle impostazioni IP del tunnel può interrompere la connessione di rete. Procedi solo se sei sicuro di quello che stai facendo."; +"understand_button" = "Ho capito"; "data_collection_policy_title" = "Politica di Raccolta Dati"; "no_data_collection" = "Nessuna Raccolta Dati"; diff --git a/TunnelProv/PacketTunnelProvider.swift b/TunnelProv/PacketTunnelProvider.swift index 45feab3..7b3f533 100644 --- a/TunnelProv/PacketTunnelProvider.swift +++ b/TunnelProv/PacketTunnelProvider.swift @@ -12,6 +12,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider { var tunnelFakeIp: String = "10.7.0.1" var tunnelSubnetMask: String = "255.255.255.0" + private var deviceIpValue: UInt32 = 0 + private var fakeIpValue: UInt32 = 0 + override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { if let deviceIp = options?["TunnelDeviceIP"] as? String { tunnelDeviceIp = deviceIp @@ -20,11 +23,15 @@ class PacketTunnelProvider: NEPacketTunnelProvider { tunnelFakeIp = fakeIp } + deviceIpValue = ipToUInt32(tunnelDeviceIp) + fakeIpValue = ipToUInt32(tunnelFakeIp) + let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelDeviceIp) let ipv4 = NEIPv4Settings(addresses: [tunnelDeviceIp], subnetMasks: [tunnelSubnetMask]) ipv4.includedRoutes = [NEIPv4Route(destinationAddress: tunnelDeviceIp, subnetMask: tunnelSubnetMask)] ipv4.excludedRoutes = [.default()] settings.ipv4Settings = ipv4 + setTunnelNetworkSettings(settings) { error in if error == nil { self.readPackets() @@ -34,120 +41,69 @@ class PacketTunnelProvider: NEPacketTunnelProvider { } override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { - // Add code here to start the process of stopping the tunnel. completionHandler() } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { - // Add code here to handle the message. - if let handler = completionHandler { - handler(messageData) - } + completionHandler?(messageData) } override func sleep(completionHandler: @escaping () -> Void) { completionHandler() } - override func wake() { - // Add code here to wake up. - } + override func wake() {} private func readPackets() { packetFlow.readPackets { packets, protocols in - var output: [Data] = [] + var output = [Data](repeating: Data(), count: packets.count) + for (i, packet) in packets.enumerated() { - var modifiedPacket = packet - if protocols[i].int32Value == AF_INET { - modifiedPacket = self.packetReplaceIp(packet, self.tunnelDeviceIp, self.tunnelFakeIp, self.tunnelFakeIp, self.tunnelDeviceIp) + guard protocols[i].int32Value == AF_INET, packet.count >= 20 else { + output[i] = packet + continue } - - if modifiedPacket.count >= 20 { - var mutableBytes = [UInt8](modifiedPacket) - - // Swap bytes - (mutableBytes[12], mutableBytes[16]) = (mutableBytes[16], mutableBytes[12]) - (mutableBytes[13], mutableBytes[17]) = (mutableBytes[17], mutableBytes[13]) - (mutableBytes[14], mutableBytes[18]) = (mutableBytes[18], mutableBytes[14]) - (mutableBytes[15], mutableBytes[19]) = (mutableBytes[19], mutableBytes[15]) - - modifiedPacket = Data(mutableBytes) - } - - output.append(modifiedPacket) + + output[i] = self.processPacket(packet) } + self.packetFlow.writePackets(output, withProtocols: protocols) self.readPackets() } } - - private func packetReplaceIp(_ data: Data, _ sourceSearch: String, _ sourceReplace: String, _ destSearch: String, _ destReplace: String) -> Data { - // Check if packet is too small for IPv4 header - if data.count < 20 { - return data + private func processPacket(_ packet: Data) -> Data { + var bytes = [UInt8](packet) + + let srcIP = UInt32(bigEndian: bytes.withUnsafeBytes { $0.load(fromByteOffset: 12, as: UInt32.self) }) + let dstIP = UInt32(bigEndian: bytes.withUnsafeBytes { $0.load(fromByteOffset: 16, as: UInt32.self) }) + + if srcIP == deviceIpValue { + let replacement = fakeIpValue.bigEndian + withUnsafeBytes(of: replacement) { bytes.replaceSubrange(12..<16, with: $0) } + } + if dstIP == fakeIpValue { + let replacement = deviceIpValue.bigEndian + withUnsafeBytes(of: replacement) { bytes.replaceSubrange(16..<20, with: $0) } } - // Convert IP strings to Data with network byte order (big-endian) - func ipToUInt32(_ ipString: String) -> UInt32 { - let components = ipString.split(separator: ".") - var result: UInt32 = 0 - - if components.count == 4, - let byte1 = UInt32(components[0]), - let byte2 = UInt32(components[1]), - let byte3 = UInt32(components[2]), - let byte4 = UInt32(components[3]) { - result = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4 - } - - return result - } + bytes.swapAt(12, 16) + bytes.swapAt(13, 17) + bytes.swapAt(14, 18) + bytes.swapAt(15, 19) - // Convert IP strings to UInt32 - let sourceSearchIP = ipToUInt32(sourceSearch) - let sourceReplaceIP = ipToUInt32(sourceReplace) - let destSearchIP = ipToUInt32(destSearch) - let destReplaceIP = ipToUInt32(destReplace) - - // Extract source and destination IPs from packet - var sourcePacketIP: UInt32 = 0 - var destPacketIP: UInt32 = 0 - - (data as NSData).getBytes(&sourcePacketIP, range: NSRange(location: 12, length: 4)) - (data as NSData).getBytes(&destPacketIP, range: NSRange(location: 16, length: 4)) - - if sourceSearchIP != sourcePacketIP && destSearchIP != destPacketIP { - return data - } - - let mutableData = NSMutableData(data: data) - - if sourceSearchIP == sourcePacketIP { - var sourceIP = sourceReplaceIP - mutableData.replaceBytes(in: NSRange(location: 12, length: 4), withBytes: &sourceIP) - } - - if destSearchIP == destPacketIP { - var destIP = destReplaceIP - mutableData.replaceBytes(in: NSRange(location: 16, length: 4), withBytes: &destIP) - } - - return mutableData as Data + return Data(bytes) } - // Helper function to convert IP string to Data - private func ipToData(_ ip: String) -> Data { - let components = ip.split(separator: ".") - var data = Data(capacity: 4) - - for component in components { - if let byte = UInt8(component) { - data.append(byte) - } + private func ipToUInt32(_ ipString: String) -> UInt32 { + let components = ipString.split(separator: ".") + guard components.count == 4, + let b1 = UInt32(components[0]), + let b2 = UInt32(components[1]), + let b3 = UInt32(components[2]), + let b4 = UInt32(components[3]) else { + return 0 } - - return data + return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 } } -