From 20f1f06a38da5dcbc4ff9a74e70c8a72c77942f4 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 27 May 2020 17:55:30 -0600 Subject: [PATCH 01/22] [Maps][docs] Provide detail sections for map features listed in overview page (#54377) * [Maps][docs] Provide detail sections for map features listed in intro page * move detail sections above include statements * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * review feedback * add screen shot for embedding map in dashboard * remove choropleth map section * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/index.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * review feedback * replace play with plot Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: Elastic Machine --- docs/maps/images/embed_in_dashboard.jpeg | Bin 0 -> 572722 bytes docs/maps/index.asciidoc | 36 +++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 docs/maps/images/embed_in_dashboard.jpeg diff --git a/docs/maps/images/embed_in_dashboard.jpeg b/docs/maps/images/embed_in_dashboard.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7be233e7a0364a81c3a0745aa9afb918f8a4e1d6 GIT binary patch literal 572722 zcmeFY2UJtrw=Wz;R6ssze)G3j zpIFPFb5LVbW6-f{yU({571!-S5H9zs!(}D7LUHb3pxhaX%xeQS4iH%1bFScpd zV_EM(yrdA za0&_ui-=0g$jZqpsB36yY3t}3-Y_yYxoHZuv9+^zaCCCMd(YF$+XwC&5*ijB5gGL` zEFKlN%&hF3+`JbrQN@^&(lTs0uA;WCzM-+Hxuvzcr?;=!PdT#xyXH
1!9Q8flGM0v-@c02J#PADzlSJ_rkJ3*LPSTCbv3p(KAt2U3U+~|EWSpx<~$} z=VEg6e$=$Oe-Vno*R&hV;aH%LZNU5D%pojL`uMQf&)Egl?_8Zrvy0&SQ!LO|S3C>U zRfcAP27Fda8C&1-ezGqGZtY$~+jKOhVVge&VxB=Ob*8FrT7M|-kox9ivSNCj+sWL0 z0(ixDX6N_2QRQ)CNxP57F467Z-(`U=+E|uRQGj6A@mUPW2Uw#oWDnE4IYwJHTX;zHV4?EIJ>tHx^-592KDc_=O?6x z@#m|lnl~PaYuv{VZ>n5$@(7#S*8H>Tn6;Yh10z^nvVHdSku>v~M1=b@*?A4fp->TZ1gn-_hmwz(!x>p2`vsXHCLbpq2Wc|GUFd)p-pSrbH(j zv%3+@2+vA0$Z`*TvfH$O@Z1QuXdzMju_k}$<<318=vm=Y0;O@*?cOF2zrq8v6;~<{ zyROcEXMwK#hp4lH8p;9{#!Rq47u*M#;58ufMSeXN4MfF$JWL&vI_$s2y$m#w=|LSa zVLlSV(=^`#vymOGi~Ktf|EJqOQ}U0N{IhWWF$#c<{V%eUj_=xp-iq|{&0o1S;-_?8 z*Hj92Chh!_A?WiQ?O*n))+J5u?bhKd@UGYNHeJfueq>N*SfD3p<|qsF_TU*pXBi?1 z?}SiTpx!{)GnjI2cYA;ZGCrdJ&H^n-asX|1!2e^P3&3-?l8|57 zcv+xqg)eJuyGcMZ>$f$ccmM-iey@YDU!_*%tx2OKTTMm+$6>gJ^E!9XdE9q2{{;eg8Uh6 z!Z3pf0(jCeFu)uZ=;ux3KT`bv=3Bsbk#*h-!6vHXQ880F(q?%omY3E=uIy!AomwFS z3oQ)twADTZlCZyHahnD5o*?X+PrX4ANW`4Gk3L`QQ%ZgJ>_mnreuU!i=(BtGobvsj zGq0awj6!T}ORX$^-7;{_UM>~hRk0^H69yZ0$OozV8ofHDO0TUeuU9(^pR&5vZyjw+ zE@*Kf=nu;5brA5|lD};|-(FJW>BjRx93iZaOo|4Kb})(GzCDTGD^;w`1wy?u_)CRH zXq(_V(5vH*I6-oNzNbYnuQ|BycCkREmUff0*|G0;kZjD>eAR<5EYO=Y0EQJ!Uwn#f z6Z`GSzxDW6$Nw$2VWQbNta2{c8ZM z$^K% zAWaFOKPPejnw(=ihI?gAzj?tSn+;$(k2`Y1(9SH91xko5HQU!v;P`v~{%fY;vO0QS zXo(7*LhjW%6KY`Of$zU{&f>6+j~T|uu7D60i02&b35S$wcOcubF&HgxY4%|Kk?*32 z$I=m`7r9{tNk;(aa^`pZ(L=zLmHf#-)y(k>U;m$f!K*#g+fuQUOLZ3{Om^hSbm3)S zZdQsN#)6QHOsAToCwK6BeTH+yhT-0qek@RVDuh||n3)D+*18{Vvp|QuH9wBeG!-*4 z_KtlUV~zhW6wg0hAfNsy(;$b#^%Kw75^wA$u+Xd7fIDRO?R_GcH_`%0u-KyBCa<;B zFpz;9TMru>yp>1V4-TAf#Y(oh_<=QtcG&~Gn=h9HenIrAer*om8Z@XX@_0Eaz^oL% zg%Q`%x0TAWN?nKyv6x7w#7EpBxH42OCD-}PW_I7cpbO(8k7rkYZ_)_;LMk82)k<;a zFZDBU8<}K*{4<1TcS+c1`o}2i%lP)Z7V+5#X4=WB9wU5^2T5&n@0iqyMF z5yTMDg0$UUNmWW&K6#cn+p~0>;BqSxJFs|hM%2Tjj4&9cBpAL`ySPU3s~jXfIjt-c z9(%lD9OJ-iuP#?P_yZy>+&5$$lbP(l^GR0D2CLBET3o%kE6ty|IS*HS*m2%lm25*z zm|;rMhWjCBVlObx(q5AY}Puvv(L z+0~g>Vk^xx!lI*1;yN$T*ho^&*}%GC1T8N~T*EA~KwewtBenW8CFN2~TYA8C3mR3m zr%Qgie93}u4G5%8#@m_7WX;XZ9Y!p@E-M&CJ*=L!+nQgq1gv{sMnb1j6GdVvAy%3J zp(xkH88)S=Ag->ss<||gU!+N88dm6^ZzUu+dU~m4gN%ENxNTA~?AE5`9fgHx%%>m= z8|vkmm|PYpeAS0}h4D)sjN(=;)aRa93y)=^>rh59;Ea0gBtwYW%jb;rvyh$hUdJd7 zP@fdtd8>%B;7e=CGHuMwux~PJbG83!e^3wsmtkbh;bpzO>)!R#CaK9Z+m^aPUM!>nF||mt65jj=Xa*e7C~SBL6@Zb%o{} zn`C5t>^F80Kgja`>)Y{k%+_x+Uk5)Tzpw+o;FAK+kzhj@GDX$;0vRoia6GDKTq3Kj z1ok0MFzn*Y$oOt_JPTAio5TY7#Q2d6-ES>z2{|~gr-bct^}KS~;C;Us)7P_MkMoph z>*!mU{{H@tOoxcMd!Gf;NoSrUdSr*#_S+Abo#K=?9?Rq5{D#TTT(z>!)62BPTBww) zWrqK}AHh%j-hSBW@FIA!$GThJc5?`}0Ie)r8Om*y_S4caFE>`Mj{=r+qv{S=C@J=A zq!SC|xd8tC2#bdo`t?fwLNg<)_AZ?-8&`@Iq;cIy?ssC?QA}>7z?zvO&5fezs61V- zmw}O_ExX40WYc@+_1(IcJH?8$M4UzHa-AL}NI&cC&P3s!;$(8ph>I_8;+jWnDy?lN z6LfR#VFUzJ9u}CP3^|fQ-n$5;6wHXme<4ak&spc(`n}~IE?A~i+sMLnv``~z=vEzi z9zr_kc?!%GI0;`5=|Zwcs;wk-!{+LG-RswTlE|leQ&=D|1YmPs(PB9gXp{TVg;ypm z-?mNex|rAFYg-!Nm&~Dykzyuh;RJp zpE&Ts3QmO6Q;0li-wb3J^0d1Y$u09F<5mg_)YHM!f1qpLG4DRVVeNb9T2@RQAN@1! zV(+ZXvt+xC4~hkwcg8ehT^GK8xSx27Gz3TRQqEJ2HI@-n3d`Vx@YL7OGkv}^x3staQ4&qeYVGS?0+uA4V;5K;aF!{}lzV9>h<>Kf#jN#RV2T4U z!d@-icE#83*AN1;_Z_4gwCY|uSY*JIR~0LbK)D21Gdih2n<6}CDE&c4dSu(7sheIy zFzP>;fwWn>w}<)HS@=UC(vliu0!j+GeoxlYIx4B!X%2P1Zm@$iNRZ8(Q~9Fm-VZ9| z=+!RLXE%O!QGMEjT(>1DMter$NhCDBTlT_Bo~GPr6*!p7vzsXHH0pT5^`b~fbM{&h z$BlQ-yp2r1Fwkj{zT&C{CTyl-nV~qlRNr9wO@-%psn23@LGU*|^(9q1f}b5W#N~^| zo?gMGRSu7E=Eygl4KUS)ex_I-WMZ^r8_ zd93fbCC%s2;+CV-2x#i>YE=>EZhB<-CA<`VBP{w8TJQJKGVB$ptOXM~s~#|WrE_zm zva%BUCiPI*w$yHTZct0e+pDlJtFCc$MDJ=Cw~5R6p4X&}{dE0;@_w52Ri2x!W|oOv z4K8z;rWflP_56-~_VqC`Aq4l_6 zx|7@w4T12S`8maJ3-x9;H@=sozreX*4Ao3oAiHwFJU*neKv2;NmjQ<2zJfarXL<8K zSnT8F!wM`=)RT#x6WtllK%ym&2sPs7hX>$QUV+GLKit#3(FgRf;pPFtU? zRrmxQepgp5Y}!e#9ye8KemH^C^x+zkUdY6)l1jwBj z;!k}SEG@6MQ+uLb;`jkH-dUYcpj9{e#~@r7|4unL^^SYvwOq+N0sSGVvfG<_W_3%^ z{+&Cj_Rp(q3TzT_JL{N-5#w54^XDWSlJw1pyTU#XVb2({H9nnkWQxh2;sQV#qzDkfd+S)dSe zgAp(o!FJSUAjq5m*TV*C<_?HJTp>R{Og`0p2!0xt@zg+@d=f+6?RL}7a+qOQ5$R7E z8YfH72pv#!9f}0;j~gPF>Fgg;erYHo-hnIXD-qMW+dXB!xd}SEO~w_tWb}#k`IHqe zZa9y$ZhY(=;DS8EwN-Zv8eefB*at5vm)1oXbWmW=>Qzrh2KE}LQVd=TJ}2TieIklv zD1z1cf$Gk#iD-Z2h1KB_-_c?IU;q4aF<0-wF)7Y5fv1V*dGzhPeXi-4&b3M9Ka`rE zFY8G2v8+t4IitZIHB#Oe;XkJwy7ZB;MPp}y*d+r~!RKPxBk%SDz7)H|MLyL9Zs<%Z zr=?KMX;_MZJLje@Pv6tM9l=0;r1xfPcus|@uYu^)Zm43^ex;&>ukeSN#t5HX?kQD2 zSCxX-Iv(%NUhXy4A1$2BG%b}v`Rmw(B$ww*xr`6WeDGDrRhcUerJ$0oqHc}l=MYQ{ zoW7f0cZWA`>|V+yuQLR^yE>&PCh-gtq3wOj#4z<5Edj9qOc5lJ1=^_#QBCxs8IfQ@ zX4S*Q7~M5*kQwjrm}x zlBipxs;rvDmu16euX6d`cVZiGL=4W_Q?)G(ZwF7z)Clg1C4&>SrHO`2_ z83k%q&8UsuYnj^nv_7%&>5j{wjMJrzLW@tLKhxa9b7cAF#~Y;WzgsOB8w{E1NRPGK zq+`vxr|jfDnxRS#m9rW&F);-t6~^`stL7n2ZIYMBSxioJG2-S7^F(A;FQoQhhl7l! z-Z`q$_YMTYU#j~Nj)7PdhOr~er^0T&ktSEQW+W+x=^(DX`a~=BmuB{KOe>A6jPzv= zHP%Gkuib?v%7k4=sy++-9*6sLn_!hxpDmshWanY=qfm2iHQOd6HFFg=EIfs~_G2$7}UpqnB7#^)@ovkNi8)t~dnrGL&THa@2`VgarFm7MgrzEErcEP?b4 zoHwD~r^!~jngoW>e?$1v%!=m_s^riJJ|)ejMWv>Rh7m(o@^osZ>A6e*xYYGbYk2X8 z#+Td*iM)poY^ufe3hr8)OXZIbw#oe{-Ts+hoAxC;-&B)e9OjasV~-Vq@|t%#Hcmiy z%Hf)sZHRXPgKbXWNQ4nBZ8-x7K+m=ZQT#|kPpc4WX|Y}y?BHAI;QqC~=t>FP z68?iQdg!#@`MGh1?&6ve2f$S<5KRt)aHiqN`NWJq*qk5r@lo!*qcQ{+j&buSSAzvg z%AIzzwWyuS@uHIODFjY|})vCoPNa2B`TWjbqlOUJ&mN%fS| zaWa*ycqs1v2(nx$d4@8Z%oO$;qw6EW$+O#el&uvt=Gf9P7U=$nf4i1!_tMiMDHL@J z`tgnDM~^A@UfqBMlJfQLE!cS2@Rrn*?<5zAjX;V0lG+hDi-0tFdV`-K!6t6PI=O6f zo?aI^S&kc;cwqjmz`U~jW10iSIJ-q=#S5bn1`BJytNB`9nZI@3W~+vfL4898Z?}=( zbzbxn)k=<)_G=yJy(+dm(1T8ZoVoaJ#^55tlG5}v@Y1{ScIDE6pdjuNE$j9)^$B;_ z3C-Nb1EKS}Cg(+muH-n^fAyHvfTopK=e3r~>u8nSJ$>D#0No=zY&Ivb{aVyc(H<3l zK@xt|Wj4piSY8Jjl8q5IlKEUx;~9>i07i-?AJLP>^&Z_|-$6HHT&CsIl^MSsrRsyR zj2pBiGJ1dqLtA%kA%E-ej|n3BM|V5tK8pzPsB!jFgU=E?Yn^X4ap6AQavC{dt?*Kz zNuj&SLey@m8+l^_)nA;5 za6q;`$g58)$W058@9M--qmNqlRg=NO{szYofk!Wx8nJ((1>2p-sFjt0?wYfVd(#M2 z61N@+nNSs|zQql%+P}(U-QL(Zqwcit|BLTKi4~KO`>2Mha_?t_lMdzzVfi>A-COM& zdf#!b@;KFS%eBv&Qt zjG#pwNm)KfW1eG(&`inR11wO3>cCjKr1(tig-BImQg=*rPpd#t9udOBtrLb6q{a0* zH|%u2#KQdyYDyjFZ+_QrYC;w8UK4w){yez5q{6;X!EZUaAiuUY%a_BIK9O&3tXSeH zul{^o!74#+8mB04mJ{KxI5=N&yHn<{KDYYPAONI3K{HeV{;2nE0t+OF;34O&IHbiY zBks`_kaQIqm}*itp&lbfjccUk6~n3wNg14e?_AyAr+?46d? zh%W5D^x^|_1ICPJSK)2gC1uR^N^I27;TtDe^Zw6^GgA}67lQi*uul<1Lr^|vy;1uw zsqQ^0v7U1EJA+YrPV-9;&p^VM=~3xjS{$H37sO5bt`41 zWz12CBvXnx0Z}J3<*rjPouD$b)iIgpHgXv=jN-;MO40h2yD9&HC<|-y$(GWj61E6 znY?)U0Tt)&tp%OtKaW?;aFPO|+H^eGQW2em7i74S{g&OgyC{>?9!f+vBmouJk56AB zzuxEJbpC`;`>0XY>3?>DBP_<^qwgUV7g)Nf)#!Y-ursQ$4;(O*j*$0%H$4R z+tNWDQw_KrZb$)gK6H7i!i8v^JY&(tX@e@|)Xd&e@lh-(&?&GjSZWg<^0kZ$bP&<< zDVvH_2Q(!;QjmV_C@-ISo902`qT(sLJ4xixt(AzbjAIPtDRtP%pKhlntJU*6V11o3 z)BD52E?4>b7xqUkS@62PYt6Tsy3>$;GPJOmP_0l;X?S2UGLf83@EyA1Z`1Tcw_3|w zSz36=yu7bY*9M~`emSgkcnsn#T>rCRA|S%W$l8={yqMN6uVZl;X&gJWRKN5D?+1&| z#q%>HiX+>)@^al2W|-oL>oh-#ka?U5ErpEkixr+)A8$7y7KYDols#5e0#Kjp)bGP5 z#@p2lm7YV>eM?ntPU3_{IG@|3)H$TI&M3=xFk37oR2(-UdT{r1qCqL-9J&n-iPKR#^@%ZcBPvfi1vB;p-5EVMT*O9`W== z8eE_Wx&zC8PMO3*bK<4p&5@v($HJ9MNPmvbK5E!6aa#Fr&t20Y)mPH7zO7faCP}o2 z-59++nZk-T>)DtFTC8eYO+aZ38)>NEduyUPdVarD z`@$sJTQ(wFdi6_6BSo#k75;*=7=ywN5v#8>?A;4yH<6c998=9E$<#9}njm0}QS}L$C zKC?hWH)1aU^C&~sV&?Bw(huH4erjqX4_P1pXPPKRiqin=F1?C8+&5%_OrQVMaDRu+ zO^diWVJa1tu1$j9%QQKzJ$=o~>+XBdanq}yvaG-b2anL4#etb{7N`yxhqweztU~&z zravQR3@mDlhc2CqL@v)hW^!(!>v{UBCC8kT<@ZbxR-T?=o_?6I@@rSCM>;cSg>*44 zi-bR^4_;!7X)Qta5DA58Z9kR6QPFHHhXc;7NHn$7oPd3oy`p26DplZVXRIEDk?Rkx z^PV#NrP~8zA+o0R$)Ox0H<2JRTPdJkAaS$bGEGZ;3IjvgMR|&7E9M!fFo$%}T^aF3 ziogctnJUBM>bF9=k(lC#i266sN4Jjq5ioG>FFMvdQ}j)E+tOWDd;-uY`3)Lf&5t8v8l^1g_7o!&s5|_+lW?> z$Wxd33bn3HVt3wjirB0NrB05A=&9$aXJl3*Z|@RJ`rJjC1`J-B&2m(%{1S7tNUM|V zozd>?T?uzPPBuc%?Mf2*Nii^oj>h^YE?+p*?TsVQCx1U_dj(vR@w8plFzL#o)Tm#T z`sKH&xJlnIU#-B{%V~1Z5X;u1V+`Dt>}iXKD{dATNjn}#O@gK8*R10ipVuj zQEz4X7x}p2S$`MTT}8xv_<^ z(jBV}OCLhM=7VY@o#M#~hb$MSxw>MwP1By^8cx+Un6|psAM6b~IXhL8&aU$}$1PH>*4N6u3{>E&5vw># zH0+H6^RI4c5VwE#v-Iz)FDdX8bGwq7?a3iE3E&JtzEBDrtxqNGvklc`#xtsD_Ss^Oodj&N^iV8TJ6sAQ4)e~?JS+p1y2$%lM?UW#LP&yxg zL}g@Ipxx^ocU%Q z-=>>2-IOwm{E{=FdE`BBkL{Zi_gPtuv*{vUP#C(^{5FjUY z<>UDmZ>2%kyJC5#+PO**4o#C`J9^LwhTX~h3WY7fnI`Ik8#C0_BF|)v3z9z0@}>K( zzuQpERC-83KYII7_I9$I=_!ReqoKEO%uVa~`L&#@QVWFC77X~Z&1*1EP{Y^dm86h> zZ|AZF>_obGD=?5nW3}X4?+OVnny5f3*z#@Nv{HkFnq}h?YL8VSsrztr?Xq&il-je4 zDEV{bp|9IjdWjmeY*}6F1ZR~AdpOn4j)tzXjaRsCyOx#G3g4bwfXGhKj?Y^FSu@Y4 zft}|OQnZk&*hwU3gA43k?3n1lv)Eq<8=~v)%`%DSdm!gDQhufZ+L)+>Q4R8_aT-8Y zN>`WU0(k=md3aRJp?(D!Ei|OlAC{cXCL)CR{jTYdHbD1+Jop$Nb>V6Lfv;5-)@T%3 zC3{+@8{K1^$4j2bwaXzcs&Y=3L+$u-PBqom=ybxzlMi0oD}+UzFO?gDs-ef1Kuk_I zgw%xowF(-(zZKuh0;S-28ywrsDc&UGvP}3)(S@nIN!wH^O7r>J;MwOGIIxt9Kf!ai z7i|^pHKV?L^Q&xOx<9S^x^A~&-Q}@j$Zo8{4>um^S6&z@*)FxOTI#SasUA_jBy5v< z0sLz4O4Mp-gCZZ}3Y1L*AoHN$9(8RsJmqW4G^rp@d7)(7 zVwcBy+}c@I@{RuR%QptUULTw~u!rGFWU*>QPA@W{kUbDX{fZ;Wu>;QOBx@ zY>#2Lv=+OcIGkHmsfDUzSNR-P$N*lc!T&*i3e_8ZhTZtfhW)~PE>^+TU$d|vAAKbv zXf-u=`%m%{nx5^9ffmDzCgM+2&1jP3JxXAB6JflF3p61*5dBacX|5|Hx|DhrXd7~p zmSvq~i;9?5ju$HKF|BW;BQ$F&eu;E8a=I&`ko`92b#mNl0Zs*OyPlkhrrhPv&yx~c zhnGw~2{f0KJXiCq`@31DB{j1)p)}CDR7Vro@J&V8;5+l7v-;~@O@x!Um7UlXVl0k4 z->0h&CYwW2nEaiPI{bFb8|EmUtNv8tWOtLZd!o?@V^+&~VWcH9!py9U@6$`M14ZTS zudOQ!rnf^N{vUqkXhoSCgqLcJ2oKzx)2tEuI%VT4^U^HtLv8(pg@!d;Hd5Yr2MTj_ zwipX9D6C&Q%@m{Pry?XtaixXjeqtE+Yb zcJE`eT?W@Bp0xkzNsXPn6^V98QTUp13 zeUE$tdDsOyT%Ci_2`(Yj1q@8P*CxfQqmMDi!DLJD8Ja`Sxk$aPG|F(d!7tV}(KacOX(@{NndIz?+p(t13k)_?mhswS{4ouLk#E=M)Li&O~Wmq5KAOSIfeW-#ZJ_GO^O^B*R?wEa_k;W8>Na=Aq zNkf;>=)J8)dALE}Ti0-lK7&-f=N^&OJahYgMf!txGr_aXhUs~yBV()+#Xe0}JN%m0 z_}Ye48K28npm3cUjJ0U%(6LRxM)t}2G!Oq!qQ|fF>PLyvR_%o!MrsV&bC;gE5p<e6CYSZ2sxRnR=WmWb-T(C&@>lQvUbFOQJ zS((x`TN!PQGnw!62&zEkV>Qkg-Gst}Lnc$d;ig)@7P?6lycMCUomfwO-)?lqNcW+_ z-e!MxAwn@9`=OwGGW+(9BDD0X?1|MMF&WSBJ}l6@;sCNfg>jpvSBX%f>~^VsVj~Uo zWW-CJ=pd`qEW<<)v9M&JH3_ZWaA$!pP1pP7{1M<1_~ZtjAQWPP^Sx5I#dW=UFYLiB zt@kZ5XUmMz(`AaZz>gwdR{Vj3ogrIgubWRLCqeWn=W!erR&M<$a~+(^`&>0$(&vc= z{Yf?@eRA_HzgMLq*CU^j3ND<)HAxFW)w2}_3Wo`{@j195xuerZX%L?nq&*qkrTSR% z;!!Td51ptxmT17UVIVmJBsC0)+)W9cVoq*8qTC79y{fo3rHY9~j;_iBS@iyu)h%}c zlF(TX49W{(9zQ~MOb!bYkQEKBY?%(Kw6``loGUGc4=;{`jk^1l1aLw+V7fYNSC zvp_Z80GZp|se1f|t}5ekJ(7OH82}~#P7YEuw&sV&I3ik8SM5jp_i6;>+=?%8Rc=(93o99L@2Gtz zz}ap!b_Qcbjc@ohuswznq;D9*7dg8UOsMH|e=;L49^rOb5C_NkxCJzEt}JiK&b=ue z-UL~Ee2HAywIX8xO7G0x_w7ta$H9+1OP^L2r&LEcbIVwuFTNdLtL5nxP)JW{s@u<0 z%3N)YTz`X~LNk!?QEkk=3b5GoTykNwq8|>lO^;Z%uNj{{*BQ~R0#(+TVumCICZ+a) z${rb0^!_%_eTPxXKwmZxC!ZAh3y#@+kk|DR`N``N5IY!+rGP<7%(x$$vrdk5JYT?vR5z-=lx&ehQgBz%OFIpoHdiAwe z&fKl7w1DO2%5dGNP|r_uG=bV>2B-glD%3MFA!CS+r0LvukqcP?(LUzz`U9(D#+9{GfMT*#K9PwrDsxkPX>^7isF%P9yF_bB3jJSjj)35{`jSprZCrjXlLfsIHhx1I6|Q{XU1 zb!w_y>Tlxnznfz=5}x2f{Xvtb{}Q>|PN?Qg#2PG< zYTi|jQ^eB$tVgY_E^0>&75FIzw*)uET&S~vZR7mlS5<`sCxh@m+KAE0uw}@59-7qb zBc#t*Jf1z4?K2!*r`78&M2H=CZy4B)ChZd19B4MxK%TkP3n$bQbE#W2X0@~|g_P!E z+F`nuXaD?Lq54)nmkV4PKG7lmyT=hmUu~jPUxqWqvcA-=I~8spFV&KjrjSkgQe3jW za{;U1A7mLO$wM%PWja>b*)FNyWml-n0kZ6)KN5^r#yrnDxlIJYCIEtX&0{7nEw2>W zB^C-vMxXYgXeAnm7}4+1@_P)#0CuVhjBTTnqqUZn<>^VxZ6W)Aws!f-&7L-YlyoEe z#U6#<%H zvopU~TBxMKvD^EWw{|RMC(M0gfe^4uNuRfrp+@G}@guMI7zi4iA`8Xgmy5w7^}9*2 zoOR=+%wUZK9{M?=U1u;KNi zH~JAI4`c~V>pFn9h9D%SH6Z8R;7x%Tm!4AE`bye2OzpCOM?JDHo+b#hR`8>V(3(ugyAB+=r>)%XRXYotNUNKnh81O zetfUOal6Rj#r0Wxz!G^^)QA?issx02eU7qOvv)uYdsQv$HH_YulGH5Kjf{xU1UB^+ z-{u>0(5CLWW2hZ)0`gtp&O5R!m2%X~xIh^rt*7hT5MfV6ts}GEyT3iPolwq@ru63p zk!x;tOuhlQN>a3hm4%1qqF04!W4#Xp(E1NHHXhEP1k*0g^=XVyU&rp$4lBmkoGboZ zIbF75)fPN~4TE@|ZY-S2_H>RO4NAQL5M%o8TPOG!zKlL?9z2iQSMWO?g2BG7v&3JXH8nX}H6wi60 zPAYz>f82ZD#pfDoIY--WI7H!m#ucR9E!^Co_TBTQ3r-z1Vcz~$+jO^Ef^I7sf)yl* z#R^>yrO)^G#`hxXO!dIY_|u_0=NPwVk+>)SFd#F zo&4Z8V!Mi!ht}t01!ON5Z!`!g*{;iVSJtgsRoivRlrVlbmp!8?d-Amc;=5Iv#&Bpy zsZNM7ytzs@)ze-uz`QkdMH+4tJB92rdO={^2NublEw@X}<5jWXIVJ&BRFt2`kO!-emHyYJk+))q_; zaMYqiH-!p>z5$3#&~@KjK5Zix34Zd&nxq_0@3C#$FK6-o8rV0X8xKnQB+7Z;6`$rafPV&=iuMw!6@E8Fy%z1{WgRdhus9Brfj4C_!|I z>5Sxc%Bg3otueAz6MbuF_OvP9su}xPO)Is5{xU_5^lnd0N8eATlNg?ap(?DgWm5ZO zf@8PF)%r5bh-Qtv&u9TR)bYOO8DrpJ6B2e_WYm5w6m1y%TZ zluHrXo}>))qsfNC08v@KUhgH|2T)_0Oh6$yHt_V;>@$g-rBr36Bmp2Ydn_)f3HR2z z&8LXShTl8e_wvPYSj4$0yUY8RvzH)sH5PS2(^FIp591jHR3&v3;6VsG z!0}w7V$eX!hy!6np2mA!3L)q9L%6pQLL{9qJw+drXDSVN5p~m2r(t!pC;1yD6gkcu zQ(6r7&q2bc`t5q`E#i7+u^dOJ+FmGck^){m^GS}WUUan_Bx>W$DS>@)JkR6aYxFP| zZXJ^ndx@5@m(<`?I5s>#?@Fu5AcUt=K`R4t2lB~=$>DyNJV1)gq5C4h05WSxbQpjo z0#<;l;Rs?(Q!GK8rK~3+OiAdcy6C5#@609I^S{xZ2J*6(EU!(Zp3Tkv;!MIvZdq>sJ zs=-=i?6d8cO)c*LHwQTScjmYvnX5ic>KmOcD$*Dai_Smd6MONdYR_z-@rS6)8*z3=>ptRT zfx>bN;bhYeTx)W%O=d)pMODcKgygPL6^X9|sKd#^VE+sqhenmRlL*l-j814?a zL8)qe`|W|9Lhv^NwKg=55L)V8<O1)KtbLxgGA<$+{`BJry% zEv_Uo!f28yse(q{4UCSd(I`yph(?yq-}vr4;Bh9HM|Vx&4d)h5!f+jIN3P$|$zwsR za+n}*hjm6gH$z$4ex;8nHd*t!?T`BkCpT}m7V$Qda*)2u(}f1kcJd|!y=Hmc9P1}* z5tcaROZ=;2a6BL2FIDICR(7}HbVr)^`$bvWU0^}%(<*`MDspa^n3r0Qj+c}H68ZvB zcS){_{gOfx?N*qWOmmnCK+Ty?p;doVy~G))?r{bi)63pic*_WI@I2{(1lx2ztId*f zlXC@p$+T(Rk3lI`hM}AzPJXSi!TLdn0 z>*wzKIKX&ug&`l~$u_EBgdFWPacOR;7fH53r{Tf+<|X(Z*E`4*FjuT7!;&oZ*8!eO zlvD0xlyf0;X4Ivc>vsSn`p!L_izdCmqJF*5Vz<&`o$kK>P&hdaS|-M8zBpooa~C_~ zscRh+?0!N3vTElXk7^kG>$NnTo!Bp(EFwp+;>kxKZGtsN&daD}QZpp**D3 zCQqqaZXjn+R_b|L-}O?1&}tZW5;V9ot)ju#EK?VHE4k!+?ZY3=n<`66h#RzVA>h~@ z-2fPq4Fotdtwi&r+;uss#QPxA(Bi8{!0sdRF43!l#Kl7}GpGHGsPOINo!K)F7n7YZ zF2tIV6f2d3*Va}~W-f|%M&}r5GU4`oBj0aHIwjWPP9M1iI0s8R2hN+()3bAK>{b`3 zerOou5!G??cLBR$LTg0F{TyVy17o*Bq);6?T!#}PX3Xdxt3cDSs0Et;vI-ubaApn7jO zH`%N*kavDi@P>mjxF+9giJ&N?BynoTpw6wzBWy(5Ax*{21^#X5?3Ip|fRdxxkdfhF z?BmiW)cuaJ%JEViGa^=3t@1-*KB6{$YDHS;!_-P;GX61hL=^lKvW)8d1sGrq!tbc2 zU6r((gg=V_%(-`Z{~9JC@meQeQAzU+whB^^R%qixNRGbvSCjN3r8q^vUz^I&Swhd~FUzfa>)q3<-!0o!hlm@b0!1-~>F!V`U z)B9MlBOv|a4-;dKvp}5sS}Qxpx4I=YVW-`keI!N6R4nf6fz?3Rox^rXVSg`0mlrEV zdNIyRBSyj9S@B<&A2>QEPs?{>bz2c{-pF)>i8ybeeg)VCB|GZVd+?wiHkE08Bsnuw z!TMPzr&4K)1W^?$>-qw5-0<_}0hD+xbVTcrjdE7?X;!3`QwmWNvmB#H;yOYzdAD|- z9!kC@K~B0n4?EUM_s_|hZurpBD8vQM)Ai56czu3Vc^7*H-!n5m@7fv8Fwb+LhVO46 zFHz#CQ?*Cc`(OdaS#n2HD#Y{1o7#aq-}Dskl|i#cb0VCG=#(O!#6=PT%;zVXSQAm> z>NH2QbpD;}J6JIfyNi%XUhrRQ^Ybstb=j8GX;rvY0qF?#o2v+*QgMp)s|@XdgY?ou zJ?+7&%eTh6Aor&W{tx!vJFKa$UlYcPfKrqW5|Q3TdXYSWfPjE>AwnMMy(66{Rk~7@ zDmBuK^iHIAkS;YONN))>K!~%S_kGWtGw+<4>nk(gne$!z#dVQn@3q$6YyIwDx$j?@ zCg;ig6U13#GqcGM^y;g8B4_q?ceq}MDBj}_ZHD1oQ=f8A4Q1S;?r_H)aUlIUx1qQI zu2q9SmQT>8E74r}XpyFN*MgVnXRt$5Uham*#St<$I=&LxJFwbV)e)LRX zvac`gk6wEOZDmyoz?LGR`1mS8zW=6U(@$Sn-;50|#Dx9yp(e&PT_LuljPAr`bftRS z=4}|?M%MkzDbFt$E<{2?G}2#S)8@qLD?tD&($*7T3W{r?*z`*!+ySz8JOlRS|8KO<=huHL9q`d$~<$p^o&OP6F ze(>PD${)Sh=I0_)Avk z>?;ca@>qBm@*ViblwtbPP&1IuYImQ3sNMI8Xg#(=%Tz-&EF+A@g%CGg+$z+p)(y&; ztOO-R7^Jpx%u1d|RV_szR5Hn%1{Z#~XPT79CKoVi!iRm`^xKoXhmzcDS zmc7;uGVRIF%;c+oWU)v^tGx)q3-SOV6Tq~y zpBD*BM9Un4$nYS2yvq`ZnxKo*4)>~KdzgYKUiXV{6}iP#+XHOZ8}mm-!auj$(F@S1 zf>eL)6Z$TR0s{M4x!nhlz@DyNjsFz+`pSDU8EJyrS2>81_0Epa<$sOz{GF-ZF$x=p!hXVZ zfHJ6F2m5AlJE-^anOR|`IVp|_7=1mUZ}E_Uw@sV4+LwVF@nftwn)ZwmWg@p0792FWCe5lRVpEp?cQn-L8Tw<-NXGd5(&|4|RWvjPT?4-A>nX`84|FbN>27K8ho>bend`r)ucR66`G^h>^gD zg@(0=&-=sy^oCL#PlsGKivt@A&Lv(#o8G5#(dJE}QqSZNVs*D-!1tDa#)?iwn}7;ihbp_^pEq?Jr=r)vO? zkWEa35BB_WU6tlZSx$1DZcH42>kM}3B^4;f-`9bQ{~G5vNcXx6#wb!pXN!ROaKwDF zF^NAe_1k&#UOwb(y+>j+Ge#5)G+GHLna&;qLLuA!*mm^rcFq|WK^z~8O*}G7Y->Pl zwPKMPV@SLH-7pjHNCo)-Hk@!7diqc7&esKw`UZc4@-dOgfsb6ZN=|prUNR}NqX=;A zV6m8`P@lwyeWE|>Fosghlk^hsn-YGm8CJTKG3Et)6NM{DN$1CmV>PwVAG(;iJgxye z^tbXw~TlO<#iEKio0Q~=yPnieznQiOI@e5`yKbt~W&#^o;I@;Q(VvK(d$ zxP^B*b0JQkD3LBAG(e5cFxDU71Xa;ZwQ6c(=36TBl;|Ql9^H0;%xY+wE4*|3%1L3x zx*i(!Bv|S|>}5CE+hKPz$$rs8_tKQFkeiQ~f3yp#PQb}W-P`qbLzlHqi6^Gx_9lIl zPFkd7k!5d&ee^`z^#(kw;tW=`yplnsqn^1rhPPwT19^Sf<#@h*Wn<09^xN{<{vKye z@KAZTTml7F3y!rRl09CE57k72!%&RXBC+&rBvC@bD;ra7r>l{NFGe+Dp;}SsoHSl| zW6YD0+8L0?)fg4Fq$cqJ55a3Mm2J)UUp{iNgHYWB*948yB-`s3Nj7Jye9cE|)(g1L zOYydimuPo9OBC$Z%Tq(U8mynmdaXi#!qxNii}k-$W!&HHgNx_x6!cB}CJ~d63r1m| zYKOB?)gr?e!F@=fErTK~Y z1hA#}pyce5b>rDx;u!2Q%yM`7cu6EIh&F&0OCL$PEwMB_OJ#HX$dPrT>syXE(t7FKR|3EqO-sqh02L z(e7HAHl)M+AM6zfOIulk8lObQ9^mbbiKOgg}Izn=Areocadv6KMhlWI58jz#;L5A?|3yqRzdySv0)i>qvv%Esy;N$ob5 zhUt8M;Kw>(cO370$Ij3HCUMxHVs|o=GgX=2);vgGst>%&)lb)RByIQ=e7BQT;NvP& zfa}LE%OC6cT?>o4lA4?H$P~#;5{op8zLZGwHx+S?O4r3P%3s&%_$XKjk~h4I!RmPN zDEMl+duZKBbQ;%R$q?Qh+?uium^!n!w=u*6!i`sdrI~7aLDIGHJgA7O^iRv<*9$!C zCl~Hdy^5PLoEs>kwf*pJE;uUPRr0;USO{-dDz)27cD5HyekoCXdpV@s4Gui7C%5N! z0^(`(JRg*p?3^$rmSkVoz?D&(Q) zh`@Ku@Cj!nkZJ>pUDl%_%G$Nnd!RgQ1Ihy1|W->Iwvv2B9O5#b{88kk*byv-7LTMRo&#f;BA?waWiBeD>j zTd=F4784RYckGQ`*J$2sd0d|!u*(ci;Y?91ZhVKRY{#`cWK@@Sv?e8c=b6LomibcN zO5v&9jd~uIJ%pDe!t(3%Ub2t&EkR8ayrVUDR1v^Wfg5+Rj^fiad4I3V9#b49pSw={7%MsvwHRn@x7_K^Z|%>_wa9? zHPx}Tp~(H}v( z*V*F{k8G<{(jnI&@t=nLmV2!?TUS5yE{;`D^gQ%WdGtou75RAP?SF_i#9vwzyc-Ht zx13`#Nr``$h@1xlRts=@jqnwR_d#SuZ!>?c7CJ~KjwEq++>4Ep>1FIO_s4wXOjv&U z{PV56Fz|P>+2LAs!7PlLP$+p`ZrCY_=pO?JYS_O?IypUzILWHsHyXuG=J&a;t*22DA+>5|41BtbMhN(KnLMV(g;yZt6% zGQe1j%?A3RHai_4XJS`=lZ1N4OP%ZF0a|W1ZHRRG08~MXv}s=>&|w42$gvV%iyQnm zrWQCSC15n0$63NSXjHY6;qtDRCd6ps>#u~Bot+I|rUm1di&tamIO4>i=|f@}LH=<* zgx2n~kr;~`UDToX>R;VZ&_Jh=RZ`T(r%;CbCTkyrx2=5L3`#3Tv*+IYOthCWhH_w)OI(Z~8n z>CDyEt)YnX2;0iT*8EZbSjlR|{prj=V@pe(qF*7ydQ+3pPiWJ|AIx3edvJx(j_K{H z{I7ldL5}i0cSi;1v-pX~D?edjWL)3kq%b0H2og9wfV&qL#E2gq1v2t39og46vM%AQ zvn@(Z*NjsAtSc?t;HYjFe15=7C1%st<# zMg_&sY)iMwa&Br|i(#o*D>0v6dY0znub-%G`WiEd!c`kEytkK`m{YQcJEfq#T z@*lxE8veW`T;4?uQkSVdi5}U_mDt2RmM$&3W5fOZa^0o;*%-&$lHcV>>O1Mesa7bZp~xCgqnfyKSIw5J-U;-@mxq<#O4_ z1_K3Rx$k6^Y!x12!O;g*lk#8$gh5TmDy-i4eu}hBxKCgI)gQ`&S_${-J}JwnyB>oI4m5E_HLZ-Mi1IPD_#7YDyY|-60Mp$20!+Ut*Wk4nEc))`eBST%?|RI zEZDCqcF1*4EKK2hn&G=y7uPNo3Q_0|6XTa|?NsTd%h6ASJ69P|?5p=aF(xm@C#}Y} z{q-{4d@VTS@!mB0!Hx`f^b^HD<20Uj%joV^CLc4&2ho~vIDKpFM!lyYC>k0`A3FXb ziW{4>dix*VWDD}wx3*m6@)0-ESvnkXUCWndjA=i-za=0Pu#GoE zdCfP!kg81uQa?9aFcS}M+SK2Dck>Uh&JUt^DZ-T!*0l5^;vS+R1N$gUj(tAjUScXI zu5rL=389p649*mI!kRw*XwPqt;x^eKNByz5_{ZRn|D9R56bV#Ed}#r;G7&g$3KAwK z{9xhWglk95nz9{K7%?J+$8Qoo8a#j{EYrWEPF-3MyC@Q%=H(}_6E}$*Kvha4!D9(T zNCgr}n-f&$+^WAOg1UlCXfKuL_{4Vv(bYFMW8skmJ+$1s)=y)5?<{JZN*-EZP>cG( z{f3kw+ce87ZxT{SUYCk8zT|#L1CPxkFOP08U}wrdE0EyKPOBdLVlK*PEQ7XJPq!az z(+zQ`bhF>=ooD`@?<^G+A0@M9%w;a@>_W{jN1iA8v<9gf z0wT&kynk-Rh|aPIC^=C?-mjJXaGphf^_yipi_&F{>sRh&9KyHlJv{amoR7WFj`t3J z$h_+B?<<>`33?KI<7%1fy*DrA&3WpnztrzJ#~j_ZjYXC840@h z3vBy4IBmQ0IhNXZr}(qT{0hujfIMCHm1Hf%s1DX%arTJ&Sz=%>60R9A%{G*j-As4P zZc|y=@aM7N>r`P5QPR3vwe(jqylPDR+FaVCqe=Ga6myAY@dz07VWza^*@*Tpc?g7z z<0AwjIHGjqV-4{%&WVqo&$Hmqph{wOmBu7y%(%I~_G>mnAQ2zkJH@w)XZwEyJa4B- z&I!I@<|{wFz-!2ziM@V&@7Ca(>npvB9!g1R>RLy$J+$WO%O=f)bN~1vrfndm$3V!~ z-RcLDEIin=-z0i>Z#Pj20;~WHDd2s4rcM0##h(>0lw91VK%SEkcK+zfIWy|q5_vfN zo8*84x;&v>xfXwL4G_;8Ct|(eG}9)1x;7etW?dUD_etwNaKxcaRDXUhC%?pVrQr40 ze0Pa1^ljg<_CRTX9XhAArS7U1se0p8*e_W`$;29x_IWlo4evmNtpW)G)2ZJi%y}CV zjX}Iuh_UA$|pRZmiCs{XCNP5|A!Mgd_gMxQk@Z7;SY4Q$gq zKlK{7SJbAB9Zp>f&v2c{f?_@e&U9koZ%bXN_$-&Lv4KZ_<9 zoy6`){cV6h6rluqV4-knL0yPFq5z=-^tb5*14*pKirwENF(X?5_eBJQ9QgZ;{`Cis zVxh~xmEQbqN~bpfXCb&BNfc8pFCieKev>@-$D|&U!LY{Oze&1mk0fBJIOxhhX0^sH zLZlD|mS>Rd?|1$VMoVC)&aVRXfUQ=5=sQ#1&j}*56ZVmmz}>EWrS|m5PYi|G z4fcuvMlH9r)a>u}3o!a%BKZyyKOyoL7|4nEySd8-Py*J-3ox8tPOF_!QU9=Z|N3o^ zVc9J1kH6cxe?}kVCh*7uQ$Rz+(GlL%(AYR;6FhUHD!O8?v8(TM&@O9&jJ$y!Tv|V7 z*@3&^D>1)sZqPz^rQ-9FqeqyXnT=WP-~}Jf zQRnt2xOV1;+4D#D;@cW{6ibWMbt*M$8+JE1CqB6R6Ywzr|20mf|635}Z%6=uPQ$sat1qMej=%mZRIv}dz&01~>;hr_%`v#Z z`TxIkRdklLDerXU@I8t+GF{OgJJ$b)S9N(IYQZXFKQ#IFrcp~{s0PLN6&c}tpPzX^ zfyjFmRVDS>j)b+mllw*;s81!vNigngtO@F8|4}#&w5^rRM!Xv!3e8wDMGU;t?_+6 zj+*?{+|8xq9MbyBc3tjOF7$v*(aLoG*lVIWE+j-cny#bdQNL>?LJ^QbZg6vVO_E72 zV4R;(gEMhCjZFv;C1C9WL_p6UC>yVmA~Hc~V0&Ca%fu#EqjO5vY`l&t5HA1&j;4NH zB{9q=n?Pd(^cO2TGX{`&PhRacp9j2av?lyxep9O z9Xu6B4v^7?fWedV0)u}{EON6sC&z*D_YuEI?t!p#qxRKnanmr?^(= zflM0=tqdYQ1y2YAVU`>-9w2pT09^43u&zfy_%F}qJO_#G!${#A+1f| z1wQH}JuT?WJ`ey>jEhl7!kd5Rsem@Sufcw-k^zhqTG+|Gi%0UWk0j9UjFQ*}s|Lrz z>|t*`%mBHZ>_rivC<@aZ5p*9v)`g-DpbK1VzM?eddCP3<#Yc_>P8H0`;?J@w$s_c9 zex2?tjd6D;{w+rP+A@Ltqhg$uO0(a%{U}^3`RRC4f#L07Bu7Gw#o!>HdS74Pc7CAt zbyps`C7<+bx?iuC@#`0l70HZ;=Fl;F#LOJmzsxAJ%=7m4w)_h7igO>Bz2ag{s3G6s zT!K4Jo$OWpAPxh$$KMmg!|uliUqdpYx3HFpdmN9GjvBb;0 zOGxVwqAy@P1IT55T{^M_uO`8czvpHB0lN7A#X9__c^`a82^I0glgn|wmn5EEBTON!ejby4k*=C#(P-#uUq+gamPY5G$DE|G3D8+6)6w9`9G{-rV1ebYS+_80<*EYR z{2YpE+PO6CUIZABFo+7eQqhc)>OxMdVr+tg?ymPAl{s{ws0dbQpbVvKaaNh%3OQLN zB&fW{!CHI`|<6nkQsQJv5J+h^s@-*0;4-Z99sGOug>!uR5H~gM^{|X z23#8HPqM|9<%@8_R>2`1HcY1KK3*l6GGmCIhCbJjql_Zw^{#?iKl?!MoXrNF$OBE5 zjuw_lPXsmIqr=ajrWqIl^_py`Nlh5yg_&Y1y?2d~o0#&WCY%~;`5?6A7H+pFq#oQtuAby^uK#w0=((VG?;R$JB@wuX5YSC%N5%_S|ST^9H z_N~(UavCr4>(bP$>%w`L!lk_JNXQ+=dLOC5}eBTWRJ(#01$#pz3vid|(69;PcvugH3$4Zk2ho;CBQt%%#-U zjD57MdY($ZoEu`QJG6JTzB=npOobZlyA8LIlK49jh>(u)Rt#pzFeAf?p~;GVJaJ!B z+$jQ~!K9caa7)%fY z@R5t!VX|E%ZZ=DZNZIR14D7lsT(zk#-mn7OI;v7FFkh;2<0fd<&v`s^q+owI1!S@9 z6Hv(#(~mPQWMjyQ@Jv?oPM(+(gnJF{XcQy1Y zRu}f0>FZOUvOk?UvdJL0ofiam!u{+&uncd5=mH*%E3o4$ z4K-*SPix>p%?+Wz=3CnpvTSI|9Jy~iwaX?jj^1Gys7p4tNAsv>-jt`^7%wxVEoznO zzfrH@JD%Ejqf-)PRn(oidJ?2W4t*J`HeMoZ;<>Jute$A+p^+l0IYXnR>)gvVQI*~# zb*2@-g#)z6*cVIuk<4o?{J7(|02}OCYnn)m0wW#}eKccl!E!vEA$()$fBM7tMCatF zc0jp#%el;X&xS73jA?NF&*Bxy&@W?oDou0zquHDSeWLJzJnr$6{5)A`M^q*x3nw$tgKLf_7dRWSJ()=hNU-bF_$2NJe;eSvI2=j5GeYpj?slAt z#0Icncvn&%18T~y`jF7E zn1m$#JkP_IBMAvRX*OmQOu)mK6u4q2!6(I8aJ_&YGiRA-qF~I!FkKke=&;JdIUoCT zZ#GC_$E{ZSt3Y1yfbNZrm<$`r0!HHXkK&U{w$%UBIp+WC&R_qh-4FJAig>7nW)kSX zb`n&FX)r((4F$RSSbU#J?TBXznm_Fb;sO|CsOT)#^UsdrcjW_wa1+_V@(v|EN`dUCV+&CCLLmA7r2oF!nt|{D5 zl(5Has5CpjknS_MU!+Jm6*QD_Kcy%;`_(s(0ntzM2D?Npj01%sTU za3070U;Q6bTth@0t?>u zT7ppqh*VU+bvnot(Y78veB_|{&EV4Q$@UJv_^8rcpcHJ*gz@?P4w@kExD9;-M4;RJ zuydmI)v_@%vL6*DqkdYiO~owcv?=Ut<3E3v0jMJ8eSG!cH_6Tc&LB@sC@FASOLV=T zd9;K!Q(~vAAG^D**dqR8Zi4#P-Kzb!Z?o`&0rr_J4y3bjXq;k__7$SQ2) zvUUk_(E~~CLI8;Vau6gQiq59+>F%EV@gzVBjbO&NEPXd)oLG^fF8#1zk9~pCa4ezF z+URu>rf2bY0U&D;0cVEt{wO{K+a3;^1O}?JO_{f2>%{NwP267nGrJMA9o10d7 z-N)6%bI6_-HfMP0q>7uSV)Hzr&zk`y1jIWS8_WthUGg19wi_hhjSe)2&0blGZ`+pZ zY~Trj8UcDa^9RryCT4T?qg)}grubC7nr6w0%qcQ-WE(b4)g|JiJpC1}A!)?JPC>!I z>~UKI*Njm_l;%W|0eFE=iHy8_CBBs(>*5n1gOkos5fMTYZizU_OuR_@7PCaU<(d$h zo1V5@h0|?c+a4zO()CvD3@80&g%(Ba{o{;+!V*gsIg$6s(RcR&vxT&$qI9J#>Xs^W}c+h9sEz4Lv zO9Hb;P~i_gf;EYv^i?o+ZP6~P00~Hh!2YWg7AD0^ zmBIpk>6@BXx-pr4PAYtgZtb$gb8%wYDH@-i;|ogGz?H~o1-1l- z&IIL^yztq4j&Cd@4&v+;9^ia%0VdpezHZ*$rIt70irr zJbiVhZiSRI;T+;$Q|oWaySc^Qd|0qe%W*@&KJr!lxcTahFTM3aXlH+BfPu2YgJnZ5LFhRVf(%<#PZ98K3+;t zJt1gWbxb27e2E~r2x&kMoBQW{A2W{w+p!{`jM)N?Y5IhZrBqK=sej3wa_nJK_hdFG)DP^ zNIA66+StCp4G&Awjc!vjOXh1FFOpWP*ShWG-sxVrO}5~=oal5aZ&N1hlr-D1)hZCQO%RAEi(d1N$kLZvL;y5pYIijxF-U}Dz;;WJL*-Di+9YO+RX|HSRbpU?rT45nR`8j=1)?FhD#}pD zutK#j`<8?p^ePbcm;6m)ahDX`9i@^8ApBTxwH%(}C_4o@12x4f7mB+|#ms79TZ)z# zgHT>*7AKS4r#~E>uV=bAarM7E&!~F1K_zqcY$vG_Ot-H-T}@>tuW-q*O{93NY*1&k ztzJKjVJjypnOCd&g-U(_GU>T0?_J&zL@ZEHS8w5x9?CsR zZ0D2Kfy=asrW-IjX~E?K`JF_%Yg#Dq2&^tRW>Vn__R-XK=h-74F;%=3mgA@gC)Ev$ z1Xl*M@ZvPXvZJf=aRu|qaXIkEB@h<5{zoE%^$?Y&X3G}|PokPkyej6jtdeaK`{(`o zNz*kaI~HxxYnUZfQWH;>9IXO%FH@#{6)z_;b^bJG-FVRr3qA|%$D7?kaRNWv4EB18 zJ>9$<#&h`VW?V~v9x_^Y@{8M(yE0djCe#EJ1K_(rJL0efa=hqbEDIXZ-hazT0~-UvsXdad}X)azNNKKG=o=2^L!MY;bV z?a=>IZ+iu3tp1O5!bvtJ{(Jmw`xb?eC7V{NchrD-Nmmw2MC$@qDg-;`GmCcVoTndh zh%S@Tz*&c;N>=uq1{`}=ys%FToT%Q;p54(4>}(pHRXb$Trhdh1g}8^gDK+_kb;wmG zwX#exKS4K>IZjMXQ$=AkV@X;&MR+7FW@>1~n47y$#zsa0W)Z#oJTb|4-5?a=7W;yS zeh!idmsS^x5HmY~MDJ5jg#p>Kmb#YvKME#c*0AYX72MZvr&I9+?=yKHJp&xHbC_;! zNC?w7E@(aBCXCGRx<=#u(Rs|^kHS;jlgF2ZJN zJI=z^X~t}7O!3_-^;vSV1NJMQlC}H}@BZ3KeUhMK7-K=3^y)?dqcU$N=Z8a?AZSS6 zH~qb>t1`A@hU(iVHM5OL`Ljs{+{*y}M{?H2&CK^F&}sO}r)Uee;X*lBw%I{~#;clz zRWNCoynqA7RJH5%0uy$-HpVNHd8)mkJKE_$LL^^HfH#H_O zT6(a$cnRTsT*Rp3F{-C9%qN{`CPmD3oD0`itS@j|Q+h-gI;u>GG z{A;yh<(Fo!YI=|XH%e&x_59a?M-a42yAX_c$7OprLgDfhRmb4{v3AsL%JRiQDP1tN z=h@XXIhI=6?ug*Q=_BI7=Y~yj26ANitWzFc;8^fm77=<}b5Z^_@VBVkhG!8%EYF zUl646-UTQ-=E6^lR9Ds;;1P$hQ0NZ{0V*=PBa^sD7>0~9-K?eZ(|xLIT?L$DkA98N z`KKfg6!hQr%Ch*RUm$zCWBgYVyOz#sVsx0CzqEwEv|h!p=!URVenZ2-KV20j%;^|C ziiUDi1)br#gng~4)ijqZDDBsi^hOypR&4R(D3RSZ8tZ{pT>DMJAR#r`B4{UoT~aX> z!^HkdSDMGip|%#x3dF8Hw`wwG4P(Wb(hTi)$_q|PR%46D!M@-*u8O=}v$TyQ8H0fZ zqZCaHOS_&6^)6&C9%$bjw6DEjJ9E67$B9L?iUbpHVZUZB!fpiI!yBWuuh}l}gmj%s zg)~WE_n-bC2;@5$rao9O*`%KdkleiL{bTO&Ror}TWWrOOiFRJ`a^nT>xUQ!DyRl`4 zjUj~_TBXZUWXf&NJ>1>hlDK%)g{C{}npx;UynU`dE?>~DRXIwZv=hY9j2>O;I@$c{ z@*_zWTmq(QJPk&Nm(^r=IJ4At%}fjp z&d9|-|Gjkq1Fb#&fe0?v?ae=H)BKO$88E=xKkQa!%~-tY4HRd5K5a>gF*tnmKw8ci zqE~CED;rGl3uIrdo(H8k%RV8Km=9b6*LcECDeRzl@mhd%lXRY}y$tjCO~Ou?S^&+; zg3qs2AqdP6fI8Io=pP^5J3%!4)35ybv-^mv#K-$kADAO>{2kDbBC&QZze&1zj|{-c z=fi}Ml@=^TTj`xZ z=YVo51&3X#?Mx6cc*cl$O9-GJEwlB(_mK5K{a3)n#DM2~@x(4(#fv?5ad=#uivQO7 zU7U*lNl!(kCVwIrtC4bSIHhhjgIQRns}Y-h$<@YpAejFqFjgr#E```)&cnkxdKHn& z+goh+{^^MJmluy8vWkmsP%H6+R8(Bsadhgp{k}B%J!sfb{%1f^e1T&w0NMreynxgf zPSAyScj2~P_~ZYH0uB9!Q#D47#9nVZ&-*Ld6?2`Q7Nl<=7H;_QA+d;#vW+xCcfr;t z>wHx}Drd7vf4S7r@kI~&gx5J(t%as%M84*jftM%V@BMe#>xz#_9lrGpdOz3rGIoeMj9LYYa0~hNZ9sVZCJl_fc8n1nz1cm@@haHfN{8dQto1|m(2p_)+ z^QTmY_Jj~=U;wM`$CW2Q7)u!lW8G1$?SRRh{dCtQJ^^8)@h-$S%sfQ$zv5A8kN$SY z_Jq_ufDQNGUUKB`E5@3H{6I>$PXri*pRWU~zu;&Xkvrby9nt&v+phw`J2097i#jI} z*Cx>ZH3xD30M&hDa|D;jFMx%00|~Gj*DmG47IT4ETV&oW1`JF=h7We13a?C%0yy-y zfV%5zK*0h*lMO{f*xh~At8qdNYZE~uPf2XE@w`Ad5Mz5Wxr-W$OqT*4)9981PI}e4(+RIM z_w7gDi`zT3s%VqPVA!Xbw2}P(0yHQF$e=wf^>WtKN5QF#PW;oxvksCI zEHZLRtd!rgk^;?ZTFwCMq(@XfzVjC@sRYyp@BRyDQU1>bS`>k<lTl0I0@L z3HRSa)Or6iI86OJ-2Cge%nOXz(U{CD$_Gm-Z;^i_o&W8snX)dn|MTBnpu-F3d*QTP zcw`su=7leP5h(cYq9AeFou?{^d3K@>CT5>r!8c@`i_DK|4Glj`570w;gjOP>E;Yz- zq$pcD7WGK?TyJHj&S~4(EqAr4?ia@K9_7p}SYM|USlxfA9KdZ9+4ag`qb*~ZZb2v7E^zJW z;RdbSi&Msz&&sqsVl2;;d$|wCo}8}1u7W5f5F~gJBH8vC06bd%3~<3Ah~%O;hNE8m zFfMo17(a1l7Bmd5(hhGjc3GsNu8qkVt=bKl8EyyB;M3aG>PM=1zs69nod#vg&9vKz zkA;4FvCXpa;Kb3@mHXT#;$Rx^|(Wn?fEM^!B} z4GkJE0GuFDg;D43OxqGhgg^uOj;c8B1Vx}KvfGidsA`+-K=dv>0faRQkvA?0V8;Q2 z4V70zY?zb*dIksS@ppPo2c%3)K6=hFalQ4-)KzJYv%6zeMVF+PY2w3NhYAX5E8-Op zHXs}K&~Y-Av0ai}!R+o-&G@^~^1kw5ouUYhj#c+rC6yzn6{}}XM$RtiMlI{cmRTo) zfm=CK&59kh10{fqpFx$-ty^cHO>iYoyQy~i9QtYxdTXEy8J?`fmdu(Y{AI@59g(%0(q++E)}d&wknK)Y^plHX8}Y+LisvfKkI1lcBW?+szo4X`okh z?->no08CB19-x3v#$7qG#2=qo5T4+Hj<7GL9bhct^IF~QNM?c?dY+=qgg@4#&vuQ^Z03a?L+zo35iXfe4QPVq9M}I~fsp7dj zaH>QyDGXxP8^a2sm%oA$c{eEwjwD>eDVbsE%Rmv_)f4O%HYNQ9FV3@Oev=H+(@%Ln ztnNG*QD$ve`l3V{-evxZ9<83jR?{H0ox^t~`L%&(*SHFk7~?w|ClknwA24Jg<6@9a z-h8!7pW#9#tzw7LpMj`PW=l2YCYE4ecwr#MOobtSI+M1|uB>f~C-s40fUfe3AN@$T zSC_uX%bfA!QAed?3io`FW)sz>APuZ1eZ%WUI5MnBNW4LQ+Z*F>vYXbYv6jOb?VaY^ zp<6&+*Klx0f2~0v#gBVqB=+^ZDP10!u^mgbz=_AAy}IYOaW^5439rDl`D$i^0%ZwJ z?ww_pUI#1Q*~-7VQCK0O*#zy|b3c9=MG+J0t^WZe$3u90xi9ez)%!CTCJW`o>`)l(0(Mm3Z(Ds>X5IyLRml2Y5WaVXiej{oeCvHpL(5chx2Hx~&mL}V-SNLuMPNxt{Q1dtC& zMWWBmJur83v$NL*;#qO%TaKsev4DWzmojY0c`k?t&osHBKOg^`hx}>JN%Ps%(AlvH)Ro_w z8nHt~i_o}Jg_1A$*JoWbAF4xjt;fKxnTgwKD*Ky=C*_ZY992Gd&NE8pGhKM#IwHQZRlv~+ zws64<@epYJkK*g_%D8Alya*bFe-3Co)`kQLY(`oY2KBXwV&S1MYYFVvw-`;m?+sz_ zjTwt&P{*(cX3o#;@TF=-Q2yB4x>jO7DdFqlvT^$%7<@5 zTs(6InwNi}c_O?2bbHYxMW}DoaWLlh%9L%^U9n#nwoGtOwHWqv0Zs+&Z8;ndku2iO zB)}OD!FqSGk>Nvt0kWRw9U`Y049Dbo%BFqBT2bWkw-!NnT64^%o0tb)Px%dfBQhdC z?CieEnt8EYnZV*Rp2GNYi0iWjn5{6qmTya&eDy4BGYyX{2o|#AB6+Jmly(&UcJZ!}~>c{jO#t!I(bu12@jOKn+@GFA7j@(8QHPZsfQ?QF4?60%@2lb=x?_DMC` z_?ZT3FaDL`8Bmg%l`-+;#Kto%!#wRccN|cjxq$};bPdSo1xE&OW)sPm&eZw<^GMlz z28eF9iW8+b0d8577`B5THD$B}?R;dRKiUMgK;Q7XYb9Y-Q90__tlBYST>$fD<=)t# zfXw<#&dKXNUTSkTR_atkILRjFX&pb0N%m3A3N(q8ky8;C_Na1UDfB53l$9Z zGSij}m!_pK8@yz<%1grR@^R;|fPMKm-r$S~^btgIO!2HXycjI`DOmMI*JM6|-2T=|;`C(BL+P-ifyMicNfZ8)VCv#Uc#D-Ve3FVu_ zFhAN5jamMDWN$T+v>XCgP|r3AyP<9(qv)2Asip+9BMgD__EGBL(E=t9kwc?h>bl`V z1^kqu#l5OVOr2dLF$nvlUvP$@ddD%f{!b98zjR82%VDkB08cvI1<#9W2ZUPW&SQeu z0p$hYP_zNP$);|iT8al~oa7RLQf)KyKn8a>%8xYM%RipR_So-NMXR8RbGaAm>+(5O zmV8Nuo_h>Jj?KO*cSO3Ul4Ws8v~G2NROxfgvPm22PSCW$z0R5gxUi3ZFCSfGi5_K< z*29<_Sqc7mhf*uru}O zTOCIAUmY{xH_uTN64-;Q6sRpcvdomCt*UCCmC8HZ>?R|p6;0yjQ`$%ty>pzLk@qf^ zSJ(>M+2)pBk?3GxxzjYO1B@sK)(Y{2y+u}0#upNYD)8+XsYuaR126|cP;-(qbfM+3AW%0 zYsz?8JVYmBRHYMYCo`7a$-rh~r6X6zlk2QLSMHKcJ&~rLv<@Gn7++mZmXQ%Q{kmR- zlE`)dXA!xG3#i)KZ3!yE9r}GVXgeO;|D7le!}G_-fGvijY86QFS8!5`#7u;JnpX7n zyj)|T)vaCGhHT(=)6tA$t%V`h(|bx1>NM{7Rp>C-DUI>qyJ8lHXq#3>4!@V{$EY-o zEY|Upq?t-BvyG^ThoLz-GH2tf6oPGc+JF75*Voj_5}?p_R*#YhVwqRaFIEXy_fRQQ zc+q04;(cCt4&?P6kTXc2qZ;63Y^k1I3F>aB{r*?F{WjQsmonfFd@KeUiv$rsMTE!L zW1wFj$@-*`Q=u)}-O6!Cliwt|Eotj9;STR>CTn&uQbH}lFNOG)L>cS!0>0&_8SJdA zf^BXWuwW`fa_;Q>GkzD5N z4+7{sr%HPkj)_5CY2hJg?u*gre~Q9hu;py>WU+s<`gx18{tUYKZu@hQ|0} zz0bnWrlWo6{l@v9{0r07?P}L?$K0@BPYQj{u4k($>62na|Q5F!FnVnBKe ziHeBym#(xZy%>5xAP^xG={58kdQT`JkPz>Bzx|zi_jmW%XN>*FJ>%^APsSjutgNgx zfAcrzGoSg)ZjR|&W!tTD1o^O^wu=mc7Kdi29PT4Qb6!*qeal48=FYTsp3{EY2_B;J zoXq~5ux9-QLJj-DV9s^KGqAsotXV{=wx)~W^A0Jk+klT%_&d7ypx&k2I?itpU=06e z0@7Xwa5xY_H_d!PR)AZ2&roA1*9h`#XX$RyZOypLdom@fyxZ?k&+6(wwv6+<=*Re^ zOiNlSK&HZk{m|?tPIjdD1yp5L#M5MFje#Pe94?%%5g9S>VH{CwNO4OqcKM@HHXFD{;bF zI?HglvuO2b_c{Lmn>hAAZ(zH?G{+E3^E29J;P!qq9p4)_w>cvkrcFs^#C6Gl@HCv9 zOP(em^!b}f*+^SO(CinW7r2HsKENsgEnrEjz@xa5Qc?0y83sm2-^_ zW6i9-AvJuYBAo8}RKHmGtxiXJojb@kZ0QcRIc7U0g9492x$`wFqd9QUvg0w8npA< zP}L2ZdsJ_Ia{F2JuE0FO^|cVzg6*>iJJVh%!DW_E+M8@HY+sx`?rP|BU_Y+cq2N1w zaPg6u_!EQr%n01G90zWCzwV>-0ZYraGP>|_D9!-_bb*7^l@WuebLwm>Gi(fb#=wA; zHQbZz7K*929B(6XwxGMJ-EF2;ayKh~Y>oSGi6rez58qynTQW=1=G785Mw@+Pf5vNs z=rE>4tI&E@F@YEa5UChcg%eC`sh@~YsFBQqL5Y~5Hay{FvVEM^$8|92aS2t_td6ui z$K4cVPI2y&QspLb%&QmC?!)=t`c1T$F@&i8#7#FVbwL6~PsK)0&-?Mf_R}$U$=DhN z7$wk4f${uuws%O0`5DNiPfeXkettWH(2dpuOjVp4!hU-QYico%!0hLB?|<1PFzDmZ zFB6WhhLg%&Co-~V7JzS21;3n`NLiojKG?J-F*nZeNHc)h!(RY@JIPbK>9{ZieV=k<$08=Dn$cFg##XIW{B*IBDu)md%` zXm=!+#ve!r`UJSt*>q4a8ztqcqOBm3MhsPiJ4XE+T;Moe)sQAa)jXI3ZTx2PC5o2> zr<_TSq?>+QN3jjIq(p5M5v{~Qmo3*~U5IT)wL?VTIrv~?7&$yxZmE<@n5dt?7HB^(+1{%04A9lHqt{7)oRIo;#EeIgfJkR_xv@dM zPyG+-!&$8lSYaaa0wCDQXqgsBZ5j!P3H5^U%|-QO9izb^l9j1}38jy1cJCf%-=~!J zP=B2Gtbi%wEW27{gqCs|HjLaJzN7cx_V%?Fm0K-2P;sa4w)P}bCv$vYMUIr8+NR_o zrhaPQ_4x>)er)%knT;wqLg(NkhT^y1gIMV9wA)nZGg8dP`YadKm=t@1JQGpr#=e5! zcD7H)D&<3mYrk9OqH`)MCUwRUWuCsSz1}LvlDM^{F-}F#B2T<-tat*Hef=WI@k0YYRkw+8f&}_lDSg)OX5)2% za#Bn%_QqV0lmHvvhHId5!s+|ov5J1#2MIIEaNonLGWXdFHDe3&nO=rt3SWxppdJ0& zr*I0&UUNG9354W*B+lok-X_mHaUYa^-}diUCP^j{t^D5MMB+(cLg&Bgr<}fc&Hl2c zd*iRKOtPgNf8mGt`%d*#VnbdtD2iv0G(F;&|N67sqXet#`UP@RsMRX#&f0S63#qjRK?Z)f;}D#Kq&ek5Fy#V4{jzgP z%tkVdwA4GN3O*;#c6r^rO8e{T_Qfi*VADW+A=U~S1VKa8~9=~O|T~cMPQU_DUOmiUR`(C{iRIOxJbzkSGn+; zX#1cTw8rp+(HSiCoV3snYr<)KquX$152!lhgk^4CvFXy*QVAHgf_;}Yz?3alQlhxh}rLyMPIk$7hjpE`H4{)-2D$|luR?pUw#41{WDIT5(THMv` z+|s=3k6X|wPhBPD4&zup_TVFc5Z|wYxUc zQ>t;#QUj~p{auc%1s0pMrDh|U5{eSQ=C0J&*J)%3VxB({ zy)XdNF^pf`ejp{|GK`7$)z01)*;<$otZ`|=8W~4AUfpQmscTn1@R_D)3){zuJEKS% zGgOi5F(l&_WW|2TM$9ZUCiJ=@^<56#m@HS@_KB`dWDB#5`BeGX6kyy8czvS-n6F4y*VM#f)OH6t z?e<`fSmI62fY_&r`&c_tiw(uFZc%5l+6OaM@g0bG01rHyinwu{E@v>NYkr&v=W{24 z@hDEzeD0UI6|6Qw)K!tBbD3ddS>anECMcOzfNX?IRT9fh*D2JG_mjB+d^t=tO_b5lK*64Ab0(*;hbN8@IC z8DlhSL?gIdbaQ6T?Y!SZN-6dBSGx58_RROr5~|1%?HPeCPV7B5_58tK)>U6hR(*YH z)61W?@r!$2RAk}o9h=)VddTnKt}V8HIWf;!94(jJ{JpYb4Q=;W$7BVoYJbS5S2Vq) zXy|%0Wxd`|Qq$=NVVpqg1N=4!=D!g!vXnOwo|-Li zL?YSL*%|F9RRQ6$;t=oaKQ;TGS$1+_ z4NmLF7Pax+Hp^bOwYgAKFETGu*CE!Ikg=1X-kj>n4M$t28l~kEv!e3oCMo*kx7w!- zwO6vh)mLjAD&y}UK)|EF20Z#NI2Lsd>h5gJTbx7sDLjf5A?i2SWCJGehu~u1*8W5T zP8XZgxL{+Fe;xVac*R;bH2e94mT+-~R7jd_4&1vBM~*OPARu(I=xF_!?I34W`dIig5&YrUd@0IgWo8?- zYz+PsQVs@Wh-VmgA&}LKa}7h4H7PTOrMQZ^()4p|7Yk%JZ2!_aeQ?@ypq?I`sC<~t z%b7SYGHCGXyT4M}vhE2pw4$@H7wzssFgcJI93!b}K)m7GR}|r0^>7{6u@LZLWMyX5 zLLN6|2Ot?=$l&p@f-%&ETM>bT z9-g4KkmV^6NDgYk=8fFD5l(Lfni%WxtI+_SV!Hq!DBhv-3=Gc|T>ATs7}uA%4S?0b~wUZ6~UHfT0W99_G&x^u$ftp(z0x2xxT zUjj`tQfy&4)ony+4($_y@>g!9%wDvFU)Dx(Eo8e>fiKLAJ;SNRYznkgI)q- zdXp#Np`x2enhV?!KC=6FQvne^(dzJ3cK#iEET~Zh{ zB7;8CSpbmz&zixvgL^lF93B19Yrb${5Tw&K z6I}uLnl|u-btIEKS{FhUr)g7Jnk_3CAOj9R54?FW%}S$TVBb$Oy>P{Mpr;D0Dy!u! z1p9H|05Z&p%&O7WBNF1u3un_f(x%;ffHY>V=%6C}NECml`l4-EYfgz@F)(tj%6CNBdkI~z z%4>%5Rf|gVZ1F!aR2+BfNtMd87%82@Xu&4iJ7b|0oi3uT})BRJp> z$f#(qb)dL*7Kvap?<+41{RbQ{5pQxkf# zj<*f1lv-sHu|p2>2Wr0MW3T8pfG^o$l1`8_2o3}R!9)!K;P2^aE2^CqiRNOb zP5#Y9dG7h##d!`L0KHb3Zt?B?@S3Kw_vB9r)}Mc6kK}BW$prKs(V`WV^_(yY4ZMgU z3KzJdEv7-8?sl95RFFDnnBdA(6q!Sd?Asc1CKdG&$4uwUq58H4d<=ESUMpX#X#ayC zw=E_hOYYmOt$$+m{axbcg3Yvq7r&WGex$gbSNB{{1THnj3B-?sx{XTDX>G*Q9{H)X z&9EWv&cI&`HmEq6P4mU|wg&k3sq>3|Qst4H%E)tcD_S*FBX)bACY}yIx;J^VD}1z< zGqjm_hm$k}^)O8n%95uD5fZAZYxfoLgl`wE#V|Lz^>m~Rx8ezI1g9V#cVNNY0K!8~ zGDw%oOcn=1HH$f9^yRf-#91K3#^bo)(`i!=B z4S?22nE4^DqlB0dgCqhI$?#Vf9iRsE70K z$RMC%2Kh?Y#2%Nxq4QIckTza@TpnB*OO549{nq_@n37bwYJL#ADpmsf1FEJV|A%(1 znNq^wB61k@m*w#5dE6`M2`x(TaXv!TZ@y`UG>9rU_-XJ7cY&b>ZMaPCrE?&Oz#Es> zK$Ym2x0RqPQ=={Dm@AzCaQt0(9)wx(KU{1 zu(p78Tn6ki)DPSW!GQ3`(AgLO#iZS*a^S0w7a$b>y1F`G$^{6Y3T7W$wc#RgK*IGz zW~H+1rCm$x2#7I%n7f>=!_~6!@A@t>M&=c~5w2|s3<3}*8$zPN<&a2uX}aet9647VCRO*BXkGbxmdO8Pi+y!+uY4Z4jEaj-+V7^#d1cZ z>SnWC-ia8%CK17IuKQ@0@vXH9nk6{|Gg;NKkePJl*RS(@0e_vKLqD3jwCbx)2)JAT zDg^&xIs+5}GWCcSJXZV*Ja+?#S5|KO9_Ibsr(0D-pBb6F-tBY$e`bTk`ZN_j1!YE- zvcFr9Vn*=AJf~gegHVAW4TH)e`i5GX3O5dekv=?5-LXWBm+XS^^x!dkDH7@e*`+Bi zR0g`>x&Zz99X3bSCWRcNAl4wri~W&P=Y#dD9oJyOe9RY5{8IaLHiu9+sBf@?{Db1I zry|`;T3;O^#hjqdw_1uu12y*D){L9DVc};D6JOUAV;{wMl(rUscpb@i* z^ubw^(Sx}+-Jf_ssLmeL#R{Jdyx1T<#LRWTUd77N83KC$4%NlrJi=9>|Gq_tz>T@l zLbyS3#u>7Hz^6urf7XNNi}cm0DGV4oC9H=7Q4)+aBhVch<) zlHY8+j9-un8If7=oVi)aHbc39U}c$ z?=ys#^Y0zPo2sDi3R9Z32a|gB4i*F4CVr9163Xs5PwD+oL#=oKR+difWqb^JLJMXE z@0t3~OeiJO0RR9H1587VSMTE17o1nY?5c*g-b*%X$tgM6ZzcM4`m;aXJ;;0!d{Jq3 z(cob;rvGEF`<{!<_etV`{>Y(a~{m zio_E^%*QyLO3!Q2JzGs4)#{MWwDv30_k|q%PBsKsM1xsck%nlC+G~-Ds)CzNL*I-D zl6m8K_uAL?qeJ^7uCtb03UW=CE9^&iilP@U#A4k_#^Rh|_0j7zD(Yko0a!~1lg5dkEfPhmvrfV8X`T>$Q zOMPlng;qNob`>{Voi>0he(vhMN1V9h&_3QB(8G&et$>$M!{b zI=a;WPw3q}Nj*-{FkTZR(nIu9fFhNTT2zE%)%GVADpoxHt^`-$2PxIeQKXVSBPyG+u zf|mT74^g1J*#M1?1M9Z?Q1bf!+L1OMqYIF|8#8hLhzIV{!M^}E%uJ~Qf;4aiLicZv z-U~!CfBY9t*#;(_+uwXSEj);|LQ_4C#ts?-^Mts~wmYgiBb+aP57%K0dFG*bxeK%S zYV?V#ohI0%bqG(0z&f&;)r+3b<7uH_EmtM=>1S_V3eKMvy>ww{ydts~_1%Fh&2oEN zT9U)YjaYJ-?$}RPLgVGeUlp@Ax4RJmrvKz6agzaht~PIAy85FRzpj9gf3b4A^Dsb> zM1JHaC4@#qsHF0a$-=zNhx)|F_r{+Oelt#y?N@hmxa}OMx!k{a&*nsz&(s~ zwE=tF;CGjY=)HM>+H}EYpk%icxZR30=-=*UJ%;WR<7|F73OJjqP~}*Ft9sZr0-DqM z=a$LJ7#;e}w0wjdq~D?>BGW@FLTxq63Stg}KGXP-Az;92|BmL;RIVM>9}@@%A?!q= zwkh0#rBMA2+vxU@yG@dXk!OLCWl3VmQPjGjHXKD~cba7f6SdFY9szE1Xybafb{%gl9l z>odlMQ#QvRe=VzIzMow}Ex=eb8!MpIwzK>s#uP5B+Sv2QXGkEFro5^Aae0U7Z zaR(rRShkIeBa9&ALjP|j83(E~IqZvS$*J=E8#x?)F**`>T2VxN@Rna5qtYI-`+t8C z%OBkV1Hh2-EQTW|5yIw&Z}KILL8q_R4mkLA^`pB;lafalU1@ScIcT2E2bR|8;(AB7{Dvi+6?KC$gqFMr8W!C84k}}j`(Jf zl9RZP8KCp&+C5Pn7B>D#EbwfT%_h#*H=w$s@|A~s@Z^8sq6UIC`bIqr5USo znakD5nd5UJekrmZapI5qRrNYb|A_vQC+636mm+)cDg{>v-5%M#TcnfA#=iQ}&be`| zUSe;=W_fapZAH}E66Kv!^3w$b%@NV6LgU6>jVqdCKMfz;wMD#GT@AcAWZS1FB; zi7=+dQ5eUsaHR;upgdpf;5nDdF50|+ zpWXFz>6Pm$yEZB4dL9Dvf0=b1>IThb_^xcuBoA63&PH>vkEqnzplhtQ5Gh{k6mB|4 z9wmy(18{K$DPXD{O$qKvm7GiEI!>=-`Hp$UGA2MUU^pSEupFZBdFg!yk)&8*o}y5fl7PoLiF1tU3gFwEL4P1 z;+>foKWGhZDIQ0~;3}B$)COP&ZxnwG5S0u7c9-!sa1r*TFxA6 z(smp8U4wcB*}CUjp+Z>!^txpEko}18@HcDyk!OsaU8#j1@0U*YtnBah~S4SD4#&B;s)65aQ;xr>h52VcZJ=k6n z+<3>Y2q-%8VL`xb$7ry?5*Zx&$4Cj>JZE(6`X2)u5~^zagM7E*I%Z6M)DC6rZG?ok zj+>$-OcTwLC5$Z9V43E+MBOQZumf~Y_1iAIxK9Qj zvdC;7XK_?#If`XcaaPy+fpL|3P4DDHjI>ZVcf5^_{QR_qk-wJ-SxmA?7G7vXxK(2@ zzFMcEqBdx*@`jB6{@OM?K15_7A#TatTo1!n4E3q4SwvMZZ?erxkFgMu8{#wpxbkr! zf|)S`Do3`W-4W;D7yIFgXsYWrrR6vSt~S?u5wcdRQ09xAOYKZ&Yf)z#+&eydNqPNQ zN~cc!J8wSC*e#m}B^EwX4PfRARIF;g>0k=GyQ^$}ozA6J!;PbT!+@LI50ZGX-$Dxu zA7;nJ=>=$uq^vj8DPYt^%j*W@AXL$jjTy2iQMNBHtppz_aB5 zbt{(COLS`jI>A8faQQh@OvJo22V9jbl0NUyzo%v}w_u(kl3w64Y@}-OBZY-VQ{hhS z()Ie0Xcw(0(XS(a6LF-dz~kKYxiKuDY;%}A=KTbtWxF9l$6y#I>mM3#5DTo}dK+$#K|Uc=>p%j_c!s z@!is{vzdpl)AumjP`B7% zmHs`J5?+^Y+(zVxF=sO$bkXxOuMCB^6Dhe&e_d)^7!fc_*X$|OowQ6f{qptcNp?=_ z(ZXyOfXrsgt69`}S7!DWf6~2EHCeAF#$09`rYP1E{oZ|Q;No^)*h>h7ab0j@EG&f!ZG z1=g_!qYKCD9rMZNA_@6Uu0Pk0gECHaE7bOs`bOUUnZZIXMv?E%Q9_|mN7rFD`HXsJ zU#O}t_k{vGWA7mjq*A8NSPG7~4cmKqK(?y(Z@(BC-J|05?3 z=?vcY)|*3f`frV!!64I>DNA*RggQ-`a`ggg80`*S6L>Xb0MQ0Wp6$~#SL(y#6o6)L zN=|OJR;R#h23vSBxR?e|`<%7%2;Q(z_cBd>VO!|EGkW0GW0|7r4v$~5X)`AhU%vU$ zE{1*}8QJTkzwV{-~f zv|%(j1Za3UcU%DQu`fNGYr{jvS@6hGt)^6ikQo7hkYU~ks^Z2&_^AgixXOdKUec`8 z!d{E}vq2}<@ulif1rW<;EqON60zN^?=eDJJX20lY*1l48#;bzE^4|5z=tOCcX=TV7 zChHbt&v#^Otx8pKv3>OHA|{ks*a!^emIUf3TE8Z2We@lJCe%WVS7A3PUdNem4w@r^ zfZ|46gU+1whK!9+$iYnjr??q>Wev^_wP3gRq%VI_mM*7|IuTrLf ze|kTmn&BDe>u7HvjGs2Afwkt9Iy1^P$Bpj|iKB|G?apiAp}m~c&{kAsciVfc)i=Mm z>Fs7-p>cs9B*IqVxJhzK@i)rUE8^0Twvi0KIlGxY z?jQ+r&1v?Mo3d%w)2=+{aPDsRMvm-%8#&{YZBlRxV6-vc#JZN>yu9X-jbuAyRGz4F zD`?(%6o(h>7A$)G;^)F!_dbHA>VRR8CFE0~;yJ|yf6&KmtQ#?1A;=#7h|vvRyJS&_`)4pXKACERt^n4%R55pPM@EYX$?UhZCwVs|kdo_l6wZDdb z;^#4Rh|x?;ZU~ZJ4Z$O08;^5hy*geVLkX%CM8y#AZo%QfHbcKu;}KPjY?q`RAcIP9 zcDsZX7d-x`5hlxiPwKIS(zq?|hl=KTFv@-V;?fs&_GE!M_e2?`j~B9Cl=L*kN6|_* z&k0{^m7EUTy{*^qi6+I?Q%=Wo8i$l!bLww;`GT0mwQ!tMBC;s?Jm+eS*MQ-B>t1NT zcOc}lv$AWAJ({zs$f?@>=dxGTcaQR)K&z65U^@pA!&5TqG1+-O&0*;7bC!DEKI53U zAhnm<+)G~$d%&k45^ZLkWsv4PQSN0JDmyV7oAN5%m;dGa`)9O`)84b5yZPa!GE7JJNglRx0?(^n12p{v=2ggr>f{zAZ^ zi9n%VL+92I%7zaiLRbFl1xMz(`$>JzTB&rkqEH1m);$h6^4;aoV*vT>;Pcg)i%a6P zJrLtbuU1K!`kQ}nEB{00cB-vG5*m<>&A3GBi5H&AqcBR;%SvXfzFld{ahA!Bx8%8F z!q=IadhSBd{N=Rh6E~Oc#dBMx;9oc?)MuyVj?ihj@$NYPj;CgpJG=fFQf`*nrmAY< zv~Hm0RVOfVjGeSwnX!9YlA-$7KZuuczaF}woh%0@+B|*d*2hZrFe&EY)3=u^Gn#+R zJ(jEzFDPZ>c|AL8r^6m~(Luso%p-RqY8%=ir8pQUve#E=MDd=p8F7c9k8*4M6#@)C zFl4Bpme|$)`+)_kwV0{*HdCw0xR3JIw^ob)oVi%dKJiKMaTJQ3E0&#@NF^WL~r#LZBW#0O<8?Opxqi}LP*&Q zdLY@V<2+W}5WP-TEx{*yQaMb@s7Um4wVnvLB{+0^FaL_g)h%VUiI@a~>)TT@t)!p6 zf8wsh5eo3v##L{A*2YR~m6}2veD^J5+?@4*s>9AsiZ0O%Y4~{{Cu7dVk$Nk~M!_!} z+AuxNVm2>I7AE0@dJSHwZXGhMXD}U&OoF7GbHj>$6$n0iY}%^1dNT^g`RX)6zA($Q zXeV~_#w27zz>)E806F^zO!q($3Mt3{ZcJ`%#PK^cvQG^Fkww^m2{ZqEKXe~}W)$?e zO~VxvHyl{FyC&?THQVw{UmDD5_kT~E)GTbG)Fc%@W~+O%aewk!An&ifo*{m|?F)f^ zh1U;zj|6@*>Fkx4%$xpZIz=bCzXJWV0j{Etx@17j_MTjb*%*v=r#o-jv~p8PhX}1R zkhuziNpS2WN87xO^QiKFbC{x^F{Q42o(*4b|G?Bik*kOgJZW}U>Mnp%;C2+h{${E_ zx~>idfPnFtImbqi$u+^d>=T80k$iD;U+>Mo5il5BhZNnaLU?a!OjT_3jy-U!A>~CZ zWSj{nf_aV;7fy4C<$igw{t?u4G4jvNA4en0{H}}pN8))EznLbogK#YQ$3`Vmz$_rz zYlFfbruNO=CnK$>C!T$NC3tg7LT{)fW|M2VnM>xdIz^zN1g4I0`P{QA$@Ne+I;}jq zvc|OJh4STx7fD*n542x1cYrY;;wGqejh+(^uf_o#LQXGXqpbZ^U*KKgQ`K_rC@ND) z#ca~FIyS%qx!JF77Y^IkF=rr;tF&5Iee;zp;wCyC*Erccl@d}f{Bt%q%@dL}u01^t z;&jpt>N%@xLiO}4qQ=}ORe!>;uwC=Z96(-i;=Q;Y$Qmo(D!D}1+?!R`+jt3mcUG63 z|LxV-_FHWi7A+I_jN)o7bAqIj4OHA}rg-DqZuONIi9L-ljPI|+7`maWB7Caa+=<<6 zkI74+%pvN6RFe7%cnQIFLuBfI?yH zZFu$TBw$AaTC-U2T!Z`p-cf}bFqhz$0#z%Y#q#3Lz(Rh`-7!g*kQBaFe>5|E;I=dq zn+`X9ZK`30(Ojr<%geNsPK*o;V*V4DXqVg~M1_%>*urXCvXgjG&6|pIF&{S&5;J%S z&1sVwvY3Tb)*nfNb{>wC9nE(y>-(+R^QcMav^;pftiNty0oI-9w-EB`RqPTo^z*gY z!8m#qGn}6XTai#90Gnz`ln9DsT&3S6Rz>by*j*64$}#R-#C+BoizS9v-) zmzvt#z(X#HQaw*PXhSHHOh+bEnded0;Hm&59f@_DRf6w&uqL7*7M=dD9(4^ARLA-# z2|q}wt>H4TEJQ1_e6e~(teki>aJavwp*nLXOM4*CB6~Y9d%6Jzp-1oDCkvIj)Edx* z#-&2?SB`w@+=*6a%1P5-UQcrmm7D>H-rniboz=$91xf^Y(ZF?Be3zT!^oG3%c5?9J zo6p$O`HLizb@3l+-a#)X+yLB$rYsNBpFA4`VT&+z_w)o>(Ceg^%&gjwYHq&JAm%J| z$UY&K@ZC$&s^vP@fUDf5c(ZSSK;lx4d$!BcDan?^u2{L)iM5j*V{Vf3wtNOoW*RSU z_Rhz7=L0M(cjvKOjGoiruEE1S%*L9qv1W>%dX!qqP7u#58LmhY-B_OIAT!Sb%gP`G z#0J#ZxPPU%MJ-YxqzJqX6Pc@YF#=ORos&0;_XcN}JpWVpuY%et8TCi~A@sKBd!e7G z#`2Bit1ddZ`r~<@va|RGJqG0MgleWXy;9wcBO=W5(Fc>_@%Hfh$uB*^jGuPJdE^*& zn8lgFizRnf_7W2hg}YJ~d=IqUuxI9a&nHAnpI=2>B+L08gylFR1j>Uo$S+3hlMYP8 zv+-v;+i-D2=i>X}nn~K}Ii0TZlu?FYhsXB@rD5BM4|mG7TVdI`DND~|r(wA%k;XyS z+d5v9s{*qYlPo^qbxete4t!Rzd5*mzLoedjMUpe}0gE{AmqiJrI%cmT1gKC_d}G7u zez{BfyB2+N;8S!(Qp`KKZq@_CYK4HPsRXWW(AaX#yA+C;9OZ#lj1z)1{>QP z#tC3W^Pht$=?(REzBjj0WyaSfx&jkFx+xAaEH0iHEZrwD?!NKX$>_XmN~%~Z90&;b z0oh)>Cr))}PMF)gBb#HX#xFuRzM6>Jv3qDjZJbS49@)G+<-(iRy_1t|X+Lggyee@J zaZ%s*8TyuV&D%0baiYiSL8Sc>9VHtc(+jy7b7pRt^W}Q2=`Arss}7Hd zsJa~H+qzr2bxOL(Fox=gwmJ_lld>xK;E*varEqi2A-4VNPFpUO6qzEi#(#BpR;3WeHSA`1j3L zww9}6t-jzt`5A}IBRKIo4dRd)Gd&N0S}D(6qW^dhXHg$x*#}q5^m{d~3*#^d?|S}@ zGEwDIH?+@=J>}`O&@Q4PE>J`l%L+dh7yjiDEzl@&Ry#CGEC7;BjJI|a_18YCsuO}s zIj1gJ4BuS0$Z<5%wcm?`f8*S02@pScJyG&}_rcq{-e_(eGH0-J3L(Ll;?Ufm9oetv zeCwCR=8}=nN7GHA*L+ovf2kv!6CG-%FZjE{H07Oi{o0)oQEKzT1BT8ecPpg3WNP#! z?L5|^(@hE9kdDCt!)+cBR4ma_~1OcOn1QNyXn5DPOZEc{VVDQx?j-BNg-YXIi`3VsHBuL&ndk8^4*}1dQ~O6=3F~ z9iouaHGpP-^V67Jv;0G6dgiv0dbpz6^W;;yvRyZ|*f$^C?kU>T=k44c5FdGP5bE_9 zu9WFKF2pKKJIyC0%AZ;@n*8H)#^QqGA4jmg;;!V|S+NfH;F%FiCRvW6*xZSPCHk@= zU}Ro*x^^$r6x&+eDauOiM@pE*#$>;Yqjjh3v$C@kSpof5MVB6&sVT)_;#!Z!qR%wn zy{RRJ5bHXz@g~sBJHNl#FavajQ_NFe*1(ZRT#lady3kv!uZUmcyvI~)2aG=(N zgMbx*H0>lIXV9`eKAwXtb|OyerCJM<-*iLA5v6LaF?Qc#?3vdezaGnz?#&!@%*-b* z!K=iN*Gi~g;-BX-7y5y%`@GPcux;;qu&q37(vrR3Qf$1i;fWjPdWM*pGBA5%W{Rgm znr@lpCrrSKbc?4{uJ=H~@P_!E4sGo!ptmYhj9Po3JA5{^(9f-zi!v?MC*tfSdPkpf zFzw7DnNVo#Dl%u1A*)k%VWV@A%&DxDOxWd5z5MO-Tw0C>MoQZ=hi3qg+A-DEq&1nv z4J;2V95O6ECO%<(aafA^o*M`6n7KHYbC@}`i5@Ochzml6V6|byD4CMXkGd+Ix=DlH z>9P*?sXBF$rzAw*wA*-m_ix1865bxjUflW^`1WY(o=*DX_Q4{32&Y)-z?+~A29I>O zq^?hAw?{{fne^IjT!K)-H~Gq0N^;^+(N=MBid$BR)9(BKm^_^5$Qd)#v>p{K@fDh7 z>q*h8`$OG>K(}_DSE<1WNK6V`@7P&?G`N^>I-Is)?rGWU%X)t5YI)0zsAv|!Q}0r! zs;;&MvS_hNa47dJk)xgVmUe$7(awdKBzp5U{KBgLSmpSRD<$YjAyKI--OjKU z=w`7J5ZtvMlD7^R#1AW51A=A=y9Rz6v0F(#&tmV}=$5WA8;5t)YY$M~!5oPW(8MIyx-oU5~ZApl(str85g>{`Q~$?lgZP5U!hT z~Gs!c-Fq&d>=%+DfGG8xvtHjW#@F?nta@0Y1ymt|@?XISi}ueM%ft9B*su zCOoy+_3b_^R^wu{&-*vnlTO+-LP_7*(i!IvLn-F1V0I9*3-Y4+ZTfYxW*%v$cb@ru zB_v$gCmH5HA9DdR$?|O93Q`KOMq`I}wOx`^91hZ} zhcAsiui7YfsX`Zgbl}x1!*ljhN>9(ugV)wUu5~;#r%Q}s0&;~DNT!2re>1hNP{rYFKeQ$H0YH8Y7!volpLQ#12r5l zb?W-GTJZXv4aV$$ycCc{sN(@Z%qaqz7>XctJ~oD;R&~saqb?Qj4}fq6IXVLrQD#Sx zU z{`A*FpTYd_c{2lryJxy6==6Lok+ZhJ{h{!;$^}+`dcTaq{rexATpjZg@!#MU{MR0x zI|@dGuGiJ;52y*=IeJcN6j%TLP3Z1~me&Qw_E(FOX$QeOX@^C<1V9{?+p9 zv4I@_XRV0;nmPPuD>)JkZAnfM4qoF{mhi}&9vl1q#%0Cc2aByLf7o#%1p2m3EnzQd)19+k-#lF(KpZVAE2z4sZaUv{WtY2|LJ|?^oHquX4@#T ztpQpAemfXVFWxbSOKlR;ckgk#M!eus6wnEB${w>zX+SGKAwLO@IqZlk}Ra=K_ zj=Ws{ulTqB^eX;kW&WS%ms{1p%(K)RKP5|{Si{TO=jzQai7hS?o@#j<@WPU^c~!O2 z3zN&fO$FER@mv$GZC8;~GBxyZ8vWNjVHMa|xc@tEPygxT6R9A$=G8|JEVZg2Wv8{{ z9&c;(9_4+yP82R=V$WLtmTzSCa zUd$ZW^f1d*S&_DUIMhqL@jB-B005<{xPe(Qn5e2>0~6;)_cV8t&o;z_;uhS2J(+vO zZ>$cG@*VG_eW(9ss!26^Y$GjoZswKx$dcRSiEA%DulEKVJEoXT81E*0BkLM(#EkCv zFO!hbdL4qlGQjp{tUP{!%e^Xo1UQO@(+8uh{G<4OGxg$*Yqh4{;3FD`4F5*5MduIb z{CYGeL?8I1Iv1lCQhu;em+y!B^Z(-Ry~CRP)^uSM6%hqNdW%Z$O7DmW7!Z)&i8PTe zy%QCs7wOWacR~jt5b2#r@4a_I4J5?#?tS*2nctp0-mo&UjZs3Qy)Gu?7J~gJCw@*4pwOtcOAXasY{yM zoVhYSyen9$t27QXiy#w%XQ+;sFg3DY?{Tx1%zUjx>YHjwtzNRCW>q+(q^dsQvJagh zRxZG@EpqTE1wlX&n;S%rf8$x$BpF>fUFeR!SHqk_5C4=D@Cljq&sR&iK%7m180Ca> z`QkY{ZYUK9*o~~^b+0DiyF`PC6(&!Gnp1=LfYTiPUQ|5OfEQ)y--U1@CX6t|)3+y=^BjY;Lr&4qo%Q^lB~J zZz5@@rA7!Ulob*kxKLU0T@bqGxT)f?Tcen?FTrvi3@c)yF<`d8HwF7)h7s^26BTNQX>~Q}Mk7>A*G5X^fzE;>Vh_=Xxd8`n>il6RuMxj)e2G zVv)V8-Pe8$^BU3^`jmgTE;H6g@66s?07H6?Jk|&sJdB<}7xJcXhLw(w?AJ)Q1q!%P zRyH6NvBH@BrOorG^t32Dt{gPt*^kR2U=Jr*FeUaur>f#k> z{CA_X3z=*|y-z3Uc})X~6IK?B)C;L-`@c>Q!Mf7qsG6#IiJ4%yI8s11XGebCdPU%Si$$Y47f(awvpV4k zb+`kPMg}P<(5f%2-Q~RG@HD)FES$WYzfgE{FxmbHBeH+IebsmLqtnT0oCnvJhGMje zS`yvB3JHP5pw$KPoL^%@BS!1MQuMnUyK983F)@(WGc(iEj}@)0Ev@NoCEL#Q3>$gRBKb2^>EvA}ekh@~}XndQ0<0&`R4A&Ge+3xU2=vUQ;I6M-M|1ADB zLF9FJTffeBt{TOqyp5inn}lw-&4|rT8b@C85T<8-Yhm3tg0>z`zfhi9IPmVmlD&Ey zBQ)AO0ysWNF|L)JAnv}Sq_Vrk%X3ojdFbOWg_qKLr=)u~PGK@Pzpmn|y*_sqY zS$;w`^=5paR`_421uMQ@OYCsVrM@(7W&-t(5&NO%Y|7|y^w-PQDmUp1zMhfI@F0_{8?~H?| zx78w+4ybt_^<~Ge$Gjdm+#4=dQsL+UY?bm+Ci7P*)v@->BmOX&_cOguWBM!65Z+?z zR;Tg%>l5)c{(1mxN>8f`*Wb2^M8GI6?^y5p>S_LOx2Z*Q-HGOhNajd7l|zP5MSHwi z5kPz%9#i{_CY1fGOrTpc15VJTsV2Gt?#-)q-jtX3Xg7O2oA(=UXO2kTYf#N)GY4?5 zMcX`88gq(qP{XATTeHK&ROT-A4iJf^TM#qfO~Al`kq2d~+BCxJD}^GG4}n&n5KY>_ z6kntZF!=>{LmMoTeb}V3$DBQ7Au;H*&+Tj4PZ%GqsW&s>3l_1QZK~8TV`H5oE;$x5 zFWIgyzgyW_MoT<#&khZH@3=dvZ0J>;E!fbTyzjl9QmDTp?vPQuHB2LTrO_+(yl3X% z!ntfs=frZ2+TFr*8llm$d^m|^;r1ss8nsan2sof&o*10Dm_#{u0^>|KV=1DEg++*?0q z>MwZSBp+PkVvf}An`B~$!#iJk@apKRzlsr&G-C#cTkxGNh-~zm74aP!!^MDx)0&wJ zg{zXeC^eoorRuAqnRgdGjs8?uDj8o$d*_M6G&5LN+6@NIgW0|UG`uvi2(`6aiYB)= z#LD}qbLKCmIkYC}k z>Ay4(1BL{!6T7ySL5789d78~hO5?aHe!-Pt)3;A{^!iJeWmva$DwIp5C^@M5^;2xB zL!ZaL(bygB8?q_l49)dt7YY6*v6DNS#P{UxJ`Wn>^NV~3V{YQloez%=T( z5xXGQkdPkWMitc6Xx^V%=b9#r8{z&+2Lgw&E0nNv1ajnL?MX%^$N*Md1n9 z-$;MrwIUQ~8dMnebG&s(H+6YA(S1B@U4fOX__^zwvT1AH-E&wlZFu^P!?TP6Pq{Wm zx`YcXI0yZ<_nyMAp`XCZz%$1xuVFgNW9>I|c+*a)cTZq7gItR2EsCUxOH0T-j#iGm zIIT3;KCi8!vcWVqD!Z%a&HL>#%2Y2HMOp9u#0X^csJ5Z0*`s+ht0L%iqkBVB*eh#` zk?i;$tNS!gto`XC5%bM8M`N6$?cni}nA8-|`VcJldU#J#|%4cMrk&_JKqxVe-c& ztaq8OReExJAE(~Aa(VLxHEH$VPd zJ6V(C%cXq}P(_Da^o^Sgn_>*pBS9oVtsNt6E%L^-i7wyEs{XWM?%+ktlw;pr7ss;| zCit=S?EVP2&f*3?eKBzoHPYzvc*~&R=rU&iL``l`Qa9IndcJURp+-UDKmpYpTV$ndm_&*`{tSqJMUc2Pkgq>wpbI?DkwPP zuFPUF2*@2-Ljq;Uu<|A7*p-c4%%WrPW$9Sd?!<~r0HiXp9T5Vh+LIKrW={6NvUo>e z=LyHKJPc=4Vix}|nRR)YidwNcaABS87(A1Z1|u0GK$^W`y4 zb;byj##*x@$3vM77=zx?Kz3Q2R`!Ou!NoTd^y^d#;PhQ|e-4EUf*L2;_z!16{|vm= z&s(a<@3~zFWT7Uop|l$eg2Mtkm=2iQ-O}Jt(QV(mr{A3or@F6f`^7uHlZc}`4lhAr zh}-@gSoR;It3z+lX@@IDXfNrCdj-vj;3&fp-szoRx2L{dpR=2h&8xfS zzB@26;Tp~SVII%7b8&js>Hu_UWyE%SVQ-HO2PME=pM|1|@MP+$GcK?oG?5bk#unh= z=7*ucU2Bo2>o*?lcYKTw7!b#`0Ai0i5Z2}c$$!;XV|W~utTVOYv#(Geiml(%G`s!8 z#4QiU{CI7{uafR}*k&+dekdHwxMOPVMrkxX%g}~_sMAnKje>epVytgWJL4Lwn*Pw& zLgxROH~HgJ@$tdq)g9x$Mh2T7rX$l^n)}|%0YHs<#;Gd>n;#s(1pQ+~Kgs>^^M750 z|Jbkp!?=q185)exwa?!*bydPI-gm50>AJk(hix8H8XxJe9;@;DjYnZ#@W*&R{0}|h zzij6G@u~QcsP&pW@Y0VP9#9vfA!c7g)hD-_axIQQM;pnx%(0xpV_pn7$!BrQu~$#7 zGkgSD)~~>>1ajFtoE4ys)-uOvnL|oI%M_vUe~8e3Q~$4_Y#YD{lE$BW$3!taKau@1 zTWLZK^d1USK|%u@t~?wnzchHhy_uc`UD$K{#!L4a{e-+0#?WYA-HpqXhkERFuxVJ2_%>P<<3*|^1ms<|DkcM%CphY zZ5YdOpSZ4TEWP#3i>%{g^GIstwXKWs6KRpH%aqq9$8>*mR5K~VzuNLv{*4EI`|af$ggFf_sHIs7^X%CUiZtFp1o=&-;so|B zvJ1vIcF{!(0K%P#S3ZzSt*Dx%M4C6-qQFeR%{*9iMDtoHQT9-tNIBY_GFC@0i+d#zv77TGsfRf=CfQOZyihKN-B-`cArVizNHjcVU zM|sobabJ4l!co^SLK)u78`LgDwV(1_3Or|}=}>=hFMVaLTuND5{8Fp1N6MW)Ez4z| zO^s4MA6$Zly!zz^CAY>IdF!MVvqy^AuhrL49k#i?dof_jKUa2W>-$p#{nwwrw{c(~**g0;NwH+;tVyPKC{*h&7_EHT)P=7hx zxOe5ZeD2#bBqSOi>|-0tHmE(>{!n_pcyI3&Z~9`zcJwU>|MaTZT(e5gYV72-G4I9K zVoE$-Vbo&}e}dn{pA$r`t-j0sSm$u#T2Bi;^}~~sMR$NvDTvv{z(5t0Q$TtH5IV~O;6^TKH#P57t2Yp@Q_ zl!soz{G+-U$r;!A2I+FY(lcnIqreF^Oh`YSE;;)O%QM(`qG_ULwXq!vrK~pevu*u~ zjvSP?jUwT<`D&xXm!z7(rQpCED2v>GS=S6CiHN4~fk_qQSsbn1UvIizPt?WmDF&vb zj*bbtT2>q4$ekCNFhBLbHemh{NogE1K@zH(nuVic&0v{0PjQ_Y-q!IWo@u$P3H|eo4*J|p9PxOMZ z$@{+h(0F*FSi5D$Te5S<#?PhfA{)KK{?=!FI}Iz#bo8nQC8_z7UaCXma-NkqQpi^{)MW3) zrI_p%@*&QS;o#u-G zT6}VoB5=JL%bR{Hk@9d?qeZ(im8`BZZ5plHnsX9^HW%`o76{oD zy8L)3`zMegy`LD=$~HJ5%``_$3fHTx5cWThiP?z4*haNB%LGzY57q}!P`Pm%1mTD> zRb)Df z3YZWC*W;RXWu7l_^W0Ui40J@3j}*%sju;IiQsNT_7(?>5$~UJS zGO~ZpWDb{PjjTwm9)0B!lRB?GXB!*vlP0(+$JGK<`sy9sY!zJDx?KQko;bBzZePw1 zZy)W{0!%a6j_q+&by>U<>L30$X!TbQeBjfaYvv!QQ8CX3+3`031kRuBP(BjoJ8egc z2$5!O%QAdNy2VHrdFB>4uH5EEJ<6-YWOc(SB`Kd3jQ`|yz2r4i5>A3M@UcT^{43{A zpTfoF5=HnoY0zW< zZfJ^!d<=EsJ!XfF)f=?uXb916d2DfTY`lkXY6_we>eTTr(=8_k0Z)gyjP(?B3R-G- zk2aGKlk~4Hhp;=UU}^nv29zL#u0=WL{KV=U-o5-(J(8uHULJ6cfecK-!&e zj1>;`r4-;eTDb-_Vk)sR`1t~HkG}XGc#t<4>PT8-H1H#yu*g27#HV@aCfbe6Q!Ide zmBjmw&yCp z!;HGpOFigE+@t=ly!fu8{Z8A0hkA6c+ceab69!!>4Inn})s(qL6Fu`BB~928sC{Mj zw`5uJD&rG9a&!|)w`z0glrw0oC+Y;O{bj~?1shA{-Kc&+D+D7H1_dga6GZo|>U_R{ zeM<*|2Dj)x5mNU?vI(>eLUcQNpE$3tt>*KF2&QJO#@5W&HQEb^>UIprYT49K9@xs` zctl`@(9U@wbO7I%(;i6yppwz$Ueo79gO|gCwp@*Ujh{8%)DlT*@J<K zB{-!i<7+P#)sHEm);`nO+k?EM<{BUav}P`MTZR%V(=wD5B+ka{ka?3&m`MX)Q>voh z+&Y*Ly2Kxv+V^`ojraUL;rH9XCV!iHb^QY=PK&A0=jf&_^^9Lntoxc_mH4(<0h)UH z*3$t^Yp!yaaQoHwv~geDkar{6D^Mm0F9*fvXC~yu*tn|F?T_YQOgqlksD*~jd`A&g zx%nSmL6IRCNp#*hU`g#SY&(M9HrCSzuPoquO0=Il6>Za=B`y&ae;z4a9kp2SDlnYB zN~hb|+Gt8L*k4}vDo(3Sttn?zTRixPs3VSA0TJ0U@?F6N5j1GISEzfXz#_uZfp(LY z5ciaq)1)~9=B)b)JBlQ0^E}%W&w_{MCHL>V>@eB@clJ{Hm&9eb?2r5je5z!>0LjOt zDVyL`SfUuSs4^PEc0NY6Q4Hwx9P`O}jyi?@7&GoS*lG2`5{*bSrpbsAn`V-^< zRs%QG)Y$ZLjQ0Q=n;)V-xAro5Qh4;;@rZb&o~V59o{|A1H~Uu)m$t*SzTd_#MgeIS zTGkR)6%vd@e>j&s&k%z2s)(Wfru)H6q(H)Ql|Td-4)F^c*85k9NG14at7h3 zIb5HHixKmo9_4d``0P8*iiwC-aQp0D$d)do$=eK5(x)K><o@Uapuh3dK`iFO&(z`3b;c@5fkBrfxp7`*)O*N*&uz2!f(`|pg{wO(6B0GDMX z`i*Ctx{V$@xHx>}|D&tP$Z-UDBnX@`pwVNvzYIsflmC_;bO2*G2;i#LRcGPQR@uzc zxe1Jq^47t4s`sUTfz!^`W%iH6fn(;bjED_~IrNU)+~;Oi#lH^z*6n{i)c?^S{BuB^ zz2+^vFba|#gC6Dw#MR@Q1=yD@hsczxfZUZm5Ndx4@PxV8<2&gPIs6X2Bl6crgCG61 zJO949`0wl>e!yW+3Lt<2b*P;J#NE$*YFmvk?Bh#fn~jDOd8DO%34#g!moYiL@$Ve* ze}37&_WqyO$lvMLEm;J{tj!}OqkPWqYGI-Jv@Dcr-LDitCJ+*P<`O_9?NATI=~X_k zK6?k7Uj45G6Fl1|2z(Bva1_9;RP((~r&DYK;x0 z=&CSv;plm@mq6s`#wFj0o24g5zK)A-@ECAr!;qVD2<`F|vlz>+qrtmiHVHPl;rjQf zCpM!k;LWB@K>pO!WOj051&ey$VY>D9sR6>-eM__yl#>lBl8Tcn=zP_>Op`7f^yyj8 z9dA3PbQy!a^H}T2qmclE(wlm2)XELWyL)`RF~!{K-sD}tpS3cV_$0USe2L81n_4YpVb7}p- zg%%Y0PCdPfQR9;+1YIF-Oqfo?0ge2em-Ob9En#>d8;KfSKw4~-+S{B)fQrU%aFIQT zqlC}XqS(Tu86htR&l2wySeLRtDwFR2+QxJ|ZwnS|4A|}y$%M803cD=zV?+)yWD7hr z4JUl#aeF?{nKCl>oqpt)=t`_aFF)?d_nJZq)zSvAi;(|#av_7abNUvfA|ol?){Fhn zD$KE_xWM5-TRLkv&)O>Gx~D6q_RU2c9}~aV{u4q|Ki0WU{-9%DW4%KUN;8*PEhA^R zo#~zp^X$9jhZkDgEG4EIBJkZ|$N9<2ZBpEPcj4NJMY;&_0=FS}F!9}j!g%PytZt=; z6zeVJ6ibnUMWG&+-D5kZjZC5J__R5Znu9aGe36E+ zJY@M2@gtzD51opNJNEWM%UJ-s&48$vFV24p-el2NQbx4ut}e7zOA=P zW`;?%vt8*Yg-$U(`!Sp;@uBvLWBUB7j)!;2o3U(NVvb~%+D>|T<>(S|#|KLOJ2@*T z)xm{^rmKxZ8FwA`W=U}Cx7jEVt*Gnv(ss?R704$gMVr80Y_Fy|`FtgJZ=th?+iBoI zPK65Xz}<>+&o#x@-Mxx8?*9zfwA~xc8g}v)Og>iAx}qHe@vzs30J^ei>;2?88KH^G zs={Dj<)$I8iyXocDOGlZYG86f##>`6?G`1kcfOO<_WM|i>8wLi6F5z#>%Yp#sX?Vu zv5)5`uRN-Gt)-2LC(=1W0L7S~!&Iqz5k9 z!&sC~AGrU}luT+N-mZ%s zhAIH+!=j@e`xKXIM_CFRQSoYlPvUAN4ATE;5t<$IhX zx>da$9-xCqeDzbk^~a`c&BF>LC?+OXQ%IS`k7gq2-p%z%B8+(G8I;^$_;uoWCReA4 z&6WB^nfZryOV6prr!wRwSIl)9I{QGr-&Lr1Ozh8f<*vnakfXl64Ha8 z7kZFSSf&&rG*t|1Pf`$w;vTl`Uoo$WJm^Y)aCq9hHjEWuKt}QL=wl~`*WwKIZxS%$ z?J~EB-b8oWE?308TNXv|_OQcdm$Ef!Sc;7f&INUQdUKUMbZ0N`)`s&B(s!s^dek<}A5=_) zw|3E}3g&XLu<-quUl8cQx-I(fuyrs#K(Qv?cp~e#6rtHB9v*{ap8hf$JGbSL&@X%8 zUQqjE_8EP5HbJ;=r%T*$>+&JGU%c{lA)(FwjO%Jf)|$tRtLH@|aoU~gq9GlfIEecJ zC4$v-BGu{7Qy+WAg_trjzS3Kl+hzEX%M<~k1|H&n`(qN&c z2GQGUuc)(U@4qsEqs|Y_Kb+a|7ibubtXnpIu3{}{tfXx%$zp~!mQi6B)lawy-Y4v% z+0WH*qWyS!LGD8EQLkiJ!_7v7SLa}NrTWoM?~i;0g0%r8m*8i;bXCi#mTWN9cvKdR zDOpI_^=9y4`~G6%E1>y`!~4AW;MrZ-SsX@kGYhVs%RGuuX_GPuNbz`yM^A}w$&keYWf#_FNV7j5${ zQ^O(u({Oq|)iddi(065kZx&(9J2qKCf#ek#}^-W>hRp zxErnQZ6o#pL^M|MayHz|q*uUrVs)^wGoq@Mc4(V8b=DOph|}ISHQs5tNEI^vjx=(F z|HeD0I~H1Hj;WL&40;Gse|3kprsi}$sQ@t4_&DrFmqJ*2a`oCk(cg7yURclJ2FVe4 zO-y%kmCLS0lr@49bM0aW!(feLf`(??hrvlvd@F1npbsWAhpK6Z6Z+_QR9KfmPy~0g zu&?6q!9HT?5sK~e<3_KW>1p>U7z}M@ zWEeZ_ZCj}b&euT-&oUz2Qhb{54Mv!UPk%AQ46Mh#tPkwzn$CJY@A>n#mqZJQ@8LuS zPwuASR3fC!n=gs&l0N@DqG$Ag-`^a0dAVv2F%PNn3j|yqM6!TfYg`6epb5yHo|s5| zLhXVMBQ_DoYizi?2T=4CRn!|m3x;L#=EGh9bcq0o1)Plh$|N5nz?--|9|oLxHK2=w zz&$x?$n%V-s~q|dYEqi--e#-b?dor&{7<-wOja3IGEPSo29-A7D`|kUkvM9!&&${r zS`Ht5L%ZouWkPiAcW%K7Q0)tl{*m~SPdaLs`-A5=(k3dLZw`=uO9Srwpj^*0ij_&3 zCAuN#Mz0!{W*)Hbz69PBkl&#dP9PUYz;Dzo4+PdftgGBaD&TLvorT&3f(0Dx9RW!} z28Ya{mCv8>0=Uo3e_Weldu(kDa)48*PEGtL8=X4@XYq^lTRQm}3;yK72?+!iXL}b6 zB>(q~=6`C=RrGCN-im2vJ9I8B`DloN$e^CW9TM2RFQzu~(XUI!=X#ZROy&TtQNiCC zoCp8^8Qi}&2_q%C(m}(I4`;vdSQt;QhtOGR!r%PdnST9n-SPP2^EGP#YEdZdJ=t`x zL_5kKTMVR@Vmf=o)ArTaa4941s^hnY-77$UoDfQ=U9NxJLjF$;efcI?_MhZxP9vHP38aWe#&EQpc0r-W}s|Mq;Rw~q24Go*U|aRNA3f&JAV42 zRp@wNmA9+V_p9}izXg(v{sJWRwL=LnVFR>|C4jtI%_f#DhGf&a`T#iUq!Sf zJqUzOu`~dFYKR44T-8#SA?Hd^AYnbDj|xn=xtji>)H96J;b@5I>L)?qtN_xn7xB_Y zWqzZ5!H+nS%XWl4)wrlXh=@8$xPJf6sf@u7v3EUTMzD&~GoM1_*6~ZYH`_m2)EGL&gkT zLvc0zkatbtCL{jDqoL`8w&|VRjW4Iw!V@9y4Jk3d^1rP@38{5VkMSrPz6%}s>VEAL zZspdYfILvKcC2HVl`y$%#W^)M_+VvH6?w}J(TO$>7BDbNKIXH;7`43OS0~>6Hi>_W2ZS#J0QNsk=3JQTrf?rOIAs@I3()Wi79}GFg6Aqyw0@e1x8B9c4>ZE6 zV;ca^vWC2di|o&iK?dZ`k`2b^!PRUrI&o!*CH#h+daHX18cwPAiRg6!yu84Rhk(P< ztwL1!Br`bmA*^^U?;?|Y;YCR;81$k(pFfpC(o$TzGiQO_8YErUXcdPL9Lf`Eot@YVM4i_XGd!(T!}$0mY#^hWspzr z=Zxa>%;U;ak!l%=cm9ta^GF|CZgwXsH9;zEoGP!@NMqzy5D5d3XqY3*vR$H#LxQp4 z`4GBLMcgfOjZ@=1u`kIh-N8I|UEg4%L+;$sy5m?DSh0PMX^}upt4NX>pRRBJbp7|I zITO6L2qA-WCc{GZAg$vX%F8=f z_f=ei?v*{vWTeeYu;mou)bX7yFI14M2)Ge z^*-Su{=GIIPU}@i(Vw5+0mE*Tbf#5Rq=ePoAKp7N>MRX3l*8-p7#3c z71LfxssHAyVC|reh&-KD{Gl58+u_zeg7~F5OS!q?PpP9%^=ySR%HxK$H(kRyg)}1K z=#$s%mLnN|4!0|kh7}bSHMEgZ3@DYJX_GtdZX24s!_+)jH#P^!s)YdT0NGoW4P9UM z)$UORpLmsIA-^ZdWnQk5Y(Tv0R~}`vs0p9di=DL(r2#a$kGY)oUdNLcY;80-i`#FE zo{}CYEct z%fmZ(Co{)>cXdBUs;b@ibF0jW zxr`@&p5^4H49~k>Ry2&BDu3JK=3Y7G0~$zn-c%Xe`1rFMj@l^NcR9=6hCtsZl*(?$curYIWSq4pa9RsuM&4A+c zV#!mbnG?AI%0p(+`}MtRJ3UoGih zIUeJEClN!(dzs!!%Q7%R-htTA_T|Oi2s*D*xtDV^8(hB~ZJ82%v<_!{Sgb_tt>mnv z>c8!05T06^mtcTk>K({cQU7dlwZTK>Cxj(ofyGP8D&7FeJ!7!?Bq_Tbh5$`%YCt5L z$!pMFE}qlg)~^*E?LBT~o7&ql8Gk-DP>i(AtjMq?U1hs5Q5C!5bSm(2agA$fMZVFw zlsW%)#}C7#IHwA~!fcSA{4B&X7rGk&#oyx!z{+ofa4 zrIiZxmZ40IC;6PA8ZlrOg(0Jc+7avR;o$+0P*mrYS!L#JF#8YI>Dpoyp)p}ZcOOi0 z6$s*yfe??RbVBFP9%{s zZO8*xhpd-jyy}6@>@6JYo5%J;KCc${!V~yG{=aQc{)NvE&ahJpw?25(wW#2CB2;5Ik@Bmi9 zaP^mJOEtY}uP8u5y+5rtNfx6Z=W`r79;T#HCHDLm*j-v@49-+!sPt&0W`WGw-Bx6O zPjG=0Vtp2Ueail87iZSFO6WR@GVpOmM`Z=(w`<`lDf!4fO`zD)Q>yWF4jqPEY04df0Jn0cMs8jCeW)) z5*bOBs&VGJM76;}zB*UukpSdV-PO^y?MdAzkBDG4ybP-C5*a?}<`8Y=EKC$=eh;1I z5V6Fgv;J~r^b|?Dt&{%7+U`{CJ_It=Q@u(Vs&7nu8`)2y)a&_W$p0quW!3fpp>y3a9<1%2>2>3gjhq-4` zY+MS!P=MaEgRblv;CFO(h7*D*6Jp;j^c{(EHEP;3R=YIIPKwDSvBKM`lcYDl6FYV$ zXlzT9ptQd<2Usm99l%APRs?}=_p~;37$14rvqsplHj{SSuhertvThZNu;iwwU98Dg zY4i%1#8zK@sFt~ney{@TKz_cY`iQVfF@`QdT45yC{!hjcZ_iMy@k@{|v|rY93uIjm z&yJ8fqYg1!rG_stFK8p;+)YT(&)rY+N`PO(iMKpeb7kkq#(a>j;h zj8t6u0fO4Z*5py0iG;&B>KH+1vdz}tc<+L*o6U;6Sy^MY%2TlIOGgeR_gMjH*~hU{ z=mNRQY{@4mqyH2zo-t#iNF@1jZ^FZN;$duAjSe__i?MB zzisEuxdh?|!6a7uH=dky27tWyLa>R7jaPb7|A6-8va3+w1Q5EgdIfXREq(vRy<=j2 z-b(4L;QBek6JB0oFwYg~#=>1YxRURKY%fNpkrjx@>l-3p$P}PJeaO|-xx0P@pb)`o zurTX#0%ANL`Zoa?IfoWM*!O@slT@IKfm)X`02+!$T<}JDT$cN!EzAb&`f~!PM1~rG zu}bsdl(Xk>C5#&$=MOQUP{gLy2yhsQ0>IOlO`siuA9GjT(p}52OPUj)o;ee6v{-GB zTG(#+A8bF;16+xcIYWjyEgOp&+33(Av5#NQM4f4u-3HmNM9wv8m4e{9jc0)BE9-Aw zX}f7*yB+iYKn(t^F=R>@D}k#3R2h+gI?pIID>lHk-&6bkT|L%a*z}?2*3LpGoth(m zB3~b*PqXlEqVuN#|9^Vo2y`X*voX@g4x$)7hq~?E$7?2k*_*Mq_vHFhSC@cD5`y$p zjfScUkBFRQ_ey=w0*Q_GOAq3yuFp(Ng$HN7_Q2jmlnfe%tcv`dC8YL$;Zpgxrpdp# z)Sah2OS%JaWcH%CQ*Sg-La|>WtbfR}2_ZXA1R0_>p{qoR{yG@}g}9!|;ZtZXu}@8$ zSGvjAoDT5tz&5FZbT8s!^=I z%rTBKhhdwdrYRNS0q5St@4c1~F3`sroc`yDazFlN*=+&8Qz8G8zexYxv6CO5T`&kT zuCZ6str>l6FT71d^%}Pr>j9n^g4u7fZ<7P&D`<5m0H(ptD*h2uhYa-YHYDm~EoY~t# zxnu-SmBFw0pP!eF7d`)S=SE33^({5o=mG!YK3=UTWJ;yAgI^7XxQp537WzYs(%Y`~ z{G-W;5-JSU%b(Is7q9{JkkB^`HJl$HO&gY;353pZLZblMY6yxCOGSXY69CYkTZ9o- zusbrXn0wdH0jh47pSk*BR~v&`$1lICRuIXqYl@x&Tz0t_W4u|X(80(3u(mqp(+uaHPjg^!c=QM!a!Ik)&vUS6eOFIDY@@WRzB9E0oU6W>>2A(13>r?FcVSx@4 zLDIp{(0bx4p-8Zbn|toh`=;O9HQ1&ZesCDA@duT zM9>yagky>tnjN_t1k|k8HK8BDGN1^+69@h@zGjCB5l%eFAXf;vHK9GrZ1Ss^if@w; zLz77x;fj7F^OJ3^yD_~e!HA`0cAqu@F-s3wxPyj-Huu-4#ibdq=0H}J=A#PdPa%3q|#%6SJH~LGcWTd|; z?&1_SG@Mp8pWmK0ZPb@J)?qF1id7`iLH641;M){0FB1Fq2@eb;YJS}J7EtG5yBq6Q zGtf21{Qby%BM07SN9BRx$1DJS|lzgEe-p zL=4Vvw6>J;t|0>S04Qhg+$L$^Tm7=Bnm{P-aW%Y1-WK>Tm-2yBh+TeoRh##+E|7Z; z;5O4@8zp{foS)R+c*EVLUH^OY`#~3x zi4fZS%51{CvI{iZCwO{8&mri%mYPHqOd{l9%76d4cDh1#&4>aNnhhsEDy_;4fF2tSfrT39$69I5K;0yx!!nmR^+7XWn zk+4ooRvEvc**fFEJ!K`?`ATK=s|$^-E&(+x=uo+RS5+Y3{SSBl)FM;RSUxkti$DRe z8<rN(0U1h25&U?hyMC7Cg)uU;AjcqNs zCFRX4$ESH3{MI^VtzJhcUZ)DCZqZ%5N>usw~z#$ z9=IyVeY=0+gB^Tcl`QCAnxt7x)yBp$fTN7xPn@#Pi%%#TKj2y;$-DzVPDr9n|Hl`n z5|VQTx1?0ZI%;!CL9Q3y9-$_c=!t*oeo1>juiXArO)%R#8f_zAuN|Ot*C}pU)JJ-c1orvj>PGm5Jrg=*E@J3wB`QfQSWxPB}Gae>7=c;p3QSVD> zo!BSZXI^^(GZa zCl%_#!=Js8&ze3cMfo;i1<(6Pi^wV!7WlNf%%@lq7wO= z6dHc8o=JxVTiq2bcz;T0LhU)NgVDAuSv#7N5w`SPSvt)t^#Fys&Y1z1)=zWom9`q) zX9*(vA!}XCG1=K&;$`N?%gk^qi;CXN=SL{V>%Rt_;?S|&9dKfEWgAo-cYH~_a(%vK zzR*G6ehqVs@vKOPTjehI(JKegj-J?WyuSRBtOKZ%{^mTqtS@CgEIh^WQw2JIxrxlM zl&{@=S~o&)hI(vYh>qxUU#IGDpZJSMDGvNNw`ywoBoYI(5miVkIL^!}enYTu-Sth= z_M}MvFa${fvY6gZ4p6r8$5waII`YKBHm!i-B9tK z&fpl+otUz@YDm3SCWH6D0MFIRrt=^f@@TVb$FpZF>Zqq{3Z^Z@VU1{Hsj2>vPY_(4 zvKC6Z1f$w{0gqyg&NT^>AyL?4k|>3%%eg$x)35wl=+dLb_HMWD>6FFMuJpCFi(28Q zp;yCkg{J$bPT>!mZ?f(k*fuJi8P%ueGbmJV_b~)~pV3Wix~#1P_w=+9s~9RINA^_5 zia&5GgG@H%B_6Vh?y*U{sQYT8;!RIXZ`7SIeAj94kmTXS$imZ(MMlGf_vGe5@vuEh zYKhX^!8jY%^dh6#iR~z+?I{yFvI^>X&L;U`QWe8G&bVdV`rFM6GPjI7+rpR9#ik|P z?8{tf1X?%OMn(^r1HsyCp^_)|5e}lWGvFjiIHFy$@3T|f(d>HUWAgEsw&nlD-Ft^M z)ottI_*qa9QIIAjD!nVcM@702=@Lo=qzg#ziIrZYOBX2-5JE3fB3*j#J@n8LY9Jxr z^?m!?d(U(Be(rOBzkBvQ=iEQY!^)ajYt1>w9Ba%m#`})IjV6R7h<3=6gFPNQuf?H5 zQndlUf9<<^`#Gtsh_BAfAonZWfRB4zYzpsSvYz>aoH$&`q5vI$J=a<@ISFERlg}@D z$s}}b-8V}4R~P8nBWwPSQ!1gJ66VHB%!x(@`dJD&b%){DoT_-J7FY=K>w(Wx?ejMU zg@xtI&E$$V4#U^S*Rs6owB4KKwaKs!n#(eryjtvH{nV?}ej=+2a0vpMR!a|Gcoz*7 z0xSyPox*WIO1TO|al?uG2=5YGZw#hn6M%~fPb}GnKqu1hp)X5;cv)1k0suaR!;zPd~+MQ@4xh^rD%NONVi zhe~8K_OeO{bkI-^_HO9bSDOyGM%zuMgQk5<%V=A0+dP*J5*!i}jJYNQ#D~4S)a!C) zQ?&fK(;ca!GHq>LE=UfTJS=T-ak<@g;VNZU$Qz1+YzhkLw!mCjk9@sIejS|%U3Jb_ z^;fY_&csk5+KH3NKKHnMooeo#X>X^7X&1xk(Z<{#Wsm>9Hp2N|WWn`n+4lrGNV}^Q-#s^$MV-+%3X454aknj5Lop|qLD3W#@rjtABlqpjI7YRWRhf- zY;WZ(X_Wb?Xag+u6~40p8_O3d^haFk_3V+oE(?>pS@=su-qv3?dM)z|BX>|Q-XeX- z8=5{j8D6t{Z?Ev=UE!}e^*Bp3;V#s7eYZkB7^*Xopzq}g6u+Gx8eRL*Nn4A{MH0>B z6=+Tj=(zb3`PuNEig6I;)|pz<>G+0dwb%;OD_BYVHTgHew;c`i~~B~r#f zH~!^Jfx?~I?5?72PV%tPbnTu`7wTrXbG&61Bj=P~XOV7ea?umv-3UO1-7r6K>`uq z44*N*5!l>g(#cKG%Y95LbvGPW?dKkANFC0GXlAdA{%U99Rmqq-BlWHM7^m9VSW+~v zgkDvk%=MQV>i7cKSQ-!igpt#~p1I5ttE%m9n5R2tcsF$iE)g-BW6$X6esArAf*TOc zKRKk&QM{=og^2m(;Pv&12f|4~7y8^UCcgaK(}`ZxO>1-zp7$@4745m#zUmXequwX5;xWIF+)J=+ zrpocLYDszZ3BK3=q$+(2`$=O!Y}aAMdds1Pr3!em1JE2{KUQ-Fv3sDjPvD4rQm=1^KCHeoZYPZDK>*}yG%etY zH)oY?touT9!_M1}c|1Vm8=FAu6mMO1?EJQ$=Y-+?S*2CqPhGd-V{VqXhG}Zbna}^$+Z=znOIxn*U5P~GA~qDRmY&tds~`BvEO{Q@*y>G8(VQApdfpatY`G?unr1x^Ep-? z+^&}>!UDvN>5@4i)vgK+kwujU`+;A1SZrTsnWYkD-&`zv?pb_g>x?S1SwF57N(RzQ z!vj%gN79OS1|G3y%sVY@m^w)wRL`LoSlzT5Xo=&bb7Wa^)DcM?+8pOzKmfQvhXn3rh2wf?LP_Byf}T?yokKBu-fX+(~za0MaFdD1qc* z-U?FVA^Fi?Z2*rA8-g54MgxE+27rF3Gad?u`TeH2^S3sDEq)z1^#p)b06yPvU^ltk zB?J~}Kz#a_W`GMk7&!G6fdahh%3pp{>{&BpCe5LL{jC+ESqV5X2p$Jq!(RswC!*ny z?p@gO-!1&ATe%8Su;tU+C zY(N}+z%wt~CLMiC-*P1GOy?&_eB5)Qo-X^I52IP;@zh&eEyQE}3)rckhqJzM(dNm& zww1JU$#!m9sLeV#^xqAm?q7rOp4Pm5mDFL@IMI<}HR2$O)r}E#8?B4`5Lb-)!I8XZ4h6r<5O6)nZ(QYR}|*Z!UYx|J${azf3L;0sj7L zuI_){z^j6m8W3i2Eyc*6ep@iS{Gdkp<|&=P&Ek!hd~IvY8#VY?v53`t?zmc4EfrN; zo{;)St7<^R)8~C64`r+DRd0pHY4vs>Y*@hc*C+Eo(vOCJ>A$~y{{L5T|GYr}l=weU zsRzLCjgx-$lLUTK+yH7_>2-v7Fu2sq1y*O~*?*gyKUC5wM`I%(G>)gIb}5$86r253 zmrll8Wp7XuCn2DXw8NZ)anda=Mj@Tjf9iAoKQlA`qLEeU76TDxkedMzfdvIGm{{AX zyBZ^GAmIx~%k9fkll4vOmpSePE!EIVc<;ikwRq4;dH@sq-@UxG{(1#-|37Ov{GTkV zNFhr75!B(P-EO@^{<>>ho|!BpFn^=E^L4xCqf)~uU)CEk-4qSwKoMeP<8pwLT&tlQ zeG{>)_owy04gO7`ZRm-80iH|BK_4Uqj|x6D(e-dFM_7`<_?Xv#ZT&=bax> zpmhZfgBnIrhsU6de6vZA6S*a(0)C0`F3&aryl9P%H>K`EPyA51qzWs7JGEDn2eN-t znE!?CcW-f$XPqLu05v$4y-BQ&M0OIK(2FZS@;oa9+XRZWDc&Wd5^wtq8{rwU76Avr z1`>+jx-DFN7U{_oB5racR${g<@|%yldaa{cR-$TE3RXEvi6RV=_R}y|+YPB_FS7re zLTtK-VJLPT!FJo0bZeY^m9BWx5Y9I6o8nb}l=&UJWYIU_1f&n_Vf3T%dV_-5zE#eO z>Y<_o@46IUwy?__p*c2kkJrKu;V7l=^k|eAjid0|vF&e)3%Aa~8hPMt;F8?pkN85B z8eDZ7BJwu{ohLXNE`n3QD-{NSwIGlo@pK;55lOi_4O(F3vJ9-mZwftEe{mkyU{`!; z!lHS@V%Z>@_?JaCZ^hxW8jN}XBX03&Bps@?(k}fvvk8&Wko7u=t}PIJF=ziOV7F$v z0Oi+17hFY%xnMkE`#T|{xf^WjUH^IJ+dbxUH{+St96S^p4?@~1b`BNqs?UwdhHQ29 z#8xh^u79$MThaY;^AlYbI~wX1uG4VHO+DL^RUoLn@)@Ri)Y6~Y#Ns~Oy%D|n>}z86 zNRp6@9|Oa$!X(Dn@P^u0UHa<$jreuSTn2w+zI~Ubdl=p`w>mhl3cr#RTnV8iq^haa zD|V;{p7ubUbA6qwqY@X@5-jCx_No$_C5P%$x+<)+C%!dxeLeP=Pt<~qO`mcgudNx^ zpD)PLHcG5>SC;dGIi{~o$meqrB@ViUG3995Au;!CdJ3-A1-Owag?kI9XTGG?== z&C@+j%^P8cQ%81R+yYv4L9PHy(vQ71FX?gZ>=Dq&@aKgGEx!EF`<;`_^B`A}2SKPnK=YZN~jmVXk`Gbxp><*77|WS^WVlL)>y&nP99SQOZg zTaIHKyb?j+8G;&DU99NEpFv_v8lN@r5XOEY?ZX)B}#_nY=665 zTNY%ux4+$3lE^fnyX}n)u!Za^0@*l9*52{ocU~ZSt`A{$1j4JNf=a2#4I@C+9xg-! z9LZ(+p3`r!+|LQ&YqFQLu`etY&2U|W#IYp6kx`WETY7VAOYcy}Y<}}=UTvwbiel>a zAslgb@6{TR?zJL=D7PxvhaK)Gob`fxbTFB8Fd9Of51kGbi4nRzFq|cG;eE-6qxH3E z@l0A*VTpO(Uk-Z*iQKueSLYY&k*LKHcCC1e^zv(6jAW>eI|4rcCNLVKaPpf%ZLA)= zNC;gKpBAZ}9@kCGPNJRif`8<%+_ut24>q%`UE%?|O}&rU|BWlzpCDu>e$ ze^Urx+|#PV#GbZSU$$l*efre;QYn1w)~Kw8VTI{NTP1(yKK4qdz`g<$ru?pTg-QOF z*p|&7w{FKC$yd8&96Jbgk?yKQb)AVM7N9bW{ff7$S=s@ixZEWRyn3cIIL z5E4oZ8GqC8NN*Qr72HL7Zx!*1pKUExA8Tj7iVKZK8!5QpuY`cC)W0uqS-A_d3!+P6~Y~ zse&C!9z7Gvam(Dj|4@|j)gh{+WiaNsiCcyQFeR zoLCpq*p(8QD*s01VcLxuR_lna*T!Qv7sdGR7b>5n#ORvmOJwgG!fhr@`+D&XhC(GFOQJj0V@NyYa!Ys*{_am%L`$C?bHilT+Ywgi_JnS zS8{Z!>X4HPGv;dEH+!mYF5IG1AsCVh#c^o1Pa3|}!O|OxjxeZbrUdhe|FL>;SiqpY zNs27U_uW#DqCL$wR~y=N9|TxLa2Pw!osVAqm_9oLt=;l-Y1e`&*E)%HK7fpfsIT@yi@yPdhTZzsGR6ymZH^~l9-;O^mWEm<;I4$ z@^JwbYYGH(s;(747?zUH8* zI&-{tovAnfwGH@g$MBIsf%aF^K79E{iC&*M{IPjqX*SBIzpYWA?d9!M zROZuzSqj_ty47)c9oX%Qeh&^RlQ(#ZW{f^<=dWP3*0{pCgjYA;p3Ti&W1Q};8IsrX zUr4QM0AVOY7e^EKwSr*-han99M5z$EwhcnL zS`ttS_Al(dU!n(splaPzqrJZ&Jv%`h4u=DcgatVl*_6^Tje^p!%a!GCw1q;1W zRc#_9x~ThtleXq*Yie~g-JR~5=(LGB|bCSij$c+p8`)oEQOM@Y|u;4@5z){$_`R_Bs`%{ePr2z5A@i#G>vw>?v1D6i^~^Yx;{^(`K#W^zvlG?AO`2# z;UbeT(;1RvedRm*R~6`64tfsdDiiO_t-9uOP4cRG@5gFP&Huvw zR1bvT+V-{wYYNTJyCfe-OY{8M{*7Y7mUn9H&^l+42ge4#6yD72=U+BqTR((hi zsIA^A>~t%b9zyp%U0TXd&o$vxGF!rVGf{oMfylmNU?_3FFJ(^D{`80d5=?-inZ4`7m( zJ8P=}hdgZv2FEHWJbz(Zs_Bz`QsS%q7EDt?Xa3X-XPL72^~9a9NV;~sywkp5jC3bc zM~gnjwBsg|;ZNPXFJlGBid8Mil)*ydycEB@XgZ=1odKVP#jOldpHainaDks+#>Yh= z$n&uZUX?dKyPbJYD8 zK=i5<+;$%QRo`Fii%$2_w;*c-SX^Nb+T;1h76seI4;|vt>k8Z=RY62wWmNL^>ruOw zkk@g6w%z+Fu8`#^0L?b_!*pycDG}c(YChHGef!~6<=fr2YgnT57Nq+j-Sa_Kk1M4u zdF9&e)lDj5W2-wesEr?gG#)5G@m4c7Zd3qqa0WblS|rWt=Eq03RhUZ7bHNCn;*LbVadMxwGT?UD%L@P@W|95 zgnhQ;x`MJTkce2(g5{4yKBnphVkrEpGI6cA`jVP%nghA51dex!Jk%h2~#P z3S1yWKaSSX58sr9c2C6y0$$hPg34qOtrg2r0MB-uc^{p|Af$Uw#(}GA65HG9`kO-Q z3iA=?c#88*ZkFg?LEytL11t5O**ADHQaclk#ck^WPwOb zwZB_2%FwK;wsU(-RekIV6UXN_R`2ZdRfIG&HmhI9I*F%8_kkvCe=>ruH;RyyaYrBV zyGK5RLfrmC0?mR8#kwD&*@VRrLO-MRWuB0piypOr+;lLyskMe3FQ1z;qjb{UH?>!q zuB^{@osIZb@JQ+kpNv%T)U*?$OTv$t_5{h)QHhs8^1;$32hzvUd=wP`DO5#HeL>d+ z9cl7b6x!)x_*m6`Q`lZFz4ty2eOG^_ZakgmJEm0s z7cM7rCV)Y-=#K?J`|(swYGn=#*P;S6?L#SsiXL&St)*Ozb+Mk_ll{9+ymR^wdf>l% zlK&6GxpL?d`kR6}v$gShjN)A%zU&C>;xddD>J;r6@xu9R4V0vi-{DeU(;&2Y!lwFn z(yR7gaDJtC*+|+1N2y>o3&Q(_&d-iNIATDdLdFS3=EKZUQU?^Yt`l@q#d6~MbmfNR zVz1Z$J;IBZp8&aR$35(c>>zQDAz3qzuqJi2veh19e_>{2n1=DBvN^)DavmzVX5q&sFe!UH(Cq@XE;vvmvVo|D)9c z?QK5}b?)u;sOi6(>wK~QOq%O|QxR~$S~4EsqC@2$xi~G(-||72)m9A^I}6_#Jhbz? zvJla2_jdMKETijro`{t7FAb|Cw4TEQ2j{a$NC9p@aG*rDlPU?8 zwX}-f6DlGzz-_Q&Rph6QP9yET6aweFiSM#%PD*1h`Qu^VyClQ5;C?wPa)9f$hX^}j zw!4Q@ZI#on6_ZEMUdzz?b^G~JAdBWr{J8yt&Ub!WE*hlqNJbK`4&q=Jkm;CXR>|R} zzFl*dL6A!#21Q&dX#Yg;`|$Nprntv&s<9r`^|EE#usLhdK25lR2B%`T<`_y zq-Sa$Ti#uvbWd9iIwHh-A9ZjaQfDQfwsew0DNK)z%&G`(N-S*cP1F~bbIy}_RdJ(8M+I3 z57|_S6t1wGZ@XRrvOmg9*c^=8)>@(1#o~!z^@umx6bea99jIF~R^9$sUa6jOB?CbV z!J4`nB4W-yU~p}_A1tEPIC1!WNPYfW-t6{3S)!|8WZ9}`9ff@P6(#L12unOZTASCk zG0B@%LW_psS#})#Xpi^#ORH)tAiEcV?mwkBI+%*?rH(CYXsdn>cu+U;G(!jn4)OG# z?q~3!F_9d`mTPd<;e})1=9_9GoWGi^SQP3?Sk+ykFg35sQ{0=!64ofuKHbmJ?fnCX z4-WF-yDULr`UORagJ~Y|2r87`h;BPu|B++i=O`~zUv0Lu!;|vChRq`3;N9GCgM$13YqLwX#vh4YOAUzL1u%stnB_EQ(b7C zz}X_tEEQYCCGgBlPgPN@MPx_pL?7Jw%WJobEOx2HCiO#Th@ewFDsk1qHd^c#t>ru$ z*}3MZ7hvVG{)p0`mo{cW*XOK~40?HI395!g z&qt18H1^Us7*HailatuMW4hP7*Oz@$b3^l?_tV!dH$RA%F-=*CNP$rea?i#=EAxRe zU{*eRq@a-i3;Ud`lg7@)Z85?0*SD=!YPScY#~QP&SskMy_pf1?5Ic)@Dw|}?m@}k* z)(FZ@c@#`-VOHWBP;fH#Z5t@qsBA*MUWL6=MTpF!bvmS`X}gcSD{&c7UU})XX5z}R zJqv147e~HpU3~C>>6M3^!H1GVC$g-w{`9`%2-4&OzQ`YH@Oo&Mahu~_&5vKgQ zX&Lj4;T0UCT{?#9ho#SciJnGJ4fJft3K&bK+0v6QO}pe4SMm%8@F^T_L64(^oeo*n z8~p=$@5^2fWs;kq?^K?jDR^-6oQ^r|k%Rhr}}zaQbC(#U=NU_<2im16brJ)qQs zj?gBgXsgJ^Hmon-qGY(+$4fY!2d_0hHM;HX;we=IomTGlN<&C^Shm5PbuhI1~;Y;Q9OQ7(MMux>?t_XYC z(Uki8@$*yu`9`s1dZEL$gjm%8X5h`K*~Wt7dXJ<>S?jXi z!5-@evocp(k-arF@#o$Bg(*b4RGEJ^e>>56UD&REEcz<-+@}>>x7&Kl<$GK{5d7mCo>{&Ac4yFw zma?uo$STdj7n=5d0Mt~I0(6OdncNDiPTIbS%RWM$<)UAKSjqhe zDxpKi-O1>q!(l-WSlE0yGBVFsNL+vXK)r$*)M}V0n=qGUQ>`;2eni)lZAxWa(w|}4 zA<*p}rb(Uh>?71jdsstbqfi3gm@aOsLdO=-y^MX~&_!J+#V~%jGKsBJ%yN16n}QZl z3DF-j>A?0P(TK|V?MFlt?EF=Mj*uUny%=(PteoD`Ho+8TmSz3-TL0hB~Gu zd#Yx=Z^NvQ6h#}X+{Oy4V`rvg0k`fP-r4+cxE$gUV7p{#P9d1(LGp@A&YVJeR2@Uk z)ce_K!F@H1(&Zy~c4EC?8KSVwBF)tFmhStA3fC2=@$9^o^R)bNXghx)+qTK~lz`r9 z&avKxgX)anDr`!1NAwg6`6>vXdgO^S+E&G9E{JSpEznFTE%LO7o6#&PLuCD;YY+@?5dh}2pqIXt=aD;q7Q=;ufCJVI* zvw`^YN1-?u621FRG)@aKd3=N-WG=GN7~{QzD?~#55N}CJ78nTKhSyl)sZIWOAH>t~ zN`T?rd`=oAEVPwjcV#Ym^M{VxQKW+_pPbvgQVC%g$Aj_ynK|80zPxW$NFD{VqwQ&e zrlPl9ml|X-(?`)ifb{QrZ@^Ym!XesK6d;;o9=!sPq%FoOCwQEFHJ_m2FsG2Sg-Wbs zmjs8vsK&T`z)k`{RxzKurHAC5k~<{zbk9$V9p%=XCCd9+Ek=jaO$YcBMgiWXpZH7? z9de6SP7@@_6Rvyu^*G`Yn-B)%UrqN7AqH}~;x1KkMV!w4YW zoAX-vBR7B8Bq2MwKAy#on>%NEvW7akUa*;5ic*OR88zVOWj|v5y3iMVtOD*c1#3CK}Q{aFdv3Njgflrbs~wq7*z zUqUoRvUC7+bE}E0c2mNo;zBOprzc!&-EBmiihFClZ1$k?rJJUnU$S(&^9MDILJtEi z9sUO^*?%wgMVUr=7H1ILGUm1cXBm^%D0RFdS$O?j=`8j~U_p!G=I8H|2|HDFDtSy| z!c1j_+fxCGcb^Bp4R0At(A1LQo$Pv0ejIP2ZRmAuwQF2GurFqyvly4F)jelawPC#J z{A0s9A2Vf>k93rDowxUPot@IyW{Tm6ogEwu>tu~lE97*JxLT%G(DmrT)sw3Rb{M{b z3NFumL&t20{ zb|xhdUB>(C4*kL!m3fA$Hh60Od7bW&+dDJ16=vA@Y;|6+voX_|_msj3lw>(gj8oWl zt@UQ*hFev8Gp{y|oQkb%h9j6e3O4tB%3Hi|n@TBik7TNkwUIN0(+i=MTfHwzny&4> zjt~k+beHAnt&7#BT&rAPecfu1AN_TSSvxxdbt#wK1``{R7Wb@jC-!7LAl>14fv2tf z6T!4xThD?zfM$x|&=&Qv_5BeD2sZPjW7iNN>MuLSHwsM7JGVOT2 z7uBZ>33vz6C|lx&TI;!FkU9btm9DV44VJCA(W8Mzz<3zHTT4xG>l|m`rbghyJXI?) zy)IgyG%jq-F>8UH8|Q=Tt1Whvl)8A}!ie22PM2;e^$1jX9`A5Zit>_Nb)@sVPglE+ z6_l<8DB31|XTMj>9gp^gnvP8;<|ZlBl%VF)D5Gp<&Sa$9ywAAnLX5$W>Fd3k+1l&o5;+ z=AfuKIqW=p=q+RA(@F``lWby7!&Kz?>^#MSMM!We6U{0 zB>c+e*&vo-XhP%aibg-n6ZegljQ9c_WC&n?Dl#J(H#h-qmrK&4%lWr)L#_^*4n9S-Dq1KqN!jbQ_7_^jEyJNtuCI?IFll zW(zl&m+4XL9)5 zj*#&uqfb)ck!&F;TqfT<>w?hF+eYL}m5-j)9W89{Q(SXJH~1O|b?r{3LKfi>SWe$3 zv6kvTY41}!U7-0)9OuaA-1a7Oavlk7Kxme}#a__isa40^K7N^yK z))!ylt(XP!7|~ym{s1U>QjuiqO@|IKV50tyyAgY6GJOAoh8NS{x|9MaJ?=dzn zUyCD+O0EyzC(;j|EtRrL6w`q9phIp>`-(voNItE+Q|9@9n*hJ?FA4DG{~!T=kUXUb z{*f63zq{`hQtq^3JT@0f{I$90n(9?Qxo9i&R;WZ6eR@XvW*+?pcXI_7S2#RB9u6-qZ~DFIC#i3 z?iylhJfnhFvl3NbseQJwsyKG;Gdrsn>}}7T>?mYU+_1;kcsX=)yfGL~!yMY&=pa_^ ze{zaM8mhY!VeoNDVtS*X$#>;9dLk{`=OYfZ@6XU3Bv})* z$1k-VN;Gea7Q?LMu{9U}rU-_EDCj0EhYHW2os1+v;5w0HOY(eA^&07(Y4B0wS+Npt zDyE_FB|=ClKw;o!ng0u@E|9-k#)a2G5N@G+z*YN~D)Ircy$(_cN*;!%#CX+OpaS&q z@N7)F`Pik3!7(4FiXu5Rm5G-OiC&$o55$9{dtxsN6Y1P<6j0{B?=F!EFunhJ1rliD zGFsOl>m^UJ5u*=xHdyO*i9Hc&2$ao;K~7Ay52$j+rY1i8wF};DKgVNFa%>P{M_%I! z>?>w*R1(ywC_BsTJB-N%+bw}T4p{vSYH})PLb|k41}BYU@9w`O8e2%E@d$aSYBxOS zcxtG@=NPD}=n`Wu_`RoHJjKETT^}>F5FSL`(Gw`0rL1CzeQFZ6$3^5ywo$W*alR*$ zqL!!V@7zCMbeE+tkB3L7PYGIn+a^ET(VPuewwY3SRAjp-a?3%I@iDc())05B{nLeN z+KvltFMTE=1WK9joQr(9Bt4pY-CpwRyt&EznpJW9S+2|w$|#XfrVaeD6K-UNIA3BS zAmwG^`!e*aqCRHMD*5szTH$Qdlb)^EeP7-Aog53_70JDNyP}n+B~KsAnA&=y(PLj^ zawkd>CG|KI>ia&u{2tTv;JGP^(v#Zcp|jDb!xd}md(0Lo%9Se_ym|K~0l)JwvPeAE za9!A5YL&|NWZbM@sJ!*QjqI}#!_I{0hwK7s&jAL>pOW_*hgXyO-zbO(87VwH! zmdZ4`QqGpazM$tWE>i3-{U)#TS%^XP@^h?rG>1%JX7S(W6Z#6Kbrh-abLkjn%iG?; z0sgl>IVOflDt(0s4TkFmv)wYr3J#;rKprT)zE!FZ#%l z!zm%bf5+;U)2|aQ#5cnH4S}WmGaM25ADskLB)HhDuhPaw+BbQ|+gEQe@(i4^Ga!Qs zGX|o#$Bp9YCP%{R^#ZFMiJffP=@%o5(=D9xZk)c7)ZxxpEMINbfy!Lz;A)|?noW-k z)V>}>L-j5@sC($S&*KM3r`lUaLiK5{NXJ;8&nY$ERk(9sS)Wzp%X( z)I$J)-i z@vD*Jo}Qk^thOz7LRL8EIQg4jGKjr3Bf`G+F5K#?;XN^-eUHCUcrYtWh6lic#lI=N zzb_s3x>BRmlfTEpN=Ks`p3wcs~bSJcy1=kqX^byz_khhga^!xy)~7O}Bk@>#A<>gC_BGI*I5)v@rDZLI*Rc8AY zutPr!c^F;(1Xj8mwj(crE9f}#!AX5kWak<~=656Q{0u6$&!&Nl$J^hlkp?3o&YT~& zof2p7JmFWzB&LOM1Ur*@b{nsfdon9T-e!mYM6-dN98pu*M}F@Yi}P{CyNfPSzbR}) zt`X!gl+ogK+w%63E$wir@&?LU6`J@`n~S zM1QIP6L_jasMz{GJ7dQ}Ss3${E%TxSz~er<|eeCEm80 zDx-Z)<|`^91=N`%2>}gr;A)H|1+b)vqRc_0znl#XE1JW&$0NFG1Ru2WB z;_$>nlc_nGrG5gBZF7HEBg0vl$F?2@(JCj9IkkI~hO6EVT|lw>NNJVeb|V4*IHQl! zL!5Q+M^7+~sm6YbzfkV(`y!FlZC8~tRey!@b`>)KN+3rAjTf+3>D9JZSAVs{dO#(kS)tBU)ok>dFs)V11dpDz7x_ zPtBjAu^QRBihH&Kj9Xkdf7n@iqd2)QrN14`=HuVmD0)^^Z%lL|fG~*(7TG>hnCPE0 zA&g`hb{X7iR@NiIBnEH$Z1Zz2Kh~WZt7AQ5rR#fWQh&NesfVRM<-S*Mhq2ez$LbYI zKX%Y5Th(zJqk}eUdYmfI*wVN7=F+n&^XulTxavhLGHXaC95_#@zZ$KO+r0*FM$^k1 z6CcC7L6x9wMxw3bJZpeIkfpnmWU4mobZ_;@~$Wn(@^6@f;)yW63$>s7}~)S+sEdw z1vvW3O1^h2FoVs{=15h^Mjr*XZSC4vT%=dS@YTr(sV6Yc4f=r`){g*Z656W&9r`kv z#z#(N!~=DKq=55Ez_~0W0r$H)RUJz5#e|3}$jX^e3usn!b^CfQH?7W?^>yCzO~hb* zvT3;74Zh{%ntzYCV4I#qGzHQcxjac7SnhEbSLo&0Nnsw&@SU5uKyib934_|FkBBt0({h{mR^k(4e~Gm27t7cJE$e4 zL@vKJFBi&7Wvi3O8Eg}Odvj%fZ)W^_>R7986OvfzF+HYnb(?Pwp&$6X#!iE1f;>nf$v<^BOelJCHfAn&S&T6@fe+Y5f-o_Xv+UMN)5XNO|HQ-rn>MVC9$zo1` zO)oaZ9%fQ?q@ymmd|0MlWf9W)ta@m8#}Xi>pz|cG^n}zHI7Gye|E{V7%3WP2T)A>0s@O#I5Og z8K5_26$>lFc_~@`>UwGXLv^n4W{KP8L*|L3=;D_K>YU0ix?)8Oqmxblc*udhkGOp% zliM@oJ(_9hW7{@Q*Oa@NNmDQ9E)@A)k;BY#Ls&#uKG`~>3lMUDyIW~uT`p`@5v4a@ z%f{@nLZX5|bnlx+>{XDJ-p*5Pk2ve9dv-UlKE}PCS1Wky{Ac=iG&+6j%A-k_Pa}*% zeBb^#Tjx5ljlAO(4N3-suOz65)S`iZ^qY>DPwCJ)NqKv*Xue&|GwG(TESX-SWCQjY zxUas#91?BTpQq#}axWX^E$>oZpme6SUShdiybS4!<&ERTKL2>d&tqrqmy7yX@|`AeRcH zCu~ZKLQ)d=R7Qq~d@c+>jO*sN?G7rF>Y6=Ec11jR+eh!6ohfo3d1EW8MN|WK-N)y5 zQV7{tH9LwgS2%W|df1EJ=1cfOe=$CLfee2<`03ao{zbB}U~= zpkoS;mYVvJDr|-8(Jw<0C$RXkZC`f_Ee=Agtb z+xqd3$jGJUX18isfF8qM9NG>bIw?MJ=7{2{ zjlo9Ctb1xQP0t$61h7RcI|0^tvy(Pds_D&-==ym~dHd$w{Lbw-e3>4KKk5mjX5>-);H`JLt*Z$GO&W}dp`4^AEB;uiK_?euD; zbv)4>C^Ym)G~>CI!y}J8faENVsl&I}3)oJmw>A^L&KM1xVn`gMQ5P`#QRO-!uncJ2GCti_q)7dcLsBs@djTZ!N1KKZ2=PFLe!N#3^+0iTba95AaX@(ANeSYA)xBmmeQ_I)kBh%=fYh4OpmiKou3$>;VseO$ z!iqYMatD0mDq4?yC~t;OUl8*tDv$Obrn?mZXA^BDe^Y!3{qsgs(!dYTL|RDiw*Z&_ffPv_07SI` zaV4_x;8}SpV&KW2ciLt}kjP1kC#E)J)s5&@h5ycfOldzBOi5nvMhPwV)@B38evfjZ z2>L|^1}e`!`2wX^qyPYqG)wTP16I-_1+H|qKfd^TnA1!IQ0G4gtV6CB80HDQb(<(- zBJhiB5g--(2l7(2g?Vy}l!8P3xP&T(tsfEEu*3)V0nPoK!jWuIpdAFf^of4lOZ4Jz z!AT$j55_(;P23a+A#o@`H@{;ALL2yk8N&_LjW&&+U75Qw=RCaIYiu+trU^6U7^*T~ z(0<;+nln}jyhhRN?`5zC|MR?`{`cnmgU$K3RA$B+*P@k?Iv~46XW7~mdIC!D6ChM5 zO=nLEvWG+1m#cfllP&TEEAJW{yW3PnLMJ3n;LOlK_!FBysQ2JsRG0Sut-AeNuIRtQ z=lOC?%-s@-O9gI)90?HxC+&oK>}aH$o`M47nkUPAI@7i`%e;uovd`1(<b*Gb2%e>&Ltnrt?K(>QW3?Y-YEg5P%241G;1&;g-Ww(olk|Kg9!FxQ@nMALzYrz3?Xar6rkZ_Uq9U>V-|4 z>{4m?ABARZ|9duc|49V%&+hz9R%TpkBxaks$r(B25eK_3Qu~?3CRKb)M*D1T)BxI@ zZhrxvX<3j_KrL9yL}3l09YU_b6m*k9lwd!`{=Qj>?q8af;Qv9hl0ni>5?JZFk1+mB zOkR*^b&UA;+NYgrHY?xYBt=Gh{BL$J-*S0p$oZ$-IZ~hBO+s_xRyFpPie?3l6zNwZS|5RMX3^EHQax+*te3ao$gw^8 zA(=MclEP68=gq}$fwFlqQZ5gEsAa_qJB{;>TUFWh9k0Ij_PnourCq4NL{;JbsNu{Q z@qWGQhWD;t6X=|Au=g*rpewb?AMI%$cfSR|ayRXGm%yVNJxOzcBp^$0#0Hc=={~si zo5hwFwLyWCv2^`K)~f&Lrj`oU<2B7MvRYDT8+gA(l%xlr1D}3HkJM3l0@SvlG^8f* zxy(L$((Px@CayGa1t_Q|leW%z-xA%0Pp?^o;d+-6nA}2@M8z=xQ?cD zOt0?4;R=<_%TToMB^6t@RRK|cxlP-dH878>)+|e8ljEmuCT79i2M!FY-`r&il9aQr zXlWGCxr}U#47wYS>}{o~*vu{KYdH}fXH$wZNlUMd#?Mx!AUMj(zA8TZOd>g5s_lM0 zM;;ll*@((7*NH!@lCi0+3}4}QnHMq?l=CJRDv50vXon*tS(__TitKV=O45~Y6m5}( z1=i^G#$EloK|88q!($yW<9*?1pSEvbhEnaza^%0mrKP%?ozryt!H{g$K51ubkwtW# z`1sz^r>4uMR%)xv+{!)u#=WyM6=9lQ!PTyJqn{6oUcCS2d31BBVV9+|Sena0RY_KN zXJ1rar|T8vuL}=YV~~v9*BIaeB3jm3VX-PEy`sM5J2GP!{*9_c)=Uf)^;AViD2Zt; zeD2h5)sD$xbn}yEqE0SxF>Yh`p# z^l8Ks7DfBRxKP+jYxTI=_mi+P1v}Hm4^iC_8rOACdPvS~x?KCY^_%{Nwt^Wa8uJ^= zhpBoop*|5OvcCDsOR*cbKd9>Y4{&v|_0p7QO``m0$0nk~59t=Nm$*Mb0tDUk3YFcP z+cnIBYXao^)yE=Y4eUnWd3GPnYEGfb+wfz7#f7i*IDq=B&kaJrefYB@#X)Zfe?*bh zOsHEpaGuzVPv(#9^auMeL8N-{L;((1&NLIajAMK7ccs$DG?-k+Ht}-nU^o7=(av_1 zN?gXQq7{IuhpD>OD9Yo?+W4`MEAr=uOS=j@;5~z=-lj=UN9rdB(!q*{Ga^=5d#Qt7 zNAPRkqEIxr1v#{9cnjLhL;$N95CS2p8vtD2LL1(7uqZ{2z6D&DuR+a0`NYH^A)_v1 zdhF1gbva9SChhJGvaXl!*SKx(XV6X>w;qf=sJg4Spb;g2E%e+RjaeNmqEttnzo#V8 zC7TSir`~~$$Esy33v1`rs_~1Qh-{^GB`da!bE?w+B2)Sni-cdZIW*uC1|N6$Gs+m& z?+miIkiC_l!zWX64|c7a(?&-%jTHride^utdg<=Ih|*oR2eOi>A~UZbAY~b}UiPIT z{_3p6*amA-Q3KKyYUMNc;%xDcPD5$&t3R0}`Xz`w8Jp~zPOnk)5dxSP&S_ETC1d}H z?dIdqy4-7K)$g6IXxs)j>+7SZQ}1s=DH@9w2}aOMSTN#!5%|O}7S>(F6YOTKCL67@ z<_n?C#TLBizqhVj$F`Hqz?VTBO>NjceB*t~cVPD~na|%5(HkX&cp1gF^B=-CWgijm zk;l7OO=mg=DonIYy`W$?Ephgo&mJhWCtpoe^XKoYILCvyISqg)=G~iK4s3_=6h6>+ z_~_2tBk-n?0&n;zjDniq4|GNGW$PEF~rRWpcG$YL#W}KC_mD;}T<#-$9W! zGY}iOix5fFEz=k==~of8nLYw|3XH{0o{Ru=*0fI_j>YLZz$QLES=3*AxNiCyJpC;~ zB}KAp)7kcP01+yG7PH4syHK#7`DgXH}GMA&TdW)Ig$5rUZcp zev9VZL-re8?2Gmy!`1>4{nZ<8;x%^F*#_41N%kV)Hfn}JI$GURhEs~W3iBlsy*DHB zyIXQmV-7#VSj|2lLt8{;Wc9ce^J6$smTPIeyGsxYKlh;Y&_>hcfFchaBxjmOpMWb; z(IPF=Ksp)zkzI;2J&(Y;X6cM1&s`Dz?k+o>h4l89Shf)(x?UM0&vL~lb8s(w{th{Z zHHiUx2iR|7EV-;uQnYs0t5jSR(W#Fm!!OAwKIZm@IOQAjWL3biI#pR-o!bRl{RzVM z<*Kw=rW0|YS=Lv6PID|JUD;_MBfqcf*huEO!ux?K)?EL6CHS&33gVZ{Njd@`p0ov2 z5gi!tG;bdWlN@ytU3t9OQ2Y77j}A}ap8x66er`D*Rr(EP=o_J=fv+3ZWCM=ielDq}@KNW~z?JhUl9>6f z4vvQ?&3jm*3-$(jHo^F(pXt;>z>^itbD6+>-ZFtSS} zoasE@k8mmF*`}3mEp}cg%~7$1?t0w!i4aMdzo(Lxu>YZEv9zkA%$KU)$yz@EmcVyH zr<2AZ9-PU@V=D)>Wt{Hqoh5Lu($z|VCbpGI8wjHJk zQkPL3smXCLi0oS(Nf))MR^}01tybpd;?3QK#+r=D%s2ai@D!Vmuq$=G^G8HcXPi9- z)sCVuBFYjRv5&2NarQ)kSK|_;Q&JCii=nWNqMYMW>#d?1WurpOUE5j)tg*EkS+t4iMyVD z3AmdbGiUHrtxBZJ9w!)Ri@-UL!?sb95TYr{hn)F%Mci@4KrYyUKN}zytI|q4xpV&_ z{n0Mhr#Mq3R9>TF{D^}K?pxxutodF~sW`hGr;UU9dMZv9X+)!`qfnRNjog6(4mrrH z-tMD26qd|ib$sG&;@zhAB~c;A;+q_EApcofx!Z~-j|c`^+l^^d`)N#*uu5>*QY>;} zwksQU$k0VzH{svHQ~UTvWEA;zNtEXKb}h%x-4gQtDyfd)Q%O}KQCqdi`o&biPDB*# zXCV36R-?5n%|pr6#lUMLX>YccBo?y)cJIueIICpVu_j1!v+R{P z=c$|C^_H!V`&GhtX`T7Rblo*>zkHA-epFzu z)%X{!gW3gZI=Y9R)w%^0Y260^9E+MT+XSMN5i+@~vRde3MNcD;r9*+i_-E+QpJbInZn4Kna6v=$O|c`m0q+g@yU|7KNc1Bgmz*YmcAUI<+iK zhIs_uLbOOpJU>^>CC;tvQxeZ-X8t;5Ok`nDSFKBR=0LdDQ6fwlsqkUZ$+qhCCY>$c zaaTq0sM_>3_zQehNO9p(K)?FeA%SVdaZ!)Go4$|dAwKVo@5Boxzt#FMj<`KHmZmB7 z9eE+ITQE(@Nq+oTx*%EOyP(sD5SZK=&-(TctnFCq_1QH8WDrr^6>HP`SX%GZu1kS0 zbN};*5l-W;hRw?4cVf!JM?wU$J!O7&$0DIOjfZ2ZH4e2j)EfpOLJn))M~c7fA}KZcyijxZ`koOb@eJyZ?}j5J7q9_|Q#UJ-+89(o&HgFY#*Yin(H4+cwe6Tq z06#3L47geF06q|r2j`J(sVg|?2%utDtk?9W);m6Odt_1`C-9(fSiocGeTbT@I z({%0*2X0m+gitx#ZUX;tM)XItYeUeJ)p%Ub4%fnJ+kb@$?{QO(esX|zS^-Jz7E zI47QP7_4(?o}JiXb{<8)B%kGo&U3Ao0g#Ue2FBMtNF_cvkLard9`%vxU&_ucH^{SZP>{`qm2Ey7Ay3X3WY<@qb08MSYOm47wTPBuF&CMS@ z`H?JsV=3}`o>_@Uuo_L2Q}`yst*mP8*lNSUX++u{l#Wn^y-<?55!>7m%pdogjx%pPNZ!=R%Kf`33}`+mVC1b5}^%|LeNI30Lxk1$IMPx}yt z#G#UE9~W?!=LgExlQXJ9=J7hi)^JtLcDlsWh06>dQ*AyKJm%SliB;!;mk_%eb~BC; z-OQ>Sv#J@{K>PNFoUwYt!CT-L*UA zsdo#DP;5l3<9yVCZk6_ta0b2xaI!%~aiHC+=0I4mA@Fz%bpS%QVK5Hc(LI z^TN$r4GJgO9oUC{)}&59sw#r*$uo~33_xObK_rEt)r698KBKs3ej0pGg16rkrf5;U zyQ`BTBa9<;xo-0G?)7*^wdf4{*QZ~7nwPNbODIm(10-oa{NH%mkXmy zqV<{u;-~av0z|ZX!k9!1; zfS_nJz(D_wR0E__zGwqIP|>7^e|+)EFEV|Ar$G)3RMq_ej~S%x0k0ANMb=3{6t!$a zAD<%vZRwls4S{%VJ$OI90rZQE3r>8C9#cmD`N_aPJ}Iyt2i*lCy<7n1mEzxU2B395 z^l}FYNDfX=9ItDV-s%2HV1U*I6cVa_kv&ZFhZ0oR;l!%UQ}cKt5bp(GS|<;Gkr`XV ze*g<<1Y~&|gd0f%Zr>}kxB{RJM!h`{Q{IFBjdVflMUdn3P{K{1BNHXC4c6PCrr2?G zsT`fT9Zeun(`(rhw9lC5qdbTn0XD!L5LSqhjR<=Be@=!r76;u_#T!gEPl(XKz?Z`u zi-sUQVobka{?E9r${X8dPv0Om{XAIASdK>{v5Ff@qoAtEU7)>(<2+A9^5VXBcEcoqd}@C4 zhi_~Y{#P4E^MAAH{7-6W80EN5^GJM`XE*&5}ngc%(?fltHtHU`s}v{K|j`9*1yzISJLQqHASShk^rpoAD7-X#SYg1yl` zc%QK_o>r_l_fPgUJ!IY>90r_bzfU0rAcy&PrWnBM{q@{N{TH#Y{{d9W7;o!mzk%?7 ziuw-5CXZcswoH1zm)(kr1ujIuP5~!ly3o8qGU_z;4QUei17v_IFpUAwmpQ6)M*Pby zdh-1rH}0Q<;@++896f$Ucd$j8Hkx-_CYSq=?Uxyd?f%*_6w=axK}`6@M;=##z`3~c zq>PF%XzOvC=dC~@knM*8b_56P|3!Z2FS7U%^zpPI>0Kt^;DJd`Cr|vKyBPQ!ga}a8 zj6NC!j{s#D`VBCAaQ#$fh{M)I5s}=#jli~LWonVZu50HLI1Kgf8 z!Xs;7CJmXVc7S{GZ~$=HfIr^_P3{2yzx;cY1rV;Xfgj!vd=wDk?Fu*vs!poX0sIu8 zJZcW|i!73A^9bJW|63qH|4u_FJsP-1Vvr=T)X=mU85xoqQ zJ~XBs0i?%&FWX^w(Fl5l8T@(B|6LgQmt}97OE}u=K*C~IE!;ip)S2ia*?PYT}ra6E`$VE&?p#Q;Urv0tl z(fry|c=_3nTYQ@`vW~9S4Io_aL9k0{MQn;L>g<5V;sZeGz|VCE70c;#eaMGyc*kp2rN1+2?QcED;`HEVyF$k zrji`*2n)Szd>%ozJ^ih80Vl}n1=KmL6+Z|)82m|Gtm57QIs3KoUMH}1D4fl{iM{!N z5@@fZv{!r{=zA6dhGxuHmHi@{%<}EOBHuxw0f3!=R&Y6GjhvJ(%j%5#LC3+F z;f{c_1O$m@yTZ4CeZn_)+7DZPp!JI^#pGaTa(fmsoYc@U0li4#BaqLhwb)bm7!nMz zDo}a?MMol^*I_`#q>bkWE0*apTZ^-$l%g}t-JVCq*450NMOQ3dY_~~9UFAk(u@k_# z&cv^-G;MS=doW_-I5&Gn-m%KIqxBB;l$;Ki;>b11&Bk@;t0s+*@4V0>@WD!&che5}8BHI^~nh-DvQYCs9(wqdwo7z1&ip*xJt~O3ra+p(>u? ziF~gxr_0?x*;6mhPVIH}Qa(N~d|z`IJmS)Y7#}ecxS*z>mAv0#$sVzvuWoOAsV=U* zD>LwU_4E}OqYXS}(~Rl%{xbN%2BhfvB2Z*)=gfdJqM|1F*;B1Z@oy#MLRFE3^%vLg zrxocNKC!$rv}NYo(jOuDC^%C(=}o4^g?Xc)W$knxK~-^>T%MugvgMDNq-;K!)4~ZD z*ZDd_`xz6}BF#y)WeAIb@#xao+jmZf--^e4yCo#iS+tc{qdmQ4BzH0pd<=6Im}qXl;WTc~t@Yjui8{g}TnnL9(w{{K~0ukHOw2q6{I}9J}tROQHeY ze7dZYDo8?r5=ss8-jaiOMVO<0k$pXWOGhk7o_tsLB)wJr&}pMLUm_xeZf`MZoVOOz zb6Au1Lmx^spSr2b>31N0etU46$IWkTy zX>_UM*0vszVsm@Km|lZFYpsMhNKP46v3Cg(KL|uX)a5yMsra z0yGpE(bN-HB*`tmZBbjCx0bk;r0DNqri&(+V-3?NJTeyKKIHWu^jv)v^8|Jy{`wo$ zM`RMu?!V@}HDwm+oxzTkQ~|Y17(QtCaBKywaZzh6^{mUi;ec61M^~|V%PUO?tDeO2 zb8J07m6mOKtF&C2yep+S{?V`98n?K!Xa-g9G(wTQ>ycaZ%d(E-GVE40x>gyYsjHs`TP6e{0qu3-mcfKEgv|4hhPBz9! zR58aa&ZNk1KRUKLM&`$-$6I_O=9CqENQow7jES(FseJ~7H=j;LdCsBexI$c1sv8FK9$DUak6l@>Dd-~a?)oPA z><7OOnqgtb)2nTM-FYy{o(2q;P+p&`*>}7efM*r z4ijm4_Wii{Hi~zHn2Pv*(gmRk8qHjcH|bye;W5JBb8*Y(L{jQ}y~ddXs!mzhsaHsp z_BJKZQEDY1a_txu4z#}>O4p7{+i~~BVs{`@~WGp|N8di=ttBSaa+i_ zQ{?{Tr>99kyxXI0F$zjhH{n0Jd%8|Vh&0)8Y$R`h(2Yc6aqF^815R}*240FYaOO>K zpMJLBuOo}i<1t0%`(6|E47kPF<6Su?d`FuhB&-(@=6lkOAAVd)`G!8KI9{T{Fp=>% z%!Kua$lbV!ls&2Vki9Op_ucw$vffP$-1pguZWr98M(4r{Y10Eyx)Loaq!vrb|rn+`hf*UhGECume=Fg__0~}>IbvB;a2U*BFQoN#d_l%mQ2$*MK`4z zq#KVRABnE>m+dcdwaf;aP!AFH?eUlT8)x_`Ps@C~3#W~YJuVv{TE-Mko-;(ACRlt+ zu?P#!ZtmEVl?T5IcM<&|bwx_G;$^=mmSyn+akCy#w-2wb*>M0o-)1|ZX&BytiA?cL`Qbo!(L z>Y23(!hlF;05Z2wmszSj`uWR5+bETI7@5GgvFs;7PBL!yMI3e$V-})}N-7pMDw77c z4fz?;*Wgz8`-)LK)p3`E^}KZR!1mipnuvOSSV5J=zPr8Z_&)kz^y5~~1vKUa@wxaF z{(MYA$Dk3wP`{tTQ#HzWOu*v$F?kHT&?Uo&rO`J>;&Imj@_v5hndc<(iCv9WfzJ4MW)Xlxd_t%?nUUT76)m*Nr;@|A`i(mCyRFnDP7-sKUIkrOrWY+__ zOjI1TvxBxVD?^oFkRZtEX=oT94W3?&$BBo+%O=+N zrPXXOu!E0-ugC5Nf3J12?d@w1Vp;U*(@kGBtcw?Psh+>MJBe9VF_{{z`i|b%fO2e9 z*E;i)*5Ob#vqsiS4fa%1O7okyY%3-a)NAh4`kXbQ^d&>t)%?gtJN};v?GiyuCW?=p zcx&%xuj^EVD+^_2y>aw?$0 z%ARucv|&d%n*&`HhphQZT+wM>hy7a0WchFSz848rJ>e~Jg9|qDc~wqr_BRMWq}SF~ z7=BR@<#6Ewg!3)qd^+*oSt)=79NO@03(P!vZLM)+@AXsHbFPe%*yIc(tBzSA(+2*q-iChpe>#p=0~@rM^>x6RB6mE10!y8L>3m+Gz<`OX%5ssLpo zgsG9_ecxSDnW2869(lZ>F|blr@Q6Q87e&96Oe`B3NG zFY>=8ad)jtMfsXbny8&_mMW%yo?o}{7@xP{m9(Y9wevn}7F(suNtE5pYcckD@qVlw zh~j)qYLRNKB(X%z0NKb^w`2cMJ^r>{|H^ch#{*gVzsN?W+Or#P3+^pAX=5+BIP+A) zzb0uNX(l>UEYe9kRdc@?ne|1a#=$O{E`M~Ht$jUVJqA;;L6(`w0}VWMs)veR17kQh z)f@()a=uoJ^=*v?g9m70oS8S-2HS)(-(MR|*@t^sKwd!&AbxbjSFZR<2$p>D{iVV zM_bzdb9ixFjno3@aZCE$hHY@q*YQf#;3hLoM@J`B*u8GbZsE|?dtF=%14m-MChB3W zFP)hg>!c53qI{EIADPqFLDsdRHS7hBtlR0$A%8NLmL#{42Ew96&4EhYs!k@fQ#kdLltUkLWoUIBHvy%JLv$}Ui+G?&Q@$Lrue6foSsfs`1_~SPS2W{s8v>0ernB8GLO@_ zqfSSckP>w13_JcI=pw1bPm-WstmknsCQk@=#b2IhXbpFRPVi#E!J?3WR1ShBDB=xK zQCM$<85!_q|C@$)|Fxg16DBF?KTRf-9M1$Q`X?Iinjhn1*5r$=CN57auTD(POdGoU z`v2V44uEgI*+-U`e_LvI|m(#Rld6P6RL~DgHIi@v+pnk z=v|*~cQ(1^RK4@&wa!+oHY%AN0hYCvq?fFEoeP9FhnzOx+)&)uFEWasXTSP9oOs9! zWcz)Lsn|$R-lGUfb3g6vmhE^Th6?8_)Vbbs*s}!$Hi2yP*z85{a$qYJkqtPL7rN0K z-xYUTwt@UBsq6y~^TeMZ|7SY>u$k%zgC_?(F#`NZ2=SN4d@U(}Fzfsw5c&i%u{PTu zK|q^B3K9)~BHA$rjekZg2Lh!aM`Xu+R3v!EKOWRSPRCFU?1Mg{{@*?I*Qxzmj0r9i z1oczZ1G7A{p9})R&xmR8Z-@e_fg0XV6$BzEwgCD27`TNgI2Gg#h=zP!0t^JSK{bEM zO+$SEr!*Br4aOmW$Wrt@()U)ljNIXGS&cftcS&FuV9{rvp>2MVeZcAk2V%+2YJ+#U zTD^eUGh}zLxofrYGF1bV_%=JF$*FeqPlGQLMNf=;*eZXN|1|&5L3(XEC)R(lRd=br z#__{Jzancz0~=qfa$R=+E!$COH@e2f)KNk{D1KX4Et;f#+Tu)NKEY5BafEk(h4KLt z698-Xm)T#D`}f<e8+6a7|y zZ!eGn@Wp)~dH6g8@(Xex((}v{VHzUtWcIiI>o);WLc;0L?+yNY`6(V)upMCz0p!X* zA-sE&eq+#!I=ec~6bJx|2xWnnGw&5be^GH0uMn;&>VfK5&RgWhHTRY8URcZTj? zGh+ZY^Di<@|HZbu8*m0~P#>LPQEe=&a#QwvpDmjO?=@S~M~Q>q>^&ij#*}uiuTM)SjJb%VBuw!yG9a1Qw6paTMEwA`Jbq7M$op-_nd82D(V7i1-n3OKfqP{;A0vY zz=?;;fPcfz(3YTOC}8dH+V_B#fa-FJ0}}A=$6Vpy?Pb7A0I-o|h+R|%kR-mQ_lr!3 z2=DyED`b=5DSlvLkWX%si>W|r9-RvM4Z~#Z1NWgp zq^FW*#2#QGw@I_Z0GjbB9(hUxTs{CSx^m!1as`Iox$`d-!eaR?Z%t<4wkF0(fe+on z(|^{dH$Gz^K*%Xq59rIkpmv6l{Z-)Yg-bDJUFZ8M;l0HElWd8OIJuqi!!2S2^6%G> z_vaa~@B9~%;=fjvWP1+0hqtzUobx&yF}-j_ZCutMe|zz<*(2@~fGsY~qCVx&6)fc6 zcruP{Kz+=}3@dAG6 zfm4n&%^(u(J~UBOGZWqbPkBzdOW*lxm^4O`=?uoL8w%Ywi%{|8FnaymFXO1Em(vnslAMmFlFd?_UO+K#91&y@)^CutV55MqD0hTgF%ydQm9qd4UNq+B&lb^(-d zi6p>g+dET+N&CP|(c0x>n+}91$C~?tNeuY@)?Q7M(^MDK1anLCXq?~OLH4isn1lF< z%2bgaD5VJ>>)qN>{@&IDu?ek1Zo8$K295CKDXH?~$>WBOfgZD!v#A0g)=BJTzaJz9 z0Kh_xCi@7&^@q>(a@cF?GmqDUX&_;8BM1FoZ^>Mh-e6Vyxr4Sk0b+GgWu=RghTF#! zX-^u#bIDaw9l?H-Hqh%>e0%u3eIS%hj+2ntk#?m*mFmD_2yW>Oq8*v#Puhm9-tNjZD$#wP8`0l+oo%~*kySlB>f_Szkg}HkEwNHLj-j;Ya@u*% zz@Dt2%k__Lk&C14Z1&poCL`bY2!%%NNC}=MFr838(}$jaxO98^p}_i-v%2jY?M3r$ zBi+H)v{#dMZsD`;H1xNs;NED1fcY}cAwo~&EglV9?b|$oPRX_i*+#zw%S7wxvx12u zx2JQ|mVUC|G{q>r2=cyFwE1JCt!bqTR-|t&DUuZRYMhLI-qijqdxvk}H-PPfqkE>s zsLPniUyXmgC7b$hmxj&@3P*R|l;-!%- zo(Z&X=^XTjVe*^n#8pMdCo{Kz-dmpt5EO#OLx)#@*7p;krSZ_oL!j-XF|6Me`8Lwz zOuNP!xxE9jI6*F^@18Dx;a%0>nwXGyg1o}c7(>%|UU+Qq?P0?i^3~@V zhdm!390l>5n=EVOUVmr+y+|<_D>p@dYr$@!AR!d)Zh44q2A(Aof~g}X>F)B)-%)?k z-H~@j*4HnFqV9Ak9oLSw#Q0iw=#`2ov1g5UmL*&*%oFeS0m#qgEp%)%*(}v67MDGJ zuk`a31hhiqmAosR>O=>RjSJeK^$|oAli?Wz(jXS)?LB)nJEzDx$`%|sIBPW{h>v=N z2_3R|GXtuPJ`ubw;?1l7NqqeJ<3jz`ubrQwI?ht2e7gl_o|pOXULyW&ncA&Pb*%#E z)W>Sny-_4=D9zgX>duIchHi>@QPHvea@;B!y2psrxK$|#!wwo+7y z49!FKw`bUs$)pmm*Ot<{=}M$1wjaCz{9lU|Y89;No2c7WLrrnroSN_Zc|O#?KqU2a zhfxnIjy6aO&cC?;VmeKT)QFR2K`&0%WJwXEA(eGyBbvR?LwQMn4uUa`07x{g7E4d0JSFOd;44~EJJtMmNA z7;rOWJOjW3PH?qDSv~sJb%%g!N054gk8F;W0Y_pNmT^HoM90zb)@JhakU;mIDQ*_R z3>~JAzZr7A?Z&O=GW_>;DzlmDX~R%C@fwCo2J6#`e#WUw$+AJmGn$%lP6Nn%nDknj z*2a*kXi=5r(iRFYa4>>sVU@u*0?EmDeyxXcS5G5k;7A`CLXYd*ECt~M_7>8=PBD)Y z=#3lbN^6-jH4U9DvoVm(FkChDY#49?Du6#lwWqepfiUs`O|RCQD`2nKk;=~TXpgow zNr`dQohtf?+UfPYE?uebmQY%gD1UGvCz286ZVcstU!AQt&#+hJLlnX-w}a4C?6cS9 zm_1PQiU>bykI6Z3yZvT=fZWAW9I6F=!-oUU5g7JHV@E}CSOiWDt2D?`w;R}(z~ANR z{PHY8LD7!r$8bL{UW?Qn7VA+YdEh02ve9>zm@Pt?h4?GrX^#71woo=EW20j=^(dQt zu(AwyQB@GY18rTJ*+%HqgyE2I zea?J&TjsCP{?7`g$JOpn)HBz5r!G0ickq5+o12?_4{NKRVn^K^=eNzA)S9l4C0CNh zc*M}d%Wbt;qKvMbSyLjpZl%83wGV2LB*eGMNkXoY`n|v(8w4jjK=Pxavtcxx1&&CA z!ni82IC{BT1FriDLqmq1@CpmD!}Az&RYA3b1}C-8W+gwb6yI3B8Qy1QY*2HH1a`6x(}h2)tiN6}|8JLKWK6^_#Q%F7L+1BIgI;jbr)E@RUW za`*g(Nz{Y)>tu1r`D?-HR3B-qnca|cDbUs)j`VuGZqUB(S$$RXgg^yFWo4jx9DC|B zmjJ!7PV;ZIgc+Id4l^^UFDi;4gouGbol=Boa!TA9P@C80?c@+x@*Pho=58KxXdZi^ zrYB=SnA8iuG1X2%Ea(UzF|%IY7;=+hS`1`rWrWyWdHOqJg&IktW=|A zIO}u$80r z5g(QD#sf_-Z&VE};!=W!m}PCWD+UDwus=5K_!8HwqMlt?aCrDAxCe&`_F|yq(tVL0p{-thk@(D3IS%}-fKaZ0B2kqTcLUsZka+|zts^-4hCpuD zC4t0_*UCy=qT6^bs)f%!QN_Gef$GWG3fH4;yOm=l+gbYMGmNjVR>xi%&$%qz?Nq44 zF&r*2Z&5_Yn5R>qR=9byGIlz4asc#ZO-eR)F_skTnhl#+4%|Z4_pbCg`D{^!2Vv>jhesg_K$y6j+h%W!?LnxGU!xz z?ra@dt11boj886jg4R$Mwd2dO-(~hLE2IFZjz)+iA#l$ArzIwf*?0`$$K-PcHzl<> zJZd0p;v@Ps^hC|j!*4*wp-`t#MUm+mfx=2sbZyQ#;`Vo=^q5hUiMkTnlDkJ?BgtLG zxwThF?Q+*V<1<}2K8E1E)v z_xuLw;^4x-9*|*LOBJt9dFrR-SkYAJO(W2)r(nC&a*68aVnVU6KXBv=PY8vT2)B+8 z$E3(_0X=jV>T8*F;I=-BU+07O@O^i6i;ao^IwVliXxF^c%`?o9XDWWn=nI zBaSlTHOKnws)ReuoIBsTB#DSeP|=`dhffFJP)^duIkBW|0!66$$;DmWLtXa_DXI%A z3=>tY{BoqVJ}5!4ju%s~p2r^hMBiksCagrSg`67`USFtNM&0<QnpIPjP0me<7vp;sm^&M7@k62P_b6>vKJXjWG1}IzBm|W z#-tcKJ%N;+w|6@c@RUU;6hkG=Fu_^aFHx%cd-0+pDbbVOsTJQ+>-!+i(5GI_|4(Dt zuAKLyOvQG{kcrVzhU)6-6yi7j%y5-1wkmV&bJ3fc8V=c%S_K@8S(CQo>=m|ErOKNP z!9wYj!%;|8an3;{-pa{RCHFUTdsM+DEMs<n* z50R>3DL)t+*zm03m~g=gV~f@Fpl<#m+b>Y5Uu2po4U6^V#wH5H7?zT=--LbE?|0%L z556z=T+YpkU6zzhSG%m=XMEknUL~d4&k#Tcs!)CiU$m(zH>0b|I#4(9-l&j-Q>-w* z9o|o4@ks3At5d~ts5}$d2!^&KzG0&u^$yf$^chU8o+nE<@5us=HC+sAb-eEhiM|=6 zEa*RUaD%Pz-mInA>2axHUl;6_m$Q)tYsw{kIbB}N>d9c@(8P$BvOS8204okP>G+cD z1bNbhZAfYBaPH91_<3~LR;9y`$}`rR95>iy>B$80;8Xy8-qJjpP-)4yNLz<#L6WBUe1 z@YX0FtkcHa`ycGRby$?`x;Ko80*Z=sj0#AD(mg5y0>Vf)BO+Y_0z-}ph*BdhIS(yT zl0%Pl2?#^i(A_Z%O!(cdz1LdLTE{;28~fe+-QV$j`~%!^-B+Afobmge+y2Y3rh8O& z3~DUzr{!^|n0G5>{HEQlzbMKmHq3njV1qyI{Y*bV@*lay5@NKL@iJ{ze0%|Uu1(~R z>7;@$&LE>(FVk2Ksvtz)9;juccatH&X6^|-{0K4)MvvH=o&au!9L_ZSt8O6U3EL8U z(V&9j{dqP%%KckGs}D<9-(?~xmxNCPOc3Nx2*^jk9LdZei#@=>k%zs#Pmw4XaBAle z2!8H2?m&N>WTKvq!6 z@oUE?lRo1K-j!!QAE)#mwrL6Hjv9VT+uW)-Nh4hJzl~3tg@&0JV)kdlS+3n}zS?AUffp{3VqXKPL_2)KTEuyuN zR*G8tw&AgBxhYzq=-^%!vx*7UrGbbjLOU19;y_~nI=!qer8POrly)4`L01{^(|&Ip zKm!GP>$nP5qizJBTk0c?EmrxIr1$Fj81M;^;vuBlsca8Y=7>$)@F@WDgV6!M`>^9w zrJAwk}DU`e+Ko{2>AIDFO&x}aKGK#U=v3ECvn>j1eooWf2nEjpsUmSG)HpEOIRYJ zN_GDiMYbk+*x4k~)tRSDI1OaI`1-}SBXT*|-CP#Dgow`gbH|nat>%{he%C$286i%N zMTi#w1A0Jh4;k)+-W3+v%NiRds|8?5U;evw-G7Go{HYJ3&l^@LdSXvKqwhRv4;*I( z{0MyHVZD6AXYZaRS|IAg(`Z!7^R_i?anJ+s9r)iRK|=AbqWqNfUn@-i$vyI4AQb{# zelJ}FfkmdULk!-t_#8Bi@U0#!+FY?yOasA{jGndn@uTY!#|a{J`+|QG(l37#a_j$J z$p1%cKJ;CkYzWDrjB8AVK7W zdl4Wvk^!$(nL~(;s$_|n9E*vEq<&%qJ&khW_U|k+FzsA9fb zj*{en!%wzq%?5Ng881Z+b-e(ev&{kgl*)1t6reD7uAyUz;2+>QiCtIH)fp-vSg2nE z@U(^rDPn_wE%yIocW=*_qeTv6;IuGQvt|iVDcawBj>mA1BdP51o&oZXqP$pU{zUVO ztCwyqWSnOi)LVCdG~lO*I7uqdSqj%cFZZFyH+HDtKgZ{wM1ChQehX5bPeg3P7j3(Q zfle0Q%_Ch&rw2MY7w|hr4Q#H%Ie{UkiK|VF18`?-TZGrmir1nS!5@9h5Ycp-513se^Jo9q^QNGg(?^h&4^Vq{wv2E$|Wy3#qppZ{%sm}s!BLSO8 zXB7%>d@`BepZ6gq3;Y!p4#0{OJ9Y7QjB{%6oPJn~<7}Cz%WO8P*-`@MYlqBkz zL_=FctA;#X`?~f(^jiZ1o$vYQuRXaH1Z4}jy$b{E(01gGd8=%AbM63bbI>d|-Vcxj zib<8gOOXoxUfAm)B{<3RVRj?P!o z>KPJBRh^w(Z?w3&o`1pg{P7v>>#9^=Db75g0Dfo;tU>hTDOVPlz}!kQC7@p1&}R<= zf_%n)!yqR2O3G%FzAV$10LN&c6{|=IKyTZQLjwv@RVThc3keCa3g)tS`i5CD*D~UW z710nF2`lRV=%7|}*A?K6F9>&!W)f97iU^2@JckrXN#~pO78Kk5{K?4T_^pzf?vbzB zw}8+0n%cLMmUAuoPMy(5B>%8y@x|e8Q)?yUFdfhxMXTsf0cjuBzXqrt<-I;yy((&m zBuWdlr-+^Cdbr^&Uu~bFWSuf{lJ0~(sh$)!N_w;Q7CTWXb7K9Cx=2!4N|eiy|CP>@Ulf7&Q~etb zCW&EZ2TiDiUoS%|#odJ3Uk!+!ac9k)@*T*X>$*kIO1)`T=*9}@fe9K+1g*^g;6`AE zJu#SIkopn#VIeZl4Jj=BHVN@c^@U7Eoj^$T;l&z^B~@h<&8=2`rg?ClaU|V#;(EX&`7Q-QLy!GEIM(60;Z;~@ z`l})RFC%X41FJ=HkIF1!7Gu|o`&XG>q=M{31CQd9w0rr(0$ zhYIYGSEC3fMYqa)%pl=0%e&{V`%_#CONg{Z{=x<`YV%~P#0EZ_o17L3Y3gwLdh8CU z{|AAs3GN7U3u+g#4f?vKLA)^#cr~#TH$k!^Zl2+Hzj|r$deg->@_7$x$u0Qkc_!nIw5?A^Lzi*{O``Z?)_NWFG)8AIgz!>a zQasP+-6&egsIot%`OqRE(B(fy@k#5$r}lfc0t@EGhX`8p3T_~TK!@`QCPwUIx>`G1 z2iCo#{++Cx>bk(Pbc>_=^^Y}e|XO*z^4SoModzTYBkAOH+C!9Om6~RDzD$m0# z>Y*>Eyh`SN=HosEIYR@xse7H!_ z=F5ClEqHD!^F1U;eQ1H6k1J7r@HkJvU$c9A`_#_ErY6#9lwFtI80~|)iEUvx)TsIh zt*f&+q+|8bu_m8;e-0nFtGZ-Svy%4g`FHx;@o%gxe+G4mQ&dp=t8otabyLE0X|N*A zRNr0FKH0o4Q*D*zni@Z_S#)RZ6+5{IGttod2SDD(@kjxldgY!&sph$*ur{4$p%q?W z+Ml%#%xkw`9txCRKW@BLj@R~^^ApF5i#zMKDqh;V02my%E*HZPN)>w?Syu4EYN70w zi^zPFCToRiZ}Ly5g zraHI43Pj}u3gUZqRdMg}mAiiPu1!}&a31)cTz~1k<1j%Y;~e75mtmq@p=zPMl}7bo zW&c%$O}kN?>pcu2p?CQ!cvM|97~tC}_s;e&@U$X>YgO{D4=A$3Xj{qRmC5s1!_nvFkXETX@j?aWHEdSJJGG0a zvzMu*5PsiF|5;J0)X%}-JcIl1>HxF@$xEKiMc~T2W(ZwGatLqkR7#neXC1MSbd?nc z__MKB0(+s9;w3liRvrxlAc+g6Z6u^Pt!=&rU6*)*VRC%A7?T8RoxRZZPSLUS`|b7l zd)wFU6X75CZmy)h;Me}La@AfO>$SbL6i`40Mn-+CGrc*_02C_63_^wg^*y-45raiKzA@q7>#lG^`rH?O9;UVU- z6M!yo)t-?%3vzmr+${5ivM11IrDVT&lmR7CUl#~nzQ7*1e~+Uf-?S*$2Z~S>CyL@7 zg#XxsgdcvXob)VbAYUHL<+z0pD(uOZ-?LAcfQN3Ou+y3_97^M?^7RA7F1eS2I-;jA z8sxnnwoI1xl4(cd0w!CiO!f7xiumD~FZ&)eJAyqWH2V5m3X>20hPf6e!Xl+-+}-W7 zV@3w6dP~w8necucX!;7|P5h(@ev+UH<1Qf!z#3Z~?G`flO1-lh6n9hz+`n?=VoJUp zZNN3jvp)fy=f1a$(^0UocM8J*O!lT_DrGgUF5LNav+feOEI?jG$&6d zueyfUS$sM*eUxmo zRX16;?fcn6)p&^c&!B&0e`YM5e`o#SgkA3#)_M0g=ysnrdS z>6kgY2YQRq4|+T*e+HgAj#ax_c_mJ2*Npopa!NQtoM52CX=s4BU6WZPD;-8l{V_LB z>$u$6(WV4efpa#s_4X*Z-?i}hh24CXMGk+(NlYA@tG#KGBCJ;;vno;3#baUiI2`jC zz#{^dNtsvoq^4jDKrHN|-Cmy^t}d4HW?+Xun-2v4epbEPUUcvjLN*2T$F~b}V1({= z;1Ifkl2nNa1oZ+jA7ftGciZ^vP;8wh_D2%(Lm&hlp+E+o3n(Xzu* z79ef39}LqkgzH1Dt|{_h>P2$aB>M}DNbi#Q2=e~iIQ4x1DTLXA|_Ua;)v1u!2O85MIhb%^D=mKZ?B+JFe~Y6W(Ck>!}$ z+=?oac^wI=G*G!EN8mBU2<}vTKig(6c!slbqVCyb{H<0!iks~!6zBeE3vjVaupV!` zYV2aKB4GzE8~Iq2>TJu<_#?}fBZcE4Eo;Pg!_%3oSs@l1MMvJI;-`55SaYpwCb0hR zZ{g)82OTrlKUfijm)!t5+1yYNo2h1md3zR^GZMdgQ4A`w2}8VpLC)_-^o$bgVxcD4 zb&p(nuG16CD>a;XMyEX8osIww;Qcu_*R2A=W%Q2FnpAH7{;{0%xmFW!nE27qp+=Lp z^Ky#M;FI2l>4<{kjOt+GK&Q+Jgp%??sKjBCfor0zkwjDvzXzr+e4t%B2A?6_Js7+& zB5ILnk}hnSxFA})Lmd?=SmZe@j&pNV<5@b8EEtsTG<#0+`Qzfxvu}*!A9UGV%F0!n zeHQC%>LzEZ`@>&~Ch*=~ROx~}r$&QF%RYdU)rM-6X=E5bE#JKFkGlMzyTiSFW)msr37lb>V!F?1Tcxf< z)3XwtE}3r8h{epp)Evfwvf;6W$tQajNyV_|>oele8*8Dhyy4Csb3Fkf&%$)=VOF1} z9>4ldF~admwfvcVp+?Ur0#ah z(t?Xw-&A+6fI}m}Idj!gT?09-KC(uFH!0#sl`fSBgxi55_j|JKqsM5+Cp)NwvqsZR zOGL=mr=JL%fNair-J6tJs9G3l{GC@h+CYTdp!bVnkn5EjEiv{almr8)3UjmJ7u8TN z0FMv#X(OFvq3}fhA!s5AIhbVl$sfH*j=Qi35+Q(d&iGKrAA!=&_*@43XXU5Q z82{-mWe>T3?SaL^zurBZY*5^pVOraGkUO28YZH$m$c}mqwAR6>0l3F7g%KjRPT=DtUg}OoC=RZEcAxflW!?ax(Z6s1@jrR@olv9m zjMrkl?H{21HvXkRBVRCyFHy=)_Yi)n%k%pK{FnY0i~P5%bLaAtgUwyW!s$@r0ev<+ z1e~~RPfd_5A%au>@)-d!x&Kf@{`IST*e!wpB9Y@Y^DOAZ=Y3@sQQ4&*NXKP^_nNjY zQG>7D5RshjJ@%+RH4u2|(Nrg-Li{~;9X|g&EdMy9|Nh-80d-si^!g-*ko(S-&%FUM z0S>)pf((Vzetb9Twk!EbO>!>={`1yKj{i14^@ao}MKPmYXuVdXi#>6C3%oLc0sO$g zQHZK};HnXvpWJAP^Mjn=0EowTz+TrJ{#eG6Sa5n0`VY?vU0Vv>FWFcI*#gfY9U(+Y z1d+EwDFM`tF8Lggjv)sWfp9FM^M^z|FuU`BU+#W&Tu?zqj{{kcR*OwSt%#0&uU^i2(UT0Mr+}hdhbjqKFT)Mf)rNlWBPDucl%Be*=RvLLMf|q7!$IO*~a%U*gbp)CX#WrL`TX z+9wE^{);`Zyl}zBD|CC-0Yw>^mK?wJm8(pJ+KhhU8yBp4>QXlfq~+@d{Zjj>45NE6 zO4<98kPyfmh?&UyF3^8Xi8h3_y^&>){fBS-NThvWtz>yFwByG2(QBQn1GQZ@-8#5* zfaV}z<7WQdhjZ=;yDdJ6n z1|$Lewoy1;YmG7duy_7l_zd zNcb{m;&oWZQ&&N6Awn&5{WSnzy9>tCyxrsGZs0l2^aSkB>1$egJm0a5GV(Q0M*Bie zsE$8+Fn`zF;xnKe0Pz|vB&$&32^@a|$RORV$U_F2+A*!#GSbo9KL@^q5A>0^bhzeu zrpQ4mF{bq=DRd+U^=n|uO6Qkr zvJa?rBYdpbo&Bn|9I-jIrgb$?t@_GID*lV8`}01TkSQLWy6RsPM}`A3O`9-&#iJw) z_txj=>(5wqyyTm~heng~BI+{p=^5P4rozfTHcSt!KsN0Rx}Z~8fc=YpCK_a@3VU&qd8#e%QLRwVs3jUi=c2mL;A(w<6}iM2^L3_i%SCU#F#R&@0ZI z{3CvtI5?139O{I^Imvfr?HB82i>lTJ)?0g zPtjPh*C!FyeaeWcL2UR3ctHC(B<48dZH+-}s!w$Dk9_+p`N<2eD8W?jrS8DCxu`ov zM3mUvN3gG(KA^xxv8-)4!nH_1dK5_(i<;eo4in$XRox2w5tR>6R!1C^Za?-5v7ukV^MklgjR|r3 zCC3CwlAPJmWqI>Cac?MIP5j-*+t0A}Jg?5b3EY8iKs|+p=J=i4jf+_|!I88Fii$EE zKGOMu^ibl3&#|x((~T}cfA(x}7|T!BA(7Vh9`)espQ5`by=6AlC=M#X-2Tb+R=S`M zFc;e90C+Uvh+bJM_%)ipfNMd=_2fmex$&w}=-m6vf|Vn3VcxE4Vsh4jo1p_3;pe#^ z;j9W^T7%IoEI`|XE3bf`l}8rNm7B(Tx)r~8ly073RF$ah`=jYI@#{U9#NK$LZE{P5 zsQ&_M%xIngRi&^|U%aZZtb2^!lu2F4r2ojVMbt{e+oo9yrKp})V|cC98k@!W`TUb! zDL<*3@m2As?3wruW9LR_3znYkNLbPeOHwN-0~p2*5_ezW?h{u_`fU5_L(kyKO+Y7N zbjkys?7I3uf}dOvKaP>_54*<+p-K^wkE8O)CNbx(Oa&c$qv3qQp&h#{6J=AK7k0bn zL*xjE_VvR1@EM)Tp;9{N&Bo@ks5<5-%aG>hzbHz}j4fiz3k+=y42Fe@G@TOajOEOG z>PjjVU-6#vP)EMjJTu#Jz*8HG*#-B#k@!2Ig!zbNKYV`MA)ySXA)G!{y_9{P^vQ^8L)q7T^wv_!xe2JkD24v5P9wjO9& z<&M=ND;$x2884TI$IN3tiUZlaXYAl?iZbgAR*AZCSAnhNZtIG1n%PBDdM9p>?-sY+hO3mft6rdp;@#%w3XSk6 z9k=!ucNe--9B#(s@fYLDD%d9Q$#FV{wF*E}7@M7K4%%g*?XDp#szE}EB6fi;Z|Bil zZSbpWXl8NdStHQn5eW^um(^-p)+o$&p~%aySyMH;feH(=!O^~#*UJ^ z#b;OSNEb!JBOJ87BVz2=i?d^)L52!W1*~kCb8IhiXLoq3>!g^Qb%NvPC%odU?RjE!vNs0^yDYpAUPCuq6NeCR@K-Z_b(v ztgyhqCRFLzIAc8z=-Xj4RK5LI4eH& ztmM4Q?(M%Q8tTg2H@LY{)4P{wDe)r*T6m>7`}zw6aXf(dD-S6%frSy;PicHTi!<`= z@8}2A15q#Pz9N*f#XWABn+mo_lR8X2w*^;A_JzKRwbe>#6JK-OcY7 zi|12(f(gzZ&W??Vhz++lFGvGN>xJaxTVdiVwxA<))9s_+f25=CSXe;gufN?=qkX zhW_06M1Tw5%4q1$w`zRBURZ$CJg6B=voTs$QI+f!B-EJWnYa3lnQFoqf|FC?L(6o!QHRq^%R$xmAYzfFCP1<;P7nc@5S+3Zn(X_Q8Ka!Bz7}y z&S4sgt&LPP?z=fm8dH2CW0&FqM0`5=Yv7Tyi1$^pfdvcw*G*v_nnRV*b6diGDH?U- z66_EENMG3;P9DB|eg9q8BiXQQvjUAh2Dv5K0I3h- z92eI2RUq+p(@Qp6+qpY0u{}d4bo1CK@(uFOWB5fy=GCpQupP}|Mfp{eyztldiX5=0 z$w!G#N-Ks}YWyY(QZ5xeJ_{*7x2$;C`W#mnVViL-0wdhkPxtvDCOkOCJ{uE&3{3Mr zLbcf@Md`Ofb$jlu>%Z7&>Qn5?6A{##Tz0u^g45PvAG2TY8Dl%10o%M zSy{fngFEdb*K*@>ni|HUj~1c;?Jb`QrQEI1Pk?HyoX5^=_kec0k>xxjz&+F~Lc9Zn z2(h4Dq3A_>a{en6iFyq_3mnlo5kr77OAR@XUuc3}2ixq>_|xO9OIBqS>*o6Dj2#+p z4mktndgG0A>UQ2~vX4J?ISPONk!kjY5rVSk8Wpw-$w;x}pk}|D^&>l3Bh&E+{dHtR z=^g4yVI4?SbS_!XZYV7EWh#q~&Qkd?i+6ZbVr{uERJQhNGgD_nQ^f5=_Ml8l(pegVg<1rlC=kdUtxgFLEt5&E;E<(Z6lh z(qik~SdN)o%E!bn;;U_j4^qcf zJj@aJ%GVgp?#C;ht+xX9j^B&zM`=m8O&Lc^MD@|j8_<$11Qqxm<=kwXvgA`6&5b`9 zbja3O4s%!?WHJkqfLu;E_}LnObd=y74!AR+_6V}spgU=Zf@Z+|EzzQy&mHv zn&RhJid%dps_|g#({s-g*iP6f4GP?OfH=9iz-QpqkRiU9n9818ze8`;)xKn0Y+eke zl@=;q*lrw2=p#wgttS06EcBUs03^Alct)9yZ!sBi+4*BvB*cY*_PRqA)_%BBucahd zeB{JptAltH#~v*LO}+lEQ?+YlJVE4oSSZa)eVP05R=qlzqw7N)Q3Vi)J@|dF#lAm5 zW##80US5G;wBO?i^or)hH9%z__EmzEvoDj)S!B29lrjEt*<-883h42QEm;x%8L=SF z7;pI)sl6wg8e-l&5fl{1WmBjNv9o;EN&Yf+7=y3|;-u@Ax+aQG;pO(sN_15Fi*g#X zz3MKD>}jm>I9DxKe9UTvgh2HY%^^;PW9ZCxd}#ATm;-b-0mknaAlJHZPN%H;MBJ76 zvCKUS-tTm9_l2NOQrBKBEO|tPGnAHmfVsQnAqKQWy>i0B2=wR#HGldyv@M!d?0#X;B2sjomZ z)9yDg-D4e1Eevlt*GYM&ylD@8)gT)%kl(-8Jb!1(LAyj6ldt6ntH9RRX-P$l6nxub z6HCD)pH?y(=5VDt=pe-JruUlKPQSL=0q7ad4k~obJ6A0S)q%d72DsixR{^CaiM%i`t0T*PTbasq?iJStv8H|!`b8JZ$C zIWKO|^m4fV`W~%HNc&=SVv7x#LASe{DK)-x#h#fy@pO*LZKZwb^MtmaRH!F?9om|& za&`FBWEs7_xUOg>EOkZ4Jl+Bbs*B}9&P2%p;S9|3GS;(5y56}SLJ#)(6_z=t*KMUW zm`b}hs08C&{pgD{ZpwV;Zz$0#oZ)PpzY6Z2fk0_L8M=4$3E!OS(xJbzh?LMWZWcLy zrIX@-b5m7e4R!MguuZakUGy%CS^vudZ$OM4 zDUOckaSJMYSC&I$??dh<@l?J3bkY7Lw?`$)UDiNaR)9L*a=%bQtvy7#OMGw7C+1d2I7g_1fS< zP6qNe?A?C!2V$DFhRd#r@>B4+H&1%K<_hLtCE_I3<$h5}sP%8JxTAXZWcUnPwKa9~ z1r+z)i92|s{-L5Hc7xNEXNm2gYg>0~-MC8aITVKuQ!d;(^LZ;XPMO2&-6P)fiwm)- z8+vU9U)D9~jHQT`w)CjSX^CC_ALE}sUR>VL+Nl7*4u1Ys;>A4a+xEgPOEKHaHna+D zO;^OX-qd}5bB5=fyy4@G?!wgds>Nehud6z-?kROISs$!LAIf}L4*#i~b{5DOG0)TD z$ZDT1EfHX7h|v9L=u`7<@?m3*9?$uZ0|N%>cJ(j)Rs)G6@$wrN)Kdnv@+1=0#k058 zdTsY5o4TL<;N?1WF+6!#i61+Syq)ys{-jn5p@)v1xCi~id}3W>n~WA)-y~d*OObo3 z0q71~`z!H#iE?A&`{^ zptD3D{K8(!ETU}(v|-4CdUw@|zL(5)v6$PM#&~1d zR?O<&T@uWEYZaN6BUbaF1EUhjUojtllA6VEYK(QQ?$(XtA{e8qJ4wlw_>A4qg}ZNe zJ=$j^c9E@Dq!vKmsnHWRfZ(?Wc@43?8vowb5!MU(7)+gdAup0|c8=-Xe{SFf! zYS6)J9+ykDiNpJct$wmYX+|njWlNQl19{G;1#*+B0fN`vb;`YKYu2$lkB*lpr((rs4aWeXxX=rgq-Q)Xl$;#)x0gFxe?oBvTd%@E0zv#)(MUnAD zvY$E7-DcrU^<_HE_%54nSJAD-7Msnh;q6uAw^>^5TF(KsL~m zEpGs6MBpU%21&BctK7hyk%tM?tz?C@) z$1{rH2mV%74oo)~PeofULd4YpAF6@3Bka%#z$GBo8kepOTzdBR4~qLK6H9?hh9{JN zX<=xGQwHXE^z)49g~cFwl7ra}&hU2|KkC;8{-uLdY+{}Av?_lbr*Uui0Cv}e1HX~V z++kzCg1m9_#Ar-df&bGTrbEJgvi_po-@haA*B((({Et-c|HJ^;;lfX>fI%tQr?p=K z5id~wX~0!0pgq7P_^1Dq-Je(i??mr{@MpGi{?gZ0z7fofKctokG^u2E=23Ru8+xL%hJYn;mugJb#{i0a;{aVC(^j=bY5|ix>c0ZGWEC zdH-kT(La>=zqwNUmk25!cJfQ5E7roc{|&rjvjCv^yGIxv%qO&M7a_-?-Mz1lpeRU! zoW^DcfXy*?)axQ0VF4?kNDMsEnkCth{#a!Hek8=x@Ao3|4Eg6Z(D1KwiS)m;KK_@q z`hRnE{P#vxVk_|_vJqHu4W?Zd*%1W2hQEp0U43(89f)`lycqb?Um9ZtzDfomt2UGr zDF;o@nb)52uskzMxdv4TOF8Y;XqQ8mgZ34(CKP+DafUCwpySc-ejEx203@KvGG=59 z;dfU9YX||t{d;R6{|G0;E73&I^e>9NZiT$#-)kEn)Du1c&XN-M5_&)a{7kcCU=xYb z-U9ziJvcC3@L67P`5izR*>VLehsSWDJHnnc20VHHFZ+bX@BM|8#7G4AJ>hsT(5{6z zKgjm)-4Nhktk{PFTg+xBdWB#L@OP51zbM$UCg5Ixy9W;Jhrc(tXK))}rhzB0WLf}o zi(lgSYsG;*5x|@V5ky5!$UxM=E*#i2J9u%(X$1KkK)h(bhz2&(e`vI71sT|Tn1G$q z?|-7rpx1$&r;l~;ppNtFid;I1+_m$xH=(A$nIH__vce@8#FP5+;0>h%AvLPN$6O$% z{#0ZcKGLy96avyV+1CjiKr+d$oa=~9Y49rFJd((NL`zn%D3M3U{|43-!d2Q+Dp($1yJ=7Y{Dj*5B1=%<@Up1%KWd-?YL)@Xo)>w< zsL|^%iwd!QlpKZf%x^`ndD-%pl~V+CNS74N;$}oE2k{I&KTfZ*$M1R41N@+3tNs6! zgX*ZrI->0iAO`8yu`9^lbxe3Ib3hPdly`-OJTa@OBh|3 z@7~aK3G~ezO6!2}%=U*jiq5Qi&0Md-SZNAbu~ZezvxZ_0>n?NC3_LKAUW{IR9vuAG zIqO2$d-E9=+tla#V?1GK@hUa*)uVtL7IlYXhu@3?ML4jf>OEf5F^#~?yHZgzH5K?B zOmCKeFu_};t~ffHWIH_E=)`Ekup3c20K@0B#wl=Ui%|efv;?lD-yG#1f#GUW3=|Y_ zL73v92hvkl%fG7J$L6MWoesl`Wt5;T`NzLsp*?a1`2pndzemm_9Crp^a9uNbr9~*` ztsANIE6r6O(4NR5SzjQ+y`-E9`5Jz52YSWoRO>f=E?wvzstL*D&oK15M}*FJ3}W>) zJI2^i_CgDEjjrOMi4hr=75(zTx_T{5KDP$N7|#92!i8kz9-8TqbpuVPZC&l5uV>}J z%ECTT>#W)fA=`435>1`aMWOeZNr;~JDpk*Jm*ca_`n>KI zfp7@Vt7@_t{_b#}!P4z~^kbj5GdG&Gu@P>Y3hS;z%GDB=p4?r&{JeQPsP_Z%wV zU^#I3i-H#Vz0_gBSW3&%PYs8-XZA>4T(B+Zv81r5BcJ-KRu6TJ@k&QIX!5D?QEg+W zdL*A^K&m}TUy6qt#a-o?gM^BGVTthb5Wm5Vm3w~w#@5>VHV33u9+(?9b}>7}ePq9A zl{N6ki@WC2jZUwR|Bx}?3?UC7Ebm;_++{VHQt@wdeKgjtuzJ> zQN28vFufe#!GE+<}7?@?&1$$>ERPz*Qg;~j*<1Dq}!y zp1Bllt$~K0dtJlTE<9$E8_Raq|xV-NF zRm5V$RuWsl zfndkX_{11Ff}fw?lZ1)EOG3{d8JSL+=G0$Lka=WaS%Z=>(WMuPq-DwRl>66h-l#%zdp5jVUrf-0SD>&|-Z+XSeem z?XVq$gu{GkUHpMnAC&-lTt8E#ijG$qzv|457UFgl_Ac0$t0g=x$~egQZGSxD-gTGp z(r$)(=t@5oV+LT#5kE8dcbv@y3Lk81Qe+fzPSeZ0KNsdYe>J+u@&4nSY&!<82x-t^ zpBkr=cjp?Ey}iuH|011CuZWbSGFN}rc}EhzTejn=R@xVQhwk8(=cU|e z7Kyu9&Wq44P5h0Te8kHhl4gVpv7XTDWL=+i%ZCjZoy^6OY_{Jo>+nUiI)$zCI) z6;2g{SUIHmn;+Gg@6ENCh>h7Byv5#^=Qfv|&F-v2%?Ha2y$n>7SF@BArG~(EJL4P8 zwYE`2zG6GZz-#!H-Tr0{+c%B80Ld0EbKQHQ{*)f0?C4f}=j%haoOM21|4#PV>Xg3g zXcyB+pBFwVZoLf2i*YG&I^*2vI#dH|NB6O9{G)99_OKBy6+P3k zlTY8Z`B~p|w;6olD>gO3?7}#1$zS3ur)bynq)q%7;v=4r zCKA9rZ1P&VgIPT+bLq_=Q%HGkMxFAA%*-sVWW5YNbyv7OZ<}etlLD#l;PA$~c)z*+ zcfTm;8#(b>2Xlepwz*@DCjG&O<`$4}@QosIjnBe|1apY?Pup0_%BqLkpS z9a~^<**%9(uU^+->c9*Wixvo~NE}6dD$cX?%Y_I{7s}=)D#j~}AbG}Iige~L-?DPO zMcHH58o5+;b@1yex3H78;Md>cRxujMR6@|g_+sSiX^cYh!D+8aSzNO2vWbG8`C$2W zd?5jO4{zH7We>bGqc%$tcsLxW=+8FjFP4e-n0r;R2MUn~?Qu4_t&P|W&QBWAnHrf+ zPku^>ZW4D_<5xY$d_Lj?TK|2oNPxPSm$2B8ianCn(Vh74?9^ z>_>Se$35B(E>netjTri^-6jEoF z693vKxdJ$l6xic;dL488OpXr>6CUyUz$JyPpQJUvNo^b76zx)f88Y=G07 zU69aLQ*PGwRg*Iz3E5-=%zAQ6V2UH`N0XfpdDSnl73011$_#T@4Q9@wV2`>bA)N{z zQiyjJbV`t$c2%zoyENys1Fzti(saGhV?ynnekt2M2=_$2;!DehTZE&85ASA*uM1Yg z{O+KiR82=qyciYUq4IuATz(DOn*UP-zdDlNF!e>2V}DA#bh{Q?v9^vg$K=z~TfY$t zXS4cCNPgH^e+r(%jw zfk_GN@@Jpk>UQy$vCcUTRbCL~jJ0^2ZSTMMmW1Ya=xDDPJ;Z6~euV`YR5e)Tgkk0yJJ2wb8GE4CiWs;Y)!23;A0IM@6`JU48aR)3^r`_2mpYAW;maagB%^0S2H92SATY9rz zGkak4qTo>iOD^Yi5qH2W?>o+m;yE@8i;3hHiyf47#+4ZkdybuCDrE9{Igc;q_NHc- zqlFbpBm4|kq7A}OFa6`Z3_wpU{~}IbdRYrg>$tu!>llq?e_=iI?%U$U@15+g#5AQC zf1q|o7f;W+hc8D(G>!P*pXOx185?Pi%Ki^c zbNAhG)nEPhC$_4#CO!D$@(mIttbY)9$To+9xZ2mg5{09ZwNDLfwZgSf4e8W&v;4Z< z57@5Nsj;!``z+UH$TTB{*LuHjJKh~cIrqlpG5JaG^i&paxz+=yNYxfuP$W^pFUu~$ z#JPVmeXQT*;0f8(RLl6@{=FvNhVl-R)2kQ1&)plZbco~2CPfTy&!i3!s#I7a`StZO zSQY$!Q6wGl0B`}w-{1mkc-Q04z9L;54FF)EFh8dCa0<@h*ely*cWxdzQD?Sm+tT1T z*WU`iLAMi$c}YB_P5>U7&h}H03y*B7wJ7zTck|%Aayzm9uk2_A0Yo(neDqq5R4KRf?wGEMWM3m+VRq*Iam8kfN z*5Q1eU>+$}$w@U+bBO?veDOh@CAHPs^do``CAhR?>m_IV0YM6ny%0nX=>M+T8&Phf zIWXhQM#C@&IRFS#7-U}gN5sI{>m*bUB1PoLaYV-BC%h8ce;;R70RK)F&D)eQY(piU z(Eg&(JOT_kXh7lK(}&g`uzv&cArnSVC{JCB5TxHqdRW%6g{2etxbcYmkespsm~{dH zm4E&VY4o!xEor9#{t2FY3K(p#HE{e_u;(&E3y=g(>CVT@o7&1b}dmS+-k0%6LYi$XU^2xe=67}E37m)w|hrRcX zYpPqAglkq(ne^3q(agx^w{{BGOCf9U@)2^iJr#B$SXq z67O`az3%?j-s}F(KKr-tx$B&}|6(%7%$Q@2F~>W{c;4rI-j|;LAH3B6FHJ#ufuMy- zczTy++C{fsy>;UPP6#BM|9Ke>VUhkf~k$OIbZ-LO&ITP=kXw3dJcj}zD)A1UQOlvy@7i!M>HFb_!#8&Q=ZPv4w zb(E8SbIH!^qVOv=r$`|;9rE!4*)r1h^hAPuZWfO12CO6N2ny)DPu9j{awGtdA434V zd)6mJOkghnw8}IFM`gn2<;H)**nrjTQ#(b65Q4=Jd+TUC4G_4{$pcv3|E2ZHJAmf^ z)vQw_PJs;Ii|^Sx&)##taBk6ht-rFd3&@UWcU$Pr5~#?(LvewWq;Wjwk4io&J%Lc| zHzcMZv3fhixsXwBEQm<-h5~(q1R(ewKZcw&z)s4C9iD{ z1OhOu0-EKgfDhoJEPy+L*=_+iKJaU@j6xoPv_*XPf6VXL#xYkNGCNK}roRoDQwG^y zCLySMU7b#C5OcyZSFPnPx zr?-8$fTWvMHq^d9y(5%5u$N6 zq(*sAz@TsR+Xgw0`Dhj*CziV%9;^uvO-2GlMu=jIs7tU{mBGZjc)2urWCagcB9Ll|gupS<4HNDpq4b7rm+93kZYT zZm`a2^~U7jS_2yK;h!E?Z9$W_P}1*+0;) zedTbq*UVHC_gFmjE%OiSf!VDns502g@tW6#KKOT-#CGuuy9cxrk)eVS<+WR}X%FQh zS&xUN;E?f6yRTCR{9NB$`@{;dkD_O4BI?DZcgZ8l>vqd)~Z^t_SG z+?jdi=P{i#4sx{5QR$ppLX8VI{SbKj=Y=PH(x0D8Wcuma7ky9mV9;t=99rbIGNDuM zO}9eS2}@Fz(uH*IxP{^a7ml%=fk$xa3b&1u_#mj{+ zt451;)cBp%A|>Fqn+8#1$2fq|e61@pfJVV4CkT0zawC5#&{g7X@HWA$O|kwkfq->+e>k6=MUb@-BrmnGO%V-A8_u&tNZ}h8iz__CIvz$&0E5 zrwcuFRd(GReu_0SGMQ0xv*(?8(`|X9;uWjgR>Bg!*u9P-Dee5mNiIaDI(XpAf{uH3 zeyjViMc!-xcV%|Uc}p$VSEuGCF^~RmzaouAZ%{1l@m$-JJpNsTOKv~^-CCNn zt*+;UrdWC_jjM#thc}&(d4s39gb(5EDQkdST`JXjpKF-A;itmmrjuCbHvO`Aczmw0 zFs*5z%?!yH)hjsJaU~p4nME(J-)GOYk%(8D>PO{D0S>;l#EzA>^?i!S-Pf2*GEv_WgzFfk^v!<9- zTF;jzGq@xz7>KZh#NV46Plz*|PByQ}8SLWdb^efU6P1<;ZB|NNK-@4zE30%&e0v@n zc=Y0pHF}(W#bty$@cZ+FT|*cfSCGL@rBu(P9>G;(uj@8Za4D>9QMl@`P5U!^XZdp` zK?LPrpK5tEH9GP8vM>;SIZ)F~gzlKE#D%THMojG`YNnphomIXp{K~*--}JiFiPpuIKNK_A6`tOvSETqt`DbtkmI{#mpOk5a$n)a)7pNx1 z5Rnk31}T?$2nCRQxTGm>k;PtMIjn!nI04vHMME8hnQiM6_pM@D9FyEGPSFG%f$xambh;Wqm4yCimj1;u-Q$hSwI6(Ze4;)>u*<20T5VmJ`C=K~tR&j%|7iXAJu1<{?-XgzIftuL z>c(EA*)*F`4>TxJ;YQT}8;+zQ{FZI$Ko3mO!{BrqZnT)wdvLxvFs>qgjLY7+IiFFe@YG zkvS?OXXvVKD1tUN3E^9%D0|H+kj%xDAPb5W-`axQ{nWX|v@K6x&ul}|`O-(pkR3n2Dr>t+>RV(ndMOhDI%Zz8fLx$sA-{(t6siBv@LR-gcq=wbUvJGdeS3A;MXmHZOcT2j((;QUWKIwtlxJkI zITmo^=gJt1^6;{zib>p7S*#?1op)1WQ;44;Heq0wvwMcS(sB7Gj#;x^ScobJ{B%@T~MhcN-FA9 zOS`(NW(_+E6ohgnhjLDaiwN~d$;N8B?U_?fW;tGu|2t^)Z$RsrwRFj|{9X&{Xo@FT zYR8G=KNkDlxArOwyIcfnlb7`o&#a=m-T4&J64vXkn(%WeL;kP(fTgDxu;-^r>&VD8 zvNzD#G)dbjPP2SPIVIry^1A6$%_~%F%ZJ*ruV3?R2zmEDI7fBgLb}j?@LfX=S0?@D z-1x=}mPZR2R$MY+BsJov$h&jG{x-aW?f$rNG3@sIkDNi>4@YoD2la*Kg3n7H-_Dpk z4n(BkUtyyX_D2qg$6^8K5Z9Ia5~?*}Q6UuvS(>qKD?9gc(O=~zmkAmd4-Yz}kl z=xb^|=)JCu$kc(*RAzNi z9qPo!X=_3cJ*8#f%-$MnDk0{YH|((XA}^@w8z0LEN1+0^BY$|rNDDuYnZEPRKTP&X zjA2h^YAdt4WtN|YP6YiJHa1Q}Bzh{)tS4V~Dp}r9jq(1~l3|a8#)mvtNhJ_Sze2sZ^WsS8JXH6a+T(W zOG@v4*QuE}h>C|dOjyf-{-kQfh!{gBBm&JST)9HDFE6pmR4yMU5VCoo{tI_GDyO-=*Z# z|8{=q^Eor0pvzWe+Zwdg_cYR!vvC?)vGx1ox>xnNKeUW~P5Ye5d7K@cUbNI+lwWdY zXozP9$ zbOr=(MTS9BIo0eWhPAn->OlCiy&<__0FYnJHU~$7o_Mc3!~|EP$($j%0B94w2l;C0 z(e|5)eYm-C(f7*+9MO0cw3D!REA6As{oGA&Eoxg&0^LmxZ zuu@(2n|`f)fPX9T(R#!SM~^z3iC%O8+rp#nUWd1oW3PEqC`}z!Nm1A$stgYt+AX(> z#Euc2H+ryPdqWOzwON&HHWY~sBV(mqyszrCt9OhI z?p{vH2!{Ssq<#`)pr zhS7KM_KRn&66suUje;LdW?5ZuP4j^!1N1>!A$tr1$m8USeIleh$F2x56@35(k5vBq zaq0Q%xI~Y*z`Or4@cWPc{YCPXA!Lu^kpI30m>B<|{!vf?VpLI)Jsy@UFwybBED1Iv ziInH|;*Xh2$w?E}p~{OTbN%oJh%GX?Q5MCxoo_5qj!W`dJ4pn1qknHJj7d-$;?|zv z|7u(D&tkLwE83BfM;?H)d@c8Rfp=UyukG^cGPF_fYUOO50I@N>up4}9EQ;^iCSRY& z7HQ1g62p|GFAgM~&?c++ls_a7fLOh%iKgJ|5klwvbJSkB0Wd{EZ2Q8HLCR^rN7CYu zi2z{FR=J5Hs7{&_E{nUsccDlG2>RnW83Pf<=Rn%+zbF8~V%gYb&-#2`_m`4>e_w|sTTY@a_s5(hu@3AmS?0>RV4dr2{PH;mHKCA69fUWHYYZm z99kWU+J6Gjao5Rhy}u~d&}4Pc0nHH<5c~Mz1;l*;MR7EE9S9R@J=HrESfGFj52Cl9 z4UmEMFAx5r0P6YgO8*mmDql!SargIYPG`ZchAe7Q<3rR&#}{cWDpT!y+*|GuWxjm+ z)Sx2_Yrfp!wkd@y>@KN%J?SrP6rahlyyHE9 z-XR2sAUy`WY(!eXjJF$R^?+6(aN@bC3crxQE7AUI0mc9R=hG)K*Dz+@*ucolpCX6~?q zmhC&(N{4@$fReb9}wjNI}*93MC(cndixZ*NV-hsCJ&g%p(B7TRIfBD zj1yA{WO5aGh8b-v8cA7AuuEqdsi5{#GF3aO9cr+a(X1t*;Z^@rxp%&t#Wg)UO_I$!gi{$2+pqTmd!UO?SgKggfi zsOyOHyU-VjOLH#}tL&@D-4wjMYG1_s)oTJvGi|j9g? z#~TpyX8VSgN>m)6)BpAW_H3wm7C{zLCf7vW`RezDt#8zhS_ zt2+imtlG-^+3ev`X*St|b7wIRTeOw?Bwz+dWR5R#W}$UF8fukja8m6VEUt|1%ZSCv zjp?yaJ*N{pu9QIlx2!SriXF14wgjU6MQ&~y%27*J(^nzJk4l#41$3S^)+*X2j@i74 zo~1M2M}peE9B;~3-kK@aAKWw!+g;+!sYtl{aTUbl6TJ}(LM}aS#F3j0#EpZ=D-xuy z{T{S1Od)%(;ztc_314)k?6GuQ?(%VS ze2v}GnvwUcj~1WvxO1+e%2fjzD`w{6Of6X;d7wDu(8QNk-rACFQTow2MR+B}_gl*G zt)p@Xdn2RQ-K*-h_v$++9;Ld%8|#Paiib>C#ZLowk`#q*0o~c)csH28nT*>$%<+QK z+n^t1?{CEQg!NmxGg7Y>PcYtAezh+rq%embpJPz-`cmZQx>ZIc^%SsaYt%6hr00+O zCBN}`O>i{SesruZPx6-fq#;|WJ##KyW#@^yQ>a|hLSL_^#f=f<-Pjd{oVIW|*Zrv# zSyUfGQslSS0}dX8cHR7 z(+}fxbdHxe0M?r-acmZ%e_%_wh@imxsbTsnb2k!?$4(*>LSsAZkEEQMKh@oL_(7l* zd6BDgnFITS9>Z$>{j<>f1=xUKt9DAk6)~=FTLwuDnOP(GqPr(Dvs0Zz%P_T6tMbne z7;j3}xuxi+Ubonr8s#hCH{Eb_uiY?FBh)Fz2oMj4_*rffs=`nj&7-&pUNKb4bvR5{ zUWuOas=kTyw^h{sON-*bvpeqsy=XM!ldpNRJ0La{DBRuu2Fph1i2882M=^cuxgT5C zNymFpO(yni?yd@jj-w)f&(lhOS~XAf)4J-MT#jk&u+jCpS)7_DF=ma{d-K#R-47I! zBJ3T#y|+AzPtvY&lxZ>0@O_`evTNkQ#~?#m=!3b}d~I^nF$$n*y{{TxQP8i!WK_Qy zKjd0CuCMMoYx?PgXIbyHP%!%ksI-Kk-q+d!6?aF+^QT>;wshzAo+k%JFqyG8^B)A9 zD~wZbW4`C^jf|dZ$Y(k^81c@G<|L7exY*K<*j?L4oPJQ{T{vp$k58d6ybl1`DYY^cjhmR*k_w(uU zRXTW)W0unH!_X8bUZGrqb%3cr*g%F>^XnPYB2vaZ#d}Sf)|^r@^7;iX)ncFHJfZ3W zZr{nw0l>QOW&oW+z8N0AG!RtjOplK!Oc%k2EFvd2$4vmT{_N}S>T&cmU$}P^ES!fy z#_o&^`%M4NZea*#j-uo{4BK0vT7Ncnb#}gJ;+fS)z4!Z7#bm@?yG}LQ@!Pfj&I~I*S>fTko_Hk znCCB0Jij)Ihi&%TH-o*Z6ZWh(GF9Vk`;!{c7$Nq)v1;~n3Dq&-AiK+B9O|&BlYNih2(>8|Gb8LDTr4uV^ZPdBq zQvz_u*Tyy7T~_6q>tNKiR_#%8(&>EL1G&}GkzBy49B&T8X!EJZ%3kMs*)2b3`FttmI(LFwo44=;+XIaO;W25BL@9F~T z<_@)u((zkEIqKZoD;f}bPc)~r#slpn5%mKLAxDsYtG7vo)WI{4j5nXTHC$6y)*{A6 z#`cqh)lJnU{BEVd-|Zf$;bD)kXE&$KN1uP}$+lw{Ou!@s@4KEC6o(O%m=n#SQ1IYl zA~*GT$6`h*)<$_8$>{5z2`~5wp9v&$D&*`rn9uEAx%YXrJm1JnwuJerIj?{U;2UDd zPP4(W7gSg~%6lDJskye5%Biu&K`gmFr)LPuMPI&rd~`l=H5bD?42bWjlzH56YJFITB1M;w& zMFBf}O~@xB#$!$;G2c7s#Z)Z1REka@exB-+?n=)tju?$xc*>$9sulC)P@k2irLoan z&3VhIGr4}%4`8L32HgS1fa0&o5-7f0v+k6x9D57UWuRk!-1N`D%jl223Tp95+~Lm( zYHzbr_|cshaaLH8JH|{Z%V$Bj!GJfdHbeDW0U5cYG=cv}fycB{> zf%|_xyzu2(G_b+m7so@%Ejhq4-U+(pEkIV(hi?H}+rxYtZSo%k#3S!5@>7yCxfxil zEAj_~2K}P&3HeHl+0@4~Z$8Oc1f=0RwJOeF;q80p6;Ty?&3hjNiBfe~%HW*>t_GkApSIn%X*S3g#c0gEhJOy>)q;xPCbO=g--&0yJ1ji@-_}$srf-NUB-EXc6d?Dsi z{ErULDnBOt#DK@SopC|jGX*fMe;so9ev(bTRtqdP8x9;b|`!a-u3N1lpq| zz&Ci-OMu%HUVZWp$M+wP`d`oXS7_sQ>~=udBj|(+IgnbfDg=P6hLW@Ncb^PFPIN_I z0~P0q{KuO9r)N7S?wxkzcuDD|vRi;^C-X~yTA{agwjx|L64)nt9lR_dQ)`|Ae+MQX zfY*kW08%1?$j8^#KSWbz1|P`kB%cH0wY`JBfnL-ABsR5Z;zc;-E0#)GzRLwrn@$4Z zuL7W{!Xm>*|JWt6{{t|F`L{rN8~>eC&Q9Wq8GIf9wj_y%0D%Lr{VFxy}y-r*qF@_w{2xIy@2~cZBep5e9_hhO<&27 zX5%yj^wbN-5VEX4C*b7zF&<;s8~65jz}dI`Rg_)!*Er_iZ-Q{(|HPo2=e@*!Za+&P z=mh*DnaI5bYE=MXipU_=tMHba*>2G%9#N=gS;Q;wh3MtzDNK z!~}Un&^q(`nBqTnNXhqwhwUytLOhzlbl8tRx^I{84PC45^IQENXTAQ5Lfpd$sMFxZ zMaG{2dK8xalq(PaV~1z9QD=i??Q>n;z=Y&w0RPc!n!gt%5aa+vi<~76z(c@jUU*P| zZPWj=jJn}JkWn8Z4+lt9#1O$_FjR^)f5``xmf(XpW*lg!3GoL6QxpOXaQ=xc_k-IS zI6D~x_&JnWC`W@PlOG86u7pe)-tH`h9)az9tH>y%$U)nZ#|!`JQyS5b??ASD+4Xd8 z5G}-W7vKcbIoK#w`mYDUpEPA`_k!_Gq-8LXrhx_)Frk{);yV|9jjL2JEb5};)^h?CiuK1&Vfp#(l9*Svwit%cLgd4zFgQHs1-Z&0%jB~=aC_iSN5i{cSOD-(iO<{h}CiCO0T9Iqd6bxBQ$L|h?( zrc^h3G`D`>eH3}6(`3C23ws1BT%4I&Ta5gRLYH2%&82OAM%Mj&pE^ie*}m~n1t)PT z#X@^WZ)W+Ro-KWH$GEE}Rqu}xL&h*zM+N*&1TXu=8Vkx^rHsRZh^&`Wyn|4G6&=4( zH;zQ7=N@hLH_wT_fctIj43(SB8Xl2+q6T-3!ZweXBdT5v{&2hU_=&6q;H4kS=E{I_ z=e=Y}otPw^D!%?jA^Hcy`A%{xV3Wq)*n6>6OAH3zG!`xFbbrafLdO=?cFa}*9Z}~v z^tw>n6v4DoA>2169uyMq_LJ7v>P@*HD=2Dd_|=Xm>b7?n+9*sjs9Hi^u)67|H6yJo z_(d$$1ZT9p{he6ui^}8Y33qmx#0Ekm#ppxx;Infko>c|?B#jxmt$v;6g(1>WhHd4Z zJ0Pcq{IRnm#=N^-WLp*LG`2s)SFbi<#=^XqA{Kk^(IM}q%bsbT8>dqp0S+0BQfY5- zqMa2-F|*uYQ~ny!1L?Gm6l>`hF*OG`(7ynx@Um zQyXePWBs~ncoZ1ZG*Fv_xId-ptnZtUF|c6v}T z`^U?t#;XU0r;j`A2=`po8$M4!6gy#RYC0$MUG!g6I#3&n;$DY4>4Y1^u5M-KVaWYpX1puE zs^%^HvP0q!DcmrM=6Z#;XwcJ=8O0!~`)+Mryulm=%r~W;0P4*;IqfrYYNB~5)|nsF zTPgy|#`%r*UMzSp^Qi(vNT~bHbh|!hYjPV#=(}YaGbgXBJJMV3{*=81zho0m$3)cY zGUh-b#cp}@Nb}~_#&t_aw#s4^H|p>bzBR>sIzo7}j^>3&o%BcOO%2TtvE+#Y2;&7m zr5h&tcUcOgc&7MLrX~EG3I{$X-CWveFTB93$5J^f?eIWFX1{8B@aPHgjGMdrWp`5? zI@eoMFSV61b}4l1?5(+neyiM%eo;`+n=zYSFY~csnshU4)=R&oNl1|K15#~Fk7Qju z750uzp#M}Dz-*Gpb)$%W8nFbqm$T(og)Edkr>kPt$2U)maipA$#`9@iT=|Ot>WxMC zO^c~Hg#|cO^R_9a@j_L$@q zfK~t1)5ym>Wu;d3XPR5B#7=+=B0&^ZYNByX1XGuD=f3E%z0snK@b2ImCrbqMvt3t? z_45ZAV!<6nR5XP7F>(XuB&J|;C}MqgKZjME7b(zjSkX2qn!8Z0nNVUpG|D~a|dy7V10A`uv`TR zy(KiohlOLPOulgSeY*K+MMV-PNv_p6w}C)2Sna^q zWN$7GfB;-C`XMGdWVb;r|2~sn{imX@!r^}I9L_18ljpUgEQ~X?F5fXMf7hblX?<_O zj;~us1vZ=5H9c-KvhT*~coliZ5ESZ}qwzqqF}5+u6Q@?-sq}%!f=O&#fSm7iTT+OC zDP!l#J+LB+p_h)00J) zBm0n_ex^sfy&GfzH(k> zRnDcie#@?Zn~wLwIShs2n&{})q*!?cj#y<6t(Jcs`gI}*&?a{dMs4%L4-;3Ls^0<5 zU7Npg1NA|R0?CJre-|LV{t5Ee0O>5q+w^bJ0o;J>qX*SPP&%B}y%Er%uM*E&+@pnQ z<3qoAJGVnh1=<`TZTp%_c?+0cIHgsb8=+i#B^&5Sph4R`TznZD5O zkh!yR|8@r5)Mv-+V;wXqBTj9~yeaxn7J+*_*dT;i!c}2`T@Uc_$S@{~VBy=-8L%gK zR|E}N6asS@4B#;`*%~*n?F`^=Xf#?W8$aT4K0HzidSE@05w)v0vS%^u*z_sso~5-; zPTRNPy2^@4p9l4(>KD`%)c1F+ccQ0EwHs3B89S*|U}6PDrFcu^_wfVG9J$a(IWsh( zxwXREcbqzt>On0u^anmmRVu(D8z}}qoQb->GtJQfu$1H-fCNyrp#GS$vaY^_bU%Rd z*GZ-)<}nW>N|zHf#CTniKBPte;7&5^6+i-D0Aq3n9&97+!K-jMk>Zp(nuwnSD8u*R z3re!}CAc`U?J=V48E@H+B}H=AJBVB&1I&l$WKkVdl%` zW70dr4$HcFQu0xg(U3jXPn!u042~*A*5&?_gpF0e$01h?|1EHgG)*_3oIf=|4+s!1 z|DyQhQ}$cL81Y-g*lsP!lWnZ}0J!)pe3k7LAX2;r9IgN&#ZoJ?A(chMePALY2qCF} z3UMuP2&fQ8`FL6GK;g0|3^&>GPq)cTH=pqPC%K6yiaHs+XxQq#?31M;f7k8gY#2k2k3xphM zvJgobMDGFS*H1M|4W_xrf@1*@u;oBs7y-ByLbks26ri1m0H5u7%86I-wGLq4dd3<+ ztbTW31>)d$gzld$-(R}vpZgb=UKPHPEGuWd0Z3HFq@y)ARCSa1Mz>Gmq!Xk-4Y=I^ zBvEYWuo~|+f6-Ay-P8HPMpjy(m8~_-h`{Znf*iKjODfH-ZR+&}SSO%LOVg9e+W~Fh z!+1~Bq_iRF?BM{B0zjfe3vjVy=eDVRn(Z_`@>^e9GR2c$6m5e$oJ8~oi$|omEcj1> zXFxw+g5y)->PkgM-ijrfCB`;q_VrecWSPs1_yztw~PkIo<|IZe zruzG52ZC~RaJZQ7+w$WtUaP)Q#vzLrE=xofdEpqz@qR?<>Gly#g5jz^HI|XAAcH<3 z1K-5M6lgqzVz3H&7~OHkb5? zyH5H>y*0#w4cE)usajA#PPDymbbo4mIst)@j!22+C}oPdeUsXA_bNYm2x&p0(SRN) z^)A_E9<0{hI*>!*EJJaXe) zZbj5n;RQ40@8T=Xcqg9j(weD?Qb}bg*Up5jy3q>aFiO3scy08BR4~hBRd*rUmHIko z$5<$as97|PYa}J#+#|Z+U*!xos9i!PkemBGPb$bu>lTiQMdo&-CGbKC{3Yn*0h~Gj zg^7DYrjrenGF`|y7Wzfuu!24~0ec^jknop^rzq9{mQt`g4ee9FmVi~&?(|zs*pqtI z#Cj0Krsz3X^r3OOb zTdx%Vi1waU@57URhHmV{l}Z<*T-RCGZ^yGT)7fK&Xx%k8VgL)hDjknnO8-t#Vx;MS zR~1^MZQEvq!;VendFdavU9sA0KYTI1*OJdQ@$KGBC>}_(SD8E{H$=rsd7QhG>=+U+ z{B_!wFtDrnC|b4H9`d74DS`86C2L)%vs95`7pR`0zH{oL&zz>_E8VoIeNNGp9ugcP zJR*?Ge6`4_=xX>|r!pFG`5MkTkZ(e7waKk1@zG6V+RaO=O4Y`HxCFhEqKLif`}z6W zRIK_opHj{Jx-cQ1JH`f@$=0FY?Sv-c#%102QXbhI+Wg2GiR%?M4Q-+SX4GJY1Ic%1_hZX z_4J5%+|KO!!@H&UR_sbfq~;A3e%jo$f@T41rB07te&<)P)sJ$TophEgoy0|X>=?nPQ6|W*QLD__{iE1?a4+ zSmu_x9E)5(%EAvwjprkW2optI?!r=OkMkN}6)`?A zAvmnEczP|h%p5Y)&^K@iKLn?rro>MV$^*@RQ+6QVu{M4Gu@1) zeby|x#9TrpYK}8;b=R{0;Fh?K;I+kuz&Aw)utzCNCDGIg%b4(v#VpC;cpzFXKeQ?iHtW4cr_q`Ofl5w<-Fx$R`T9Gf}L1u0$YK0?R`~o*WYII);jw}g~CJh z%)vaV5dJb)YY_Gtb74rZyD@<@dZH|CW5VZoRZ{ldqt1&}2^X8Vk_yz0STb{qW=;prWPUTm;J{tihJO0F8{q9 z6^y*sjVa=zMDHunu|3}d?$z0Hzq{5axHfUE@^hA|fJq6koLL~-D22OT=Boo1l@~@y zclwW;=R`56HX52Kd_nV68Po#QP+wnCHDX;_H~citXjaX}=SJ`FNfA{&PMhc#cOtos?=_q-|Gdf(z=j-2>1@?~YjXA>a#n~u71nw-j*kLDX|&FcX} zDEi7OT2U}{6TP?LLLz`=?sxOezFgDAT9l;s;e2EzKFaW(S})S%Wk2fROl~yZ^&K>3N_5=rR}+nl?N{mII7zQOz9Ikx zDfFp(5EVZv&0Pp+&>A+4RFSjJ3uSB*xNJY3(h)-{h2}Y&nDM*$WvrJg}JgCDSim zQ3>r)N90|L#yYpAG)_%6g)cQyr%)yrHz+J{4_6#cotdyTeqr7z%hUhbpD&5J?bB5S z1@)G~+en{bdtY;jygoIFR=uSAnLLCV02$5%Xvzla&Wf0A>GQoboiJn##COU#0r|`P#R*9-$r~j#w40rs2!)Tjm8vFh;jr zaulf&g~BSV>NyEV&W4__QJ4Zu-+s|W*DVhqBh@>f5FUJ}Hoy4jUlm7zu=w*awNXYd zC~mUmZ_+&03nblZujx{8KewC;zPwJRs~f%V-ec;xWHiE&s&z_t-NDdmNvE!HS~fT1 z+y2!2*Q9|>u|X2$q#Am=k?`(<5(v?08&(QAX>>y6HI}Io8Wk3k#x5AXw;?Z*>7kxG*!6y>WQDd$lWAWzemqc++$@XWzRgm^z6lw9R-EVb89C0 zQ32n$47ul{MP5)(w6&oZ&C9v8%Id6oW?xW&+iph~J5~ zIZ%yBpv+d3Y_|+<)oLEWO-Symj@89i5vmk;T{6J-O0#};bFkI{}A*#FDWZ?Erbpme>WO6Hk0MPNFo&E)Y+?WrT3F4 zO~6KEK4&$Uj){DVoVtg;f}VEejq}QxZ}PwJoLi@$FEdd2BQb^QPlI%35Dz9RqN(8% zdH`_5-{ zIVQqnrN0(A`zm;>x$g(O)P%g{loB_>}AYq=lApnBeHUfG*Ei))32^%POz2I!#;I^-)e{E*{*k>S z{9z6L0=82pJ@y*_}qz?3L~F4PA@&7`slU@Ll+D0@0)~c6oCG%YVRGN#F#$jzv)?~iGh$gxqon~K8~PVT zu_nRVmbCDT;u)`v@hZQ*kAxHoZ=O%x%^0T*_>U2J2$#IM#?B_3v-p2=H zSJvA`qQ|&u88uhQ`m63%yq(isk`EAl#Dd=SroZoOKG5Gf%KHD8z5QSF?nP{=8I#e4 zOL|R|JK|p!Ssv4z(18zIG5HA!T{JGh>`1LYc;LYf96JiEl5I&#N`LpV=KSq-zVY8< z@SmRl(Ng$O%y=v6#(1jVZLZSU*|r552VeCY;vywJ);28akU3STFam zXx)lak)B)i9@xWUZ}VPDBusWm=gN4r@dM;(Cj#EeNn`>zQUZ+d1sm`$3YL8G&mv;! zDPVj!T>LdJ0~XPcd;$Dh8zPo`6+Vy@j>41yg^`1#3{!&jF;F6(^B$;x4}i~q{|JQX zf?ou$^|Yh$#+rbUTmRSkK)NmP0RXXl3!IOo!M{KSf(}*|_lWm%0R2XHxSavnh&1rK zC~pD01}vDr1LuKAWMN2iG+`g>1tc{E%vl|{f)9Q_VC{F&2nKPm0-py?F9(vD1?D@6 z1n+tPy8x^yeik$Z`*M8zjztjVwjbAZ+W?Ba+{(K}brJ)qj( zg-5d7L;?__`-_4AsQ3h{;Q{zb-r@o9-R_2yC6sVM&MVO~zY9;&Z<1kvJ_P)?KE%K2 z!OYXg)%%^hK+%7u|L%}d0EI0RAjxeCe|6}>=pnz?vr*B>U0H3;?dyGPIku%Kj1dKI zvOarmhA~_)gJ0jnNhls3gE{BMz03o zCktjmc`O1h0pL|LhxT>}U}+Es-+vPD_lAobiJ}Cb+ChmXudA(8eKoAZ@ z9}a^zUy;CDLC_=`3#R%^JRy;*9s-T1B-C>8GsiP<` zPZXlxrap!Xs|O^hYP;Ld@hwEdS1fFIn4ta!;cDAYQ2R)cO7cMCFN%y1V7vL8kVq`5Yk75~4(^YXUsRT^E)nz~y`Jb;~h0h6QjPEK7rT zMvqZsWdXKk62cD%PrX(SVEj|Ss^jh;fFmG*8|**w#?fq_qEDDS5X6gsNX@nAf4L1+ zX9?VP?ia<+)291$)37Z6OzUDt}B4z75oL=Ko^vy~CQ^wtZn-7Q}|q zd!%=e-pLZAH|d=yAP_J#=`D&B>C&Y}dN)dy8l?&dNbkK#PbeWki1&5vw)Q&voaa2> zJ@?-8?X&-YK;}E=JLi~Xj5*400FX6`d4yRA(Eds=W*anlj5@rx1;*Vhgzqzgu$yP| zzT{CtxxZh5fUgBTsm-)b_ zU+MfjDNe~=mvP1@zB7C$Ma6ahQS^EpTdbe)82Y6Sy{VGI9{fOV z3m}YsDFWsdG6g4OmTw)-5T6YlrVOHqSVoiceFNu1 z1lUgkiurqLHM612m~TAG&*2qH`O7)^jygq0I12jKXWh@=-*DE4o(Rc-3}dH_!NjHU8Y;eEqc`1opvQcXZeq}Sg;dDptz3*MGz5CK8O49l2Hry_*U)}5Iv3#c6#atW%S2SfeVZ2dU`9=iX0P`w$!X(J`JwPHifWcOpJ-iWzoc>L8F^f$z%6$vo>G&52X175`&`(Rw=q6WA+yZd)xA|; zBLyL*BU+x6u$%R6XdJ2dEe>0hx^g*`;U)q$|1o~6su*10sgl+LyTy@v^icwvQItSN zW8&)Eo)Km9QM>(YI8H(!g(_nHEf||$%t~^(@#TR9iNwj96_|xvcIN5Or5R7k{*t?f zCW|$^2eh&SvOOw~WG>FjSD$XOJLd|GvQLMEO>`Z+Kaic5j9dJ|aIuf8N9&M&^}BHc z-K&IN!xv;-55Ebrj2>pZS~=j1beQ!9#0uHT3pZp!DNnj0>*X|iUvAmGF@aD&hnp3^ z<}0YEoO6gk|1OEnop$9>6!hFuu--HHr0Y_jcFqInk9x} zdr8?Vu(pq{WP`}^-9&A8J4RosYYRDdcNfqWb4#%0r&NGy(01_TC%(13;m@WrU$=J* zB1Cjo)19yFoR!E!m46UD*{{pBcMal)8Z(inT2=-RLGCm}`2_Hce}vRZmnnBXDrjl_ zJZ4yL$iB=>Y4&Utn4I?Vm(*=S1K+o-bSBH?_Kc^eaZs1u@$9jc@ufj!`_J{AmT4os zW>)>Y8PgiGg*o_xK)RZuOEZaD{QRu(L#!jg^AJZn$swdhe;8v$74Z0Aor!AI&aCg=`2X zk0`f7wB2a^iHmRXVU)k8|MuV*UV!jP*r$K3t=&(#Zb?qRon_0ivhsBoeDTalm25!! zeaf7sIu*^3vGC5FZuXf15*lRP;+q9S*#{frG3vuvYl&mmcvEh>`JI)>!FpD?&7XyH zns{pGg(~qRcqf>5_6!=$D~&sKPhe$;C%s7q=4@z>XRZ=_ki~L|1%Pf)cDjQcFs5Fo zUNn54BGGIfW9`eY`*KFX&^K&9lXpkbJ-$}Z|wC1e) z2tL5ty2$7Q5d_p6fS{e9_Z=(@IoT3CKX=@hE6`bo1INF}_X=|I_H5=4=(_Nu0g5eZ zeZ_p7y-Fj7sYoz$B66;E&b+?6yHi|Y*2zL*jCVYg4puKwaF&THJ$&!u_@)7MiDl)S ztPvj<*+PO7>;mK=A#~4fSGzHBJKey`iYC}n7QMNPFo~zj9a>qXlEq9>UkT~zg*C3^mlTA4WfKw}7Ig@tM9+>@?h$QI5R8xBtO+0WEioiPE!sZ!?{qDb(J$F zjV~mRL%HUg4*}uq37Fi+sng836HN0xoBf;E^baE10Dp{lbFnGZthqKXFn7{qRxnhQ zy)jZ;@M?Nn+dU1kFIS8dl-BvoG^(ms$N)2^iI*_#ZK5LCUe=l@7(Drg@LO_1-`hK;^c#&9OMLUesg3Q%Fp&h z(g7U!I_SyukvO+;`BBXuVT|-vhJDfexhaCl!3q@K1*eBQ zkkV>Y;KIg++q_#CaEv*Ab3Wv`vu$$PXPs`d&9}18)XpB%lGPJkrOU z3|1WJiCH?cW63fH?j6s}j_WuZr}pZXY^7?N9>oHFjz$K#oATyU39(Wfb}y93OFn*y4wrUTlLeyaJ?U!QdKR zW8-hK&?OD?+DFmpJB#CoC;Pv)J>Qg$wNH0eCExHH$8f6@Rp+084%g%tD3@Xrpt68Fw>;--3+;^@(J z;}3K(A8RVxj|VG#UooqxJ9}S(=?AM3EwzNvXg+bYnu?)S7jLMX^|h=Zs0^r(zDf!# zkcO2(oDni~go{;}C|qRg-b1wDs{pb5)=JrN0&~kSb9|k0_j}W}XMCSu!J9r2DU()s z+2R65ZE}oisXR8yX8Rv*k0u!u2sEM;%PuI=GiW**ufGqAQ&dz$rpk>wxhdXWvX>u{uwg01c!rBe49nQ^D5hbPY{}Cuxf(`i zlr;VMqteiN3EPy4x=M{Qdl{Ey$mQAP?G{1w$n?i$lVDa{*yFg)CP!I~HlH$CaT^7z zeZ_tlkOmg+E2ywFDzo(SZNtw9f8!R)HXTzPUX0R(Aq;X9Ll;U%)qOLJqb)NXII5Ex)XQ{cV+UtXP77*k zYLaW3v$C4RQ@mbRGy^a`*1Y}>WEEK+5ex2g5MKHKoTRw@of;b4#&d z>1IL9-_v7r%FG?9rwZCry^%{TnE1@KRi2Ck4RoRg`UBD|=`Rq=e*yRaz|R>$FM(Sm3_X4xszXSa z86QJK@X@6}fHH9V+%V|L!z&%g2V=(Z5vTL#FG&f}X6NMB2?wM~C#)l7Xpxa{opu1r z^dL6J;o>4`g!DkGmN&L>2uK+QoETkkM~yLXtOcen>?q5-g9%g%BB~j<)mQ8T=*Z26 z*vymWOXj4bbncnE)CE(eNL8`DqApD+yCG7dZB(5&ywpB z1cbe(0bJh<@kpA*6XPbp@0=1)5rBFyv7lssK)-eYf`6Uu1=uNm^BlZJ0zbKy1=#2N zfOPACHmDYKQUIt5kOWoP9hcv{6Di1mjYmn<2Hd4kzcqFFuTS4!cY^=sDEKxNIC+cz zRu@Qf1%)pFI>7`|8S_887=~U#;X{@FR`)6R0O;q>-uO<<|K=UZ#SW|ip1;-onHURz z%)17B`?4R1!TssfxOiU>P-5u*t+F{O9tdjw1kiwu>F-As^|$K56Yw=4X**zFIjBMX z=1BSQCyfk#SNV4XB+dfNW54-ewgy883b}u+{I>z7kklaMZ*2J4$sPjeI>C@V(o^>W zuEi5b^KWE)&@UNeyrd?{~r?Xztzf$K2xiSt8?N! z6Vc?{5pQDjdI(dz$}loxS?o z3i)p}$p3EJ=RZLlW!TIV3R@TguM++C3|@WHOM(9Ujz}U_8!X_YsvK8|XxiC5PoBps z#~TDDov*uiZ@&Y4phcVh?$omX>pqG9+Zp#i_tg4Nko`YF9AUAO8pL+VOK8I*5bXU) zSTnQB3CW~Q+=n>Fu@DD;L#SK<)_5PaNB7M@uGB4Y3i1TbOTg5yolbi9rxx1#4&V*Q z4hGJBjd&!341K{r*^aUhz?{qgLH{Q^82I~hPx~*&FZ1sX!2gR!{eKP7{_pa^ntqRF zk(}Q+lg{ZuNkUG~4rkTbPkzkdMEd1?1NIYzJ^^eTL^p$r4v<0fjA`2bgut4iH{&1@!lYRN>yof&^9mf94|h^veUl9dz+7?v=6Ppakd+G;{=4 z>k9DuR*~Fg;xn1o%C~%0mNRW0-lI8I|M0uZ*o5i0-{ zT3iT5BW8^AGpG|5*grGT{)2Vm@A8SH1}f`T9HXc`T%OBBo|&KGx00S$6)!e2TBlgq-`b_hbheo%bQJYcX-!l8a zTC<--3GBc2vw065OY*HXza=1(G_BB*^o&isQzU+s`*n|s=K5P~Q7`Aa&}Til7F58fd57XesWJ=G8@DI1Aaqz7%{I5v<0zAkRw=0teuNGq3a#np`Sc>Q4oRt1 zyZc2$%Zu+-4Ku6Gnt4{6{iLuV(N@-6%aNA)bp^UOu^|whBa4oV$BpfKFmKApd(w}a z{Ra0WzdK~Y>{QA1RD@mX62C5g;nS1EWWt=!rHVoIKw!h$4_zg!BH_Vsi8Whm8&w@x z`0!M4;Jok*cS$FWOYrhnnOE-Cw-HzsPb~H=P@3zg>#WP(+zG_*bu)9XB#vB|A=U9C z-kpZs*Vm6QyNA|kj2Eppiq1v}y2?CM<@3w5={aCda4TtVPRVd=3`d#>XL0NbgBqlxg(=?%85*Wiyg>iJ$Gxi~WrJ?)Xo8bsr>G#+3nR zpT$@qIyvnJ`_Zp|6$;B{FNv-uC;@&@`Tpn4waO1W4C7HU8RN?q9%kSknF6^E} zvH4}bVc*$_hTpsM;kD-d?}5})+2?TNo2-VLDg4TwGIMj3*FL{h7QX)cQyH(sqx&pz z?$}}^Q(1$b*nzQ5_XNF@nfB1Ee4k8V({PoQz0N{NrEp-|h zQYjk``fup{a+UmgE{RpN5Txxx&vKGM2fCA;n~%}&qrV!bkACuoIKof3=-r%4(N=(# zQOc93qD*(BeRP3#bGp_uZ4$%SIx_=3ot`d!&k7$Mh4JbP1j%L#-3aXI>a;}IAxwcI zcHr8^-2>~ncqN{mo_Fnm>DJN2Df<^rQk+ySx0$X;*0Jc8XjxiweMY`0Q}>wCQhL|$ z{Rn4{`fkD8PU}s(O4>Gae8&;EBifbqdGGReW}?zM_*wRL?q(XJu1fg}BYCp) zRvT&JUP4^k97da8*%P`g+X`QYYt=a`1$^Jf==JM2sxX$uXl zvH}Ra$LniItp;J!wmOXBb!VynX+m)hNL`%2MCFQx{s8UNfvy zk(7F>wH}U#EDTUP63B+dVDkMqoMWJ$7uWvy@rNUnYqt>edyYo-1_7?Q8f=n zLoz9oBmGZH?)YBPv?bTUB#P#Yl*$sVkz<40ydw4~eZT4gPumR1lEt#eZUz|74Ni&^ z`Z4`D@km{b?YSPUx$fDg10GVuXXO>+Uat2y!E|RYH*S^AJ$AdMF&j31vFaB65y9g^ zzt3i?f<5b)YFlq-V$O0spk$>Q>-|B*SCM!3^8M)TOD{qVqoeK;x;)){ z8d~P>Rp1@_Onasku5asweG5MFwo5B?J)jwGd;EC&y~od(i>Ih&!L^LdQ;*I0$5tmR zmx+7?P|L_DK%GGuV2)m1ObwN%hD`g2e3oaxSe2FI?_->+axG@Mm$+-b=LSz*r{^9i zXH|S%)%c6%^2Nx-uLn8K}b+S;DXRP;Kh%n?xNuCGgOlcNDswU){H`J-I=nOSQ6 z5}u3?5_ChVtp+fB;pgRw&XDUtUoi_Sg z(D>=84XfD6oKs{`%vUGt?;LqjJ?dwZ-OWJbT*pF1$2I+Gvh2N7--R-3w4=Ei z%9yXM*C`n`u~Y|1q0pV+;VEVejy$()Hdm>m-bL~X*3+hX)z+m9nORMn&rTuID&FOo zE?7$uLofXzb8p3q{mRvjqOg{VeFA4XlO9u`AI-wTkfaIH}Ld1EVvmG>uisg%0dLR1p(p1OjCAhcQ9lm4r7+Pp{dMSL+Bze63& zx1qYYp5Qs*d)9R^S2u!hU$n}S+;6?Noq)g7VdPyVC0{|XEl0Oku(x$lHgKmbu0Hy} z=5SrrB>NtPkd)kI*wur6q3`p^g(uux9sOo(0XAnmGnP)Ei+GvksEKw!jYSopv7{3{ z&KoTm*TKX*Qp0O*$2&Tq|<;R&AHVz?#n4t^Tjdtm*)ZCqfz*q((o>j;YlRqQZuPM4l0_bIQk^k zlpG!OaPSC4u3mSrSA<^y|n zqQisZ1AphK4=?A}C^0h@>u*D#E005y15Qhu zTnC$6sw%)<>C*)>jb*GQh}LZK`iE6GNL!V1G3$d=rCKkgi;nMh(iVtBGBb^vA?)2k z(#D?#6AlWrzBf40XKTrhixurDQtF*GYOC)xzq8gs_b$$U=I4AV%5H=ALaRBq7sOelxy_*!v7+hH`z5t6SV6tJ3t=x_RwP_&xjj7Tx6ki^aQgy%8$ocOy1eHEaX)iaBE_o_) zS$3JhRRM8nVe9^5j0xV*LIm0$qds%EX*xID9JN%iGqoLgJ_8LZB0dbIWk)>08$sQUZ-q<>c52XrsfpEV1%`>jtmu`j>z zSQ}+?l5_5Dm5}Za^+~wLgXx8?HI(qj&2@%Lec6LtNN+e4s=Q+BD`F3L0yxF_`|&%z#J1+mr*Y0Smo#2t7%h47MBTS3%lvrgK-St z-`s4YaMXZfq(&PYcfAC@&kmZL7&tisd{b3`pPT=B?mwgpiz>=t;Dv&N8jwEmz3eF4 zd8+>M8t8CCZ520Xe1^iOgYmBmdV9uY;b=*CTECACHVg;4^`fvt0x+1}Qeg?q7p8}4 zxUZe=guw@8!iX{NqO~ofeInHKcgDays3w;PH=l?z%my|OUv>su!tkPyPpDHKD|*1> zVyOW*_3@H!Z`oMT5OEyCvDmG} z-DQtm1k4(p;s0imcm;nypK1S^&%Z78|Gjzo&+Z4>I!Lw3r?ru4dq@O?=7x_(3E*SLzRVK@_-^ijkQC3H(6#*Le!Lk){m}9HXpr5(se)89lD0KoB@bC+nEBncZ{pnhO z5`gn!MfQQC`sb-ljAt`5KCS`dIgTKN2YC~tKMMfsK{xRS1kfDl=aTt%-Xj-{|7$u< z5-I>L1F+$cGy}JocrL7108j+qzrSt23IzQC+#Cq{QLRSqIl^&Tn<#vQ%7?O_1&Til zY`{OW69UmRtx5%Oe|u>qEvU{Ddsd#`tGR_)iysKhuSo^p!^?XasPI$zQWKYV zo$TuIrO0#fWT{e7EY1dCm`wvyu7jzgP#9XV6o^RlLZII`K<0tA(2?Unz{8d5Rm79y zE_~m4W>d@2&!oI0VWH>eEORWlz#3g4Mv3wTYZDm8Tu^%eYwQiiJS79j5SjlYy{;1<4( zKz{T3+37stj@b_Y%=hkKuYB)b+)4O9Yuy3&^X#Kp5kpL8(MDJ3{{-VBn7t##*Em?9f-rOLyqi++Z}x@`tuPP2)o=0w)#3 z=X>8U2appgV53}@zvl0Rg;c4z(Y4DfN;6Ymx`ohjmn%CmrtS7U221&=k8xR;%xi#B zj)lq}t@M$BZuYOXcctL^o#+}5q_njmI_jmRb4B6f5mtoyTtw)olMUfm)YY%D_R~y}W z$)~3fd@JK3s-dFeO)*?gk@HW(d~$^t^4*w)RQ*#q6SxZ`av!aGuUJtXucqj_QMiD5 zDR_#$JU!yi4wO$W$WIjku)S(Icy>6Rw!wm~HXJOGy{LIK74+2reSZ((7rZiLQS4iX zx={ymi0Zpr^1S3sQh#q;o^Xf|&6*Z5-sE$IbnZzY$a~ss6na_#ZNvI}vxPy{Y>&41 zC>-L;_41*@6Z2QA2|B17kwz4ZwKl^?#Z`OffgS9W4YnmPIElT+n*v{{1gVFwzF{Y0 z+lE`F{2esh0!eaSJ`AbXcvC2h@3+&FEj+UD!sg89vBlpVVZQOfqJ!)8u6>sF_lcwF z*ty{6mtQ`N(S&+3M6MvjO$O5L$hmE8b1{zY{xbhCLcTv$=uN-Z01LVF#mof{`H{=N zeNVE&KXeJ?wfxvTnK3Bs_$|5dD3cbNFc-+#38BGL!uX7^MpoP(Fv$tQowjl9RJ?MX z9h{E57Ur6+Z{62R*v4;BANxcrGd@jE*xTcWQw$h0_UT^^>CiA*8>5>e zJh&}40;O3PV6e52WW2CVT0%MFn`%6*JKzFmd6nN7$p$%bx&{*0WD?n!mfX58F}7?q zNASGP|5cYKVEV0MgMzg4AyeL5jEjFT)H&2ajO6)&fOSZxBIoOn2pSLm>{%b6>s22s zuH*=?IlamC>Hj{&#vuXTIsUw2{bJTjj(71{L0qJ4#Lmty0Q6IR*fyWFYJSuE#GO0! zH*V4Hq$_daYTxM)f!1S%KM#NMiF(yUEg*4IyLrcdB=nW8y+c5#oM--&6_omv!YJjv>82U1GYut{c+KAH;ZIeF0m&rzLML`I_jY+A!XXlaun>e?|M_zjq#*{I7Yv5E0Pov zdf`c@VQQLBkQ#H-InX;R-+JWN06HYM>w|lqpk{>{N1au6_8&wA;P~Sf4qXFW&Uoap zqh66(zcG+^Md{>#r#Bzcn;7LGtML8SpiNf*irzET-I&m?KF1@i2ufZq@dF0=<| zHEEe^W_*%x=3 zz{1C`9wu35B}*#jbMBP(ZtH7H2bMImG$3@_M6=1sKE9+D&}0{|T_MaAP=o9*WApdQ zCYg%ctH|1^WUB;Rb=*bzNxIk5&+0X@on6Z6_q*NSS+zMTQ(RbTxe6#1GI7U0h-|$V z;|R(4`^d;;m4@*Tkk=G zL`DKg%W<4twUFD@mey^G?=ft8b0+3ipIs>XvZmhTN0=S<3)PI7`S>AjLh>5S@?O@XsdqRX zskc$|@)S;MVpH)x84EW%Gx%QCZpDBtqP++-;by0AF#SwgJa1%tOH=R+kTq96RK)wO zW0OrlbYdh4axF)(lv9Cf1hPbhb>0T`&2fj(j+tJri7jq@MTihW~;muE5LU^cPXra4j(L z;|}+MQXfQTBGj1FyI`Q)X{wn}U+POP&Du*h<4DG$x>?>!msRQmB0<<}*i9xsHIyXm zI*-A7l9Na0CpFf*U9rUEDNmA$m-4gxd!D&@TO4t6_xI&bttF~&K!hPPV zuspnWwv?VHS?A~YZk{&8r&A_B<8Q46((etSG95=M5t8be&6%U=@=oVS`MZ<2iwlD7 zSIG^Bw`FaXQ8%mtz&N)ei}`}=GNhCAR~wBwEqRvD>j@Y9oK3BJ`CMi0gj&nZB!n8r zn6wye4C$3{Bsz`^XBgKc4^_I9S(>5x-Q+wON__*l3m{~p*VM7j1$HG}$<9;mYn9(K zCS^RbFAehHB^KaUaNgRl?icy^w~3okW!?Tf=>om>nUwWqQVc!o%Ldf_MQ=R|vDDGh z3aN)hoLiCysOD}|+L2TZkAaA$GCe6?Qma+2{!tQ3i>}&JPtVg}EBK!4LNV z9WvooY4X|G>y-5D<;C?-i^(|-8u;#fHgKn@V>vvjd6y!9d-m%%wdF{Y`BHav${5n) zW3`ry&S1J}xd-oqXM7*Zk-bgt4Aa6bE4urMwRMv1oJ1-R>qCVYkr1c?MSUi>estz4 z#d>*x)RbOwLO=<-4MQ*Jg%6#nwmxmCP*M@Mc8?*)XkxXOt{K~r`EKlH%UksCkkx+= zI{zECK6~(U5>6tIf#qMBWB|D)cF59uTbeY?v)TTBO%n{PhY6m$p99_Cdy47BUWYzU z$4X9KYwG?$LKEE`tn#&mBku_HBqT>_SgXW9OUY6k!IE4cnm%hPQ8U0~+5s+i*L#^n zUX=jlmw}j?exDnkSZm?%dA+r@Ah^w|p3HpOYKbKi9gf(_Hn@>G_k(?J!v~ zfln)<0J0O4m;W0+4_B07$aIXsYE2RYC)Iqjx81Or!+2U(+R|b~j9^)brTX4rM^RwF z-VdTHom}5V#+!Y+X#R~U;J?my{{V$e!tq!5AeM367}}66WT} zXB&IdW`cK++u>&>vg4=BfTw$y7pCnh%g{TrLqJ%*x?5E3i-Pht3CP3Vd^!8L)O2H- zpyY!*Jp#^bRr`!~Edi#l^wSeYKZu6i!7o);UaNrme-Les;|7kE;L?KjPxe@G?|2YA zqffzK6VHG-2}~EfwFP`WH{M015vOqiDWlIstr*9FxO*b7C;p3UHyDV3KAy})?*gB= z3unl+`)g|F0P}0BsAmdO?|4?o);^zjDrjuV}aAKX1)Bb@ypnzxH;YXCkMh=G3HidB>S zLhwFY21y+iuIi+0wkGE19x2-;vLPnNiu@NMR8I!*crCLrH|&0MLy+o5$HzcBM=cK^ zQJJ;F$)7u7GWVxZt^YeO`END&vTR0R0)U>fG-3tC#Qxw(+@DsLqwnH8TKMGaM^#E%=}PUSXE;#lSsXU>eja(D1rG96m@ z8WrnQ0do96%^u-mFM;AD2j6>oLfnY|jP;*C!2)m`pM2r1u?}!yLd$(XuX`^r`<1v#dEEN9|&%(Fzp=>Pwv6jr-03TVf82a`v3Ws zTWJJ;<=j5bdkMJlumP`((7q*TSjAz{gfs}M#EVp;0JKe}rQwIHgxfLqNDrYV@UHT} zTfB#x0`i?%04C3=I@qbT8l7ZGXqN`AHjJo=Bhbmg2pCP}Lg1)rf&=QfOY>_j=rblj zIVtZKPWYwoCq6n5%cVoO8ZbTwvKfJ|4*)8^Po^kbx*%xd2hnHJ^s}~Yzc~EKCJ1+3 z0^k`+%jaMm^8v&sFb>cfBIE!q;|05)AnAWI~eM zW&iue3x9Tn?Eg)_|Bq699f`jkyeUXKFV;@2%Z+Z|EcD4{=iKqKC#sAaY5_8|`Am%w z0RCCP1XwKL%_G2y!w-1kq5$P@*4{ZB`h)1yy$U&u2JLA8=|45(k$3Q%n8vX%){EuwEjs^lP8b#EnyOP1h7r#c@qMP;?zt-rraRS)l<2>=S0u3( zcU>lx!_X2NW#7RuX8wi6$0a1i_+CDCUxkS?otr||*Ey~2R$$qYq35oK&4L*=DqE(q zDMdn$Gm(EVmVMnrcRTs{#>d0u$in*S7DNP47t)WajM?QcRk5QZ%ulaoTbX zBMmNg?L&TqORypGkKiV@(j)8Hrabv z89WeJ{PtchD9OFY9MBgdSiT{)jT0)>k8Qg_ePmrs6G_KC$H%3swcE*MgVcJh=*q9h zjsmPp?6I=u#htene5FbNw+?7;_q)|ad!Ow}`i_G^uTq|%1wmKik^!X6!^HWLTgKj$ zJI_94YAkK?^)NOcU=*6t(g9xbaZQh#;JnPS@KkRwhj399jRZF10WN#Lm zApDgky-X(t*^N55Z%4zYXFUzuEK`=bG`UUZy@6vs$J%d?+JfMk!!31`M;`-YzbnHC z6Y>Mc?lyg&^hcaGa7Tnq`v+a(XdbIs9hld*`}s57 zBO#G0*}`g{tnW#cCy#Ne`oEJ{+w$1yA!to(IA(k>6CVIXXXtF{NuU=B}*t~Sa5-@C^oS`iiB z*QfBOeRWpQlAZOP&gp%^g>XUwlvX*hTA96m#b+p;|8GUpL$Y!;jAR9oSS^&)djdyz)44iI2d0`@b>}gqAOp zmNvyjSdF*|gsQ+wte3Zs_6-ds_QC4tU1VLDePUhthH^Reak2XDT=hEZ)+h_fXMI$6 z29Kh>kI}-*y~q=f8MgdmoqhR;cRnAFRR-p7i81oF8Y3tx#G3WB21Oya98puoQ}2)^ zih19sZ0}fY8Y!C=rlm-}<}nT4{TyU_X`grB74Gmo9z@tU}A zxYK5yG;ytL48AeS8xG283QK@DhJRKU%ExE}D>jW9gQ>h1h_5Wq&d;Z{ZEe0rkU>RqfFACXDL zW(q30bx0aKFYEYtMlvsIUuvFu3xiW>wPM9Q>FBG?a(eqc!SSWR2uI|&W;HAawwmI5 z^%b*sbns41^XK)i145&f<*C$ZgD;cS4c55|nC#Y4KPEjr$w-W>)TxpY-V_xwIi+wD zqkyXGt|cZ!8%V&qt8?r1k2C7h647Vvi0dBBOtkz#Y(5ta$7??3j^H)Q)G*goM#LDk zcMVJ#WP?|-;;SehFx;?DcxK`{e^ZCOcf2N~AgVl1`iKoFoou0>DpENluz4HzC^?~} zP-=i`HLXynHJc+LM;lW>(KLZyqU+4xjc90dq15?xtNPr^zb2+P#9|G0l3s6gTX87@^U|jCK+*nf}j9? z+iB_J*7^M9E#RsGlZW#IN`kz5KsGE%mvi3Rfs~MJ&_jv~B>aipTU)=9q#S{>h}eH7 zV!T4RI9&nli?&sk@E}NqLvWNnIOH>lHZ?3fL(YtDHF^A~lE2r9O=*|UH9&I>Crw|R`%lJUfA(%ye}>* zFlS>NOi?`_gCK7bE5b$Tr!Vc9R|N-pt*ZrJXHPJC#rh!1<&Dkd2mWdnwuFpy`$6v_0DxGaq z$g(SHiLbU<-JMSLN7y)|#MtCIcnQ)*YRFLyjj5)2RcoeT%9t5n-3^wzj|39Q4t-vI z^ORvUOWI&z+@406KOp_X_HtRdwtNe_Ovy-Q;%))Q9xmN;#yvs7jZfu$vd$(??ul8D zLs};qij^b{_qC)qtLA(5co}9kocQrMhswjC7aajEmkMswQHKFSjn7wG_bU;^Ervpqmfp&58a$V zep5!?KFJ5a$N2tBw=U+P;rN&qx*tUEOMq*fdHU(xbwG8N3^_djpYx;{z+bi4f3pH) z+ITR)o!MB5w|~E zbfI-1$e_KD=>FdJJSAMf7I7G7BVkay_JiUxu`>}C_Kv>x+*up2y$O>V<0(}1{iuhr zk#}t)L0J#d6x-a-i&e+Dy#;q6VnO5t1_+MOwt#xE=rURNi4O8Ah!=-kx)QhC3{h?& z$IZ6~%UPdpsGB)HG{<=jsj4TXww(?;d(>-Makv{i*3PvUnDb+I+OFPfJhBYE>|3t_ zLoE=(2jSJT`==@oF1W` zBg%u5;Usqp+uZF@x>~2A-PMw|Z1GA>C-XD9-}26@0kT}`BG@GqajOB4ze6~+04!1f zxuBjQNG3Um0LPJolb5ZUQ(M{yl!C4BQ+CuXI686|j_U)zTL!NKRnQzvQ*{TZtrZZu zB#0a!I6v+g(2x-zymvaB?uroLI)H8E@lF|B2Dn-M>2>F1^Wk8e5)_5Ei~AqZj2d;T zP6#1@l|bpzmg(DbRi0#6I|x{vnowCU>Ar>`;3oB^zzW5Cj94V7NG-aAg0HQj3F!v` z_i*04@$P0SXsgVATuY;F;;Pp*;&0dHDPuaj?r@b3X=o!)bO$3VOpO!t0)a$VE`VCM z00&U~LEYj2U{44Br!5a^j0Vms;J)-JExfh@zX#lV@jQ?aK>48&#PHK%UkJdurpy2J zsW<+P^MKw93HXBiv8}wVj{_&?U_8mc8u}BB;s+gHMxEhEDPVaAaHt`>@|7qA`Rr%wtdU7;lk0&4qm%cXF zxU9p+zknC@@SH$aOLO%4PahTFVjVsBmuK3hjR@Z70Wbg92*?uf@&xYW3z~BOQyYoy zMTLT{br$91;_u*8Wekrg(Am&8!i+ z(2(~QQ#ggzskJMFp-TD$rB}k4WWxDOT23mAF`jy!`J)A+fXXWdeYACE^3EHJI!t2> z$tFR&#$y&?R|D2xSby9)IvtnpwBbYf3pVvgHt9zO4gSn+MuHAMzfMO@AQHq4pRNfK z;2L|Rdz+-5L^Ioob#UsBmyO(E$;L-o*mGddgT3? zaZKr)AbvAdEt=vb0mN(4RtSz${m)E8?w_~rF>-Ra)rt~*99v_aMcn2m5ak9ADXhy5 z6z_(yXUR|7PSeEZNlG3e%NI#Tvc>CUPz@-Nxy6khlZMQJZRFQe?qJQ26?BoB8+{o|`hOV+)Cu>)p`*HS!MrL&V+Qqt4E*^D42^ z4%Iq-FR*m$Xi!(mR0X&fO=vuJ-x!h&G8nIHeh=bOGMR~6ym5}{P#9J|luk;Vh}05S zqu}q@YH~XMh3iH4wrOL$_TIa;>IX1!=&$Bc-89T!{V5+ahbsi?)Z9F>UWxR6&nRws zt)^ouRq+iSn@O;Q_5HK1sjL;52XCPJ^)ah0ZwBat78Ar`9v;j1C(h*#IquJB>za|# zbEp5hb~Lp@IxAePni#9xkM}I1DVx&_XFG*MUf7yw(x|&YcAf|AB&#G*f1I45qx*I{elC>is3kv9@!dJ2l5#LX}v0e}B56exBoz zBHsK6rKB%=Y{moF@E=4LmX}@;5Q0y=%BQwlG23@5)5X1mvG+v~hjBs|cjaPb?q~`$ zk}2BoDdD3wC{U;8n;d+zUkDprj+dsLx8wO%<6LW-;ti)ocwewO@7~|mDY)3MP4bw} z(Wb81GxVTIID&zEq|B?RaQ2t2_fa-1Maeg}D(W{I71j2_cXYG?zwlx!x$x`U;=a88 zoD*NB>l}nH@8+EI09tQklecA!>~KdaU19R_e292NxmDNVz@1IH`LG&(d8vR#rxNW{ z>@-zUENy&6!PPFBnLwx5rXn3m#W_b|cP;pIoiYBY_hQL#*^3Sh;PP^*Ci^xA#L~~$(Ht&Uno;>-4QyRnZpb_Ue@ONv-PQNA5l4X6;P_*!9w@Dq|N6mg z!g{Y#1ZA_=vFPP-8;DAEfAp-dT-KinI+ajqs&GUdXaCZq7z3U83x(mT?qklxKK=QJBW#|X75!> z3n_Xo2ji`ab1TJBwf!&l-a9VJF3A_i*8nKk3KB(H1SE^(OsgmoBnwDv$r&VPS|v)9 zELm~}$r4*~&NUjS zYZkOr`)#0gbg$SSJF3w9{Ah zGhSY)cF@w@+@(M5oRB_7MUeIArG;^DM%u|M!VLlorUH6`@H<7aq z@OhOAw5}^YPAiWw=~?4X z)cWROSup-9or!}hppG!jcAqAPS)D(&UeNg;8yRyYkhDBwlQaz z_Y8V+(4v|=dFsAGSdeVu&C96~cXMr-^zP+3Kc*0Do$bl7yqoew-GI zBQo^hPdd=9V~tpfGNUy)MQEhIx;dljRO5U^%g z2=t!q{R67zeL^pm=%t0CCVmuE%crJ0vu@x{eaU$FrhprEcem@31-tK@>s8HFcXYlQ z-D6VW{5I&-Aw^mV8A>Mp_?mYzVXRO8QNwtmx|y(ws^*%#9VX06HA+WYR1e<8^0E8K zmhrq%w~kuIU=7JOistc`D1W~yVUsMT3*ibJ;_US>Vu zaBZoRr}~2Qm|f3yfT33B@v{FE=d&_V5=VXoAlBG=z?F8S(p92DLiZTF9ixNMlryQa zXQQY?q7u!vctOhQiSrn6Wp3N_%=X4B+MM)~FL;LSK`OL&6gg)Hb44tz`}21;7K|3} zzGm467?+7lMIkU&q)10=0a3^J?}<^Xep~I0+0;iOA`suC`FLIl_)UvJP)ltf+F!?@ zz>p_ScYvL$RD;YRX+(TR`}TU$h;HHnR8GeY-NNDb?chb&sqcx%U2FRtVz@%R(U@&`d3}&IQxZoJn1Jj#CoQgCnU_j zB9@AtGhVy8I>}no%FZR2>}4nqN8G3Qdri74j6BUE;Z*lDh2tpd#dWvydLEIl77_`t z5Hm9+XELQ!*_$RS`Ih9jVvZb#1)x8%+0#!gZmNlbE1EmMbkCYN1@6ni5M z+mZ4bBTnXV-bU)9PG1sS3%51PrrmwVrEa}})sZ@^@Jw;mrB(G=J&O?=i+Kw_G=+nH zERy=QubAzkVzNbCLUrLB$+~G24V1<_7L(dFL3&C9;sRgwEQfPMqY&z_2UhEgbf~$F z?)Qb_zzrbJL%<5iH{w~lNRr4yl{m!Hr4(vjYA!KgAwkH}A_h1@# zsg6b%G@V1y(lB@OsIsUm7xm#Z7k9V${x4Y?!T@chQL<5_GxD z9c#6zVEO}Um;8Rg#s-1#5vXvr2bFJC^fKtWo97!B&BRmrP`y~O&KZV2s>_g*5f(^L zX)$7Vd_(IdNB~BmZSQcHs9OPL%V*rE2qo{W&{ZV1p{a-YUkn2QFKtmdw36`efc0Mi z=)f;YY^>U}xdSy{MeD#R*^0J(rAFnOnU>eLiuY{ez>$i?!6S(BDd_x)$b(uQx7|nA zAIGul7C5Yhhb?Ht6lb5mXqus(EPZ)1lYOMzws)fc`0&+Q6+D=pVrXJI6+&(Wu{2W_ z7eH7QznhIAz+)a=w;k+JA|xDXz$)D``Tjb&b`7?g%ceb#w4!t7(`6RZNz}x@sj<@o z2~7xGfGI2?v!Xyha3hMo+gg>h=&*-@`SF1czoDAmlu+APM}D+lX!5)pmifg{vMew( z%93Lt#CNp&c=Ba|c(URH>Vl@3L<=o0_0-fRX{7+8rUTnF!Tb#K^S&7`?XZscdu!tn zQ|XPKTC3HG@`n8vU4GwsQr|9BTJ!7-e$0eE&NvXZRDD;kY1w^Pouuhem{YoH6qu_+ zL8uXWH*BV{-W=)OLpHzInwRnjN`!qXAL+q)1&;b?Nw&4ShW*yEbvxs*`~F#dwT%eV z_3olqmKRh3MJY&_i6jsT2%e}(*{zF8*HeldPC;Xs?ci4Ka}yIqCm@hkBfdCm=dpHH z$ZabH+Ko4#;|&XgibrHY_gDRY&_!Lf3vOM0_YVC%SWV^7FB=|nCm~x~J+C!2izz-6 z7Tb4^Pj~dh{n3MRJq7(~N?D+Mgx#@fdiRYQC1xQ709rlqqVaJl3FpM5R1{zlKvpRIVn|Rc{Ax+VQ&?Vy*X@#N-3q4oZJWIk%ENh^SN&EVrr)X_Ql?qk z-c$1#KGLghMB2u`1{g-|2_uPdzi~~VUKVR z=+PEzN%dFOLN35Mb<=phg8Zf99KL%Jw&?`$;9`e? z2-m;;Gr~$>TmNh8yg!UMJSdO%2HsjwpvUJwhx=daj&Jw4*bzB1M9&MSsjcd!ryBkQ z*#xMBqcw1VC73 zCn%opr3ClcF>ttn1ZX5cmH11e!V4BX0P7kB{%6ad>;S(buo=>Tll@!#ul(eHj`zRT zUxYG72vvxughU{nxNl)L+Fa0a3-`ta%uPocAn7`K#6~(Y?+wu<*>Zi;)Z3S?XqHAB zpxm}&%_nj*f<5Hq)j3?f2R#E()Zzn;))F2zFJ8#c$3(*g>K1EHa6P<)y3f zc#_Ysf`peAKme>02xb%hjWJ*TWk}G88Y>d=s{`j5ka`>dLB-?lz=F~+oG1Vo<;cUg z^uVK_7~ZG&0+V|H*yjrd@{_@+PCOY9lZ!Y2ZpK$r?*f%~oxxLDnuow1x+Vh|f0YRY z`cOuIZNH2M25x~KtKc8NmMU6d*pkeP8|-*l*itv)d47yb8qm=b`ySQ`#>nG?A#F-n zN;e>48#@LwFoAY+V`+d8k~(krC@}X3fNTi*MFk>;4Zp;E0#MvRQXtQ|E@GFn@C;Cc zFB5n>M`Z@~t6}EhrJn>OFa-BGE8r|ZP+AB$UQ-3<9}8oGql|t39V!HZ#KACQJ7OJk zO|sH9Xpo|&^60I=Q7_>FuYM!N5D{88al5Y5%OW%sPUYfduj~A(VTXs%o_@A>)yla( zS^!eLwu0AOb#n0OTp%NpP5T77t;l2$o#SR#1~~!!QZn#b1+*+}<EdntbB<6bnYw5xSU;h3~^A&39Eiu6go*91(>_pgKcA{A>=f7-h#_0w&1oYMx zo(hFdvN`~3Q`VVAQYM*~V^~@p<;ryS0we}(e2l6EdR;{XkUo3FYRbb*@eSu3U|H(X zY@!iAr(jvVdY~K4$)XhOg0LNYta1XwGKd3SZ&&3RfNu;|0nU~T?9Y88!BdjJR?dhh z1jq`+h*JEE%+xgO1yDr8_s`8Qeg8OyBXDNYtN@e#`OkebVQ(>+_+ZIWz`U>oz|Sbd zJzz&jzySmOx#cEk7kmdeS>wR`{7{pCb3Ht$1n~c{*PjAd$G>#z#Q82qoU@+8@wZX| z0@A9s$Y13AbFWXxH!qc621ye*^W?2iY{*Lq$Qc@V0}=kYODG{46b#wS+y+vCp1A?i zMVfB_Hbrt0e-$|Bf9}YMZ$5a5yW^{lG8%Uu@H-GT9}1{+BCaFWk)ze7SSyal zJykU+#9;ltT>(uz>NmJ<8aLNk*_jKa!s|6}rS#NRo-@aVUgm;`IH3nT_yL_JVQe8~ zy3MgzZPmIqG4p3u$w^24Z~4Coa6TYNt8=}XrRr4L*bCIlJHPOc>SrQ)RATm-;Rb=} z?Oof>@Z!!p$>hKxga$Qc!Amg)#$}5YgWqFU32o}dIA7cybL!4X@58M_EO0Oxjc>f7 z{HGNSts$l)xAM2;N}rjRs~$brn_!`RH&@EMnzI4<{_Yvkk5zxgz=fm`+Y#I4x*eQP zX4v~9O6kTg3(nzhpRhOnh{%z!V3pI8t{mT$u!ebnk*XmrwHCa!9CKIjNb|38@ng#6 zM@*FWMVuNF?1=ixP2@#a2<~h}D9N$g@?WHDv~g5Od9u&JdR^z3xKk60azh;xM zdnhkGusPle@`5Of4*eEFafoJKZRx@;$S~SU2%U85v)-HEdxsYdkr}PrzqvzO5?kOF zHTmKoF6m*kU9L$9zkJBFVrpGrZ|{rWbZbA;g@wAUFeXv$BB)>IQ*p>@Jqp``b?#w3 zA6pj7j^!$5MDR0v;<6g|pbwF`33IZ!tQx^q-TEUBUQ6q#yt_#_IOo*vl$<Gv~Px;&%t(@{c2y;Qx)BU5;?%@ikA zjVnOA6AAlO5CsbveHa^JnsI%CW|&rJ-yM-p)~S8K&535u{AezBP821^Y!%{CTc0ZX zDqY3*%=%7B`BnA%$%T)FMMRKlq8#MJ%29BBUFX>a1+C-iy19`QI|B`YiRAK7IEpd_ zr(P-f0pnSc4G$!Z{YkJ_Y+dDk+~rKnv=EnL5`bpiJHqEdW}k%NH~MZ@R|~-&x>-r* z82rGnszk>zf@ot3q>vB;Rj2){4Yh{x{E|#nvW1603E~4A^^eQ6_+f|Pg0Xb2DD)>W z`EuJW+0BKp!ooAxR^p{-bqtQHDB~Ht>Sgc*8^hZJx-I-&Ydbpo2YD+^RtKeb-&JjH z40RlS?}=e;baJscKB+kS;%1_MgkV}W-E{Y(q*97sb@!> z65z@K89fd1h(VHV{ae*z;)JeQ(lvEH`JTC!RLXNN@+?lxmC~}c${P%*uiTF!F3m+W zJ??kYr`R$<?QLFDPhcidhifT0FCV3k!9~AK8iUbrm+7@p#abd1_xnsP)VvG<2 z*(;>vviRPy(gu*tGR{o5I#q{DZu3XW>>YXJ7&zEEnrCh4X$Kt1k2*o?eW1MR*G?PbHlZ*Gd1-xgXHoXzh zE8bndr+Z(ME_E>S(|HjWx4(KgguURa{IIuLWQ1EkF6HBIlS^TK7IDCmv2P2XoG)99 z9}eBFtCA$LynvpMIq-Yv)y@7EHJ7oUwmwZOma5g&eYyN=?_*_xecAEMI0HmL@OnzM z9u&sB*67bV)-mCnou$7Jl5w=X&})x3!DbsB8mlk``)35r(vk5BRr-~9kX^cOMt7vu zQ(~iWGub?EQGU@tnp)c>f6x=cg3-}&X-v}t1xONGpeJf3;)hzvfC|ghc;5NNx#vVy zQK^Cx%VE;84}^yWvy86S8iiJnpIbi`wg%loU8LX16@SDqpl8C0Kn*K2Rm(CDbJf-K zx40F2PbKQhR8?pZu06~xSM4xl+O4nNTiENijyy5xqdfgAYvFEpbv`STOnd%W4dwoc z^c5co@16ZZmCR3>oPrOpJFOP2FlAFVj1FVbBIe`yfytIb(Ll{>F@YoKsPK+bU@Cdp z*aLXYw|J8ZnxflBQ18sK?L#l<(-EG745_SEbEMush)Uc!ku|5|tq#-Wm# zox+aWS#Km!aa^ODi;I6g(I+2iF-Z?OU?0RK*n!?VX&DpE#N~Y|bjv|J5pTBUxuZq; z`OvZJLGiM1z1S$BtO>>py`8N_Hi1Vn&9nPd(Pig!Z<_78!8mlM3L>a<&J5gClrBbn z05=smYw4s7Z7scSF;az`kH$p5iLIHlN@f3S`S1YrUb#v-IXj)E~>doalyu{+EnBU}hq3N_b z_tJ3t*s3>KA+<&f70xqxH4RfdbS@5L^AG(n+J=#p(2MsLBUr9-U$}E)<1XkUpl`i4 ze?O|1{tD9v3fO2J7|D36DWbw==CW=e2JgNo?j@Igv&c4bq66lVfv{aWFz)Vpz$+Gf zw!oB*d^g5^q@`AnH3@UbvH{BFKv&&G8ihpp*Ss0|f$P0i>DUqbS#+CRPitf_ujmSE zb0?iKU9i1Z`MQ)u?~g<-z&wJ#Zi#xliW}DMb)$5DRc_Z|cdiwja@RSH)~#YW zYw@=DjSGP{Zd3>=e;+2FK@X+fgGafj?Nha~6z8?-vQ&iKhG!Uy%tsl$BE|UcY{R>x zXGhf?5A(H&9cuNe9@%*;ayak%tf~gXb+T=W(@$YY;tW!yrNDL^v44Ki~ndsx^=W0Nc!e z5@_;(k8gvp*Ph~Y3;}-i1F#bS2tW{DeE5K94CDs{^KSK5n=A14IwSrg1CR>d1sUsu z0x|$X5@Pv49k6pk3?bmt(4}FEGjY0Yu%YJ=6b<2dLdY)>ya7}IxM}~5xxfm)L;&*R zF9Tnz@xTBf>R>=dOCJQFes6-8z*u1i*kN_ViR0~G^8eBgc-xd4kl|Db>x-ueT!G*& zV=n{kF>Wg1HHPseh7dq_42du9RXZU0b4dUy_zY`(j0Lc*udw$p6rvlzD`y~oOMy(j z=(m`mNy_ay*n3Hf;U|#WOviA=JT! z<;hZ@h?${Yw;`kcMG4gLT)7!=qP=N zC%h0!B^pd$uFP+Zt!3~)O&`a*SUkGf@x6unHYxWAtZ&gyay|EdTGM}XW+T)7xv2js zX2pXWpsE2Gf;4Uy3KPyLms@6HXahbJZc(Bvptpt;qo|ROZq&v#zh-?Cw89i6S+!$A z^ZXkH&^%h3OE^0N*6&j-f%Ro5ja_D+EY;vu4UVYGo)_CO+FnFL0qZ&x2mp(L4|@TF zQ#g-)hljP|iH{q~@OG_uBA6uxj`tITVnqa@SpSz5fk${SN-7T0kAXFV{`hp>zdTIj z(0K+2VHj|Qz@_v277~V9orWD!&<}tIfv0Z1`AHyz0EqjLDlY)Ce0HxCPnX1vf0jAj zdiIk5c&rz^j)g1*qDuh-yeS2sx~wtXJif#w2G0!3E1+^jV?!f;v=vh1GynFq}?wq#cA zI8%~*f8*fT8&Zeu@nh^iaNSzP4rD0kbX?O?!rpgD+X13H-Lhqj`N!o&XBI%R(65=L z{;nFc|7r5L|Nr9s7hV=(CehLmEC#mh3%C-x-v`^07}CDLMq~fDwK|5Xpj2UZ6@VZV zS$~YqXAqV%92jpEO&d|=k%A_$NzdO#sAADm;F2Jl>f?0(Q7W6 z8xj~K$v}bP%A^FcPV|)8teALi1Mz}OX=T`H0>PIGQ^>?xX}Zt4IIz+_giksnlgcL| zH%T<@kA|b*_tR(g4}bXoQQ7xLo0o1&TQ@_}Acg9)r!i!^|B zDYTSE>=R=($2LYP*2v1CXFt}dW@gWu@MZ@Gg-Wh#Pn~<3yw?jLj`TOHK&$+XD$pbN zSxMobMZ{j|`bw`5Wma?tVQRv9Q^b7@fS?8w+H^|*$V`6cy%(j&5c&qFp*YKmXGjP? z*d!dy1yfRXW%|~$U?nY4L!4PUfk36jzQ&EiTpRI6Tajia_I9L0b#Xexnerj(QFin0 z4y?u-`G^3%)L38ncnuF?kw?ZYdb|X_NKJBu->_vxBL+rYKbr3;y)q5gv7J^_tzJ5} zhH}r8u*4Jg`pFA6(?|%WikuIPY)|3N%$qB_K7lQ2Q(v<5e#nj|z3aje>bNi4tedJ) z`RypXwbtt*VKrr7*4-rDIx=#wOTu!Ex~6c50B|Tco*=SniCB!DAJWC$B6hGfrK)%RB;Kb` zldJdzowFQ!LNTjBSN)inNIt=T>h5ZcY@I3Lm{aFHF%3b@Bf^KLw>iHafxBxHY{?T+ zO!`Vwll%qixGq(n(#PG3hgHn=MPDv=h}w5yxj5VJ7qZ&Csjw$c5!Q6i#+D^0f0`#) zuf1!hUINs3AE**^drBwPz{Z*1{APC?n?uRVh3;K%;NnF9q^`W#wMj6(rQ7qFOnrpL z=h;ir!O~*j_sh&-_0q32$%+e&EA4xObZ7=8UflHnB`hp)7Kc8`Zi5>^go9**cqU7A zotMKTpRK#D3qwCm(w6w6Mmx@dn^6@p*9jMSt1In9T;C^W+hV(FQ@v24x5Gt+zN0Rl z8r0pdbNvccLn>ozo1mzhb9HyhX#8n~{oUkbA*pF8;XN~A9P^R`zo=4`JH12#cipn$ zd9Hl-XIAux{B-Rahk504?r;|V#4*aEB`bPfuxZ1vb!xVNd*+d8)YTu)<8-BKmmI@A zLXFj^#Qozs=AYqm*4-JY-}sHbWs~3u&mH;jaI}t0{st@_Da0ouf5mqo{wnqH?Ed~U z&7mh~Wm~06J;g)H>C4@$no?sF^o{PhR@>tpNjk(5p#b@Lyt_V9PN#o;*=<0WRn#mO zvU4Ko52ERw2VQxc6gdKq z;XNPf`92#Y>`F364<<)0O+)}WG|WucoQXoKDg4Lw7wdEavFj(xX;m5dy#+o4>}>oO zc|BWb;k1v5SF?do1Cl0Jo4@6T-HcuPZS8a)#>Fg*z6s$N$G0E51jnU4Sff&?z_M&F z*=W9Mn52bve?5QoXvWE|d(++FY~ORNdC42K_Av`+X6U0vkn?cP5hvQn!XI6bnhxDi z!H@xN-=)${Uds|UW<}_oyCG*V4TySYp`pmch%69Q<5I9ZQM~{4TH~&Z`5;4=?d>~Z zheB^5JcHJFuc^e!yq7btJ&yIDQCH>EP0X>__%CTQ6Fs@DC0Tdz_rk)Lfk-1eiMT&^uP3i8d`?iS8&91opm z^L!!4C3rzs#KB$c2L2pz;+fol21UJ9zd1$+|*c#{C!K;Cq>^=jIulQ5}e zr6AiRc}e<;@3obl0u?o~_rF&)_PLTg(__7{a}jqrkk|GuVoSWb>gA_Sm2|Gx?nb@L zDuwwXTJrO=nT>-#%#zF+^x9vSVYXjq`u#BExig{~UC6(Tpj_$7q&M%Dy%>}(wuNWD z+aA&BMti@y;$>n>b@dHs`K>S`u5!s$eZ4_jD@=~;yvc}Ob41>3XSP3c-}3F&L`2n( z`qH)SMo2d{Y~0yILz5)*GH0+u5$GA{8Dx-R=V4Y!HP9Jxmy72r!BdIx#&7gq-8AAE z4kO=Bhi>wS;5i9-LvK~JP;?^tk#@obHLSXTWWswg{`4`@nRU0y1O?7{7@`5hv zwO1z4T^ONnTp=2p^ya#vtarW_gd4+>PIpyQ!>umPI}WIDr_n)k!bZQXdhhc?=7a=2 zy5E{#Gw9lob`4y^uYZ46$>Scg@F-hRBPCk?aNNA^tioDdTUeM=f_2|z@@(E?%QkQj zPHxx4IPYbKg0wDP!^$Kf7Ggb7X>C3dV|zv7K;n0P+SI=_EMQN zNgInWb?KNecK~lN##)-=aY&)M9I8e5Fr^;hoYG80Ux$R|oaJ?}xDui3Z-*?z<{E z^#{M9wN_-00q)q=!OU#uV=`%h8&P^$1gmzT?!JtlC${EDyu=wucESrZ3MtrWoLO7g zw&Nbc;cQx)*@{u2YE{c?bz8>+4!v&rcb1T9R6;B^;PRX(6}!rX>goBNA+*j_4vU+P z2{+_qx8-^8?=|PZyt)9uN|&(kFgxe_EiA`JihkV>g40Gf#qd6%rACXPju_exC-p`SP|JZaLff`Hri4 ziiIO^{rWf@j7O%aZ3&k-Y&?pg+DliAv6w9uxY{#WQoL{Kq2L{P^x+Sv_|;z(sxCdD zIj@?FqgBlHCQ=i~4vlWPC*HPjjhv%HTBd7X7gJXfK$~rDM_t_ryUc!aPn0*WM&_)1 zMH>@XD3K+3|3D~U-zmg1pfQ6dG01NZ+gf#_G3$hY=`2{4|^oq?SA$5@xTp$0xr)LHZV5AKed04~ACT_RFHc8e-UqnswcbMr^C6o?7>_dmk z6n~nv&8S>9E?`A%$1k%|Q(Zn9o?>Q0I#B?hoykvGAItPFUIGn=6)H`$%e$OahD0by z%pQ)G-O1SR!wJ;_7sYnu!yBMLABpkY3Fr0z(%<&b<~d_)i7ou#hPMXSWuNd068Pv} zb#puMy6Oavf}P7#atZkr+O5UoqXvUb4hH>5qF`-!@?U-UzL;i+rJcK$c2cnCGxwgs z63%*Z#kj7)S{xCea}WTEf9!t=c;;IdqVQf!`h^G@gi-Wj0MO%27)mP-h~h}l50oC_ zStXJ$2(c`Z0I2)*7=qy(gPqYwm}#ED?$8f-`{K#dh+sn=U@WC21RL?Pq7VxY2AN4V z12oV7hs~!?5 z&^4^GrwE!;8?({8yf>EOLvVG>EJa8K5BQIxRrEcjcD>lv>A|u#%#Dr(vWVsxGRfNO z<;7^t3n67|GmSBsRh^Y|aEgUStdb>eVZNT5cUvt@Y-k7m2O&<<{xn_2zq{oBzzfki zinT{@Bkjo3kW+$HCm+;sDS2K~BghXw3F2YOmf3QpoO<=>{hf6o;%PmYrr;kJ?nLrW zdrJQwd+Yoi7odYaeFa98;@aY8g`$uujDt+q1zfXcybRgI;R;sd3UUQ(7ZZF2bR!fO z695zZSEnZLPy7Elu$TXi0{tT#&HwM|(47W17$H0xZ(4bJo7g^jIPT;ZK;)DnEt_M9 z?B_(PQ%p==tihAb0KaA!#-)4#&}$&Tj-mvs0tKvojl&7~Z#GCb!+5dyrjLRS z&H>g}3~0^`HktzH4nWVpxc^cJJt1whPY0lFo=Ps&ekYs9*5l<|UtnFuMX`{kc=*)z z_S$rWSoN>$E<)f3t|N* zXqk&=9EPBr;C+G`2o}BZD*Wlv%4GVL9nKn_*GqBqo{;j3@>I~>y@i<4(wFloO6aQG zQvo|Hb5$B%st8_D0X`=Ljz#x*93S56PbUReY=P_70nC;Su!^5I|8mkm`9M$6zCWFm znTfQyaX2b&0(N#YVt2O_|6v1I@NfTJ$MDqrAwTuV%PNoQ!Py%(4Ks-4u-)-0Bhm%t zyzxlo_1Q{>@&u(AhS37NYT92=T*du7|zeT-;CFP=f^dmqUJz{(@DDj1c&5#y>)k zlpV@Gn@|y1y!!F<_0S403G_OSX2o>-%*GB?ak#&{7efBVLi;4oRL3)5)b`qPSJ?o` z=h)**!yS;VucZ?YqO`%WD{8W@F9v)ODJMCZ2w}$h*wy&wwcd}O$94y?ocB5q)=4g2 zm|B{~tz)#Y$Ew?v61S0@hEGn(#6RPvCM@JL_NdQZm?CWy16e#nm{X$O&UGCc2Q441 zaZ(9)42~v>s8;(sDr%a`a_(lbK4NmU0L2m~>h$U(R`okJXKohwdEFM(f-_i$VB$j*Ksq>Fp9W$nC>Zyd?@5 zu5<1tN|88xuYKAi%NTRE3RYW$-)pSDY}44L!@NAMFDy#-4JQb_fKXf4=P$YiXhG-Y;tW=Knw4_(`@syoAP2bw|eh{ za@93hu-&@XKo|U|IHwg5=;Gd|kbW}AwCs@_vD~Z>0>^sl?&X(K^@2-DYQ))wQFU~m z)`CApQ}KIQZ2((Odhjw;@KbOmh0Bf2Hv8uY+RyLeTSk@E;iWrLa_TH{MOJD)$J$oo zmf^4;(HNcAC>DQbz28<;lUhL;t#+AV7F~@pHWj8B2*&H2ZH1%;en6<)Xdf zWTCxM*3Rr>Ww8c9@+q=4HYF!@C$*EZW+t?p(XxzyN5UDWb>n$b-CLgrb)3Z|ovcw> z)6WahpY9FAU2mnTB4oE}u;wmR3#|&pA9ci7(IKCV9T{%7Jxq?H`Sp$EY!H1`e4U2+4KoH7UuX}W z0l3DD|0JMdHRJWF=h2zzb$3Ku$8eGIWRS`Ypg=VXrHWt{i`-V^QTW^fi}QhO3nRx|a}5># zBP|84rj2NYS~1mU&ya%;;h>edMeaeq?^Ba?N1BNOBi5%ukf3|3nBImY_RGSe#8_oYTV>iA<_2z z61_6S_4srHb$+BNPn51UJD!w`RyaPEKe`@Uo7t6-Q8QYa7cVq1k#MAI*P+3R8o9mw z@&*0wlT7lkRs_XPul_9jJDb7w1fI?bOHyMs|GLxfLL#F{s)lJr*j8ykT5;&wkfMXV zzMjmAqo>-c)24I%ggn6EcCI`UUH*pQs6SG-%IQ7d8Jh{G&hV2W+YMz?*Ilb!jq;36 zj`E1In$1;Ap=N&_n^7%()}wwmd45*X2{wJI{q4ZD4NC3?Mt{N}QLT!Ylobt(@3Imh z<__lN1%c(rR-$RVv-6difKRS2OxGmBI^rFtZUoq1Lhw3u2 zUFaMh$!S;$FjCo?Mz2jX4`Fx65y_F@X_%|Om>@!p#lHo$%t+c&~5>>dJXcK}}Dyt~3fJ#!^Im>eKH_$A_ zFqox7930y9-H|HUq&Af|+tR*He_V@WM$IxstXnO_na(gNo||3Me6N9UxpWrRx^NQ} z{l+a9t%y0xNxN<_I*S?cEWLx3fFDeG%4kcxnVaQ8ry`w-Drk`D!ECSm+f;0)nkamj z5W0fAm5l!F2;3Qq(y2OygdPy@QV443gW+4cI~auLpF#%mY-`Wn5Z1c0Dr56-)%d~6HG5sF z&p-+9-G+PG<6@KfwC}WGTvs-@m8`(Z*)8I(p+GmD6%@ve%O)_Jy$T#J;ga7B^PC#Q zO5kSE(g!~E2aHRwfGSXsYe=D&63VBz$cqJ2`0kk$dhoWJyhg*207th$nEKO3LFMi1 zUu~xI7?dgeJ>65~V^umhU2Z;l&Cx+&aU?hrCX=66f(_O!IdxSKn_5GJ?(=o54z;eV zH&r}SXH~agnwR5?6_HnCOjqEXEcq}Z0v+f=vD9r+Vh~e zQgz!Swkd(6q=^M3=BF7uE^owQF7iV%_T2Syhg$P;tvZq&cJUd5wUK*`DJ0pEeIYL4 zTquv%N1WHw=Tc_p^jb0Risr;hgesKl?ARzSZ1<3d`nyN=uyqQv2qU3->P6yua)WUk zt`9Tf3ti;b2h+2egQCJ|j%vyy8W!=F9eb)4$)CEffJt;QdJhint;ZVVX(b7p32t%5 z+xttaK6w=Mz%_D`sNkBhZZI}eaJh(HD8ym$M32+uK@5+|yIc;b#4HP~oW@p*4VYy0lV6ncXN-<0To8K*`4tB4H zmaWMP_dJGw?|pYGMF3s+$fEnyV}_#_^&F1!*Mkk6u0XIiAy{=wj697u-<&I+6u{g# z7;$d_0PWcv1W&+#QePK7m<&0*#yjZ;IOX6xuX~{$FuN5v${KQZ31&Csx%LHyy_)jU zU!40|1jTrzrjTaN-dWW>CFT12b8}sY*T1=Uw?s$DGS7dyS_n9Bax|2b+1H)TG@RMx zisfQyomoVtg&sy}GewQU9S8f4*lV-R)$@s39tZmw-D9LKwvI16+^nPbBWNjj|63?Q z=6gZ{&2smaf{Io4IN|Q=LT^1rWot6($)n_un+8x!QmeK;BG1kDd8LV%7Ss3x_oswc ztX2Dy4?@jKv)zUJj+lA{`pRPRVZmAC7p1Tt`>kv4IeZH(hz)@?s}XG}8kMHW^*aTM`xzVd z%E8`q)%6nEUK~kMjUFM@F#{4J4c({f@XNF9-IT{j7!r{m*Kykv$*^+LDy(7%~tSizXt4jH=GAK(WLLP z9$TM!qiR0b&ee==c&6LcFXG`%m0-|k+!DfjUjDBE~jHFR7=mQ4ca z?V7QOV(wv^ZuHdC?VmWA=a3q;t0GlWF0Tq0Rjh^2I(lEts^PG?-2b43$$8;I?UJVW zx051!;Y49=wL)zRW*P}?&2pQWeN995@m#s2e8IS|{b{gjPGN3m#*CFFmGabw{+VoS~prI4$B|+@JP3kwvt>Xc-MO0sjyhliMRvn?fd2-0IQDbW*Sel+WtF|6-Yg@DC zC&4W|gZA9O$h5huhhSt*YbB@4he{o*ozGb}<>ftOStJOSNHl+}t8c3hlsRp1yU_Qr zx!^{kYYL;`y&H#9-2-mt!_gz+`LHE6ymhf|&R-{U{9Ow)S*_SHiiaANIPjb=2UfrL zxjeHCyX^DGZDoZr{({944r&6sMIg+Y?Ly%<@xNiLTF$3ya2arO5IrWmW%;NrmEn7$ z3x1fExfsi7on053HC6=@Jf<$*Ei$f0b7{mdaH`Kl``VPc@aS-B)EsIo+RC@r?4Cc2 z2NJ@2PbA}UpG%vrx<#V{P|}4L9GjH1FI&@y@$G^>gctxVC4vWLp%$VutvE`6%znPs zy4{CNm-R-F1_xyL!v-5s}lCdSVpu6vKtIHFdyb)eAg zjZMOKsbv`ENrTOL7zx0QoSM8#!sWz`Z3wG(n}yp-)Oc!s0s#rvETs_W=oVlWLufoz2?bH&nhU|hb*SndDf`A@!COD)#{vt6YgE9!#)_XA%k2@8h z4AN!*hydLCmeA9=F>MC(K5{w+ zJ2(L!^ufX`gxkzWQJ8HA%72quH0Z8f3zF{=fMkXNI6Ep*1AAnngLg`Ne?c`c_gGFe6%$fcLtXUBLyFjrS3V#R9 z{kzualW$)2R{&2Y_L_-cd9&iw2E?T#Me|rML~3l)5-dt&xt02WMEKv8mGnI1KTwbV zcE!k8L_gOLxsTZcvgQVga0~VRB%pX0sUM)6QDH5F8J>)1s<;kWhUTA!co#YzxkvDn z1$-tkUZFV8<-dS;Vk7Es`(GB1OZW9*iw+~W{iDagXIM7O;|PBd7XeI>543O=c&>R` z3fZqU{}1|p6F*)jp44Ec>M(LUG;}@DnY`ZGYGzRf{}3Fgur+i%g7kuR*{mh%MsLVZ z0x@!)XE7tXHDnv*YmH&0|6p_Zqb`%V{d^{Y#R9iW+5*RbI6N(shF}o;;QZQtr|=+L zyH-Sh`{F_FAk5{0vF;~<9R6ejcgpp0AC?e(vH18ezW_JlO~H*vpg+%c_+oM0;6LGe z8c+(Z)My=umaGhH;4B<+*Q+}9aWL(f(5&^ddY_!i+OtIgG@s-H;QZuz0wj+a7(TgZ zXYBWi<-q#|qJEaCE-G}faW*!%%wQeya|}NxDO}FoI&ai}x#vQmG^swaWM_r{B3{4exElB6w&gGDAm#Ok}Q1rcqNJCEPh z*`y_n`=$t8s}bizC>D~Y!X^As>NVp_^wPCGw(zPd(z@y+3%{UjHxws?aY7rcFZqj8Mcs(-h(bGE}6mKDo+YT|u8%CaTtTqD2F?c^&F37(^R6N~S~_L{klyH!dw%>xVHcL+Q1g_Zzx zGEs_RpS1U9tE@GndOj16??c4c99Mnu8?P>ulij`GzrE1$=2Ev^!~?8fq9ah8$UXAO znWUQD^C?@TZYoEh{pt{II)j82Gg#9nZQ+-3nW@jdSk zzd`ndrsNf~mSXb!^HLf)QJc(B#eK(mu(YtpH?&O^tF%XbqXyh@n6bgiTX0@O>-v{P zza!l)U&uT-%vnr(-zX$e$9Hxs4xz8h@8I=my~|jA5X=f3*t^vk3cG<4B}ulL{R9bv zF#(#q^sxF(iA^wn5-obhnzO9WReVaOubk$dXDI#LX?ndS)6A4+)u^HKM}-ax{EFOK z_Das(8ZTu=mQH<|h69#X8@tx?dnW-Yh3zXK5T;bNal&gh?7db@N{ z{2`*!q<3PWM?jF?q99#Bx^$H$AidX!Qlv{)T0}r<=)Fpp-g`~xC6G`9g#6C-n=|Lm z_szL;=FXXK&YijU-|XzY-~E>LzUx`fdRC;tdvhST>FcnerlPH9=K1XQXI+C8St;%8 zu(nrjw=s_7IXwMImpdXR`Knq@&&EpKuk>QayqSr@htMx^3AeNb3n%QJ4vLZcitxO- zpObwcUaOGj@NU=?OTBs-8wp4jKt5IT_;VE~CK`;_-t5Cf$IhAUg8~ZAnsHUQT0nAdCq<1~Z6chhs_)?24vl??J z_)+~_h{)R^CjVCI{ahaXpAur8xmSVKC_kH9+8c*UY$RS-dIA_?iHU|7 zNpSS;&~Ob37yWjm$aD^HOywUBO;lgQ$9x}K43$Q9O2wWvz_0|YfhRsYC01XcjY_jR zcv}IViwAkLh(|*wAn8lKlmf?jwd(gbTu#Hq9FI86Q)IIwZ5Gxpr}dd1b^!X>Rz4GW zTRXgID>ZLj-=whFo}a+(VR@ce(7?UB7VMaj4;hfUhHa^#d#>F@Td9^lQMo$Cd!l0S~{SU6m$KUNQLEUcbfZe|fSy>OeZa`L6t zmwk_hh4{;?nBT_Qx5-kDIUIv-W2HJy1L@I2;nt>b_ec^FZxozwG(F{2T=z%6_yN}e z6?Rx?w}qfYD1QlrSxj=$if0HYq^f~xv@JqqU5J{etQ@A3u~hQ?$dXI6xT#<^8buYQ z?PN-|TQEXCgA+8_7AusxJx%@YhTvKGus=DVPPJ>Oo4>MGD^#SDvKZUxUqI0r%ZML< zQpw6LY=emKTsTAYbT>-A141p!I_obp(lr$$ZSP@E9PF=@v&-~(A@#WzI2Y@uOJA!M zkU~#Ca0uoEoyJfPR78!3pl76)nQzlNXHE%Z%xQdZtTLg-!UwhKqBp(US!!%c+mGf9 zhsj(xC2P!6^g2hoFPW;Y5)F7eh4XboRG|Gi=Wi!A)VxIm>qVNS~} zINdBoMI>8h@5hhF;d@^^2Od_%59m~+%WmRr0?@8d(v(3KXhaK}w^|R(;x~P(4MKsl zxJs|!%;1W^ao8XY#*^PfbJx;S%KqHo?kDO-MrM9w8tL4uvz}sV$O|lY)9imX=HQd= z-Bf$O$F<3mQEz=#LolhCzoZFOkAZZ?2D=0f%koYKKEyf>BlaLS{cSMBKj)mHTG+N* zDMXkVo4|y<4v0mym*tWsyX4wDgR5ax37;4Qx9sL=ZH>f{K{(|D8{{4?)n7Y7}N)y9eI6W@<**`^AIoFj&O5k4YkDx!OFN88*~b2i{EP#*Kt+I=I#Do0sWZ0R{n15Bz$R5m~caLqJfWWBqo4bHUM*m z;>*TL8H_gxdR>ch)+0y7R5RvWE30h8Ym!i}tr?a`5Obp)oAr@JpX@MM zp}~c^De6ob7e%Iq{98y4Y#dTAna^Ui^gUkOTM04rt-cJyKPbD?@!aXaJFH_)eqnk0 zv$ElJw?}D?%5`)LHnC(uKW)CG1PveUBo(^nYF?#K@MEH~ZPiQ0(v8QarO%MpUAs`| zS(dW8z@);%>B6efiC~`$_T$Q?_)Gt0-+qA@Xa#?a(k#w!dRkx3h8dFN@23S^IY#O__=XxL8Z{bNDlI=acFfi7f9fyh~}g3RyqMMN}b zJ+xsG$SNcc3K~4b?WWd{R}}Q^E$)xo%IHkKJqR3j%ffJev_S^Yohi1o_qefL`o#+P z&1$?q*Wvy(G^SedLF~b=`VND*OiQfvB^aJ$;g}_olhSpI@3naIL>5@YNn{fCG*Uer?+H-BPNGD zH2uz@PE;(BJ=nj;j7|l%T7WD-Z_>yoJX-fpqN^%b<=uBqnJusy)J}wR6dBJPA4!)| zXeS;;rJBqbUyfGiDb(gzf!15X^DJwc3hDYS!v;((_^^)NU#N$=ge2! zt<7Z4x2Oxk{j$>jb@e#ZO4_qcTX2WWRzH1fB8j(e%=mX2hobwAP7#rIS_5?RjopWK zpwR0-iq{iHU?Yp?-?EWTRfDTjmBnVai)#=@R`w{lsXo!R9oqdnWxG`@Ze|*OW(?1N zRNEC)@53R@;$4A!CMyGlipjTg)~n+$*HU)8D|z%iWV9kOugJlxnlM}VP$^j%bL6FIYF{S})1?}}&|5#Z*o%EG!#!GP3j3Zk?J`pFYU=kMZ?18~Kiu_P-p zvO_)Xl#4TVByOt$wAig)7F7P*7c+}SN`4$YakS}L@?@DFGIEo!%G=wAt+qscrJiSp zYQr^|4G)+i3^WAHB5}i3*w+CVxsFo+3vJ>8l^B+7UCr=8-@HDg6#4hjjn|FcF{x0FY1q;a$X&Wvxd$5NBw6I`(&J zzG%p~2^6yZ&(u08D>cGh#7Wk!L#hFP=4)`|UTkhwDw!^oT_N7|? z`eXj-;3)l2EF%W?H_KG}pBN^t|AZ#xKW_H_FAc40pfFYoy{tJB zGMV?WD$?(h#}y?qliGzQ4u(QKa@41`q)cB|mi8zLr68go)(ECaF32y+TWD~9H0qDZ zrI~7YFwPE82d~Fd?8VQ-)jJrx=mi9`#=AUBx$Fa>8*k5bs#_sP4*=sy-QIe98-f*` zfMBl_a4D6p`%~{3O0Oe^iqi` zZ|7YemJo|e5K4P=yH(#vUrHW75&J%#Fj9}9$16xJU*G{LyW@2mvyy)#rd$2bc(RS;MAf|k-8Cfy-%+7ZqU$;o1A40MwMf(4o5e)bB$07<$;%H zszO!_(o_;Fev?N^$g%{#duB4c^OQ+pkMSrkYM!<;8RBNubh_m)>}PU9w)%T_->yPz z&ja7J$O!dtD1d)JeC4Wqb)WO8b{bj0zU+5PF#50gxjm_t`*Qqq*>axz9O`oxE6_Hb+x?1Yj=1mT9Vf1o|bUqhta!H%uY$F33nc}+JfOU`X^_STYbC2B`mJ~FqHWDdmpyYVC31G zv&?Vdxh4f^@1DLuxg^{<_ob?DJN?FbkY6bLbsS}EF(3Q&<@qa%pv3J9=*i?{3DXZ@ z{={ESo}JVOLaT(3eaG&Aayc&pBEK#EMQ)|j!E)5)Ps{jQ$InkryQH?AcMCeOZ~EIM z#lmGD{D2ilqBM0eM5U1@(Nt>wAo7|l3l^=LWd!bZ#)>J@pWA}E++IZA_ORzxMOAY) znsQ)gP@VmhI%HuPFO7Kl1)+oeoXdk|OJUCaxpUvrbKb=}XS)P8dlpE0Y|b?_PnIHG z?5gOVjlp#vKja!@roKMd;p{9$?i-;#|H7bUr8jpjsjusDwT$JfH$>;>_8{lj0`1uo z%r?NboDx04Yb6VzKnK*HWn{LONWSA+OMa%wRoH5k)x5rA+XzaJS>?-=ba`^X>D}55 zqu5#EiAB@~H9cNMc_AiRgt6g}5D_wqr(hqN!2)l!F1lo%e52O=eTU9N()M*_TiVg& zXVEE#0?al_w|*u)mc)7((eP@gf15Xmtq$3n?qFY~r(ZPOn%%N2?=cv1t`8(+lol>( zNL)aaRAd<{s0yekUgp_M@e4&6UEM*Slzh$JGGYtK{rS!vPW-HL#Jy3G9iCC0R4h88 zkU9S#oH%O-jO8s6^)7z4iv%5TadBRVan4^3Z~GHH6eYZ+NfZ{#C(c3B$PRzQr~3AL zbP2e7U~^A!=AC+GipFANAXj7XdO;Xm@pAqGN95Po zKf*Mp?7+ub1Mk-;v?hM9caeU26SAUbHZRy?8x~vf13yunaBND{|FHu~do)}zzhPQ4 zhWaM85b*ug{6Ku^wPv|Z#xn`olgZHjM>9TthGrg+RHN3EH@vI7lP2Y3GI4p>gni%X zZ}YyDi97@^h)BZ4MB7F+B;8V1Iw!PYyuJbh>u_*?lDn)L7Dk2jJB43;ZSp9dX)Clf z<3cM%w-9=3ukLNT6?j9s=nL|^+nKk#Zn(#ssiBA97JLKup5G7;j$R*fIsRhu3?ohX zb%jTzU@YVIp@FSNglks+Y@Ke=t^C%=CHt4V=$FT3nfENuV|b;Hcg8zkBP!i@h6IaK z8=aEf^Cu$X&GzFQ$Ib#{jKf(_(e!a~^K2U}xAf9mXaX~sCb_^0;DqZLb+&&1sv;u2 zplEYGwZ&hPij_;|?-6%cs^TG)EEK==T)B!IaNXObRrBZZyoJYlY;_ESA`I{dttd~W zuQ*%mM^L*{FoY(M>lb0|`#_K#p10;xy2!+-=VLW{f)k;kd!NWRo=8nQ5({Lyd_h#$ z`5}3Aa<>ZA6Vsn7UR=nH3_pr5o8=E;FL*-i_ezDVn`GMn>wSv#pUG}bT zVuop2TH?>P)nylIaXJ)*NA^r{_EVj4c4RG&S#$T*^7{(ZmmeWh2iRf4ZznF{7h#iT zLpg!?uuVYr&%r>uV(g^#&fJz!q5}drx|!47YnV8=|Fvq-j5(GK8=U*qJ^IUI>3F%~ zo9&>dK7=`mo z6B`QTVc|?Z#3{T>ybTga9m-p{S?O6B12@-={g%*SbnvOu%ZzW@>ci}$P3?%kn855q z#6n|S4lI6;kPrqdrI>5UyD}MmJiLTal<7{J5`Gk)BxzshTG;BNSCS^*Z&Bk@W11wU z#L>Z}C7P?M)8`s!f{F~fuuXU5qZKKD(Uxgm38#82EdZoW4g zDhm6->x7QC)(kHf0ZO-a^iRd(#>Kv2-3pC`0wR&1sBalDi-o(+ISHS?Ig&zU-vX6p zj~KdV-d!?-FskW)5{Tae@?vlCxiFfsUMQ6IZGPEV5<}B}Xwvh_npHzWVj(O@5@4fl zr^8@BcKQmkKLpL`2*YMCSPUPC8NoXh2nEA$oii5^b}(8iee!>riL^4OJ1sREQswa% z=IL_nP(Ob#*w~;nxasewkz=Niqlm4=xtJ>W{-G6zbJ15rdWy)B_;X_nJ_0ys zIEYr3+fGt84->XZ4tMf{!zh}@w=!>!9M7b(GPlo}PGnhSE)A%;2v1Ahqo=3WSklga zYEG27q1BD#Q2po#6VCN9I!dT$PL2@#5G}5FxE|%y^mS$Js|NU%Ic2JKi~!>&+iK>z z@jTFnMB_?3F-MJFRrMC#;#erbA5o7OjeQ@1gl#5#LB8ix38OH1n_8Vs^G~3vgN|h~ zY-u;_=0lHRRy!ztlh}$el&(L^TMZ!=j_2SEqAMp`Gh#)J&&;YjRTxKFcRDT~{tEpm zQTn~jdCETZ_4cZ4>2R29O~r@C=#qE`natDUNs!1FjI3cumq8zoMs`>GZIiNG{XE`O z|L8h7tx9`qTxz8V#D;+kCURAwV-RPvoIq&6V3;CF z4;F@WU;tGMy73A2wg`#cr+swJCw)d7}t{m zNuP750Au@O1+OmUn;Ak=wxB>eSb3wSKAayu1Etaa-b;zoOT>$uIwx`wNorthg)e`U zzy^i=aoOA|?cb{sY%hL{<8)Y`$31!TgivCILfiKRQGmdU@`+$CNskHo&t1N!09V`T z<@yJ?c*Ug) zdQOcxT}>1iaEB2z>`mF!36Dd`Ug-g?uA!!9g#yP!Ww*Ryv5@pwqi+;>^%+23y=Cnk zHHZ}IQ`KE(2+04D`XO>m-SbFRi5vNlh?Ks(M|VBl3R1B+o)C}KIaoMdf3;OXu*FIk z691Sbg5eJ_o;5Zf;y80yuXu0Ueww-0$&qX~|IU>#&I6yko4+IfKcXZ@FiMB&3te8mjJ?{!xTO6^07bdw)5Dzv)tMw)4u0Ti$cRhfsGIT?1x^P}7% zJLje6%*zbY@@!!%=MK-(_;F928+30sN%b7|Iuq<3aVrC0LgtTFqm?F7m#=+Y`gm5N zq2;rhuvM=^A*8=?R~Z+od!3E2lSyqd&>9arjm=y7Ggq8zIORrnm-PjGEunG zz2XK|4rkU6l%JLIyEsdVi9>5UobDLg1wNWU!Zca{93!FIH#XvRsKnfo_nW$xR5zKu zZ(H7a_x`io+R4vB|7epiW)w#Ji+KN>UdFRh>qNL!sWC@M&+tUQAUWKqAa9WKtR|+{ zX)Q)$Sp~EGg+CX)X*Bk5N`e!nm)0rCcM|elF=}t9+~jMF+{*RnaIRXTL&S$6mezoe ziT6tu>bI-nr_Bt-uq=@zF>|>$lHo0Ht6Dap^|!Y7g}{7lMHV#sB{Zb}7@Z^dMji`5 zSBIildwhEykecjhzw0f4SJZ><0;%E0g;qe(!E@MC?_K<}D<^y#fQTsa1%?AQ!6)oH zE^bE;%eW(-hlFPM^t^~tW_gt!(@ZS$mhh0In~e_E1*z^1D#cl0Zv}k!PFQsc!|ALH z|6%OUcU2_qgn-2);~BB8XObmfeM+}4^z&@9O5%z%PRD#+XcSllAo8-h1Gia?3pRavM#_%_&%`!mezEgcLr`BUc-wh33rtqi5 zK#i_4aa^l1jz@^nPFAHJA#ZvGQ>RXFHo$>W6Bab$%yM!o*d3qWp}VV;Pc-2i&YB~@ zPg@`-?!l|=C_QKg_p{;+g9CY8;knBL<&(mHov z>q{+JCyRehR9plyb9kfxCoocc%ErEQjuFZ9@BRhM2YqUsQtKQz=@1T-_)SIoLVC$A zDS&#VR+Rt}qz%GDlp3#I!rU4!KL><$!j6Sz0R>_n3IKb`Uc?u(ZF-&E{pWv|89La1 zdJ3X~j`Z6AugHPm0%N@{%KS2x7e4OEvIB9Lds2U7Eb5x}s}iNIut9R*UK^(lV09b4?LSkbQeX>Z1-_YiiwJ+0++w?enl zgnO3ooN`@VO}*E#^d%xGBdJSSgvzt{iXLCj-HF_KEE!N z9A%p+Xi74dtZW@brw=7#|9T4lm+lm&*oRHeT37<`4=P{HoqoC@EkKnBnV&PGpl7*~ zblV{U|Hz0K8%{*AmtpSuJVqKrPND%UwJdY9b&jW&wsnhT1RoFNm$d$~g4(|}s73#o%K^Cq4$ns|e;ZdEqphWN>Mef`$YQeg96`~Nem&-HKFCI0oz{6DtC0sFmO*=};r zi^*3L4;&=7lvpH%eP8Pz@d?dO>2t*h2JL2oRn;Y`8kx0SHav0R|BsR)rttH4ami8u zOJA^}+Mk^DbY#Dk@__c(@W$5~(Dbpi|1@5qy0v{cv}uu##*FtFP_@zEG4+DO9<;qx ze?x`K?I=?D{Bo5nw_=w`0aX^;KT+iwf-A>45B%I`YqU1M+^GIB9ur0<#HS$?ptaY+ z&^rDDJsfs&Lpi!@Dvlui{&|AaGfHLUi)`wX;x%NhMPbsqx>|1ZRDx>FwWQbgof1E# z3`l8e2N0n4Fq8?sXKdepsu5jC>S0+qVB6*rAs`f^LYVarN{M!Sb^-ox7 zpjC?@ETc1@1#%S?%9KTWkEAG41-I*4lUVxglX~w8+1j-aJXA2=u)fO>#PZ&Jn(f$4 z>9x_bLig{;ksQ(pF?TlYvOVL=#jOov6BeU|gupKcr*d)E&A+~kE~jIC;{SiI9G_?({gx@31M;ql1D=mL8eeRZJ~;r-7= z&t{xNJY|XHYwKhRb&)6R=3>ti0}A3f+!09=4_i8%{76iAJL<(vLUiUD1E$(3W1-F4BYFxJz?6-uNQ zQd#gSyMTmMe$V0cLqDH8#mHw43&gL3rs|WFl^FNx_14)O9UG*K*XyVE3Wu+u&KI*~ z&CDWGrKinmaO8;GF;vR%vyiVB5A8TUZy13 z#Lz-Q`At}tq*cby#_=Qbp_|8?E!174_0~(Qo8k=n=p*}*a+Cf;T(t9-Pb)_c$tBIn zq!n(-W*$^WabVS9Z?Q2x!dF~IT8Z_QwSMwdn}aX#%2p4ef70DOBUl}QroNPn$n}0v z5}&ey8@)0xO4JQ#ruTKgO(!TZA`e1aNYJsNsFJixwHGSYeq_veE;g>ZvQfmPWk0pa zg0zc-^6HBr=P+@?sEwAO=>)HehC{)Gb^Ta}R=GWMk|qu}1VfX&J=A^N*fzR&b~wxX zhpGLOxD`J3z-Psg8(jMnEQO!FNL}=pCRq}-7o=)VWX!q|`+M&k*M7zC^f4D)lMan% z_Z&uc*Jq}(Mp_zudqYLg`;)a-yo+1~+`Gj&W?)5gF7Jn(i-P`r{<={ zxF>oaj{WN7Rbm1+HnQ+$Q@;ntc&v-dYT(8wrva>6x>bMaPEU`#3b`d1mB683=tg>laeCbG#+x6+8DbPEkCbJ9(oL%=h9 ztPhdQ>zb_zkOS?M=;_;i-w1gp7tJE}0Bcv1D;Xb^pdBJUzL{!=i}UZ#L({jZRJGF1 z;a*^2s}44+^xfjeyKt~3#;m|jT54sPV9q?)c%FjT+nUSXfq%&|hI^wfu0&v8`w>^8 z$2sxGR1C*+PujIv^_z$?vI0r_r3@7%MCSb>lS#`oN5LxF9`808&2PQps^Ze`+|oDi zV0@Btl2rJO+!NsgWyd-$IXUs#39dyVIXh}<0k@dg!AB5wt1nT6$ECLgqv#*Y9^Q%O z-sy$r|2l({{Q+=P&m&LMDggIsj3Njq`VlVxkbT?HS6NMhh-SM<4K@doj-&onbIKbB z<$L}j!lZ6vXmYPNEj>YRc{ay-WayZpjZ#n&xuH2%y1PdLXfFr^!&X|=_o!YnB4r9A zY+DUI_fl`tvszBpMekGKY_@qE)?qAC^gSky?5iiGbqS62n<01U`F5a^1g_=eIh*Uw zJ*{#S$GIFHuOcF3X(wgL@gw?dWY}Evk#Y<6jz8CGEG2eRYrJ~UZnulD^HdZsGQor3p2INR*4UOhbz+tNbreMmOYB>OUwn8oB0JZ?9p!eMW0Ja4n^wrXqT zZypxnPiM$`OT%ORmY9}??3`Q1VwJv5rB`KjQf8he!s%lxGoBf1-vN|jJP4lyMOXEc zkq@gjpi_Eoo{-t`@hkJiGun*$tG(^ep~G9g(;wDWE3Ym~kRveK?8PpnmlasQ^iwiZ zB2hTZ+s|WmMg2&xQ7f1@47}Ty&GeGx4csy@+dNf2sdf`HuTZOK8TMf`P$gXTGR5Mbo-1g?RjX15R$p*Y6{X90Fz1Hj-Enw>C&Q-7^ z_G`WRiQ@qV6(BPDwn}D?j*uwj^%VUzRpITDI2G`T<9zL8W6g;}rMW>(%>IyOs`&n0 zHV=5Olx4NEqM`C;+-D{E^gH&$r5YkUExR_eTkg6MiA>g7?hlo%+TJ|jr;nO`tUof? zXg55p`SDDX3r912+Vd=_C+<=d$6sSwY{1OboK|}k0K446Lu%25YN6cu2ZNBI<*f4- zLkVc7`rw<37aaoi062i^*~*)U*VNW>RFrI~ZW?S>8?sdI>M7RMU0Lr zoO|wQue>u=GN8~V_cp9qRCSIO+0tu)Dv%`}vT|XGZF> zMFA@QuS3OPx zo+jNTN2FMKQK|^^X($h4c>ZWr8x-^rbxI%m<@WI5RgRVWyq1byG7xsa0sA7_#eY-zI3M zi|yCmXyeXFVUPV1O!z<~h0cYXnc{si;WaJENtx-sgI8;aI_?kYdfg#=QL{4V?!6C_YbOyUA#Z)#1KilrMnv~o)tDm2OSF`tdiLEP;OxRq`gkG4yvBql-Q{6#N*s{@mn;P*DDx)^O z;#7DpD$P#o*?Y4NmYPGEywoSX`XtUTs9cU#86_?p*)n+Kn#Dzia+%L6V;f+7r|0LH zLwe%kx@t&u^JaM7u0nuK+LLxFzUm1sy&uDdZzJXS^$ zKbxczqt_;$-Znp{AC>C2EwI=Y$agM!k-h15JAS~sFqF)nW=?a`?+6-ytTaj#N!3$S zZgC==iW_B5iaWcnLjWkQOMpH}MlZ#p0jRB^`GY(MK4B%pShpeuq4wl(e#Yc^P!A*H z({4rkp&{OhtVHDQnAx$dZv4rMge&sr{u$D=cI8I-Dp#X6!JWJ8qK5@bmGcVXP6x!% z=8%{jtos2i|2CxA`~qKk1h#~LcOa4$4Spp57k}S95P%!wYCFtNX(1PCZsx{q&_ki3 zKMBkLY%y1dHx@%ba6!^ze#o^8Jtc))2-+V%7q}ddpTLhil zg9;I!e52@w1%d7q8=MAVdolb6r}5~paL1N=Z}H&iDp)w^4#biIkYrPxmVU5uP(81Z zg=Oxl#HL*G2N1TWcu_7c%o`c8H)N{^_;RG6)C1^q%~JLssOyXxE3lscg0}AK71L_Q zxls==qRWVL-`_Ij*AFJuOR857D0V<}(@2W&Cd1sP7+9BNYYfy1L>)K`VrUUkDKR1O z1F;U~+chjs7|a>VTf6rglSqLT#`#e19B^sMV>feOuJ3o7)Tk-g@^Cn&@_|gvaOx#PRWz>X=rq%*dM;TI?T+~|pB)q{G!6i|1fV&|lq(V=7@o9h84r2# zzyAdCSgi^F88<}p3knG_vD47>PXE>PfNWT(w_t+AJ$qme{Hq?)p&jQe@pBCc{>ObCr_Awmn7l^S67jVOP>R##uc`MT*dBR;5eg=OA>9oufh{X|$5Y zJifvF!aIk;(&0~nzcK=U{9TsBzhQ{}Sv$z7+l^wrORHd%1;RWelyIC(E^h>?PHsXG z^dqk1zYT^&QF4KQG?z~xvDe?2x|18P|K^v!zw!H5jNvuWuRdO~wQp0H)Ym`o!(8>% zA{*60TrI0sZsu6C)!(J?U8Z1G)$BhJ{nmVn3&BPLc|aKlS5R9ZuI*Y`YH$sI+|2PO zK~Cj!B{ZxMH(Hp%e07A|vBBJ_QTh`oXO5SkjYOQnIZ1BrJAmGls5yM~{^P&vq=cPZ zQGfsiqqyI)&xquP@+gr$1!fb$p5#xY>x~~IW8s0tutw-l+Qhhv! z%0zke0C&qN`}Wsn50USwISEppjpMJ{LLMXx5Y*L1Q5E_o_dJn`NC;FRG~F%>+~;16 zvy}My?UUs9%!8PvNrPEVmUu$1yl2k@d#E1(OYrULA}OH5>mPKXyR`VUE7t|@nHels z-n9m~m{#sE?$%WAhRN2{#XHPW&@Yx{tjzfj~x|}EHF*R#fX%2F%+U||f4WW{KZJY2$nOM6unyh=;kF2Z5ncm2wTe>Uy znf#f$^lNzmmeLwOorYZ?_m?x(H-i6oJM`QlhBLfHQ}z*w0J?&Fw9vxboOt~~FJd|F@)z6mAn#KSHH+NW+Ns`!diC+PD#k_4 znVDgxOv5{R=qC7&Rq$~v*zTZrX{ko)qt}n_?=LN)a}u!ko^Hg{FK)-Ur7kuLLpNLv zo3%%DeDaTSVXQeg!S}9ThA7KJ9_sVDBk4~aygVx@Kexvt zh#Bgo?ur??vn$cK2)hCs=c9bfa7|B~pLUacyj&Vw^8Q`r)wj8jX7AM-*N4@6@{GLH z)ILTkrQn>6?T0@?=!7q6Z@6Q<3U_MUo-**TPG!8C%cx-nP69%`fJ#8tH89-~X^vHx%Lc2AxbMty~%l)y}li#d1-MywT zru@tKi53eyJ7C;*cvzBTOagXgulWtC^%uUj?Tu}nVzt<1ea>>W3ZB0H1`KJBt(sRS zzcex@wHH-q@oc%lk%`s6%$@X=_-wD z7QOWb*{T)U5*%9a2h-E#FS4|C19EiM_kD#5?-wd&QHk7Q5?E9qyiGjvDv)OA15b%X z5W5d6rG;YL?1B=D-M7le!62>YEjD)Wi*De@!i*6hB{yw{RUmT#o1^x<{ z+}QUJD>Ai}p04>TX8E*k5VgN;v3L6^z%xksz{mF5DtjB`G&*ISU@);spP+PescgFpe#WAhgj{TSu9mHq>yT?SGM8+)AUmR4eDYpx=n#p!v7fQu+o_vyWHjxA z2=1SA`4NQ?g?|(l2K}T(*M>Y>NNe?5Y~1x)T-HBpwAp@<7ZOZ!Kk-eK{% z$*Rr{F5W>FRlsc4mz_zK>NG}`?qC1)g4W!qM$t+Ak1s?(SzqO(oVfPy{2LZC&`iNy z9f|IAmK`YtNAWx!?k>}cD7t0G*B)NXpI*M18wEJ3KKyu8Telx6#zgR2dBV$d?X$oE zbA`q8mPJv?Je{3_(Qj7=)dHiwpj13J#tB8<3To0s?;_1nWUJ=0v;OwTd4TU@eJK#O zOd-vTgan&Y9xL-T^*hK8n@t`!Mh;_DA4JUUZ@w5SWujVjn_)l2NR>`)=p`E`>I@tX zv?Ox|-*2u=EG$gi^b_Njb201N=cS79l~V7j%Rche6zz6lHOZ44|UUFOLU&prU%K*B6QdL*|IWAhpCjX(ct4F_!h?nZp&xF-C!R0k!|Gr-Lcq=HBQEWrh!H>klfVHwNAM>>jc@CA^<@bTkNHJ-R4 zEUlBRNYJD(dXE_6N(1@~= zscy(@FcLBOh@4dsAmkuQxekgc&Mo+7n{UK`J&os}*fn`75 z!46e$-ozE#r4yqSnovN*iA+g4F=*7WZQ1C?OBi!oQq&cv zs>9b37*h>i=u0~&=qj29(bsXda0w1!-~5o;J>eOq*0QA)a7}+xqvALPu~$ zSuq|zvcGk!J(zXgekna|*S#2?TRg7fG;w@o(W$>gQ|>2aFBNTLR5Sh{o>>bYME)K5 zD1UtMb35cw0Y}-IzuviBFvNuo8D+fvoT67^Y`RX!XUG%cwjeoW*E77*NEh#bu1j23=3tyKrqq$DDcpsBncWwpTF`*SVm$~HIPTG5t& zms{biy}?CE_Up%*_MElQcdV;#XH@L{WO8<%Zh{|Dm1fPywb7nW+8viOL{#TD=1IWe z=-#|D;oB(tYyIQ}u@|~Xv94;O2@3BQrZTp#+&VoSRb)m9vdVTN zd7gh|=wJ>3$0`nix5Vv&5jynYt&L(T{P;B{z(4*OYrvhy!8@5YT31>x6dU^PT?t;; z`}9hm9;QOI|LR*mOC`Mcwo11vr6nWF>RhYUpv!F*$`r)+lY)MzvRf~nAF|kZD>)@R z7Iq5Wel2|nq&i^4K7EhB`+0tGd(JG0wbHRS!K3L~`e(sVaaNbq4vG%d!xTp6VEUQ+=+mU)B5^MFAGWK@ z$-kJrU(i@I(_-!CbT_ghGDK$O(p$XZTl=#_ggkhbGHew*tIUz39j4od+hPVxmeX!_ z)V4<=*~<&_J@zu&=I3^!N}on*P4fvD8A@+g6NeT(luAee+o9MO8>*_z`J~vaR2`EH zwVU@)Q0$v#%O`)CU;j?P?Yq?|57xk{Yv&p0K7l!KmpOBj8wQH>+M8ZIAj3Awp`AW8 z(OwFBLpuXS(a)fSc*bq{zD(kYQsF_nGaU!}E_ym9pXSz&&y!^&$G9J^Xj2^mYoQ_g zTYh(vWW-<|ABQJ?*GSBB8mJ20>vm)c_w~fLmOijKbwY!>iePh2NUtJt@0A$xj#NNn03w>G|GVkyqn%5V1mX(kkC5Hw1@I2Wus`t{PTdyk^#% zGZx1I?B%ddRl0rv%zd=_vmj5J(_&!Fi;`#b-+n{Aj%-;A2K$WsPK*vIFL0E}eK;b&S z>SMeqkaVwwh`nGGrogex1K_Hz(Nmzg{((H`pYac|2_4v@&*{6Oi(jDC2G`G%L)wLO zj938eNg*)Y8U0VlHZOA=6k2n2YP;&;L(b{(t+~|2G?TShbJ!{!gJcg`eoH zO!*%RGnryvn8LKlVkCMhU0~m5jAA;!$X0I`cQ0Od{gRWLH!+}>3j7`YHHgV0%K#|* zvB_O)XKy2~YF~xqoo;A6ZvCm9y?gvWb=&~nJ_#twD-Wx7d>bICy_$g>_?~kB2Tu2Y zHQT=qjQ{quL7_dY^hfNVeV8+|8a&5w;j-(h#VfwDju9?faT`Pd97R>@nXkOJE|~Sp zZ&xs9wzug&I4YF7-=Ipw)|(YyUPnygT>h7O#=jhAMiL*I|9@jbqMaA`NDl-~BQwlH zHG+SE#?;bGQvyz;9>f^v@$Aj-n7Ee{_OYgeLQkBnf+P6W7-U_3Huq{zT2W5_mwBO0 z`k%W!{@cdzzu80o%gfH8o!b;8F6fRDlrAtFs(50$L8ceio4(BJ_ZL< zx@un`4a`MgS#G{8|4H7W=%4Zy09f!}+AjXY&*7z-p-ZRbn^7v7WvYhOHMS0mVc_+q z5WLDbr00TF0SIUxq8FB&y7D~g(Tq}NdrT{rk9*=?&wZ1+0-rb@kK<;~19~MrFe6NJ zO7`W0;=j$wBObo2W_=jYSK^c| zMLOeiBpKC3BU|AeI50k&2ORV7U68d(HMiQnOC9|NTIW2Y@ad&+=e6Q~QQIEPqBx}X z3>wz_hrmM2%Xa=@uv2`Pb4&Xh{*7^^V)L7a-DdT}j7u;65U3h&-W0hwE;8XikM$#a z+$qXBWBJla1o9>7xEEwDbh53LTFE`LJ>4Mp)Xl3wdS2kkw#=Kp-yvhI^>4UNuR)x* z^-UX|Q0zKn3eRaKwyJ=H&7UNPT;G&%hlDZ2g4*4Wlnq0TxnnFsMl=670DgqXTGzk!~P6(=*EouZ^?xnpZ)`vWFy+vcYbS$Ie5{fluodb+0f zJu+e4X@ZARc&fGl>SZBg6OMNlm-><;B${=y&&X-dV|MD6vr(%pXGr}gHt5tNMwZ6N z6^T`WS@&aNwhB&papcJ%YkGYT-RbAhZzom6Yh0z%-ca%tEsBTJo>F3|-Y*%X- z&j-6_p@3_zmGHKf+4yHg%eJ5C;upONN7gOQ0niXIlT;Kt$5L!RvmPbij+EQ1S3GMw zxMZ+#Fx1@RnKMXUiW`Coj z6!xC=J1q=xWo##sJbh8x#g=t1Z=s*srd9dmB@|9g0aIkU6qkw>;UL1}O))=2oZhr1 zhF$TjHDm%7bN{!0Q@;~RC_krkxHCj`M!1n^}(aQ2g^a!e+b%DX%V@s7LB;S3Y*_-RBa_c)@199-KFI@r5E+c~Dy;@bUhQR_@d|!P17o>jc|SXuWs*F&*Zu8{^shjv?`)~zUi4BJ{?ZVxLb!`ip6D^N zk%FsXslPGMpuVXr%wF)mS-x`Yttv(ygBOhqL^Oo23B6_coobo2WeJVjY0MdoqDoG{ z{&{(Ja3KVr@bm;77D^!eP~UN7gID4MY91;x(@S>un-dn;w{ls*j^ z#O#FwbXWmDz9!eU57x`m_~yvMg#~}$j-cHG8YSvj4y&Q$ zZ-|jClkR1&dp)*}YsPK^`fjZQIvMSu(-$iD2$cwY6I_SF}l5{Lf~G((R{OiPpTHyA*Y&WJvP&wBBo7_oM7+`H*w^+8SY zs%>^wJ7^z(rD`TWDk(3d7v}tdKZ7rlEaiXEwr)_ z6JIg9G~czDg@EQ4Ok>dQ=1hRoyFjCO0M(3P3jzH)GE9O@(*@IJ7vZ6bUcr9yyY4I@Z%K98dO)%w~p!t1}Dj>kE6f{!* ze2vl5j|&yMd93u-O5OXL1TNO={y677nY^l}_rZSmOWHgYE-7{sJt+{AP5Jm4Jww>l z59^pKcsqK#t}z#G@rS@6nh(+*Qh#dVVPLcOIR5I4l){qsKE;~#TXyOGr=dDWQgyK) zX*^{efS0=zhmYfh)A)B}7EGsbB$twbPvn^lH+)b!ZtnwJ*5~({92)P7h@>8nJR_bi` zZc>GPTISVHX^49V2);D5YxDZfd1xm(+t*IiB^Zx|8mM$)`g9|nsIr!N0-f#d8oqu? zc+$otB$^=Sf3wufKZW~dCb%FUI8(4Z*ja6cUV~2CjcJ6x9_(_=X5zxx&KXa--xpm^ zaw5;98mZmdTo0Cxf2{WN<8;zTfmhu^m^hfsRCU6L&#OTSW-gi9Y<3|BKc3*BHgQY;Q->tT<*ED^vWY-?^wnsSl8SdV9=C!U8^WiVoCBb#AsfOSSq7{xQG_dn6qk7Oaow zNbK!tT^)Mkgl#7XsISe13QkrE`9WE*eoOD%>NLad88zfSUU1H-=kepru;HdxddWI_ z?QB6B(-9d}ZBSxE^VWrv!hz%Bax>suNZCzhGuTW^UBjq&MtJ~#B77)=Af7?z-NosS zKNP7SpBJ~1SR;$ErJa;G^;~q4V1%O<$7*ikO&a z#1j(zAvj$PNIhDsqbB&r4E*(Samjjo?J%{yBOhE6*ekCsTbF}p4~*Je*ohw!ORL>X z9&+9UxZ%bxVITqjC!bz;*<^VeNAXjaaR-=}nQYNXEF-mzD}IN@k52^8kA(;A&1BRc zHuRwF-vM&sy8kchLO&P&gexZa`iJ1;wk|OU6Gv8|`DA?iRlb>!yBn^_&dIckWi$L> z(UZcQVBPs|9GZtP7uLJdrsGm_tM3=)r@Mf))qtrc=TLcUYw%%p^T^ZKfBx&O?|l`2 z4f-$Wp8DD_cru+1<(%hem}0thdhzc2W4<7-htJEWtVY_?cDT8`xL-pG0V8D)aRVtAf^NlP#gN zN2QOF^ib3)*P@9(1brfR{aZZ!womTWzw0zyqfk2jbO+LPDk;HRT7eR9^Fdf!chyhC zDT@^@+a+eOKp(!AVf_1h*F}2>2wvEs{uW^;;p@!$Li z%P{=zsM){jFnv~Cqbyqu?R_o#PdyTXzW*=_Y3X!6*svXxqy>4n>|hOwFG#PVeSnr> z)90b5^y+IFk)IIllz+FUk8AP=u>|ISkK|FPCRieWX(vRxP8oK1soYvy|1MjF17^x{ zmsXBIlR$mZDU)E1g&6gk_V2;oCM)C5kWB+k@S(KN@W{G91Xt2#Q;z>0-#JSCFZxi8;^!5lYPq}StVVAqHX6UvWoEdQ z;mN;VLvhXo;HUuH!QM9n`E6l=6TmXr95BmBM3-#ZN@~t%O4!GIxnDkX*;F&1YsWo_ zG||}YTb*#|XHb{TCD||fwkxO31^?YX<~*sxw+uVGx60wD@cH@9RFlni0KsZd z{`=Byibnlld;QZ~sORD5q@Cz{+SN3A$-Q*UXG5%GKxjoeb4Ia49~oNp z-R&Cs=-g?Ld}gIjCpcis>Fh?wK7RDc+9NeVh0T!_maOWlS>Ln59eD`i!#gV#!G*R6 z!+Q2tCc-2#)8G3Xb|i5W*tkqdp|=20SRrq&Ao}>_Anm{Qw?OiQ~_&XfrQDlx{?r2{X?y(O3A9 zfoEdANXf1~YvdARF+F@jGnfDuP+=L3N@&_E8Up>?8LXz>53G+Z3sKf|Xvd(e(}R)Y z$7Uzb($uZdlP+s%D*kbUhx3orxxM;|!s{nj+W;>&>1!&inaNdTht07u&1u*{`F*z? z;hy{1@kxodf9rGq+S;4r?DUsnRKvtW(x&m@`e)pUI`z^z_1(mJQ14g|wRLxWL^k5ygD0-e5gfD);qc!apq7OeMAb_PoD+*VXQ zEG>DpeVKU4i|0#eZ0~Ezheg!K^YzJRO!~!k4)w2eP;z`_d_hs*DE*p01WqM`sKfY; z0c*sx${&K&FzW@bLIwi2<~rW&wbXvLFQj|qs7Kjkghix2 zd>-VW_Cb=*5c-krm6P}k9Q~{NoDS%*9=!~D2e|>TTIjH%x&UJ7z2cX^)@2UwHuE(; z;9w)E(=srqubYyy@PbDu{A}TjKb$Z2m@Dh7(YUQQXzHnQJrN`iH!qOhs5c%rOp$L_ zdpeMMtAB&eJhaL}<1F4UMQFy-~LY37k{$juFdM zH!S69LbL+Qz3;IE_4C#^Q|EsLbzBSs@g1Vpp=G@4ay4qFr>#mVpb*d50<&#-ofG0Q z_QXQ-`cgRw+Sx%&^0W;+OER9CeWw(c4zYP?Dwy9$>^%E>rSOBJszUS5FLeXSct^*hnxeZSac#Ouc{0ioCJ;L(1!aTto_L=@^~JaK`YtYS($G@jc%hg`?9a zjK+C_@aPi|WqnUqAO@VlPC0GyW0~?>Q<|>GJfP7ecavLWY4iAziw1l$xgOONF9 zlV#yH*@tO+nb@^58=`YBe${Z2!jGh%TRkz{GP5dLK;C zHjY#0j;yO-vvR>bz>wP*#pyteV4Z_n$V9TTn0G00ehu_lXJ(;GrqB?!lvQabcG2>UrUX;KFdjDm+O zE!^oN2XxQs=lH%k=56oK2Syt;qAKjuUBZ%rDvK>#tI;G z+QIRa?o~t2pV|e>8WhU@sd)D(r;%LVs~Uw{Sc~44#@9DSy4e`Oc(yU$Aqy)IDV_=o z#mpz=KP@K%*ds%DsEZGg8{hQYqlAwN_w6Dc=^(EX%yVv;^o+wb9mYTUqhN_>wE7cwdk>QibtgHCqK|Ah|JA2X^QFW+@vrSM_jBx6e= z;vtnCxPG);Yfb%K{)-X5G3M=;6khdSwjtgSRc$?2iJBFUjE-30EV=8;iJZRN5#QSG zFlud)Cbb90@T8#<(8aw@ooEml`y^X8_gCwCjr%)& z?+dG}glz6wva5?vT+ZC|x@V~+hDy2p>oMEM6U3nCEXr)sCuV5njt*E_Gwp0e$9bV5 zHT5E|$g@|KmFc@@Gh@jP3y+GBf1@0%Hnqh^wxMlA8^LiF@wXE~kqUB2;0LOx>$Z?2 zTS$tL9*X!DM3-Ce!V=;gPI`$6N{>C#iP}Z0!LR}xWMpiOWID%#%@5xWQSErI`(K@1 zUuH||}MhodmM;>==$c7_3R|5m5esF4k$*0jl8)_J9 zn{)TG+P7~=Rob`zMuB%IuDe{MB`w+zx|sj)?kRT(CmHn}GUqM2H$*ehk?M3~KsG|@ z@gQ@oDHRFP?-RsE_VdpI&*nhy+V9*hO?72(BQ=F$R4DZ)FN(`H8^<@d2!Ha-&t*9% zYZW=ID0zQ|w5d+L<{``)rxXX1RY)4>1-%TRPsE`0jVy28i7#)m_kB^B`1bMRGF~D= zOKck#9ZOV6MDLhEzMi>WTB&C3@%owe5aZI;RHsQ4H<=`9Qh=6kNa)x!Jl{l1bZEPt zZ138ZzUjR62v=Nbb4Sy-LnlMrV-<9Kse*DQxAT_{o>ETro!x;bi|lZdG!1xk2JSJl zk*Yu*o$#!-4puyPEO}aaj#r^EemhV41RLwylrC_wN=4fzm?n_npBryeq<4?KaQAZ5X$Qb-boe{xn(CZy_K1eLg>8wkUy}CweSsh zMYx@I{qyIglV#vbjWVqY#@bjM6+Yvjw4hAGkEMeb(c-PSuTtpx=o5to)(H&n6OO6G z#NLPW?lGf=A2=^;CJ~H6@6DHF)zQp&wDOv~KWrYnYcWq4R1xrP*Vpta{r) zB;vFsWO(X$av_UpiQJX_fE|+-*>oPQ8)s}fEdl#kV0>65wf4}od1U_>F@97o8Y+^q zJh>@EfzlcPT|DnNisnbWx_s2BzQ@VA3DenkK8Zai-1s-+{%aN#JxPukKIu4yPM5h( zULfD&tljc69~5F+&bp?^9uc%nDpDs+5${Tz@M+(nV2{Q9Az-o=KfvZ1xtqfxktR&w z^}WxBO_|k**fLI(R@fvS`2%jb`t%<`(&-;R6*ob=kf zykfiQOB2)Q9uvFNdjai$KYefeVpaT~(d^&8i~m)T?*dv@7wg5GS4$idO0l%?zQyLf zTRnKjhSeD~BLj&Od!L_evq5W67e|wDJc9`V558Z0W8X+QNUv^gTK{RCFK>sW>D>3| z;g>Av?mQe|*;gauL4XUuiu1+J2zT$jhfs~YZ6jaWBVSLqA@AVEkDNkC5ywOBr!4vw z1+}dWZOzq9wEZ_~he8UhY)q}gTJBLVDjoUS<||U$ZDX3Vg5hCedzBsjj=tFiGj6yE z=vXF3@?RfBPVzLR4GV|kh_H>2eHC(*EzAV`^$8g=dJ-+4lYp=AE9Ky<$ghvsk26Vq z|A5x}ZZ!jYg^SX(%;@RJTn7@x6*`MZ_E~I_GrH6Zoar4oh*ZluE!p6H#v0CfA!f3Zf>slRANdVmdJYd z)LSon*=>F=%Yw5pbs{%C+%X{MynbOHWETB2w|#3w;$I))?i#b-Cki0;X2t1X_Z$wm zJfe{da(b6uSYefR?7IVy^@N|z^vI$wUMND3WIbYOgTvD2JhpsJL{CG287s!!!D@yb zbc~zfEL*W*g_fZz4S*yD+57r{y7>94FJ#7GQ@HStQS;g-ungLVcBJ5lnxfKvJ*)@( z^C+vk(NObt{m0J#aG4N%qIfN5u{eT8bm!GUdMPMzLfBRWPWERT_agMB>Y^}dsM5Zr zwfI%80=uOSTa3e$+pb&6%%-jtNA(8ZMO11S(-RKpP(!Qbv*3+Ea%Q;)`gHDRE@(|~ zfYq7#nMFpw)==Fxl5o@JEh{&+5aV&jrm>eTN&*n8ar&}V>+JK(*;=vz`(_a^_^#WY zZNbAa#pSwIOtO*uUwTT+&F1Hj7PypzZ<<)AHKyZ49hCbkjNuiADgUx17YY6=nsLmvETG-pf|BK47jq)64|jj6XDJi+6nk`yq_rcy#@Op)L$9% zT4*%7Rz*@~&Yb%BqV!SvUj=K(-)^cno6pOu$V0&jJZ<=kQ0vJ8{CAX?C+sQb)seOJ z1Ns|oMvB)qZ^PC=$HPc7c;#hYI%Wd=?TnL?Kxu`P&ntZS@!jZ|=Hq;r@`#b>So-5!=_flBkLPbp41vR?Fy)=DuGIuqf;$E** z({RB|-I&XEzy@7>RyQexGucOKiwd}1A}L%B!TUgdU_>*ChzOw-BOEp{oWs~uW_C1Y zBODa&f0;OF`v`k;Oe4qX4}k~B@ecuitHN3^Am_NViFL z5P5P&I<>njFw9#hn(B0g5C>_1PRGOexCO%I0$Qsc zx2L}%Zk23;T^8b^es93O;XrtM%{%sxYfP+#BCdjC(XX=)b8qVM z1lM<*_D!+UDAjh2g?dwIFZLgM=QNi|T1couwP1e=0;p#HA@EZ`Hbod+iY4*&bGE(R zaqLoSV|Kz5CeA@f@p9d|6_=$cbYdk9J0Vu$VE^VTa^=pusWMQN3dlriB_gT9{pCZ8 zkSOQ?$-}z6pf{fo{j%_JZ$_i)!JGRLBs3j18e)eRx>iODWs?`;rR#gXr@#8> zTqjnGDiLl*7Z$rXMz>ef2kKa(1D{ie#1QE8=`Y~W7Ix-r&pUl}K)zoy)y6=p`91GW zs1ld4RFtOj(vIO(7O176wazNWMkfZ5en2!^J6XKU36y5LNRqTu1-7^j@9o$YU+!Vb zH1gY^BfJh7BR8K8MzNp7x5!*+Xpa@Ol+!r*eyLmOGCrg0(x|5oiT-4PA6p=-3?*Db z!~pblx^T8Y%}xc;F*^O9Tn8TSD~>7dT7~Z1ZpfQ{jGUo8BtcoYRM2vz@h-t0OY$Nz z{ty@i_BJ?J@P3X=2jpBByj6^-{9Do=TV})J4C40&dBi!kN8pwL-wbPl8CJR3Zs}Fr zkP1=n%?h6GOYLwE?3dD}U5#Jn5i7`)clsJGw4V-bd+<4M>TB>xbZjU)hTphj6!)}9 zG)w*oM~%e~(w4G54*f2H$4Yz!N$OPHAt< ziJ@JJvQ+ESo#+Mr5Zus_800HW;p6YsYp?SMTbT6#Y0mxh*$yq1OC|KXRa*?6$Ma~NXh}>t5 zLNYT0oK7^-S?_@Rs|`a3eW>9+0$L$Qyo6v9jNU%LEYK-0A$Nu#OIJHPy$HXh9Tl!j zhkDwU#Qb9PhNyVA{;kZ5p>w9#t3IODO%&)@h(RkQ}P-$aI(7Hd^%n~7xpzR$;Gt#gEi|aZ0)7R`X7Rs;L3E2mjBvP-}XjD zM+^q~7C=hN^6EFt!Sm)l%=@nB?Te7CtQ-xO6*W#|pc_nTS+*lUe%Wk^`Y`ccNqGg!%IH?%rLET}{xa zWIZmG++;03c)?@z?NaayHn3(7F3zQ>U;%B?1Tw34s;mH)g z3$?8QeWvcaLqiR0@3IY9;*hAoP~W8{rG8n$d04@Uto2l*sDFFvPCNAH;Wm_`|NIX@ z%_GBNpP8&_g9HVz+t5Jj4(gJngaf9%#$95o9bVK#p{wy%UW&->P2N{sB8!=+<4?Ce zCaMiVFW35TX5vMczJ!ma?;Jg{ql5|Q!81nSx}e0S%f=d?9dnn^@#0;9Sz z2TZGiliO{DmuqIO_V86Sxv>=IN4w;}ABsl&8a8xdspCQ?dPR9059?yh+2_;sTNq|- zJ$CWyx5G^`d)ts1QzX%Ux0E5^wLbyRFb|6^{w_11Yg_cxz0zhjPqgk$Tt`5 zE$>I5-wKGX#OPy4o}302rb)1MSAK=v;XlfweV`pm9G?Pn7fQAoJB_jO_jhxt$Wle^ zr~Iz{Ue+q51(G#G^l-JILUM%Ptvy=DGo~qqLnur+61abu%4aihT&xlAi(lNNyBdaK z9{?H%&-M=*OgA^&cK9G0-m)#fR{vvQaKrMq+b~{Y=W_acFNj&M0+qN_I5Coe;1~m{ z?1IG7YhYi&=?DC#ZnPb)*4pV$+?GAFpR=*`GD%A#M!*B{)#B}umTgBf;3EZ(K8Wb= zttOchX~ss;nf5sV#7Nz`_Xx;_UW}T*=cDAzmaKy3HQOn==UFD*Y_n(jeTu-eX8_zn+C#?w;?Zq5i)Uxs z1w)!uEVQo6_JP#=ltG-yxo8c2xwuYnj#~W+#~%U%5j;CiCibeXSuSkx`-ylPek4p9 zr|H~S=7k(Qd>(Ry^df7l)UrJ)&oDZrpwrAfZLCY!tFH*#`w88-O()6S@b1!wKNAg) zl@s|q!!+m7-EuR@p3}m=b-X?#MAnXd&DFz^&^i0nsoq*JXc@bAyp(-g$f{AjVR_XuNYeI!u2UGZ9tXu0x+ zlalD5mxg|)E$@)vxf7j-l{!43b3zMMM(2*wIpLTH1!jeGPUr+l9SBjahrRS*nJg^( z=HiaJYsz){Lh>#NVF$U)behe(h?1CYMG^F_mj=)`!AQi^RWq|tt#B2^R2bOWX@2~8 zcHJ5nMlBK5`MsgSt+c7puh_Zjfo8O)_q9!)&lwI)#m!6A)T_z0b(ozkr%xrAstE(% zP2~%9(D+a*Hfeve_s|NcF6zVIt{%Vt(ZbTqIxr1|-kn!^O*xuw@ zb(vQMtdgTvgjn(BPW<|z`jQH_%Sk#6$;j=~}=$_2uRU1-~E_Ns}Evc*zkq*0V6CY&&N>PcjSz za51~#mc9Rjh~U2gga7(MM4B%}n4Ao-AFho}i4oNO6WF@;511=U#V663fb^!<{J+x; zuD`yUeS0wvZmv~O`SoywJk%NMhS`e&!s+lkfdSoG#i6QLS*OpNY?N&>V&F>;tm@|j z&bqTq(W^=|V>F~r*-aLMR=*u?&2dYOSY5A#RIh?_7Z8$j*MNC@S>%s5Qk)|9BJnhI zlRc#L%=@#!5uz9RTH?MpCE5`i3iPAmc~o0xafR#FtSEQCIk0{X%cttPx_7%mPM)6{ z*b^mf3Ao9=iea)~@y6v$4e&(#FtSedHOS=;L9|GyG1ks$`8|#i|^dL8#bh0*x2C z(TKO)6Oih9^4qG#>*-@IEji6mySECjhPtWxknVlcDUQ~zo2U{M%T%MB_WPf)zjz@T#9ebX1G=cVG9||3*E+dPLt$(b0AjsxCk?moc^L>w|3)&@a5m!{ z%?IQ;ZSP0>i=3TnRD!II)H%vceibJo&Eet7K8I}RjC`}E&gMetH?qsb z6O%pMpLgB;Y?>Y*y~fd~V?NZd=QjLZDUF0(4z#U5e17czri? zzpH_kJ4KM+eKyD1EWUu}TuhH--^mYg&9zTlg)OVg|4In(-!3AP_7@(J%z0}IYRLy! z{c;nsg;f>Qh;bil%i5coHQM}r!g6$mhp%hOHrHKbY9yli!#}ac35~qm#&d(V5Z^zdL{{g903VdwO%DxUso}rd% zXrDNX(A)fm5Go)$4NIt4B=v#u(^?myKD&XjE4g*~X6UwBiDVZ^gO1op@E zcuW`@(PUt_*f;NXSH*TvYRUK?g4tJ>QOFpI4N+0!2e10?dmQDHT9o3xX0v^gJ{bzi z7+V?SlU(uOuP?8WO# zLwJWb-)2Sg?94v|0?>2^Whn1HBq3B2gSdlxjD>s-9PGZR?`^NZc4_VVy+g*A_j)yVPIy3fb8LdLuPBCg8gGmdkUwtlnUjjiby+5^I63g<7sC8 zC@CLuv$a5Gavs}K^?^dQvDj?5aLj;E#~$xoLl8U>j@`Nx4fL_ZW|ahmsr6kn#5)V%-9(Ng_%C0)f z&Pm}UInvHdu8Cjf<(RKpX>a=xE*jVL@ZIx;d$B=LX6n*L@k_TbE~tpsY;G-sLX$K} z_w0>M{S_2KJYTrNT+Jj;fmY=j>gj!whgG-BrPrSlA0UPtILTdQgX_ZU(j}@Uf?V}s zJ2`KSW4Y7iI`(G!c6A^td(+K)wtK=3?<|kD5Up$`Q=?3Z?_fDj14vp0rYAKda7djc zm4g2zuzOoTh~GD?nEBqew>u4)AeGl!NDG~K4xgIKBZq*dYTZ1919%=BXdhtaBBSvV z*dR=C9-eZ6*@e!Uxg!m27z-fW_bj?U%s=_@G=na&*v*>CWpZ=$jD{Gwl!^ z`A#A8V@n6>6M(XCkbdT>nn|_CAa*P|?ERb-0>eCJ?lL#p7@z_N9!Z;f`uk@y>c^*5 z!?euuzv3xE#jr+~&#}a62kCta@2rUrpnYsaIwAY~7{q%-c@dp?6k@UUGKVh+lg7&q za%kbc)R?1~)iQlEKDA|ZG&>aqZlk+x$EQEI$zzg#gP&8Qje0RN;Oq-BfP2z#L6Z%( z5(@fokaklF&-cxsEK|>?%OqW>vWT^yWC-rytgSu~p^m1ZnqM1-kcZ#K@nfaI6~Ayo z`$Ex+aW+&oU8Uer=LKiT4mi$PVbDWtNUTQ0dFcwZ_?j->%bLq2*YSLI$wZ=Cqx@55 zT=KM}e`-bR_~mVA)MFvWcN#%ljAE%O+0Di~9I0pRF!fi#Zb8It|DHd*b}u_SSeKB8 z@GCCF;|~E@bnj0bajg)Z40XTy0J1|2A!;?Yk}$i`8?)G*6l9U$t_i7|CkRk3H2Z#M zER4)#3s2|S*=-A&jDH0QP)EZcu3zRMOK=E|yztZHP`-^_Wgmf-`JT_KRa**W~|M= zZJ8sd1wE(z1Ic0{)T_jxZdF#)uo`Ea;(^*&#}C%EFy}?qyV$zO@t1T@HfFkCy2;RG zRLa%8(JQJt(h)xOh4H@la3r4cQ&O1v7Z!hO_@FAsog72_s*9w+28aIwsCQf(!dZg9 z_24vATf0q3_2YeJk>)gh>6+?SWssnvf{q>|@%;hfO7w!_%LK<%V6AgLdwGr(n zH<8K;ray^jW(ytz@rAa@(We{#5a0lyj_a@4n22DKa_^GNnzrfx!EsL(n`7L1qNVw~ z4Mrkld!SGsI&{uXEJRq@w!S^84N+W`ZW|OxX%zYJ@az%&Q#__B5gXE5|go|3Bv%C zPgi#pJDd9Z+=0PNSz*hhsE<{|&Vi^(i`T|t1{_q>h)c8vdX*js7&q!#x}+0`sfdD- zDWMc^`%~%PG3R+a{Ne>$r%zXh?h~NxonFq(I(@k`X~!7*A67EtGG^7k z(mVy@XxmK?XJHFwA012~ZgB?bUF0^E{h*Ou`3EoG+~W6m_4YPDXPxul@dIzr$P#Wi z|3-mrdOsxT#GQASU-jOiCiCMPE6=J0-Y8@cQ)kA_2{#kQ2Afjxq}=_`MXRlr$O#mB z5nRg)mcBPF+)ON>o2%Th1L#-PFXYVN2eR-_&MVP}h-S!#W|}>Z?>>D@Z#sDF z8Rlx#(v(LkZ}rf|8M}ZCKcaO!O)*atm8oB3CsC8#<);5lAc`H+;5Fk&hpADin_Y{Q z(66|y4d3HP5{UI0yC3hR(cfp7d1P|$t$Ec%6cIcJdQKHBcd!qiJkcc}up_wkT4d+> zr@!rsFn=F{OXy(yLr_%$zQgIKwG8kU2q<5wdijT7 zG|uMBOUV4obtFe{YWU6I4;$FLHEXZ&e`QttM^3`uq1!);75;^<@EO{Trr;N_ zlAULEwi6<213nf(K%C$sKXFb?Q*t+!wCM1p+>m|QZ#Jy;d(*(3lDYPkf+SE!7r6Kp zIB@dF(NGZ|;rD50hHaBK%IEnYWHUnyF%^q9g9LW%-qv}x@CS$E3ZELM7%30WCk0=) z`TJOLN!$+@4P$FQ1SmCctSG`pttR z(5Wv83+)0CiUIu>4X`Fa;RDgi0iXibcr)*S@2t-}9O`o*F+klm+Sp&J24e}>Ic+R@ zhMF0KjZ>43)}z@JD^zdhn6P>{HwzB#Z=Y_sUug%13=f>HOoahbl6@P(U)iQRM*7(H zRoy^KCQ+~2^p+NAaV}RMK}*6-f`~1NmN{g+ANd`oCLy=(BZj(t;qvl~R~645Dc7ey zc=CfH$GkPsWyh&Bz5+FgOuGnM9gUV?N_C&Ygi9;bUh3jp$Lb)A)@GqTR^;V{Dvu-V!X36`<=(}q0V%-Y=z zbewZ1WE{5I*aM%NS`AT6JYIM_zl#jt4*O z-VWpRLha0-`V1ypEe7m!1Tr8)XQ*kGS!A-lcu}N z`@Yt5<4xM@b)W^;>i_+o{?B;8 zKll6pqd0#YU@J(T=j|ivz3wcC?ifcr`a|FoklQqZ0vHP?L;D*ZLl>+P?!ZDz)Zn*3 ztT=tnsg8&9=nryRIl&7mMk;e`yYUjg2{%%Mue@bc4Gv=ybnag1D-@++P7agI&JFBg zhf=hQguM%vlR~GXtZ_Bd@!+^KqeLdI#3zsUWFzTV(x((Uj`PIpW}h4_^uHm`c>VcD z(NYA^I@3X9N}+CUr)ZIX)<(pDJXxhQ;74r}Id>@n+0GpvX}n4975ZDw|9KL8=;8B4 zE#aDkx%QBsGwW}G_kVC|s@{bnnd6BLomwvJ7AhWBur9iLXvQdK#rd6EbGxL+3%jTUY^N7{MRhAnVVo+8c;##qPwfEb)CYab7uZhjLr5koINz-BO$r#%i1 zGdVc|K8y1TEq6%k&txF(zb(M%Ts<;$f=OMFKvR)5kZ0dk2_+`BKLm&om^6Ukj+JJHcODBLVI)=07IHYY$l>J@{J7GdxZfswJysL-M zHy{Rg7ao1?J)Pko&2u1is1nr0`l|>rF37qlBs^*^S@-xkML*x8yOPbjA{);IS(lZ2 zKi%sGD~?@Fe55>mIkk$D=RLR3tqaNaNIcOL+n>$6)5=v+1nG1OVC%ZH7@~IX04Er# zyXQIHr>dxvrMv%D_eZdagpghWn}c5c$ZnZOkiSfo?`DXDd92ph*@8su=-$!B_@;p1 z>X_IZNV%%UnH^RB0JW28Ci%76;@OAZ04D*pc>COfOXXeX)x29D&>37eW zEY47Bgt!KjnL4d~-#{{kc z3=bpurHXF*lGr}ddP-L%>g_pU0O=lwj9rF}n$O`fNVm$DL)k4#jyf$z4*}~|OFFLp zqfACDFL(*?U+|bo|K9Hh`&z`CT#0*#HaGMW&d+Mp1sRPMA!>R8C0g91hQd7BM7w;m zQ+$W>f2D8s0E{uEDLS{lnMHcvN9D_RFQnQJt(56!ernxV%D9g^ISr6V@*d;TZTL~9 ztwYU?OZBR`TUf%aTRQTXH zL70H(lPrNRnvmwriOyAXo!PzctIZWt_$|=V!xHy?9-3S})Na&h9dWz)&T5hPmY|i9 zV9{&$zH|QV{!d(2Q&V$lC(5Y{cD4!=I-X{ko4Ve1Xq(NAo4sEO<%<3K_jy9KA_?m&^A!mInq9f9)q zwuBlotE`5BRP?>O;&rm+y?WiSqQq?lW^LhZQE!um`^Lf%Kf@FEi)@x`ujq~UgoImS z(9#R7p6L=^8$8H8`+7d9-CoK`!R4xgN1fOS8ItfJPs(Q9g#z(tU3*+EycTcA6p3u(uD;SKupqp>B(cJmn4ge46sz zpJF}0>|;XjLPs!?vB=v&=S*)UJ6*j$+y-{|t2X}OaML;lC$oEp{AZH(9M%;yvVU^u zEG>qSPVIRvUP9&+&-P#;E03v7vq9YF zml`oklH{DHiGSV4PswGk;o0|#@Q?nNs83Cw;!OcG(M_^GF{MoC?&aA=@oaUd-e&>6 zFN06auRlIII5IURy=Xwuq29sEj@N~d(x3fz@43;QKtV0n9SNF>k@5-GkoK59agt=R zFW&NE8Q8# zfP#;ik1ShR!&WS()X3@Wb3HTRo&!o(=OG{IeDb}A{ej|MBmD`>wbie}grT&URg+Rm zt~j}y4}s?(N~GS*dUv!}FJ+10m7QL5s?(eTc#&86NNDKuhsPTo6_s;RBAEDUyq$_u zb_#Mbk!2Uo=PqSV$APX1YiH!>0y8$_rM5<)A$OMH0Vl{)LJr^RNiR2PO7Tp8@xOo3 zN4vD_j2dTVAy@Gt{p=0*Y7gVskdwJ>rh6mr?`szmpDsynb6zcSZ3fbf(Z-?GN*U)l z-GQrAbz{&0pDLf{<|!^rO&hICK4_h0LvjDks=n`AeQmvO&%h3ZauT!q(MIxHFV#&P z@p_+cdCJ41baMv3O3=u-3t>q*$Ft52YZ!jpR(Vibe?wOMZ&KbzIusxJ@jl`(7So(5 zOiq8hn38#kNGm?L%W$A13qBIM&$2+l2`mTBn^f{;>Hf%7PAM zV->!VdYNP` z9P&1kk5!#!irG8xlHpf#$ai6~)z<+>T7P-NN^~;tN1USK+}Y{sT^KTuiYCbKLFeApg^XR6qmi9uzhmUQu!f@hU?DWv$^A2tApJ$&HVjzo(8vz zqvRD3F;6H7Q83dVD{nJadV+861LEYn8wa183M^4WPt;d!WQ=@PlOATI0coBhoHzCY zXg7|%Q8Kw{rkP81#*guR0X*tD>Jbl@2Sv-S7FH&Gtda)I0bd07ID5Nhyra0KP|tsW-XH$O zh{o_om&~YPIy{g)2yZVN7cpSBk>${tt`yFA#yu7yBujfh`)tx*b^lrYUku9`;y&-_ zqYS3848ws~Zvza8G6LHT4)d*D75H?$=5dFa0IP;DX<^k#vWN)4DXAz6YzWxD3kYuY z)EChg*|)Q?dZt{}OTy2F7Zz4pT8i=E*Q0NSE@fN|wSGAzQXd|F#gPsTRL2lv+dO&h z*CadhmCW`ADS*43jv+z_x<82BeS_24xf^>uc5r|gfBY2}^M94H|NB<(U$|0_x{(V1 zcXZj)X#7nSt;>Ee%(qfB$}oIno@7$PNvu?fH9PSI?HhF6PM31qA>TK$j8;IP$)U2e ztpqfEb(0YFG?j6j5*b&4zP@cx~_L40#)+O0ZC7Lawh2F}P*_}WM7_s`}i z;qE__BK<(EG2z&@3u)4!k&54w_S(?opUf>#0p)XCgMKT_+1WY*Nt34wcbIA=Y7IjT zYHkIBX-vpo?tEO0%`0P(@!O%D!!?Mg%|pX-p7H!zh&`WPHZ-*H)Vsr)QG z&Xuh}A&91E?$5KaoQ>siv|_*d7)M>rJ9QD7sMuRa{7qK22OWd)fs=D#jcH0g4X|vA zW6WKxj8%2VFa6wa9B=uJS_vZs(>EriHF>I70bV&x`E0>AhuOcY;abT)PLrP#j+LH$ z6{4wBflKe9)f4|h`;Fu&q`hEn*4&}ld;OFChZxnz?EI1u%8C(?X~*n_p%-?7b{G+J zwQ()jO-LJy=;Z{JbZBu=1&ZZWtn0h<#7}+K1CsHo@8g4`1rtJOS0U)$;`>19>(q4e z?Zk)0pX=tkEzethy};Wp2N!gW^a|;+h)u~A`c!ThWtWln3r^c1?qu~Z!M;LuP++?nAx6i$EyG#}GUXNY)zR?8D zVq4_x)~S!S7y3fF558ZB;cvKk>E?`b9_;_+lO9PQ?lj5%rrS7$fT$m6+ImL`ud5X^ zYH1-YoGSPb=|cS+cTDgP4Hexo<}4kA_F}@2VL`gbM_ByL$D_@9&I`!_`Y(uG`&fCn zt@B-Q{*pn8w!e?(fJ^1EIcJEVZ)tYw&A}UhbgvzdmE&xYiIZaKOpVVvr|N?eCVH)) zD|7)k&(LclCi~Ex?<$Xy1H~~eY4g5Ts|`zyylY71)??HlXiD^%#9WoeVI$z)Q9o52 z-R+^HlHo*D?<{ZDB0y_x`0G58jmM8K^lZ+o+udPaNvt6j^d9G~hqCc9@f4HLv`+$f zE~;8dD!eD^g>>l=AW+(!Z1CJuy^*uqx_3t!eEDP(4fhM#9i*~qbfyLu{P#ZL5Q2@t z*8a1XK*9kOd0JI6Wc2A%CnBh!jssw687>AK1B04$Cr?DQ#$OmXhxu@ zo-(QzdZ!Nt^bDu?N>wiri`~v)jy1fUGZ+W}3$i9mkH&$q)omsN*pc*u_>3s+Uru{3%0JtL%sZ-*I9^5Gf zmjlPp^o~=zblPv=We31$p~oWkAvd?sWm9w3m{kN@;m>CVv8GW?+pg!@2`+gmg8d-NHZp^11X+Q1OOFWgz9~Io zY~$pGf55bdPipHO`B@Rf6=HYi-$Zf2U3*(Q_Zhb!u5k|oI_@2!%aAsN8JwQQCB$x? z&s;l0nV!!MWuJ;x;n@dIArHRW>HAO)qfJ0LEp`n^*`(L6(rci2F7KvFV3`a|s42rM ziF&2R15<{p?td%CqQ~AM#<4swN}~>of4C3ON0Ujq4Zp#Z#!;b8$6APJkX09%ezUoc66 zGJX%|o#a<K3+xSjx+jj<<1ErLR-CD>6XQ7VZ(5mKl22!jP|B z`YQ7AD$^y{fj;Wz_qFi-KMD38w@VPF*xC-_fH57jT-wwBK6IkhIn&ge5^9eTE){?Pg!-rC31>_;MpSlag7#ifh)?npIfvm$^0%$^r2rN9pR?vvURQG2?G&*_1&iY9oar4bmqA0kR~Nw6_6aLxNQrlXtN%nX($2W&%eI&m@9e*75U zNTtQyj13LsYN(z@8z6e;s2NmOIt&Hi15PKG>vIL#Z{=4b6VDUO#d_W=j%_gEAr4`T zeXv3u(ytXzlC69;(l=@%3&c`&t0l*reFn?nW{1hi9rY$DFH4syE`#7r zRkk3)qBTt@qrN{|7dgSKm{?4H0(BW_W@v=eLeBP<$CFVPd2Lsxqe}pgn(GVD;FWrXJ`va7M zSae`d?4a3?(;?n4=(A^WLv*1_Opt+afCJD1*FB1`2MsXGygXleZ91`9b!kqS81ecs zx$5c7qt-6OG1)5hg9EFdt(P5$9&{xB=0oLTB88p2PrJ=8%u4C~x}vDSlT^q9m}NPS zN{3=a8N~NqN#PoI7Q!IuK{N{Hnb8edv>DX_rS0a(`4P^1!_z2aAjS?^W)weHbGdj3 zKa`c=F50~Dam0eZ@6uDY{D{suS*kw~m4PfSe8T|>tbF;X^`?Jb?fmx*H|%wGx$`pi zD7aBQ%+u1gcI@rL(MoL)D^eZvw$}paEc1t&kjqoDCEasY5#xDLlr{Ua!KHvqna<~8 zA1~#(l5o+&>4ubX7 zNn5%z8UF{vQia(N(MzOQKYgGFDVj|Lvg^Zh`o31hY-2OWIA+nfOM;!hr1b!%Osyi> z+I517jHg|_N9(>59jw0G`1i#g(T6-{u*Qt6o+H0vKR}TXyUM)!jx!s`xV-PXJqiJN zZT#^V@i(c#2N4+0*`2=OalQZz2@!FfLOWB2cZkT9V zhJv;6__drx?p3v2(r#DPeHqb>LwE*#ShILugiiQ5rq%ej1kgMy`yf8=iMNJT$C z!q`wLgdM-6kAnRS#eeo#u(8i*_yWzfs+2A!ZqVw#*BVQ&>Lr%H`L$$X#abi#78YSA zT4lOE;@#bAb{gz$131fuIK%euNK5|+8PTo4O&OZ9-_=*aocM1lpw5L2b>DEgnFsGE zcl#{)ZUZTcL@9(Rg*LWXRwDQfoOgubUBT@7b^~S1q^$+Z`B=?^+Ve3J|$x7e3M%@@wRdQN9RIV?_A<6<~fUDHBqr9}^c1IW7dc z&y;PCmGik28Ui`l#^bq-rJ`^y;wS#-@@ju6=9By*P2i143$PT<4Gn1@TTMxxk=$E| z!7H?TfRLfHdW^`3Epw`&rjy1EsKJgB=%fPEC>|#SkN(eUD`@|P zuqGQ$$r~jlX;*G^z=DE%|5Dy+NR}pTH<2)TvS@5(xYC2!+HCx+Pf*|(O)2gsP1xMG z7L(n8#mB4f9kqUjo(`C(IKsSS{KN-N)2@xoSci?SNiEh{Y7?Eaz&Nx0WHz)V1u*r@ zezYWm*#GU>Z17dbQ*SUp5V5+J5?g@qIkP5E+Q2>uHs}G2BnR{66x-dUd-gZi^~27#QgwbuH{ItTnGT(3J4 z##*%qs#7kQ2QDZ8av{c9+oGR$+MUa8EJ@)3g~EknZ^{Y&WlN9n*=&d!5nG(!vv&cRhty4S=mKG;Ha%h}3e?!EKsU|%w}`cUQ=ao7rusnK z38^gizJyn%kBt|M?3!7QGg{>%j@Rngc0RWAI4pN|rziMHsT&+tF34^ncfT--e|^C~ zAHr`qmF4)pgK_gF{5#6B;ch8y+$$a4YhT`$KK}6gA%N{s!WcnqpyN50T_Zg!Q@k%W zW_&=fjeZ@Mu&jfrD*y2iShdj5O(%Lj=I$ZB@+tK>@0s}1S2EwiSR0HDQZHI5K`q+x z$8ihQ!#aT%D%Xyc=_{Ft;c9fRZu03Zma%Ti<8K>X876nA^WQmhYF{1A9htF;M0zOERr9Iv^YHlH7!$!FkHFuQ%* z5H2!eza_<-GDa6()OLfD#MS_`;SPLNzFpv)t_?Hm7(&p1Y`R4@xITYLv?|qBTM%}D zpkZ4zJsKTQXUPQV6f5u-E~*;CHMJG?C)ugFZf zli0qAq2iF9lL*%bq?tMqe;z?StsjiaFMsXjdudy!m_iW?LemxUYBPO|4qiUhP> zU7dshKU&{Ax~=xbee8E_ux;Yo&Nlq;nJHm_K_egQv2-Bq=`7QLJ88Cs{Z#K}3bL*I zw)`(fI{(b1nNnoMisnJ{M>8Vq|BA{zlRMbF_yREL) zR$x+v@kQw`pv4ys8wrn+!8${>E{>!6copYGU*?@lju%-feI$9?EQj$1PVM2`M(0X# z4rVm%bo;~wBC`@9?Zb0+ml@t`)mmf22}`YNybsk&;`h_HeKs4j*jCf+P>t3qL8H*+^y)bA9#YrumUQESmiC8tpcOT2|FIyFOPia#_G!-|j>6c?oK=b8G+b zK7M#F*n|vrn>PZiUR&8l7`KU564) zw^kizJ>gy|9Jx>xHS>>4Ba3MlcKE%tNB7)G=pKizSt6^TWy#Z=d3vP81@Y|TO@*zi zL4;xcb(1V%R}yXZin9RPnU5`C3H%=6_touW*;>4{RM+U9*`u{K8hsBZV8UfJzp?;FDgM%nU6tUi4mFRbn?c(5D)iS-CY?gS8Qe%wmwl2~{b z%b3NYq^mF_(nY-nWX03KH8$95G-L)my$w_vEN z* z_2BzMp+vdeNDb?evdriACR>bPnotPqh!c5&%F1u_9|jX}z3L4F^8a8>RkD!8vy7~1 z6!J}+8~*vmk|Bw4C|ntJb|_tpZAEW;MM3ddK%OXUoBn;ZDri9_5es1SL#agYssEz) zus?V6c77slO9m7MBO#_WEil$#4pv3x&E{}_gRA+DOYVOnf@32un5e?eQA2;i2u+sV zPu>I*!QT$wuUVVdE)u^}mNaj(rA@wgp;W>s)Na)}jNYruhp^3LlUlqJa2zm-E6Mk-jq!?A|RW z(&^=@S3ixG6x${hf~q@QjlCs+ugl!aM8##3LknZe6kP}pmv8OfN_tJ#B4_%G$m_^7 znMR)3ODxf|Sodp4(q_(@?}Sajb$H_^yKyAOUKwtopY!im*R#I~bvzz!j1g-iAQ@ z@j!CBls`P&hihRtu{zC3&osUKN)!ZCJN3!U!{4}UJ{LY~i6SGJ4w2Uu^OvF3F3PnM z)=8QlbXvKwhjYvvRD|wRbFa_fO8jBBp_m3_uM$1c4Xw#6DdmgT)`|dVsLKZGXluig zm|`_fL5HUv9pw8fyoeuX_=X4wZxGYHQg;Ba>FG|^`m$_SigPvBLhsTm^G{R4A7ZyU zeb4&1^H#Tes+G@k5;p0`#mb_pn|(AmWzi ziTa0G>_+hnL|utc^eO9k;QI%;Xw@%S@cuM`==NMLL3|TA;pna{4Zadq*A_aSr+=O` zQmh3t8L-gN07&zL`a2a}?07>=vnren2sJ#G9T{7FE6PxhaKc}tf!kAS-dpkWD9XiS z#mj1xn_*7qT0$t)B`1=3d`I(J0!@f7kxEf1?ZpqNwkg@OAnuqSu%$J>*-}@L_!b!u zqVQf7DUPtIFhWqW%(TBo8cjL%_C=%JI+JtI=|^TgYCVol*~iNt<-q_qd{emF;$kt@ zi8N;iZt{j}qgPBUw-kpb5Iz(i;ox0j*qrbe1MHD6e#^L96UZ`DovG_KJz_+|?7hC% zzo2ioFqx>MRfr4Pm`RcVpsBFb0;p-qolI?6GSr}Kok7Ul<5`{kcI?T(*ZbFNpZPC5 zvQ*cXylyR7Y08w>`0990Z?lQj3gLQrDEQQ;loeOa2>vOi63goMj?6Pt`}$_Ap-{aJ z1*&T$szTIw_1u9MWlk4#-s?K?Oqa4%!}-^=%(Df5ncCEbyXjc%8J;8N=#Md$K-)#k zA4XCg_;fdi{ZG|__B9aR=3t5NJ9oycGhzG5FP&E83-NxYQMUa%XTt18vnk{2T$hBA zft-k2vY73MOh*(BlKU*SyK|j4!jqQe3~hj@P<~+0%#~o`ZKPi{=`o$g4RzXVo%R^m zxe!&e3cz5>P@VyY)nrq5o));>eQXHtft8KOCr2y4|9=#^8Aam-{OE$|XtHi|OtI?oWFv(vkfC6+%&S-rAVnv$L7VRdeylh62~M)^ACE0C!9X{ z&EHqx%TYf~-lV)x#(f@>n~0*1IOAqKfD-H9zV*5#0a{bJUJ0dF&%RA-psdSkZejYq zp+NDJXpsFch8=2;F6|Phk)I-&_tD4stOW$Ib zyB;a@|I!(R`qQO#gk3`!=wUCbh^l@R&859jTZNAQT~!;Y0Lpnvo*h zyJa|L1F8H)5$5I45GkV#DE@#IT@M}Y!K7WiL@um$wlT!}@;MydL zU*i}elqX=utBK{UEz#-{+zJ)?od2ZHHL++`C_`1MlzV6aiHlY#b*&Nzy+qrt;TtY> z6U-FKG(g~Y^|>rH8z54+!F$RRo#`ufmGt9d3lgE~oFv8=A>C*q+{3Ao$y`Np-xnXi zSo!3=0DiU4DH;!p)Ag=vm12$^=vWp_{cU!YCJlGLQ8(W~jUj_-6{dLQBaYGE|3ck= zgl>ZwHe+Aen=($*t?z#C%syVV=Hf`l;*@KsiAsg7B6#Mb{RwYr&3(wkt^sWbV+eETGCXH z8OqgUded;caoKRf0bnw20X~2ov z4qF;p3tMyIRe-{mN)i8B6JzYs!O$oapoUi$@nc;Uw^K;s7((skTHF+>QXREwf1dwc z-iPz%MO==6b+q^>{1$z*MIzjT_b+z6i@WrjLwmIi7RCVw%kw_j$C}+fJART@sa|Yg z8`0xVnf8lnC(r2Bxb2rJ8?iB7r=28ZD0K9z)oWulsbX3ut?BA=NG!+BCL@2TOFepG z`*B35g(T2Q?+iBr@n?NnB2|ViQad5uwJbb<%)!^MszY!m3v#2IpMda@)3Xw@aQ9(} z2XvwH8&r)%&qnUclDQjB0E9tE!FBH_Uz~9Bq8g>`5f273K-Svc`x`gsbUB~Voz5}U z2S1KK=Z-PoySL^(YK5#E>Mfuy+u3D~8UhXj-BWkwE1Yx|t-Zr_{pMQ~WZ)bVu}R4x z!K2Z6E01}Fq=^qjxv#S*XVx>|00D>UikDA~5VhvK9~DrxyWq$^?U`u1-dhc|b6e|- zTw4HRYqLmb-ahfbaDtsLnw%>5U@Am#H{)%LgZp@!i}Z<(i`NrH?z_f<{_ws{*AgWP zQy}rYs$0An%Y3Pdg<-h0tWWrW@QhnQa@PmFtEMf`OBBt>hWGjzYe>U9Vo~vYyEc2q z)yln`39FSayqS5JDZxqb3%-zMY5@aCYO?~btVd|yMx5j!*(Ic=P|J2JxqVdA=ArKz zVY0~*TfNT13QidGF?FEzZ?2o#xccDY!#sZ^1OcA#28w?1rrN{_u9!EPLu7oY9rstq zD(X5kW0<@g(a@Dt>pD7@=X~)lIYD56Bm$1f1N(Ry8cw0%Cnxr7qu|SYff=)^;0>>E z{+At?0m!wbcbREA+B@>w1$9MvmAEdAKS_!ZE1geqn|3^)#Uou^Rm2JG;m5B3NCk^4 zvWW^|OdCWS z%MZzFt9ahrMtU*$L2MIYhwFk8f=q^wl&RjXeV!e*@o_f%-qlYQ+|?%#S>v%^;UEm{ zq-v>crsc5=>i+PnOe-%z)4ShD=%l`7?!rmX7zPZ@rot?K>ZC=x!7VS}KJoc2!>1tp zRLkY~C>i5T>dh$RGPMH7d7}An`f9ph3_5!@0!c_oO0uXTgoK%;E7m#M{zs>(Q`7d9 z{r@}}1T7_6*Zv>PVh?B{nK;S?@IZk3e%M5yQn}CaY&YRk;}NdDUIriPKLc1HSlHoA zM_7;IRrXD^dS@fHcRou9ZC`_+zsvq&;DNhjFOFDI*rJHZyA{@!`;^ehL2EjoXgZ^w8<5*y48Cijj<`TsFof*> z=dJ(y|Kpzv{?9V|=jQrnOZjIb{pa}j=g|D8RQP{hAZZ?W2bU$FOS|v6*tHUWNAx_7Rg#c}Zfu%iJ1^G2OJ&qgsE*QS%+P z!MvyWyB9^Pjh&eV{;pRzeZ6FU8TUc6~-97xEWEfjYrE2F|u)`z)I#QRVfs z`c;v+HDB7ydxHZV^?v#DVaA68Snj2t5uBJcfq7Vse4oo+fBg(59g6Po;bTR+x!%_} z4IN4P;?DWu1}K10F0nYx(=p92?85WGn{!MJQ&x*R%L-)4UhLlm)GGIkq}zfqHKe~m zPIjz(c=Drqyxvu^FO0zFkB;83(*7Q|C$3h$;qRMpCvh#|=kGTdGyaPKz*_QUcqV$> zrQ=RK_~R)t`#ItJ<72zpnGJQIeEV3S*_bF__?v~FL9*8U^4YskfP8aZ`D6Su)`dVA zQ3BO_Ny7Q00BJP#U@9_)MFvNCHw71(*X03SYSuh3+XEi3=r( zB-nS;S)6=q^UW-;Rv9)@GRt|=;OCA)8euZHe%Ryg1DS@wPv-XAr!10i4PYX#A;@q#8@ znlXaOI5hHf_r;jWi*o!NcvW0x-HSzTMniC$6(Wyst4dxr(g-e|L1O&+D`Qe=M#JlUg-LFv~Ymc`y_(<~m+q|B_zi2dsWbB@}?OwRWUo zHxsqS9A&SpT;lPJ?q(phVa~uK)-IVBQ!Z9N-XX%zEW6MEt-sEz6h^?(%HG0gp2f72 zzDpb30%YCK8h9II@DiK8l5x}j-SAnOD3-Nh_G9C^T=nzzQFVn5-He9p+-K5Uo`O$P z^gF5{fF$vX(*$R&=4o~`32VMZXl&fpB4ULcJwy$eTzI0rvM@PAUyM@&`SacDpuZU3V^mJ% zH#B1c@xAHRl4~|&DG)3UbVqG|Jt*GlQ_wdjIvp4{kV*$Pxq+;K%_2+Gf(_*X9HW3* zat>5_b0s{D964)^s4iiXOJdh68N#apb2h1FvH6|ZAG<9}(w;m$l?`j>u%1t*>PEKz z=w2&@<(j>W?CmC06}JBX4vUDEaD|4K-IvBCC+1VFNX_cYN}(77mt^aedL4`&I9wuR z=n$fLaQ$;YU2LZrewgqO5csLUq2WmQx0RUWn)1h^wF);$^Ni2r?0rQqxvsD6R!I#O zSP~3O`@VzK^uTQ#$rrM|1MMMA6;>Krn-%;exMHd@V;tQ|gyaLg#RD6zZaoI^LFp;S z`{V94(Hn)}L*7H_0)#5>yw_SoRIBJ(4xzWGJ|h2gOz~_r#%g>$*>Clw{cL^i@kt$l z+M+sq5nv3WnPo_`NyQ*#zSu3$r4IZR*f7%1bt4+lU~3J6}zD)eG;Yv zIen%S=BK&{Ud-^W@nDIhl0KlZ!5N3pZK+DjAevonIOwLbn06dsfq_ep;hy>JJLgtY zVb#r2Rofva!7fj4IDF)SZg^51@~vQb9&kKoVx)rmXwI4|Hd&Oq}Qtm*SCr~o$QywJL~3}d|eM_ zBpp5kRPYv|(S_>l=N+~Ar)p-bOYai2V1F^ZxCp#(Jmm(}EXO&YRni?cZdMgO-4P=@ zgm+GdOgMn(GrxF)$0*#?O8o+DbB-u`e%*S;EtYJ04n%){8Tv@kbK6aP`zzcb22IMg2rQH+SsB%z zWcO+B;C`OkO2a`10OJF$+aY%@5036+3&4?vpjPaFbu)zGB}86(_7XyQcYM-yeb+X! zy_4&a>{`0OX^%y#H_X?P~1aUHIX&Wo`=PtmH#(bY~r2U&IMlpiPxS!h8zg^iZ1DsMr zdipV{LfAny4!GMhb^?ZuB+^V|d?KoVogdw85 z7{jd(0_q-Xl}Tra1+ixWZK^de^E;x@eVczOx@y{OEZfCveMp^HcR#mAsid4|ZhV z1|M44NFHm+W4MrHMc&|^qW`j(q+c@CJ`)R#KlE(^^-Qw)@} zv(z{tzfLCMv$wI`9d&fE=pZ0P#8|+l>^y9f5c!&p#NUQ4rj^|WY{XJ}r#tBlQiO4( z=(fa&*4NmDq-1nHOJP~X5^_9a&$&bqL)C&$8;#p5BnUC_+=6no1q#Kc^*E+>@{dRY z^5PTC?bz50DdSRlU+%gZCc9FmMZY&A+{osr(=$!nD+CY+6^|DlmfZ_8EA-DdT_{ZJ zu1bru9;=$jhJkEXsl2Z*fo_}&MSv& zh$~0Iin3p@k-(ZDR@jS2;b(M|XK`S8Li8ieZ@LVI20P$KI)&nr3wO+%GT0I<&P2hsy;w zyV_};?zyo(bL0*lp8OL<6jk$dE^$eKDqb9#-Gf+yTO4q;a3t<4x@n~dE!wG^*XL_Y zxJBo1&PWPgw?ey+2G^c6){Ub8)F}0SF%*>K4l!zpg8G<_xtEQ%^BmAJ#L?GHv~t=2 zIa800>Oe&QV#>7h{87WtrU-N$1*EP#{xu8z>75q4VdzI)Ll~^rvAg_U2P_+(#3{Nr zAL8;m^?f`~g$Tq;^EOv4TUJsMnyD>$H6_DBnAS@8OIeaBkeO|DpvKI$D$}p5Byl`2 zwW#BU=z@@-E60Yfw9R()itT{1qbE$rNgvKjU?)S{RD~`Au%>u`vPWW;_d?vV$1n^s z1}cm)-;JiTrcl}deQ4Ft-ujXyyF_(GY4LgQ&~i~O8N1yv_;}U8BVDv}tx?;%`9n4j zFtL#Qyx7fTpcsCVXE3wSmIQStTx-v8AwwJGS6!?e`1YI{zhA2zBFMmsk>2IlX6s+b zwYL2E9mX9(X|1g>H@)P~OL>+lW}U>?JFjh#SWOsKy1Pf2HuMFN~n9vuDLDmDw zvVF9@mmD9G%~X#I6_5PvH_29=?H0z3Or6d5$~urTRJNcH@ul zjW*%vNUeIlxFpTnTROMAi`^I~YNhGqGg3YKvwn<;$-VG3^NIX685$~FY;7Ck3SDpL zIl&s*MoOOrku|@MdNX-tsG}LPNRJ$G;Bp5L%XT<3h?U z_9hOna3K3R`j7a+ihed@|NZ^9W67B$F~2@3)$2OJ1-|%c#TT_kN34fOE=Cnw-QuS+ zQEiz5rSXv~+S5p={>_EHrBYbCl(!8^o|d%k%p@=1AX1I3V*8Wi?FwgH`*C}C%RNW5i_@e7*gf9FQpvSRIGQ0zafh?i=tyfRCkNc- zGtq0#1f{HWK)T-FRILwj5C5972`SFl+aHltb4xW?5j%Z|m+Y2W$c9B<^9NPqj-wf| zbobjCdk#B-G7{_lRn0C$NA@6YrXAGPF^cz6rl0K;7Uk|y8elZ1gR&n>*d2t5{>AtT z)gkaV*vK*OZ|98?JE<@d&Rkvp27cMVdytj2bPI*y# zO4qnQX3;HoubTf~jN3OIi?T0%k6jCe#^jvFfNq?4k78dM^d?UJ#rU0qPB$RD0(GL@ z^y)d#W?>J%qw8|QlwuF<#7_QVJb}5R>9L6*M?`XVle%mN+B)=AqkHF8$Cj7y1)8ys z1=)xtTU_U9G>?+1{#orc4wT~NUU`ba$e|l zopI@sUGzOg@sQmz#BOxF0&MKubahF}Zkkn^EhdhM3vRpz{m#dniU@brBwNqu**ItC zzz;OMQ1@9h8we6({puQbSC1L~`iw?=6B~D{ViTd>K9D{`D>;7h(&I0NJ?uKGT208} zx|eEvNxsbhwSaYpcj<?@oaydj=I<|`^sB8BDZkTwIeOZts$x6v>Saw$(G)yLqC+M*icr5_tl7t za42?KjHjS%*SVfDFPRR0g-!{Y6_qB#^;p$#g0we`BPdh-P06S$5vi&K?4|;dQBas- z!f|ZH)yRjv=2y9;OmaS4Lbp8T-%^9qrd~w!xIMCHV$8H5y|WVY1N;Q9tj6sPppU7_ zl69K56Q&1!rYxe&kFv_sN4v&AXFeZp391A$*{$gHY_+PCki;9DnX zMi9g5Y3LGYe07r!`Ml;Y#+Gl66W#3%T|XL0gYJN4|H!TrHvYxP?dX$5(4a%4{#^Rm zq7l1Bl|FGvv8j)wT21oS@;p!m_Nekmgb4X#**%xD zSQM@y8WNPIU68#vmW{m)tujNCE1_r@kIwZkhCC<=bSg21UXy#*6X?8OS0rdyIs#?$ z;Qs^l;y(6{3TcVP`DQ@KSfzS2=oh<*GCwr9KnJ+f{ZAiXx)!v%1fshjwCF&)6`Ikb zeQRVkQ6YaZ$p2!j0nwZ^#)+eRG^n_V-r`dINReZAx41}#8@fwTME_q5Of+x*mNxdE zOYqMn_-7UTb0hq-7yPpw{&OPyb142(7yR!kjlfr7=<>1nKgvf%Q>Yba-Qi=MH&VVF zUOx_hRey8mSvhmVKSI#kqu-n75l$=qVz?SJ9#UDx{)ZDH4(n0Z`J(0NX@6g^(%`%` zNIPO8Sq4E~O8jzPqNZu}*o^o?_;&)e&|&*dz@PK%y?MmRw?~Y{_tTfgXnhl-zbqn_ zOblITnt)Dg&TZC7OhMtyVajJpyrD%l{9lG!jz*WRM*^FKJpv7bKy5AqIm+nx?Uw`T zH+y|jyC{D%8d7bcXpTV8l`1vK8l{G5e0=L~9F67Z#u zv6T34iEiJaLB`pAjfrFRnff=^4Q@$x&_M4+55*_Q+GTjR)B}fNrr#4Mo-KB!h8FAC zR4o3ZFgk5;g@~zo$><#(hVqJ_}RdaKY3c7)El_6 zM^H^NxTy&A@2FEqt2Q+K;-&3^WKFUr5M0wco}Zm$No;Z6qY{Ok9-kemU_%Clv&)y<$EsAt@K4c}2z530)XygZ=GEWn+`)1#liFUN#? zlUc7Qy$-x?2C^%>m@ZT&d>4}fCL*LA=a-tFFtxEPJ+pf0c*y@1-)4WZMU&_3kP~1s zm?wUsnV93z^IhCHCL?1pCd(GTzcShmC{VhzYX0JT$dew&Lvid_f7&VR%{kghxFf|$ zrKMypU;lP=cfP390~>yS)vg)o+Vmlkjy1}Wg7*p(oQ_I5`=JUW!S{30YvuK$E%CD7 zjx{{An99>u?un&1GUM-?H<8*65~Qv#xFy-wT=8YAZAu7KDRh@e4gHZt-52FkC|AHy zh+G*po{YHovZFTIznbn@SabmJ%qicSb+xDDsj2_*yw@xK2vb3dH9=i{0CiOCEzNha^!d+ldE>-PjFZYzo3 zPmrL~XLzPK;0}02Zydq_pgS*ai|9-kN;iqOgpdV;sfTJuCaDtr z^Ia9{l0ECWw9y2LN-~aV3p-QXVWEHsw20FMo%$iZl`r@k~pS!Q}Aw(-)^?~$FZ@*eby;0xeFf>9cF*Z zoJ@5Mr@si?9_b=sR4USz(B871CM4|Qa<+&@YB~lh833k2ZRz7aV*$cQ?XTG9}k+{WGwxT+J zAeDrtl<1Gu`1IAhUCH<}c6$jYz0c`Keao8VQ+Z^VHGy>WUC7W?(!G{_IBrv#tl%oc zf41*dVd)yEl8kUcZ%w<`zjiL!tbP{!$r~JU+17f1>Gxe}BlR|$D~B%^*HAK@?En~S z!~7HBb8=i-x~^*eM$&TG9;hE1)aGN~!>l-=*Ja8yUsO}JF@np0c{ z->E;c6$Jdq8}u$=h?|i16DWDm4w&Yjpc07Ae;Rvj5=!9l>pV~RxHsl& zm$9fxPh6M8$IzYDp#2HbpnBxF8N(K!a3~=3w{`pHb8ad*YA(u+w5EneW}CJ&o{P04 z;Zb3+{?B$lqu#f@-YIIt`!0uf^wu;%*5?0=19*^fcDD+0j`p-J>WgbNXNLQe)Qm10 zq0`Si75;ffYmEo9pkE!{qh!A0v2p_bF&bHZ_Epb!*~n(cH3_^0#lN{xW~qZP6ENZqY1z9aa(Q zG&q45bA8a0ckq6g~xB5?n}l@saGdR zF>m+vMQaP~ZY`U02$}07gRDBv17{E-#v7eJ;Pr?iY(!IR(-Nibi^G3KB8- z#86$u&RojO2d_WC@kJS&$+i6{A0JF^*Clk#CW$X+gm@vYIkHhjHbcY3eJ z+Eq`lEWqQ@_N2tiQPEuqh=f?Jn9A9-n5rJKra93NgIG!h#>+jV(h@Z1ETpv9gnzHl z-wG|15wc_QJ)SshoKP>b;WZ0uof0X^jaN3-RW`RnSKb`Q3cc`TqgPY>dvk!|rRJ@; zMeL81d+M%*j|EtH^J0)H6%fB99QI7~ zQBn)!c_Wn|LG0e$KO^uD6?6Oq!2s2jtQOerc={JKtUYE3^EFrpfetYn8P@mMD>*ao zLENaybUpHZ@is&lL002YC+Yl!7rvn70vZlU7jODS^ds|dF<`RDs5yFipdyL*$fSzd z{7Y1MdPsJK4OYE}jFc5gAy|r$^$}g zjuUcuhT)`C*KT|qim(i0*!1$WDfvesBkZx~ok*SzTn()X4gRmu0`7q2eQwny5tkjG zBcR#BxF!5a7lRh_srzVlfNjX-Kg|nTy;pCayF_GF^XIwK)dJQC#~tCmYKJa7LhKFw zsD-pLuB4R+?bIg^TMA5!;ZQWDgQa~8(Ro$BN5%_v>ud%jVf`M_yVv~Yb_#EF7w)@V%w?T}8V!wM%?oR7{`TixSn=Ie2G&-K=M86f1te zc=s^#Y&5Id1XI7agn{slr)f)`n6+{mqmQbs-t|wWv1}ES5RDgAc3ue+T<-+gn*~y}QUVuBsm09kdS79#2Bko|48zXWGJAq=F2e64MTyX@|8XalAV~l6(}Nx1`aL70s@?B&KrRJ4sZ$ z;s|Yj@;b&*ZF`co_P`>Ku7QWma18BeVv|dVjVBv|0Zfj;GPiI?A(h2hn(e70u}AJ? z_CTL2SQLj$1?-GGF*fTG>tWp}z zoQdJT`g*%}c;N=#`*v4bWEW4R$0#MVlK^j#t^^Bojbox{A?E=(o}# z*J%2?rF9@bSaMUe@GI=Mr@dDC8+mbq^0Xxf-4jDSdm@7_8H7{Om%&!>4eVdQ7pOvsh*r|Mb*|)gk1@>XYj%L!l-V`3c#9 z%d7nq6fakyyiGWbWnH^7%7U>B7%=L%1Y(1=>-=5uJ*zo{BMS`yKJ zn8y5q?y-_i?W7!=&7Dq}4mO@UM(94-4)uZ*(SnH<#NT}ul*~x=!uO*VXW>#U>smIt`j-&l_`~w|wT4JG7 z;hm#*`NG{D6K`&8RXu(i*CMmHm95-KjO!MK8|B(7$!Kan3f(Rp)M_`-p9k~v`_*i$ z)SW3U$4j>8cf{Vv1vK!tg;umVrq{S#-5(jp*LZ>t=Evjmo!vU@E0nwwiK@qgA!3na zl^-Y{z{J*~x_ZjPW?Fc|dz9mzm*h#~V9_4z#YARmYC^~9F7eAb(C2BhZs9+7gX$0- z458jEOg=KhqdN7&=N}Q5a2>XzAXgNJ#RdlI+@3jBmvsG?d3zb*EcN%O^og~#PbLG> zc0w}X?R9yG)@!D>$}R`k2g8L{KlJe0Wpj$pbOl9pRbuBRU_KKMfjFJ2a;oVN5(VnZATW2!6=`~Ow zUM@cpzHjt!tcQPJCpqH*Tm~x0o9l|C53^Gdex!FhC(AQjt6Zqj(n@zuO}oF=DWyi< zerlae4IpimiT((F_I*%S09KAz;|~fQV~n-hU$BYiLMLw zW74G|54Ujb(I7%V!=a^n`IBpVcN4VX5v7&~nCj4eQ|+xiE*s-4nN0JJm}bQ_fu~e85wy zM{*esWq~dbzT$zwLN22D(q`?9uG7|p8g4L^ch1%7ufaxoy}yq1!|9o4X+3LN{6h!M zq6L+wVYu2i-&rx`GNcio;vk()NKXyl4C+ypmExvtR|1n+{A~8Ox)Y<6?6(Vt&9dpw zD^4`Jc_?9vH9Rax8S)H@5#)rRnTNH>1T!rmA{Oe?8qe=p6ZMyG?0zqX@(}8Xv2XxI z_Y30-0S0}q=(0m41Tw_Mmw$cK`D1oKXvfYyjxWf+q+TRKr@>&xLWn6C`LynuEodYR zv9!WP*0>ee%bbR+INh<(8ZA_t>ol%T`{JF=D@a|m&@7|?nX=Lz_Zqs8y{LpO{>-bK z*x^~$kK~~RfhD+z%^fQ8#Ex%UfhQew)KJyM{n$`ZHx*fS)7AL+&YTo>fgGQ;&BD>U zQ`F(T`>%RSlT&Hmn%!G^x7qu{&`*2!u%}D5Zf|p=Vy;GQv{1o9Cb6`Td8IM8r(H4` z1>xtiO`ShebaDaV%y=f<(0MhYplX$5yoY%@_S#_Q_Wsni4xXvIJ&(nL#5j(;x9Qg( z@RNAG8_SsKN_1UDGvo3-MzAPw%h*E-40)@RQm;r>7|40jmJy^rM~>tOx~2*pT8@U< z9ee~A6(Km}`lCuYffLDAv0cgx((cQ&M3si(o7?RZk&*B-OL93tTmqJ?7i=*zk5NU8 z$h(N>_(zebFcCun<5id6qJUmq2S<*`A}W6H1MtAaO!VtM4F+KYqzguTITVHRHQjxw zb)vb0|-h4e=1o5tjS9(%>*yT2Jaq>2^s zvgmZTY|pBzE0$NMqMfKV$_{Aa+dCR1*hehjOkk4>*zQlDHy|D;2bM0{SDz+y7Ig<; zvxUQ|Q+Eg3_vyiM+@j+xk^+^?)gA#5ta9fWxl#(% zCag+>9$-vuvZjLKwI?PDJB4FZCbG!3qXeUatl(lWvI$&0JOy`GTw)GOJph(84gZZ{uPX45E+E((OR=a~%BxyVydA-NK@0`QNp@F*3!(7{MT3eLX+ zbeqJ8KWU@>N0Fey*f@s8t)*h^X|@ywK7N@c`h}Qb=cm`vvcoo3oA?aDMoLEac2^8S zFTG}E+GI5O#3rOXn_q+^)NN7!Wr_eabXt*R^x-lh(f4@tXSjbV@XQX392_u4 zXqN4;bSu5}IfxFNZaDWW_kMHT#}0#-ah+Is@w?Y1Y}6hPq4nYl9T^K|jA9IvS7Vdh z=KO~{w@ZSw#Rj-W5fSkL&t^y7X>T6t327UCveN5;`~KK=_Ti~bBrzih92c2NB5#0E zY*y(!4w5>4eW%j@+${L+h|;6QeJ1Ek8#^k({jDI3dYgQIq9$H;>lU5*7$UqdJ22tf z@coN|M{n&j8!A&J8Q*>F{i-Q6md|l8-!q_nwAmOeY|0Vyv2}Hj*1EAxr}Ua$xNC!X zba9_{&8d63bmJ=^lTk%&-zw9{%dct$*mDog%-@3+3-fLsfrx^jorUvI@@P|hWLrPo za(a8>6=>6XM=1O7F(RrdmKfX3>{kVzXTy=x9oati(Wf>yUl*-A=);n@^0p+*HNb<>S zjlt>~GLP$2jvS<-zgB}vGg~6xgSC007Bl}*&>-1^X^FL1kA%>Bu z4L|(!#4Cs|Etew5PjgHl2f$1(Wqx2%YW}muyN$conj4yLZ z0t;Q&q!H!Ka;uCUHKh?P#s2zgr6+C?Q}z9NA-6u5c{E>WAx){Jyr(Y746+q&=J{Q_ z)%8q0{=s-E234Jt{U&X1vnXkNx+al=7yulxpNOis!`~oQfQ9~&WKFb|hz3TEA2_2E zC#x4xA5l&cpB5N`ZI|=dbr)y0U0x0W?kCpF_GPm%-@eDrH;hMpToucD zN2jhY56(uDz0n3a5C(7;LuLxLtdQL^%s9P9TWhY?jYE$X+T#BUwsR!hp6NBBlba&Q z+E-Atvg)qy+i9P#++hTi&%p231}Z1tAzdX7FAc^4jPdlP#A){#Gz;o#4c(`_Yb_r5 zAZ%pZH(X3JvB`V!LQuP5{4I89T%IdzvtBe=eDbd#6 z)W~=|H!~lX@7AvMT3xTkCZ9P^5#D>0{IeEN&E3twoB46y`DUG&56Jg`kKl@0%mzSv z(sYq34;qO}2DY zZ2BYDQV%{B=JeYwI($<1_oLchJ^UKIROz|;&Sb`8QMadJd7WI{$f8FKR3OI0VeHNIAGPdX12G-rX4xFNe&8v@XX9e3nq{-B zmN&`zO+k--mi7G)@h1P_mjX<@|MfphT+65Ov};r1a&1nkYMXGC z?|D54s&c`eF>R%#TqjeLd{zDi;)p_*&+#8TDF<7U9{}4CJrN{Y%Z9ush3uxvPvG;u`KIWSP2#{QNiaz|B!u~_o8ezy5}|GEJa!vy7m^2TirA)T_KQ}Q_D&dc}r5uViz$3F%p zUPD?fLShUBa|lz{rZ^i7S9i(#>6=aKG&2L>9PFDJ@NS@gz+z zrpF`b{u7HxgRAkm{!H$p6tRx?ziWE%>%5{hjtutx%!4VvrMU4Q5}N9d8lUOXfP2;I z^Z_rgzxuWUjNPby1Tj3*RYvcN#E^dPMlJ@PK8w7s7R_>AofxyOUV}uSH*VZ$77}jnZRjN^z#Vi@M z+L~H!Li3=#PVsu^a-qKrgicbsPwi*otGz67i8n#Mr>0NttYf_WyIH@L3-p|PObVb(-K*iG`04yR0Px`8q;PW%b6;Fg_F3$CrK2Z6iyf} zX47y3!Z4@LW=1=hw6G6r-wmaUWZQVORsc21m01-!l10^oKrPV$%R|W%0bKqUBFxqX z+sCVr<%|6=O$@Tn;Ua%2$NW`ntY&cEl^p!Z&=YIqi*gMMf8q9o}F2g)tviC*|^GK_*28E6siaBS&Y)I{3;3KH*(F9 z2~bWNyXZ4!pNwI3^(wVWm3on)Bv=-)SIN+in?|x5R z#uls|`zi4eJPN+cXkcH3Xdzf4i06`h#J)?N+_&2+Ugy1>ZFE`O81FRh zG%W6|WTnyRXfNQ^U|?c|8yTLpLJiSf2l>vYVuf2Gr50B6u|ctH0w4JD^ja=?_?-Bd zKkU84>$T3tc7u)Sbf-15^s!+nRb^Zu(__VUoAT1OW)<_MCcS=Jo}D85*z&KAlW)5j z!pg&QT;KiNcy&MDE;idFM|fDz&=g$XqhhJ8Gz^i=6xXNmmpzg7ZjKG=vwXWJ%ahla zDI1MbV5l9qR022hacysvNVuhC-(ux9=;IdMG2G?g_R>?V#MD8-dvzhHfM3tgTCPvf z?YQzBh(skh#bV8OfTDJedw*vLidnjz1t;CY@4io6o$~xK-N~I%`a11EM(m-rZ9dPb z%R%?}BjavH<-9xkavg5rz=m5h;-Mp)oLsC+NTouKWVhZW50m8_r>;ByCdTPUWSr?d z?16JKnIT+1!>{5df7+YtGe!86w(SP!akS+H_3%A>FuxUbol&yy*BLEL7`J7b9~mj5 z#n%K>5ca%Vo0ycNq6#yXB$XG;)tWg4uUCc6g5jqVQk`R&Yx(L%iT*BRCuF-^tyaOg z`%|y<`p-3DZZt1{J=lFH#&P-PTW6dKdfXxki- zlJQEesfN}jYk{eE<2!@GXr%^@Fg|*{K-rGHZl(l&EFN0>$uB9gWn?%|@mTuD#?pq; zv!=CSUzo)9_fq7U@j=I}Z=8?*1Y`bDT;k3%v_q(5OjgIK2jsPg{?&SB1J9e)?&URTe)S6gVj+yt^yVu zuI=m6)yh_EoVgbFW1mg1T31A7{U9*os8nqMK&g)N~uyNl9{1@KnJc5|3GN5CK%Q1C+1+2v=27o^cG#)k^xib7o zaS#7d93SM7(;0e^HzdhuJm(ww;xdarae?$_%0P$Vt?@sK%S@*?-j6wp)1i%Xhbwju z3w2TG3+hf6{yc}ZdY>G!sVhIxhR}QQi-ZQsJzAZvdC@wY`zMv+2Oq7csI4}c{pkbV z&Dp$l789X0V>OV*Jly#5S;fg9)H${x>sq@!m(4oMzE)7p(s-c;t{YR9rwJdQIDvZK zM|(26(KLmR`lPIqejyPg{iToFg5^nXS5!ENQb90cMX(-b9*VGZLVl>dO6^_PEd^mv zg0*=|L$A^iPr|w{Uqgo@o!=AnnZmrVdxEVmmgyU_(n*b3`YHU`WNOc)MAb!j}%dS+Tzr$u>O=8vwm{U{E(x_WQG1Pt8D8QGC?6(APl4K%u)iqUCViaYA;CA!rRCT z76Sz&3Q^LFiZ>_G9Y$LK=OAffmDjD?{y=aWMxX(mNxDt^N9pev4%J*P#XTC0)JOlL zP&iD;KlH`|bqM|ukP>1tI5k0-#~d$Q?!@IU@$958qu!HwajR?jKQ-|503;7D+x)}T zkA+#b$7vkm%xU$uPr7POL%8{_#Tyz+d7OzUjr;2;M42ROp!93EIqjT)(c~b@$Gtu9 zAc9qDLNa>s7ptq4c6eZ|V@S5Ep$RtatXQPEpuE~c^+00r2I-D50Ye1rO zxhu>`xl%H3&J~zA^Z$%B<{PVHh>VTyr}Fw6aKipY0#Yz^6vP5r%&`OEXj>P>cr`A* zpdhzEgjnJik7X`Z!(U@E{q&fQ%<(V$6_H%6IqkZ^7*~U;ZeRWy>pMMpUSaN{bp;Ot z$~qMSb^q6e~D%9&^O_MPFm>ub)ycPH|p zcJcT_Y&d|)MDdW!E+T-;^w$s#!ubfw{VK74De?U-Zji7wyjv4uq-@vShMV4)cC7fI zyz=T^5f7WKEfOx%Qmv)r?Q#Aft^_gW_EHjBaEkNtiunXK4V;-)JFnE8$-QF}-+qh# z!Mt%M5S-ev{EO%^{kY+QP8PN(2LbeKJD% zFf!ts7&%0ey2vJ9BN-6E*ozxxttkB{xwG{6EH!dpmS(+&{(M$OA= z5B#QoRr!d#f{T@mgfTUD!4*-db%)YjgWDEL+}uGYhjxm~zjtoVX1N^KbSMq2Og2V;6jIwBw!bs7=_zqb z^T@rUM~_hxSlgCNAD29?oYVp>n1ovjL71~0AJ0o<{x~rTTRUC$+b?*9bpJ%A#GeO~ zJ8~s~dxvD`-+vUhgSBwH%XB;W=Q4nRW9ZyK6v5hmg54sSd*k~IhJ#-yff2}NJTq7f zR_$Z4!(q@^=knGumm_lQZa{_pWJk}&8`dUY@4sR;HYT38`|vf^@nZt{VJ6sPuy@Y` zbs@kR;z{njsoEuiZn{M)?)4ob#hw1zoNgIy{LoMAH2?j6ePt#%PB2;)MiCr9}{n}eD z{FvQiH#xl0mzhbcop7V2m1M)5-5-`M^RBEd%8#A24ny=R=xx$!;gN*fsRfzIRf#g# zr0U>mZ@(ihONYv1Pm8PBb^>VvN?ZGxOv(lMd^M{OaB1t&JFR;_FO78DpYZh}i{yce z)gUI8kkRCa#DMchBqd__VqO>zb8QfiC7Z_)dLKIC!3_1c!i}eT{tT8F4_1XNqG+Z= z@+_Sur03Wwu;bq&bi5!dX^PuW^ca+M&1D(fz0L4_$7tN=IHu^dP{d@#XRI|7ETq*- zt5j(iW3uT`nUcyPr)EZoKlIY&=a=dIku5(;o~f>i-{1GPBwhk~jw%;*B(X)hY19&3 zJW`58LuA3}EbEgP4!b~Ag5l&#2-gTG>3 zkxPvN@A>COx;Q z;TR8p+$rofec0o&RwBsQnrZW86{1@!(gSDeEtvjI1n#U?UtAzbULeQ8xcam19ph!5 zX@;fx9lpF@a$OP;KuiY+z)n(zQp~%|bB_CpBwmLi)bKaL;}fG~*qkey>ONWHx)AJO z|F`1L9!oF|9hs!E*t01;N_idQv!$OQ^w=aWz_Az6qX1Ftl8Sp%kUC@DlrLo5u>{t) zbT|csN9czD6Q4R2(YO1rQwG!$%;sF2-mOt=RW;gXSR13G>D%aMRd1->td;U7RN5{(2{( z%%NK8>YF)Elb-|oT6PIs4$HTs!yK=k?MW^%Nr+7jWLm3Mu` zeXn;Uc|F^SkQDdk$H~A;P8E+s2gB53Ip) zQ|_h$q-fT04`UEq6&qZ!IfZm|!dPWbnF>!TT^FP@gNu}uly(YfER<|%*caVrg-BwWuzJ5{NVvk>59Q-}VO~&ML$}D_9 z-2$5JgU_pmC0Z^Ol3vAFsNC=Hc71zyv|Ogprqhc*es@(TwkVG&+6T`Xh_^Y2lVse| zLaHxYPc;-^3s!d=_0@2z-(D01^WtCz#P9(4)>(Zg zAlidfm;e{V65FVfjtack&D?Ca06m>hUOERJ(JNmQYe{Cavg=I9zuB8wFw(C5F_3>y zR99iQi>fzAhP7c@D!sKlDa#OBtX^)REyN%ETzINp>F zB5E-qkAY4t{iQMKZX^bw^I-N{xrg6M5UFPd<=Dun?6g zA3~M2CPYR=?3rc%j#2AsOLKVvzo4B`>1`b2HYTsVwfaX|i3ELdS9PXe>!=gJi!o04I=V-><;4cuo@o$Bd5pv z1xAo#5Ng_dF`dMiPe`~ZK{6A0v9%L1dn%OBiQhamx9U>icAKI1#>$Qcca;_Gt7=D5 zQ_CRkkTjhL`x@;MYNdJ><11+|rB2nQOn!NFnCPALO#@}9Zc(N|axA!D4Z(bBT38{@ zC<)yO6@s7ds43uP)YuK-4|>Hn>#);Fp?jNlc6%QGDHZOo?{?zv^GtCp12(!&i79hz z{jNU_-UhnUat*)S{>aUq9`q`4Y6hJas)T1G3sxn!TcJ9<9V@JK^KJeT(xv9DtBEo5 z&Pk^~zFvQfAwX?R$mQIwz7L+IWVcQUQYHN?_|DN~7)(mYF8J=PV-f)JNwf1B!fwEUG~JgC%a~OlmHX{8o59EoRWB@8%2q7 z9K20pNyjd{4}OjBBWMycaEjeO1kzFP<10ADwonP82k!NfT*pF`{T&(m*m-4~T!-?FHlz#@ zQDJ#Y(F*8&fdg&J)AF&@&F}VCb${y9Oz3l;2v1yP@sdmCuu2o*u)gywGmKwg)NELH zBORWa{^m>fheE3e<{Z)Ir|XQ#fm`QWGv_m@=`AzO%1(^~zy9~z8vpav61Y(FU?oT~ z{;1;%IB;w49cX^Yv#&E^f2JdehEbj&`q_(zQ464fBG?`3H?V&g@+?y6xd0J@y{SK! z)f2X|JFxznjRYICIuqxvCv@?U?7w5zc@9JnWady+lF%I zdxOQe#+`7%aK40w-6yB%&qbz$W(cK?g$8X7^Xu_uh7@UB+?#PlU72t(S#k1RcASupP_cjQQ{4uF_{R`{_P#e=W6zz72`k0%LTGV0cDjrs4hwb&oOM2GCi8R!QaQ8&-hw=0LK`b*8o zdei@M?9zMU-cjK)@lAH7K`hQmtl0NqHSgbp`pX}@hvaN)U^BqnbogF=&BnH$ziE-r z{h9Fk-bzAiWu~fbd3aLi&C6?BU_%R0?H%6f?!5zrOh1p(tJ9NwmFmA6nlo^IPyV)x z#ZSIhsAci+qtbm#_o~bk-jcIAS4ByE^+DjrZ@$XlE0C=L-cJ9_?hi^&7Z>6JZCJ>B zu!x?L8E9#H-MfHkcvP@txvDdFi%-LcYsb|0iYB*itNv+VHh$XC$6>xk7JdhDms!%z z2&K2*l`h-`!`-wEbssOlr67Xy69-#;j{>umvz87w;17(};x)_XgcCUTlvi)u?AO?R z&?`Kkl^b%d3e*QWEpoWzE?JdJL|+zyWT)4bWv-)?ZGe@y2 z)>+MmZ>b9ZzH3jU$uR4lM_{d#9;s5Nif${TwNv@!D4*pBnG~~$r9Pi^&>GzF?)P>p zN`qm7ne?Mbrr4=>_7O+8T1nwJHz6$kU59b8?m{LM+9gwpO%(|}HiV1oR5&HSApXZ- zfHO#(xzc^z!e@bv$gsGU^;n3YAD&BT>t?T}^m03}PtV^g6bgB*bXn3SsUPZmbN79p zqm>T$m1}cw@vwn?h*^^>%wWY{HI%RW!T9ptLjt%|JHb3WPGU~UOm0Stuol70#l8~^ z!=BFtVU^bjk)1rO#C>e-9=6>++V0V)lBF}7{67j)2fmNJ_XepssVEkyqVegs)oBwh zm%SVPN0Cma#~6D0G)Utgg@h2u^VT7`_kH)^=?(o)3EBQ52EG9T$1b*sKVfW*HlR++qciN*UowxK}g-|GwK_W z-_sp<(^p5AHR!mQ6b$2q!G0#2Kih)yH(vFzjqKB7nFPjz3o0M1PE(MR*S}`H(4Kbc@ zwxHVLk;HC!^@lB+Q|cpY$>v&<`3bmJufSjjti+q(irYU zmyIbf7V8x{aw4k>rQ33RP-OaK16ocyMeDT z9SGkhpLXaVny2x98@-DtCt8j3Ipb<;`?;tTJ*% zf|ON;wJyPtjhW-){I720DLv1of4(TCg^n?`u@*j7{k{!|9AN;4+_iHB`Wo}#Kh%?h?eMOFR!z8YALgu0W>j=LW%U4Q;>A<#u}Tx7yBN=xlR1IUi4F|FYH7!h>w(se`UyZT(Rx zfw=+{`>T8e``Y!LQ?cWU90YX6i0I+_Q}aGXzYBH=`f0H?q6{5Q?G{uvHDmS1|9129 z?^POHTf*-&7yyq^WJgJl$BwXZ#WMN9NcKugPT6^?4my|4*ObOgz#>3r2^wSiZp(ft z75YpnRBQGiAXEg(g4NgspQ{i*Ep|0Zp!@9UT;^qo9(WL%d}GL?c8~(s<>p-FWD4d^Nj*!=e z5SWRHSsgpHI1qL|h26oYS(-<BC$DB#T*YBFTk$;$V zXxu<;4U6-xoV@G`8Ox9=F}UD?sJAbAw7!HZWxhb(v&)-`-M-kA=;1gh)u~;AEK$HP4`Igrf$uto;3Nf4dp_q~VdXV4LBsdPSGk|3qc6jGptK9&j?sk! ztv`tA*o44eYc_qbzr7V#J~u<$Q1sfD;u2Ho@E0MdyiHr_2SP!|%y~f0v8&H%>w4u9 zh)Y@$pyCjh2~jxZZKydmuLE&u0h+XJRQF#0N3hPX;c~}Tdpc-Ihj2Qf>gEfBS^9cE zUGejPQTOa^S5Mq-pe%HjU2jke6MDp#m6TpYV#7EmYm5au{JbNOk8SQJdn(qeaVSmD z7R03{9bj>v=I+K0na@Lw(iIFoquIIYz2={*AI9GQVcYy-U-GjDX;KRULB!f3hSP+RJHM&m zRMBqCR9ZX1Eayg{b0`|Xn+D?mqi)J9TnjeDFGMLh;|M^`t{WNeP=3x7e6z?)6E>KBJJvR*737+_h)=QCMA&x)#co zq4MCQeV-^)|4B)V7EuWOL~y<+d+U>xqvj#nV#(63Gt(+(DCF!0SrKdMax~Ykmgi3- z)o@23tvftu4nuD*S*!+x2kNzy=y@5Yj_5vBvv)dj9`b}UE;hs}obAy*GReQ$=`Eso zsHd-g9^k98aFK?33yb8bbx&XJS8boBi&MJdy+}u|@y%6%1%06ewMMg4_CvV-%HgJU zYSDD4mwY@KtWL;M>EC@q+4rK0=>lwndfx7wxUTmbc%$Jv-v!-=Jq}dh7xO2f9-&W|zSl#Q}UHdW1# z>E7+o%o8P@4nj4_2p>ik9ow}7Q9=D2zy)A`&sBFmbuDcD7rJZpH!A>fdFEV{Gpc}z zNO-Cp%I|56CHdGB)M@otHFd~#y2`FSkiwMQE%HESQ(WSRx9hLPP#zn_uq5&@THN(8 zaWZzK=d`q)BdFzAH2X&g1-g=V#U*^f#_{HExLXK;1_>CQvy*VGK|0+&n$)O8{+T8dcGhd%p@6hW5JT{OY zAhR=0uO_qG^5rJu@4D)euXByrU*4n5EB}M_Oo(uZeFud(^Rres3#=_-lH5`s|E%>{ zKnJpN-ZHm(oH<*O6FRH_(7qq3!q=Q|Zi_SfP;940QI~+V4!HZpK=Nh5 z^9@>RPUfqJ6HL2UDb92j5G1<2-Ke$#GqW3Oe(5~0Q&;LbF8tUh zwbPvQ@_~AuOk<-*Il^tOwPHt9g_=6d=&V(SW16rHK`ti^g|Z7oF6U!6Jnri_#-cf- zj~ApT7@!}?Bjh!#76*rBkQv8yb^hO7!+8?dzO-o6CTo$jQbWa;e>=a0E7l z^9~y*J}*-u+m2A`jpP4Y-1Q(2*BILg<#Q(l5|3AIDL5F7{t0^v=kpbJw(W$K|=b;4DRWb$Bb#R!(A#E z>2mj$n=9!j+WIeG+JBCi($biA%Dwg&p6w56;hrMuHM^2j?h7#p>_o zV$E~Nns!>A!e0jaRJAtHnK~wPjvi}w)3C37W>tCn&R4rn)E??~+kMQUhADy@v*#Zk z(i;oRgkKr*>8=xMJsOf<;dxar^?H|q`j^t6w9Yxnht#mCDPJ(wba`qznyL`}V^jT< z-x4;$DjRxINlu}hJEN*ITb**qb!^mg^7&d*p0^+3qCHKQG2PCeaxL3>P}=MJjG~5+ zv;6uR>1?>S9Dck-DKkXhHM!4>83?!T&FlS|wEpSv{2ZfWt?|Swt&J%GkBJS{2)+I<1qSxF!-$zTMnr(2B+oP|-OMlt6)-&xu zQiK|F!Nw{k&%ixug5S8|MM75RTae;JPfiNPj%Wj@#tlSc_!}GKL}8vHy3xxbbCN@eR#y>CDmO1$ zRH!zr65B#vcg?en_~ftyx#!uj+Y3iC&&6IDO; z4#HqqFaA0wB{Tr5_f)Anq7u4Okz%KkBb=RXZmcJpBFGcrI)FFU6LyuV#fH#D4liX_ zqusgt8!}BFtonFPg0aq#S>Mg1$JAVZm0v9}^4WUaTd>(H!yic)Jx$62JzU`XlIoBh zq5jv4&Q$p!^lrkpHPirQ%a&Cjbz@}O(tZ|g3<#P0AKuJ7?xSbLP&Oxijbdotb23CfWP@JZr7bGM2sby$foK z9rjC9sbxKulfg)<-=WJ(do(POXJb^F_{9^NPlwtiCZ=KeFV~Z*JYE8!1+dqBtYH zT!2Q(*=A$_ap%oVhv9)GK1#=&)~9uw-@GM4#rZs-7C9>*?wocZgsX>ajd>XHMBMRN zNppk|hh@pUrIphRJsT5uolR{OTFKUwU8k#DbflFNKD_tIn(8N|3dSWeBp^N2+0wSH zkW%!rFyrR*=3aRbLL9{7BeibuH9+xzF7x%jbYugWx{b=eDY>1Dj(JFek$+{h%AUb46ZjcDp{#`b%lkn{dHn zxj54r#UbRj*|GnFsXo{^S%AlbZ zxp=le)!oiJz3xdAr8wo`Pw-AkDop7k!S-*%9H#ecb8}@G!F#MUN?@)8Z-d-0w{PAJ zVj@P9Zjq27dS3_PZL6Lo*SN6y-=BXJ60kaIu)cGPMU|3(=Cl$`+%=aWMABouvb<;B z{TTT6^B@wRu(gw3{*c)q;S>9KL;(55NL~i%2&JcPz+I!<^R6o}n}R z-V;UW%MmtYJT(b*APwnuX;+RNKK;9(w{OW%+32laCvvo?S19SGRifS(Y^$j^xU4tC zHk(PmAQ47wJMX0&Jp{8TvDm#TQz>y$KIGZ!BDEM(DLfd=(#>b*{%HR(W(IvU?sTk} zG{HMF>Fdp!Mz%g7@2M~S7<*;)?hN=Wp=F&FQ0Swf>YSrNxgb%0A{nPZj*Uv}_m0v&O02r09Oqr$o=Mx%5@bY*dd97k+M>~yY zM+YZa>#A!MqlG~v98c}AlfRH)37NlyjBrf$Hu!SxufSK$mRC3YZbc+@Gf$@{wOoyP z$T64=WWX-a^TK7b}|MRV?wnl)jW!ifFbq{7d>Z zZqRg$xMVVIUULma=b&k&fn&j4G&_!CwVB$|i%sqPeE_Z87-`=H6;aR_eipzB@Nm=? zKVDf!v{QQfv2l8A*t#}4Cu7L&=EYc%>w~%o&BXoEsky$>iorhj+H6YVMU&wo@HSL| zHuH<9F~e|f$C!CtaIw|&QYNUqzC|f$=;^lCRy!a?`a#~u;l*Ds0n^72uD$EONR*++ z16zk~)U^+IM%h_BoAq981v9_kZ=Rj1+DboaC-nJ>AKm%GRwHAvL$jm;7*<7U-6Ihw znZ!ze9VxjY3dHoB2<;->)r4IRT>q@)A=2G|K85|mkMX(hDDu!w0CzX zfU@uTILmdfk=OirGf}wWu2Kl_Yw&0{2(n?1lomPN?DEsGZ!S;sl}wWzvHsj#0QW4> z(92Y$A1-}Ud@ddPj!9{_=h62~SL~Na&#pAni-1-9hfELEg_$HMTgJz4o+61g=K#^= zc*N(l9P+d07BnqyXlrLSY9Zn9B@ zEuX`HjD_fShp^|A;>6$6#wkJ*yi6{=vnXO&Mc;DWL}L}vD6g8mt9pb~P8OtQwdaK1 z9MY*)d!+Lb3E$wgT_5YwT*Ss?Iw1u10s&6b0Saf#ecrOK$4^+IezyxF6?j(X+bK>P zLd%5-NmTQF@->N;_n&BTclV?aBwKMbNwT|E* zN~HfrM#j*GV@J5iZhPx&Pmt{*!*lDZ);a@huW>AKhPhpHHtX9_F`O@JqeS7_=36Fy!%zvfT zzf=|E?4FO5d;7(#V5}4bbD)|1szA`o>`V8tCF+H|p10vm*00?T;`I&+TRsXJFGBt< zi*50y>D*^Wx;it8u=-Un-(*YO$%txnqXDl@&pP);6{)uUo6=S8Kz>h>Iv{Zipj~go zYHx%cFm=f*IHWw8Cwdo@h1F26>?~-oRWrct31YFa^_H%YqPx0327c+>Hl&iU0lrir z$;+p>R_*XwUdk~N9s6_EIILk6RTA5$nhsYUVc(tiWwj=qV2Qy!l!zJOe$ZXL8iz2y zrAqpr=p(M#GH2g?nBRUkic`)2W}oy(dWZ3P{1JIkTc2R2w0XF<n zkTzv)V5jdwIonetW-`J5g|NZe7ax7;dhnJAB)Qwe%jdu%D;ayEQseSGQS6(?U$HKs z`bTcTAAWr%K=Qo18W?d1>))mDe(_)}>3YwXBx2T-*fG44B1EgsQhE=AaxK=KKn}Ll zH{znrnJVK3suU;6c`v-(i%kOr=K_qNrf-XTeinSexYjMr%&ID*pQNu+_soZgyNySF zH*S&?u~#gd5uU7%(_QIHc8|8X%u6*n*HBsIC6qrkh^b(i+LV<#BMiaNR`lnjJ6YUaf|r~-DFb|4 zIN2YBN6)F#F6pZ6rXs3tj#h8*zM+Ew-}`mGrM!_mjw%5DHMTb{%ChzKCTR{yj#-|R zcMl}ZSGW$1Amn2fdPhy!pWa>F{7b017L0_J z<7;KgI(dMA{$bs@)szoo-%nnqq7#N)>AQkp7fPib&NpKhB{@Cs=IQ^f%pZvqiomPuOs z_tG~huZ(*EbXqzf9kLIX*rQ+J7S5(|iY(sfw*N`Bmo^oZ=>}_mwGc+@bi?V+>xcdKP`cB}+TCq)*a*M>NSXc!qT(dF z>S}g=`=6Iq*#o}q(mAKI%YiOOPY?jUaK01QA#2OeK3ZG%DueFqNrWAeL;ge^?HV!%|jH-c}g}vf!e$bgSRp@r>0@*`4obbIeePP_{#i{6!+%W&nTU^Ye*qkxELSUTY6|yE(eNYKdZ0HGhd!xMo8)!Zzs*B zvdM8QnlFqnYN}6^ow11#+HFFYJ1|Q_^8XGix^f!|wA<{S;&q*dS!s}|<+&0$Wgb}W2 zs`p?d)mIfRMn5*h-(OIYig_%eh0(Mk_q``F&k{zvX!F*Wqr(QnM+Ce~uYsCy`VB}N z>UD|gXYK{VK0P*X5Sy&7I#2I5#g?N?d##%{N)hH=8E0)7Tcvh9HP++Ivo$L4XTh~! z=yA^cwWwLOzU(H|5 zPpXjD11G>;`iNTsKAO#?e(tWm>86%{4;L)aR9Uu${>JMKdyoO zbj_o`jlpSfhhgTEP$$~}Gj0V<&yQ{0%_mP98R#A3&HiEOqzC7vgBMo0Ghw9I9QC!c zJ2E3%p~u`a*5389Hro6=KcGL919B~pgevDX#w4dT`H_VM8C!u)H&Lh!R2pKtE~tvC z(LTMPDK%lfVo-I2HkTnWt{bsXKXrKMo;`QZitOIt|Bj(K;mxD?CR*jneY!U=V3t=X zf$@#A*zyIjZhx(W5m#w^(vAK;_8%a{POcH%! z9Pwf<-F%7;o1AV*gui_QveX^p+N&F~tJpfM`Boiim~NEfEcvswi+5xe&Iyo=G07(J z&7#uROi2&s*O25CU6d`YiS>b7#_lVoZ-{X7>;vwVD308--IQ?X3g%+o5kmnwB`~wN zMkqPO{bE`Tu`6t`3y;F_clLYyfXX%B;P@$tH_`W0=LeA5UE#gLLXHbL;QngbzV<^O zP_oTl3etIBaTA)^u907Ay!CLw<9qD}NgC38;%5}fO*pv^grLMNPjs-~HJAuH8C3dq zzNKhBcw`glSG#q5iAPe9vwb@klcSl6l|M5;7ptGxvtmY!nnSpqo4t*Hm!Oty7xJW+ z&L&=?Grmq<+I_Z-JR(==wcbu5!2HB4{!j5tiP#W%3x+sSfqcqJb-gDX-)wCB<4;2Q zlvMV1Aa?GdKaoR9=H^d*y?hh}_yOU48MouWe{JtX{;<{1pon&yVrNO5E2;RfMf62z zb^)+`QQ`HYEFj8SDmU8wf?nHa4K4dUl*0aJWcw;5n7)Oy)ExX!bO*L7(zDQz9U{DN zhA3_Uu^xTFqWj`%{>^Qkrq8JchPWe3E^#ofJF3qp0!e!I!Ak7Ot9{A5$Yv{BZ^Ve@ zPWwq*Tcekgaf<5zD#CWk>1FBBmJQ$*)(bG}j{8QHu8RkIM9+ZIYYp{*d5%J_)dZCj z%nB-K8d8%tSPwtT_}z8507uj$oFklDQx?eFalQ|~uCjjgXF>H*wql^lS}b3*=a2(r ztv;Z16HTbDWE8{a!0u%2FI&H|;tyU*gMh~7x2v)HG@qQ!iKTMKjpE8pkMdv|P{7V8 zvVL^ODdYj46S8J^23e514n@*d1dXjydGO+GRD2gPb1*?#mx2705^W(osS8=d*KP%5 zr@7%y2}+E5$}H)7zfUWO)@r2LxJkdls9fMG+DX5rEt96e4SA|9(yf^6QKJd{4;u;^ zKGDq5F+yX3Xlt)+E;j%RhMP!a7EmXffn>I~953g4DH|xJQfHu(`PEsvUrtj({IVY& zl)COj`!2;H!bI}4sEu>tTlM|iQs5lj>`t#m@wE=vZ%}UQA69|CUQlTO#(_ezu5QxX zf!`{=U#)z16ip`90|=1XfDroRYaxBlbbhDm z*wYgRF(b$(_Q}(qEb%R7aKnt`ygi}I9P=^-Y5F?xp;&W=NK=o~i-d%o;0ATn<>8!0 z4)cYPc2peKME=mTup@zDWRyv3CDQ6%1jUU^+aO?*BlPLMt~wpbYH!&jBr#NCeBEzd zP|F=q{VP;3e&2n_F^0;*B`Wp=Zawj^<(q*Z>yQ9DD?ED#^8y=QcZAa8qa;pqx(3!E zgrd0tHz+mzgOW2#jG^x(;bPf$T*H^p0rrjKl&}>Pn6eA9I;bf zw#u{Nr~=XLzPI-*NM077i)N;RLs+ayie?8^tq|4XtzOua3EB>eGuQ6loR&rtojw9r zT*0s_{pk~}$@c)uc=kxcS-ZlBo_LkmC*1ijaev4^b&;>A)&8ymD9Rp@D#|W_)~Gwq z#?VV}3<|lV*Cv9X%?_UDesTh!aE>SLn9Z;rhPzDvXZ(3CgD3Mv9>VFrYvYgleb9ZF zb4}MADA1XpYXLZKpAsd8s%)-riB$E~$!QOBrH`W+@s-%-@^l+0Es+uj0B@6$(=W_k z()0;$ha~2xitMLXZIGTpM?3p2;2JZz z{l$8vBeAy8elM{eOWkGTKIGOKpwIO^GK)vENuw;uijza%KugDIl$3XLdou(2pD2H;OA|6HG~t)M~~d&qfPl`YSVjG<#K`&RCtN}4zm zSD!>;KNXVxJ=%b+>V^b<3}8Fn$oV)JR73SL%i}OR=J>?_q~a>K4VaN#`CtA54oZg4 z_?b>J^(&pg1WElb)Qgog1&n*3pnN%@rFv$s zr41)@{l&#}f@+JG@okO}%Il0TEk6Siu74wXSD5ofns9@|>CkGWX4PzUAU{iT1$(hB zdTQPm8=DatN4ZOn-P?!~p);M$Y}$O6>`>T}^pL|8wYZYx8x&X`(B~adI9R1ykPf9> z_8m%19rAQegP-0l++y^a#~3*r4ybJv)HD=4?*;crMAKLCQ@>3@x4-|rB% zhbsNU3c#d=(@^huJ3Wgjm zT%+}av{6ZM#uMoD~p0)xeiQpJF-b#9r(p3YOjN zMAJ?4;bKDlHoUcY27+H%c*aGEt7HwO{bt?b+Ppj_oOCx(v1w~lyh#AIZt90#?+Yz& zh=&)=MI^$pEjaOkb7H zKL+0()n3y|6l_j}Q?06nq~LhfjCz$Ms2^h?E-=_25$AAFT`4L2^6!#~EPhSqu`f<) zY+BIrnPSSicaQ}>mE|Aaf#){2H?yDf)#f5eaJB+aBY0P!4K15xzHnHy#Xs({M z+)q^-GmtV&+1f@jq z{^UTOiG|8^-=w4YZh^k3z8@m!N)FzsZprztlUhvC%Fc@Zj63m4l{Htsr|k2| zEnYYRA#sYb(!w?z2no%6fIV^x=~fPY>V4n6<`%fr1|DD(Uzd;K<)2FDdf|WC4zbl2 zeh5zfutMf-yx&5#o|zv}gcwRuQ5magp4)ExhefEF4@5e2-)-p=BU1cQ!fcC8K;FY6 zvY82seM3%regLW;F{>PQMVpduiZ?$`PFzkor*!uyxl~AMCnT!F%Ilqh**h)Wg^Nrh zY*Tas6yAbNyZ5Djo+z$cW(SenSh!o{DadQTf^RY*2%!&^35;`*$jLPk(@11bf-=G|w3m6qq0NEA8jU)-E|WQ>h;^ zn;_yz8xjdvc5y$uotI0{i#gkajsAKk)jqGEB9gcFs;x%NgK*NSrgjf5QFZ{u{gARW zWX3%hX%--HuZ$d2Rf9w0r0Lf?!tL=xQUIF`O{dodhKU2K`STy#F+))pO(a_8PGK8{ z*ZUKHo|k(fi5h(+VFuZ%MwdYf<=zG{q_BrJ!oEX!?JO&if0XZkrt`(&U4}YAU|qi$l|((cNPyd1gb#!~G+ne+7Pr53%^( z&x=#i%iqn4bMP7I2AakDl(ZC6rs&6;YgB!Hu}Qsa%_3O5FTTrO=xI>AH@UNasYH@H zCMA=yB^Kj!4qz<{(q;Mio08#}Vs}bnl)GotN<@JGcl2a|9VzN}s}ogWHmPqK1KApY z04JqVDQxJF2(@o9vke=Bc$#_0)y@WPhfU|OY}P51{~9duqRhBF)g^IJkxyv%^lO?$O0_s&HIbO8&WvK8$?wqZ$g*A4jl{gsbu9 z7zP?>n1m-U489kC2DiRfYz==QwPyLKB6aw@RY@_+Qm|EJCktng$n{{T#sI-_KEQj# z0!eKmv(=OwdNbdPse88X1oWalrc4I6s1Rufr(P�V;akEZ+x{kdY9WKA)~Tr7TM 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 z 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 Kq0dy{4*nh2cLLM^ literal 0 HcmV?d00001 diff --git a/docs/maps/index.asciidoc b/docs/maps/index.asciidoc index de90d7adb29c0..6480d64bdd174 100644 --- a/docs/maps/index.asciidoc +++ b/docs/maps/index.asciidoc @@ -11,17 +11,41 @@ With *Elastic Maps*, you can: * Create maps with multiple layers and indices. * Upload GeoJSON files into Elasticsearch. -* Embed your map in Dashboards. -* Plot individual documents or use aggregations to plot any data set, no matter how large. -* Create choropleth maps. -* Use data driven styling to symbolize features from property values. -* Focus the data you want to display with searches. +* Embed your map in dashboards. +* Symbolize features using data values. +* Focus in on just the data you want. -Start your tour of *Elastic Maps* with the <>. +*Ready to get started?* Start your tour of *Elastic Maps* with the <>. + +[float] +=== Create maps with multiple layers and indices +You can use multiple layers and indices to show all your data in a single map. This enables your map to show how data sits relative to physical features like weather patterns, human-made features like international borders, and business-specific features like sales regions. You can plot individual documents or use aggregations to plot any data set, no matter how large. [role="screenshot"] image::maps/images/sample_data_ecommerce.png[] +[float] +=== Upload GeoJSON files into Elasticsearch +Elastic Maps makes it easy to import geospatial data into the Elastic Stack. Using the GeoJSON Upload feature, you can drag and drop your point and shape data files directly into Elasticsearch, and then use them as layers in the map. + +[float] +=== Embed your map in dashboards +Viewing data from different angles provides better insights. Dimensions that are obscured in one visualization might be illuminated in another. Add your map to a dashboard and view your geospatial data alongside bar charts, pie charts, tag clouds, and more. + +This choropleth map shows the density of non-emergency service requests in San Diego by council district. The map is embedded in a dashboard, so users can better understand when services are requested and gain insight into the top requested services. + +[role="screenshot"] +image::maps/images/embed_in_dashboard.jpeg[] + +[float] +=== Symbolize features using data values +You can customize each layer to highlight meaningful dimensions in your data. For example, you can use dark colors to symbolize areas with more web log traffic, and lighter colors to symbolize areas with less traffic. + +[float] +=== Focus in on just the data you want +You can search across your Elasticsearch layers to focus in on just the data you want. Draw a polygon on the map or use the shape from features to create spatial filters to narrow search results to documents that either intersect with, are within, or do not intersect with the specified geometry. Filter individual layers to compares facets. + + -- include::maps-getting-started.asciidoc[] From 995c2cb725a5588fc843b35895d48408036ed8ca Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 27 May 2020 22:42:15 -0700 Subject: [PATCH 02/22] skip flaky suite (#67554) (#67555) (#67556) --- .../integration_tests/ingest_coverage.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dev/code_coverage/ingest_coverage/integration_tests/ingest_coverage.test.js b/src/dev/code_coverage/ingest_coverage/integration_tests/ingest_coverage.test.js index 0f159b1a1890a..03126d130e984 100644 --- a/src/dev/code_coverage/ingest_coverage/integration_tests/ingest_coverage.test.js +++ b/src/dev/code_coverage/ingest_coverage/integration_tests/ingest_coverage.test.js @@ -40,7 +40,10 @@ const verboseArgs = [ '--path', ]; -describe('Ingesting coverage', () => { +// FLAKY: https://github.com/elastic/kibana/issues/67554 +// FLAKY: https://github.com/elastic/kibana/issues/67555 +// FLAKY: https://github.com/elastic/kibana/issues/67556 +describe.skip('Ingesting coverage', () => { const summaryPath = 'jest-combined/coverage-summary-manual-mix.json'; const resolved = resolve(MOCKS_DIR, summaryPath); const siteUrlRegex = /"staticSiteUrl": (".+",)/; From ce18e6e9ec258079b55431a97949977b10cd4214 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Thu, 28 May 2020 10:30:35 +0300 Subject: [PATCH 03/22] [SIEM][CASE] Improve api integration test (#67249) --- .../basic/tests/cases/push_case.ts | 6 +- .../user_actions/get_all_user_actions.ts | 16 +++++- .../basic/tests/configure/get_connectors.ts | 56 +++++++++++++++++++ .../case_api_integration/common/lib/utils.ts | 34 ++++++++++- 4 files changed, 107 insertions(+), 5 deletions(-) diff --git a/x-pack/test/case_api_integration/basic/tests/cases/push_case.ts b/x-pack/test/case_api_integration/basic/tests/cases/push_case.ts index a0f5e51175e05..68fc37a73b9cd 100644 --- a/x-pack/test/case_api_integration/basic/tests/cases/push_case.ts +++ b/x-pack/test/case_api_integration/basic/tests/cases/push_case.ts @@ -16,7 +16,7 @@ import { deleteComments, deleteConfiguration, getConfiguration, - getConnector, + getServiceNowConnector, } from '../../../common/lib/utils'; // eslint-disable-next-line import/no-default-export @@ -39,7 +39,7 @@ export default ({ getService }: FtrProviderContext): void => { const { body: connector } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') - .send(getConnector()) + .send(getServiceNowConnector()) .expect(200); actionsRemover.add('default', connector.id, 'action', 'actions'); @@ -75,7 +75,7 @@ export default ({ getService }: FtrProviderContext): void => { const { body: connector } = await supertest .post('/api/actions/action') .set('kbn-xsrf', 'true') - .send(getConnector()) + .send(getServiceNowConnector()) .expect(200); actionsRemover.add('default', connector.id, 'action', 'actions'); diff --git a/x-pack/test/case_api_integration/basic/tests/cases/user_actions/get_all_user_actions.ts b/x-pack/test/case_api_integration/basic/tests/cases/user_actions/get_all_user_actions.ts index 9160a530d4291..f292f51b377bc 100644 --- a/x-pack/test/case_api_integration/basic/tests/cases/user_actions/get_all_user_actions.ts +++ b/x-pack/test/case_api_integration/basic/tests/cases/user_actions/get_all_user_actions.ts @@ -15,12 +15,16 @@ import { deleteComments, deleteConfiguration, getConfiguration, + getServiceNowConnector, } from '../../../../common/lib/utils'; +import { ObjectRemover as ActionsRemover } from '../../../../../alerting_api_integration/common/lib'; + // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const es = getService('es'); + const actionsRemover = new ActionsRemover(supertest); describe('get_all_user_actions', () => { afterEach(async () => { @@ -28,6 +32,7 @@ export default ({ getService }: FtrProviderContext): void => { await deleteComments(es); await deleteConfiguration(es); await deleteCasesUserActions(es); + await actionsRemover.removeAll(); }); it(`on new case, user action: 'create' should be called with actionFields: ['description', 'status', 'tags', 'title']`, async () => { @@ -264,11 +269,20 @@ export default ({ getService }: FtrProviderContext): void => { }); it(`on new push to service, user action: 'push-to-service' should be called with actionFields: ['pushed']`, async () => { + const { body: connector } = await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'true') + .send(getServiceNowConnector()) + .expect(200); + + actionsRemover.add('default', connector.id, 'action', 'actions'); + const { body: configure } = await supertest .post(CASE_CONFIGURE_URL) .set('kbn-xsrf', 'true') - .send(getConfiguration()) + .send(getConfiguration(connector.id)) .expect(200); + const { body: postedCase } = await supertest .post(CASES_URL) .set('kbn-xsrf', 'true') diff --git a/x-pack/test/case_api_integration/basic/tests/configure/get_connectors.ts b/x-pack/test/case_api_integration/basic/tests/configure/get_connectors.ts index 836c76d500034..f5f290476dd0b 100644 --- a/x-pack/test/case_api_integration/basic/tests/configure/get_connectors.ts +++ b/x-pack/test/case_api_integration/basic/tests/configure/get_connectors.ts @@ -8,12 +8,19 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { CASE_CONFIGURE_CONNECTORS_URL } from '../../../../../plugins/case/common/constants'; +import { ObjectRemover as ActionsRemover } from '../../../../alerting_api_integration/common/lib'; +import { getServiceNowConnector, getJiraConnector } from '../../../common/lib/utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); + const actionsRemover = new ActionsRemover(supertest); describe('get_connectors', () => { + afterEach(async () => { + await actionsRemover.removeAll(); + }); + it('should return an empty find body correctly if no connectors are loaded', async () => { const { body } = await supertest .get(`${CASE_CONFIGURE_CONNECTORS_URL}/_find`) @@ -23,5 +30,54 @@ export default ({ getService }: FtrProviderContext): void => { expect(body).to.eql([]); }); + + it('should return the correct connectors', async () => { + const { body: connectorOne } = await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'true') + .send(getServiceNowConnector()) + .expect(200); + + const { body: connectorTwo } = await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'true') + .send({ + name: 'An email action', + actionTypeId: '.email', + config: { + service: '__json', + from: 'bob@example.com', + }, + secrets: { + user: 'bob', + password: 'supersecret', + }, + }) + .expect(200); + + const { body: connectorThree } = await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'true') + .send(getJiraConnector()) + .expect(200); + + actionsRemover.add('default', connectorOne.id, 'action', 'actions'); + actionsRemover.add('default', connectorTwo.id, 'action', 'actions'); + actionsRemover.add('default', connectorThree.id, 'action', 'actions'); + + const { body: connectors } = await supertest + .get(`${CASE_CONFIGURE_CONNECTORS_URL}/_find`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(connectors.length).to.equal(2); + expect( + connectors.some((c: { actionTypeId: string }) => c.actionTypeId === '.servicenow') + ).to.equal(true); + expect(connectors.some((c: { actionTypeId: string }) => c.actionTypeId === '.jira')).to.equal( + true + ); + }); }); }; diff --git a/x-pack/test/case_api_integration/common/lib/utils.ts b/x-pack/test/case_api_integration/common/lib/utils.ts index 5861db2eb8e5b..fe9cb48178633 100644 --- a/x-pack/test/case_api_integration/common/lib/utils.ts +++ b/x-pack/test/case_api_integration/common/lib/utils.ts @@ -23,7 +23,7 @@ export const getConfigurationOutput = (update = false): Partial ({ +export const getServiceNowConnector = () => ({ name: 'ServiceNow Connector', actionTypeId: '.servicenow', secrets: { @@ -54,6 +54,38 @@ export const getConnector = () => ({ }, }); +export const getJiraConnector = () => ({ + name: 'Jira Connector', + actionTypeId: '.jira', + secrets: { + email: 'elastic@elastic.co', + apiToken: 'token', + }, + config: { + apiUrl: 'http://some.non.existent.com', + projectKey: 'pkey', + casesConfiguration: { + mapping: [ + { + source: 'title', + target: 'summary', + actionType: 'overwrite', + }, + { + source: 'description', + target: 'description', + actionType: 'overwrite', + }, + { + source: 'comments', + target: 'comments', + actionType: 'append', + }, + ], + }, + }, +}); + export const removeServerGeneratedPropertiesFromConfigure = ( config: Partial ): Partial => { From 2279b3dc0b8ae7d42d64934bfeb35296b3785b43 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 28 May 2020 09:46:18 +0200 Subject: [PATCH 04/22] Add /config/apm.dev.js to .eslintignore (#67442) --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index 362b3e42d48e5..c3d7930732fa2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ /.es /build /built_assets +/config/apm.dev.js /data /html_docs /optimize From a5e717c03292740b94e917f7a3a9e90b8a2fd559 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 28 May 2020 11:19:06 +0200 Subject: [PATCH 05/22] fix reporting link (#67440) --- x-pack/plugins/reporting/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/reporting/constants.ts b/x-pack/plugins/reporting/constants.ts index 8079c5b1d9887..9a1d0cec2cf96 100644 --- a/x-pack/plugins/reporting/constants.ts +++ b/x-pack/plugins/reporting/constants.ts @@ -12,7 +12,7 @@ export const API_BASE_URL = '/api/reporting'; export const API_LIST_URL = `${API_BASE_URL}/jobs`; export const API_BASE_GENERATE = `${API_BASE_URL}/generate`; export const API_GENERATE_IMMEDIATE = `${API_BASE_URL}/v1/generate/immediate/csv/saved-object`; -export const REPORTING_MANAGEMENT_HOME = '/app/kibana#/management/kibana/reporting'; +export const REPORTING_MANAGEMENT_HOME = '/app/kibana#/management/insightsAndAlerting/reporting'; // Statuses export const JOB_STATUS_FAILED = 'failed'; From dcca06bad28ffdde0617eea67757879b57af3e05 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 28 May 2020 11:50:56 +0100 Subject: [PATCH 06/22] [ML] Update job service id schema (#67462) --- .../public/application/jobs/jobs_list/components/utils.js | 2 +- .../plugins/ml/server/routes/schemas/job_service_schema.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js index 0a3728c7351b5..15c54fc5b3a46 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js @@ -19,7 +19,7 @@ import { mlCalendarService } from '../../../services/calendar_service'; export function loadFullJob(jobId) { return new Promise((resolve, reject) => { ml.jobs - .jobs(jobId) + .jobs([jobId]) .then((jobs) => { if (jobs.length) { resolve(jobs[0]); diff --git a/x-pack/plugins/ml/server/routes/schemas/job_service_schema.ts b/x-pack/plugins/ml/server/routes/schemas/job_service_schema.ts index 1ca1e5287e9d0..be107db9508fd 100644 --- a/x-pack/plugins/ml/server/routes/schemas/job_service_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/job_service_schema.ts @@ -40,10 +40,8 @@ export const forceStartDatafeedSchema = schema.object({ }); export const jobIdsSchema = schema.object({ - /** Optional list of job ID(s). */ - jobIds: schema.maybe( - schema.oneOf([schema.string(), schema.arrayOf(schema.maybe(schema.string()))]) - ), + /** Optional list of job IDs. */ + jobIds: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), }); export const jobsWithTimerangeSchema = { From e492cf138dcf3309d1685feffb9e6eb8cc0c36c7 Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Thu, 28 May 2020 15:19:25 +0200 Subject: [PATCH 07/22] [ML] Functional tests - add validation messages (#67583) This PR adds validation messages to all ML and Transform services in order to make it easier to debug test failures. --- x-pack/test/api_integration/apis/ml/index.ts | 3 + .../functional/services/ml/anomalies_table.ts | 2 +- x-pack/test/functional/services/ml/api.ts | 20 +++- .../functional/services/ml/custom_urls.ts | 18 +++- .../ml/data_frame_analytics_creation.ts | 4 +- .../services/ml/data_frame_analytics_table.ts | 7 +- .../ml/data_visualizer_index_based.ts | 25 ++++- .../test/functional/services/ml/job_table.ts | 5 +- .../services/ml/job_wizard_advanced.ts | 80 +++++++++++--- .../services/ml/job_wizard_categorization.ts | 4 +- .../services/ml/job_wizard_common.ts | 100 ++++++++++++++---- .../services/ml/job_wizard_multi_metric.ts | 25 +++-- .../services/ml/job_wizard_population.ts | 41 ++++--- .../test/functional/services/ml/navigation.ts | 6 +- .../test/functional/services/transform/api.ts | 5 +- .../services/transform/transform_table.ts | 12 ++- .../functional/services/transform/wizard.ts | 52 +++++---- 17 files changed, 303 insertions(+), 106 deletions(-) diff --git a/x-pack/test/api_integration/apis/ml/index.ts b/x-pack/test/api_integration/apis/ml/index.ts index 3a4453e7ae40a..403179ec4ac28 100644 --- a/x-pack/test/api_integration/apis/ml/index.ts +++ b/x-pack/test/api_integration/apis/ml/index.ts @@ -23,10 +23,13 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await ml.securityCommon.cleanMlRoles(); await ml.testResources.deleteIndexPattern('kibana_sample_data_logs'); + await ml.testResources.deleteIndexPattern('ft_farequote'); await esArchiver.unload('ml/ecommerce'); await esArchiver.unload('ml/categorization'); await esArchiver.unload('ml/sample_logs'); + await esArchiver.unload('ml/farequote'); + await esArchiver.unload('ml/bm_classification'); await ml.testResources.resetKibanaTimeZone(); }); diff --git a/x-pack/test/functional/services/ml/anomalies_table.ts b/x-pack/test/functional/services/ml/anomalies_table.ts index c8701099dcd7a..26af97d008feb 100644 --- a/x-pack/test/functional/services/ml/anomalies_table.ts +++ b/x-pack/test/functional/services/ml/anomalies_table.ts @@ -19,7 +19,7 @@ export function MachineLearningAnomaliesTableProvider({ getService }: FtrProvide const tableRows = await testSubjects.findAll('mlAnomaliesTable > ~mlAnomaliesListRow'); expect(tableRows.length).to.be.greaterThan( 0, - 'Anomalies table should have at least one row (got 0)' + `Anomalies table should have at least one row (got '${tableRows.length}')` ); }, }; diff --git a/x-pack/test/functional/services/ml/api.ts b/x-pack/test/functional/services/ml/api.ts index 3f3f6cdde1724..897f37821001e 100644 --- a/x-pack/test/functional/services/ml/api.ts +++ b/x-pack/test/functional/services/ml/api.ts @@ -140,7 +140,10 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { async getJobState(jobId: string): Promise { const jobStats = await this.getADJobStats(jobId); - expect(jobStats.jobs).to.have.length(1); + expect(jobStats.jobs).to.have.length( + 1, + `Expected job stats to have exactly one job (got '${jobStats.length}')` + ); const state: JOB_STATE = jobStats.jobs[0].state; return state; @@ -178,7 +181,10 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { .expect(200) .then((res: any) => res.body); - expect(datafeedStats.datafeeds).to.have.length(1); + expect(datafeedStats.datafeeds).to.have.length( + 1, + `Expected datafeed stats to have exactly one datafeed (got '${datafeedStats.datafeeds.length}')` + ); const state: DATAFEED_STATE = datafeedStats.datafeeds[0].state; return state; @@ -206,7 +212,10 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { .expect(200) .then((res: any) => res.body); - expect(analyticsStats.data_frame_analytics).to.have.length(1); + expect(analyticsStats.data_frame_analytics).to.have.length( + 1, + `Expected dataframe analytics stats to have exactly one object (got '${analyticsStats.data_frame_analytics.length}')` + ); const state: DATA_FRAME_TASK_STATE = analyticsStats.data_frame_analytics[0].state; return state; @@ -414,7 +423,10 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { async getADJobRecordCount(jobId: string): Promise { const jobStats = await this.getADJobStats(jobId); - expect(jobStats.jobs).to.have.length(1); + expect(jobStats.jobs).to.have.length( + 1, + `Expected job stats to have exactly one job (got '${jobStats.jobs.length}')` + ); const processedRecordCount: number = jobStats.jobs[0].data_counts.processed_record_count; return processedRecordCount; diff --git a/x-pack/test/functional/services/ml/custom_urls.ts b/x-pack/test/functional/services/ml/custom_urls.ts index 6842908462018..4acbd23cd3580 100644 --- a/x-pack/test/functional/services/ml/custom_urls.ts +++ b/x-pack/test/functional/services/ml/custom_urls.ts @@ -19,7 +19,10 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon 'mlJobCustomUrlLabelInput', 'value' ); - expect(actualCustomUrlLabel).to.eql(expectedValue); + expect(actualCustomUrlLabel).to.eql( + expectedValue, + `Expected custom url label to be '${expectedValue}' (got '${actualCustomUrlLabel}')` + ); }, async setCustomUrlLabel(customUrlsLabel: string) { @@ -29,11 +32,16 @@ export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderCon await this.assertCustomUrlLabelValue(customUrlsLabel); }, - async assertCustomUrlItem(index: number, label: string) { + async assertCustomUrlItem(index: number, expectedLabel: string) { await testSubjects.existOrFail(`mlJobEditCustomUrlItem_${index}`); - expect( - await testSubjects.getAttribute(`mlJobEditCustomUrlLabelInput_${index}`, 'value') - ).to.eql(label); + const actualLabel = await testSubjects.getAttribute( + `mlJobEditCustomUrlLabelInput_${index}`, + 'value' + ); + expect(actualLabel).to.eql( + expectedLabel, + `Expected custom url item to be '${expectedLabel}' (got '${actualLabel}')` + ); }, /** diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts index d67f6bc946df2..cff7e00eef688 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts @@ -75,7 +75,7 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( )) === 'true'; expect(actualCheckState).to.eql( expectedCheckState, - `Advanced editor switch check state should be ${expectedCheckState} (got ${actualCheckState})` + `Advanced editor switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, @@ -317,7 +317,7 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( const actualCheckState = await this.getCreateIndexPatternSwitchCheckState(); expect(actualCheckState).to.eql( expectedCheckState, - `Create index pattern switch check state should be ${expectedCheckState} (got ${actualCheckState})` + `Create index pattern switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_table.ts b/x-pack/test/functional/services/ml/data_frame_analytics_table.ts index 2a621aaf28fe3..d5f4ee63f615b 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_table.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_table.ts @@ -107,7 +107,12 @@ export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: F public async assertAnalyticsRowFields(analyticsId: string, expectedRow: object) { const rows = await this.parseAnalyticsTable(); const analyticsRow = rows.filter((row) => row.id === analyticsId)[0]; - expect(analyticsRow).to.eql(expectedRow); + expect(analyticsRow).to.eql( + expectedRow, + `Expected analytics row to be '${JSON.stringify(expectedRow)}' (got '${JSON.stringify( + analyticsRow + )}')` + ); } public async openRowActions(analyticsId: string) { diff --git a/x-pack/test/functional/services/ml/data_visualizer_index_based.ts b/x-pack/test/functional/services/ml/data_visualizer_index_based.ts index 792dd5f90ca11..7789ca78363df 100644 --- a/x-pack/test/functional/services/ml/data_visualizer_index_based.ts +++ b/x-pack/test/functional/services/ml/data_visualizer_index_based.ts @@ -23,7 +23,10 @@ export function MachineLearningDataVisualizerIndexBasedProvider({ async assertTotalDocumentCount(expectedTotalDocCount: number) { await retry.tryForTime(5000, async () => { const docCount = await testSubjects.getVisibleText('mlDataVisualizerTotalDocCount'); - expect(docCount).to.eql(expectedTotalDocCount); + expect(docCount).to.eql( + expectedTotalDocCount, + `Expected total document count to be '${expectedTotalDocCount}' (got '${docCount}')` + ); }); }, @@ -34,7 +37,10 @@ export function MachineLearningDataVisualizerIndexBasedProvider({ async assertFieldsPanelsExist(expectedPanelCount: number) { const allPanels = await testSubjects.findAll('~mlDataVisualizerFieldsPanel'); - expect(allPanels).to.have.length(expectedPanelCount); + expect(allPanels).to.have.length( + expectedPanelCount, + `Expected field panels count to be '${expectedPanelCount}' (got '${allPanels.length}')` + ); }, async assertFieldsPanelForTypesExist(fieldTypes: ML_JOB_FIELD_TYPES[]) { @@ -50,7 +56,10 @@ export function MachineLearningDataVisualizerIndexBasedProvider({ const filteredCards = await testSubjects.findAll( `mlDataVisualizerFieldsPanel ${panelFieldTypes} > ~mlFieldDataCard` ); - expect(filteredCards).to.have.length(expectedCardCount); + expect(filteredCards).to.have.length( + expectedCardCount, + `Expected field card count for panels '${panelFieldTypes}' to be '${expectedCardCount}' (got '${filteredCards.length}')` + ); }); }, @@ -60,7 +69,10 @@ export function MachineLearningDataVisualizerIndexBasedProvider({ ); const searchBarInput = await searchBar.findByTagName('input'); const actualSearchValue = await searchBarInput.getAttribute('value'); - expect(actualSearchValue).to.eql(expectedSearchValue); + expect(actualSearchValue).to.eql( + expectedSearchValue, + `Expected search value for field types '${fieldTypes}' to be '${expectedSearchValue}' (got '${actualSearchValue}')` + ); }, async filterFieldsPanelWithSearchString( @@ -91,7 +103,10 @@ export function MachineLearningDataVisualizerIndexBasedProvider({ 'mlDataVisualizerFieldTypesSelect', 'value' ); - expect(actualTypeValue).to.eql(expectedTypeValue); + expect(actualTypeValue).to.eql( + expectedTypeValue, + `Expected fields panel type value to be '${expectedTypeValue}' (got '${actualTypeValue}')` + ); }, async setFieldsPanelTypeInputValue( diff --git a/x-pack/test/functional/services/ml/job_table.ts b/x-pack/test/functional/services/ml/job_table.ts index cfb3ed8977716..a72d9c204060b 100644 --- a/x-pack/test/functional/services/ml/job_table.ts +++ b/x-pack/test/functional/services/ml/job_table.ts @@ -163,7 +163,10 @@ export function MachineLearningJobTableProvider({ getService }: FtrProviderConte await this.refreshJobList(); const rows = await this.parseJobTable(); const jobRow = rows.filter((row) => row.id === jobId)[0]; - expect(jobRow).to.eql(expectedRow); + expect(jobRow).to.eql( + expectedRow, + `Expected job row to be '${JSON.stringify(expectedRow)}' (got '${JSON.stringify(jobRow)}')` + ); } public async assertJobRowDetailsCounts( diff --git a/x-pack/test/functional/services/ml/job_wizard_advanced.ts b/x-pack/test/functional/services/ml/job_wizard_advanced.ts index 755091ca10f3b..e4d2ecf66f646 100644 --- a/x-pack/test/functional/services/ml/job_wizard_advanced.ts +++ b/x-pack/test/functional/services/ml/job_wizard_advanced.ts @@ -35,7 +35,10 @@ export function MachineLearningJobWizardAdvancedProvider( const actualValue = await aceEditor.getValue( 'mlAdvancedDatafeedQueryEditor > codeEditorContainer' ); - expect(actualValue).to.eql(expectedValue); + expect(actualValue).to.eql( + expectedValue, + `Expected datafeed query editor value to be '${expectedValue}' (got '${actualValue}')` + ); }, async assertQueryDelayInputExists() { @@ -44,7 +47,10 @@ export function MachineLearningJobWizardAdvancedProvider( async assertQueryDelayValue(expectedValue: string) { const actualQueryDelay = await this.getValueOrPlaceholder('mlJobWizardInputQueryDelay'); - expect(actualQueryDelay).to.eql(expectedValue); + expect(actualQueryDelay).to.eql( + expectedValue, + `Expected query delay value to be '${expectedValue}' (got '${actualQueryDelay}')` + ); }, async setQueryDelay(queryDelay: string) { @@ -61,7 +67,10 @@ export function MachineLearningJobWizardAdvancedProvider( async assertFrequencyValue(expectedValue: string) { const actualFrequency = await this.getValueOrPlaceholder('mlJobWizardInputFrequency'); - expect(actualFrequency).to.eql(expectedValue); + expect(actualFrequency).to.eql( + expectedValue, + `Expected frequency value to be '${expectedValue}' (got '${actualFrequency}')` + ); }, async setFrequency(frequency: string) { @@ -78,7 +87,10 @@ export function MachineLearningJobWizardAdvancedProvider( async assertScrollSizeValue(expectedValue: string) { const actualScrollSize = await this.getValueOrPlaceholder('mlJobWizardInputScrollSize'); - expect(actualScrollSize).to.eql(expectedValue); + expect(actualScrollSize).to.eql( + expectedValue, + `Expected scroll size value to be '${expectedValue}' (got '${actualScrollSize}')` + ); }, async setScrollSize(scrollSize: string) { @@ -97,7 +109,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlTimeFieldNameSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected time field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectTimeField(identifier: string) { @@ -113,7 +128,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlCategorizationFieldNameSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected categorization field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectCategorizationField(identifier: string) { @@ -129,7 +147,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlSummaryCountFieldNameSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected summary count field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectSummaryCountField(identifier: string) { @@ -160,7 +181,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlAdvancedFunctionSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector function selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorFunction(identifier: string) { @@ -176,7 +200,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlAdvancedFieldSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorField(identifier: string) { @@ -192,7 +219,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlAdvancedByFieldSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector by field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorByField(identifier: string) { @@ -208,7 +238,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlAdvancedOverFieldSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector over field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorOverField(identifier: string) { @@ -224,7 +257,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlAdvancedPartitionFieldSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector partition field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorPartitionField(identifier: string) { @@ -240,7 +276,10 @@ export function MachineLearningJobWizardAdvancedProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlAdvancedExcludeFrequentSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector exclude frequent selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorExcludeFrequent(identifier: string) { @@ -257,7 +296,10 @@ export function MachineLearningJobWizardAdvancedProvider( 'mlAdvancedDetectorDescriptionInput', 'value' ); - expect(actualDetectorDescription).to.eql(expectedValue); + expect(actualDetectorDescription).to.eql( + expectedValue, + `Expected detector description value to be '${expectedValue}' (got '${actualDetectorDescription}')` + ); }, async setDetectorDescription(description: string) { @@ -287,13 +329,19 @@ export function MachineLearningJobWizardAdvancedProvider( const actualDetectorIdentifier = await testSubjects.getVisibleText( `mlAdvancedDetector ${detectorIndex} > mlDetectorIdentifier` ); - expect(actualDetectorIdentifier).to.eql(expectedDetectorName); + expect(actualDetectorIdentifier).to.eql( + expectedDetectorName, + `Expected detector name to be '${expectedDetectorName}' (got '${actualDetectorIdentifier}')` + ); if (expectedDetectorDescription !== undefined) { const actualDetectorDescription = await testSubjects.getVisibleText( `mlAdvancedDetector ${detectorIndex} > mlDetectorDescription` ); - expect(actualDetectorDescription).to.eql(expectedDetectorDescription); + expect(actualDetectorDescription).to.eql( + expectedDetectorDescription, + `Expected detector description to be '${expectedDetectorDescription}' (got '${actualDetectorDescription}')` + ); } }, diff --git a/x-pack/test/functional/services/ml/job_wizard_categorization.ts b/x-pack/test/functional/services/ml/job_wizard_categorization.ts index 97d45701a2685..705cc29938dfb 100644 --- a/x-pack/test/functional/services/ml/job_wizard_categorization.ts +++ b/x-pack/test/functional/services/ml/job_wizard_categorization.ts @@ -41,7 +41,7 @@ export function MachineLearningJobWizardCategorizationProvider({ getService }: F ); expect(comboBoxSelectedOptions).to.eql( expectedIdentifier, - `Expected categorization field selection to be '${expectedIdentifier}' (got ${comboBoxSelectedOptions}')` + `Expected categorization field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` ); }, @@ -56,7 +56,7 @@ export function MachineLearningJobWizardCategorizationProvider({ getService }: F const rows = await body[0].findAllByTagName('tr'); expect(rows.length).to.eql( exampleCount, - `Expected categorization field examples table to have '${exampleCount}' rows (got ${rows.length}')` + `Expected categorization field examples table to have '${exampleCount}' rows (got '${rows.length}')` ); }, }; diff --git a/x-pack/test/functional/services/ml/job_wizard_common.ts b/x-pack/test/functional/services/ml/job_wizard_common.ts index af33ec2301edc..2843c36e08a1d 100644 --- a/x-pack/test/functional/services/ml/job_wizard_common.ts +++ b/x-pack/test/functional/services/ml/job_wizard_common.ts @@ -101,7 +101,10 @@ export function MachineLearningJobWizardCommonProvider( const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlJobWizardAggSelection > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected agg and field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectAggAndField(identifier: string, isIdentifierKeptInField: boolean) { @@ -118,7 +121,10 @@ export function MachineLearningJobWizardCommonProvider( 'mlJobWizardInputBucketSpan', 'value' ); - expect(actualBucketSpan).to.eql(expectedValue); + expect(actualBucketSpan).to.eql( + expectedValue, + `Expected bucket span value to be '${expectedValue}' (got '${actualBucketSpan}')` + ); }, async setBucketSpan(bucketSpan: string) { @@ -135,7 +141,10 @@ export function MachineLearningJobWizardCommonProvider( async assertJobIdValue(expectedValue: string) { const actualJobId = await testSubjects.getAttribute('mlJobWizardInputJobId', 'value'); - expect(actualJobId).to.eql(expectedValue); + expect(actualJobId).to.eql( + expectedValue, + `Expected job id value to be '${expectedValue}' (got '${actualJobId}')` + ); }, async setJobId(jobId: string) { @@ -153,7 +162,10 @@ export function MachineLearningJobWizardCommonProvider( const actualJobDescription = await testSubjects.getVisibleText( 'mlJobWizardInputJobDescription' ); - expect(actualJobDescription).to.eql(expectedValue); + expect(actualJobDescription).to.eql( + expectedValue, + `Expected job description value to be '${expectedValue}' (got '${actualJobDescription}')` + ); }, async setJobDescription(jobDescription: string) { @@ -174,12 +186,20 @@ export function MachineLearningJobWizardCommonProvider( }, async assertJobGroupSelection(jobGroups: string[]) { - expect(await this.getSelectedJobGroups()).to.eql(jobGroups); + const actualJobGroupSelection = await this.getSelectedJobGroups(); + expect(actualJobGroupSelection).to.eql( + jobGroups, + `Expected job group selection to be '${jobGroups}' (got '${actualJobGroupSelection}')` + ); }, async addJobGroup(jobGroup: string) { await comboBox.setCustom('mlJobWizardComboBoxJobGroups > comboBoxInput', jobGroup); - expect(await this.getSelectedJobGroups()).to.contain(jobGroup); + const actualJobGroupSelection = await this.getSelectedJobGroups(); + expect(actualJobGroupSelection).to.contain( + jobGroup, + `Expected job group selection to contain '${jobGroup}' (got '${actualJobGroupSelection}')` + ); }, async getSelectedCalendars(): Promise { @@ -190,13 +210,21 @@ export function MachineLearningJobWizardCommonProvider( }, async assertCalendarsSelection(calendars: string[]) { - expect(await this.getSelectedCalendars()).to.eql(calendars); + const actualCalendarSelection = await this.getSelectedCalendars(); + expect(actualCalendarSelection).to.eql( + calendars, + `Expected calendar selection to be '${calendars}' (got '${actualCalendarSelection}')` + ); }, async addCalendar(calendarId: string) { await this.ensureAdditionalSettingsSectionOpen(); await comboBox.setCustom('mlJobWizardComboBoxCalendars > comboBoxInput', calendarId); - expect(await this.getSelectedCalendars()).to.contain(calendarId); + const actualCalendarSelection = await this.getSelectedCalendars(); + expect(actualCalendarSelection).to.contain( + calendarId, + `Expected calendar selection to conatin '${calendarId}' (got '${actualCalendarSelection}')` + ); }, async assertModelPlotSwitchExists( @@ -229,14 +257,19 @@ export function MachineLearningJobWizardCommonProvider( const actualCheckedState = await this.getModelPlotSwitchCheckedState({ withAdvancedSection: sectionOptions.withAdvancedSection, }); - expect(actualCheckedState).to.eql(expectedValue); + expect(actualCheckedState).to.eql( + expectedValue, + `Expected model plot switch to be '${expectedValue ? 'enabled' : 'disabled'}' (got '${ + actualCheckedState ? 'enabled' : 'disabled' + }')` + ); }, async assertModelPlotSwitchEnabled(expectedValue: boolean) { const isEnabled = await testSubjects.isEnabled('mlJobWizardSwitchModelPlot'); expect(isEnabled).to.eql( expectedValue, - `Expected model plot switch to be '${expectedValue ? 'enabled' : 'disabled'}' (got ${ + `Expected model plot switch to be '${expectedValue ? 'enabled' : 'disabled'}' (got '${ isEnabled ? 'enabled' : 'disabled' }')` ); @@ -272,7 +305,12 @@ export function MachineLearningJobWizardCommonProvider( const actualCheckedState = await this.getDedicatedIndexSwitchCheckedState({ withAdvancedSection: sectionOptions.withAdvancedSection, }); - expect(actualCheckedState).to.eql(expectedValue); + expect(actualCheckedState).to.eql( + expectedValue, + `Expected dedicated index switch to be '${expectedValue ? 'enabled' : 'disabled'}' (got '${ + actualCheckedState ? 'enabled' : 'disabled' + }')` + ); }, async activateDedicatedIndexSwitch( @@ -318,7 +356,10 @@ export function MachineLearningJobWizardCommonProvider( subj = advancedSectionSelector(subj); } const actualModelMemoryLimit = await testSubjects.getAttribute(subj, 'value'); - expect(actualModelMemoryLimit).to.eql(expectedValue); + expect(actualModelMemoryLimit).to.eql( + expectedValue, + `Expected model memory limit value to be '${expectedValue}' (got '${actualModelMemoryLimit}')` + ); }, async setModelMemoryLimit( @@ -347,12 +388,20 @@ export function MachineLearningJobWizardCommonProvider( }, async assertInfluencerSelection(influencers: string[]) { - expect(await this.getSelectedInfluencers()).to.eql(influencers); + const actualInfluencerSelection = await this.getSelectedInfluencers(); + expect(actualInfluencerSelection).to.eql( + influencers, + `Expected influencer selection to be '${influencers}' (got '${actualInfluencerSelection}')` + ); }, async addInfluencer(influencer: string) { await comboBox.set('mlInfluencerSelect > comboBoxInput', influencer); - expect(await this.getSelectedInfluencers()).to.contain(influencer); + const actualInfluencerSelection = await this.getSelectedInfluencers(); + expect(actualInfluencerSelection).to.contain( + influencer, + `Expected influencer selection to contain '${influencer}' (got '${actualInfluencerSelection}')` + ); }, async assertAnomalyChartExists(chartType: string, preSelector?: string) { @@ -367,9 +416,13 @@ export function MachineLearningJobWizardCommonProvider( ) { await testSubjects.existOrFail(`mlDetector ${detectorPosition}`); await testSubjects.existOrFail(`mlDetector ${detectorPosition} > mlDetectorTitle`); - expect( - await testSubjects.getVisibleText(`mlDetector ${detectorPosition} > mlDetectorTitle`) - ).to.eql(aggAndFieldIdentifier); + const actualDetectorTitle = await testSubjects.getVisibleText( + `mlDetector ${detectorPosition} > mlDetectorTitle` + ); + expect(actualDetectorTitle).to.eql( + aggAndFieldIdentifier, + `Expected detector title at position '${detectorPosition}' to be '${aggAndFieldIdentifier}' (got '${actualDetectorTitle}')` + ); await this.assertAnomalyChartExists(chartType, `mlDetector ${detectorPosition}`); }, @@ -393,10 +446,15 @@ export function MachineLearningJobWizardCommonProvider( async assertDateRangeSelection(expectedStartDate: string, expectedEndDate: string) { await retry.tryForTime(5000, async () => { - expect(await this.getSelectedDateRange()).to.eql({ - startDate: expectedStartDate, - endDate: expectedEndDate, - }); + const { startDate, endDate } = await this.getSelectedDateRange(); + expect(startDate).to.eql( + expectedStartDate, + `Expected start date to be '${expectedStartDate}' (got '${startDate}')` + ); + expect(endDate).to.eql( + expectedEndDate, + `Expected end date to be '${expectedEndDate}' (got '${endDate}')` + ); }); }, diff --git a/x-pack/test/functional/services/ml/job_wizard_multi_metric.ts b/x-pack/test/functional/services/ml/job_wizard_multi_metric.ts index 2fb768d924cff..c1c945933b106 100644 --- a/x-pack/test/functional/services/ml/job_wizard_multi_metric.ts +++ b/x-pack/test/functional/services/ml/job_wizard_multi_metric.ts @@ -20,7 +20,10 @@ export function MachineLearningJobWizardMultiMetricProvider({ getService }: FtrP const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlMultiMetricSplitFieldSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected split field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectSplitField(identifier: string) { @@ -33,15 +36,21 @@ export function MachineLearningJobWizardMultiMetricProvider({ getService }: FtrP await testSubjects.existOrFail(`mlDataSplit > mlSplitCard front`); }, - async assertDetectorSplitFrontCardTitle(frontCardTitle: string) { - expect( - await testSubjects.getVisibleText(`mlDataSplit > mlSplitCard front > mlSplitCardTitle`) - ).to.eql(frontCardTitle); + async assertDetectorSplitFrontCardTitle(expectedFrontCardTitle: string) { + const actualFrontCardTitle = await testSubjects.getVisibleText( + `mlDataSplit > mlSplitCard front > mlSplitCardTitle` + ); + expect(actualFrontCardTitle).to.eql( + expectedFrontCardTitle, + `Expected front card title to be '${expectedFrontCardTitle}' (got '${actualFrontCardTitle}')` + ); }, - async assertDetectorSplitNumberOfBackCards(numberOfBackCards: number) { - expect(await testSubjects.findAll(`mlDataSplit > mlSplitCard back`)).to.have.length( - numberOfBackCards + async assertDetectorSplitNumberOfBackCards(expectedNumberOfBackCards: number) { + const allBackCards = await testSubjects.findAll(`mlDataSplit > mlSplitCard back`); + expect(allBackCards).to.have.length( + expectedNumberOfBackCards, + `Expected number of back cards to be '${expectedNumberOfBackCards}' (got '${allBackCards.length}')` ); }, }; diff --git a/x-pack/test/functional/services/ml/job_wizard_population.ts b/x-pack/test/functional/services/ml/job_wizard_population.ts index 8ff9d5c12a642..88b773b201c51 100644 --- a/x-pack/test/functional/services/ml/job_wizard_population.ts +++ b/x-pack/test/functional/services/ml/job_wizard_population.ts @@ -20,7 +20,10 @@ export function MachineLearningJobWizardPopulationProvider({ getService }: FtrPr const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'mlPopulationSplitFieldSelect > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected population field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectPopulationField(identifier: string) { @@ -41,7 +44,10 @@ export function MachineLearningJobWizardPopulationProvider({ getService }: FtrPr const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( `mlDetector ${detectorPosition} > mlByFieldSelect > comboBoxInput` ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected detector split field selection to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }, async selectDetectorSplitField(detectorPosition: number, identifier: string) { @@ -59,23 +65,30 @@ export function MachineLearningJobWizardPopulationProvider({ getService }: FtrPr ); }, - async assertDetectorSplitFrontCardTitle(detectorPosition: number, frontCardTitle: string) { - expect( - await testSubjects.getVisibleText( - `mlDetector ${detectorPosition} > mlDataSplit > mlSplitCard front > mlSplitCardTitle` - ) - ).to.eql(frontCardTitle); + async assertDetectorSplitFrontCardTitle( + detectorPosition: number, + expectedFrontCardTitle: string + ) { + const actualSplitFrontCardTitle = await testSubjects.getVisibleText( + `mlDetector ${detectorPosition} > mlDataSplit > mlSplitCard front > mlSplitCardTitle` + ); + expect(actualSplitFrontCardTitle).to.eql( + expectedFrontCardTitle, + `Expected front card title for detector position '${detectorPosition}' to be '${expectedFrontCardTitle}' (got '${actualSplitFrontCardTitle}')` + ); }, async assertDetectorSplitNumberOfBackCards( detectorPosition: number, - numberOfBackCards: number + expectedNumberOfBackCards: number ) { - expect( - await testSubjects.findAll( - `mlDetector ${detectorPosition} > mlDataSplit > mlSplitCard back` - ) - ).to.have.length(numberOfBackCards); + const allBackCards = await testSubjects.findAll( + `mlDetector ${detectorPosition} > mlDataSplit > mlSplitCard back` + ); + expect(allBackCards).to.have.length( + expectedNumberOfBackCards, + `Expected number of back cards for detector position '${detectorPosition}' to be '${expectedNumberOfBackCards}' (got '${allBackCards.length}')` + ); }, }; } diff --git a/x-pack/test/functional/services/ml/navigation.ts b/x-pack/test/functional/services/ml/navigation.ts index b0f993eab1a2b..8454a0b071b8f 100644 --- a/x-pack/test/functional/services/ml/navigation.ts +++ b/x-pack/test/functional/services/ml/navigation.ts @@ -25,8 +25,10 @@ export function MachineLearningNavigationProvider({ async assertTabsExist(tabTypeSubject: string, areaSubjects: string[]) { await retry.tryForTime(10000, async () => { - expect(await testSubjects.findAll(`~${tabTypeSubject}`, 3)).to.have.length( - areaSubjects.length + const allTabs = await testSubjects.findAll(`~${tabTypeSubject}`, 3); + expect(allTabs).to.have.length( + areaSubjects.length, + `Expected number of '${tabTypeSubject}' to be '${areaSubjects.length}' (got '${allTabs.length}')` ); for (const areaSubj of areaSubjects) { await testSubjects.existOrFail(`~${tabTypeSubject}&~${areaSubj}`, { timeout: 1000 }); diff --git a/x-pack/test/functional/services/transform/api.ts b/x-pack/test/functional/services/transform/api.ts index 5c7f04e7bc1a5..a805f5a3b6013 100644 --- a/x-pack/test/functional/services/transform/api.ts +++ b/x-pack/test/functional/services/transform/api.ts @@ -54,7 +54,10 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { .expect(200) .then((res: any) => res.body); - expect(statsResponse.transforms).to.have.length(1); + expect(statsResponse.transforms).to.have.length( + 1, + `Expected transform stats to contain exactly 1 object (got '${statsResponse.transforms.length}')` + ); return statsResponse.transforms[0]; }, diff --git a/x-pack/test/functional/services/transform/transform_table.ts b/x-pack/test/functional/services/transform/transform_table.ts index 7bbe6724e3fff..3155ef0b26050 100644 --- a/x-pack/test/functional/services/transform/transform_table.ts +++ b/x-pack/test/functional/services/transform/transform_table.ts @@ -98,7 +98,10 @@ export function TransformTableProvider({ getService }: FtrProviderContext) { uniqueColumnValues.sort(); // check if the returned unique value matches the supplied filter value - expect(uniqueColumnValues).to.eql(expectedColumnValues); + expect(uniqueColumnValues).to.eql( + expectedColumnValues, + `Expected '${tableSubj}' column values to be '${expectedColumnValues}' (got '${uniqueColumnValues}')` + ); }); } @@ -123,7 +126,12 @@ export function TransformTableProvider({ getService }: FtrProviderContext) { public async assertTransformRowFields(transformId: string, expectedRow: object) { const rows = await this.parseTransformTable(); const transformRow = rows.filter((row) => row.id === transformId)[0]; - expect(transformRow).to.eql(expectedRow); + expect(transformRow).to.eql( + expectedRow, + `Expected transform row to be '${JSON.stringify(expectedRow)}' (got '${JSON.stringify( + transformRow + )}')` + ); } public async assertTransformExpandedRow() { diff --git a/x-pack/test/functional/services/transform/wizard.ts b/x-pack/test/functional/services/transform/wizard.ts index f2753ab645b9d..6a99e6ed007b6 100644 --- a/x-pack/test/functional/services/transform/wizard.ts +++ b/x-pack/test/functional/services/transform/wizard.ts @@ -120,20 +120,20 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { }); }, - async assertIndexPreview(columns: number, rows: number) { + async assertIndexPreview(columns: number, expectedNumberOfRows: number) { await retry.tryForTime(2000, async () => { // get a 2D array of rows and cell values const rowsData = await this.parseEuiDataGrid('transformIndexPreview'); expect(rowsData).to.length( - rows, - `EuiDataGrid rows should be ${rows} (got ${rowsData.length})` + expectedNumberOfRows, + `EuiDataGrid rows should be '${expectedNumberOfRows}' (got '${rowsData.length}')` ); rowsData.map((r, i) => expect(r).to.length( columns, - `EuiDataGrid row #${i + 1} column count should be ${columns} (got ${r.length})` + `EuiDataGrid row #${i + 1} column count should be '${columns}' (got '${r.length}')` ) ); }); @@ -185,7 +185,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { 'true'; expect(actualCheckState).to.eql( expectedCheckState, - `Advanced query editor switch check state should be ${expectedCheckState} (got ${actualCheckState})` + `Advanced query editor switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, @@ -198,7 +198,10 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'transformGroupBySelection > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected group by value to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }); }, @@ -214,7 +217,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { ); expect(actualLabel).to.eql( expectedLabel, - `Label for group by entry ${index} should be '${expectedLabel}' (got '${actualLabel}')` + `Label for group by entry '${index}' should be '${expectedLabel}' (got '${actualLabel}')` ); if (expectedIntervalLabel !== undefined) { @@ -223,7 +226,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { ); expect(actualIntervalLabel).to.eql( expectedIntervalLabel, - `Label for group by entry ${index} should be '${expectedIntervalLabel}' (got '${actualIntervalLabel}')` + `Label for group by entry '${index}' should be '${expectedIntervalLabel}' (got '${actualIntervalLabel}')` ); } }, @@ -248,7 +251,10 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { const comboBoxSelectedOptions = await comboBox.getComboBoxSelectedOptions( 'transformAggregationSelection > comboBoxInput' ); - expect(comboBoxSelectedOptions).to.eql(expectedIdentifier); + expect(comboBoxSelectedOptions).to.eql( + expectedIdentifier, + `Expected aggregation value to be '${expectedIdentifier}' (got '${comboBoxSelectedOptions}')` + ); }); }, @@ -260,7 +266,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { ); expect(actualLabel).to.eql( expectedLabel, - `Label for aggregation entry ${index} should be '${expectedLabel}' (got '${actualLabel}')` + `Label for aggregation entry '${index}' should be '${expectedLabel}' (got '${actualLabel}')` ); }, @@ -278,7 +284,11 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { // const advancedEditorValue = JSON.parse(advancedEditorString); // expect(advancedEditorValue).to.eql(expectedValue); - expect(advancedEditorString.split('\n').splice(0, 3)).to.eql(expectedValue); + const splicedAdvancedEditorValue = advancedEditorString.split('\n').splice(0, 3); + expect(splicedAdvancedEditorValue).to.eql( + expectedValue, + `Expected the first editor lines to be '${expectedValue}' (got '${splicedAdvancedEditorValue}')` + ); }, async assertAdvancedPivotEditorSwitchExists() { @@ -291,7 +301,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { 'true'; expect(actualCheckState).to.eql( expectedCheckState, - `Advanced pivot editor switch check state should be ${expectedCheckState} (got ${actualCheckState})` + `Advanced pivot editor switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, @@ -310,7 +320,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { const actualTransformId = await testSubjects.getAttribute('transformIdInput', 'value'); expect(actualTransformId).to.eql( expectedValue, - `Transform id input text should be ${expectedValue} (got ${actualTransformId})` + `Transform id input text should be '${expectedValue}' (got '${actualTransformId}')` ); }, @@ -330,7 +340,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { ); expect(actualTransformDescription).to.eql( expectedValue, - `Transform description input text should be ${expectedValue} (got ${actualTransformDescription})` + `Transform description input text should be '${expectedValue}' (got '${actualTransformDescription}')` ); }, @@ -352,7 +362,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { ); expect(actualDestinationIndex).to.eql( expectedValue, - `Destination index input text should be ${expectedValue} (got ${actualDestinationIndex})` + `Destination index input text should be '${expectedValue}' (got '${actualDestinationIndex}')` ); }, @@ -373,7 +383,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { 'true'; expect(actualCheckState).to.eql( expectedCheckState, - `Create index pattern switch check state should be ${expectedCheckState} (got ${actualCheckState})` + `Create index pattern switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, @@ -387,7 +397,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { 'true'; expect(actualCheckState).to.eql( expectedCheckState, - `Continuous mode switch check state should be ${expectedCheckState} (got ${actualCheckState})` + `Continuous mode switch check state should be '${expectedCheckState}' (got '${actualCheckState}')` ); }, @@ -405,7 +415,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { expectedValue, `Expected 'Create and start' button to be '${ expectedValue ? 'enabled' : 'disabled' - }' (got ${isEnabled ? 'enabled' : 'disabled'}')` + }' (got '${isEnabled ? 'enabled' : 'disabled'}')` ); }, @@ -421,7 +431,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { const isEnabled = await testSubjects.isEnabled('transformWizardCreateButton'); expect(isEnabled).to.eql( expectedValue, - `Expected 'Create' button to be '${expectedValue ? 'enabled' : 'disabled'}' (got ${ + `Expected 'Create' button to be '${expectedValue ? 'enabled' : 'disabled'}' (got '${ isEnabled ? 'enabled' : 'disabled' }')` ); @@ -441,7 +451,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { expectedValue, `Expected 'Copy to clipboard' button to be '${ expectedValue ? 'enabled' : 'disabled' - }' (got ${isEnabled ? 'enabled' : 'disabled'}')` + }' (got '${isEnabled ? 'enabled' : 'disabled'}')` ); }, @@ -460,7 +470,7 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) { const isEnabled = await testSubjects.isEnabled('transformWizardStartButton'); expect(isEnabled).to.eql( expectedValue, - `Expected 'Start' button to be '${expectedValue ? 'enabled' : 'disabled'}' (got ${ + `Expected 'Start' button to be '${expectedValue ? 'enabled' : 'disabled'}' (got '${ isEnabled ? 'enabled' : 'disabled' }')` ); From 81a69480a9ddce827942e2da89d1a1e00704971d Mon Sep 17 00:00:00 2001 From: Corey Robertson Date: Thu, 28 May 2020 09:29:10 -0400 Subject: [PATCH 08/22] [Canvas] Reduce Bundle Size (#66099) * Move some code around to reduce bundle size * prettier Co-authored-by: Elastic Machine --- x-pack/plugins/canvas/public/application.tsx | 22 +++++++--- .../canvas/public/lib/run_interpreter.ts | 42 ++----------------- x-pack/plugins/canvas/public/plugin.tsx | 9 ---- .../canvas/public/services/expressions.ts | 19 +++++++++ .../plugins/canvas/public/services/index.ts | 16 ++++--- 5 files changed, 49 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/canvas/public/services/expressions.ts diff --git a/x-pack/plugins/canvas/public/application.tsx b/x-pack/plugins/canvas/public/application.tsx index 426b34cf73b9a..8751d8102ad37 100644 --- a/x-pack/plugins/canvas/public/application.tsx +++ b/x-pack/plugins/canvas/public/application.tsx @@ -18,7 +18,6 @@ import { CanvasStartDeps, CanvasSetupDeps } from './plugin'; // @ts-ignore Untyped local import { App } from './components/app'; import { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; -import { initInterpreter } from './lib/run_interpreter'; import { registerLanguage } from './lib/monaco_language_def'; import { SetupRegistries } from './plugin_api'; import { initRegistries, populateRegistries, destroyRegistries } from './registries'; @@ -37,6 +36,7 @@ import { startServices, services } from './services'; import { destroyHistory } from './lib/history_provider'; // @ts-ignore Untyped local import { stopRouter } from './lib/router_provider'; +import { initFunctions } from './functions'; // @ts-ignore Untyped local import { appUnload } from './state/actions/app'; @@ -82,15 +82,25 @@ export const initializeCanvas = async ( registries: SetupRegistries, appUpdater: BehaviorSubject ) => { - startServices(coreSetup, coreStart, setupPlugins, startPlugins, appUpdater); + await startServices(coreSetup, coreStart, setupPlugins, startPlugins, appUpdater); + + // Adding these functions here instead of in plugin.ts. + // Some of these functions have deep dependencies into Canvas, which was bulking up the size + // of our bundle entry point. Moving them here pushes that load to when canvas is actually loaded. + const canvasFunctions = initFunctions({ + timefilter: setupPlugins.data.query.timefilter.timefilter, + prependBasePath: coreSetup.http.basePath.prepend, + typesRegistry: setupPlugins.expressions.__LEGACY.types, + }); + + for (const fn of canvasFunctions) { + services.expressions.getService().registerFunction(fn); + } // Create Store const canvasStore = await createStore(coreSetup, setupPlugins); - // Init Interpreter - initInterpreter(startPlugins.expressions, setupPlugins.expressions).then(() => { - registerLanguage(Object.values(startPlugins.expressions.getFunctions())); - }); + registerLanguage(Object.values(services.expressions.getService().getFunctions())); // Init Registries initRegistries(); diff --git a/x-pack/plugins/canvas/public/lib/run_interpreter.ts b/x-pack/plugins/canvas/public/lib/run_interpreter.ts index bd00cad4fcbe7..07c0ca4b1ce15 100644 --- a/x-pack/plugins/canvas/public/lib/run_interpreter.ts +++ b/x-pack/plugins/canvas/public/lib/run_interpreter.ts @@ -6,32 +6,7 @@ import { fromExpression, getType } from '@kbn/interpreter/common'; import { ExpressionValue, ExpressionAstExpression } from 'src/plugins/expressions/public'; -import { notifyService } from '../services'; - -import { CanvasStartDeps, CanvasSetupDeps } from '../plugin'; - -let expressionsStarting: Promise | undefined; - -export const initInterpreter = function ( - expressionsStart: CanvasStartDeps['expressions'], - expressionsSetup: CanvasSetupDeps['expressions'] -) { - expressionsStarting = startExpressions(expressionsStart, expressionsSetup); - - return expressionsStarting; -}; - -async function startExpressions( - expressionsStart: CanvasStartDeps['expressions'], - expressionsSetup: CanvasSetupDeps['expressions'] -) { - await expressionsSetup.__LEGACY.loadLegacyServerFunctionWrappers(); - return expressionsStart; -} - -export const resetInterpreter = function () { - expressionsStarting = undefined; -}; +import { notifyService, expressionsService } from '../services'; interface Options { castToRender?: boolean; @@ -41,12 +16,7 @@ interface Options { * Meant to be a replacement for plugins/interpreter/interpretAST */ export async function interpretAst(ast: ExpressionAstExpression): Promise { - if (!expressionsStarting) { - throw new Error('Interpreter has not been initialized'); - } - - const expressions = await expressionsStarting; - return await expressions.execute(ast).getData(); + return await expressionsService.getService().execute(ast).getData(); } /** @@ -63,14 +33,8 @@ export async function runInterpreter( input: ExpressionValue, options: Options = {} ): Promise { - if (!expressionsStarting) { - throw new Error('Interpreter has not been initialized'); - } - - const expressions = await expressionsStarting; - try { - const renderable = await expressions.execute(ast, input).getData(); + const renderable = await expressionsService.getService().execute(ast, input).getData(); if (getType(renderable) === 'render') { return renderable; diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 1265bfbb69b70..9d2a6b3fdf4f4 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -28,7 +28,6 @@ import { Start as InspectorStart } from '../../../../src/plugins/inspector/publi import { argTypeSpecs } from './expression_types/arg_types'; import { transitions } from './transitions'; import { getPluginApi, CanvasApi } from './plugin_api'; -import { initFunctions } from './functions'; import { CanvasSrcPlugin } from '../canvas_plugin_src/plugin'; export { CoreStart, CoreSetup }; @@ -117,14 +116,6 @@ export class CanvasPlugin plugins.home.featureCatalogue.register(featureCatalogueEntry); - // Register core canvas stuff - canvasApi.addFunctions( - initFunctions({ - timefilter: plugins.data.query.timefilter.timefilter, - prependBasePath: core.http.basePath.prepend, - typesRegistry: plugins.expressions.__LEGACY.types, - }) - ); canvasApi.addArgumentUIs(argTypeSpecs); canvasApi.addTransitions(transitions); diff --git a/x-pack/plugins/canvas/public/services/expressions.ts b/x-pack/plugins/canvas/public/services/expressions.ts new file mode 100644 index 0000000000000..16f939a9c97fc --- /dev/null +++ b/x-pack/plugins/canvas/public/services/expressions.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { CanvasServiceFactory } from '.'; +import { ExpressionsService } from '../../../../../src/plugins/expressions/common'; + +export const expressionsServiceFactory: CanvasServiceFactory = async ( + coreSetup, + coreStart, + setupPlugins, + startPlugins +) => { + await setupPlugins.expressions.__LEGACY.loadLegacyServerFunctionWrappers(); + + return setupPlugins.expressions.fork(); +}; diff --git a/x-pack/plugins/canvas/public/services/index.ts b/x-pack/plugins/canvas/public/services/index.ts index 42176f953c331..a929b4639d3e4 100644 --- a/x-pack/plugins/canvas/public/services/index.ts +++ b/x-pack/plugins/canvas/public/services/index.ts @@ -10,6 +10,7 @@ import { CanvasSetupDeps, CanvasStartDeps } from '../plugin'; import { notifyServiceFactory } from './notify'; import { platformServiceFactory } from './platform'; import { navLinkServiceFactory } from './nav_link'; +import { expressionsServiceFactory } from './expressions'; export type CanvasServiceFactory = ( coreSetup: CoreSetup, @@ -17,7 +18,7 @@ export type CanvasServiceFactory = ( canvasSetupPlugins: CanvasSetupDeps, canvasStartPlugins: CanvasStartDeps, appUpdater: BehaviorSubject -) => Service; +) => Service | Promise; class CanvasServiceProvider { private factory: CanvasServiceFactory; @@ -27,14 +28,14 @@ class CanvasServiceProvider { this.factory = factory; } - start( + async start( coreSetup: CoreSetup, coreStart: CoreStart, canvasSetupPlugins: CanvasSetupDeps, canvasStartPlugins: CanvasStartDeps, appUpdater: BehaviorSubject ) { - this.service = this.factory( + this.service = await this.factory( coreSetup, coreStart, canvasSetupPlugins, @@ -59,27 +60,31 @@ class CanvasServiceProvider { export type ServiceFromProvider

= P extends CanvasServiceProvider ? T : never; export const services = { + expressions: new CanvasServiceProvider(expressionsServiceFactory), notify: new CanvasServiceProvider(notifyServiceFactory), platform: new CanvasServiceProvider(platformServiceFactory), navLink: new CanvasServiceProvider(navLinkServiceFactory), }; export interface CanvasServices { + expressions: ServiceFromProvider; notify: ServiceFromProvider; platform: ServiceFromProvider; navLink: ServiceFromProvider; } -export const startServices = ( +export const startServices = async ( coreSetup: CoreSetup, coreStart: CoreStart, canvasSetupPlugins: CanvasSetupDeps, canvasStartPlugins: CanvasStartDeps, appUpdater: BehaviorSubject ) => { - Object.entries(services).forEach(([key, provider]) => + const startPromises = Object.values(services).map((provider) => provider.start(coreSetup, coreStart, canvasSetupPlugins, canvasStartPlugins, appUpdater) ); + + await Promise.all(startPromises); }; export const stopServices = () => { @@ -90,4 +95,5 @@ export const { notify: notifyService, platform: platformService, navLink: navLinkService, + expressions: expressionsService, } = services; From 17573f1a0b6b5ecc9c0d3ed3c528ca43df1860db Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Thu, 28 May 2020 08:48:49 -0600 Subject: [PATCH 09/22] Add unit tests for filters agg. (#67229) --- .../search/aggs/buckets/filters.test.ts | 253 ++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 src/plugins/data/public/search/aggs/buckets/filters.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filters.test.ts b/src/plugins/data/public/search/aggs/buckets/filters.test.ts new file mode 100644 index 0000000000000..295e740a2a780 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/filters.test.ts @@ -0,0 +1,253 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Query } from '../../../../common'; +import { coreMock, notificationServiceMock } from '../../../../../../../src/core/public/mocks'; +import { AggConfigs } from '../agg_configs'; +import { mockAggTypesRegistry } from '../test_helpers'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { getFiltersBucketAgg, FiltersBucketAggDependencies } from './filters'; +import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; +import { InternalStartServices } from '../../../types'; + +describe('Filters Agg', () => { + let aggTypesDependencies: FiltersBucketAggDependencies; + + beforeEach(() => { + jest.resetAllMocks(); + const { uiSettings } = coreMock.createSetup(); + + aggTypesDependencies = { + uiSettings, + getInternalStartServices: () => + (({ + fieldFormats: fieldFormatsServiceMock.createStartContract(), + notifications: notificationServiceMock.createStartContract(), + } as unknown) as InternalStartServices), + }; + }); + + describe('order agg editor UI', () => { + const getAggConfigs = (params: Record = {}) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + find: () => field, + }, + } as any; + + const field = { + name: 'field', + indexPattern, + }; + + return new AggConfigs( + indexPattern, + [ + { + id: 'test', + params, + type: BUCKET_TYPES.FILTERS, + }, + ], + { + typesRegistry: mockAggTypesRegistry([getFiltersBucketAgg(aggTypesDependencies)]), + fieldFormats: aggTypesDependencies.getInternalStartServices().fieldFormats, + } + ); + }; + + const generateFilter = (label: string, language: string, query: Query['query']) => ({ + label, + input: { + language, + query, + }, + }); + + describe('using Lucene', () => { + test('works with lucene filters', () => { + const aggConfigs = getAggConfigs({ + filters: [ + generateFilter('a', 'lucene', 'foo'), + generateFilter('b', 'lucene', 'status:200'), + generateFilter('c', 'lucene', 'status:[400 TO 499] AND (foo OR bar)'), + ], + }); + + const { [BUCKET_TYPES.FILTERS]: params } = aggConfigs.aggs[0].toDsl(); + expect(Object.values(params.filters).map((v: any) => v.bool.must)).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "query_string": Object { + "query": "foo", + }, + }, + ], + Array [ + Object { + "query_string": Object { + "query": "status:200", + }, + }, + ], + Array [ + Object { + "query_string": Object { + "query": "status:[400 TO 499] AND (foo OR bar)", + }, + }, + ], + ] + `); + }); + }); + + describe('using KQL', () => { + test('works with KQL filters', () => { + const aggConfigs = getAggConfigs({ + filters: [ + generateFilter('a', 'kuery', 'status:200'), + generateFilter('b', 'kuery', 'status > 500 and name:hello'), + ], + }); + + const { [BUCKET_TYPES.FILTERS]: params } = aggConfigs.aggs[0].toDsl(); + expect(Object.values(params.filters).map((v: any) => v.bool.filter)).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "field": 200, + }, + }, + ], + }, + }, + ], + Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "range": Object { + "field": Object { + "gt": 500, + }, + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "field": "hello", + }, + }, + ], + }, + }, + ], + }, + }, + ], + ] + `); + }); + + test('works with KQL wildcards', () => { + const aggConfigs = getAggConfigs({ + filters: [generateFilter('a', 'kuery', '*'), generateFilter('b', 'kuery', 'foo*')], + }); + + const { [BUCKET_TYPES.FILTERS]: params } = aggConfigs.aggs[0].toDsl(); + expect(Object.values(params.filters).map((v: any) => v.bool.filter)).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "query_string": Object { + "query": "*", + }, + }, + ], + Array [ + Object { + "query_string": Object { + "query": "foo*", + }, + }, + ], + ] + `); + }); + + test('throws with leading wildcards if not allowed', () => { + const aggConfigs = getAggConfigs({ + filters: [generateFilter('a', 'kuery', '*foo*')], + }); + + expect(() => { + aggConfigs.aggs[0].toDsl(); + }).toThrowErrorMatchingInlineSnapshot(` +"Leading wildcards are disabled. See query:allowLeadingWildcards in Advanced Settings. +*foo* +^" +`); + }); + + test('works with leading wildcards if allowed', () => { + aggTypesDependencies.uiSettings.get = (s: any) => + s === 'query:allowLeadingWildcards' ? true : s; + + const aggConfigs = getAggConfigs({ + filters: [generateFilter('a', 'kuery', '*foo*')], + }); + + const { [BUCKET_TYPES.FILTERS]: params } = aggConfigs.aggs[0].toDsl(); + expect(Object.values(params.filters).map((v: any) => v.bool.filter)).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "query_string": Object { + "query": "*foo*", + }, + }, + ], + ] + `); + }); + }); + }); +}); From 57345e092e72a76d3180cdb85658956da944bb9d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 28 May 2020 08:54:44 -0600 Subject: [PATCH 10/22] [Maps] convert HeatmapLayer dependencies to TS (#66823) * [Maps] convert HeatmapLayer and dependencies to TS * heatmap_style_editor snapshots * eslint * fix merge problems * eslint cleanup * revert rename of getOrdinalMbColorRampStops * eslint * tslint Co-authored-by: Elastic Machine --- .../clusters_layer_wizard.tsx | 1 - .../point_2_point_layer_wizard.tsx | 1 - ...olor_utils.test.js => color_utils.test.ts} | 0 .../{color_utils.js => color_utils.tsx} | 92 +++++++++++-------- .../{color_gradient.js => color_gradient.tsx} | 13 ++- ...nap => heatmap_style_editor.test.tsx.snap} | 0 ...tmap_constants.js => heatmap_constants.ts} | 0 ....test.js => heatmap_style_editor.test.tsx} | 0 ...yle_editor.js => heatmap_style_editor.tsx} | 9 +- .../classes/styles/heatmap/heatmap_style.js | 1 + .../extract_color_from_style_property.ts | 5 +- .../vector/vector_style_defaults.test.ts | 35 +++++++ .../styles/vector/vector_style_defaults.ts | 11 ++- 13 files changed, 117 insertions(+), 51 deletions(-) rename x-pack/plugins/maps/public/classes/styles/{color_utils.test.js => color_utils.test.ts} (100%) rename x-pack/plugins/maps/public/classes/styles/{color_utils.js => color_utils.tsx} (53%) rename x-pack/plugins/maps/public/classes/styles/components/{color_gradient.js => color_gradient.tsx} (72%) rename x-pack/plugins/maps/public/classes/styles/heatmap/components/__snapshots__/{heatmap_style_editor.test.js.snap => heatmap_style_editor.test.tsx.snap} (100%) rename x-pack/plugins/maps/public/classes/styles/heatmap/components/{heatmap_constants.js => heatmap_constants.ts} (100%) rename x-pack/plugins/maps/public/classes/styles/heatmap/components/{heatmap_style_editor.test.js => heatmap_style_editor.test.tsx} (100%) rename x-pack/plugins/maps/public/classes/styles/heatmap/components/{heatmap_style_editor.js => heatmap_style_editor.tsx} (85%) create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.test.ts diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx index 4e75ae8823385..84bdee2a64bd8 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx @@ -27,7 +27,6 @@ import { VECTOR_STYLES, STYLE_TYPE, } from '../../../../common/constants'; -// @ts-ignore import { COLOR_GRADIENTS } from '../../styles/color_utils'; export const clustersLayerWizardConfig: LayerWizard = { diff --git a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx index bda1a6650c48a..8d7bf0d2af661 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx @@ -17,7 +17,6 @@ import { VECTOR_STYLES, STYLE_TYPE, } from '../../../../common/constants'; -// @ts-ignore import { COLOR_GRADIENTS } from '../../styles/color_utils'; // @ts-ignore import { CreateSourceEditor } from './create_source_editor'; diff --git a/x-pack/plugins/maps/public/classes/styles/color_utils.test.js b/x-pack/plugins/maps/public/classes/styles/color_utils.test.ts similarity index 100% rename from x-pack/plugins/maps/public/classes/styles/color_utils.test.js rename to x-pack/plugins/maps/public/classes/styles/color_utils.test.ts diff --git a/x-pack/plugins/maps/public/classes/styles/color_utils.js b/x-pack/plugins/maps/public/classes/styles/color_utils.tsx similarity index 53% rename from x-pack/plugins/maps/public/classes/styles/color_utils.js rename to x-pack/plugins/maps/public/classes/styles/color_utils.tsx index 9dc79c006dffe..116e03096b0f5 100644 --- a/x-pack/plugins/maps/public/classes/styles/color_utils.js +++ b/x-pack/plugins/maps/public/classes/styles/color_utils.tsx @@ -7,73 +7,85 @@ import React from 'react'; import tinycolor from 'tinycolor2'; import chroma from 'chroma-js'; +// @ts-ignore import { euiPaletteColorBlind } from '@elastic/eui/lib/services'; import { ColorGradient } from './components/color_gradient'; -import { vislibColorMaps } from '../../../../../../src/plugins/charts/public'; +import { RawColorSchema, vislibColorMaps } from '../../../../../../src/plugins/charts/public'; export const GRADIENT_INTERVALS = 8; -export const DEFAULT_FILL_COLORS = euiPaletteColorBlind(); -export const DEFAULT_LINE_COLORS = [ - ...DEFAULT_FILL_COLORS.map((color) => tinycolor(color).darken().toHexString()), +export const DEFAULT_FILL_COLORS: string[] = euiPaletteColorBlind(); +export const DEFAULT_LINE_COLORS: string[] = [ + ...DEFAULT_FILL_COLORS.map((color: string) => tinycolor(color).darken().toHexString()), // Explicitly add black & white as border color options '#000', '#FFF', ]; -function getLegendColors(colorRamp, numLegendColors = 4) { +function getRGBColors(colorRamp: Array<[number, number[]]>, numLegendColors: number = 4): string[] { const colors = []; - colors[0] = getColor(colorRamp, 0); + colors[0] = getRGBColor(colorRamp, 0); for (let i = 1; i < numLegendColors - 1; i++) { - colors[i] = getColor(colorRamp, Math.floor((colorRamp.length * i) / numLegendColors)); + colors[i] = getRGBColor(colorRamp, Math.floor((colorRamp.length * i) / numLegendColors)); } - colors[numLegendColors - 1] = getColor(colorRamp, colorRamp.length - 1); + colors[numLegendColors - 1] = getRGBColor(colorRamp, colorRamp.length - 1); return colors; } -function getColor(colorRamp, i) { - const color = colorRamp[i][1]; - const red = Math.floor(color[0] * 255); - const green = Math.floor(color[1] * 255); - const blue = Math.floor(color[2] * 255); +function getRGBColor(colorRamp: Array<[number, number[]]>, i: number): string { + const rgbArray = colorRamp[i][1]; + const red = Math.floor(rgbArray[0] * 255); + const green = Math.floor(rgbArray[1] * 255); + const blue = Math.floor(rgbArray[2] * 255); return `rgb(${red},${green},${blue})`; } -function getColorRamp(colorRampName) { - const colorRamp = vislibColorMaps[colorRampName]; - if (!colorRamp) { +function getColorSchema(colorRampName: string): RawColorSchema { + const colorSchema = vislibColorMaps[colorRampName]; + if (!colorSchema) { throw new Error( `${colorRampName} not found. Expected one of following values: ${Object.keys( vislibColorMaps )}` ); } - return colorRamp; + return colorSchema; } -export function getRGBColorRangeStrings(colorRampName, numberColors = GRADIENT_INTERVALS) { - const colorRamp = getColorRamp(colorRampName); - return getLegendColors(colorRamp.value, numberColors); +export function getRGBColorRangeStrings( + colorRampName: string, + numberColors: number = GRADIENT_INTERVALS +): string[] { + const colorSchema = getColorSchema(colorRampName); + return getRGBColors(colorSchema.value, numberColors); } -export function getHexColorRangeStrings(colorRampName, numberColors = GRADIENT_INTERVALS) { +export function getHexColorRangeStrings( + colorRampName: string, + numberColors: number = GRADIENT_INTERVALS +): string[] { return getRGBColorRangeStrings(colorRampName, numberColors).map((rgbColor) => chroma(rgbColor).hex() ); } -export function getColorRampCenterColor(colorRampName) { +export function getColorRampCenterColor(colorRampName: string): string | null { if (!colorRampName) { return null; } - const colorRamp = getColorRamp(colorRampName); - const centerIndex = Math.floor(colorRamp.value.length / 2); - return getColor(colorRamp.value, centerIndex); + const colorSchema = getColorSchema(colorRampName); + const centerIndex = Math.floor(colorSchema.value.length / 2); + return getRGBColor(colorSchema.value, centerIndex); } // Returns an array of color stops // [ stop_input_1: number, stop_output_1: color, stop_input_n: number, stop_output_n: color ] -export function getOrdinalMbColorRampStops(colorRampName, min, max, numberColors) { +export function getOrdinalMbColorRampStops( + colorRampName: string, + min: number, + max: number, + numberColors: number +): Array | null { if (!colorRampName) { return null; } @@ -84,15 +96,18 @@ export function getOrdinalMbColorRampStops(colorRampName, min, max, numberColors const hexColors = getHexColorRangeStrings(colorRampName, numberColors); if (max === min) { - //just return single stop value + // just return single stop value return [max, hexColors[hexColors.length - 1]]; } const delta = max - min; - return hexColors.reduce((accu, stopColor, idx, srcArr) => { - const stopNumber = min + (delta * idx) / srcArr.length; - return [...accu, stopNumber, stopColor]; - }, []); + return hexColors.reduce( + (accu: Array, stopColor: string, idx: number, srcArr: string[]) => { + const stopNumber = min + (delta * idx) / srcArr.length; + return [...accu, stopNumber, stopColor]; + }, + [] + ); } export const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map((colorRampName) => ({ @@ -102,7 +117,7 @@ export const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map((colorRampName) export const COLOR_RAMP_NAMES = Object.keys(vislibColorMaps); -export function getLinearGradient(colorStrings) { +export function getLinearGradient(colorStrings: string[]): string { const intervals = colorStrings.length; let linearGradient = `linear-gradient(to right, ${colorStrings[0]} 0%,`; for (let i = 1; i < intervals - 1; i++) { @@ -112,7 +127,12 @@ export function getLinearGradient(colorStrings) { return `${linearGradient} ${colorStrings[colorStrings.length - 1]} 100%)`; } -const COLOR_PALETTES_CONFIGS = [ +export interface ColorPalette { + id: string; + colors: string[]; +} + +const COLOR_PALETTES_CONFIGS: ColorPalette[] = [ { id: 'palette_0', colors: euiPaletteColorBlind(), @@ -127,14 +147,14 @@ const COLOR_PALETTES_CONFIGS = [ }, ]; -export function getColorPalette(paletteId) { - const palette = COLOR_PALETTES_CONFIGS.find((palette) => palette.id === paletteId); +export function getColorPalette(paletteId: string): string[] | null { + const palette = COLOR_PALETTES_CONFIGS.find(({ id }: ColorPalette) => id === paletteId); return palette ? palette.colors : null; } export const COLOR_PALETTES = COLOR_PALETTES_CONFIGS.map((palette) => { const paletteDisplay = palette.colors.map((color) => { - const style = { + const style: React.CSSProperties = { backgroundColor: color, width: `${100 / palette.colors.length}%`, position: 'relative', diff --git a/x-pack/plugins/maps/public/classes/styles/components/color_gradient.js b/x-pack/plugins/maps/public/classes/styles/components/color_gradient.tsx similarity index 72% rename from x-pack/plugins/maps/public/classes/styles/components/color_gradient.js rename to x-pack/plugins/maps/public/classes/styles/components/color_gradient.tsx index bf7e88df3a694..b29146062e46d 100644 --- a/x-pack/plugins/maps/public/classes/styles/components/color_gradient.js +++ b/x-pack/plugins/maps/public/classes/styles/components/color_gradient.tsx @@ -11,17 +11,20 @@ import { getRGBColorRangeStrings, getLinearGradient, } from '../color_utils'; -import classNames from 'classnames'; -export const ColorGradient = ({ colorRamp, colorRampName, className }) => { +interface Props { + colorRamp?: string[]; + colorRampName?: string; +} + +export const ColorGradient = ({ colorRamp, colorRampName }: Props) => { if (!colorRamp && (!colorRampName || !COLOR_RAMP_NAMES.includes(colorRampName))) { return null; } - const classes = classNames('mapColorGradient', className); const rgbColorStrings = colorRampName ? getRGBColorRangeStrings(colorRampName, GRADIENT_INTERVALS) - : colorRamp; + : colorRamp!; const background = getLinearGradient(rgbColorStrings); - return

; + return
; }; diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/components/__snapshots__/heatmap_style_editor.test.js.snap b/x-pack/plugins/maps/public/classes/styles/heatmap/components/__snapshots__/heatmap_style_editor.test.tsx.snap similarity index 100% rename from x-pack/plugins/maps/public/classes/styles/heatmap/components/__snapshots__/heatmap_style_editor.test.js.snap rename to x-pack/plugins/maps/public/classes/styles/heatmap/components/__snapshots__/heatmap_style_editor.test.tsx.snap diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_constants.js b/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_constants.ts similarity index 100% rename from x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_constants.js rename to x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_constants.ts diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.test.js b/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.test.tsx similarity index 100% rename from x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.test.js rename to x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.test.tsx diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.js b/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.tsx similarity index 85% rename from x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.js rename to x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.tsx index 6d38a7985269e..d15fdbd79de75 100644 --- a/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.js +++ b/x-pack/plugins/maps/public/classes/styles/heatmap/components/heatmap_style_editor.tsx @@ -15,8 +15,13 @@ import { HEATMAP_COLOR_RAMP_LABEL, } from './heatmap_constants'; -export function HeatmapStyleEditor({ colorRampName, onHeatmapColorChange }) { - const onColorRampChange = (selectedColorRampName) => { +interface Props { + colorRampName: string; + onHeatmapColorChange: ({ colorRampName }: { colorRampName: string }) => void; +} + +export function HeatmapStyleEditor({ colorRampName, onHeatmapColorChange }: Props) { + const onColorRampChange = (selectedColorRampName: string) => { onHeatmapColorChange({ colorRampName: selectedColorRampName, }); diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.js b/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.js index 3b5bcf591c2a6..5f920d0ba52d3 100644 --- a/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.js +++ b/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.js @@ -91,6 +91,7 @@ export class HeatmapStyle extends AbstractStyle { MAX_RANGE, GRADIENT_INTERVALS ); + // TODO handle null mbMap.setPaintProperty(layerId, 'heatmap-color', [ 'interpolate', ['linear'], diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/extract_color_from_style_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/extract_color_from_style_property.ts index 71f77bc313191..dadb3f201fa33 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/extract_color_from_style_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/extract_color_from_style_property.ts @@ -43,7 +43,7 @@ export function extractColorFromStyleProperty( } const palette = getColorPalette(dynamicOptions.colorCategory); - return palette[0]; + return palette ? palette[0] : defaultColor; } else { // return middle of gradient for dynamic style property if (dynamicOptions.useCustomColorRamp) { @@ -58,6 +58,7 @@ export function extractColorFromStyleProperty( if (!dynamicOptions.color) { return defaultColor; } - return getColorRampCenterColor(dynamicOptions.color); + const centerColor = getColorRampCenterColor(dynamicOptions.color); + return centerColor ? centerColor : defaultColor; } } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.test.ts b/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.test.ts new file mode 100644 index 0000000000000..bc032639dd07d --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +jest.mock('../../../kibana_services', () => { + const mockUiSettings = { + get: () => { + return undefined; + }, + }; + return { + getUiSettings: () => { + return mockUiSettings; + }, + }; +}); + +import { VECTOR_STYLES } from '../../../../common/constants'; +import { getDefaultStaticProperties } from './vector_style_defaults'; + +describe('getDefaultStaticProperties', () => { + test('Should use first color in DEFAULT_*_COLORS when no colors are used on the map', () => { + const styleProperties = getDefaultStaticProperties([]); + expect(styleProperties[VECTOR_STYLES.FILL_COLOR]!.options.color).toBe('#54B399'); + expect(styleProperties[VECTOR_STYLES.LINE_COLOR]!.options.color).toBe('#41937c'); + }); + + test('Should next color in DEFAULT_*_COLORS when colors are used on the map', () => { + const styleProperties = getDefaultStaticProperties(['#54B399']); + expect(styleProperties[VECTOR_STYLES.FILL_COLOR]!.options.color).toBe('#6092C0'); + expect(styleProperties[VECTOR_STYLES.LINE_COLOR]!.options.color).toBe('#4379aa'); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.ts b/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.ts index 86602381cf615..a6878a0d760c7 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style_defaults.ts @@ -16,7 +16,6 @@ import { COLOR_PALETTES, DEFAULT_FILL_COLORS, DEFAULT_LINE_COLORS, - // @ts-ignore } from '../color_utils'; import { VectorStylePropertiesDescriptor } from '../../../../common/descriptor_types'; // @ts-ignore @@ -58,9 +57,13 @@ export function getDefaultProperties(mapColors: string[] = []): VectorStylePrope export function getDefaultStaticProperties( mapColors: string[] = [] ): VectorStylePropertiesDescriptor { - // Colors must be state-aware to reduce unnecessary incrementation - const lastColor = mapColors.pop(); - const nextColorIndex = (DEFAULT_FILL_COLORS.indexOf(lastColor) + 1) % DEFAULT_FILL_COLORS.length; + let nextColorIndex = 0; + if (mapColors.length) { + const lastColor = mapColors[mapColors.length - 1]; + if (DEFAULT_FILL_COLORS.includes(lastColor)) { + nextColorIndex = (DEFAULT_FILL_COLORS.indexOf(lastColor) + 1) % DEFAULT_FILL_COLORS.length; + } + } const nextFillColor = DEFAULT_FILL_COLORS[nextColorIndex]; const nextLineColor = DEFAULT_LINE_COLORS[nextColorIndex]; From 0302a45664590f89ae87d16ead0b15e23f9099dd Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Thu, 28 May 2020 08:55:49 -0700 Subject: [PATCH 11/22] Updates Management doc to reflect new navigation (#67506) * [DOCS] Updates Management page to reflect new navigation * [DOCS] Adds link to security doc * [DOCS] Incorporates review comments --- docs/user/management.asciidoc | 176 +++++++++++------- .../security/authorization/index.asciidoc | 8 +- 2 files changed, 116 insertions(+), 68 deletions(-) diff --git a/docs/user/management.asciidoc b/docs/user/management.asciidoc index bcaede01b7a86..1704a80847652 100644 --- a/docs/user/management.asciidoc +++ b/docs/user/management.asciidoc @@ -1,123 +1,171 @@ [[management]] -= Management += Stack Management [partintro] -- -*Management* is home to UIs for managing all things Elastic Stack— +*Stack Management* is home to UIs for managing all things Elastic Stack— indices, clusters, licenses, UI settings, index patterns, spaces, and more. [float] -[[manage-Elasticsearch]] -== Manage {es} +[[manage-ingest]] +== Ingest [cols="50, 50"] |=== -a| <> - -Replicate indices on a remote cluster and copy them to a follower index on a local cluster. -This is important for -disaster recovery. It also keeps data local for faster queries. - -| <> - -Create a policy for defining the lifecycle of an index as it ages -through the hot, warm, cold, and delete phases. -Such policies help you control operation costs -because you can put data in different resource tiers. +| <> +| Create and manage {es} +pipelines that enable you to perform common transformations and +enrichments on your data. -a| <> +| {logstash-ref}/logstash-centralized-pipeline-management.html[Logstash Pipelines] +| Create, edit, and delete your Logstash pipeline configurations. -View index settings, mappings, and statistics and perform operations, such as refreshing, -flushing, and clearing the cache. Practicing good index management ensures -that your data is stored cost effectively. +| <> +| Manage your Beats configurations in a central location and +quickly deploy configuration changes to all Beats running across your enterprise. -a| <> -Create and manage {es} -pipelines that enable you to perform common transformations and -enrichments on your data. +|=== -| <> +[float] +[[manage-data]] +== Data -View the status of your license, start a trial, or install a new license. For -the full list of features that are included in your license, -see the https://www.elastic.co/subscriptions[subscription page]. +[cols="50, 50"] +|=== -| <> +a| <> +| View index settings, mappings, and statistics and perform operations, such as refreshing, +flushing, and clearing the cache. Practicing good index management ensures +that your data is stored cost effectively. -Manage your remote clusters for use with cross-cluster search and cross-cluster replication. -You can add and remove remote clusters, and check their connectivity. +| <> +|Create a policy for defining the lifecycle of an index as it ages +through the hot, warm, cold, and delete phases. +Such policies help you control operation costs +because you can put data in different resource tiers. -| <> +| <> +|Define a policy that creates, schedules, and automatically deletes snapshots to ensure that you +have backups of your cluster in case something goes wrong. -Create a job that periodically aggregates data from one or more indices, and then +| <> +|Create a job that periodically aggregates data from one or more indices, and then rolls it into a new, compact index. Rollup indices are a good way to store months or years of historical data in combination with your raw data. -| <> +| {ref}/transforms.html[Transforms] +|Use transforms to pivot existing {es} indices into summarized or entity-centric indices. -Define a policy that creates, schedules, and automatically deletes snapshots to ensure that you -have backups of your cluster in case something goes wrong. +| <> +|Replicate indices on a remote cluster and copy them to a follower index on a local cluster. +This is important for +disaster recovery. It also keeps data local for faster queries. -| {ref}/transforms.html[*Transforms*] +| <> +|Manage your remote clusters for use with cross-cluster search and cross-cluster replication. +You can add and remove remote clusters, and check their connectivity. +|=== -Use transforms to pivot existing {es} indices into summarized or entity-centric indices. +[float] +[[manage-alerts-insights]] +== Alerts and Insights -| <> +[cols="50, 50"] +|=== -Identify the issues that you need to address before upgrading to the -next major version of {es}, and then reindex, if needed. +| <> +| Centrally manage your alerts across {kib}. Create and manage reusable +connectors for triggering actions. -| <> +| <> +| Monitor the generation of reports—PDF, PNG, and CSV—and download reports that you previously generated. +A report can contain a dashboard, visualization, saved search, or Canvas workpad. + +| {ml-docs}/ml-jobs.html[Machine Learning Jobs] +| View your {anomaly-jobs} and {dfanalytics-jobs}. Open the Single Metric +Viewer or Anomaly Explorer to see your {ml} results. -Detect changes in your data by creating, managing, and monitoring alerts. -For example, create an alert when the maximum total CPU usage on a machine goes +| <> +| Detect changes in your data by creating, managing, and monitoring alerts. +For example, you might create an alert when the maximum total CPU usage on a machine goes above a certain percentage. |=== [float] -[[manage-kibana]] -== Manage {kib} +[[manage-security]] +== Security [cols="50, 50"] |=== -a| <> - -Customize {kib} to suit your needs. Change the format for displaying dates, turn on dark mode, -set the timespan for notification messages, and much more. +a| <> +|View the users that have been defined on your cluster. +Add or delete users and assign roles that give users +specific privileges. -| <> +| <> +|View the roles that exist on your cluster. Customize +the actions that a user with the role can perform, on a cluster, index, and space level. -Centrally manage your alerts across {kib}. Create and manage reusable -connectors for triggering actions. +| <> +| Create secondary credentials so that you can send requests on behalf of the user. +Secondary credentials have the same or lower access rights. -| <> +| <> +| Assign roles to your users using a set of rules. Role mappings are required +when authenticating via an external identity provider, such as Active Directory, +Kerberos, PKI, OIDC, and SAML. -Create and manage the index patterns that help you retrieve your data from {es}. +|=== -| <> +[float] +[[manage-kibana]] +== {kib} -Monitor the generation of reports—PDF, PNG, and CSV—and download reports that you previously generated. -A report can contain a dashboard, visualization, saved search, or Canvas workpad. +[cols="50, 50"] +|=== -| <> +a| <> +|Create and manage the index patterns that retrieve your data from {es}. -Copy, edit, delete, import, and export your saved objects. +| <> +| Copy, edit, delete, import, and export your saved objects. These include dashboards, visualizations, maps, index patterns, Canvas workpads, and more. -| <> - -Create spaces to organize your dashboards and other saved objects into categories. +| <> +| Create spaces to organize your dashboards and other saved objects into categories. A space is isolated from all other spaces, so you can tailor it to your needs without impacting others. -|   +a| <> +| Customize {kib} to suit your needs. Change the format for displaying dates, turn on dark mode, +set the timespan for notification messages, and much more. + +|=== + +[float] +[[manage-stack]] +== Stack + +[cols="50, 50"] +|=== + +| <> +| View the status of your license, start a trial, or install a new license. For +the full list of features that are included in your license, +see the https://www.elastic.co/subscriptions[subscription page]. + +| <> +| Identify the issues that you need to address before upgrading to the +next major version of {es}, and then reindex, if needed. |=== + + -- include::{kib-repo-dir}/management/advanced-options.asciidoc[] diff --git a/docs/user/security/authorization/index.asciidoc b/docs/user/security/authorization/index.asciidoc index 853c735418cea..4b91812660c78 100644 --- a/docs/user/security/authorization/index.asciidoc +++ b/docs/user/security/authorization/index.asciidoc @@ -2,16 +2,17 @@ [[xpack-security-authorization]] === Granting access to {kib} -The Elastic Stack comes with the `kibana_admin` {ref}/built-in-roles.html[built-in role], which you can use to grant access to all Kibana features in all spaces. To grant users access to a subset of spaces or features, you can create a custom role that grants the desired Kibana privileges. +The Elastic Stack comes with the `kibana_admin` {ref}/built-in-roles.html[built-in role], which you can use to grant access to all Kibana features in all spaces. To grant users access to a subset of spaces or features, you can create a custom role that grants the desired Kibana privileges. When you assign a user multiple roles, the user receives a union of the roles’ privileges. Therefore, assigning the `kibana_admin` role in addition to a custom role that grants Kibana privileges is ineffective because `kibana_admin` has access to all the features in all spaces. NOTE: When running multiple tenants of Kibana by changing the `kibana.index` in your `kibana.yml`, you cannot use `kibana_admin` to grant access. You must create custom roles that authorize the user for that specific tenant. Although multi-tenant installations are supported, the recommended approach to securing access to Kibana segments is to grant users access to specific spaces. [role="xpack"] +[[xpack-kibana-role-management]] === {kib} role management -To create a role that grants {kib} privileges, go to **Management -> Security -> Roles** and click **Create role**. +To create a role that grants {kib} privileges, go to **Management -> Security -> Roles** and click **Create role**. [[adding_kibana_privileges]] ==== Adding {kib} privileges @@ -63,7 +64,7 @@ Features are available to users when their roles grant access to the features, * Using the same role, it’s possible to assign different privileges to different spaces. After you’ve added space privileges, click **Add space privilege**. If you’ve already added privileges for either *** Global (all spaces)** or an individual space, you will not be able to select these in the **Spaces** selection control. -Additionally, if you’ve already assigned privileges at *** Global (all spaces)**, you are only able to assign additional privileges to individual spaces. Similar to the behavior of multiple roles granting the union of all privileges, space privileges are also a union. If you’ve already granted the user the **All** privilege at *** Global (all spaces)**, you’re not able to restrict the role to only the **Read** privilege at an individual space. +Additionally, if you’ve already assigned privileges at *** Global (all spaces)**, you are only able to assign additional privileges to individual spaces. Similar to the behavior of multiple roles granting the union of all privileges, space privileges are also a union. If you’ve already granted the user the **All** privilege at *** Global (all spaces)**, you’re not able to restrict the role to only the **Read** privilege at an individual space. ==== Privilege summary @@ -111,4 +112,3 @@ image::user/security/images/privilege-example-2.png[Privilege example 2] [role="screenshot"] image::user/security/images/privilege-example-3.png[Privilege example 3] - From f546fc3b2f261548b61299568caad257913da824 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Thu, 28 May 2020 10:56:58 -0500 Subject: [PATCH 12/22] Index pattern field - add unit tests (#67549) * add unit tests to index pattern fields --- ...n-plugins-data-public.indexpatternfield.md | 1 + ...lic.indexpatternfield.readfromdocvalues.md | 11 + .../fields/__snapshots__/field.test.ts.snap | 35 +++ .../index_patterns/fields/field.test.ts | 223 ++++++++++++++++++ .../public/index_patterns/fields/field.ts | 1 + src/plugins/data/public/public.api.md | 2 + 6 files changed, 273 insertions(+) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.readfromdocvalues.md create mode 100644 src/plugins/data/public/index_patterns/fields/__snapshots__/field.test.ts.snap create mode 100644 src/plugins/data/public/index_patterns/fields/field.test.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md index a62cee7b654fe..1d3cfa9305c18 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md @@ -31,6 +31,7 @@ export declare class Field implements IFieldType | [indexPattern](./kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md) | | IndexPattern | | | [lang](./kibana-plugin-plugins-data-public.indexpatternfield.lang.md) | | string | | | [name](./kibana-plugin-plugins-data-public.indexpatternfield.name.md) | | string | | +| [readFromDocValues](./kibana-plugin-plugins-data-public.indexpatternfield.readfromdocvalues.md) | | boolean | | | [script](./kibana-plugin-plugins-data-public.indexpatternfield.script.md) | | string | | | [scripted](./kibana-plugin-plugins-data-public.indexpatternfield.scripted.md) | | boolean | | | [searchable](./kibana-plugin-plugins-data-public.indexpatternfield.searchable.md) | | boolean | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.readfromdocvalues.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.readfromdocvalues.md new file mode 100644 index 0000000000000..4b012c26a8620 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.readfromdocvalues.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [readFromDocValues](./kibana-plugin-plugins-data-public.indexpatternfield.readfromdocvalues.md) + +## IndexPatternField.readFromDocValues property + +Signature: + +```typescript +readFromDocValues?: boolean; +``` diff --git a/src/plugins/data/public/index_patterns/fields/__snapshots__/field.test.ts.snap b/src/plugins/data/public/index_patterns/fields/__snapshots__/field.test.ts.snap new file mode 100644 index 0000000000000..4593349a408a7 --- /dev/null +++ b/src/plugins/data/public/index_patterns/fields/__snapshots__/field.test.ts.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Field exports the property to JSON 1`] = ` +Object { + "aggregatable": true, + "conflictDescriptions": Object { + "a": Array [ + "b", + "c", + ], + "d": Array [ + "e", + ], + }, + "count": 1, + "esTypes": Array [ + "type", + ], + "lang": "lang", + "name": "name", + "readFromDocValues": false, + "script": "script", + "scripted": true, + "searchable": true, + "subType": Object { + "multi": Object { + "parent": "parent", + }, + "nested": Object { + "path": "path", + }, + }, + "type": "type", +} +`; diff --git a/src/plugins/data/public/index_patterns/fields/field.test.ts b/src/plugins/data/public/index_patterns/fields/field.test.ts new file mode 100644 index 0000000000000..18252b159d98d --- /dev/null +++ b/src/plugins/data/public/index_patterns/fields/field.test.ts @@ -0,0 +1,223 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Field } from './field'; +import { IndexPattern } from '..'; +import { notificationServiceMock } from '../../../../../core/public/mocks'; +import { FieldFormatsStart } from '../../field_formats'; +import { KBN_FIELD_TYPES } from '../../../common'; + +describe('Field', function () { + function flatten(obj: Record) { + return JSON.parse(JSON.stringify(obj)); + } + + function getField(values = {}) { + return new Field( + fieldValues.indexPattern as IndexPattern, + { ...fieldValues, ...values }, + false, + { + fieldFormats: {} as FieldFormatsStart, + toastNotifications: notificationServiceMock.createStartContract().toasts, + } + ); + } + + const fieldValues = { + name: 'name', + type: 'type', + script: 'script', + lang: 'lang', + count: 1, + esTypes: ['type'], + aggregatable: true, + filterable: true, + searchable: true, + sortable: true, + readFromDocValues: false, + visualizable: true, + scripted: true, + subType: { multi: { parent: 'parent' }, nested: { path: 'path' } }, + displayName: 'displayName', + indexPattern: ({ + fieldFormatMap: { name: {}, _source: {}, _score: {}, _id: {} }, + } as unknown) as IndexPattern, + format: { name: 'formatName' }, + $$spec: {}, + conflictDescriptions: { a: ['b', 'c'], d: ['e'] }, + } as Field; + + it('the correct properties are writable', () => { + const field = getField(); + + expect(field.count).toEqual(1); + field.count = 2; + expect(field.count).toEqual(2); + + expect(field.script).toEqual(fieldValues.script); + field.script = '1'; + expect(field.script).toEqual('1'); + + expect(field.lang).toEqual(fieldValues.lang); + field.lang = 'painless'; + expect(field.lang).toEqual('painless'); + + expect(field.conflictDescriptions).toEqual(fieldValues.conflictDescriptions); + field.conflictDescriptions = {}; + expect(field.conflictDescriptions).toEqual({}); + }); + + it('the correct properties are not writable', () => { + const field = getField(); + + expect(field.name).toEqual(fieldValues.name); + field.name = 'newName'; + expect(field.name).toEqual(fieldValues.name); + + expect(field.type).toEqual(fieldValues.type); + field.type = 'newType'; + expect(field.type).toEqual(fieldValues.type); + + expect(field.esTypes).toEqual(fieldValues.esTypes); + field.esTypes = ['newType']; + expect(field.esTypes).toEqual(fieldValues.esTypes); + + expect(field.scripted).toEqual(fieldValues.scripted); + field.scripted = false; + expect(field.scripted).toEqual(fieldValues.scripted); + + expect(field.searchable).toEqual(fieldValues.searchable); + field.searchable = false; + expect(field.searchable).toEqual(fieldValues.searchable); + + expect(field.aggregatable).toEqual(fieldValues.aggregatable); + field.aggregatable = false; + expect(field.aggregatable).toEqual(fieldValues.aggregatable); + + expect(field.readFromDocValues).toEqual(fieldValues.readFromDocValues); + field.readFromDocValues = true; + expect(field.readFromDocValues).toEqual(fieldValues.readFromDocValues); + + expect(field.subType).toEqual(fieldValues.subType); + field.subType = {}; + expect(field.subType).toEqual(fieldValues.subType); + + // not writable, not serialized + expect(() => { + field.indexPattern = {} as IndexPattern; + }).toThrow(); + + // computed fields + expect(() => { + field.format = { name: 'newFormatName' }; + }).toThrow(); + + expect(() => { + field.sortable = false; + }).toThrow(); + + expect(() => { + field.filterable = false; + }).toThrow(); + + expect(() => { + field.visualizable = false; + }).toThrow(); + + expect(() => { + field.displayName = 'newDisplayName'; + }).toThrow(); + + expect(() => { + field.$$spec = { a: 'b' }; + }).toThrow(); + }); + + it('sets type field when _source field', () => { + const field = getField({ name: '_source' }); + expect(field.type).toEqual('_source'); + }); + + it('calculates searchable', () => { + const field = getField({ searchable: true, scripted: false }); + expect(field.searchable).toEqual(true); + + const fieldB = getField({ searchable: false, scripted: true }); + expect(fieldB.searchable).toEqual(true); + + const fieldC = getField({ searchable: false, scripted: false }); + expect(fieldC.searchable).toEqual(false); + }); + + it('calculates aggregatable', () => { + const field = getField({ aggregatable: true, scripted: false }); + expect(field.aggregatable).toEqual(true); + + const fieldB = getField({ aggregatable: false, scripted: true }); + expect(fieldB.aggregatable).toEqual(true); + + const fieldC = getField({ aggregatable: false, scripted: false }); + expect(fieldC.aggregatable).toEqual(false); + }); + + it('calculates readFromDocValues', () => { + const field = getField({ readFromDocValues: true, scripted: false }); + expect(field.readFromDocValues).toEqual(true); + + const fieldB = getField({ readFromDocValues: false, scripted: false }); + expect(fieldB.readFromDocValues).toEqual(false); + + const fieldC = getField({ readFromDocValues: true, scripted: true }); + expect(fieldC.readFromDocValues).toEqual(false); + }); + + it('calculates sortable', () => { + const field = getField({ name: '_score' }); + expect(field.sortable).toEqual(true); + + const fieldB = getField({ indexed: true, type: KBN_FIELD_TYPES.STRING }); + expect(fieldB.sortable).toEqual(true); + + const fieldC = getField({ indexed: false }); + expect(fieldC.sortable).toEqual(false); + }); + + it('calculates filterable', () => { + const field = getField({ name: '_id' }); + expect(field.filterable).toEqual(true); + + const fieldB = getField({ scripted: true }); + expect(fieldB.filterable).toEqual(true); + + const fieldC = getField({ indexed: true, type: KBN_FIELD_TYPES.STRING }); + expect(fieldC.filterable).toEqual(true); + + const fieldD = getField({ scripted: false, indexed: false }); + expect(fieldD.filterable).toEqual(false); + }); + + it('exports the property to JSON', () => { + const field = new Field({ fieldFormatMap: { name: {} } } as IndexPattern, fieldValues, false, { + fieldFormats: {} as FieldFormatsStart, + toastNotifications: notificationServiceMock.createStartContract().toasts, + }); + expect(flatten(field)).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/data/public/index_patterns/fields/field.ts b/src/plugins/data/public/index_patterns/fields/field.ts index 12db09bbb846f..625df17d62e0d 100644 --- a/src/plugins/data/public/index_patterns/fields/field.ts +++ b/src/plugins/data/public/index_patterns/fields/field.ts @@ -56,6 +56,7 @@ export class Field implements IFieldType { subType?: IFieldSubType; displayName?: string; indexPattern?: IndexPattern; + readFromDocValues?: boolean; format: any; $$spec: FieldSpec; conflictDescriptions?: Record; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index fd40153e12c06..32abfd2694f16 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -991,6 +991,8 @@ export class IndexPatternField implements IFieldType { // (undocumented) name: string; // (undocumented) + readFromDocValues?: boolean; + // (undocumented) script?: string; // (undocumented) scripted?: boolean; From 642b6bd36ab02fc54e9e90bc6ad47d9dd2129b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Thu, 28 May 2020 12:19:29 -0400 Subject: [PATCH 13/22] Update wording (#67486) --- docs/user/alerting/index.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/alerting/index.asciidoc b/docs/user/alerting/index.asciidoc index df11f5f03a7de..6f691f2715bc8 100644 --- a/docs/user/alerting/index.asciidoc +++ b/docs/user/alerting/index.asciidoc @@ -160,7 +160,7 @@ If you are using an *on-premises* Elastic Stack deployment: If you are using an *on-premises* Elastic Stack deployment with <>: -* Transport Layer Security (TLS) must be configured for communication <>. {kib} alerting uses <> to secure background alert checks and actions, and API keys require {ref}/configuring-tls.html#tls-http[TLS on the HTTP interface]. +* You must enable Transport Layer Security (TLS) for communication <>. {kib} alerting uses <> to secure background alert checks and actions, and API keys require {ref}/configuring-tls.html#tls-http[TLS on the HTTP interface]. A proxy will not suffice. [float] [[alerting-security]] From 321a10d1dffc047fe778699caf021b2a02ded342 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 28 May 2020 18:02:50 +0100 Subject: [PATCH 14/22] [ML] Renaming mlSearch to mlAnomalySearch (#67602) --- .../shared_services/providers/system.ts | 4 +-- .../signals/find_ml_signals.ts | 4 +-- .../signals/signal_rule_alert_type.ts | 2 +- .../server/lib/machine_learning/authz.test.ts | 4 +-- .../server/lib/machine_learning/index.test.ts | 32 +++++++++---------- .../siem/server/lib/machine_learning/index.ts | 6 ++-- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/ml/server/shared_services/providers/system.ts b/x-pack/plugins/ml/server/shared_services/providers/system.ts index 698ac8e6261e5..33a4d854dd3e9 100644 --- a/x-pack/plugins/ml/server/shared_services/providers/system.ts +++ b/x-pack/plugins/ml/server/shared_services/providers/system.ts @@ -23,7 +23,7 @@ export interface MlSystemProvider { ): { mlCapabilities(): Promise; mlInfo(): Promise; - mlSearch(searchParams: SearchParams): Promise>; + mlAnomalySearch(searchParams: SearchParams): Promise>; }; } @@ -68,7 +68,7 @@ export function getMlSystemProvider( cloudId, }; }, - async mlSearch(searchParams: SearchParams): Promise> { + async mlAnomalySearch(searchParams: SearchParams): Promise> { isFullLicense(); return callAsCurrentUser('search', { ...searchParams, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/find_ml_signals.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/find_ml_signals.ts index 342976f3fd0fc..e95b713105fc6 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/find_ml_signals.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/find_ml_signals.ts @@ -27,14 +27,14 @@ export const findMlSignals = async ({ from: string; to: string; }) => { - const { mlSearch } = ml.mlSystemProvider(callCluster, request); + const { mlAnomalySearch } = ml.mlSystemProvider(callCluster, request); const params = { jobIds: [jobId], threshold: anomalyThreshold, earliestMs: dateMath.parse(from)?.valueOf() ?? 0, latestMs: dateMath.parse(to)?.valueOf() ?? 0, }; - const relevantAnomalies = await getAnomalies(params, mlSearch); + const relevantAnomalies = await getAnomalies(params, mlAnomalySearch); return relevantAnomalies; }; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 24cb9102915f8..8cef4c8ea0e6a 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -161,7 +161,7 @@ export const signalRulesAlertType = ({ ml, callCluster: scopedMlCallCluster, // This is needed to satisfy the ML Services API, but can be empty as it is - // currently unused by the mlSearch function. + // currently unused by the mlAnomalySearch function. request: ({} as unknown) as KibanaRequest, jobId: machineLearningJobId, anomalyThreshold, diff --git a/x-pack/plugins/siem/server/lib/machine_learning/authz.test.ts b/x-pack/plugins/siem/server/lib/machine_learning/authz.test.ts index 93c3a74c71378..93aa6fca87607 100644 --- a/x-pack/plugins/siem/server/lib/machine_learning/authz.test.ts +++ b/x-pack/plugins/siem/server/lib/machine_learning/authz.test.ts @@ -173,7 +173,7 @@ describe('mlAuthz', () => { const mockMlCapabilities = jest.fn(); mlMock.mlSystemProvider.mockImplementation(() => ({ mlInfo: jest.fn(), - mlSearch: jest.fn(), + mlAnomalySearch: jest.fn(), mlCapabilities: mockMlCapabilities, })); @@ -194,7 +194,7 @@ describe('mlAuthz', () => { const mockMlCapabilities = jest.fn(); mlMock.mlSystemProvider.mockImplementation(() => ({ mlInfo: jest.fn(), - mlSearch: jest.fn(), + mlAnomalySearch: jest.fn(), mlCapabilities: mockMlCapabilities, })); diff --git a/x-pack/plugins/siem/server/lib/machine_learning/index.test.ts b/x-pack/plugins/siem/server/lib/machine_learning/index.test.ts index 35a080f5ade76..63e3f3487e482 100644 --- a/x-pack/plugins/siem/server/lib/machine_learning/index.test.ts +++ b/x-pack/plugins/siem/server/lib/machine_learning/index.test.ts @@ -26,17 +26,17 @@ describe('getAnomalies', () => { }; }); - it('calls the provided mlSearch function', () => { - const mockMlSearch = jest.fn(); - getAnomalies(searchParams, mockMlSearch); + it('calls the provided mlAnomalySearch function', () => { + const mockMlAnomalySearch = jest.fn(); + getAnomalies(searchParams, mockMlAnomalySearch); - expect(mockMlSearch).toHaveBeenCalled(); + expect(mockMlAnomalySearch).toHaveBeenCalled(); }); it('passes anomalyThreshold as part of the query', () => { - const mockMlSearch = jest.fn(); - getAnomalies(searchParams, mockMlSearch); - const filters = getFiltersFromMock(mockMlSearch); + const mockMlAnomalySearch = jest.fn(); + getAnomalies(searchParams, mockMlAnomalySearch); + const filters = getFiltersFromMock(mockMlAnomalySearch); const criteria = getBoolCriteriaFromFilters(filters); expect(criteria).toEqual( @@ -45,9 +45,9 @@ describe('getAnomalies', () => { }); it('passes time range as part of the query', () => { - const mockMlSearch = jest.fn(); - getAnomalies(searchParams, mockMlSearch); - const filters = getFiltersFromMock(mockMlSearch); + const mockMlAnomalySearch = jest.fn(); + getAnomalies(searchParams, mockMlAnomalySearch); + const filters = getFiltersFromMock(mockMlAnomalySearch); const criteria = getBoolCriteriaFromFilters(filters); expect(criteria).toEqual( @@ -66,9 +66,9 @@ describe('getAnomalies', () => { }); it('passes a single jobId as part of the query', () => { - const mockMlSearch = jest.fn(); - getAnomalies(searchParams, mockMlSearch); - const filters = getFiltersFromMock(mockMlSearch); + const mockMlAnomalySearch = jest.fn(); + getAnomalies(searchParams, mockMlAnomalySearch); + const filters = getFiltersFromMock(mockMlAnomalySearch); const criteria = getBoolCriteriaFromFilters(filters); expect(criteria).toEqual( @@ -84,10 +84,10 @@ describe('getAnomalies', () => { }); it('passes multiple jobIds as part of the query', () => { - const mockMlSearch = jest.fn(); + const mockMlAnomalySearch = jest.fn(); searchParams.jobIds = ['jobId1', 'jobId2']; - getAnomalies(searchParams, mockMlSearch); - const filters = getFiltersFromMock(mockMlSearch); + getAnomalies(searchParams, mockMlAnomalySearch); + const filters = getFiltersFromMock(mockMlAnomalySearch); const criteria = getBoolCriteriaFromFilters(filters); expect(criteria).toEqual( diff --git a/x-pack/plugins/siem/server/lib/machine_learning/index.ts b/x-pack/plugins/siem/server/lib/machine_learning/index.ts index 5ff164a3f778c..ad2f1e5a8285c 100644 --- a/x-pack/plugins/siem/server/lib/machine_learning/index.ts +++ b/x-pack/plugins/siem/server/lib/machine_learning/index.ts @@ -10,7 +10,7 @@ import { AnomalyRecordDoc as Anomaly } from '../../../../ml/server'; export { Anomaly }; export type AnomalyResults = SearchResponse; -type MlSearch = (searchParams: SearchParams) => Promise>; +type MlAnomalySearch = (searchParams: SearchParams) => Promise>; export interface AnomaliesSearchParams { jobIds: string[]; @@ -22,11 +22,11 @@ export interface AnomaliesSearchParams { export const getAnomalies = async ( params: AnomaliesSearchParams, - mlSearch: MlSearch + mlAnomalySearch: MlAnomalySearch ): Promise => { const boolCriteria = buildCriteria(params); - return mlSearch({ + return mlAnomalySearch({ size: params.maxRecords || 100, body: { query: { From cae6b9e35a3675867f7d021be7224beeda0df8f6 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 28 May 2020 18:04:16 +0100 Subject: [PATCH 15/22] [ML] Using mlClient callAsInternalUser in job validation (#67609) --- x-pack/plugins/ml/server/routes/job_validation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/server/routes/job_validation.ts b/x-pack/plugins/ml/server/routes/job_validation.ts index 7c510b33d564c..0af8141a2a641 100644 --- a/x-pack/plugins/ml/server/routes/job_validation.ts +++ b/x-pack/plugins/ml/server/routes/job_validation.ts @@ -66,7 +66,7 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, let errorResp; const resp = await estimateBucketSpanFactory( context.ml!.mlClient.callAsCurrentUser, - context.core.elasticsearch.legacy.client.callAsInternalUser, + context.ml!.mlClient.callAsInternalUser, mlLicense.isSecurityEnabled() === false )(request.body) // this catch gets triggered when the estimation code runs without error @@ -187,7 +187,7 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, context.ml!.mlClient.callAsCurrentUser, request.body, version, - context.core.elasticsearch.legacy.client.callAsInternalUser, + context.ml!.mlClient.callAsInternalUser, mlLicense.isSecurityEnabled() === false ); From d431b3cf0b0c6507861ffd2952564cc234dde345 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 28 May 2020 18:31:42 +0100 Subject: [PATCH 16/22] chore(NA): add support for accessibility test group on jenkins flaky test runner (#67652) --- .ci/Jenkinsfile_flaky | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.ci/Jenkinsfile_flaky b/.ci/Jenkinsfile_flaky index 425a5e71798b1..2f496329dfd8e 100644 --- a/.ci/Jenkinsfile_flaky +++ b/.ci/Jenkinsfile_flaky @@ -70,6 +70,8 @@ def getWorkerFromParams(isXpack, job, ciGroup) { "run `node scripts/mocha`" ) }) + } else if (job == 'accessibility') { + return kibanaPipeline.functionalTestProcess('kibana-accessibility', './test/scripts/jenkins_accessibility.sh') } else if (job == 'firefoxSmoke') { return kibanaPipeline.functionalTestProcess('firefoxSmoke', './test/scripts/jenkins_firefox_smoke.sh') } else if(job == 'visualRegression') { @@ -79,7 +81,9 @@ def getWorkerFromParams(isXpack, job, ciGroup) { } } - if (job == 'firefoxSmoke') { + if (job == 'accessibility') { + return kibanaPipeline.functionalTestProcess('xpack-accessibility', './test/scripts/jenkins_xpack_accessibility.sh') + } else if (job == 'firefoxSmoke') { return kibanaPipeline.functionalTestProcess('xpack-firefoxSmoke', './test/scripts/jenkins_xpack_firefox_smoke.sh') } else if(job == 'visualRegression') { return kibanaPipeline.functionalTestProcess('xpack-visualRegression', './test/scripts/jenkins_xpack_visual_regression.sh') From 79a61d026f4865241a1d794d61c4133a1e31b7a1 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Thu, 28 May 2020 20:46:09 +0300 Subject: [PATCH 17/22] Populate RequestHandlerContext with start API only (#67579) * use start API to populate request context * remove client creation from uiSettings service setup API * remove __internals.uiSettings * update ui_settings mixin tests --- src/core/server/legacy/legacy_service.ts | 1 - src/core/server/server.ts | 10 +++---- src/core/server/ui_settings/types.ts | 5 ---- .../ui_settings/ui_settings_service.mock.ts | 3 -- .../ui_settings/ui_settings_service.test.ts | 28 ------------------- .../server/ui_settings/ui_settings_service.ts | 1 - src/legacy/server/kbn_server.d.ts | 1 - src/legacy/ui/ui_render/ui_render_mixin.js | 5 ++-- .../ui_settings_mixin.test.ts | 22 ++++++++------- .../ui/ui_settings/ui_settings_mixin.js | 2 +- .../ui_settings_service_factory.ts | 2 +- 11 files changed, 22 insertions(+), 58 deletions(-) diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index df1ed3e100923..cadbecb2e9a3f 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -352,7 +352,6 @@ export class LegacyService implements CoreService { uiPlugins: setupDeps.uiPlugins, elasticsearch: setupDeps.core.elasticsearch, rendering: setupDeps.core.rendering, - uiSettings: setupDeps.core.uiSettings, savedObjectsClientProvider: startDeps.core.savedObjects.clientProvider, legacy: this.legacyInternals, }, diff --git a/src/core/server/server.ts b/src/core/server/server.ts index 8226b4e3a57e0..b33528e2a3931 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -247,21 +247,21 @@ export class Server { coreId, 'core', async (context, req, res): Promise => { - const savedObjectsClient = this.coreStart!.savedObjects.getScopedClient(req); - const uiSettingsClient = coreSetup.uiSettings.asScopedToClient(savedObjectsClient); + const coreStart = this.coreStart!; + const savedObjectsClient = coreStart.savedObjects.getScopedClient(req); return { savedObjects: { client: savedObjectsClient, - typeRegistry: this.coreStart!.savedObjects.getTypeRegistry(), + typeRegistry: coreStart.savedObjects.getTypeRegistry(), }, elasticsearch: { legacy: { - client: coreSetup.elasticsearch.dataClient.asScoped(req), + client: coreStart.elasticsearch.legacy.client.asScoped(req), }, }, uiSettings: { - client: uiSettingsClient, + client: coreStart.uiSettings.asScopedToClient(savedObjectsClient), }, }; } diff --git a/src/core/server/ui_settings/types.ts b/src/core/server/ui_settings/types.ts index 076e1de4458d7..a29f16a90daeb 100644 --- a/src/core/server/ui_settings/types.ts +++ b/src/core/server/ui_settings/types.ts @@ -84,11 +84,6 @@ export interface InternalUiSettingsServiceSetup { * @param settings */ register(settings: Record): void; - /** - * Creates uiSettings client with provided *scoped* saved objects client {@link IUiSettingsClient} - * @param savedObjectsClient - */ - asScopedToClient(savedObjectsClient: SavedObjectsClientContract): IUiSettingsClient; } /** @public */ diff --git a/src/core/server/ui_settings/ui_settings_service.mock.ts b/src/core/server/ui_settings/ui_settings_service.mock.ts index cd781e9759b07..83cea6d7ab3e2 100644 --- a/src/core/server/ui_settings/ui_settings_service.mock.ts +++ b/src/core/server/ui_settings/ui_settings_service.mock.ts @@ -46,11 +46,8 @@ const createClientMock = () => { const createSetupMock = () => { const mocked: jest.Mocked = { register: jest.fn(), - asScopedToClient: jest.fn(), }; - mocked.asScopedToClient.mockReturnValue(createClientMock()); - return mocked; }; diff --git a/src/core/server/ui_settings/ui_settings_service.test.ts b/src/core/server/ui_settings/ui_settings_service.test.ts index 08400f56ad281..ebcb0cf1d762f 100644 --- a/src/core/server/ui_settings/ui_settings_service.test.ts +++ b/src/core/server/ui_settings/ui_settings_service.test.ts @@ -67,34 +67,6 @@ describe('uiSettings', () => { expect(setupDeps.savedObjects.registerType).toHaveBeenCalledWith(uiSettingsType); }); - describe('#asScopedToClient', () => { - it('passes saved object type "config" to UiSettingsClient', async () => { - const setup = await service.setup(setupDeps); - setup.asScopedToClient(savedObjectsClient); - expect(MockUiSettingsClientConstructor).toBeCalledTimes(1); - expect(MockUiSettingsClientConstructor.mock.calls[0][0].type).toBe('config'); - }); - - it('passes overrides to UiSettingsClient', async () => { - const setup = await service.setup(setupDeps); - setup.asScopedToClient(savedObjectsClient); - expect(MockUiSettingsClientConstructor).toBeCalledTimes(1); - expect(MockUiSettingsClientConstructor.mock.calls[0][0].overrides).toBe(overrides); - expect(MockUiSettingsClientConstructor.mock.calls[0][0].overrides).toEqual(overrides); - }); - - it('passes a copy of set defaults to UiSettingsClient', async () => { - const setup = await service.setup(setupDeps); - - setup.register(defaults); - setup.asScopedToClient(savedObjectsClient); - expect(MockUiSettingsClientConstructor).toBeCalledTimes(1); - - expect(MockUiSettingsClientConstructor.mock.calls[0][0].defaults).toEqual(defaults); - expect(MockUiSettingsClientConstructor.mock.calls[0][0].defaults).not.toBe(defaults); - }); - }); - describe('#register', () => { it('throws if registers the same key twice', async () => { const setup = await service.setup(setupDeps); diff --git a/src/core/server/ui_settings/ui_settings_service.ts b/src/core/server/ui_settings/ui_settings_service.ts index 83e66cf6dd06d..93593b29221da 100644 --- a/src/core/server/ui_settings/ui_settings_service.ts +++ b/src/core/server/ui_settings/ui_settings_service.ts @@ -65,7 +65,6 @@ export class UiSettingsService return { register: this.register.bind(this), - asScopedToClient: this.getScopedClientFactory(), }; } diff --git a/src/legacy/server/kbn_server.d.ts b/src/legacy/server/kbn_server.d.ts index 02491ff872981..40996500bfbe0 100644 --- a/src/legacy/server/kbn_server.d.ts +++ b/src/legacy/server/kbn_server.d.ts @@ -113,7 +113,6 @@ export interface KibanaCore { legacy: ILegacyInternals; rendering: LegacyServiceSetupDeps['core']['rendering']; uiPlugins: UiPlugins; - uiSettings: LegacyServiceSetupDeps['core']['uiSettings']; savedObjectsClientProvider: LegacyServiceStartDeps['core']['savedObjects']['clientProvider']; }; env: { diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 52c43c426ed91..10847b9928528 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -247,9 +247,10 @@ export function uiRenderMixin(kbnServer, server, config) { rendering, legacy, savedObjectsClientProvider: savedObjects, - uiSettings: { asScopedToClient }, } = kbnServer.newPlatform.__internals; - const uiSettings = asScopedToClient(savedObjects.getClient(h.request)); + const uiSettings = kbnServer.newPlatform.start.core.uiSettings.asScopedToClient( + savedObjects.getClient(h.request) + ); const vars = await legacy.getVars(app.getId(), h.request, { apmConfig: getApmConfig(app), ...overrides, diff --git a/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts b/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts index bee0d69706ebb..84a64d3f46f11 100644 --- a/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts +++ b/src/legacy/ui/ui_settings/integration_tests/ui_settings_mixin.test.ts @@ -59,6 +59,15 @@ describe('uiSettingsMixin()', () => { decorate: sinon.spy((type: keyof Decorators, name: string, value: any) => { decorations[type][name] = value; }), + newPlatform: { + setup: { + core: { + uiSettings: { + register: sinon.stub(), + }, + }, + }, + }, }; // "promise" returned from kbnServer.ready() @@ -70,13 +79,6 @@ describe('uiSettingsMixin()', () => { server, uiExports: { uiSettingDefaults }, ready: sinon.stub().returns(readyPromise), - newPlatform: { - __internals: { - uiSettings: { - register: sinon.stub(), - }, - }, - }, }; uiSettingsMixin(kbnServer, server); @@ -92,10 +94,10 @@ describe('uiSettingsMixin()', () => { afterEach(() => sandbox.restore()); it('passes uiSettingsDefaults to the new platform', () => { - const { kbnServer } = setup(); - sinon.assert.calledOnce(kbnServer.newPlatform.__internals.uiSettings.register); + const { server } = setup(); + sinon.assert.calledOnce(server.newPlatform.setup.core.uiSettings.register); sinon.assert.calledWithExactly( - kbnServer.newPlatform.__internals.uiSettings.register, + server.newPlatform.setup.core.uiSettings.register, uiSettingDefaults ); }); diff --git a/src/legacy/ui/ui_settings/ui_settings_mixin.js b/src/legacy/ui/ui_settings/ui_settings_mixin.js index accdc4d043d1a..8190b67732dac 100644 --- a/src/legacy/ui/ui_settings/ui_settings_mixin.js +++ b/src/legacy/ui/ui_settings/ui_settings_mixin.js @@ -37,7 +37,7 @@ export function uiSettingsMixin(kbnServer, server) { return acc; }, {}); - kbnServer.newPlatform.__internals.uiSettings.register(mergedUiSettingDefaults); + server.newPlatform.setup.core.uiSettings.register(mergedUiSettingDefaults); server.decorate('server', 'uiSettingsServiceFactory', (options = {}) => { return uiSettingsServiceFactory(server, options); diff --git a/src/legacy/ui/ui_settings/ui_settings_service_factory.ts b/src/legacy/ui/ui_settings/ui_settings_service_factory.ts index ab4eb75e4b703..6c3c50d175dc5 100644 --- a/src/legacy/ui/ui_settings/ui_settings_service_factory.ts +++ b/src/legacy/ui/ui_settings/ui_settings_service_factory.ts @@ -32,5 +32,5 @@ export function uiSettingsServiceFactory( server: Legacy.Server, options: UiSettingsServiceFactoryOptions ): IUiSettingsClient { - return server.newPlatform.__internals.uiSettings.asScopedToClient(options.savedObjectsClient); + return server.newPlatform.start.core.uiSettings.asScopedToClient(options.savedObjectsClient); } From 6643b9c191d80a3cfca89a36d76bc8988a7c9de6 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Thu, 28 May 2020 19:31:36 +0100 Subject: [PATCH 18/22] [Logs UI] [Alerting] Fix time state bug (#67630) * Read from alertParams state only for timeSize and timeUnit * Typecheck --- .../alerting/logs/expression_editor/editor.tsx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx index cc87167b10a96..d81d11e01d4a5 100644 --- a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx @@ -17,11 +17,7 @@ import { import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { AlertsContextValue } from '../../../../../../triggers_actions_ui/public/application/context/alerts_context'; -import { - LogDocumentCountAlertParams, - Comparator, - TimeUnit, -} from '../../../../../common/alerting/logs/types'; +import { LogDocumentCountAlertParams, Comparator } from '../../../../../common/alerting/logs/types'; import { DocumentCount } from './document_count'; import { Criteria } from './criteria'; import { useSourceId } from '../../../../containers/source_id'; @@ -123,8 +119,6 @@ export const SourceStatusWrapper: React.FC = (props) => { export const Editor: React.FC = (props) => { const { setAlertParams, alertParams, errors } = props; - const [timeSize, setTimeSize] = useState(1); - const [timeUnit, setTimeUnit] = useState('m'); const [hasSetDefaults, setHasSetDefaults] = useState(false); const { sourceStatus } = useLogSourceContext(); @@ -165,15 +159,13 @@ export const Editor: React.FC = (props) => { const updateTimeSize = useCallback( (ts: number | undefined) => { - setTimeSize(ts || undefined); setAlertParams('timeSize', ts); }, - [setTimeSize, setAlertParams] + [setAlertParams] ); const updateTimeUnit = useCallback( (tu: string) => { - setTimeUnit(tu as TimeUnit); setAlertParams('timeUnit', tu); }, [setAlertParams] @@ -217,8 +209,8 @@ export const Editor: React.FC = (props) => { /> Date: Thu, 28 May 2020 12:35:24 -0600 Subject: [PATCH 19/22] [SIEM][Lists] Adds _find to value lists ## Summary Adds the REST and API routes for find and filter for exception lists and value lists * Fixes bugs with string parameters for the _find with exception lists * Adds the _find for the value based lists * More scripts for how to filter things for both list values and exception lists * Misc type script fixes * Adds a cursor to move from the previous page to the next page * Adds name space 'agnostic' vs. 'single' feature for exception_lists **REST API's:** ```ts POST /api/lists/_find POST /api/lists/items/_find POST /api/exception_lists/_find POST /api/exception_lists/items/_find ``` **Parameters you can send:** * sort * sort_order * filter * page * per_page * list_id (for list items only and required) * cursor (for finding the next page or advancing to deep pages) **See test scripts below:** ```sh find_exception_list_items_by_filter.sh find_exception_lists_by_filter.sh find_list_items.sh find_list_items_with_cursor.sh find_list_items_with_sort.sh find_list_items_with_sort_cursor.sh find_lists.sh find_lists_with_cursor.sh find_lists_with_filter.sh find_lists_with_sort.sh find_lists_with_sort_cursor.sh ``` ### Checklist Note: Unit tests are left out as this is blocking people but I will be adding tests as this is being reviewed unless someone needs these features now. This is still all behind a feature flag and considered to be in the area of proof of concept and not production ready until more tests and end to tests are added. - [ ] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios --- x-pack/plugins/lists/common/constants.mock.ts | 1 + .../lists/common/schemas/common/schemas.ts | 31 +++++ .../create_exception_list_item_schema.ts | 12 +- .../create_exception_list_schema.mock.ts | 3 +- .../request/create_exception_list_schema.ts | 8 +- .../delete_exception_list_item_schema.ts | 11 +- .../request/delete_exception_list_schema.ts | 8 +- .../find_exception_list_item_schema.ts | 28 +++- .../request/find_exception_list_schema.ts | 21 ++- .../schemas/request/find_list_item_schema.ts | 31 +++++ .../schemas/request/find_list_schema.ts | 28 ++++ .../lists/common/schemas/request/index.ts | 2 + .../read_exception_list_item_schema.ts | 17 ++- .../request/read_exception_list_schema.ts | 17 ++- .../update_exception_list_item_schema.ts | 9 +- .../request/update_exception_list_schema.ts | 6 +- .../response/exception_list_item_schema.ts | 2 + .../schemas/response/exception_list_schema.ts | 2 + .../response/found_list_item_schema.ts | 25 ++++ .../schemas/response/found_list_schema.ts | 25 ++++ .../lists/common/schemas/response/index.ts | 10 +- .../common/schemas/response/list_schema.ts | 3 + .../common/schemas/types/default_namespace.ts | 30 +++++ .../types/string_to_positive_number.ts | 35 +++++ .../lists/public/exceptions/api.test.ts | 4 +- .../hooks/use_exception_list.test.tsx | 2 + .../plugins/lists/public/exceptions/mock.ts | 2 + .../create_exception_list_item_route.ts | 10 +- .../routes/create_exception_list_route.ts | 17 ++- .../delete_exception_list_item_route.ts | 15 ++- .../routes/delete_exception_list_route.ts | 16 ++- .../routes/find_exception_list_item_route.ts | 14 +- .../routes/find_exception_list_route.ts | 13 +- .../server/routes/find_list_item_route.ts | 99 ++++++++++++++ .../lists/server/routes/find_list_route.ts | 89 ++++++++++++ x-pack/plugins/lists/server/routes/index.ts | 2 + .../lists/server/routes/init_routes.ts | 4 + .../routes/read_exception_list_item_route.ts | 16 ++- .../routes/read_exception_list_route.ts | 15 ++- .../server/routes/read_list_index_route.ts | 2 +- .../update_exception_list_item_route.ts | 3 +- .../routes/update_exception_list_route.ts | 14 +- .../lists/server/scripts/delete_all_lists.sh | 38 ------ .../server/scripts/delete_exception_list.sh | 6 +- .../scripts/delete_exception_list_by_id.sh | 6 +- .../scripts/delete_exception_list_item.sh | 6 +- .../delete_exception_list_item_by_id.sh | 6 +- .../lists/server/scripts/delete_list.sh | 2 +- .../new/exception_list_agnostic.json | 9 ++ .../new/exception_list_item_agnostic.json | 22 +++ .../updates/simple_update_agnostic.json | 16 +++ .../scripts/find_exception_list_items.sh | 6 +- .../find_exception_list_items_by_filter.sh | 29 ++++ .../server/scripts/find_exception_lists.sh | 6 +- .../scripts/find_exception_lists_by_filter.sh | 26 ++++ .../lists/server/scripts/find_list_items.sh | 19 +++ .../scripts/find_list_items_with_cursor.sh | 23 ++++ .../scripts/find_list_items_with_sort.sh | 21 +++ .../find_list_items_with_sort_cursor.sh | 22 +++ .../lists/server/scripts/find_lists.sh | 18 +++ .../server/scripts/find_lists_with_cursor.sh | 22 +++ .../server/scripts/find_lists_with_filter.sh | 18 +++ .../server/scripts/find_lists_with_sort.sh | 20 +++ .../scripts/find_lists_with_sort_cursor.sh | 21 +++ .../server/scripts/get_exception_list.sh | 7 +- .../scripts/get_exception_list_by_id.sh | 4 +- .../server/scripts/get_exception_list_item.sh | 6 +- .../scripts/get_exception_list_item_by_id.sh | 6 +- .../scripts/lists/new/list_auto_id.json | 5 + .../exception_lists/create_exception_list.ts | 4 +- .../create_exception_list_item.ts | 4 +- .../exception_lists/delete_exception_list.ts | 8 +- .../delete_exception_list_item.ts | 8 +- .../delete_exception_list_items_by_list.ts | 3 +- .../exception_lists/exception_list_client.ts | 9 +- .../exception_list_client_types.ts | 28 ++-- .../exception_lists/find_exception_list.ts | 26 ++-- .../find_exception_list_item.ts | 24 ++-- .../exception_lists/get_exception_list.ts | 9 +- .../get_exception_list_item.ts | 5 +- .../exception_lists/update_exception_list.ts | 4 +- .../update_exception_list_item.ts | 8 +- .../server/services/exception_lists/utils.ts | 23 +++- .../server/services/items/create_list_item.ts | 2 +- .../server/services/items/find_list_item.ts | 116 ++++++++++++++++ .../server/services/items/get_list_item.ts | 3 +- .../services/items/get_list_item_by_values.ts | 3 +- .../lists/server/services/items/index.ts | 7 +- .../server/services/items/update_list_item.ts | 2 +- .../items/write_list_items_to_stream.ts | 2 +- .../server/services/lists/create_list.ts | 2 +- .../lists/server/services/lists/find_list.ts | 104 ++++++++++++++ .../lists/server/services/lists/get_list.ts | 14 +- .../lists/server/services/lists/index.ts | 1 + .../server/services/lists/list_client.ts | 64 ++++++++- .../services/lists/list_client_types.ts | 27 ++++ .../{exception_lists => lists}/types.ts | 6 +- .../server/services/lists/update_list.ts | 2 +- .../services/utils/calculate_scroll_math.ts | 41 ++++++ .../services/utils/encode_decode_cursor.ts | 127 ++++++++++++++++++ .../services/utils/get_query_filter.test.ts | 34 +++++ .../server/services/utils/get_query_filter.ts | 32 +++++ .../services/utils/get_search_after_scroll.ts | 64 +++++++++ .../get_search_after_with_tie_breaker.ts | 41 ++++++ .../utils/get_sort_with_tie_breaker.ts | 27 ++++ .../utils/get_source_with_tie_breaker.ts | 15 +++ .../lists/server/services/utils/index.ts | 8 ++ .../services/utils/scroll_to_start_page.ts | 94 +++++++++++++ .../utils/transform_elastic_to_list.ts | 24 ++++ 109 files changed, 1921 insertions(+), 196 deletions(-) create mode 100644 x-pack/plugins/lists/common/schemas/request/find_list_item_schema.ts create mode 100644 x-pack/plugins/lists/common/schemas/request/find_list_schema.ts create mode 100644 x-pack/plugins/lists/common/schemas/response/found_list_item_schema.ts create mode 100644 x-pack/plugins/lists/common/schemas/response/found_list_schema.ts create mode 100644 x-pack/plugins/lists/common/schemas/types/default_namespace.ts create mode 100644 x-pack/plugins/lists/common/schemas/types/string_to_positive_number.ts create mode 100644 x-pack/plugins/lists/server/routes/find_list_item_route.ts create mode 100644 x-pack/plugins/lists/server/routes/find_list_route.ts delete mode 100755 x-pack/plugins/lists/server/scripts/delete_all_lists.sh create mode 100644 x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json create mode 100644 x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json create mode 100644 x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json create mode 100755 x-pack/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_exception_lists_by_filter.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_list_items.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_list_items_with_cursor.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_list_items_with_sort.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_lists.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_lists_with_cursor.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_lists_with_filter.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_lists_with_sort.sh create mode 100755 x-pack/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh create mode 100644 x-pack/plugins/lists/server/scripts/lists/new/list_auto_id.json create mode 100644 x-pack/plugins/lists/server/services/items/find_list_item.ts create mode 100644 x-pack/plugins/lists/server/services/lists/find_list.ts rename x-pack/plugins/lists/server/services/{exception_lists => lists}/types.ts (72%) create mode 100644 x-pack/plugins/lists/server/services/utils/calculate_scroll_math.ts create mode 100644 x-pack/plugins/lists/server/services/utils/encode_decode_cursor.ts create mode 100644 x-pack/plugins/lists/server/services/utils/get_query_filter.test.ts create mode 100644 x-pack/plugins/lists/server/services/utils/get_query_filter.ts create mode 100644 x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts create mode 100644 x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts create mode 100644 x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts create mode 100644 x-pack/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts create mode 100644 x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts create mode 100644 x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts diff --git a/x-pack/plugins/lists/common/constants.mock.ts b/x-pack/plugins/lists/common/constants.mock.ts index d174211f348ea..8c5f6b0cbe56c 100644 --- a/x-pack/plugins/lists/common/constants.mock.ts +++ b/x-pack/plugins/lists/common/constants.mock.ts @@ -28,3 +28,4 @@ export const META = {}; export const TYPE = 'ip'; export const VALUE = '127.0.0.1'; export const VALUE_2 = '255.255.255'; +export const NAMESPACE_TYPE = 'single'; diff --git a/x-pack/plugins/lists/common/schemas/common/schemas.ts b/x-pack/plugins/lists/common/schemas/common/schemas.ts index cd69685ffcb1b..14ae030c63df3 100644 --- a/x-pack/plugins/lists/common/schemas/common/schemas.ts +++ b/x-pack/plugins/lists/common/schemas/common/schemas.ts @@ -9,6 +9,7 @@ import * as t from 'io-ts'; import { DefaultStringArray, NonEmptyString } from '../types'; +import { DefaultNamespace } from '../types/default_namespace'; export const name = t.string; export type Name = t.TypeOf; @@ -97,8 +98,38 @@ export const itemIdOrUndefined = t.union([item_id, t.undefined]); export type ItemIdOrUndefined = t.TypeOf; export const per_page = t.number; // TODO: Change this out for PositiveNumber from siem +export type PerPage = t.TypeOf; + +export const perPageOrUndefined = t.union([per_page, t.undefined]); +export type PerPageOrUndefined = t.TypeOf; + export const total = t.number; // TODO: Change this out for PositiveNumber from siem +export const totalUndefined = t.union([total, t.undefined]); +export type TotalOrUndefined = t.TypeOf; + export const page = t.number; // TODO: Change this out for PositiveNumber from siem +export type Page = t.TypeOf; + +export const pageOrUndefined = t.union([page, t.undefined]); +export type PageOrUndefined = t.TypeOf; + export const sort_field = t.string; +export const sortFieldOrUndefined = t.union([sort_field, t.undefined]); +export type SortFieldOrUndefined = t.TypeOf; + export const sort_order = t.keyof({ asc: null, desc: null }); +export const sortOrderOrUndefined = t.union([sort_order, t.undefined]); +export type SortOrderOrUndefined = t.TypeOf; + export const filter = t.string; +export type Filter = t.TypeOf; +export const filterOrUndefined = t.union([filter, t.undefined]); +export type FilterOrUndefined = t.TypeOf; + +export const cursor = t.string; +export type Cursor = t.TypeOf; +export const cursorOrUndefined = t.union([cursor, t.undefined]); +export type CursorOrUndefined = t.TypeOf; + +export const namespace_type = DefaultNamespace; +export type NamespaceType = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.ts index f899fd69110fa..c10d441d93aa5 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.ts @@ -10,6 +10,7 @@ import * as t from 'io-ts'; import { ItemId, + NamespaceType, Tags, _Tags, _tags, @@ -19,6 +20,7 @@ import { list_id, meta, name, + namespace_type, tags, } from '../common/schemas'; import { Identity, RequiredKeepUndefined } from '../../types'; @@ -41,6 +43,7 @@ export const createExceptionListItemSchema = t.intersection([ entries: DefaultEntryArray, // defaults to empty array if not set during decode item_id: DefaultUuid, // defaults to GUID (uuid v4) if not set during decode meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode tags, // defaults to empty array if not set during decode }) ), @@ -53,13 +56,16 @@ export type CreateExceptionListItemSchema = RequiredKeepUndefined< t.TypeOf >; -// This type is used after a decode since the arrays turn into defaults of empty arrays -// and if a item_id is not specified it turns into a default GUID +// This type is used after a decode since some things are defaults after a decode. export type CreateExceptionListItemSchemaDecoded = Identity< - Omit & { + Omit< + CreateExceptionListItemSchema, + '_tags' | 'tags' | 'item_id' | 'entries' | 'namespace_type' + > & { _tags: _Tags; tags: Tags; item_id: ItemId; entries: EntriesArray; + namespace_type: NamespaceType; } >; diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts index d38d3cc038525..f0b98cb96f743 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DESCRIPTION, LIST_ID, META, NAME, TYPE } from '../../constants.mock'; +import { DESCRIPTION, LIST_ID, META, NAME, NAMESPACE_TYPE, TYPE } from '../../constants.mock'; import { CreateExceptionListSchema } from './create_exception_list_schema'; @@ -14,6 +14,7 @@ export const getCreateExceptionListSchemaMock = (): CreateExceptionListSchema => list_id: LIST_ID, meta: META, name: NAME, + namespace_type: NAMESPACE_TYPE, tags: [], type: TYPE, }); diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts index 5ba3bf4e8f43b..3da8bfca126ae 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.ts @@ -10,6 +10,7 @@ import * as t from 'io-ts'; import { ListId, + NamespaceType, Tags, _Tags, _tags, @@ -17,6 +18,7 @@ import { exceptionListType, meta, name, + namespace_type, tags, } from '../common/schemas'; import { Identity, RequiredKeepUndefined } from '../../types'; @@ -35,6 +37,7 @@ export const createExceptionListSchema = t.intersection([ _tags, // defaults to empty array if not set during decode list_id: DefaultUuid, // defaults to a GUID (UUID v4) string if not set during decode meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode tags, // defaults to empty array if not set during decode }) ), @@ -45,11 +48,12 @@ export type CreateExceptionListSchema = RequiredKeepUndefined< t.TypeOf >; -// This type is used after a decode since the arrays turn into defaults of empty arrays. +// This type is used after a decode since some things are defaults after a decode. export type CreateExceptionListSchemaDecoded = Identity< - CreateExceptionListSchema & { + Omit & { _tags: _Tags; tags: Tags; list_id: ListId; + namespace_type: NamespaceType; } >; diff --git a/x-pack/plugins/lists/common/schemas/request/delete_exception_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/request/delete_exception_list_item_schema.ts index 607e05ef8286f..4c5b70d9a4073 100644 --- a/x-pack/plugins/lists/common/schemas/request/delete_exception_list_item_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/delete_exception_list_item_schema.ts @@ -8,13 +8,22 @@ import * as t from 'io-ts'; -import { id, item_id } from '../common/schemas'; +import { NamespaceType, id, item_id, namespace_type } from '../common/schemas'; export const deleteExceptionListItemSchema = t.exact( t.partial({ id, item_id, + namespace_type, // defaults to 'single' if not set during decode }) ); export type DeleteExceptionListItemSchema = t.TypeOf; + +// This type is used after a decode since some things are defaults after a decode. +export type DeleteExceptionListItemSchemaDecoded = Omit< + DeleteExceptionListItemSchema, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/plugins/lists/common/schemas/request/delete_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/delete_exception_list_schema.ts index 7a6086514f943..2577d867031f0 100644 --- a/x-pack/plugins/lists/common/schemas/request/delete_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/delete_exception_list_schema.ts @@ -8,13 +8,19 @@ import * as t from 'io-ts'; -import { id, list_id } from '../common/schemas'; +import { NamespaceType, id, list_id, namespace_type } from '../common/schemas'; export const deleteExceptionListSchema = t.exact( t.partial({ id, list_id, + namespace_type, // defaults to 'single' if not set during decode }) ); export type DeleteExceptionListSchema = t.TypeOf; + +// This type is used after a decode since some things are defaults after a decode. +export type DeleteExceptionListSchemaDecoded = Omit & { + namespace_type: NamespaceType; +}; diff --git a/x-pack/plugins/lists/common/schemas/request/find_exception_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/request/find_exception_list_item_schema.ts index 3fc51dd20b0b3..31eb4925eb6d6 100644 --- a/x-pack/plugins/lists/common/schemas/request/find_exception_list_item_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/find_exception_list_item_schema.ts @@ -8,8 +8,16 @@ import * as t from 'io-ts'; -import { filter, list_id, page, per_page, sort_field, sort_order } from '../common/schemas'; +import { + NamespaceType, + filter, + list_id, + namespace_type, + sort_field, + sort_order, +} from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; +import { StringToPositiveNumber } from '../types/string_to_positive_number'; export const findExceptionListItemSchema = t.intersection([ t.exact( @@ -20,8 +28,9 @@ export const findExceptionListItemSchema = t.intersection([ t.exact( t.partial({ filter, // defaults to undefined if not set during decode - page, // defaults to undefined if not set during decode - per_page, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode sort_field, // defaults to undefined if not set during decode sort_order, // defaults to undefined if not set during decode }) @@ -30,6 +39,19 @@ export const findExceptionListItemSchema = t.intersection([ export type FindExceptionListItemSchemaPartial = t.TypeOf; +// This type is used after a decode since some things are defaults after a decode. +export type FindExceptionListItemSchemaPartialDecoded = Omit< + FindExceptionListItemSchemaPartial, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; + +// This type is used after a decode since some things are defaults after a decode. +export type FindExceptionListItemSchemaDecoded = RequiredKeepUndefined< + FindExceptionListItemSchemaPartialDecoded +>; + export type FindExceptionListItemSchema = RequiredKeepUndefined< t.TypeOf >; diff --git a/x-pack/plugins/lists/common/schemas/request/find_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/find_exception_list_schema.ts index f795be9493fbf..fa00c5b0dafb1 100644 --- a/x-pack/plugins/lists/common/schemas/request/find_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/find_exception_list_schema.ts @@ -8,14 +8,16 @@ import * as t from 'io-ts'; -import { filter, page, per_page, sort_field, sort_order } from '../common/schemas'; +import { NamespaceType, filter, namespace_type, sort_field, sort_order } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; +import { StringToPositiveNumber } from '../types/string_to_positive_number'; export const findExceptionListSchema = t.exact( t.partial({ filter, // defaults to undefined if not set during decode - page, // defaults to undefined if not set during decode - per_page, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode sort_field, // defaults to undefined if not set during decode sort_order, // defaults to undefined if not set during decode }) @@ -23,6 +25,19 @@ export const findExceptionListSchema = t.exact( export type FindExceptionListSchemaPartial = t.TypeOf; +// This type is used after a decode since some things are defaults after a decode. +export type FindExceptionListSchemaPartialDecoded = Omit< + FindExceptionListSchemaPartial, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; + +// This type is used after a decode since some things are defaults after a decode. +export type FindExceptionListSchemaDecoded = RequiredKeepUndefined< + FindExceptionListSchemaPartialDecoded +>; + export type FindExceptionListSchema = RequiredKeepUndefined< t.TypeOf >; diff --git a/x-pack/plugins/lists/common/schemas/request/find_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/request/find_list_item_schema.ts new file mode 100644 index 0000000000000..c9ece4224c4ce --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/request/find_list_item_schema.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable @typescript-eslint/camelcase */ + +import * as t from 'io-ts'; + +import { cursor, filter, list_id, sort_field, sort_order } from '../common/schemas'; +import { Identity, RequiredKeepUndefined } from '../../types'; +import { StringToPositiveNumber } from '../types/string_to_positive_number'; + +export const findListItemSchema = t.intersection([ + t.exact(t.type({ list_id })), + t.exact( + t.partial({ + cursor, // defaults to undefined if not set during decode + filter, // defaults to undefined if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) + ), +]); + +export type FindListItemSchemaPartial = Identity>; + +export type FindListItemSchema = RequiredKeepUndefined>; diff --git a/x-pack/plugins/lists/common/schemas/request/find_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/find_list_schema.ts new file mode 100644 index 0000000000000..c29ab4f5360dd --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/request/find_list_schema.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable @typescript-eslint/camelcase */ + +import * as t from 'io-ts'; + +import { cursor, filter, sort_field, sort_order } from '../common/schemas'; +import { RequiredKeepUndefined } from '../../types'; +import { StringToPositiveNumber } from '../types/string_to_positive_number'; + +export const findListSchema = t.exact( + t.partial({ + cursor, // defaults to undefined if not set during decode + filter, // defaults to undefined if not set during decode + page: StringToPositiveNumber, // defaults to undefined if not set during decode + per_page: StringToPositiveNumber, // defaults to undefined if not set during decode + sort_field, // defaults to undefined if not set during decode + sort_order, // defaults to undefined if not set during decode + }) +); + +export type FindListSchemaPartial = t.TypeOf; + +export type FindListSchema = RequiredKeepUndefined>; diff --git a/x-pack/plugins/lists/common/schemas/request/index.ts b/x-pack/plugins/lists/common/schemas/request/index.ts index 0dbd9297b773e..7ab3d943f14da 100644 --- a/x-pack/plugins/lists/common/schemas/request/index.ts +++ b/x-pack/plugins/lists/common/schemas/request/index.ts @@ -15,6 +15,8 @@ export * from './delete_list_schema'; export * from './export_list_item_query_schema'; export * from './find_exception_list_item_schema'; export * from './find_exception_list_schema'; +export * from './find_list_item_schema'; +export * from './find_list_schema'; export * from './import_list_item_schema'; export * from './patch_list_item_schema'; export * from './patch_list_schema'; diff --git a/x-pack/plugins/lists/common/schemas/request/read_exception_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/request/read_exception_list_item_schema.ts index 095fcd2f63b48..fded35dfd1cc9 100644 --- a/x-pack/plugins/lists/common/schemas/request/read_exception_list_item_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/read_exception_list_item_schema.ts @@ -8,13 +8,28 @@ import * as t from 'io-ts'; -import { id, item_id } from '../common/schemas'; +import { NamespaceType, id, item_id, namespace_type } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; export const readExceptionListItemSchema = t.partial({ id, item_id, + namespace_type, // defaults to 'single' if not set during decode }); export type ReadExceptionListItemSchemaPartial = t.TypeOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadExceptionListItemSchemaPartialDecoded = Omit< + ReadExceptionListItemSchemaPartial, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadExceptionListItemSchemaDecoded = RequiredKeepUndefined< + ReadExceptionListItemSchemaPartialDecoded +>; + export type ReadExceptionListItemSchema = RequiredKeepUndefined; diff --git a/x-pack/plugins/lists/common/schemas/request/read_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/read_exception_list_schema.ts index 5593e640f71ac..6b623ea8c0b9b 100644 --- a/x-pack/plugins/lists/common/schemas/request/read_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/read_exception_list_schema.ts @@ -8,13 +8,28 @@ import * as t from 'io-ts'; -import { id, list_id } from '../common/schemas'; +import { NamespaceType, id, list_id, namespace_type } from '../common/schemas'; import { RequiredKeepUndefined } from '../../types'; export const readExceptionListSchema = t.partial({ id, list_id, + namespace_type, // defaults to 'single' if not set during decode }); export type ReadExceptionListSchemaPartial = t.TypeOf; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadExceptionListSchemaPartialDecoded = Omit< + ReadExceptionListSchemaPartial, + 'namespace_type' +> & { + namespace_type: NamespaceType; +}; + +// This type is used after a decode since some things are defaults after a decode. +export type ReadExceptionListSchemaDecoded = RequiredKeepUndefined< + ReadExceptionListSchemaPartialDecoded +>; + export type ReadExceptionListSchema = RequiredKeepUndefined; diff --git a/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.ts index 162406a6d6589..3d66dad959c25 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.ts @@ -9,6 +9,7 @@ import * as t from 'io-ts'; import { + NamespaceType, Tags, _Tags, _tags, @@ -18,6 +19,7 @@ import { id, meta, name, + namespace_type, tags, } from '../common/schemas'; import { Identity, RequiredKeepUndefined } from '../../types'; @@ -40,6 +42,7 @@ export const updateExceptionListItemSchema = t.intersection([ id, // defaults to undefined if not set during decode item_id: t.union([t.string, t.undefined]), meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode tags, // defaults to empty array if not set during decode }) ), @@ -52,12 +55,12 @@ export type UpdateExceptionListItemSchema = RequiredKeepUndefined< t.TypeOf >; -// This type is used after a decode since the arrays turn into defaults of empty arrays -// and if a item_id is not specified it turns into a default GUID +// This type is used after a decode since some things are defaults after a decode. export type UpdateExceptionListItemSchemaDecoded = Identity< - Omit & { + Omit & { _tags: _Tags; tags: Tags; entries: EntriesArray; + namespace_type: NamespaceType; } >; diff --git a/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts index e8a0dcd4994a2..76160c3419449 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.ts @@ -9,6 +9,7 @@ import * as t from 'io-ts'; import { + NamespaceType, Tags, _Tags, _tags, @@ -16,6 +17,7 @@ import { exceptionListType, meta, name, + namespace_type, tags, } from '../common/schemas'; import { Identity, RequiredKeepUndefined } from '../../types'; @@ -34,6 +36,7 @@ export const updateExceptionListSchema = t.intersection([ id: t.union([t.string, t.undefined]), // defaults to undefined if not set during decode list_id: t.union([t.string, t.undefined]), // defaults to undefined if not set during decode meta, // defaults to undefined if not set during decode + namespace_type, // defaults to 'single' if not set during decode tags, // defaults to empty array if not set during decode }) ), @@ -46,8 +49,9 @@ export type UpdateExceptionListSchema = RequiredKeepUndefined< // This type is used after a decode since the arrays turn into defaults of empty arrays. export type UpdateExceptionListSchemaDecoded = Identity< - Omit & { + Omit & { _tags: _Tags; tags: Tags; + namespace_type: NamespaceType; } >; diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.ts index 15e1c92c06d13..ab405c21d9c77 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.ts @@ -20,6 +20,7 @@ import { list_id, metaOrUndefined, name, + namespace_type, tags, tie_breaker_id, updated_at, @@ -41,6 +42,7 @@ export const exceptionListItemSchema = t.exact( list_id, meta: metaOrUndefined, name, + namespace_type, tags, tie_breaker_id, type: exceptionListItemType, diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts index 1940d94597dec..120ed31f87d0d 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.ts @@ -18,6 +18,7 @@ import { list_id, metaOrUndefined, name, + namespace_type, tags, tie_breaker_id, updated_at, @@ -35,6 +36,7 @@ export const exceptionListSchema = t.exact( list_id, meta: metaOrUndefined, name, + namespace_type, tags, tie_breaker_id, type: exceptionListType, diff --git a/x-pack/plugins/lists/common/schemas/response/found_list_item_schema.ts b/x-pack/plugins/lists/common/schemas/response/found_list_item_schema.ts new file mode 100644 index 0000000000000..f792774cd0c12 --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/response/found_list_item_schema.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable @typescript-eslint/camelcase */ + +import * as t from 'io-ts'; + +import { cursor, page, per_page, total } from '../common/schemas'; + +import { listItemSchema } from './list_item_schema'; + +export const foundListItemSchema = t.exact( + t.type({ + cursor, + data: t.array(listItemSchema), + page, + per_page, + total, + }) +); + +export type FoundListItemSchema = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/response/found_list_schema.ts b/x-pack/plugins/lists/common/schemas/response/found_list_schema.ts new file mode 100644 index 0000000000000..aaf4a721d050d --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/response/found_list_schema.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable @typescript-eslint/camelcase */ + +import * as t from 'io-ts'; + +import { cursor, page, per_page, total } from '../common/schemas'; + +import { listSchema } from './list_schema'; + +export const foundListSchema = t.exact( + t.type({ + cursor, + data: t.array(listSchema), + page, + per_page, + total, + }) +); + +export type FoundListSchema = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/response/index.ts b/x-pack/plugins/lists/common/schemas/response/index.ts index 213685d1183bd..fb6f17a896ddb 100644 --- a/x-pack/plugins/lists/common/schemas/response/index.ts +++ b/x-pack/plugins/lists/common/schemas/response/index.ts @@ -4,11 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './list_item_schema'; -export * from './list_schema'; export * from './acknowledge_schema'; -export * from './list_item_index_exist_schema'; export * from './exception_list_schema'; +export * from './exception_list_item_schema'; export * from './found_exception_list_item_schema'; export * from './found_exception_list_schema'; -export * from './exception_list_item_schema'; +export * from './found_list_item_schema'; +export * from './found_list_schema'; +export * from './list_item_schema'; +export * from './list_schema'; +export * from './list_item_index_exist_schema'; diff --git a/x-pack/plugins/lists/common/schemas/response/list_schema.ts b/x-pack/plugins/lists/common/schemas/response/list_schema.ts index cad449766ceb4..4e664685db9c7 100644 --- a/x-pack/plugins/lists/common/schemas/response/list_schema.ts +++ b/x-pack/plugins/lists/common/schemas/response/list_schema.ts @@ -37,3 +37,6 @@ export const listSchema = t.exact( ); export type ListSchema = t.TypeOf; + +export const listArraySchema = t.array(listSchema); +export type ListArraySchema = t.TypeOf; diff --git a/x-pack/plugins/lists/common/schemas/types/default_namespace.ts b/x-pack/plugins/lists/common/schemas/types/default_namespace.ts new file mode 100644 index 0000000000000..ebe2cd60cf6c8 --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/types/default_namespace.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as t from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; + +const namespaceType = t.keyof({ agnostic: null, single: null }); + +type NamespaceType = t.TypeOf; + +export type DefaultNamespaceC = t.Type; + +/** + * Types the DefaultNamespace as: + * - If null or undefined, then a default string/enumeration of "single" will be used. + */ +export const DefaultNamespace: DefaultNamespaceC = new t.Type< + NamespaceType, + NamespaceType, + unknown +>( + 'DefaultNamespace', + namespaceType.is, + (input): Either => + input == null ? t.success('single') : namespaceType.decode(input), + t.identity +); diff --git a/x-pack/plugins/lists/common/schemas/types/string_to_positive_number.ts b/x-pack/plugins/lists/common/schemas/types/string_to_positive_number.ts new file mode 100644 index 0000000000000..4b62d6c11d801 --- /dev/null +++ b/x-pack/plugins/lists/common/schemas/types/string_to_positive_number.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as t from 'io-ts'; +import { Either, either } from 'fp-ts/lib/Either'; + +export type StringToPositiveNumberC = t.Type; + +/** + * Types the StrongToPositiveNumber as: + * - If a string this converts the string into a number + * - Ensures it is a number (and not NaN) + * - Ensures it is positive number + */ +export const StringToPositiveNumber: StringToPositiveNumberC = new t.Type( + 'StringToPositiveNumber', + t.number.is, + (input, context): Either => { + return either.chain( + t.string.validate(input, context), + (numberAsString): Either => { + const stringAsNumber = +numberAsString; + if (numberAsString.trim().length === 0 || isNaN(stringAsNumber) || stringAsNumber <= 0) { + return t.failure(input, context); + } else { + return t.success(stringAsNumber); + } + } + ); + }, + String +); diff --git a/x-pack/plugins/lists/public/exceptions/api.test.ts b/x-pack/plugins/lists/public/exceptions/api.test.ts index cc172ee1e6109..3a61140e5621d 100644 --- a/x-pack/plugins/lists/public/exceptions/api.test.ts +++ b/x-pack/plugins/lists/public/exceptions/api.test.ts @@ -68,7 +68,7 @@ describe('Exceptions Lists API', () => { }); expect(fetchMock).toHaveBeenCalledWith('/api/exception_lists', { body: - '{"_tags":["endpoint","process","malware","os:linux"],"created_at":"2020-04-23T00:19:13.289Z","created_by":"user_name","description":"This is a sample endpoint type exception","id":"1","list_id":"endpoint_list","meta":{},"name":"Sample Endpoint Exception List","tags":["user added string for a tag","malware"],"tie_breaker_id":"77fd1909-6786-428a-a671-30229a719c1f","type":"endpoint","updated_at":"2020-04-23T00:19:13.289Z","updated_by":"user_name"}', + '{"_tags":["endpoint","process","malware","os:linux"],"created_at":"2020-04-23T00:19:13.289Z","created_by":"user_name","description":"This is a sample endpoint type exception","id":"1","list_id":"endpoint_list","meta":{},"name":"Sample Endpoint Exception List","namespace_type":"single","tags":["user added string for a tag","malware"],"tie_breaker_id":"77fd1909-6786-428a-a671-30229a719c1f","type":"endpoint","updated_at":"2020-04-23T00:19:13.289Z","updated_by":"user_name"}', method: 'PUT', signal: abortCtrl.signal, }); @@ -112,7 +112,7 @@ describe('Exceptions Lists API', () => { }); expect(fetchMock).toHaveBeenCalledWith('/api/exception_lists/items', { body: - '{"_tags":["endpoint","process","malware","os:linux"],"comment":[],"created_at":"2020-04-23T00:19:13.289Z","created_by":"user_name","description":"This is a sample endpoint type exception","entries":[{"field":"actingProcess.file.signer","match":"Elastic, N.V.","operator":"included"},{"field":"event.category","match_any":["process","malware"],"operator":"included"}],"id":"1","item_id":"endpoint_list_item","list_id":"endpoint_list","meta":{},"name":"Sample Endpoint Exception List","tags":["user added string for a tag","malware"],"tie_breaker_id":"77fd1909-6786-428a-a671-30229a719c1f","type":"simple","updated_at":"2020-04-23T00:19:13.289Z","updated_by":"user_name"}', + '{"_tags":["endpoint","process","malware","os:linux"],"comment":[],"created_at":"2020-04-23T00:19:13.289Z","created_by":"user_name","description":"This is a sample endpoint type exception","entries":[{"field":"actingProcess.file.signer","match":"Elastic, N.V.","operator":"included"},{"field":"event.category","match_any":["process","malware"],"operator":"included"}],"id":"1","item_id":"endpoint_list_item","list_id":"endpoint_list","meta":{},"name":"Sample Endpoint Exception List","namespace_type":"single","tags":["user added string for a tag","malware"],"tie_breaker_id":"77fd1909-6786-428a-a671-30229a719c1f","type":"simple","updated_at":"2020-04-23T00:19:13.289Z","updated_by":"user_name"}', method: 'PUT', signal: abortCtrl.signal, }); diff --git a/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.tsx b/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.tsx index a4390ac07a5a0..308d1cf4d1b17 100644 --- a/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.tsx +++ b/x-pack/plugins/lists/public/exceptions/hooks/use_exception_list.test.tsx @@ -69,6 +69,7 @@ describe('useExceptionList', () => { list_id: 'endpoint_list', meta: {}, name: 'Sample Endpoint Exception List', + namespace_type: 'single', tags: ['user added string for a tag', 'malware'], tie_breaker_id: '77fd1909-6786-428a-a671-30229a719c1f', type: 'simple', @@ -84,6 +85,7 @@ describe('useExceptionList', () => { list_id: 'endpoint_list', meta: {}, name: 'Sample Endpoint Exception List', + namespace_type: 'single', tags: ['user added string for a tag', 'malware'], tie_breaker_id: '77fd1909-6786-428a-a671-30229a719c1f', type: 'endpoint', diff --git a/x-pack/plugins/lists/public/exceptions/mock.ts b/x-pack/plugins/lists/public/exceptions/mock.ts index 6980051238973..38a0e65992982 100644 --- a/x-pack/plugins/lists/public/exceptions/mock.ts +++ b/x-pack/plugins/lists/public/exceptions/mock.ts @@ -19,6 +19,7 @@ export const mockExceptionList: ExceptionListSchema = { list_id: 'endpoint_list', meta: {}, name: 'Sample Endpoint Exception List', + namespace_type: 'single', tags: ['user added string for a tag', 'malware'], tie_breaker_id: '77fd1909-6786-428a-a671-30229a719c1f', type: 'endpoint', @@ -84,6 +85,7 @@ export const mockExceptionItem: ExceptionListItemSchema = { list_id: 'endpoint_list', meta: {}, name: 'Sample Endpoint Exception List', + namespace_type: 'single', tags: ['user added string for a tag', 'malware'], tie_breaker_id: '77fd1909-6786-428a-a671-30229a719c1f', type: 'simple', diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts index ddcae137a961a..e914d816b5e91 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts @@ -39,6 +39,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => { const siemResponse = buildSiemResponse(response); try { const { + namespace_type: namespaceType, name, _tags, tags, @@ -54,8 +55,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => { const exceptionList = await exceptionLists.getExceptionList({ id: undefined, listId, - // TODO: Expose the name space type - namespaceType: 'single', + namespaceType, }); if (exceptionList == null) { return siemResponse.error({ @@ -66,8 +66,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => { const exceptionListItem = await exceptionLists.getExceptionListItem({ id: undefined, itemId, - // TODO: Expose the name space type - namespaceType: 'single', + namespaceType, }); if (exceptionListItem != null) { return siemResponse.error({ @@ -84,8 +83,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => { listId, meta, name, - // TODO: Expose the name space type - namespaceType: 'single', + namespaceType, tags, type, }); diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts index c8a1b080c16f6..9be6b72dcd255 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts @@ -38,13 +38,21 @@ export const createExceptionListRoute = (router: IRouter): void => { async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { name, _tags, tags, meta, description, list_id: listId, type } = request.body; + const { + name, + _tags, + tags, + meta, + namespace_type: namespaceType, + description, + list_id: listId, + type, + } = request.body; const exceptionLists = getExceptionListClient(context); const exceptionList = await exceptionLists.getExceptionList({ id: undefined, listId, - // TODO: Expose the name space type - namespaceType: 'single', + namespaceType, }); if (exceptionList != null) { return siemResponse.error({ @@ -58,8 +66,7 @@ export const createExceptionListRoute = (router: IRouter): void => { listId, meta, name, - // TODO: Expose the name space type - namespaceType: 'single', + namespaceType, tags, type, }); diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts index e10ffab5359b0..2c91fe3c28681 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts @@ -13,7 +13,11 @@ import { transformError, validate, } from '../siem_server_deps'; -import { deleteExceptionListItemSchema, exceptionListItemSchema } from '../../common/schemas'; +import { + DeleteExceptionListItemSchemaDecoded, + deleteExceptionListItemSchema, + exceptionListItemSchema, +} from '../../common/schemas'; import { getErrorMessageExceptionListItem, getExceptionListClient } from './utils'; @@ -25,14 +29,17 @@ export const deleteExceptionListItemRoute = (router: IRouter): void => { }, path: EXCEPTION_LIST_ITEM_URL, validate: { - query: buildRouteValidation(deleteExceptionListItemSchema), + query: buildRouteValidation< + typeof deleteExceptionListItemSchema, + DeleteExceptionListItemSchemaDecoded + >(deleteExceptionListItemSchema), }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { const exceptionLists = getExceptionListClient(context); - const { item_id: itemId, id } = request.query; + const { item_id: itemId, id, namespace_type: namespaceType } = request.query; if (itemId == null && id == null) { return siemResponse.error({ body: 'Either "item_id" or "id" needs to be defined in the request', @@ -42,7 +49,7 @@ export const deleteExceptionListItemRoute = (router: IRouter): void => { const deleted = await exceptionLists.deleteExceptionListItem({ id, itemId, - namespaceType: 'single', // TODO: Bubble this up + namespaceType, }); if (deleted == null) { return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts index ef30ab6ab64c5..b4c67c0ab1418 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts @@ -13,7 +13,11 @@ import { transformError, validate, } from '../siem_server_deps'; -import { deleteExceptionListSchema, exceptionListSchema } from '../../common/schemas'; +import { + DeleteExceptionListSchemaDecoded, + deleteExceptionListSchema, + exceptionListSchema, +} from '../../common/schemas'; import { getErrorMessageExceptionList, getExceptionListClient } from './utils'; @@ -25,25 +29,27 @@ export const deleteExceptionListRoute = (router: IRouter): void => { }, path: EXCEPTION_LIST_URL, validate: { - query: buildRouteValidation(deleteExceptionListSchema), + query: buildRouteValidation< + typeof deleteExceptionListSchema, + DeleteExceptionListSchemaDecoded + >(deleteExceptionListSchema), }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { const exceptionLists = getExceptionListClient(context); - const { list_id: listId, id } = request.query; + const { list_id: listId, id, namespace_type: namespaceType } = request.query; if (listId == null && id == null) { return siemResponse.error({ body: 'Either "list_id" or "id" needs to be defined in the request', statusCode: 400, }); } else { - // TODO: At the moment this will delete the list but we need to delete all the list items before deleting the list const deleted = await exceptionLists.deleteExceptionList({ id, listId, - namespaceType: 'single', + namespaceType, }); if (deleted == null) { return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts index 3b5503ffb9833..1820ffdeadb88 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts @@ -13,7 +13,11 @@ import { transformError, validate, } from '../siem_server_deps'; -import { findExceptionListItemSchema, foundExceptionListItemSchema } from '../../common/schemas'; +import { + FindExceptionListItemSchemaDecoded, + findExceptionListItemSchema, + foundExceptionListItemSchema, +} from '../../common/schemas'; import { getExceptionListClient } from './utils'; @@ -25,7 +29,10 @@ export const findExceptionListItemRoute = (router: IRouter): void => { }, path: `${EXCEPTION_LIST_ITEM_URL}/_find`, validate: { - query: buildRouteValidation(findExceptionListItemSchema), + query: buildRouteValidation< + typeof findExceptionListItemSchema, + FindExceptionListItemSchemaDecoded + >(findExceptionListItemSchema), }, }, async (context, request, response) => { @@ -35,6 +42,7 @@ export const findExceptionListItemRoute = (router: IRouter): void => { const { filter, list_id: listId, + namespace_type: namespaceType, page, per_page: perPage, sort_field: sortField, @@ -43,7 +51,7 @@ export const findExceptionListItemRoute = (router: IRouter): void => { const exceptionListItems = await exceptionLists.findExceptionListItem({ filter, listId, - namespaceType: 'single', // TODO: Bubble this up + namespaceType, page, perPage, sortField, diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts index 41c0c0760e03b..3181deda8b91d 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts @@ -13,7 +13,11 @@ import { transformError, validate, } from '../siem_server_deps'; -import { findExceptionListSchema, foundExceptionListSchema } from '../../common/schemas'; +import { + FindExceptionListSchemaDecoded, + findExceptionListSchema, + foundExceptionListSchema, +} from '../../common/schemas'; import { getExceptionListClient } from './utils'; @@ -25,7 +29,9 @@ export const findExceptionListRoute = (router: IRouter): void => { }, path: `${EXCEPTION_LIST_URL}/_find`, validate: { - query: buildRouteValidation(findExceptionListSchema), + query: buildRouteValidation( + findExceptionListSchema + ), }, }, async (context, request, response) => { @@ -35,13 +41,14 @@ export const findExceptionListRoute = (router: IRouter): void => { const { filter, page, + namespace_type: namespaceType, per_page: perPage, sort_field: sortField, sort_order: sortOrder, } = request.query; const exceptionListItems = await exceptionLists.findExceptionList({ filter, - namespaceType: 'single', // TODO: Bubble this up + namespaceType, page, perPage, sortField, diff --git a/x-pack/plugins/lists/server/routes/find_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_list_item_route.ts new file mode 100644 index 0000000000000..37b5fe44b919c --- /dev/null +++ b/x-pack/plugins/lists/server/routes/find_list_item_route.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from 'kibana/server'; + +import { LIST_ITEM_URL } from '../../common/constants'; +import { + buildRouteValidation, + buildSiemResponse, + transformError, + validate, +} from '../siem_server_deps'; +import { findListItemSchema, foundListItemSchema } from '../../common/schemas'; +import { decodeCursor } from '../services/utils'; + +import { getListClient } from './utils'; + +export const findListItemRoute = (router: IRouter): void => { + router.get( + { + options: { + tags: ['access:lists'], + }, + path: `${LIST_ITEM_URL}/_find`, + validate: { + query: buildRouteValidation(findListItemSchema), + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + const lists = getListClient(context); + const { + cursor, + filter: filterOrUndefined, + list_id: listId, + page: pageOrUndefined, + per_page: perPageOrUndefined, + sort_field: sortField, + sort_order: sortOrder, + } = request.query; + + const page = pageOrUndefined ?? 1; + const perPage = perPageOrUndefined ?? 20; + const filter = filterOrUndefined ?? ''; + const { + isValid, + errorMessage, + cursor: [currentIndexPosition, searchAfter], + } = decodeCursor({ + cursor, + page, + perPage, + sortField, + }); + + if (!isValid) { + return siemResponse.error({ + body: errorMessage, + statusCode: 400, + }); + } else { + const exceptionList = await lists.findListItem({ + currentIndexPosition, + filter, + listId, + page, + perPage, + searchAfter, + sortField, + sortOrder, + }); + if (exceptionList == null) { + return siemResponse.error({ + body: `list id: "${listId}" does not exist`, + statusCode: 404, + }); + } else { + const [validated, errors] = validate(exceptionList, foundListItemSchema); + if (errors != null) { + return siemResponse.error({ body: errors, statusCode: 500 }); + } else { + return response.ok({ body: validated ?? {} }); + } + } + } + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/lists/server/routes/find_list_route.ts b/x-pack/plugins/lists/server/routes/find_list_route.ts new file mode 100644 index 0000000000000..04b33e3d67075 --- /dev/null +++ b/x-pack/plugins/lists/server/routes/find_list_route.ts @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from 'kibana/server'; + +import { LIST_URL } from '../../common/constants'; +import { + buildRouteValidation, + buildSiemResponse, + transformError, + validate, +} from '../siem_server_deps'; +import { findListSchema, foundListSchema } from '../../common/schemas'; +import { decodeCursor } from '../services/utils'; + +import { getListClient } from './utils'; + +export const findListRoute = (router: IRouter): void => { + router.get( + { + options: { + tags: ['access:lists'], + }, + path: `${LIST_URL}/_find`, + validate: { + query: buildRouteValidation(findListSchema), + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + const lists = getListClient(context); + const { + cursor, + filter: filterOrUndefined, + page: pageOrUndefined, + per_page: perPageOrUndefined, + sort_field: sortField, + sort_order: sortOrder, + } = request.query; + + const page = pageOrUndefined ?? 1; + const perPage = perPageOrUndefined ?? 20; + const filter = filterOrUndefined ?? ''; + const { + isValid, + errorMessage, + cursor: [currentIndexPosition, searchAfter], + } = decodeCursor({ + cursor, + page, + perPage, + sortField, + }); + if (!isValid) { + return siemResponse.error({ + body: errorMessage, + statusCode: 400, + }); + } else { + const exceptionList = await lists.findList({ + currentIndexPosition, + filter, + page, + perPage, + searchAfter, + sortField, + sortOrder, + }); + const [validated, errors] = validate(exceptionList, foundListSchema); + if (errors != null) { + return siemResponse.error({ body: errors, statusCode: 500 }); + } else { + return response.ok({ body: validated ?? {} }); + } + } + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/lists/server/routes/index.ts b/x-pack/plugins/lists/server/routes/index.ts index 97f497bca7183..72117c46213fe 100644 --- a/x-pack/plugins/lists/server/routes/index.ts +++ b/x-pack/plugins/lists/server/routes/index.ts @@ -17,6 +17,8 @@ export * from './delete_list_route'; export * from './export_list_item_route'; export * from './find_exception_list_item_route'; export * from './find_exception_list_route'; +export * from './find_list_item_route'; +export * from './find_list_route'; export * from './import_list_item_route'; export * from './init_routes'; export * from './patch_list_item_route'; diff --git a/x-pack/plugins/lists/server/routes/init_routes.ts b/x-pack/plugins/lists/server/routes/init_routes.ts index 16f96d99505d8..e74fa471734b0 100644 --- a/x-pack/plugins/lists/server/routes/init_routes.ts +++ b/x-pack/plugins/lists/server/routes/init_routes.ts @@ -20,6 +20,8 @@ import { exportListItemRoute, findExceptionListItemRoute, findExceptionListRoute, + findListItemRoute, + findListRoute, importListItemRoute, patchListItemRoute, patchListRoute, @@ -41,6 +43,7 @@ export const initRoutes = (router: IRouter): void => { updateListRoute(router); deleteListRoute(router); patchListRoute(router); + findListRoute(router); // list items createListItemRoute(router); @@ -50,6 +53,7 @@ export const initRoutes = (router: IRouter): void => { patchListItemRoute(router); exportListItemRoute(router); importListItemRoute(router); + findListItemRoute(router); // indexes of lists createListIndexRoute(router); diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts index 77d37373549c7..083d4d7a0d479 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts @@ -13,7 +13,11 @@ import { transformError, validate, } from '../siem_server_deps'; -import { exceptionListItemSchema, readExceptionListItemSchema } from '../../common/schemas'; +import { + ReadExceptionListItemSchemaDecoded, + exceptionListItemSchema, + readExceptionListItemSchema, +} from '../../common/schemas'; import { getErrorMessageExceptionListItem, getExceptionListClient } from './utils'; @@ -25,20 +29,22 @@ export const readExceptionListItemRoute = (router: IRouter): void => { }, path: EXCEPTION_LIST_ITEM_URL, validate: { - query: buildRouteValidation(readExceptionListItemSchema), + query: buildRouteValidation< + typeof readExceptionListItemSchema, + ReadExceptionListItemSchemaDecoded + >(readExceptionListItemSchema), }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { id, item_id: itemId } = request.query; + const { id, item_id: itemId, namespace_type: namespaceType } = request.query; const exceptionLists = getExceptionListClient(context); if (id != null || itemId != null) { const exceptionListItem = await exceptionLists.getExceptionListItem({ id, itemId, - // TODO: Bubble this up - namespaceType: 'single', + namespaceType, }); if (exceptionListItem == null) { return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts index 1668124acdfce..c295f045b38c2 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts @@ -13,7 +13,11 @@ import { transformError, validate, } from '../siem_server_deps'; -import { exceptionListSchema, readExceptionListSchema } from '../../common/schemas'; +import { + ReadExceptionListSchemaDecoded, + exceptionListSchema, + readExceptionListSchema, +} from '../../common/schemas'; import { getErrorMessageExceptionList, getExceptionListClient } from './utils'; @@ -25,20 +29,21 @@ export const readExceptionListRoute = (router: IRouter): void => { }, path: EXCEPTION_LIST_URL, validate: { - query: buildRouteValidation(readExceptionListSchema), + query: buildRouteValidation( + readExceptionListSchema + ), }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { id, list_id: listId } = request.query; + const { id, list_id: listId, namespace_type: namespaceType } = request.query; const exceptionLists = getExceptionListClient(context); if (id != null || listId != null) { const exceptionList = await exceptionLists.getExceptionList({ id, listId, - // TODO: Bubble this up - namespaceType: 'single', + namespaceType, }); if (exceptionList == null) { return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/read_list_index_route.ts b/x-pack/plugins/lists/server/routes/read_list_index_route.ts index 248fc72666d70..21f539d97fc74 100644 --- a/x-pack/plugins/lists/server/routes/read_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_index_route.ts @@ -31,7 +31,7 @@ export const readListIndexRoute = (router: IRouter): void => { if (listIndexExists || listItemIndexExists) { const [validated, errors] = validate( - { list_index: listIndexExists, lists_item_index: listItemIndexExists }, + { list_index: listIndexExists, list_item_index: listItemIndexExists }, listItemIndexExistSchema ); if (errors != null) { diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts index 478225ee35eb8..14b97bbe15206 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts @@ -48,6 +48,7 @@ export const updateExceptionListItemRoute = (router: IRouter): void => { comment, entries, item_id: itemId, + namespace_type: namespaceType, tags, } = request.body; const exceptionLists = getExceptionListClient(context); @@ -60,7 +61,7 @@ export const updateExceptionListItemRoute = (router: IRouter): void => { itemId, meta, name, - namespaceType: 'single', // TODO: Bubble this up + namespaceType, tags, type, }); diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index a112c7422b952..fe45d403c040f 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -38,7 +38,17 @@ export const updateExceptionListRoute = (router: IRouter): void => { async (context, request, response) => { const siemResponse = buildSiemResponse(response); try { - const { _tags, tags, name, description, id, list_id: listId, meta, type } = request.body; + const { + _tags, + tags, + name, + description, + id, + list_id: listId, + meta, + namespace_type: namespaceType, + type, + } = request.body; const exceptionLists = getExceptionListClient(context); if (id == null && listId == null) { return siemResponse.error({ @@ -53,7 +63,7 @@ export const updateExceptionListRoute = (router: IRouter): void => { listId, meta, name, - namespaceType: 'single', // TODO: Bubble this up + namespaceType, tags, type, }); diff --git a/x-pack/plugins/lists/server/scripts/delete_all_lists.sh b/x-pack/plugins/lists/server/scripts/delete_all_lists.sh deleted file mode 100755 index 5b65bb14414c7..0000000000000 --- a/x-pack/plugins/lists/server/scripts/delete_all_lists.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# -# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -# or more contributor license agreements. Licensed under the Elastic License; -# you may not use this file except in compliance with the Elastic License. -# - -set -e -./check_env_variables.sh - -# Example: ./delete_all_lists.sh -# https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html - - -# Delete all the main lists that have children items -curl -s -k \ - -H "Content-Type: application/json" \ - -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X POST ${ELASTICSEARCH_URL}/${KIBANA_INDEX}*/_delete_by_query \ - --data '{ - "query": { - "exists": { "field": "siem_list" } - } - }' \ - | jq . - -# Delete all the list children items as well -curl -s -k \ - -H "Content-Type: application/json" \ - -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X POST ${ELASTICSEARCH_URL}/${KIBANA_INDEX}*/_delete_by_query \ - --data '{ - "query": { - "exists": { "field": "siem_list_item" } - } - }' \ - | jq . diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list.sh b/x-pack/plugins/lists/server/scripts/delete_exception_list.sh index fe2ca501b4416..efdb6d03db60b 100755 --- a/x-pack/plugins/lists/server/scripts/delete_exception_list.sh +++ b/x-pack/plugins/lists/server/scripts/delete_exception_list.sh @@ -9,8 +9,12 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./delete_exception_list.sh ${list_id} +# Example: ./delete_exception_list.sh ${list_id} single +# Example: ./delete_exception_list.sh ${list_id} agnostic curl -s -k \ -H 'kbn-xsrf: 123' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X DELETE ${KIBANA_URL}${SPACE_URL}/api/exception_lists?list_id="$1" | jq . + -X DELETE "${KIBANA_URL}${SPACE_URL}/api/exception_lists?list_id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list_by_id.sh b/x-pack/plugins/lists/server/scripts/delete_exception_list_by_id.sh index a87881b385328..2eb4f93d93015 100755 --- a/x-pack/plugins/lists/server/scripts/delete_exception_list_by_id.sh +++ b/x-pack/plugins/lists/server/scripts/delete_exception_list_by_id.sh @@ -9,8 +9,12 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./delete_exception_list_by_id.sh ${list_id} +# Example: ./delete_exception_list_by_id.sh ${list_id} single +# Example: ./delete_exception_list_by_id.sh ${list_id} agnostic curl -s -k \ -H 'kbn-xsrf: 123' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X DELETE ${KIBANA_URL}${SPACE_URL}/api/exception_lists?id="$1" | jq . + -X DELETE "${KIBANA_URL}${SPACE_URL}/api/exception_lists?id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list_item.sh b/x-pack/plugins/lists/server/scripts/delete_exception_list_item.sh index 7e09452a23e11..7617b4c47b1bc 100755 --- a/x-pack/plugins/lists/server/scripts/delete_exception_list_item.sh +++ b/x-pack/plugins/lists/server/scripts/delete_exception_list_item.sh @@ -9,8 +9,12 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./delete_exception_list_item.sh ${item_id} +# Example: ./delete_exception_list_item.sh ${item_id} single +# Example: ./delete_exception_list_item.sh ${item_id} agnostic curl -s -k \ -H 'kbn-xsrf: 123' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X DELETE ${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?item_id="$1" | jq . + -X DELETE "${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?item_id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh b/x-pack/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh index bbfbc3135ddb8..0e18004909222 100755 --- a/x-pack/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh +++ b/x-pack/plugins/lists/server/scripts/delete_exception_list_item_by_id.sh @@ -9,8 +9,12 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./delete_exception_list_item_by_id.sh ${list_id} +# Example: ./delete_exception_list_item_by_id.sh ${list_id} single +# Example: ./delete_exception_list_item_by_id.sh ${list_id} agnostic curl -s -k \ -H 'kbn-xsrf: 123' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X DELETE ${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?id="$1" | jq . + -X DELETE "${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/delete_list.sh b/x-pack/plugins/lists/server/scripts/delete_list.sh index ce9fdd6aa21d4..95aa8eddbdf8d 100755 --- a/x-pack/plugins/lists/server/scripts/delete_list.sh +++ b/x-pack/plugins/lists/server/scripts/delete_list.sh @@ -13,4 +13,4 @@ set -e curl -s -k \ -H 'kbn-xsrf: 123' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X DELETE ${KIBANA_URL}${SPACE_URL}/api/lists?id="$1" | jq . + -X DELETE "${KIBANA_URL}${SPACE_URL}/api/lists?id=$1" | jq . diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json b/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json new file mode 100644 index 0000000000000..4121b13880660 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_agnostic.json @@ -0,0 +1,9 @@ +{ + "list_id": "endpoint_list", + "_tags": ["endpoint", "process", "malware", "os:linux"], + "tags": ["user added string for a tag", "malware"], + "type": "endpoint", + "description": "This is a sample agnostic endpoint type exception", + "name": "Sample Endpoint Exception List", + "namespace_type": "agnostic" +} diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json b/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json new file mode 100644 index 0000000000000..db0b11480b81a --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/exception_lists/new/exception_list_item_agnostic.json @@ -0,0 +1,22 @@ +{ + "list_id": "endpoint_list", + "item_id": "endpoint_list_item", + "_tags": ["endpoint", "process", "malware", "os:linux"], + "tags": ["user added string for a tag", "malware"], + "type": "simple", + "description": "This is a sample agnostic endpoint type exception", + "name": "Sample Endpoint Exception List", + "namespace_type": "agnostic", + "entries": [ + { + "field": "actingProcess.file.signer", + "operator": "included", + "match": "Elastic, N.V." + }, + { + "field": "event.category", + "operator": "included", + "match_any": ["process", "malware"] + } + ] +} diff --git a/x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json b/x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json new file mode 100644 index 0000000000000..72ddd15ebee47 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/exception_lists/updates/simple_update_agnostic.json @@ -0,0 +1,16 @@ +{ + "item_id": "endpoint_list_item", + "_tags": ["endpoint", "process", "malware", "os:windows"], + "tags": ["user added string for a tag", "malware"], + "type": "simple", + "description": "This is a sample agnostic change here this list", + "name": "Sample Endpoint Exception List update change", + "namespace_type": "agnostic", + "entries": [ + { + "field": "event.category", + "operator": "included", + "match_any": ["process", "malware"] + } + ] +} diff --git a/x-pack/plugins/lists/server/scripts/find_exception_list_items.sh b/x-pack/plugins/lists/server/scripts/find_exception_list_items.sh index 85c5b0e518fab..e3f21da56d1b7 100755 --- a/x-pack/plugins/lists/server/scripts/find_exception_list_items.sh +++ b/x-pack/plugins/lists/server/scripts/find_exception_list_items.sh @@ -10,7 +10,11 @@ set -e ./check_env_variables.sh LIST_ID=${1:-endpoint_list} +NAMESPACE_TYPE=${2-single} + # Example: ./find_exception_list_items.sh {list-id} +# Example: ./find_exception_list_items.sh {list-id} single +# Example: ./find_exception_list_items.sh {list-id} agnostic curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/exception_lists/items/_find?list_id=${LIST_ID} | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/items/_find?list_id=${LIST_ID}&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh b/x-pack/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh new file mode 100755 index 0000000000000..57313275ccd0e --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_exception_list_items_by_filter.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +LIST_ID=${1:-endpoint_list} +FILTER=${2:-'exception-list.attributes.name:%20Sample%20Endpoint%20Exception%20List'} +NAMESPACE_TYPE=${3-single} + +# The %20 is just an encoded space that is typical of URL's. +# The %22 is just an encoded quote of " +# Table of them for testing if needed: https://www.w3schools.com/tags/ref_urlencode.asp + +# Example: ./find_exception_list_items_by_filter.sh endpoint_list exception-list.attributes.name:%20Sample%20Endpoint%20Exception%20List +# Example: ./find_exception_list_items_by_filter.sh endpoint_list exception-list.attributes.name:%20Sample%20Endpoint%20Exception%20List single +# Example: ./find_exception_list_items_by_filter.sh endpoint_list exception-list.attributes.name:%20Sample%20Endpoint%20Exception%20List agnostic +# +# Example: ./find_exception_list_items_by_filter.sh endpoint_list exception-list.attributes.entries.field:actingProcess.file.signer +# Example: ./find_exception_list_items_by_filter.sh endpoint_list "exception-list.attributes.entries.field:actingProcess.file.signe*" +# Example: ./find_exception_list_items_by_filter.sh endpoint_list "exception-list.attributes.entries.match:Elastic*%20AND%20exception-list.attributes.entries.field:actingProcess.file.signe*" +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/items/_find?list_id=${LIST_ID}&filter=${FILTER}&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_exception_lists.sh b/x-pack/plugins/lists/server/scripts/find_exception_lists.sh index a1ee184b3e5bb..d3420e53343a3 100755 --- a/x-pack/plugins/lists/server/scripts/find_exception_lists.sh +++ b/x-pack/plugins/lists/server/scripts/find_exception_lists.sh @@ -9,7 +9,11 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${1-single} + # Example: ./find_exception_lists.sh {list-id} +# Example: ./find_exception_lists.sh {list-id} single +# Example: ./find_exception_lists.sh {list-id} agnostic curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/exception_lists/_find | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/_find?namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_exception_lists_by_filter.sh b/x-pack/plugins/lists/server/scripts/find_exception_lists_by_filter.sh new file mode 100755 index 0000000000000..3f5600af76b83 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_exception_lists_by_filter.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +FILTER=${1:-'exception-list.attributes.name:%20Sample%20Endpoint%20Exception%20List'} +NAMESPACE_TYPE=${2-single} + +# The %20 is just an encoded space that is typical of URL's. +# The %22 is just an encoded quote of " +# Table of them for testing if needed: https://www.w3schools.com/tags/ref_urlencode.asp + +# Example get all lists by a particular name: +# ./find_exception_lists_by_filter.sh exception-list.attributes.name:%20Sample%20Endpoint%20Exception%20List +# ./find_exception_lists_by_filter.sh exception-list.attributes.tags:%20malware +# ./find_exception_lists_by_filter.sh exception-list.attributes.tags:%20malware single +# ./find_exception_lists_by_filter.sh exception-list.attributes.tags:%20malware agnostic +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/_find?filter=${FILTER}&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_list_items.sh b/x-pack/plugins/lists/server/scripts/find_list_items.sh new file mode 100755 index 0000000000000..c4a610e313fa8 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_list_items.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +LIST_ID=${3-list-ip} + +# Example: ./find_list_items.sh 1 20 list-ip +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/items/_find?list_id=${LIST_ID}&page=${PAGE}&per_page=${PER_PAGE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_list_items_with_cursor.sh b/x-pack/plugins/lists/server/scripts/find_list_items_with_cursor.sh new file mode 100755 index 0000000000000..3fd5178b2d9b1 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_list_items_with_cursor.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +LIST_ID=${3-list-ip} +CURSOR=${4-invalid} + +# Example: +# ./find_list_items.sh 1 20 | jq .cursor +# Copy the cursor into the argument below like so +# ./find_list_items_with_cursor.sh 1 10 list-ip eyJwYWdlX2luZGV4IjoyMCwic2VhcmNoX2FmdGVyIjpbIjAyZDZlNGY3LWUzMzAtNGZkYi1iNTY0LTEzZjNiOTk1MjRiYSJdfQ== +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/items/_find?list_id=${LIST_ID}&page=${PAGE}&per_page=${PER_PAGE}&cursor=${CURSOR}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_list_items_with_sort.sh b/x-pack/plugins/lists/server/scripts/find_list_items_with_sort.sh new file mode 100755 index 0000000000000..dcea698be231d --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_list_items_with_sort.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +SORT_FIELD=${3-value} +SORT_ORDER=${4-asc} +LIST_ID=${5-list-ip} + +# Example: ./find_list_items_with_sort.sh 1 20 value asc list-ip +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/items/_find?list_id=${LIST_ID}&page=${PAGE}&per_page=${PER_PAGE}&sort_field=${SORT_FIELD}&sort_order=${SORT_ORDER}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh b/x-pack/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh new file mode 100755 index 0000000000000..07b67a9bd1c5f --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_list_items_with_sort_cursor.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +SORT_FIELD=${3-value} +SORT_ORDER=${4-asc} +LIST_ID=${5-list-ip} +CURSOR=${6-invalid} + +# Example: ./find_list_items_with_sort_cursor.sh 1 20 value asc list-ip +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/items/_find?list_id=${LIST_ID}&page=${PAGE}&per_page=${PER_PAGE}&sort_field=${SORT_FIELD}&sort_order=${SORT_ORDER}&cursor=${CURSOR}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_lists.sh b/x-pack/plugins/lists/server/scripts/find_lists.sh new file mode 100755 index 0000000000000..6ff673c91cad4 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_lists.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} + +# Example: ./find_lists.sh 1 20 +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/_find?page=${PAGE}&per_page=${PER_PAGE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_cursor.sh b/x-pack/plugins/lists/server/scripts/find_lists_with_cursor.sh new file mode 100755 index 0000000000000..a3bff5c37d090 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_lists_with_cursor.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +CURSOR=${3-invalid} + +# Example: +# ./find_lists.sh 1 20 | jq .cursor +# Copy the cursor into the argument below like so +# ./find_lists_with_cursor.sh 1 10 eyJwYWdlX2luZGV4IjoyMCwic2VhcmNoX2FmdGVyIjpbIjAyZDZlNGY3LWUzMzAtNGZkYi1iNTY0LTEzZjNiOTk1MjRiYSJdfQ== +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/_find?page=${PAGE}&per_page=${PER_PAGE}&cursor=${CURSOR}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_filter.sh b/x-pack/plugins/lists/server/scripts/find_lists_with_filter.sh new file mode 100755 index 0000000000000..1919d13fdf793 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_lists_with_filter.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +FILTER=${3-type:ip} +# Example: ./find_lists_with_filter.sh 1 20 type:ip +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/_find?page=${PAGE}&per_page=${PER_PAGE}&filter=${FILTER}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_sort.sh b/x-pack/plugins/lists/server/scripts/find_lists_with_sort.sh new file mode 100755 index 0000000000000..411f3a396cdb3 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_lists_with_sort.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +SORT_FIELD=${3-name} +SORT_ORDER=${4-asc} + +# Example: ./find_lists_with_sort.sh 1 20 name asc +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/_find?page=${PAGE}&per_page=${PER_PAGE}&sort_field=${SORT_FIELD}&sort_order=${SORT_ORDER}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh b/x-pack/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh new file mode 100755 index 0000000000000..c706eb68869ef --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/find_lists_with_sort_cursor.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License; +# you may not use this file except in compliance with the Elastic License. +# + +set -e +./check_env_variables.sh + +PAGE=${1-1} +PER_PAGE=${2-20} +SORT_FIELD=${3-name} +SORT_ORDER=${4-asc} +CURSOR=${5-invalid} + +# Example: ./find_lists_with_sort_cursor.sh 1 20 name asc +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET "${KIBANA_URL}${SPACE_URL}/api/lists/_find?page=${PAGE}&per_page=${PER_PAGE}&sort_field=${SORT_FIELD}&sort_order=${SORT_ORDER}&cursor=${CURSOR}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list.sh b/x-pack/plugins/lists/server/scripts/get_exception_list.sh index 34e6de2576879..9aa15a08dec14 100755 --- a/x-pack/plugins/lists/server/scripts/get_exception_list.sh +++ b/x-pack/plugins/lists/server/scripts/get_exception_list.sh @@ -9,7 +9,10 @@ set -e ./check_env_variables.sh -# Example: ./get_exception_list.sh {id} +NAMESPACE_TYPE=${2-single} + +# Example: ./get_exception_list.sh {id} single +# Example: ./get_exception_list.sh {id} agnostic curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/exception_lists?list_id="$1" | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists?list_id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list_by_id.sh b/x-pack/plugins/lists/server/scripts/get_exception_list_by_id.sh index 0420a1f702328..bcd6721b6fd00 100755 --- a/x-pack/plugins/lists/server/scripts/get_exception_list_by_id.sh +++ b/x-pack/plugins/lists/server/scripts/get_exception_list_by_id.sh @@ -9,7 +9,9 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./get_exception_list_by_id.sh {id} curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/exception_lists?id="$1" | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists?id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list_item.sh b/x-pack/plugins/lists/server/scripts/get_exception_list_item.sh index ac8337aab8368..141bbe60f193f 100755 --- a/x-pack/plugins/lists/server/scripts/get_exception_list_item.sh +++ b/x-pack/plugins/lists/server/scripts/get_exception_list_item.sh @@ -9,7 +9,11 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./get_exception_list_item.sh {id} +# Example: ./get_exception_list_item.sh {id} single +# Example: ./get_exception_list_item.sh {id} agnostic curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?item_id="$1" | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?item_id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/get_exception_list_item_by_id.sh b/x-pack/plugins/lists/server/scripts/get_exception_list_item_by_id.sh index 575a529c69906..97a90c28daebd 100755 --- a/x-pack/plugins/lists/server/scripts/get_exception_list_item_by_id.sh +++ b/x-pack/plugins/lists/server/scripts/get_exception_list_item_by_id.sh @@ -9,7 +9,11 @@ set -e ./check_env_variables.sh +NAMESPACE_TYPE=${2-single} + # Example: ./get_exception_list_item_by_id.sh {id} +# Example: ./get_exception_list_item_by_id.sh {id} single +# Example: ./get_exception_list_item_by_id.sh {id} agnostic curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ - -X GET ${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?id="$1" | jq . + -X GET "${KIBANA_URL}${SPACE_URL}/api/exception_lists/items?id=$1&namespace_type=${NAMESPACE_TYPE}" | jq . diff --git a/x-pack/plugins/lists/server/scripts/lists/new/list_auto_id.json b/x-pack/plugins/lists/server/scripts/lists/new/list_auto_id.json new file mode 100644 index 0000000000000..ef48ba8f67009 --- /dev/null +++ b/x-pack/plugins/lists/server/scripts/lists/new/list_auto_id.json @@ -0,0 +1,5 @@ +{ + "name": "Simple list with a type of ip and an auto created id", + "description": "list with an auto created id", + "type": "ip" +} diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts index 7ba832e72bb8e..c6d4bc006ef0b 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts @@ -15,12 +15,12 @@ import { ListId, MetaOrUndefined, Name, + NamespaceType, Tags, _Tags, } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; -import { NamespaceType } from './types'; interface CreateExceptionListOptions { _tags: _Tags; @@ -68,5 +68,5 @@ export const createExceptionList = async ({ type, updated_by: user, }); - return transformSavedObjectToExceptionList({ savedObject }); + return transformSavedObjectToExceptionList({ namespaceType, savedObject }); }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts index 4a6dc1da97854..44e87ab06f52b 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts @@ -18,12 +18,12 @@ import { ListId, MetaOrUndefined, Name, + NamespaceType, Tags, _Tags, } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectToExceptionListItem } from './utils'; -import { NamespaceType } from './types'; interface CreateExceptionListItemOptions { _tags: _Tags; @@ -77,5 +77,5 @@ export const createExceptionListItem = async ({ type, updated_by: user, }); - return transformSavedObjectToExceptionListItem({ savedObject }); + return transformSavedObjectToExceptionListItem({ namespaceType, savedObject }); }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts index 6904438c8d275..afeed6b5e2cde 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts @@ -6,10 +6,14 @@ import { SavedObjectsClientContract } from 'kibana/server'; -import { ExceptionListSchema, IdOrUndefined, ListIdOrUndefined } from '../../../common/schemas'; +import { + ExceptionListSchema, + IdOrUndefined, + ListIdOrUndefined, + NamespaceType, +} from '../../../common/schemas'; import { getSavedObjectType } from './utils'; -import { NamespaceType } from './types'; import { getExceptionList } from './get_exception_list'; import { deleteExceptionListItemByList } from './delete_exception_list_items_by_list'; diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts index 3b2d991281cd6..8dce1f1f79e35 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts @@ -6,10 +6,14 @@ import { SavedObjectsClientContract } from 'kibana/server'; -import { ExceptionListItemSchema, IdOrUndefined, ItemIdOrUndefined } from '../../../common/schemas'; +import { + ExceptionListItemSchema, + IdOrUndefined, + ItemIdOrUndefined, + NamespaceType, +} from '../../../common/schemas'; import { getSavedObjectType } from './utils'; -import { NamespaceType } from './types'; import { getExceptionListItem } from './get_exception_list_item'; interface DeleteExceptionListItemOptions { diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts index 31bf1ffacbbb2..e835ffae02c9e 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts @@ -5,10 +5,9 @@ */ import { SavedObjectsClientContract } from '../../../../../../src/core/server/'; -import { ListId } from '../../../common/schemas'; +import { ListId, NamespaceType } from '../../../common/schemas'; import { findExceptionListItem } from './find_exception_list_item'; -import { NamespaceType } from './types'; import { getSavedObjectType } from './utils'; const PER_PAGE = 100; diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index 6e71ed1b3e59d..efd117a3c38f4 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -7,6 +7,7 @@ import { SavedObjectsClientContract } from 'kibana/server'; import { + ExceptionListItemSchema, ExceptionListSchema, FoundExceptionListItemSchema, FoundExceptionListSchema, @@ -59,7 +60,7 @@ export class ExceptionListClient { itemId, id, namespaceType, - }: GetExceptionListItemOptions): Promise => { + }: GetExceptionListItemOptions): Promise => { const { savedObjectsClient } = this; return getExceptionListItem({ id, itemId, namespaceType, savedObjectsClient }); }; @@ -142,7 +143,7 @@ export class ExceptionListClient { namespaceType, tags, type, - }: CreateExceptionListItemOptions): Promise => { + }: CreateExceptionListItemOptions): Promise => { const { savedObjectsClient, user } = this; return createExceptionListItem({ _tags, @@ -173,7 +174,7 @@ export class ExceptionListClient { namespaceType, tags, type, - }: UpdateExceptionListItemOptions): Promise => { + }: UpdateExceptionListItemOptions): Promise => { const { savedObjectsClient, user } = this; return updateExceptionListItem({ _tags, @@ -196,7 +197,7 @@ export class ExceptionListClient { id, itemId, namespaceType, - }: DeleteExceptionListItemOptions): Promise => { + }: DeleteExceptionListItemOptions): Promise => { const { savedObjectsClient } = this; return deleteExceptionListItem({ id, diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts index cecd6bf3397a7..0ac543afee9f9 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts @@ -14,6 +14,7 @@ import { EntriesArrayOrUndefined, ExceptionListType, ExceptionListTypeOrUndefined, + FilterOrUndefined, IdOrUndefined, ItemId, ItemIdOrUndefined, @@ -22,14 +23,17 @@ import { MetaOrUndefined, Name, NameOrUndefined, + NamespaceType, + PageOrUndefined, + PerPageOrUndefined, + SortFieldOrUndefined, + SortOrderOrUndefined, Tags, TagsOrUndefined, _Tags, _TagsOrUndefined, } from '../../../common/schemas'; -import { NamespaceType } from './types'; - export interface ConstructorOptions { user: string; savedObjectsClient: SavedObjectsClientContract; @@ -113,18 +117,18 @@ export interface UpdateExceptionListItemOptions { export interface FindExceptionListItemOptions { listId: ListId; namespaceType: NamespaceType; - filter: string | undefined; - perPage: number | undefined; - page: number | undefined; - sortField: string | undefined; - sortOrder: string | undefined; + filter: FilterOrUndefined; + perPage: PerPageOrUndefined; + page: PageOrUndefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; } export interface FindExceptionListOptions { namespaceType: NamespaceType; - filter: string | undefined; - perPage: number | undefined; - page: number | undefined; - sortField: string | undefined; - sortOrder: string | undefined; + filter: FilterOrUndefined; + perPage: PerPageOrUndefined; + page: PageOrUndefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; } diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts index 539dda673208b..6a8fbf3306971 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts @@ -6,20 +6,28 @@ import { SavedObjectsClientContract } from 'kibana/server'; -import { ExceptionListSoSchema, FoundExceptionListSchema } from '../../../common/schemas'; +import { + ExceptionListSoSchema, + FilterOrUndefined, + FoundExceptionListSchema, + NamespaceType, + PageOrUndefined, + PerPageOrUndefined, + SortFieldOrUndefined, + SortOrderOrUndefined, +} from '../../../common/schemas'; import { SavedObjectType } from '../../saved_objects'; import { getSavedObjectType, transformSavedObjectsToFounExceptionList } from './utils'; -import { NamespaceType } from './types'; interface FindExceptionListOptions { namespaceType: NamespaceType; savedObjectsClient: SavedObjectsClientContract; - filter: string | undefined; - perPage: number | undefined; - page: number | undefined; - sortField: string | undefined; - sortOrder: string | undefined; + filter: FilterOrUndefined; + perPage: PerPageOrUndefined; + page: PageOrUndefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; } export const findExceptionList = async ({ @@ -40,14 +48,14 @@ export const findExceptionList = async ({ sortOrder, type: savedObjectType, }); - return transformSavedObjectsToFounExceptionList({ savedObjectsFindResponse }); + return transformSavedObjectsToFounExceptionList({ namespaceType, savedObjectsFindResponse }); }; export const getExceptionListFilter = ({ filter, savedObjectType, }: { - filter: string | undefined; + filter: FilterOrUndefined; savedObjectType: SavedObjectType; }): string => { if (filter == null) { diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item.ts index d635cafbd3b1b..c3b09a5f44b15 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_item.ts @@ -8,24 +8,29 @@ import { SavedObjectsClientContract } from 'kibana/server'; import { ExceptionListSoSchema, + FilterOrUndefined, FoundExceptionListItemSchema, ListId, + NamespaceType, + PageOrUndefined, + PerPageOrUndefined, + SortFieldOrUndefined, + SortOrderOrUndefined, } from '../../../common/schemas'; import { SavedObjectType } from '../../saved_objects'; import { getSavedObjectType, transformSavedObjectsToFounExceptionListItem } from './utils'; -import { NamespaceType } from './types'; import { getExceptionList } from './get_exception_list'; interface FindExceptionListItemOptions { listId: ListId; namespaceType: NamespaceType; savedObjectsClient: SavedObjectsClientContract; - filter: string | undefined; - perPage: number | undefined; - page: number | undefined; - sortField: string | undefined; - sortOrder: string | undefined; + filter: FilterOrUndefined; + perPage: PerPageOrUndefined; + page: PageOrUndefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; } export const findExceptionListItem = async ({ @@ -56,7 +61,10 @@ export const findExceptionListItem = async ({ sortOrder, type: savedObjectType, }); - return transformSavedObjectsToFounExceptionListItem({ savedObjectsFindResponse }); + return transformSavedObjectsToFounExceptionListItem({ + namespaceType, + savedObjectsFindResponse, + }); } }; @@ -66,7 +74,7 @@ export const getExceptionListItemFilter = ({ savedObjectType, }: { listId: ListId; - filter: string | undefined; + filter: FilterOrUndefined; savedObjectType: SavedObjectType; }): string => { if (filter == null) { diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts index 8b28443b4e30c..8f511d140b0ff 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts @@ -13,10 +13,10 @@ import { ExceptionListSoSchema, IdOrUndefined, ListIdOrUndefined, + NamespaceType, } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; -import { NamespaceType } from './types'; interface GetExceptionListOptions { id: IdOrUndefined; @@ -35,7 +35,7 @@ export const getExceptionList = async ({ if (id != null) { try { const savedObject = await savedObjectsClient.get(savedObjectType, id); - return transformSavedObjectToExceptionList({ savedObject }); + return transformSavedObjectToExceptionList({ namespaceType, savedObject }); } catch (err) { if (SavedObjectsErrorHelpers.isNotFoundError(err)) { return null; @@ -54,7 +54,10 @@ export const getExceptionList = async ({ type: savedObjectType, }); if (savedObject.saved_objects[0] != null) { - return transformSavedObjectToExceptionList({ savedObject: savedObject.saved_objects[0] }); + return transformSavedObjectToExceptionList({ + namespaceType, + savedObject: savedObject.saved_objects[0], + }); } else { return null; } diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts index 7ef3e4af3d604..d7efdc054c48c 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts @@ -13,10 +13,10 @@ import { ExceptionListSoSchema, IdOrUndefined, ItemIdOrUndefined, + NamespaceType, } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectToExceptionListItem } from './utils'; -import { NamespaceType } from './types'; interface GetExceptionListItemOptions { id: IdOrUndefined; @@ -35,7 +35,7 @@ export const getExceptionListItem = async ({ if (id != null) { try { const savedObject = await savedObjectsClient.get(savedObjectType, id); - return transformSavedObjectToExceptionListItem({ savedObject }); + return transformSavedObjectToExceptionListItem({ namespaceType, savedObject }); } catch (err) { if (SavedObjectsErrorHelpers.isNotFoundError(err)) { return null; @@ -55,6 +55,7 @@ export const getExceptionListItem = async ({ }); if (savedObject.saved_objects[0] != null) { return transformSavedObjectToExceptionListItem({ + namespaceType, savedObject: savedObject.saved_objects[0], }); } else { diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts index 6c5ccb5e1f2fd..e4d6718ddc29f 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts @@ -15,12 +15,12 @@ import { ListIdOrUndefined, MetaOrUndefined, NameOrUndefined, + NamespaceType, TagsOrUndefined, _TagsOrUndefined, } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectUpdateToExceptionList } from './utils'; -import { NamespaceType } from './types'; import { getExceptionList } from './get_exception_list'; interface UpdateExceptionListOptions { @@ -69,6 +69,6 @@ export const updateExceptionList = async ({ updated_by: user, } ); - return transformSavedObjectUpdateToExceptionList({ exceptionList, savedObject }); + return transformSavedObjectUpdateToExceptionList({ exceptionList, namespaceType, savedObject }); } }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts index 4e955d4281c4d..39c319a944e38 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts @@ -17,12 +17,12 @@ import { ItemIdOrUndefined, MetaOrUndefined, NameOrUndefined, + NamespaceType, TagsOrUndefined, _TagsOrUndefined, } from '../../../common/schemas'; import { getSavedObjectType, transformSavedObjectUpdateToExceptionListItem } from './utils'; -import { NamespaceType } from './types'; import { getExceptionListItem } from './get_exception_list_item'; interface UpdateExceptionListItemOptions { @@ -82,6 +82,10 @@ export const updateExceptionListItem = async ({ updated_by: user, } ); - return transformSavedObjectUpdateToExceptionListItem({ exceptionListItem, savedObject }); + return transformSavedObjectUpdateToExceptionListItem({ + exceptionListItem, + namespaceType, + savedObject, + }); } }; diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils.ts b/x-pack/plugins/lists/server/services/exception_lists/utils.ts index 28dfb9c1cddaf..82a98f4bdd3e2 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils.ts @@ -12,6 +12,7 @@ import { ExceptionListSoSchema, FoundExceptionListItemSchema, FoundExceptionListSchema, + NamespaceType, } from '../../../common/schemas'; import { SavedObjectType, @@ -19,8 +20,6 @@ import { exceptionListSavedObjectType, } from '../../saved_objects'; -import { NamespaceType } from './types'; - export const getSavedObjectType = ({ namespaceType, }: { @@ -35,8 +34,10 @@ export const getSavedObjectType = ({ export const transformSavedObjectToExceptionList = ({ savedObject, + namespaceType, }: { savedObject: SavedObject; + namespaceType: NamespaceType; }): ExceptionListSchema => { const dateNow = new Date().toISOString(); const { @@ -68,6 +69,7 @@ export const transformSavedObjectToExceptionList = ({ list_id, meta, name, + namespace_type: namespaceType, tags, tie_breaker_id, type, @@ -79,9 +81,11 @@ export const transformSavedObjectToExceptionList = ({ export const transformSavedObjectUpdateToExceptionList = ({ exceptionList, savedObject, + namespaceType, }: { exceptionList: ExceptionListSchema; savedObject: SavedObjectsUpdateResponse; + namespaceType: NamespaceType; }): ExceptionListSchema => { const dateNow = new Date().toISOString(); const { @@ -101,6 +105,7 @@ export const transformSavedObjectUpdateToExceptionList = ({ list_id: exceptionList.list_id, meta: meta ?? exceptionList.meta, name: name ?? exceptionList.name, + namespace_type: namespaceType, tags: tags ?? exceptionList.tags, tie_breaker_id: exceptionList.tie_breaker_id, type: type ?? exceptionList.type, @@ -111,8 +116,10 @@ export const transformSavedObjectUpdateToExceptionList = ({ export const transformSavedObjectToExceptionListItem = ({ savedObject, + namespaceType, }: { savedObject: SavedObject; + namespaceType: NamespaceType; }): ExceptionListItemSchema => { const dateNow = new Date().toISOString(); const { @@ -150,6 +157,7 @@ export const transformSavedObjectToExceptionListItem = ({ list_id, meta, name, + namespace_type: namespaceType, tags, tie_breaker_id, type, @@ -161,9 +169,11 @@ export const transformSavedObjectToExceptionListItem = ({ export const transformSavedObjectUpdateToExceptionListItem = ({ exceptionListItem, savedObject, + namespaceType, }: { exceptionListItem: ExceptionListItemSchema; savedObject: SavedObjectsUpdateResponse; + namespaceType: NamespaceType; }): ExceptionListItemSchema => { const dateNow = new Date().toISOString(); const { @@ -196,6 +206,7 @@ export const transformSavedObjectUpdateToExceptionListItem = ({ list_id: exceptionListItem.list_id, meta: meta ?? exceptionListItem.meta, name: name ?? exceptionListItem.name, + namespace_type: namespaceType, tags: tags ?? exceptionListItem.tags, tie_breaker_id: exceptionListItem.tie_breaker_id, type: type ?? exceptionListItem.type, @@ -206,12 +217,14 @@ export const transformSavedObjectUpdateToExceptionListItem = ({ export const transformSavedObjectsToFounExceptionListItem = ({ savedObjectsFindResponse, + namespaceType, }: { savedObjectsFindResponse: SavedObjectsFindResponse; + namespaceType: NamespaceType; }): FoundExceptionListItemSchema => { return { data: savedObjectsFindResponse.saved_objects.map((savedObject) => - transformSavedObjectToExceptionListItem({ savedObject }) + transformSavedObjectToExceptionListItem({ namespaceType, savedObject }) ), page: savedObjectsFindResponse.page, per_page: savedObjectsFindResponse.per_page, @@ -221,12 +234,14 @@ export const transformSavedObjectsToFounExceptionListItem = ({ export const transformSavedObjectsToFounExceptionList = ({ savedObjectsFindResponse, + namespaceType, }: { savedObjectsFindResponse: SavedObjectsFindResponse; + namespaceType: NamespaceType; }): FoundExceptionListSchema => { return { data: savedObjectsFindResponse.saved_objects.map((savedObject) => - transformSavedObjectToExceptionList({ savedObject }) + transformSavedObjectToExceptionList({ namespaceType, savedObject }) ), page: savedObjectsFindResponse.page, per_page: savedObjectsFindResponse.per_page, diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.ts b/x-pack/plugins/lists/server/services/items/create_list_item.ts index 83a118b795192..d46b9b4703fcb 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_item.ts @@ -58,7 +58,7 @@ export const createListItem = async ({ ...transformListItemToElasticQuery({ type, value }), }; - const response: CreateDocumentResponse = await callCluster('index', { + const response = await callCluster('index', { body, id, index: listItemIndex, diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.ts b/x-pack/plugins/lists/server/services/items/find_list_item.ts new file mode 100644 index 0000000000000..d10e6466d03d0 --- /dev/null +++ b/x-pack/plugins/lists/server/services/items/find_list_item.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { APICaller } from 'kibana/server'; + +import { + Filter, + FoundListItemSchema, + ListId, + Page, + PerPage, + SearchEsListItemSchema, + SortFieldOrUndefined, + SortOrderOrUndefined, +} from '../../../common/schemas'; +import { getList } from '../lists'; +import { + encodeCursor, + getQueryFilter, + getSearchAfterWithTieBreaker, + getSortWithTieBreaker, + scrollToStartPage, + transformElasticToListItem, +} from '../utils'; + +interface FindListItemOptions { + listId: ListId; + filter: Filter; + currentIndexPosition: number; + searchAfter: string[] | undefined; + perPage: PerPage; + page: Page; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; + callCluster: APICaller; + listIndex: string; + listItemIndex: string; +} + +export const findListItem = async ({ + callCluster, + currentIndexPosition, + filter, + listId, + page, + perPage, + searchAfter, + sortField: sortFieldWithPossibleValue, + listIndex, + listItemIndex, + sortOrder, +}: FindListItemOptions): Promise => { + const query = getQueryFilter({ filter }); + const list = await getList({ callCluster, id: listId, listIndex }); + if (list == null) { + return null; + } else { + const sortField = + sortFieldWithPossibleValue === 'value' ? list.type : sortFieldWithPossibleValue; + const scroll = await scrollToStartPage({ + callCluster, + currentIndexPosition, + filter, + hopSize: 100, + index: listItemIndex, + page, + perPage, + searchAfter, + sortField, + sortOrder, + }); + + const { count } = await callCluster('count', { + body: { + query, + }, + ignoreUnavailable: true, + index: listItemIndex, + }); + + if (scroll.validSearchAfterFound) { + const response = await callCluster('search', { + body: { + query, + search_after: scroll.searchAfter, + sort: getSortWithTieBreaker({ sortField, sortOrder }), + }, + ignoreUnavailable: true, + index: listItemIndex, + size: perPage, + }); + return { + cursor: encodeCursor({ + page, + perPage, + searchAfter: getSearchAfterWithTieBreaker({ response, sortField }), + }), + data: transformElasticToListItem({ response, type: list.type }), + page, + per_page: perPage, + total: count, + }; + } else { + return { + cursor: encodeCursor({ page, perPage, searchAfter: undefined }), + data: [], + page, + per_page: perPage, + total: count, + }; + } + } +}; diff --git a/x-pack/plugins/lists/server/services/items/get_list_item.ts b/x-pack/plugins/lists/server/services/items/get_list_item.ts index 83b30d336ccd4..296d1e4e82184 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SearchResponse } from 'elasticsearch'; import { APICaller } from 'kibana/server'; import { Id, ListItemSchema, SearchEsListItemSchema } from '../../../common/schemas'; @@ -21,7 +20,7 @@ export const getListItem = async ({ callCluster, listItemIndex, }: GetListItemOptions): Promise => { - const listItemES: SearchResponse = await callCluster('search', { + const listItemES = await callCluster('search', { body: { query: { term: { diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts index 29b9b01754027..cf0ccf3f10aa6 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SearchResponse } from 'elasticsearch'; import { APICaller } from 'kibana/server'; import { ListItemArraySchema, SearchEsListItemSchema, Type } from '../../../common/schemas'; @@ -25,7 +24,7 @@ export const getListItemByValues = async ({ type, value, }: GetListItemByValuesOptions): Promise => { - const response: SearchResponse = await callCluster('search', { + const response = await callCluster('search', { body: { query: { bool: { diff --git a/x-pack/plugins/lists/server/services/items/index.ts b/x-pack/plugins/lists/server/services/items/index.ts index ee1d83fabca31..bc04ba88b943e 100644 --- a/x-pack/plugins/lists/server/services/items/index.ts +++ b/x-pack/plugins/lists/server/services/items/index.ts @@ -8,12 +8,13 @@ export * from './buffer_lines'; export * from './create_list_item'; export * from './create_list_items_bulk'; export * from './delete_list_item_by_value'; +export * from './delete_list_item'; +export * from './find_list_item'; export * from './get_list_item_by_value'; export * from './get_list_item'; export * from './get_list_item_by_values'; +export * from './get_list_item_template'; +export * from './get_list_item_index'; export * from './update_list_item'; export * from './write_lines_to_bulk_list_items'; export * from './write_list_items_to_stream'; -export * from './get_list_item_template'; -export * from './delete_list_item'; -export * from './get_list_item_index'; diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.ts b/x-pack/plugins/lists/server/services/items/update_list_item.ts index 6a71b2a0caf41..6a428b4be854d 100644 --- a/x-pack/plugins/lists/server/services/items/update_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/update_list_item.ts @@ -48,7 +48,7 @@ export const updateListItem = async ({ ...transformListItemToElasticQuery({ type: listItem.type, value: value ?? listItem.value }), }; - const response: CreateDocumentResponse = await callCluster('update', { + const response = await callCluster('update', { body: { doc, }, diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts index 10d8581ccdbc0..f485f557433c6 100644 --- a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts +++ b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts @@ -114,7 +114,7 @@ export const getResponse = async ({ listItemIndex, size = SIZE, }: GetResponseOptions): Promise> => { - return callCluster('search', { + return callCluster('search', { body: { query: { term: { diff --git a/x-pack/plugins/lists/server/services/lists/create_list.ts b/x-pack/plugins/lists/server/services/lists/create_list.ts index ddbc99c88a877..0d2ee606a066d 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list.ts @@ -55,7 +55,7 @@ export const createList = async ({ updated_at: createdAt, updated_by: user, }; - const response: CreateDocumentResponse = await callCluster('index', { + const response = await callCluster('index', { body, id, index: listIndex, diff --git a/x-pack/plugins/lists/server/services/lists/find_list.ts b/x-pack/plugins/lists/server/services/lists/find_list.ts new file mode 100644 index 0000000000000..41dcdfcd0f8db --- /dev/null +++ b/x-pack/plugins/lists/server/services/lists/find_list.ts @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { APICaller } from 'kibana/server'; + +import { + Filter, + FoundListSchema, + Page, + PerPage, + SearchEsListSchema, + SortFieldOrUndefined, + SortOrderOrUndefined, +} from '../../../common/schemas'; +import { + encodeCursor, + getQueryFilter, + getSearchAfterWithTieBreaker, + getSortWithTieBreaker, + scrollToStartPage, + transformElasticToList, +} from '../utils'; + +interface FindListOptions { + filter: Filter; + currentIndexPosition: number; + searchAfter: string[] | undefined; + perPage: PerPage; + page: Page; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; + callCluster: APICaller; + listIndex: string; +} + +export const findList = async ({ + callCluster, + currentIndexPosition, + filter, + page, + perPage, + searchAfter, + sortField, + listIndex, + sortOrder, +}: FindListOptions): Promise => { + const query = getQueryFilter({ filter }); + + const scroll = await scrollToStartPage({ + callCluster, + currentIndexPosition, + filter, + hopSize: 100, + index: listIndex, + page, + perPage, + searchAfter, + sortField, + sortOrder, + }); + + const { count } = await callCluster('count', { + body: { + query, + }, + ignoreUnavailable: true, + index: listIndex, + }); + + if (scroll.validSearchAfterFound) { + const response = await callCluster('search', { + body: { + query, + search_after: scroll.searchAfter, + sort: getSortWithTieBreaker({ sortField, sortOrder }), + }, + ignoreUnavailable: true, + index: listIndex, + size: perPage, + }); + return { + cursor: encodeCursor({ + page, + perPage, + searchAfter: getSearchAfterWithTieBreaker({ response, sortField }), + }), + data: transformElasticToList({ response }), + page, + per_page: perPage, + total: count, + }; + } else { + return { + cursor: encodeCursor({ page, perPage, searchAfter: undefined }), + data: [], + page, + per_page: perPage, + total: count, + }; + } +}; diff --git a/x-pack/plugins/lists/server/services/lists/get_list.ts b/x-pack/plugins/lists/server/services/lists/get_list.ts index c04bd504ad8c0..386232bfeee1f 100644 --- a/x-pack/plugins/lists/server/services/lists/get_list.ts +++ b/x-pack/plugins/lists/server/services/lists/get_list.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SearchResponse } from 'elasticsearch'; import { APICaller } from 'kibana/server'; import { Id, ListSchema, SearchEsListSchema } from '../../../common/schemas'; +import { transformElasticToList } from '../utils/transform_elastic_to_list'; interface GetListOptions { id: Id; @@ -20,7 +20,7 @@ export const getList = async ({ callCluster, listIndex, }: GetListOptions): Promise => { - const result: SearchResponse = await callCluster('search', { + const response = await callCluster('search', { body: { query: { term: { @@ -31,12 +31,6 @@ export const getList = async ({ ignoreUnavailable: true, index: listIndex, }); - if (result.hits.hits.length) { - return { - id: result.hits.hits[0]._id, - ...result.hits.hits[0]._source, - }; - } else { - return null; - } + const list = transformElasticToList({ response }); + return list[0] ?? null; }; diff --git a/x-pack/plugins/lists/server/services/lists/index.ts b/x-pack/plugins/lists/server/services/lists/index.ts index f704ef0b05b82..bafeb929a8d53 100644 --- a/x-pack/plugins/lists/server/services/lists/index.ts +++ b/x-pack/plugins/lists/server/services/lists/index.ts @@ -6,6 +6,7 @@ export * from './create_list'; export * from './delete_list'; +export * from './find_list'; export * from './get_list'; export * from './get_list_template'; export * from './update_list'; diff --git a/x-pack/plugins/lists/server/services/lists/list_client.ts b/x-pack/plugins/lists/server/services/lists/list_client.ts index cba48115c746c..5a7d20c7d64d5 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client.ts @@ -6,11 +6,18 @@ import { APICaller } from 'kibana/server'; -import { ListItemArraySchema, ListItemSchema, ListSchema } from '../../../common/schemas'; +import { + FoundListItemSchema, + FoundListSchema, + ListItemArraySchema, + ListItemSchema, + ListSchema, +} from '../../../common/schemas'; import { ConfigType } from '../../config'; import { createList, deleteList, + findList, getList, getListIndex, getListTemplate, @@ -21,6 +28,7 @@ import { deleteListItem, deleteListItemByValue, exportListItemsToStream, + findListItem, getListItem, getListItemByValue, getListItemByValues, @@ -52,6 +60,8 @@ import { DeleteListItemOptions, DeleteListOptions, ExportListItemsToStreamOptions, + FindListItemOptions, + FindListOptions, GetListItemByValueOptions, GetListItemOptions, GetListItemsByValueOptions, @@ -410,4 +420,56 @@ export class ListClient { value, }); }; + + public findList = async ({ + filter, + currentIndexPosition, + perPage, + page, + sortField, + sortOrder, + searchAfter, + }: FindListOptions): Promise => { + const { callCluster } = this; + const listIndex = this.getListIndex(); + return findList({ + callCluster, + currentIndexPosition, + filter, + listIndex, + page, + perPage, + searchAfter, + sortField, + sortOrder, + }); + }; + + public findListItem = async ({ + listId, + filter, + currentIndexPosition, + perPage, + page, + sortField, + sortOrder, + searchAfter, + }: FindListItemOptions): Promise => { + const { callCluster } = this; + const listIndex = this.getListIndex(); + const listItemIndex = this.getListItemIndex(); + return findListItem({ + callCluster, + currentIndexPosition, + filter, + listId, + listIndex, + listItemIndex, + page, + perPage, + searchAfter, + sortField, + sortOrder, + }); + }; } diff --git a/x-pack/plugins/lists/server/services/lists/list_client_types.ts b/x-pack/plugins/lists/server/services/lists/list_client_types.ts index d66575e7a30db..4171b6ee9f165 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client_types.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client_types.ts @@ -11,11 +11,17 @@ import { APICaller } from 'kibana/server'; import { Description, DescriptionOrUndefined, + Filter, Id, IdOrUndefined, + ListId, MetaOrUndefined, Name, NameOrUndefined, + Page, + PerPage, + SortFieldOrUndefined, + SortOrderOrUndefined, Type, } from '../../../common/schemas'; import { ConfigType } from '../../config'; @@ -110,3 +116,24 @@ export interface GetListItemsByValueOptions { listId: string; value: string[]; } + +export interface FindListOptions { + currentIndexPosition: number; + filter: Filter; + perPage: PerPage; + page: Page; + searchAfter: string[] | undefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; +} + +export interface FindListItemOptions { + currentIndexPosition: number; + filter: Filter; + listId: ListId; + perPage: PerPage; + page: Page; + searchAfter: string[] | undefined; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; +} diff --git a/x-pack/plugins/lists/server/services/exception_lists/types.ts b/x-pack/plugins/lists/server/services/lists/types.ts similarity index 72% rename from x-pack/plugins/lists/server/services/exception_lists/types.ts rename to x-pack/plugins/lists/server/services/lists/types.ts index dbb188bc2754a..2e0e4b7d038e7 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/types.ts +++ b/x-pack/plugins/lists/server/services/lists/types.ts @@ -3,4 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -export type NamespaceType = 'agnostic' | 'single'; + +interface Scroll { + searchAfter: string[] | undefined; + validSearchAfterFound: boolean; +} diff --git a/x-pack/plugins/lists/server/services/lists/update_list.ts b/x-pack/plugins/lists/server/services/lists/update_list.ts index 9859adf062485..28be50e9d6ac8 100644 --- a/x-pack/plugins/lists/server/services/lists/update_list.ts +++ b/x-pack/plugins/lists/server/services/lists/update_list.ts @@ -51,7 +51,7 @@ export const updateList = async ({ updated_at: updatedAt, updated_by: user, }; - const response: CreateDocumentResponse = await callCluster('update', { + const response = await callCluster('update', { body: { doc }, id, index: listIndex, diff --git a/x-pack/plugins/lists/server/services/utils/calculate_scroll_math.ts b/x-pack/plugins/lists/server/services/utils/calculate_scroll_math.ts new file mode 100644 index 0000000000000..6ec240d844f84 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/calculate_scroll_math.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Page, PerPage } from '../../../common/schemas'; + +interface CalculateScrollMathOptions { + perPage: PerPage; + page: Page; + hopSize: number; + currentIndexPosition: number; +} + +interface CalculateScrollMathReturn { + hops: number; + leftOverAfterHops: number; +} + +export const calculateScrollMath = ({ + currentIndexPosition, + page, + perPage, + hopSize, +}: CalculateScrollMathOptions): CalculateScrollMathReturn => { + const startPageIndex = (page - 1) * perPage - currentIndexPosition; + if (startPageIndex < 0) { + // This should never be hit but just in case I do a check. We do validate higher above this + // before the current index position gets to this point but to be safe we add this line. + throw new Error( + `page: ${page}, perPage ${perPage} and currentIndex ${currentIndexPosition} are less than zero` + ); + } + const hops = Math.floor(startPageIndex / hopSize); + const leftOverAfterHops = startPageIndex - hops * hopSize; + return { + hops, + leftOverAfterHops, + }; +}; diff --git a/x-pack/plugins/lists/server/services/utils/encode_decode_cursor.ts b/x-pack/plugins/lists/server/services/utils/encode_decode_cursor.ts new file mode 100644 index 0000000000000..205d61f204ba6 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/encode_decode_cursor.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as t from 'io-ts'; +import { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; + +import { CursorOrUndefined, SortFieldOrUndefined } from '../../../common/schemas'; +import { exactCheck } from '../../../common/siem_common_deps'; + +/** + * Used only internally for this ad-hoc opaque cursor structure to keep track of the + * current page_index that the search_after is currently on. The format of an array + * is to be consistent with other compact forms of opaque nature such as a saved object versioning. + * + * The format is [index of item, search_after_array] + */ + +// TODO: Use PositiveInteger from siem once that type is outside of server and in common +export const contextCursor = t.tuple([t.number, t.union([t.array(t.string), t.undefined])]); + +export type ContextCursor = t.TypeOf; + +export interface EncodeCursorOptions { + searchAfter: string[] | undefined; + page: number; + perPage: number; +} + +export const encodeCursor = ({ searchAfter, page, perPage }: EncodeCursorOptions): string => { + const index = searchAfter != null ? page * perPage : 0; + const encodedCursor = searchAfter != null ? [index, searchAfter] : [index]; + const scrollStringed = JSON.stringify(encodedCursor); + return Buffer.from(scrollStringed).toString('base64'); +}; + +export interface DecodeCursorOptions { + cursor: CursorOrUndefined; + page: number; + perPage: number; + sortField: SortFieldOrUndefined; +} + +export interface DecodeCursor { + cursor: ContextCursor; + isValid: boolean; + errorMessage: string; +} + +export const decodeCursor = ({ + cursor, + page, + perPage, + sortField, +}: DecodeCursorOptions): DecodeCursor => { + if (cursor == null) { + return { + cursor: [0, undefined], + errorMessage: '', + isValid: true, + }; + } else { + const fromBuffer = Buffer.from(cursor, 'base64').toString(); + const parsed = parseOrUndefined(fromBuffer); + if (parsed == null) { + return { + cursor: [0, undefined], + errorMessage: 'Error parsing JSON from base64 encoded cursor', + isValid: false, + }; + } else { + const decodedCursor = contextCursor.decode(parsed); + const checked = exactCheck(parsed, decodedCursor); + + const onLeft = (): ContextCursor | undefined => undefined; + const onRight = (schema: ContextCursor): ContextCursor | undefined => schema; + const cursorOrUndefined = pipe(checked, fold(onLeft, onRight)); + + const startPageIndex = (page - 1) * perPage; + if (cursorOrUndefined == null) { + return { + cursor: [0, undefined], + errorMessage: 'Error decoding cursor structure', + isValid: false, + }; + } else { + const [index, searchAfter] = cursorOrUndefined; + if (index < 0) { + return { + cursor: [0, undefined], + errorMessage: 'index of cursor cannot be less 0', + isValid: false, + }; + } else if (index > startPageIndex) { + return { + cursor: [0, undefined], + errorMessage: `index: ${index} of cursor cannot be greater than the start page index: ${startPageIndex}`, + isValid: false, + }; + } else if (searchAfter != null && searchAfter.length > 1 && sortField == null) { + return { + cursor: [0, undefined], + errorMessage: '', + isValid: false, + }; + } else { + return { + cursor: [index, searchAfter != null ? searchAfter : undefined], + errorMessage: '', + isValid: true, + }; + } + } + } + } +}; + +export const parseOrUndefined = (input: string): ContextCursor | undefined => { + try { + return JSON.parse(input); + } catch (err) { + return undefined; + } +}; diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter.test.ts b/x-pack/plugins/lists/server/services/utils/get_query_filter.test.ts new file mode 100644 index 0000000000000..50c266eb5d573 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/get_query_filter.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getQueryFilter } from './get_query_filter'; + +describe('get_query_filter', () => { + test('it should work with a basic kuery', () => { + const esQuery = getQueryFilter({ filter: 'type: ip' }); + expect(esQuery).toEqual({ + bool: { + filter: [ + { + bool: { + minimum_should_match: 1, + should: [ + { + match: { + type: 'ip', + }, + }, + ], + }, + }, + ], + must: [], + must_not: [], + should: [], + }, + }); + }); +}); diff --git a/x-pack/plugins/lists/server/services/utils/get_query_filter.ts b/x-pack/plugins/lists/server/services/utils/get_query_filter.ts new file mode 100644 index 0000000000000..cf0dd5b6250e5 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/get_query_filter.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { DslQuery, EsQueryConfig } from 'src/plugins/data/common'; + +import { Filter, Query, esQuery } from '../../../../../../src/plugins/data/server'; + +export interface GetQueryFilterOptions { + filter: string; +} + +export interface GetQueryFilterReturn { + bool: { must: DslQuery[]; filter: Filter[]; should: never[]; must_not: Filter[] }; +} + +export const getQueryFilter = ({ filter }: GetQueryFilterOptions): GetQueryFilterReturn => { + const kqlQuery: Query = { + language: 'kuery', + query: filter, + }; + const config: EsQueryConfig = { + allowLeadingWildcards: true, + dateFormatTZ: 'Zulu', + ignoreFilterIfFieldNotInIndex: false, + queryStringOptions: { analyze_wildcard: true }, + }; + + return esQuery.buildEsQuery(undefined, kqlQuery, [], config); +}; diff --git a/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts b/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts new file mode 100644 index 0000000000000..9721baefbe5ee --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { APICaller } from 'kibana/server'; + +import { Filter, SortFieldOrUndefined, SortOrderOrUndefined } from '../../../common/schemas'; + +import { getQueryFilter } from './get_query_filter'; +import { getSortWithTieBreaker } from './get_sort_with_tie_breaker'; +import { getSourceWithTieBreaker } from './get_source_with_tie_breaker'; +import { TieBreaker, getSearchAfterWithTieBreaker } from './get_search_after_with_tie_breaker'; + +interface GetSearchAfterOptions { + callCluster: APICaller; + filter: Filter; + hops: number; + hopSize: number; + searchAfter: string[] | undefined; + index: string; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; +} + +export const getSearchAfterScroll = async ({ + callCluster, + filter, + hopSize, + hops, + searchAfter, + sortField, + sortOrder, + index, +}: GetSearchAfterOptions): Promise => { + const query = getQueryFilter({ filter }); + let newSearchAfter = searchAfter; + for (let i = 0; i < hops; ++i) { + const response = await callCluster>('search', { + body: { + _source: getSourceWithTieBreaker({ sortField }), + query, + search_after: newSearchAfter, + sort: getSortWithTieBreaker({ sortField, sortOrder }), + }, + ignoreUnavailable: true, + index, + size: hopSize, + }); + if (response.hits.hits.length > 0) { + newSearchAfter = getSearchAfterWithTieBreaker({ response, sortField }); + } else { + return { + searchAfter: undefined, + validSearchAfterFound: false, + }; + } + } + return { + searchAfter: newSearchAfter, + validSearchAfterFound: true, + }; +}; diff --git a/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts b/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts new file mode 100644 index 0000000000000..b5d44fbc9fd84 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/get_search_after_with_tie_breaker.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SearchResponse } from 'elasticsearch'; + +import { SortFieldOrUndefined } from '../../../common/schemas'; + +export type TieBreaker = T & { + tie_breaker_id: string; +}; + +interface GetSearchAfterWithTieBreakerOptions { + response: SearchResponse>; + sortField: SortFieldOrUndefined; +} + +export const getSearchAfterWithTieBreaker = ({ + response, + sortField, +}: GetSearchAfterWithTieBreakerOptions): string[] | undefined => { + if (response.hits.hits.length === 0) { + return undefined; + } else { + const lastEsElement = response.hits.hits[response.hits.hits.length - 1]; + if (sortField == null) { + return [lastEsElement._source.tie_breaker_id]; + } else { + const [[, sortValue]] = Object.entries(lastEsElement._source).filter( + ([key]) => key === sortField + ); + if (typeof sortValue === 'string') { + return [sortValue, lastEsElement._source.tie_breaker_id]; + } else { + return [lastEsElement._source.tie_breaker_id]; + } + } + } +}; diff --git a/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts b/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts new file mode 100644 index 0000000000000..fee65cce580a0 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/get_sort_with_tie_breaker.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SortFieldOrUndefined, SortOrderOrUndefined } from '../../../common/schemas'; + +export interface SortWithTieBreakerReturn { + tie_breaker_id: 'asc'; + [key: string]: string; +} + +export const getSortWithTieBreaker = ({ + sortField, + sortOrder, +}: { + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; +}): SortWithTieBreakerReturn[] | undefined => { + const ascOrDesc = sortOrder ?? 'asc'; + if (sortField != null) { + return [{ [sortField]: ascOrDesc, tie_breaker_id: 'asc' }]; + } else { + return [{ tie_breaker_id: 'asc' }]; + } +}; diff --git a/x-pack/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts b/x-pack/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts new file mode 100644 index 0000000000000..76cdd22f710e1 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/get_source_with_tie_breaker.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SortFieldOrUndefined } from '../../../common/schemas'; + +export const getSourceWithTieBreaker = ({ + sortField, +}: { + sortField: SortFieldOrUndefined; +}): string[] => { + return sortField != null ? ['tie_breaker_id', sortField] : ['tie_breaker_id']; +}; diff --git a/x-pack/plugins/lists/server/services/utils/index.ts b/x-pack/plugins/lists/server/services/utils/index.ts index e6365e689f761..28bb3cea29e61 100644 --- a/x-pack/plugins/lists/server/services/utils/index.ts +++ b/x-pack/plugins/lists/server/services/utils/index.ts @@ -5,6 +5,14 @@ */ export * from './derive_type_from_es_type'; +export * from './encode_decode_cursor'; export * from './get_query_filter_from_type_value'; +export * from './get_query_filter'; +export * from './get_search_after_scroll'; +export * from './get_search_after_with_tie_breaker'; +export * from './get_sort_with_tie_breaker'; +export * from './get_source_with_tie_breaker'; +export * from './scroll_to_start_page'; export * from './transform_elastic_to_list_item'; +export * from './transform_elastic_to_list'; export * from './transform_list_item_to_elastic_query'; diff --git a/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts b/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts new file mode 100644 index 0000000000000..16e07044dc0d4 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { APICaller } from 'kibana/server'; + +import { Filter, SortFieldOrUndefined, SortOrderOrUndefined } from '../../../common/schemas'; + +import { calculateScrollMath } from './calculate_scroll_math'; +import { getSearchAfterScroll } from './get_search_after_scroll'; + +interface ScrollToStartPageOptions { + callCluster: APICaller; + filter: Filter; + sortField: SortFieldOrUndefined; + sortOrder: SortOrderOrUndefined; + page: number; + perPage: number; + hopSize: number; + index: string; + currentIndexPosition: number; + searchAfter: string[] | undefined; +} + +export const scrollToStartPage = async ({ + callCluster, + filter, + hopSize, + currentIndexPosition, + searchAfter, + page, + perPage, + sortOrder, + sortField, + index, +}: ScrollToStartPageOptions): Promise => { + const { hops, leftOverAfterHops } = calculateScrollMath({ + currentIndexPosition, + hopSize, + page, + perPage, + }); + + if (hops === 0 && leftOverAfterHops === 0 && currentIndexPosition === 0) { + // We want to use a valid searchAfter of undefined to start at the start of our list + return { + searchAfter: undefined, + validSearchAfterFound: true, + }; + } else if (hops === 0 && leftOverAfterHops === 0 && currentIndexPosition > 0) { + return { + searchAfter, + validSearchAfterFound: true, + }; + } else if (hops > 0) { + const scroll = await getSearchAfterScroll({ + callCluster, + filter, + hopSize, + hops, + index, + searchAfter, + sortField, + sortOrder, + }); + if (scroll.validSearchAfterFound && leftOverAfterHops > 0) { + return getSearchAfterScroll({ + callCluster, + filter, + hopSize: leftOverAfterHops, + hops: 1, + index, + searchAfter: scroll.searchAfter, + sortField, + sortOrder, + }); + } else { + return scroll; + } + } else { + return getSearchAfterScroll({ + callCluster, + filter, + hopSize: leftOverAfterHops, + hops: 1, + index, + searchAfter, + sortField, + sortOrder, + }); + } +}; diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts b/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts new file mode 100644 index 0000000000000..bb1ae1d4b9ff3 --- /dev/null +++ b/x-pack/plugins/lists/server/services/utils/transform_elastic_to_list.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SearchResponse } from 'elasticsearch'; + +import { ListArraySchema, SearchEsListSchema } from '../../../common/schemas'; + +export interface TransformElasticToListOptions { + response: SearchResponse; +} + +export const transformElasticToList = ({ + response, +}: TransformElasticToListOptions): ListArraySchema => { + return response.hits.hits.map((hit) => { + return { + id: hit._id, + ...hit._source, + }; + }); +}; From 639dbbeb1950b8ab885d32ada51f0e8d939c9c63 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 28 May 2020 14:46:42 -0400 Subject: [PATCH 20/22] Migrate audit logging to KP (#67381) Co-authored-by: Aleh Zasypkin Co-authored-by: Elastic Machine --- .github/CODEOWNERS | 1 - x-pack/index.js | 2 - .../plugins/encrypted_saved_objects/index.ts | 46 ----- x-pack/legacy/plugins/security/index.ts | 27 +-- x-pack/legacy/plugins/spaces/index.ts | 20 -- x-pack/legacy/server/lib/audit_logger.js | 40 ---- x-pack/legacy/server/lib/audit_logger.test.js | 195 ------------------ .../server/audit/audit_logger.test.ts | 2 +- .../server/audit/audit_logger.ts | 13 +- .../server/plugin.test.ts | 3 - .../encrypted_saved_objects/server/plugin.ts | 24 +-- .../common/licensing/license_features.ts | 5 + .../common/licensing/license_service.test.ts | 31 +++ .../common/licensing/license_service.ts | 4 + .../server/audit/audit_service.test.ts | 165 +++++++++++++++ .../security/server/audit/audit_service.ts | 63 ++++++ .../security/server/audit/index.mock.ts | 11 +- x-pack/plugins/security/server/audit/index.ts | 3 +- ....test.ts => security_audit_logger.test.ts} | 8 +- ...dit_logger.ts => security_audit_logger.ts} | 10 +- x-pack/plugins/security/server/index.ts | 1 + x-pack/plugins/security/server/mocks.ts | 2 + x-pack/plugins/security/server/plugin.test.ts | 5 +- x-pack/plugins/security/server/plugin.ts | 35 ++-- .../server/routes/views/login.test.ts | 1 + .../plugins/spaces/server/lib/audit_logger.ts | 6 +- .../on_post_auth_interceptor.test.ts | 2 +- .../spaces_tutorial_context_factory.test.ts | 2 +- x-pack/plugins/spaces/server/plugin.test.ts | 3 - x-pack/plugins/spaces/server/plugin.ts | 40 +--- .../routes/api/external/copy_to_space.test.ts | 2 +- .../server/routes/api/external/delete.test.ts | 2 +- .../server/routes/api/external/get.test.ts | 2 +- .../routes/api/external/get_all.test.ts | 2 +- .../server/routes/api/external/post.test.ts | 2 +- .../server/routes/api/external/put.test.ts | 2 +- .../api/internal/get_active_space.test.ts | 2 +- .../spaces_service/spaces_service.test.ts | 2 +- .../server/spaces_service/spaces_service.ts | 7 +- 39 files changed, 346 insertions(+), 447 deletions(-) delete mode 100644 x-pack/legacy/plugins/encrypted_saved_objects/index.ts delete mode 100644 x-pack/legacy/server/lib/audit_logger.js delete mode 100644 x-pack/legacy/server/lib/audit_logger.test.js create mode 100644 x-pack/plugins/security/server/audit/audit_service.test.ts create mode 100644 x-pack/plugins/security/server/audit/audit_service.ts rename x-pack/plugins/security/server/audit/{audit_logger.test.ts => security_audit_logger.test.ts} (91%) rename x-pack/plugins/security/server/audit/{audit_logger.ts => security_audit_logger.ts} (89%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6df4136ef74af..42bf7662ff2e1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -158,7 +158,6 @@ /x-pack/legacy/plugins/security/ @elastic/kibana-security /x-pack/legacy/plugins/spaces/ @elastic/kibana-security /x-pack/plugins/spaces/ @elastic/kibana-security -/x-pack/legacy/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security /x-pack/test/api_integration/apis/security/ @elastic/kibana-security diff --git a/x-pack/index.js b/x-pack/index.js index 0975a82f16f6d..9cf63854d4093 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -12,7 +12,6 @@ import { dashboardMode } from './legacy/plugins/dashboard_mode'; import { beats } from './legacy/plugins/beats_management'; import { maps } from './legacy/plugins/maps'; import { spaces } from './legacy/plugins/spaces'; -import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; import { ingestManager } from './legacy/plugins/ingest_manager'; module.exports = function (kibana) { @@ -25,7 +24,6 @@ module.exports = function (kibana) { dashboardMode(kibana), beats(kibana), maps(kibana), - encryptedSavedObjects(kibana), ingestManager(kibana), ]; }; diff --git a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts b/x-pack/legacy/plugins/encrypted_saved_objects/index.ts deleted file mode 100644 index ce343dba006cf..0000000000000 --- a/x-pack/legacy/plugins/encrypted_saved_objects/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Root } from 'joi'; -import { Legacy } from 'kibana'; -import { EncryptedSavedObjectsPluginSetup } from '../../../plugins/encrypted_saved_objects/server'; -// @ts-ignore -import { AuditLogger } from '../../server/lib/audit_logger'; - -export const encryptedSavedObjects = (kibana: { - Plugin: new (options: Legacy.PluginSpecOptions & { configPrefix?: string }) => unknown; -}) => - new kibana.Plugin({ - id: 'encryptedSavedObjects', - configPrefix: 'xpack.encryptedSavedObjects', - require: ['xpack_main'], - - // Some legacy plugins still use `enabled` config key, so we keep it here, but the rest of the - // keys is handled by the New Platform plugin. - config: (Joi: Root) => - Joi.object({ - enabled: Joi.boolean().default(true), - }) - .unknown(true) - .default(), - - init(server: Legacy.Server) { - const encryptedSavedObjectsPlugin = (server.newPlatform.setup.plugins - .encryptedSavedObjects as unknown) as EncryptedSavedObjectsPluginSetup; - if (!encryptedSavedObjectsPlugin) { - throw new Error('New Platform XPack EncryptedSavedObjects plugin is not available.'); - } - - encryptedSavedObjectsPlugin.__legacyCompat.registerLegacyAPI({ - auditLogger: new AuditLogger( - server, - 'encryptedSavedObjects', - server.config(), - server.plugins.xpack_main.info - ), - }); - }, - }); diff --git a/x-pack/legacy/plugins/security/index.ts b/x-pack/legacy/plugins/security/index.ts index 577b23f3418e8..41371fcbc4c65 100644 --- a/x-pack/legacy/plugins/security/index.ts +++ b/x-pack/legacy/plugins/security/index.ts @@ -9,8 +9,6 @@ import { resolve } from 'path'; import { Server } from 'src/legacy/server/kbn_server'; import { KibanaRequest, LegacyRequest } from '../../../../src/core/server'; // @ts-ignore -import { AuditLogger } from '../../server/lib/audit_logger'; -// @ts-ignore import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize'; import { AuthenticatedUser, SecurityPluginSetup } from '../../../plugins/security/server'; @@ -33,28 +31,24 @@ function getSecurityPluginSetup(server: Server) { export const security = (kibana: Record) => new kibana.Plugin({ id: 'security', - configPrefix: 'xpack.security', publicDir: resolve(__dirname, 'public'), - require: ['kibana', 'elasticsearch', 'xpack_main'], + require: ['kibana', 'xpack_main'], + configPrefix: 'xpack.security', + uiExports: { + hacks: ['plugins/security/hacks/legacy'], + injectDefaultVars: (server: Server) => { + return { enableSpaceAwarePrivileges: server.config().get('xpack.spaces.enabled') }; + }, + }, - // This config is only used by `AuditLogger` and should be removed as soon as `AuditLogger` - // is migrated to Kibana Platform. config(Joi: Root) { return Joi.object({ enabled: Joi.boolean().default(true), - audit: Joi.object({ enabled: Joi.boolean().default(false) }).default(), }) .unknown() .default(); }, - uiExports: { - hacks: ['plugins/security/hacks/legacy'], - injectDefaultVars: (server: Server) => { - return { enableSpaceAwarePrivileges: server.config().get('xpack.spaces.enabled') }; - }, - }, - async postInit(server: Server) { watchStatusAndLicenseToInitialize(server.plugins.xpack_main, this, async () => { const xpackInfo = server.plugins.xpack_main.info; @@ -67,11 +61,6 @@ export const security = (kibana: Record) => async init(server: Server) { const securityPlugin = getSecurityPluginSetup(server); - const xpackInfo = server.plugins.xpack_main.info; - securityPlugin.__legacyCompat.registerLegacyAPI({ - auditLogger: new AuditLogger(server, 'security', server.config(), xpackInfo), - }); - server.expose({ getUser: async (request: LegacyRequest) => securityPlugin.authc.getCurrentUser(KibanaRequest.from(request)), diff --git a/x-pack/legacy/plugins/spaces/index.ts b/x-pack/legacy/plugins/spaces/index.ts index 723164480b3b8..2f3e5e0a86d21 100644 --- a/x-pack/legacy/plugins/spaces/index.ts +++ b/x-pack/legacy/plugins/spaces/index.ts @@ -8,20 +8,9 @@ import { resolve } from 'path'; import KbnServer, { Server } from 'src/legacy/server/kbn_server'; import { Legacy } from 'kibana'; import { KibanaRequest } from '../../../../src/core/server'; -import { SpacesServiceSetup } from '../../../plugins/spaces/server'; import { SpacesPluginSetup } from '../../../plugins/spaces/server'; -// @ts-ignore -import { AuditLogger } from '../../server/lib/audit_logger'; import { wrapError } from './server/lib/errors'; -export interface LegacySpacesPlugin { - getSpaceId: (request: Legacy.Request) => ReturnType; - getActiveSpace: (request: Legacy.Request) => ReturnType; - spaceIdToNamespace: SpacesServiceSetup['spaceIdToNamespace']; - namespaceToSpaceId: SpacesServiceSetup['namespaceToSpaceId']; - getBasePath: SpacesServiceSetup['getBasePath']; -} - export const spaces = (kibana: Record) => new kibana.Plugin({ id: 'spaces', @@ -79,15 +68,6 @@ export const spaces = (kibana: Record) => throw new Error('New Platform XPack Spaces plugin is not available.'); } - const { registerLegacyAPI } = spacesPlugin.__legacyCompat; - - registerLegacyAPI({ - auditLogger: { - create: (pluginId: string) => - new AuditLogger(server, pluginId, server.config(), server.plugins.xpack_main.info), - }, - }); - server.expose('getSpaceId', (request: Legacy.Request) => spacesPlugin.spacesService.getSpaceId(request) ); diff --git a/x-pack/legacy/server/lib/audit_logger.js b/x-pack/legacy/server/lib/audit_logger.js deleted file mode 100644 index 7d3467b323b3f..0000000000000 --- a/x-pack/legacy/server/lib/audit_logger.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { checkLicense } from './check_license'; -import { LICENSE_TYPE_STANDARD, LICENSE_STATUS_VALID } from '../../common/constants'; - -const FEATURE = { - ID: 'audit_logging', -}; - -export class AuditLogger { - constructor(server, pluginId, config, xPackInfo) { - this._server = server; - this._pluginId = pluginId; - this._enabled = - config.get('xpack.security.enabled') && config.get('xpack.security.audit.enabled'); - this._licensed = false; - this._checkLicense = (xPackInfo) => { - this._licensed = - checkLicense(FEATURE.ID, LICENSE_TYPE_STANDARD, xPackInfo).status === LICENSE_STATUS_VALID; - }; - xPackInfo - .feature(`${FEATURE.ID}-${pluginId}`) - .registerLicenseCheckResultsGenerator(this._checkLicense); - this._checkLicense(xPackInfo); - } - - log(eventType, message, data = {}) { - if (!this._licensed || !this._enabled) { - return; - } - - this._server.logWithMetadata(['info', 'audit', this._pluginId, eventType], message, { - ...data, - eventType, - }); - } -} diff --git a/x-pack/legacy/server/lib/audit_logger.test.js b/x-pack/legacy/server/lib/audit_logger.test.js deleted file mode 100644 index 51a239801caac..0000000000000 --- a/x-pack/legacy/server/lib/audit_logger.test.js +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { AuditLogger } from './audit_logger'; -import { - LICENSE_TYPE_STANDARD, - LICENSE_TYPE_BASIC, - LICENSE_TYPE_GOLD, -} from '../../common/constants'; - -const createMockConfig = (settings) => { - const mockConfig = { - get: jest.fn(), - }; - - mockConfig.get.mockImplementation((key) => { - return settings[key]; - }); - - return mockConfig; -}; - -const mockLicenseInfo = { - isAvailable: () => true, - feature: () => { - return { - registerLicenseCheckResultsGenerator: () => { - return; - }, - }; - }, - license: { - isActive: () => true, - isOneOf: () => true, - getType: () => LICENSE_TYPE_STANDARD, - }, -}; - -const mockConfig = createMockConfig({ - 'xpack.security.enabled': true, - 'xpack.security.audit.enabled': true, -}); - -test(`calls server.log with 'info', audit', pluginId and eventType as tags`, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - - const pluginId = 'foo'; - const auditLogger = new AuditLogger(mockServer, pluginId, mockConfig, mockLicenseInfo); - - const eventType = 'bar'; - auditLogger.log(eventType, ''); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(1); - expect(mockServer.logWithMetadata).toHaveBeenCalledWith( - ['info', 'audit', pluginId, eventType], - expect.anything(), - expect.anything() - ); -}); - -test(`calls server.log with message`, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - const auditLogger = new AuditLogger(mockServer, 'foo', mockConfig, mockLicenseInfo); - - const message = 'summary of what happened'; - auditLogger.log('bar', message); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(1); - expect(mockServer.logWithMetadata).toHaveBeenCalledWith( - expect.anything(), - message, - expect.anything() - ); -}); - -test(`calls server.log with metadata `, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - - const auditLogger = new AuditLogger(mockServer, 'foo', mockConfig, mockLicenseInfo); - - const data = { - foo: 'yup', - baz: 'nah', - }; - - auditLogger.log('bar', 'summary of what happened', data); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(1); - expect(mockServer.logWithMetadata).toHaveBeenCalledWith(expect.anything(), expect.anything(), { - eventType: 'bar', - foo: data.foo, - baz: data.baz, - }); -}); - -test(`does not call server.log for license level < Standard`, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - const mockLicenseInfo = { - isAvailable: () => true, - feature: () => { - return { - registerLicenseCheckResultsGenerator: () => { - return; - }, - }; - }, - license: { - isActive: () => true, - isOneOf: () => false, - getType: () => LICENSE_TYPE_BASIC, - }, - }; - - const auditLogger = new AuditLogger(mockServer, 'foo', mockConfig, mockLicenseInfo); - auditLogger.log('bar', 'what happened'); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(0); -}); - -test(`does not call server.log if security is not enabled`, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - - const mockConfig = createMockConfig({ - 'xpack.security.enabled': false, - 'xpack.security.audit.enabled': true, - }); - - const auditLogger = new AuditLogger(mockServer, 'foo', mockConfig, mockLicenseInfo); - auditLogger.log('bar', 'what happened'); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(0); -}); - -test(`does not call server.log if security audit logging is not enabled`, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - - const mockConfig = createMockConfig({ - 'xpack.security.enabled': true, - }); - - const auditLogger = new AuditLogger(mockServer, 'foo', mockConfig, mockLicenseInfo); - auditLogger.log('bar', 'what happened'); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(0); -}); - -test(`calls server.log after basic -> gold upgrade`, () => { - const mockServer = { - logWithMetadata: jest.fn(), - }; - - const endLicenseInfo = { - isAvailable: () => true, - license: { - isActive: () => true, - isOneOf: () => true, - getType: () => LICENSE_TYPE_GOLD, - }, - }; - - let licenseCheckResultsGenerator; - - const startLicenseInfo = { - isAvailable: () => true, - feature: () => { - return { - registerLicenseCheckResultsGenerator: (fn) => { - licenseCheckResultsGenerator = fn; - }, - }; - }, - license: { - isActive: () => true, - isOneOf: () => false, - getType: () => LICENSE_TYPE_BASIC, - }, - }; - - const auditLogger = new AuditLogger(mockServer, 'foo', mockConfig, startLicenseInfo); - auditLogger.log('bar', 'what happened'); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(0); - - //change basic to gold - licenseCheckResultsGenerator(endLicenseInfo); - auditLogger.log('bar', 'what happened'); - expect(mockServer.logWithMetadata).toHaveBeenCalledTimes(1); -}); diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts index 760c4ef01b31c..1d1396fd520d1 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts @@ -9,7 +9,7 @@ import { mockAuthenticatedUser } from '../../../security/common/model/authentica it('properly logs audit events', () => { const mockInternalAuditLogger = { log: jest.fn() }; - const audit = new EncryptedSavedObjectsAuditLogger(() => mockInternalAuditLogger); + const audit = new EncryptedSavedObjectsAuditLogger(mockInternalAuditLogger); audit.encryptAttributesSuccess(['one', 'two'], { type: 'known-type', diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts index 1a10dd343d43d..de14a79dd0ddb 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts @@ -4,22 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AuditLogger, AuthenticatedUser } from '../../../security/server'; import { SavedObjectDescriptor, descriptorToArray } from '../crypto'; -import { LegacyAPI } from '../plugin'; -import { AuthenticatedUser } from '../../../security/common/model'; /** * Represents all audit events the plugin can log. */ export class EncryptedSavedObjectsAuditLogger { - constructor(private readonly getAuditLogger: () => LegacyAPI['auditLogger']) {} + constructor(private readonly logger: AuditLogger = { log() {} }) {} public encryptAttributeFailure( attributeName: string, descriptor: SavedObjectDescriptor, user?: AuthenticatedUser ) { - this.getAuditLogger().log( + this.logger.log( 'encrypt_failure', `Failed to encrypt attribute "${attributeName}" for saved object "[${descriptorToArray( descriptor @@ -33,7 +32,7 @@ export class EncryptedSavedObjectsAuditLogger { descriptor: SavedObjectDescriptor, user?: AuthenticatedUser ) { - this.getAuditLogger().log( + this.logger.log( 'decrypt_failure', `Failed to decrypt attribute "${attributeName}" for saved object "[${descriptorToArray( descriptor @@ -47,7 +46,7 @@ export class EncryptedSavedObjectsAuditLogger { descriptor: SavedObjectDescriptor, user?: AuthenticatedUser ) { - this.getAuditLogger().log( + this.logger.log( 'encrypt_success', `Successfully encrypted attributes "[${attributesNames}]" for saved object "[${descriptorToArray( descriptor @@ -61,7 +60,7 @@ export class EncryptedSavedObjectsAuditLogger { descriptor: SavedObjectDescriptor, user?: AuthenticatedUser ) { - this.getAuditLogger().log( + this.logger.log( 'decrypt_success', `Successfully decrypted attributes "[${attributesNames}]" for saved object "[${descriptorToArray( descriptor diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts index e8568e9964c2f..4afd74488f9fe 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts @@ -16,9 +16,6 @@ describe('EncryptedSavedObjects Plugin', () => { await expect(plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() })) .resolves.toMatchInlineSnapshot(` Object { - "__legacyCompat": Object { - "registerLegacyAPI": [Function], - }, "registerType": [Function], "usingEphemeralEncryptionKey": true, } diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts index 83b412de5db7e..cdbdd18b9d696 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts @@ -22,7 +22,6 @@ export interface PluginsSetup { export interface EncryptedSavedObjectsPluginSetup { registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => void; - __legacyCompat: { registerLegacyAPI: (legacyAPI: LegacyAPI) => void }; usingEphemeralEncryptionKey: boolean; } @@ -31,16 +30,6 @@ export interface EncryptedSavedObjectsPluginStart { getClient: ClientInstanciator; } -/** - * Describes a set of APIs that is available in the legacy platform only and required by this plugin - * to function properly. - */ -export interface LegacyAPI { - auditLogger: { - log: (eventType: string, message: string, data?: Record) => void; - }; -} - /** * Represents EncryptedSavedObjects Plugin instance that will be managed by the Kibana plugin system. */ @@ -48,14 +37,6 @@ export class Plugin { private readonly logger: Logger; private savedObjectsSetup!: ClientInstanciator; - private legacyAPI?: LegacyAPI; - private readonly getLegacyAPI = () => { - if (!this.legacyAPI) { - throw new Error('Legacy API is not registered!'); - } - return this.legacyAPI; - }; - constructor(private readonly initializerContext: PluginInitializerContext) { this.logger = this.initializerContext.logger.get(); } @@ -72,7 +53,9 @@ export class Plugin { new EncryptedSavedObjectsService( config.encryptionKey, this.logger, - new EncryptedSavedObjectsAuditLogger(() => this.getLegacyAPI().auditLogger) + new EncryptedSavedObjectsAuditLogger( + deps.security?.audit.getLogger('encryptedSavedObjects') + ) ) ); @@ -86,7 +69,6 @@ export class Plugin { return { registerType: (typeRegistration: EncryptedSavedObjectTypeRegistration) => service.registerType(typeRegistration), - __legacyCompat: { registerLegacyAPI: (legacyAPI: LegacyAPI) => (this.legacyAPI = legacyAPI) }, usingEphemeralEncryptionKey, }; } diff --git a/x-pack/plugins/security/common/licensing/license_features.ts b/x-pack/plugins/security/common/licensing/license_features.ts index 571d2630b2b17..8576e4bbc3555 100644 --- a/x-pack/plugins/security/common/licensing/license_features.ts +++ b/x-pack/plugins/security/common/licensing/license_features.ts @@ -38,6 +38,11 @@ export interface SecurityLicenseFeatures { */ readonly allowAccessAgreement: boolean; + /** + * Indicates whether we allow logging of audit events. + */ + readonly allowAuditLogging: boolean; + /** * Indicates whether we allow users to define document level security in roles. */ diff --git a/x-pack/plugins/security/common/licensing/license_service.test.ts b/x-pack/plugins/security/common/licensing/license_service.test.ts index 89901d663d82a..77e6460b7669a 100644 --- a/x-pack/plugins/security/common/licensing/license_service.test.ts +++ b/x-pack/plugins/security/common/licensing/license_service.test.ts @@ -24,6 +24,7 @@ describe('license features', function () { layout: 'error-es-unavailable', allowRbac: false, allowSubFeaturePrivileges: false, + allowAuditLogging: false, }); }); @@ -44,6 +45,7 @@ describe('license features', function () { layout: 'error-xpack-unavailable', allowRbac: false, allowSubFeaturePrivileges: false, + allowAuditLogging: false, }); }); @@ -63,6 +65,7 @@ describe('license features', function () { Array [ Object { "allowAccessAgreement": false, + "allowAuditLogging": false, "allowLogin": false, "allowRbac": false, "allowRoleDocumentLevelSecurity": false, @@ -82,6 +85,7 @@ describe('license features', function () { Array [ Object { "allowAccessAgreement": true, + "allowAuditLogging": true, "allowLogin": true, "allowRbac": true, "allowRoleDocumentLevelSecurity": true, @@ -118,6 +122,7 @@ describe('license features', function () { allowRoleFieldLevelSecurity: false, allowRbac: true, allowSubFeaturePrivileges: false, + allowAuditLogging: false, }); expect(getFeatureSpy).toHaveBeenCalledTimes(1); expect(getFeatureSpy).toHaveBeenCalledWith('security'); @@ -141,6 +146,7 @@ describe('license features', function () { allowRoleFieldLevelSecurity: false, allowRbac: false, allowSubFeaturePrivileges: false, + allowAuditLogging: false, }); }); @@ -163,6 +169,7 @@ describe('license features', function () { allowRoleFieldLevelSecurity: false, allowRbac: true, allowSubFeaturePrivileges: true, + allowAuditLogging: true, }); }); @@ -185,6 +192,30 @@ describe('license features', function () { allowRoleFieldLevelSecurity: true, allowRbac: true, allowSubFeaturePrivileges: true, + allowAuditLogging: true, + }); + }); + + it('should allow all basic features + audit logging for standard license', () => { + const mockRawLicense = licensingMock.createLicense({ + license: { mode: 'standard', type: 'standard' }, + features: { security: { isEnabled: true, isAvailable: true } }, + }); + + const serviceSetup = new SecurityLicenseService().setup({ + license$: of(mockRawLicense), + }); + expect(serviceSetup.license.getFeatures()).toEqual({ + showLogin: true, + allowLogin: true, + showLinks: true, + showRoleMappingsManagement: false, + allowAccessAgreement: false, + allowRoleDocumentLevelSecurity: false, + allowRoleFieldLevelSecurity: false, + allowRbac: true, + allowSubFeaturePrivileges: false, + allowAuditLogging: true, }); }); }); diff --git a/x-pack/plugins/security/common/licensing/license_service.ts b/x-pack/plugins/security/common/licensing/license_service.ts index 53cae857e5d66..75c7670f28a67 100644 --- a/x-pack/plugins/security/common/licensing/license_service.ts +++ b/x-pack/plugins/security/common/licensing/license_service.ts @@ -72,6 +72,7 @@ export class SecurityLicenseService { showLinks: false, showRoleMappingsManagement: false, allowAccessAgreement: false, + allowAuditLogging: false, allowRoleDocumentLevelSecurity: false, allowRoleFieldLevelSecurity: false, allowRbac: false, @@ -90,6 +91,7 @@ export class SecurityLicenseService { showLinks: false, showRoleMappingsManagement: false, allowAccessAgreement: false, + allowAuditLogging: false, allowRoleDocumentLevelSecurity: false, allowRoleFieldLevelSecurity: false, allowRbac: false, @@ -97,6 +99,7 @@ export class SecurityLicenseService { }; } + const isLicenseStandardOrBetter = rawLicense.hasAtLeast('standard'); const isLicenseGoldOrBetter = rawLicense.hasAtLeast('gold'); const isLicensePlatinumOrBetter = rawLicense.hasAtLeast('platinum'); return { @@ -105,6 +108,7 @@ export class SecurityLicenseService { showLinks: true, showRoleMappingsManagement: isLicenseGoldOrBetter, allowAccessAgreement: isLicenseGoldOrBetter, + allowAuditLogging: isLicenseStandardOrBetter, allowSubFeaturePrivileges: isLicenseGoldOrBetter, // Only platinum and trial licenses are compliant with field- and document-level security. allowRoleDocumentLevelSecurity: isLicensePlatinumOrBetter, diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts new file mode 100644 index 0000000000000..94a2ada8df1da --- /dev/null +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { AuditService } from './audit_service'; +import { loggingServiceMock } from 'src/core/server/mocks'; +import { licenseMock } from '../../common/licensing/index.mock'; +import { ConfigSchema, ConfigType } from '../config'; +import { SecurityLicenseFeatures } from '../../common/licensing'; +import { BehaviorSubject } from 'rxjs'; + +const createConfig = (settings: Partial) => { + return ConfigSchema.validate(settings); +}; + +const config = createConfig({ + enabled: true, +}); + +describe('#setup', () => { + it('returns the expected contract', () => { + const logger = loggingServiceMock.createLogger(); + const auditService = new AuditService(logger); + const license = licenseMock.create(); + expect(auditService.setup({ license, config })).toMatchInlineSnapshot(` + Object { + "getLogger": [Function], + } + `); + }); +}); + +test(`calls the underlying logger with the provided message and requisite tags`, () => { + const pluginId = 'foo'; + + const logger = loggingServiceMock.createLogger(); + const license = licenseMock.create(); + license.features$ = new BehaviorSubject({ + allowAuditLogging: true, + } as SecurityLicenseFeatures).asObservable(); + + const auditService = new AuditService(logger).setup({ license, config }); + + const auditLogger = auditService.getLogger(pluginId); + + const eventType = 'bar'; + const message = 'this is my audit message'; + auditLogger.log(eventType, message); + + expect(logger.info).toHaveBeenCalledTimes(1); + expect(logger.info).toHaveBeenCalledWith(message, { + eventType, + tags: [pluginId, eventType], + }); +}); + +test(`calls the underlying logger with the provided metadata`, () => { + const pluginId = 'foo'; + + const logger = loggingServiceMock.createLogger(); + const license = licenseMock.create(); + license.features$ = new BehaviorSubject({ + allowAuditLogging: true, + } as SecurityLicenseFeatures).asObservable(); + + const auditService = new AuditService(logger).setup({ license, config }); + + const auditLogger = auditService.getLogger(pluginId); + + const eventType = 'bar'; + const message = 'this is my audit message'; + const metadata = Object.freeze({ + property1: 'value1', + property2: false, + property3: 123, + }); + auditLogger.log(eventType, message, metadata); + + expect(logger.info).toHaveBeenCalledTimes(1); + expect(logger.info).toHaveBeenCalledWith(message, { + eventType, + tags: [pluginId, eventType], + property1: 'value1', + property2: false, + property3: 123, + }); +}); + +test(`does not call the underlying logger if license does not support audit logging`, () => { + const pluginId = 'foo'; + + const logger = loggingServiceMock.createLogger(); + const license = licenseMock.create(); + license.features$ = new BehaviorSubject({ + allowAuditLogging: false, + } as SecurityLicenseFeatures).asObservable(); + + const auditService = new AuditService(logger).setup({ license, config }); + + const auditLogger = auditService.getLogger(pluginId); + + const eventType = 'bar'; + const message = 'this is my audit message'; + auditLogger.log(eventType, message); + + expect(logger.info).not.toHaveBeenCalled(); +}); + +test(`does not call the underlying logger if security audit logging is not enabled`, () => { + const pluginId = 'foo'; + + const logger = loggingServiceMock.createLogger(); + const license = licenseMock.create(); + license.features$ = new BehaviorSubject({ + allowAuditLogging: true, + } as SecurityLicenseFeatures).asObservable(); + + const auditService = new AuditService(logger).setup({ + license, + config: createConfig({ + enabled: false, + }), + }); + + const auditLogger = auditService.getLogger(pluginId); + + const eventType = 'bar'; + const message = 'this is my audit message'; + auditLogger.log(eventType, message); + + expect(logger.info).not.toHaveBeenCalled(); +}); + +test(`calls the underlying logger after license upgrade`, () => { + const pluginId = 'foo'; + + const logger = loggingServiceMock.createLogger(); + const license = licenseMock.create(); + + const features$ = new BehaviorSubject({ + allowAuditLogging: false, + } as SecurityLicenseFeatures); + + license.features$ = features$.asObservable(); + + const auditService = new AuditService(logger).setup({ license, config }); + + const auditLogger = auditService.getLogger(pluginId); + + const eventType = 'bar'; + const message = 'this is my audit message'; + auditLogger.log(eventType, message); + + expect(logger.info).not.toHaveBeenCalled(); + + // perform license upgrade + features$.next({ + allowAuditLogging: true, + } as SecurityLicenseFeatures); + + auditLogger.log(eventType, message); + + expect(logger.info).toHaveBeenCalledTimes(1); +}); diff --git a/x-pack/plugins/security/server/audit/audit_service.ts b/x-pack/plugins/security/server/audit/audit_service.ts new file mode 100644 index 0000000000000..93e69fd2601e9 --- /dev/null +++ b/x-pack/plugins/security/server/audit/audit_service.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Subscription } from 'rxjs'; +import { Logger } from '../../../../../src/core/server'; +import { SecurityLicense } from '../../common/licensing'; +import { ConfigType } from '../config'; + +export interface AuditLogger { + log: (eventType: string, message: string, data?: Record) => void; +} + +export interface AuditServiceSetup { + getLogger: (id?: string) => AuditLogger; +} + +interface AuditServiceSetupParams { + license: SecurityLicense; + config: ConfigType['audit']; +} + +export class AuditService { + private licenseFeaturesSubscription?: Subscription; + private auditLoggingEnabled = false; + + constructor(private readonly logger: Logger) {} + + setup({ license, config }: AuditServiceSetupParams): AuditServiceSetup { + if (config.enabled) { + this.licenseFeaturesSubscription = license.features$.subscribe(({ allowAuditLogging }) => { + this.auditLoggingEnabled = allowAuditLogging; + }); + } + + return { + getLogger: (id?: string): AuditLogger => { + return { + log: (eventType: string, message: string, data?: Record) => { + if (!this.auditLoggingEnabled) { + return; + } + + this.logger.info(message, { + tags: id ? [id, eventType] : [eventType], + eventType, + ...data, + }); + }, + }; + }, + }; + } + + stop() { + if (this.licenseFeaturesSubscription) { + this.licenseFeaturesSubscription.unsubscribe(); + this.licenseFeaturesSubscription = undefined; + } + } +} diff --git a/x-pack/plugins/security/server/audit/index.mock.ts b/x-pack/plugins/security/server/audit/index.mock.ts index 888aa3361faf0..07341cc06e889 100644 --- a/x-pack/plugins/security/server/audit/index.mock.ts +++ b/x-pack/plugins/security/server/audit/index.mock.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SecurityAuditLogger } from './audit_logger'; +import { SecurityAuditLogger } from './security_audit_logger'; +import { AuditService } from './audit_service'; export const securityAuditLoggerMock = { create() { @@ -15,3 +16,11 @@ export const securityAuditLoggerMock = { } as unknown) as jest.Mocked; }, }; + +export const auditServiceMock = { + create() { + return { + getLogger: jest.fn(), + } as jest.Mocked>; + }, +}; diff --git a/x-pack/plugins/security/server/audit/index.ts b/x-pack/plugins/security/server/audit/index.ts index 3ab253151b805..3db160c703e34 100644 --- a/x-pack/plugins/security/server/audit/index.ts +++ b/x-pack/plugins/security/server/audit/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { SecurityAuditLogger } from './audit_logger'; +export { AuditService, AuditServiceSetup, AuditLogger } from './audit_service'; +export { SecurityAuditLogger } from './security_audit_logger'; diff --git a/x-pack/plugins/security/server/audit/audit_logger.test.ts b/x-pack/plugins/security/server/audit/security_audit_logger.test.ts similarity index 91% rename from x-pack/plugins/security/server/audit/audit_logger.test.ts rename to x-pack/plugins/security/server/audit/security_audit_logger.test.ts index 4dfd69a2ccb1f..c6883f681cf41 100644 --- a/x-pack/plugins/security/server/audit/audit_logger.test.ts +++ b/x-pack/plugins/security/server/audit/security_audit_logger.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { SecurityAuditLogger } from './audit_logger'; +import { SecurityAuditLogger } from './security_audit_logger'; const createMockAuditLogger = () => { return { @@ -14,7 +14,7 @@ const createMockAuditLogger = () => { describe(`#savedObjectsAuthorizationFailure`, () => { test('logs via auditLogger', () => { const auditLogger = createMockAuditLogger(); - const securityAuditLogger = new SecurityAuditLogger(() => auditLogger); + const securityAuditLogger = new SecurityAuditLogger(auditLogger); const username = 'foo-user'; const action = 'foo-action'; const types = ['foo-type-1', 'foo-type-2']; @@ -64,7 +64,7 @@ describe(`#savedObjectsAuthorizationFailure`, () => { describe(`#savedObjectsAuthorizationSuccess`, () => { test('logs via auditLogger', () => { const auditLogger = createMockAuditLogger(); - const securityAuditLogger = new SecurityAuditLogger(() => auditLogger); + const securityAuditLogger = new SecurityAuditLogger(auditLogger); const username = 'foo-user'; const action = 'foo-action'; const types = ['foo-type-1', 'foo-type-2']; @@ -96,7 +96,7 @@ describe(`#savedObjectsAuthorizationSuccess`, () => { describe(`#accessAgreementAcknowledged`, () => { test('logs via auditLogger', () => { const auditLogger = createMockAuditLogger(); - const securityAuditLogger = new SecurityAuditLogger(() => auditLogger); + const securityAuditLogger = new SecurityAuditLogger(auditLogger); const username = 'foo-user'; const provider = { type: 'saml', name: 'saml1' }; diff --git a/x-pack/plugins/security/server/audit/audit_logger.ts b/x-pack/plugins/security/server/audit/security_audit_logger.ts similarity index 89% rename from x-pack/plugins/security/server/audit/audit_logger.ts rename to x-pack/plugins/security/server/audit/security_audit_logger.ts index d7243ecbe13f8..87f7201f85665 100644 --- a/x-pack/plugins/security/server/audit/audit_logger.ts +++ b/x-pack/plugins/security/server/audit/security_audit_logger.ts @@ -5,10 +5,10 @@ */ import { AuthenticationProvider } from '../../common/types'; -import { LegacyAPI } from '../plugin'; +import { AuditLogger } from './audit_service'; export class SecurityAuditLogger { - constructor(private readonly getAuditLogger: () => LegacyAPI['auditLogger']) {} + constructor(private readonly logger: AuditLogger) {} savedObjectsAuthorizationFailure( username: string, @@ -23,7 +23,7 @@ export class SecurityAuditLogger { const missingString = missing .map(({ spaceId, privilege }) => `${spaceId ? `(${spaceId})` : ''}${privilege}`) .join(','); - this.getAuditLogger().log( + this.logger.log( 'saved_objects_authorization_failure', `${username} unauthorized to [${action}] [${typesString}]${spacesString}: missing [${missingString}]`, { @@ -46,7 +46,7 @@ export class SecurityAuditLogger { ) { const typesString = types.join(','); const spacesString = spaceIds.length ? ` in [${spaceIds.join(',')}]` : ''; - this.getAuditLogger().log( + this.logger.log( 'saved_objects_authorization_success', `${username} authorized to [${action}] [${typesString}]${spacesString}`, { @@ -60,7 +60,7 @@ export class SecurityAuditLogger { } accessAgreementAcknowledged(username: string, provider: AuthenticationProvider) { - this.getAuditLogger().log( + this.logger.log( 'access_agreement_acknowledged', `${username} acknowledged access agreement (${provider.type}/${provider.name}).`, { username, provider } diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index 0de86c72002c9..a0a06b537213d 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -27,6 +27,7 @@ export { SAMLLogin, OIDCLogin, } from './authentication'; +export { AuditLogger } from './audit'; export { SecurityPluginSetup }; export { AuthenticatedUser } from '../common/model'; diff --git a/x-pack/plugins/security/server/mocks.ts b/x-pack/plugins/security/server/mocks.ts index a6407366bbd3b..72a946d6c5155 100644 --- a/x-pack/plugins/security/server/mocks.ts +++ b/x-pack/plugins/security/server/mocks.ts @@ -9,10 +9,12 @@ import { SecurityPluginSetup } from './plugin'; import { authenticationMock } from './authentication/index.mock'; import { authorizationMock } from './authorization/index.mock'; import { licenseMock } from '../common/licensing/index.mock'; +import { auditServiceMock } from './audit/index.mock'; function createSetupMock() { const mockAuthz = authorizationMock.create(); return { + audit: auditServiceMock.create(), authc: authenticationMock.create(), authz: { actions: mockAuthz.actions, diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index d58c999ddccdf..fc49bdd9bc0c3 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -25,6 +25,7 @@ describe('Security Plugin', () => { idleTimeout: 1500, lifespan: null, }, + audit: { enabled: false }, authc: { selector: { enabled: false }, providers: ['saml', 'token'], @@ -50,9 +51,11 @@ describe('Security Plugin', () => { await expect(plugin.setup(mockCoreSetup, mockDependencies)).resolves.toMatchInlineSnapshot(` Object { "__legacyCompat": Object { - "registerLegacyAPI": [Function], "registerPrivilegesWithCluster": [Function], }, + "audit": Object { + "getLogger": [Function], + }, "authc": Object { "areAPIKeysEnabled": [Function], "createAPIKey": [Function], diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 89cffde92d564..cdfc6f0ae542f 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -24,7 +24,7 @@ import { ConfigSchema, createConfig } from './config'; import { defineRoutes } from './routes'; import { SecurityLicenseService, SecurityLicense } from '../common/licensing'; import { setupSavedObjects } from './saved_objects'; -import { SecurityAuditLogger } from './audit'; +import { AuditService, SecurityAuditLogger, AuditServiceSetup } from './audit'; import { elasticsearchClientPlugin } from './elasticsearch_client_plugin'; export type SpacesService = Pick< @@ -34,16 +34,6 @@ export type SpacesService = Pick< export type FeaturesService = Pick; -/** - * Describes a set of APIs that is available in the legacy platform only and required by this plugin - * to function properly. - */ -export interface LegacyAPI { - auditLogger: { - log: (eventType: string, message: string, data?: Record) => void; - }; -} - /** * Describes public Security plugin contract returned at the `setup` stage. */ @@ -60,6 +50,7 @@ export interface SecurityPluginSetup { >; authz: Pick; license: SecurityLicense; + audit: Pick; /** * If Spaces plugin is available it's supposed to register its SpacesService with Security plugin @@ -72,7 +63,6 @@ export interface SecurityPluginSetup { registerSpacesService: (service: SpacesService) => void; __legacyCompat: { - registerLegacyAPI: (legacyAPI: LegacyAPI) => void; registerPrivilegesWithCluster: () => void; }; } @@ -90,14 +80,7 @@ export class Plugin { private clusterClient?: ICustomClusterClient; private spacesService?: SpacesService | symbol = Symbol('not accessed'); private securityLicenseService?: SecurityLicenseService; - - private legacyAPI?: LegacyAPI; - private readonly getLegacyAPI = () => { - if (!this.legacyAPI) { - throw new Error('Legacy API is not registered!'); - } - return this.legacyAPI; - }; + private readonly auditService = new AuditService(this.initializerContext.logger.get('audit')); private readonly getSpacesService = () => { // Changing property value from Symbol to undefined denotes the fact that property was accessed. @@ -135,7 +118,9 @@ export class Plugin { license$: licensing.license$, }); - const auditLogger = new SecurityAuditLogger(() => this.getLegacyAPI().auditLogger); + const audit = this.auditService.setup({ license, config: config.audit }); + const auditLogger = new SecurityAuditLogger(audit.getLogger()); + const authc = await setupAuthentication({ auditLogger, http: core.http, @@ -178,6 +163,10 @@ export class Plugin { }); return deepFreeze({ + audit: { + getLogger: audit.getLogger, + }, + authc: { isAuthenticated: authc.isAuthenticated, getCurrentUser: authc.getCurrentUser, @@ -205,8 +194,6 @@ export class Plugin { }, __legacyCompat: { - registerLegacyAPI: (legacyAPI: LegacyAPI) => (this.legacyAPI = legacyAPI), - registerPrivilegesWithCluster: async () => await authz.registerPrivilegesWithCluster(), }, }); @@ -228,6 +215,8 @@ export class Plugin { this.securityLicenseService.stop(); this.securityLicenseService = undefined; } + + this.auditService.stop(); } private wasSpacesServiceAccessed() { diff --git a/x-pack/plugins/security/server/routes/views/login.test.ts b/x-pack/plugins/security/server/routes/views/login.test.ts index 5c41a48bf5ee4..fee3adbb19f97 100644 --- a/x-pack/plugins/security/server/routes/views/login.test.ts +++ b/x-pack/plugins/security/server/routes/views/login.test.ts @@ -172,6 +172,7 @@ describe('Login view routes', () => { showLinks: false, showRoleMappingsManagement: true, allowSubFeaturePrivileges: true, + allowAuditLogging: true, showLogin: true, }); diff --git a/x-pack/plugins/spaces/server/lib/audit_logger.ts b/x-pack/plugins/spaces/server/lib/audit_logger.ts index f770fa29bd396..da7c3886277cb 100644 --- a/x-pack/plugins/spaces/server/lib/audit_logger.ts +++ b/x-pack/plugins/spaces/server/lib/audit_logger.ts @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AuditLogger } from '../../../security/server'; + export class SpacesAuditLogger { - private readonly auditLogger: any; + private readonly auditLogger: AuditLogger; - constructor(auditLogger: any) { + constructor(auditLogger: AuditLogger = { log() {} }) { this.auditLogger = auditLogger; } public spacesAuthorizationFailure(username: string, action: string, spaceIds?: string[]) { diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index a8e3ec6276be7..e596eade802fd 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -174,7 +174,7 @@ describe.skip('onPostAuthInterceptor', () => { http: (http as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 1a32e861b22e1..0abf545fa7493 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -41,7 +41,7 @@ describe('createSpacesTutorialContextFactory', () => { http: coreMock.createSetup().http, getStartServices: async () => [coreMock.createStart(), {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); const contextFactory = createSpacesTutorialContextFactory(spacesService); diff --git a/x-pack/plugins/spaces/server/plugin.test.ts b/x-pack/plugins/spaces/server/plugin.test.ts index 7126f96f4f829..a82f2370cc124 100644 --- a/x-pack/plugins/spaces/server/plugin.test.ts +++ b/x-pack/plugins/spaces/server/plugin.test.ts @@ -23,9 +23,6 @@ describe('Spaces Plugin', () => { const spacesSetup = await plugin.setup(core, { features, licensing }); expect(spacesSetup).toMatchInlineSnapshot(` Object { - "__legacyCompat": Object { - "registerLegacyAPI": [Function], - }, "spacesService": Object { "getActiveSpace": [Function], "getBasePath": [Function], diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index 36809bf0e9e7a..af54effcaeca6 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -14,8 +14,6 @@ import { } from '../../features/server'; import { SecurityPluginSetup } from '../../security/server'; import { LicensingPluginSetup } from '../../licensing/server'; -// @ts-ignore -import { AuditLogger } from '../../../../server/lib/audit_logger'; import { SpacesAuditLogger } from './lib/audit_logger'; import { createSpacesTutorialContextFactory } from './lib/spaces_tutorial_context_factory'; import { registerSpacesUsageCollector } from './usage_collection'; @@ -31,16 +29,6 @@ import { SpacesSavedObjectsService } from './saved_objects'; import { DefaultSpaceService } from './default_space'; import { SpacesLicenseService } from '../common/licensing'; -/** - * Describes a set of APIs that is available in the legacy platform only and required by this plugin - * to function properly. - */ -export interface LegacyAPI { - auditLogger: { - create: (pluginId: string) => AuditLogger; - }; -} - export interface PluginsSetup { features: FeaturesPluginSetup; licensing: LicensingPluginSetup; @@ -55,9 +43,6 @@ export interface PluginsStart { export interface SpacesPluginSetup { spacesService: SpacesServiceSetup; - __legacyCompat: { - registerLegacyAPI: (legacyAPI: LegacyAPI) => void; - }; } export class Plugin { @@ -73,24 +58,6 @@ export class Plugin { private defaultSpaceService?: DefaultSpaceService; - private legacyAPI?: LegacyAPI; - private readonly getLegacyAPI = () => { - if (!this.legacyAPI) { - throw new Error('Legacy API is not registered!'); - } - return this.legacyAPI; - }; - - private spacesAuditLogger?: SpacesAuditLogger; - private readonly getSpacesAuditLogger = () => { - if (!this.spacesAuditLogger) { - this.spacesAuditLogger = new SpacesAuditLogger( - this.getLegacyAPI().auditLogger.create(this.pluginId) - ); - } - return this.spacesAuditLogger; - }; - constructor(initializerContext: PluginInitializerContext) { this.config$ = initializerContext.config.create(); this.kibanaIndexConfig$ = initializerContext.config.legacy.globalConfig$; @@ -109,7 +76,7 @@ export class Plugin { http: core.http, getStartServices: core.getStartServices, authorization: plugins.security ? plugins.security.authz : null, - getSpacesAuditLogger: this.getSpacesAuditLogger, + auditLogger: new SpacesAuditLogger(plugins.security?.audit.getLogger(this.pluginId)), config$: this.config$, }); @@ -177,11 +144,6 @@ export class Plugin { return { spacesService, - __legacyCompat: { - registerLegacyAPI: (legacyAPI: LegacyAPI) => { - this.legacyAPI = legacyAPI; - }, - }, }; } diff --git a/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts index 632e64156291c..09fc990e9935c 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts @@ -78,7 +78,7 @@ describe('copy to space', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts index 511e9676940d2..774b794d77e29 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts @@ -50,7 +50,7 @@ describe('Spaces Public API', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.test.ts b/x-pack/plugins/spaces/server/routes/api/external/get.test.ts index 3eb9b676bcc61..19f9b81baa0b0 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.test.ts @@ -43,7 +43,7 @@ describe('GET space', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts index 5847b3f84f41d..380cc9dbe5abf 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts @@ -43,7 +43,7 @@ describe('GET /spaces/space', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.test.ts b/x-pack/plugins/spaces/server/routes/api/external/post.test.ts index 51fcfbfeaa95d..ca3afc04b9798 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.test.ts @@ -43,7 +43,7 @@ describe('Spaces Public API', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.test.ts b/x-pack/plugins/spaces/server/routes/api/external/put.test.ts index 3575d89b151e8..62444fd3e4dfd 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.test.ts @@ -44,7 +44,7 @@ describe('PUT /api/spaces/space', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.test.ts b/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.test.ts index 82de102e119c7..086d5f5bc94bb 100644 --- a/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.test.ts @@ -24,7 +24,7 @@ describe('GET /internal/spaces/_active_space', () => { http: (httpService as unknown) as CoreSetup['http'], getStartServices: async () => [coreStart, {}, {}], authorization: null, - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + auditLogger: {} as SpacesAuditLogger, config$: Rx.of(spacesConfig), }); diff --git a/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts index 3ea1da1c835b2..3e1a849a9bdfa 100644 --- a/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts @@ -71,7 +71,7 @@ const createService = async (serverBasePath: string = '') => { getStartServices: async () => [coreStart, {}, {}], config$: Rx.of(spacesConfig), authorization: securityMock.createSetup().authz, - getSpacesAuditLogger: () => new SpacesAuditLogger({}), + auditLogger: new SpacesAuditLogger(), }); return spacesServiceSetup; diff --git a/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts index c2cc26d85fcfb..759b0606a5e8b 100644 --- a/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts @@ -15,6 +15,7 @@ import { getSpaceIdFromPath, addSpaceIdToPath } from '../../common/lib/spaces_ur import { DEFAULT_SPACE_ID } from '../../common/constants'; import { spaceIdToNamespace, namespaceToSpaceId } from '../lib/utils/namespace'; import { Space } from '../../common/model/space'; +import { SpacesAuditLogger } from '../lib/audit_logger'; type RequestFacade = KibanaRequest | Legacy.Request; @@ -39,7 +40,7 @@ interface SpacesServiceDeps { getStartServices: CoreSetup['getStartServices']; authorization: SecurityPluginSetup['authz'] | null; config$: Observable; - getSpacesAuditLogger(): any; + auditLogger: SpacesAuditLogger; } export class SpacesService { @@ -52,7 +53,7 @@ export class SpacesService { getStartServices, authorization, config$, - getSpacesAuditLogger, + auditLogger, }: SpacesServiceDeps): Promise { const getSpaceId = (request: RequestFacade) => { // Currently utilized by reporting @@ -81,7 +82,7 @@ export class SpacesService { ); return new SpacesClient( - getSpacesAuditLogger(), + auditLogger, (message: string) => { this.log.debug(message); }, From ea12008ab02daa9fe862ef922a35b5c0a59de812 Mon Sep 17 00:00:00 2001 From: Poff Poffenberger Date: Thu, 28 May 2020 14:44:16 -0500 Subject: [PATCH 21/22] Fix canvas fullscreen when nav is docked (#67625) --- .../canvas/public/components/fullscreen/fullscreen.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/canvas/public/components/fullscreen/fullscreen.scss b/x-pack/plugins/canvas/public/components/fullscreen/fullscreen.scss index c198884ee7131..7110a22408fe2 100644 --- a/x-pack/plugins/canvas/public/components/fullscreen/fullscreen.scss +++ b/x-pack/plugins/canvas/public/components/fullscreen/fullscreen.scss @@ -1,5 +1,5 @@ body.canvas-isFullscreen { // sass-lint:disable-line no-qualifying-elements - // following two rules are for overriding the header bar padding + // following two rules are for overriding the header bar padding &.euiBody--headerIsFixed { padding-top: 0; } @@ -8,6 +8,12 @@ body.canvas-isFullscreen { // sass-lint:disable-line no-qualifying-elements min-height: 100vh; } + // following rule is for docked navigation + &.euiBody--collapsibleNavIsDocked { + padding-left: 0 !important; // sass-lint:disable-line no-important + } + + // hide global loading indicator .kbnLoadingIndicator { display: none; From 177cda42bd1e3b53b8fb7a1e08600e75dc43fdb4 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Thu, 28 May 2020 15:45:46 -0400 Subject: [PATCH 22/22] [SIEM] [Detection Engine] Incorporate large lists to rule execution. (#65372) * introduce lists plugin for use by executor * adds getListClient function on setup * refactors searchAfterBulkCreate to integrate with the lists plugin so we only generate signals from events not in the list * fixes type check issues * fixes unit tests, adds field and other parameters for using lists in executor. * cleaning up types and exports, updates to match new contracts with lists client from master * prior to this commit the refactored while loop was doing more search after loops than it needed to and this fixes two bugs in the list filter function where we were returning the wrong count, and we were not accessing the right field on the event * exception lists are optional * use exceptions list format, this works with given sample query in scripts * updates tests and fixes type issues * updates README doc in detection engine with example for rule with list exception * adds one test and removes commented out code * fix sample rule json from 30s to 5m * fix sample rule json from 30s to 5m * remove unused import * more cleanup * e2e test for prepackaged rules was failing because lists was undefined in the siem plugin and was preventing the registration of the rule alert type. I removed this but once lists is ready for prime time we should consider adding the null check back * can't reuse the same env var since the tests are setting the ELASTIC_XPACK_SIEM_LISTS_FEATURE env var to true without enabling the lists plugin * fixes from pr review, still needs more TLC * exports listspluginsetup type from top-level in lists plugin, fixes logic for empty exceptions list, updates types * utilize type.is to remove as casting, also do null checks and throw an error when exceptionItem is malformed. This will change in the very near future once the new json format for exception lists is incorporated * fix type issues after merging master into branch * update mock * remove bad null check for ml plugin before registering rule alert type in siem plugin * prettier linting * adds test for filter events with list * pr comments * adds logic for included vs excluded and updates tests * update test cases for search after bulk create to default to included for exception lists * filter out non-list exception items from the loop --- x-pack/plugins/lists/server/index.ts | 4 + x-pack/plugins/siem/kibana.json | 3 +- .../server/lib/detection_engine/README.md | 9 + .../queries/lists/query_with_list_plugin.json | 24 ++ .../signals/__mocks__/es_results.ts | 13 +- .../signals/bulk_create_ml_signals.ts | 2 +- .../signals/filter_events_with_list.test.ts | 242 ++++++++++++ .../signals/filter_events_with_list.ts | 111 ++++++ .../signals/search_after_bulk_create.test.ts | 366 ++++++++++-------- .../signals/search_after_bulk_create.ts | 151 ++++---- .../signals/signal_rule_alert_type.test.ts | 10 +- .../signals/signal_rule_alert_type.ts | 70 ++-- .../signals/single_bulk_create.test.ts | 12 +- .../signals/single_bulk_create.ts | 10 +- .../signals/single_search_after.test.ts | 23 +- .../signals/single_search_after.ts | 3 - .../lib/detection_engine/signals/types.ts | 1 + x-pack/plugins/siem/server/plugin.ts | 3 + .../common/config.ts | 1 + 19 files changed, 770 insertions(+), 288 deletions(-) create mode 100644 x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list_plugin.json create mode 100644 x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.test.ts create mode 100644 x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.ts diff --git a/x-pack/plugins/lists/server/index.ts b/x-pack/plugins/lists/server/index.ts index c1e577aa60195..33f58ba65d3c3 100644 --- a/x-pack/plugins/lists/server/index.ts +++ b/x-pack/plugins/lists/server/index.ts @@ -9,6 +9,10 @@ import { PluginInitializerContext } from '../../../../src/core/server'; import { ConfigSchema } from './config'; import { ListPlugin } from './plugin'; +// exporting these since its required at top level in siem plugin +export { ListClient } from './services/lists/list_client'; +export { ListPluginSetup } from './types'; + export const config = { schema: ConfigSchema }; export const plugin = (initializerContext: PluginInitializerContext): ListPlugin => new ListPlugin(initializerContext); diff --git a/x-pack/plugins/siem/kibana.json b/x-pack/plugins/siem/kibana.json index 1106781fd45e4..6b43b41df8eee 100644 --- a/x-pack/plugins/siem/kibana.json +++ b/x-pack/plugins/siem/kibana.json @@ -24,7 +24,8 @@ "newsfeed", "security", "spaces", - "usageCollection" + "usageCollection", + "lists" ], "server": true, "ui": true diff --git a/x-pack/plugins/siem/server/lib/detection_engine/README.md b/x-pack/plugins/siem/server/lib/detection_engine/README.md index 610e82fd5f6ee..695165e1990a9 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/README.md +++ b/x-pack/plugins/siem/server/lib/detection_engine/README.md @@ -165,3 +165,12 @@ go about doing so. `./signals/set_status_with_id.sh open` will update the status of the sample signal to open `./signals/set_status_with_query.sh closed` will update the status of the signals in the result of the query to closed. `./signals/set_status_with_query.sh open` will update the status of the signals in the result of the query to open. + +### Large List Exceptions + +To test out the functionality of large lists with rules, the user will need to import a list and post a rule with a reference to that exception list. The following outlines an example using the sample json rule provided in the repo. + +* First, set the appropriate env var in order to enable exceptions features`export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true` and `export ELASTIC_XPACK_SIEM_EXCEPTIONS_LISTS=true` and start kibana +* Second, import a list of ips from a file called `ci-badguys.txt`. The command should look like this: +`cd $HOME/kibana/x-pack/plugins/lists/server/scripts && ./import_list_items_by_filename.sh ip ~/ci-badguys.txt` +* Then, from the detection engine scripts folder (`cd kibana/x-pack/plugins/siem/server/lib/detection_engine/scripts`) run `./post_rule.sh rules/queries/lists/query_with_list_plugin.json` diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list_plugin.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list_plugin.json new file mode 100644 index 0000000000000..fa6fe6ac71117 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list_plugin.json @@ -0,0 +1,24 @@ +{ + "name": "Query with a list", + "description": "Query with a list only generate signals if source.ip is not in list", + "rule_id": "query-with-list", + "risk_score": 2, + "severity": "high", + "type": "query", + "query": "host.name: *", + "interval": "30s", + "language": "kuery", + "exceptions_list": [ + { + "field": "source.ip", + "values_operator": "excluded", + "values_type": "list", + "values": [ + { + "id": "ci-badguys.txt", + "name": "ip" + } + ] + } + ] +} diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index 251a1e6d118ff..2d75ba4f42d12 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -101,7 +101,10 @@ export const sampleDocNoSortIdNoVersion = (someUuid: string = sampleIdGuid): Sig }, }); -export const sampleDocWithSortId = (someUuid: string = sampleIdGuid): SignalSourceHit => ({ +export const sampleDocWithSortId = ( + someUuid: string = sampleIdGuid, + ip?: string +): SignalSourceHit => ({ _index: 'myFakeSignalIndex', _type: 'doc', _score: 100, @@ -110,6 +113,9 @@ export const sampleDocWithSortId = (someUuid: string = sampleIdGuid): SignalSour _source: { someKey: 'someValue', '@timestamp': '2020-04-20T21:27:45+0000', + source: { + ip: ip ?? '127.0.0.1', + }, }, sort: ['1234567891111'], }); @@ -313,7 +319,8 @@ export const sampleDocSearchResultsNoSortIdNoHits = ( export const repeatedSearchResultsWithSortId = ( total: number, pageSize: number, - guids: string[] + guids: string[], + ips?: string[] ) => ({ took: 10, timed_out: false, @@ -327,7 +334,7 @@ export const repeatedSearchResultsWithSortId = ( total, max_score: 100, hits: Array.from({ length: pageSize }).map((x, index) => ({ - ...sampleDocWithSortId(guids[index]), + ...sampleDocWithSortId(guids[index], ips ? ips[index] : '127.0.0.1'), })), }, }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts index 9ac4d4087016a..5862e6c481431 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts @@ -86,5 +86,5 @@ export const bulkCreateMlSignals = async ( const anomalyResults = params.someResult; const ecsResults = transformAnomalyResultsToEcs(anomalyResults); - return singleBulkCreate({ ...params, someResult: ecsResults }); + return singleBulkCreate({ ...params, filteredEvents: ecsResults }); }; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.test.ts new file mode 100644 index 0000000000000..86efdb6603493 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.test.ts @@ -0,0 +1,242 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import uuid from 'uuid'; +import { filterEventsAgainstList } from './filter_events_with_list'; +import { mockLogger, repeatedSearchResultsWithSortId } from './__mocks__/es_results'; + +import { ListClient } from '../../../../../lists/server'; + +const someGuids = Array.from({ length: 13 }).map((x) => uuid.v4()); + +describe('filterEventsAgainstList', () => { + it('should respond with eventSearchResult if exceptionList is empty', async () => { + const res = await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: undefined, + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '3.3.3.3', + '7.7.7.7', + ]), + }); + expect(res.hits.hits.length).toEqual(4); + }); + + it('should throw an error if malformed exception list present', async () => { + let message = ''; + try { + await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'excluded', + values_type: 'list', + values: undefined, + }, + ], + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '3.3.3.3', + '7.7.7.7', + ]), + }); + } catch (exc) { + message = exc.message; + } + expect(message).toEqual( + 'Failed to query lists index. Reason: Malformed exception list provided' + ); + }); + + it('should throw an error if unsupported exception type', async () => { + let message = ''; + try { + await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'excluded', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'unsupportedListPluginType', + }, + ], + }, + ], + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '3.3.3.3', + '7.7.7.7', + ]), + }); + } catch (exc) { + message = exc.message; + } + expect(message).toEqual( + 'Failed to query lists index. Reason: Unsupported list type used, please use one of ip,keyword' + ); + }); + + describe('operator_type is includes', () => { + it('should respond with same list if no items match value list', async () => { + const res = await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3)), + }); + expect(res.hits.hits.length).toEqual(4); + }); + it('should respond with less items in the list if some values match', async () => { + let outerType = ''; + let outerListId = ''; + const res = await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async ({ + value, + type, + listId, + }: { + type: string; + listId: string; + value: string[]; + }) => { + outerType = type; + outerListId = listId; + return value.slice(0, 2).map((item) => ({ + value: item, + })); + }, + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '3.3.3.3', + '7.7.7.7', + ]), + }); + expect(outerType).toEqual('ip'); + expect(outerListId).toEqual('ci-badguys.txt'); + expect(res.hits.hits.length).toEqual(2); + }); + }); + describe('operator type is excluded', () => { + it('should respond with empty list if no items match value list', async () => { + const res = await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'excluded', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3)), + }); + expect(res.hits.hits.length).toEqual(0); + }); + it('should respond with less items in the list if some values match', async () => { + let outerType = ''; + let outerListId = ''; + const res = await filterEventsAgainstList({ + logger: mockLogger, + listClient: ({ + getListItemByValues: async ({ + value, + type, + listId, + }: { + type: string; + listId: string; + value: string[]; + }) => { + outerType = type; + outerListId = listId; + return value.slice(0, 2).map((item) => ({ + value: item, + })); + }, + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'excluded', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], + eventSearchResult: repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '3.3.3.3', + '7.7.7.7', + ]), + }); + expect(outerType).toEqual('ip'); + expect(outerListId).toEqual('ci-badguys.txt'); + expect(res.hits.hits.length).toEqual(2); + }); + }); +}); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.ts new file mode 100644 index 0000000000000..400bb5dda46e7 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/filter_events_with_list.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { get } from 'lodash/fp'; +import { Logger } from 'src/core/server'; + +import { type } from '../../../../../lists/common/schemas/common'; +import { ListClient } from '../../../../../lists/server'; +import { SignalSearchResponse, SearchTypes } from './types'; +import { RuleAlertParams } from '../types'; +import { List } from '../routes/schemas/types/lists_default_array'; + +interface FilterEventsAgainstList { + listClient: ListClient; + exceptionsList: RuleAlertParams['exceptions_list']; + logger: Logger; + eventSearchResult: SignalSearchResponse; +} + +export const filterEventsAgainstList = async ({ + listClient, + exceptionsList, + logger, + eventSearchResult, +}: FilterEventsAgainstList): Promise => { + try { + if (exceptionsList == null || exceptionsList.length === 0) { + return eventSearchResult; + } + + // narrow unioned type to be single + const isStringableType = (val: SearchTypes) => + ['string', 'number', 'boolean'].includes(typeof val); + // grab the signals with values found in the given exception lists. + const filteredHitsPromises = exceptionsList + .filter((exceptionItem: List) => exceptionItem.values_type === 'list') + .map(async (exceptionItem: List) => { + if (exceptionItem.values == null || exceptionItem.values.length === 0) { + throw new Error('Malformed exception list provided'); + } + if (!type.is(exceptionItem.values[0].name)) { + throw new Error( + `Unsupported list type used, please use one of ${Object.keys(type.keys).join()}` + ); + } + if (!exceptionItem.values[0].id) { + throw new Error(`Missing list id for exception on field ${exceptionItem.field}`); + } + // acquire the list values we are checking for. + const valuesOfGivenType = eventSearchResult.hits.hits.reduce((acc, searchResultItem) => { + const valueField = get(exceptionItem.field, searchResultItem._source); + if (valueField != null && isStringableType(valueField)) { + acc.add(valueField.toString()); + } + return acc; + }, new Set()); + + // matched will contain any list items that matched with the + // values passed in from the Set. + const matchedListItems = await listClient.getListItemByValues({ + listId: exceptionItem.values[0].id, + type: exceptionItem.values[0].name, + value: [...valuesOfGivenType], + }); + + // create a set of list values that were a hit - easier to work with + const matchedListItemsSet = new Set( + matchedListItems.map((item) => item.value) + ); + + // do a single search after with these values. + // painless script to do nested query in elasticsearch + // filter out the search results that match with the values found in the list. + const operator = exceptionItem.values_operator; + const filteredEvents = eventSearchResult.hits.hits.filter((item) => { + const eventItem = get(exceptionItem.field, item._source); + if (operator === 'included') { + if (eventItem != null) { + return !matchedListItemsSet.has(eventItem); + } + } else if (operator === 'excluded') { + if (eventItem != null) { + return matchedListItemsSet.has(eventItem); + } + } + return false; + }); + const diff = eventSearchResult.hits.hits.length - filteredEvents.length; + logger.debug(`Lists filtered out ${diff} events`); + return filteredEvents; + }); + + const filteredHits = await Promise.all(filteredHitsPromises); + const toReturn: SignalSearchResponse = { + took: eventSearchResult.took, + timed_out: eventSearchResult.timed_out, + _shards: eventSearchResult._shards, + hits: { + total: filteredHits.length, + max_score: eventSearchResult.hits.max_score, + hits: filteredHits.flat(), + }, + }; + + return toReturn; + } catch (exc) { + throw new Error(`Failed to query lists index. Reason: ${exc.message}`); + } +}; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts index 208f0e680722d..7479ab54af6e6 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.test.ts @@ -10,58 +10,28 @@ import { sampleRuleGuid, mockLogger, repeatedSearchResultsWithSortId, - sampleBulkCreateDuplicateResult, - sampleDocSearchResultsNoSortId, - sampleDocSearchResultsNoSortIdNoHits, } from './__mocks__/es_results'; import { searchAfterAndBulkCreate } from './search_after_bulk_create'; import { DEFAULT_SIGNALS_INDEX } from '../../../../common/constants'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; import uuid from 'uuid'; +import { ListClient } from '../../../../../lists/server'; +import { ListItemArraySchema } from '../../../../../lists/common/schemas'; describe('searchAfterAndBulkCreate', () => { let mockService: AlertServicesMock; let inputIndexPattern: string[] = []; + const someGuids = Array.from({ length: 13 }).map(() => uuid.v4()); beforeEach(() => { jest.clearAllMocks(); inputIndexPattern = ['auditbeat-*']; mockService = alertsMock.createAlertServices(); }); - test('if successful with empty search results', async () => { - const sampleParams = sampleRuleAlertParams(); - const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: sampleEmptyDocSearchResults(), - ruleParams: sampleParams, - services: mockService, - logger: mockLogger, - id: sampleRuleGuid, - inputIndexPattern, - signalsIndex: DEFAULT_SIGNALS_INDEX, - name: 'rule-name', - actions: [], - createdAt: '2020-01-28T15:58:34.810Z', - updatedAt: '2020-01-28T15:59:14.004Z', - createdBy: 'elastic', - updatedBy: 'elastic', - interval: '5m', - enabled: true, - pageSize: 1, - filter: undefined, - refresh: false, - tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', - }); - expect(mockService.callCluster).toHaveBeenCalledTimes(0); - expect(success).toEqual(true); - expect(createdSignalsCount).toEqual(0); - expect(lastLookBackDate).toBeNull(); - }); - - test('if successful iteration of while loop with maxDocs', async () => { + test('should return success with number of searches less than max signals', async () => { const sampleParams = sampleRuleAlertParams(30); - const someGuids = Array.from({ length: 13 }).map((x) => uuid.v4()); mockService.callCluster + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) .mockResolvedValueOnce({ took: 100, errors: false, @@ -76,7 +46,7 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(3, 1, someGuids.slice(0, 3))) + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6))) .mockResolvedValueOnce({ took: 100, errors: false, @@ -91,7 +61,22 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(3, 1, someGuids.slice(3, 6))) + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9))) + .mockResolvedValueOnce({ + took: 100, + errors: false, + items: [ + { + fakeItemValue: 'fakeItemKey', + }, + { + create: { + status: 201, + }, + }, + ], + }) + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(9, 12))) .mockResolvedValueOnce({ took: 100, errors: false, @@ -107,8 +92,23 @@ describe('searchAfterAndBulkCreate', () => { ], }); const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: repeatedSearchResultsWithSortId(3, 1, someGuids.slice(6, 9)), ruleParams: sampleParams, + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], services: mockService, logger: mockLogger, id: sampleRuleGuid, @@ -128,63 +128,63 @@ describe('searchAfterAndBulkCreate', () => { tags: ['some fake tag 1', 'some fake tag 2'], throttle: 'no_actions', }); - expect(mockService.callCluster).toHaveBeenCalledTimes(5); expect(success).toEqual(true); - expect(createdSignalsCount).toEqual(3); + expect(mockService.callCluster).toHaveBeenCalledTimes(8); + expect(createdSignalsCount).toEqual(4); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); - test('if unsuccessful first bulk create', async () => { - const someGuids = Array.from({ length: 4 }).map((x) => uuid.v4()); - const sampleParams = sampleRuleAlertParams(10); - mockService.callCluster.mockResolvedValue(sampleBulkCreateDuplicateResult); + test('should return success when no search results are in the allowlist', async () => { + const sampleParams = sampleRuleAlertParams(30); + mockService.callCluster + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3))) + .mockResolvedValueOnce({ + took: 100, + errors: false, + items: [ + { + fakeItemValue: 'fakeItemKey', + }, + { + create: { + status: 201, + }, + }, + { + create: { + status: 201, + }, + }, + { + create: { + status: 201, + }, + }, + { + create: { + status: 201, + }, + }, + ], + }); const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: repeatedSearchResultsWithSortId(4, 1, someGuids), ruleParams: sampleParams, - services: mockService, - logger: mockLogger, - id: sampleRuleGuid, - inputIndexPattern, - signalsIndex: DEFAULT_SIGNALS_INDEX, - name: 'rule-name', - actions: [], - createdAt: '2020-01-28T15:58:34.810Z', - updatedAt: '2020-01-28T15:59:14.004Z', - createdBy: 'elastic', - updatedBy: 'elastic', - interval: '5m', - enabled: true, - pageSize: 1, - filter: undefined, - refresh: false, - tags: ['some fake tag 1', 'some fake tag 2'], - throttle: 'no_actions', - }); - expect(mockLogger.error).toHaveBeenCalled(); - expect(success).toEqual(false); - expect(createdSignalsCount).toEqual(1); - expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); - }); - - test('if unsuccessful iteration of searchAfterAndBulkCreate due to empty sort ids', async () => { - const sampleParams = sampleRuleAlertParams(); - mockService.callCluster.mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ + listClient: ({ + getListItemByValues: async () => [], + } as unknown) as ListClient, + exceptionsList: [ { - fakeItemValue: 'fakeItemKey', - }, - { - create: { - status: 201, - }, + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], }, ], - }); - const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: sampleDocSearchResultsNoSortId(), - ruleParams: sampleParams, services: mockService, logger: mockLogger, id: sampleRuleGuid, @@ -204,31 +204,59 @@ describe('searchAfterAndBulkCreate', () => { tags: ['some fake tag 1', 'some fake tag 2'], throttle: 'no_actions', }); - expect(mockLogger.error).toHaveBeenCalled(); - expect(success).toEqual(false); - expect(createdSignalsCount).toEqual(1); + expect(success).toEqual(true); + expect(mockService.callCluster).toHaveBeenCalledTimes(2); + expect(createdSignalsCount).toEqual(4); // should not create any signals because all events were in the allowlist expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); - test('if unsuccessful iteration of searchAfterAndBulkCreate due to empty sort ids and 0 total hits', async () => { - const sampleParams = sampleRuleAlertParams(); - mockService.callCluster.mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ - { - fakeItemValue: 'fakeItemKey', - }, - { - create: { - status: 201, + test('should return success when no exceptions list provided', async () => { + const sampleParams = sampleRuleAlertParams(30); + mockService.callCluster + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3))) + .mockResolvedValueOnce({ + took: 100, + errors: false, + items: [ + { + fakeItemValue: 'fakeItemKey', }, - }, - ], - }); + { + create: { + status: 201, + }, + }, + { + create: { + status: 201, + }, + }, + { + create: { + status: 201, + }, + }, + { + create: { + status: 201, + }, + }, + ], + }); const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: sampleDocSearchResultsNoSortIdNoHits(), ruleParams: sampleParams, + listClient: ({ + getListItemByValues: async ({ + value, + }: { + type: string; + listId: string; + value: string[]; + }) => { + return value.map((item) => ({ value: item })); + }, + } as unknown) as ListClient, + exceptionsList: undefined, services: mockService, logger: mockLogger, id: sampleRuleGuid, @@ -249,31 +277,35 @@ describe('searchAfterAndBulkCreate', () => { throttle: 'no_actions', }); expect(success).toEqual(true); - expect(createdSignalsCount).toEqual(1); + expect(mockService.callCluster).toHaveBeenCalledTimes(2); + expect(createdSignalsCount).toEqual(4); // should not create any signals because all events were in the allowlist expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); - test('if successful iteration of while loop with maxDocs and search after returns results with no sort ids', async () => { + test('if unsuccessful first bulk create', async () => { const sampleParams = sampleRuleAlertParams(10); - const someGuids = Array.from({ length: 4 }).map((x) => uuid.v4()); mockService.callCluster - .mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ - { - fakeItemValue: 'fakeItemKey', - }, - { - create: { - status: 201, - }, - }, - ], - }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortId()); + .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) + .mockRejectedValue(new Error('bulk failed')); // Added this recently const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: repeatedSearchResultsWithSortId(4, 1, someGuids), + listClient: ({ + getListItemByValues: async () => { + return ([] as unknown) as ListItemArraySchema; + }, + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -294,32 +326,40 @@ describe('searchAfterAndBulkCreate', () => { tags: ['some fake tag 1', 'some fake tag 2'], throttle: 'no_actions', }); - expect(success).toEqual(true); - expect(createdSignalsCount).toEqual(1); + expect(mockLogger.error).toHaveBeenCalled(); + expect(success).toEqual(false); + expect(createdSignalsCount).toEqual(0); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); - test('if successful iteration of while loop with maxDocs and search after returns empty results with no sort ids', async () => { - const sampleParams = sampleRuleAlertParams(10); - const someGuids = Array.from({ length: 4 }).map((x) => uuid.v4()); - mockService.callCluster - .mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ - { - fakeItemValue: 'fakeItemKey', - }, - { - create: { - status: 201, - }, - }, - ], - }) - .mockResolvedValueOnce(sampleEmptyDocSearchResults()); + test('should return success with 0 total hits', async () => { + const sampleParams = sampleRuleAlertParams(); + mockService.callCluster.mockResolvedValueOnce(sampleEmptyDocSearchResults()); const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: repeatedSearchResultsWithSortId(4, 1, someGuids), + listClient: ({ + getListItemByValues: async ({ + value, + }: { + type: string; + listId: string; + value: string[]; + }) => { + return value.map((item) => ({ value: item })); + }, + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -341,13 +381,12 @@ describe('searchAfterAndBulkCreate', () => { throttle: 'no_actions', }); expect(success).toEqual(true); - expect(createdSignalsCount).toEqual(1); - expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); + expect(createdSignalsCount).toEqual(0); + expect(lastLookBackDate).toEqual(null); }); test('if returns false when singleSearchAfter throws an exception', async () => { const sampleParams = sampleRuleAlertParams(10); - const someGuids = Array.from({ length: 4 }).map((x) => uuid.v4()); mockService.callCluster .mockResolvedValueOnce({ took: 100, @@ -367,7 +406,30 @@ describe('searchAfterAndBulkCreate', () => { throw Error('Fake Error'); }); const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ - someResult: repeatedSearchResultsWithSortId(4, 1, someGuids), + listClient: ({ + getListItemByValues: async ({ + value, + }: { + type: string; + listId: string; + value: string[]; + }) => { + return value.map((item) => ({ value: item })); + }, + } as unknown) as ListClient, + exceptionsList: [ + { + field: 'source.ip', + values_operator: 'included', + values_type: 'list', + values: [ + { + id: 'ci-badguys.txt', + name: 'ip', + }, + ], + }, + ], ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -389,7 +451,7 @@ describe('searchAfterAndBulkCreate', () => { throttle: 'no_actions', }); expect(success).toEqual(false); - expect(createdSignalsCount).toEqual(1); - expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); + expect(createdSignalsCount).toEqual(0); // should not create signals if search threw error + expect(lastLookBackDate).toEqual(null); }); }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts index acf3e9bfb055c..05cdccedbc2c1 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/search_after_bulk_create.ts @@ -4,18 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ListClient } from '../../../../../lists/server'; import { AlertServices } from '../../../../../alerting/server'; import { RuleAlertAction } from '../../../../common/detection_engine/types'; -import { RuleTypeParams, RefreshTypes } from '../types'; +import { RuleTypeParams, RefreshTypes, RuleAlertParams } from '../types'; import { Logger } from '../../../../../../../src/core/server'; import { singleSearchAfter } from './single_search_after'; import { singleBulkCreate } from './single_bulk_create'; import { SignalSearchResponse } from './types'; +import { filterEventsAgainstList } from './filter_events_with_list'; interface SearchAfterAndBulkCreateParams { - someResult: SignalSearchResponse; ruleParams: RuleTypeParams; services: AlertServices; + listClient: ListClient | undefined; // TODO: undefined is for temporary development, remove before merged + exceptionsList: RuleAlertParams['exceptions_list']; logger: Logger; id: string; inputIndexPattern: string[]; @@ -45,9 +48,10 @@ export interface SearchAfterAndBulkCreateReturnType { // search_after through documents and re-index using bulk endpoint. export const searchAfterAndBulkCreate = async ({ - someResult, ruleParams, + exceptionsList, services, + listClient, logger, id, inputIndexPattern, @@ -73,71 +77,31 @@ export const searchAfterAndBulkCreate = async ({ lastLookBackDate: null, createdSignalsCount: 0, }; - if (someResult.hits.hits.length === 0) { - toReturn.success = true; - return toReturn; - } - logger.debug('[+] starting bulk insertion'); - const { bulkCreateDuration, createdItemsCount } = await singleBulkCreate({ - someResult, - ruleParams, - services, - logger, - id, - signalsIndex, - actions, - name, - createdAt, - createdBy, - updatedAt, - updatedBy, - interval, - enabled, - refresh, - tags, - throttle, - }); + let sortId; // tells us where to start our next search_after query + let searchResultSize = 0; - if (createdItemsCount > 0) { - toReturn.createdSignalsCount = createdItemsCount; - toReturn.lastLookBackDate = - someResult.hits.hits.length > 0 - ? new Date(someResult.hits.hits[someResult.hits.hits.length - 1]?._source['@timestamp']) - : null; - } + /* + The purpose of `maxResults` is to ensure we do not perform + extra search_after's. This will be reset on each + iteration, although it really only matters for the first + iteration of the loop. + e.g. if maxSignals = 100 but our search result only yields + 27 documents, there is no point in performing another search + since we know there are no more events that match our rule, + and thus, no more signals we could possibly generate. + However, if maxSignals = 500 and our search yields a total + of 3050 results we don't want to make 3050 signals, + we only want 500. So maxResults will help us control how + many times we perform a search_after + */ + let maxResults = ruleParams.maxSignals; - if (bulkCreateDuration) { - toReturn.bulkCreateTimes.push(bulkCreateDuration); - } - const totalHits = - typeof someResult.hits.total === 'number' ? someResult.hits.total : someResult.hits.total.value; - // maxTotalHitsSize represents the total number of docs to - // query for, no matter the size of each individual page of search results. - // If the total number of hits for the overall search result is greater than - // maxSignals, default to requesting a total of maxSignals, otherwise use the - // totalHits in the response from the searchAfter query. - const maxTotalHitsSize = Math.min(totalHits, ruleParams.maxSignals); + // Get - // number of docs in the current search result - let hitsSize = someResult.hits.hits.length; - logger.debug(`first size: ${hitsSize}`); - let sortIds = someResult.hits.hits[0].sort; - if (sortIds == null && totalHits > 0) { - logger.error('sortIds was empty on first search but expected more'); - toReturn.success = false; - return toReturn; - } else if (sortIds == null && totalHits === 0) { - toReturn.success = true; - return toReturn; - } - let sortId; - if (sortIds != null) { - sortId = sortIds[0]; - } - while (hitsSize < maxTotalHitsSize && hitsSize !== 0) { + while (searchResultSize < maxResults) { try { - logger.debug(`sortIds: ${sortIds}`); + logger.debug(`sortIds: ${sortId}`); const { searchResult, searchDuration, @@ -152,25 +116,60 @@ export const searchAfterAndBulkCreate = async ({ pageSize, // maximum number of docs to receive per search result. }); toReturn.searchAfterTimes.push(searchDuration); + toReturn.lastLookBackDate = + searchResult.hits.hits.length > 0 + ? new Date( + searchResult.hits.hits[searchResult.hits.hits.length - 1]?._source['@timestamp'] + ) + : null; + const totalHits = + typeof searchResult.hits.total === 'number' + ? searchResult.hits.total + : searchResult.hits.total.value; + logger.debug(`totalHits: ${totalHits}`); + + // re-calculate maxResults to ensure if our search results + // are less than max signals, we are not attempting to + // create more signals than there are total search results. + maxResults = Math.min(totalHits, ruleParams.maxSignals); + searchResultSize += searchResult.hits.hits.length; if (searchResult.hits.hits.length === 0) { toReturn.success = true; return toReturn; } - hitsSize += searchResult.hits.hits.length; - logger.debug(`size adjusted: ${hitsSize}`); - sortIds = searchResult.hits.hits[0].sort; - if (sortIds == null) { - logger.debug('sortIds was empty on search'); + + // filter out the search results that match with the values found in the list. + // the resulting set are valid signals that are not on the allowlist. + const filteredEvents = + listClient != null + ? await filterEventsAgainstList({ + listClient, + exceptionsList, + logger, + eventSearchResult: searchResult, + }) + : searchResult; + + if (filteredEvents.hits.hits.length === 0) { + // everything in the events were allowed, so no need to generate signals toReturn.success = true; - return toReturn; // no more search results + return toReturn; + } + + // cap max signals created to be no more than maxSignals + if (toReturn.createdSignalsCount + filteredEvents.hits.hits.length > ruleParams.maxSignals) { + const tempSignalsToIndex = filteredEvents.hits.hits.slice( + 0, + ruleParams.maxSignals - toReturn.createdSignalsCount + ); + filteredEvents.hits.hits = tempSignalsToIndex; } - sortId = sortIds[0]; logger.debug('next bulk index'); const { bulkCreateDuration: bulkDuration, createdItemsCount: createdCount, } = await singleBulkCreate({ - someResult: searchResult, + filteredEvents, ruleParams, services, logger, @@ -189,17 +188,25 @@ export const searchAfterAndBulkCreate = async ({ throttle, }); logger.debug('finished next bulk index'); + logger.debug(`created ${createdCount} signals`); toReturn.createdSignalsCount += createdCount; if (bulkDuration) { toReturn.bulkCreateTimes.push(bulkDuration); } + + if (filteredEvents.hits.hits[0].sort == null) { + logger.debug('sortIds was empty on search'); + toReturn.success = true; + return toReturn; // no more search results + } + sortId = filteredEvents.hits.hits[0].sort[0]; } catch (exc) { logger.error(`[-] search_after and bulk threw an error ${exc}`); toReturn.success = false; return toReturn; } } - logger.debug(`[+] completed bulk index of ${maxTotalHitsSize}`); + logger.debug(`[+] completed bulk index of ${toReturn.createdSignalsCount}`); toReturn.success = true; return toReturn; }; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts index 0c7f0839f8daf..ea7255b8a925a 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts @@ -17,6 +17,7 @@ import { scheduleNotificationActions } from '../notifications/schedule_notificat import { RuleAlertType } from '../rules/types'; import { findMlSignals } from './find_ml_signals'; import { bulkCreateMlSignals } from './bulk_create_ml_signals'; +import { ListPluginSetup } from '../../../../../lists/server/types'; jest.mock('./rule_status_saved_objects_client'); jest.mock('./rule_status_service'); @@ -68,6 +69,11 @@ describe('rules_notification_alert_type', () => { modulesProvider: jest.fn(), resultsServiceProvider: jest.fn(), }; + const listMock = { + getListClient: () => ({ + getListItemByValues: () => [], + }), + }; let payload: jest.Mocked; let alert: ReturnType; let logger: ReturnType; @@ -110,6 +116,7 @@ describe('rules_notification_alert_type', () => { logger, version, ml: mlMock, + lists: (listMock as unknown) as ListPluginSetup, }); }); @@ -199,6 +206,7 @@ describe('rules_notification_alert_type', () => { logger, version, ml: undefined, + lists: undefined, }); await alert.executor(payload); expect(logger.error).toHaveBeenCalled(); @@ -358,7 +366,7 @@ describe('rules_notification_alert_type', () => { }); it('when error was thrown', async () => { - (searchAfterAndBulkCreate as jest.Mock).mockResolvedValue({}); + (searchAfterAndBulkCreate as jest.Mock).mockRejectedValue({}); await alert.executor(payload); expect(logger.error).toHaveBeenCalled(); expect(logger.error.mock.calls[0][0]).toContain('An error occurred during rule execution'); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 8cef4c8ea0e6a..6885b4c814679 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -4,14 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { performance } from 'perf_hooks'; +/* eslint-disable complexity */ + import { Logger, KibanaRequest } from 'src/core/server'; import { SIGNALS_ID, DEFAULT_SEARCH_AFTER_PAGE_SIZE } from '../../../../common/constants'; import { isJobStarted, isMlRule } from '../../../../common/machine_learning/helpers'; import { SetupPlugins } from '../../../plugin'; -import { buildEventsSearchQuery } from './build_events_query'; +import { ListClient } from '../../../../../lists/server'; + import { getInputIndex } from './get_input_output_index'; import { searchAfterAndBulkCreate, @@ -19,7 +21,7 @@ import { } from './search_after_bulk_create'; import { getFilter } from './get_filter'; import { SignalRuleAlertTypeDefinition, RuleAlertAttributes } from './types'; -import { getGapBetweenRuns, makeFloatString, parseScheduleDates } from './utils'; +import { getGapBetweenRuns, parseScheduleDates } from './utils'; import { signalParamsSchema } from './signal_params_schema'; import { siemRuleActionGroups } from './siem_rule_action_groups'; import { findMlSignals } from './find_ml_signals'; @@ -32,15 +34,18 @@ import { ruleStatusServiceFactory } from './rule_status_service'; import { buildRuleMessageFactory } from './rule_messages'; import { ruleStatusSavedObjectsClientFactory } from './rule_status_saved_objects_client'; import { getNotificationResultsLink } from '../notifications/utils'; +import { hasListsFeature } from '../feature_flags'; export const signalRulesAlertType = ({ logger, version, ml, + lists, }: { logger: Logger; version: string; ml: SetupPlugins['ml']; + lists: SetupPlugins['lists'] | undefined; }): SignalRuleAlertTypeDefinition => { return { id: SIGNALS_ID, @@ -51,7 +56,14 @@ export const signalRulesAlertType = ({ params: signalParamsSchema(), }, producer: 'siem', - async executor({ previousStartedAt, alertId, services, params }) { + async executor({ + previousStartedAt, + alertId, + services, + params, + spaceId, + updatedBy: updatedByUser, + }) { const { anomalyThreshold, from, @@ -67,7 +79,7 @@ export const signalRulesAlertType = ({ query, to, type, - exceptions_list, + exceptions_list: exceptionsList, } = params; const searchAfterSize = Math.min(maxSignals, DEFAULT_SEARCH_AFTER_PAGE_SIZE); let hasError: boolean = false; @@ -123,7 +135,6 @@ export const signalRulesAlertType = ({ hasError = true; await ruleStatusService.error(gapMessage, { gap: gapString }); } - try { if (isMlRule(type)) { if (ml == null) { @@ -199,6 +210,18 @@ export const signalRulesAlertType = ({ result.bulkCreateTimes.push(bulkCreateDuration); } } else { + let listClient: ListClient | undefined; + if (hasListsFeature()) { + if (lists == null) { + throw new Error('lists plugin unavailable during rule execution'); + } + listClient = await lists.getListClient( + services.callCluster, + spaceId, + updatedByUser ?? 'elastic' + ); + } + const inputIndex = await getInputIndex(services, version, index); const esFilter = await getFilter({ type, @@ -208,34 +231,13 @@ export const signalRulesAlertType = ({ savedId, services, index: inputIndex, - lists: exceptions_list, + // temporary filter out list type + lists: exceptionsList?.filter((item) => item.values_type !== 'list'), }); - const noReIndex = buildEventsSearchQuery({ - index: inputIndex, - from, - to, - filter: esFilter, - size: searchAfterSize, - searchAfterSortId: undefined, - }); - - logger.debug(buildRuleMessage('[+] Initial search call')); - const start = performance.now(); - const noReIndexResult = await services.callCluster('search', noReIndex); - const end = performance.now(); - - const signalCount = noReIndexResult.hits.total.value; - if (signalCount !== 0) { - logger.info( - buildRuleMessage( - `Found ${signalCount} signals from the indexes of "[${inputIndex.join(', ')}]"` - ) - ); - } - result = await searchAfterAndBulkCreate({ - someResult: noReIndexResult, + listClient, + exceptionsList, ruleParams: params, services, logger, @@ -256,7 +258,6 @@ export const signalRulesAlertType = ({ tags, throttle, }); - result.searchAfterTimes.push(makeFloatString(end - start)); } if (result.success) { @@ -293,6 +294,11 @@ export const signalRulesAlertType = ({ } logger.debug(buildRuleMessage('[+] Signal Rule execution completed.')); + logger.debug( + buildRuleMessage( + `[+] Finished indexing ${result.createdSignalsCount} signals into ${outputIndex}` + ) + ); if (!hasError) { await ruleStatusService.success('succeeded', { bulkCreateTimeDurations: result.bulkCreateTimes, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts index 6f3cc6e708fce..265f986533134 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.test.ts @@ -141,7 +141,7 @@ describe('singleBulkCreate', () => { ], }); const { success, createdItemsCount } = await singleBulkCreate({ - someResult: sampleDocSearchResultsNoSortId(), + filteredEvents: sampleDocSearchResultsNoSortId(), ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -175,7 +175,7 @@ describe('singleBulkCreate', () => { ], }); const { success, createdItemsCount } = await singleBulkCreate({ - someResult: sampleDocSearchResultsNoSortIdNoVersion(), + filteredEvents: sampleDocSearchResultsNoSortIdNoVersion(), ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -201,7 +201,7 @@ describe('singleBulkCreate', () => { const sampleParams = sampleRuleAlertParams(); mockService.callCluster.mockResolvedValue(false); const { success, createdItemsCount } = await singleBulkCreate({ - someResult: sampleEmptyDocSearchResults(), + filteredEvents: sampleEmptyDocSearchResults(), ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -228,7 +228,7 @@ describe('singleBulkCreate', () => { const sampleSearchResult = sampleDocSearchResultsNoSortId; mockService.callCluster.mockResolvedValue(sampleBulkCreateDuplicateResult); const { success, createdItemsCount } = await singleBulkCreate({ - someResult: sampleSearchResult(), + filteredEvents: sampleSearchResult(), ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -257,7 +257,7 @@ describe('singleBulkCreate', () => { const sampleSearchResult = sampleDocSearchResultsNoSortId; mockService.callCluster.mockResolvedValue(sampleBulkCreateErrorResult); const { success, createdItemsCount } = await singleBulkCreate({ - someResult: sampleSearchResult(), + filteredEvents: sampleSearchResult(), ruleParams: sampleParams, services: mockService, logger: mockLogger, @@ -352,7 +352,7 @@ describe('singleBulkCreate', () => { const sampleParams = sampleRuleAlertParams(); mockService.callCluster.mockResolvedValue(sampleBulkCreateDuplicateResult); const { success, createdItemsCount } = await singleBulkCreate({ - someResult: sampleDocSearchResultsNoSortId(), + filteredEvents: sampleDocSearchResultsNoSortId(), ruleParams: sampleParams, services: mockService, logger: mockLogger, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts index c162c8855b091..39aecde470e0b 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_bulk_create.ts @@ -15,7 +15,7 @@ import { buildBulkBody } from './build_bulk_body'; import { Logger } from '../../../../../../../src/core/server'; interface SingleBulkCreateParams { - someResult: SignalSearchResponse; + filteredEvents: SignalSearchResponse; ruleParams: RuleTypeParams; services: AlertServices; logger: Logger; @@ -64,7 +64,7 @@ export interface SingleBulkCreateResponse { // Bulk Index documents. export const singleBulkCreate = async ({ - someResult, + filteredEvents, ruleParams, services, logger, @@ -82,8 +82,8 @@ export const singleBulkCreate = async ({ tags, throttle, }: SingleBulkCreateParams): Promise => { - someResult.hits.hits = filterDuplicateRules(id, someResult); - if (someResult.hits.hits.length === 0) { + filteredEvents.hits.hits = filterDuplicateRules(id, filteredEvents); + if (filteredEvents.hits.hits.length === 0) { return { success: true, createdItemsCount: 0 }; } // index documents after creating an ID based on the @@ -95,7 +95,7 @@ export const singleBulkCreate = async ({ // while preventing duplicates from being added to the // signals index if rules are re-run over the same time // span. Also allow for versioning. - const bulkBody = someResult.hits.hits.flatMap((doc) => [ + const bulkBody = filteredEvents.hits.hits.flatMap((doc) => [ { create: { _index: signalsIndex, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.test.ts index 580080966457e..2aa42234460d8 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.test.ts @@ -22,18 +22,17 @@ describe('singleSearchAfter', () => { test('if singleSearchAfter works without a given sort id', async () => { let searchAfterSortId; mockService.callCluster.mockResolvedValue(sampleDocSearchResultsNoSortId); - await expect( - singleSearchAfter({ - searchAfterSortId, - index: [], - from: 'now-360s', - to: 'now', - services: mockService, - logger: mockLogger, - pageSize: 1, - filter: undefined, - }) - ).rejects.toThrow('Attempted to search after with empty sort id'); + const { searchResult } = await singleSearchAfter({ + searchAfterSortId, + index: [], + from: 'now-360s', + to: 'now', + services: mockService, + logger: mockLogger, + pageSize: 1, + filter: undefined, + }); + expect(searchResult).toEqual(sampleDocSearchResultsNoSortId); }); test('if singleSearchAfter works with a given sort id', async () => { const searchAfterSortId = '1234567891111'; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.ts index 8071c18713c19..a7086a4fb229e 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/single_search_after.ts @@ -36,9 +36,6 @@ export const singleSearchAfter = async ({ searchResult: SignalSearchResponse; searchDuration: string; }> => { - if (searchAfterSortId == null) { - throw Error('Attempted to search after with empty sort id'); - } try { const searchAfterQuery = buildEventsSearchQuery({ index, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/types.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/types.ts index b493bab8b4610..32b13c5251a6b 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/types.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/types.ts @@ -100,6 +100,7 @@ export interface GetResponse { _source: SearchTypes; } +export type EventSearchResponse = SearchResponse; export type SignalSearchResponse = SearchResponse; export type SignalSourceHit = SignalSearchResponse['hits']['hits'][number]; diff --git a/x-pack/plugins/siem/server/plugin.ts b/x-pack/plugins/siem/server/plugin.ts index 3c336991f3d9d..5a47efd458888 100644 --- a/x-pack/plugins/siem/server/plugin.ts +++ b/x-pack/plugins/siem/server/plugin.ts @@ -19,6 +19,7 @@ import { PluginSetupContract as AlertingSetup } from '../../alerting/server'; import { SecurityPluginSetup as SecuritySetup } from '../../security/server'; import { PluginSetupContract as FeaturesSetup } from '../../features/server'; import { MlPluginSetup as MlSetup } from '../../ml/server'; +import { ListPluginSetup } from '../../lists/server'; import { EncryptedSavedObjectsPluginSetup as EncryptedSavedObjectsSetup } from '../../encrypted_saved_objects/server'; import { SpacesPluginSetup as SpacesSetup } from '../../spaces/server'; import { LicensingPluginSetup } from '../../licensing/server'; @@ -52,6 +53,7 @@ export interface SetupPlugins { security?: SecuritySetup; spaces?: SpacesSetup; ml?: MlSetup; + lists?: ListPluginSetup; } export interface StartPlugins { @@ -194,6 +196,7 @@ export class Plugin implements IPlugin `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`,