From f0f42f7a944471636a2313a850a98b1c29c02b1b Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 9 Jun 2020 16:42:17 +0100 Subject: [PATCH] integrations: Add Thinkst Canary integration. This commit adds an integration for Thinkst Canaries - physical, VM and cloud-based canaries for detecting attackers to a network. Thinkst Canaries can send webhook alerts when canaries have been tripped, and this integration will post Zulip messages when these webhooks are received. Signed-off-by: David Wood --- .../integrations/bot_avatars/thinkst.png | Bin 0 -> 2439 bytes static/images/integrations/logos/thinkst.svg | Bin 0 -> 2493 bytes static/images/integrations/thinkst/001.png | Bin 0 -> 44301 bytes zerver/lib/integrations.py | 2 + zerver/webhooks/thinkst/__init__.py | 0 zerver/webhooks/thinkst/doc.md | 14 +++ .../thinkst/fixtures/canary_alert.json | 27 +++++ .../fixtures/canary_alert_no_reverse_dns.json | 26 +++++ .../thinkst/fixtures/canarytoken_new.json | 12 +++ .../thinkst/fixtures/canarytoken_real.json | 12 +++ zerver/webhooks/thinkst/tests.py | 102 ++++++++++++++++++ zerver/webhooks/thinkst/view.py | 79 ++++++++++++++ 12 files changed, 274 insertions(+) create mode 100644 static/images/integrations/bot_avatars/thinkst.png create mode 100644 static/images/integrations/logos/thinkst.svg create mode 100644 static/images/integrations/thinkst/001.png create mode 100644 zerver/webhooks/thinkst/__init__.py create mode 100644 zerver/webhooks/thinkst/doc.md create mode 100644 zerver/webhooks/thinkst/fixtures/canary_alert.json create mode 100644 zerver/webhooks/thinkst/fixtures/canary_alert_no_reverse_dns.json create mode 100644 zerver/webhooks/thinkst/fixtures/canarytoken_new.json create mode 100644 zerver/webhooks/thinkst/fixtures/canarytoken_real.json create mode 100644 zerver/webhooks/thinkst/tests.py create mode 100644 zerver/webhooks/thinkst/view.py diff --git a/static/images/integrations/bot_avatars/thinkst.png b/static/images/integrations/bot_avatars/thinkst.png new file mode 100644 index 0000000000000000000000000000000000000000..36161c57f2b3dd0982ba61788033de411d880b46 GIT binary patch literal 2439 zcmV;233&F2P)powO4Qh5=ei*bR_mL!iS%$7-#$ z4pQ1EWlCukX{#05ai}KYnB`I!Tcvcg(%Vd}gG^i7>Chr76Y2=K80cXqSS41es$Iq&-$9?tFCbIwxJ;dSMa@fEFLSxW zF<>muvSuYJDsCtW$p9wu#SN5QRR^FV>%vl8R}_*75+~yac&Z_F1y3ys$pqr_@t;W= zQkPjP3dsNhRmKm<*90fbRn6 zPqID(v>StEP1N0eDmqvck`08FPJjEF%Z3BKA0cd;1){A0dWZe>SrC2!;wB38+(CWr zxN916`r8fwbe);G3!D%UZg$%{o=>y@*VL3k(<)I?a*n*-frOP9R1{(iVSv|p9Il^a zTA;C4pTiM(x6Q~@qZk`NI~)BQ8zqGw=(2BqGu0LAj_PAYY2;px$aVmSi$V;9!CxWP zmNob{KEaZ9AFb89K;SDa>-4owCqc_3%XI|$-<5wM?Xvm-c!{Zp!6%9MeE?vhF#x8L z+js+xC3jLYRs6*aWp5snPo~E#maGPG^WaiLeI1 zBm?th%7J_o@&*yUG16&fx-=fwD|kTO1HyW!6>}ipE)3m7VW*KY0Kh# zOk(;mfUuGE(;=UP{8szm!nJPuma}Fxc**gDcipuQeFuW;88~KEpOMHHAy0Yi9bZo6 zplt-6xh|g!o>|C1JAhy=dPcGQSr!A&4`^a_qVsvP@Ye4N0dQUVb46wzzh}(H2FHyZ zw23ki)Fug{>zVLqHhrxvgwazv=Hjxh+1qpazcf|)X6+p6yY!`$^KWgHEU`Mj@!x*gb#Kan&&Zz~TGexH6PK9U^%X04=SjJ~G5=Le7j8v{iM8DCJbXfg*3?~D`T3Dq&8)c5F4T=_c-Q?ZN?X5L|?twSST zp`x!#6mTs0*~t0PqP_{gn$L&>qzpV$mcmR@q;* zkdyAYdO&f8c!(CMY_C=b(X&?CU0tF{WpkxMNYZ|l{fAR`R38hVMr8(-Lc&85FDUGP z8Mbm%15o;QBsD^q_Y#ZSd*=}i zy0)0!#{d{8Rh_}ygE~Ra7a0HmsqQB0D5eQv!VZtU;~}%^n*kA&pY@p|gz$LR+zw0K z%99ezXH-WpUI^n!&s_0s3r>k7M~GKdM=Cxm&g+u_<_QWi__Y5#_+ktaf44@zxiUd~aaL5Ryfsj`2nLP7wq zu-Z)tX22AwPrj6Sq$q?pcpR=H=0>pwOv2)~k`nfN?5;<0kVQQV0`n4;5t2>6za7!S zUn}(EMighDZ6ScFqzjtJNLz>`h*jP>Ta-;BXvXP#^L%i~7{f+K4=7w^tU zLR83UNpgvI-X>#y+$zs-`rDcqbiL{vz=y|>i^SqKuYGjN000JA=Ke98WL|%?R=4bn z!pvr2KyQ{TKchNF6!kkzg*12Swt>mg3kB~qNkHDcNZC*ZCP(gtbz}fg{m`dEK71bC zI>(MEqf$t7r*6|&JPF_`)mer!Duwh<<~AsP{5cV$PDq1K|15zYRGlLcR(t27snq%P z*#!AC6hHbr5~F4dS>)3zHORdHCaBIb5~D)Myl#DBh~z#1GgN0uM!^edJg!%iYVtV( z7O2jW3I#2ssaK!GgK|HB2Gv;?c`7b(J?zL%?AEW>P002ovPDHLk FV1j!Zjbs1- literal 0 HcmV?d00001 diff --git a/static/images/integrations/logos/thinkst.svg b/static/images/integrations/logos/thinkst.svg new file mode 100644 index 0000000000000000000000000000000000000000..9a1af49dec55c1dcba65d230af18f7243978bc45 GIT binary patch literal 2493 zcmb_d+m53~5PhEciWZ|tyNZGC25ew$uarz?vu{y0m&XwcZ5u5H3wmr%qWt@wD!`tL zA9kh8$aYbE>U352sbc>AxUIzAv|ZWM3rBg<5vIjOMEv59acHZRM zQ0cKM>o1qEoD8or=f;%lja@iF>_td3iP?K73%g-whybcIBtDNP0Yb@4mM)yJ3@i~a6 zGc4mY)8B9Jmh(JM|8CkZ1fxIlXP=t~)CE+Lr>myjW_DR_v$dh){1IB1@8PJXRyZENGi6E99&wH>xGYDaK1iW6)+rYbWn8i zq%FZ4sz`fU?1dXhZz^&jC$97&A-#}{7)IP18v#TF1l-94AK@x5nou+w0Y%|47TOCY zk*5Sc{Hwqv;hhrEQ~-!Fy%3uYj1qJa@dAf<+Lw)AMG$&3;3T$18X-1Kh(>A9qu*d5 zj`-aGYiuM>4KRz4Bf!H3lIv>>1o*%pserSkxZoM!;GTr|o=#$dXn-Yx-Ne%q+T?8X z`C>_Vvxy?;l+Wd#(>3<8RQIg%D_n$6w?ub%H75oCHrxx{?R+G zlUtI}KsdHqp=UiAl|dNn+z;4OmoA*=ZOVC#rG*d_JBHHmtZ7Im?98jI>u4(U#i3lK z5-;F2l&m5I(-5K4UE^o?=8hZsCJ0~mP0;t!rM}V8cn8n=CQ{I+(xj0bnnN>;njXa6 zw*u6_Jp#RwgT4l4csLProl!6nuw@!uzp;|3O81#%KMVDtemk zH>hZ}(uH2}MrRcT{gq!<5ym&eM-?SrOfT`_Ej~!;x$`8Y{w@4cN+Bk3&+uALFD7vm P^8pWPW65FI@7K$(R9$~w literal 0 HcmV?d00001 diff --git a/static/images/integrations/thinkst/001.png b/static/images/integrations/thinkst/001.png new file mode 100644 index 0000000000000000000000000000000000000000..618d92c76c484326dbbf32df2904c02228492fbd GIT binary patch literal 44301 zcmbTeWk4Iv8aBK*E!yHHq{@_1X#-@{41pLi{%ec8Mo0|Qf0&tr}@(FzX3L1{&`8U$7 zE|)&iEMxxnLi0BP0e4kaA2I^tf4yPaM3;adpezb*00yg$$f zD|7I^%&^YTf-90!uKv~*(H6to4?K8nrNdif9Yf@g{>>d9$&30XEBkgA);dxCD z3;zd(#BJg{(wpALiV9?HMjjMAr;^IZe@opAQEHtaXqu3`fv}=BmdfhYQLbAfzv#M- zVX5p1s*ZWMj9~2UMT@JjAnCj*wz*>3ub$0@Z7E)ZHwSGo?=|((%6`80*3q%Ukk6Sg zSKTuFTPn@|&|YsK43~oeTbb=$zV2&w;hG1|UKRUiU%n&WiKFeGhOn zgu7Y~Dt-;z$wInc+z7?T=Hfv&PhDzfGzWmW#vE zC^;&yvu}Zo#>TBkpMV@6S~c`=x5?=!#(w8cyY2|(-{f-HC~$e&kwqmkf8X^&B#wu* zpp~iczL@sAh!S?pXO&yK-JcX_>?PwSC^?RntE}^1z04uFj$Zh5LnNecB%U{!OvNzQ z)L^G*6*BIAx^~xlQSOoTc30WvXw?g)F&ay`XXE3DdX><3L_(If9xgy5I7^D}?H|rn zcZ38lzV68IZA9HX>)qs;TKiS7QxmBA;A3pYly~xS{-mlYrtzN^dEDCvxsaK@2vgIb zK%3eJ{~FgIL2O!9v9=r&@Z?m|STNd&0?P@Ge`cWX zMpsUQ4C=DOaE7E8Hywp%BKP_ZN@*3IZ82OV3zz7DZyPmmc{5#S7@CHwlsm{=Vp1u|ttBgToU4Ql8KayMnxqNU7 zXx~}DJwa_b9C$kFsFONdQT=lQ(kS^GpJtln@boYUEOY%4Cak;tnb3FrHu%CWt63Y38{M+++%sw8>+!SBK;%VoW5poa(!~v-VBc`Hx9!!TBSFvvO*VWP zR*8Z^B1N%-w?PLIRF0y7mZ&>OgJ4;QVeowK-OBvwM6n%L6@1zkb?Raiqi1IoAv*_4~Jh~}B zsMFplo<>BgOJ1M-Zd?tx`I8O0{>h9_fb?Ic7`-US3tbI>l{c(6TNG^3 zvHikhxi5JCPh17UGgOifYwB%pOsZ8`sw<*hrI4$l^;j*^Ikys4wucg%w{yLCRov`8 zPjuAk`^xfwtlAn<>v)b_+Y2<_L@s8>%;?j$zn?E#PrHB}aVWZFxgqzUi!|Fv5af=n z7CzS+Xnpi2#KM&vg~Wg*S*NVvF|^$T9D3_ybC&KNxx*sQcySCS7rhaip@m!&qHVO3 zHK)pvFz8C$0KUk!dSJcU%AZSEVD;RMvS4S``-wk7%=)M%7+Bo}?>Nv8Mn_V#PqBNb zRb(02PO$2H`sa6ERJkAp(U%IZzBB?NO)@qh=veff?}+B2d3`HJ><%Tz>{G~Z$y!+8 zZG$oA(rqin(18L`hrLY=T=q+a>1YyHDfW&xp0O>mI7amKCgJ9x0u>2eR;WK z!-79rky{^`t)N5MFB-nq2S!%W9jam#eBXh|8x5tHr=xXf*^;jqq~*OwCkGuhfVu2jp0Eyef?1u)a1G?&SrhTC}0@n1@ewFL!5t93*;G|RL)i9 zbEuuV-{D;o|(Tbdn&UTK&lCs@fhFjW#ZEUfBxWX6djwrj@j= zZk2nc0Jiiq>0PJ^UVZJwrEtX{zF_W(^8_-HtX1BOy2}st%(|YLc*Nsd_8Q~e$s8L?vIJx6Aa=?sRg4Ze(ybkkT{Eh;mCyp@Q@Zr%-BH!|W@o&11G)-a60zW&!YI#~K=GTcJheTmukO3GeOz?$9e zJ`dNQx6Zio0l3jqfg%?IMc+%5WJ5lE%hhnZHeu{pVCMydH~JMEItokB^)w|<@C z21(#=o-6Kq$_hHGOVU(9gNbT|U%xGVY};ca2T8c!%$#i(JMRt2`K}%5zU*94UkPwO z7OAuwTetAEaju7-X9uEqRu~)&8cj@21COz$vKA~25N!q#%04`L3y{vvW2J$9sE>9lALW#xtoG%B;>1~S25<+TNEMr$Ft-Zgk)>x9d*?HNoonzPfQ4O@=0& zQ{(KR?<{x6ZMv4X5>6HLXxXD`o?P(&+!=`D*2=*14v>OQSYZj@};3&JJ9=N&7l%>YfxH+WRP1;Nj5ro(SH4-enzrtGRFZD@o@P_ z^~4imKqPrn+8gG`y40|3=9>niX>3h)Nw;qBW@F+-_ z_{K<5TcEh_(kwuPD$ya=7VEEn7E<`>e8=od9BKLM>WFK)?j2Z z2(`DFi5D4$=~O?Hdv^zFck=9@4Z5C(Ed~bmyHxleel);wz0N<&R1rj;p>+94q>lGi zJI@0bB$rTy-XO$4HqDtu(A-6#(V{I+h6BvNB@`bpm+Qx&hj+Kd&!2R}is1!ZEu!p@ z<4XoEJ6)PVPOz5=4VEwnN;2>VVM3`DIIy)@-JsUu@S_sxvo-&Yw|s$6U$IL;1n{iT zv^VMIxto)~j9}^P^ap?~yp$Yf7aXp2RlzpPj=4A?Ar@U9aTpq-7ikcWy?}8zdYKU( z+OTB%rpfl|xV$!^Lq0){&0q+9u(XIbMK|+gC9Mxjq^!~zRpB4y;EDX5Krx^^Z@Zkv7N289yVYu-V|(@!4n$L;!);B2z+Nl$?rz98 z=5D{xu@0jzJ@8615gngz;{CgB3r{o?7yeKFcqQlrYazqi*rye(!NW(`L9|AbFcE6( z!(52P&ig+t2c`$j!LT3WA4r4L-J1OYGfx~~(3Sra6r@myX6NMI^foWW6t7lW@=RN6 zDl72T-X9R@-|=){1A1R@c4f~umX2}rBKElqgv!|7Tyq{DEI2o{->r$2ax_rt=IrT~ z)0jMDSh(w1Ku_}2Q%gI*vc<>V_NW-KnnQGde|M`$qOxA)X%Dh#0L|J z0!8GGOD)yXtRA$>tvkA{mCnZ%d0(n4ocyu41(49 zeFO(TLJy3*2S05s;-gQkh`#291aQnN{4+INreGbL_~@^XdYY@(ku|plI~k1z-a1yE zPkE-c)`1V<%9hnYY+79E7DB%EbEPnL^smiCe9QoV z&yj0_$?n(*-@3TvG&l~U^Mg>k^X|Km*5lv4m2{|V>TZ|o6je-0BoZQCUs5KO$IhnL zY%P;ZPHS+vdz7heU&PKnZf<=#Bv@7)i}6RVTn5Hmq%GcXR$Q;e!eSwiK1<36{M6;d z1V&3JJUXi^W;A57o~fAW!eieON!2whgm6h(J`|Ef^%Nwk3=iQ`16VUNKEP!{J>5x? zpuT*>t(5l6yVk(7>jjQ~GQN9LZ>{5N>w)7?s z16?(0cEX^qCj6(eqkPUAHq!7go?CK^>c@um916tJ57UX~y0d=J5p@z(>S4uM> zQCIs3F@fz#>VqGGK^|1K&$34p48|ZuZr)*CJYGh(!sJMje|Ctm_s;YUG4SKLIR@-} zif2L8~gvchQ6%e7mVErjANjsPeLf5aSk@N^}*pdZn1Sz6vpPxBDxcq{mk{JNNaITHXzR-k5t|NNi? zi2uOjJ(~-(pj#!&CkL-=*GKt8?nlG2is{wkN79owF*`3T{b*i5UvET%GF%)DPSFY` zdmiD^l?wt@4E~o4(M0sjK-bnO+8fRa_ICn82>mPMCId`|GOE<3*qtT08@)D|zq@5mT37 zr1hM3O*OPfEzt{pkOOK99HZCX-yVIQqGLU1bG-p~CSy9bzk`4bPYd#Y4>d2G3DA(M zwrNP)=r8O>z%i=DN?z)fJZdBsjqa>53(PaX>>6}+)8mj_BY8PwV-F~$@>EA%jjYi5 zzP<-hv88U*iA&prhOL(=79p&0WgKQFce9qB8^5Aev8$_RaEk7`gBI>R+)Yu`Z~ z&y4KxbAS)F9hix1`a_2pu|q0Jt#qG>)Eh6Bz}DLxz#7D~^gk(^KcdOLCC0fC_mcD= z5)c_iZ(6~Ah=qsw64YUN8COKX;xYim*Rv+i;gz#jkE0&`d4G!eKhoe;>FaPKl?x*zHq?JG>b^_ zpY%VI{o_}rR}vS9(GNX6f%9U3y1=e^pEt>FKSC{HkQEWe^m!ClPyXF3ufCagbxDm@ zF-@+Ys?1DBJ9n=)T1S&lC{)5K9a9VCnM1;NR&EVyH5lE*+Le@wp<5(q7DtBm@*LyP zLn`eAP)AYcMxF_AxOL?1)HgU!W4#gD`PnHI5cxU@`$LlbZNRT8trKg$v%)Pm=Epp@ zC#x$WtmNgsr#VBqNYqMg`Nqht4v$ehnM752|A`~&?ssco%h{|uoFsFZ2Qost(Wfg* z(k^+oK+n)!bJgb`B{>)YwOekov<_x69t~i!@}yfm2`@G>cY7}Au=3_z?t8QP*@61X z+#X#<#|lp&sHfX6gXKJhfV<5sx=;g*H(UW9VEu^}-r?5-Sn?9Qd2ay8&81f4su0z) zQ;!Pu+I^u=?Whyc(y0%C*peVc$vX4!(VR4{YOsSi&E~Fq5YMHd-&P~!@bUe2l^UyS zmml9Q7h+HGhPcvf$KwRpq|SV3;_Ajxhd}p8rua(m1J5BH56GLcF39`B9PY^?)p_D6 zrV~|TnmJm!a4tQQ7M)NZO2kmn*qnZavQZ!F1l7AuJ`%WlbtWlUtdMZkhu&z|hyDQPGUM{pZLJ`uAy!0dQD*M8c7O`WPbyjf2W65jEBV?}JBAt+WDgvpWLCz z$Nk2M;o85#%6TyY$?A|-AMm;BfV^g0`YDmvg8R; z8;`X5RA%~#FsQP=n)$9psG-czfo%%IgdlgcN6MPG7a;a|9Pqabh z)dG)P?W1M^z{t7UR8$}Lse?05I7V_97uzgG(5Sg`oiC{#mXh8s@bvgO`w*+p&_-Q_C zp=<6ekbTOUkAWZ7aDWMgh`)TcgLKVpYlr96Ar|$Q@x?)1sO5xbXW)$hvr%f=fg3O+;>zl|S`w!! za&~3>f=<{gq_@lhq@PsOsAH`66i=}8=FX~Ji6-1^R4bd?{}UM+f;&S}Xk`+N7-}Wp z1#09#Z8}5))iPERBqFvx^76_hF=nA(W=%P3ka{#daem973dg?&rSE?p&#!HySg3wCcVY+ z-5^b)6#;Z@WAqG-b&_E|Vv*-rHg3Se>Wc65{#JX^)g@g6+Bi*A$ccTd6+by|&~n|? z_r5+~vFKy5ISzCYt^T>(i?WAiskDD)j#mQ9Bz2F>|7 zIogLNdkP@mJKp2`@F=acJ!{7A6I(z~T%?5bAj#Y~y_Lv8%O= zb#>9VjhS2uUeFG?+h0>Eji3O!Eh4xQAwwFkf7d+cm@RvQ_GjkMf2$~e7X&&+nTE5V%sNQo~pA&C~X;YrK2`yDv+UTYl; z)H+Kgql#%?AeI!|e0P63E?^ATInMJ-2e%ei<={>mXYuagx~;3H#?ME_INPj{h>ICl z9F!Va%R^_*!Hw zW&;Pov&h9eYY_0FgqCcHBn%ner`315y&bfCzL=c`0H+zW-d%J}V*wZsBju6RLUxp9 zTp(Q;)zp%Xl^xrqGxM^i3<(L$3X@8tE$9Skhfe9nesZWA3T;dFAwda`%ELZ0K``t$ zMWByxHQl?SQp9M=RO9@5T1kdzf`J|Ab_qm>9WI2r`;tgo+?(}?s6 zy#0v~FwowL^2CU89!9b@wolMIVgOGHeTGARB1vjX1RYB153K3i_Jc}H?@!TsH`w)V zla+UtdqR)Bc~9boBZTbeo8BY88Q`kQsh)ISYEKxUhSXtbiOx5Hb}u#Umlx^|6GaMe$>Eb1e6l5z-4|uUNxq?y4`C|@I0fW&wyT? zzrkcwe&ZK~s>6h(kA=a3%S#uL1o7Ey0n6cm34CC!-I%S0RL@(~ZQh@$fc?+e$)|tt z&%HAAn5W5*c?(H7VdYtkMXe82|CgZYpM_dTo`uye_J*;Sd}(AYAb6di6m`~WV5=UW z>w8+)oG_eGyQx5gvRh>K9HHl}N^1VlyP>`kXvMgJxOO`POWHMr!Tam`4LW}oBV&`x z7F#@=>1ns8tRSuC!}MN$i!v(Dj6Y?wzql(h{FS;2vZPyW!_ZeXhksOD<;`r{0_dGYX(ya zf30ZpIm6?zQw;EgE(USw-t=6S_nT(=t+hA=)^W0TS=(eSz-t8}E;vHonq2O}%?QBy=8x#}h1ig3jK!SF82C zh&0Rx+by*rx4=*R$HQy5?zIb}$e$GcHzDsW==*Kp*I(NpJ6l*!jM3la+`BKFC(pQL z?Sep$uG@{wFz@EJ!^5<(|4PHFl5xg6EQO(=ywIxku|B;i?RFmd$5HYL4B5ry=_@2l z=a$=JmKI=3tA3qs_wzv1)Sbufk-zsQf+6 zIw6_=1H{w)g!8(4ymEXzMe^Uun!8WWLMg_w?@2pqM91E(bSB}) zMsmT~e(zpB)H>x2(2f%zV7~n*M1Ng*DD}p?+L)e$YfHv1c1pyAv z5q-g}9si95_$&O{M$Mk7XPNfn=liT{q5oIpj^*jDhrwC38nb~|#R}gD$$ypEe^4KG z?g&U}&&6ALpMO>Me|mbV{Cyk3u>U95`;Fd<1!vFiq`gz+NP<$w|4#vZ4 zY@5yrg8%)4jkLg-`NRBggYJ_KI<~WaH~Rm;Od-~xziQk4AA_S|yrBOC1Q5HpQXBX3 z%!55{mvv?d|J%OLuctk;5yvl$^PT_y!Uf*`-$xkyKV?Cce6}kjY=>_@a`oJmZ~X7w z4K~Uw)X~b3B1Rc5GY}CF7&#+aE&wRqY9*#MpZV%}YC-j%K+{4<3^L+wcaBn-_5Uz@)sT+XRdul}#4w@mk#5cFw9Ko0SaGv; z%5(DiZ$o1pgJOHP-|p8B(JV(hR#^|;#wkv3;fjdLNLK|;M?KB!=(&=Ygb%JRjr;a- zFZuZPw|zMsPL`gKji>nd_AFFFw{H^=(UN!S zJg6`wN_hRyjt$sIqS-NhVEZe>H&;>2*ZgOp`&q{DAHRr#kYmI3Vx{@O_~m{}s4)yP z7WIcFl%6YG0F^ug64}Qw@w!C{F-)tKl&{ia_+vh>3(+s1N!G5=M-A>zKJe3M(19*r z>9c+}ZoRsm+A?!ogtXex>Euj6W`4v}>or}~9BMfFtSpJooV%6%4aVT5V`A(mEDSxy z`*QPc@&|8UBo!a&kA%cnM@dYtCK(SCB(#AC+(YlHGAzy*nRA*FQHaC zZ*Jq|jZ&GJ-&lhDJ~0f;6JEuFQ6w`vU4P7va2%x*xeWEE0Nw54apV6vJ;?VqyCC=* zEOScssCk%Tkw;iO_|N#x)a1;9_ZQcC7@{pT@;du4ZJf+z3&Xv_? z!2o^?isdu2T;MvJw6aNw7vq(*Utcu1&MG~rjF)Ai669Qk;WcLbmbBfjZ22iE`S`)W zzy%BY<4j5afUq98oL>>>;b%GiSwy%aWH2Re*FRn=-mNQgq^=pyqECgl4zBTqmn$j` z^9Df!^ATvan-3p((7|X?(H#pRsA#4T&m8lLmq>+ zLDuhB(%P;DrjpX>^VIs8Tv(!u>&pP*F*3QzF9?Zn%f(MH=qTaMCKK0o{nW<}IHeJ$ zG-$`T7RWU6-BHCT6bKslz?E?sJyp(FDH$(`umgT@Se3H<`AbdGsGqxMfKbgkio+@S z;P0cqv^jLGl>-%VU6zySjEs`?)xjPk;JPBI3xOfz@~j}CO?i^5FsGnQeO3s9)uJSI z)o^vA2JbTZ`|BK&{P>YF{x7@&o@zeUUnUVRQPw1ZGhBp({R+Pi$2c z$lkns5ykL0O!i|Wl{Ng!UUp-F821;`(ua7%e^gbPDtX4TZgw3$Ammx`uxY#fG@_Q)lL zh;GhvS2lf$xvDv23nmDX?0KL&=CPTdiSydB@cRgtki$xgyT!yGV~l*w4THcN=5spknR_Ji*w-PXD$NVo*m-jooq^k1Yi=!w`7s(B8_K?&QmtQx#Awaa6cEkNC1~8GyJ96kc-8viX`;4Xiy99C0yA4vy;_ z(g28+dd>H2PTXo1N5-w>j&#UDL?rF+&Rx%%o#633l}ZOh^PGgiGs#IbO|iX8mWQ+I zXKz4IZ5^wvZ~6WE6a6Y8>GMn5YnW^^A@QfV2i>F6hK&Og*7c&o_FMaLi)1x3srpU9 zp=BDW<${#TB>4}Tk~Z80Us)H?x7ab7i&@y5NEvjr__b);s0*C6(tRX8KsCipZC20M z>H@{q@sT6bZhD9jTFZdy+aA{7VI%3Mj}JST>asS)gX|^Divndfs;OmNqVZ9g>o!BE#_J zuasG)VYf#ckYl?)7=S^|MKXAD-wT!%MZ^+7o-s?}8(`{w5OB7))%&=xK`|RGf!_*=3hv z>U1F?={hEBETl1DWpZ7_Y3&s<)_&pAem*4ylSg>;7342gq&u0iM=>{2fhxwJ*6geK@aso$tM`2SRzvCmE$~`a;bkqWtq{F){`~5pP zn`ZSj^5+tcHuxJ2%DJpT)oc6X8m!Ih7n#(oaU?GEr{*r;GehC1lRg zm`V?Ry9aGMMlR$%?ETJWjK}s{cY_7tqG1AM#l(C>lIS8o(M6~om$t(Jf!a*H)57G? zDSo%*OCf%f7g?SL>Z$fUY!++r>;#Eh`s~E(!ZA}e0#NTJM#gMc(WcxV1B`|Cx24eo z)+K$1GX6+_J7Ci4823xO&2|3Ec&dNKb91;eT?_8X#~t{{=NMFx0WYmAW!^mwldaTS z$xeIrYczRmq2%bf}D41wULH0zq-CwowaA;EL6-t?c`rUFC3+kF6vu) z2H3szw#Ej!Z5p2Wzv4ZY(+6-L4a`}CmVJ883*9yXl%dT{o0QH;N$4|Y`SBIx5*Ak%z+&-@C15Y z_0pHt{@uP#IT)O}OJ_o`s&~(aAl&7VgZ^m9_H2P{$JX_W)12;O?H@54O<8k+7{Lrd zbI_@cj&p0*vn}UaGpT=9jKO54_15b>vR4)0wijYiH|u#sD18Ie$yUeD2qlPOEyYR! zgt(&4=v=N})MRxlh9dtXQh)!|*rN!p*@w1ft3vKJHg-HlzE_~Nb3JUYJ$2`xmjX-qx!cAe^UJsvqm zfMVtLtQMAWlpO2&bW=C9m z!*SKnbsBAop#>`pQzJ$b1)r;u>Ho+LR{5Tkbf@3F|l0eXUXXU`cRy) zxsd?(fcjT>0KIJlfm%9W68A+uy!y&%t%wAe?oVD_x|y6(N1e{-G*SayQ*W%Oe7r6^ z1CU22LPTxwqm>JIwbd=bv$OHlyvX>_s}8W|?R9HsMPy)eX0;=yRd_b89lSw^=+OV7 ztLr`Hu&rYn+Gn+Pk3nkN%=fTh8DH?S?{1g2%)yIH1wwxOn<%ofo2(`4OAM*Ig-o9E zjuqMnwW%zlR*yq(m~0^fklyLBNOF?;7;2rK?{-0=UKSyQITVkR?X@1pnx!kDO!R4W ztL3Out5>eAq7({mjQtm{#qucqbp7?{b-GrOP65-sZ(*HdAT-?Dk4C{I&Qmq>16IoF zzHh`^O^-9U`1@6CDH8)d5)CiSI(Kayc^7>UXivQIx0VJfCNzBR-Kfjv*I$}CP!qvM zUHb+HHIqbrnP$egfc%9?mv-$3Ig9UW8|qR<3EbTam=&U@>!U<8K_w0<5i-_nqYUx$ zGK6O*%mbs*#Kf)3)TMMOI!{JtN`5{8G+JCE<_=MemIuzMJT|D10}P9v0}SunV;KxunKy%UDRcYGIzxD?|%!<*vc z-AMR;k7Rsg5M^zQzlIM^Z>F?)ycBfo#^%V>3) ze%VG2V;nTPIVU0E&SZ1zxJtOm5?=4RUJwjGA`?Rm_lWO#o;0|M*G=aXQt>R3p3y>j}@QB zKIxK^6ocG|e`3g6WY3V8m~tx-GVTI3usjWV8WlHU#MZfUJQLU`*qUqEzx3twwU)l} za%E3o?d`p2<#xyGrF+=X-^TDY-s9!o;x${29kmYJSn z6sF@JO^*ft?7T}hQ0W}`nfc~X zEW9+i!$-v0C!?t-u+O_k1swc>Il zhGom6ww$wsO*`&*$Zs-}VUSEQ&x(#qWV^vIAJFA$dNa1M)U+Td@;KGwJ={}UllyrZ zi@M*$jBjE$`t&&y{zz>kacY*TYcpgp!P$ z&%|pA570*r*5zDz<7GA#t5FMGG2bFZBEqd=T5iF5nnw0-KGmjjMZ?DCckH&wL%VE- zONZ+dzSS^j385!yQz$AW*DHZ;sS4EFJ=NHccf%CF`p+4=K{e)I_ z>A{)OFJ8Mlv}$U_P>z?QDxV7VdwGfvB)RLaM8srDQt{KX)?IK_FWQsjE1)#=a~kL` zCcm{c@3~S8Iix;M_mAK=%8I8QVR@{??<|$dRBsY&n72{k)`xeEF)-5`J(S(Fm(UY3;T2r zSAhFG-{+p#z>KMX^#{23Wj-H}*aDpN_Xy2?835b^>{7rbnl;sF9#pII4X%o>(37-c z7MQo4pO(nuhiq0WB`UM5-LGxpwBIp-7{0iI#Aan+D01%EA20C}Rbfb1syw)MU8Kcz zwdItxA9}*1Wi!m+-Gm5&7cmf*S<+}n7uqLu+u-8~P!$KcHN5YhIf_|&q*$}fHC{3a znDeB77H70%-dd=HTSgoGQP-<$)AuQ<=rhFOphHPEV(dInKcRf>Bma}eVH z_(9M&&5@D!%Fn<3nvh_U=du#XRyc@}N5i~*WQ!Mg^eL+%;#Hvf=6Ydp>GJy1ya2<& z+kKu5Sf{Iwy>Ff0wH0?FA^xKQ8)2tynP-c;p}iNr*y33Z0B(J|JDc_+qI)cNSHH-9 z5iVJ~nxfiG)RTy;w&Y!;5dp{qkqXq<72ktq0hja_Zc?Hg{;V zhygb!o#-R=_2!UC=arJKH>tYBt1i=%7|Z6Hr#bY|jWVrvD<% zp2&Wy??CA>cw66k)epV#q+ht3trs9rAgR$S4`avD@G!K;NKXNG6M#=&yqapz4EgI! z_wFNo!tb2eUJ}wgIPr(7RZ-krzcIxM)WyGI7O*c-7w&a#fjQy)4wv{~ka0`pIl}jT#^JIMorPecO+Kis)1l@l{r3}fzxr0tw-_?2 zl|mm9S_$nqx!Cw0CBGQ(yB|9QlSt49CivA=@6LnJkH`$3jKtpiQOW%pE?pNBGcx_6 zaU^l?;p97wwO!iZ%&%1we*92IFi$AvPJ-(|96CP~E!ewdvF_MR8nLLfA3tAXNZ&;1 z)q*(X@yG`e*Izr{NLFn3R9Z8IO}VIK!&24RFCka3zf;-cppV`+L^>VCkUxu}8@;zwi7iix~?E4qHXlw)_hWu_lQ}a|}-hL?zZ>XU(SNyaWKo$uI^}FS&M8&mxUZ2_yVSn7w z;C^a;1Sz_{m#sPz^`pZwb~XDUG0}BgMGsDbpy5vFCayMRs8C z^dg4xwQm`^iNF1Z|F%Yb;ppSeNjQwYf)=qn_CgZz^VCH#%F$kAKiFis5f#Zo=N^6mssACq2MJiU2KAbJn+CZiHJ@yL5V4SRo{8Ta zp>fFo%`7-Jm9CSs6aV%Rt`Z4{$wKa}X0(u&__GrB9c6xick#~G=0#?c&xT{(!c~aV z$p@>~JlvagB0ybAbRE9rys7A9E*IEHlHZ+U+->W<=^145ATJh;aMcJIyLsIGPB23)SJdEK}mdEB>FKW+z?46Qkv(mzz0OJE! zfh*Lz$1y8DzVZ`HeVQxLPF0ip#~c)s%^qOi)x3hJhw?Icale;M6iK?Bt}=1Ug`FbmcZEU~EeAGT=YUzq{p!n#l}@P=%4%7qON*BUSo~24ac%aAj;j zwxYIvG=eHbHs6?4xGy`Fy;$f!cY-B32Ra-#!It za6A?H!MO=G^t(Ya-`#zdYMAM`177~{(=vX!!end=q=&)yAt}=%z(h~UgF9U(HcL!l zVFT}8bQm2=*e3fC+P6zV@kyuU^EGa#Y`jFo#D2aj#o*Kyd;5x$a=0vMo}{{6ymB26 z@t#LGJA3@2MZWerm~p`T$?cfTwp#G004Er=y8)}R+Dc+XV#uX~7qP zuMhfr!NMkfF!qz4d2Yi8g^<)ddho0LN2aKtUswS@Z5N4T(};JfyuZ&3%w9d8QJyo+ zL?@AS7#SzKVFccAY(Sjt-QBg-tcxnRHPDr1iWe*;Ewq!it-7qOe}4-JE(RE*H>4S_ zu>eMOPoW)edMy0ekqG$FJCwwqvwx&C;h4u_UuBv0j$=*@n-m9$9r(EEkJ4I1MECjmwsg_Ou%EXno?e}5w{dVeEGQ}P4SO`y?Rmr5yYUe$VSP$RZQFlG$@_YK& zu~Rdt#w2ci1xH}-)T<}{b%O&+r{{KZi0jxJFsJl{w%6Ut3x!511Xf-cCX_o$-~1?{ z(Eesy0H;s?+sl#3bI6n8g6G!F7And$`GD+QO?mI{Ed*0BuSHUW6v&_(AZ`WO+wDJu z=-1r}j>_h?c-7l`9b~($#o#zL_+7Yg?R>DduI@_)J+IGaVL{mCYAJsFDAN?qC8)?>##XGOVhx)YDaoZo}Mb4&p0w2A`zhIt*IyQdkXd2hiMdTA*s6T(-a@;4?!Oxx= z(iicAf~Oh%w{0u0!a`PN&J2ad+Fw0ch&aKhO%alAze96F5J9n$Yff5=r(#JoFT2@s zT{rI|H#nZmlksM4pgs@z4)^ve!I{h+KQxt&_WN{F63z6-^8CKp$+ZvfY!fGc9-w~F z1r!~e&XnRXDAjL059Qj2ChNe4E9X`9G}{pf*!O(I{tRLQtesS0D6x(Qop)TnU%AYf zZw=M2OH>Z*j&IJH@154qhX;%SpW2(Go=jc~t#Y|e-Q46+fbi~p*^0yaq-fRTLfo9) zK6MO-P-3im$HvouwM{lWQ%k8}RkhqB)+&8i-p0u+mlZdwxe7ZZgbXDpKV{=g6cd%n zfPh|1->XpuV{pe*9+l+$p9_~4^!u!@mxijUwXc0Lsnc&M~yuG9XaBX~*We$I3rDxLf&J|K+%u`sf4flPtQd9HY-^lV`VmZl}=W zFHajxq~bp|<868v6g9@dj$>BSE1@(F4r|+_LqGPwXD!xS>I|T(^C$<*zhMHKiyzcc^OWE*o*itj~^dzQjghUfTLfj=!Z zQP43*d@bhMmr2Jc7xOFnUd?nHdTNK__Ab7U;qMQm8pY;!<>9$<;dt5DpWk$1p4Ph=e?LCQ>?YD{gdB9La5*yEy$_Lhd z^Axl?zQ_>O_<5&?A@hKXE&e6v|9KI^s`0yu-^u5$$|bUCS@C%m5yO1s-`F*607A8y>8;1)t~cemgk+$FdZ++6|$4{k|tcN-jnyF+kycb(tte)qHc{sC{F zIdjf*Pj}btuDbHv=T=GNO<8dwBbgDFB;OaSs$#`Roj-Mt3JbG8;~fU~5wc50iKmyc zBrXYj%3%oBPw*b`UCMf7kEAN)89dWTT6GS8UVB}tsr7v~$8ka`CM)NA3&}l=P1VAo zm_r8sjXv4{(TC9A+4CLacO70$(<=Y)LgF2(4qLQxC4y%;Bc%qITU;PcYMAOf5xeqI zk-%AX*>SrV63)(J0+z%whu4{GHnK>*Qz; zA4qfWvR{7=oTAQ=->0l|nM!HuI&|EmJhF3J14fiV%p(6vS-*%)bR~6n3?6pg;^Gde z&is$R@|cq0yq78ij1HSJlv*+}s?oAb3;z^P_x8~!#QdJ~nAucQ84vexF>5dQkW>2W6!w~7~a>VMSfGw!#jrpcE#U98)tV117IkzCM+ zTfp(xOPz(tM4w{@8G7%XPL~79SUOAQ5i!;O*+vMZCLN+x_ebT8+$X;GV27!vU}p~H zzSx|k&#EIaD7L(WUFkjt0r7G9 zY>CE30mUrAzx)u8rmBG)l!#tPIo=(FQ*geT`|4pkR}=A?P`pf+Q*o_$x%z($4#@r1 z^&!EJhrdW!U3=WU^wx)a(dB_R2u?-BBv75wAwqI`9!Dg%3%NJfOVh;kpd@7o4m55$ zSj5MJe6HV*=KGrf_9)^c!BP*Bsv$v9Bn6#~RYbnbvO)iH1;xF%e8magpbN`Y-F@J- zz7uKh679yr*9y(gRbi}U9Es)PUs%?nvPbV@K4Nn; zUJU*u6m!k2_34T~{44TRh2y`}_@cJFaq?rmxTRve`}+^>Gc~|GISjdavT+ z=ci>qO$;$i*#CTl>+XoJ$>+ED{Su!&+Nufsb;uZ*Ln{?ntmwA7KSW&!V|P_#GLXN} zJ$Ss!cg%XK54W2N#v}ZHRj+bPG|+2Cm@; zQXmHZ-)F`4Ip%TK`NVde*U8-bvo`Jra#_~v@vUAXxk*8Z!Mq_BCRszxHum<11Dwb| zy|sDk!mvOI#%7#9ADa#-ORDL4Tf@a$YxKxSqKDMO%rXjwN`zAd<7Yapb^P-;Cda2% z++8RyeL-%XR@dFrzS)S&MRvsQNrV7oP{6>1C*I@ZJ2ry9mIXl1R{>F4SoTNfuDBrm zN~#a!(7>PYn<*|>Rz_C_%*2%KAM}V7feLtU7tFZu|9i3yxprV#D>7;_KT0+>S@gg# zaI2e3ShnFs2YDT+1GWj8VY~B69=PH?Vba=Ac3gj|FkO4@sBXgrd6^y#FQd5BQ37~r zM(JKO2Ru{9;_4Ujf>&neBCIG?UPLDw6z1C|xczS|@y&PEn!3>Y7({>>R?tCbFGxXfQr$~Y^ zrrnVKZ>Ko><=0t;AxakE_c0>N%j4@;F<1aeG;t$@LCoFe^K-R08GgERXDy>aJGSqA zh2Dy^eCH$i+v70s)G5PP(Gn6yJgp0`pV~Ai<2jKH2Ch+pR`rS>4TftFh z@t8X^3NajJ59x`s!UEAK436#N%8DyjCFr;YVr%lfm2>(C3rs@5I7;4FDR0Kq z-h5^Fa?%P=nnR<8gi0*o7_D+ktcO9wVe(q5q`V&(Nm?`A4|vYpar9Nw)#={3 zifOGXH+Ft}aSXt@Cp%6Z__(GITAIp9yT$!V1v7T~|9LOTud%18RI-Wr&7LPC^;eUd z%@IWb$mf_!Mu}8})TAnX zQ|mHsN=ttIf^*pmHs)cFm-&>(?Rf*$H(jew*2MZoj(Ik*PW7_c^AIq&`!%Y--18=A zmb?K=nms@H)R6z%e@8V1d21_ct_b7p`AF$PQzW#!fsI9z|Bs-6|*jC;#aj6e#xk_HCf13hc(7 z?X!{aJyg0gOM=#nVMNtxhTks@Rlte$tSsOw#kr#zL^&RIB>qT@a$K>FGhqreEvkE`3A%U1AGoiyl4 zB>o<9ZpB|jVGokq{*#jvJD25~eTJ$y1OaUWD^5JkTLqNX^OwUd2fER5$Y$%hdYt%= z__Z`1Oq6{{kba>?24eAdqix0g*YH@+K@3fSf>EIw%=watgS{(@u%k?bF8HF|lbTD( zQJW~Ek@eK^@PQEN=-CNSNGFj##3qyZfQ`KyXF)A&&3ge9`~=fK8q4_#GC%+2K_}rQ zXyVo;g8|})AO#P7GXY){;B(cttMpIGlf%74`plizShqZHuU8d30VwS0^=%3yyskzK z8jo?{WQwha1bIyKTQ=0BA=Y$MRt4lR3S8vH05Qz3!vQZ<_ZoVUFcJB?=J7)g?T^dE zV1KXuHqUvJI?W$=dxSAk)D!x1i`yBk+rc01zqPWl2ne)R_q9j(wVS@?34gxfi^%GT zYd0oubsDQfA--32`>z?Y_Ao)~)F{Eg!Vvo1{MFw2eKj-?*bUtYaezWH5Z+z#-T?)k zJC}bxig|wI$%bT_!S92oKfXM+Z`{VEsFMHbyxEoLVm*KENiOM2 z_rQaB89pbumS)GECX-k2`^KA?<7DgawW*27s=yo)60tqwiZpAAq#LEO9x?J|@9+8& zy+6aX%eBa3g57)CAK=ta>wf5fu~*p3h~-wSSzrLV89S2rFJkhF3m!mJiR=%0p)rNL z=T%AQiX}FgASDyaCw&q;`~icfR6X!ZlFIL`E;T7H=V48qO9wqg#n$NPH)dy!aryl$ zcOM-+%jBHqke(0spL)rxvrA6vtJ`*i#p8LaEcQ8`3RutW!+670 z@KLzz!s_$W)tAS*7ZEKlm#G2|yo?G&YgHj$^Q1s^1=zpQGqiynE@Y&762AYrUq_4j z?aBJ_?H3CjRG14V8WUQY3X%%^IsTdf`*?j`r5;6S9$x?ZMbgZ<_G#Zu_D z=R?3f=$~N~Y-ird22L)4`&OA52UX4}Pw%$EmFs&sFW3BW1F!Q1;sspsHuqI2yv25U ze{80b12FO9R>2fO+qJtNhXg*9my2T4O$@3IZ+G#0@U#r=6Fr#pyF|bkh)_!bEJQF_ zQ8_Vih7h*5wrXY(E+Lo&uM;aXYbPUP<)1#&Xp~=Q@(<)g&FxLQvJ{uSpAbZ^A~adM zu-{I#v;x3Va*77iNy;#R0T)Klr{E$+*k2btLBOx$>%|zJ7aT`Mt+(^i9xyEX$^4&( zl_hE}4+B5}Pgj^C>ALrm>^iGSb%$)QM}3n34DgdJyM1y{q92MNUHqCvxiCJVJ(RDh zy~$&6Gvn?nWo6+(@YRvC6tO*)6VD!L=bwV)*YYB&$@R7QxeX2>!i#q`T1=S=;w89 za_nAzocew{Fa1^vOHBPvLN%cnwxO1?kKTD&1dePJU0E5!T-8~#yaC|p5g_jqHzU*= zr21(}LDtL5vy-AshtG=WS#2y!APnYg;Tkmlzu*#v|Jf5s^jFahd z@8NbE2hvgcGjsF3rM6Z*xArZo?Z(Cwl-FLceD=jlzru95!Yynze4fBR|7i){l6U9+ zmTck-F0g($`W4UScDZHIanq+jXtvj{L-b#A&QEpce1giZHuPA0NDAdW%Fb5 z>jz3BSq(lMJxPD>{4yb5Xiis?7DDd+yL?EE7sc$d-{=4OuksN86};WK4gg(L@vMN1 z`tX?#kV4+`YVOVE`6wNzslGg8pT?D##FncoKiT|`Fv8M$l3GpDuz~dotC|g$=<`3gd0~KN zekL^Egk~}=`b#G&q5a~3%Kq`NrtOvQESRfGq0b8*6)cd+8(i+Q>cj3;k8f~+bBD5G z#8lMZMv=C)l|?fod@(i4eT0_h(c_Bd14!5qh|lyH>;J6cj+!+@tF=0=Mm?hWyp+kt z3FdfG39&INalh_Wgoz>oTVHkL=$XTepT@!ta;6h$kxvyASx$dh3|n zO>8BXgk>(IYW7qh5MYLWms92~|A zCQe|?V+a0@BtP=&9bpcI{c_gl$Q~&DQ zZx<`q%E>HffG!-GKZXWbUXGw0e&4|0mIZwbHp`&h&hTABO264XU)KyIJwj~|C8Z2l zb6dLSX6|H#Fb8pC0~8AU`az_h{5J&4shesm)s?*w^fJONB*v%CvA?6%M1U0T?!6@f z>rJy8y)$sz9DF+E4QlN*Dc})7<&`TxDtAau(N2|^H|)-dICNrQyIi$i`Lux9@L`TQ z3tgD<_L9QxvqOGMmIFowsEa!u&hO4YM;U8$N6?5a_?C~3S-hAVZc^{G=ar%+c6;35 zibhaoE)R1GUGju4mJn#lZe8v8R7dxXIQWQ>ZBL*kNsdoSrlDfD*~Xx=+S`d|U1hx@ z#qtWLn~I~#%2o-rEBG%==ckiC2^aiwU=_^z0%{r?hbmTNc`avSfrIr}zKn9fI4JeD z+uZPNdXgGXt9vD(<%r8>HYvunr$(%7d~%3G%vj;KbrUPhxJTuh<>WK4KSfvj@CjPM zL#I`U63DSAtz;gd;+rtm8Yvj+0`=g?kstv2krsLXv801VQymMZ1M}jxlD|*b{8Wcu zA41}2Yh9AujAZ51hkFEQWgnBmVVa?%SHY)|U0KTdI)=otonCY8$?qbcRbKKKHeT)@ zjnJHMs#e?Bnn=(d*u>xGP2=QPB$E44iWS5LFmgmH#74^=$67o@h-3O;87gw*Xm_Ct?_eldIY%Qo}oA-}l zYRf+&SogP~fZ4yKmS?u|0?z`+@`OSKic?2p8WyC$H-}WqSNSz3(3!ZU#;=6J>rw{7 zj{qPbgtL^ExG?Q#TfcKiXCK8aRP|RJ1{hTU@s#ry(ec_s_OnUxXTt&&Lv~$IyhW?; z#z#4}w%pMl#q4cPtZR0r>T9b1if;oHPm2eCZ(3(15fK3Zw&V{~;N%fX8Dl?_mhgAn zrX4#=4YF*d0%9ghdNf|ZN$HsiK&)JQj{!LFu3E9FQi;VMh7~b!1|BrFdID)@=U*d% z^xc>_R7q@DS++TIc#^Jdg6qnWZS7?^Te?p({nJO-qyWIv>)>4mEf#NP~f?%le~z_HBWe)CWbZwmi#0grCgCwwyD%!4#@Dd&9w;fn906Xu!r9c?J|9 zSXWyyWv8ILK#X!+hQdWG*ZFrMuK(`C{~5f0cby9uRDenWIuL;t0v<_-Cz1eUz7klm z>qTHE6qs*XgVSVcg02#mYqMV-Sb=7L`^R<>=Hl}KjU%S0nl`Gjb?vu<(uXs0{K7Rv z*gdWMxjkr90H9$#stGNMEA6=P{4I!{1Vb{v1&Mo<+T7LtX05CZnPGBBi2gf{?pu#x z5ND{3;81(J27_EV2ndK1$axWg5gy)Mo-6duhpQFvE0|Wiim^jDr#OJ#7twezyPek< zrW-SBqo);ndi-1SlXu{Cjf*J43K=>eq4nwg4DPBVDx@8cynuIH(b@N>j8C4PRq@nQxL`!>V2Akyl7CKn|sy1@7b#G_jLIu_> z?DH9~nn2VO)Pqy)PYyP{26YLnO%`bB_agrZL44^UP>K=hZlz4T$R*cq_m77Q8UlC> zlFtO&Y+fXLK1KilQ5%PyO8(&Xjl|}^=S;7c_dyZl8nj7CTVFI+@x$VC^>SY8F4pu= z&YKNwmGg%puXjosEWIDdaWej4LW))o>V)I$iH zI*EyS&}s68oMl2cQm^xs2cQ67EtkxLse8qAwGmC&Hw`9^-V0Ew_PnRszeS4gu(uP~ zw<@oZl2T)sv({~x-bMjV2;3d?#j-sb=4L%2j1a$-&CteVWNrf7g~3U~Xh;e09C>7< z$Ox~xMK187EvAE=9pO{tzn4x_@e?c01(mtEZu$L^?#^U=JOm8f_X`Lrx{I zV&Cg6fIwP!Zl(GG*^i=uajyQ+L0$c))Q5ECQ1_@80$7Ol} zkuMczhS|sV`7%zk#I`3sN9EMtEs`vX7xrBhyl<88L}l^MxOUd9Slp(F%KpMLm77jl z9Ft}2=&y3I*sw?~BrRj@XTtyxjR=c5#|s2byZYx(HP5A^@nCL*b9}H5%Z)la#1+a@ zivtCsHcLy3l?-v}3^T~jX9&n-vl;kVhikzclf3&H!`xI|UJ8j#>{cr}^gjHc0uVA1 zQ9|aPm>Rb?;h_^SE{@@o?Icun8;Ce_qi`bsv7A!RITMhHx0f4Wn%eA~ykwz)_2=$@R$iWm8H{z3ef)>yvFppPVJFq_ z0S`5QMvHzx!cWJuAsUUZ>BvHu$)gnf#Hr@jQAHPwy#Tix7Yr~$^ zqgFK1ie9L$eF9f|uh==<0$AXJH>*sZ08wvNMKM)fGi6c$177q$Nbe5WlH({#+yD>~ zL9Xa|@l8CTd48V^xqD0eAVVwbh4lO-IrrHK3D|Kykyoa&o%)I$v+b{Q$B;SKOZ z0^V-!ww7_4@bJYq?FoznO@KhCKRC4^beD%lvg|^czh`Ka6j!{r8!|iY!@|1ctR$lf z!y)OF2rf^l6l_+7gz960=he_p_i%>PVL)&GJEWwchjsARJMvQT6@>R^Axi;LAQNkd~Pq>$*~8x6mudF}udSm0_`J+IW<4cJal&*OQl@hPN<)4CY&ODpurTh&1j}K=Mlg4fghyxnmnQcoU&# z2a;b4=(V&+BGi$EpkD(xwHG~Jvct`cANU>x-l{FulfIj$QOQ<&sxhZV5`@zwIkdkP zEd}_#$IVLmm4sVPD1$3YTdNC{Gx6)*G1H>O2N_xAfnoenIcyVETAdm`}Os7mkUukZtRE=R=9&kf$eKgNdTA+ohGRl$LIqW27{S1DkND#75}fS2E$DBLKTxNb|6&{EQOdS zv*^{Y=7G+Xn|5Ty%WI-lt;C(L+MX@K5W9Mqq2-F|>?d;9&hNQ80*~)l0f9>)_@T1A z?<3t+$;#^f+&Lwc2|;1}2sR#!958xW#bXQ3*|10ySM90DL~3%N4x&4`+Ed z@oN( zS#(2Vv$S6U{gQdY*zA@`izVhSeTPRmD3-BP)^a3TrEV?emiGJdC39mEpn|%h>l?NZ zB~m5jq;x&!e%+1?5{<>XIuuJeXSakGPX68+Q2($1@&go5zn40mLO4CU`G*rWKp^iV zlCwV^K9C`q&B&o^pYYVL24qVF)YpqeI4=Gh*G8k!)9*1nYUN6-?3i?EtPNB`Aum+Q zQ#7|cLeBf;BWJiBR%hPA&lL+(IiF5HabKT4Gym}ykDfD^oW5!GkF)j!nExbEobtGE@;w9l4o)!f!B@cq>Z3>Iza$Lc98ArKSFsPof`%2aG4PxYNeFn{@ zudrpX|MU&?nXq54lgWaIw=q_lz~v(E_TbApRyT0x;PzS8b;x;ZQRX#u|DOG#XECgn zpgBZwsk}>i*G|@j#?r1!^Dh`_$TS=O`0&8pAJn<`z?X`cUc|C2_xYaxAGbT`l%#Jx z%WYQS|VxMBguXk3%1qX2{g^9&^#3})NxXr$~M!VSyE zG$sf)(Hor`sJ;kq( zz{8@~)0X}NoG)%RdJeZ15D1H@wJ<>w3JB0ZL!1NY=>7Nq(crc1t(ey%X4>LkvaSLJ zv9UgJq7VFj&xaQoz{bd4E=nDeDj4d}&4 zh$ru5g^ViZvjG6xQ(m}0K5 znmATlq-HF?Un>1o7QaxzXYsE6uRgq3KS1oZ$z)u8|D+%OEfI{UAhXX?@zG&kslmN| zOnRq6lF?c(?B(36X~4sg5mmq~%bk!`fTO0S_%Kyp?@_yZ5j8d49)1Y9ZGtdTaO$oT zpmK}~m+VGc`$F)!z#f0L@k}0lp?+W&7fQ>9)-PyNJMtq71eBmWx5JoPp0o8(tYa=h za4OKv<4H%B8%DmRy9ZtTVHhM25UvrXnYW>aso`AXG7^(%4SR}mrRaaJWB4;IAa9JVU7xxa*r_F5|B7jk zvS`lpk7CAzea!#YKhSV4&Dlpi#=s*yYp9*1n2mbWqKQ4GfbYVK?A64Lg8zR{*l~gG zdm*;}wlDYOtt?j9d+kYgW7_`LFbwd9iFGDz2 zW%QrG3G%00W!k;}W!U2ch)G zi-YkOeZpFUZxzoz+XLkj+?z4@$JSehsVHLc$^y98j+W!A>vMDGu5}&2zZ?X%)KvV! zq-Xh=xtTS{-e*q=y1(k02I}`rxm@>}IS-gf5A(!Wsjahhj@g~epwxkRzruX#2Nd46V zoiLLt+Z+U!g6OI5p!6>ILAs#uEJkIU8+aElbGq!>Pls)1HU4^9=Le{MdvlFFXvr}- z3h0BJ?cMr1I;HEvOpeNjO%q=80fmgb=hZ~#`NmzX&&!}E=~YIWEu!oxeM4)uN))Ql z!|uB~!`A5CK!rTT-OP?7H-XmHR(%^6x1FGDdk&FhQr>w!RpqL6$MQAL=}M7n8_V}d zXZ>y4sm-UV3ejlT4~JNK9#yNmmtTL*9(<>k_u~761;qE@nl*B|#c1nZ-QA_0UVr`i z)j63yk^=qg5ZJkv#Qc-VgYPS>l=pf4xHdFqj)SIXY`O0bn{N_X?%*Xexo^ssH&Ud^ zlniQtA~q6+DJ+{;p|W}Wm&WR2NjA%KBGkzkP9&oTm#~v{P$y3!H{qX*#`n=j;sF{<=V_VXtWI4Q1b)4N|T0|s`M%0lgmC&Mn#f&4ROKQ9iXd9AMCVNXl2!VIPcTi{Ff*MHp&WEtRbu7r99ZV&{i#sZjD~cT3w@x5TTe(4 zdgw>SxW+BI_qCiyfN@$b#-F|+406p?CBB4-cfnm4f^j#dlu6pM3L+npK@1VWLf8tIWvm#R~<@&BjzyE#havXaSB=@{xs* z0n`518p5foMYC@2e2fUtdsTi420i{I#8I4qb4#s))e^}BXwi=_uD*XLDxz;h&J2tzR}?h8DHyhEJN!f$ z?`UyzUSQTDa#kMjRnrc<_g9i5C0m^XKDD5o)boodwExc zN(08C`-l7I^qak<;M3!Ko9v*%5oW_>=WQCeRlJ_YcG@*TJy8h#MKV!%dw=*oNk5P# zbFE`xH{Ri94-4?ZcUXDN54db^V9uri9}cfh81r_g3AUjh zX`Edx1B(~um138^P?uUJRXAOk=;GeLbUu z_b*w5F3{5Ha6f`)*W6A@Sm#(Uly!MiL)t?4Co30}8-Rn1yH;Sp8(Nfbo*Kc*MUnra z!eL#7y=WEAd&V6G_s;b1Jo`?sTe79zC>suYeg9F)Q^R{y@BW`TUwM~Slk{|TW8>B> z%;E#uwqcVJN>z-J-zBT92nx3P`#6=JtNUw~$_3G>m*_|~z^HXEFTWo|pT*l%p@%C} z$+y_atyX+kpkY0>VjBOYj*O~S%uXPG{1ATn%=|vElf@`uPO#w==`T+smvr~yOY6C3 z92P7yqCCX8g1{%p%WIqQ%72ua!YBktT5Q8V+k$C2vamAka}pH*OQZg@=fh z0TN{@SGdW)+NCbg5sS8e8m%9uB+vkvU8` ziLOUA>?>RBRjI$-(v@;ii3VcCDVVP&k>pR^{6(}4=FSh{J&cmL{S)q)Of?4xPN4V* z_$Ki!?4Z)#_NN6byGpfV3z}{sW_$4I|DLw8xFd`9?x&WVB>a*BD>Fr0Y}E>Xz6&i{ zXl*+E!CERV+M(!~xm;ib1%QQ=#d=hO;)lu((hXOKqeT<-=FRVe?G@~CumC3#$`~A~ zlK!CUYTE|n3(5^S-{^i6%oU|38A9&LJSU#!=TnZKX2W9wBAsSL9G8UqjRB25m|0d9 zY5UJFIz{|;oz*(m?_xog&Pu3NLf*Bck9;3V8O^O5Uwh{5WV5YanblVCuWve*(d%GR zvd%jMD`{>1b?hsBbOWhn6#xA1^Pk(WE;nH&#^t2#?WFT0;4TzYHGz&N*G@1tw5XG> z=ZmSq`y~-!!Al*3;H72Lp>c~NQrlgRCR__kOZ>)i1FoL5VCEeD}tBeqnqQ zR-@ePVR*+Iu6Da{?)e47S(c;YkUc5hnZ2!-v!l0KW|jfZSqR33&n*xV;)z{9KRm#? zs+l&XZ9t)LzmU2|SQm4P4kb!Z!fs)yg?7cJ!~3^X9)-~Kj{jZAlx??wMOl;GUqc(y zypK+|dJLmpQh5n<_1ZowY-1RDsqeYf^4O~COU+FiLalP7ObxC5;-c5DDxoNNkFLLS zxnmjE(uoKN2vkj>CGhJ$wFi5YSCqy_(j7xs9W}#Q0|YS&Cf05vgRXXJkxc`M_T@xa zJ^NW~7R1+b$Gvl#Mb8x};{8@;$PBt9O$%#6%UW62qa)k#CdI=E1S4otbr)ptYd& zuax@-C@|ewe`D9yV)wp8H3&_xHsCZ(*=@MB`pWt7?yR%SvkBMD+)Z4e?QqkkSqwDi zae+<0J*w4RT|>6?av$zzO5Nb^%XCl$MRQrUcDI_X$2cg#6h<s69|sld%MbBP+MvdA9+&^zN!$C3D3= znU@aP8L79>#SKJT}WP~+wvl4Pon0ETGk z91z^)SUg+_xBTNTyy5dtVyAXCkQ4Jz8X*_YtophLDPKpxWFBYQcfA<)iT_tB=^JP7`0Un$rgV>; zc9t?viyIV+`~ntD1kCA}8?$Qpo`%%}tQw@q&+ZMxow8*5uyYP`B1C3|VkL_iduxjR zt&YvZd|=f$2uAwRyBAMOXUku38W$%`e#!)qG7@4L-#m0%!Kb9>0v!W5;UYIyz(>1&h>*e%cVax4F%Y5Ly%XTc#S zV)MdZf_8^g48ZrSp)B031!hW0Z0$4n%g3fqP+Ps3vqVnzb5P?bDtTzl-8?l4Z~iDLU-Y~N__}Itc!%?nP!`oHw%{c}ye~*^=z(v>n%$~Hs(;csBzlibaLkOj_1|EK{ z6`7Ok4y5`ecC$TvCD!8D>f#v8DY)YOySaH$)z)RPBlTs|X}}O%Y582bE) zsHaqqj-i)}`(}Kcw)nb;*uDKFXn19WUi9SR?_6qz2E=^!;}wK-SASr6fe+0M;PDRV za@JjNUpj@y7D%LX_HrcRz|spg7?6N1;wN}lI2>o~4OvI0$9>0`V1^B)E_UyCxjGyK zvrYNjx}QWyLaSOnPdc*BnPc(-8%7uPTu9l(2Ql0lZPslI!l&+WtG6U)4@~Q9**Q^! zvdzo?))gvNXq{-h=OjSoDnI;;3K5B5RvgT?{?AaU*-U&se1cX+X$}m2mCNQHS7BkT zx64=K?=1mW1`MZPzd2ct+`VD* zgs*@M zI|=}>Fi9@ZJW zgH|}^^jKofZy!aUYZ$4k%zpz!I9&AS)@-5mA<0s_1<7U9qJf7yNw)@tYY zwm5XL>18G$v$COY-o5(ZlkXK`x^kpp!U7j8Y z6c;nE$PQcT*vd*YnY+)huiz``Lg&o&&KWWx#TiQwha)XYJHIQ?O;kIY7`?Kz3PEB)R;#2^Y)2SXD@bCvl_ZAb6k-1zWtEm?}% z7!qm5IyJg8TSNG6%rAv8IbhgA=vI*9jGVk`46=kb?11uaz`b-`%lf$$Q=zfV&qs;V zr=ri`>W};B!Vj?xrfI*7=cl}fpA^Pt8E_h3gl>61OSOZ122byT4N-u$ks*4tmP6*E znXyzG*>CklHgY{72{ND3Z|(TTR1!ocu>Jb#6k`paNlcX@^#eW6 z0@FWhou%iDi$?()14p?+*5o!;lgaf4<%Mb#pu(g0Y^DYkz1*po;;nh3onq(tN;$Y> zF{tV~pYJ`md<}k`ykfgm2FWGr;mG~3-4tCpPo5k~i~gT~43`^7mVPf+fAE^@9FT&6 zGd+EVGwag_)Zrxo;uRl~LsLIWrO&M$JCwZs^x$;zN0)#}{&;05fffDdE061t@yPkX zLwP0}zhoi@=1Lc{SL2^4Ncb#Vwx=s6?l6}axyEv!ck9+iR^zg0O1E4K^Sk(T)cwkm z9_gnH!*qn2zWeI7EHf$H1zVT2cqmCsew;6{w9b*7=*nHKwJ0U+?S!n1J|!lut>SSI2r2gQ}m<*UYo z46L0(>1)+)YWSCV#^Q)oyz#F2^hZ+y9b=Ol+OQ?mLATBxix)jgib$fnX23%c2~OS5 zVdL83@2Jou+iFgf?_Si@$f1)Heg#tq2#>>Ss4L<9>&InD356M*`|5jME;hKKKEe{r ztZahZD+bj%XLj~l+K0#4Sw_~9u2^NLgrsCBR)Nj5t4}s~Nn*QZqWiOdaB(e9J41oe z?^(Wm&B&k-9lpm$LgERrNfV)4`GB>s$POnTQ6(j%Qju+|vWD|nr-!7Hpw0B1-?6bc zj{p$gyJKc{qxiXu4zh^m%SJV_f64IB#5(=3CNMf-p*@g!tpUW_SXVT>zC3OQAsIUZ zzza;nya;W_%<%!OW|(|@fiZ_%MgJ6eTpE;4+`^pu?B0Sy={epv1!^2}XHXAT$A){0WNDkqKrA}H zkT{uQAnRcU{6`$pU4?uOh0#sjPnGEUGY%M`+gc<5G?agXTk?uGQ!J^~sAVJC1Jqs{ z2MH~jtxKkikYaan#4d$zNi7-q2E4ahD3D-1x%sI)0&Wtf`pz)5n7NqQXe{Wb{Frqr zh(u|vZGNM*5;eGP;VfiyX3mx&-wH(zm5EC!0>MhC`p!S~+sv+;tzw`A$WXdRlMSr& zBYaUqd-07d^&2t0DPGc4Mj6xVM5BN=sf&WijhbK+hz%5qCY#Cr^|`pPt%e`O2pQ!n z`_%2__1ef01I_IX%{RwpyY9klm@=z$=Q}%&o>J6y28EmO4ho} zw{ol3VQN!>eWFiswVa~N2uX!({;GK;-rz;=iq^w0$CnUW;jHsFP?5B`w3=;$F#(nR zTFA>Un}72EN`ipJO+pg|{Mq|>()NmG&pesDP|+Ummf9QEqWxkcDXFcc{22hUw8vPx zpl9Z1R5b=!zqdTSEG2S&t!*8E11K(zRdF@dR-CqAF@Xywc|gOvu|{HGi8wYuKm@!* zpK0vCXG#g>bcGHRP+EWavc%zL4##LXS&LQ=|w9=-AD`R#m zzd}H8;4T)qkZmqo6yXEvCpdY9S(z~vzK-_#+xUOQ8;uj_`DCdx@E~Zm%TY#H zdKK;b#lh_4qKi{7Jy*G6oWi!VqBqJ6-Da2$`~cgmm)Yma{?&p7QvIxBeMW z$#Yl zv1*#v3*TK5`(bxotR6nF{+O3@;vc=6&^pcHp^ zEl{AiTY$8sxD|IOu7M&!lLEyx4X(kV!QBGn%iHH&_t$sV{c-2ltds1Sz30qXduH~` z9!$)`vVY4@)R|BA^@TUKc7-0+yS}I`7wr4*`ElTx2haJ&Gczc1xmY=$v-XMb_6M^0 zLi-Owh@^kIJ?|fMU&hBAPc~^uqj60*a3Y=`I=aEcrKZ^)*1#Q_L|;c^{j>MuIo4HO zT9zxZtEiV9w;h|Z5D{a4?YYwftmfV$z|%z+A#NVNQ}3b=`yQU@-AnuZ3AO43`V`*c z)s0!qB5}9dVp9B_^zIl17BL!{c>#Y69V|!gpQ`~rv+kc?6OK(`3+(bNj1*_}bdj!n z&9ImMye-!`=+G{Yuj}HK0w^;knr!ptW{90S{j@u^aM8CPTkOCjkFD##!&|3M>*iKI zgLDD-!{1;HW_V3qsJc=TsNLj}$Nt`lGm(6oH)s94n#0AR@?dDMRt3)rkR2F&)7CWZ z{qU`7y70y8@SSx+=rqqnuj8FXAgA)fPYbt)%`X+w+eu(8$xXu<|sLM+$dGgM4e#R@K&|1}lPj<lr?>;)?-Ob!wfL4i4T~{PWs!F(rukb(LKN)w>|HC1)Wo(*A-F|e=B|-4|^u&J%h=^HW5Q+Y422d+p^{o`Oa+67RR_Y6MM5bK@oday1~QW6!mr; z#FK?5=I?z`JL=KD4K4o^w9mKQw9_cGn~tk(PPdJ>U;C+1sd9+}0Dw?+Q~T*vM4j*M zH%*&L)3~$=)gfdTZZE+}ZwZDIwCaDIp5`4e`?! zy+q*0Zd^>U%?ftmKi?671#k(rNB$)4I<4ULJl>L>EzclZ}I8`K~BUMDTRUssCD#2&+Gc&5S6FyC{=Fvjp!m7)7l zF)mLhLq?+eFTphGH%ui#4kJps)TMEgE2*Y-_h#XP{P^1PqKe*8I}`n z-nJtu1Mdv3)g|@MrQB8tF8XW7#DWskQ0Q;<;@Bj}C$zHKVtEC3XYVq<=Dh6d`51+X zxR~Ixtt%IXI#vqpK;gutd5Q@+cm$$^BvtEzWKopWNlHEBYfsv4DRg&tVp|{9H`d99 z<91gGI$TIhiRG3?C3LeSm@0FCqaDgt;$n3T)$IKq7bRLTGXi#6xRql`W|Bq19wPT% zlu5s7;~IkY71}3o6|sI$WT#TCg*#G3vph4E=Uu=|A#5^hhu<_tK-l3G1$jxz-Pb|N z6uoGwt;RZqgL=p8avx!+gsPkzGIi9YvJzDJeX%=tbkwDA>wSQqXnRr%RNXn)g*;XJ zd!g@PBGld9=TgJ>`sRXF+eLrMf^a;0;bWyI_d#3zu!u;rfS$fSfK`Yq;ls+@cP;;q z#@fC6<_`=6ePP4zIXn-=NFxp%&06lSjo<e|!2gCuVFTU+oOI|$od->b1 zxAtkGiraZSz-v9iC^d_r@AuqtFQvIdRe~#z0*F<|6l!65tZozcnMFtMN%C;CXWDz| zDjk91V&CX-pW-BT#;tN~XZw$U4?jSo?K)G}-agg)o35TDB-$o<`>sCfZUoqCd%5+N zyRha~|03|+rRUu_Y&*hK(_@$cDn5Z&2(Q>N0}1q>S__D6#r3*T zGYrf>Ycxr<>HSh)AG6zTNu1_4mw8F*zVAz^C!b^wW=*()4J7!d=ng)qtE5NIJi$8T z@44+2?V5gltd*4+KaWp8WLM0Nrsjj(k)ISgbEDp1KRZSg{4CV-r-eBU@+x~&4!cN! zn;eRW)ohHFm2Q(0vpYA!bZVa(TYugVPKnsp=4*0jX)haT0*x$F zkt?9l{VDQH$FI&rRX2Ts!VN#`HTF^Ik;wB@AL}r?12so~Pa1cy+=AZ1V$iKXCr3@| zoq`vNuyC~3b#-Rlug^6_#N?h?-^_&tG;ktJCnuksed4Fr`yqeJK7zy9^+jwSVlky- z7=?RIo2aHgTFYNQX~kc8JFMfaPN#b|9q!1u=3nF}UQZiS$0y%=sA=5P^i)NwTfKI@ z*#6QP3`a=R44ZjK8~-y{BYvRuSyyUlh>Msoaz3vWwx`BeQQp|L2KWfqw*2IwA+t5x(_k~NbBmPp#n1ZQjJ8QG#GWfa>5z;*aLq9^TM3HGwyVnUXQDRdgu7ae;7Ch4 zC+S`~ym^b(iTRts!1Yg}z$^(OYEZb&;D&as?nbd;>6YcU&53L0CPKz}sc!%L$R^4% zijFFXppZmM`hZ@|KtedDW2?!~Kz&X=hye<1&8-<&q8f!;=2J%O8n)2@kCjom(^IQ= z**W&(pS4_UoLZ4D;(xT}U7E-QdU<7YR5@yTED}ppBuLf~0!NB+)L4~^P<$s3A9P-S zKE91`CrVIP<-H9C=z>T{N`xOa-{dh;22rYn4bzQQg1S3)uMvsc?3zK-3t76F``f4= z&1s6Pzwjrl$h|l9s@E9Uml+WegYliUt~0ajn1*Z09PqmZ91aIrmD(qM z%c6pmQyxY|y#sqaJtYo0sdqw8oi^gs_*tXja>rKpx7k+g>{KJFuQH;ehjEIo$itL^ zMZu2~6{=WO22QkFRT7w0;mnw}-bOw`{dD+OQETu&1SMG$Kb*nw5`rk4?LQ7y&psC< zI^4%6rv?AEJLJ%9-2?QHyJ^+$K%3*=nXH=NX3W^8e7(;ixm)KfUn9(ia%-D+6GbK#)-FhZb5V?U9n+*>3yE%_c{j~g&m;F<<2JDF&?gd2+fnc3QN(K)L78($cb}N$zG&G=dxYKlPDc4-%N*bcS0=X# z#vXW^7yos%t7=o}^(%Hl$^NBNtLwb%w1NH**i_3>aa2r!J0{h9G8NF5lc<1l#SsWh z?sQ_WV^y%0Fxka+JLV*4{RIz;(o$n!G&YFb_&uN%%M#wuMynuHHU0YJ49saA8YQwb zndvV`Ypj}dUoX;JJ9089XQcCr)DxdhJnTKy9B@~qrOTFoXOi9c8B-k{IdCFfz1&@= z7r$8{)*$x`xJZ(@rB0ZWl~fn`iiIq$H`~c&Y-&5!|F$`Vv{`H)6277I@@aI1x*y={ zGeuc@K?id7tYOY?-C_`PhD(R5bxwK>8k)wDc-mBpy>D9s&(ZPUg_nc91p@Zp|3Rc~ zM&TC8bnh`w7uGQ&T{QMBKIqheA5DCV`;Fm7v=~UG{i<+eG)08dP(K@HZ+r_^I-(yuLEa013~S!|a-PQt z2}=2_M5m(LvU-d+xW6?ZHed|OoTG!dQ{b2z1tR}>Y7!zc^uk_`^Entmip z>S{RRI9a^$flnnzL*CQ(qZ#e_QcOMJmsGdkj!AV|uQT*A1682!O9V{Mi50tvC4UN8 zY^rp=2BK_1ZPnR@t zZ1pty05D-#E5}7aT2`uO&0S9`5;t;==_eVpDS4+cxQ@P3Ig8SF`2AW%Cyg#!i%)@_94pUQA3ZV7sc4Lf7#g`Yj}P4jA-+`hP5+XkSm2CNT~%v?zPd{6H(LVUDxecODh?To~j@HR55jJH8<|bOsxGy~! zH}b%bDk8f4Tv^GHX0R1uziV0*Szc-3u*IQqV58~K&7a`egbOB@t7@=01;>%g=`GC8 z`;VB{syVB(hWfa1S;NT*u-=Zj7FgaNO7EkaQ5L9+;Z~HSMs{z{DQgVqbSo4#-NDOo z(rZotlb{FYUcyh6*EdgE35k z&u&Tx<~DC)=m~@JW`hSGM#1o;+RAHfqd?WI?#PRYZE3QpmnZFGF*hn{k)R4E56yc} zIc}|4H->Ug!@^&Jb*Vx=l)QI5NgZd`7KBltNlS<~3Tb$)f4h3U-OT%elC(~!r1D2Q z>K5svYR;nCQ=fVxuDZQp2vC(etS%lJgPjhAAdHpw6tD9)fW27++%tDLjn!`p@5ph1Nb7X@s9ErU&G0=O)80rEgAtrfvry zF03RwRxWqF5E@nN02K`>l=$7b4VzorH5b6KwBz3T#C7IF6+0?)KfvAFFU=zVR2;;L zu&oz|##kO69MnkHA4B$Kw0UzZ_V|v2VD^BH{j+pp9*okJl-q+5W+QhL`I^32M7+)3 zk_fcp^1Tnwg5&{O?h=qX?lZfzq%Lh4w6Wi4OdJx21Knu`=APL}5LKOS71>(?(P1;c zEJGSY95AW;tw0L#(~$PwWjt0~I#pG;cP2qXeYzc}PH+5jw{#P{tD0mbD+p|C_7_Vub;eu($`T2%Y}*)_4W94^oFkDi^{L+}DI zEFXb5?AqbV?Eo13IPWQ=C?voRFr{tj)Y)V~%T$nxfBVm~wgt=myuJpecvkIUTVLM9 z-N3>$P4vZCplTDLBTvZL$0(k?$Zm73jX4+9(R*b2Wr^k=8%@XV`gqT#4c*J$P--Jq z)$<-y*+lv!2uFHa){qP9C{I)>8a;S$;2LsxU9|v2pi!Fnw@7j-`1WnKMDz$(F~uguU$77 z;S)p71HCv&(^+rcOgNdr7GqUu=yu$BPnmS_G7b4n;hmDO?tcIQK@|zoj@^g3es^l3 zvL)G!QtNH}E>zdm3HERU>C#l19OUJBGTO`=T8EM63<60;SKrRkua162a=3ck{2qzU>OB3ck5eX-j+T4qOqL$s8HM?^YG1y_ABU-Hd3sEr~M zr z!*gq+s4bjdYgAhd90&OHul}F{JE{x~GXP&F35qJdd869nH`}<%7F?53)ZOPam7*di zD{zmoTz4<;%PS5MVt**=bVy|?yJmoMF3C=T?Mot|SZmR14sLtFxg4Gd z<7U5e2sxpe+9O77u{zB2xTY~%zqXu*5mmbnF?@%vwZDT_s&f)FsIbPSkG0=ehhV)j zWK6t8YNCgMxBbB2e)`j2>>v2iH}@zs>JW&Q1{s`|?ml#jxrCVdSJ3wY5C%s(zaL|F zYR4z69mhY%N>Qzv3c6exyYS^mzMjdhA%HyKLdnSEgyN-sJCr=6u-H*N&TA%zh3fQ~bk|sbK*uvO*05Q2iHRlfnNSfL&dV6**SvR42Kt(Z;!CR%Q zhATq!m|0^$H2?M1Qs`SuZN06soQz%``aJTY*(^Bejbp{nQ;$wv!#=xbPIX_C)RZ6B z?+z_rBc~sV@0Jetl*AR+lg6rgBP69IuvN+&2_ZT%7M?vg9#U1NB#xW& z&D5FeNHr2|Nt-+oPR<()DO?xYbm^NFIEhTy^}jE{)X9QBjkO_-8vJe(eIf)>y@1<$ z#YvenZPI_~_&dGa0!n&+DbpOdgOdA`n5jPJ0iZ1ITRDd_aSlo@{|<*BCw=Tz_nHh? zS-_|Bm;Xx64JURR&p-QhPtG~3uEc+Zc$D{U1l{zWij{?zFo2fZuEF?6dqfY!+clFV zp|xVL;oCgQN;PZ8YYxXNd2Vrh6-g|o%OV`$08%rfMeaM0jHugnA>a~?joOYvg(GQX zR69O%I1R0Xi)%+uxCi^?5;CtmoA~X#R27$FQ>^g|XF#9YD+U+Ywt`bkjs%4=B~<}{ z1XxSfNM4DWf(7-7=p(P>){-JO)-1-tNrlesdV+{-TbmvP^HrKaMO;`&v-xY0OjEO; zIAXGLm{TN6#h5u~SC2Cd{5g zIj-4DU&G(e1f-gaSQf|vMk(?=goH9tX{WaaO1@Fcf{3b?J{sYhZ z>3WrS);>EK;xa41vOz?IEJdr|&^DT-fi(%dLd-HmW?qC!60vEN)g~%(Ws=s>k&V2l zyHtONPRXY#?yL=3bmS$!yG>(nSk;$E2OWg7FS2Z1E7!mOl<;)#WC`v^y~3XVsOg9e0o&8nU7{aSt`O-=%Y^5 zpGb+~S79Iu%N^*AhiJ(rh^U>FlsuGpscz${xW5HR=DYFj(D9YtP7Zv*EwJ@yr298P z=;-e2XMFRXUW$Kpy;JN{2HGV#w(q*#%g@xCi=@}y%FSxFkI#*6^xa7jQ^aVzlJao#OS zOD4HGO4}5jqxqWzKK*688$g2YX9|K{eHkui9deHKzO^&KSJ2`16{>?Q6+V`F9OaSD z>9_EbDQcXk+jMmE>#ZE`JCbBS&qeM2XYgsA!_sRwmg3q*B#pgxZnuf!Dnx7Og-NVBS#)8lBFm3 z(`CPpOxYN_uR>I}<$RB4Vboc}8(d5QRl-wG%1nm{hdFGu9fBt? zU+1GB8^GXA(l@@~wq4(@e>#mDuCzRrPk4olWW_M3e;`ewpZ$o5g!vzSmt5k>!><^dRy!e#!6uVA30^QJVwSLxm$wA;}!?ILWhbQ zj=42w;YFWU2y~1C0mQ5ax-(C^r#dejeyU@M#5n{*TyHm{(_&fU}3z-o#&%|8B3(Y_mvo~i)({3gv zi?Y^`oG1Hc{Y9CIBA_fItCjgwigtV3fGXQoJ@3+);~3(l%Tgv~u#Eexn&J~2&HY#S zi3-7$+c*83Bog^D7AWy{^A2>eWxUekJ_pHt!k91A2gN#a)au5vTdB6up3O}0Nps5V z#d5e(&ZAx*-ZH*Z`geo<(CL5gX9kADMGlSzhCe43JVt}62JyV^enr)ZR0;T9jnF}9 zRCSArCMITTO8baQwiZlI0$zkqO`|a1Yklqfux=O9y?$~_?}==RN=anM*B|KqPGh=o zcmx9<0xmOb9s9&$I1^ITSw1B+F!6=<Cb#;Lx$w z+53ZCS|i|~tjs~}#aDE|a&ny8l}+;R8`8k+mqanD@~s#kDu&| z1&X0T!DDcEC-XyDCY)wn{>+oZ-KTui;Ak>2)@@)53sJx#RCk=F9r;&iShd)QeW3k^ zV)o_#>^aI${X@f_C5ClU7x{^6DAA`!t1Y&ZGluqB^Lu8c&=N@nbO|ncQ^gF`L8b=e ziVLdp$~!BP`Lq|cXd0iShPW)vZi1s`zJy#xXm?p#CDkd(8F-isCEO7DR$W9%2i10y z^Y4%uC+R>Y(z1x4CIUGo;Hf_1rR=Q8eX6z*d$JSKicv{F7r1E`vdWM-rng*o4X$Jx zS4a0kLZ&AR5XdzSJ?f6gos|6G3J6Kg5xIC0*B6#m#5ARJl;#iA-6TZXu>U1dAAkRm-rJQFuebn-`ZB z!WjLy{|J1^B~Z$fKYaA;bDPQ0g+ze5PT(4`Tw$GFxKh7q0AZ1k@i5fmuaaUN7U%CB z9BiS{wXWy@^r3X{$?%LtzTe>KHjEf}b()X9J)e1`p_u1s_Pk`Q|AFRGb`AdDk)0K^ z^u6n1(vW6bzOyf9U+5nEYjx)6MqaN|`KY@RHyt{}YC|78@yjPbe-vr_~G>KiEt zVlWqZ!qgWsOAh}v?fn;CZbe+GtDWJ6Dht`~ATL{YzI7A*9XZC^b9?l26+oE=_>brC z7c8(b2I{}4X#P;dOqubCGXpD)}!9tQF@~v42;Gxq0$y z#{Wj2JYgG6Pl)D5^&6tE4#0-E{~c;E2IH998H!Gd38`;yM`bzv*OkGleSp~iKTG(3 bc{mejJOU7Jbw)MM-{H#g8ge!7tiJpYFZpfH literal 0 HcmV?d00001 diff --git a/zerver/lib/integrations.py b/zerver/lib/integrations.py index 90b9d98ebd..4d8fe32a7e 100644 --- a/zerver/lib/integrations.py +++ b/zerver/lib/integrations.py @@ -389,6 +389,7 @@ WEBHOOK_INTEGRATIONS: List[WebhookIntegration] = [ WebhookIntegration('stripe', ['financial'], display_name='Stripe'), WebhookIntegration('taiga', ['project-management']), WebhookIntegration('teamcity', ['continuous-integration']), + WebhookIntegration('thinkst', ['monitoring']), WebhookIntegration('transifex', ['misc']), WebhookIntegration('travis', ['continuous-integration'], display_name='Travis CI'), WebhookIntegration('trello', ['project-management']), @@ -619,6 +620,7 @@ DOC_SCREENSHOT_CONFIG: Dict[str, List[ScreenshotConfig]] = { 'stripe': [ScreenshotConfig('charge_succeeded__card.json')], 'taiga': [ScreenshotConfig('userstory_changed_status.json')], 'teamcity': [ScreenshotConfig('success.json'), ScreenshotConfig('personal.json', '002.png')], + 'thinkst': [ScreenshotConfig('canarytoken_real.json')], 'transifex': [ScreenshotConfig('', extra_params={'project': 'Zulip Mobile', 'language': 'en', 'resource': 'file', diff --git a/zerver/webhooks/thinkst/__init__.py b/zerver/webhooks/thinkst/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zerver/webhooks/thinkst/doc.md b/zerver/webhooks/thinkst/doc.md new file mode 100644 index 0000000000..e152bae231 --- /dev/null +++ b/zerver/webhooks/thinkst/doc.md @@ -0,0 +1,14 @@ +See your Thinkst Canary alerts in Zulip! + +1. {!create-stream.md!} + +1. {!create-bot-construct-url-indented.md!} + +1. Go to your Thinkst Canary settings, and click on **Webhooks** on + the left sidebar. Select the **Generic** tab. Press + **Add Generic Webhook** and enter the constructed URL above. Finally, + click **Save**. + +{!congrats.md!} + +![](/static/images/integrations/thinkst/001.png) diff --git a/zerver/webhooks/thinkst/fixtures/canary_alert.json b/zerver/webhooks/thinkst/fixtures/canary_alert.json new file mode 100644 index 0000000000..e3adefe621 --- /dev/null +++ b/zerver/webhooks/thinkst/fixtures/canary_alert.json @@ -0,0 +1,27 @@ +{ + "ReverseDNS": "attacker-ip.local", + "CanaryName": "0000000testnode", + "Description": "Dummy Incident", + "Timestamp": "2020-06-09 13:59:38 (UTC)", + "CanaryIP": "1.1.1.1", + "AlertType": "CanaryIncident", + "Intro": "This is a dummy incident.", + "IncidentHash": "aa875f255f94e3ffe40dc85cf1a8b1e0", + "CanaryPort": 8080, + "SourceIP": "2.2.2.2", + "AdditionalDetails": [ + [ + "Field1", + "VALUE1" + ], + [ + "Field2", + "VALUE2" + ], + [ + "Field3", + "VALUE3" + ] + ], + "CanaryID": "0000000testnode" +} diff --git a/zerver/webhooks/thinkst/fixtures/canary_alert_no_reverse_dns.json b/zerver/webhooks/thinkst/fixtures/canary_alert_no_reverse_dns.json new file mode 100644 index 0000000000..af2f08a808 --- /dev/null +++ b/zerver/webhooks/thinkst/fixtures/canary_alert_no_reverse_dns.json @@ -0,0 +1,26 @@ +{ + "CanaryName": "0000000testnode", + "Description": "Dummy Incident", + "Timestamp": "2020-06-09 13:59:38 (UTC)", + "CanaryIP": "1.1.1.1", + "AlertType": "CanaryIncident", + "Intro": "This is a dummy incident.", + "IncidentHash": "aa875f255f94e3ffe40dc85cf1a8b1e0", + "CanaryPort": 8080, + "SourceIP": "2.2.2.2", + "AdditionalDetails": [ + [ + "Field1", + "VALUE1" + ], + [ + "Field2", + "VALUE2" + ], + [ + "Field3", + "VALUE3" + ] + ], + "CanaryID": "0000000testnode" +} diff --git a/zerver/webhooks/thinkst/fixtures/canarytoken_new.json b/zerver/webhooks/thinkst/fixtures/canarytoken_new.json new file mode 100644 index 0000000000..564812d6dd --- /dev/null +++ b/zerver/webhooks/thinkst/fixtures/canarytoken_new.json @@ -0,0 +1,12 @@ +{ + "manage_url": "http://example.com/test/url/for/webhook", + "memo": "Congrats! The newly saved webhook works", + "additional_data": { + "src_ip": "1.1.1.1", + "useragent": "Mozilla/5.0...", + "referer": "http://example.com/referrer", + "location": "http://example.com/location" + }, + "channel": "HTTP", + "time": "2020-06-09 14:04:39" +} diff --git a/zerver/webhooks/thinkst/fixtures/canarytoken_real.json b/zerver/webhooks/thinkst/fixtures/canarytoken_real.json new file mode 100644 index 0000000000..0dcac91ef3 --- /dev/null +++ b/zerver/webhooks/thinkst/fixtures/canarytoken_real.json @@ -0,0 +1,12 @@ +{ + "manage_url": "https://canarytokens.org/manage?token=foo&auth=bar", + "memo": "Canarytoken example", + "additional_data": { + "src_ip": "81.151.13.3", + "useragent": "Mozilla/5.0 (X11; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0", + "referer": null, + "location": null + }, + "channel": "HTTP", + "time": "2020-06-09 14:04:47 (UTC)" +} diff --git a/zerver/webhooks/thinkst/tests.py b/zerver/webhooks/thinkst/tests.py new file mode 100644 index 0000000000..c19ae640a4 --- /dev/null +++ b/zerver/webhooks/thinkst/tests.py @@ -0,0 +1,102 @@ +from zerver.lib.test_classes import WebhookTestCase + + +class ThinkstHookTests(WebhookTestCase): + STREAM_NAME = 'travis' + URL_TEMPLATE = "/api/v1/external/thinkst?stream={stream}&api_key={api_key}" + FIXTURE_DIR_NAME = 'thinkst' + + def test_canary_alert(self) -> None: + """ + Canary alerts are generated by Thinkst's hardware or virtual canaries. + """ + expected_message = ('**:alert: Canary has been triggered!**\n\n' + 'On 2020-06-09 13:59:38 (UTC), `0000000testnode` was triggered ' + 'from `2.2.2.2` (`attacker-ip.local`):\n\n' + '> This is a dummy incident.') + + self.send_and_test_stream_message( + 'canary_alert', + 'canary alert - 0000000testnode', + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def test_canary_alert_no_reverse_dns(self) -> None: + """ + Canary alerts are generated by Thinkst's hardware or virtual canaries. + """ + expected_message = ('**:alert: Canary has been triggered!**\n\n' + 'On 2020-06-09 13:59:38 (UTC), `0000000testnode` was triggered ' + 'from `2.2.2.2`:\n\n' + '> This is a dummy incident.') + + self.send_and_test_stream_message( + 'canary_alert_no_reverse_dns', + 'canary alert - 0000000testnode', + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def test_canary_alert_with_specific_topic(self) -> None: + """ + Canary alerts are generated by Thinkst's hardware or virtual canaries. + """ + self.url = self.build_webhook_url(topic='foo') + expected_message = ('**:alert: Canary `0000000testnode` has been triggered!**\n\n' + 'On 2020-06-09 13:59:38 (UTC), `0000000testnode` was triggered ' + 'from `2.2.2.2` (`attacker-ip.local`):\n\n' + '> This is a dummy incident.') + + self.send_and_test_stream_message( + 'canary_alert', + 'foo', + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def test_canarytoken_new(self) -> None: + """ + Thinkst Canarytokens are simple tripwires for detecting when resources have been accessed. + """ + expected_message = ('**:alert: Canarytoken has been triggered on 2020-06-09 14:04:39!**\n\n' + '> Congrats! The newly saved webhook works \n\n' + '[Manage this canarytoken](http://example.com/test/url/for/webhook)') + + self.send_and_test_stream_message( + 'canarytoken_new', + 'canarytoken alert', + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def test_canarytoken_real(self) -> None: + """ + Thinkst Canarytokens are simple tripwires for detecting when resources have been accessed. + """ + expected_message = ('**:alert: Canarytoken has been triggered on 2020-06-09 14:04:47 (UTC)!**\n\n' + '> Canarytoken example \n\n' + '[Manage this canarytoken](https://canarytokens.org/manage?token=foo&auth=bar)') + + self.send_and_test_stream_message( + 'canarytoken_real', + 'canarytoken alert', + expected_message, + content_type="application/x-www-form-urlencoded" + ) + + def test_canarytoken_with_specific_topic(self) -> None: + """ + Thinkst Canarytokens are simple tripwires for detecting when resources have been accessed. + """ + self.url = self.build_webhook_url(topic='foo') + expected_message = ('**:alert: Canarytoken has been triggered on 2020-06-09 14:04:47 (UTC)!**\n\n' + '> Canarytoken example \n\n' + '[Manage this canarytoken](https://canarytokens.org/manage?token=foo&auth=bar)') + + self.send_and_test_stream_message( + 'canarytoken_real', + 'foo', + expected_message, + content_type="application/x-www-form-urlencoded" + ) diff --git a/zerver/webhooks/thinkst/view.py b/zerver/webhooks/thinkst/view.py new file mode 100644 index 0000000000..b13772ba96 --- /dev/null +++ b/zerver/webhooks/thinkst/view.py @@ -0,0 +1,79 @@ +# Webhooks for external integrations. +from typing import Any, Dict, Optional, Tuple + +from django.http import HttpRequest, HttpResponse + +from zerver.decorator import api_key_only_webhook_view +from zerver.lib.request import REQ, has_request_variables +from zerver.lib.response import json_success +from zerver.lib.webhooks.common import check_send_webhook_message +from zerver.models import UserProfile + + +def is_canarytoken(message: Dict[str, Any]) -> bool: + """ + There are two types of requests that Thinkst will send - depending on whether it is + a canary or a canarytoken. Unfortunately, there isn't a great way to differentiate other + than look at the contents. + """ + return 'Timestamp' not in message + + +def canarytoken_message(message: Dict[str, Any]) -> Tuple[str, str]: + """ + Construct the message for a canarytoken-type request. + """ + topic = 'canarytoken alert' + body = (f"**:alert: Canarytoken has been triggered on {message['time']}!**\n\n" + f"> {message['memo']} \n\n" + f"[Manage this canarytoken]({message['manage_url']})") + + return (topic, body) + + +def canary_message(message: Dict[str, Any], user_specified_topic: Optional[str]) -> Tuple[str, str]: + """ + Construct the message for a canary-type request. + """ + topic = f"canary alert - {message['CanaryName']}" + + reverse_dns = '' + if 'ReverseDNS' in message: + reverse_dns = f" (`{message['ReverseDNS']}`)" + + name = '' + if user_specified_topic: + name = f" `{message['CanaryName']}`" + + body = (f"**:alert: Canary{name} has been triggered!**\n\n" + f"On {message['Timestamp']}, `{message['CanaryName']}` was triggered " + f"from `{message['SourceIP']}`{reverse_dns}:\n\n" + f"> {message['Intro']}") + + return (topic, body) + + +@api_key_only_webhook_view('Thinkst') +@has_request_variables +def api_thinkst_webhook(request: HttpRequest, user_profile: UserProfile, + message: Dict[str, Any]=REQ(argument_type='body'), + user_specified_topic: Optional[str]=REQ('topic', default=None)) -> HttpResponse: + """ + Construct a response to a webhook event from a Thinkst canary or canarytoken, see + linked documentation below for a schema: + + https://help.canary.tools/hc/en-gb/articles/360002426577-How-do-I-configure-notifications-for-a-Generic-Webhook- + """ + body = None + topic = None + + if is_canarytoken(message): + topic, body = canarytoken_message(message) + else: + topic, body = canary_message(message, user_specified_topic) + + if user_specified_topic: + topic = user_specified_topic + + check_send_webhook_message(request, user_profile, topic, body) + return json_success()