CoolisTheName007

install

Mar 16th, 2013
302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 347.59 KB | None | 0 0
  1. local t={"CoolisOS",true,"CoolisOS/bin",true,"CoolisOS/bin/kernel",true,"CoolisOS/bin/kernel/compat.lua",[===================[--compat
  2.  
  3. local interface_events={
  4.     'mouse_click',
  5.     'mouse_scroll',
  6.     'mouse_drag',
  7.     'monitor_touch',
  8.     'key',
  9.     'char',
  10.     }
  11.    
  12.    
  13. --needs to determine the terminal in some other way.
  14. local check=require'checker'.check
  15.  
  16. local compat={}
  17. function compat.get_pullEventRaw(term_em,plat_em)
  18.     return function (filter)
  19.         check('?string',filter)
  20.         local t=assert(sched.running)
  21.         if not t._native then
  22.             local pipe=sched.pipe()
  23.             t._native=pipe
  24.             local h=sched.sighook(function(em,ev,...)
  25.                 if plat_em and em==plat_em and interface_events[ev] then
  26.                     return
  27.                 else
  28.                     pipe:send{ev,...}
  29.                 end
  30.             end)
  31.             if plat_em then h:link(plat_em,'*') end
  32.             if term_em then h:link{[term_em]=interface_events} end
  33.         end
  34.         local pipe=t._native
  35.         repeat
  36.             local r=pipe:receive()
  37.         until (filter==nil or filter==r[1])
  38.         return unpack(r)
  39.     end
  40. end
  41.  
  42. function compat.adapt_env(env,term_em,plat_em)
  43.     env.os.pullEventRaw=compat.get_pullEventRaw(term_em,plat_em)
  44. end
  45.  
  46.  
  47. function compat.adapt_global(_Gnative)
  48.     local Box=require'kernel.class.Box'
  49.    
  50.     local turtle=_Gnative.turtle
  51.     if turtle then
  52.         local waitForResponse=function(id)
  53.             repeat
  54.                 local em,ev,rid,p1=sched.wait(sched.platform,'turtle_response')
  55.                 if em==sched.platform then
  56.                     if id==rid then
  57.                         return p1
  58.                     end
  59.                 else return false,'timer' end
  60.             until false
  61.         end
  62.         local native=turtle.native or turtle
  63.         local turtle={}
  64.         rawset(_Gnative,'turtle',turtle)
  65.         turtle["getItemCount"] = native.getItemCount
  66.         turtle["getItemSpace"] = native.getItemSpace
  67.         turtle["getFuelLevel"] = native.getFuelLevel
  68.         local function wrap( _sCommand )
  69.             return function( ... )
  70.                 local id = _Gnative.debug and debug.wrap(native[_sCommand])(...) or native[_sCommand]( ... )
  71.                 if id == -1 then
  72.                     return false
  73.                 end
  74.                 return waitForResponse( id )
  75.             end
  76.         end
  77.         for k,v in pairs( native ) do
  78.             if type( k ) == "string" and type( v ) == "function" then
  79.                 if turtle[k] == nil then
  80.                     turtle[k] = wrap( k )
  81.                 end
  82.             end
  83.         end
  84.         if peripheral.getType("left") == "workbench" then
  85.             turtle["craft"] = function( ... )
  86.                 local id = peripheral.call( "left", "craft", ... )
  87.                 return waitForResponse( id )
  88.             end
  89.         elseif peripheral.getType("right") == "workbench" then
  90.             turtle["craft"] = function( ... )
  91.                 local id = peripheral.call( "right", "craft", ... )
  92.                 return waitForResponse( id )
  93.             end
  94.         end
  95.        
  96.     end
  97.     rednet.receive=function( nTimeout )
  98.         local em,e, p1, p2, p3 = sched.wait(sched.platform,'rednet_message',nTimeout)
  99.         if em==sched.platform then
  100.             return p1, p2, p3
  101.         else
  102.             return
  103.         end    
  104.     end
  105.    
  106.    
  107.     local dyn_k={
  108.     'term',
  109.     'os',
  110.     'shell',
  111.     }
  112.     local dyn_f={
  113.     'write',
  114.     'printError',
  115.     'read',
  116.     }
  117.     for _,k in pairs(dyn_f) do
  118.         rawset(_Gnative,k,function(...)
  119.             local box=assert(Box.get_current(1))
  120.             return box.env[k](...)
  121.         end)
  122.     end
  123.     setmetatable(_Gnative,{
  124.     __index=function(t,k)
  125.         if k=='_BOX' then
  126.             return Box.get_current(1)
  127.         elseif dyn_k[k] then
  128.             local box=assert(Box.get_current(1))
  129.             return box.env[k]
  130.         else return rawget(t,k) end
  131.     end
  132.     })
  133.    
  134. end
  135.  
  136. return compat]===================],"CoolisOS/bin/kernel/debug.lua",[===================[--debug
  137. include'kernel.class'
  138. local check=require'kernel.checker'.check
  139. local debug={}
  140.  
  141. local function wrap(text, limit) --from Kingdaroo
  142.         local lines = {''}
  143.         for word, space in text:gmatch('(%S+)(%s*)') do
  144.                 local temp = lines[#lines] .. word .. space:gsub('\n','')
  145.                 if #temp > limit then
  146.                         table.insert(lines, '')
  147.                 end
  148.                 if space:find('\n') then
  149.                         lines[#lines] = lines[#lines] .. word
  150.                        
  151.                         space = space:gsub('\n', function()
  152.                                 table.insert(lines, '')
  153.                                 return ''
  154.                         end)
  155.                 else
  156.                         lines[#lines] = lines[#lines] .. word .. space
  157.                 end
  158.         end
  159.         return lines
  160. end
  161.  
  162. function debug.step_print(s,t)
  163.     check('string,Terminal',s,t)
  164.     local x,y=t.term:getSize()
  165.     y=y-1
  166.     local tt=wrap(s,x)
  167.     local r=#tt%y
  168.     local n=(#tt-r)/y
  169.     for i=0,n-1 do
  170.         if i~=0 then t:write('\n') end
  171.         t:write(table.concat(tt,'\n',i*y+1,(i+1)*y))
  172.         t:write('\nPress any key to continue')
  173.         repeat until (t.pin:receive())[2]=='char'
  174.         if i==n-1 then t:write('\n') end
  175.     end
  176.     t:write(table.concat(tt,'\n',n*y+1,n*y+r))
  177.     t:write('\n')
  178. end
  179.  
  180. function debug.printError(s,t)
  181.     check('string,Terminal',s,t)
  182.     if t.term:isColour() then
  183.         t.term:setTextColour( colours.red )
  184.     end
  185.     debug.step_print(s,t)
  186.     t.term:setTextColour( colours.white )
  187. end
  188.  
  189. --debug.traceback
  190. do
  191. --[[ Notes:
  192. getfenv(1)=getfenv()~=getfenv(0)~~_G
  193. error('',1)~=error('',0)
  194. ]]
  195. rawset(_G,'loadfile',function( _sFile )
  196.   local file = fs.open( _sFile, "r" )
  197.   if file then
  198.     local func, err = loadstring( file.readAll(),_sFile)
  199.     file.close()
  200.     return func, err
  201.   end
  202.   return nil, "File not found"
  203. end)
  204. local traceback=function(level,terr,maxlevel)
  205.   local terr=terr or {}
  206.   local passed={}
  207.   local err,ok=terr
  208.   local j=2+(level or 0)
  209.   repeat
  210.     j=j+1
  211.     passed[err]=true
  212.     ok,err=pcall(error,'',j)
  213.     --if err:match('^[^:]+')=='bios' then break end
  214.     table.insert(terr,err)
  215.   until (passed[err] or (maxlevel and (j+1-2>maxlevel) ) )
  216.  
  217.   return terr
  218. end
  219.  
  220. local function classify(t,f)
  221.   local bins={}
  222.   local c
  223.   for i,v in ipairs(t) do
  224.     local fi,r=f(v)
  225.     if fi~=nil then
  226.       if c==nil or c.n~=fi then
  227.         table.insert(bins,c)
  228.         c={n=fi}
  229.       end
  230.       table.insert(c,r)
  231.     end
  232.   end
  233.   table.insert(bins,c)
  234.   return bins
  235. end
  236. local function get_chunks(terr)
  237.   return classify(terr,function(v) return v:match('^([^:]+):(.*)') end)
  238. end
  239.  
  240. local function get_lines(terr)
  241.   return classify(terr,function(v) return v:match('^(%d+):(.*)') end)
  242. end
  243.  
  244. local function put_lines(path,diameter,ts,l)
  245.   local ok,f=pcall(fs.open,path,'r')
  246.   if not ok or not f then table.insert(ts,'  (could not open file)')
  247.   else
  248.     for i=1,l-diameter-1 do
  249.       f.readLine()
  250.     end
  251.     for i=1,diameter do
  252.       table.insert(ts,'  '..f.readLine())
  253.     end
  254.     table.insert(ts,'->'..f.readLine())
  255.     for i=1,diameter do
  256.       local l=f.readLine()
  257.       if l then table.insert(ts,'  '..l)
  258.       else break end
  259.     end
  260.   end
  261. end
  262.  
  263. local function format_traceback(terr)
  264.   local ts={}
  265.   for i,v in ipairs(get_chunks(terr)) do
  266.     local name=v.n or '(no name)'
  267.     local path
  268.     if fs.exists(name) then
  269.       name,dir,path=fs.getName(name),name:match('^(.*)/') or '/',name
  270.       name=name..' ('..(dir or 'unknown')..')'
  271.     elseif false then
  272.       --shell has input string; modify to behave as file?
  273.     end
  274.     table.insert(ts,name)
  275.     for j,line in ipairs(get_lines(v)) do
  276.       table.insert(ts,' line '..(line.n or '(no line)')..', *'..(#line))
  277.       local n=line.n and tonumber(line.n) or 1
  278.       if path and n then
  279.         put_lines(path,1,ts,n)
  280.       end
  281.     end
  282.   end
  283.   return ts
  284. end
  285.  
  286. function debug.traceback(msg,level,maxlevel)
  287.   local level=level or 0
  288.   local ts=format_traceback(traceback(level+1,{},maxlevel))
  289.   msg=(msg and '\n' or '')..'['..(msg or 'debug.traceback')
  290.   table.insert(ts,1,msg)
  291.   return table.concat(ts,'\n')..'\n]'
  292. end
  293.  
  294. function debug.printTraceback(msg,level)
  295.     debug.printError(debug.traceback(msg,(level or 0)+1))
  296. end
  297.  
  298. function debug.tracebackError(msg,level)
  299.     error(debug.traceback(msg,(level or 0)+1),2)
  300. end
  301. end
  302. function debug.raw(t)
  303.     if type(t)=='table' then
  304.         local mt=getmetatable(t)
  305.         if mt then
  306.             local f=rawget(mt,'__tostring')
  307.             rawset(mt,'__tostring',nil)
  308.             local s=tostring(t)
  309.             rawset(mt,'__tostring',f)
  310.             return s
  311.         else
  312.             return tostring(t)
  313.         end
  314.     else
  315.         return tostring(t)
  316.     end
  317. end
  318. function debug.log(...)
  319.     return log('debug','DEBUG','(%s):\nMsg:\n\t%s\nFrom:%s',sched.running or 'nil',debug.args_tostring(...),debug.traceback('',1,2))
  320. end
  321.  
  322.  
  323. function debug.objinfo(s)
  324.     local name=debug.named[s]
  325.     return (name and name..'|' or '')
  326.         ..(typeof(s)=='object' and (classname(s) or debug.raw(s))..' instance|' or '')
  327.         ..debug.raw(s) or ''
  328. end
  329.  
  330.  
  331. function debug.getinfo(v)
  332.     if type(v)=='table' then
  333.         return debug.objinfo(v)
  334.     else
  335.         return type(v)..':'..tostring(v)
  336.     end
  337. end
  338. function debug.args_tostring(...)
  339.     local args = {}
  340.     local t = {...}
  341.     for k = 1, table.maxn(t) do table.insert(args, (debug.getinfo)(t[k])) end
  342.     return table.concat(args,',')
  343. end
  344. function debug.wrap(f,silent)
  345.     return function(...)
  346.         --wrapped level
  347.         f=util.bindn(f,...)
  348.         local r={xpcall(f,debug.traceback)}
  349.         local ok=table.remove(r,1)
  350.         if not ok then
  351.             local er=r[1]
  352.             if silent then return nil,er
  353.             else error(er,2) end
  354.         end
  355.         return unpack(r)
  356.     end
  357. end
  358.  
  359. debug.named=setmetatable({},{__mode='kv'})
  360. function debug.name(obj,name)
  361.     debug.named[obj]=name
  362.     return obj
  363. end
  364.  
  365. function debug.namefield(self,k,v)
  366.     v=v==nil and self[k] or v
  367.     check('table,!nil,!nil',self,k,v)
  368.     self[k]=v
  369.     debug.name(v,('(%s).(%s)'):format(debug.getinfo(self),debug.getinfo(k)))
  370.     return v
  371. end
  372.  
  373. debug.say=function(s) return log('init','INFO','task:(%s) says:%s',tostring(sched.running),s) end
  374.  
  375. return debug]===================],"CoolisOS/bin/kernel/driver.lua",[===================[local driver={}
  376.  
  377. local peripheral=peripheral
  378. function driver.update()
  379.     for _, side in ipairs(rs.getSides()) do
  380.         if peripheral.isPresent(side) then
  381.             driver[side]=peripheral.wrap(side)
  382.             -- sched.signal(peripheral,peripheral[side].getType(),side)
  383.         else
  384.             driver[side]=nil
  385.         end
  386.     end
  387. end
  388.  
  389. return driver]===================],"CoolisOS/bin/kernel/init.lua",[===================[local path=shell.getRunningProgram()
  390. local function override(f)
  391. local t={}
  392. local fo=printError
  393. local key='printError'
  394. local co=coroutine.status
  395. local wrapped=function(s)
  396.     coroutine.status=co
  397.     for i,v in pairs(t) do
  398.         rawset(v,key,fo)
  399.     end
  400.     local ok,err=pcall(f)
  401.     if not ok then
  402.         fo(err)
  403.     end
  404.     coroutine.yield()
  405.     coroutine.yield()
  406. end
  407. for i=1,20 do
  408.     local ok,err=pcall(getfenv,i)
  409.     if ok then
  410.         if rawget(err,key)~=nil and not t[err] then
  411.             t[i]=err
  412.             rawset(err,key,wrapped)
  413.         end
  414.     end
  415. end
  416. coroutine.status=nil
  417. repeat
  418.     os.pullEvent()
  419. until false
  420. end
  421.  
  422. local function fixes()
  423.     local string=string
  424.     local rawset, rawget,type=rawset, rawget,type
  425.     local nativegetmetatable=getmetatable
  426.     local s_meta=getfenv(('').sub)
  427.     rawset(_G,'getmetatable',nil)
  428.     local function getmetatable(t)
  429.         if type(t)=='string' then
  430.             return s_meta
  431.         else
  432.             return nativegetmetatable(t)
  433.         end
  434.     end
  435.     rawset(_G,'getmetatable',getmetatable)
  436.  
  437.     local nativesetmetatable = setmetatable
  438.     rawset(_G,'setmetatable',nil)
  439.     local function setmetatable( _o, _t )
  440.         if _t and type(_t) == "table" then
  441.             local idx = rawget( _t, "__index" )
  442.             local newidx=rawget( _t, "__newindex" )
  443.             rawset(_t,"__index",nil)
  444.             rawset(_t,"__newindex",nil)
  445.             local r= nativesetmetatable( _o, _t )
  446.             rawset(_t,"__index",idx)
  447.             rawset(_t,"__newindex",newidx)
  448.             local meta=getmetatable(_o)
  449.             rawset(meta,"__index",idx)
  450.             rawset(meta,"__newindex",newidx)
  451.             return r
  452.         else
  453.             return nativesetmetatable( _o, _t )
  454.         end
  455.     end
  456.     rawset(_G,'setmetatable',setmetatable)
  457.  
  458.     rawset(_G,'loadfile',function( _sFile )
  459.         local file = fs.open( _sFile, "r" )
  460.         if file then
  461.             local func, err = loadstring( file.readAll(),_sFile)
  462.             file.close()
  463.             return func, err
  464.         end
  465.         return nil, "File not found"
  466.     end)
  467.  
  468. end
  469.  
  470. local function start()
  471.     debug.name(sched.running,'shell')
  472.     --log.setLevel('sched','DEBUG')
  473.     log.setLevel('DEBUG','debug')
  474.     --log.setLevel('DEBUG','pipe')
  475.     --log.setLevel('ALL')
  476.     --log.store=require'kernel.log.store'
  477.     --log.store.reset()
  478.     --log.store.instant=true
  479.     require'kernel.compat'.adapt_global(_G)
  480.     local gui=require'kernel.gui'
  481.    
  482.     local terminal=gui.Terminal.from_native(_G.term,sched.platform)
  483.     local shell=require'kernel.gui.shell'
  484.    
  485.     local Box=require'kernel.class.Box'
  486.     Box{pin=terminal.pin,pout=terminal.pout,terminal=terminal}:run(
  487.     function()
  488.         local s=shell.new()
  489.         s.run_startups()
  490.     end)
  491.     sched.wait('end')
  492. end
  493.  
  494. local main=function()
  495.     --save copy of old _G
  496.     rawset(_G,'_Gstore',{
  497.     old=(function()
  498.         local c={}
  499.         for i,v in pairs(_G) do
  500.             c[i]=v
  501.         end
  502.         return c
  503.     end)(),
  504.     base=_G,
  505.     base_env=getfenv(),
  506.     })
  507.     --overrides
  508.     fixes()
  509.    
  510.     ---set install variables and module loading utilities
  511.     do
  512.     _FILE_PATH=path
  513.     local loc=(_FILE_PATH:match'(.*)bin/kernel/init%.lua'):sub(1,-2)
  514.     rawset(_G,'_INSTALL_PATH',loc)
  515.     rawset(_G,'loadreq',dofile(fs.combine(_INSTALL_PATH,'bin/kernel/loadreq/init.lua')))
  516.     rawset(_G,'require',loadreq.require)
  517.     rawset(_G,'include',loadreq.include)
  518.     loadreq.vars.paths=loadreq.vars.paths:gsub('%?',fs.combine(_INSTALL_PATH,'bin')..'/%?')..';'..loadreq.vars.paths..';'..loadreq.vars.paths:gsub('%?',_INSTALL_PATH..'/%?')
  519.     end
  520.    
  521.     ---load modules
  522.     do
  523.     local function G(k,v)
  524.         rawset(_G,k,v)
  525.     end
  526.     G('util',require'kernel.util')
  527.     G('log',require'kernel.log')
  528.    
  529.     do
  530.     local serpent=require'utils.serpent'
  531.     G('pstring',function(this,max_level) return serpent.serialize(this,{debug=true,indent = '  ', sortkeys = true, comment = true,maxlevel=max_level}) end)
  532.     G('pprint',function(this,max_level)
  533.             debug.step_print(pstring(this),getfenv(2).term)
  534.         end)
  535.     G('debug',require'kernel.debug')
  536.     G('log',require'kernel.log')
  537.     G('sched',require'kernel.sched')
  538.    
  539.     G('net',require'kernel.net')
  540.     for i,v in pairs(require'kernel.class') do
  541.         G(i,v)
  542.     end
  543.     end
  544.    
  545.    
  546.     --overrided to os
  547.     do
  548.     os.sleep(0)
  549.     local o_os=os
  550.     local check=require'kernel.checker'.check
  551.     local os=util.shcopy(o_os)
  552.     local function wrap(f,i,e)
  553.         return function(...)
  554.             local ir,fr=nil,nil
  555.             if i then ir={i(...)} end
  556.             fr={f(...)}
  557.             if e then e(fr,ir) end
  558.             return unpack(fr)
  559.         end
  560.     end
  561.     os.version=function()
  562.         return 'CoolisOS.1'
  563.     end
  564.     os.sleep=function(n)
  565.         if sched.running then
  566.             check('number',n) sched.wait(n)
  567.         else return o_os.sleep(n) end
  568.     end
  569.     rawset(_G,'sleep',os.sleep)
  570.     rawset(_G,'os',os)
  571.     end
  572.     end
  573.    
  574.     sched.task(function()
  575.         debug.wrap(start)()
  576.     end):run()
  577.    
  578.     sched.loop()
  579.     log.store.flush()
  580.     print'Press any key to shutdown'
  581.     sleep(2)
  582.     os.pullEvent'key'
  583.     os.shutdown()
  584. end
  585.  
  586. override(function()
  587.     local ok,er=xpcall(main,function(msg,level)
  588.         if _G.debug then
  589.             return _G.debug.traceback(msg)
  590.         else
  591.             return msg
  592.         end
  593.     end)
  594.     if not ok then
  595.         if log then
  596.             log('init','ERROR','%s',er)
  597.             error(er)
  598.         end
  599.     end
  600. end)]===================],"CoolisOS/bin/kernel/net.lua",[===================[local string_mt=getfenv(('').len)
  601. local net=string_mt.__net or {}
  602. string_mt.__net=net
  603. net.ids=net.ids or setmetatable({},{__mode='v'})
  604. local ids=net.ids
  605. local id=os.getComputerID()
  606. ids[id]=_G
  607.  
  608. net.queueEvent=function(id,...)
  609.     if net.ids[id] then
  610.         ok,err=pcall(net.ids[id].os.queueEvent,...)
  611.         if not ok then
  612.             net.ids[id]=nil
  613.             return
  614.         end
  615.         return true
  616.     end
  617. end
  618. net.queueAll=function(...)
  619.     local t={}
  620.     for id in pairs(net.ids) do
  621.         t[id]=net.queueEvent(id,...)
  622.     end
  623.     return t
  624. end
  625. net.rednet={
  626. send=function(id,msg)
  627.     return net.queueEvent(id,'rednet_message',os.getComputerID(),msg,nil)
  628. end,
  629. broadcast=function(id,msg)
  630.     return net.queueAll('rednet_message',os.getComputerID(),msg,nil)
  631. end,
  632. }
  633. return net]===================],"CoolisOS/bin/kernel/util.lua",[===================[--- ## Moses: <em>A utility-belt library for functional programming in Lua.</em><br/>
  634. -- @author Roland_Yonaba
  635. -- @copyright 2012
  636. -- @license [MIT](http://www.opensource.org/licenses/mit-license.php)
  637. -- @script moses
  638. -- Internalisation
  639. local error,pcall=error,pcall
  640. local next, type, unpack, select = next, type, unpack, select
  641. local setmetatable, getmetatable = setmetatable, getmetatable
  642. local t_insert, t_sort = table.insert, table.sort
  643. local t_remove,t_concat = table.remove, table.concat
  644. local randomseed, random, huge = math.randomseed, math.random, math.huge
  645. local floor, max, min = math.floor, math.max, math.min
  646. local getfenv = getfenv
  647. local unpack = unpack
  648. local pairs,ipairs = pairs,ipairs
  649. local _ = {}
  650.  
  651.  
  652. -- ======== Private helpers
  653.  
  654. local function f_max(a,b) return a>b end
  655. local function f_min(a,b) return a<b end
  656. local function clamp(var,a,b) return (var<a) and a or (var>b and b or var) end
  657. local function isTrue(_,value) return value and true end
  658. local function iNot(value) return not value end
  659. local function count(t)
  660.     local i
  661.     for k,v in pairs(t) do i = (i or 0) + 1 end
  662.     return i
  663. end
  664. local function extract(list,comp,transform,...)
  665.   local _ans
  666.   local transform = transform or _.identity
  667.   for index,value in pairs(list) do
  668.     if not _ans then _ans = transform(value,...)
  669.     else
  670.       local value = transform(value,...)
  671.       _ans = comp(_ans,value) and _ans or value
  672.     end
  673.   end
  674.   return _ans
  675. end
  676.  
  677. -- Internal counter for unique ids generation
  678. local unique_id_counter = -1
  679. -- ========= Math utilities
  680. function _.format_number(n,r)     local e=10^r     local b=n%1     local a=n-b     local c=b*e     local c=c-c%1     return a+c/e end
  681.  
  682.  
  683. -- ========= Filesystem utilities
  684. function _.with(handle,f,...)
  685.   local ok, err=pcall(f,handle,...)
  686.   if handle and handle.close then handle:close() end
  687.   if not ok then error('util.with:'..err,2) end
  688.   return ok,err
  689. end
  690. -- ========== Table utilities
  691. function _.set(t,...)
  692.     local arg={...}
  693.     local t,n=t,#arg
  694.     for i=1,(n-2) do
  695.         t[arg[i]]=t[arg[i]] or {}
  696.         t=t[arg[i]]
  697.     end
  698.     t[arg[n-1]]=arg[n]
  699. end
  700.  
  701. function _.get(t,...)
  702.     local arg={...}
  703.     for i=1,#arg do
  704.         t=t[arg[i]]
  705.         if t==nil then return nil end
  706.     end
  707. end
  708.  
  709. function _.delete(t,...)
  710.     local arg={...}
  711.     local n=#arg
  712.     for i=1,n-1 do
  713.         t=t[arg[i]]
  714.         if t==nil then return nil end
  715.     end
  716.     t[arg[n]]=nil
  717. end
  718.  
  719. function _.map_args(t,f,...)
  720.     local args = {}
  721.     for k = 1, table.maxn(t) do table.insert(args,f(t[k],...)) end
  722.     return args
  723. end
  724.  
  725.  
  726. -- ========= Scheduler utilities
  727. function _.wait(f,match,...)
  728.     local r,b
  729.     repeat
  730.         r={f(...)}
  731.         b=true
  732.         for i,v in pairs(match) do
  733.             if r[i]~=nil and r[i]~=v then
  734.                 b=false
  735.                 break
  736.             end
  737.         end
  738.     until b
  739.     return r
  740. end
  741.  
  742.  
  743. -- ========= Table functions
  744. --------------------------------------------------------------------------------
  745. ---nils a table of arbitrary keys/values
  746. -- @function [parent=#utils.table] tnil
  747. -- @param table to nil
  748. function _.tnil(t)
  749.     local del=next(t)
  750.     if del then
  751.         for i,v in next,t,del do
  752.             t[del]=nil
  753.             del=i
  754.         end
  755.         t[del]=nil
  756.     end
  757. end
  758. function _.shcopy(src, dst)
  759.     dst = dst or {}
  760.     for k, v in pairs(src) do
  761.         dst[k]=v
  762.     end
  763.     return dst
  764. end
  765. --------------------------------------------------------------------------------
  766. -- Copies a table from the source to destination table.
  767. --
  768. -- The copy is recursive.
  769. --
  770. -- @function [parent=#utils.table] copy
  771. -- @param src a table to be used as the source of the copy.
  772. -- @param dst a table to be used as the destination of the copy.
  773. -- @param overwrite boolean value, to enable overwrite of existing field in dst table.
  774. -- @return the resulting dst table.
  775. --
  776. local _copy
  777. _copy=function(passed,src, dst, overwrite)
  778.     dst = dst or {}
  779.     passed[src]=dst
  780.     for k, v in pairs(src) do
  781.         if type(v) == 'table' then -- recursively go into tables
  782.             if passed[v] then
  783.                 dst[k]=passed[v]
  784.             else
  785.                 if not (type(dst[k]) == 'table') and (overwrite or dst[k]==nil) then
  786.                     dst[k] = {}
  787.                 end
  788.                 _copy(passed,v, dst[k], overwrite)
  789.             end
  790.         elseif overwrite or dst[k]==nil then dst[k] = v end
  791.     end
  792.  
  793.     return dst
  794. end
  795. _.copy=function(...) return _copy({},...) end
  796. --------------------------------------------------------------------------------
  797. -- Produces a diff of two tables.
  798. --
  799. -- Recursive diff by default.
  800. --
  801. -- @function [parent=#utils.table] diff
  802. -- @param t1 first table to compare.
  803. -- @param t2 second table to compare.
  804. -- @param norecurse boolean value to disable recursive diff.
  805. -- @return the diff result as a table.
  806. -- @usage
  807. --> t1 = { a = 1, b=3, c = "foo"}
  808. --> t2 = { a = 1, b=3, c = "foo"}
  809. --> :diff(t1, t2)
  810. --= {  }
  811. --> t1 = { a = 1, b=3, c = "foo"}
  812. --> t2 = { a = 1, b=4, c = "foo"}
  813. --> :diff(t1, t2)
  814. --= { "b" }
  815. --> t1 = { a = 1, b=3, c = "foo"}
  816. --> t2 = { a = 1, b=3}
  817. --> :diff(t1, t2)
  818. --= { "c" }
  819. --> t1 = { b=3, c = "foo", d="bar"}
  820. --> t2 = { a = 1, b=3, c = "foo"}
  821. --> :diff(t1, t2)
  822. --= {
  823. --   "a",
  824. --   "d" }
  825. --
  826.  
  827. function _.diff(t1, t2, norecurse)
  828.     local d = {}
  829.     local t3 = {}
  830.  
  831.     local rpairs = norecurse and pairs or _.recursivepairs
  832.     for k, v in rpairs(t1) do t3[k] = v end
  833.     for k, v in rpairs(t2) do
  834.         if v ~= t3[k] then table.insert(d, k) end
  835.         t3[k] = nil
  836.     end
  837.  
  838.     for k, v in pairs(t3) do table.insert(d, k) end
  839.  
  840.     return d
  841. end
  842.  
  843. --- Iterators
  844. -- @section It
  845.  
  846. --------------------------------------------------------------------------------
  847. -- Iterator that iterates on the table in key ascending order.
  848. --
  849. -- @function [parent=#utils.table] sortedPairs
  850. -- @param t table to iterate.
  851. -- @return iterator function.
  852. --
  853.  
  854. function _.sortedpairs(t)
  855.     local a = {}
  856.     local insert = table.insert
  857.     for n in pairs(t) do insert(a, n) end
  858.     table.sort(a)
  859.     local i = 0
  860.     return function()
  861.         i = i + 1
  862.         return a[i], t[a[i]]
  863.     end
  864. end
  865.  
  866. --------------------------------------------------------------------------------
  867. -- Iterator that returns key/value pairs except walking through sub tables and concatenating the path in the key.
  868. --
  869. -- This iterator break cycles: it does not recur. If it detects a cycle, the entry causing a cycle is ignored.
  870. -- However, if a table is repeated, its contents will be repeated by this function.
  871. --
  872. -- @function [parent=#utils.table] recursivePairs
  873. -- @param t table to iterate.
  874. -- @param prefix path prefix to prepend to the key path returned.
  875. -- @return iterator function.
  876. -- @usage {toto={titi=1, tutu=2}, tata = 3, tonton={4, 5}} will iterate through
  877. -- ("toto.titi",1), ("toto.tutu",2), ("tata",3) ("tonton.1", 4), ("tonton.2"=5)
  878. --
  879.  
  880. function _.recursivepairs(t, prefix)
  881.     check('table,?|string',t, prefix)
  882.     local function it(t, prefix, cp)
  883.         cp[t] = true
  884.         local pp = prefix == "" and prefix or "."
  885.         for k, v in pairs(t) do
  886.             k = pp..tostring(k)
  887.             if type(v) == 'table' then
  888.                 if not cp[v] then it(v, prefix..k, cp) end
  889.             else
  890.                 coroutine.yield(prefix..k, v)
  891.             end
  892.         end
  893.         cp[t] = nil
  894.     end
  895.  
  896.     prefix = prefix or ""
  897.     return coroutine.wrap(function() it(t, cleanpath(prefix), {}) end)
  898. end
  899.  
  900. --------------------------------------------------------------------------------
  901. -- Iterator that returns key/value on multiple tables.
  902. --
  903. -- @function [parent=#utils.map] multiPairs
  904. -- Tables are traversed in the same order as they are passed as parameters.
  905. -- @param t1 first table to traverse.
  906. -- @param ... additional tables to traverse.
  907. -- @return iterator function.
  908. --
  909.  
  910. function _.multipairs(t1, ...)
  911.     local state = { tables = {t1, ...}, i=1, k=next(t1) }
  912.     local function f()
  913.         if not state.i then return end
  914.         local current_table = state.tables[state.i]
  915.         local k, v = state.k, current_table[state.k]
  916.         local next_k = next(current_table, k)
  917.         while next_k==nil do
  918.             state.i = state.i+1
  919.             local next_table = state.tables [state.i]
  920.             if not next_table then state.i=false; break
  921.             else next_k = next (next_table) end
  922.         end
  923.         state.k = next_k
  924.         return k, current_table[k]
  925.     end
  926.     return f, nil, nil
  927. end
  928.  
  929. -- ========= Collection functions
  930.  
  931. --- Calls function `f` on each key-value of a given collection. <br/><em>Aliased as @{forEach}</em>.
  932. -- @name each
  933. -- @tparam table list a collection
  934. -- @tparam function f an iterator function, prototyped as `f(key,value,...)`
  935. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  936. -- @see forEach
  937. function _.each(list, f, ...)
  938.   if not _.isObject(list) then return end
  939.   for index,value in pairs(list) do
  940.     f(index,value,...)
  941.   end
  942.   return list
  943. end
  944.  
  945. --- Alias for @{each}.
  946. -- @function forEach
  947. -- @param list
  948. -- @param f
  949. -- @param[opt] ...
  950. _.forEach = _.each
  951.  
  952. --- Maps function `f` on each key-value of a given collection. Collects
  953. -- and returns the outputs.<br/><em>Aliased as @{collect}</em>.
  954. -- @name map
  955. -- @tparam table list a collection
  956. -- @tparam function f  an iterator function, prototyped as `f(key,value,...)`
  957. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  958. -- @treturn table a table of results
  959. -- @see collect
  960. function _.map(list, f, ...)
  961.   local _list = {}
  962.   for index,value in pairs(list) do
  963.     _list[index] = f(index,value,...)
  964.   end
  965.   return _list
  966. end
  967.  
  968. --- Alias for @{map}.
  969. -- @function collect
  970. -- @param list
  971. -- @param f
  972. -- @param[opt] ...
  973. _.collect = _.map
  974.  
  975. --- Reduces an entire collection. Folds from left to right to a single value,
  976. -- with respect to a given iterator and an initial state.
  977. -- The given function takes a state and a value, and returns a new state.
  978. -- <br/><em>Aliased as @{inject}, @{foldl}</em>.
  979. -- @name reduce
  980. -- @tparam table list a collection
  981. -- @tparam function f an iterator function, prototyped as `f(state,value)`
  982. -- @tparam[opt] state state an initial state of reduction. Defaults to the first value in the list.
  983. -- @treturn state state a final state of reduction
  984. -- @see inject
  985. -- @see foldl
  986. function _.reduce(list,f,state)
  987.   for _,value in pairs(list) do
  988.     state = not state and value or f(state,value)
  989.   end
  990.   return state
  991. end
  992.  
  993. --- Alias for @{reduce}.
  994. -- @function inject
  995. -- @param list
  996. -- @param f
  997. -- @param[opt] state
  998. _.inject = _.reduce
  999.  
  1000. --- Alias for @{reduce}.
  1001. -- @function foldl
  1002. -- @param list
  1003. -- @param f
  1004. -- @param[opt] state
  1005. _.foldl = _.reduce
  1006.  
  1007. --- Reduces an entire collection. Folds from right to left to a single value,
  1008. -- with respect to a given iterator and an initial state.
  1009. -- The given function takes a state and a value, and returns a new state.
  1010. -- <br/><em>Aliased as @{injectr}, @{foldr}</em>.
  1011. -- @name reduceRight
  1012. -- @tparam table list a collection
  1013. -- @tparam function f an iterator function, prototyped as `f(state,value)`
  1014. -- @tparam[opt] state state an initial state of reduction. Defaults to the last value in the list.
  1015. -- @treturn state state a final state of reduction
  1016. -- @see injectr
  1017. -- @see foldr
  1018. function _.reduceRight(list,f,state)
  1019.   return _.reduce(_.reverse(list),f,state)
  1020. end
  1021.  
  1022. --- Alias for @{reduceRight}.
  1023. -- @function injectr
  1024. -- @param list
  1025. -- @param f
  1026. -- @param[opt] state
  1027. _.injectr = _.reduceRight
  1028.  
  1029. --- Alias for @{reduceRight}.
  1030. -- @function foldr
  1031. -- @param list
  1032. -- @param f
  1033. -- @param[opt] state
  1034. _.foldr = _.reduceRight
  1035.  
  1036. --- Reduces a collection while saving intermediate states.
  1037. -- Folds the collection from left to right to a single value,
  1038. -- with respect to a given iterator and an initial state.
  1039. -- The given function takes a state and a value, and returns a new state.
  1040. -- The function returns an array of intermediate states.
  1041. -- <br/><em>Aliased as @{mapr}</em>
  1042. -- @name mapReduce
  1043. -- @tparam table list a collection
  1044. -- @tparam function f an iterator function, prototyped as `f(state,value)`
  1045. -- @tparam[opt] state state an initial state of reduction. Defaults to the last value in the list.
  1046. -- @treturn table an array of states
  1047. -- @see mapr
  1048. function _.mapReduce(list,f,state)
  1049.   local t = {}
  1050.   for i,value in pairs(list) do
  1051.     t[i] = not state and value or f(state,value)
  1052.     state = t[i]
  1053.   end
  1054.   return t
  1055. end
  1056.  
  1057. --- Alias for @{mapReduce}.
  1058. -- @function mapr
  1059. -- @param list
  1060. -- @param f
  1061. -- @param[opt] state
  1062. _.mapr = _.mapReduce
  1063.  
  1064. --- Reduces a collection while saving intermediate states. It proceeds in reverse order,
  1065. -- folding the collection from right to left to a single value,
  1066. -- with respect to a given iterator and an initial state.
  1067. -- The given function takes a state and a value, and returns a new state.
  1068. -- The function returns an array of intermediate states.
  1069. -- <br/><em>Aliased as @{maprr}</em>
  1070. -- @name mapReduceRight
  1071. -- @tparam table list a collection
  1072. -- @tparam function f an iterator function, prototyped as `f(state,value)`
  1073. -- @tparam[opt] state state an initial state of reduction. Defaults to the last value in the list.
  1074. -- @treturn table an array of states
  1075. -- @see maprr
  1076. function _.mapReduceRight(list,f,state)
  1077.   return _.mapReduce(_.reverse(list),f,state)
  1078. end
  1079.  
  1080. --- Alias for @{mapReduceRight}.
  1081. -- @function maprr
  1082. -- @param list
  1083. -- @param f
  1084. -- @param[opt] state
  1085. _.maprr = _.mapReduceRight
  1086.  
  1087. --- Looks for an object in a collection. <br/><em>Aliased as @{any}, @{some}</em>
  1088. -- @name include
  1089. -- @tparam table list a collection
  1090. -- @tparam object item a value to be searched
  1091. -- @treturn boolean a boolean : __true__ when found, __false__ otherwise
  1092. -- @see any
  1093. -- @see some
  1094. function _.include(list,item)
  1095.   local _iter = _.isFunction(item) and item or _.isEqual
  1096.   for _,value in pairs(list) do
  1097.     if _iter(value,item) then return true end
  1098.   end
  1099.   return false
  1100. end
  1101.  
  1102. --- Alias for @{include}.
  1103. -- @function any
  1104. -- @param list
  1105. -- @param item
  1106. _.any = _.include
  1107.  
  1108. --- Alias for @{include}.
  1109. -- @function some
  1110. -- @param list
  1111. -- @param item
  1112. _.some = _.include
  1113.  
  1114. --- Looks for an object index in a collection. <br/><em>Aliased as @{where}, @{find}</em>
  1115. -- @name detect
  1116. -- @tparam table list a collection
  1117. -- @tparam object item a value to be searched
  1118. -- @treturn key the object key or __nil__
  1119. -- @see find
  1120. -- @see where
  1121. function _.detect(list,item)
  1122.   local _iter = _.isFunction(item) and item or _.isEqual
  1123.   for key,arg in pairs(list) do
  1124.     if _iter(arg,item) then return key end
  1125.   end
  1126. end
  1127.  
  1128. --- Alias for @{detect}.
  1129. -- @function find
  1130. -- @param list
  1131. -- @param item
  1132. _.find = _.detect
  1133.  
  1134. --- Alias for @{detect}.
  1135. -- @function where
  1136. -- @param list
  1137. -- @param item
  1138. _.where = _.detect
  1139.  
  1140. --- Selects and extracts objects passing an iterator test.
  1141. -- <br/><em>Aliased as @{filter}</em>
  1142. -- @name select
  1143. -- @tparam table list a collection
  1144. -- @tparam function f an iterator function, prototyped as `f(key,value,...)`
  1145. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  1146. -- @treturn table the selected objects
  1147. -- @see filter
  1148. function _.select(list,f,...)
  1149.   local _mapped = _.map(list,f,...)
  1150.   local _list = {}
  1151.   for index,value in pairs(_mapped) do
  1152.     if value then _list[#_list+1] = list[index] end
  1153.   end
  1154.   return _list
  1155. end
  1156.  
  1157. --- Alias for @{select}.
  1158. -- @function filter
  1159. -- @param list
  1160. -- @param f
  1161. -- @param[opt] ...
  1162. _.filter = _.select
  1163.  
  1164. --- Clones a collection, rejecting objects passing an iterator test.
  1165. -- <br/><em>Aliased as @{discard}</em>
  1166. -- @name reject
  1167. -- @tparam table list a collection
  1168. -- @tparam function f an iterator function, prototyped as `f(key,value,...)`
  1169. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  1170. -- @treturn table the remaining objects
  1171. -- @see discard
  1172. function _.reject(list,f,...)
  1173.   local _mapped = _.map(list,f,...)
  1174.   local _list = {}
  1175.   for index,value in pairs (_mapped) do
  1176.     if not value then _list[#_list+1] = list[index] end
  1177.   end
  1178.   return _list
  1179. end
  1180.  
  1181. --- Alias for @{reject}.
  1182. -- @function discard
  1183. -- @param list
  1184. -- @param f
  1185. -- @param[opt] ...
  1186. _.discard = _.reject
  1187.  
  1188. --- Tests if all objects in a collection passes an iterator test. <br/><em>Aliased as @{every}</em>
  1189. -- @name all
  1190. -- @tparam table list a collection
  1191. -- @tparam function f an iterator function, prototyped as `f(key,value,...)`
  1192. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  1193. -- @treturn boolean __true__ or __false__
  1194. -- @see every
  1195. function _.all(list,f,...)
  1196.   return ((#_.select(_.map(list,f,...), isTrue)) == (#list))
  1197. end
  1198.  
  1199. --- Alias for @{all}.
  1200. -- @function every
  1201. -- @param list
  1202. -- @param f
  1203. -- @param[opt] ...
  1204. _.every = _.all
  1205.  
  1206. --- Invokes a method on each object in a collection.
  1207. -- @name invoke
  1208. -- @tparam table list a collection
  1209. -- @tparam function method a function, prototyped as `f(object,...)`
  1210. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `method`
  1211. -- @treturn table an array of results
  1212. function _.invoke(list,method,...)
  1213.   local args = {...}
  1214.   return _.map(list, function(__,v)
  1215.         if _.isObject(v) then
  1216.             if _.has(v,method) then
  1217.                 if _.isCallable(v[method]) then
  1218.                     return v[method](v,unpack(args))
  1219.                 else return v[method]
  1220.                 end
  1221.             else
  1222.                 if _.isCallable(method) then
  1223.                     return method(v,unpack(args))
  1224.                 end
  1225.             end
  1226.         elseif _.isCallable(method) then
  1227.             return method(v,unpack(args))
  1228.         end
  1229.     end)
  1230. end
  1231.  
  1232. --- Extracts property-values from a collection of objects.
  1233. -- @name pluck
  1234. -- @tparam table list a collection
  1235. -- @tparam string a property, to index in each object: `object[property]`
  1236. -- @treturn table an array of values for the specified property
  1237. function _.pluck(list,property)
  1238.   return _.reject(_.map(list,function(__,value)
  1239.       return value[property]
  1240.     end),
  1241.   iNot)
  1242. end
  1243.  
  1244. --- Returns the maximum value in a collection. If an iterator is passed, it will
  1245. -- be used to extract the property value by which all objects will be ranked.
  1246. -- @name max
  1247. -- @tparam table list a collection
  1248. -- @tparam[opt] function iter an iterator function, prototyped as `iter(value,...)`, defaults to @{identity}
  1249. -- @tparam[optchain] var_arg ... Optional extra-args to be passed to function `iter`
  1250. -- @treturn value the maximum property value found
  1251. function _.max(list,iter,...)
  1252.   return extract(list,f_max,iter,...)
  1253. end
  1254.  
  1255. --- Returns the minimum value in a collection. If an iterator is passed, it will
  1256. -- be used to extract the property value by which all objects will be ranked.
  1257. -- @name min
  1258. -- @tparam table list a collection
  1259. -- @tparam[opt] function iter an iterator function, prototyped as `iter(value,...)`, defaults to @{identity}
  1260. -- @tparam[optchain] var_arg ... Optional extra-args to be passed to function `iter`
  1261. -- @treturn value the minimum property value found
  1262. function _.min(list, iter,...)
  1263.   return extract(list,f_min, iter,...)
  1264. end
  1265.  
  1266. --- Returns a shuffled copy of a given collection. If a seed is provided, it will
  1267. -- be used to init the random number generator.
  1268. -- @name shuffle
  1269. -- @tparam table list a collection
  1270. -- @tparam[opt] number seed a seed
  1271. -- @treturn table a shuffled copy of the given collection
  1272. function _.shuffle(list,seed)
  1273.   if seed then randomseed(seed) end
  1274.   local _shuffled = {}
  1275.   _.each(list,function(index,value)
  1276.            local randPos = floor(random()*index)+1
  1277.           _shuffled[index] = _shuffled[randPos]
  1278.           _shuffled[randPos] = value
  1279.         end)
  1280.   return _shuffled
  1281. end
  1282.  
  1283. --- Tests if two collections are the same. I.e, they feature the same objects, but not
  1284. -- necessarily at the same keys
  1285. -- @name same
  1286. -- @tparam table a a collection
  1287. -- @tparam table b a collection
  1288. -- @treturn boolean __true__ or __false__
  1289. function _.same(a,b)
  1290.   return _.all(a, function (i,v)
  1291.             return _.include(b,v)
  1292.         end)
  1293.     and _.all(b, function (i,v)
  1294.             return _.include(a,v)
  1295.         end)
  1296. end
  1297.  
  1298. --- Sorts a collection. If a comparison function is given, it will be used to sort objects
  1299. -- @name sort
  1300. -- @tparam table list a collection
  1301. -- @tparam[opt] function comp a comparison function prototyped as `comp(a,b)`, defaults to <tt><</tt> operator.
  1302. -- @treturn table the given list, sorted.
  1303. function _.sort(list,comp)
  1304.   t_sort(list,comp)
  1305.   return list
  1306. end
  1307.  
  1308. --- Converts a list of __var_args__ to a collection.
  1309. -- @name toArray
  1310. -- @tparam[opt] var_arg ... Optional variable number of arguments
  1311. -- @treturn table an array of all passed-in args
  1312. function _.toArray(...)
  1313.   return {...}
  1314. end
  1315.  
  1316. --- Splits a collection into subsets. Each subset feature objects grouped by the result of passing it through an iterator.
  1317. -- If iterator is a string instead of a function, groups by the property named by iterator on each of the values.
  1318. -- @name groupBy
  1319. -- @tparam table list a collection
  1320. -- @tparam function iter an iterator function, prototyped as `iter(key,value,...)`
  1321. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `iter`
  1322. -- @treturn table a new collection with items grouped by subsets
  1323. function _.groupBy(list,iter,...)
  1324.   local var_arg = {...}
  1325.   local _list = {}
  1326.   local _iter = _.isFunction(iter) and iter
  1327.     or (_.isString(iter) and function(_,item)
  1328.         return item[iter](item,unpack(var_arg))
  1329.       end)
  1330.   if not _iter then return end
  1331.   _.each(list, function(i,v)
  1332.       local _key = _iter(i,v)
  1333.       if _list[_key] then _list[_key][#_list[_key]+1] = v
  1334.       else _list[_key] = {v}
  1335.       end
  1336.     end)
  1337.   return _list
  1338. end
  1339.  
  1340. --- Groups objects in a collection and counts them.
  1341. -- @name countBy
  1342. -- @tparam table list a collection
  1343. -- @tparam function iter an iterator function, prototyped as `iter(key,value,...)`
  1344. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `iter`
  1345. -- @treturn table a new collection with subsets names and count
  1346. function _.countBy(list,iter,...)
  1347.   local var_arg = {...}
  1348.     local stats = {}
  1349.     _.each(list,function(i,v)
  1350.             local key = iter(i,v,unpack(var_arg))
  1351.             stats[key] = (stats[key] or 0) +1
  1352.         end)
  1353.     return stats
  1354. end
  1355.  
  1356. --- Counts the number of values in a collection. If being passed more than one args
  1357. -- it will return the number of passed-in args.
  1358. -- @name size
  1359. -- @tparam[opt] var_arg ... Optional variable number of arguments
  1360. -- @treturn number a size
  1361. function _.size(...)
  1362.   local args = {...}
  1363.   local arg1 = args[1]
  1364.   if _.isNil(arg1) then
  1365.     return 0
  1366.   elseif _.isObject(arg1) then
  1367.     return count(args[1])
  1368.   else
  1369.     return count(args)
  1370.   end
  1371. end
  1372.  
  1373. --- Checks if all the keys of `other` object exists in a `list`. It does not
  1374. -- compares values. The test is not commutative, i.e `list` may contains keys
  1375. -- not existing in `other`.
  1376. -- @name containsKeys
  1377. -- @tparam table list a collection
  1378. -- @tparam table other a collection
  1379. -- @treturn boolean __true__ or __false__
  1380. function _.containsKeys(list,other)
  1381.   for key in pairs(other) do
  1382.     if not list[key] then return false end
  1383.   end
  1384.   return true
  1385. end
  1386.  
  1387. --- Checks if both given lists have the same keys. It does not compares values.
  1388. -- @name sameKeys
  1389. -- @tparam table listA a collection
  1390. -- @tparam table listB a collection
  1391. -- @treturn boolean __true__ or __false__
  1392. function _.sameKeys(listA,listB)
  1393.   _.each(listA,function(key)
  1394.       if not listB[key] then return false end
  1395.      end)
  1396.   _.each(listB,function(key)
  1397.       if not listA[key] then return false end
  1398.      end)
  1399.   return true
  1400. end
  1401.  
  1402. -- ========= Array functions
  1403.  
  1404. --- Reverses values in a given array. The passed-in array should not be sparse.
  1405. -- @name reverse
  1406. -- @tparam table array an array
  1407. -- @treturn table a copy of the given array, reversed
  1408. function _.reverse(array)
  1409.   local _array = {}
  1410.   for i = #array,1,-1 do
  1411.     _array[#_array+1] = array[i]
  1412.   end
  1413.   return _array
  1414. end
  1415.  
  1416. --- Collects values from a given array. The passed-in array should not be sparse.
  1417. -- This function collects values as long as they satisfy a given predicate.
  1418. -- Therefore, it returns on the first false test.
  1419. -- <br/><em>Aliased as @{takeWhile}</em>
  1420. -- @name selectWhile
  1421. -- @tparam table array an array
  1422. -- @tparam function f an iterator function prototyped as `f(key,value,...)`
  1423. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  1424. -- @treturn table a new table containing the first truthy values collected
  1425. -- @see takeWhile
  1426. function _.selectWhile(array,f,...)
  1427.   local t = {}
  1428.   for i,v in ipairs(array) do
  1429.     if f(i,v,...) then t[i] = v else break end
  1430.   end
  1431.   return t
  1432. end
  1433.  
  1434. --- Alias for @{selectWhile}.
  1435. -- @function takeWhile
  1436. -- @param array
  1437. -- @param f
  1438. -- @param[opt] ...
  1439. _.takeWhile = _.selectWhile
  1440.  
  1441. --- Collects values from a given array. The passed-in array should not be sparse.
  1442. -- This function collects values as soon as they do not satisfy a given predicate.
  1443. -- Therefore it returns on the first true test.
  1444. -- <br/><em>Aliased as @{rejectWhile}</em>
  1445. -- @name dropWhile
  1446. -- @tparam table array an array
  1447. -- @tparam function f an iterator function prototyped as `f(key,value,...)`
  1448. -- @tparam[opt] var_arg ... Optional extra-args to be passed to function `f`
  1449. -- @treturn table a new table containing the first falsy values collected
  1450. -- @see rejectWhile
  1451. function _.dropWhile(array, f,...)
  1452.   local _i
  1453.   for i,v in ipairs(array) do
  1454.     if not f(i,v,...) then
  1455.       _i = i
  1456.       break
  1457.     end
  1458.   end
  1459.   if _.isNil(_i) then return {} end
  1460.   return _.rest(array,_i)
  1461. end
  1462.  
  1463. --- Alias for @{dropWhile}.
  1464. -- @function rejectWhile
  1465. -- @param array
  1466. -- @param f
  1467. -- @param[opt] ...
  1468. _.rejectWhile = _.dropWhile
  1469.  
  1470. --- Returns the index at which a value should be inserted. This returned index is determined so that it maintains the sort.
  1471. -- If a comparison function is passed, it will be used to determine the sort ranking of each
  1472. -- value, including the passed-in value.
  1473. -- @name sortedIndex
  1474. -- @tparam table array an array
  1475. -- @tparam value the value to be inserted
  1476. -- @tparam[opt] function comp an comparison function prototyped as `f(a,b)`, defaults to <tt><</tt> operator
  1477. -- @tparam[optchain] boolean sort whether or not to sort the passed-in array
  1478. -- @treturn index the index at which the passed-in value should be inserted
  1479. function _.sortedIndex(array,value,comp,sort)
  1480.   local _comp = comp or f_min
  1481.   if sort then _.sort(array,_comp) end
  1482.   for i = 1,#array do
  1483.     if not _comp(array[i],value) then return i end
  1484.   end
  1485.   return #array+1
  1486. end
  1487.  
  1488. --- Returns the index of the given value in an array. If the passed-in value exists
  1489. -- more than once in the array, it will return the index of the first occurence.
  1490. -- @name indexOf
  1491. -- @tparam table array an array
  1492. -- @tparam value the value to be searched
  1493. -- @treturn index the index of the passed-in value or __nil__
  1494. function _.indexOf(array, value)
  1495.   for k = 1,#array do
  1496.     if array[k] == value then return k end
  1497.   end
  1498. end
  1499.  
  1500. --- Returns the last occurence index of a given value.
  1501. -- @name lastIndexOf
  1502. -- @tparam table array an array
  1503. -- @tparam value the value to be searched
  1504. -- @treturn index the index of the last occurence of the passed-in value or __nil__
  1505. function _.lastIndexOf(array,value)
  1506.   local key = _.indexOf(_.reverse(array),value)
  1507.   if key then return #array-key+1 end
  1508. end
  1509.  
  1510. --- Adds all passed-in values at the top of an array. The latter args will come the
  1511. -- first in the given array.
  1512. -- @name add
  1513. -- @tparam table array an array
  1514. -- @tparam var_arg ... a variable number of arguments
  1515. -- @treturn table the passed-in array
  1516. function _.add(array,...)
  1517.   _.each({...},function(i,v) t_insert(array,1,v) end)
  1518.   return array
  1519. end
  1520.  
  1521. --- Pushes all passed-in values at the end of an array.
  1522. -- @name push
  1523. -- @tparam table array an array
  1524. -- @tparam var_arg ... a variable number of arguments
  1525. -- @treturn table the passed-in array
  1526. function _.push(array,...)
  1527.   _.each({...}, function(i,v) array[#array+1] = v end)
  1528.   return array
  1529. end
  1530.  
  1531. --- Removes and returns the value at the top of a given array.
  1532. -- <br/><em>Aliased as @{shift}</em>
  1533. -- @name pop
  1534. -- @tparam table array an array
  1535. -- @treturn value the popped value
  1536. -- @see shift
  1537. function _.pop(array)
  1538.   local retValue = array[1]
  1539.   t_remove(array,1)
  1540.   return retValue
  1541. end
  1542.  
  1543. --- Alias for @{pop}.
  1544. -- @function shift
  1545. -- @param array
  1546. _.shift = _.pop
  1547.  
  1548. --- Removes and returns the value at the end of a given array.
  1549. -- @name unshift
  1550. -- @tparam table array an array
  1551. -- @treturn value the popped value
  1552. function _.unshift(array)
  1553.   local retValue = array[#array]
  1554.   t_remove(array)
  1555.   return retValue
  1556. end
  1557.  
  1558. --- Trims all values indexed within the range `[start,finish]`.
  1559. -- <br/><em>Aliased as @{rmRange}</em>
  1560. -- @name removeRange
  1561. -- @tparam table array an array
  1562. -- @tparam[opt] index start the lower bound index, defaults to the first index in the array.
  1563. -- @tparam[optchain] index finish the upper bound index, defaults to the array length.
  1564. -- @treturn table the passed-in array
  1565. -- @see rmRange
  1566. function _.removeRange(array,start,finish)
  1567.   local array = _.clone(array)
  1568.   local i,n = (next(array)),#array
  1569.   if n < 1 then return array end
  1570.  
  1571.   start = clamp(start or i,i,n)
  1572.   finish = clamp(finish or n,i,n)
  1573.  
  1574.   if finish < start then return array end
  1575.  
  1576.   local count = finish - start + 1
  1577.   local i = start
  1578.   while count > 0 do
  1579.     t_remove(array,i)
  1580.     count = count - 1
  1581.   end
  1582.   return array
  1583. end
  1584.  
  1585. --- Alias for @{removeRange}.
  1586. -- @function rmRange
  1587. -- @param array
  1588. -- @param[opt] start
  1589. -- @param[optchain] finish
  1590. _.rmRange = _.removeRange
  1591.  
  1592. --- Slices values indexed within `[start,finish]` range.
  1593. -- @name slice
  1594. -- @tparam table array an array
  1595. -- @tparam[opt] index start the lower bound index, defaults to the first index in the array.
  1596. -- @tparam[optchain] index finish the upper bound index, defaults to the array length.
  1597. -- @treturn table a new array
  1598. function _.slice(array,start,finish)
  1599.   return _.select(array, function(index)
  1600.       return (index >= (start or next(array)) and index <= (finish or #array))
  1601.     end)
  1602. end
  1603.  
  1604. --- Returns the first N values in an array. <br/><em>Aliased as @{head}, @{take}</em>
  1605. -- @name first
  1606. -- @tparam table array an array
  1607. -- @tparam[opt] number n the number of values to be collected, defaults to 1.
  1608. -- @treturn table a new array
  1609. -- @see head
  1610. -- @see take
  1611. function _.first(array,n)
  1612.   local n = n or 1
  1613.   return _.slice(array,1, min(n,#array))
  1614. end
  1615.  
  1616. --- Alias for @{first}.
  1617. -- @function head
  1618. -- @param array
  1619. -- @param[opt] n
  1620. _.head = _.first
  1621.  
  1622. --- Alias for @{first}.
  1623. -- @function take
  1624. -- @param array
  1625. -- @param[opt] n
  1626. _.take = _.first
  1627.  
  1628. --- Returns all values in an array excluding the last N values.
  1629. -- @name initial
  1630. -- @tparam table array an array
  1631. -- @tparam[opt] number n the number of values to be left, defaults to the array length.
  1632. -- @treturn table a new array
  1633. function _.initial(array,n)
  1634.   if n and n < 0 then return end
  1635.   return _.slice(array,1, n and #array-(min(n,#array)) or #array-1)
  1636. end
  1637.  
  1638. --- Returns the last N values in an array.
  1639. -- @name last
  1640. -- @tparam table array an array
  1641. -- @tparam[opt] number n the number of values to be collected, defaults to the array length.
  1642. -- @treturn table a new array
  1643. function _.last(array,n)
  1644.   if n and n <= 0 then return end
  1645.   return _.slice(array,n and #array-min(n-1,#array-1) or 2,#array)
  1646. end
  1647.  
  1648. --- Trims all values before index. <br/><em>Aliased as @{tail}</em>
  1649. -- @name rest
  1650. -- @tparam table array an array
  1651. -- @tparam[opt] index index an index, defaults to 1
  1652. -- @treturn table a new array
  1653. -- @see tail
  1654. function _.rest(array,index)
  1655.   if index and index > #array then return {} end
  1656.   return _.slice(array,index and max(1,min(index,#array)) or 1,#array)
  1657. end
  1658.  
  1659. --- Alias for @{rest}.
  1660. -- @function tail
  1661. -- @param array
  1662. -- @param[opt] index
  1663. _.tail = _.rest
  1664.  
  1665. --- Trims all falsy values.
  1666. -- @name compact
  1667. -- @tparam table array an array
  1668. -- @treturn table a new array
  1669. function _.compact(array)
  1670.   return _.reject(array, function (_,value)
  1671.         return not value
  1672.     end)
  1673. end
  1674.  
  1675. --- Flattens a nested array. Passing `shallow` will only flatten at the first single level.
  1676. -- @name flatten
  1677. -- @tparam table array an array
  1678. -- @tparam[opt] boolean shallow specifies the flattening depth
  1679. -- @treturn table a new array, flattened
  1680. function _.flatten(array, shallow)
  1681.   local shallow = shallow or false
  1682.   local new_flattened
  1683.   local _flat = {}
  1684.   for key,value in pairs(array) do
  1685.     if _.isObject(value) and not shallow then
  1686.       new_flattened = _.flatten (value)
  1687.       _.each(new_flattened, function(_,item) _flat[#_flat+1] = item end)
  1688.     else _flat[#_flat+1] = value
  1689.     end
  1690.   end
  1691.   return _flat
  1692. end
  1693.  
  1694. --- Returns values from an array not present in all passed-in args. <br/><em>Aliased as @{without}</em>
  1695. -- @name difference
  1696. -- @tparam table array an array
  1697. -- @tparam var_arg ... a variable number of arguments
  1698. -- @treturn table a new array
  1699. -- @see without
  1700. function _.difference(array,...)
  1701.   local values = _.toArray(...)
  1702.   return _.select(array,function(i,value)
  1703.       return not _.include(values,value)
  1704.     end)
  1705. end
  1706.  
  1707. --- Alias for @{difference}.
  1708. -- @function without
  1709. -- @param array
  1710. -- @param ...
  1711. _.without = _.difference
  1712.  
  1713. --- Produces a duplicate-free version of a given array. Passing `isSorted` will
  1714. -- provide a much faster version, but will produce the desired result if the array
  1715. -- is properly sorted. If `iter` is passed, it will be used to compute new values based on
  1716. -- a transformation.
  1717. -- <br/><em>Aliased as @{unique}</em>
  1718. -- @name uniq
  1719. -- @tparam table array an array
  1720. -- @tparam[opt] boolean isSorted whether or not the passed-in array is already sorted, defaults to `false`
  1721. -- @tparam[optchain] function iter an iterator function prototyped as `iter(key,value,...)`
  1722. -- @tparam[optchain] var_arg ... Optional extra-args to be passed to `iter` function
  1723. -- @treturn table a new array
  1724. -- @see unique
  1725. function _.uniq(array,isSorted,iter,...)
  1726.   local init = iter and _.map(array,iter,...) or array
  1727.   local result = {}
  1728.   if not isSorted then
  1729.     for __,v in ipairs(init) do
  1730.       if not _.include(result,v) then
  1731.         result[#result+1] = v
  1732.         end
  1733.     end
  1734.   return result
  1735.   end
  1736.  
  1737.   result[#result+1] = init[1]
  1738.   for i = 2,#init do
  1739.     if init[i] ~= result[#result] then
  1740.         result[#result+1] = init[i]
  1741.     end
  1742.   end
  1743.   return result
  1744. end
  1745.  
  1746. --- Alias for @{uniq}.
  1747. -- @function unique
  1748. -- @param array
  1749. -- @param[opt] isSorted
  1750. -- @param[optchain] iter
  1751. -- @param[optchain] ...
  1752. _.unique = _.uniq
  1753.  
  1754. --- Returns the duplicate-free union of all passed in arrays.
  1755. -- @name union
  1756. -- @tparam var_arg ... a variable number of arrays arguments
  1757. -- @treturn table a new array
  1758. function _.union(...)
  1759.   return _.uniq(_.flatten({...}))
  1760. end
  1761.  
  1762. --- Returns the  intersection of all passed-in arrays.
  1763. -- Each value in the result is present in each of the passed-in arrays.
  1764. -- @name intersection
  1765. -- @tparam table array an array
  1766. -- @tparam var_arg ... a variable number of array arguments
  1767. -- @treturn table a new array
  1768. function _.intersection(array,...)
  1769.   local arg = {...}
  1770.   local _intersect = {}
  1771.   for i,value in ipairs(array) do
  1772.     if _.all(arg,function(i,v)
  1773.           return _.include(v,value)
  1774.         end) then
  1775.       t_insert(_intersect,value)
  1776.     end
  1777.   end
  1778.   return _intersect
  1779. end
  1780.  
  1781. --- Merges values of each of the passed-in arrays in subsets.
  1782. -- Only values at the same position in the initial array are merged.
  1783. -- @name zip
  1784. -- @tparam var_arg ... a variable number of array arguments
  1785. -- @treturn table a new array
  1786. function _.zip(...)
  1787.   local arg = {...}
  1788.   local _len = _.max(_.map(arg,function(i,v)
  1789.       return #v
  1790.     end))
  1791.   local _ans = {}
  1792.   for i = 1,_len do
  1793.     _ans[i] = _.pluck(arg,i)
  1794.   end
  1795.   return _ans
  1796. end
  1797.  
  1798. --- Clones `array` and appends `other` to the result.
  1799. -- @name append
  1800. -- @tparam table array an array
  1801. -- @tparam table other an array
  1802. -- @treturn table a new array
  1803. function _.append(array,other)
  1804.   local t = {}
  1805.   for i,v in ipairs(array) do t[i] = v end
  1806.   for i,v in ipairs(other) do t[#t+1] = v end
  1807.   return t
  1808. end
  1809.  
  1810. --- Produce a flexible list of numbers. If one positive value is passed, will count from 0 to that value,
  1811. -- with a default step of 1. If two values were passed, will count from the first one to the second one, with the
  1812. -- same default step of 1. A third passed value will be considered a step value.
  1813. -- <br/><em>Aliased as @{count}</em>
  1814. -- @name range
  1815. -- @tparam var_arg ... a variable list of numbers
  1816. -- @treturn table a new array of numbers
  1817. -- @see count
  1818. function _.range(...)
  1819.   local arg = {...}
  1820.   local _start,_stop,_step
  1821.   if #arg==0 then return {}
  1822.   elseif #arg==1 then _stop,_start,_step = arg[1],0,1
  1823.   elseif #arg==2 then _start,_stop,_step = arg[1],arg[2],1
  1824.   elseif #arg == 3 then _start,_stop,_step = arg[1],arg[2],arg[3]
  1825.   end
  1826.   if (_step and _step==0) then return {} end
  1827.   local _ranged = {}
  1828.   local _steps = max(floor((_stop-_start)/_step),0)
  1829.   for i=1,_steps do _ranged[#_ranged+1] = _start+_step*i end
  1830.   if #_ranged>0 then t_insert(_ranged,1,_start) end
  1831.   return _ranged
  1832. end
  1833.  
  1834. --- Alias for @{range}.
  1835. -- @function count
  1836. -- @param ...
  1837. _.count = _.range
  1838.  
  1839. --- Inverts `key-value` pairs. Keys becomes values, while values becomes keys.
  1840. -- <br/><em>Aliased as @{mirror}</em>
  1841. -- @name invert
  1842. -- @tparam table array a given array
  1843. -- @treturn table a new array
  1844. -- @see mirror
  1845. function _.invert(array)
  1846.   local _ret = {}
  1847.   _.each(array,function(i,v) _ret[v] = i end)
  1848.   return _ret
  1849. end
  1850.  
  1851. --- Alias for @{invert}.
  1852. -- @function mirror
  1853. -- @param array
  1854. _.mirror = _.invert
  1855.  
  1856. --- Concatenates values in a given array. Handles booleans as well. If `sep` string is
  1857. -- passed, it will be used as a separator. Optional `i` and `j` will only concatenate
  1858. -- values within `[i,j]` range. <br/><em>Aliased as @{join}</em>
  1859. -- @name concat
  1860. -- @tparam table array a given array
  1861. -- @tparam[opt] string sep a separator string, defaults to `''`.
  1862. -- @tparam[optchain] number i the starting index, defaults to 1.
  1863. -- @tparam[optchain] number j the final index, defaults to the array length.
  1864. -- @treturn string a string
  1865. -- @see join
  1866. function _.concat(array,sep,i,j)
  1867.   local _array = _.map(array,function(i,v)
  1868.         return tostring(v)
  1869.     end)
  1870.     return t_concat(_array,sep,i,j)
  1871.  
  1872. end
  1873.  
  1874. --- Alias for @{concat}.
  1875. -- @function join
  1876. -- @param array
  1877. -- @param[opt] sep
  1878. -- @param[optchain] i
  1879. -- @param[optchain] j
  1880. _.join = _.concat
  1881.  
  1882. -- ========= Utility functions
  1883.  
  1884. --- Returns the passed-in value. Used internally as a default iterator.
  1885. -- @name identity
  1886. -- @tparam arg value a value
  1887. -- @treturn arg the passed-in value
  1888. function _.identity(...)
  1889.   return ...
  1890. end
  1891.  
  1892. --- Returns a version of `f` that runs only once. Successive calls will make `f`
  1893. -- keep yielding the same answer, no matter what the passed-in arguments are. Can be used to
  1894. -- init variables as well.
  1895. -- @name once
  1896. -- @tparam function f a function
  1897. -- @treturn function a new function
  1898. function _.once(f)
  1899.   local _internal = 0
  1900.   local _args = {}
  1901.   return function(...)
  1902.       _internal = _internal+1
  1903.       if _internal<=1 then _args = {...} end
  1904.       return f(unpack(_args))
  1905.     end
  1906. end
  1907.  
  1908. --- Memoizes a given function by caching the computed result.
  1909. -- Useful for speeding up slow-running functions. If function `hash` is passed,
  1910. -- it will be used to compute unique keys from args passed to `hash` for results caching.
  1911. -- <br/><em>Aliased as @{cache}</em>
  1912. -- @name memoize
  1913. -- @tparam function f a function
  1914. -- @tparam[opt] function hash a hash function, defaults to @{identity}
  1915. -- @treturn function a new function
  1916. -- @see cache
  1917. function _.memoize(f,hash)
  1918.   local _cache = setmetatable({},{__mode = 'kv'})
  1919.   local _hasher = hash or _.identity
  1920.   return function (...)
  1921.       local _hashKey = _hasher(...)
  1922.       local _result = _cache[_hashKey]
  1923.       if not _result then _cache[_hashKey] = f(...) end
  1924.       return _cache[_hashKey]
  1925.     end
  1926. end
  1927.  
  1928. --- Alias for @{memoize}.
  1929. -- @function cache
  1930. -- @param f
  1931. -- @param[opt] hash
  1932. _.cache = _.memoize
  1933.  
  1934. --- Returns a version of `f` that runs on the `count-th` call.
  1935. -- Useful when dealing with asynchronous tasks.
  1936. -- @name after
  1937. -- @tparam function f a function
  1938. -- @tparam number count the number of calls before `f` answers
  1939. -- @treturn function a new function
  1940. function _.after(f,count)
  1941.   local _limit,_internal = count, 0
  1942.   return function(...)
  1943.       _internal = _internal+1
  1944.       if _internal >= _limit then return f(...) end
  1945.     end
  1946. end
  1947.  
  1948. --- Composes functions. Each passed-in function consumes the return value of the function that follows.
  1949. -- In math terms, composing the functions `f`, `g`, and `h` produces `f(g(h(...)))`.
  1950. -- @name compose
  1951. -- @tparam var_arg ... a variable number of functions
  1952. -- @treturn function a new function
  1953. function _.compose(...)
  1954.   local f = _.reverse {...}
  1955.   return function (...)
  1956.       local _temp
  1957.       for i,func in pairs(f) do
  1958.         _temp = _temp and func(_temp) or func(...)
  1959.       end
  1960.       return _temp
  1961.     end
  1962. end
  1963.  
  1964. --- Wraps `f` inside of the `wrapper` function. It passes `f` as the first argument to `wrapper`.
  1965. -- This allows the wrapper to execute code before and after `f` runs,
  1966. -- adjust the arguments, and execute it conditionally.
  1967. -- @name wrap
  1968. -- @tparam function f a function to be wrapped, prototyped as `f(...)`
  1969. -- @tparam function wrapper a wrapper function, prototyped as `wrapper(f,...)`
  1970. -- @treturn function a new function
  1971. function _.wrap(f,wrapper)
  1972.     return function (...)
  1973.       return  wrapper(f,...)
  1974.     end
  1975. end
  1976.  
  1977. --- Runs `iter` function `n` times.
  1978. -- Collects the results of each run and returns them in an array.
  1979. -- @name times
  1980. -- @tparam number n the number of times `iter` should be called
  1981. -- @tparam function iter an iterator function, prototyped as `iter(i,...)`
  1982. -- @tparam var_arg ... extra-args to be passed to `iter` function
  1983. -- @treturn table an array of results
  1984. function _.times(n,iter,...)
  1985.   local results = {}
  1986.   for i = 1,n do
  1987.     results[i] = iter(i,...)
  1988.   end
  1989.   return results
  1990. end
  1991.  
  1992. --- Binds `v` to be the first argument to function `f`. As a result,
  1993. -- calling `f(...)` will result to `f(v,...)`.
  1994. -- @name bind
  1995. -- @tparam function f a function
  1996. -- @tparam arg v an argument
  1997. -- @treturn function a function, prototyped as `f(v,...)`
  1998. function _.bind(f,v)
  1999.   return function (...)
  2000.       return f(v,...)
  2001.     end
  2002. end
  2003.  
  2004. --- Binds `...` to be the N-first arguments to function `f`. As a result,
  2005. -- calling `f(a1,a2,...,aN)` will result to `f(...,a1,a2,...,aN)`.
  2006. -- @name bindn
  2007. -- @tparam function f a function
  2008. -- @tparam var_arg ... a variable numer of arguments
  2009. -- @treturn function a function, prototyped as `f(v,...)`
  2010. function _.bindn(f,...)
  2011.   local iArg = {...}
  2012.   return function (...)
  2013.       return f(unpack(_.append(iArg,{...})))
  2014.     end
  2015. end
  2016.  
  2017. --- Generates a unique Id (unique for the current session). If given a sring `template`
  2018. -- will use this template for output formatting. Otherwise, if `template` is a function,
  2019. -- will compute an output running `template(id,...)`.
  2020. -- <br/><em>Aliased as @{uId}</em>.
  2021. -- @name uniqueId
  2022. -- @tparam[opt] string|function template either a string or a function
  2023. -- @tparam[optchain] var_arg ... a variable numer of arguments to be passed to `template`, in case it is a function.
  2024. -- @treturn id a formatted Id
  2025. -- @see uId
  2026. function _.uniqueId(template,...)
  2027.     unique_id_counter = unique_id_counter + 1
  2028.     if template then
  2029.         if _.isString(template) then
  2030.             return template:format(unique_id_counter)
  2031.         elseif _.isFunction(template) then
  2032.             return template(unique_id_counter,...)
  2033.         end
  2034.     end
  2035.     return unique_id_counter
  2036. end
  2037.  
  2038. --- Alias for @{uniqueId}.
  2039. -- @function uId
  2040. -- @param[opt] template
  2041. -- @param[optchain] ...
  2042. _.uId = _.uniqueId
  2043.  
  2044. -- ========= Object functions
  2045.  
  2046. --- Returns the names of the object properties.
  2047. -- @name keys
  2048. -- @tparam table obj an object
  2049. -- @treturn table an array
  2050. function _.keys(obj)
  2051.   local _oKeys = {}
  2052.   _.each(obj,function(key,_) _oKeys[#_oKeys+1]=key end)
  2053.   return _oKeys
  2054. end
  2055.  
  2056. --- Returns the values of the object properties.
  2057. -- @name values
  2058. -- @tparam table obj an object
  2059. -- @treturn table an array
  2060. function _.values(obj)
  2061.   local _oValues = {}
  2062.   _.each(obj,function(_,value) _oValues[#_oValues+1]=value end)
  2063.   return _oValues
  2064. end
  2065.  
  2066. --- Returns an array of `obj` key-values pairs
  2067. -- @name pairs
  2068. -- @tparam table obj an object
  2069. -- @treturn table an array
  2070. function _.pairs(obj)
  2071.   local paired= {}
  2072.   _.each(obj,function(k,v)
  2073.         paired[#paired+1] = {k,v}
  2074.     end)
  2075.     return paired
  2076. end
  2077.  
  2078. --- Extends an object properties. It copies all of the properties of extra passed-in objects
  2079. -- over to the destination object, and returns the destination object.
  2080. -- The last object in `...` will override properties of the same name in the previous one
  2081. -- @name extend
  2082. -- @tparam table destObj a destination object
  2083. -- @tparam var_arg ... a variable number of array arguments
  2084. -- @treturn table the destination object extended
  2085. function _.extend(destObj,...)
  2086.     local sources = {...}
  2087.     _.each(sources,function(__,source)
  2088.         if _.isObject(source) then
  2089.             _.each(source,function(key,value)
  2090.                 destObj[key] = value
  2091.             end)
  2092.         end
  2093.     end)
  2094.     return destObj
  2095. end
  2096.  
  2097. --- Returns a sorted list of all methods names found in an object. If the given object
  2098. -- has a metatable implementing an `__index` field pointing to another table, will also recurse on this
  2099. -- table. If `output` is provided, will export results in this table.
  2100. -- <br/><em>Aliased as @{methods}</em>.
  2101. -- @name functions
  2102. -- @tparam table obj an object
  2103. -- @tparam[opt] table output Optional table to collect the results
  2104. -- @treturn table an array of methods names
  2105. -- @see methods
  2106. function _.functions(obj,output)
  2107.   if not obj then return _.sort(_.keys(_)) end
  2108.   local _methods = output or {}
  2109.   _.each(obj,function(key,value)
  2110.       if _.isFunction(value) then
  2111.         _methods[#_methods+1]=key
  2112.       end
  2113.     end)
  2114.     local mt = getmetatable(obj)
  2115.     if mt and mt.__index then
  2116.         _.functions(mt.__index,_methods)
  2117.     end
  2118.    return _.sort(_methods)
  2119. end
  2120.  
  2121. --- Alias for @{functions}.
  2122. -- @function methods
  2123. -- @param obj
  2124. -- @param[opt] output
  2125. _.methods = _.functions
  2126.  
  2127. --- Clones a given object properties. If `shallow` is passed
  2128. -- will also clone nested array properties.
  2129. -- @name clone
  2130. -- @tparam table obj an object
  2131. -- @tparam[opt] boolean shallow whether or not nested array-properties should be cloned, defaults to false.
  2132. -- @treturn table a clone of the passed-in object
  2133. function _.clone(obj,shallow)
  2134.     if not _.isObject(obj) then return obj end
  2135.   local _obj = {}
  2136.   _.each(obj,function(i,v)
  2137.     if _.isObject(v) then
  2138.       if not shallow then
  2139.         _obj[i] = _.clone(v,shallow)
  2140.       else _obj[i] = v
  2141.       end
  2142.     else
  2143.         _obj[i] = v
  2144.     end
  2145.   end)
  2146.   return _obj
  2147. end
  2148.  
  2149. --- Checks if a given object implements a property.
  2150. -- @name has
  2151. -- @tparam table obj an object
  2152. -- @tparam key key a key property to be checked
  2153. -- @treturn boolean __true__ or __false__
  2154. function _.has(obj, key)
  2155.   return obj[key]~=nil
  2156. end
  2157.  
  2158. --- Return a filtered copy of the object. The returned object will only have
  2159. -- the whitelisted properties. <br/><em>Aliased as @{choose}</em>.
  2160. -- @name pick
  2161. -- @tparam table obj an object
  2162. -- @tparam var_arg ... a variable number of string keys
  2163. -- @treturn table the filtered object
  2164. -- @see choose
  2165. function _.pick(obj, ...)
  2166.     local whitelist = _.flatten {...}
  2167.     local _picked = {}
  2168.     _.each(whitelist,function(key,property)
  2169.             if obj[property] then
  2170.                 _picked[property] = obj[property]
  2171.             end
  2172.         end)
  2173.     return _picked
  2174. end
  2175.  
  2176. --- Alias for @{pick}.
  2177. -- @function choose
  2178. -- @param obj
  2179. -- @param ...
  2180. _.choose = _.pick
  2181.  
  2182. --- Return a filtered copy of the object. The returned object will not have
  2183. -- the blacklisted properties. <br/><em>Aliased as @{drop}</em>.
  2184. -- @name omit
  2185. -- @tparam table obj an object
  2186. -- @tparam var_arg ... a variable number of string keys
  2187. -- @treturn table the filtered object
  2188. -- @see drop
  2189. function _.omit(obj,...)
  2190.     local blacklist = _.flatten {...}
  2191.     local _picked = {}
  2192.     _.each(obj,function(key,value)
  2193.             if not _.include(blacklist,key) then
  2194.                 _picked[key] = value
  2195.             end
  2196.         end)
  2197.     return _picked
  2198. end
  2199.  
  2200. --- Alias for @{omit}.
  2201. -- @function drop
  2202. -- @param obj
  2203. -- @param ...
  2204. _.drop = _.omit
  2205.  
  2206. --- Fills nil properties in an object with the given `template` object. Pre-existing
  2207. -- properties will be preserved. <br/><em>Aliased as @{defaults}</em>.
  2208. -- @name template
  2209. -- @tparam table obj an object
  2210. -- @tparam table template a template object
  2211. -- @treturn table the passed-in object filled
  2212. -- @see defaults
  2213. function _.template(obj,template)
  2214.   _.each(template,function(i,v)
  2215.     if not obj[i] then
  2216.         obj[i] = v
  2217.     end
  2218.   end)
  2219.   return obj
  2220. end
  2221.  
  2222. --- Alias for @{template}.
  2223. -- @function defaults
  2224. -- @param obj
  2225. -- @param template
  2226. _.defaults = _.template
  2227.  
  2228. --- Performs an equality test between two objects.
  2229. -- Can compare strings, functions (by reference), nil, booleans. Compares tables by reference or by component-values.
  2230. -- Comparing objects, if `useMt` is passed, the equality operator `==` will be used if one of
  2231. -- the given objects has a metatable implementing `mt.__eq`
  2232. -- @name isEqual
  2233. -- @tparam table objA an object
  2234. -- @tparam table objB another object
  2235. -- @tparam[opt] boolean useMt whether or not `mt.__eq` should be used, defaults to false.
  2236. -- @treturn boolean __true__ or __false__
  2237. function _.isEqual(objA,objB,useMt)
  2238.     local typeObjA = type(objA)
  2239.     local typeObjB = type(objB)
  2240.   if typeObjA~=typeObjB then return false end
  2241.   if typeObjA~='table' then return (objA==objB) end
  2242.  
  2243.   local mtA = getmetatable(objA)
  2244.   local mtB = getmetatable(objB)
  2245.  
  2246.   if useMt then
  2247.     if mtA or mtB and mtA.__eq or mtB.__eq then
  2248.         return (objA==objB)
  2249.     end
  2250.   end
  2251.  
  2252.   if _.size(objA)~=_.size(objB) then return false end
  2253.  
  2254.   for i,v1 in pairs(objA) do
  2255.     local v2 = objB[i]
  2256.     if _.isNil(v2) or not _.isEqual(v1,v2,useMt) then return false end
  2257.   end
  2258.  
  2259.   for i,v1 in pairs(objB) do
  2260.     local v2 = objA[i]
  2261.     if _.isNil(v2) then return false end
  2262.   end
  2263.  
  2264.   return true
  2265. end
  2266.  
  2267. --- Invokes an object method. It passes the object itself as the first argument. if `method` is not
  2268. -- callable, will return `obj[method]`.
  2269. -- @name result
  2270. -- @tparam table obj an object
  2271. -- @tparam string method a string key to index in object `obj`.
  2272. -- @tparam[opt] var_arg ... Optional extra-args to be passed to `method`
  2273. -- @treturn value the returned value of `method(obj,...)` call
  2274. function _.result(obj,method,...)
  2275.   if obj[method] then
  2276.     if _.isCallable(obj[method]) then
  2277.       return obj[method](obj,...)
  2278.     else return obj[method]
  2279.     end
  2280.   end
  2281.   if _.isCallable(method) then
  2282.     return method(obj,...)
  2283.   end
  2284. end
  2285.  
  2286. --- Checks if the given arg is an object (i.e a Lua table).
  2287. -- @name isObject
  2288. -- @tparam object obj an object
  2289. -- @treturn boolean __true__ or __false__
  2290. function _.isObject(obj)
  2291.   return type(obj) == 'table'
  2292. end
  2293.  
  2294. --- Checks if the given arg is an callable. Assumes `obj` is callable if
  2295. -- it is either a function or a table having a metatable implementing `__call` metamethod.
  2296. -- @name isCallable
  2297. -- @tparam object obj an object
  2298. -- @treturn boolean __true__ or __false__
  2299. function _.isCallable(obj)
  2300.   return (_.isFunction(obj) or
  2301.          (_.isObject(obj) and getmetatable(obj)
  2302.                              and getmetatable(obj).__call~=nil) or false)
  2303. end
  2304.  
  2305. --- Checks if the given arg is an array. Assumes `obj` is an array
  2306. -- if is a table with integer numbers as indexes.
  2307. -- @name isArray
  2308. -- @tparam object obj an object
  2309. -- @treturn boolean __true__ or __false__
  2310. function _.isArray(obj)
  2311.     if not _.isObject(obj) then return false end
  2312.     return _.all(_.keys(obj),function(i,v)
  2313.             return _.isNumber(v) and (floor(v)==v)
  2314.         end)
  2315. end
  2316.  
  2317. --- Checks if the given is empty. If `obj` is a @{string}, will return __true__
  2318. -- if `#obj==0`. Otherwise, if `obj` is a table, will return whether or not this table
  2319. -- is empty.
  2320. -- @name isEmpty
  2321. -- @tparam object obj an object
  2322. -- @treturn boolean __true__ or __false__
  2323. function _.isEmpty(obj)
  2324.     if _.isString(obj) then return #obj==0 end
  2325.     if _.isObject(obj) then return next(obj)==nil end
  2326.     return true
  2327. end
  2328.  
  2329. --- Checks if the given arg is a @{string}.
  2330. -- @name isString
  2331. -- @tparam object obj an object
  2332. -- @treturn boolean __true__ or __false__
  2333. function _.isString(obj)
  2334.   return type(obj) == 'string'
  2335. end
  2336.  
  2337. --- Checks if the given arg is a function.
  2338. -- @name isFunction
  2339. -- @tparam object obj an object
  2340. -- @treturn boolean __true__ or __false__
  2341. function _.isFunction(obj)
  2342.    return type(obj) == 'function'
  2343. end
  2344.  
  2345. --- Checks if the given arg is nil.
  2346. -- @name isNil
  2347. -- @tparam object obj an object
  2348. -- @treturn boolean __true__ or __false__
  2349. function _.isNil(obj)
  2350.     return obj==nil
  2351. end
  2352.  
  2353. --- Checks if the given arg is a finite number.
  2354. -- @name isFinite
  2355. -- @tparam object obj a number
  2356. -- @treturn boolean __true__ or __false__
  2357. function _.isFinite(obj)
  2358.     if not _.isNumber(obj) then return false end
  2359.     return obj > -huge and obj < huge
  2360. end
  2361.  
  2362. --- Checks if the given arg is a number.
  2363. -- @name isNumber
  2364. -- @tparam object obj a number
  2365. -- @treturn boolean __true__ or __false__
  2366. function _.isNumber(obj)
  2367.     return type(obj) == 'number'
  2368. end
  2369.  
  2370. --- Checks if the given arg is NaN (see [Not-A-Number](http://en.wikipedia.org/wiki/NaN)).
  2371. -- @name isNaN
  2372. -- @tparam object obj a number
  2373. -- @treturn boolean __true__ or __false__
  2374. function _.isNaN(obj)
  2375.   return _.isNumber(obj) and obj~=obj
  2376. end
  2377.  
  2378. --- Checks if the given arg is a boolean.
  2379. -- @name isBoolean
  2380. -- @tparam object obj a boolean
  2381. -- @treturn boolean __true__ or __false__
  2382. function _.isBoolean(obj)
  2383.   return type(obj) == 'boolean'
  2384. end
  2385.  
  2386. --- Imports all library functions in the global environment. <br/><em>Aliased as @{mixin}</em>
  2387. -- @name import
  2388. -- @see mixin
  2389. local function import()
  2390.   local fn = _.functions()
  2391.   local env = getfenv()
  2392.   _.each(fn,function(i,fName)
  2393.     env[fName] = _[fName]
  2394.   end)
  2395. end
  2396.  
  2397. --- Alias for @{import}.
  2398. -- @function mixin
  2399. local mixin = import
  2400.  
  2401. local _mt = {import = import, mixin = mixin}
  2402. _mt.__index = _mt
  2403. return setmetatable (_, _mt)]===================],"CoolisOS/bin/kernel/checker",true,"CoolisOS/bin/kernel/checker/init.lua",[===================[local classname=require'kernel.class'.classname
  2404. custom={}
  2405.  
  2406. function conforms(t,a)
  2407.     local k=t:sub(1, 1)
  2408.     return t == "?"
  2409.     or (k == "?" and (a==nil or conforms(t:sub(2, -1),a)))
  2410.     or (k == "!" and not (conforms(t:sub(2, -1),a)))
  2411.     or type(a)==t
  2412.     or classname(a) == t
  2413.     or (custom[t] and custom[t](a))
  2414. end
  2415.  
  2416. function check_one(d,a)
  2417.     for t in d:gmatch('|?([^|]+)|?') do
  2418.         if conforms(t,a) then return true end
  2419.     end
  2420.     return false
  2421. end
  2422. function check(s,...)
  2423.     if type(s)~='string' then error('arg1 is not of type string',2) end
  2424.     local i=0
  2425.     for typ in s:gmatch(',?([^,]+),?') do
  2426.         i=i+1
  2427.         if not check_one(typ,select(i,...)) then
  2428.             local msg=string.format(
  2429.             'arg%d:(%s) is not of type (%s);\n args=%s',
  2430.             i,tostring((debug and debug.getinfo or type)((select(i,...)))),typ,
  2431.             (debug.args_tostring(...)))
  2432.             error(msg,3)
  2433.         end
  2434.     end
  2435. end]===================],"CoolisOS/bin/kernel/class",true,"CoolisOS/bin/kernel/class/Box.lua",[===================[include'kernel.class'
  2436. local Opt=require'kernel.class.Opt'
  2437. local compat=require'kernel.compat'
  2438. local check=require'kernel.checker'.check
  2439. local pipe=sched.pipe
  2440. class.Box()
  2441. Box.token={}
  2442. do
  2443.     local def=Opt{
  2444.     pin=Opt(pipe),
  2445.     pout=Opt(pipe),
  2446.     perr=Opt(pipe),
  2447.     cc=false,
  2448.     terminal=Opt(nil),
  2449.     env=Opt(function()
  2450.         local env=util.shcopy(_G)
  2451.         env._G=env
  2452.         return env
  2453.     end)
  2454.     }
  2455.     function Box:__init(opt)
  2456.         def:drop(self,opt)
  2457.         self.env[Box.token]=self
  2458.         self.env._BOX=self
  2459.         if self.terminal then
  2460.             self.env.write=function(...)
  2461.                 return self.terminal:write(...)
  2462.             end
  2463.             self.env.read=function(...)
  2464.                 return self.terminal:read(...)
  2465.             end
  2466.             self.env.printError=function(s)
  2467.                 return debug.printError(s,self.terminal)
  2468.             end
  2469.             self.env.term=self.terminal.term
  2470.         else
  2471.             self.env.print=function(s)
  2472.                 self.pout:send(tostring(s))
  2473.             end
  2474.             self.env.write=function(s)
  2475.                 self.pout:send(s)
  2476.             end
  2477.             self.env.read=function()
  2478.                 self.pin:receive()
  2479.             end
  2480.             self.env.printError=function(s)
  2481.                 self.perr:send(s)
  2482.             end
  2483.         end
  2484.         self.env.os=util.shcopy(self.env.os)
  2485.         self.env.os.execute=function(s)
  2486.             if not self.env.shell then error'no shell' end
  2487.             return self.env.shell.execute(s)
  2488.         end
  2489.     end
  2490.     function Box:run(f,...)
  2491.         setfenv(f,self.env)
  2492.         return f(...)
  2493.     end
  2494.     Box.get_current=function(level)
  2495.         level=(level or 0)
  2496.         repeat
  2497.             level=level+1
  2498.             local env=getfenv(level)
  2499.             if env[Box.token] then
  2500.                 return env[Box.token]
  2501.             end
  2502.         until env==_Gstore.base_env
  2503.     end
  2504.  
  2505. end
  2506.  
  2507. return Box]===================],"CoolisOS/bin/kernel/class/init.lua",[===================[-- classlib.lua 2.04.04
  2508. --
  2509. -- Changes from 2.03:
  2510. --
  2511. -- 1.   Included patches and ideas from Peter Schaefer
  2512. --      ([email protected]) considerably improving the efficiency of
  2513. --      build(), __init() and other parts of the code.
  2514. --
  2515. -- 2.   The former remove_ambiguous() function was removed, improving the
  2516. --      efficiency of both build() (instance creation) and mt:__call() (class
  2517. --      creation). Ambiguities are now processed using the ambiguous_keys
  2518. --      tables introduced by Peter.
  2519. --
  2520. -- 3.   Removed inheritance of class properties, which was inconsistent with
  2521. --      the way instance properties are handled (see pages 4-5 of the manual).
  2522. --      Mostly harmless, but confusing. Now only methods are inherited.
  2523. --
  2524.  
  2525. -- PRIVATE
  2526.  
  2527. --[[
  2528.     Define unique value for identifying ambiguous base objects and inherited
  2529.     attributes. Ambiguous values are normally removed from classes and objects,
  2530.     but if keep_ambiguous == true they are left there and the ambiguous value
  2531.     is made to behave in a way useful for debugging.
  2532. ]]
  2533.  
  2534. --[[
  2535. Changes for OS:
  2536. -__root field of each self points to the deepest self table;
  2537. -methods matching '^_[^_]' are not copied into subclasses;
  2538.  
  2539. ]]
  2540.  
  2541.  
  2542. local ambiguous
  2543.  
  2544. if keep_ambiguous then
  2545.  
  2546.     ambiguous = { _type = 'ambiguous' }
  2547.  
  2548.     local function invalid(operation)
  2549.         return function()
  2550.             error('Invalid ' .. operation .. ' on ambiguous')
  2551.         end
  2552.     end
  2553.  
  2554.     -- Make ambiguous complain about everything except tostring()
  2555.     local ambiguous_mt =
  2556.     {
  2557.         __add       = invalid('addition'),
  2558.         __sub       = invalid('substraction'),
  2559.         __mul       = invalid('multiplication'),
  2560.         __div       = invalid('division'),
  2561.         __mod       = invalid('modulus operation'),
  2562.         __pow       = invalid('exponentiation'),
  2563.         __unm       = invalid('unary minus'),
  2564.         __concat    = invalid('concatenation'),
  2565.         __len       = invalid('length operation'),
  2566.         __eq        = invalid('equality comparison'),
  2567.         __lt        = invalid('less than'),
  2568.         __le        = invalid('less or equal'),
  2569.         __index     = invalid('indexing'),
  2570.         __newindex  = invalid('new indexing'),
  2571.         __call      = invalid('call'),
  2572.         __tostring  = function() return 'ambiguous' end,
  2573.         __tonumber  = invalid('conversion to number')
  2574.     }
  2575.     setmetatable(ambiguous, ambiguous_mt)
  2576.  
  2577. end
  2578.  
  2579.  
  2580. --[[
  2581.     Reserved attribute names.
  2582. ]]
  2583.  
  2584. local reserved =
  2585. {
  2586.     __index         = true,
  2587.     __newindex      = true,
  2588.     __type          = true,
  2589.     __class         = true,
  2590.     __bases         = true,
  2591.     __inherited     = true,
  2592.     __from          = true,
  2593.     __shared        = true,
  2594.     __user_init     = true,
  2595.     __name          = true,
  2596.     __initialized   = true,
  2597.     __root          = true,
  2598. }
  2599.  
  2600. --[[
  2601.     Some special user-set attributes are renamed.
  2602. ]]
  2603.  
  2604. local rename =
  2605. {
  2606.     __init  = '__user_init',
  2607.     __set   = '__user_set',
  2608.     __get   = '__user_get'
  2609. }
  2610.  
  2611. --[[
  2612.     The metatable of all classes, containing:
  2613.  
  2614.     To be used by the classes:
  2615.     __call()        for creating instances
  2616.     __init()        default constructor
  2617.     is_a()          for checking object and class types
  2618.     implements()    for checking interface support
  2619.  
  2620.     For internal use:
  2621.     __newindex()    for controlling class population
  2622. ]]
  2623.  
  2624. local class_mt = {}
  2625. class_mt.__index = class_mt
  2626.  
  2627. --[[
  2628.     This controls class population.
  2629.     Here 'self' is a class being populated by inheritance or by the user.
  2630. ]]
  2631.  
  2632. function class_mt:__newindex(name, value)
  2633.  
  2634.     -- Rename special user-set attributes
  2635.     if rename[name] then name = rename[name] end
  2636.  
  2637.     -- __user_get() needs an __index() handler
  2638.     if name == '__user_get' then
  2639.         self.__index = value and function(obj, k)
  2640.             local v = self[k]
  2641.             if v == nil and not reserved[k] then v = value(obj, k) end
  2642.             return v
  2643.         end or self
  2644.  
  2645.     -- __user_set() needs a __newindex() handler
  2646.     elseif name == '__user_set' then
  2647.         self.__newindex = value and function(obj, k, v)
  2648.             if reserved[k] or not value(obj, k, v) then rawset(obj, k, v) end
  2649.         end or nil
  2650.  
  2651.     end
  2652.  
  2653.     -- Assign the attribute
  2654.     rawset(self, name, value)
  2655. end
  2656.  
  2657. --[[
  2658.     This function creates an object of a certain class and calls itself
  2659.     recursively to create one child object for each base class. Base objects
  2660.     of unnamed base classes are accessed by using the base class as an index
  2661.     into the object, base objects of named base classes are accessed as fields
  2662.     of the object with the names of their respective base classes.
  2663.     Classes derived in shared mode will create only a single base object.
  2664.     Unambiguous grandchildren are inherited by the parent if they do not
  2665.     collide with direct children.
  2666. ]]
  2667.  
  2668. local function build(class, shared_objs, shared,__root)
  2669.  
  2670.     -- If shared, look in the repository of shared objects
  2671.     -- and return any previous instance of this class.
  2672.     if shared then
  2673.         local prev_instance = shared_objs[class]
  2674.         if prev_instance then return prev_instance end
  2675.     end
  2676.  
  2677.     -- Create new object
  2678.     local obj = { __type = 'object' }
  2679.     if __root==nil then
  2680.         __root=obj
  2681.     end
  2682.     obj.__root=__root
  2683.     obj[class.__name]=obj
  2684.  
  2685.     -- Build child objects if there are base classes
  2686.     local nbases = #class.__bases
  2687.     if nbases > 0 then
  2688.  
  2689.         -- Repository for storing inherited base objects
  2690.         local inherited = {}
  2691.  
  2692.         -- List of ambiguous keys
  2693.         local ambiguous_keys = {}
  2694.  
  2695.         -- Build child objects for each base class
  2696.         for i = 1, nbases do
  2697.             local base = class.__bases[i]
  2698.             local child = build(base, shared_objs, class.__shared[base],__root)
  2699.             obj[base.__name] = child
  2700.  
  2701.             -- Get inherited grandchildren from this child
  2702.             for c, grandchild in pairs(child) do
  2703.  
  2704.                 -- We can only accept one inherited grandchild of each class,
  2705.                 -- otherwise this is an ambiguous reference
  2706.                 if not ambiguous_keys[c] then
  2707.                     if not inherited[c] then inherited[c] = grandchild
  2708.                     elseif inherited[c] ~= grandchild then
  2709.                         inherited[c] = ambiguous
  2710.                         table.insert(ambiguous_keys, c)
  2711.                     end
  2712.                 end
  2713.             end
  2714.         end
  2715.  
  2716.         -- Accept inherited grandchildren if they don't collide with
  2717.         -- direct children
  2718.         for k, v in pairs(inherited) do
  2719.             if not obj[k] then obj[k] = v end
  2720.         end
  2721.  
  2722.     end
  2723.  
  2724.     -- Object is ready
  2725.     setmetatable(obj, class)
  2726.  
  2727.     -- If shared, add it to the repository of shared objects
  2728.     if shared then shared_objs[class] = obj end
  2729.  
  2730.     return obj
  2731.  
  2732. end
  2733.  
  2734. --[[
  2735.     The __call() operator creates an instance of the class and initializes it.
  2736. ]]
  2737.  
  2738. function class_mt:__call(...)
  2739.     local obj = build(self, {}, false)
  2740.     obj:__init(...)
  2741.     return obj
  2742. end
  2743.  
  2744. --[[
  2745.     The implements() method checks that an object or class supports the
  2746.     interface of a target class. This means it can be passed as an argument to
  2747.     any function that expects the target class. We consider only functions
  2748.     and callable objects to be part of the interface of a class.
  2749. ]]
  2750.  
  2751. function class_mt:implements(class)
  2752.  
  2753.     -- Auxiliary function to determine if something is callable
  2754.     local function is_callable(v)
  2755.         if v == ambiguous then return false end
  2756.         if type(v) == 'function' then return true end
  2757.         local mt = getmetatable(v)
  2758.         return mt and type(mt.__call) == 'function'
  2759.     end
  2760.  
  2761.     -- Check we have all the target's callables (except reserved names)
  2762.     for k, v in pairs(class) do
  2763.         if not reserved[k] and is_callable(v) and not is_callable(self[k]) then
  2764.             return false
  2765.         end
  2766.     end
  2767.     return true
  2768. end
  2769.  
  2770. --[[
  2771.     The is_a() method checks the type of an object or class starting from
  2772.     its class and following the derivation chain upwards looking for
  2773.     the target class. If the target class is found, it checks that its
  2774.     interface is supported (this may fail in multiple inheritance because
  2775.     of ambiguities).
  2776. ]]
  2777.  
  2778. function class_mt:is_a(class)
  2779.  
  2780.     -- If our class is the target class this is trivially true
  2781.     if self.__class == class then return true end
  2782.  
  2783.     -- Auxiliary function to determine if a target class is one of a list of
  2784.     -- classes or one of their bases
  2785.     local function find(target, classlist)
  2786.         for i = 1, #classlist do
  2787.             local class = classlist[i]
  2788.             if class == target or find(target, class.__bases) then
  2789.                 return true
  2790.             end
  2791.         end
  2792.         return false
  2793.     end
  2794.  
  2795.     -- Check that we derive from the target
  2796.     if not find(class, self.__bases) then return false end
  2797.  
  2798.     -- Check that we implement the target's interface.
  2799.     return self:implements(class)
  2800. end
  2801.  
  2802. --[[
  2803.     Factory-supplied constructor, calls the user-supplied constructor if any,
  2804.     then calls the constructors of the bases to initialize those that were
  2805.     not initialized before. Objects are initialized exactly once.
  2806. ]]
  2807.  
  2808. function class_mt:__init(...)
  2809.     if self.__initialized then return end
  2810.     if self.__user_init then self:__user_init(...) end
  2811.     for i = 1, #self.__bases do
  2812.         local base = self.__bases[i]
  2813.         self[base.__name]:__init(...)
  2814.     end
  2815.     self.__initialized = true
  2816. end
  2817.  
  2818.  
  2819. -- PUBLIC
  2820.  
  2821. --[[
  2822.     Utility type and interface checking functions
  2823. ]]
  2824.  
  2825. function ofType(value)
  2826.     local t = type(value)
  2827.     return t =='table' and classname(t) or t
  2828. end
  2829.  
  2830. function typeof(value)
  2831.     local t = type(value)
  2832.     return t =='table' and value.__type or t
  2833. end
  2834.  
  2835. function classof(value)
  2836.     local t = type(value)
  2837.     return t == 'table' and value.__class or nil
  2838. end
  2839.  
  2840. function classname(value)
  2841.     if not classof(value) then return nil end
  2842.     local name = value.__name
  2843.     return type(name) == 'string' and name or nil
  2844. end
  2845.  
  2846. function implements(value, class)
  2847.     return classof(value) and value:implements(class) or false
  2848. end
  2849.  
  2850. function is_a(value, class)
  2851.     return classof(value) and value:is_a(class) or false
  2852. end
  2853.  
  2854.  
  2855. --[[
  2856.     Use a table to control class creation and naming.
  2857. ]]
  2858.  
  2859. class = {}
  2860. local mt = {}
  2861. setmetatable(class, mt)
  2862.  
  2863. --[[
  2864.     Create a named or unnamed class by calling class([name, ] ...).
  2865.     Arguments are an optional string to set the class name and the classes or
  2866.     shared classes to be derived from.
  2867. ]]
  2868.  
  2869. function mt:__call(...)
  2870.  
  2871.     local arg = {...}
  2872.  
  2873.     -- Create a new class
  2874.     local c =
  2875.     {
  2876.         __type = 'class',
  2877.         __bases = {},
  2878.         __shared = {}
  2879.     }
  2880.     c.__class = c
  2881.     c.__index = c
  2882.  
  2883.     -- A first string argument sets the name of the class.
  2884.     if type(arg[1]) == 'string' then
  2885.         c.__name = arg[1]
  2886.         table.remove(arg, 1)
  2887.     else
  2888.         c.__name = c
  2889.     end
  2890.  
  2891.     -- Repository of inherited attributes
  2892.     local inherited = {}
  2893.     local from = {}
  2894.  
  2895.     -- List of ambiguous keys
  2896.     local ambiguous_keys = {}
  2897.  
  2898.     -- Inherit from the base classes
  2899.     for i = 1, #arg do
  2900.         local base = arg[i]
  2901.  
  2902.         -- Get the base and whether it is inherited in shared mode
  2903.         local basetype = typeof(base)
  2904.         local shared = basetype == 'share'
  2905.         assert(basetype == 'class' or shared,
  2906.                 'Base ' .. i .. ' is not a class or shared class')
  2907.         if shared then base = base.__class end
  2908.  
  2909.         -- Just in case, check this base is not repeated
  2910.         assert(c.__shared[base] == nil, 'Base ' .. i .. ' is duplicated')
  2911.  
  2912.         -- Accept it
  2913.         c.__bases[i] = base
  2914.         c.__shared[base] = shared
  2915.  
  2916.         -- Get methods that could be inherited from this base
  2917.         for k, v in pairs(base) do
  2918.  
  2919.             -- Skip reserved and ambiguous methods
  2920.             if type(v) == 'function' and not reserved[k] and (type(k)=='string' and not k:match'^_[^_]')and
  2921.                 not ambiguous_keys[k] then
  2922.  
  2923.                 -- Where does this method come from?
  2924.                 local new_from
  2925.  
  2926.                 -- Check if the method was inherited by the base
  2927.                 local base_inherited = base.__inherited[k]
  2928.                 if base_inherited then
  2929.  
  2930.                     -- If it has been redefined, cancel this inheritance
  2931.                     if base_inherited ~= v then     -- (1)
  2932.                         base.__inherited[k] = nil
  2933.                         base.__from[k] = nil
  2934.  
  2935.                     -- It is still inherited, get it from the original
  2936.                     else
  2937.                         new_from = base.__from[k]
  2938.                     end
  2939.                 end
  2940.  
  2941.                 -- If it is not inherited by the base, it originates there
  2942.                 new_from = new_from or { class = base, shared = shared }
  2943.  
  2944.                 -- Accept a first-time inheritance
  2945.                 local current_from = from[k]
  2946.                 if not current_from then
  2947.                     from[k] = new_from
  2948.                     local origin = new_from.class
  2949.  
  2950.                     -- We assume this is an instance method (called with
  2951.                     -- self as first argument) and wrap it so that it will
  2952.                     -- receive the correct base object as self. For class
  2953.                     -- functions this code is unusable.
  2954.                     inherited[k] = function(self, ...)
  2955.                         return origin[k](self[origin.__name], ...)
  2956.                     end
  2957.  
  2958.                 -- Methods inherited more than once are ambiguous unless
  2959.                 -- they originate in the same shared class.
  2960.                 elseif current_from.class ~= new_from.class or
  2961.                         not current_from.shared or not new_from.shared then
  2962.                     inherited[k] = ambiguous
  2963.                     table.insert(ambiguous_keys, k)
  2964.                     from[k] = nil
  2965.                 end
  2966.             end
  2967.         end
  2968.     end
  2969.  
  2970.     -- Set the metatable now, it monitors attribute setting and does some
  2971.     -- special processing for some of them.
  2972.     setmetatable(c, class_mt)
  2973.  
  2974.     -- Set inherited attributes in the class, they may be redefined afterwards
  2975.     for k, v in pairs(inherited) do c[k] = v end    -- checked at (1)
  2976.     c.__inherited = inherited
  2977.     c.__from = from
  2978.  
  2979.     return c
  2980. end
  2981.  
  2982. --[[
  2983.     Create a named class and assign it to a global variable of the same name.
  2984.     Example: class.A(...) is equivalent to (global) A = class('A', ...).
  2985. ]]
  2986.  
  2987. function mt:__index(name)
  2988.     return function(...)
  2989.         local c = class(name, ...)
  2990.         local cenv=getfenv(2)
  2991.         cenv[name] = c
  2992.         return c
  2993.     end
  2994. end
  2995.  
  2996. --[[
  2997.     Wrap a class for shared derivation.
  2998. ]]
  2999.  
  3000. function shared(class)
  3001.     assert(typeof(class) == 'class', 'Argument is not a class')
  3002.     return { __type = 'share', __class = class }
  3003. end
  3004. ]===================],"CoolisOS/bin/kernel/class/Opt.lua",[===================[class.Opt()
  3005. function Opt:__init(t,typ,...)
  3006.     self.typ=typ or (typeof(t))
  3007.     self.val=t
  3008.     self.args={...}
  3009. end
  3010. function Opt:drop(dst,src,name)
  3011.     local typ=self.typ
  3012.     if typ=='req' then
  3013.         if src==nil then error(string.format('parameter %s required',tostring(name)))
  3014.         else return src end
  3015.     elseif typ=='function' then if src==nil then return self.val(unpack(self.args)) else return src end
  3016.     elseif typ=='raw' or typ=='nil' then
  3017.         if src==nil then return self.val else return src end
  3018.     elseif typ=='object' then return src==nil and (self.val.clone and self.val:clone() or self.val.__class(self.val)) or src
  3019.     elseif typ=='class' then return src==nil and (self.val(unpack(self.args))) or src
  3020.     elseif typ=='table' then
  3021.         dst=dst or {}
  3022.         src=src or {}
  3023.         for i,v in pairs(self.val) do
  3024.             if classof(v)==Opt then
  3025.                 dst[i]=v:drop(nil,src[i],i)
  3026.             else
  3027.                 if src[i]~=nil then
  3028.                     v=src[i]
  3029.                 end
  3030.                 dst[i]=v
  3031.             end
  3032.         end
  3033.         return dst
  3034.     end
  3035. end
  3036. return Opt]===================],"CoolisOS/bin/kernel/class/Var.lua",[===================[include'kernel.class'
  3037. local check=require'kernel.checker'
  3038. local dump=require'utils.serpent'.dump
  3039. local util=require'kernel.util'
  3040. class.Var()
  3041. local p=setmetatable({},{__mode='k'})
  3042. function Var:__init(file,opt)
  3043.     p[self]={}
  3044.     p[self].file=file
  3045.     local dir=loadreq.getDir(p[self].file)
  3046.     if not fs.exists(dir) then fs.makeDir(dir) end
  3047.     if not fs.exists(file) then self:setAll{} end
  3048. end
  3049.  
  3050. function Var:getAll()
  3051.     local f=io.open(p[self].file,'r')
  3052.     local s=f:read'*a'
  3053.     f:close()
  3054.     local t=loadstring(s)()
  3055.     return t
  3056. end
  3057.  
  3058. function Var:setAll(t)
  3059.     local f=io.open(p[self].file,'w')
  3060.     local s=f:write(dump(t))
  3061.     f:close()
  3062. end
  3063.  
  3064. function Var:__get(k)
  3065.     local t=self:getAll()
  3066.     if not t then t={} self:setAll(t) end
  3067.     return t[k]
  3068. end
  3069. function Var:__set(k,v)
  3070.     local t=self:getAll()
  3071.     t[k]=v
  3072.     self:setAll(t)
  3073.     return true
  3074. end
  3075. return Var]===================],"CoolisOS/bin/kernel/gui",true,"CoolisOS/bin/kernel/gui/autocomplete.lua",[===================[
  3076. local list=require'utils.pl.List'
  3077. local pathutils={} --API
  3078. do
  3079.     local segments, get, concat, find
  3080.  
  3081.     local function pathconcat(pt, starti, endi)
  3082.         local t = {}
  3083.         local prev
  3084.         local empties = 0
  3085.         starti = starti or 1
  3086.         endi = endi or #pt
  3087.        
  3088.         for i = starti, endi do
  3089.             local v = pt[i]
  3090.             if not v then break
  3091.             elseif v == '' then
  3092.                 empties = empties+1
  3093.             else
  3094.                 table.insert(t, prev)
  3095.                 prev = v
  3096.             end
  3097.         end
  3098.         table.insert(t, prev)
  3099.         --log('PATH', 'INFO', "pathconcat(%s, %d, %d) generates table %s, wants indexes %d->%d",
  3100.         --    sprint(pt), starti, endi, sprint(t), 1, endi-starti+1-empties)
  3101.         return table.concat(t, '.', 1, endi-starti+1-empties)
  3102.     end
  3103.  
  3104.     function get(t, path)
  3105.         local p = type(path)=='string' and segments(path) or path
  3106.         local k = table.remove(p)
  3107.         if not k then return t end
  3108.         local t = find(t, p)
  3109.         return t and t[k]
  3110.     end
  3111.  
  3112.  
  3113.  
  3114.     function segments(path)
  3115.         local t = {}
  3116.         local index, newindex, elt = 1
  3117.         repeat
  3118.             newindex = path:find(".", index, true) or #path+1 --last round
  3119.             elt = path:sub(index, newindex-1)
  3120.             elt = tonumber(elt) or elt        
  3121.             if elt and elt ~= "" then table.insert(t, elt) end
  3122.             index = newindex+1    
  3123.         until newindex==#path+1  
  3124.         return t
  3125.     end
  3126.  
  3127.     function find(t, path, force)
  3128.         path = type(path)=="string" and segments(path) or path
  3129.         for i, n in ipairs(path) do
  3130.             local v  = t[n]
  3131.             if type(v) ~= "table" then
  3132.                 if not force or (force=="noowr" and v~=nil) then return nil, pathconcat(path, 1, i)
  3133.                 else v = {} t[n] = v end
  3134.             end
  3135.             t = v
  3136.         end
  3137.         return t
  3138.     end
  3139.    
  3140.     pathutils.get=get
  3141. end
  3142.  
  3143. function env_matcher(path,opts)
  3144.     local env=opts.env or _G
  3145.    
  3146.     local lpath,pa = path:match("^(.-)([%w_]?[%w_%.%:]*)$") -- get the significant end part of the path (non alphanum are spliters...)
  3147.    
  3148.     local p, s, l = pa:match("(.-)([%.%:]?)([^%.%:]*)$") -- separate into sub path and leaf, getting the separator
  3149.     local t = pathutils.get(env, p)
  3150.     local funconly =  s == ":"
  3151.     local tr = {}
  3152.     local function copykeys(src, dst)
  3153.         if type(src) ~= 'table' then return end
  3154.         for k, v in pairs(src) do
  3155.             local tv = type(v)
  3156.             if type(k)=='string' and k:match("^"..l) and (not funconly or tv=='function' or (tv=='table' and getmetatable(v) and getmetatable(v).__call)) then dst[k] = true end
  3157.         end
  3158.     end
  3159.  
  3160.     copykeys(t, tr)
  3161.  
  3162.     if s == ":" or s == "." then
  3163.         local m = getmetatable(t)
  3164.         if m then
  3165.             local i, n = m.__index, m.__newindex
  3166.             copykeys(i, tr)
  3167.             if n ~= i then copykeys(n, tr) end
  3168.             --if m~= i and m ~= n then copykeys(m, tr) end -- far from being perfect, but it happens that __index or __newindex are functions that uses the metatable as a object method holder
  3169.         end
  3170.     end
  3171.     local r = {}
  3172.     for k, v in pairs(tr) do table.insert(r, k) end
  3173.    
  3174.     -- sort the entries by lexical order
  3175.     table.sort(r)
  3176.     --when we have a complete match we can add a ".", ":" or "(" if the object is a table or a function
  3177.     if l == r[1] then
  3178.         local v=t[l]
  3179.         if type(v)=='function' then
  3180.             r[1]=r[1].."("
  3181.         elseif type(v)=='table' then
  3182.             if typeof(v)=='object' then
  3183.                 r[1]=r[1]..":"
  3184.             else
  3185.                 r[1]=r[1].."."
  3186.             end
  3187.         end
  3188.     end
  3189.     for i,v in pairs(r) do r[i]=lpath..p..s..v end
  3190.     return r
  3191. end
  3192.  
  3193. local tKeywords = {
  3194.     ["and"] = true,
  3195.     ["break"] = true,
  3196.     ["do"] = true,
  3197.     ["else"] = true,
  3198.     ["elseif"] = true,
  3199.     ["end"] = true,
  3200.     ["false"] = true,
  3201.     ["for"] = true,
  3202.     ["function"] = true,
  3203.     ["if"] = true,
  3204.     ["in"] = true,
  3205.     ["local"] = true,
  3206.     ["nil"] = true,
  3207.     ["not"] = true,
  3208.     ["or"] = true,
  3209.     ["repeat"] = true,
  3210.     ["return"] = true,
  3211.     ["then"] = true,
  3212.     ["true"] = true,
  3213.     ["until"]= true,
  3214.     ["while"] = true,
  3215. }
  3216.  
  3217. function keyword_matcher(path,opts)
  3218.     local r={}
  3219.     if #path~=0 then
  3220.         for key in pairs(tKeywords) do
  3221.             if path==key:sub(1,#path) then
  3222.                 table.insert(r,key)
  3223.             end
  3224.         end
  3225.     end
  3226.     return r
  3227. end
  3228.  
  3229. local function esc(x)
  3230.   return (x:gsub('%%', '%%%%')
  3231.            :gsub('%^', '%%%^')
  3232.            :gsub('%$', '%%%$')
  3233.            :gsub('%(', '%%%(')
  3234.            :gsub('%)', '%%%)')
  3235.            :gsub('%.', '%%%.')
  3236.            :gsub('%[', '%%%[')
  3237.            :gsub('%]', '%%%]')
  3238.            :gsub('%*', '%%%*')
  3239.            :gsub('%+', '%%%+')
  3240.            :gsub('%-', '%%%-')
  3241.            :gsub('%?', '%%%?'))
  3242. end
  3243.  
  3244. function fs_matcher(word,opts)
  3245.     local matches={}
  3246.     local p,s,l
  3247.     l=word:match("[^/\\]*$")
  3248.     local cwd=opts.cwd or '/'
  3249.     local absDir
  3250.     if not word:match("[/\\][^/\\]*$") then
  3251.         absDir=cwd
  3252.         p,s='',''
  3253.     else
  3254.         p,s=word:match("^(.-)([/\\])[^/\\]*$")
  3255.         absDir=(p=='' and '' or fs.combine(cwd,p))
  3256.     end
  3257.    
  3258.     if fs.isDir( absDir ) then
  3259.         -- Search for matches in the resolved folder.
  3260.         local ok, tFileList = pcall( fs.list, absDir )
  3261.         if ok then
  3262.             -- Populate table with all matches.
  3263.             local pat="^"..esc(l)..'.*'
  3264.             for k, v in ipairs(tFileList) do
  3265.                 local match = string.match( v, pat)
  3266.                 if match then
  3267.                     -- print(match)
  3268.                     table.insert( matches,match )
  3269.                 end
  3270.             end
  3271.         end
  3272.     end
  3273.     table.sort(matches)
  3274.     if (l == matches[1]) and fs.isDir(fs.combine(absDir,l)) then
  3275.         matches[1]= matches[1]..'/'
  3276.     end
  3277.     for i,v in pairs(matches) do matches[i]=p..s..v end
  3278.     return matches
  3279. end
  3280.  
  3281. function getmatch(path,opts)
  3282.     local r=list()
  3283.     local matchers=opts.matchers
  3284.     for _,matcher in pairs(matchers) do
  3285.         r:extend(matcher(path,opts))
  3286.     end
  3287.     r:sort()
  3288.     return r
  3289. end
  3290. ]===================],"CoolisOS/bin/kernel/gui/EvtH.lua",[===================[class.EvtH()
  3291. do
  3292. function EvtH:__init()
  3293.  
  3294. end
  3295.  
  3296. function EvtH:destroy()
  3297.  
  3298. end
  3299. function EvtH:queue()
  3300.    
  3301. end
  3302. wxEvtHandler::Connect
  3303. function EvtH:connect(src,event,f,...)
  3304.     local cast=src.EvtH
  3305.     local t=cast.dst[event] or setmetatable({},{__mode='k'})
  3306.     cast.dst[event][self]=true
  3307.    
  3308.     t=self.handlers[event] or {}
  3309.     self.handlers[event]=t
  3310.     t[f]={...}
  3311. end
  3312.  
  3313. wxEvtHandler::Disconnect
  3314. function EvtH:disconnect(src,event,f,this)
  3315.     srcs=src and {src=true} or self.src
  3316.     for src in pairs(srcs) do
  3317.         events=event and {event=src[event]} or src.dst
  3318.         for event,evth in pairs(events) do
  3319.             fs=f and {f}
  3320.         end
  3321.     end
  3322. end
  3323. wxEvtHandler::GetClientData
  3324. function EvtH:()
  3325.  
  3326. end
  3327. wxEvtHandler::GetClientObject
  3328. function EvtH:()
  3329.  
  3330. end
  3331. wxEvtHandler::GetEvtHandlerEnabled
  3332. function EvtH:isEnabled()
  3333.  
  3334. end
  3335. wxEvtHandler::GetNextHandler
  3336. function EvtH:next()
  3337.  
  3338. end
  3339. wxEvtHandler::GetPreviousHandler
  3340. function EvtH:previous()
  3341.  
  3342. end
  3343. wxEvtHandler::ProcessEvent
  3344. function EvtH:process()
  3345.  
  3346. end
  3347. wxEvtHandler::SearchEventTable
  3348. function EvtH:search()
  3349.  
  3350. end
  3351. wxEvtHandler::SetClientData
  3352. function EvtH:()
  3353.  
  3354. end
  3355. wxEvtHandler::SetClientObject
  3356. function EvtH:()
  3357.  
  3358. end
  3359. function EvtH:setEnabled()
  3360.  
  3361. end
  3362. function EvtH:setNext()
  3363.  
  3364. end
  3365. function EvtH:setPrevious()
  3366.  
  3367. end
  3368. end]===================],"CoolisOS/bin/kernel/gui/init.lua",[===================[include'kernel.class'
  3369. local sched=require'kernel.sched'
  3370. local checker=require'kernel.checker'
  3371. local check=checker.check
  3372. local list=require'utils.pl.List'
  3373. gui=getfenv()
  3374. Point=require'Point'
  3375. Rectangle=require'Rectangle'
  3376. Term=require'Term'
  3377.  
  3378. function read(pin,term,opts)
  3379.     pin=pin.Pipe
  3380.     term:setCursorBlink(true)
  3381.     local _sReplaceChar=opts._sReplaceChar
  3382.     local _tHistory=opts.history
  3383.     local sLine = ""
  3384.     local nHistoryPos = nil
  3385.     local nPos = 0
  3386.     if _sReplaceChar then
  3387.         _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
  3388.     end
  3389.    
  3390.     local auto
  3391.     if opts.auto then
  3392.         assert(#opts.auto>0)
  3393.         auto={}
  3394.         auto.mode=opts.auto.mode or 1
  3395.         auto.count=0
  3396.         auto.matches = { n = 0}
  3397.         function auto.reset()
  3398.             auto.matches = { n = 0}
  3399.         end
  3400.         local function split(s,n)
  3401.             local s=sLine
  3402.             local n=nPos+1
  3403.             local l,r=s:sub(1,n-1),s:sub(n)
  3404.             local pl,rl
  3405.             if l:sub(-1,-1):match'%s' then
  3406.                 local sp=l:sub(-1,-1)
  3407.                 l=l:sub(1,-2)
  3408.                 r=sp..r
  3409.             end
  3410.            
  3411.             local ls,lp=l:match'^(.-)([^%s]+)$'
  3412.             rp,rs=r:match'^([^%s]+)(.-)$'
  3413.             if lp==nil then ls,lp=l,'','' end
  3414.             if rp==nil then rp,rs='',r end
  3415.             return ls,lp..rp,rs
  3416.         end
  3417.        
  3418.         function auto.update()
  3419.             local l,p,r=split(sLine,nPos+1)
  3420.             -- debug.log(l,p,r)
  3421.             local ok,m=pcall(opts.auto[auto.mode],p)
  3422.             if not ok then debug.log(m) end
  3423.             -- debug.log(pstring(m,1))
  3424.             m.l,m.r=l,r
  3425.             auto.matches=m
  3426.         end
  3427.         function auto.put()
  3428.             local matches=auto.matches
  3429.             local match=matches[matches.n]
  3430.             local l,r=matches.l,matches.r
  3431.             sLine = l..match..r
  3432.             nPos = #l+#match
  3433.         end
  3434.     end
  3435.     local w, h = term:getSize()
  3436.     local sx, sy = term:getCursorPos()    
  3437.    
  3438.    
  3439.     local function redraw( _sCustomReplaceChar )
  3440.             local nScroll = 0
  3441.             local su=''
  3442.            
  3443.             if sx + nPos > w then
  3444.                     nScroll = (sx + nPos) - w
  3445.             end
  3446.             term:setCursorPos( sx, sy )
  3447.            
  3448.             local sReplace = _sCustomReplaceChar or _sReplaceChar
  3449.             local s
  3450.             if sReplace then
  3451.                 s=string.rep(sReplace, string.len(sLine) - nScroll)
  3452.             else
  3453.                 s=string.sub( sLine, nScroll + 1 )
  3454.             end
  3455.            
  3456.             if #s<(w-sx+1) then s=s..(' '):rep(w-sx+1) end
  3457.             term:write(s)
  3458.             term:setCursorPos( sx + nPos - nScroll, sy )
  3459.     end
  3460.    
  3461.    
  3462.     pin:reset()
  3463.     while true do
  3464.             local _,sEvent,param=unpack(pin:receive())
  3465.             if sEvent == "char" then
  3466.                 if auto then auto.reset() end
  3467.                 sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
  3468.                 nPos = nPos + 1
  3469.                 redraw()               
  3470.             elseif sEvent == "key" then
  3471.                 if auto then
  3472.                     if not (param == keys.tab) then
  3473.                         auto.reset() -- Reset completion match-table.
  3474.                     else
  3475.                         if auto.matches[1] then   -- tab was pressed before.
  3476.                             local matches=auto.matches
  3477.                             -- Shift pointer to next match.
  3478.                             matches.n = (matches.n)%#matches +1  -- Wrap around if the pointer has gone past the end.
  3479.                            
  3480.                             -- Assemble the new line.
  3481.                             auto.put()
  3482.                            
  3483.                             redraw()
  3484.                         else
  3485.                             -- [[ No matches yet, look for some now. ]]
  3486.                             auto.update()
  3487.                             local matches=auto.matches
  3488.                             matches.n=0
  3489.                             if #matches==0 then
  3490.                                 --nPos=nPos+4
  3491.                                 --sLine=sLine..'\t'
  3492.                             else -- Show first match.
  3493.                                 matches.n=1
  3494.                                 auto.put()
  3495.                                 if #matches==1 then auto.reset() end
  3496.                             end
  3497.                             redraw()
  3498.                         end
  3499.                     end
  3500.                     if not (param == keys.rightShift) then
  3501.                         auto.count=0
  3502.                     else
  3503.                         auto.count=(auto.count+1)%2
  3504.                         if auto.count==0 then
  3505.                             auto.mode=(auto.mode)%#opts.auto+1
  3506.                         end
  3507.                         auto.reset()
  3508.                     end
  3509.                 end
  3510.                 if param == keys.enter then
  3511.                     -- Enter
  3512.                     break
  3513.                 elseif param == keys.left then
  3514.                         -- Left
  3515.                         if nPos > 0 then
  3516.                                 nPos = nPos - 1
  3517.                                 redraw()
  3518.                         end
  3519.                        
  3520.                 elseif param == keys.right then
  3521.                         -- Right                              
  3522.                         if nPos < string.len(sLine) then
  3523.                                 nPos = nPos + 1
  3524.                                 redraw()
  3525.                         end
  3526.                
  3527.                 elseif param == keys.up or param == keys.down then
  3528.                     -- Up or down
  3529.                     if _tHistory then
  3530.                         redraw(" ");
  3531.                         if param == keys.up then
  3532.                                 -- Up
  3533.                                 if nHistoryPos == nil then
  3534.                                         if #_tHistory > 0 then
  3535.                                                 nHistoryPos = #_tHistory
  3536.                                         end
  3537.                                 elseif nHistoryPos > 1 then
  3538.                                         nHistoryPos = nHistoryPos - 1
  3539.                                 end
  3540.                         else
  3541.                                 -- Down
  3542.                                 if nHistoryPos == #_tHistory then
  3543.                                         nHistoryPos = nil
  3544.                                 elseif nHistoryPos ~= nil then
  3545.                                         nHistoryPos = nHistoryPos + 1
  3546.                                 end                                            
  3547.                         end
  3548.                                            
  3549.                         if nHistoryPos then
  3550.                             sLine = _tHistory[nHistoryPos]
  3551.                             nPos = string.len( sLine )
  3552.                         else
  3553.                             sLine = ""
  3554.                             nPos = 0
  3555.                         end
  3556.                         redraw()
  3557.                     end
  3558.                 elseif param == keys.backspace then
  3559.                         -- Backspace
  3560.                         if nPos > 0 then
  3561.                             redraw(" ");
  3562.                             sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
  3563.                             nPos = nPos - 1                                
  3564.                             redraw()
  3565.                         end
  3566.                 elseif param == keys.home then
  3567.                         -- Home
  3568.                         nPos = 0
  3569.                         redraw()              
  3570.                 elseif param == keys.delete then
  3571.                         if nPos < string.len(sLine) then
  3572.                             redraw(" ");
  3573.                             sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )                          
  3574.                             redraw()
  3575.                         end
  3576.                 elseif param == keys["end"] then
  3577.                         -- End
  3578.                         nPos = string.len(sLine)
  3579.                         redraw()
  3580.                 -- elseif param == keys.leftAlt then
  3581.                         -- write('\n'..'..')
  3582.                         -- if auto then opts.auto.mode=auto.mode end
  3583.                         -- return sLine..'\n'..read(pin,term,opts)
  3584.                 end
  3585.             end
  3586.     end
  3587.    
  3588.     term:setCursorBlink( false )
  3589.     term:setCursorPos( w + 1, sy )
  3590.     if opts.clear~=false then print() end
  3591.     return sLine
  3592. end
  3593. function write(term,sText)
  3594.     check('string',sText)
  3595.     local w,h = term:getSize()     
  3596.     local x,y = term:getCursorPos()
  3597.    
  3598.     local nLinesPrinted = 0
  3599.     local function newLine()
  3600.         if y + 1 <= h then
  3601.             term:setCursorPos(1, y + 1)
  3602.         else
  3603.             term:setCursorPos(1, h)
  3604.             term:scroll(1)
  3605.         end
  3606.         x, y = term:getCursorPos()
  3607.         nLinesPrinted = nLinesPrinted + 1
  3608.     end
  3609.    
  3610.     -- Print the line with proper word wrapping
  3611.     while string.len(sText) > 0 do
  3612.         local whitespace = string.match( sText, "^[ \t]+" )
  3613.         if whitespace then
  3614.             -- Print whitespace
  3615.             term:write( whitespace )
  3616.             x,y = term:getCursorPos()
  3617.             sText = string.sub( sText, string.len(whitespace) + 1 )
  3618.         end
  3619.        
  3620.         local newline = string.match( sText, "^\n" )
  3621.         if newline then
  3622.             -- Print newlines
  3623.             newLine()
  3624.             sText = string.sub( sText, 2 )
  3625.         end
  3626.        
  3627.         local text = string.match( sText, "^[^ \t\n]+" )
  3628.         if text then
  3629.             sText = string.sub( sText, string.len(text) + 1 )
  3630.             if string.len(text) > w then
  3631.                 -- Print a multiline word              
  3632.                 while string.len( text ) > 0 do
  3633.                     if x > w then
  3634.                         newLine()
  3635.                     end
  3636.                     term:write( text )
  3637.                     text = string.sub( text, (w-x) + 2 )
  3638.                     x,y = term:getCursorPos()
  3639.                 end
  3640.             else
  3641.                 -- Print a word normally
  3642.                 if x + string.len(text) - 1 > w then
  3643.                     newLine()
  3644.                 end
  3645.                 term:write( text )
  3646.                 x,y = term:getCursorPos()
  3647.             end
  3648.         end
  3649.     end
  3650.    
  3651.     return nLinesPrinted
  3652. end
  3653. function printError(term,s)
  3654.     if term:isColour() then
  3655.         term:setTextColour( colours.red )
  3656.     end
  3657.     gui.write(term,s)
  3658.     term:setTextColour( colours.white )
  3659. end
  3660.  
  3661. local function property(class, attribute,field,setter,getter)
  3662.     class['set'..attribute]=setter or function(self,val) self[field]=val end
  3663.     class['get'..attribute]=getter or function(self) return self[field] end
  3664. end
  3665.  
  3666. local cc_events={
  3667. mouse={
  3668. 'mouse_click',
  3669. 'mouse_scroll',
  3670. 'mouse_drag',
  3671. },
  3672. touch={
  3673. 'monitor_touch',
  3674. },
  3675. keyboard={
  3676. 'key',
  3677. 'char',
  3678. },
  3679. }
  3680.  
  3681. class.Terminal()
  3682. do
  3683. function Terminal:__init(term,pin,pout)
  3684.     check('Term,Pipe,Pipe',term,pin,pout)
  3685.     self.term=term
  3686.     debug.namefield(self,'term')
  3687.     self.pin=pin
  3688.     debug.namefield(self,'pin')
  3689.     self.pout=pout
  3690.     debug.namefield(self,'pout')
  3691.     sched.task(sched.pump):run(pout,function(r) self:write(tostring(r)) end)
  3692. end
  3693.  
  3694. function Terminal.from_native(term,emitter)
  3695.     check('native_terminal,!nil',term,emitter)
  3696.     local h=sched.sigpipe()
  3697.     if term.isColor() then
  3698.         h:link{[emitter]=cc_events.mouse}
  3699.     end
  3700.     if term.setTextScale then
  3701.         h:link{[emitter]=cc_events.touch}
  3702.     else
  3703.         h:link{[emitter]=cc_events.keyboard}
  3704.     end
  3705.     local t=Terminal(Term.from_native(term),h.Pipe,sched.pipe())
  3706.     t.renderer=sched.task(function()
  3707.         while true do
  3708.             t.term:blit_native(term)
  3709.             t.term:copyState(term)
  3710.             sched.wait(false)
  3711.         end
  3712.     end)
  3713.     t.renderer:link{[t.term]={'*'}}
  3714.     debug.namefield(t,'renderer')
  3715.     t.renderer:run()
  3716.     t.term:setSignals(true)
  3717.     t.term:clear()
  3718.     return t
  3719. end
  3720.  
  3721. function Terminal:write(...)
  3722.     return write(self.term,...)
  3723. end
  3724.  
  3725. function Terminal:read(...)
  3726.     return read(self.pin,self.term,...)
  3727. end
  3728.  
  3729. end
  3730. ]===================],"CoolisOS/bin/kernel/gui/Point.lua",[===================[include'kernel.class'
  3731. local check=require'kernel.checker'.check
  3732. --[[-------------------------------------------------------
  3733. Members
  3734.     Point.x    -- number
  3735.     Point.y    -- number
  3736. Methods
  3737.     Point:Point(x, y)
  3738.     Point:Point(point)
  3739.     Point:assign(x, y)
  3740.     Point:assign(point)
  3741.     Point:clone()          -- return Point
  3742.     Point:add(x, y)
  3743.     Point:add(point)
  3744.     Point:sub(x, y)
  3745.     Point:sub(point)
  3746.     Point:equal(point)
  3747. --------------------------------------------------------------------------]]
  3748. class.Point()
  3749.  
  3750. function Point:__init(x, y)
  3751.     return self:assign(x, y)
  3752. end
  3753.  
  3754. function Point:assign(x, y)
  3755.     if (not y) then
  3756.        
  3757.         check('Point',x)
  3758.        
  3759.         self.x = x.x
  3760.         self.y = x.y
  3761.     else
  3762.         check('number,number',x,y)
  3763.         self.x = x
  3764.         self.y = y
  3765.     end
  3766.     return self
  3767. end
  3768.  
  3769. function Point:clone()
  3770.     return Point(self)
  3771. end
  3772.  
  3773. function Point:add(x, y)
  3774.     if (not y) then
  3775.         check('Point',x)
  3776.         self.x = self.x + x.x
  3777.         self.y = self.y + x.y
  3778.     else
  3779.         check('number,number',x,y)
  3780.         self.x = self.x + x
  3781.         self.y = self.y + y
  3782.     end
  3783.     return self
  3784. end
  3785.  
  3786. function Point:sub(x, y)
  3787.     if (not y) then
  3788.         check('Point',x)
  3789.         return self:add(-x.x, -x.y)
  3790.     else
  3791.         check('number,number',x,y)
  3792.         return self:add(-x, -y)
  3793.     end
  3794. end
  3795.  
  3796. function Point:equal(p)
  3797.     check('Point',p)
  3798.     return self.x == p.x and self.y == p.y
  3799. end
  3800. function Point:__tostring()
  3801.     return '(' .. self.x .. ',' .. self.y ..')'
  3802. end
  3803.  
  3804. return Point
  3805. ]===================],"CoolisOS/bin/kernel/gui/Rectangle.lua",[===================[include'kernel.class'
  3806. local Point=require'kernel.gui.Point'
  3807. class.Rectangle()
  3808. --[[ -------------------------------------------------------
  3809. Members:
  3810.     Rectangle.s -- Point (start)
  3811.     Rectangle.e -- Point (end)
  3812. Methods:
  3813.     Rectangle:assign(x1, y1, x2, y2)
  3814.     Rectangle:assign(rect)
  3815.     Rectangle:size()    -- return Point
  3816.     Rectangle:clone()   -- return Rectangle
  3817.     Rectangle:move(deltax, deltay)
  3818.     Rectangle:grow(deltax, deltay)
  3819.     Rectangle:intersect(rect)
  3820.     Rectangle:union(rect)
  3821.     Rectangle:equal(rect)
  3822.     Rectangle:contains(point)
  3823.     Rectangle:empty()
  3824.     Rectangle:nempty()
  3825. --------------------------------------------------------------------------]]
  3826. function Rectangle:__init(x1, y1, x2, y2)
  3827.     self:assign(x1, y1, x2, y2)
  3828. end
  3829.  
  3830. function Rectangle:assign(x1, y1, x2, y2)
  3831.     if (not y1) then
  3832.         self.s = x1.s:clone()
  3833.         self.e = x1.e:clone()
  3834.     elseif (not x2) then
  3835.         self.s=x1:clone()
  3836.         self.e=y1:clone()
  3837.     else
  3838.         self.s = Point(x1, y1)
  3839.         self.e = Point(x2, y2)
  3840.     end
  3841.     return self
  3842. end
  3843.  
  3844. function Rectangle:size()
  3845.     return self.e:clone():sub(self.s)
  3846. end
  3847.  
  3848. function Rectangle:clone()
  3849.     return Rectangle(self)
  3850. end
  3851.  
  3852. function Rectangle:move(deltax, deltay)
  3853.     self.s:add(deltax, deltay)
  3854.     self.e:add(deltax, deltay)
  3855.     return self
  3856. end
  3857.  
  3858. function Rectangle:grow(deltax, deltay)
  3859.     self.s:sub(deltax, deltay)
  3860.     self.e:add(deltax, deltay)
  3861.     return self
  3862. end
  3863.  
  3864. function Rectangle:intersect(r)
  3865.     local s, e = self.s, self.e
  3866.  
  3867.     s.x = max(s.x, r.s.x)
  3868.     s.y = max(s.y, r.s.y)
  3869.     e.x = min(e.x, r.e.x)
  3870.     e.y = min(e.y, r.e.y)
  3871.     return self
  3872. end
  3873.  
  3874. function Rectangle:union(r)
  3875.     local s, e = self.s, self.e
  3876.  
  3877.     s.x = min(s.x, r.s.x)
  3878.     s.y = min(s.y, r.s.y)
  3879.     e.x = max(e.x, r.e.x)
  3880.     e.y = max(e.y, r.e.y)
  3881.     return self
  3882. end
  3883.  
  3884. function Rectangle:equal(r)
  3885.     return self.s:equal(r.s) and self.e:equal(r.e)
  3886. end
  3887.  
  3888. function Rectangle:contains(x, y)
  3889.     return x >= self.s.x and x < self.e.x and y >= self.s.y and y < self.e.y
  3890. end
  3891.  
  3892. function Rectangle:empty()
  3893.     return self.s.x >= self.e.x or self.s.y >= self.e.y
  3894. end
  3895.  
  3896. function Rectangle:nempty()
  3897.     return not self:empty()
  3898. end
  3899.  
  3900.  
  3901. function Rectangle:__tostring()
  3902.     if (self:empty()) then
  3903.         return 'rect (empty)'
  3904.     else
  3905.         return 'rect (' .. tostring(self.s) .. ',' .. tostring(self.e) .. ')'
  3906.     end
  3907. end
  3908. return Rectangle]===================],"CoolisOS/bin/kernel/gui/shell.lua",[===================[include'kernel.gui'
  3909. local check=require'kernel.checker'.check
  3910. local acpl=require'kernel.gui.autocomplete'
  3911. local Box=require'kernel.class.Box'
  3912. --[[
  3913. methods:
  3914.     loop
  3915.     execute string->command->stuff
  3916.    
  3917.    
  3918.     runFile
  3919.     runLua
  3920.    
  3921.     destroy
  3922. fields:
  3923.     cwd
  3924.     tasks
  3925.     env
  3926.    
  3927.     input history
  3928.     output history
  3929.    
  3930.     pin events
  3931.     pcmd commands
  3932. defaults:
  3933.     cwd
  3934.     path
  3935.    
  3936.    
  3937. Full craftos programs support:
  3938.    
  3939.     special option:
  3940.    
  3941. ]]
  3942.  
  3943. function new()
  3944. local shell={}
  3945. shell.env=setmetatable({},{__index=_BOX.env})
  3946. shell.env.shell=shell
  3947. local prompts={
  3948. normal='>',
  3949. }
  3950.  
  3951. --[[
  3952. input
  3953. pout output
  3954. ]]
  3955.  
  3956. --filesystem
  3957. shell.cwd='/'
  3958. shell.path=fs.combine(_INSTALL_PATH,'bin/programs')
  3959. function shell.resolve(sPath)
  3960.     check('string',sPath)
  3961.     local sStartChar = string.sub( sPath, 1, 1 )
  3962.     if sStartChar == "/" or sStartChar == "\\" then
  3963.         return fs.combine( "", sPath )
  3964.     else
  3965.         return fs.combine( shell.cwd, sPath )
  3966.     end
  3967. end
  3968. ----intertask
  3969. shell.pin=sched.pipe()
  3970. --rendering
  3971. local w,h=term:getSize()
  3972. local up_term=Term{size=Point(w,1)}
  3973. local down_term=Term{size=Point(w,h-1)}
  3974. up_term:setSignals(true)
  3975. down_term:setSignals(true)
  3976. -- debug.name(up_term,'up_term')
  3977. -- debug.name(down_term,'down_term')
  3978. sched.task(function()
  3979.     sched.running:link{[up_term]={'*'},[down_term]={'*'}}
  3980.     repeat
  3981.         up_term:blit(term)
  3982.         down_term:blit(term,Point(1,2))
  3983.         sched.wait(false)
  3984.     until false
  3985. end):run()
  3986. --piping stuff to proper terms
  3987. local up_pin=_BOX.terminal.pin
  3988. local function _read()
  3989.     up_term:clear()
  3990.     up_term:setCursorPos(1,1)
  3991.     gui.write(up_term,shell.mode..shell.prompt)
  3992.     return gui.read(up_pin,up_term,{clear=false,history=shell.input,auto={
  3993.             function(s) return acpl.getmatch(s,{env=shell.env,
  3994.                                                 matchers={
  3995.                                                         acpl.keyword_matcher,
  3996.                                                         acpl.env_matcher,
  3997.                                                         },
  3998.                                                 }
  3999.                                             )
  4000.             end,
  4001.             function(s) return acpl.fs_matcher(s,{cwd=shell.cwd}) end,
  4002.             mode=shell.mode=='=' and 1 or 2,
  4003.             }
  4004.             }
  4005.     )
  4006. end
  4007. sched.task(function() sched.pump(nil,function() sched.wait() return _read() end,shell.pin) end):run()
  4008.  
  4009. sched.task(sched.pump):run(shell.pin,function(s)
  4010.     shell.execute(s)
  4011. end)
  4012. shell.pout=sched.pipe()
  4013. sched.task(sched.pump):run(shell.pout,function(s)
  4014.     gui.write(down_term,s..'\n')
  4015. end)
  4016.  
  4017. shell.perr=sched.pipe()
  4018. sched.task(sched.pump):run(shell.perr,function(s)
  4019.     log('shell','error',s)
  4020.     gui.printError(down_term,'perr:'..s..'\n')
  4021. end)
  4022.  
  4023. --keeping track of running tasks
  4024. shell.tasks=sched.Catalog()
  4025.  
  4026. shell.trace=false
  4027. function shell.runFunc(f,trace,stat,pp)
  4028.     -- local env=setmetatable({},{__index=shell.env})
  4029.     local box=Box{pout=shell.pout,perr=shell.perr,env=shell.env}
  4030.     local func=function() return box:run(f) end
  4031.    
  4032.     local t=sched.task(function()
  4033.         if trace==nil then trace=shell.trace end
  4034.         local debug=debug
  4035.         local t =trace and { xpcall(func,debug.traceback) } or { pcall(func) }
  4036.         if t[1] then
  4037.             table.remove(t,1)
  4038.             --if pp then t={pstring(t)} end
  4039.             table.insert(shell.output,t)
  4040.             shell.env._=t[1]
  4041.             local n=table.maxn(t)
  4042.             if n~=0 or stat then
  4043.                 s=tostring(t[1])
  4044.                 for i=2,n do
  4045.                     s=s..','..tostring(t[i])
  4046.                 end
  4047.                 shell.pout:send(s)
  4048.             end
  4049.         else
  4050.             shell.perr:send(t[2] or 'error(no msg)')
  4051.         end
  4052.     end)
  4053.     debug.name(t,'in'..#shell.input)
  4054.     shell.tasks:register(t,'in'..#shell.input)
  4055.     t:run()
  4056. end
  4057. function shell.runFile(path)
  4058.     local f,e=io.open(path,'r')
  4059.     if not f then shell.perr:send(e or 'could not open file')
  4060.     else
  4061.     local st=f:read'*a'
  4062.     f:close()
  4063.     local f,e=loadstring(st,path)
  4064.     if not f then shell.perr:send(e)
  4065.     else
  4066.     shell.runFunc(f,true,nil)
  4067.     end
  4068.     end
  4069. end
  4070.  
  4071. shell.input={}
  4072. shell.output=setmetatable({},{__index=function(t,k) return unpack(rawget(t,k)) end})
  4073. shell.env._in=shell.input
  4074. shell.env._out=shell.output
  4075. shell.prompt=prompts.normal
  4076. shell.mode='='
  4077. local modes={
  4078. ['>']=function(s,name) --filesystem mode
  4079.     s=shell.resolve(s)
  4080.     shell.runFile(s)
  4081. end,
  4082. ['=']=function(s,name)
  4083.     -- local pp=false
  4084.     -- if s:sub(1,1)=='?' then
  4085.         -- pp=true
  4086.         -- s=s:sub(2)
  4087.     -- end
  4088.     local proper_loadstring=function(s,n)
  4089.         check('string,string',s,n)
  4090.         local ok,f,e=pcall(loadstring,s,n)
  4091.         if e then e=e:match'(%d:[^:]-)$' end
  4092.         return f,e
  4093.     end
  4094.    
  4095.     local function get(s,name)
  4096.         --xpcall catches parsing errors which normally are returned as nil, error_msg.
  4097.         --so we pcall loadstring to avoid loosing the error
  4098.         --strangely, the xpcall lets execution continue at this level
  4099.         local func,e
  4100.         local f1,e1=proper_loadstring(s,name)
  4101.         local f2, e2 = proper_loadstring( "return "..s,name)
  4102.         if f1 then
  4103.             if f2 then
  4104.                 func=f2
  4105.             else
  4106.                 func=f1
  4107.             end
  4108.         else
  4109.             if f2 then
  4110.                 func=f2
  4111.             else
  4112.                 e=e1
  4113.             end
  4114.         end
  4115.         if e then e=name..':'..e end
  4116.         return func,e,(func==f2)
  4117.     end
  4118.     local func,e,stat=get(s,name)
  4119.    
  4120.     if func then
  4121.         shell.runFunc(func,nil,stat)--,pp)
  4122.     else
  4123.         shell.perr:send(e)
  4124.     end
  4125.    
  4126. end
  4127. }
  4128. --history
  4129.  
  4130. function shell.execute(s)
  4131.     table.insert(shell.input,s)
  4132.     local name='in['..#shell.input..']'
  4133.     shell.pout:send(name..':'..s)
  4134.     if modes[s:sub(1,1)] then--mode change
  4135.         shell.mode=s:sub(1,1)
  4136.         s=s:sub(2)
  4137.     end
  4138.     if #s>0 then modes[shell.mode](s,name) end
  4139. end
  4140.  
  4141. function shell.run_startups()
  4142.     local dir=fs.combine(_INSTALL_PATH,'ect/startups')
  4143.     if not fs.exists(dir) then fs.makeDir(dir) end
  4144.     local st=fs.list(dir)
  4145.     table.sort(st)
  4146.     for i,l in pairs(st) do
  4147.         shell.runFile(fs.combine(dir,l))
  4148.     end
  4149. end
  4150.  
  4151.  
  4152. _BOX.env.shell=shell
  4153. return shell
  4154. end
  4155. ]===================],"CoolisOS/bin/kernel/gui/Term.lua",[===================[include'kernel.class'
  4156. local Opt=require'kernel.class.Opt'
  4157. local checker=require'kernel.checker'
  4158. local check=checker.check
  4159. local Point=require'Point'
  4160. local Rectangle=require'Rectangle'
  4161. -- local function nimpl() return error('Not implemented',3) end
  4162. -- class.DC()
  4163. -- function DC:blit(pos,section) nimpl() end
  4164. -- function DC:setCursorPos(pos,section) nimpl() end
  4165. -- function DC:write(txt) nimpl() end
  4166. -- function DC:setTextColor(pos,section) nimpl() end
  4167. -- function DC:setBackgroundColor(pos,section) nimpl() end
  4168.  
  4169. class.Term()
  4170. local term_opt=Opt{
  4171. size=Opt(Point(5,5)),
  4172. bcolor=colors.black,
  4173. tcolor=colors.white,
  4174. pos=Opt(Point(1,1)),
  4175. color=term.isColor(),
  4176. blink=false,
  4177. }
  4178. local function update(self) self:emit(UPDATE) end
  4179. checker.custom.color=function(n) return (type(n)=='number' and n>=0 or error('Invalid color, must be number >0',3)) end
  4180. checker.custom.char=function(s) return type(s)=='string' and #s==1 end
  4181. local native=util.shcopy(term.native)
  4182. checker.custom.native_terminal=function(t)
  4183.     for i,v in pairs(native) do
  4184.         if type(t[i])~=type(native[i]) then return false end
  4185.     end
  4186.     if typeof(t)~='table' then return false end
  4187.     return true
  4188. end
  4189. function Term.from_native(term)
  4190.     check('native_terminal',term)
  4191.     return Term{
  4192.         size=Point(term.getSize()),
  4193.         color=term.isColor(),
  4194.         blink=true,
  4195.     }
  4196. end
  4197. local function wrap_obj(self,tMethods)
  4198.     for i,v in pairs(tMethods or self) do
  4199.         if type(v)=='function' then
  4200.             local f=self[i]
  4201.             self[i]=function(s,...)
  4202.                 if self==s then
  4203.                     return f(s,...)
  4204.                 else
  4205.                     return f(self,s,...)
  4206.                 end
  4207.             end
  4208.         end
  4209.     end
  4210. end
  4211. --[[process
  4212. e.g. shell
  4213. in out err
  4214. term
  4215. ---in out in out
  4216. ]]
  4217. local active={
  4218. 'setBackgoundColour',
  4219. 'setTextColour',
  4220. 'setCursorPos',
  4221. 'setCursorBlink',
  4222. 'write',
  4223. 'setSize',
  4224. 'scroll',
  4225. 'clear',
  4226. 'setPixel',
  4227. }
  4228. function Term:setSignals(bool)
  4229.     for _,k in ipairs(active) do
  4230.         local f=self['_'..k] or self[k]
  4231.         self[k]=bool and function(...)
  4232.             sched.signal(self,k,...)
  4233.             return f(...)
  4234.         end or f
  4235.     end
  4236. end
  4237. function Term:__init(opt)
  4238.     term_opt:drop(self,opt)
  4239.     self:_allocate()
  4240.     wrap_obj(self,native)
  4241. end
  4242. function Term:setCursorPos(x,y)
  4243.     self.pos:assign(x,y)
  4244. end
  4245. function Term:getCursorPos() return self.pos.x,self.pos.y end
  4246. function Term:setBackgroundColor(color) check('color',color) self.bcolor=color end
  4247. Term.setBackgroundColour=Term.setBackgroundColor
  4248. function Term:getBackgroundColor() return self.bcolor end
  4249. Term.getBackgroundColour=Term.getBackgroundColor
  4250. function Term:setTextColor(color) check('color',color) self.tcolor=color end
  4251. Term.setTextColour=Term.setTextColor
  4252. function Term:getTextColor() return self.tcolor end
  4253. Term.getTextColour=Term.getTextColor
  4254. function Term:isColor() return self.color end
  4255. Term.isColour=Term.isColor
  4256. function Term:setCursorBlink(bool) check('boolean',bool) self.blink=bool end
  4257. function Term:getCursorBlink() return self.blink end
  4258. function Term:write(txt)
  4259.     check('string',txt)
  4260.     local n=#txt
  4261.     local pos=self.pos
  4262.     if pos.x+n<=1 or pos.x> self.size.x then
  4263.         pos.x=pos.x+n
  4264.         return
  4265.     end
  4266.     if pos.x < 1 then
  4267.         txt=txt:sub(math.abs(pos.x)+2)
  4268.         pos.x=1
  4269.     end
  4270.     local line=self.matrix[pos.y]
  4271.     if line then
  4272.         for j=pos.x,math.min(pos.x-1+n,self.size.x) do
  4273.             line[j]={tc=self.tcolor,bc=self.bcolor,c=txt:sub(j-pos.x+1,j-pos.x+1)}
  4274.         end
  4275.     end
  4276.     pos.x=pos.x+n
  4277. end
  4278. function Term:setSize(self,size)
  4279.     self.size=size
  4280.     self:_allocate()
  4281. end
  4282. function Term:getSize()
  4283.     return self.size.x,self.size.y
  4284. end
  4285.  
  4286. function Term:scroll(n)
  4287.     check('number',n)
  4288.     n=(n-n%1)
  4289.     local ind,nind=n>0 and 1 or nil,n>0 and self.size.y or 1
  4290.     local matrix=self.matrix
  4291.     for i=1,math.abs(n) do
  4292.         table.remove(matrix,ind)
  4293.         matrix[nind]=self:_newLine()
  4294.     end
  4295. end
  4296. function Term:clear() self:_allocate() end
  4297. function Term:clearLine()
  4298.     if self.matrix[self.pos.y] then
  4299.         self.matrix[self.pos.y]=self:_newLine()
  4300.     end
  4301. end
  4302. function Term:_newLine()
  4303.     local line={}
  4304.     for j=1,self.size.x do
  4305.         line[j]={tc=self.tcolor,bc=self.bcolor,c=' '}
  4306.     end
  4307.     return line
  4308. end
  4309. function Term:_allocate()
  4310.     local X,Y = self.size.x,self.size.y
  4311.     self.matrix=self.matrix or {}
  4312.     for i=1,Y do
  4313.         self.matrix[i]=self:_newLine()
  4314.     end
  4315. end
  4316. local def_pos=Point(1,1)
  4317. function Term:blit_native(term,pos,section)
  4318.     pos=pos or def_pos
  4319.     section=section or Rectangle(def_pos,self.size)
  4320.     term.setCursorBlink(false)
  4321.     if self.blink then
  4322.         local cell=self.matrix[self.pos.y] and self.matrix[self.pos.y][self.pos.x]
  4323.         if cell then
  4324.             self._bcell=cell
  4325.             cell.bc,cell.tc=cell.tc,cell.bc
  4326.         else
  4327.             self._bcell=nil
  4328.         end
  4329.     end
  4330.     for i=section.s.y,section.e.y do
  4331.         local line=self.matrix[i]
  4332.         local tc,bc=line[1].tc,line[1].bc
  4333.         local tTxt={}
  4334.         for j=section.s.x,section.e.x do
  4335.             local tl,bl=line[j].tc,line[j].bc
  4336.             if tc~=tl or bc~=bl then
  4337.                 term.setCursorPos(j-#tTxt+pos.x-1,i+pos.y-1)
  4338.                 term.setTextColor(tc==0 and self.tcolor or tc)
  4339.                 term.setBackgroundColor(bc==0 and self.bcolor or bc)
  4340.                 term.write(table.concat(tTxt))
  4341.                 tc,bc=tl,bl
  4342.                 tTxt={}
  4343.             end
  4344.             table.insert(tTxt,line[j].c)
  4345.         end
  4346.         if tTxt[1] then
  4347.             term.setCursorPos(section.e.x-#tTxt+pos.x,i+pos.y-1)
  4348.             term.setTextColor(tc==0 and self.tcolor or tc)
  4349.             term.setBackgroundColor(bc==0 and self.bcolor or bc)
  4350.             term.write(table.concat(tTxt))
  4351.         end
  4352.     end
  4353.     if self._bcell then
  4354.         local cell=self._bcell
  4355.         cell.bc,cell.tc=cell.tc,cell.bc
  4356.         self._bcell=nil
  4357.     end
  4358. end
  4359. function Term:blit(term,pos,section)
  4360.     return self:blit_native(term,pos,section) --temporary?
  4361. end
  4362.  
  4363. function Term:setPixel(char,tcolor,bcolor,x,y)
  4364.     check('char,?|color,?|color,?|Point|number|table,?|number',char,tcolor,bcolor,x,y)
  4365.    
  4366.     if type(x)=='table' then
  4367.         x,y=x.x,x.y
  4368.         check('number,number',x,y)
  4369.     else
  4370.         x,y=x or self.pos.x, y or self.pos.y
  4371.     end
  4372.     if self.matrix[y] and self.matrix[y][x] then
  4373.         self.matrix[y][x]={c=char or ' ',tc=tcolor or self.tcolor,bc=bcolor or self.bcolor}
  4374.     end
  4375. end
  4376. function Term:copyState(term)
  4377.     term.setTextColor(self:getTextColor())
  4378.     term.setBackgroundColor(self:getBackgroundColor())
  4379.     term.setCursorPos(self:getCursorPos())
  4380. end
  4381.  
  4382. -- function Term:from_npaint(file)
  4383.     -- -- pos=pos or def_pos
  4384.     -- -- section=section or Rectangle(pos,self.size)
  4385.    
  4386.     -- for line in file:lines() do
  4387.         -- if section.x<
  4388.     -- end
  4389. -- end
  4390.  
  4391. function Term:_dump_key(k)
  4392.   local s={}
  4393.   for i=1, self.size.y do
  4394.     local txt={}
  4395.     table.foreach(self.matrix[i],function(_,v) table.insert(txt,tostring(type(v[k])=='number' and string.char(97+math.ceil(math.log(v[k],2))) or v[k])) end)
  4396.     txt=table.concat(txt)
  4397.     table.insert(s,txt)
  4398.   end
  4399.   return table.concat(s,'\n')
  4400. end
  4401. function Term:dump()
  4402.   return self:_dump_key'c',self:_dump_key'tc',self:_dump_key'bc'
  4403. end
  4404. function Term:blit_all(term)
  4405.     for i=1,self.size.y do
  4406.         local line=self.matrix[i]
  4407.         for j=1,self.size.x do
  4408.             local p=line[j]
  4409.             term.setCursorPos(j,i)
  4410.             term.setTextColor(p.tc)
  4411.             term.setBackgroundColor(p.bc)
  4412.             term.write(p.c)
  4413.         end
  4414.     end
  4415. end
  4416. -- assert(Term:implements(DC))
  4417. Term.test=function()
  4418.   rawset(_G,'t',Term{size=Point(term.getSize())})
  4419.   for i=1,t.size.y do
  4420.     t:setPixel('a',2^i,2^i,i,i)
  4421.   end
  4422.   sleep(1)
  4423.   term.clear()
  4424. --  t:setCursorPos(2,2)
  4425.   t:blit_native(term)
  4426.   sleep(1)
  4427. end
  4428.  
  4429.  
  4430. return Term]===================],"CoolisOS/bin/kernel/loadreq",true,"CoolisOS/bin/kernel/loadreq/init.lua",[===================[---require implementation in pure Lua for a sandbox environment, with support for globs and full directory tree search.
  4431. --Licensed under the MIT license, whatever that is.
  4432.  
  4433.  
  4434. local fs=fs
  4435. local string=string
  4436. local loadfile=loadfile
  4437. local error=error
  4438. local function log(...)
  4439.     return (_G.log and _G.log(...))
  4440. end
  4441.  
  4442. function getNameExpansion(s) --returns name and expansion from a filepath @s; special cases: ''->'',nil; '.'-> '','';
  4443.     local _,_,name,expa=string.find(s, '([^%./\\]*)%.(.*)$')
  4444.     return name or s,expa
  4445. end
  4446.  
  4447. function getDir(s) --returns directory from filepath @s
  4448.     return string.match(s,'^(.*)/') or '/'
  4449. end
  4450.  
  4451. vars={} --to allow edition
  4452. --vars.loaded={}
  4453. --function loadFile(path,_reload) --@_reload forces reload
  4454. --  if (vars.loaded[path]==nil) or _reload then
  4455. --      local fnFile, err = loadfile( path )
  4456. --      if not fnFile then error('load:'..'path=:'..path..'| '..(err or 'nil'),2) end
  4457. --      vars.loaded[path]=fnFile
  4458. --  end
  4459. --  return vars.loaded[path]
  4460. --end
  4461. --
  4462. ---iterator; replaces '?' in g by s and returns the resulting path if it is a file.
  4463. local function direct(g,s)
  4464.     g=string.gsub(g,'%?',s)
  4465.     if fs.exists(g) and not fs.isDir(g) then
  4466.         return g
  4467.     end
  4468. end
  4469. --add your finders here: must take (p,s) where p is where to search and s is what to search for.It must return a path.
  4470. vars.finders={direct}
  4471. vars.paths='?/init.lua;?.lua'
  4472.  
  4473. --helper vars for lua_requirer; other requirers may index theirs vars in loadreq.vars
  4474. vars.lua_requirer={
  4475. required={}, --to unrequire filepath s do require[s]=nil
  4476. required_envs={}, --to prevent garbage collection
  4477. requiring={}, --to throw error in case of recursive requiring;
  4478. }
  4479.  
  4480. --[[lua_requirer(path,cenv,env,renv,rerun,args)
  4481. Accepts empty or .lua extensions.
  4482. if the rerun flag is true, reloads the file even if it done it before;
  4483. if the file has been loaded already returns previous value;
  4484. if the file is being loaded returns nil, error_message
  4485. else:
  4486. loads file in @path;
  4487. sets it's env to @env, default {} with metatable with __index set to @renv, default _G;
  4488. calls the function with unpack(@args) and returns and saves either
  4489.     the function return
  4490.     a shallow copy of the functions environment
  4491. ]]
  4492.  
  4493. function lua_requirer(path,cenv,t)
  4494.     local env,renv,rerun,args=t.env,t.renv,t.rerun,t.args
  4495.    
  4496.     local err_prefix='lua_requirer:'
  4497.     local vars=vars.lua_requirer
  4498.     local _,ext=getNameExpansion(path)
  4499.     if not (ext=='' or ext=='lua' or ext==nil) then
  4500.         return nil, err_prefix..'wrong extension:'..ext
  4501.     end
  4502.    
  4503.     if vars.requiring[path] then
  4504.         return nil, err_prefix..'file is being loaded'
  4505.     end
  4506.     if not rerun and vars.required[path] then
  4507.         return vars.required[path]
  4508.     end
  4509.    
  4510.     local f,e=loadfile(path,path)
  4511.     if not f then
  4512.         return nil,err_prefix..'loadfile:'..e
  4513.     end
  4514.     env=env or {}
  4515.     env._FILE_PATH=path
  4516.     vars.required_envs[path]=env
  4517.     setfenv(f,env)
  4518.     renv=renv or _G
  4519.     setmetatable(env,{__index=renv})
  4520.     vars.requiring[path]=true
  4521.     local ok,r=pcall(f,args)
  4522.     vars.requiring[path]=nil
  4523.     if not ok then
  4524.         return nil,err_prefix..'while calling module:\n'..r
  4525.     elseif r then
  4526.         vars.required[path]=r
  4527.         return r
  4528.     else
  4529.         local t={}
  4530.         for i,v in pairs(env) do
  4531.             t[i]=v
  4532.         end
  4533.         vars.required[path]=t
  4534.         return t
  4535.     end
  4536. end
  4537.  
  4538. --replacement for os_loadAPI that keeps APIS to the caller's env
  4539. --local old_os_loadAPI=os.loadAPI
  4540. --new_os_loadAPI=function(p)
  4541. --  local cenv=getfenv(2)
  4542. --  local r,e=loadreq.lua_requirer(p,cenv)
  4543. --  if r then
  4544. --      local name=getNameExpansion(p)
  4545. --      protect(r)
  4546. --      cenv[p]=r
  4547. --  else
  4548. --      error('os.loadAPI(loadreq version):'..e..'\n'..'path='..p,2)
  4549. --  end
  4550. --end
  4551.  
  4552. --[[add your requirers here;
  4553. each must
  4554. take as arguments (path,cenv,...) where
  4555.     path is the path to required file
  4556.     cenv is the environment of the caller of @require
  4557.     ... are extra arguments passed to @require
  4558. return
  4559.     one value to be returned by @require
  4560.     false|nil, error_message in case of failure
  4561. ]]
  4562. vars.requirers={lua=lua_requirer}
  4563.  
  4564. function sufix(s)
  4565.     return string.gsub('@/?;@/?.lua;@/?/init.lua;@/?/?.lua;@/?/?;@','@',s)
  4566. end
  4567.  
  4568.  
  4569. local function _find(s,paths,caller_env)
  4570.     local err={'_find: finding '..tostring(s)}
  4571.    
  4572.     if paths then
  4573.     elseif caller_env.REQUIRE_PATH then
  4574.         paths=caller_env.REQUIRE_PATH
  4575.     elseif caller_env.PACKAGE_NAME and caller_env._FILE_PATH then
  4576.         paths=sufix(string.match(caller_env._FILE_PATH,'^(.-'..caller_env.PACKAGE_NAME..')'))..';'..vars.paths
  4577.     elseif  caller_env._FILE_PATH then
  4578.         paths=sufix(getDir(caller_env._FILE_PATH))..';'..vars.paths
  4579.     else
  4580.         paths=vars.paths
  4581.     end
  4582.    
  4583.     --replace . by / and .. by .
  4584.     s=string.gsub(s,'([^%.])%.([^%.])','%1/%2')
  4585.     s=string.gsub(s,'^%.([^%.])','/%1')
  4586.     s=string.gsub(s,'%.%.','.')
  4587.    
  4588.     local finders=vars.finders
  4589.    
  4590.     local finder,path
  4591.     for i=1,#finders do
  4592.         finder=finders[i]
  4593.         for search_path in string.gmatch(paths,';?([^;]+);?') do
  4594.             path=finder(search_path,s)
  4595.             if path then return path end
  4596.            
  4597.         end
  4598.     end
  4599.     table.insert(err,'_find:file not found:'..s..'\ncaller path='..(caller_env._FILE_PATH or 'not available'))
  4600.     local serr=table.concat(err,'\n')
  4601.     log('loadreq','ERROR','_find:%s',serr)
  4602.     return nil,serr
  4603. end
  4604. find=_find
  4605.  
  4606. local function _require(s,opt,caller_env)
  4607.     local err={}
  4608.     table.insert(err,'loadreq:require: while requiring '..tostring(s))
  4609.     local path,e=_find(s,opt.path,caller_env)
  4610.     if path==nil then
  4611.         table.insert(err,e)
  4612.         return nil, table.concat(err,'\n')
  4613.     end
  4614.     for req_name,requirer in pairs(vars.requirers) do
  4615.         local r,e=requirer(path,caller_env,opt)
  4616.         if r then
  4617.             return r,path
  4618.         else
  4619.             table.insert(err,e)
  4620.         end
  4621.     end
  4622.     return nil, table.concat(err,'\n')
  4623. end
  4624.  
  4625. --[[require(s,paths,...)
  4626. @paths is a string of paths separated by ';' where there can be '?'
  4627. -acquires @paths variable, by the following order;
  4628.     0-arg @paths
  4629.         Example (_FILE_PATH='myFolder/myFolder2/myAPI.lua'):
  4630.         myAPI=require('myFolder2.myAPI','myFolder/?.lua')
  4631.     1-REQUIRE_PATH in the caller's path, if existent
  4632.         Example (_FILE_PATH='myFolder/myFolder2/myAPI.lua'):
  4633.         REQUIRE_PATH='myFolder/?.lua'
  4634.         myAPI=require'myFolder2.myAPI'
  4635.     2-directory named PACKAGE_NAME in _FILE_PATH, if defined in the caller's environment
  4636.     with sufixes appended by @sufix and concatenated with @vars.paths.
  4637.     _FILE_PATH is set, for instance, by lua_loader in the files it loads.
  4638.         Example (_FILE_PATH='myFolder/myFolder3/myFolder/runningFile'):
  4639.         PACKAGE_NAME='myFolder'
  4640.         myAPI=require'myAPI' --@paths is 'myFolder/?;myFolder/?.lua;myFolder/?/init.lua;myFolder/?/?.lua;myFolder/?/?;myFolder'
  4641.     3-directory of _FILE_PATH, if defined
  4642.     with sufixes appended by @sufix and concatenated with @vars.paths.
  4643.         Example (_FILE_PATH='myFolder/runningFile'):
  4644.         myAPI=require'myAPI' --@paths is 'myFolder/?;myFolder/?.lua;myFolder/?/init.lua;myFolder/?/?.lua;myFolder/?/?;myFolder'
  4645.     [email protected] as set in loadreq.vars.paths
  4646. -replaces '.' in @s by '/' and '..' by '.'
  4647. --for all search_path in @paths
  4648.  -  for all iterators in vars.finders, iterates over the paths returned;
  4649.     default iterator:   see @direct
  4650. -for the first valid path, calls the loaders sequentially until one succeds,
  4651. in which case it returns the first value that the loader returns, else if it returns nil,e accumulates e as an error message
  4652. els, if all loaders fail, errors immediatly, printing all error messages
  4653. -in case of failure finding the path, errors with useful info
  4654. ]]
  4655.  
  4656. function require(s,opt)
  4657.     opt=opt or {}
  4658.     local t,e=_require(s,opt,getfenv(2))
  4659.     if t==nil then
  4660.         log('loadreq','ERROR','require:%s',e)
  4661.         error(e,1)
  4662.     else
  4663.         log('loadreq','INFO','require: success in requiring [%s]',e)
  4664.         return t
  4665.     end
  4666. end
  4667.  
  4668. ---same as require, but copies the returned API to the caller's environment
  4669. function include(s,opt)
  4670.     opt=opt or {}
  4671.     local caller_env=getfenv(2)
  4672.     local t,e=_require(s,opt,caller_env)
  4673.     if t then
  4674.         for i,v in pairs(t) do
  4675.             if type(i)=='string' and i:sub(1,1)~='_' then
  4676.                 caller_env[i]=v
  4677.             end
  4678.         end
  4679.         return true
  4680.     else
  4681.         log('loadreq','ERROR','include:%s',e)
  4682.         error(e,1)
  4683.     end
  4684. end
  4685.  
  4686. function reload(s,opt)
  4687.     opt=opt or {}
  4688.     opt.rerun=true
  4689.     return require(s,opt)
  4690. end
  4691.  
  4692. --protection utilities; these are meant more as a warning than OS-grade protection
  4693. vars.bProtected=true
  4694. local function protected_access(t,k,v)
  4695.     if vars.bProtected then
  4696.         error( "Attempt to write to protected" )
  4697.     else
  4698.         rawset( t, k, v )
  4699.     end
  4700. end
  4701. function protect(_t)--shallow protection for tables (slows down access to the tables themselves, not to their values, e.g. local t.a=protected_table.a print(a) should do the trick)
  4702.     local meta = getmetatable( _t )
  4703.     if meta == "Protected" then
  4704.         -- already hard protected
  4705.         return
  4706.     end
  4707.     if meta then
  4708.         meta.__newindex = protected_access
  4709.     else
  4710.         setmetatable( _t, {__newindex = protected_access} )
  4711.     end
  4712. end
  4713. function unprotect(_t)--removes the shallow protection
  4714.     local meta = getmetatable( _t )
  4715.     if not meta then
  4716.         return
  4717.     end
  4718.     vars.bProtected=false
  4719.     meta.__newindex=nil
  4720.     vars.bProtected=true
  4721. end
  4722.  
  4723. function permaProtect(_t) --same as the os.loadAPI does
  4724.     local meta = getmetatable( _t )
  4725.     if meta == "Protected" then
  4726.         -- already hard protected
  4727.         return
  4728.     end
  4729.     setmetatable( _t, {
  4730.         __newindex = function( t, k, v )
  4731.             if vars.bProtected then
  4732.                 error( "Attempt to write to protected" )
  4733.             else
  4734.                 rawset( t, k, v )
  4735.             end
  4736.         end,
  4737.         __metatable = 'Protected',
  4738.     } )
  4739. end
  4740.  
  4741. env=getfenv()
  4742. return env
  4743. ]===================],"CoolisOS/bin/kernel/log",true,"CoolisOS/bin/kernel/log/init.lua",[===================[------------------------------------------------------------------------------
  4744. -- Log library provides logging facilities.
  4745. -- The module exposes extension points. It is possible to provide both the custom printing function and the custom log saving function. <br />
  4746. -- The module is callable. Thus:
  4747. --    local log = require"log"
  4748. --    log("MODULE", "INFO", "message")
  4749. -- calls the @{#log.trace} function.
  4750. -- @module log
  4751. --
  4752. local assert,string,pcall,table,tostring,setmetatable,os,pairs,next,print,math,type,unpack=
  4753. assert,string,pcall,table,tostring,setmetatable,os,pairs,next,print,math,type,unpack
  4754. local base = _G
  4755.  
  4756. local util=require'kernel.util'
  4757. local check =require'kernel.checker'.check
  4758. local textutils=textutils
  4759. local string=string
  4760. --temporary
  4761. local pprint=pprint
  4762.  
  4763. --no more global access
  4764. local env=getfenv()
  4765. setmetatable(env,nil)
  4766.  
  4767. function s_to_real(t)
  4768.     local n_s=t%60
  4769.     local m=((t-n_s)/60)
  4770.     local n_m=m%60
  4771.     local h=((m-n_m)/60)
  4772.     return h,n_m,n_s
  4773. end
  4774. local os_time= function()
  4775.     local mc='Day '..os.day()..', '..textutils.formatTime(os.time())
  4776.     local t=os.clock()
  4777.     local h,n_m,n_s=s_to_real(t)
  4778.     local sec=tostring(n_s)
  4779.     local s,p,e=sec:match('^([^%.]*)(%.)([^%.]*)$')
  4780.     s=s or '0'
  4781.     p=p or '.'
  4782.     e=e or '0'
  4783.     s=string.rep('0',2-s:len())..s
  4784.     e=e..string.rep('0',2-e:len())
  4785.     sec=s..p..e
  4786.     local real=string.format('%sh%sm%ss',h,n_m,sec)
  4787.     return string.format('%s',sec)--string.format('%s;%s;%s',mc,real,sec)
  4788. end
  4789.  
  4790. -------------------------------------------------------------------------------
  4791. -- Log levels are strings used to filter logs.
  4792. -- Levels are to be used both in log filtering configuration (see @{#log.setLevel}) and each time
  4793. -- @{#log.trace} function is used to issue a new log.
  4794. --
  4795. -- Levels are ordered by verbosity/severity level.
  4796. --
  4797. -- While configuring log filtering, if you set a module log level to 'INFO' level for exemple, you
  4798. -- enable all logs *up to* 'INFO', that is to say that logs with 'WARNING' and 'ERROR' severities will
  4799. -- be displayed too.
  4800. --
  4801. -- Built-in values (in order from the least verbose to the most):
  4802. --    - 'NONE':    filtering only: when no log is wanted
  4803. --    - 'ERROR':   filtering or tracing level
  4804. --    - 'WARNING': filtering or tracing level
  4805. --    - 'INFO':    filtering or tracing level
  4806. --    - 'DETAIL':  filtering or tracing level
  4807. --    - 'DEBUG':   filtering or tracing level
  4808. --    - 'ALL':     filtering only: when all logs are to be displayed
  4809. -- @type levels
  4810. --
  4811. levels = {}
  4812. -- Severity name <-> Severity numeric value translation table (internal purpose only)
  4813. for k,v in pairs{ 'NONE', 'ERROR', 'WARNING', 'INFO', 'DETAIL', 'DEBUG', 'ALL' } do
  4814.     levels[k], levels[v] = v, k
  4815. end
  4816.  
  4817. -- -----------------------------------------------------------------------------
  4818. -- Default verbosity level.  
  4819. -- Default value is `"WARNING"`.
  4820. -- @field [parent=#log] #levels defaultlevel
  4821. -- See @{#log} for a list of existing levels.
  4822.  
  4823. local defaultlevel = defaultlevel or levels.WARNING
  4824.  
  4825. -- -----------------------------------------------------------------------------
  4826. -- Per module verbosity levels.
  4827. -- @field [parent=#log] modules
  4828. -- See @{#levels} to see existing levels.
  4829.  
  4830. local modules = modules or { }
  4831.  
  4832.  
  4833. -- -----------------------------------------------------------------------------
  4834. -- The string format of the timestamp is the same as what os.date takes.
  4835. -- Example: "%F %T"
  4836. -- #field [parent=#log] #string timestampformat
  4837. timestampformat = nil
  4838.  
  4839. -- -----------------------------------------------------------------------------
  4840. -- logger functions, will be called if non nil
  4841. -- the loggers are called with following params (module, severity, logvalue)
  4842. -- -----------------------------------------------------------------------------
  4843.  
  4844. -------------------------------------------------------------------------------
  4845. -- Default logger for instant display.
  4846. -- This logger can be replaced by a custom function.  
  4847. -- It is called only if the log needs to be traced.
  4848. --
  4849. -- @function [parent=#log] displaylogger
  4850. -- @param #string module string identifying the module that issues the log
  4851. -- @param severity string representing the log level, see @{log#levels}.
  4852. -- @param msg string containing the message to log.
  4853. --
  4854. displaylogger = function(_, _, ...)
  4855.    -- if base.print then base.print(...) end
  4856. end
  4857.  
  4858. -------------------------------------------------------------------------------
  4859. -- Logger function for log storage.  
  4860. -- This logger can be replaced by a custom function.  
  4861. -- There is no default store logger.  
  4862. -- It is called only if the log needs to be traced (see @{#log.musttrace}) and after the log has been displayed using {displaylogger}.
  4863. --
  4864. -- @function [parent=#log] storelogger
  4865. -- @param module string identifying the module thats issues the log
  4866. -- @param severity string representing the log level, see @{log#levels}.
  4867. -- @param msg string containing the message to log.
  4868. --
  4869.  
  4870. storelogger = nil
  4871.  
  4872. -------------------------------------------------------------------------------
  4873. -- Format is a string used to apply specific formating before the log is outputted.  
  4874. -- Within a format, the following tokens are available (in addition to standard text)
  4875. --
  4876. --- %l => the actual log (given in 3rd argument when calling log() function)
  4877. --- %t => the current date
  4878. --- %m => module name
  4879. --- %s => log level (severity), see @{log#levels}
  4880. --@field [parent=#log] #string format
  4881. format = nil
  4882.  
  4883. local function loggers(...)
  4884.     if displaylogger then displaylogger(...) end
  4885.     if storelogger then storelogger(...) end
  4886. end
  4887.  
  4888. -------------------------------------------------------------------------------
  4889. -- Determines whether a log must be traced depending on its severity and the
  4890. -- module issuing the log. This function is mostly useful to protect `log()`
  4891. -- calls which involve costly computations
  4892. --
  4893. -- @usage
  4894. --
  4895. --    if log.musttrace('SAMPLE', 'DEBUG') then
  4896. --        log('SAMPLE', 'DEBUG', "Here are some hard-to-compute info: %s",
  4897. --            computeAndReturnExpensiveDebugString())
  4898. --    end
  4899. --
  4900. -- @function [parent=#log] musttrace
  4901. -- @param modulename string identifying the module that issues the log.
  4902. -- @param severity string representing the log level, see @{log#levels}.
  4903. -- @return `nil' if the message of the given severity by the given module should
  4904. -- not be printed.
  4905. -- @return `true` if the message should be printed.
  4906. --
  4907. function musttrace(module, severity)
  4908.     -- get the log level for this module, or default log level
  4909.     local lev, sev = modules[module] or defaultlevel, levels[severity]
  4910.     return not sev or lev >= sev
  4911. end
  4912.  
  4913. local function debug_getinfo(...)
  4914.     return (base.debug and base.debug.getinfo or tostring)(...)
  4915. end
  4916. -------------------------------------------------------------------------------
  4917. -- Prints out a log entry according to the module and the severity of the log entry.
  4918. --
  4919. -- This function uses @{#log.format} and @{#log.timestampformat} to create the
  4920. -- final message string. It calls @{#log.displaylogger} and @{#log.storelogger}.
  4921. --
  4922. -- @function [parent=#log] trace
  4923. -- @param modulename string identifying the module that issues the log.
  4924. -- @param severity string representing the level in @{log#levels}.
  4925. -- @param fmt   string format that holds the log text the same way as string.format does.
  4926. --              function must return fmt (string) , vararg
  4927. -- @param varargs additional arguments can be provided (as with string.format).
  4928. -- @usage trace("MODULE", "INFO", "message=%s", "sometext").
  4929. --
  4930. function trace(module, severity, fmt, ...)
  4931.     local args
  4932.     if type(fmt)=='function' then
  4933.         local t={fmt(...)}
  4934.         fmt=table.remove(t,1)
  4935.         args=t
  4936.     else args={...} end
  4937.     check('string,string,string',module, severity, fmt)
  4938.     if not musttrace(module, severity) then return end
  4939.     local c, s = pcall(string.format,fmt, unpack(util.map_args(args,function(v) if (type(v)=='number' or type(v)=='string') then return v else return debug_getinfo(v) end end)))
  4940.     if c then
  4941.         local t
  4942.         local function sub(p)
  4943.             if     p=="l" then return s
  4944.             elseif p=="t" then t = t or tostring(os_time(timestampformat)) return t
  4945.             elseif p=="m" then return module
  4946.             elseif p=="s" then return severity
  4947.             else return p end
  4948.         end
  4949.         local out = (format or "%t %m-%s: %l"):gsub("%%(%a)", sub)
  4950.         loggers(module, severity, out)
  4951.     else -- fallback printing when the formating failed. The fallback printing allow to safely print what was given to the log function, without crashing the thread !
  4952.         --trace(module, severity, "\targs=("..table.concat(args, " ")..")" )
  4953.         loggers(module, severity, "Error in the log formating! ("..tostring(s)..") - Fallback to raw printing:" )
  4954.         loggers(module, severity, string.format("\tmodule=(%s), severity=(%s), format=(%q), args=(%s)", module, severity, fmt,table.concat(util.map_args(args,debug_getinfo),',') ))
  4955.     end
  4956. end
  4957.  
  4958.  
  4959. -------------------------------------------------------------------------------
  4960. -- Sets the log level for a list of module names.
  4961. -- If no module name is given, the default log level is affected
  4962. -- @function [parent=#log] setLevel
  4963. -- @param slevel level as in @{log#levels}
  4964. -- @param varargs Optional list of modules names (string) to apply the level to.
  4965. -- @return nothing.
  4966. --
  4967. function setLevel(slevel, ...)
  4968.     local mods = {...}
  4969.     local nlevel = levels[slevel] or levels['ALL']
  4970.     if not levels[slevel] then
  4971.         trace("LOG", "ERROR", "Unknown severity %q, reverting to 'ALL'", tostring(slevel))
  4972.     end
  4973.     if next(mods) then for _, m in pairs(mods) do modules[m] = nlevel end
  4974.     else defaultlevel = nlevel end
  4975. end
  4976.  
  4977. ---
  4978. local wrapped=setmetatable({},{__mode='k'})
  4979. function wrap_class(k)
  4980.     assert(not wrapped[k])
  4981.     local old=k.__init
  4982.     rawset(k,'__init',function(...)
  4983.         old(...)
  4984.         env(tostring(k.__name),'DETAIL','initiated obj %s with args ',debug_getinfo(obj),args_tostring(...))
  4985.     end)
  4986.     wrapped[k]=old
  4987. end
  4988. function unwrapp_class(k)
  4989.     if wrapped[k] then
  4990.         rawset(k,'__init',wrapped[k])
  4991.         wrapped[k]=nil
  4992.     end
  4993. end
  4994. -- -----------------------------------------------------------------------------
  4995. -- Make the module callable, so the user can call log(x) instead of log.trace(x)
  4996. -- -----------------------------------------------------------------------------
  4997. setmetatable(env, {__call = function(_, ...) return trace(...) end })
  4998. return env
  4999.  
  5000. ]===================],"CoolisOS/bin/kernel/log/store.lua",[===================[local store={}
  5001. local log_dir=fs.combine(_INSTALL_PATH,'ect/log')
  5002. if not fs.exists(log_dir) then
  5003.     fs.makeDir(log_dir)
  5004. end
  5005.  
  5006.  
  5007. local his={}
  5008.  
  5009. local function flush_file(s)
  5010.     local f=fs.open(s,'a')
  5011.     for i,v in pairs(his[s]) do
  5012.         f.writeLine(v)
  5013.     end
  5014.     f.close()
  5015.     his[s]=nil
  5016. end
  5017.  
  5018. function store.flush(module)
  5019.     if not module then
  5020.         for s,t in pairs(util.shcopy(his)) do
  5021.             flush_file(s)
  5022.         end
  5023.     else
  5024.         local s=fs.combine(log_dir,module..'.log')
  5025.         flush_file(s)
  5026.     end
  5027. end
  5028.  
  5029. store.instant=false
  5030. function store.append(module,msg)
  5031.     local s=fs.combine(log_dir,module..'.log')
  5032.     his[s]=his[s] or {}
  5033.     table.insert(his[s],msg)
  5034.     if store.instant==true then
  5035.         flush_file(s)
  5036.     end
  5037. end
  5038.  
  5039. function store.reset(module)
  5040.     if module then
  5041.         fs.open(fs.combine(log_dir,module..'.log'),'w').close()
  5042.     else
  5043.         fs.delete(log_dir)
  5044.         fs.makeDir(log_dir)
  5045.     end
  5046. end
  5047. log.storelogger=function(module,severity,msg)
  5048.     store.append(module,msg)
  5049.     store.append('log',msg)
  5050. end
  5051. return store]===================],"CoolisOS/bin/kernel/sched",true,"CoolisOS/bin/kernel/sched/barrier.lua",[===================[local check=require 'kernel.checker'.check
  5052.  
  5053. PACKAGE_NAME='sched'
  5054.  
  5055. local sched=require 'init'
  5056.  
  5057. --------------------------------------------------------------------------------
  5058. -- Object metatable/class
  5059. --------------------------------------------------------------------------------
  5060. local B={__type='barrier'};B.__index=B
  5061.  
  5062. --------------------------------------------------------------------------------
  5063. -- A registry of all currently active barriers. This is intended as a debug aid,
  5064. -- and can be safely commented out if not needed
  5065. --------------------------------------------------------------------------------
  5066. sched.barriers = setmetatable({}, {__mode='kv'})
  5067.  
  5068. function barrier(n)
  5069.     check ('integer',n)
  5070.     local instance={n=n}
  5071.     if sched.barriers then
  5072.         sched.barriers[tostring(instance):match(':.(.*)')]=instance
  5073.     end
  5074.     setmetatable(instance,B)
  5075.     return instance
  5076. end
  5077.  
  5078. B.reach=function(self)
  5079.     if self.n<=1 then
  5080.         self.n=0
  5081.         sched.signal(self,'zero')
  5082.     else
  5083.         self.n=self.n-1
  5084.         sched.wait(self,'zero')
  5085.     end
  5086. end
  5087.  
  5088. return barrier]===================],"CoolisOS/bin/kernel/sched/catalog.lua",[===================[--- A general purpose Catalog.
  5089. -- The catalog is used to give tasks well known names for sharing purposes.
  5090. -- It also allows synchronization, by blocking the requester until the object
  5091. -- is made available. Catalogs themselves are made available under a Well Known
  5092. -- name. Typical catalogs are "tasks", "mutexes" and "pipes".
  5093. -- The catalog does not check for multiple names per object.
  5094. -- @module catalog
  5095. -- @usage local tasks = require 'catalog'()
  5096. --...
  5097. --tasks:register('a task', sched.Task.running)
  5098. --...
  5099. --local a_task=tasks:waitFor('a task')
  5100. -- @alias M
  5101. include'kernel.class'
  5102. local log = require'kernel.log'
  5103. local check=require'kernel.checker'.check
  5104.  
  5105. local named=setmetatable({},{__mode='kv'})
  5106.  
  5107. class.Catalog()
  5108. local C=Catalog
  5109. C.named=named
  5110. function C:__init()
  5111.     self.objs=setmetatable({},{__mode='kv'})
  5112. end
  5113. function C:register(obj,name)
  5114.     if type(obj)~='table' then error('not a table',2) end
  5115.     if self.objs[name]~=nil and self.objs[name]~=obj then error('name taken',2) end
  5116.     self.objs[obj]=name
  5117.     self.objs[name]=obj
  5118.     sched.signal(self,'+'..name,obj)
  5119.    
  5120.     named[obj]=named[obj] or setmetatable({},{__mode='kv'})
  5121.     named[obj][self]=true
  5122. end
  5123. function C:unregister(id)
  5124.     local s = self.objs[id]
  5125.     local name=type(s)=='string' and s or id
  5126.     self.objs[s]=nil
  5127.     self.objs[id]=nil
  5128.    
  5129.     if named[obj] then
  5130.         named[obj][self]=nil
  5131.     end
  5132.     sched.signal(self,'-'..name,obj)
  5133. end
  5134. function C:waitFor(name,timeout)
  5135.     check('string',name)
  5136.     log('catalog', 'INFO', 'catalog %s queried for name "%s" by %s',self, name,sched.me())
  5137.    
  5138.     local obj
  5139.     if self[name] then return self[name] else
  5140.         local em,ev,o=sched.wait(self,'+'..name,timeout)
  5141.         if em==self then obj=o end
  5142.     end
  5143.     log('catalog', 'INFO', 'catalog %s queried for name "%s" by %s, found %s',self, name,sched.me(),obj)
  5144.     return obj
  5145. end
  5146. function C:__tostring()
  5147.     local t={}
  5148.     for i,v in pairs(self.objs) do
  5149.         if type(i)=='string' then t[i]=i..'->'..debug.getinfo(v) end
  5150.     end
  5151.     return debug.getinfo(self)..'\n'..pstring(t,1)
  5152. end
  5153.  
  5154. sched.Catalog=Catalog]===================],"CoolisOS/bin/kernel/sched/init.lua",[===================[include'kernel.class'
  5155. local log=require'kernel.log'
  5156. local check=require'kernel.checker'.check
  5157. local Linked=require 'utils.linked'
  5158. local table=table
  5159. local pairs=pairs
  5160.  
  5161. local sched,Obj,Sync,Task,timer,platform
  5162. local os_time
  5163.  
  5164. local fil
  5165. --[[
  5166. 2D array of sets of objs, fil[emitter][event][obj]=true
  5167. wildcards for emitter, event are '*'; can only be used for listening
  5168. reserved values; do not use for custom signals:
  5169.     -emitters:
  5170.         'timer'     -timer module;
  5171.         'platform'  -events yielded to the scheduler by os.pullEventRaw
  5172. ]]
  5173.  
  5174.  
  5175. ---emits a signal with emitter @emitter, event @event and parameters @vararg (...)
  5176. --can be called recursively; be careful not to signal the same entry which is being run
  5177. --to use infinite loops of signals (e.g. A->B->A) blocking the scheduler, use @Task or @Call instances.
  5178. local signal = function (emitter,event,...)
  5179.     log('sched', 'DEBUG', "SIGNAL [%s].[%s]", emitter, event)
  5180.     local function walk_event(evl,emitter,event,...)
  5181.         local copy={}
  5182.         for obj,val in pairs(evl) do
  5183.             copy[obj]=val
  5184.         end
  5185.         for obj,val in pairs(copy) do
  5186.             -- if d then print(obj) end
  5187.             obj:handle(emitter,event,...)
  5188.         end
  5189.     end
  5190.    
  5191.     local function walk_emitter(eml,emitter,event,...)
  5192.         local evl=eml[event]
  5193.         if evl then
  5194.             walk_event(evl,emitter,event,...)
  5195.         end
  5196.         evl=eml['*']
  5197.         if evl then
  5198.             walk_event(evl,emitter,event,...)
  5199.         end
  5200.     end
  5201.    
  5202.     local eml=fil[emitter]
  5203.     if eml then
  5204.         walk_emitter(eml,emitter,event,...)
  5205.     end
  5206.     local eml=fil['*']
  5207.     if eml then
  5208.         walk_emitter(eml,emitter,event,...)
  5209.     end
  5210.    
  5211.     return true
  5212. end
  5213.  
  5214. --[[Class that Task,Sync implement and that describes what can be put into the waiting table @fil.
  5215. --Objs instances keep track of which signals call their @handle field in their @fil field;
  5216. --their @parent and @subs fields maintain a tree-like hierarchy used to destroy @subs from an object before destroying the object itself.
  5217. --Objs expect to have defined a handle field consisting of a function used to process signals received, syncronously:
  5218. --@handle is a function called with args (obj,emitter,event,...) everytime a signal (emitter,event,...) that obj is linked too is emitted.
  5219. ]]
  5220. Obj=class('Obj')
  5221. do
  5222. local O=Obj
  5223. --@name is an optional parameter to set a debugging name
  5224. function O:__init()
  5225.     self.fil={}
  5226.     self.subs={}
  5227.     if sched.running then self:setParent(sched.running) end
  5228. end
  5229.  
  5230. ---Takes a link descriptor and tranforms them into a a proper link table for Obj methods to consume
  5231. --supports emitter,ev1,ev2,...,timeout
  5232. --or {[emt1]={ev1,ev2,...},...},timeout
  5233. local function get_args(...)
  5234.     local args={...}
  5235.     local nargs=#args
  5236.     local t,timeout
  5237.     if type(args[nargs])=='number' then
  5238.         timeout=args[nargs]
  5239.         nargs=nargs-1
  5240.     end
  5241.     if nargs~=0 then
  5242.         if nargs==1 and typeof(args[1])=='table' then
  5243.             t=args[1]
  5244.         else
  5245.             t={[args[1]]={nargs==1 and '*' or unpack(args,2,nargs)}}
  5246.         end
  5247.     end
  5248.     return t,timeout
  5249. end
  5250.  
  5251. --helper
  5252. local add_timer=function(t,nd)
  5253.     t=t or {}
  5254.     if nd then
  5255.         if not t[timer] then
  5256.             t[timer]={nd}
  5257.         else
  5258.             table.insert(t[timer],nd)
  5259.         end
  5260.     end
  5261.     return t
  5262. end
  5263.  
  5264. function get_t(...)
  5265.     local t,timeout=get_args(...)
  5266.     if timeout then t=add_timer(t,timeout+os_time()) end
  5267.     return t
  5268. end
  5269.  
  5270. ---Registers @obj in the waiting table @fil in the waiting sets described by the link table @t
  5271. function O:link(...)
  5272.     local t=get_t(...)
  5273.     if t==nil then return end
  5274.     local ofil=self.fil
  5275.     local root=self.__root
  5276.     local fil_tev,ofil_tev,fil_tobj
  5277.     for em,tev in pairs(t) do
  5278.         if type(tev)~='table' then error('Wrong struct for link',2) end
  5279.         fil_tev=fil[em]
  5280.         ofil_tev=ofil[em]
  5281.         if not ofil_tev then
  5282.             ofil[em]={}
  5283.             ofil_tev=ofil[em]
  5284.             if not fil_tev then fil[em]={} fil_tev=fil[em] end
  5285.         end
  5286.         local ev
  5287.         for i=1,#tev do
  5288.             ev=tev[i]
  5289.             ofil_tev[ev]=true
  5290.             fil_tobj=fil_tev[ev]
  5291.             if not fil_tobj then fil_tev[ev]={} fil_tobj=fil_tev[ev] end
  5292.             fil_tobj[root]=true
  5293.         end
  5294.     end
  5295. end
  5296.  
  5297. ---Unregisters @obj in the waiting table @fil from the waiting sets described by the link table @t
  5298. function O:unlink(...)
  5299.     local r=self.__root
  5300.     local t=get_t(...)
  5301.     if t==nil then return end
  5302.     local ofil=self.fil
  5303.     local fil_tev,ofil_tev,fil_tobj
  5304.     for em,tev in pairs(t) do
  5305.         ofil_tev=ofil[em]
  5306.         if ofil_tev then
  5307.             fil_tev=fil[em]
  5308.             local ev
  5309.             for i=1,#tev do
  5310.                 ev=tev[i]
  5311.                 if ofil_tev[ev] then
  5312.                     ofil_tev[ev]=nil
  5313.                    
  5314.                     fil_tobj=fil_tev[ev]
  5315.                     fil_tobj[r]=nil
  5316.                     if not next(fil_tobj) then fil_tev[ev]=nil end
  5317.                 end
  5318.             end
  5319.             if not next(ofil_tev) then ofil[em]=nil end
  5320.             if not next(fil_tev) then fil[em]=nil end
  5321.         end
  5322.     end
  5323. end
  5324.  
  5325. ---Unregisters @obj from all the waiting sets it is linked to.
  5326. function O:reset()
  5327.     local fil_tev
  5328.     local r=self.__root
  5329.     for em,tev in pairs(self.fil) do
  5330.         fil_tev=fil[em]
  5331.         if fil_tev then
  5332.             for ev in pairs(tev) do
  5333.                 -- print(ev,'|',self,'|',fil_tev[ev],'|',fil_tev[ev][self])
  5334.                 if fil_tev[ev] then
  5335.                     fil_tev[ev][r]=nil
  5336.                     if not next(fil_tev[ev]) then fil_tev[ev]=nil end
  5337.                 end
  5338.             end
  5339.             if not next(fil_tev) then fil[em]=nil end
  5340.         end
  5341.     end
  5342.     self.fil={}
  5343. end
  5344.  
  5345. local ending={n=0}
  5346. --helper
  5347. ---Kills @obj 's subs and removes it from the waiting sets.
  5348. function O:silent_destroy()
  5349.     local root=self.__root
  5350.     if ending[root] then
  5351.         error('Detected recursion in Obj.finalize: ending stack='..pstring(ending),2)
  5352.     else
  5353.         ending.n=ending.n+1
  5354.         ending[root]=ending.n
  5355.     end
  5356.     --handle subs
  5357.     while next(self.subs) do
  5358.         next(self.subs):destroy()
  5359.     end
  5360.    
  5361.     if self.parent then
  5362.         self.parent.Obj.subs[root]=nil
  5363.     end
  5364.     --remove self from the waiting sets
  5365.     self:reset()
  5366.    
  5367.     --remove self from the action queue
  5368.     sched.queue:remove(root)
  5369.    
  5370.     ending[root]=nil
  5371.     ending.n=ending.n-1
  5372. end
  5373.  
  5374. ---same as @O:silent_destroy, but throws some useful warning signals.
  5375. function O:destroy(...)
  5376.     if not self.destroyed then
  5377.         local r=self.__root
  5378.         signal(r,'dying',...) --warns subs
  5379.         self:silent_destroy()
  5380.         signal(r,'dead',...)
  5381.         self.destroyed=true
  5382.     end
  5383. end
  5384.  
  5385. local function check_tree(self,new_parent,seen)
  5386.     if new_parent==nil then return true,seen end
  5387.     new_parent=new_parent.__root
  5388.     local r=self.__root
  5389.     seen=seen or {r,[r]=true}
  5390.     if seen[new_parent] then return false,seen end
  5391.     table.insert(seen,new_parent)
  5392.     seen[new_parent]=true
  5393.     return check_tree(new_parent,new_parent.Obj.parent,seen)
  5394. end
  5395. ---Changes  an @obj parent field.
  5396. function O:setParent(parent)
  5397.     local rparent,oparent=parent.__root,parent.Obj
  5398.     local root=self.__root
  5399.     local ok, t=check_tree(self,self.parent)
  5400.     if not ok then error('Cycle detected in scheduler hierarchy;debug:'..pstring(t),2) end
  5401.     if rparent==root then error("A scheduler object cannot be it's own parent",2) end
  5402.     if self.parent then self.parent.Obj.subs[root]=nil end
  5403.     self.parent=rparent
  5404.     oparent.subs[root]=true
  5405.     log('sched','DETAIL','(%s) parent set to (%s) by (%s)',self.__root,(parent and parent.__root),sched.running or 'nil')
  5406. end
  5407.  
  5408. local TIMEOUT_TOKEN={}
  5409. ---helpers for linking @obj to timer signals
  5410. function O:setTimeout(timeout)
  5411.     if type(timeout)~='number' then
  5412.         error('timeout must be number',2)
  5413.     else
  5414.         timeout=timer.norm(timeout)
  5415.     end
  5416.     self:cancelTimeout()
  5417.     self[TIMEOUT_TOKEN]={
  5418.     timeout=timeout,
  5419.     td={timer={timeout+os_time()}},
  5420.     }
  5421.     self:link(self[TIMEOUT_TOKEN].td)
  5422.     return self
  5423. end
  5424.  
  5425. ---cancels the current timeout and sets a new one in @timeout seconds, where @timeout was set by @O:setTimeout
  5426. function O:resetTimeout()
  5427.     local td=self[TIMEOUT_TOKEN]
  5428.     if td then
  5429.         self:unlink(td.td)
  5430.         td.td[timer][1]=os_time()+td.timeout
  5431.         self:link(self.td.td)
  5432.     end
  5433. end
  5434.  
  5435. ---cancels the current timeout
  5436. function O:cancelTimeout()
  5437.     local td=self[TIMEOUT_TOKEN]
  5438.     if td then
  5439.         self:unlink(td.td)
  5440.         self.td=nil
  5441.     end
  5442. end
  5443.  
  5444. function O:__debug()
  5445.     local fil={}
  5446.     for i,v in pairs(self.fil) do
  5447.         local k=debug.getinfo(i)
  5448.         fil[k]={}
  5449.         for j in pairs(v) do
  5450.             table.insert(fil[k],debug.getinfo(j))
  5451.         end
  5452.     end
  5453.     return string.format('%s;   \nWait descriptor:%s',debug.objinfo(self),pstring(fil))
  5454. end
  5455. end
  5456.  
  5457.  --[[syncronous calls; are called as soon as the signal is received, but can't block as tasks do
  5458. once are one-use,
  5459. on are permanent,
  5460. ]]
  5461. Sync=class('Sync',Obj)
  5462. do
  5463. local S=Sync
  5464. local sync_once_handle = function(self,...)
  5465.     local sync=self.Sync
  5466.     local running=sched.running
  5467.     sched.running=self
  5468.     sync.f(...)
  5469.     self:destroy()
  5470.     sched.running = running
  5471. end
  5472. local sync_on_handle=function(self,...)
  5473.     local running=sched.running
  5474.     sched.running=self
  5475.     local sync=self.Sync
  5476.     sync.f(...)
  5477.     self:resetTimeout()
  5478.     sched.running=running
  5479. end
  5480. function S:__init(f,mode)
  5481.     check('function',f)
  5482.     mode=mode or 'on'
  5483.     Obj:__init(self)
  5484.     if mode=='once' then
  5485.     elseif mode=='on' then
  5486.     else error('mode?',2) end
  5487.     self.f=f
  5488.     self.mode=mode
  5489.     log('sched','INFO','(%s) created with mode %s by (%s)',self,mode,sched.running or 'nil')
  5490. end
  5491. function S:handle(...)
  5492.     if self.mode=='on' then
  5493.         sync_on_handle(self,...)
  5494.     else
  5495.         sync_once_handle(self,...)
  5496.     end
  5497. end
  5498. end
  5499. --asyncronous calls through coroutines
  5500. Task=class('Task',Obj)
  5501. do
  5502. local T=Task
  5503. ---Creates a task object in paused mode;
  5504. ---fields set by Task.new are
  5505. --co: matching coroutine
  5506. --args: table of args to unpack and pass to co
  5507. --parent: parent task
  5508. --subs: sub tasks (see @{Task.setSub} and @{Task.setParent}
  5509. --name: name used for logging and result of tostring(task)
  5510. --Can take either (f) or (name,f) as args
  5511. --@return task
  5512. function T:__init(f,...)
  5513.     check('function',f)
  5514.     Obj:__init(self)
  5515.     self.co=coroutine.create( f )
  5516.     self._resume=function(co)
  5517.         s,m=coroutine.resume(self.co,unpack(self.args))
  5518.         self._resume=coroutine.resume
  5519.         return s,m
  5520.     end
  5521.     self.args={...}
  5522.     log('sched', 'INFO', 'created (%s) from function (%s) by (%s)', self, f,sched.running or 'nil')
  5523. end
  5524.  
  5525. ---Schedules a task for execution with args (...)
  5526. --If T:handle is called several times before resuming the task, task.args will be overwritten and the last args set will be the last ones.
  5527. function T:handle(...)
  5528.     self.args={...} --no point in catching args after nil, since self.args is unpacked before returning to the task.
  5529.     sched.queue:push(self)
  5530.     sched.ready=true
  5531.    
  5532.     log('sched', 'DETAIL', 'Task:handle rescheduling (%s) to receive SIGNAL [%s].[%s]',
  5533.     self,...)
  5534.     return self
  5535. end
  5536.  
  5537. ---Runs a task with initial args ...
  5538. --@param vararg optional arguments to start the task with
  5539. --@return task
  5540. function T:run(...)
  5541.     self.args={...}
  5542.     sched.queue:push(self)
  5543.     log('sched', 'INFO', "Task.run scheduling (%s)", self)
  5544.     return self
  5545. end
  5546.  
  5547. --- Finishes a task and destroys it's subs.
  5548. -- @param self task to terminate (see @{Task.new})
  5549. -- @return  task
  5550. function T:destroy()
  5551.     if self.status~='dead' then
  5552.         log('sched', 'INFO', "Task.destroy destroying (%s) from (%s)",self,sched.running or 'nil')
  5553.         self.Obj:destroy()
  5554.         self.status='dead'
  5555.         if Task.running and Task.running.status=='dead' and Task.running.co==coroutine.running() then
  5556.             coroutine.yield()
  5557.         end
  5558.     end
  5559.     return self
  5560. end
  5561.  
  5562. function T:resume()
  5563.     sched.running = self
  5564.    
  5565.     local co=self.co
  5566.     Task.running=self
  5567.    
  5568.     log('sched', 'DETAIL', "Resuming (%s)", self)
  5569.     local success, msg = self._resume(co)
  5570.     log('sched', 'DETAIL', "Exited (%s)", self)
  5571.     Task.running=nil
  5572.     self.args={}
  5573.     sched.running = nil
  5574.     if not success then
  5575.         -- report the error msg
  5576.         log('sched', 'ERROR', "In (%s):%s",self,msg)
  5577.         signal(self, "error",success, msg)
  5578.         --preserve events/subs for error catchers to analize, and then finalize
  5579.         self:destroy(success,msg)
  5580.     elseif coroutine.status (co) == "dead" then --If the coroutine died, signal it for those who synchronize on its termination.
  5581.         log('sched', 'INFO', "(%s) is dead", self)
  5582.         self:destroy(success,msg)
  5583.     end
  5584. end
  5585.  
  5586. --- Waits for a signal
  5587. --Can only be called from a task
  5588. --If called with no arguments, yields and reschedules for execution
  5589. --If called with false as argument, yields without rescheduling for execution
  5590. -- @param vararg an entries descriptor for the signal (see @{get_args})
  5591. -- @return  emitter, event, parameters
  5592. function T:wait(...)
  5593.     local task = self
  5594.     if task.co~=coroutine.running() then error('calling Task.wait outside a task/inside a task but inside another coroutine',2) end
  5595.     if (...)==nil then
  5596.         sched.queue:push(task)
  5597.         log('sched', 'DETAIL', "Task.wait rescheduling (%s) for resuming ASAP", task)  
  5598.     elseif ... then
  5599.         task:link(...)
  5600.         log('sched', 'DETAIL', "(%s) waiting", task)
  5601.     else
  5602.         log('sched', 'DETAIL', "(%s) waiting for pre-set signals", task)
  5603.     end
  5604.     coroutine.yield ()
  5605.     if ... then
  5606.         task:reset()
  5607.     end
  5608.     return unpack(task.args)
  5609. end
  5610.  
  5611. ---resets the Task class vars
  5612. function Task._reset()
  5613.     Task.running=nil
  5614. end
  5615.  
  5616. ---Some pre-built utilities for tasks
  5617. --- Create a task that listens for a signal.
  5618. -- @param f function to be called when the signal appears. The signal
  5619. -- is passed to f as parameter. The signal will be provided as
  5620. -- emitter, event, parameters, just as the result of a @{wait}
  5621. -- @param vararg a Wait Descriptor for the signal (see @{get_args})
  5622. -- @return task in the scheduler
  5623. Task.sigrun= function (f,...)
  5624.     local ff=function()
  5625.         while true do
  5626.             f(sched.wait(false))
  5627.         end
  5628.     end
  5629.     local t=Task(ff)
  5630.     t:link(...)
  5631.     return t
  5632. end
  5633. --- Create a task that listens for a signal, once.
  5634. -- @param f function to be called when the signal appears. The signal
  5635. -- is passed to f as parameter. The signal will be provided as
  5636. -- _emitter, event, parameters_, just as the result of a @{wait}
  5637. -- @param vararg a Wait Descriptor for the signal (see @{get_args})
  5638. -- @return task in the scheduler
  5639. Task.sigrunonce= function (f,...)
  5640.     local ff=function()
  5641.         f(sched.wait(false))
  5642.     end
  5643.     local t=Task(ff)
  5644.     t:link(...)
  5645.     return t
  5646. end
  5647. end
  5648.  
  5649.  
  5650. do
  5651. sched={
  5652. --modules and respective shortcuts
  5653. signal=signal,
  5654. emit=function(...)
  5655.     sched.signal(sched.me(),...)
  5656. end,
  5657.  
  5658. Obj=Obj,
  5659. ready=false,
  5660. me=function() return sched.running end,
  5661. Task=Task,
  5662. Sync=Sync,
  5663. -- Call=Call,
  5664. -- Wait=Wait,
  5665.  
  5666. sigonce=function(f) return Sync(f,'once') end,
  5667. sighook=function(f) return Sync(f,'on') end,
  5668. wait=function(...) return sched.running:wait(...) end,
  5669. sigrun=Task.sigrun,
  5670. sigrunonce=Task.sigrunonce,
  5671.  
  5672. --others
  5673. }
  5674. local _require=function(p,t)
  5675.     t=t or{}
  5676.     t.env={sched=sched}
  5677.     return require(p,t)
  5678. end
  5679. platform=_require'platform'
  5680.  
  5681. os_time=platform.time
  5682.  
  5683. timer=_require'timer'
  5684.  
  5685. _require'pipe'
  5686. _require'catalog'
  5687.  
  5688.  
  5689.  
  5690. local loop_state = 'stopped' -- stopped, running or stopping
  5691.  
  5692. function sched.step()
  5693.     local old = sched.queue
  5694.     sched.queue=Linked()
  5695.     --------------------------------------------------------------------
  5696.     -- going through `self.queue` until it's empty.
  5697.     --------------------------------------------------------------------
  5698.     while true do
  5699.         local obj = old:remove() --pops first from left->right
  5700.         if obj==nil then break end
  5701.        
  5702.         obj:resume()
  5703.     end
  5704.     if not sched.queue:isempty() then sched.ready=true end
  5705. end
  5706.  
  5707. ---Exits the scheduler after the current cycle is completed.
  5708. function sched.stop()
  5709.     log('sched','INFO','(%s) toggling loop_state=%s to stopping',Task.running or 'scheduler',loop_state)
  5710.     if loop_state=='running' then loop_state = 'stopping' end
  5711. end
  5712.  
  5713. ---resets internal vars
  5714. function sched.reset()
  5715.     fil={}
  5716.     sched.fil=fil
  5717.     sched.running=nil
  5718.     sched.queue=Linked()
  5719.     Task._reset()
  5720.     timer._reset()
  5721.    
  5722.     platform._reset() --after timer
  5723.     loop_state = 'stopped'
  5724.     log('sched','INFO','scheduler cleaned.')
  5725. end
  5726.  
  5727. ---Loops over the scheduler cycle,
  5728. --returning to the caller function after sched.stop has been called
  5729. --calling platform.step for performing sleeps.
  5730. function sched.loop ()
  5731.     log('sched','INFO','Scheduler started')
  5732.     loop_state = 'running'
  5733.     local timeout
  5734.     while true do --this block is the scheduler step
  5735.         timer.step() -- Emit timer signals
  5736.         sched.step() -- Run all the ready tasks
  5737.         -- Find out when the next timer event is due
  5738.         timeout = nil
  5739.         local date = timer.nextevent()
  5740.         if date then
  5741.             local now=os_time()
  5742.             timeout = date<now and 0 or date-now
  5743.         end
  5744.        
  5745.         if loop_state~='running' then sched.reset() break end
  5746.         --debug.log(sched.debug())
  5747.         platform.step(timeout) -- Wait for platform events until the next timer is due
  5748.         sched.ready=false
  5749.     end
  5750. end
  5751.  
  5752. function sched.debug()
  5753.     local d={}
  5754.     local t={}
  5755.     for em,emt in pairs(fil) do
  5756.         local tt={}
  5757.         for ev,objt in pairs(emt) do
  5758.             local ttt={}
  5759.             for obj in pairs(objt) do
  5760.                 table.insert(ttt,debug.getinfo(obj))
  5761.             end
  5762.             tt[debug.getinfo(ev)]=ttt
  5763.         end
  5764.         t[debug.getinfo(em)]=tt
  5765.     end
  5766.     d.fil=t
  5767.     return pstring(d)
  5768. end
  5769.  
  5770. local t={}
  5771. for i,v in pairs(sched) do
  5772.     if type(i)=='string' then t[i:lower()]=v end
  5773. end
  5774. for i,v in pairs(t) do sched[i]=v end
  5775.  
  5776. sched.reset()
  5777. end
  5778. return sched]===================],"CoolisOS/bin/kernel/sched/lock.lua",[===================[--------------------------------------------------------------------------------
  5779. -- Thread-bound lock objects
  5780. -- =========================
  5781. --
  5782. -- A lock allows to define atomic units of code execution:
  5783. -- a portion of code that is protected by a lock will never be executed by more
  5784. -- than one thread at a time.
  5785. -- Because of the use of coroutines for the threading in Lua, the use of locks
  5786. -- is only relevant when you want to protect a portion of code that contains
  5787. -- blocking APIs (i.e. network access, scheduling, etc...)
  5788. --
  5789. -- A lock must be acquired and released by the same thread: an error will be
  5790. -- triggered if a thread tries to release a lock acquired by another thread.
  5791. -- This behavior is enforced because it is almost always a concurrency mistake
  5792. -- to have a thread releasing another thread's locks; but you can circumvent
  5793. -- this by passing the owning thread as an extra parameter.
  5794. --
  5795. -- A lock is automatically released when its owning thread dies, if it failed
  5796. -- to do so explicitly.
  5797. --
  5798. -- API
  5799. -- ---
  5800. --
  5801. -- lock.new()
  5802. --      return a new instance of a lock.
  5803. --
  5804. -- LOCK :acquire ()
  5805. --      acquire the lock.
  5806. --
  5807. -- LOCK :release ([thread])
  5808. --      release the lock. The optional thread param is defaulted to the
  5809. --      current thread. A lock must be released by the thread that
  5810. --      acquired it (or use the thread params to release another thread's lock).
  5811. --
  5812. -- LOCK :destroy()
  5813. --      destroy the lock. Any waiting thread on that lock will trigger a
  5814. --      "destroyed" error
  5815. --
  5816. --------------------------------------------------------------------------------
  5817.  
  5818. --------------------------------------------------------------------------------
  5819. -- Associative lock objects
  5820. -- ------------------------
  5821. --
  5822. -- Function lock (object) allows to associate a lock to an arbitrary object.
  5823. -- This API creates a standard lock (as above). It removes the burden of
  5824. -- creating the lock and managing the association between the object
  5825. -- and the lock.
  5826. --
  5827. -- Locks associated to objects still have an owning thread, and the rule
  5828. -- "locks must be released by the thread which owns them" still applies.
  5829. --
  5830. -- API
  5831. --
  5832. -- lock.lock (object)
  5833. --      lock the object.
  5834. --
  5835. -- lock.unlock(object, thread)
  5836. --      unlock the object. thread is optional as in lock:acquire() function.
  5837. --
  5838. --------------------------------------------------------------------------------
  5839.  
  5840. --------------------------------------------------------------------------------
  5841. -- Synchronized functions
  5842. -- ----------------------
  5843. --
  5844. -- A common pattern is to have a function that must not be called more than once
  5845. -- at a given time: if the function is already running in another thread, one
  5846. -- must wait for this call to finish before calling it again.
  5847. --
  5848. -- API
  5849. --
  5850. -- lock.synchronized (f)
  5851. --      return a synchronized wrapper around f. A typical idiom is:
  5852. --
  5853. --      mysynchronizedfunction = lock.synchronized (function (...)
  5854. --          [code]
  5855. --      end)
  5856. --------------------------------------------------------------------------------
  5857. include'kernel.class'
  5858. local check = require 'kernel.checker'.check
  5859.  
  5860. local sched = require 'init'
  5861.  
  5862. local setmetatable = setmetatable
  5863. local tostring = tostring
  5864. local string = string
  5865. local error = error
  5866. local assert = assert
  5867. local table = table
  5868. local next = next
  5869. local pairs = pairs
  5870. local type = type
  5871. local unpack = unpack
  5872.  
  5873. env=getfenv()
  5874. setmetatable(env,nil)
  5875.  
  5876. --------------------------------------------------------------------------------
  5877. --
  5878. --------------------------------------------------------------------------------
  5879. class.LOCK()
  5880. LOCK.hooks={}
  5881. LOCK.objlocks=setmetatable({}, {__mode = "k"})
  5882. --------------------------------------------------------------------------------
  5883. -- Create a new lock object. It remains unlocked.
  5884. --------------------------------------------------------------------------------
  5885. setmetatable(env,{__call=function() return LOCK(...) end})
  5886. function LOCK:__init()
  5887.     self.waiting={}
  5888. end
  5889. --------------------------------------------------------------------------------
  5890. -- Destroy a lock object.
  5891. --------------------------------------------------------------------------------
  5892. function LOCK:destroy()
  5893.     self.owner = "destroyed" -- means that the lock is being destroyed !
  5894.     for t, _ in pairs(self.waiting) do
  5895.         sched.signal(self, t)
  5896.         self.waiting[t] = nil
  5897.     end
  5898. end
  5899.  
  5900. --------------------------------------------------------------------------------
  5901. -- Helper to release locks on dead threads.
  5902. --------------------------------------------------------------------------------
  5903. local function autorelease(thread)
  5904.     for l, _ in pairs(LOCK.hooks[thread]) do
  5905.         if l.owner == thread then l:release(thread)
  5906.         elseif l.waiting then l.waiting[thread] = nil end
  5907.     end
  5908.     LOCK.hooks[thread] = nil
  5909. end
  5910.  
  5911. --------------------------------------------------------------------------------
  5912. -- Helper to release locks on dead threads.
  5913. --------------------------------------------------------------------------------
  5914. local function protectdie(self, thread)
  5915.     if not LOCK.hooks[thread] then
  5916.         local h = sched.sigonce(function()
  5917.             autorelease(thread)
  5918.         end,thread, "dead")
  5919.         LOCK.hooks[thread] = {sighook = h}
  5920.     end
  5921.     (LOCK.hooks[thread])[self] = true
  5922. end
  5923.  
  5924. --------------------------------------------------------------------------------
  5925. -- Helper to release locks on dead threads.
  5926. --------------------------------------------------------------------------------
  5927. local function unprotectdie(self, thread)
  5928.     (LOCK.hooks[thread])[self] = nil
  5929.     if not next(LOCK.hooks[thread], next(LOCK.hooks[thread])) then -- if this was the last lock attached to that thread...
  5930.         (LOCK.hooks[thread].sighook):destroy()
  5931.         LOCK.hooks[thread] = nil
  5932.     end
  5933. end
  5934.  
  5935. --------------------------------------------------------------------------------
  5936. -- Attempt to take ownership of a lock; might block until the current owner
  5937. -- releases it.
  5938. --------------------------------------------------------------------------------
  5939. function LOCK:acquire()
  5940.     local t = sched.task.running
  5941.     assert(self.owner ~= t, "a lock cannot be acquired twice by the same thread")
  5942.     assert(self.owner ~= "destroyed", "cannot acquire a destroyed lock")
  5943.     protectdie(self, t) -- ensure that the lock will be unlocked if the thread dies before unlocking...
  5944.  
  5945.     while self.owner do
  5946.         self.waiting[t] = true
  5947.         sched.wait(self,t) -- wait on the current lock with the current thread
  5948.         if self.owner == "destroyed" then error("lock destroyed while waiting") end
  5949.     end
  5950.     self.waiting[t] = nil
  5951.     self.owner = t
  5952. end
  5953.  
  5954. --------------------------------------------------------------------------------
  5955. -- Release ownership of a lock.
  5956. --------------------------------------------------------------------------------
  5957. function LOCK:release(thread)
  5958.     thread = thread or sched.task.running
  5959.     assert(self.owner ~= "destroyed", "cannot release a destroyed lock")
  5960.     assert(self.owner == thread, "unlock must be done by the thread that locked")
  5961.     unprotectdie(self, thread)
  5962.     self.owner = nil
  5963.  
  5964.     -- wakeup a waiting thread, if any...
  5965.     local t = next(self.waiting)
  5966.     if t then
  5967.         sched.signal(self, t)
  5968.     end
  5969. end
  5970.  
  5971. --------------------------------------------------------------------------------
  5972. -- Create and acquire a new lock, associated to an arbitrary object.
  5973. --------------------------------------------------------------------------------
  5974. function lock(object)
  5975.     assert(object, "you must provide an object to lock on")
  5976.     assert(type(object) ~= "string" and type(object) ~= "number", "the object to lock on must be a collectable object (no string or number)")
  5977.     if not LOCK.objlocks[object] then LOCK.objlocks[object] = new() end
  5978.     LOCK.objlocks[object]:acquire()
  5979. end
  5980.  
  5981.  
  5982. --------------------------------------------------------------------------------
  5983. -- Release an object created with lock().
  5984. --------------------------------------------------------------------------------
  5985. function unlock(object, thread)
  5986.     assert(object, "you must provide an object to unlock on")
  5987.     assert(LOCK.objlocks[object], "this object was not locked")
  5988.     LOCK.objlocks[object]:release()
  5989. end
  5990.  
  5991. --------------------------------------------------------------------------------
  5992. -- Create a synchronized version of function f, i.e. a function that behaves
  5993. -- as f, except that no more than one instance of it will be running at a
  5994. -- given time.
  5995. --------------------------------------------------------------------------------
  5996. function synchronized(f)
  5997.     check(f,'function')
  5998.     local function sync_f(...)
  5999.         local k = lock (f)
  6000.         local r = {f(...)}
  6001.         unlock(f)
  6002.         return unpack (r, 1, r.n)
  6003.     end
  6004.     return sync_f
  6005. end
  6006.  
  6007. return env
  6008. ]===================],"CoolisOS/bin/kernel/sched/pipe.lua",[===================[--------------------------------------------------------------------------------
  6009. -- FIFO PIPES
  6010. -- ==========
  6011. --
  6012. -- Purpose
  6013. -- -------
  6014. -- Tasks can't easily exchange messages with sighook() or wait():
  6015. --
  6016. -- Calling wait() in a loop might lose some messages, if a message arrives
  6017. -- before the loop had the time to go back to wait(). Example:
  6018. --
  6019. --     ----------------------------------------------------------
  6020. --     -- sender --
  6021. --     for i=1, 100 do signal('foo', 'tick', i); sched.wait (2) end
  6022. --
  6023. --     -- receiver --
  6024. --     while true do
  6025. --        local  _, n = sched.wait('foo', 'tick')
  6026. --        printf ("received %i", n)
  6027. --        sched.wait(3)
  6028. --     end
  6029. --     ----------------------------------------------------------
  6030. --
  6031. -- sighooks are guaranteed to be called everytime the event is triggered,
  6032. -- but they are executed as interruptions, they can't pause a task.
  6033. --
  6034. -- Pipes solve this issue: everything that is written in a pipe with :send()
  6035. -- will be read back, in order, with :receive(). If there's nothing to read yet,
  6036. -- the task calling :receive() will pause and wait for the next :send() to
  6037. -- provide data to read back.
  6038. --
  6039. -- :receive() can yield, and therefore must not be used in a sighook.
  6040. --
  6041. -- :send() can yield only if there is a maxlength and the pipe is already full.
  6042. --
  6043. --
  6044. -- API
  6045. -- ---
  6046. -- - create a new pipe with:
  6047. --    P = pipe()
  6048. -- - push data in it with:
  6049. --    P :send(x). x can't be nil.
  6050. -- - read data back with:
  6051. --    P :receive() or P :receive(timeout).
  6052. --   This call will block if necessary. It also supports an optional timeout
  6053. --   parameter. If there is a timeout and nothing can be read within the delay,
  6054. --   nil is returned.
  6055. -- - do a non-blocking, non-consumming peek at next value with:
  6056. --    P :peek()
  6057. --   This might return nil is the pipe is currently empty.
  6058. -- - return all of the pipe's current content and reset it as empty with:
  6059. --    P :reset()
  6060. -- - cancel a reading by pushing back an element in the pipe with:
  6061. --    P :pushback(x)
  6062. -- - retrieve the number of elements currently in a pipe with:
  6063. --    P :length()
  6064. -- - tune the recompaction parameters:
  6065. --    P :setwaste(absolute_waste_factor, proportional_waste_factor)
  6066. --
  6067. --
  6068. -- Algorithmic complexity
  6069. -- ----------------------
  6070. -- The amortized complexity for sending and receiving is o(log(N)), N
  6071. -- being the current number of elements in the pipe. Notice that with
  6072. -- the obvious/naive implentation based on table.insert() and
  6073. -- table.remove(), one of the operations is in o(log(N)) but the other
  6074. -- is in o(N); therefore, writing K elements then reading them back
  6075. -- would have a time complexity in o(K^2), compared to o(K*log(K)) here.
  6076. --
  6077. --------------------------------------------------------------------------------
  6078. include'kernel.class'
  6079.  
  6080. local check=require 'kernel.checker'.check
  6081.  
  6082. local sched=sched
  6083.  
  6084. --------------------------------------------------------------------------------
  6085. -- Object metatable/class
  6086. --------------------------------------------------------------------------------
  6087.  
  6088. sched.Pipe=class'Pipe'
  6089. do
  6090. local P=sched.Pipe
  6091.  
  6092. local insert, remove, os_time = table.insert, table.remove, os.clock
  6093.  
  6094. --------------------------------------------------------------------------------
  6095. -- A registry of all currently active pipes. This is intended as a debug aid,
  6096. -- and can be safely commented out if not needed
  6097. --------------------------------------------------------------------------------
  6098. sched.pipes = setmetatable({}, {__mode='kv'})
  6099.  
  6100. --------------------------------------------------------------------------------
  6101. -- Create a new pipe
  6102. --------------------------------------------------------------------------------
  6103.  
  6104. function P:__init(maxlength)
  6105.     check ('?number',maxlength)
  6106.     util.shcopy({
  6107.         sndidx     = 1;
  6108.         rcvidx     = 1;
  6109.         content    = { };
  6110.         maxlength  = maxlength;
  6111.         state      = 'empty';
  6112.         wasteabs   = 32 ;
  6113.         wasteprop  = 2 },
  6114.         self)
  6115.     if sched.pipes then
  6116.         sched.pipes[debug.getinfo(self)]=self
  6117.     end
  6118. end
  6119.  
  6120. --------------------------------------------------------------------------------
  6121. -- Check whether the 'state' field is consistent with the pipe's content
  6122. -- and maxlength, produce a signal and change it if needed.
  6123. -- Helper for methods which modify content or maxlength.
  6124. --------------------------------------------------------------------------------
  6125. local function updatestate (self)
  6126.     local length   = self.sndidx - self.rcvidx
  6127.     local oldstate = self.state
  6128.     local newstate = length==0 and 'empty' or self.maxlength==length and 'full' or 'ready'
  6129.     if oldstate ~= newstate then
  6130.         self.state=newstate
  6131.         sched.signal(self, 'state', newstate)
  6132.     end
  6133. end
  6134.  
  6135. --------------------------------------------------------------------------------
  6136. -- Move all entries to the beginning of content, if the following conditions
  6137. -- are both verified:
  6138. --  * there are more than self.wasteabs cells to collect;
  6139. --  * the number of wasted cells is at more than self.wasteprop times bigger
  6140. --    than the number of actually used cells.
  6141. --------------------------------------------------------------------------------
  6142. local function recompact (self)
  6143.     local rcvidx = self.rcvidx
  6144.     local wasted = rcvidx-1
  6145.     if wasted <= self.wasteabs then return end
  6146.     local sndidx = self.sndidx
  6147.     local used = sndidx - rcvidx
  6148.     if wasted <= self.wasteprop * used then return end
  6149.     -- Tests passed, proceed to recompaction
  6150.     local content
  6151.     if sndidx<2000 then content = { select (rcvidx, unpack (self.content)) } else
  6152.         -- avoid stack overflows: stacks can't grow beyond LUAI_MAXCSTACK,
  6153.         -- which is set to 8000 by default. Our choice of 2000 is just as
  6154.         -- arbitrary as 8000.
  6155.         local oldcontent
  6156.         oldcontent, content = self.content, { }
  6157.         for i=1,used do content[i]=oldcontent[i+wasted] end
  6158.     end
  6159.     self.content, self.rcvidx, self.sndidx = content, 1, used+1
  6160. end
  6161.  
  6162. --------------------------------------------------------------------------------
  6163. -- Read a value, yield the current task if necessary
  6164. --------------------------------------------------------------------------------
  6165. function P :receive (timeout)
  6166.     check('?number',timeout)
  6167.     local due_date
  6168.     while true do
  6169.         if self.rcvidx==self.sndidx then
  6170.             log('pipe', 'DEBUG', "(%s) empty,(%s) :receive() waits for data", self,sched.running)
  6171.             due_date = due_date or timeout and os_time() + timeout
  6172.             local timeout = due_date and due_date - os_time()
  6173.             if timeout and timeout<=0 or sched.wait(self,'state',timeout)==sched.timer then
  6174.                 return nil, 'timeout'
  6175.             end
  6176.         else
  6177.             local content, rcvidx = self.content, self.rcvidx
  6178.             local x = content[rcvidx]
  6179.             content[rcvidx] = false
  6180.             self.rcvidx = rcvidx+1
  6181.             recompact (self)
  6182.             updatestate (self)
  6183.             if x~=nil then return x end
  6184.         end
  6185.     end
  6186. end
  6187.  
  6188. --------------------------------------------------------------------------------
  6189. -- Push a value to read
  6190. --------------------------------------------------------------------------------
  6191. function P :send (x, timeout)
  6192.     check ('!nil,?number',x,timeout)
  6193.     local maxlength = self.maxlength
  6194.     local due_date
  6195.     while self.state == 'full' do
  6196.         log('pipe', 'DEBUG', "Pipe %s full, :send() blocks until some data is pulled from pipe", self)
  6197.         due_date = due_date or timeout and os_time() + timeout
  6198.         local timeout = due_date and due_date - os_time()
  6199.         if timeout and timeout<=0 or sched.wait(self,'state', timeout)=='timer' then
  6200.             log('pipe', 'DEBUG', "Pipe %s :send() timeout", self)
  6201.             return nil, 'timeout'
  6202.         else
  6203.             log('pipe', 'DEBUG', "Pipe %s state changed, retrying to :send()", self)
  6204.         end
  6205.     end
  6206.     local sndidx = self.sndidx
  6207.     self.content[sndidx] = x
  6208.     self.sndidx = sndidx+1
  6209.     updatestate(self)
  6210.     return self
  6211. end
  6212.  
  6213. --------------------------------------------------------------------------------
  6214. -- Pushback the last read value
  6215. --------------------------------------------------------------------------------
  6216. function P :pushback (x)
  6217.     assert (x~=nil, "Don't :pushback(nil) in a pipe")
  6218.     if self.state=='full' then
  6219.         return nil, 'length would exceed maxlength'
  6220.     end
  6221.     local rcvidx = self.rcvidx-1
  6222.     if rcvidx==0 then
  6223.         table.insert(self.content, 1, x)
  6224.         self.sndidx = self.sndidx+1
  6225.     else
  6226.         self.content[rcvidx] = x
  6227.         self.rcvidx = rcvidx
  6228.     end
  6229.     updatestate (self)
  6230.     return self
  6231. end
  6232.  
  6233. --------------------------------------------------------------------------------
  6234. -- Empty the pipe, return what it contained in a list
  6235. --------------------------------------------------------------------------------
  6236. function P :reset()
  6237.     local r = self.content
  6238.     self.content = { }
  6239.     updatestate(self)
  6240.     return r
  6241. end
  6242.  
  6243. --------------------------------------------------------------------------------
  6244. -- Try to read without yielding nor removing from internal queue
  6245. --------------------------------------------------------------------------------
  6246. function P :peek()
  6247.     return self.content[self.rcvidx]
  6248. end
  6249.  
  6250. --------------------------------------------------------------------------------
  6251. -- Return the number of elements currently in the pipe.
  6252. --------------------------------------------------------------------------------
  6253. function P :length()
  6254.     return self.sndidx - self.rcvidx
  6255. end
  6256.  
  6257. --------------------------------------------------------------------------------
  6258. -- Change or remove (by passing nil) the curent pipe length limitation.
  6259. --------------------------------------------------------------------------------
  6260. function P :setmaxlength(maxlength)
  6261.     check ('?number',maxlength)
  6262.     if self :length() > maxlength then return nil, 'length exceeds new maxlength' end
  6263.     if maxlength and maxlength<1 then return nil, 'invalid maxlength' end
  6264.     self.maxlength = maxlength
  6265.     updatestate (self)
  6266.     return self
  6267. end
  6268.  
  6269. --------------------------------------------------------------------------------
  6270. -- Change waste parameters, hence the memory/speed performance compromize.
  6271. --------------------------------------------------------------------------------
  6272. function P :setwaste(abs, prop)
  6273.     self.wasteabs, self.wasteprop = abs, prop
  6274.     return self
  6275. end
  6276. end
  6277. sched.SigPipe=class('SigPipe',sched.Pipe,sched.Obj)
  6278. do
  6279. local S=sched.SigPipe
  6280. function S:handle(...)
  6281.     self:send{...}
  6282. end
  6283. end
  6284.  
  6285. sched.pump=function(pin,f,pout)
  6286.     check('?Pipe,?function,?Pipe',pin,f,pout)
  6287.     if not (pin or f or pout) then error'No pipes or function' end
  6288.     repeat
  6289.         local r=pin and pin:receive()
  6290.         r=f==nil and r or f(r)
  6291.         if r~=nil and pout then pout:send(r) end
  6292.     until false
  6293. end
  6294.  
  6295. sched.to=function(pin,pouts)
  6296.     repeat
  6297.         local x=pin:receive()
  6298.         if x~=nil then
  6299.             for i,pout in ipairs(pouts) do
  6300.                 pout:send(x)
  6301.             end
  6302.         end
  6303.     until false
  6304. end
  6305.  
  6306. sched.from=function(pins,pout)
  6307.     sched.running:reset()
  6308.     for _,pin in ipairs(pins) do
  6309.         sched.running:link(pin,'*')
  6310.     end
  6311.     repeat
  6312.         local redo=true
  6313.         while redo do
  6314.             redo=false
  6315.             for _,pin in ipairs(pins) do
  6316.                 if pin:peek()~=nil then
  6317.                     pout:send(pin:receive())
  6318.                     redo=true
  6319.                 end
  6320.             end
  6321.         end
  6322.         sched.wait(false)
  6323.     until false
  6324. end
  6325.  
  6326. ]===================],"CoolisOS/bin/kernel/sched/platform.lua",[===================[local log=require'kernel.log'
  6327. local sched,pairs,string,term,_G,fs,os,print,unpack,select,pprint,next=sched,pairs,string,term,_G,fs,os,print,unpack,select,pprint,next
  6328. local coroutine=coroutine
  6329. local tostring,math=tostring,math
  6330. local debug,util=debug,util
  6331. local plat={}
  6332.  
  6333. local sched=sched
  6334. local fil
  6335. env=getfenv()
  6336. setmetatable(env,nil)
  6337.  
  6338. ---Whether or not the coroutine running will yield to the scheduler
  6339. plat.is_running=function()
  6340.     return sched and sched.Task.running and sched.Task.running.co==coroutine.running()
  6341. end
  6342.  
  6343. plat.time = os.clock
  6344. local time=plat.time
  6345. local wake_ev=tostring({})
  6346. local Task=sched.Task
  6347.  
  6348. local cc,CC,load=0,1,0
  6349. last_yield,last_return=-math.huge,-math.huge
  6350. plat.info=function()
  6351.     return string.format('load: %f;last yield: %f;last return:%f',util.format_number(load,2),util.format_number(last_yield,2),util.format_number(last_return,2))
  6352. end
  6353.  
  6354. local yield=function(...)
  6355.     log('platform','DETAIL','yielding to platform')
  6356.     last_yield=time()
  6357.     cc=last_yield-last_return
  6358.     local x={coroutine.yield(...)}
  6359.     last_return=time()
  6360.     CC=last_return-last_yield
  6361.     load=cc/(CC+cc)
  6362.     log('platform','DETAIL',plat.info())
  6363.     return x
  6364. end
  6365.  
  6366. function plat.step(timeout)
  6367.     if sched.ready then timeout=0 end
  6368.     if timeout then
  6369.         local ev,id
  6370.         if timeout==0 then
  6371.             if time()-last_return>=0.05 then --retain control for at most (as far as the scheduler can control) one tick if necessary; set to math.huge in case there is too much of a delay between computers;
  6372.                
  6373.                 ev=wake_ev
  6374.                 os.queueEvent(ev)
  6375.             else
  6376.                 return
  6377.             end
  6378.         else
  6379.             ev,id='timer',os.startTimer(timeout)
  6380.         end
  6381.         local x
  6382.         repeat
  6383.             x=yield()
  6384.             if (ev==nil or x[1]==ev) and (id==nil or id==x[2]) then
  6385.                 break
  6386.             else
  6387.                 sched.signal(plat,unpack(x))
  6388.                 if sched.ready then break end
  6389.             end
  6390.         until false
  6391.         return
  6392.     else
  6393.         if not fil[plat] then
  6394.             log('platform','ERROR','no timers or platform listeners, so exiting.')
  6395.             sched.stop()
  6396.             return
  6397.         end
  6398.         local filter
  6399.         if not next(fil[plat],next(fil[plat])) then
  6400.             filter=next(fil[plat])
  6401.         end
  6402.         sched.signal(plat,unpack(yield(filter)))
  6403.         return
  6404.     end
  6405. end
  6406.  
  6407. function plat._reset()
  6408.     fil=sched.fil
  6409. end
  6410. debug.name(plat,'platform')
  6411. sched.platform=plat
  6412. return plat]===================],"CoolisOS/bin/kernel/sched/timer.lua",[===================[------------------------------------------------------------------------------
  6413. -- timer module
  6414. --      supports one time timer timer.new(positive number)
  6415. --      supports periodic timer timer.new(negative number)
  6416. --      cron-compatible syntax (string conforming to cron syntax)
  6417. --      support simple timers
  6418. ------------------------------------------------------------------------------
  6419. include'kernel.class'
  6420. local linked=require'utils.linked'
  6421. local check=require'kernel.checker'.check
  6422. local shcopy=require'kernel.util'.shcopy
  6423. local error=error
  6424. local read=read
  6425. PACKAGE_NAME='sched'
  6426.  
  6427.  
  6428. local sched=sched
  6429. local fil
  6430. local Obj=sched.Obj
  6431. local os = os
  6432. local math = math
  6433. local tonumber = tonumber
  6434. local assert = assert
  6435. local table = table
  6436. local pairs = pairs
  6437. local next = next
  6438. local type = type
  6439. local _G=_G
  6440. local os_time=os.clock
  6441. local setmetatable=setmetatable
  6442. local rawset=rawset
  6443. local unpack=unpack
  6444. local debug=debug
  6445.  
  6446. env=getfenv()
  6447. setmetatable(env,nil)
  6448.  
  6449. local timer={}
  6450.  
  6451. timer.norm=function(t) --the CC clock moves in steps of 0.05
  6452.     t=t-t%0.05
  6453.     -- if t<=0 then
  6454.         -- error('time values must be non-negative and multiples of 0.05',3)--to be used internally inside timer functions
  6455.     -- end
  6456.     return t
  6457. end
  6458. local norm=timer.norm
  6459. -------------------------------------------------------------------------------------
  6460. -- Common scheduling code
  6461. -------------------------------------------------------------------------------------
  6462.  
  6463. -------------------------------------------------------------------------------------
  6464. -- These functions must be attached as method :nextevent() to timer objects,
  6465. -- and return the timer's next due date.
  6466. -------------------------------------------------------------------------------------
  6467. local function stimer_nextevent (timer) return nil end
  6468.  
  6469. local events
  6470. local link,link_r
  6471. local n
  6472. -------------------------------------------------------------------------------------
  6473. -- Take a timer, reference it
  6474. -------------------------------------------------------------------------------------
  6475.  
  6476. timer.add = function(t)
  6477.     if not link_r[t] then
  6478.         local ind
  6479.         for val in linked.next_r,link,val do
  6480.             if val>t then
  6481.                 ind=val
  6482.                 break
  6483.             end
  6484.         end
  6485.         -- print(ind)
  6486.         if ind==nil then sched.ready=true end--if the next due date changed, signal the platform to break it's step
  6487.         link:insert_r(t,ind)
  6488.     end
  6489. end
  6490.  
  6491. -------------------------------------------------------------------------------------
  6492. -- Take a timer, dereference it
  6493. -------------------------------------------------------------------------------------
  6494. timer.remove = function(t)
  6495.     link:remove(t)
  6496. end
  6497.  
  6498. -------------------------------------------------------------------------------------
  6499. -- Signal all elapsed timer events.
  6500. -- This must be called by the scheduler every time a due date elapses.
  6501. -------------------------------------------------------------------------------------
  6502. function timer.step()
  6503.     if link_r[0]==-1 then return end -- if no timer is set just return and prevent further processing
  6504.     local now = os_time()
  6505.     while link_r[0]~=-1 and now >= link_r[0] do --about the above redundancy, maybe while loops are heavy?
  6506.         local nd = link:remove()
  6507.         sched.signal(timer,nd)
  6508.     end
  6509. end
  6510.  
  6511. timer.meta={__index=timer}
  6512. setmetatable(timer,{__index=Obj,__tostring=function() return 'Class timer' end})
  6513. -------------------------------------------------------------------------------------
  6514. -- returns the next expiration date
  6515. -------------------------------------------------------------------------------------
  6516. function timer.nextevent()
  6517.     -- print(link)
  6518.     if link_r[0]~=-1 then return link_r[0] end
  6519. end
  6520.  
  6521. local meta={
  6522.     __newindex=function(t,k,v)
  6523.         if type(k)~='number' then
  6524.             error(tostring(k)..'timer events must be numbers',2)
  6525.         end
  6526.         -- k=k-k%0.05 --math.ceil(t/0.05)*0.05 --maybe round up for user comfort? this way it's 1.5 time faster
  6527.         -- if k<=0 then
  6528.             -- error(k..'time values must be positive',2)
  6529.         -- end
  6530.         if v==nil then
  6531.             timer.remove(k)
  6532.         else--could move it here...
  6533.             timer.add(k)
  6534.         end
  6535.         rawset(t,k,v)
  6536.     end,
  6537.    
  6538. }
  6539. ---resets the timer module
  6540. timer._reset=function()
  6541.     local holder=sched.task(function() end)
  6542.     debug.name(holder,'placeholder')
  6543.     events=setmetatable({[{}]={[holder]=true}},meta)
  6544.     sched.fil[timer]=events
  6545.     link=linked()
  6546.     link_r=link.r
  6547.     timer.link=link
  6548. end
  6549.  
  6550. class.CyclicTimer(sched.Obj)
  6551. do
  6552. local C=CyclicTimer
  6553. local O=sched.Obj
  6554. function C:__init(delta,...)
  6555.     O:__init(self)
  6556.     check('number,function',delta,f)
  6557.     self.delta=norm(delta)
  6558.     self.f=f
  6559.     self.args={...}
  6560. end
  6561. function C:handle(_,ev)
  6562.     ev=ev+self.delta
  6563.     self:link{timer={ev}}
  6564.     self.f(unpack(self.args))
  6565. end
  6566. end
  6567. timer.cyclic=CyclicTimer
  6568. debug.name(timer,'timer')
  6569. sched.timer=timer
  6570. return timer]===================],"CoolisOS/bin/programs",true,"CoolisOS/bin/programs/bt.lua",[===================[print(1)]===================],"CoolisOS/bin/programs/help.lua",[===================[--By CoolisTheName007
  6571. --CoolisOS/dev/help.lua
  6572.  
  6573. local mon=peripheral.wrap'back'
  6574. mon.setTextScale(1)
  6575. local delay=1
  6576. local textPath='CoolisOS/dev/text'
  6577.  
  6578. local function getText()
  6579.     local f=fs.open(textPath,'r')
  6580.     local text=f.readAll()
  6581.     f.close()
  6582.     return text
  6583. end
  6584.  
  6585. local function parse_text(text)
  6586.     for line in text:gmatch("([^\n]*)\n?") do
  6587.         local t,b=line:match'^#([^#- ]+)-?([^#- ]*)#'
  6588.     end
  6589. end
  6590.  
  6591. local function write( sText)
  6592.     local term=mon
  6593.     local w,h = term.getSize()     
  6594.     local x,y = term.getCursorPos()
  6595.    
  6596.     local nLinesPrinted = 0
  6597.     local function newLine()
  6598.         if y + 1 <= h then
  6599.             term.setCursorPos(1, y + 1)
  6600.         else
  6601.             term.setCursorPos(1, h)
  6602.             term.scroll(1)
  6603.         end
  6604.         x, y = term.getCursorPos()
  6605.         nLinesPrinted = nLinesPrinted + 1
  6606.     end
  6607.    
  6608.     -- Print the line with proper word wrapping
  6609.     while string.len(sText) > 0 do
  6610.         local whitespace = string.match( sText, "^[ \t]+" )
  6611.         if whitespace then
  6612.             -- Print whitespace
  6613.             term.write( whitespace )
  6614.             x,y = term.getCursorPos()
  6615.             sText = string.sub( sText, string.len(whitespace) + 1 )
  6616.         end
  6617.        
  6618.         local newline = string.match( sText, "^\n" )
  6619.         if newline then
  6620.             -- Print newlines
  6621.             newLine()
  6622.             sText = string.sub( sText, 2 )
  6623.         end
  6624.        
  6625.         local text = string.match( sText, "^[^ \t\n]+" )
  6626.         if text then
  6627.             sText = string.sub( sText, string.len(text) + 1 )
  6628.             if string.len(text) > w then
  6629.                 -- Print a multiline word              
  6630.                 while string.len( text ) > 0 do
  6631.                     if x > w then
  6632.                         newLine()
  6633.                     end
  6634.                     term.write( text )
  6635.                     text = string.sub( text, (w-x) + 2 )
  6636.                     x,y = term.getCursorPos()
  6637.                 end
  6638.             else
  6639.                 -- Print a word normally
  6640.                 if x + string.len(text) - 1 > w then
  6641.                     newLine()
  6642.                 end
  6643.                 term.write( text )
  6644.                 x,y = term.getCursorPos()
  6645.             end
  6646.         end
  6647.     end
  6648.    
  6649.     return nLinesPrinted
  6650. end
  6651.  
  6652. local function wrap(text, limit) --from Kingdaroo
  6653.         local lines = {''}
  6654.         for word, space in text:gmatch('(%S+)(%s*)') do
  6655.                 local temp = lines[#lines] .. word .. space:gsub('\n','')
  6656.                 if #temp > limit then
  6657.                         table.insert(lines, '')
  6658.                 end
  6659.                 if space:find('\n') then
  6660.                         lines[#lines] = lines[#lines] .. word
  6661.                        
  6662.                         space = space:gsub('\n', function()
  6663.                                 table.insert(lines, '')
  6664.                                 return ''
  6665.                         end)
  6666.                 else
  6667.                         lines[#lines] = lines[#lines] .. word .. space
  6668.                 end
  6669.         end
  6670.         return lines
  6671. end
  6672.  
  6673. local function extract(t,s,l)
  6674.     local c={}
  6675.     for k=s,s+l-1 do
  6676.         c[k-s+1]=t[k%(#t)+1]
  6677.     end
  6678.     return c
  6679. end
  6680.  
  6681. local function print_screen(t)
  6682.     mon.clear()
  6683.     mon.setCursorPos(1,1)
  6684.     local x,y=mon.getSize()
  6685.    
  6686.    
  6687.     for i,line in ipairs(t) do
  6688.         if (line:sub(1,1)=='#') then
  6689.             local tc=colors[line:match'^#([^-#]+)']
  6690.             mon.setTextColor(tc or colors.white)
  6691.             local bc=colors[line:match'^#[^-#]+%-([^#]+)#']
  6692.             mon.setBackgroundColor(bc or colors.black)
  6693.             local l=line:match'^#[^#]+#'
  6694.             line=line:sub(l:len()+1)
  6695.         end
  6696.         c=' '
  6697.         if (line:sub(-2,-2)=='&') then
  6698.             c=line:sub(-1,-1)
  6699.             line=line:sub(1,-3)
  6700.         end
  6701.         line=line..string.rep(c,math.max(x-#line,0))
  6702.         write(line..(i~=#t and '\n' or ''))
  6703.     end
  6704. end
  6705.  
  6706. local function main()
  6707.     local x,y=mon.getSize()
  6708.     local text
  6709.     local c=-1
  6710.     repeat
  6711.        
  6712.         local ok,r=pcall(getText)
  6713.         if ok then text=r else error(r) end
  6714.         local tText=wrap(text,x)
  6715.         c=(c+1)%(#tText)
  6716.         mon.setTextColor(colors.white)
  6717.         mon.setBackgroundColor(colors.black)
  6718.         local t=tText
  6719.         for i=1,(c+1) do
  6720.             local line=t[i]
  6721.             if (line:sub(1,1)=='#') then
  6722.                 local tc=colors[line:match'^#([^-#]+)']
  6723.                 mon.setTextColor(tc or colors.white)
  6724.                 local bc=colors[line:match'^#[^-#]+%-([^#]+)#']
  6725.                 mon.setBackgroundColor(bc or colors.black)
  6726.             end
  6727.         end
  6728.         print_screen(extract(tText,c,y))
  6729.        
  6730.         sleep(delay)
  6731.     until false
  6732. end
  6733. parallel.waitForAny(main,function() shell.run'shell' end)
  6734. ]===================],"CoolisOS/bin/programs/master.lua",[===================[rednet.open'right'
  6735.  
  6736. function slave()
  6737.     local t={
  6738.     1=true
  6739.     }
  6740.     local send=function(id,n) turtle.select(id) turtle.drop(n) end
  6741.     while true do
  6742.         local _id,msg=rednet.receive()
  6743.         local id,n=msg:match'([^:]):([^:])'
  6744.         if id and n then
  6745.             n=tonumber(n)
  6746.             send(id,n)
  6747.         end
  6748.     end
  6749. end
  6750.  
  6751. function master()
  6752.  
  6753. delay=5
  6754. function _request(id,n)
  6755.     repeat
  6756.         rednet.broadcast(id..':'..n)
  6757.         t=0
  6758.         repeat
  6759.             if turtle.getItemCount(1)==n then break end
  6760.             sleep(dt)
  6761.             t=t+dt
  6762.         until t>delay
  6763.     until turtle.getItemCount(1)==n
  6764.     turtle.drop()
  6765. end
  6766.  
  6767.  
  6768. function request(id,n)
  6769.     local r=n%64
  6770.     local q=(n-r)/64
  6771.     for i=1,q do _request(id,64) end
  6772.     _request(id,r)
  6773. end
  6774.  
  6775. end]===================],"CoolisOS/bin/programs/quarry.lua",[===================[--CoolisOS/dev/quarry.lua
  6776. include'kernel.class'
  6777.  
  6778. class.Machine()
  6779. local function link(t)
  6780.     if t[1] then t[1].start=true end
  6781.     for i,v in ipairs(t) do
  6782.         v.next=t[i+1]
  6783.         v.index=i
  6784.     end
  6785. end
  6786. function Machine:__init(t)
  6787.     link(t)
  6788.     self.states=t
  6789. end
  6790. function Machine:find()
  6791.     for i,v in ipairs(self.states) do
  6792.         if v.is() then
  6793.             return v
  6794.         end
  6795.     end
  6796.     error'no match for state'
  6797. end
  6798. function Machine:run(state)
  6799.     state=state or self.states[1]
  6800.     while state do
  6801.         state.action()
  6802.         state=state.next
  6803.     end
  6804. end
  6805.  
  6806. Vec3=require'utils.Vec3'
  6807.  
  6808.  
  6809. Var=require'kernel.class.Var'
  6810. var=Var(fs.combine(_INSTALL_PATH,'ect/quarry.var'))
  6811.  
  6812. winding=require'programs.winding'
  6813.  
  6814. ut=require'utils.turtle'
  6815. for n,mov in pairs(ut) do getfenv()[n]=mov end
  6816. goto=ut.goto
  6817. turn=ut.turn
  6818. clear=function(...)
  6819.     select(Tr)
  6820.     local _,_,dc=ut.clear(...)
  6821.     if dc~=0 then
  6822.         clear_inv()
  6823.     end
  6824. end
  6825. force=function(...)
  6826.     select(Tr)
  6827.     local _,_,dc=ut.force(...)
  6828.     if dc~=0 then
  6829.         clear_inv()
  6830.     end
  6831. end
  6832.  
  6833. place=function(dir,n)
  6834.     clear(dir)
  6835.     select(n)
  6836.     if not has(n) then error('missing '..n) end
  6837.     return ut.place(dir)
  6838. end
  6839. drop=turtle.drop
  6840. refuel=function()
  6841.     return turtle.refuel(64) or error'not fuel'
  6842. end
  6843. clear_inv=function()
  6844.     for i=1,8 do
  6845.         if getCount(i)==0 then
  6846.             break
  6847.         end
  6848.         select(i)
  6849.         drop()
  6850.     end
  6851. end
  6852. local fuel
  6853. api.ensureFuel=function()
  6854.     if turtle.getFuelLevel()<10 then
  6855.         if fuel then
  6856.             refuel_machine:run()
  6857.         else
  6858.             print'Out of fuel'
  6859.             repeat
  6860.                 sleep(5)
  6861.             until turtle.getFuelLevel()>10
  6862.         end
  6863.     end
  6864. end
  6865.  
  6866. inv={
  6867. R=9,
  6868. C=10,
  6869. M=11,
  6870. T=12,
  6871. I=13,
  6872. F=14,
  6873. Fu=15,
  6874. Tr=1,
  6875. }
  6876. local env=getfenv()
  6877. for i,n in pairs(inv) do env[i]=n end
  6878.  
  6879. function isInv(a,b,c,d)
  6880.     local function is(s)
  6881.         local c=turtle.getItemCount(s)
  6882.         if c==0 or c==1 then return c
  6883.         else error('inv not match') end
  6884.     end
  6885.     return is(R)==a and is(C)==b and is(M)==c and is(T)==d
  6886. end
  6887.  
  6888. select=turtle.select
  6889. has=function(n)
  6890.     local c=turtle.getItemCount(n)
  6891.     if c~=1 and c~=0 then error'no inv match'
  6892.     else return c==1 end
  6893. end
  6894. getPart=function(n,dir)
  6895.     select(n)
  6896.     repeat dir.dig() until (has(n) or sleep(1))
  6897. end
  6898. getCount=turtle.getItemCount
  6899. dof=function(f,g,delay)
  6900.     return function()
  6901.         if f() then return
  6902.         else
  6903.             g()
  6904.             while not f() do
  6905.                 g()
  6906.                 if delay then sleep(delay) end
  6907.             end
  6908.         end
  6909.     end
  6910. end
  6911.  
  6912. refuel_states={
  6913. {
  6914. is=function()
  6915.     return has(F)
  6916. end,
  6917. action=function()
  6918.     place(up,F)
  6919. end,
  6920. },
  6921. {
  6922. is=function() return not has(F) end,
  6923. action=function()
  6924.     local fill=dof(function() return getCount(Fu)~=0 end,up.suck,1)
  6925.     select(Fu)
  6926.     repeat
  6927.         fill()
  6928.         refuel()
  6929.     until turtle.getFuelLevel()>10 or sleep(1)
  6930.     getPart(F,up)
  6931. end,
  6932. },
  6933. }
  6934.  
  6935. well_states={
  6936. {is=function()
  6937.     return isInv(1,1,1,1)
  6938. end,
  6939. action=function()
  6940.     clear(bottom)
  6941.     force(forward)
  6942.     place(down,M)
  6943.     force(back)
  6944.     place(down,C)
  6945. end,
  6946. },
  6947. {is=function()
  6948.     return isInv(1,0,0,1)
  6949. end,
  6950. action=function()
  6951.     place(front,R)
  6952.     sleep(delay)
  6953. end,
  6954. },
  6955. {is=function()
  6956.     return isInv(0,0,0,1) and front.detect()
  6957. end,
  6958. action=function()
  6959.     force(back)
  6960.     clear_inv()
  6961. end},
  6962. {is=function()
  6963.     return isInv(0,0,0,1) and not front.detect()
  6964. end,
  6965. action=function()
  6966.     place(front,T)
  6967. end,
  6968. },
  6969. {is=function()
  6970.     return isInv(0,0,0,0)
  6971. end,
  6972. action=function()
  6973.     local p=peripheral.wrap('front')
  6974.     assert(p)
  6975.     p.shutdown()
  6976.     p.turnOn()
  6977.     select(R)
  6978.     repeat
  6979.         front.suck()
  6980.     until has(R)
  6981.     p.shutdown()
  6982. end,
  6983. },
  6984. {is=function()
  6985.     return isInv(1,0,0,0)
  6986. end,
  6987. action=function()
  6988.     getPart(T,front)
  6989. end,
  6990. },
  6991. {is=function()
  6992.     return isInv(1,0,0,1) and not down.detect()
  6993. end,
  6994. action=function()
  6995.     select(16)
  6996.     force(front)
  6997. end,
  6998. },
  6999. {is=function()
  7000.     return isInv(1,0,0,1)
  7001. end,
  7002. action=function()
  7003.     getPart(C,down)
  7004. end,
  7005. },
  7006. {is=function()
  7007.     return isInv(1,1,0,1) and not down.detect()
  7008. end,
  7009. action=function()
  7010.     force(front)
  7011. end,
  7012. },
  7013. {is=function()
  7014.     return isInv(1,1,0,1) and down.detect()
  7015. end,
  7016. action=function()
  7017.     getPart(M,down)
  7018. end,
  7019. },
  7020. }
  7021.  
  7022. recharge_states={
  7023. {
  7024. is=function()
  7025.     return has(I)
  7026. end,
  7027. action=function()
  7028.     place(up,I)
  7029. end,
  7030. },
  7031. {
  7032. is=function() return ((not has(I)) and has(R)) end,
  7033. action=function()
  7034.     select(R)
  7035.     repeat
  7036.         up.drop()
  7037.     until (not has(R))
  7038. end,
  7039. },
  7040. {
  7041. is=function() return not (has(I) or has(R)) end,
  7042. action=function()
  7043.     sleep(2)
  7044.     select(R)
  7045.     repeat
  7046.         up.suck()
  7047.     until (has(R))
  7048.     var.count=0
  7049.     select(I)
  7050.     up.dig()
  7051. end,
  7052. },
  7053. }
  7054.  
  7055. refuel_machine=Machine(refuel_states)
  7056. recharge_machine=Machine(recharge_states)
  7057. well_machine=Machine(well_states)
  7058.  
  7059. wind_machine={
  7060. run=function(self,center)
  7061.     function project(v)
  7062.         return {v.x,v.z}
  7063.     end
  7064.     local p=project((get())-center)
  7065.     var.count=var.count or 0
  7066.     repeat
  7067.         if var.count>max_count then
  7068.             recharge_machine:run()
  7069.         end
  7070.        
  7071.         -- print('actual:',p[1],p[2])
  7072.         local n=winding{p[1],p[2]}
  7073.         -- print('winding:',n[1],n[2])
  7074.         -- print('turning:',n[1]-p[1],0,n[2]-p[2])
  7075.         turn{n[1]-p[1],0,n[2]-p[2]}
  7076.         -- print('pos,dir:',get())
  7077.         local x,z=p[1],p[2]
  7078.         local d=math.max(math.abs(x),math.abs(z))
  7079.         if (not(x==d and z==(d-1))) and ((not(d==math.abs(x) and d==math.abs(z))) or (d==x and d==-z)) then
  7080.             well_machine:run()
  7081.         end
  7082.         local nex=center+Vec3{n[1],0,n[2]}
  7083.         -- print('to:',nex)
  7084.         select(Tr)
  7085.         goto(nex)
  7086.         clear_inv()
  7087.         p=n
  7088.     until false
  7089. end,
  7090. }
  7091.  
  7092. function resume()
  7093.     order={
  7094.     refuel_machine,
  7095.     recharge_machine,
  7096.     well_machine,
  7097.     }
  7098.     if not fuel then table.remove(order,1) end
  7099.     for _,machine in ipairs(order) do
  7100.         local s=machine:find()
  7101.         if not s.start then
  7102.             machine:run(s)
  7103.         end
  7104.     end
  7105. end
  7106.  
  7107. function main(opts)
  7108.     delay=assert(opts.delay)
  7109.     max_count=assert(opts.count)
  7110.     fuel=assert(opts.fuel~=nil) and opts.fuel
  7111.     resume()
  7112.     var.center=var.center or (get())
  7113.     wind_machine:run(Vec3(var.center))
  7114. end
  7115. ]===================],"CoolisOS/bin/programs/question.lua",[===================[--CoolisOS/dev/question.lua
  7116.  
  7117. local questions=loadfile'CoolisOS/dev/questions'()
  7118.  
  7119. local set=rs.setOutput
  7120. local setDoor=function(...) return set('back',...) end
  7121. local setFire=function(...) return set('bottom',...) end
  7122. for i,v in pairs(rs.getSides()) do
  7123.     set(v,false)
  7124. end
  7125.  
  7126. local right=function()
  7127.     reset_term()
  7128.     print'Right Answer! Pass throught the door!'
  7129.     setDoor(true)
  7130.     sleep(2)
  7131.     setDoor(false)
  7132. end
  7133. local function pulse(f,delay)
  7134.     f(true)
  7135.     sleep(delay)
  7136.     f(false)
  7137.     sleep(delay)
  7138. end
  7139.  
  7140. local wrong=function()
  7141.     reset_term()
  7142.     print'Wrong answer! Burn in hell!'
  7143.     local t=os.clock()
  7144.     while (os.clock()-t)<20 do
  7145.         pulse(setFire,1)
  7146.     end
  7147. end
  7148.  
  7149. function reset_term()
  7150.     term.clear()
  7151.     term.setCursorPos(1,1)
  7152. end
  7153.  
  7154. function copy(t)
  7155.     local c={}
  7156.     for i,v in pairs(t) do
  7157.         c[i]=v
  7158.     end
  7159.     return c
  7160. end
  7161.  
  7162. local get_permut
  7163. do
  7164. local permgen
  7165. permgen = function (a, n, fn)
  7166. if n == 0 then
  7167. fn(a)
  7168. else
  7169. for i=1,n do
  7170. -- put i-th element as the last one
  7171. a[n], a[i] = a[i], a[n]
  7172.  
  7173. -- generate all permutations of the other elements
  7174. permgen(a, n - 1, fn)
  7175.  
  7176. -- restore i-th element
  7177. a[n], a[i] = a[i], a[n]
  7178.  
  7179. end
  7180. end
  7181. end
  7182.  
  7183. --- an iterator over all permutations of the elements of a list.
  7184. -- Please note that the same list is returned each time, so do not keep references!
  7185. -- @param a list-like table
  7186. -- @return an iterator which provides the next permutation as a list
  7187. function permute_iter (a)
  7188. local n = #a
  7189. local co = coroutine.create(function () permgen(a, n, coroutine.yield) end)
  7190. return function ()   -- iterator
  7191. local code, res = coroutine.resume(co)
  7192. return res
  7193. end
  7194. end
  7195.  
  7196. local function factorial(n)
  7197.     if n==0 then return 1 end
  7198.     return n*factorial(n-1)
  7199. end
  7200.  
  7201. function get_permut(t)
  7202.     local n=math.random()*(factorial(#t))
  7203.     local iter=permute_iter(t)
  7204.     for i=1,n-1 do iter() end
  7205.     local perm=iter()
  7206.     return perm
  7207. end
  7208. end
  7209.  
  7210. function test()
  7211.     for i,question in pairs(questions) do
  7212.         reset_term()
  7213.         print(question[1])
  7214.         if type(question[2])=='string' then
  7215.             print'Type answer.'
  7216.             if question[2]~=read() then
  7217.                 return false                                                                                                                                               
  7218.             end
  7219.         else
  7220.             local permut=get_permut(copy(question[2]))
  7221.             for i,answer in pairs(permut) do
  7222.                 print(i..')'..answer)
  7223.             end
  7224.             print'Press the number key matching the right answer'
  7225.             local id,ev,ok
  7226.             repeat
  7227.                 local t={os.pullEvent()}
  7228.                 ev,id=t[1],t[2]
  7229.                 ok,id=pcall(tonumber,id)
  7230.             until (ev=='char' and type(id)=='number' and 1<=id and id<=#permut)
  7231.             if permut[id]~=question[2][1] then
  7232.                 return false
  7233.             end
  7234.         end
  7235.     end
  7236.     return true
  7237. end
  7238.  
  7239. os.pullEvent=os.pullEventRaw
  7240. wrong()
  7241. repeat
  7242.     if test() then
  7243.         right()
  7244.     else
  7245.         wrong()
  7246.     end
  7247. until false]===================],"CoolisOS/bin/programs/questions",[===================[local questions={
  7248.         {
  7249.         [[When was LG Founded??]],
  7250.         [[2000]],
  7251.         },
  7252.         {
  7253.                 [[Who of the following is NOT a member of LG?]],
  7254.                 {
  7255.                 'DarkRaven',
  7256.                 'FatherAbel',
  7257.                 'Tuglowz',
  7258.                 'Sanitty',
  7259.                 },
  7260.         },
  7261.         {
  7262.         [[What is Legacy Gaming's website address minus the www]],
  7263.        [[legacygaming.com]],
  7264.        },
  7265.        {
  7266.                [[How Does LG Staff handle griefing?]],
  7267.                {
  7268.                'All of these',
  7269.                'With a Ban',
  7270.                'With Jail',
  7271.                'With Smite',
  7272.                'None of these (except this one)',
  7273.                },
  7274.        },
  7275.        {
  7276.                [[What are you supposed to do if you see someone breaking the rules?]],
  7277.                {
  7278.                [[Message an Admin AND Email [email protected]]],
  7279.                [[Message an Admin]],
  7280.                [[Call the police]],
  7281.                [[Email [email protected]]],
  7282.                [[Message an Admin AND Call the police]],
  7283.                [[All of these]],
  7284.                },
  7285.        },
  7286.        {
  7287.                [[What is the Owner of LG's Minecraft Name?]],
  7288.                 [[RoseD83]],
  7289.         },
  7290. }
  7291. return questions]===================],"CoolisOS/bin/programs/recharge.lua",[===================[--Recharger
  7292. --log.setLevel('INFO','recharge')
  7293. _log=log
  7294. log=function(...) return _log('recharge',...) end
  7295. args={...}
  7296. tmax=args[1] and tonumber(args[1]) or 1800
  7297. local Var=require'kernel.class.Var'
  7298. var=Var('ect/recharger.var')
  7299. local t=require'utils.turtle'
  7300. local pdir=t.moves.forward
  7301. local tdir=t.moves.down
  7302. g1=pdir.detect
  7303. g2=function() return turtle.getItemCount(1)==1 end
  7304. g3=function() return turtle.getItemCount(2)==1 end
  7305. select=turtle.select
  7306. function out()
  7307.     log('INFO','outputing cell')
  7308.     select(2)
  7309.     repeat
  7310.         tdir.drop()
  7311.         if not(g3() and g2()) then break else sleep(1) end
  7312.     until false
  7313.     log('INFO','done')
  7314. end
  7315. function place()
  7316.     log('INFO','placing cell')
  7317.     select(1)
  7318.     repeat
  7319.         pdir.place()
  7320.         if (not g2()) and g1() then break else sleep(1) end
  7321.     until g1()
  7322.     log('INFO','done')
  7323. end
  7324. function remove()
  7325.     log('INFO','removing cell')
  7326.     select(2)
  7327.     t.clear(pdir)
  7328.     log('INFO','done')
  7329. end
  7330. local BREAK
  7331. function main()
  7332. sleep(5)
  7333. repeat
  7334. log('INFO','starting')
  7335. if g1() and g2() then
  7336.     remove()
  7337. end
  7338. if g2() and g3() then
  7339.     out()
  7340.     sleep(5)
  7341. end
  7342. if g2() and not g3() then
  7343.     place()
  7344.     var.count=0
  7345. end
  7346. if g1() and not (g2() and g3())then
  7347.     log('INFO','recharging')
  7348.     var.count=var.count or 0
  7349.     tc=var.count
  7350.     ti=os.clock()
  7351.     select(1)
  7352.     repeat
  7353.         var.count=(os.clock()-ti)+tc
  7354.         print('now:'..var.count..';max='..tmax)
  7355.         sleep(1)
  7356.         tdir.suck()
  7357.         if g2() or BREAK then break end
  7358.     until var.count>tmax
  7359.     log('INFO','done')
  7360.     remove()
  7361. end
  7362. if g3() and not(g1() and g2()) then
  7363.     log('INFO','waiting for input')
  7364.     select(1)
  7365.     repeat
  7366.         tdir.suck()
  7367.         if not g2() then
  7368.             sleep(1)
  7369.         else
  7370.             break
  7371.         end
  7372.     until false
  7373.     log('INFO','done')
  7374. end
  7375. sleep(1)
  7376. log('INFO','done')
  7377. until false
  7378. end]===================],"CoolisOS/bin/programs/test.lua",[===================[--CoolisOS/dev/test.lua
  7379.  
  7380. -- r()
  7381. -- function r()
  7382. -- v=loadreq.reload'utils.Vec3'
  7383. -- t=loadreq.reload'utils.turtle'
  7384. -- end
  7385. -- r()
  7386. -- function g()
  7387. -- shell.run('CoolisOS/dev/quarry.lua')
  7388. -- m=recharge_machine
  7389. -- end
  7390. -- g()
  7391.  
  7392. -- function r()
  7393.     -- w=loadreq.reload'dev.winding'
  7394.     -- iter=function(_,p) return w(p) end
  7395.     -- for p in iter,nil,{0,0} do
  7396.         -- print(p[1],',',p[2])
  7397.         -- os.pullEvent'key'
  7398.     -- end
  7399. -- end
  7400. -- sched.wait(sched.platform,'*')
  7401. function b()
  7402.     printError(debug.traceback())
  7403. end
  7404.  
  7405. function a()
  7406.     b()
  7407. end
  7408. a()]===================],"CoolisOS/bin/programs/text",[===================[#white-black#&-
  7409. Hello!
  7410. #green-white#Green!
  7411. ]===================],"CoolisOS/bin/programs/transpose.lua",[===================[while true do
  7412.   turtle.suckUp()
  7413.   while turtle.getItemCount(1)~=0 do
  7414.     turtle.drop()
  7415.   end
  7416.   sleep(1)
  7417. end]===================],"CoolisOS/bin/programs/winding.lua",[===================[local max=math.max
  7418. local abs=math.abs
  7419.  
  7420. function winding(p)
  7421.     local x,y=p[1],p[2]
  7422.     local ax,ay=abs(x),abs(y)
  7423.     local d=max(ax,ay)
  7424.    
  7425.     if x==d and ay~=d then
  7426.         return {x,y+1}
  7427.     elseif y==d and x~=-d then
  7428.         return {x-1,y}
  7429.     elseif x==-d and y~=-d then
  7430.         return {x,y-1}
  7431.     elseif y==-d then
  7432.         return {x+1,y}
  7433.     elseif y==-d and x==d then
  7434.         return {x+1,y}
  7435.     else print(p[1],p[2]) _error'not a valid state' end
  7436. end
  7437.  
  7438. return winding
  7439.  
  7440. ]===================],"CoolisOS/bin/utils",true,"CoolisOS/bin/utils/git.lua",[===================[local tArgs, gUser, gRepo, gPath, gBranch = {...}, nil, nil, "", "master"
  7441. local usage = [[
  7442.  github <user> <repo> [path] [remote path] [branch]
  7443.  Remote path defaults to the root of the repo.
  7444.  Path defaults to the download folder.
  7445.  Branch defaults to master.
  7446.  If you want to leave an option empty use a dot.
  7447.  Example: github johnsmith hello-world . foo
  7448.  Everything inside the directory foo will be
  7449.  downloaded to downloads/hello-world/.
  7450.   ]]
  7451. local blackList = [[
  7452. @blacklistedfile
  7453. ]]
  7454.  
  7455. local title = "Github Repo Downloader"
  7456. local fileList = {dirs={},files={}}
  7457. local x , y = term.getSize()
  7458.  
  7459. -- GUI
  7460. function printTitle()
  7461.     local line = 2
  7462.     term.setCursorPos(1,line)
  7463.     for i = 2, x, 1 do write("-") end
  7464.     term.setCursorPos((x-title:len())/2,line+1)
  7465.     print(title)
  7466.     for i = 2, x, 1 do write("-") end
  7467. end
  7468.  
  7469. function writeCenter( str )
  7470.     term.clear()
  7471.     printTitle()
  7472.     term.setCursorPos((x-str:len())/2-1,y/2-1)
  7473.     for i = -1, str:len(), 1 do write("-") end
  7474.     term.setCursorPos((x-str:len())/2-1,y/2)
  7475.     print("|"..str.."|")
  7476.     term.setCursorPos((x-str:len())/2-1,y/2+1)
  7477.     for i = -1, str:len(), 1 do write("-") end
  7478. end
  7479.  
  7480. function printUsage()
  7481.     local str = "Press space key to continue"
  7482.     term.clear()
  7483.     printTitle()
  7484.     term.setCursorPos(1,y/2-4)
  7485.     print(usage)
  7486.     term.setCursorPos((x-str:len())/2,y/2+7)
  7487.     print(str)
  7488.     while true do
  7489.         local event, param1 = os.pullEvent("key")
  7490.         if param1 == 57 then
  7491.             sleep(0)
  7492.             break
  7493.         end
  7494.     end
  7495.     term.clear()
  7496.     term.setCursorPos(1,1)
  7497. end
  7498.  
  7499. -- Download File
  7500. function downloadFile( path, url, name )
  7501.     writeCenter("Downloading File: "..name)
  7502.     dirPath = path:gmatch('([%w%_%.% %-%+%,%;%:%*%#%=%/]+)/'..name..'$')()
  7503.     if dirPath ~= nil and not fs.isDir(dirPath) then fs.makeDir(dirPath) end
  7504.     local content = http.get(url)
  7505.     local file = fs.open(path,"w")
  7506.     file.write(content.readAll())
  7507.     file.close()
  7508. end
  7509.  
  7510. -- Get Directory Contents
  7511. function getGithubContents( path )
  7512.     local pType, pPath, pName, checkPath = {}, {}, {}, {}
  7513.     local response = http.get("https://api.github.com/repos/"..gUser.."/"..gRepo.."/contents/"..path.."/?ref="..gBranch)
  7514.     if response then
  7515.         response = response.readAll()
  7516.         if response ~= nil then
  7517.             for str in response:gmatch('"type":"(%w+)"') do table.insert(pType, str) end
  7518.             for str in response:gmatch('"path":"([^\"]+)"') do table.insert(pPath, str) end
  7519.             for str in response:gmatch('"name":"([^\"]+)"') do table.insert(pName, str) end
  7520.         end
  7521.     else
  7522.         writeCenter( "Error: Can't resolve URL" )
  7523.         sleep(2)
  7524.         term.clear()
  7525.         term.setCursorPos(1,1)
  7526.         error()
  7527.     end
  7528.     return pType, pPath, pName
  7529. end
  7530.  
  7531. -- Blacklist Function
  7532. function isBlackListed( path )
  7533.     if blackList:gmatch("@"..path)() ~= nil then
  7534.         return true
  7535.     end
  7536. end
  7537.  
  7538. -- Download Manager
  7539. function downloadManager( path )
  7540.     local fType, fPath, fName = getGithubContents( path )
  7541.     for i,data in pairs(fType) do
  7542.         if data == "file" then
  7543.             checkPath = http.get("https://raw.github.com/"..gUser.."/"..gRepo.."/"..gBranch.."/"..fPath[i])
  7544.             if checkPath == nil then
  7545.                
  7546.                 fPath[i] = fPath[i].."/"..fName[i]
  7547.             end
  7548.             local path = "downloads/"..gRepo.."/"..fPath[i]
  7549.             if gPath ~= "" then path = gPath.."/"..gRepo.."/"..fPath[i] end
  7550.             if not fileList.files[path] and not isBlackListed(fPath[i]) then
  7551.                 fileList.files[path] = {"https://raw.github.com/"..gUser.."/"..gRepo.."/"..gBranch.."/"..fPath[i],fName[i]}
  7552.             end
  7553.         end
  7554.     end
  7555.     for i, data in pairs(fType) do
  7556.         if data == "dir" then
  7557.             local path = "downloads/"..gRepo.."/"..fPath[i]
  7558.             if gPath ~= "" then path = gPath.."/"..gRepo.."/"..fPath[i] end
  7559.             if not fileList.dirs[path] then
  7560.                 writeCenter("Listing directory: "..fName[i])
  7561.                 fileList.dirs[path] = {"https://raw.github.com/"..gUser.."/"..gRepo.."/"..gBranch.."/"..fPath[i],fName[i]}
  7562.                 downloadManager( fPath[i] )
  7563.             end
  7564.         end
  7565.     end
  7566. end
  7567.  
  7568. -- Main Function
  7569. function main( path )
  7570.     writeCenter("Connecting to Github")
  7571.     downloadManager(path)
  7572.     for i, data in pairs(fileList.files) do
  7573.         downloadFile( i, data[1], data[2] )
  7574.     end
  7575.     writeCenter("Download completed")
  7576.     sleep(2,5)
  7577.     term.clear()
  7578.     term.setCursorPos(1,1)
  7579. end
  7580.  
  7581. -- Parse User Input
  7582. function parseInput( user, repo , dldir, path, branch )
  7583.     if path == nil then path = "" end
  7584.     if branch ~= nil then gBranch = branch end
  7585.     if repo == nil then printUsage()
  7586.     else
  7587.         gUser = user
  7588.         gRepo = repo
  7589.         if dldir ~= nil then gPath = dldir end
  7590.         main( path )
  7591.     end
  7592. end
  7593.  
  7594. if not http then
  7595.     writeCenter("You need to enable the HTTP API!")
  7596.     sleep(3)
  7597.     term.clear()
  7598.     term.setCursorPos(1,1)
  7599. else
  7600.     for i=1, 5, 1 do
  7601.         if tArgs[i] == "." then tArgs[i] = nil end
  7602.     end
  7603.     parseInput( tArgs[1], tArgs[2], tArgs[3], tArgs[4], tArgs[5] )
  7604. end]===================],"CoolisOS/bin/utils/linked.lua",[===================[include'kernel.class'
  7605. local pairs=pairs
  7606. local print=print
  7607.  
  7608. class.Linked()
  7609.  
  7610. function Linked:__init(t)
  7611.     self.r,self.l={[0]=-1},{[-1]=0}
  7612.     if t then self:append_r(t) end
  7613. end
  7614.  
  7615. function Linked._insert(t,val,i_l,i_r)
  7616.     if t.r[val] then return end
  7617.     i_l,i_r=i_l or 0,i_r or -1
  7618.     --handle left               right
  7619.     t.r[i_l],   t.l[val],   t.r[val],   t.l[i_r]
  7620.     =   val,            i_l,        i_r,        val
  7621. end
  7622.  
  7623. function Linked.insert_l(t,val,i_l)
  7624.     return Linked._insert(t,val,i_l,t.r[i_l or 0])
  7625. end
  7626.  
  7627. function Linked.insert_r(t,val,i_r)
  7628.     return Linked._insert(t,val,t.l[i_r or -1],i_r)
  7629. end
  7630.  
  7631. function Linked.remove(t,val)
  7632.     val=val or t.r[0]
  7633.     if t.r[val] then t.r[t.l[val]],t.l[t.r[val]],t.r[val],t.l[val]=t.r[val],t.l[val],nil,nil end
  7634.     if val==-1 then val=nil end
  7635.     return val,t.r[val]
  7636. end
  7637.  
  7638. function Linked.next_r(t,ind)
  7639.     local _=t.r[ind or 0]
  7640.     if _~=-1 then return _ end
  7641. end
  7642.  
  7643. function Linked.next_l(t,ind)
  7644.     local _=t.r[ind or -1]
  7645.     if _~=0 then return _ end
  7646. end
  7647.  
  7648. function Linked.__tostring(t)
  7649.     s={}
  7650.     for i in self.next_r,t,nil do
  7651.         table.insert(s,tostring(i))
  7652.     end
  7653.     return 'Linked instance:'..table.concat(s,'<>')
  7654. end
  7655.  
  7656. function Linked:append_r(t)
  7657.     local old
  7658.     for i,v in ipairs(t) do
  7659.         self:insert_r(v,old)
  7660.         -- print(v,old)
  7661.         -- read()
  7662.         old=v
  7663.     end
  7664. end
  7665.  
  7666. function Linked:has(val)
  7667.     return self.r[val]~=nil
  7668. end
  7669. function Linked:isempty()
  7670.     return self.r[0]==-1
  7671. end
  7672. Linked.append=Linked.append_r
  7673. Linked.push=Linked.insert_r
  7674. Linked.pop=Linked.remove
  7675.  
  7676. function Linked.test()
  7677.     t={'a',3,4}
  7678.     l=Linked(t)
  7679.     print(l)
  7680.     l:remove(3)
  7681.     print(l)
  7682.     print(l:has(4),l:has(3))
  7683.     return l
  7684. end
  7685.  
  7686.  
  7687.  
  7688. return Linked]===================],"CoolisOS/bin/utils/luau.lua",[===================[-- luau: Lua-upgraded
  7689.  
  7690. -- Since we're sharing our scope with the user, make a table to keep
  7691. -- all our stuff in, so we pollute the namespace as little as possible:
  7692. luau_={}
  7693. luau_.n = 0         -- current line number
  7694. luau_.opt = {}      -- options data
  7695. luau_.mac = {}      -- macros
  7696. -- A default macro:
  7697. luau_.mac.la = {['def']='os.loadAPI("%1")',['pnum']=1}
  7698.  
  7699. -- Default option settings:
  7700. luau_.opt.skip_lines={
  7701.     ['type'] = 'number',
  7702.     ['value'] = 0,
  7703.     ['default'] = 0,
  7704.     ['desc']='Number of blank lines to skip between input/output pairs.'
  7705. }
  7706. luau_.opt.use_color={
  7707.     ['type'] = 'boolean',
  7708.     ['value'] = true,
  7709.     ['default'] = true,
  7710.     ['desc']='Whether to use color, if available.'
  7711. }
  7712.  
  7713. -- Some variables we do want to expose:
  7714. in_ = {}      -- input history
  7715. out_ = {}     -- output history
  7716.  
  7717.  
  7718. -- Help topics:
  7719. luau_.help = {}
  7720.  
  7721. luau_.help.summary = 'The following topics are available, and can be abbreviated--for instance, "/help sub" for "/help substitution".'
  7722.  
  7723. luau_.help.substitution = 'Typing "s/find-expr/replace-expr/" will repeat the previously entered line, but with all occurrences of find-expr replaced by replace-expr. Lua\'s string-matching patterns may be used in find-expr. This is often quicker than using up-arrow to recall the command and editing it manually.'
  7724.  
  7725. luau_.help.history = 'The tables in_ and out_ hold the input and output histories, and can be referenced, for example: "result=out_[9]".'
  7726.  
  7727. luau_.help['repeat-command'] = 'To repeat a previous input, use the "!<n>" command. For example, typing !23 will re-evaluate the 23rd command in the history.'
  7728.  
  7729. luau_.help['question-mark'] = 'The "?" character is a shortcut for print: "?foo" is short for "print(foo)". If foo is a table, then its keys and values will be displayed.'
  7730.  
  7731. luau_.help['macros'] = 'You can define macros to shorten frequently-typed strings. For example, if you type "/macro %la=os.loadAPI", then in the future any occurence of "%la" in commands you type will be changed to "os.loadAPI" before processing by Lua.\n\nMacros can also accept parameters. For example, "/macro %rs=rednet.send(%1,%2)" will tell luau to expand "%rs[23][\'hi!\']" into "rednet.send(23,\'hi!\')".\n\nParameters may appear more than once and out of order--a silly example is "/macro %palindrome=%3%2%1%2%3", which expands "%palindrome[A][B][C]" into "CBABC".'
  7732.  
  7733. luau_.help['commands'] = 'Luau has some built-in commands which are invoked by starting a line with the slash "/" character. Type "/commands" for a list.'
  7734.  
  7735. -- Build a sorted list of help topics:
  7736. luau_.helpkeys = {}
  7737. for k in pairs(luau_.help) do
  7738.     if k~='summary' then
  7739.         table.insert(luau_.helpkeys, k)
  7740.     end
  7741. end
  7742. table.sort(luau_.helpkeys)
  7743.  
  7744. -- Define the appropriate color function:
  7745. if term.isColor() then
  7746.     term.setTextColor(colors.gray)
  7747.     luau_.setColor = function(c)
  7748.         if luau_.opt.use_color.value then
  7749.             term.setTextColor(c)
  7750.         else
  7751.             term.setTextColor(gray)
  7752.         end
  7753.     end
  7754. else
  7755.     luau_.setColor = function(c) return end
  7756. end
  7757.  
  7758. luau_.terminated = false
  7759. -- End of initialization code.
  7760.  
  7761. function luau_.terminate()
  7762.     -- Goodbye, cruel world:
  7763.     luau_.terminated = true
  7764. end
  7765.  
  7766. function luau_.separator()
  7767.     -- A line of dashes, of the appropriate length:
  7768.     return(string.rep('-', term.getSize()))
  7769. end
  7770.  
  7771. function luau_.loadData()
  7772.     -- Load config options and macros:
  7773.     local h
  7774.     if fs.exists('luau.conf') then
  7775.         h = fs.open('luau.conf','r')
  7776.         local opt, mac
  7777.         opt = textutils.unserialize(h.readLine())
  7778.         mac = textutils.unserialize(h.readLine())
  7779.         h.close()
  7780.         if type(opt)=='table' and type(mac)=='table' then
  7781.             luau_.opt = opt
  7782.             luau_.mac = mac
  7783.             return true
  7784.         else
  7785.             luau_.showError('Unable to load configuration; /luau.conf is corrupt. Exiting. (Delete or rename /luau.conf to start fresh)')
  7786.             return false
  7787.         end
  7788.     else
  7789.         luau_.setColor(colors.blue)
  7790.         print('Configuration file /luau.conf does not exist; creating with default values.')
  7791.         luau_.saveData()
  7792.         return true
  7793.     end
  7794. end
  7795.  
  7796. function luau_.saveData()
  7797.     -- Save config options and macros:
  7798.     h = fs.open('luau.conf','w')
  7799.     h.writeLine(textutils.serialize(luau_.opt))
  7800.     h.writeLine(textutils.serialize(luau_.mac))
  7801.     h.close()
  7802. end
  7803.  
  7804. function luau_.firstMatch(s, t)
  7805.     for i, k in ipairs(t) do
  7806.         if string.find(k, s) == 1 then
  7807.             return k
  7808.         end
  7809.     end
  7810.     return nil
  7811. end
  7812.  
  7813. function luau_.showError(errorText)
  7814.     -- Report errors to the user
  7815.     luau_.setColor(colors.red)
  7816.     print(errorText)
  7817.     luau_.setColor(colors.gray)
  7818. end
  7819.  
  7820. function luau_.trim(s)
  7821.     -- Trim leading/trailing spaces from string s:
  7822.     return (s:gsub("^%s*(.-)%s*$", "%1"))
  7823. end
  7824.  
  7825. function luau_.macro(s)
  7826.     -- !<n> to re-evaluate n-th input:
  7827.     local a, b, n
  7828.     a, b, n = s:find('!(%d+)')
  7829.     n = tonumber(n)
  7830.     if a == 1 then
  7831.         if in_[n] then
  7832.             s = in_[n]
  7833.         else
  7834.             luau_.showError("History entry "..tostring(n).." not found.")
  7835.             s = ''
  7836.         end
  7837.         return s
  7838.     end
  7839.     -- s/foo/bar/ substitutions
  7840.     a, b, find, replace, flags = s:find('s/(.+)/(.*)/(.*)')
  7841.     if find and in_[luau_.n] then
  7842.         s = in_[luau_.n-1]:gsub(find, replace)
  7843.         return s
  7844.     end
  7845.     -- Macro expansion:
  7846.     local lMark, rMark = '>tboss>', '<tboss<'
  7847.     -- This lMark/rMark business is an ugly hack that wouldn't be
  7848.     -- necessary if I knew how to directly capture the stuff INSIDE a
  7849.     -- balanced expression captured with %b[], i.e. without the brackets.
  7850.     for name, macro in pairs(luau_.mac) do
  7851.         local pattern = '%%'..name..string.rep('(%b[])',macro.pnum)
  7852.         -- This is a workaround for a bug in the string library:
  7853.         local s_ = s..string.rep('[ ]',macro.pnum)
  7854.         local a, b = s_:find(pattern)
  7855.         if b and b<=s:len() then
  7856.             if s_:find(pattern) then
  7857.                 local def = macro.def:gsub('(%%%d)',lMark..'%1'..rMark)
  7858.                 s_ = s_:gsub(pattern, def)
  7859.                 s_ = s_:gsub(lMark..'%[', '')
  7860.                 s_ = s_:gsub('%]'..rMark, '')
  7861.                 s = s_:sub(1, s_:len()-3*macro.pnum)
  7862.             end
  7863.         end
  7864.     end
  7865.     return s
  7866. end
  7867.  
  7868. function luau_.columnList(t)
  7869.     -- Print the elements of t in columns:
  7870.     -- Compute the max length of the names so we can decide
  7871.     -- how many columns to print them in:
  7872.     local maxLen = 0
  7873.     for i,k in ipairs(t) do
  7874.         if string.len(k) > maxLen then maxLen = string.len(k) end
  7875.     end
  7876.     local spacing = 2   -- Spacing between columns
  7877.     local w, h = term.getSize()
  7878.     local nCols = math.floor((w+spacing)/(maxLen+spacing))
  7879.     -- Print all the names in columns:
  7880.     for i, k in ipairs(t) do
  7881.         if (i%nCols == 0) or (i == #t) then
  7882.             print(k)
  7883.         else
  7884.             write(k..string.rep(' ', maxLen+spacing-string.len(k)))
  7885.         end
  7886.     end
  7887. end
  7888.  
  7889. function luau_.showHelp(topic)
  7890.     luau_.setColor(colors.blue)    
  7891.     topic = tostring(topic)
  7892.     if topic ~= '' then
  7893.         -- Do partial matching:
  7894.         local mtopic = luau_.firstMatch(topic, luau_.helpkeys)
  7895.         if luau_.help[mtopic] then
  7896.             local m, n = term.getSize()
  7897.             textutils.pagedPrint('('..mtopic..') '..luau_.help[mtopic],n-3)
  7898.         else
  7899.             print('No help found for "'..topic..'". Type "help" for a list of topics.')
  7900.         end
  7901.     else
  7902.         -- Print help summary and list of topics:
  7903.         print(luau_.help.summary)
  7904.         print(luau_.separator())
  7905.         --luau_.setColor(colors.lightBlue)
  7906.         luau_.columnList(luau_.helpkeys)
  7907.     end
  7908. end
  7909.  
  7910. function luau_.searchHistory(s)
  7911.     -- Print a list of history entries matching s.
  7912.     -- Should refactor this into a search and a print.
  7913.     local nFound = 0
  7914.     for i,v in ipairs(in_) do
  7915.         if string.find(v,s) then
  7916.             print(i..': '..v)
  7917.             nFound = nFound+1
  7918.         end
  7919.     end
  7920.     return nFound
  7921. end
  7922.  
  7923. function luau_.keySort(a, b)
  7924.     -- Order function for table keys, returns true if a<b:
  7925.     if type(a)=='number' and type(b)=='number' then
  7926.         return a<b
  7927.     elseif type(a)=='number' then
  7928.         return true
  7929.     elseif type(b)=='number' then
  7930.         return false
  7931.     elseif type(a)=='string' and type(b)=='string' then
  7932.         return a<b
  7933.     elseif type(a)=='string' then
  7934.         return true
  7935.     elseif type(b)=='string' then
  7936.         return false
  7937.     else
  7938.         return (type(a)<type(b))
  7939.     end
  7940. end
  7941.  
  7942. function luau_.serial(v)
  7943.     -- Wrapper for textutils.serialize, to work with all types
  7944.     if string.find("nil boolean number string table", type(v)) then
  7945.         local err, str = pcall(function() textutils.serialize(v) end)
  7946.         if err then str=tostring(v) end
  7947.         return str
  7948.     else
  7949.         return tostring(v)
  7950.     end
  7951. end
  7952.  
  7953. function luau_.setMacro(p, overwrite)
  7954.     -- Define or redefine a macro:
  7955.     luau_.setColor(colors.yellow)
  7956.     if p=='' then
  7957.         -- Display currently defined macros:
  7958.         print("The following macros are currently defined:")
  7959.         print(luau_.separator())
  7960.         for k in pairs(luau_.mac) do
  7961.             print("%"..k.."="..luau_.mac[k].def)
  7962.         end
  7963.     else
  7964.         -- Should be in the form "%name=def":
  7965.         local a, b, name, def = p:find('%%([%w_]+)=(.*)')
  7966.         if name then
  7967.             -- See if it's already defined:
  7968.             if luau_.mac[name] and not overwrite then
  7969.                 print('Macro %'..name..' is already defined. Use /Macro to overwrite it.')
  7970.                 return false
  7971.             end
  7972.             -- See how many params:
  7973.             local n = 0
  7974.             def:gsub('%%(%d+)', function(s) n=tonumber(s) end)
  7975.             luau_.mac[name] = {['def']=def, ['pnum']=n}
  7976.             -- Save it right away. We could wait until we exit, but
  7977.             -- during development crashes are likely so let's not
  7978.             -- lose people's work.
  7979.             luau_.saveData()
  7980.         else
  7981.             luau_.showError('Invalid macro definition (see /help macro).')
  7982.             return false
  7983.         end
  7984.     end
  7985.     return true
  7986. end
  7987.  
  7988. function luau_.setOpt(p)
  7989.     luau_.setColor(colors.yellow)
  7990.     if p=='' then
  7991.         print('The following options are available. Type "/option <option_name>=<value>" to change, or "/option <option_name>" to get a description.')
  7992.         local keys = {}
  7993.         for k in pairs(luau_.opt) do keys[#keys+1]=k end
  7994.         table.sort(keys, luau_.keySort)
  7995.         print(luau_.separator())
  7996.         for i, k in ipairs(keys) do
  7997.             print(k..'='..tostring(luau_.opt[k].value))
  7998.         end
  7999.     elseif p:find('=') then
  8000.         local a, b, opt, val = p:find("([%w_]+)%s*=%s*(.*)")
  8001.         if luau_.opt[opt] then
  8002.             -- Make sure the types are right:
  8003.             local t = luau_.opt[opt].type
  8004.             local ok = false
  8005.             if t=='boolean' then
  8006.                 local v = val:lower()
  8007.                 if v=='true' or v=='1' or v=='yes' or v=='y' then
  8008.                     luau_.opt[opt].value = true
  8009.                     ok = true
  8010.                 elseif v=='false' or v=='0' or v=='no' or v=='n' then
  8011.                     luau_.opt[opt].value = false
  8012.                     ok = true
  8013.                 end
  8014.             elseif t=='number' then
  8015.                 local v = tonumber(val)
  8016.                 if v then
  8017.                     luau_.opt[opt].value = v
  8018.                     ok = true
  8019.                 end
  8020.             elseif t=='string' then
  8021.                 luau_.opt[opt].value = val
  8022.                 ok = true
  8023.             end
  8024.             if ok then
  8025.                 luau_.saveData()
  8026.             else
  8027.                 print('Value for '..opt..' must be of type '..t..'.')
  8028.             end
  8029.         else
  8030.             print('Option "'..p..'" not found. Type "/option" for a list.')
  8031.         end
  8032.     else
  8033.         if luau_.opt[p] then
  8034.             print(luau_.opt[p].desc..' [type='..luau_.opt[p].type..', value='..tostring(luau_.opt[p].value)..', default='..tostring(luau_.opt[p].default)..']')
  8035.         else
  8036.             print('Option "'..p..'" not found. Type "/option" for a list.')
  8037.         end
  8038.     end
  8039. end
  8040.  
  8041. function luau_.showCommands(p)
  8042.     luau_.setColor(colors.blue)
  8043.     if p=='' then
  8044.         print('The following commands are available. Type "/command <command-name>" for details.')
  8045.         print(luau_.separator())
  8046.         luau_.columnList(luau_.cmdNames)
  8047.     else
  8048.         local cmd = luau_.firstMatch(p, luau_.cmdNames)
  8049.         if cmd then
  8050.             print('/'..cmd..': '..luau_.cmd[cmd].desc)
  8051.         else
  8052.             print('Command "'..p..'" not found. Type "/commands" for a list.')
  8053.         end
  8054.     end
  8055. end
  8056.  
  8057. -- Now that we've defined all our handler functions, we can set up the command list:
  8058. luau_.cmd = {}
  8059. luau_.cmd.help = {
  8060.     ['handler'] = luau_.showHelp,
  8061.     ['desc'] = 'Online help. Type "/help <topic>", or "/help" for a list of topics.',
  8062. }
  8063. luau_.cmd.exit = {
  8064.     ['handler'] = luau_.terminate,
  8065.     ['desc'] = 'Exits Luau and returns you to the shell or wherever else you launched it from.',
  8066. }
  8067. luau_.cmd.history = {
  8068.     ['handler'] = luau_.searchHistory,
  8069.     ['desc'] = 'Typing "/history" will simply print the entire history buffer, while "/history <pattern>" will only show entries matching <pattern>.',
  8070. }
  8071. luau_.cmd.macro = {
  8072.     ['handler'] = function(p) luau_.setMacro(p, false) end,
  8073.     ['desc'] = 'Define a text-expansion macro with "/macro %<name>=<output>", or type "/macro" for a list of existing macros. Type "/help macros" for more details.',
  8074. }
  8075. luau_.cmd.Macro = {
  8076.     ['handler'] = function(p) luau_.setMacro(p, true) end,
  8077.     ['desc'] = 'Same as "/macro", but able to overwrite existing definitions.',
  8078. }
  8079. luau_.cmd.options = {
  8080.     ['handler'] = luau_.setOpt,
  8081.     ['desc'] = 'Type "/options" for a list of all options, "/option <name>" for an option\'s description, or "/option <name>=<value>" to change it.',
  8082. }
  8083. luau_.cmd.commands = {
  8084.     ['handler'] = luau_.showCommands,
  8085.     ['desc'] = 'Type "/commands" for a list of commands, or "/command <command-name>" to view a description of a particular one.',
  8086. }
  8087. luau_.cmdNames = {}
  8088. for k in pairs(luau_.cmd) do table.insert(luau_.cmdNames, k) end
  8089. table.sort(luau_.cmdNames)
  8090.  
  8091.  
  8092. function luau_.go()
  8093.     -- Load config options and macros:
  8094.     if not luau_.loadData() then return false end
  8095.     luau_.setColor(colors.blue)
  8096.     print()
  8097.     print('LUAU--LUA Upgraded v0.1 by Tinyboss\nType "/exit" to exit, "/help" for help.')
  8098.     while not luau_.terminated do
  8099.         luau_.setColor(colors.gray)
  8100.         for i=1,luau_.opt.skip_lines.value do print() end
  8101.         luau_.n = luau_.n+1
  8102.         -- Get the next input, passing the input history for recall by up-arrow:
  8103.         local input = ''
  8104.         while luau_.trim(input)=='' do
  8105.             luau_.setColor(colors.lime)
  8106.             write(' in_['..luau_.n..']: ')
  8107.             luau_.setColor(colors.lightGray)
  8108.             input = luau_.trim(read(false, in_,getfenv(1)))
  8109.         end
  8110.         in_[luau_.n] = input
  8111.         luau_.handled = false
  8112.         -- ? is a shortcut for print, with benefits:
  8113.         if in_[luau_.n]:sub(1,1) == "?" then
  8114.             rest_ = luau_.trim(in_[luau_.n]:sub(2))
  8115.             if rest_ == "" then
  8116.                 -- If they just typed "?", they probably wanted help:
  8117.                 luau_.setColor(colors.blue)
  8118.                 print('"?foo" is a synonym for "print(foo)". Use "/help" for help.')
  8119.                 luau_.handled = true
  8120.             elseif type(getfenv(1)[rest_])=="table" then
  8121.                 -- If it's a table, display it:
  8122.                 local keys = {}
  8123.                 for k in pairs(getfenv(1)[rest_]) do
  8124.                     keys[#keys+1]=k
  8125.                 end
  8126.                 table.sort(keys, luau_.keySort)
  8127.                 local kv = {}
  8128.                 for i,k in ipairs(keys) do
  8129.                     kv[i] = luau_.serial(k)..'='
  8130.                         ..luau_.serial(getfenv(1)[rest_][k])
  8131.                 end
  8132.                 print('{',table.concat(kv, ', '),'}')
  8133.                 luau_.handled = true
  8134.             else
  8135.                 in_[luau_.n] = 'print('..in_[luau_.n]:sub(2)..')'
  8136.             end
  8137.         end
  8138.         if not luau_.handled then
  8139.             -- See if it's a slash command:
  8140.             local a_, b_, cmd_, rest_ = in_[luau_.n]:find('/(%a+)%s*(.*)')
  8141.             if a_==1 then
  8142.                 cmd_ = luau_.firstMatch(cmd_, luau_.cmdNames)
  8143.                 if cmd_ then
  8144.                     luau_.cmd[cmd_].handler(rest_)
  8145.                 else
  8146.                     luau_.setColor(colors.yellow)
  8147.                     print('Invalid command. (Try "/help".)')
  8148.                 end
  8149.             else
  8150.                 -- Do macro substitution before passing it to Lua:
  8151.                 in_[luau_.n] = luau_.macro(in_[luau_.n])
  8152.                 luau_.setColor(colors.gray)
  8153.                 is_print_ = string.sub(in_[luau_.n], 1, 6)=='print('
  8154.                 -- Try it as an expression first:
  8155.                 func_, err_ = loadstring('out_[luau_.n]='..in_[luau_.n])
  8156.                 if err_ then
  8157.                     -- Try it as a statement (e.g. "pi=3"):
  8158.                     func_, err_ = loadstring(in_[luau_.n])
  8159.                     if err_ then
  8160.                         luau_.showError('(loadstring)'..err_)
  8161.                     else
  8162.                         setfenv(func_, getfenv(1))
  8163.                         success_, err_ = pcall(func_)
  8164.                         if not success_ then
  8165.                             luau_.showError(err_)
  8166.                         end
  8167.                     end
  8168.                 else
  8169.                     -- It worked as an expression, so store and show the result:
  8170.                     setfenv(func_, getfenv(1))
  8171.                     success_, err_ = pcall(func_)
  8172.                     if success_ then
  8173.                         if out_[luau_.n] and not is_print_ then
  8174.                             luau_.setColor(colors.green)
  8175.                             write('out_['..luau_.n..']: ')
  8176.                             luau_.setColor(colors.gray)
  8177.                             print(out_[luau_.n])
  8178.                         end
  8179.                     else
  8180.                         luau_.showError(err_)
  8181.                     end
  8182.                 end
  8183.             end
  8184.         end
  8185.     end
  8186.     -- Save config and macro data:
  8187.     luau_.saveData()
  8188. end
  8189.  
  8190. luau_.go()]===================],"CoolisOS/bin/utils/path.lua",[===================[---
  8191. -- Path utils.
  8192. --
  8193. -- **Definition of path** used by this file:
  8194. --
  8195. -- - it is **not Lua path**, Lua path meaning the way Lua provide table indexing.
  8196. --     - especially, **'table[ ]'** notation is not supported
  8197. -- - **element separator is  '.'** (dot)
  8198. -- - provided **path is always cleaned** before being processed:
  8199. --     - if the path starts and/or ends with one or several dots, there are automatically removed.<br />
  8200. --       e.g.: `'...toto.tutu....'` means `'toto.tutu'`  
  8201. --     - internal repetitions of successives dots are replaced by a single dot.<br />
  8202. --       e.g.: `'toto...tutu.tata..foo.bar'` means `'toto.tutu.tata.foo.bar'`  
  8203. -- - if a path element can be **converted to a number**, then it is returned as a number,
  8204. --   otherwise all elements or paths are returned as strings.<br />
  8205. --   e.g.: `split('a.2', 1)` -> `('a', 2)`   (where 2 is returned as a number) <br />
  8206. --   e.g.: `split('a.b.2e3.c', 1)` -> `('a', 'b.2000.c')`  
  8207. --
  8208. -- @module utils.path
  8209. --
  8210. local check = require"kernel.checker".check
  8211.  
  8212. local M = { }
  8213. --public API
  8214. local split,clean,segments, get, set, gsplit, concat, find
  8215.  
  8216. local function pathconcat(pt, starti, endi)
  8217.     local t = {}
  8218.     local prev
  8219.     local empties = 0
  8220.     starti = starti or 1
  8221.     endi = endi or #pt
  8222.    
  8223.     for i = starti, endi do
  8224.         local v = pt[i]
  8225.         if not v then break
  8226.         elseif v == '' then
  8227.             empties = empties+1
  8228.         else
  8229.             table.insert(t, prev)
  8230.             prev = v
  8231.         end
  8232.     end
  8233.     table.insert(t, prev)
  8234.     --log('PATH', 'INFO', "pathconcat(%s, %d, %d) generates table %s, wants indexes %d->%d",
  8235.     --    sprint(pt), starti, endi, sprint(t), 1, endi-starti+1-empties)
  8236.     return table.concat(t, '.', 1, endi-starti+1-empties)
  8237. end
  8238.  
  8239. --------------------------------------------------------------------------------
  8240. -- Concatenates a sequence of path strings together.
  8241. --
  8242. -- @function [parent=#utils.path] concat
  8243. -- @param varargs list of strings to concatenate into a valid path
  8244. -- @return resulting path as a string
  8245. --
  8246.  
  8247. function concat(...)
  8248.     return pathconcat({...})
  8249. end
  8250.  
  8251. --------------------------------------------------------------------------------
  8252. -- Cleans a path.
  8253. --
  8254. -- Removes trailing/preceding/doubling '.'.
  8255. --
  8256. -- @function [parent=#utils.path] clean
  8257. -- @param path string containing the path to clean.
  8258. -- @return cleaned path as a string.
  8259. --
  8260.  
  8261. function clean(path)
  8262.     check('string',path)
  8263.     local p = segments(path)
  8264.     return pathconcat(p)
  8265. end
  8266.  
  8267. --------------------------------------------------------------------------------
  8268. -- Sets a value in a tree-like table structure.
  8269. --
  8270. -- The value to set is indicated by the path relative to the table.
  8271. -- This function creates the table structure to store the value, unless the value to set is nil.
  8272. -- If the value to set is nil and the table structure already exists then the value is set to nil.
  8273. -- If the value is not nil, then the table structure is always created/overwritten and the value set.
  8274. --
  8275. -- @function [parent=#utils.path] set
  8276. -- @param t table where to set the value.
  8277. -- @param path can be either a string (see @{#(utils.path).split})
  8278. --  or an array where path[1] is the root and path[n] is the leaf.
  8279. -- @param value the value to set.
  8280. --
  8281.  
  8282. function set(t, path, value)
  8283.     check('table,string|table',t, path)
  8284.     local p = type(path)=='string' and segments(path) or path
  8285.     local k = table.remove(p)
  8286.     local t = find(t, p, value~=nil) -- only create the table structure if the value to set is non nil!
  8287. --    local t = findtable(t, p, true) -- for the creation of the table structure, even if the value to set is non nil!
  8288.     if t then t[k] = value end
  8289. end
  8290.  
  8291. --------------------------------------------------------------------------------
  8292. -- Gets the value of a table field. The field can be in a sub table.
  8293. --
  8294. -- The field to get is indicated by a path relative to the table.
  8295. --
  8296. -- @function [parent=#utils.path] get
  8297. -- @param t table where to set the value.
  8298. -- @param path can be eiher a string (see @{split}) or an array where path[1] is the root and path[n] is the leaf.
  8299. -- @return value if the field is found.
  8300. -- @return nil otherthise.
  8301. --
  8302. function get(t, path)
  8303.     check('table,string|table',t,path)
  8304.     local p = type(path)=='string' and segments(path) or path
  8305.     local k = table.remove(p)
  8306.     if not k then return t end
  8307.     local t = find(t, p)
  8308.     return t and t[k]
  8309. end
  8310.  
  8311.  
  8312. --------------------------------------------------------------------------------
  8313. -- Enumerates path partitions in a for-loop generator, starting from the right.
  8314. --
  8315. -- For instance, `gsplit "a.b.c"` will generate successively
  8316. -- `("a.b.c", ""), ("a.b", "c"), ("a", "b.c"), ("", "a.b.c")`.
  8317. --
  8318. -- @function [parent=#utils.path] gsplit
  8319. -- @param path the path as a string
  8320. -- @return the for-loop iterator function
  8321. --
  8322.  
  8323. function gsplit (path)
  8324.     check ('string',path)
  8325.     local segs  = segments(path)
  8326.     local nsegs = #segs
  8327.     local limit = nsegs
  8328.     local function f()
  8329.         if limit == -1 then return nil, nil end
  8330.         local a, b = pathconcat(segs, 1, limit), pathconcat(segs, limit+1, nsegs)
  8331.         limit = limit - 1
  8332.         return a, b
  8333.     end
  8334.     return f
  8335. end
  8336.  
  8337. --------------------------------------------------------------------------------
  8338. -- Splits a path into two halves, can be used to get path root, tail etc.
  8339. --
  8340. -- The content of the two halves depends on 'n' param: there will be `n` segments in the first half if `n>0`,
  8341. -- `-n` segments in the second half if `n<0`.
  8342. --
  8343. -- If there are less then `n` segments, returns the path argument followed by
  8344. -- an empty path.
  8345. --
  8346. -- If there are less then `-n` segments, returns an empty path followed by the
  8347. -- path argument.
  8348. --
  8349. -- Note that if a half is a single element and that this element can be converted into a number,
  8350. -- it is returned as a number.
  8351. --
  8352. -- @function [parent=#utils.path] split
  8353. -- @param path the path as a string
  8354. -- @param n number defining how the path is splitted (see above description).
  8355. -- @return the two halves
  8356. -- @usage local root, tail = split('a.b.c', 1)
  8357. -- ->root contains 'a', tail contains 'b.c'
  8358. --
  8359.  
  8360. function split(path, n)
  8361.     check('string,number',path,n)
  8362.     local segments = segments(path)
  8363.     if      n>#segments then return path, ''
  8364.     elseif -n>#segments then return '', path
  8365.     else
  8366.         if n<0 then n=#segments+n end
  8367.         return pathconcat(segments, 1, n), pathconcat(segments, n+1, #segments)
  8368.     end
  8369. end
  8370.  
  8371. --------------------------------------------------------------------------------
  8372. -- Splits a path into segments.
  8373. --
  8374. -- Each segment is delimited by '.' pattern.
  8375. --
  8376. -- @function [parent=#utils.path] segments
  8377. -- @param path string containing the path to split.
  8378. -- @return list of split path elements.
  8379. --
  8380.  
  8381. function segments(path)
  8382.     check('string',path)
  8383.     local t = {}    
  8384.     local index, newindex, elt = 1
  8385.     repeat
  8386.         newindex = path:find(".", index, true) or #path+1 --last round
  8387.         elt = path:sub(index, newindex-1)
  8388.         elt = tonumber(elt) or elt        
  8389.         if elt and elt ~= "" then table.insert(t, elt) end
  8390.         index = newindex+1    
  8391.     until newindex==#path+1    
  8392.     return t
  8393. end
  8394.  
  8395. --------------------------------------------------------------------------------
  8396. -- Retrieves the element in a sub-table corresponding to the path.
  8397. --
  8398. -- @function [parent=#utils.path] find
  8399. -- @param t is the table to look into.
  8400. -- @param path can be either a string (see @{segments}) or an array where
  8401. -- `path[1]` is the root and `path[n]` is the leaf.
  8402. -- @param force parameter allows to create intermediate tables as specified
  8403. --  by the path, if necessary.
  8404. -- @return returned values depend on force value:
  8405. --
  8406. -- * if force is false (or nil), find returns the table if it finds one,
  8407. --   or it returns nil followed by the subpath that points to non table value
  8408. --
  8409. -- * if force is true, find overwrites or create tables as necessary so
  8410. --   it always returns a table.
  8411. --
  8412. -- * if force is 'noowr', find creates tables as necessary but does not
  8413. --   overwrite non-table values. So as with `force=false`, it only returns a
  8414. --   table if possible, and nil followed by the path that points to the first
  8415. --   neither-table-nor-nil value otherwise.
  8416. --
  8417. -- @usage config = {toto={titi={tutu = 5}}}
  8418. --     find(config, "toto.titi") -- will return the table titi
  8419. --
  8420. function find(t, path, force)
  8421.     check('table,string|table', t,path)
  8422.     path = type(path)=="string" and segments(path) or path
  8423.     for i, n in ipairs(path) do
  8424.         local v  = t[n]
  8425.         if type(v) ~= "table" then
  8426.             if not force or (force=="noowr" and v~=nil) then return nil, pathconcat(path, 1, i)
  8427.             else v = {} t[n] = v end
  8428.         end
  8429.         t = v
  8430.     end
  8431.     return t
  8432. end
  8433.  
  8434. --public API
  8435. M.split=split; M.clean=clean; M.segments=segments; M.get=get; M.set=set;
  8436. M.gsplit=gsplit; M.concat=concat; M.find=find
  8437.  
  8438. return M
  8439. ]===================],"CoolisOS/bin/utils/print.lua",[===================[
  8440. local io=io
  8441. local string=string
  8442. local table=table
  8443. local type=type
  8444. local tostring=tostring
  8445. local pairs=pairs
  8446. local print=print
  8447. local getmetatable=getmetatable
  8448. local select=select
  8449.  
  8450. env=getfenv()
  8451. setmetatable(env,nil)
  8452.  
  8453. mtostring=function(...)
  8454.     local t={}
  8455.     for i=1,select('#',...) do
  8456.         table.insert(t,tostring(select(i,...)))
  8457.     end
  8458.     return table.concat(t,';')
  8459. end
  8460.  
  8461. -- Make sure stdout is actually flushed every line
  8462. if io and io.stdout then
  8463.     io.stdout:setvbuf("line")
  8464. end
  8465.  
  8466. local function quotestring(x)
  8467.     local function q(k) return
  8468.         k=='"'  and '\\"'  or
  8469.         k=='\\' and '\\\\' or
  8470.         string.format('\\%03d', k :byte())
  8471.     end
  8472.     return '"' .. x :gsub ('[%z\1-\9\11\12\14-\31\128-\255"\\]', q) .. '"'
  8473. end
  8474.  
  8475. ------------------------------------------------------------------------------
  8476. -- virtual printer: print a textual description of the objects in `...', using
  8477. -- function `write()' as a writer. By providing the appropriate writer, one
  8478. -- can make this function write on a TCP channel, in a string,... anywhere.
  8479. -- print_indent is the number of indentation characters used to render
  8480. -- tables. If nil/false, tables are rendered without carriage returns.
  8481. ------------------------------------------------------------------------------
  8482. function vprint (write, print_indent, ...)
  8483.    local in_progress = { }
  8484.    local indent_level = 0
  8485.    local tinsert = table.insert
  8486.    local function aux(x)
  8487.       local  t=type(x)
  8488.       if     t=="string"  then write(quotestring(x))
  8489.       elseif t=="boolean" then write(x and "true" or "false")
  8490.       elseif t=="number"  then write(tostring(x))
  8491.       elseif t=="nil"     then write("nil")
  8492.       elseif t=="table"   then
  8493.         if getmetatable(x) and getmetatable(x).__tostring then write(tostring(x))
  8494.         elseif in_progress[x] then write(tostring(table)) else
  8495.             in_progress[x] = true
  8496.             indent_level = indent_level+1
  8497.  
  8498.             local function print_separator()
  8499.                 if print_indent then write(",\r\n" .. (" "):rep(print_indent * indent_level))
  8500.                 else write(", ") end
  8501.             end
  8502.  
  8503.             -- number of elements according to pairs(): zero, one, many
  8504.             local at_least_one, more_than_one = false, false
  8505.             for _ in pairs(x) do
  8506.                 if at_least_one then more_than_one=true; break
  8507.                 else at_least_one=true end
  8508.             end
  8509.  
  8510.             if not at_least_one then write "{ }"; return
  8511.             elseif not more_than_one or not print_indent then write "{ "
  8512.             else write("{\r\n" .. (" "):rep(print_indent * indent_level)) end
  8513.  
  8514.             local list_keys = { }
  8515.             local last_list_key = 0
  8516.             repeat
  8517.                 local i = last_list_key + 1
  8518.                 local occupied = x[i]~=nil
  8519.                 if occupied then list_keys[i]=true; last_list_key=i end
  8520.             until not occupied
  8521.  
  8522.             for i=1, last_list_key do
  8523.                 if i>1 then print_separator() end
  8524.                 aux(x[i])
  8525.             end
  8526.            
  8527.             local first_hash_pair = true
  8528.             for k, v in pairs(x) do
  8529.                 if not list_keys[k] then -- don't reprint the list-part
  8530.                     -- separator
  8531.                     if not first_hash_pair or last_list_key~=0 then print_separator() end
  8532.                     first_hash_pair = false
  8533.                     -- key
  8534.                     if type(k)=="string" and k:match"^[%a_][%w_]*$" then write(k .. " = ")
  8535.                     else write("["); aux(k); write("] = ") end
  8536.                     -- value
  8537.                     aux(v)
  8538.                 end
  8539.             end
  8540.             write (" }")
  8541.  
  8542.             indent_level = indent_level-1
  8543.             in_progress[x] = nil
  8544.          end
  8545.       else write(tostring(x)) end
  8546.    end
  8547.    local args = {...}
  8548.    local nb = table.getn(args)
  8549.    for k = 1, nb do aux(args[k]); if k<nb then write "\t" end end
  8550. end
  8551.  
  8552. ------------------------------------------------------------------------------
  8553. -- A more precise print (on stdout)
  8554. ------------------------------------------------------------------------------
  8555. function p (...)
  8556.    local out = {}
  8557.    local function write(s)
  8558.       table.insert(out, s)
  8559.    end
  8560.    vprint(write, 3, ...)
  8561.    print(table.concat(out))
  8562. end
  8563.  
  8564. ------------------------------------------------------------------------------
  8565. -- Build up and return a string instead of printing in some channel.
  8566. ------------------------------------------------------------------------------
  8567. function siprint(indent, ...)
  8568.    local ins, acc = table.insert, { }
  8569.    vprint(function(x) return ins(acc, x) end, indent, ...)
  8570.    return table.concat(acc)
  8571. end
  8572.  
  8573. function sprint(...)
  8574.     return siprint(false, ...)
  8575. end
  8576.  
  8577. function printf(...) return print(string.format(...)) end
  8578.  
  8579. return env]===================],"CoolisOS/bin/utils/serpent.lua",[===================[local n, v = "serpent", 0.224 -- (C) 2012-13 Paul Kulchenko; MIT License
  8580. local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
  8581. local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
  8582. local badtype = {thread = true, userdata = true}
  8583. local keyword, globals, G = {}, {}, (_G or _ENV)
  8584. for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
  8585.   'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
  8586.   'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
  8587. for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
  8588. for _,g in ipairs({'coroutine', 'io', 'math', 'string', 'table', 'os'}) do
  8589.   for k,v in pairs(G[g]) do globals[v] = g..'.'..k end end
  8590.  
  8591. local function s(t, opts)
  8592.   local name, indent, fatal,dname = opts.name, opts.indent, opts.fatal,opts.debug
  8593.   local sparse, custom, huge,dbg = opts.sparse, opts.custom, not opts.nohuge,opts.debug
  8594.   local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
  8595.   local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge)
  8596.   local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0
  8597.   local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)",
  8598.     -- tostring(val) is needed because __tostring may return a non-string value
  8599.     function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end)) end
  8600.   local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s)
  8601.     or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
  8602.     or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
  8603.   local function comment(s,l)
  8604.     return comm and (l or 0) < comm and ' --[['..(dbg and type(s)~='string' and debug.getinfo(s) or tostring(s))..']]' or '' end
  8605.   local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
  8606.     and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end
  8607.   local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
  8608.     local n = name == nil and '' or name
  8609.     local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
  8610.     local safe = plain and n or '['..safestr(n)..']'
  8611.     return (path or '')..(plain and path and '.' or '')..safe, safe end
  8612.   local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n)  -- k=keys, o=originaltable, n=padding
  8613.     local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
  8614.     local function padnum(d) return ("%0"..maxn.."d"):format(d) end
  8615.     table.sort(k, function(a,b)
  8616.       -- sort numeric keys first: k[key] is non-nil for numeric keys
  8617.       return (k[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
  8618.            < (k[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
  8619.   local function val2str(t, name, indent, insref, path, plainindex, level,pass)
  8620.     local ttype, level, mt = type(t), (level or 0), getmetatable(t)
  8621.     local spath, sname = safename(path, name)
  8622.     local tag = plainindex and
  8623.       ((type(name) == "number") and '' or name..space..'='..space) or
  8624.       (name ~= nil and sname..space..'='..space or '')
  8625.     if seen[t] then -- already seen this element
  8626.       if dbg then return tag..comment(t,level) end
  8627.       table.insert(sref, spath..space..'='..space..seen[t])
  8628.       return tag..'nil'..comment('ref'..tostring(t), level) end
  8629.     if mt and not dbg then
  8630.       if mt.__serialize or mt.__tostring then -- knows how to serialize itself
  8631.         seen[t] = insref or spath
  8632.         if rawget(mt,'__serialize') then t = mt.__serialize(t) else t = tostring(t) end
  8633.         ttype = type(t) -- new value falls through to be serialized
  8634.       end
  8635.     end
  8636.     if ttype == "table" then
  8637.       if level >= maxl then return tag..'{}'..comment('max', level) end
  8638.       seen[t] = insref or spath
  8639.       if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
  8640.       local maxn, o, out = #t, {}, {}
  8641.       for key = 1, maxn do table.insert(o, key) end
  8642.       for key in pairs(t) do if not o[key] then table.insert(o, key) end end
  8643.       if opts.sortkeys then alphanumsort(o, t, opts.sortkeys) end
  8644.       for n, key in ipairs(o) do
  8645.         local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
  8646.         if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
  8647.         or opts.keyallow and not opts.keyallow[key]
  8648.         or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
  8649.         or sparse and value == nil then -- skipping nils; do nothing
  8650.         elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then
  8651.           if dbg then
  8652.               local s
  8653.               if not (seen[key] or globals[key]) then
  8654.                 seen[key]=debug.getinfo(key)
  8655.                 s = '['..(val2str(key,nil,indent,nil,nil,false,level+1))..']'..comment(key,level)
  8656.                
  8657.               end
  8658.               table.insert(out,val2str(value,s or (seen[key] or globals[key]),indent,insref,nil,true,level+1))
  8659.           else
  8660.               if not seen[key] and not globals[key] then
  8661.                 local sname = safename(iname, gensym(key)) -- iname is table for local variables
  8662.                 sref[#sref] = val2str(key,sname,indent,sname,iname,true)
  8663.               end
  8664.               table.insert(sref, 'placeholder')
  8665.               local path = seen[t]..'['..(seen[key] or globals[key] or gensym(key))..']'
  8666.               sref[#sref] = path..space..'='..space..(seen[value] or val2str(value,nil,indent,path))
  8667.           end
  8668.         else
  8669.           table.insert(out,val2str(value,key,indent,insref,seen[t],plainindex,level+1))
  8670.         end
  8671.       end
  8672.       local prefix = string.rep(indent or '', level)
  8673.       local head = indent and '{\n'..prefix..indent or '{'
  8674.       local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
  8675.       local tail = indent and "\n"..prefix..'}' or '}'
  8676.       return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level)
  8677.     elseif badtype[ttype] then
  8678.       seen[t] = insref or spath
  8679.       return tag..globerr(t, level)
  8680.     elseif ttype == 'function' and not dbg then
  8681.       seen[t] = insref or spath
  8682.       local ok, res = pcall(string.dump, t)
  8683.       local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
  8684.         "loadstring("..safestr(res)..",'@serialized')")..comment(t, level))
  8685.       return tag..(func or globerr(t, level))
  8686.     else return tag..safestr(t) end -- handle all other types
  8687.   end
  8688.   local sepr = indent and "\n" or ";"..space
  8689.   local body = val2str(t, name, indent) -- this call also populates sref
  8690.   local tail = #sref>1 and table.concat(sref, sepr)..sepr or ''
  8691.   return not name and body or "do local "..body..sepr..tail.."return "..name..sepr.."end"
  8692. end
  8693.  
  8694. local function merge(a, b) if b then for k,v in pairs(b) do a[k] = (a[k]==nil and v or a[k]) end end; return a; end
  8695. return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
  8696.   dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
  8697.   line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
  8698.   block = function(a, opts) return s(a, merge({indent = '  ', sortkeys = true, comment = true}, opts)) end }]===================],"CoolisOS/bin/utils/turtle.lua",[===================[
  8699.  
  8700. --[[
  8701. process:
  8702. -state
  8703. -state handler
  8704. --interrupts
  8705. -state machines?
  8706. -complex for generalism
  8707. -simple for dig queues: <- are generally stateless
  8708.     are kept separately, dig queues are just vector coords
  8709.     position and orientation->state
  8710.     turtle api overwritten to catch movement
  8711.     interpreter command to set position, world-wide
  8712.     implies keepig initial referencial
  8713.     simple wrap-up of goto
  8714. (need stack like state machines for pausing, and then returning)
  8715. -general pathfinding
  8716.     djikstra algorithm
  8717.     maintainig map
  8718.     - imprredictable movement
  8719.     + can contornate obstacles
  8720. ]]
  8721. --state_stack={}
  8722. --
  8723. --
  8724. --
  8725. --function get_move_queue()
  8726. --  local q={}
  8727. --  for i=1,10 do
  8728. --      table.insert(function() goto(Vec3(i,0,0)) end)
  8729. --  end
  8730. --  return q
  8731. --end
  8732. --
  8733. --[[doing queue implies
  8734. --getting state/resuming state
  8735. --executing and saving <- open new, save current, delete old
  8736. --goto needs some context
  8737. --turtle movement is single -coroutined; means that mode can be global
  8738. --]]
  8739. --function get_coords()
  8740. --  f=fs.open('ect/pos','r')
  8741. --  pos=Vec3(textutils.deserialize(f.readAll()))
  8742. --  f.close()
  8743. --  return pos
  8744. --end
  8745. --function save_pos(pos)
  8746. --  f=fs.open('ect/pos','w')
  8747. --  f.writeLine(pos:serialize())
  8748. --  f.close()
  8749. --end
  8750. --
  8751. --
  8752. --function get_state_for(queue)
  8753. --  local coords=get_coords()
  8754. --  for i,v in pairs(queue) do
  8755. --      if v==coords then return i end
  8756. --  end
  8757. --end
  8758. --function do_queue(queue)
  8759. --  cur=get_state_for(queue)
  8760. --  for i=cur,#queue do
  8761. --      goto(queue[i])
  8762. --  end
  8763. --end
  8764. --
  8765. --function main()
  8766. --  mov_queue=get_move_queue()
  8767. --  do_queue(queue)
  8768. --end
  8769.  
  8770. if not turtle then error('not a turtle',2) end
  8771.  
  8772. if turtle._old then
  8773.     turtle=util.shcopy(turtle._old)
  8774. else
  8775.     turtle._old=util.shcopy(turtle)
  8776. end
  8777.  
  8778. local _log=log
  8779. local log=function(...) return _log('turtle',...) end
  8780.  
  8781. include'kernel.class'
  8782. local Vec3=require'utils.Vec3'
  8783.  
  8784. local util=require'kernel.util'
  8785. local Var=require'kernel.class.Var'
  8786.  
  8787. ---forward declaration
  8788. local api
  8789.  
  8790. --persistence
  8791. local pos,dir
  8792. local saveDir=fs.combine(_INSTALL_PATH,'ect/turtle')
  8793. if not fs.exists(saveDir) then fs.makeDir(saveDir) end
  8794.  
  8795. local dump=require'utils.serpent'.dump
  8796. local var=Var(fs.combine(saveDir,'pos-dir.var'))
  8797. local mode=Var(fs.combine(saveDir,'mode.var'))
  8798.  
  8799. local function merge(dst,src)
  8800.     for i,v in pairs(src) do
  8801.         if dst[i]==nil then
  8802.             dst[i]=src[i]
  8803.         end
  8804.     end
  8805. end
  8806. merge(mode,{
  8807. dig=true,
  8808. attack=true,
  8809. count=20,
  8810. delay=0.5,
  8811. gps=false,
  8812. })
  8813.  
  8814. local function save()
  8815.    var.pos=pos
  8816.    var.dir=dir
  8817. end
  8818. local function load()
  8819.     local p,d=var.pos,var.dir
  8820.     pos,dir=p and Vec3(p) or nil,d and Vec3(d) or nil
  8821. end
  8822. local zero=Vec3()
  8823. function set(_pos,_dir)
  8824.     check('?Vec3,?Vec3',_pos,_dir)
  8825.     assert(_dir~=zero)
  8826.     pos,dir=(_pos or pos):clone(),(_dir or dir):clone()
  8827.     save()
  8828. end
  8829. function get() return pos:clone(),dir:clone() end
  8830.  
  8831. local function sign(num)
  8832.     return (num==nil or num==0) and 0 or (num>0 and 1 or -1)
  8833. end
  8834. --fuel handling
  8835. function ensureFuel()
  8836.     if api.ensureFuel then api.ensureFuel() end
  8837. end
  8838. ---
  8839. --atomic overrides of the turtle api and moves def
  8840. moves={}
  8841. do
  8842.     local s_dirs={
  8843.     up={
  8844.     vec=function() return Vec3(0,1,0) end,
  8845.     at=function(at)
  8846.         at.y=at.y+1
  8847.     end,
  8848.     raw_name="up",
  8849.         attack=turtle.attackUp,
  8850.         suck=turtle.suckUp,dig=turtle.digUp, raw_move=turtle.up, detect=turtle.detectUp, place=turtle.placeUp,compare=turtle.compareUp, drop=turtle.dropUp,},
  8851.     forward={
  8852.     vec=function() return Vec3(dir.x,0,dir.z) end,
  8853.     at=function(at,dir)
  8854.         at.x=at.x+dir.x
  8855.         at.z=at.z+dir.z
  8856.     end,
  8857.     attack=turtle.attack,
  8858.     raw_name="forward",suck=turtle.suck, dig=turtle.dig, raw_move=turtle.forward, detect=turtle.detect, place=turtle.place,compare=turtle.compare, drop=turtle.drop,},
  8859.     down={
  8860.     vec=function() return Vec3(0,-1,0) end,
  8861.     at=function(at)
  8862.         at.y=at.y-1
  8863.     end,
  8864.     attack=turtle.attackDown,
  8865.     raw_name="down",suck=turtle.suckDown,dig=turtle.digDown, raw_move=turtle.down, detect=turtle.detectDown, place=turtle.placeDown,compare=turtle.compareDown, drop=turtle.dropDown,},
  8866.     back={
  8867.     vec=function() return Vec3(-dir.x,0,-dir.z) end,
  8868.     at=function(at,dir)
  8869.         at.x=at.x-dir.x
  8870.         at.z=at.z-dir.z
  8871.     end,
  8872.     raw_name='back',raw_move=turtle.back},
  8873.     }
  8874.     local t_dirs={
  8875.     left={
  8876.     vec=function() return Vec3(dir.z,0,-dir.x) end,
  8877.     raw_name='turnLeft',raw_move=turtle.turnLeft,at=function(at,dir)  dir.x, dir.z = dir.z, -dir.x end },
  8878.     right={
  8879.     vec=function() return Vec3(-dir.z,0,dir.x) end,
  8880.     raw_name='turnRight',raw_move=turtle.turnRight,at=function(at,dir) dir.x, dir.z = -dir.z, dir.x end},
  8881.     }
  8882.     local opp={
  8883.     up='down',
  8884.     forward='back',
  8885.     right='left',
  8886.     }
  8887.     for i,v in pairs(opp) do opp[v]=i end
  8888.    
  8889.     local function helpMove(doF,moveF,undoF,fuel)
  8890.         if fuel then ensureFuel() end
  8891.         doF(pos,dir)
  8892.         save()
  8893.         local r=moveF()
  8894.         if not r then undoF(pos,dir) save() end
  8895.         return r
  8896.     end
  8897.    
  8898.     for mv,t in pairs(s_dirs) do
  8899.         local args={t.at,t.raw_move,s_dirs[opp[mv]].at,true}
  8900.         turtle[t.raw_name]=function() return helpMove(unpack(args)) end
  8901.         t.move=turtle[t.raw_name]
  8902.         moves[mv]=t
  8903.     end
  8904.     for mv,t in pairs(t_dirs) do
  8905.         local args={t.at,t.raw_move,t_dirs[opp[mv]].at}
  8906.         turtle[t.raw_name]=function() return helpMove(unpack(args)) end
  8907.         t.move=turtle[t.raw_name]
  8908.         moves[mv]=t
  8909.     end
  8910.    
  8911.     --aliases
  8912.     -- local function tdo(turnF,doF) return function(...) turnF() return doF(...) end end
  8913.    
  8914.     -- moves.around={}
  8915.     -- util.shcopy({
  8916.     -- suck=tdo(moves.around,forward.suck),
  8917.     -- attack=tdo(moves.around,forward.attack),
  8918.     -- drop=tdo(moves.around,forward.drop),
  8919.     -- move=function() turtle.turnLeft() turtle.turnLeft() end,
  8920.     -- at=function(at,dir) moves.left.at(at,dir) moves.left.at(at,dir) end,
  8921.     -- },moves.around)
  8922.    
  8923.    
  8924.    
  8925.     for i,v in pairs(moves) do
  8926.         setmetatable(v,
  8927.             {__call=function(t,...)
  8928.                 return v.move(...)
  8929.             end,
  8930.             })
  8931.     end
  8932.     moves.top=moves.up
  8933.     moves.bottom=moves.down
  8934.     moves.front=moves.forward
  8935.    
  8936.    
  8937.    
  8938. end
  8939. for i,v in pairs(moves) do
  8940.     local env=(getfenv())
  8941.     env[i]=v
  8942. end
  8943. ---
  8944.  
  8945. --world pos related
  8946. compass={
  8947.     {name='north',n=0,vec=function() return Vec3( 0, 0,-1) end},
  8948.     {name='east',n=1,vec=function() return Vec3( 1, 0, 0) end},
  8949.     {name='south',n=2,vec=function() return Vec3( 0, 0, 1) end},
  8950.     {name='west',n=3,vec=function() return Vec3(-1, 0, 0) end},
  8951.     }
  8952. for i,v in pairs(compass) do compass[v.name]=v end
  8953.  
  8954. --vec, mov, string, or nil
  8955. function getFacing(mv)
  8956.     local vec
  8957.     if mv==nil then vec=dir
  8958.     elseif classof(mv)==Vec3 then vec=mv
  8959.     elseif type(mv)=='string' then vec=moves[mv].vec()
  8960.     else error() end
  8961.     for i,c in ipairs(compass) do
  8962.         if vec==c.vec() then return c.name end
  8963.     end
  8964. end
  8965. function getChunk(v)
  8966.     v=v or pos
  8967.   return math.floor(v.x/16), math.floor(v.z/16)
  8968. end
  8969. function getChunkPosition(v)
  8970.     v=v or pos
  8971.   return v.x%16, v.z%16
  8972. end
  8973. ---
  8974.  
  8975. --[[input patterns:
  8976. x,y,z ->vector
  8977. string->move or compass
  8978. move or compas->vec
  8979.  
  8980. drop
  8981. suck
  8982. place
  8983.  
  8984. ]]
  8985. --arg transformer
  8986. local function trf(...)
  8987.     if classof(...)==Vec3 then
  8988.         return ...
  8989.     elseif type(...)=='string' then
  8990.         if moves[...] then
  8991.             return moves[...].vec()
  8992.         elseif compass[...] then
  8993.             return compass[...].vec()
  8994.         end
  8995.     else return Vec3(...) end
  8996. end
  8997. --public api
  8998. --mv based
  8999. local lastMoveNeededDig=false
  9000.  
  9001. function clear(mv)
  9002.     mv=type(mv)=='string' and moves[mv] or mv
  9003.     local maxCount=mode.count
  9004.     local delay=mode.delay
  9005.    
  9006.     local dig_count=0
  9007.     local count=0
  9008.     while (mv.detect()) and (count < maxCount) do
  9009.         if(count == 0) then
  9010.           -- Am about to dig a block - check that it is not a chest if necessary
  9011.           -- If we are looking for chests, then check that this isn't a chest before moving
  9012.             if not mode.dig then
  9013.                 return false,'dig'
  9014.             end
  9015.         end
  9016.         dig_count = (mv.dig() and 1 or 0)+count
  9017.         count=count+1
  9018.         sleep(delay)
  9019.     end
  9020.     if dig_count~=0 then lastMoveNeededDig=true end
  9021.     return (count~=maxCount),count,dig_count
  9022. end
  9023. function force_back()
  9024.     if not moves.back() then
  9025.         local a,b,c=move'back'
  9026.         turn'back'
  9027.         return a,b,c
  9028.     end
  9029.     return true,0,0
  9030. end
  9031.  
  9032. local function _force(mv,key)
  9033.     mv=type(mv)=='string' and moves[mv] or mv
  9034.     if mv==moves.back then return force_back(mv,key) end
  9035.     local suc
  9036.     if not lastMoveNeededDig then
  9037.         suc=mv[key]()
  9038.         if suc then return true,0,0 end
  9039.     end
  9040.     local maxCount=mode.count
  9041.     local delay=mode.delay
  9042.    
  9043.     local dig_count=0
  9044.     local count=0
  9045.     while (not suc) and (count < maxCount) do
  9046.         if mv.detect() then
  9047.             if(count == 0) then
  9048.               -- Am about to dig a block - check that it is not a chest if necessary
  9049.               -- If we are looking for chests, then check that this isn't a chest before moving
  9050.                 if not mode.dig then
  9051.                     return false,'dig'
  9052.                 end
  9053.             end
  9054.             dig_count = (mv.dig() and 1 or 0)+count
  9055.         else
  9056.             if not mode.attack then
  9057.                 return false,'attack'
  9058.             end
  9059.             mv.attack()
  9060.         end
  9061.         sleep(delay)
  9062.         suc=mv[key]()
  9063.         count=count+1
  9064.     end
  9065.     if dig_count~=0 then lastMoveNeededDig=true end
  9066.     return suc,count,dig_count
  9067. end
  9068. function force(mv)
  9069.     return _force(mv,'move')
  9070. end
  9071. function place(mv)
  9072.     return _force(mv,'place')
  9073. end
  9074. function advance(mv, steps)
  9075.     mv=type(mv)=='string' and moves[mv] or mv
  9076.     steps = steps or 1
  9077.     for step = 1,steps do
  9078.         force(mv)
  9079.     end
  9080. end
  9081.  
  9082. --vector based
  9083. function turn(...)
  9084.     local to=trf(...)
  9085.     local x,z = sign(to.x), sign(to.z)
  9086.     if x == dir.x and z == dir.z then
  9087.         return
  9088.     elseif (x == -dir.x and x~=0) or (z == -dir.z and z~=0) then --or?
  9089.         left()
  9090.         left()
  9091.     elseif x ~= 0 then
  9092.         if x == -dir.z then right() else left() end
  9093.     elseif z ~= 0 then
  9094.         if z == dir.x then right() else left() end
  9095.     end
  9096. end
  9097.  
  9098. function goto(...)
  9099.     local to=trf(...)
  9100.     if to.y>pos.y then
  9101.         advance(up, to.y-pos.y)
  9102.     elseif to.y<pos.y then
  9103.         advance(down, pos.y-to.y)
  9104.     end
  9105.     if to.x ~= pos.x then
  9106.         turn({x=to.x-pos.x})
  9107.         advance(forward, math.abs(to.x-pos.x))
  9108.     end
  9109.     if to.z ~= pos.z then
  9110.         turn({z=to.z-pos.z})
  9111.         advance(forward, math.abs(to.z-pos.z))
  9112.     end
  9113. end
  9114.  
  9115. function move(...)
  9116.     local to=trf(...)
  9117.     return goto(to+pos)
  9118. end
  9119. ---
  9120. --init code
  9121. local function update()
  9122.     load()
  9123.     pos=(pos or Vec3())
  9124.     dir=(dir or compass.south.vec())
  9125.     save()
  9126.     if mode.gps then
  9127.         local ok, pos_,dir_=pcall(getGps)
  9128.         if ok then set(pos_,dir_)
  9129.         else log('WARNING','Could not use gps:',pos_) end
  9130.     end
  9131. end
  9132.  
  9133. function getGps()
  9134.     rednet.open'right'
  9135.     local x,y,z=gps.locate(5)
  9136.     if x then
  9137.         gps_pos=Vec3(x,y,z)
  9138.         local org=(get())
  9139.         for _,c in ipairs(compass) do
  9140.             if goto(c.vec()+org) then
  9141.                 local x,y,z=gps.locate(5)
  9142.                 if x then
  9143.                     local gps_pos2=Vec3(x,y,z)
  9144.                     local dir=gps_pos2-gps_pos
  9145.                     if dir~=Vec3(0,0,0) then
  9146.                         return true,gps_pos2,dir
  9147.                     end
  9148.                 end
  9149.             end
  9150.         end
  9151.         error'blocked'
  9152.     else
  9153.         error'no gps signal'
  9154.     end
  9155. end
  9156.  
  9157.  
  9158. api={
  9159.  
  9160. set=set,
  9161. get=get,
  9162.  
  9163. moves=moves,
  9164. front=moves.forward,
  9165. bottom=moves.down,
  9166. top=moves.up,
  9167.  
  9168. clear=clear,
  9169. force=force,
  9170. place=place,
  9171. advance=advance,
  9172.  
  9173. mode=mode,
  9174.  
  9175. getFacing=getFacing,
  9176. getChunk=getChunk,
  9177. getChunkPos=getChunkPos,
  9178. compass=compass,
  9179.  
  9180. getGps=getGps,
  9181.  
  9182. turn=turn,
  9183. move=move,
  9184. goto=goto,
  9185. }
  9186. for i,v in pairs(moves) do api[i]=v end
  9187. api.api=api
  9188.  
  9189.  
  9190. update()
  9191.  
  9192.  
  9193.  
  9194.  
  9195. return api]===================],"CoolisOS/bin/utils/Vec3.lua",[===================[--[[
  9196. Advanced Vector API by Tomass1996
  9197.  
  9198. Vector 'Object' Functions And Fields:
  9199.   vector.x                              -- Vectors X component
  9200.   vector.y                              -- Vectors Y component
  9201.   vector.z                              -- Vectors Z component
  9202.   vector:add(otherVector)               -- Component-wise addition
  9203.   vector:scalarAdd(n)                   -- Scalar addition
  9204.   vector:subtract(otherVector)          -- Component-wise subtraction
  9205.   vector:scalarSubtract(n)              -- Scalar subtraction
  9206.   vector:eldot(otherVector)          -- Component-wise multiplication
  9207.   vector:scalarMultiply(n)              -- Scalar multiplication
  9208.   vector:divide(otherVector)            -- Component-wise division
  9209.   vector:scalarDivide(n)                -- Scalar division
  9210.   vector:length()                       -- Get the length of the vector
  9211.   vector:lengthSq()                     -- Get the length ^ 2 of the vector
  9212.   vector:distance(otherVector)          -- Get the distance away from a vector
  9213.   vector:distanceSq(otherVector)        -- Get the distance away from a vector, squared
  9214.   vector:normalize()                    -- Get the normalized vector
  9215.   vector:dot(otherVector)               -- Get the dot product of vector and otherVector
  9216.   vector:cross(otherVector)             -- Get the cross product of vector and otherVector
  9217.   vector:containedWithin(minVec, maxVec)-- Check to see if vector is contained within minVec and maxVec
  9218.   vector:clampX(min, max)               -- Clamp the X component
  9219.   vector:clampY(min, max)               -- Clamp the Y component
  9220.   vector:clampZ(min, max)               -- Clamp the Z component
  9221.   vector:floor()                        -- Rounds all components down
  9222.   vector:ceil()                         -- Rounds all components up
  9223.   vector:round()                        -- Rounds all components to the closest integer
  9224.   vector:absolute()                     -- Vector with absolute values of components
  9225.   vector:isCollinearWith(otherVector)   -- Checks to see if vector is collinear with otherVector
  9226.   vector:getIntermediateWithX(other, x) -- New vector with given x value along the line between vector and other, or nil if not possible
  9227.   vector:getIntermediateWithY(other, y) -- New vector with given y value along the line between vector and other, or nil if not possible
  9228.   vector:getIntermediateWithZ(other, z) -- New vector with given z value along the line between vector and other, or nil if not possible
  9229.   vector:rotateAroundX(angle)           -- Rotates vector around the x axis by the specified angle(radians)
  9230.   vector:rotateAroundY(angle)           -- Rotates vector around the y axis by the specified angle(radians)
  9231.   vector:rotateAroundZ(angle)           -- Rotates vector around the z axis by the specified angle(radians)
  9232.   vector:clone()                        -- Returns a new vector with same component values as vector
  9233.   vector:equals(otherVector)            -- Checks to see if vector and otherVector are equal
  9234.   vector:tostring()                     -- Returns the string representation of vector "(x, y, z)"
  9235.  
  9236. Vector 'Object' Metatable Overrides:    -- [x, y, z] represents a vector object in these examples, not irl
  9237.   To String             -- tostring will get the string representation
  9238.                             ie. tostring([1, 2, 3])     -->     "(1, 2, 3)"
  9239.   Unary Minus           -- Using unary minus on a vector will result in the negative of vector
  9240.                             ie. -[1, -2, 3]             -->     [-1, 2, -3]
  9241.   Addition              -- Can add two vectors or vector and number with +
  9242.                             ie. [1, 2, 3] + [4, 5, 6]   -->     [5, 7, 9]
  9243.                                 [1, 2, 3] + 3           -->     [4, 5, 6]
  9244.   Subtraction           -- Can subtract two vectors or vector and number with -
  9245.                             ie. [4, 5, 6] - [1, 2, 3]   -->     [3, 3, 3]
  9246.                                 [4, 5, 6] - 3           -->     [1, 2, 3]
  9247.   Multiplication        -- Can dot two vectors or vector and number with *
  9248.                             ie. [1, 2, 3] * [4, 5, 6]   -->     [4, 10, 18]
  9249.                                 [1, 2, 3] * 3           -->     [3, 6, 9]
  9250.   Division              -- Can divide two vectors or vector and number with /
  9251.                             ie. [4, 10, 18] / [1, 2, 3] -->     [4, 5, 6]
  9252.                                 [3, 6, 9] / 3           -->     [1, 2, 3]
  9253.   Equality              -- Can check if two vectors are the same with ==
  9254.                             ie. [4, 5, 6] == [4, 5, 6]  -->     true
  9255.                                 [4, 5, 6] == [4, 99, 6] -->     false
  9256.  
  9257. Vector API functions:
  9258.   Vector.getMinimum(v1, v2)             -- Gets the minimum components of two vectors
  9259.   Vector.getMaximum(v1, v2)             -- Gets the maximum components of two vectors
  9260.   Vector.getMidpoint(v1, v2)            -- Gets the midpoint of two vectors
  9261.   Vector.isVector(v)                    -- Checks whether v is a vector created by this api
  9262.   Vector(x, y, z)                   -- Creates a new vector object with the component values
  9263. --]]
  9264.  
  9265. include'kernel.class'
  9266. class.Vec3()
  9267. function Vec3:__init(t,y,z)
  9268.     if type(t)=='table' then
  9269.         self.x = t.x or t[1] or 0
  9270.         self.y = t.y or t[2] or 0
  9271.         self.z = t.z or t[3] or 0
  9272.     else
  9273.         self.x = t or 0
  9274.         self.y = y or 0
  9275.         self.z = z or 0
  9276.     end
  9277. end
  9278. local vector=Vec3
  9279. local new=Vec3
  9280. local isVector=function(v) return classof(v)==Vec3 end
  9281. local getType=ofType
  9282. local vector = {
  9283.   add = function(self, v)
  9284.       self.x=self.x + v.x
  9285.       self.y=self.y + v.y
  9286.       self.z=self.z + v.z
  9287.       return self
  9288.   end,
  9289.   scalarAdd = function(self, n)
  9290.     self.x=self.x + n
  9291.     self.y=self.y + n
  9292.     self.z=self.z + n
  9293.     return self
  9294.   end,
  9295.   subtract = function(self, v)
  9296.     self.x=self.x - v.x
  9297.     self.y=self.y - v.y
  9298.     self.z=self.z - v.z
  9299.     return self
  9300.   end,
  9301.   scalarSubtract = function(self, n)
  9302.     return self:scalarAdd(-n)
  9303.   end,
  9304.   eldot = function(self, v)
  9305.     self.x=self.x * v.x
  9306.     self.y=self.y * v.y
  9307.     self.z=self.z * v.z
  9308.     return self
  9309.   end,
  9310.   scalarMultiply = function(self, n)
  9311.     self.x=self.x * n
  9312.     self.y=self.y * n
  9313.     self.z=self.z * n
  9314.     return self
  9315.   end,
  9316.   divide = function(self, o)
  9317.     return new(
  9318.       self.x / o.x,
  9319.       self.y / o.y,
  9320.       self.z / o.z
  9321.     )
  9322.   end,
  9323.   scalarDivide = function(self, n)
  9324.     return new(
  9325.       self.x / n,
  9326.       self.y / n,
  9327.       self.z / n
  9328.     )
  9329.   end,
  9330.   length = function(self)
  9331.     return math.sqrt(
  9332.       self.x * self.x
  9333.       + self.y * self.y
  9334.       + self.z * self.z
  9335.     )
  9336.   end,
  9337.   lengthSq = function(self)
  9338.     return (
  9339.       self.x * self.x
  9340.       + self.y * self.y
  9341.       + self.z * self.z
  9342.     )
  9343.   end,
  9344.   distance = function(self, o)
  9345.     return math.sqrt(
  9346.       math.pow(o.x - self.x, 2)
  9347.       + math.pow(o.y - self.y, 2)
  9348.       + math.pow(o.z - self.z, 2)
  9349.     )
  9350.   end,
  9351.   distanceSq = function(self, o)
  9352.     return (
  9353.       math.pow(o.x - self.x, 2)
  9354.       + math.pow(o.y - self.y, 2)
  9355.       + math.pow(o.z - self.z, 2)
  9356.     )
  9357.   end,
  9358.   normalize = function(self)
  9359.     return self:scalarDivide(self:length())
  9360.   end,
  9361.   dot = function(self, o)
  9362.     return (
  9363.       self.x * o.x
  9364.       + self.y * o.y
  9365.       + self.z * o.z
  9366.     )
  9367.   end,
  9368.   cross = function(self, o)
  9369.     return new(
  9370.       self.y * o.z - self.z * o.y,
  9371.       self.z * o.x - self.x * o.z,
  9372.       self.x * o.y - self.y * o.x
  9373.     )
  9374.   end,
  9375.   containedWithin = function(self, min, max)
  9376.     return (
  9377.       self.x >= min.x and self.x <= max.x
  9378.       and self.y >= min.y and self.y <= max.y
  9379.       and self.z >= min.z and self.z <= max.z
  9380.     )
  9381.   end,
  9382.   clampX = function(self, min, max)
  9383.     return new(
  9384.       math.max(min, math.min(max, self.x)),
  9385.       self.y,
  9386.       self.z
  9387.     )
  9388.   end,
  9389.   clampY = function(self, min, max)
  9390.     return new(
  9391.       self.x,
  9392.       math.max(min, math.min(max, self.y)),
  9393.       self.z
  9394.     )
  9395.   end,
  9396.   clampZ = function(self, min, max)
  9397.     return new(
  9398.       self.x,
  9399.       self.y,
  9400.       math.max(min, math.min(max, self.z))
  9401.     )
  9402.   end,
  9403.   floor = function(self)
  9404.     return new(
  9405.       math.floor(self.x),
  9406.       math.floor(self.y),
  9407.       math.floor(self.z)
  9408.     )
  9409.   end,
  9410.   ceil = function(self)
  9411.     return new(
  9412.       math.ceil(self.x),
  9413.       math.ceil(self.y),
  9414.       math.ceil(self.z)
  9415.     )
  9416.   end,
  9417.   round = function(self)
  9418.     return new(
  9419.       math.floor(self.x + 0.5),
  9420.       math.floor(self.y + 0.5),
  9421.       math.floor(self.z + 0.5)
  9422.     )
  9423.   end,
  9424.   absolute = function(self)
  9425.     return new(
  9426.       math.abs(self.x),
  9427.       math.abs(self.y),
  9428.       math.abs(self.z)
  9429.     )
  9430.   end,
  9431.   isCollinearWith = function(self, o)
  9432.     if self.x == 0 and self.y == 0 and self.z == 0 then
  9433.       return true
  9434.     end
  9435.     local otherX, otherY, otherZ = o.x, o.y, o.z
  9436.     if otherX == 0 and otherY == 0 and otherZ == 0 then
  9437.       return true
  9438.     end
  9439.     if (self.x == 0) ~= (otherX == 0) then return false end
  9440.     if (self.y == 0) ~= (otherY == 0) then return false end
  9441.     if (self.z == 0) ~= (otherZ == 0) then return false end
  9442.     local quotientX = otherX / self.x
  9443.     if quotientX == quotientX then
  9444.       return o:equals(self:scalarMultiply(quotientX))
  9445.     end
  9446.     local quotientY = otherY / self.y
  9447.     if quotientY == quotientY then
  9448.       return o:equals(self:scalarMultiply(quotientY))
  9449.     end
  9450.     local quotientZ = otherZ / self.z
  9451.     if quotientZ == quotientZ then
  9452.       return o:equals(self:scalarMultiply(quotientZ))
  9453.     end
  9454.   end,
  9455.   getIntermediateWithX = function(self, o, v)
  9456.     local vX = o.x - self.x
  9457.     local vY = o.y - self.y
  9458.     local vZ = o.z - self.z
  9459.     if vX * vX < 1.0000000116860974e-7 then
  9460.       return nil
  9461.     else
  9462.       local nMul = (v - self.x) / vX
  9463.       return (
  9464.         (nMul >= 0 and nMul <= 1)
  9465.         and new(
  9466.           self.x + vX * nMul,
  9467.           self.y + vY * nMul,
  9468.           self.z + vZ * nMul
  9469.         )
  9470.         or nil
  9471.       )
  9472.     end
  9473.   end,
  9474.   getIntermediateWithY = function(self, o, v)
  9475.     local vX = o.x - self.x
  9476.     local vY = o.y - self.y
  9477.     local vZ = o.z - self.z
  9478.     if vY * vY < 1.0000000116860974e-7 then
  9479.       return nil
  9480.     else
  9481.       local nMul = (v - self.y) / vY
  9482.       return (
  9483.         (nMul >= 0 and nMul <= 1)
  9484.         and new(
  9485.           self.x + vX * nMul,
  9486.           self.y + vY * nMul,
  9487.           self.z + vZ * nMul
  9488.         )
  9489.         or nil
  9490.       )
  9491.     end
  9492.   end,
  9493.   getIntermediateWithZ = function(self, o, v)
  9494.     local vX = o.x - self.x
  9495.     local vY = o.y - self.y
  9496.     local vZ = o.z - self.z
  9497.     if vZ * vZ < 1.0000000116860974e-7 then
  9498.       return nil
  9499.     else
  9500.       local nMul = (v - self.z) / vZ
  9501.       return (
  9502.         (nMul >= 0 and nMul <= 1)
  9503.         and new(
  9504.           self.x + vX * nMul,
  9505.           self.y + vY * nMul,
  9506.           self.z + vZ * nMul
  9507.         )
  9508.         or nil
  9509.       )
  9510.     end
  9511.   end,
  9512.   rotateAroundX = function(self, n)
  9513.     local c, s = math.cos(n), math.sin(n)
  9514.     return new(
  9515.       self.x,
  9516.       self.y * c + self.z * s,
  9517.       self.z * c - self.y * s
  9518.     )
  9519.   end,
  9520.   rotateAroundY = function(self, n)
  9521.     local c, s = math.cos(n), math.sin(n)
  9522.     return new(
  9523.       self.x * c + self.z * s,
  9524.       self.y,
  9525.       self.z * c - self.x * s
  9526.     )
  9527.   end,
  9528.   rotateAroundZ = function(self, n)
  9529.     local c, s = math.cos(n), math.sin(n)
  9530.     return new(
  9531.       self.x * c + self.y * s,
  9532.       self.y * c - self.x * s,
  9533.       self.z
  9534.     )
  9535.   end,
  9536.   clone = function(self)
  9537.     return Vec3(self)
  9538.   end,
  9539.   equals = function(self, o)
  9540.     if not isVector(self) or not isVector(o) then return false end
  9541.     return (
  9542.       o.x == self.x
  9543.       and o.y == self.y
  9544.       and o.z == self.z
  9545.     )
  9546.   end,
  9547.   tostring = function(self)
  9548.     return "("..self.x..", "..self.y..", "..self.z..")"
  9549.   end,
  9550.   getMinimum=function(v1, v2)
  9551.       return new(
  9552.         math.min(v1.x, v2.x),
  9553.         math.min(v1.y, v2.y),
  9554.         math.min(v1.z, v2.z)
  9555.       )
  9556.     end,
  9557.     getMidpoint= function(v1, v2)
  9558.   return new(
  9559.     (v1.x + v2.x) / 2,
  9560.     (v1.y + v2.y) / 2,
  9561.     (v1.z + v2.z) / 2
  9562.   )
  9563. end,
  9564.     __serialize=function(self)
  9565.         return {self.x,self.y,self.z}
  9566.     end
  9567. }
  9568.  
  9569. local vmetatable = {
  9570.   __tostring = vector.tostring,
  9571.   __unm = function(v) return v:scalarMultiply(-1) end,
  9572.   __add = function(a, b)
  9573.     if type(b) == "number" and isVector(a) then
  9574.       return a:clone():scalarAdd(b)
  9575.     elseif type(a) == "number" and isVector(b) then
  9576.       return b:clone():scalarAdd(a)
  9577.     elseif isVector(a) and isVector(b) then
  9578.       return a:clone():add(b)
  9579.     else
  9580.       error("Attempt to perform vector addition on <"..getType(a).."> and <"..getType(b)..">")
  9581.     end
  9582.   end,
  9583.   __sub = function(a, b)
  9584.     if type(b) == "number" and isVector(a) then
  9585.       return a:clone():scalarSubtract(b)
  9586.     elseif type(a) == "number" and isVector(b) then
  9587.       return b:clone():scalarSubtract(a)
  9588.     elseif isVector(a) and isVector(b) then
  9589.       return a:clone():subtract(b)
  9590.     else
  9591.       error("Attempt to perform vector subtraction on <"..getType(a).."> and <"..getType(b)..">")
  9592.     end
  9593.   end,
  9594.   __mul = function(a, b)
  9595.     if type(b) == "number" and isVector(a) then
  9596.       return a:scalarMultiply(b)
  9597.     elseif type(a) == "number" and isVector(b) then
  9598.       return b:scalarMultiply(a)
  9599.     elseif isVector(a) and isVector(b) then
  9600.       return a:dot(b)
  9601.     else
  9602.       error("Attempt to perform vector multiplication on <"..getType(a).."> and <"..getType(b)..">")
  9603.     end
  9604.   end,
  9605.   __div = function(a, b)
  9606.     if type(b) == "number" and isVector(a) then
  9607.       return a:scalarDivide(b)
  9608.     elseif type(a) == "number" and isVector(b) then
  9609.       return b:scalarDivide(a)
  9610.     elseif isVector(a) and isVector(b) then
  9611.       return a:divide(b)
  9612.     else
  9613.       error("Attempt to perform vector division on <"..getType(a).."> and <"..getType(b)..">")
  9614.     end
  9615.   end,
  9616.   __eq = vector.equals,
  9617.   __pow = vector.cross,
  9618. }
  9619.  
  9620.  
  9621.  
  9622. util.shcopy(vector,Vec3)
  9623. util.shcopy(vmetatable,Vec3)
  9624.  
  9625. --[[test
  9626. v=require'bin.utils.Vec3'
  9627.  
  9628.  
  9629. ]]
  9630.  
  9631. return Vec3]===================],"CoolisOS/bin/utils/pl",true,"CoolisOS/bin/utils/pl/List.lua",[===================[--- Python-style list class.
  9632. --
  9633. -- **Please Note**: methods that change the list will return the list.
  9634. -- This is to allow for method chaining, but please note that `ls = ls:sort()`
  9635. -- does not mean that a new copy of the list is made. In-place (mutable) methods
  9636. -- are marked as returning 'the list' in this documentation.
  9637. --
  9638. -- See the Guide for further @{02-arrays.md.Python_style_Lists|discussion}
  9639. --
  9640. -- See <a href="http://www.python.org/doc/current/tut/tut.html">http://www.python.org/doc/current/tut/tut.html</a>, section 5.1
  9641. --
  9642. -- **Note**: The comments before some of the functions are from the Python docs
  9643. -- and contain Python code.
  9644. --
  9645. -- Written for Lua version Nick Trout 4.0; Redone for Lua 5.1, Steve Donovan.
  9646. --
  9647. -- Dependencies: `pl.utils`, `pl.tablex`
  9648. -- @module pl.List
  9649. -- @pragma nostrip
  9650.  
  9651. local tinsert,tremove,concat,tsort = table.insert,table.remove,table.concat,table.sort
  9652. local setmetatable, getmetatable,type,tostring,assert,string,next = setmetatable,getmetatable,type,tostring,assert,string,next
  9653. local write = io.write
  9654. local tablex = require 'tablex'
  9655. local filter,imap,imap2,reduce,transform,tremovevalues = tablex.filter,tablex.imap,tablex.imap2,tablex.reduce,tablex.transform,tablex.removevalues
  9656. local tablex = tablex
  9657. local tsub = tablex.sub
  9658. local utils = require 'utils'
  9659. local array_tostring,split,is_type,assert_arg,function_arg = utils.array_tostring,utils.split,utils.is_type,utils.assert_arg,utils.function_arg
  9660. local normalize_slice = tablex._normalize_slice
  9661.  
  9662. --[[
  9663. module ('pl.List',utils._module)
  9664. ]]
  9665.  
  9666. local Multimap = utils.stdmt.MultiMap
  9667. -- metatable for our list objects
  9668. local List = utils.stdmt.List
  9669. List.__index = List
  9670. List._class = List
  9671.  
  9672. local iter
  9673.  
  9674. -- we give the metatable its own metatable so that we can call it like a function!
  9675. setmetatable(List,{
  9676.     __call = function (tbl,arg)
  9677.         return List.new(arg)
  9678.     end,
  9679. })
  9680.  
  9681. local function makelist (t,obj)
  9682.     local klass = List
  9683.     if obj then
  9684.         klass = getmetatable(obj)
  9685.     end
  9686.     return setmetatable(t,klass)
  9687. end
  9688.  
  9689. local function is_list(t)
  9690.     return getmetatable(t) == List
  9691. end
  9692.  
  9693. local function simple_table(t)
  9694.   return type(t) == 'table' and not is_list(t) and #t > 0
  9695. end
  9696.  
  9697. function List:_init (src)
  9698.     if src then
  9699.         for v in iter(src) do
  9700.             tinsert(self,v)
  9701.         end
  9702.     end
  9703. end
  9704.  
  9705. --- Create a new list. Can optionally pass a table;
  9706. -- passing another instance of List will cause a copy to be created
  9707. -- we pass anything which isn't a simple table to iterate() to work out
  9708. -- an appropriate iterator  @see List.iterate
  9709. -- @param t An optional list-like table
  9710. -- @return a new List
  9711. -- @usage ls = List();  ls = List {1,2,3,4}
  9712. function List.new(t)
  9713.     local ls
  9714.     if not simple_table(t) then
  9715.         ls = {}
  9716.         List._init(ls,t)
  9717.     else
  9718.         ls = t
  9719.     end
  9720.     makelist(ls)
  9721.     return ls
  9722. end
  9723.  
  9724. function List:clone()
  9725.     local ls = makelist({},self)
  9726.     List._init(ls,self)
  9727.     return ls
  9728. end
  9729.  
  9730. function List.default_map_with(T)
  9731.     return function(self,name)
  9732.        local f = T[name]
  9733.        if f then
  9734.           return function(self,...)
  9735.              return self:map(f,...)
  9736.           end
  9737.        else
  9738.           error("method not found: "..name,2)
  9739.        end
  9740.     end
  9741. end
  9742.  
  9743.  
  9744. ---Add an item to the end of the list.
  9745. -- @param i An item
  9746. -- @return the list
  9747. function List:append(i)
  9748.   tinsert(self,i)
  9749.   return self
  9750. end
  9751.  
  9752. List.push = tinsert
  9753.  
  9754. --- Extend the list by appending all the items in the given list.
  9755. -- equivalent to 'a[len(a):] = L'.
  9756. -- @param L Another List
  9757. -- @return the list
  9758. function List:extend(L)
  9759.   assert_arg(1,L,'table')
  9760.   for i = 1,#L do tinsert(self,L[i]) end
  9761.   return self
  9762. end
  9763.  
  9764. --- Insert an item at a given position. i is the index of the
  9765. -- element before which to insert.
  9766. -- @param i index of element before whichh to insert
  9767. -- @param x A data item
  9768. -- @return the list
  9769. function List:insert(i, x)
  9770.   assert_arg(1,i,'number')
  9771.   tinsert(self,i,x)
  9772.   return self
  9773. end
  9774.  
  9775. --- Insert an item at the begining of the list.
  9776. -- @param x a data item
  9777. -- @return the list
  9778. function List:put (x)
  9779.     return self:insert(1,x)
  9780. end
  9781.  
  9782. --- Remove an element given its index.
  9783. -- (equivalent of Python's del s[i])
  9784. -- @param i the index
  9785. -- @return the list
  9786. function List:remove (i)
  9787.     assert_arg(1,i,'number')
  9788.     tremove(self,i)
  9789.     return self
  9790. end
  9791.  
  9792. --- Remove the first item from the list whose value is given.
  9793. -- (This is called 'remove' in Python; renamed to avoid confusion
  9794. -- with table.remove)
  9795. -- Return nil if there is no such item.
  9796. -- @param x A data value
  9797. -- @return the list
  9798. function List:remove_value(x)
  9799.     for i=1,#self do
  9800.         if self[i]==x then tremove(self,i) return self end
  9801.     end
  9802.     return self
  9803.  end
  9804.  
  9805. --- Remove the item at the given position in the list, and return it.
  9806. -- If no index is specified, a:pop() returns the last item in the list.
  9807. -- The item is also removed from the list.
  9808. -- @param i An index
  9809. -- @return the item
  9810. function List:pop(i)
  9811.     if not i then i = #self end
  9812.     assert_arg(1,i,'number')
  9813.     return tremove(self,i)
  9814. end
  9815.  
  9816. List.get = List.pop
  9817.  
  9818. --- Return the index in the list of the first item whose value is given.
  9819. -- Return nil if there is no such item.
  9820. -- @class function
  9821. -- @name List:index
  9822. -- @param x A data value
  9823. -- @param idx where to start search (default 1)
  9824. -- @return the index, or nil if not found.
  9825.  
  9826. local tfind = tablex.find
  9827. List.index = tfind
  9828.  
  9829. --- does this list contain the value?.
  9830. -- @param x A data value
  9831. -- @return true or false
  9832. function List:contains(x)
  9833.     return tfind(self,x) and true or false
  9834. end
  9835.  
  9836. --- Return the number of times value appears in the list.
  9837. -- @param x A data value
  9838. -- @return number of times x appears
  9839. function List:count(x)
  9840.     local cnt=0
  9841.     for i=1,#self do
  9842.         if self[i]==x then cnt=cnt+1 end
  9843.     end
  9844.     return cnt
  9845. end
  9846.  
  9847. --- Sort the items of the list, in place.
  9848. -- @param cmp an optional comparison function, default '<'
  9849. -- @return the list
  9850. function List:sort(cmp)
  9851.     if cmp then cmp = function_arg(1,cmp) end
  9852.     tsort(self,cmp)
  9853.     return self
  9854. end
  9855.  
  9856. --- return a sorted copy of this list.
  9857. -- @param cmp an optional comparison function, default '<'
  9858. -- @return a new list
  9859. function List:sorted(cmp)
  9860.     return List(self):sort(cmp)
  9861. end
  9862.  
  9863. --- Reverse the elements of the list, in place.
  9864. -- @return the list
  9865. function List:reverse()
  9866.     local t = self
  9867.     local n = #t
  9868.     local n2 = n/2
  9869.     for i = 1,n2 do
  9870.         local k = n-i+1
  9871.         t[i],t[k] = t[k],t[i]
  9872.     end
  9873.     return self
  9874. end
  9875.  
  9876. --- return the minimum and the maximum value of the list.
  9877. -- @return minimum value
  9878. -- @return maximum value
  9879. function List:minmax()
  9880.     local vmin,vmax = 1e70,-1e70
  9881.     for i = 1,#self do
  9882.         local v = self[i]
  9883.         if v < vmin then vmin = v end
  9884.         if v > vmax then vmax = v end
  9885.     end
  9886.     return vmin,vmax
  9887. end
  9888.  
  9889. --- Emulate list slicing.  like  'list[first:last]' in Python.
  9890. -- If first or last are negative then they are relative to the end of the list
  9891. -- eg. slice(-2) gives last 2 entries in a list, and
  9892. -- slice(-4,-2) gives from -4th to -2nd
  9893. -- @param first An index
  9894. -- @param last An index
  9895. -- @return a new List
  9896. function List:slice(first,last)
  9897.     return tsub(self,first,last)
  9898. end
  9899.  
  9900. --- empty the list.
  9901. -- @return the list
  9902. function List:clear()
  9903.     for i=1,#self do tremove(self) end
  9904.     return self
  9905. end
  9906.  
  9907. local eps = 1.0e-10
  9908.  
  9909. --- Emulate Python's range(x) function.
  9910. -- Include it in List table for tidiness
  9911. -- @param start A number
  9912. -- @param finish A number greater than start; if absent,
  9913. -- then start is 1 and finish is start
  9914. -- @param incr an optional increment (may be less than 1)
  9915. -- @return a List from start .. finish
  9916. -- @usage List.range(0,3) == List{0,1,2,3}
  9917. -- @usage List.range(4) = List{1,2,3,4}
  9918. -- @usage List.range(5,1,-1) == List{5,4,3,2,1}
  9919. function List.range(start,finish,incr)
  9920.   if not finish then
  9921.     finish = start
  9922.     start = 1
  9923.   end
  9924.   if incr then
  9925.     assert_arg(3,incr,'number')
  9926.     if not utils.is_integer(incr) then finish = finish + eps end
  9927.   else
  9928.     incr = 1
  9929.   end
  9930.   assert_arg(1,start,'number')
  9931.   assert_arg(2,finish,'number')
  9932.   local t = List.new()
  9933.   for i=start,finish,incr do tinsert(t,i) end
  9934.   return t
  9935. end
  9936.  
  9937. --- list:len() is the same as #list.
  9938. function List:len()
  9939.   return #self
  9940. end
  9941.  
  9942. -- Extended operations --
  9943.  
  9944. --- Remove a subrange of elements.
  9945. -- equivalent to 'del s[i1:i2]' in Python.
  9946. -- @param i1 start of range
  9947. -- @param i2 end of range
  9948. -- @return the list
  9949. function List:chop(i1,i2)
  9950.     return tremovevalues(self,i1,i2)
  9951. end
  9952.  
  9953. --- Insert a sublist into a list
  9954. -- equivalent to 's[idx:idx] = list' in Python
  9955. -- @param idx index
  9956. -- @param list list to insert
  9957. -- @return the list
  9958. -- @usage  l = List{10,20}; l:splice(2,{21,22});  assert(l == List{10,21,22,20})
  9959. function List:splice(idx,list)
  9960.     assert_arg(1,idx,'number')
  9961.     idx = idx - 1
  9962.     local i = 1
  9963.     for v in iter(list) do
  9964.         tinsert(self,i+idx,v)
  9965.         i = i + 1
  9966.     end
  9967.     return self
  9968. end
  9969.  
  9970. --- general slice assignment s[i1:i2] = seq.
  9971. -- @param i1  start index
  9972. -- @param i2  end index
  9973. -- @param seq a list
  9974. -- @return the list
  9975. function List:slice_assign(i1,i2,seq)
  9976.     assert_arg(1,i1,'number')
  9977.     assert_arg(1,i2,'number')
  9978.     i1,i2 = normalize_slice(self,i1,i2)
  9979.     if i2 >= i1 then self:chop(i1,i2) end
  9980.     self:splice(i1,seq)
  9981.     return self
  9982. end
  9983.  
  9984. --- concatenation operator.
  9985. -- @param L another List
  9986. -- @return a new list consisting of the list with the elements of the new list appended
  9987. function List:__concat(L)
  9988.     assert_arg(1,L,'table')
  9989.     local ls = self:clone()
  9990.     ls:extend(L)
  9991.     return ls
  9992. end
  9993.  
  9994. --- equality operator ==.  True iff all elements of two lists are equal.
  9995. -- @param L another List
  9996. -- @return true or false
  9997. function List:__eq(L)
  9998.     if #self ~= #L then return false end
  9999.     for i = 1,#self do
  10000.         if self[i] ~= L[i] then return false end
  10001.     end
  10002.     return true
  10003. end
  10004.  
  10005. --- join the elements of a list using a delimiter. <br>
  10006. -- This method uses tostring on all elements.
  10007. -- @param delim a delimiter string, can be empty.
  10008. -- @return a string
  10009. function List:join (delim)
  10010.     delim = delim or ''
  10011.     assert_arg(1,delim,'string')
  10012.     return concat(array_tostring(self),delim)
  10013. end
  10014.  
  10015. --- join a list of strings. <br>
  10016. -- Uses table.concat directly.
  10017. -- @class function
  10018. -- @name List:concat
  10019. -- @param delim a delimiter
  10020. -- @return a string
  10021. List.concat = concat
  10022.  
  10023. local function tostring_q(val)
  10024.     local s = tostring(val)
  10025.     if type(val) == 'string' then
  10026.         s = '"'..s..'"'
  10027.     end
  10028.     return s
  10029. end
  10030.  
  10031. --- how our list should be rendered as a string. Uses join().
  10032. -- @see List:join
  10033. function List:__tostring()
  10034.     return '{'..self:join(',',tostring_q)..'}'
  10035. end
  10036.  
  10037. --[[
  10038. -- NOTE: this works, but is unreliable. If you leave the loop before finishing,
  10039. -- then the iterator is not reset.
  10040. --- can iterate over a list directly.
  10041. -- @usage for v in ls do print(v) end
  10042. function List:__call()
  10043.     if not self.key then self.key = 1 end
  10044.     local value = self[self.key]
  10045.     self.key = self.key + 1
  10046.     if not value then self.key = nil end
  10047.     return value
  10048. end
  10049. --]]
  10050.  
  10051. --[[
  10052. function List.__call(t,v,i)
  10053.     i = (i or 0) + 1
  10054.     v = t[i]
  10055.     if v then return i, v end
  10056. end
  10057. --]]
  10058.  
  10059. local MethodIter = {}
  10060.  
  10061. function MethodIter:__index (name)
  10062.     return function(mm,...)
  10063.         return self.list:foreachm(name,...)
  10064.     end
  10065. end
  10066.  
  10067. --- call the function for each element of the list.
  10068. -- @param fun a function or callable object
  10069. -- @param ... optional values to pass to function
  10070. function List:foreach (fun,...)
  10071.     if fun==nil then
  10072.         return setmetatable({list=self},MethodIter)
  10073.     end
  10074.     fun = function_arg(1,fun)
  10075.     for i = 1,#self do
  10076.         fun(self[i],...)
  10077.     end
  10078. end
  10079.  
  10080. function List:foreachm (name,...)
  10081.     for i = 1,#self do
  10082.         local obj = self[i]
  10083.         local f = assert(obj[name],"method not found on object")
  10084.         f(obj,...)
  10085.     end
  10086. end
  10087.  
  10088. --- create a list of all elements which match a function.
  10089. -- @param fun a boolean function
  10090. -- @param arg optional argument to be passed as second argument of the predicate
  10091. -- @return a new filtered list.
  10092. function List:filter (fun,arg)
  10093.     return makelist(filter(self,fun,arg),self)
  10094. end
  10095.  
  10096. --- split a string using a delimiter.
  10097. -- @param s the string
  10098. -- @param delim the delimiter (default spaces)
  10099. -- @return a List of strings
  10100. -- @see pl.utils.split
  10101. function List.split (s,delim)
  10102.     assert_arg(1,s,'string')
  10103.     return makelist(split(s,delim))
  10104. end
  10105.  
  10106. local MethodMapper = {}
  10107.  
  10108. function MethodMapper:__index (name)
  10109.     return function(mm,...)
  10110.         return self.list:mapm(name,...)
  10111.     end
  10112. end
  10113.  
  10114. --- apply a function to all elements.
  10115. -- Any extra arguments will be passed to the function; if the function
  10116. -- is `nil` then `map` returns a mapper object that maps over a method
  10117. -- of the items
  10118. -- @param fun a function of at least one argument
  10119. -- @param ... arbitrary extra arguments.
  10120. -- @return a new list: {f(x) for x in self}
  10121. -- @usage List{'one','two'}:map(string.upper) == {'ONE','TWO'}
  10122. -- @usage List{'one','two'}:map():sub(1,2) == {'on','tw'}
  10123. -- @see pl.tablex.imap
  10124. function List:map (fun,...)
  10125.     if fun==nil then
  10126.         return setmetatable({list=self},MethodMapper)
  10127.     end
  10128.     return makelist(imap(fun,self,...),self)
  10129. end
  10130.  
  10131. --- apply a function to all elements, in-place.
  10132. -- Any extra arguments are passed to the function.
  10133. -- @param fun A function that takes at least one argument
  10134. -- @param ... arbitrary extra arguments.
  10135. -- @return the list.
  10136. function List:transform (fun,...)
  10137.     transform(fun,self,...)
  10138.     return self
  10139. end
  10140.  
  10141. --- apply a function to elements of two lists.
  10142. -- Any extra arguments will be passed to the function
  10143. -- @param fun a function of at least two arguments
  10144. -- @param ls another list
  10145. -- @param ... arbitrary extra arguments.
  10146. -- @return a new list: {f(x,y) for x in self, for x in arg1}
  10147. -- @see pl.tablex.imap2
  10148. function List:map2 (fun,ls,...)
  10149.     return makelist(imap2(fun,self,ls,...),self)
  10150. end
  10151.  
  10152. --- apply a named method to all elements.
  10153. -- Any extra arguments will be passed to the method.
  10154. -- @param name name of method
  10155. -- @param ... extra arguments
  10156. -- @return a new list of the results
  10157. -- @see pl.seq.mapmethod
  10158. function List:mapm (name,...)
  10159.     local res = {}
  10160.     local t = self
  10161.     for i = 1,#t do
  10162.       local val = t[i]
  10163.       local fn = val[name]
  10164.       if not fn then error(type(val).." does not have method "..name,2) end
  10165.       res[i] = fn(val,...)
  10166.     end
  10167.     return makelist(res,self)
  10168. end
  10169.  
  10170. --- 'reduce' a list using a binary function.
  10171. -- @param fun a function of two arguments
  10172. -- @return result of the function
  10173. -- @see pl.tablex.reduce
  10174. function List:reduce (fun)
  10175.     return reduce(fun,self)
  10176. end
  10177.  
  10178. --- partition a list using a classifier function.
  10179. -- The function may return nil, but this will be converted to the string key '<nil>'.
  10180. -- @param fun a function of at least one argument
  10181. -- @param ... will also be passed to the function
  10182. -- @return a table where the keys are the returned values, and the values are Lists
  10183. -- of values where the function returned that key. It is given the type of Multimap.
  10184. -- @see pl.MultiMap
  10185. function List:partition (fun,...)
  10186.     fun = function_arg(1,fun)
  10187.     local res = {}
  10188.     for i = 1,#self do
  10189.         local val = self[i]
  10190.         local klass = fun(val,...)
  10191.         if klass == nil then klass = '<nil>' end
  10192.         if not res[klass] then res[klass] = List() end
  10193.         res[klass]:append(val)
  10194.     end
  10195.     return setmetatable(res,Multimap)
  10196. end
  10197.  
  10198. --- return an iterator over all values.
  10199. function List:iter ()
  10200.     return iter(self)
  10201. end
  10202.  
  10203. --- Create an iterator over a seqence.
  10204. -- This captures the Python concept of 'sequence'.
  10205. -- For tables, iterates over all values with integer indices.
  10206. -- @param seq a sequence; a string (over characters), a table, a file object (over lines) or an iterator function
  10207. -- @usage for x in iterate {1,10,22,55} do io.write(x,',') end ==> 1,10,22,55
  10208. -- @usage for ch in iterate 'help' do do io.write(ch,' ') end ==> h e l p
  10209. function List.iterate(seq)
  10210.     if type(seq) == 'string' then
  10211.         local idx = 0
  10212.         local n = #seq
  10213.         local sub = string.sub
  10214.         return function ()
  10215.             idx = idx + 1
  10216.             if idx > n then return nil
  10217.             else
  10218.                 return sub(seq,idx,idx)
  10219.             end
  10220.         end
  10221.     elseif type(seq) == 'table' then
  10222.         local idx = 0
  10223.         local n = #seq
  10224.         return function()
  10225.             idx = idx + 1
  10226.             if idx > n then return nil
  10227.             else
  10228.                 return seq[idx]
  10229.             end
  10230.         end
  10231.     elseif type(seq) == 'function' then
  10232.         return seq
  10233.     elseif type(seq) == 'userdata' and io.type(seq) == 'file' then
  10234.         return seq:lines()
  10235.     end
  10236. end
  10237. iter = List.iterate
  10238.  
  10239. return List
  10240.  
  10241. ]===================],"CoolisOS/bin/utils/pl/tablex.lua",[===================[--- Extended operations on Lua tables.
  10242. --
  10243. -- See @{02-arrays.md.Useful_Operations_on_Tables|the Guide}
  10244. --
  10245. -- Dependencies: `pl.utils`
  10246. -- @module pl.tablex
  10247. local utils = require'utils'
  10248. local getmetatable,setmetatable,require = getmetatable,setmetatable,require
  10249. local append,remove = table.insert,table.remove
  10250. local min,max = math.min,math.max
  10251. local pairs,type,unpack,next,select,tostring = pairs,type,unpack,next,select,tostring
  10252. local function_arg = utils.function_arg
  10253. local Set = utils.stdmt.Set
  10254. local List = utils.stdmt.List
  10255. local Map = utils.stdmt.Map
  10256. local assert_arg = utils.assert_arg
  10257.  
  10258. local tablex = {}
  10259.  
  10260. -- generally, functions that make copies of tables try to preserve the metatable.
  10261. -- However, when the source has no obvious type, then we attach appropriate metatables
  10262. -- like List, Map, etc to the result.
  10263. local function setmeta (res,tbl,def)
  10264.     local mt = getmetatable(tbl) or def
  10265.     return setmetatable(res, mt)
  10266. end
  10267.  
  10268. local function makelist (res)
  10269.     return setmetatable(res,List)
  10270. end
  10271.  
  10272. local function check_meta (val)
  10273.     if type(val) == 'table' then return true end
  10274.     return getmetatable(val)
  10275. end
  10276.  
  10277. local function complain (idx,msg)
  10278.     error(('argument %d is not %s'):format(idx,msg),3)
  10279. end
  10280.  
  10281. local function assert_arg_indexable (idx,val)
  10282.     local mt = check_meta(val)
  10283.     if mt == true then return end
  10284.     if not(mt and mt.__len and mt.__index) then
  10285.         complain(idx,"indexable")
  10286.     end
  10287. end
  10288.  
  10289. local function assert_arg_iterable (idx,val)
  10290.     local mt = check_meta(val)
  10291.     if mt == true then return end
  10292.     if not(mt and mt.__pairs) then
  10293.         complain(idx,"iterable")
  10294.     end
  10295. end
  10296.  
  10297. local function assert_arg_writeable (idx,val)
  10298.     local mt = check_meta(val)
  10299.     if mt == true then return end
  10300.     if not(mt and mt.__newindex) then
  10301.         complain(idx,"writeable")
  10302.     end
  10303. end
  10304.  
  10305.  
  10306. --- copy a table into another, in-place.
  10307. -- @param t1 destination table
  10308. -- @param t2 source (any iterable object)
  10309. -- @return first table
  10310. function tablex.update (t1,t2)
  10311.     assert_arg_writeable(1,t1)
  10312.     assert_arg_iterable(2,t2)
  10313.     for k,v in pairs(t2) do
  10314.         t1[k] = v
  10315.     end
  10316.     return t1
  10317. end
  10318.  
  10319. --- total number of elements in this table.
  10320. -- Note that this is distinct from `#t`, which is the number
  10321. -- of values in the array part; this value will always
  10322. -- be greater or equal. The difference gives the size of
  10323. -- the hash part, for practical purposes. Works for any
  10324. -- object with a __pairs metamethod.
  10325. -- @param t a table
  10326. -- @return the size
  10327. function tablex.size (t)
  10328.     assert_arg_iterable(1,t)
  10329.     local i = 0
  10330.     for k in pairs(t) do i = i + 1 end
  10331.     return i
  10332. end
  10333.  
  10334. --- make a shallow copy of a table
  10335. -- @param t an iterable source
  10336. -- @return new table
  10337. function tablex.copy (t)
  10338.     assert_arg_iterable(1,t)
  10339.     local res = {}
  10340.     for k,v in pairs(t) do
  10341.         res[k] = v
  10342.     end
  10343.     return res
  10344. end
  10345.  
  10346. --- make a deep copy of a table, recursively copying all the keys and fields.
  10347. -- This will also set the copied table's metatable to that of the original.
  10348. --  @param t A table
  10349. -- @return new table
  10350. function tablex.deepcopy(t)
  10351.     if type(t) ~= 'table' then return t end
  10352.     assert_arg_iterable(1,t)
  10353.     local mt = getmetatable(t)
  10354.     local res = {}
  10355.     for k,v in pairs(t) do
  10356.         if type(v) == 'table' then
  10357.             v = tablex.deepcopy(v)
  10358.         end
  10359.         res[k] = v
  10360.     end
  10361.     setmetatable(res,mt)
  10362.     return res
  10363. end
  10364.  
  10365. local abs, deepcompare = math.abs
  10366.  
  10367. --- compare two values.
  10368. -- if they are tables, then compare their keys and fields recursively.
  10369. -- @param t1 A value
  10370. -- @param t2 A value
  10371. -- @param ignore_mt if true, ignore __eq metamethod (default false)
  10372. -- @param eps if defined, then used for any number comparisons
  10373. -- @return true or false
  10374. function tablex.deepcompare(t1,t2,ignore_mt,eps)
  10375.     local ty1 = type(t1)
  10376.     local ty2 = type(t2)
  10377.     if ty1 ~= ty2 then return false end
  10378.     -- non-table types can be directly compared
  10379.     if ty1 ~= 'table' then
  10380.         if ty1 == 'number' and eps then return abs(t1-t2) < eps end
  10381.         return t1 == t2
  10382.     end
  10383.     -- as well as tables which have the metamethod __eq
  10384.     local mt = getmetatable(t1)
  10385.     if not ignore_mt and mt and mt.__eq then return t1 == t2 end
  10386.     for k1 in pairs(t1) do
  10387.         if t2[k1]==nil then return false end
  10388.     end
  10389.     for k2 in pairs(t2) do
  10390.         if t1[k2]==nil then return false end
  10391.     end
  10392.     for k1,v1 in pairs(t1) do
  10393.         local v2 = t2[k1]
  10394.         if not deepcompare(v1,v2,ignore_mt,eps) then return false end
  10395.     end
  10396.  
  10397.     return true
  10398. end
  10399.  
  10400. deepcompare = tablex.deepcompare
  10401.  
  10402. --- compare two arrays using a predicate.
  10403. -- @param t1 an array
  10404. -- @param t2 an array
  10405. -- @param cmp A comparison function
  10406. function tablex.compare (t1,t2,cmp)
  10407.     assert_arg_indexable(1,t1)
  10408.     assert_arg_indexable(2,t2)
  10409.     if #t1 ~= #t2 then return false end
  10410.     cmp = function_arg(3,cmp)
  10411.     for k = 1,#t1 do
  10412.         if not cmp(t1[k],t2[k]) then return false end
  10413.     end
  10414.     return true
  10415. end
  10416.  
  10417. --- compare two list-like tables using an optional predicate, without regard for element order.
  10418. -- @param t1 a list-like table
  10419. -- @param t2 a list-like table
  10420. -- @param cmp A comparison function (may be nil)
  10421. function tablex.compare_no_order (t1,t2,cmp)
  10422.     assert_arg_indexable(1,t1)
  10423.     assert_arg_indexable(2,t2)
  10424.     if cmp then cmp = function_arg(3,cmp) end
  10425.     if #t1 ~= #t2 then return false end
  10426.     local visited = {}
  10427.     for i = 1,#t1 do
  10428.         local val = t1[i]
  10429.         local gotcha
  10430.         for j = 1,#t2 do if not visited[j] then
  10431.             local match
  10432.             if cmp then match = cmp(val,t2[j]) else match = val == t2[j] end
  10433.             if match then
  10434.                 gotcha = j
  10435.                 break
  10436.             end
  10437.         end end
  10438.         if not gotcha then return false end
  10439.         visited[gotcha] = true
  10440.     end
  10441.     return true
  10442. end
  10443.  
  10444.  
  10445. --- return the index of a value in a list.
  10446. -- Like string.find, there is an optional index to start searching,
  10447. -- which can be negative.
  10448. -- @param t A list-like table (i.e. with numerical indices)
  10449. -- @param val A value
  10450. -- @param idx index to start; -1 means last element,etc (default 1)
  10451. -- @return index of value or nil if not found
  10452. -- @usage find({10,20,30},20) == 2
  10453. -- @usage find({'a','b','a','c'},'a',2) == 3
  10454. function tablex.find(t,val,idx)
  10455.     assert_arg_indexable(1,t)
  10456.     idx = idx or 1
  10457.     if idx < 0 then idx = #t + idx + 1 end
  10458.     for i = idx,#t do
  10459.         if t[i] == val then return i end
  10460.     end
  10461.     return nil
  10462. end
  10463.  
  10464. --- return the index of a value in a list, searching from the end.
  10465. -- Like string.find, there is an optional index to start searching,
  10466. -- which can be negative.
  10467. -- @param t A list-like table (i.e. with numerical indices)
  10468. -- @param val A value
  10469. -- @param idx index to start; -1 means last element,etc (default 1)
  10470. -- @return index of value or nil if not found
  10471. -- @usage rfind({10,10,10},10) == 3
  10472. function tablex.rfind(t,val,idx)
  10473.     assert_arg_indexable(1,t)
  10474.     idx = idx or #t
  10475.     if idx < 0 then idx = #t + idx + 1 end
  10476.     for i = idx,1,-1 do
  10477.         if t[i] == val then return i end
  10478.     end
  10479.     return nil
  10480. end
  10481.  
  10482.  
  10483. --- return the index (or key) of a value in a table using a comparison function.
  10484. -- @param t A table
  10485. -- @param cmp A comparison function
  10486. -- @param arg an optional second argument to the function
  10487. -- @return index of value, or nil if not found
  10488. -- @return value returned by comparison function
  10489. function tablex.find_if(t,cmp,arg)
  10490.     assert_arg_iterable(1,t)
  10491.     cmp = function_arg(2,cmp)
  10492.     for k,v in pairs(t) do
  10493.         local c = cmp(v,arg)
  10494.         if c then return k,c end
  10495.     end
  10496.     return nil
  10497. end
  10498.  
  10499. --- return a list of all values in a table indexed by another list.
  10500. -- @param tbl a table
  10501. -- @param idx an index table (a list of keys)
  10502. -- @return a list-like table
  10503. -- @usage index_by({10,20,30,40},{2,4}) == {20,40}
  10504. -- @usage index_by({one=1,two=2,three=3},{'one','three'}) == {1,3}
  10505. function tablex.index_by(tbl,idx)
  10506.     assert_arg_indexable(1,tbl)
  10507.     assert_arg_indexable(2,idx)
  10508.     local res = {}
  10509.     for i = 1,#idx do
  10510.         res[i] = tbl[idx[i]]
  10511.     end
  10512.     return setmeta(res,tbl,List)
  10513. end
  10514.  
  10515. --- apply a function to all values of a table.
  10516. -- This returns a table of the results.
  10517. -- Any extra arguments are passed to the function.
  10518. -- @param fun A function that takes at least one argument
  10519. -- @param t A table
  10520. -- @param ... optional arguments
  10521. -- @usage map(function(v) return v*v end, {10,20,30,fred=2}) is {100,400,900,fred=4}
  10522. function tablex.map(fun,t,...)
  10523.     assert_arg_iterable(1,t)
  10524.     fun = function_arg(1,fun)
  10525.     local res = {}
  10526.     for k,v in pairs(t) do
  10527.         res[k] = fun(v,...)
  10528.     end
  10529.     return setmeta(res,t)
  10530. end
  10531.  
  10532. --- apply a function to all values of a list.
  10533. -- This returns a table of the results.
  10534. -- Any extra arguments are passed to the function.
  10535. -- @param fun A function that takes at least one argument
  10536. -- @param t a table (applies to array part)
  10537. -- @param ... optional arguments
  10538. -- @return a list-like table
  10539. -- @usage imap(function(v) return v*v end, {10,20,30,fred=2}) is {100,400,900}
  10540. function tablex.imap(fun,t,...)
  10541.     assert_arg_indexable(1,t)
  10542.     fun = function_arg(1,fun)
  10543.     local res = {}
  10544.     for i = 1,#t do
  10545.         res[i] = fun(t[i],...) or false
  10546.     end
  10547.     return setmeta(res,t,List)
  10548. end
  10549.  
  10550. --- apply a named method to values from a table.
  10551. -- @param name the method name
  10552. -- @param t a list-like table
  10553. -- @param ... any extra arguments to the method
  10554. function tablex.map_named_method (name,t,...)
  10555.     utils.assert_string(1,name)
  10556.     assert_arg_indexable(2,t)
  10557.     local res = {}
  10558.     for i = 1,#t do
  10559.         local val = t[i]
  10560.         local fun = val[name]
  10561.         res[i] = fun(val,...)
  10562.     end
  10563.     return setmeta(res,t,List)
  10564. end
  10565.  
  10566.  
  10567. --- apply a function to all values of a table, in-place.
  10568. -- Any extra arguments are passed to the function.
  10569. -- @param fun A function that takes at least one argument
  10570. -- @param t a table
  10571. -- @param ... extra arguments
  10572. function tablex.transform (fun,t,...)
  10573.     assert_arg_iterable(1,t)
  10574.     fun = function_arg(1,fun)
  10575.     for k,v in pairs(t) do
  10576.         t[k] = fun(v,...)
  10577.     end
  10578. end
  10579.  
  10580. --- generate a table of all numbers in a range
  10581. -- @param start  number
  10582. -- @param finish number
  10583. -- @param step optional increment (default 1 for increasing, -1 for decreasing)
  10584. function tablex.range (start,finish,step)
  10585.     if start == finish then return {start}
  10586.     elseif start > finish then return {}
  10587.     end
  10588.     local res = {}
  10589.     local k = 1
  10590.     if not step then
  10591.         if finish > start then step = finish > start and 1 or -1 end
  10592.     end
  10593.     for i=start,finish,step do res[k]=i; k=k+1 end
  10594.     return res
  10595. end
  10596.  
  10597. --- apply a function to values from two tables.
  10598. -- @param fun a function of at least two arguments
  10599. -- @param t1 a table
  10600. -- @param t2 a table
  10601. -- @param ... extra arguments
  10602. -- @return a table
  10603. -- @usage map2('+',{1,2,3,m=4},{10,20,30,m=40}) is {11,22,23,m=44}
  10604. function tablex.map2 (fun,t1,t2,...)
  10605.     assert_arg_iterable(1,t1)
  10606.     assert_arg_iterable(2,t2)
  10607.     fun = function_arg(1,fun)
  10608.     local res = {}
  10609.     for k,v in pairs(t1) do
  10610.         res[k] = fun(v,t2[k],...)
  10611.     end
  10612.     return setmeta(res,t1,List)
  10613. end
  10614.  
  10615. --- apply a function to values from two arrays.
  10616. -- The result will be the length of the shortest array.
  10617. -- @param fun a function of at least two arguments
  10618. -- @param t1 a list-like table
  10619. -- @param t2 a list-like table
  10620. -- @param ... extra arguments
  10621. -- @usage imap2('+',{1,2,3,m=4},{10,20,30,m=40}) is {11,22,23}
  10622. function tablex.imap2 (fun,t1,t2,...)
  10623.     assert_arg_indexable(2,t1)
  10624.     assert_arg_indexable(3,t2)
  10625.     fun = function_arg(1,fun)
  10626.     local res,n = {},math.min(#t1,#t2)
  10627.     for i = 1,n do
  10628.         res[i] = fun(t1[i],t2[i],...)
  10629.     end
  10630.     return res
  10631. end
  10632.  
  10633. --- 'reduce' a list using a binary function.
  10634. -- @param fun a function of two arguments
  10635. -- @param t a list-like table
  10636. -- @return the result of the function
  10637. -- @usage reduce('+',{1,2,3,4}) == 10
  10638. function tablex.reduce (fun,t)
  10639.     assert_arg_indexable(2,t)
  10640.     fun = function_arg(1,fun)
  10641.     local n = #t
  10642.     local res = t[1]
  10643.     for i = 2,n do
  10644.         res = fun(res,t[i])
  10645.     end
  10646.     return res
  10647. end
  10648.  
  10649. --- apply a function to all elements of a table.
  10650. -- The arguments to the function will be the value,
  10651. -- the key and <i>finally</i> any extra arguments passed to this function.
  10652. -- Note that the Lua 5.0 function table.foreach passed the <i>key</i> first.
  10653. -- @param t a table
  10654. -- @param fun a function with at least one argument
  10655. -- @param ... extra arguments
  10656. function tablex.foreach(t,fun,...)
  10657.     assert_arg_iterable(1,t)
  10658.     fun = function_arg(2,fun)
  10659.     for k,v in pairs(t) do
  10660.         fun(v,k,...)
  10661.     end
  10662. end
  10663.  
  10664. --- apply a function to all elements of a list-like table in order.
  10665. -- The arguments to the function will be the value,
  10666. -- the index and <i>finally</i> any extra arguments passed to this function
  10667. -- @param t a table
  10668. -- @param fun a function with at least one argument
  10669. -- @param ... optional arguments
  10670. function tablex.foreachi(t,fun,...)
  10671.     assert_arg_indexable(1,t)
  10672.     fun = function_arg(2,fun)
  10673.     for i = 1,#t do
  10674.         fun(t[i],i,...)
  10675.     end
  10676. end
  10677.  
  10678.  
  10679. --- Apply a function to a number of tables.
  10680. -- A more general version of map
  10681. -- The result is a table containing the result of applying that function to the
  10682. -- ith value of each table. Length of output list is the minimum length of all the lists
  10683. -- @param fun a function of n arguments
  10684. -- @param ... n tables
  10685. -- @usage mapn(function(x,y,z) return x+y+z end, {1,2,3},{10,20,30},{100,200,300}) is {111,222,333}
  10686. -- @usage mapn(math.max, {1,20,300},{10,2,3},{100,200,100}) is  {100,200,300}
  10687. -- @param fun A function that takes as many arguments as there are tables
  10688. function tablex.mapn(fun,...)
  10689.     fun = function_arg(1,fun)
  10690.     local res = {}
  10691.     local lists = {...}
  10692.     local minn = 1e40
  10693.     for i = 1,#lists do
  10694.         minn = min(minn,#(lists[i]))
  10695.     end
  10696.     for i = 1,minn do
  10697.         local args,k = {},1
  10698.         for j = 1,#lists do
  10699.             args[k] = lists[j][i]
  10700.             k = k + 1
  10701.         end
  10702.         res[#res+1] = fun(unpack(args))
  10703.     end
  10704.     return res
  10705. end
  10706.  
  10707. --- call the function with the key and value pairs from a table.
  10708. -- The function can return a value and a key (note the order!). If both
  10709. -- are not nil, then this pair is inserted into the result. If only value is not nil, then
  10710. -- it is appended to the result.
  10711. -- @param fun A function which will be passed each key and value as arguments, plus any extra arguments to pairmap.
  10712. -- @param t A table
  10713. -- @param ... optional arguments
  10714. -- @usage pairmap(function(k,v) return v end,{fred=10,bonzo=20}) is {10,20} _or_ {20,10}
  10715. -- @usage pairmap(function(k,v) return {k,v},k end,{one=1,two=2}) is {one={'one',1},two={'two',2}}
  10716. function tablex.pairmap(fun,t,...)
  10717.     assert_arg_iterable(1,t)
  10718.     fun = function_arg(1,fun)
  10719.     local res = {}
  10720.     for k,v in pairs(t) do
  10721.         local rv,rk = fun(k,v,...)
  10722.         if rk then
  10723.             res[rk] = rv
  10724.         else
  10725.             res[#res+1] = rv
  10726.         end
  10727.     end
  10728.     return res
  10729. end
  10730.  
  10731. local function keys_op(i,v) return i end
  10732.  
  10733. --- return all the keys of a table in arbitrary order.
  10734. --  @param t A table
  10735. function tablex.keys(t)
  10736.     assert_arg_iterable(1,t)
  10737.     return makelist(tablex.pairmap(keys_op,t))
  10738. end
  10739.  
  10740. local function values_op(i,v) return v end
  10741.  
  10742. --- return all the values of the table in arbitrary order
  10743. --  @param t A table
  10744. function tablex.values(t)
  10745.     assert_arg_iterable(1,t)
  10746.     return makelist(tablex.pairmap(values_op,t))
  10747. end
  10748.  
  10749. local function index_map_op (i,v) return i,v end
  10750.  
  10751. --- create an index map from a list-like table. The original values become keys,
  10752. -- and the associated values are the indices into the original list.
  10753. -- @param t a list-like table
  10754. -- @return a map-like table
  10755. function tablex.index_map (t)
  10756.     assert_arg_indexable(1,t)
  10757.     return setmetatable(tablex.pairmap(index_map_op,t),Map)
  10758. end
  10759.  
  10760. local function set_op(i,v) return true,v end
  10761.  
  10762. --- create a set from a list-like table. A set is a table where the original values
  10763. -- become keys, and the associated values are all true.
  10764. -- @param t a list-like table
  10765. -- @return a set (a map-like table)
  10766. function tablex.makeset (t)
  10767.     assert_arg_indexable(1,t)
  10768.     return setmetatable(tablex.pairmap(set_op,t),Set)
  10769. end
  10770.  
  10771.  
  10772. --- combine two tables, either as union or intersection. Corresponds to
  10773. -- set operations for sets () but more general. Not particularly
  10774. -- useful for list-like tables.
  10775. -- @param t1 a table
  10776. -- @param t2 a table
  10777. -- @param dup true for a union, false for an intersection.
  10778. -- @usage merge({alice=23,fred=34},{bob=25,fred=34}) is {fred=34}
  10779. -- @usage merge({alice=23,fred=34},{bob=25,fred=34},true) is {bob=25,fred=34,alice=23}
  10780. -- @see tablex.index_map
  10781. function tablex.merge (t1,t2,dup)
  10782.     assert_arg_iterable(1,t1)
  10783.     assert_arg_iterable(2,t2)
  10784.     local res = {}
  10785.     for k,v in pairs(t1) do
  10786.         if dup or t2[k] then res[k] = v end
  10787.     end
  10788.     if dup then
  10789.       for k,v in pairs(t2) do
  10790.         res[k] = v
  10791.       end
  10792.     end
  10793.     return setmeta(res,t1,Map)
  10794. end
  10795.  
  10796. --- a new table which is the difference of two tables.
  10797. -- With sets (where the values are all true) this is set difference and
  10798. -- symmetric difference depending on the third parameter.
  10799. -- @param s1 a map-like table or set
  10800. -- @param s2 a map-like table or set
  10801. -- @param symm symmetric difference (default false)
  10802. -- @return a map-like table or set
  10803. function tablex.difference (s1,s2,symm)
  10804.     assert_arg_iterable(1,s1)
  10805.     assert_arg_iterable(2,s2)
  10806.     local res = {}
  10807.     for k,v in pairs(s1) do
  10808.         if not s2[k] then res[k] = v end
  10809.     end
  10810.     if symm then
  10811.         for k,v in pairs(s2) do
  10812.             if not s1[k] then res[k] = v end
  10813.         end
  10814.     end
  10815.     return setmeta(res,s1,Map)
  10816. end
  10817.  
  10818. --- A table where the key/values are the values and value counts of the table.
  10819. -- @param t a list-like table
  10820. -- @param cmp a function that defines equality (otherwise uses ==)
  10821. -- @return a map-like table
  10822. -- @see seq.count_map
  10823. function tablex.count_map (t,cmp)
  10824.     assert_arg_indexable(1,t)
  10825.     local res,mask = {},{}
  10826.     cmp = function_arg(2,cmp)
  10827.     local n = #t
  10828.     for i = 1,#t do
  10829.         local v = t[i]
  10830.         if not mask[v] then
  10831.             mask[v] = true
  10832.             -- check this value against all other values
  10833.             res[v] = 1  -- there's at least one instance
  10834.             for j = i+1,n do
  10835.                 local w = t[j]
  10836.                 if cmp and cmp(v,w) or v == w then
  10837.                     res[v] = res[v] + 1
  10838.                     mask[w] = true
  10839.                 end
  10840.             end
  10841.         end
  10842.     end
  10843.     return setmetatable(res,Map)
  10844. end
  10845.  
  10846. --- filter a table's values using a predicate function
  10847. -- @param t a list-like table
  10848. -- @param pred a boolean function
  10849. -- @param arg optional argument to be passed as second argument of the predicate
  10850. function tablex.filter (t,pred,arg)
  10851.     assert_arg_indexable(1,t)
  10852.     pred = function_arg(2,pred)
  10853.     local res,k = {},1
  10854.     for i = 1,#t do
  10855.         local v = t[i]
  10856.         if pred(v,arg) then
  10857.             res[k] = v
  10858.             k = k + 1
  10859.         end
  10860.     end
  10861.     return setmeta(res,t,List)
  10862. end
  10863.  
  10864. --- return a table where each element is a table of the ith values of an arbitrary
  10865. -- number of tables. It is equivalent to a matrix transpose.
  10866. -- @usage zip({10,20,30},{100,200,300}) is {{10,100},{20,200},{30,300}}
  10867. function tablex.zip(...)
  10868.     return tablex.mapn(function(...) return {...} end,...)
  10869. end
  10870.  
  10871. local _copy
  10872. function _copy (dest,src,idest,isrc,nsrc,clean_tail)
  10873.     idest = idest or 1
  10874.     isrc = isrc or 1
  10875.     local iend
  10876.     if not nsrc then
  10877.         nsrc = #src
  10878.         iend = #src
  10879.     else
  10880.         iend = isrc + min(nsrc-1,#src-isrc)
  10881.     end
  10882.     if dest == src then -- special case
  10883.         if idest > isrc and iend >= idest then -- overlapping ranges
  10884.             src = tablex.sub(src,isrc,nsrc)
  10885.             isrc = 1; iend = #src
  10886.         end
  10887.     end
  10888.     for i = isrc,iend do
  10889.         dest[idest] = src[i]
  10890.         idest = idest + 1
  10891.     end
  10892.     if clean_tail then
  10893.         tablex.clear(dest,idest)
  10894.     end
  10895.     return dest
  10896. end
  10897.  
  10898. --- copy an array into another one, resizing the destination if necessary. <br>
  10899. -- @param dest a list-like table
  10900. -- @param src a list-like table
  10901. -- @param idest where to start copying values from source (default 1)
  10902. -- @param isrc where to start copying values into destination (default 1)
  10903. -- @param nsrc number of elements to copy from source (default source size)
  10904. function tablex.icopy (dest,src,idest,isrc,nsrc)
  10905.     assert_arg_indexable(1,dest)
  10906.     assert_arg_indexable(2,src)
  10907.     return _copy(dest,src,idest,isrc,nsrc,true)
  10908. end
  10909.  
  10910. --- copy an array into another one. <br>
  10911. -- @param dest a list-like table
  10912. -- @param src a list-like table
  10913. -- @param idest where to start copying values from source (default 1)
  10914. -- @param isrc where to start copying values into destination (default 1)
  10915. -- @param nsrc number of elements to copy from source (default source size)
  10916. function tablex.move (dest,src,idest,isrc,nsrc)
  10917.     assert_arg_indexable(1,dest)
  10918.     assert_arg_indexable(2,src)
  10919.     return _copy(dest,src,idest,isrc,nsrc,false)
  10920. end
  10921.  
  10922. function tablex._normalize_slice(self,first,last)
  10923.   local sz = #self
  10924.   if not first then first=1 end
  10925.   if first<0 then first=sz+first+1 end
  10926.   -- make the range _inclusive_!
  10927.   if not last then last=sz end
  10928.   if last < 0 then last=sz+1+last end
  10929.   return first,last
  10930. end
  10931.  
  10932. --- Extract a range from a table, like  'string.sub'.
  10933. -- If first or last are negative then they are relative to the end of the list
  10934. -- eg. sub(t,-2) gives last 2 entries in a list, and
  10935. -- sub(t,-4,-2) gives from -4th to -2nd
  10936. -- @param t a list-like table
  10937. -- @param first An index
  10938. -- @param last An index
  10939. -- @return a new List
  10940. function tablex.sub(t,first,last)
  10941.     assert_arg_indexable(1,t)
  10942.     first,last = tablex._normalize_slice(t,first,last)
  10943.     local res={}
  10944.     for i=first,last do append(res,t[i]) end
  10945.     return setmeta(res,t,List)
  10946. end
  10947.  
  10948. --- set an array range to a value. If it's a function we use the result
  10949. -- of applying it to the indices.
  10950. -- @param t a list-like table
  10951. -- @param val a value
  10952. -- @param i1 start range (default 1)
  10953. -- @param i2 end range (default table size)
  10954. function tablex.set (t,val,i1,i2)
  10955.     assert_arg_indexable(1,t)
  10956.     i1,i2 = i1 or 1,i2 or #t
  10957.     if utils.is_callable(val) then
  10958.         for i = i1,i2 do
  10959.             t[i] = val(i)
  10960.         end
  10961.     else
  10962.         for i = i1,i2 do
  10963.             t[i] = val
  10964.         end
  10965.     end
  10966. end
  10967.  
  10968. --- create a new array of specified size with initial value.
  10969. -- @param n size
  10970. -- @param val initial value (can be nil, but don't expect # to work!)
  10971. -- @return the table
  10972. function tablex.new (n,val)
  10973.     local res = {}
  10974.     tablex.set(res,val,1,n)
  10975.     return res
  10976. end
  10977.  
  10978. --- clear out the contents of a table.
  10979. -- @param t a table
  10980. -- @param istart optional start position
  10981. function tablex.clear(t,istart)
  10982.     istart = istart or 1
  10983.     for i = istart,#t do remove(t) end
  10984. end
  10985.  
  10986. --- insert values into a table. <br>
  10987. -- insertvalues(t, [pos,] values) <br>
  10988. -- similar to table.insert but inserts values from given table "values",
  10989. -- not the object itself, into table "t" at position "pos".
  10990. function tablex.insertvalues(t, ...)
  10991.     assert_arg(1,t,'table')
  10992.     local pos, values
  10993.     if select('#', ...) == 1 then
  10994.         pos,values = #t+1, ...
  10995.     else
  10996.         pos,values = ...
  10997.     end
  10998.     if #values > 0 then
  10999.         for i=#t,pos,-1 do
  11000.             t[i+#values] = t[i]
  11001.         end
  11002.         local offset = 1 - pos
  11003.         for i=pos,pos+#values-1 do
  11004.             t[i] = values[i + offset]
  11005.         end
  11006.     end
  11007.     return t
  11008. end
  11009.  
  11010. --- remove a range of values from a table.
  11011. -- @param t a list-like table
  11012. -- @param i1 start index
  11013. -- @param i2 end index
  11014. -- @return the table
  11015. function tablex.removevalues (t,i1,i2)
  11016.     assert_arg(1,t,'table')
  11017.     i1,i2 = tablex._normalize_slice(t,i1,i2)
  11018.     for i = i1,i2 do
  11019.         remove(t,i1)
  11020.     end
  11021.     return t
  11022. end
  11023.  
  11024. local _find
  11025. _find = function (t,value,tables)
  11026.     for k,v in pairs(t) do
  11027.         if v == value then return k end
  11028.     end
  11029.     for k,v in pairs(t) do
  11030.         if not tables[v] and type(v) == 'table' then
  11031.             tables[v] = true
  11032.             local res = _find(v,value,tables)
  11033.             if res then
  11034.                 res = tostring(res)
  11035.                 if type(k) ~= 'string' then
  11036.                     return '['..k..']'..res
  11037.                 else
  11038.                     return k..'.'..res
  11039.                 end
  11040.             end
  11041.         end
  11042.     end
  11043. end
  11044.  
  11045. --- find a value in a table by recursive search.
  11046. -- @param t the table
  11047. -- @param value the value
  11048. -- @param exclude any tables to avoid searching
  11049. -- @usage search(_G,math.sin,{package.path}) == 'math.sin'
  11050. -- @return a fieldspec, e.g. 'a.b' or 'math.sin'
  11051. function tablex.search (t,value,exclude)
  11052.     assert_arg_iterable(1,t)
  11053.     local tables = {[t]=true}
  11054.     if exclude then
  11055.         for _,v in pairs(exclude) do tables[v] = true end
  11056.     end
  11057.     return _find(t,value,tables)
  11058. end
  11059.  
  11060. return tablex
  11061. ]===================],"CoolisOS/bin/utils/pl/utils.lua",[===================[--- Generally useful routines.
  11062. -- See  @{01-introduction.md.Generally_useful_functions|the Guide}.
  11063. -- @module pl.utils
  11064. local format,gsub,byte = string.format,string.gsub,string.byte
  11065. local clock = os.clock
  11066. local stdout = io.stdout
  11067. local append = table.insert
  11068.  
  11069. local collisions = {}
  11070.  
  11071. local utils = {}
  11072.  
  11073. utils._VERSION = "1.1.0"
  11074.  
  11075. local lua51 = rawget(_G,'setfenv')
  11076.  
  11077. utils.lua51 = lua51
  11078. if not lua51 then -- Lua 5.2 compatibility
  11079.     unpack = table.unpack
  11080.     loadstring = load
  11081. end
  11082.  
  11083. utils.dir_separator = '/'
  11084.  
  11085. --- end this program gracefully.
  11086. -- @param code The exit code or a message to be printed
  11087. -- @param ... extra arguments for message's format'
  11088. -- @see utils.fprintf
  11089. function utils.quit(code,...)
  11090.     if type(code) == 'string' then
  11091.         utils.fprintf(io.stderr,code,...)
  11092.         code = -1
  11093.     else
  11094.         utils.fprintf(io.stderr,...)
  11095.     end
  11096.     io.stderr:write('\n')
  11097.     os.exit(code)
  11098. end
  11099.  
  11100. --- print an arbitrary number of arguments using a format.
  11101. -- @param fmt The format (see string.format)
  11102. -- @param ... Extra arguments for format
  11103. function utils.printf(fmt,...)
  11104.     utils.assert_string(1,fmt)
  11105.     utils.fprintf(stdout,fmt,...)
  11106. end
  11107.  
  11108. --- write an arbitrary number of arguments to a file using a format.
  11109. -- @param f File handle to write to.
  11110. -- @param fmt The format (see string.format).
  11111. -- @param ... Extra arguments for format
  11112. function utils.fprintf(f,fmt,...)
  11113.     utils.assert_string(2,fmt)
  11114.     f:write(format(fmt,...))
  11115. end
  11116.  
  11117. local function import_symbol(T,k,v,libname)
  11118.     local key = rawget(T,k)
  11119.     -- warn about collisions!
  11120.     if key and k ~= '_M' and k ~= '_NAME' and k ~= '_PACKAGE' and k ~= '_VERSION' then
  11121.         utils.printf("warning: '%s.%s' overrides existing symbol\n",libname,k)
  11122.     end
  11123.     rawset(T,k,v)
  11124. end
  11125.  
  11126. local function lookup_lib(T,t)
  11127.     for k,v in pairs(T) do
  11128.         if v == t then return k end
  11129.     end
  11130.     return '?'
  11131. end
  11132.  
  11133. local already_imported = {}
  11134.  
  11135. --- take a table and 'inject' it into the local namespace.
  11136. -- @param t The Table
  11137. -- @param T An optional destination table (defaults to callers environment)
  11138. function utils.import(t,T)
  11139.     T = T or _G
  11140.     t = t or utils
  11141.     if type(t) == 'string' then
  11142.         t = require (t)
  11143.     end
  11144.     local libname = lookup_lib(T,t)
  11145.     if already_imported[t] then return end
  11146.     already_imported[t] = libname
  11147.     for k,v in pairs(t) do
  11148.         import_symbol(T,k,v,libname)
  11149.     end
  11150. end
  11151.  
  11152. utils.patterns = {
  11153.     FLOAT = '[%+%-%d]%d*%.?%d*[eE]?[%+%-]?%d*',
  11154.     INTEGER = '[+%-%d]%d*',
  11155.     IDEN = '[%a_][%w_]*',
  11156.     FILE = '[%a%.\\][:%][%w%._%-\\]*'
  11157. }
  11158.  
  11159. --- escape any 'magic' characters in a string
  11160. -- @param s The input string
  11161. function utils.escape(s)
  11162.     utils.assert_string(1,s)
  11163.     return (s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1'))
  11164. end
  11165.  
  11166. --- return either of two values, depending on a condition.
  11167. -- @param cond A condition
  11168. -- @param value1 Value returned if cond is true
  11169. -- @param value2 Value returned if cond is false (can be optional)
  11170. function utils.choose(cond,value1,value2)
  11171.     if cond then return value1
  11172.     else return value2
  11173.     end
  11174. end
  11175.  
  11176. local raise
  11177.  
  11178. --- return the contents of a file as a string
  11179. -- @param filename The file path
  11180. -- @param is_bin open in binary mode
  11181. -- @return file contents
  11182. function utils.readfile(filename,is_bin)
  11183.     local mode = is_bin and 'b' or ''
  11184.     utils.assert_string(1,filename)
  11185.     local f,err = io.open(filename,'r'..mode)
  11186.     if not f then return utils.raise (err) end
  11187.     local res,err = f:read('*a')
  11188.     f:close()
  11189.     if not res then return raise (err) end
  11190.     return res
  11191. end
  11192.  
  11193. --- write a string to a file
  11194. -- @param filename The file path
  11195. -- @param str The string
  11196. -- @return true or nil
  11197. -- @return error message
  11198. -- @raise error if filename or str aren't strings
  11199. function utils.writefile(filename,str)
  11200.     utils.assert_string(1,filename)
  11201.     utils.assert_string(2,str)
  11202.     local f,err = io.open(filename,'w')
  11203.     if not f then return raise(err) end
  11204.     f:write(str)
  11205.     f:close()
  11206.     return true
  11207. end
  11208.  
  11209. --- return the contents of a file as a list of lines
  11210. -- @param filename The file path
  11211. -- @return file contents as a table
  11212. -- @raise errror if filename is not a string
  11213. function utils.readlines(filename)
  11214.     utils.assert_string(1,filename)
  11215.     local f,err = io.open(filename,'r')
  11216.     if not f then return raise(err) end
  11217.     local res = {}
  11218.     for line in f:lines() do
  11219.         append(res,line)
  11220.     end
  11221.     f:close()
  11222.     return res
  11223. end
  11224.  
  11225. --- split a string into a list of strings separated by a delimiter.
  11226. -- @param s The input string
  11227. -- @param re A Lua string pattern; defaults to '%s+'
  11228. -- @param plain don't use Lua patterns
  11229. -- @param n optional maximum number of splits
  11230. -- @return a list-like table
  11231. -- @raise error if s is not a string
  11232. function utils.split(s,re,plain,n)
  11233.     utils.assert_string(1,s)
  11234.     local find,sub,append = string.find, string.sub, table.insert
  11235.     local i1,ls = 1,{}
  11236.     if not re then re = '%s+' end
  11237.     if re == '' then return {s} end
  11238.     while true do
  11239.         local i2,i3 = find(s,re,i1,plain)
  11240.         if not i2 then
  11241.             local last = sub(s,i1)
  11242.             if last ~= '' then append(ls,last) end
  11243.             if #ls == 1 and ls[1] == '' then
  11244.                 return {}
  11245.             else
  11246.                 return ls
  11247.             end
  11248.         end
  11249.         append(ls,sub(s,i1,i2-1))
  11250.         if n and #ls == n then
  11251.             ls[#ls] = sub(s,i1)
  11252.             return ls
  11253.         end
  11254.         i1 = i3+1
  11255.     end
  11256. end
  11257.  
  11258. --- split a string into a number of values.
  11259. -- @param s the string
  11260. -- @param re the delimiter, default space
  11261. -- @return n values
  11262. -- @usage first,next = splitv('jane:doe',':')
  11263. -- @see split
  11264. function utils.splitv (s,re)
  11265.     return unpack(utils.split(s,re))
  11266. end
  11267.  
  11268. --- convert an array of values to strings.
  11269. -- @param t a list-like table
  11270. -- @param temp buffer to use, otherwise allocate
  11271. -- @param tostr custom tostring function, called with (value,index).
  11272. -- Otherwise use `tostring`
  11273. -- @return the converted buffer
  11274. function utils.array_tostring (t,temp,tostr)
  11275.     temp, tostr = temp or {}, tostr or tostring
  11276.     for i = 1,#t do
  11277.         temp[i] = tostr(t[i],i)
  11278.     end
  11279.     return temp
  11280. end
  11281.  
  11282. local lua51_load = load
  11283.  
  11284. if utils.lua51 then -- define Lua 5.2 style load()
  11285.     function utils.load(str,src,mode,env)
  11286.         local chunk,err
  11287.         if type(str) == 'string' then
  11288.             chunk,err = loadstring(str,src)
  11289.         else
  11290.             chunk,err = lua51_load(str,src)
  11291.         end
  11292.         if chunk and env then setfenv(chunk,env) end
  11293.         return chunk,err
  11294.     end
  11295. end
  11296.  
  11297.  
  11298. --- execute a shell command.
  11299. -- This is a compatibility function that returns the same for Lua 5.1 and Lua 5.2
  11300. -- @param cmd a shell command
  11301. -- @return true if successful
  11302. -- @return actual return code
  11303. function utils.execute (cmd)
  11304.     local res1,res2,res2 = os.execute(cmd)
  11305.     if lua51 then
  11306.         return res1==0,res1
  11307.     else
  11308.         return res1,res2
  11309.     end
  11310. end
  11311.  
  11312. if lua51 then
  11313.     function table.pack (...)
  11314.         local n = select('#',...)
  11315.         return {n=n; ...}
  11316.     end
  11317.     local sep = '/'
  11318.     function utils.searchpath (mod,path)
  11319.         mod = mod:gsub('%.',sep)
  11320.         for m in path:gmatch('[^;]+') do
  11321.             local nm = m:gsub('?',mod)
  11322.             local f = io.open(nm,'r')
  11323.             if f then f:close(); return nm end
  11324.         end
  11325.     end
  11326. end
  11327.  
  11328. if not table.pack then table.pack = _G.pack end
  11329. if not rawget(_G,"pack") then _G.pack = table.pack end
  11330.  
  11331. --- take an arbitrary set of arguments and make into a table.
  11332. -- This returns the table and the size; works fine for nil arguments
  11333. -- @param ... arguments
  11334. -- @return table
  11335. -- @return table size
  11336. -- @usage local t,n = utils.args(...)
  11337.  
  11338. --- 'memoize' a function (cache returned value for next call).
  11339. -- This is useful if you have a function which is relatively expensive,
  11340. -- but you don't know in advance what values will be required, so
  11341. -- building a table upfront is wasteful/impossible.
  11342. -- @param func a function of at least one argument
  11343. -- @return a function with at least one argument, which is used as the key.
  11344. function utils.memoize(func)
  11345.     return setmetatable({}, {
  11346.         __index = function(self, k, ...)
  11347.             local v = func(k,...)
  11348.             self[k] = v
  11349.             return v
  11350.         end,
  11351.         __call = function(self, k) return self[k] end
  11352.     })
  11353. end
  11354.  
  11355. --- is the object either a function or a callable object?.
  11356. -- @param obj Object to check.
  11357. function utils.is_callable (obj)
  11358.     return type(obj) == 'function' or getmetatable(obj) and getmetatable(obj).__call
  11359. end
  11360.  
  11361. --- is the object of the specified type?.
  11362. -- If the type is a string, then use type, otherwise compare with metatable
  11363. -- @param obj An object to check
  11364. -- @param tp String of what type it should be
  11365. function utils.is_type (obj,tp)
  11366.     if type(tp) == 'string' then return type(obj) == tp end
  11367.     local mt = getmetatable(obj)
  11368.     return tp == mt
  11369. end
  11370.  
  11371. local fileMT = getmetatable(io.stdout)
  11372.  
  11373. --- a string representation of a type.
  11374. -- For tables with metatables, we assume that the metatable has a `_name`
  11375. -- field. Knows about Lua file objects.
  11376. -- @param obj an object
  11377. -- @return a string like 'number', 'table' or 'List'
  11378. function utils.type (obj)
  11379.     local t = type(obj)
  11380.     if t == 'table' or t == 'userdata' then
  11381.         local mt = getmetatable(obj)
  11382.         if mt == fileMT then
  11383.             return 'file'
  11384.         else
  11385.             return mt._name or "unknown "..t
  11386.         end
  11387.     else
  11388.         return t
  11389.     end
  11390. end
  11391.  
  11392. --- is this number an integer?
  11393. -- @param x a number
  11394. -- @raise error if x is not a number
  11395. function utils.is_integer (x)
  11396.     return math.ceil(x)==x
  11397. end
  11398.  
  11399. utils.stdmt = {
  11400.     List = {_name='List'}, Map = {_name='Map'},
  11401.     Set = {_name='Set'}, MultiMap = {_name='MultiMap'}
  11402. }
  11403.  
  11404. local _function_factories = {}
  11405.  
  11406. --- associate a function factory with a type.
  11407. -- A function factory takes an object of the given type and
  11408. -- returns a function for evaluating it
  11409. -- @param mt metatable
  11410. -- @param fun a callable that returns a function
  11411. function utils.add_function_factory (mt,fun)
  11412.     _function_factories[mt] = fun
  11413. end
  11414.  
  11415. local function _string_lambda(f)
  11416.     local raise = utils.raise
  11417.     if f:find '^|' or f:find '_' then
  11418.         local args,body = f:match '|([^|]*)|(.+)'
  11419.         if f:find '_' then
  11420.             args = '_'
  11421.             body = f
  11422.         else
  11423.             if not args then return raise 'bad string lambda' end
  11424.         end
  11425.         local fstr = 'return function('..args..') return '..body..' end'
  11426.         local fn,err = loadstring(fstr)
  11427.         if not fn then return raise(err) end
  11428.         fn = fn()
  11429.         return fn
  11430.     else return raise 'not a string lambda'
  11431.     end
  11432. end
  11433.  
  11434. --- an anonymous function as a string. This string is either of the form
  11435. -- '|args| expression' or is a function of one argument, '_'
  11436. -- @param lf function as a string
  11437. -- @return a function
  11438. -- @usage string_lambda '|x|x+1' (2) == 3
  11439. -- @usage string_lambda '_+1 (2) == 3
  11440. -- @function utils.string_lambda
  11441. utils.string_lambda = utils.memoize(_string_lambda)
  11442.  
  11443. local ops
  11444.  
  11445. --- process a function argument.
  11446. -- This is used throughout Penlight and defines what is meant by a function:
  11447. -- Something that is callable, or an operator string as defined by <code>pl.operator</code>,
  11448. -- such as '>' or '#'. If a function factory has been registered for the type, it will
  11449. -- be called to get the function.
  11450. -- @param idx argument index
  11451. -- @param f a function, operator string, or callable object
  11452. -- @param msg optional error message
  11453. -- @return a callable
  11454. -- @raise if idx is not a number or if f is not callable
  11455. -- @see utils.is_callable
  11456. function utils.function_arg (idx,f,msg)
  11457.     utils.assert_arg(1,idx,'number')
  11458.     local tp = type(f)
  11459.     if tp == 'function' then return f end  -- no worries!
  11460.     -- ok, a string can correspond to an operator (like '==')
  11461.     if tp == 'string' then
  11462.         if not ops then ops = require 'pl.operator'.optable end
  11463.         local fn = ops[f]
  11464.         if fn then return fn end
  11465.         local fn, err = utils.string_lambda(f)
  11466.         if not fn then error(err..': '..f) end
  11467.         return fn
  11468.     elseif tp == 'table' or tp == 'userdata' then
  11469.         local mt = getmetatable(f)
  11470.         if not mt then error('not a callable object',2) end
  11471.         local ff = _function_factories[mt]
  11472.         if not ff then
  11473.             if not mt.__call then error('not a callable object',2) end
  11474.             return f
  11475.         else
  11476.             return ff(f) -- we have a function factory for this type!
  11477.         end
  11478.     end
  11479.     if not msg then msg = " must be callable" end
  11480.     if idx > 0 then
  11481.         error("argument "..idx..": "..msg,2)
  11482.     else
  11483.         error(msg,2)
  11484.     end
  11485. end
  11486.  
  11487. --- bind the first argument of the function to a value.
  11488. -- @param fn a function of at least two values (may be an operator string)
  11489. -- @param p a value
  11490. -- @return a function such that f(x) is fn(p,x)
  11491. -- @raise same as @{function_arg}
  11492. -- @see pl.func.curry
  11493. function utils.bind1 (fn,p)
  11494.     fn = utils.function_arg(1,fn)
  11495.     return function(...) return fn(p,...) end
  11496. end
  11497.  
  11498. --- bind the second argument of the function to a value.
  11499. -- @param fn a function of at least two values (may be an operator string)
  11500. -- @param p a value
  11501. -- @return a function such that f(x) is fn(x,p)
  11502. -- @raise same as @{function_arg}
  11503. function utils.bind2 (fn,p)
  11504.     fn = utils.function_arg(1,fn)
  11505.     return function(x,...) return fn(x,p,...) end
  11506. end
  11507.  
  11508.  
  11509. --- assert that the given argument is in fact of the correct type.
  11510. -- @param n argument index
  11511. -- @param val the value
  11512. -- @param tp the type
  11513. -- @param verify an optional verfication function
  11514. -- @param msg an optional custom message
  11515. -- @param lev optional stack position for trace, default 2
  11516. -- @raise if the argument n is not the correct type
  11517. -- @usage assert_arg(1,t,'table')
  11518. -- @usage assert_arg(n,val,'string',path.isdir,'not a directory')
  11519. function utils.assert_arg (n,val,tp,verify,msg,lev)
  11520.     if type(val) ~= tp then
  11521.         error(("argument %d expected a '%s', got a '%s'"):format(n,tp,type(val)),lev or 2)
  11522.     end
  11523.     if verify and not verify(val) then
  11524.         error(("argument %d: '%s' %s"):format(n,val,msg),lev or 2)
  11525.     end
  11526. end
  11527.  
  11528. --- assert the common case that the argument is a string.
  11529. -- @param n argument index
  11530. -- @param val a value that must be a string
  11531. -- @raise val must be a string
  11532. function utils.assert_string (n,val)
  11533.     utils.assert_arg(n,val,'string',nil,nil,3)
  11534. end
  11535.  
  11536. local err_mode = 'default'
  11537.  
  11538. --- control the error strategy used by Penlight.
  11539. -- Controls how <code>utils.raise</code> works; the default is for it
  11540. -- to return nil and the error string, but if the mode is 'error' then
  11541. -- it will throw an error. If mode is 'quit' it will immediately terminate
  11542. -- the program.
  11543. -- @param mode - either 'default', 'quit'  or 'error'
  11544. -- @see utils.raise
  11545. function utils.on_error (mode)
  11546.     if ({['default'] = 1, ['quit'] = 2, ['error'] = 3})[mode] then
  11547.       err_mode = mode
  11548.     else
  11549.       -- fail loudly
  11550.       if err_mode == 'default' then err_mode = 'error' end
  11551.       utils.raise("Bad argument expected string; 'default', 'quit', or 'error'. Got '"..tostring(mode).."'")
  11552.     end
  11553. end
  11554.  
  11555. --- used by Penlight functions to return errors.  Its global behaviour is controlled
  11556. -- by <code>utils.on_error</code>
  11557. -- @param err the error string.
  11558. -- @see utils.on_error
  11559. function utils.raise (err)
  11560.     if err_mode == 'default' then return nil,err
  11561.     elseif err_mode == 'quit' then utils.quit(err)
  11562.     else error(err,2)
  11563.     end
  11564. end
  11565.  
  11566. raise = utils.raise
  11567.  
  11568. --- load a code string or bytecode chunk.
  11569. -- @param code Lua code as a string or bytecode
  11570. -- @param name for source errors
  11571. -- @param mode kind of chunk, 't' for text, 'b' for bytecode, 'bt' for all (default)
  11572. -- @param env  the environment for the new chunk (default nil)
  11573. -- @return compiled chunk
  11574. -- @return error message (chunk is nil)
  11575. -- @function utils.load
  11576.  
  11577.  
  11578. --- Lua 5.2 Compatible Functions
  11579. -- @section lua52
  11580.  
  11581. --- pack an argument list into a table.
  11582. -- @param ... any arguments
  11583. -- @return a table with field n set to the length
  11584. -- @return the length
  11585. -- @function table.pack
  11586.  
  11587. ------
  11588. -- return the full path where a Lua module name would be matched.
  11589. -- @param mod module name, possibly dotted
  11590. -- @param path a path in the same form as package.path or package.cpath
  11591. -- @see path.package_path
  11592. -- @function package.searchpath
  11593.  
  11594. return utils
  11595.  
  11596.  
  11597. ]===================],"CoolisOS/bin/utils/search",true,"CoolisOS/bin/utils/search/init.lua",[===================[---filesystem search API by CoolisTheName007
  11598. local fs=fs
  11599. local string=string
  11600. local env=getfenv()
  11601. setmetatable(env,nil)
  11602. --The hard work here was writing the iterators to be efficient; for instance they don't use coroutines or recursion.
  11603.  
  11604. ----DIRECTORY TREE-LIKE SEARCH
  11605.  
  11606. ---iterator over files/dirs in directory dir and with maximum depth of search depth, default is infinite
  11607. --following refer to the iterator returned, not the iterator created.
  11608. --@treturn string path
  11609. function iterTree(dir,depth)
  11610.     dir=dir or ''
  11611.     if dir=='/' then dir='' end
  11612.     local index={0}
  11613.     local dir_index={0}
  11614.     local ts={{dir,fs.list(dir),{}}}
  11615.     local level=1
  11616.     local t_dir
  11617.     return function()
  11618.         repeat
  11619.             index[level]=index[level]+1
  11620.             name=ts[level][2][index[level]]
  11621.             -- pprint(index,name)
  11622.             -- read()
  11623.             if name==nil then
  11624.                 if (not ts[level][4]) and ts[level][3][1] then
  11625.                     ts[level][4]=true
  11626.                     ts[level][2],ts[level][3]=ts[level][3],ts[level][2]
  11627.                     index[level]=0
  11628.                 else
  11629.                     level=level-1
  11630.                     if level==0 then return end
  11631.                     dir=ts[level][1]
  11632.                 end
  11633.             else
  11634.                 t_dir=ts[level][1]..'/'..name
  11635.                 if fs.isDir(t_dir) then
  11636.                     if ts[level][4] then
  11637.                         if depth~=level then
  11638.                             level=level+1
  11639.                             dir=t_dir
  11640.                             ts[level]={dir,fs.list(dir),{}}
  11641.                             index[level]=0
  11642.                             dir_index[level]=0
  11643.                         end
  11644.                     else
  11645.                         dir_index[level]=dir_index[level]+1
  11646.                         ts[level][3][dir_index[level]]=name
  11647.                         break --send dir path
  11648.                     end
  11649.                 else
  11650.                     break
  11651.                 end
  11652.             end
  11653.         until false
  11654.         return dir..'/'..name
  11655.     end
  11656. end
  11657.  
  11658. ---iterator over files in directory dir and with maximum depth of search depth, default is infinite
  11659. --following refer to the iterator returned, not the iterator created.
  11660. --@treturn string path
  11661. function iterFiles(dir,depth)
  11662.     local iter=iterTree(dir,depth)
  11663.     local path
  11664.     return function()
  11665.         repeat
  11666.             path=iter()
  11667.             if path then
  11668.                 if not fs.isDir(path) then
  11669.                     return path
  11670.                 end
  11671.             else
  11672.                 return
  11673.             end
  11674.         until false
  11675.     end
  11676. end
  11677.  
  11678. ---iterator over dirs in directory dir and with maximum depth of search depth, default is infinite
  11679. --following refer to the iterator returned, not the iterator created.
  11680. --@treturn string path
  11681. function iterDir(dir,depth)
  11682.     local iter=iterTree(dir,depth)
  11683.     local path
  11684.     return function()
  11685.         repeat
  11686.             path=iter()
  11687.             if path then
  11688.                 if fs.isDir(path) then
  11689.                     return path
  11690.                 end
  11691.             else
  11692.                 return
  11693.             end
  11694.         until false
  11695.     end
  11696. end
  11697.  
  11698. ------GLOBS
  11699.  
  11700. --WARNING: for compatibility with Lua ?, ? was replaced by # in globs; taken from https://github.com/davidm/lua-glob-pattern , by davidm
  11701. --only needed for filename conversion, slashes are dealt with directly for iteration purposes.
  11702. local function globtopattern(g)
  11703.  
  11704.   local p = "^"  -- pattern being built
  11705.   local i = 0    -- index in g
  11706.   local c        -- char at index i in g.
  11707.  
  11708.  
  11709.     -- unescape glob char
  11710.   local function unescape()
  11711.     if c == '\\' then
  11712.       i = i + 1; c = string.sub(g,i,i)
  11713.       if c == '' then
  11714.         p = '[^]'
  11715.         return false
  11716.       end
  11717.     end
  11718.     return true
  11719.   end
  11720.  
  11721.   -- escape pattern char
  11722.   local function escape(c)
  11723.     return c:match("^%w$") and c or '%' .. c
  11724.   end
  11725.   -- Convert tokens at end of charset.
  11726.   local function charset_end()
  11727.     while 1 do
  11728.       if c == '' then
  11729.         p = '[^]'
  11730.         return false
  11731.       elseif c == ']' then
  11732.         p = p .. ']'
  11733.         break
  11734.       else
  11735.         if not unescape() then break end
  11736.         local c1 = c
  11737.         i = i + 1; c = string.sub(g,i,i)
  11738.         if c == '' then
  11739.           p = '[^]'
  11740.           return false
  11741.         elseif c == '-' then
  11742.           i = i + 1; c = string.sub(g,i,i)
  11743.           if c == '' then
  11744.             p = '[^]'
  11745.             return false
  11746.           elseif c == ']' then
  11747.             p = p .. escape(c1) .. '%-]'
  11748.             break
  11749.           else
  11750.             if not unescape() then break end
  11751.             p = p .. escape(c1) .. '-' .. escape(c)
  11752.           end
  11753.         elseif c == ']' then
  11754.           p = p .. escape(c1) .. ']'
  11755.           break
  11756.         else
  11757.           p = p .. escape(c1)
  11758.           i = i - 1 -- put back
  11759.         end
  11760.       end
  11761.       i = i + 1; c = string.sub(g,i,i)
  11762.     end
  11763.     return true
  11764.   end
  11765.  
  11766.   -- Convert tokens in charset.
  11767.   local function charset()
  11768.     i = i + 1; c = string.sub(g,i,i)
  11769.     if c == '' or c == ']' then
  11770.       p = '[^]'
  11771.       return false
  11772.     elseif c == '^' or c == '!' then
  11773.       i = i + 1; c = string.sub(g,i,i)
  11774.       if c == ']' then
  11775.         -- ignored
  11776.       else
  11777.         p = p .. '[^'
  11778.         if not charset_end() then return false end
  11779.       end
  11780.     else
  11781.       p = p .. '['
  11782.       if not charset_end() then return false end
  11783.     end
  11784.     return true
  11785.   end
  11786.  --Convert tokens.
  11787.   while 1 do
  11788.     i = i + 1; c = string.sub(g,i,i)
  11789.     if c == '' then
  11790.       p = p .. '$'
  11791.       break
  11792.     elseif c == '#' then --?->#
  11793.       p = p .. '.'
  11794.     elseif c == '*' then
  11795.       p = p .. '.*'
  11796.     elseif c == '[' then
  11797.       if not charset() then break end
  11798.     elseif c == '\\' then
  11799.       i = i + 1; c = string.sub(g,i,i)
  11800.       if c == '' then
  11801.         p = p .. '\\$'
  11802.         break
  11803.       end
  11804.       p = p .. escape(c)
  11805.     else
  11806.       p = p .. escape(c)
  11807.     end
  11808.   end
  11809.   return p
  11810. end
  11811.  
  11812. ---turns a glob into a table structure proper for iterPatterns.
  11813. local function compact(g)
  11814.    
  11815.     local nl={}
  11816.     local s1
  11817.     local n=0
  11818.     for c in string.gmatch(g,'[\\/]*([^/\\]+)[\\/]*') do
  11819.         if c:match('^[%w%s%.]*$') then
  11820.             s1=s1 and s1..'/'..c or c
  11821.         else
  11822.             n=n+1
  11823.             nl[n]={s1,globtopattern(c)}
  11824.             s1=nil
  11825.         end
  11826.     end
  11827.    
  11828.     if s1 then
  11829.         if n==0 then
  11830.             n=n+1
  11831.             nl[n]={s1}
  11832.         else
  11833.             nl[n][3]=s1
  11834.         end
  11835.     end
  11836.     return nl
  11837. end
  11838.  
  11839. ---iterator creator over valid paths defined by a table with the structure: {t1,...,tn}, where ti is:
  11840. --for i<n: {dir,pat} - dir is the directory where to look for names matching the pattern pat
  11841. --for i=n: {dir,pat,ending} -same but will combine the name (after successful match with pat) with the optional ending (can be nil) and check the resulting path
  11842. --e.g., g={{'APIS','*'},{nil,'A'},{'B/C','#','aq/qwerty'}} will search in all subfolders of APIS for subfolders named A, and in each of those for a folder B
  11843. --containing a folder C, and for all one-lettered folders in that folder for a folder aq containing a  folder/file named qwerty.
  11844. local function iterPatterns(l)
  11845.     local n=#l
  11846.     if n==0 then return function () return  end end
  11847.     if n==1 and not l[1][2] and fs.exists(l[1][1]) then
  11848.         local done=false
  11849.         return function ()
  11850.                 if not done then
  11851.                     done=true
  11852.                     return l[1][1]
  11853.                 else
  11854.                     return
  11855.                 end
  11856.             end
  11857.     end
  11858.     local dir=l[1][1]
  11859.     local index={0}
  11860.     local ts
  11861.     ts={{dir,fs.isDir(dir) and fs.list(dir) or {}}}
  11862.     local level=1
  11863.     local t_dir
  11864.     local _
  11865.     return function()
  11866.         repeat
  11867.             index[level]=index[level]+1
  11868.             name=ts[level][2][index[level]]
  11869.             if name==nil then
  11870.                     index[level]=nil
  11871.                     level=level-1
  11872.                     if level==0 then return end
  11873.                     dir=ts[level][1]
  11874.             else
  11875.                 if string.match(name,l[level][2]) then
  11876.                     t_dir=dir..'/'..name
  11877.                     if level==n then
  11878.                         _=l[level][3]
  11879.                         if _ then
  11880.                             t_dir=t_dir..'/'.._
  11881.                             if fs.exists(t_dir) then
  11882.                                 path=t_dir
  11883.                                 break
  11884.                             end
  11885.                         else
  11886.                             path=t_dir
  11887.                             break
  11888.                         end
  11889.                     elseif fs.isDir(t_dir) then
  11890.                         level=level+1
  11891.                         _=l[level][1]
  11892.                         if _ then
  11893.                             t_dir=t_dir..'/'.._
  11894.                             if fs.exists(t_dir) then
  11895.                                 dir=t_dir
  11896.                                 ts[level]={dir,fs.list(dir)}
  11897.                                 index[level]=0
  11898.                             else
  11899.                                 level=level-1
  11900.                             end
  11901.                         else
  11902.                             dir=t_dir
  11903.                             ts[level]={dir,fs.list(dir)}
  11904.                             index[level]=0
  11905.                         end
  11906.                     end
  11907.                 end
  11908.             end
  11909.         until false
  11910.         return path, index
  11911.     end
  11912. end
  11913.  
  11914. ---iterator creator, over the valid paths defined by glob @g, e.g */filenumber?to
  11915. -- see the unix part of the table at http://en.wikipedia.org/wiki/Glob_(programming) .
  11916. --@treturn string path to matching of the dir
  11917. --@usage
  11918. --for path in search.iterGlob('*/stuff?/a*') do
  11919. --  print(path)
  11920. --end
  11921. --APIS/stuff1/a.lua
  11922. --var/stuff2/a.var
  11923. function iterGlob(g)
  11924.     return iterPatterns(compact(g))
  11925. end
  11926.  
  11927.  
  11928. --iterator over glob @g with ? replaced by @s
  11929. searchGlob = function (g,s)
  11930.     g=string.gsub(g,'%?',s)
  11931.     local iter=iterGlob(g)
  11932.     local path
  11933.     return function ()
  11934.         repeat
  11935.             path=iter()
  11936.             if path then
  11937.                 if not fs.isDir(path) then 
  11938.                     return path
  11939.                 end
  11940.             else
  11941.                 break
  11942.             end
  11943.         until false
  11944.     end
  11945. end
  11946.  
  11947. function getNameExpansion(s) --returns name and expansion from a filepath @s; special cases: ''->'',nil; '.'-> '','';
  11948.     --s string = filename
  11949.     --returns: name, expansion
  11950.     --Example
  11951.     --print(getNameExpansion('filename.lua.kl'))
  11952.     --filename
  11953.     --lua.kl
  11954.     local _,_,name,expa=string.find(s, '([^%./\\]*)%.(.*)$')
  11955.     return name or s,expa
  11956. end
  11957. function getDir(s) --returns directory from filepath @s
  11958.     return string.match(s,'^(.*)/') or '/'
  11959. end
  11960.  
  11961. --iterator over directory @p searching for @p...@s, where @s is a glob.
  11962. searchTree = function (p,s)
  11963.     if not p:match('%?') and fs.isDir(p) then
  11964.         if p=='/' then p='' end
  11965.         local iter=iterFiles(p)
  11966.         local path
  11967.         return function ()
  11968.             repeat
  11969.                 path=iter()
  11970.                 if path then
  11971.                     if string.match(path,s..'$') and not string.match(path,'[^/]'..s..'$') then
  11972.                         return path
  11973.                     end
  11974.                 else
  11975.                     break
  11976.                 end
  11977.             until false
  11978.         end
  11979.     else
  11980.         return function() end
  11981.     end
  11982. end
  11983.  
  11984. return env]===================],
  11985.     }
  11986.     args={...}
  11987.     if args[1]=='help' or args[1]=='-help' or args[1]=='--help' then
  11988.    
  11989.     else
  11990.         local loc=shell.getRunningProgram()
  11991.         local llen=loc:len()
  11992.         local nlen=fs.getName(loc):len()
  11993.         loc=loc:sub(1,(llen==nlen and 0 or llen-nlen-1))
  11994.         print(args[1])
  11995.         print(loc)
  11996.         local r=args[1] or loc
  11997.         for i=1,#t,2 do
  11998.             p,v=t[i],t[i+1]
  11999.             p=fs.combine(r,p)
  12000.             if i~=1 then
  12001.                 fs.delete(p)
  12002.             end
  12003.             if type(v)=='boolean' then
  12004.                 fs.makeDir(p)
  12005.             else
  12006.                 local f=fs.open(p,'w')
  12007.                 f.write(v)
  12008.                 f.close()
  12009.             end
  12010.         end
  12011.         local r_s=args[2] and r or ''
  12012.         if not fs.exists('startup') then
  12013.             fs.delete(fs.combine(r_s,'startup'))
  12014.             local f=fs.open(fs.combine(r_s,'startup'),'w')
  12015.             f.write(string.format("shell.run('%s')",fs.combine(loc,'CoolisOS/bin/kernel/init.lua')))
  12016.             f.close()
  12017.             print('Running startup')
  12018.             dofile(fs.combine(r_s,'startup'))
  12019.         end
  12020.     end
Advertisement
Add Comment
Please, Sign In to add comment