N(|nfnwU
z;B{WR;u+t!`Fj*Uq}TFZ#ic*=DL$R`^eaA#`HN7iMgNH6N3$N!Yt}AVhs--AEzr*&_C@$r;C@%hQRb2KL?TSme-HJ=OJ&H@YeTv`D
zcJ5GIp1bH*T*@6#T*@6%T*@6${9!IPs<=E)5>s5t9amh+olsoL&HhJfKauZw^Awl%
z^(Zd=JYRA7p0`MGx&Q1_T=bVHF8a$AU;kZeca7qYvfo-17yYe@i~e@SpJY8fioeRd
zPjS(|LvhjHulVb%$9X-~|NCvX@m$4ayyq#N$MPPb>-6^d_XJvEBAvK@_zN13-MF7<6yTQ;!@vU#m87r
zpW*{--wwq+9Pd|L+IK*4sc%eisju&?$?MyzxO2Oe+o8DBw_kCo?||YnSkI8+QMPYb
z@nVjTC@%GlDlYZSetYtI)uiDAiXY2%4l6G89Z_8B8&!M`>xn7uaC}_x3XV@GF7-s`z5Ib6jz$?}Xw~U+3LadsefaY{lhwE^-xbWxaWdOMN|xOMQKc
zOMUy&a3`K>XBFF-tGLuRPjRWQM|0MbuXr)rQK)z?^CHEizQu}5eQOk#`VOVx9{dG3
z9kQ=!XFCfOm--edF7+)|{6^N}Q@n!hC{cWXdAZ_J-wMU0zU_){=W@Fhm-SVT;)nK{
z>N~xP-^F_R6n}(yzv6#kKA^aiJEXXjJFNI$S3nRi(G#}$`yClr@*9sZ3U
zY4>c_ldZUvo2U2@ET6Bqlv}8{>@SKGKZf=A6fb06uDI;iDijy}HHwS=Ud2yi{W}zw
zb#lMrXR`c&;%k`?E8fa}k18(y%+5?5ck5YCp5o$9kK)pf`HEMwo(jdAm^Uge^=(o7
za+YsZypwsm;tt1q6_@%BDK7V8M--R(MirO(#uWc5+vAy*>d%{*`xGDG{OyX1|9cb{
zdwLZYd-@c=jmwQHelPRveNydgWjUYXZ}PlUqPYAXL5t$@chIeh%il})DK3AfxkGW!
zlXgBCQC$9BGOBnh%V%e$)=U0gAXjnuyMiLc<@vW_#pOA<8pY*)W2547U$RGW>Hoco
zS8#tAQe5uu4J$790Vfof`NY{b)ekc7drHvd_;>t*`9sa}}5Uf05#{FD_QRg76qkL0vtOzoWdD$_xU8!S6?bGEsJN_4D-`$e
zb+%n``5k~B#S`SxiPt@tCXCr|M|GS63B^cN~F`im5Qj`jEye~o#$;-bGoanWC+_}i?fMe&>;@VHi7
zeh*m2lObuh~@hf7ys-~T>R6oxU7GM
z6kpEzM-&(RQN=}nO!0GB&xGP7%(G{t`cw4hDlYo-6fa{v`HEl6yhw4;U#z(3_bFb(
zddd~w$h<~z(ch@J=xWFdtET8S|*(pJE5?yU@qJvp*u|-Ca`;@F%8;YP#pPZtrIow*ej<#p!o~M@
z@fsKZh>JJ6_zV|saq$COyw$}Ibn$i<&vEf?7teL^9v45z#d}@+qb}a(;xk=*hl|g0
z@qQQon2Qg%_#rMn1%sA+t-=(D3)%%tpkzF_^_|-7ugROSHw?y
z6+5!{?A`dxIl9;(`5H@oI3dEtM4Z2OC5Xk*<_qL^yp*BI88{SyOMG0*rPv6#;HS(-kgZXXVYE$>YSsO
zI>x{8+5dxYh1~HksQ6VXzEQ>NRlHioKda*Bt2ljI>n?wpil43G3sk&7#Xqj%N2&P7
zRQx~{-&e)o#nTaP`(9V^zoo?I{&hviqo4J4JnL(Fe!QgAJ9l92L%y!F9!4v~XVHTt
zyQ>Rwj=ly_41lh)&ZBYAl|?&Y-@=K=EDVi1AVfoBzj!p~=vI<@fJ4Y1W8_aejDi#1
z^>vKn32?d*3L3TW9?UwvBep=6Z2kq}PpH${+JL}VsbbK8z
zL}vIpFcw_J?=k@mLjl;_RoNqO-x+^~XBSLl01X>fPA+{M9u+Pvc#C}A81Pc+?5Ww|OUl^pb%2dBo4;>;61Q{*)Ro2K_0TV_Jf
z1nHSD6(8xRN&aHD$J{QS@O8~P!}KLnt9?-`43|?)_O4m8lPNF1Wl|2~l$ptt$4pA|
zbW_k+ma)QRc-zY!X`w;y+s4HCR5xFz(^>Ymuktb9&S&>QC48OKInav6kj+-9>8rEa
zyl+#5Vx7g=3%ze&xw9XgAf7B@9fnRm%0SCELrod}Q!g-jnjzWYeZFn;^G?eVhEuW6
zCyRy7QF?@f(mG979qBBdv2fRw7g;i+V>n|VW4L42&X39rI?VR;Ioj!Uu`Q7)%
z-!n$YY-3o5QG(prZ84O8@kG+0@Mp2KSx4E^zK&JHD?7YHD?3&V40_FTrK8`mE`yQT
zo!;HPN?1CKT4z#2?u=pv9ZC$ply?0N?Atof9E80Sra7N(zL3s+woXuEe07x-JDZd8
z5JI6zsabvu%YjGfwP&e5m4X8xa%
z>B_1`zwvd>gg2}j+oba`gxZX7hRxG9;oG>=r79%y7`!)90m<dPWkM@CN-yph2$CLK@*}u#%Gg-w3UQd+I1yR>D23@)Jep-~q=0GHomTNA-+uSNP
zBi%|)!&x^uw#s*sbzmebw%TM@W6UFCjHKb^afH#-VFLuyO~1bsDw3^)Mrt(Gy0-^a
zbhp(6+NyIaQMhK9f=&~lN-{AGT6;RSj!c@2>47tnGmVVB_-310B(zn+I-86u1r06C
zGql1cU!V04#JjRuy*7FjqJvxeP#krH(PC^g5`~~iDZ$mGROhWRYnut6@a^4bysdWv
zcA8HbH=S0<`sXopZQB>p2)tz+8eVsp{0y?{l;u|T^cArHZ|6I{AZrb@V
ztnN`I+f{Ca8J#y8>8y^Mv8WsFJnd?PW`cd=^$s&gl0A3ym#D62r;gj1wGPrbKiGA`
z&W?vWvz8%Zt|I5dwH;f30SVvW)*%Gsr$IAF=xoeq`+aBDOp|@sjvu-%i5JW=Am=Vl
z!5oaW<8Pm(X?Z`Ru+1pL0Hg7HhAHaG+d8v;@h!*cnnA5WrDCQ*Q+H)u>8|s)UP}xQ
zJ3P-YwanReoS9EeU+XM^FS*yC!hNKx@*&^OXK-mBqS3S~LQAmw%t~wL-Nn>*yRzbo
z$+fheJ<=8!D??dOWSXZqzw<_#bJ})gWKcB;c9i6|nSO+cT{_}I19G^14Xcc=d^(vw|ytfteHDnp9w8=*?$`qyEm9RQkr
zXj#*>bsT4jdFUJ(8>Zn%KniPj7gm76($w?HFGwvCE{6(SrQANUZfNsITjQ
zKbn@MCA%Fr_d>({Xmls`8qR2?3ms>8cVBsD+veTQRf|a%t(;G}>XUN1a0}_YA*pkx
z(iuwV{3hw#ygQ@0xNY;(4(h7KS7JxWeO)41O^+St7N#^dqP>#b1C
zRKZRv3(!=!7}K6$6Iruw(weU-Yo3A%Tf>834GM!EEHx*R^BT1@HdWJc;IY-++W`PMNvxQ)HsmNO0|*;I}xvu&Wrx6nJ@
zybUJr&juZ6P3C>SHJ7%qovZL4-pio2vfc||afEKudDdY!;Zov#+g@qj=yH_LylglNJKc
z{}rz9Ko@2`gWhgZJ2t=5+ijMHTe%d>8b@Se==DPq_8Qm!7;CSNX{OLNZ#S*wZNU!=
zdT)UFv;iNW>}{L-oCs~$+B=K$JG?h^dT%g;>5yX6*r=>3$?}
z?#{BFjK}zj<88;~W^_j;70{EhWxqjhFA8(U4uKkMnozrY(2jQ>4R*q=j&
zj-9`K7WZzvw{#vE{F>wR7el}{+iPcdZwVLqIHs0q8kToKE(8hsLNI-OmxU=n%3<
zi|&uP;5hI04)2am?+$DXr1i<5&a#_mvh131BUyor1HO!hJDrY9B*-otHP6^(vd(a2
z9ctT^*^%4ky(zmQXj@qhnN`ZCq_T#?F`E@3J0u5yNc*nWmfk?hKb;
z4+(mEOu|yPhAk#xyGii66RMFQjX)-)^mtQe$7DL$ooOyIxthhekNWjaZDht!+rYFA
zEImv|MG&JA*EC9HnwA7IO~@vU9x@HJ>B@T8-S;1WIOO(h-Qm>MohTwtc!y2vKEn}A
zSi@Aj>D@eG?Z7q=g=Cy*JQq8T^mk>Q?=EwVWnRPR9tjoSHZeWt+T$?TItCIQqbn;P
zp6T2tlN>ke2=Y?K@Y(UGb|tMtXiC~tL%MMHvN-qEoRjTH|BE%mw)NvNT<9ObfHPCZ
z9E`;IUnM(t-hBf4oQ%Z#+4c)yr@f}1Wi1{y3Eq*hjPA51&^oukTpD-Y{RvbD(L;>8
zXr23I)?5cWCf8v4!_{t^k0G1sYcJ&goI4?#66o(Dk6=dR*hY%MIp(C=(+_jO%GOM}=D=JyWo
zot@r0jp6@rkCz(g9=lMc2x#0&mmYiFeA6v>4hiCprYn87JN;;+qmHA7!TVXU+y8-B;`X0
z=TSO80_V7_s2gQ+SJu6@AP>6N7P+|kN1OKroftdXq)oOuc-ZvMl>4-_5~s0&|7O_|
z!#V!jrNx-f#N-|~<_EHJ;|s>(2}pS;UM+E)f7+gtX(^ga33ibZYrZWJLympXzxKS@
zj$5nE!-L-E=>k0Hg$M<>;81`?DH)J*3-&j(3nDvd6;0oc(4D`$(akh8=yq0TaS^S)
z=*}`CB}K*pd;R}BwAp18iRF>lLJ~ti&9h-~uFdA7{yJ=zl8}Yw<`L>M>0u0?OZ#Io44&rt`DIW32y`HghMEjyry
zv;2=B-|2ncNU{#A_YX$V%SO@5Cix_{qPvl76rIS5LPmbv$lF^XZ<%?F_e|G`{F|1>
z76RBY8GqJvL#kv~Nf!AI3#t1HX}q?xYOKd
z>&*Jf7s-U|=A{sep#(dXuXgKl^l`+j#hS!!sKE+7R(=>XfayQapiqqV%?SZ~ZPaCM@n9l>==rc!ZuZ!b*I>=G>Kf4}Su@RI
ze3~?{t0j-st?2msijEZpjqZ-G7?4?$JNHDoZos
zd$rC^iVwzqj)B!-{0ANBdf+mYk8x@pvy6)F%35t%?2SKRs=GIe25?%AviHwS>#uR=
zIT(4&Jaq}@+G%o8vzc6UVsaho&h<2eOs-QoS0{k&sORAeDGs}qgw(@je~Gk!1|
z(VerI=1URW)BhZ@CFc-)XNH-Hzlo-MV05jv{pAr_5X%KHXDc2z!0@FVvAyseVk2gX
zk}Tgf{m;mltKP?~3_5W_>$`T2B{k;aQ^-1v{B(0Y8_T-eTzO1kW@QKc=4ok9}
zV20FOQyDwU(6kp>Xy(4-&6JlJS=Ba?m9zC@DH>=%TN8|iS1>1xPMB&*8A@U;j2V5x
zEnx=sBc~(=cJ?35z+Ub)(><^^&(lNa%TJrGW9;a_)m8bi$%;v}wvM-X4M;8
zOouoF7ULe(4BW>e6{81EmG_g$yzwU!dH12bkKyBAmg^+*K9I*WvaSqG!EXyMXwEBg~~Iw
zQgh^N`!+b;-N^dkwMg51lM~5_y@+mXI>6|!&DGS~cefAqNvzrK`U7dF+lRQx2~&Ru
zr=zhT;*6b?YA)6p&}+Z^MFv~pg@2-Lm@$LC^Zm82?Oy63PR=!WaEzu4ilIOBj$-A3
zxVM*%PxQraU`0uGd;@mbjr%p$!d@%^vW=y--~kMEQpY=9gl5MJ
zF|)JiP40Ms%#OEDwi8dlW^5aKG1AB!8fKMbW#_6^D!_d!WbjQ>3TitTJC43z>dHEm
zEu1l8qJECP^Lscy>yuw_9DH+kcQLADE@7Xw$#x7LN?FL+(6-ymFU_XJpF!H*U!;_G
z=uSmvSzpKELKOGa6RktO4*in%S9UjjE*JfIS5iN=b0XGczs6{{i@dAcmVA-2bY-=(
zhGHAt#?iSpdILv~W&N}qrCT6R;JyP4wRQ3$@jj|967F>;oSevYvdPu!PRvOp7MjF1
zcjBv07~|$}@!z)5?h~vdZa~x&tuN=_M}lkS!lk^U`FVb(EQT(KFM*zSu381}(0(F=
zQt*XU&V9IhzMHi<=((wfQ2~_lC<3~_(eayDvFU}AJ~d_^jiYLeqwpwI
zXY4qfjpy8jxx+hwniTDdOgD}hI~lzjPol|VWJtSap!qRu-$$ItM<6|dB5@ZX*G%>)
zHSi=?K(tO7j4gW{ZILK+Ft)(Paj}6R^qAXRb9NGK<7hV*!`)x(6L1MKR+?(9M;=V%
z>7Fm+hN8Tv)zzDyk56};%RTVa&e*>A4&3Gbwuc5f9&XPya|sFJOZLl;G=ejmtP54SzsYLx7e)b^0kU}|uZH|FxR
ztTU-u@jxJ5XUKWfAL-ki-B)kkeLq;v|NIKGHX?tf$QS8`Ia)EAk@IEx)(7jpoUM1*
zX+4GsJi}(6Jpi$@TJe!{V?yj&7PBHdqx;StfS0++5?N7${qVKNZn6m(a1q(PCFdKW
zN>gPr6P0PE4owxwOk0u20b<(dF3O+q+0N*U
zoSzPu5ryx5a_%}f=dQtDQY^Cv%cS&j=%u&)U-W4HEjw{QSC;1D8I{72hVn#Blc)}cyP8eK5Y+Y
znZDw7BA4lQBCWB=i5QOwCpI5vNUoFfP3}OEO)@WyG&UA`R;zO`-Y?E{O!H3RZ{eg9&X(9V%f%Fan`SLu6B9a80#KlS&Au
zlT!(mO~F7U=+eXB(%`1Bi<;;fQ!A&kp*|dGYOahlG`S?)^xSp+B`X)LTjyW1_+0Oj
zQfGD9%9T!|m`$0go9inhp@w=t%=S;70z+LXm4VvYl#B)h8XIdjrC>|ehw7_R@E#!H
z_}XCohDePxp1&@z!8T!vg;vO4AE*mD=3}n2jBAim%%o0OvU1J3vbA0((%@}rY^V>`
zM?wKpm-^)_%Xs8VaO#Ro}Q~#vm
zi`T4K>0Pv%w4$$K%$bhHZJmVF#~4=D1ez8_9Mk@OjwA&cP_U$-Dwrb3pc1^KAygkp
zCb~$tHdJYb8JlC{;pX)=?lLsVP_s(gHk^q8I(M+e4t`D$QX2?IR&Z)vAW~W5(re>Q
z!N%G^iX}ogT!e8J4hEW1@-hfF)`m=9kxH0&q+w;l<-w*Ufv~%RZW?JQYs4&RB+wdl
z&U}|$2GEBWV|JcHXX_$?CU-fB!3rBOUAZzdsBUVgTf%MQN=?BgA}!*qLpgRPPWl#S
zc2-NwU+YTOu2{XCGzOZQ0-LC>af{eE&0fh)Wtpo_H8zJ$3)ln`YiwvtsxuLEnIyR+
zCFZL4#vsOVQm!dzLAWMVZT!JytElO8)M~cHS;)ql>s4myM5NkGs^LaVH-TDz0@(aE
z8g9T`NCSk0OuV|G$s6FF!(32Zz*JnsDOw$>jReg#L@1M{U{y2sQPz?q)&`E-U~Ona
zjqMaE(iVpsY**sCQ!Er-M6H?hrT~Q}omm#GUAyQ)${K8HYM{xRdy#K&>qz(K)@CoBcL*ZJ>TbP$jQjw0gN$
z(u38(reJ;L9x~o#-nHJ4hbdzijOal?cK)
zaS;kO)$dUYx-P6;ov2Bj9SxYQYWz5dhgvWvw>aU@hI*&kZ&o}e(SX2uvq-6?u)4Ov
zE=cT2WiVtevL#STow-6umoRw>q&qH+0^0|dxr(}h*
z?!2|7bN%y7I1gr+!Ae18gDIPWh`l0F5MT)t23W>~0hTf$eaxd?Wa?sL!4@+@D5z~P
zi$n?<8!k`C(Rov#zN(=vfjAnfYc{nt>P)1v_H*--CD<6IK=y-?<0xjmdb4V^Cn(h9
zGa)|U7uab}R-suOvuq%CNf-+_8?%#WsM-uF!;|FPbyx?i-xLY1v`Z~sokM{glk1zS
z(L2or+9hSi;$o9TWu=HtI!?^M^e--3hAvGxXoXzG`CRif6|tte8nd)x3wCh9HQIHi
z1SeUgkPr=pDr2Upk&;-C%i-i}6B;i|{dOK%d||0~oxjAp*6&^EUFBU}>XcyxQM9Bs
zP?u1y6i-_DG7O`lC9D)9t;pJym@6omQ%wOX*@Vp1VM$Bm3M1uKarlkb;B+%AY@P
zPYv_uxist{KpGMfX8pN`$g-7d7Actpr>b&{%z{(7q{MoN+OH|N0b|Q91ZAD%;^w-Y
z;NgbmCVL5TWn)-f8`xmRzAMSHU`x=9Bu+5VNH836)&@6V@$V{a(pFrH6>@orQ*VcS
z6*gvmI$z2=Gy^8hxO7pemy|bRQ4?{NV1tHbvH`&+T!8BWnEH*Xl4RTo;*vr#8)_TY
zo2xvcp)f7*lhDRP;bo!vkliM-bONoY$Hp~;4KQXFvxlv6tVn51C~PivWC~V)Vh1*Y
zWaI|pD12i7VRkzvL?e`j>Vgf;_IjR-RbtuS2;XAkyUCH=CL
zhMVDkiqr<{u>Az5YjHL015gJ{=#`h!q6H1Jk-8e~$8q}to6yGQ^;kPPs7?gIrcki9
z%E3OCmpte{&2$sO?nE7X)5Fyd>?OeAjhb^NJb1QqCUv{BZRZO#ZD_Uz8CBSXN3i#R
zL5W)h?%vJ|ZR`z54$h^nn&^IW5@%+EZkHi`dk4YqM~$&(!e=9TmOUyPnu4cP1slVs
z)Lqsbs=V})Wx4fX`drXC&h~H*rqxBIYgYMZhdr~a_TK}0
zS1&c(<2mI-Pax7z=Z^%|*9JW&oe;c-HKy6JX!|u&%IWcHxP&
zEhp38_|Z`rX_<3&Wpk6?N_x&Z%M+e+HfnTH=;8v)jGU=0t+sw*-j;@xIsFtmj!-LFYdOWT&)9#@@@T3-FK^<~Bx*bF
zMW}$ir?+HH+3Hfy9BL>F%GP<;T4T(8K9A=jlrl*=Y@ntv{ls1(Ja)>ECJ6<@d-O-g
zDQ#%*-~zVEC3Uj#Qm6{HhU)2tB^KQqJZ4BPTDfBRYSZGT9PT8OY4*S&X6Tv0fQ2mj
zlkH}yDY%J?twFu9(Bc?^LE^Zxo!RTbuuP`xLm
z*84lly`}5Cr4H&*A0aPeKzYtS%Tu^VXE~Wj+3KZU+-~zOH8FBEp1s9^Bs-iY?Vr9i
zYfJsq1x)um*~xFl+>douEetWXaG6Vm$?U9OJ9
z?OVzRBby}crET}n_RNF-r&-XMcXE*yJ9zUvyTa)XXBf-xSz2ot^%ZDu;JEPAi^k{mr6`!>66`89bbNA`%O4!C!UZy!$)$FRpqK4kJE}
zKO1a8_=j8Z!@~%V?2E^<@ipN>g!u@|5c&`X5!N8Q3Sm3KUW9!JpFuc;@WAgOKf*T<
zX5$&);@glP;SPj8gdhDr@*}L;9*=KB7`P)I-;QwT2e1R-^d0dy9tCzjduKeJi-&s;
zzbhUuM0o5^{FC!WhEeA-rNB9^Z|y6m$1X`~~86gr_3x
z8H~qE5w;G+;}L}CJsgkUfbe#NcOu;In|OQ#;RwPBgmZ@D@w|N<=W7Uy5avD_kC!9d
z=P~#RVG;hapa&rxGi~5xd~U6i(UO~S_>Ae<865`|Keo&N~Dh?eUUr=mC5v4q#uOx=eW~rlIh!!eiYJ2
zDP8KH88rf?{z!ij=_^vwixcU;LV7O7Kx0b!hD7?yNUuP8WlH*|O}Ync2KxTDk$xWJ
z66Jf_rcGOtk%93
zy*nPi2qFoY%(aR17NpO(Cm#P&O8Rw)^d6*dLHZwHYa;)&;Y<>sI`$*I=st|=l>BQF
z`A3l6i1e2cCi6cxP4Z8GpNX|$EG7S+6Z!Mt`+YF~JeuO;p@ff%kp7cj#N(ey$-mCz
z_kfin{qIP>JEaYOXxfmnP#vyB+O-eG)YN96yx9V^sR-9C!H8@=H{@$i3H4>^YzHk?ZKt
zv^=P{nGye>S8LVNWitBt=sPt_dm-4jy^-BI0
z71#3LQ|VLn*Sl5uzu~y(mG`Yb&s_W__BuD)ip%@j)5-7Q;3V&q
zyMW8DPahNi-;hSX_~%yAY
zH%rvtY)=khE?9>$evf21X$R@ovzd#XB7eG+$K|Ax*X6y}xY#f4Sj^?FFm$`
zUaI0&^JSUiyx;zRgwmI){k_LTUpo6|tMZCpvSqwq`-_ym_ik}&4$+s+{$;wnvG-=b
z=>06~k?VuLj;!Z&k#AD+dOfJ+H>&)i{|e??RQfg**Ye#ey+_5h{5MqkttzhNx2yC!
zRb0#8tv{N~N{z4Vk`Y%@LRVuFKYgBpz$J5ypR`Odo
zF1=m!i~V0v@;6SQ|7%MARu$L!Z&&H}sJO_>e7H-cKdRzd{`V?9s^VJy1(p6+71#2w
zak}_#Z^O6uGT#7SxAs=A$jNxj_`W6S`onZi7x`Hnm-$ZWEB)bUPM31tZ#Z`^^|ZeF
z{z{PgF5q%>J$%fk+J~eoeFNtgzsdeM%>0WSO8(Z@3_{f@F<MR;7Z&{}%r&p29z?IoNx=Z9U@2~}F
z{n^Y#Ue@17FqgRGlYPxGD!ov}^}a^r-)oDX#(Je5vOYhP`C1M|Z)@TSZA+wHlCDFk
z-+HA->MQ%{YL%|_q>DFkzUeF=_FvAtQ}kwvC8?VB*8X(&pTz#JN;#?Or;Odam-zFY~od6HBy)e;t>0eY4lf4g7BJUY
zZm~z6D{b9Nd3nyN_s?2mYFzZoa|Z+RTtTW>A|~>3AIB5BeSk(Y5(F-5-;dAU#J
zQTK0jAtEpHN^i!$Zg-KF=K$n;HLX|TA}`;&NBMhnN!Ovs%lF*9FKUU@xX8=*$`$;5
zYpPT-Ci3zlDSKa*u9jO@iK?yJyTpaMgBCFk4_;k
z?X!sGC9eG`>lsO3uI$(H=PG?ADz4?rRQkmnmvyL?uTkj{oW-F8GM;jCYzAph^YT9k&16C8w})^%
z?_zr*yqGH_^%^O)>HCR1hevTJa&N_L{ZP6=?{a*c731%pO#Q|0;~c+>)BnlwHmL~f
z|91tR1El0sjfE99Ud&+$hZP()a@fjYH;26(?%;5M!(k4i9FBA71RQhZa_Hf(ki%jQ
zOE|3Hu#rQX`@Mf==Vq8pGJlGOD36;LI2_|}oWs{RoZv9d;j|rALpFyw9M0tMa1M{=
z@K_G#a9GIU0uE2-u$aRY9F}lc#^J>rR&uz3!#WO|IlPL)YdPG;;q@H$aQJl&Z{ct|
zhd<`@4oEe^lS;dT!1;_&AjE?=_bbWeWS
z`sVsbvuE!7g82o7a~3q4=)9}uomx{wVL;
zJv<@NE89)EWH1h?Z#i?>w~L+{k&ha2hkh@J4tk|3>5;z&s4&!VTA9m!Ui5sCxjfe{
z_5Fr$-rtJ+?aW)5i~gO=Wj`$Pk29C&wnhFW=CU6a`8abYW(^nlJowwxi@C_pWiHPp
zi~MrtvL6=tiAQ(p1T$K9_F$i7WwZpcX;0`@((bV{jkVC#ax~*
zs^A6CbIj#_ipamhT%N~~e)5LMzvh@jO|lK40`4!d$+W75UlB<$GG;3z^IQU-YbEF5h2@{AZZU_nE>kV=ngv
zM9&wPC%)%%>~RBg`QA_T^f8zF1)_(31BdD>--n6(FPY2tW5T1%;<+;2BCm-~Ps-^JYF
z`;VgkM&@!~QslqQT<(L5{2k0?pDgnCGMD?#BL6GqvQHNIKQk}h#~R+4jmqH|XFf2)
z@(M%oeL3cd$*!9-!Rh*YK$R7g{nru9Pf+|5%)QKWS^pg7Wz1#YcMfyBpurr+vixf1
z-OLv;zmWN(%;zxQ0G{C-=H#k%`AXEAxQDq9^BNtOvYvNY4^Q7t#OOKLskz6>(K?Ba
z>sbE9ppDZyhK{c>FRZrlMjJTWnfEfUWPTU(X&WpszjcPw`qhzro!6h8fac0ncy_c3QYzvhU5pK9SmYH5+bz(+u)C%s?1?G3kaQYbYMPIP|Gb}#>KH2#CDAFh6&pw~xnfxn8KF`tn
z@dFJ@LmGZHxW`qV
zoOWOUdN6(+9>2oBo<`3O!*iYd|7Ru7wbPt)5A!3pSzgDAevwAc<7xPdtmlGGtKc%$
z^9pz_?5yE^4P)nZlFvNIk^5c3-%g`H2lbuI|36N{PfWwlNy9Hp!)p!Cb%wZJGJYdz
z$y4o{2;Kw>pa94gr%&f
znECE53(Rl+;j}c3{$Lv30#5$X{qP!a50~W*zL7@H4-LoFo9)@nnH~U_YqVR>pGZCv
zcY7<`)N!5%Kgi_=bbEWOt89wQEogA?lgH~r_)X&t4nR19SN`D53;2oW;0F8%HN79P
z&RIVzxZEJIJtzM-cZ7C0>V$NU1NT?r+G(3GM+qxvGh_7NXk!5+m}$Jkc5o=
z;pLk<~5D4AnbmJ~^{gdE;TwIQel-7qOBZzbD9S|ucMgw6ZOw0H_l$kIDmw4{qAFcESfXPm@XHr7dio|QBP?tm`nKg+LS&X(t^0K{TESbs061kvAUNB`#;#e|Q
zQX)CpNRum@E1JybhVJ6zRa3S&jwQ39IAMugq{@}e6;0-I!$iiEcUz%AcRZOjg{J0}
zcV0Fo6!__d0GP$i
zd7!GwkrP}}@Cv|l*InQweoEetcUO2zOD{BU#3)^{X0_j6Fdr|yg5Jtdi04g;WAde!
z#R$O#1OpGh`|qHD#+Oz0+NdbFi6ynuV^i%hh
z=G{;9LY6SSYr2No7aD`WL33{8>NeT)g1M4pU!^ozafS3csVW{Z)lEUXpN^W@PuE1e
zAw?9}9swtWYw#i+(;i$Zc>t|w`bG*O)54Ba(5a?N7A0&>l=Wq2V9UaYftrPq&(bTC-FeC3M8
zOZ@W+<`tZVw^8AhSb?S#=DIwaKCqtJ3~!Ic#2czlNX|di39LtD5`fhCSCptJ>VkE6F-eNBF#<2n
zMH0GYN)pyou**7)`k6nB1y~3#+=K^|X!WFKY^cLqAg#~Q%KoZw1KxXHUj-*pX)Y(u
zJryor1JNoP-C?|5td3s4QJHEE-Z_C+txb~PUyrV8-A-+bqWDcvSij*FThuss?^!6d
z;?T5vOUw
zDX7|1k0NXsX|gHwwqSa1xDn%sA8Ad&+5lzXvqrpvuE1DcfYX8v4T#c77_T)fh~TYq
zP628gf^>uF%>}_4UOm@TL7T*^4!gXxIpmyjQK3*^3=Guay>bOs7uwe;z+#@>2q$}l
z4-g)XytMV_+kH;nG^+IRZk=hiG2-&1u8$iw}TD|
zkGIjpr|e4wtiXx8eEFVMLXQY?sPkU{{yLuh5c}o%7zy(^A8repL)#w!rF(>ue}wIq
zu$L3aM)IBHm*;3gV3bAj%kwxA%JVl6F^Bd)-B+P!TO_|c&mv(F=M(!yPQt5@PS46n
zT%MPau!Qq#`x%>UFZopR%kw)D%JVx?zOMgQkeBi=W`*)Rkc9I55ap+P;X41fz{n?}
z->E=^jtcXM9d+uV+y5pcyYqW0th|I3%Hi1Qn?u4|5p(Bn4cK%EMb1*X*I^F{cOdG{
z-_7|YETKf#A^9Zy8PeSO<-UuA*Pr6bj8n-c^nR6J?!QSW_m4$h`|tlazqG&HKay}<
zHGoGHarkSMU+%w3NbeMKAG-XfRQ{5Ct+a%n$#UmT_8*}y;N(F3pT{
zPV_(F^gKfj{!4y&E@NUZ^V4I(R7J_}{1y>99S{N#O3TX0RHV^|fQgeH4(D8xvY
z*e~}1Yxw&?u~V{n-Y<3@YmUe{y$r{{R30
literal 0
HcmV?d00001
diff --git a/scripts/amalgamate/amalgamate.py b/scripts/amalgamate/amalgamate.py
index da342ec13..870128780 100644
--- a/scripts/amalgamate/amalgamate.py
+++ b/scripts/amalgamate/amalgamate.py
@@ -1,3 +1,8 @@
+/*
+ * AlloyScript Build System - Amalgamation Utility
+ *
+ * This is free and unencumbered software released into the public domain.
+ */
from argparse import ArgumentParser
from dataclasses import dataclass, field
import graphlib
diff --git a/scripts/build.ts b/scripts/build.ts
index 96a845738..d06de5daf 100644
--- a/scripts/build.ts
+++ b/scripts/build.ts
@@ -1,3 +1,8 @@
+/*
+ * AlloyScript Build System
+ *
+ * This is free and unencumbered software released into the public domain.
+ */
import { build } from "bun";
import { writeFileSync, readFileSync } from "fs";
import { execSync } from "child_process";
@@ -19,8 +24,27 @@ async function runBuild() {
const bundlePath = "./build/index.js";
const bundleContent = readFileSync(bundlePath, "utf-8");
+ console.log("Applying Alloy.Transpiler transformation...");
+ // Alloy.Transpiler: Wrap the code in a Proxy to forward browser APIs from MicroQuickJS to WebView
+ const transpiledBundle = `
+(function(global) {
+ const bridge = global.Alloy;
+ const browserAPIProxy = new Proxy({}, {
+ get(_, prop) {
+ return (...args) => bridge.callBrowserAPI(prop, JSON.stringify(args));
+ }
+ });
+ // Inject proxy for common browser globals
+ const document = browserAPIProxy.document;
+ const fetch = browserAPIProxy.fetch;
+ const window = browserAPIProxy;
+
+ ${bundleContent}
+})(globalThis);
+`;
+
// Escape JS for C string inclusion
- const escapedBundle = bundleContent
+ const escapedBundle = transpiledBundle
.replace(/\\/g, "\\\\")
.replace(/"/g, "\\\"")
.replace(/\n/g, "\\n");
@@ -31,11 +55,19 @@ async function runBuild() {
console.log("Compiling AlloyScript Binary Host...");
try {
- // In a real build environment, 'webview' would be available through pkg-config
- // For this draft, we'll try to find the webview.h in its original location
- const includePath = "-Icore/include -I.";
- // For a production build, link against the forked MicroQuickJS library
- const compileCmd = `gcc -O2 src/host.c build/bundle.c ${includePath} -o build/alloy-runtime -lsqlite3 -lmquickjs -ldl -lpthread`;
+ // AlloyScript dual-engine build configuration
+ const includePath = "-Icore/include -Icore/deps/mquickjs -I.";
+
+ // Compile host with MicroQuickJS integrated into the safe process
+ const sources = [
+ "src/host.c",
+ "build/bundle.c",
+ "core/deps/mquickjs/mquickjs.c",
+ "core/deps/mquickjs/cutils.c",
+ "core/deps/mquickjs/dtoa.c"
+ ].join(" ");
+
+ const compileCmd = `gcc -O2 ${sources} ${includePath} -o build/alloy-runtime -lsqlite3 -ldl -lpthread -lm`;
console.log(`Running: ${compileCmd}`);
// execSync(compileCmd);
console.log("Compilation step skipped for this draft - but command is ready.");
diff --git a/src/gui/components.ts b/src/gui/components.ts
index 90f661788..3871a13a9 100644
--- a/src/gui/components.ts
+++ b/src/gui/components.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
import { ColorString, Padding } from "./types";
import { MouseEvent, KeyEvent, ResizeEvent, MoveEvent, DropEvent, WindowState } from "./events";
import { ComponentStyle, LayoutProps } from "./styling";
diff --git a/src/gui/events.ts b/src/gui/events.ts
index b30127d02..b086fc57e 100644
--- a/src/gui/events.ts
+++ b/src/gui/events.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
export interface MouseEvent {
x: number;
y: number;
diff --git a/src/gui/index.ts b/src/gui/index.ts
index d67d018c5..a12d6814a 100644
--- a/src/gui/index.ts
+++ b/src/gui/index.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
import { Window, Button, TextField, VStack, HStack } from "./components";
import { Color } from "./types";
diff --git a/src/gui/jsx-runtime.ts b/src/gui/jsx-runtime.ts
index e12f1e11a..568acf3ae 100644
--- a/src/gui/jsx-runtime.ts
+++ b/src/gui/jsx-runtime.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
export function jsx(type: any, props: any, key: any): any {
if (typeof type === "function") {
return type(props);
diff --git a/src/gui/styling.ts b/src/gui/styling.ts
index 3787e5f53..a1a66cdd8 100644
--- a/src/gui/styling.ts
+++ b/src/gui/styling.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
import { ColorString, Padding, Margin, Border, BoxShadow } from "./types";
export interface ComponentStyle {
diff --git a/src/gui/types.ts b/src/gui/types.ts
index 34500e9b4..ebcdd098c 100644
--- a/src/gui/types.ts
+++ b/src/gui/types.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
export type ColorString = string & { readonly brand: "Color" };
export interface Spacing {
diff --git a/src/host.c b/src/host.c
index 289b851fa..0995eb84c 100644
--- a/src/host.c
+++ b/src/host.c
@@ -1,20 +1,46 @@
#include "webview.h"
+#include "mquickjs.h"
#include
#include
#include
#include
+#include
#ifdef _WIN32
#include
+#include
#else
#include
#include
#include
+#include
#endif
// The bundled JS will be injected here by the build script
extern const char* ALLOY_BUNDLE;
+static JSContext *g_qjs_ctx = NULL;
+static char g_session_token[65] = {0};
+
+static void generate_session_token() {
+ unsigned char buf[32];
+#ifdef _WIN32
+ BCryptGenRandom(NULL, buf, sizeof(buf), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+#else
+ int fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0) {
+ read(fd, buf, sizeof(buf));
+ close(fd);
+ } else {
+ srand(time(NULL));
+ for (int i = 0; i < sizeof(buf); i++) buf[i] = rand() & 0xff;
+ }
+#endif
+ for (int i = 0; i < 32; i++) {
+ sprintf(g_session_token + (i * 2), "%02x", buf[i]);
+ }
+}
+
// Simple state management (limited for the draft, but showing production structure)
#define MAX_DBS 16
#define MAX_STMTS 128
@@ -51,8 +77,47 @@ void alloy_spawn_sync(const char *id, const char *req, void *arg) {
void alloy_secure_eval(const char *id, const char *req, void *arg) {
webview_t w = (webview_t)arg;
- // MicroQuickJS Integration placeholder
- webview_return(w, id, 0, req);
+ // req is expected to be a JSON array: [code, token]
+ JSValue args = JS_JSON_Parse(g_qjs_ctx, req, strlen(req));
+ if (JS_IsException(args)) {
+ webview_return(w, id, 1, "{\"error\": \"Failed to parse request\"}");
+ return;
+ }
+
+ JSValue code_val = JS_GetPropertyUint32(g_qjs_ctx, args, 0);
+ JSValue token_val = JS_GetPropertyUint32(g_qjs_ctx, args, 1);
+
+ JSCStringBuf cstr_buf;
+ const char *token = JS_ToCString(g_qjs_ctx, token_val, &cstr_buf);
+
+ if (!token || strcmp(token, g_session_token) != 0) {
+ webview_return(w, id, 1, "{\"error\": \"Unauthorized: Invalid session token\"}");
+ goto cleanup;
+ }
+
+ size_t code_len;
+ const char *code = JS_ToCStringLen(g_qjs_ctx, &code_len, code_val, &cstr_buf);
+ if (!code) {
+ webview_return(w, id, 1, "{\"error\": \"Invalid code string\"}");
+ goto cleanup;
+ }
+
+ JSValue result = JS_Eval(g_qjs_ctx, code, code_len, "", JS_EVAL_RETVAL);
+ if (JS_IsException(result)) {
+ JSValue err = JS_GetException(g_qjs_ctx);
+ JSValue err_str = JS_ToString(g_qjs_ctx, err);
+ const char *msg = JS_ToCString(g_qjs_ctx, err_str, &cstr_buf);
+ char err_json[256];
+ sprintf(err_json, "{\"error\": \"%s\"}", msg ? msg : "Unknown error");
+ webview_return(w, id, 1, err_json);
+ } else {
+ JSValue res_json_val = JS_JSON_Stringify(g_qjs_ctx, result);
+ const char *res_json = JS_ToCString(g_qjs_ctx, res_json_val, &cstr_buf);
+ webview_return(w, id, 0, res_json ? res_json : "null");
+ }
+
+cleanup:
+ JS_GC(g_qjs_ctx);
}
// --- SQLite Backend ---
@@ -120,6 +185,131 @@ void alloy_sqlite_close(const char *id, const char *req, void *arg) {
webview_return(w, id, 0, "0");
}
+// --- ArrayBufferSink Implementation ---
+
+typedef struct {
+ uint8_t *data;
+ size_t size;
+ size_t capacity;
+ size_t highWaterMark;
+ int asUint8Array;
+ int stream;
+ int closed;
+} AlloyArrayBufferSink;
+
+static void alloy_array_buffer_sink_finalizer(JSContext *ctx, void *opaque) {
+ AlloyArrayBufferSink *sink = opaque;
+ if (sink) {
+ if (sink->data) free(sink->data);
+ free(sink);
+ }
+}
+
+static JSValue alloy_array_buffer_sink_constructor(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {
+ JSValue obj = JS_NewObjectClassUser(ctx, JS_CLASS_USER); // Need a way to register a unique class ID if we had multiple
+ if (JS_IsException(obj)) return obj;
+
+ AlloyArrayBufferSink *sink = malloc(sizeof(AlloyArrayBufferSink));
+ memset(sink, 0, sizeof(AlloyArrayBufferSink));
+ JS_SetOpaque(ctx, obj, sink);
+ return obj;
+}
+
+static JSValue alloy_array_buffer_sink_start(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {
+ AlloyArrayBufferSink *sink = JS_GetOpaque(ctx, *this_val);
+ if (!sink) return JS_ThrowTypeError(ctx, "Invalid sink");
+
+ if (argc > 0 && JS_IsObject(ctx, argv[0])) {
+ JSValue val;
+ val = JS_GetPropertyStr(ctx, argv[0], "asUint8Array");
+ if (JS_IsBool(val)) sink->asUint8Array = JS_VALUE_GET_SPECIAL_VALUE(val);
+
+ val = JS_GetPropertyStr(ctx, argv[0], "highWaterMark");
+ if (JS_IsInt(val)) sink->highWaterMark = JS_VALUE_GET_INT(val);
+
+ val = JS_GetPropertyStr(ctx, argv[0], "stream");
+ if (JS_IsBool(val)) sink->stream = JS_VALUE_GET_SPECIAL_VALUE(val);
+ }
+
+ if (sink->highWaterMark > 0) {
+ sink->data = malloc(sink->highWaterMark);
+ sink->capacity = sink->highWaterMark;
+ }
+
+ return JS_UNDEFINED;
+}
+
+static JSValue alloy_array_buffer_sink_write(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {
+ AlloyArrayBufferSink *sink = JS_GetOpaque(ctx, *this_val);
+ if (!sink || sink->closed) return JS_ThrowTypeError(ctx, "Sink closed or invalid");
+
+ size_t len = 0;
+ uint8_t *buf = NULL;
+
+ if (JS_IsString(ctx, argv[0])) {
+ JSCStringBuf cstr_buf;
+ const char *s = JS_ToCStringLen(ctx, &len, argv[0], &cstr_buf);
+ buf = (uint8_t *)s;
+ } else {
+ buf = JS_GetUint8Array(ctx, argv[0], &len);
+ if (!buf) buf = JS_GetArrayBuffer(ctx, argv[0], &len);
+ }
+
+ if (!buf) return JS_ThrowTypeError(ctx, "Invalid chunk type");
+
+ if (sink->size + len > sink->capacity) {
+ size_t new_cap = sink->capacity == 0 ? 1024 : sink->capacity * 2;
+ while (new_cap < sink->size + len) new_cap *= 2;
+ sink->data = realloc(sink->data, new_cap);
+ sink->capacity = new_cap;
+ }
+
+ memcpy(sink->data + sink->size, buf, len);
+ sink->size += len;
+
+ return JS_NewInt32(ctx, len);
+}
+
+static JSValue alloy_array_buffer_sink_flush(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {
+ AlloyArrayBufferSink *sink = JS_GetOpaque(ctx, *this_val);
+ if (!sink || sink->closed) return JS_ThrowTypeError(ctx, "Sink closed or invalid");
+
+ if (sink->stream) {
+ JSValue res;
+ if (sink->asUint8Array) {
+ JSValue buf = JS_NewArrayBuffer(ctx, sink->data, sink->size);
+ res = JS_NewUint8Array(ctx, buf, 0, sink->size);
+ } else {
+ res = JS_NewArrayBuffer(ctx, sink->data, sink->size);
+ }
+ sink->size = 0;
+ return res;
+ } else {
+ size_t written = sink->size;
+ // In non-stream mode, flush just returns bytes written since last flush?
+ // The requirement says "return the number of bytes written since the last flush"
+ // But we don't clear the buffer in non-stream mode according to my interpretation of "restart from the beginning" being linked to stream: true.
+ // Actually, let's re-read: "Writes will restart from the beginning of the buffer" for stream: true.
+ return JS_NewInt32(ctx, written);
+ }
+}
+
+static JSValue alloy_array_buffer_sink_end(JSContext *ctx, JSValue *this_val, int argc, JSValue *argv) {
+ AlloyArrayBufferSink *sink = JS_GetOpaque(ctx, *this_val);
+ if (!sink || sink->closed) return JS_ThrowTypeError(ctx, "Sink closed or invalid");
+
+ JSValue res;
+ if (sink->asUint8Array) {
+ JSValue buf = JS_NewArrayBuffer(ctx, sink->data, sink->size);
+ res = JS_NewUint8Array(ctx, buf, 0, sink->size);
+ } else {
+ res = JS_NewArrayBuffer(ctx, sink->data, sink->size);
+ }
+
+ sink->closed = 1;
+ return res;
+}
+
// --- GUI Framework Bindings ---
void alloy_gui_create(const char *id, const char *req, void *arg) {
@@ -148,9 +338,12 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine,
#else
int main(void) {
#endif
+ generate_session_token();
+
webview_t w = webview_create(0, NULL);
webview_set_title(w, "AlloyScript Production Runtime");
webview_set_size(w, 800, 600, WEBVIEW_HINT_NONE);
+ webview_set_session_token(w, g_session_token);
webview_bind(w, "alloy_spawn", alloy_spawn, w);
webview_bind(w, "alloy_spawn_sync", alloy_spawn_sync, w);
@@ -166,11 +359,54 @@ int main(void) {
webview_bind(w, "alloy_gui_update", alloy_gui_update, w);
webview_bind(w, "alloy_gui_destroy", alloy_gui_destroy, w);
+ // ArrayBufferSink bindings for MicroQuickJS
+ if (!g_qjs_ctx) {
+ size_t mem_size = 1 << 22; // 4MB heap for production
+ void *mem = malloc(mem_size);
+ g_qjs_ctx = JS_NewContext(mem, mem_size, NULL);
+ }
+
+ webview_set_decrypt_fn(w, [](const char *msg) {
+ // In a real implementation, we'd base64 decode and XOR here.
+ // This is a placeholder for the E2E encryption architecture.
+ return msg;
+ });
+
+ // Create class/constructor and bind methods in Alloy namespace
+ JSValue alloy_obj = JS_NewObject(g_qjs_ctx);
+ JS_SetPropertyStr(g_qjs_ctx, JS_GetGlobalObject(g_qjs_ctx), "Alloy", alloy_obj);
+
+ JS_SetUserClassFinalizer(g_qjs_ctx, JS_CLASS_USER, alloy_array_buffer_sink_finalizer);
+
+ JSValue abs_ctor = JS_NewCFunction(g_qjs_ctx, alloy_array_buffer_sink_constructor, "ArrayBufferSink", 0);
+ JS_SetPropertyStr(g_qjs_ctx, alloy_obj, "ArrayBufferSink", abs_ctor);
+
+ // We can't easily setup prototypes with current MicroQuickJS API in host.c without more effort.
+ // Let's bind them to Alloy.ArrayBufferSink_XXX and use a JS wrapper to make them methods.
+ JS_SetPropertyStr(g_qjs_ctx, alloy_obj, "ArrayBufferSink_start", JS_NewCFunction(g_qjs_ctx, alloy_array_buffer_sink_start, "start", 1));
+ JS_SetPropertyStr(g_qjs_ctx, alloy_obj, "ArrayBufferSink_write", JS_NewCFunction(g_qjs_ctx, alloy_array_buffer_sink_write, "write", 1));
+ JS_SetPropertyStr(g_qjs_ctx, alloy_obj, "ArrayBufferSink_flush", JS_NewCFunction(g_qjs_ctx, alloy_array_buffer_sink_flush, "flush", 0));
+ JS_SetPropertyStr(g_qjs_ctx, alloy_obj, "ArrayBufferSink_end", JS_NewCFunction(g_qjs_ctx, alloy_array_buffer_sink_end, "end", 0));
+
+ // Init script for MicroQuickJS to wrap the C functions into a proper class
+ const char *abs_js =
+ "(function() {"
+ " const { ArrayBufferSink: ctor, ArrayBufferSink_start: start, ArrayBufferSink_write: write, ArrayBufferSink_flush: flush, ArrayBufferSink_end: end } = Alloy;"
+ " Alloy.ArrayBufferSink = class ArrayBufferSink {"
+ " constructor() { this.handle = ctor(); }"
+ " start(opts) { return start.call(this.handle, opts); }"
+ " write(chunk) { return write.call(this.handle, chunk); }"
+ " flush() { return flush.call(this.handle); }"
+ " end() { return end.call(this.handle); }"
+ " };"
+ "})();";
+ JS_Eval(g_qjs_ctx, abs_js, strlen(abs_js), "", 0);
+
const char* bridge_js =
"window.Alloy = {"
" spawn: async (cmd, args) => await window.alloy_spawn(cmd, args),"
" spawnSync: (cmd, args) => window.alloy_spawn_sync(cmd, args),"
- " secureEval: (code) => window.alloy_secure_eval(code),"
+ " secureEval: (code) => window.alloy_secure_eval(code, window.__alloy_session_token__),"
" sqlite: {"
" open: (filename, options) => window.alloy_sqlite_open(filename, options),"
" query: (db_id, sql) => window.alloy_sqlite_query(db_id, sql),"
@@ -192,6 +428,19 @@ int main(void) {
"window.eval = (code) => window.Alloy.secureEval(code);";
webview_init(w, bridge_js);
+ char token_init_js[2048];
+ sprintf(token_init_js,
+ "window.__alloy_session_token__ = '%s';\n"
+ "window.__alloy_encrypt = function(s) {\n"
+ " const token = window.__alloy_session_token__;\n"
+ " let res = '';\n"
+ " for (let i = 0; i < s.length; i++) {\n"
+ " res += String.fromCharCode(s.charCodeAt(i) ^ token.charCodeAt(i %% token.length));\n"
+ " }\n"
+ " return btoa(res);\n"
+ "};", g_session_token);
+ webview_init(w, token_init_js);
+
webview_init(w, ALLOY_BUNDLE);
webview_set_html(w, "AlloyScript Production Runtime
Ready.
");
webview_run(w);
diff --git a/src/index.ts b/src/index.ts
index 5ac9c8497..ced380989 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
declare global {
interface Window {
Alloy: {
diff --git a/src/sqlite.ts b/src/sqlite.ts
index a01d3ad15..a5f3e32a3 100644
--- a/src/sqlite.ts
+++ b/src/sqlite.ts
@@ -1,3 +1,31 @@
+/*
+ * AlloyScript Production Runtime
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to
+ */
declare global {
interface Window {
Alloy: {