From 937330ac3da59ad328b7ebf2c410ef12c2ca6b59 Mon Sep 17 00:00:00 2001 From: ngc2207 Date: Fri, 10 Jan 2025 18:35:33 +0800 Subject: [PATCH] feat: integrate language server support with WebSocket connection for C/C++ languages --- code-editor/bun.lockb | Bin 159263 -> 164170 bytes code-editor/package.json | 7 +++- code-editor/src/App.tsx | 31 +++++++++++--- code-editor/src/lib/lsp.ts | 82 +++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 code-editor/src/lib/lsp.ts diff --git a/code-editor/bun.lockb b/code-editor/bun.lockb index 0b2d6093b70bb89dc5d31f0be59310df48085610..27939335c4dda921192c51acf4c615c23238da38 100755 GIT binary patch delta 31924 zcmeHwcUV+M)c4MnMRpYd6$JqSyBH8rDWVIusJr%t4HXd;r3qND?HV;A(O5|Jh}RtbI+MGGv~~lnLBs)a(D4% zgZ(4pw4mxs8}_+>rr551OVXczQ?X?0Psi3-@J-DsF~-hkTQ4>Ceq8Jeo1~*-=JXg} z>!GPkW|X9uPG{Q(fg7j~v`T=k1@8`e7JPZou0?b@FVKvH@aI^A)|4dA;u=yWci zTS2MZY?Lbnx)@bcy%|H|)8jG{bW%~Bt~B_x#PqmKYeI%Dd4$sVugD<9%mE20iT$#4 z=T!bWs59gb9Tmg+C#CkG5_Yso`pJnYiD_{e86HN(kZq8cfm}0eJ$N!uK-m>E2bAjj zq_|FJrHr09L0Ov#Qld4$J}jK}hr@+@lJ7;V$V@MgLTfR(=p#r=HR3 znQzcpWs4S|zp3KsDjhZ;F@69%Ow33ao&Z{-q|&uU^d~i(7MD37a8N?lZS)8=d-z=qjUoe8GE_u__)oLqL`dh|5SFmZH<8q7*gM zMXlJ|L&=ZN$VkYD*XhiVlYUxiMkZvsFtkeg?vPWDq{OA9Cid0o!oX7uWW^;X(U9fq z6@vp+z0y{gDR-q>;UVx;K^g@Bj!ocUyv>Mw>Y*2?fEs=TN_xG0lnVQ#$HgO*bl1R> zygDM4^sJ!NLjw~t6REz$j6gYjqTxR2^|^|QsN!>~WyuNY{S!iTI!#{APYIfSaT%F| zQ9*jbkPNcz7UbmFHh(2n94e?or0Vxg8VYTl?u4GtD^lLtx}su_cO@l;<5IGc<1*t1 z#HII_)pnzKip^|H8rg18vO7H?EUFfWB}MM+P{Z1|hE9iCZ2Av$IzP~=;HgLnPzs(wfl8PEiF}g(6rj@~{%nas zI-Ni03Gk%14U~fG2K35-E(K3L@&pv&V*4Ft(==RHOOad9tLSN~Ei)r2ktXnI2*}q+ zQ1ZPBDEaWBw&I%$cxqrVDnLP-4V0p`FDMz-8k8CcSLx1BrM@MgWI(n`GeD`{SkN+< zaki*%rNJejC6O@|)D6@J6(Qbi43rwU9;|rWvYt+d;kD&~Cqpm5c+xuzO2H}jE$G%r zr6F5=#o(cdnF&zQrKct(4N24Kjz#HoKA3T~4LG3&W`I)H4WSIs9-!2x%YhPCsy9{b2h5f2vB`A3^2b97n zA*0Wb#H7Bu$t{$g$pWP@O#mfNJE-y~m9Gw32J$kXq{l$1tM4~g%3lJda)&`lZ*y~9 ze_1dO0vg-#YQ|ttsvs7W3RpmCXu?$9ACxL60ZMw$nkfz41SS2iK`DQ?%CBw4%N6yt zc2H({jgHE|B_#|^p#kv+Z=~8(>H%s1-!~y4Eif@dw;ko^Ql?!&v`gE^ot1KHkzXA7 z<3TYIZCRicp^5!dQqwWy{Ss6924cjmExITfCY7cICZ)#5Wuld&#N@au> z&>!0?(excC1z1=mll_vkx&bAvSk=9 z6hy59aY7Y4!vh))TB+mU0J4G$l#G}t#`Xi_Q~?VB)oNF2Q1 zgK{*#H-S>mTvrV`2}%a;040Ot<5P#Ez!(~8Ua6S3_0lM%OY%UALE#Xn+_fsLGe#+h zZAe^FT;GJM;Hjrdfl|d5cuTaNO_5gvrJe{MtCV{Up6YuBo|eq3pyXf$CEsd$q!ug& z0eOIbx@w?bqkG7p4<{%W1#SDQ?K-pKl9CcLGIckQU!L?qso|=i6m(xsRMz0U@rr|5 za34_l`=D-gb-IQVR}>hiY_)VHQ30)~I<>;B$fp?TpOBJ~l@hNTn30-NSEtjpg`9%y zA`GSLdn9C3PfbwrIAyXDOW3bvW~C+2g+z8JYKoGNHgql>ptx^j@)6Ir?b@G+{KoQA zlXc}UHTHU0!c=qY!Lu!<)p?ZH2{qmlE!PQ@@#kBjjRqUhVH~6vQ*;{)%Kahg&Ip{VVy%)1_^7jeX*A4jPMbG(3 zEv_{fzr5+Xzy;^cjdMO-($y!$z3tGY`!?h?yp}LyYg^Ye{nlgdwjzeFnNHUl#uef1 z28QWtNIG3}?(83_&%jw{Iz#=~-jN3UaO3T~YVc@JC+AGCSZDq!HT(o=IHW~+yVhaF zy&ZHq6F5Ce^1N~%P(ec?gk}gO?&cFF9dO`wACqLzbF-&O8m{L#AhR909i&WAZY*b# z1{LLIkd;Mw4#?A@+z#@g6E}L9B%2dAgM8)0b3mL7+z!&uz>VG}>70R^K_ZPj2V|I$ z+d+01xe@J^D8|h`CPPaE9vN7KpYaZpRzq0cWcXDTI`K0;VTSD(Vp4%e1H%ljz(s>| zB;yUuF+qsag9~TQJjd5$xCa?7E=qqInj@eZfpd~e=ct?mdNIs!0o;ekQ#zu$3%C23 zq(m2P^fwt+V>P3ii*h&rFvBgCL#yDbBKVph53Qz#Ggoe`V3Kybax+K~H=a|$WN7N9 z)3t;K#uV+W21hnH$ffgD4*rx2GjzmE3PqkI`JBNUz+DsHW`921C$V(?j2?r1&*p^e0qg2>5Mx! zS1}oyV9gpR3n>aWf{W&@JR_xhWw^1b$q@G8r7PfYy^6bqfqLn88tDN$!IjaAblbc`cpv<;I#ODZr1LYnlvw z{FFSs+~+I&xE*=V{kSpMB-QfgW{^StJSW&>*zd0dE92x=sS0n#-Z#t;3$C%;UORN$ z5^y2lpcxQmI15hcDmRoXSy2nOGYHxqDhJPNh8gDkCGT5s)K$pCR0+gdOpzydv3?}D z`n**@q#+k))RtZj`+RUsWsYnNs;t#OZ4Ct%g}jo~%LY5RFpZN~6>hI%GW4vXbS!4| zz%Xe+6>hF;GF*a?!oW!himF&lu!rM1YuSX}DxU)~Bp)tq&ayxc)?pcI6VB}>le8tA8>39p<8W?{G8sZ6bh<8bRbRb967ZkZOM&h zO3iYbgR~X5%c;>q=VnWk14ghVcWzOiwdQsRTXSPeO3g^y@SK)W4s9^5yp_2=u_)V? zn_ERWAc9-+Db4GHwYQ35?YOZurDmkW#(H@2bFET=hgYDe0M8{1N9meU+L zwIl7!jqNBk%V`eM7;cwSV|zL`w~unbxYgsW21Xh>;*5q=UULkyRnAe~!<`3*Wo}@k zRJtqA=@8}ARngUPH&Zw<6m#;1M0(hjn>$9aZaha$?Q&}DL=rR7?mS0M?Q&}DOcFEF z9y~`*?Q&|2iDI$bET=g!QBJXME@W5^U&nG|mnhr^o8>e|PVHTyoO&uNy0T~n_TuKQ zQLGowkyAU;-rU%YQnQ@qAdTa8IW=~tbF-Z0Ann8La%${B=Vm$0K^o8Pa%zmFb2HMu zJSR5F3DcyB)^*a+zTDU|iY0J!&nTw^+{YuQguIYXP2hGp$Ji^1_2Xta&5=_((*E4o zn^H5<0X(O7l+ysEUR-Oig^{ph?!uj0N9w!b%q*X+z*#r>>=n)sdB`&Hk%lOo(TZ!N z3y+?I!!8~r^KmAZ)K^cDO^c6|rloLmg30g{0$SH`HOIQrE>+=_ZOMFaSkEYLP`DEq zWsN2mJ=5eB6t)b&8Lfu6Yz2oIqH(Vr4h|K78x9ULh9VW*GjJGrbzc*cuG969HEChm z3J#%*a@cSfie)H%U|WYRSTAtxkmoF47`-wTqp%;wwxuUHy41?sGs6LJwDie=rLQ`K zI+|w89Gp>G%Fg|Fa8yQ~F;cyu+&mChl%dL=qlkRXJ_(Mli^{bxZJ2iPK(`u>{Dt!# zuDL<|HyIoafLu<09b7m+6MSB&N08h}&!=sGy+F=g);JVL2X z;l_hg`iN?|3@%)2%20ZwGNrKBj0uz4j^ySPlVK}_)Zy3y`iDsgqqrTyUq&fItdp-b zbw+b@s!19;n&*HV7|rdeCWCp5(vWfiUJtImViK+yx5n_CG?Nr$<#v#9R&E?@lHzRK z46???b3j^;<#v!IW4STiBzb+r&FLongpbfqyj6OnbmJp#hoIRwIVK^PIF6e$O!|uu z43#woj^}m=`cKg529Ut;8fWAy#t)qw_OWt}RYGjJk+G$m5u2u%U@=5I|NN9Aw;OKVJ6OK4j?WN zrgm^NTa@`xI!75SW!Covhs{Gqq_irBn}?eWw;-UR%AUjL6PoN~*)W`?%dO>q!p&JG zspe#!17e-b?O7(nvB{c4ZVkfO6mA}2k}Okr4#>1A+&-dSTm|d`3ABgAmRCNA76GaN z5>O4GqcA1?>HyIIfDWR>*8s`@4S}LOd1P5D)n)-Gx1~y3fzt6V>IgZ)T5i1)DdBh* zrTRJpWF^8`K8R9zM62vY9Bpq%u@688Q8Eatw0sn%q}LB1+F#C9DCrMW<%3i?(IR}x zDBtSTJeDr`AWGU;XyjV3jK~L3#;=Sj%kPeIGLXh_K;kb)`O4ihTGrC(3RAKIGe)k* zs^$}=_QtAwVM_9G0M-7nn*T29fII}0e1IxdlYlBf$jAp#Qk({mA=3dm{)tj~E^8^2 z%FP6b&Qj@YP&x`IMw%3aELJG-a{xWCP?ZxU`67TCS^^Ni6rh7B$(I9+w;JQidyH{n zPJH2*vR2aD2+%>4^fnQL<6V?`a4SINwyAVGC>=yezJnMXL`i>_O80=$QHUx%Oadyn zSEc(v=^#q-FM;B~34kg*4UnOEfHQCfpbq%~p!}Nv<=;~IUsV3CO7E%k0gbQ|n5O_8 zL}`k=0z84TXuT+Cc~Bbi3S`Y&lp3t8=2utqiIRRGD2alQkb$*9$*{Vh)J`Pze+itl z0HuQ{RoGIcZ9u7DN0pBOr3$)&(m|9?yCES%<3K4t9@GGu1WNU#g3>{hdTbOZ8ECbs z8APezM=DR$1^jeSchFU;{C}BR|5q!fA^TD_^xsj8|G!iGf22q8|4#)cUsX9#8oK+SBzmCA|A~^yLnKxz_?ueb-%!$jtm+e`(vwSqongvRU}GLEZ3q^%3@TjO6jx+5|TTpa-ziRRh}rF7FFd=63-cD zw9-TcY9<7fv}%KrLS0H!N~d8+XuU9j(#mR9^NCVDZ9!>a>;g*l zbOptKU3Zo5K@5&U)G90VR26!Gl6iepngELby8e`?lqw#e@L8+lhpk&ZwRsN|epQ_SnpmY!=J+AVFDT!vOa-vl4Y?YtQpG_!c zC5ccaM2VlH^6#RQKUdY82TEhIRMmeMrBGdoe6nzjs#l0A(}@Jsmm5_DqO_1~1*HbJ zfl}5EO5UO*+KGhpcB%9WP?GOKLf3>7pj2NT2~|q^XC$S4oXGOOP_q0SP*-cfm?bo#5xzoGJSre;vyeI#Vr15n~0QSuh0{NGeLQ8I*% z3MweSA_;I1rTi)Y6)C*&2dfJt0TrmO(g098h?2YpPzGoS{C5X{PN3tzI{kp7|2J@!uT)Ej|C;0sPY~$bWYLw2u7K&L7!wKI#2;2k_q=z<+lD|J?!n zH2v*ze{;7ku|e(uYw-2XDif~kuj%a5rcKJ2(v@EJ8sQ$&FFw4~kHmqjcHF4;!`pVDE&vO=Hhpn^a=P z%!Iu?x4quGWc;wZy}O=$^>VVO?z_=Z>x<5J>(O`lhLH#N)jYGiSa_YfO_wd=S76;A zDNz%n12&zAzExqz`2oeZRjE)b@6+vl&z94dn8Awlx?AbO-daEG_YJDJGt71H+MTm< zP4@dQtsm+Kb)4dC?3}iykacvcrX3C~CWL<-W667wUF)j*)FUO^(IbrjQ;-9nx31ES6{8G7u4oKP+vY}mIt5p#L|lH z5VgZ$<_7oIo$stjS*35-Z2P`b?FU6WRC&^McE9;a&e_)^#yh^~lsDtL&y{V5x9qjM zPdXaRQojms65nHY=E;{Cv5klR!W+!?;D_g0n1Q>^i{VdaJM&+;g%#rwGh_G~;mjA# zwBP~5d~jXnIP+GsEX;+^ofX5K<~sA2;M{nN*)e=4xX)%=SSkJt+<qd*MNJjf`8yfud?7Fm*e2F*TTQm7ChRLwHp4dgMZ)}^XhBhAGj%NEO=<;0=PNr z;on*d9#xsN7XEF3f8bj1h;{G}+`@GhJeHCVZp~-#Z@mQ%oy=Vi|2D!uaBX;t4e;-C z__x7==SQA_+X*iAGYg&|S^F9M+XVkMTJWq$*NyORGyDS=!wsLqKXA#PTUb}V3*7K6 z@Nbg^k7p!qf`41#AGlcVxf%X}8@<_rhbxYQ%iae6wpj20Mb;Mhw;le0i|5t1!as0R zwp#Eo#07A3cEG=F7ChoGX&d~@g@51@dBk@32X5hZ3me4qx5uy~-f%|@OXhQTz`I@W zZij`X@)o)9?hAOAYhi==GjKb>#qPAQ48C?JyxR@$c3IdE-gOte+XL^w4daF{;2pT+ zFD$LHv1OhF3prcF-L+y?)EBj{WL)i)>@Y6*)66LyJlp?f zJzHgT--EOFMOSMY*Rbu78f)`BPMdDWaG!l1){T}UHv%puI8JST?OD(I#;rv==Kc6G zICf8?dgo6?cc1X3>#^jUlYPu5u8o*~e|h$&_Mv_*=c}_xjr9H@Id9%p&$Y!*e?7m( zkrnrY%S=Brw1atj=jGYYZkDZ=#!v0@X!)Ybf|&>GjnnFF9ChI2^&-}y?W?9VEHk!4 zUW?6}PuGs?G4IQnD{7p#{n9Sb|IUb zzeL#Xwy?20aW{f-Kf)H=IPSRz!3b{j9t)emkAs_Y0Aah=!Y1;py$Hsy5VqhZ@#^~! zjNqp1v#?M21#oK)B5c33;7jvKUm_e2A#A}-rb&j+^?T&n{X#`)X> z2*)D`TyV2^i?0xlM-jMRS(xC@z#Rh@d(gt>^0fys*^VJ_4_VlJ-t`bB+i?UgxP{zs z7?TZL@?i^G%y)syw!^<87Pgcp9)W)+;2*f<-18{>12_7pg{|brkH)Z7-2Ye%Tg|hO zuHk2puI1H_$FOyLEYkJ-0@4ks@(k;B<$r!ek z&qcb8KSa8nw>TBUcJQT0bNMr*J9)d)F>DuKi}VZ5zK&tLdDpMu$+z(2YYW@U4S6wa zACE)&CEtZ~KX*G5!w&F7q+js^NDp$)voY)tAB^-cKaTVW_x~n_9pza_kMT1|kMru^ z#xOe{i}VD)fb=A?J`xy2OpNsTc{t)Ro z-r{@=`;IR~`aOS!^gM5OA%|zYN#JeKB%r_&w!VQ;V*i{~f^cvrV^g4ID z9K&w##LF0k8yJPl7WO0eyn;~xH~NZ&-Q>r?&G`XQcGbde@vN(evL6v;;PQF(Ylt#% zQ?6Oq9ex4anx7D5*DdT?WcN+>b|c7kj5gN6OZ=l*~w zyM-tN_n5c%5m9y&qz6)IT9YonJi^Lcoc&jrHzY7P!7Gb>H?aur**wMEwlAdup*g3z##e9oY zl<^Vyoq6+n@DZ$m@qk}C^QT~^{9=)cF@6#3n)~qb4sARp-GP@6;3YU09&s05K7^Nd zY2%R(ZYQ`_ztYBI?yvCj5xfNF&Rg7rm%qWwd$jR*2JRTR*!#5cSbHB{{tho6(8i8~M+{&l4@puSsz)NS|=^1T2mOg`jubjF5Ic+@JJ%@kbwu6h{>`(aj+L_7csNWgF6f^io3mx5!npvke9UcH~=XAsB9iAi)uW?qV|usuhF4y(k2+BCaR|=Sgsw1igft69n1CAsFHW zL7X^1f^cUDDjOh(7lRED+$O;}5+n$JBLs6wKrq1wL4R?E1kGI_s9OwzL@~A)1W!qD zlLUiAt>O@@afM)3aR`#d4H9&5gP^H11gT=WGXzd0A$UxJ!J=Ua2zHWSWeEr}#6uDc zC3c)bZ&J}`VB-l=ZEWz9$814>1f*S-Q#by#zD+7UhNeD)Z zxRMZ@C&6J7ScO|D2(rsUFr*X&W5odygnK|xxikdh#Ng5p+$O;}5=;>O?hwrJgkXX@ z1QW#>2w1kLUIt{67)vBaTp;p^s8tqZvY13V%WAUR2i4f`a+=7fgunJ@;}`KLBfiA7(G9rvC**A#;LF2YRL*5x zak3gSI5dME$%;whrvT>9+UK4QX7d!Mv_Jg4-XnKoAiKsK;$dCxnP3*_Kn;JORO4Eg zIZ2&Hk>8ET2EX;A%}STh@O3ddO~ZZ+$G6kPqjAh+ zef3&7NH#&M`y6+>ccqy7||h0hy@E=-bp|IH!Z&yg;XP8-7BSO;Tm_ zHEY?sg>+*bEX#DdPgEIw*a8>4t^RBWMo}7b> z>UIOVt1^0N3;xqzuF_-3@*z}NDR8l!RN)-8aB1*;0jhYOsz^^d^#Z8Cd{stY*Y;Lr z3sjkoEX9#IN9>ruW?Ox5ULNoT`~ZL8F)aKYpzoCFd*_D$eGg5;yB1gntOqs#^ws}- zU;(fYSOhEvXxI+}M}VUM4Y?hlVLl0*0!}lXc>OVRw|)!e9Pl0RJ#Zel09*tv0hfU* zz*XQHa2>b-`~dt2`~=(t#=-arKnEDm3FrvK0PO(!{`v!eVk!uz2~a52rueFZle$1C zfWN$dU~*#p1!8P*`Yu6(nSOG(9?e406@V{&zp@0MgjDYS{g7INCz^2OkfBw z6rfMWXsjIoJ>UowWmY_~f)fK!3~&Zq09U{bC603OnpA7EmTNdP_kM4tiD(^T|?*6#p)QTzb(HgFf9N5ZVXAjt=MqYyo( zvjR#hfz`k|U=A=Bm=DYVrT{s>L;#(qvjKSCT}QXwSVZM#6dHlj)NTSa1wI6@XzQX- ze>BhtXbgNP;en2DoJ2_C(@Cs+$i-0A-3ScEL3!urk46p(Hfk>b}&9?HS9Tskkn z6QJkG5>PiiYDUjDWB~LW+;iYD#VURG_6X<$g?OMZz@hXRun1TTOatg+h9SUEpcT*> zXbZFhXx(fMv;fRNN7PpZC=ZN6eWQUf0EMOv7z=y^j3Yr7Faj8kf_b3cKtG)SiNa3+ zdQxj9_+`KnU<{B7!~mTE3!Ou+3or}1(}3x~3?K*i1egH)LHW>K4s-!%5w~_j(jB0c zIu@7-#fiWmoF@VCz(AlPun%&7pcLQ?tb%MFK+oEI4gLy1R~5QqbOP-F5bXo>1>%7I zKrf&-0KSx*Nf}Eh%5V%{K`VI$D+LJ!C0(BA`ZfiihiK!0AEDO=G!Ezu&}66sN|&=A zfExfUDKvx|fa$PCZ8PL~%niyAe>I%qxx)TD?O7 zcc3)j0?=d1&Ok|^6yOTDsXSc@ynu2*S-=x019+%B8BNznZy*5h2Wa?w0h)p3fl7cs zbq@*sfQmo`fcVNl6(A6x3aD^(-~*tB$_Ini1nL5{fm%QaPzQ(vB7kt9o_ZbyY69re z6b&>4tWA(K2B#7n<^eMRx#dEQ&xK3?GlAIv2UH`h@={3|npJO~&nc9rRZ>`& z3?iNm&0Fo9^4{h3a>$nflW6>DyhxEeBITvP5@0bP*IKAztuksz%ct{q8LCt0;nJFoXUGiNvWHtfu}8obD1WW-zZ>*Kv9cxC&eWE(4c_110BUx0kz7VtB0 z6CgS9M1KVgz&+qG@H_AX_yc$fJO^F^e*!N627_o5??9U(vXYph0A&!2KqV*^2c=Ct zSx%dI+SF?seA?d8HjfOV9w5)j+ll}@)A@q>0OXK2C~c7Z0Y9JuKs{H*ii8T1Qgu)o z0_y&nKoC$vmC>*ePkT$!?**QEtsLM8d;l5gXnN$7reC-&t-LnWRvKqgs0~mIkU|JR z9?&pQ#S|Y}0Wyg6$Oy{Q0t94j6w z)L6fJNNDVkaFbu|Bf*wP&D%om3}dxdX-Oe~LBW(Ee@Z}Q zwAXY=Y)rVw+sVollUUDM;X$>bWfh;zW1e2rp(UWYF+r4gIpwTB6heYRgRoxC7B`?^ zU8}ZoP}oF|LrxeBO-85EO=Wo$(%x4_4b?*CyBbn$(`hd^*4}MaP)2(Pr1o|**<-oiwmOJS z$C!urVz^KY?U|n*PtxCC-qDqH*UOuH+itxmGoQ7TPUuD7`7A^_rxzPfGY{#iUTh(G zzJB%sRG_`o_D=Gl`CV?cJAo$Zplc8(FZ5!}8Wb=(iq_DS+#SV$1*pi^Q7oX6+WU09 z)>^M^ytN&xwpj=yEqDmg)ribqqu&9x$8r4 z1#%Qg3sL<;N3n#mq@v>9LNt4>s7PCc%B~kxf~)3h2Vm1~u_iIs6e-R5X)^n0? zfoy7tP`v6`ei@x-$&yJOE4qA(5*Q3>UVA(9{&JNaclYXjUCn_N$0f0E5exCw-silo z_;;^fH$GPf8YoF+?FLbNG3@d%iYkj)KqY^peEoRyD(b(FRZcPSDN3}}-UYoT>s4y) zC0-33SWk>48Kk}Z`DGH@lvbh1MYKkt276i;SA2N-eB^+yy3AZDu`o!=V#IqE7o(P< z*3sZ;R`l(9@T)~GOY{;O00~Vt?G@3TzPVdzM5=37)T)Nu8feg@t7Uw6C*Z@<4icLQ zNoh!aD=vC2VIHCHu&9pGciM}qeJb3jxZhA=7iz^Eq@FQ3iw!92t-X5sZr^U5uGHV( zL~d8s_}*Dur`q3B2SP`C&2^u_l^R4BbHP`AnB#K9`?`oA_#3Ld$hvjSua- zp`G<``}s>zd&WQmD`!wh9o+#83XOK}7V*U@OzK3Dp~kRMwoLgtI_*W;%Lfh}lJ%;) z4|GsFEsS1eMBC-CwQ?CTa5-#EEh`p*dTX!NURL|N){9p@3zIDhCND8D?=FWo+Do-F zCN+PxZDplVvPLbkS$pkvjdRP>&kWkqL(Y-C$=8dN6|A3B+Dm-500*w%P#m76f#r~D(8SS0g4qZYzo^o7w z7#ixBYH!&NsM-9*)9$4oAty|!J=#~4ScUeDe#+eWr0>kldoCWoCf6=|S!6I`l^F*=y0* zfy(0K8Z@S`-rD=QZ?DO5`R+SMM0L|Disy=g_5Ihl_g^uGX2hrVO~4*o{P^p`GbN9@ zvSC%_4{zSQd0M;5yRtFrWnO*pw@rJcrYm(LmMf&kdO3;e4aS5V?S4><>)^ULAzNKDY1q~`;3JcHMwTX zjSocHdbIiH2cj+6@IKpAnH-quz=#tz5N3?v6 zzH#hrM>NC#$7V=q(f0Yj>g2p&F^UH6-*)QtV6h0D9m+74-Wayk+vB4TmN>n(V1TuE zrjP&G)o)f&H>n^;4Hj?h_3Rs(ZEJG7YO!OaAsrE(hDZw|?alKeM_>B7f9a#^ z3hGh^)4MUk2=mFt9;X+b_%!;GqJfy!DShA}^{plLpiXb?W$~Z2%AE9|?$Ij+buF$X z9#E_6Y6;_(f7NR)A!70tl&BISdT(RyV)qv2_v%ZQ5O0Ld5S| zSQBGstl^A7w3YRgI){h{TbZB8+={4C8REtu5MF#S_WWo9aG$Jg0BCv<7-qwh&OG`iZOZ!m6|aeF3Y@ zG<66F81wYA$XGI;ZEi$O$`^tcfr>s;Uc;))qL0b6+VBui}m~;jEFYn z-cgghPPMEjHhl4~dH`+HO8KS--k#K23vaKGZ>`#IR!B8Q{zYePjTEQ%Fc0h7HB`O_2V0AGto&Mzt-f;KG`LmEIYXjzXkS75d&J7$+xY~# zcsgk>8^aoipZ2my5Wjt_Hb}>PY(B^Xa9$1MFH&r~OP47bJ9X|y4y;a4ZF%Rqzkx7) z$vo>q!52ogn|JSC^pZ2L3KX=TO872h_v(vB9?|lqyi@ zXcGIWZYWeh-JeW-xgfWq+b;zQ+RrsS?KyW$odx#S1vxuSqQrisC_bdK#U3Brw2682 z*#ZUa7a+o_eik0`XWoYeIpv~64;1x^Qf_uTUj1_E#NWr3D^TbWC8kl`P@r+}8PSH_ z9CglCprHK<#YdLKgYK*~wk*im5GAe_Dw>@>zv`9j7S06{c_>@ki8KO z_>>`}4sBj{HxnNmfLTx|gI3#{@@jbdxUDWwxYcC0q=Fp(=3*li#Rn>MpY)aPUb8CsQgnfW_UjReyXvp0q_%|7`N4;gAj z4>uQM)S_fopE55DF21Fo6ewuFig9ap=A)%iPj(mNuomJZih8wB%*uAyFrb%Pz2OB4 z)mzLy2&<4!RrAQZ6$eh4mtByr{V>OYo72~nD%9;ykNlBCH_hE9`j3d%{)Cnc)DVg_m z9yQ)U>8al@R&-yw_Qxn$0nOui2uyt{YU(NN`S!jO-HE8Hje7@C|1j<&a95dg7)weA zvF|XvM@_gPx6PkhX}?vq~!uF&tuaKS0-#)4=uVk zgsF)gMCK9PAmHv~%@MiQ%L;KlT2Oh)vxujy2DbM?u{!t|EkyqCWAaH{h_-hSJ)sC= zh95=gj$(sCu9L8%c&>0k$7Bw99^U>P@o7Iy37;J})Bj+}KJQ< zr)pashcR76zvHZxS2ty8Pp)3R&$^j?+9;p(VHEI-CF1mPtkn3(pY8|d%#1$t?anS9 zsIM;FZ5Q-z9Xl&!fEKdd+s$`;Frj{A zGQX!dYe&299xqtdyO;1g0S9`CdMDrj^k~NYC64e}0=|uk6U$Dp?Rem~%Sj9`KCHrc zd4gSa5|P_i39|M6U6wtc@VXK#q##2v?Z-~;KJ9a*S1Bj@FiX7=cg9Dlr%;0&h4@UX zpJ;UIO~oD(qHWqKR-tl`N9h!LmJkn*9V>{S5}>;2@E97WY)zZ@m1n za!KfhOQy2484i&@q1S#cW^cs4Dmp!J0ID>vgj`=7K|?NttgfQtcr$nyT4 zP}};4o=|Fc*JIK>NfLhN5z;fyv2xOmG_mO%`u}8_GPReExm=;y7zbChs(wg#9XWK} zDR!qV=?uziOyygpbN!=twK=jLo)S+k&(LY8mJ5T~Im?a2_gsqi-$!uxv^)_$MI(`8oA z;sbLE6@Ho_+CoDrmMI2)j}ofy-r7$9jqfydz~iFTze02B!lPB7hDyi`*4V8Z! z2;I>?(&_V2sS_d!oV5*6?&r2vDeFFYe*A`l9Ie&&mwl@hZ|xU_4m`beV8zRWvrw0M z|M}rC@c^S2s{IC0xqC4|jh>`FEzo#>&hX*FbO9HH_lLXM*<$GhR@3A*N`6Swrak_i zI_GPbG1)Bzn!>J@?(VhUBdR?ke#C)=OGZm97iDNekvB?|xCk?~UoaXS66E_;sUj6n z788UnY47|XSH7-p@)A8RvXHiauibHsQoHv1Mt36P;*N*3HlWs8L3M+|YU{LLK+5$v zd^s=g)lX`-)QZs686&Pzt?z7C{(SCjKV8`}v_}_Y?dOiRJu824nr+ce)EY+1Q?Tx$ zRrJ0DKXo?cGsr4_Wx{+%b;2hsq)`{2$W}uR&7Y53m@LbG&wi=o1P9gC)w79>m+oGEOXCkOxit7ST($^TWIT{zn|%ceuc1J@ zyfUSJZdon6`2o${+M0s)>q?{dbg)Gpm{`c$udQO=HC9HLudqIqR*hF0dS89PI>luV zZ|!HCn*ET}G~hrkeRrdF@PY9n=m!{|H(sP&Lq}^r2z6)R$d3*6LKhckD!&-} zpkdU0!Rm;2saFg0T|5eMZcGsOsP?zR2O5|rvD%;5u{o zho)6yL;wCUzqXjZbFRr(N7bnJ)EH^_hfCk3_v6StDy^ zTw>BN{32qr?q{pqtFgJN{MSC1YvNVyMoF72CExzu{Ox@0hl6(TQA6vA*FUllPweJMXMA|wlWcg2 zSJxlmiwGQBY`Ny2*icq8IW+};DixT}H!(9cU1gHuQu+^x>z{x>cuGjg#7{dW$0a3> zNC+H~o+S3)WC2x_FJ=P&s;3HvWdzbMv!$oSi@1E|+u(2Fnt?U{CJU5zAVHb^N2pna ztMLD;tf0KA6c{cxmyxRWRMq}!Re|i1NR$ zygUCxMFpl5R30eT9Z{&SQ&STA4@n=A9H%N}CJfI^7W<#E3c|aURDnf^2a!_Ms%q{V z?SejkBci&+fhVl880#hZNwq^oyRuT{T<#>TEIGThDc4L&TQ)YOrqY_K z)Lb2COG#;IQEDh{6{Uu@TD16mK4*}8Rr`Lw&+~hq_x+>y@!4yywbx#Itv#K6?>SC# zr#M!ev%g%YM&s@yZ>%qta-rYIGo2E5BzD|6tyse&g{SOVQR&O$o&Ow@`ckT<@H1;( zT>0Wxr>Z(*B!v{kGkD(d(%G2>6r}{1;mH~CBac z8Ppf@1l04Vk(BfV)@bEz=%*&9B@d6!%$yJ2j`BL7r9eYW{$N2xDGI*4kD?S&lx$D1 zS+EZRKNM^OWdqw$n+9egaexj+LfQ>{VNiNk8uTuNbTrtccfqiJJ19~ApY3Gl8CZZ? z@aT!5!f=cZ9e|JxykpWaLy{ARAmZfAq_Ih$-4G5V3WG8m9v(k(NbO-sS-sFh44?%l z9i4>k3It6AEd%-^Xz6TZVv#8cnvs;5o-#T~i7l=u<-xZCWdz}%bZkg`X8M>kMOlpT zVnc^9x-{Gxm06ycnVFQCs3?0OCqFzrb0lQS0Q5igXFyJSY4K_4$paN-9r$e6_GHDU zrf>{8Ne|C^zFCim75mQU? zLD;O{1(bU0$|%`-gF}-?CevVYW^H{wB?lXd9Zkb+KFw_Q-5H}Xf~%b(a`_&C~-*ou;hX98G|yDMkl3> z%*;rNA2={MWB8Z~hNrD78nZn+vic%5ueel$K1C$fu1oY7Lo(1694c9<1RGweq5!d3YwG6qlwmxpzo{^a;$q6Xj z4*|od1In-hK{+#T)iK=Gz_Wq*Fu(!N1m#SP1Es^wLD@h}lWq((>^Chrhxi``oR#_%C9wz2EGJk#L*2E1zqX+2s|A<1LvuC0F*QGP`EL3 zUk7DFo(RL?(a9r|prT}?r=*M;t|*5ZD@s|+0na967{Po{cHJlzfc61p*E&HlnLI(D zRX`s!GKT6DDEZx>EMEwUvG!zw(!p+^?4gDxEe%S&KO&9x&VgoAVV@~j3(80qgZhFd zWhRVDP8q1oX=U_G7AVIw36zm`HRaJJUjvjwPzscKDyTk$EsgqTL0RtrDD}3sME_Ip z3IrV6X=cF)P#Wk9%5pa-hbF@0D}vHM5m4&gZ(%fa8I<~;gR*?D$*%`x{q5*}4($d| zF1@78?3CoRk&5zhtRbk`(HPT|q|s>{tBT;MSj40Opj<-(lahwlPR>+zpk7h%PhVkX zbT;a(M|okCPXon5@MM8<@+J>XOV7Y;7?hoyHn28kLrhnrz-iLqwNug)aZvb*CQArtD%7z|B zy`;?H8A))!)fS5E!rF00WbujV8EG&W1vxz**wc_#17CuCQo<kI%?V3Wc0rj_GgE?4iieuq%!w85sX3Ti-f#Cas za&1`Mv7o)NYxpJ_YwT@M*3V2z9i5b+C;~i}&fNq1y~d_q1yJ_vK^S5EIztUQ zQ>WO@GLi--jYR_$AfVymsNf5_45P%kKW@fxzf+Vq*FzF`-bE>S!l1Xu7&I%(sDJ}Yd`kSlq!jRUxF;wba3f06?D2*?6|@-mi4%-^tw3qd zInmf>D}yqy!A5zuCjuE7>;y{BTf+b@qn;9=bm#?-aV4=PlXYIricd*N&K#*!oor0T z5}<521^S$9UQ>;YyCir9XiaW!lWzd(&r4brWc;8o)HswWap2kItwCw<9>$4tV{lSh zW>#9FGBh(it)ZeQ3nAy^Di23-{r5ycMmu#u8S%E6#vH=QZe-T*Bwl^=fTqnd%F%{W zlo7r^KJ{Q=r_No(aNk*ey*{{UTXx~6>T#V80wNb=W&z(tH_5H65XULpr1*-PYt?D7(ha!&1z zmvDiE*+dRVmQCb>d}R}k@=mRzw{U^%@D@2Bcf3Vzd8fTzK}G2aH&t=GVx(G7xGFfc zlLbX?8K+j;M>v9=_EA2H;)F&4alCwlcFafQR&d%&Ve6;RNB9Rv*e{q|LD9KVguNQ3 zcr%oFi{oV?>?2IhMo!!65ROVtt#l#bs^qkfKnJzZt+3uUlk*at%SG5U^l}?zDi(xX6gXyvn_KD!a!D)Jw+n#Xr_8K^sUIxzA40EH6 z=uj!jJ_ETXkQWg15XFb!oMLXdC{6JfIn|t+^cT4xYBAxc?zG2Y3dS1BIQ^RQ=faMv9V#CF?;M(ZQh~9o39IieX z2=+zSk{nLkTFlHy-P7~PwbP4_SBcO84eumB(I+rY7JRR&{Mv4YtaLaP>G zZv?IjI4^dN?FDcR#N4t`+6SdYZY`(%Aq1@I#c{W}0?g60zl>ZAaGs}$5{1QXx|Es74-S4Jt!k`>N)LogB7K*-rT&p5%x@QbWGE$Zv)o?oHt|D?gopT zP^Z?ltjG;@+F!ud&oX1i9W5(d^_^Pfav}$$cR7&@vY?!BggNck${BMLYpqIzy$SX) zbF>lq3~(*=_BvOHupb6j9~?AmMcDrUXO05uMOCmS*l|qJ=_Ut1LnG|_|D)_7I0mhW zfN{{k+; z;=f6 zUacIVZK)+(PNzM)wlO30(bGP!Epj2W)iL_gXsQD^?m@7EVOs)@O<@9KD%=Cd*@^1d zKf~)9!C-)^Mc8(OYax!7i?TmJZh&C{A@{Clh0GwggNrpROpNpiwHU7GJ>U%ERQw$r z*RbJK4CaBs9gmCj0b_ay`&YoZp$IRqm9z*GxhC~=<30F&}y#|J~=M#q} zgUcI(v*3(g=X{RG1$NMrRzCsP;t6LDe_{ojQhc~@w2oH8g$rqf$kEeWJ$1B+RwIQA zX=9OtG)m;^siQ6PE~HIFj-KWsZ7Lk?n7Z^d2dPu!>Zv0pT8$PiJ1 z(;TGjM6RAXIx_F-8102!vc2%_&_s<9xe&$(M<=E(q%M)uDcTD&K2~&yZ9*1x-NMy5 z+6$x9Ud(OZ1Z-~SXtlj?bYbd3+Ck(XjTN~_I|@fvrY=3r(bHU{orI$sQBk!D{5J^U*huJKcn%l8XH;d-on*4TJ0@z z^fVXg^TN@OsY_3DkoFO|dg|!Uyh~4WkoFb1dg>U!yh~4WkoFU~dg_R0-i5Tk$kEeW zJ#{2Rs{@29A=(Ga9LG;j5xq}d8X$7@5=UaR8ZTUWnxm(=NE3u(AX698M3FNv+9%Pt z=wOG!mRxk8aFub|+F~*G6uw=eY%7p+>A7pj_11GO@#O|HuS=BuCFHn@eZ;)}kzQD{ zIDkb&*^-d!Mg?upAdx%BX`3`y-n?R3UIJ;gdSk$Vpuw|$&c;HWcIQTplUqh-kTfgJ5%tGow} z+naIF>Xc>#fdfJH2>Tjvol)kiU)Tqv8y?}0?u z^WfN?ac*uj!l-Agm~3#|nhnk4;F^I$*WzsDpMgsxFN3xn$e}ZlE0k&G?D5DMQ5;W> z^a5jCF+)ZgU103|eN7JAJ6v7}4l5K_1zs_(f@=!S=$?>K=q&vhHVV0JdPf~b&gdG{ zwpAR>117J^y^!NFFDm?>kI)v57LE+3{T_tR92( zbZUFY3KxiXmdMF;+F!~t+AuD=x53deIsjLRTH}Okq*KcrCvrdzjT5;bua6gwQBLir z@xlcnCWsu6%M(N{$bgB$G1_U%#kbWy!gq9(R&|odfnd%geF~0>(vD0LjxkPK`D{fQ zt!uoMEpi~(y^Y)WdeD>pyQ4E6?Ls2E9T*v!K6OKuSXiCjTr- z$FS|{A5!XL1JxTCqDwK|Odgw}{`m_n3^6OF0GcT4DJ^Pwd_pO~Hlcs=Q^tU8LT>`Q zf&L-YL|;#7I~^JW6cBS^XPL(*+Y8(zfS>%7njQ-A@c`7D2GBmHo&NbJ%K9@+JyO=2 zWzyLu&B4!z$SMjl`iGQ?FBq&&$GvYlBHQl8UlZN@sH{_W&HdcL6&2 zKHv*{3NXlH0L#AwSboyvPn-PLCOv1;3!wD<2Y??^u7DdrAYg+l1wjj|=xq+8AANg@ zvcckzv%IufPD;KEC`G|Y=wL-qI#wB!4b=cG0vZ9z4=L?6Hfd8()@z}fOQ|&kG|(25 zA5v!9A)%)oL0R4z)DGGklm`2P@kT(~(xTwAK}&)zV1}Os{~yup z|E6J%*_)<=|Ced@|67Lt(JsgSZ9O22KQomfI0?$hbJmQMlw)@ul%fl!{GTXQzCprz zmrVVCq}*+&zzW})6-b%=-lUgJ`U8ddkTQD(3F}=m`5!67=btE5uA6$KjW~;MngUX0 zZ<#zP8@OZ2e>UZ$s^~DIv_5-(Go_@Q`wv(O`iCk1UnpC9Xx7V5DSBkeNx23KYIIJN zomo1Y)f`MrO3gwhpPy1*7;*+()GW_WDe^bvq?`_=LD^gdP}Z+#mXk7DSyM!zS$5rr z5D2(k@bLg{tdUeODQ!8yb7SOl4Ybu3lqxYM?;?Xweo9e$v%CW+eeYz_uAum*bl1$w z7Bafw9+cuk%7*)Z76Kh?%1N0`Hu-;|3_iouA8FFjpbTIPC>!c3FS0_D)WWR^dRa`p<8 z)6qqy-m@rsbeUOB%Ize36*BZ_H7Lv0FnNkn^g0siy#bR z-$k=ReoBQ)rks?H@biED1ka7M87aaI?+IS{ z_XPj%3I6}5C-};Wa*?YSpZt^y_sI!f+?ON8^rddGd$F%LztpW35H*&?i6KjT#oT3X z)h5n>3wXs>G=0^LXS-&<8Yd2c`w5&~G+G`f#xC_0uP%41g~T;*)tC8-4lCTMuUN7o zPMik!5L{6avocQ1dev9Fxzerri~Harm-~v7uejCXqTFdC+>kuea)?w5qrR`TjeXtu5qhnMe>?B(Gw4A9R*ij z1g?z}KCk(TiEG_zMR6G1Zg90h%nq6Jq|G+K}N-axeL-D+)d4cuvP9X7btx?;%&#J3L7f(sQf8xh}nM7zo+034T$eeHy%gm^(Nxmi1@%Y686oA4_xYIHy%LP18&_W#P^mP zj~yhxh4|h?eBh!*;1m}@a5FfbIJ#O6h z-UDvkF2wha8+Wyn-$8u45g)kzB5*I_+k^P_x^aj4Fu2{|YQO8o9qFuh5#KwA4_uO{ z@gCyai}>DitAoWEaEHJ(ec!Dni`nlZzIPEHxM8Bv2XShOn1?h~T>Ajgy@%-bxz%*B zWFMk?AJKsuA!7C;x)0#QZqS+`6NP?+ds3s>u2R@qLE)z^xE9zC?VVBfc-)>MC&t z+-`79Pq@|B#OxD@?-=3(w^lSd8K=H3<{^DUTtm7}G(Q!mt`|#?ZV-2nZWJ+J#i^Ub zDx`0U`$#v7&Zpzlx5Rp+TZDQhPTeYcA$?nHMY>Jczm8M4i+H3v#2%zOh5y+&b(cs+ zx?Ai=x<>?_i&NhbBarSDhtDCB(}?7}TYXPtosU!B7sru)AZlEQQ}>CbMWgGOWmhoEuDjJM;u^R^;5yuJtJlPm8<=HRG0VVR7coC!mR-Xv`^l~T zB<_Pd4X*D^w|YygzlmA)BWBqxw|YnPx`kPG9kc9~Tl+;3j@v!NRj{eI-P&D6yaRUe z4a~DUZtZtP487AswEGDY4eWhI1pVAY+yguDXSeo;B67j5yNLn%#jQP5#JFF2h@Q7F z*T6nj#B;y)5I(mt*?x7asyOp2!UWg!E-z)X?;^}Q2os!5H2Mu;{){kxLF9;J{ArW&AVg8CR@9|Q0AKYnheed&9w*EfCyo)d&@KV<60mA$ZVS+0z z?0;Y}flK{^m$E(J7XOYQ|Kz1C`A;mSdx#NSpa^`3#RP8RLte@bgIjkW5kBIjEb9># z(*pzuuDq!67>nr-UlH;OFJ+U#?FM)GF)n2bL$SpU`O|mdLKT;?g_pnuJoJ^VRj}3M zJQe&Q@OR1Akj*vlV;}j-wHo-E@(%gxk9}qL0^n=QRRzGG25<8MUsrbaQsWlRQhntP z@}W|-sc|w=g&@fWL73c1!Bq-MdPC4q#(P7sScBjI1rgG}AO!6SKrpHx1dZf=3hq%5 z;sZgH9N`1OIxh%LQqWXZv_sI-2ElYY1kv(11wP&oG;~1FTuydCu$zL*6tt9~g&-JG z5Q2q;AZRTwQ4rt*LF>X0w3YJ;LvVNntY(*jHC_5L0U{)arc2Lk+s(uhe7KR|n4}z|8D+O06DCrMDcNy;w!D3$s4p0y$ z{fi-KR|JAl#USV<_fv3>f{@}6JTFHShhSY%2u@PaS5_(USmmh(zOaEOAt6eP>$0T7HW z0m0e;2!_c!6jUz>LH9riQst^Z2u@RA3xXhBb`FAIRw)Q}P%uKOWgv(w4M9>F2r}hX z3a(O6G8lqUGCmlB#Q_i;pkR#jFAG7tKnO;ag&<4rr{Eq1A>|+#FGrMvU|kRdCn=aH zE0%|#XBh~lmxmx*9;d)37=nfsAebyCSAbwQ1(zw9DnlzmFr+L53oAk}U0$Lfpd19P zD?u<*&Z`7x-mR>juzi9b(*5MBYU)e7wp3AftMh}rd=v32zC*!(S_L)AB+8ng$YK3Y z-&@7x@@ndGZD~pAtga^5e!&AQMQElpw07;QuC`OPTV<#-f7k7Lsz=o>RN7UpmRimW z`D4-f6ue{Ad&iMt3-9P*+=a(I2!uC_3&!IKH9oYg?B=+yzYtn)NA zaV(J5eXak5b}Nqeh_hUxE@-lIsk`10f7U|L;MvVlDNGydAB2*~U!5eR4YS{4?5M+nwmL z^vr!ZV>13^lzt8RheMw@Hg~5rfi}q!_63_0>IBCQ^xx(_9m? z^4(0?OQ!6!ovz{&Fh^dPr!MOL9V~te@H^*4;2VIqn0O;j0*iqqz$*Z6>dgjnfER!{ zz+8Ysw++}1>;QJk;|taDH9kOgAFv-{0f*)J`D)G9n5{|{&>R+9 z0xf{nKr~Pe^723hpdwHS-~d+zssYu38o+aMgiwoThay`a2m|>0>So|AAQRv-AsN6h zfWJQX1^NN~fdN1~kN_kC1A!#qChYtS`~v(6+y#CEeh2OYe*h1GN5EtKnI=@)2IdW5 zEzlD&>;$$0+koA`E?^7r7O)k-=Hw2dhD}a>%UlTA7m=6>N3IJY! zH^86%{^T6{9hrN;ec%`1SAe&%l7K+~pDEz;2Dbq|m~aE&gASK~Z-E@>TmU@Oys8klL4-hX}~;S7QmIs^}?mh)yLH~2jB{u4+vl?z}5OPkOp)I z_(0TiKs_K7s1K9@Y=Af51K5FeoGbkhQGZ|n5Dz2(iNHW02^a*N26#jH6u>*y?*Q)t z`+(H|Z=?GFcAy}@heCRx7w>`&0UZqR`IW1{cfdEmMW7QOBb zf5MP=Glv4rfaX9;pcTN)FABhex_p2bk9XlelLC0oOc@G$!+;bZ6-Wcpf#JXiU@$NQ zNa0+09~lS0`?l9m`FntmR?Gsw2v`7Q0EvJbZ~;!BHT2p5Q=vNv$Ob&XSRf0?1TLd| zHgqM>9^g(K3vl!0W}D63bqW+m0sWC50K@_PfTED80DozJ1^kP^r{G(Fa+@y;v_rlP zK-vS~&fFb%9_R{mGkKO#-i{LppVOSV@awyIYQ=0{sYuPONS~ zH2CVEXj^|Y@C4`@U?s2u;INGbMgb!Mt~~Z0S6(WR0-(BHe;6o+He25t*u4n=BVZ5E zTYArNW|y(+*oDmjI$=f5`M}}eTxbXs0O|pCfx-YUir#MBTlP?Ea9;gbiKI>Kj zLeRecAABj`Wu!V#2dD)+2h;>=0}X)s0Ix4$W8e$5WPX|T-X=Z-7Ny!tOTvGrKkPS=(rUK)DEMN>^ zMM?csV5})4&oa^}tUVc-34jN%jL{G)Jj>8{$e%XO`j%0PPI`vSDzoSWHs}G^;NKax z3|W;J&2oS}@U-*GAX^H&0Y5y@O&I=}|_vAS#yWH|u0=h?sv zz$%|*$}OHc`SUO2<1HKc%jppKY|5TAXysY>tf&`3z7Vj6i+YTRx(fgS%m;L%`RrP@ z7?@Sg{5THy)5;PBRu3#eez6HQYBl(D9rCQhA<3`zD)^^$>9D20oXg0nYH7{|;z0uomE|lKYpdmF2PJs@=ASB3X8YS|;>uWVZrafVY6nz?;A( zU?Z>rSP!fN-T+>g$t%<_+b75#l-HK4b+bcM>{∨1t9s0iH2}fB>L0Pz2zmg;!*r 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 diff --git a/code-editor/package.json b/code-editor/package.json index 6e3f00c..ba41223 100644 --- a/code-editor/package.json +++ b/code-editor/package.json @@ -18,10 +18,15 @@ "clsx": "^2.1.1", "devicons-react": "^1.4.0", "lucide-react": "^0.469.0", + "monaco-editor": "0.36.1", + "monaco-languageclient": "5.0.1", + "normalize-url": "~8.0.0", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwind-merge": "^2.6.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "vscode-languageclient": "~8.1.0", + "vscode-ws-jsonrpc": "3.0.0" }, "devDependencies": { "@eslint/js": "^9.17.0", diff --git a/code-editor/src/App.tsx b/code-editor/src/App.tsx index 284c505..e30fbe1 100644 --- a/code-editor/src/App.tsx +++ b/code-editor/src/App.tsx @@ -3,19 +3,38 @@ import { DEFAULT_EDITOR_THEME, DEFAULT_EDITOR_LANGUAGE, } from "@/config"; -import { useState } from "react"; import * as monaco from "monaco-editor"; import { highlighter } from "@/lib/shiki"; import { Bot, CodeXml } from "lucide-react"; import { shikiToMonaco } from "@shikijs/monaco"; -import { DiffEditor, Editor, Monaco } from "@monaco-editor/react"; +import { connectToLanguageServer } from "@/lib/lsp"; +import { useEffect, useRef, useState } from "react"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; +import { DiffEditor, Editor, Monaco, loader } from "@monaco-editor/react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +loader.config({ monaco }); + function App() { const [language, setLanguage] = useState(DEFAULT_EDITOR_LANGUAGE); const [theme, setTheme] = useState(DEFAULT_EDITOR_THEME); const file = DEFAULT_FILES[language]; + const webSocketRef = useRef(null); + + useEffect(() => { + if (webSocketRef.current) { + webSocketRef.current.close(); + } + connectToLanguageServer(language).then((webSocket) => { + webSocketRef.current = webSocket; + }); + + return () => { + if (webSocketRef.current) { + webSocketRef.current.close(); + } + }; + }, [language]); return (
@@ -71,10 +90,7 @@ function App() { beforeMount={async (monaco: Monaco) => { shikiToMonaco(await highlighter, monaco); }} - onMount={( - editor: monaco.editor.IStandaloneCodeEditor, - monaco: Monaco - ) => { + onMount={(editor: monaco.editor.IStandaloneCodeEditor) => { const value = editor.getModel()?.getValue(); if (value !== undefined) { window.parent.postMessage( @@ -82,6 +98,9 @@ function App() { "*" ); } + connectToLanguageServer(language).then((webSocket) => { + webSocketRef.current = webSocket; + }); }} onChange={(value) => { if (value !== undefined) { diff --git a/code-editor/src/lib/lsp.ts b/code-editor/src/lib/lsp.ts new file mode 100644 index 0000000..cdbfcd6 --- /dev/null +++ b/code-editor/src/lib/lsp.ts @@ -0,0 +1,82 @@ +import { + toSocket, + WebSocketMessageReader, + WebSocketMessageWriter, +} from "vscode-ws-jsonrpc"; +import { + CloseAction, + ErrorAction, + MessageTransports, +} from "vscode-languageclient"; +import normalizeUrl from "normalize-url"; +import { MonacoLanguageClient } from "monaco-languageclient"; + +export const SUPPORTED_LSP_LANGUAGES: { + [key: string]: { hostname: string; port: number | null; path: string }; +} = { + c: { + hostname: "c.litchi.icu", + port: null, + path: "/clangd", + }, + cpp: { + hostname: "cpp.litchi.icu", + port: null, + path: "/clangd", + }, +}; + +function createUrl( + hostname: string, + port: number | null, + path: string +): string { + const protocol = location.protocol === "https:" ? "wss" : "ws"; + return port !== null + ? normalizeUrl(`${protocol}://${hostname}:${port}${path}`) + : normalizeUrl(`${protocol}://${hostname}${path}`); +} + +function createLanguageClient( + transports: MessageTransports +): MonacoLanguageClient { + return new MonacoLanguageClient({ + name: "Judge4c Language Client", + clientOptions: { + documentSelector: ["c", "cpp"], + errorHandler: { + error: () => ({ action: ErrorAction.Continue }), + closed: () => ({ action: CloseAction.DoNotRestart }), + }, + }, + connectionProvider: { + get: () => { + return Promise.resolve(transports); + }, + }, + }); +} + +function createWebSocket(url: string) { + const webSocket = new WebSocket(url); + webSocket.onopen = () => { + const socket = toSocket(webSocket); + const reader = new WebSocketMessageReader(socket); + const writer = new WebSocketMessageWriter(socket); + const languageClient = createLanguageClient({ + reader, + writer, + }); + languageClient.start(); + reader.onClose(() => languageClient.stop()); + }; + return webSocket; +} + +export async function connectToLanguageServer( + language: string +): Promise { + const { hostname, port, path } = SUPPORTED_LSP_LANGUAGES[language]; + const url = createUrl(hostname, port, path); + return createWebSocket(url); +}