From 06bc5107d6011422c74b45b82053d299de700f8b Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com> Date: Mon, 31 Mar 2025 16:24:08 +0200 Subject: [PATCH] Initial commit --- .bin/.gitkeep | 0 .gitignore | 5 + assets/static/geist.woff2 | Bin 0 -> 64184 bytes assets/static/iosevka-curly.woff2 | Bin 0 -> 19692 bytes assets/static/logo.png | Bin 0 -> 3029 bytes assets/static/podkova.woff2 | Bin 0 -> 60580 bytes assets/static/style.css | 105 +++++ away.go | 1 + build.sh | 41 ++ challenge.go | 171 +++++++ challenge/generic.go | 74 +++ challenge/interface.go | 123 +++++ challenge/js-pow-sha256/runtime/.gitignore | 1 + challenge/js-pow-sha256/runtime/runtime.go | 92 ++++ challenge/js-pow-sha256/static/load.mjs | 125 +++++ challenge/tinygo.go | 59 +++ cmd/away.go | 150 ++++++ condition.go | 53 +++ cookie.go | 27 ++ go.mod | 44 ++ go.sum | 99 ++++ http.go | 221 +++++++++ policy.go | 188 ++++++++ policy.yml | 150 ++++++ state.go | 512 +++++++++++++++++++++ templates/challenge.gohtml | 191 ++++++++ templates/challenge.mjs | 68 +++ 27 files changed, 2500 insertions(+) create mode 100644 .bin/.gitkeep create mode 100644 .gitignore create mode 100644 assets/static/geist.woff2 create mode 100644 assets/static/iosevka-curly.woff2 create mode 100644 assets/static/logo.png create mode 100644 assets/static/podkova.woff2 create mode 100644 assets/static/style.css create mode 100644 away.go create mode 100755 build.sh create mode 100644 challenge.go create mode 100644 challenge/generic.go create mode 100644 challenge/interface.go create mode 100644 challenge/js-pow-sha256/runtime/.gitignore create mode 100644 challenge/js-pow-sha256/runtime/runtime.go create mode 100644 challenge/js-pow-sha256/static/load.mjs create mode 100644 challenge/tinygo.go create mode 100644 cmd/away.go create mode 100644 condition.go create mode 100644 cookie.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 http.go create mode 100644 policy.go create mode 100644 policy.yml create mode 100644 state.go create mode 100644 templates/challenge.gohtml create mode 100644 templates/challenge.mjs diff --git a/.bin/.gitkeep b/.bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4d458d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/tinygo +/.bin/* +*.gz +*.br +*.zst \ No newline at end of file diff --git a/assets/static/geist.woff2 b/assets/static/geist.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..6fd61c44dbbbede2b274bb765fb83f75c5e26872 GIT binary patch literal 64184 zcmV)2K+L~)Pew8T0RR910Q$H96#xJL0!)Me0Qx%s0cNNG00000000000000000000 z0000Qi7Fd`>v9~LNDDM(YC^=UKD*; zC&W4IK-8PtIa&d5eX~zcG2I-zKzHEIg{jI`{{R2~|JNjw7}HCDOOl5N5X54gR@=7Q zK*bE^(j$a944zg3y=OWc10xb%iHN?BVm3}OPxLwll7*NA!G$LiPO;8{L=JlCRgN-< zATmPCBZ9P|_nS(pd$T`z$FhkCaf?Rd z0v2KVtpVj-n0~Z($!hSxLwsPG;1hxo*qvb_g}XEi?qZBGX2D=-`f)Adxp5h;uO1cK z_DS*j!V-g@LwruDnVCwe)Gl>2@`NLl6`?2Ll3x_xVsmf)b8mcG$ND&n-^O*+sap%w z{yuBfvU?}jc5pi85B!`GAAq_o>i)RGlA>yCtrI|31URLi@WD(X< zMpB+TJN8&L>T_p)o4lw|CkcvGQu0n%+q?d$9_-$Kbzjk6-eh)X&sL~}N?dv{6hE|*-4 z5JHfo5Uhw7s-B9ciq@RcI#v;()S;#FEmi%R3rx>%>;Fa`ki5`>frZE_D!PiX+ZeT# zZ=-%!xUXv0=VGkmGZL|o1%tT6tpPr7|43R4vzA!OKb;?+cbA;Fe$y#ZNlm{PNhqNukVl}o zc38%+ZYRShJmZAl}UGzMDF5=xs~@s`UWmrMPYJP>li3&i%& zBH|zK)c#KrE8L`zxM{Nh*b6|r7rGCC=l{(r$|J-SFb%l2CEJoLAPX!4%d(6~{x6rk ze}xS;KSm0{GHa`6Bu790PVGAe$&xG!uLuk>${0n#I@nJ8O0Wb}$C1N0v| zS_UQZOVQ0pjCirE`xoQ&{M?u#ImM*wyw?N{4|b1g&Yjk0IH*UhW^%hra(HU;?X&%c zF9bD&4s zY)JZn<_{@J)DJPQChk&L&dQ7Btd@B>c{khDEN8c!GmHKB&oBLE@0q*1%*#;T*_ubI zGpK~3{S-=G=C{e#H_5h={j}uMx>^n0IE38NLM;x2L^_1>IE;|o|FmYeP)hU7BGg$* zHKGcW%;aZoU$WOqQJoao)X>DB zFs{$ykZN{wQ5%3yXhKdtM2W;%jJ5E5-#yc2uKl5Z7R(A?)RN@6MQNDE!{>AwN292F z#^PN*Gj+@*xhj^b5E4IHzO(=S&P(64W&UzT!(Qk$xm^h@XtiNa{K z#Q&U@)bU$gvC=i3pVmDg%*PHs8U$UmP5!Bs1$7kaW7;647914+Kb^hp+#SzZY1!)^ z0vGeC3KR`NwOwfq?C5DU3oJPV_D8C$)dzhiT&AX?P8qHM+ajsr*RQF)-P>P=Q;Dmr zke7K8Dkmc=EC2|VsfsV*Pl0|dOY*Hy1e!>B(xy{aWn96k$;NksffLRndW%ZkI}iM~ z+1K~E1y<57BO5`fvBjcAPWL&?5Fcw)tYyK0mop0vMb`fWpw?Fw^h9Z8_K5&OdAW-V3<3`o`0< z<(zSNj2RITp&619k)ue4ghY6A2=R(|+x_b@{BJXInJ{KNi8K(4x{X#rN19uI{GI$N?Acq_%&w6NsVnm5U(2;atB6Ax|H{BsgmjEVHBA7lt1d}5J%tEukEVcy9T5G{< z^(B}cHiOw`7nq}Rz?^j!%oFFqJog)z*KPslry1bxstN4ATEQNu9qi${z#gv`9H1b> zQwK`KFbNQ+9x~?p1;L=Hjzc88n-9i^eS$T^VL^A$_`jkOU@ve6K}Mh&fH^cLum~LU z$N>RPV1TQEdjl^Ab90FN1cw0btp+#<1gP~;AkK4RNwTta4cXuj2n6t5$qS-nfC**1 zZiH0EjkB_B?fF4iLAqTmw<6yU04RV!V$(c(_3wMSy>H2$w%%xOQ{SmR96QD#-ZMU5 z#4Y%e;4b>$AC!H=`^NLJX{cp*WCR&8jf{*AkF$RgIkFs`yjnf&_>@`qj@n_I)$iOj zZDFg3d0@e-a$e)&PbVYgj~B-$jZYq5e`jHG)a2C38Iv3CPLCfS&x|tKxKn@H zo*p|reR{^xw} zqqQf@7HTxo3?)K$WmsnXKY&mg=Vafg z^lh@0wCwT?NmH~<073)`fjRN1wH5 z(eXh3oO(KU!;hgRSERK0;-ZHOf_#~QWmPOm9tlkq?MO6iXBi%pL}ii*S<3jv(-QLq z%KsOPrq-%hFG6S{qU@X287KOC{-N&~nW2t@gYhm6>qTNsWes$%VV9ek%=Wr=zso zT3eueXJeU_g1C7D(8_LyUyt?$3)bG2rSy~gX{_0@br-G$> zxf=^vDv5vGMerlCOsv+|xD3wPn$?`rjMP_mkI0gQM?dDKr6gLKNb0H94hpL>8^XozG-=kofMy7sT6$pO1 z#Pv0tP!jv!p+aObh!UwoM9NIon~fyg!I zA|`Be2DVZL*@69F(W^)5fvMW8K9!(Ax@soc<5>_R9BuTB;ds{b81sB~P)nPMrj!Kb zp03+Pp|kne*t9DAjbJj4_|Sui6)Vj(sq5qt9veF!wZv?09g=IJ`p5^pPJKVODVD1ziF|f zl!-`LB4QO*-U~a(T2l?2RC&!z!qvo980W((Q%0Fm!JUmdxB&Z{m++-YPV|DFho^FN zsvjVt-mV$sTnxuTBF=Ci-?^OVEjjLR;E_$|13z&!Jylr|0#;Q#vNra6K5XMewc7l` zz@2-;U&lC{bD&cwL(}f1N5U(=NczyUcx5s~0av`rA2OBDcj^ffrwY^szXS4qmdno^ zGZ5!3W<|wVie^Ea>;+8{Y#Cn>Uji}yoHTv;`2nqIQ6kNw=~e^?G<+})bXHW zmW^WjGNM>~cnd`b^x0L<`hO&&P8uYXUKTM_)ZW$Q&5D_2I(qY6K8_ZN7kFe4wucmV znx;2{40}2hzFjDdJJf)G=zH9cDmCAsy|)xKgm^|t+EFl?1MzLo-yONo)W?JN@Go1K$H#ZI|^h_UhqZtf{Xt^M05=0z%A3Oim=i^fz7BD9y9Ue?G&up-mi-mdVPSDLIgD z*%!YE6WwkR@(gn?;nwegB_h#NcXO51Ltn50$*>36=bv^q?dF0s#V)Qw-lWUG9*g@D zMiw1lDGe*3my66>`-Qh$WmxDPr=;?3e}VZ3}#FJdQ!pe>G$gS&*lrJi~+-OE>zG7&DKH z68^2MHV)yjdU7BC(VaaZN)@-bd{pA4EM$0*oaoz0(X0$!A{>MEM>>QjpMZ-F@o|bc zaKIqnVIQ6lCo(AqMAP;a%?I`r2wG<$lAb$Ag$xNk=j?<@-A-LSe{xx~P}!`CMtjuL z-`7fSM?DAHCqd~-No~GEA4oXA6x%E~G*Y8fGklXKTlu-Y&htuo<^o*69gq%~xVTK&+!IP`)4SSNuCr1-aWa4EiIa2;8C5ot)bQwMYKVME&iRhm` zjj@l6DHrw6P<0QNdRcGwR6-JFht*y6O4uDE10%=1Td97$Kqi?PrIQQ#5M@$ghUH6x zK!ls6*OLF^b^Sp|sr5mIP*UIU07UTL?>~!wh6`4LOZtlj2!1n@|252!J2Qb}B>od) zP~~O09zQ6ym<(q#1rqfC_aJ~O0tN70`W;9J3hY*)9&z-idcu~v_;Bmsc`f*Ux1YFu z5yJ6;VEdh1REt(#ymIcp-GOF(yKg@RBI%*~n1A;6RfO-Wb(DahHYo1ShbAbbab$4Y z_xu)75r^fu?ZTzURGwr&ClI{b$+EaJvKD%7x5 zI8Xjmy(f6hJ=u9L1%CUEuHv1|jX~epY_5lU2cgZw*13B<*HGK8B|}!SVrxlr);7Pz zE&zX<-vJb0>tC|`pV@}p*u=Tv)%yS8r6jUujV-5KkfK0_#MdKoxwV4PRHQJ`>u+pZ ze^*57H$Pu)R=KWdS1$qkaboro4cPiOmut*+u@}d10XM_#aZfxLkHypRLcF?tD>6wRg1 zuVgzttCqqb)sTjCWZd(V%`-fg7nww32pyT8H_d7cUe*vW6vHqaSy+YD?`L)`KhatW zRhgc2AI=m>ljbr}7`oxvFo-nu%ew>w_rs`IkzwOCRgS^q#yc-(;~Wa92)#ua5(%3h zUFLA5D*$TBz{tcys4$feJ=<85_?c;@IhPh%Y9&RgH0d(rS!w579CzIfH-qt$iXSqv zayUGJNSYFsFKK7PjWF5_b1d+gJ$`b=udcZ2`XERbU^{jWGOt%Jlc2gwF25S)@bQm< z7qu3D=&nezPX3U7+iEy;bADCVJGu#fd}b~yB2@lEE&wO^5rj)%lxYwjQ_K-;vBjb- zwM>i^3dJc>B*9wiBq~uR$q{GOcgqtk0}wnTSm3&35Nmpd5yRN9UT0i4{D%p-=t4nw zZ!+o#~ZW!pzF8Wmd0kW?@rKv!pfGSk{ItKc|eQqP+a%K*|v#36x{F z!?ux`)wznl@M51O(nz-qPc(GPoLk2m2X?suZgR_RyPx2@_JbQB93KV*;Fse+1&B4a z_oN!uPwMmmKpkjwKHq(Dh8dxk4=mQF@E;RsypIer(I*C*A;aiT2Qofvi;VTEG3h5k zTWd}3$S`J4J1wv$O^ap8S^Iu2UM|-`D;#px>Q4=dZ7mqKqw&Qb25oJ!zvDnhZpRND z2QP`g32*Q+`!{%RsqfSG>j(6M`kUyti9d;caT-L3Lr7RpmLtw59iv6MOA)x4dvMfG z_-9+R1bRyWv8CxdJ4Yo+Hx0)9+%6Pqo=*+4*pk<0%Y5d;P!*r)ZM0dc9d=c2X_}@p z(+?rb(Zn3b`*WT0vw424i=0Do&Y}`mT(i`5S^wzvQUAkBtd}j(58FE&@Ac#QV9-ZHhK(5Y+qNCM_U!xPp#M$= zFx?C@<;XS5YBII8$9w&_J{a`TkYOW6{kCn#u08wyIOxBV0Zcc;OgVDR zGMk=(5d?-XF|)9;!4cd%LgMz?XTp95yyYWPKJ$~G{otkQF&lG}C=nlk(15vNTPW)I|1#0|<)=q;Mje<}4Sv%8l+cXRU;8>5D{F!*JtS;N~OcjZ93D{*^ppoZ_P`$9~rAGY4G_#|1YBVmI z8s@h}9JRRku#qnQJop(KMYP~w7w!3r!2P~vVv8Jf(aTRK;nch|J8lA@QAvY@(~u`E zq(T`~bn#+x`7B!zI%d=}Wy}ee%#zbXd9oviS2M(}TLH>NS`!@EN<_0LI9-IP2}4Aw ze4Wc&m)I8fu=@!-3eywtP{ll+qX9lJ`t=sO$2!RVEkppuKNgq7Ib6mKjAa-0V1Ewf zSdw3588APiH?*4Vux|$=1aC~P2Vs!iV3wB_D`{z4fmBUSl?Nk_MiGZ?OP}h}LB6w@ z%iu*LNu*Gcnw*qav*HU6azEYazmxA?lYjYvQ>su!;WNbO*b?KxzrB>Ck(yjanP1Uz zmQhUClAeML;TMRBLyMBUE;>^NcnVk+w?G*J4qT}5Td-R0B9#=MF&rk5F?+kv$C zF4R_J1F*}&Jy8km=#??kg)O7$e;%Jbc?Cr!7YQMR5{9tEQhc{_?M`kH^3FHE0t$>& zNTG!nQB3qQ$|VT*WWB4`6~~Se+m#O zS45w`&Vr)_2sltA2vP|lpzk3a3RH8Lwb%vAIh2Zw=ihGP~J8J3@fu?p}^`Hx8t_P9141Cl7U3f~> zRk{9k!KR2b0F5G+W5B(~ihtgKUGg-t8ZMHH*$>vzZC0ffk&x9X>+f-ZI$4|9PEV8c zXW5REUl&s9fM0$BtbK9A6n-Im`mtMaU0Cx2F!Cgo4CM@Ms?%@7#>lKjJMkHF<4JS(!l^jHbn=G_$@>jXzvT>yi zbain@ZY*op|NG#`%_uT%pJBMu57X=1@5eFyvzncROoz9QCcGd6;w&Uk5}|?`(mi@I z!$!);gKZNY6#OA&?+@h=LM7tTyhKTO$*R#j8xYKDQiq)jc(YGip<0UyZ5I1!s~xJn zP7K_-cfJQ3B`GrKHtnzF4VFc11dBAXjpbpS9G>!yjb;TVGi>8Giso8Gbt)f}mZ+9b z3WLIOsIrn&Q9o~$)zsG1o~QLew4Pe^q4W^bJ8;VEZyaRo?XXM!96!a^dDjrv-Nbn5 zHSHNj;Jl;ueiq|jne!0~^CJW>6e*A}r~rLHs0NG%wJed0B=10Tj3uzZk@!Rfn@Ulo z4I*0Dghq!~^rDALR4g#57Hdcvdkybk#K5Jw*TJ;Z9+D0^gXyRXB%Q>;rnCRz6})(u zboDkQ-E_q_Zo0uGMRzRm(36wplK^Eh9!Tk_6}nAnl;Wo~%5#W=A_IXYgH}jO5M3E5 z(2Ry(q97+a?q6ekh&mGhO-@kqfGLTPGC8_B$;V|npqT+Vsln)(j)N%~0?qua(RTKM zltqFji$SxbgE~viN3(DVbstRzrj&wa9cVT}kBlH%2w#N!w=Y;0hqJ#YB1nn{IBa_$axYxn>mo&GcdUi z%ma`-1e3?m<|{ByJFs~sAMM6Dy85+CWmzD33nuS@`2dnn!1Ebcz5vNr!1)0xzXrBK z-JhTaD<$mb&fG4ejuOOW#Qh_zSTW**ks!i}AN=cYl|aIX&oN^vH3Utx9cRNTf%lbg z5<~1@EQ9TYG^-MF-vT=h>^O$tGO73;F{q4nf2Fb-ok_G2Mdj*ZoPnYTjF1W1M=)r- zkN_disA*9vjZy7qgVoUpO0C~)qb<}f#rg;$^#x>fGX6OkMi>+Y6ioWe;^#GtO zcqn}05)LoJ+G%I(GRQ{LhfkoVUhshM$_IuBy9Pn?nCNIBFawE{W)tm#o+iam!J&u4 zEQ9nT+Sap&8fpuQox!-3PBVa@g2TL#oq!1q{!&~Zf)NIf0z`f`BzFx4`Sd=R5r%_I zqd+K9-#W-4r)yyHHDIQ44bMEb!Y@YHi+tuvM`FRF%vcEg6!OH6Bm3VLfcaQX@l@DV zgJKWVL9!JFf?i}|V(xWeOE)kgV(BCV4IIR}r*8(f?RmMV&itY~UUs;Ys|lK1gDqo% zDooNr1}1l@ctjpJFnL4;8G4Agiwo$#jb)a>p_itBmH!j;_eO)!EW?6bo&??|pa zX2Qq?Ea-3;a5(9KDkW-U;V_Z|PI{?Fjx4!sJbt2;9EL*wrtK8_Z@L@*9}8v@5SKJA zY4XVU=olt!^`~&;jerYLvBWjNwn3xibSc!G$ElQi>K8hN18_p&bv(1J@N&3t(3+dv zjw&MEQid_iiQVoGQ69vGdc=tno}-lcl=TwVyiIBETj&!$riMIO>Eqz^0qIIS1N>zW z_-;4|4g3=kgJ95$XCGM190R$=KaiL>a0rhI99aRG)eYPe7K3NIef$K)Kv}zRe?kC| zjwJMf!SsflYAgs$HArZMz%i`_761>MBkp8*A2HGCdfSNxxNsBjhU>;q%N1XQ6BliU zQqEf!*Ewqh=;T=*uXaor$`OOm#KAp40+)6Z9Cq&#>e;@taAnJmp^=T-k6WzY?n|+C z#{~cZC!I^f0_PIL`k=;0Ga<|HC^*l;2WshcXToF4?xpiKlvD7Ww4a_0;xq;w(mSTp99ychzwGJEGgJp4V z4#1#gOO$EpA&p)%^F=?;pQ;B z%U%ZvEb%CTIgL2li;|_mxf)U8X^a@*AwzObnu76^MX93V*%Frb}2#K|3E$P$^7o$kx2ylI!=X2DuoQps;wlCP;&?p#!DG&1a1K$c`YGuXEO? zfk&-sjbM~963x~K=ZRsV1%o6*KRu>bvG;N6s5xGM*mD$7)@z?dIpd>~I#N;f8xhJF zG(hp*_yCHk@GG8Q7V-jmb$9~jscn$1G=5s@##F|mRd(lAl{T#Izs z0YaOT9H^6(oq)1C8zp!kLlqj?kVXCrtjjEDu_|ehwa=3rL(g&LWVq^dPz(@QZF&+W zmuZ2J>Fbrn$g~%^lL}Akz6?oA$kQVYkwe$i6fq}!DgrjKPbvTR3F|U<7g`U@y1{gB zU0GljmnW3sb%XC3;V=RuL;@*<^&Y`;$?G6U*w%2xg{?HG?>(bnrsQj54J3JS zL{3(dX0jdnNsDgKSaQ!+$>ez+gA)v4$tj+m)}djvgpLthG`&ORI!6&Ca1w{0Ay7+h zNpgFvb5QKn?4?qKmN9ceLljfxs5_CQh^}jWMtWxmBT2MeLFgqiuE2tLdF%=#=pZVt zg#~ToVz&haQHBiL1Ii5{ahE(1aJ9u+f1=?Ai$$(`JSg4(70y$r1ZQIxc7Ye`t89L( znrN7S-Ny(XlmaJ)5LNdj1RJNv$X_j^(Svx5=^gP+nK>Q$+<}GK}^Kr z=)r^trETQ!zZirq*bRax9D^an9TDL$h$SvUC0zF>qujCyB{7lk(9anrocY^2`yl{oWmEkNcE%l=BVR^P)9YK9K;x&mpT{x7z19gid~b z@dT@z04hh_SJFk(YOll%RN2r~ zCVuT3=#=qw7SaBT6%JR*3XB14IRqy0DvJ|i4o|I>)oZ*c(WI?OngxzfBER?O0CsThF>Rv};KTxwISg1EoM>qf z%S{o_9F;|NLyA#bScKh|sIdN9$RSX1jJjs2mT6cKBb=E`(yGyoxyyp0>jEqZ#g~gB zx|6p+HdNW`J0mbphDZ!N_D1yigk@D!2OYrf2+U;8g&$>$iUS5JS4liPX6d3}x1pWq z<18|w5<)7ZOYjtgFB*(z#N_Dl-CO0_#M_2f>5G%B%gya=A_|Hn4Gh zh$=kb?E+gf2x){x)`)Pkew<-hLxl@P8ggL>z_653qGUmWlmk?X#h!SfJl+M^Z2&X! zC9jVe$QQeQnt=()Wich>n5+3h{7Sq8{S7fniZmG(SQegZWZ7tY{Byx_i*n2v`L4O8 z7(parD!hmyYh24-4ukbM&tVGof1&md(ENGNixbFy&6g5r^%@s3w0=XP0P=o$MG*6z z2pDt#7p@41SNndTV+lzg%GUvoeDr<+4E>by0gU=Iov$fb^pwilrn0UK);Evd7O|nv z+1Q%T?{CAOe2-y^B!^seekS|N${OhXzaci^xP*}_92XiPVJ!(qBy2t5hziFAW0%`( zgrd6`%T*(OwTB?KGou;UKKB%E&=FP25&zbyhiz(n4ZOs2JjG-4kk#9aEs5t5&!XF4 zmnfq|gLdw$>sm3vsnxaOF1BtH?xqD>sG{ zapN+9z1&*`bPCbrWB?^b{-JT(fkjTqVkf7=Nm=5|Sn5nz=8RbG3|Zlv(J7FsRSR3K zs9L^OtdcM5zg@Oh0|FQjK)GLj0mHfUCB(J-g#}cC>X1gXZytR54L?&@9s^Ri33KDy zaAuDDRrq;uBYYB^Gymn6S-uzQ!s-zlxP7v1SD?TV|8k!$_A%jZd5)3GvH6LiF3bWh z`N-9R+3z6B^@~ULE66hSN*%tw#cVvE@RH*$a&=kkZ_x3bQ=^2e2r#agOn_{YIrki1= zS!SD4xfNE1XhSEimol&1e(|d=e&OQhUpU2o`QXw6pK+Vl{KsAJ!WT2j#+JPFWvyT( zt61F{*ShZO^5ro8HYQ$xF)d09axt5kv4QLc$R2>~1;{>t><7pJfE)xl1acTzlEqnU ziKUiVZiPZC6c=yZwJkU5W#v}pm0!X7<2j&eRj)=ht5xluF0wkNWV3LuZI+5HU8d|e=WBw^q)a4; zc1IAlPl+<{5(=B$Qi+C9AWP;IT0?cyi!(zMNcFS`thK73@(gc$cxro{a38ct6tP>L z>dsX$)7~@Y!vvE|NmD@HTCs+%!6_sH0wAc@O)6Dua>VyKc!Fe#U9a;~^kjWzFg!#>Z6 z2`4gWoMNkSKAWi7tiqs4)gb5Oc4gPw2ut(1_RzipH;E#E5}<5jQBUB84R zQ;}Z3%ty|bS--+hp(?w6Re(}WZm~5%Ds|o}2Pcwe(*4YN1hE2(K`@YyAb%cQiH$ZX zwb>S1ZS$Y)cFfr8e_y(_3v+)N`Gewc^sKxkCpOc^aHHj<{9|8ei~UYG>55zKx$luD zp8B0J%F&39E5(7PTVeC73;M#pdc4>@k31vvd%uNFl!~;{AfSP;w-l6A@IfaIIU_M- z^%`rYy$(9+6yP%BNm(LGd>TRP2Vd1(*vo0%o@Pn@>$QAO7G8xa_EeRsT$QR;w|dpD zK@DqECzU<6c>`xA9fgtD~td zj&wm?z1>Ln(w-ZKtSsTAX0pG}-q*vf`8ddqv76axb_ZwiduM;a=iS`9UrN4|erf#B z`Jvl=6F(`FB?W$YmvTw+ysXXojON}u{}$eIDHfVAgd-Bs2r0n_Jp0(o?V=P`;S^5^ zmS~+{HFZ&|Z=M$DbNbaD9_0fb&fyx#nK?7lG(9u=@|JgXtWHcv95iy^K?xJ0dQ}H% zXq7S)S5o~tpbMBsl~oi{Lnnu9mg&YYrtwW?TGN@q+O2zE-SRHmlI`+&p6|sj@p?D- z@Mr&qLK3RbhAxZ&g*)0};IEsj_Kb_|#qj;F-~C2k)OUPeETsq9L3BAk^sfA4(ES@=Ke>C!(dDopfQFQdPuk?* zV2-yiAp3KlN_=)ka6a$$yK?f=v%<^6`3(Kpx&8f<5TD5o5eR(hDz~rp{%W&sa_(l! zZc}o*8Fx5#w~6-|_pk+zTmQHPPa5}}+~@3h-r^VJzhugr^50VYjxFz6^qvbJA?IVo zpE&+G=6zw$m-c*Z(vK$o?`iPm9Y7HT$oet0*P-p}Bhr}1GyvS{LJ0)_@oG&JhIYj& z_!Do-w_(*JJ0zO>c7j)FvC z#+g6I=Gu!#1R98S#W`CI>g1k)x3V)*0lRgi+Uh(A!tL(M1eJ2Us^Se>9;~cr+IN52gET&#)&ByXfUnxpu0N z%sh0$@q2{$rm3fjC>iBP3TA5c>a2#gBdzX{05tqQ%_+kJTR&C3QcbexqgyG-m1sU0 z%0})9RzxpWj6o&z!6|tf&&gPu%8P+O3Odgb!p6`#Gw{k8@K|1ZX|nvRJi74D6vRs9 zPQp+@|DS3nsKU@}Iz%tV8$THT*qG|hCJ4{8(riw+rk`JO8Xa;_c!bCNW#EtgQl{Lm z-5n)2t@hq=u)uxrJYjfI@gh8z>A_)?@KE;;7HDPwIPdLpk_zKb| z4nHY1G_=snk=cISF;ls{uuOk3MyRcp`k{JqvHPs&b|S2QVRZm+c=I_#0T70I?-q_N zd)HP4NU8r3JdztoB$6ieQ};iR4f%9|CPx4?kqe2e)JQMaVp>t-|Hdz?(rm; z|B>(oUt&o0a9O}^jNnqld%z}sehYcin~};@e?*9*GpcY!k>)$G{^2&zS~q=U$%TL% zkqY*#IqFpF@o2-ajb~D~_D2}DpUx&&bGA;?&oi#MIEww3hs+W1vH$@3l$W;2KuWF5 zj@$pC_z$1N86aGuF*bHAS~(NTSZiyPDW=QydvZNf=bCGc-KPmrB^9Y|)W>9USH3q} zLg=EbMH{!>eeOMJbS9E!K{Y&sEAAt`0Nn5%1+?)$*)r-WtDSDFuuYv z?cWbSW{K-rhkhlq;<5rc^Yss1vzC=CE{IS?q0*#+jA_nmBew1zH{g8I>$92|KsPAA z1~EpD4OpxrXUV1;k(63*k6G1Bb>!$AQETIrH&5Nl2AOI#UQso*Do2Z7HdtdoYF)3n zWm2EN{MOx4TW9Y6| zb+xtk^$WVF)4J)T{!bxV8hrW!L@T0t?U;sZQ2(h7^*#Wd>JBQA2p^Ie0Dtx~;7=d= z(<`5j0EPAc^eE47D($yk1bklp*69H3`o=r1ppT&J#kp1$60`bR<1`2`SC8fxN!E>pBq{!m;FP!OrGL$)#@o#1x3rb5ZGE}%K%`s~F9?hgroi3Jh>QgAhBCTE zN}+dd0<$d)o-$*uArgBc|1(yUK%z@u00}id<~}9&3i7GFPgPV{Ob_#p)$Jm}=Q}K4 zHxQ@({&H{>cD#X^okOS@5Qi%NDX*ih#@cA7J+~B@1{-38Y~zNUU-69;H8mx6+U0;F z&N=V8Tb_F9jgR)EgOMVGO4Ohs3Q>$|5YcXI4aGH-OCGh>Q(L{gs%omO)}x$;tC>z; zG}!g*r(Rx_{WslW^(;5bp6$63P#{+BQb7^@I;aq zs(G!3w`zH>rgv)lpq|f;`|6l4I(*mfpFV$`41lL}7&>(XIwlOAI||(bL)S#1OCpdS zR9cc!gBTQC|K#*a%D_(Qm#hKF8-5cHe-t(ae z66UE>{G1%rk||4q8y#z$WaH=e%O*+nTI!;QYVE8>!7Z)P*S7e^R@?0Gz5NczoyDU& z(h60Wizc1%vrRTT>q{q2|J|mXmglHrezMbcIes+DFJ?Puj$h4nULPCu^_6)pm@nS~ zzgg&_OuzfoC5v3P*cD4%v&|M9NPPN~NUamB~!n<1LtRNP+9kH~Nqb1+%oLej^cY&$A%RK{OcK zGDSz^+H*P2j=10iMOEEOzT-X?*BBsqW?EO!P=pA`JFL$gh{1`mNMoEcEzStSYzyLe ze;2dOc$HLJ8OH7c?oQ|wIc7i*K$M|kPYCa*bU>hqi&c?TQlls(`0R9^T`JbF4&<8h zWV2Dd+W|D<6BA_AWdw|f{7@;(ZM0sAbt-m3pX^>6i>=WA+#z>~CeaXPtfG>09C8;+ zs>#8{f(}o#Ze=NaD9i|H1(3f{Z3eV#*JuPJe_Dl#lcnx@jit#q=7(FSF`FIw@^O`y zbk=Esq&s@w?XZQ`*Ej9?M2BSS=R6zEF0g|wS*ruG6#Y%!pu?7cj?>&EJSaC?xz({z zYdx>mA8tV)YH(c=v-2L-JDmp*M$B|rO$Z%c+{=m6b?%)u(M=js7%|ipx@+YcIi_P_ zkxy8&?LSioEbpJDH|FL}{5ovPXSr=AY_~`U8Moe2O(k<{hhh}*8^Kz8w8t}yvdyeZ zCJVr?=#uCD&UzIA`y@;`lzM^P`prz+s2l@NqP5Moi;y?BvL?1rU^R&QLe6 zPB9WZuVoO&k8WZ*RC1d)M1N#J#JtKuyQME$sJK!Nh!ATYM4X+eGK(+~lHe6^I_sH>mG9O1Sr5#v<|E!+!$gszc)=pR^MP;$kQK0WFpgj=vRoS3e0OE zIT^jQXK$;39TM5vFl3teC7=0NHL~{4b*!d)ejH2rzV{o=c}h;1z$tHPP;mPoPWDn{Pl$iLFF)>Hm?%6r2aGq42FEyPY z`-kw9R#Crrq<1HrlY2buCaxRpDcqidPVD!@q)R3?S<8rIRGLY$+qqoB;)2GLda4%} zADkj)f@8uF(4>p{o_ua78z#=K@$5=aA-k^$hm^;GlQE?UOUnBfjGGEItSJx#GMGtH z)b)e<;!q4m#h_nPhRiz*9%`ADvRmtq&4TH^8MHNGxc44=vlGrPj;*vSns05^2CTP; zUy(7~H05Z$Q=b4YK+wO}Au^zp>o&fd2`JhKTPHrPV$AS{#}KR%wj=6LE6q=YnJ!*# zCxcFW3MeA?suvM#RQmbgx#a(DE`$SE!bg-!7{R8davc{s>4fCw#jbhY9Lp!&xtzIR zPW>30=$uJxAUaF>Sxkz%s52C!XcncYErzYKBpBKQzRE5QQ+#FQK(R$uVTw#%d?g9* zfpf|{wFd-A1BkIeH&~}B=nb?n&H`)Am|Uh0YX=Ep@F^>0MlS6jKSGMLOwWMYYMXk7 zlO%{0ysaj0UTGSUtfg{ZtqV(-_x77s-8Shuy?nP@NiF9(&HVI|{e|+++GDiapF1Qe zaUpRm$@oj^UAOm7cGiL1?#RW*MwtZZ%(1A2?4ot~tYsE1jk_nNhE&{74dYCor0Jn& zmRPiO+(=7?K4uLXsLCSV(WYcGX*}45rW89OJlh*In=!P>gLq8l5fm8fiDgy$vIk5T zuyxU+J~B3Q3zQI;J(&_@@q)7RK-myXG*z?n>6_CyEed@IUG_wF?(`PVdQmmQpem!b z=JWmg*^y(OeO^guq&bOFeM;QF0xFD%^WAAd$Luigjuj8V{XionvNIo?5S%26*QmTnw8^J(UfND7 zF%FKmY*daKEyuQ9WjGv88!malT)>vDL=>y!UxXZwE;13npic7o6w9f~lb?kQZv^WY zMZ?=M)bc{-7sD-)cNiSmge0O~6;o0txo0}95wg@NiQ0VPMSL3taj1+|W<7?fbI}#y zvZJ1LvpLa#*mc&lnYR!+1U_AS0SyHbP`|k~!lcPM(2hkG=|q{w0k`cunIFx7up0o1 zRe4Pqs>wH#NY*1oOeoOrBu?biK^%4Zc_I!#j89u&LygLMu){kMiIU))AKl|5YWlNT zCCMU9c}&6j);NM7UfB8Sa?ik~r-rH430^I`tJTHlz1X}eYk%)arqLVTnbs`(Y>E@i zb}Aag*J`rE66#DlnWHM_rb|;3vFYTDMHI9bj#$Oq_-|yu5tMmj=Jx2}54`NN%D}hi zY4>_O!o6)7FJmv4a`GOG9VkL!Hxd&0HaROI5s+bsN%LI2k+6zgni7#D&(%!W7$bNb z=D-QVgDH<|p(yeuiBb6BL%ilaWk&DMd~uc99_pgRS=2D8YGMOb>AX9{hDnNr^`@~! zskk7wT0ZZIw7OtYaRAj8i{_R7-8{&AKD|K?UmF~$I1$?3&=72DCQ*s1kR6qHjgP9C>giK(3noP7gx`g$#1#Gz4@w`gQLi?3S_9v#7|r*$nK^31+%!tp!L_rf$PhKGLF!LZu=hs;doQq;B9EG{0P z3SLS&hRzL1 z@0f63c&Hv#Wzr}Tf}YGENos8*@P5#>6{L>y-5AOOKk}#yJedY-oAvIe{ji+#iiP*U z<2q1u)6I{HELsw*)sdiw9NC`UZPWO$Kv)oyBV?Q-UO%w&pn77YgYqFs`zm)Li9gbc zoO9Z`zRH{C2*Z=o3Mg)>ovy8j6E(Z4l^|UYKmmX1_Hxv%m+QFrW<|fJ8@4fILI*Hg z7d`1TN*}X6k1X|L#&s-HImCmE@uB63=Ht|C$NZ1($Fg`=Ta8hXQRT)`{V_)>;21sxHy1-3d z6YZ&VJX&^ipO@z}Fbe`;5xU9LjTd!P5p-s}PdzRs7L2c6t)>}62yHu!PYMjSOy|ZJ zWFc~`u76xsn6TD%&rDsh285mg!;UcYIJpU%f;&6NJfQU~-b=wcf#qQ#xo1H8t4#pi z?^*NB`eH}hop=X9!>c-CU=@JD~hh zb5-7Pubh&>-Qh!cCgZnPS`uAp-MkRYQ&WwQkc<99tD4TF`woc$h z{QA{?p0UQ=hbwK}7?ObZc-n6lvvzk^PDdVnzwKO=muBfr#|x}^?X?De?l$XhF$`pH zcER(2+>V*^B=_1Z7}AOM4nC35DYpI-4{@*RlN*!TrA7s>Sfe3m3PbUTn)%BxrsEjB zvIkJZt#*1UP_!FbE?ys0wCd*lG5gto(Q`fJZtcdsb;M(Z?uPeb3{GL4zUD%`D+;1I zaS(B7b&0!L+5Zu%hA*=Bau$Dzm__{W290$Edf8O$=maSi1_*k+9m!?l3h!BFEH1Ow zz^0{zWhoRh#cDVnIQ?J*n7to%$Dp>!YPx4OT3yd(&Bs0 zq4>)sN08W?*vpR$Bwz1NiAF(X+0K(^z(LaBDZJy3sGT6keL_9sV)v@XJHS`%khWmw zfoJ6mKMT$FQ=6aFVD=Ft!$mu~*QH$k@PkP~b{Xkq!bBTmuG8%w^M}csb+=5dy8Mkf zu$;g=IAkr62}$LD^2UY}Bd!MgWajiW_@+_pWa$e)oo@>ENpzCqrS-kcoDe*hYeS%I zcDlURqR5WP7mfocD(RHnI@$k6lSg?s24|bmP-^J)TjAoKUq8G$u=S?}R+ofEZT>*8 zPZHvEnYc7dE?4BYvsPG%g@%cL;He~VruX?)T5R7Taer5ijsQ94-cTgrK!iuB!@Cdh zY&xr9%!-aPha^iz9f-3`A9!R-vRm+iUV zFDE{n>~jMwb)*bxNrKP>m31re&SxND=REPB4rU3Ch4g`(lk*xY>U+PMx&1a}SiHg6 z3J=_8p;!*@Yf$-vVJ-`_xkaJ(fzJF6XXDtm?jhP6$#isOc<;T^45S6%$TR~6?Ppt8n92>7V=-$-V0Zn{#R4>1MEq#hm&3ukh>JiR)3OmZouGmNX&-=LnV;Ih`8YdbS z{9#IYd`CYI`yYRPy2;8!%eGbDZ1Lm9t!}sAxApgGPrRB>jY`IUqx+P%noQ)u|NX&h zhwBoXs*E`*r1F{AYF5i)De|pHF!Wm5M9r$(>%(wkVl~_DNV`U*UL^M|WAZLKqIa^e zYU}=889ifAHdIZuv?ii>flUQc9^G2aA;-!8~o+L{0G`fG>QtKUw5Ye!B)9TeuyX-jRvXPl zTo@Ub9cOWBJWm`;YAO;rOLm5v+)rYT4!^-Eo7HmHQFlf#EWE9&+v_4D8+rUy^?H&0 zrjpfGaP~+TxxnLFQ0$NB@T-)dqn284)a>o%kGE6 zS)~QvjvM#{%O@SLmOr~E4tY-VlY2n<-OJHG-}=hMyPRivj}1V&n5`mYRSd7$quIZ2NixeltLANW8ak+2M)rkiGq$b z`xrZRh-`Vz)-Co8`uO%-A*p`7;jZ2;)TEU{-nZt)kzpae1 z54l3ScGr`iceRKdJrA%I0J6vuCD}Q$1`|QV@ zU#)T$tU3$q0NA~|f=?KK`4i5+jhauMABuv4;X}7b+X<~ldx~(_@o6>3dnF(>EdbHU z%lC~$ngvX=ogt+}S{t#Zk){QQyevCLqf}yg`y^R_dDSu{A$LCqeDdOt2J!6!1Ne?d zL-DbP#|nGGlsS&3K**Fbsg{Mqs?ii;YDhND@`Nd~oQ{E|Mi8C+y=3qHJukd8v1P4y z)yT-I2Uc6&3G=Tp?~<)2qV~~Ky$%2qPtI^E+5&R5F|E}N1*-%4#c6|qW2?MR5S~#0 z6Y-vUB=Kn2wWBX6c#w=Q5L?xqJYP_}GAOB&_^sygJ(fLVp0PbK(3aQoa2(yy(c#$n zNMnm{fzH%63kp$YnL_@Ey9F2A?{W*5B^|gSq7=uoKljL|jg+nLyoaDM4)A-z;<5O) zr5{SzcBWg=osTxB7O!1a&>Er)^DHiw&Xbf=W2^G{#onL+D z)sUazU$x;`qbxwngOhq?53mI&;JP&cnQRUIFWX`FnZXtVaDhAe#;!ssYhBw7cckUt zn!$oSkC5zIG?)I84y|p(r}TkNVdzsV!T0p~Czl1ATZk>)JkgDRODF@^7ffu(u=ktiqUXbv8>gE+BL5QEsts%=*dez+ThsH z)r~%ED3&IMwCUt#56MPPqBxdDC1YMvx-4Y_(aC$+ z^1h@=ljxD+y9-)(69j@lL`&NZg2%}zHx`0nAMKtZ`-aGUsgyPJ*SLA!Tb)VmSbV!K z^+>{@bGen4XW!YHFmHv#f$n(^&M!EWiitX!vqVchxMVDa1wDzeg44gvQ!WslobBk4 zsvBVu4>fb$K?v1Qp!}}`l2e*C{g;*fA3)b2o!$kb6TmLdvsh>8q*z0g7NMP>t0d+U zh*opduSpiT3mU~7t4ym5w@K_+j~Ys58$*;Z2e#8?uuCtkIg2Zz)L>z&mWNCAhH#Gv z;I1@v^hE2TS?9iayr#Vc(ItB2&Q;_p)Nj>84Q4#$0vAU9Q@o=kr48aeju3V zS!6H{y1(+fEWRNC#XpkW6Y7uw90$Gl>GV_@&n9rBMGU9mkKu_6IbNEbN%Xc6AhFoY zZzAlk*jLeVGQN}~yji27z^~eyTT|~jdiVbb1er?FOgGk;);`L=IJskf1Fu0RBHv{weBdbeK%I z%b)jFEux1Eiu3OTv*w`v(QvAxKlvN=%e+EVG&hGfDPpZ_^5c~>y9{M9Ej-4as?dWq zbQ?GDk%Zf-NGheIV}nIz#e*TbTzkZ^%zLHIwDD#huvYIGP1;9P}I z)IJS&PLc;AZ@t2jL=?k5pJF(Ppg7`ci$qEG0?JaHk2? z#W))GngC^mT`9M_Tcc5Tt6gr_tPN1sX#6oD5EV7IAhKbfPd40wm}LQ8@Gd#&6vV?J z5d#+*g*8E~z9wK42rZu0XvEV7{u3J&cZ@dnFVk)t@y4_B?Xj85oy2h6=JefGk9D|gYCYxvE37n# z%|@bF)saf=#wqj^3W~R=B6OYkr2ysspXzK*mDnfch^9 z*R++dul*8IVwwGp9OV4S%Sa7Rgs zK38t3VCyg$Bdqk1I`Mp%%FuXh2P~ z0OryH5L6dHxQDf({%c8srE(=)LdO%&el8Wx9Qg6kU+xaCe)lygTs7QUhAxOF)`EZL zfM5nW-Gp$V}R;8Ye24LUqu(9|+NuN!tV%%!x`oM+)q?)g}I%tz{7 za+}IvC9GPKN-UquGlneSr%uV}Q*X6$lugi5ES%v3BL~8rx%5D^G}{;cuRS|J=Yzcc z8HqJhtEO5Sr@uElvF?Ze{Qy$qsIGi-qNd{g?C7%x)~9O!NG?stfGLR$n9(g4N&p3s zzTD}AhcK@Kn2g^iZ*flR8A}YhtLE)*>bauMghMpqK!qa-r&HtM2T+pgoIZ45Tb8w= z0#}?a3ybT^f~OQRL|zq?Nh-sL0^lY|7T9>d{w|l_uj($W&8R59Vf9U4fhi3(y9F7U zy=G>Pw)#RYs;H?-bpNhqmePwn^TvnfQN7@s`ZNb8Id4fE z$)4!2-9yU<(#hq0L%Y1Y6E*}PL_56OmrwqZRt^5_5Ziyf?{%c6|9IaI{|{iTAlH-5 ziYChzkDp~TMzav-os4_hL!h1fxgB?-Cx%{HBggOxpI2R=Kfg$sWW2>mkDx-RAML{-sOfCGzpUehR0X&|<8fR)y%g=B-mOD^*lxT>s%bLY z{^j>q4&W{R<+` z3nzWc^xlPe-ssOdBFItM+lq2INIcQ({=Qft8O?Kh2RCUYRv9S+ggkOgKjxnlM+?dR zm=8_klfjf;Rz1hm5~ou|Uhl#&Jz4a(ZeP%EhBjNDF_8qhLF9krsP~1mH?lQ<0h7ap zszY|Rl6*(su(mbC=M(C$+&!H#{rQUcZjLPvQ>efz{G;w72Nz>iVi19NlL z?uVK$y}@_pesJvO3O;V8wo|;%ccchu)%ZFY* z9#blyuncjOsvDy1envjfdckf3?>s-h#tQQchMm#D8*F zd4fn?&_`eHX{s9~JWyF>^lG^esD-}YtKK^}-<<(x%zD^W&9}Dc)jf8Xp|4kK#f3I5 z%Ow#r9A*w*?BH-5AVb|{=K?JC_oxqMlDageOjj6Do6|&Sn|-@*aV=w5xE*~^a-gnu zpX5P+r4FFBv9o}n+R-Z?KR0#4aRF#fq5A06Q-HHJC>2%<8inZumHhYv4f;$g3R?v) z{z6WAGf*Qc89z+U0^!*ieO=TEDoH(Y7SzLrW*nZ;gIK8VTRadIH8wJ2*6P4?x|y%i zn7MSGQA9KnjbFDaRsUZqSf>qVj<(y$XghA^+O%h9S#sT&(zd`02rBu%6YH9($&ZgI)@Ruab`8K%7i>N7{DA=~Ir#9x zwnr8Y=AX*Vm|uJpwMU1_)<=!r`WXDj?m)joJ3a=6V)wAl(q*+-Iyvq3h;^MdtEJ23 z^|$!!_Soz9A;sKjQC}2X8hi0;$k@z=@MZ|+n;B)C6(sCUTkCgOa(Yte^n zR=z-J71$mEAw_jdK=<6)DfAiYo;oCbyQkcl=qA*YNn0)jew>lvR%#@C%5JWx;2Jv- zhK7ez(7AtXRzP8Hcu6Wh96s^1SB|F0GJ5c~w5P(yB1>8$Xz{E!ovSodmA4$>F_eYA zI#*d8hH(Yam4ordVqr0Sfu+yy+aYdZz!Sz-HaBEN>G{kp---p z1`-HUKNcEkv|ThKt#DMM5xaNi;i9qmhj+S?T7PZq-_Iuro#uZ0+b2f9podUk|7JR= zU)Q@1n)xE}?Ubu{A7gBk3sv#b_jdw456@j;2b z`O%PTOSgW~pvJp#1v#6ncH4#bVFB6F6olGS5bFW##LpU=OM*;=ckk72z4FcrOUq@b zkkhfIQhZ}?{3QylL#bcRd-t_(fzxfp;byYAmR?(hesYn#`0f;Hi~?4kYd~g*>7{JK zBl{GDtQ;D`SExO00uwJ#jB?g0Ove*C0=}_CP%W5*Pt*`NQSGRCmcxG5Q7f%QixAGR z%<`;T&{PU+^86zq)As&;(~gm_KM;AK0eQQo`@PZTCss#!%Sc$SBcAo>YWd#|L96%^ zsFr!mz%fk%twXSAu&Yfm^Q~8D^sDED4!C)#akfx@SOJp?g_ z>YtfRVD-ePD|w*fKtC zL;luIf+n@JY1Ex|%+TAbwR$bVATFj`5e8r6U~sKsF~ecyfO>z;ue}49%hTj_EST({ zlzqDh;O999g>Zw}6=`wI%Rh*sVWl#Vl$gyai6Wqc?ar_Bo%6yiE;HP)Q0VmHQ6r-F zprN1_)gw_O7KN=!mDH>;Ar_5PWmN)&ykNIK9|~u^eyu(fdju3*D2CHEv$;*D?Ljd^ zZ@1PK>UGQh*AgmQZ|H8-87yKuonw`X8BQx#A~tjA4zYw`Lztj2(@J*4Vr07&sQv8t zI?S3<(bCU03oLx=VkqvLZ{?eLr8?0+&Uj@qsa)xDDpx38SWedpL|#FRawShclt5}B zyh63<&AU}zvyD+mbV03rT&yu zRS1XWYWX?+#1-lPyHs6|Jep_V{ViHfCge05lp2S=xa*yq=FRFK%MR;arIpv^R?}D3 zRWbq>jh1?KAAZYKnrZM@A+rlsSN*hwev4Uo+&}utCauz>t!&W+@rY4H-;qSqN^LfX~c zx(#(QRBcw#pQ)%=PiL&EsCbBepyF)V{L>W`r{|ZQt=?d-Zp|^aRsXc^#ZUN7g+(A0 zV`FA9R8tK7PSxH%be<@XoGB`RN`Q}D-@zjYUWZ=KYbS7_=%tS15D@9WiN8~4{|CZE zg1X8UlUAwS^vVyug-Yfv`nsR0)h^f!d91%MH_~ZCtl}D|ICCR-;!LA@>!^vg+3|R= zLqGZF3|YX-igNlDQk)m5|dFGV1Y+Hg}?OTSSjtx*tq&}J3>zjWe?{+wJb55Mww z_oJZ7Ol7GzUJNiQ>sHdMbL+}!uj?(V!g(pG&s#*!pw*dy2U^L$!z(l z>Rc3w#o3vAfHR~k?US_Q2h^FoCPiE2pc%YuWPeV#&>W+rejAc**U&bJH-u z>(eeE*eKj6t2Plf7hD;;XTYoOku&uR8 zLwd!}mGve>hhmOwYluRD49O0a9ZETtKY2m3%Ovy z={2|`%b5NHQez{hu55Ev_2#lVW~!@70sVm(PA)Po%8JEMJKQcthzOypK5TK zQkNxB=P7VD?vO2GH6P`g4`kMSL|*B7T?m+6)PX1wE%2P*@hJ$&U}^Hoz`EA0O2#i2-NvqAAdR@NAHGQ4 zpVvJyTr0)rR}0;|+s}S%J#C`W>&W8HfsT9Etsz0h~`g_9%00 zX&6Qu0E~4vkJMfNQ~CR$uQO~QzD{|OzY5u8@?%*Cv`)KqHb4665R-WIQQ|KUK65l& zub;VSX4@s_UXiv)KW*`hmrI+UW@*7M>F+a#?x*XUC7&ie^kv}b(NOCCi7>gr4d9OS z+UL>k73n=w3;UjU>P^6PoKt&fd;sdL`~yUgGBZk<86>m~%-_nBd;xj?fJBYue{)3d zX2U1~13$3G%KqVq-_3#@2m(q!Mz5kEI{8!B!(^PxM(lJECEOauqRTpacX@YP2%SQS z>1?~nr<}!;(m1v=V*Y1`r9KKL*HuSNM5h!DmJ;=uO{G z`5U_Ig@xM>6cs5VB8_*U`E>%3$)fYRWuewP`7qshtK;LnIVsL6of$P?Up0;T`{9kh6=`? z%8J_azM)vD^M{J1s*YHLd2AJ&@I0VsO4UCcXfWNs9Er(W3toHsQOV&-C%dk-n#2FH z$|a2${*xuvrqzSlzoApH6^r#G}Zw|!TQwzCNZZ)s<2+K3b%?($0xDjrX`@vfHVt~ z1nj4bnw3U@xM_Zsk&opeb3DudgLm(V;R$7-)D)rXv|*;gk@QhUtYTHwh4%`oU|YV6 z8sa+mto4sQJ}ltM;3&OHA#AU!DMqP`vX5SyKmSvU9LO);4&iiVco(>wG$*b}@o4XhQmAPe(F+|BT`Uo`~a`4AIZvI#Zh4q2R zY;%N?Ych4V>E6DHuFJ8ndmX+Z-f9q9&diPC@>*NvF7T_G{;*fJ`m_&u>>;D3|#~W}GnZpPYO6Rbkx! zbjA6Kw+DdI)2B@sX6BdlqfL`}NR?6^j7znSxJZh3H)p+X(&aIhou(K4KJgm5BgE@G z_jCXR9>FHD-p6sUdhI8Xk{@UO#AXVouyP&1y!X5P_L}bQRHn+&qf=nEL7H@6MH_K& z`m@;QDW&~ly#L~f^Nh;ITuZ(6O>>P?MLzs$4hqRbpAmt76>=VN)D85}Nwl}8k5FJt$RMd zbVohe2aKKH8%DR?1kC$}YT66zX*@oQ0=~!VU~B=VkkMByj4RY9^^WI48bpi<`IuP5 z#+^dBx>3rrYFqVU2gfBjd=72E<*L~t>7LCwEcT4eo1M~mu~|OA9~WfVMP)yVjNWY6 z0V8xa1?B&6Aa53IgFyjyeW>@^5H{QO*6$(^F+QgklVhE8usQF}0rKP?3(y+?Ni@;idq5jECT5s(Xmp2ipEZ9@t$lt!K#syrQ7xRZp7;Mi_NM9UQbiS5mOB24Q}OnH-e; zz50g)(0K45^S#ZI=2h6L_Kny>7|Ht8a;B6HFE0{ z3Uy4QiIjwV5{W3!c*wOcm^yf{tMfmg>yi;1`?I#jJTZ_rcw}y8{>_6gzW7w-0C6rb*2Y#A;1lpG zjvkS^aquQzM84bfzBx4KAqOzZZxm5>H^_zq);@L>I^*b2lTTp!s_4dzb3nPi+TeJy z7PTzWG`}bXy7#d1zEn0_0rc&n#DnrwLb;M~D_3b=BniY^~_`8 z`we8?KlyQ+T%fh{hVp)!Cs?w!=ocv9wj_cHe~gm`z)F|DXH2dSViYPAPgdL|rFW$n zS`q881#O-?0Jy&r6wB?LV8Z2_oU0x<$22j~XEsrXsOKDH-pQ|=HCvNMZOyMQL0QGZ z*|)>9^3}9@mL6#J+Gg1RH|){2s^yKeFyNkhP+H{YCD=SIdS-Lo%I``_|DT_~U-VAI zSdnp?$uZuWL( z&^c>+iei=?I$?bvh+Kidj*;M>|5i8Eo4={fq8F4m6=21tYS^%;$|BYeLE zaWls9dWeOJeJnyat1A*Qtw&#OjMx7GIODnviC;@N4Ni^*l0|1uYZ$Mi>Uw8XX@dt! zvs3K|2mJo!ht}eTilJSb!saaKrBa@1q^a(j7By~ zaDipLS%878hLO&wEyl3~Cs`-OiEwCVSZ5)GfELK%k0}@yFyD+Jx`cAYmX2eq*TqnV4n0paWxLUN8sz|3|9&f)RIkw)?= z+t(kRLns=neW=OAs$mG(C}}p(%Z$T*og#pbnS$(LE;a(q9HEl+x<#n&Za2roVf1F4`ME+Ue$HE!9M176Dre9cG*>-n=(LXd@ zV*CyO&#v;!YyB3jc$SD!oJffZ`FDqx>2P@6YpQvPGV^90w7IPMM5`2kZH)Q$+yUF4 zLG)8+xZI3SPjs);z-HSD<5O0D%o%<_)*pvI;;cH`$G)2aVo5?wui$)+wHsJI0kq#s zt%Z$HA`Rw5cK|5NyA-4|-(mwwbPtDEo+*(Z-s;R2LL#x;3x)YD3RA}!z!LrQA@Yle z&=;#7?wv3bV?oZEUg}poGniFNgSj1cJz#efH?ZLhEPKWRym4yy21F^rzHapB$($9s z^oTN181JXrGB^tDME9(QAga&8_V$ajbSnl|byv0XF?tLqy2q=_B6LL5saVsKyn9eG z1{gmv$nQ0=v~YH?)DgXaME7EK*$Vx7L|L$=mwDidvBbQIW&SvG^=Yi_uBvucaWyd? zWlwDX3`updKbvznh9eK`FS!Z6A*}TD)#Q-$NgU_7588jGzPN&qtqAsZL=`(CQ#fv= zKlF@3D)tvjYRB$rj%b*864&lH>~0xMJTAB7vKNhkbL9@_)NJ+SRc;p%nQWO8F23ph zMkJ_L9*1F|8-QLtD0utNek9X`**#PnyW}xl@=Ap83e@RuKxoMuvo_3>bi+o<-@SND zN3T^jqInwJQTUQxQFf!KBUEhiM4t^FZo(Vx9+_CFQ|_3!F{N_<&eh!U>HQ`jk=$`c zcTJRhGWCm?ZOl;pt+Kx3-b^cA(?1tCr5+YKl=vn5=x-o`@5%!X-z|B211lZ7Dnr)R z7IPS;tiM(LEaA+ZVf9uVoRUF9rO)1qxS>;~r}}8&m}(1iol9ZAIVNxJXmjqagDSg} z1cu9fMqk7#VDzJF_&c6BL%*@6Q(k9P=;Q5>x%br{FuSR9LEaV(C- zu{iFPV?jXiPszXCg@_~)xVy-;>-d~-#Y48an{Z8%pI50FBCN@`zp`z0TM zP5}El{S8I`{Cdfa+@b!~`S52~NE+@zp&h4RH&NeJsePL@Bh~KOxrw5QyGI5#pX0zr z_P~a(=kDJ2IY8P&%)aI_{YIGTEtEaAdjoR7l$#e@mt5p(NY&Uo441i%>$$-j!A;!4 zy|{hCQEVdiZSG$G`F(VX|I6cl|N4L2|0?=h;TwPa{%e1`;lZYFuKj#{fL40+_A}z- zTF;$(udk&)zdCvo76vL_vGQ|CFFtHe{Z7CdTZ`*|ta;F1&X@n8+~)!g0`~@RQH_0n z31}1a!=sjsNtr34MtJ#B1T!RSDv!z^dTs6M6oLuoo7kB#zU2m4@Sb8SYtGIsbJaxA^~;&94j25J8*LKsct>tc=auI;%14j;7BcPQxl1k-?bYa zD|&wZ!?kj3l{LDtUBg-)o9Z3=0#1>_EC1URviVj*ZcA3XP;<4SaecKILo+snqULPR zx4HDF+b5OoG_h+)2E|%}Z3)v*X~Js`p?DR9XyOoZU9apkhNqey*O$Z?n&oDpg^KMn zr!avzds`CIjlTNzHL-^-Lyn&6y@m3_-TXjw)m-5`me5(?OyCbecH90szo-OTVqvc zKZTo4<>_QFKkxMlJZd&_E?UcRoWf=2<2#H*Xy%9AE4ScIe(W);)cfllRmVy<3G|lT z;PrYd$y>NRRY|H95@=t;i3_k$sT{6ZZ|AB>7}mZgGS2Mwln8Fd-<>-qE+I6RyrUQA z1lfdka(+A4H77m4W<7Uq7se9uW z6zIBCEl4l~jL6%n*FO|1QO3RO(&MUHH&0oLoxB+K8c4?99pfk@gtIBP>BW&In}9mg z4g6}mnqKEexDL_bmU&`h5qvM^ya)#harCWi@z2S$EYYfJoxC@{?SoX z<^3=%(=$rm>q9vA{cHHAAp3ZjN{;#QikR}oCszeh1Fwz6MbLu84R*IM! zZnb1hG|xgH2-x`W|L$*n{Qpz!5GYPvt)&=byqT8UXpfJzOZJIH*4ZJ~-x0)Em0H#| zTt0=DSXR$^RnHX0YFT@>#`SJ^b6dTg1jm*}oEwn%1~CmtZedSi-$A)fc{k;|-fz5r zd2b+hkv(J-MlYxE0&nsScH=;f<_6xDPRQa(Ajic)+$2bbbe34suj^M$El8I9RZFxi zE42pe_S5e9jITS^@lNx6ukts}ao#;2Mkl4n#zK61_(XUlMpm@Oc$ksl&;rs}#%Z{~ z8?i`50eJ8+N~JQ{%+<6@eEMZ%QZqZ3b5z49m9N>_tQ+N4K^0ReRZ!K{TJK9Jw+5|Q zx#inz`=eIhIvdfX=Cwg5xWT2lI`^OaDgMtL0Uk(_?F*j}Ut0Fn9)S{;wk~u;h!Yd5 z;wM@_M^Pvlwb3(DkSDz+{jd}w#Y+|GUJ@lJ5t1aiQeQ54vM0~T-z*d4V3{F5$dZg@ zQ-1IX1X%nyiXi|Xz#N^@M23>WD#sKE=yQ(YX_BGNhX{$Xr(|_xGc=JPpg`@x^f7~J z$T{4@J4=$oWGuvbyn%Nx5Th_zIeM;6ebX}tHP&fRxDQhs4P*slEy#hzue;lc8yW>2cE^W;1ixyv2OOQe}D2a@g|CGBwvs#1IDC%uemmJ}lqf z*{}Tt_w5Q@pW8lw{aKItx!?N_U+C+6r{6!CgbiWqBov{sCW;~yXK@*CqU!JX7!v34 zKu3%Ogal37OxqeZ4=#?WaLrV!7{+8`26SqvE?YY#YD%}uwOgsbwoA8$t?FG?+<14) zlka)j^PacC`v>Vneo1co)IQu7^L6{~_pSHs^=J9j{&xRr|IdMQfmefh!TW-5hGvE= zp{=1WLkpp;aDJEwr^0K)JHsD^7bD;ZJ0gn=Mb<{1kIsuC(L{7Kx-~l4pxKaU_%8M^ zwkdWn_Bjs3tK!CZJiaWxH-5NLtI^fi)A&N;$)>|iwM|e{W79~}uBH#0W}0>q1qo5Y zkw_)R63-_NB|av$oBwG3h13zJta7!O!uWn(`(Zk(p%H7q~A(UrH9j>)641Kt+QH- zTScwf)|mT*5jbRAfD#MM#J=Z?cNY+uAq%i~5%zzZjbDHMPCd`53*WywbEcES(W|9wUMoz@}0EZ3Xv{0pXdQ}sPRHy0_A8WKt>@EgGwF{wx<3rdv9;N zg8HG?E-1^n&YC*o80&TdLWkLYSgh)GbQ`Y^7sh%i3}S7DWwB=AY$)|;M4Jghn-Rd? zgRlq}a1u_|SR8rvfKCPH7K2|_jEy%4VveO02`UtoPK`HeEK^n?Nh9A%Ji=Af8d@*> z%ncGHv5x4bFfCFDM6|;?chANa=YG1s(a3d1Tksoo3iFp*I<5;}Eml{~D+;ME7R@AZ zV-xti<)S=#u5v4tDgJJ62cJ9S&VcIJBOS7b?P6<8UoOiZObaMN`nUCV&p zlbun7Sn$#G%V|h|zLNYFA{V5A^v<;gH-C|mu}?)AK|j-jvk(y;79YqYb|qEc6#Jx* zaGeb~jQS!~>ybpCwWU)_z$T(|4NxjB2{GnJ2I4eL*jlVM(CoFfTL#K?>-Ez1LY{+} zd|bBe&90fh=LVhS?`+qyBPs{m!W$dvadSS~HZ2L-6%y31OL#gmn>*q>mVx@-sq@Mn zY-?xu4oCB;G8gS4YL%l_# zx@xTAz&f7bR5vML?3oLT-;U>qDs^m^qMKz|Xod?tFWu3d3s4a^vt6Hjn1=h9&-%WO z;?|IcLZ(n?g)7&I&cP}F4m;`xoz-$cq+2DG2JGX9LaiPEUENLLV zh!txdvoqe8Qm#NCB7PS=+51y7fcq=>ZY8!WVE)3b6`+AuJ&}fiWS7TV2l}_ls;_Mb z{%tcpczb&eCb}4$TRor)>tfvsi?L3^QY$E9lmX?)uh9*@oUA_}wYiG)N`u-|9ke@6t=Ij4o`oxZQUU~H*G7IsV84xQ`8I|k* zSk=4V-f%8{UPR~20i{pn(~hXP#Em5A7=t{*NXmb$X+D!)e1ia$3PT2mI|}J9{nLRZ z=k3=7z%V;=asAs95L~&j?4^r|Nb7Ah1Xr;j_p%7@gipW)HPgnW9-idP754N?LB9d$ zp?yRf$lFl7`}f`a%J|thXFZ{DAM{*rNjWq4?37-QqH9cyLc`504Mqs~g%p%e4uDbI#tK!0EFt-ID2Qa^ z6%@;)=Pa(n>ckD|(vP<5u4gbB3wj3-zcPPs=l!BL7251#dPVg*x^O|P`(Y3cfohgR zmd*QC-g){?xc(Zn;D}|t{_HT-W2$b$VRJJawDiC%!VNeN=Lc63mc!{(NkUyw#%fzD z@++5)jl_cPVLBzbbXOb~K@ZWQ>9ZD3b63Q8!`tl*^_4PO^D`jeZw64jQBi#vqAOKw z#bze6I^Dc!Q)5DIwj~lpe&wQFo7`)dV=gR(-_q_ER6sqVvm9hjO!-)5aC1Q9{+xZR z7HGrKrP3hscc+Z|JXa+lBdB7kL>==6WV^5zrR$ND9R+JjRfajHtGWdPo0+lp*3g)F zE;9$NS>lCAX6Sz2D0~Z0x##TeDl`rQ#hXlaaW?_nj9Xmec{w>+COw(-RPV_BZb7zb zvrybEY#ldC=mnJxUSjK9Nx0bn8Iw}<6&4p<&{{vBkuuND^I16X5 zSnf#5R6U5zv8J1^N-;W97NNDea~rYx=^W#x+b5K<)f5P#DNET z<9kDEU(EF!#=;naqcqpmU|`ki>&yn4wx6laxA8fS$QL&eNcS4e*u8I20zx)u^3Ct9!-PPhR#e44RFTYhW5 zW~J#$CLD{ywZlGSqVZgAJ(P19Sf3H6!3uWh`M3eZNCP%Ct-h;jDSQHW*it3d3skqk z>2|Vi)*93aQ)N*Y_h!PZ9cE{Zkl#xXx6I_JYEH2HoQWkqzFt{A<0j68lU8M;S)7Qm zZe|muns)4(~%EAfJRau0e^~naU25ENR&6Q(II=seteSKhB1Qg=n@Nc~lJ9mc88zMJ;`P$&y7DA{o_)sV@*}YY=_x zs>LE-*t8N20ec+{2V4B&UB_iaoQgBQFr7F!FtTm;FI83;$O>fuc@l|!g2+~MvOS;> zyy#tXPaK~%h(U3L0-079^p&uSpr&kl zwm3-#5_L~+AZxT>))F}&w@($fqJ-z3=x-5RYUxr~QLjf>0E(}afEyWmZ*Z=ZUR@dd2^VLW~aj6EzDC@R>5xN~Q!l<&XLRHSgSr>Y)iAg59O zF0~RYV18)auYs^l&9BlKZmH4Zv_d&e* zdE?aJThJ`}%hLWb#K$`&%AdfM-z-i3R!{!Y_kmzG=^Tl7JRGF4XB&oAR@Q&sOSkcw zaDJ?5m<&Ic%CEf^%z zMS={`)A)B5)QmyoFuy*^m*NW_(=^Bo@!(UK=H_R@r%$F*0H;G3bcwK6O`*lZSw8@U z?>$}E66+|8$65~a;Y*;@G(JFtfK+-qdT`J63$I*)Ci$}XBKH|V5}op9`u-NL?aFts z(3392w^y$r!(`YbHBvolm?FTgHF#hkX1PN?)HQ;XkAwoiL0VFZRb$>$S%x+_1XpK3 z4h_&CZ^Il;?2K-fn`fhj4bs4Z1R{{$-PV;(YStWpw%oSSHuGG5&J#|DEZiU+d_AT-g%&THXJtVxf8$5Z+rs_eV!;^s!X3|1KV z8x@otTI^!>csmSFy0E{!XI+a!rykHVM+aic3In>C1{V#%M-%J#Tj(}J!z8943F|O? zxiZ4d4BUac_Tfbj&wN!db(7NpPRw$~Gebq<;h|42>qv?srW`p{^O_=u=rbQ3G9*Dt zR_5LLmS|ec1hG#;cAr)REn#=z(1EXD=_k4AvMMKLLmE3A!x8g&@k0-}v~VSIna=0d zgNhoBdOR*gZ8paQwZ`FF>R?Lb!{65IV*%F68X|2=J7?=+y}@*mV%_|bW+MV(&dqHA zLJ8`8S+R7Oj9g}^(QQ8iC?qXOjN?h3A*QlgP4#NEpve|X<1yWY|{v0~=e8AB0FE~@GI0SJ+k9TwG;1LBdfX{Z=)eNhY<2vV{%Qv_c}-^lceShD|X{J zw(Mv~V<%4BuVBJ&KRtW0xD;LiR!R?(h4QKT{<_x2gK766$=T5Ag8Qb0O%N)>=4+@DR0P>)6Qjo$mjFmF0r_$c(lnLHOnXbISUsK z43ToC*CeiT-DXD-G(R`6$F*JL9;51#WY7lf&SaueA$ne&N~dk-5rr5H2;Qri*;e*} z6Let@*}H4JX(bn1U>PE_sdx`!4^Sl;Bod0y@Uxm;%@c;W_Qad#97$}Btf{U45p4Ik$R zGj>qTt~RR>$qiu1%F!Jx)y+kdFR`3#dDBN$m?UwKwh}OHnxT8vIQSp$*;C@_?^(;J zfm3kNwUTWel?R7PCq;5>8%CD8xVV%OG%*eAXVSp&(JryPHn=1Xka~l<<<=k>lWrH% zx&l=uj-ImuC|(Dot_`ik)5nTOHf(dP`Qt<&K&NMS!d0;xaLshO zwZSc7_h}NQO68`a7GD*fu0XZAGF3vuW9iPpKj^4?DyWGocpwZY z(nL8|&ynZ^6;b6)tI0h|S}}w{vsdfvf@Xy|{ZdgGp82UVH=a`U1>2nTYDt>Ze86To z(6$>mvzb5pUZPFfl3?mS`b-{Smj|c(aO{$tFd_2~-T6z)S3;NQes{mcugK9S@b`gs z6tjpMR1I0y;47koVLne8yAUKz03~{fz!VK!Ir^`dKID85-qAtBk)Dlxx16j7ZaUKx zakwju?@dIbP5NnPOasSd=Yg{oylnem5B}*v>YvOCT!pLDwREG~{Ks{_&zd=iN`-?* zQDNo;NxD_fP9~wQsVuN(R$)9iNF5ba-T|C`s~}DM;DiK(Vp^loT+1*#`tQKvYFBZl z@PBO0Nlt3^y%@|%9)fhxfrE>vySI|R#iz1MD%_*MAGa$f9JEp^t0h6Ws0?fC54u^0 zMmjND%U(xYpb^}+q}XJKICMG7fvAQN|1I0l+K+jrLZps90 zUI+PgDTjvi=6_4HVP?-;Q^A|^@J@%@t%kQmQ#iiNJ---Ia0zPE<^acO)~J@b)AU=X zO`XcM5WgXv*K}_Xlc0MZ{XDr8_L_s4LJJJRuoVUR9S;Nlnhx~eas@(T0*WZdQjwq7 zb9?URqHU`eyuPyD^13-;*yneG0<9;MN_&H19U((MoW7PxFWl( z>*zB8Mdn!re|{je+65l~3lusM?aqlopGWBt=r}z=*G3WL^sjwPF6CTV>mVha<#(E1 zV>;XByVYLL0iUh4(E_1VH9s%IhD}l=2x&>z(>M3M7xqqR2ndZJfpG}r%5z=*LAvS2 z@z%j@v;2V^P<`p4VmpB7A9VUu2GeGPXsa2nc%$X|lQViP!_ZrFMnm z%WwkDEoxcuO^wsSq?j&bD~bC-GXS3EiAQ{!kM|Y&|7RcU8}XxeHJcE9rxD*2wWZL znv7V7nD5e#%lzn4ky)F%WRvT?R;dI9+OHt z>F+#hF*E5at<5L?9A?xmt!x@Lc6d|aQ(%mXfZkOy<(UdMXyzOHcFqUIZ6&v1u(@g% zJYI&4)i&jY6yCNju64?T!_ecJvoLR~LAyt4ck>z>F6eA`#XC4~JNa7eU2{M`(xgJ4 zKVn2yk%b<((R0@L=}0&n%LVG8#p)(%3zo+jL1T9)CmB+dRFHNZ4|F4NWe)-4wgbeifIqyVl6uywj|t%-2q zt!4H+g;S|lca`Q$z=LEeuIYpJ5{%CJz6I98fIFhjhMjjp!JyaUKwVYK zZYR9KpwI6wnKo_5?MlFExVU4gj&6)+ITvvaX8XZ4>tct_5xcC^DHEGOdPEmtn38P7 zktNfl&+SpMWW!+#p=O-nPp%g`7?O|3w3DYwv$kMlhP0qKRbgC?hv+JfZ8x7TLQyQX zmXTXWedY4GJ@4Q@xH){kS~=x=TXrr~Qw3GVY0`ER_~Ii&*y!u)?D<5G#o05x#2z}pcV@^w*z?#?k|<=SS{_|Lz5@2GRA-}di`}~ z&;9KOt{Zh`?r=@ciqLf(@0(fjuvt597B>P&T^8FI#_gO6*vdeMrd_Q+wp3TJ^ZyP; z%}a}*yT}cwt@s9A=Omk9loq>51Bprn&3MbJ&Jt|W?iFF@*9@e%kj|1MB<`k0H@g)g zR@gJg8uUNMs*2jS;R!6wH6V26Se%qqG9mOu34x^{oxGF5(4<7OI3aVr7K_kHEwCFK<1hy%K{a3XERqtO z$5ER4N*^{D7Z&Q}yyq=srE{*tIHG6&2X5nariJ-*Ob6eW?T=1)sl2hMz?TonJp~7 zyb@*y%Tf%D_i;M>{+7YfNSg;^B=e$b^rXvW4xI4Oy?obo?!G}P_jQH_2xS`O(MOYX;>5%)y_#o9g31Rw4qtPI3lyrB4BB^1Bm zTjtVza`rVcn31gZaHRJzE6=S2_lZx&8^1Vak;PhBgqEc^_w#IWSgp4dCL=+ zS>=YaUWO)ZCkK>6l`*CY=qk4Rwq1JPdB_kA9%3)sK0Bs4U3k(}iaEMB7PV|pTjR#J zY2eG)`AM1z@KQyn*7MENI?sHU(vd3jg>Ba+5L4!n0&gqE0P{>O)uj~9ic00_{jgIo zf>@ZQGf(Bt+Hd2!I_12d+Hmycqi5J(M)9>vs9an*={9f?DpubbrJk6V)pSb?U^6-!a@ZbpOPXpT4HW9ut z8gt?)k3I01${EA}-xSzIx958|4ws*bB&!P$45~(X#Ik0Be#lXFnh+6b+oG7;R-;JlNe7HNUROy+uuu z$g%kz`|;PC8wdp0r+Su`O;a`rWZt|(UC~LN@jzg}lwlA%+z?us^}e)bP1&apmpSse z=-`9Sx&O*b;9XQ1uc+RSPNW`ZX5*`i*FVxR1f1}Iq07|7APQTE9VO$xL5aXwE%KCF z#Bn}q)I+&#th%na%ax%Mbjo0H?04UFB&Hk=_5$Z%pyS-E3r~4H7g5-ETF#kv*x&71 zC{#N@lv{;1Js#ntD7=F>~O`D7Ak2|gG8`cU}e|!xMs~|#)K~D z&CNNkJ1EX+S!KzK^ky>?0}>w69IW&Nuknf*qD|NlMUkG|SOLVYD;AJ{swZTNzt z65J@?Q36v{gnUzhnOPHkU>gOADhO+k3`-RJXhnqU3^Cme($*r}8pnnk(_7@Y62RIg z9^B5Vi};?Fv+iZnwgnZqJWGXuwh{O{cV2V3Pkr|32(Tl&ij;^)Ifs!x`KAq;*(x|A6I0xly|AtaRfvK?8YOT)ZbJHu9Rr}+LIDR{m4!n1 z3EkFE4s}qMY#|?o!>w*QYss~!Ck%qtz1491yoiEfY~-vJg&lZJt9KHoFzFd_3meEP z$RBo&T}ceCm&*> zc2X1NXUIA2{A5pGU-12Xy?x-HlT*_-HA#H`D**a4QSB>}U;tI(Do^Nc@wH0Vax>ToJo168(0>t&~I=IzpsbPBaoRC+xPke=q40p`&e)mT7ZJN#m!J zyrmEQLLu^Rl4O{Ap>SHp|EP86mMic?tP~>bX1s1O(f3)o>l|wnY$epgNODA=XCZdZ zO;lWHka8p%|PGNAf9W z!ijqP^|bPS4KG)Km&@|=E?$Qyc_nt_velrK9hx6&xnG4qJU+>HNf7$7?jOu~HySLf zgLg=l)RnN~(Cmfp{$+5ZX3NkKDVKg?1R`M(HJ?x|FR#jxqS&2cK~5EWaAx_g@h%J6 zk3}&mPfrMjSI?Bg@)KsOt~uPGl9GZ|<0G><7g=v_n)LPeFa4^Jg!jlgahA$~!jv`4RD*L~ys&hGRZPzJ*u8-E4}?7TH~X=9on zTowKoW*Vv~&744)>v$s_bd%M+C{N{gdQ_q->yhnJJVQ;4ui(Q3qpvj|Hyq3I{5%o* zA#3NOy@vgf6)5a|Sk~dIEW2Jo>%sv@(sudE31c7m!2_tdwybQa;PG% zC`QbFmy-~|CPy}{*zFCb_GtTvf@~aDb94c>XOY5gj(JPk{4{+|* zd*fQ~Dh+x40rQUS7$R~ihtV|hlu2^8R)jEtk^hFLa(}wQ0}asV)3NCr!i@uW-^cOl zjVpp)XPec-yEleD$MAn^>Enep3%jJKcZ@baO9N$uf2|{$OBc^!ip7Q5pqv-_JND_+ zojsR3tir=Lm9IC5)JZ3gNjBFpGqoEG+(Yx`6$Y+2S^zC-tm_{xzP(hV%&C=juitPD z=Z5{aS5b8{heZQKH&X8MO?E zPi_E5teF^YC0Dhyd;7+#%-OuNTIDU4+}*u%gIq+iP~pOAZ3=rVHqu1#aM>8nU6=g` zhvA$x6I5F)7dGnkbUthA`qMW!PbW@rF64q5P#T6a{~*a?jao`l6#MP9u)KWqop=r0 zyY7ZQfV5y`K<+tj6LUjZGsUGV!T-Kof36nfq$9(Td29C{c@l3kU?y@zJ8>5yQqThf zXJb}X7&pAdH)&;)Bd6o>iAa}D`L`K_|Nq`2?hOUuaSRwZBauvZ%uHm+xokZt5k;#8 zy!a@r0@Ev&Br|TPgTYCbOjbzHhGbV=edY{rt}Z zqRs^L5p_(esJVY|(>}N*(OQSOh5CGPva;Y4@QK2cHd`&-wgO|eqr!>Ci?Q5dH1$=L zgn4LwiRw5W2EOmwR$JH9mg45mx=4~0%`hD|ll!eW3n#UNE1{|BnG{N!rnwdMEJaUH zTk#t6iw=rq9`cY=?v|Xglh~!;m~+eFH@DXh%AtkM*ru+jhWW_EU9HuE=AM6WxsJ{< zv?&CtVFc-yxEwzPzzF_JA>*c8SbPixP@v|h^akHuX5@(Ey(x^yfJ(h`DZQn=wYc^0 zid-~5tncd+P6q-JA5OM|n|qOu{~F7K^c}dzd_fu1zM;uF@rS3lyOf`aqZ#fG=|+oQ z;~^nkUuEFoKzZ@2!oUQM+ZTUIzx^+7N%_Hcc8dAU2jV?VCC{mUK-wX--=&}eD(<+9 zSFaw#QPb|S-4DZ3yW?`Nd@7Eorky|ZOkGShub~etuDA$hu&Zg%{d7w%znon7q}c?? zQ6kgaKgd+YopGLv^PgbezZ{DJPjO$={ps#fm_Wcu+)ppsUgPS(_mlHF9f%HUo65+0 zt)eD;pU8VG(QTTq|M6)~ee%zbSIMz|gF4aRTf)x0=Hpvk$HAApiPBku6I(5XxE1sz zJ5qRx$P^@~VErh~K0>v;G#C0sqkmwZ&HT9wnWH*U+3I;)DlifBc*_IHP)B7v(hJ=x zbTchFJsS>F?MbG73%!}T1~PNkBxz2oV+x-=0ok(Y88a@bx50t$L-&-B=TooTu7J?1 z=gz}u;>yU}%Bop$9PTo2WBEtMvoHl(38jjFU|uIEeDC&chZTWjo$j&G3a1_ROwi&m zWi=5RXP5V&jYP^h0fYEe6!%0T3N^aKz1Uk}n@W16h6)&+6+56@YstrBVQ-7Tj;ufj zWi8dPF|r|Ld0|*B$)t0Yh*`j_tz*h;9&u15tMKaaN4rU_QwH1HJ3<;@J2ocHEh*#S zj#lh9WeM?2kmE47f?Oq(?ZC372-h6)#rQa>=jDAV`XQT8e$CDTZA(O=ye^Q?u#~M~ zTfymE?aZrx^i(#!@!`(93MdoBle7;Pf~HQi?*r63cTNY#H5f=FBBiUI|CWq+pMn&> zC6t@4M*8lzfYXx{>*`9v4Q$GtSP@MJvOSHO6w)+H!bhLAbjuRU_#LoQT(+Wv>Hee>aEOuq@sn<-FD zQ+eV)J3{fGdn>=`PK}Q4D3=XH|E1dxvEN3;)vF*1?1z>GMa`SXk)7pN!;MO%ERG!e zpe7csRzBfDKyT5h)#+K655k2D;vT;y#e(f_wwZZ){CC98#c!Ol$!EGbJDYsp%sGG0 z1^&_K+vR_(P3g!!s(eBq%YaZskYafg6HZMb4sD7EH?S|(ClCU9X6M@L`oCWB4wwFtIi zUh7Oe$F?2?elFbKMidasF~b5RAw+y_1s<%w==#8-I^DXJf@i#OHsyM>SH`tg@CNR} z+D%xKbUI}!f_=z5*>IdvAbL(EGo=@p&{mj8R-NXdUu;3l9~~eFVs6gYyB3ML*P6VjI@rV=u+OOS> z@Y{If)T_USAvOs8b|YvsH%~j?@Oh`-6ax;|TLJkR$iI9bJTSBxgX`TzcF_l*cqZEf z|LfjQVv3@r0B!|EmVvR$A9*hqVW)yuDu<6{{_^^znr1!&;M(vT3pS-Ae&SFw0*z9X zGXK+Orz>md_4PMvdGwHeOngXzc438QZ=mSq)~2@QDh;Q}+OEieG3bMzIA z+O8vkES9owLcFAC)N0uYYuH<-?wWpIjZD3qvWhC7Z0W$V95J)~!!)q7tD$lcA>d}XOT9R| zzFpI*h6#dV1`{kC%~z4FQ@7V{7$5MYPlYd^{wSa*@~4Z}00nPf0JI8-O#?&H;Uiv+ zB!~;1PbcF;-5XG>tE#MxuY~8q%N`U58@0cfD09$&95?AV!{}d@58jXdjL% z%E(q@HTIZE=mS)P@AbEijDNdQ;O72Yc8Y#uIqNWcL$HY=rbAS1BmxvoXwaZ)L?XDb z2@6HY|NQkEwZKmc*>l!@t@&>10yd>IoQ7b00BW5(CuZ0DnzyRCRGg-Bd1e$Z4i>&0 z=nzj1t`3At?Uu#+VDw`V03wv2Hbc`aS()sZDt2|{=Gu)goHr#z);#Q_8)fXVn`*aN zT-l`KY}9uqwU954Nqw@n_lomO_DL`g?{Fq_VZ1TiIMH%#G_bp(H`VTc>Y0uivNK)Z z{6c)XQ2k6O#;z8sajb$9H+0;3NqF8u6YtCDjV0(i_B?EQ_Rwzgm;5LFl}##rWLvMDeASzo0X`zF*FEpV zMyLkzmS!@EXT5a<@l9`Nyi0xFiwB*09BE}_=G5Y4p%Pu#qHoumW)j`>?Q>ubyXySw zgMv`q+u1yDCl|-umGjQqIw%||f;5CARw1M0JpwLt9ZJ-@q)@7uMOfMtE<&1 zkAOIQv$a3t9jwX7`Vte!14AE%-0Vx0>7S1@k47pD%w{vHX(&HrayE|#DT$)( z2p-Yzd#5wqXLJ z-}&ay$#NTce(||GQ>rbgzF_`~xCdKrp+P%EHy1qc-w-;?znIF!2krPe4ZuON(A{zo zIdWY-+~4}=$W>!Yzu8>(UqN$af39I(FpCMVewb|L^D_C#-t$jq{ik%y5ARE0WU3qL zhwQQlW+dR!50RZV!u`}R4e_FeB4>qMx_58My+Lh8|4*Fme7ZYL_eGFZ%U)g(bz%>+ z$fV+EISez;`?2B|(eoX+j4ytPtN9NMK!Aczbxz(ny%kpTmYctNM?dJlW3D!c!WG|L zb3X~}b!OG=Q^$#cn(bt4qa01w!|-I0^ogD1qQ0&Wc;|0HJ_vy0vLdJUN~~gaX3EZH zrs?OoBqOY~HV$j;9+CPrhAcG#2o6Iw7V^UxS zn%|(#f%Y$#+r-KLJYprg_zmg+{X2_nW8`|92*$`huILekJQe+)|H{E|@%GVeDOg>N zLn)MN$DEK#7WgMt{mx9*A+u^|`CZGl6Z?&ZZRN5sJsxmDjZHY7S_sdCSf{*@Jj6>+ zZ6x3Q5O7uAcp`T!*J=a5^6vWS~dFX*fN+r1*pWOu1ny7*4}@P5l3_oSby1=H+mbDV}h+&e|6Z!Ya-V zmv29k0!$bi1R*|mTYI4S2yGAj+tTTezp=8PSgTFg?JJDMlN{ruX|z6{<-hV=c)dc-ZSDuj( z@CMw3w+$YZ_o%?FYqF#YR4J!bIo7plb22l9CYp1`g_hMe?XPt+TPSB&GBSv=?xPL0 z5LR576l;7$u|a<}1(PI8AGAynD+-}bG0Ced>dH~jH%|m8-HZuc7%vgbzo@)qr?I5y zl943-HFGcT~0LRwTi9X zX6D-*C0Z4{(9%DdXvS97CM359?I;sw9b1qor<$FJ2KY~tK-GhlwIFpo1|oiJ(k?~= zsz}rq))1hNzJjd4H;saTIijDI)`|i562HA1V*hjdfe;?pNY)fgg|X{uUD{CNRuft{ zzck-h^NQcZgvym^A=CW%1;BT~{P|fg(r0ud@Zl&NEuE>+6)NqxKJ;{|%<1~PwoA!~ zTr(@+5B5$AfQZZ4snlT2J~8d)QJ9g^*$PEV2#78A%H{1DK|^9&WFpt=9M8>vcj`Lv z#k4E#T3&O;mMp0SU_UOmG)kr+M21`KLE_(>kZPI zX?W#u`EgmQgDO;(%#Kpjg=j`Au|q|1Qz|pSBkdd~X;o}%fcOg9!*hNoSZ)^a$v8rk zV;P@})^4nKNGUsE-)q+7rDyxZg$J8B3l{2}bizyIS%0omPo&}4aolaiKx7kd@@-YQ z+%^uvM=#cm7V&JWwDU0T5tSs4#F{j`W~Fgs)R<|EZ2}1Rxz(XA-m%T<=Cii61Fd#g zeh)wg`TxIz2YhEfHDl!&a2~*O-$6nT^ib!D9_i{0$~p2fwFHwc@j5lnCm~rT>%1Lx z(f9PI4+*4@1gmzdur@5NG^iHGbrNrQThh}~rZ&*g*XA7DR5ag9>T~2S^}E%4S@w+7Naq zf0kZj8mGDIJ?;|Il&o{S7WKwe8J1bmC~<5mD>uoU+=X1c8I2layFG-RRzL^xHe+Tf zRT(D=0l#(Zx>ZrLJU;DLu^mNh*{H!lw2jgU(|Hu=wv>?&>9y&!Mw3~rPEdi_*f%-h zT&r|4qB$o_`FK=SQUoIIB@?B79nJ@9h?u1GWU7RM)>r0mgx}FFxIOayb_WAH*cQ|k zPSWI#S(F1;5J0{Me3X~w!mz`hH9pzXTdrQaDW)j1crg$FN(hHF>?!>0b0@mzy1+Y~ zqf3@`*p}-`6h|6kIA({kY^5yM=D>0$RleaQee8)=VLDNhtNScOm@I)nOR;ujyd85i zvxN#oHx2>6J95%RA=61Uj!(SBKopBM1$K136;H&5qKKs&$B-z)TYK4-K%lvgO}k{} z(=b&QXvLVUJQG*QTqzm`+9|t~NHW^NrZKe#sED_t-jy0FvA_)-x6;6lih^|Jzf`15 z2K6ht>{0XRy@K7>^x-}#<_u%U8Y|7OWV1YmU!F^Wi<7&mt zJO4sfryI}`_+mUphIN5vm|kn=y`Bwl6*ypzSQ>EYgn9IPARc_n!Yx(w> z0;9B4Ks~sUATxKV3EQoJ!?%@#*0S^pJ^ep*Gx)8H)a$a>e^ zZ4c{26%Wm}{J=koPppNq?wOL6T5;vnSuZR>Nbe9wg_>jxG>XsHlDH_9B<)Z2ACC+# zd-E!71!0QvIMB5v*A&T?|FSgO?~ZaOBhix$1kSQC6{2of6X#golnL+4NmHM$Xm$pD zW!xR^l@jatxU2z;h~@a4lX&Fl1+JLV+HYjvSu!>lv=Mf6ZTuN70f`jQR@|a(yXk;c zZcNaAI9?QbbO$5mPyOV9A}0MgmBx#2=I-?P*|+JQHX&*}PN4y~{qn3(iP? zZzs?*%~vFKdOPc1+FJ_%ICv99bvH(qh}SYYS5$9CSk^%}VP-Y&G#(p|yhT^3*v0`f zL>=i5+1*gl!5pLyqq7LupC7?5NxrP3{J?E%pYf-x6z|A-C#5qlRsEQkH+&UkyD_8o zwu)w)qzLQ~^Y%`K^_=i3xCOWD6H20h-kTOiONl0uL(hw&#R)MsRZ0hKBODp3x~k|| zI2i`XEO^3=RvHlEgmHl}@DkjQN1$vgI#HHee{e$VNHm~Q;YQ^Y4ce`xU`jKoE-b`H zHj9(I#Z;x$Y%qg?2ll9ZNb`ERj0;eq4D2n2(!2Eu`k+|)3Y<7XsaR+w!g_Pb32S5> z7K={nHf%Ev8=50@+C&k9NMm*>PL#6#BiGCgX#$vCFIO>q2tH)@?bH;mNo}wnH6ivY zDTN&xCpf3ns=<)@vf*?~lyB4BoF2A0)4?U{r+E6i!%ivSV^P&h2)CcuWJ3J!9>alz2&rG;5faC0mNH30!kLd4UkAOu($ z4{QSxm&mBs;v_qQlibtwXTJ`GU(pt$?4i0AQhwWZSWGi_DF|^E9Y(W2&TASMD`lGM z#-uHP+yc)R@ohVtlol#40fPd~$o^*U=fv3BeNctaxH%RoAt%F#cU%n8GyxvX%2)no|;xxsYgdPXVqFcO|1T z6+HX2nxJ?fNP%W48R--qAgXS+FIVN<*lrWj70t;IKZA>07X~I%%-rgJ6t8#AB9_#DnrN=TihOTd1 zPu)9YcKFILe7(?x1zpl?(Gu|(SUB{mKH(|)^gfi)u53dhg7^j`_*4mW)BZ&xpuqox z`g70}!9Lh;iN+l3TvU@}d`;GZKC@+rEXMG#1_dHz-KY{Z*tK)heV18rD#uQQ)%nh3 zFFsmc`GFY>L-0VPtQz$VYLa``T&Sgb)UeCx*=c|)wdsOhnOZ)MJMa9&);Kf#l=e(S zN&;a-d<4ETBPGE>M<^#9S_B_`gTnM<=sjqo9~7s>BWC6xEl07WG?>h?=@?7i22H%M z%t4ZQP|h4^@?6r?BF<7c zQ}}LSGIo=$P9RDTVyBS>Qzhh*vd*(Jc~UklvqH+NPCzMeT3*9fP&usJi#B+<;eXB+ zapQlDQHJOi8XLr~-625hr9*imP~S6pViAY;jok&vElsAQQ@cP9Xa65Jw^KjI%^~|M zMIN`*&Ds0W;q5K&X@GF`UjxudwPRWy*?+qVZ|`jV=0X_r+v?|R{Nzl5>_JU_m5dA} zP?DEiX?%R0HgPk{X&#(S9RbItsdRNmi%%KY_I;qt$iTg%CSiMbxH-GprTpZ_wtTU+ zSh!}PIG(c#;gUVSz&4->Q4%0=9RUf}J{r=I>bnBH!1$-J6rk)iX&kmzMDeQxQfc0o z3M*-hO=Jjwk%)xyJRtnf!T~5c*Tu`c0N%?jj3vV1aWYBQMNsuk{1}(wM1d*D1rJ91 zqwpci9Ye|EV}bKDE8VCoz8p3J8V4BZP*UIg0X73iyOj5Wzep(1}u?;Hyz5YGdRLt9^MMFD1$V95Jm}YSw!MYSOo;U z{dwd9xf`3p(&;?+!BnvR1SkpH&svN5_3X*n+I-+GV zUrKRID}*492SZ-RwmVwIMH8p1Gc_j#YRtOfH5y>XX?ChG49cUlHOj&@xNcGIT}5sc z&t;XVgK?hDFi~w2Cvw!s@x(GQKORW~9mqT?cmZsq6{SbEXuLu+5;@ql7gn*nIJb-! zY=j#P+a%ZpTVlcUwpZ;hf^S6NB|`iiMfhK@UAuwwfhwMz6ASDl>nQ`GWl>_vi)$w6 z4hSYN-gh=8fC`cEu;^gkB`;sw2kbqs9!G=fA!E|Z*^naWS5v~?We;f@(8Iw@gY32jkz!$R#&X7W}S87iStZdr;8)=fa0w2+r)*pDH^Bd1?TPSBs9sDG-eJxXS?!#O3Zj7j?r+* zv<*RgfePdE+r726Vd)|l`lzw^U5U$t2dK6N3tQ|KX9MTabqFvfEt{S7vl5Yv9xN3a?v>CEC3$F@$fnu7QKzLQUZu7ijWv0-Av!odBlO~=Euy5YTTv8u z2G-Sv%yenL)H}k7j;OkUT||sYVU#6@+^>4P1R0Li)@85s#P<_XKC3YIjn1>5{e zffJsuR%qEDDQDd$s*0E%J%7*zTnQwe0y3g;)8{<;U`Yf8GLjzVqp=!&b?47+{To}N z-l^^GPOpJXBid2mhpHFjBi{~z=x*~qacOM>N7-fwkQ05I*6aMr%{967JB=LT{Yp?2{ZZF|LwLneXy7<6{iC_)% zFeqiaL!Nw@o$IphQMlfvONup6f;X(Dy#}iATV;Iylo60gqpyKy_=OwLEJGf;sQ(|v z!Pi<}hyxVRe!}B5sI$w9lOMEz%eTs4R(5!29o>e(UA+2V@Eri{3guJ*-<&FhqZO~Ox`{P4!V6|))8s^4twYhsrh7!n8s zHLy101KM!XIqFShc#)_e(Cqu=6?IS#Ubh-^71xJrE}W!mkmyzd`TkHFtCc`sp&-AV zxtwOWW(gw`%)Pbr3eWrFZ%Ev1+sb&}aWMql$T*BsPnIG$Czc9rZ*2D1v4A$zUa z>Ez??brRljF?K*BUKeDbS$E``w+CCbE7|dg+OdVhIXH7YmW`3=4Q=CODpsoyjZ&x5 ztC;Jt+&h`2$zkC+y|g|nyO-)zR?>{_^Yy4;qC5snJNj~o0)OO?PO52(yQWK))l?HJ z;kXmv3$~;vG($7P@MBlfw54>DyOEZNq_=FeJSNR^-pN^%>%Dj;88)v9${92?4xm$G ziej+UUHJJ1?Bv!ugXwe;8-fUIqJfJNU1SS>73D{0=y(A^vhc1)?(~BdXzr2D#PvP{ z+Q1gGU*bjc>8f|By8SZUhlA+g*~Fxu)mkhiu$+;o-gh*`)JnStwHkpF#Fbksa7(&C zv#=aD9a_0*uJDE^>D4)B=|&$wcM>IK5w_T-?)I1tQ*{9|u4AjR5hpq+Fw(o_>6!=DhFgYzIcn5MC9Xs0b=>KED#bvH}nk7Rydw+b~wHx zuQnxFf^D?hMlWU`Eofv26+qW@!?IhhnU0kFg~nD&P=dy`y=mwo34+QK zncS>vU`R<;*4Z$~#oNT#Ko_rvX#kf$(phcqi)-`eYaN{mU{GXI)1hrY9qD(44K*!g01v5u*K{s91Bt43ESOX*4=TEyLc5{8QU(v9_r<#m_<$QmTp_3)0kNTMxg3Veim%y53W|(hPAEK`41r?~K z+hdXAglq=f;5yT9Ds@z>Ugi12k|9Nk+ct??AqaHzkR&Hr518kVk^sBG)~LTa_e%U; zh@m1vzM#>K1S!v|TE=OPIPd`ZhsUAWv^bRk$a+ocsHmFLn&aTezvovrb z$Ju?(+LVaX>{nYLwIIYS$`}n(LL>Vrbj=y2yVkdLEgLPEOYb`Eyf@m=5M`Gn`7JZW z0X2@C3&MI3Tquh5>&~<;0278G1&Fg8x^)V2*jAPtPh-}vna()LZ*yw<-wdJueE{*; zS|H>Gja~O0)C5=vl3xUucfj0-!N;#wzrxuW4mcP?yRW#a_54J66!KG0%hT%;0S>S> zW#R#z{g$Vh4;|}f2ZG@HX||+-UQ8G8Q43>dE*JBYVk`If@f75of>1_c=2D`dT5&L{ zOe55&v=s47q)={Lnv;F>u*uC;hNws;cko*wBb1D{gmP&#RocE)&zOZ=E>$iM%T{st z<#bYVCvT99U@Um;?nAsJ0TGOZB4!{`Nc16{j!KmM9+|Yd4`dv{xzTdUuB#CvEIOW= zP3#~U!4QgXNoEnvJdvw58x~o36h2eVVR^nPl8l`+bVC6r7(23v+$!KEDJuB&Nl~9u z0YAtuFMy!$WuBrw!%U~tM3n41FByumD8#)Q*zwZMILc=qDCyne1#(`A=c1#ace6~w z@|!73DF^;h^Y4J*`WzE2iUUUgZ&RU9yVR^!YNcYD1JY5dWoxUR_p38;mP5Pkx8~q_ zWX>}~rg?+LPzMQP8%1$coMs6f)dhx7P089=0wO8y^8^uHjVuQ(m&W_IrJ};Lt;1SA zIVY%>W7}e#u4xsEa(WWtht9O@K3JmW4M<9-v5OXq$12wEha`0yU!oF2FR7Q`QAf9^ za!AaT^0r}HW~jO%sE(ENzUn|7!Y(_a<1Wt>yj&(t^CZ8yH2;z=OP1nT&36%jsR^<>HnsQB@>WquvsQmvKhCMd*@@hyA_Kke9>elAp=P2Y35)vQ0} zkkxSeOhfMiT}gll{J`=z+Q`z}l~Q`T z&BUA>f3MK)dr+EI8Zyl=3E}>%ad1fg_1OO3jo>B%H!GnTRJYQM?q6RGl2lFoCo*v* zN)zKHJ0E@kKcx2y0tnuy8SuQzE*@{>zJx2vDUwf*< zrg2ZY+zeGa%q6O>96*M&Uiwl%iRH_3P6_CV!Z82*eRl4GnyX)*{oLzK=Pix$?4}y~n?dY4t@2 z+h4|qZ}5Op%pMjmo&Dr;%jJIBJF4GZI=aZpZWFXnE;jf6&ce zEsZ<_G)4d*z)mXFd7^S8`PJ0Ee{Z=^) zOpR}a-LbGxb%QlnIYvnaaX;z;#ch)c?ezTU3yYyqGHJ7RrUQ%$X<=-^AM1P==Bcdg z6V+n_Vk!b0&%wYnPl_O(sv?9va3fTNp2@9Pk9ImyFdl_& zrNMw*(F{B4j2ayuA~dATZA0_t^DvkwnC&9!j-lmYa^iK*6TO=Xr?$Z-Iv^ZH?>~Ie zQ2kXT6XapU#oC+NML6zBxKy`qT};Z0D;XVRGFGQw=wqFIda!MjZmXlA9X;nTN6)ky z{lYBozmpRwDE_)rED%~9!nj@_M`%^(5kD?O0}bkh)S!eEe}M&9zP04#ndPZC+I+3L zsCV?<7@?C25&ZBxnE4CFz!M~Vo31nE_3euA7D-3pke0oW|9B566fT=u9ed5 zYJFP9O|kK6!D;^eIvj#bC7UIiyafYSl_bh9aieVx{tB+mR{3tLKlpVL7%AXEm=cV< z2}m%{{ueB+5&LdoQ~mopd*^JtvHMs&Qs9jx64}sw!qbJ6O*$uZkXY9K|1lQd9>a~Sn!jZey{o=kY*T-MgOiHdNvLc0p zI?knP+3x#Ik+SJaB9ca)4>5hF@L*#G6Z4QBl%x&(F%y~wa}n2{rjKeGiyxn!z=2g zqZ7kt{(G7j92W$aJaf4aE~+Qt`F^VttQt=-!3`=Mu9IL4m=@w#bXM#T&|P9#Z}-Uy zk+L0Rn>I14TZt3@NHb|MdnIpejSY0bu{W+)p*E!@undD|f}i4LrzIBQu-d^|KIVqI zrSEcDa$ZZ(>p9Co@HH%yVK*nFu>earvjNYNC2XHGXVv1g-(;#PXh%;C+6N+%;znMw zLX&e}(n}AzyK+(lSb@H&RA^&%?_RXjulOscRTJ6SZ9J4LsCO$ETF63)Bz8P#0QVM`&OZN$V*@>GKpEI(`D ziH|2o=V%-_cJ`mW`5d@OoRGd&0^6fZ5^!;Bxo8GwcK&>p(OKJwGaQqd4Mah9vdo{8 zk2E#g^*!Ia+DEqIm5NzgrfpN!eKv43y^)}3mLFftv+9V|Iq_%1XO1mLW!S)Y&ct}$ z1~L*KVF`R*$6ZvE&U9o~Nr3IODs_w#LIhh3A6XpfE~`^T#FfvH&s*V1`!B7rms@w+ z2d2@hjIr1 zhby)lj;Zu`Ow?AZcv9!4qC_GcO6A0DuZr=?*i*+}UwGWC6z`h@NRw#q*-^pAzn~cr zKw~5MKA%3Ip6iqdnRe4Kp2VXg$CE)dHS`G{t{u)v(Cvcmmc$g-bFQym+gRn$0iwzX60@RO_<^(y;CI+I=G~Ini+(}a&FZzJRX{xl$!cu9f`CGcpw+uz~DOC zN9JT@kX#MX5hvGyn9hzsVZ1u#4b#Ol|9oBFBu-`?>GPd4``P8wcsYoqbe_I9K4mVt zfj+J?F>g*eYf-z`&<`9oGgX1THVDUUp&ubFCe*6?Z3QyVL$94;J*d2t3f~jPnc?VF zl19bjn&U8_S0ETRSKGD=)uR+?G2i(~UbwJmXb1wY@qZio*-?9lLTgt+wtlkCLEBpQ z&_4u<1Rb_3^#WW&$9Tteo_(A769FzQZMPBMkWu^Dc7JfoKXUw0%ctzqlmCq`69~0Tz1uE&KJQI6BVxJU zJ9}9o^x>LWzvLl3U;B14!D9D(!#*lT3DJ|ZuP%vo^{>>vhce5SKEGdi9D6ST(-zOi z#Wx%#CU0f*F2-)sg|3G}5|b;@MJX`S4EkTq&hC9CgFM@TQA|{ZRagwHcAd@pv=nOJ z%!b-Ec0%y5MzdK`w+&H86_SA54vjEDV z&*~Ml^@)iBJ?%Oz=OIA(B=f)iB%j^2&tx+Ez0>cB0P-HWgI0Q(qYwlNTPp_{Rw{EY z?%>6{$bTXPWE^Y#$UrIjES7MjV(jI3;2TmL)#Z@>S_|@)85z3w8g0(1ee0##-J2fn z^9LR1azc)r{QZH&7!ArQe*zErYMKk~q2qS7vGWg}AUB-g{>vV7HJ%v%Ah_QJiv#iqxffKJhQOq^ZnuLEnwH-Qbcd{A znXOX|D2%7N(bD}OllUD<2bQ)aSY#^FI!>0cy+{-X=Po()CY^2=Z)%qa=d^6S-U;yv zZc&0p3Q3~iOq)yeA5GT|^E@*WUiR z>r>TsSi^@Tl=8wSoxzt+3?YTXIC>oF^Uroe(PS4A)~Eh&2JkuRys`_RpWOhI`{}&1 z8jDfdUw=}N?}j!9aptuvHGWFvKWzkA`rp6|(r#!8Q71}6{5E@U7zIh38h#&9X$Zsr zwiD5OdhHynUaPz2H0YNie(-wx;3g8!fEjG1$&|l$Frc>&PuJXSgT;t#_FPDdp);yA zP>BBoqWN9}jxSye?yq46!9P>~Yz$mNm*>Z-c1@9hWE@w7C=U-Kl1PfFqb>=2y_<(s zv3y3;Q^*pL!dtA=KzON`ia3Ua+}Bt8o=kO=Off-0>g9$Tlw+q1wu%Z{>wmo^Cso>FA zDr3pp?I8qd3h z8C-DrD6YEo_Jq1NTB<@B(KysNBOoirt^{Pyxh+E==YJj#jf79W+x>6~s(%nc`UbdU zYV<;U)GwDMKO4 zdc&8p?vw6$z&+GqKu}SwPK-$NHY<4t^hoq*&toTm9Kl00+8>+Vt^_eHxM_E#82QYt zYi^xQzSK9KKgCUiox9C$lkTg*92&i|AFj6h5Py8p>Aw5^@C$%s_+jTm@BZ7j1h}EZ zRdyNbd+gz+rpbzQlLhK6GFh@r1XQEp369d9_iYuI#LS${X(jPg%Ly@*Eo*X7G;EjP zh`#;!s=sve)&fdAuN?FiRbNxyr8G^5oF#Jhe~)SJzS8e9!D~ma@eeo2Jpv9hhdG;5 zLCep^WUR>ohqz|QGkCoz*HZ9mVXhjkoZ%~6G8~-D-Ietn~gkn^iQ#S!tVJ9(>Y5Y8{i~`wl zUZ^T0=y4CSCI~qKqJGl}NWI@RI>!0axdTf7RKIIFE_fDmKZ-emn zF6xJa4fQZTDgcwl0UTN#e};qoCa-!hc6bfpVX(0h?7u`8ujTjj{3qL?Yb4*=ec}H~ zGYC@>EizZ_)otPWwT4F!4)#|7VPV6ZJcaJ^duE(zuK}{E!>jw5%(}j4*?kfs&)tMJ zGB5eoMrlT{{_4H<$B?o9tsj8JdS1t;@V(#|6Q4Ak-|{`vxgnB-)P<)oCuYPI^Ufs^ zkd@x%n?Um18_n*pg_nN*+G{U;rIo$(dza$N;^L;o@eKzi78mtL7u#i>G`-mf(t?i+ z+pJc@Nx}wDq->jkY7q{+@!*yrrm*m{HW+l)zk9(R=jR>VfyxRUD#~mRh&9}mr1R?o z;DPkdYlNOVFhV*tFg~RhSi=N{_%#zXonA|+$oO|t+(+wokz)TFpA42B{dLY;Ir@1Y zRZUc;ztJH9;qI+78VkE=PfLG)e88F{q4KY zTYq_d_t_A*2JRa#)jsB*aU#+JFofNULeN>PBjPZcK&KYs zxc34R*j_9vhuL4OSt;IJyzI|#3OqJh>@2R;DMUn+Z1T@HJ-Gbrn(L}|?LF7HdF{c+ z*urwXB?0u+QzgHK6>^U(*Dqakmlx%=BPNt_tNEtOtmTD5z5OGZod;XG?Ka9L4S(d8 zs(AaAoR=B$o|z!9mL1j<%G+q@|9EXFa< zHZh*0$i|kHbWP#$0!eOxj*Xh}U~+}!w_x^gp<@)frm|9ko#>cHa2tPLy%rIU8?&og zt9Mx|X-1cebA{5E``pxZ>@ksBptS=oTID%*Z4gIL_6P9^s(cUmku1)GWtm3}`SH*t zDL>p_5AdVC+cpeqa9C5@ohU|m5yp)7@0#`zt*IXzggm}+v6^Rt-W)9;)McQ9KsTuA z*fj_<7{_mc_n0)7@a8nXEyO*%lMGVKY*EmpOBT=KDMz_$TI`Fxe33`Sxlr|%(isdUq>eQ<-!dgl6CFn#q zGCqIv#~GrcN{!dQYq=4Xf9jc^fR|f39Ud>JQrb$ZZvNEw*1yr?rz_Q0K7DVL6c8MU z%RS4G&r0viQ>%Y($I3f@ZU5gN{-6vfql6IeoB0Yz7ybKpZHVN*A^b2{9QXMrOfVpT zC?oQO8A}oFt_|+5Ik9x0L`QckR{@=s2P*$A4gP6)s=brQ=zAI3NATsY;5>Y#j(s%2 z`QaqFRo~_GLCQf7q^-OS;fj$*0-DDkK33`gX+H|vahNyj6Y4I*hII-)XtiB$=7wuf*)hY5VEMM zco{NIxhUImqRFV>)yw{^aF~t-tBN3)weqSe*S@|Vgds(>u@-|QRn^UkvW%xKjG$(j zEz|`Ojqzc!rW$$=%SEQH@T4q_I@Z%ZcI~1pJv3pxbZ8f_Yh??LtE$8q74!%XoqOkQ zd2;09ZltyBm(So+m8LOY*{{`1bM+QCNy_7j`TVHZIZC%Rxp^yc&aHVH*E=2)Hxt&2 zFX=_6QL^AhL~+h~=v8O~-cR_TjYpM_A31(!Y7;f0-e|8Zw#K&utft~(CBdLw4hPb< zb0G+g6sjxTaZ=340&TOAL_yxHSaZ_OSUK5Eqd}BW%C?zc_c+@fpOOV6u7cM#LA70m zk5zF?&A;Gf<^xtV-OxG4#Y&Ap+9FdmP+p10ACt*H%;@7#j}yIlY*Sk$OLMbfYd&zz zx9`KYbm?WW$Fr&cGAT=#kKd)SUAdCejP9GGX6Z@59>Y|B<5&+zvR8#Lf4^$2Yxq{i z40tX%HQjm;B-@k^2-EbE;5ez>1nLkFq7Oysvk;!i5YL8!Ald0~L>?Th&a2Th4Mvob zUINoc1U?I)Ga{XtlQ!v6KELz>OO_<_f`wMGsKmEZlJ2S2kjP5~cUuCx=LB3xSpAki zdWr1;iUcR`(jCHothB5XI9sutOYk0DalU!@FInHB8$`dxfM2rvW>0Vo6!I#N^DNMF z23UC=Xn6^^H~`+xK{~95U={Te{RIQGr7f;C9&kQ64?b(u9@SX!WSqJk1SXro#J(c; z-)YX&fdI&yV|;8T4O(cl8&QIrZr>&-FC{sqGV4sEuAO!g`|^#D_1KZ=s{)J36z42S z;xl`I2q4f;?fTRD$6r2`=i6_`L>~ZnW9s+c!BTGi@V5f@lt;_tYV0qPodFvNK*0Zh zaObXPe@nd4rA4TdbIIJLPB@#VsXcA^=+o05cmFx==^za4Ex3aQF^!;As=%Pt;GYn<836tM1Qi?CjtJwqAvDwq;} z2U<@|B9=(2qgFfO71{>0*GFcE!U-`C*R@>6u-v*{C!;3xNlzy14P2vC8E_-TC}42| z>A{sGl55Z20Rmeu;X-_e!;*TM`bgck_)CFN$O2>bv!+`lR3RVS9$dy@>Pr+omQ_DD zea9*jnKvc$PP?uIJ|;8~xFE@lEttyacnwzx#9OgRDRKPK={c@Hg*4L`xO$cF%1{|E zqbf1uvktB4?AHoXAd$)Y1WyYX+<EYd@cvB@}xfqR<_(o^VY|8RD1u=Aw$?o!Oo^o7Ju z5*Da#i318uRtT93|VUz=7BZhy!i=e3dJ7A+2p>&H-StcT_o>~ zjCL#dny$zaFO07HBoyvZ_G-ODf5XH7iG^S{z`v@f|48Sgh2w_mPj^K>;&9TJA2XrPb6~E=ODf{&NQ9wCLNL5hrJqo@MrNs^B%I+hCb*4*9@@aC z14J6q&JvG}Zc3Yyqj)urVtOFX+v6-xAg-JQl)%BcgL9<#7fZnU4I<92XH#tlh*|0` z^1slFqQRY>vuRxu1za7WiI!pl)PR5V%#j3frf-xvWH+I@p%0c`Hz9EZiDP54*1~K2 zQ{2cdJxM~RnYo?`)Z?rsc?5Bk2C*1bAx;fsCO@6fj zzuGp}f>&%y>t~z@K|}x`cmfYtK$Q8$cKy_O(S9qpQ+TBQ9Rzb1S+u%fq3oBM$B3Nl z^WWp7nps|ln?G_M{<7lEM1q&^vqArm1sewP2nHuN@pv2+26>E@O&-UpEKd+b%aatU z$y3zo%F{S4-labz54t5n3cxSZAc_T0i2{dAd)G{m`Qf69)p%dSwo^q*>28PuU7=@fP z@m=Xi5B#dRG&8N78=hJ}ffi*a(Tlj6cMz@2E9p(UdLnJCt77RxxjHC)8CHGLk8U+B z{n=Kl(vIH{m}7S1xU59n2%&)2cJp|zEe*CkI}zoD!D6c3Yk!|)728-NbW~{Aa$qv^ zwrT2c$p}NMrdQXT*7=%Vkv(ZIE2K6L=h3?kwxfXW zuiz~0c53orLYUrw)eTzQ&?ft*`@#K9{oGUJ=?Q)Q`l=kY0}UFVZJ=H-BND4VIGR%L zg&vV~2qA-d8Ha72N-gV>71a~mUQyv)ZL+GbU+&t?-L48`Y@Vh~epEupo@OPf%}Yyj zAepea?=1>qr}l;3Z!uvmvaT9wvAA0>XtyIh_v+HNoH%GI+YUZg)MXXGsO|cJb z0y`_S_nlEY(`B7ytz0L0`^EX3z)0&xy_c9ySKn$MzlBc8aJEF}PqqG2QNDrAU4SkB zCx{eI>S0qt$U=%zGgT7c9|@kHFe)H0AXLFCPHBn2DW?;KGl5Z!5^5kwu%8HrBd{D7 z63KfcG}6wxFCY1BESanp7RYY>MBR;y(i+&6wxSFABGF^wKFeUOt*(FJ`HyHM2b*lQIcwUwW z5vL9skzj%psV@?N#=likN6(1*&|4q9^3{)i`YKdcJ>^00s{9S0et`6KFn>Y7$Sl zw1`Ol*lA>yLQ5lzG)i`0whW&6+xN|6l6Ga8ZH~FLH>Nzs z8Eq#5`JB#`^P&nX!6(ER z`hZMAxON;#Ww;7=;-2BvH3_1$vlcU9%8X*p63eWx${L(htq}OgxljKef~f&6plo5cK?E^d0-qyd*vN5A6_-p zzkF*fnIK4v{jCreYH0ZsMHJbCqKfw9K03Cz$i+uBUzJcIiEG|QD}`hUVUrNFOrPfj z#L&tsAE-$P=l*F$6<1Oz`+S|>_l$4Y`D5i(R9RKk)l^$uFRJfl4ZZS!E`+~zY_6p@ zwboX99d$x`xbEK8gG|GlO$o*-{)!w`K;7eTbgEOaWzf3oKU1w4Mj+~_n<&Tl9u zSTP=BVv>i35=tpUS;|obRZZ1`E($d}5?W#_ncrN9iGHRVW>9SglW$%bO2!oUO07UINvyqsuRm@Gc{ z0s^+nSY;o>N=#@+_W|KG0@DybsK09-=AO#q3Rr=A}Lpf}zf>v~e3vsCuolmW) z*11+HdYa?pd_5Y<1h$SDTJ1IKS@asMQJq^uYN_2g)Y*0sD+wR(LeKrI<0ENw8hu92 z{*t;o=-~6+*s1PnH+7AZ-Lja-7~SRXHTsb|^>2T=A5vU}iTn~K5{*0UWQ?7zcveGW zJ?&0&@R{9haiz5ub+>iY^MAHwplTKAg`$?xn*9@7lB>-TC-E&JBDG#OqA-%z+O8{a z#7%Vnc*(@JEn6>tv9WdM<#us3ge<)vu8#uM!^Y9y3m4?6(7J4^!lo6ndw&E=e3hsvcHdkT22NYv1f@F~E${lqQF~gM2RFl!#8Q|d@*a$;P)jR=AQf{6d-z+|XPL398b4%0!H-AoorOMPKsN5&ygAk?L| zGliiTPIT#-hDPnu)?JD=T_ykk9thi|bRhJYN*SlfWJ{Ssi&Fs*wy?QAQ=CqWc=z>v zlT&s4p6DNY;4Loa@Vka?g2SLdD2z_VrH2L4QD`_!2Vr(ISt!klqOc?52q+Nh(x-pJ zG8Ds!E?v{ms9oB+OVOswgrex9VY`$L^iT_rRavRfVTB9_Kv;+MkYkWxva8b=W7vZ_ z(U>B_v4A&H(9d@tE@{uXcRDogVvLwK&4sk}dga4TZ#@a)$ZI<&I-@&UVZ3wP#rt;$r-@ zO>s=kcQ%+Ynmm&1Ue#)Nfnq|ttD(pSoGh;>!%rP#=4!fB3|j}dRUlVy=%ySz`e^S< zVAujBHpNsx*&+~HXqZr_S`<vioLR%|60|S})w%csswc zXq*>m6_#*Gjc`YmU%v$2LG)BtBm=`=BigCwrg3OjxpkV?v+_=o9~~1#VWK=2Tn5f?MOU5_Nj2tU}9AlMQTf?Vk-c_ zKap*Tm0m#vmpqA1SNS?3?>C*ku7+UOZcS=ICQffxs>Ug2YgYqVwxYqzR#za+yV{0P ztA>h8%~Z?KSr2rgTIWz*5$wo_uHuAIT)sEYVCV1un+q{m;foiux<^X;r{Au4kvht{ zQcv6Y+aJn`1T*OUZ;y3H7dL9yj zADd&dZ($(D5*E=YF=9?OStFd8=S2Lw$!Qp(wKaFdRqtMLWO#(sDIB%H!7Xt}2olnQ zL4^o5A)+WP+OJq3sDOZA;6H)^Ef|G``HEoj{PX_RxAv*}s`BgpBgOzDBO+7PfKjId zN3f#F8U1jG3qAck?05IPW}1ofj1mh1%%f%^iUa@n1tWUb_id|@|7f8>3Zdf}T{XMh zc0QfHcQ4yr%YqQfAGYGuw|7FzGJWE)yftgO3eXN1PHd24OUBQJ5-dx*pU!&86L?SZ zTn-5rN24UOGCggv`rO~K}JYQe<>A(aKPtD^xlLm>~SO3`c73v)c4z7`nP8S zrfqj2mvFI{MZzG13^Is__(G60yzee+{`&(2-l7d4(x@yIJ#`+g)e%kGiFt()PLa1^ zT(+Fu``c%Y{2_{>&$f010Z!X{u4n@82*%C*Feg0;(`*||XA-cMivw8F*25~O3)a=H zLIgONLU{P=TorZ(0FA!@0I{1F{e)3$J?EmcPkrJSoPFFW@k@_7_jDodH+~)c55_p> z{nT^OdhY3GoQAFQQ;#|Z_g$WG+Szyl(96Qg#;%D&Gba}}4=*3TBLwWw;z&U|wc5qB zTS%A|5!I$$hfZB$_K542uvbz_T1Hk*UO`bwk6wNH4HyIv0m_(J(*IWKKII#J;9nFn zz=ldjRZ3M+8B%st-k{vBqNUQMDpP%cv%q!X9SC?r93h|3Ks-s}QW~hkj5_8c<^qe# zGGMJ^HLxzR23d1#3w9(sm%W$W#!=>2a5_0pIDeon_z{oJGvWpFp76E!GJcytB#05* z5qbzesWH_w)U4IK)#B6+sXY?eiUveaMDyxIstxsEI2oP`Zx8Pap9v3#zv`%-(~bI` zexc_h-bj0-Co&gV7paI`0|8{mEk7VK2;i1)VV)D=AnCLd627EkWhWH!_tcHGTB<_IJKdkd$O?he3xaBa#j}m(1wd z&4z56JeFh@Z$9Bm09(4!VprITlP+T9iIMM4MTkbxm?+0YEh^bJ3{xp7sZgP$LP<%9 zBlemLNEpopZ#c?JKH@6?K?;!&zyzA$0>xEwqR@y}y0OqJQ0Z&u#Z@aS+HA{nkXBnE z#jaJHB3VRxD}~K;%03#ioua1DnUHaxu|TC&J?DV&O9%8ET^oxr={vH^RT`3SY+2k^ zo=xQ?-llgWFIuJDV=?QLsZM@uXD9Gg)}3YzC@F*39t4$kX+&En9eg~YaH4xdW@O_Q z?QCbfXGy(tV`F25UC4WQV+GuH$%E1XxS>s7g(}3%&KJO_x?sWI8KGm)M#RwI6>_zi zH*~6{oxeq@HUO2cuOnCNvd3O;c-MOlJL=>Jru|u@MZ0^MB56ifr}|!%i%7ciM|3W- z*dP^XhePgQmfW=8e;x2nZjrHtQ$BFUM?S+$Ac^79OX}q)16LDNZi*hD;c$MUaLu({ zQ^Ro7ZaS}nSUa8Clg@C|NV=H@x0nGnL>wO-HF|<`ji$hyitU_4E~NBCC-_+!^zcQC zb|?$uqMbZ={Lg*itgoHxj`lKCXr+BZOT+jRZ=~C+-gl%Upt8Sk+g_Uaz2xnj>Eh%Px9LhNg_6~mw=vgOT>+aimpi%vZc*Am?!G!xqs zp7LSTe^isVHN3t)xc)}ZMF*4ltq6>I2r;S?10G3-w488zlx5Nw&zq4XzRXOH+z}8) z_GaN4;esIxfD`6{RP3>JVEK`x?@$Px_rSRo&K8_Y<$KHQ1!@?ObF^Zey|1DsW&y0R z?$yq7`^1kMs()buKs0{*iY%L$!sQBZjM+gROa=OtT-K1KSD+I{mfqO%2L$Rh)x;-s z)!4OrrheH@#s`)@mg(Q=;sM?QpGd06&qeyN0G@#@(eII^i@US>)SqLalpB*&l(FXx6uo}&PW^tExeu8 zb+St+oQ*=d2|x0K>1v6AM9lP?kkAM%8(aNW8UrkDLyO_*uaoD0@dL~TkclerOD3EX zIMtbiaX*tG$3#8Kv=}Yoyr!guV- z$1bXtnS7yh_A7;YrGAJ0NeG{UPdUT#y=C-3U#8Zn4)PDB({J%8aj@>O$9wq0H)jJo zw4k`skOyJtLyH{~q+>QCj{yZNus`7M_T%54tM>Ei%E=OZ`^vtkHcWn`=j| zq_|JAw4vzwIYzK~G=kdg7Hp8~XX+~M+pD4rN3?$~OU6=+xb%XS0vf8uJH^NYKS=(M z@YAd9wai2{`>SoYueGWEV15B>n4v158mg|7uP&xKn$Lb|dI9g#D!tcey!ad`3s-y7 z+oAfvL_IAlttT#Oma(8{-?@U~8&fXX2a96XDFZPT%Tr4%=GG2x)Fs>wIh(8%88ZB7 zoF z+5~K**M~$sb~h*Ot8>KY2j#i4QsI?nk`Bix0ur@S-e+Y>&ts!_Xf>TQpw!@}!hUhj zL;o3CfMx)u07nmwD^%{Esf+8(s3f~~8pXk3Wrvt#yf@2ch~cnL?HsuNTE5*3YR#L^ zp?3*z%^xs@g#&lVd;+r;08IxUcyB|Cs5m5T7IXayLG>dvhs-sq@l3n)Fx1d7^1Fvg zIgN+TlSaiOXP9y1l|D4wPWw>ZX+l62unC)6SixtW3UV4%;J0tc?@Btg8lttuNO?iO zkz%_$C25)WRVICo!;Be6(GcE1lXF$d9tS*^ee>b#J$(hZ#4Hf-Ii|Hz%ufJHK%aMEf{DWb)Q?Cwgt+Z|hIX z)^){UCXAyXt1Q784@0ywNtXpy+tGKky%u97h0%PUi37 z1iO+}j`Z4Qk5^hQY>|3ndiq_EgW}|6{+9P1lV@|%gsC~N*Jtgjf1LHX-FbvK=L@L$ z?YenVyLSt5$Bn3pg%dzQ-CR!1UWn!TS-4DrjimICFfT{ZPc1?*0KyC6%C$`yN~A3Bi99cOXzk@ml| zVL(12`pnmv%*7G{RVoI8QAE|nzMKJ2RKjYA9Rhsb8qM#PsI29;E;8mb5nm|&j3XwL z0c$my9~q1HYlEk2M1%KSKvZO)%P1ny5JH%b_b3+Ak;wb=Q{jhJF_z5do=f^Je@pM~ zPQT@uTY93WEQ;J!>h9b9lA4%{dEfA}F9K{u!wN(wB4G(vbU-%YyGQaaB7{XhYsQyZ zoNz2n(QTFGQ(RfiE84b`w^XsDS^lNsUm=D0?yqoILopL;u@PIb0(s3C_XOkKz-Mhf zWiJ&=wR{VEIhK}KdRrAN9xIWhtVm{`CRH)oGB2fOH9ika$~*p$cFUtOn!>4_dFMTL zmUZ6{UFxH&eis$u`-qr62|hUfy=lp>Ll2aTe4{$j>$P?KqM?uX$Z-z&B!Ng}_2iwc}WU z4dm_y0q*duc+-;$0Z+gJ%Q__hz*qnq;1qxcVC~5D1$=_5z1h2YKL_=ZY8u@7GXP{? z1tEa|1q#dw3vmBQas5Crq5&XJGX%I??gcN#oR-}1qNL%{*rD5Wm(J)uJ+1w2n{sLUIC%ovTSkOvC_cgq_MYrpe&gy)XP*25sR^;kbBKj~}|v{}p&dMIvq1 zPk$8#w56?WYkND4Hm02wS5m3#T<-=`Os&i`)6FomU6r>RHy{L{Z2$lOb^r+JoP^jK zJOEZ704z5FIToa!21=U&&b@)A5!fv0^2M=Cm0pOWBe0c>eT~5MDTQiZnw(TRqHC-g zIn|a(VB{AvOG%_xehKTfZxuwic=(GGQxmB9%w9dL$x7L=N+gU`U-M;8RC!KjaIN0# z5X!N0>)#nulsB7&vtX-|OC|D-yke5|OGCL)?z0|!h zBtOv5t!HH}6WNsZl&zoTd5`o`PfWQhbk4?a-v07n0~@c5g(0p0zsx+H!2>g4WCwl6 z4I>UpwYoG+l-uj^CWD9LSY)_;Y8m4mMak%FopuwTgBq-%6j0}z$stfZ5ekG`5OW#& z{xWH*iLA4*%b5&LtC!+%8B<2B(Gc)vua(p)8j(kJ4;KAPE528 zf-CSmti`6)T8sB*`225n^YHKgNIRNbw*R{aSyeRIR{7L#pdqAz-ZdRiy558-x3Y@?RilnnhGt2~!70HDQN!&%1D$OFg(``%A#k-C+5*KPW_%RoC=L{I!8vkp zhITAI-;{e7Of>v<+vXqskM3;&N}NG+U>`kCH!VTxE>;`HZe6kJKhJXh@f zry9T%9gNFdej*25;7a_Ag$B93>i3Cfr+b|2_L34JVFHgVNyi^-i)bYN=iXv0h{1&$ ze6>#)m72_HkNYp>ine&zJOR}*8-w1nOlj}BM){zq>yC47Ct5;O6J~0fZFdT}ugisu zkoLT(6^vYTdzA|ejNwTUoHPGXaG9?qL5Nj#vGHzKS6X95E2o*+>q_C@8HWo=|J~F>Zf2oKeq8e30m|fnXRo)rR<4#KMFXXQ@u=-FAHFmH^xAiU(t~(1*sOfz*4(j@rWY`P=17 z1J^K2k;xxH3@A6(epF^HBMY-SZnpfHrg>yA;G6ZFc{i*?C~q)^zVLkM+uk~f>7Jov zP?Z1~t?n&m>`Neu@_mjA6+?@**|VzlB1Czt>(FG1;o^3rX`p!KRT@{J{@1J8!OS=K z8hLWTKc|}wf2{{_dBmLQ4ffyttjQ_UXT+6V@i0-wr2-Ea{1FSBBxypE88Ru$MQ~;g z-Z7|_<;Nn^$`Bb^s`oJyW_;h+C#Q_E4R2Ep1*XFwbcs1|jiVD&e_UL)5JwCYS@^6y zKUdeP+W3)DLPv{!#2CjB8!nNdXlCi10id@zo{d<+hG4>gMK1hlaP*I@bP?Sv2CmjP z*@Y@HT+0qvBFvZ&O!fc9z|R@|nGF4N3h_^C11$-h{EPru5(aVEbrFn9jLd1T@}5Z! zi4&CI`x%1DDYjKjuh-ju)YC;}NJZmw;K`s>2zh_nJFGkl?0I11>rq1XXp`{6JGYJL zm9K^|*~3kSsc1h~Q;zG+12YbLl@E+_x&Im2IQZ{Y1YiAPg^$i9RIhTVBl?1$ZRV97 zF`kXl!YK<C@N5LR7YP&zl zy$EsaTc8LZF1<)-_x&xFlJv1akLZaa)_1e@mCBkK|1#`1MwP~4dikr`{5d^^mBPpo^u!*8p3)nBXs*+%rH~; z8=8=?ezEMb_e-g#x%@sTnRKzMM^C`u;3EcL_E!PsE&&UvTBV7MP}LKgT<9>RxEYT# zo1MeR=${O|MZIx)7I$!~({8Ycy-BUjJ>7Z-BN)fMu30*R;ek@0#VwlKTt+-?R@QIN zPgQp?K@G)JBI*3iW%rIRGcb=rtaag|Lb~h?)8T=L9tbYH?imeYr~}JRwJb1bEZb*f zG{=SWghOUqna|0e$&-e`dvJ_|y3o-tnwcxFV_2Py?fxWcHi||GQbO9uTKT9Y5g+fF zx&g*)f$X#ipR6qB%2S+2su~}%YBvVd8i-D@2Zj?8 zVbHc3dzH(MA>{k01-UhP*lB|_68{~Ttgntejn6LGf7eb=zH%_VhN?(;bd8}LIO$qZ z)Z>Iq{V0-3RHhP@4f3dnPGr1XL+>2igB~~~5emr0?Np91HbjPCK?aBoubACy8{&HC z5$nd=bjJ==-&t$?^66*MjY|0qiWo?H)c1;ZJL&S`^}ejDPUkoX5_eD1EIEx+`If-J z`y#XdY&9y|cW>tL1vw3%g3`Q%i;9H7q*;}`BMWXP z<;P*o>a9Ism!6yQ#M}qy`b*!sfY6xdyR9|F8ySFPzh&1K15ml zNDC~8?n7C~DPobt#5R)iFcR#d0LcuTkySxO(Tc6jW(&b^q-$JcAp?Qbmq6|eK{IW5}c_8UyeRM(SLH7niC%BmPQ^4)SS~g;$b$sj=P7 zmqJ8!6ox4HbeTT3h_VZzcK!@cs$OSgw}Fx>MBm0X=X5p zJbcd61KNM%0$!AJ=ha`lpyweHD-dwZ-eX}H$H2J88y{y(Sawu}UvjJqbv;EGV<1^U z8wVAzT4e)+BpM?XVjT0YJ#;j3n{4uM2!?Bj+`Z^G?L>8Vlm6;X347qdAvMsm&espBjD3YhQj zXth9Klk6IsSyb$w<1|Q-s$w5E*C&B|(?)mPL#W`ALd9JD5@c zIozShV1+ua1Kh8R8hlG&-%*L2_kF-kwV%uKhqdzDVWvt)yS*DiXrfg*;@b3ted}d* z?eMy}P`8|QiKcE1aoqPk=MA!IrTft1R~72~n?E0jhVDqt-CpI-jb3vXw^u{K-DjKu zHSp@GZS6Rrb0~BFSnd3DP2J`Szh1@H3%kH>F8bja>H-kaihdA92K7M1#E$#mTtEvo z`_V+=Z^-#zU;BH;whrUSo<=jFBD=jK!~2>L-Ep!cQi5L7Va>B^uUrIw0+)4fdPOgT zCA1;kcwwHck4Aq-j5fK%n85U@UM5twpoNb@%mm`b_6SfYJeJGr{-SIp?FRK`yyhac zKPzbv=8(LbNzsx8f(HQx)JIEV<)+_@ZP)}0{fkh&@H$cmWO9=?Dq+K{22=Mhm>N}w zlkYYOmCcu)5fMr_KmTF#xpK9dn*uyfgFu%;hP(R!@3v@ZxUJTo|JLC9xflPvAU|i4 z-+ga)^xOWBawg?O( zo7a+%P2)jY3&)#Km7@|zA#O&w-eklNi)!wkZA&<1@a&-ymK?H+kSD+_h(1L1t9^uD zei>oXtn_7n?2vRbI~XM|PF#Bf@A%YV{QRMnAUj~rb=r|L%87dceR zP}TadeYQh=r>JE$$VDy2tJVpW9Q@c_RX9BgN62#2?bNMQzsl|zU*TkVV>PsN!la{w z)|@y#BdUHhWB;~Nnb?#n7#0tPMn7)ySDpl%i)L_x+`oV$P2w~2)M8XCTwBrJ0vBt& zE!3@Czc`R(a<@Gr{0YR_kQF-*?L`@3u#Qx_$vy# zLli4RC0o;{q*0L?4}4Z6hgi#*lJ3;^6L1Bg{nESieiBQacqTGpXs*6m}An z#qm7|U8-y3aX zqkz|68<7277`$O183lex4ciklHc+f6lZ}p%Lz(M=jWPm?GIV0KG zweIJ7Wz_ZcKfGoW9M4~?)^Kq|U9mJ3}{?7aXMqgl8U{41I24YWRSAeub|Hz~g)G&k>PF!tn zPF&3kHw=-WGU-2I>jR^frn3vBQg-3e^uVa~VAG-SLc&tE0K=*(b%j1jr7~wFCARvY z53_;BUbL|iscigtZG!RXE+s3)BURd)6}#y4U2&6i`eNWFx&hr=$9K}dF0v2)f z$+%O=U~6Ds&V1hQ8}y?uhG6BChi`^pyCB2YV``;f_lv`KW55@@u9`EpGt94gU4R*@ zR&**k=ovyLBhP}TRB-U^jUeEKRAiMz|9g3h{9X|Pq{x)h%iEh;`3#HmYHfH1eD(ee zjAD3)lC}Hse1X@rk$Hwd?r5b&3FG!cu&ve;~yLqFkO#ooHSvvOipSXb!7^UKEQ)tIILF*+TO0Vg({6$ZoG3#$Z7K~>>)I9T}l zN^XOG2s@#0s(*(uO-7S6rBJCUO%hs|KJNKR6xYU3d?}T zbohK7MI|QULG+}Zz}(G(0rl=M{&T)C%AA2=h(A)8M-`s`W4xmmVpsqVC>aqkXOUS8 z5dtEi07R8}2f33CzTx=xQ#KK4Sge2{?v}NDX9x@GsL4oYL3@Ny717YiP&6JaV=@C2 zA^s))$d}dYA3Vo#7ml-5p66mw3^Z`{Acyg)l7GOFu0R$1R7Y-yJxDwpZYX2RA$h{T z@jMP~@F5qOyEsGRT-< zlV#{GQui0ZbJE>+i=aZV#n*k(Qvkj=d^d(_i|me=QNa-3k+rBYR)06wEZY`zeTA$dnI*ZbvDb>lvZ`Ft zZqG^v3phS}(?73eRJ|#FeH!9&pML$o6IdAZOb=}~+;l_0+q+7y-H^w_U(!lC#KWK% z==QzyFnsOC9avz=y@T+oye{A$Em%5X2S)DIB85opJ+O%5+y4jqr12G~f-XMGKk}VU z|9*sjR@_hVG#~gsdx-uw#8BCuvGgfgfeaM|gf2O1)sK2MOEk;NZBDp25Fajy24v`^ z1A;xki2doZ+@@UpL&c5v+vg9@KZO2eve~_W&c1Xe32<@nZCO=%C<>uA=~c4Z zFpskF)E_@y6VLC@sf`qCHwI1!sV1&Oa1*#nlSc7&Qru`#i5ta_iIooweA5L@oSWT@ z_87N*ap0a$(=Z0b@($%$+~k4>xRMkP53mV^J{(my2ENi5_%XmI1N^`VLf+a&W(b-D z>aT-rYYT??UCA|=!Oq6%D50t|Ro;hYOWj{v@Yes5z}22j$fhh#g6@#tcFsy#(P&FcFjRQCo*)dw-bV{^qy0{ z#GMLV2D4vGCa@)R<)cT5Kab#67@eG!6=mm6;W4?>yh*Q}XL_fahKcx{7* zh7HL3^uLr19`ihZ6G(8-fNcL;Z`dgkiJU=anvrHF3NN@CTTCX$(~iaIlT}e7lrw+C zx&}<+TH8Upqcs>hWak&17vB>U)Dxd9zpMqw2(a@po3%nv&t}VKlb73wT^uZ}6GlUl zhSDLys|0vWBTI<^AJdHBpo1>HS=VZkYJEG;#u>?9!9a>YXJI7$=O0Nyc@5uoHfG}% zemOm2DE`hjIzs<;Cw?e`Ue4dLF=p15k1)Pnji2$MmqW?CR-v$!mkgEDeP-gXeq(^) z@_w`*#MDIZ1CsR{7dW@$hubcl+*y*Fv?eJzKQA%Y!qTll7qNBsl*zoqR)y=k!;9i{`X2M}o8}St03$@s zj6ad!|Byo@avu5imc4tW3G%%F!8dgzoIb}>aRT$&jvWM^rg z`x?xK&)6QnmUFzv4g8P`cmIQ^$*J|0?Nr8$T>*nVF<8uYV|v!Mv8YMk8>p0Gr9_Hc z$cgh63Rkaz)L7dXO?ZP}uC*MIeZvv((kJfNjEk8_o71rUgAjsh1tK-|b>PLc8&7oL zHt^^36tvq1M7)tNUgwve2a76NW!O2=k&YSY(*s#Xzw~71 zo>b~EXWx6rH%yug??%{qK5$C^@g6Arl&Gz}4E{I+9H+maHZ$>D6t?22HPSUG-7n0f zW;+$PuLiqba7uW39B3h?x3|1WO^*8}XPT!pKmPckmqASZsYArwk3tUnGj*i8=~53< zC(~W%uF0UY?V+PtS2kZElR&!BRB9T6h9paq8`Yg%=DzMk#_VOS@3NQUpYO=%?~6YA ziKuhVvc+0&S26-dRtFd^rrYW4M8;hLj5uuX@@Wg6O(WXuMS`+u;4xpc#< ziswKzearUeSruThn4N(xIPGAgw64@~8f`qai-xjyI4z(VU~&38G+12E3T?W`VqI(s zWd(;az`tlh@p!c91wMHD0j%eoleX>UWjs86Zs~ZLPRyxBce@1B>w_w+{g%PWF7t@66k35k;@hi3y~D4{ks?IuH96M$GYJ z2#JJ@JYsgvw^X3~{Vq*Py*$YOB~_II&h*@t&9%hh)Ep*;76H}*sw4QH>momslfh1y z7{4zjUo4}Rx+HB}PtB(7I+#9O9#e@_3Q?huF&PLIHY9>WgT*dUOOrq(5;V1lf@6U- zwdtN6z~)70a9C1s_79cif$|HL2@g$BPr_8TM`gPJbH8Rx^HjDJ^i6OsaJ*}~ZRx?c z$3F0xejFbK2X%=9yAlbWl1Zvz?$L$Jnmd?$%plwAe#a1hdn5~d!2!3I^UQ%kEUX;-q z467;^1%^dNhiy|rycNyt$%-H}+yZ312n+U041T>TM%M(7TE45g2krul{Afj5f1rm+ z$|vXy`4I_zLplT^o5KWRge~UbESngC;BKKK6vkRHSZtwPwkoAj%PiYzw06rfDy`J& zGIeHQjR>t&1Pnw}nudObV3D3SXgJ=*LcQ-l2Y{|9Z9=L7BZCYP!_t55g$|933oo4J zUp}kkz8_bKuB+k1A6Sg%)En&wIb}4pV>PDjqNyyCy9`pwPb(t+eiTx~034r==-nLv zQ7YUMw@E_0UYq7SnFgxJQqdkG&zvj~@jK>O9r!zO`3*DyR}nBwvByK`II6 zg6V&=fX5$y4(vJwqY{$hm(7E zpNHP$VSR=h+2NQ0*@SFx%z;eVi~%{0ait8!VdhZMaXO8xzyEuIY;qKXnJWCJs!YUv zRayc?$>z5#ph@^2av?c!w~(YJpPdmO{c-RLdWcjo3y=bf3gnE_11S%E)o&>u4W-fk z(?5=15m-Df7FcKfML{^7nnBPweKA>M10`w8=n|H`0@O3!D!;wFHk)8BHQ2en=!I|$PzL) z=b5k=PgXW-c#)UKm1K&b%bP`krLeGH@zFTsuF83}V#tfN69!h1r_Mi-`PQ&g;Pt?3 z;P6S-XgY++m>H+vnT&;aTm1!}#Pu%G*aOKaWd(%;}bsE{j2L$}$S|kCf z)wZq~y|J{j63|+VG;5RWfm}_?5!v&`b5_KedD}T4w;0&Bfb8mzXti{W@YCbJke@9j z+Pe@fr-eEf>4-VF5cxK~AF=bL`|~A8v7{vyyiYa|*kgo||rSF6hSLQG63ij=* zAiWRCKS%E)_gW?tFPI{~>^Q|_6fxB*?cOkcL|qXV>YAj#qJC=3J^Jwavj(E^<<*7(pdJ@6a6H#Qk^!|8GUL_-)pL*;+8-? z=51ZTqLsO@i>D@NrGq>-8)z7!zfiCNvuBld4&x90SDQ_L>EB9r zF>E7=3=pMJ7lRGY3qR?;p+`>+(fyBf0=1y8Zh@ZjvynO@p`1b z5snZ8h&_(#g1vjA6$&`~I|Yb9*vk_z`Z9VkLX3}(T7|n=Vu};vOiOO!HkFp*|HGVr zsA67Xc7Ha-an44{a%I5|Ob&&d_@yd{OQyi?RnOLtDG8WNlH3i4bnbZhf(|tqZJm-q zu-BWdc1`2}?5{OT7+&crz{)X{8qF#SwNp2l8u>7v%?i>yjfrL36KT3VEm?PfN*mB! z5d3=>99Qglb{pX%($f22Q7+n7$``S-b%uBg`JVzn7qS9A56vYut-Mli%J<{hJK&*3lVJzeX60kzY{^`a0ea_$kNi`_Ur& zC0z>G9EXoxg9O+TobzBY?I@$!IRflFvr{uw*v+uq#`G(31}$G#Y>*M)2AGo@0x%$J zZ>z@FF*z%otX<~r0k1zrOjC=L|Dk)$~e774M*L+{^+u6%bMJ(f+B+r-3-gV>^s>N%wt`^ zO@!OA*%30ABzDDPvfA9jrwzNjAgJjyIjmR+X-?bcBE-n4H5zKo4!tB=#KSxic#qgv zmZX)CwE1Mc{{;L;B%pg|Yxg|A?Z$U=qG`Zci@TWjIehbsne2mx*^`~X?9ZJXlIpf1!|MZ z9P{u&1WiZHq_R^;6<|s?*5@eqCs4@9wO|s_>fvf4!X=pva(RDs?(vvgXsgcBF{{#Q zq@YBJ`_5q**PWC~u_BS;KgE&hU1_s4N9slAIx0zV)rLsq3`P+Vm_!|f;YWbXr6s>{ zy)~Ob+C=B6TTp>2S``H160rDG<89f) zf6r-Xocs4-*;|dh126DxUm@XJ`1~#5$g2z3W#IX>1%-MN)bKw;R07`V#aNnkEa|X} zF?F|6j%OL4*7O$Z$3d*zfgiG@WC?QW=g43Wj&^(LoBCDWYBY=&jzXrELK8_c4!3r> zi5i89FBTQ2@KVsJ4&eu;kr~john$H?Ad?d?S!7C9@F~nR-}4nkYVE=3i5Ea6I+KlF zVO~O%yhtn^#pXXmigJ}F7f+##UzGwfuIIMw0p`fp>vf|m%4y*hQ{kxl zh7q*qqKG+!s5x!IDn`g5J~LsRk1nJw#@*nQ4RvsG*d0Sf2hO&c^O`&8nc2I(`vxaI%D57>K2`;FH7Ar_Md_l)+z}6rU{^RziDzy5gPAyhW zq*4-apzQ}b&bYsX>| zy`ps7rtA({*~Pcts1+~Jbq-gNdswNnV&iOe@V%mW-M!9eq~&l6mG~tjXCN8VwqTqX zk(|Iev^eRs2;g)WYWazcV3Gf7Bhh84Y$!r(k_ZaqA-uzZ!^D6;>U)LaZ}Z~S`}jBt z{D@VNv9&s9wI%Fs4{p)(xViA1{#aAJQV5#G^H$|*pd<@>!)D}IDFm80C92B&*NEd3 z>WTH=a={uUiV{xY%Df-+3$`Fok4Jo+SD{e8BmxWoC#!^?pyEG&n}`Wn_1n}jF_K_E z|HHe=18ZyrW+ciTK}JYNy6*uh-xb(!D^L*Vv~Fliq z)_9ipE7|Q_pnmwz$1kF+J4$_ad&hY1_R$XqxSJxomsMnkWxEl;ISfzx#pIs6H7w)%TpM9W|Z2A-)yF^ZP3l%e#`=l~>L)=>EdrJE(AP{5OXsToTXJm#T1j9E$0?&x;YU&4TVjhq7z%o`U^U z`N!*{%ZHWbAb+}r$sQj_;;_~{7-K2hVF`YN$^;_2+mFD+$d~k4v4p#bOCKqSM8(6U zL=HXtrg*dzEZU2%$aifoRhOxkZr>%pBD(pa48v0i*NJOk8N8NwJz)x7EeqIMfY1Qw zSU`wrO1~K92#8@0gHAxFr+QH%n9Ea2n2WLZD@*^`A=#M{Bb23$9Sw9OzlD>34phJc zf$b&JuL`TMSrJKPo1PTTO8+mN##v3=H{B;gmSeji?UHH>ZfytPCw*=ETK94I0pO%n zm}L>3a0~N~HtooHQ=JLAL~KjeBJWP&Ztmu8Puum30%th$Nrt57CE^m7yhPqFim}Tg zeb5%I!Ql)zXeEn#3+)?AH*c+RlOZ@Qzm1@zIvp8m(D^61J%}*!iYS=cd*; z_^-g$z^Evk7peA2!8@u2Oz2iyIxUj6- zT?$`75_Q|Spf}a)=DF+dQ8PWQJ}z~qr!&o$#H-o3RF`g?+vu6vwnLZ2CbZ=Y9x6kB zeddhvyyaHC8%P;9 z_f31Lf7^P&rM50Mp{-}|01mVvdv}?6G?F>HV1DH_n7?YK5Z|3l(VWV2lnMoQKy#s7 zmcxe*+!0V&K?|Wm4p{`5@nRO#iJ9TVtvQuFFbr=VUK=`QAz=Z0tn6{Z_Wv5HCZ{-@ zHaH89hfja92hL3v=FGPPg+R8?@rbT_<{URZ_GwSN+PUu2JObx)5t2b z<7u>`9qnjGJKE8Xb`(WX6h%=KMSq|_&>uLcn<`qPK3b-cRp!?m^lJ|4ri#|6kCsD` zEaqbkGuUO9{*vNBmm{uYpj!nrIgIoSwhQRDXh?>Bq-P`-K_OKSFE^U-jmFV=QwjaK}BHE+}G-78;*lvJ_2LR540T2Z5M)0)8 z_17l3ZsqTM{NKOb+nXFWH7;*!;7Z5+?^c5R6!LfBm7&J=oqsOe!20bUc-5&D5JVaP zoRXIoZ#jx>FT1vtx3pK{kuwjsb}!5Gk=rK1vA`2X1A!(q8QIf)K`(WZb}PA6Aj2_d zn^`#X%-8E-xGg#H%OTh(g*;52!A1sia`8m3Ye(9;&uMWsc&lEE?W1S+sW!EvC_xRVk@AmvxGxmcTzWsKtf_=;CCc zJm$P3LPIM_&eVpkB*|oz9)$BH)FAC0&;YNA9E%>>i2wUT9|0phFI*~MKdY2sOWc*+ zrJl$7pHTPieF>*OKL}Sf(?a0bjjKlMRh}!qkdN?Do8CDSEH!+(JLuuc#02p5kh8#J zvc7{(ISZT`sY6FCiOKf_b%fgu8ir*>UW}FlJ_TVY=a@!!tw zEqP+de0jJ79{g+_;~sCBAw>39Fp$)cai9bGVSsfGt%~vR2v6pvp>xP72VQ8twytLD z5HrGUp_q!58~UMRdZzu(br16vjfCVpljFH5wMcd&gET(${0bPHXwe0JxU_3W>2qkM znnuq)AKBwAQt>DU(+4wYEt%jj*E_9yiHV8uQKBnzj!4-#CGwDSS?&S%^0O?j7=+)nlvpYo%+dR{T&%YA zPjm&EC5fw$bHm)zy6Nv}uf%B(z8#=xlqS5mI^{z|ZNxbumCxa(;34M*aS!6S$5UHH ztRQ?cfG+pEy-&(SHF0zz+(cAYoFh{C94-tVa&8d!AdY+7SrUwd?)V=m;Jzb1EiASNdAT2ay!sT zT*6!(Dbm4oyP46RlWq%V@ya7j=*(yU+=XAw0=OYB(u5cI+J@GRx2#3P9(n%z_m_7v z+S-OYdFGFQKLJPpDZK{3?O$ZW^Z#pL;V8}5?EO3aa356&RL7Hu4~4s}FBnwQR* zvW4v+~Pd*Og z5U?~^qDUhM0gbl2psQ&d2ZD)@IyIAQ#jPPp#HI5r;|x_srS3B=`*BRvT*i4I6}i^Z z1ZKSo!I@-}57XdFAJa4j+-MAHe5_IMQSNBzF*(%si+j;v^cr?6#kGIyj0yFC7AD#hV`^Z9S)w9(| z%DA*gM)?r{6hjO!Xnuy80O0rJnf>s#%pq)>V-JAs-d1lRRo#wvDfW0Km^U0mrS5nJ z+~kGch(4A&^_0Pgk_CrU7mJA_^l1o8QgI|N8|;bAEkQt4RWi7b(A(bo?cRnXz*T2q zf71T;%6a$pet-OaIjOkxe*c}h=G0!o647+-B%TADJHEBu*h!t6HOuv9-A#*pBlEZP zezT=5t+x{2ZhR@Y8Hp5Umv5}8_qV0mJ|>;0t2&1!`?Pj0@scNiFu*&*-M9i@^S_jD z-kt=j%vOWFjb##y!sQXMi-xp_O}=#+*&*n)BNp06Ez=j6fGOTVkZnI>`bUCg3mS_& z`-Ogl+gtuhJ>BmDz+S5c@HO#;C$qsGn0CDX=g3bM5cjj4c`8lF4yyq^4uZYnLSDB;~$UrnY3_ z@LR{re&o5Hh!Z8_RqN}a*3~T*bH1C@BlO#2qqk|hX<}1H=~9(74KHch2|Y-h0k-o^$^^&pG!d-Lf#@*KUUuY`*YKb%Bc|7UmV_6u(o0n{D=3bK|5FpE)HL8JR=n<5$np zOfG!BT(oP#W0e04d_%g3MMM}zJ=1u__?nCnGT~|CUvJ=6zKUOOMVz6qM--Q-FQtcA zh+b7+*}%{p*PS8@_e@DQ$MdEmqqdLk7Iu7Fc9O;l7@m^(|40PqKr|~FX_a9w;$4|g zTu;Ou-Q>WtMJPP?m@P1b=Ik9f@)r2dO0axlnFC5JcBG8+v~vf~Tu}(W8YsEDyCHy9 zAGL8On#5gcKQ5t7Shtm57*pfe^VdTsx{Nz!iV^cqM_Wb2eI%Z*;gB0I**b9zt{mq-vl{$aOk->qf6pxX62+^$=Tdti^tD;jPGOXHz3(uC?**srSde(Mt(I&ej( zP!~i$h<#>nzvgV24#?>~rR>=YoW=P*fE%O<6#ixKp?CZRk#Xwhg#k2qY)W*VM}l*d zU()lzD0`aw%KBA=JryGSGQ$B=Obez$mUb@FJCAh3vXWGVBgbo6<7b3S(`1MQ%zClRI9RsYZ zfV#f2%G917#OBi9jv`Q$jht1CQhu2v_n8Q^WH0IchhW@O<<=-*B*wQYAIW$6rtB8P zS3N@Bo@PAUOZuwlXi{IT+_ZqVsf`*c5sTBsjdG%Wzr5ldsSbDdJJqGTaX46gmWYFD zbbE@??`o9zi+p6nRZErCU64t|4OG2k(p~;(W~X*(%GmB=C!L770(ZL?qc_a`j332~ zAI>g3PNKbDu@gCj#7bG^raJX``6J#suFeYuyy_+u-VMRVr%CI_c7%uT`fS(zyP^hu z9i8=jYj?{GVVp^qHna6VUt2tTpA6fG8mM_le54!6idD!65$>T}s_eV{rMfkk6`c_x zs|y7(o`uLZsGXilICLTA(4QDjlx1WMef!Q<=?7lq(|d%pq-kfUzWf~1nicdr0*rEf z@Jl!4(CvMIgPjXE{IK7#ChECJ{D8r_Wa7Pd`y_y(R?hopB?JV)(9zyi; z?yrI5OxFVO+@07^VVruo91}Wfr()tT-^E$V%D6{d8e_BI4m%L3r(6SP!KaQB`o8Fs z^P~N01{BF54;im$l~S_@Z_Y+uM^a#9S-kF0mlooBtd{jx4NLs;kJB3?xZ;X9E4;2R zR`8`8uq#Jy`N~kAI&E1pE#s;s(5<^RDP=^)S+MuZ#5>X0xmkPW4azx?mk*Yg=Kg6FujXoFh1x>D9L)UTlmFzaY#+ z9s80Qk?4eTI_h{2iDgMYQzYF*_RJga!B)Xhzh51q?~Um#A7JvzSL%wehRUT7W zF{k8yB-Y!*SD5oX6VG@?!knWr9kYJcf4p3Q?>mwmY`#~Er%0nTmr?ilJDm$+-8!2( zjoU*8A|GuH{$^GMrp}~`=Pb3#djx`^9ld+UX}*{|tqXsQy|=RiQp1yGxRCXxUbPs> zk4hyP)MF-nF`uF4l!oucd*6O{_R#O_?(gpz`@nRw zK1oj7tuR3_@pV0$KU@9TpG-lF8@Z(fy(W*sw|<&w2y8XKi!GmM!CR8Y6UsxOR#in; zqN}Qwm%EjrX73D0yTV(rPWq@n4`x^FEqE0@RF33}TDNIrxnt`QyaamRyNH^*Z7mb8 zDluioXxq^k)D%(>@|1ILCQ)SkHg#q8134FjT1i5RGVS9Qxq8iZMWN#EShyIgOuQPa zonra)9a1tr4~9I=30m4u6JPam#mY&AUw^xKFrFsAssF zCI?z$S;0nHXeqjDq(R4O50-4&2$AZW$V|!pv<)o83FUd4;?KFN+3og0GLoJxDRf)@ zsIEJS18Y;{NAC51|f3-2jG)JK+6M2bRQ`@TRw_2jnfslfMll+Jcp-q{Q5f!yNa!q zUvttUxUgd>COT9g-E^i>qa-2>2|y9`weu%5feab$;TwpH^rY!mbi~^s|Dej*(Lfz^ zc8F{c6u384+yjWeMAVs@_uN^7psZ@W110rlIGw<;l*!PKw}V9(Vkp`3R=4C9>BG_DOl-rKS%S_lY=LVs zR+L?_8~(o8;*I?b?_46YQRspvgnET+nT1I+(X2Z^wVQ1Z<56WHBm~_&m`{%M()w6) zz2r&bLIms?t2o5C*^Qri1|fznj`=4!>8>m9NtgSFm`$uet310z1*4V+z+^7OBY(`7 z>s&7$ClR{wdJCD1U10LEBj^ z_LaaU(cdg{rG~rf_~iSv->qUf{Y=@O|6O8@tbQBR3Y(^i<$Z5DspJ4tn1xZDAtL@i DVS>0r literal 0 HcmV?d00001 diff --git a/assets/static/podkova.woff2 b/assets/static/podkova.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..508f97d3eb900a6acda802777ad9b64142e959c9 GIT binary patch literal 60580 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≫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

WChu}hT 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 Zt~emFYo&}!yR5z6UO0X;|N9RXFaW>2e8>O* literal 0 HcmV?d00001 diff --git a/assets/static/style.css b/assets/static/style.css new file mode 100644 index 0000000..60c97c3 --- /dev/null +++ b/assets/static/style.css @@ -0,0 +1,105 @@ +@font-face { + font-family: "Geist"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url("./geist.woff2") format("woff2"); +} + +@font-face { + font-family: "Podkova"; + font-style: normal; + font-weight: 400 800; + font-display: swap; + src: url("./podkova.woff2") format("woff2"); +} + +@font-face { + font-family: "Iosevka Curly"; + font-style: monospace; + font-display: swap; + src: url("./iosevka-curly.woff2") format("woff2"); +} + +main { + font-family: Geist, sans-serif; + max-width: 50rem; + padding: 2rem; + margin: auto; +} + +::selection { + background: #d3869b; +} + +body { + background: #1d2021; + color: #f9f5d7; +} + +pre { + background-color: #3c3836; + padding: 1em; + border: 0; + font-family: Iosevka Curly Iaso, monospace; +} + +a, +a:active, +a:visited { + color: #b16286; + background-color: #282828; +} + +h1, +h2, +h3, +h4, +h5 { + margin-bottom: 0.1rem; + font-family: Podkova, serif; +} + +blockquote { + border-left: 1px solid #bdae93; + margin: 0.5em 10px; + padding: 0.5em 10px; +} + +footer { + text-align: center; +} + +@media (prefers-color-scheme: light) { + body { + background: #f9f5d7; + color: #1d2021; + } + + pre { + background-color: #ebdbb2; + padding: 1em; + border: 0; + } + + a, + a:active, + a:visited { + color: #b16286; + background-color: #fbf1c7; + } + + h1, + h2, + h3, + h4, + h5 { + margin-bottom: 0.1rem; + } + + blockquote { + border-left: 1px solid #655c54; + margin: 0.5em 10px; + padding: 0.5em 10px; + } +} diff --git a/away.go b/away.go new file mode 100644 index 0000000..5d4ffd5 --- /dev/null +++ b/away.go @@ -0,0 +1 @@ +package go_away diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b342086 --- /dev/null +++ b/build.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -e +set -o pipefail + +cd "$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" + +# Setup tinygo first +if [[ ! -d .bin/tinygo ]]; then + git clone --depth=1 --branch v0.37.0 https://github.com/tinygo-org/tinygo.git .bin/tinygo + pushd .bin/tinygo + git submodule update --init --recursive + + go mod download -x && go mod verify + + make binaryen STATIC=1 + make wasi-libc + + make llvm-source + make llvm-build + + make build/release +else + pushd .bin/tinygo +fi + +export TINYGOROOT="$(realpath ./build/release/tinygo/)" +export PATH="$PATH:$(realpath ./build/release/tinygo/bin/)" + +popd + +go generate ./... + +do_compress () { + find "$1" \( -type f -name "*.wasm" -o -name "*.css" -o -name "*.js" -o -name "*.mjs" \) -exec zopfli {} \; + find "$1" \( -type f -name "*.wasm" -o -name "*.css" -o -name "*.js" -o -name "*.mjs" \) -exec brotli -v -f -9 -o {}.br {} \; + #find "$1" \( -type f -name "*.wasm" -o -name "*.css" -o -name "*.js" -o -name "*.mjs" \) -exec zstd -v -f -19 -o {}.zst {} \; +} + +do_compress challenge/ +do_compress assets/ \ No newline at end of file diff --git a/challenge.go b/challenge.go new file mode 100644 index 0000000..f4fe93d --- /dev/null +++ b/challenge.go @@ -0,0 +1,171 @@ +package go_away + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/binary" + "errors" + "github.com/go-jose/go-jose/v4" + "github.com/go-jose/go-jose/v4/jwt" + "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/api" + "math/rand/v2" + "net" + "net/http" + "strings" + "time" +) + +type ChallengeInformation struct { + Name string `json:"name"` + Key []byte `json:"key"` + Result []byte `json:"result"` + + Expiry *jwt.NumericDate `json:"exp,omitempty"` + NotBefore *jwt.NumericDate `json:"nbf,omitempty"` + IssuedAt *jwt.NumericDate `json:"iat,omitempty"` +} + +func (state *State) GetRequestAddress(r *http.Request) net.IP { + //TODO: verified upstream + ipStr := r.Header.Get("X-Real-Ip") + if ipStr == "" { + ipStr = strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0] + } + if ipStr == "" { + parts := strings.Split(r.RemoteAddr, ":") + // drop port + ipStr = strings.Join(parts[:len(parts)-1], ":") + } + return net.ParseIP(ipStr) +} + +func (state *State) GetChallengeKeyForRequest(name string, until time.Time, r *http.Request) []byte { + hasher := sha256.New() + hasher.Write([]byte("challenge\x00")) + hasher.Write([]byte(name)) + hasher.Write([]byte{0}) + hasher.Write(state.GetRequestAddress(r).To16()) + hasher.Write([]byte{0}) + + // specific headers + for _, k := range []string{ + "Accept-Language", + // General browser information + "User-Agent", + "Sec-Ch-Ua", + "Sec-Ch-Ua-Platform", + } { + hasher.Write([]byte(r.Header.Get(k))) + hasher.Write([]byte{0}) + } + hasher.Write([]byte{0}) + _ = binary.Write(hasher, binary.LittleEndian, until.UTC().Unix()) + hasher.Write([]byte{0}) + hasher.Write(state.PublicKey) + hasher.Write([]byte{0}) + + return hasher.Sum(nil) +} + +func (state *State) IssueChallengeToken(name string, key, result []byte, until time.Time) (token string, err error) { + signer, err := jose.NewSigner(jose.SigningKey{ + Algorithm: jose.EdDSA, + Key: state.PrivateKey, + }, nil) + if err != nil { + return "", err + } + + expiry := jwt.NumericDate(until.Unix()) + notBefore := jwt.NumericDate(time.Now().UTC().AddDate(0, 0, -1).Unix()) + issuedAt := jwt.NumericDate(time.Now().UTC().Unix()) + + token, err = jwt.Signed(signer).Claims(ChallengeInformation{ + Name: name, + Key: key, + Result: result, + Expiry: &expiry, + NotBefore: ¬Before, + IssuedAt: &issuedAt, + }).Serialize() + if err != nil { + return "", err + } + return token, nil +} + +func (state *State) VerifyChallengeToken(name string, expectedKey []byte, r *http.Request) (ok bool, err error) { + c, ok := state.Challenges[name] + if !ok { + return false, errors.New("challenge not found") + } + + cookie, err := r.Cookie(CookiePrefix + name) + if err != nil { + return false, err + } + + token, err := jwt.ParseSigned(cookie.Value, []jose.SignatureAlgorithm{jose.EdDSA}) + if err != nil { + return false, err + } + + var i ChallengeInformation + err = token.Claims(state.PublicKey, &i) + if err != nil { + return false, err + } + + if i.Name != name { + return false, errors.New("token invalid name") + } + if i.Expiry == nil && i.Expiry.Time().Compare(time.Now()) < 0 { + return false, errors.New("token expired") + } + if i.NotBefore == nil && i.NotBefore.Time().Compare(time.Now()) > 0 { + return false, errors.New("token not valid yet") + } + + if bytes.Compare(expectedKey, i.Key) != 0 { + return false, errors.New("key mismatch") + } + + if c.Verify != nil && rand.Float64() < c.VerifyProbability { + // random spot check + if ok, err := c.Verify(expectedKey, string(i.Result)); err != nil { + return false, err + } else if !ok { + return false, errors.New("failed challenge verification") + } + } + + return true, nil +} + +func (state *State) ChallengeMod(name string, cb func(ctx context.Context, mod api.Module) error) error { + c, ok := state.Challenges[name] + if !ok { + return errors.New("challenge not found") + } + if c.RuntimeModule == nil { + return errors.New("challenge module is nil") + } + + ctx := state.WasmContext + mod, err := state.WasmRuntime.InstantiateModule( + ctx, + c.RuntimeModule, + wazero.NewModuleConfig().WithName(name).WithStartFunctions("_initialize"), + ) + if err != nil { + return err + } + defer mod.Close(ctx) + err = cb(ctx, mod) + if err != nil { + return err + } + return nil +} diff --git a/challenge/generic.go b/challenge/generic.go new file mode 100644 index 0000000..9442418 --- /dev/null +++ b/challenge/generic.go @@ -0,0 +1,74 @@ +//go:build !tinygo + +package challenge + +import ( + "context" + "encoding/json" + "errors" + "github.com/tetratelabs/wazero/api" +) + +func MakeChallengeCall(ctx context.Context, mod api.Module, in MakeChallengeInput) (*MakeChallengeOutput, error) { + makeChallengeFunc := mod.ExportedFunction("MakeChallenge") + malloc := mod.ExportedFunction("malloc") + free := mod.ExportedFunction("free") + + inData, err := json.Marshal(in) + + mallocResult, err := malloc.Call(ctx, uint64(len(inData))) + if err != nil { + return nil, err + } + defer free.Call(ctx, mallocResult[0]) + if !mod.Memory().Write(uint32(mallocResult[0]), inData) { + return nil, errors.New("could not write memory") + } + result, err := makeChallengeFunc.Call(ctx, uint64(NewAllocation(uint32(mallocResult[0]), uint32(len(inData))))) + if err != nil { + return nil, err + } + resultPtr := Allocation(result[0]) + outData, ok := mod.Memory().Read(resultPtr.Pointer(), resultPtr.Size()) + if !ok { + return nil, errors.New("could not read result") + } + defer free.Call(ctx, uint64(resultPtr.Pointer())) + + var out MakeChallengeOutput + err = json.Unmarshal(outData, &out) + if err != nil { + return nil, err + } + return &out, nil +} + +func VerifyChallengeCall(ctx context.Context, mod api.Module, in VerifyChallengeInput) (VerifyChallengeOutput, error) { + verifyChallengeFunc := mod.ExportedFunction("VerifyChallenge") + malloc := mod.ExportedFunction("malloc") + free := mod.ExportedFunction("free") + + inData, err := json.Marshal(in) + + mallocResult, err := malloc.Call(ctx, uint64(len(inData))) + if err != nil { + return VerifyChallengeOutputError, err + } + defer free.Call(ctx, mallocResult[0]) + if !mod.Memory().Write(uint32(mallocResult[0]), inData) { + return VerifyChallengeOutputError, errors.New("could not write memory") + } + result, err := verifyChallengeFunc.Call(ctx, uint64(NewAllocation(uint32(mallocResult[0]), uint32(len(inData))))) + if err != nil { + return VerifyChallengeOutputError, err + } + + return VerifyChallengeOutput(result[0]), nil +} + +func PtrToBytes(ptr uint32, size uint32) []byte { panic("not implemented") } +func BytesToPtr(s []byte) (uint32, uint32) { panic("not implemented") } +func BytesToLeakedPtr(s []byte) (uint32, uint32) { panic("not implemented") } +func PtrToString(ptr uint32, size uint32) string { panic("not implemented") } +func StringToPtr(s string) (uint32, uint32) { panic("not implemented") } +func StringToLeakedPtr(s string) (uint32, uint32) { panic("not implemented") } diff --git a/challenge/interface.go b/challenge/interface.go new file mode 100644 index 0000000..3828191 --- /dev/null +++ b/challenge/interface.go @@ -0,0 +1,123 @@ +package challenge + +import ( + "crypto/sha256" + "encoding/json" + "fmt" + "net/http" +) + +const ChallengeKeySize = sha256.Size + +type MakeChallenge func(in Allocation) (out Allocation) + +type Allocation uint64 + +func NewAllocation(ptr, size uint32) Allocation { + return Allocation((uint64(ptr) << uint64(32)) | uint64(size)) +} + +func (p Allocation) Pointer() uint32 { + return uint32(p >> 32) +} +func (p Allocation) Size() uint32 { + return uint32(p) +} + +func MakeChallengeDecode(callback func(in MakeChallengeInput, out *MakeChallengeOutput), in Allocation) (out Allocation) { + outStruct := &MakeChallengeOutput{} + var inStruct MakeChallengeInput + + inData := PtrToBytes(in.Pointer(), in.Size()) + + err := json.Unmarshal(inData, &inStruct) + if err != nil { + outStruct.Code = 500 + outStruct.Error = err.Error() + } else { + outStruct.Code = 200 + outStruct.Headers = make(http.Header) + + func() { + // encapsulate err + defer func() { + if recovered := recover(); recovered != nil { + if outStruct.Code == 200 { + outStruct.Code = 500 + } + if err, ok := recovered.(error); ok { + outStruct.Error = err.Error() + } else { + outStruct.Error = fmt.Sprintf("%v", recovered) + } + } + }() + callback(inStruct, outStruct) + }() + } + + if len(outStruct.Headers) == 0 { + outStruct.Headers = nil + } + + outData, err := json.Marshal(outStruct) + if err != nil { + panic(err) + } + + return NewAllocation(BytesToLeakedPtr(outData)) +} + +func VerifyChallengeDecode(callback func(in VerifyChallengeInput) VerifyChallengeOutput, in Allocation) (out VerifyChallengeOutput) { + var inStruct VerifyChallengeInput + + inData := PtrToBytes(in.Pointer(), in.Size()) + + err := json.Unmarshal(inData, &inStruct) + if err != nil { + return VerifyChallengeOutputError + } else { + func() { + // encapsulate err + defer func() { + if recovered := recover(); recovered != nil { + out = VerifyChallengeOutputError + } + }() + out = callback(inStruct) + }() + } + + return out +} + +type MakeChallengeInput struct { + Key []byte `json:"key"` + + Parameters map[string]string `json:"parameters,omitempty"` + + Headers http.Header `json:"headers,omitempty"` + Data []byte `json:"data,omitempty"` +} + +type MakeChallengeOutput struct { + Data []byte `json:"data"` + Code int `json:"code"` + Headers http.Header `json:"headers,omitempty"` + Error string `json:"error,omitempty"` +} + +type VerifyChallengeInput struct { + Key []byte `json:"key"` + Parameters map[string]string `json:"parameters,omitempty"` + + Result []byte `json:"result,omitempty"` +} + +type VerifyChallengeOutput uint64 + +const ( + VerifyChallengeOutputOK = VerifyChallengeOutput(iota) + VerifyChallengeOutputFailed + VerifyChallengeOutputError +) diff --git a/challenge/js-pow-sha256/runtime/.gitignore b/challenge/js-pow-sha256/runtime/.gitignore new file mode 100644 index 0000000..917660a --- /dev/null +++ b/challenge/js-pow-sha256/runtime/.gitignore @@ -0,0 +1 @@ +*.wasm \ No newline at end of file diff --git a/challenge/js-pow-sha256/runtime/runtime.go b/challenge/js-pow-sha256/runtime/runtime.go new file mode 100644 index 0000000..07cc988 --- /dev/null +++ b/challenge/js-pow-sha256/runtime/runtime.go @@ -0,0 +1,92 @@ +package main + +import ( + "crypto/sha256" + "crypto/subtle" + "encoding/binary" + "encoding/hex" + "encoding/json" + "git.gammaspectra.live/git/go-away/challenge" + "strconv" + "strings" +) + +//go:generate tinygo build -target wasip1 -buildmode=c-shared -scheduler=none -gc=leaking -o runtime.wasm runtime.go +func main() { + +} + +func getChallenge(key []byte, params map[string]string) ([]byte, uint64) { + difficulty := uint64(5) + var err error + if diffStr, ok := params["difficulty"]; ok { + difficulty, err = strconv.ParseUint(diffStr, 10, 64) + if err != nil { + panic(err) + } + } + hasher := sha256.New() + hasher.Write(binary.LittleEndian.AppendUint64(nil, difficulty)) + hasher.Write(key) + return hasher.Sum(nil), difficulty +} + +//go:wasmexport MakeChallenge +func MakeChallenge(in challenge.Allocation) (out challenge.Allocation) { + return challenge.MakeChallengeDecode(func(in challenge.MakeChallengeInput, out *challenge.MakeChallengeOutput) { + type Result struct { + Challenge string `json:"challenge"` + Difficulty uint64 `json:"difficulty"` + } + + challenge, difficulty := getChallenge(in.Key, in.Parameters) + + data, err := json.Marshal(Result{ + Challenge: hex.EncodeToString(challenge), + Difficulty: difficulty, + }) + if err != nil { + panic(err) + } + out.Data = data + out.Headers.Set("Content-Type", "text/javascript; charset=utf-8") + }, in) +} + +//go:wasmexport VerifyChallenge +func VerifyChallenge(in challenge.Allocation) (out challenge.VerifyChallengeOutput) { + return challenge.VerifyChallengeDecode(func(in challenge.VerifyChallengeInput) challenge.VerifyChallengeOutput { + c, difficulty := getChallenge(in.Key, in.Parameters) + + type Result struct { + Hash string `json:"hash"` + Nonce uint64 `json:"nonce"` + } + var result Result + err := json.Unmarshal(in.Result, &result) + + if err != nil { + panic(err) + } + + if !strings.HasPrefix(result.Hash, strings.Repeat("0", int(difficulty))) { + return challenge.VerifyChallengeOutputFailed + } + + resultBinary, err := hex.DecodeString(result.Hash) + if err != nil { + panic(err) + } + + buf := make([]byte, 0, len(c)+8) + buf = append(buf, c[:]...) + buf = binary.LittleEndian.AppendUint64(buf, result.Nonce) + calculated := sha256.Sum256(buf) + + if subtle.ConstantTimeCompare(resultBinary, calculated[:]) != 1 { + return challenge.VerifyChallengeOutputFailed + } + + return challenge.VerifyChallengeOutputOK + }, in) +} diff --git a/challenge/js-pow-sha256/static/load.mjs b/challenge/js-pow-sha256/static/load.mjs new file mode 100644 index 0000000..d098de4 --- /dev/null +++ b/challenge/js-pow-sha256/static/load.mjs @@ -0,0 +1,125 @@ +let _worker; +let _webWorkerURL; +let _challenge; +let _difficulty; + +async function setup(config) { + + const status = document.getElementById('status'); + const image = document.getElementById('image'); + const title = document.getElementById('title'); + const spinner = document.getElementById('spinner'); + + const { challenge, difficulty } = await fetch(config.Path + "/make-challenge", { method: "POST" }) + .then(r => { + if (!r.ok) { + throw new Error("Failed to fetch config"); + } + return r.json(); + }) + .catch(err => { + throw err; + }); + + _challenge = challenge; + _difficulty = difficulty; + + _webWorkerURL = URL.createObjectURL(new Blob([ + '(', processTask(challenge, difficulty), ')()' + ], { type: 'application/javascript' })); + _worker = new Worker(_webWorkerURL); + + return `Difficulty ${difficulty}` +} + +function challenge() { + return new Promise((resolve, reject) => { + _worker.onmessage = (event) => { + _worker.terminate(); + resolve(event.data); + }; + + _worker.onerror = (event) => { + _worker.terminate(); + reject(); + }; + + _worker.postMessage({ + challenge: _challenge, + difficulty: _difficulty, + }); + + URL.revokeObjectURL(_webWorkerURL); + }); +} + +function processTask() { + return function () { + + const decodeHex = (str) => { + let result = new Uint8Array(str.length>>1) + for (let i = 0; i < str.length; i += 2){ + result[i>>1] = parseInt(str.substring(i, i + 2), 16) + } + + return result + } + + const encodeHex = (buf) => { + return buf.reduce((a, b) => a + b.toString(16).padStart(2, '0'), '') + } + + const lessThan = (buf, target) => { + for(let i = 0; i < buf.length; ++i){ + if (buf[i] < target[i]){ + return true; + } else if (buf[i] > target[i]){ + return false; + } + } + + return false + } + + const increment = (number) => { + for ( let i = 0; i < number.length; i++ ) { + if(number[i]===255){ + number[i] = 0; + } else { + number[i]++; + break; + } + } + } + + addEventListener('message', async (event) => { + let data = decodeHex(event.data.challenge); + let target = decodeHex("0".repeat(event.data.difficulty) + "f".repeat(64 - event.data.difficulty)); + + let nonce = new Uint8Array(8); + let buf = new Uint8Array(data.length + nonce.length); + buf.set(data, 0); + + while(true) { + buf.set(nonce, data.length); + let result = new Uint8Array(await crypto.subtle.digest("SHA-256", buf)) + + if (lessThan(result, target)){ + const nonceNumber = Number(new BigUint64Array(nonce.buffer).at(0)) + postMessage({ + result: { + hash: encodeHex(result), + nonce: nonceNumber, + }, + info: `iterations ${nonceNumber}`, + }); + return + } + increment(nonce) + } + + }); + }.toString(); +} + +export { setup, challenge } \ No newline at end of file diff --git a/challenge/tinygo.go b/challenge/tinygo.go new file mode 100644 index 0000000..f75ffa5 --- /dev/null +++ b/challenge/tinygo.go @@ -0,0 +1,59 @@ +//go:build tinygo + +package challenge + +// #include +import "C" +import ( + "unsafe" +) + +// PtrToBytes returns a byte slice from WebAssembly compatible numeric types +// representing its pointer and length. +func PtrToBytes(ptr uint32, size uint32) []byte { + return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(ptr))), size) +} + +// BytesToPtr returns a pointer and size pair for the given byte slice in a way +// compatible with WebAssembly numeric types. +// The returned pointer aliases the slice hence the slice must be kept alive +// until ptr is no longer needed. +func BytesToPtr(s []byte) (uint32, uint32) { + ptr := unsafe.Pointer(unsafe.SliceData(s)) + return uint32(uintptr(ptr)), uint32(len(s)) +} + +// BytesToLeakedPtr returns a pointer and size pair for the given byte slice in a way +// compatible with WebAssembly numeric types. +// The pointer is not automatically managed by TinyGo hence it must be freed by the host. +func BytesToLeakedPtr(s []byte) (uint32, uint32) { + size := C.ulong(len(s)) + ptr := unsafe.Pointer(C.malloc(size)) + copy(unsafe.Slice((*byte)(ptr), size), s) + return uint32(uintptr(ptr)), uint32(size) +} + +// PtrToString returns a string from WebAssembly compatible numeric types +// representing its pointer and length. +func PtrToString(ptr uint32, size uint32) string { + return unsafe.String((*byte)(unsafe.Pointer(uintptr(ptr))), size) +} + +// StringToPtr returns a pointer and size pair for the given string in a way +// compatible with WebAssembly numeric types. +// The returned pointer aliases the string hence the string must be kept alive +// until ptr is no longer needed. +func StringToPtr(s string) (uint32, uint32) { + ptr := unsafe.Pointer(unsafe.StringData(s)) + return uint32(uintptr(ptr)), uint32(len(s)) +} + +// StringToLeakedPtr returns a pointer and size pair for the given string in a way +// compatible with WebAssembly numeric types. +// The pointer is not automatically managed by TinyGo hence it must be freed by the host. +func StringToLeakedPtr(s string) (uint32, uint32) { + size := C.ulong(len(s)) + ptr := unsafe.Pointer(C.malloc(size)) + copy(unsafe.Slice((*byte)(ptr), size), s) + return uint32(uintptr(ptr)), uint32(size) +} diff --git a/cmd/away.go b/cmd/away.go new file mode 100644 index 0000000..f36f4a6 --- /dev/null +++ b/cmd/away.go @@ -0,0 +1,150 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + go_away "git.gammaspectra.live/git/go-away" + "gopkg.in/yaml.v3" + "log" + "log/slog" + "net" + "net/http" + "net/http/httputil" + "net/url" + "os" + "strconv" +) + +func makeReverseProxy(target string) (http.Handler, error) { + u, err := url.Parse(target) + if err != nil { + return nil, fmt.Errorf("failed to parse target URL: %w", err) + } + + transport := http.DefaultTransport.(*http.Transport).Clone() + + // https://github.com/oauth2-proxy/oauth2-proxy/blob/4e2100a2879ef06aea1411790327019c1a09217c/pkg/upstream/http.go#L124 + if u.Scheme == "unix" { + // clean path up so we don't use the socket path in proxied requests + addr := u.Path + u.Path = "" + // tell transport how to dial unix sockets + transport.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) { + dialer := net.Dialer{} + return dialer.DialContext(ctx, "unix", addr) + } + // tell transport how to handle the unix url scheme + transport.RegisterProtocol("unix", go_away.UnixRoundTripper{Transport: transport}) + } + + rp := httputil.NewSingleHostReverseProxy(u) + rp.Transport = transport + + return rp, nil +} + +func setupListener(network, address, socketMode string) (net.Listener, string) { + formattedAddress := "" + switch network { + case "unix": + formattedAddress = "unix:" + address + case "tcp": + formattedAddress = "http://localhost" + address + default: + formattedAddress = fmt.Sprintf(`(%s) %s`, network, address) + } + + listener, err := net.Listen(network, address) + if err != nil { + log.Fatal(fmt.Errorf("failed to bind to %s: %w", formattedAddress, err)) + } + + // additional permission handling for unix sockets + if network == "unix" { + mode, err := strconv.ParseUint(socketMode, 8, 0) + if err != nil { + listener.Close() + log.Fatal(fmt.Errorf("could not parse socket mode %s: %w", socketMode, err)) + } + + err = os.Chmod(address, os.FileMode(mode)) + if err != nil { + listener.Close() + log.Fatal(fmt.Errorf("could not change socket mode: %w", err)) + } + } + + return listener, formattedAddress +} + +func main() { + bind := flag.String("bind", ":8080", "network address to bind HTTP to") + bindNetwork := flag.String("bind-network", "tcp", "network family to bind HTTP to, e.g. unix, tcp") + socketMode := flag.String("socket-mode", "0770", "socket mode (permissions) for unix domain sockets.") + + slogLevel := flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)") + + target := flag.String("target", "http://localhost:80", "target to reverse proxy to") + + policyFile := flag.String("policy", "", "path to policy YAML file") + + flag.Parse() + + _, _, _, _ = bind, bindNetwork, socketMode, target + + { + var programLevel slog.Level + if err := (&programLevel).UnmarshalText([]byte(*slogLevel)); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "invalid log level %s: %v, using info\n", *slogLevel, err) + programLevel = slog.LevelInfo + } + + leveler := &slog.LevelVar{} + leveler.Set(programLevel) + + h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ + AddSource: true, + Level: leveler, + }) + slog.SetDefault(slog.New(h)) + } + + policyData, err := os.ReadFile(*policyFile) + if err != nil { + log.Fatal(fmt.Errorf("failed to read policy file: %w", err)) + } + + var policy go_away.Policy + + if err = yaml.Unmarshal(policyData, &policy); err != nil { + log.Fatal(fmt.Errorf("failed to parse policy file: %w", err)) + } + + backend, err := makeReverseProxy(*target) + if err != nil { + log.Fatal(fmt.Errorf("failed to create reverse proxy for %s: %w", *target, err)) + } + + state, err := go_away.NewState(policy, "git.gammaspectra.live/git/go-away/cmd", backend) + + if err != nil { + log.Fatal(fmt.Errorf("failed to create state: %w", err)) + } + + listener, listenUrl := setupListener(*bindNetwork, *bind, *socketMode) + slog.Info( + "listening", + "url", listenUrl, + "target", *target, + ) + + server := http.Server{ + Handler: state, + } + + if err := server.Serve(listener); !errors.Is(err, http.ErrServerClosed) { + log.Fatal(err) + } +} diff --git a/condition.go b/condition.go new file mode 100644 index 0000000..7a02f92 --- /dev/null +++ b/condition.go @@ -0,0 +1,53 @@ +package go_away + +import ( + "fmt" + "github.com/google/cel-go/cel" + "strings" +) + +type Condition struct { + Expression *cel.Ast +} + +const ( + OperatorOr = "||" + OperatorAnd = "&&" +) + +func ConditionFromStrings(env *cel.Env, operator string, conditions ...string) (*cel.Ast, error) { + var asts []*cel.Ast + for _, c := range conditions { + ast, issues := env.Compile(c) + if issues != nil && issues.Err() != nil { + return nil, fmt.Errorf("condition %s: %s", issues.Err(), c) + } + asts = append(asts, ast) + } + + return MergeConditions(env, operator, asts...) +} + +func MergeConditions(env *cel.Env, operator string, conditions ...*cel.Ast) (*cel.Ast, error) { + if len(conditions) == 0 { + return nil, nil + } else if len(conditions) == 1 { + return conditions[0], nil + } + var asts []string + for _, c := range conditions { + ast, err := cel.AstToString(c) + if err != nil { + return nil, err + } + asts = append(asts, "("+ast+")") + } + + condition := strings.Join(asts, " "+operator+" ") + ast, issues := env.Compile(condition) + if issues != nil && issues.Err() != nil { + return nil, issues.Err() + } + + return ast, nil +} diff --git a/cookie.go b/cookie.go new file mode 100644 index 0000000..dea995c --- /dev/null +++ b/cookie.go @@ -0,0 +1,27 @@ +package go_away + +import ( + "net/http" + "time" +) + +var CookiePrefix = ".go-away-" + +func SetCookie(name, value string, expiry time.Time, w http.ResponseWriter) { + http.SetCookie(w, &http.Cookie{ + Name: name, + Value: value, + Expires: expiry, + SameSite: http.SameSiteLaxMode, + Path: "/", + }) +} +func ClearCookie(name string, w http.ResponseWriter) { + http.SetCookie(w, &http.Cookie{ + Name: name, + Value: "", + Expires: time.Now().Add(-1 * time.Hour), + MaxAge: -1, + SameSite: http.SameSiteLaxMode, + }) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9aa6c9a --- /dev/null +++ b/go.mod @@ -0,0 +1,44 @@ +module git.gammaspectra.live/git/go-away + +go 1.24 + +require ( + codeberg.org/meta/gzipped/v2 v2.0.0-20231111234332-aa70c3194756 + github.com/go-jose/go-jose/v4 v4.0.5 + github.com/google/cel-go v0.24.1 + github.com/itchyny/gojq v0.12.17 + github.com/tetratelabs/wazero v1.9.0 + github.com/yl2chen/cidranger v1.0.2 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + cel.dev/expr v0.19.1 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982 // indirect + github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 // indirect + github.com/creack/goselect v0.1.2 // indirect + github.com/gofrs/flock v0.8.1 // indirect + github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf // indirect + github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect + github.com/itchyny/timefmt-go v0.1.6 // indirect + github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43 // indirect + github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-tty v0.0.4 // indirect + github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tinygo-org/tinygo v0.37.0 // indirect + go.bug.st/serial v1.6.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect + google.golang.org/protobuf v1.34.2 // indirect + tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9 // indirect +) + +tool github.com/tinygo-org/tinygo diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a0a82ee --- /dev/null +++ b/go.sum @@ -0,0 +1,99 @@ +cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4= +cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +codeberg.org/meta/gzipped/v2 v2.0.0-20231111234332-aa70c3194756 h1:bDqEUEYt4UJy8mfLCZeJuXx+xNJvdqTbkE4Ci11NQYU= +codeberg.org/meta/gzipped/v2 v2.0.0-20231111234332-aa70c3194756/go.mod h1:aJ/ghJW7viYfwZ6OizDst+uJgbb6r/Hvoqhmi1OPTTw= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982 h1:cD7QfvrJdYmBw2tFP/VyKPT8ZESlcrwSwo7SvH9Y4dc= +github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw= +github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI= +github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= +github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= +github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/google/cel-go v0.24.1 h1:jsBCtxG8mM5wiUJDSGUqU0K7Mtr3w7Eyv00rw4DiZxI= +github.com/google/cel-go v0.24.1/go.mod h1:Hdf9TqOaTNSFQA1ybQaRqATVoK7m/zcf7IMhGXP5zI8= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= +github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= +github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= +github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg= +github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY= +github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q= +github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg= +github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43 h1:Pdirg1gwhEcGjMLyuSxGn9664p+P8J9SrfMgpFwrDyg= +github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43/go.mod h1:ahLMuLCUyDdXqtqGyuwGev7/PGtO7r7ocvdwDuEN/3E= +github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw= +github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E= +github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= +github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= +github.com/tinygo-org/tinygo v0.37.0 h1:N6ThUAOfgqcsZmcbkFBIJQSTBe4d/JFyTSbEjIy9yeU= +github.com/tinygo-org/tinygo v0.37.0/go.mod h1:k3d5kfRLHcJ+bvZLe/VOlF00NVd/cvjgIEIyManFmF0= +github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= +github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= +go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A= +go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 h1:MMsD8mMfluf/578+3wrTn22pjI/Xkzm+gPW47SYfspY= +golang.org/x/tools v0.22.1-0.20240621165957-db513b091504/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9 h1:rMvEzuCYjyiR+pmdiCVWTQw3L6VqiSIXoL19I3lYufE= +tinygo.org/x/go-llvm v0.0.0-20250119132755-9dca92dfb4f9/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= diff --git a/http.go b/http.go new file mode 100644 index 0000000..2c83670 --- /dev/null +++ b/http.go @@ -0,0 +1,221 @@ +package go_away + +import ( + "codeberg.org/meta/gzipped/v2" + "crypto/rand" + "embed" + "encoding/base64" + "errors" + "fmt" + "github.com/google/cel-go/common/types" + "html/template" + "net/http" + "path/filepath" + "strings" + "time" +) + +//go:embed assets +var assetsFs embed.FS + +//go:embed challenge +var challengesFs embed.FS + +//go:embed templates +var templatesFs embed.FS + +var templates map[string]*template.Template + +var cacheBust string + +// DefaultValidity TODO: adjust +const DefaultValidity = time.Hour * 24 * 7 + +func init() { + + buf := make([]byte, 16) + _, _ = rand.Read(buf) + cacheBust = base64.RawURLEncoding.EncodeToString(buf) + + templates = make(map[string]*template.Template) + + dir, err := templatesFs.ReadDir("templates") + if err != nil { + panic(err) + } + for _, e := range dir { + if e.IsDir() { + continue + } + data, err := templatesFs.ReadFile(filepath.Join("templates", e.Name())) + if err != nil { + panic(err) + } + tpl := template.New(e.Name()) + _, err = tpl.Parse(string(data)) + if err != nil { + panic(err) + } + templates[e.Name()] = tpl + } +} + +func (state *State) handleRequest(w http.ResponseWriter, r *http.Request) { + + //TODO better matcher! combo ast? + env := map[string]any{ + "remoteAddress": state.GetRequestAddress(r), + "userAgent": r.UserAgent(), + "path": r.URL.Path, + "query": func() map[string]string { + result := make(map[string]string) + for k, v := range r.URL.Query() { + result[k] = strings.Join(v, ",") + } + return result + }(), + "headers": func() map[string]string { + result := make(map[string]string) + for k, v := range r.Header { + result[k] = strings.Join(v, ",") + } + return result + }(), + } + + for _, rule := range state.Rules { + if out, _, err := rule.Program.Eval(env); err != nil { + //TODO error + panic(err) + } else if out != nil && out.Type() == types.BoolType { + if out.Equal(types.True) == types.True { + switch rule.Action { + default: + panic(fmt.Errorf("unknown action %s", rule.Action)) + case PolicyRuleActionPASS: + //fallback, proxy! + state.Backend.ServeHTTP(w, r) + return + case PolicyRuleActionCHALLENGE: + expiry := time.Now().UTC().Add(DefaultValidity).Round(DefaultValidity) + + for _, challengeName := range rule.Challenges { + key := state.GetChallengeKeyForRequest(challengeName, expiry, r) + ok, err := state.VerifyChallengeToken(challengeName, key, r) + if !ok || err != nil { + if !errors.Is(err, http.ErrNoCookie) { + ClearCookie(CookiePrefix+challengeName, w) + } + } else { + // we passed the challenge! + //TODO log? + state.Backend.ServeHTTP(w, r) + return + } + } + + // none matched, issue first challenge in priority + for _, challengeName := range rule.Challenges { + c := state.Challenges[challengeName] + if c.Challenge != nil { + result := c.Challenge(w, r, state.GetChallengeKeyForRequest(challengeName, expiry, r), expiry) + switch result { + case ChallengeResultStop: + return + case ChallengeResultContinue: + continue + case ChallengeResultPass: + // we pass the challenge early! + state.Backend.ServeHTTP(w, r) + return + } + } else { + panic("challenge not found") + } + } + case PolicyRuleActionDENY: + //TODO: config error code + http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) + return + case PolicyRuleActionBLOCK: + //TODO: config error code + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + } + } + } +} + +func (state *State) setupRoutes() error { + + state.Mux.HandleFunc("/", state.handleRequest) + + state.Mux.Handle("GET "+state.UrlPath+"/assets/", http.StripPrefix(state.UrlPath, gzipped.FileServer(gzipped.FS(assetsFs)))) + + for challengeName, c := range state.Challenges { + if c.Static != nil { + state.Mux.Handle("GET "+c.Path+"/static/", c.Static) + } + + if c.ChallengeScript != nil { + state.Mux.Handle("GET "+c.ChallengeScriptPath, c.ChallengeScript) + } + + if c.MakeChallenge != nil { + state.Mux.Handle(fmt.Sprintf("POST %s/make-challenge", c.Path), c.MakeChallenge) + } + + if c.Verify != nil { + state.Mux.HandleFunc(fmt.Sprintf("GET %s/verify-challenge", c.Path), func(w http.ResponseWriter, r *http.Request) { + err := func() (err error) { + expiry := time.Now().UTC().Add(DefaultValidity).Round(DefaultValidity) + key := state.GetChallengeKeyForRequest(challengeName, expiry, r) + result := []byte(r.FormValue("result")) + + if ok, err := c.Verify(key, string(result)); err != nil { + return err + } else if !ok { + ClearCookie(CookiePrefix+challengeName, w) + http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) + return nil + } + + token, err := state.IssueChallengeToken(challengeName, key, result, expiry) + if err != nil { + ClearCookie(CookiePrefix+challengeName, w) + } else { + SetCookie(CookiePrefix+challengeName, token, expiry, w) + } + + http.Redirect(w, r, r.FormValue("redirect"), http.StatusTemporaryRedirect) + return nil + }() + if err != nil { + ClearCookie(CookiePrefix+challengeName, w) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + }) + + } + } + + return nil +} + +// UnixRoundTripper https://github.com/oauth2-proxy/oauth2-proxy/blob/master/pkg/upstream/http.go#L124 +type UnixRoundTripper struct { + Transport *http.Transport +} + +// RoundTrip set bare minimum stuff +func (t UnixRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + req = req.Clone(req.Context()) + if req.Host == "" { + req.Host = "localhost" + } + req.URL.Host = req.Host // proxy error: no Host in request URL + req.URL.Scheme = "http" // make http.Transport happy and avoid an infinite recursion + return t.Transport.RoundTrip(req) +} diff --git a/policy.go b/policy.go new file mode 100644 index 0000000..7b639cf --- /dev/null +++ b/policy.go @@ -0,0 +1,188 @@ +package go_away + +import ( + "encoding/json" + "errors" + "fmt" + "github.com/itchyny/gojq" + "io" + "net" + "net/http" + "os" + "regexp" +) + +func parseCIDROrIP(value string) (net.IPNet, error) { + _, ipNet, err := net.ParseCIDR(value) + if err != nil { + ip := net.ParseIP(value) + if ip == nil { + return net.IPNet{}, fmt.Errorf("failed to parse CIDR: %s", err) + } + + if ip4 := ip.To4(); ip4 != nil { + return net.IPNet{ + IP: ip4, + // single ip + Mask: net.CIDRMask(len(ip4)*8, len(ip4)*8), + }, nil + } + return net.IPNet{ + IP: ip, + // single ip + Mask: net.CIDRMask(len(ip)*8, len(ip)*8), + }, nil + } else if ipNet != nil { + return *ipNet, nil + } else { + return net.IPNet{}, errors.New("invalid CIDR") + } +} + +type Policy struct { + // UserAgents map of a list of user-agent regex + UserAgents map[string][]string `yaml:"user-agents"` + // Networks map of networks and prefixes to be loaded + Networks map[string][]PolicyNetwork `yaml:"networks"` + + Conditions map[string][]string `yaml:"conditions"` + + Challenges map[string]PolicyChallenge `yaml:"challenges"` + + Rules []PolicyRule `yaml:"rules"` +} + +type PolicyRuleAction string + +const ( + PolicyRuleActionPASS PolicyRuleAction = "PASS" + PolicyRuleActionDENY PolicyRuleAction = "DENY" + PolicyRuleActionBLOCK PolicyRuleAction = "BLOCK" + PolicyRuleActionCHALLENGE PolicyRuleAction = "CHALLENGE" +) + +type PolicyRule struct { + Name string `yaml:"name"` + Conditions []string `yaml:"conditions"` + + Action string `yaml:"action"` + + Challenges []string `yaml:"challenges"` +} + +type PolicyChallenge struct { + Mode string `yaml:"mode"` + Asset *string `yaml:"asset,omitempty"` + Url *string `yaml:"url,omitempty"` + + Parameters map[string]string `json:"parameters,omitempty"` + Runtime struct { + Mode string `yaml:"mode,omitempty"` + Asset string `yaml:"asset,omitempty"` + Probability float64 `yaml:"probability,omitempty"` + } `yaml:"runtime"` +} + +type PolicyNetwork struct { + Url *string `yaml:"url,omitempty"` + File *string `yaml:"file,omitempty"` + + JqPath *string `yaml:"jq-path,omitempty"` + Regex *string `yaml:"regex,omitempty"` + + Prefixes []string `yaml:"prefixes,omitempty"` +} + +func (n PolicyNetwork) FetchPrefixes() (output []net.IPNet, err error) { + if len(n.Prefixes) > 0 { + for _, prefix := range n.Prefixes { + ipNet, err := parseCIDROrIP(prefix) + if err != nil { + return nil, err + } + output = append(output, ipNet) + } + } + + var reader io.Reader + if n.Url != nil { + response, err := http.DefaultClient.Get(*n.Url) + if err != nil { + return nil, err + } + defer response.Body.Close() + if response.StatusCode != 200 { + return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode) + } + reader = response.Body + } else if n.File != nil { + file, err := os.Open(*n.File) + if err != nil { + return nil, err + } + defer file.Close() + reader = file + } else { + if len(output) > 0 { + return output, nil + } + return nil, errors.New("no url, file or prefixes specified") + } + + data, err := io.ReadAll(reader) + if err != nil { + return nil, err + } + + if n.JqPath != nil { + var jsonData any + err = json.Unmarshal(data, &jsonData) + if err != nil { + return nil, err + } + + query, err := gojq.Parse(*n.JqPath) + if err != nil { + return nil, err + } + iter := query.Run(jsonData) + for { + value, more := iter.Next() + if !more { + break + } + + if strValue, ok := value.(string); ok { + ipNet, err := parseCIDROrIP(strValue) + if err != nil { + return nil, err + } + output = append(output, ipNet) + } else { + return nil, fmt.Errorf("invalid value from jq-query: %v", value) + } + } + return output, nil + } else if n.Regex != nil { + expr, err := regexp.Compile(*n.Regex) + if err != nil { + return nil, err + } + prefixName := expr.SubexpIndex("prefix") + if prefixName == -1 { + return nil, fmt.Errorf("invalid regex %q: could not find prefix named match", *n.Regex) + } + matches := expr.FindAllSubmatch(data, -1) + for _, match := range matches { + matchName := string(match[prefixName]) + ipNet, err := parseCIDROrIP(matchName) + if err != nil { + return nil, err + } + output = append(output, ipNet) + } + } else { + return nil, errors.New("no jq-path or regex specified") + } + return output, nil +} diff --git a/policy.yml b/policy.yml new file mode 100644 index 0000000..f5df8ee --- /dev/null +++ b/policy.yml @@ -0,0 +1,150 @@ +# Define groups of useragents to use later below for matching +user-agents: + default-browser: + - "^Mozilla/" + - "^Opera/" + bad-crawlers: + - "Amazonbot" + headless-browser: + - "HeadlessChrome" + - "HeadlessChromium" + - "^Lightpanda/" + - "^$" + rss: + - "FeedFetcher-Google" + git: + - "^git/" + - "^go-git/" + - "^JGit[/-]" + - "^GoModuleMirror/" + +# Define networks to be used later below +networks: + # todo: support ASN lookups + huawei-cloud: + # AS136907 + - url: https://raw.githubusercontent.com/ipverse/asn-ip/refs/heads/master/as/136907/aggregated.json + jq-path: '.subnets.ipv4[], .subnets.ipv6[]' + alibaba-cloud: + # AS45102 + - url: https://raw.githubusercontent.com/ipverse/asn-ip/refs/heads/master/as/45102/aggregated.json + jq-path: '.subnets.ipv4[], .subnets.ipv6[]' + googlebot: + - url: https://developers.google.com/static/search/apis/ipranges/googlebot.json + jq-path: '(.prefixes[] | select(has("ipv4Prefix")) | .ipv4Prefix), (.prefixes[] | select(has("ipv6Prefix")) | .ipv6Prefix)' + bingbot: + - url: https://www.bing.com/toolbox/bingbot.json + jq-path: '(.prefixes[] | select(has("ipv4Prefix")) | .ipv4Prefix), (.prefixes[] | select(has("ipv6Prefix")) | .ipv6Prefix)' + qwantbot: + - url: https://help.qwant.com/wp-content/uploads/sites/2/2025/01/qwantbot.json + jq-path: '(.prefixes[] | select(has("ipv4Prefix")) | .ipv4Prefix), (.prefixes[] | select(has("ipv6Prefix")) | .ipv6Prefix)' + duckduckbot: + - url: https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot/ + regex: "

  • (?P[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)
  • " + yandexbot: + # todo: detected as bot + # - url: https://yandex.com/ips + # regex: "(?P(([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)|([0-9a-f:]+::))/[0-9]+)[ \\\\t]*
    " + - prefixes: + - "5.45.192.0/18" + - "5.255.192.0/18" + - "37.9.64.0/18" + - "37.140.128.0/18" + - "77.88.0.0/18" + - "84.252.160.0/19" + - "87.250.224.0/19" + - "90.156.176.0/22" + - "93.158.128.0/18" + - "95.108.128.0/17" + - "141.8.128.0/18" + - "178.154.128.0/18" + - "185.32.187.0/24" + - "2a02:6b8::/29" + kagibot: + - url: https://kagi.com/bot + regex: "\\n(?P[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+) " + cloudflare: + - url: https://www.cloudflare.com/ips-v4 + regex: "(?P[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+/[0-9]+)" + - url: https://www.cloudflare.com/ips-v6 + regex: "(?P[0-9a-f:]+::/[0-9]+)" + + +conditions: + # Checks to detect a headless chromium via headers only + is-headless-chromium: + - 'userAgent.contains("HeadlessChrome") || userAgent.contains("HeadlessChromium")' + - 'headers["Sec-Ch-Ua"].contains("HeadlessChrome") || headers["Sec-Ch-Ua"].contains("HeadlessChromium")' + - '(userAgent.contains("Chrome/") || userAgent.contains("Chromium/")) && (headers["Accept-Language"] == "" || headers["Accept-Encoding"] == "")' + is-static-asset: + - 'path == "/robots.txt"' + - 'path == "/favicon.ico"' + - 'path == "/apple-touch-icon.png"' + - 'path == "/apple-touch-icon-precomposed.png"' + - 'path.startsWith("/assets/")' + - 'path.startsWith("/repo-avatars/")' + - 'path.startsWith("/avatars/")' + - 'path.startsWith("/avatar/")' + + +# todo: define interface +challenges: + js-pow-sha256: + # Asset must be under challenges/{name}/static/{asset} + # Other files here will be available under that path + mode: js + asset: load.mjs + parameters: + difficulty: 4 + runtime: + mode: wasm + # Verify must be under challenges/{name}/runtime/{asset} + asset: runtime.wasm + probability: 0.02 + + # Challenges with a cookie, self redirect + self-cookie: + mode: "cookie" + + # Challenges with a redirect via header + self-header-refresh: + mode: "header-refresh" + runtime: + # verifies that result = key + mode: "key" + probability: 0.1 + + # Challenges with a redirect via meta + self-meta-refresh: + mode: "meta-refresh" + runtime: + # verifies that result = key + mode: "key" + probability: 0.1 + + http-cookie-check: + mode: http + url: http://172.20.5.5:3002/user/stopwatches + # url: http://gitea:3000/repo/search + # url: http://gitea:3000/notifications/new + parameters: + http-method: GET + http-code: 200 + +rules: + - name: blocked-networks + conditions: + - 'inNetwork("huawei-cloud", remoteAddress) || inNetwork("alibaba-cloud", remoteAddress)' + action: deny + + - name: golang-proxy + conditions: + - 'userAgent.startsWith("GoModuleMirror/") || (userAgent.startsWith("Go-http-client/") && query["go-get"] == "1")' + action: pass + + - name: standard-browser + action: challenge + challenges: [http-cookie-check, self-meta-refresh, js-pow-sha256] + conditions: + - 'userAgent.startsWith("Mozilla/") || userAgent.startsWith("Opera/")' + diff --git a/state.go b/state.go new file mode 100644 index 0000000..3b8a212 --- /dev/null +++ b/state.go @@ -0,0 +1,512 @@ +package go_away + +import ( + "codeberg.org/meta/gzipped/v2" + "context" + "crypto/ed25519" + "crypto/rand" + "crypto/subtle" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "git.gammaspectra.live/git/go-away/challenge" + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" + "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/api" + "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" + "github.com/yl2chen/cidranger" + "io" + "io/fs" + "net" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" + "time" +) + +type State struct { + Client *http.Client + PackagePath string + UrlPath string + Mux *http.ServeMux + Backend http.Handler + + Networks map[string]cidranger.Ranger + + UserAgents map[string][]*regexp.Regexp + + WasmRuntime wazero.Runtime + WasmContext context.Context + + Challenges map[string]ChallengeState + + RulesEnv *cel.Env + Conditions map[string]*cel.Ast + + Rules []RuleState + + PublicKey ed25519.PublicKey + PrivateKey ed25519.PrivateKey +} + +type RuleState struct { + Name string + + Program cel.Program + Action PolicyRuleAction + Challenges []string +} + +type ChallengeResult int + +const ( + // ChallengeResultStop Stop testing challenges and return + ChallengeResultStop = ChallengeResult(iota) + // ChallengeResultContinue Test next challenge + ChallengeResultContinue + // ChallengeResultPass Challenge passed, return and proxy + ChallengeResultPass +) + +type ChallengeState struct { + RuntimeModule wazero.CompiledModule + + Path string + + Static http.Handler + Challenge func(w http.ResponseWriter, r *http.Request, key []byte, expiry time.Time) ChallengeResult + ChallengeScriptPath string + ChallengeScript http.Handler + MakeChallenge http.Handler + VerifyChallenge http.Handler + + VerifyProbability float64 + Verify func(key []byte, result string) (bool, error) +} + +func NewState(policy Policy, packagePath string, backend http.Handler) (state *State, err error) { + state = new(State) + state.Client = &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + state.PackagePath = packagePath + state.UrlPath = "/.well-known/." + state.PackagePath + state.Backend = backend + + state.UserAgents = make(map[string][]*regexp.Regexp) + for k, v := range policy.UserAgents { + for _, str := range v { + expr, err := regexp.Compile(str) + if err != nil { + return nil, fmt.Errorf("user-agent %s: invalid regex expression %s: %v", k, str, err) + } + state.UserAgents[k] = append(state.UserAgents[k], expr) + } + } + state.Networks = make(map[string]cidranger.Ranger) + for k, network := range policy.Networks { + ranger := cidranger.NewPCTrieRanger() + for _, e := range network { + prefixes, err := e.FetchPrefixes() + if err != nil { + return nil, fmt.Errorf("networks %s: error fetching prefixes: %v", k, err) + } + for _, prefix := range prefixes { + err = ranger.Insert(cidranger.NewBasicRangerEntry(prefix)) + if err != nil { + return nil, fmt.Errorf("networks %s: error inserting prefix %s: %v", k, prefix.String(), err) + } + } + } + + state.Networks[k] = ranger + } + + state.WasmContext = context.Background() + state.WasmRuntime = wazero.NewRuntimeWithConfig(state.WasmContext, wazero.NewRuntimeConfigCompiler()) + wasi_snapshot_preview1.MustInstantiate(state.WasmContext, state.WasmRuntime) + + state.Challenges = make(map[string]ChallengeState) + + for challengeName, p := range policy.Challenges { + c := ChallengeState{ + Path: fmt.Sprintf("%s/challenge/%s", state.UrlPath, challengeName), + VerifyProbability: p.Runtime.Probability, + } + + if c.VerifyProbability <= 0 { + //10% default + c.VerifyProbability = 0.1 + } else if c.VerifyProbability > 1.0 { + c.VerifyProbability = 1.0 + } + + assetPath := c.Path + "/static/" + subFs, err := fs.Sub(challengesFs, fmt.Sprintf("challenge/%s/static", challengeName)) + if err == nil { + c.Static = http.StripPrefix( + assetPath, + gzipped.FileServer(gzipped.FS(subFs)), + ) + } + + switch p.Mode { + default: + return nil, fmt.Errorf("unknown challenge mode: %s", p.Mode) + case "http": + if p.Url == nil { + return nil, fmt.Errorf("challenge %s: missing url", challengeName) + } + method := p.Parameters["http-method"] + if method == "" { + method = "GET" + } + + httpCode, _ := strconv.Atoi(p.Parameters["http-code"]) + if httpCode == 0 { + httpCode = http.StatusOK + } + + //todo + c.Challenge = func(w http.ResponseWriter, r *http.Request, key []byte, expiry time.Time) ChallengeResult { + request, err := http.NewRequest(method, *p.Url, nil) + if err != nil { + return ChallengeResultContinue + } + + request.Header = r.Header + response, err := state.Client.Do(request) + if err != nil { + return ChallengeResultContinue + } + defer response.Body.Close() + defer io.Copy(io.Discard, response.Body) + + if response.StatusCode != httpCode { + ClearCookie(CookiePrefix+challengeName, w) + // continue other challenges! + return ChallengeResultContinue + } else { + token, err := state.IssueChallengeToken(challengeName, key, nil, expiry) + if err != nil { + ClearCookie(CookiePrefix+challengeName, w) + } else { + SetCookie(CookiePrefix+challengeName, token, expiry, w) + } + + // we passed it! + return ChallengeResultPass + } + } + + case "cookie": + c.Challenge = func(w http.ResponseWriter, r *http.Request, key []byte, expiry time.Time) ChallengeResult { + token, err := state.IssueChallengeToken(challengeName, key, nil, expiry) + if err != nil { + ClearCookie(CookiePrefix+challengeName, w) + } else { + SetCookie(CookiePrefix+challengeName, token, expiry, w) + } + // self redirect! + //TODO: add redirect loop detect parameter + http.Redirect(w, r, r.URL.String(), http.StatusTemporaryRedirect) + return ChallengeResultStop + } + case "meta-refresh": + c.Challenge = func(w http.ResponseWriter, r *http.Request, key []byte, expiry time.Time) ChallengeResult { + redirectUri := new(url.URL) + redirectUri.Path = c.Path + "/verify-challenge" + + values := make(url.Values) + values.Set("result", hex.EncodeToString(key)) + values.Set("redirect", r.URL.String()) + + redirectUri.RawQuery = values.Encode() + + // self redirect! + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusTeapot) + + _ = templates["challenge.gohtml"].Execute(w, map[string]any{ + "Title": "Bot", + "Path": state.UrlPath, + "Random": cacheBust, + "Challenge": "", + "Meta": map[string]string{ + "refresh": "0; url=" + redirectUri.String(), + }, + }) + return ChallengeResultStop + } + case "header-refresh": + c.Challenge = func(w http.ResponseWriter, r *http.Request, key []byte, expiry time.Time) ChallengeResult { + redirectUri := new(url.URL) + redirectUri.Path = c.Path + "/verify-challenge" + + values := make(url.Values) + values.Set("result", hex.EncodeToString(key)) + values.Set("redirect", r.URL.String()) + + redirectUri.RawQuery = values.Encode() + + // self redirect! + w.Header().Set("Refresh", "0; url="+redirectUri.String()) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusTeapot) + + _ = templates["challenge.gohtml"].Execute(w, map[string]any{ + "Title": "Bot", + "Path": state.UrlPath, + "Random": cacheBust, + "Challenge": "", + }) + return ChallengeResultStop + } + case "js": + c.Challenge = func(w http.ResponseWriter, r *http.Request, key []byte, expiry time.Time) ChallengeResult { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusTeapot) + + err := templates["challenge.gohtml"].Execute(w, map[string]any{ + "Title": "Bot", + "Path": state.UrlPath, + "Random": cacheBust, + "Challenge": challengeName, + }) + if err != nil { + //TODO: log + } + return ChallengeResultStop + } + c.ChallengeScriptPath = c.Path + "/challenge.mjs" + c.ChallengeScript = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/javascript; charset=utf-8") + w.WriteHeader(http.StatusOK) + + params, _ := json.Marshal(p.Parameters) + + err := templates["challenge.mjs"].Execute(w, map[string]any{ + "Path": c.Path, + "Parameters": string(params), + "Random": cacheBust, + "Challenge": challengeName, + "ChallengeScript": func() string { + if p.Asset != nil { + return assetPath + *p.Asset + } else if p.Url != nil { + return *p.Url + } else { + panic("not implemented") + } + }(), + }) + if err != nil { + //TODO: log + } + }) + } + + // how to runtime + switch p.Runtime.Mode { + default: + return nil, fmt.Errorf("unknown challenge runtime mode: %s", p.Runtime.Mode) + case "": + case "http": + case "key": + c.Verify = func(key []byte, result string) (bool, error) { + resultBytes, err := hex.DecodeString(result) + if err != nil { + return false, err + } + + if subtle.ConstantTimeCompare(resultBytes, key) != 1 { + return false, nil + } + return true, nil + } + + case "wasm": + wasmData, err := challengesFs.ReadFile(fmt.Sprintf("challenge/%s/runtime/%s", challengeName, p.Runtime.Asset)) + if err != nil { + return nil, fmt.Errorf("c %s: could not load runtime: %w", challengeName, err) + } + c.RuntimeModule, err = state.WasmRuntime.CompileModule(state.WasmContext, wasmData) + if err != nil { + return nil, fmt.Errorf("c %s: compiling runtime: %w", challengeName, err) + } + + c.MakeChallenge = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := state.ChallengeMod(challengeName, func(ctx context.Context, mod api.Module) (err error) { + + in := challenge.MakeChallengeInput{ + Key: state.GetChallengeKeyForRequest(challengeName, time.Now().UTC().Add(DefaultValidity).Round(DefaultValidity), r), + Parameters: p.Parameters, + Headers: r.Header, + } + in.Data, err = io.ReadAll(r.Body) + if err != nil { + return err + } + + out, err := challenge.MakeChallengeCall(state.WasmContext, mod, in) + if err != nil { + return err + } + + // set output headers + for k, v := range out.Headers { + w.Header()[k] = v + } + w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out.Data))) + w.WriteHeader(out.Code) + _, _ = w.Write(out.Data) + return nil + }) + if err != nil { + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + }) + + c.Verify = func(key []byte, result string) (ok bool, err error) { + err = state.ChallengeMod(challengeName, func(ctx context.Context, mod api.Module) (err error) { + in := challenge.VerifyChallengeInput{ + Key: key, + Parameters: p.Parameters, + Result: []byte(result), + } + + out, err := challenge.VerifyChallengeCall(state.WasmContext, mod, in) + if err != nil { + return err + } + + if out == challenge.VerifyChallengeOutputError { + return errors.New("error checking challenge") + } + ok = out == challenge.VerifyChallengeOutputOK + return nil + }) + if err != nil { + return false, err + } + return ok, nil + } + } + + state.Challenges[challengeName] = c + } + + state.RulesEnv, err = cel.NewEnv( + cel.DefaultUTCTimeZone(true), + cel.Variable("remoteAddress", cel.BytesType), + cel.Variable("userAgent", cel.StringType), + cel.Variable("path", cel.StringType), + cel.Variable("query", cel.MapType(cel.StringType, cel.StringType)), + // http.Header + cel.Variable("headers", cel.MapType(cel.StringType, cel.StringType)), + //TODO: dynamic type? + cel.Function("inNetwork", + cel.Overload("inNetwork_string_ip", + []*cel.Type{cel.StringType, cel.AnyType}, + cel.BoolType, + cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val { + var ip net.IP + switch v := rhs.Value().(type) { + case []byte: + ip = v + case net.IP: + ip = v + case string: + ip = net.ParseIP(v) + } + + if ip == nil { + panic(fmt.Errorf("invalid ip %v", rhs.Value())) + } + + val, ok := lhs.Value().(string) + if !ok { + panic(fmt.Errorf("invalid value %v", lhs.Value())) + } + + network, ok := state.Networks[val] + if !ok { + _, ipNet, err := net.ParseCIDR(val) + if err != nil { + panic("network not found") + } + return types.Bool(ipNet.Contains(ip)) + } else { + ok, err := network.Contains(ip) + if err != nil { + panic(err) + } + return types.Bool(ok) + } + }), + ), + ), + ) + if err != nil { + return nil, err + } + + state.Conditions = make(map[string]*cel.Ast) + for k, entries := range policy.Conditions { + ast, err := ConditionFromStrings(state.RulesEnv, OperatorOr, entries...) + if err != nil { + return nil, fmt.Errorf("conditions %s: error compiling conditions: %v", k, err) + } + state.Conditions[k] = ast + } + + for _, rule := range policy.Rules { + r := RuleState{ + Name: rule.Name, + Action: PolicyRuleAction(strings.ToUpper(rule.Action)), + Challenges: rule.Challenges, + } + + if r.Action == PolicyRuleActionCHALLENGE && len(r.Challenges) == 0 { + return nil, fmt.Errorf("no challenges found in rule %s", rule.Name) + } + + //TODO: nesting conditions via decorator! + ast, err := ConditionFromStrings(state.RulesEnv, OperatorOr, rule.Conditions...) + if err != nil { + return nil, fmt.Errorf("rules %s: error compiling conditions: %v", rule.Name, err) + } + program, err := state.RulesEnv.Program(ast) + if err != nil { + return nil, fmt.Errorf("rules %s: error compiling program: %v", rule.Name, err) + } + r.Program = program + + state.Rules = append(state.Rules, r) + } + + state.Mux = http.NewServeMux() + + state.PublicKey, state.PrivateKey, err = ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, err + } + + if err = state.setupRoutes(); err != nil { + return nil, err + } + + return state, nil +} + +func (state *State) ServeHTTP(w http.ResponseWriter, r *http.Request) { + state.Mux.ServeHTTP(w, r) +} diff --git a/templates/challenge.gohtml b/templates/challenge.gohtml new file mode 100644 index 0000000..24efdba --- /dev/null +++ b/templates/challenge.gohtml @@ -0,0 +1,191 @@ + + + + {{ .Title }} + + + {{ range $key, $value := .Meta }} + {{ if eq $key "refresh"}} + + {{else}} + + {{end}} + {{ end }} + + + +
    +
    +

    {{ .Title }}

    +
    + +
    + +

    Loading...

    + {{if .Challenge }} + + {{end}} +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + Why am I seeing this? +

    You are seeing this because the administrator of this website has set up go-away to protect the server against the scourge of AI companies aggressively scraping websites. This can and does cause downtime for the websites, which makes their resources inaccessible for everyone.

    +

    Please note that this challenge requires the use of modern JavaScript features that plugins like JShelter will disable. Please disable JShelter or other such plugins for this domain.

    +
    + +
    +
    + + + +
    + + \ No newline at end of file diff --git a/templates/challenge.mjs b/templates/challenge.mjs new file mode 100644 index 0000000..8b0272f --- /dev/null +++ b/templates/challenge.mjs @@ -0,0 +1,68 @@ +import {setup, challenge} from "{{ .ChallengeScript }}"; + + +// from Xeact +const u = (url = "", params = {}) => { + let result = new URL(url, window.location.href); + Object.entries(params).forEach((kv) => { + let [k, v] = kv; + result.searchParams.set(k, v); + }); + return result.toString(); +}; + +(async () => { + const status = document.getElementById('status'); + const title = document.getElementById('title'); + const spinner = document.getElementById('spinner'); + + status.innerText = 'Starting...'; + + try { + const info = await setup({ + Path: "{{ .Path }}", + Parameters: "{{ .Parameters }}" + }); + + if (info != "") { + status.innerText = 'Calculating... ' + info + } else { + status.innerText = 'Calculating...'; + } + } catch (err) { + title.innerHTML = "Oh no!"; + status.innerHTML = `Failed to initialize: ${err.message}`; + spinner.innerHTML = ""; + spinner.style.display = "none"; + return + } + + + try { + const t0 = Date.now(); + const { result, info } = await challenge(); + const t1 = Date.now(); + console.log({ result, info }); + + title.innerHTML = "Success!"; + if (info != "") { + status.innerHTML = `Done! Took ${t1 - t0}ms, ${info}`; + } else { + status.innerHTML = `Done! Took ${t1 - t0}ms`; + } + + setTimeout(() => { + const redir = window.location.href; + window.location.href = u("{{ .Path }}/verify-challenge", { + result: JSON.stringify(result), + redirect: redir, + elapsedTime: t1 - t0, + }); + }, 500); + } catch (err) { + title.innerHTML = "Oh no!"; + status.innerHTML = `Failed to challenge: ${err.message}`; + spinner.innerHTML = ""; + spinner.style.display = "none"; + } +})(); \ No newline at end of file