local deflate = (function () local a;do local b="1.0.2-release"local c="LibDeflate"local d=3;local e="LibDeflate "..b.." Copyright (C) 2018-2021 Haoqian He.".." Licensed under the zlib License"if LibStub then local f,g=LibStub:GetLibrary(c,true)if f and g and g>=d then return f else a=LibStub:NewLibrary(c,d)end else a={}end;a._VERSION=b;a._MAJOR=c;a._MINOR=d;a._COPYRIGHT=e end;local assert=assert;local error=error;local pairs=pairs;local h=string.byte;local i=string.char;local j=string.find;local k=string.gsub;local l=string.sub;local m=table.concat;local n=table.sort;local tostring=tostring;local type=type;local o={}local p={}local q={}local r={}local s={}local t={}local u={}local v={}local w={}local x={3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}local y={0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}local z={[0]=1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}local A={[0]=0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}local B={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}local C;local D;local E;local F;local G;local H;local I;local J;for K=0,255 do p[K]=i(K)end;do local L=1;for K=0,32 do o[K]=L;L=L*2 end end;for K=1,9 do q[K]={}for M=0,o[K+1]-1 do local N=0;local O=M;for P=1,K do N=N-N%2+((N%2==1 or O%2==1)and 1 or 0)O=(O-O%2)/2;N=N*2 end;q[K][M]=(N-N%2)/2 end end;do local Q=18;local R=16;local S=265;local T=1;for U=3,258 do if U<=10 then r[U]=U+254;t[U]=0 elseif U==258 then r[U]=285;t[U]=0 else if U>Q then Q=Q+R;R=R*2;S=S+4;T=T+1 end;local V=U-Q-1+R/2;r[U]=(V-V%(R/8))/(R/8)+S;t[U]=T;s[U]=V%(R/8)end end end;do u[1]=0;u[2]=1;w[1]=0;w[2]=0;local Q=3;local R=4;local W=2;local T=0;for X=3,256 do if X>R then Q=Q*2;R=R*2;W=W+2;T=T+1 end;u[X]=X<=Q and W or W+1;w[X]=T<0 and 0 or T;if R>=8 then v[X]=(X-R/2-1)%(R/4)end end end;function a:Adler32(Y)if type(Y)~="string"then error(("Usage: LibDeflate:Adler32(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;local Z=#Y;local K=1;local Q=1;local R=0;while K<=Z-15 do local _,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae=h(Y,K,K+15)R=(R+16*Q+16*_+15*a0+14*a1+13*a2+12*a3+11*a4+10*a5+9*a6+8*a7+7*a8+6*a9+5*aa+4*ab+3*ac+2*ad+ae)%65521;Q=(Q+_+a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+aa+ab+ac+ad+ae)%65521;K=K+16 end;while K<=Z do local af=h(Y,K,K)Q=(Q+af)%65521;R=(R+Q)%65521;K=K+1 end;return(R*65536+Q)%4294967296 end;local function ag(ah,ai)return ah%4294967296==ai%4294967296 end;function a:CreateDictionary(Y,Z,aj)if type(Y)~="string"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;if type(Z)~="number"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'strlen\' - number expected got \'%s\'."):format(type(Z)),2)end;if type(aj)~="number"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'adler32\' - number expected got \'%s\'."):format(type(aj)),2)end;if Z~=#Y then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'strlen\' does not match the actual length of \'str\'.".." \'strlen\': %u, \'#str\': %u .".." Please check if \'str\' is modified unintentionally."):format(Z,#Y))end;if Z==0 then error("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'str\' - Empty string is not allowed.",2)end;if Z>32768 then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'str\' - string longer than 32768 bytes is not allowed.".." Got %d bytes."):format(Z),2)end;local ak=self:Adler32(Y)if not ag(aj,ak)then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'adler32\' does not match the actual adler32 of \'str\'.".." \'adler32\': %u, \'Adler32(str)\': %u .".." Please check if \'str\' is modified unintentionally."):format(aj,ak))end;local al={}al.adler32=aj;al.hash_tables={}al.string_table={}al.strlen=Z;local am=al.string_table;local an=al.hash_tables;am[1]=h(Y,1,1)am[2]=h(Y,2,2)if Z>=3 then local K=1;local ao=am[1]*256+am[2]while K<=Z-2-3 do local _,a0,a1,a2=h(Y,K+2,K+5)am[K+2]=_;am[K+3]=a0;am[K+4]=a1;am[K+5]=a2;ao=(ao*256+_)%16777216;local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1;ao=(ao*256+a0)%16777216;V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1;ao=(ao*256+a1)%16777216;V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1;ao=(ao*256+a2)%16777216;V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1 end;while K<=Z-2 do local af=h(Y,K+2)am[K+2]=af;ao=(ao*256+af)%16777216;local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1 end end;return al end;local function ap(al)if type(al)~="table"then return false,("\'dictionary\' - table expected got \'%s\'."):format(type(al))end;if type(al.adler32)~="number"or type(al.string_table)~="table"or type(al.strlen)~="number"or al.strlen<=0 or al.strlen>32768 or al.strlen~=#al.string_table or type(al.hash_tables)~="table"then return false,("\'dictionary\' - corrupted dictionary."):format(type(al))end;return true,""end;local aq={[0]={false,nil,0,0,0},[1]={false,nil,4,8,4},[2]={false,nil,5,18,8},[3]={false,nil,6,32,32},[4]={true,4,4,16,16},[5]={true,8,16,32,32},[6]={true,8,16,128,128},[7]={true,8,32,128,256},[8]={true,32,128,258,1024},[9]={true,32,258,258,4096}}local function ar(Y,as,al,at,au)if type(Y)~="string"then return false,("\'str\' - string expected got \'%s\'."):format(type(Y))end;if as then local av,aw=ap(al)if not av then return false,aw end end;if at then local ax=type(au)if ax~="nil"and ax~="table"then return false,("\'configs\' - nil or table expected got \'%s\'."):format(type(au))end;if ax=="table"then for ay,az in pairs(au)do if ay~="level"and ay~="strategy"then return false,("\'configs\' - unsupported table key in the configs: \'%s\'."):format(ay)elseif ay=="level"and not aq[az]then return false,("\'configs\' - unsupported \'level\': %s."):format(tostring(az))elseif ay=="strategy"and az~="fixed"and az~="huffman_only"and az~="dynamic"then return false,("\'configs\' - unsupported \'strategy\': \'%s\'."):format(tostring(az))end end end end;return true,""end;local aA=0;local aB=1;local aC=2;local aD=3;local function aE()local aF=0;local aG=0;local aH=0;local aI=0;local aJ={}local aK={}local function aL(O,T)aG=aG+O*o[aH]aH=aH+T;aI=aI+T;if aH>=32 then aF=aF+1;aJ[aF]=p[aG%256]..p[(aG-aG%256)/256%256]..p[(aG-aG%65536)/65536%256]..p[(aG-aG%16777216)/16777216%256]local aM=o[32-aH+T]aG=(O-O%aM)/aM;aH=aH-32 end end;local function aN(Y)for P=1,aH,8 do aF=aF+1;aJ[aF]=i(aG%256)aG=(aG-aG%256)/256 end;aH=0;aF=aF+1;aJ[aF]=Y;aI=aI+#Y*8 end;local function aO(aP)if aP==aD then return aI end;if aP==aB or aP==aC then local aQ=(8-aH%8)%8;if aH>0 then aG=aG-o[aH]+o[aH+aQ]for P=1,aH,8 do aF=aF+1;aJ[aF]=p[aG%256]aG=(aG-aG%256)/256 end;aG=0;aH=0 end;if aP==aC then aI=aI+aQ;return aI end end;local aR=m(aJ)aJ={}aF=0;aK[#aK+1]=aR;if aP==aA then return aI else return aI,m(aK)end end;return aL,aN,aO end;local function aS(aT,aU,aV)aV=aV+1;aT[aV]=aU;local O=aU[1]local aW=aV;local aX=(aW-aW%2)/2;while aX>=1 and aT[aX][1]>O do local V=aT[aX]aT[aX]=aU;aT[aW]=V;aW=aX;aX=(aX-aX%2)/2 end end;local function aY(aT,aV)local aZ=aT[1]local aU=aT[aV]local O=aU[1]aT[1]=aU;aT[aV]=aZ;aV=aV-1;local aW=1;local a_=aW*2;local b0=a_+1;while a_<=aV do local b1=aT[a_]if b0<=aV and aT[b0][1]1 do local bk=aY(aT,aV)aV=aV-1;local bl=aY(aT,aV)aV=aV-1;local bm={bk[1]+bl[1],-1,bk,bl}aS(aT,bm,aV)aV=aV+1 end;local bn=0;local bo={aT[1],0,0,0}local bp=1;local bq=1;aT[1][1]=0;while bq<=bp do local aU=bo[bq]local T=aU[1]local bb=aU[2]local b1=aU[3]local b2=aU[4]if b1 then bp=bp+1;bo[bp]=b1;b1[1]=T+1 end;if b2 then bp=bp+1;bo[bp]=b2;b2[1]=T+1 end;bq=bq+1;if T>b7 then bn=bn+1;T=b7 end;if bb>=0 then b5[bb]=T;bf=bb>bf and bb or bf;b4[T]=(b4[T]or 0)+1 end end;if bn>0 then repeat local T=b7-1;while(b4[T]or 0)==0 do T=T-1 end;b4[T]=b4[T]-1;b4[T+1]=(b4[T+1]or 0)+2;b4[b7]=b4[b7]-1;bn=bn-2 until bn<=0;bq=1;for T=b7,1,-1 do local br=b4[T]or 0;while br>0 do local bb=bg[bq][2]b5[bb]=T;br=br-1;bq=bq+1 end end end;bh=b3(b4,b5,b6,b7)return b5,bh,bf end end;local function bs(bt,bu,bv,bw)local bx=0;local by={}local bz={}local bA=0;local bB={}local bC=nil;local bj=0;bw=bw<0 and 0 or bw;local bD=bu+bw+1;for W=0,bD+1 do local U=W<=bu and(bt[W]or 0)or(W<=bD and(bv[W-bu-1]or 0)or nil)if U==bC then bj=bj+1;if U~=0 and bj==6 then bx=bx+1;by[bx]=16;bA=bA+1;bB[bA]=3;bz[16]=(bz[16]or 0)+1;bj=0 elseif U==0 and bj==138 then bx=bx+1;by[bx]=18;bA=bA+1;bB[bA]=127;bz[18]=(bz[18]or 0)+1;bj=0 end else if bj==1 then bx=bx+1;by[bx]=bC;bz[bC]=(bz[bC]or 0)+1 elseif bj==2 then bx=bx+1;by[bx]=bC;bx=bx+1;by[bx]=bC;bz[bC]=(bz[bC]or 0)+2 elseif bj>=3 then bx=bx+1;local bE=bC~=0 and 16 or(bj<=10 and 17 or 18)by[bx]=bE;bz[bE]=(bz[bE]or 0)+1;bA=bA+1;bB[bA]=bj<=10 and bj-3 or bj-11 end;bC=U;if U and U~=0 then bx=bx+1;by[bx]=U;bz[U]=(bz[U]or 0)+1;bj=0 else bj=1 end end end;return by,bB,bz end;local function bF(Y,V,bG,bH,bI)local K=bG-bI;while K<=bH-15-bI do V[K],V[K+1],V[K+2],V[K+3],V[K+4],V[K+5],V[K+6],V[K+7],V[K+8],V[K+9],V[K+10],V[K+11],V[K+12],V[K+13],V[K+14],V[K+15]=h(Y,K+bI,K+15+bI)K=K+16 end;while K<=bH-bI do V[K]=h(Y,K+bI,K+bI)K=K+1 end;return V end;local function bJ(bK,am,an,bL,bM,bI,al)local bN=aq[bK]local bO,bP,bQ,bR,bS=bN[1],bN[2],bN[3],bN[4],bN[5]local bT=not bO and bQ or 2147483646;local bU=bS-bS%4/4;local ao;local bV;local bW;local bX=0;if al then bV=al.hash_tables;bW=al.string_table;bX=al.strlen;assert(bL==1)if bM>=bL and bX>=2 then ao=bW[bX-1]*65536+bW[bX]*256+am[1]local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=-1 end;if bM>=bL+1 and bX>=1 then ao=bW[bX]*65536+am[1]*256+am[2]local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=0 end end;local bY=bX+3;ao=(am[bL-bI]or 0)*256+(am[bL+1-bI]or 0)local bZ={}local b_=0;local c0={}local c1={}local c2=0;local c3={}local c4={}local c5=0;local c6={}local c7=0;local c8=false;local c9;local ca;local cb=0;local cc=0;local bq=bL;local cd=bM+(bO and 1 or 0)while bq<=cd do local ce=bq-bI;local cf=bI-3;c9=cb;ca=cc;cb=0;ao=(ao*256+(am[ce+2]or 0))%16777216;local cg;local ch;local ci=an[ao]local cj;if not ci then cj=0;ci={}an[ao]=ci;if bV then ch=bV[ao]cg=ch and#ch or 0 else cg=0 end else cj=#ci;ch=ci;cg=cj end;if bq<=bM then ci[cj+1]=bq end;if cg>0 and bq+2<=bM and(not bO or c9=bP and bU or bS;local cl=bM-bq;cl=cl>=257 and 257 or cl;cl=cl+ce;local cm=ce+3;while cg>=1 and ck>0 do local bC=ch[cg]if bq-bC>32768 then break end;if bC=-257 then local co=bC-cf;while cn<=cl and am[co]==am[cn]do cn=cn+1;co=co+1 end else local co=bY+bC;while cn<=cl and bW[co]==am[cn]do cn=cn+1;co=co+1 end end;local M=cn-ce;if M>cb then cb=M;cc=bq-bC end;if cb>=bR then break end end;cg=cg-1;ck=ck-1;if cg==0 and bC>0 and bV then ch=bV[ao]cg=ch and#ch or 0 end end end;if not bO then c9,ca=cb,cc end;if(not bO or c8)and(c9>3 or c9==3 and ca<4096)and cb<=c9 then local W=r[c9]local cp=t[c9]local cq,cr,cs;if ca<=256 then cq=u[ca]cs=v[ca]cr=w[ca]else cq=16;cr=7;local Q=384;local R=512;while true do if ca<=Q then cs=(ca-R/2-1)%(R/4)break elseif ca<=R then cs=(ca-R/2-1)%(R/4)cq=cq+1;break else cq=cq+2;cr=cr+1;Q=Q*2;R=R*2 end end end;b_=b_+1;bZ[b_]=W;c0[W]=(c0[W]or 0)+1;c2=c2+1;c1[c2]=cq;c3[cq]=(c3[cq]or 0)+1;if cp>0 then local ct=s[c9]c5=c5+1;c4[c5]=ct end;if cr>0 then c7=c7+1;c6[c7]=cs end;for K=bq+1,bq+c9-(bO and 2 or 1)do ao=(ao*256+(am[K-bI+2]or 0))%16777216;if c9<=bT then ci=an[ao]if not ci then ci={}an[ao]=ci end;ci[#ci+1]=K end end;bq=bq+c9-(bO and 1 or 0)c8=false elseif not bO or c8 then local W=am[bO and ce-1 or ce]b_=b_+1;bZ[b_]=W;c0[W]=(c0[W]or 0)+1;bq=bq+1 else c8=true;bq=bq+1 end end;b_=b_+1;bZ[b_]=256;c0[256]=(c0[256]or 0)+1;return bZ,c4,c0,c1,c6,c3 end;local function cu(c0,c3)local cv,cw,bu=bd(c0,15,285)local cx,cy,bw=bd(c3,15,29)local cz,bB,cA=bs(cv,bu,cx,bw)local cB,cC=bd(cA,7,18)local cD=0;for K=1,19 do local bb=B[K]local cE=cB[bb]or 0;if cE~=0 then cD=K end end;cD=cD-4;local cF=bu+1-257;local cG=bw+1-1;if cG<0 then cG=0 end;return cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy end;local function cH(bZ,c1,cD,cB,cz,cv,cx)local cI=17;cI=cI+(cD+4)*3;for K=1,#cz do local W=cz[K]cI=cI+cB[W]if W>=16 then cI=cI+(W==16 and 2 or(W==17 and 3 or 7))end end;local cJ=0;for K=1,#bZ do local W=bZ[K]local cK=cv[W]cI=cI+cK;if W>256 then cJ=cJ+1;if W>264 and W<285 then local cL=y[W-256]cI=cI+cL end;local cq=c1[cJ]local cM=cx[cq]cI=cI+cM;if cq>3 then local cr=(cq-cq%2)/2-1;cI=cI+cr end end end;return cI end;local function cN(aL,cO,bZ,c4,c1,c6,cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy)aL(cO and 1 or 0,1)aL(2,2)aL(cF,5)aL(cG,5)aL(cD,4)for K=1,cD+4 do local bb=B[K]local cE=cB[bb]or 0;aL(cE,3)end;local cP=1;for K=1,#cz do local W=cz[K]aL(cC[W],cB[W])if W>=16 then local cQ=bB[cP]aL(cQ,W==16 and 2 or(W==17 and 3 or 7))cP=cP+1 end end;local cJ=0;local cR=0;local cS=0;for K=1,#bZ do local cT=bZ[K]local b8=cw[cT]local cK=cv[cT]aL(b8,cK)if cT>256 then cJ=cJ+1;if cT>264 and cT<285 then cR=cR+1;local cU=c4[cR]local cL=y[cT-256]aL(cU,cL)end;local cV=c1[cJ]local cW=cy[cV]local cM=cx[cV]aL(cW,cM)if cV>3 then cS=cS+1;local cs=c6[cS]local cr=(cV-cV%2)/2-1;aL(cs,cr)end end end end;local function cX(bZ,c1)local cI=3;local cJ=0;for K=1,#bZ do local W=bZ[K]local cK=E[W]cI=cI+cK;if W>256 then cJ=cJ+1;if W>264 and W<285 then local cL=y[W-256]cI=cI+cL end;local cq=c1[cJ]cI=cI+5;if cq>3 then local cr=(cq-cq%2)/2-1;cI=cI+cr end end end;return cI end;local function cY(aL,cO,bZ,c4,c1,c6)aL(cO and 1 or 0,1)aL(1,2)local cJ=0;local cR=0;local cS=0;for K=1,#bZ do local cZ=bZ[K]local b8=C[cZ]local cK=E[cZ]aL(b8,cK)if cZ>256 then cJ=cJ+1;if cZ>264 and cZ<285 then cR=cR+1;local cU=c4[cR]local cL=y[cZ-256]aL(cU,cL)end;local cq=c1[cJ]local cW=G[cq]aL(cW,5)if cq>3 then cS=cS+1;local cs=c6[cS]local cr=(cq-cq%2)/2-1;aL(cs,cr)end end end end;local function c_(bL,bM,aI)assert(bM-bL+1<=65535)local cI=3;aI=aI+3;local aQ=(8-aI%8)%8;cI=cI+aQ;cI=cI+32;cI=cI+(bM-bL+1)*8;return cI end;local function d0(aL,aN,cO,Y,bL,bM,aI)assert(bM-bL+1<=65535)aL(cO and 1 or 0,1)aL(0,2)aI=aI+3;local aQ=(8-aI%8)%8;if aQ>0 then aL(o[aQ]-1,aQ)end;local d1=bM-bL+1;aL(d1,16)local d2=255-d1%256+(255-(d1-d1%256)/256)*256;aL(d2,16)aN(Y:sub(bL,bM))end;local function d3(au,aL,aN,aO,Y,al)local am={}local an={}local cO=nil;local bL;local bM;local d4;local aI=aO(aD)local Z=#Y;local bI;local bK;local d5;if au then if au.level then bK=au.level end;if au.strategy then d5=au.strategy end end;if not bK then if Z<2048 then bK=7 elseif Z>65536 then bK=3 else bK=5 end end;while not cO do if not bL then bL=1;bM=64*1024-1;bI=0 else bL=bM+1;bM=bM+32*1024;bI=bL-32*1024-1 end;if bM>=Z then bM=Z;cO=true else cO=false end;local bZ,c4,c0,c1,c6,c3;local cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy;local d6;local d7;local d8;if bK~=0 then bF(Y,am,bL,bM+3,bI)if bL==1 and al then local bW=al.string_table;local d9=al.strlen;for K=0,-d9+1<-257 and-257 or-d9+1,-1 do am[K]=bW[d9+K]end end;if d5=="huffman_only"then bZ={}bF(Y,bZ,bL,bM,bL-1)c4={}c0={}bZ[bM-bL+2]=256;for K=1,bM-bL+2 do local W=bZ[K]c0[W]=(c0[W]or 0)+1 end;c1={}c6={}c3={}else bZ,c4,c0,c1,c6,c3=bJ(bK,am,an,bL,bM,bI,al)end;cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy=cu(c0,c3)d6=cH(bZ,c1,cD,cB,cz,cv,cx)d7=cX(bZ,c1)end;d8=c_(bL,bM,aI)local da=d8;da=d7 and d70 and bM+1-V[1]>32768 then if db==1 then an[ay]=nil else local dc={}local dd=0;for K=2,db do M=V[K]if bM+1-M<=32768 then dd=dd+1;dc[dd]=M end end;an[ay]=dc end end end end end end;local function de(Y,al,au)local aL,aN,aO=aE()d3(au,aL,aN,aO,Y,al)local aI,df=aO(aB)local aQ=(8-aI%8)%8;return df,aQ end;local function dg(Y,al,au)local aL,aN,aO=aE()local dh=8;local di=7;local dj=di*16+dh;aL(dj,8)local dk=al and 1 or 0;local dl=2;local dm=dl*64+dk*32;local dn=31-(dj*256+dm)%31;dm=dm+dn;aL(dm,8)if dk==1 then local aj=al.adler32;local dp=aj%256;aj=(aj-dp)/256;local dq=aj%256;aj=(aj-dq)/256;local dr=aj%256;aj=(aj-dr)/256;local ds=aj%256;aL(ds,8)aL(dr,8)aL(dq,8)aL(dp,8)end;d3(au,aL,aN,aO,Y,al)aO(aC)local aj=a:Adler32(Y)local ds=aj%256;aj=(aj-ds)/256;local dr=aj%256;aj=(aj-dr)/256;local dq=aj%256;aj=(aj-dq)/256;local dp=aj%256;aL(dp,8)aL(dq,8)aL(dr,8)aL(ds,8)local aI,df=aO(aB)local aQ=(8-aI%8)%8;return df,aQ end;function a:CompressDeflate(Y,au)local dt,du=ar(Y,false,nil,true,au)if not dt then error("Usage: LibDeflate:CompressDeflate(str, configs): "..du,2)end;return de(Y,nil,au)end;function a:CompressDeflateWithDict(Y,al,au)local dt,du=ar(Y,true,al,true,au)if not dt then error("Usage: LibDeflate:CompressDeflateWithDict".."(str, dictionary, configs): "..du,2)end;return de(Y,al,au)end;function a:CompressZlib(Y,au)local dt,du=ar(Y,false,nil,true,au)if not dt then error("Usage: LibDeflate:CompressZlib(str, configs): "..du,2)end;return dg(Y,nil,au)end;function a:CompressZlibWithDict(Y,al,au)local dt,du=ar(Y,true,al,true,au)if not dt then error("Usage: LibDeflate:CompressZlibWithDict".."(str, dictionary, configs): "..du,2)end;return dg(Y,al,au)end;local function dv(dw)local dx=dw;local dy=#dw;local dz=1;local aH=0;local aG=0;local function dA(T)local aM=o[T]local W;if T<=aH then W=aG%aM;aG=(aG-W)/aM;aH=aH-T else local dB=o[aH]local dq,dr,ds,dC=h(dx,dz,dz+3)aG=aG+((dq or 0)+(dr or 0)*256+(ds or 0)*65536+(dC or 0)*16777216)*dB;dz=dz+4;aH=aH+32-T;W=aG%aM;aG=(aG-W)/aM end;return W end;local function dD(dE,aJ,aF)assert(aH%8==0)local dF=aH/80 then if aH<15 and dx then local dB=o[aH]local dq,dr,ds,dC=h(dx,dz,dz+3)aG=aG+((dq or 0)+(dr or 0)*256+(ds or 0)*65536+(dC or 0)*16777216)*dB;dz=dz+4;aH=aH+32 end;local aM=o[da]aH=aH-da;W=aG%aM;aG=(aG-W)/aM;W=q[da][W]bj=dI[da]if W0 and T285 then return-10 elseif bb<256 then aF=aF+1;aJ[aF]=p[bb]elseif bb>256 then bb=bb-256;local T=x[bb]T=bb>=8 and T+dA(y[bb])or T;bb=dH(cx,dZ,d_)if bb<0 or bb>29 then return-10 end;local X=z[bb]X=X>4 and X+dA(A[bb])or X;local e1=aF-X+1;if e1=-257 then for P=1,T do aF=aF+1;aJ[aF]=aJ[e1]e1=e1+1 end else e1=d9+e1;for P=1,T do aF=aF+1;aJ[aF]=p[bW[e1]]e1=e1+1 end end end;if dN()<0 then return 2 end;if aF>=65536 then aK[#aK+1]=m(aJ,"",1,32768)for K=32769,aF do aJ[K-32768]=aJ[K]end;aF=aF-32768;aJ[aF+1]=nil end until bb==256;dR.buffer_size=aF;return 0 end;local function e2(dR)local aJ,aF,dA,dD,dN,dO,aK=dR.buffer,dR.buffer_size,dR.ReadBits,dR.ReadBytes,dR.ReaderBitlenLeft,dR.SkipToByteBoundary,dR.result_buffer;dO()local dE=dA(16)if dN()<0 then return 2 end;local e3=dA(16)if dN()<0 then return 2 end;if dE%256+e3%256~=255 then return-2 end;if(dE-dE%256)/256+(e3-e3%256)/256~=255 then return-2 end;aF=dD(dE,aJ,aF)if aF<0 then return 2 end;if aF>=65536 then aK[#aK+1]=m(aJ,"",1,32768)for K=32769,aF do aJ[K-32768]=aJ[K]end;aF=aF-32768;aJ[aF+1]=nil end;dR.buffer_size=aF;return 0 end;local function e4(dR)return dW(dR,F,D,7,J,H,5)end;local function e5(dR)local dA,dH=dR.ReadBits,dR.Decode;local e6=dA(5)+257;local e7=dA(5)+1;local e8=dA(4)+4;if e6>286 or e7>30 then return-3 end;local cB={}for K=1,e8 do cB[B[K]]=dA(3)end;local e9,ea,eb,ec=dS(cB,18,7)if e9~=0 then return-4 end;local cv={}local cx={}local bq=0;while bqe6+e7 then return-6 end;while bb>0 do bb=bb-1;if bq7 then return nil,-13 end;local dm=dA(8)if dR.ReaderBitlenLeft()<0 then return nil,2 end;if(dj*256+dm)%31~=0 then return nil,-14 end;local dk=(dm-dm%32)/32%2;local dl=(dm-dm%64)/64%4;if dk==1 then if not al then return nil,-16 end;local ds=dA(8)local dr=dA(8)local dq=dA(8)local dp=dA(8)local ak=ds*16777216+dr*65536+dq*256+dp;if dR.ReaderBitlenLeft()<0 then return nil,2 end;if not ag(ak,al.adler32)then return nil,-17 end end;local df,ej=eh(dR)if not df then return nil,ej end;dR.SkipToByteBoundary()local eo=dA(8)local ep=dA(8)local eq=dA(8)local er=dA(8)if dR.ReaderBitlenLeft()<0 then return nil,2 end;local es=eo*16777216+ep*65536+eq*256+er;local et=a:Adler32(df)if not ag(es,et)then return nil,-15 end;local el=dR.ReaderBitlenLeft()local em=(el-el%8)/8;return df,em end;function a:DecompressDeflate(Y)local dt,du=ar(Y)if not dt then error("Usage: LibDeflate:DecompressDeflate(str): "..du,2)end;return ek(Y)end;function a:DecompressDeflateWithDict(Y,al)local dt,du=ar(Y,true,al)if not dt then error("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): "..du,2)end;return ek(Y,al)end;function a:DecompressZlib(Y)local dt,du=ar(Y)if not dt then error("Usage: LibDeflate:DecompressZlib(str): "..du,2)end;return en(Y)end;function a:DecompressZlibWithDict(Y,al)local dt,du=ar(Y,true,al)if not dt then error("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): "..du,2)end;return en(Y,al)end;do E={}for eu=0,143 do E[eu]=8 end;for eu=144,255 do E[eu]=9 end;for eu=256,279 do E[eu]=7 end;for eu=280,287 do E[eu]=8 end;I={}for X=0,31 do I[X]=5 end;local ej;ej,F,D=dS(E,287,9)assert(ej==0)ej,J,H=dS(I,31,5)assert(ej==0)C=b3(F,E,287,9)G=b3(J,I,31,5)end;local ev={["\000"]="%z",["("]="%(",[")"]="%)",["."]="%.",["%"]="%%",["+"]="%+",["-"]="%-",["*"]="%*",["?"]="%?",["["]="%[",["]"]="%]",["^"]="%^",["$"]="%$"}local function ew(Y)return Y:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])",ev)end;function a:CreateCodec(ex,ey,ez)if type(ex)~="string"or type(ey)~="string"or type(ez)~="string"then error("Usage: LibDeflate:CreateCodec(reserved_chars,".." escape_chars, map_chars):".." All arguments must be string.",2)end;if ey==""then return nil,"No escape characters supplied."end;if#ex<#ez then return nil,"The number of reserved characters must be".." at least as many as the number of mapped chars."end;if ex==""then return nil,"No characters to encode."end;local eA=ex..ey..ez;local eB={}for K=1,#eA do local dG=h(eA,K,K)if eB[dG]then return nil,"There must be no duplicate characters in the".." concatenation of reserved_chars, escape_chars and".." map_chars."end;eB[dG]=true end;local eC={}local eD={}local eE={}local eF={}if#ez>0 then local eG={}local eH={}for K=1,#ez do local eI=l(ex,K,K)local eJ=l(ez,K,K)eF[eI]=eJ;eE[#eE+1]=eI;eH[eJ]=eI;eG[#eG+1]=eJ end;eC[#eC+1]="(["..ew(m(eG)).."])"eD[#eD+1]=eH end;local eK=1;local eL=l(ey,eK,eK)local eM=0;local eG={}local eH={}for K=1,#eA do local S=l(eA,K,K)if not eF[S]then while eM>=256 or eB[eM]do eM=eM+1;if eM>255 then eC[#eC+1]=ew(eL).."(["..ew(m(eG)).."])"eD[#eD+1]=eH;eK=eK+1;eL=l(ey,eK,eK)eM=0;eG={}eH={}if not eL or eL==""then return nil,"Out of escape characters."end end end;local eN=p[eM]eF[S]=eL..eN;eE[#eE+1]=S;eH[eN]=S;eG[#eG+1]=eN;eM=eM+1 end;if K==#eA then eC[#eC+1]=ew(eL).."(["..ew(m(eG)).."])"eD[#eD+1]=eH end end;local eO={}local eP="(["..ew(m(eE)).."])"local eQ=eF;function eO:Encode(Y)if type(Y)~="string"then error(("Usage: codec:Encode(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;return k(Y,eP,eQ)end;local eR=#eC;local eS="(["..ew(ex).."])"function eO:Decode(Y)if type(Y)~="string"then error(("Usage: codec:Decode(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;if j(Y,eS)then return nil end;for K=1,eR do Y=k(Y,eC[K],eD[K])end;return Y end;return eO end;local eT={[0]="a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9","(",")"}local eU={[97]=0,[98]=1,[99]=2,[100]=3,[101]=4,[102]=5,[103]=6,[104]=7,[105]=8,[106]=9,[107]=10,[108]=11,[109]=12,[110]=13,[111]=14,[112]=15,[113]=16,[114]=17,[115]=18,[116]=19,[117]=20,[118]=21,[119]=22,[120]=23,[121]=24,[122]=25,[65]=26,[66]=27,[67]=28,[68]=29,[69]=30,[70]=31,[71]=32,[72]=33,[73]=34,[74]=35,[75]=36,[76]=37,[77]=38,[78]=39,[79]=40,[80]=41,[81]=42,[82]=43,[83]=44,[84]=45,[85]=46,[86]=47,[87]=48,[88]=49,[89]=50,[90]=51,[48]=52,[49]=53,[50]=54,[51]=55,[52]=56,[53]=57,[54]=58,[55]=59,[56]=60,[57]=61,[40]=62,[41]=63}function a:EncodeForPrint(Y)if type(Y)~="string"then error(("Usage: LibDeflate:EncodeForPrint(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;local Z=#Y;local eV=Z-2;local K=1;local aJ={}local aF=0;while K<=eV do local _,a0,a1=h(Y,K,K+2)K=K+3;local aG=_+a0*256+a1*65536;local eW=aG%64;aG=(aG-eW)/64;local eX=aG%64;aG=(aG-eX)/64;local eY=aG%64;local eZ=(aG-eY)/64;aF=aF+1;aJ[aF]=eT[eW]..eT[eX]..eT[eY]..eT[eZ]end;local aG=0;local aH=0;while K<=Z do local af=h(Y,K,K)aG=aG+af*o[aH]aH=aH+8;K=K+1 end;while aH>0 do local e_=aG%64;aF=aF+1;aJ[aF]=eT[e_]aG=(aG-e_)/64;aH=aH-6 end;return m(aJ)end;function a:DecodeForPrint(Y)if type(Y)~="string"then error(("Usage: LibDeflate:DecodeForPrint(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;Y=Y:gsub("^[%c ]+","")Y=Y:gsub("[%c ]+$","")local Z=#Y;if Z==1 then return nil end;local f0=Z-3;local K=1;local aJ={}local aF=0;while K<=f0 do local _,a0,a1,a2=h(Y,K,K+3)_=eU[_]a0=eU[a0]a1=eU[a1]a2=eU[a2]if not(_ and a0 and a1 and a2)then return nil end;K=K+4;local aG=_+a0*64+a1*4096+a2*262144;local eW=aG%256;aG=(aG-eW)/256;local eX=aG%256;local eY=(aG-eX)/256;aF=aF+1;aJ[aF]=p[eW]..p[eX]..p[eY]end;local aG=0;local aH=0;while K<=Z do local af=h(Y,K,K)af=eU[af]if not af then return nil end;aG=aG+af*o[aH]aH=aH+6;K=K+1 end;while aH>=8 do local dG=aG%256;aF=aF+1;aJ[aF]=p[dG]aG=(aG-dG)/256;aH=aH-8 end;return m(aJ)end;local function f1()_chat_channel_codec=nil;_addon_channel_codec=nil end;a.internals={LoadStringToTable=bF,IsValidDictionary=ap,IsEqualAdler32=ag,_byte_to_6bit_char=eT,_6bit_to_byte=eU,InternalClearCache=f1}if io and os and debug and _G.arg then local io=io;local os=os;local debug=debug;local f2=_G.arg;local f3=debug.getinfo(1)if f3.source==f2[0]or f3.short_src==f2[0]then local dx;local f4;local K=1;local ej;local f5=false;local f6=false;local bK;local d5;local al;while f2[K]do local Q=f2[K]if Q=="-h"then print(a._COPYRIGHT.."\nUsage: lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT]\n".." -0 store only. no compression.\n".." -1 fastest compression.\n".." -9 slowest and best compression.\n".." -d do decompression instead of compression.\n".." --dict specify the file that contains".." the entire preset dictionary.\n".." -h give this help.\n".." --strategy ".." specify a special compression strategy.\n".." -v print the version and copyright info.\n".." --zlib use zlib format instead of raw deflate.\n")os.exit(0)elseif Q=="-v"then print(a._COPYRIGHT)os.exit(0)elseif Q:find("^%-[0-9]$")then bK=tonumber(Q:sub(2,2))elseif Q=="-d"then f6=true elseif Q=="--dict"then K=K+1;local f7=f2[K]if not f7 then io.stderr:write("You must speicify the dict filename")os.exit(1)end;local f8,f9=io.open(f7,"rb")if not f8 then io.stderr:write(("LibDeflate: Cannot read the dictionary file \'%s\': %s"):format(f7,f9))os.exit(1)end;local fa=f8:read("*all")f8:close()al=a:CreateDictionary(fa,#fa,a:Adler32(fa))elseif Q=="--strategy"then K=K+1;d5=f2[K]elseif Q=="--zlib"then f5=true elseif Q:find("^%-")then io.stderr:write(("LibDeflate: Invalid argument: %s"):format(Q))os.exit(1)else if not dx then dx,ej=io.open(Q,"rb")if not dx then io.stderr:write(("LibDeflate: Cannot read the file \'%s\': %s"):format(Q,tostring(ej)))os.exit(1)end elseif not f4 then f4,ej=io.open(Q,"wb")if not f4 then io.stderr:write(("LibDeflate: Cannot write the file \'%s\': %s"):format(Q,tostring(ej)))os.exit(1)end end end;K=K+1 end;if not dx or not f4 then io.stderr:write("LibDeflate:".." You must specify both input and output files.")os.exit(1)end;local fb=dx:read("*all")local au={level=bK,strategy=d5}local fc;if not f6 then if not f5 then if not al then fc=a:CompressDeflate(fb,au)else fc=a:CompressDeflateWithDict(fb,al,au)end else if not al then fc=a:CompressZlib(fb,au)else fc=a:CompressZlibWithDict(fb,al,au)end end else if not f5 then if not al then fc=a:DecompressDeflate(fb)else fc=a:DecompressDeflateWithDict(fb,al)end else if not al then fc=a:DecompressZlib(fb)else fc=a:DecompressZlibWithDict(fb,al)end end end;if not fc then io.stderr:write("LibDeflate: Decompress fails.")os.exit(1)end;f4:write(fc)if dx and dx~=io.stdin then dx:close()end;if f4 and f4~=io.stdout then f4:close()end;io.stderr:write(("Successfully writes %d bytes"):format(fc:len()))os.exit(0)end end;return a end)() local expect = dofile("rom/modules/main/cc/expect.lua") local expect, field = expect.expect, expect.field local filesystem = nil settings.define("containers.compression_level", { description = "The level of compression for the file systems on a scale of 1-8", default = 4, type = "number", }) settings.save() local compression_level = settings.get("containers.compression_level") local lib = {} local function deepcopy(o, seen) seen = seen or {} if o == nil then return nil end if seen[o] then return seen[o] end local no if type(o) == 'table' then no = {} seen[o] = no for k, v in next, o, nil do no[deepcopy(k, seen)] = deepcopy(v, seen) end setmetatable(no, deepcopy(getmetatable(o), seen)) else -- number, string, boolean, etc no = o end return no end local function buildRom(path) sleep() local out = {} for _, file in ipairs(fs.list(path)) do local fullPath = fs.combine(path, file) if fs.isDir(fullPath) then out[file] = buildRom(fullPath) else local handle = fs.open(fullPath, "r") out[file] = handle.readAll() handle.close() end end return out end local function getRom() if not _G.rom_cache then _G.rom_cache = buildRom("/rom") end return _G.rom_cache end function lib.getENV(fspath, has_http) local global = deepcopy(_G) setmetatable(global, { __index = _G }) local function getFileSystem() if filesystem then filesystem.rom = getRom() return filesystem end if not fs.exists(fspath) then return {rom=getRom()} end local file = fs.open(fspath, "r") local compressedData = file.readAll() file.close() local decompressedData = deflate:DecompressDeflate(compressedData,{level=compression_level}) local data = textutils.unserialize(decompressedData) or {} filesystem = data data.rom = getRom() return data end local function setFileSystem(data) filesystem = data data.rom = nil data = textutils.serialize(data) local file = fs.open(fspath, "w") file.write(deflate:CompressDeflate(data,{level=compression_level})) file.close() end local function normalizeParts(path) local parts = {} for part in string.gmatch(path, "[^/]+") do if part == "" or part == "." then -- skip elseif part == ".." then if #parts > 0 then table.remove(parts) end else parts[#parts + 1] = part end end return parts end local function getDataAt(path) expect(1, path, "string") local parts = normalizeParts(path) local current = getFileSystem() if #parts == 0 then return current end for i = 1, #parts do local part = parts[i] if type(current) ~= "table" then -- trying to index into a file return nil end current = current[part] if current == nil then return nil end end return current end local function setDataAt(path, data) expect(1, path, "string") local parts = normalizeParts(path) local filesys = getFileSystem() local current = filesys for i, part in ipairs(parts) do if i == #parts then current[part] = data elseif type(current[part]) == "table" then current = current[part] elseif type(current[part]) == "string" then return end end setFileSystem(filesys) end function global.fs.list(path) expect(1, path, "string") local out = {} local data = getDataAt(path) if data then for k, v in pairs(data) do table.insert(out, k) end end return out end function global.fs.isDir(path) expect(1, path, "string") local data = getDataAt(path) return type(data) == "table" end function global.fs.isReadOnly(path) if path == "" then return false end expect(1, path, "string") local offset = string.find(path, "rom") return offset ~= nil and offset < 3 end function global.fs.exists(path) expect(1, path, "string") local data = getDataAt(path) return data ~= nil end function global.fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) expect(1, sPath, "string") expect(2, sLocation, "string") local bIncludeHidden = nil if type(bIncludeFiles) == "table" then bIncludeDirs = field(bIncludeFiles, "include_dirs", "boolean", "nil") bIncludeHidden = field(bIncludeFiles, "include_hidden", "boolean", "nil") bIncludeFiles = field(bIncludeFiles, "include_files", "boolean", "nil") else expect(3, bIncludeFiles, "boolean", "nil") expect(4, bIncludeDirs, "boolean", "nil") end bIncludeHidden = bIncludeHidden ~= false bIncludeFiles = bIncludeFiles ~= false bIncludeDirs = bIncludeDirs ~= false local sDir = sLocation local nStart = 1 local nSlash = string.find(sPath, "[/\\]", nStart) if nSlash == 1 then sDir = "" nStart = 2 end local sName while not sName do local nSlash = string.find(sPath, "[/\\]", nStart) if nSlash then local sPart = string.sub(sPath, nStart, nSlash - 1) sDir = global.fs.combine(sDir, sPart) nStart = nSlash + 1 else sName = string.sub(sPath, nStart) end end if global.fs.isDir(sDir) then local tResults = {} if bIncludeDirs and sPath == "" then table.insert(tResults, ".") end if sDir ~= "" then if sPath == "" then table.insert(tResults, bIncludeDirs and ".." or "../") elseif sPath == "." then table.insert(tResults, bIncludeDirs and "." or "./") end end local tFiles = global.fs.list(sDir) for n = 1, #tFiles do local sFile = tFiles[n] if #sFile >= #sName and string.sub(sFile, 1, #sName) == sName and ( bIncludeHidden or sFile:sub(1, 1) ~= "." or sName:sub(1, 1) == "." ) then local bIsDir = global.fs.isDir(fs.combine(sDir, sFile)) local sResult = string.sub(sFile, #sName + 1) if bIsDir then table.insert(tResults, sResult .. "/") if bIncludeDirs and #sResult > 0 then table.insert(tResults, sResult) end else if bIncludeFiles and #sResult > 0 then table.insert(tResults, sResult) end end end end return tResults end return {} end local function getReadHandle(path, isBinary) expect(1, path, "string") local data = getDataAt(path) or "" local len = #data local seek = 1 return { readAll = function() if data == nil then return nil end data = data:sub(seek) seek = len + 1 return data end, readLine = function(includeTrailing) if data == nil then return nil end if seek > len then return nil end -- EOF guard local start = seek local nl = data:find("\n", start, true) local line if nl then if includeTrailing then line = data:sub(start, nl) -- include "\n" else line = data:sub(start, nl - 1) -- exclude "\n" end seek = nl + 1 else -- last line (no trailing newline) line = data:sub(start) seek = len + 1 end -- NOTE: do NOT treat "" as EOF; blank lines are valid return line end, read = function(count) if type(count) == "table" then count = 1 end expect(1, count, "number", "nil") if data == nil then return nil end if not count then count = 1 end if seek > len then return nil end local toReturn = string.sub(data, seek, seek + count - 1) seek = seek + #toReturn if toReturn == "" then return nil elseif isBinary and count == 1 then return string.byte(toReturn) end return toReturn end, seek = function (offset, whence) if data == nil then return nil, "File is closed" end offset = offset or 0 whence = whence or "cur" if whence == "set" then seek = math.min(math.max(0, offset), len) + 1 elseif whence == "cur" then seek = math.min(math.max(1, seek + offset), len + 1) elseif whence == "end" then seek = math.min(math.max(0, len + offset), len) + 1 end return seek - 1 end, close = function() data = nil end, } end local function getWriteHandle(path, isBinary, append_mode) local data = "" local seek = 1 if append_mode then data = getDataAt(path) or "" seek = #data + 1 end local handle -- forward declared so writeLine can see it local function hwrite(str) if data == nil then error("File is closed", 2) end if type(str) == "number" and isBinary then str = string.char(str) elseif type(str) ~= "string" then error("bad argument #1 (string or number expected, got " .. type(str) .. " )", 2) end data = string.sub(data, 1, seek - 1) .. str .. string.sub(data, seek + #str) seek = seek + #str end handle = { write = hwrite, writeLine = function (str) if data == nil then error("File is closed", 2) end expect(1, str, "string") hwrite(str .. "\n") -- **no global write** end, flush = function() if data == nil then error("File is closed", 2) end setDataAt(path, data) end, close = function() if data == nil then error("File is already closed", 2) end setDataAt(path, data) data = nil end, } return handle end local function getReadWriteHandle(path, isBinary, erase_data) expect(1, path, "string") local data = erase_data and "" or (getDataAt(path) or "") local len = #data local seek = 1 local handle = {} handle.readAll = function() if data == nil then return nil end data = data:sub(seek) seek = len + 1 return data end handle.readLine = function(includeTrailing) if data == nil then return nil end if seek > len then return nil end -- EOF guard local start = seek local nl = data:find("\n", start, true) local line if nl then if includeTrailing then line = data:sub(start, nl) else line = data:sub(start, nl - 1) end seek = nl + 1 else line = data:sub(start) seek = len + 1 end return line end function handle.read(count) if type(count) == "table" then count = 1 end expect(1, count, "number", "nil") if data == nil then error("File is closed", 2) end if not count then count = 1 end if seek > len then return nil end local toReturn = data:sub(seek, seek + count - 1) seek = seek + #toReturn if toReturn == "" then return nil elseif isBinary and count == 1 then return string.byte(toReturn) end return toReturn end function handle.seek(offset, whence) if data == nil then return nil, "File is closed" end offset = offset or 0 whence = whence or "cur" if whence == "set" then seek = math.min(math.max(0, offset), len) + 1 elseif whence == "cur" then seek = math.min(math.max(1, seek + offset), len + 1) elseif whence == "end" then seek = math.min(math.max(0, len + offset), len) + 1 else error("bad argument #2 (invalid whence)", 2) end return seek - 1 end function handle.write(str) if type(str) == "number" and isBinary then str = string.char(str) elseif type(str) ~= "string" then error("bad argument #1 (string or number expected, got " .. type(str) .. " )", 2) end if data == nil then error("File is closed", 2) end data = string.sub(data, 1, seek - 1) .. str .. string.sub(data, seek + #str) seek = seek + #str len = #data end function handle.writeLine(str) expect(1, str, "string") handle.write(str .. "\n") end function handle.flush() if data == nil then error("File is closed", 2) end setDataAt(path, data) end function handle.close() if data == nil then error("File is already closed", 2) end setDataAt(path, data) data = nil end return handle end local function ioHandleWrapper(handle) local closed = false return { read = function (self, mode) if closed then error("File is closed", 2) end expect(2, mode, "string", "nil") if not mode then mode = "l" end if type(self) ~= "table" then error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) end if string.find(mode, "%*") == 1 then mode = mode:gsub("%*", "") end if mode == "l" then return handle.readLine(false) elseif mode == "L" then return handle.readLine(true) elseif mode == "a" then return handle.readAll() else error("Unsupported read mode", 2) end end, seek = function (self, whence, offset) if closed then error("File is closed", 2) end expect(2, whence, "string", "nil") expect(3, offset, "number", "nil") if type(self) ~= "table" then error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) end return handle.seek(offset, whence) end, write = function (self, ...) if closed then error("File is closed", 2) end if type(self) ~= "table" then error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) end local args = { ... } for i = 1, #args do local arg = args[i] if type(arg) ~= "string" and type(arg) ~= "number" then error("bad argument #" .. (i + 1) .. " (string or number expected, got " .. type(arg) .. " )", 2) end -- preserve your existing semantics: underlying handle decides what to do handle.write(arg) end end, close = function (self) if closed then error("File is already closed", 2) end if type(self) ~= "table" then error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) end handle.close() closed = true end, flush = function (self) if closed then error("File is closed", 2) end if type(self) ~= "table" then error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) end handle.flush() end, lines = function (self) if closed then error("File is closed", 2) end if type(self) ~= "table" then error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) end return function() if closed then error("file is already closed", 2) end return handle.readLine(false) end end, } end function global.fs.open(path,mode) expect(1, path, "string") expect(2, mode, "string") if mode == "r" or mode == "rb" then if global.fs.exists(path) then return getReadHandle(path, mode == "rb") else error("File not found", 2) end elseif mode == "w" or mode == "wb" then return getWriteHandle(path, mode == "wb", false) elseif mode == "a" or mode == "ab" then return getWriteHandle(path, mode == "ab", true) elseif mode == "r+" or mode == "rb+" or mode == "r+b" then if global.fs.exists(path) then return getReadWriteHandle(path, mode == "rb+" or mode == "r+b", false) else error("File not found", 2) end elseif mode == "w+" or mode == "wb+" or mode == "w+b" then return getReadWriteHandle(path, mode == "wb+" or mode == "w+b", true) elseif mode == "a+" or mode == "ab+" or mode == "a+b" then return getReadWriteHandle(path, mode == "ab+" or mode == "a+b", true) else error("Invalid mode", 2) end end function global.fs.move(srcPath, dstPath) expect(1, srcPath, "string") expect(2, dstPath, "string") if not global.fs.exists(srcPath) then error("Source does not exist", 2) end if global.fs.exists(dstPath) then error("Destination already exists", 2) end local data = getDataAt(srcPath) setDataAt(dstPath, data) setDataAt(srcPath, nil) end function global.fs.copy(srcPath, dstPath) expect(1, srcPath, "string") expect(2, dstPath, "string") if not global.fs.exists(srcPath) then error("Source does not exist", 2) end if global.fs.exists(dstPath) then error("Destination already exists", 2) end local data = getDataAt(srcPath) setDataAt(dstPath, data) end local function find_aux(path, parts, i, out) local part = parts[i] if not part then -- If we're at the end of the pattern, ensure our path exists and append it. if global.fs.exists(path) then out[#out + 1] = path end elseif part.exact then -- If we're an exact match, just recurse into this directory. return find_aux(global.fs.combine(path, part.contents), parts, i + 1, out) else -- Otherwise we're a pattern. Check we're a directory, then recurse into each -- matching file. if not global.fs.isDir(path) then return end local files = global.fs.list(path) for j = 1, #files do local file = files[j] if file:find(part.contents) then find_aux(global.fs.combine(path, file), parts, i + 1, out) end end end end local find_escape = { -- Escape standard Lua pattern characters ["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%", ["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-", -- Aside from our wildcards. ["*"] = ".*", ["?"] = ".", } function global.fs.find(pattern) expect(1, pattern, "string") pattern = global.fs.combine(pattern) -- Normalise the path, removing ".."s. -- If the pattern is trying to search outside the computer root, just abort. -- This will fail later on anyway. if pattern == ".." or pattern:sub(1, 3) == "../" then error("/" .. pattern .. ": Invalid Path", 2) end -- If we've no wildcards, just check the file exists. if not pattern:find("[*?]") then if global.fs.exists(pattern) then return { pattern } else return {} end end local parts = {} for part in pattern:gmatch("[^/]+") do if part:find("[*?]") then parts[#parts + 1] = { exact = false, contents = "^" .. part:gsub(".", find_escape) .. "$", } else parts[#parts + 1] = { exact = true, contents = part } end end local out = {} find_aux("", parts, 1, out) return out end function global.io.open(path, mode) expect(1, path, "string") expect(2, mode, "string", "nil") if not mode then mode = "r" end local handle if mode == "r" or mode == "rb" then if global.fs.exists(path) and not global.fs.isDir(path) then handle = getReadHandle(path, mode == "rb") elseif global.fs.isDir(path) then return nil, "Attempt to open a directory" else return nil, "File not found" end elseif mode == "w" or mode == "wb" then handle = getWriteHandle(path, mode == "wb", false) elseif mode == "a" or mode == "ab" then handle = getWriteHandle(path, mode == "ab", true) elseif mode == "r+" or mode == "rb+" or mode == "r+b" then if global.fs.exists(path) and not global.fs.isDir(path) then handle = getReadWriteHandle(path, mode == "rb+" or mode == "r+b", false) elseif global.fs.isDir(path) then return nil, "Attempt to open a directory" else return nil, "File not found" end elseif mode == "w+" or mode == "wb+" or mode == "w+b" then handle = getReadWriteHandle(path, mode == "wb+" or mode == "w+b", true) elseif mode == "a+" or mode == "ab+" or mode == "a+b" then handle = getReadWriteHandle(path, mode == "ab+" or mode == "a+b", true) else return nil, "Invalid mode" end return ioHandleWrapper(handle) end function global.io.lines(path,...) local args = {...} expect(1, path, "string") local handle = global.io.open(path, table.unpack(args)) local count = 0 return function () count = count + 1 local line = handle:read(args[count%#args + 1] or "l") if line == nil then handle:close() end return line end end function global.fs.delete(path) expect(1, path, "string") if not global.fs.exists(path) then error("File not found", 2) end setDataAt(path, nil) end function global.fs.getSize(path) expect(1, path, "string") if not global.fs.exists(path) then error("File not found", 2) end if global.fs.isDir(path) then return 0 else return #getDataAt(path) end end function global.fs.makeDir(path) expect(1, path, "string") if global.fs.exists(path) then return end setDataAt(path, {}) end local tAPIsLoading = {} local bAPIError = false function global.loadfile(filename, mode, env) -- Support the previous `loadfile(filename, env)` form instead. if type(mode) == "table" and env == nil then mode, env = nil, mode end expect(1, filename, "string") expect(2, mode, "string", "nil") expect(3, env, "table", "nil") local file = global.fs.open(filename, "r") if not file then return nil, "File not found" end local func, err = load(file.readAll(), "@/" .. fs.combine(filename), mode, env) file.close() return func, err end function global.dofile(_sFile) expect(1, _sFile, "string") local fnFile, e = global.loadfile(_sFile, nil, _G) if fnFile then return fnFile() else error(e, 2) end end function global.loadAPI(_sPath) expect(1, _sPath, "string") local sName = fs.getName(_sPath) if sName:sub(-4) == ".lua" then sName = sName:sub(1, -5) end if sName == "term" then return true end if tAPIsLoading[sName] == true then printError("API " .. sName .. " is already being loaded") return false end tAPIsLoading[sName] = true local tEnv = {} setmetatable(tEnv, { __index = global }) local fnAPI, err = global.loadfile(_sPath, nil, tEnv) if fnAPI then local ok, err = pcall(fnAPI) if not ok then tAPIsLoading[sName] = nil return error("Failed to load API " .. sName .. " due to " .. err, 1) end else tAPIsLoading[sName] = nil return error("Failed to load API " .. sName .. " due to " .. err, 1) end local tAPI = {} for k, v in pairs(tEnv) do if k ~= "_ENV" then tAPI[k] = v end end global[sName] = tAPI tAPIsLoading[sName] = nil return true end local function load_apis(dir) if not global.fs.isDir(dir) then return end for _, file in ipairs(global.fs.list(dir)) do if file:sub(1, 1) ~= "." then local path = fs.combine(dir, file) if not fs.isDir(path) then if not global.loadAPI(path) then bAPIError = true end end end end end function global.os.run(_tEnv, _sPath, ...) expect(1, _tEnv, "table") expect(2, _sPath, "string") local tEnv = _tEnv setmetatable(tEnv, { __index = global }) if settings.get("bios.strict_globals", false) then -- load will attempt to set _ENV on this environment, which -- throws an error with this protection enabled. Thus we set it here first. tEnv._ENV = tEnv getmetatable(tEnv).__newindex = function(_, name) error("Attempt to create global " .. tostring(name), 2) end end local fnFile, err = global.loadfile(_sPath, nil, tEnv) if fnFile then local ok, err = pcall(fnFile, ...) if not ok then if err and err ~= "" then printError(err) end return false end return true end if err and err ~= "" then printError(err) end return false end global.settings = settings global._ENV = global global._G = global global.shell = nil global.multishell = nil load_apis("rom/apis") if http and has_http then global.http = http load_apis("rom/apis/http") end return global end function lib.start(env) local func = setfenv(function () settings.define("shell.allow_startup", { default = true, description = "Run startup files when the computer turns on.", type = "boolean", }) settings.define("shell.allow_disk_startup", { default = commands == nil, description = "Run startup files from disk drives when the computer turns on.", type = "boolean", }) settings.define("shell.autocomplete", { default = true, description = "Autocomplete program and arguments in the shell.", type = "boolean", }) settings.define("edit.autocomplete", { default = true, description = "Autocomplete API and function names in the editor.", type = "boolean", }) settings.define("lua.autocomplete", { default = true, description = "Autocomplete API and function names in the Lua REPL.", type = "boolean", }) settings.define("edit.default_extension", { default = "lua", description = [[The file extension the editor will use if none is given. Set to "" to disable.]], type = "string", }) settings.define("paint.default_extension", { default = "nfp", description = [[The file extension the paint program will use if none is given. Set to "" to disable.]], type = "string", }) settings.define("list.show_hidden", { default = false, description = [[Whether the list program show hidden files (those starting with ".").]], type = "boolean", }) settings.define("motd.enable", { default = pocket == nil, description = "Display a random message when the computer starts up.", type = "boolean", }) settings.define("motd.path", { default = "/rom/motd.txt:/motd.txt", description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]], type = "string", }) settings.define("lua.warn_against_use_of_local", { default = true, description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessible on the next input.]], type = "boolean", }) settings.define("lua.function_args", { default = true, description = "Show function arguments when printing functions.", type = "boolean", }) settings.define("lua.function_source", { default = false, description = "Show where a function was defined when printing functions.", type = "boolean", }) settings.define("bios.strict_globals", { default = false, description = "Prevents assigning variables into a program's environment. Make sure you use the local keyword or assign to _G explicitly.", type = "boolean", }) settings.define("shell.autocomplete_hidden", { default = false, description = [[Autocomplete hidden files and folders (those starting with ".").]], type = "boolean", }) print("running container!") local ok, err = pcall(parallel.waitForAny, function() local sShell if term.isColour() and settings.get("bios.use_multishell") then sShell = "rom/programs/advanced/multishell.lua" else sShell = "rom/programs/shell.lua" end os.run({}, sShell) os.run({}, "rom/programs/shutdown.lua") end, rednet.run ) end,env) func() end return lib