From d913eedbd703d7e26fe997f0592fea5a7e2c379a Mon Sep 17 00:00:00 2001 From: YasserYG8 Date: Sun, 28 Jun 2026 20:47:54 +0100 Subject: [PATCH] feat: add Java language support to call graph analyzer --- public/wasm/tree-sitter-java.wasm | Bin 0 -> 430239 bytes src/app/api/analyze/route.ts | 1 + src/components/ui/CodeWorkspace.tsx | 27 +++++++- src/lib/analysis/analyzers/analyzers.test.ts | 45 +++++++++++++ src/lib/analysis/analyzers/java.ts | 63 +++++++++++++++++++ src/lib/analysis/registry.ts | 2 + 6 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 public/wasm/tree-sitter-java.wasm create mode 100644 src/lib/analysis/analyzers/java.ts diff --git a/public/wasm/tree-sitter-java.wasm b/public/wasm/tree-sitter-java.wasm new file mode 100644 index 0000000000000000000000000000000000000000..45022a965fc8693178f0bda935dad920f18c1f03 GIT binary patch literal 430239 zcmeEv2YgjU_W#UH1Kxe~UV~DsAQlj@-E{%o)t|e+?Zw5qyBgQ-u5L3x=p9iI5TYOu zK}j$OQY0Wvq(nrz5SpU2&^!5m&p9*mUXqtkg1f)Z=MV1QnSAfeIcLtCnLBsRJ@eE< z&;La${HvJw=*v$&{!~hK?^^MmQo4TPgZdSP|La#CRO&(R70TeM9#r}j@3--Bk3IF* zaHmdxdF(GwKlgH{haYFFf?{laEDXiBil{iBzIar%sPQ_2}czJ@&{8 zo&NaZQ;)px_|s2G9sP{*;wqH)yo5N7e{qS4kRec^r2mbt(y7zmAZw>b9(wZ0PLI6s z^mETERr!VI9(%0Q^N+vq!eh^Mdg7tKKBPQwfAsmMJN@~gryhOsu{f``srAq^&pi2Z zr$--p;h|2?J@(|&k36q*`Epuau0vj2xe9BB#FdX%m33&~_3CmJ3_DZv2_)%zp^ zOMvtV7RV7`?0XiNFTlX{mhEBzGF^$K1ZZhSF6RSnBswHzbJtpGBt2R_C)ZL-6X5VX z3-lCV@@E$4D?m2~3>4rE2MiHl?-E;On4#f-kpc{HK)L`6m)R;~1sK2F0uuz-=&DQ- zAk8TvQ-CfG$QGc-OiN?B0F&2QV3q*uS6U!PfECj%FkgTr4p=O}=Z?lw0S>INRdNMb z09R1BM8&#R0nQRu0*x~`3{&az)=Ux65v}0~$uUC%}iU%60(`I7xR3km*Y77T{|K+i5IcfC+PLYYz$VzSGAs0rH*3P6;s0H9xfr+ehvkOCwEy zsg7+=0fsxGeFYfc%weDaUpfU15g^AA9VWnM4j3uG76+sYFwn6bE5Irz=>!2ryS|+y zzzNs5Oab0+Y3z^yA2{Hc0B<|3 zpAz6**ZkD3Y#&{mU}*v@bFJ+uz~{~^`wDQ>0Rsit~{)UD!>jWSgrsA7TYST1Q_jrwE}#%$d=eBKrcrlPk>Dh*e*b-Q{hel);Jow z1z6~Sd;vaiG!6-H%9S`Kz*HyLDFL$FM4y_*_OZaxNE2Ytd@FiS0hYUUVP63@I-&yw zSmA&n0xXQ!hXA7;myrT|;VJR=;BIj6yS_| zdgKW(&DrU80p4+q+bKY%o5ywwkme?Xd;x~J0dz=!39ia90j9bI{3!uWI3Tqf+s9l- zBTax!4(KUB4+r!WptIvLP=G-W7$U$sj>|9shB{!R0I#_@C|!VVZbBI=z;0J!f&kqe zFiC)gj%cO;lbwxa3$W33<#Yi)cWs#^z0^ihhuk0>Ccs43mXQJs zc5O))V3Zr#V+C01jBbJe#~qhR0t|6gG6l$Y6H2xKBc0Jr7a-dW!dU`*;i}{a(8EnR z^96X#4dlfFM3xFm1=#Awey#wUUEi(};8oZBwF0bmTs8`@$I-|W;Ivcnb^-Rfw(K-C zT#4NRWI7;UfLV_1Apu4@tsfI0$LaKx0NY$=r}kj`819Is32?}1y{7=P9nro5Y@<_plpNxIn3a3-}>fId!+TmcTaDysyT=t`^=AhJN)D8Me) zm3abu;`(K~0DWAEodT?LM0X4D)fzjYrzz_ijthK-}0Twu-BL&#(s-z2W#x3#33UJC* znIOO-$99qcz1CSSnF6G_wqy(Nm8&vcfSr!ZECCL<#^new(g`+SfJLsvVgVMo#w`_K ztOIfd_{IUN1Q_OMtQFup*9{v5SnGg10meFDy8t6yYj+AT)irLn0Pi|3`2uWkz##!% zbybd;Dz3Gs1nBM9red=f`(yK6i8KK|b!It4fEjMe879C;H-JV8u++^T=>jZrz*qqy zi{1$W>~KSUk^pnvl#?kyZ#M|D1&FLIrwcH{J%MHk@VT3%as*iE zr2=f4ZjCNifIY6tDgh#owY367_6#-(u+B}vc>;`ct=%rb0Y`MF0G~L~cMGu036?KF zn^&hPSf3VcRf_k_ZE0l z^anayPt^;(5A`%XU4Nu!=$U$!o~=LDb99cLtLN#3dXZkNKh;b0XL_k#ra#xK^cuZZ zuhZ-G2E9>#r8nu#dW+twx9RPAhyF%?tH0B`^lrUJ@74QszTU47=!5!@KCF-EqxzUW zu21Nb`jkGc&*%c3>UH+IcwN0TubbE1>*4kEdU?IQK3+eszc;`e=ne7)d#`#!yw|+f zy`kPP?+tIbH^Lj~z3GkeMtkYrTi)B=7;miijyKL5?@jPBym!5c-X!lm?|pBwm+57B zQ@jtnY;UUfp*PK&?tSFV@Me0myxHEz-W)H-o9oTxAsTy7lTeXxJ#u{#iV29DiAY z3V~4hlpx{$aD`By8^;HqsK#-Aw>ZL2s+5ZHaq$U>NugjK`1)PrLc!HYyC5A;Kxbs; zP$m_bv6Lx5Gma98GssLOGAwOKv6*212(jpQ9q*-U&q#xA1t{yjh12wRE z%^J09hJvq2=;M$egUTO6rZZ)ZB2yFT5u~T72=&t$${a!_or)YpW+Y_}Ad^Lz{m8sY znS5ksQDz@9Z&PM3GK;AC9%McsWH&N7l-Y&MtCaZ;nXZ)i7MX#R*@?^)%6x;&T*`cn z%yi1^K;|RLY>(1zULox!v=49e{B0-*11oM@#+=qi*%!LWX}(Iae`=ri_bOHX;l*8j zO?<+&iAm+kyCM}@g{t{C-c&_2??Egym^FV2x{eE9UNNHhZ@fyCLKTgkNeiTBQUYt0 zl)zdgC9pC{3A3#dSec{*RwgN-n&?1ONR4I9ZAFGnbqg|Vp?S!#VQzMYxjssD>x-&x zwda3@Dl|5|K$KLS#$dFL;*0%Ln>=8NN%3{-l`CH#<{2r`C^_s^y1Yre=qL_igFe$^ zdtBqiRjSNdB9(cStH6xe8a6n2S3{nt(UaIdywda6iI4#cS6IBt#r~=F9xyMia?M)t z3ANFMkrMUlV>C5NHiIV~;(>BRyf3^;A)m#gu@u(`<1Q3Tpl(?M0a7VL;*F-vm&lBu z%qnC?QRWL|W>97&GH+4lb7Y24CKs6+NLL^oM8I-n*s_-)Gmem@$hUV20v1^jJ{A!U6S%Mx5#|*WVF#)>5f+mOyCakf ziSVt#gKG?vJp?QeZnmj*ny=*N;6?#TaG#=ujdL&%@o#}wNh23mDL#S!=1XEyZJJ$O zhkKZ4%}n?S==ppcJ;5KdSQW30X;m?3zm=w9~3U*3q)l)gimWfBXYZAc!C$u z{Va#IAhPR-6)@D@i$lz>AC9Oqb>j&BcY6*@eJYx54zg-3b*2(Ct*J=}EmJFX6T zAv_G-8<9)&|E5O@F&0IIhI+x`qJ>6!{+L3AUL#d;CxnN1f$0?K479XxUyShlw^4aB zh(@s)VoQk_!#)44LL6R=a2VtT8%ZMD-OyiQ4sUpVIyZd_nhyD!2`7KF17G)oh6WtP z;5L+e%?mC!;F}C?2Z-i;0&NEvV*W@*cL06W3$8GrD4D>)UQpkF!(B-T+sJ@#IB=jB z%(p~`G5R&?5AcEprsz-xzXjMIy=lPL8Qcx9pBG$az}Fbu3$U*jTxGx^3?2a3#|xSm z@Kpv60_^PtjSV=M!9xIhVa7M$Aklo#!pxJ0@vuu8gwIFuzc?NpFFhNueIG|Z_$cnZ zlI&fkVdXRf>EL!rF6)4NvwOo{U8K!B_~503I|$sUIy~oV`g5E5pZHgh?l)DxR&*ch zeW`_|vs634_#q7ExO<*U2y`eEPW6Ig#J>QK2YS>&T-XE)JHYci<#`$nnM+0bBXfi@ z{kXkW{8I)BPEh6~1fqq1$8cAVOA}SUk2AxQJaOevQ37v`IrH=`VvAipzqg}s8sq7> z4qC>n*{ev+E}q{@Y6ex^d(YJ=6%%`V8voM@&F1-qN)?-5I(vRkQ@f4nM%0b#=_&j# z6s$!n%%G70m+JXFSU3Mh*LDn_(ZQD}!W!uA5|I(-JEJWhEM6> z3tK&nap7`O2Wu?eH3~nW13Uy0Jp6aBN`Dec_GXE6l!n4CM zO%{Wm7LkrD3#FEUtd%}CkQn|CtTz0w$ts~k$ZLDvu6l5Vlz&?pi6{&Gp`=?9| zGCIpDs>aD8H4bUAOlqrbSWzA)iqtr${S&5!5x;1S<3(y5(Ef2#BeroKD^g*<_K%qg zx5aG5(IOS{wSSbf-ky|Np|SMo5g~#1{zDoXi2as-OvhEN8lQkS{KTX>SdTTRYX3EC zgaz5p|@2(At{Zrp+uVKUJT?1Fd>>4zb z_p+XnS()U0PT_BCYUS0EBDl^V7k8G4=FhLpDrwj#re)7^;7TZC*thTnA8Bf~4|b;#tFm~>!s;Y zy|k!MFJZIc6YVd-eHD1^wAn`Yt0+V}VEF3B3D9SY4&kY8Lmhv2dKOR4rFg`~tGGCN zVl5=?gI#bV($7FlW2H{3$?M(UYw?g$L1p|6X534g%;J9m%;-ZJOt~nc{SR5z$da4L zdBF}mOuZl<4`GNxfK2SusNQ^j#Dd#u5`)^};bnpzyHOZF0MH()AP<0f+W!<~OK*2J zmGAT{TH7H!1vB+du1#L3bAqSD1N zTFHzlhGRfte86JViWXxri&5zVEwdeoF$H4K;=Yhp=4gK*ixF4MIMEd_%=bhiY>*wo zlXTD)IK2hDuW1cO#x+qRLvl34E%R7>m#S@{SFL-(8Jg@oSXPwx$J$>|D(^{!cu&+p z9mD%Q#~XZvcY_G;j40j{O5iWL2>toXKDYFQiWmmW>#R<(gp8mBg_QKP!H6zoWtX} z;f66fVQewRcnO}V{dpxY<}NdFU=7yljRwug5u49h)@iP{#umiL!v}~wFJ@M*FK(WK@xQI?+~6zNySuT6f}^C z@lYc+1GE`fK2XsVGNPuaQQn`q;*J^R_?wp5)Lj70D4(Q#JPAtU4Q^4q`)k9Sh89mJ z;eOG4FsSi&5k45y6Sa@2J|>@_9Y~Sg4>x9jX`Pzc&$6n3`_u-|?n}au=*agGt!|36 zNxJG??Prz5il!oB^+sVC|12oV3nc$%#v8K?M19FPGd`g|782)KaDVB zU<16(6m4)5v_H92(x{BSuLwfL%z8b|RqvrTHI`Ojx8UzdvAB%Y{=`za*f)AN*S@Dc z{Ex@Z24VuDrV(kJvo?wea|_)k;-p!u@j}6M05Z6kom9V~GJwpyW;(g6d!6N;zCZky z_9viT2?NCP40qL0y!-*oNlY}gh>7Cw;wCyu`|p&%1uri$a7fTdpT46<>35>EKUTk~ z>Hi_TImY{c31LGv-hYw=4;32OP#HWQ&-pKfum>IQKS3qJg-QgGb$DahEw4Z;YjzsE zMGXu8)qj>$kG(6}X2c5l8UMvn>9i0!ynDWj^qx+1+J~PJX?}{_iT`zt4%)5gu@rnuk2SP8jpqYmHU#J%<#&z23#}v( zdFz^0{sfgoH>jZEx%3`;orZJoJxQGoS{(xt09vXSP7xo*FlJmLz35)tPrdjC(Q6-m zoT-I9|8b-JCxkAv|L0N#Gz2f}5T;F@t2&1NC?rT1#%NDn zAoQhzN`<-)l%S43iRke#s`lZBv0sa#L6T^*aCsiANrwMR5X6{C_(7_LL0%by{MVtN z3X)%iFsH`*za*|zi*l89-S7S1kf%J}|2Y+^7Q4`Iu@~$=RAPY+;a?J!8ldu1+U1D% ze-a96A-SKb)G9>NOuo%JhW{13q5a>-E`eKUVY3e5-;t)_`1xnhQ~ST8_uhE_UaC_& z7F87ddoWa!Fm+JyN1>oDl6yiyJtTLB;E9O$JBHv;i1#~$;OvO^+lSzZi1&XO3X+lB z6$%<7`9UbS3`r0QE=O`_2;PEt{|@5Xq$t+}?vB^6mEtDr+u);rQ9Tt3Cea4V3+Geq z1%=t?J*xIRxzpnPTd8)_*i0uHrce;Pbl$U?XZ8{bzgxKQGYaPQIx%`W6f^^)n?vxZ z#QSYRaN)%JtwX_;NNx(jc@pp6NZAk#mJF9Jv+UUDmCrQPZRNJDS0iJVO#{=G+9}u79)#6h&OJo?GV0=xZd6| z{0Az0TL>PJc)tZn+M*b96od)=KIpFfc2uHetP+@LTB0C)puZD3C6#KyPrQ=r*U4t%}hl zq8-D(2zqPk&g)UIDHXiFgn~Z{`e^_9P;dhZUQPvXD52m_gTC6oj!N8Ew1fw38Z_RoN7dTJss{J+JpuM!uAmaP#wr12-5m_mP-k!(NYxGnw=aNGw$B|kY<2~SOv%XK2iB9rljOwy(MVw*9qZyf};2e z5Dv|FzkCRz7HK)EstdOf_k%0Z28_05^oB0`zsO*~R!(XkZjEslyVgSLMcUfMOpOJWq`DdOA!CxTyY! z(5?f+$(SI}d%@?*PYSWujK<6DegggB#|y+I>xOu5it{jo&lEL#t1^O+`SWf(%)b?c zf%Wr;EY)CZq=Bj-a$7=i;$aL|CevYGGOUr_pN%!fku}!EpFS-X;z(k+z({2J>a+^7 zqB^{-AP=*{mm>6jr=JBK{?ZYWQ_=Fc4e^w!wCR)B?yNFCOxLHOpm*V>8?zm zYIzCxGWQ;kMt*lf2d=d@fjAycr2F}aQDl!L-W^7xgSV4}Y!8#3F%3GCNP-_vG?Eu2 z5}ocz9fW+JBoV4_62WgL5&8Z}L>`$VxJjflD+uXcvL`HQzAx!$lkN+p1o1)}yMB9pBKMh3ibiHtSj7D@ zOz<~h;<6)b#LdS|5_eEVp?Jn{I1#2DX|7+u^#)cnt=Qoa8@Nl za#tl0dQN2_`G!f4n?^vwLzOx(=@VQtwQ@>O({$bN${kpqv6YGD1amc%*HsqEJ*x=i zeTH%#2!uq~o>fG(1FA^T^eQRARV3t$s?_eZs!`gVU6o#~(04TqxoVPTm^96#YmC|F zRu!qYGO7JlQ-aDy>VDNk#RICP1RinAs7Bmgt!4zz!hO>6GDC5yNvBj3inFUxYiCq5 zJ+{1>C}EQ+wy7GKR}~xpmpIZu{~E-!TMeUu z!8Pt?U1!%6SvMPVRHN~qRfFK{8h6W7G6OK_b9N2VTduhpR$FnC zL>X*YrJ3}24H3CtO;$(ED0S478d;`fR!vq%O{$5qeN9p*_OT9%j7Y82&Z;eGKa;L7?A`}EUq(_c)9zL~B`9aCW>9VE zj0{sLqc*8&P;H~88MQ^e*|o)b3rw+%CS40sW=i?0HmLv&$g6E;mDD;?sh<(BUmc>I zR>#mDR7YrM)RCU*YTC2W6wh`k_nfUZyAF@5I%ZsLMs4aCV$63A)}c<=U&nMpzq&$w zmerO^iE6*PMwpp(O+)KShc2&6T-MYjTC3_>D+Dbvmaz>))2a0(ol;NIG?SjFOPlCC z8xE~U6o%JJ32GaS&#GtaydH5_#P@UR84g+XjV=s_IfesTH>JK<;-dOQv2%lnsi!p% znfsVZeHu{Hx-~FO8{0sd_6~}X^aYl-NwZu^)yCOsvm20n*$s@I7c>yb7BZaIfP~oC zz=)mNP)PUS9YPf>ZYT;_+>l7lX=o(b(@-So*GTl3nw%0`O%uzUWa2d^*^pbEES6r- zOvtQhBI#(}uT{YwGXnBVx*l}QqjC#V+5y1Mi~B*04CFAdFwbI*iCO=~hS|c#(y)_; z_)?QDYApI*#>I0Rlc+M&e%eH8ENMb)L2FGD(nf9*Lvd{r(Z-ynBK822ZZ^$W&-K_m zdNmc{dNn0Q^>1pXl`OzC-A!p~ILv8E9Huul9CDfphc$-sB9qSJ@=SS6Q_=OHW}@rC z%?zmx&4|>nW`@+j=A!G>Ek)S;YbD)#jig7LOPbz11&eDj>NCxWMCU6~g5B{(C#lzp z#GS8A3F?wgc3n$l(yujaj^jQV-)7zuRlz8ernX24stVO9EvQBg1ET0XEu_+3VEh2e zZb?N_TNVnHjBvAan}UnhTWY$;uM{5q}%&xl=3X0#H@@3taaIMRylXSOnA zM_+Hu?|LD#&!oB6rvwc}*2C9}b|>8+MKf1i)L*|{s1LiHCP~~~cso%~zuiz@j{8J?y`jF=r8GoV z+-~NQb+?O7Hry_g-&eO2r!!1zv!yll4(aCZ^Nhwf-yxzdFzIZU67i{b7~&t}3uP6| zyMx*iQ6*&vs1ZoGq}UVVp=dJpcC)Ms)Gr^ANw;X8=(eoJ|Ojv~^h?=aJ9 z0siKS1LrC;KXt*EUMPaZ(Cz_%2Tz7=#u%F!5|tr7z2+&?gx7@18}mTcTK!leL{g5E zn-g4OIK2;^%xS)*JJV(+6Ctx8&p|PsWR}?S%Y{<6PZVjTD-wBg+OZA zhEBHJM%zs41`w(x);WFyq$4`WkoHj8Ou*CV4iT7R>mfr$aKk7V4G|@*pt3Z#<=A)R zG@DstYa>IoQPk9)41WrM&8RB|)+5hw%*um+2{bTf141$ri8O2I7Q^Y}7Ne>3s0=X} zxy3R-5fLwStErT^)l@=;%BF3#We03CWpj|>?s{vvovS{znGt3qpx_%r=9y=M{B24` zVd_q9&YTh2uKh-08-Ns8Fvm*?`j@BnocYwF_T(aw_ViooiRR8MHC!@m2E+$0^@R8& z6hpn7rJ&T(n82uIrfT{!pbPn(HGMgk8;V5e_gaBMWPROp4gFOsOlF16^jU%WIp)Fk z#R`vlWhLrKudF8u)VEzM1!PEh`&W3TCqY{j-3J-w*4a+?MaheyttIP)x6ZCY@8mC5Y*!eqMI%;c2@>Aez^>x;23TFKhU zBdCGV;s;-VJPm*qUoc~kB2DKZ5e?>30qVw2EVly71Q}Aq@h_|*GFC}9tpWo(Z7v1I z_45d=MOJWP6|+KOcw~NwGQ2kU(uh6BX0mN2>q}z`(@+>hKKc^m?6j7Ho6KY$GPt=( z%4|R)t=MHb^t8%LwV4A%$h^VySZ#W805UAmpw+m`Ju@B-#o&^AvO^ojYNn~qXN{R6(5>{zcmIl?wsqu7Y zIsTSCkWH3KYUlVAY^zc$-|Qx=kO-^Kk>ie9)WfuCMR${#WHS#w8>DuRm+5nEcf$@D zVz&f;3%et9help%53p-U+~)USZs|ybTP||UZA~x3WU|eq_C&2wX8&_luXyRHQ^;_I z)ZVy#1rgoen~7#35uzuNV=}MXOrNL>iH$l&f3NmIZPFhybO%*TgWje) z)SxN0GBQ*IH%w(P5;(X?1^7VJ9+Np}Q3t86sZL-x5c2 zg!oKkxPhAo8sZl{N2vfk z91adLOg7t0>L3tmBqoi!BGeINxP0nh+^tDHGik7NHWeq3~*Q61v8=@ z1@Im4M&afJ5#*?0a8#4l*J#tD^VnCg5WWK6Xl_S>RD{m}1;t~qH-WTfSi^n5kG+1z zN6^ir$4!$kpB+h*(Ib9>Gl^zF0EYp~)W_85lSH!gNHVg(eZW%&90<(7dJ2x1;zzjn z+qQU@^3pSK9&quj3be=tLGd1}i}oA9mB2=yX|~+An_c}q#$T}4IB;^|H>hWNp1lw0 zeq`$+-xtlSGL=__N&I}@h!1xHiw}na%QL`u5RRMT(92#^L_7$m!$vP~C2)#~Z*R^d-z>BpPx{Q}d9gC<>4DJ5tuQi}uONF_u0bvOuUi2^SIuHr)&TiK9> zGl9ukufb+RJ_p`|Iznz&WzjLb2wb!mya)V9Us8o6Os^7U7jP)>^pR$EuI*<1V6$nT zZ-&4Mlfv7;`hph$q}IZFP{EjBXX8ES2Jb;R>d`^$Js4oU2XH2Et7aL>SuUjx$*^t# zI1}*ahah4%THsdTits1k&L*b1(NcvMf!k<(0R7G8{z*d}{g-bX2yi5zem89G+sE7> z<3PwTl``0YFxWZ}vW!;%js)gm9S74)@o8K<+ZLZ;io=<}#oBW@-)l0>w^*+16hHp8|{0-|X!l zGt{A#JmW`zKY_FYKZ4sJH-3Z+Qz?TT0E4X`AO4Q1%8TsoGi2I7iL4;?$TRNK$_X&f6wrn05^hJD2p3mMlCZ!`xzg?AX8%y z`w;qBA3}!lA;6cw-Lu&gTVqoA7I+Ye17SmLLv^bu4le?=lXvyI*t*ypE0gnPR8)P-*Qex88x)25# z7Xn-fTzodW5X6zN+`16pQQ+>ed-ZdS%is-@9yhc%!-Zh9oysnPZg3$~HIvH}<3gBa zD$S}#f=sDrOks9CQ7C*1EJ&)|;5W{Mtol?uwZ18y%?^c}`jK~qu4bl7JDP$N031Zw*m{bz!YD=x93=|1KbN-8x98M zVm%3S8j7{T)4=x^8&?8c3S6#dBQxeFCiB8P*~~ETEU>i?HLipeO@vOr#*%I~qhOs$ zbCcbgOk4?@l8rrnlPvAoixT_}(4{ePI&3-hZ!8U4VJI(jDQSCjW20@j74RpV3i57o z(s&;}HFAC0gi4>ZrI$C6hZj5y+{|faqraC)*O_W?Ij~wbH6fYuu=Kjp*b00KtnVyS zBa1x^1DYCfJ~VCuI2f3L^(4$S#o=jS!V66~xD~kEAfwMg%}CxgmfY*jL|!-;xEYcjq ztH2cB4_8DvnQ{lSYhg6p2-S>QRvOpB9#d&g3!=Tbg`vH_h0un>f!i_JcoqtbXJLc! zmcRqS>Vc;L)zh!z7fI>aZpOusVX9`dA`abK84mC~a839gn1gjPtT4`oR5%;V0)DS? zHo)n?MN{EyxQ5mgOKzav&b%RN1q1&BFY!;cLTT%T-Z6uxFTGDYh zNt%9RN^p~?4SomE?*@N^-F92nS|-x2ZOk$+ll=|vTYm%G4?O4#ZWdxoO_~aSLlYsI z%l?M-42Y(B!Jj}g#X$HC*d3U|{)XAs-vIXmoA7AUf&$ZmLoOxF?rCc@D?W##ZOypN zX(!ZEZ%qka=MOnXv6En!brQh;z~rr?VTEC{m>m?{No#KxbAZ!k(LBJPixseMq8SUd5hEw5?n{ni5;CgT;NIhhz{kUP;j|NEl z$KZ8VoCPG_W{xtUF~Dj%z=&wSzu? z7fuF{NQa9-`h1`DNfeN~p%D$huie2n!gkb^;_BfrA+ z)PiGhBM@QdS0G0NKPS?yUtzS}t3Gab`ZwF1{>|2%(932{6J?{sapG6VB)>u}^K?B8 zjHmRpFMzfr5sZfciD?`88n_qdScY&VNZY=qS`}m}gPTD}8Gi$L8N`y|k`My($+y5S z*+&6^7n}`-2{{{B$?L5rVYA;+vYhk}-kVk}!>+~>+@w7nB1}@*r`51@j12K;2}W7ucA z3qA#D1~SwP)G^I~(?K+6ybt7a5Y25{gFDn1@;D$d{stt5F?k+XxPrrGx4dA#$$T~$ zd*H34Z}uMI&GP(1fWEU{j2?FT|5e)lXS+5o2PB3*IUl%TD~}qob8HLYTafl3L+wFP z(;nk%fHT4jRrn`FN_ZTk4l+~+H%y%=a5%8K$pOI}ott5h^*7|6fSlF?xY#-z$n(Gz z;CT?@$PjTjEDZ6}rwws(MDS>uZ2b-eX=XzN{Yb`VH8Pz2<|Aj5`+)j3@$_BqJ$9_4hiXXWatj67<(WG1XIaP#l~<& z8m=ch^Tsgz5QY=EAy^-yt=9qW1mRR*oh<3yP~F%@I(!SD^ImsA)y=d(o(JJWC~tI* z5`P065QYyqAefJHGZa{c2;p1Y!#FiYS$6~Z9k~43UZB~8WS=1J2KXNgP4Yi*|2TJp z^AEsc-tKu&)^_WSAoKO7I;TG zU^n~zC$R)cgnA`xK^zZLqg@X0LhweBjY+Uk5Np`wFvq$aD1?FNh$jLL2(br5EpTm# zTflvBK78$tz_+z`PfH$-sB4ROg0amfvV zM}qY}TyjIuZp9@x1VTBjbKsI2;*uMJ*Up#R5SQE#9OWQ;PVh%uazlv6Swhel)Q5Mm`5!5Vk zO28K(G~tHeYW9?+%nCFBdX+bxG#sqt{5S}YVE^^fiZWP=o}FY5v&us}#g*b=#j#7E zCWk7?mmWAwiQABe_z3)R9ECwpk-fh08qyg{)C_xkk`1_s3X-7WI8>>U@oyp~f@>fc z0(Wqz60U=71Ox&iSmrS%M8O`NG{;0hAVPvQj&DV9loD#<%q0;N0TE1A&Q!u3356JL zgCGzS!IW(fggvAQ!4XUmM=YU|9H=A|FGeiHj&qKM$VXHK^|w8HNlsZ}(QwETZpaZ! zBHDi^Fyd=OSeP?%${ZMBPgW{9Fak|phrkOP(qYe8`WhG;VhK?aHU!~66D47fSlUri zltg|FW1l#DiS2IyVjSe8EIy6t)tY7?Ax45-2Sv|Tvgbx+b4W#&4XKd$2pr5L20IfqHeBaVVAVIsj%Ot_g}nvB`#845~}dftV*XQNPXbDGiNKl3}9q}04^h3$g88(0e(HdL>VHyxlf;6NC;xxDh0yJ=E zI7e*^j6VH|RAi5sy7;F+o#pf=GO!q@KaotOo&H2UU;`a&FoliDurVBkPlIApU&GNK zI1@@Vk8llE%`hAe^$ACt<2Wc#PHk@H3It`aF{IiM3=_X0VH&J(L}{SLzH3r~DrOmk zzznXGjsT3$m?}>`9AHg1W{Lzt8v|3tmgBZ9REyc=M&+#6q2+*(}+S1ulG=SL>|o;dq$qpv)tFw4tro#IwCuoNgMD@VJ-)A z;MggdE-1!>n3oviLE1V0kPfOCco#YHy~cK&cSr|`R%%EG4ICFC;36PgoP|3~ zs^n-7#0|`npb?7ukdENPrKl%d2ouG9@IWxl1apWTBSUvk z#aJ>0cQ8vtYzP%(s0ePD*Ih7@PYV#iA*?g)caARpW39xLaI?&TQr#q~Ls~|G9V|7D zkTOeiIzkG3=DJu9is9h-(m5&I0Z%TN#vM0>3`vPPMoKzd3IL)!B4-S6pa+?|3F1JG zVmFZBxG1AfIxkA}X=6YNYzzoRcW{eLbca1aN}A+CJ8U2a$eQz^a9)(5&M_QhlrAj8 zoo6+AnfYAagm*9}6X1b^qaugk@!3(-g4mKXpFfdqf#l3!%U7P9vMZwi+Buasf!aqY=?_;;OGt_j0~9! zg>gueDS(4*-yJE14BNg7z@Ss3SaIvAEOmlA5z4tsT$qYES&GY>v!%{ZK*;rGy+F|% z%+JJgfEopJAi*J0M#X%B6!CE}8!ldi0zH_vIaSI8bBOvVnuF!*?1DH3Aj$%S5Y=I5 zQ&a~JFn4HE@$;b&v|%O_3F1I7ju~Kx>M(PN+@YWj(IbU(aJ%dwQs8<5fgMQlk%;Z^ zky6w!7r)^mNGRxo8)lA~GJze^FpBKphS}H-kf6X0Bsf*d5a%PM$okzuQ7(AH1*}l$ z2Xo<&53(C%sJBtnG=u^=n3oCgps)@Uz=2YR4<9H+d|b$e3mdUVOfd^{$dq-YNJ}W7 zgVmo;$4dD$yVF@xNb-@0mMD;emvja8XrlrfMX|0}*oKRk8c6XQW?-44s7y$QaHg0J z?jRTXVZu9DSc>j|5GJ-mYEXCwYr>r!<&LdFhKEss4L;!mr%0d3&>f2I5W}Fj4yH1P zqB$y2i|Je`Bna;?EvE1eStZ*b4tI2vJ2ESkqB$DKGRd4L1sZhvlt|0xN|9~Nqi7C} zzoG-Bhz}CcEQNP4pV3yc?$9b6F%^jkHc=qvKq;aBu8r)-bdeo&wiM_i)WguHP!H}o zcP5hy#c=0Gxx>J4{uI43u=@D~DpH^Evrv$SsE<#VqGq|1sE{EIv3{@)&Fjx+K%pgE4vFZH4wd3Ier!*U>SZ$p z_9Ut)1JJbc(lm3HRCk;XB}{PilrWh_$4l`JopGrkF-+)iDQ4o%k}9xF@~Duu*d3 z%Pw!ybfVX+`4v}Qb@esZwrF`>tLtyL@ut>oZf-ltyQST&x7~inoxu<8`eFMH9q+#9 zM?b#zzW=%ZCqMn)pZ)w7zx>s&fAibl{r-VJbb9cihaY+Lu|NLl&yPQm^5kEhdit4X zpL_m=7ytUVmtOw+KmPfzf4`EdJL@jGt4`D1ba&lD_td>~Z{0`t)%|pTJwOlCgY;ni zsve?W)358HdYFDg57#5~Nc$mjVdJKLX^Bp}-kJl4)hJII1)RXjk`h7iF zXX-3HMSq~P^;G?#o~EbkkMs;ZQ_s?~^~ZXS&e3!AJpGBDuNUZrdXZkNKh;b0XL_k# zrkCp#I#++LSL!eHD*dHit=H(adYxXcH|UM}E4@i?)_Ho1-m16h?Rtm)T7RQ=>TmUT zdY9g<_vpQPpU&6&^#OfQAJT{Q5q(r2)5rA*eNvy&r}Y_Kpi{lhUKg*cm*#czx_dpm zo?b7nx7Ww(>-F>cdjq_I-XL$V_o_F4ut|=Ak&G!}=t5}3w5?$Cj7I|VHi@a+1rQ^7u zdTzzzj^X$4TciLc86lISge0DElf22^yTbDrcuex}3y1hM-l8JnSriw1iwa3P z%ggfczbp^GBph50dU0^hlQvkACWcv4L!}wgcZHfvRVcm(bmZsznu|EVz6Oc+J!X7` zsd6RK43Ctz4>vQ&RPbw_04F$bf`C^89B*29O;ii<(Llw7@n|3YH%?l47_`RYSJhBu z9Mj1MFiz;S1o)1jbDgE*#Aa#}yovlD{oZaIe*KfWji}>)^s84)6hEUUbZ$U8mYM7T zld;0&Mu204iP(#s!a?s4=p|~f_B__WLo1q7U@<~?KY%uvD{?mZ;9Nu159_CPZ#hGfTM*` zkb|M@M!-%;j44Nv6mxOIAH`MaN90CH)p>-z>A1WpD1I+b`y(AXQqcK?j&RIJ2#O!@ z(*AHpNx#Dd#ZQoF{|!bD0ewTzMT8DBk}k#{PSS%U=`c@$eDEoi8p?IariV)1C4|22 z(ANe1jL_E@-HWoX3A&WfA&inq4-pilll-@QEr^7Q*~+VADK z_maBn3GK<~c2MjoD1PZ%`#l(?e(fPBe&|m7-5EU!w7a1AEko^hW0cz3O;G&Coc7Zg zC3{H|6u)_{{jQ8|1KL&4JVLuLN^R{T=oUgdORLap-|~dJ)qnsF5DLJPD!QlcmS{WQ9D8lLMkDtDk5NQo>&1#_dR_zh*w;K%M{$~~h4niBDYfZ9LJ zDDgin=(mKPGTf*te=TTtLU%Aq{j)>R9)xaZbPv$&g7zeI8>3{o+XThWYHEM0 zqp(%b-h^&pl;qtaXdgoJ7$wQ_1no=cW`}MT6u&sD{Y~gr%o(1))|fzlpl)vBW!P6( zsOM<~s=)xNvXKdqIyMTSfrM@VilcC1&gRtc)lzm4m0iyiz5%*k(7}YRW0Yp|<$}IS zDCA0}nWbZRnV>@mT?1iqNbJw~Hd)PQavMJ}t^F?I`Wd5S%Q-rD%c4sdrEZ#|@o}i3 z@F}CD&X094#-fWErEZ$7gRvG}CC<>nc#FG?AqgQ+^0Xm8J9l%9&&ntn%I)buf< zGyp!(^fTdt&SsR@PSN<$WP{FPl)5TQ)6XqSS>eWS85%!_ZO|F6>|`BeS@a`DN&WBZ zV2VYjJM=vrd|=UOj8Y>f=^)#pA2LdYIZ+2wEjkrV$9(Delaawn%=6#pawOFRjUNj) zQcb~a%zvIgiEmRMjMMZ>;L?;#Mybc&(e!h$f`VqUEVIVy;3JC)15(BqjdRsa+4sNz zs}0W|j|?7=oTMmr+viXdTS5Xa=Ly+-9)WIB!3OAxKLI*h(eTU1E48wIW*P>$?rLKQN2lFgC#+4nWgHJ5_HkyOSiRX{x z+a%2EI+$;7r!z`Zz-u~KVA0X2R2_BRz+G&Q$DHq|3&4J%t@9>RBB2KBV39?ID|O5u zO+Ugb9W%m}9mu~9E$DDYNd*HmemB{aB^hLH?62upm8I-3hxXIKQi~2{l+@K%2g@w_ zx+~j92g@z`nk(B|2P-T(gi(^Amkx3*`YNN;Wj%H9xkU#%x;=ET(xQVHrKzL44!*GH zKt@TjZaP?H(E+Y(nhw6SXn#g&1a#HGYK!(mpLEAwir<58)55nieiYo^?!zc`N~#Xl zTC_JRl|!90q*zgUeph7hy!ZSrT%MZr&tRP`-W_-GGUNHFe3#Vl_h7xfOGL2l^!$HQ zkI;PdQn10^6nfPCe+xERu(MvDN;IO^-5Mk7wUj|1k_FxFVaD(!{rF%3?ejXgP z_x?Z_$?>z`n8iRBKSfvKB=+mzxGnj6s!fyCPlFQ{`<=yp5}dTyZ}~UTJ^$yS0B_Bn z|1&B>lHV7cvSof13h-9%`9Gz5q=g>`r|rF85Jsz^9|dPD_H)9hrS}8{7W-K!=u9oW zkM7af?ii$E&y<%*OqZ|@L1&Bogv!ybWBZ_s#qKAJEa-USeO-y}Tft+~IwcMD-8Z_8kS#h52(iS27P8-r|d56UFuc10*H_d`q zZJp~ZouVWULO6Gr`4BN%P5MwV9fAl+gO38UGpTJV;|Ko{F7o?j~z zm^=j227bV64SJ3)>T(Uxn_G9z(%9_8!wE zJFF0lvsm>|fNcZMuNcC!18JD*oj{qSV7x6;C4@N)_d;}!bd(TGu=fyrf$a>>FHbwd zo?p%u@q!Fn#1CNr<6a`&+m27k@EFFfjSu`?Tc%tnz}BAUW2*_9nx2nmJGS7keWjAU zLeIcZpiwn36x7BW8%j4ug2LC*?;)Wqd8x})iC4gwNhmoX(9ecKvwGLk>T(sz?p-TR z#VJqqRK3(VT~}36HB?R2Of^?ms4LY~>T1R$B=^{{$U{Y5>co>tGOXVr7+ zdG&(&hx(`bm-@GQMWw3Fs*CEXw5qSF;o4L+!u5xcPpiAZO@qsiaZOS8TFVrg4M*m7BM9E)E`Dp8pAW`vFzM*|J zQ+=(zQ-{=HbwZs~rR}dapc-NhOjeE6Wtat(vRBF#k5;xwi$+zA|Iqh&j78=HPo( z)e&Um|7YY5m!kVR>V8P2)&JsJMg1Jtrs}u2{!l%D>wW4$ zTpv)6;F_ZTi0g~$aa>~<@0 z#GidcUuYlnMk}hQzPNt>eGtpC&ejK|&#BTMGR7}XACxvDoo!aFRN}l8ZA1N`>vo0a zQ@hr*Gij`+K~bBL`SZR~o)TAM%$EEVI5$}b{vVOGbSoGPDQjHdNDP(m94*Zb%C6TT z|0ndCs9uL0+O0MZRDtB$!#YCZ4$&&UP2`nzv*dZKoC{G=lxqJO?Xn9b;$XURa&w zT(1!4rDx^5q|BVl6?(GByM;XUti_i$UsdGifb7K-9lPzYGOxyZi5{n|i|y=C`;*jC zP1dmzwh*XH8_tuNfE4L-oI>&j1_U>ul zJ{02_Bl{`QJ1K?tP)hEZ=CJd^W59X}Xys=|L2Mf-+!w`H_f`)jb1$8KbIfLich91q zcO;*E-WHz=Ebs5r{tM4dVv*4^)P7h-?NZ+$n`0-TXbaC}$E~FI#q#FKcNClhB~QMp zSOrC%eCzO0@MzUo&xl$F9LAnsWG0YxKs$9Xp>`>j8NK$B=RU1G63xgs&10hQXgGdO zv*5||9uKkFtk2qJofxal1sBlfSp3_bm48A^{&9)tuk%>^Z#^sj@-g`*T>$^Y81tYV zec#Uvh;W`njU9N)Wvr$rS;_Ad<8-}qdg~>dj-LIZ*Ky&*b6F);O00u1b2d+`tP{l- zOEY?c*{QVcDa)KyxyWoD?faz}^WLbnX_drtTmM%p)hePn*f)R&qPU#@57$e%c@0UV|c87$X{VRz<$+-)uZsOK8}5@;$LOFguSieIwNbgn!5g++Hqr< z+EFjQq<(J@U$%a)rWRwI)HJKOT;yL=va9+Wp6G3K^cOK<-bt;AYqI_!@2yUQzqh*E z=_$Im`T};1tLYj#+lw>b!$iK3Dg0f`5?z|VEu!nz=cMbK%cSdD&WXpZ7r-M){Qxr) zy!yD(^Gd#@vg_lOQS0M7W3H8MFO_HP^>IXZcb`+cew28=Z-)^M-`9FO!r|U?YQz7O zp$$JdCl3F6-W=dJ;iup)F{X(VaIabDTe_A!bI6=w?Y`)2@vxaKB6GxZp4~Yv`W;>A^M&27xRCE{ zuEzH^_FdP$mo_hTpDeON@B{SJeX3FnjYQ9)=c0=(7flzDvGaZG3C8OE=(gU({eBxi zD_+6%Q+TDdTI}Y&qBcm zH3l>I18N+uFS;3gRHBDx#LMb%)HnR;iKV@rj7+SEx5*TIi+Q#;#fdTXlaWZV6zAK= z(feJKW72)^yy@P}>zBxi;e(iTvo4Tsl8MilSxDd0V(9y$QuRIcob_EVk#;cgC)U*pg-y+w+3jR*45Td`W{;T>Mda?N1zU+`h^fD)=US?mQULtfWl_GDr4Dx;w zQ{K7fEibJ~qV29xDe^WbgS?Ak%Ddpa^SCkzQL7lj^cEQvD(()z2@8 zYNGlQV=ho@aJ@^d!?nGe?>6aJGishL?faYP6|21SM6~f$Ou08)klYcfTVhh(Tt=!p zVp82!MylV&r20)6scw(CO51utPris=_qaErU1feFicsAjQv>_TsDZd-P$eKRK25oM(MR!pj+%SiQ|m{iACzg?FR!pjs%Sd%FNkV_dqZ3i zZ{LjOVQoZbtvs&gB!#fsUECX>)w1|1Zs)1weWwJ~1KzP3>LYw3mmY)DviJ*sOGr?1 z;?;HFF!LhQj?B3WlM;BxO}?9)e^H)fOA66kTn3s|)C7F3_<&l9cYUpv)UaOGOX+RtBZI+zkRW<5+yj(~f zv4o;g@HYB&HSay#11^#1*Q{tNINgK1Q4}{o{wVQArK#nJI%#_`g8Zw_Du2YLzDknstD?_;+mKY+H;2~S zU}Ig$3l*WaB?i6CWuUhs2EA=%pm(w5`!*>aV^T)sH%ax}JoErg%8K><^4WaSjbpU8 z(RsJGa-p$Ud=zeu8in_MPopqm6MJH`Y1etTDMD`(P6#R*t(K=R+-CR3kZ)fZ=HL9b~U=v^Jv-YYM-y_M9p<>*Ypwz#%b?Qp$L z-G*x`72tZKx(nCV#cZo3Y>ZAKXoZxb(QiOX=h)tal%nU`AZ>xuZ0|ryC)(C3SAoCM zqH}J^@74~n@w5`DsOm7sXc;ap-;m?msu1U}X>lxWbs%*u=)sPp^KWfQT&tdww%bD| zSE-J;UajuI^_DX0zj3)F)a%dbP9R%V*frxCP*twi^) zUx-U#TRNMTOOl~hxiIs!=O!2K*Ge%g>OW`C|E>Q0ak2hQP(Oj?v~!koA8h(&jJXdG z(^qsgmX%oT9N%^lO@9`(7dzhTK#mA?I-R;!xvDX&gyw|8mh#`y+|P<>E~$hz7PZGZ zRDV{sTXm*QN4_7TlEiIZ&Clk^N(MitdXuuOn@cPP6*jd zi}SXbn&&YZqMwIY!)tuLjA&v)E}jm3$5iA~wDSoEoNzSdI zwK8Yn$*IxjYvE$sR;CNJMz376;@peV=l@1-Q}B{{|7zu8AWj_RYT=RFf% z96M?Je?W%*Q8JV_c2#&}+EGx_yj^(hTKE(#TDL~}+AqWSFNr(70Yz4<5nhqGv>M_8 zqW8C><1MNro^6l2qVn)0|FIf~k*n2UTx|^T?U)(M>p$b_>%zPDMdL?*gSgob)%2*} z;wXI1K+&E1N`>sPq^I%4ABz#4t;UIfCF$(!`|AI#H7D6JJ%edpsa!~hvby>HG?|De zPsH|;N|>LE+Hld8?%C$(|CU~dK(7=F*7pCgcO8IM6H9wHn?tWk5ftg5AfkvOA}AtC z5y4&%yV!g0U4MJmXYXB6v5UQ-*xR#rvG?BnzsY2>o0FW|Ip;pvoBL&VXJ%(+cPE>A z66eZ7c0Z9nYt()Zk=>8CPHltyOYWL)eYe$e>+4X*W2dvDx#2%p4_9mAZr+l~`xImb zt?ltrT|HqR&Wrq++8~~^O1(Yc0%+FiBCOl1OQQB(hV>-%Ddxh@)cQES{#0#%^%u#J zj{DAps^5}ekEq|m8~Uc;J4SUqN~&M)U4a&LQX?9q_v+`#RgotvGy+eqi9A`p5qNT4 ziy>&s1i{n;CgB zxIv<#Qv2H5nwfY{Th~$H+5e8HFIH=izDRE&ylvbC{e5b^g&b9jEu^mPzXzTTSNCE) zN&N@yA5`I}ygwR=4I5-6>e?q96Awn7tluD>*qMiZzr!=nz*^5=b#2eXXi0nZDAxGi z7uqwb!ejh+)U(GnNYB=_Pk4-ZxU$sd+AV4egnv zjz)VbJr}$Y_3Wqy>Dl_t)Ne(eEYS!&c_;E@)kfgSdyyv-8-XVuM4qhE2t4^H@?@0@~ZFWnk$uwPwAp zM#-Bb`5F4JpjWGJupXnn!+N6n0qdjGPgozLRuAY2`=79$p{C+GL03Ht9;~eC3!+Vu zu}U2a#9yfW4UwhQA6T!d z{=#}k^$*tg+H!OH#+|`B{f#^RI{bpswW=nFyPwq{tZVXh`1IAOO2tm0IXy)&3Ez7j zgmzZ<^yFB`H0<+yO(Xlm(ff6?-y9<{Lbb%2ehtEJ(yr^ZuqNtHjD26#8rsGbeXF-G zzL%4IM;y%wBcm_r(6eI2@0P1npSF$1RNB)%YR~JKC+&B|e=FIZKT5Wz^!&ddEXe#n zqF(cVrTVNR`i$peDgoqGqOt(BYk2UXPiU|6sJQD%HUe~B%dtGxLY_BU-wD(5Cdj0n^w)gr~(R+(k(R=A* zm@)8bQ#BUr&D82xZ=ZTTW5p=a<*G#KBc^^OkC^H@zl?`3m5cO=uwJ?S;v`sapB$&w zb-!5Go}XONwy#yuwy#sswy#%F>mTFFX#J1I>Kb($G)UX)x<}`I`9jfbSKh1N8=>8m zo9CuBNUzs*%%?R-+gqpZ8I`&Mum{dBnS^RCN} zt76}8>zBR`{u_R)Q|b;Oez$>f8I$aP>T;dEW_@Mq-B&fU^Hjay9PpG%gHM7&c-ge}E_ouktHCFLmZ@$yL z6?#jnZK6JN?{rT?|8>=i!EzJ5IM(g;l2{k?63`GP+h|qyx@*?9-t}&q-IlJx*Jb$Y z^gPaEqLID=U;8aR(rx0W4cwl|_6Fbg{|9~2B<_bXsebql_f;mMAFJw*W;xF_@Uskc z{Y_16eE+##zPC!v-`gTu(!Zjp|2ar)+VWey+EN=!9RGQdUy~8Hk+~GUQIn0#C99l+ zTBiEk-DlRnw_C;cp!pXv+edT2;^@`u)tXqh)SF`6D%r|qPrM`UUea4Dw=scgquc7z zXOwCEJ4gBlMf#^i`ZvkdziX_2daS=$$um~zo82SLZr`i`&CN5OPsKfZ^4#7(=v-2F z+V?%3zWF-xeFMx`*}mC3_Wf5p*;1Rn+1Js(7VFRLoBd<`J67BG65sB#O?7>$sjB%b zZO7f4)MP)>JvDz;ZKt-^{uZra45Xipsb6~*t8shM@pYiHZM+$c|NrI2*TM1lUm3?& z%aZXc+s2`h=3DSC%;xdiX!U$6?jvafkNmvcz7Kc$e`3`C z8|Q9+N5=iXb-ewxszcHvb$smWo_QP{ZFz3r?SOHSa}GY{s?DtWG-kJH@wttwl}F?!=&t*Sv{u=DkcR(x z&uVtBVRWUp?7SX2Hq%2}WqPRQ`_bw~_^*2Pkd3@SnV20|Wz33SH8}$tjcv(3b6u0j zE2xvui}soH6EKhW#o3EH#~#UNdI|QudFV>`WST) z*2k*vu$6VyA)etmNj1Ux3Uxkwuupup2?BMpIz<&f`JQKkwOtlaQ!>W}f5 z6_3Y_=(h!u){cxuWm@iNv{0q=4XC3&_c&xWJkzOh=m^i+>z`^ouIZ7;>I-VAFa7lp zcVzQM;5}>;e0M{>A3|TP$FI6D{yOy(!m^03=K3J4pG@vb$aSOa)tB_KPdaw%w-sbP zTR8GeT32(QvYL9=NmK25{8P*r(&OVWgHV6lW2>i{8^rrK%vVq1m}Rwyn|J@BdCmy+ zsFU}3nwD%ZO~V>Y({gpvWPA3xq-US0vS&lZ`x1$#n(am8sEX$X-k0#K^#W#y(dt_q z@mw3v6a2O2=doSSNVcS%an<2s)l}y3swo?bKfMt4SpqK8L&<4@|)R`_7`{GkYXZtN~x8idwKC=8+-#T&&+ow!XJ< zG`EG?Qnki$#BVtAEI!I?uHHr6_Ue7CH&-8Fy_Na|>uuEMSWj19VZCjlZGDW-TWV>2 zvni;z)w}9F^}hN5`&4&saL3ynn{>qGjY>21Ev(_Uq)t2D!x(hc-(dY);)S%SxGhZ- z_u==@f^URHeQ4)8gSm>1mVYZ0_g`uM-FU5jw#eICzKgcldCNUQ{Hb{Xd&`AzSAPWd zm38qUZ)-^(k8o7-k7`VH&N)gM@I zrT)Tt8}$#?)0J-F#@6P!vDLh~+R$O2Wz3IHIezEJTmW$~Bi>(0bo_v=gTCVHyw_#_YZsGw8frU=*{!>@4|y>ueZcy$L$HxkwYKst^P@7WOrUm_g!n$98)6V`RfF3 z-L&nR?U&v9P2;_BTUf=sfb}uz1|0iz)fZs)vse0x$6M+x7}e_-)%!80Uh&qQH{%}> z^^eRfom&{3^WZ&0sTsCO{5B50GjRiI6q4f%xvEucE8RCdE?wZMjLY7U-AN_KC2jNe z8re+O`M5@P3aS0K^h386d>pcHi{ia+6V(H)Xr=mK-A?s_TpL`??T3`!II$Sg|5L}Q zLvZ$Rsya=buDaaC`RVZDzUj`hB3 z9LD+wbs=KpOZ76=->AQ_{#IRr7Jr{ac_ALPPUz$8)y?AZ3Kd_;It-fZ)vFOLvRAB{ z#BCo5Us@$SAnjTyr#<3Hml}F98k(0=et$5rnxFLgRdIRH8Z1GrW160tNu)R zQM%^HsOAk(&0nzoRz04o8LGn~&%Uh2vjwq5;@Mru?yKDX84~r+jZyz}g$}L%O6hMJ zZ_!7fW_xuM*5l)?djRH1yLDe3Z{6~RYwn3xq4!#~DK!3&%mc^Zn1kMSH3?4+%G~&W z*zYcnV`VxPnTGw|(W(&N;XOWT-Hy=kRU$pZxmK5!d#j|JwRK{~R#SCy)Vfon)}4X1 z%wYL#w7SmD=(4>3RKYth!%O$u>ruZAN%h+WNxwCX{4y7oG-8%wtClSOs$T|JB?9l1XRPOIpczFl-g-$XqFeJ#~RR6Ew-M0SY)M%nj6*rB&z*6*6q|+xjH1KzXdlxrbXiWY9)Rw zDPhO=XL#z4Z{Bt>CfY8#VAQ@AhcJ$@bm@PJD{Q?J1VK(pNo{+Z0? z@+5_O?~3oT@RfQQ^Dv(E4@~L#+tI^cm*B4u-VA?6sE>1Iv9vw+?o;|Hjx9^*3{bo7716VvhuVG|v zO!jI)OZuAUa1|n54M)OxetnwbSE!n_q__0**vaUh9DU`2zmLf8Y+VquUwhR&lI;b{ z%jyxBaXwA#H&HCt5)$oI>qzbs#KW?>XG*T1+Jd*CYLE3ssv|s_ljyh@`?}d`0Iq59 zQz34Q{*cpG_O7oyr_&$zrA9|ruS3PP`RN{Mm&?C5)qm1&3&#DJ_JPNruUn?$CsZAy zwtj=Qu8>@}TBs#o>Dm{^AYCIq@8QJ{>R;NouYn^^K33+t6ZlCU?n~eT7_PmDY(aH{ zhH(pfmXk$Ya!Puu~tw$!Rx4cM{=LRlUeE>NIaeB2vuM3hO4HaS}*&ft>bX4 zhQ0!KAvFkV`>XVU;L>rka0lmd3-LU`M}0?Plzvdx!HPX1OiLUVNj#R45DQD^TCiK_ zGA-?Q&O|F8m97_Q{Ty1qP1;kq54K6|)Q zR6oGTmhy0g$irrkuzeTCquvTsJKn>iaifvpQSA<|?5K{2xdp}FG#v@=I;oYg?yS~^ z-QrQ)Jq=0ghuBZY{@BR=zNpXk+4Aa<7eiC_(>>ff z>Y)y)_7~K4xJo%jjYsX_Y9iK?)OpY`H1Rf!zjU1b#<6^>SR!i@YUV}uTA;6{n!@JS zN!(0M+RwJviEOVI*&Ywu%OtjKWNwg(Ot;=fQN43h^`zempxS<)8rwB$8tSxmju{P( zl-gmQD8$!kHv@khu4!rYiPG@hMwInv3&$ggqWfXbj^0+$I8B09K4RcFUn?4gS0QPm zFl~20WcOl7Si9+2tQ&X>=nJrRXEE2x29cHj7Fl5rczaz35`jKHB@xE^h2KH7_b;|V zJ66W=lC*=jw~ZqUFG14vl6_!_v5~~hMG~$LTSY#+SmXn5bLp7hHtx$%ZI7|(tkPT5 zPVvav(b*+6I(wkbaK(F7ne}%=o%X4#77L*czNP~jZCh?{4vt##NXpN&#DbB;twj>N zhvcnvZ}>1qrN6x$D&9WcKs~#C>>Ibn#Cr|#cp&z9{0&Npw{KC;#@qf$AF*BDr}D9q z=)hIUXnQ{p-b_*lW4(2&L7g0}$Y9E7oi#zpJ!*(}ZofJuI0$%roXGi%I^hoiwr`-}-7|+S4 zMLMQIhn<lb#`B)EE!%=T=(hjM2QEol< z<&s?9<`~0H>as}Z7SOqpqw`OUO?!1k#M=S9r5qmXyed~G^RCI|T?c9(bwi}{B5!t>gvb{5G_s-b9C$}EA=iXdiGwf^I ztNSCJQ=rp+Ju6haH+m2}Y#-p|?TvPV@AM`UoDIa=%)_~M9*wAvN4m~|t|c7bc{_Xp zym9y@j8<ivSZ9<^7`gEw3iw~KYYl&h1EAYO@h z>Fq??_iAoE*75Xs^=dTx@*csq z>t|@eGiO*Iql)L2KO#GSVLe*p4*^Cd(|$gHxhoja}sM?AkthsKX!=fb&Bd0&t*It zbpfxBS{XXsIcedj#-dnHQagcXzqu4Do=JK{^$q~foln@8Uf^|7+k@xM)qNsrzewk< z;JMqf8?$^3z>clU|E{C)h1*AZRi_@;DEQJXjI7-Ern;GX_U~t%Ui& zJ|`2Zr9mC8hDN-7P|qIKoA@|Dd|9qlaxMxT9Tgut@bwDv{V{F3+8!B8y^D}B@o zk;Qbs+BS_un|Oa6#(S@oAm1qy*P|mXt72U|2g~sb&zr-G;*5_`R*UK#4W2zlu|C-E zi{g%cWM^U|pPm=2{G@1X=$V@0KAW8M8OPLG(9=g9kA8MziogH0PGqAv7S{u{liC35 z;i~xfhqvF2BZ=be*NrKDI?j#}Up3q$s+YdzB(c9KczslQj6%h6v^jW_)P$lqVtZSH zH%4s+-nGs?XX{AYbgXf-hPJ!gA#YFHgV#x&2A;b;?Hj$JkFRc~&n;!2vtv}Rxb3WS z=ZIH4U$|Gu(pSZB6*`(@dB52UZE*LStaH~$=ky{!c^r1n^@YcFPw=wy%yBrz=%n_J zc*XMt*V{L@9v^?~AMw)1A7Ol!eqh8a-k$la4mT=rRwvP56kqlF16Qo<)8R%P3*S1b zyU@~0l94p(VCe0r`e9FWsYB&+;gzBH6Nk!YN25Wt*T9WB6dJTTJn~O`uv^lR*k0)T z#i*krxnomuVt=_J`y6}eC^zwykK>?WjN=u{j!#7>&Z1E6sD`1dk@p{tM5mwbLIqh=KEZO%Xs(}?liHKWc#d7Rn}V|24a<$1R)Y}*;v#8*o% zf~=)lk2=6U?F%gB98l<(TIShvQ}JQt&W9YGr5kl&H2xQ-PMj-l1p7QmwH5sYAr1vx6)FsO>A?VjX+Ji4O_YEqjtN; z2sg&MB$`_nMKd3h-IVGdt53dDCR<4Q=)|bs;m0_&0(3TYW)!B5ETXdKT~nS*uXRcF zgjh=-Ct0uhpiT6PV5!}?s5Zy>;wh@FEq52Bc83yjx5PbXYyO6-C-nU&OW8Ujb8F-q zMduc8N~w&8*nArQDZzb0_?m zq8>oasW~+t%G7)$LwPKsbaq-lJJHTPzI>`DWwxGxUa)%$>)Yo^t9Y+6J|!nx_>-wV z5$aPZs@3@nJmT%1qir>Kl((Hcmw3*$`xn_}>S9Gy-c$1LR_uJoWAZ}EBbi~E!@fJi z@JyXPXEpJ!gwnqxux)w?zS6Z-OF1{`IqvuMi~610J~`EPiS`YPWLd*TMO1F-B8VCH zn1J{5Lm`{p&rdDV@Cy24jC!@GSJ<;HA)7ZUuP39zdyC~Dm$zSd6LP#4V13)B^vPc3 z5A>O>Ek`sRv7dF1Xt@1Lro6X3{WdIdJn<;Mn`)1hljnqF`%Yg`m3eaMq8X9r$)PE# z)%kv8`)Fs}KLq6%+*g*d+^NXxxkcW6g0g+ra-cp#**?<{s4r0N=*$LR70L7Quta*G zz5#zBN1l)NE&n_4X;$VVfk5qpmaXEHe<RO*KPYeJ*wd}k{u-3s{wh8a;A<4texay-)1vZ#qV_j0(%%wgw?A8>?E24F8LYjw zMf~u!ujXs5}_uDUN^ripFQ@BKc*C%F7m&hZU8F7nMh#Y<~+F z#AhVd-=Ua`-1r{}dFA-GQjxyVD7*17rl>p?WjB8LIS^}a^&? zvvjL(GWf3lYZcY+QPjWd6zN;9NPdGN{zgURsVLiXxj;=r+4cvzF7>w>O7{Un(W%!1 zy#l4q1-=K?GD^(=x`av{1-uEYR#56f;0IuQ6QwQ&egc+js??dl_rR29N}UAE0a`a# zY7%e~@GMYhq11}Np1}RUKfvggN*xH?2mA?)Zl%-_z(YWb)=EtPjshM9!Zu2+3LFf~ z1m*&Zv{h;{a0GBW@F}oxJNN+{2iyyM4fJZS)Vjbiz+J%Sz={hfwF__w@CMLwLC}Dm zfs25bffgN54>$vO18Ck+skMP)fIERtfi9ikCvYHe1MoJ`t~1&K>;YU3ybKf;LSF&f z0_Ov>fggbGU6fh}I25=Zcoi^Rl^P681&#r30p0>yFRaw^z*fM?z}>({K-)!>S^?Mw zI2D)$dm&3Y)c46rG1 z9B>=(F3_TdMPyw*b+DixC{6YXwzG%;lS3wDZo9zT%cVarA7eL zfzyC{flq)1`YJUN*bX=ccntUf=+;lE)qxX%`+zTjZvB-S3+xP>1>6VB1zInL_yG0= zE(T@;-vFH#S863-Ti_JnPT*aj=>YUQun}-1a6Rx6@CVR)pi&cogumt=74ghWi zz6XX4Lc4)efR_QYBw`lW4Y&aK6zDKmsZqc-!12Htb}Dey5c zaF|j%0k;5O0!uHi)IPv0;2og%aEt?RBk(;iYz3tb0v-aIj6lBtrvkSEzXBsy#5M`c z23n1Tec){1zrdfslB1N`0XPwO8VFZXsvj^8*a5f>_#7CpGW-J01YQRI1eP3)?G~5; zd<87Aic&iQ*8!gai;cm!0#^ZZfkjru_66((+zNaSEItr<2AZyh`3*Q4coZVk#88{bs4EP1;wE^hBPQW?9{lF(c%MH;+U@CAVa6Rx0 z@DtE=BW$C<*1*xgMZhD#r$FnCl^Oy}1f~P00`~wP0d1zD-N2T>LBLhO^T1C)r%e#M zz;fDF91r{lxC*!pxF2{Lcmwzp_!$Uy#c>4C z16UGR5tsmM2uug|0*(Mq1ug<^0PX>v0A2*%1HK0S1X}Edc^c>k33_0s8<)0jC2O0M`Mx0S^Mt z0&fAI1HS@I_CS9Dy?~{FQNS9&#=v&KKEP4H>A)qx4B%d14)7ZAG4LZ0?1@+c76N($ zO9I1zRe{OChQL<9F2Mf4QNSs{dBByx&A=?+QQ#TiHQ+v<3b+Nh7nlva2)qe=1bhSh3h2Gjw?Jp02QUy=4j2ur z0c-$l3G4{$0~`(<51a*D1Y8Z=4BQPo3OonA0elF24g3P&Ap_MC=m2yB`T>K16@an8 zn!rZD*1)d7e!!8yiNHC)Wx$QVUBDy2v%u@X2f!D=&w$<+?EpFhy?{Z$^1v8iO<)6H zOJGM}AK-A{MBp6Y65x8^HsAqZ4)6-_4)6)^J@7ja?1z{J767^ey?_D05MTvh6<`9e zHn1_UC9ngq2XFvz1aLfXI&dCv8E_pi6SxO>7?=aR2)qG&0DKO75Bv@U`@=r40MHfa z1q=X&04o5i026?;Po{_%|K}g||$o0PhFG+bNN@MA`~z z8$98*fGXe_rzWZ!u3pez572u7lJ-HqA3#^s7Y7C)zXY%(uoN%^^_E3Sf5VW{JwN)@ z{(A@D2nHM*c9QM@_%6ST$Im`WiLW{X^bn7UJXck z9rA=5A%7G4>{j4TU>5KI@CYy)cnbVyAoo0UzkvKpNM8p1HQ+7K-vvGZ{Uem=w?AJ1 z^kgu7d;Ld%?p6N|`~{hR0F66ygiwdk7vWkWZL15a1JDIn6zC0Ff4rrD?wJihx&%Pi z#0Mi?8tD+!UlwvJK#rb-9F24=Fdmo$tOcwGYy?aLwt&pmz_!Tmh~Eq;)gC=Teq^Pa?0DXZ@7{AVlqYg+h8b~RR<3QwF zAZ-@ql?Dyp+|o$3?gF4bWSHIsDe3D6(3>{$=u(&J!E@ColH-&-BKwrmc1$Vhp>$EC zvTaj6l52^yBlNTbI-}e@k`EO8h-h6=CLYmy0lkq&UEK%h3y3e=4h_FG{0^wiPWzaS zxdgNTZKnDf^91*e^b>T@oC6;B73HN4$rBbsymOxVDdHz|$igo3>Fx@ARDDrL^30?D zFj3oSo|1geINt^-_aDnF9F=K)!!cM?&(=XZlKNx=ZA<#HE6Ut&oOVE&`jBQCnoFC- zeE^@(CkB0DH2KSYLO$SFocn{~Msr_qj4TE@?t?%t1`o)KKF~~Ul{ONc^35Y2jkd^8 zj$<=UVO!!YjN0B4^|)_B%=vC#F@ND4KKGyHOIiAp>X5wxQi?{2LwbjPYuHDs+edxO zI?x{(AGp7nFaFV3k?xkzNpVcAqrRp*;xih94xn{U?BX~xk|H_kZ}N-t)Naain@JPX z*>}#9Uqa`Uu96qf|M-1Yq&JG6XuGCuf&3%CXeWNBZ|zRNgR zzsNqdnfjIbnRHWM_C${RQ`#l{%Y62o`p@#Y&n;idG6qyf^mob8&*Q=M#WwlE^`ibs z#sa^-P5OIb_#l1m&M~yz&>}Rd(;sDeZlFK<3#ld=#WAJSr;?JK@Q6-*y8u$&`gp7Y z)aiiQ9G@)T2IX}Bkqotge3U*F-SJESwi#-gHy4ZRQ2WJK(o4S; zCZ89C9QnN<#ve4@4S8xqH_*F*hBEEf&>q@9(HzX%4z*9(iMYa%hC!QnA3+i3`rIGS zRS`{mB)^5``VLxDQ|w8K{>Q%3+NCl@W>eUdxiG|0NU^T|I8r1}tRDO*!TrOHx2pfq z0r;0nl#i;%wV2zO*K}vG(f{)hu%GGS;NGYHkN&ya6Jk6H=_--1&azM|OJqtFEVl~k zyTv-^i_CE`QJ!S#tlzCzWUC66xIw){$ZITQs#fT3Tjj}vooCoyAT-O)-`u>>j7RNdM zK%Ctz3y+3g){7Q-6 zI<+0n@^`@5{!VIVwTs#n=lQ#7{{}6SkI!qmo^Zg_7 z<(i|TC#>i_LC32TaK3*M&i7A=-}HHgIumF8XRC8?-hZw-4`=-ss0-CacuW5!IP1Sm zU5<18E7esv>%Rt1cV36zN8f<6{TVphzZvgAoQX63+tlsq4xIJhg?CKdgERko@r1(t zIQxH4J)|DS6@W+8W9o5S1$Y8q{+NR+0Z-#fz_aQ(Tnl(Xy@)FTFXKDh|5dNzTEOe- z4g4PPExh&oo#egeAL5$8T=g-Y&ihn-ras4&fiLk6wXgB^&~I^d;CnoW|D*az{fsLF zzv6v_zpFp+TkgNq-?&OZL5nBybcmm_H_=TsW`Es6x74lhh!lN+wViIS7tjmp4!Wc6 zq&w?{bQj%KFRT~Q-SncmyY8WT>R!6H?xXwae!9P2OfRkn=z)3(JxDL92kWKu(t3zq zMi14?>gDt>y}TZ-SI{H$ih86TrB~7`>(S|ObRyGd8*dNLpsiX3=n7pPqz=`u2_RM@ zxti#zN`~yvUsW=7<;^R-b@ivZdh^m>iV646jS-jb^S%e_+XEC^66<_LKdVvrl**sv zU7nj4IZ9o6h_b+?Q=aH9t+*^QQr}I5C#lO5JwkJ3U^1~weIYVcr6T91qNl2QRq=}J zQyJH>BY%q1s`Lm?^ie8*!mDXY^+Z;52u;#FezB~`NLpN1=(R~*8r@ zQ~rwW3!PGz=a${PD^p#bV#kdikr$ejt4pc9(jIAhaUJ0ky_9~c>-yyCDArp_hg(PT zHIWs&?)XWbY!mo8w;c!ZiPD-qk@et}moV zbP2swN^LI1tBOwctK!#`*HC(DVlS^x@@O^D^}iz11mi?-{VguLysGl^s;}T)%D+4x zY9f7UvP5tWiY;9a2DXxe!)YyU+`dw`vni+9s=DvD866tTztRa zCEQ_nBD%A{67S(I!dyIM_!#ajJdXPbzv3>+&W-GT!76%;UR96PtLfGCI6YoZ&=d6< zdXipKPu5fPT6%50j$T)7(^A`dIyc`Zz2n=o9rx`ec2IJ{8O9z?oQ%Qs?OZ=yUaX`h0zXz7WgB`VxJqz6`hm z3$3rw*Xrx^_4)>Vqn@E}(l_f{^h|xLz6~|*(0A&)fP3^TtY_%^^#l4r{g8fGKcXMi zkLkz3eL_E}=jf;O)A||xtbPu6WnR!P>X-D(XyJeLtNJzlx_(2yso&CX>v#0K`aS)= z{y=}IKhksc$NCffss2oVuD{S<>aXZIWG;EdqR;4HMbdGMd$+~B<6e3UK>E($IVx(1hmcP>gKbuMUUg4z$|^RZlv@)_XV zidNnp+!4I0?+We?UdD*Nrtb^x4;}~}3?9`F2hZw9gU5o$gW16o!IQz9;3?#u37!p} z3!V>N2;SDu1}_J%V0kroEtsQeO;Ya!?}GA{emD3qcuvm^J`O$!J`FwtW(Qxw=99rU zkeCBKKLkGp6g4mCUxVM!BYy;c27d*A2S?#YHF#Lo7@%NY(oIb>)7-Q$Es?f1ZA@F! z&a^j8&4Q)_=$%Ywvykaxx|)Rz^~Iv5J90fuFRZ%;eN8{pFIdbhZU$gk!VEG?n!#o% zv$T0uFJp$9WzBMCm|5NoH!GMC<`zBDj4~@>xkIml^{Qs9S6`?dA@1r@71AZSFC%%)RD5bH91OJP4VG(Q}WQ z$IRnqwt2!lY37)xzQZ!@o&*UanC^rm^sylvhw@0$0_`{o1l zq4~(nH6NQ#%%|ov^SSxLd}+QiUz=}0`_6oCelS0ppUltZ7xOFDzneeIpD6#0yu!oe zL1@A-EQC$MrbwHIEy9-JPo{O)CTttF3)_c}nFYfRVaKpj*g0G%>=Jej7Y-K*yM>E} z-NPPX&#+h6JM0to4f}=t!^OhI!vW#IaEWkGxMVmuTq;~T91<=Q4h@$LmkWo5%ZJ0m z6~YnWis4Ae3=UTgM~AC~W5QL#u~B(kI6j;J+8W^`NKFo>Kzb-@Ef=l_nGL|%DBKvF zO~Ps6rr~Dc=HV9Mmf&n1ZWB%qw+*+$dWUewaHnwRaF=k`aJO*xaF1}$aIbLhaG!AB zaKCW>@PP2Z@SyPE@R0D(@UZak@QCn8SU);E23GzrJPtKa2u}=8Lj9JoK0Q1=JOlaV zA#o0HZg^gJet1E6VR%t^ad=61X?R(9d3Z&5Wq4J1b$Cs9ZFpUHeRxB7V>lzcDZDwn zC7c=F8r~M(4*s3tUE$r~J>jhI-tfNg{_uhD!SJE*;qa00(eSbG@o;wdMEGPlCwwY= zI(#O4HheC8K71j3F?=a}IeaDjZ}@8XTKIbSM)+poj4X^QtW;RJFuJe`q=yv77FH{)jymHD6ABXxYZN9G)+|geOew5Y zSi7)JVco)dh4l*?6gDhuRM;5OQ;;rN*bM7#g)QMt*8(5);;EeyOLhEG_5Qc%^ot+= zSI!qqnGK7mUq&f|Gh=dWY*oTo#Gvh;ft{_BD#xfaHP zCsw1s?$Nqu^otIb>Wk;O7RR$(gYX>J(s+hzSvQRw!soH)R#D_lVwVQ za|TC*_*H0xQ8=o+OOJ}cG_JQlCq--grUy?t{2xgoJUDUmv&aB|_V;6yXTj59w6v>b|CDO2LvDzXj188`@&zqyHDLa8eK zE#tXTTj2S*>Cv)1o}QE3PI!7Q{Wl#?(pCMpcZyBt&e^{M6Vf4g0`G7vII4{Pj*ZsG z<4hXA^N;eUsx$D^-MKhBz8Fv0U5Rt#>+w__{oMlGhUe+-iQe=h@(~N?!jItG^-1VR zFHhrKnEqbG`S5FahEA4u@Fd;)Sm^Jg=nZ$&yTLq-K>Xq-H~u*8$dkq!ffR5v@HDyn z)jtA1_j6!o4)hUNdJb&(2*ev7l6`OfUij-M+^gRU%T~c@-S@)Z;@MsLcs2P2^0Z`UpI*isQfqXrW$_Tub~8Kq|M7as~VzKqxgyJK>iD zS-CC=Z4vyMpgWdcF{N*mE{0zbEQwzmP|ce<$oNm_^%mp*1~#S zT<6~y*Y`=%YE^1;T<4#T>-$}bmYr~&pJeyIHU9l@ZC{o{aE1SHEW|qs*Y;~3fi*c3 z$&bJ$6^uY?=e&$Sdj6#JUw#Buw--J>8lCFrz_i`E&w(f6&JO7+{~Rdi!eqVrInYNS z^;3E;%uksSJ^!z65qNT$Bd~INVIP5bKUkqY$AR-E0#Ef3Sm*13`Fr6O|Khzcy=kcQ zU)|=w(|rUsa0L3}z;ujOcN}=8k3b)RametM^3qph=FMLCY#)I>0xKGUeh$Pn)8wx3 z+CgpZ3+EpPw)z(z2ewM@V2et1I}ZGhp932>0-ODdBanWRRr;@P5y<+=cRldme>G<3 z68Gd9?#YBo-IXgHd(80>ShJ_IsJG_j73uwa1g1ij-tgEE&j+TI;^{zo4`lJ5eUh)- z&j(iK$%Opp1Dp5=Oa+FIz~U!Vse2k`4$P0h9ef1(2(0oM>3JQ2d-@3U5m?a(Jk&>^ zkHCsX;6XkDQxSL`-VNV)&qOZJ*IDNi)p>j{CvK#a6 z300?=IobTHG5$=X+-D*O_&G2YojwA~9fAA!2=ozH(c?gWPb3w94fbozv{rvbn))OE zdf@hc4on4$-wT&}FT9-3w3m5$GeZq7k@_k3b)R6^+1AJ_3CNRx|>4^bzPI zu%Z#Tua7_4ZM_@%Ga2FqeJ_0Kmf&cuAe=C;?txUl`8&mFI zD&^mmYwzd4RBZaYa^=1&*TP3&Dgvu}Zww3j-wW5}UHbX&Oz;ty3czaLBkd!wq2JnZ zoSy?zA?WA8dAAqNp9B3}xl{o9IWXsI4h{8t;rs~P&Ch|U5cG3kx#vKCE}RNLKL?h5 z4)oUpeFVx^^v_892&`-b`d=#f2&`-b`d@4M2&`-b`gbOzBhWvcHSg|;E zAA!gF`@*RZ^!J75-5i*IPsG2yEfs+NzHr&^3;Q=%`Uou7UO0aa^zV^QN1#6wnRk2P z{Nq6XO{H`M`s2WP7lHY6p#PeKkHE_Ah5c8(d<0fD0{8bA$`UtFO1o|_PQ~>%X6XxN$aQ<=N4t@?yg`htdF88_co<0J71Xgq}?7u6Q3P68F zdLHhD^RGzzGm&%zo~N5DT3TX}Tx-=fEd);cB1+Z8hWfhe1$vMgtd>^GsAbhKH9RtU zkyh#wy^T0~2s5%!dzpBZR)LLpCwO%p<&g=KaoEkW;C0YLt)ubz; zjE}&1cN~}>fpf!VC5{ATWSU_cQ^_0mM+dZ6o{6|prqpPn3Ek+n#^q-7EYCI5+{uN4 zInfL;$sSzUq~K zSI)n|($9gFodf+FEPVu4HUj+{EPVu4HUj-rAA>_BMY#&_`go=D_?2^w$G@1XeZz{q?|f1YTB) zH&|Ywuh3WJF2x*rgC)_@i&9tN-E)MFs*73}OSh-J6xoh-Tm8E7W zEG~3TYa4;j1ZyYDlmh2XFbeO^V~h%V1$XID5tznS*RIvu^)gM22~7e~F3;z=8T#gUnV}_5sf}~a5rycbx{I`sge+XPRN}fN zkrus_DkV}jM|IqV>}Si?E0>qf+jgYsToS!L0&QQGCpS~y7B4fk$WtOKp?n3snW$Ts8OXqDn(sV9~ zULS$BFUym=N8cMS_h`vedQTE-oFfX+OL;|FNJ17aTPksFi7kjmvcQ@}ipnfcb=-yQ zXUoT((r=+7eq3 zjbwo}ixibvp6a*@+0T}(S1vD|x9v#Nxg>gh1lqnVPwrv;XuLeEB~R(YNvv^>C`2#i z6=@*}S-5Pe#I+^1AR5U6YZfUgvpm&t7qXu%Td!PRI&a&NrgKU3`UtdrS+3mUHNGDB zM9KKe`kMbmn>mSwF3I&kw{FjxeIda`^j!rMn>gOZdb-Nz;adI_q z?V$YE18)mxv3*f}Zq+(pQVPR6g6#K1_6qL|_X@@CtYj3G>RKyHd*rs_MIV9qt{44H zQ=8#xAa`l{tsV1E1WqoLKLY(6SpAa;^G^getH2yso4ax{4_BYoe=q#9GuJEJe{=V> zWWSty;S2xA_QGRowQqDsb8;c5;;!7xNYvh~P^xx!t;M4+l70R_Bv>-UAYKH1?9G)J7n?z?7;YkRr}5b&o)aMjwImeDE8Iflq6EHRkhZrl^_Q z`DY@wZmH{mUzV^T*ZHi5ay}n;d`0)dlMO9Oog7XrOfA?Rm>0S7KOd-6%_H#Z648;@ z6Fvf|R~qICRf)h|!Xbqr^K}G%>mv|zVfpWgNCci4u3A|2Ul@VaU5)uZio52jecn`8 zl2&>S{4vt!_rfK+F2j%rRBF3$yX4+jMyx>ymDmec7lGWchKoSfS1JN~m*_`24jh)^ zmGe08%LYCUTqRs36G>T$H22^AI}xR-i@={7cnQ;NX!UpXW2(gu#e zbW5r$l`jJK4;$kg_-6x0Aoq8vInbXAXXDZCg=dAcGIM8EzCM&nMBv{wz8a%)pRLJn zZ|UPemM;~7%ndS@Dmw@Mr$OexjSxMA+WwVq4peG#VQ6$uWFzx)KnwXgrRePEUS~g5 zyZgfVEw64b97bN0>p0NQf!R^=b0GBzMPQT6%#`gdq4+tFdLn&2(9eMq9qE+bS5VcT zyt{zjl~DX<1pEGkVov&93AV&F*e2!a4GOf-yBNp|S`$~w*0W+iSts#Xo+XJ&lE!UYy zHV!17;_F5etT_e9G5HHYe-(&uQPz3?LQZ3JHFBhZ-?DtASC z(fKw48|E2lXAoZL~*StIv>5)WsV|_B=Lq7*P+f3!=K*xz{v-Lj??3KhN8LRAZ z;M+a|oe`g3BCt;*iooxD1pccduwN2ujdd^lgpa^~bp+bRxe>Tn5|_lU>|S_|k3c&} z>fg5)9+1SE8-Y%fD;|M<4s=K3-xqsQx5rIQeG2ytBll^zif!F#7bjG-0=fI)C za`7@WkUXVBlW60dOL3fWvbF{hNvp$*vzA8I*dnu-Lsq1wcq9ICx_q!g>@Sz8w$;jZ z(>0`I+aVM;Wj)IUm3?Qz?NMi}siWk7cEzozsrxGiqvB=7K=PEXn8Xj~TuQ!fTZ8zd zH7jRnWQ{Gd6m!Um)D&;TKTatET?*T>mRw#sZ`+ZkbBXngs&E9pA2npy|9Av)E9{t5 zm#g`2>N1LN1!ttm5abB^KAs4>?5#IL}2>O@QzD4 z*?-p@c$$wuXN)U12d+Ec&Vg6?2y7G)xc+<_fv5WjY!ngbI8kl3{(IpKQ}JHeGm*D^ z1Ue&LxxMhlshDtF%E{J00@F$>8-XYJ2y}*{auK-6d>esh`Uq?k5xD7m8-X|b2y7G) z=r~brw*GtJ%~SDS*}d?qJ_4N)uiRdE%T!D_F6CtFAAxD5m5sm|J_4QLs9Xd(PE?z% ze*|uwiucM!;1@muoe{5G1Wr%IgyT|9w*C>AR$AEzJi|wzGaQwR!0qPS2)xlp;5>`K z9fFwni?_*_2+IzwE!z3^`HZ3JHD zBd}3K;2!gB1YYJNuu(*y<3zRD`tODJO2vC+&xN1z5$KF~<@Umk6V+yG6M_3AvDUMs z-pWRxf0w>HFqMnI{gOy={mIYQCIYR7#u|Z_`#I1KQU%{&={Qksw*C=#Kq}rVI|sh! zBhVS~%FTg}6V+zxAAtuoq6mD$N1!v}^GgIeO-8n|bKnC$0-fRT5y+iU&M#bl>LYL- zMquOmzOd8KRJO8n;3Ovk8{+%Isisw1sPvZ&=k@o6eFRQbQ==%DrZ!XZ7T-}pi=Yh_ z4v%$w1UlPE<-Tz3I8kl3{%0a-6P29<{TFTA(eTHC+#BUQ4t&s=1N}GFeFT<20zdH) z=uCn>0?QwP-}(sj5$Nz;^vU)axqehw`E z9Qd)H1D!d?M_~CQ@O~eGJ_4N{D1QXL4EY`;B!6#o&NW8 zVEH5PF&}|G0-YWxe*|utMBrwDT#Z>M7= z-wPuun;IuH>zMTsSbYR;=OfUGu7*Ai^buHn1b*%#&_|%t1Dq}AZ{@!C5$N>4p99Mu zfxGw!^bzRvK=~u^SRa8-|NA+x{1Ldlk3b)RP7jnn0=M=N==8sz1Ir(QyZH#5hY{%S ziBx|z<~Sz;{arbKPo(^F;Lc72`gUn9O(DLelN_MSUK;B_%GVH(^|vsg_ZL6g{z+fpLOOye;nA*5$N~A)komL zP6YbBu-^-pe=q!|6M=pXZ0I@A?}e+M17GnG=o|<(bOidnaP<-B{!&Ty!o|N-nvGv7 z5&nI@RPx^wq0O(dUvoIbnFA#Pi=Wc>5$H^lwaWUvaP@Pb`wmrq9O(DLyn&VTdf@(k z4s>R6puBYXrp{qN_%@<-s&J_3CNIz3SS2>d@EflmMX zIk5Z@c#x04c^HBIYE1QKBCk0S=&!~!^wk(2fz?Og4n6{%InYO7`S-%x_z3h7==4DO zBk)}xflmMXIk5Z@xT}xAc^HBIo=Ek_fwwvl=$}kz=&LdQOr-h<{I3&%{#>}B_rga9 z%@r*zu}H49YU|9plx?n#4UWtC{bi9@HN`o)Sm1;lomnY*I;)uav>qEjv*mK+DXuv> zy*#U*k8Cr410~BwY9m#B1QvTu<;_BQ7H|~arrIm`!cZ!-yc)Hmy%LK2Z2>J(s!6(9 zo!@LaxzN{~Xoi?^=I4NxJZoP%+H3a?)je|b-J$P_mpioNDZL|!70$VoJg=0pHHc4I zvvQV3*4QFTF^8;3P4Pzj%TL*swUjSKRNIa`8P;=`Hp=N)KEN1*M>GUd(>E{vD+1Ibf*eiA>N zb1C_**&4(rtywusBWrAtrIlgY6v|U-I+{MAA z@p5q>c}g!%;)ioCCEqn$gZQL1D`#nBjV-bibI6L+6mP^oPDQs+xoj;7J)7EgWO-u! zQXhe~E6bF-Jh(DmE)OJ6>E%iMaL%RVyJl+;pR{J>ERC$OMV4X?S&^FJjrhl@=oTuM zttFvnQ`?R#Ppn_*BhYqbnQ~VL*T&1$f#fN@I*A|7xs-g@Yz^X*)~uYRku|o+Qp_PM zQd7JU|2P%hLglixB=l@*+mYpo^=o|u+O8~9?)u=yc)321Jf+ts@xwWnlJAo+;5_&eZ?a1=P z`t3dfZC92l_m+MmUf$A@r}VAl$rjGJlzi804dRp5temBhHMYo7%pogMQ@j!XI2GMO z<+8OT^lWO|k>!c?H~h0Pwkyk&yEC{uUhWJePwAb>48}Q^lJAUrrZO;L-F!JAbCn3 zNaBZcE+yYJTZ8zdH7jRnWQ{Gd6m!Um)D&;TKTburP`PX^2|b(Ic4T>C{UINLwkyk& zdn9-)ULFY~Pw68`{BX{t6(wddCG_uAPS&BJiMQVyS;vc7? zTc}*NmV};7Z9B3&vHqlwK--mN$~_f46E9B%lBe{kBz`#OQu1B1HHc4IvvQV3*4QFT zF^8;3P4Pzj<5YADmCM$W(6gy+N0uknpYaiByRuBV=YkjF<+(uels=cl59eG;zH7Dy z@kwh|&eF&lTVyHbkQJ#Z-iUvkif*BD*;*2MHnr`@^2GWJJ_2o5mMQmA@JhVA6iA-Z zmy-D5oJ+}f&DJ13Y0b)68d+nDEX5qMA~nSu@sCr{EmSUBOG3}4wjEiXSbxPwpzX>s zGoQiIta@krEdN#G~$nwPcTpxk9E6bEyF?!n$y>Vwn zEd1^rN>@zchjT6^-!)r<`1}r^Vo7?h5C4%hw#a4XkQJ#Z-mp)yCTYowq}7_{xpLya zSV;54`Y0cPJRD_Qe-eBaFP{XGr}UE~RygNU^4+sFh)-Ixa+XHc*dj|Yhpb3V@kadP zRCEiK%hr<6v#D)ImM7Lf^ATvfvP`)zg0JG`i$L;}ev!lv=Uhs@YqkdQNo!Wl(#RTH zWGUv56{#uSh<}`lZlQA7S`vCTwe86A#QIl00&Q28DfdnAUA%k~NS@MflKA1AOUZZ5 z)*wD<&B|FCS!0VV#T>FCHN_k8k5kbtR4!XfLeHkQ9a)}O|ISCC?aDIceh7YwmmdPj zQ~E;^Kb&(Z`L5X-#3!v;IZGpJY>}myLsq1wcq9ICD!PTrWot?3+0?cp%MMOCWhle@Wtpb1o&{HCu!Dq%|vNX=IHpvJ`X3iqsTu#6M0&w@|rkEeSoF z+ID1lV*NKCfwn8ll=~z2D_;HxBv0udN&IlmrR2M2YY?BbX5}o6tg%IwVh&l6n&OT4 z$EoNRDwnM#p=VRujx0~C|K%glc4e7z{{-6b@=qXnO8-gXhjT6^-!)r<_@px{XK7@O zEwU7I$coeyZ^S=NMYmA7Y%K{ro7#3{d174~{}x}{m*vSBQ-~LXKh9H%p@{!D=Td}| zPHhdMlcqGEsX`-b^e0lBk`<{b-iUvkvKC8AYh}BZ>*j1bT&mm~7P4jqZ zY9vpoeMdUyTuQ!gwg&M@YgW$E$QoN@DdvzBsVUxwf1HYLp>o+;5_&eZ?a1=PdUJ$n zj@wqf&oy`tv^1^brKOQPr7e?z;G9dzcf!^nK55O$SsGbmi!8+)vLZFb8}W}*(JfRi zTT4RErnVhfo>*_~BhYqbnR0DS`*>+4Hi8aL%RVyJl+;pR{J> zERC$OMV4X?S&^FJjrhl@=oTuMttFvnQ`?R#Ppo(J5oo)zOu5dcOT2V8lBcwD5)Et}Ih-Vbd*M z7B-Tnbm1g^IOkIGU9&ZaPg=8bmPXdtB1Urd)T^GhVtI$y3@ri673nlzi804dRp5temBhHMYo7%pogMQ@j!XI2GMO<+8OT z^lWO|k>!c?o<0I?SC%Q)+w_f>-bV72_Do+;5_&eZ?a1=P`r(C-K8Mmy++AtwDU!nw7IOvc?u!iaBIOYKk}FAE%;Qs9d&|gq}@pJF+~nzO;`( z+m&U?En}9Amt~CPDP1OsAI`ayeAjFZ;*-{_oTZU9w#ZVo+;5_&eZ?a1=P`fwkCwkyk&8(~Jq%LpTRN=GE|!#S6d@0zVaeA1egvox~C z7FmipWJPLH}}Jh48~N1*M>GUZk>qvK^IBY8?!O5%reE+yYJ zTZ8zdH7jRnWQ{Gd6m!Um)D&;TKTburP`PX^2|b(Ic4T>CeYB52+m&U?jWJ{6WsH$L zrDKx#;ham!cg@xyK55O$SsGbmi!8+)vLZFb8}W}*(JfRiTT4RErnVhfo>(7i{PjTF zm*vT=ZpO#U>PGUEuAamX=Uhs@XSN3MNo!Wl(#RTHWGUv56{#uSh<}`lZlQA7S`vCT zwe86A#QJz2fwn8ll$&TK#mht^c}gcH@xwWnlJAs<<>Fl#mhQI@|3QV#1H3OO1^8h z2JuO2R?gDM8e3#3=8zSsDc*>GoQiIta@krEdN#G~$nwPcdOiYeSC%Qaf!QctHZYQ> zbb};*IOkIGU9&ZaPg=8bmPXdtB11Ij%aL%RVyJl+;pR{J>ERC$OMV4X?S&^FJjrhl@ z=oTuMttFvnQ`?R#Ppog@BhYqbnQ~j1ZQ^AsBY8@CeH&x^uQhFFmL<2X**;#jHIk=v+a!KC=Th<= zvo(lMTC;MNM%LIOOEHJ6NKNrZ{Nq$~3zf^(lF+lMZAX?T*0=W&XuGmZxgE{U@v@_l zJf%A(@xwWnlJAj(P?v|U-I+@a?1csbNa zp3*~;_~D#O$#>1xAUS)San=D2t{)<~YxW0UydoJ+~~%+?@2Y0b)68d+nDEX5qMA~nSu z@sCr{EmSUBOG3}4wjEiXSU=83pzX>sGoQiIta@krEdN#G~$nwPcNj?H?SC%Pvia9M_PBD_F^pqriIOkIG zU9&ZaPg=8bmPXdtB1;%dN1*M>GUaYHx5vw^M)H*2n#2$1TuQ!cwg&M@YgW$E z$QoN@DdvzBsVUxwf1HYLp>o+;5_&eZ?a1=P`t3dfZC92lcc-~KUhXuKr}WMwemLh+ z@?Envh)-Ixa+XHc*dj|Yhpb3V@kadPRCEiK%hr<6v#D)ImM7Nl_7P~ivP`*I=Dv8D zWhDRq?OhAJZd0|N>sxD|73ED5I^^ngP_ERKkV-&^l+&z z>Iz9kdA|usQshmNB)LdZA^R2m z4%DUWk#uE!b=a<~A@g`;>>rU*O?zqT!8}JT?NrCvB%@df!&%^oYEYkyhz+e^%>;cp z>O4vg*{|+*pe|*Pq-*Qz!**>Ana68m|A>@o+DlUp<~eFqtc2k#@I*DJPe#OsRcKomE$vjt*(9S_3By_7iE2=vjED`bV9f-5IqE!04%u((cc3n1 zkEGk{JHmE*4VlN=WB-VhYT8Rv59T>)X{S2QCK<&_7|sGuRD=3tL~LjUYbNN+QRh)| z$bLt^19d5TB;8rx9kx4b$UNQ|`$wcy(_Wf-Fwap-JJoSE$tYIBa29x?8q_BvVnZuf zGeKXDI**b=_PhHXs7u)+>7M%Du-#Kb=JB4`KO&`?_R`dYd5&7zsgAQrMzIoxv%nM8 zpgtK98(P7d3Hox>d6XQo-`np%UCJIw_tifM+kG`;9`B3&BT}kqFHJp|=cuKf>NuNZ z6f0pk3p`N`>XQ+%p%tu|pf5+AN68`kPx>9GOW7mof%?I)Jy1jD@qySsBBh%4($s@_ zj#}EOjTCkP@jy54Xt3!1bsQ`JW3APAMSUc zE@h9TU)8?}+plWKJpL;7k4UMey)^Y;o}-p_s^e^uQLKdFEbv4%s82@3hE}jE)= zc%mBACnI7*D_Ao@UyeGDl0)_<`yHrD*(2$x`suJeRYT_Ssn|avrJDBA)Ps4BTH2|O zvq?s=5{9$D6V;$T84(*=!I}yBa@2X09I`*%??7G39!byCRU_LoHDn&2iTxu|s%bAx zJ(%a1rJd?Hn`9I#VK@ssQ4Q*o5wW2ateK!MN1aE>A$!&IKaJ6~?2S}617WKh$UN4u ze?&?(?Uktq^BlFbQypiMjAA7WXMrcGL47hJHnf5@6ZGY%^C&rFr~Li@(MA`uC(`U@ z*|5!SAoDmo_K!%ZroAxrV4kCvcBNuNZ6f0pk3p`N`>XQ+% zp%tu|pf5+AN68`kO8pMhrRf z;E8HbpNxnNtzgXreL3npN)Fjq?RTIqWsjuQniqy`wFWYetHu5iDb=)>rXI|5)Y49M zoJ}%{l`xzIo~Q=($%xp{3f4@}m!r<3A^Y0>4%DUWk+g2J ze%RJ+AoI9x>>rU*O?zqT!8}JT?NrCvB%@df!&%^oYEYkyhz+e^%>;cp>O4vg+1KxP zpe|*Pqz#*m!nR=pna2%d|A>@o+DlUp<~eFEON2FBKUYdF^&rwS|)p0h-C|1I77I>l>)F&fi zLn~M_L0^tKkCH?7P5K?EOW7l7vt~}%HftdBxLNEUky1^2Y3ji|M=kAC$Jr#KSP8>f z;E8HbpNxnNtzgXreL3npN)FlQ^gB?OvPaSu&6Z)?qJhlg7O{UsN;U1JsR#2MwX{4 zpe|*Pr0tsR!?s-mnaAy7|A>@o+DlUp<~eFQ@;asDSIUC-0T{*og2tJ?i~9^q*T*hntCwLQA<13 zaW=^)R>E)=c%mBACnI7*D_Ao@UyeGDl0)`g`yHrD*&}JU<{e?%t%1zrZn1wvN;U1J zsR#2MwX{=Cxz8^}EF z9{We6RMTFXdN9vXOFPwZHpwVf!f+ONq8ijEBVt1NQm!=-fbJWsKb(~Eyij^>&1)it|^~s3X&K8^}Bk$Nmv1)wGwU9?Wyp(oS`pO)`p=Fq{RRs0Q`Ph}h5y z)=bcsqt2t`kiFaQKwZinNei0Muq|jH^SB`Pk4UMey)^Y;o}-p_s^e^uQLKdFEbv4% zs82@3hE}jq ztc2k#@I*DJPe#OsRiC*&}J9*)MDp4P+iCV*iMgYT8Rv59T>) zX{S2QCK<&_7|sGuRD=3tL~LjUYbNN+QRh)|$i82{19d5TBuzClVVi0o^EegzN2FBK zUYdF^&rwS|)p0h-C|1I77I>l>)F&fiLn~M_L0^tKkCH?7nSKZAQuat%(i{-BB@JXA zm&E=NDb=)>rXI|5)Y49MoJ}%{l`xzIo~Q=($%xp{3f4@}m!r<3cKomE$vjt*(9S_3By_7iE2=vjED`bV9f-5IqE!04%t7@ z??7G39!Vc+4i4Lg8pu3;DE5y?siwU&^)X{S2QCK<&_7|sGuRD=3t zL~LjUYbNN+QRh)|$o`Rj2kKJxNcvcFSlB++K<4pdv42ELHSMLT2lE`Yv{M~tlZ;{| z3}=BSszH4+A~v*wH52sZsPiZ}WIwFmfx47El8$IT5w;^5$UGhq`$wcy(_Wf-Fwap- zJJoSE$tYIBa29x?8q_BvVnZufGeKXDI**b=_D}RXP?xet(vi(kVLP&c%;S-x|BVVj%kh!+c6Df z9*>FrBT}kqFHJp|=cuKf>NuNZ6f0pk3p`N`>XQ+%p%tu|pf5+AN68`kvHcFzrRuels%J__6`i_qRPBTK(_mcY1SX*iLUC^LTpfACXc`dlvOzo}-p_ zs^e^uQLKcKEFz;C)F-3FmiWk_QB|LNG17UI9I~JJSL(oWCHfkyz}d~YVLQ8l%;VXy ze?&?(@Xbf{U_D38dC@}0*(9TA#9Fe5jA~GyjEDj)FycaAjyjK$L-up~9f*bO*?4|) zLD>rU*O?z?b!8}JT?NrCvB%@dfBUwa7HKNuNZ6f0pQi^!-3^~or)B|dU! zRMqERjC39)hwK;kJFq-xe|60zjck`TmqzIll95=XR0HPOMvhtXs^e^uQLKdFEbv4% zs82?=zNEPO54ZlEk^X-+@@j z9*);HvfbF+7^Uk;MhPON8Zgf`a?Fxf9cPn_VkL}Z5gFB>J{j4Xd1!$pit54ZsPj;r zN)qS#eg|S9dpO?I$aZscbChl(86}96YQQ|($T3S^b(~Eyij^>uMPyWi`ebBl=Ai|a zD5?jqqs~KhDoLE1`W=Xc?BRGzOQ*D@KZCyWJFPmcI-_;74C8XUrQs;N^AAT7bVenN z=%pf9iOxA&r(%`V_LjzOxB7YB(%f1wYzfc0|9`AwDS9^Q>OXr*?g-mw+Ks3A9!hc9 ze`3?`z-M3Qzd!c2Mz-6V+oN7W zL{U9>9c4zGL3JugoZI?$VJu`1$3OiVc!s~P>UA!a?A5XD3aHmfnI8M&F05BZ+;9J< zyRh6^+$8zPhL-3$A|`#!B>VyrWsx@wPl|kXCRjngW(}cP2;Bkbeez@t^2> zcai<9>h7l0mKsR_y^Om%Yovn$L zee2FTgk%$)di?p)?3%YfKhB>LVdsHE>W|l(*KewS+u@CUFk|>X9G>GD|0U|Wx8H&P zs}9`j@2&$eV|3t~lJoK}(SeBT99kQvTLlG~un1ha!@ZNzr+ZQHa=u2`I~Q=Kh$}hJV{_VzpH-o=t*5fAz%e6eF^LH-ocjvw$>k|yB&gx$BL8uyF z=cvz#DfQIftT+C??_2Gu|6A?pJZRO^`OvDT^P)9A^?$3L*10uKuqTdxbiQ=nw8o+H zr&UkqQLCQLC)U%R$EWkERZr(vYn*GBQV*SPt@d=@wd(2oYt_?v*s7=Vu~kp!Wviaf z&sII1r>%NAUt9Hb-nQ!L{B70KdEBa}^SM<|=XI-|&hJ(|o#(B3I^SFMbl$h>k6KC} zhW?Z`N&1kk2ONj?ynpDr&>Ekv53PE-PPFRjdeN$<>qe`do_t&NbR8i*?i*EgxYR3U z)9abUru;>o@k+1Hv2%}_>-J*??`^JwpUmPr_fokIB7r;BTo-2y-oVG#>)T6%C)G_- zskhfX*ay9z9nH4`y}j;1FW0@eZoyuUH|)Z7u!w7~cd)nDJLv884tjgNgWg{6ptsjM z=t83oo>jnM-p>7A<{$C6!HW!DUanWs zer5FQ<9SXzm_1*UyIxey_Qno{;%h)r$zzp$h>mroT}m&%NL~k7o5$z~F1c z14sVrxqlrn_>SR$BY$D;-w7CeeF5>Sax01*aO91Don!jVNpFeuaPCy|+&^iK&u0vO zjPVclp&sYHVEFT-&QPCoCm4LX;NV|XU(5K2BY%wH1;_hb1zzIB^VR5MIqn;#-gC|T zKak~fZo{l!oZG38|0TaVwE#0%@=+#@Fc?@hh? zoBZ;K5X*BXoAsEKdSd*mO??($W%zAPeWyzN81E93Z*AlMLW6&2?7wO7#m4?LgKskS z=NSH@W_`YF_;n1<&u{16oAFi6@AF@foUb`1&RoA{W&KdqH<15oiGRR;7MyBheu>vN z=U#5`rUq|j@Vg8?$>5U>-re9e4W4803k;S|>a~BrV))$*e!aoF8hon3Z#6jF&*FM* zW%%_nTs8Uei8%W2l-bj#%?2+tczy4w^F74$*ZRi(D1-TWugACQyiDSGEkB0{_CeV$ zVBc3{8OwHCnCrkTK7!WuD$|F{X7<&_55#Y+{=netTZvEa^8rWxDic58$X{*vfFpm6;RBBRwT2Hk^4Agn4_bd6aOAHy z{sDvc{qRBc2L|tt$7RX`gP+aE|77KXGyW9A69(V8Ie zKl>?)e|q8{aO9afBjE!E-~2SM4;Xys@|*_-->gQ`4jLaA{48F-1C3uOI392MoU9IPx6-bsE13IOAVyc*5Xk zne_(--&@7<_$2K7U~F13bUQ z>JJ=wUhnaQ4>Qp9vFP* zY4T6|Ct&b?J=61x^C#DT|2#8a;{(IrU;qA9d0_C~eoy6r!FS}HZGiOL7ch8#e@c%( zha#Nu>G{t*Veqwy4-DSddzjV-48At&2MpfVx2^gEgZKT`RUSCwM+{FGyszhQ<$*K) z2*VT3_>UW&aK?Ya@Ps4J{q}DOA8^JWX?VhsH`mWu=J|Iye%`!M{ej`{pO?O>JTUm$ z#0LgHV6N}L;Ol!Re{y~RgZJlCy8c`W;f(*J*5~aBgRlAd<)z94gI|W{f0pvV8Gp9n z34{0fj#3^N{PGyy0{ zdEmf1_mj-uxhb)a{HKMF_>6`{uk^Z={UKKTs@n5Wv9Gs6e)^lUCf;_&fBpRPs_H+D z|L4R%#ve2M@flxr#9#aHAA={=NfPR+I--x?O9V{cdwILk-+sS{xZ!*3kOgra{Z2IJ zE8|nWtoO4ZlbF|j|BCpuUaj`w`_Urr((0sjZmq|D4~o3@dr;`@_n^?*??IuL??FSE zwEoNb*~H^eecl|;@Vyb%2YkTJ@%2}aBXC^LU{9ZsdKL2UGa&!OOp z^*8EYy8Q;epKU$x(|S(yas7**57t4}2YGG1^gUM|zw^3K`PIHp5Wfog=pXHDf5YGQ z4fM9Zp+C{|G4!^Np||}C{nGN~f5gZK;5$s?2Wg~+Z$aOv1 z?;!CbKF8p<8GNqCvCliN4W70SMPJ(4;|_n@Z_rad%239!{RVs6Z_tOlq1r0eZTkxL zwy&VKeFeSkE9gUCA@9KHbUYTu<5>ZNubE$6d5fzr%JGD~!Op$OUnc@h_nGy)h`t4m zeHeJ}N0z0Ye*b{<8gDrh&*0`vs_%_zZ*jFu?r*Sjhx$Vuk9W9E)9)>K73SgGRdRjy ztHCe->Lu`1{RP4+YaPIth&xW~{VU&B`1-5&7mMk7Ao+s7#9zt8Ck(#f{I60TIOG4( z@Pq^J+|k+ms^(l@Dfo!Jmg=s}aRvt8c}}$)$Zw+gd?8^49Qo%OKH$JR_s;CRscP=~wY2XH zcJ5udeZ%(ur1rp}9_P-<`?PaA+0!FuHvO?6*wv1svlY=cO2L zfcbZ*Juu>VytCm6gRj~D`N{)l{PPS?82l{upH?0iyr0h&$^&QoD-BN=ys!VA$^(P< z@wQSP7`(4%N_k-LKHe_MTih}4I|GjAdBDy+Ztm0KNB{qlystt&V;|?)oJi~FPZ=43 z;n$pP_<+H83~zDukodzM*lYQP>Zc#nV{uiV#I&vxFyhswe&EQP`f5{uGh6ceER+Wr z{{H^)3e67;zLxhn0n+^-U?|)ZQh&r7XZJID=4kx`ivY>r;yWaMv^Th-&z(|#i|c&86|nc>_5D3b^!+^I14sUGl8#Pz zgR4(?%UC}!;>|YK1z_+UbG(4Td;8?P1qSbr|K_@Wz~DRP_yB{SeHPV!lKKOKpT+#g zlm`Ys@G0WosyuMuoy)&3p?h-HZ&kzoFIWEpo8#SB%=NuK@edgFHRlkY^q0l;_lbRx z9$#SZMSeB+$4e7F;K*}7EJ=8SJ6wc1jhP!oIDo*XMA$s^E}~(+v9o6^)0Y{$WC(kY3KYecD`Mf>x4>l4>3;fLjeb#eg{(WM7)bUpGSPJ;eTlGJ%ar!J8kNpxApysyl?b+ zvWfHWgx?Dec`D!#r|O*G8H9}(ynmmtovy#dv;Ii_*JwVA{ri$N)gKt~JI9m1|B6ZK zuy{7dzggo0duy7f$KNu1f_=T)YkuIE|5C||c%6X34;)9#KI#t)zA^q5`}Md^>jOqU zU;nq22L?aD^Z%0a7T2F9ehsY;IMnCdj#-~o%W%9~HJ-)wXNZ4s5-(uPw>I;&*w62J zjSoyw<>%l15X*CS3XTeke`xG~Z0vtwc#9t~_KzCO_b=)r|H>}`N5vau{UW~CTjKn3 z?negyCc{;IEa5eh&*Q@Th0tg5I)wK*MgM({{P&IP>D>FX_|A=FpA*u1SW|Dn-iu$t z`=^M1=_Q?y#Sa_)zYPABVE@W5zZM+V>zji8E5BI$pzzWDeuM85>|gmM;9y^ME*3ue z-(m2782nq0b=~p)mez@4==BtO`JAWJi@mN}_&uIj#|&&N|*Qn!C4WJUx?T z$FZvHd9kO7{|$pz5$s?2o zk2d%X2LD#-^ICq{(DXz8eGdI@p*dbpnfc8a{QRtc>Ak<`yWLkiq!9 z1h1x-R~i05gSRmA-P_a?&R1UryFM(ukHRl+Hn?l>KN~#X;N1+q%i!P1`o(-Z8Gc`b zA29fIn2V?Sc>J_ZkGxa#0KC;@@vbu#e&-^)|xxQy->SsdrSZ|c0?@bZ^6 z)&DnU9xEC9E#y3m^BgwE`F!L5C4<*6_CGZ7FEaJsYxot#KNdV~_>UX^?L78HQ_c7u zm;Mh*@e6UPim#vPI^LVbsj8cVk9oJx@>ZRVWuAyq+dA=rpey)In zeN`LYVETPKZ;AUuIp5G80oo zU5fsQrRYEE_3^N{-^%gEaR}ezm-C-R7PFK4-qqrwnCi?h)t6zaE5k!3 z{zj&c-(m3K?4IP`OU}D6FGqiC)brkoU(S>G5r5g>#|(a97O(28MEr(HzPD!QdDYpR z_{?eARie7kyB&2ljD^DfJY;RsVje z6M@~MQfI{9HTX8cq3)^^&i{bvJME08_tSnJ+UIgTaE`7Mlq05b^8ZRHKGw{CrTyqv+cxh{T ztOo8Ud{M;w9*lpY|19ROO7M>fUy)$`+(!^4?TZnxEkPi7bc$%trcb% zeh(<1YJl@x7_S>ueH7vJI`TY|_ZD*9-Q(wn zxb(Lyvb^+fue_b|*BSl=X5O-l&HI{=_mBSbO2n-?qE|cAN1un12kiJ7z(0zA zXX^Q*;h$?TvNsqP5rnY#e7F*`Kl(5SJk|p>&Nroxy^F>TGm(l?$seO zts_a8SJe@H#I?!Ok>_}gBbXw{b6Bi*)Xb09Z^a}J*Smbg^to_mPxmK--<=%~T5q2T zbvn0yW?xke@yjOh-){W($kvDM=LWBppWiiKhgM1AeJaaedH&FZ-@)YDKEqXKGw-kK zD44#d%AOzicR~3_=eeE1_h)tRdx+eARfAt_@Efvqqrc%|@Z8M4s=t)u&LtVV zv!<_8=O@@X`gc=F-m3EwLYpS_3HI0J%#P2K-IM2tZGC+I`3Kwi>@;>nkGiYQHlETt z1UpCl&3w zF#qk1d>%V^KbwB@u|8kRGFn!-(;{Ga|M^$|}!}PbB zvbgj)lV2yT_m!0AYVx7`C`qWN>WDtaS0?({LZ182y|(+pO0XWKHJ= z-*;2Lj_8q}*4^ZrOL#}}qx(hXCwll*HGf|7=9s_oaW9Y9xo`Wpu;;%O$3MVTXCu$+ zdI|RTnItd&+oROaxhG8A8w`H8>DT?T<5YECW%3I4*Yzy#aVE|-rjC;gzpTN}H};<~ z_zwp2@4x8!(6P(vruPK~-)8LJXs+uAX6sTlt7Moy7c%zt`Ep*CuWDA!{HqTC{(*j8 zS9Rpb>ha}%`R91No%?a-Pk;L(k6+vODQjo;@;pq>Z(hq&-`QMu*30bad@%TfX1$Kc z_^Pt++YRpgI`gkO=VzGyHi(&zeV+TOv0vS+|5r1A`dlExRVP1wRh?u0odW*B`c$<& zUMtglpR2sTU(x$vzY646Grw`f^gDvt`q1YLc|HDlTAxp=%FgdAV(+Wsmo?1!af~^B zt7rMD`rpat!?B*K!|SQUWY z#MJj3W52BF&+nM|ea^(2W$+Vby?Hs_ssKG4`%tQ&NGCsP5SBWnZ0v+W$`>o9_R=9+dLWX z+)3Gb(r1chy=M%6uE8rC`~9GKhj&wh@z#Mpnr*v}aLyM}*>ng67zZ;9tWNax@| z2f4itbkmauxcQ^wLt|qHxP7|^xZ$y(sj0zv6C)%}j89EZ&J0gaOp0Q%J3KKtGPrnX zdb&F~F1qgc%p#G7#>Xe7ho(m-#s{YlSlkumqKT22u^^9*liU2E;Q)swCx;GjqvIpp z_qpkXlM_qacz20Qq6|$gm|4^vpB@|=otk!o`wvZy4$Y%rBV8(Ta)`_FjL+t!(M5|V zCa2xhLVl%rbZMZh&J;d8L3ZO5*-dvBEgl=1?hYcCn>RKwyzd}caAr3)I^K<7(ahNN zsMpZ4jE*lDoIg3Vz?;z`4o=bByMlN!36??<1)DD!onAON*`1o0nH=s;C1iJe;n4VS zcVuur%};}lOeA2kJ3T`OK-up57E`P#UVBvzPERZz>+atjOLX%lyF>dXcyxXO=zvd; zj?Z)x)slsywBj1`fYI*QNP?#h7$2tTj*q^dDps?xp?Tf0OhYg%)zJ9VD6g&W9N%L@ zghsmahiHB2aE;RO8eOoE7QZ`x+D**cr#nmsa~`ev5DD|gCWh#^@e)rtnl>HjDd#%? zhj7YK8%VY(x41jGXp}5`vkeXn(^^kazw;yln3^FQ-}R1Ge9_Pt_4nk^qAvAn2%O;2 z@%i1!Nt#%qqZS{fh-4klh1jBWK&ITtD9xOY&6Jy1OcGT;I^|}jx>MAc`^}8fk#lmM zP`#5A`;U%zCbR}ka=JS{GBp@apDE{SP8HNnVubaKv{m?2|0CAkN=N78eei}7cX zqYl?IUC%Dpa>ltqTA76tBXNcklX?sVnY=ho*-Y^68NsENOyxT-+3$5ktv=l0|b=;}yIWe=C zCObJgJUxH0o1SnZ6VwWPPCGh!)Jk-nfRHz&Q zIWrOsuJ40Wi@U?rXu)u1e2DGWTPy7vrw!rz!mHQ%I4ZF&{V!{GK+`V5WvCiltcp|Z=D8UL{125}McHws7R zuYVGd`-Yo$z;u_6`{@4EL{54M&#QxU{HVZiKM0^ZMwH{AI70YM%ev`M^f z-o(UMcSxRC{WXO8Ys_C8Ls)OM|HP==G8~;T;W`#>B5pxh`1m`98>hzy9IZ)O zpm2A0`}->iVgFP`7yTJ}oW<3QZUAz}_ZMJ#F6h$fMT;{vJVX!EQ&5D<*JPI-M7+he z++6;#Iy~mO1vB&@K&>H91akZEj|FrRjmTY}M*k!ym%jFA>(LRHKHc%jH%;Br9dY9m zP~no+?_d zcF`icDlng5eoaNjr;E>Fs&9FAjy`yt zQtS3->FA)()KQgPM(7P4-}I6v$!J$TQAR533|%1qycUgcp5{08NSk|d)c;R?IR|&Q z=ux(0xG_YFtX>>Ox}ox$qT&)9y_S0UjuuP3j7JN32KR>=c|GvgnP^qcAU~<*6xTO7 z+2**-+@_mu>NeSg{$PNQGfeBSv3?n3#sO&^zIKikhP_*G{z+UBeQH*@lUyWsQz_YvAZOZzzO zo6)`s?Khk;;5IyS!0knHLwP#1f9&&Qf8Kz5_t^t(=Mx6pKhu62;YY~sMzVW~M^_Ak-CA=Uj~RLfULeuV5Ur13v!pG9_WBA>@d z_bb|eMDls0KZo{*3BT*a0rw!u8=W-ZR;3ub5Wfk{>jz&LaQD+XJ$~ANdw}?t(;D1G z_(tNEBfFbvzlZRS#7)qC7x}%7_BBZVP8v6-aUHTfi{gHf_+L|;O9_9M@@+}n=Sa6A z$#+nUt7yEL_Mg!HJmS7jc570;-;>YDWOoqlPmumes_ENge$STq5UCRgJno}1MROPelgk3qx~7m zy$R)bkk<4*+J8j*_i6tCaSKl!aK9nn2gznd+SjE07o*vQv=-OXxY8*D?yVGSFOqkr{f%UQB8{)6@$+Q+Fs)yQ>R*lU#x%Zw{4ODR3E4bN zeiu-k=TiRJBri*`9_M+{_(Ag9it1aRd@iKg8=CVAXgrJdOGy8F+FwudduX3c`@ysy zMf>TbKaTcQDdqsh8l!O*?KhC_0;=bSB=1Ug`_cYO(mg=?+LUi~+Sj4|e#(0u)%bnN zcO{K`k;*&Es4ek0$#s&^*6Qc@7}_ zDUuh{z6SZelIFA<$+Ic`s+6CP^*pk_kMJ>M`%W4c5&i(h94GsC()bG6FDLE<(r-)S z1C;Ycq7Jr-oP2ku__xsbIhyOiv>!_Q8z{~(G;U7&duX3a`|+gv7qWW~ z#aN!?M@Zh7M(&}9DBgAy{|FlQAl<#^Qs2`4Fzu((e)%~A?&~zJOV^R7X`dpzEa4TY z2e&6YNb(=4j)O?vfw;p+e<VAbcZ@+Y`4Q?F(rC4B=mp&0VygM*9h* z+mgm}NPiFQE0g>(@;jWyf1>ftR9pJ9J&gJYnv8KJL#@UB9ILzX8J`atHtb literal 0 HcmV?d00001 diff --git a/src/app/api/analyze/route.ts b/src/app/api/analyze/route.ts index 0600dc7..c6e578e 100644 --- a/src/app/api/analyze/route.ts +++ b/src/app/api/analyze/route.ts @@ -22,6 +22,7 @@ const EXT: Record = { go: "go", rust: "rs", sql: "sql", + java: "java", }; function normalizePath(p: string): string { diff --git a/src/components/ui/CodeWorkspace.tsx b/src/components/ui/CodeWorkspace.tsx index fa53d67..eab67c2 100644 --- a/src/components/ui/CodeWorkspace.tsx +++ b/src/components/ui/CodeWorkspace.tsx @@ -6,7 +6,7 @@ import { saveGraph } from "@/lib/graphs"; import type { Graph } from "@/lib/analysis/types"; import { graphSchema } from "@/lib/validation"; -const LANGUAGES = ["python", "javascript", "typescript", "go", "rust", "sql"]; +const LANGUAGES = ["python", "javascript", "typescript", "go", "rust", "sql", "java"]; const EXT: Record = { python: "py", @@ -15,6 +15,7 @@ const EXT: Record = { go: "go", rust: "rs", sql: "sql", + java: "java", }; const PROJECT_EXTS: Record = { @@ -24,6 +25,7 @@ const PROJECT_EXTS: Record = { go: [".go"], rust: [".rs"], sql: [".sql"], + java: [".java"], }; const IGNORE_DIR = @@ -163,6 +165,29 @@ CREATE TABLE post_tags ( FOREIGN KEY (post_id) REFERENCES posts (id), FOREIGN KEY (tag_id) REFERENCES tags (id) ); +`, + java: `public class App { + public static void main(String[] args) { + int[] data = load(); + save(transform(data)); + } + + public static int[] load() { + return read(); + } + + public static int[] transform(int[] data) { + return clean(data); + } + + public static int[] clean(int[] data) { + return data; + } + + public static void save(int[] x) { + write(x); + } +} `, }; diff --git a/src/lib/analysis/analyzers/analyzers.test.ts b/src/lib/analysis/analyzers/analyzers.test.ts index be85613..46165ed 100644 --- a/src/lib/analysis/analyzers/analyzers.test.ts +++ b/src/lib/analysis/analyzers/analyzers.test.ts @@ -5,6 +5,7 @@ import { typescriptAnalyzer } from "./typescript"; import { goAnalyzer } from "./go"; import { rustAnalyzer } from "./rust"; import { sqlAnalyzer } from "./sql"; +import { javaAnalyzer } from "./java"; import type { Graph, LanguageAnalyzer, SourceFile } from "../types"; function run( @@ -493,3 +494,47 @@ CREATE TABLE user_roles ( ]); }); }); + +describe("java", () => { + test("call graph and inheritance inside java files", async () => { + const graph = await run(javaAnalyzer, [ + [ + "com/example/App.java", + `package com.example; + import com.example.Service; + + public class App extends BaseApp { + public static void main(String[] args) { + Service service = new Service(); + service.execute(); + } + } + class BaseApp {}` + ], + [ + "com/example/Service.java", + `package com.example; + + public class Service { + public void execute() { + log(); + } + private void log() {} + }` + ] + ]); + + // Check class nodes + expect(hasNode(graph, "class::com/example/App.java::App")).toBe(true); + expect(hasNode(graph, "class::com/example/Service.java::Service")).toBe(true); + + // Check class inheritance (App extends BaseApp) + expect(hasEdge(graph, "class::com/example/App.java::App", "class::com/example/App.java::BaseApp", "extends")).toBe(true); + + // Check call graph edge (execute calls log) + expect(hasEdge(graph, "com/example/Service.java::execute", "com/example/Service.java::log", "calls")).toBe(true); + + // Check call graph edge between files (main calls execute) + expect(hasEdge(graph, "com/example/App.java::main", "com/example/Service.java::execute", "calls")).toBe(true); + }); +}); diff --git a/src/lib/analysis/analyzers/java.ts b/src/lib/analysis/analyzers/java.ts new file mode 100644 index 0000000..5f02c28 --- /dev/null +++ b/src/lib/analysis/analyzers/java.ts @@ -0,0 +1,63 @@ +import type { LanguageAnalyzer } from "../types"; +import { analyzeProjectWith, type LangSpec } from "./shared"; +import type Parser from "web-tree-sitter"; + +function classBases(node: Parser.SyntaxNode): string[] { + const superclass = node.namedChildren.find((c) => c.type === "superclass"); + if (!superclass) return []; + const typeNode = superclass.namedChildren[0]; + if (typeNode) { + if (typeNode.type === "generic_type") { + const baseNode = typeNode.childForFieldName("type"); + if (baseNode) return [baseNode.text]; + } + return [typeNode.text]; + } + return []; +} + +function resolveModule( + fromFile: string, + specifier: string, + paths: Set, +): string | null { + if (specifier.endsWith(".*")) { + return null; + } + const relPath = specifier.replace(/\./g, "/") + ".java"; + for (const p of paths) { + if (p.endsWith(relPath)) { + return p; + } + } + return null; +} + +const spec: LangSpec = { + language: "java", + wasm: "tree-sitter-java.wasm", + funcDefQuery: ` + (method_declaration) @def + (constructor_declaration) @def + `, + callQuery: ` + (method_invocation name: (identifier) @callee) + `, + importQuery: ` + (import_declaration (scoped_identifier) @mod) + (import_declaration (identifier) @mod) + `, + classQuery: ` + (class_declaration) @class + (interface_declaration) @class + `, + funcDefTypes: new Set(["method_declaration", "constructor_declaration"]), + classNodeTypes: new Set(["class_declaration", "interface_declaration"]), + classBases, + resolveModule, +}; + +export const javaAnalyzer: LanguageAnalyzer = { + language: spec.language, + analyzeProject: (files) => analyzeProjectWith(spec, files), +}; diff --git a/src/lib/analysis/registry.ts b/src/lib/analysis/registry.ts index ffb7dde..5f79a59 100644 --- a/src/lib/analysis/registry.ts +++ b/src/lib/analysis/registry.ts @@ -5,6 +5,7 @@ import { typescriptAnalyzer } from "./analyzers/typescript"; import { goAnalyzer } from "./analyzers/go"; import { rustAnalyzer } from "./analyzers/rust"; import { sqlAnalyzer } from "./analyzers/sql"; +import { javaAnalyzer } from "./analyzers/java"; const analyzers: LanguageAnalyzer[] = [ pythonAnalyzer, @@ -13,6 +14,7 @@ const analyzers: LanguageAnalyzer[] = [ goAnalyzer, rustAnalyzer, sqlAnalyzer, + javaAnalyzer, ]; const registry = new Map(analyzers.map((a) => [a.language, a]));