zf-RX(#Gl$0zt_NsdYu_e&9Wuh=+7wjA{Z+9B;?7SwI%9BGAnmS
zS+qRcd!(SwoH^eh6>v$EAQOU1{9X;8hO(Af`=e%kNeuNq9l3J>{lYn0%ZO|(G&X9C
zh=$Jubs1gQ-rZ^7?EzzZ{g
z&qchbk9$JaSX|Fpi-QZPYM-ss(R~7y>MXb>o^?;0`_07B;fZHIn0WWxwb!0u%Wd+N
z;mH@?op}GH$(LTZ`iGO(-aF57PriJ1^2m?wZSCZ{4%jO@np?KlS8i?X?0(|fZ_Zyk
ze~RU~@$3uN{_yU^(WgvS=ZCJnJ9Mr8C#;UTmLSSvlUI!}9)Gv4B6vl1jB|2r?7{TFUWN1^
zQjC1Egp`wr0x?p{vc-;&`yN(_w3G
zZ^c|_u{GHb+8wrz2fH1u?e+&d4%#1UZ)&DlQnCM_kc=vN64{(!Gp8chb{5j@4G6wE
z#QEbBkM=&_>rXHrOM5BJpOSv8_h-GA3#>zT4{aZ=_7yDeuYP&kmntqXV@k~#O-FkV
z_j)v$efD7F%a|EYzOn03@oTwN8Hx)Ts;bJEfV!otb8qXumdMe?SaAyc-TGe`ujeo;
z9HBYm1QD0UN{Edq#kP~Gztz{v+Qa!O0n==f^M%O0;-AO=TeMM
zb}CMAe9G&JGpSNbXoW_eT?ggXwC+`iPV~J#@%B$Aj=VY@fr)tLKR@W3c=6Qa$-_4e
zoxlFafr)pI0P$V@@bzo29RJS`4hxwmUw2v+P(IQ{Y{mXA0b#ctYfZBsOX)zDz%wqQ
z`Qc`}Z5nQ(ek{V@ts(@k$hKf@6Mou*`OzzL$_~pP=U$Z^lgYRvIwg0I`?cbLOrW$E66i7QWUbJh1R8Z3JGuG8DTX2{^jaS5{SYUBywcM)4(`{4bF;em+{
zpS}LeABmW|eBuu;O&oq9obRPS0$pGIaA@*JXRnUD|DPYc)?NNx>H*5Xaqg*lmtLOt)k2@{WfWHw5Cb;yZzUP{94nANIY|VTq
zDVvgF4+voNq_lv-Zg02hXKhNbQW;%yx1+12tD~dUArRPvc@$JqK@&>{Pm2rv(>>J$4H52lXk^IVR%fB41^{f5LZ)LhyoSzqks
z_(UJg5(H!MD=!=3k8U}<#go3r^8?Lt)TslzaH>XG5QnLqpys4#r>7J5xtY@IdWp&^0OIhYm&-UjOp6WT?<0)M=vdfpV
z&YzigYV+~Ut|x~DU*<}GR{p8RjBS#D$o4&qq&~^nlV#tpYjFGExbAxPzyFkx6nCl
zxe`LAb#_aQkhpwp1lfqjJn#vv++nUQ#3oS9;`Ns7MOm*bjJ%w(FwwCam@FWFM$;>I
z%AK;NQ28)Pm`j%66-<(w7ro`S5Mq`30{&kqAx9z6DQimzKapa*>Wo^-BcpeUf^6H8
zq}<^<9}_O+lo2cAAS}bK0#3LL1Wt5{T~39Rw^#Wc-&DiibTO}WDj&!4o26fb6K7n!
zPHKz24KXA$E{Vjn$nWQPeXrt4Mg45=O{i(c#T%ST2O%nUh2N}=@Yam$dyG>^cK#k^
z;-okI9%bUCG8lK`J3+=p#yuT`!~xj>PGmN%iQPoNuD|&EiKDNE@cnlon}I~a+s!SI
zvzvgun>w32Y%P(Hp;>Rj->uaMh;c{%BcBK3ZL}h1T)d2zORNc`7eyVz+(Id`S>+66
z3d<=j6R2)GFn5X==K&S3OH3uq1GDQ;@nqV-TjKQOa$kx=D5iBK2qFoLY5!6(Jz^
zis4pY#yXFAov;oM1L~S);XrFABOVQ)7Fxj;Y@nMaZdA}t_VrIZe<~0Y6sCH#MCf=6
zNL_a!$^?_eVYvRgXD5&S4y1JQ*Kbaobl-UHh3jWusi>%^>n44Km}lax_pbl;7ZHRn
zACIi+fXYUilYoxhnj8lqK!oWqk09_V|un6zPcq&v=
zu!4e>6wnxeUjp3|si4Y%`CtoZYoBPbF@+2WGHB&e%9hXsge)A4fW5GZ6{k)GK+$Oa
zK&nx(Aq^<0aiNxS$WWu${|@^;J2C4Zgc2!?n?9aBX|oP>6$;ubFjX*`Q_5^@;$>6%
zv9$why{3gO{_RJH9z~?D=C+zMXACa(pU6D
z#|$g{rj))dUtNt){ep`{^QjqwRVUPan=Z$vNOf+y6hCjcY&6Zga5L4V8PJRyEncI=
zle=-uxXGWAF`hEdn=;RrQu!BSWkmghYy3GSmkUbV32)v#Ua;6(u-KoSck0pOkDlr}
z-sRrw%U*KF@4TY7%ZAF{t{kcyF7@Tz<DA(*hjCjd_RFzQO#`G$k%BZ9_LiKq+
zcf=7wy)oUSjt#DLQ4b@oW^sv6o_v3z59@v|*`=FM`?d2&uYdTQ#Rde;V2LUZRno3IsW!Zr#rDPUZ!lHr9N_#IFZ
zf`SU7-DcY#T%*GM^dJW8u&raiL)cBlet>{2QCguQw<_#HT2E%gy1WAuv`{H00x+y8
znS&4fHO1O@_mo@{n|(PY``A+hPkB?8xXouXPG=y}uM94YW3dCVt{8XBaPDcntJkx*
z-jm%hX55Wc@-zKSEtgvQ)omST&iaB=#%B9X>4T5DtB!YFGR^aw(>^z5P$jwn-Qa>(
zW2dyp@r|80qW&s*Rf_yVO7VJ`>LX5u5Gd@i_JDdnNL`0LpvT>AYa*4hy(Prfp&$t;
zY=*Z3xX)>cwZu$B;>;^LxpT_Sga{tf4-uN1aY+o#^IBfPE87(v%3dYR0}9MNRfoD)
zMdksgl2`X>p~Z-S7DL5r&<9Di9Z_4Sj$3?JtRF@O>bz$_*>)opXIeYAcVyGn8*
zyRdqzdkG>^Ld3l-H{wSy%E#l~ITF<*(j
znkO}3<}06@?cJXGmUlbAg|LXJdo7xsJpA_cp(8MrOrHA1^|NnGocrDN4_}@*@$;Hy
zNAm_uUE8ntgNIZ9l8iHF;0;5W+Eq8&oM=ah=gPec|@{tn$_*i9S`%(YkEo|5XWQPHgFJ*
zt|oqOm~oSGK8d;+>H&QpQZm*of@@TOouU4N8Pe`YkC~D*U1wozF9AuYx
z+r!=ag!_;d&;iRdx3@fE>o_RvrG)r!LIrhL*hl3VZf0zkd_R;@Od*1d!X7H3Xt#9+
z)S_xA5W~0H_jf^wMd+KcTEb3>)l)#KTdR(7S`po(7iW!&ZFS*iK+f+K?xA!-?{>m+
z46{?PPE<%NAgDH!})!6V}_+*w9KjFrXsJY$Y(0)
ztNFjxTADjH56ePAqMXWx3Mv2BO9dD1I>Yadzon*)8@#tdt(n3ATF!P1>vdSbaZ
zKHqOlJ{C6+_ZOpOO2HWmzPfGVjA>tRG1^3_2FA*j`?D;5OVQ<=JlBE~k5A{iz(wg9
z7o`FhWnf%XJj(xbDsk3kzOfeoIzL`tP_5!VR%vSz6d%W}sWB)%F{lv#BtcPQ<~}j!
z)GSg2bdKhS+ii?f77n6NK-cm}cju!`_SPPlJOvxnMPR=ZTK9E!2_RCigtoRYN)^OG
zD8g|e&3Pwc&*ej3sXC-^Dh*t($|;YA8-;A(Okx>kTy0Tk6c66$j6xFKVCq%!vR*a*
zVt8dQ45PhT{OR^_y?RC;gMw*f#S(_^RRh0kBcF)z&~u_P(R!u7vkb3t&d|*}W1{NJ
z)s&BqnZ^soL{qqgdSP%HYPh4ZEwCoE$oJrVdSjijypnVx1M(wUCD$8=l<(eC4eNo{
z83%hoNU1|SXH=RkbA;45(P(p6RTIqw&FgqQSrYcegjH8vJ8^HGFn-0KQw
zVuU&;QKIB$;@?q-uLBq-*f)IdnvIcj1#>z^Fk)`y&j1mAN)SOiYR0?FndhMLpwb!d
zOrUu*=a`rx-pVAsRj+xL_t4+jFYt&o=M$V}go&@Kq&m<~Q?${BoCa);aWFY!S?@x;
zP`GZm354vZZN=eqDJH?9H_4fV@wI;M-kP1U=xx&U-pmXBfm10KQrhUKS4-WyW<^(IHJnNQs(iyX^n
zu$RWB2QyuY_onb^Yy{Jt$$&|QGX-Jh>oL8lvp|)s9WyRIi`9_rOr3#sOl_4jvf?M7
z6KXpR@R)yRjyW+xx?_=4!m&h(In$i!64j7u$4q;S;~oT#@6Dj_`TX8YXa|-_W%}|V
z=U5=;%rZ}6tY!T^m<6rfn^Z39ZemCW=LP8=3jeyDLP-w
z=D>$eZE%ig59iP2QU?g-9JRD4TG5X^P@uB8oYQM@<~T@ZW0%w7SQm_Pj`g8fjTGA(
z;--WIN0pT7v`AwK%$1kU@g+1CHL7_2%|ctI=oC>{Qc=
zQO=wN9=U8}bI+7YQa@&?zU^+Qf8o0`lP{a44#p+T@{HAgIG-;+8A*{;_9vd^oVprgcE9{cpBM}44}$YN
z?*N(Q>Li#$&+$6uu^OC+x{YMM8P~VsmD%5J#p{ZQIhZZYK?ezy>~e!E<#tc
zru%b%L??;RqSxKzvA5w|F>&-wxZmA4^cuY5CXfCM{&JJAo}2v5EAX`tJyn9@o#>ze
zYtTgh5txNUpS;Oehf(+rxi8ev_2+&y@w|KDt!Ln32j%j_TS38zUP3
zCg1ND`#|<4)(z3LgzCi%S3h_S8K7^TJobx;5071ccX;9tuY?+^VRfR{bb^;=YmiWeG&VHEj_0Cjoa_FRBzw9ds|(-
zWy7xR+bj6H$q_@GIWDkX2Sr0SeQeR1>hIQkEZDB
zPs8(c;^#l5smM&9*Z**4@`X3xfV8=O`*bH!ngR?iM9qQo?YFrY0aK!LZ7mTsN7W
zc?0IB!PaT-hW@14-qPBNp;xxq;d8FyyF2#Vg%?o&e+fL7sR9u^qmPaDzE$vc=}@VA
z=g97{ylPM01D?hQ5Hj$5BQLk~$P4W~v774ZYj-tRHq|w3w>;FNc*s)HqqAD>soJ``
zw%$@AEJT&e5Cq7ub&!k%%e9wJL1_uliqi-RN?Hog61Bje%|2~bkqEp9f468ZN4T+R
z!Pdcv%_$>dA9Q4cxE|riChBh$LJ=~+9kmOVl3)W=r{vEjP`y3n-(?a>esBL5N{F_1
z(Vxw-)w_Jlu*sF|R{SCZ(V$0Le4fG_1n8UI+}%pffU~6U_EG>o+0?IhtJ)3
z?r3BO8UR_M?V|ephlmAY#TNJ8c^IH(L^J;NJiU4^O7Ejv~ww7)OoEG-lKoQ6Xu$R*1o%@BS
z5fL2hS6vl3G3-A`eiS0XP&>K^#R`wpb5%<_wDSQ~^Zxzq2jNMGT`bs@(gJML1z(cw
zlqH5N9l*>C@bH1??C!vx7BsBrY26PpN;_SksX&XVtVVc3cG!jIDS@f_e@d|<^hk|X
zY@NL5aRGN~=KHvZ9`B&X8lkJb{o&@8M^|ml4Y@
z{G3vZaKl8Q4glZ@=G79=OAP|P0RvNnKho8X1!xDQ6DbziNnWPXF<8;9EjD{V)*4W>
z@=pYmJgj8Q%n^`18jw96FxVe~6L4^G1Y`nR!S(_amRPqr?m@dq+;l=Y%`;{CqgPO`
zJpsDouV5W9a)vCAzQA8l=F)o%Sy%M2N0&dpJZOLzH)MJZnVzhbqop20=9pod-(ol(J2(&AMVri7>4AlhTeoFz~=jd-^s+
zS~jw3N83gp^knQBGt|Qt6Ki6wD_Qf0(}xWsRi2DBFq!x>a)VBoeOo^(U+zm=aeAw(
zelUNq`9zU>Yu{#1+KPxO2OC_au1wFob))H{22TcTE_J9lJ@Zuh@pN?gW#QQ41CO5+
zPIVvecG=v!higX`dW>sen!lw|q{n@!=Hg9<`Je8cis52YU`|Od7*8wnrj?DSE%c@>
z^rbEC+x%I@a$k1c={A>rqTsc_oDcb2V@A4NdyPTfo$*%OJ&qu=vxwkoGLgGyWXNG|&
z!Y9YI*sXIpJ&PXj
z)0d2=uk@y`^rf%v+j2QO*Hz}ruISqy0XTnRa(_>MyC-k$XuN0b4$qD~9^(&gE99|p
zQ#vj+e>|mhETyzx;m@yd+r9aV#`9Nr^H+Rk-hE3UFG#$Wm^6_8QsI;eo&Q3^nG5{p
z)MFb5HXf@RsB<;AOWm2n_l>lS?Dnkh^yGJqnfLoER*d9(E7pux)OaguK1+Q7)l??;
zZ#lMoVEY?YF1u^PC3D$SJeOKFmCC^p&U)NBvTA%)-KAA^zJl%ERdvJFuE*Rax5~Zq
zjYiL^I&Z;tU;2)|E#x$};`j;|@4Dwq%W&EF!dmabT3^KmZ{Y@C#@&5e{TU_hbhlx+
zdPG0mJG%Lz^J1sx!9AX|AM|aGfW_dwu142Z&-@LeJ)`ZOjQTM{113>Q-gvUrn{0Jk
zeaVaa?)E3=jwcs;lZ(fbE4;}SzU29RcV8`-hh~dMmia2G|5{K3KdOG&z+L?t2CJv!
zOA_)fXIOlett0yJoKpp8OIeYycHW$o{R}wuyC+>O3M`$yABLB`U?tOdxtjp
zOUv9_PgnZqRk)w>&Rcs+t4d49lqy(wlM2C1Id9ce3YU;`n=>RNPGxfDyqhI+PU^3}
zs8Vt1E5H6CnakNO`#NB0`1*@=GOlok?5o=)Tx#Aet}G$%N=hoN^ugwVgRYuODJA~Y
z5_gq1b)F}+1YodMo;92{oQb=wQk10sy=3W-(j{{(z>>+z{vds{>OU0!(J)qjujlUj
z##Y?_mcmu_rrPCjD_jP5_a)0>Pt!x*%!fWJS^70_MoIdh;U~FMddg3>Pn1#4iNC2v1I^tiiu=wM`3`BoU4(~7AV=~6HL->;|cl>y@a>kFq01NznN
zOlHG2Y7>L#2u@Qk$49O%2}OG{s-l{-3o86em;e5ee|h9ByL;hV2S%&NRWM}aM!V5x
z<3^8plRtmK<=g_-4}7_c36o+{0h403k#k`#y7bSR1#`}=Z|r{nY5ZeV@x2AyM}>x+
zWy+5htXJa4Crh+D=PN&1t3>#zLXDJ9wc4Fal%JZE6sA-ek@RnIRf}=^v!W^=w|_5+
z-MLcp?~B$K;>Ukat18*KR{lR^RTlj6H*!w)EZ<)ulx%
z>gVZv<<*7wF`ht;ji;#acsx@>@d9n5PBA`jeQKi$!h#Av0y;%wEcn#o#>I*jl7plR
zBwln9`w9`}A|`KxQ^d>*j)_s#jy&7f>y(8hdMF9y(ai9YimzAUR0t}kf@iygA^$6x
zOBBo*;ssUVVz@1Scb7?KNaxj11CpMCUCxl1`bC;aH~AX=
z<4`}eRugah{Q4iCop}DVsO
zUOW$34Li7+D*?rj4k`+3R$sfdwz?sxI%=w`+EzPPZl+nr{-?2dT
z_PY9pT~$yHuopwA;vKs-ZL8XKfAL(cvAtKKCnyt)LvXir8!R&pTJFvoInD4GZ@YQAV%a&7R%xzm_wFi5MUGglc^<-`M
zj~36a`v10^>?AZly=*o2zHBx3fwpRe;)1HQYO&(NVin@k+@MJz
zLHOX-g9vfj1U8>y?IB_26<+DR3g##iiA92$Lu*`#9LhPdfXb<+*E+5TphF8EnNEvRk6-JI|jxAEFz;97qs>9Fg
zxmGgO#?)|oU;ydWhMiSmq*Kw*yc5K*(RMdU_4Mkdl~aG`a(cAFHu3_?24gT=XnGA!
zz0<&JPs(A0)vZP^j_iP$H#(eB!Z4F!yv`|$fVZZNIyB>w`Yyd69B_lP1W<$X?|&7p
z`P@_g#X2MxRT!tzrOt!m%!BhtbV!gR<%|pauw)Tq6LO<~i*V>|VZ71w#y%MvL1W^&
z$@~<;X`}%<`^#(Rf5Oyg&xjjY=k$m@a`lfVCZ7G>)$^~4lj5hfbc>QI(hhy6MZJukAz}|=Q0@FP)Vni!}>A6I;-6s0^9tA{)uxG&`wC)#GcS_n`%XD7W
zxCs4LGi8350`hVdYxYrDy-2c}NNtDxyKG1T3Zd&jK!br{gAFCHG}yvtRQetScA|yT
zM?-X$O=YA^9FmYGl!m=0e9Sl
zKJ}Ec04}T3G(J=Etk^6+B#eyX87H#()j?O+L5TKa#xj3e&Z(T^Ili>gel;ANbMjqF
zPqg>zKTFAr&>VR3*NwLI*NvHX`ZKboinxRnQOyz7aTG$c)35$Kqo}|7Dx6~%xgHx@
zdg6!UIrF_a^L;rB`!`;;c=e$yp{z%%cA~G{;~@9W4~JJGP!oXkv#0^
z-wa7Ax71%W|0V>wWQgm_FPRG<|7I3XC36W$v@43_UQfhmCzbT$Q)6E3LdB;G6%=2h-B70ZbWO>I
zBE_GIRER?*&-{7Cc@=#-$%C-?!JZ|H#wA4CN+MAO?7$5=62Kux5smswIVJi5_g^I(
zR^T|oTv@>jkPEI;6?D~92VFH|kQzOo=&C8@(;%NlAa^O^dS+a+ZO3wIBIJtDb_>|)
zlwt*-Y%(XKx6!x@>5Y1|PHnV9Cj_}u3rin(g?`zdN7?%+oQ&4@>fltuWTaj_V$4wk
zG+Zk_Z8Od2K7LAV&Bav+dz^Y6@Dt>`8eBmP=$=$#6q*mWVa=J)xn6kF=#Y!T34mLW
zW2C~h&(+_I+1~{mL~zcab+`tj=l|+72)_ySI_u7|j?nfRX&zB-S{b2Ip&a4T(VVX(
zh&m0A)?jSnoN;r)_7RM+C0wHvbH+K<;(1AJ(b~xII|9t@+MCnnt1DNdiee?
zrD`ZWz_zgC#Hx<{-Qu1l>@lQ6Pg?5~&nGN1Q;MaH>|Y3
zVLxC@Z0~Fq`9THD(lCzN*~WNgGyN^)!8TXe2Sq!so{X@;R}ihGN>tY@uyYL96?IQi{tv2*=0PBq
zx9x3)0;LK0yKQ6!@4~@go%@f>!CzW}V%6v)l
z`gDGM(zrh3l0L(4%7Wbwi_4tbSM5&$59&=R>D%Z}wYZXD9O&ERPs??cd($fWi1jq4
z59S|!YCOKs8(-*)FCLFC^TwBr#m~D^ROwk%=Pjxml6xBN>yPy#-zudsPn*gSjp
zd0Oqh72vj+wd=0od{6!ouX$;Z;U6~_c+CZ#!li!eBEPlVzi_p`e8qVAUEcD$eC2D=
z>7+s^^OJBmg4pRLzW60ma$UmRva3ZUZ+8xL4mXY}-fQv|)%I^5w7;}{s#XT*Pu(X2
zcs-i5ufOP)acNs&E=u3|)$NC5Txu@%*`f4|=I_i8$IVOrITcT>
zd}E)Fr7@!2n6A7aS5j!uZp=|$NLC{Jx0M+i3*;9Iw42LR7w1(i+FYdi_aYU31oV&|
zC0B)M+&bY_5|D4@fqw$G9@WY9du^k`;bCF#G;E`zV+{yJ&$y!T^}G^1vcf@qVwW@I
zP|D$lF&d~7>
z&?L&EZDE5%qKS}5G|+6t1SJwpP$JP{W1+e&8b_^-D2+FSo>1ddJTA&98f?did0mb=
z;@F0SkhIaO<26xhQ$*ATZ7S6ksskJSu;CzF2c!sl$q3CI&0Z9{(q&uMff^Z;5C*DKwziDnzy
zL_?g{jLT_oMjj@hZp)jI0Y5RrRc#@DJN#Ul;Y=2bw)%?0d8HU{#OhOG+kZ$q=~TAJ
zXO7;TDItzs6XMvvH8%5D(N2YUrqi9X=b&z8-h(|k2CuaAKnyQ9c3$oVNHduOMETRUN
z9WxMi)Md@XQCF~`D)9&c=KU^KCLTcmuAQk*sZ(OQ=+Sydc9Gw1I4ueqOn=IJC9TPf
zD~@27A465lDKWx#Fsx$z2R&u{_PVRE1Pif~UO&@fN>>yW0coZIB
zE|tOulwl7A)ua1dlOv#0{UQ_xZ8lNNw|XYVo}CN!#|M7x)>Lgw?wG!;F~4R
zIWAaT(Eoj!Ti^6Y0pgN>47>p@S2>MH!SbOJ}^Go6fi#8;wfD@PL7IC8!UUvJ{Di*&nX@3=+|G#$b>UhLeh9bfj6OG
zETPC<5Onc-d5>%FmE6Md+%?|ZH6uN~+|B)){T1`iw*9K@PPe)KyWuv6uEKtrHk5W@
znXk-tVcAIa#TL)~{G~eHZFk#-7yW9>=rV7a&6m3uHRYGSy?SW%pY^`^4S&{;nue=~
zmy9U>CF7#rJHNq~zq^0y-|-rvqm<}~EvE$;j`9~mhg)OiXY{A^{duW-Y;vf)L+zFD2L<={3X=Qo831%NpC_;&U-mU@njPoc|GZfWu7Lyd!{(=$`ilD1j
z#Fj!dBVDx~`MB*Eb->|XB@bT(m#6QW`pzJ4Q8r1X2;wmMQK3%TeSf=}vJcdH88YzE@H*B1*
z`%^|$1%6!AYEj~1q824CW~Ncf64k~v+KVe=kp5>m)%0h*YLhwU&qf8s%`8mOZjMv@
z*<#(SRs6eFh4?f(I=C;9-wq%`c644&M`=tF-FGqkUd}~IAMx-Z>&?+4Twsi3Wo%THeb=Sjm
zqBzd9#St~oTHxuvF5zHz0RS*D{F6|p#g0x6x+aFsFbF_Spl_Sezt}R@FQy
zWbDHGs6}*TUrsTm;2~lKFBF2Xcm|4r@KK+pyLu`Kvi#4;^RM=V4jP9n>v+~YZ`M3_>qxRMYhB-_{+8$K
zfHE@5v23-mVM=h9zhEAWR)qg$+R7{OsqpR=)}aqLi!AIeGff<&DaXXombU58&l#7r&>*UY7-;4I6LL2T7YGZsy-El#Fkj7O6vE<$`GPHOHH1wy
zgeJ8!211hpf=5*GHGH-g1dJRkW`*!*ge!u=VV3$LEqzI7X2Q-)LmCdaWoMa41~M&>
ziB?!2y=^{b79mtCK?wcVMxH$~3)>z|@Pl)SQyb|nLQWPWMDlS_1>X?*L!S88RWO!C
zJ(I*4aU}07y@_H#B7td|sv{w6x`1#JGUC8su@J_&=;Cb@!H)?i#FDei8QS&BC!8^b
z)gUkpn0xh4>LE_E`!peiaLlCZ96p5+#$(KpVWRH@cC3E8Y(g9@a?wU4W&mIU$OdL0
zn4@0EKPV&+Z41aOJ+VP=J`3CrvDuHr4spjHtNq4~l0RZDUQ
z^Ft)*qeN%1^eD?Iln=7eT~69~5Kybd7|#*+#1-D9Ho5
z{f|m|IvkND9$QDv+=G7D32Z_9&u$_SFbA`V3VVsU&xvr#h?b#*2*L^UOJwnlcKB
z8uMJs{$ivW^A_FIaK?k4j+6Rt2
z3Sl$y>BBWhF{wSKv8AOlaP3#K$hDQ2%IzbG7V;Ks0!)Yk|j8SoQa2#
zM(cMpqK#v^a2RPwI~!(B93i3_PK)OIz-w`+YtZwb9Y(5}ei*4$-%Zx`&>^7L&;EMi
zC_dUWmuw+yM2Vh4(rMM#*4M*V-a?Lmq9%yE7)eyPYw3Kt?l@8tpJ4&X5js#so%m4H
z{jrlw#fK0N$nr38^w`87-kW&og`ld7(jY>JT@C8Fg#Adg8rgnb(SvUV62x=Le?>8x
z*VI#o}Z$%WLa6=_j3B|J>Q0xGkcVy7waAqd1a@7)VA2s>1n
zQjF0VTBad7!-$MfilWnw$PB8?hz9N=Qj(1fL`u>j;?JhextfwgMWCd{p5j%XR9{qoyk#(MEOiGy
z&GBW@H0{JxI&I2|KOH|9OQrP3^(R>*xZw@OFYckD5BPJ+zs#9d^nWJh_3xRfxxhA`
zs0V50nB8u3o14C`F6-M;0xTKPp{`l#dH2<>Psj^6@fN4X6EhbqrEIQEHI#Nvx_SIp&i@
z1;vwDn5L~QRD6=Rrq-hP)S^Osn!-VaMj7J&6C(dr$9*``z^n%J7$gitBt%zrDP#^%
zD)72WG&kdlrhb4VBXg>N)`B$>5nvmALdplA8wGuR>>!K^!4E%ZyBDGA$u|$tF}F~8
z51yUq|E0*M&b{b+{uS(F7yw
z&EUGkT`)3j+GnQJDFyD|FfWo<)>N6HKGarO6c=)22&b)%kiKC(Uh3QR4fgMIp6nfl
zaHb6)9nOr4%-)dZBN?ISvSKv$3ESGH$)IXTo+0f7lRRmo4$YYvS2RaPoc<^afBh`1
zrQp?PG}9zcZLj=EIV4YZkB~fdqEV~Qb>sM3SebLLM)4ycd@;0+@uZkVZO_Ede%3BcBH|
zO58Oh15E61kqq$dsA#*oa9D4!W}x|~+Gwd2aTl5RH7W44*ohg|QZxR0M#`LA?u@(#
zm3MHt$`F@(C)rVj$d0;uDS!bt%j;)BMm}P`6fv1;G3qQ<1J|VX=Bw|@IO_H6mJ$+WvMRcw1{3X
zX_0y%OI1~*y^t3}DWw`pS){639dlv1g5s-LxK_KKEI=}ZR@n^#iB%3)Qbp@^#5dH5
zC-Wbs!Gia@?9-WO@ay8;RE^z9Z64$c;!}n
zvs54zDf^13@KcJ>sh7f5%8Bz@*cbi)aadrhLqEjxb`&r>2sDe>$3sMxoOm#1X%>i<
z3bfEf4^3@IJ16we6AuN1<%KZ{XlV-npg=}NOcXHv)O?CD%*L?Y3i`PUK_E8x4b>KW
zBo$vIk_qW3%?|w%k9HA^R2v2K()Poc5nnyS-IOa;8nCJfNryK14e5QGNJZf@WFD%$
ztyHP9rs6VG8)SoyTO8e|R$5evt{BOUZ;jWo<`##fn>8}MD%)K@#o;z$8gZOUzeQ0n
z
zSJ(dA>IR
zfoEO4cU8kJdNB2ntV*UzcP~7<`t<54j^d;B;@w}l2nT|gM_NV~jXZKL+q3v?Z{@}*
z1!eJX+x|Zu{PTmi*pI0V^5v>T>OF2!=MnW6Sl#(<$8h!OgYF7%!HOvbC9bKuMfWL(
zEK!x_N_;zWD07NKbhuy`C&vsw@m|F(`Z-m~ZIW%1-BgsQ(%kkb4!03G`4Y0IzqE2#
zG2Aec|K9zhO3(ZnZ)xom<@E2w!7I2=HORza$}7I9$WkTJFyS_Hn2>~%QKl$|zkI=P
z{;*@DX4Ev=GMaj>&bw@jXW7Q|EW8}zZkr#M`mj0${wtBg0ER8pR4PlDyF2@#tB$-K!vNi907i(e=W
zXxUdS==-d#|0gsi0j1E@g&lbd7B0g7fGNrcjRmqCF#Uv3PO%CEU{}g0PI?aUgP$7^
zyFu!N8^p&1@{gJ4lk0?@^k;oF`<$u^7Ad
z{AL&%tvG$eq&~D|%E)O_2UlE*DVUNgjfwqbQygyo{6fDa&!3zBMGSr+NlRyL=+X!8
zyQD3glB0{1I9x&F*-e^w4uxt{b@9@FYC^hm}&daZ8CNHwmStwuJ_=(BAd
z&8?kHO`<3zeKtHu*V!J>o{S*PzNdBcglA2?Bzif^|e9F#T|Z*#2h6BkipZ3uKoJ
z7}&?NE84sE;bcIOZ8lPV8dH&g%K3*y+M=;D`Qju}itQN`b
z8sP`Xga4fU90EvWGTG;x_H$16IT!yqXZoCr`<&B%&L#eh%lI3Y_dmJnajx3SRe#PI
z|HftgjZ4KRRAgCSs<-N7X*W3vzj(-;BTJluD~Zz3*Kr1}
zqZ^OO^2TJ1#pHaZiS@)4j%kXJY)U#-F;L;jUE@n!+ZRJmjJd92x7C}scsy@~H*dvA
et~YPBC-*K-+?u~=*8ZIp{R@hwamsY|YX2WtP5Q?G
literal 0
HcmV?d00001
diff --git a/utils/logger.py b/utils/logger.py
index d8e80ba..87fc32c 100644
--- a/utils/logger.py
+++ b/utils/logger.py
@@ -76,7 +76,11 @@ class CrossPlatformLog:
if key == "extra_output": # 跳过自己,避免递归
continue
value_repr = repr(value)
- if len(value_repr) > 200:
+ # 对于错误信息,增加截断长度限制,避免丢失重要信息
+ if key in ["error", "error_message", "sql", "params"]:
+ if len(value_repr) > 500:
+ value_repr = value_repr[:497] + "..."
+ elif len(value_repr) > 200:
value_repr = value_repr[:197] + "..."
extra_items.append(f"\n → {key}: {value_repr}")
extra_str = "".join(extra_items)
@@ -92,9 +96,10 @@ class CrossPlatformLog:
logger.add(
str(error_log),
level="ERROR",
- format="{time:YYYY-MM-DD HH:mm:ss.SSS} | ERROR | {module}:{line} - {message}\n{exception}",
+ format="{time:YYYY-MM-DD HH:mm:ss.SSS} | ERROR | {module}:{line} - {message}{extra[extra_output]}\n{exception}",
rotation="10 MB",
- retention="90 days"
+ retention="90 days",
+ enqueue=True
)
@staticmethod
diff --git a/utils/mysql_agent.py b/utils/mysql_agent.py
index 0a1472e..0967e12 100644
--- a/utils/mysql_agent.py
+++ b/utils/mysql_agent.py
@@ -87,7 +87,13 @@ class MySQLAgent:
self.log.warning("Windows连接超时,正在重试...")
return self._retry_connection()
- self.log.error("连接失败", error=error_msg, exc_info=True)
+ self.log.error("连接失败",
+ error=error_msg,
+ error_type=type(e).__name__,
+ host=self.config.get('host'),
+ port=self.config.get('port'),
+ database=self.config.get('database'),
+ exc_info=True)
raise
def _retry_connection(self, max_retries: int = 3) -> Any | None:
@@ -129,7 +135,12 @@ class MySQLAgent:
return df
except Exception as e:
- self.log.error("SQL查询失败", sql=sql, params=params, error=str(e), exc_info=True)
+ self.log.error("SQL查询失败",
+ sql=sql,
+ params=params,
+ error=str(e),
+ error_type=type(e).__name__,
+ exc_info=True)
raise
finally:
if 'engine' in locals():
@@ -309,12 +320,18 @@ class MySQLAgent:
except Exception as e:
if conn:
conn.rollback()
- self.log.error(f"表 {table_name} 批量插入失败", error=str(e), exc_info=True)
+ self.log.error(f"表 {table_name} 批量插入失败",
+ error=str(e),
+ error_type=type(e).__name__,
+ table_name=table_name,
+ total_records=len(df) if not df.empty else 0,
+ exc_info=True)
# 记录事务回滚时的失败记录
if failed_records:
self.log.error(
f"表 {table_name} 事务回滚,已失败的记录",
- failed_records=failed_records
+ failed_records=failed_records,
+ failed_count=len(failed_records)
)
raise
finally:
@@ -601,6 +618,7 @@ class MySQLAgent:
sql=sql,
params=params,
error=str(e),
+ error_type=type(e).__name__,
exc_info=True)
raise