From 6960b3f7aa16f6246a8f25159c4eea001db9b179 Mon Sep 17 00:00:00 2001 From: wumode Date: Sun, 17 Aug 2025 17:09:02 +0800 Subject: [PATCH] =?UTF-8?q?update(LexiAnnot):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=80=83=E8=AF=95=E8=AF=8D=E6=B1=87=E6=A0=87=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- icons/LexiAnnot.png | Bin 53047 -> 35574 bytes package.v2.json | 3 +- plugins.v2/lexiannot/README.md | 3 +- plugins.v2/lexiannot/__init__.py | 1338 +++++++++++++++---------- plugins.v2/lexiannot/requirements.txt | 4 +- 5 files changed, 802 insertions(+), 546 deletions(-) diff --git a/icons/LexiAnnot.png b/icons/LexiAnnot.png index 651e0977e025746940550ff42e40bc07d1c5a876..97658e18fd8f9bb4de9726bfac27e671814073a1 100644 GIT binary patch literal 35574 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 McG9%u$oW724-xBa?EnA( literal 53047 zcmXtAbzD^4(_i&bkx-;Nln%+2R-{3sJ4ImWB^MM#3_`lQS-PcNVilyjb3s5FM5QG6 zJ&V8h5A_4*-Z^vT%zP)W!5V6cMEErL5D0`wSxHU{0=X6d{=C7v0e+JcQ0@)>x#F&+ zC<7@UpxXdH{Acsz*%JulQzXHe#dYxWEf*z2cL;=H6ZhxJN`x#i1TxU4EcZm`rP(&- zrU%{1!I3L#+`X@ndWwVWayXF7i z)o)j4XOc0x)x1aV2_8QDd1KC}qWDN^uDg(*gCrr~ca29MdF7(B*Os3{-Am6pOe z&?EjrLvJFw_#;iu?1Cp^Hq7BVyM)mXmdUQi%rFB=RElpTtsrBt!)hC^D|E}N+~UzH z6|8T#UqApux3dl#Uv#PMYDj{g_ui6!vy0vJ-9*z1G9sW`o}K*a&(>FiLr$tYYv=U@ zB~A%8ck>I;1=!v4!uMLHjM(eERN0)0oH_l)&tvQwfvn^qB(s zs$VegMZD}fX(koC`5ASPQj$t)A|==}+#e7Dn_%;Jx)jvyWOTMk$A*zYn> z6zOb49p@~Y5^Nm_U{IVCb!x#5hu!3hN>4sL`nCSm@K}-aS^JOqoa5N7vT`(*63F9{ z6Q_jcS;ohlhdS?aLYiNgV(qJJ%rOGn?sHM+1QlJQrGD)m?k`kB!y-1K1B#Qhu4iPT zHU3aOe^RxJ_+?(8PL)u2RWM(^LrlS{)M1LR0d-zzIVB?cc{nzZI-pa%7rjyV^*H?c zk4FKoMmO*O+tR-#E#KWc2Koz6ce|)H$6zv&;RWMqp4D#aa;(KxpTEVz_st2?2#c1V zwi7z~)e{NSbu8!YPYLAj%w%9wL?|NaL{n<#hRXyZEU>)rsXLv}tztQ|eYyIebKly{ z!Z#J0MTrhfvrGJ7P#&)v&?lE1@yGWIxVb>-Z7ghLWaQOCzQT-Hf1 z^~Y_llC6WtK{NSod~P{DTAkAGiTU(X#07b0{({9^$yebukulSDx_@xluc;!&4k|;})je)x%xEL}bAYy7z|Nicbt(!JRYaH1o(#k#vp4qH;L4b$I7-BT5W2-tT1J-pLI)f*2MrAAa1>8wdox7~Z`&(Y zud;hI=E{Yhb@bN`AbgB4X=i7ACGqkH&yg>g0`C1&vrIXsE4mn_AUX%XA{O>Fhu>zy z4_uMoHybRPzpqc!{GE?a&c7O^z^8f68$%T0>qV3DhFqbPugL({`e%Dsr>KW2-yqZnDY85jS+x$;@|#ms9h^u8XO4q1uQ0 zECet!TA%Cjen>J6JtFZLoGo?_w!g?nrZP674&0O@UVTa#E*jWqnaS&=6pK~5RcNHIF{rAUbI>BBH}NiPm9_V2aPv!}n$B`)A7P{2#(^I=%UT zpXClkh|u4CpmWDw55>F%)vvDz+wk-R#^hW)omqUX5-X+tPiPZ31E3n*IW4pD9K;51 ztOmooya9ARD&*hxM#Og8Gew!v=-<_SSE%s3aPQ+PnTXY6LCJzFeu}!5Bk#K71G{jc z{|Sp2iSjSLArPP4)LL$`VvGhN`9ty+&hhfSTB@rYoX8Yo`P58n&r3bSqA zgcs^vI~R$82&!AQr4)wglza@--P(*+j(|Nfp$U`36>wSKm1N{eAuhSSsR^hSkde%?5XW&2=Y&g9Wmy(xkN^g>}gh zw~xptEA={MqxD~8f7E9xj;3@JxI{+f;XciP=kNt*G4D)9Hur6A`hM@~vC8^lr);wK zklXUw?+OQ)*$`XHNiZ}O!Aj=RkE7$o@8zcGC+{wmXrx<{`~7BE7LC!)s$7!{KXqNb zuoF?9F~{4w9DKRjb`M9m`S`TQlVF$>;~=l-XHoRvols8VOH~$sFk1B|QY+xOd_^nP z-K{i~4)a>dZYq`YzbhVb>iFLzD`GcZ>(^&K^WRgao^LxDE;03f9eXtz7op^a3-O{q z5!0nOFwlzNKk$%=)~CbFWGN`>Xy9F4mwR?S$6hOTXy;V~Ov-$OcLd$w@QC}L?1M-V z_sIwQ&-DZ+B_{;%AGpa(a0_6J7Ig4Npk&g;nx?AUt(rwWTldT110g}Bou*}8Xs;R| zcOyWW0wNOzKoYrn&3Zy*eQ{J+^lwp(`T9ivB}m~ zlCmuQjXOS!+Ly3U9eEjD4N>RnUH6+hGInhnNz?doLs5i1k#<-dAuG>}$ApQesSCrS zEFN#0dD*2F=U>{(Rda#KM@Shu@mU{4;Rt*UkIlrcaMel)i@0g2hBj#w&pIgl5PV83 z4bxi7>}{t0=*v=W7>bEH$h9Psn`1aUy7|c)cU@6gxy6O+T^7I`mb@+06-E3uY$sF^ zvAL+ADlR-GjRf->k&f8`^o6I=m5#+Pi)gVgn3VZKPC-p}~ ze#*$W)=M|)XEx-0vE6}-Dx5KxcH$neMQVcNx)ijy=wmDg)`s&Ew2b7#V+wotPRe5) zjyz>n`AjisniLV<{gfR4UHLwmqIZWotWcEM!BM8ZJT#!J$s#+prS0FYBV4Rv0p_$Y zG6qJGQUdz^Gn-eUC=^%yos##EA^c7ED#zVvS^a7~iIf8q$xb@r-YqY>lAufTm@cG^ zH~9N)S8TDh5NUYlo3Q&E>xLm?@*ky45W1B7aoO7TF%TOGw6(lxFq?`Um&ILcuIlRg z$?#_Bb4i^nz3U5HcZ_KjS1449)NX1*Y`IU%8N}@m_^qV$U+gnP_3?`9g&+L(dq|3V zv&M&Q<}gvkjllgy3L+kvs*8hBdbulE=g=|+R3K{v?2ax`(~D+rYi&9lrsT?Ml~Vdb zGiF5=hWi@n`_pt=>N&64T)&cK`6~UX?q2y^VMB^kF^iS?av*-IF2Ka3_6e=aovf`i zCf0)Xw~rsU?Vq)3;PDqNKcOfhnxyy4@dN4wu?k*IO`{I$>zPy!hK( z-P@z+C}I3azFXubtNx`ixpy%Ff+ifw$YUZr2-86vOot04c12HEd_R~2tFa5y(F1nZNjV4Mp_aQI@&3@cgwtF^@1G?62%s6 z3txW!a{p}M3hw@HxtNK7P%u0rpd3D5Fn}yPe!uxzCCw=Z5_MNcn`WF$6%pbIbx%W1 zi|DVC?|bj~6ub_|7Y45?Negi}46Q8?X8vt{315f>`1xB4a{*M;oD)g>-`lW!hLfVQ zya?D}xWmM?U61L0U z4UPBfexlp^WZ>1PZao=`e&UKVEi0E|Z!%w@{MmxWlweOx8CiKCr$@ zSo!f!!|dX}cK+}a8^%ZuLrZN)Q1SwJ5K&ue1sw&d`MQx~SIk9O$y%zep}gV=+8vyM zI7Ws#4Is-)wcRT~sXG1PywvHlL0}UX107cbyFz&0s)>I6PdAxnpF0CRk9)B6a^STn zwZ0O0d2+<34S)UEaKX{N{ht#k_dvXNn%0lf{_ZwhX`GU3!(@lI6cJScoY^fElXR;yY#$kujY(7pAUr2dV z3G_Fymm7~7QvV0ZCDEme(BKaGJS-If)BEPJHM6Mj^^U&)1y0W`*4*1<*nQc{$xT)^ zVb;kOlhuNF5G7q#OhQkGfYR)8%7HU`=c59_$5>i2+#X%bRz`0wG(Tzl*iM37+=nO4 zj!hF`6Zs&JBBgLytyvZNev>W#zJfFt79;3K>Pxmta_T}791_S!@fqAbww5&sGj2k1 ziv-*B+;4-ZGKF-s%m~TDhQwI zlIaSR!hX$CPEJMf?h`B}E>9&%>iY6dG46-Knt00bAV7iQ0rNuk;tM`dC=m>pxxSnp zJK1Ob2{@x!-UXh^tVSXRX9DYlJv95rF=?&u8yH^A4fjVXy1|Jd#Qepnbu;v&qoqeC z{Vkp2qRzm)SRk5f>`Tqw2<0CJUY}E-*@C63L|TMbA@7xUA~f&waD}Z$G{D(aJho6G z?*HD9)y75p4KTAE09Xwcg3iQ{x6LU7v}_&@v9wiYp<9O=y5eg@KpU+zOzyj-lq6$a z2;J|m-M9j=O%``HfKQQ(-h2AArYkc|V|P9V`jIye+}g;)%#yB+13v-YKN_k+YvFi8 zFRnt~4(2eV6=Q_015Ftxx0T^tC|BFUBLPQF5Msr6y0#r&kAU9}--1cCGeICX3+!4f zS}PxR2ydC=pl2vA4k(;au5bZ==Xe>rN&nf$vK$D6j^W^Wt!ku-YCWuzaPM|~>bb8T zj@ewt7?f`wX%*La0;S$fz$IKu#<$MpO}I-hJWB-72S2xxaM_kt^l7= za#CH-HjD3uOHD%iBzpF8u)W2=KSt?w3iN4PqR71v)d>Qm5J+x81N>3K+z?x} z+1a*9w{fa-JE=J5fqB@P0WK1GQ1Sr+vAR)fpER`NtyrDk;okpF?af8v`4I#>s-$O9 z&7&CFL_OM>o%hb2Z(n?p0~YG@p1%t+?G3(FNaa2qfy2PLNhDch_*K zJgfJQfo#(~TNznA<|kpab$l+ede$SAC8XlB@>d{uG_~o%<;JPYfd>j&B8ZeBz@D^L z-j;cI(Dp)yu)8v6KM**caP14K$x?52tNxE0!r4G9VUZ=X`6aWg<**&AvHu_tjj{ER zstz_`2UCo9RUgOSE3?YCm|3oo-kGg0E_j=VGEKEzB)9^Kr^c3~G(JJdWZmvcQypC$ zk6i4V_h3&Nwh4^n!1(spa<~&tlOc2;QTj@ob)u-_XwtejQo?*Hq%uPi{Z61&GqGb-}hfHl8qq~Q_DG32|q2)9R%wSP~hf%?={@2QI=6S|;_jY}X)=nXvkFooY{Ul$eKs=i=`)Ar}8AGF8>cxh>n( z7=H^P+_p7h6&C3*5m1cEm`oQA{h13;gX9&`=faD={~{Hb*T0L9KGnRFapWmvzF~XV z-|e`!b>V}HJL!`wP~(&1J0bos{c2M(;Me?pQL%6Y(N@5S2HNscQPQIt^j^jz4TVTi z@?M${$k1Zb&)h)Wo%LwVyw71}O#V@~duvM1kS56Q0{TMw?L>|5-UG%w67rGUuKg!N z-Q1!Dz#$^fj~)Q+oZ*i*Jv|#5-l+#E7cQoNXuU(RbB;GB2O697H`%<5WLVf=Xaf*$ z_aV-|ubQr(hH-L-244nfoxKWe5N6kduw-fn=9lRn2n;yTm1xUTv6?~%eiax`mA^<` zYq1y99W^RM6J7e`Qeth&){|$>qAAB|$YfehfY8$78b>_yzM(Kab*fe9B`oZ7XiSFj_J3Fdlu4IXeqG2;TB-4 zu4yM1rMtBb3z+?I$yBju%By;$VefLdX;X@C1CF!U{GD9awzMNpQ7wLc?kzm*`5mC< zrKP1`kL@qAjtxwzA8G)P^j05IQMFL&kh7N`o&37})IlKiP8F0{ALXa+il!JodjiBNm~JHCAzaciUUu`T8$Nm! zEppF4N}82I&`G~qp%K-7227rqYO|$txZg-I^sEF_Cw9<^xM#j~e;RZ}I0Tj$6Os8t zAWXJ21hOSxhf7Bq%CTr3aiFR1;~Ff?b~h)2Tygh8{5<^ViM?Zh80OYm5S8H*yjyZ~ zNa^r2gB`?oaQ3%c_~VZstF9i_1w@nkN2!L>h}|76W2f(*8^9ssmx5Qb%CZw3Nw5qN zUR>7KOa>ekVtzdXYud^2w?JIu@;H@#5%7sSlRKF$MmqcQSSfPwkhO{%z8f7TgngYK z^jCf*kDY6oh-}S89aw!T_Z#SxOY?p7*dQ7}{B|(RDR?F2P+CEcSVl{%95z4L1=Qnh-K1z$>wGbO+Y?X# zI9dq0E2C5Zv+z8mq(gqUm^5Z~ykG{spto&n7#q6@iph@|dTG!oa=@T{E~wdiBDR$E zg&fWqO~4kmJ|K3yGupQoa#M?nL`Gb!m`Qbgg0vha5XS)g;We=oU3w%xi@ygf?dS0V zV!x|bxvdz<1ORmXW%wT9PUh`_!N)y*6$*IFJ1HV5_%i7@OU)9}#1WGOuwbCb{kPtT zdEbu%fN9opJJI;tjuso50A}XgW+BPW6U|@-Y9oret#d{Nz|Okltv0eJ|Q=|O{SWK5}sJYw_002MG>2LocTa< zMRchGd2occmdX87ps|;{3JJqmYq_}h)Gq?D^MK-`c&+|z$^sm*F46FSY-K=b+Al^y zIA*BqmIpQH%yp?g3s@wcy@1P5j?2Q+o0oa6wkq)d&8XUdqR13 z^wB@+Elat4<2Rx$qDvk9u6g8ltF71_y7%dY>Eju{3MIVmUk#Y;U3Tc+cr?yhA@A~j zUW)|d5x&n)3LUpi!J;vbOH+qUY&RgH2(>ATP zVg|UJb2dK<%QfwT$MWXkTdU6F37R-|AvG-7dV~m{0!sr*@;h{(Basn99Fw1nt4Nzl z{mJ6O8>hu!S8swRQwp#9C&6}jhWkS~32$}3#VHN(Xuo+wimvSCUK77O6YM4;vH>f( zUOL7Wp!}qEx$q%g*in}b9=xV-`c!XX?ffXkKT23>j-x@mXnOooBBErsFcgZ_A`PEm zkHNK%@F*j{)9KegWI;4er_zGWZF!yFedVWYrmy?M!oB5wajGVxgwIxVv_U($696)q zuh@K?*4<9vA_RD`x_}_!DX#Lg zxA1{PMvJAbiXbv_D|+#M>##TME>OWN-lEgqTnl~BOFUu*jh{aYp*U-nt@620Hxa=~ zikoz~;2Og<1miFBb?Uu3YPw{LN1L%3al|9aoEMDeC7{kC8iP|@$c}1wF~=yV ze!?h#EkeY#ir`OGtM%gj?_d9rWTB+QF89M-tsD{PU{EqnJA!4yHKS*YM@|dGL^6zr z;;94uJzPwhGdDI5=c@Rt@c>{9i5(tR+qw`{SJil-EzgchLEf!0S6R~l*W(Yx@tXb& z!SaksuMF63@pcN92;0mJim}=-vNNV^*OyotHQSm3$zREXx#flDR&OCq&Q+iwxuv{|+0{Mab z--OI%U0F{)Jlds+9yMv3NwQshhP$HN)ZB6f-K0@VP=654VE!RQvNhc4Lgb)enACyu zfn9{I7zuNZayY6@CK`k^?`|>s?5(;^9MQFTyUU3hb&BCE*D5C0qJ+FH9rPd$9D%Po zJ8Jd+?~!aoEjn(f?4}}30AV38TWJL@p&YGz#mR=0y z8yjf4ddpzC`VK9(|9ldZaHmQl4b^j{9pcHkKh`*^m;Z)my- zySGZDjE8p!vHVh|3FwqSiRIs;D?374Tt1YWGVqP4@$2wCXV8yYPrdN5lDQgdRdw=2a z59sBVsY!APY2pr!SKk?e*+RebCFclCpx2+P#Od?jAx*0PEYVq>w4 z=^MCsk4*L}<=-}{3kNz1!RD<}CeR!PlC+_GT|iyu!pBZ#tu$q-{|kSCxi>?qJbuA zbyhy$Wf1*^hn0E=0x76-`*8oWU<$Ks@Cd{xA76H|l8tDv)}31W$;iV`%cZ+wC}>gN z^D~@LxbPo7C>9n4?L${kJNCT{SmuBKtSP_$5tX!e9m%a$)xBtDK&>=t$QaG_OTsj~? z4tDsPbjH_+g65|E#vz1ss)oFUOuZ*~Hhf69eU*V zdmTDaap9yt$q@*5-eq>M__j{pf~?ptf~)%>0=L*ZR6dLi--!N{7uf$7M0JoX`qzT_ zGNF>@rCa6)3$dglcGPk42d^eSN^09r)m~6OxFmu^MFX=xaFKFz`iIT#GUBYR{gQ*@ zrSun+IGYAFl>y2Q4+n3-!A)*MLvYOW)Oz4Aygc0DGWGus>H&e~=ctkgrX2510Yg1I zTKD%b7;~#d8agLzQ2gWfc5a8xHzM~&WU|+te?gv_QVKsqw zNQQ9PYT`x|(WM+i(nosGM z*C$>>g-5Y3a9T0+8(gT?{o;$`qn;tL z*BbojlHGtZy(`fY$&72(Ei90_X?*77#&Uorn@}zYu^~!#G9B-a_bY}V&TX+$kC<h>An*?RL>j#QpUkP?CW4xBI$9fin&hr+I;h_qh7G`Ay=bJeGoA z4zB$seX2OufU76Lb2VKL-rI!k?V%SduH*e)T0eYxt1bUCsI@_&-l@>04mg5qty+2~ zoX*_Rko~^0#CYqRj}FH`vZYl+q-db7WNzatx@R_B1xtb3xh2NJiMYcHPR&mTEZIkA z>XMVwZ&VN{NiT0sdm|t#SEk`JaxvQxTADf?O%8m;U=@{SG;^@S zgzCT7Y|DyGoM|_jD?B%V@I2II>fs&;hft#%huECU4O#88nvu!Xv7ZTR)K3eo&Gl~K zeoa?eJojjc=1{7_(;~}vhONk0sAva4*!V8DWrqg&;mjS$o{`+l^N*RTC z$~m_l!6^Ty%7d(u)L8@8OLtV*Luh>Np66h|j#m<}5i2-*QCDIdx?Dq z{@30H9DnHjcAjVn3$(rN8!n~)-?E8vtr1n#!`qYh*gqL1-Jqrje$Aer`t%>^Aw7ka z!{{W~qjQC$v)vO1;+Pk~cJ}c@R`JAuv~;RwNk9b5iKaM}y~-%5wTLi%pI*euE#cpy zcDmAX;Bj1=y~Sn+w6D_y)I_+L!E0~pCTfffUL;*J;8p#q6L@dI75YyoHH^-+8kV*E ztjkn~jE0wI8_GB=r+{m^6Wj#MiEHYjN(@7nQ2qbtc;<;m7k>^YrO4L+<0;FxOZ)+K zh`98qeKsi<$BSD2>slkDV<4>N`1iJ63RKELKJw@| zyV7V%%#~=55u_WdJeMboIPA91hGq86wW@UuHLYViWL9OwBXH!`dF9eoSXtHr}2pE~GFjt~wr{HQB0u~ia z@#ZdW-y!Or@IsbWPhDKywn42hxTx-#1SU7?PC{H!7<7>?0`Vb`q+r!Ho2eP~yxJL$jM*D@^<*Dp+VP?7a? zrWvSt5_0fPQ6fbw;2-Uc7ogKU?y(y2r>UvpuLGT16t2XoUq4Z;0&;!`lWF0&jADHP zi<{3{mC?&2SK&s$3}Fc_iI39jSUHHdnrf*6kfr38E^CyWMDh9CaOukb*5N%w#wM7w zUuya#v?T#SR3cXF|1&`)ZR8$)J1Bp1;Cg)MdFIT!>~q|kn-f=Q`T%8!l0FcpD9Ui# zvl>0ffBGSe^r5+%usbCY47ZxgtvkpvnWtMpI0hc2{l4XDf zGjCPl=6a8}7?(m*Ez`f-uipE|Qx_R|@nV=oM<6Vlgj0{GWQ8?~5Ts$^h)aF|;UFi6s_m-D|9H|V zUQ|`Bo@b!h^a?|>;lEx&9W)@5XYKfL9)(GJr_Af{o2=d=W2GbIS7!72F(_zu-^VHh zP7KltwCR(IbW$f-Wb%l{;G zMS!h7GH&B=1N1tR1Hd?HJHp*F=AR_4%0SbU*Q4uSEdDw=gKB+WqFJ^4cMxJ0vvcG$ z)KzLkXo$#W>}yXFJe=2h>(X_;#f?#cDT6%wrj3gDtE7|s6~Mc^N-IMGRv}km&TYwt zyZa%Yw;bE3MXXvFCi}#(?KtVYWuhW~5C`U2YDGbz-LEgC z7@Ulmmcn+L3t7LWYkNHf#%%w8)n_Z)RDk!zf8~o|C59_`3UU8Cg_ENhqcYVYw0l$? z`yLJNnTn%Yg(wQGu}z8NoGR0I02U_&+NFvYnP|_RsRo4~%!>7O{}b&{5sIVSSYla$ zkC)$A$+VyA-zg!&G_jM4a~he9Xk1y_?>x>GH?mj`^Zhb$34OL>4FO{w3xviCdy^W} ziAfgc5#^Tx_+>s%q18V}{*gDg9M0BDnEFpHm3L|bg!7FjVfz$XBJ8-v^xh?VS{bkq z(vX)gFng>MWk&_{3)(71oC!OpUPo?j_)VD=7smY;r;w`!bCn>;3z>4IZVDK~HI!>v zW?HX<9`#a6#CpkNh4T6&m6u)x2%a@CXt|lp z`w?{KANgr7u4DJEb%_?MschB}g5*-jjbP()q;s@X5EXG%ltt{i;EOL}T8N)3T6yr& zt5*A;6MH|#4p_5Z5!J~g^SeGDVyf)PSFx_$u2<#dM_q*9;?5U)YjSRz+;tR=)`!gr zDa~Us%T>0&N~+dZ{JJ;qBCRq0oK{uKD9nV9c0=K28LH5e!ez*{M*#9 z{%GMy^|gLNv+2F37YF%$KCAM{$6t_w%Rd*oe$c`X3XfW}hIa`$!_zq0biYpNmWdz! zVIb4wxSDL|0cTY9CveWNoi+b6sbiP_nNMhE93#MzY3<>J~dR5|Q>f=o!b<*=Ob}&|e(u|d~{J2Q9aqms? zUXYE|qWJ}L3AbW5DtNaiBCpr_D5X}*T>E}{vecHy%L#SwNgphquLN7D`72Y{qrX1M zf2t*{=kg}IyR;wt(&MKkXlEdiXi2PJ>TbKwbPgs6PuAAM=43Yg??pdn$i zi|c;+r0)1BrtFX+_3@{{s&g{M36Gu%SJ%V=#lM{Z^R{tJXwkk$gg{)JBERHjw>;5H zh#*!(GGEUUMX`QLyUHonlBkcDuu9pz?*1UYTV(!0HRBtTN8U(-hia+J2no-V1vTnK zRJw%qR;#>OcEk72=&mt|pNXF+u?9W(>hUp*D-S7x?Hf5W>7{21@sIB6bDvE|sm{ps z0Fw+-k=kKEtV&Ps&pTG|B~&Ai%A)MXLjuYY}WCqep3y;pz+gAv-!qZq9{ zIcl$VB0+~CM(gQc4ci8FCN!H{=gyQ>>Yfjb7t>Qse$6ddozNfkegu~;UQ&F!K<(oo z2@^RK!AwsR5-9Y7zz#Icp!vzxgrzrKDs^m{Uq-f6!Nv^WCx@`DxqxsY8xH*F4dKz* zKZRf{noYp+0l4T!ti|zqf4%kAdwDH$<1Ig*D7{?x6DWP0vCW|-JjdXq7BJYH9;**X>LBt0Wq+vwS|8KNn86gk-QmmBVQb|%$g zQ@wEaZA8HUMTe~38zX1t@U_EpJ(>ERo;I9myNs!P?HYaX3w5&!u|HZg-(bk4E*@De z-Gyf+P+0eIl>$d6>a#kUX^UMg-bnAdgyd$mXYbr`)%SLEZ$q#1ue!M6cv!wp z-3M_=aLlO@@YiRxdNckwiyW`CgeIS#7UX)5!mz$iziXSD@-j*uT&4dndV)s(#vaRX z3A&!ud)OSyJiE$AQegunlZ(rgEMtZDr894!k0pN-s@c32(D-k1vz zrl`tr5iSYD?GQNmoXv!TyH}w~r6JQXyX1`?`yt$cqZ!hz-#L>9M|L7%6 zZcD!2gnHV&YDQlzg$(a^N7Q8u^T&Q@$V?}PGlAV=Z3P9n@36Uh-s=|%Zx|JY7M=q4 z`{fDEn^NXb>;+#@MfvZA)Tm}nA{)K=qZ^dhNvwc($8Pn)aq$kwUs^M=OzymZhMe*N)(l&L0mKw&}&#A|3O$abWW zeBruZU}-9Uav3r+T8j3ew`}377m;x*PUJhB-Dekq=Mkq(H>shsb*JV%Ed5mu2Sydt z{ar#2UW^m3LpC`wkcP%8-Ula-al~E0Tsf$T0l>LwJ%tUhTKy2&^AkaPcEtQG@kDA| za5tHfT0A`NhX)^VfpJUN=kF@VzZPVzCO4rMiTujTh3Rw-ijj$4hS2}S{byuoMDTBt z*;vyrRy1lojF?{w0uwHpFga@ZD_P@XqpJpL?|5h#Y#v&0S0f$}*+hBk+)sXK#+dB7 zD_iwy^)!vP?|b13zs08&U4^3$VqzYAeob*@C-)v5xnks5i)6Zj_BRBWhcILm47vK{ zE7b*3lG^W>sA}cIt2wzk!P?pS-XE!O%ETRGr7N4;&$s_(mF~C+>jIxfO#X?xK1-U z3Cz3=J$cL*{eoj4dETQG$wzBwB|9tWpts{;wZ!yYx01vAtp*xp^b+*E zE97N1J%7eU&c8HPNPFEP67mg;y5eHn#C#Zd0K-iSFIIfjdH^bSdO@0Gz(9@cL|YPH zpG`WUPd6+M*!}%BJLzjR z!TusCt#iV{W2aPpLD+=TV%%nmKDKtnbCvI&(g3_F=NyUOJF- zkVbnJGWE~T!QF)Z-N8I27T)~q7PW_J>CCZj{t)bb%`EwS{2$!|XiAO__jck4k~5Ie z{MR*o5pEEIet%AQj;2dK-6znhcc{l^ysr^7YfJ9of>GpPUhS>7*7cqBBdeB|^T_;v z2vs``lO$jCp62E{sN>6i=Pw#2D~CT82jd~V7e+kRG5p}m3t!N^sE=$6it zHm=1*>%kd>;Gcbh_QiaH9XaT2<^6T;y^DRyX)vebMm+t=_@Y+x zw)kzYoiA%Xya|HA0o#hE{lyk!*WXUi9A1;npZBf+ZuC8QP@8JAz3AQ=S|!-18&Gyq zg$i<2t0k~vU&`9oIUS+T@Q(W&jnAS*^bs#7B_AQ*wq@bBffOn&j_#Re>6W4dO1F;# zA5xZ|4C34jp5sYl;UqhxV{+pcN5!kHK@yx8W`-W+r@7ZDT~Fgj9|}1E~sN&eR3L5CxiTYai77 zg}`T^tb_{SV+DF>s>|VSWK2(}V>R{pWq6$~w_})WB2c7larfAvN=;o=$ed@K7e|wvy+E1-92CDGt_nFd;M_+9QT&_&}MbK z27NwpHO4q7k7rMx6jkfQivL$>zG5#N0A?BF!2AaK;Z{u?b#yhDUCp!t*RMx&*jC9y zccu;;L42iDmGw^<<^63%KvuG!M1=hwau6-^5RJWZo!M@3Y;vqC#;=7l*zCM1egjsa z2;o(E2xm?w!CEXhA3Id5Jq?DPcMO+F0i+qCv7eak(&mdoEVGS1&rb*8MQGD$sQIwV zjhp=&6UIHKX%9-0=~cuzpvLvxX`L5iFDX)-cBM;LJ&flC@!x!}=ojaOcU>rchP!7F zOP3Hzv9SpG?G@@c&n%%un4IDQ18*4WiW$A=_H8{~<(R%L?pNu6}?%E#5B<{b=jgw?BQ$CK#?YN#?f`zu@9~CtV|6bToZ6 z?w%D!_mKm1T?srj5iswH_~6Mop7GR&r{-#4koTclCZ{D|i^2;ti>X!zvM&XN?g8M# zPD_joq2{)_YPC6!kf=J|_v)g%x8m6|?mHBB41dY_pw;}UTD5t{%oRmmNl(D* zHWprQ(K`mjSKH`yYA)mN@v`oL!M2knd`>~d0*~&axPDSsXvS309)2$vgO7mSF5%x6 z$1)N_&I0L6x

YE3ky1aa5d*DBS(a3yhuUhlC>C*60Fr9uS{dJrz+-=AoxZ9C?2w zoI8-W34TRbYYm^ize(b95~$WFC{LI!7==21@C*idosbV>XS`@k+OeZgOXt>mIzF8^ zm{ixkgU@E-iX8hnx8XNUJhCw@ zY?%<&yuR51GvsZ0bH!k(KX|hA+2t$&ARCHIR*x6RB$npJ!Ts^~-;ae(OJhMWa2&Hf zofs(e*MH`r5sjE;LZ^yhGdpMM9rM#j5sBEFMqe&;i+OV~$Y{`M&peuR*vY^R#)LRb z(8dRvuIUy+Dj6f}5evJjhPsbbXf_R4x5I$mvuHb`)zjd|!fEdc?BXk1P%~IJW)|xz zpB?XH&&g}^a8i8PENk*&4&iNDT+7a{f8r-~IptxP-D-o@{hn7ckekBW2B!HK&&X|) z+7tzf^rZ3o#kQi?)JM4%Q=%=W2A*j>0wJ)HJX)w}vJ6{G_$3C{VW&7uDEpvH}z zpqbc^Qp@vo$QyF=J5=PByjAz(1*=dacAK?7@mh!hYvHt8;{9}}R-r9A{J|6zXAl0%_F+Bsm5jkfopN8U638rHAxg>&$gm7(} z%6r4zMVQ*B6iw1?$ywUQAA7fBt(W(4R?{P;99ham%SnDdXjMx*73o%MG}U&|f`&O9 zHJ}cT@WITMCf;}HF~`;;zoQ0ln=9A|_H^QLmwaKtEZ66+2+(|1q6a?uCI0o*DldmL z52|M_ej*2~igo|eGxEmo_!MEAoqj8ZuR)FfdL@l||C(-wg{xwLJ8hNr$&xRgR^`!g zvA_lR7pO9fR*ZJi@;Z!l@75K%k4DiP;TiXO(^!lZwOIgg^oIE`k`y%Bi?)U94izr= zB>RRqrU_`%h%TH?Py2*>mKpGts3>;b^gFA@h2*b}D7|_c-c9xZAw&`}Thd-dOi}$DZ#BbNGbqkn2TCGySZcg5^)hrpwxrsl%SCyAbCBX? z)^%(9JPnad`WLur416cSp!`(^a+W|0*uQk(`A`%mC>Ka1yzUEE$G1M{;^N#;XiNU0 ziFR&F0EGm#&f#ZG@>S*Ar|CFPk2JJr4ECJEI!9In zS8TkL!+=6iBg(G3igsR8s=Ea8v+A$wA9(7e&L^PdNH|B1ZKF!TpS5;ok{9dL~bQDrA zo`)YT%d2pB(U^HAS!4uY3r?R9j`$dYVA1qccXo zoe4NdPTW@l`+@PC=A|Tui92MK(moEpA;g)0!uVJXFPI}2RlgLb+UjnP?JT|CZ7G_q zR!nHtzI4YbJF&DC<1O;f2_~y}eT$WJ`tRiwbT#yrC$6-Sk_GWv%`V-s{zFv%io5c{ z;nsiYDf$L64w)ut@d$tP8;3nYk(2W;x?r$Vu-Eaeo_=JaMWsaFThHq=SnvP z3au(jI^DtV->-Z0;N?$et-+q=L~mWf+u=}(4-?9nrAyF8PkQB9i4H}f<|UW2yh$iU z(AmJF`0IQv+dFa_A9LuH*f&iqWJDMZlhV(x`w>m92GfE>Xryv{ zqU~DP5fs+=L)=j6g>YtpPqp_LRgvVeN!^!gkCYFlvyJ0dUKP|}iG4Z&ID0tAwpON| zKY>V7&$H^YnRUS*ty;B23c+9(x_Z#Z*6N}rk z7TDV@_Q?!?%{>QYgx_QilRf(qyGJyCe;r?coq{x!5V!gWI<9vTH#7q$uGuETRFo$f zKvJ1#%OAT0;^gG8=D#$-ziXtBP-v2&h^tE0;1S&X&nMO9bF+$Tw&G+T-V}?f9&!Pj zyHK&OcizJuTup4pz8;;0r$(TkW=X{d5#-5ziD?t-h{K^$QxLn>hj)v0WLi(U7@ZWz}Vxn|qVyPjgLO5Js zIHxU||38+lGAhchYZH=!po9-dDo6{?P}0(kLrROn&?Vg}q0$XQcb6cbqyi!}Al=%m^{>XDUuH9#}AJHr8G^wm~wIDBz?La$h4$x@axdp&0xH6PtzPJHaah4N^yGpu5dmP3bd3|sUC>wO8PoKRT4E9v5_WVSed zRcn;`YqY$P4w=(U@{YQ=B9~F@h8tQt#0~m16@Tt8d*EK!Q#d|n_*v`?52*O5Rn5hf z_Q-dE8lJd=ICd)g>0XX)9(-FDZP9hMW6&&LFneSB*)8`rM^z<6oU=Q_56~^WwfaC; zQ62jjie*6FySJO}tgj;osWLGzr|8HSN}Eke}5Ld#t8qj><+|9fcr ze%C2^uXwIX2|kDB17Bw_?aNF(_L_jx-%_NariWV(OpX#%B^17yrm*HWhnWwLoaSXq z2(RB3YAWrgGC_Wqe#KaVYi(3->Rqdn#Cu`e(5@~mq~Yr3qKkQ4zS=7LpnvCifLo`= zGYsH!^W_LCIkPD(Qg|#L+btW>(}K+!^BLB0Z+gA!@kf08T8~YxYor9Ir&QtwBg2{KY9M$2l61TJ%e(ZcT*Gz}Fj#s9v{(q(}>otC_K*=g)e5ANU{ zXE-?5I53!10FowkGQhLMna}UX?Lb)*Q+*--w^y?-y9{qnu8m&{ z%$ofM+H&(I9UZqURk7C#ILpLwzJ;W@_3yxkz9ZWMLZ>In>ym{SJ*91FVuvE(|C zbUtv+!zYx9$N<=0Pagq8%uAt=$->ftqac8_k;%fU{E170cxV{2Mx_PZE&Alf_i3?C zvQv=Xp5dL|-@X{Unc9nn8u9LIZmn%-K2lzXVP(E>*_F@q2rkRy7a$kPeBNF1mbO0+ z>XuP8BcX5Oers85kwD|>yR(I%tv?S=uOZJK@AQ4Y|31;vO;d9xDve(o(T$2v2JpOl zr(E)d68L9J>UN}Pp${!Z8@|5-&*($|?1AtZ(NFkLn#5g3f0pGZmqZ$~!|}O>CSf;B zW%uk&4`WoD_NYVOQ+JRW0&eJ1%2z_qafW3WbrI1~J-LX*Z*3NXt$&oq`<^ zx#U8Qek$O?NPPcxPHVz5J7^{ntqQa=oFYedr*>QIXp%xMM7+?8znf>deBs!cC*JPv z({4;|GAFr@BBa57ch&*+yPiBov}zsi4f}FETk&rEFv?pB6wwFh01G=oWE#(EaG_I8 zx&yz~z2=MF-!dT~;zxIc+(#J%1`WucN;;a7X#<6|$B0wko+p#6?fQ(RE z!rQipzM4R=7H!_lRjGgM( zaR2%oo{x2s4_08qaR(+kYk%C6AU$?QF+fkKFo_29b$W(e|A;QGzc#R`v-J09&qu}c z&w0A@MwdW&PiSdxu}*8ZBYGu>sn@$?@i=OWD8P-`X%*oN|uK z+uBiK9ZSz4x2mpZR6Xx_v&(yK+Z3p-8g<8&-$x(wxt`QD^705jm+;-?u`WVh@hHVP zHW@E{51yO%J0o*xMp!+c2+cp74}s2j7UH>ua92k4`JC`-W-hwOc=$G{KAv|<6}IuI zL5nQ3j#!17T$>wW^;2n5;vl`~72S@O51Rxxq_(!!c!6pkQ<(PbgXeX%I^LT|20`}? zMXqw?9|qM(aD37h>OW=lGP3d5`-{$m+X*(Gw#47h=%H?Qt*YK!) zOd$@SG6n%7n~#Tk)2K`h$seI(@)5M#$NW9o2mNBoAAj>N6zODNQ8eLmBW`}c2NwdA z#pnRBMZ6`_jQ;b6Ml#3zXot-FDnV$-lW?B{ngbF0-7mg#Cr`cW%7qoYwjFyu=;6q1 z^W#s0H1n_I<FyH5Gn?IuM(EZFv728BUP+$+5RW}BH?%P63*EI+6T)5bpCUvmt%gn zXxw(V$K#;{sPD}2b^Fwv0Qs6!b%C74*~}YFn|cfXxby-$!^7-w06IIr{Whs=o&8Ch z(!zgz(3nfNyHRNVyT@@u@b)_ms2#$0n4ZRz(!ubX>|^6o7w3k9XLvg*RKbxBH%DnUmY_JMK7vxYp+S1r-5E7g(^7Irm5QHoEY62 z`=z+FB1SF%o#ataoxlBl&y27|d3MZf`Lu=lYuWTfSORPhRr<;EVa6mal6U(DH zB$v&w7YaKyK^TLQfX|%icCAPxjNBO*dJuOl=aTW^y~C_QY=v)NC~xl7IDsBh50ltYW?^b;7XT>mBAY9M0iJnfun@BEziQcMKN)jCD_sx!m#=2^W8{0#&g1Wp{OKAEUz4%To;{B142BDlW$< z39Sj&W+#51=p~m8uW&m&YTcda`FO-diuPr)mN?~u(9LyOa`+8fkjxXNy1 zI^=NWNW#T7WvioPs>$*qVytDd&XZ{NS~G!GVes;nqmReqsNAC2FEa3%%jnaaTy{HF zR4t69QMcm6v_Jfxw4n#tn#X?2z-gj}7$g)ebn!un-!mQ2_66la(BE6(S9SaeQ8!TS zo*gZT%Md8#K}Z8?GWmQLovNv)_2{-vJB>q^R;0+bKBzHm>da3P*LDH80b2XLU6XxN z+?|hllqX5{NB1rM;syewvNx#IaV?wb4~{_T{_dXc95a$ryM}uy=-X??R#`;f{x1hd_b1jp?Zk=->P&{M>fk=$E;vmWuHIwX} zDL7)ehD3K-qq--;0{SA*KY>x9@@CHcRMp|$m~i1fzR3gN=6D&J2XpENe^eEIdX)(n zC0KX3G}E`QofWyzJsL`ItWQgtJbr|qc7!lgNG(b{(+cp9s$b=2&t6mw9a6<`n%obz zx>5$0n?4HHPJ1XKPv|up-y{h&zJR4GQPpnEzbFj-{nz_X?u`Qgc-fyaD1S8>J{csL zziBob*c7i*a2?#;9DUCGHD!HOGz!?a;%RY==GOW3Ma(@rg(_d@ zpAGfSQ8xv0xNBp7clpJMj_TPc`;_!Kw*tl$X6Z^-Tdrx3($W6?>UbcAEtB^RfeBY! z#bt1x-_kS0Y2WSYD|$WMDB4F43i|i^H%IN}_rzyjSelP+;0SCOS#vXNYr>}&4;P(v zOUQJ);)kws!UH^O-DhNrMJ_czyRFw^pB3l)87x~Tv)0X~2$iLuO;d#t-Wtao1Z_H! z3G|G-YKYXflfH?tN^5sgiLfb?#uY|K^DDb=et>Rzjc^)OTXH%|VBjD2@m$qsNng_KBo`dr@Kx9ags~dne6gxTLr;7YiA#U+9$;eT~>&<~@x$5;Vamad9Kr9~b zjj?W0M0{=T@9sK0l{|Q_VDVhFnvHu=d8y4Yj4CRkG>Wv=ZLUryMuv;w{>`e6vr96} zlW%1I0#Jf62kqN>QM6o-G+L8&%(L)(qHtOQ6l;i=&9*re>II8>hR}i7<`QmD;jQp6 zi``@*YmdE+7m&*swq~kNG8}J5`r3FH`|MA3Vzom>YIFzDst!Ls$ZL^FpHN3V!;AQp zt0#P7H&XkN%J53ts@5h^`O37`L^NMI{KWIV{>Xbdam%f;7v(to`VMbey~lX0|0W*RB=wg z*=E1$?wd)YP~)IND+oU6cbbMhbIr#Y@9e_tqDx$OZN=Ee+iK6ax9G-q6f*bg zhVfW^#vJ4I$!;=6rN7$E>-^rsLyK=u=ukz9=dUPuK|sB&d>g-OBCO(|?oq49JZj}y zAv6A0Wz&;VF8Q7*=Mqn&y$C{ z0>$#IA^zwtz8Y{XFmL%dTc0d~KN+m&n5{Wocm}(QiQglz=jbIwM2GqpGQNdvq)&d% zcsQE+0b29I!b1NSTL2n9e#?qb6+?+r)K<${@8OQC!ID3(Euru-RbXig8IBWW$+E|V16wqkOSDkr~Qm)VQ?>{U$k1K^(wn{ufks@d(QIQBdb?ST8&-y>G@bm z)_rDga9QAuOKSN}d(|pYC_rFXG|C}EK%vvrS=?~)J?{QvKXsjx8kQ?SpFN`_s!Je8Q8?guQAYT^O%-3j zg~aGl+N{z3GhR(OwgNhxQ8cAF_~)_IJF9|vycbB~-oJ%CYOqpo``I}Yd((@BFP0Gh z#}h5qR#wqK5Ax)T!@0e|D_micIj=VCYM*v_w4vZ~HQ1vSXC|iEkpc8rzHNg@`%3yg zEFXm$$4Fc1!0q=~FoM5a8o~;IFvNYTYj(Y2t@&&rtuCOt452xPRxO^S4TmDsCiyH< z!nF;ZCtL9HZnEx+4)K; zlAC1G7Six)zMcj#8720ldrofmEydF&TQYqiv$vg&lT$+cY1o=!A{xT$2Yr$nFPoin z`_4ukPuv++YY2qN9d)zkxI{~9ad+rv8TdcskQ0*B8YFH^>aAUG$`zAI1tLPGL}>hO z5|)Cd*74gmO_+vJO{QD8`$7Km;N(;itA8=$-cW&Mpp?$m#}zN2Ljk#29OuR{n%o;HX&nAIEb`21slm7frnuM`e?9=T)jvQx6RX(S3FEA`N72 zGKrftKd&&|`O1B8?INl0o-VEaxQ1B-`jxU@M$)NhVEMKbS5ZP+(A{T^!nO-{Z!RkJ zM|OzyYD}`g!j=ZW>6l?baYFf4-yD2|vNklSYkRoDFk(co2NYi1$ATC}3qVzIqMXb!6lo;y&8zE9By?^WwfI|9(5xUPw( zn93`i(WYQ8s5AgDh*=5uLUdih^?WT2;yi$XJAX}y-WxZ2 zO|l|D=s&sB7X82V0fSfA8&>k#iH-U1g&8Z{U-kK~C~+)`G5@h~o}HGU)r*k37I;-7 z9O6|1ROzuHvkL%QgM0)kL+?=EGt_HG2UGGK+E&*I&P5Y-by?5@ykhD<-AO&Bm`?z@ z@{YPES-Ai-N^?pa_hluVJpAd4a5_dta0TDkVrR)ksL3KdFd@|4rnrJ(skSCN|BZ2u zrgx$PvCJdEw%h$JEPz`y@yTu3NAYeHg{-~Hx>YT7idMA^sR_gi?P6{ zAu93>soN%JjUxoFNP>H+vm@hE*xb(oC79Cxm6&)GyJM8W-Yd$O3<+28fV8~Qg-8v7 zs+SLb=+fcPLw(sm^sbb@fXSI4XCe)hng4tP8?Lj+TCe|A0*& ztY6(&)A$=X6#5q6ZkBvu=NA$_KQ}!A?_dceH4z~z;PTAT-$(S@?iQx;+A3%ecIekP z00rP$PO0eb=jscT`nRplAN&DUp*F(M^9w`P#M$WwMZ2v}u%_h2>Z8E9c=ywQO9GF} zT6a*X!)r=Br%ydc7%&ez6(m15Dy&fh6osaYr7=mhVX^K9f3p5!ykH#?-Sx2e-~U0F~mLcssQMpY;1Fw$T5^&Q7^xNCt!Tn z@zVAO+*#oACT6jX7Cav4v)MeN=8uTL1P2iJKh-R9);6AcDljTX_HK_1xH1_7QsgyAX^%}feilG~ zR@@;y7WXLJibsw)8lk-$1&UPWX-Vx;T|@xI7u!)A&>Y0}^D6Ue$!EN68QCM0xBO8s zVmHNI<1Yig194#kSqaapNhxu=DPf>$p!ei4RCq5F&(H1b;&b`{q<-ic4@>7R}3oeHKY#mwVHcLKYJ#Zr{x9c>qy1hC_FZyZ(Z-`w2T;$*pL!!|b7 zc*$N;cGgA*7afihC2C(?Fjw%K8FB7-Ux+7twCcM3r$hsB`2Wv zVq?I;bH|kZ;i{i{91^;IYsu)WMgMH6_ujTiv}Wd}R0B-T%%}z}j7ftE;5k#8>)xFn z6)0PzG6Tur9<=NDun}p$ckI;s1x)cRN}VD z#YZ8-h!CjMb}_>D5vYI#2QnUfqsQm$eWS!tuVI#i{Rh7(p)LAc6O)-yi6=<}e%xy$ z$tuUv^nBrqBp$psCM8Ty-?dKoS@ET;zWDJxpM3-WtsQ*F*>6gat?>68Mpd}Qasrl| zTw*#vZ%3aDlLl4pHNF>0uQg%u_v#mA!msbYfusNM-^`91gZ;QGk4tt-;`gfAbz2c) ztG<(BF7B@~_%vF#h3=6lXkFqoXrD2k>Dj07uO#emLBUYN;tJ{_A!s}>f z2y9G%D9mp{(P-9qg`q2>5A+53<=bf%YKlHSPT_FL^wg!raliS-Q7h`+16se>*a~1_ zoKjv^UbLhPcFsM;(i583pmh&K6JRMyZqX_0|D`-XE6;xK)zfq~8lVD72y2*A(fmND zd9aYgBgM&1K4EQUATRmU zl(Iqoh6sd+=YUNoFlC*8?L(=>K+5qAYAPHVpE(yJ9~{CF=kQH!>-5$eDvx6 z3KcT6>VXH47RWzOO$xo}m1Fvkl{lTYW#Cnw(lio}A1i-~34`AF|JVC$#HdXcNWHHc ze`AiW;l4@8R^MNn*Fdag>hAxQn{Qn_wc24u7IYB5tdARUM5Mb9n$4GLCF6j#=xko_ zea{x`P5z;*F46nCg3z{P2X*0Bu>XWq>!NUIr0vB^=$s+}JSNUZzr7}T6bm>KPrNT^ z?>uf~d~m?E!a_gEsNM8q)GWHn1GkS8>ks=_Es#g-uvPnY|9&uZ4S2aq6JlJzeti!ho!-OTj(G4T4gb5z_|THD^^Q_U^+telI)JU}$?cWC zHVmUdePHc$Lt*6zFp+$qf-xWVsgc7uWO5A9zstK^gKfoT0<(Jg2D6n#e7J2qYlP5_ z+cP|42EjhV%~F`svb)q#84&xlePs+!J0CR1WC-0YuuB$^q1_6sg;e=bfSC_s07QGfdJRZ)8tIsKkx>6L!OzyR`a%P;^1D>CVD#I z#C@nT4mVMcZVX=`q&RuO=y~Gh{=;d}<);oF zJH(|9cAjmT8SIN7N{0qZHE5PvELS!>eNlsg&s-Zi{%6~8p9(NY;xAh33yN}D`XrvI z4Fuv440P}DB*Y96={f)t-PuB`DKGPeY#xZGD(a$95(glV%s#C zz|H)%naGO)1gbq=n~a<1L}J+`0!^Lg^15&)w$$ZtS;POF(?2ypoP-8Qxm1G@=COfx za;5lw*9j{lKD={uNzWt+P^UCsdh#SNk`V6&ICTlP=YfSYX^IL{jR18J8^8&gX}XND zFMHpzapcEP3_IkJM^`Aj8G=`j!maFpDx;>V=lyh`b4344cB?%os*1FZe}{`rPt%6QqwB_ zy0GLw<=f!*|E>VOySh!wLg#G|{|H{L{%4Uu2>5iMg)aG=JMA#Q6kHCGM<>h`@N18E zfp?p~NCJt~BlqSCLdS>@w`pkB*r)dSUukHzm1$8SYpKlEG z4Bgda5D&J`l_IzV32b+(9YISv6xHxq{bY~VCDVJ(cAGw^Xvt&9O>&?ql}MmwKhGuK zLBT2XvS7!kPP1Ufl>pdVo=R|lL?f2y={B<&}w>z5)$v1JxXguaI1k%OsHI(p+Cq>~{Y)*Wqb(l<_;%as^BwNvWlIW7dvrBPqVo@GQV%Gk3PAu! zKju4bZvaBZ1f{?na>d&zoA%jh*G^RpIxQZktZ+ux3OIG-_x%zn!NQ5}uM<=Y7DY79ljo(C{ol-l5353IxwhqE?-{+=s{c9w#u{5K+ zIgLS)HOYS&2#WK`hF96)-}h}kyY=p;68{ge^6GE;apiCdra%y=%zV||H!dSj zna;|Hw)_uo(Z3o~68CxO2|AEEF4E#`{0H__eiuAY266DC)Og}5uD!BoW4RfwG&t%% zJnenL5Q(V`NJcoFw5)^!U9*YXLUU@&Epm*uaQ^E1@=Z3|L;%AHu8$r%)l>$Hz7Q0K zGwiP}*`pticyWz}uPh7A6R8H$#NZ>mx5bz6SIZFa9zuZ{zE50aZpVjneq_T=_#EY5 zn8e~f>|?<)O~Xw5)c|L{guh_M5WPiPAC*EdCy~PU(6Z5cCHEFruv8Ba1Ied*$LtWj z2t<&^6(|E?xH9)J{un9>xWJyo*S_f_cne<~s#nQt8n6a#K4n^eBa=7JlgqN0#H7Zw zBaY^Ne{pC|H3nBZV8}s&2m|%82$3O53&#tLIJLD-bHlufIeO?< z<#aSKg!^>!`>BUB@y1+wy(*XA^y?92 zGgats9XF1P9L&n8hza-r)X;fiqvjSs0IK5mF5^X|s%}qL+yL2}uCxwG@TI5yUZ9Kn z-&UYxD^5W(SNzp!QxIFhHm>J#4}UHP5Np55F4!@smB)xRI;!<~WEE=u znHSpxgnA23B?=&0 zp}EbX54Ew&a!{YUJVvqO|9=m^duO3fdemtRIOzJH-M-kyqPN)~BSH9H+gE#?5In@b z=o60z%-Caa9AqC%9Z2A5CV~h)kTDCU1pbgSQx#Icychte()lcoYBFZkSb!0SNnda) ziF^q}6(X27CpE?*5adM!IBEdotqun}lE|MwC|k&Joe#$5Oc|7U*KO`RSLmbn^h|nI zUku(*JSVX+(svoWAJF!Nfo%@PtQ9MM*?VP)<~+u>;j1}wL<561OC^(oyV?hH6!lPN zdHc^zkw(XYdC`CG{-gi_*P_@6qOUw&l7JETMXloii2FxF?K@>3_fY8Pdq{|aD0 z5Kpa8FAoDZ@Y|M8%QeIfZDsw+L6dgN#$sys6tDhgIB2VZ10WuQXz}VW9XcO40Tvja z>#mhhBz270Z`yyheB)j{{I!}Br)sk;5`Y%sX~u$x?=rhZ4Zfljzs$@AFxR(gXWVMi*c0bX*BemFvEF_xK>UNMI1_t~Mq>HVhi5fTv$C}PS@r^co!p*_D4?7PL$fLvbb(FB z{7}uq({So~oI=WGx>57&H#p%i-WTDNYa0M6msp?PFydrUcp9@^_5kx$+(pU)K#F3D z_T~9*wfqdv^cG*C?rE|#AspE@n^#4T21ZPezU1jJ3w7%~t+U_-u(@WV-$!)5yg?T@ z-hn`8Pt!8ilMDxph61hs9P~^|&dh6$!_?Vrn>PW2E-2nrt0Ag?Vsx)4AsgV#tPaZr zdNsE9T(=(A0aX@G?b{~D#1?TQ&I@psd{jtR;{g#BmX<6b(gzS07Ax4w(rHxZWJGGG}r zDF2tp67j($v<9DHvGSH=!pkmir##q885p6fgxgW(hTjKn`mI|fKl^^$uoi8oI!l+` zs#SDjM)JfXPOsIsN^P%_c*zl$BS-vcKbbksVHx4Vi+1`FV$5!h?1YAKfRbMg1ok%& zW3aSRmCvYXsnmXtjkgtrnO}Oj{X^r|=#GzkFyI{G$wRw}w0QrvL83f@(TkHi zswx5FmT&TdBApdK=<*&x)AzS!)JssBIug{qM8JTufP4>vE$Fcma5^N7CkPCdGU72u zGi$?Mrp+HexB;{S9kOX^5XnO{>u@52p@XMl8rw0=7MFZwwh(uRGY_c9bi zJ%C}Ht|TsQnr_#&iv-vk!W0!vFaSUl{tUlpRBt`~WjavMQj2NlZ8C>3w6?Z8o)pi-rXOxJY~vfm)cUpNujR8>|TY1NRR$Ya;&` zL=0Es6*COF@o4@Xd^8!(pXdBq05$9Vi1t>YwF#^daGE_+f?TAju*#1Qj=?J9fGi#G zmZUpdzX>!XPy(&5ZgZqOwW9&1@y8}d(En+h+_%8tuv?tSTG_(f-Srv#%@CMeb}j-% z_G}FJK=JLUL0UXWF^$V1-w@jh`_?p2tXTsxATC96q3FrhA=n|)GiK0Jdg#BJ-m1*} zTY)(q46^#k)q#k1^6Dl{sv?h3S^IgBE@7O_ZAlad)3T?WSy$RjNe&+f4Hj*9*3$QB z>=H0fcd|N3gK`h&!~<~z9J0LI<-JbVL{A0pST8nY$!&F(gKV6!h;;HUL@=jKud}Ma z<0Uhk6I$=GCt8k;3UyBmK%>x8w0jBe03NnoCv32?Ykso%kGj#!No^=KTm|BE@FC$; zmYVy=lx0GAUI?A{F6RSs)DGpF+`#;tYj@U0^yo$b=a}4V-WM_+`#`_w!~SK1YV)yP zwcmjPWl*`Q-|-wzE*|(Bk5&GwqcuT~V=~79y`sWhIqw|lkf0s3D}s47*!)_ZX&x2} zBFZHXVnKbxtg~+PICr3VX8PWzG1$1>p<2DyEKXoDz>Io2Y#ptQEKXW8!T3Fn_JIEq z^;^BPf#r);T706U=!4TiDLT>oClTh=Xvt+isLQa^fhF%uo(6#Ve$7Kw+sQhFu2szu zG9xcTLf#47f#JrUmKn1(j#nJrd=9MfnZ1yz48_Ew00b+FC+~T!#`AAJNLqAn;0{{} zlMw*7S@nNR5HS$~{Q5sU550dI9d>HI7%IL}IOW;5wohXK$)@k^{;UWfy~$deT6AM7 z`P+A8nPNI6{rQWkOrTGbc-S~zcHGL}<)4$H<+nePnJhzi>l5v>|Db)_hB}mB{KL66 zs~q#610V$imHphXp>)?ziz)h3<+4T_?G78W7e#xGKmgHIHh=T}!#-0^UCMyh4h@jv zZ5zv=-S7aF0mGO{jnlyJ-hk`z*I-a_%w2giQt+GaPx>DliN96NqU|Fe(#5ocz_Yq6 zU~6-7Bi#vWwH!^}3jCd!0H~~MUV`e(qN6R0a)u=tMRZHO*h~ea%!;yeZ65(v_t!V( zqm~$esb|RqKZGo;9N|uLgN%N);{qh);I|}&LPX(yYil&D=|h!a3ucEao@^RLYcgGa z<|MSdS-VRt&6EZ3Vk1$#e<^`zgK#iRt?^%v?@Er02e6`}r;pzc%ylLL-+x%_hH(d} zBfc#sq2vp^MQY-;k}!PQ{(naT*Ak-nlE*<|LO$n*3W-?27nXfRK}lOxFm_x z^bwo_H296W<%a=L6w-Gd0$WJzQ?Sf{C8fVhHj^?a3XK4dQM1OS(8EML#!&G&;jQG{ zRMP(md;qBrqS8cCz8mm7y$Ja4o%^c^$a$g1pI0H#f?c3PkU0t`$rCXz$#L3?8&E_iid&n*c+!2E;{D!W)3P z&IvI$i?44Io42SMav=ZszdG)#UM|gg%X+k)`bpdtGS#B3R+1tq-BfBpfI9f3jJfWb z6?4PFUb?0V^#utu?#*Zd9IH1N>Q+Ppgh3nzWP&?p1{%<=AX|SqFte%PeD)(R>gWicw%#-)$d75`*`fZe7sfa@(SxF(c+8 zg%<50!n{HbJuSZ9ls#jYq~aKXXQoa4f}8>K88TyHebT5aINrTd{;#fs^wQDA71(CM zC6bUHi$11?ptZ~C#)`c1~us)~(!LOM(A7;!W=EpHTfHZKvlQ^RR*S7}8}1l2_*Q_0qk&|1buIn>YM}+U6ZvHigq@RA5lpFo7If`1e=>7kx@L`A zX?W|_W9MZ3WQnE^eA3T7qxJPgq?Jc$4A957-Zd+O07(~@sAC{AL%fW1D=(c)rFlj6 zmCQ{SeuBz)WlPDtoBUlvoVWXmVnRLX4*#&>X!_A*Av+=2LtyZJ3E~otXbGHNrPN+# z;g1Uef0hdfH8=a9AN;?sA|?VlmxPa5bqKc{lf zkSd7MD(w5VUSDl_Esw5@+F^5H@Y7rpzYuKAz*@+4_wVE{y&4Tfz$W68#{$7M`AmqW zI(4_s#fBJQu4ztxFJ5`|^ZJm}V=Ax&wV$7r5?Bo2gS7x+yG-C$-q9?F#HpqlSXR%M zg^6994u1Br+x7f;fqIh`{VWLl-hv)g0mt=mM*yU{7-)8=gnLZ9N|=C7_l z^@I5x&E}o6WYy9WJtKQ_JX)x;T9&sQgxFs*XcZQ1)~*Qza;rFOrkWo>&~0VXSrIge z^=c(8DfrMJS0E!l{=jk@tOex|k6mVrz`?!3Xcg@iL!A@(K=s=N2qw-&R zVz|h><;}E|`H#%tR5bK$FlF8I|NE zGv58a#&Q;)Ms(i*48-`D*H^`AwsQJxgCiK&o} zWX^H|K&Cp4PbenEd>HV|xTyC+-T`$0w0pehQK9vBAw5H8g*da#cHTkrZ=_luo+cdKdVmp5526>&r(z@c5mP)pWCIMj&rU1)EOL zuwdRfb3{+?vh|XPnLZw@eT{a6Inr|N_+(t10(&ERGV&KMq@qCa+( zmB_ki`3MDaZ0&+re2#6wy@FU2XG&)%FZJ7d7v#K)bbd)k?ess!)c9pELaaU7$7~?M!w56%xmH z9v*(bhxE?S5B{-OZE;f*kl>B^5HP~N?pxprpxT)3DCak>)fc#It4}IJooiGG#-=3_ujzG8ew=I z)gCe2zMB@rZMq-;5Y7CV0rNWVqFU6y;?_hCKg+FI+7+^12mV)$Z@RLfKS1W z`(N|WDY^mDGT$XLAiB$>7s!E(=kGIP3^P4{n;Z;2(Q<57SQ6W}6HQ?S@T0|HM14;M zKn{{pcPNgdojRMzl*H)l{lPko0Pn5>9+BcH3^p*$*jX(PftsAYD$E^zcoyI(56Gme z(_3JuXn&|D!0e`8a5vV6H~tlw6mh(}UPwkRkoabb7X_yJ{MiE{J-^M#ogJA>uzg{& zCNQ&{sa%=x?ih#}v4c#G75vX&+S+bKI>yY!S5rk=q#p#bEtg1*EvdI}v}#HI5@yi;3&0t20keyP9_jDkrrcjlrI~)#OP3@!HBGEVmKL^#$&(!b* zDPnst`90d{ZbXKPWHAO7JW&}B!_WsJnQjDK6{EK1S2~hZNzgJZk?1WkgGuUig;X$x zU463<$2->+W{H#!0K9$g%R-iAOI1`a~-wHU}iE!M81FohId$2bS-;Qq?MJ-6asWG0op#jN8PJdUO5fE#ya>q4PAs?` zl&4bHZ^({uOQ?U!*_YCO{?hC4do@J=dEwx-ELG4Wjqg7$pX{4TVr{UOboW&`Bqk-V5?6676qOfBy5b zK;OOME9OS+=bi^q;LOj9Cw|0vFr$e6UxJK_{XHS``J_KP zK!TR_-E$(*xOD6cMFU2{B^FDzriMU$>f70TPJylWCitT<55~Aos~+?h+2>~C zAg+c*tRFciPz8Y zs=Zexe%M!*01D9^*d6Nv&YnU*1(B!>xVZP?k_B_W-|)h?q_CSO$4~AQNuu5Y`D4?M zmOFRiPxt&3fo`20+<%(+@|o0W?a7ANRDALr*EA6#e-(VDH!4s}D5+*WmnSJaku*XH z?1@b-s*xnuEl*^kHY0qWH*M;z6ZT$aJn6;M z&%ec_1E}x#>nJ~B!}npOk?PS@g99)B;po3V`0V0GEuVCH)99{6%??Ti<_9qfu!cebZh2%Fj27+aHF_Sa$hGeSBN^sg)VY0GzX5N#I0 z6=av)qiAEeAOFCSY{j;bqm)x#S*~?~KMnS)AB2C#s|~|%?fL$-1i5szkekr$RAVTX zq5zmf#xkh6@x?yV4qoP{n&L@md>XS@&*~Eiy$wD zC#%UA0(1ekIqih;0VGwcItmYewf}ozh&yX!6@WO}h>P7A<>lk*#2V5=n3d-2Yhb2A ztyC^fu~xvZYui2z+2Ox0FsK_iZy$c&WM*;|C1k}%fz=+h&Aj}i)dXyL8v#VO9*ZVD zNrDxcrVW+`Z!Pv?LTUSnghmLq?ZD&O3X?kiOKPyA% zjYtI;>lRGN&+{;KK9k}bKGf#PV!Ywr-~O~>FF3N|HY8-L%y16ns(<0Gv{0vrN-b_} z8ZZ<%HqBIBC?`DK<2}l}zCA7P2TFo$Aj5qP_E_sj))SgjqORes?zZ*9&&K2`9Q=|O zjF@qhXB8t_S44{Eo2LU9V-EC)_iYLy2X>`&CjvJVLEuqeYR~iIbbHD&p=c_$wS^ z<@LZwf$wlED?q2ee`T7Vr}9Kd8T&5aH%j`ORqOf?_rK{J_(9iV8HE}JH`UAE>D&=k z7}H3hoq$VU_I`Av#0bv7unNToHdf6P)h0BrJ^pw}Ctx5!_QCS;9@55s04qSiYagOx zY8(@PZT>)O5dXKELdhRHqmTtabdG4a?u( zmblkG_8h?W!vY+soKG>&Og5d3d$4>Pe;v%Ishph>h%}Q(8?g_Wc;p0PTP@abqi($w zoh4@DIGAY*|Nc~dn*^*0Psuo%usjPX!vJI?H&OYtQzp8h2> ziFK^J`#O{jUV~1JWFW0v78(G~g_NM5?dqS)hW$FzQP|Luc7tbBG{{iW_St4^cYyM!m{}13eSo&kTO7 zlZ}e8=WI;rf1kv9I($91WgvW~i5W~d_hdkHmFp&@d{zq)a3}=qrS5p^#CMr&5>y44 z2w!iXz%K@T!99fk9=ys>(+>E{9RY!$DOPrOx7OhS0o2B&niU4>$ z280=L1O07mAG+r7eqL~r`Ol-k)$5O$(J?k*^%og7i?w9t)rU^nRKfMdExh1Q%Pd(9 zN&@()98HFA&M8o8H{LUPf~X(camJCNoNRt$ zaPCREOe6x>;Qj`cX)I#0*888~@Lunl5Ajc^G*xi6;@AI0@sBaXsESJs4eyDp6UUs7 zFrjEXB-z~>PtRJzAQIb;o40E#JfvNhZ&zb{Qs9(jJ#Gwa+;sxVI0&%2ry8ezB?p>n znLr7XAal4ow;{8Zzk8tv{?w>}=QS?E-csi@2TWiA;dV281i}ph&~C6`-r0y%x$ksH z3Bu3zGaZLs;bVBIaFONLfZEs0s%KEYwzv>TgBfc9*3%plc?l>x`v5isW2p441QCsm zEnN#pBksqsODO-i*w|p1@DXv$f%IJz{G0plJLuCFotD29dd&}!tt(;FCV}?^V$Cry zqMw>mJ!3^NEt`c+m6wP(3#>GVEtBp4YI^QKsNesUPbrcRilnZLGRsJb6DoUUZ^>TS zW!zPEvbREqGwy65^NOhKnH3kZ&dyypH-69Q`}_Ca&+~dc&uhP4&vVZU{Qtl)HQ~t< zAx2h%pni6W?c;~1%RH}v=Iad>^{$!5QJO|WwM8Q5Nb!pPtLBm}@4$^osXCI!?BpdA z@DfAx7|8&oq7D zIkNt9g?hSc4?GsF*l7uCk)3vy2yKxXUfsAgZ;WC7-SzyDKX^;>inaoj5Ywh(bTW5V zIZ4(^?*US0>qvL*xu_2Xb75Zf$dh_ zT;Wco$A{aazE1dK#$AgOKJ+brq(phS`=rX)#HK@Wo(paL#3o`KmnfuUT8*o=xjN#dt}`Z%2`+ZUuvmvvuicyFn0*~am`ElhkdyRECo2Fn{OIRCaZ01FV%k&jwU{#}>h44{BuUA=11L)fOZ3&fLrI zV+Y;bZN63gttZ!-79p?JOMD&dx!%VCNe1tuvsbj5y3{jx%FO=1?yLD%j5JN$chRkg zNw@|c(}xV$o%XM=dYc4#c5q_Bla_tHh7E z%1Um3y`@3U`Q;zQ|CtfMb$H@|kc|k@F6tM=gZG638nbHo5k-p=;8l0<9!3pFGpW1U zoka+QRT^mrt3M!B<=AH#{X5{<2>mBRQ@XJGw3LSymljZ zAa_5~4Nw3_O_s9L-EwJ-XKsw|ULb@l;Cfyuk55 zLl@dRAUwHWc6P=T9H88XYo)P8ulz_>n|6>o zHk1Ya&d{e;ay#Un#`MNC?U978Ek4jxpe+C5MeybixIdwEsUItI_;fOGp>os^c9#pv zRYBzARKCQ7H>UyNpM>cNanO#m4Ik+3B@e6%Tl89VIWZR0fQ;eEiteoh_n-A*CPILR z+V9?xfNvbnorQL#s*O!Ufcx9V6dX-m36LLXV0M(!n0sJQNc{sVsQ`_TP8tECoOL-H zj-KK(Tv&pSS;rtX-#wN39Z`B?0T8Bm18Du7^)2|xEMz(=5W9IhSCZ@p8W4 z&Rql5;yb~R>%ReWAM^aqUP2DI|P9zP-;6fR5= zw>pX0KB@Cdz2nNFSt+{ZH-mBxIvzqZzjOR8lF4W2JFyU9ML2#s1EJZe8&ztOZvER$ zyTw1m+?I;J@I$wwEqI)fyu3FgFkq24&-Ia^;vkcU=lhKH1mFH>tjF{<$EUY0|5fex z+WEOq0e4*#*Pu?{68CQj-{6HQJkl0Q_f4DD$|ZXjV%H1S00NP5m`8Wrvzg}nVM&vA zX_$0)V-EV-fLmUiSipp{V`EwT-6Tr+ca?y$*SMncYV|02J?K-18A$!?Ds}xqWQ|;k z+w))d>K7M^*0**tU4G==X{?-bZ=PM$WLZd=29!BAZ>*Q`l4IyXV$Nsoa`lJ%rqKgw zGz@`p%+qDqmM^g$-)D|6zuj!=CzIOw0`v}!MkuY_fU6Gc^zB1ER*Dks?1WU% z=uvA9iTZM!NXsSpAZfSMeRZ>v@--%A<45nWmEL*q@u1>kCwQTEQH~EBr_IHE;}u1#p>98-J(@ zqm1Hy^&v}1nv_KQyfPMrwd2+>+-Yd8+L8`$Z~Anvb%Vq(1L@3-vw5SIY1Y5znia}s zEAmv+RmrTvfC;e`OXKgRwqmLNS9BCIDRIvG5xK!bq`p0<=b^L0J~t^R5iGEQFiB- z->RkOEb`?LF4HN09HSKP#vN zrcCH~WEA2|Sx@dAv*bmp#k7dAUI8G#H{>Irj_YWQ^6uA{ewo2sj;rlF(-jH?Q{&q? zj~?FGC%u#$qx2q3CkIe(B%`<3rz!0kmhQH@G}_PB$Mu>2-e@ABG%LQb?bC?!gNV@e z6?Mu&3k`L=d~Plx1=xFepZ>;iYkySGpP7SUtZ1gwd@RPxRa+su>EsRmwRhp=nBeLr zSHs_(52}NH_0+}2H+)WSb%@OEFF5hKT&D$+Y`k&?NfS|&+I-R{H&q7?>x`V*tiqgf ze(`d~nsTTJcvO=4D_?}yPI~L&0~vR9c>R;SCSyUdKV!O;>QN<^Qqau>!{k49OHG4i z6El;0-SMy?!zIy~ZAYn-<#$%yZgm}mshkRTGIjOlhY$1=MLyX@teB!ps+BBFQUhhl z)@L%DVf=RU%(oo9U8fcgHUgjrU*p}Wf1U_^8QChDr0l(^Z-|6%3*VB-YJv9)1pYR@ z)i`r)TnWeWy>b6lg`@X@oZg)Xr4Ojj7T--xO`5CA+_Cs~qXrYF$zw(tO=!^PfPUMW zd#rh<#bdRdr3hnub5I%cafXm(9LIN}Iysj`;yf<5V&Egza*y{`+Vo8&)S?)CIaRk(j%{+CAt*RD zygf5~$;JBDkLEe4-LI{+H1{QJ)*i30c)ZcNrM=(L(}JAl^DH;PDG1R2eh9)#&%|T| zZ~joQdZ>9q-H*Xsb?`)>)zAuz>`9%ilmDwil;dZYe>&6jM4iAex-Hf?Jyy`}sR|&3+o-Zp-*$_Pz=J++v^jStmcpD=b`o2mT$X@H8Z4RXq3i0~t?k z>Q{Dq82~@Y3gc(6Y>hvzkwqOD^bPHp^Fa@l+A&>ocx_#_RYZ{YUtP~6trCAkUi2T! z-K{7eYJE|bpW#2ay)!+4p82(Luq~bWvr&F<%Pzj@CHr5>r%czGZL3?2_O3)|j!+HF z#Fh4@l6Cj0(x&d*N#r1Q10G~tPEGf1w5IG}K9=#^D#U2q9L&e;XY&M4xZ>Kqh>rA{ zw-GqO8OowC_8ZB56(C;OZqFHl=3A!xe$%w=!}avrsli8&g;a#M%^xN=i+%X{V=x+} zgt_4W79Is%Ys+oEEtAv|kVUdR8$cHFPQ*mKGF0kG$T7XWn_L6^B{S_6AYi;IIQeYY z)6(zr9EebwRQ3>+Ya1v7$^E7`%PRmjddvKwohi{2nNP~Yi;UhRsQIXnAqNRy`BsC# z$C7Ft8+vzV(kU0etGwL|`cy{!_0Ur4E8O(v*~bnbhO>n4KM4ph=q4%pEWD+5b`ZoV zyl`!Jnr?ZPc+*38&E?@x=|eNYi1Cv;Noc^jq%y7MiV5S5f&Q-45uIi|$Qvxv-;yWp zX3Wl7PycekA^W^PopMMzhwUVzbwUJcBIUJwmyn6*zNyerC4`0h?8!{BQx zmI#QFq=@NL_Y*c(z2Q#UUfjMb zL*JXblrSEXKPW&Gc&4|jjzV_w!)Sc~k>iaguk_fd4}SnyqMTf=DRVD(UBcr=0}yCJ z$p>(6^NYc0-5-essb(y=&A+X9hR2zvY;tiX-oAa zu;}YA18Y-V=m9N8NvwOy6)@$HT9Fv{AkxWz9j;c~^{=1>W$cwh^R*_u5l?nq6`Xfy zK=%didhp67hjo%SFs;e^hDLe5z`FQTxL=zr*P_j~+lWQ39XGyS=;74Yj2!(Mwoy;r zcfUpY!oIQ@uZiDV4`}qOfQ8n8PQQ6CPb^#)|2{^wNhCD=-LT+odP4DVyWE@la}!OU z$yXRX1jszGUzYD>qmTi5Jh8iDl^QdFyj`bEBPU7x8{1PG=b!^^d^eN%`x=78n!HJt zN=7FKZAhF$=o#Y0-DNGF>ix~7|CWAcvFl)GmuenS21Wfa^Rxw67{O2Rn|Wj(%uwe2cs zcqjY%cp3o?ZJ7^%8(!IgO4>Lsiu_iTmMRmz!_`D-zGH{9@K+49>QWhfPePdB7)ajE z#7J86QM$5HfmrOce}971dL}S8gGeUM9(5&hvcl;0CXt4@xW|OMG}7v8*OPOSZyJ`hHw$p$IR7`DgYx3MFuu`n9hZTB zlk)v>$?-ttc20d7=FF}6z78=~qG;`3Btzj+zNQ0`62*Z7H)3f0hMoKVYv;eoqJ4Z4k5U(3DLBWe_CLt%JH9woHDC@}YJjN&C>%r2?>Fd$ z#zsl_C(TBo<-qJzTwK_w5)G|r7oP;XMo2?yOq{#j>T=xuYFUH%PluglMRDF>e9`l< z`_t15$fe6DK3O{jk8oI+XaQ}enHKrQdBnwN@5W?$ha3TOq5q;K#(aJq_6|0x0m(<= z0M_INoU$`qb4DI%g4*m*Vy-cxwT*qBTKYZJ!Vs12^Qp)BTLdw-${@gyA02)ORoU9f zLZnA}(83Sg-lr-lPrD!7SF-&4@~~m8S;xYD2P}09G@^K_8hAV}+aPt(`f&-LJ<~NX z`GtdVYNsh8r}BACf?=DbNETYo4&hnq{clYIw=%?=WOb>$3;4v9iAaiO^Z-;nj9ZPW zNaO7LOp6~4-wf$PAPhZg4*unV?jj@ErJRSfH=?)wPVMi`YtWFjaR}IfN(he{{^R(2 zQ_Go#aY8uJ^R|rxi-r<;#sqhOlG~r9%~QOx${bsx@4hS#)BARP_Tt}gyPnU{605Fm zmucBqOPcs9=5L|HLTx8T+y1DPvT1wE z^Daso6*r-h{z*!#^Cgjk&rh{PMfm!UNIudPG3-_Eu>T7t(s2*n0g_@RYCcithQ;4i zPS%AG%rc0djeH~L8v9gES}Q@!uhdwo_)dIVwp7&)2nzgg$&WUT$GB&^prX{l?|z}d7g zqMT82?>}B=T!URKiRc_v@=KbpCa$bM^zkd=Aj*i<(0WHpJo@pwTZ|Fkf&PQbkg1E) zhI`+f zuDI=S$ZIvpR&^&avySVwKEKm_|F_BWxJ@=j`K14l#!Yn#rED_F{vOw&=>3W?1~yb; zwlzX6R1L(}#M0n^!UHooIv+Pvpxoki8-R2)PLs>AM^1kFx6|obF>C*5-Q4|q3h-xv zKi&&mPsGi`Y9+`lht$i7v*v#j)+(5UOs`QN|2=BV6i&?kpSX$rL5Il*QRKkW>iQ6T zL*jr=0rlRYMwwyvn!+&gi`DAmH%HUN%OaBCI&xdq5)z#ac>lm?_5Z(s<)AuUt zqpV|JwZ8m2O5|x8!`O-KNl=T$Mwf>TF@|lNr4T>32;nJ_?=J1*o?)9=-$!*TOwdBL z{XyZA)C@`_3vB=;kEr4@^>!2Y)WQJUXlhC_5*bOu)5Mrg(SKBFo(*x! z@Td>5OUCG=d1Gn~)7MTVY-jkPItu{cvIAJvC)?rfrEGODz4z2>i?0vO5~1DxO^yC^ z;)xygud_ENuBG7|t48uySZI#s#oAV6_o+qozSnaNw^W}i270{b>|-Q%n&4trSPnII z?c6Di^6TJQ$^~QHC)Gl_wI--UJi{TSR(H^0YRe@7UdQe~K!;m)n4p4&`3}iY<{1mM zc#vV3Xfe>oarV4eBF;5>#6pjzSx=%cuOMl}!H>$>pTQ^bu9YigBlX_*X~+_IL-&c- zXN}i?w(Sf_9<`ScCPcC!ax~$(;3M6KoR^irc6gfd7AJpv^@@^`8W_^X!2!M~YV3er z0ChM@*anQDtTep1X(1|6WR59%CdhYzHo5Gx^}WOse#q=8!{3aIlb3}JE@()mV2*le3>F$gtjR)Vg#-};_yxM^);$n3Voy?Z+5A|qUEi26dP zBJFFIF$ODhoe)x|jL8ueTJCqyk;f&doQ1a`XwFa3wODDT-GAO zA3aIx=&x`4xvV3o4zHw5mr{TW+Il)!K=8)Ig4+;sj}D$I=83Z@giwf&WTJrpPv`?n zB{eqr-eOK$X>z`F09vXhpG0{0 zL-Xwe-&_#eyKD;Q8E~P>Zam2EYeNm;msp8?_(Nq;oZp&yz-}v6RsB>XfNiKC-8W-* zH^RY{7)q0Po5lU%2WWllPxdrzfA{VQ8TDjrSDpRAgO}W;>XKO$I-0xAxIMZ}@9-e$ zQ!uGb36!jB?hY0hvLcUFN$eIv!@vMKhdvvVzf%wLuVSU&y5~zRbW}gHigl+MUPa}t zqSzk=4J}2=n3>HD4Jd|PD^Pj*kFN0Of^=OX4ZLKRCl4XuwK+n;M{l<@bf|wr<&lv{ zmj;MlwBSOAej=Bc9oAMF8(My0>VflQP2Q>`xw=_&;(H`JnEz>n`vkd8j~sasG1KUM z9*j6nq?xL#uc0O3ZdYg`U-&3w%BlD(TS=?b)g~4#D4Jc%+$$31EHX-7VL1$tO6J8& z;*nOv!mlp_0G%3P#IG+coQ0=oe(FWZt#fG>6;kzA^GL?;WYn1xMbDm&4sZNmjRQ)` zNn672lJHJye{a=5?ysakmtrG^js~L)bF_Xu68aH*r~8|O%`{H#G%Ydy8)hl)0az$) z=2eU}U?MEyBe`f0W_a-FBauX|Xrb)N<}&wO{EqD4o2AL0lBEXLX6)Wtv~5Ua5|!pr zh*l^g0ejjnU^5-YDd>`6%I;Y0pU`u_I2KS?Ib2mf5k z-yBSVLL#n9)?nu&>{S+odM}oqaId_CHtR1aj|Cwcq#5z6v~Q@?Ll(WJ3_Lx=T**LE z%a6vuAQDS7xc2CH;l9}L#&Fl`VD5|QC6@FmeM8shey7HCbRR9&CqAh5br6-Zctqpg zTEt6>@429(E*mP{3rzMCM&7-YM)djL*Q^;Lfqn6Fj$%l{s$em{`s)s^PJQcPp0tmJ zH0jurBq^yIayy1oC|wibO9i=Q(OGq7HjQPv@&7#ZU3uz7TanRPj=|a&007e4z58$M z{V|5)KKB2%=KuJBz#d?D6!c`veVR(@RA#)MYX4jV{bAYMuQaKE2xo8Xh#tqg1 z8PRcVeyD2d{M>vOCL;lt%n)|BJyg@`QYe0xHEZgzsX}k9=#qj`mo^vQ^Et^fA()qC z+yN~_P0*q!w3#_wd{aPS*tk-lS$91bD!^I@zvTE}i24ek07)3G{*8J~FC)QPS^r`d z%t)Y1lR`-~$-@39nEge|O`g2MUKqT^<>;=*Pzy zP|P&uT_q0&n5AIew{mAayn=vw*&-_8#LNt#ozb@NuU`=jc~E0+Eh-bu?Mc<3@Byq@ zdcr;Ysd0a5hWgu7KD0d1UinWLPquIazW9aFTt#javayacEq+N}DG!>A8COVKENvZl zx<$*D%w9oF3a=AHYu~L{&HU&*Mo@v5fOvR30{6((d!g)91Q_Gw01L0YCAGV&8uGWx z{(^||hi*eo5XD1Asiz_wz^x-NruUn*t~FC{p-EQ%KKt%)f3pgn3zuuzWm*EaWYYMz zl)^bKnNF@-n(j^>v(Hx?Eg_Q~d5XE`n8^SAqeC(md=IU_zAEJEt!=*WVUC5u;B7!sc+M&N&I;%p>Z0iNwr50pp6+imI`xi zqn(n_C(1z1w}7I#yq*uyXhAkpl9$f8R$20zy2>L19g{l~j06c|!^8ReOM1ei6_6^S z-?)=`&TDOTZIr~3O;x4Z%tL}oe$JILV`o_xg?&)dd2XL^Hyh{Plf zkj5q}@Ae#$qr@P!lO_CZ=}2yCrS3SC?53_FIfC3FToBf}nK6Hwrn{Q4#B2F&r_61| zN^0x*GGGGydFMS0Z8*(J;1h4>|KTa$4rh?&WNMMQEdzf>G);-(zACIq1h8_TW>Kt4-lYGB=02sN ziWAqH`bmUu&O0z~krvY>e+qWDj5}lr+=?vLHsBV02QLUFn-z0_I!w0e&bqX%bH?ES zxpqa>k-3hYo3qKx-LC$K_msw!L$q69 z$UuA52;j2mw?)Q#hFMQ8NnKg7rln}#($?u`qf!@xXa=3Urm7-3sW|f+-FAu)=^#ap zq1pcPkP#<{dL8v!pJQR}`RL+~8lR@u(Yj-V8|Q${e4-CNi}(iLpueo=Z!TZ-zEl@# zF9A%)H*RT84e2e7<4O?J@fdB*f=OMb-tjn$2mm?ox^x6;dAXN$#Zej37N`-LVh z3CyrdYj&5e=J^7jhkjh*QE`)o;)95A43E({04OjEq8A*RifeUo^4~iKKD`hS9N84h zu6gDUOrYdY|4S7WIO^f@t$*{*Az-_qw=H3pu0n|29WP<*G>R$4*Z>Uj*OHKu=V?64 zdYg(%xU0mTV z+3lgqhlitKm~tg*8jU~it4vG2k`(tsgL7UcL)~y2SHwQBL|X;bv@1ewJE?JCQmrou%5V zsH!qNrdU3nsv2S{I&wvhq7NwW=>uz^$m!l)nGfRf66Br-DpE*-Z$_|)FI=3q+fQ#Q z+c3(-n1)uG`jvvuqJ}&3p|=0vY6>GBJ_Z|f2@AY~*8l-8N=^P<0o)Xj#pe2(FE8&< zm1tj6e)LE_G)IWp()gNjhjP1HU7DK#xnpwqYF`c-|FBKS+%yv-2?B}D!G zBtQY~k6HTtaRtOc5xk5Mjn)G39D%Y)i|fkn(+9}h&rwm_sGR3Jr(@`S?uqmW&@}l) zi=%SOjnlnTVs3Wf2~k-EsoiPoZ%>4Hh!8>#=@it*7^0(7Y>fjRQ4Q+D$|@bK_r5<) zWqZQ}cO!xZ!BUd)v!Jt7WF{qyNreXxTG~hLy|trqh#iC=bV!rjrQCEj1c^6n3=d8% zh!d})im%nYT!{;ByqV~7=x%J5IvJE&MAH`G5e0Xp$eQ<6Mn(+(Sn?+7CUP7u!`YAu z4WGQAM!sz>bRh|r27$OluYqI?Qi91mLAZK|=HvEDUC(O$>_@KFfi}eR0Ly}U81YRi z?gnkA34WC4LP@xnqe{7LykROSCD&h45>kn~?=*pRuP&yLuHZ8`aA`S;Tpzt(McvF~ z9yMn#@mzcYd`JTSRK>e@8*${qbi$9wzyVG{?-VlULr2{&h`tTOVndbJPeiap!Opi)k*&mE# zvPrSvs^C+=u@4DZ)Lca1PsSa%_{QDs%oWGW5Xc{MHKwAA`l*XYh4Bw)j8zog>X)Lh z%*c%FjvOTyngz)jYoB2yH;}%Y%M9>U>0=XB+mA>Aq|WYGvJ__|@qt`@Rp~>&krfMvORxpTaG?6T+NxF@c_EO=aNvDjaonj>a$l4O@h4!Ce9ken^Bz_Pw zFusbIX``7a?)$VHa@5WUWw?FU$Cr3MA}UItO2K*Z3Zm6BJn+>npvEW7Kk$N$RM@2v zma9s+awg9fe1`hPR8*vnm8JZl6UJjeF(NrE;&AAPoz2rkrj@b*jMl62F)!*R*1=OL zsy=b4xH0LHhB~0&nmq7ECy@~&kZf`2nf;msK`TuAG9=HrYq7DB9YI9t`?!O|BEvg` z@KP7bra>SWGI3o@g~@<1=bhf$eU3rBq!@{e+RcAe+}vXVIlhhO2$t`ZhFIESeClcP zOS7gxe`01>RFs1R#{CK-{&|%|y|J=nmp_m+2~(2)ATi`S2&DN?$zmdB|LQ>v#cSgR|d{t*~I;)0)%jP*;FD*?@zXB5OczSW*wlPeT|ykkXtkPcE%6m=GI|q4w$Q_KG7Dz~7dq z?e~s@7-Li%wgqF1!Y4RS`Wfns6S9~lr&u(hl3+72 z#vGPKD%InUQUiTb4S`tS{7k*^?31jFRCs9#Ok%1k}5@|T-6~x6w956U$q44`(Jh@_#t)gtWT=oevU<@5A>mb#b zZF#p-$#N`Lvi*V*Jt(wH!bZOs3FGewT+kvo^A zWmJqX$*OT#*T~JL#0i4oWp276{7NB$iNu#Pm0wVo>FAihRh%ZS=TW9V%NkIPn7Y3f zVTQp1{(hwNvFB#`p2f0;cku0oJ7fegAE9$PMIlo^6LIfhB1tGC=9nTYDc2wORyMsM zkUX_(G=@eJyNz%R2j0jVr}K`0Qp#Qs!vR?Nq5uyro}Wp*W(YeC>|*lFpM~z-Xyo%C z5kLLpz;XCxB&Gm3*O6^_ie<8JlY(jB_;Hu}z%4aayHB*PY`Osi*Vczfb0AIC=}^Ls z_S4oroOesAT%b3Dnb4oF7$T8l2a4h;UsgmeG3HdqlC2a)8izzlC` z_~H>^LOr9=*~aj$^FjqnKn@_9RNnGCLgm8ZyZo3 z{8lVCfOA2};Xt=2a6{*xiXru}jnm+&(uBn|8^468sH{5L^%x_6vR}N&>A&4W66Weh z=*AnO%kn~o?yj*s)$qoRS}5tLsE7{7tK4|=WILD5)B@Azd2JyD*dNN5&EjqI`&UZD zVvw+avX+Ake84qURy~aoF8@?J+tvhCpIw{sp6Lj>7n(c9xA!fjjI!QBO8PaFM8~hI z1E5$UsCJp)hTTj^Ait8KLgd>o(_PXKnBn=LG;PejVzFc%TM*^f9?s$w(M-SAN<@Y#Td>J4zB(=*X<9F4_TK3Z$?j@`DIhS zhO%8jn4HD9_$=s`g{-_>*;If4eNhu$%*ba)%y4K}!m$aWNC5uEHW=@8F6tOJN2z3A{fu@Hc|GWmrhAW#AU_Du1V0&}N#9xQb zt$4i`*ABAq*7Vt|hFITkx#IWeV9a({CI$L+$>n z8r8e|=?S_FP0EG^^c3(_rK$vJp5kPe^_|>YiWP0v`7TlG)_8D)99v+vAi&$TKJqI-6Ts zr$VJoC(o*dc)c60cx(^2TpVrI;5N~k-e-DuDgsw#gt`aF|EYY7tDhx|e@wWyPzASX z-!!7rJ@J%Z1b{(fC#ZpwEYSY06|5YfDF zseI;P$cc3e$E^d~$S0H#CZ`|^T*^Z&?s@@Z?$y-57?5BZrC2p3*@8_AHSN12?ZuouEtOwB|FT6G`qA5>_imFNwlrBz&H-5lRIA8cm;S?hJn9@0EcxKo_gOG)YUfz z#MfCnsLQE~8wgUK9u>$%=rOwY&+$JZKMy&H5Xuroa*S6@25M<{M#=JuK&$aZVp-Cg zmFnd`4HJo1q@6v?-ipT(BVXe~kJG*P0#{7y#f-VD^exXbk?Xw%QV)zCeyth8>;SA$ zIdvS18KJ`7t#9nNr}c{ALws4R@a%ACi5Pk72wlc=%B~N*TuSCl7OSwY=he~b&$lgW z#<==spkz5f&nTz#ruRTOm3fK$qm`=!qvDUo8D*gjf6f7UkcvP_c}N&@*C=_`ASnJx zw<^};T30((uuEXcDnY5{;Ivt&DE>|R-1kHgtDii$NL=L5+V3OB=p+az_?^2ChHZ6Iw%f9<>E$uqr0#~LgYUe;HL^yJY?i2nz^lsr@P7U(ZYh7x6 zk)189a;s~p0B#N353AO5a&~tA+KR+;sxC-6hqEfb1Vz$G93ye+QCn@u0j0Xi(ITyO zip#f!-`tiZH)YbcHo3#X-vTyPW#DM=q^d|to+N(suQ=6CM` zrxi~8?e1<*A)JebtM?gb%=$xty02FG@yt@s!!n_naq-onG;axJy0yG$!_O~?eN2Af zSY|@Hj zuGoZ@Z#;{;9f(X}D1d(j%E&6M1tV;|2JzGU`;;1exKJAII6RUQ9ZC1zQuKl~#~Qd) zQNn;m1e$w3H2(T)?I^?7Gr+;D`qkcGsK}b$eyccZjOpox0OPH4;6+*OA=Cj$DbE>O^sDlB%uO>q8h(})Qdj6pFCKNWrC5C? zqHIjOjh1WG`kF6i4of%vD9_2J$g6?frDVEjq+k39M7I8+$g}(L2G)GvQa5Y~XB5#} z@MTmuvWkd$Zvc-f*nbCogT~b0kB-sqB5bPA>{Cx&DTq0Qn-&m>QtKRg!8%t*`-uhT z|Dq#Dv+p_`QOxJ&`!9B?^}tptt+84iH_WD&B@Iqc++AIR9uNa)3ul!_njP%nY-{s> zazu9Ms8m0D1f_?(IKIem4)_%Yi?D)RzCk z5~XIvHCMT(COoP|wskg#e|vGl#zE`UtNG27KkA#Uc^6)9#)s$l)Ji=Zp@qIw?Ze3} zP9d`+$|UQbLEsAK1)RhPS0r&M zQEExhr)wuUn6ia1tubLeoRubU{7Y)}!9bQ!^L5S+&k=?%7SW=Gbd)CtahCLsK-q|it(8(ZhA*g6K2etU;dlL{E3fxxRY`G;HxN?{Key%6ZZbB2@aWus zG;4Ts{LjV)xm?EaLNlef?ed^SjnL`Q$a!7MLB1?e*xM35w&z@|P73qrmkw^gvZ2*> z-g8{9zPHkn&M5!YQyAk!`l2hA0^)i|9<>*^Vv+Rj(;q+Xd~p;2iJ;3kp;Ltu!+SDB z$J42<0N8a?DRazi)JKOrrxR2&t~sk zzv~fxgQ12$1#B)#K$L1jE0a<4Ha0?G8Qr|+kKuYud@Y}}7nMS8UOoEAY?E!2yu6_?)vr?YS)dK$HzI(L-w zuqc1pfhti>L%b3J3o*p?gM+mh;a&-4NTmjjnu8x>i5z4xKx(@T1>Xg}G27%Me)E_I z^isq z^P@R%7lnJ`=RP%80536f(NOk_=fq$5Q(OK+cxDL4y-0Ivg1M_JR3fYCqh#7*Nb~@< zULQNng=39S`A{8wd4T0b)ku4y(9F4GM4mwlGAG=z7<19#z)08V2yJ7UJw`Wj}@sMcdy4m!iY?NTemd$8^6#6lrVCD{&4s@hykJ=TJ`vo52}GO4vgGmzSnI zOd;l4%ZbsEd+Yws1{nP3O5iqIGJ^W-aEYG<07oG0=Aof%T|Q{!CZ4UP4_X|1zd(n&^T5sExio zLB2nQ=qvF(+w=oODp+`qg*kZ|6Wz~6f9MPJYGkf1ASg5S>JP`9Yd;0w<-{=&++XNp zb-}+s(gJ-S+t@g{nXSNK`LHc;|F233WUhwpx+Gtbo=EX^lV{!{vEH=uE>xJNmntcr zUDjiAJ@0RGBo26%Fp|HUpge&HUpyJ&3RyMRm&a5a@Lin9x+9r$XUqK-8&eDL?W-m@ zit2Jjr+$d9Ay|Zru?Pq=2k=l=8U;ZX;!<4Zj`%&EaEVY1d%`rkR4hM?B}@TaXd-P>-67U|nGEoMs9ZRt@bkI5L54z4=R zcC#sTQ6$LJv9NV& zQ@^n?`3M!h`slvxwx{tDXUZC>{4vr8QGSiEhKG9sVrJr~M?R@8ZNgdwLCj7^r*>ak KrCiD8)&Bvg?Hy?V diff --git a/package.v2.json b/package.v2.json index 68190d7..67f8ed2 100644 --- a/package.v2.json +++ b/package.v2.json @@ -508,11 +508,12 @@ "name": "美剧生词标注", "description": "根据CEFR等级,为英语影视剧标注高级词汇。", "labels": "英语", - "version": "1.0.1", + "version": "1.1.0", "icon": "LexiAnnot.png", "author": "wumode", "level": 1, "history": { + "v1.1.0": "支持考试词汇标注; 优化分词处理; 修复错误", "v1.0.1": "合并连字符词; 避免ARM平台依赖问题", "v1.0": "新增LexiAnnot" } diff --git a/plugins.v2/lexiannot/README.md b/plugins.v2/lexiannot/README.md index 4b08489..1bb9055 100644 --- a/plugins.v2/lexiannot/README.md +++ b/plugins.v2/lexiannot/README.md @@ -7,6 +7,7 @@ ![](https://images2.imgbox.com/d6/b6/kZu6EH2a_o.png) ![](https://images2.imgbox.com/c8/3a/rEJBWu5v_o.png) ![](https://images2.imgbox.com/97/b7/d6RXFtwD_o.png) +![](https://images2.imgbox.com/8a/d4/AtgOe265_o.jpg) # Gemini @@ -38,7 +39,7 @@ CEFR全称是Common European Framework of Reference for Languages。 # 计划 - 双语字幕支持 -- 考试词汇标注 +- ~~考试词汇标注~~ # FAQ diff --git a/plugins.v2/lexiannot/__init__.py b/plugins.v2/lexiannot/__init__.py index fec6d93..78b5f63 100644 --- a/plugins.v2/lexiannot/__init__.py +++ b/plugins.v2/lexiannot/__init__.py @@ -1,3 +1,4 @@ +from collections import Counter import os import re import sys @@ -7,16 +8,17 @@ import time import threading import queue import shutil -from typing import Any, List, Dict, Tuple, Optional, Union, Type, TypeVar +from typing import Any, List, Dict, Tuple, Optional, Union, Type, TypeVar import venv from pathlib import Path -from collections import Counter -from apscheduler.schedulers.background import BackgroundScheduler import pysubs2 from pysubs2 import SSAFile, SSAEvent import pymediainfo from langdetect import detect +import spacy +from spacy.util import compile_infix_regex +from spacy.tokenizer import Tokenizer from app.core.config import settings from app.log import logger @@ -34,15 +36,16 @@ from app.plugins.lexiannot.query_gemini import DialogueTranslationTask, Vocabula T = TypeVar('T', VocabularyTranslationTask, DialogueTranslationTask) + class LexiAnnot(_PluginBase): # 插件名称 plugin_name = "美剧生词标注" # 插件描述 plugin_desc = "根据CEFR等级,为英语影视剧标注高级词汇。" # 插件图标 - plugin_icon = "https://raw.githubusercontent.com/wumode/LexiAnnot/refs/heads/master/LexiAnnot.png" + plugin_icon = "LexiAnnot.png" # 插件版本 - plugin_version = "1.0.1" + plugin_version = "1.1.0" # 插件作者 plugin_author = "wumode" # 作者主页 @@ -63,11 +66,11 @@ class LexiAnnot(_PluginBase): _sentence_translation = False _in_place = False _enable_gemini = False - _gemini_model = False + _gemini_model = '' _gemini_apikey = '' - _context_window = 0 - _max_retries = 0 - _request_interval = 0 + _context_window: int = 0 + _max_retries: int = 0 + _request_interval: int = 0 _ffmpeg_path = '' _english_only = False _when_file_trans = False @@ -76,18 +79,12 @@ class LexiAnnot(_PluginBase): _accent_color = '' _font_scaling = '' _opacity = '' - - # 插件数据 - _lexicon_version = '' - _swear_words = None - _cefr_lexicon = None - _coca2k_lexicon = None + _exam_tags: List[str] = [] + _spacy_model: str = '' + _delete_data: bool = False # protected variables _lexicon_repo = 'https://raw.githubusercontent.com/wumode/LexiAnnot/' - _spacy_model_name = "en_core_web_sm" - _scheduler: Optional[BackgroundScheduler] = None - _nlp = None _worker_thread = None _task_queue = None _shutdown_event = None @@ -98,109 +95,65 @@ class LexiAnnot(_PluginBase): _gemini_available = False _accent_color_rgb = None _color_alpha = 0 + _loaded = False + _config_updating_lock: Optional[threading.Lock] = None def init_plugin(self, config=None): self._task_queue = queue.Queue() + self._config_updating_lock = threading.Lock() self.stop_service() if config: self._enabled = config.get("enabled") - self._annot_level = config.get("annot_level") + self._annot_level = config.get("annot_level") or 'C1' self._send_notify = config.get("send_notify") self._onlyonce = config.get("onlyonce") self._show_vocabulary_detail = config.get("show_vocabulary_detail") self._sentence_translation = config.get("sentence_translation") self._in_place = config.get("in_place") self._enable_gemini = config.get("enable_gemini") - self._gemini_model = config.get("gemini_model") - self._gemini_apikey = config.get("gemini_apikey") - self._context_window = config.get("context_window") - self._max_retries = config.get("max_retries") - self._request_interval = config.get("request_interval") + self._gemini_model = config.get("gemini_model") or 'gemini-2.0-flash' + self._gemini_apikey = config.get("gemini_apikey") or '' + self._context_window = int(config.get("context_window") or 10) + self._max_retries = int(config.get("max_retries") or 3) + self._request_interval = int(config.get("request_interval") or 3) self._ffmpeg_path = config.get("ffmpeg_path") self._english_only = config.get("english_only") self._when_file_trans = config.get("when_file_trans") - self._model_temperature = config.get("model_temperature") + self._model_temperature = config.get("model_temperature") or '0.3' self._show_phonetics = config.get("show_phonetics") self._custom_files = config.get("custom_files") self._accent_color = config.get("accent_color") - self._font_scaling = config.get("font_scaling") - self._opacity = config.get("opacity") + self._font_scaling = config.get("font_scaling") or '1' + self._opacity = config.get("opacity") or '0' + self._spacy_model = config.get("spacy_model") or 'en_core_web_sm' + self._exam_tags = config.get("exam_tags") or [] + self._delete_data = config.get("delete_data") or False self._accent_color_rgb = LexiAnnot.hex_to_rgb(self._accent_color) or (255, 255, 0) self._color_alpha = int(self._opacity) if self._opacity and len(self._opacity) else 0 + if self._delete_data: + # 删除不再保存在数据库的数据 + self.del_data('cefr_lexicon') + self.del_data('coca2k_lexicon') + self.del_data('swear_words') + self.del_data('lexicon_version') + self.delete_data() + self._delete_data = False + self._loaded = False if self._enabled: - self._query_gemini_script = f"{settings.ROOT_PATH}/app/plugins/lexiannot/query_gemini.py" - self._cefr_lexicon = self.get_data("cefr_lexicon") - self._coca2k_lexicon = self.get_data("coca2k_lexicon") - self._swear_words = self.get_data("swear_words") - self._lexicon_version = self.get_data("lexicon_version") - latest = self.__load_lexicon_version() - if not self._lexicon_version or StringUtils.compare_version(self._lexicon_version, '<', latest): - self.__load_lexicon() - # try to import spaCy - try: - import spacy - except ModuleNotFoundError: - logger.info('正在安装spaCy ...') - result, output = SystemUtils.execute_with_subprocess( - [sys.executable, "-m", "pip", "install", 'thinc==8.3.4'] - ) - if not result: - logger.error(f"无法安装spaCy, {output}") - return - result, output = SystemUtils.execute_with_subprocess( - [sys.executable, "-m", "pip", "install", 'spacy==3.8.7'] - ) - if not result: - logger.error(f"无法安装spaCy, {output}") - return - try: - import spacy - from spacy.util import compile_infix_regex - from spacy.tokenizer import Tokenizer - if self._nlp is None: - self._nlp = spacy.load(self._spacy_model_name) - infixes = list(self._nlp.Defaults.infixes) - infixes = [i for i in infixes if '-' not in i] - # 使用修改后的正则表达式重新创建 tokenizer - infix_re = compile_infix_regex(infixes) - self._nlp.tokenizer = Tokenizer( - self._nlp.vocab, - prefix_search=self._nlp.tokenizer.prefix_search, - suffix_search=self._nlp.tokenizer.suffix_search, - infix_finditer=infix_re.finditer, - token_match=self._nlp.tokenizer.token_match - ) - except OSError: - self._nlp = LexiAnnot.__load_spacy_model(self._spacy_model_name) - if not (self._nlp and self._cefr_lexicon and self._coca2k_lexicon and self._swear_words): - _loaded = False - else: - _loaded = True - if not _loaded: - logger.warn(f"插件数据未加载,初始化失败") - self._enabled = False - self.__update_config() - return - if self._enable_gemini: - self._gemini_available = True - res = self.init_venv() - if not res: - self._gemini_available = False - if not self._gemini_apikey: - logger.warn(f"未提供GEMINI APIKEY") - self._gemini_available = False + self._query_gemini_script = str(settings.ROOT_PATH / "app" / "plugins" / "lexiannot" / "query_gemini.py") + self._shutdown_event = threading.Event() self._worker_thread = threading.Thread(target=self.__process_tasks, daemon=True) self._worker_thread.start() + if self._onlyonce: for file_path in self._custom_files.split("\n"): if not file_path: continue self.add_media_file(file_path) self._onlyonce = False - self.__update_config() - + self.__update_config() def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: """ @@ -229,28 +182,13 @@ class LexiAnnot(_PluginBase): } ] }, + { 'component': 'VCol', 'props': { 'cols': 12, 'md': 3 }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'when_file_trans', - 'label': '监控入库', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3 - }, 'content': [ { 'component': 'VSwitch', @@ -272,7 +210,23 @@ class LexiAnnot(_PluginBase): 'component': 'VSwitch', 'props': { 'model': 'onlyonce', - 'label': '立即运行一次', + 'label': '手动运行一次', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 3 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'delete_data', + 'label': '插件数据清理', } } ] @@ -280,199 +234,510 @@ class LexiAnnot(_PluginBase): ] }, { - 'component': 'VRow', + 'component': 'VTabs', + 'props': { + 'model': '_tabs', + 'style': { + 'margin-top': '8px', + 'margin-bottom': '16px' + }, + 'stacked': True, + 'fixed-tabs': True + }, 'content': [ { - 'component': 'VCol', + 'component': 'VTab', 'props': { - 'cols': 12, - 'md': 3 + 'value': 'base_tab' }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'annot_level', - 'label': '标注词汇的最低CEFR等级', - 'items': [ - {'title': 'B1', 'value': 'B1'}, - {'title': 'B2', 'value': 'B2'}, - {'title': 'C1', 'value': 'C1'}, - {'title': 'C2', 'value': 'C2'}, - {'title': 'C2+', 'value': 'C2+'} - ] - } - } - ] - }, - { - 'component': 'VCol', + 'text': '基本设置' + }, { + 'component': 'VTab', 'props': { - 'cols': 12, - 'md': 3 + 'value': 'subtitle_tab' }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'font_scaling', - 'label': '字体缩放', - 'items': [ - {'title': '50%', 'value': '0.5'}, - {'title': '75%', 'value': '0.75'}, - {'title': '100%', 'value': '1'}, - {'title': '125%', 'value': '1.25'}, - {'title': '150%', 'value': '1.5'}, - {'title': '200%', 'value': '2'} - ] - } - } - ] - }, - { - 'component': 'VCol', + 'text': '字幕设置' + }, { + 'component': 'VTab', 'props': { - 'cols': 12, - 'md': 3, + 'value': 'gemini_tab' }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'accent_color', - 'label': '强调色', - 'placeholder': '#FFFF00' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'opacity', - 'label': '不透明度', - 'items': [ - {'title': '0', 'value': '0'}, - {'title': '25%', 'value': '63'}, - {'title': '50%', 'value': '127'}, - {'title': '75%', 'value': '191'}, - {'title': '100%', 'value': '255'}, - ] - } - } - ] + 'text': 'Gemini设置' } ] }, { - 'component': 'VRow', + 'component': 'VWindow', + 'props': { + 'model': '_tabs' + }, 'content': [ { - 'component': 'VCol', + 'component': 'VWindowItem', 'props': { - 'cols': 12, - 'md': 3 + 'value': 'base_tab' }, 'content': [ { - 'component': 'VSwitch', + 'component': 'VRow', 'props': { - 'model': 'show_phonetics', - 'label': '标注音标', - } + 'style': { + 'margin-top': '0px' + } + }, + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'when_file_trans', + 'label': '监控入库', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'spacy_model', + 'label': 'spaCy模型', + 'hint': 'spaCy 模型用于分词和词性标注,推荐使用 Small', + 'items': [ + {'title': 'Small (~12 MB)', 'value': 'en_core_web_sm'}, + {'title': 'Medium (~30 MB)', 'value': 'en_core_web_md'}, + {'title': 'Large (700+ MB)', 'value': 'en_core_web_lg'}, + {'title': 'Transformer (400+ MB)', + 'value': 'en_core_web_trf'}, + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'annot_level', + 'label': '标注词汇的最低CEFR等级', + 'items': [ + {'title': 'B1', 'value': 'B1'}, + {'title': 'B2', 'value': 'B2'}, + {'title': 'C1', 'value': 'C1'}, + {'title': 'C2', 'value': 'C2'}, + {'title': 'C2+', 'value': 'C2+'} + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'english_only', + 'label': '仅英语影视剧', + 'hint': '检查入库影视剧原语言' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 8 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'exam_tags', + 'label': '考试词汇标签', + 'chips': True, + 'multiple': True, + 'items': [ + {'title': '四级', 'value': 'CET-4'}, + {'title': '六级', 'value': 'CET-6'}, + {'title': '考研', 'value': 'NPEE'}, + {'title': '雅思', 'value': 'IELTS'}, + {'title': '托福', 'value': 'TOEFL'}, + {'title': '专四', 'value': 'TEM-4'}, + {'title': '专八', 'value': 'TEM-8'}, + {'title': 'GRE', 'value': 'GRE'}, + {'title': 'PET', 'value': 'PET'}, + ] + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'ffmpeg_path', + 'label': 'FFmpeg 路径', + 'placeholder': 'ffmpeg' + } + } + ] + } + ] } ] }, { - 'component': 'VCol', + 'component': 'VWindowItem', 'props': { - 'cols': 12, - 'md': 3 + 'value': 'subtitle_tab' }, 'content': [ { - 'component': 'VSwitch', + 'component': 'VRow', 'props': { - 'model': 'in_place', - 'label': '在原字幕插入注释', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3 - }, - 'content': [ + 'style': { + 'margin-top': '0px' + } + }, + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'font_scaling', + 'label': '字体缩放', + 'items': [ + {'title': '50%', 'value': '0.5'}, + {'title': '75%', 'value': '0.75'}, + {'title': '100%', 'value': '1'}, + {'title': '125%', 'value': '1.25'}, + {'title': '150%', 'value': '1.5'}, + {'title': '200%', 'value': '2'} + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'accent_color', + 'label': '强调色', + 'placeholder': '#FFFF00' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'opacity', + 'label': '不透明度', + 'items': [ + {'title': '0', 'value': '0'}, + {'title': '25%', 'value': '63'}, + {'title': '50%', 'value': '127'}, + {'title': '75%', 'value': '191'}, + {'title': '100%', 'value': '255'}, + ] + } + } + ] + } + ] + }, { - 'component': 'VSwitch', - 'props': { - 'model': 'english_only', - 'label': '仅英语影视剧', - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3 - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'show_vocabulary_detail', - 'label': '显示完整释义', - } - } - ] - }, + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'show_phonetics', + 'label': '标注音标', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'in_place', + 'label': '在原字幕插入注释', + } + } + ] + }, - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6, - }, - 'content': [ - { - 'component': 'VSwitch', - 'props': { - 'model': 'enable_gemini', - 'label': '启用Gemini翻译', - } - } + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 4 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'show_vocabulary_detail', + 'label': '显示完整释义', + } + } + ] + }, + + ] + }, ] }, { - 'component': 'VCol', + 'component': 'VWindowItem', 'props': { - 'cols': 12, - 'md': 6 + 'value': 'gemini_tab' }, 'content': [ { - 'component': 'VSwitch', - 'props': { - 'model': 'sentence_translation', - 'label': '整句翻译', - } + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6, + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'enable_gemini', + 'label': '启用Gemini翻译', + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6 + }, + 'content': [ + { + 'component': 'VSwitch', + 'props': { + 'model': 'sentence_translation', + 'label': '整句翻译', + } + } + ] + } + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6, + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'gemini_model', + 'label': '模型', + 'items': [ + {'title': 'gemini-2.5-flash', + 'value': 'gemini-2.5-flash'}, + {'title': 'gemini-2.5-flash-lite', + 'value': 'gemini-2.5-flash-lite'}, + {'title': 'gemini-2.5-pro', + 'value': 'gemini-2.5-pro'}, + {'title': 'gemini-2.0-flash', + 'value': 'gemini-2.0-flash'}, + {'title': 'gemini-2.0-flash-lite', + 'value': 'gemini-2.0-flash-lite'}, + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 6, + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'gemini_apikey', + 'label': 'Gemini APIKEY', + 'placeholder': '' + } + } + ] + }, + ] + }, + { + 'component': 'VRow', + 'content': [ + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 3, + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'context_window', + 'label': '上下文窗口大小', + 'placeholder': '10', + 'type': 'number', + 'max': 20, + 'min': 1, + 'hint': '向Gemini发送的上下文长度' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 3 + }, + 'content': [ + { + 'component': 'VSelect', + 'props': { + 'model': 'model_temperature', + 'label': '模型温度', + 'items': [ + {'title': '0', 'value': '0'}, + {'title': '0.1', 'value': '0.1'}, + {'title': '0.2', 'value': '0.2'}, + {'title': '0.3', 'value': '0.3'}, + ] + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 3, + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'max_retries', + 'label': '请求重试次数', + 'placeholder': '3', + 'type': 'number', + 'min': 1, + 'hint': '请求失败重试次数' + } + } + ] + }, + { + 'component': 'VCol', + 'props': { + 'cols': 12, + 'md': 3, + }, + 'content': [ + { + 'component': 'VTextField', + 'props': { + 'model': 'request_interval', + 'label': '请求间隔', + 'type': 'number', + 'placeholder': 5, + 'min': 1, + 'suffix': '秒', + 'hint': '请求间隔时间,建议不少于3秒' + } + } + ] + }, + ] } ] } @@ -480,164 +745,11 @@ class LexiAnnot(_PluginBase): }, { 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6, - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'gemini_model', - 'label': '模型', - 'items': [ - {'title': 'gemini-2.5-flash-preview-05-20', - 'value': 'gemini-2.5-flash-preview-05-20'}, - {'title': 'gemini-2.5-pro-preview-05-06', - 'value': 'gemini-2.5-pro-preview-05-06'}, - {'title': 'gemini-2.0-flash', 'value': 'gemini-2.0-flash'}, - {'title': 'gemini-2.0-flash-lite', 'value': 'gemini-2.0-flash-lite'}, - {'title': 'gemini-1.5-flash', 'value': 'gemini-1.5-flash'}, - {'title': 'gemini-1.5-pro', 'value': 'gemini-1.5-pro'} - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 6, - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'gemini_apikey', - 'label': 'Gemini APIKEY', - 'placeholder': '' - } - } - ] - }, - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3, - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'context_window', - 'label': '上下文窗口大小', - 'placeholder': '10', - 'type': 'number', - 'max': 20, - 'min': 1, - 'hint': '向Gemini发送的上下文长度' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3 - }, - 'content': [ - { - 'component': 'VSelect', - 'props': { - 'model': 'model_temperature', - 'label': '模型温度', - 'items': [ - {'title': '0', 'value': '0'}, - {'title': '0.1', 'value': '0.1'}, - {'title': '0.2', 'value': '0.2'}, - {'title': '0.3', 'value': '0.3'}, - ] - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3, - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'max_retries', - 'label': '请求重试次数', - 'placeholder': '3', - 'type': 'number', - 'min': 1, - 'hint': '请求失败重试次数' - } - } - ] - }, - { - 'component': 'VCol', - 'props': { - 'cols': 12, - 'md': 3, - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'request_interval', - 'label': '请求间隔', - 'type': 'number', - 'placeholder': 5 , - 'min': 1, - 'suffix': '秒', - 'hint': '请求间隔时间,建议不少于3秒' - } - } - ] - }, - ] - }, - { - 'component': 'VRow', - 'content': [ - { - 'component': 'VCol', - 'props': { - 'cols': 12, - }, - 'content': [ - { - 'component': 'VTextField', - 'props': { - 'model': 'ffmpeg_path', - 'label': 'FFmpeg 路径', - 'placeholder': 'ffmpeg' - } - } - ] + 'props': { + 'style': { + 'margin-top': '0px' } - ] - }, - { - 'component': 'VRow', + }, 'content': [ { 'component': 'VCol', @@ -649,7 +761,7 @@ class LexiAnnot(_PluginBase): 'component': 'VTextarea', 'props': { 'model': 'custom_files', - 'label': '视频路径', + 'label': '手动处理视频路径', 'rows': 3, 'placeholder': '每行一个文件' } @@ -690,9 +802,9 @@ class LexiAnnot(_PluginBase): 'text': 'README' } ] - }] + } + ] } - ] } ] @@ -722,6 +834,9 @@ class LexiAnnot(_PluginBase): "accent_color": '', "font_scaling": '1', "opacity": '0', + "spacy_model": 'en_core_web_sm', + "exam_tags": [], + "delete_data": False } def get_api(self) -> List[Dict[str, Any]]: @@ -744,7 +859,10 @@ class LexiAnnot(_PluginBase): """ 退出插件 """ - self.shutdown() + try: + self.shutdown() + except Exception as e: + logger.error(f"退出插件失败:{e}") def shutdown(self): """ @@ -755,9 +873,29 @@ class LexiAnnot(_PluginBase): self._shutdown_event.set() self._worker_thread.join() logger.debug("✅ Existing worker thread stopped.") + self._worker_thread = None else: logger.debug("ℹ️ No running worker thread to stop.") + def delete_data(self): + data_path = self.get_data_path() + lexicon_path = data_path / 'lexicon.json' + try: + os.remove(lexicon_path) + logger.info(f"词典 {lexicon_path} 已删除") + except FileNotFoundError: + pass + except Exception as e: + logger.error(f"词典 {lexicon_path} 删除失败: {e}") + + venv_dir = data_path / "venv_genai" + if os.path.exists(venv_dir): + try: + shutil.rmtree(venv_dir) + logger.info(f"虚拟环境 {venv_dir} 已删除") + except Exception as e: + logger.error(f"虚拟环境 {venv_dir} 删除失败: {e}") + def add_media_file(self, path: str): """ 添加新任务 @@ -768,35 +906,54 @@ class LexiAnnot(_PluginBase): raise RuntimeError("Plugin is shutting down. Cannot add new tasks.") def __update_config(self): - self.update_config({'enabled': self._enabled, - 'annot_level': self._annot_level, - 'send_notify': self._send_notify, - 'onlyonce': self._onlyonce, - 'show_vocabulary_detail': self._show_vocabulary_detail, - 'sentence_translation': self._sentence_translation, - 'in_place': self._in_place, - 'enable_gemini': self._enable_gemini, - 'gemini_model': self._gemini_model, - 'gemini_apikey': self._gemini_apikey, - 'context_window': self._context_window, - 'max_retries': self._max_retries, - 'request_interval': self._request_interval, - 'ffmpeg_path': self._ffmpeg_path, - 'english_only': self._english_only, - 'when_file_trans': self._when_file_trans, - 'model_temperature': self._model_temperature, - 'show_phonetics': self._show_phonetics, - 'custom_files': self._custom_files, - 'accent_color': self._accent_color, - 'font_scaling': self._font_scaling, - 'opacity': self._opacity - }) + with self._config_updating_lock: + self.update_config({'enabled': self._enabled, + 'annot_level': self._annot_level, + 'send_notify': self._send_notify, + 'onlyonce': self._onlyonce, + 'show_vocabulary_detail': self._show_vocabulary_detail, + 'sentence_translation': self._sentence_translation, + 'in_place': self._in_place, + 'enable_gemini': self._enable_gemini, + 'gemini_model': self._gemini_model, + 'gemini_apikey': self._gemini_apikey, + 'context_window': self._context_window, + 'max_retries': self._max_retries, + 'request_interval': self._request_interval, + 'ffmpeg_path': self._ffmpeg_path, + 'english_only': self._english_only, + 'when_file_trans': self._when_file_trans, + 'model_temperature': self._model_temperature, + 'show_phonetics': self._show_phonetics, + 'custom_files': self._custom_files, + 'accent_color': self._accent_color, + 'font_scaling': self._font_scaling, + 'opacity': self._opacity, + 'spacy_model': self._spacy_model, + 'exam_tags': self._exam_tags, + }) def __process_tasks(self): """ 后台线程:处理任务队列 """ logger.debug("👷 Worker thread started.") + + self.__load_data() + if not self._loaded: + logger.warn('插件数据未加载') + self._enabled = False + self.__update_config() + logger.debug("🛑 Worker exiting...") + return + if self._enable_gemini: + self._gemini_available = True + res = self.init_venv() + if not res: + self._gemini_available = False + if not self._gemini_apikey: + logger.warn(f"未提供GEMINI APIKEY") + self._gemini_available = False while not self._shutdown_event.is_set(): try: task = self._task_queue.get(timeout=1) # 最多等待1秒 @@ -811,13 +968,35 @@ class LexiAnnot(_PluginBase): """ 处理视频文件 """ + if not self._loaded: + return + lexicon = self.__load_lexicon_from_local() + if not lexicon: + logger.error(f"字典加载失败") + return + try: + nlp = spacy.load(self._spacy_model) + infixes = list(nlp.Defaults.infixes) + infixes = [i for i in infixes if '-' not in i] + # 使用修改后的正则表达式重新创建 tokenizer + infix_re = compile_infix_regex(infixes) + nlp.tokenizer = Tokenizer( + nlp.vocab, + prefix_search=nlp.tokenizer.prefix_search, + suffix_search=nlp.tokenizer.suffix_search, + infix_finditer=infix_re.finditer, + token_match=nlp.tokenizer.token_match + ) + except Exception as e: + logger.error(f"spaCy 模型 {self._spacy_model} 加载失败: {e}") + return video = Path(path) if video.suffix.lower() not in settings.RMT_MEDIAEXT: return if not video.exists() or not video.is_file(): logger.warn(f"文件 {str(video)} 不存在, 跳过") return - subtitle = video.with_suffix(".ass") + subtitle = video.with_suffix(".en.ass") if subtitle.exists(): logger.warn(f"字幕文件 ({subtitle}) 已存在, 跳过") return @@ -829,6 +1008,7 @@ class LexiAnnot(_PluginBase): text=f"{message}") ffmpeg_path = self._ffmpeg_path if self._ffmpeg_path else 'ffmpeg' embedded_subtitles = LexiAnnot.__extract_subtitles_by_lang(path, 'en', ffmpeg_path) + embedded_subtitles = sorted(embedded_subtitles, key=lambda track: 'SDH' in track['title']) ret_message = '' if embedded_subtitles: logger.info(f'提取到 {len(embedded_subtitles)} 条英语文本字幕') @@ -839,14 +1019,17 @@ class LexiAnnot(_PluginBase): if embedded_subtitle.get('codec_id') == 'S_TEXT/UTF8': ass_subtitle = LexiAnnot.set_srt_style(ass_subtitle) ass_subtitle = self.__set_style(ass_subtitle) - ass_subtitle = self.process_subtitles(ass_subtitle) + ass_subtitle = self.process_subtitles(ass_subtitle, lexicon.get('cefr'), lexicon.get('coca20k'), + lexicon.get('examinations'),lexicon.get('swear_words'), nlp) if self._shutdown_event.is_set(): return if ass_subtitle: try: ass_subtitle.save(str(subtitle)) ret_message = f"字幕已保存:{str(subtitle)}" + logger.info(f"字幕已保存:{str(subtitle)}") except Exception as e: + ret_message = f"字幕文件 {subtitle} 保存失败, {e}" logger.error(f"字幕文件 {subtitle} 保存失败, {e}") break else: @@ -854,7 +1037,7 @@ class LexiAnnot(_PluginBase): else: logger.warn(f"未能在{path}中找到可提取的英文字幕") if not ret_message: - ret_message= f"未能在{path}中找到可提取的英文字幕" + ret_message = f"未能在{path}中找到可提取的英文字幕" logger.info(f"✅ Finished: {path}") if self._send_notify: self.post_message(title=f"【{self.plugin_name}】", @@ -863,37 +1046,73 @@ class LexiAnnot(_PluginBase): @cached(maxsize=1000, ttl=1800) def __load_lexicon_version(self) -> Optional[str]: - logger.info(f"正在检查远程词库版本...") + logger.info(f"正在检查远程词典文件版本...") url = f'{self._lexicon_repo}master/version' version = RequestUtils().get(url, headers=settings.REPO_GITHUB_HEADERS()) if version is None: return None - return version + return version.strip() - def __load_lexicon(self): - url = f'{self._lexicon_repo}master/cefr.json' - res = RequestUtils().get_res(url, headers=settings.REPO_GITHUB_HEADERS()) - if res: - self._cefr_lexicon = res.json() - url = f'{self._lexicon_repo}master/coca20k.json' - res = RequestUtils().get_res(url, headers=settings.REPO_GITHUB_HEADERS()) - if res: - self._coca2k_lexicon = res.json() - url = f'{self._lexicon_repo}master/swear_words.json' - res = RequestUtils().get_res(url, headers=settings.REPO_GITHUB_HEADERS()) - if res: - self._swear_words = res.json() - self._lexicon_version = self.__load_lexicon_version() - self.save_data("cefr_lexicon", self._cefr_lexicon) - self.save_data("coca2k_lexicon", self._coca2k_lexicon) - self.save_data("swear_words", self._swear_words) - self.save_data("lexicon_version", self._lexicon_version) + def __load_lexicon_from_local(self) -> Optional[Dict[str, Any]]: + data_path = self.get_data_path() + lexicon = {} + try: + lexicon_path = data_path / 'lexicon.json' + with open(lexicon_path, 'r', encoding='utf-8') as f: + lexicon = json.load(f) + except Exception as e: + logger.debug(f"词典文件读取失败: {e}") + lexicon_files = ('cefr', 'coca20k', 'swear_words', 'examinations') + if any(file not in lexicon for file in lexicon_files): + return None + return lexicon + + def __retrieve_lexicon_online(self, version: str) -> Optional[Dict[str, Any]]: + logger.info('开始下载词典文件...') + lexicon_files = ['cefr', 'coca20k', 'swear_words', 'examinations'] + lexicon = {} + for file in lexicon_files: + url = f'{self._lexicon_repo}master/{file}.json' + res = RequestUtils().get_res(url, headers=settings.REPO_GITHUB_HEADERS()) + if res.status_code == 200: + lexicon[file] = res.json() + if any(file not in lexicon for file in lexicon_files): + return None + logger.info(f"词典文件 (v{version}) 下载完成") + data_path = self.get_data_path() + lexicon['version'] = version + try: + lexicon_path = data_path / 'lexicon.json' + with open(lexicon_path, 'w', encoding='utf-8') as f: + json.dump(lexicon, f, ensure_ascii=False, indent=2) + except Exception as e: + logger.warn(f"词典文件保存失败: {e}") + return lexicon + + def __load_data(self): + """ + 测试插件数据加载 + """ + try: + nlp = spacy.load(self._spacy_model) + except OSError: + nlp = LexiAnnot.__load_spacy_model(self._spacy_model) + lexicon = self.__load_lexicon_from_local() + latest = self.__load_lexicon_version() or '0.0.0' + if not lexicon or StringUtils.compare_version(lexicon.get('version'), '<', latest): + lexicon = self.__retrieve_lexicon_online(latest) + + if not (nlp and lexicon): + self._loaded = False + logger.warn(f"插件数据加载失败") + else: + self._loaded = True + logger.info(f"当前词典文件版本: {lexicon.get('version')}") @staticmethod def __load_spacy_model(model_name: str): try: - import spacy - result = subprocess.run( + subprocess.run( [sys.executable, "-m", "spacy", "download", model_name], capture_output=True, text=True, @@ -912,7 +1131,6 @@ class LexiAnnot(_PluginBase): logger.error(f"下载或加载 spaCy 模型时发生意外错误:{e}") return None - @eventmanager.register(EventType.TransferComplete) def check_media(self, event: Event): if not self._enabled or not self._when_file_trans: @@ -946,17 +1164,20 @@ class LexiAnnot(_PluginBase): word = word.lower().strip("-*'") return lexicon.get(word) + @staticmethod + def query_examinations(word: str, lexicon: Dict[str, Any]) -> Dict[str, Any]: + res = {} + for examination, exam_lexicon in lexicon.items(): + if word in exam_lexicon: + res[examination] = exam_lexicon[word] + return res + @staticmethod def convert_pos_to_spacy(pos: str): """ - 将给定的词性列表转换为spaCy库中使用的词性标签。 - - Args: - pos: 一个字符串形式词性。 - - Returns: - 一个包含对应spaCy词性标签的列表。对于无法直接映射的词性, - 将返回None。 + 将给定的词性列表转换为 spaCy 库中使用的词性标签 + :param pos: 字符串形式词性 + :returns: 一个包含对应spaCy词性标签的列表。对于无法直接映射的词性,将返回None """ spacy_pos_map = { 'noun': 'NOUN', @@ -1016,9 +1237,9 @@ class LexiAnnot(_PluginBase): @staticmethod def replace_by_plaintext_positions(line: SSAEvent, replacements: List[dict]): """ - 替换 line.text 中的内容,使用 replacements 中的 plaintext 位置信息。 - replacement - {'start': int, 'end': int, 'old_text': str, 'new_text': str} + 使用 replacements 中的 plaintext 位置信息, 替换 line.text 中的内容。 + :param line: SSAEvent line + :param replacements: [{'start': int, 'end': int, 'old_text': str, 'new_text': str}, ...] """ text = line.text tag_pattern = re.compile(r"{.*?}") # 匹配 {xxx} 格式控制符 @@ -1052,7 +1273,7 @@ class LexiAnnot(_PluginBase): end = mapping.get(r["end"] - 1) if start is None or end is None: continue - end += 1 # 因为 Python 切片不包含结束索引 + end += 1 new_text = new_text[:start] + r["new_text"] + new_text[end:] line.text = new_text @@ -1104,15 +1325,11 @@ class LexiAnnot(_PluginBase): def select_main_style_weighted(language_analysis: Dict[str, Any], known_language: str, weights=None): """ - 根据语言分析结果和已知的字幕语言,使用加权评分选择主要样式。 - - Args: - language_analysis (dict): `analyze_ass_language` 函数的输出结果。 - known_language (str): 已知的字幕语言代码. - weights (dict): 各个维度的权重,权重之和应为 1. - - Returns: - str or None: 主要字幕的样式名称,如果没有匹配的样式则返回 None。 + 根据语言分析结果和已知的字幕语言,使用加权评分选择主要样式 + :params language_analysis: `analyze_ass_language` 函数的输出结果 + :params known_language: 已知的字幕语言代码 + :params weights: 各个维度的权重,权重之和应为 1 + :returns: 主要字幕的样式名称,如果没有匹配的样式则返回 None """ if weights is None: weights = {'times': 0.5, 'text_size': 0.4, 'duration': 0.1} @@ -1156,7 +1373,7 @@ class LexiAnnot(_PluginBase): play_res_y = int(ass.info.get('PlayResY')) play_res_x = int(ass.info.get('PlayResX')) # 创建一个新样式 - fs = play_res_y // 16*font_scaling + fs = play_res_y // 16 * font_scaling new_style = pysubs2.SSAStyle() new_style.name = 'Annotation EN' new_style.fontname = 'Times New Roman' @@ -1212,12 +1429,13 @@ class LexiAnnot(_PluginBase): cefr_style.bold = True cefr_style.italic = False cefr_style.primarycolor = pysubs2.Color(self._accent_color_rgb[0], - self._accent_color_rgb[1], - self._accent_color_rgb[2], - self._color_alpha) + self._accent_color_rgb[1], + self._accent_color_rgb[2], + self._color_alpha) cefr_style.outline = 1 cefr_style.shadow = 0 ass.styles['Annotation CEFR'] = cefr_style + ass.styles['Annotation EXAM'] = cefr_style return ass @staticmethod @@ -1233,7 +1451,7 @@ class LexiAnnot(_PluginBase): @staticmethod def __extract_subtitle(video_path: str, subtitle_stream_index: str, - ffmpeg_path: str='ffmpeg', + ffmpeg_path: str = 'ffmpeg', sub_format='ass') -> Optional[str]: if sub_format not in ['srt', 'ass']: raise ValueError('Invalid subtitle format') @@ -1258,15 +1476,15 @@ class LexiAnnot(_PluginBase): @staticmethod def __extract_subtitles_by_lang(video_path: str, lang: str = 'en', ffmpeg: str = 'ffmpeg') -> Optional[List[Dict]]: - """提取视频文件中的内嵌英文字幕,使用 MediaInfo 查找字幕流。""" + """ + 提取视频文件中的内嵌英文字幕,使用 MediaInfo 查找字幕流。 + """ supported_codec = ['S_TEXT/UTF8', 'S_TEXT/ASS'] subtitles = [] try: media_info: pymediainfo.MediaInfo = pymediainfo.MediaInfo.parse(video_path) for track in media_info.tracks: if track.track_type == 'Text' and track.language == lang and track.codec_id in supported_codec: - if track.title and 'SDH' in track.title: - continue subtitle_stream_index = track.stream_identifier # MediaInfo 的 stream_id 从 1 开始,ffmpeg 从 0 开始 subtitle = LexiAnnot.__extract_subtitle(video_path, subtitle_stream_index, ffmpeg) if subtitle: @@ -1283,7 +1501,7 @@ class LexiAnnot(_PluginBase): return None except subprocess.CalledProcessError as e: logger.error(f"错误:提取字幕失败。\n错误信息:{e}") - logger.error(f"FFmpeg 输出 (stderr):\n{e.stderr.decode('utf-8', errors='ignore')}") + logger.error(f"FFmpeg 输出 (stderr):\n{e.stderr}") return None except Exception as e: logger.error(f"使用 MediaInfo 提取字幕时发生错误:{e}") @@ -1300,8 +1518,8 @@ class LexiAnnot(_PluginBase): venv.create(venv_dir, with_pip=True, symlinks=True, clear=True) logger.info(f"虚拟环境创建成功: {venv_dir}") SystemUtils.execute_with_subprocess([python_path, "-m", "pip", "install", 'google-genai']) - except subprocess.CalledProcessError: - logger.warn(f"虚拟环境创建失败") + except subprocess.CalledProcessError as e: + logger.warn(f"虚拟环境创建失败: {e}") shutil.rmtree(venv_dir) return False self._venv_python = python_path @@ -1357,12 +1575,26 @@ class LexiAnnot(_PluginBase): logger.warning(f"Failed to reconstruct tasks: {str(e)}") return tasks - def __process_by_ai(self, lines_to_process: List[Dict[str, Any]], cefr_lexicon, swear_words, coca20k_lexicon): - simple_vocabulary = list(filter(lambda x:x= self._context_window or (len(task_bulk) and i == len(lines_to_process)): logger.info(f"processing dialogues: " - f"{LexiAnnot.format_duration(lines_to_process[task_bulk[0].index]['time_code'][0])} -> " - f"{LexiAnnot.format_duration(lines_to_process[i - 1]['time_code'][1])}") + f"{LexiAnnot.format_duration(lines_to_process[task_bulk[0].index]['time_code'][0])} -> " + f"{LexiAnnot.format_duration(lines_to_process[i - 1]['time_code'][1])}") answer: Optional[List[VocabularyTranslationTask]] = self.__query_gemini(task_bulk, VocabularyTranslationTask, self._gemini_apikey, @@ -1476,8 +1725,8 @@ class LexiAnnot(_PluginBase): end_index = min(len(translation_tasks), i + self._context_window + 1) task_bulk: List[DialogueTranslationTask] = translation_tasks[start_index:end_index] logger.info(f"processing dialogues: " - f"{LexiAnnot.format_duration(lines_to_process[i]['time_code'][0])} -> " - f"{LexiAnnot.format_duration(lines_to_process[min(len(translation_tasks), i + self._context_window)-1]['time_code'][1])}") + f"{LexiAnnot.format_duration(lines_to_process[i]['time_code'][0])} -> " + f"{LexiAnnot.format_duration(lines_to_process[min(len(translation_tasks), i + self._context_window) - 1]['time_code'][1])}") answer: List[DialogueTranslationTask] = self.__query_gemini(task_bulk, DialogueTranslationTask, self._gemini_apikey, @@ -1486,7 +1735,7 @@ class LexiAnnot(_PluginBase): model_temperature) time.sleep(self._request_interval) for answer_line in answer: - if answer_line.index not in range(i, i+self._context_window): + if answer_line.index not in range(i, i + self._context_window): continue filtered_raw = [x for x in lines_to_process if x.get('index') == answer_line.index] if not len(filtered_raw): @@ -1502,16 +1751,18 @@ class LexiAnnot(_PluginBase): i += self._context_window return lines_to_process - def process_subtitles(self, ass_file: SSAFile) -> Optional[SSAFile]: + def process_subtitles(self, ass_file: SSAFile, + cefr_lexicon: Dict[str, Any], + coca20k_lexicon: Dict[str, Any], + exams_lexicon: Dict[str, Any], + swear_words: List[str], + nlp: spacy.Language) -> Optional[SSAFile]: """ 处理字幕内容,标记词汇并添加翻译。 """ lang = 'en' - cefr_lexicon = self._cefr_lexicon - swear_words = self._swear_words - coca20k_lexicon = self._coca2k_lexicon abgr_str = (f'&H{self._color_alpha:02x}{self._accent_color_rgb[2]:02x}' - f'{self._accent_color_rgb[1]:02x}{self._accent_color_rgb[0]:02x}&') #&H00FFFFFF& + f'{self._accent_color_rgb[1]:02x}{self._accent_color_rgb[0]:02x}&') # &H00FFFFFF& pos_map = { 'NOUN': 'n.', 'AUX': 'aux.', @@ -1540,7 +1791,8 @@ class LexiAnnot(_PluginBase): lines_to_process.append(line_data) main_dialogue[index] = dialogue index += 1 - lines_to_process = self.__process_by_ai(lines_to_process, cefr_lexicon, swear_words, coca20k_lexicon) + lines_to_process = self.__process_by_ai(lines_to_process, cefr_lexicon, coca20k_lexicon, exams_lexicon, + swear_words, nlp) # 在原字幕添加标注 main_style_fs = ass_file.styles[main_style].fontsize @@ -1560,12 +1812,13 @@ class LexiAnnot(_PluginBase): dialogue.start = main_dialogue[line_data['index']].start dialogue.end = main_dialogue[line_data['index']].end dialogue.style = 'Annotation EN' - cefr_text = f" {{\\rAnnotation CEFR}}{replacement['cefr']}{{\\r}}" if replacement[ - 'cefr'] else "" + cefr_text = f" {{\\rAnnotation CEFR}}{replacement['cefr']}{{\\r}}" \ + if replacement['cefr'] else "" + exam_text = f" {{\\rAnnotation EXAM}}{' '.join(replacement['exam_tags'])}{{\\r}}" \ + if replacement['exam_tags'] else "" __N = r'\N' - phone_text = f"{__N}{{\\rAnnotation PHONE}}/{replacement['phonetics']}/{{\\r}}" if replacement[ - 'phonetics'] and self._show_phonetics else "" - annot_text = f"{replacement['lemma']} {{\\rAnnotation POS}}{pos_map[replacement['pos']]}{{\\r}} {{\\rAnnotation ZH}}{replacement['Chinese']}{{\\r}}{cefr_text}{phone_text}" + phone_text = f"{__N}{{\\rAnnotation PHONE}}/{replacement['phonetics']}/{{\\r}}" if replacement['phonetics'] and self._show_phonetics else "" + annot_text = f"{replacement['lemma']} {{\\rAnnotation POS}}{pos_map[replacement['pos']]}{{\\r}} {{\\rAnnotation ZH}}{replacement['Chinese']}{{\\r}}{cefr_text}{exam_text}{phone_text}" dialogue.text = annot_text ass_file.append(dialogue) if self._show_vocabulary_detail and replacement['pos_defs']: @@ -1588,4 +1841,3 @@ class LexiAnnot(_PluginBase): chinese = chinese[:-1] main_dialogue[line_data['index']].text = main_dialogue[line_data['index']].text + f"\\N{chinese}" return ass_file - diff --git a/plugins.v2/lexiannot/requirements.txt b/plugins.v2/lexiannot/requirements.txt index 88f3dde..2e0d417 100644 --- a/plugins.v2/lexiannot/requirements.txt +++ b/plugins.v2/lexiannot/requirements.txt @@ -1,3 +1,5 @@ pysubs2~=1.8.0 langdetect~=1.0.9 -pymediainfo~=7.0.1 \ No newline at end of file +pymediainfo~=7.0.1 +thinc==8.3.4 +spacy==3.8.7 \ No newline at end of file