From 3462d495163752c4d5e835ff5e9fd03bb99211e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B5=E6=91=87=E5=B0=8F=E5=AD=90?= <84499436+Wxw-Gu@users.noreply.github.com> Date: Thu, 3 Sep 2026 01:50:34 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E9=87=8D=E6=9E=84=E9=80=80=E7=BE=A4?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=EF=BC=8C=E6=8C=81=E4=B9=85=E5=8C=96=E5=BF=AB?= =?UTF-8?q?=E7=85=A7=E5=B9=B6=E9=99=8D=E4=BD=8E=20CPU=20=E5=8D=A0=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 持久化群成员 - 支持 TraceMemo 重启后恢复离线期间的退群检测 - 使用 Batch Membership 替代逐群成员查询 - 降低大量群聊监控时的 CPU 和数据库查询开销 --- resources/wcdb/win32/x64/wcdb_api.dll | Bin 331776 -> 357376 bytes src/main/services/chat-service.ts | 58 +- .../services/group-exit-monitor-service.ts | 547 +++++++++++---- src/main/wcdb4-client.ts | 100 +++ tests/unit/group-exit-monitor-service.test.ts | 631 ++++++++++++++++-- tests/unit/wcdb-group-members.test.ts | 150 ++++- 6 files changed, 1284 insertions(+), 202 deletions(-) diff --git a/resources/wcdb/win32/x64/wcdb_api.dll b/resources/wcdb/win32/x64/wcdb_api.dll index 07b4313f52e9e1917280126a585b5656de7e8bcc..530f6edebaa3571d7d22e9b5e29ec5e48b17c546 100644 GIT binary patch delta 149782 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

