From 05d9b96a91168b1716a20782e9f053fa37d96b33 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 21 Mar 2026 23:18:44 +0800 Subject: [PATCH 01/29] Add Everything 1.5 SDK --- .../EverythingSDK/x64/Everything3.dll | Bin 0 -> 154792 bytes .../EverythingSDK/x86/Everything3.dll | Bin 0 -> 111272 bytes .../Flow.Launcher.Plugin.Explorer.csproj | 6 ++++++ 3 files changed, 6 insertions(+) create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x64/Everything3.dll create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x86/Everything3.dll diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x64/Everything3.dll b/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x64/Everything3.dll new file mode 100644 index 0000000000000000000000000000000000000000..be6a6f1409d4d3f61aceb8741f841ab2f7510b70 GIT binary patch literal 154792 zcmeFa3w)Ht)jz(uLAY)}R-+_sVpS|wL$!9}dchk6v^@Xs_sl$(-E0uw`u2VQ@8_4# zXY)KWb7tnunKNh3oH;X3^(Bjac|M;nA3w|T`Ih0yzY6)k|9?p&_a69kZ{HK$HXXSv zC$j0tvD2=pE15C#hO1{@eqG7b%dfxwhG@wZSC!1HzrN&}>q{!fTv&454Od=ua<5+9 zgSzM+&h!2KwH?<#ZvS>3chKWo5Z-y5@9~XzJ~THV;n#ND@OVPv^B(_+Jo`QVsyzGZ z=fU#4;F_t^SXL(HHB~;}l?%G~rZu%qv(t9^jwK~ z&sFqcu)v1^|K_R4(3QD5MrG1@0gxG1F^f|0wR=}$Sn{siJ6LX#;-CvGQZgS+b58vuA3X-8TSZg2;<5s3YNfBT_;VI8yQXF0x&_MZ`Zztm`4 zAMIzD;R-A8IntJ~H;vfp(pAerlC80LFM`Cim(_(!xG+=0sXpPd|w2#jqeM1_uy+H*qqAm4CUwQ(3cfcWx)XeZ zNIGzQ2LRf}_b|MB@ZEl2j_;*ZXXtLsj_-@e1bn}6@XZ%|pGR~j_(qX*;P_q-XdB<} z;N64oAOxFJxt$@L9p3@S1bp9e@GTL1{fO=a-_`ei9ekeyw2kl6c=zCYGlI>jg0F|~ z^~eN#pLg)B5PT;ix)Xf+A?d*B+Z)g}zTNTe!FR(?h;Ns#f$ynS;5lTPKXuM+mSt&_ zkC_M2CrJMmX`LWF8A%yPyZu+@kq?sqXybbc-aYspj$m`D>(|4#H!=ZVYoCiRl{3M2 z?>(L3`$r@l5War^ppEZu@$SKQI)crq!moiZzzLup%r`_4aMHeiJs1X$H(^OM32zI{Cbw% zBzSq|jc0tAqf4%nkl_gg=f6!v=YK&2qvd!4-{^p4 z)L0QflD}%LTdBfl8DKq_s7Mz`^`2)^bNk1c&oI6wv3Bt5ZV$gg%@HOz7ipa^f%T&f zOyHL99bfwZX!Gk{yn7n{41&$69{cTorN!CvFYx^XG7;a8JosY$B>3Kov`+9HgCwDi zI|*mU_dEdF_@0Y*557GRY)66k3(^ zr#t>)o2hUbO5+@B1?pKydEKlHF0lU*^z=UyTSg9+PM7}YlAlpi_(cCp?(F^l{R8WNfT8~wl-v1L%JiQeHPf`X37j-T#Q~l)Q&Yz3l(}L4CHED0d)lCO>BOKXVZs_Wxk^f3E8P zD%Jl|DEl8Tog#Rn4fWvupe_`s4hZg_KhI&NH2gGwD*UXw*l6H)?EY$g-G=h*59-eX zl^s7JUE^j6a;ABJi?Gly-emhDcv+!Ft z0*DZ^`K=>3RMPoeW?Xk)AuybIHhgOj^FbFIJrjfdl~`ace_Mp!S5OZ z*!b1P&cxV#A!0WB8;*ub6OO%L)z;Q7wtpf2Q+>j*=G?^XzEaB?Zb8|YeH0>dYKQyY zm|2Yft#y6puk40I|5HuPfA5~Rh2Zn|()fF8C3UEw=E~;wzQL|NcZL@F_}(*kcF%dC zg%vsG%6Wf3yScr~ycgy%DjaLdNA$kX!Wyg1gsccBD)Lh|qpYqd>ok^iyvpzI*(zma zX3w*;r^X;}Uh3@F-rH^!`_mELx(4=aLS4BI@KFHHP4#63-9ihCkd~9`jkug}c~jUw zVr9f^stv`4`uvR_Kw}43*lddCht~RhD}Ao1D?`6EsEPg+)0V&Ck7!H8Tv@iYcIZL= zhMU;3*m{dZUJOze5|_mMbo%SGkE!{s6h@5>`HP(VF99xF{^i;72krWc zjJ%5r6#|PpDPWGLfXw<2HDX^_D*O4JWFN}-7)*q0Q)d2)iyi#?bdrD1o%?HliIe{& zz-4X!e)Geir|JLwPV(QFEq`C5{QMzxJqTb<@1|GHnlb_{VVYe<|Kc`w=hl%F92803V~S5Ad%r68$bPE4LJS z8_|e7ZX>ePe~RQk-p()FWKP^tWD~Oz1!Upnlf1aFSeqY?KzSu~hoC%YB|W$7%E^fa zI*{a}g`Souq&m%?nF z{)XS-r5b86hj=7$0ZsA#hA1K_ua*`ztoO%52>F*b2U~|V)t?=X?a7@vw7PMtzu`Q@ z1EwNp-j0DrY*lXXZ2!`i!dQscHvhegf2jzs+8&5$%dL%HxUVgs%h@@swZ0nVDWjZ};T; zZ@(RHp*t&bVmrFVTF-9Y(WS>a1am#_dG@;&utVp!aoa2$+nYOcmf2i8e}|O^jPje? zyVoKq2+VS8Px6%lw|ulIzcxPd%i8$peW?nxB3fA+?_uL_L!^$yTMl4zQvC^20z7RP zuz4D|ji#m+FEPEBak4FtX9R*f|LyY~4i6ZPAO2#HgL&_(;g1a$mF? z6!yYMyf~E?i60(j7or~$Ba0&OOR?QCvM7vXJW=_`BIEcvw7e&_k46`{YXsoyZtpzV zz&^LNUq^e}xG@rs1WPWwNHolFtUV`eCJot!sPAoNL#P!p*Hb83SQER6=e{%>aGozgvLTvL9y7ITWz+AX4O`Au%otAa9_+| z_RvHi-?Og)MV9RwY?MRIo{K#q|A-fiM1D7;ycw@6jl?i4UD{_}iY>qBI4dwc=Iz&u z5Ry&BozXL~v^C6Eu-BNpVGHD z*J=gYZJs6zL>+BkbpB=sm%8{2F78_vQ@1hlKE0*itc6GG1+##d>6ROPSy&A(Fq zjBeaj-}O0ed!`ODmVqMt8_484?nGoH5&Rqvh@mg7=v*t1gIe9q)6{%Df?DfsdaXlL zYEr};2^1~_wbqeClApXtzHv4%p8=3-ba;}bAOnyO#ZO$#*Q)rns|EE)eCiM*UN<9U zZx2rsU^FFSUJ0Jz0<}>}1BD`BqZ)KL2Oma_UWuK7WH-{&UEqb6B8gtRgaewxu?<`u zMEzVKK{n;qhT;|byi18ySW0kxB+H5Vm$63hH@pMda2e)r_$%IwM6df%8mETd`zys@ zDOi)#zrwuH8G6m;e=0ZDeoXYxSo@jLezEq6Q9nz{2O^+VFJ8cd{c798Z99-PDDZJ1Zv{ z-xrM!UBtm%wmpI^c(aYGqe!CQL9%CJB-SvixQ0;#m37Rv`hN=P?nXiWr@GftX(6i_ ziNIuJQj1qv!+P@DxYJW088%;$^_TytX40#O^y)!+QEug?^6|e*t$A*)WNKVr|C*5~ z@DU$#gOqEpkB!8|!0&b7_qxFj7xXsNCym6-kbE32=VP1yvm#3MPp|!35YlB#Z4(@MDC$4h6FjhC{&-M!X7R z_!dku)jklwh+kHiEO!@w#1^8dMx^LvlP|M<3x=rdZ<6oXU+_qX28+js#;RU}IIcF= zq35u~h5RYoTDCs<%g-_AmSbu&cPb|eig1)Z2y`hi%0HqD!k$~$%r)8t;ZuZ^Z$rEs zwnE)z+ld0pTL|nkjPiXmuaud1k`-7k`E3`5UogMNi6VwD+I*BjCyF{Cav^>_Aib;2 zHOVeS4^y=>eLxCeDpU;*O?12}&QgW^%^mS+`u1$))KbE#&C#XwT8Z|y0yPY`jD$&q zipOZI(AG!0Sb?Dm3|3PKo}hviI(WDQA&PSGVg=rqOX6UjkvZj6gcPojOO8}}5V1-X zaJ^jEKTs^LRh=aMEftXdA#LZ&KoY!x(;^Pq{GH^mA( zhVl_AjU*z$DV0R#HJOR6!1s^>TB8$s;%)dlP;a7LhyMeQ`Wp@NoQf(Gn;47fE?&tw z@0`J*gpnJ1nJgwg%2~-*46paMb z`dgLnVYjbses}4qm_9TvM189!^gMgGs_dO=v#q*(b2XK#J^njRK#_4Yz7ne0X+{FG zekj3CNr2{yv(bAD=rjiOt`N+|fZmIO_W&&+`Ky}bha(Xr2iQ+;${_h%!yILk95Wp# zj0holmARSW3M=pzWP-_OGAVwcVX~42U5O(4?-ambQ`HT+A49r-OuCO^GtD(&Dm|N% zKY_$RQRi1CrskwZ3)NF+rBk~L3S%W!Afn&w>O2G=iX_a*+W+N7@H@y<6Eata%}WP| z&FMqJW*s!vw?mUdlR}qqRBHJn{ZTv)0tmf;g;rD8Y!@ZI&EEhG4dq-u&6dyLcA!%J zh5wwl%9_IQ{9qXLDCEB){sXsHgJg+$$Yuqe2NH-7hM%UWPib8O`HB?9@Q33qli{mu z>e~!oH6(-KFOvMxiJIYAMP(3GtP7ieu>z;4)Kj2@PXlF-GX}LAc{|~6AY(mO0a zg)BdV+zx6?vKjs-bA;jF)SP}Nf^38p*rMO0E=72$u1RJ1z0Kdn7m=2si-fP|zdr^1 zYnTP6ZbLa`tBrUAbbG`!!bkweEYNrth!uJsbcH>jx_o!F`7XJ~deCS7#=dS( zEK(FH+n79JJ*&Sz_!ucPe>F+xuqnCera(TJUF(78RoZe=8FEe>#RttsowwL?$!H{L)7 zQ409X9>#FuZr2N|O`*K|UQDED4(%lb2%lF?Txi#{I|_F&_>pp|v77O>lfPc#k~q z4`NFZnj=vi3cToKbGzg~Kr5a%Aq-Op<~E6u;lihMMRk`?&~ykuRGf2daEpU)&G%i4Q} zQNFJ3NG`%d=B~7{%S3$=&vjylWh85gcqS$RpWYbjWR#iWsqx6W}opG{ZLL8kfs}q0=GMA8KG{^56a_$t}H7g12-_33?@g zNLWgwSHx0sn-zEsEa+NFnh}yw<624{Kve2-^a{|r5Q?_4l&pJJdIbv&>6PyT$aOY1 zSqd`1Dgtfg<|$RmTrxo#8KTWZTILu_$^{->!WAiWZZvp;M4_uZ4c3yh7m_@&8#h*! zt;b@Z?J5|`q<IgOARhi9gBP7P_@8fUSOq$7L17V7p;JZ`Urh$ez0DAll z(k#6~dIBNrBpK$X^*fYn2s1QpCtEHSNZUL8PC}a4ELVwjX^GdV#0s4_E-kS}C4#O} z?9jBtGK8$aF%oC5Ne4;>%z-l9sHsI0>YeLlf&=e*XB(Ms#$&#jm&-0J_`{39Rn0e3 z5F_&qEKD-rgyVHPDcNe&eDjGiazgsztb)up6>|OnlA*@m@N*EdV#t{=o5C`UDZ64w zxlGw&tuxBE&7O_Ld!@OdY<<~QyRK={$yGm`?=f$n(+QBl5gI_#mHbIc54_%Je@-4g|DJ{}sZt+Aa!`YzAa{l#*)x z>UjvJ5uDsrOo{N7M?plYf(-|ANDoOr4{|cQN%?wNgURoMrMMd z&=9O;*d*YTH-!Hb!@%YPhJkvd8D_Gyb6_Y@m2=L*69=SnsrpR}PT_nojigd*9(xUF zlpH&!Z`UESF*;BbE1DcG$F6z8JR(%)4oRE{k zuIB3uVP|D5c3~0~-6Gr$*_@pGcgsp)wXR}wbZnTh!*y)I)x!D$K9~u?<-L^ML#?al zeg{l5ltw*sRTRD&Ry40R4go5oQ?zSZ{ai70AoS$=Pto)Jj`XZJAbR$h-Q7I5XKYW- z%&r+keeu7WsNHvDBkE_6OD<9S3PTD}w=*GwsK;G%z(oBI(=+csPtT{{%0|zJ8S60V zN^qg(UXuwK^nC5=1E!}(KiDgS8*5w5jL>>ya93dxpw58N4gaK?=y2N>lx2Lc(&M`b zgM4}G4uDB=N3isa3_rQ zzsJZsEOt{-fz$E*vcQ{%yUul=O=YXIbo+KDxXtFsEgGloPu1q@Rpu7upW$yvIxT+_ zZ*=Vt!&JB>R0vhY3b*9&LCqD4=Z%=~!UiM(ruegz08smZX0svlyO9UC&Ymq**l@2Z zUpcc6{>|;PhxH!#a@(h}fQX#omX%88sgowSN7#G7he*ze!;6%QqV9abg`Nxo|F8DRfZ{8Bhu&-w&^31u+^cD z*acv?Z`g#WkfKYdC6xc)N}s-2+bZ;-&@jw=&?krV>FUtu&C9dXM-dIGY$tU2mE`l% zrPJ{uwo8#08$gWzw(-(WV+2tyo}y~JKw*x)saoG}PdKkA6q{4j!x=NJFj{FjXy*y} zpPpLUyRN`655p0(!`$)ngurGQKld@gsk7sJL6fbL7c0M+_8*^BUiP!wLU*xw?u5~5 zjwp&XeMaT?1SL6pVsE3nc_>b-0Z@6gy*4?!sC*vrLLg6}dSpC|Bu}i}{W3mEV1f&Y z43U*UwfR!W+=qeL+lPiAb^F71$c4~o&#V+0p$zLIMc@LS6E=4hIS3@!gRNH0F+l3US zs`N1|ed(Fe;Vc~<(<`wQkrD@dv`Dsn>;Xwn-w8q_*L%}LVg+pb5mvh$ z>I=!y%H&VH@ag4Yjpa+;=uHnTD?nUZm0ezF8O~+;+D>=FSTp+Cj&Z}Z(Y6I}vQp{~ zE$hZ`ft%i);m>zD>F73J+dpjhbbPv^r;}|vJ?+QtsK4Pi$RZO57s|ylGQ<;*#!;Cs zoe6R=OoN4nxev};vreJ00ZYZv#hgSdj0D!SoUuY!Zxe`~eZ>M_zSHoJYB$V-z!r3i z8-)suoO0v%n+uJ+kBmXP>mNz=(CP7R&quH~* zhmpp)uLD>ouyz%fvu_09yC2yf!t21y4#Kj#K9MSh*s7g-I5f^Av)CiD;mdLOjo|z4 zulI*H(Q@ET>it!t8D{=f+PpmH-q0(zuF(U+Q6+EKiVr}?N;5vM!`NG=T#s$ zT;70M3X*?Aays^(48j~{JpC`gNS_i8_M-BY2H|?3G(@+`v@GkK?7Tvjskl(wsOG=_ zAUnq_SOFQPExz**1LqP9KJki!3qH@BL)!Zrmf|Hc^zy>`Uie>J-?eOg+apYiKN{R3 z&nMId7>uMdjQ9%K1*6$=0{7~sMwrG-|bLm}S zz|Ch!Rs5=8h>l3;fs#%K%k!Dd~9JvwY!CJ(|M9gWHNu<@p%6D)Bfl^u<8YeRA~POXU(w74dR6V)d^O%9d9H?i)U()e`)^EVAC+TVHz-3)bFfh1k@T> zCYp>vFUffhB<;;j4Pcab{WF}G>K&Tb+8&zMz7tl<*xvjoW`fsI#oB!A{;Ts}Xj9fD zUORT()S^inI%H3oV+PyLGCnYBl*-8c_6xE9@fax0{f{S|(ZJ0BYklekI zya6jKMsUPz^)KLdyp+q{tl$nq1Z`k%R_NZWM0j)pnj&kLio)gZr`IJo%sflBSmE=~ zT}rUs9X}h3mSKJ^(i#{{?^R=%EV-=s&RXGDj1^7S3icQ!+d~A zRp}OddLaTsw7&N)1A~lvM8GDnk4nxR@w&4ew3g|%yY_MfA{e>cyNO`rE|llP!NquT z=-ngFC)BnO(q)@Sy2b9iyQBoS^X@=cICYWQW5VbgOOZ8yHTlkUri6Uf{I~^k~FQ2D@TRo^)HYSmnfNl*~Cox7d$Dv*q}TahBgE_i$@Q|{^tcGiwbL|{3D{^ ziggnHX?PSo2k=Ju=SE9|6sv}Uc8q{;7mJ%&DSpIfS%IshPYZMvcT6I6^E^T~E>< zMA29gNsNNK!@A`3pJFX(56uC@#2sowtpJ^9ye;le+>YctHv@#jeCd?y+}8K{7-o4i z_!veMw|%+l;<#>-=M%wo@_aPd%BRiPo`LYV-C;Nvd zvskR*Ki2kZiI@-^;CC?it6Es>aU{m-1@q!n1kJz zb}SOmvhHroyDFxi2d9@+6n5PmG@B6hslN!S0dnUnWIy%y8CBT!E2Mm4rxd7^Pb6iL zH>ImLWhPRV7h$BLFau0JhU_P&0*&~nLVv@tlo@88&^pW|^hh!Kww;N5P@#~k&=)<@ zzcg*ONnC^w&`FPRN`n758`{bfh*qS0$1Ek$+WG_ii1{u(M_Rgu;Cgj+ zp%vI$Eks3Ai=x|D&hUBVR(*eBpr#knV-wV2#nNwb1_C~A+T%{zN=ZBEM4;v-|G-K9 z1(N5lycIab_V)4LAv;b}S8`}Ao@NiNXZsW_L$CVUxC>MJY~LbfNBX^l4k}uPp7pi; zOhSR8W$doD?@Opchhh>cQl+Hk)IOW5ib!2o`)m*WdPVKCd8(+?_}XW?>(@x_v;9;d zsZi~+UG(c2wa?~jfI+p-7U>`NqzCzuz<`i zLZXU;w&k1u-V)RtE#Z}H{ct5)eb?I1iUGbJUQy+LY9mHWB^nXN zNmVTOjd7si6b2x?L0<`(>ys9b2{ks2j#qx}i=G^gt;M0f z7945?@p4#p{cmbR^Edib(`zf^#{mIQ0t882q4kn44e(gwF8KOJj}t3fDE4Jx*o^!Q zizX{@FdD&ChNpC?;iYqhu<3f z-okGWe&3qv^WBNx7W@WY>GQ3_uejFdn~n*`my?^9U(ls%VYlu*diLt=FY43xpnida z4>{~V_E%h7d>DT2qxjH64_*9E;P^Ryc~|*-zrwE%egpA43BMuujl}Of{Frtzepljm z1AaH**NER@{O-d~oA)^ z(yxb0ZruLUuw61hZLdL88@C>pgC?yw|6GMIy)!(;ChMTdz~*8FE&;S^awu_r4p-$j zms)`p$Rh)JWJUBUm0Y%-09N23Cuwl>^z@_!PSTJll;BTO=V~nLnE(sV@OAJ$IbBCi z(UGN$EYXppb>u;ewDsIGByxpbV&1QooUYyr`@o5S@anxm$sum#!Wqy&KW2;PiwmOb zRu2CLoGwt@)bucrbiF;He9G-XJ;5FGh6;1l7+BD8{Y!2dOx_v-vf?lY)O}gl;iZOj zeLd>e_FeaU#_P*C%^LA1)XEu7pHW==BI%PS8lJPz{_q0ZWt1 z>wq9hZKuwc5XPAp7(0`*Xxzh^VhTwC(%$_eJmImAV48QQvwz^ZUz&F^eO#FsRhWDX z%TW%$91z&d8@>*$_BVWl|FQNf{SEKp#k??|Hz2%*WjO)2F)DBPV!*=-vp|^pa9~C2 zp==2_S5XiDzJh`3jsdV6ZvRL#cqo z>$4`(tc<>}TL4UBj$5+3>msWmVaP26#~P%<3RIy$Jp|zZxjDH>BwF+mp8mw1&gSG? zC=Hl*!|2ChaFdxmP|k(oR(=!MXRscNYR`A~)s zAzS-#H-*!Fz$eD#C=#$q8`nsaTmsw-#iUaLoZQkG0j^Y}u?g^GMHT{VL1YI4K(F}< z0$c-#P6-f^iaZ3cCqDiB3VNK5?1^!?E*muF|8 zM-w7D(Bo!A?w=tp21KXy7$z0{m+5f~vM0vnx%7B+RR%pSg=bu+^ysa)DGNO+6{T!? z{OGJK^mq)B9q2I~k^84d7!aM(<3y?Gzf6w+vM0vnyY#q!Wd=P)V-KcNdhAow%R-OS z6s2r>G!D-~j|UOifgYD4a{u%g3W!eW(O)Y1FVmv{*%RXmTzV{O&Y(v*R`{LL<3mNg zEc6Jfac9$`epnWIEJkDpdW=To{^@Z%AUdT-PpRm?OpnjYNsmI89&?*A=rIVM5uMWG zO+~#d^ysHJ$EL?ssHek(G7pg*=uwWy{nO)6Ky*rvFVAE}oznvs1r&|r{$8m&zlzHi z=GPJ{@DF6KOq_=!2iV(5jO)fJ=9=eSl3)?PIav&65KWS?&Kz5z=hzL3fF#M-=Qz=) z>^U|^F^^4>3j|Zl>S~U~&HVSo62END__-qyR`qg%=W`Mrt|hIYGrG`Viu?UsERC+-hM=OY`99a)QWTJe#Je&qRc&Yk5eq@`U>oLLN_jG04P4xbW5WG>G0!i><*886H+y!Z%NhytpWTtZ?c3~9y~ix-oMy#Z zBq$F4>K$pDQ`Hkz|BmN>NA1wwS!%seqI?gzdmyKO{~`L~T$|lJ`I3 zGBXtB4aw1;I?SA@FmFiiTOo-j!fP;1Vcw8DO$`d0nH$ew%jYVE84p=$KZr;$^C;{< zxeD{88nQysLlovot76FGvu~h8Ip}8YrGti(R&i_h802Dx^b}3qLMamPfRG#>5|U^4 zL!Zx2Cw+=t`pkVggFb`c0N9EA-;jJ$Q8NpD`aLVzZ2DY}u*C-D3YG%j0#t;n4i2P-8`Ucv`pbMj)CNI{VruB>1W z+?*_gLn0#1##o<-FsB5V$+?GTHYJ}?1U(A%PgL_kf2_HZpDD`q&(pMp?O1m^}8bQ)5m1d)`lgdF6j@tBt+{H((h-u^@pIWD?NE$7Oa$ZJ45V6 zm~`nplH~C~Zi3RiwA7KTI6Paq5T-bP1C}x{8{=9peMiF&LH@*U zuZ1DT!x6Aws7aBtDR1lZ+P&PFbuH#iUvh?0kl?v$H;tp~5-eadr`D4*usxR8rcJG% z-Oh=zts#mt#}>M2RKt)+#iS|*%R@B+DU41MZw zVjB7A-2?~WV_#=2?ap?_tEV6b8%bqFjDK$+MsnEwPYBx3VDtl7X!Lt%zQX{#4hgq4 zLa210=k&Y28G2p{1TyLQ)}J%z`Mp#oJ@1E-*^!=SsE+82o>wb!+w@#^vZm)-c*#o7 zGk%p$&jrkpM$biv@zS$F%1oo@`ST8ho`-+$o1te9AdpGVyZ)3x&$HmP30Cy*X9UZc zj`Vz2bwp?MJVcS(rsuSiG(GRaOICW$dM%xvXD~+^J%=I2OV87!%rtuD+;$-J+_31I zq31IvrqL5OyKhLI{dfjFKTKxQ^GoQB9qDWI$h*`mm8)3X>=qYNu>HeRyQ^Nd&0 z>G|%UOnSbL7%x5FAw>FkfBcpMq36x!H$%_qK)}PFLeG!>m_g46{+UV7N14IX_RQ=iSVa#-H~i#!Js7Qf3-|UOx9g=sD=lZ-${_GDK^gQp~OnOelil-wzcd3r(jGo6Sa@+KrbG)YK&+w9!o(o=1r{_7$kw(u5 zV!ZUMlrq!k+2`gg^!y6@MgfZP*f)An!HEA}h#*@CV&56^4~gI&N=N%nO3^TjedEZ- zB%8hDnORCIKxy~dcM^yMMbsXOZQn5vsaAv8>>DQ_Rq6S5s#ebXsBF;9VG*+RdpUp9 z1?vFATs=--oH<3`IMQmw=WL6_r)Fb!%E1O6+y2H}ZssDHG?Bf_=-Jq}jE2l5 zLAu&d3m+)F;cs9~4k+|X5cN>}*E^UOAB*kzz5r=CCx}>9$pT1#pW7j2q6s%eV9u@`vb;Zky5rjbsX#+X*sN8&{xWnz#f}#NYr***#|$lov5x- z7ipNd!2acA&qv9``go>!4jhZlDY7Br=M>{^S^UNoh0Ql38BJ&Muvc^LkgidK8HJs7>3(VwemwJrM@NZZB*ytbjf!!XHP&Cfss@#Gct?12(w zYHfRrfC{N+0GOJs1Ak!PJNg>QhY%3{!FS^9*Dy4D+$5>^$-Yc-3v->Ob4|BFalfzq znl;zGNOh1~6XgIJh^Y8EC8>T+{O=JDq`CL1Zmfny2r^49=EY(M&ER?03asO&&@(CH zaG&Vwv~+MmGDIEU!~!STf;}<#1>*QZ2)AX_b%%SazNJzFf?2_r8VY_t?30-tB5_Cv+*@}z-1j@4`bx`)E|!ePB4dOZ!^}7^ z{Ulg8k$;dr3Z^o9kAn#sws6Fg>s2uI|IPc0&fWlrj|;ej`|L&*@p{dEDU#PS4EyE8xBWtsv|D6};bK z7~DNNOV{^XtjBi00|M>IxgSHP@9|cVo=ycj8Sgy5q%ZG0KU7j*GTeE7Nx!l4{8YS> z-8#=N=|elu-xb<%ay_>DJ88e9?@22k`c-H9X*l-}rS^8L021T;?tWUg2V~vs?x!t- z^{UhTwCO*S#LWG)haZ$^dq3^-VsH!>-?E=}2&%-Y``h0Av>;P$ABwdA&%T%TC{ong z+}UOGXp_()9fGA6 zw$qNl)7?(%icrRO+B*jWu#@eyX$v#A)6PiWPWv@7f4%Lrgye9y(;5*@-%h)58hWV1 zcADtZUjLN-v(h-i-cS1q|CD2YEu$f0Cv8fWowRoXY?_Pc8wjWGr2Y14vJw`TWT_5L zDtiBiAG4riy<+35>m8)0Af{}4I57wJyG4UF;qvw>^J9F$NPT!p&R{Gm-Fp0*H zoeuP72fDkn$%n)K_#g^CKlfsC=jCW|;|Epo(@x`Jd$9Sbzky~f?5J6RXOK5yZU*$z zMJg^?@e|8>9(d5Kb)nw#+mw87i}b|^5E*-Un{bY}1pB;YTaypnD+$LV(%fwYW}-mY znX2AOok|CRm+wmxXhA_0^^PXkE`r(DH+N%F!n>L0M~v5a+7)5dsq7B!<-LL1k8g(K-wbBKCi=i%z{aE4kOec2L1sha1Pk1Wtuv~&(r%= zW>P-qAU6o_AXlg_IXGSd`ZEsj{zkE`SmP1D|1};0-^>>r%KJi4U5$Rm)0JqaBa|W0 z`V#Q0><$8V$Gj4)%G^Zj-&R`@Co*E z9ort0oUY7x1mSeyHft*K;OGsqx~6HFH}SmykN4eK-%aC>4C#hjSd=IS#^TpH4;K6BsQl9;K_{N=|IZR<0~pb}S~8HLb(^_g9M)k5tpDzfB{I?YIXG@2&KiYCPT1|80aa zMt?s7cB0SRbDMYcbLeO2Gq3ex>0ie^=vm3(4*4e$P9O5I$ufjyWDI$ZAFnA|(=P+joKr^@&{bmljFUwJKn?JcgK4LWl%dz zEPA|GB8*$H?g!3zuk`o>zVpMh@qRigamV|3gfQOe4_Fwr{Q;SbJ1p(n zt@9*@_})4z6+PyYJy000EJY3{P0P5iw|;rRF3B13>Er$S>1n;2%^%P>aECxHVsITu z?a(vz2b-|}_;1ekqwu|^7F;0%&$f2&_nJoGdreNf{k^79_+FC}iK`cIA&V2P_4or$ zM*Lg6L-tLotY3)Aif=Z3fz$JtHowv(Fx(wO`6?@LF`n*j-$;Zq#(W6@hdDDLEb_`F za4x>t^zhA@WBydEVW8|fYU1Cq)AscS{W{6v4*Dj9jr38UxHMzbXO8!Y*Q9ZTJ>Kd3 zhVAUHa0r~NG~|Fg%X4^L3_S+-+i*gQTl4#&aw|=4X*T6ew`EFfSJAx_hjSNDSrF~+eu;+k`uz(LGW6B2If;K_HT|$ z>;Eo&^@L8pIChO^!Npx4*Y6R{A_ER~ZcQ>_18O@M?X&{-;MJY9ZbwKMc%1_~nXvCs z=dxWYAunGIn>d4xWnHp$4({@5e20GGve7iyfZqUhNM0N#>M2|cWCeq}wK&mmq*W|@ zRA9`%`5Ph#W4f~f0|XO(a{cLkSR!x={Dmn3c809W7;%9*p){Eum8^&bCojVi4x;-M z?TfiYVhR1(B1!m`DIS>(62Gv2&NIm5OC8QK2sPk)T8bkYtI->}aK{+<+>ICBv9T1; z5x7*cG2z&rU|o^ko~{Bw8!kjasw$h8A>zZ;Z-mT>61Zpw4lv zQSn5OSGaH{PV$+yfIUxgg3WZX=OApt`F@c)N)L^_-+1JiznbILb#7PsC)XExJimEm z$MK9iHQ@{v(IIYum%SqDttKL%jCz zW0>k_lTQLZyFvUuq;#T7QleTvu&eR2x{?KPx$c)0rH*zac3Cq3%q50TlCZ4l}*KV!VzBeG22 zcZqT5nvHIh9IiU~U4+xM$+ORw!Q)*+X6lnYC#P{lnm+ke>SWPk850?+$ZY3JUfiby zoP8Q*EyC%m$R#yEHOndz_VDrYErbbGa==(V=!UQQ;xo=YvD?P0ATc$}<(;zo@F8a_ zP=}&JiE+?zG5+D-x+%HmcA|+T4|ex>dkjs^^qDjwiR-2r30$d+2=U7NDu2wh?>%3D ziqwagp;V!Sv`;?c(rw!rlWDB}W_BdLiVbJX1&Fc&-~Sh!?A`%VQQH|)^||vgXdIG( zRK?e!GhH!TkdsB;0U;@_m=Q`#vl@<}5VI)U_Qbqf0}e#Gsgjs4kKlrecw!c6PfXH5 zd17|s4Kj^w2t!5SnOIy9d6SX2xCj!i$bWl+O@VClH^lH}1wQ(c-D{7G*Ac?Vz>>n> zU?5!=fy>E?jJQ!q2T2ymuK7@R&4&PkrW!2>#|NhJBIer>e030TN`w1CU2W4?1N8y> zohZI+Yh_{t?3B3OX}YS--w3<8eW%kX#OV!;VR&u3i%B3fRLBze8Gd?Q;6=7sy2|Bi++-Goz1U^b-7YJS~?o8Y}$_Ps@iG{Tb>^ z_q4o|(SJjyI06)cEg=jB>Dc4Nw>sWzPnPafdvB}ACQ0F;( zlB5SByxT($<-Ck(d^*Ei>wozMsRV(@BD;>6d zWg_e=mETF94>u+I?!_uX_7kJ0$}zij$)AaDLOm{{Pe@(%z0P+aRJO}eRVPT|e`V+8 z49V$Ep(i7pVUhVFj3{^OCG&d+8^=2w#N}N2_YP=}gr&pZ@FZR`zIX6zreVReMV|k& z-#Zvz30yk;-bsAaf8u)wG3?LMiUsfME&SfW(NMUveD7d{^1J2Cz9IP*tP9z`cQ6~y zD^&}B$wf`Z=MGMSZ({b(9SlMWS1~nuDRMNz4u|dfoL3XC=7L!k?O2$+4XS`I9z-3U z&mC;cc3$QU3>WHMC05`S6y!NCbEw$gZW1-hJug$Jj#FhnFY^oxlUTuKIWP0^TuHId z%Zxx(vPAKom$?j)SgD*XD;4{^OtFS6!A2HV4mkaS>k}$`(LT%2I4J|BMTzIt3GZRb zN*C{)#f9>Wm{dZeGHYRBP`^d9Hh*7o)KD^k_c*5(q;56voDdi!Pl&RIr(>R4Se zf-4R8_#5t%Y2{DImKfLHzCr`-pDpb_k2V`KC3K2$J@eIt5e2$g?|rN? zD+n1f_*kCJ@7Ry0?@nm^vXXwVfBx+Q01s+~>&7q6cP0uSQsi!xCxSEZT5axuzXm>S z9>L);tWO>U8DQ!Ta*q8aDhn+K5M{PnNh%!8iF-^B3vQM zEcw`VL$Cw^Mz%sS7_c6R#UQ(2eY6XIf_VvIMMU@gu)ZB`5J&a%6 z8&4E981Z&dGZ=@o!9ArYwvt(j5X3#qA@dD}9s}Vi_fh6Lv?kV?6MH+CC2`hfNobEv ziiNuAi}7RNj8P%Xo}3kQzr?LkgJ#!K&}!zbrNX=7McN4gv>8P z=KHbMqS!z4WB(`wjg}}H;VVrG@fK?>!P5F#K+jd*=fa>plJk10_U`>1F8;&xGQ%ea zq>ijycz>`GXh%;r5=*pii~xfyzT~X{j@Ujku#!bU)MZG(RoAqcp>~FFxbFn!u0c7v zD#=};b2FYfo0t=amCymqWvM!4m8TGtT-|jpiHF-9bFO1f)VUdTu8>gU2dd5~8Fljh zOk&J<=G>y|Tp@3<6+$iy?}sr!Kn4S^+W=x9g<~eiA0y9^F=eb`cYx!P-%Gjk0}25Z z);h{_De^$DIslpujN-DziK*P>C#+iIF+Fgp*hTT<8wdE6QFB>q-_Dw>^bC zq?Z(>i$}u{r;1&R#lQ~kE1KN4(W`yX0OHTqI9n9t>t*GQ(!z=U*xTmke&8{P zeLPw?Am86I5;x}n1*>9!la&r2JwfTo*8Q&(~D02tqk2)dH$FP%S49s^C^)(6fJ7n<; z%q1+r^NpM+!l{x@X`!28w-7XdaG49?@*A{V%b6D9kLGYfg`9a%H%BH>FeT@E%9*23 z6Pv@ZmJ){$8T7ZBZ|_%AH5k)7H4_|6Nf3ycza@2M*y(WP`C0_on!|N>|B7K<2m8yG zGc1H$E+`T|4a07ten41LiS&X7vFmub_DV1yIn; zum#P4j)F!P$(5z(647B$`&>P4$_m%{Ik1( zDuCUuWIuM1BW&J$R|%UB@pMf=+YrhWHcv3lWj^-~J>|Vq@ zH^?DFTaC_A7T}RJg$Sqm+u7`*ND7!b?Y3|ULiHE2(}9NiXcWhvaJa2 z)K6I0BuuTxAG4b&>NlFn^#z5{Pv23^WLOKKA0Ud&RGRwzO34SqdX;*DqnQK&8%#hB zPcuU-z|+hl5mwD)Ha1h*Ao%Ix!6Z^7lF>ve{Scfs&Z77O=O#oG=eD;M&J1gu-$WE~ z7Elm}iwIW4lI*S_IB+HiaDEs$JUAy~lfJ79|U-KoL4L<@&?optK4?z2x0?OI(CEv3kM zjP-cb>9>KFIh=fL9=!f9WD2QLHV`-%#5Xb7fmj zv~R2}AG<#c?ZG`K+q0ctvD zA*(J!PENIq|MzrycA{01}jcHo^5Y%VeiBoN0D8 z3ZPDZhm>vW^xtK%)akb(k5;Uzr7A6r{V`i*m0CSWo+SmTF4t^U#++Kbs%bV;u-bfp zX_n>TyEt#AO|v@?^vbGcgq6x#0&u&bKn@Slj%NX$`LP?ro?*FN&yUhX5JpgB z$7UIpf7J7%+(v7gJeT1*KUtgxvkc3L-eLJYfyA(!cp$@aj(1pI$gCKabM`+h?*V;v zHklUtBOCjN@!!O-oG;~f9F`lQ7G-dJGot>jVL1f_a9GZevh87c35(^l_>Ma)&ycDd z4gNQs49nxBpfsW1pE${QD3|00 zAZ#9{4M?s1H#9|i4=b46J+?>`|uHPsH*XUkh#gB6Z=ktczU#)~8*(gx=q0ZauqCp~ zli6(9?Lo7-`Nd{G`HE^b!@AkOMU>ra0Y}^91FUYdo&6&u5d;}fIm__hz5%L^YIZZ; ztiXj*gWc@mES$|=L@?EC=3}#2s%kc4+-CnILXJ@?E4x#vVA#2mjXQ;0^5Jo6Px8Ac zm%tSM1Xl9`w!pA;mAp*@oh_BCjw1g&h!(&P>{_NH5l5 z8=Ddxmi;uOm+G)=9U?qfhh30eTMoq=zH2Bo*gZO(g|kQV33gzN+;Z*#G4g`~c3_PBJ{BSDcXpF*_6|hZ z&E7&D`+AH#m!nLYJri%(|B@Q)W=B~#n?0Oh2gb--!Uw>}+b>j%JPze{%E(JKP*4NO z-Y>YFozAmQ+>lOQew8Ze6DV6ONjMfj!pQ*Q?sRgP25Qnk!nOcXyWsfhJa$5ohiIVh zX&~WU0IBV8Y^h^^Hu=ews=A2);^ZQm;++gG*)#_8+k;Cs$`Q5)m+TxPY!5EkEJxTL zT(W(PusyhB*BoJcaLFDr!ZNt#Q9c17wIAt@aG5m#WFw*Mr!EpAW|3|qA#w*{8wsxa zC?RYlnmDo%wvkw;!$d+BfAxkKw15uoE45xF_uPVk5ABC2!smV=9&P91V>o)Awl+f| z+6Q_*LBQ69aSF)5eY}XF%Rap*=u}3p3eF4Si-Adt+vYUxkUA9h>jYkf^%!{;QJmjo z^BtfhG(mr=K^fMdKhU7Eg%42n89`@iP=+<=)f!YB0RT!?Am}I!%CH60H9$p@vSR_t4kzdg4a%?vy-I^tkVgPY-XUm}24z@-o~c1+P>=wWY)H_p3E56%~uwgC=`Z%QEZCO76&-trM5L90Xw{I1} z`KSpLE*!d*_z+G7kAu!bz<}rBV16HG2rU@+D0LIPph}XL{?)R?X={S`Y#nI+&@$+@ zD3nDMdx|*l{9sOP1GPQu%e2$X9^kb3I@GsYR#)XECEiwRFF!UCghtR}3ky-)#(f9bZf4$BuC_h8|;! zQGW8-5!3|eS699=Vz&Ahs4Y%bV1IV4?*=kA+N}pccZ5eLPQ(gV&_M0s^7kE=afJZM zG!xe={L6}-ZUwfyz!KKz{7)l3B3M2~Ogl5R`c*H7Kbv||j`F6Vi0&A_^3 zH^G_b-I1X*c>+#rU}+&|r-X>AX*^7%zRB!uOqHPGHfA`HFXljm~! z<2ipdd&a#G-k>*_I>>TSXso`bD~YaE$CE-l!2Wlf5s2_h=>7)bUwVM=J_v=yXW+W{ zIqR&zi|aZ5agccpUaHZ&3LII=3(s%2P*T`zs!ELO8p7T%ZiFsKoVyPsIEg97a0?IK zjPOFLuThZW!+3#w_Jzw^!u}C2RAXA27Urp~SaZG++mnyT4dFz7p;6w9SKJ#W3T{YZVUOhGd ziPz);rc3J3@SxY2o?jWClPfRar7lS79X2NhD~K8nHQ|{3s^n@&x@ts1Wf@zJ13dl9 z>F!$tmM<^l+cfY3yR0A17XWjVe{N1{CT9y@YPzO2Qo60p1?EU9kR;7Oz$4HOU>RGKh2q8mP~7O8;)WnT zfk+J|;zv?e^4BT;qQL_ftc!U~$fo4au{xp(`Dd`P6?lIQwS>^Jc|@1z(q2Xc_%mX* zlRqg|9f|h{l2Sz;=;W~nqqlKcT|+GjD{HDw%$^cjfte5@qcS*!hZU!U<6Xk>a|-b* z!mpTbgmCuuc)EvpXH7evRJtC6>eu~?@DuY4) z)2+Qj@lmC9hlExXA|d{$OsFf4!fpDsXD*5Em)n zl59o-Es{Yyb9H=jVU_}Z;uLV0TR>StGE=SNk=S;}}H$5d2nJC?BpY0_XJ4+ z1G~lYHxS}(Rsk3ZCYMA{a0FWW{Luo9lat6WxIUnjzd5VOc9>7vKF3NTY~D76_sEAG z|60Wdnqs3}ByerL?kLi-GJbgSWSv+8wV==#^smbJrC-*s5TN9#3e|{IZulFnz`VyV zJFE%s{?v%I7uP9dM<;q-YBcZ2OZHXB0@Dfy(-&9Tn2r`qN1>Z~!dSNsbHXMgk>5?p z_%)u`L9>xg`b2Bs?Ta#0@@G`5~yxOQXZ>!*uRUDvr z5K#VxD#%Pde}s080s}QXj(9b!wqwYNp0X20SBb5GpD@0vhv?Ye95@QUq^9zj=$jGX zwv~u#hHENu?5%L5<-DN~l^FB)an_%C%vv9&^_p%{1#}{4mO07ufowQ_3$}6A6t>+- z6KeuhQBnh4V-FN{bp-gUOA&O=NNu zm+boQwCT*Db{F~^!mMR~ZMx-dPn(vCbuGP36TJXGqOHJf(*l8)nToxM)5^({2#&67 z`;MCiIVWj-R9bG^d2Sj7C-Z%dn`)3RzwJ~v4gDc$udB4ewu9ZYBAxcEN-JvHTfqKs zW=)p)ke%;Mron#n2r>x_QsGURoCknN-bZcExp{4Tu2OmP+kP%-V}obv!i8-|A=SS$ z8a%V2VOMl?g@5UX+A|$IWh5?wOnL=Owk7$;Z@XRbvJ~VHcMTcFTH>Mp5CC|Hd%UjL z7On#@)cb8uy<&DrP(c<(T~iw$oV>$ZZxh<=srPXNGlh3@ z9P3>=H&~JwwQo45S^ph#2zL)$;7Z4S0ps4H#$r4)4?|n^lB*cGWt0!8TqyDZ|JsJ= zdhE$n+V>%D6|D4Qe>PZKi36PwB?Rpypi9IlNtcTlU$TkN+*?J!1O6sA8xk<9BU*!# zm6G2FI9II_&(hnT5J)Zx6z53ien-HV{G*IyL2zX6TM;A%2jTG(ab^3|xJMQeF@-E7b7s9q9kpmPWsuO&~&M1$ux zBk>X=F|82xE8>#88zWS8K=cOT2gMApbz}yd3m0bi%c(jCX3k5AvYurQOXmYMa~^_5 zrm&=Pm_Vk>9LDCt1cy1*;5-?7A2YW!(BFv77OVr50+7PT7u1_3k|>avF1m#lR_zYQ zFKZ9ST8f$7Q5hQlvK#oxr^O)nsmJiVDJ~PGGWKDPs4O&6FvZ{S9R5cDw;0d1;mD~M z29x32r4|NoOtM{&&UGSN+{n|N$UnJ}B~Ii|-N+tJ409Vg~W9kbPm zxj@G>IWZMB_NFqP={NHhpjg3;SQW-vOE1=4Q!aGGa*Ql$rAnoXa%0kE zwW=I#JF;z)=cvML+Yqc+h&{Ui^ueD*-ea^YClwR7beTt$ptttP@^L>f$k8LM>nuY0 zAo%P_(SK0ckNnv9p2IPZ-vayB!gD3Rhxkp+`8`fJVgEAmy}V04$uD6kt6#z&I2`Zr zEBL$qRq*ujyPDs4;xoS`yx(X4GI3AvF8L(?qz`pjzu@^gzY=&~4ZrX3`ys!_`EBF( z9>0=*I2>p5yOdumKhHjgW5RySqJv<Ai9(q4Mxo+6|*yI!T`|$JIZ)GVcFmzu@<}@zY3T)6D{Ot4F+x;@f3ST6KdbARm z+pMa0b$y z`#ST&o@SGXsFi0MCiivbhf8!+zA{zjH<}xRok@3Owhp+$V*-2+sE-A~^rpx_Fxo#7 zdtL-V*WE2pP=~63iXtCoBD3IWn;*%rfIGaHQ#oEFzc6IZDTEDodNFeLhhnoW79a|_ z;dM^oAe9g~K;&TLMJgMg`~iX>x4e}YD;=e19DiC(feuf3exaw_U+4?8cDC>i81DpH zlagY!kN1#Stm_MTx<~PwUBH1Rg>b7mh2^{kOC_#c;=B?!5wLs`-!Jj3HH2)y(iLB9svz?Ubpjks56ipTgP8H&uLmf0y_r=PbD*lW8<1b{bXHMY&6-x(ku+{8R=^zj{ zMpwhSM(mi#OR9So4eK6hr}WQ2I=xu;4}BrslIYbnnRUh)`u`fRzc?M(K%Y|3!?O5s_N`GLjcp_!ud4Wgx~` zADwFOd?beOLKZ>NoibYXsqv$0R^x-^utimpJ~o?8^dKElyiS`lZNXtPq@hQ zWFp!>5V$Yk>J3(JXZ_4NonBX#KRMbadwhqD_8ffIl_X1?j>s{A&d$>2{n%|Hc^`HM zIyaRjzX|W#(lwm@ZwbWRCn!r&$-`q|jWPEQaufL|3V$G0BIo`Sxj{$1sv~=KPzGJm!9cx18qqt^k8x)MXA%^t68& zE}Sm&{T5!&TE)GfK&@4rNrY0bcZJU+qQ@a$(q##v;iV_1%SIC#k`)D#KLOt4Mq1Vr zs?6&lh;T)XxrlWk7NE_Wi{)U(fE+E-`c`_m6t?*{xkaq!&4_-S7tZ&recxkl5RH*J z@`Sw;oQ}@^g4mQd2*f76#$VU^Sp5s~=H9|z>!}G+4u#8nOf7a(v1rn)wtfe)vHs;W zfjT_Tnq4LJen?HA~U1vzLC6ld7CaJ&~*6+_!fpK`Qo?kA($gxrP zA4%)X&s1CZt6#Nc-&b%iAUfiicGvdxmM94E+3 zCtX%d^Jwh^QD8T#^3r7kzb1Ll3^~>@9dqRXFG+q1dNNQ)54s{FY3|5VhsFYJ%;h~Y z=~JCsDm`0n%z>P$P(--y+}x{*rseciCX>M3=U%!J$M)dfI+W&g_Se&ckT4OFl)@&d3xx<6OSUdc+oM7vHik zCs9Jk9Jfr>vL{@W`Cz1Xut?&Lrd^TRY^m>kthAqk>OC~eoANTDI2o^ti^vRq!*FX2 zSGrf%ZFVyOgw9x;)$=nbZWbL?Wn67z$@gU$U)-}4FtJi>Hw&yU0G;%uK1O>8e_zQC z#6gqujy`}Q#;b<(m^-)~ODf?!A|Ylne`zg7rlk_X4zL@)I zKK8hOMC7P^N215Qf{=`LGW-z7KdE*;;kX@MfIr*6vl`?6m~@)>*PaW(a_-pW#DjsK zLfq-HdS0USeMh6V=6*$tW2O@(PmB70b&Ni zOYRDQk31$toJ2Vk4m*9f)hx0UXacZ z7fH{PoQbWPiEi8N^gQY8n2}!TdD7K!oV?%J>v?iUx-AiTS156ouZ<`836G5aQX26I zRO#cGE8h|LQK_16V`*zqft${?sq2-GpXh$HLa<^g zN2HwGuks`g5#40%B5Q{$^1i~VLNU9hRfimj;#~H-xIRq67ENs#KkWDKU8t$_D6aO~{6`0PRR zb1F)?$V@p@34zUpqU4}e>^h2k+BY>eq4jqOeFZ%2w?R_YbY!$#TVk%xrLemCn}mKa z8%b>V6thDQ!FRapB~of_t&>d3B}3(^o3fdUO&F=BPPSf>xveWv9dwk8)EVOYaUaFm z6sOXrrU=J}>!K3p1<*wUF-ENnRz-FJEi`O6QcO;C5smHdMtoLt13Yb?KH^SX@_HPo zc|aYe*KV4oHq=8EkEnsST78Og%I!Dgph=l#i=zG%`Pq~|5^X;VG-b_QGr zmr)+$+9&LVxXbdwt_>p_ zg674gEj3l)uQZq!=NqVXOGg^}cWs#IoMdoH_Og>!k8e-SHuhVc2i;~@r#0Ty>-b9E z^?eWcU0oz7B*AxJ)+#|>Hi7H4?=Mf?oh4ISR-_0 zoz2+Anb?v`3Lmj*Q4b|`vV%Wjh3)gBDfp^4$^MLpJ5aPEb&?T1 z08!A>J3RL$0+qe2yPKV!2PH^AzWU=AJNeeWPj3A2K`;SV4--@?M#Xf7d&5Xa>I;5` ze6Q33pguLZ@MBOF4Qbm3Ok0c*^b~8uA)%!ZZNyLWs=xE1g*+GY4Od_F{jW-i`m)Vm zIGYg;Gppe|N`O*1{Yy2f&oFlzYtkTH-KP3M^D|YfLafk>cOC2| zWGbN+s+%+t?FETuvzk`!ojL4vR;X^ue79mTcWD;$E&1%WKCFbrs3;j>3zO z!f=#mTjh+Y=PgVAJF14b$!iJIXH$=s*9kBLR#W$DRUs{mCX(~tBK+Mk!=9lA@c z6KjOOq@k#P8{#j?Wzuj?VDF00DC!t1)9Jdsi)*cCe4kO2Fb``RO&nH~#3s+BsGvDo zh@sP(JRvP>{PptJ)BZEQ2csWDGmS;-Qtn1N`LHnmiTu2*Pv!Z|&9Y*61|kBID5r3! z!qfKGJeaQrHz~UhTbAcdij3SaauN$BPVDr;msT&~&ziaX*)X!Ieb3r&6Y?~42I80H zbII$F;Ng1KJv%?{tG`Jkb#S5dTA6II2<@P*)!?7w4I2`f!UmSZH>L*LM?@xUn3>1)3FV;26+FEw zuzy$MNt=w;y@$bBhT2jEBsy18gv__3ft<8D!ss};B6UnKS9LKu@+%tKkN4dE&r}y! z%OC!EXwj|J)WE9$*1+jqQppah*_PY+|?sd z($eYdC`jeE_|kxWE5^(2KQOb|X8GQgshS>A0oNg;Wm-i}PXs;wk8!>eJcHBcJ3K-| zoyp0qdxds_m7A6n!gM*MwI?rCB^z80kXtAGUT16Rtm^Op{;+`~QuBd|hiEz6eU{$g zAfo;n>?>;ieM3dLlI2QM(t483#|(36zUbdtTY8KlqVGE!IZ3vCQ-e9E6sE{>s|>%= zAKe68^i5EU8!@-_IibP7Rhh!#;o0SwAs2lflCT?g-HXD>9J)ex|XLE9v$IvMqN5mUY$_dO4BxxO0M-A@|{&1{D3a8 zkpj^%SlV?4n=a08Pb@z(5Zxr3L(EV9{yWha_G5E|fiya;DQ~6IB!=wQJ5#QJ%R(#h z+!YtZ3}xXy5g4?cOgqi6uWKKH>o3| zCyY}cvZ{e73KP)}ybfzKLt9jXd7>Izh)X^rYRQmZ;1e}KZYaD@`p$G04`$me3X`lC zTdK{2Tt{fIkK;&%=@3xhREWa#bJU`vw|NzPq7|l{QVVt{MZH|&!>jlJ$T;yc8TT8} zb#fZ6Z<4f8HnPM|K35c~ohjJPPFBv8uH?s|1Jm6+DpUv<;Yj@eB>8dH^Vjuz9_Wk? ze!Of--TGV3ZQB$cot?u*{?Rex@K6Ce(UZlMTp`M7J&X>e^{svZQuHnPTBRzJw4!g} zi6Hvcm7-$7p%nZqqzn96{cE?y$JTX%P~#fmS=q@Q0Z6Ncj{J6b5q}%P-{Ws{gk$f~ zPlXcZ>GE$x-qTMt-F*IL_)Pv9;Zuhvnn;%U3Yc0fV=D1yB`DbUpCst{$WD+0-vR~S zbqc<64O&KVvUUnhWx+c`f#(%?vgsz$csU~3YyC9Sl+XBn{XguoKI41k5Nv`+#s6i1 zq8^P~&cgb0IL(6lBI~?-p5n$0zYoM_3`Q_PiU~1_^>C;Q^nBjjZMk5n(9qM+P{1r{ zrzGofH=2-mM@gQq1=9W0mr0MM?VI#yx~%9Ye23~z2*k@SB1YNO-osWak@;M3*DIIY zy-S3EyJbxQaP0DGMsNfv9?vm2-(!Hudb+0bO#*%4ES0<|} zQ0NKK7MWz7c78@iDA|zdEL+Q+Jjot{s^3g^2PPz{*c5XLSB26vc#1xCd3{qpue>+T z&Mhxme*xt=!q1!TIs!R`<}@u@{{pykuo(|~Oi4Fk>q|a0f(ry?e~^fALd)@SBM1lL z^<#Me9+%&qguy#ZFN;S@UV3{5ElHxUp|B^%lJ}dK9Lc*@`XXNclsw3J+|iI3t#2AD z@Qx?%R|#3`$qPC>GS}N=;C`7dn@+sQz6{d7Y?Um2;pM z)*7zS#!Y+wBKsr6SRbhS>%#GYXq_WGHel9S`J$`W4TcLvv3!e{bZ=@0B>DzRS2Xe^ z9@a`3it)0&I;u~iZXs%A1M{3h4fr@D7_X6WJ?<`+R0LiFkyBvh^MO-OtarqCB}kbi zlPw(Vu>Fe_CPP12`+xM7d5%n}Jt89*Q?No140@f(C$u?#i_of^x|w`LN9gfpO`&E+ z7WOP_>I?~Pwq7&zbM0CB*=4`~%6@h+#w6WMuhUANKa%%&3Aa$Dt>bA2#`gz5;2~o> z1FhyKEajk2%5+%q6*Fm;+(OFefwZ_+ec?xBf;KQ7v^)l4Q#VoSEg&ylmj0pogq=J5 z17%87>nJ{J6-W{(=3aiGSn794vZlZ^Cik9I#uzk)f^q^QD3tvOQ%;cnFb}E@`0(Gt zXKM54#JXJzU!%8Nd{tgnck0T*DDPY8TvtGZAlr<@fI3TBB?_|Ak7-ZlJ_)nrj{~|T zW7B2x>=KIYmL!$F7B6}H9%;;Z`YR~+wCNA18gLP0H-z#A(vc=rxtCumO>&c%CAOhP zp%-KubyhCD#;4R$e9#=sv~Mz|-(WN`v94FO?{vP>UFou4Axs6&V<^8@T2`Z`^U|_! za5Q!1U9qbnjxJ;2DE;@$``P}x&MsH_@9|9kJwvB*?yLUvss7u4a9ID9OR}M+9@&3a z34wfO|26Sd_22V%>-K$q|K-}Ug(X9g6U~zM@M05kEKQgFnqqp~yNQtbwOO)r=u?OK z)MbAHaTAljJ%57yB7X9;R#4WfhdgrD&{%y-ayQW<3u< z1_tyXYfP9%*mran0ZsARj-EJ>LEB8Bk-dEX478o8ogu^@0{R!i8^T}R5%kYjOdy7uk*AeBjg&gmd&o$85Mr$qYqxMjul96QOeV_@ zb%tjo11Yjf;gEbxm#tiZbS%kxm%oF^Lk1z^f$RIIazsZHnGxey#MYbeTiJ zvye&zp3{y7&$wam%p|FT=XO;=2A&Rt4EOX&Ty_;6cuvj2^GlOYa(_*f|4VD}tgh1w{)AyR9uyLBPB;px>U=Z*%pVPzc}fo0XIg>$fHP?Oyd} zw$Q;kBB~=El8Ctbr4*04jbyu?_%$WOTBp*ND+8t}v?LbQD#fE z$v48PCf`b(aWyk`O%8vZtcrLlAw@7P!ZNVUI_p%atG?^+C@5^IbYJy>ybp#)M=x?j z;9}dXou_0e@CM2fY4@U_L@`O>mtEOWKSX~D=6Xqs(R6BGb(hhn*8{_YC=Z+^J-S+a(FvjPPI7rx)!{RyWy|Y?#QZUdc;}lWN`51d0g)Md2_gDl`;^ zXXeL7-Nz9!e+mw`azJQL`KTy-A!UFF$+YAS z!OPEVy!?oG!~774J~HY)iah)I5Gi*SWIXL&>nMeU5u6s~2`$FlU!p9`AJT`)U}(s3 zFrs+jl!j&oOF>lsp5#LWn57&Y5dDF9g`0x7CsYdVaepLpT>c$N89QLrYNc8+h+ooc9nXkoqclKA3gngv#amd&Vv4Nta7GvFY)N#XAVV)?I{?gK1TMHAkbdw@VNZtBMDUQ`d51&$*dVYD>W zv>e%r{8zI$Sh&e_|B`~l8v?MF-JUA-oAo~?h7C&b`bP6R?^-V!t$Nrw8@#NWf= zYq-o~#AD9zmme#L6sF5wZdWX7W}pem-x%mT;KmI*5TD!<==@uLz%_YW&}=|HjgVX& z7qgk^OQmb&6f3I};e*C7B6@MLlhZBfHiVo5aKIVA^#w-VtIMJd<~u?2V~rgCVvu_- z(D^zAk8=w2CjKETFmn^f;NkG7mP-p-k}Z@1Mq0%ZI&uxtJe?{r%q>Rr6P7zWqn#h6 z%T57inea;1AXF3fD>I5mH|2srtXdpY2lFB$DAAW16&-X%@(BX{r8e}g4D>UAz7*(F zRgyN);}Y%1z%H%U9`JYbte8oRSyIcgBj;$fiJVBe$PtQb3mzt6FXmwUYH#LF;HH|a zSs2F2da@ouZ!4lPyWuYk$LzA|5&XoqOx3^1`N`bR9iQ|Ug{1Lf>a7XHqe3&>mbB>9 z+C|08)oBfS@@;|))}WwsH9|sBjlv!vK zEczg(e{oyberF!OK6{P0&$*V7gl50d8jn0wLURCK^{qox$OeRrB0N-w;K&y+$F=-} zY>1wKc09UH$s2pQ;LzWH*K)94YHB(V_63@fYM0|y>uEuO@WK({MJ${J#BX7vb^d9J zbaVU_6r-|!cLFs;HxvY1uilAoQ{?B=S}3)mA^ia*BNUr(=p!*XpV8yK5ONScAOZ)N z1h)X0f!;hGKa#*c3->UfEK2T4YRh0vn9)$e_@Jx*57JWp23 zXC(GMJs8FwC6T0%ZOyBOfHO(8&pEgQX1-qT8_f>)q0iHQhSoX@R{q;t41kPRLsovC5ceOg?C^B00uj^&k z^F)RBNy{qQo{yY@Ma$E2v-7k7PQC~?b62WJ*0Y#V-kUH7wkOec#zs5ob=KrJjJ#Tg zv9t>#XHxs1HL=`K090R_HY)rT*0?V5JiF2QP&8MO%y5%qZ5#>2;7M{1VNKzP56RhZ z1rjUoKZ(qKsNsWMJJh6WPreRY(M`5{QkrZNjUt~M%E_4k3VrCMN?{FE(fZfW;ACLF zek}0D>z558iB`*L>#PBpJ2$w$e*oO3%f_?_d5l|6>Oidi3{nXTafAJcOWm%9=c-!D z5R0YwI_rgl?;*7UO|pKtnnuV!&Q%#$G(XTJp02RlMVL#A2bhv9oMR1$>0NZ*!SKvb zJfF#arckBz*hQX5k;*#`IKIChXrtY%3HoE>uHr=yfONJkf!a=^-|gX_H4NG#W;i~4 zraMa0P#dPE%Z%mHNCi%DkNZ2s%NR-3rOOuIB6|Fih^NOri)c}Mk{|QObjx@ja-s0b7mU5 zD?F{G28SEXPZLgFINvU+1MgLK6ACm9NWF(Y%=CDKt8_8C{RyCi0S>Pbw{PWQw9#tZ zLXbn)RL9vdc1xf7()W+%I+hhyJ_yrHenq zAHdgW{(#MIXEmDNtqE4XSDoHxPB^bC8a8VwFgZnLhK1 z{Klr@3ZW)6m6;QRu0J=LT*3Wmy+xloh)z{~Qsy>@E&IPvg}c9jM?`%y+aIU8qTQlhf2p6JiWT07O#{u7=d^O6E~ zU3l7J(z($C?#M}MDZ=iAgL94mSmQY$%!2I=NfD?%QQ6AVb83u=^z)Pj0OM>eWeqOPfj4zp3{w~o{$_4njN zp;kLm7u3gdqR=@Vsfv26yxEMmOVly-Oo{toJblc%pRWSwP zQLsc)1*=CSKT5(O^umM`=35V_(c(_Nj@ZE%u81kefT8^Dz03!jcG3gSo%isolkTr1 zlv$_<)b)f*1N(bXNQ06>6{^OjP?|4Y=2}Xua3J;tEn(iy@m|$?IFEMmP`HKoApELCrCd4{;gn=9w=~dtpHFOVQYE+h_bL{P#Z)2PImy zSxFts;>O;F>OHvnz5ojRv9EJX;nxfJu?y|%rJ>3V1k0gC;cv_e^UFm~l4Wx?Kt$dP z#Y^rJ%*F2#Gwa$GKn+#CAZg_{o%8}OUi@!6JB-8R_m4WbVIn}krEnvET`4SIttl@xX6_YfB93?rYVph8BdOAYf66aAl*yjH4`y>e;7nt48 ziAvCsCjyNDRM)fcLpfUFN<1?bcmwfp#g)up&hb2Xr4vu8gukw9@$p7wFI?f0cqo5? zEHnPWYdy~?DtBHC{2OFK(`Pmm17eMsR~EoptIURczqw7AY#k%8Sslp$iwRVfV$PzL;mpy4^k;>|dije-&4Cg#JcqGb6dOC!FUTY(C`j97 znksPMcr}jxTIFKye;fz-oGi7rj4JJD6|AIAc`VP4rkIvdUORf^2K5;l>;!2tx$ma! z?>i%ZO3juH?v3LVQZxMOI4+%kmXn9 zq?h`>HljZ=PMOXhT+K%*1T*_M&u$X>MNvL^AnHm-j>mew`9;B`ZH9MSzYz~8)BWZy z$#sXyY`S-cUZv~soJ=acF5$JhUXh$=VCA(vzSG!OXB+h?s1ueHpks>d`uyVz8`2np%`X+Rrs>~ z>zHr5AKDJGw0|8k_GPOV_}del?beQQ5puuz zKX!dV?E2zB?E2C`<&N0(ur!&k=1+ZvKOjB<^V~fK&ahc!T*u@kwjo=;qdt`6g#UuB@%`v^_$>jILmG9V0AJ zg>tdbYE4_8;J4ehoNuk^qzW%0>{*4%|KLK+zgWcF{C^H8)h8A$iXTPm#?aFuqAJJ)9{~AUYS98lu8s1kwd9*x8~9xC9yAM;&cVJ_`E@FX3c^ z@Z4y!BwT}f6fS2i4?rB|dd`ZJPM`;pzahqsU!9MwI_J|5b3PqA{L_s&pYky-<>dNW z&ZlFB=koCh63A42F0Zwdro9cMC5S?+50g!@f=Kj^BzrNzbPiJ2J(o^j7B9XQ4sieu z5$xQXABvCrGeKi5)i^?~jY>Z@YM457h65S=An$yF>XwVt5t$+Yk_P}Y&_-&49Hdj9~8eiK=Sr;RPwtdxms|gA?hU*pYZYvbZ6a`@MtUX z26La0MD-9Ah&`)Qk96+4eIxnuJneGPz&>~X4)~m>T@0q0?FYspTFjaGF?XH?_%jP) z?oZy5Kyl1HD1jZw8!zhBt4|+JM-RGhIWf@mJSe@awAqNY1qQ#6=YRxc3rA|NPTP7= z#_}yENV+HewI@&SXmdV(+)%Ptr9ee*t%ro?-g0uFX)_|eR(O^qPK+UOw^Nd({sQZq z082wyr8$SeEGg$jTI{x75Z|X*{Ydq7q*FI1SO(ElV*81l0WO}}Dv3YF>_xx)jPzC# z$)&vnQ|{_LewMCe`k%Gyz{2N20#!Lq4N8;Me~y%YW5Dz<`N#TGwEo@qL3m`0>~u_9 z^0&vmlPDS|)`w`$5~WRF8F{HK17_<)lFI2n*z1-ueZCRt$kDms@3Hw!d%7pW-;84R zxH@3o?Ul65S&xs_a!!S{_BElhyQKu{XOpCuyUT~CxGyKg**b+3YPICVhgJBFDwUJ< z3aRWOic;LVHF=npShIBcfTW3bwpc#>J}dKHrQf9tt3rq8%D1@tj9om?`cI6mnMaI( z{l_mTP$hx2Uj|kD8*`r>!8aBaE@UAlU%I_=rdkBs!L}piwdgg;4pL>hn8`K+45g@5P$Kxx*Gf{WM)T0SM(WUe230zJ z+?Z>u7VweBOL}?K1_r`7qABP|LKV>^Kn&~VP<|k`;}Twx%#q%Jd7GeOAlf1ba%N|Q zB=xlYgmQ%q908@g=Rzs(xlqb`E|lOn2g<%}A{#Ssmda)dVB+}r44j!1km%|OxP+!PACREoK=8$p*^Yhl7%Fx^w9v|do90SIPPL=ak;_g{M z6sqfGoc~!Iu+>Tw9u<1(YBBHUylykP^k}P0eZMaO;!>5`7ey`z zV0q7!I97~i&`A~-)=4osf%6z40Oh6QwVvq9fgnRHJcsy!@+a9^N}gf-AXc*XwanyK z(qF-}@FAHp#PvqUblLs$A z44Y@>#(4;oQN2lAA}a0Dyqr@<5YuU~YC|B;TEMYK_(^?-DV{1(j;VixH=OqcB8AaU z@uSvv#7!JO0T}OCTEaF-)^xC2SwGkblnfAW$h^0rpG0ilV?wUo8A2is(!I$a1LGQm zANNzq{$Cp1&kOgQOT9GOmu>WEt8}AR>qg5RMXJ%W)Yb%PXO%Qsvdc?Nx-38$y3yy` zrD5baonUUGZ>C!OH;El;^!v>+F4;CnRZP`N*&kERf~fb?(>3i6?~B%dsOoLn9f8HT z_iyFW^!&L|EOA(@zt+usyvAYuez#shSCE=52?4auog%HkOX2s3Kvvrw!>1dW9p_hU z5lLamO*~?9VKO1-y-J2aUD-LCq2r;nXX>=8Kggsd8Qu=0HTFd}Qg~iutPxccpgg-U zz6o^B=;~tOBkab5guF`SLlycRrX-ax1s`hhkwQ1CWf=_$7Z~;wNw;!nJTH*(+_am5 z=d-Ev5h}Kx*hTLF&OGrUFjpp|rFCWR0kAZ97NzUPv;8=HMz--+(!R)8>jH+ifH4mr zBq@aCqyu^9JU_hsl6;J{8alRi)HwTq2-3sd^#L10g=jTo z(Zc9jjVAUN0fw@KfTlZ;O+#q~SGQ$x z)Oc$Qq^!X0aR98OYT-dDNepNl>;fkdsGCbyM$iju` zsi;$15yJiLku=rzw{N7M@Gku=fq0migtR%I@p(7$cWMQbZu%ApiTF* zE*^T0y@X>D)BzR;pn$m$Dpq5MRrF^~sH{Cfs2vH(R#zhT0?D$7FNaVAIV11400-sW z#p=8ef+9N7$|7T(yQ2pxJ;gB95Nvn1N?MO~EIaqJX#-gTJuO3^0+cg_Szq%($TDcM zFEYkS63`y3eh%XS%+D7B=UfH$LlUUsHxb7G9$xFR8lYB5%$@8UNYL~9x?PbAS)hrW z2y*8-bO+6{J4hWVkm7S*L`e2ipJgJL8o#gG8QHt9J1_FgQPLoM>8&L)SK9jrVb~Ao z-Hom5TFA`eov7@}^vNsz@tXvX&+CtyUp!iW{0SU>UVn@O<@Cp4&ce;&INKkC>xcEn z2OCs>+{PkHHtqkJ{&?>EVf``i#s91QG5hyN>kqwODr9a#)kJ+`QHaH7e}~h0jSl+k zQvyB$vze1eYV4B$#ovJ$z9{<`e-fAlu!D#3lVEE97KKNujE-ZhJBO944j5eEG(rsY8m-D@_hQMYXO_8}{*r^fSUzfASyvD~SJ@X51<`|(77oOXcR6=^@rc!^ z2afL6PR>2ma4ILA=z-Cmi@Ul5O|*YYkO=HljA;@RdPS74#2|w~9YYVgn9sp34$qiMo%~y2a;M z3qGqL!H0F56l7zDf>a4;Jcjeu3eS@sHg=BkJj+I~9`15ddwvbE;L(BvC!{2n<2jcA zZ%a;TxoFC=6J&ROOHFO0WTm}TpO^4QEe@yAGWFa@i4isO^*%U(SoRplZ{nRZTjG~H z^{!`8#(lpMLkTz{RR&3N-iR!0NDrFs7oO&!NB4rD$$BJbV{GDdNwkAKYj> zVG7~R>UzJ_Y)Rmp)==GNZtv_b>fBq@`F5Fb?xJ3!sL!+Zwejd1{)K1Q^F_1M)#uv8 zu`H5}v*uJnNww%rN!Q#^w2`CyL-29cP%I>s7R zFEZ3$F$d?Y*o*?tv;K<9S(c8uJkOys#Af7Mcc9N8v&)Y{HP#_(L-Yw z4#k!QGty3zwCuXK(>1yhmzn-`1=fo! zogA&{#R6))?0b}LtSIpxr(VhSBC93no8?(<)(Aq-S!+V|qe4 zWn@}l!=Le=x3`ow?S58a1ixG{QZU79LtBr3X`D5UA+3AtN1f7RhXO9f-h}m#T`)TB zV+UKxH>8%XnMf|nM}x4&h~)NI)mZI&9K{-ebJr9~g1h;%Qe}&rqxwqB`!A1>{$Wd! z%x|}1e?5T8VdvbJ@&scif1F}*b+h$DK7!AZBz33DW?adPNZElQaCM~YGL&%X!^}~i zs>xY<4;dd<84JlM>GTq)!iTovHtohY?45*QZciXO?NzaIZdFTuZ2SrwV|`QB8qDHX zbuUoDH^A)^Umn7(RH*G+O1X(&Qf~b#FpJka+WvX#2)5%f;9kOVD39;Ts_3Zr4D4R& zWZoWFnUI@)wL9!n{Uw_nWI*7XYh46Hf{`;R$@-D3XLBN>SyC#mQC?Z-2-dCl-1Za7 zWg#P2`AI0gnB|?r1)ke(BTkMX`SryzSMCqiZCLbWwZlW-Xw}QvJL0ocB5A%Ot&lzn zB6PjMx)&FoA(fD;4k6Be_cz;@#OTKJB+UU~yV-LN?QB5Z$_U}Tm zBGJ$mBb=OCYa71`xi!t6);g_lRs)?-*xb6Tu)HV_2VVwGrYQB~#AOmc0?yT&OV!BRmPdThST0RUls=bmP;2@r~)gmK4=B{P^DVvZpvCozF zSjl<%QLP`7c}Pz|ey0*l=F`hkpwMrrh(LW5fuT=9@|nB2f7dV%`}u+&M?f61%piUxWAjp4B6&`4x}nNG@(F3sONoJfuI| zKkS1jU3cpb9m771<-@J|!{XczRY=z{{ZLQjt(uCY_o@$SJy_o0KdTMpAs6kKSUn2O_N;xW?(Y`s+@| zY5eN=jpFw#gyL{J-Ff`vf47UD+nt}MsN1&xBQf5N-m<`<8u2`Wih`>$@}OiX<0Q*; zAoL^Oe=zJj<0V}-V%BGEaU0IRy-MEtly7f!ntq!n5B{CszqgJQZ$mDjVb34hp{|D)W$B8;6E|B1 z=!8@JHdSPu&mx9aVXVq*P_PB%vEV}WAdICktAspOK{m;!+mqE#w2cE1`*PU8*iZ$(nC$7$_PNaUh&&=T%xK+ALd8M)Zu-DxN4snZk$Sb7Hgo&3stv zTlR6q2O=yFKc7j-@~%2B3hUId)`JKUK(mX+@0m-;`ekxZC4E}6c*ZlTOU;rEOa#!a zWHrmV4P)fPIck|y7XOCak7#8|hzo9Q#DQtF_; zAY|PxD!1m5f^n2CyW>(u%0|nfOp0gS zdCy5{D-%ML=IYhzv5PgB>yRn9&e_M6zwvwY6SuWqmgDQ{UwE8v$7c-J8|7Ppb=6KO zXz(*U>sXXnk55OB6GRtZ5}qQga1y=)$0SX295zMd*gX{)E@S;HOMLPjd&F|u+Dif z_T^ICGa{F&tuJx+Idd=_$WjV6dbt*oKi+iNMtTpz7~zj!;Y^(XzYEG5Y1t1cQkiww z;^X)DxBFvdw-V(y8y9ed@~zVhu6QwVKvw(&eY56-aFLi?;RPQc!3=X#w>542YGU;QJ<%6J^`Yb$^Vd$-~4R{WZ^eoZ$LlbTo!gT z%+Ig=*Of%7wWHOe2sLu1w7J#O(3{he^MM?TL=$(|1}MmL*L417xkix723b?^+;%px zm&QZqmj<3=iBA4`IGxi$A1*!zOQr`Gmc@`UdujRytS&!zuIv{#W*<{pPuqLouV=)T zEocVES#9D^rFR+?_BdW)4G0J3Qk4$FszO%CY$#A*1FqOSWnw*(wSd& zG@v6%leXow=bTG)d-^?Xm6EE_;aR)4aM4t=y#)+NX4w)bXY1X~sZg>&#xiTe5_5aD zFjgSn*l#eu0=vqMvTI*+`V$}>A70Uz_Tmvr?te%lJDwd)ZY55S& zqJk+tTybG;^VGI2CEPg|LG@SIr`rQew7sT1(O_1jP@^Mre4h|uJa znHb)kU!liC<}FKvL^m=V3OskcMaArD=?|KlJa^zd1^IMldw|u>r4ZwR#f3S98hvX3 z(zGh4OJBSdh-doZUvvB7U2F+Q?F&FF2uB*5IzcwA{PIu4b?=%28)CDOz1G$mp-vocKtR98zuDY9yi2w|EgS1zu-5aG z_IOQrrMA=P9>=?5X{7miBxRUh~X0`|xo<37K1| z(nr)rs$v^CZ#BFncr&p4qtJ?vjuN!IOeBmn6<*=BexlZiZ>U%x8yuHpPMr6(f!wDn z9wJrNh1@p#XP3OyeF(WS$|o`k{p1?tR3w0mqI29=J^~Vyj4EJH=sIEA14t#IlD(0e z^maN3%7NB?4_b>Mo<5f_KSvs|)wGlhj5SB<>)am%>yfRd7xlOgbnC6AW@JHinnBAI zZTS`Ef-&Yb^YI|kZ*%h@wvAKN5cag6MJc$A-^9aoKTCGmt(l;br)35DO*1k-x1jvm zTb4kHbBBowF;lFelI}dxT^7%;kP*Duy5~nSf*a>D zWEH^X3pRsQqJ4q_Gh7xj8|V3%r<*$%ROzz6flYI;^=6w#UMf8D3#=cSJ*l~M-QkJ! zi4+Kj+njB)m7EN~O8@t?{SIANjv+G}C|0F4SlZ8Qd0bBM@O>5r3WUk@GNjblEs(K$ z`8{gv`WU;IydabKw@ZhQT~UGpGJd1)Ecoof%b~ZNfIocj{`msV-^?xHhgIC1D(BPe=6Ykxj69ztG@XpN+UTPXPc;Qv} zWMl>-vexHUgI9*DjLAkdc&m7Oj5j@a5$J7dC@NNHwS6pz=jZ};C5w#M7LwW{RurV6 z5j)I71t_H6R=vy-Ihw1$I)9bmi^IJp=|H(vp#xs)BpsM&9jgOX)+iMyvYa}? zXAM57atEyUbzqkDHyxO3y`ls2tQU1)zO`8gYOF3DSYWNufhE@CDqu=OtVeZN5O3Y5 z!_q2ig$@fhwOVxeAqj_dSny@d*I~h=b+rx)*Ry8na6-a<9o{J68XfMH@Yy=NOTu0q z?w9Zw9kwJ~pu+hd5>Du_SHe%|u=0X_ zOozqw)p|gOYb3lNa{I_ z8iD+1{v-lF`=CSS%i_#&3{81p}%94{XzU>R6Ezc@_Fst z@?vf~(Kw;r?JUGbv;%_OK6L`9_{&UBhbOCjMsKCgR_k-xpCNW>9`@Q8l0KEA&>Di49X+1bcR5g#Zq=MoDJm6$1CL`(Sn7i z$u+%WxIfo9HNP-&w!RaTxX62QhbZ@lM#h7out$F{w(ku6Ai(;>Nr~vLboWXU<%KU0 zb*qjNz9t9%2kQKV1(6Uz#)QAHG*V9xYWEkGN6vvfyxa&H*(&$8+LeTVn#s>aRr;3F z_xLV2fG> z+yZh~{k!!>HrWlNL$1DHbyu*xJKUKn7Ssezg6cpH*N~mrwl91-cW{&vK8f&HJM1Bh zON&J3x9y8`NVc5TDAR&0*v+FQoF}KeaK*V%ri|7(zhwxEJjQt-q+O6hb?*5;SLSyF z^pF>Bu5)AWgEVlA^?Q`(tb-hBwR7XIe+G9Oa&CN7(t4~ZYH`qZgdB3FJ3HgtsLIhE zj(Aq1hbr|T>*1(Aa~w{+@b<;kQWq6=2q*Te%D?LL4a)P-)AkmP%6ie_YAE6hnx7}< z{w}LnqFrTu8CO{mICSs$&v2DBl+h(sc7$)Np{@@UUmPD^Y9bhzg|=0+@HCAvO7{b! zRd~y)RuE=E%a7v@A+PnDeIl=b1$J>7F0pfmdtAayhJo!_MNYeUl9G8w#_@Gnx@?at z`?J!luuoy7SCcJ$U!hEBSi0FO_Z8wxVx9YI0p;-ofOGAhNN6>~n(|$`Y-nrk>&#~{ z@~u;A>jP}9ef|MSNC89pYoC)eZfh3i(jhCLy04H+iIjW!XWUmPhG=aB#1a!QZaa&_yF!|0XxgN^h7(Uh8}5i_}YnXO*+FzqIwRlQkykw8+$I6nb_5_0%qF^G3?V za}EoQYuSMDoRphI`$Uxjxv`x1)c5Z@d3qZ=}Lt3qJ>saSWcz6Tg!rD{HS_;l+50zMqPujs$g7b{U<6ZbiD48ylN8PB;B4ygOct7nib-n9m9PZhazP+?Spn z3$5@n`Dp50GD)~3d&wu5)XhC4oP6f5ODr70EoM$Thd;(Ak>N|(pa`(WGcJJI(LeoE z|D#?FY;UmcrCZpD9=g}tXs!=ccHzp|*`H_4Xva#vC+xzV#w=CEe@1@b-FpH%}ZOvpVjQz@ivQ%Mca+jyCAQX z6hA#Sr|o39lT2QW9eW$=)-T)A*tAYe2os+Y8o4B%-_8Rv-^^8KD>=(zS%H}s1L3Ls z*s>LZEp~|{olD>Jo9;6np%g`J1~)94Z`}{50_QH^G&&C{!uZf%*$-hnA%wBl6GbPy52=@#Sabq$!Pq&Hf@}RnxyGs+Yxl3QV*jGU{w_H z1Qa1qYKjO|zO9Ht$l=XANW(fe3VU&neOPrO9Yzmi0NrH+dPwzK?~XSs2li`!CcD3$ zH`kvoz4ZdUWp|bIV5X;3x6xgwGA`*aj>x6I=%Q?IRrc!jgwN@(3|&HE=Aq;Ru(G-- z*Zdp_wL)eyrdz^_1{L9Y*4|Lz9e=;@4my=QHVI1C3eJZ&MOV(>|6Y59{I)^}!iqHc z1>*TXR^(Ty_iqR4UWWdhG5-UK{vLq-lIpm-rEi)g4?ZNgF8K|QOyiWtgWtuS1j|oJ zip((G?K;)%JUnaR09 znxF@iOx{s@6nBPM%fYAte`WpZ2c=0*@>k^0Jdwut(MseI9fXM&BH8~yMGH|UZNfqEr2q$Nzl!RZ1&N_h|n9Uy@%eQ}Y>&8a7kK;tmw?!G}pjItXo0(9vxZ#g4Ml;)KzVA1gfxV?BO0P0zxHs^c z=Z6{BWcFoW;I#;6QP!5`6^L8$pqR-x0k@bFa0{jtaz1ZKq==&!Q*Rk-n4V!@D4DV3 zFvsePy{%L$gpDvnZ2^NzSv|lYKf)!M1E7=N})eU4AMq zA}1^w-ST#o-}REwaa_ptN-EFwig9OY$hDpVZh85$pl+kI9H@H*ck!~-H)f!IOhf%Z z25Mu?2zo2oNH+Xa6cB#%lgL;qiIi!3=$)mNujp#S9}>N+LLeOfX$UKG;QLDs3?U7} zs`7Qabzql}Em#E0U9ll7p;ZF%Ie? zhdDvxK%uAo10q;|eYX*pB~RPi%%j0#x#xDV6v}q&f95&Oy=+vzvqQfGIThPjTTV1P z$Wk|}QSmJ3O07ZVPd!mB#ANpP%>IZ&|jS(*x<3KBW{`4|<7cBO&HAR^59X5uRlUs2Hl zoQBzFU2>xMp6rubL#vj$xSHMXV)Nu1kpjP~t)f&qlymtD{FQAL<-8cJg94)GZn0eO z@^}ggUhya|5bpAOc|_ly$6iWL+fw3|jwW^!6D*3A4`RNXhqG*r;~8pqG<*E(N!tuM z=6TvKmJ-)ETGB(;d(hu34oAD@V2^QOw`QI!Yx#4y{=99p)QM|)v9Gyx+MSM;P<-;8 z3(w>RW|<6O`*IrQ#RVa}qZY`Pa9X#3t(2wEA7w0L=fIZ=1)A#^Kb}?Fo4F-o&ZPcC< z(Per_=r=jgZcfD<<7wgB+<(&k#*Das5>0PtHq3uC#;>H^R~OHV{>=$LUzNwN zh+9cL|FO}W{;@w^T;Ruy<@VQYS~No2H|PTnD(dwYb&?!wqGYBQ=8{i@->l`EQf|V_zpXwm{kmsWPcwAL&Q`A5KFGPkvz&6t z09Tb$Y{J-{?A$wk``exU z!G&~L>a1qBuH~yLE_DJjlsd1}ZzJ{F<*I;I{4q40FD!0`5U@c*)u}V3n#-Gu#3)V9 zW)-W3Ml)jlIvVw@RC#lI-)ct4a)VpbNi-j*=JC5$4(jm9uxpq5d#lrwIN!4hw{_yb zB_%aO`>9$^88vq*cAYxY+}X?yVNS4M&aTXb&DEPyV^xY&p-u=VaS+?genR>>&|HK% z!jWYLlXo7YjM(hFhM0lWUs3T8N##(3;)NokAEpYJk-r;h%Tu#@g|K;UvKS$sy4#k}@_iceLc;3H-KmQ_seky++kU#$_e|{!^9+W>1 z$)BIgpN9|e=aGy2<_SV>vy?Z!aJj1Rhz&FICZ+QE>upA)1Y!?V3<`L$-ze`cIpK06 z?{e>Xf@fqJZnvKHW;%y$Sf2K42(0$sFc80t(-z$;&c)AGt&TT83z6>; zDf1>7avbf^zP-x7VZ%(<2=l|_D5-(f=}UFdTomS$!oC(r9D9AQ?`xbMUy)b*?$hrete;-NE-v9Pod-%qVjEA3K=yl{lMPCfjr}is z+Rle9Ko&~2zZ<97`(M^VABX7^`6g^OEIem{$OE%W%kP6)e#53jesc!e=7N^qDzIitAN{j395T_z^8*U|gnT`Aswj6~h+hS65t{5$0DTf-}NA zem2Kk&Z#)h6TJukY(YL*1wRo%ewGd*$T=t*Kq(WiyUjdkQ#X$V$ulGgvivOCxTG1m zXv_8!7zdFtaACO%lB~_7z9~6qi}wo*PKL}$eWp?Sjr_=|M(y~>XV&zzlK3Br#J{$| zOo2~4&u7H*&o|6ZMBM+N!Teh&KBss=WBePOHuZ**_k|$Dg|J6jhsTM;H@k-keHYih zi?~mn^f@1Cg{=;}k2=tWI*`gkLO*0g-?i0&4X6X}dhWg+y|cM>y(j_idhYs@P#XO| zpY~rXG%!zwu&odz&;o`Of`ljpo5-pZf@_67=Tn9-qj@L<%Lw1PSSgH3R*#X>E|jbu z6j|+QKSWhj@Ga!Er~P&PA{f^Z2_lq!M@+NGY)?Bj0Ed7j#DAU0ZmE#oOR{a_2%r^I zOKs5odJL%IlW$&4;SvdE71eNdWinGs*eVGxr9Sq#_a zq76#2D-0!1CRPDvs}Sg6t@`Y2IYpEkf{s*3V@e`>O{~K2XsHe35bjEfUDB;Vv@z z&6FOt?R#tm{SYJ8bC)D;Fy9Qt^`fmP>g+ms!wGGv`K@Qw|AFyqtMiOsxtS+mpyLne z^m~*T@Z5d*u#wyeoLS0Kbehrc8O~FbBL3eP&Pi#u;t-1oe9ox;2cNT}`W5{$G^*Fy znXjXN>`{G>q&eEC{xu(tXn^nwpRE?8IpPe(Mfi=iRSA$6JIY|k*}>G6Ep z|NeL$hr*Rs8ortcqvdO&RYP{F8nQA_n~kFPb4O=p#Hw+cI#vqN`52ZTGkaK~=1{W4 zHy7ki4&g;Fnt2Etr051H^9_!09qW1i`&@&t`N?d+=OXWxAvI1kI3soqw ztg36=Mn^+l@)uCMWEC#71dU{M8Aa9&sxjobY!E780tnM%I%wdS#e~pbv{A+$i{?5S zj{$R&q*HT6S0CRcDk18PC38n2D8tp4O(-vvr&94GmC9w;GCUiRDxWS&O-2(G=<53~ zexQ7R{N!Ub3?iNu_=|Q6_QOW&+lMcL%7nQry%;?R>uFzm->r2rlJ);I!GQm6w`A7Z zKOSMhRMps?qBN$%?S0Gts!GzuDkg<_C>Z}A z_hWLr*tzmAqDHYFpg=fjFpA4bs-Z=ls?kE!omP3r)fG4ASJ7Sr_s&}p5@0hqhA{*- zr{l2scHaMD?@PdLd@E4);hM4u8m(W%gfmP|H6b($5(+do(QZM6}f5E}#BGH>{-(mtoperwbePcNp%4*um6lBZfi#M%DRM7VV-i%0e5chk35d{w_ z#$w!!AKd8PyYpR`la?ZU3=NE5M=!INL z5VkcOE8d^R?cX&q3q|icgST<>u9Rr0AsE-JYQbIerOU4h{$jf*HY9w$`7fx6`lj%+ z*XZYr;HQB6%r`#{57-TT2xR<)g)l7MnS~ig7S_GvPU!7t&BaND2g(gT-{k^SRoKw! z?8n&trJsmv>BqgiO4N=Tl7A3qshFljyK$?af))+_9idEEAt=#s1l}u-0|LLzTl_B`+SlJsXkWdPGp40nQ%%ws_j9xFxD7)By;tBVAi+Oj) zit&OwrYW(fo>m2EzV;yr0Qx^JDX|Z(x&^ z-kLX5)NeO7g!>%eOVRohZVtc~r;p9?qh(C0A47Gr3<-VdQhO0lwHmlUxW-HsaF zOfDHXBo>_ojBs(5Tk?LMhfLEBw?IrD<)%?0Xy>&mqTo;oTtW+)h5G%{^NVo&YE{AS zA@kGGc(9cc>z?P2k{3LiA1Sk+Wk(lXG{o(tixN4dIh7)WocV?uc0JRl4sr`3J6RIJ zIZtplObeR%=gZI0;Xq?lFF6*@Y0ip5PZ3v4HHQ%Nb0NU}g6; z``Ppv5nn)6NM3~jb1Piads?$?jo$GW$ZfT)~CI6 znZ(6xKkEzRFcQ0m1MsVsyv1(Zb@U&oP6e}RI7O8JwGaEI>3i%;ms}wrI!kA>$^-jR)B28G$6z)iq-sS9B zzl->pEbDt$(6;#YfNRUE?Zv^8Ew`)7{Kr(Pnq2!(%!X~!Yurz{kNa#;V9@6%4NT&E z9w-x7PHaDmK17neHcVHHl;bl`OUwrq1j|FszQIgTflWcM46_$b)6OM}EQ> z^GJxzMOevfieZpdsLi#Yf-m^N5CVnL0P*Vr+m<1icUUB|_A8z5gkSs$nI9_)nLkoa z-$RaMneV5%OkYFHV7wTMhy6|m^*oAU5Ut?l3V-%#7^u`+(#p*F!Ez)b3{j%?9J!}7 znPlNt4`bXkf1pe+n~9&k!HAc}X&B8)5HMDbQ5Xhnp~5#38<;UL!x(9PEPmOS3uS*e z5)+d$`Fz`!L0CpCL-H(wxH^fqYNW3@mY8zsJMwD!ERb|0FATFAGf!gbW8YusxTndP zp#uso7W2lRSK$TWXu**qKVUqrK#?hq+*H_<;pI03;ZP>?ZSjJs=Qho@E z-?ua?7)asqN?(R?alw)KW>oShW{fv&j-qgIk1)`;DYgH!+#Yddof|iQnl<%m3hMEG z9!?dEwwB^$1dH9V$`BnOta%8%T=fscMB}LvT5vP6pdzB+A-d2oO!?3k*NO$`g{g7} zM)1ZuB6_-fo=KwuOkGFtzxfq`O4tqSZRgP_Z?>H(1Mlaq6%On8{TbaNcq{2h0>#p^ zi5#7`zPZu2lzcl^EW>ut2)xnYb0f8G^7=TJ;*%QM&*UP8iFi0u(j=8`G!(}y9eh{s ztmK^OCxB&<^9|@R9vgxyc4ABZj-JrXcqucPL4F`AKDjNxV%Ksxh8k9Z3wqM;zf~R%%zfFBT6B)V2?J&fY8aemp2P1w!L_5B7%yTj_4TjBBm6E{6C*%eXoQB(n-tc=|IVQ+{*CVqB#$uZTcTDf% zuf%|luQSV~dU@Vo$V%>HTMPqy^3Wt-&d6?Cu^J;I^2P5tgMF^^FDsp(kRFC-+>;e2 z^I$ISzt2cHRh^U|`|Kv%1Cwc0=Rhx6_Df5}I93wf!zML@jNp zrz(SHXslzR5eJQLX7=hl10F&PPDNlgzu-$_t;J5jMRp@G=&0z2kB;0p21dww80E7s zTir*W{<2jS_jk4N5rNo^y$SmFnLjHc<~z5fCM%DmAEAV4nuzvgk@kHrX(9?5x1zfr z+4B;992noeSXJbrcNsRd2c0w{t)VKS0AZ00^mWG-$Kdxr$Ny>xMBhQH!jUMjR^VKL z7Ye*m;OzqM6ZpKqcLe@RVCTDhyv+sn7C1!U(E?8pI7i@F0v8FqPvFA>=hF)_4(AG< z+X>uF-~j@U5I95Ne1X>rd{E#rfo}`^m%xtq`1o52+)dzq0>=qFTHq9cvjxrKaFxJ+3fw>_Pfvk6 z2pk}AgutT()(Xts1pL9v2pze!&W)J+i$B+e`}MQHMtyx87$U(}B5e2?!E=57>e8o_ z-b*1prKLZx|G0$h-^Z6NV|EDiuzGGj*XksrqPLX0j$Li?Q^qAL6Z zKa9gWJvAp;r)QxV$(d?RbY^OXUZaD4U}(&s&|B zWo=_?*T7!k;OOM+($Lk--J?Ap*{XFLueR;lcj)NdN#*0~=ij+Y*KXZ= z^bF|LyH8+H-{6qYe*MG32Mmme926BjI3_j@(_8VwM~qAuHF`{9(%59RX59Fc)Cm*Q z(lau(lXO{nL-ypHDO0CSf8)&=OlQc@r>1L^8l5gvr)12I1_n6dBBEkrc`c`k4Ik8B zbjm`aB7?#Qi8Xw>}-3}up5o0giKq)*MvP^KhhDbthG8f6mndc7uHt5@nX zm1&ttYNb9!qYPFW(~*`sR+prkqD)13>U5f9ecBXn>*zF1QkF)UoSC6dN=8V85XIgm zOPOWRYBP0k(IllS#~~x>xJifuVmg-sZ)3hFeSUV<9hE^f$uJ=9$k^}*TmVTNr^`&o zB~r7LNm*H%^s#AElxl-6HDkOo15ssDGTo8tG6;-uY}k1%q+b!Ep?&>u~T+*nk++_UYR*gnVgiCMi)a#QJOj?XQpdY z(==+OSEuAOU0dZiLq;-Jrd&FcY7&)^rPmpf^~gN_bB-ZtX^}~(8C>2e-@cUZj7+^! zlaXl{pQ6mtCM6@k@Sc{5%bFCJxV(I7l~;A%HT=zsiQ~&#pMpeZW+ZF8|9N?cucM;t z1S2*|W6ed>&$S|G0DBb1XSM~n7@nnR^iyQPvpuAB_GvfwWrRWMbbqSK&N zqDD*6JrMx!eY~Z(m(55qzgeg=&qq z;O*_r0<^l!@jCQ&8A<594H*+NGAC#B#{CzHGL-uBX4cktaFMqjN(zi4+}Lkvf_3P@ zP(Nc)Nzg|JWvFAdsTskUhyea3YIGTzG(5kI4>~UNfBq;jwlMwYh0zKB&s1OcSr}8i z_TMb_>Oa#Ed93E2g#ELB;u!K-%|9&4{73(c;g$cX0JZKu-Q|@3=^7x(tNzDZg!%iw z#yd!yFRA$_mHe}R#_)C5>VHN1cP)Uf4AfX4u4j9ECr*BT>hu?9&YnAeq3p|xmo8tq z`qj0suYdFHcQ?K-zxl(h+dtm9TXFBF%AbF^|7+EQhrd1g{qd8h&z}GB=Zn8y{+C}M z>VHA_M=ucn+xh?BzW#r?{QvF+u6}p!1@3=4|6yT0($jm;n=yZ=adc2d;!u(>1qbI4 z8QDp#?!=!&M`D5+pabv4c*o*inYr^pnb{`iQFx;v=U9yvuZ_INAj5b=76vH;3~5~C z12BfAz(HDFD!r9QCh3y72?fagG-GuJyik%m9RrdwxKmu0;aUvwQ``)3QhY!L!cU>N zC>{z=VOVUE-k?*%0Y^VwsvzM#ImMvMsy<_Em`0tU5h>y@%q8c@%nZ&~tU=%;J;g)e zDGY-@^26ZHd|C`16f}r|!w12vIL9Fz$8vf~Lw}8NPGT5dJ2NN8>baL0(htef=%U6> zz_2d7<^?#20^xvrL{gSM2xGo%Ojl?P+G;(o-@&#bn*Ars>f1HuRof> zxd?OGmw=EH64uOI%FK^jnCK+Va^|eIV$N}3e@o`~Ge8o#?X8gM%)#EI}GI`}DTf_MOvc*Hu2#}n}YCh>@L z5(_D_@Rf4uDpfLe9uWIA(ILJ>WHh2+0)(By{lGcN-vKH*Zy;k0j$1Kv#ATwllQFy7Hq898wMlr1T*lm*Kc=A^b}PX1QR$=ANjuGB`$w?8|yKO3|^Yv!y|XeEtpS!1;$YaHjm8v83)EY!`IDbUxqy9yYdx$b5Kh=8CJrswR zSjm``uX(9iB7YBaF(0rIh^M$4SfD;wGjqhp5TA(~-QQX|A+9oGT!De;vjMJuKsret z2CSsGDZJY9RUOKzcDTSG#zq0(QaG-B1~CV96v}4^$|sJA-QAm*F&jxVlWF;Tn1~Mq zR7NFz(LVxiXM{33Zi(w#nCK<;7R(;)#ok}e?0r$k+^m_Kx&d>Gvtw?kH*PwV1m zVT{cI_`KmFNVkcO@>g4jaM9t6Wdq`HCORRUiH^bzKsdl8oLFZJC)QE8fd~hfgcIwG z;lw(G3&a~M?oG{^oy4D6l*vk^D!xtRO87PrI0Eeo2sn@Q z4YOs#(4IVRM>ChpgPFte7$(=pGMO6fOXQDlUqhKph)av)(7i58KpzIoqPQAavqqP* znd10lW~s+OmqmR#0x+-Kpf6QCxkQ6 zA)Ly9F${3_it(PvOm$qiS~?1sjc|ZTII+$cPOL*Xd@5#cKoN~&x&BaYs-tlFS~>(% zPDTCzaX1s55KgS)`%$j$BuZowChN<$G3|8h76!O+f~TB$Vw~WNae|F7P7u3u?cQI7 zw%>tS2=$r9Gww=D)41vP zTUoGHh|^7tIOB$yx;e|3Gp1Kl9Ns2nOld3pkg;8W zf@|Nrycg$x3TY?#d!T~OX>5Dh3T5HIO!QP&AIZ6Rs>6~FV_I?i5^Hm2y}_cKf0N8h})itPH1~#odmmT zt@~PN%@g@_M;~A;1rWz!q7&jU(c#*O2l3tph{Kuagm7XVH(thjjJ>}lH(ut(PRH}5 zOg~e~;ucB+4>PtGD7wnmHwqeXKgxnd#lEx9n&dU_{DyfVZo4li-HVD6G8 z%&}ZihPTgX_a^3ePw9a7l$!ie|3U|sM@K%7Wl{-KVHGSluhT@%nxId0(c>K&?@s1% z7EJ7J5}Qk0Pc*DsV? zO4uFX+iQF|ko*|X3+E)8%Oxz4&Z%CgZ8>)n-EliEj_PpqUW(^{xxY259lz2_!de5y z>yaD^l#1dv(b0Pv;y1=84$sYD>7-hYWB7Mkt&N0PVEeDv*OVXJ{M(qv5bLOagH9gj zXrh<6S~AxSPE`(N_N8`O+e91GL-$7L|4~lHrzh1XE!{JEp7=X6_oXgXPUY1hq9x62 zSu?d0YlgU+;ThO$X_Kl(i^1JC2WM7gq@-^D`a?< zI-ssOn&{mdTj2TbL}PoZMX;MEq{UuVeP12i@P47T!8-=tWn=jFS7V*%*#!1|0F@_S z@r3z56+c&Ejkyv$Q+@fl5(mnk-iEoWDW6u%-PfhusjQ}c-EWRM+Cstt0XiIfWZP;cdZalb6hm}Osn{A1P3jx{^(&YJ1naIai(pBl1e5=Z7y zkTh8)^SSQCJCl(4TmP+dYFf-+$!6BdU#612GzxZMJZzJa@goH;;m4!zNz zi90t}gEoQiV!cpzOC_GR%oFi@!rc?`cp@H8UypLPGUS8W0Pd?j?yG%_jkX!eB-&TP zjsni#QrcvU9Y@;YtWEXwtc2dYmY$E#4)NJCdmZLJxO$8JAP#lbzX5BetEsnit;8;{ z@6i=@qPV^tcNcw;iH`b(S~^J|8S8^Q80VM+dq~&}U>l`ZF2(bE4-@O$TUuhy?jzL0 zy%^h-FdH;9u8y0deo@(>e$gD7@&2q0kgz9!vKL>!xH9RDzOIjiDZaxss9ju^Gx>1^ zix%m*c9?J44!a?be4V#NokzV#IlIT0*7;|BCG1czt{1{z&w-ymR~gguYk%~UVQ60f z9TF>gzue2{c_wkSVy@~>nQPo9n1kGpImmrXf&6jzUdQ)a%7GG=gDqC4DD6}}dPgSK zaegmKRql;(PyJn(-9rm4l}`>`i{2Z?3h~8AweGO`WAl(7@f-UIDxab_#63j9I@|zr z_srTvC$U2xgF0asV^xaz+C&OdJ`~T8Vdy(3T@EsgLoHCptxWX%+!^{D)LS>)bIfn> z^RRpwMLTfMDmGK zwMXuq$#@?=PC#0LDuHXecOE5S-2n>CF{Lp^8tvd}jeDfP{jq1RIy?u;`MGCfyf;Tn zSoRp)-$eepT%R)5Oe>8>8o2z~A%8Z=AD+p&n*2p2!NwU-C~z}eS20$?S^(U0zM%~B zzx@29SkJ!~V%|80z8#@`qwJ{Nl_X2pL*UW(xF6Imgt38GUmX_hMPeysmXddwdq=y_ zrg~@A2+t>1JX@TC8|=2Ol9zLHMaToylX#?!(x;p#VeJ9>9XL8CISx?MxlD@jj+3db zp`10mjQRHC_NcecnEyfD6~!U3ky3qBx%=34ZlPDOrfPfE2>pz!A7?2rjvbs8Kv_i7!N2F&+ktUzr?hQ3T3hlJYHMVU&{KuYs= zDv7m}`V$pht0)`&(qst>p=(jQ(A%5n`0{jM*1Ltdz8ndA8(2ea0^v#i2$*FIkN(y~ z=Yl#|+5*7g%uR-!vAmoR-uVLa|>l)&?`0px8^l1(2{H{`j z@}V+PEs?M#%kT`R>(P9`qlQd=+tozxe$18~yX?je;Q72K&Vzm6-xTAoM%82a>bTZP zSaK2C0L4Z36@9!)q?0HxAK~x76id0f#l5@p?cgKk?!@<%RNuXjF84Mzq3*%X80Fbj ziRKej)UJ(vr+W+ITy4#q1-U6GZxiHfLYzIu;)ntLhdJtX;5G@vHS`W!MzEcbB>HTO2e?yJSYuo$Ju6zN7yw( zTFkg|uKloihOu|CUj{3^Yb`;>${lHhCMmo2(qzm;Vx3T$M*oV#BxxkAS?@bVuZhbX zma5hSr(n%a7Z#kBnWYI!%220iSO*rIggpsq;h1@Un^F~pbtGw6kgie3aJw$payjSP-L!2e4IS1BCTJNfAw%W{?thmhT zw6X-V*fb4R9Ss*sm*N>#vuB7~bDe^{M{!A66C*Y0e34>rQ?-UGMy&rA7HCIBga!?X zGp^PSr(6abuze;&AIB}{4_7nxE9;k*g_|`rDGh6loH#$3>FFq>h|~;C5UV83P>n7N zi@`&4f|%MY&bSu8diPVPC}yKlZ#Ed>5IEYm`GUHic4bKYE zV5iJ@jV>BHV31sPLmHz`8_I8^7?Lp=YnvGRigXc~nG+4#e!}h-R3BQ?RYoqsNm{JU z(gb67kS0gZHc%QVaY1S|BE?S^CnRuGFP z|F1f*=kJF;qS<=Q%!B&v;IP60U%Hnbj38Px_A59s?s}JO$U_7%|kQ5afNperrAKbB2 zbuewc!)i4)NE(4X6~cB2lt^Q)++#HStqPPz1V<)m`BH&vkoX)qJIJMlD>Ev0`1s6J z13%fMiQu+N@wb9`^7lV=D*844Fz#m@_mF=N!L&Rh?61Ta`##1M4}d_%lzBV{tsPUg#yL;~l(m8k6cNY|xE!oP zI0X<*aS{VsiYE-|!9Az-1+;#G)(4a%f(HR_A^Z}=xfp2)1(qSqQpD3A@hyTJf;3~j z1FfH+wHVQqM#QN?dKEx9vBh zIc!>oSJo790Y#9NZUDlla6f5XUoP%x5x6`Dm<$9Ud^5zUM7mrNPZr!az;6-C3!rbK zRVW|&wn^Vb>H7f9@6$I+74E<4HqvkletO_hVo-P*Fn=HhNCV~qn}Jf`E8thanMqjykOa&G zb^w=vhk&a@%DMo2NnRuzog6xv+-JmANr@=D`}V#;ghRWKEfpHDk?L3)YggVy#&lyhFBS?O1z^B0FN= zc_*e~KFpW-F@M$>>Y&09g5^*QTvSg;lp7wFr$xb`kC$Nbu zjiqB}dnUe5OhPxG#q`X8eeaVoKRAU=Wz*Pn_6B>C&0x7KkL9B#%wn_I95$EDWAoVp zR=^grMeHrMm=&@mY$;pDma`S?ZT1dZ$yTw|7>}=E@3FOP9V=q%*#@?eZDO0*7Pggb zWAC%=toG7t8lZ}G7;438Xw^L)>{^XZKP86W-}#R`Vc?BT+Sm*Fk9>!vj!#Jg>h&Ls zjo>CR1!MQPuFm9T)#s1msO6ZMk%1NUL8c*i<&e03-Rja0GgWf$QG7aRwZ6v0RTvuv zr=`*;SX{P(3;(VXk(yPfYkkr7!vLCl88V5IwEa?H34jJ$rdcv^GR*)v4Z;Y!?m$MD zSHl?V#H$xFy1Y_=bSa~wX@nSk^);lXsRtRj%^>1}f)kfCJw|Y24cLZndcjwm=_Tj2 z;X`v?xwh#AUP<>W*LXF8%rvz|7mLwiKiCE6>cJ4aof4ORd=J z^i@~>>-6|a_Km(mG~<#mV}N&ZeM;>@F#36IddTs0$sqT7ug<;A)ygQ}u3?QrsI;|H z#k+@~zX(bu6C|~|Nz}L+AN=d4X+LV>0WZO+<5FK2MGW?1Wx(hLCQ>rSzt$r*D%F{l z&>X!cgC-GPsnmQztKI7=##&xpDM{X)noSyd!g`xe-QMcIVC@L&yRIQEEjme`QfCbj zt|{{Jn(K*t)pITC>G?P3I!l?HDb;`Hh3g&u#*?w)3lHso&9^Zy-sS5}sL_vb0dAJ1 z{2E>jO%2=o?TZ#IUeY9^DJnZLQB(OcBG zaakJEr*(B>d`%6iuZQ95SDpO}??g4To;F8L_18vnt)~_mORn$mxX`)_rrJkZ=GfQ! z2nml29TXcLH7NFP{0)nW!SETgwEPZ0zcJOtX1rMVAWU|?-V1phnxsojsx_Q?C9c@; z5usz^ULRQ;hCTHatuW#xFV!R2f5q=>?n_-!|ILk}WQc~y{~#eE-~TKrq5%IOG5;*i zzlmrFZn%%H=^*=+8%dtJ_`m)})?c+?IOR3%y8e!VpDC=fwvto**(cX}vTge6!DTc% zl^&_DWKKx*YsZqtoQXZvnXEb@dnJMVi$*{0v4Xi;yhGGZ6YnDoA7l7#DJnfRi_-o| zrg)Fx<1tj!MAN*!f#1Sht1NkMkxBaGlweo^tNU`Cb4Y4ZGH2ALo=b6_sIz-b9QY0~ zE;Z*h9%2pSUhiR83ckw>%hajsNrkZwd)?EP&vPxGeD6|s(rS6FZleFlw=wXmk4HWo zF`Dt3dWuBIM7QTJgg(lIv>Lrrmu#o?gjoJ^oB{jZbxb z>ElYRcY^RNzAxb0x=9AYvy2t1AKoG9Ce`B{o}t#{yb`Z5a12fM1Yyc2qh2o*H>OGI z8ZL%s@hRhm)7(2vtwh9RW(sdmCJyvwnXmS|!xmZU3?>NlydD2D{5k9My%0%aH*E+}N z-cqd4uRic;*yNl(5sTdmYn|gWvWffBTIb7ZotxoGmOv5kZ^|-as_#(Ld+;HY^&a)b z_H(} zKTqh_ImmNxtq_u0=l@-&WerX3zt_Ib|F%1o!|TdI(X{ULYY*_{%Sw69J;HNg6W)Kh zkZ)t$#`EfWiR;o*Ct6uSKy~1lp21jdgjE)>@eEi1*fqyJ3vIzvnTbh9OwUGoPSUg7 z=tl8USYmsC;-^lGbXe|&bs9WK-wYsqXMoOwgmbDdbRG>*m>7Wk#R@zOOz{r~=-O!j zxu*k4KnpYmbO5E5@j{O`j5o%??^{(m)m?ezTra&GKj zb;5J3>=<89&kB4>;Nt?93VcxD{Q{Q=yiMRDfeQuB6<9BDioj}t69rBXI9}j5fujYE z5I9WW5P<^)4iLDTz$$^20y_(AE3h$snQ;E+Q9l2V1g;RcT;MW+O9kF9@Lqwp30x>} zuD~#DXY%|rKEJ$cS2W{u&_{S4{ug_PjqaY*!f?UqeK2{;md^bQz-fJqxX4nB5I#k zyA??TtL0PXHS%+LwH&y{wpxxpW?wD0eB@}9bKhRs&?qYp9(Lzt*=MI4z2#5x`d`kT zZ*=t1pg?8S+K;sDx9vRfUTR?3s28n%^mr@Ey>e#Yq_@9X5!}FhQQKW>1D}0X6!J@+ z%{TrA(dM%|MsNv=76ayE`(~%e!ir^ zmf|A!TO0e?XRGUM>4=x3wp6WG zmd0&f*fr_P7X>2N=;gk6*8YeW(6-W%*}U@Af(R;>G!-Sq_uWesH@_r-+d^Baa_m zzT(d5K1+|s_B4c?b3VL!SDzc>KV9BEbf@Qs7nb*F+2Z662S4rUlT;ia=({s`&Qvd`vw-8Z-SX~wp8ecsry{`Nuj^nPXE4e6ac&Ejl} zxXCkLF3Ib)}M~&>iO-wczL4_D{jr%V%GEItkAxe z`&Jpce&gN4Z&KrnExz%+A6_`3`~`21vo2)#$BGWE!f$u% z;vW@Te12l9#lvNrN^cx}E2z-Q4jo4XAfs2TfW=Hguz%inOg-SNh{ z^A}IazT0w*8#+;arZGxSU<5$pi+6yJfXl#dfCCz+3K#^WQ)9(p4A%oPjV&hwZv%UQ zOTa@w0l%GqNFYrJ2lc=8pmq9v0J5DC2wn=%zVjmRC4g)m6MJGHsDezK3n(EI8|@o& zjKN_F^lsqxKs;pHN3aTzT|=DUAA#x6)82w`3?50QeGw}Knf4ew6J**S(I4RafZrEn z+C%YFkZEtiaDe>KzKU&vO#2nAFwiDF?X`#(w2xKg`=k^DY|8mGi8`H$L zEzu_7hu9NHfvg0#1*pywM*wS}Cmszfgq#RY1;`KaBA^s{;&ng?fIPjxt+qk9qS z#8-iZ#X{P??DBM3Wuq zrajQN!w>OTAPzEdF%STm_$1H)ve@=B*@!L*Ksuo({t{RSS!~Z)Z1Z_iFZ89ok!ScJ z)&OTA6HfyULKfR}CcDp;ebByOXPNjZ;02kuK_K!1IS?E}GU_n#Fo5hi6E6j3K_+e% zgnJK}*dI_+Snw!->^Kwa`yvgHi8li~AdBrZlf7o|V8+-P3CHUpSCJoZQV7xpJ?+yw z5Q@EQ7g5e&+P_CKG41~&nRpIBX(ql0s1cUfGaPLSGI4+)6Gs7o(2MObXG8Z5um*Z! z#{p;;kcs^SnK%r{p|Id=fUZk?9k>iVaif9gTObqr3o>ySP(oqB*#H+7{0(4x7S{#a zMBv`Q4{YRk*PBG|9ArlV-Y$4M=(Nuu!7tub^g@RlN-XX}P;BN)F z9Q>ys(_Ynu0EI0Ce+ZC$XX3tbC?Ckgp@5pM1%3vsgpBQ5tkp1HrhT|Zo6f`^#-k6U zc);@EXcv%)2Ld}N9&n!#{PR(4kD2T@FH69-((~9W2|fYHAdBrWlU?RXiD(bd6K?^c zA(w!!r64_!#kQ3#QyF_a0ev0x#9k9IMujZ4l}xsj!_yc#VC+u>&jhOArx1K5o$uSl zHj>GH^4l4>F8mYk2Ld1y)1KlEkco{pl8N8RWNbO~#Ge4Ukcqzpw2;L%kI6>zRxSEB z=!s7Q`ymtG1hzq@y}Cx5$iyE5vN8$BUqh~fAL0iCE@wvLG(1C8;lCw88UvVctN1w1AH;ETX*=xN{ampOcW6Wcx} z8_1snaqvTY3kZZv{6dh4U8bU+fnEtV+CL_~3oL}5*lZg5Nyx-a1ev%qkOF-m*lRk< z{1Vazo&eBTMQrDo>>>Ai6Ll4O;>o~X$h613;|xA8v@iXQT(n`*gU{vhav8YEOkP%k z(`WHA?P)(Wo0n;yyWLz~rhV;3+sMRMfdD*Th#!#~WMcU|)CYP7fsHniiJLA&9e|#= zIS>t51#Yzn{xMFVedkl(;-6WxKmCivyi9x4n=avH+OwXyl$UA0`e(~{nf9;Sui$0c z3*Q!?K1u}+7i8KOpC-s!@IpZ@1n&^!67X3;E(8B8$W>t5xA{0}|9b~Prv2~{f*cJ_ z6J#xTp&%E6v)|#Ehh2Sp$ zN@p3^Xs4O@{Sw?igeATXBtRzH5Q{$K(0_=x>VwpMY?Lk(6 z+gaef6S4{%0ZhMv`vP7B(40dd__`(10$FTJSZt?QY@?X$5=R0N@K0O?1VAQsw1VwR z$iz*7#*oGKgvEA;$tLk4U}%W0hu@-SO~cU{1~_m83vwNKY;Qpwl_?+i0=c6 zuX)aGfVmL(CoTbgrg*@|?2%6RDFYWe!`>of;-4DAwgcoU@Heg!HV?AcUhoJvl%YG~ zfSx!6D1safz7NoIp$fdfgO>}zp93_PQU-njP?}jITpu7g5xfE@M?6K~djJ;?xOZb- z4g}jY;p0(&+j=4|@K5%IqX4>(TJTo@#aRw6X^QfOOuS0T+mkH&zY_vN} ztZIYnA}sM_U?pU+jbXAsTndy?{NNLG4!H~*=!JWQ=MM3C;5O;OiEVkA_(R}N3Jbmo zP#&wme|13J_y*BFIYcXn>oe1FscivWGgf3*ITeMgG7> zyTHVqyP^D{Cmsz%LnhV&fshNq1G}SdBN^PY2j9lUc7SIt{rDZ?0e1(uc)%$D z-4`wRX(+Cb@{jH>VIKfgXG*}W!eA2yVad*KIKb6O@CzUZdKM1*A_I_S$O>?yfxMki zu`OS+^V=>`!uG-s@f=_ig5yEP?m00DA$HmlAL#P)>fp4x@NKN^mg1 zzQ?@)rvc=@2;4Ri;h`s+yb*vBaxQo|!1)2cm4x&|Pxg0r1M!f{z!qcqw25u*l1<*j zKoR^9Uj+&wmxJF=#`6oZ*v>B5;hm_4EqmyRi-6;hi3e-=`lAIe2Ut1c0XLqAa)d0l zk1MvXOLlg50nzY7oSKHZ0GW6Spn{wWzLtS!5M;59Td|E?vWuGrT!tUwMp~o|GO-u1 z7qSZ6SciIg6X^j@0NfyJ!IoLPUI9JW60+FNt=Jwe z*~)zZXyJ!AYYN&oWMZ;k8x2`($5w0)m+ao2n}L25eu(XJaZex<`v66d#rA2%c5KPs z?V>s8yMEyL0%T{%#18-&WHuMJot7Xyki|A@$#(6*cX2PFCvLG0b)EcxlZ(*qAQO*S zk9z`{cs5W5xe$C0pfaoi2W;TwK=4gKehYeV>_(J1RH z*_S=>0sKN=2DaJ3$EgCp2^4*Wu%bi8$*|1?R$^%B2JQw1aR=|t+oOxFLobD|lsfcQ zwjw3`7~`S!7=<`5N|ds41isBXu-s%R>>AaamrMO|HWcge#^7%#Bil#eu!A%R=i&I< z4>BExWWWB!uY`bIbxy;xD<|{UHO(<&fw(S86}FIcu#%JkYf1gUX-tEdGhjUl(@3xY zNPbkX*QA1_CgQR9i}5X1_o3&3pLDDNOoIO@NKF#XG~5-l;gSj~OnPu8;>1)BVz);a z<26FyGYgiQ=-OKNONGA-E^H_)Gijio0xj8ZqLe9-&JfsvqCUt~63U)$pBGoyTazlL?&x<*FCu5Oc79 zQ>Ol0nVN>LU9z>yH3ZkiXa{M;?>wU{OluC_g}B-t2Un^eS#VE6s%q}Dm8?V-kOY$~ z>0{HTD09-&GO~I#hasIFS;;Ay^rWng>8Z)O%&g3D`i{w&={=IN(!H~Nnk!*)HFX?J zfeN;BdNud)RyFT!XC2VV7+3G;py;5GknlnMKSNhQbZXjb0m78v{3n zZG=K0W#597MP5a!qHaZjMPWtJMe#+6MJYwvqSDQ!Tf(-cY@N4t+tyQC<=d3oytb*f zb=wxWEqYu0wrlTKy#Mrl`F6MMUfa8E58EEUJ!N~&_IcY^Zr`?j|MpYcuWhf`{&c(i z1Gf*nKIryA?#_8T3wN&ES+sN8&XS$`cb4uvwXb5IzSJd>Sp-|oID-=aj7FI!n;CY4B~3i-~!-H8|1M64Tq?)^i{iod2fg_KHck)E+WHYzI% zvmr7IC+Uz_9~YGqome~BhNO;94Td>EC3dL$xFeNN+c+sEPoC_phEp<}ywS7zG*dMt zCo?Cv>JV`{18fSbm9)KE+23E~>1yZeqw@FduHudnu6BN1aN5n+uXFd#-AAZWP1E42 za^cg^z!+l(N`$vhkg5-VscuFGrSVez{gq^hSQ(40>abd*jEN2MS9R~Aj13F&>*lZY zRr&fTgM)lj`O@a%62KiX%a_{Y4oa=1`BDkHvbR&;GOwLEACJ1yeR!h}=k@*FZ((Jx zymz!G4jiA|TD5M|TPfEPey{XzX?b&C)TNx@N3LIaUVnD+%6N~Ms0QnY{W)*dktJvI z%z8&^TdMag`a%AN{~Hmx!yG3DuU_@=M9-!Ve?8NGgwvLYJrZTB-xQY$cK;!-T2TI; zRjFp{^Od>bo#*x%>|RmWEGN`^{kje}-Hv*kJ#l|oxVEqF;y+IQ)c7||%90I{5%~^b zF)23`hn$Cvs&I4CoS3mYYIcXPO+#mOzWU62&35MUW!JwvES4Xge(I-2zIVPj`e^G$ zvj+OjySnfDAkpzw#nn%q_}u(<=WVy5Ye!o2@4sigea6NQ(pOr{Z1nMj@f|N73h`K~ z$Xi^})9S0w-}N1F^yP%axPtH_%YM1JH=#VUvh}ltS9U+^rnvLd`6a&}zVt`tvLye6 zgUdp_W_D>e&TC9b*7<_gtt@uWyqxgZ#XaJevE`%v9#&NRY`wL_to@SRU8WpyaBxf`;R%D z7o9a*(W2S##0BcOBWIg=RCIHnKCbb(oNl42RZ%aKqaqG$x0A;PO^@%@f6w!MKQHvP zlAcWqupR0kMe~zv%$E#T0uSaoS= zxzuCx(=h+vI_$fnANORr?nCy)t~6B}C&#sgA?pUdSi5n0>nmLk_81kGzT!%s@JDS9 zG|UT)ezE4zzS-s3Z+4w@rumZ*+Y2xJzHGv+O68YVqNmJTy-&yeRxK zd(L-_OA-@)v)gvReE#}F-EVdqbUouhm-qhov03bhV_)2x@L)slZ-V#xor>z_ymZy? z-<^+3|9X_vxoM!^bh95;>^|DekQH;L-?iiZjW=u_xaeGFcGnKG`*@sheb4Q1p=C+% zj1}{g`P!cUytSyx#q0bp58Q@Yw(F!gZYx&@_$@B>S{QI<@jM&5&w4&O?>X(QUq7lm z^KsQ=r#pAO`s{El-rT8qTF|rn1ebAV(;9qnV$QM0t^I5*2NuB=@PrA0s<46n+XgES z>})h!{=;y)^e@b#+y6A6@!HKVincbj(BFM{HKy>zuGwMDo(=1{ca7OEb3z~OP0IKz z<%iaZbACFt>;1o$H@TbKsK=b4IfGRBmR(f&=AObcOBN9{r~Bm?eSez=o1fn(auZh> z8$7fA2cH-8=<2NMjK`Pp(dF9(rz+#4EAOz6lgh!uMtG(NNF`=Y(x4$eO;nB02xRuQ z&e6KmY#5MKM(M`m-D4_eX358y>sn;yPBvY9{gr-Q{gi&)yNaHIhygta#UOXGkIgjb zQa<7ubQ%<%D0xsi8kCx`4z7}(6rOv_S6#|>9T#Dy5$ z%<6DMH@87tyxap(vKS9U$pUGfStjjY8k{=J?r{-tF6UMfmBCe?72s8@ZA-{q*7fpQh|=wD9?L>A)fPhn>HW`u*LB z&r|#_6x6jT`=31ScR(NL50pF;clP4E7f9%`&>8H=q9`E@f z-Fvm8diK*#GoE#L;TLyyurz$z@s);E$G&a9_}e&#O&i8~+IM;~*JE<`u7zO z#R^6Ikko{Vk(0N#9JWH%;(1;}>m0jV!&g83^8HRtk`t~sPwSnP8_**D&CTI=8@1V< zQ2hJiw!`9b-ZAUJ-rJ+@YGZvr=uX4_4Tq$kiEm-<{$PD>UPhxbXB@Gy7=Jj=%^!Imv+7i}u z_+9^Z-fVdA>=(nEephfN>h$Gc_wm95Nh-x1`OD<#Qs?8R=IQif<@G&&KYS3BTxq#% z|LxyGZx(d6Q1#+_W{kd6zQ&%pt*VXjxgnJ_Y$Wvewa0m#f}>+ipIw%@bw9iEKB9{> zmF4YJN~OITssC#qP5&&?yyeDX zz(Y50t}1WVKYZ*a7{jTgbE1tI{RfZTf08UcH#l$NB$KL`xSgUKedhh#Qk(pH9 z`kfoUNlt#fAaB#O^cL@y%)S`>`@Mu|n-+E0pZ{4Ko%O@s&QH8l<6j;=ExX)e>hs-f zYDJsrR}zoE+utTFCGfg>k}yC=JC{yHZwxksDb;g!Mp z)^Ej+Svkwl&FtfW6TketPlG{I_FR6h==b5Kmt~EtR$5)$Hm~zXD}9UF#Rm@^+Kp(`}ZDh`01MGF*bC9>Z;H09z!lk*S>hs zYrZ6*MUd{tL;J0LB5&sP-Inw5A6E-y(s+RXt2Bbu7+PB*C~}*z081lkZfHjJP|n|9d)f=gq-e!`#d4 zD;NK0xEJiPXJUN7)4=TSr$#)vFY9u`J!}5Ln>U6u96V_1k#|zx-hcAJ(GOz$*wAj9 zA2b>$TQ;L&%?Ixux%~OhjkXnjRpohe*Ke)cdtLUM;yriJXS)a9lX^YAqhA~HaGA5J zYoEb=-#C~wreZt`9N$1zp<8vspcs+ulkcHa<$E;7yQb=m|G@{NR8iMMTJ)k@G+m_- zz1Z6NPz83ce)qI8^RX2<%P?lFc`vr{X`m9jx~MwU1eEzSmnkih%X{`(bv*CJs6!1t zNq(4nAa>P-zuJ5-=H7~D#roT&X5yxTN17~OlG}Uyq|1ZW_L}tRj~g#neD>TkW~bkK z*X`c=;cQVe`MgTWt@I&1{r5e!d~iF?)%)sxAG3ZDTP7~C47qyL7dcFdl4dL}!rU)?Px*S3p8jK0mO=VRtn9=wtl?T^UCP8qk2t< zcbeC6jPFv*b&egVwIwgI#;dXS#PiGwXVfXO^X7R`vXJ*1aB~jY^`w*=ZA;xN^J2zhGYFiZDjC&i&PG;GzfS`ClH--nv4cBCc`&zA-BOEE9gOAYEH) zPQ$lz7n;-P%*|==V^n&k8^@@aUg@s#GmcS{MFUGr@zguL(o@x)hLC1XzQ*@Mnm(aR z8D~={Ia!n(C9H*MGhsSV$0y_OCsxY(?da%ua&6g9#fd}rv>*0q=HQoewAPaEzvz0_ zy{{_SciXD(ov%*%!=|+I%M%f<+O+ACu)76Ye!DyVWaRVb0s6?#HvMt_^WT#nbZr*Z zGWTmwMY|QjzkG9UoM*{M_0%Qp4~4utNYLa$ycF8BFMJ6z+?{)eU~TNFLW)OdZd zN57zFoZa9rM}56jduySYcAMqX<>5}tm1UQne9>}u!7`t`L2ITu%-wac;y}XPZWp`^ zpR_C5wYg2kK)E(%LdQ?!2{XUZex3W|*p8*)?GNAB9AMjL>jJazh7+fDko?+Iw{-u- z3iZdGo4lCse`4TGyFr@|zPsu3{rBd2`rFw||EA6Rr|-4;p=0~1n{D?zi0nCM{hL)S zze)+YJtXasVaV`fpR}1fWL3fspXc_x|K9b|eU-nJ^}6)zsz>Lu9&euL>%MgPY_l_0 zvuArX{%Gs_nyz}~Zs+ug>)Vxk`pUes8 zm9wsZ(XWD88_)#Q(^S(`0+mkg_^Z(6hQQyrzz$$OzJM7Qlj8o!VX%R-r(c_=QsEP6 zX?~?}je!&Q4bm98)J-7s!c@wcWp`$qRe4k}G>fRrA%L9Dn+mU+mUIY|KiFnO{kYLfYiOONX-y;Lf`2Eg;&B!L=p%H8aZBWDf^)dwct zAkse9bS0F;5JV(TY}KNpg*h19WgI{{3~rKMYwS~5*)zYQ7o^LYIj?_5lAW{xi{_%a z^MKl|saxaG6PL+wT`u6IdD@S3+8Kt)h6;=`UABX9q8}%$soddOzIV;LOG7C11sK63 zdnBDd_yk?ahBT^(#elu1s5R8^qRsXN>#7=qhMDqW_P{<1`L*~KA~CqJea2q7bz|h# zSsos7v=GQ#nGQ8KvkSxfhDHYSbPAj8&t``%>_}I7+64}M6m)^J$S>KHw_9R>SBe4N z^WT7XuBku^?}#OlM+(MDEUFOrKY{n3DiSbh3?TG7>4Y(q7C0f@zb6B_gD4!M9oA*2bb_gn0 z@M{2#Gd{M2(Iq6(AgZU0(JBTUH};poND04;C6fc(cg48(q^kCz?(h8x!RoPO4tyX+ zIP@;@0IP`DebJ!+$A-+@>#`%%U7g-tiZ@ZZ?akf-h7O4GBunF`LUcB7?Rp9NA{rfH zKxRnRsxs*($@^km+Br^Kf*SDQI5E8PIm!!^Z;>(H~swY z2a2`z&{-Kk^e$Kmxe3lV~ zlaaEc&?fId;iLQ}uU2gcVO&V4;ksr@IPV;%a^`&7Li<-2G5(S{p0xbyca_HjYL4_S zzKLoLhS2xnig|Tv745&Z6PPn*Yh|rn=%cqVQ1qu)v-uDcGX=|Tl;aw3~YIk1#gnYdA)+pI8l zeTTBskyjPqo|}PR`xofqX+JJ<T8HwYHZ0>;r`yK z2%#6V&`s*PT3ni|-8XDPP!H~fF>PsYV?D-M*DgVRrX69Htm{UhE;{#xVs(SO-2@k^ zT6&Wb#-$neVxM;q?8RIwRKFPRiq&tH5q?NGjGX2b47`@1wF_}oAZ}7qR0|D))~8yM z@#13VLG<#<;TJ2WJu6Z8FJ$q7=%EO$jFZ=we z0&SQQO=%6OgRp>$UK-?iqWMIftMioH$|T4{)E>ey=}sO+5}N>zxln92?NMNTBaaSx z^q##!==DoD_ZN0cWb}t%@mIXz9LXt%hZ4(_1=^QGLc2-0izgtAiOs2pjbz0;ETfIX zp0~D<1Cm>S-)G>!72I;(Ybd7Trb^|zbDggAh)R6j?B?K4@RVxJe2Sd|GSbR`R#pC< zCJwuNbh>@UHPnZJsBPsp<@%T+AsoXkx8Jx$l1vk^*9D$i9aWhkkfPB&&8_1C-27*E z^v@UIYyc}}R57-R{)cUXy0~Ee6xobfLFU&E90vW~f%5?vTK$eL2*zKEoS^GJfzQ8U zR?Tdbi`DqM83RQzfEBRjU#ds2^R%#tuZIlj)K79D#I^I?liHCF=>5+%02eptGli)Z zH5(J`8S_g#*IUVZW{d{##8gRDFE+lQ%<`#D&DEmP(Qq!Zigm0ndFz&F1;0$kTNRv zvRLtGmd~-!(n?j=jv&5Tu8aVNHCI|67)%$oC>wqfoP)HD#2Su8MEZ@OqMu1cdA`5j zgeq<*v!M~jAqyYs6UyYldlZ?T3?0KS3qQ&|dYajVtXjv0vmLMo-+t#rp7& z;pzLx9hQ<3^741S>-}Ml+)(4ZVpAHKr*!UjeYX8x?a!NK^LIZvGg(zW3(KUb$o2qD zlEx9UFqWuuu|Ki?wUIB2eTX;`w`Qz)pD}{BhI308Khd8s3zKz# zt^uUS0Q&CH@Gw6z0v(;QX@6R5p9Yrf;>)7Vm^L^Bd?yrvU`g4qZzlcOreT_I&l6XL zabxy??celbu#=}SUQFo3C;eY(`)|XjAah)E!=T@5ZrS7Sb`e(sz!cq>1-)y50w*W^ zua4`F$Jk+tzwf?^2*9id;NxN})=wGz_jVhES;bDPf$3|^2^*zlxYCQGs0Mdxw9Zr| z6{H7oF9jIp(!FEd4WhGFXI;(=_OP#_yRdm)(Tf*cF1)&V*Rc?;XRxE zd0jwkX$Pk%D5vL^6s@3~jkWr#igeA0rObZu`Qou}3`3h9y87y24y)-Z;s@@8R{p6D zt)tB0g2oKkIBm?Y3bfNmq)gGzSnEo3wlr)zIrHt@I~*>7H+`IJF4?jkQBle_xzn$t*4$4i{$}_w?^(GDi$MFW>IQRdZ8TH@M=-6a`7Sf&0s2_C$ zbU(63OeB5or+g8UNuR7r5#m8ekDK6AnILfW)Q7Q&Aq)Vff(0;ZAs_Do1%X6hz;;Bq z*veBCII|D+`9pwR<7PP4lpR;;YG8)VhAgRj;Md(YTFI@$~2gW1|^ zJtfcyOYxy7)f6!-pMw&vsfzS0_O4nsSp7F0P)Kg~6;l)I43KNFf#@qVn@POV*MO|0 zs^+np#ruvr9L_5%iQ#By2E3oG=&oBxZAMc#BPD})b?W`e)Hri#!P=#H9cW&pZX;@8ixd~k@D!EyRw}V_j zADu~y$@@36B0RI25@^W}xv`OkE1L$r9S09e8R%{@Zid=FzAjqUK{_ww%VZ{^D=$qP zeH4TJV3s$B?WupHB-8D&q@;UM_pXNI|MJKn!GyfJadqWsBJ@%sMblXLnF~}Ej)LK5 z*hOmLRfT1ik9YZ2IdvtjZeF1#t)2ITHTV|S-%8ed{Sue!>g`FRm12%C91|cCT;3grvq(GvrrZJ_;H_U>q zyd<5CW-_c|rPa2y)nZ%w``WL4@dc~mhQ$OB6@0}a8kBx}bI(2Z+?Sd2t+j$t5CjvhSWFN$;!b~M{P)a1y@<{o^S4~# z@ywSl*l3vj(gpLHZdvMD(sJ8(TWpM5zdh2bX>)SWGS^~GaZn@Pp^ZFXs_iwxD z=1X&OvfLWzhQhtEQB{9^G=5FJ|K&$5c%ORz-bV%8ch`UPXg-hs%cC=R_`8qJ;rDHi zp2zR6X!jTSz515#G!d*g=H7Bam~Ai%i^F|Q@vvSY?SgEBMG!7D2*OQj=+7U*-Hxja zVe~}LX)0YPfat^jb|M}x&;BuuqVb1>ls0i!U&9Lxf`7Ci{O(r}z3K6Y{Cz#(pC0+Q^mZdGCq^K)1}R6RAwMlA0Z@^nQl{iSRAgDxxKMGD{$LLLb2H- zG(nPjV|f+?6@~GxqAU%>0=Z2{l8B11AZ$A>q)+JK9)xrQmpVo=A z90?UP{|#9M&(@_zX zmZ$S7M3nSeWfGy~53RC$dPFOg{RVKPazmz3o`^iHr-HZ9o(hWzb!zO%K;tn}9ql^w z8;ZhrK@hCBK~9(JExe>fIs|=+=(hNaV(mx7c{RRRo*T)P3RinrDWzhS(S(p_ zA!x68V{a)H`2ePSb?RSzTB-#Nyqx+}t|&bX6rv*@9(Cnkg5vY3%(-Pn;gXqdyU+HM zu(a=Fc9&dH7Rz%XDm2Rg7#2ORIaEsmst(@RIJ{M5c%tmYcajg}k$MfMqNfGwG1S4E z7>5VcfaB5Kqry_JUE23?c9-w0G1S2uABQ&teqGEoB#OFl6-ynwA@NI-_I>_u;y3OL z`0ZjtqL&Pg)9{P%GfDf7|C{)onSN(!S@v z7W~prgI^;26#OoW%S*C-jBAB%Zrisy7K@!Fk~(=gGk-HqgI^;2tnd?{McekpPJZ?H zSx$prBK#EmhHSqUY2VSaBpnBM*7P%;2ERnOiXZx0i!@-YS$=cO-QMaH>_vN`Bc37C zHfnu_jJK%y86jN|s9dYsj}*k^prUMC>=-B;Nvg-^L2rRn_JUKj_@JPoFa-=lk$JfC zagD|0^D8Ud)}kY@FY^3af3ds_PpW>8nssJC+y4?~Z6^s^u>g0VD~>D*;|byDTpH>n zW{`S~=#?5alC@4bkf#1hpJ$}~H z;FkzLJN#T6zxTd+{Bll%Um`peKhIIIBq6shSYN}v5Gu_`BuhwM<&sww%d4jPxD2ZT zrGN=DL)rT^cZ6 za*Anm+6XNvA*sV}?jZ2v0RG6#E|Vc(=2ebcPp1WY+K3^_OQCoEko3-%R~5>uCVvI= zF4QoK*Fa;^P;5Iry$gxn`Cl8o3zvf4`9$wD@oS(r#3z-%$?^O%cV7k;Aj*n<1ep{%t%l^eQO zD2T+Z2RV73k$k zm0ew*4R3uvqjh_Khn-%mt?yqYg$=FSTh;e;-Fxdk9<{Bt17m4J)E}xeMP~sT#)+#& z0$Pp+z}C9GHyRFA8lx9W$5tn!0BcO^_HguxP$fp<$dI7|$_-T-FwQk&@ET21x*DZv zg00;Jv#vc>FB-cAAwHz6RTjG~?FZ3K_uGQM0R@U;jU_7ucy!*KA)GoauYnGtG5zU=<(hvZ&!;T0z$=jf$>Sr|?m-1!(Xu@F|6U<#v zKdQguOQv_7ZF-;datv;Z5z1`0)l=zOnx&NGE2gc3R1;OpA`t#Qn44kI9Zx<=@#b^U z3C`SZ63^3dD5dvJ=0|3#Pr+H?Hyh;YZ2p!YVz^A}s1g@80lV2Vgx2E3$GBt?@uFH_Fyxte>nLRVW- z+Mgyr`KXu0Q|VYbLMba$tQ|)T25|((EOi`#W|8y-5nWE3Kke-EtNb771?6-GVW{F1 z4-#((dT#94(H`a+5&G~GTkw96to>D6a24GTD%(T1$814N00=eFjL^ew&{OD44~A_r zIpaHbw|>yudORE`mOf8wDQZX3ODMSB;2zUxdotYm!Bx2JY3%AvZ_JJ~$_A+`P5Rh? z-a|T=)_0U(0YZQ4@!mj%^trKRIzeC*TyIeGhLibscUGji30}Cd>jS{s-6)?Mhi8-y z8vA~)!5e5j-fwHa4{y@vCfkoX@nCzh9)qY1;30i*RdxigX}V`){8?4vS4XY4THo(& z{VW`~h_JskV8W#f&ZaYKCl{!6QMO)Uwd_q|YGj%jnvdF1>$M_IA9c>7I@8XSMO6r$!IRyJr=+ zN&46nJs*@K;HIb}wdOB% znMtm&DixNC>#ZTHQ=V&S(9j4?H%J2p?nYNtQA-YN7?>Wa-&}Q?>o6vLrzOmSW|Aun zQrH|(H5Vm=a>;2ejs-9SVUEBgifmjlUGK$*p3UtvOhp1^x&g8qj=)>5gI`rc?bpHG z4o=v0f0xO-Wm85}RmbMJ3#2WU_VDTvicwA{QC;k|8!#ghF-6}|Y;rD_UV}JV>M=!M z3_1QtG^qCb*zcD>RJK?_`~`IpXefKg+D>s*H9n^3U zNR6`4?IhIfKILf5u8(}RUbYhq1w9ICCYVOn!83pv2QYcKj>+)nkm01x z7Lc4^t{^eBBECr#aH8Ii-3I5+Om~5|*5}vC&)4P*_#_9wXr(4N0E|t_)g~I2Ss`JV zVIdo|KC(>3uRfw&ZBgc0JX@EuQQ@Pz6Z1B40JS`4(Lv9rep~QE&={yVfW9rb7cV7? z-A)-a3|M-=1!xNaI-bu#R7~}}Am3WN>=I0d$i>RsV#VhoPRZ!=pQD6^TjQhnhI-|N zMVqYxp9-p3YJtTG6r;mEFDY*azW)q7MBoIKCa_!o0X__PJ{K!gh{kR7UsdgA>uv>V z6)s4H=LONs+9_d0F}UfJtv!mb7-c);nQtY^CU->r)CEA71}1S7NF&6?EL%(E|2Rd* zsVMH)LE{r~JO)VFjmoe_+0JL&(4TvD#*O>UP{Ncd@ONql)Nv^Te_Mk_qjbZ5S94~? z=jsOO7HzKX@6gO+8>OoRarDzc+K}!+T(0-(z%mk1o-sZUc z`FVLo+fW|#fi|nAO#~`i1JU+_H9loPENGNg!lQQqFQe!Pqw$FHMp2CU6Q$%(&_Hr1 z05Ni~j{O+7gzFcGPSDpX|G=bVDlf3%gpekFd)8aYG7q|`yQVy z_zMstw7j4wjOk2tB^BsUta622nU(LAXBEft$_T&foxadacfPl#wkno46(Q~60G720J$lCYV+M7UvI3dw5M4C{9#xYJ-9%fC10ZZUi2w(u-Y)Ap0Ob_kR z8-1CJBL5+J6z!2t#{9~$<;B3-0(31^p&1rgblcfWuzSF5pmh;6r=wcwW`9crIT}JU z3=23Ku(jjDq(pd-R)loG+8*W0KZGSO_M$Cv&<%CayKqC-^sL*B2ebmG zx9A8cYn4f%qamO>cM#ROAq@ii?!kDg$RYa)-L09_RX=3LLYX~XqMcSa==Bo#kPiSf zTmT>5YbHJrDk<2h<4dK|O<=2(N+%%NndM)+IG6;mr~Y0012)H0^n4TGgqNpwkp)oU zqRv8|y)$714C?*)3KYEo@`AE^kO6Y=9qJFc0m2~~U#0(Qub+)*1Ywf~h-ohp!s?j^ z1H|!)YKl1I**%G}hc-Yk$bGXNrKH0IOs#debKA{HB?ONDk`|+aLViu8X zF$>McA;ck?CFnQ9ZZ`8hV1J-Dq4lmj@*ozB805a35T{q&z$r_Ht+qDxsF;y!)Yz4ee zY6ocEgmm10M^H}J#Hl#m!as-nw{0P0QZzibN83J!Sg(e@>0jPJEu45o|Fs|;sg2pB zgvrXAu6m+r5m*f@uIGUa`JFFOa)BSu=C7))rcB({<4(ed> zR*_B72zsDVKoqW`_F#S5h#|dI3J*vF8Oul8o?P2eEZAf2pTIP>D+X#GvO%*jo3NNw zGd*B=M4B>EUz3Ij#VWC@0ig;P>S{26q3U?tNiyLDE1XpT?kw8F=5dTL7#D9Kb%0@g z0Uy?nR;p-pKLu&?tEDcp@&>!*02dJ&d)uDe8Qn)wMXy#rO^yLXUz?29G8qs$IT>04 z6G(}O7!`=7MtPAyfD#l#76%Z(s9eOlI#O_6LNT9s&aUD}Vzjo|5nr%&+Vlpbw|%Mf z2KF9r{VDJ{3BDak&~PQ-(C%uEC&85$2t(25>Z{D9mub$2;ux0e#f_zj z=Ss{jI#Mufgx~2ct#0-D(y`>PW|}Fy%Eu3vKoqlQJ;2i^h3x z2PVfEtxKXqQy-edR2LdYmgouB4^a{3G5YDt77$2h{ zg{~6ZM4? z|1DHG(rWus<<}N`fJm(B0Gp)Hi%t*R3+Iul2X2hZF=QlrkOEM}?`VZnC`0zkM3?jf zldwFa#R>UdHnLg3+?A#jw8l2H+$Yt3Lhh5I6AvPJ;rfg81F&rsZ;Q9UMm^?l4a6~@ zs#IE~uEWwX!}9Z~5{{>hcI9%_&!OdGd{tgn{w;u<=Pm?4DF?SswQMzr9*<~5HDxC|-yvYz zHP}yHCT3vLF8Z6IBY??K&;!&pqIk4cl)fpcIFr3=M@8YGO7@S`5fyD?7jTMD?`4no zj(mJIWcsJcxMLr250*a5>EJ)zPw6)emEHn;OwDQDD)tzfX~ObW`FmP;@C?A8I~2U3 z@r85?Y}!!i)$+|K{~JS=ug0e%-gbug48(to7JMrHYJOO5>>Fo@&qVxVXNb=t_~6j# z;AbQLwjuKmO^*yPkX_0Rcs>7MHn;ELMz?sQpZrY~CeLo=_%aMT(1})%$vGudX_0dk zFD8;qiooZQkY*WHeki#xuh}(z*oxCGUS)!W8$X`#Uf`LAMGGQWcu~uKrOJIzg*^+B zPr+4imBN@bdAWJYRzh2M!nVW^Vrpz@I_87wF@%JCRPptpY!Tu~^-zMw(pYS1p6#iy z8J3GsN`vP%|O1L-w=G)zLxW&?XC zoM=<4HoAeK@+o|JGck;+r1*}7ZZDHzH3GwYG~TIb3NCpTb+`rcIlMJrPvSFCo<+)_ zSoT{HSSVjlHtuA37DmP<A zyM`BoxN4v>(>;@Asm0F(#4>NlKXD@=#oera_LNeBUl%qU~V7910ks*>E88 zH8H3@keZ4L&c^U=G>v2R9-L^lPX8!tI0gCaFFDq7>u9(~v`!W1_{(j$Jeu<5v%`4BQl{2@1FgsUDb6IK6wHitn=Tdf%X3mDt@%17 ztU&N|^O?EiEN@?jwMb?#!Muc=mE;j;;o-lLutvk73SgI)C^AK%)7SO7+&c1jBN!oNx4^a_i; z%TuGB#8y)ow!65S7bPlFXzWXhpN~SS=r{Iedw7Ki*(RoA2C2FY`C_X#($DfVr3d3J z@<%y%4l1FxS{;ACNe<8zS9*@N7(>fpsHaelyav&WxglO^&|X2Rq{$5#+U_G6B6=sse{BZ}(K96JKM`+`y{WkIW?Y5`Orr+f zlTl_-3?5@Q9;(#I8u?lGM7;HYNw}%pc-CEvXZHBsIN=}XIap*H(cTsuhFEZEHkA|P z*{ktdK%p(^Z1-|b=3SP&N@Pbh8qCM46GfwhL&~yQ4>mtmdS_;^vj|giTl^3GFcVO*7 zq6E)zaTu70w&Z8`tDsL|1i-t{vM)QOWslJisK(|v4d2uad@5N(YdD!t#apk?e_I<>uInh}ERJvB)Rm~(_vpa6ItsR+m3-6+zjfdeGD(wbTxO@9hy!ru8R z)~S(*vI~9V(S(P@KW#|-8&fNgjYMBm1LLVR0OBch82QC?$T}4YD&P?M4yj!q@hDyB z`-k?nclX=Sl@0Z8YgI?ANzZUFqXA@51p$%fGeu_TBSjLGW_x2#dL_C_YU!RH470@s zVn0U9cBRTBdug=X0MaPeSk*F8d80B9pp@+ZWD(fY=-9o=W_B;#n=R~^I@sl)ZS5=2 zq;&dKFZG%n#6gXLJ*|PN;Go7t|2ini`2xF6OEQ)xIX}9VMucF>E9^3aDE%02F24s& zbE2=Yr(BpW$N`I{)V8*7ljm4%!CN6VK8(Qj!J7}G^}IP;uO(ZM)_BaTkZ$j8cyDZX zy^SV^{ZFPU!MB_~uVsnX zd+60puhg9TTIn^7UI|oG+?1VoZrWs|XM!1BxG5{~?A_#`X96CbxhXyIT)fGYNHcMh zIT7yKl#zILY^tPZTtd`BO$gd~BF+AJKE@Dxj(`=Lw!11IkG99QDsR^$dj;`|noz9? z6KMOd<2tVx`U_jWkww1U+Ccp(RR?YnYkf-F*GT{(VeqH6XZdyuTS|Gz}veU zZU*=x?PO40@Z9+b!m1rt^t|WB#2;Nv#Bs}i1Wd+*$ zl19vAyDR~#V)_;E&PQ}KU9tYED)xpH!TR==_k6K8hN376)`&WoqPpR_o((!%Ss#4Y zHG=&iT+iX^#bv%$uovLE4p#uzk8wSS>jhjN;>x*BuovR0!F409+i?9D*JHSL;2Jht zurI{58rN@deTJ)bu3&!^umwY!(PU1~uw-UsTXS-4_F=A9okT$F16fXsGP1ziVcdEvWgN97^dt7}UNd zh-_K2(Z?Sk>2Gm`7${XH(c%|nv=_gzH%kABWVZJ0_-)RLy+-oiENEHDx~9i)m6ln2 zrCD!(@dXF44+G)ux^2tAy66326?$t znPTFvWctgq++u+mqmBhIycEw#4RDF+GNx3b<8+P2&*npsM~63oguPL-E{1eKLp|u3 z@7cU)!50|wpI;j{=2NC9&pbcr=@xGRug)|_`3$rMY;TyrS?J76)$B9UI5XWQ$_LBT zHfUKnyr#+;w-c3tRocXnqA?th^0DVBE7m38ofairtB)n&!XNyl{r;jo$}u071hGre zCGx^;!RNqJCB1YjaX$Fp_>~53Qg`TJS*7w8E844$Cw@Zdu4p^C7K%JDtjP?b#wU4T zu14BU-m6Byv>g<&PK_Ak*+q`SYJ}yK9G|KYnS&ylvIYgHb}P+~MB?kg+(@p{;Tok)ecI1rkr*5wW)a>l(acJ6JdQQlTQW##I~Tr5*+ z$@5I(2WPcB$HemE;4pKG;XQ0{e>W5h^b0wmU=>n5keU`JOEfEt6sU6^XvFJ`L>k+* zI_uKvYYj2x`KvJ41#GH~qnTvhUWMgL&~xl^R6*L}0My~=(F0}9xM*76@0a2oh&fd5}#BYY#^5BnP7n*jgMC%!)V zm;t})YlLqB{7;U5#rSU`8{5Za6rF~vx;YbTiIqet!%EwUm zS%5#`KZAdU^>O6(bD_PWg}{m+%L2^|28A6uC*khH0y&q!mc{!CY!IF2wpQ1&{cq7= ziW)a%K8**3pmUEZI-}=iQ2*&fNQy%h5KOc#PF){Id(!OH?EVjla~4cA^Zi-s`Z+7D zldx9PDmr#WloD8xKu^D<{%Fo6{$sX5ZQn(wS0Lb-Ma3N7_PSrJ4Hvz{h&)9;%XJ z2_~1hl0TRlB9Rk! zYZVr%TOlcgSJ9E?Z2cGk*iRJLed<&r$UBO}gNy(#AQl6VpN;${XYyG$aJ28eS5X}Z zS^f0v*N6XW>eL|c&nKlpx*?7~?2+GgbK&_i704g50$&^bM-0MWbw%^VU=Ba4{a?c0 zs^QN^C_|1<;u;nVSU7Dc27ER6)0*kT7*my>nokKs+6O#@{Je<`EKm|(hWx)Q9SZ%g zNPdRE|GvX<{D+dCo3~J`>C05$9h`i5Y6JM%=>OWGRQyxrCyz7WOUY0EkofESyHo6w z9I}7-VsmHFRik|`|ubvuC&U5r#JAV)mKwG`<2 zu;77jeIa`V>!4}5;VP#f76BcLmph@^Fr-GCf|+6!mS+R9rR5S>CCkQPFsH3?;Pwdm zFH4oWIO1IlagY$i!*(~0=AiW$&mjS-c-r+CzeN0(TaWQQwMc?^HtR7sfo``8H9m0+ z_XsFQ8GD8ghBJC*5gi33qrO`Z7DQ^qC!ssE;?J|CNgF@C7Ra*5ka z>>n5#Ddzx(Zqp^gqWT394x8OQ7&6J;A_Ctt-JXlGQugK%&ri1=dgiOd44QdeMBIbP zcTr~=7DDGM*V20EqR`c5l66-t%X*KeRF^|Kd+r(WI`t@h0 zh0oJpdiL-!?J2POvxm>qzkK%Txe7nYod;)yKTm(_*~91S^L};q@Ok>&Q{bOrd~1Vs zF^PKu;!eOb3~x_y0`lGh>qEb2JbMRpGSa4wXOqXooMF6}I-Wh#{=$qWsEolwS%X?K zw=vIho8j%3lZ~l&qMQN0)bZ>Y{X0M1u17FFl)ZsB_p`U+7hx3g=4GiEVm=F|OLF{5 z14Iln3vk19s;MYkLpNOZ4qCAVmlUmV!bx799@qgc9|pAKi^`|TEu28`BAwu+E-w4g zm zM#*l^<{`&dgeSSGX$jErLaG{7Ct*#g=Wn1By%;;0;IS7inD1@93j6)3V=qT7FC%vX zuR52zK^UI_-!CD5Be&`iCT9i^wgOvwHD=T|a;+L4%$%LOaqc$~a+reg8T8FC=$q$o zu7;GDbol?OzPbNTadPTiXa9!2v0R#i;LSdQvCY~9;1YDKvn+5w&{}+)g@d#g~uwKk@f`WiBn(mtJ_MHZ<2AUvRIj-k@S4r)7U=0Xo@^I|EO z?g%^(mKdTDkuPQ#lwb{C6P{Rg|G>p0VZ@<$&xrNXcuVq&;`IEQiFY5&2P*>U8EYF* z9C@+5A$7Gh=Na{Z@_N2(8mp(t%f#uu-aQqM?EbC<&jh@KXWR%ulOhE|_CW#o<^!5XlZTl`Fwh^P^Y)dG`GxWD3X#Q&UyM)+T82H-! zReXAm$|e&Z3gXQ3RYThMU&nmag@4e5C}qCtL_&4J0t3Cz;w+K-#_QDVm*@{*EuC?` z>d%|>2*x|z1v&)3s4L(MM@R6uON^(Wpn@y-#FBYcl!CwE-%4qU1(|$C5T!y9uU*kt+97wK&vEwj3 zh^;ju&$r0)t#YBf#3V1licT5;MIYCV4OIEIM!tamL|xup(F4RQUp?pMG}HL2e;1d4 zNoY4Ta$2H>-WJMf4&qSnXm=X*y279Sh^-?12Wbs`}FKTW3_pM>J$zp)9? z;CA)_jHKF}#xwz~1s~M?=XR}}J?H<$yLq=5bE7-4g9MIw`s8aT;rGc0b%Sv7h zq&B`^?OST`GrghfCvr7R>lS7+*mtq+yGZ>Ce7hRXKRV5JwRzaCw)snLS8KSC$UYO$ zwR!k>t32cU&AAxyyttcWf)w!Or(M5Nf|UijMG}@lizKw60Wb25<(-G}7W_XfZxqUl zVxfv!zkh3f3cRz>VR3vYVQns;ooHAq!`8*Y){E!S!i$1{`t2<8BW3AF_w&2X??$*|uctSAgai8KxX&&LgKW$3~2Mjbg6k`p02 zGI_|ebVHNE<-+C0Re)0DeDOwhDBcKdyit?K8)4sw`%bFGdX7H5 zI;k4#-Bb;FWmKK@ygKwMU`_`&sumzUOSN0iYlpX1!gD>Z9o`+b8pbQgw-Yyv*+LJy@gP9rMpSP^ zm9QVs?P8_x^Z7TLsVZ5|3+V{DA4jY>2@Dv(LzO!D=RiW(&nFN9Q70=KSzuIG0>9Z& z3pQp{;+hR0gq?U9a#JETH!tc{jEexlgit`RBp}cUw(~dyFCfeV1gaBNKk`4k4joySUo{hgI{rywKzBg%tYCuX#6;jbRC;qCeDW`WJ{8uC>8xF>gLXFoWr<>1PMX$(rEw(WS8I)aovt{MB=GbHj0qg-M797BXZwGZs1~&Yo(L+AVsTXV8ZINYC%dq1S{lf- z-BpAL>}dRx%y%?Cf?MmcbTO;-SjMueT90KdzmiT;IT9(u=6;p;>YOqcjHlm&V65TW zXMhLsoR~5jHJj%aqbAB3-1CEPAmeVJq088+W_$;s$k>aUn(=mITyZo)^2f^~NzrAy zM$N`O+3R?fDBBu$D*#Xv#0{B24xYIeue!`uHS>OiqD&GmH8UslIyVs-nZbSWB5=Ie z%jdyW`F|JHob8^frYBCSb+bLGwm2#LxipY&yNf`8lv`C&K8qUwx&Uw)7oq44c(vg5 z8)#xA!8-B2jfz<3K8#R^H?>|WY##VN)4dqk?8rugMlRFDd-gdW_L{U3Xr!E94Iw3# zvwdn@r;1)MyexOBd3lz!hD)J6YLOo1PamVGiRk(yhQ2Kqa*It|wjgOudT3va5Tu~C z0VY$sPzJoT*Iemi&p*iRSxg8#?hZq*vX|G8)Y*ddYNo9SLwzWU&a+*Mv*BmkEtp9skd6= zeo#$GML|3FQJ;M}GClC?L1g;9qLS&GYNkPCx&_HmDyfiEYEjiVnV$N6f=q`|Wt6KU z6A_b>>0X|Slj&tjwT8D9jZ8#LPNwfAQ$0ed)~WPSsZ~wD9*4BDb=-L2oM}^m5ydnz zRuN{mqd#QdPbT}8iW#AzQPfL?K8TKzRV0&<<^dSO1@$1}@tth+$*gLjj{+B@ zrVbgYmrxhHMrGj|-YYISfHYBtCkm4$26UV5FIvv3{ntij%g!B7Bugl_BH zkKzWtMwg%%F7#{ECa{ig)=$a}aS6FJx#2oJAvYwnNx322o0J<8RlHF#NTL-=C@3)N zFa~y`+-LC`n&&R7_QuxnP8EX$ThX4rfuph5Mp|v+#dfM5v`Fo|jUca>GKDX;DkVQ4 zR1Dc5o~}jenUHUJV{Za5SzxfL$UehJho2Uy#c+FT4Y$EC*wn{pb|P65gYuC1hJwhL z87YDhL?RDaorCg_sf#>h_zucL3LkmMiXD`P8XxkI`8+6(W)hQuJSY!0 zxz}+6JS7jhd5}3-b2tXDwT15rojSSFt<8rz(<1#{kJL*pN}9qZhr^6E}2A$ z)%{4Yuacm_fju3|3`WNu#`|A!T^OYBw6rwAfc0H8BSY)(>DW{kls|n^pinkZPyzYl zX^kO~;9=wiJ=oH#O=a0QvgBE<9Tj^5IGg7~@5FI;-PB$v0BO38x2nf3n zwVMqBDm@URuOJUdVSLFO3+hb#I2z;D_&2eq(-#})I8^l`9{f0c$Gt z8BRL8WRI276wq>n>n4U~PBY0CnhcRf$qLd7HKwR8PIhGO5v9SJ!xYUuI;)gnG zt{lA36-Q}dBEu2LX@Ww~79~V;C|wP^&xQ^NN4QdoGFxyY87;LIoaR1bvOJ?$o-tLP zQ3fi^_4hwyxKhLem}d4?4&4u!JCl)xz0n0S&^JUMBl zd8~y$JNR=qp24&kE_L%U1Qn-H^N-b~(~f^*m>q6YQ{<<7lCAF;x+w4lCqsbusF72g z1%Oi%X8C;Pc@2CacL6kGGD^;37g7ZLB@`)Fa&~U9T)aXB6L^~Ab*Y9IWQp4$TQ{LY z64*b14Ewf*kvkQm?-E8c3fKlpGfhh~F*VH$j&(u%Hl@Z5#7T>j;&R)9S`Y8!3@c{2 zuXE&`@^lkRqi0HZwS_&YR?2x~y2XfNXXNQtk$+w93O-(QEHAM=*?QCcG*)Y`#0{q! zM@QjHd(n}hS(fOq&@6kDHk9OtOeHu-cvhzF<9i6EL(ttazCUP^y6iX^!DS%afTz>e zegil|!lKj^C^IHDwO%4%1qizf%8_I-oLbF=FfEiBa9v{EIGJl}TS1Zu_#svorlu`K z0xE{5$HP=xkUsLe7VX7>5#mItdopv~Pg#MXTgC|FQ>;26GT~VJ-(#^Xf*lcWlUB-`lxJWQ&1EydN&pP zdurQgjJ9Aa3I&A8T>rJWL)V$Rjj<}AF<+ixV6W`t4O$+94+c^3edkii*BN+%4kLSP zaQrc}F`RBegKQkG6~!Ayh7WVb{bU6(jvC4zP&) zs@Wq5!+|cqY9X7-i?k$Bx)X)K*N{MQ8Q%SIhtYgyRZ#>5c?HM{@^3`vMDC>d?4wtB z1*M)e9(yH^#g7`hGajo}o)n0mdzX0LzrLLVkXN36EVDkG1pIUc`d!`FfjMG#H2h0uJ1XE#_q8Qs>4oKVEUf2@mhaMN+_ z5wn3U9Y$g$XAX0y1tjT0LsVWyGs?grfsJtqc^;E7c#oG;m{QKlL^(c`LnjtZ4$VmO zQaMzQMtKDLKQ9jwlEWY`FR2$e*q-dC>VzszmeQEPcGnY#wLRG}z=b08EC~hG{Bfj3 z!pgp%#B*;(2p#@b+4rM(&?^YyAxq*Rd$kZ~oY{TfqENW_68^&ZEJsDI?<$G{EOjda zq0avG634rbj=BiVc2}xf0C?0}T2y8NAnzb3*RxvGN9e&g!01*rb0WphwG=y$g5>%c zQnAFd%kI4=dlh{3jO&jY&CKuo5m+UPUhc=ZJ2&`58^SO z2AmhNu^ft}uQm?lYCwtexEO(L-K!u`(#c`VzZr8svGxIh*6@(4Nr;Z8C)8Dl=F<~3 zfaq{~qDn={+fQy|s*Mv3_UStaJuI1wn^#E`=ju=#2NX$O=$lR^70dZ-rMi=)k2c$I zWw0I$Qjd2d@nEHZtux$`kPqLRto(}u5QAbQL(`fJc_`$Nsx?UB6`))>5J_f!3Yk@X zw-#Cb%#YYO-J&m&7+9idIHUrgWG5BB7)v$?aNxJR_LV@52CDYX*=`%^RM|lTlG(D? zAXl2Da3+%Cj5-OLnEIDuc##^xU%X?l%VI3~u(g}nnGtvweArtvuL)<@b4dBXJhcj$&d2sn~{THq^ zxbDOCKe*n*HSQ-ks|ME(f2zU6X*}li^z;mz$b%z!@R$4l?9Xbo=Hg1;tT{P3sMBoV z=fiaat`)eNwJRR3kE1m4c>S}8a6XxdAMi~*AD7P0edS*yn^yf4Ya)Im;vYLh{5gof z=hXN!%$vf$6?|g^?H{tLTR!*ldP2|y;iL(El5Ut!Soz#Y zj@|eKKRzPZ*h{UKCithq704&}&t_E}UsHD&9hbJ^5;Oc5Kl*(N&YzlNCyDP;b{V@p zCzn|~1GXPMOj_<3IU8EWNTm<_!eGZdhTkXs(I&k(-%WnYWCh3*d^ zYzr=iYwWJh^p1?q3PZ;%1HN4fxE-_bwNRtf!=dj;K!?mE((+XN3#mQ$D6OUCcZpPM z)igMuk}$-XUWn~T!~(|mfWUlQUR;&9%5W9qD#TTQOPP81etG6S`*CNuGu#j0egOA= z-1~7qjQe5S2XG(2{RHkOLZ%R@B4fXCKqH3|qe`#A^#HC%33fT?xGl1lYOH@&Yp;a> z#}tZy9PzXv@v;-46(uJ$Cb*MK$oc%xZ%?3H`!7*S?C9H|ba*{11gvw>cydhT$pqqw z15rppiPyr_X|Ke!1XpK;aqO;+Sw`t2PCa~s7S#KT4m9DWrAhMYBl>D8r?W2QT3tHS z05#Nj_7QzD6{&4M@}XDNE57}?bL>`S z%Q&Gw7V~Uv$x^!N*5Pn)lRGjAote-sMEju1s+4jZlwrV!Ol|FSZnpX@r02;L8vNDL zKt@rxk4!|LJS~=YQyG0k(AO*kviY}7$q0zPODkRIp%n$rIkBPOKAfTM$YO6IxR1us?3D}2HGcz8*{~kUmvvqs2pbN7jBM*DO1v_Iy^sfk zatC|LMei$I%!9KN@qlC1*fdZc;87tnL!LgGDqyc*l}U74QOwg5m{L+o;kLUEW55#2 zq34p)n}Arr%-xTr zywZR%kl|;)I0pem;W8Lp+pr?F+1hk_4PgDrjgpQj|56sgk5wj@@5krPttEN97Qq)# zJ?Z8Xf~Ozna-U2KT>8*f9HxkJEq-53Y$sAnEB6bwAf3L85cV=g>I5RJ4)iJL8o;M? zCk+8NSmE+}YuFToL3C=^uaG_tGMz$DsUuXBF)*GouR=UB881)^5{JbTC(7?Br^Tc( zrF?&Mv{HTm-}+qG}o0%406lPWw8lhE52Jqrf;~)hhPT5g+Bw5)(K&b;+ z$n|@`BCk9lW4jW1aCF~u>|K2s(RB4_%SPL6>A2?F@#Ayhr@pY!wmJjX^$1$+N6_j9 z1l`tHhM!x#_*r%XepW3(#CH+4`Zk2EUXHNUtCxhHYz5^)&(rTUfei}ETzP`bVU9+= zyz(&6kQbeR8(N9{3m}(d}ngQu^71&tN*xP1%+G7FJ^h?8?j1zSZ&^ z=J`Y%G2s(mjhE3V9VQxbD{~kQ16ZysvMaS#<7*Rk$+ZWJyC=LYFX~qU2b7ilNO0(3 zB#hR0UI|QrlI*g}bN0t6u^(}BEJg$%ckO;O$O+~9z13B0cA|vndGW+{Wf#=vq2EH0 z?lW?r3Ti@CJWN%T#;qgchh>5l8|V?=kml7kf%=^8R?xlC_Hj6B(dH4>f@nnQS$6ty z(N7`$5LsstS!WShXDx{nbf=!0b^=>&NhKPNWSmM?+Ait+)pG4&&vtS6gzfm&2Wbxs zxQJr4hoSw;ji~BoxqP4~tgIYR<{Uose~3tz9(_;h0pNZL266i-7&JsKyK(D;ofraD zu~iA$B++R*P+&y0E%%c8GSP3IK)<6;ti|t?0s1XHjNisJc`igWuE}xm+vt8CXgd?&O{<&r=KdvPMtrK9Wcn2XyHIg++>B;qY>F{FvUT~uK?Qnn;5;E*bp zq@f5y6rTYHWcq}<3FAvl194fi`(goWXih&{jM^yyi)|AIus_8%IcebLsI|iOBwlA> zzZdEJPk7`Hc;xMMfwYPWFkF#oLRiV{Oz+I>$gSwi?MUzJ>ddVOZVMbLo^zreMc%;ek&(EoH%N;uZMP!Lge~ zYwNM{c+AJj&dS!}Lh&=@ZngZHPUn^9E(jPZJG08J4sPqP1dg<>JR#`IfBPdcS>AEJ z*L!5k^dDlEX&HUC9b~Agl2%%TSilhr*fHT!KHz14L!Fg51L*lNGc)G|T=no^m*b?X zS*SijA>wdWZ?SHRKmafq7r)paxv<+K?KmyEUv&6bVUZw|d40yCKK2BWZi^jXS*1J{ z_CwOSb@4a)iX+}sw!qlHu?t`fJ_txh65hEAPcCLxLKv`&l`5K` zv(nRd0Su6mfMwavl7MxU8Q8*a5{3t)q};MRlWhk=%@;=h*18f$ah$KzI`DyqfYtWv zaM3pD%1O3$UCMy*MVwrGB}v3ehji5>ghZ#MBNux`(biiz z{e@1UBfThGT<)~33meO=#(t1AhA&fKZ?1X5yT(P9rq|IxFv|Sz%L!*Ij^PZ8IW_dh zmSc+%s!_7Y9-5mb8oSfWm08vbV(+EOEK}tV%tv>3r%$TD*`q76e%5?b!_kwTd)`>R58UayKRF~thm`5-;Mp}fW6IUaDbcGQ9+FBh`MRrHna=xyi_JdtJl zXj@9af!gEqoeq$7a2U%Xfo zH^#+nKQ(KmyUz|du0W-kmN$&~BvM7e;x{kRg{J1}`zR=yUunhOvFk z*zH)#yxrEm7KPJ?uscYNl-ohNfGIm1HA>-=R2fI8KFwR>=bvc@@gX$lwytCXN`Tb` zTTz*_U%GM0=Y5@cZuLwGm`GB((+evkhT_2Q;S%h$w(wR-trPl+-#f3<#Jy>`|LC z=beNq&4lMNnO~kWu-xL=Y`gObV1+)qryOhWY{1?jteT_vO=D{ZlnmSRb54vcKiq}| zwKjpBfJ>>-Tqw{CLTQPxEX^2!GLyc4!qkzjlpnS|y4BRxXR3(JaWqQM9pDWLS@}o) zvZ88en2!+5Qj4(cGJLY8)6#mZQ8c$6tAJ(@3M-=@dCIM#gMv!}8Lg2kJDkzXlU*H_ zsPSZ3jH5aXylgJ?G4Chb7BdDMP)yh$AHaueh!cOF9H;IQAejLqD%fO{S+r*y$;;T+ zCX^qjsT;NHcI#@BC(@GMoj#!=nnm0`x_iWHNB{15O*sj|uW&!jKx3roYB{&23iE_9 zh_|T_{KscFYWv}gdM%LM{_2YJSK}LtH??3;(|i+By{)A}k_t)#`KMH4C{8mYVSWoH_k-nE~!?*j54G&2)|K#`ibfpz5jPu1Yc0u#i1<@lp}sHA`y zUxiv>l*w;xMTP=o@DmT$e9U?HA8OPcsD4tT7EMZO)Ni8!qOn7xek-X_xmw89X;Y|J z(xb|p-Nu)7n$+0iWyg5O7+0Wq(21l#Np)h{;U;vn=!O%@vlz9}xK%i)D}W;Oqrdg5 zUBOPRD;SYL{7_&N`yt9wyMki&2aK@@@t!^!5yG(cytwRLrTq0uxxAND{Z8T-jvEV2 zEkt#;Mbjp14VCYNVs}*e*-RbM=SSyLwvzH*+xjkP;KYhao^r>^f-7GXvpO?o!Mk&; zqXC}=MZd7K*?{cI%hWA&@@~N%&5y_ME~6Xq6#E;j(9?GsWgltvCcQmyv)CXFl#Abz z1{wqCaa_C~v1^^kcuq101}y_OiswrM(?vB23PNuaPxUlXMGJY})Cf8RHG0kv5i8IX zfD-SVNZYH~2wSb-dft2GFN)xl`&j5HaxBHJU?vmD++&hr1$AF9bR9YK#Z z?MHm<5QGU`KA9NYR$`6|Ib-V89^bjw%wUb|UDUtV+{+)>-g5R%p#PmY{qKCA?OinR zHhX8$02zwrADUq(ZiA(`Ez)GYnr!@581R6c*VK=!Fz8pP?`BkBXQYois8+(#gNbKi zuLF_TlwzRGx}lbuXhl?PCs2zt73hJDY;xi?2`rs*0~`mk3q+{n0eL}`wF93^c@c^T zmZODzh?43eur;IEN;vW^>k3T z2_KjAyc`(K{(|0}6RSrU2`t%OIEEn0%_Ha6M;;>g6V9#wyKE>5BOB~!%GQl+cMQt* zJ6*PtDU?s#g8>TeGBBx+NTtt$Yy!SfNq6=Mj06lW#B8;G6jsM<5TvHrcx)=BG*_Vh zNK+S>=kqt+w;8_t3y^D5A>x$o=O^Rl>8V?4)7SrK%O_IlS{h$B)Qh8<=!xB_6=j7o zPXn{^C=?@rW_!~E` zU_oq32SNQ9#y0#ru_-}%+lRNhI;CF@^p>pLFOHW!GU3q^*xxcrnkI<-$~5)_l6VHh zfB4zslsL9C`uC=JsKZ7t)s+r7uWMRJ@AK*XLVDMnIBX2>2%wk?WR4f{9|BfKcHXNr zO4u_)q8`G6h+PyBVIxr~j4+@iaIOs-#+#Eh(u{+_;LS_ZUVY33RFr-ny9rjVkFCZK z!N=Z&wd7;B@aH=IdkrY)W9NJbe;k{L=ccuP1v8crR$JT~NXmHwtE#G@&#;%Ds3_Xw zRUJ5N8>yz1C(L!LF#L>O?Z=jXYDdbFsmA`slKOPpQx%TTibChIvHqsXXbQ{%Oo-`X zE~3(BNIeCf-7OzPP14N+uoDNk`3|pO846XVbO0264nn-(A#xMKh!oH9s*$lbxuejc zv<{$-(eX{Q6YY+^04I)R*K+ZKKu$#r_V;S-ISUlCz{f{(eYj}U#xO4yLu>m|#hy4# zv9E!%!1%nTg=a1{mbV7A!+>2YHkL=VCENp}VpEnt9QpCf5V}NywUnS6%{ESqks!wH zlyW*%04gGfds81G>JhPWp?TIJlaxatvA(M&peb0JHr61^JvJ~pNi@hh`~*D}3pArI-1ZPI~o!8-g#zuP^ zG(<%c5P1OknyrihhdOe;(jdHIF*KOvA@YadIks#uYk`M2(J(OeAg~EQG=hw8VLS#V zVS}|m7;wii)@wZn1Y;VX&f0p;~T8AP?U#fbDGJmig(IIe5(JyeJQ`!;1n7{gSU+1qzI9J2 z_f9$5VrB47iB<_GTmi_>$;}=I0u2J<o`D;0};b zZRTFmaOy`G*|k`z5}QKV*-`#TKsl!DpZuM}qd@i+es;y-dwU#b|kkVRULq#*#VuZs6 zXh17%66OJyB3eXFtw9WcVm~+7je!}>CUy{5acT9jU9h$5_>_v6>GQIK^qLSaZ+VhvnD>TDWFKa#!XLQ(yyPVll$yvgZx>}VEr27N(^caP0D zL6=0LE^twac?F2IYz+DXFIW}2lSY*uHISC3gE}}le;a*rgy%?0VLt7Um#en;@#*&pUYeyWF?u`{6un4U;xLfr|3~SrW5!l@FW<^OUuPRLM3h)Soiqr%kmAi9`Ph1JVlmV~n{xD7RoRaj!>y)&fp{ic$Yy({j+ zDz!rdVG0M3PCab4G;mT(Z=Gvujka`GnA+O+1kBAx=EE%?sXV$H+abcAf3I)Xh~wVk2EP!@|(aYnnme)(y7~u?fwi1{;<~ufdzokD14X!ypk;Xu=s2 z#)kq<6xl}~&6`>(8fN*JAs9@`^44jkb>cUgafmM+SL%r%ZH9QQuhz@11Vn8t$cO37;-CNr29U;2i_Z@{ z8{^opCMYL)G$AIB=`j=b)aMn2>lVS*jKro;$!rEsM33a#-A|JT80FW%g|jm0LRu6~R4#j{?QZ$!{0q)g_vyW(LwLqKD>2Kj0BN5kcN0AXu&>v7KS7coqNNa?h&*LJiC0Fk6Lkw1<-iH07MgRwTT>HSd6?y*DbZ}!7HcWWylUyS zmkjVxWc!ih!k^E}?oWD`m~ppDtooP2Q#sjJ44^ObHf*Z4wXi8F9az5PomosHtqLMC+A>>9v~ zRSg}&IvH7+Cn{cE%ie^q2JMQL(TZbhYHGdcs@zBwdkg(*F7;b%9Fo*wv8)}dXlW$% zEGdadbiU^W5kA{MYb?s;f7!8I9MkZQ*f1)O!5NC|7Gue0HP|>{qZx*fFlgfs90F2V^Ud|VQ7h?3Bo8U zqbLGWqLK^&A`qMdx`{vsT8_slch~OPU2ApKUEADUch^VH@;Za|Ak^^m(a|6!PCAst zR23*M)I*;vqlV{fkU3N6bBWc64IQdGPI{4*;liV z{DV1sSe~Mz-)8L<%LnD*%bN`Hnnhw(G;Z3O!h(lU@HFk;fsp0Y>d#0RgPZaKF0GW; zWC{Hnr)P=C%Ds5XdU&z-DtezY0s zYobJb9M76?^Vb}m_IQ+GqVf&KrcAe8=+*bn=p71??J>G+W6cQaAj=Kncimt)MneCC ztOk+Nuvtp(;ukyOS8#IT^C2}&jz!O#WGwKo(3L#fQ}1|TxJDw^tAco17SbbpQ?nL|%y z5#-avL)fzMWUhI1o(5OOQvgZCB;qR7hDTVvkBQDP;A%Iudftc9#bK{MB8A}o>l<-9 zenzdLR8~cklmqlWTQ7gmx(EryXARxP>Ld^WZ;nU*N=rAT1Yxa1hys#mmWeelF~Mjz zpPY7J&iR-(EsbxYXL+ z&EC-`5bp%VvtEv}wnahkPUyFPE^>AU)qE@T!>ZV23Tl&BPv|%!O`s1fUV;O3Y~*4V zpvLluy$6J{jia57)^pT7+@nYy4Vq?C{4oIdz$vKII-V$kIH76seDizJsp&W?eyv$+ zHGGG+M$N>2JfuZnB(Sjy64eiF(_(dZkErPQJ4Gd!Hzcq^?W049`hA1guMXRs`h5e* zO;h>Xv?7$-QgDQ^I4mt$NrYCVv_>bb(MxL#FuAqH^!n?sGY%MLw}^(dhS1ueIGfPn zcwrb4?#H19w>CsmJ1};R&_Nx!KE<&!JPS)vTqK0bWnCib9jRs`KA4>5u%Z{0>O4bS zXwjOw1C-oY{Wa<&s;;)$e2upgi+@Wz#7(@5Zgw#^LCx1$*66gTuNJA4y7cundxjqpbWK?G*JZp2W6JFT> zSV{vR7aS19Qk8eGqav;d?k+>^!b z?}R~pqntw&_eWxPmoSLVj$?Gaf$l?;)+g^JH~8dh%)b6!0<^^a?m8i1h8~V z<$7U&T(6vBOt{vc0TmPq3#NTBD5$X-(=X@2!FpZflr}hvp$DyeM?E?lF{?bS%uRM( zjC&hF#xAm2Ggc?S$6-~Hu!mO1fwB4lc;(Pgbi{>$m(&0q%czsnFyx|B6zN%=RAMkb z--%CDmVbrpkHh5g}K&NPDY?U-ZBiiX=YeDOD}-%OrMUOnb3?j0~L4`=d?T!#YMLd$*H7nU)+IEo6Doe8jfImz-A8V8;a+NT%!8Ea_e*zQkb5j&y3;RWMi z!(iWli_>l0jPl8G`mNj8)39|1o-k#AuGZ;aZpxMu<4oC-!MXw7F>Zy0OrhRW9=tX& zG_1BZQlx-ZHGqh0IcQWU5trK9iPaQ#9!I}urXI8hv$5NQcsmZ#(xqV(1-mHU_(c_Q z?noeO97KcHeJ|KYg1PFNTHIu%j#4Q)11K9isHGz@7Y<2W%7g77E8-MlwQ$0qyzi7$ zv|W0mKY0Kvkbjzua3pM!pMQ(qzqGuQ#urXWkg@5_k)PiMKWx<&M~@bske{c8HQw&T z+u$T+7QX7)L#Y%ePX2Jl`TXwdB0SI=VJVB?*+cm$1AF}g2y-N?QxnD`=NS3k10PzwDk160LPl7C#xztC(=>HK)D|Z7KG2^gyb2D5M9^>F9D(2)nf z#q?Q+`w8VXb^4rMgeBG*OrK%OYvf&&@0~+8e?qAnlqpC-r+rSNcSt*?=gaI!O3B4X zF^sPpP)T3*da06rGgeE& zN~xUBUiZ>wyl1a-Y+#R!qU?3n{Ooo1oa}WgvNpX~vk~6%Uv?rJM-BZ-HJjkmXl)_U zbLlVZDLAGpFG;Fd2dBeYNp_MZ907^8R!Y_r4r>eM6RcdYKdY03b&~b8Dtn&C&M8C42@piVq%ZE<37j=+2GhPFPe=6Hjll+l-6py6 zFcryG=Vtn#P>j)NP_`OOkA&xiLlnUZib(1ReU8ICuQiJ<$6734b~##yeBDd;RC3pbbioUt3J=K*4kB@ z@m+(pn@e{OQTPC&#}6W(sHWPCt_JIOTr6^g+(nVjk!u6e1RB8IT?%xJ2y za5_OKq%qQ|5dw^Rtex&4;~v`;DDl}lgPdM8ZEds|BY9*$G6-@pLyX2Om}tx zg+qt71+VLK@UsE15748d{C)b&lsoiYd*XU^V;i8c+()08;c#1hW^W!AWHlOK2804k z06l;MbOImfz@CE+?0-_9nLZ|asL+c5Ie^vV7HSKRXpW$iM z{$@ITm)AuPoFiF|rl#?FNTxvjqwH>lIJ-=8TRl7lUo2oykc??qxl)g9zpf~bP|#`Al(ApWn4d1r>|E+KBBo>2-vr=77@q` z)JnF6Fq#jMD0^t*Mk3a&HNXdQ-lczo&YtB|?QjU_9VBj9OtjTd zHh?kAeCQssoPrcNP6OB6wblq(hG70q{abCr*e6Z}1~I`rHQP$z}D6RVsWM8lzjaqkuRh_iKw(-jnSILJl{K+eyCYK}qSOEL)~ zpiY~llh0~TI^83JPHCH}FeP9Sa7Idk#XkO1WEgaO$>MA&LGNRBTqi*eE_#M373(=n zv3hli4MQ`er$ZVYca`J~#KkBMp-t}EzCC-pat8C7ES!L4JL7)q8A)qAU_C9x>1cL_ zn02c14A!Y^$pCw+UWI`vSnp9QLJtVsi^Xz1v8QtCXm;&m9^l=yRInbSz9jB>P+j?u z8CGz$O&u*AABrtx|11QCnP^23hQN>+2n+2E3nMdeL3P4t3#77}%`;}WzPa0-ZL zn_Sd{5aKwrKOt>N=;RsilzOl)K94cr=pKG-9;>WsWKav zK$V(=l2GjizQ6Ja;zOt0UwMEfgaA`U{X9A!foaUBc1SUVeYY87j}Mq3dhUeWvFA>s zScd&}N}g8PW5qJBQv;2oaqxl1c6iW%9t6WWA!>kwtxyD1UF$+`HdarCJEtx|V|p_L z)Gzt%7Oa+2l$GGoU|EZGtoImlI`%%mR6WhUgg6j*YViNZOITWahR}I72*Q0iJCIM# zH7xa0l}CGW=;=CsY96V|ix__~V&~-a(ut|cb2J#gvS=Ifv~OJeInr-KCJ~3B5jX?t;8f;zKMf6dD)k8>B6Pwsle4212n<(P2YGrv?C^&8i`AS-HG1g>rNbBV;`!XRpT5R<)lbC0FyEqg;LLF zQ!pGJBEKXxWIhXlFc5E%W5S)vh>jEB0C+2@?}@i+VNJD|p@}-l&M1u=4$24nNW;;N zwfBr%O_8V1F#~U9l?x4Gq>dJ|5?{N6waW=N?7#Gtr&E3z10wTN#I4Wy=o~PgMWb(P z%*$A+QKfE;hihvB{Up*)k}p6GCQ*vi=p-GEpf4?NH)tUVAl4bs8{Lp>(8AjGV%RqJ zrwHg<5Kp7@%2SkmeV#cdhH!lU??ezl52W%I5=OfgRFMcpdq@+dM>zR=0D3@Hgj0xD z-XjhR`1dUkS`7iezcmw6(SAa23;np4dde2bra`FR7tI+`r#X=xw1N_Z|DGyj$qU9k`!LyoG+er^ZRjtLWw6{KHfW zjzKU#wxD^T2PgCc8IMB0j<%j7$@V5pX^4Y!V)2@u4@BW$H|3g6xLckJA(7M4jHU1g ze|c_}WINF~BWoS9A)m3Tu!sbG+h8UyGK7Rfv`37B0z+q%D%-2STLtWA{f& z0HG7$8)i69W4Vm*lw~D*Qe5fop{QB8yoJP&p?AY6>6k&&>si?Khz*27pBF1A;hvCY zWWgv)*(c~4tS2l)9jLCX9#;;zKw5B?n}E3leG69RaP+d2TDRkG-q!U@pm<6)>IO<6 zIJ!@Ez$l4g2CEN(y_j$4PZ@+$5;O(y)IiKZHM z#}mF0h*OGc;H?%kpA~NcJ(L~z5@;@OWW_x}PMonq9ENUf*#L z9UDrtYyCi@kj)p^ULw)Q9S8l$e_OVU0LuRud>bhLcaZBM`BP#8|Um!zqK#?jyc z>_C$YFxdreN^yU&E(EfK7l60QfF+A6u_kcw3~6$A#43Z>(B=HvC?C&l(gAD7I!!zf zgCK-FU?vXCC0m!V<`e>w9bx0-!O$6(Q@bRniKkp{Kd6B^ufRL6>Sl>or&rjg=ykdGsH-^%95e-kyCC*qMxqg)W}8q;=B6`qkzE3q3$rpELTs+rhSJH8-bAE z)Q?Qpk&T{YJv4~18`0V>OHb%XRu#YV^*CJwPB4el_p2G5;^#o-va#kx-&CK?JC3nh4Pkq&K zW+V@M6SX>FBq24hzQw`1Bvj+^lxv_r>=Qbw9u&nNY2LVx{Zw{#Sgn^3(-KHN(3kx`+oA59IPl^;M?wg86u-WJxdbA}hYTJT)#6WaOLgK3eFz&HZ2Ta`R`Qpo zQ2CgE+!h*1kZhzu1X)K*n=oFiGcB(RftDM61q(w}X0a1!z$h6AiF>7}jz2XO8?(#X zL$oY@&Y@TgYrQWO4QorIG~L8E=IL@cGh20-I0zD4_J$aQL7vjy&roUIzYyo>J<{V4 z>+$##VleXtwF$Wa+X9T?d1QNEj>Q5;eg-&y&t$Hs7VB#mM8erx9w zQjA`TA>;6~gv)t4`5F@$b$(&gu7chS+S7{)R^ED=s$W5yIeyL+;k@=LWT498`vzeqkQBBYIa$k+a;cFn`ya3b|~c$ zlFdXMn-@}mR(m}T^{sGVx%sW}MGIUYJI*V*nc|hHkP$5n$eWr@vZ70LmL+;2PQ2o! zZFkW~>~th*7;#%q#O*#J6+_)4L??(_Z{Vi&RJ=a)ZLS`3`gr-c+swjDj=47wj%tQ9ynSPw z?3|%y9Py8INw}j#(*@d=LIVBLv@R+Bk@LTm zC|E2rIlFap#O|q>Ip9Y{THFqeKx0iM6b7@ZE6z(%#7 zxqB5(K0{xuSXzV%c^GAUt2i)YM{&*yPr41_ zvwDuDgda4g+mLdcH)a2xFbhl3h7?1TUt{4)QaOmvM6t=Pda@Ej%WQeJNrFKUlQ_}C z|C=<7AsJ_qP2yD#=nby6UdOtfyn227C>!B?TzG(qwW+-^AzqI5m1TejR+fHJjjG22 z&HV*Ynw!Uc;`;a~&!}TKCRQ^>rg`QipqWiGYMMYZZI|T*S9Ee<1Xetke4W$QxrTbC zrNdaw#4Ts(EVJ~&B8(~p=G3Ad8a*x5- zQKPM6lc5@Wu%X+}lOF`me5yr{w~o1ow8& z{?F2C%kh?q>Kqqa3!VC^|6?Fy(98*v0;R-(G~_`Eg*I(7jcRy3f7fd9}1X|mc-2>IjiC>|o zP^+gZZD6e4ia8-6VLhTwz_yT>KKa?`+MNSeN-h=vxmW{n-^5=t^+ zK#LikKE4=Zy=|r%SFCClbS{MZ;IV>XGT^A#aP||yns5`N0?D?=01JQjS zrsSZ89lt1Q>2)-hXbfNktHEQ>M4TKrjsKZaUtBsn^^FVib) zXqfh42Q8r+Og$$=v5p+1VEH%l(NBIU!Y9LYs0_4>r5^%W+)^V55NNmjqeEbIRPU9#688 zi~NusQm=(eJQND^9YO-yBmixKs_$t7VmqpP=@DGY6qZ?tk9{x} zn1ZXp3F9EJqnX~DDJ`Y@EL!DGYzfic8G01DA38sD<;&02c#Jhf9=vTe1|0Y{1W{X^ z1Upb^15XwDr$T7Wn1CR)$r2Og*{h2kWi=5W70pVc{RYV*uvJL|8@64P z&Gs z_pYoL!6QeTAA$nPlZ-{s5v#-50k@Ch@lp65Y<}va4l94!M$%R}p|qnaGC@p8d7PEQ zkip`h7?R&UVt;^cf)ye^;CUv@^GvAcnb8Uj}j22dM3NoP}@X6%?U z>g5aaCD{pkq;~=<7TSbxkLNtv0hL6?U~&$iUgjyDN7+q*bPx;bJbxbQG(_2r-o-uu zT`F)b(E@`+MPD`XZxE{`8On$1sE4vP4e2X&MCTAZ$V!@gNtl?N3`(4q69Udt4us$! z=sQFgOZ!(|FHNCX?jgO}jDd~*&&Za}w+=FvvkeHbhLwS9S<*3jOMGaW3if|^7 zSu9PAWDVIu@gb08tbQGtTk3HG6P}nOj5SB$h|Vxe8Jz<7mSh9fYL+LA#_)xdc}6%? z7=;kyOLdTsa_HVcT*z6%{?!>e2{Bf`0FO0sd9J9F3p+ZHfAM3E_^J9SoQ~tl1}mST zKIKC&)EL%?s}0fO195JFqZ24f^8Fh*svvCRpsNDu>Ws_L;C56`L57gUx~y8|f`Ax( zi+1s!;mh&_suRd$u?Q-^O+IWnimi;X+KC9+9aaN$TONqc2s2jif``QxW_*!k+EnXV zeG|5>r|_d|tSa`G2z#t_`+Kp!LkTDBFGHs^uQ7nI2Vd8HSCX=<^Tq-|@fU}Dh!_if zGEhLmo+0OJ!h3*Ea>W@%DDCgQj=Ared*_2l) z>Y-35^I9+Sr{xJ8t4~xmo#rzBB?WaNoA%bdNWEr?*y$?6MKwLOG5`k(a+l>A|F_0| ztX3LXt=KTDT;Hsq(teooukpK4E3i>1fbtMGL+C^e!HAi!lFq1K)J3(s??vT6Eeq%Q zP)r~rYZsL-Av8z^quPLV$0v8Uk3w?gC0aqb@A6e8GBf#VoC+kjp)2wIsV@IW3nDOu z&<73C)=*-NzskHC9CjCo4pwkc?Ov%aQ01Qf(W z*by;fggyyQ407lwlgb+uj;vi^?s4j{7`lykvZ1TM5uFjL4&8oi=!W(VT{8_`6C1jQ-k}@n8@jJk z^G>evV6Lht8{c=>Mxc}2IBZwo^x}s0#cqhtb?Bx-RwG&Y`KzpTVY!O61r1z$3FM0` zThdYj>~1P9I#;stK5eGZ!`%Xwvl(IN%|ISqI}C+UUqFOlIxkH5&1ki2GcMH(3tDhE zb!ZbhH0&&33H%-+&^0X(E8;)KN<^g_-rfLw_B4Gu z@V=qxE4EY9hqI^WZfkUhhclk7QBIl`Wk zm4kSShhjXXG0I-%6|ek(Jrk7QuxFz3OZH4se$Ji?lo#1^q4Hz)T%=U6=TfDNJ+qWT z_RLY9X3ubJ=sHGJ`!=D^u|#6!ui2e<|b0cMol7mHU{pmYjDpC!IMd zCgvnktoSo0iHs{(_ffKqWdcY6d3kGQ2+X zRi6-x|01tXjOr6=@n7oo8LRq)S^TrSK4Gel+2Wt$^$BD?rQwzd`OGI(>Dsyo=XOn=4?Z=D%7ypf(V~c1L@K?Lw8m zwICm_u-)#Sqi7JZRPPZb%&rnY40p}=;k>6m&V-Dw>%!fau(!n;1O7N3S{uNE8Z^eO zy6}>(WGBd?YTwl>WQQe6nt(AVm>@_e4DyPyVZ8POi<1cqrVt)v>QxmOtU5u>NacAS zX(25*+yvOiAto*Wv6&zb1wcwXv__wFz;>A!Rge06l zZVTJqIpQ=^XkAwZBotK-z_?ep&@F(Wbh9vhA$l{(So8?fch+WHX|P^}Fnu6N(04Xi zuk=XJhma7xwF_6ZV|sy5ejYAuj=+u=*nkIanuwVmYKKgiAFTcm<6bL_A;aJ|6Y^K3 z=Y1SHnnr2Qu^JO1_8fF)LGKQONgCcj_}Hp;40hhey$ONI^4Y3Sxk@@~yC^3FNH&+8 z;Ah;+ReetKhE;CQRGhoGOjXx3SP`e;;t0vA2=`+#UKhQn#w7$p&Pu!bGIsvkv3!KC zUAgP^*Yo^dU)cH*-bK5fOLahju>AD)?c3!E8!=GkfMX*&UluE&8I9aox#^v@G5fMjP z42f^u1#-j7c_Y$CHM5+n&Qrdt{O5?rT+@k*6LAc>k*7X$B-Xg(aoTUdppeJGsC@A~ z(J6ZO-C!<7P%IWa&{3?hP>f>ST%sxIhutpv0hfTQfu(_1f2?Yj!1c!p;;`qGYb09g zGNDi&oTp7E+#?Q0)qVRqGfAU~+p+d%Y(hO^m=PBHUpLx z;k0}h6}Vlkob5O#?DSV_XS=szMEhk{sp4@D&fLBLT4td2KuTA~2iRFV7QNzFYIBHW%J1|GS{PMa6R)uyusNlx_?& zeYJ(&tL!ci>Q+qQVYXsr?9P*@FZMsf<;p@`n zmsi6K<`3!8kU*pE%Ifvh=U{wyoV~jV1Q0bEbXE@D477tXT;i1&FaW{DOgV?s7ipk7 z5XT&XKYXO2OMGylrnZp89StmZBoW&DPxnAu}jL>fU~IgpoYk{AYLQyo%L)Zf)(jdaHX*Y zky3W9^@GVi15EbmCkMiMV6dQ_=63%%a;@Jq@k)^K#}8xuMGA03U=RIpW$U=gEBdkk zEahgo|0dhQ<^H~FOdvw%pXZa=Dz+E*fFQ|1D=2c&=#^>kb?S^cP)eGP`34Et)3QXDAN|tVcfcvh=(G_=z z<-3QL1bVEyAFQwK2X!Zpbr)-lgczdhY zjOsP9>a|c3ed}|?$FXhnE$je$F_Uuz*AlCasWW%%<~#*CY+FWooGJ=&LP>Fbl~ z-EWKKW{#hs=IfZ{!AJRn$o)^aC9Zr2r1#fLFw3$HXAzK8kGAeEHC2{(_^;M>TRY~W zZY1k&Dz)+X*AT;1|qV(qFO@YS!ZIF^VQFSFL1b4Rd zSF81NxBnaS@GjXlxq~K08((}91yX}9wa$gxW801I%&nZt@s}OeL*SC_c353F_k-N2 zY~6$_LSWLxwz1r=qeW}o6>ZxrXtmbRXxlbH8(|HbLf=l=EU zaD4F9Qj1fv?le~KhF5uTM+@*Hj^0j$L}SCP%a&}1qHTykhP7quPG|W}t=OOw^Vt3>1J{gw@HOsDhGoxVB*Ba-J1tpT zAWJJBWQuE1&QZrleZY33*|tV@ysPzl-gE7t#Gdir0to2j~L&WmKFpMFVAA%rX_DI{Y)&|6ZxWA=Y7&)UO zPS0Z989iGk42ljC21vGdCEH;XxAj%T8)@6<5Lz0oJLot|wr!MCc4(VwPD&}8)}%NR zgAa-Iknkj8BilC1Dcg*Dp`q7bwAbQz`v`sg)Z;2%sA}}9qXK!>SURj9BYCCpkPOop zw$sh_)6Uir@)>P=&?QK3J1>mTHU%9~_4E*55?UbXU2z1?3R{nF`84@>$64dvOWN*s z>uC*7Lz*sN%4m^OTAEjU?EG{@vl}a1+iB-#Bbr--j?9rVkk4tMIa=7o`)7-`)0*t6 z^3z;p8TPlQ>7FMIU20va;e;r${EP<{FRnBk^ z$o5!2aYMrVLn0?<(0ZN<^o)`)=qR3{K88zeBwGV;3hI<>N3x~zWA3}MnVn$!VfA_{ zf3DI~A=(ddlJ#A&d?#nDS;0|m3wA*vmR2VRXn{!KOy0}FrmgE@)4aaZ3QH=!pk zZrp1f4n&Q6kH}|pn@l!vpWJ#_>r+A-b1)U218`mQpTA!g;CuvusE|NVbi}>fbZc_XZI@773nUyHx)i-lBEm0{N);X+P&R zZB3K0dKD2nXrtIRLYoM*&bFy|uzbl;erWr4&}ERj2FbcfhSt!kKsg1c((>{B)VNVc zMx7beEm`+TR$^n}z(i%LWn0cTba&#?GNY(P&e@i3FUgxiWUdWOn>__oju~lEAbA0d zTif9q)sB?Hu$T_3!id=5XyKeNAX;!?z)8Y|){~Ud(k+C`DVt(CruiscF;TilKbYyi)mFjn+Cw>{7PLLY)@sPLi-|%|ge5AucIp2XYb*>akb?A(Vxk z#=Vb%!jWXiihjVaCfY5x!K-Egw7Lm6(h&_)d=m$ zpfmoYnVgMT2>7RT62+^lnD6r}PmoV^d}!PYg8i2EV7s-A(Y$>$?$iudbP}cenlfy2 zo*&VCA?S?9_7=;lO*k%=@8cNRYa_DP#>ieu8(lUBvUk--_P$|c?;8}gosqqEB70Z8 zWDl`o7}>i@WUrmb-Z$A(JQYOpQocbqbU`~oO8E>Z1v#aZ^XQHj++o?oa3E1LmFWQO zZbtN67~%?D8n_%JkF>NDXRC>3%BgQs|1v(8fbJs;A7W)?+}kW4Lx(#x>RVqYI|UY* zWZluz`PkG-9LsEo5{uuGL!DR^)rl^L6MUuhOBUsXFbs35ucKM1qd_?d9nE^7wVB0e z6G9LJ41dhJfzj5}xJJ!-0vaUtoiOx+>-)UjYGsjb|DQFgSxqWJ%676qc z4m~3mVGg~+@(KFXht#Lu!k19dZ*kH>)}b&o_n|{=>*-K$#>9B6JG~vM;wS0^8daBV z>0C3}*P+Hzhsx;Fp*{-wu(v~bXG=>bozA02VWrU7GlyC_F^4vGv|zAmJAM5LqXJ4C zEI+kBxhX$ie@bBav|$dl?)Y~)(>SplooO_6B+2@XaF^PTBx^gHLD7}e8MJR#q8YS! zIQol97kq3gwa1{h;9TI*Y#DtHL<8JS$@&?NXM?UtR`j&;3vL(dX?=Sc(x_RrTSGN+ z3KllIv!y`(5#xa-jV&bF8d7n8ws;S9@eN#M!!)g?cQ%>k*Dwt;$uxhi^^aGu@E($m zwc{GC1Q`}VaeigW(^q}fJr&&yedb9RZi8qS3v=poYO-^yd-Ux*+FlQr^Q6 z!iP2O<&SiHQgt3bBu?Qk4qNbLM1y}L$&Rd&Pcft-wA4i;ZrQ{)os(c2CEw@_1PFnv)5{8Po7Xd zK(^Jn<0~!ELjMMBvi%P~I4azq#$Oe)rHLogC>ZvS8oOEvi@bwe%8?jtf{3jsk5Zoi;|l&uaI8Y338 zG+;cf{h*2W-&ctyZ9hnwvv0Cb_yyIsAJkDS}Mz*<40JI1F@q(>=+@oR7EUCMa&FCjrfvw$*5*hQsXqRwtok6`SF3+LKuT-`BpC; zj;Y5TQslbGtl0nJENKTXBD)c+e)3FDsP%RP^+xr01odd5r(b)$nVuS|&w#2Ugr#vW zZX!NFbu_B+Z9-G6Ml%z?;s;NmlJR<|_zVbo-yIlq#!cx^!K2>e4JgF`%0N|{U7s#gBswN1`Z9X=NQ$zeE4nZ0jS6a zfr=T`9EN8Mo(9W%!X1c&)&Sziyoev8YJZbjeiXEVWB9O#>M#=%!zYHtMmwQ(*#vKEOCTb1VGOV;KJQ zB>d^=Cm%%r36oDmH3vC64x-|*MhZqiC29JT04m$|m@zUH=TAUBAPiXvAt)?&p~j?& zycuhLj|4dJWl(6%`3ZErV~8qDNMZy71lPzm@XyoJmr? zUC%r>GtX+T=O^&oT8kH~I+B!uFQ`The3x$f{ekT`pylX?-AT3jnIz>kB!U#w*7Zoo zhvek@{C@)f^sVdQyM=ymnrm_LtD=Khyl0XW1>v3v^d`3{A5kXX!pcM^p9;y0`Gh|% zR<~W8mxsf5*F2ox)2$JFK)Y4Z2vN-T+zyAT0PMXJeA(~4=(XvJ`&ZdO@ywh%o;h@! z+p>iUX|Z)Js@uG% zANIh0gDJ;FBJi^|vxRB~sR;ZXD+Q3OVM+`Vs%cckfaN_2-N`=T|A`O)|AgfEnACec zc7qUtgw#79B$srFUx7(@4(c63j~xh-VkQ}I6GTY80_6*-U$wzxW+0HLhwMIdSYRDm zr~DopNr>$_c81@^1ZKN`9T?P_R4BFwD*Yk6l&<{j05ual?oeKWGhK}WsoTx?@c(g( znc6Zk5m*U+pK3HSkF0$|M?c1AGxK^&nXn*mX`RPI_WUp^Q<&KEzWXqQAYvL2$Z=#l z2KOM`ET{bl=nrgMbU{u#5TAscwn5#yts8zBGud|E%ML zJ5_n}_&@8FnfSC!jwNuo_ktYhveYXbyaMM@by+ZXfWN9$I>G@KAm0x+ET5d?0m$WcFBmGH8mg6#7M$ZhrY#i9J1!c+6VQ``b zNqEOI#KZ(X1%C(F!EmvXp|AY+Ft6+s% z^`zU2yC1=b#IZ*CX=C*gWF=1^bKa1}n8)tJlZTNUH@{dc2PIiZ20LjmlUU|#=4FND zXjE$>*nFr48s{y_D}Mx+zbzdXg0Fe9s=Ez4hq7cx{G(n0;D?o9`phAWv58)x?uXJK ztot#NlF%n^?_f3(umWpsMxIGZ6b@Bz1MPJJ-x!rxh0`6dEe_qIBF2HxjLqNF}8bgb&oj<;Ep7AA5M5)1Qz~taHl969~Za-eD&SsJ2)b zP;RQ9=YYmR#9!Hu&ZRs)`uO3amd-TD8}NUf0}oJ!~{= z88ljzIWZs`ky4RPD$*ODpH4Mzk{9BpDaIPyPR7|rI3^Ergxnp}3`Gg~TiTg41s#*h zFUlRF{URrS2-|GhCfb`El{4D3?O=v{;FvrdhUFv4Ok08;+mCCsXTC^10JCt$MQI{` z7n51?iNJgm2ffE49j}W;eB3MpUW6kIcCIXE*@m0+vaqXKh=r3Uh9sFZ33~dr!!T9; zfc8z3?*``tn$CosBMf^beb6URw_T}|7Q&d@AjkND7F>(fhRhg8h+!g@Uqs3IFvncl zKph7vS9}{NXk7EUIHdK^-B=JrGH_t?V?7E9^7{zAX6FTygzuT;tIkhN&aX{D$DN;< zs;o*IHi)FJZHg|^^Y1g||C)t*AyST%SLzT>Od|Q1wjH%9MPeHUra1~sWgxbB%~5KI z1U-KOd}sw`?QlZjW&92gUFFY!QMMo}gyX>R2}u-y~7?>KNt-H@^5791vT4u<}|YNQN~86A$Mezqa4x zm3;8zh0F`v8qPfuVIZv>5hu6k#uI@)N1%~YmZj8W>#Jq3hy$l*lHG?O%_{7$xvXd$7OEC_X|49kvrh&W8GIF+`U61JTAKY z`2JOp8^;>BtUro4CR*q!yJqXjW9G zpEMCsu~q5F=(?`?U;x7%>WdS3T@Y?|S)$70QlBIX)0hOji#jmq&9I#5hQ#O}v9Ey8 zZH9W^OKLLI_k)^v8zg;EzP+)3eqxWAS09DaFYea#ju*#$0Qeh1oOTL+#SsRxJnLdla5ajC%NNOX6sQ8yNw|b zO+&nnPqn9>ygvE6j%l7J>wP9!v%+zJvKBFu%;W{Fi%aNybK`h`=SbhC^(&zmBu>AT3Sq7@-hrsJ&cm=@gwEJHcFHv!x z){S)aj%nYik1l$6?(M=Hi(LQb?|-odHsP|5oq)Fh?*du?=K$>hzl9p^F2EyzS%9U0 z0>F;|>jA$7>;W7CoB&(|_(4xB5b)bYh>vF}pcb$ZuoF-R_!w{%FaQFfX25vBG(Zwy z5g-r11J(hy0rmhI0H*=x0bPJQp44z-0SSPo07ZZ`fOUXh1NH#k1)K+b1Ly+ifzw@p z2LY1+34jHFEC3I99R;-1h<3iGUmb?%m3n{`D|yULWU7cYjW-zFYt0 z*R|$Q2=e4+0K$?rTv)W4-vf9zbEEOgaf|S8EFg)S39!Ot=BWXk<5er)UDAZ#lltT@yv*wS&~#-xXfNsQdm6Q zp2-Wv_M~EaiM@bFgxS{lbF7I`xWo*%ycZT*SLX8G$Q-w#WLaUc-99!eKc5@BB6sDo zVxF@WEGx{iCl%%v@b=<9>Bq(=CQ=^p_Upr^=a)=J9vq&@c0M&TUtsPTecZA6`Gw0U zt;SEQ^AG5!?;jXs2p(WG4IDH$WXK(Nh7P^!?yzCQN0>+6Gb;Sv`|cn8z=IKE9vb^_ zER&}^J~bwGT3oz!`iz8`vt}pS=FCl+H$Qm+G;SBBKk?)un4(>p z`P8y3d-l^gxp~X;R}>T$JyTr53#DZ%SN-VO)#Ym{xMHDz&s||R+lz|}i_IJtjH!P? z;@sq9)rVfWeMJ#(<_pdFg_&7qKF4m3GyA@upZipCX7MU>F6z3t*uIRQB0c~Vvx^H?;1jte=FE~3`--RXSDCYf;@pC#%>~G+l+Zw|+=5&_H#0x? zM=blm1r$HGAd3oYM@sWk!qa#+uPPLZ`{Fv*Jd-yg>Wab=-khJi+>YF-IOvl?K5s6} zHZRM}&!>-}rU<8pmKClj%FVZDnMXgoEWh{xbGA^hjMXW_GqV?|f)c)1SjMC9_|F34 z^Yd+)xdp83RPINp+y#Za*UR zTHkyQkS;7(W*_^*>w~^SxJA-8;*b;J*ZYAiZ}=k>E3VlK@s=7r4s-UgzUWFH{BFeYwO_e%;3 z?4UdkqvPOV=BbE1c#VsubiL&+EV38SI4CJZJ!IKSbC>mr>#ZaE$|8&#^cbp{zM~U( zjAQj9;EUckE70w7`J7@qMk0E_@*CsdzFxeEvNHKhpc||bo5Bb+Ohv&H7e|}hd{g8jY^ydHR0ynk487t8L z!#zM#)$o(Dr`9JV? zWBeah+TK_uuGg))$TAx?4OP#H)iuxmxK>&#uXDWc;`*Qb^k*Ah`j?+?eEDC0vFVjp zf4OIS}(XSe)-kcZI{0J_VPd4 zJ36miz1Hw3Uuok7fVvCA%^YOH07B3^_!F2mm#R4{h6gDfffI0CU%AZ5NlqZM0 zC?7xp(ygLAC_Sa6G+Z+6_p=Z{`4#6f*Mc0OxWwz1X3r|HdtVk{nM&Ta!U7hWEO?)p zJf-E3jzfG7@hA?5aBkeFd2?dtaCpv~GacWcXFPi*GkAPRheHfjKQqApM+s2Nlc>Iv0_T0`Zb4pEh;QL0${%}bTsCPDwi=7dDJ4XMiyCn{GyhuocQS2qO7MV zrQ`^rCGAKo`TrF(YI_2DGj+Bd(jeVoac z*XTa(8}ljq>-G8IEWRh7*Wcz$e*pB&w{QA>;E9a_+%BB_#iQ4Uljcj`_;KK=^?mP~ zKlyJs`TgOeKl}dhN-w|8R~LQj=`~#c@HU|D_xpxlLzw4=@VXoD|ML9x>HC)Na~SNu z3h0~vjpZA5`TN6N|F}N<#(rY$`2O%s_o{sJTa`axjK*{iAU~BY0SHYll=z=9;QN9v z?E6cAUwEvBV;4qyJ?FzO6n?k*`yXEOe~j1sjK)j-*ya}V3l|5z1aAkCDd5vMZnPF` zRHBaF@H^<81>$M~zXWhQRCelC%EwE2$(Q5qV4;i|%WVW77u<&%w#Xbe&o9xQS$gBv z8S*KZ-}3GJO#y$8!{K67@LS{i$z8#mY#$|#ZmOm3V zWi}92b3rfj!6dO~&1W1x?gedHW-dRyu$X05ly6sO1uxbSV$;&{Pn`n(qS>WR);O2NcA18oyTfi@1Y^9l5XdUKTxMBsWB{8?a9?P|o zPpZAR1ndbb=CQ@v1wM|Dx8*o)TA#dpo(0;J0 z-^`MDJNU9s+lzf?0GsIxlyz)Y7Fe*T^$PN_6=n(f-ZqRS>Egae19t6#{1QT*@$;9_ zo41a#$qf|LkSuy*bu|WU1O$n_X3v^gu&mfld?fVezW$hleg5H84z&k)SvGGFR>^#p zw_9=9^iB=8U{#Tw+pC6Vg8x`V%ZXU7ytfn-YYuowC`UV1GIqPQm*kG6+Wk-oaq_l35ZEWUaR4U*?u$J9MYIG;a-AtOOXa)uElU?z#mT+!s<{Xn*o)8r2rSe zJPrBf;tAmJjvG8U7u+%MZ^H(m4zMc*xQ#?wKoKBj6rO-x01mME9)tr(wxb9T1Bj%} z1t1A&*WAL z3_qk>Itl5f!5?|<0=|`iNZ`-Cj4;$i<#NQMvH;eHqAWv^_Z^5k2zd;KUkKt4!8ZVH zc;6KU9EKqb&<6LeJK;te*WJJeupVt%iRaQM@D4Det=onpPk;$=%?t64*~bJ(0#xF? zG8}Q!kq6wHpG6qjq!MZC;9rEkaY8~mJY5@scL87p(gL_p#K*VIz;`L|<$zxd@O1%5 zv~@Gym*Sfo;?zBeFyOYCzJq>N`3P_aPLY5*q+gHzVSX97;k&;@KRyol4)9QxhMNH> z1gryW0lWb?2Dk_auwxAdhy$bpc)*K**8uf^zX7fSLb5g7!+<$}Lcn^!p8(B(PQX1+ zYq*(!rvc9aegW7EI0d)@xF-ka<$!#E1b7Y50Qd~xmkS&KR>0GM^?=_2-UGA&OnDma zF+e7u7VtWt8E_dec)5mq6!0WK0=xzI3NR!eXYPQd01@z8z)8TDfS?r`?mj>)U<`3@?HV0w4?U9AFb*FW`MZ z;4>&cUt$=`48g3+DD&Pq~IbaLG31~x|d`wRODed@i zT29CLa{*jGsH61f0=XdQ0R?jdI3vj3KyDBQMhG{AyMwzELuM#<7k4)o#tq|!b0au2 zHxlG%6c-L+dmnc{ILr@Vl^DT|;T{4hewd5o#&M5uQCLS#;2z~3<0f*^+$0dB$=np~ zac(LX17bK0(h%{Gm6#6ciUbg;S=?+ck+X4gxVcy}&*SEU$S>ehu)<5@7INv_6Wo)K zt;paOb4$3TTqgGvw+vDi*^sRu8H+q_IhT(iUceRNo}Onw%u67BAwUwNj9Upwj305& za;v#=ZVgw#RdQ80We{jey~h2PyOE7RQWt&wusln) z6K4pMf04bIUo~GnSNuVdu(*a00L~zPQ0#=>~_NY@2jUjPc4V_$ijM81%l)A;(t%^&iG+*E<| zDPQ3A8DbSSO~}p9njW;q{rn99w#>Z3;@jkB%PqKVn6F*2^DZo)LvVHXb3^X8jCHH>-!kG&#rMUEw`XU9 zD}a4BpL1g+_~LvoJ{0(UXi)fVzs`1pHxyJI*N}GdcG?@UQp4jxFJhOGoZJm$^8ah^ zOTel6y2f3uSs^l4sL+6O?sV>a2_Zt6OGOA}%9NzyhJ;F*G*d)#sZgm@6s1sr#_B#8(jQfGnyNvspkN$)J3um7NK7Yz$ zChQgXgHsn6OZ>h5hzJJuL7QR{9^&bbn+<-O)V&q`9zR$&{(|ybPxi*+WaA5*a7gkQ z9Bt?Vf6Z{HazlN6ZQMe<2c02(We!03LwN(RhA0c?^u4R=L3P-cO6*6oUa$acf`e!GhZ!^!hv}VPgYuW&D12rPL34Q2(6bSb z9by*t_uLd`JCng%@*TrBVE&&mjLoN;SlOCeTiN~to}=|lP@lmP+q;`Zp7))H^%rJt z1qRJOqu{6xZb3e7zo=8cURaTzS@e;6pd z8Us}1zo^In?7yqZfCPV0nZL{PA2PCs0Y^zcE7`vdB#uO*{COaUo?76z_XoNjnlbcR z3$o@oSxWG0b4krI#~V`}qXpb^m!u1q0ZNXzm5tqNfe+I33!%1OH2>^rB673vu^0 z0!Q<~i|dIt_HlFX@vR)9s2(Jo-~AyE*nC*v6aEJT+t3AnMsW0o?H9*@Adewx(a*;I zByfA%{0n9;gBiSPzo34n(!av)PyD-t?5)R4PcP3Qx}>iWL(0$I4E`w4f1nIXfc}-mh!zB49diRL=8p{KVpZVf__>5hkEy;46Y9Jmf+|OJBdB+{=bfv9k?~ahL@W= z_;vg|@nNHCFtYxc;}3!KTU&>~`?=MyKQ{&6gZX7yU>@Ad3wmk&rv~)A-P2k8U9F1yek*tgyk9HP$8v|{-jGdiP5+5| ze@FZ?_x_GHIQRZJdI;|QGtzI|`4JcsN|M&I(MGsiLFgSNY`J!}>`E1k}OS=wCoG_#uMJThE1e z6n+yW@vnCoY?|HyM@HQ`z-_R*TTJ6-}7|??$-~vPabf;VZeRLfcuRD z?u8&fQGjrO|3LNoYV)^&%#c@a4(dZ*e_O);ZoHwL@q6n%v@`hs?sokvwHtB@^pV1l zQ$YP+Ddm4X?*H+rAQKIztqBsv@NX-)@|W_#-KOW-|F}0y&+HAO_dNNE-x;ik>It&} z|I)tNed@i@zy0={OOE4z>y0}7m-vQ#__=^zzPDkoioo-|O?zh#o&SpTo)j~H@y@87 zTdOWGuXbTAIHmk@Mc=8Zd-554`B(JTOwE$e<3DcHhlhIr{C8aRxL*I{{=EOQ|9d?Z z`g7|I@o#bVKT(=SkV&&5$f(;8Wa1MDG6qmSo(2!`vF^vipMkp$_&oFiba&4^F0a5H z2)rQRtN;KwI|4i*dSwfoi3)xZ0{GdeJQD!DU{59G)+p77wKX@G|g%@n^CC zxQh`E_;U>a{5iO)_53&N`;U(c9&ZDHrI;A0PuW3=7I-@0C+d_{!fPxuTKU5-qtJt z94`+5uiq^IJpLX49KXDP7vb#GZ{iWudh=H zGI;;gKnSi^0*4{Q$0P(oWe6=H1Q#p;c?iKpOyHpjK?ZN@DF{bHxCz2B5F!w&L)c+V zkkNop076X&T#X1axSn7M;Zg|M5Jo^a8A6=6bs+49Pzgc^z%!=z>JR(={`K>r(hZf* zQ271N`@{b9{~JP_?o@!Mn8E3##sCHYYydg{1pooi0Z<1}0+0d_0O*)OkZA#E0%!nu z0`L%^2A~R{0-y|_1fU3@5TF3y6hJmW8bB%lj-Lz=4-f?q0^kea3Sb9d17HbY05BOq z9Y7q2y}vJUUI8wn0>;2gBH^&oe}a{L7tVX|Jn*#rdG(A3o;Q5X8>efW9t;4wfyqQc z2nVNk0dTDENK)>#|#_m+x2^sJHGu9XKibNbxQogNiv_2Hm^81!zlel*t4>C6ZB)EwTyLS6c2VBm3dZN^u@S2tLlAwbN#f4&E+PZ zW!E+g-+wes`Psgy!#owGLZjnC!%EGjJ56cG+Q?v0^K)L?PS1Kihf_R|4;N>> z;Ti1D_3=F>d>)Hy=8-uCQzD*MZ@PH5k$1VP>y}%L?2@uW4Lp6z+4a+lE^ONTqLi0X zWXlRQzA1lU`!Qaf*V#=BlOv-~lyBmV8+-L>!C4mSmKecvvvre|^cg;-Z(Os0tDZVSa8=rPHQ)ozb{Kzd`I zJd3e^^@T#m+D!iby{Ab}y>n!DVMzOX%dTY`6_0GhM!n(`LJDaYK z-rX2K%W(tyqRlEzB`XWh`CY5l9~0TMT(&{CZqKdTCB#SjYjBZ-Ur{o~-)TBZ0O`HQ z=Qu87SODPS+q2%>3gKyhDuDL@vOuT^fE56^vG%N~@ia^TTwX5$*aC10;10k$0Gx^F z155`1*VzB?1#AZ{!5)1>9om5N8G0|8zB(2j{ts}KmI=vq`*H1&|l`kuSt(Dr#bj_TETyF_?-&(_;sH6 z_FHdH3-#zFIA_Fl1;w7&-unOAJqA!Nc;|w5XAt;(;%943h0qs#LCxXc0`UI?oudZ_ z0sm73JWug(K0c%nNQ*a zSB5cQ27~7*UUneh`2e1OPujsx{jvogSBsu_1SG(Zd>kMj+(-3CdNN2Aqz@R7g4rGj;G}RR`Z)1b_;6 zgY^jLb}-`zFowN(;iG_;(BDV+zuq1ltd4j)JpdcmVSC$X1Nj8Nvry>QkO3`(cTk}G z-%nEe(WjK2KK(iUuRZ%~zZyfi_-u89Qu}NCW9A5ePcuHL?I0GPAHh&hx1YvYoOqnb zcI!V>E8Nf5KbWHlj)BZzcW+NWw_shr{zG!`Q?HnA!G3ySs3sg7=I^rrUMK4F1>|U= zdWa@>m;_tDKQFG0p^c%jF&t0kQGq1JM}t zIC=?fMLSUf$&?g8N+9hbT_lx~DoHO$(&Wix9(f+whrF1)hJ1`%Mt)50CW}*KDLNEu ziZ5j)We?>5YyyU2=2!rhgzdpDVx?Fm_7WRL$LJPxcX}8-iXKCcrzg?(&=1h_>Cz08 zVa%Av@L?=wtYI8uR5BVE-3)Q2EOP?Wnz@)6!`#C>z&yb$Wxi#8V+ylWSd&@SEN7M* zE0~qc+Rw^oU1U|V-m;|G3Tz#=KHHEzkL}M6WhbzAvM;hr*_G^P;A*bG(c$QG3_0^S zD>-qTRL&mG2~IiZE$0(Qj4RF6;Ig^XxU;z{xofx^xcj&T-0R#2+-|NoPnI{92U9>@ z06f111YRLB=s46AbwXF6o6wVJ5!!%$MAb+L$(H0nT1DDKI!P)beIkt~)5x}D5At?$ zHTebk5T%(SO;w=kP;b)eXfkv~I){FnuF2GAvY0;1_slV@y{yYDQK-2cdkH&}eU{DR zEaoJ0(m66*HSTn-19uKLh)yR@ytFvkBW9;Yb z&+G+I-wcivzUPYY;&}~t{~5qq4}yt^F|vfbm2w=)E~2cWZlvZ> zooVN3Eih{&F$`%jF&?li*;m=aIHFuD?p>}AFMzj> zcc0hF!xzatMj3>Nh#^vl3?h#xA!>*^G7ix}Cc`0$6oihj5d$dK4Eo3hu|u2?7sM6u zK)ewmDh5;{gUX{ys2ZvcBddc>MiG>P(or^QfEuG_s3Uq1Ek(;w36d;n6p2NeL2@PS zCglSK)sRHV3&?(C5y}_}oic;6kg^Qug+SG$PM~tAen1@xv{5uNEtr->tD?Q8QLyRQ zChQ3I0Vu(a?ngfb?Neru7)u!`j4XyUQ-OJkSnBUKy_) zAGg3>*}nksLvAAPktxt073e)wloU;hC*_eAlSfdLDP#(h;ziM>mQpLIub|z|v=CYj z?HY}V8Dd`81MDfLM_&#!Uq^pVe@hom#=4`x&_>ptrX%bdNC zeTIFTt-@h(BH%qWfhbs`LtsU+CvAgyD@vEAtI)j|35;yUVMYO?kWs|A#tdUEXT4&b z;N(L~YPr6=WZoCN?#YlA_#y$Bi!4F*At%wZXbGHdYev0Jdr51hNn#_g(HIjm!z?iy z%nozHTrgKG5{trOuz28H$uL@}*iI}BE5Hh|BCG@}!z!>UtOk3CJ;55VCaeW(h0#o= zZ=$Etchb}78T4%WVft|x*?f8dy^vl+FQJ#wD_|CzGVU?z7!#TEnBmNo%+<^!W-@aV z^E~qzlfV*VNwH*D@+>8m8cUruj^)n^VTH3ISy8MPtTvVuTaK;7Rs%{iWG`axVrQ_k z*@xN3*{9g~>;iTnTY@9Qk>@CJ)PVk4IGylHjR;qQE5nuNs&Geh$8mMIx?D0B<8ru$ zTvMRU8C-krLZHnyt|(8D$Kl!XJb4RwfxIx@UYJuSc+YuVc;BV<+L6Q&X~Z6xjf5dt z$Q9%PqKD2#waFy%1d2X|N?}n9DW()Fiao`J;tunFF(sT5MTw^*Q+84^DF=bd&r+^X zZc%C}k3oifpnQQ>fE1{sdgRCg>SF3hdIa>AAomJp3+T`r>ao(s8p&o)tNevx`-M;| z9-yA4o}-pfZ&PciHh5t=p9ayI!C`8>IZe2ZK~t|fma2f<9(K-o%hqpqNqQ%};) z0SA0TGXUulg{{T5Vd>Zb>@;>CtH)krX`ltr7=et{j5o|~CWAGVWy6}w@?tFp*?ttH zdnM}u>kUhWZOV>huV;6&)i@rUtDNVYS=(ixHi*_FJI97|3jA0n%Q?lYUZ znyO3tLemG%V2wHUa0L&j^-0iTex-db-I#7hx1`(9bLp4p59!Zflv`k&Wf?4nA0q_D zGm;U-h=DOpVk9$a8BajBX@U`Dum~mHR#qpAz!qgou}88=Y&y(JGqw%ef$hrnVlQL!+41Zxz{&Qq4*?Im05a$$ z`z>f_?l`}16@WMJ1O)I_GGP{OM<1g(FtdtbR<)2Z;5YLr+bP+U7K#~lP9LR8&^WYE z+7sFf8isK&H{jm+*ahr5CQIK1GwU?S7%8S2Q-?`nGMOgKP-Z5R4YV?xoy4BQspm9v zgn(blgPt{ki*Q{*zw*cXA65l6@EeHoLC-sZUO}tTM)Wf(2|B=3Dw}3ZYp31Eg6QFN z6^1$kVN@_08S%^&tT+~ft;#vYIm>b3&Ig@s1aAUJQ_z55k&mx}Pmykro=_X8P1F`@ zEA<1lgZdR-iX_s+Xi_vq&=G_&dCUNG<{}J`)#05_2>elHG6Gy}D%pbU4%&J+c?CI< zoI}1szD~YRt|K=Cy}47OL0hk-)KeNM!>A_Icab31Jbf$p%D7%yex6e1LW)}kg-J|U#o!b z8i49P^zc?GhCD-!F^(~rL1D0AU115DMii_e;`?N7D)7)WW(G4G^x5N}apf}$n1#$D z&~3|@70fDT4d}Q}m<`M(W((-LADA7?ukf-e@i!^01FH~(Wxz6HSpvVZ177UHa%Fk2 zyji{=y#v`HxZ3jX>)$=_?;iMf5B$3a{@nxrZ9R~!16d0S3Lt!)og(5B^t z)A%}T;n5mF0s)mqhKY!~#+ea3g@}R#VFAQNL}HQ%fk@zEf&^lk6<9_T2RxBR#Dxd~ zX~eyPu=#=hl9s5>a?W`6Dp~I0gkYA+YAHpIp7Zgw6GGZHn^@1E;Vi^fN#hTDgYZR; zBYa|Nnh+dCD<~sA@_D;(^b8j9vzwzjOJkP$G5~QF$^HE7eTtvv8C?Y3lZ;OsZ zh+O)1D|#bG2Ap^zA06@qJ);xIA|{?bWgP>LC|5TBpxpoom@t;6vC94F(I z&_fLoUT;zK{s{H{qD(33_~A?Hw%~V^fkS_>FmYmX`QlWDsJa0}l!&&u2{FIO6q-IX^*1+O(MX_4Qo{V+g zH7*~UDdR-zEv)Z^8+}l`H@f!o?P@QTnbyP89lyqJyR@M!T8KM6aGb}W8$2m<(a-PL2bF5=0 zn`Jn}Q15=$+j&r6WF_`ZMP$?E$dXs8q!-sOf5_S=G(05p7$f(P>xgGfch9t=^$(9U zD5ce08f$8LGF{q#-yy$LkyWaB3%zu2pEp)Xk%?Y^oF#tm+78mJ%iRlI?Gnu|ZG2sS z%H>Hwv)1RN>YUGXnHR5aZTNWMPG`VIH;PNaMiZS?w22FJ<{b~dm8dmdBxhBX%cqgb zmapeOnM;1x)YKx8bzErDh8)_`3++e5Mu+bAEIaqi%;x=)4JzLr*zBEJ;^vh4F;Y;0 zy-Mc@Bd(PP|Zqs=qHiXq(bh;5FGr_R6y4X)E%v;t_ z&T0EYtx1FrYoCc zm>|d~{Mm4#0#V)@d(xcC>X;`R*ZIwDnOMB%2dgPP#4u_sQ3+9ql5e^9jDLIa91qLK zdS1N7v#Cebq^*(RczS6(Pa;rgTo1jC8c&o$Bt*o3GYAWd3JD=g`tJz@;v&Qc8Q1?G zA;c+phlB(&_4NbXg9CpeMa1wsmS7yU56c}s%K_(u{Di3APdX)8IOQXb*`tu3$CI4L}zK9y0i8>K@2_h;Y>=i9V5JJR6MDQCTVIcVd0|N4c z4+@Pn=ByP9d$YcPx$Ta_6G4^C4l~O8$+<5=7PM~)Iw5fVm@lF&H)40P@g9q=-TNZ7 zs<8s*95cVo)jabL+UFFaO>DY$p3jYa61Dq@Q+i+iMY+|}j%uMbw1ayopt5<%Y|)wxetu;$tBiw z`IK!RAKkL^yFW)zevAP*Qt0XCoXZ-a!8316ttq0Y?aj1Udov&mn;gqixux||=|ZyT zaif)+~JiFweI%#b8`qQuCmjy0*k#@F=$urqs)TFRsW};!CS&YS& z>4%IBo~>;isdMXfo05a*M17eeDKQT=dHqqHB=(K<@sh(XvOe4zy=>jv)6F;XT9?SZ zXw=~y9&t2NU(?s{Gv8(8f->LX*Nfw>e9|IIiCU!H5fxmx&;T*Bpk&WbKX*hmR_v+s zFu&`W<$70PiK0C5b?G$<)XY%2coBu`cr&_LYuS$*` z__k?Oqq{0I&LP|i;fvA`zVPTinMJfTjAK;I3^A2#%luN8rZjNMNP^7zACwok=%ON2 z5MTYGi$sIJNWbWczJSUhvLcdwGMz0*5Rwx#v`0rFsz3xpX(@S|AfGV&(b+v`?3jXW zHZRrv);3IOcB;Ubv+wd>Ej^-|^rcqN!v2lpt#Y5ojf=i`Q_914e*QozDg0JamC)9h zs)rsqvs(P>vg8{l&ylRduU=iN`H4jBIQ!Z6)5)iPdfP{M#CDwZ|2(;iY*#iz&^)^+ zHFVpRhm+Pnw3E%)JAbsae*0>bB@FjMaWTcYA=>L@WSs1MT$*MtIXKR7GjZ&fXa$Mz zVb7emcT^tGALZ^+tLe)Pj$)5>T9IkqsH%O?<><%t6CCZrw+b-@cAfOVBqiP$zECh# zu=l&+G*(!-Ej=pwc=OXy{MDwmo5f5T91ERsYC=We}=zP&%RvCKD<(kPe z#~()>JzCV2&b1bgZ71x`Z@CiM7v*Z2oe-j`}qB@ zdY-ii(EN&^q60BAS*Od-zWByOU@Fd z%=_Wd?o90*^JXKy#5$*WsWG8+p*)L4mDhN~t(Kmw`XV#+L`HXos(7mS?d*8!=~PnM zL?9`}GmU=TRa#v5w0{)Op`#K4Hv` zV+k+1S3aUF_DJ?Hmm6VnN6^BEp)472wcW4H+gZ6z@6l|w+yO}s&(h(1(&4i8O;U^b zfqOoBiKZ^DKceu--}2>RXXjY%9a`bmNg1C%WV9%9oXcAR>+zIzuie25>JlnF-!gN=VuzaRbmYH&ebo2V> zp)ZY8PA+m{cNl~{j<9ThL!=ce2d_!0ud`Q}VHI&{tIwAFt8JGL%_Ivr&@&q`f>BUrFd;o)p_>+o$P8H6N}>1!R{p;B z6c<9J21FA=0ow>Er#ZuYd(q9ZBp=U5FEZT z)%dh&NX68EU)OjvYukC6!+58d}zvE*$m7Wus5)(r*^`S6o%pp2N6W`q93n zYFv?)Rn!w-M+M`qh2*3u3&)Sz>Qr?+&-&z$8ay<5f0nG#~#Z>)>b$If+$w z9)EQF8Z-0B(yi4km6DgU)dSxb&rwi9-HV++bb2h3QK-C-;3D1l_7Rs?*tWi8uK9~o zf{Q;##D-g2=ZbE-;b7t~wmju*&?`5S#-iI2#C^LgXP>v-GTO}LRQUV_OGiF&mH$wv zS~@S!Y{hY=Qbw!ywq=K|)kemxq#7+uSy7%7V@9Xuee}t^j?5kB6uLGu*6PN)6CY0^ zc@Me@Y0nsS>~_z0R7+IpX8Sjnwakb0n;o1dYDbyh@Yp;~RcqR6%9*06l3Ek11IyQ@ z^A(pMe8u4J<18dZK>3R9@NC}q(Z!7?iZ<}b5)`T5jVIwEl6|%daT&0l_z=AiPnh|= z7M8d!Us1v!Mw0~->Yv@*daKiF!pCZZ(8r&*-q^1wwtF^l#C>~ZaYn!rL0N&UJpv{l zx9mAuYuP#7sM+s?k~BygD(v;4py-iM+N?Cb91{#HufecV-KV5VM7>qASlcGduPh47 z+8pBj3wQo6qDA~HYB+!qKHK=SQG-OK;YJN=k5QvnNyUYFzmf{}6$X5xvCqEZK0vbs z8_$sT6&Aw4bx0vOQvU)Gx1Zoe^_x@h>ICD}QHS@Q1L5-~of8I^PHX9Ye>5(>-~?bu{4w@JO?PW$z7If)z5XsewO zva633G@Wy4q?hZ2o|%|-EK}RxLM(9RLftcBE~_2{-j8a(ayZ3&(uKNAwiGWbLC9QT zQN(1z+c7~Y`L~-q@~ES_)=-Kq>W5in7VOBlmj80~Xv#3j$Oqa7N?(qDsynH*e!|JN z>8!Z)6|Lj$c^fy_`+f+ucfN8)d$s*Gm#5dFSZ{XK7Unj;ui)JId{>29rm~`VigL=P zSfLwt!(w&RPG=qP#6r|_h~z-NIlwI3uUmRfJkqA7O+0hd)v%>f%y_rEL6AmA!zWGa2h_w&iPHhGvMP}Z z!j;O>HH1U=ZhGI3U7xP;{*#t5)@FVD)W%D83j5r?JkW@~FuW;$?5fKJ5jOc>V)+L{ zdB{c2ksbTrcL!-Ln7Pa?k|13bl5UmDtw9+F*>4xzDpilyt#FN%zOQ?2O54>cn>U|5 zC(d3yOEaU%Wd?7&bdiA47|)=)ww6yV>oz>rks$`l3#Tpht1b7Pn`DwmsT-~1YouMg zYHOR#j0vy(X^|E7SmJKotkEXjQx4tRdH36VgW`=NMNSpf#-Cb#nQeFVb-Ij}&!O?u zB~w)AWgdLrG4gChQ_=|GrOFElH)8BLY7?)1E8A$CQ%`7l(;d`&$MBFgxk4c@W{d;l z{n4+Q;(Hh}){--)ZHSA>bKf<5v`Fe}-t$X!n*?*e5uY2R49jMI8UK~!8hU%l^N_aX z<~E&|p70-!zn|E7G%hPJMR@VqvBG7ZCYRzWax}8ikC`-xM3pENi&R(ZUOuvLTbXL8 z=|l6Vtd17##rBFTcU6x!vhprY%Dp*qvjVzo+w~5~6;kUX)WjXt1V2x6tSQ=kW6^HS zx3+5b9@fqK?{;d)(zcXJu=%cj`#$ISTwVWBQcsUlj1fGoRdO2}I*f$7ijT(YmD4>s zU+hnO)jp+Qsc&4(BWf^T!>nat-c2tMc&9+%?d%hH!>%266z%ueF zVw*Wyrk$^Kk8-2-wYYsHo;yMGH#pyE7aHe(9nP$Y4J^ty zz%r>-tSFDHm}ZeX>t;zLWo|%L-gYn7&6vu;y8nRO}_Q8D3h>>IaLyj^|R)z=lY zpYGzm*Y_T!kZk=aJJS4i^>KDV6YweCp$dXoo+*CONS z-G{D4Tz5jnHzg#_edn-it$w4nbw<;TS2w=|v&lJ)dTEDP^R4S*FLuu!b0+zEJgQnn zWJi=c9_u{oOKEf+cU`maRh8<3In!cPZ5NiMq&zj+e|74F`@ZXj>%BEZq8C(~jQ{9d z$GsKplNB?oqjVa1L2VlMM5SH$RLTLTa-HW#SGAp;w<9WXLRpJy?jm(}+kSaB2jrde zKkOt7D%9|8wg2o+g4qA@orM38+)}*NsSu_1O_U=Wwir2oL9*mDW&g^X6|0NmRgjg| zS9Z9F1h+Q5iM4e1NuRU%nbd8YMI|39$O~h}wdXanRn6AFu((;fqI8KH{hNlEja+`! zH0{Yqtv@}uU-!n&{C1%0v=;!%b;m%3&<%{Fnh z;pIJEGWtZpgXrvor{A0>-;NMkck2Ri7Pmb2x|y2t9Ln^BPkQHH->8jGpk*B~Ua~N< z=<@9M3v_aplb`9HDV|!=GJjYX(>^k2qS4-?-?HzxXS>v?Dw0lJu(izT@H|Ke+h5OA zSmG&DwO{V7xpI<~(y5Em0dz|6>@;-eHqXbGLV})7eN#_xWBQ?5^~8WW>oa*Su#*7$@5InPxix%;(z?$Tx{Yri z*gO?8P?|MRZs9xNo1Mut6`;3Rk@ z;>S(`8HM#FqhECWPl(Tdl35pDBnNxfookpgjg4p`KIE3mS>yFeH8}4QYMd|EPsrjp z9SYli^XM|wm|;c8nD?p~bcJSzt6Tj>9m-ky?z-&lhIw~|*)yeQj=8#fWaf$sdk#1% zINJvu^WGSEIp=KXwuQl@O_egnGJ22s??q!?gs}V;Kh>2|eWPAosy@nng6^%BxmG0` zJ2c#OP@09W&TW~kQqWvle)BNJVBU#{1#gy=m}M_;blhX-v`%VLo^=*--{H;mWpkb# zDYc&aoZ5)qsNFdC;kxxvwYeKo4U(5$3BQ(mqUiKOCAyHz+L|gXLr-{l{6{`lW<%g1 zd%hv*-UDLrME?zhNDa%Xf}^TJp>x6)+-IW3+sOtO#qP~A&$#^JK$_R14DEt+YsP6= zC&l)0E>qWgv|sXx4@(W>IM109wtCH0p9r(oCwoVzF4!J&z0P8E<8b$*FRI?Aq%e1L z9tt#=j9-(x-B@|jio#8&ZoBz4lkXQlwjc_WEmzxoWqrFwPL6Eexs~s#lL99jx*j~? zu4KGfC2anRPf^D^n>_ZDE7yqDpU-6l}P`*OoOfOrTwcaSdIB1i~e#gX4Ibw)?!%y zI_Xd5_C8`XH^%q5jSPGCxlQo4jUjU34JBq8>~zOb`g0m`#r1nOzOeJxv#yeWSD-{h zh_J-^$w=R`y-gqp1g2dyaeNABfb4yP~EtKnL;I26%*^e=sJ{t{?L9HiP)Z) zGqZv_vq2_lmQAPY*NY6$GXBH$PDXg+c{PC^%1R7*eMy>uob+G)7r zHw(6I=(bS@cIeSPu7qR9Q+#cjvbP@dI_)lOc0N$Ek?wDbU;}g4M|BV_c(V>n-_z1~ zdney>i79s3xSqexYthc5*H7}E`Dtz6M`@cXD?uJ8-e5PE$QKk4);AoJ+A7LRFtoad zAX%5SIu`D6*KA=A5Y%PZ9PNExABkaC6UCr5d|~OI>yD1S%aAjI-71ej4mpozT)e(eq|P z=-S$u(cYNx>S@z`3SR}C3z5Dfa+08O!QAh0(zj!g_0ezJQWCP(uE}!l*nFf^5EY&M z$||$X`G|nmrgsT5UfT1zBW*I1_~lzy9r!{~digr^0aH@vTqP^f(I&S-cwZ~EZtjtF zE$%B5O%*bA9CfDEj6FO>Y87*e$G+`x_e87Sz4peIYzvnWk(zY6e7t+gg_wmWzg1T> zoFBE{L_tS4%8n^a3HDQQRd-f8WL?&D%w(K+<_r_5w_VdZ!v#(0{u*ap%`3k?n0l{5 z+nba(TVr0 PreserveNewest + + PreserveNewest + + + PreserveNewest + From 9fca73791eb3cacd314ac3bd55c9cca8b7d3cbd4 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 22 Mar 2026 01:07:14 +0800 Subject: [PATCH 02/29] Introduce Everything SDK 3 for Everything 1.5 --- Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 2 + .../Everything/Everything3ApiDllImport.cs | 109 ++++++ .../Search/Everything/EverythingAPI.cs | 326 +++++++++++++++++- .../Everything/EverythingApiDllImport.cs | 2 +- .../Search/SearchManager.cs | 3 + 5 files changed, 435 insertions(+), 7 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index f5b8b932581..ab48d76d53e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -48,6 +48,8 @@ public Task InitAsync(PluginInitContext context) EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86")); + Everything3ApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", + Environment.Is64BitProcess ? "x64" : "x86")); return Task.CompletedTask; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs new file mode 100644 index 00000000000..c613923345c --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -0,0 +1,109 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + internal static class Everything3ApiDllImport + { + public static void Load(string directory) + { + var path = Path.Combine(directory, Dll); + int code = LoadLibrary(path); + if (code == 0) + { + int err = Marshal.GetLastPInvokeError(); + Marshal.ThrowExceptionForHR(err); + } + } + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int LoadLibrary(string name); + private const string Dll = "Everything3.dll"; + + [DllImport(Dll, CharSet = CharSet.Unicode)] + internal static extern IntPtr Everything3_ConnectW(string instanceName); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_DestroyClient(IntPtr client); + + [DllImport(Dll)] + internal static extern IntPtr Everything3_CreateSearchState(); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_DestroySearchState(IntPtr searchState); + + [DllImport(Dll, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_SetSearchTextW(IntPtr searchState, string search); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_SetSearchRegex(IntPtr searchState, bool matchRegex); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_SetSearchMatchPath(IntPtr searchState, bool matchPath); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_SetSearchHideResultOmissions(IntPtr searchState, bool hideResultOmissions); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_SetSearchViewportOffset(IntPtr searchState, nuint offset); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_SetSearchViewportCount(IntPtr searchState, nuint count); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_ClearSearchSorts(IntPtr searchState); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_AddSearchSort(IntPtr searchState, uint propertyId, bool ascending); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_ClearSearchPropertyRequests(IntPtr searchState); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_AddSearchPropertyRequest(IntPtr searchState, uint propertyId); + + [DllImport(Dll)] + internal static extern IntPtr Everything3_Search(IntPtr client, IntPtr searchState); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_DestroyResultList(IntPtr resultList); + + [DllImport(Dll)] + internal static extern nuint Everything3_GetResultListViewportCount(IntPtr resultList); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_IsFolderResult(IntPtr resultList, nuint resultIndex); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_IsRootResult(IntPtr resultList, nuint resultIndex); + + [DllImport(Dll, CharSet = CharSet.Unicode)] + internal static extern nuint Everything3_GetResultFullPathNameW(IntPtr resultList, nuint resultIndex, StringBuilder buffer, nuint bufferSizeInWChars); + + [DllImport(Dll)] + internal static extern uint Everything3_GetResultRunCount(IntPtr resultList, nuint resultIndex); + + [DllImport(Dll, CharSet = CharSet.Unicode)] + internal static extern uint Everything3_IncRunCountFromFilenameW(IntPtr client, string fileName); + + [DllImport(Dll)] + internal static extern uint Everything3_GetLastError(); + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index a4e959dd9c4..120fbc9a77c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -11,6 +11,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything public static class EverythingApi { private const int BufferSize = 4096; + private const string Everything15AlphaInstance = "1.5a"; private static readonly SemaphoreSlim _semaphore = new(1, 1); @@ -32,11 +33,44 @@ public enum StateCode const uint EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004u; const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u; + const uint EVERYTHING3_PROPERTY_ID_NAME = 0; + const uint EVERYTHING3_PROPERTY_ID_PATH = 1; + const uint EVERYTHING3_PROPERTY_ID_SIZE = 2; + const uint EVERYTHING3_PROPERTY_ID_EXTENSION = 3; + const uint EVERYTHING3_PROPERTY_ID_TYPE = 4; + const uint EVERYTHING3_PROPERTY_ID_DATE_MODIFIED = 5; + const uint EVERYTHING3_PROPERTY_ID_DATE_CREATED = 6; + const uint EVERYTHING3_PROPERTY_ID_DATE_ACCESSED = 7; + const uint EVERYTHING3_PROPERTY_ID_ATTRIBUTES = 8; + const uint EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED = 9; + const uint EVERYTHING3_PROPERTY_ID_RUN_COUNT = 10; + const uint EVERYTHING3_PROPERTY_ID_DATE_RUN = 11; + const uint EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME = 12; + + const uint EVERYTHING3_ERROR_OUT_OF_MEMORY = 0xE0000001; + const uint EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND = 0xE0000002; + const uint EVERYTHING3_ERROR_DISCONNECTED = 0xE0000003; + const uint EVERYTHING3_ERROR_INVALID_PARAMETER = 0xE0000004; + /// /// Checks whether the sort option is Fast Sort. /// public static bool IsFastSortOption(EverythingSortOption sortOption) { + try + { + var client = TryConnectEverything3(); + if (client != IntPtr.Zero) + { + Everything3ApiDllImport.Everything3_DestroyClient(client); + return true; + } + } + catch (DllNotFoundException) + { + // Fallback to Everything 1.4 SDK. + } + var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); // If the Everything service is not running, then this call will incorrectly report @@ -59,6 +93,13 @@ public static async ValueTask IsEverythingRunningAsync(CancellationToken t try { + var client = TryConnectEverything3(); + if (client != IntPtr.Zero) + { + Everything3ApiDllImport.Everything3_DestroyClient(client); + return true; + } + _ = EverythingApiDllImport.Everything_GetMajorVersion(); var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; return result; @@ -98,9 +139,10 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO if (token.IsCancellationRequested) yield break; + var useRegex = false; if (option.Keyword.StartsWith("@")) { - EverythingApiDllImport.Everything_SetRegex(true); + useRegex = true; option.Keyword = option.Keyword[1..]; } @@ -117,13 +159,136 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO builder.Append($" content:\"{option.ContentSearchKeyword}\""); } - EverythingApiDllImport.Everything_SetSearchW(builder.ToString()); + var searchText = builder.ToString(); + + var client = TryConnectEverything3(); + if (client != IntPtr.Zero) + { + await foreach (var result in SearchWithEverything3Async(client, option, searchText, useRegex, token)) + yield return result; + + yield break; + } + + await foreach (var result in SearchWithEverythingLegacyAsync(option, searchText, useRegex, token)) + yield return result; + } + finally + { + _semaphore.Release(); + } + } + + private static async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, + EverythingSearchOption option, + string searchText, + bool useRegex, + [EnumeratorCancellation] CancellationToken token) + { + IntPtr searchState = IntPtr.Zero; + IntPtr resultList = IntPtr.Zero; + try + { + searchState = Everything3ApiDllImport.Everything3_CreateSearchState(); + if (searchState == IntPtr.Zero) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + yield break; + } + + _ = Everything3ApiDllImport.Everything3_SetSearchRegex(searchState, useRegex); + _ = Everything3ApiDllImport.Everything3_SetSearchMatchPath(searchState, option.IsFullPathSearch); + _ = Everything3ApiDllImport.Everything3_SetSearchTextW(searchState, searchText); + _ = Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions(searchState, true); + _ = Everything3ApiDllImport.Everything3_SetSearchViewportOffset(searchState, (nuint)option.Offset); + _ = Everything3ApiDllImport.Everything3_SetSearchViewportCount(searchState, (nuint)option.MaxCount); + + // TODO Something here hides all results. Need to investigate further. + //_ = Everything3ApiDllImport.Everything3_ClearSearchSorts(searchState); + //if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) + //{ + // _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); + //} + + //_ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); + //_ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_NAME); + //_ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH); + //_ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); + + if (token.IsCancellationRequested) + yield break; + + resultList = Everything3ApiDllImport.Everything3_Search(client, searchState); + if (resultList == IntPtr.Zero) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + yield break; + } + + var resultCount = Everything3ApiDllImport.Everything3_GetResultListViewportCount(resultList); + for (nuint idx = 0; idx < resultCount; ++idx) + { + if (token.IsCancellationRequested) + { + yield break; + } + + buffer.Clear(); + var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, buffer, BufferSize); + if (fullPathLength == 0) + { + continue; + } + + var fullPath = buffer.ToString(); + if (string.IsNullOrEmpty(fullPath)) + { + continue; + } + + var result = new SearchResult + { + FullPath = fullPath, + Type = Everything3ApiDllImport.Everything3_IsFolderResult(resultList, idx) + ? ResultType.Folder + : Everything3ApiDllImport.Everything3_IsRootResult(resultList, idx) + ? ResultType.Volume + : ResultType.File, + Score = (int)Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx) + }; + + yield return result; + } + } + finally + { + if (resultList != IntPtr.Zero) + _ = Everything3ApiDllImport.Everything3_DestroyResultList(resultList); + + if (searchState != IntPtr.Zero) + _ = Everything3ApiDllImport.Everything3_DestroySearchState(searchState); + + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + } + + await Task.CompletedTask; + } + + private static async IAsyncEnumerable SearchWithEverythingLegacyAsync(EverythingSearchOption option, + string searchText, + bool useRegex, + [EnumeratorCancellation] CancellationToken token) + { + try + { + EverythingApiDllImport.Everything_SetRegex(useRegex); + EverythingApiDllImport.Everything_SetSearchW(searchText); EverythingApiDllImport.Everything_SetOffset(option.Offset); EverythingApiDllImport.Everything_SetMax(option.MaxCount); EverythingApiDllImport.Everything_SetSort(option.SortOption); EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch); - + if (option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) { EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT); @@ -152,12 +317,11 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO var result = new SearchResult { - // todo the types are wrong. Everything expects uint everywhere, but we send int just above/below. how to fix? Is EverythingApiDllImport autogenerated or handmade? FullPath = buffer.ToString(), Type = EverythingApiDllImport.Everything_IsFolderResult(idx) ? ResultType.Folder : EverythingApiDllImport.Everything_IsFileResult(idx) ? ResultType.File : ResultType.Volume, - Score = (int)EverythingApiDllImport.Everything_GetResultRunCount( (uint)idx) + Score = (int)EverythingApiDllImport.Everything_GetResultRunCount((uint)idx) }; yield return result; @@ -166,7 +330,149 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO finally { EverythingApiDllImport.Everything_Reset(); - _semaphore.Release(); + } + + await Task.CompletedTask; + } + + private static IntPtr TryConnectEverything3() + { + try + { + return Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); + } + catch (DllNotFoundException) + { + return IntPtr.Zero; + } + catch (EntryPointNotFoundException) + { + return IntPtr.Zero; + } + } + + private static bool TryConvertSortOption(EverythingSortOption sortOption, out uint propertyId, out bool ascending) + { + switch (sortOption) + { + case EverythingSortOption.NAME_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_NAME; + ascending = true; + return true; + case EverythingSortOption.NAME_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_NAME; + ascending = false; + return true; + case EverythingSortOption.PATH_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_PATH; + ascending = true; + return true; + case EverythingSortOption.PATH_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_PATH; + ascending = false; + return true; + case EverythingSortOption.SIZE_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_SIZE; + ascending = true; + return true; + case EverythingSortOption.SIZE_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_SIZE; + ascending = false; + return true; + case EverythingSortOption.EXTENSION_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_EXTENSION; + ascending = true; + return true; + case EverythingSortOption.EXTENSION_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_EXTENSION; + ascending = false; + return true; + case EverythingSortOption.TYPE_NAME_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_TYPE; + ascending = true; + return true; + case EverythingSortOption.TYPE_NAME_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_TYPE; + ascending = false; + return true; + case EverythingSortOption.DATE_CREATED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_CREATED; + ascending = true; + return true; + case EverythingSortOption.DATE_CREATED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_CREATED; + ascending = false; + return true; + case EverythingSortOption.DATE_MODIFIED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_MODIFIED; + ascending = true; + return true; + case EverythingSortOption.DATE_MODIFIED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_MODIFIED; + ascending = false; + return true; + case EverythingSortOption.ATTRIBUTES_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_ATTRIBUTES; + ascending = true; + return true; + case EverythingSortOption.ATTRIBUTES_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_ATTRIBUTES; + ascending = false; + return true; + case EverythingSortOption.FILE_LIST_FILENAME_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME; + ascending = true; + return true; + case EverythingSortOption.FILE_LIST_FILENAME_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME; + ascending = false; + return true; + case EverythingSortOption.RUN_COUNT_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_RUN_COUNT; + ascending = false; + return true; + case EverythingSortOption.DATE_RECENTLY_CHANGED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED; + ascending = true; + return true; + case EverythingSortOption.DATE_RECENTLY_CHANGED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED; + ascending = false; + return true; + case EverythingSortOption.DATE_ACCESSED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_ACCESSED; + ascending = true; + return true; + case EverythingSortOption.DATE_ACCESSED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_ACCESSED; + ascending = false; + return true; + case EverythingSortOption.DATE_RUN_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RUN; + ascending = true; + return true; + case EverythingSortOption.DATE_RUN_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RUN; + ascending = false; + return true; + default: + propertyId = EVERYTHING3_PROPERTY_ID_NAME; + ascending = true; + return false; + } + } + + private static void CheckAndThrowExceptionOnErrorFromEverything3() + { + switch (Everything3ApiDllImport.Everything3_GetLastError()) + { + case EVERYTHING3_ERROR_OUT_OF_MEMORY: + throw new MemoryErrorException(); + case EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND: + case EVERYTHING3_ERROR_DISCONNECTED: + throw new IPCErrorException(); + case EVERYTHING3_ERROR_INVALID_PARAMETER: + throw new InvalidCallException(); } } @@ -200,6 +506,14 @@ public static async Task IncrementRunCounterAsync(string fileOrFolder) await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); try { + var client = TryConnectEverything3(); + if (client != IntPtr.Zero) + { + _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder); + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + return; + } + _ = EverythingApiDllImport.Everything_IncRunCountFromFileName(fileOrFolder); } catch (Exception) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index c952a980c47..70c02cd87aa 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -126,7 +126,7 @@ public static void Load(string directory) public static extern uint Everything_GetRequestFlags(); [DllImport(DLL)] public static extern uint Everything_GetResultListRequestFlags(); - [DllImport("Everything64.dll", CharSet = CharSet.Unicode)] + [DllImport(DLL, CharSet = CharSet.Unicode)] public static extern IntPtr Everything_GetResultExtension(uint nIndex); [DllImport(DLL)] public static extern bool Everything_GetResultSize(uint nIndex, out long lpFileSize); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 28ab1d2e24b..46216f931c6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -291,6 +291,9 @@ private bool UseWindowsIndexForDirectorySearch(string locationPath) private bool IsExcludedFile(SearchResult result) { + if (string.IsNullOrEmpty(result.FullPath)) + return false; + string[] excludedFileTypes = Settings.ExcludedFileTypes.Split([','], StringSplitOptions.RemoveEmptyEntries); string fileExtension = Path.GetExtension(result.FullPath).TrimStart('.'); From 84edda4827574a936d0e64f1b53da148b9b9add5 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 22 Mar 2026 16:36:38 +0800 Subject: [PATCH 03/29] Fix missing search --- .../Search/Everything/EverythingAPI.cs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 120fbc9a77c..188575df3f2 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -203,17 +203,10 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I _ = Everything3ApiDllImport.Everything3_SetSearchViewportOffset(searchState, (nuint)option.Offset); _ = Everything3ApiDllImport.Everything3_SetSearchViewportCount(searchState, (nuint)option.MaxCount); - // TODO Something here hides all results. Need to investigate further. - //_ = Everything3ApiDllImport.Everything3_ClearSearchSorts(searchState); - //if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) - //{ - // _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); - //} - - //_ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); - //_ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_NAME); - //_ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH); - //_ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); + if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) + { + _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); + } if (token.IsCancellationRequested) yield break; From 9d1c0aec1f887ce19e1de92ef320728c58cc41b6 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:12:47 +0800 Subject: [PATCH 04/29] Add fast sort detection --- .../Everything/Everything3ApiDllImport.cs | 5 ++ .../Search/Everything/EverythingAPI.cs | 71 ++++++++++++------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index c613923345c..82138f0894f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -105,5 +105,10 @@ public static void Load(string directory) [DllImport(Dll)] internal static extern uint Everything3_GetLastError(); + + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_IsPropertyFastSort(IntPtr client, uint propertyId); } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 188575df3f2..612f5f19dc9 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -15,7 +15,7 @@ public static class EverythingApi private static readonly SemaphoreSlim _semaphore = new(1, 1); - // cached buffer to remove redundant allocations. + // cached buffer to remove redundant allocations. semaphore is used to make sure the access to the buffer is thread safe. private static readonly StringBuilder buffer = new(BufferSize); public enum StateCode @@ -57,18 +57,26 @@ public enum StateCode /// public static bool IsFastSortOption(EverythingSortOption sortOption) { - try + if (TryConnectEverything3(out var client)) { - var client = TryConnectEverything3(); - if (client != IntPtr.Zero) + try { - Everything3ApiDllImport.Everything3_DestroyClient(client); - return true; + if (TryConvertSortOption(sortOption, out var propertyId, out _)) + { + var isFastSort = Everything3ApiDllImport.Everything3_IsPropertyFastSort(client, propertyId); + + // Keep the same behavior as legacy path: throw when engine is not available. + CheckAndThrowExceptionOnErrorFromEverything3(); + + return isFastSort; + } + } + finally + { + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + // Throw again to the caller + CheckAndThrowExceptionOnErrorFromEverything3(); } - } - catch (DllNotFoundException) - { - // Fallback to Everything 1.4 SDK. } var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); @@ -93,12 +101,8 @@ public static async ValueTask IsEverythingRunningAsync(CancellationToken t try { - var client = TryConnectEverything3(); - if (client != IntPtr.Zero) - { - Everything3ApiDllImport.Everything3_DestroyClient(client); + if (TryUseEverything3Client(static _ => { })) return true; - } _ = EverythingApiDllImport.Everything_GetMajorVersion(); var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; @@ -161,8 +165,7 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO var searchText = builder.ToString(); - var client = TryConnectEverything3(); - if (client != IntPtr.Zero) + if (TryConnectEverything3(out var client)) { await foreach (var result in SearchWithEverything3Async(client, option, searchText, useRegex, token)) yield return result; @@ -328,19 +331,37 @@ private static async IAsyncEnumerable SearchWithEverythingLegacyAs await Task.CompletedTask; } - private static IntPtr TryConnectEverything3() + private static bool TryUseEverything3Client(Action action) + { + if (!TryConnectEverything3(out var client)) + return false; + + try + { + action(client); + return true; + } + finally + { + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + } + } + + private static bool TryConnectEverything3(out IntPtr client) { + client = IntPtr.Zero; try { - return Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); + client = Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); + return client != IntPtr.Zero; } catch (DllNotFoundException) { - return IntPtr.Zero; + return false; } catch (EntryPointNotFoundException) { - return IntPtr.Zero; + return false; } } @@ -499,13 +520,9 @@ public static async Task IncrementRunCounterAsync(string fileOrFolder) await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); try { - var client = TryConnectEverything3(); - if (client != IntPtr.Zero) - { - _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder); - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + if (TryUseEverything3Client(client => + _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder))) return; - } _ = EverythingApiDllImport.Everything_IncRunCountFromFileName(fileOrFolder); } From 9246dea855d25669925cd7662ae9801efaa38b8b Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 22 Mar 2026 18:48:33 +0800 Subject: [PATCH 05/29] Add highlight --- .../Everything/Everything3ApiDllImport.cs | 14 +++++++ .../Search/Everything/EverythingAPI.cs | 37 ++++++++++++++++++- .../Search/ResultManager.cs | 4 +- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index 82138f0894f..4514a1549f3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -76,6 +76,14 @@ public static void Load(string directory) [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool Everything3_AddSearchPropertyRequest(IntPtr searchState, uint propertyId); + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_AddSearchPropertyRequestHighlighted(IntPtr searchState, uint propertyId); + + [DllImport(Dll)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Everything3_GetSearchPropertyRequestHighlight(IntPtr searchState, nuint index); + [DllImport(Dll)] internal static extern IntPtr Everything3_Search(IntPtr client, IntPtr searchState); @@ -97,6 +105,12 @@ public static void Load(string directory) [DllImport(Dll, CharSet = CharSet.Unicode)] internal static extern nuint Everything3_GetResultFullPathNameW(IntPtr resultList, nuint resultIndex, StringBuilder buffer, nuint bufferSizeInWChars); + [DllImport(Dll, CharSet = CharSet.Unicode)] + internal static extern nuint Everything3_GetResultPropertyTextHighlightedW(IntPtr resultList, nuint resultIndex, uint propertyId, StringBuilder buffer, nuint bufferSizeInWChars); + + [DllImport(Dll, CharSet = CharSet.Unicode)] + internal static extern nuint Everything3_GetResultPropertyTextW(IntPtr resultList, nuint resultIndex, uint propertyId, StringBuilder buffer, nuint bufferSizeInWChars); + [DllImport(Dll)] internal static extern uint Everything3_GetResultRunCount(IntPtr resultList, nuint resultIndex); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 95215935c24..7bd421b8be8 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -46,11 +46,13 @@ public enum StateCode const uint EVERYTHING3_PROPERTY_ID_RUN_COUNT = 10; const uint EVERYTHING3_PROPERTY_ID_DATE_RUN = 11; const uint EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME = 12; + const uint EVERYTHING3_PROPERTY_ID_PATH_AND_NAME = 240; const uint EVERYTHING3_ERROR_OUT_OF_MEMORY = 0xE0000001; const uint EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND = 0xE0000002; const uint EVERYTHING3_ERROR_DISCONNECTED = 0xE0000003; const uint EVERYTHING3_ERROR_INVALID_PARAMETER = 0xE0000004; + const uint EVERYTHING3_ERROR_PROPERTY_NOT_FOUND = 0xE0000007; /// /// Checks whether the sort option is Fast Sort. @@ -211,6 +213,12 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); } + _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); + // TODO somehow error, no result + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); + // TODO need to check the "IsFullPathSearch" + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); + if (token.IsCancellationRequested) yield break; @@ -233,6 +241,7 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, buffer, BufferSize); if (fullPathLength == 0) { + CheckAndThrowExceptionOnErrorFromEverything3(); continue; } @@ -250,9 +259,33 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I : Everything3ApiDllImport.Everything3_IsRootResult(resultList, idx) ? ResultType.Volume : ResultType.File, - Score = (int)Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx) + Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)) }; + // 0 for the first requested property, which is name in our case. + if (Everything3ApiDllImport.Everything3_GetSearchPropertyRequestHighlight(searchState, 0)) + { + buffer.Clear(); + var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( + resultList, + idx, + EVERYTHING3_PROPERTY_ID_NAME, + buffer, + BufferSize); + + if (highlightedFileNameLength > 0) + { + var highlightData = EverythingHighlightStringToHighlightList(buffer.ToString()); + if (highlightData.Count > 0) + { + result = result with + { + HighlightData = highlightData + }; + } + } + } + yield return result; } } @@ -488,6 +521,8 @@ private static void CheckAndThrowExceptionOnErrorFromEverything3() throw new IPCErrorException(); case EVERYTHING3_ERROR_INVALID_PARAMETER: throw new InvalidCallException(); + case EVERYTHING3_ERROR_PROPERTY_NOT_FOUND: + throw new ArgumentException("EVERYTHING3_ERROR_PROPERTY_NOT_FOUND"); } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index 6c33f5ffb63..56a63735628 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -145,7 +145,7 @@ internal static Result CreateFolderResult(string title, string subtitle, string IcoPath = path, SubTitle = subtitle, AutoCompleteText = GetAutoCompleteText(title, query, path, ResultType.Folder), - TitleHighlightData = highlightData ?? Context.API.FuzzySearch(query.Search, title).MatchData, + TitleHighlightData = highlightData ?? Context.API.FuzzySearch(query.Search, title).MatchData, // TODO if length is 0 CopyText = path, Preview = new Result.PreviewInfo { @@ -347,7 +347,7 @@ internal static Result CreateFileResult(string filePath, Query query, int score FilePath = filePath, }, AutoCompleteText = GetAutoCompleteText(title, query, filePath, ResultType.File), - TitleHighlightData = highlightData ?? Context.API.FuzzySearch(query.Search, title).MatchData, + TitleHighlightData = highlightData ?? Context.API.FuzzySearch(query.Search, title).MatchData, // TODO if length is 0 Score = score, CopyText = filePath, PreviewPanel = new Lazy(() => new PreviewPanel(Settings, filePath, ResultType.File)), From 5fbb520d78858a81d7e002fca79bba4be6e52c88 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 28 Mar 2026 15:05:40 +0800 Subject: [PATCH 06/29] Fix highlighting issue --- .../Search/Everything/EverythingAPI.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 7bd421b8be8..043cb2ab8de 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -214,10 +214,11 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I } _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); - // TODO somehow error, no result _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); - // TODO need to check the "IsFullPathSearch" _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); + // Everything3_GetResultFullPathNameW requires PATH_AND_NAME to be requested + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); if (token.IsCancellationRequested) yield break; From 4bf530be2886e20b6a7a39b9967632bc2d19f5f9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 11:13:02 +0000 Subject: [PATCH 07/29] Fix LoadLibrary return type to IntPtr and use Win32Exception for error handling Agent-Logs-Url: https://github.com/Flow-Launcher/Flow.Launcher/sessions/bfa04540-ad54-4f04-a7cf-fed5dbc06dcc Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> --- .../Search/Everything/Everything3ApiDllImport.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index 4514a1549f3..e2ca1bd2162 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -10,16 +11,15 @@ internal static class Everything3ApiDllImport public static void Load(string directory) { var path = Path.Combine(directory, Dll); - int code = LoadLibrary(path); - if (code == 0) + IntPtr handle = LoadLibrary(path); + if (handle == IntPtr.Zero) { - int err = Marshal.GetLastPInvokeError(); - Marshal.ThrowExceptionForHR(err); + throw new Win32Exception(Marshal.GetLastPInvokeError()); } } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern int LoadLibrary(string name); + private static extern IntPtr LoadLibrary(string name); private const string Dll = "Everything3.dll"; [DllImport(Dll, CharSet = CharSet.Unicode)] From cc6236256c59ffa78643c8bce914d83c9fee893c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:37:22 +0800 Subject: [PATCH 08/29] Fix LoadLibrary return type to IntPtr and use Win32Exception for error handling --- .../Search/Everything/EverythingApiDllImport.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index 344c1a42c16..e5088b79e54 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -10,16 +11,15 @@ public static class EverythingApiDllImport public static void Load(string directory) { var path = Path.Combine(directory, DLL); - int code = LoadLibrary(path); - if (code == 0) + IntPtr handle = LoadLibrary(path); + if (handle == IntPtr.Zero) { - int err = Marshal.GetLastPInvokeError(); - Marshal.ThrowExceptionForHR(err); + throw new Win32Exception(Marshal.GetLastPInvokeError()); } } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern int LoadLibrary(string name); + private static extern IntPtr LoadLibrary(string name); private const string DLL = "Everything.dll"; From e5cc9112dfb6bcaacd946d7f63626c4d750c62d0 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:44:51 +0800 Subject: [PATCH 09/29] Extract Everything3 functions --- .../Everything/EverythingAPI.Everything3.cs | 316 ++++++++++++++++++ .../Search/Everything/EverythingAPI.cs | 305 +---------------- 2 files changed, 317 insertions(+), 304 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs new file mode 100644 index 00000000000..9aef87e0f3f --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs @@ -0,0 +1,316 @@ +using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + public static partial class EverythingApi + { + private const string Everything15AlphaInstance = "1.5a"; + + const uint EVERYTHING3_PROPERTY_ID_NAME = 0; + const uint EVERYTHING3_PROPERTY_ID_PATH = 1; + const uint EVERYTHING3_PROPERTY_ID_SIZE = 2; + const uint EVERYTHING3_PROPERTY_ID_EXTENSION = 3; + const uint EVERYTHING3_PROPERTY_ID_TYPE = 4; + const uint EVERYTHING3_PROPERTY_ID_DATE_MODIFIED = 5; + const uint EVERYTHING3_PROPERTY_ID_DATE_CREATED = 6; + const uint EVERYTHING3_PROPERTY_ID_DATE_ACCESSED = 7; + const uint EVERYTHING3_PROPERTY_ID_ATTRIBUTES = 8; + const uint EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED = 9; + const uint EVERYTHING3_PROPERTY_ID_RUN_COUNT = 10; + const uint EVERYTHING3_PROPERTY_ID_DATE_RUN = 11; + const uint EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME = 12; + const uint EVERYTHING3_PROPERTY_ID_PATH_AND_NAME = 240; + + const uint EVERYTHING3_ERROR_OUT_OF_MEMORY = 0xE0000001; + const uint EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND = 0xE0000002; + const uint EVERYTHING3_ERROR_DISCONNECTED = 0xE0000003; + const uint EVERYTHING3_ERROR_INVALID_PARAMETER = 0xE0000004; + const uint EVERYTHING3_ERROR_PROPERTY_NOT_FOUND = 0xE0000007; + + private static async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, + EverythingSearchOption option, + string searchText, + bool useRegex, + [EnumeratorCancellation] CancellationToken token) + { + IntPtr searchState = IntPtr.Zero; + IntPtr resultList = IntPtr.Zero; + try + { + searchState = Everything3ApiDllImport.Everything3_CreateSearchState(); + if (searchState == IntPtr.Zero) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + yield break; + } + + _ = Everything3ApiDllImport.Everything3_SetSearchRegex(searchState, useRegex); + _ = Everything3ApiDllImport.Everything3_SetSearchMatchPath(searchState, option.IsFullPathSearch); + _ = Everything3ApiDllImport.Everything3_SetSearchTextW(searchState, searchText); + _ = Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions(searchState, true); + _ = Everything3ApiDllImport.Everything3_SetSearchViewportOffset(searchState, (nuint)option.Offset); + _ = Everything3ApiDllImport.Everything3_SetSearchViewportCount(searchState, (nuint)option.MaxCount); + + if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) + { + _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); + } + + _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); + // Everything3_GetResultFullPathNameW requires PATH_AND_NAME to be requested + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); + _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); + + if (token.IsCancellationRequested) + yield break; + + resultList = Everything3ApiDllImport.Everything3_Search(client, searchState); + if (resultList == IntPtr.Zero) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + yield break; + } + + var resultCount = Everything3ApiDllImport.Everything3_GetResultListViewportCount(resultList); + for (nuint idx = 0; idx < resultCount; ++idx) + { + if (token.IsCancellationRequested) + { + yield break; + } + + buffer.Clear(); + var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, buffer, BufferSize); + if (fullPathLength == 0) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + continue; + } + + var fullPath = buffer.ToString(); + if (string.IsNullOrEmpty(fullPath)) + { + continue; + } + + var result = new SearchResult + { + FullPath = fullPath, + Type = Everything3ApiDllImport.Everything3_IsFolderResult(resultList, idx) + ? ResultType.Folder + : Everything3ApiDllImport.Everything3_IsRootResult(resultList, idx) + ? ResultType.Volume + : ResultType.File, + Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)) + }; + + // 0 for the first requested property, which is name in our case. + if (Everything3ApiDllImport.Everything3_GetSearchPropertyRequestHighlight(searchState, 0)) + { + buffer.Clear(); + var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( + resultList, + idx, + EVERYTHING3_PROPERTY_ID_NAME, + buffer, + BufferSize); + + if (highlightedFileNameLength > 0) + { + var highlightData = EverythingHighlightStringToHighlightList(buffer.ToString()); + if (highlightData.Count > 0) + { + result = result with + { + HighlightData = highlightData + }; + } + } + } + + yield return result; + } + } + finally + { + if (resultList != IntPtr.Zero) + _ = Everything3ApiDllImport.Everything3_DestroyResultList(resultList); + + if (searchState != IntPtr.Zero) + _ = Everything3ApiDllImport.Everything3_DestroySearchState(searchState); + + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + } + + await Task.CompletedTask; + } + + private static bool TryUseEverything3Client(Action action) + { + if (!TryConnectEverything3(out var client)) + return false; + + try + { + action(client); + return true; + } + finally + { + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + } + } + + private static bool TryConnectEverything3(out IntPtr client) + { + client = IntPtr.Zero; + try + { + client = Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); + return client != IntPtr.Zero; + } + catch (DllNotFoundException) + { + return false; + } + catch (EntryPointNotFoundException) + { + return false; + } + } + + private static bool TryConvertSortOption(EverythingSortOption sortOption, out uint propertyId, out bool ascending) + { + switch (sortOption) + { + case EverythingSortOption.NAME_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_NAME; + ascending = true; + return true; + case EverythingSortOption.NAME_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_NAME; + ascending = false; + return true; + case EverythingSortOption.PATH_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_PATH; + ascending = true; + return true; + case EverythingSortOption.PATH_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_PATH; + ascending = false; + return true; + case EverythingSortOption.SIZE_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_SIZE; + ascending = true; + return true; + case EverythingSortOption.SIZE_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_SIZE; + ascending = false; + return true; + case EverythingSortOption.EXTENSION_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_EXTENSION; + ascending = true; + return true; + case EverythingSortOption.EXTENSION_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_EXTENSION; + ascending = false; + return true; + case EverythingSortOption.TYPE_NAME_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_TYPE; + ascending = true; + return true; + case EverythingSortOption.TYPE_NAME_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_TYPE; + ascending = false; + return true; + case EverythingSortOption.DATE_CREATED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_CREATED; + ascending = true; + return true; + case EverythingSortOption.DATE_CREATED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_CREATED; + ascending = false; + return true; + case EverythingSortOption.DATE_MODIFIED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_MODIFIED; + ascending = true; + return true; + case EverythingSortOption.DATE_MODIFIED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_MODIFIED; + ascending = false; + return true; + case EverythingSortOption.ATTRIBUTES_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_ATTRIBUTES; + ascending = true; + return true; + case EverythingSortOption.ATTRIBUTES_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_ATTRIBUTES; + ascending = false; + return true; + case EverythingSortOption.FILE_LIST_FILENAME_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME; + ascending = true; + return true; + case EverythingSortOption.FILE_LIST_FILENAME_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME; + ascending = false; + return true; + case EverythingSortOption.RUN_COUNT_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_RUN_COUNT; + ascending = false; + return true; + case EverythingSortOption.DATE_RECENTLY_CHANGED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED; + ascending = true; + return true; + case EverythingSortOption.DATE_RECENTLY_CHANGED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED; + ascending = false; + return true; + case EverythingSortOption.DATE_ACCESSED_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_ACCESSED; + ascending = true; + return true; + case EverythingSortOption.DATE_ACCESSED_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_ACCESSED; + ascending = false; + return true; + case EverythingSortOption.DATE_RUN_ASCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RUN; + ascending = true; + return true; + case EverythingSortOption.DATE_RUN_DESCENDING: + propertyId = EVERYTHING3_PROPERTY_ID_DATE_RUN; + ascending = false; + return true; + default: + propertyId = EVERYTHING3_PROPERTY_ID_NAME; + ascending = true; + return false; + } + } + + private static void CheckAndThrowExceptionOnErrorFromEverything3() + { + switch (Everything3ApiDllImport.Everything3_GetLastError()) + { + case EVERYTHING3_ERROR_OUT_OF_MEMORY: + throw new MemoryErrorException(); + case EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND: + case EVERYTHING3_ERROR_DISCONNECTED: + throw new IPCErrorException(); + case EVERYTHING3_ERROR_INVALID_PARAMETER: + throw new InvalidCallException(); + case EVERYTHING3_ERROR_PROPERTY_NOT_FOUND: + throw new ArgumentException("EVERYTHING3_ERROR_PROPERTY_NOT_FOUND"); + } + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 043cb2ab8de..0c60787a4ff 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -8,10 +8,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { - public static class EverythingApi + public static partial class EverythingApi { private const int BufferSize = 4096; - private const string Everything15AlphaInstance = "1.5a"; private static readonly SemaphoreSlim _semaphore = new(1, 1); @@ -33,27 +32,6 @@ public enum StateCode const uint EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004u; const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u; - const uint EVERYTHING3_PROPERTY_ID_NAME = 0; - const uint EVERYTHING3_PROPERTY_ID_PATH = 1; - const uint EVERYTHING3_PROPERTY_ID_SIZE = 2; - const uint EVERYTHING3_PROPERTY_ID_EXTENSION = 3; - const uint EVERYTHING3_PROPERTY_ID_TYPE = 4; - const uint EVERYTHING3_PROPERTY_ID_DATE_MODIFIED = 5; - const uint EVERYTHING3_PROPERTY_ID_DATE_CREATED = 6; - const uint EVERYTHING3_PROPERTY_ID_DATE_ACCESSED = 7; - const uint EVERYTHING3_PROPERTY_ID_ATTRIBUTES = 8; - const uint EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED = 9; - const uint EVERYTHING3_PROPERTY_ID_RUN_COUNT = 10; - const uint EVERYTHING3_PROPERTY_ID_DATE_RUN = 11; - const uint EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME = 12; - const uint EVERYTHING3_PROPERTY_ID_PATH_AND_NAME = 240; - - const uint EVERYTHING3_ERROR_OUT_OF_MEMORY = 0xE0000001; - const uint EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND = 0xE0000002; - const uint EVERYTHING3_ERROR_DISCONNECTED = 0xE0000003; - const uint EVERYTHING3_ERROR_INVALID_PARAMETER = 0xE0000004; - const uint EVERYTHING3_ERROR_PROPERTY_NOT_FOUND = 0xE0000007; - /// /// Checks whether the sort option is Fast Sort. /// @@ -184,126 +162,6 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO } } - private static async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, - EverythingSearchOption option, - string searchText, - bool useRegex, - [EnumeratorCancellation] CancellationToken token) - { - IntPtr searchState = IntPtr.Zero; - IntPtr resultList = IntPtr.Zero; - try - { - searchState = Everything3ApiDllImport.Everything3_CreateSearchState(); - if (searchState == IntPtr.Zero) - { - CheckAndThrowExceptionOnErrorFromEverything3(); - yield break; - } - - _ = Everything3ApiDllImport.Everything3_SetSearchRegex(searchState, useRegex); - _ = Everything3ApiDllImport.Everything3_SetSearchMatchPath(searchState, option.IsFullPathSearch); - _ = Everything3ApiDllImport.Everything3_SetSearchTextW(searchState, searchText); - _ = Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions(searchState, true); - _ = Everything3ApiDllImport.Everything3_SetSearchViewportOffset(searchState, (nuint)option.Offset); - _ = Everything3ApiDllImport.Everything3_SetSearchViewportCount(searchState, (nuint)option.MaxCount); - - if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) - { - _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); - } - - _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); - // Everything3_GetResultFullPathNameW requires PATH_AND_NAME to be requested - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); - _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); - - if (token.IsCancellationRequested) - yield break; - - resultList = Everything3ApiDllImport.Everything3_Search(client, searchState); - if (resultList == IntPtr.Zero) - { - CheckAndThrowExceptionOnErrorFromEverything3(); - yield break; - } - - var resultCount = Everything3ApiDllImport.Everything3_GetResultListViewportCount(resultList); - for (nuint idx = 0; idx < resultCount; ++idx) - { - if (token.IsCancellationRequested) - { - yield break; - } - - buffer.Clear(); - var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, buffer, BufferSize); - if (fullPathLength == 0) - { - CheckAndThrowExceptionOnErrorFromEverything3(); - continue; - } - - var fullPath = buffer.ToString(); - if (string.IsNullOrEmpty(fullPath)) - { - continue; - } - - var result = new SearchResult - { - FullPath = fullPath, - Type = Everything3ApiDllImport.Everything3_IsFolderResult(resultList, idx) - ? ResultType.Folder - : Everything3ApiDllImport.Everything3_IsRootResult(resultList, idx) - ? ResultType.Volume - : ResultType.File, - Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)) - }; - - // 0 for the first requested property, which is name in our case. - if (Everything3ApiDllImport.Everything3_GetSearchPropertyRequestHighlight(searchState, 0)) - { - buffer.Clear(); - var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( - resultList, - idx, - EVERYTHING3_PROPERTY_ID_NAME, - buffer, - BufferSize); - - if (highlightedFileNameLength > 0) - { - var highlightData = EverythingHighlightStringToHighlightList(buffer.ToString()); - if (highlightData.Count > 0) - { - result = result with - { - HighlightData = highlightData - }; - } - } - } - - yield return result; - } - } - finally - { - if (resultList != IntPtr.Zero) - _ = Everything3ApiDllImport.Everything3_DestroyResultList(resultList); - - if (searchState != IntPtr.Zero) - _ = Everything3ApiDllImport.Everything3_DestroySearchState(searchState); - - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); - } - - await Task.CompletedTask; - } - private static async IAsyncEnumerable SearchWithEverythingLegacyAsync(EverythingSearchOption option, string searchText, bool useRegex, @@ -366,167 +224,6 @@ private static async IAsyncEnumerable SearchWithEverythingLegacyAs await Task.CompletedTask; } - private static bool TryUseEverything3Client(Action action) - { - if (!TryConnectEverything3(out var client)) - return false; - - try - { - action(client); - return true; - } - finally - { - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); - } - } - - private static bool TryConnectEverything3(out IntPtr client) - { - client = IntPtr.Zero; - try - { - client = Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); - return client != IntPtr.Zero; - } - catch (DllNotFoundException) - { - return false; - } - catch (EntryPointNotFoundException) - { - return false; - } - } - - private static bool TryConvertSortOption(EverythingSortOption sortOption, out uint propertyId, out bool ascending) - { - switch (sortOption) - { - case EverythingSortOption.NAME_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_NAME; - ascending = true; - return true; - case EverythingSortOption.NAME_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_NAME; - ascending = false; - return true; - case EverythingSortOption.PATH_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_PATH; - ascending = true; - return true; - case EverythingSortOption.PATH_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_PATH; - ascending = false; - return true; - case EverythingSortOption.SIZE_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_SIZE; - ascending = true; - return true; - case EverythingSortOption.SIZE_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_SIZE; - ascending = false; - return true; - case EverythingSortOption.EXTENSION_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_EXTENSION; - ascending = true; - return true; - case EverythingSortOption.EXTENSION_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_EXTENSION; - ascending = false; - return true; - case EverythingSortOption.TYPE_NAME_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_TYPE; - ascending = true; - return true; - case EverythingSortOption.TYPE_NAME_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_TYPE; - ascending = false; - return true; - case EverythingSortOption.DATE_CREATED_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_CREATED; - ascending = true; - return true; - case EverythingSortOption.DATE_CREATED_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_CREATED; - ascending = false; - return true; - case EverythingSortOption.DATE_MODIFIED_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_MODIFIED; - ascending = true; - return true; - case EverythingSortOption.DATE_MODIFIED_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_MODIFIED; - ascending = false; - return true; - case EverythingSortOption.ATTRIBUTES_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_ATTRIBUTES; - ascending = true; - return true; - case EverythingSortOption.ATTRIBUTES_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_ATTRIBUTES; - ascending = false; - return true; - case EverythingSortOption.FILE_LIST_FILENAME_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME; - ascending = true; - return true; - case EverythingSortOption.FILE_LIST_FILENAME_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_FILE_LIST_NAME; - ascending = false; - return true; - case EverythingSortOption.RUN_COUNT_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_RUN_COUNT; - ascending = false; - return true; - case EverythingSortOption.DATE_RECENTLY_CHANGED_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED; - ascending = true; - return true; - case EverythingSortOption.DATE_RECENTLY_CHANGED_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_RECENTLY_CHANGED; - ascending = false; - return true; - case EverythingSortOption.DATE_ACCESSED_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_ACCESSED; - ascending = true; - return true; - case EverythingSortOption.DATE_ACCESSED_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_ACCESSED; - ascending = false; - return true; - case EverythingSortOption.DATE_RUN_ASCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_RUN; - ascending = true; - return true; - case EverythingSortOption.DATE_RUN_DESCENDING: - propertyId = EVERYTHING3_PROPERTY_ID_DATE_RUN; - ascending = false; - return true; - default: - propertyId = EVERYTHING3_PROPERTY_ID_NAME; - ascending = true; - return false; - } - } - - private static void CheckAndThrowExceptionOnErrorFromEverything3() - { - switch (Everything3ApiDllImport.Everything3_GetLastError()) - { - case EVERYTHING3_ERROR_OUT_OF_MEMORY: - throw new MemoryErrorException(); - case EVERYTHING3_ERROR_IPC_PIPE_NOT_FOUND: - case EVERYTHING3_ERROR_DISCONNECTED: - throw new IPCErrorException(); - case EVERYTHING3_ERROR_INVALID_PARAMETER: - throw new InvalidCallException(); - case EVERYTHING3_ERROR_PROPERTY_NOT_FOUND: - throw new ArgumentException("EVERYTHING3_ERROR_PROPERTY_NOT_FOUND"); - } - } - private static void CheckAndThrowExceptionOnError() { switch (EverythingApiDllImport.Everything_GetLastError()) From 9eeadfe135b80b0a388910006ac4a36df730a732 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 28 Mar 2026 20:20:10 +0800 Subject: [PATCH 10/29] Add option for Everything 1.5 support --- .../Languages/en.xaml | 1 + Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 7 ++- .../Everything/Everything3ApiDllImport.cs | 27 +++++++++- .../Everything/EverythingAPI.Everything3.cs | 4 ++ .../Search/Everything/EverythingAPI.cs | 53 ++++++++++++++++--- .../Everything/EverythingApiDllImport.cs | 26 ++++++++- .../Flow.Launcher.Plugin.Explorer/Settings.cs | 1 + .../ViewModels/SettingsViewModel.cs | 20 +++++++ .../Views/ExplorerSettings.xaml | 23 +++++--- 9 files changed, 140 insertions(+), 22 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 1eae757083c..e05b0135008 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -186,6 +186,7 @@ Search Full Path Enable File/Folder Run Count + Enable Everything 1.5 support Click to launch or install Everything Everything Installation diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index ab48d76d53e..7a77c17dc2f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -46,10 +46,9 @@ public Task InitAsync(PluginInitContext context) searchManager = new SearchManager(Settings, Context); ResultManager.Init(Context, Settings); - EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", - Environment.Is64BitProcess ? "x64" : "x86")); - Everything3ApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", - Environment.Is64BitProcess ? "x64" : "x86")); + var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", + Environment.Is64BitProcess ? "x64" : "x86"); + EverythingApi.ConfigureEverythingSupport(Settings.EnableEverything15Support, sdkDirectory); return Task.CompletedTask; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index e2ca1bd2162..2ca04bb4798 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -8,18 +8,41 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { internal static class Everything3ApiDllImport { + private static IntPtr _dllHandle = IntPtr.Zero; + public static void Load(string directory) { + if (_dllHandle != IntPtr.Zero) + { + return; + } + var path = Path.Combine(directory, Dll); - IntPtr handle = LoadLibrary(path); - if (handle == IntPtr.Zero) + _dllHandle = LoadLibrary(path); + if (_dllHandle == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastPInvokeError()); } } + public static void Unload() + { + if (_dllHandle == IntPtr.Zero) + { + return; + } + + _ = FreeLibrary(_dllHandle); + _dllHandle = IntPtr.Zero; + } + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibrary(string name); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool FreeLibrary(IntPtr hModule); + private const string Dll = "Everything3.dll"; [DllImport(Dll, CharSet = CharSet.Unicode)] diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs index 9aef87e0f3f..e9a8eedbde3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs @@ -171,6 +171,10 @@ private static bool TryUseEverything3Client(Action action) private static bool TryConnectEverything3(out IntPtr client) { client = IntPtr.Zero; + + if (!EnableEverything15Support) + return false; + try { client = Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 0c60787a4ff..a12bc4c0e83 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -13,6 +13,7 @@ public static partial class EverythingApi private const int BufferSize = 4096; private static readonly SemaphoreSlim _semaphore = new(1, 1); + private static volatile bool _enableEverything15Support = true; // cached buffer to remove redundant allocations. semaphore is used to make sure the access to the buffer is thread safe. private static readonly StringBuilder buffer = new(BufferSize); @@ -32,13 +33,42 @@ public enum StateCode const uint EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004u; const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u; + public static bool EnableEverything15Support => _enableEverything15Support; + + public static void ConfigureEverythingSupport(bool enableEverything15Support, string sdkDirectory) + { + _semaphore.Wait(); + try + { + _enableEverything15Support = enableEverything15Support; + + if (enableEverything15Support) + { + EverythingApiDllImport.Unload(); + Everything3ApiDllImport.Load(sdkDirectory); + } + else + { + Everything3ApiDllImport.Unload(); + EverythingApiDllImport.Load(sdkDirectory); + } + } + finally + { + _semaphore.Release(); + } + } + /// /// Checks whether the sort option is Fast Sort. /// public static bool IsFastSortOption(EverythingSortOption sortOption) { - if (TryConnectEverything3(out var client)) + if (EnableEverything15Support) { + if (!TryConnectEverything3(out var client)) + throw new IPCErrorException(); + try { if (TryConvertSortOption(sortOption, out var propertyId, out _)) @@ -57,6 +87,8 @@ public static bool IsFastSortOption(EverythingSortOption sortOption) // Throw again to the caller CheckAndThrowExceptionOnErrorFromEverything3(); } + + return true; } var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); @@ -81,12 +113,11 @@ public static async ValueTask IsEverythingRunningAsync(CancellationToken t try { - if (TryUseEverything3Client(static _ => { })) - return true; + if (EnableEverything15Support) + return TryUseEverything3Client(static _ => { }); _ = EverythingApiDllImport.Everything_GetMajorVersion(); - var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; - return result; + return EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; } finally { @@ -145,8 +176,11 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO var searchText = builder.ToString(); - if (TryConnectEverything3(out var client)) + if (EnableEverything15Support) { + if (!TryConnectEverything3(out var client)) + throw new IPCErrorException(); + await foreach (var result in SearchWithEverything3Async(client, option, searchText, useRegex, token)) yield return result; @@ -254,9 +288,12 @@ public static async Task IncrementRunCounterAsync(string fileOrFolder) await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); try { - if (TryUseEverything3Client(client => - _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder))) + if (EnableEverything15Support) + { + _ = TryUseEverything3Client(client => + _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder)); return; + } _ = EverythingApiDllImport.Everything_IncRunCountFromFileName(fileOrFolder); } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index e5088b79e54..d31db5ab0aa 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -8,19 +8,41 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public static class EverythingApiDllImport { + private static IntPtr _dllHandle = IntPtr.Zero; + public static void Load(string directory) { + if (_dllHandle != IntPtr.Zero) + { + return; + } + var path = Path.Combine(directory, DLL); - IntPtr handle = LoadLibrary(path); - if (handle == IntPtr.Zero) + _dllHandle = LoadLibrary(path); + if (_dllHandle == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastPInvokeError()); } } + public static void Unload() + { + if (_dllHandle == IntPtr.Zero) + { + return; + } + + _ = FreeLibrary(_dllHandle); + _dllHandle = IntPtr.Zero; + } + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibrary(string name); + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool FreeLibrary(IntPtr hModule); + private const string DLL = "Everything.dll"; [DllImport(DLL, CharSet = CharSet.Unicode)] diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index b0fbad84fbe..0f4162514b6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -163,6 +163,7 @@ public enum ContentIndexSearchEngineOption public bool EverythingSearchFullPath { get; set; } = false; public bool EverythingEnableRunCount { get; set; } = true; + public bool EnableEverything15Support { get; set; } = false; #endregion diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index a9b2e6a89e3..e81f43946f3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -666,6 +666,26 @@ public string EverythingInstalledPath } } + public bool EnableEverything15Support + { + get => Settings.EnableEverything15Support; + set + { + if (Settings.EnableEverything15Support == value) + return; + + Settings.EnableEverything15Support = value; + + var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", + Environment.Is64BitProcess ? "x64" : "x86"); + EverythingApi.ConfigureEverythingSupport(value, sdkDirectory); + + OnPropertyChanged(); + OnPropertyChanged(nameof(FastSortWarningVisibility)); + OnPropertyChanged(nameof(SortOptionWarningMessage)); + } + } + #endregion } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index d6066df953f..d0b7958d4cc 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -435,6 +435,7 @@ + @@ -602,6 +603,7 @@ + @@ -614,11 +616,20 @@ Grid.ColumnSpan="2" Margin="{StaticResource SettingPanelItemTopBottomMargin}" HorizontalAlignment="Left" + Content="{DynamicResource flowlauncher_plugin_everything_enable_15_support}" + IsChecked="{Binding EnableEverything15Support}" /> + + Date: Sat, 28 Mar 2026 20:37:58 +0800 Subject: [PATCH 11/29] Allow customizing Everything 1.5 instance name --- .../Languages/en.xaml | 1 + Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 2 +- .../Everything/Everything3ApiDllImport.cs | 1 + .../Everything/EverythingAPI.Everything3.cs | 4 +-- .../Search/Everything/EverythingAPI.cs | 30 +++++++++++++--- .../Everything/EverythingApiDllImport.cs | 1 + .../Flow.Launcher.Plugin.Explorer/Settings.cs | 1 + .../ViewModels/SettingsViewModel.cs | 29 ++++++++++++++- .../Views/ExplorerSettings.xaml | 35 +++++++++++++++---- 9 files changed, 87 insertions(+), 17 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index e05b0135008..a0cd5316549 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -44,6 +44,7 @@ Date and time format Sort Option: Everything Path: + Everything 1.5 instance name: Launch Hidden Editor Path Shell Path diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index 7a77c17dc2f..1389d5be16d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -48,7 +48,7 @@ public Task InitAsync(PluginInitContext context) var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86"); - EverythingApi.ConfigureEverythingSupport(Settings.EnableEverything15Support, sdkDirectory); + EverythingApi.ConfigureEverythingSupport(Settings.EnableEverything15Support, sdkDirectory, Settings.Everything15InstanceName); return Task.CompletedTask; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index 2ca04bb4798..fbc9335ed7e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -9,6 +9,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything internal static class Everything3ApiDllImport { private static IntPtr _dllHandle = IntPtr.Zero; + internal static bool IsLoaded => _dllHandle != IntPtr.Zero; public static void Load(string directory) { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs index e9a8eedbde3..8f718250397 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs @@ -9,8 +9,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public static partial class EverythingApi { - private const string Everything15AlphaInstance = "1.5a"; - const uint EVERYTHING3_PROPERTY_ID_NAME = 0; const uint EVERYTHING3_PROPERTY_ID_PATH = 1; const uint EVERYTHING3_PROPERTY_ID_SIZE = 2; @@ -177,7 +175,7 @@ private static bool TryConnectEverything3(out IntPtr client) try { - client = Everything3ApiDllImport.Everything3_ConnectW(Everything15AlphaInstance); + client = Everything3ApiDllImport.Everything3_ConnectW(Everything15InstanceName); return client != IntPtr.Zero; } catch (DllNotFoundException) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index a12bc4c0e83..c27fa825ac8 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -10,10 +10,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public static partial class EverythingApi { + public const string DefaultEverything15InstanceName = "1.5a"; + private const int BufferSize = 4096; private static readonly SemaphoreSlim _semaphore = new(1, 1); private static volatile bool _enableEverything15Support = true; + private static string _everything15InstanceName = DefaultEverything15InstanceName; // cached buffer to remove redundant allocations. semaphore is used to make sure the access to the buffer is thread safe. private static readonly StringBuilder buffer = new(BufferSize); @@ -34,23 +37,40 @@ public enum StateCode const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u; public static bool EnableEverything15Support => _enableEverything15Support; + public static string Everything15InstanceName => _everything15InstanceName; - public static void ConfigureEverythingSupport(bool enableEverything15Support, string sdkDirectory) + public static void ConfigureEverythingSupport(bool enableEverything15Support, string sdkDirectory, string everything15InstanceName) { _semaphore.Wait(); try { + var normalizedInstanceName = string.IsNullOrWhiteSpace(everything15InstanceName) + ? DefaultEverything15InstanceName + : everything15InstanceName.Trim(); + + var supportChanged = _enableEverything15Support != enableEverything15Support; _enableEverything15Support = enableEverything15Support; + _everything15InstanceName = normalizedInstanceName; if (enableEverything15Support) { - EverythingApiDllImport.Unload(); - Everything3ApiDllImport.Load(sdkDirectory); + if (supportChanged || !Everything3ApiDllImport.IsLoaded) + { + if (EverythingApiDllImport.IsLoaded) + EverythingApiDllImport.Unload(); + + Everything3ApiDllImport.Load(sdkDirectory); + } } else { - Everything3ApiDllImport.Unload(); - EverythingApiDllImport.Load(sdkDirectory); + if (supportChanged || !EverythingApiDllImport.IsLoaded) + { + if (Everything3ApiDllImport.IsLoaded) + Everything3ApiDllImport.Unload(); + + EverythingApiDllImport.Load(sdkDirectory); + } } } finally diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index d31db5ab0aa..3ffd80b3e09 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -9,6 +9,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything public static class EverythingApiDllImport { private static IntPtr _dllHandle = IntPtr.Zero; + public static bool IsLoaded => _dllHandle != IntPtr.Zero; public static void Load(string directory) { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 0f4162514b6..2be694a7f40 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -164,6 +164,7 @@ public enum ContentIndexSearchEngineOption public bool EverythingSearchFullPath { get; set; } = false; public bool EverythingEnableRunCount { get; set; } = true; public bool EnableEverything15Support { get; set; } = false; + public string Everything15InstanceName { get; set; } = "1.5a"; #endregion diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index e81f43946f3..de28ceb9255 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -678,7 +678,7 @@ public bool EnableEverything15Support var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86"); - EverythingApi.ConfigureEverythingSupport(value, sdkDirectory); + EverythingApi.ConfigureEverythingSupport(value, sdkDirectory, Settings.Everything15InstanceName); OnPropertyChanged(); OnPropertyChanged(nameof(FastSortWarningVisibility)); @@ -686,6 +686,33 @@ public bool EnableEverything15Support } } + public string Everything15InstanceName + { + get => Settings.Everything15InstanceName; + set + { + var instanceName = string.IsNullOrWhiteSpace(value) + ? EverythingApi.DefaultEverything15InstanceName + : value.Trim(); + + if (Settings.Everything15InstanceName == instanceName) + return; + + Settings.Everything15InstanceName = instanceName; + + if (EnableEverything15Support) + { + var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", + Environment.Is64BitProcess ? "x64" : "x86"); + EverythingApi.ConfigureEverythingSupport(true, sdkDirectory, instanceName); + OnPropertyChanged(nameof(FastSortWarningVisibility)); + OnPropertyChanged(nameof(SortOptionWarningMessage)); + } + + OnPropertyChanged(); + } + } + #endregion } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index d0b7958d4cc..90a0213c301 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -13,6 +13,8 @@ mc:Ignorable="d"> + + @@ -436,6 +438,7 @@ + @@ -604,6 +607,7 @@ + @@ -619,9 +623,26 @@ Content="{DynamicResource flowlauncher_plugin_everything_enable_15_support}" IsChecked="{Binding EnableEverything15Support}" /> - + + + Date: Sat, 28 Mar 2026 22:35:39 +0800 Subject: [PATCH 12/29] Use variable for default name Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 2be694a7f40..5ecfaa7c66c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -164,7 +164,7 @@ public enum ContentIndexSearchEngineOption public bool EverythingSearchFullPath { get; set; } = false; public bool EverythingEnableRunCount { get; set; } = true; public bool EnableEverything15Support { get; set; } = false; - public string Everything15InstanceName { get; set; } = "1.5a"; + public string Everything15InstanceName { get; set; } = EverythingApi.DefaultEverything15InstanceName; #endregion From 68f0f47a0d7ac455dd754b2f1a0cd7693f03f4be Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:15:23 +0800 Subject: [PATCH 13/29] Clear handle after successful unload --- .../Search/Everything/Everything3ApiDllImport.cs | 6 ++++-- .../Search/Everything/EverythingApiDllImport.cs | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index fbc9335ed7e..9844330750c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -32,8 +32,10 @@ public static void Unload() { return; } - - _ = FreeLibrary(_dllHandle); + if (!FreeLibrary(_dllHandle)) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } _dllHandle = IntPtr.Zero; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index 3ffd80b3e09..4607badba3f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -33,7 +33,10 @@ public static void Unload() return; } - _ = FreeLibrary(_dllHandle); + if (!FreeLibrary(_dllHandle)) + { + throw new Win32Exception(Marshal.GetLastPInvokeError()); + } _dllHandle = IntPtr.Zero; } From 584ce0790b699a775301195cff5aa77a908fcee1 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 01:40:34 +0800 Subject: [PATCH 14/29] Refactor --- Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 2 +- .../Search/Everything/EverythingAPI.cs | 235 ++---------------- .../Everything/EverythingApiDllImport.cs | 2 +- ...gAPI.Everything3.cs => EverythingApiV3.cs} | 165 ++++++++++-- .../Search/Everything/EverythingHelper.cs | 69 +++++ .../Everything/EverythingSearchManager.cs | 71 +++++- .../Search/Everything/IEverythingApi.cs | 14 ++ .../Search/ResultManager.cs | 3 +- .../Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- .../ViewModels/SettingsViewModel.cs | 10 +- 10 files changed, 330 insertions(+), 243 deletions(-) rename Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/{EverythingAPI.Everything3.cs => EverythingApiV3.cs} (72%) create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/IEverythingApi.cs diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index 1389d5be16d..d872ae22b1f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -48,7 +48,7 @@ public Task InitAsync(PluginInitContext context) var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86"); - EverythingApi.ConfigureEverythingSupport(Settings.EnableEverything15Support, sdkDirectory, Settings.Everything15InstanceName); + Settings.EverythingManagerInstance.ReloadApi(sdkDirectory); return Task.CompletedTask; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index c27fa825ac8..6ecd4b3d0c0 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -1,126 +1,27 @@ -using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; -using System; +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; namespace Flow.Launcher.Plugin.Explorer.Search.Everything { - public static partial class EverythingApi + public class LegacyEverythingApi : IEverythingApi { - public const string DefaultEverything15InstanceName = "1.5a"; - private const int BufferSize = 4096; - private static readonly SemaphoreSlim _semaphore = new(1, 1); - private static volatile bool _enableEverything15Support = true; - private static string _everything15InstanceName = DefaultEverything15InstanceName; - - // cached buffer to remove redundant allocations. semaphore is used to make sure the access to the buffer is thread safe. private static readonly StringBuilder buffer = new(BufferSize); - public enum StateCode - { - OK, - MemoryError, - IPCError, - RegisterClassExError, - CreateWindowError, - CreateThreadError, - InvalidIndexError, - InvalidCallError - } - - const uint EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004u; - const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u; - - public static bool EnableEverything15Support => _enableEverything15Support; - public static string Everything15InstanceName => _everything15InstanceName; - - public static void ConfigureEverythingSupport(bool enableEverything15Support, string sdkDirectory, string everything15InstanceName) - { - _semaphore.Wait(); - try - { - var normalizedInstanceName = string.IsNullOrWhiteSpace(everything15InstanceName) - ? DefaultEverything15InstanceName - : everything15InstanceName.Trim(); - - var supportChanged = _enableEverything15Support != enableEverything15Support; - _enableEverything15Support = enableEverything15Support; - _everything15InstanceName = normalizedInstanceName; - - if (enableEverything15Support) - { - if (supportChanged || !Everything3ApiDllImport.IsLoaded) - { - if (EverythingApiDllImport.IsLoaded) - EverythingApiDllImport.Unload(); - - Everything3ApiDllImport.Load(sdkDirectory); - } - } - else - { - if (supportChanged || !EverythingApiDllImport.IsLoaded) - { - if (Everything3ApiDllImport.IsLoaded) - Everything3ApiDllImport.Unload(); - - EverythingApiDllImport.Load(sdkDirectory); - } - } - } - finally - { - _semaphore.Release(); - } - } - - /// - /// Checks whether the sort option is Fast Sort. - /// - public static bool IsFastSortOption(EverythingSortOption sortOption) + public bool IsFastSortOption(EverythingSortOption sortOption) { - if (EnableEverything15Support) - { - if (!TryConnectEverything3(out var client)) - throw new IPCErrorException(); - - try - { - if (TryConvertSortOption(sortOption, out var propertyId, out _)) - { - var isFastSort = Everything3ApiDllImport.Everything3_IsPropertyFastSort(client, propertyId); - - // Keep the same behavior as legacy path: throw when engine is not available. - CheckAndThrowExceptionOnErrorFromEverything3(); - - return isFastSort; - } - } - finally - { - _ = Everything3ApiDllImport.Everything3_DestroyClient(client); - // Throw again to the caller - CheckAndThrowExceptionOnErrorFromEverything3(); - } - - return true; - } - var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); - - // If the Everything service is not running, then this call will incorrectly report - // the state as false. This checks for errors thrown by the api and up to the caller to handle. CheckAndThrowExceptionOnError(); - return fastSortOptionEnabled; } - public static async ValueTask IsEverythingRunningAsync(CancellationToken token = default) + public async ValueTask IsEverythingRunningAsync(CancellationToken token = default) { try { @@ -133,11 +34,8 @@ public static async ValueTask IsEverythingRunningAsync(CancellationToken t try { - if (EnableEverything15Support) - return TryUseEverything3Client(static _ => { }); - _ = EverythingApiDllImport.Everything_GetMajorVersion(); - return EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; + return EverythingApiDllImport.Everything_GetLastError() != EverythingHelper.StateCode.IPCError; } finally { @@ -145,18 +43,10 @@ public static async ValueTask IsEverythingRunningAsync(CancellationToken t } } - /// - /// Searches the specified key word and reset the everything API afterwards - /// - /// Search Criteria - /// when cancelled the current search will stop and exit (and would not reset) - /// An IAsyncEnumerable that will enumerate all results searched by the specific query and option - public static async IAsyncEnumerable SearchAsync(EverythingSearchOption option, - [EnumeratorCancellation] CancellationToken token) + public async IAsyncEnumerable SearchAsync(EverythingSearchOption option, [EnumeratorCancellation] CancellationToken token = default) { if (option.Offset < 0) throw new ArgumentOutOfRangeException(nameof(option.Offset), option.Offset, "Offset must be greater than or equal to 0"); - if (option.MaxCount < 0) throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0"); @@ -196,33 +86,6 @@ public static async IAsyncEnumerable SearchAsync(EverythingSearchO var searchText = builder.ToString(); - if (EnableEverything15Support) - { - if (!TryConnectEverything3(out var client)) - throw new IPCErrorException(); - - await foreach (var result in SearchWithEverything3Async(client, option, searchText, useRegex, token)) - yield return result; - - yield break; - } - - await foreach (var result in SearchWithEverythingLegacyAsync(option, searchText, useRegex, token)) - yield return result; - } - finally - { - _semaphore.Release(); - } - } - - private static async IAsyncEnumerable SearchWithEverythingLegacyAsync(EverythingSearchOption option, - string searchText, - bool useRegex, - [EnumeratorCancellation] CancellationToken token) - { - try - { EverythingApiDllImport.Everything_SetRegex(useRegex); EverythingApiDllImport.Everything_SetSearchW(searchText); EverythingApiDllImport.Everything_SetOffset(option.Offset); @@ -233,11 +96,11 @@ private static async IAsyncEnumerable SearchWithEverythingLegacyAs if (option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) { - EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT); + EverythingApiDllImport.Everything_SetRequestFlags(0x00000004u | 0x00000400u); } else { - EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME); + EverythingApiDllImport.Everything_SetRequestFlags(0x00000004u); } if (token.IsCancellationRequested) yield break; @@ -264,7 +127,7 @@ private static async IAsyncEnumerable SearchWithEverythingLegacyAs EverythingApiDllImport.Everything_IsFileResult(idx) ? ResultType.File : ResultType.Volume, Score = Convert.ToInt32(EverythingApiDllImport.Everything_GetResultRunCount((uint)idx)), - HighlightData = EverythingHighlightStringToHighlightList(EverythingApiDllImport.Everything_GetResultHighlightedFileName((uint)idx)) + HighlightData = EverythingHelper.EverythingHighlightStringToHighlightList(EverythingApiDllImport.Everything_GetResultHighlightedFileName((uint)idx)) }; yield return result; @@ -273,6 +136,7 @@ private static async IAsyncEnumerable SearchWithEverythingLegacyAs finally { EverythingApiDllImport.Everything_Reset(); + _semaphore.Release(); } await Task.CompletedTask; @@ -282,96 +146,43 @@ private static void CheckAndThrowExceptionOnError() { switch (EverythingApiDllImport.Everything_GetLastError()) { - case StateCode.CreateThreadError: + case EverythingHelper.StateCode.CreateThreadError: throw new CreateThreadException(); - case StateCode.CreateWindowError: + case EverythingHelper.StateCode.CreateWindowError: throw new CreateWindowException(); - case StateCode.InvalidCallError: + case EverythingHelper.StateCode.InvalidCallError: throw new InvalidCallException(); - case StateCode.InvalidIndexError: + case EverythingHelper.StateCode.InvalidIndexError: throw new InvalidIndexException(); - case StateCode.IPCError: + case EverythingHelper.StateCode.IPCError: throw new IPCErrorException(); - case StateCode.MemoryError: + case EverythingHelper.StateCode.MemoryError: throw new MemoryErrorException(); - case StateCode.RegisterClassExError: + case EverythingHelper.StateCode.RegisterClassExError: throw new RegisterClassExException(); - case StateCode.OK: + case EverythingHelper.StateCode.OK: break; default: throw new ArgumentOutOfRangeException(); } } - public static async Task IncrementRunCounterAsync(string fileOrFolder) + public async Task IncrementRunCounterAsync(string fileOrFolder) { await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); try { - if (EnableEverything15Support) - { - _ = TryUseEverything3Client(client => - _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder)); - return; - } - _ = EverythingApiDllImport.Everything_IncRunCountFromFileName(fileOrFolder); } catch (Exception) { /*ignored*/ } - finally { _semaphore.Release(); } - } - - /// - /// Convert the highlighted string from Everything API to a list of highlight indexes for our Result. - /// - /// Text inside a * quote is highlighted, two consecutive *'s is a single literal *. For example, in the highlighted text: abc*123* the 123 part is highlighted. - /// A list of zero-based character indices that should be highlighted. - public static List EverythingHighlightStringToHighlightList(string highlightString) - { - var highlightData = new List(); - - if (string.IsNullOrEmpty(highlightString)) - return highlightData; - - var isHighlighted = false; - var actualIndex = 0; // Index in the actual string (without * markers) - var length = highlightString.Length; - - for (var i = 0; i < length; i++) + finally { - if (highlightString[i] == '*') - { - // Check if it's a literal * (two consecutive *) - if (i + 1 < length && highlightString[i + 1] == '*') - { - // Two consecutive *'s represent a single literal * - if (isHighlighted) - { - highlightData.Add(actualIndex); - } - actualIndex++; - i++; // Skip the next * - } - else - { - isHighlighted = !isHighlighted; - } - } - else - { - // Regular character - if (isHighlighted) - { - highlightData.Add(actualIndex); - } - actualIndex++; - } + _semaphore.Release(); } - - return highlightData; } + } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index 4607badba3f..ad3da871993 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -92,7 +92,7 @@ public static void Unload() internal static extern string Everything_GetSearchW(); [DllImport(DLL)] - internal static extern EverythingApi.StateCode Everything_GetLastError(); + internal static extern EverythingHelper.StateCode Everything_GetLastError(); [DllImport(DLL, CharSet = CharSet.Unicode)] internal static extern bool Everything_QueryW(bool bWait); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs similarity index 72% rename from Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs rename to Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 8f718250397..7f42dfddf7b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.Everything3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -1,14 +1,28 @@ -using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; -using System; +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Text; using System.Threading; using System.Threading.Tasks; +using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; namespace Flow.Launcher.Plugin.Explorer.Search.Everything { - public static partial class EverythingApi + public class EverythingApiV3 : IEverythingApi { + public const string DefaultEverything15InstanceName = "1.5a"; + + private const int BufferSize = 4096; + private static readonly SemaphoreSlim _semaphore = new(1, 1); + private static readonly StringBuilder _buffer = new(BufferSize); + + private readonly string _instanceName; + + public EverythingApiV3(string instanceName) + { + _instanceName = instanceName; + } + const uint EVERYTHING3_PROPERTY_ID_NAME = 0; const uint EVERYTHING3_PROPERTY_ID_PATH = 1; const uint EVERYTHING3_PROPERTY_ID_SIZE = 2; @@ -30,7 +44,124 @@ public static partial class EverythingApi const uint EVERYTHING3_ERROR_INVALID_PARAMETER = 0xE0000004; const uint EVERYTHING3_ERROR_PROPERTY_NOT_FOUND = 0xE0000007; - private static async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, + public async ValueTask IsEverythingRunningAsync(CancellationToken token = default) + { + try + { + await _semaphore.WaitAsync(token); + } + catch (OperationCanceledException) + { + return false; + } + + try + { + return TryUseEverything3Client(static _ => { }); + } + finally + { + _semaphore.Release(); + } + } + + public async IAsyncEnumerable SearchAsync(EverythingSearchOption option, [EnumeratorCancellation] CancellationToken token = default) + { + if (option.Offset < 0) + throw new ArgumentOutOfRangeException(nameof(option.Offset), option.Offset, "Offset must be greater than or equal to 0"); + if (option.MaxCount < 0) + throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0"); + + try + { + await _semaphore.WaitAsync(token); + } + catch (OperationCanceledException) + { + yield break; + } + + try + { + if (token.IsCancellationRequested) + yield break; + + var useRegex = false; + if (option.Keyword.StartsWith("@")) + { + useRegex = true; + option.Keyword = option.Keyword[1..]; + } + + var builder = new StringBuilder(); + builder.Append(option.Keyword); + + if (!string.IsNullOrWhiteSpace(option.ParentPath)) + { + builder.Append($" {(option.IsRecursive ? "" : "parent:")}\"{option.ParentPath}\""); + } + + if (option.IsContentSearch) + { + builder.Append($" content:\"{option.ContentSearchKeyword}\""); + } + + var searchText = builder.ToString(); + + if (!TryConnectEverything3(out var client)) + throw new IPCErrorException(); + + await foreach (var result in SearchWithEverything3Async(client, option, searchText, useRegex, token)) + yield return result; + } + finally + { + _semaphore.Release(); + } + } + + public async Task IncrementRunCounterAsync(string fileOrFolder) + { + await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); + try + { + _ = TryUseEverything3Client(client => + _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder)); + } + catch (Exception) + { + /*ignored*/ + } + finally + { + _semaphore.Release(); + } + } + + public bool IsFastSortOption(EverythingSortOption sortOption) + { + if (!TryConnectEverything3(out var client)) + throw new IPCErrorException(); + + try + { + if (TryConvertSortOption(sortOption, out var propertyId, out _)) + { + var isFastSort = Everything3ApiDllImport.Everything3_IsPropertyFastSort(client, propertyId); + CheckAndThrowExceptionOnErrorFromEverything3(); + return isFastSort; + } + } + finally + { + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + CheckAndThrowExceptionOnErrorFromEverything3(); + } + + return true; + } + + private async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, EverythingSearchOption option, string searchText, bool useRegex, @@ -62,7 +193,6 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); - // Everything3_GetResultFullPathNameW requires PATH_AND_NAME to be requested _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_RUN_COUNT); @@ -84,15 +214,15 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I yield break; } - buffer.Clear(); - var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, buffer, BufferSize); + _buffer.Clear(); + var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, _buffer, BufferSize); if (fullPathLength == 0) { CheckAndThrowExceptionOnErrorFromEverything3(); continue; } - var fullPath = buffer.ToString(); + var fullPath = _buffer.ToString(); if (string.IsNullOrEmpty(fullPath)) { continue; @@ -109,20 +239,19 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)) }; - // 0 for the first requested property, which is name in our case. if (Everything3ApiDllImport.Everything3_GetSearchPropertyRequestHighlight(searchState, 0)) { - buffer.Clear(); + _buffer.Clear(); var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( resultList, idx, EVERYTHING3_PROPERTY_ID_NAME, - buffer, + _buffer, BufferSize); if (highlightedFileNameLength > 0) { - var highlightData = EverythingHighlightStringToHighlightList(buffer.ToString()); + var highlightData = EverythingHelper.EverythingHighlightStringToHighlightList(_buffer.ToString()); if (highlightData.Count > 0) { result = result with @@ -150,7 +279,7 @@ private static async IAsyncEnumerable SearchWithEverything3Async(I await Task.CompletedTask; } - private static bool TryUseEverything3Client(Action action) + private bool TryUseEverything3Client(Action action) { if (!TryConnectEverything3(out var client)) return false; @@ -166,16 +295,16 @@ private static bool TryUseEverything3Client(Action action) } } - private static bool TryConnectEverything3(out IntPtr client) + private bool TryConnectEverything3(out IntPtr client) { client = IntPtr.Zero; - if (!EnableEverything15Support) - return false; - try { - client = Everything3ApiDllImport.Everything3_ConnectW(Everything15InstanceName); + var normalizedInstanceName = string.IsNullOrWhiteSpace(_instanceName) + ? DefaultEverything15InstanceName + : _instanceName.Trim(); + client = Everything3ApiDllImport.Everything3_ConnectW(normalizedInstanceName); return client != IntPtr.Zero; } catch (DllNotFoundException) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs new file mode 100644 index 00000000000..8f8db86b5c6 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + public static class EverythingHelper + { + public enum StateCode + { + OK, + MemoryError, + IPCError, + RegisterClassExError, + CreateWindowError, + CreateThreadError, + InvalidIndexError, + InvalidCallError + } + + /// + /// Convert the highlighted string from Everything API to a list of highlight indexes for our Result. + /// + /// Text inside a * quote is highlighted, two consecutive *'s is a single literal *. For example, in the highlighted text: abc*123* the 123 part is highlighted. + /// A list of zero-based character indices that should be highlighted. + public static List EverythingHighlightStringToHighlightList(string highlightString) + { + var highlightData = new List(); + + if (string.IsNullOrEmpty(highlightString)) + return highlightData; + + var isHighlighted = false; + var actualIndex = 0; // Index in the actual string (without * markers) + var length = highlightString.Length; + + for (var i = 0; i < length; i++) + { + if (highlightString[i] == '*') + { + // Check if it's a literal * (two consecutive *) + if (i + 1 < length && highlightString[i + 1] == '*') + { + // Two consecutive *'s represent a single literal * + if (isHighlighted) + { + highlightData.Add(actualIndex); + } + actualIndex++; + i++; // Skip the next * + } + else + { + isHighlighted = !isHighlighted; + } + } + else + { + // Regular character + if (isHighlighted) + { + highlightData.Add(actualIndex); + } + actualIndex++; + } + } + + return highlightData; + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index eb994a6f98f..7404e1a0ed5 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -12,19 +12,24 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IPathIndexProvider { private static readonly string ClassName = nameof(EverythingSearchManager); + private static readonly SemaphoreSlim _dllSemaphore = new(1, 1); + private static volatile bool _dllLoadedForSdk3 = true; private Settings Settings { get; } + private readonly Lock _syncRoot = new(); + private IEverythingApi _api; public EverythingSearchManager(Settings settings) { Settings = settings; + _api = CreateApi(Settings.EnableEverything15Support, GetNormalizedInstanceName(Settings.Everything15InstanceName)); } private async ValueTask ThrowIfEverythingNotAvailableAsync(CancellationToken token = default) { try { - if (!await EverythingApi.IsEverythingRunningAsync(token)) + if (!await _api.IsEverythingRunningAsync(token)) throw new EngineNotAvailableException( Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, Localize.flowlauncher_plugin_everything_click_to_launch_or_install(), @@ -85,7 +90,7 @@ public async IAsyncEnumerable SearchAsync(string search, [Enumerat IsFullPathSearch: Settings.EverythingSearchFullPath, IsRunCounterEnabled: Settings.EverythingEnableRunCount); - await foreach (var result in EverythingApi.SearchAsync(option, token)) + await foreach (var result in _api.SearchAsync(option, token)) yield return result; } @@ -119,7 +124,7 @@ public async IAsyncEnumerable ContentSearchAsync(string plainSearc IsFullPathSearch: Settings.EverythingSearchFullPath, IsRunCounterEnabled: Settings.EverythingEnableRunCount); - await foreach (var result in EverythingApi.SearchAsync(option, token)) + await foreach (var result in _api.SearchAsync(option, token)) { yield return result; } @@ -140,8 +145,66 @@ public async IAsyncEnumerable EnumerateAsync(string path, string s IsFullPathSearch: Settings.EverythingSearchFullPath, IsRunCounterEnabled: Settings.EverythingEnableRunCount); - await foreach (var result in EverythingApi.SearchAsync(option, token)) + await foreach (var result in _api.SearchAsync(option, token)) yield return result; } + public void ReloadApi(string sdkDirectory) + { + lock (_syncRoot) + { + LoadDllCore(Settings.EnableEverything15Support, sdkDirectory); + _api = CreateApi(Settings.EnableEverything15Support, GetNormalizedInstanceName(Settings.Everything15InstanceName)); + } + } + + public bool IsFastSortOption(EverythingSortOption sortOption) => _api.IsFastSortOption(sortOption); + + public Task IncrementRunCounterAsync(string fileOrFolder) => _api.IncrementRunCounterAsync(fileOrFolder); + + private static void LoadDllCore(bool enableEverything15Support, string sdkDirectory) + { + _dllSemaphore.Wait(); + try + { + var supportChanged = _dllLoadedForSdk3 != enableEverything15Support; + _dllLoadedForSdk3 = enableEverything15Support; + + if (enableEverything15Support) + { + if (supportChanged || !Everything3ApiDllImport.IsLoaded) + { + if (EverythingApiDllImport.IsLoaded) + EverythingApiDllImport.Unload(); + + Everything3ApiDllImport.Load(sdkDirectory); + } + } + else + { + if (supportChanged || !EverythingApiDllImport.IsLoaded) + { + if (Everything3ApiDllImport.IsLoaded) + Everything3ApiDllImport.Unload(); + + EverythingApiDllImport.Load(sdkDirectory); + } + } + } + finally + { + _dllSemaphore.Release(); + } + } + + private static string GetNormalizedInstanceName(string instanceName) => string.IsNullOrWhiteSpace(instanceName) + ? EverythingApiV3.DefaultEverything15InstanceName + : instanceName.Trim(); + + private static IEverythingApi CreateApi(bool enableEverything15Support, string instanceName) + { + return enableEverything15Support + ? new EverythingApiV3(instanceName) + : new LegacyEverythingApi(); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/IEverythingApi.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/IEverythingApi.cs new file mode 100644 index 00000000000..3c7ed7e896a --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/IEverythingApi.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + public interface IEverythingApi + { + ValueTask IsEverythingRunningAsync(CancellationToken token = default); + IAsyncEnumerable SearchAsync(EverythingSearchOption option, CancellationToken token = default); + Task IncrementRunCounterAsync(string fileOrFolder); + bool IsFastSortOption(EverythingSortOption sortOption); + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index b73a59bcdc1..176c7eeaef4 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -412,8 +412,9 @@ private static void OpenFolder(string folderPath, string fileNameOrFilePath = nu private static void IncrementEverythingRunCounterIfNeeded(string fileOrFolder) { + // What if result is not from everything or even not indexed in Everything? if (Settings.EverythingEnabled && Settings.EverythingEnableRunCount) - _ = Task.Run(() => EverythingApi.IncrementRunCounterAsync(fileOrFolder)); + _ = Task.Run(() => Settings.EverythingManagerInstance.IncrementRunCounterAsync(fileOrFolder)); } private static string GetFileMoreInfoTooltip(string filePath) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 5ecfaa7c66c..acb39b31412 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -89,7 +89,7 @@ public class Settings #region SearchEngine - private EverythingSearchManager EverythingManagerInstance => _everythingManagerInstance ??= new EverythingSearchManager(this); + internal EverythingSearchManager EverythingManagerInstance => _everythingManagerInstance ??= new EverythingSearchManager(this); private WindowsIndexSearchManager WindowsIndexSearchManager => _windowsIndexSearchManager ??= new WindowsIndexSearchManager(this); public IndexSearchEngineOption IndexSearchEngine { get; set; } = IndexSearchEngineOption.WindowsIndex; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index de28ceb9255..a5d1c4781bd 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -619,7 +619,7 @@ public Visibility FastSortWarningVisibility { try { - return EverythingApi.IsFastSortOption(Settings.SortOption) ? Visibility.Collapsed : Visibility.Visible; + return Settings.EverythingManagerInstance.IsFastSortOption(Settings.SortOption) ? Visibility.Collapsed : Visibility.Visible; } catch (IPCErrorException) { @@ -642,7 +642,7 @@ public string SortOptionWarningMessage { // this method is used to determine if Everything service is running because as at Everything v1.4.1 // the sdk does not provide a dedicated interface to determine if it is running. - return EverythingApi.IsFastSortOption(Settings.SortOption) ? string.Empty + return Settings.EverythingManagerInstance.IsFastSortOption(Settings.SortOption) ? string.Empty : Localize.flowlauncher_plugin_everything_nonfastsort_warning(); } catch (IPCErrorException) @@ -678,7 +678,7 @@ public bool EnableEverything15Support var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86"); - EverythingApi.ConfigureEverythingSupport(value, sdkDirectory, Settings.Everything15InstanceName); + Settings.EverythingManagerInstance.ReloadApi(sdkDirectory); OnPropertyChanged(); OnPropertyChanged(nameof(FastSortWarningVisibility)); @@ -692,7 +692,7 @@ public string Everything15InstanceName set { var instanceName = string.IsNullOrWhiteSpace(value) - ? EverythingApi.DefaultEverything15InstanceName + ? EverythingApiV3.DefaultEverything15InstanceName : value.Trim(); if (Settings.Everything15InstanceName == instanceName) @@ -704,7 +704,7 @@ public string Everything15InstanceName { var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86"); - EverythingApi.ConfigureEverythingSupport(true, sdkDirectory, instanceName); + Settings.EverythingManagerInstance.ReloadApi(sdkDirectory); OnPropertyChanged(nameof(FastSortWarningVisibility)); OnPropertyChanged(nameof(SortOptionWarningMessage)); } From 96b666473a1bf6a83a82b67017b1bb76f992ef4a Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 11:32:36 +0800 Subject: [PATCH 15/29] Fix default everything instance name --- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index acb39b31412..eb02ec26967 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -164,7 +164,7 @@ public enum ContentIndexSearchEngineOption public bool EverythingSearchFullPath { get; set; } = false; public bool EverythingEnableRunCount { get; set; } = true; public bool EnableEverything15Support { get; set; } = false; - public string Everything15InstanceName { get; set; } = EverythingApi.DefaultEverything15InstanceName; + public string Everything15InstanceName { get; set; } = EverythingApiV3.DefaultEverything15InstanceName; #endregion From 4db9d67fe3697354514c7c6ba6a4f743132711ee Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 12:17:48 +0800 Subject: [PATCH 16/29] Handle the timeout result from WaitAsync(TimeSpan) before releasing the semaphore --- .../Search/Everything/EverythingAPI.cs | 56 ++++++++++++++++++- .../Search/Everything/EverythingApiV3.cs | 10 +++- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 6ecd4b3d0c0..f6c57b27b17 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -169,7 +169,12 @@ private static void CheckAndThrowExceptionOnError() public async Task IncrementRunCounterAsync(string fileOrFolder) { - await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); + var _entered = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); + if (!_entered) + { + // If we can't acquire the semaphore within the timeout, we skip incrementing the run count to avoid blocking. + return; + } try { _ = EverythingApiDllImport.Everything_IncRunCountFromFileName(fileOrFolder); @@ -179,10 +184,57 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) /*ignored*/ } finally - { + { _semaphore.Release(); } } + /// + /// Convert the highlighted string from Everything API to a list of highlight indexes for our Result. + /// + /// Text inside a * quote is highlighted, two consecutive *'s is a single literal *. For example, in the highlighted text: abc*123* the 123 part is highlighted. + /// A list of zero-based character indices that should be highlighted. + public static List EverythingHighlightStringToHighlightList(string highlightString) + { + var highlightData = new List(); + + if (string.IsNullOrEmpty(highlightString)) + return highlightData; + + var isHighlighted = false; + var actualIndex = 0; // Index in the actual string (without * markers) + var length = highlightString.Length; + + for (var i = 0; i < length; i++) + { + if (highlightString[i] == '*') + { + // Check if it's a literal * (two consecutive *) + if (i + 1 < length && highlightString[i + 1] == '*') + { + // Two consecutive *'s represent a single literal * + if (isHighlighted) + { + highlightData.Add(actualIndex); + } + actualIndex++; + i++; // Skip the next * + } + else + { + isHighlighted = !isHighlighted; + } + } + else + { + // Regular character + if (isHighlighted) + { + highlightData.Add(actualIndex); + } + actualIndex++; + } + } + } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 7f42dfddf7b..22ccd42ba09 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -122,11 +122,15 @@ public async IAsyncEnumerable SearchAsync(EverythingSearchOption o public async Task IncrementRunCounterAsync(string fileOrFolder) { - await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); + var _entered = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); + if (!_entered) + { + // If we can't acquire the semaphore within the timeout, we skip incrementing the run count to avoid blocking. + return; + } try { - _ = TryUseEverything3Client(client => - _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder)); + _ = TryUseEverything3Client(client => _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder)); } catch (Exception) { From 5fa18c8527929241af583629d02fef77614a6911 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 14:49:56 +0800 Subject: [PATCH 17/29] Stop dynamically loading Everything SDK --- .../Languages/en.xaml | 7 +-- Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 2 +- .../Everything/Everything3ApiDllImport.cs | 17 ------- .../Search/Everything/EverythingAPI.cs | 48 ----------------- .../Everything/EverythingApiDllImport.cs | 18 ------- .../Everything/EverythingSearchManager.cs | 51 +++++++++---------- .../ViewModels/SettingsViewModel.cs | 7 --- 7 files changed, 28 insertions(+), 122 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index a0cd5316549..3d162b0d410 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -1,4 +1,4 @@ - @@ -44,7 +44,7 @@ Date and time format Sort Option: Everything Path: - Everything 1.5 instance name: + Everything 1.5 instance name (requires app restart): Launch Hidden Editor Path Shell Path @@ -187,7 +187,7 @@ Search Full Path Enable File/Folder Run Count - Enable Everything 1.5 support + Use Everything 1.5 (requires app restart) Click to launch or install Everything Everything Installation @@ -216,3 +216,4 @@ 1 year ago {0} years ago + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index d872ae22b1f..f23f897ee2f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -48,7 +48,7 @@ public Task InitAsync(PluginInitContext context) var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86"); - Settings.EverythingManagerInstance.ReloadApi(sdkDirectory); + Settings.EverythingManagerInstance.InitializeApi(sdkDirectory); return Task.CompletedTask; } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs index 9844330750c..5e24d7298a4 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Everything3ApiDllImport.cs @@ -26,26 +26,9 @@ public static void Load(string directory) } } - public static void Unload() - { - if (_dllHandle == IntPtr.Zero) - { - return; - } - if (!FreeLibrary(_dllHandle)) - { - throw new Win32Exception(Marshal.GetLastPInvokeError()); - } - _dllHandle = IntPtr.Zero; - } - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibrary(string name); - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool FreeLibrary(IntPtr hModule); - private const string Dll = "Everything3.dll"; [DllImport(Dll, CharSet = CharSet.Unicode)] diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index f6c57b27b17..681333f4a21 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -188,53 +188,5 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) _semaphore.Release(); } } - - /// - /// Convert the highlighted string from Everything API to a list of highlight indexes for our Result. - /// - /// Text inside a * quote is highlighted, two consecutive *'s is a single literal *. For example, in the highlighted text: abc*123* the 123 part is highlighted. - /// A list of zero-based character indices that should be highlighted. - public static List EverythingHighlightStringToHighlightList(string highlightString) - { - var highlightData = new List(); - - if (string.IsNullOrEmpty(highlightString)) - return highlightData; - - var isHighlighted = false; - var actualIndex = 0; // Index in the actual string (without * markers) - var length = highlightString.Length; - - for (var i = 0; i < length; i++) - { - if (highlightString[i] == '*') - { - // Check if it's a literal * (two consecutive *) - if (i + 1 < length && highlightString[i + 1] == '*') - { - // Two consecutive *'s represent a single literal * - if (isHighlighted) - { - highlightData.Add(actualIndex); - } - actualIndex++; - i++; // Skip the next * - } - else - { - isHighlighted = !isHighlighted; - } - } - else - { - // Regular character - if (isHighlighted) - { - highlightData.Add(actualIndex); - } - actualIndex++; - } - } - } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index ad3da871993..1191c07d281 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -26,27 +26,9 @@ public static void Load(string directory) } } - public static void Unload() - { - if (_dllHandle == IntPtr.Zero) - { - return; - } - - if (!FreeLibrary(_dllHandle)) - { - throw new Win32Exception(Marshal.GetLastPInvokeError()); - } - _dllHandle = IntPtr.Zero; - } - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibrary(string name); - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool FreeLibrary(IntPtr hModule); - private const string DLL = "Everything.dll"; [DllImport(DLL, CharSet = CharSet.Unicode)] diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index 7404e1a0ed5..4bdde287a1b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -13,23 +13,27 @@ public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IP { private static readonly string ClassName = nameof(EverythingSearchManager); private static readonly SemaphoreSlim _dllSemaphore = new(1, 1); - private static volatile bool _dllLoadedForSdk3 = true; private Settings Settings { get; } + private readonly bool useV3Api; + private readonly string everything15InstanceName; private readonly Lock _syncRoot = new(); - private IEverythingApi _api; + private bool isApiInitialized; + private IEverythingApi api; public EverythingSearchManager(Settings settings) { Settings = settings; - _api = CreateApi(Settings.EnableEverything15Support, GetNormalizedInstanceName(Settings.Everything15InstanceName)); + useV3Api = Settings.EnableEverything15Support; + everything15InstanceName = Settings.Everything15InstanceName; + api = CreateApi(useV3Api, GetNormalizedInstanceName(everything15InstanceName)); } private async ValueTask ThrowIfEverythingNotAvailableAsync(CancellationToken token = default) { try { - if (!await _api.IsEverythingRunningAsync(token)) + if (!await api.IsEverythingRunningAsync(token)) throw new EngineNotAvailableException( Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, Localize.flowlauncher_plugin_everything_click_to_launch_or_install(), @@ -90,7 +94,7 @@ public async IAsyncEnumerable SearchAsync(string search, [Enumerat IsFullPathSearch: Settings.EverythingSearchFullPath, IsRunCounterEnabled: Settings.EverythingEnableRunCount); - await foreach (var result in _api.SearchAsync(option, token)) + await foreach (var result in api.SearchAsync(option, token)) yield return result; } @@ -124,7 +128,7 @@ public async IAsyncEnumerable ContentSearchAsync(string plainSearc IsFullPathSearch: Settings.EverythingSearchFullPath, IsRunCounterEnabled: Settings.EverythingEnableRunCount); - await foreach (var result in _api.SearchAsync(option, token)) + await foreach (var result in api.SearchAsync(option, token)) { yield return result; } @@ -145,49 +149,40 @@ public async IAsyncEnumerable EnumerateAsync(string path, string s IsFullPathSearch: Settings.EverythingSearchFullPath, IsRunCounterEnabled: Settings.EverythingEnableRunCount); - await foreach (var result in _api.SearchAsync(option, token)) + await foreach (var result in api.SearchAsync(option, token)) yield return result; } - public void ReloadApi(string sdkDirectory) + public void InitializeApi(string sdkDirectory) { lock (_syncRoot) { - LoadDllCore(Settings.EnableEverything15Support, sdkDirectory); - _api = CreateApi(Settings.EnableEverything15Support, GetNormalizedInstanceName(Settings.Everything15InstanceName)); + if (isApiInitialized) + return; + + LoadConfiguredDll(sdkDirectory, useV3Api); + api = CreateApi(useV3Api, GetNormalizedInstanceName(Settings.Everything15InstanceName)); + isApiInitialized = true; } } - public bool IsFastSortOption(EverythingSortOption sortOption) => _api.IsFastSortOption(sortOption); + public bool IsFastSortOption(EverythingSortOption sortOption) => api.IsFastSortOption(sortOption); - public Task IncrementRunCounterAsync(string fileOrFolder) => _api.IncrementRunCounterAsync(fileOrFolder); + public Task IncrementRunCounterAsync(string fileOrFolder) => api.IncrementRunCounterAsync(fileOrFolder); - private static void LoadDllCore(bool enableEverything15Support, string sdkDirectory) + private static void LoadConfiguredDll(string sdkDirectory, bool enableEverything15Support) { _dllSemaphore.Wait(); try { - var supportChanged = _dllLoadedForSdk3 != enableEverything15Support; - _dllLoadedForSdk3 = enableEverything15Support; - if (enableEverything15Support) { - if (supportChanged || !Everything3ApiDllImport.IsLoaded) - { - if (EverythingApiDllImport.IsLoaded) - EverythingApiDllImport.Unload(); - + if (!Everything3ApiDllImport.IsLoaded) Everything3ApiDllImport.Load(sdkDirectory); - } } else { - if (supportChanged || !EverythingApiDllImport.IsLoaded) - { - if (Everything3ApiDllImport.IsLoaded) - Everything3ApiDllImport.Unload(); - + if (!EverythingApiDllImport.IsLoaded) EverythingApiDllImport.Load(sdkDirectory); - } } } finally diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index a5d1c4781bd..cf47dfe1a32 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -676,10 +676,6 @@ public bool EnableEverything15Support Settings.EnableEverything15Support = value; - var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", - Environment.Is64BitProcess ? "x64" : "x86"); - Settings.EverythingManagerInstance.ReloadApi(sdkDirectory); - OnPropertyChanged(); OnPropertyChanged(nameof(FastSortWarningVisibility)); OnPropertyChanged(nameof(SortOptionWarningMessage)); @@ -702,9 +698,6 @@ public string Everything15InstanceName if (EnableEverything15Support) { - var sdkDirectory = Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", - Environment.Is64BitProcess ? "x64" : "x86"); - Settings.EverythingManagerInstance.ReloadApi(sdkDirectory); OnPropertyChanged(nameof(FastSortWarningVisibility)); OnPropertyChanged(nameof(SortOptionWarningMessage)); } From 7254dc0bc155b3d2a3dba49f9d2eec53adf9595b Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:03:58 +0800 Subject: [PATCH 18/29] Clean code and revert useless changes --- .../Search/Everything/EverythingAPI.cs | 25 +++++++++++++------ .../Search/ResultManager.cs | 1 - 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 681333f4a21..afb940621f5 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -12,10 +12,19 @@ public class LegacyEverythingApi : IEverythingApi { private const int BufferSize = 4096; private static readonly SemaphoreSlim _semaphore = new(1, 1); + // cached buffer to remove redundant allocations. private static readonly StringBuilder buffer = new(BufferSize); + const uint EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004u; + const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u; + + /// + /// Checks whether the sort option is Fast Sort. + /// public bool IsFastSortOption(EverythingSortOption sortOption) { + // If the Everything service is not running, then this call will incorrectly report + // the state as false. This checks for errors thrown by the api and up to the caller to handle. var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); CheckAndThrowExceptionOnError(); return fastSortOptionEnabled; @@ -43,6 +52,12 @@ public async ValueTask IsEverythingRunningAsync(CancellationToken token = } } + /// + /// Searches using the specified criteria and resets the Everything API afterwards. + /// + /// The search criteria. + /// A cancellation token that stops the current search when cancellation is requested. + /// An asynchronous sequence of search results that match the specified criteria. public async IAsyncEnumerable SearchAsync(EverythingSearchOption option, [EnumeratorCancellation] CancellationToken token = default) { if (option.Offset < 0) @@ -84,10 +99,8 @@ public async IAsyncEnumerable SearchAsync(EverythingSearchOption o builder.Append($" content:\"{option.ContentSearchKeyword}\""); } - var searchText = builder.ToString(); - EverythingApiDllImport.Everything_SetRegex(useRegex); - EverythingApiDllImport.Everything_SetSearchW(searchText); + EverythingApiDllImport.Everything_SetSearchW(builder.ToString()); EverythingApiDllImport.Everything_SetOffset(option.Offset); EverythingApiDllImport.Everything_SetMax(option.MaxCount); @@ -96,11 +109,11 @@ public async IAsyncEnumerable SearchAsync(EverythingSearchOption o if (option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) { - EverythingApiDllImport.Everything_SetRequestFlags(0x00000004u | 0x00000400u); + EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT); } else { - EverythingApiDllImport.Everything_SetRequestFlags(0x00000004u); + EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME); } if (token.IsCancellationRequested) yield break; @@ -138,8 +151,6 @@ public async IAsyncEnumerable SearchAsync(EverythingSearchOption o EverythingApiDllImport.Everything_Reset(); _semaphore.Release(); } - - await Task.CompletedTask; } private static void CheckAndThrowExceptionOnError() diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index 176c7eeaef4..7845498a963 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -412,7 +412,6 @@ private static void OpenFolder(string folderPath, string fileNameOrFilePath = nu private static void IncrementEverythingRunCounterIfNeeded(string fileOrFolder) { - // What if result is not from everything or even not indexed in Everything? if (Settings.EverythingEnabled && Settings.EverythingEnableRunCount) _ = Task.Run(() => Settings.EverythingManagerInstance.IncrementRunCounterAsync(fileOrFolder)); } From 01e66975171da5316641cb0ea8d414b9e203ba59 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:14:33 +0800 Subject: [PATCH 19/29] update expected text --- .github/actions/spelling/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 81b9aba97e7..fe2b8a73553 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -108,3 +108,4 @@ Msix dummyprofile browserbookmark copyurl +PInvoke From a78397d2f250a19f1e14c51d19c3c2456829c9b0 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:22:27 +0800 Subject: [PATCH 20/29] Revert unnecessary changes --- .../Search/Everything/EverythingAPI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index afb940621f5..d6c8fd8fbbc 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -23,9 +23,9 @@ public class LegacyEverythingApi : IEverythingApi /// public bool IsFastSortOption(EverythingSortOption sortOption) { + var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); // If the Everything service is not running, then this call will incorrectly report // the state as false. This checks for errors thrown by the api and up to the caller to handle. - var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); CheckAndThrowExceptionOnError(); return fastSortOptionEnabled; } From 5a6a46163aa32805134ffb1e605e3374f7eaebef Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:27:48 +0800 Subject: [PATCH 21/29] Throw error on add sort option fails --- .../Search/Everything/EverythingApiV3.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 22ccd42ba09..552358a445e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -191,10 +191,14 @@ private async IAsyncEnumerable SearchWithEverything3Async(IntPtr c if (TryConvertSortOption(option.SortOption, out var sortPropertyId, out var ascending)) { - _ = Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending); + if (!Everything3ApiDllImport.Everything3_AddSearchSort(searchState, sortPropertyId, ascending)) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + yield break; + } } - _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); + _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); From 825674fb95f0e63292c7418178e972affac42a30 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 01:11:09 +0800 Subject: [PATCH 22/29] Move default alpha instance name to Everything Search Manager --- .../Search/Everything/EverythingApiV3.cs | 2 -- .../Search/Everything/EverythingSearchManager.cs | 3 ++- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- .../ViewModels/SettingsViewModel.cs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 552358a445e..db74746822a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -10,8 +10,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public class EverythingApiV3 : IEverythingApi { - public const string DefaultEverything15InstanceName = "1.5a"; - private const int BufferSize = 4096; private static readonly SemaphoreSlim _semaphore = new(1, 1); private static readonly StringBuilder _buffer = new(BufferSize); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index 4bdde287a1b..c0277c588aa 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -20,6 +20,7 @@ public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IP private readonly Lock _syncRoot = new(); private bool isApiInitialized; private IEverythingApi api; + public const string DefaultEverything15InstanceName = "1.5a"; public EverythingSearchManager(Settings settings) { @@ -192,7 +193,7 @@ private static void LoadConfiguredDll(string sdkDirectory, bool enableEverything } private static string GetNormalizedInstanceName(string instanceName) => string.IsNullOrWhiteSpace(instanceName) - ? EverythingApiV3.DefaultEverything15InstanceName + ? DefaultEverything15InstanceName : instanceName.Trim(); private static IEverythingApi CreateApi(bool enableEverything15Support, string instanceName) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index eb02ec26967..0cd37feb478 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -164,7 +164,7 @@ public enum ContentIndexSearchEngineOption public bool EverythingSearchFullPath { get; set; } = false; public bool EverythingEnableRunCount { get; set; } = true; public bool EnableEverything15Support { get; set; } = false; - public string Everything15InstanceName { get; set; } = EverythingApiV3.DefaultEverything15InstanceName; + public string Everything15InstanceName { get; set; } = EverythingSearchManager.DefaultEverything15InstanceName; #endregion diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index cf47dfe1a32..a16f0bb55b8 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -688,7 +688,7 @@ public string Everything15InstanceName set { var instanceName = string.IsNullOrWhiteSpace(value) - ? EverythingApiV3.DefaultEverything15InstanceName + ? EverythingSearchManager.DefaultEverything15InstanceName : value.Trim(); if (Settings.Everything15InstanceName == instanceName) From ba2e8bd8fbe2923d222e157e391595ae57d1ff61 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 13:06:21 +0800 Subject: [PATCH 23/29] Refactor EverythingSearchManager --- .../Everything-1.5-architecture-plan.md | 252 ++++++++++++++++++ .../Search/Everything/EverythingApiFactory.cs | 22 ++ .../Search/Everything/EverythingApiV3.cs | 2 +- .../EverythingAvailabilityService.cs | 68 +++++ .../Search/Everything/EverythingSdkLoader.cs | 31 +++ .../Everything/EverythingSearchManager.cs | 110 +------- .../Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- .../ViewModels/SettingsViewModel.cs | 2 +- 8 files changed, 386 insertions(+), 103 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiFactory.cs create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs create mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSdkLoader.cs diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md b/Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md new file mode 100644 index 00000000000..a0996e72cea --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md @@ -0,0 +1,252 @@ +# Everything 1.5 SDK 架构实施计划 + +本文聚焦前一轮 review 中的第 3、4、5 点: +- `EverythingSearchManager` 职责过多 +- V1/V3 搜索流程重复,容易漂移 +- V3 错误模型过于扁平 + +## 3. `EverythingSearchManager` 职责拆分计划 + +### 目标 +把当前 `EverythingSearchManager` 中的工厂、运行时初始化、可用性探测、安装引导、Provider 适配几类职责拆开,降低后续维护成本。 + +### 当前问题 +`EverythingSearchManager` 同时负责: +- 选择 `LegacyEverythingApi` / `EverythingApiV3` +- 加载 `Everything.dll` / `Everything3.dll` +- 检测 Everything 是否可连接 +- 处理“未安装/未启动”的用户提示与安装引导 +- 对外实现 `IIndexProvider` / `IContentIndexProvider` / `IPathIndexProvider` + +这会导致任何 SDK 演进都集中修改一个类。 + +### 拆分方案 + +#### 3.1 引入 `EverythingApiFactory` +职责: +- 根据设置决定创建 `LegacyEverythingApi` 还是 `EverythingApiV3` +- 统一实例名规范化逻辑 + +建议接口: +- `IEverythingApi Create(Settings settings)` + +迁移内容: +- 从 `EverythingSearchManager` 中移出: + - `CreateApi(...)` + - `GetNormalizedInstanceName(...)` + +#### 3.2 引入 `EverythingSdkLoader` +职责: +- 负责 native DLL 的一次性加载 +- 隐藏 `EverythingApiDllImport.Load(...)` / `Everything3ApiDllImport.Load(...)` 细节 +- 维护线程安全 + +建议接口: +- `void EnsureLoaded(string sdkDirectory, bool useV3Api)` + +迁移内容: +- 从 `EverythingSearchManager` 中移出: + - `_dllSemaphore` + - `LoadConfiguredDll(...)` + +#### 3.3 引入 `EverythingAvailabilityService` +职责: +- 负责“是否可用”的判定 +- 根据异常类型生成统一的可用性错误 +- 保留安装/启动引导逻辑 + +建议接口: +- `ValueTask EnsureAvailableAsync(IEverythingApi api, Settings settings, CancellationToken token = default)` + +迁移内容: +- 从 `EverythingSearchManager` 中移出: + - `ThrowIfEverythingNotAvailableAsync(...)` + - `ClickToInstallEverythingAsync(...)` + +#### 3.4 缩减 `EverythingSearchManager` +保留职责: +- 组装 `EverythingSearchOption` +- 调用 `api.SearchAsync(...)` +- 作为 Explorer 插件内的 Everything Provider 门面 + +最终效果: +- `EverythingSearchManager` 更接近应用层协调器 +- SDK、运行时、错误与 UX 引导分别归位 + +### 落地步骤 +1. 新建 `EverythingApiFactory` +2. 新建 `EverythingSdkLoader` +3. 新建 `EverythingAvailabilityService` +4. 让 `EverythingSearchManager` 通过这些组件完成现有逻辑 +5. 保持外部调用接口不变,避免影响 `Settings` / `SearchManager` + +### 验收标准 +- `EverythingSearchManager` 文件长度和私有职责显著减少 +- DLL 加载和 API 创建不再散落在 manager 中 +- 可用性判断逻辑有独立入口 +- `SearchManager` 和 UI 层无须理解 SDK 版本差异 + +--- + +## 4. V1/V3 搜索流程去重计划 + +### 目标 +提取 Everything 1.4 与 1.5 共用的查询构造和结果映射逻辑,避免双实现长期漂移。 + +### 当前重复点 +`LegacyEverythingApi.SearchAsync(...)` 与 `EverythingApiV3.SearchAsync(...)` 目前重复了以下逻辑: +- `Offset` / `MaxCount` 参数校验 +- `@` 前缀触发 regex +- 关键字、父路径、content search 的查询字符串拼接 +- 部分 cancellation 入口 +- `SearchResult` 组装思路 + +### 拆分方案 + +#### 4.1 引入 `EverythingQueryBuilder` +职责: +- 接收 `EverythingSearchOption` +- 输出标准化查询描述 + +建议输出模型: +- `SearchText` +- `UseRegex` + +建议类型: +- `EverythingPreparedQuery` +- `EverythingQueryBuilder` + +示例职责边界: +- 校验 `Offset` / `MaxCount` +- 处理 `@` 前缀 +- 构建最终 search text +- 不触碰任何 native API + +#### 4.2 引入 `EverythingResultMapper` +职责: +- 统一把 native SDK 返回值映射成 `SearchResult` +- 统一 highlight 字符串转换入口 + +说明: +- V1/V3 的底层字段读取方式不同,不强行抽象整个 native 读取过程 +- 但可把“构建 `SearchResult` 的约定”收敛起来 + +可拆分成两层: +- 共用层:`CreateResult(string fullPath, ResultType type, int score, List highlightData)` +- SDK 适配层:各自读取 full path / run count / highlight text + +#### 4.3 保留各 SDK 的最小差异面 +`LegacyEverythingApi` 保留: +- V1 专属 request flags +- `Everything_Reset()` 生命周期 +- V1 的 native 错误检查 + +`EverythingApiV3` 保留: +- search state / result list / client 生命周期 +- property request / property sort 转换 +- V3 的 native 错误检查 + +### 落地步骤 +1. 新建 `EverythingPreparedQuery` 模型 +2. 新建 `EverythingQueryBuilder` +3. 把 V1/V3 中重复的 query 构造逻辑迁移到 builder +4. 提取 `SearchResult` 组装辅助方法或 mapper +5. 保证 V1/V3 两边行为一致后,再清理重复代码 + +### 验收标准 +- `LegacyEverythingApi.SearchAsync(...)` 与 `EverythingApiV3.SearchAsync(...)` 不再各自拼接 query string +- regex 与 content search 规则只有一处定义 +- 新增搜索语法时,不需要双份修改 + +--- + +## 5. V3 错误模型细化计划 + +### 目标 +把 Everything 1.5 的“连接失败”从单一布尔值扩展为可区分的错误结果,使上层能够给出更准确的恢复策略和提示。 + +### 当前问题 +`TryConnectEverything3(out var client)` 当前只返回 `true/false`,会把以下情况混在一起: +- `Everything3.dll` 丢失 +- DLL 版本不兼容,缺少入口点 +- 实例名错误或实例不存在 +- Everything 1.5 服务未运行 +- IPC 断开 + +上层只能统一处理为“Everything 不可用”,提示粒度不足。 + +### 细化方案 + +#### 5.1 引入连接结果模型 +建议类型: +- `EverythingConnectionStatus` +- `EverythingConnectionResult` + +建议状态: +- `Success` +- `SdkMissing` +- `SdkIncompatible` +- `InstanceNotFound` +- `ServiceUnavailable` +- `Disconnected` +- `UnknownFailure` + +建议字段: +- `Status` +- `Client` +- `Exception` +- `Message`(可选) + +#### 5.2 替换 `TryConnectEverything3(...)` +当前: +- `bool TryConnectEverything3(out IntPtr client)` + +建议替换为: +- `EverythingConnectionResult ConnectEverything3()` + +收益: +- `IsEverythingRunningAsync()` 可以区分“没装 SDK”和“服务没启动” +- `IsFastSortOption(...)` 可以在实例名错误时给出更准的异常 +- `SearchAsync(...)` 可以把失败转成更合理的业务异常 + +#### 5.3 建立 V3 错误翻译层 +建议新增: +- `Everything3ErrorTranslator` + +职责: +- 解析 `Everything3_GetLastError()` +- 把 native error code 翻译成领域异常或连接状态 + +目标: +- `EverythingApiV3` 不再直接分散处理所有错误码 +- 错误语义集中定义 + +#### 5.4 上层异常映射策略 +在 `EverythingSearchManager` / 可用性服务中约定: +- `SdkMissing` / `SdkIncompatible` -> SDK 问题提示 +- `InstanceNotFound` -> 提示检查 `Everything15InstanceName` +- `ServiceUnavailable` / `Disconnected` -> 提示启动 Everything 1.5 + +### 落地步骤 +1. 新建连接状态枚举与结果模型 +2. 重写 `TryConnectEverything3(...)` 为结构化返回 +3. 新建 `Everything3ErrorTranslator` +4. 调整 `IsEverythingRunningAsync` / `SearchAsync` / `IsFastSortOption` +5. 调整上层提示逻辑,使 instance name 配置错误可被识别 + +### 验收标准 +- V3 连接失败不再只表现为 `false` +- UI 层能够区分“SDK 缺失”和“实例不可达” +- 用户配置错实例名时,得到的是针对性提示而不是泛化提示 + +--- + +## 推荐实施顺序 +1. **先做第 5 点**:先把错误模型立住,否则后续拆分职责时仍会传递模糊状态 +2. **再做第 3 点**:将连接、初始化、可用性逻辑拆出 manager +3. **最后做第 4 点**:在职责边界稳定后,再抽查询构造和结果映射,风险更低 + +## 预期收益 +- 降低 `EverythingSearchManager` 的变更面 +- 减少 V1/V3 功能演进时的不一致风险 +- 为 Everything 1.5 实例名、多实例、兼容性提示提供更稳固的基础设施 diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiFactory.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiFactory.cs new file mode 100644 index 00000000000..609222dd097 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiFactory.cs @@ -0,0 +1,22 @@ +using System; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + internal static class EverythingApiFactory + { + internal const string DefaultEverything15InstanceName = "1.5a"; + + public static IEverythingApi Create(Settings settings) + { + ArgumentNullException.ThrowIfNull(settings); + + return settings.EnableEverything15Support + ? new EverythingApiV3(GetNormalizedInstanceName(settings.Everything15InstanceName)) + : new LegacyEverythingApi(); + } + + internal static string GetNormalizedInstanceName(string instanceName) => string.IsNullOrWhiteSpace(instanceName) + ? DefaultEverything15InstanceName + : instanceName.Trim(); + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index db74746822a..0be8f7a4fec 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -308,7 +308,7 @@ private bool TryConnectEverything3(out IntPtr client) try { var normalizedInstanceName = string.IsNullOrWhiteSpace(_instanceName) - ? DefaultEverything15InstanceName + ? EverythingApiFactory.DefaultEverything15InstanceName : _instanceName.Trim(); client = Everything3ApiDllImport.Everything3_ConnectW(normalizedInstanceName); return client != IntPtr.Zero; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs new file mode 100644 index 00000000000..daf7ba9e6dc --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs @@ -0,0 +1,68 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Flow.Launcher.Plugin.Explorer.Exceptions; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + internal class EverythingAvailabilityService + { + private readonly Settings _settings; + + public EverythingAvailabilityService(Settings settings) + { + _settings = settings; + } + + public async ValueTask EnsureAvailableAsync(IEverythingApi api, CancellationToken token = default) + { + try + { + if (!await api.IsEverythingRunningAsync(token)) + throw new EngineNotAvailableException( + Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, + Localize.flowlauncher_plugin_everything_click_to_launch_or_install(), + Localize.flowlauncher_plugin_everything_is_not_running(), + Constants.EverythingErrorImagePath, + ClickToInstallEverythingAsync); + } + catch (DllNotFoundException) + { + throw new EngineNotAvailableException( + Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, + "Please check whether your system is x86 or x64", + Constants.GeneralSearchErrorImagePath, + Localize.flowlauncher_plugin_everything_sdk_issue()); + } + } + + private async ValueTask ClickToInstallEverythingAsync(ActionContext _) + { + try + { + var installedPath = await EverythingDownloadHelper.PromptDownloadIfNotInstallAsync(_settings.EverythingInstalledPath, Main.Context.API); + + if (installedPath == null) + { + Main.Context.API.ShowMsgError(Localize.flowlauncher_plugin_everything_not_found()); + Main.Context.API.LogError(nameof(EverythingAvailabilityService), "Unable to find Everything.exe"); + + return false; + } + + _settings.EverythingInstalledPath = installedPath; + Process.Start(installedPath, "-startup"); + + return true; + } + catch (Exception e) + { + Main.Context.API.ShowMsgError(Localize.flowlauncher_plugin_everything_install_issue()); + Main.Context.API.LogException(nameof(EverythingAvailabilityService), "Failed to install Everything", e); + + return false; + } + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSdkLoader.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSdkLoader.cs new file mode 100644 index 00000000000..e36b808c07e --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSdkLoader.cs @@ -0,0 +1,31 @@ +using System.Threading; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything +{ + internal static class EverythingSdkLoader + { + private static readonly SemaphoreSlim _semaphore = new(1, 1); + + public static void EnsureLoaded(string sdkDirectory, bool enableEverything15Support) + { + _semaphore.Wait(); + try + { + if (enableEverything15Support) + { + if (!Everything3ApiDllImport.IsLoaded) + Everything3ApiDllImport.Load(sdkDirectory); + } + else + { + if (!EverythingApiDllImport.IsLoaded) + EverythingApiDllImport.Load(sdkDirectory); + } + } + finally + { + _semaphore.Release(); + } + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index c0277c588aa..9e1f5a32131 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -1,6 +1,6 @@ using System; +using System; using System.Collections.Generic; -using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -11,80 +11,22 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IPathIndexProvider { - private static readonly string ClassName = nameof(EverythingSearchManager); - private static readonly SemaphoreSlim _dllSemaphore = new(1, 1); - private Settings Settings { get; } - private readonly bool useV3Api; - private readonly string everything15InstanceName; + private readonly EverythingAvailabilityService _availabilityService; private readonly Lock _syncRoot = new(); private bool isApiInitialized; private IEverythingApi api; - public const string DefaultEverything15InstanceName = "1.5a"; public EverythingSearchManager(Settings settings) { Settings = settings; - useV3Api = Settings.EnableEverything15Support; - everything15InstanceName = Settings.Everything15InstanceName; - api = CreateApi(useV3Api, GetNormalizedInstanceName(everything15InstanceName)); - } - - private async ValueTask ThrowIfEverythingNotAvailableAsync(CancellationToken token = default) - { - try - { - if (!await api.IsEverythingRunningAsync(token)) - throw new EngineNotAvailableException( - Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, - Localize.flowlauncher_plugin_everything_click_to_launch_or_install(), - Localize.flowlauncher_plugin_everything_is_not_running(), - Constants.EverythingErrorImagePath, - ClickToInstallEverythingAsync); - } - catch (DllNotFoundException) - { - throw new EngineNotAvailableException( - Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, - "Please check whether your system is x86 or x64", - Constants.GeneralSearchErrorImagePath, - Localize.flowlauncher_plugin_everything_sdk_issue()); - } - } - - private async ValueTask ClickToInstallEverythingAsync(ActionContext _) - { - try - { - var installedPath = await EverythingDownloadHelper.PromptDownloadIfNotInstallAsync(Settings.EverythingInstalledPath, Main.Context.API); - - if (installedPath == null) - { - Main.Context.API.ShowMsgError(Localize.flowlauncher_plugin_everything_not_found()); - Main.Context.API.LogError(ClassName, "Unable to find Everything.exe"); - - return false; - } - - Settings.EverythingInstalledPath = installedPath; - Process.Start(installedPath, "-startup"); - - return true; - } - // Sometimes Everything installation will fail because of permission issues or file not found issues - // Just let the user know that Everything is not installed properly and ask them to install it manually - catch (Exception e) - { - Main.Context.API.ShowMsgError(Localize.flowlauncher_plugin_everything_install_issue()); - Main.Context.API.LogException(ClassName, "Failed to install Everything", e); - - return false; - } + _availabilityService = new EverythingAvailabilityService(settings); + api = EverythingApiFactory.Create(settings); } public async IAsyncEnumerable SearchAsync(string search, [EnumeratorCancellation] CancellationToken token) { - await ThrowIfEverythingNotAvailableAsync(token); + await _availabilityService.EnsureAvailableAsync(api, token); if (token.IsCancellationRequested) yield break; @@ -102,7 +44,7 @@ public async IAsyncEnumerable SearchAsync(string search, [Enumerat public async IAsyncEnumerable ContentSearchAsync(string plainSearch, string contentSearch, [EnumeratorCancellation] CancellationToken token) { - await ThrowIfEverythingNotAvailableAsync(token); + await _availabilityService.EnsureAvailableAsync(api, token); if (!Settings.EnableEverythingContentSearch) { @@ -137,7 +79,7 @@ public async IAsyncEnumerable ContentSearchAsync(string plainSearc public async IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, [EnumeratorCancellation] CancellationToken token) { - await ThrowIfEverythingNotAvailableAsync(token); + await _availabilityService.EnsureAvailableAsync(api, token); if (token.IsCancellationRequested) yield break; @@ -153,6 +95,7 @@ public async IAsyncEnumerable EnumerateAsync(string path, string s await foreach (var result in api.SearchAsync(option, token)) yield return result; } + public void InitializeApi(string sdkDirectory) { lock (_syncRoot) @@ -160,8 +103,8 @@ public void InitializeApi(string sdkDirectory) if (isApiInitialized) return; - LoadConfiguredDll(sdkDirectory, useV3Api); - api = CreateApi(useV3Api, GetNormalizedInstanceName(Settings.Everything15InstanceName)); + EverythingSdkLoader.EnsureLoaded(sdkDirectory, Settings.EnableEverything15Support); + api = EverythingApiFactory.Create(Settings); isApiInitialized = true; } } @@ -169,38 +112,5 @@ public void InitializeApi(string sdkDirectory) public bool IsFastSortOption(EverythingSortOption sortOption) => api.IsFastSortOption(sortOption); public Task IncrementRunCounterAsync(string fileOrFolder) => api.IncrementRunCounterAsync(fileOrFolder); - - private static void LoadConfiguredDll(string sdkDirectory, bool enableEverything15Support) - { - _dllSemaphore.Wait(); - try - { - if (enableEverything15Support) - { - if (!Everything3ApiDllImport.IsLoaded) - Everything3ApiDllImport.Load(sdkDirectory); - } - else - { - if (!EverythingApiDllImport.IsLoaded) - EverythingApiDllImport.Load(sdkDirectory); - } - } - finally - { - _dllSemaphore.Release(); - } - } - - private static string GetNormalizedInstanceName(string instanceName) => string.IsNullOrWhiteSpace(instanceName) - ? DefaultEverything15InstanceName - : instanceName.Trim(); - - private static IEverythingApi CreateApi(bool enableEverything15Support, string instanceName) - { - return enableEverything15Support - ? new EverythingApiV3(instanceName) - : new LegacyEverythingApi(); - } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 0cd37feb478..e746bc453e6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -164,7 +164,7 @@ public enum ContentIndexSearchEngineOption public bool EverythingSearchFullPath { get; set; } = false; public bool EverythingEnableRunCount { get; set; } = true; public bool EnableEverything15Support { get; set; } = false; - public string Everything15InstanceName { get; set; } = EverythingSearchManager.DefaultEverything15InstanceName; + public string Everything15InstanceName { get; set; } = EverythingApiFactory.DefaultEverything15InstanceName; #endregion diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index a16f0bb55b8..7f0d2298252 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -688,7 +688,7 @@ public string Everything15InstanceName set { var instanceName = string.IsNullOrWhiteSpace(value) - ? EverythingSearchManager.DefaultEverything15InstanceName + ? EverythingApiFactory.DefaultEverything15InstanceName : value.Trim(); if (Settings.Everything15InstanceName == instanceName) From ca3cb6eb6319074ed3b584df4fb8f7f9a7c2e7a8 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 17:33:46 +0800 Subject: [PATCH 24/29] Extract commone code in API --- .../Search/Everything/EverythingAPI.cs | 58 ++++++----------- .../Search/Everything/EverythingApiV3.cs | 40 +++--------- .../Search/Everything/EverythingHelper.cs | 64 ++++++++++++++++--- .../Everything/EverythingSearchOption.cs | 3 +- 4 files changed, 82 insertions(+), 83 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index d6c8fd8fbbc..7d3030c058b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -44,7 +44,7 @@ public async ValueTask IsEverythingRunningAsync(CancellationToken token = try { _ = EverythingApiDllImport.Everything_GetMajorVersion(); - return EverythingApiDllImport.Everything_GetLastError() != EverythingHelper.StateCode.IPCError; + return EverythingApiDllImport.Everything_GetLastError() != EverythingStateCode.IPCError; } finally { @@ -60,10 +60,8 @@ public async ValueTask IsEverythingRunningAsync(CancellationToken token = /// An asynchronous sequence of search results that match the specified criteria. public async IAsyncEnumerable SearchAsync(EverythingSearchOption option, [EnumeratorCancellation] CancellationToken token = default) { - if (option.Offset < 0) - throw new ArgumentOutOfRangeException(nameof(option.Offset), option.Offset, "Offset must be greater than or equal to 0"); - if (option.MaxCount < 0) - throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0"); + var query = EverythingHelper.PrepareQuery(option); + var preparedOption = query.Option; try { @@ -79,35 +77,15 @@ public async IAsyncEnumerable SearchAsync(EverythingSearchOption o if (token.IsCancellationRequested) yield break; - var useRegex = false; - if (option.Keyword.StartsWith("@")) - { - useRegex = true; - option.Keyword = option.Keyword[1..]; - } - - var builder = new StringBuilder(); - builder.Append(option.Keyword); - - if (!string.IsNullOrWhiteSpace(option.ParentPath)) - { - builder.Append($" {(option.IsRecursive ? "" : "parent:")}\"{option.ParentPath}\""); - } - - if (option.IsContentSearch) - { - builder.Append($" content:\"{option.ContentSearchKeyword}\""); - } - - EverythingApiDllImport.Everything_SetRegex(useRegex); - EverythingApiDllImport.Everything_SetSearchW(builder.ToString()); - EverythingApiDllImport.Everything_SetOffset(option.Offset); - EverythingApiDllImport.Everything_SetMax(option.MaxCount); + EverythingApiDllImport.Everything_SetRegex(preparedOption.UseRegex); + EverythingApiDllImport.Everything_SetSearchW(query.SearchText); + EverythingApiDllImport.Everything_SetOffset(preparedOption.Offset); + EverythingApiDllImport.Everything_SetMax(preparedOption.MaxCount); - EverythingApiDllImport.Everything_SetSort(option.SortOption); - EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch); + EverythingApiDllImport.Everything_SetSort(preparedOption.SortOption); + EverythingApiDllImport.Everything_SetMatchPath(preparedOption.IsFullPathSearch); - if (option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) + if (preparedOption.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) { EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT); } @@ -157,21 +135,21 @@ private static void CheckAndThrowExceptionOnError() { switch (EverythingApiDllImport.Everything_GetLastError()) { - case EverythingHelper.StateCode.CreateThreadError: + case EverythingStateCode.CreateThreadError: throw new CreateThreadException(); - case EverythingHelper.StateCode.CreateWindowError: + case EverythingStateCode.CreateWindowError: throw new CreateWindowException(); - case EverythingHelper.StateCode.InvalidCallError: + case EverythingStateCode.InvalidCallError: throw new InvalidCallException(); - case EverythingHelper.StateCode.InvalidIndexError: + case EverythingStateCode.InvalidIndexError: throw new InvalidIndexException(); - case EverythingHelper.StateCode.IPCError: + case EverythingStateCode.IPCError: throw new IPCErrorException(); - case EverythingHelper.StateCode.MemoryError: + case EverythingStateCode.MemoryError: throw new MemoryErrorException(); - case EverythingHelper.StateCode.RegisterClassExError: + case EverythingStateCode.RegisterClassExError: throw new RegisterClassExException(); - case EverythingHelper.StateCode.OK: + case EverythingStateCode.OK: break; default: throw new ArgumentOutOfRangeException(); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 0be8f7a4fec..e4fbdf44805 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -65,10 +65,8 @@ public async ValueTask IsEverythingRunningAsync(CancellationToken token = public async IAsyncEnumerable SearchAsync(EverythingSearchOption option, [EnumeratorCancellation] CancellationToken token = default) { - if (option.Offset < 0) - throw new ArgumentOutOfRangeException(nameof(option.Offset), option.Offset, "Offset must be greater than or equal to 0"); - if (option.MaxCount < 0) - throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0"); + var query = EverythingHelper.PrepareQuery(option); + var preparedOption = query.Option; try { @@ -84,32 +82,10 @@ public async IAsyncEnumerable SearchAsync(EverythingSearchOption o if (token.IsCancellationRequested) yield break; - var useRegex = false; - if (option.Keyword.StartsWith("@")) - { - useRegex = true; - option.Keyword = option.Keyword[1..]; - } - - var builder = new StringBuilder(); - builder.Append(option.Keyword); - - if (!string.IsNullOrWhiteSpace(option.ParentPath)) - { - builder.Append($" {(option.IsRecursive ? "" : "parent:")}\"{option.ParentPath}\""); - } - - if (option.IsContentSearch) - { - builder.Append($" content:\"{option.ContentSearchKeyword}\""); - } - - var searchText = builder.ToString(); - if (!TryConnectEverything3(out var client)) throw new IPCErrorException(); - await foreach (var result in SearchWithEverything3Async(client, option, searchText, useRegex, token)) + await foreach (var result in SearchWithEverything3Async(client, preparedOption, query, token)) yield return result; } finally @@ -165,8 +141,7 @@ public bool IsFastSortOption(EverythingSortOption sortOption) private async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, EverythingSearchOption option, - string searchText, - bool useRegex, + EverythingHelper.PreparedQuery query, [EnumeratorCancellation] CancellationToken token) { IntPtr searchState = IntPtr.Zero; @@ -180,9 +155,9 @@ private async IAsyncEnumerable SearchWithEverything3Async(IntPtr c yield break; } - _ = Everything3ApiDllImport.Everything3_SetSearchRegex(searchState, useRegex); + _ = Everything3ApiDllImport.Everything3_SetSearchRegex(searchState, option.UseRegex); _ = Everything3ApiDllImport.Everything3_SetSearchMatchPath(searchState, option.IsFullPathSearch); - _ = Everything3ApiDllImport.Everything3_SetSearchTextW(searchState, searchText); + _ = Everything3ApiDllImport.Everything3_SetSearchTextW(searchState, query.SearchText); _ = Everything3ApiDllImport.Everything3_SetSearchHideResultOmissions(searchState, true); _ = Everything3ApiDllImport.Everything3_SetSearchViewportOffset(searchState, (nuint)option.Offset); _ = Everything3ApiDllImport.Everything3_SetSearchViewportCount(searchState, (nuint)option.MaxCount); @@ -242,7 +217,8 @@ private async IAsyncEnumerable SearchWithEverything3Async(IntPtr c : Everything3ApiDllImport.Everything3_IsRootResult(resultList, idx) ? ResultType.Volume : ResultType.File, - Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)) + Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)), + HighlightData = [] }; if (Everything3ApiDllImport.Everything3_GetSearchPropertyRequestHighlight(searchState, 0)) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs index 8f8db86b5c6..0be29b4ab57 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingHelper.cs @@ -1,21 +1,63 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Text; namespace Flow.Launcher.Plugin.Explorer.Search.Everything { + public enum EverythingStateCode + { + OK, + MemoryError, + IPCError, + RegisterClassExError, + CreateWindowError, + CreateThreadError, + InvalidIndexError, + InvalidCallError + } + public static class EverythingHelper { - public enum StateCode + #region Query + + public readonly record struct PreparedQuery( + EverythingSearchOption Option, + string SearchText); + + public static PreparedQuery PrepareQuery(EverythingSearchOption option) { - OK, - MemoryError, - IPCError, - RegisterClassExError, - CreateWindowError, - CreateThreadError, - InvalidIndexError, - InvalidCallError + if (option.Offset < 0) + throw new ArgumentOutOfRangeException(nameof(option.Offset), option.Offset, "Offset must be greater than or equal to 0"); + if (option.MaxCount < 0) + throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0"); + + var keyword = option.Keyword; + if (!string.IsNullOrEmpty(keyword) && keyword.StartsWith("@", StringComparison.Ordinal)) + { + option.UseRegex = true; + keyword = keyword[1..]; + } + + var builder = new StringBuilder(); + builder.Append(keyword); + + if (!string.IsNullOrWhiteSpace(option.ParentPath)) + { + builder.Append($" {(option.IsRecursive ? "" : "parent:")}\"{option.ParentPath}\""); + } + + if (option.IsContentSearch) + { + builder.Append($" content:\"{option.ContentSearchKeyword}\""); + } + + return new PreparedQuery(option with { Keyword = keyword }, builder.ToString()); } + #endregion + + #region Result + /// /// Convert the highlighted string from Everything API to a list of highlight indexes for our Result. /// @@ -65,5 +107,7 @@ public static List EverythingHighlightStringToHighlightList(string highligh return highlightData; } + + #endregion } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs index d8b670a0895..1d6446d396a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs @@ -10,6 +10,7 @@ public record struct EverythingSearchOption( int Offset = 0, int MaxCount = 100, bool IsFullPathSearch = true, - bool IsRunCounterEnabled = true + bool IsRunCounterEnabled = true, + bool UseRegex = false ); } From cfdff0de03f8fa96355d846ddc292343dce4b3b6 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:00:49 +0800 Subject: [PATCH 25/29] Extract methods of API v3 --- .../Everything/EverythingApiDllImport.cs | 2 +- .../Search/Everything/EverythingApiV3.cs | 109 ++++++++++-------- .../Everything/EverythingSearchManager.cs | 1 - 3 files changed, 61 insertions(+), 51 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index 1191c07d281..9f2a5b739bc 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -74,7 +74,7 @@ public static void Load(string directory) internal static extern string Everything_GetSearchW(); [DllImport(DLL)] - internal static extern EverythingHelper.StateCode Everything_GetLastError(); + internal static extern EverythingStateCode Everything_GetLastError(); [DllImport(DLL, CharSet = CharSet.Unicode)] internal static extern bool Everything_QueryW(bool bWait); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index e4fbdf44805..4e7d7df5618 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -139,7 +139,7 @@ public bool IsFastSortOption(EverythingSortOption sortOption) return true; } - private async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, + private static async IAsyncEnumerable SearchWithEverything3Async(IntPtr client, EverythingSearchOption option, EverythingHelper.PreparedQuery query, [EnumeratorCancellation] CancellationToken token) @@ -171,7 +171,7 @@ private async IAsyncEnumerable SearchWithEverything3Async(IntPtr c } } - _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); + _ = Everything3ApiDllImport.Everything3_ClearSearchPropertyRequests(searchState); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_NAME); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequestHighlighted(searchState, EVERYTHING3_PROPERTY_ID_PATH); _ = Everything3ApiDllImport.Everything3_AddSearchPropertyRequest(searchState, EVERYTHING3_PROPERTY_ID_PATH_AND_NAME); @@ -195,54 +195,8 @@ private async IAsyncEnumerable SearchWithEverything3Async(IntPtr c yield break; } - _buffer.Clear(); - var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, idx, _buffer, BufferSize); - if (fullPathLength == 0) - { - CheckAndThrowExceptionOnErrorFromEverything3(); + if (!TryCreateSearchResult(resultList, idx, out var result)) continue; - } - - var fullPath = _buffer.ToString(); - if (string.IsNullOrEmpty(fullPath)) - { - continue; - } - - var result = new SearchResult - { - FullPath = fullPath, - Type = Everything3ApiDllImport.Everything3_IsFolderResult(resultList, idx) - ? ResultType.Folder - : Everything3ApiDllImport.Everything3_IsRootResult(resultList, idx) - ? ResultType.Volume - : ResultType.File, - Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, idx)), - HighlightData = [] - }; - - if (Everything3ApiDllImport.Everything3_GetSearchPropertyRequestHighlight(searchState, 0)) - { - _buffer.Clear(); - var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( - resultList, - idx, - EVERYTHING3_PROPERTY_ID_NAME, - _buffer, - BufferSize); - - if (highlightedFileNameLength > 0) - { - var highlightData = EverythingHelper.EverythingHighlightStringToHighlightList(_buffer.ToString()); - if (highlightData.Count > 0) - { - result = result with - { - HighlightData = highlightData - }; - } - } - } yield return result; } @@ -261,6 +215,63 @@ private async IAsyncEnumerable SearchWithEverything3Async(IntPtr c await Task.CompletedTask; } + private static bool TryCreateSearchResult(IntPtr resultList, nuint resultIndex, out SearchResult result) + { + result = default; + + if (!TryGetResultFullPath(resultList, resultIndex, out var fullPath)) + return false; + + result = new SearchResult + { + FullPath = fullPath, + Type = GetResultType(resultList, resultIndex), + Score = Convert.ToInt32(Everything3ApiDllImport.Everything3_GetResultRunCount(resultList, resultIndex)), + HighlightData = GetHighlightData(resultList, resultIndex) + }; + + return true; + } + + private static bool TryGetResultFullPath(IntPtr resultList, nuint resultIndex, out string fullPath) + { + _buffer.Clear(); + var fullPathLength = Everything3ApiDllImport.Everything3_GetResultFullPathNameW(resultList, resultIndex, _buffer, BufferSize); + if (fullPathLength == 0) + { + CheckAndThrowExceptionOnErrorFromEverything3(); + fullPath = string.Empty; + return false; + } + + fullPath = _buffer.ToString(); + return !string.IsNullOrEmpty(fullPath); + } + + private static ResultType GetResultType(IntPtr resultList, nuint resultIndex) + { + return Everything3ApiDllImport.Everything3_IsFolderResult(resultList, resultIndex) + ? ResultType.Folder + : Everything3ApiDllImport.Everything3_IsRootResult(resultList, resultIndex) + ? ResultType.Volume + : ResultType.File; + } + + private static List GetHighlightData(IntPtr resultList, nuint resultIndex) + { + _buffer.Clear(); + var highlightedFileNameLength = Everything3ApiDllImport.Everything3_GetResultPropertyTextHighlightedW( + resultList, + resultIndex, + EVERYTHING3_PROPERTY_ID_NAME, + _buffer, + BufferSize); + + return highlightedFileNameLength > 0 + ? EverythingHelper.EverythingHighlightStringToHighlightList(_buffer.ToString()) + : []; + } + private bool TryUseEverything3Client(Action action) { if (!TryConnectEverything3(out var client)) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs index 9e1f5a32131..787b5e3bb40 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs @@ -1,5 +1,4 @@ using System; -using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; From f439a6d3e9efa51c822fb5dd9ccdd45b21bb6eef Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:53:42 +0800 Subject: [PATCH 26/29] Update exceptions check --- .../Languages/en.xaml | 1 + .../Search/Everything/EverythingApiV3.cs | 18 +++++++++++++----- .../EverythingAvailabilityService.cs | 4 ++-- .../ViewModels/SettingsViewModel.cs | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 3d162b0d410..557aaf46976 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -152,6 +152,7 @@ Failed to load Everything SDK + Please check whether your system is x86 or x64 Warning: Everything service is not running Error while querying Everything Sort By diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 4e7d7df5618..37d65448cff 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -55,7 +55,11 @@ public async ValueTask IsEverythingRunningAsync(CancellationToken token = try { - return TryUseEverything3Client(static _ => { }); + if (!TryConnectEverything3(out var client)) + return false; + + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + return true; } finally { @@ -104,7 +108,8 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) } try { - _ = TryUseEverything3Client(client => _ = Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder)); + if (TryConnectEverything3(out var client)) + Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder); } catch (Exception) { @@ -291,12 +296,12 @@ private bool TryUseEverything3Client(Action action) private bool TryConnectEverything3(out IntPtr client) { client = IntPtr.Zero; + var normalizedInstanceName = string.IsNullOrWhiteSpace(_instanceName) + ? EverythingApiFactory.DefaultEverything15InstanceName + : _instanceName.Trim(); try { - var normalizedInstanceName = string.IsNullOrWhiteSpace(_instanceName) - ? EverythingApiFactory.DefaultEverything15InstanceName - : _instanceName.Trim(); client = Everything3ApiDllImport.Everything3_ConnectW(normalizedInstanceName); return client != IntPtr.Zero; } @@ -310,6 +315,9 @@ private bool TryConnectEverything3(out IntPtr client) } } + /// + /// Covert the old Everything 1.4 sort options in our UI to Everything 3 property ID and sort direction for compatibility. + /// private static bool TryConvertSortOption(EverythingSortOption sortOption, out uint propertyId, out bool ascending) { switch (sortOption) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs index daf7ba9e6dc..de497861000 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs @@ -27,11 +27,11 @@ public async ValueTask EnsureAvailableAsync(IEverythingApi api, CancellationToke Constants.EverythingErrorImagePath, ClickToInstallEverythingAsync); } - catch (DllNotFoundException) + catch (Exception ex) when (ex is DllNotFoundException || ex is EntryPointNotFoundException) { throw new EngineNotAvailableException( Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, - "Please check whether your system is x86 or x64", + Localize.flowlauncher_plugin_everything_architecture_check(), Constants.GeneralSearchErrorImagePath, Localize.flowlauncher_plugin_everything_sdk_issue()); } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index 7f0d2298252..601f74170e4 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -627,7 +627,7 @@ public Visibility FastSortWarningVisibility // update the message to let user know in the settings panel. return Visibility.Visible; } - catch (DllNotFoundException) + catch (Exception ex) when (ex is DllNotFoundException || ex is EntryPointNotFoundException) { return Visibility.Collapsed; } @@ -649,7 +649,7 @@ public string SortOptionWarningMessage { return Localize.flowlauncher_plugin_everything_is_not_running(); } - catch (DllNotFoundException) + catch (Exception ex) when (ex is DllNotFoundException || ex is EntryPointNotFoundException) { return Localize.flowlauncher_plugin_everything_sdk_issue(); } From 6811cdd157ce3b35265dc591246214d418355877 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:58:06 +0800 Subject: [PATCH 27/29] Delete Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md --- .../Everything-1.5-architecture-plan.md | 252 ------------------ 1 file changed, 252 deletions(-) delete mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md b/Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md deleted file mode 100644 index a0996e72cea..00000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Everything-1.5-architecture-plan.md +++ /dev/null @@ -1,252 +0,0 @@ -# Everything 1.5 SDK 架构实施计划 - -本文聚焦前一轮 review 中的第 3、4、5 点: -- `EverythingSearchManager` 职责过多 -- V1/V3 搜索流程重复,容易漂移 -- V3 错误模型过于扁平 - -## 3. `EverythingSearchManager` 职责拆分计划 - -### 目标 -把当前 `EverythingSearchManager` 中的工厂、运行时初始化、可用性探测、安装引导、Provider 适配几类职责拆开,降低后续维护成本。 - -### 当前问题 -`EverythingSearchManager` 同时负责: -- 选择 `LegacyEverythingApi` / `EverythingApiV3` -- 加载 `Everything.dll` / `Everything3.dll` -- 检测 Everything 是否可连接 -- 处理“未安装/未启动”的用户提示与安装引导 -- 对外实现 `IIndexProvider` / `IContentIndexProvider` / `IPathIndexProvider` - -这会导致任何 SDK 演进都集中修改一个类。 - -### 拆分方案 - -#### 3.1 引入 `EverythingApiFactory` -职责: -- 根据设置决定创建 `LegacyEverythingApi` 还是 `EverythingApiV3` -- 统一实例名规范化逻辑 - -建议接口: -- `IEverythingApi Create(Settings settings)` - -迁移内容: -- 从 `EverythingSearchManager` 中移出: - - `CreateApi(...)` - - `GetNormalizedInstanceName(...)` - -#### 3.2 引入 `EverythingSdkLoader` -职责: -- 负责 native DLL 的一次性加载 -- 隐藏 `EverythingApiDllImport.Load(...)` / `Everything3ApiDllImport.Load(...)` 细节 -- 维护线程安全 - -建议接口: -- `void EnsureLoaded(string sdkDirectory, bool useV3Api)` - -迁移内容: -- 从 `EverythingSearchManager` 中移出: - - `_dllSemaphore` - - `LoadConfiguredDll(...)` - -#### 3.3 引入 `EverythingAvailabilityService` -职责: -- 负责“是否可用”的判定 -- 根据异常类型生成统一的可用性错误 -- 保留安装/启动引导逻辑 - -建议接口: -- `ValueTask EnsureAvailableAsync(IEverythingApi api, Settings settings, CancellationToken token = default)` - -迁移内容: -- 从 `EverythingSearchManager` 中移出: - - `ThrowIfEverythingNotAvailableAsync(...)` - - `ClickToInstallEverythingAsync(...)` - -#### 3.4 缩减 `EverythingSearchManager` -保留职责: -- 组装 `EverythingSearchOption` -- 调用 `api.SearchAsync(...)` -- 作为 Explorer 插件内的 Everything Provider 门面 - -最终效果: -- `EverythingSearchManager` 更接近应用层协调器 -- SDK、运行时、错误与 UX 引导分别归位 - -### 落地步骤 -1. 新建 `EverythingApiFactory` -2. 新建 `EverythingSdkLoader` -3. 新建 `EverythingAvailabilityService` -4. 让 `EverythingSearchManager` 通过这些组件完成现有逻辑 -5. 保持外部调用接口不变,避免影响 `Settings` / `SearchManager` - -### 验收标准 -- `EverythingSearchManager` 文件长度和私有职责显著减少 -- DLL 加载和 API 创建不再散落在 manager 中 -- 可用性判断逻辑有独立入口 -- `SearchManager` 和 UI 层无须理解 SDK 版本差异 - ---- - -## 4. V1/V3 搜索流程去重计划 - -### 目标 -提取 Everything 1.4 与 1.5 共用的查询构造和结果映射逻辑,避免双实现长期漂移。 - -### 当前重复点 -`LegacyEverythingApi.SearchAsync(...)` 与 `EverythingApiV3.SearchAsync(...)` 目前重复了以下逻辑: -- `Offset` / `MaxCount` 参数校验 -- `@` 前缀触发 regex -- 关键字、父路径、content search 的查询字符串拼接 -- 部分 cancellation 入口 -- `SearchResult` 组装思路 - -### 拆分方案 - -#### 4.1 引入 `EverythingQueryBuilder` -职责: -- 接收 `EverythingSearchOption` -- 输出标准化查询描述 - -建议输出模型: -- `SearchText` -- `UseRegex` - -建议类型: -- `EverythingPreparedQuery` -- `EverythingQueryBuilder` - -示例职责边界: -- 校验 `Offset` / `MaxCount` -- 处理 `@` 前缀 -- 构建最终 search text -- 不触碰任何 native API - -#### 4.2 引入 `EverythingResultMapper` -职责: -- 统一把 native SDK 返回值映射成 `SearchResult` -- 统一 highlight 字符串转换入口 - -说明: -- V1/V3 的底层字段读取方式不同,不强行抽象整个 native 读取过程 -- 但可把“构建 `SearchResult` 的约定”收敛起来 - -可拆分成两层: -- 共用层:`CreateResult(string fullPath, ResultType type, int score, List highlightData)` -- SDK 适配层:各自读取 full path / run count / highlight text - -#### 4.3 保留各 SDK 的最小差异面 -`LegacyEverythingApi` 保留: -- V1 专属 request flags -- `Everything_Reset()` 生命周期 -- V1 的 native 错误检查 - -`EverythingApiV3` 保留: -- search state / result list / client 生命周期 -- property request / property sort 转换 -- V3 的 native 错误检查 - -### 落地步骤 -1. 新建 `EverythingPreparedQuery` 模型 -2. 新建 `EverythingQueryBuilder` -3. 把 V1/V3 中重复的 query 构造逻辑迁移到 builder -4. 提取 `SearchResult` 组装辅助方法或 mapper -5. 保证 V1/V3 两边行为一致后,再清理重复代码 - -### 验收标准 -- `LegacyEverythingApi.SearchAsync(...)` 与 `EverythingApiV3.SearchAsync(...)` 不再各自拼接 query string -- regex 与 content search 规则只有一处定义 -- 新增搜索语法时,不需要双份修改 - ---- - -## 5. V3 错误模型细化计划 - -### 目标 -把 Everything 1.5 的“连接失败”从单一布尔值扩展为可区分的错误结果,使上层能够给出更准确的恢复策略和提示。 - -### 当前问题 -`TryConnectEverything3(out var client)` 当前只返回 `true/false`,会把以下情况混在一起: -- `Everything3.dll` 丢失 -- DLL 版本不兼容,缺少入口点 -- 实例名错误或实例不存在 -- Everything 1.5 服务未运行 -- IPC 断开 - -上层只能统一处理为“Everything 不可用”,提示粒度不足。 - -### 细化方案 - -#### 5.1 引入连接结果模型 -建议类型: -- `EverythingConnectionStatus` -- `EverythingConnectionResult` - -建议状态: -- `Success` -- `SdkMissing` -- `SdkIncompatible` -- `InstanceNotFound` -- `ServiceUnavailable` -- `Disconnected` -- `UnknownFailure` - -建议字段: -- `Status` -- `Client` -- `Exception` -- `Message`(可选) - -#### 5.2 替换 `TryConnectEverything3(...)` -当前: -- `bool TryConnectEverything3(out IntPtr client)` - -建议替换为: -- `EverythingConnectionResult ConnectEverything3()` - -收益: -- `IsEverythingRunningAsync()` 可以区分“没装 SDK”和“服务没启动” -- `IsFastSortOption(...)` 可以在实例名错误时给出更准的异常 -- `SearchAsync(...)` 可以把失败转成更合理的业务异常 - -#### 5.3 建立 V3 错误翻译层 -建议新增: -- `Everything3ErrorTranslator` - -职责: -- 解析 `Everything3_GetLastError()` -- 把 native error code 翻译成领域异常或连接状态 - -目标: -- `EverythingApiV3` 不再直接分散处理所有错误码 -- 错误语义集中定义 - -#### 5.4 上层异常映射策略 -在 `EverythingSearchManager` / 可用性服务中约定: -- `SdkMissing` / `SdkIncompatible` -> SDK 问题提示 -- `InstanceNotFound` -> 提示检查 `Everything15InstanceName` -- `ServiceUnavailable` / `Disconnected` -> 提示启动 Everything 1.5 - -### 落地步骤 -1. 新建连接状态枚举与结果模型 -2. 重写 `TryConnectEverything3(...)` 为结构化返回 -3. 新建 `Everything3ErrorTranslator` -4. 调整 `IsEverythingRunningAsync` / `SearchAsync` / `IsFastSortOption` -5. 调整上层提示逻辑,使 instance name 配置错误可被识别 - -### 验收标准 -- V3 连接失败不再只表现为 `false` -- UI 层能够区分“SDK 缺失”和“实例不可达” -- 用户配置错实例名时,得到的是针对性提示而不是泛化提示 - ---- - -## 推荐实施顺序 -1. **先做第 5 点**:先把错误模型立住,否则后续拆分职责时仍会传递模糊状态 -2. **再做第 3 点**:将连接、初始化、可用性逻辑拆出 manager -3. **最后做第 4 点**:在职责边界稳定后,再抽查询构造和结果映射,风险更低 - -## 预期收益 -- 降低 `EverythingSearchManager` 的变更面 -- 减少 V1/V3 功能演进时的不一致风险 -- 为 Everything 1.5 实例名、多实例、兼容性提示提供更稳固的基础设施 From e21f300c1ae61bea21798b19582c6e3730125445 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:04:42 +0800 Subject: [PATCH 28/29] Destroy the Everything3 client after incrementing run count Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- .../Search/Everything/EverythingApiV3.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs index 37d65448cff..b7c1e932e71 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiV3.cs @@ -109,7 +109,16 @@ public async Task IncrementRunCounterAsync(string fileOrFolder) try { if (TryConnectEverything3(out var client)) - Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder); + { + try + { + Everything3ApiDllImport.Everything3_IncRunCountFromFilenameW(client, fileOrFolder); + } + finally + { + _ = Everything3ApiDllImport.Everything3_DestroyClient(client); + } + } } catch (Exception) { From ae6720b7c474c4c7352a71106080ec3d162d3159 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 5 Apr 2026 18:26:54 +0800 Subject: [PATCH 29/29] Update exceptional message --- .../Languages/en.xaml | 3 +++ .../EverythingAvailabilityService.cs | 18 ++++++++++++++++-- .../ViewModels/SettingsViewModel.cs | 4 +++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 557aaf46976..af9d61177ea 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -154,6 +154,9 @@ Failed to load Everything SDK Please check whether your system is x86 or x64 Warning: Everything service is not running + Warning: Everything 1.5 is unavailable + Ensure Everything is running and verify the configured instance name + Warning: Everything 1.5 is unavailable. The service may not be running, or the instance name may be invalid Error while querying Everything Sort By Name ↑ diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs index de497861000..dbde7ff3093 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAvailabilityService.cs @@ -20,12 +20,26 @@ public async ValueTask EnsureAvailableAsync(IEverythingApi api, CancellationToke try { if (!await api.IsEverythingRunningAsync(token)) - throw new EngineNotAvailableException( + { + if (_settings.EnableEverything15Support) + { + throw new EngineNotAvailableException( + Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, + Localize.flowlauncher_plugin_everything_15_resolution(), + Localize.flowlauncher_plugin_everything_15_unavailable(), + Constants.EverythingErrorImagePath, + ClickToInstallEverythingAsync); + } + else + { + throw new EngineNotAvailableException( Enum.GetName(Settings.IndexSearchEngineOption.Everything)!, Localize.flowlauncher_plugin_everything_click_to_launch_or_install(), - Localize.flowlauncher_plugin_everything_is_not_running(), + Localize.flowlauncher_plugin_everything_15_unavailable(), Constants.EverythingErrorImagePath, ClickToInstallEverythingAsync); + } + } } catch (Exception ex) when (ex is DllNotFoundException || ex is EntryPointNotFoundException) { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index 601f74170e4..22093a9abf1 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -647,7 +647,9 @@ public string SortOptionWarningMessage } catch (IPCErrorException) { - return Localize.flowlauncher_plugin_everything_is_not_running(); + return Settings.EnableEverything15Support + ? Localize.flowlauncher_plugin_everything_15_sort_warning() + : Localize.flowlauncher_plugin_everything_is_not_running(); } catch (Exception ex) when (ex is DllNotFoundException || ex is EntryPointNotFoundException) {