)jMApAGJ!
zlG9tsnX9=|ydI4xar_zFkd+N^amC@NBCZWN$&MpvgrnGz0@*~S8`o|BwJ-n87(*;L
zv!I~rWm;rvC^t6ziJS}d-OI~#{@z}cxHmA?H|j%cxFVpi9I$Wtej*Bdj4AxN0X7%-
zy=cBYWj_uKYyI3!VBnO1syFk0t7;L%(x|x5)`Jv%q42k#K0EW=Fc!21$&l<7(G{(=B5HMGYis7g@9X2O
zW?J;q3GHS%ol(Vj00ci0`PU=8_vTVqE|w^R6TMktWYvJpUjNrfFtUvcMOr>;ku44s
zg_kxQnt0gVaN!ctd<{%W>D|CMIzAE{@!1P%>&d=!_=IT#=
zYF#n4mHq@pz@g?T@4Ik5eq{}r0bykxsx#-0VIA6^MC$2Yc6h~Ay9MhE^xTuV@;i_X
zt#ZW{gd0XZn=V|@hG}=?oY0~2W7VTx4?d4z9#^_Jl!t!;-~Qt!v)`COfCi%Q0;~MK
zy3arnUtVqM6mOfeA`znxjhF#NKdi$IQb@ymu%e)NYPCBPc=k;Zz7F!dos$~>Ge@t23s`D~
zO}baIN|1Tk85en7NE9^mkmRLG&q{5lFXWA;sqEDk3CpVC5jdG5a@GTWa`&365Jpd616F%3{I;08{UWvJ)%YR+8Eo*TdXaAk7v=2>P(
z`V#mNS6pDMlu7Wi9xIwr;&YURfD(r8f2)mc
zNt20;OmgWzeIzyFic8`2>*`Y0o;S->v^O@BpK!%DXch0B=MHr!VT^4>rz4{VGHUY%
ztZX)G6J{yO!u&_Hzvi;{z^Y{Ye=qbUmF1V;@P5<5=Up`vWK=p2ie@T(LY-2JTC+~_
zeP!B{r*>U<$(xt@g4!tu_rZ{#%`k?dkhWF{Gx^sUuFpQ17&C;;kUNdz%Xc{x^T7GZ
zgoejnuIKSL;AjfJJRxaLixo{n@n#kWrCg00*dHF@3mq^
z^lo7c`W&2-5FTH@1OobPT2+5*D(v4CZd@}A4Ob#qeeyNvs)*qQ@7hoOC$aWxd*aQ;
zqVP&Z9&VEv(F5ugc0J1K;j)q(O!q0`VHoWnlM2Yin-o(FxayWuHFd0wdCM15SE02}
z_n!#rE1_2J0C`=P(a*93sPBk!5-8>2l(F3-beNuak-MyVHUeDBji;~gs0dglE#}+{
zpPW85T*le?pSa?;auMG#sYu_QjU3*R9^8?K(h}j}M-GMbrzKV&!)gDZ{`-`g4deTW
zO>L-C7`jAKwLl(jcLjuqu>r*t!6jBYnR)|HxtYA^df4x0zP8I6Jg|Xi?l<5LVHVI!
zUwnO+IV)7aIbmc4dUa2{loOD@{~S?sKfe>thaEL)O3vviPq!7+0|w(
ze1N$S+&@4-DvlpnMBB#K2&?R77?<=1!2nSO-mPs~oco^IKJ(x>P>B^etEJ7rL!unW
z8`z;{JiDT+)^>p%PZt$DC*Xrj=<)k){4(Is3a#u}wZHbre-i1<4U2>f(8B+L_-~hU
z=!ze80N@6i|MW4zKAvc5HI>G4<8bpZ(Ml{vZDiy-RO(M(i)FL>MKtS5RxM(7S*c4iN
z@d#PO^0`V9qEH)3%Le>IS@t73G4gOF#2WvS^f2ygS^Q>6(!lv^xIe7@eZ8e=Xu{v<+HjyZ-3t3RqN@c
zvx>)kF^aI?Ie3CGVofg*_Gtk6jRodimf`R<%`WiUaxwK|+>yfe4=mhcLvXyVP>^!P
zt<(TWN2K-Z#5I0P>~ktMeIdTZ6#K)B3x*=MvcrGSYG+(Zmf?~uN+ZjV*W_4$z=I8l
z0*|HXw3}ud-DPmO!etb*D*76OFcnVU8=MJ%?g}!YV<&!w?CC@vFD6yj{fhSmT9~>Q
zdM+Kqtpw%aOBkp5HYOqDYBhe(Yk7MvYhX4+f1{}IWSi^&(@hI^4UGDi9w`KwMH!wq
z(-c>SAD`ChOWcA9eKX9Ty(~M@(wp|;S=c-fk1IY}{X#>K9h02G|Ep+#XQIt>
z@oF6Cho4-O8!D(u6~Ra8w2gZcoV4LdhSGB%X*2na;2z$3ab3$z7od??2r030L1X?Q
z#q(?yP+*ncBjn~zPn%PA7LE~xT8yN
zrE-QrtbLRiJbIP$|EnXz`Xx-sZdL1zTzL;?)_>JdC>;2Clfh`Izmhtncmy2{(I$CD
z{v{Q!riV^US*A%ac|^EwMki$U!q}qZ228e@kLm^7#CDY@&Sb38N?Zz^tJ;{wQU&9gH@jxrfP%O-ltnSNZJ7Tld1bu`(zdT*Z
zR{SwiFd$dcz)*VLr-k0{;V;Fbcm7{5(aII<-{|x|vsGrc;AptxpVZkCQ#LuUBK!6{
zs9W%qbD^xt>6-hCf;yt3$F1{nldE(O+%K%i(q@urDNJ%tOmvcO-k6S
zU{}-yMH()vO5aeA1V3ugvaZ?@g?~u^K{5R+nr?q(75$i630&pGOya4eQ9f3!v%vFg
zaBnWt(4zWA)GCifm9?Q`r6PGz5tF8_b@;NmGS*x-JK1g4FT0UL#Z@{m*-BzK9XsRR
zEZfavLIzvw94&{HM3hqWUX;g{;_dg}?f2~WN&yI!eu(%Y3jb)eqk_NEci~dRAD!u0
zG;U|KrO9ExIcR&hNY$N^8c-6nV4-sak6t^y40Ar@ohMc{5Bvs7+*3|Bt+v}vlA+y>@3+uu$P)9jaK
zy30`tg+@sgUK=AX;#CPZ{t%q49f)ak`85^#H;Rr!scoIiUz2On35IP|VoW5bQV$-vc{D8n7_ST5ch4hs-uMuW)@
z6tM~I)(S(PYm%N$HDqu@m)^|^4X!~nQlD4{8x|JS)4pxQ7ni+k7@BnAGI#EB
zP@8$HcdPWe_+ARvyrj!{*x3=&6B5182DGSb%KYHdIntsJ0eSu}ps8&ry|lv{{wGu3
z#`7}e*_Yed#%_D0IN59cRUUVB!pG_YLnP*Zt6NPM3T*P(J|40ZkRZ?YB1tGXcmFOV
zD+tSV)qK`Y-=0Fq)V0PmMof)9Qc^vY@(JP&J|26&e3~2LCGP*!5ZbSJ{KK|kH&EEv
z$UJWax1xA;{{pX|8J%GN(GKytVVTyolssIQ3`Pg9`+U;Q^~y8yS-#%*UgLzmxnm$_
z{8Pf*0YEBm7AJ_epZ)qEueDy|;R9PP=XIv4!irt2cI^tml4vX>-<-2W+dY3efsS91
zXIJ#KcqwnYQpX2Kj|z)z|IkrwM$on00I%(;ccxsSdV|1_Go7~%S}#+v9W>GagFdj>
zgnANv9+Rj|Rm0)_6`*?aHHxFbnX
zn55ySf``s)Y&^uCw_&>1SfnE7GS@~!rQf4?t%o11HSwBed-n=zdCnJk|K|HQ9|fq-
z&Osl3^SYkEEa!NKQHg&`Y!B}FVP5!yo_pE+VFhv@tt9O3o_)0`vFaD3{8!j!P&S1-
zQo?B4WRHbVU{t6?>7Xh57W8jM`R9^;>ngl>RfGn+SZcSfuHuF19ff~{1!?Is;_&D3
zc>UDS8V}2EE`k4E9{29B2=`$SbpQV+>R5;&g$IK9mPYzowem{U3#LjHla_)k%x_M%T<6tg=u>|t1v8#MWy65^$u
zc^5GwjN5)9RH6p(pYTqGr%k{0$zW*k<<}LdrUTYTI&ErEgm|r9qW=F}LX7gaYSl+k)9?t}geo^mxNU+6(j_{8x`ltP|#9Hx=xpc4(RFtqZ#y?!<@6wPkO9NYC82=fbdkDO8fCh(-#NuxAQN!
zMztfL{N@DzbcZk`v%`^cE7MNnX%jWke=!PTH{yxhB+i99`Jnc{(KaY%#NYUOOWE0L
zTb3X0o)nWM+j{PAhf2AL9~YMvV`tP*Z;@bK7e#TM;dBmOJLUyplHOJX(52Tq63clx
zt9adrVLr@qa*8&$YwIMMN;Z^tHZjHPib4Db#?C`g>XY51M#gzLY)s|MIO95>q)bKc
z(4CpeEN|rM#-1sXsKm_nrlm)ZzpaXGk;5{>#MI)tpj9i;Ci23^bD2c
z+ej7ow5FtFtIzQOQh@zVL%VxR@AkJTEs38`S(ld&w(rOVx9?vWtFdZ+Ye<7lCb#tV
zZEgJ&$+!1R{Vh!Iu#5!+d?C-S@9Q9BU74&UsLtWpBM+X=2&&$B^>xL`%#Nq#q@q@A
z8C!4XX2;Wi5)z%gg|(@l!jMic=z0~)w)|caVgX~6uZ6cC&K$q>hTJFE3k(pG6Q};p
z9~0%gC-!`@F%5Nths{TDb*GK?*q_PgYV4yiHbL5kSZ+l+g<%Cbztr!%(HD*Tb+T-2
zi5TeamRc$c3s1V`lxEDoAi2*7o3hA@XJMB81suqt)x5r!UcY&RSrYnTXvNgH#@GUe
zzDc1lbrw4342n_}+9i@aDR*#%o_jSSPj5_TQP$u-IxpN#dNs8_VX(1*o$c4Pc&ke3
zZLu{aUxumiqnz1d!Qis8RG|I#WiIGfM6NNMisPe7^_`;)!tg4?Z1;
z@+cI6#F@&@|MU>Tk#`c{r@ZWhA>heD$zV$K(6egszZ6oCkTLjP&smfi?_VbT>1OTwfbe3j!tWeAkK#pPrY=T8P3)&(hO46gr76jE!^^)K?|dViBkju|tB8
z8Wtf@l}GgIFgC4%J(D*Io_8r>tyeY92QoM<*~Z_-aI}+hY+=0Og5rFOr4S6`c2?H&
zU|UuWYc1ROOE@X3zpQ5cQT4+>(x2o!G%ZT;LY*pHt*x=%F`MO6eK{j(=Urtf_toYXiMN;-o?Smr#jH7Asj-2q5HH-XLD}T=?l4ejdH;Yt4ee#|YBW?^8cTLc~xZ?>lAGo04*q
z+-fxOSb%>GY?xaW!#4h?;e|LrO6p8mMwll%roAm!U`Cnr*8Iaak#bX-quoY3;N#m)
zvW-zEX!j>UeUUFgOj!p|zD905Jzkk1AGD}Ur3hwV0R{P6QltFLr?)Ymmr%%EM)-Szh%>;rq5JbH^
zWkp%RrtpG+LRDAtH{Y9r6XGw}#!r$L94wl+9Lgr<4?Eu@rAl%FPc2Eu=bTHJeS2nN
zr;&OK4jVu6U##n9yEX&xLLWueYQDV$W81U^C4W2J4--Lcsq9c)VwFrS&d$GKzTT!5iGVCfwzT@Gl(4o)HzpCG#Ggkj&BDQPeu4x
zRzBDR3M!PD7!0D^a=pU+e7{v$!Bfc68a_!!>!kbsaQ4T>BKUSSJ4_y)Y~>RE(noP+
z#O&>*VB%?gj>GH7{ZMW^tIJji7?
zXtO-ES*^1>t=Mt2cEfnK%k!U9h^3SyN72mc!$t-Aj$d_SNl&vp)^cbth7@Iu!Y2i#
zZfktCFDV*#Hp4Bq_w4j`ztMWVc7Oe9zQh)bHvBjOtu9waM?0a%e|p4cG6H^`8#&u~
zSYwMk>ZXPz)VKXL#=mN=>UEYXN?RxO(Gsv^b|6Hyg3_d;`i-m7$@iT&6SB*&*L$Y@
zKJM|{(QE50(Q(|(;nxKhv6f_41s7)$wvZ#cBSey^9%70A&a>$E!Okx
ze2~Pup6VeR;R@9V$aBv!K{jCQuJg_9j(aorG_#KoOkz>dDfVM0(!f;en>il80TrV}
z<`sJ%LH8cjDBPMMwP)Mn=M=2EkH>*^mwB?Tknwd$p3jh@>1hQI|JEaOzv>?heYOed-sWwbFWO>b|r8SinNNr*2x`
z1eWVuFS~AWb#Vw#3G9#GdU%{yP#~<7{l|!Sy6~iJD^0zAB1}4HwrW*
zWzoNO-@P?ct<)UQi4lf6h?p29Z`D!vDpu%?zgU^{2+1X=Mj2ZKBh7^`;`D>chUXka
zC#uG-4?Mp%9j!L?V|U(uYaR^TXp+!lHn>^v`7}6tIlZcSER`
zUS^%T&)OqSMOHU8YudS63G^Wzyr%@MjU39vRifvd^yIRX+BBYmc5>!F34><_dQPmi1tN%ovdF1B^2#kk#uK*U1|a4Sjo6*o$o|{`Q9yP}5e)xABj41fP_pvd1;U_hjwn4X)&x
zts}Lk*QH)GXM1OE2IN^!(DI-cc|s+2W$u8
zW8B;Tcu)N_HzjP3oKNf+8-MY6j_j1)d32@b6PrCTs5;ZDL7AL&>xv0t{wBYa
z)7h$vYTSA-(qBPh-(BMEhgMNSH*H%o+K7)&gJNyr42>aS0HVg_ok~QqBOZ>(3R@j3LWU=&}~?E9S2&@o&g>
zC`ul@oNeYWjOpH@)!nnXfX7B}g7`5HsF|G9!=sr-`1FEr&7i>KkWo}`Xtn|us2)g;
zcyWAh5F^KyHTGaU7Cg3dOKNEHVq@3bWr5k>Q7CrHk67bacGN=Od`0OLCsP>nHE_V)
z1CM27ql(d?uBpJ6^;Q#<=Pql(=GDc?cigkOhu*_NJ1vWp%$VFrlGP~MmYVR>85OQBAp50il3dnv~=
z5@C~Jsp$Um+*dnG1L~b^TGzoDibl)QJ>T`d@820f3v0Z7Ia_p1j90Upe?26+20ToM1GOZHpe@_cuoEVySH`M*z!*iz1{53W;lQ8ywVrT
zWVKT8*}NsEmsQ%9K4o^frtH=yoSbP5t}8c1B~dCLAV3$7>O__7CEX9UzEyB*Hv1&S
zNObiMckX%*Z>T9T?L9V{yx6ijcrb$Q)sUTXXILJZbyI*ty&S%?pmS(heIA=@-1;!=
zUimxvRE|HR5Y3n*2@R17!kM(U*bPgfE1LO$0xv^toVQYVq
zCLD~bmG6=(ecI&ythA(Hq*OqKirg`xu%ewR`0niVeQo<@!~wkrleD_X?qy+Z!3RK~Z?b&1
zeOGfkepZ75cgmK#Ak0A@Cx%*z4@slrOSV+~_m}p^-$I@Zv1%DHLuOP|O?Ix}*87Q)
z2Wg5X6oPh7e~f~tF0bENk)wG8ESJ|+IWh+1g-@}fTUw75bH1oP9@NtwK{LbDS?VQw
zWJ;7#rZ&V6FTWcK=XMSmyw{Yg7!p?hnicDtAbs;#H&lHa^tws;mtb!6S=g?c>PU*3o)dPbRS
zq+Mk3h2geC!3dic^`jrD*%oMMF=~^mF4J=~Z|hYnaM#qm`DK;~M^U0*ZkakjIOPdyxwIM=QKc*eL{BGynCk)v&O>$X{&b4$ghfnZ9|8j)S9I4R`yoNTN1?|zfGGs{qnw1Gj01a-DFp4OKWz8XFzIDj|TaIYW!Z0uw|^$PU103-KjwyR&Kbe
z?&2=HnEWiS{E|Ro;^E}lxR_MNlf&De5WNte_sAp()Pia?688|C<0;rVp*~!jx&?MI
zC4+Ht{oJVf*|vf48*VEaPIp+Pe6uH2t7w=U8{vIIA5)Ooyt;e5*`e-65C^UV6dur=
z3I<#m&eqXeGxq93p>2)u-+5&V=K{NyalwE~wUTJXpUB#c_n~8xZr_mgmM1qk$PvBwIBwjqYC)rvxZpDi*R=a(yZs#<=cO6u`SYQ>
z$rlDFw8ui*7cKTp7S4@ge|2P{w>MbOB?e8m?2|7hrKO7p1N1)WkULE!OPCqkFj+VCzg&6s|e
ztd4M?K~o0XwhjRmvm4|JgH}+GJf31HaZiVix(>OY)?Xu3^xl0OP`846v=4W>$46fB
zYLhkeFjvvz`d-8%**Hq%Ae`p>TJ&Pmzjq
zOe}X7cIFgKWz*TcJ6;U|b;DS6_wE9VC}}MIqA8AFsb+4hV|vbhmcgQJzt}b~!8)Jg
zUk0%&{EWqowF3e0Zl52AGN&`+Wu7;kdsp}x9so-shIA{4nDVN0qE4740J-D6Ph;&%
z4zDJj86c)F=7hm0k7701oe0z=jJ}@z9(??Ya0i{6mDX(ky@c$r?xh6mU2Dw1@ge=0
znB2uwMx?O245*LkwYmMOZ{;p?FqNNxMai*QECoU}-m4!9TG^0ZtMmspq9)3v^<$N`
zWDrE33h+tOe7BwItwA>{Zqc}2!Eqd9ugsvJ46pfgmr8(Ajkd*9DEz~?aFIX+k9`@oDgJ(PhEb#HA>
z_`(9x={W>wq9gcmL?zyi!^+DXw>*{L6GuxQ#}{aL+C3f|U(9^R7`66Q7}U1GH?%Pr
ziL?yCGf%?{NMn_K;sa)M>Uiq9$4Ifr2x?xcex7Knh6kjKstjuimq=<-t4}=0NV%!t
z;xw2T1fv6958$I`orv?vDn!Pzdf%kTo91oR3vzVoj|EHR^|AGAt?9b-vYoUj9Fx9(~?(9N>}o*d!NH;gVWu_yg?{M
z5Y9t9Gsf)OVY3cCNKnXEhDVN0R&3)vlO=p!M%#;0d?M#Rlf#qp0<((BBQC?FbfeN$
zWDM6y5uo#@D3XHS-y0Dib?6(1#gr7`(HylNsUb$^#kuRrwtJ6-_kyO-_)IW~1+x2?
z_rM&8tB(Iexroz`h0~ht@35f~86_l*5YR?V)VI^yurkHRCRhm;RvtYk4X=;GGOT{{
zfm`m$WfC*2AMI*g-UKW8VE}OILV5QGSBCG1K7LzMC68#-m%Ztrut^|)yp%*`)Aam$
zIutca$OcsMw-T1}tOd%a-ypwt+=F7c2Y1C1_RHR@zhZi$TfCme_LQdIOCbk%s!Q_Hsq1BB)mYXiyiZRf2ej8$Eu3bvwHv)k3tr?lFi~_Go$%Fg)^3nm-UCOA?peH{#3UB}9CL{D9K9fK(Mr<4
z?QE1pzmjz$szA@E#4aw_O?Zz*X&zWUbblKnkyfkimi?Z0_pi;MNA1eKJFS@IVKC0txOk!HC)NFcA{`^8|@8PF4>lDn_
z-)hLQV}wa&K~|{hw$yF@+l7TTH(-OZy2CcqrDnyPI-!k<01b32m5qh;#LdLmTHe8;
z?U04~Ww3}S-f~ZihTAp+Ok}SeUyHxJt>DnN#c-@r$=H6mNEzq~4H3WB;ygR{+~#qk
zAe*QBM@d~zz;-!jbYV>#;}6RDfa+n{T?d^{LZov}1xSk=FA5WDQJNXsYTxdYTu8$d
z8<5nYoyFt;pX=Eg$s6BybT{5=MQJ?PY(i`kq`c$zeT6d7H_8umcMffSR9M$|@1|WF
zRw+~>b$}#Ev*u=1ymj1t?|eQ*onbwGMW~u^Y)Rqq!6hn}AP1{<*9jMkr^|^b384xC
z`2rO8n5
z`j+HII>~x=G-yWlMShPS(iy4wF7wEaQ-H0&3i8M#TcnsFYRm`6L+|Agg!F<~H&uBy
z3=foF@8P||l?E!Zz>SFAI!ZEYpUqE8U+LQ3Lm0#AC*~ZYjYn?!%hznPu3$O(@7kFL#T|E2Sduu(gco
z5sB2#-OA|e3qpa6=475c!kTQ@&xJKd+FAI8t3XHHkDP#O0TV=!ySzs~q?
zlaA3Xh?qG}R4NPbICOICioC9`cs}@!+c%$|(so4(r{$Ri4OHBOo)=$q$!!ltnp?=a
z;>EtXfp_(*k@h4zHU(R4KmARVbNN%}1Jl-6XEya^@ApHWBi}s8oVv?B6Sa1*1_43p
z4GwHuEyASVUMoN3(2td&^k`7rFBMGPr8`9YHPULX@sxo+-~g*7Lv+hY#C);#6VlW)
z7t|G&?K_2hX|7p%_T9)V!ET}^$!xG-ZRUiCJE3dhq8K}Nzgdr!683!p$HH&t(%sev
zP0x(A@u@G|lQVzr>g*^axq^4d$K&F@D)C2-V_kc%9!GA8%=NmS>nnqIYt8^Re+7;4
zf-YEdv?=G-7kh_R7DjlC2A}Y>ji>YcBE+H=HhNHnah`SbhS+{gF3Pj_vZPZx(o(9q
zyO+S(HV?e(+a{pVFm+)FjWiekXnTbB6IvaJFBgHkkW1{$5=Y(vV#K!s{ri$P#VK({
zsjvdA7INKdJu%WNM{GgiP4sYAHYiBc0;fA*&)@j5mUUeZ6WB5AA6oSZOkOBeTMsBZ
zyNpUL@C&j;6pZ-y-ryHYnW!4BY30m?;i0*&k>nH0aixu7&EF7a+a?v7jecE`DGPC=
zGTXS{`P=$eyHdkEvhuYrqrj{4+19;`O(UX6w|hhIN#>W`(7$r*W7iz=OYv
zFNsb8aKU7ws4Zbl!^`Y?Gkz%&@=pbY%{N0Ol7nIsl7rNlR-I%6dyXnV$cZqOMp4V2
z-a2X-_A(jo_SBazD@Ab%Z|tMy`*7pil4h1P7jw`CKF;QI)*Vbj!>0|nBYQanmsUAq
zKkjxex4&(2F$NSM0aHwhoz!$ZFLQK#3DP9@-dzJck^LJ-f?B558EQ2^OoHviK8ys*B`fn;8jg34W-e
zsPds`cn%NW+xwp
zoHQ1lAUwX&KiJCcDk;Z=`yzOb6Ai?mlXxjU60}g3=aVNOGB}wKlPTA7;$k9P_{O*)
z%SFbl!{oNj!IPmP#XKJPuWJUAEMk*6uK0P@xok98P%dpa8l}X4=vLEVJ1mx}EBqG9
zF6X6bD;hnWsLG4fH`o3o#2$kR`q(~wKLX{(cui>S9g5!=jJ*okw2MK?pgi-#-OO~|
z#-9b#_r;taj>eiEtmA@4MztLk1%v%9WXQLZ)-=2(o1+*$t&nZ=t4!iUomP65X-#1~
zf~(R8!?hDumCZ-(%K_HFIIhhLb~)FO6OSBY%cuCM&6>CT{&bSoq&bM#Kd5Y5F?&HA
z6boDQZjGH2*wO+NjGVpf+3LY`1YzO%+3KD?=^j*+SHZrwp9_Z>k~6%j&o_TvuOfGJ
z&lKYI*@btQdEn+e9lCO1Y+W&-IDaK|Y?rZ_znM+DSX^iTCi_jM0@yH%R(4;o0!_
zXJnmFlhAi6F57;(or68ND%HHH#mu4dK}Ztii&~;)^MQc*r;K|{N(?`p>=zU~%|*YY
ztG$S{UC8hdhr*&_%wO|R?%CI$WLUN3lGWyZdNlY`LQQ>ge~L=fL$Q??hN|VuOfzV
zf1_NyeJXhq0&ElRLFF5!@H^B{>L=vh|f$()Zoc!ac6g_g1|PjENg`+Znz
z2{NE_F5Ip=eEq$VKZ6)5QRETq-XtZ|OFPyVKuBIl(>Q91y13c-BZhJD*m+^`4s(8>
z_~e_x5*wSsScI~DX{2OulfnQ`+!;k|hxhnTJ2xBp*NRdBC*pFIp2Vgya$~!bQDUD`
z!mVVlr^pLe*5&I%ymTy|Ywy)|sq$UV{PrVrA_l-8og1Wzmzce_CyLuA`Vf_zsXqDZ
zN0f8l_r;i@oTGpMiZ5=}G5k*+r1wZyI(D(PPIy!6WfN)Q5GI$
zBIm1>vHeKDl`WHw;DpF9aWr(@^QX5PA@CFK4^f(tFraLjvOSV3hHmCGYZ=}SDUXHub6pym(a{4
zq#`=nYyDf;;1LX0SWkqtlxbZz`{&eS7NY5hGSX2H=EA7qv-^r|QZK3wA3u06(=fh-hNJcO>gB~4
zJxpQzy6%dvWd^-YVoy4ClA|v#qEeuN{y=Zct@y$KJKwOx6%?J?>(5rhD)f3(LEso*
z`zjb$O2PA`v$ZKy3C&o>(;q-_FCCeogN(~
zl?gkix5;6U?b48{f&At_&u4kbx*|@AUY8NF9u2JCC1^(4q^M2i#59g8yROxo1?pis
zmc-@u1Z*@Wg0C2wQyh)k9|jfyO!|JA4aZ91kE9fj;^bA7+mJ7C3!tz#$t_RQ-$(Y8
zjkl5Z&{F69j%cUci`I{qKF5E(&X04a4h+XK*O*e=Eu!&k$_(D>&+8c^Ys~NvMl?`RoRJPPsT9ChjCRj8(p|h(lE7e~7O-O2!3AVe(o*RvO
zDSW&7MQzz3+w#t>y*uH4my-Un#|>%1<`!2OCl9GOjoLA#ap@$=UEQ2*>MUTYCx!+0
zIF5#&3mYGWqD}~MuP7pg-~QO5DqHG2i;63{wnlN%s=MaX=XLkeJ7J^cPzgNxkQ^o)
z3M8iqXrXyhSJHO@TiK4nM42h?L-S^@_~8NUn8RaNuzr}5&yX@;FZw;1%h1u<*Qn(YQ1Jw6UWts0sH!Qy19ZQHUX+N3gGH6-=g?~cpZv39i{_E@wcHhsc#;e4$W
z^;NN>b1fevA;k+cB*PzQV#TK}v*C{trT?2iiQtr0hH`&g0k2VG+kM;ZsvFNj9~}(3
z3n7ksGw4orop*KAkMk2tY^MXCf9tIC6`Qd$Bj%7XY!D94N%bOi8Dcs?%scpljtgu^
zxk;tulf1-c%>PTU^pnh<=V|+BrsrcA^o3D10QAxl=n*%e>1q}gJ5+Vj`O{Ny{wg%Z
z!jQGCs1c@01|zwfO8DQa0j%WSCZ7XJi5}RY6CR_b^pIMjL1&-c1!Xo|5-YMN!8!_B
z@g}`(UtaaxPYu5XtNrI39{$)Az)wccGs#}GuboVplX%nwH?|?ytvq49Te^H`azbBW
z_wxb;gaV^>B&EWVZoz1Z|9A4g`omhJOwgs)vhS0Y2d4jn{cLq2n`{i3BaKtrutdcAA+yrySksOtdO
zck*((nGp~u7zFKao1oTn>p*CY&X3Iq;*XfY-BEHwLuvCitM4RG6#u*-V9_tYes_{!
zC%waMy&%C(>Isj4&z4cmxj+fNA(PIwqMEnS1pnq%=FIb
zOH*vfHqOiS|1IjhMpA_LRc_ef27LD-fxBtCeJdj}jh`o~UW9Jn1}$Ho6WDo;i+{Di
zn(~5!UNgU3i+jog*CqD|xGo5om{?YaY_r+Cv;w?o9;L41XyR}%dSC+umejfPfpc=)y=F5gxYxkZ)tT?qf;(a~~
zn58}ekHwhw2)xM_yfXB?NO)4{pZNwdhrNQML^rc+ao2<$2+`d99JI$h=hR`Z*&j9p
z{aGcp=56pP#7bDpIRRB+s;_`sxTBcm!oa6;K#u1)mS4PQby85}Sb4q9e07i?OPXGV_
diff --git a/docs/images/Architecture.jpg b/docs/images/architecture.jpg
similarity index 100%
rename from docs/images/Architecture.jpg
rename to docs/images/architecture.jpg
diff --git a/docs/images/Wechat.jpg b/docs/images/wechat.jpg
similarity index 100%
rename from docs/images/Wechat.jpg
rename to docs/images/wechat.jpg
diff --git a/go.work b/go.work
index 02e4154d3..7cc1b80a1 100644
--- a/go.work
+++ b/go.work
@@ -4,7 +4,6 @@ use (
.
./tools/changelog
./tools/component
- ./tools/formitychecker
./tools/imctl
./tools/infra
./tools/ncpu
diff --git a/pkg/common/discoveryregister/direct/directResolver.go b/pkg/common/discoveryregister/direct/direct_resolver.go
similarity index 100%
rename from pkg/common/discoveryregister/direct/directResolver.go
rename to pkg/common/discoveryregister/direct/direct_resolver.go
diff --git a/scripts/lib/golang.sh b/scripts/lib/golang.sh
index 7b9d7e60c..f9648cbdb 100755
--- a/scripts/lib/golang.sh
+++ b/scripts/lib/golang.sh
@@ -314,9 +314,6 @@ openim::golang::setup_platforms
readonly OPENIM_CLIENT_TARGETS=(
changelog
component
- conversion-msg
- conversion-mysql
- formitychecker
imctl
infra
ncpu
diff --git a/scripts/lib/release.sh b/scripts/lib/release.sh
index c1fbd00a1..05e92377d 100755
--- a/scripts/lib/release.sh
+++ b/scripts/lib/release.sh
@@ -243,7 +243,7 @@ function openim::release::package_client_tarballs() {
local client_bins=("${OPENIM_CLIENT_BINARIES[@]}")
- # client_bins: changelog component conversion-msg conversion-mysql formitychecker imctl infra ncpu openim-web up35 versionchecker yamlfmt
+ # client_bins: changelog component imctl infra ncpu openim-web up35 versionchecker yamlfmt
# Copy client binclient_bins:aries
openim::log::info " Copy client binaries: ${client_bins[@]/#/${LOCAL_OUTPUT_BINTOOLSPATH}/${platform}/}"
openim::log::info " Copy client binaries to: ${release_stage}/client/bin"
diff --git a/scripts/make-rules/common-versions.mk b/scripts/make-rules/common-versions.mk
new file mode 100644
index 000000000..a4b15aca0
--- /dev/null
+++ b/scripts/make-rules/common-versions.mk
@@ -0,0 +1,17 @@
+# Copyright © 2023 OpenIMSDK.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ==============================================================================
+# OpenIM Makefile Versions used
+#
diff --git a/scripts/make-rules/common.mk b/scripts/make-rules/common.mk
index f8537b6ca..ffbb69a55 100644
--- a/scripts/make-rules/common.mk
+++ b/scripts/make-rules/common.mk
@@ -78,6 +78,13 @@ VERSION := $(shell git describe --tags --always --match='v*')
# v2.3.3: git tag
endif
+# Helper function to get dependency version from go.mod
+get_gomod_version = $(shell go list -m $1 | awk '{print $$2}')
+define go_install
+$(info ===========> Installing $(1)@$(2))
+$(GO) install $(1)@$(2)
+endef
+
# Check if the tree is dirty. default to dirty(maybe u should commit?)
GIT_TREE_STATE:="dirty"
ifeq (, $(shell git status --porcelain 2>/dev/null))
diff --git a/scripts/make-rules/tools.mk b/scripts/make-rules/tools.mk
index 917c18cfe..b30febb64 100644
--- a/scripts/make-rules/tools.mk
+++ b/scripts/make-rules/tools.mk
@@ -238,6 +238,7 @@ install.rts:
@$(GO) install github.com/galeone/rts/cmd/rts@latest
# ================= kubecub openim tools =========================================
+# https://github.com/kubecub
## install.typecheck: install kubecub typecheck check for go code
.PHONY: install.typecheck
install.typecheck:
@@ -248,6 +249,11 @@ install.typecheck:
install.comment-lang-detector:
@$(GO) install github.com/kubecub/comment-lang-detector/cmd/cld@latest
+## install.standardizer: install kubecub standardizer check for go code standardize
+.PHONY: install.standardizer
+install.standardizer:
+ @$(GO) install github.com/kubecub/standardizer@latest
+
## tools.help: Display help information about the tools package
.PHONY: tools.help
tools.help: scripts/make-rules/tools.mk
diff --git a/scripts/verify-standardizer.sh b/scripts/verify-standardizer.sh
new file mode 100755
index 000000000..08a13b9a2
--- /dev/null
+++ b/scripts/verify-standardizer.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+# Copyright © 2023 OpenIM. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script does a fast type check of script srnetes code for all platforms.
+# Usage: `scripts/verify-standardizer.sh`.
+
+OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
+source "${OPENIM_ROOT}/scripts/lib/init.sh"
+
+openim::golang::verify_go_version
+
+cd "${OPENIM_ROOT}"
+ret=0
+scripts/run-in-gopath.sh \
+make tools.verify.standardizer
+${OPENIM_ROOT}/_output/tools/standardizer || ret=$?
+if [[ $ret -ne 0 ]]; then
+ openim::log::error "Failed to check the directory name or file name. Your name may not meet the specification. Please check the configuration file and the directory or file name." >&2
+ openim::log::error "Please see https://github.com/kubecub/standardizer for more information." >&2
+ exit 1
+fi
diff --git a/test/testdata/requests/sendMessage.json b/test/testdata/requests/send-message.json
similarity index 100%
rename from test/testdata/requests/sendMessage.json
rename to test/testdata/requests/send-message.json
diff --git a/tools/formitychecker/README.md b/tools/formitychecker/README.md
deleted file mode 100644
index 7cabf8a66..000000000
--- a/tools/formitychecker/README.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Development of a Go-Based Conformity Checker for Project File and Directory Naming Standards
-
-### 1. Project Overview
-
-#### Project Name
-
-- `GoConformityChecker`
-
-#### Functionality Description
-
-- Checks if the file and subdirectory names in a specified directory adhere to specific naming conventions.
-- Supports specific file types (e.g., `.go`, `.yml`, `.yaml`, `.md`, `.sh`, etc.).
-- Allows users to specify directories to be checked and directories to be ignored.
-- More read https://github.com/openimsdk/open-im-server/blob/main/docs/contrib/code-conventions.md
-
-#### Naming Conventions
-
-- Go files: Only underscores are allowed.
-- YAML, YML, and Markdown files: Only hyphens are allowed.
-- Directories: Only underscores are allowed.
-
-### 2. File Structure
-
-- `main.go`: Entry point of the program, handles command-line arguments.
-- `checker/checker.go`: Contains the core logic.
-- `config/config.go`: Parses and stores configuration information.
-
-### 3. Core Code Design
-
-#### main.go
-
-- Parses command-line arguments, including the directory to be checked and directories to be ignored.
-- Calls the `checker` module for checking.
-
-#### config.go
-
-- Defines a configuration structure, such as directories to check and ignore.
-
-#### checker.go
-
-- Iterates through the specified directory.
-- Applies different naming rules based on file types and directory names.
-- Records files or directories that do not conform to the standards.
-
-### 4. Pseudocode Example
-
-#### main.go
-
-```go
-package main
-
-import (
- "flag"
- "fmt"
- "GoConformityChecker/checker"
-)
-
-func main() {
- // Parse command-line arguments
- var targetDir string
- var ignoreDirs string
- flag.StringVar(&targetDir, "target", ".", "Directory to check")
- flag.StringVar(&ignoreDirs, "ignore", "", "Directories to ignore")
- flag.Parse()
-
- // Call the checker
- err := checker.CheckDirectory(targetDir, ignoreDirs)
- if err != nil {
- fmt.Println("Error:", err)
- }
-}
-```
-
-#### checker.go
-
-```go
-package checker
-
-import (
- // Import necessary packages
-)
-
-func CheckDirectory(targetDir, ignoreDirs string) error {
- // Iterate through the directory, applying rules to check file and directory names
- // Return any found errors or non-conformities
- return nil
-}
-```
-
-### 5. Implementation Details
-
-- **File and Directory Traversal**: Use Go's `path/filepath` package to traverse directories and subdirectories.
-- **Naming Rules Checking**: Apply different regex expressions for naming checks based on file extensions.
-- **Error Handling and Reporting**: Record files or directories that do not conform and report to the user.
-
-### 6. Future Development and Extensions
-
-- Support more file types and naming rules.
-- Provide more detailed error reports, such as showing line numbers and specific naming mistakes.
-- Add a graphical or web interface for non-command-line users.
-
-The above is an overview of the entire project's design. Following this design, specific coding implementation can begin. Note that the actual implementation may need adjustments based on real-world conditions.
\ No newline at end of file
diff --git a/tools/formitychecker/checker/checker.go b/tools/formitychecker/checker/checker.go
deleted file mode 100644
index b17cc5427..000000000
--- a/tools/formitychecker/checker/checker.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright © 2024 OpenIM. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package checker
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "regexp"
- "strings"
-
- "github.com/OpenIMSDK/tools/errs"
-
- "github.com/openimsdk/open-im-server/tools/formitychecker/config"
-)
-
-var (
- underscoreRegex = regexp.MustCompile(`^[a-zA-Z0-9_]+\.[a-zA-Z0-9]+$`)
- hyphenRegex = regexp.MustCompile(`^[a-zA-Z0-9\-]+\.[a-zA-Z0-9]+$`)
-)
-
-// CheckDirectory initiates the checking process for the specified directories using configuration from config.Config.
-func CheckDirectory(cfg *config.Config) error {
- ignoreMap := make(map[string]struct{})
- for _, dir := range cfg.IgnoreDirs {
- ignoreMap[dir] = struct{}{}
- }
-
- for _, targetDir := range cfg.TargetDirs {
- err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return errs.Wrap(err, fmt.Sprintf("error walking directory '%s'", targetDir))
- }
-
- // Skip if the directory is in the ignore list
- dirName := filepath.Base(filepath.Dir(path))
- if _, ok := ignoreMap[dirName]; ok && info.IsDir() {
- return filepath.SkipDir
- }
-
- // Check the naming convention
- if err := checkNamingConvention(path, info); err != nil {
- fmt.Println(err)
- }
-
- return nil
- })
-
- if err != nil {
- return fmt.Errorf("error checking directory '%s': %w", targetDir, err)
- }
- }
-
- return nil
-}
-
-// checkNamingConvention checks if the file or directory name conforms to the standard naming conventions.
-func checkNamingConvention(path string, info os.FileInfo) error {
- fileName := info.Name()
-
- // Handle special cases for directories like .git
- if info.IsDir() && strings.HasPrefix(fileName, ".") {
- return nil // Skip special directories
- }
-
- // Extract the main part of the name (without extension for files)
- mainName := fileName
- if !info.IsDir() {
- mainName = strings.TrimSuffix(fileName, filepath.Ext(fileName))
- }
-
- // Determine the type of file and apply corresponding naming rule
- switch {
- case info.IsDir():
- if !isValidName(mainName, "_") { // Directory names must only contain underscores
- return fmt.Errorf("!!! invalid directory name: %s", path)
- }
- case strings.HasSuffix(fileName, ".go"):
- if !isValidName(mainName, "_") { // Go files must only contain underscores
- return fmt.Errorf("!!! invalid Go file name: %s", path)
- }
- case strings.HasSuffix(fileName, ".yml"), strings.HasSuffix(fileName, ".yaml"), strings.HasSuffix(fileName, ".md"):
- if !isValidName(mainName, "-") { // YML, YAML, and Markdown files must only contain hyphens
- return fmt.Errorf("!!! invalid file name: %s", path)
- }
- }
-
- return nil
-}
-
-// isValidName checks if the file name conforms to the specified rule (underscore or hyphen).
-func isValidName(name, charType string) bool {
- switch charType {
- case "_":
- return underscoreRegex.MatchString(name)
- case "-":
- return hyphenRegex.MatchString(name)
- default:
- return false
- }
-}
diff --git a/tools/formitychecker/config/config.go b/tools/formitychecker/config/config.go
deleted file mode 100644
index 0c4f6a16b..000000000
--- a/tools/formitychecker/config/config.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright © 2024 OpenIM. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package config
-
-import (
- "strings"
-)
-
-// Config holds all the configuration parameters for the checker.
-type Config struct {
- TargetDirs []string // Directories to check
- IgnoreDirs []string // Directories to ignore
-}
-
-// NewConfig creates and returns a new Config instance.
-func NewConfig(targetDirs, ignoreDirs string) *Config {
- return &Config{
- TargetDirs: parseDirs(targetDirs),
- IgnoreDirs: parseDirs(ignoreDirs),
- }
-}
-
-// parseDirs splits a comma-separated string into a slice of directory names.
-func parseDirs(dirs string) []string {
- if dirs == "" {
- return nil
- }
- return strings.Split(dirs, ",")
-}
diff --git a/tools/formitychecker/formitychecker.go b/tools/formitychecker/formitychecker.go
deleted file mode 100644
index 2bedbfb32..000000000
--- a/tools/formitychecker/formitychecker.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright © 2024 OpenIM. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package main
-
-import (
- "flag"
- "fmt"
-
- "github.com/openimsdk/open-im-server/tools/formitychecker/checker"
- "github.com/openimsdk/open-im-server/tools/formitychecker/config"
-)
-
-func main() {
- defaultTargetDirs := "."
- defaultIgnoreDirs := "components,.git"
-
- var targetDirs string
- var ignoreDirs string
- flag.StringVar(&targetDirs, "target", defaultTargetDirs, "Directories to check (default: current directory)")
- flag.StringVar(&ignoreDirs, "ignore", defaultIgnoreDirs, "Directories to ignore (default: A/, B/)")
- flag.Parse()
-
- conf := config.NewConfig(targetDirs, ignoreDirs)
-
- err := checker.CheckDirectory(conf)
- if err != nil {
- fmt.Println("Error:", err)
- }
-}
diff --git a/tools/formitychecker/go.mod b/tools/formitychecker/go.mod
deleted file mode 100644
index 698b77647..000000000
--- a/tools/formitychecker/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/openimsdk/open-im-server/tools/formitychecker
-
-go 1.19