ow^m8Irb)q zyI{2TcZiRR3557?D&mKDEJ6Vgr{lgsd+{-vFhHE#0s!I4S@m5bm>KzFsk#uKWwJ8DB ziZ$9CJ}xB`e9QA@Y*`8Sj5LIS{~Hl6qG7)cd;K~TiM{tG6uA{cT+}7rtY;un)b|xx zfwa1#It`k}OTYZr9==8ZSN?6H9x_l`i7!-0p-l);?O>`U~ z9BoE8H2C3o@hu5Q3sqD$nf4f+4x_>%L{cF^kHwxQV$eg8{dHvbLydrps`*(G>e3)Y zmUf9?nNcH=3>ewJxb|jBvl>CU#R%eET>KBDByzYQCCNpoidwyilpOvrkd)ZgNpw@t zL9Hp-cj*WvJQhOAE;slj%5TG2#Xpk5efs+>Q1VKI# z2!yTYO$l33WcnmY2Sf>U-=boJqf*Hz7056Y5%5HjzEp%pN{#s7>mrf6Kg&l#p~?sC z|4@h~@E_31MY44&Zy*5~f5umVSV#{cM8lGsE#@mvpD)^ML8s7Ct(UuPvcV*&19g_Fq QG?d5$ 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 DQYY1M delta 127579 zcma%k2Ut``_xH|R5L946MG)yAU_ntVC>BswF0w0Fu!|T=Fg8@M!~zD0Y}QqD)G>Br ziis&2W7i0x*s#ag6^$mBpb=xDrs#gZxw|0AoB#8CJa61PGiT16IdkT;nS0+H#XVI(x%XE?Y`yE}O{+_2s{60H< zo|^I7u;jc7x3tfB=`FSVovr=?U80s-OV-~@YPtV}G3jC~jrFgUCRwM^jD5F`=GO@; z-?CL|sx*QA^{GoMO%>n*iM9GWiA9qTlFZ&99XrGvwA1WGa|7#n6QxSd9+vn;@?Ve8Csvolfk(=Wj9 ziiawRwWL0sLhcJVJB{W?{QOou0a1rh@W0k$M`w=4^AIimsRCR*{9dvB8CYz36Xysy#7X6Gi4B#oSV zG^`@|FdmE}f*l9TxexvK%|>Ts(*e|(UdTqY#5l@E`&{&tkJ}gENBn6A7me3u+vi(r z-@}gsY5}kakB)deZm&~8b9(H{K~YIk5x#X*Z?YdMI+@&i;z!@|NJ8-o$&g=^=>(G6 zph}tEmS9kyAOU606`e7>k0=@KeZ^1o)lBC?*%&S7mN=r2^&5Jc9}0R$1V>;-{-Y`u zd@Hdhb`7&pTQT-qNmGVDK>Z=g1FOrgrz{px*|h&(Q~u#640haJ!H@W}P5FVf_GkRq zru-8gtyBI;1+AI#{%nC!OnIN^WODxiKmVHYQdB9^Bh)G93aFYX&le@5{Q~jxUsE>x zYs!bL(-c#+{+XQpcB3=s9w(dZnhn7m_6r$A;RKk`_o2iB>UcNsD^WY5Mkm{xQY{hsmaMii?)z)L9_Cb4p^wp%t|_ur>}}QYRGk4#B~n z|E*EkT}?$~5eU$_5!o2)ivK)iQ*jB)bm-`O#95G1f(45hUc!EI>J;g+Ft{35Z1&VDi8 z5bwOAtU3jtx-zCVmX<7A_QX ziS=VTZ5wIGaf!{+c9$-fN^GyTEiEyzN^KA6SBr*)yN-A3Tq+izNH$#(>pT~=AG&5p zdyh%X!);<{qhq4AR2FkNr)W?zn2z@`H|nl$St^^II?2*y<>#Xk`_wI%-Wkl!xus-# z4jLRgFg7JtXqE`s^dtc)#dJz<`Z@B3viPV#_ok~Jb$cz=zif7a# zY)`FhoD`g&y-|S4~SEuxm8!KTOHY$ir&xg<9R?RN;$f6W-HlrOU^y5#g>_A zKLu-6>9n`8+ICge_Pi>a6N!=w{irup$;LXEfNY%NDwYRG5=>{61K16TW~c60G}&}T z`5Z-|S2AQ%X>6%oYxDyhvI!Ik!HpdiJ2G~}sMHe0@0mu!HaD0gC0(&&t_{1AZ<(QC zlK0i0vAGgVClrSr0#S)<(gzQbBg>RUyRZTcyLWqgyQn`Q=NDx)(nX#Wo6H~EF7l$q zeT?WU=N5&^x#i`uQGS6Dqr`rRs)$1`W$w=`veB}Df=7Z+B{6dJ?X1TMrpB0s!PMK; zs%PpbbDFUSjbiAmw^*`AbC&GhO4{^F!?N9b(AyJOk$V>@5XG17J^WoCR^zz?JjR)h z6%SrnEXq&?`&rrYtA>qeY^)dhGk{E|l~I-Kabq8v9K>8aV(9I3AeYGw_P&QdosrHC zcyy3j{jFh7JqFf0hW?_*%L>-d)7`N*EMA#XSjDDz4w6Pd*Btkh9o(S1O6{UqRg$-) z7$36^O;V&)2PI~1B1?(*z1k$+as4l%Mxyn(!e5DfzkbApi%)wxbRO&AJB+Mng}&|Rsk!W^Z>R3$O~@o-<5P-Z(EfN)Kk0p&lg5m{pic_Z6Wx-aQCtmF%+3EGRg}`K6Guk5sXkdXsGo zyhgrZbAmFumuSB@G>7uwj))8(2U{lFQhuLIanI^;Qb6vIQZlY2!!CGxQVsXc#LFbr1Z0m>?JA zPZC^!_B@?nx}>=7swVf{wd_S`xMQcg0>j@Yr;Ch+ z-wx3KXtC%gSPFzzHC=`x)k`m6dJN`8qDq-RhmqDEbnG1F)!K*Z=CIDKTT}NrY(neE zrmo*v$8i+D=EQQva!FL2Q=VU9ds>gDk5@9kHpwpI&WS{2;8&UQ-WitH_9VH(`nEgY>=zZ! z07ocG>@!zW@VL?~0nv+_;>P7@EpZ;lHN7JHp#bZ+64kB5E2Z&Q{oX1$_9-OHixj1ICn z$u$nP1YTK$a&9Wij_T{XGapSVvXoOAjW9He)nSCK*;&Xcqq@=^cC2~lrqpp92J>QR zogJwC0XCs?G;L*KA9oIQzoQ}-N>m^ggD8`xuzQ`~@a>vcjr{hBen4mu}DZ!4Ry)>H2c)jt%;JqlSw)(X4 zo6d?Acwh^yc*>8lvt4}x+yGw)%b5m)ooY4N!%LLmWn#(fkKkXnu19qEN)ZTIoz2&N zWezIgvd#R5vpMmw#Oz}HB@N;X;cPxT_he~9^)VA{J&td7Fc(Hb&hQst^sL{4`uA!T23X#{HIeH5A5Z!{Uxt$b~`)tY)WX?cUk{l?P;BNSwXLD zbZ9>75Z9gt<+F)#Q|Xa+*v+`Gx?zjp@R`>IZ(`@5w<-t^0z;?@hT8>4mUL9PB-5HlN3`5<{eu@WVDFcBDgc z*!PJorNqs4%ufG^Hd)M`>Sxf7Z-W32mTeeJch6;44gKhhIjm*hmXga(i4E-=PCuT{ z3i|FN(X3}u3Vk56_mc*arRDgJV`{+1YFpK4l zo=5A=Qegt#2%#l2RhaZQ-lkzQ+5IJ5+#?z`9SFSG ztMS8VT$+uAeys4#D0*}>JN0H?s(+t(rC+D3)7Z20WZFB8$rC=Oji<6_6DHE=k!;Lc z=^n+Y8U&yxh2gY%#E~a0?s==&y|+H0k=vMQVl$dHnSDJm#3^qUv_T-E7NzxMc7I~5 z!$z^Mr>|tKCe5b}KV#b_b!Z(iNo=|m!8zbD)IDsf;)ALL(-}lCL9%p4Z|+T$dZNla zi13^l)W^kH4f#$h6NX8eN*xPm;oiFO3J9MF4E9a@AABF9D#6^SD`ZbawrV1qH#v-K zU>{9RCY(K+Jf5a)WvNp#1K)yUsrm%)jG)=z@(G{d!wew>!lCmT%zm5Fmd1Or(5XHS z>%?pZEN6*RzoaD}v%jV`^QlS~I~UG`>g~3kfsV#DmC&45l*{R?TSg1|X*!#b5lHjX znK`4A!y19&QXxB?(Ugv#$CQk7G;7$-eba&oJv@-zncmSSX-UnliW!iCux*eUv?0{7 z_kNqTn{k%58p3GiWqPbXyOtSFQx`MGtme|SF%pldLn7GNtfjQc5%zmlY~vRFL|}*9 zk(w{KB%5VdCDHy^qc@w7vw^Oh&+0B5K))O;ARX4d56A}5%;B94 z%sw}W3}nr7_mFk$Zf+8NxSX}i>rL&Nu($JO(_xEt{+8z~?HpYYMETeZ>h6>v(hEN$ zMmCsaR=K!|>&eU@dEZWv%ENzJzc_X_D=Qc21v_fxJU^xAw3DT~D=$eY;_;tSj;)4+MiWi5NpV$-Vt)p zaak$?4p`6;#qhWqA@OoO6QO=^vB5MYEWtF>e>~;~pQqf^DEp;$rd@&v!_AX|ueqmcW zuoLTExR5$eQ9*s>YETE~_W+vPa%btX_Jpo#zw__qbqQTGkvXi`;1CLHs;m#&`T2_0 zgzj$3Zm!(q@@LO#B6h&33-a{~|Q8HOqZ}hU11e zh4XqooV|L#OY*>RF!R{)i-(ESV_a~uZ1Nd07K$!6T9eg2@}kgAF&6i5fT>lD0ULpK z3l`cwQ~-`auDHGp?A2ISu%-&>&H$*2S$$E->O0vi+#t19jvnA?HNbH=p zBx5zyCZ9t?K>!AmE$(j#v_eOYK;lFscT-1}D2K+gwrdRy&I%=LB=W-Itq=l>`}c3K z!nIy*M=%toA*s1Rv%P5|JFwQL?l+?WY_@;!7Q4IFBPbtOK8)Ch*T|i{+ zTu-gYnKiAp6=#(vomsz)3AFz#wr*pvcTQ&kwZID1(O`}z2!4?MYOjp%%x-QBbh|wf zmZSC`yR&JYR2*eZ{kEIQ7H{^FW}=AHFTL{?JGXhc|L`n9zukPO8}P|Ghq=}{%BtjhrV?B`)uBa z%W3~0Yh{qNay6Ux5h??%m4RwyJ5+v*$^dI+fE98Tx{qySwQB=ymMsk;JFGYRX6pmG z$d9f4bdY}=KQKciC>!ccy=?h2^=JZOd0JV&g1LP*hhFq$i$Ci{&A#lyXH6&#Vh=wH zq>YC#*KLicX2{NvZ3_s?`^re$cr)$xj&xBni{BnjQdrjZX0(4STem%kzN})!+r8`k zG*}FGLK!@s{j|Lgtv{Yc?nrVND7ND+FJ{~k-y&`hAjEbW;Hc)%so0YdrO^CDY>o(J zv)DUk`ws`PKX)XC4G>*_ZK76JDs$PNXr$-(d>zV4sGIqz(`UBX`-JNMvKlaORZ?}6P zHJZWPH(hy}&YJFNPmd+DetX;<(S`{{^kY-@1h&dc7W4WKIjCr+g4w~DQ|E2()sG$A z)0SE~v&VZP=YE zml9z%*X`>`e{o~U`_WM;kn$&fuI-;M3t-_Cc3 zqYXsqTN^|cARXLT-2<(?K2lo})y~@eQ9^KqL{~g=W&I9>cxQ_36S+sjN|@gPPp^**Vw7rN;bqxyX<5I69u3;-H5#!~WK&&`s?9&DXKx?$r#%fw z5%;K9oG3bLlN!@xGPpGS3OkKWHz_BAB$r<4h1wl6(?zO z=FZb(X3Dt-axkDKGZq~!?#4Lw=uklR60{3MA*}>*lYp?epOlez?==tqO%sh4_pN}6 z#36**4h5MUt=h#**_fCP0Cf_wrP&|7u*emsL1!(~P!Ww;)hY`M?-@JD8l1Dqhg*7P ziiwGJnurH=c?3n@IJX>B8L)X-0Q;&r=h!i}0{a0~7 z#~L05Fp^ke>IZwPz}FoGFrCqpl^pHd&=q+zjNz|1hzCGfbja7HiX&J7wK|qX?1%sMvn! z!5W_ETt5e?GmIIb9FJv#Po&aW_G+tZ5BB4UwvzD`WnL$HNSEv+K1oZ$>vgxzs$y*{ zVP|eKOcNt*W5Vxc$Z>xQhVw7pt2Y)49?R-vnl@Vga zMpX=|!BBfVf2I2n71S#G6>SAnZ2*uf+QA^}!l!k|)r;zklx#}C3Bq6WHJyS0vF$4k z{zX}*vJUmO_fTh{Z0*5jmdW&6!ivg#=$p~(PFYtXwL9=HH^RT@gGx zrj$j}(cRhnvvS>8n%b@Y)vdAC)+-i_j+08YZ=mq^YS@(f5C#d`f~tP9bjso$&{1Ud z8aWF+rfR2(^4~$``EK-TS2pu}xXWGPRSNx6>{v0>mF+m+NaxV4hV!rIom-r)OzEof zMOGeIAHtNI>Vv&mAQ3yoC|P-?ab@)`BnMx6O2vtNJ#0{m`|s^lJBJAGHF^8mtK_le z7gD5SFDd)^LSNdo6YFxZzvPeN(u>J-Wk+`R;(0nTk?p+HjTqRION_4W!`}TalJsHw zzw`H5?xfMcfv8*Ku&9p1hf#1G26x!`{JTbk_S?*yzi&yuxyZVFpR783-;W4t1W^^i z_d#q2oUWUaqw+6mmy{p`7Oq&D689b9ZWF0H^S|O%_nL^P%^ga*vZ!nAqIc94#`u`< z<*~`uqZGSWt3lA(@)&YWS{$3>^t`2#hla|QYHY5ynmY{Y%C=u=OlPiRhpvUNU#>(_ zQ%~0Tx?I0*TP&jz{hVqFnPo@&RfW_|w=Y7}RX(GFyxiGQngvaBXLr>saF5+SEDp{QM8i|a`hzmd`vI)-xqr*3)<38G zr2}co4&7`(Z*^lAZU%X!+li?GMx@ee>4Qz(n9Hp&`te2EqJmx>`E{Jca?I^ zm1W=ZpuI!b>RZ7yrziXN*3`yH?T99!B~IY4$QNE>rLpA7#2&2I?I60l153Z{N7qL% z2vi3(2J8w+v-*U?n6*wiUtsl+y15_)14O{Tp5ds%S zq=u9)VVtJj@$^jmSK|=$RuWE0R7=^i;z7c$fyn4q6XB{M(M#{D2u$; zwo90BY=keq(fSaktWqEBHRoq0Di0P_w;Nr%wjPOO4FOC_#;WFhpvbbC%F>q^B}Rs>HC6PeUo7)UMSy+ zLT>M5oTZ*o4h4xl>LL;fF-qQj$__v1BE{qP?+4!QWBoK5oYG;F6e7kJg54kd3jgsm zZPc0l`J*=t8O1z*ifJ@(A65;EA&W&oo-Pka*}5M`(6}fStg#B#pwYj;z6oSql)=() zg|Zb&cX}^?eW&Q?jApE9MU1oz3`(u&W!EqOR%qqV$@MvoD^>sCb|9OSc5E8ERd!-j0U~PDUS)qZ>@MV#YV(rqw29au~ z9=>epqXav<>hew>_Vm%-hC2=lo;4M>T`J(~yDFOwvTuKh_3w6Gi0IN2SPrH5vUpBP zR?_`dp@>qx@@0OHz0+b*u4TSW3CRk*34Ar?dlLX^o3SBE>sx|}iOI^f8?^yv2~5^M z6+R8#@>2)4_VG|U+k-uO94z$*BYdhNsDn34s`8UwJ)k?MRV^XZ{5vDRD$;1|u!p}6 zk{qk(7Tr@)_c(OA;(Q5{U-D!+dCH1^Q>4w0tT6H;D~tmar(!s-!c3#i$Rhyg?$1`B zf}d3&$9QN!#e9acGk*-H?SI+X;!hKC9E?qXLu|?p{WX=QRkGH9Ka)a0VCc)?(g{$O z|FRwlm=EQnl$@Z|6Dw0M|B1U>kWl+OFC@18)i&u^86?1BmKJ_b*)JA9Df_v!(v?I? zw@%ZQy~%QE#bvtk25Il%Tu)MioN9kVqy?`1F7XgT!ldrcB;Jn@{}uuFz}5UBZC)Fp zL89YbwfW6dU2;X()fmO}sTyb7|K-fr65`czmM@kAx56CMyI|0<>S_HsWy?w1)qJ(iBF?JU#a*O+3=+)Z+=ht8fW6?5%gc(TvU?$vkzK{_NnRi z^722(!1QLDE?CEpSs?^XT+0w?rTjw34?5~BQcK@8G0`MRGJq3c3 zR?vZ{@jI3r;#PRzAI@>u{LY9WQxR&P&VRZE8P5} zJld7SNC8JEk1*3le7P%WD((4;^6jo9nXW75)Qz-~I{roXv~?q{M0?|)#bOKJ&nbP2 zcya^sM0?{v?aIS@k{goG2>syDp1&Ir9C=JX$XhigGyFQhja0La)p`cA3`4Rn`~}r0 z!*}p+8E0z@G7!CeP z=#QLxk=fL|hr2Z;UC0xzZ%W>2lv-a5AEl}s0k~b!@8kEHlJ0cgZXW1OI<`6r2(+Y} zS5bGouHM8+fyACrn%fF7qTr1J-yBLC(hHySkv_y*8ti1@d%c0G<9`0an{<{U;bXXM zYuMNaE*^H;{1Xn)Z}YdyrjbR8v$c~4!*CU8@N4yEoo!fW_LTBMA2L)5FQxpU4;d{@ zl`K5jmjt=3KStqu;|`E;td*ruy!HJ_n>rOcq1`$NC%|jfBQY4#rk(!*+7h5s{Yi7~ z=0`?JpC45bhx1K-q`jmN8}`OWRqU}=?2Q1VVt?c78tmGKHtb)Q)CS#NqGHdcVI{oE zpDdITH5Q&3Ktj7^9eGXgS>;WXB8$WwV$-GZu|~T|!gJnGX0cTI2$JQ00CzdUuLh6| zdbXJN2_yrkpM`G>Bp!5FG2a_VI?^w{;#Gm9gVdvf@~|Lcpqq>MtROO_^A%i>l#Qcs zJNZhY*}J3OI187ak<&yu4BgC!pK<1k{?9(-#_J_hLMi00jee&ULkDD z2_^dpe;h_ybje*Ksu6Kp-2KbZWL_Nn0%Td-uirs9DT+Cmr84g)A@`=m!Rnl0fKh1FR~*%9S7H@#vOhzqAM&{6$MrOr_uXfmWm~buH$~%-F$2~=_f6{L;2otvW0%Ni;rwgaKmW}-`$$X()e4HlQtx=vHwcw zK!40H*6OvG4KYg82mFmTWHNp9gkNYwn$VDM_`^12pz}=xClEw&Y+1~?Ap+!df5LMj zh;NfsXwtfAw0rE=;R&MJ+f}>UemPjNCxY~%t~>eP5u{Jppv?lq$UdGQ}8t2s0&7~J3ml9r7a0@-uq+Cc#~K0&234n*E^{CRqLiJN0$Y7Mi&KLvVNre z@3yes7k2RIcIevhb=OTR`IL5Ka%&^pfHLL4#%cl$8QAo@^B4J)pd9B+!gR zoo&V!SMaWpq^nmeR8>LNFwjvo^%RYgvclFMrKRQwLOH% zI#O#q*+yzsPWkHg@IRLPN_la6l3hPoxEVrO4Oq_;JCNRvmxQOF*stgBcOYSO;$~jb zfgIDWSY2bg&MFS;IPZwrdrsotcO*Tf_Qeu!+KGJX|DwVwB@r^NOveZ*k@eOiSRwJP zKj-&5K}xhRz)?|TBYmLoYf;3THr>XbN0Gjg1+J^ynJl60KjT+BlTOsUn!9x&?dZ_e zT-OCo_VWvrXLKR%u6Hg7s?CGoEI`POlljUn@OT$or2J$TGRAo^wvO;&pfxTp=AENS zYSS|aGRhRos#-Y|L%DDk=dI;mN0T|!Z5I#kN<7F5uIoyg)4tvIWOOA9kwDUu=2E-; z67Qxb0n$wPJ)`x+ul_+y6}!{ED=JKS;;mh2tw@OyzOmP7 zZ_ZyW6pl#H89Wst>SVKdFY1(|7u14bh_YWial=O1o+qs*+H9{gf^a><8fvH7{|0f# zDVt6%)kO*GI$P;)?P(UM6&(sVb?XivN!_C$u&4SQhqEJP2GGQ>uoZM!z>n1NAVCPWwZ5cEQ%~(4RDOYp_X}!6G3u zX2WwO=pLWgpJY0IbX@TMikbh^pCmf=S4(+j-emyk?)CKssu5wHN!TEBYMN{uiEJCL ze@y4g2ax0R!g@Y@Ael%*()o#jB*?QkSr`f3QrTqSv8LZe(izZKGPsmN1~v&lhLJ?Y z2ou6S%+cT>CU|=(&qyIHocm;;d7nsoDm^mzCn=<>-L?0uX$7eOet;!~B-mwE*94(v z>>$$1&fQjHcNFdbw;M#_?7lJDx{ZNPkT)1WDYhCXI{;PtoP5ME#7irF)$nb@NPC)6 z!m)y${EuM>IJ`@^*KjD~X{WehI7y{XKIdNyCmt=jEf5^ZYKj*b&Gt7whm|(=ag-#!INF&hpm zqc8CAkz^Kiyv#oyN&J1faH{E5YS$fB#7>BU*}eUDD(D?$+j;)ONTR1B&-1paqzetm z=aW<6ja20Ek5Wl%&t=F4s5rNu6YF6(CtHdw?$WosGL-~&jQyGSWYqC4ES#q2rFw$u6u&5WvFPu4Zqhdk+zl|q9wa_ zi;u0PnP?gJx+UA}?qF-GFPaixH<{g^z+n_5JUNXPq=Q}$bi>wiMYMQ`mYl!+wYf1! zWz?+c0UOLtz$D=9HKZrww7Wl#D0jvgu4x9G#u=UoykINw;;v)J=Jdu$5N;@-NHbn~ucJeZ+i7RN;x-_mePdZ3~J$hk0^@a?VF&kbq4v#J=&6n|O zV~9`vcXz(B#A3i!<<6XpC56FF&%Q$TUybr^scIIjFbQ}IQkbDA zTm^Sk)ucW+N*SI=QrvotQeN>e$2`%NN2!KaUlrKysQx+=YKGT1I|lNxo7xET!}RT!3+ z#y$2Ei3_2R3b^|uWW(Mn<#CgUKV4VA$4??gdgvH`GKshk`S<`lu2`*`gUNXd9%GG3 zj>6BxBmB&GC*fy`>VkNe1ap#BZ_1AmQ^TE+DCIDAG4xU!$S~@JULtUFp>86Sh+>{P znT(~UiulpVWHf!Vh=)!gaW0*)9++^Un6P^hpEHGY^B$iF4#n^*px zUz|ePH*5@ug-Db9je|9yPgdN&=1r!O7#f+$hfl@i#xCXWO@*%RwUloY%~!?dI{* ziEmQ}+(l8ZW9#6X*pIdXtj6Q`-8@GCoYe~e1>I(&R<;6c#iL<2-v*x17TXOf_L ze{8pIv>gYzVI~Qv*LsJw+;}gaJ(G9`z1V}DWGPL^EyY{0&!-=(k*}w=j#u{ZJu|U1 zyASXeKp1ofmlYxPFvm^^=OZsF<*2B1k&Aznpchd-Kc9D>Mds6f&-kHPq$wTvDZf68 zoTc~Q;-Afi;EdVIPtPWOY4nG@=^WCuzAv0Z#Gj`X!&^Ld4jJmWe~VB^4=3;s<`BK( zc(t^80)IA#jPv^A1JTxUf(Yehli6QrS$H#_O{RQe0`=zg-=MDEO_3ZdRDSEZYP!W%x++S} z)g{qMv3$V4S^$@;DwW?`K(c6xkq^y=AU?gq*JhKMwB=sjFo*P^kC*aMIiz2+twY7G z$;4aUP`|T0Q#3 z{xyQLcS#{NuHnrVkrc1%D+Lm#5n|c!8k!iiNX%%>6ux2++0giH1Xi{)_b8j>T^U9B z7p~NczfnMfvQ6*92KGcILR}TH6zZLc7pqZSX|3+%k91JBsJM;_wYiDtH3_9^A6fj` zUM)c~Jx9#nWIsH|mYqTfl>i-tHzJM5$m=4XS<~E!u5iSSB#fl-a3f4@<6(TZ5xL_6 zZsD)GOU-zhkwm!R%@mRQ5%&;bx@a267{R!EPDir{IdC65NXvAI?A50frjtI}=!go!M1Yz^QtC2cTI zT}(VXY(Po4$!2#apcATnY%I~hpos+6LKQDQRuQE>*p6Ga4CmVxlMt8a=3*6*6MSKD z|6~cjvl!M(W9BYq(zhPoQvtGb%85ii-VDR^cOiezjE%UWke@P>Va;W{>Zhg%buVPo zg#>Zo+-%sJAa0z$Y$4EM4;rp2qdV>~EFqqx-mG<2e1{YG)TN|ny-v0=llcLZ>8K^# zvJ?jd4b6N;Ar#XtGyk-Z__#gmuci}Zli`KXZ?gvTD}`h(tv8JiT!!8Hd;wpyjI?q1 z82+6?%>2+Yq~PD1#qTd81vFz5pRydW%m;6%K11kh-?$vh3Hs8MhU@sY<;3i&hr3gz zEJ(IS79k&TnURrnk&b`D5b2D5kK+J#K|Obsi>H;lz4-hUq?zlQG=awXPNDd5zh20{ zUV&cgkz!s+Vj4~CE2fM9#=HrOA*iqDzh~S^;z#I^b^P5`;A%lC|7;cM*zhLwYl7)! z1x^crDJ4zmk;Kr*`y`Dv?7{zfpZrZb595EVfl=PWdFWc= z>s>jN;*$z~n%LYjYRmTGDuK9K5dI+_y%y#nNakzT62FG07J^*~;vm&_H+P|)pIJ+q zI>s%==2dQ+c-30ch8iaGfOS}i$W?sXIuhVB7MsTwR0{b7&ps$n7vi~cc^R)*N3vW) za>POm>1|yI&00QXJq|V}MDt_o;Z66=;f@=~BDZjzU~Nqd|78N-w1J$Yz5MvZjQ~G7 zpC8!>A^Lt1f3Xol9Y0}D=qBPt=-Orciw}r5AGMj-)3O14{ASYG*{7$Cr&pDC2k_4~ zliqay8vfg6vWK=U6z~D`jsE=n2c(1Z9z;(n`>!hg{dt2eWH|MBn@`9C?%2r2 z$cl>y)kMg`lK94t$nvOdi&ek-pD~x5i+7%Iq^!nVw;*WaV~^W)bkC7i{1zTS?~zSW4gejUsweTMzM!OXXRMp8WIMv0ZI!ihJRO({$91rnjcn)cy7 z+elYBCW;T=2A}KK*?ZP)BaVbdy~{uToV0H8hAgz6jvK^%IDN2df^-%qLQ0~{AAOE~ ztRrvv1^Jdf&Eu6{0Nf|u3a)QiQVlL9RVQ8y)5+me2&2-s1JC%9WYm|Z3yK_--)<0I z`6cP&0Ok9JdP{fnjx#k8Cg6m4U_4{pkv#-e@zq)EEx~-rDYRB+g=$wNc zFm>~~;PV>3KbrWvG{_Pvp%wluQ=YxWPkarH)ng(L-HB6|gcP2?lkB7)F5q3h!ML|# z`0#JAfB%@zAACbvHx7bm>qXp$ulFD_6EFTK+8Ew_H|gLo1+kPev^5{Mi!geB9{+O} zI=J+(buhF%o?z}P4l|TLyNeE8Xk0jddpG%v?w!j+_5k)?x7x4<74~d56*=Fy2m95t z75{h-IYwhg@yUD1Y}catb{gqItaJ$(gvH)PPW<=1#H2l{)=F2@%A-zv=|1wF_Jp2aoL)BdY%Xd!c9*PZsQ=Uu8)+qkoL9(9i%HqurVT=6Ki6m z$K!FOQ0&L6c=QyH%KnamYXDGF@ny65k#CW?O7h~CZ%J$CQL}}=3?&_=JoMsS4wDvv zIiuCn4#{M{08dCCVxF_{RM5+*w3jnJY39Y>J&Xf^ZxZx|xB(mhsh zCW`Zu=sTHsA@Q^lI0}U1miVJ0>#+z`;BgHMmigU#BrJQ3y8u6}Lh z{84ML)<&SVzqK|7wS&jdY;=>8P4**EYm809dZAKN5IeRsb{v-Gxcb4XnFu-^tRzK< z4DY5ab!0;f_}NNy)I}iU5P~OU9NGhikHDepSgPv;m4diMoJjcV%?9{wDG}ndYQY$d zCQiKC7Mz01fPZRdCd!s0(79+lAus$>e42228#(t#sKFHTB7y(1mcOGX#+G5g>H=7Hxh*mAm3|Sz>AIQL;_L##zkZv=R!XW)pLf z>WP|Rlj{s+{$I$-f@C3`$;!r;A{BzAOBTB(8s5D&KMX>ob<5w5^${quwb|w(JX>F6 z?lHx-U~0Qqvoo10=kf)N*46$t_J&wCSLgfc6P9g{eFYxJ8)N;!$8tOt#0JI{%n6c_ zqCqERTL!jpbs=?xNUf?;7>N_!LOC1Kl`Os*gpB4qL?6{6*b#vL5W!@jYSV|2 zk=6S`$;zD-xI{F#2r?&5!|_&j8ioXKbaF!O3#~ZK7rX$EKE^o`SWzwWy>Sw+%6v9P z)aLoA#nVdh@LHo**r67z5=LJL(S4Xg3}hA@Jg(MG89jMiX}&kgFe+*d#&T6|Ab%`o zEIKMvfD-ihgGyLUZN3hb|0n;CO!_zfW8gnv&}#l0)2jKuRDA;fkuJkyL9BmiYyj5Y z%Jj}tYcc&HZqVA8Ui>SV4sya&_Tcjj*(t6n&BiE;1!0&m3-7k;!o>CYn1U=59XXFmZS?(p7Js@2baD8&?CqvjhnX*X~BtV93b% zGcY@=QOyCy02m-8@J-x4u~$sPF{q^k&{>yil3!;f~l~x0$WS^P}b!N?e4oOvYk;r}~;juvXtW@_L z2ocp=brCe1Ii*Udq8)h6SA6Cgf*!Ed*F@WaO2&eP6g8RnOp><3{E(E6B7vO1gZN_Cg9M|9`aoonUN{u3ZK8}m@A zg;Bj^bzY&EhgItdbXny%RIqme8gVT_psc5&yjrTeRtx29vDwlEO3dTD@@lXU&qJHA z9GXnL_I{`U?V8NKdUL*D4`!&I>6)`KXX%94b&j}6A0eCb1tK~61QI>wmFjcup+Zy% zNm9#5zzbZ;WZ{}%#npieF`OuDr>|Gk`E0*%S z(rqGW`VaPg)V@X??EfWOU2elxrLc}l=W4~HzS=E60u-tX(?~Yi#K9^zEmP2&zrr-~g?*HE0js z{eLK%TL|!Ltby2^|57%fF+$lIDVD0*5@hGeE@FdJE1LkdbXqA%sWoCn9n>Nc$${b? z0=9^Kd}NYU=cJ4BakYB5CiWW=SAdIQdVJmzK9g|0jQK*)^wEko?>Nqm#fIqw?%=nB zAAWh4GU8=;0T9Le5!T}0a^C}vqbm0%`>uF2>aJp`JK_nB%gs{VZFL8TuWy>oQJ_Q_ ze9Xd|r_=Tw_G2)msRtYdbG~TNn|4`$4ke?MkZaKzwDAbb&*7sKrb9C7Py1=~*Gggs@o`2NTUe1GJGdPJ8yH%$FXLIWEW z0(*is{;V85SN#HsMSOwexbg_WLG>3%+|@6T6boE9V+G5gPAgqSv5vLO*PbCwv#W$Y zQDy!a{3OAMD!e6tN2Bfq81V>CV8q{03it6?pnFxSvuN=B2^gAms2k`@!5MW|J}R+T za?jeyxwBn0S#~=K-fOxM^Q_b^(>3?Uzp8=K2S7MbOEbN4e|)L$TCHSZDO0K-K2?fC zTXEw_o3}=A%w%>{8Fvz|3Y+uADq^pQA8Zd-KJ6^=%vJ%cZDO-PiySGnbHolE6`|@v zTqk*x_u#%dy(?bIa8|hgNqd(P}oY#=y$eG>A;>UU-S9 za=(s*lE@eQ3isV6N7^KtL$2PmhW2!Y$KYlt*BfWM%Ex0og`qEnCfff?eXI~H%z1T^ z#EKU~2)uJ`c-I0i?>>cic>KF_J=wexOy)Zn#TRzWW>ubJ0A8aLFZELkVBksH(|P5v z^~pMwuWg0x7*qKO1zq0#tR^+4R}wUs%|pbje@aDbyZh=+!@w%ra}T+qNw7D(dI7AQ zw|3cuF4*)dh3uh2NiDh81wSqy3=HnAsyfAPH0&a`>n5_-Q3|K zwmGm)pOs*a@dXD!`bZoB{-L_6$=Lqq22y@vsMI_gpN_huTnrGg9u5lCcVE91rIycS z^B`YY0?(bIkuOuWqEU z0~O(ZR8<2s#NHI-06?XxI{+X8yTtTL)v00krlhM|x0f~cPR5#4NA3LOe#z5%^)Xqc zXCoxVfPN8_nrrb3(Veim^qZRBZ-X@UE7q z*Pson6?dE!3q=$mgjM7btl0q7v*I&CNRUd2-$tZp%ajYwYTjUFftZ~DwvnH~FO=9I zL;I?bIe--7=7>4N;lhN&YWHw`-6QIE94C}1q3D5q_uuZ9Nej=xop3nRgMwwI*D&@9h4WN8BeK+3SB6&g8!o8^f_kp=v@^TRGyVnhQio*a>Ob z4rVD?gN0l|?aYH-7UoK=Z37ZSLG2lcf-Qc2UJhsopIDLCzAsE3oZo{XR_E6a;W*YJ zzj`eoLjQJtmjU$uWd6T=-;d;faU=PEG9mZ~PO{P$*PQ;j6c|`miF};~X@Y@k@qQns zQO$d8-g32cT7hkR?QK`S9V_naTRGwNV+{}e46k{Z9XZIx#4bqN)G+Z;d@UxHqhMp= zt~)BURRA(OR})~(J?;hEKU{r$30u4d@Q=h#lrlO;pu>@ySs|Lv>UrW+>|1TvH^F$p z8NUaEtAt=JJSx(uudg-^$G6W)4WLUY!oOvVbZ*2yx{myGXd8a~I$qMbpGf(>X;M?| zChSn<{Zv7!*}h3455GYI8%?&BR|H${VAWS1_O)=&=~9S8ngDN|$_sB0|4uiZF@oNl z7c7w2ZeVBxK#6EjFA#`Qes5bz?L4bD|LF!vijEcAlQ^m|g8iqsbpT{AKoO>XnZT~aSO+H*>m`)TjZU3Tl!eTj;F(T zcMzb5j*!Ma-7&gQLoJCoF@}*`99%A{aMH8Yo`?K^)6Tj*c*+kry-DxRXa0a=U$ZPmQZ1*5q-6w6cI|~m9>n0XUy@as@vsO-a0h{sqi9e3FM~aHQqQd&2 zdY@>>tM$wH{nbZ&7(W3Ig=+U%0=k8OuEr{xR|E^q094OJ;}=Lw)?D!5H}4ZaPfxgX zI0q;K4LAolfpdVpNEY1)=Gq6uEBjF#K6e$NH#XNBC*V_+6I^2t0#IW+q83aHzhxEL z%YisKzzZZoyFLDah}+}&U%~}i*i8zmzO(eHaEVOz?OLj!Pz@1sbd@%*5voO~+8@>) z@1Az3hhM$9+s+{TKWWJ3lw|QSN@Z0X|MCH8_Qst7xVNgFl26_at+v-1d${7BooZcx zN`p)FlU)JhsFE3rjhj0^Mx)KEw6@^`wXyre*D&F$#)|U`WKoB1euZ3u)#u}Fek9E# zy(+kIlXR95mUfGzsQB#D#avE<+tZ6!9WdJv_hJ;$3MyIAa>(s+2t? z;vfKX944Ys_42395iZqL!2{U;(80PEB7wg~tn@;J0=OTx=nBxQM8YY@*TLzRvtAI5zlx7btHJ5b&ZZ0cY!o z<*!7ZOgPvqC@}B-x?fL=e0@N|p_)&t?zVH&N0uA3Up>I(b~*a=^hW}XxI!JI%TYgF zs>kafrg_Ei^6@rTLjC{8*_*&sS$zNF+<8Dy#CuUeHua)_ATC!y0dcvg$VDMB_j2Kr z=8~0|;F8%zfrPGCvD7i!u+nV%M5Vdpf=fubVWm=*p_vZhf>~|}{NHDu=U&kI^!>g5 zzKZ+IK6B2QGiT16ITK%(nUrFS-Up|pynmI>7d}hT#&JvhWMh^A_B&z-WCTDWcN2Jc zGIBS8rrM+W%M{zK2B)kR9BQTObC1i84yH?DiR+?Z;kmd-JTaqY+o=luve{I1&R_cZZITNn8&~6#F0?)RHf7G1F5DIio_-`H0_ioyRQB*N^=M8kPm_ zH!S+jr>oKWamxw#UpSOgiJJ#y6no-^e%v?u@G`iB{Th=FsxW=`!}=F~Mw`-0Y$wzi z^_9MR=`+4J^b<<)!54byLLa#^H^{Q2-UXl{yCYW|`k>n&srY?!74rQ->o@U*x(>8v z{x75e%A*J;skYg;DLL6dTP|LSQCfSzJVMpm)Ma`~L>x@9#Z+TT+#<~~ZKR5*O*ox} zf7tz&0*Zq~7n@QLV}UiZr64Z3;CYXfj*n-jDi=sCHe;x*b)`Iz%4#ySpl@Y$%jEb| z+Gq2jaVeD^S#CoMo~!gA3hY63S?F{*as=tsp8^#vuBmP=qpRWU2&sc@Q(>D!W*}XY z?W6h5YF+T4M6x8mLW*r$Z%ceuVdg_HFQ^)LheR)MipD$Rl{io<{9Ek89@3U5Wiq9L zUt0rVy}9W}I#mTcXNaFKU>A$8aU!dl_On=j?XSt(lgYM6W0P%j&B?Y! z7G4ss^O-*JK#D!lguxY~+6_2U7E^oBih_CVA`;NTkwb1n(OMn&hO`S6U8q^8>idfK zdt$+mUq$q#u0o^n39D9GXi(#6tn?!FvX0kYhFR6bARc^0*WSBtChc1)Rjt!$(KVBg zxS})ZU&0ccu$P!LycIp)mls~qMTXhj<*t*qk62#kQz)_?_ut%|yUs)6Kkoe86s@T81=LyH|^;juNkhx}T|STka!7?~=sKkdT`^F|G}2P^&fwHlpILJ54W zfR&a(!T1qA3v0`T^J&y#lB2-yC4x$9!B-h6jYvc;nqKJ7jkV!zWomfPA5C^@BaW9 zz1NY~{-H}^`5pO?KXu=PMn58@3>5h~Qm&MVn1DEQrHyhpstOmsd(`uOH+935!B=$L zc2gJ7{2D1LY^jy?K3jwNCpUF|;jdCm!9*e3_Wd6f^+!e5Z|ahi)u8G4Te_I!4$g{% z5fvOttR%*bs)h7iS?_a#q8;_7s49cMbuiOicF>Q1drQ|n@at-wOVl?wVXOC>`Q z>G-WXx`~17VhP)~X)6TT3!7ny+cNP3>OO@Uh@vVVM6x1PNXW1GKpodUnR z1KOZ6l0Y7UlhWq6Gx)98bw|hTf1zv7OynQ_1vVhB$5DJhz0SX-_>(3P$+@k|vLIynfKIat>*7Rq$(iJk^2L5Khy`ST-;`8QkEP9>(}K}1Ybm4%g(h=TYt3XAdT zSV@SLjLgG}f3C0)(@uX{)?k}`-%|Jv#YUa^Tl{i=Zggd>**x{vnojwoqVNH=OA;mg zO&QbUe`WWhguk`M5PPIS3+O(NlzhZf0ei_>TYi6+W`w-BMeFVQUv&ISR~G)Lz9X%K z5%TXZ5O@m3QS7IjJ1qLZe*P6ut<&cT!e8AN229kaJjvtfOK?$$sV8y|aElwOU=tMH zp$QA^ycimPGEwge$)w(AC50f;*(&ht9DT%gO%vd--3yF9%qdyDPt&Rv@^Bfp>rUBBeQn;TdxTQGtT zF|eUN6MoQ^K6#OjVEDsX9p7kR5p2@uyxhQE>im8lJzo3@Drb9PnCLJ{#*p{YzXDhZsIT%{UhqY$@%DqcE zKD{-2i2ZEf+gh_z%29BpLLc@h)1Bm3d{`U{tKs3ktOvVsjX&zkmMYyl*6~VT=BLc~ zRmcDGWkcEU7Cfm9OO5n+wXQyUfd}@Z?ZNOZ>N_%WWP3Ifm6e0)==4Xl-@^B{Vfk&p z3?{%RDP-smBmYL8De6IoQ~g+q;lmzsc~r|C*VpqBKQ@G2Ji$HunVG$Ff)Dja=SQ93 z>;2g{&qwy4Lb_dl?f|d#XW^dHTd1>na*KLy3Sg-$rkNB*$F_wqeuO}H->h{xzKy?_INS(R zXQk7haHn8|%jsK^r+{rqW2{)=4gfDOvR;t~j?t8F7gVf-q`4-blp3K1vTY;f`PI*2L4nqvjsi}!4rDsqv8V`L%|m%$w<;iR^&Il zRR`8r@q%ldhdZzwW%>ynx!?-oe{^8)c(s?~I-TfwQH;;x8#}V$Z2Mt;vm+Z4Ad^PZ zLU2or`j8gnRP?4?SdQ{~KPB3I0pYprVZJJaCAVuw^=O$t|G=3UmLf*6>4;k3GDaj8 zea)jn*|BbO6?7Oo3-UJr1mP7*@+vm*A7hgg-aU-9ZB_gXRB4ba=iZ|=?IELhb1t78 z#!R6{uYzMl;k~oOj1=4NxLATt8w6KXh&Yahq|j_7f3p*C^6_3BpVU^@rm4Eqi)vrT zFNd*Y)?VQ;o!FqzhnvtsNX0Gqa>#lgHkYw5kwaDOSEyAT+@n^-k9A^THFf-SCpLif zXWTEGC3wwsQ!7dnGu`U>GT!| zef+Vkjxzs(zn~QA%=%5vMlxoK$`i$I4ybn!nqfeWJMP>-eK47OFeJmzY>|lVy8#@HtD)qCBG^ zF9LVpiqqx%jERLS$?$5_qz5~#SiQhJd$5k7#~~z>kBq+EaPl~V+FT zPCXIDx+$a1!xdT->&`lOb2w-YYk3zF-wEN{C_ zZ=ykt6T*1UUd+Pw@8r+*Vl&;bXM}sto&0hyW>pfJ*7K)(vq1K3XKw2a=&fGQ-|x*V ze%J>}Q{90(;N1Wuq+S;|xSKbNVQ{ppT4rbSi80L2I{&OTFY`>$xulW@01~ln=detG z(YlBsE6HXK)~F`%26TTbSf7h!hf}vi2g0S6eg#O>FP&kao%e1k2s1UDX1I_pN`_TM zs!2QJhOqiM6=|V9)oWjDlJD~JGj2);Ypgp6jns&VAhj$rNX-J%>Bs6YTfE(2IXy#u z4JRw>r{rf6Sy?}$#*&rwd^MJ=te;b3(-6BvjZH`F3u0?v_($ zg*yN_jo?6(`Uu*f+YPtMbT|r+!BsPCPq481?5xEcBTeK?=CDz59^tDdDruUDO1gRo z-S`Yz1&0A*fma{s2cf%6#Y}eV4WhLcB$6ev37@bBYK=a1!e@S>@8JB!ZODoeP*E+q zaWk?6Jl%jDn((;`#c+*ei_c1HWD;gFv@esGhOfMv`aD-@6Gkq1Nij;cV6rFj9=>*z zZcQWfVRjC}h#mB5HzQJvXhwnn7A})m`x4NhotBOx5qSp2Ko>~xX+bwi#Ol>jYFI-h zK}|-gz~xC|xwh9S08_1S{3P$mn)~=OWPS`_^c&y_Gg4`qnFlDVFF~oWN|X9sm?xx_ zCXNG@!CZkBYlvQ#r#Sfd(i?J-%TP602U{SNvpX9Vxny=i3B-?rH9B>!V!kRSW$FPy znLk#nM*czz%qTNNAF4>ZHL%3d`8*gLA4-(fLHC}I{|k3mP`5B`C2ouV%+L=eQo=g) zne_5S*v=P|J_^6mCxI-VJpf=;UthQ59Q`BGB3X7iG}6{&=R;p4HI_h*A&|$aHhA%6 z`rK8}tu+88ODesSZ9iKeaFRhe)}QIgwtCWR8$RuV;iifBKS%_lO6;xUB+$m&GPMPpI6pjO%IJi@+4Y$p07&zWi@*=<<8r4;|5S=ZPSoKcu)!WaM%nlNTenC3Ti zu%DwF5KZu<-GHbCNBxHz5RwGdDPy83BW}`^`P<2|)gK_jLFB}C;*w)ZI zkapNR&^I}`V3>?J;`oUfskWm~StC6&$YJY*yI8IsDN$uOTR9@nR=$4bvMi_ix-1c| zcA$zaRu7nGmSNuryFr}5B!b{!a;5<=9V5cT+L|E&Pa&e6Y%R7>#!`r4i?rBc8A~DH zssukeP?F)sV9ZY=tpGt_uVju%_YeH;=&Ya}ztTj16&eH#dkqSS6_aTWRlqtc9YGSt zhJhMOr|IWbcuY&yKVRac6q#Bwr5j+c61;<54 zX{T|!UcV;KT0+o~+*+G+uqz#$PFiN1!zITi$0wUJapz%;gzw>1IJU}3h@Da0Iz___ zZmrvsO(NJwj?ON7m5H7>Krlo7mc=Jf4<)%jOtHl0CSX?O{fZ3?Sw5%9S;sG{RnasQ zowXuq!bnA&e7k{d(=pCCsR*EzIt_+=xc)>uyS;t;0#Fw!VjWj|3KB?FT4<(MQr9kPvBr zd{A->(it}qCtj2%JK+3D=z7%{FrcV2bY7Ns2D1uRK@MW^r+I73Fs0biV^ib*(C30{ zQWu@Zi7LyYJp@=5CY`+qpB5W=9IfX^6PSO95tA4d`>yvM3W>`qds-?JDN`}!^&V){ zhucf!=TNLN)~)niDibMFxl9>oMy5*nIW&zj(RZm#q)gN&)Rc})E(A;Op&673-&W+J zRG0jv+4!5hB+-L-Wwik`TSyVm3w+&LB{Iqjt|@P5<3p{oTrQz5@Lh=unL`|DrPg$-Pp7_%D^V7OFa zs+2+O*VznIoh~K{?98sE8-Uh!< z@p}r1#B#7bu*5$Xl9uWJPu!%c9-=*N#DWv86Rp+}U8LrV_g_;PSA{6#GOA2;dV``g zW5mow#D&as3DIvFVh{U?&6lXT14hK%cNO-b)4I4`*)XcXcKNXQ_`L?fUX$igoYT&>-e9_}RI&R}pXe1j}~+9$~TP7hd=TG*F>m@~@s?QLSsB6`@VT>C(hQBuZZr$FjI#7K=9A zzDUS2tH}BQn)gw&fUM%i$TCt$BFo$eSNy+OT~fg(&St5)@A$si(7+|iU!P{*X~3Vfo>$Ih z&q47wF@vpd2IEc8%wf^*0*CqL686I-o;!yH>)z*^=CJ7IkFA5APC6Gk@*cl9hxKfI z8CatNLBG(*!D8|3GJpL&UARZ_2^!?@XZVC?SRu=}$ge)bI_NfY@42jdt9xq+_5&;h zvklc#Nntm6GaosZbwv97xvU%GYx%o#S&Vx*)iLu2{_9-!(7=davAWs7!^%jf51Afn zeev|Wgn^^-eu7l!M}0&+f$5Jrs~`-TwWo9Le9yBo*^7!jwvMwb=r6bLokfb+P+;#JIQCwIVG0q0eUixs~=&7YjlEbd1LWH~SKFXpo(HPGuN-gE)D z!(mGKX%+tu0`W4Cw@NM=^Z*9rqS;<~m=c(6MPF#V?BPgW{8C9Z+mJi>EANmS$x%s<&5QmT>QdEYTxa zMvPp+s}}*1hbZ+gJ0J8M8y+tM8}0W)awFC>CnP<<>NH5|@acf$t?&8K=U9N(8dy$Y zt4BgkpOyTN=YY3TYT({-K5#L6SPi_roWHu5CHcyf(aRmop+>Hhh5YtnHj-`lgr`2w zhI)sdtF2d6zed2M-`SIV^YbjI@9j!QbO@r|_MIfcOw5LkE8hcHQB^G20Ah(a>de}O zvJN@A*2)6dTa`S>%Gy~UF2qudtzL<$dV;-}7GYF(tR<*Tbfq{{<|1z3ax=c{*%WvS9#~@9du&y!X3Q@;z4gHrc+CFjwv< zQ?*?jrcPMxgi{z=GsIDLmQwFFMA)i}c z%uOIMu^8G0KX6RkeYUx^|Bmx)7NN`L`?6U;%M(A>IuVGiDvC3)Z1C#p`L{80e}&d)LxVVVLk6#zGDgN z9rV*A)ZtWN?*(ghz%%Mw?zxl=hkGa4otU%E?qpMUPXEZ4Ed`r7{Fb9Tx-a?J9Oi3% z4>1_r;+oRLN@s1~9Yi+l{I^SKnl5b=$(}!_7FWCaF=aygU~DepEiGWAz#0TB_R%FM zQzj3Ecw0w4dl6Ax-Li(PZ=q%tAM5UG z!^{7SM0aWpX_wx?(nCs=O0c}5a{hEK^H19vAaG4KLENq$2G|OyV~)wIYP;rZaoYSX zB3w?<;wrW2MRCIm_<$Ffk2O|H1C5rWUWtJaij!e7N1X;1gh8oE-|v%SRte^a7AT<# z_i6#z;-^|5ol-Vx0W$^GsR2x(74+3pLNZs2G>T`nuS$`jeyI?fqD4cwwU1ZkvoKeq zSXsflFM}L4qJlrQjG0*b3jXFY7TWywX$Nn-r|=Vb%-7XLe0Q4vwv4s4<^k1!SY9@e z(rCa>tI+_k1cDsGBU)UE8Yf3GM2j=3adJRCDNcq7See8_9Qe7kR|S?V`vU@xP?D_u zsFq|Tn3QONN(y|Y2Ec6J)1s-f;x#S0NW7$dm56-p%P5}TOHc`CTTbz21%SoUQ@n2h zVDacFCoBdyU=eeQFDn2nMBan2kUcx0Mmu1UPJP;~#c8lGQ`~zL=NxzSPmRVsX-}hZ zkI(|L^1)ibsB`J=B4X4KhT2t&mqRsb(M7^n`zjI5_o!$u5(7{2=U!xCZUHCJqGL?8 zkcD3aC)}F*;Fx6p-%z6+W0L)Uk>Z^FKk{Rv{ttj93t>u@?WqNdXwac*06h-WqGgX; zXwj}k!gV))#D*=?h^_o18}sw$AJ$1f=3qcLo3mLw3h;1;-7WiVe%8if+GY}?SX@cQ zrR3)}8nd~QXb|(`x$k(-<-p~$U+}5RS*r4Cn|i)wIh)Yzb4V1lqJ%8w0d|%cu^66v zrCC0@wS)}WNI*%=yP#h^nBK8+^WRBpOxu8+Jm1bbv>pgi$RT!0EtyCw=X>mIVAJl9 ze_-(4_7HEnf|(K_2a#lK_c;$qg#=c3D}{7?4Kd{ule6E`DI|X>l933_ybHio9Y)sg zFxz$8T*{wcfjv%dV;z5G1xxVkLj{R>jxXiEu3&xIe*`Q1oMRr4s!h)GsuR0prXt}| z%KNWm&%19S8EVn9{J=^!-2F2Ogg(pt3n5*}!0Cm2dLbLF1{N*k2Pp6MB9MtA!O&1(bec-+en#0#Jyk;vMibR|Dmy5~@mFwubI&49aNe zNC=cuO9+%{tYr!BvW6v1`7c#_5c9*yPRHV0!#OR7(jiCA;xqtk5l9XIGo!0;jQqQ^ z&27+T%kDo^(zwA`%pYoS#$FY7ch<13%y%!fI>ck`N7QWDT%s;)Ol9cVx%}W-HoOCr zSVu(2T%Akyb0N{#9u1I)T2o2Tq^5V&5TbnfFwWZPgZBU%yK%Y?1ypF0J$wOYJw`x- z27l(#P5g0jHwPg+P>d7t7RkzK;Aj94DtTXOtY@ReE;R!Xu(@Ebt zewVYso~4)t=z&rExr>I>mQP!UE%7^ekq<-i4EcciJ!TGVfUZ~QTCq2luYCpc=zWS7 z8GOtutX+FQOgY-jmV5zyKG04>^08swQRD|-@Rwh~WRoQ(X7F>bu#Rlpe@XW^ycv{@ zQfvA1Y(9BC8|6-6kvp63T+b%BZ>B)-Y~J=&HhG{7eDO35<*5v8RTfA^b7DH0Qnv|v z!7B;D*~Dr;ML>No$3@d38s_pnud*KQCx8f%znR}efPMKgk9dvsY_ke<3>i2}lqOc7 z)5Jn!#gl{iGp}LeKLIMlguO!~GI}-L!MDDKjsNq+-qii-aj}O&k#$f84pH?>F+h~q z{5)^=IyU}mNmbZ*yy?}rlNh+^P6nMLo%@G3FmHg9PJWHLG*IBI)g;tw5?L~#eFu&zQYj6hiz=>;E?}-D(RA& zeKbx}q0}ydNhy4ETe`nZ4H!@-=GJD=_%(>HM6dLM(R-IjZC|M_HMhlj1Yg#D-p9*5zR;h69F!5G$eFUwz&|c_!Gx^U1~#DiP7tXI{L0Vxqz$Y`K)(SXBc~s>>00^%vF0=W-Uc?$ z9Xg34!fyr-dyAztm4SWJVUkz*ChNtE&*{892FS=c)A`Z20P`Zs?mwM}zKuyE0|%z@ zMb5xe)A)(E*|4}bDO=z)ol8|5sZH!~YeXivJAP3YWU~szabhzfoKTDvul&MCzr#%W zi=Pnu-~f{p*84xQmn!?+>%Z4|VffJA22kYT7a>-*v(gP&; zLvFoFg(8rTCbZ+NuyJDBo02^Ms2{z_du(RDT}CfP40dL?SE}6=B66+}{SYrTuJTlv40vhzpfMzHFphtXOr^ zD7OKzgW+1=JQ$DVWFza~f?Xknl*N`Cl8>+jnf$0KRAI(1T<{MD2a2XYu~8*hv1!## zSI_V#VcJ^k=nFE6s!dq!)c8$rsqrNge**DVu-DZg2C3K6i^5F+pIr38E|-U7V6KaM z@1itaFQ+n6JVv!(z~b%43D!uUMzn-NR3u)c1lc-eOL;>J$=domLe!)ve%-1i$_{mK zB+72LMu=*Wb-H7cKw$)*HHSqYZY#<9Wy+P;iCZ41GIpcm)e=xhuJmSLIg}fcj-Js! z8Y5+<>f{+RM6m24i3`Ddxl49y#hflO@_vH#|$YrEbK|fM1+m;XtN&l6v zg-~%kfv(RTf;j5*X&6J(NndVBW;%6;pn-U+_!wH=!UQ-KlZd1w6`oKK#ZeZC2?_8& zyW-FhKE@i*j=AYan1=A;@m?(f$j#idzFIMF(T-qeWhT0o$N zMO+pgHdqPvX#~ZY+d*d(k`=v*I};LHgoYMVU@-9>PSYtyg8ajWC1QY0N`J!{0y0IR z4B@b%2BB)Q`H02Dh^Bc&Qzo`{%kf%>2v7{Bae-RrN8(@}mSI-61K`c{<HhZOXo;f==5p!b&;K*O4lYeExzoK=2}J z5?6c5PWb$wMM@Zdk4P&(uFYVQ`BPAUYH6778f!!R463Mfmxf?j!|hkJvB^e$Lx_Mx z83{;)DN8)q2!8ds{+;Fg)O+WK&?zw4dMytzTk&agOGLK-MT&=55|2=RZb&pja7lve z%T!&;{hgz%^h}Gy8Fd<&M4v5M=O|T7pzhe++-S(CoH~qP6D?S#2CXDPQF6H&cGZFv zYOt1O7g8(L;7u(kWKgRU$=O<%z(Cpa@k=07mAd{904-= zWcrm4ENzjQvd&4ma#TVMR#N*Zk^A5t4jvG2G^W9^S2^a}FlxZ==B*7`4$ba{XBgxN zZ_5$8wbFu8BDcG>)`Bp5q_RF*(4Yp}L5d>i_^CmKQmqI}vrD_1i6kt zu0%PqZ`XjU#y0>rjpkQ89<%{TyLm$TqPAoqyIXTD7^^nDk(NQEnqk>Y9eqm+fAWS}xh!ON`&0|U!yq*^NNXxx4O&yQ@C>bK zM^lAb(-~UR>$IlT_=ctnsp%xGX}wmNNv+&N3u>coss+tzY7+_){2v^(>48zlYE7&0 z4NaQ};74D^sMU3s9%aSR)B;c><|d#^_1Iv54Z3xq??|0y46V;4vZX5vR(Wf|9k&+s z%Q|;K+`dXT)j|(zS_g<8v;cxLnd#3A`jcU?;Y8J<;3NmGg~|9H(V!A^rlC=bhf~6` z0dtbUua-+c32WQYIBj=kq!d6{D50*z@5>xSq8u3?!=(k}>*K<;E6pI7A3_qNBA89a zl{T5Q9WRTMcGHS=SnY!dbV~@if{H!qP9yGJPT-8%xEaE+? zn1=XZ?i5>^A%!HvRPw6)3bl=eNDe>U62CulZi?+4DKVx%>ad{tRNIkc*vOF8c&e=h zU-21hZw;IQ{8Fd#N~m;tW~&s0(kwY87!ks#DC@uIyK_~ch&IG}4Afye^>6&gTKD8} z4Y(wc4g{-8{L(-A7WkGMcQqMc+7*)S3eEzi{|X7NG<1FL3i`DB0a$#wvwj!kY7mH)zC>lHDfqyVO%i4P zt=agpXO>IKw8-&e9HL6X6KIuVq~25PXFCBhRjX;zpif*w3@ei2zMDdkYHu?emm)!(dUl^ju&Hy7bbMzyFd!HWQVt_s&P}5Qvz#gi zu80tbZP4;Asy=9p-9@l2mSD-CR-ST%WM3vbLg=y;R+^5W9N8d8NRGc3LcmKC-l${y zB2cwc^g%ad2LUljtZ(0LjE_HY1TGhGi~$srjlYeF%-{<87bC#oP@&teG<*%1)a#jV zXuzb3wFF7~m9MKD4{eqcHY!I^FEt9uQBU2qeOZc)Xvc*aqvR7S3Hz26fMKh2xE;*0`%loJqQ{@q4in_sd6S7i zB~in6Zh1(mZ2AOA5t9D`oN3w<YbyGbAWw01g1o=SytyX&a-%Zcbi4QK!FpTMNqv zpR*sQIr^Q~yq&Z{Bh`Nnl^Hf~G|D02D7y2S0n9m;P(hJ|AzI$Z`>7g3a*w(IY9O}K zUdUOAH^89+4z&x#5t2Rr)4IZuNbOxhCSW+rY zOg~f%-lktMhCbo|Q`D``rL{ zsKzf{XQ6>sP5%YrP1ZOd?$VqfUWgW`sDyX{?Vg+vZv%moCge!$qO=J~!}$k*8y*C> z=9O22_{tC`#M}P=fOrYEF%1xZ*mfVptx)p)9pYDKG={j5iZ~(O5}`&A&sQP-1R)F% zFHs@>C?lb|@>PuPIY7eo9Lbmez zX`djCs>RbU*GeMvLOrColT-*ys`b{X$keLsd0(|5_g6bcol_1Bwn4o)DIpfTN{`iE z!>wEKbkf8{xJ{GTRY^Rw4|VM>1J;wyd$34>|y>3ELsm zfr5Op3RNgc?&H!>?cYeo*D9+;YmVu8KeY@-wKRmj|8E>TgTR@+R>QD~LM_QwrO~8( zfI_U)CGp>BjftWX#zwNpW~4RjzzY!~T+pw0&QU_b^S@NWIdh7fA4=xr;GxWBs6x$}G2+)miINBe9IU68#FCn>FS%kl>_SQkAO3tFHgTN>&s~R$?hZ zRn+Qzti-#xF)MkKm=;*c8QebBx1yV+8bN8yTctNi7!JN&h@paSOF=^R+z9w#t*}UW zy%BKJkWt)dN7%r)2%I!=@enNbAP6*u?N(`zpmAk0`r<5s`b<(2fKnEeYAh|35b$Ix zEvN{xQh*{Qe5*ES@ReC?FKA?8LLRZ0LWID7AuIo>T8SDffG>tQDv%SYA41egb+HA$ zphcDVqQw>~17rfnf+|%_>xVXC{^yA40b^}x>jVas zhK&Nyfm1)g0(?bet|aLL367-!kpiXoej)a}Yl;nbw{*t;u7)L4P z8dN3ZeA`Ndk~B*1X=K9Xw_~ofcg~gXZH?y2RJlDuffSo|f7&`vv0(47icGTB1j-|E zO`XvY7)1LW3dt;cqzw>4vV+BrkR0<{j!+FjY_%gKG4%pMKol`>npe9pTr2fiTToy% z(0F1+=>7#yL3YO)-CTmKxG~7y{IK!F>PlP}Xqt(=%-{I9vOGjiEGZQkz-}9)qCyM+ z=#+a;IqXeA&NbS{u^u%>N*axLPM}1}|1ry=UR1Fni|oNx15&F);#MVag3JG&Wy`6^ zgR^Wp?Uy9+QAe8QXmdvP{ja46{o5>~jTpyW)dqh36&0cCB<{XIi278Cx?Qs7(}XL+ z7YVgA#j_sQbRR?#Bo4b!KK!F^4}5F74@#B@D@UBO^8NwfxM)k;(xOetHrA0?@66PP z`lGc{Or=qCNuyTE8d{;`#-hpv>J(~sP>CGT6YrBPD->jM=JKFY7HUmT#v2gxpo{ZX z9jMyfZV^9>-#@SGP`fK+8LyvYxNLq~OZn%`D0Zi$d9Mj-mqSW_2i4 z98MKONjj49p*_vKWhX_8inR&{3|>0O^=-0z7}8NPLMV$2#TtchX0Llxdn`h zc0t8X6n~*{BZ-A?Ap2{SLX*`&DK1jnZKL74g#+I-tB}p{=#YlyDURI))gbCZN4Klmp<~HTN7KnLD*_gBZoBK3ehJUA)DtYK&q7lSUcdC%yW$TvfvO4j_UA<7|f7|mUu>qcZl*J)PEV)+jaIYS+C;s;c2wzFKeI^+x*GNE#_ zA@kv!%4?0GF8LNgAx?vWN$t6HB30#%s$@ZrOuwAUTh4+Ysv3+zEW_cxhI#`UQ4wTR zTcrp|S0?1tY$ot!bGw+`*ks~IgdQ}RfIMY2qqHRKN~$Nz4NCs%0Gb))2ou4RQ)O}w zrP7` z*pUcp4Nq-@;jpgSjec}Q6i%Qy(53+`vJ<>>iES~`tlH#~nL?SvWqy0KTFcSr;b|X;(C6NaKY_(JbknQXICDQg)<7J<_%|;kNql0fQYm~1f)jfNgI8LB+|hHs4i5MK5ss{<*Z;ylYvaWN<4i@h84x9byxx6MA$4 z1n`fi8&p_4ID~R-2rg85OSC$K%0@$=650^T)gjyq(eX~O{G_K`VEfhb z86trLuoF1j(D6*_IF$mH7FcALD;qr#=MTj3v`1OX9tA}C9nlGO2z2D%U{HY><6v|S zW@}Q}=tETOSd_+WHxqRGzku&Y%e;pl|7iPSj}d$| zk;~)3Ts3NClQvPdJw0XDH0vczyd)6Lby_f)Qf$}p_@Pns%pgnMW1=(t=9HRK;vMEo zs;PogYy>hZx#cvAw8l^yz0d}w8Rdes4-?@51GKzLCovZ=pJ5h(?b>WjaxbSjv<@LE ze49usM=dPBVPGW?r_XCbg^{BMA<-14T2kzX@aZDDze%#G<`2WIVJRInUVQ$Y{aD37XDKs43HC)?2|fAO z-Le-7(R=V)RPhR&qD-4+=KL*E8lwt`do-|0Vju)%`V~ip0%IsH)#?AtXyEyzi(5s9|C;jh}?mv^Fy~%7watxfE=%s(Dd{_(Vfz ziB(W%=~o16oh7zHef>L2nLsS%4D_5hUI$D0IkOGqro$rq{thA+ZG9Fr>YCL~W;!R{ zadb>t31uP+dPM9(_DCL)nTQV2Bl;DE$r?EjvuMauh>#>?{E8bf>q9IR>RuTOQ7s^96)a8UGIAX)956A7hr0Jq1{#IrXJSN$P z8AY2}G*u4^J^kh!m|`a6U8LbwN~D#l#*A{0Ky`^*Z)x*D&igpWX>2*Qde{+?6S+2A z%UMXh?v4g<-KgrZzj#SE)`opPO`WK(X}?Rg-x=EPL)ve&_8Xx6x@f-_A6LsCQGfNH zK8}eiT7%6MimS8h_z4ePD}Lc8c;8?DAMSdVg)>t!?{=285BV86VJ;1kYh^Y@WU-G5 zG1dFbQDfmaR^2t$nvmmBr#Mwjl;&vJ@m`iW^h-;Yv1+ z&pnTuQVXW?P3LiOD=M8IJ`Z;@*QW4W=UJ#hOa?10_(Ha2b9-?N@A3=V<(&ce5#V=W zX|B3~esJq%yb@}dqVwP(7vMsEel0id(sg7n#_@F*SX}cnop2Ea`lD|}VjTbJ0$Zh< z$7lb_jBHgbU-c{N*`z8A86tR(pO}y5+H_p;puBOhyy{mL?)m{x!$YU*`YL}7uH#du z>&CJ4K>pv0aEI_Lue->G@Myt|#@0c^Rmm)hE{vwwAzadH53x`>050nn@l3%c8eUyM zdIw$3waez7BZTj|D8>4({U6HZFGRtXJH2Y!`)8o`tAuwgzKlpXg(%`_#jqTHzW>6gmiyTbz8m8VccU&{MqWukvL z8p6fVV5u5;pguFPx=wu{Vwam_6_8{?!rw}w=}-}F7B`YGMsz<#m2Bj!}*lI zSZBYNvi@h`Tbb#MYwJNgWypMB?DEs9V31fFz{P3iZk znaT}<`WXsH`bhvBhxv&|40ZK87hrV6WRAAdxqN{NU8*so&O%$(95&42+uQuoJr?2{ zfdI^@tfCk~+7b0xvyHcTa4ndpR~%2MWskG9AMnk!ETYw-5E^oc1w6t`{KYn{mQVgf z@oo8VLqa+Xe#K+cc=I|q!r3&Mhu5*VrtvKa>d-O1JZbx2!{@_@oP;+x0i4GaPUCy( zFh_iSxnDh|rF#rds%Pe=UxFv2vy*!9!g}Vz=0DEgt!M2Gm;Y2j^e5JwCH>NS@l*9| zS?gPP*v!(=%da1S=o~=g^=IETbCje3(YW~_{`!MFH_moj1}>hkXW$=jB}vEg*edwp zM%y;A5}GVDvWzm8+$(bh}2tBt#i+blK@ zNXmZVv6iwQXL=&-tsC5rDTAAtTc}_XkMU_t>DY9rx@3PijK9Q`0ltU54xT$M3w_d9%vs}jTpl<_xR6+gB$o$qi} zi~%E`qrs&X;(eZR5KyY##zqkR>h)+kzu~HMH7+O4K+j&x9YaH;Wk@>nR-L8Ro#SRV z#ovq4H2$Ux5v(cd^OqJv4~s5wiV45kHzwX`=M^cy$uhkXk8^uzFc+ZhwMqp>T?Yqpz#@ zB==N(QR4-C+VN5FGepM;(#6)g)SHev1?V-x2!ZW=M zY$`SWSAFh6AP|u4cXc9-sNd|d7zf>e!rj-oWBD)cN*7Q2=W5#`WC#!NP>f^ucLYkR zfMoFDFce5B*y=}9q#%zrfhqQ_1`65T0+41Y*eyc^d0=|5b;T%TJRHM=Pv)5ri9I(W zea7-t9!k&P0)JYjd}**4mRSF2EeshG;R_c=5b(skb1T2#p$x?3VIJO8nZp!!{%TVt zk?m^2&o@>2o0boin5hwSM^LXvo22&3K?W^gE`Z4L6p#Si}%reTa6r|&(V=Q)KeLtOXH7wDt-NIXKEX6_2r7P`sdUKQ91fpu#73DHe8{ z@l9Sz9NW$KIs6)yG7Q7sD@syrzn~Gka|@-5ZU7(KLK(|GkLSfLF!x^5ewV7hJ!e2? zjkhz72(ELE)$a3HqU>jlSdv1Z)SSPPtYg~7yXh5Q-OoHxuk2&ZT5=DAVq&?&c^`uk z=<@|wc&Td?fS3wbgK%?Z@0Bu~KVeY9SfAnK0I;(UwoBiN(a0y)&8?Kq zY*P#VWGf|!Ro&xT;f0gEd5_n(QUZHbkcVsx$w!Cz?P$9no);k{kaoI-=Msj zxH>+(wGz$z@A16WN;pIKV6jY`jhZ@lm5zoX4qa`hS=$rW8{Z@6eCNh$9q{yhe;nL*OG%ax6#;ZK~j|b2C_PI z%{y@K2ZtPP!$8b%!=^WQjgVg!$p}Z|8;sCw1Pi11X$6DA!NDx}%pcU*oIf|R-e*-5 zf67-$4E*g50Snt?a*divX6&@;L-PAi9Y5-e(T#1-Z}}>N7<-BLZKI6$OWF!J*b?8Q ziD66S$+kbyMXyg%`A2P(fu6hjN+R1P-WkO2wow)+Lz8NGmY>qT?Q>0u7DLeQL8Y$! zX(ooDKY-|Iab+O?#7{}p4W##*;@H$%ypO-qi*>!l=lCn#{7&K+1NpXzKN6^EybeW( zO)~Lq{#cW3CVs{r3z5GEzvHhAXfgFB4QL`Kz6EzL*5FN`2*4;3=e*?NsJefn#jym@ zCE{x}dfnjsEK)#cl{**DY=WV9A08@3w^KR?9#x39P$3}qTk*W41UkhHImXwwQ!LGX zFspNAU=qLFP6@YW43IN}fnrNP9iUMBY5Fs#95l_X-tZ%2rV6Ajp2Weu`HH3J8KV~#j@)fRNhK^qx;RbI7V zU<18$>4tS)mg(3HB)E+17oi2SfM`jGFcZB-B=TNHr7L?Rkxw-$xypC_Yk9R%Y1`66 zM?Q{jVzEUVz|r81JRn#xvw^Sk3BgL7lI5b~>w=a3tn@0c2nIu5dX)!tP=XRF=rp4s zuLN`qNrHZ`nr>4g%hb>uVh;s*Qe$Ozo2!N@9BF(Zs_D25TvHVzDoKneOORqjCArrp zk`TBK&fg4Hdb&SBO6-rW@arAWiJ4b;ua3%4#_RZ!j>_o3i}AF4mtuMpQ^|tG+riMW zo{Qi*e!Zj8m(9M+yN4+KnCUWqIz;hj5p}#EL>V~fL^Uo~;KGSZmairz*nN(IZ=i9b z*wUNeI=aXqniQeyV)#r_dy$Zn4(UXgXOd*nhKGhK{!Ke|rS-dO`>s4GRO!}p!#&dT z!hZ|xA%z_wwGBLxt%DGvi6bHt3DuD(x3>#_Hx#l6Y)754NZUAmG8FT(R~`2aQ~Ct_ z2+vH8o~8m!Cq*AR-hx9(z9>csXUpppuxAs3ZD}5sNP}hHT{rRimwaEi;t$uGXTp_eeN(9U6ZVqD10)^Mi?@pa z^Y;!`Wt&?@`D^_N0xG@Zr}<>j-tjy1kFlRnti^UKIr3(;l8j$+pfg;)gl56^*Wp0t zxQM2ZbfD9^k;kHTh$VM0T8|V^a7rk-g~3DGje0=y*I=W`SD^}thogC9XCPq~TkB@}7 zQ-6WK8Hx3{LmmGrQW@r#)=pc?tQQEn@M=!0;x}!1mo5-@cK*r7bwMeY3;c~PKwotmYFl#91nNkb2%$yH3?pe} ziu^l~{x<$+9yw;LWy$4YiD0+0?mVNLlE7@w^3S>{5v?+?Czjkz^4HVw@=(jKbyIxf zk{S}sq(~Usi{`jAS)n6x($-q+s!fWBPoZO^GUEC*BY6Mr${>BcVMlzx+m|IEf!HndBMHQ(9Q_52dW|bxABj#>TK7>I6AN>}9rg3o?YPe>5rIKMf zEPsdsaPF8!Szw3)Ws{WF%y5}Xa$BkpKG;;NtR5=AQz9%Xkj5;BOAe&yOkz+N4Rv&l z?KV$;OX=2Iq0`4EKSQxlug@h8Dp}xd@iH!=%BpR%WI`%nG3e5M~f@@=WNwN2PxjiNpx#DqyXGQmJ+&4<;udCvt@uQ@7spV^vhYOh5Mf>RJo*zSd4LXYGH1|5$Z z$SIMB#Jnr~+h`?B|3o%HUfUSYplo(}oSRJ1igU1>z_$YZ3yS)%PJn=fi@5SIr z(<0u4jNe?Hp2dVPj4k8ViuM%42sr23}`Gu4t_lrs|^O*JRVN-ME`2; z8H3GS&*ynmjAB;OL$uDf#)s^D6JlH6SE!voj6R7sDrDzdFQdRCSiwJCtafk@JZ$F2 zDse6Fcqk-O+v5DHfp_cc=`qW0+pt0WI}hLRkFhpyZirKSlpxd>9;d`KQO_WGdK^>- zvjzV)PKi)zLTh<_oD#q~2_D!-@sGD)ooY16#$#4M1%c`1a~3Bj5?+ZNXt{(92LZMu z1hLrYr9-A9S`{7|y&?Lrr>4IRP=?5Iz2(Fa`gt&_Y4^!|rO{^0T*2G*Q`$^;w+%7l4fHp~_T%V;QOWiXaPCnL z9-I#XgAf~f2P2BY6Sa93P)SNbVo{3iyrp1tHZD-OVR)|L61UjjfKy{x$q%-YK?Hc3g=q?&_uucn|KIKK)OL0 zdm+(fi}x^oD({ABi3nrG7dK>I=~=%8YKJ8^p3%_ls$cHw_T5mG8PBk)HREX-KYz7a zh>RcUVKWIC+>U)XM*Iwe;F#)sud50VHszO9V)0r-_)~QG#>}&NKSCOf;uhU?Lh*i~iSgGz~AEfBmY7G;!k?!c( z6!lwUJ(li!tP2wgY$p)t|OF>~~?V(DmBsq{9 zSV=S(v-&V!H+<2qx}Opd{F;y0`K%?aE>*%+wqk{{(P6CcAMQ$l-Fvj%crFTZKl zrd=hPg%E79uOWb;e}x3Yvg^og+r3VWA^=%zTPcOSphlje`71ItbX!4q72=ZTefahO zhgb0(=IGLBbSYuGL00K=yRAAAGO#W>=CX?K)S7=oHgJ9PEy6VxkMCfkfsX+-;&4;> zl_vJ99~okY{7}*Sk@_vsyg`1`(8pdu8JOHG}wRokfE)M3W$=DhN%pAs-{vC zDDY@1d|;`BL9B2*jh{2Vo zvWq}SI(E;B00xXs)LH^YGLOl_G>=OeV6utSqsASTN7%u%1f2jQ*0;DK! z)uB8RoLl=WDopK+eL3McfYaJL3qLCc?74iPVFr*eJ zorWT*VEQsT&MstvA3`a$)W7r2`haReW`FV5W{@0Q<0N?q)tE@C;k~nF!(*)DC}??S zO@dvWoeOl1WlUYXsCefhOL2jbNi6bE0oDAny4>@MXenltH=~( zy^1UYXUdzZU8Hv@>~Z#GR2W6OAA-Mhs`(I``4AU8#M|+w)hB-P=;MjAOH|D)d_)2> z4g5&_Ja%eEE%VRSbIMs#(i#f#&`Thx1HV!Z?LDQ<42eH9)BlqBOmEgDi5#ihL!X3y z$fg-l3DV5jqkSrKg_w7dyS2l;*gpSyzmbm1-o>w2v9X=zZq3w1XnGA~;G+!wk*aie zAKX&Pn~Y+uyB+bP5)Qwh4!@W61dB>~RLd92xW<fc>tM}ELO>N;JD?N)aL5i& zK3+#{gAa)=*Yq1Ua8W?z5j0_qXgqdvEUQKz1sBn~KS{Nk99&dMl>^mbf+}hfQC%Xa zs=CW3ZiIcHP(o1?%JvgPfvu$&pA2#iZWFz-Xja$^YK&AB{oZ53qlNlISkySKt9If{ zxuAMTQBJ8y5{+^Qc4(tdD+(`N7LicF$R1x!ZG@z(6<(KZ;cw5;1=xDP2Le7ll4zl# zpVn?Yfu<@$bFnmC;X~PJR-(>QNh$){J~Ul160HZ4BN)4I%~e?A*EvgS84^MzwaA82 zq8#4f)Tv&fy>93ODM>~z%0~4dzR4;!!IdbX7y~$Sk%Udf>&Zg#8a-b8Mh}du4+iITwEbBCy@M<&d-W-k(uUsk$(k^m$HZAKhF)f;wmZE8) zwvC!;x8@LH%O2M~oVQA1A)U?}|FbPj6K$avyi$XKtVOmQh~cS8tXIpJT5g`|G?u8` z#PHKetZATGjabxk%2Q=tsc46Nxc)g7Jnb$rMs0+j=p1H=&Y=@|MZ|8UWLXNb69q;6 zdxjMrL|GAkx~JkYrXgiVu9&II?OyJU_R792gRgv!wGN=5n03n_!+Xg40>mLuk$7O|+c9$ec+~hkMXR0&9Oma8wxsEEFUPS=E9j#zT>Z1fd1fewkTBO9w+=aBiiM zz=5;nf`%fRF4FF`rc1cdP}kdrrb`>)I|ukmDlW!yFQC*Kgd?^m)S4$-1JY+s;R>3l zLa3|Y)ifQmnp!Z0F4}U^6U~L}tM?gS)|Mwf&kOW z$6HQjZJH5MsUtj$o(=+(ZU}9c1t$NzAq%Vf7$lYb`v5NVWnJ4GCU6NrL`vC@c?-3X z5~R_^i;UtKeXu)pksr)-RJI78>L`U4`f9M9lXO`q*d7N5VXtddPiy9ZP{fA4Bx`(N;G}D(vr*W_&?1Ykfmj}LqESr$cOx-b-I-$H>C|VgY zRR~&QvVfMp_KHh=*KBbzGMMrkfDlJJcX8aI&8bQo&>>#(;peEBCPS*mToJnp}OiHK?DoMzqI?T5MK2+gcV zjdN}ex~jbM;1MR_SBmd)@y!t51>&1ZU;K>w%ZaR+?lM0)ktOM~hx0bcta)8eG09*E zti$7zSx~)JXr8b|;^P{L4@+iEe3O)i^$D{^XmgO(qKEv$WY*qx2xxR6P!QK3-IO1N z%A#*b?qxs+pwiS(UcE#pa_e%3EV<-Y2~q7tQhE0u;UP)!5y#Vtp@EQgK6Lo;}CGUoO=nE`JKf0LDc!4$R;~|(?rZTdIA{KEL?Q_MMrN&dJydEk3 zL4h?Xa5eiMUi1QMtN-hBUI~It=7Es653wJQeK=DCynWI_F?R3wL0xX1#2VM1_qUdu z+kf+@Nvw0T{aF0Maf4=Y_H6}-7JnDQ;xX;(_wDqUubjkUdkq0QAeXL$IS>|OnPhEu zF>$NxT|vD!E~Dr*T?}NA*JZ-DZMI$g9c9egryRF)lw+s8PHCej za5ybz)75r1n6mhmH3@e5N} z554p?Z!nd`d%lLXy_3r4U-8LPv9UPxu(RVTr`*BHc@Kjsj&x-qMqM;P;#Y_7n~IG9 ze@x>QQ(04AEb+x2OnY_e+}SV8nhFoy&2@N#Y1m(Pc>=#Z4GWlb5>NT40Dnto0~<_$ z{3{z$AB|f^B>XU)HEkRusWXp-bRaSY4aU?%N=p$qa_Y@5!BMZNq25{ZP+=`ucilGE zTtfSX#6>FK-KYE>U2f@$%}2S|CMPKqJ2{8wvrz4U#X>dCtv`5(E(o=fWK$t_dzL6! z_wj>v7UdNMDpZtnP57<+k1w(az5YJ;n$F_=cl?j&tF>Z?x<-t$8<*5n{wK z#Z5z7Kv-)2wr+D~E%-|nNkYO`)ll4PL}p-A#~^3a!9hZYx+U{#MP zR|k`d7)+*B(}>IGAfNjZ`&>Wy0B`X!w))(-&xgK@{Ah}k{o;@U`WsTXv2Azd1Bt&5 zKP(NF%`dagZ3@uDx%83^1PQ&w2qYe*x^9t-`pd5@Mn) zVIEc7e=e4dWAF2rxh%NnKln#Y9^F1couO#1aEAlc#GlB)nycNlumMvy0tzQ_zj>YK z&t=0J{`ND{pag6ZHNJZhx*5k@*3_qw(=*XjxGc|OEWjgv~)$GqZIHo}e*uCCq9+uXByTYyW*joLtKY7JGX11i>rY_6_ zTVfXo8`@&;?SWr$%Y4?@djb||D5XLI zTW|5H^I5Lvb=26Cir+?le?GQc?Oem#q_Y?Fht}|%baeWk-{QZd1K(#2_kN9yX)zon z3O6E=EYa}C0GbBy4uQK3krh1aHEim8t%8658k_0)F=mKPD(5%wUJKaso)!Vk-M}|2 zV6pnP8~DuyEZG06ZCZ{cQa6W#)07MQ|KzP+XUltcg!Xn)neZOT8Qq|gI$x5qE_pAz zg2O?zq;_5}R!dtMSW!Cu#;?E5GWErk{KbW=Wn@QWF{I;RH@1f@XSgSLrvv`z zw7kG~Q&_WyG=Rjs=|HgsERfi~`{?<-aXtbARkI`9i0v6$uS``qOJEXHov@&Ab2 zpd&x=cQV+H)|W22!o=9WSN2p;^RqIz0yIQpR;QFtU&4CpuYAfkEn&}kUc^A~q*8wk zXG__nz&Qlb?`b|*Eq*1XH2?)?`QoK)xW059FI~#IjyQo-D0NC9QY;dfv9)PEA^tu6 z$e~E(z>4d}l+o~DJyc~zU$jD4E6vIh3Zz_u{PRd3GH#`S<4*IDnXJ8TFJF|&o@M17 zaLOW+h5Df4KRH~%k=5WopRnJhc(xqE9bp)SV-U@2u*eQ7}7>RrEUYddz7c=pgq6*0sl0I zMfry0ig8O?HWnw+akY=)m&@tD;`A$B$}qyY0#ds5U>hiD0K>hN`-kP4ggo*3iO0>0AD0>+gbp=2pyu=uSQ zEcUi$_InQAF<3P9hN+#fJ!Q2A^&!xEh^aM98ZmC%Kq^sRv2z`#PjGqBOl*bEHSYKl z475*KyOR00g;g9fG=U%ObZI@Zp0td@)}%Zt=xALFc>k3wjIteZ?UzgeSxk$+`>s|~aMF*qziz$6yT8RcH1JaQe`brJcr^d(9p=kt zcf}U&f>q3`O~*qN_k=g7g~eubb@{FH6#U?h_9n%HQjJnEiJyLp1@=9^?#UQ_{Rs*r zmgZBC-FroIglXHdv!q6A)0V3Ui`K5{3~!ysx&&Cq(=?AKLUuYH2ig67U7#r zicHZmig@%EWK{PlKk>0|V;q*cjIVzi`|ZM)@hfEhp2b_egKYRJi;sT?@T@HUA;Dd< z_~my{^KWPJmaBl@n#rfGV$U`Tfa-fv8JbCa4bwSH`TP0lRoGO%Xf-#i#t!Y1OZmXn ztQE5sJ>uTwIul>Gnnl((L;Dq4`tYUv+tqBce!+4cyoUAEZRX?Fu*K|b;A8&t8Wz%g z-#eOg<1wf4gL2{=HEE-hAcK6R|3q$H%S@)88))h=EuR_^dkm${n01~HUCVk7M$b%t zqYHYKEYN$t(GaG&n#GW#SvpCY#kg6sge-;yg|_W6Uc8pI8u9>59Bubd2Q1j`QFJus zJ4x{h6D1E_vA7L7tviZ#3ED2q7SzCZ4T=v+2sZK{u#e%>vpk%$z%Czy7<`n&M>!Ic z4ssPjLjpdt)QjSw&CHANf8gu*DH{ge3pmDCj{W>g&YJh!xc-sDa<^EY>YaJ>krsn; ze7`{IQk!55;*)t3YfHFVmCnV032a||Y5m&u*b#f&h@w!sm=9RT2HNb4MHpk)5Bmoc- zX`c@#N>~jg%=0Mbot2JW2%lLRUNsm&6V#yP#6(}%wRDkaz(lvhyyLqpkQJkQw7$!F z>Oa}dm%Ph5=%sJ?_IFuxzkIC4Kqlr?ugsfQNv6u_eY^rL`q}G{@Lu{K7E+q~dF0oJ z0Nz^2ZR=U5gNc2xX2)D1Da@+CG<-G9+8m9! zil1?|f6Q;MXYJX)INj3ZJ=B2nJNbzBpiy-}zy2O;VJgFtgZI9hbze1l@4Hu5F!-pD ze+4J~hP5JR=z?KI_c}LjK+YUkKo{xVQ)N;}WgB?{=@nvPgtBFi;VRs~*M8z=H1gyi zels2VWMS-KH^iQDmBkz?j>weVhMvG?$2_E<AQH3jVJ)2fABHb8SeRu$>FdYW*p~lZ)8pV zp!{U3(i;!y9l+_L5J5E3<~JXuFLM#j9pEGj-BUtB+xKT9<(ovz{`$e{tF}U-YAaLY zs4<2DJzjP`xi2N?~Is;A_g0^3L=zmbqgJW$wSVR1kIv=#H&=sGb~k#`7G zGY@#`KojHGpLakc&lW+MvB1O@r0zcegIks{Gl3pY)T($-rCv6|i&eK8>hGGOXUJ!Z zM^zo6X$@?Ri4oQ72$~rTyRb;EP!E@rR{eLBcf&f~yN#sCMP(23#C2zNmAdEw)q7i= z2T5OtGq@{P78LQ-AF_y`^Un~Mi^`zgj4njGgAFk8kutkofA%+)OYQOuc-P7&$??qET0M;TFOq7#W`2Af zd&CcKWvz5?^WV0zMSZu<6ctRUqZay!VnQM5@0Hl13MxSh@>JD*I!!LF8lesbaGVZ< zfz5e*<7cdu_d00lZL#4ikGzZ>!OK2l*`5nOAq8ps%RKpWHa^^6K(R050&78hBzFF& zSHz4@pgTfdd`ngD#g!pSYy!XiIqRs)<4wL`qu2oUn5TTf+WCD;Bf}dsGKA72Muyi8 z@@-#WWcbnR&gx%4)qm7p-eDUiPJNU4^V?Xuerq8=zm3hqoLSs<9B_;Ll+W7^Stm{B zySGEVXg!@*ZAazI{)D&rlEp?&{Sds<_;B@$U>IqYs;%CK45#f7MXs@w4ASfsdz>l` zY=D3`9Cp6>OV+&8Du`oH7b+0OmGG*Jf-f5Jg`=n_u}}(>^U!<&6e#;Q@xQ-hYxJg< zc}@Wu{1w_DC-WIFpvoux8Gf*Uwba>pMFAard(2yZ#o9GWK~pW-4NT_JSU6)ZpYRp) z?={4QPbNt`yO-2*cp}|A`N?x{&s?Mx&=PU(?L6Q96`gyVO1$C(6b)()?p^ye8&vPu z6rn^KUfIjzzh=)g?E3-b>}(C&c(262eXJkOXN5D*mK&yva$W$Dp_CuS;LQE>-Um54 z{z@3m|2*^X5#JfcLK}sr)g}Y%{-{{?@IS(se{T;L9?83)`0r7Zkxa?3JeiCt92?P+ zQSiefKAo_Oqu%%)cRH}4(6%phPvrry@?<=CAJP~nM$r#K(+r=i>IwGW& zg)PbId@Q4__TOr0xMlai)0}8>(QZ5pd;3 zI6+}+nu}tH`!dj&R{Z1b6JLan;qgi;o9K;fb^{|1ImSDLvd5PJU4~%)3LnPbRBSo0 znD95;RKr!kdP7)E=Y@yS3Orybz;Hpu7OPn5P^*D0QL%efEEcbfYss2xyw^NaFan*o zVGKBHXq={cB@CAFJxhb>x`n{})u7K~_%R*sX*~@yjnT@^xH!#rI7DPA}5Y8W4b4LZlvI|3V zy?SB+M~R-z`|rbbK9M@;UFxqh;&PI)qf9;ObCk-CY1I;>hBgEY7MC^~UtXf)FDzgY z{>HUbGX{(U%MH7S!k2f$eqG?`^O_!qU_*5cZ3Sz{$MxsMo)JuB?;;3?I^Ve($X zuYSW!VSp)zI$7u^igd)&_^Ay=CJ1n07;a3VsZ!BLVnu%8MBZvY3-5FtMd@U*;XQby zf}xg+Q$Xe^Uw(kTE;%qPo!4=g9?dV+5`j|3oif> zXKB95;@u9-s`3f^5cBKFo%YijDwk3I8CwzcRl+sR_R^Am&jS{1VJz6605ZhB(P8>0 zmvW*8+33K^L&xO zX;rY3utI>Sy8WekKtqj^6#xFb#X;6uw`|X#gY11>LhaRo;di4_@b5~4FS;RX4tBF& zOigx}48$8m3aNNHO#XnXAnHf`IqXsw|dYBonc}l6CR(svb34J8#@T$@)0qp%RrB%1C z1dlq6R6Vyn1*B=tzdZtm zT$JGdcV(ie#eG-?neIM#={Z3 z&SBQR^-3IjrZ`Z#pChV5X#RqJd@^k>>M(|nI*dipd-L{eKFoY{`mHbUy+<&G(R?GX zK7z}KM!&#~-vj<^J&*pLjqz`SbPLTlb~q(DzM81uYO=4s$3~8}tN4%KLzpAqy*xp4RE9m%YT}EpzQ_1DDyUPI0 z>F&}_bLm1Z>uX)2P?&r*Cx3FHy;!voJ$g%J;Sr|EDyO--+|*otS;y-avnJ+Z z4gMBBt@c;3d$$~YplF3EW;&ce6%$fB|mi)n$A1&f#zu$W0VU>?W&81F*7Yw>nn%=k0Y zbkFhd6U^9n;vB6K;_$$j?Y`Do7bQq6%4C4b>^n(`2B^t7y5LW ziS8;u#4G9-HgTn*?Z`Y5KJl>D&y0Z=(a${U0Or-9*59!5qaONRmSqcxXZ51lcZI#0 z7WvHBu=Q$FI5q70r@zQu) zsbDXSV>ChSFzo{#L3D9Qoh21L?eJ7JIwb=;y}Hi1j#14n9ofxfcCB|h;q>teICbB0dq z7;6XX^_8{)g=xU}Q04sxq)lO*aY7l{4BFLTnn_siOJPncHKAmx?Vyr56}sIrN2)JM z65>-A< z`3{OvPE06frz3+XD~e+*EvWPHG3efh(NN6A*MSvNsumx+k-?f{4Zz&rqYao5wKj{+ zP7gxs8%oTNX-ce?Dqpl!S>M!_mz1*JfuC_`tq1>EnYY^G;hnFQKZSF-a;+_Ic@9fy zVP)*KfJ<$#E6RI!H5U28iT(DF%ob(iWd7BUSZMpH3@g?f+wi~2*gN`n^Z1f0tXciR zSjWM?;4UafNAfSuupY)HQK;TN;KozQ9LfJY!`{$;`qoo^e;C0xo@G7EZ7sEa^DsX% zEvi^<_PRLXM=AI|nE!j0ZP44_J>ZhaRGPVnuhW57m(-~eQWtR8_)AE;L5%H@v79k z%9&?og!*TW zQOC!B_ciqCg|0_RJ&is82HW$2W zDcRqg*Oa5(kA9vK(58K!(gb1RmtojvC_smWWzTBtQgwnvzsPg9{)8`#Wx#6RW5u~AgYN|oD<)dsVZnwqai5s@H%tb%#&S)1+F1Ez^3Y&Uss6Xt~`kF1-Dd;-YrnWuk(5<+11Zk03sJ$36jSs-a z5K7aWft+1uqZ-eCiIj}|aEx%#2de6AtL}W}b=KZ^2s{nr&?q zot=z+?zG~8h{cQ{ChMs@4q3qW{KC>b*G#9x6^HSjH<)>92>MIR6lGN-!dOfeqCW}% ziux2nX9A6j`)p9}$f>UIot9#Cd{1C7z|0!9xY0h;6X8Ju1|5Ete{OQp0CZc!uzrAG7MmVfyh!m6<`HNwkAtRt<{PyxkYBB`S^EsAWo#e=UulRY!-3 zX5&c>L-9DF{M?WL2LYu@8LlG#l?^dnn?`c&c>tL8JIC2xKcL#4q>dE`wNQLmkb|DRdlef$Aec{xJ| zE#>duWN`tPrcg4B9f&odPz&yIJ9C}F{P_1*^b-PKONQJ{0|ica7W)` zP+YL5IyZxIm22Ga3`QS|>Z`+-S$diWJOh+Ee4&Fs-n*lNyTlgmKFpVS-MYYPHKDNkVMRN(#{uOBsCw@c%;P4V2WqKIFhoL>0CoORnkf zg{a0cbNO?>vmx~_U!*3b+HUHcz(4;Tn-CtiuMGk@Ur+`IKXUME8!_A{8>#d5IR8A= z01w{gHdZ=6<3nzvPn^DxPrJ=N)#nf94gO#;L3F{cSg)iqa2=`|OZ z@u)wUUqI<=NYubNj~sZ%px2oAV?+?W_&nttih(cLCfZwmi!a^7~{l(h(hK+yhi1rRG zvgT^;{RZ$6e=&>gM7hHeZLhG}HT((a#!!2y<;|}ac}Y%5M6y6QVcW$C#nhQ9ivpe* zDv7f82Zw`ttea|yc8Ljt3>&{PHi7jGKQk2>2k8zM@m(susp30Le3Qg?D87959o8&xk_A;uT=5qQ0mP!k zwBL`m8#Y_`$9Hf8vTZ&8^A4M?H?80E+`p`YPCvc>p5=F0jZQzi@1Ber_NPw2s5gJ* zK2FW#_2zr;vuu6+)q4g#U`O=&sGhv;V{F#`ERUx?W>@rgyYoZ`w(P(B7T@7u8})a) ztx1#tzPVc}H}ny9W8xO!rB zpf4ZjAxHY0?JL3%7GV!zX#lkzKC?i_Y64 zqDV9#^g%=45m@5cn)yHIF%Huv;VTWRX9F$#q^I1$YgR3$zJ;^8a%LX)C z4eKZ$_vU@-%FTWHzzIo%q=?P5-h4(~xtD%u2fnGUyu|Cp-lBFVU~0b??@~`THERP5 z(MhZCFs;DKLZv4_rVV@e-WM-;P z;CX#No?2h-)AlyTn_!_8dUu!SuZ8D&s^?EIQP+=Os4sW+;;QHN4%4Zg__2oU>r)^w z-phudfp(aF>dU)%$szjJd-CVKPUgFzFeEW&-0P&3y-$CLVgDxE1KC?m6Axf?q0$%32!x1uF9aW2`k#jZp4dgx+rs z-|a284Vw>KR#6(^8YwTSfQRw|ELFc3=(K|Td#ExT7-cB0?<03=rU>0Dt#Rf9U0Or5 z?6g*gV+X~^$zD9sM>g9wL0O?fuY4@Lredbe*bOtyM6dD_I4TD_(GeST{2vRi=y1t@ z#4&|jg|`hF4Gbhajv8)v&`COFiYJ0*!a-x%Pno9zbrJGqSgURk(>9P32N$rOm(g!0 zf=c#_X)k8}PdEQ1rJ>4FD6aAk23sG%Rq;Sja6@cQTlabr^9UDvTeCv1>2Ghg}{z($cMy zjptxNfBANohxk>BZ0q#^ITmpinO8sSQksYL4b!~#&eEx_PiFLc85n8B#Z)=#Y?_zy zxB-9@$~``zk?bEd7;aFTE~a@X`{6*BuA$d8h6Al^m< zR7t1da^5U-u}EhhV_-{u-d7H8{9qwKw}sFEI4fb?+fVN7xf?UlIQ;SkAM7VbcWZmLcFG!1z+|-h>~0GKMZ+F6|4_)|9wqa0@(hPT`D(I&Zn@(7SzR%A1x=@u)7VkN^- zl4FR3gR<&>T6)Zx{pb>6eOeD?GdNTlAx32hKE;N^G}nU%9EBs=h_jXzrOHs)ymyx? zpYeZ8a=-RF;m3yVq4HOF%pK^!tm=FVnxmZyz&KTg+$3EUTCI~2d~9QRlF6dtQyYjn z2JRiE(GmPiV>zTr9rqwO8+=s!JI`Ti9Kn73(IXLikSCVeOKVZ;m7NZsr zy~(t$yvSdU(_aqe4Fcp|O@HnJZ<&91W>)E5tHh!R?v%SkgYHs=^GN}6j6N!uZw-(K z>WuvN06E)u4mVXx83|?-uWnv_Yv#3Y z0e&6GS2mRc^=kw9=B9G6DK?D+8il5aq(MIjG)(KvE1Jqdojd;m6lS!{3a4R6Wfgr- zo)lXr(b7c}^)mDYaql%n*lTsv%sV!d+vpp$<%!MY4ti5tzNDEPp#P^0f3KN5P`|ki zzuHV5+5VX}Xco&Ou;rT;{?WZ!taQf_X%`Mtb2w6r7Kf>68~%Kd+|_n91SnDmuE63j z6$!9pUtL)$673z7olS(x!EhbTUF2SWBm^gSfTPYx3?fdoLtQ`G0+nhjrIH4V5ZpF1 zAP9+3a-0!kw|miG;^5=JEy2<)+OX!Nk>$8ZZ}u8v~1ICuFji zX8Adof7Kis@_WI&syP(i3KMV8LT=H~TZF*Xb=a}zFx3Tw9gAJaep|KUc!di8+nPVu zLhfZ7OShw;nMttTD?^Ix1fszie^}_YnfG<*hcf#OdIdbBp{~B#TH7N_y(0YN8sBY& z5RQ*$`8&xo*N_Xl=t`9z$}wr3=^3p21|16)y%xSxuHml~?3Qs;%yWb0 zET_=@ro(V=CzN))zgcb_I7oHw`;_w+!nv`{5%NKEf?S8;;Rzc zF6{Z@s~3cB2)pXPq%9xTQjQLN2QJRuki@#e42f2D`}3jrUxpJtcbgAwg-TW0n$K^A zV&Hd`uWu!{(pO*M2V2Qu`hqL`k5+OM+qtSI!%g|U77i!6Q*J#82R{W*x$=ZN{hz(k z3_sZ3N}H7IxArAbhTCx=+H=2C{vI)-072@-(PC_@BCq(O%Vla-462b|m{`e%E`2XX6M0K~-5?K8dfhkWBNPNnD z6HZfV42aa9bHer&c}PU1A2vX0?&}Cnbh>NBLKbkGD+NzS@H7K{E(WY5B}d5mmTL7~ zVG$8t|bzbr(W8a^;~-m4bZ*Fa4+Yl+ zTPjmjcZ-wZ43%LG4ydd+FZ>f+nN_Jt-7bWJ1llZ>KEKrxtPB=n7gEol0DewbWuQ|2 zxt4&aWqvM#n#4jYt5Gyu3|cEIR9G-@L#YiydbAKtqIX#RYGzt91^Z@a+XCUe#Wey9Vcnz~)!_sQLOfw$}^`}ezplB3m8 z!P5;5u5BXY@Gnu|)U9g!%!tF9EAH)7e!b4qI?C5|J4~~G5-hNJX~(lHS333=CUcUAF8^> ztSEbTo^IoQ;OoPY=uSWIL*YoApDR55OR7?K!E}F3<= zkGR}@$p20k98T~i7hDF|R=L`RC?F46E;x_iR5zFyn&N^}2u^gt3FJT84JP+)F1Uc; zU>EE|H&It^LR+P!P!Nz^9?FTJ8(c&19UOyj`ll41b7fzVkbnyo{&%|I0AgULD}0j9 z0L1Dud~8=_$*ePcNmpcXzcc)+uCl*Ju zQd&zdkLabk$`O@|L6vTOWjaN0#1$Y(h{Xj9v2Aj}k>tL*l;7$mn-hqdG7FB*mWWb8 zDuT$YL{})${J6nIqI9_23y96&vqUu{$oL-wE6Br*(+?fIS$8>9UwE1i?k>MH6b1h2 zs1sCDwGvPWcFUn~iaHpSG**Sg{7&=x-H}7LPw|#Lkh2F)@ew`b2wVCoR|H7bI--?& zqBg96kCfEHc|j+{AorcF9wmXo`?kjm9A*h26*7c3H+>VidaU462aVIQLJf<0FVf>|f|zMh!WO@PNI#I0twg^ENs z7m*~2bf+uTMFhK*QL`vQF82&_cPnDT{f0}*KA3K(Ja@vW8lh4NF}nyP6Tu@cvF4Hc z4HsMh7#+R2G7m(NjTE8i_|24{S~#FGrC7kziJ>Vj21K?cp0L%5Nr-Kyt8Eg+x0@?~ zfH%1q*g^#TT<#?V%Pv?%=+<>5ko%3}weh78d`@?q5A6+Aqu@B7-5VpGO)d{bN9>Vory1YNM1;B&5KqC#Y;%e{!;U>8jEY?Yf_0Yskrxms5X1(00ApS zR-2-Ha=+n%MFi(ua0R&^alvMSce>yTofM1|yATq2$a29VMXAU5`aY0Y!ZCiZ4w~~6h6@nCjZeccpW9c*#THa^N|)gunvT;7>jvBiySn} zM-$hd5LY-k{Crf1OC8^9$qX0Cf`bMNuKm7u!4%7C!2Dr<*{t^|6DnaVw-V(;89v2D zA%j9hALF+MkP3K|cnQsXdEk5gibam-kqwH@CKs}?P#CvTohW8w3 zG3~|;FdU{H9sr6Bb^!Finte~R<{Dms6_aU8V2Fc}FWi&(ABd~db3}qhTRtS+Tw|;X z2UJQ$1g}uryw|ZDh=+#{l!Kd1_oN`|Jd5T76nrq0U+&3^!sMp><$L2`#i(M}4v>MX~U1$^uvIf}jA;vxTFkZkV1 zyS=){(#N=8*wk&MMX-x)r8s6w`0Rn9M+dgUU`qVB!fMaWfV`DfTlm94m>{*3@*dH0 z-{$6Pw2dV`6bDSL_84SclBd#$a5(`=t7|+jTJCOZdKLn%Z7o({GOI2yd76}K9Ryst zpv>u+%7N9cvt!Z~yV7U_8-{v6qI}^vSBiZ!HqGH*+uxL`lxSj=a)H+1bB*I4fYto{ z$RfKbY6<}0dK2!Hg>c3&*u^Pk#2H$-<+NG=o+gk?1agg06rTK5(2WoxKTM1MAsmkW z4h6L&0OJ3wE&f3%J*k9%9<3*yY9%(d8cc9MYIyv&w05xUU++G|NXKeVdGMBl<;J#0 zKq&d&2wtzjju?L;)Tsf2)zh%Mv3knIs@*ggoYn5N(zcFyl~uOJea%RVx{_Gcj~0aN z&(MtfJ|b_&thmL;VTz%GZZF}x2g{9oI|=}^{;TQ`HYn@9wCB=bIYejkxq+q*&z)aX z^C!(bqM4s*=332Ms+rR?)2f*rH8VgnWzD>GU8Q?LGk0s|Ce^e_c^cx2NTSW~OT9Qq6ovm^MjTuOW77=5fuuu9-EOdGwkZ zVYz1B(#*S>>8T~8nPzs>%z>IYRx@X7=3+7tzqC&yAd-VmrO%HS+__tkBHRGqQ+Znh6U%+cmRVGrOHt@$)ouzh+85sQ75j z%+}14n%Ur-7O`fo)yxZ;+2*|JKKr~(>6fJ48sc}&?07--@Q!9a)XW|~s`#0jS+1Fl z%2j-VX0F!E{hF!2sJfdqbEIa@yJ%A#_GyU6ni>6*iqF%`vzjSgQt`ty^G(gXteMR& ztL_stbDfqo>6$r4GrMVKBb#QaIjIIL*UX)o`Ke~E*UUFHGea|{YvxGJjMU6#nt4m3 zzfLO?LfrVI|E$Jm8>?BOHM6&7hHGXU&1|Nb)mq9fXy!r9{6aJHG=I*B>O2LvaaQAF zf&rV9pdn^z=5o#4sd|taXmFke&(zFeni;N{KAKssnbjp~3QuZgfo8s=nd!nr`AgCe zy)`pbGy7^0`)IH;MSnk)qK8kx+pnk*=WC`j+-Fx+e2Qi&6izMws+X0TgEK&)2B$xT z?^~e~GHa%+nb$RcC7QWgGcRZiex$+an*RoXMf{UA#7xZ`sCi7(U?)Q}wG>%2bEsyH z)XZ_38K9YeYi7A-9@NY_n%U!uR{z&(h?SbTR5Ryk<`m6zG7_vY7^az#nmJB0muluT z&1|BX&hV?tSq79hX?1x!)nd7#n#oU@&H!0IGj1O)r+Hb@jM%d@WqUZJnT3_Ni*-MXP3VtS|>j8LCBkaq8@;b7xGJJfD4% zK(a<4e6t$R=Sczx&sU6)oBL*K;oKy}zZoHS@=Z!o38rWw%==ou=fMbhs?HXw39Iaq zn#S-4sww%XQ6>DL@mfa}`uXE(_EdkR!j|o-S+GMjD|Tx5eAP66sG4P(nY>wrebNNo z`cjR?K=>toYm^+erzTPEChNNF>GYgDQ|}oU8y}l!?$VCGFhOp-r|oz-O1GzEqCCl< z>$#`HRM}|oHcy`ZLh9T(b7o4tF6F+=GvAe`vA<+d!~MLJI;u+zOseyywd>?L@B%n%CfKG7DkJL`>dCP>Qi8N zl%x@|hWJO85=O`p+5uvcLccg2u=B})eTy6H#OER0e{n&y+@A{gb3RXSOYu=Y%MprO zkf)=fD7N4wBH?!+%aM?m%4%7@EVqaR?0lxfo=5I@6B1=9JyBlO5dV9ia86(DED$aC zCjENr}$9u?0Ym&L`B( zPB>?9vb(d3;DoAu+}R~0xmxgoU3^`SlOC}{4_rNjM=6oF|4^-;C7_M&TGXeHWkY|r zsL*jxRZ_#ceGC8oZ)t&)RswrOj&=pJy4i_Jk|rdwyQk7Tn%^g;{*k412$C{dWr`|! zfg6c3*fq`&TT@SXca{)$Y9OID8WrHyJO*J@dX^7lxoIR|=aUTk6Ep*xQjq^Dw;-d^ z%tjIl5Dt2YvyKlaaiduQ`_sv$_$b_e)p5{L2^Yab__H$UE475JfSpe=?EgiW!u=Ov z&{7G9Lret-427naaETk?3fTWEuPNMr5e6+SuX~!4T>OQ**@@>G@a25mbH_7D<0}dD zGY|;+lqiDK1g&!;QUd!^IYdoRQwrxK?M@i9v;^OkrGV#Tsahp0s&F`9=VOKaX>Q3a z9O3>e!JwrQ&VYw?2nYtmwVO)JkJ+=g8C2V0tAH`Rm*LO8`%oj|4R(j{|{~pKz1|8)*#q8 z)U0ttb}hO|n-!q*NpiCjE)w3Ik2{k@!ubTi!ZKLKYT$~{1|>o-%Jy!CNNH3)Bg90d--`~6g%)ESFe zgYizm`x@RT+yyme4pzYC!jgqIA_ZH(@J_)y5AWdbb<#wUmg%Lh@E$s=mwvz- zS*e$X+VJ_jN-rJ2`{qyVA9(?ne;K zI)O=siA?gx`v+brnMoI3fE_Qx&7Mo905_FMCcNG84#9i$MJAQwt(w84M|h9CgfMuQ z&0w$fVJDpTj#9?@YY&@GinD`AE{@d=UPMN%#k= zlz#|PLYZ6n9h16vN|M(Jqzrq7FldqTaX!Y3$l*;&fjQp{3q3$2pk{=nPEAh@o-%__ z35~!b!iL!da+a86z@;mq>Zl%P%?=I^7lewMI|HXn;g6WKN9TlJn?l4$r%|vz5H@4V z3#l&z!X-a}ixvc@KZz4zQ=Y_$u<0(G4cx?vz!@$i;e^NRCvb7XU*40rLB!0uCvnk) z%YPCl=xuodmjHS;Nh){}DLfWFflCw-7XfDmVO27T!e0e&`9px4OQM&g3}}i%dIAo{ z(Pb#4z@0}s{YcSz^VQ)XcYz37M42mRpKZQ2#XF80}cj^(X3iv2p+2j zDhI9{X$nhMQ(LeXog0;G0pov6cr5#6sgM#dRrOQzEmBH!)xwFRP^b`xfP)E~jY@0; zAwz+5E5$e@29KD+ZQQIjFb;;|sYc1BNLBh`z??)85De+k5VB0Jg+=0$(UH|q4Vm<+ zfF&GGn%Nd`N;8d0xIsz=?XbD8&Yc__-i6{x4&QTsyS!0ndznewW}=lt>RSSDc7p>O z*OeMiX(l!9)>OhR2$FZTv7&woP17?ecq$m}g3k!NlkhgESA7UYB)mZ$nxc+mFPM~9 zgm2dje9Nl!`g&f^!Joci1~pjkdpCGTe@2#hz*lm|7qd&5l!4e=;s~*4s=pK-#ia3g zvk^exrZg7tLf|$K4t~kq9d-{B*v13-(oL#Y?O9eQ#gHr~Kr=68{PVBmCV`Pm+K2as zMkl!z=2yPL-Y-wIcH^eWQUtOgat16zUzDZi@kZC9^hD`XW$6@U&I1awGN z4G-1L^E2Vov%6k3LzrrsWYshnRCAyp!33o!n?a>0eQfs)*aDLT|Z; zH*toVkb+v6kJ%-+w$*~N6xh6u3+fhyBi#>%s>&ONp z6mvf<=x?ZQo|(#@&@aIuFZgs~wmPwPnCi3dI@NpE^{R084XW$3sOnUHi!u()P;okG z+rYGIoYd-|X6G+<73LK774{YO=~gO*eeA}LSuW_Cq4GSXD%jqk5R!WdL_t6m)aIye ztpo7*L_F@VR1N(g(C&ELQB6~hc_rqsqp;(CUQp~O+nk{M$r$k+_DYheHpw@S8tT#6 zy~!KBR0I9izk-R^I{9T^kydBXkDVrZnD1al`FTrfXzVK7==hB4;W#%vL9Yr9Eb~W8 zIvc7p8_Lacze;ZOs?#@lRh#2MT5T0>HVV(t0hJi(VyG^)y_K<@Qd{j?jN-zEWo&+Yh8~P#BCWOx zUowV_32`1#3?!ZB9n?YMqqQ^dmZj?H0QlJ&(ms&pH9kc&l8}JGfAg!wRU4)ClxOD zs&j#g;;y{Ip)4|KQ0rZRewOI-#d*9&M~hM{u&8iQVL9!n_3T!oaH^Wdw=np_DfzoO#__8r# zczc#t4e3m^KT`tDOW{UGJ%b`j72iSMn)kBN=LE^+i?O$ij92;y!ZX0glDr)uhg&bb zZ1mC%*at5g1*b}fryT>OU-Fj(-eCPs`R-ZjRRt1_Wal8|Ud#n%F`U(TmUZGQ#_63z zW1?tWILo^B72~{O@wW*L?eFgqUIj)_`T-vAi1;6^-LG)Qg;?9igVJyKJ0d2stM~cT z@Hl_|frj@oHN?p25l}rQXR99NomG!nUE6b_p@`Tkx)FQ*`8x@CvqPWwl=t^u!dW2U z?4p9}{80(Tcpgiqy7WSXDPmTKBI=)`tXp0+@=C<9Ip~+x@wWu{v(#Hu0K(Oa}fFhe|F_(J~c>U zKPj<4GGP>J|Ht#N^g{loiYe`AWO(wg(v89Y+Y&~PJPBr8jNQXuJ@5u`VO7HDdAdAm zPCa@N!MIF~C7d zG~yjYKIoI7LgiPgkY|d@Y|pSpZ!^r3^qXLA9kEk-Cc12!yq+vHwP6SLhc|rU zvu@aCluT$JFNcA6R0MNUdArpfT_Q47aFRcw%Q6*r+v`ew2I?L2X|=Uyo6}eP*EXY< z4oTK6PDt_)27`YSk^~_+=MP5zo|1r5FjHE?-wa@6*OQrsBtG+5cmKiY)%931=27)5 z(LFJ16E=16{^SoviSF?yvH1rNP2Nukm2>#60r|Gab^cMw&vCMt0hdX-sQS0rWa^&1 z$3L!`N7qRHtusfo?V*8uNB`#-Ue&Gpc$~6()GDuQ{(5gi;IPksdDdJrbRhR_Z+9!! zYV_|X?@^Dz(%A(asE`6C8*FcuiEWAcdH8|lGoYY-6;|zX}o54Q3=K|4}-uwr>_1Vddg+Sy5@DG z@HB~$DCR3}z*WQQ@lQ2bcVv(o4Jdl67qe?w{|TdYra7()h2(MqDNBl`ygbH12K9&jqW=77gE zb_Bf5YNBDydBZ6Bb=zl3{R4zBDDmGxt>ZJGLYW@bAEe5YTb)x7R0ZX^s$f=Ll6Il3 zOQLf$E7GZ2Lb@0?b!`TqhyE#FM;MV@_y+KgwH{MDpY4>A&-BaO?;PHz27o= zo{NQgNGY z!mTbC)JYYU_fkckTop=Yw`a8l6M<+(#9vMBA+S$i=XP8zZA91%{5r4+-7k$(2CdiL zGKTin(auv{H~)ZOE|6$X*wJp~{>d27MIt1OwvLeGOzWIKv9L)jM$w!ke#}L93S?)= zfJU@jBBFkHr8Gd*@)wc6sQktG^Y8Tqo3p8W>>4mb`UFl5=;!2SrTT&noq_DES_>++rtNa$R^rZV^Wwcb1E?{gdxGj6rpo<}zbnbIH}3q)eC zQr=IM8X3b~$x8b&v^oR5@uEk#c-}*~HPV)>QGYfDoTsx4hNpTY%OIF>L*?qmqQxE@ z@ff43sW7L<`MXz-ad>~U$sQQ-X{wXa66^PWHqOzJJ{ec`h?7?!{23H$Cu{71mc90f z#$J1brN$m_*=s+mF`gCIYYcm!rG~oQR@(zDHAbTzaH%oIi1uFJsKl29F3Fz`T#MI` zdfd9T&G?1RH^p^^l7Y<9fe6EZkzL8q$sqF9r)`{8qq7LwkBOPN2=@VhcJy1PNJsS; zOw?b+%!lFs$;6l{7@n>A&l$=$epvPL{K_6na|(}q#EF}&IP;YkH{U`ydOM$9!RQ~! z2s&$5*~2w0#vnDVm+M)-%#OW4ixX3p``(NePRvZVM!0pY{ntLKeC6O7agJO27#({8nJ&#-peet{atP1|ObFPczcFQ-hd z^Z(Z8Ez62zH-*C4HNM1lUg(AQ!~0UEtAjFph|pAry3kz zm5AP?1I*t$?i{an+sl#B8r&8PsWQ;-PNzO&tU=Vbg0Se}Mn^Rj@jixtG+V9n_Labh_)Q z8{avu&J^`uK2?3yQpXcVa$@=*V_S;Bo9mQ;^c~>g7k`h~rX2b3y$xx(HCxTSF z-$AVd6Hw6rr^$g-yWc^rvsFMPwkh>4NK%JN1faekt&w`G?Mkf&$MUCJ?U;$uTs`D! zveIhn`uB_hvF4yh?E$U4lX&D->ks`hZ&be=Lt*tpJ!%aw?iRCN1_h4O6Fp>wQx+NO zYA{IGvXL@r9O~>A#behe9=n;LPcP3r_OQOkZf!hHYvXZR8;@bPHXh@!Zf!h9r5>tp z@#>-amZ4tPSiOffh+1#DI!GHN)mfeILZ3H(Kxu^V(2ZqU*JAs~xUSMHY)0=`SG{GC zb?t7px5)!_kD>ZNrI`p{fl)zSHFmNq^}sw)wK%PSO)VKCn#meYJKf$P=Vs%=ZOuGg*oi@O(?yEBG_M$4Yzg_KT=IN@sD$_J|crp(={F&cYznfw6hJekw zd1&$3;kCW0>NG-H9jDc*GIgs}WmdkY%DhATT>rgvh;4fADIATY*2jnE{GH z;<9uKt$urqu>Ry(&%?{erll_ z_l#=ht5FBk<9keN*$Lt?Z{{Wj##s2Hy_vrU+QmfZOP`haz!$%^pB`IwlngzntwnNJ zJfYOnP7X^=kBw^Q`H)c3`HpTeM^z$Em4LPQzOre9*XBl@nOc00q}u)J7wMvS=OtNN zQ{(OPq4!Vz^8?RiU**dh6^i}Nn|oJu7s0$CAE&)pwt%y6y7o_Eq#3 z_UErj9^#qSaH-RlbyJ{oPSFG8oc{dT4QEKcAZR$PGd?y7u9UW-S`1vu-*jLE<<-er zym_TR)8{QWa%jH_dXPuoVSv|}UW(wkJz3gKH87HM5Ja&qfl8~bOFl9NjF;TGn`htY z^h3!14I@Rm!%dNw3tkgtQvOQF@#MTZyT@K-J{u(@^*Rrcp&~o1){hLX`^0YM5e~fKF@Xlq_5_iw)s>+s@tCJTEQ>Al;tA4eo zsp9fmRk0_ka+9I8<{b@z@A|pLy%WIJG=3IqtUD#vRKo zwl7s#+Qk+p1U4OWF*YJe3tZ<^u*St^G0|S-f7h-#{o3^w|ENlQ9RI93-RphXYvgzX z+r5`%mxh|Uh4W|RP75t4YAp`;8D1Rk^F+Vp1FrBE4=>#{_;jQE3SZfR^6h1_!YvuS zYb*MU=ri(U-|!q??_S36&w{G9cb2y#7Nov#`j~OLl*?UR%ns^*)5VPcjkp8HcQHjT z_aI-E589dVc(vPJEY(qn{(*K4r1FwmZGTq>(<6)YN2^vvc~(Lcrq$NQ&y7Cg zjtx|187gZwlaJH#`1tXt+rd)DPDi!Dm|S-{i*9pVzhm^)qqn2KF#7ANY~&*Zh}xp` zY=rrMs*Fs z1*+GaYNo+2WSV@r%1&mr2ipP(yDZFD{XsmB5W$O?7lS z4%0?E&WdNAjCX9B>3hWP@pZB5CyBi`?Pts*Jj&LV1(q!D&IPrbUAA2 zqNys!R%P2Nn_5C6D!1z3v?5$#R08^@#p_XvzA_4qlcHEzPSAM!$eg*_8ho zpK9F<`M6q3;j!motpEO+alEU|QHLrIjX5-StgCf)P-i4bVc(i`-k_8Wsdvwv#^B;>Wy~(?9`V$W?eC4je zu|*4>oYXLQ*`bE}y<&a&o)zUy)1IB*G*BxSt$1=m!}Mj3HN540Zt$9|&2RhGy}o{? zxA`6e{&?f>jpnDlTgtb7>3ik9#F}kWTNk{(Yx{%Q?TbHN<@@ygJavls`6D^wvYMSn zF`$xUIg>s{YUm&-U7lkaPA{$Da}G`isWAw*+8&u7!N`30-;T_We4JrZY2?mExF2-0 z`;*S1IOkKq9%`(jx8GlKXR2dqS6_xs!z!=N7*$@$7}lz9IG#=_!|gbEhL_6lU4*lr zV0aYt(|*)A1HpEkxYr@SuKo7gz|1~{Zx7Tlfm^XCz9@h%TVvU`}YwX@$jXA11 zpJ{_3asEmSZ+3B?^YGZoNH_k?xLAj7z3555^JRqpddg5+v!jP78@iGX>es8YV}h=w zXx2Gn<<5wM^DIM$*^^<1*^^<{*q#h$a3RB9Ge|9@ov=TdV+>G8F0VT_YN1tjh3B#3 z6i=njsWWulSjXUnt?ci!*)H*R8ae&eI=gc8*hFx}RgdjQoo&)~JVy8Tu#(sU=(=YUIV<^*p=8zqigi2cwqRFWXY|x7->+CW9 z|5Ft6TH0p7CMRiZ$32<-b$;^r?D+k6Nkr^u`)P|YiI>a`owc@C+a#Jq<-BBF+N?Hu zRY)h0-FBoB$j)?xTtBl@txgvKUe6vu_t;HEo!71*J@#jTry`XYH|d)Hc*7U#8lP9v z4tvkmwI>lp*}C;x<0qYar!_F0A!YYEgrC45-9fFfUEXVlrdfAGYwV1W%=3zS%{sU> z-oskuG-)-q`MtJn+uB~o+9TTFUK8(W0?D|2;SL@+)*K7kEvxYF#wC-b61e8qL(dHV{eND?NWprK_Dn) zE26_;M?zA3{LLY*#SkBxF;n^?f3E{07}7q5U$Xvs$QU@Pp_p2@gij2fL8^mVYHNnC z>vNUr)Rm8g>uob>wKd_eQP@{JnfQz|gMKN(H9%&|YlQ9D^1BZky~@SlV)P;p%7ckY zj*at|dBdW=9Ie{t`Fla0W$Ov|`BcMJ^03iuoS4|fgNnWUeGj@Wmw~7F8-%K2OapWE z(dax)hL?FZ9{T-(EXeDL%SIN6y)4#*?~UF)#H|V*4IIPY1kh{*f(<*Z*!M<3NFLUv z9?n{BSWVxvdPcq|;>3>UilDmUP^Oy9uySYCq;)Q1ZA;W&U6Re@?KGxNh%HIW*u(K097+G^`K*VU+4@c0hCwi#sbMo3-g-%7!i02}g`xy&_L2 z^(4sRnM8nFont*{m_4=2m-AR>)vHz**1{vk;8>y;=LUeNW3i)}SRgf2E3*+D%#m-7 z*V8FMUcN-BMvxktbF1yCY`D2bh@)UQhaXOgye&}Z3`OZ|UK($XeE zaSDHSk`_yn>TF2XY(GJ%Q;O3C`82miP8Lha%R8y8GJ73_l!V#h*lqmX3yffZ9bENg z)h*V_AB_^d?4?-@yvX0Hz?;q0*4D>A8io3^`JX=;1yxc)>p?ruCE?xboG!%mv`(xi z3#u-&?Db@&t0egRRRC|WdaHHuKaCT{D3UA>j6_$Q>7bUvCu2&yp;Q4IKx!FHT5WCo zr_tvkDaiF$m-YYItV?G7f3?9^aH@cp3=XQn`*Kx}U0qeEwHw0+c?=&Espj*P`W7S{ z|6OY9q@&Iv&T|p;s7Lj)yu_vaMSwThw!^yZsL>-!VsyUf);()j4H%9MSL!ve5KTS% zdMI0&Y;zL5Z@|N%PiQ-;CDUg!Wp%tczpc;m7Q`M4u?lsUy#`10{{brGnFO?hS^@+xt0oiJ4$lJe%=+Rd zBYOz?$K1z_4*n?#XooOZeSc<7u$;~c*scB5ZfSGcFBUO}Iy{%!;CMY+J+~Pa&>5&h zi8^B4KU+*~p1851(;5rRg~*^>(pFh3qVPV?bQ=d7+MKQV(lwhX7ZK4d z38Sd-j-Vjj|1TpyHk2!Q!0|aw^nM4baX`Y{QJv0l9rZirxUk!8+~}ybb6h8v<|9MR z-m#OFdK>H$f4kAm+Lg;5iX5%y8A2X$!XswVYKcSoB>%=-z1uyB!+k;GF{Ir3PDW2k zMt@|dSr8mS1_ZO$7>^t@yI-7E5*3nnI;(gGJ(AX~4$>2G+Wz8EN}UdjyX|O9tE~kd zv(KrK8>kIIXs!LcqgtYw;I?Kem%jDi9`ocgq<*R;PD@S>s*@@GCHuOl(5?_`oO6^h ztw2Spm0AYkDTmW)>kO}Xde89H+_4SzIR;#6>o;C=V61Hil{ARVw1d_`t!r2odX&@9 z(x9|~RE6$Vd%PZXtm>HURh9RWfx+Tt+szJYmzy+FF%@<>Dy`NrwUo`-c>1_f*{&`` z2X!&Cg7gGTTK$HeETjOb9z#d9#BnBZe7w0FN$3um)kiht)5w^P=Ur6zDV8&XhaJydYU?S#SQMsVM#9`KKz1V?ev>PdZxW- zJs*(rq(8!7!20u-El-BoL-)tVqf>ezfA%ts1bfzpw6S~W)C_Z&cKHdO(W|p(>KoS^ z*8B{!RDY-L=80Z+xEJAP5X?@B^>7Q9dp`W@w`t;~ix@;VTXMyBCW|Quebvo?9-(bhOOKsivN297I$A_thpP|e< z23%_E>kPBMUiH75hju6tlEBbk(hW3% z#xyFQ$(@wzne|e@bT+62%z|G^f`)lDoq1@%Dqr9b1@MI9YDYDZaGV+0RF+LO&UQ!H zugLy6dz-_#ndUGZ);luIv$gPMrg^5`53_R-A*yt15j@kG*j_S>AF0A7%z4)~3G$EPj?DYdY|^@~L7#V;Dx!=22UyzeAT=`)n_k*n7~Skg84 zmeyBCF!<`@Mqa1=#xfXm)!(Hy~Kz?Dli43Mprrh&Ga98TPtpH?u^)rzigkaQ-mz2-HJb8Jo+3Es5gc- zY-W!iJ5r!TZsYJ2*~=^Yab=@%vcFHsUUk_6DSO>zQ>bk46u0Ux zCyTRnw(Tk!j9Shesl0{<*8&bIsh{an_v7gkU?X@Pd;*fde1)x`;1n<(Oa*hn60iom z2|fZxK=4&V^#&DS444eA1NVScU<=p|+F$h;)^EC)r*C?riy822Iv6seo>={B=`>sR z1{uVl5ok&4W$zT38P08Ky(d4UjqtEI#bvkoBSP*oRNSSv4ZSJ2*YTx;dJ&i2SLjusH~x=l2Sa;FH$P`Axy*&p8;`j*m$^&OYr@=S zm$^B63wRR@Hn}vHVlZyXSw;Uj@BBaKo&V>&bM>F|&i`}X`G3wk|Nn5_xeQ<^_5a|! z^G#nDnim+G&OgB%=d;%LF~@A`)7RYPG0rhYN3FX4=BQ2c`G8oV zv~8};;mbyw!^Qkpm1d#!M3q^7Op#UTQXHr<86tOnDdSr!&B2cGQNn|&Y_}&lTsX!K z%Y-quANYNOb;=mChZx@CXnr@wJYUpf&a!#QS>~0FqlMOUqs_6$6qi@pito-c$Dz4t z#8~rBo|ueA6!W$59jImetvCl6l=Jy6N5#pkr7X8g&t9_iiCN7{K!6!V;hR7aas&Jq z(8Spi?eN&{d`ry39rz_sfnN#ubFg_KJ;m+}VEvNqru%phfp>%2Td@qMwx9~H026OB zGzSa#Kt^_NT-6&|(GQ`26!sP}Jb@g6`!T2$zLABU@S|WNex(PuVr(lw)8ZSzU?@s> z9dlwu$ikb!U}WJ}z*uDWoSDqA$r*VISD+8S##GT0$ii=e=a7Zp2Cc~MnWIyRIgBmF zUj>sq^WmjnB60(qnp_qh3-&S5EPO9Gf?N;B`3`>=^TJE|Dy4YK26$aRTTZ~=f}?n> z`V+GQcuCAhVYw`QawCWExhKhFQf`A+qoj;1II#GDqJ%XDV~77o5Z# z0FDa(8Vp7jz7C8<7QWHZkHd8*%K#>`HSTd{_n5VeUH=YbtuZujK<OsTXYyQf-Y+UBz1 z9IlAI@N5uZrbKuiC`A^Qsi~33?kOtwJebUn-G3TIlvo#zt>Q0%Lb#@aH$xV_73@bA zt^)=h3*Qa8A-ktn+*36&g>w`vB@n{h81rvN7On*eWZ~<9kf0uPwjOu#ptM~1?kINS(k5Oc1{ zPCW@)QB6QGFFY9>MUKP}QZo?3-%P?$91`|lL{UTz!Sg3GcR=M6hrhp=fUYA$U6P*N zm08}Kz<3-Lz5_&%-4pdPf&U%YO?@D&eo5>dkjeoe`77R(Pz#q{&7Ea9PrN~M6e?3X^iFtVTQ&htei|`#!Gq1#PC-rdk zGW3a2;fI$Ie-gb7C^kRC8zT$%T~0-TEPNK&g&c)<16fWb+_#aa7Blb|uoSr(9=XEy zpc1}drKBtW>We{my-sH@*`EeC}$}<^g2*{pYc;0C_FNs+qLB z2^qd@9W~iZ-V%Nu$P37@>;WJfc4a7c@C&vqW1LSovRbdy1aLsyfo})l7#8Xgx^E!O zW|Mp2b2sufwB^;XXA^0R9D*kT@j!-WR|4%Zym~WlNq}Vc*GE8izu@z>*m5=eD9|wt zf9}XhI5zMl+tDz5wIjRNRk_z($=a(OU^^v6_(K7*@Ii0@ISCKk>I4+N9f-#=yZ)vl z%T@vJ%UVCCLI|IL1Q~?=^T)Q!_d}ir+U_tk&qv;m?B4IR9KC&@_(7Ul_$a7Ab|2p% z$9h}>){~UN*MaTG_I~LYQG`M^Qojxw?qUQM{s^o`Zijsd`)xw-sX)vNPX}}EXA>ZN z8(5574?hJYnS|d3^9i)@2cRCg9X<%e%)uB!{}w_-rVu^}e25%{>wy>&mTfU23%5D4 zaMF>}J7L(%x{V`VK+_|%obU>;6*&Q?ww?@94S*y>CGSQ7T;3 zN~|DP!&d{@)g^ojklkFuTfjbK;X~jEvhdi~=&&roE}Yr|1;^AXG^!t>0|I{!rXjnx zD9YBwxnS&XXz$@2UVcV3s-`jk4gQH za6f2&jHrfF8}Eg`0`rL#Vc7y$k1U+O!%hy_2Y4Bf94=dyVvc?sZg6DbR~^~CJfL0l zVsB7mQDuhVSzt1h@TO9VhNKuyP4x@k0ybk;_(jl$oDc@G=0Lc| zPGT2*;Y-1M&Q{~ zaYyDxEcK=%x537TwnHKK3D9jWZwa>m2~ZoH`;l#?7@q3LTvevta^yC6<;NstjI!R0 zuxT$fAUQUDoDcngPw58$Ir~TWB5*mf@C`sZFT(eOICA<}3qESm;|vUaB#?z;SMb+{A_D&d$mh4(r__l+_L&Gz6`7nb{5t4|oZca9=$*q;Kf^A?Qg{cL zFGUnios}hA_BnQOQ}|I(F`xdwdlSna(e!>nQKKjdPY1^1q#3*o$hUhNJYc^qhvAt( zw`}kYU)pVd6y{isPJ|h&9zoPRA1|thMfl6feIVZTa_-8?!{jIQg|~v(6wE*tJ_r^er#HuQ zVCDC8w}5P<7j8U4{f{iX6|^G@?*K{UHh9pF^a<$HgyA0lBv0HzQo=tTCFaQZ>L<$o zDaxbT>ETquzXLig;qzG)H4#JAu-9knhv03F+y>un*!uPGHKs=mrc6iSH9)tPu;F*? z!eKC$JS1GLWui-jMvx$+&2UzRN6kPE!8e1Y$Z_~Z&^nVm0sr90iql@M2GYQ|PkWJ5 zU=pC5k|Nxh)8NJAr~R158q{@0f+K_SKx`M!8|}vojFW) zEOPoFSwfB8rJT;Ylb8^Wfp+BdiM*IW@0ucys>QBw9Lz@+ehe%|7H)9#gg!S4I50l2|3!ewZBMV;yrXWY) zi-&pCW;!(y_>$8+y5WhyOGbKBX)I3TfpF599yOAVWf=aklG7n+!BiE=0i@Q8z#APo z0q2de^^4(~9XSra>&We}f2>DUK1__lw}V4u-Uj&H@p#O4pd1StOPv!ceAX|>`7}bp z7lOESq2O16WX1$sash830fnCdvx&K8cxyFDK=Dh!qkct_Eh0a`KLF8ppEE4y58nzF zMydZrXaq~~pc(El9m~9ZF+6T2=|=ru4X?S89Lw7@!`!v0n(czYO{NrxY9$CFlsrrT& zcmVV8cupRb*h-x`8k1v4?CdXiP>^;_IM7E z-cH#Seg}MrEW8^WKz1J{EeB1X$Z?_h#Fp^Mpd4BFR4^VneRL>mM$sGI#jB3aqvjG} zBq$;YDq&Aomf#Y-A=vEaRa<|9499^KMd4o!W@*q8q7)8uwn09!@X&HDJ-~eW)NP}~ zY29*+_kF{>s+i0!Tp#1F0!2N%6pTj}-VCN7rw=qW^g*Ym4JU8}RCqj?f?N&14`dB; zJN(6H-u`Lw3cTYAuUhy7Ndwnh!;3Z$X!z6y%sfi{Ux`roH1|f3PF!uPF@Ezm>0ejgm?krIiMI>cmW6_r|%-6 z{+CNjELPL){58{W@H%h=S-2Gha8y>?9r~JbKZCSCkiKt2?%kMtgyr7X(1nL*gTctc zvNCTZvT*9g4B=W<>&-!5_?~VtwoszD2gUPXJ#zZq5JTT5vWcaAGYGZt2Vg0(@He0d zS(g4?!qUI+baFVHy1quZXQhv?7(?@!$i>L+YZ5M%`xsL9D7f!fkh>SY1?$N~!rz1K z$iiK!I35aFcqrJ9?7m;eefN&s!84Jyh|O1V2pBvWv?2>%2V%QWxNop{7tJ2BaFM7M z9t|px)3;R^`WB1JSkyQTec=V50aj1q?=(m6Ba*S;US*te8~gESMBo7Eb1~aI%~{;l2w=?nwG4XrIQ%DBP2Um4}dJ zf#n@6ur!DvS!mhkM$%ql3vQpyJxSM7|BJAZ#pyCyA&b;cx|y_;atvSV$WizQAgvj9 zUvrxZu_9*RIY75&@RE7F{d$Tn{NsFf0wSy1eCoX0*&K~r4gaq@d@B9|c?JGB#-F@R zJABTaKHc+iEo;}y-DlqA;{bYEE%-Sw5}6CO)tPtO0jh+5|2UZu{RG^fy#d?tz_l+x z?-$t8KxRi@xZr6vBOu4Pd0YK)8JPsjuI2K28T}W}ke=uZ=PxJcBNxNm=FM0Qp22rE z+JSKIcyRBAkX;dND|rDt6V7bn1(1aYHj(}lQBAw7A}2Ip)g;~={h_Up|6&%8={qc8j-n20Q#nINFZA^1_y4L6(Nb6Pk*8vO?N zmTj0vUoP?612)G{e2C!tgS|1tfF}a^N)^7dmA&7XSp-jgjbes84PFT3lTCQJBMbL> z-6D( zCLg{KXb<2;jx78;M{a<(JF@Ucj@%AczQs#CO#LrH6o^B@3msYb6-Q3M=d#N{0yh!f z2g)}y<_`yCcLn;wr#Nyse7z$_;k$vjFFP?B9k~e(w8enpc{i+fk=`#-?%^|m)EV3)uU3GO=x>Ivc-QtT z5<~b=6nJnHesDLNe=xKa{t!q$Fy8m63-*wH=vTuFfdokSms~qJAN?utPOuPJ_|^|8 z9mwmslKpd5; zRMtAOoEQ3@Bg;i3(}9?gdn7hGGS^9{&mCFLHlGW$JMbDumP;ZEzOeP>u83b~S;l`5 z<~k4L*3Kuvb96xD{Ll9teL3;-WFU^p!Jn5pvYhz2%8}*Z&-Wc!&i~Bh2y-#dF`(*n zN0zhAzjS0d;=CaCl@lU(oFj7!f_l-Bs}B%3px*{w<;ZeW{^yP?w-t2%#x^6j8_Z3~ ze?tahR}QrO(vjs{+aW;oV{%97)j-}@&IkRi^FYo5%}m;c;EL|C1S+TNm<@lA=D{EKQuUxvaedYd@$(5m|{HEfj(xz}z zMN@54v}sOLylGKWeN#hIQ&V%(=B7l`_NKO`-A(OH`R@JXsx=O7MtPZWtUtPSqbai-jtYUTL>hY_qS5H|TSzWt2x_Zv)`07Qg2~mhT z23oqdVQtge=CzyGCf06W+qQQ1+V-{k*Cy84g-Z$L!d!51{y<+`HjVmrH$dn zipI*u@r~7uQyL?UwT;onIgRngMU71>npbRIkyx>P1$HWlEXKZBqP6|`-Osl_f8=?! zrglwy&7w7-wWVvrYb(}Pt{uNNzIM^t`n5~Nv!r32aHH9?Px~|B = { 1: '普通文本', 3: '图片', @@ -236,6 +246,19 @@ export async function listContactsAsync(filter?: string): Promise> { + if (!dbRef) return {} + const sessions = await dbRef.getWcdb4Client().getSessionsAsync({ hydrateDisplayNames: false }) + const names: Record = {} + for (const session of sessions) { + if (!session.username.endsWith('@chatroom')) continue + const name = String(session.nickname || '').trim() + if (name) names[session.username] = name + } + return names +} + export async function getContactAvatars(usernames: string[]): Promise> { if (!dbRef) return {} const normalized = Array.from( @@ -615,7 +638,40 @@ export async function getGroupSnapshotAsync(userMd5: string): Promise item.username === roomId) + return { + roomId, + groupName: session?.nickname || undefined, + memberCount: members.length, + members + } +} + +/** 退群检测专用轻量读取,不执行成员名称或头像 hydration。 */ +export async function getGroupMemberIdsAsync( + roomId: string +): Promise { + if (!dbRef || !roomId.endsWith('@chatroom')) return null + const memberIds = await dbRef.getWcdb4Client().getGroupMemberIdsAsync(roomId) + return memberIds ? { roomId, memberIds } : null +} + +export function isGroupMemberIdsBatchAvailable(): boolean { + return Boolean(dbRef?.getWcdb4Client().isGroupMemberIdsBatchAvailable()) +} + +export async function getGroupMemberIdsBatchAsync( + roomIds: string[] +): Promise { + if (!dbRef) return null + const results = await dbRef.getWcdb4Client().getGroupMemberIdsBatchAsync(roomIds) + return results + ? results.map((result) => ({ + roomId: result.roomId, + status: result.status, + memberIds: result.memberWxids + })) + : null } export function searchMessages(keyword: string): string | null { diff --git a/src/main/services/group-exit-monitor-service.ts b/src/main/services/group-exit-monitor-service.ts index bfe44b4..06f4898 100644 --- a/src/main/services/group-exit-monitor-service.ts +++ b/src/main/services/group-exit-monitor-service.ts @@ -24,19 +24,37 @@ type StoredState = { monitoredRoomIds?: string[] notificationRoomIds?: string[] notificationTemplate?: unknown + snapshots?: Partial[] } type GroupSnapshotRecord = { contactId: string roomId: string groupName: string + capturedAt: number members: GroupExitMonitorMember[] /** 查询失败时保留旧快照。 */ membersValid?: boolean } +type GroupMembershipRecord = Omit & { + memberIds: string[] +} + +type MembershipMode = 'batch' | 'legacy' + +type MembershipReadResult = { + mode: MembershipMode + groupCount: number + groups: GroupMembershipRecord[] | null +} + +type StoredGroupSnapshot = Pick< + GroupSnapshotRecord, + 'contactId' | 'roomId' | 'groupName' | 'capturedAt' | 'members' +> + const DB_CHANGE_DEBOUNCE_MS = 350 -const GROUP_READ_CONCURRENCY = 8 const DUPLICATE_WINDOW_MS = 2 * 60 * 1000 const MAX_EVENTS = 500 @@ -58,6 +76,10 @@ class GroupExitMonitorService { private checking = false private checkQueued = false private initializing = false + private hydrating = false + private hydrationQueue = new Set() + private hydrationBatchStartedAt: number | null = null + private hydrationBatchGroups = 0 private lastCheckedAt: number | undefined private lastReadAt = 0 private events: GroupExitMonitorEvent[] = [] @@ -66,8 +88,11 @@ class GroupExitMonitorService { private notificationRoomIds = new Set() private loaded = false private accountRoot = '' + private groupNamesByRoomId = new Map() + private groupNamesRefreshPending = true private eventSequence = 0 private scopeGeneration = 0 + private legacyFallbackLogged = false private notificationTemplate = normalizeGroupExitNotificationTemplate(undefined) constructor(deps: GroupExitMonitorServiceDependencies = {}) { @@ -94,10 +119,15 @@ class GroupExitMonitorService { async start(nativeMonitorActive: boolean): Promise { this.ensureLoaded() const currentRoot = chat.getCurrentAccountRoot() + if (!currentRoot) { + this.active = true + this.nativeMonitorActive = nativeMonitorActive + this.broadcast() + return + } if ( - currentRoot && - this.accountRoot && - path.resolve(currentRoot) !== path.resolve(this.accountRoot) + (this.accountRoot && !sameAccountRoot(currentRoot, this.accountRoot)) || + (!this.accountRoot && this.snapshots.size > 0) ) { this.actionGateway.clearMemberEvents?.() this.events = [] @@ -105,32 +135,31 @@ class GroupExitMonitorService { this.monitorSelectionConfigured = true this.monitoredRoomIds.clear() this.notificationRoomIds.clear() + this.snapshots.clear() + this.groupNamesByRoomId.clear() } - if (currentRoot) this.accountRoot = currentRoot + this.accountRoot = currentRoot + this.groupNamesRefreshPending = true this.active = true this.nativeMonitorActive = nativeMonitorActive - this.snapshots.clear() this.checkQueued = false this.initializing = true const scopeGeneration = ++this.scopeGeneration - const generation = this.eventSequence + 1 - this.eventSequence = generation + this.eventSequence += 1 try { - const groups = await this.readGroups() - if ( - !this.active || - this.eventSequence !== generation || - this.scopeGeneration !== scopeGeneration - ) - return - if (groups) this.replaceSnapshots(groups) - this.save() - this.broadcast() + const checked = await this.runMembershipCheck(scopeGeneration) + if (!this.active || this.scopeGeneration !== scopeGeneration) return + if (!checked) { + this.save() + this.broadcast() + } } finally { this.initializing = false if (this.checkQueued && this.active) { this.checkQueued = false void this.check() + } else { + this.startNextSnapshotHydration() } } } @@ -140,8 +169,9 @@ class GroupExitMonitorService { this.nativeMonitorActive = false this.eventSequence += 1 this.scopeGeneration += 1 - this.snapshots.clear() this.checkQueued = false + this.hydrationQueue.clear() + this.groupNamesRefreshPending = true if (this.changeTimer) clearTimeout(this.changeTimer) this.changeTimer = null this.broadcast() @@ -154,6 +184,7 @@ class GroupExitMonitorService { } catch { // 缓存清理失败时继续检查。 } + this.groupNamesRefreshPending = true if (this.changeTimer) clearTimeout(this.changeTimer) this.changeTimer = setTimeout(() => { this.changeTimer = null @@ -175,13 +206,19 @@ class GroupExitMonitorService { this.eventSequence += 1 this.scopeGeneration += 1 this.monitorSelectionConfigured = true - this.monitoredRoomIds = normalizeRoomIds(roomIds) + const nextMonitoredRoomIds = normalizeRoomIds(roomIds) + for (const roomId of this.snapshots.keys()) { + if (!nextMonitoredRoomIds.has(roomId)) this.snapshots.delete(roomId) + } + for (const roomId of this.hydrationQueue) { + if (!nextMonitoredRoomIds.has(roomId)) this.hydrationQueue.delete(roomId) + } + this.monitoredRoomIds = nextMonitoredRoomIds + this.groupNamesRefreshPending = true const requestedNotifications = normalizeRoomIds(notificationRoomIds) this.notificationRoomIds = new Set( Array.from(requestedNotifications).filter((roomId) => this.monitoredRoomIds.has(roomId)) ) - // 更换监控范围后重新建基线,避免旧快照误报。 - this.snapshots.clear() this.lastCheckedAt = undefined this.save() this.broadcast() @@ -221,8 +258,16 @@ class GroupExitMonitorService { } private async check(): Promise { - if (!this.active || !chat.isReady()) return - if (this.initializing) { + const currentRoot = chat.getCurrentAccountRoot() + if ( + !this.active || + !chat.isReady() || + !currentRoot || + !this.accountRoot || + !sameAccountRoot(currentRoot, this.accountRoot) + ) + return + if (this.initializing || this.hydrating) { this.checkQueued = true return } @@ -234,143 +279,240 @@ class GroupExitMonitorService { this.checking = true const scopeGeneration = this.scopeGeneration try { - const groups = await this.readGroups() - if (!groups || !this.active || scopeGeneration !== this.scopeGeneration) return - - const currentRoomIds = new Set(groups.map((group) => group.roomId)) - for (const roomId of this.snapshots.keys()) { - if (!currentRoomIds.has(roomId)) this.snapshots.delete(roomId) - } - - const notificationTasks: Promise[] = [] - for (const next of groups) { - if (scopeGeneration !== this.scopeGeneration) return - if (next.membersValid === false) continue - const previous = this.snapshots.get(next.roomId) - if (previous?.membersValid === false) { - this.snapshots.set(next.roomId, next) - continue - } - // 空数组可能是查询失败,先保留旧基线,避免误报。 - if (previous && previous.members.length > 0 && next.members.length === 0) continue - - this.snapshots.set(next.roomId, next) - if (!previous) continue - - // 只有群人数下降才记录退群。 - if (next.members.length >= previous.members.length) continue - - const removed = findRemovedGroupMembers(previous.members, next.members) - for (const member of removed) { - const event = this.recordExit(next, member, previous.members.length, next.members.length) - if (event && this.notificationRoomIds.has(next.roomId)) { - notificationTasks.push(this.notifyGroup(next, event)) - } - } - } - if (notificationTasks.length) await Promise.all(notificationTasks) - if (!this.active || scopeGeneration !== this.scopeGeneration) return - this.lastCheckedAt = Date.now() - this.save() - this.broadcast() + await this.runMembershipCheck(scopeGeneration) } finally { this.checking = false if (this.checkQueued && this.active) { this.checkQueued = false void this.check() + } else { + this.startNextSnapshotHydration() } } } - private async readGroups(): Promise { + private async runMembershipCheck(scopeGeneration: number): Promise { + const startedAt = Date.now() + const result = await this.readMemberships() + const membershipCostMs = Date.now() - startedAt + let changedGroups = 0 + if (result.groups && this.active && scopeGeneration === this.scopeGeneration) { + changedGroups = await this.applyCurrentMemberships(result.groups, scopeGeneration) + } + console.log( + `[GroupMonitor] check mode=${result.mode} groups=${result.groupCount} membershipCostMs=${membershipCostMs} changedGroups=${changedGroups} totalCostMs=${Date.now() - startedAt}` + ) + return result.groups !== null + } + + private async readMemberships(): Promise { + await this.refreshGroupNamesIfNeeded() const database = chat.getChatDb() - if (!database) return null + const roomIds = Array.from(this.monitoredRoomIds) + const batchAvailable = chat.isGroupMemberIdsBatchAvailable() + const mode: MembershipMode = batchAvailable ? 'batch' : 'legacy' + if (!database) return { mode, groupCount: roomIds.length, groups: null } try { const client = database.getWcdb4Client() - const rawSessions = await client.getSessionsAsync({ hydrateDisplayNames: true }) - const sessions = Array.isArray(rawSessions) ? rawSessions : [] - const groups = sessions.filter( - (session) => - session.username?.endsWith('@chatroom') === true && - (!this.monitorSelectionConfigured || this.monitoredRoomIds.has(session.username)) - ) - const records: Array = new Array(groups.length).fill(null) - let nextIndex = 0 - const workerCount = Math.min(GROUP_READ_CONCURRENCY, groups.length) - await Promise.all( - Array.from({ length: workerCount }, async () => { - while (true) { - const index = nextIndex++ - if (index >= groups.length) return - const session = groups[index] - const contactId = client.md5(session.username) - try { - const snapshot = await chat.getGroupSnapshotAsync(contactId) - const groupName = cleanGroupName(session.nickname, session.username) - if (!snapshot || snapshot.roomId !== session.username) { - records[index] = { - contactId, - roomId: session.username, - groupName, - members: [], - membersValid: false - } - continue - } - const rawMembers = (snapshot as { members?: unknown }).members - if (!Array.isArray(rawMembers)) { - console.warn( - `[GroupMonitor] 群成员快照不是数组 roomId=${session.username}; 保留上一份基线` - ) - records[index] = { - contactId, - roomId: session.username, - groupName, - members: [], - membersValid: false - } - continue - } - records[index] = { - contactId, - roomId: snapshot.roomId, - groupName: cleanGroupName(session.nickname, snapshot.roomId), - members: rawMembers - .filter((member) => member?.wxid) - .map((member) => ({ - wxid: member.wxid, - nickname: member.nickname, - groupNickname: member.groupNickname, - wechatNickname: member.wechatNickname, - remark: member.remark, - avatar: member.avatar - })), - membersValid: true - } - } catch (error) { - console.warn(`[GroupMonitor] 读取群成员失败 roomId=${session.username}:`, error) - records[index] = { - contactId, - roomId: session.username, - groupName: cleanGroupName(session.nickname, session.username), - members: [], - membersValid: false - } + const capturedAt = Date.now() + + if (batchAvailable) { + const snapshots = await chat.getGroupMemberIdsBatchAsync(roomIds) + if (!snapshots) return { mode, groupCount: roomIds.length, groups: null } + return { + mode, + groupCount: roomIds.length, + groups: snapshots.map((snapshot) => { + const previous = this.snapshots.get(snapshot.roomId) + return { + contactId: previous?.contactId || client.md5(snapshot.roomId), + roomId: snapshot.roomId, + groupName: resolveGroupName(snapshot.roomId, this.groupNamesByRoomId, previous), + capturedAt, + memberIds: normalizeMemberIds(snapshot.memberIds), + membersValid: snapshot.status === 'ok' } - } + }) + } + } + + if (!this.legacyFallbackLogged) { + this.legacyFallbackLogged = true + console.warn('[GroupMonitor] batch membership unavailable; using legacy fallback') + } + const groups: GroupMembershipRecord[] = [] + for (const roomId of roomIds) { + const previous = this.snapshots.get(roomId) + const snapshot = await chat.getGroupMemberIdsAsync(roomId) + groups.push({ + contactId: previous?.contactId || client.md5(roomId), + roomId, + groupName: resolveGroupName(roomId, this.groupNamesByRoomId, previous), + capturedAt, + memberIds: snapshot?.roomId === roomId ? normalizeMemberIds(snapshot.memberIds) : [], + membersValid: snapshot?.roomId === roomId }) - ) - return records.filter((record): record is GroupSnapshotRecord => Boolean(record)) + } + return { mode, groupCount: roomIds.length, groups } } catch (error) { - console.warn('[GroupMonitor] 读取群成员快照失败:', error) - return null + console.warn('[GroupMonitor] 读取群成员状态失败:', error) + return { mode, groupCount: roomIds.length, groups: null } } } - private replaceSnapshots(groups: GroupSnapshotRecord[]): void { - this.snapshots = new Map( - groups.filter((group) => group.membersValid !== false).map((group) => [group.roomId, group]) + private async applyCurrentMemberships( + groups: GroupMembershipRecord[], + scopeGeneration: number + ): Promise { + const notifications: Array<{ group: GroupSnapshotRecord; event: GroupExitMonitorEvent }> = [] + let changedGroups = 0 + for (const membership of groups) { + if (!this.active || scopeGeneration !== this.scopeGeneration) return changedGroups + if (membership.membersValid === false) continue + const previous = this.snapshots.get(membership.roomId) + // 空数组可能是查询失败,先保留旧基线,避免误报和覆盖最后有效快照。 + if (previous && previous.members.length > 0 && membership.memberIds.length === 0) continue + + const previousMembers = new Map(previous?.members.map((member) => [member.wxid, member])) + const next: GroupSnapshotRecord = { + contactId: membership.contactId, + roomId: membership.roomId, + groupName: + membership.groupName === membership.roomId && previous + ? previous.groupName + : membership.groupName, + capturedAt: membership.capturedAt, + members: membership.memberIds.map( + (wxid) => previousMembers.get(wxid) || ({ wxid } satisfies GroupExitMonitorMember) + ), + membersValid: true + } + const membershipChanged = !previous || !sameMemberIds(previous.members, membership.memberIds) + if (membershipChanged) changedGroups += 1 + + if (previous && next.members.length < previous.members.length) { + const removed = findRemovedGroupMembers(previous.members, next.members) + for (const member of removed) { + const event = this.recordExit(next, member, previous.members.length, next.members.length) + if (event && this.notificationRoomIds.has(next.roomId)) { + notifications.push({ group: next, event }) + } + } + } + + // Last Good Snapshot 必须在 Diff 完成后才能替换。 + this.snapshots.set(next.roomId, next) + if (next.members.some((member) => !hasMemberMetadata(member))) { + this.hydrationQueue.add(next.roomId) + } + } + + if (!this.active || scopeGeneration !== this.scopeGeneration) return changedGroups + this.lastCheckedAt = Date.now() + // 先把事件和新基线作为同一检查点落盘,再执行可失败的通知动作。 + this.save() + this.broadcast() + if (notifications.length) { + await Promise.all(notifications.map(({ group, event }) => this.notifyGroup(group, event))) + } + return changedGroups + } + + private startNextSnapshotHydration(): void { + if (!this.active) { + this.finishHydrationBatch() + return + } + if (this.initializing || this.checking || this.hydrating) return + if (this.checkQueued || this.changeTimer) { + this.finishHydrationBatch() + return + } + + const roomId = this.hydrationQueue.values().next().value as string | undefined + if (!roomId) { + this.finishHydrationBatch() + return + } + this.hydrationQueue.delete(roomId) + const baseline = this.snapshots.get(roomId) + if (!baseline || !this.monitoredRoomIds.has(roomId)) { + this.startNextSnapshotHydration() + return + } + + this.hydrating = true + if (this.hydrationBatchStartedAt === null) this.hydrationBatchStartedAt = Date.now() + this.hydrationBatchGroups += 1 + const scopeGeneration = this.scopeGeneration + void chat + .getGroupSnapshotAsync(baseline.contactId) + .then((snapshot) => { + const current = this.snapshots.get(roomId) + if ( + !snapshot || + snapshot.roomId !== roomId || + !this.active || + scopeGeneration !== this.scopeGeneration || + !current || + !sameMemberIds( + current.members, + snapshot.members.map((member) => member.wxid) + ) + ) + return + + const hydrated = new Map( + normalizeSnapshotMembers(snapshot.members).map((member) => [member.wxid, member]) + ) + this.snapshots.set(roomId, { + ...current, + groupName: resolveGroupName(roomId, this.groupNamesByRoomId, current, snapshot.groupName), + members: current.members.map((member) => { + const refreshed = hydrated.get(member.wxid) + return refreshed ? { ...member, ...refreshed } : member + }) + }) + this.hydrationQueue.delete(roomId) + this.save() + this.broadcast() + }) + .catch(() => undefined) + .finally(() => { + this.hydrating = false + if (this.checkQueued && this.active) { + this.finishHydrationBatch() + this.checkQueued = false + void this.check() + } else if (this.changeTimer) { + this.finishHydrationBatch() + } else { + this.startNextSnapshotHydration() + } + }) + } + + private finishHydrationBatch(): void { + if (this.hydrationBatchStartedAt === null || this.hydrationBatchGroups === 0) return + console.log( + `[GroupMonitor] hydration groups=${this.hydrationBatchGroups} costMs=${Date.now() - this.hydrationBatchStartedAt}` ) + this.hydrationBatchStartedAt = null + this.hydrationBatchGroups = 0 + } + + private async refreshGroupNamesIfNeeded(): Promise { + if (!this.groupNamesRefreshPending) return + this.groupNamesRefreshPending = false + try { + const names = await chat.getGroupNamesAsync() + for (const [roomId, name] of Object.entries(names || {})) { + const resolved = normalizeKnownGroupName(roomId, name) + if (resolved) this.groupNamesByRoomId.set(roomId, resolved) + } + } catch { + // Session 群名是展示信息;读取失败时继续使用快照中的已知群名。 + } } private recordExit( @@ -508,6 +650,7 @@ class GroupExitMonitorService { this.notificationTemplate = normalizeGroupExitNotificationTemplate( stored.notificationTemplate ) + this.snapshots = normalizeSnapshots(stored.snapshots, this.monitoredRoomIds) } catch { // 首次启动或文件损坏时从空记录开始。 this.events = [] @@ -516,6 +659,7 @@ class GroupExitMonitorService { this.monitoredRoomIds.clear() this.notificationRoomIds.clear() this.notificationTemplate = normalizeGroupExitNotificationTemplate(undefined) + this.snapshots.clear() } } @@ -532,12 +676,13 @@ class GroupExitMonitorService { monitorSelectionConfigured: this.monitorSelectionConfigured, monitoredRoomIds: Array.from(this.monitoredRoomIds), notificationRoomIds: Array.from(this.notificationRoomIds), - notificationTemplate: this.notificationTemplate + notificationTemplate: this.notificationTemplate, + snapshots: Array.from(this.snapshots.values(), toStoredSnapshot) }, { spaces: 2 } ) } catch (error) { - console.warn('[GroupMonitor] 保存事件失败:', error) + console.warn('[GroupMonitor] 保存状态失败:', error) } } @@ -557,6 +702,120 @@ function normalizeRoomIds(roomIds: string[]): Set { ) } +function normalizeMemberIds(values: unknown[]): string[] { + return Array.from( + new Set(values.map((value) => String(value || '').trim()).filter((value) => Boolean(value))) + ) +} + +function sameMemberIds(previous: GroupExitMonitorMember[], nextIds: string[]): boolean { + if (previous.length !== nextIds.length) return false + const previousIds = new Set(previous.map((member) => member.wxid)) + return nextIds.every((wxid) => previousIds.has(wxid)) +} + +function hasMemberMetadata(member: GroupExitMonitorMember): boolean { + return Boolean( + member.nickname?.trim() || + member.groupNickname?.trim() || + member.wechatNickname?.trim() || + member.remark?.trim() + ) +} + +function sameAccountRoot(left: string, right: string): boolean { + const normalize = (value: string): string => { + const resolved = path.resolve(value) + return process.platform === 'win32' ? resolved.toLowerCase() : resolved + } + return normalize(left) === normalize(right) +} + +function normalizeSnapshots( + values: Partial[] | undefined, + monitoredRoomIds: Set +): Map { + const snapshots = new Map() + if (!Array.isArray(values)) return snapshots + for (const value of values) { + const roomId = String(value?.roomId || '').trim() + const capturedAt = Number(value?.capturedAt) + if ( + !roomId.endsWith('@chatroom') || + !monitoredRoomIds.has(roomId) || + !Number.isFinite(capturedAt) || + capturedAt <= 0 || + !Array.isArray(value?.members) + ) { + continue + } + snapshots.set(roomId, { + contactId: String(value.contactId || ''), + roomId, + groupName: cleanGroupName(value.groupName, roomId), + capturedAt, + members: normalizeSnapshotMembers(value.members) + }) + } + return snapshots +} + +function normalizeSnapshotMembers(values: GroupExitMonitorMember[]): GroupExitMonitorMember[] { + const members: GroupExitMonitorMember[] = [] + const seen = new Set() + for (const value of values) { + const wxid = String(value?.wxid || '').trim() + if (!wxid || seen.has(wxid)) continue + seen.add(wxid) + members.push({ + wxid, + ...optionalMemberField('nickname', value.nickname), + ...optionalMemberField('groupNickname', value.groupNickname), + ...optionalMemberField('wechatNickname', value.wechatNickname), + ...optionalMemberField('remark', value.remark), + ...optionalMemberField('avatar', value.avatar) + }) + } + return members +} + +function optionalMemberField( + key: K, + value: unknown +): Partial> { + const normalized = String(value || '').trim() + return normalized ? ({ [key]: normalized } as Pick) : {} +} + +function normalizeKnownGroupName(roomId: string, value: unknown): string { + const name = String(value || '').trim() + return name && name !== roomId && !name.endsWith('@chatroom') ? name : '' +} + +function resolveGroupName( + roomId: string, + namesByRoomId: Map, + previous?: Pick, + hydratedName?: unknown +): string { + return ( + normalizeKnownGroupName(roomId, namesByRoomId.get(roomId)) || + normalizeKnownGroupName(roomId, previous?.groupName) || + normalizeKnownGroupName(roomId, hydratedName) || + roomId + ) +} + +function toStoredSnapshot(snapshot: GroupSnapshotRecord): StoredGroupSnapshot { + return { + contactId: snapshot.contactId, + roomId: snapshot.roomId, + groupName: snapshot.groupName, + capturedAt: snapshot.capturedAt, + members: normalizeSnapshotMembers(snapshot.members) + } +} + function cleanGroupName(value: string | undefined, roomId: string): string { const name = String(value || '').trim() return name && name !== roomId && !name.startsWith('wxid_') ? name : roomId diff --git a/src/main/wcdb4-client.ts b/src/main/wcdb4-client.ts index de7f7fa..2632fd4 100644 --- a/src/main/wcdb4-client.ts +++ b/src/main/wcdb4-client.ts @@ -59,6 +59,46 @@ export interface Wcdb4GroupMember { m_nsHeadImgUrl: string } +export type Wcdb4GroupMemberBatchStatus = 'ok' | 'not_found' + +export interface Wcdb4GroupMemberIdsBatchItem { + roomId: string + status: Wcdb4GroupMemberBatchStatus + memberWxids: string[] +} + +function normalizeGroupMemberIdsBatch( + value: unknown, + requestedRoomIds: string[] +): Wcdb4GroupMemberIdsBatchItem[] | null { + if (!Array.isArray(value) || value.length !== requestedRoomIds.length) return null + const requested = new Set(requestedRoomIds) + const results = new Map() + for (const rawItem of value) { + if (!rawItem || typeof rawItem !== 'object') return null + const item = rawItem as Record + const roomId = typeof item.roomId === 'string' ? item.roomId.trim() : '' + const status = item.status + if ( + !roomId || + !requested.has(roomId) || + results.has(roomId) || + (status !== 'ok' && status !== 'not_found') || + !Array.isArray(item.memberWxids) || + item.memberWxids.some((memberWxid) => typeof memberWxid !== 'string' || !memberWxid.trim()) + ) { + return null + } + results.set(roomId, { + roomId, + status, + memberWxids: Array.from(new Set(item.memberWxids.map((memberWxid) => memberWxid.trim()))) + }) + } + if (results.size !== requestedRoomIds.length) return null + return requestedRoomIds.map((roomId) => results.get(roomId)!) +} + /** * 联系人表中独立保存的成员名称字段。 * @@ -395,6 +435,9 @@ export class Wcdb4Client { private wcdbGetGroupMembers: | ((handle: number, chatroomId: string, outJson: WcdbVoidOut) => number) | null = null + private wcdbGetGroupMembersBatch: + | ((handle: number, chatroomIdsJson: string, outJson: WcdbVoidOut) => number) + | null = null private wcdbGetGroupNicknames: | ((handle: number, chatroomId: string, outJson: WcdbVoidOut) => number) | null = null @@ -1900,6 +1943,55 @@ export class Wcdb4Client { } } + /** + * 退群检测热路径:只读取原始成员行并提取 wxid,不补群昵称、联系人资料或头像。 + * null 表示读取失败,避免调用方把失败误判为成员列表为空。 + */ + async getGroupMemberIdsAsync(chatroomId: string): Promise { + if (!this.wcdbGetGroupMembers || !chatroomId) return null + + try { + const rows = await this.callJsonAsync[]>( + this.wcdbGetGroupMembers as unknown as KoffiAsyncFunction, + chatroomId + ) + const memberRows = Array.isArray(rows) ? rows : [] + return Array.from(new Set(this.groupMemberUsernames(memberRows))) + } catch (error) { + console.warn(`[WCDB4] async group member ids failed chatroom=${chatroomId}:`, error) + return null + } + } + + isGroupMemberIdsBatchAvailable(): boolean { + return Boolean(this.wcdbGetGroupMembersBatch) + } + + async getGroupMemberIdsBatchAsync( + roomIds: string[] + ): Promise { + const requestedRoomIds = Array.from( + new Set( + (Array.isArray(roomIds) ? roomIds : []) + .map((roomId) => String(roomId || '').trim()) + .filter(Boolean) + ) + ) + if (requestedRoomIds.length === 0) return [] + if (!this.wcdbGetGroupMembersBatch) return null + + try { + const raw = await this.callJsonAsync( + this.wcdbGetGroupMembersBatch as unknown as KoffiAsyncFunction, + JSON.stringify(requestedRoomIds) + ) + return normalizeGroupMemberIdsBatch(raw, requestedRoomIds) + } catch (error) { + console.warn('[WCDB4] async group member ids batch failed:', error) + return null + } + } + /** * 将群成员接口与联系人表组装为语义明确的成员快照。 * @@ -2390,6 +2482,14 @@ export class Wcdb4Client { this.wcdbGetGroupMembers = null } + try { + this.wcdbGetGroupMembersBatch = lib.func( + 'int32 wcdb_get_group_members_batch(int64 handle, const char* chatroomIdsJson, _Out_ void** outJson)' + ) as (handle: number, chatroomIdsJson: string, outJson: WcdbVoidOut) => number + } catch { + this.wcdbGetGroupMembersBatch = null + } + try { this.wcdbGetGroupNicknames = lib.func( 'int32 wcdb_get_group_nicknames(int64 handle, const char* chatroomId, _Out_ void** outJson)' diff --git a/tests/unit/group-exit-monitor-service.test.ts b/tests/unit/group-exit-monitor-service.test.ts index c42e2a5..3c07571 100644 --- a/tests/unit/group-exit-monitor-service.test.ts +++ b/tests/unit/group-exit-monitor-service.test.ts @@ -9,6 +9,10 @@ const mocks = vi.hoisted(() => ({ getChatDb: vi.fn(), getCurrentAccountRoot: vi.fn(() => 'fixture-account'), isReady: vi.fn(() => true), + getGroupNamesAsync: vi.fn(async () => ({})), + isGroupMemberIdsBatchAvailable: vi.fn(() => true), + getGroupMemberIdsBatchAsync: vi.fn(), + getGroupMemberIdsAsync: vi.fn(), getGroupSnapshotAsync: vi.fn() }, capability: { @@ -35,17 +39,39 @@ import { GroupExitMonitorService } from '../../src/main/services/group-exit-moni import { GROUP_EXIT_NOTIFICATION_TEMPLATE } from '../../src/shared/group-exit-monitor' const member = { wxid: 'wxid_member', wechatNickname: '微信名', groupNickname: '群内名' } +const otherMember = { wxid: 'wxid_other', wechatNickname: '另一个人' } function installGroupDb(): void { const client = { - getSessionsAsync: vi - .fn() - .mockResolvedValue([{ username: 'room@chatroom', nickname: '测试群' }]), - md5: vi.fn(() => 'room-md5') + md5: vi.fn((roomId: string) => `${roomId}-md5`), + invalidateGroupNicknameCache: vi.fn() } mocks.chat.getChatDb.mockReturnValue({ getWcdb4Client: () => client }) } +function writeBaseline( + snapshots: Array<{ + roomId: string + groupName: string + members: Array<{ wxid: string; [key: string]: string }> + }>, + notificationRoomIds: string[] = [] +): void { + writeJsonSync(join(mocks.userData, 'group-exit-monitor.json'), { + accountRoot: 'fixture-account', + events: [], + monitoredRoomIds: snapshots.map((snapshot) => snapshot.roomId), + notificationRoomIds, + snapshots: snapshots.map((snapshot) => ({ + contactId: `${snapshot.roomId}-md5`, + roomId: snapshot.roomId, + groupName: snapshot.groupName, + capturedAt: Date.now() - 1_000, + members: snapshot.members + })) + }) +} + describe('GroupExitMonitorService', () => { const temporaryDirectories: string[] = [] @@ -55,7 +81,11 @@ describe('GroupExitMonitorService', () => { mocks.chat.getChatDb.mockReset() mocks.chat.getCurrentAccountRoot.mockReset().mockReturnValue('fixture-account') mocks.chat.isReady.mockReset().mockReturnValue(true) - mocks.chat.getGroupSnapshotAsync.mockReset() + mocks.chat.getGroupNamesAsync.mockReset().mockResolvedValue({}) + mocks.chat.isGroupMemberIdsBatchAvailable.mockReset().mockReturnValue(true) + mocks.chat.getGroupMemberIdsBatchAsync.mockReset() + mocks.chat.getGroupMemberIdsAsync.mockReset() + mocks.chat.getGroupSnapshotAsync.mockReset().mockResolvedValue(null) mocks.capability.getPersonalWechatSendCapability.mockReset() mocks.sender.send.mockReset() }) @@ -89,38 +119,418 @@ describe('GroupExitMonitorService', () => { expect(service.getState().notificationTemplate).toBe(GROUP_EXIT_NOTIFICATION_TEMPLATE) }) - it('keeps the previous baseline when a native snapshot contains null members', async () => { + it('uses the Session nickname when establishing a new group baseline', async () => { installGroupDb() + const callOrder: string[] = [] + mocks.chat.getGroupNamesAsync.mockImplementation(async () => { + callOrder.push('names') + return { 'A@chatroom': '测试群A' } + }) + mocks.chat.getGroupMemberIdsBatchAsync.mockImplementation(async () => { + callOrder.push('batch') + return [{ roomId: 'A@chatroom', status: 'ok', memberIds: [member.wxid] }] + }) + mocks.chat.getGroupSnapshotAsync.mockImplementation(async () => { + callOrder.push('hydration') + return null + }) + const service = new GroupExitMonitorService() + await service.setMonitoredRoomIds(['A@chatroom']) + await service.start(true) + + const stored = readJsonSync(join(mocks.userData, 'group-exit-monitor.json')) + expect(stored.snapshots[0]).toMatchObject({ roomId: 'A@chatroom', groupName: '测试群A' }) + expect(callOrder.indexOf('batch')).toBeGreaterThan(callOrder.indexOf('names')) + expect(callOrder.indexOf('hydration')).toBeGreaterThan(callOrder.indexOf('batch')) + }) + + it('preserves existing member metadata during a Batch membership refresh', async () => { + installGroupDb() + const richMember = { + wxid: 'wxid_rich', + nickname: 'Shinven', + groupNickname: '群内 Shinven', + wechatNickname: 'Shinven', + remark: '小号', + avatar: 'data:image/png;base64,known' + } + writeBaseline([{ roomId: 'A@chatroom', groupName: '测试群A', members: [richMember] }]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'A@chatroom', status: 'ok', memberIds: [richMember.wxid] } + ]) + const service = new GroupExitMonitorService() + + await service.start(true) + + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0].members + ).toEqual([richMember]) + }) + + it('keeps hydrated member metadata across the next Batch refresh', async () => { + installGroupDb() + writeBaseline([ + { roomId: 'A@chatroom', groupName: '测试群A', members: [{ wxid: 'wxid_rich' }] } + ]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'A@chatroom', status: 'ok', memberIds: ['wxid_rich'] } + ]) + mocks.chat.getGroupSnapshotAsync.mockResolvedValue({ + roomId: 'A@chatroom', + groupName: '测试群A', + members: [ + { + wxid: 'wxid_rich', + nickname: 'Shinven', + groupNickname: '群内 Shinven', + wechatNickname: 'Shinven', + remark: '小号', + avatar: '' + } + ] + }) + const service = new GroupExitMonitorService() + await service.start(true) + await vi.waitFor(() => { + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0].members[0] + ).toMatchObject({ wxid: 'wxid_rich', nickname: 'Shinven', remark: '小号' }) + }) + + await service.checkNow() + + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0].members[0] + ).toMatchObject({ wxid: 'wxid_rich', nickname: 'Shinven', remark: '小号' }) + }) + + it('preserves old member metadata while allowing a new member to start wxid-only', async () => { + installGroupDb() + const existing = { wxid: 'wxid_existing', nickname: 'Shinven', remark: '小号' } + writeBaseline([{ roomId: 'A@chatroom', groupName: '测试群A', members: [existing] }]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'A@chatroom', status: 'ok', memberIds: [existing.wxid, 'wxid_new'] } + ]) + mocks.chat.getGroupSnapshotAsync.mockResolvedValue({ + roomId: 'A@chatroom', + groupName: '测试群A', + members: [{ wxid: existing.wxid }, { wxid: 'wxid_new', nickname: '新成员' }] + }) + const service = new GroupExitMonitorService() + + await service.start(true) + + await vi.waitFor(() => { + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0].members + ).toEqual([existing, { wxid: 'wxid_new', nickname: '新成员' }]) + }) + }) + + it('repairs a persisted room id fallback when Session metadata becomes available', async () => { + installGroupDb() + writeBaseline([{ roomId: 'A@chatroom', groupName: 'A@chatroom', members: [member] }]) + mocks.chat.getGroupNamesAsync.mockResolvedValue({ 'A@chatroom': '测试群A' }) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'A@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) + const service = new GroupExitMonitorService() + await service.start(true) + + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0] + ).toMatchObject({ roomId: 'A@chatroom', groupName: '测试群A' }) + }) + + it('keeps the previous resolved group name when Session metadata is temporarily unavailable', async () => { + installGroupDb() + writeBaseline([{ roomId: 'A@chatroom', groupName: '测试群A', members: [member] }]) + mocks.chat.getGroupNamesAsync.mockResolvedValue({}) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'A@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) + const service = new GroupExitMonitorService() + await service.start(true) + + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0] + ).toMatchObject({ roomId: 'A@chatroom', groupName: '测试群A' }) + }) + + it('uses one resolved group name for both 3-to-1 events and Gateway notification recipients', async () => { + installGroupDb() + const departed = { wxid: 'wxid_departed', groupNickname: '离群一' } + const secondDeparted = { wxid: 'wxid_second_departed', groupNickname: '离群二' } + writeBaseline( + [ + { + roomId: 'A@chatroom', + groupName: 'A@chatroom', + members: [member, departed, secondDeparted] + } + ], + ['A@chatroom'] + ) + mocks.chat.getGroupNamesAsync.mockResolvedValue({ 'A@chatroom': '测试群A' }) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'A@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) + const requests: Array<{ recipient?: { name?: string } }> = [] + const actionGateway = { + execute: vi.fn(async (request: { recipient?: { name?: string } }) => { + requests.push(request) + return { status: 'sent', actionId: 'action-1', decision: 'allow' } + }), + registerMemberEvent: vi.fn() + } + const service = new GroupExitMonitorService({ actionGateway }) + + await service.start(true) + + expect(service.getState().events).toHaveLength(2) + expect(service.getState().events).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + memberWxid: departed.wxid, + groupName: '测试群A', + message: '离群一退出了测试群A', + previousCount: 3, + currentCount: 1 + }), + expect.objectContaining({ + memberWxid: secondDeparted.wxid, + groupName: '测试群A', + message: '离群二退出了测试群A', + previousCount: 3, + currentCount: 1 + }) + ]) + ) + expect(requests).toHaveLength(2) + expect(requests.every((request) => request.recipient?.name === '测试群A')).toBe(true) + expect(mocks.chat.getGroupSnapshotAsync).not.toHaveBeenCalled() + }) + + it('persists a compact last good snapshot and recovers offline exits after restart', async () => { + installGroupDb() + const departed = { + wxid: 'wxid_departed', + nickname: '旧昵称', + wechatNickname: '离群成员', + groupNickname: '群内昵称', + remark: '通讯录备注', + avatar: 'data:image/png;base64,not-persisted' + } + const secondDeparted = { + wxid: 'wxid_second_departed', + nickname: '另一个旧昵称', + wechatNickname: '第二位离群成员', + groupNickname: '第二位群内昵称', + remark: '第二位通讯录备注' + } mocks.chat.getGroupSnapshotAsync.mockResolvedValueOnce({ roomId: 'room@chatroom', - members: [member] + members: [member, departed, secondDeparted] }) + mocks.chat.getGroupMemberIdsBatchAsync + .mockResolvedValueOnce([ + { + roomId: 'room@chatroom', + status: 'ok', + memberIds: [member.wxid, departed.wxid, secondDeparted.wxid] + } + ]) + .mockResolvedValue([{ roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] }]) const service = new GroupExitMonitorService() service.setMonitoredRoomIds(['room@chatroom']) await service.start(true) - mocks.chat.getGroupSnapshotAsync.mockResolvedValueOnce({ - roomId: 'room@chatroom', - members: null + const statePath = join(mocks.userData, 'group-exit-monitor.json') + await vi.waitFor(() => { + expect(readJsonSync(statePath).snapshots[0].members[1]).toMatchObject({ + wxid: departed.wxid, + wechatNickname: departed.wechatNickname + }) }) - const state = await service.checkNow() + const baseline = readJsonSync(statePath) + expect(baseline.events).toEqual([]) + expect(baseline.snapshots).toEqual([ + expect.objectContaining({ + roomId: 'room@chatroom', + groupName: 'room@chatroom', + capturedAt: expect.any(Number), + members: [ + member, + expect.objectContaining({ wxid: 'wxid_departed' }), + expect.objectContaining({ wxid: 'wxid_second_departed' }) + ] + }) + ]) + expect(baseline.snapshots[0].members[1]).toHaveProperty('avatar', departed.avatar) + + service.stop() + const restarted = new GroupExitMonitorService() + await restarted.start(true) + + expect(restarted.getState().events).toHaveLength(2) + expect(restarted.getState().events).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + memberWxid: 'wxid_departed', + memberName: departed.groupNickname, + previousCount: 3, + currentCount: 1 + }), + expect.objectContaining({ + memberWxid: 'wxid_second_departed', + memberName: secondDeparted.groupNickname, + previousCount: 3, + currentCount: 1 + }) + ]) + ) + expect(mocks.chat.getGroupMemberIdsBatchAsync).toHaveBeenCalledTimes(2) + expect(mocks.chat.getGroupMemberIdsAsync).not.toHaveBeenCalled() + expect(readJsonSync(statePath).snapshots[0].members).toEqual([member]) + + await restarted.start(true) + expect(restarted.getState().events).toHaveLength(2) + + restarted.clearEvents() + expect(readJsonSync(statePath).snapshots[0].members).toEqual([member]) + }) + + it('keeps every previous baseline when a batch result is invalid or incomplete', async () => { + installGroupDb() + writeBaseline([ + { roomId: 'room@chatroom', groupName: '测试群', members: [member] }, + { roomId: 'other@chatroom', groupName: '其他群', members: [otherMember] } + ]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue(null) + const service = new GroupExitMonitorService() + await service.start(true) + const state = service.getState() expect(state.events).toEqual([]) - expect(state.monitoredGroupCount).toBe(1) + expect(state.monitoredGroupCount).toBe(2) + expect(readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots).toEqual([ + expect.objectContaining({ roomId: 'room@chatroom', members: [member] }), + expect.objectContaining({ roomId: 'other@chatroom', members: [otherMember] }) + ]) + }) + + it('treats not_found as unavailable and preserves the last good snapshot', async () => { + installGroupDb() + writeBaseline([ + { roomId: 'room@chatroom', groupName: '测试群', members: [member, otherMember] } + ]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'not_found', memberIds: [] } + ]) + const service = new GroupExitMonitorService() + + await service.start(true) + + expect(service.getState().events).toEqual([]) + expect( + readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).snapshots[0].members + ).toEqual([member, otherMember]) + }) + + it('uses the legacy member reader only when the batch symbol is unavailable', async () => { + installGroupDb() + writeBaseline([ + { roomId: 'room@chatroom', groupName: '测试群', members: [member, otherMember] }, + { + roomId: 'other@chatroom', + groupName: '其他群', + members: [{ wxid: 'wxid_stays', nickname: '保留成员' }] + } + ]) + mocks.chat.isGroupMemberIdsBatchAvailable.mockReturnValue(false) + mocks.chat.getGroupMemberIdsAsync.mockImplementation(async (roomId: string) => ({ + roomId, + memberIds: roomId === 'room@chatroom' ? [member.wxid] : ['wxid_stays'] + })) + const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined) + const service = new GroupExitMonitorService() + + await service.start(true) + await service.checkNow() + + expect(service.getState().events).toHaveLength(1) + expect(mocks.chat.getGroupMemberIdsBatchAsync).not.toHaveBeenCalled() + expect(mocks.chat.getGroupMemberIdsAsync).toHaveBeenCalledTimes(4) + expect(warn).toHaveBeenCalledTimes(1) + expect(warn).toHaveBeenCalledWith( + '[GroupMonitor] batch membership unavailable; using legacy fallback' + ) + warn.mockRestore() + }) + + it('keeps snapshots when only notification settings change', async () => { + writeBaseline([{ roomId: 'room@chatroom', groupName: '测试群', members: [member] }]) + const service = new GroupExitMonitorService() + service.getState() + + await service.setMonitoredRoomIds(['room@chatroom'], ['room@chatroom']) + + const stored = readJsonSync(join(mocks.userData, 'group-exit-monitor.json')) + expect(stored.notificationRoomIds).toEqual(['room@chatroom']) + expect(stored.snapshots).toHaveLength(1) + expect(stored.snapshots[0].members).toEqual([member]) + }) + + it('retains existing baselines and only establishes a baseline for a newly monitored group', async () => { + installGroupDb() + writeBaseline([{ roomId: 'room@chatroom', groupName: '测试群', members: [member] }]) + const service = new GroupExitMonitorService() + await service.setMonitoredRoomIds(['room@chatroom', 'new-room@chatroom']) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] }, + { roomId: 'new-room@chatroom', status: 'ok', memberIds: ['wxid_new_group_member'] } + ]) + await service.start(true) + + expect(service.getState().events).toEqual([]) + const stored = readJsonSync(join(mocks.userData, 'group-exit-monitor.json')) + expect(stored.snapshots.map((snapshot: { roomId: string }) => snapshot.roomId).sort()).toEqual([ + 'new-room@chatroom', + 'room@chatroom' + ]) + }) + + it('does not diff persisted snapshots across account roots', async () => { + installGroupDb() + writeBaseline([ + { + roomId: 'room@chatroom', + groupName: '测试群', + members: [member, { wxid: 'wxid_account_a_member' }] + } + ]) + + mocks.chat.getCurrentAccountRoot.mockReturnValue('different-account') + const switched = new GroupExitMonitorService() + await switched.start(true) + + expect(switched.getState().events).toEqual([]) + const stored = readJsonSync(join(mocks.userData, 'group-exit-monitor.json')) + expect(stored.accountRoot).toBe('different-account') + expect(stored.snapshots).toEqual([]) }) it('returns from scope saving before the background baseline read completes', async () => { installGroupDb() - mocks.chat.getGroupSnapshotAsync.mockResolvedValueOnce({ - roomId: 'room@chatroom', - members: [member] - }) + writeBaseline([{ roomId: 'room@chatroom', groupName: '测试群', members: [member] }]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValueOnce([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) const service = new GroupExitMonitorService() - service.setMonitoredRoomIds(['room@chatroom']) await service.start(true) let release!: (snapshot: unknown) => void - mocks.chat.getGroupSnapshotAsync.mockReturnValueOnce( + mocks.chat.getGroupMemberIdsBatchAsync.mockReturnValueOnce( new Promise((resolve) => { release = resolve }) @@ -130,27 +540,148 @@ describe('GroupExitMonitorService', () => { expect(Date.now() - startedAt).toBeLessThan(250) expect(state.monitoredRoomIds).toEqual(['room@chatroom']) - release({ roomId: 'room@chatroom', members: [member] }) + release([{ roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] }]) + }) + + it('detects a removed member across multiple groups without full snapshot hydration', async () => { + installGroupDb() + const departed = { + wxid: 'wxid_departed', + wechatNickname: 'Previous Snapshot 姓名', + groupNickname: 'Previous Snapshot 群昵称', + remark: 'Previous Snapshot 备注' + } + writeBaseline([ + { roomId: 'room@chatroom', groupName: '目标群', members: [member, departed] }, + { + roomId: 'other-1@chatroom', + groupName: '其他群 1', + members: [{ wxid: 'wxid_other_1', nickname: '成员 1' }] + }, + { + roomId: 'other-2@chatroom', + groupName: '其他群 2', + members: [{ wxid: 'wxid_other_2', nickname: '成员 2' }] + } + ]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] }, + { roomId: 'other-1@chatroom', status: 'ok', memberIds: ['wxid_other_1'] }, + { roomId: 'other-2@chatroom', status: 'ok', memberIds: ['wxid_other_2'] } + ]) + + const service = new GroupExitMonitorService() + await service.start(true) + + expect(service.getState().events[0]).toMatchObject({ + memberWxid: departed.wxid, + memberName: departed.groupNickname, + wechatName: departed.wechatNickname, + groupRemark: departed.groupNickname, + contactRemark: departed.remark + }) + expect(mocks.chat.getGroupMemberIdsBatchAsync).toHaveBeenCalledOnce() + expect(mocks.chat.getGroupMemberIdsBatchAsync).toHaveBeenCalledWith([ + 'room@chatroom', + 'other-1@chatroom', + 'other-2@chatroom' + ]) + expect(mocks.chat.getGroupMemberIdsAsync).not.toHaveBeenCalled() + expect(mocks.chat.getGroupSnapshotAsync).not.toHaveBeenCalled() + }) + + it('logs one summary for a membership check and one for a hydration batch', async () => { + installGroupDb() + const log = vi.spyOn(console, 'log').mockImplementation(() => undefined) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) + mocks.chat.getGroupSnapshotAsync.mockResolvedValue({ + roomId: 'room@chatroom', + members: [member] + }) + const service = new GroupExitMonitorService() + service.setMonitoredRoomIds(['room@chatroom']) + + await service.start(true) + await vi.waitFor(() => { + expect(log).toHaveBeenCalledWith( + expect.stringMatching(/^\[GroupMonitor\] hydration groups=1 costMs=\d+$/) + ) + }) + + expect(log).toHaveBeenCalledWith( + expect.stringMatching( + /^\[GroupMonitor\] check mode=batch groups=1 membershipCostMs=\d+ changedGroups=1 totalCostMs=\d+$/ + ) + ) + log.mockRestore() + }) + + it('pauses queued hydration as soon as a contact change is pending', async () => { + vi.useFakeTimers() + installGroupDb() + let membershipCalls = 0 + let finishPriorityCheck!: () => void + const priorityCheckFinished = new Promise((resolve) => { + finishPriorityCheck = resolve + }) + mocks.chat.getGroupMemberIdsBatchAsync.mockImplementation(async (roomIds: string[]) => { + membershipCalls += 1 + if (membershipCalls === 2) finishPriorityCheck() + return roomIds.map((roomId) => ({ + roomId, + status: 'ok', + memberIds: [roomId === 'room@chatroom' ? 'wxid_room' : 'wxid_other'] + })) + }) + let finishFirstHydration!: (snapshot: unknown) => void + mocks.chat.getGroupSnapshotAsync + .mockReturnValueOnce( + new Promise((resolve) => { + finishFirstHydration = resolve + }) + ) + .mockReturnValue(new Promise(() => undefined)) + const service = new GroupExitMonitorService() + service.setMonitoredRoomIds(['room@chatroom', 'other@chatroom']) + await service.start(true) + expect(mocks.chat.getGroupSnapshotAsync).toHaveBeenCalledOnce() + + service.notifyDatabaseChanged('{"table":"contact","action":"update"}') + finishFirstHydration({ + roomId: 'room@chatroom', + members: [{ wxid: 'wxid_room', nickname: '成员 1' }] + }) + await Promise.resolve() + await Promise.resolve() + + expect(mocks.chat.getGroupSnapshotAsync).toHaveBeenCalledOnce() + expect(mocks.chat.getGroupMemberIdsBatchAsync).toHaveBeenCalledOnce() + await vi.advanceTimersByTimeAsync(350) + await priorityCheckFinished + expect(mocks.chat.getGroupMemberIdsBatchAsync).toHaveBeenCalledTimes(2) + service.stop() + vi.useRealTimers() }) it('renders the saved template before sending a group notification', async () => { installGroupDb() + writeBaseline( + [{ roomId: 'room@chatroom', groupName: '测试群', members: [member, otherMember] }], + ['room@chatroom'] + ) mocks.capability.getPersonalWechatSendCapability.mockResolvedValue({ ready: true, capabilities: { text: true } }) mocks.sender.send.mockResolvedValue({ success: true }) - mocks.chat.getGroupSnapshotAsync - .mockResolvedValueOnce({ - roomId: 'room@chatroom', - members: [member, { wxid: 'wxid_other', wechatNickname: '另一个人' }] - }) - .mockResolvedValueOnce({ roomId: 'room@chatroom', members: [member] }) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) const service = new GroupExitMonitorService() service.setNotificationTemplate('退群: {user}/{groupRemark}/{wxid}') - service.setMonitoredRoomIds(['room@chatroom'], ['room@chatroom']) await service.start(true) - await service.checkNow() expect(mocks.sender.send).toHaveBeenCalledWith({ type: 'text', @@ -162,16 +693,15 @@ describe('GroupExitMonitorService', () => { it('records an exit without creating a send action when notification is disabled', async () => { installGroupDb() - mocks.chat.getGroupSnapshotAsync - .mockResolvedValueOnce({ - roomId: 'room@chatroom', - members: [member, { wxid: 'wxid_other', wechatNickname: '另一个人' }] - }) - .mockResolvedValueOnce({ roomId: 'room@chatroom', members: [member] }) + writeBaseline([ + { roomId: 'room@chatroom', groupName: '测试群', members: [member, otherMember] } + ]) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) const service = new GroupExitMonitorService() - service.setMonitoredRoomIds(['room@chatroom']) await service.start(true) - const state = await service.checkNow() + const state = service.getState() expect(state.events[0]).toMatchObject({ memberWxid: 'wxid_other', @@ -183,6 +713,10 @@ describe('GroupExitMonitorService', () => { it('微信发送能力不可用时仍保留退群事件', async () => { installGroupDb() + writeBaseline( + [{ roomId: 'room@chatroom', groupName: '测试群', members: [member, otherMember] }], + ['room@chatroom'] + ) mocks.capability.getPersonalWechatSendCapability.mockResolvedValue({ ready: false, supported: true, @@ -191,16 +725,12 @@ describe('GroupExitMonitorService', () => { senderStatus: {}, message: '当前微信发送能力不可用' }) - mocks.chat.getGroupSnapshotAsync - .mockResolvedValueOnce({ - roomId: 'room@chatroom', - members: [member, { wxid: 'wxid_other', wechatNickname: '另一个人' }] - }) - .mockResolvedValueOnce({ roomId: 'room@chatroom', members: [member] }) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) const service = new GroupExitMonitorService() - service.setMonitoredRoomIds(['room@chatroom'], ['room@chatroom']) await service.start(true) - const state = await service.checkNow() + const state = service.getState() expect(state.events[0]).toMatchObject({ notificationStatus: 'failed', @@ -214,6 +744,10 @@ describe('GroupExitMonitorService', () => { it('does not send twice when the same snapshot diff is checked again', async () => { installGroupDb() + writeBaseline( + [{ roomId: 'room@chatroom', groupName: '测试群', members: [member, otherMember] }], + ['room@chatroom'] + ) mocks.capability.getPersonalWechatSendCapability.mockResolvedValue({ ready: true, capabilities: { text: true, image: false, voice: false }, @@ -223,15 +757,10 @@ describe('GroupExitMonitorService', () => { message: 'ready' }) mocks.sender.send.mockResolvedValue({ success: true }) - mocks.chat.getGroupSnapshotAsync - .mockResolvedValueOnce({ - roomId: 'room@chatroom', - members: [member, { wxid: 'wxid_other', wechatNickname: '另一个人' }] - }) - .mockResolvedValueOnce({ roomId: 'room@chatroom', members: [member] }) - .mockResolvedValueOnce({ roomId: 'room@chatroom', members: [member] }) + mocks.chat.getGroupMemberIdsBatchAsync.mockResolvedValue([ + { roomId: 'room@chatroom', status: 'ok', memberIds: [member.wxid] } + ]) const service = new GroupExitMonitorService() - service.setMonitoredRoomIds(['room@chatroom'], ['room@chatroom']) await service.start(true) await service.checkNow() await service.checkNow() diff --git a/tests/unit/wcdb-group-members.test.ts b/tests/unit/wcdb-group-members.test.ts index 6f721c3..e28c34f 100644 --- a/tests/unit/wcdb-group-members.test.ts +++ b/tests/unit/wcdb-group-members.test.ts @@ -87,6 +87,35 @@ describe('WCDB group member names', () => { ) }) + it('reads only member ids without hydrating names or avatars', async () => { + const getGroupMembers = vi.fn() + const callJsonAsync = vi.fn(async () => [ + ...groupMemberRows, + { username: 'wxid-other' }, + { username: 'wxid-member' }, + { username: '' } + ]) + const getGroupNicknamesAsync = vi.fn() + const readContactMemberNamesAsync = vi.fn() + const hydrateAvatarUrlsAsync = vi.fn() + const client = Object.assign(Object.create(Wcdb4Client.prototype), { + wcdbGetGroupMembers: getGroupMembers, + callJsonAsync, + getGroupNicknamesAsync, + readContactMemberNamesAsync, + hydrateAvatarUrlsAsync + }) as Wcdb4Client + + await expect(client.getGroupMemberIdsAsync('fixture@chatroom')).resolves.toEqual([ + 'wxid-member', + 'wxid-other' + ]) + expect(callJsonAsync).toHaveBeenCalledOnce() + expect(getGroupNicknamesAsync).not.toHaveBeenCalled() + expect(readContactMemberNamesAsync).not.toHaveBeenCalled() + expect(hydrateAvatarUrlsAsync).not.toHaveBeenCalled() + }) + it('falls back to the group nickname without leaking an ambiguous member nickname', () => { const getGroupMembers = vi.fn(() => 0) const executeQuery = vi.fn(() => 0) @@ -121,12 +150,14 @@ describe('WCDB group member names', () => { wxid: '' }) as Wcdb4Client - const finalizeMessages = (client as unknown as { - finalizeMessages: ( - username: string, - rows: Record[] - ) => Array<{ senderNickname?: string }> - }).finalizeMessages + const finalizeMessages = ( + client as unknown as { + finalizeMessages: ( + username: string, + rows: Record[] + ) => Array<{ senderNickname?: string }> + } + ).finalizeMessages expect( finalizeMessages.call(client, 'fixture@chatroom', [ @@ -142,3 +173,110 @@ describe('WCDB group member names', () => { expect(client.getGroupNicknames).toHaveBeenCalledWith('fixture@chatroom') }) }) + +describe('WCDB group member batch', () => { + it('reads 200 rooms with one batch call and no legacy member call', async () => { + const roomIds = Array.from({ length: 200 }, (_, index) => `room-${index}@chatroom`) + const batchResult = roomIds.map((roomId, index) => ({ + roomId, + status: 'ok', + memberWxids: [`wxid_${index}`] + })) + const batchAsync = vi.fn( + ( + _handle: number, + _roomIdsJson: string, + outJson: [unknown], + callback: (error: unknown, result: number) => void + ) => { + outJson[0] = 'batch-json-pointer' + callback(null, 0) + } + ) + const legacyAsync = vi.fn() + const batchBinding = Object.assign(vi.fn(), { async: batchAsync }) + const legacyBinding = Object.assign(vi.fn(), { async: legacyAsync }) + const client = Object.assign(Object.create(Wcdb4Client.prototype), { + wcdbGetGroupMembersBatch: batchBinding, + wcdbGetGroupMembers: legacyBinding, + handle: 42, + closing: false, + nativeCallsInFlight: new Set>(), + koffi: { decode: vi.fn(() => JSON.stringify(batchResult)) }, + wcdbFreeString: vi.fn() + }) as Wcdb4Client + + await expect(client.getGroupMemberIdsBatchAsync(roomIds)).resolves.toEqual(batchResult) + expect(batchAsync).toHaveBeenCalledOnce() + expect(batchAsync).toHaveBeenCalledWith( + 42, + JSON.stringify(roomIds), + expect.any(Array), + expect.any(Function) + ) + expect(legacyAsync).not.toHaveBeenCalled() + }) + + it('trims and deduplicates room ids while preserving request order', async () => { + const batchBinding = vi.fn() + const requestedRoomIds = ['b@chatroom', 'a@chatroom'] + const callJsonAsync = vi.fn(async () => + requestedRoomIds.map((roomId) => ({ roomId, status: 'ok', memberWxids: [] })) + ) + const client = Object.assign(Object.create(Wcdb4Client.prototype), { + wcdbGetGroupMembersBatch: batchBinding, + callJsonAsync + }) as Wcdb4Client + + await expect( + client.getGroupMemberIdsBatchAsync([ + ' b@chatroom ', + 'a@chatroom', + 'b@chatroom', + '', + ' a@chatroom ' + ]) + ).resolves.toEqual([ + { roomId: 'b@chatroom', status: 'ok', memberWxids: [] }, + { roomId: 'a@chatroom', status: 'ok', memberWxids: [] } + ]) + expect(callJsonAsync).toHaveBeenCalledWith(batchBinding, JSON.stringify(requestedRoomIds)) + }) + + it.each([ + ['non-array result', { roomId: 'a@chatroom' }], + ['missing room result', [{ roomId: 'a@chatroom', status: 'ok', memberWxids: ['wxid_a'] }]], + [ + 'duplicate room result', + [ + { roomId: 'a@chatroom', status: 'ok', memberWxids: ['wxid_a'] }, + { roomId: 'a@chatroom', status: 'ok', memberWxids: ['wxid_b'] } + ] + ], + [ + 'unknown status', + [ + { roomId: 'a@chatroom', status: 'stale', memberWxids: ['wxid_a'] }, + { roomId: 'b@chatroom', status: 'ok', memberWxids: ['wxid_b'] } + ] + ], + [ + 'malformed member list', + [ + { roomId: 'a@chatroom', status: 'ok', memberWxids: ['wxid_a'] }, + { roomId: 'b@chatroom', status: 'ok', memberWxids: [null] } + ] + ] + ])('rejects an invalid batch: %s', async (_name, rawResult) => { + const batchBinding = vi.fn() + const callJsonAsync = vi.fn(async () => rawResult) + const client = Object.assign(Object.create(Wcdb4Client.prototype), { + wcdbGetGroupMembersBatch: batchBinding, + callJsonAsync + }) as Wcdb4Client + + await expect( + client.getGroupMemberIdsBatchAsync(['a@chatroom', 'b@chatroom']) + ).resolves.toBeNull() + }) +})