SHARE
TWEET

oeedPay Registration

Oeed Nov 9th, 2014 314 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --  Hideously Smashed Together by Compilr, a Hideous Smash-Stuff-Togetherer, (c) 2014 oeed  --
  2.  
  3. --  This file REALLLLLLLY isn't suitable to be used for anything other than being executed --
  4.  
  5. --  To extract all the files, run: "<filename> --extract" in the Shell --
  6. local files = {
  7.   cross = "0f  0   0f \
  8.  0 0f  0 0f  0 \
  9.  0  0f  0  \
  10.  0 0f  0 0f  0 \
  11. 0f  0   0f ",
  12.   startup = "-- oeedPay - (c) oeed 2014 --\
  13. \
  14. -- This program is for a payment point such as a shop or ATM --\
  15. \
  16. if OneOS then\
  17.         OneOS.LoadAPI('/System/API/Wireless.lua')\
  18.         OneOS.LoadAPI('/System/API/Peripheral.lua')\
  19. else\
  20.         os.loadAPI('Peripheral')\
  21.         os.loadAPI('Wireless')\
  22. end\
  23. \
  24. os.loadAPI('hash')\
  25. \
  26. local ok = false\
  27. local monitor\
  28. local monitorPeripheral = Peripheral.GetPeripheral('monitor')\
  29. if not monitorPeripheral then\
  30.         print('Please place a single colour monitor next to this computer.')\
  31. else\
  32.         monitor = peripheral.wrap(monitorPeripheral.Side)\
  33.         if not monitor.isColour or not monitor.isColour() then\
  34.                 print('The monitor must be a colour monitor.')\
  35.         else\
  36.                 monitor.setTextScale(0.5)\
  37.                 local w, h = monitor.getSize()\
  38.                 if w ~= 15 or h ~= 10 then\
  39.                         print('Only one monitor is required.')\
  40.                 else\
  41.                         ok = true\
  42.                 end\
  43.         end\
  44. end\
  45. \
  46. if not ok then\
  47.         return\
  48. end\
  49. \
  50. function comma_value(amount)\
  51.  local formatted = amount\
  52.  while true do  \
  53.    formatted, k = string.gsub(formatted, \"^(-?%d+)(%d%d%d)\", '%1,%2')\
  54.    if (k==0) then\
  55.      break\
  56.    end\
  57.  end\
  58.  return formatted\
  59. end\
  60. \
  61. function round(val, decimal)\
  62.  if (decimal) then\
  63.    return math.floor( (val * 10^decimal) + 0.5) / (10^decimal)\
  64.  else\
  65.    return math.floor(val+0.5)\
  66.  end\
  67. end\
  68. \
  69. function formatCurrency(amount, decimal, prefix, neg_prefix)\
  70.  local str_amount,  formatted, famount, remain\
  71.  decimal = decimal or 2  -- default 2 decimal places\
  72.  neg_prefix = neg_prefix or \"-\" -- default negative sign\
  73.  famount = math.abs(round(amount,decimal))\
  74.  famount = math.floor(famount)\
  75. \
  76.  remain = round(math.abs(amount) - famount, decimal)\
  77.  formatted = comma_value(famount)\
  78.  if (decimal > 0) then\
  79.    remain = string.sub(tostring(remain),3)\
  80.    formatted = formatted .. \".\" .. remain ..\
  81.                string.rep(\"0\", decimal - string.len(remain))\
  82.  end\
  83.  formatted = (prefix or \"\") .. formatted \
  84.  if (amount<0) then\
  85.    if (neg_prefix==\"()\") then\
  86.      formatted = \"(\"..formatted ..\")\"\
  87.    else\
  88.      formatted = neg_prefix .. formatted \
  89.    end\
  90.  end\
  91. \
  92.  return formatted\
  93. end\
  94. \
  95. term.redirect(monitor)\
  96. \
  97. local bedrockPath='/' if OneOS then OneOS.LoadAPI('/System/API/Bedrock.lua', false)elseif fs.exists(bedrockPath..'/Bedrock')then os.loadAPI(bedrockPath..'/Bedrock')else if http then print('Downloading Bedrock...')local h=http.get('http://pastebin.com/raw.php?i=0MgKNqpN')if h then local f=fs.open(bedrockPath..'/Bedrock','w')f.write(h.readAll())f.close()h.close()os.loadAPI(bedrockPath..'/Bedrock')else error('Failed to download Bedrock. Is your internet working?') end else error('This program needs to download Bedrock to work. Please enable HTTP.') end end if Bedrock then Bedrock.BasePath = bedrockPath Bedrock.ProgramPath = shell.getRunningProgram() end\
  98. \
  99. local program = Bedrock:Initialise()\
  100. \
  101. local Current = {\
  102.         Payment = {\
  103.                 Value = nil,\
  104.         },\
  105.         Step = nil\
  106. }\
  107. \
  108. program.OnKeyChar = function(self, event, keychar)\
  109.         if keychar == '\\\\' then\
  110.                 os.reboot()\
  111.         end\
  112. end\
  113. \
  114. local modems = {}\
  115. for i, side in ipairs(peripheral.getNames()) do\
  116.         local _type = peripheral.getType(side)\
  117.         if _type == 'modem' then\
  118.                 local isWireless = false\
  119.                 if not pcall(function()isWireless = peripheral.call(side, 'isWireless') end) then\
  120.                         isWireless = true\
  121.                 end     \
  122.                 if not isWireless then\
  123.                         local m = peripheral.wrap(side)\
  124.                         m.open(Wireless.Channels.oeedPayNewAccount)\
  125.                         m.open(Wireless.Channels.oeedPayNewAccountReply)\
  126.                         table.insert(modems, m)\
  127.                 end\
  128.         end\
  129. end\
  130. \
  131. local function transmit(channel, reply, message)\
  132.         for i, m in ipairs(modems) do\
  133.                 m.transmit(channel, reply, message)\
  134.         end\
  135. end\
  136. \
  137. local diskSide\
  138. local account\
  139. local failReason\
  140. local onDisk\
  141. local oldAccount\
  142. \
  143. function writeAccount()\
  144.         if disk.hasData(diskSide) and disk.isPresent(diskSide) then\
  145.                 local f = fs.open(disk.getMountPath(diskSide)..'/.Account.settings', 'w')\
  146.                 if f then\
  147.                         f.write(textutils.serialize(account))\
  148.                         f.close()\
  149.                         local h = http.get('http://pastebin.com/raw.php?i=JygZN1MU')\
  150.                         if h then\
  151.                                 local f2 = fs.open(disk.getMountPath(diskSide)..'/startup', 'w')\
  152.                                 if f2 then\
  153.                                         f2.write(h.readAll())\
  154.                                         h.close()\
  155.                                         f2.close()\
  156.                                         disk.setLabel(diskSide, account.Name..\"'s DiskPay: \"..account.Number)\
  157.                                         program:LoadView('complete')\
  158.                                 else\
  159.                                         failReason = 'Startup Write'\
  160.                                         program:LoadView('fail')\
  161.                                 end\
  162.                         else\
  163.                                 failReason = 'HTTP Error'\
  164.                                 program:LoadView('fail')\
  165.                         end\
  166.                 else\
  167.                         failReason = 'Account Write'\
  168.                         program:LoadView('fail')\
  169.                 end\
  170.         else\
  171.                 program:LoadView('fail')\
  172.                 failReason = 'No Disk'\
  173.         end\
  174.         disk.eject(diskSide)\
  175. end\
  176. \
  177. program:RegisterEvent('modem_message', function(self, event, side, channel, replyChannel, message, distance)\
  178.         if channel == Wireless.Channels.oeedPayNewAccountReply and Current.Step == 'processing' and diskSide then\
  179.                 local _account = textutils.unserialize(message)\
  180.                 if _account.Name == account.Name then\
  181.                         account = _account\
  182.                         writeAccount()\
  183.                 end\
  184.         end\
  185. end)\
  186. \
  187. program:RegisterEvent('disk', function(self, event, side)\
  188.         if onDisk then\
  189.                 if disk.hasData(side) then\
  190.                         diskSide = side\
  191.                         onDisk()\
  192.                 end\
  193.         end\
  194. end)\
  195. \
  196. function detectDisk()\
  197.         local drives = Peripheral.GetPeripherals('drive')\
  198.         for i, v in ipairs(drives) do\
  199.                 if disk.hasData(v.Side) then\
  200.                         diskSide = v.Side\
  201.                         onDisk()\
  202.                         break\
  203.                 end\
  204.         end\
  205. end\
  206. \
  207. function requestAccount()\
  208.         program:LoadView('processing')\
  209.         transmit(Wireless.Channels.oeedPayNewAccount, Wireless.Channels.oeedPayNewAccountReply, account.Name)\
  210. end\
  211. \
  212. program.OnViewLoad = function(viewName)\
  213.         Current.Step = viewName\
  214.         if viewName == 'main' then\
  215.                 account = nil\
  216.                 oldAccount = nil\
  217.                 onDisk = nil\
  218.                 failReason = nil\
  219.                 program:GetObject('NewAccountButton').OnClick = function(self, event, side, x, y)\
  220.                         program:LoadView('name')\
  221.                 end\
  222.                 program:GetObject('NewCardButton').OnClick = function(self, event, side, x, y)\
  223.                         program:LoadView('insertold')\
  224.                 end\
  225.         elseif viewName == 'name' then\
  226.                 program:GetObject('KeyboardView').OnDone = function()\
  227.                         if #program:GetObject('TextBox').Text ~= '' then\
  228.                                 account = {\
  229.                                         Name = program:GetObject('TextBox').Text\
  230.                                 }\
  231.                                 program:LoadView('insertnew')\
  232.                         end\
  233.                 end\
  234. \
  235.                 program:SetActiveObject(program:GetObject('TextBox'))\
  236.         elseif viewName == 'processing' then\
  237.                 local cols ={\
  238.                         colours.lightBlue,\
  239.                         colours.white,\
  240.                         colours.white,\
  241.                         colours.white,\
  242.                         colours.lightBlue,\
  243.                         colours.blue,\
  244.                 }\
  245.                 local i = 1\
  246.                 program:StartRepeatingTimer(function()\
  247.                         if Current.Step ~= 'processing' then\
  248.                                 program:StopTimer(new)\
  249.                         else\
  250.                                 i = i + 1\
  251.                                 if i > #cols then\
  252.                                         i = 1\
  253.                                 end\
  254.                                 program:GetObject('ProcessingLabel').TextColour = cols[i]\
  255.                         end\
  256.                 end, 0.15)\
  257.         elseif viewName == 'insertnew' then\
  258.                 if not oldAccount then\
  259.                         onDisk = requestAccount\
  260.                 else\
  261.                         onDisk = function()\
  262.                                 account = oldAccount\
  263.                                 writeAccount()\
  264.                         end\
  265.                 end\
  266.                 detectDisk()\
  267.         elseif viewName == 'insertold' then\
  268.                 onDisk = function()\
  269.                         if disk.hasData(diskSide) and disk.isPresent(diskSide) then\
  270.                                 local f = fs.open(disk.getMountPath(diskSide)..'/.Account.settings', 'r')\
  271.                                 if f then\
  272.                                         oldAccount = textutils.unserialize(f.readAll())\
  273.                                         f.close()\
  274.                                         fs.delete(disk.getMountPath(diskSide)..'/.Account.settings')\
  275.                                         fs.delete(disk.getMountPath(diskSide)..'/startup')\
  276.                                         disk.setLabel(diskSide, nil)\
  277.                                         sleep(1)\
  278.                                         disk.eject(diskSide)\
  279.                                         sleep(0.5)\
  280.                                         diskSide = nil\
  281.                                         program:LoadView('insertnew')\
  282.                                 else\
  283.                                         failReason = 'Write Failed'\
  284.                                         program:LoadView('fail')\
  285.                                 end\
  286.                         else\
  287.                                 failReason = 'Invalid Disk'\
  288.                                 program:LoadView('fail')\
  289.                         end\
  290.                 end\
  291.                 detectDisk()\
  292.         elseif viewName == 'fail' or viewName == 'complete' then\
  293.                 if diskSide then\
  294.                         disk.eject(diskSide)\
  295.                 end\
  296.                 \
  297.                 if viewName == 'fail' then\
  298.                         program:GetObject('ReasonLabel').Text = failReason or ''\
  299.                 end\
  300. \
  301.                 program:StartTimer(function()\
  302.                         program:LoadView('main')\
  303.                 end, 3)\
  304.         end\
  305. end\
  306. \
  307. program:Run(function()\
  308.         -- Current.Payment = {\
  309.         --      Value = 42.5\
  310.         -- }\
  311.         -- program:LoadView('insertold')\
  312.         -- program:LoadView('name')\
  313.         -- paymentDue(42.5)\
  314. end)",
  315.   tick = " d      0f \
  316.  d     0f  d \
  317. 0f  d   0f  d  \
  318.  d 0f  d 0f  d   \
  319.  d  0f  d    ",
  320.   Bedrock = "--Bedrock Build: 270\
  321. --This code is squished down in to one, rather hard to read file.\
  322. --As such it is not much good for anything other than being loaded as an API.\
  323. --If you want to look at the code to learn from it, copy parts or just take a look,\
  324. --you should go to the GitHub repo. http://github.com/oeed/Bedrock/\
  325. \
  326. --\
  327. --              Bedrock is the core program framework used by all OneOS and OneCode programs.\
  328. --                                                      Inspired by Apple's Cocoa framework.\
  329. --                                                                         (c) oeed 2014\
  330. --\
  331. --                For documentation see the Bedrock wiki, github.com/oeed/Bedrock/wiki/\
  332. --\
  333. \
  334. local apis = {\
  335. [\"Drawing\"] = [[\
  336. local round = function(num, idp)\
  337.         local mult = 10^(idp or 0)\
  338.         return math.floor(num * mult + 0.5) / mult\
  339. end\
  340. \
  341. local _w, _h = term.getSize()\
  342. local copyBuffer = nil\
  343. \
  344. Screen = {\
  345.         Width = _w,\
  346.         Height = _h\
  347. }\
  348. \
  349. Constraints = {\
  350.         \
  351. }\
  352. \
  353. CurrentConstraint = {1,1,_w,_h}\
  354. IgnoreConstraint = false\
  355. \
  356. function AddConstraint(x, y, width, height)\
  357.         local x2 = x + width - 1\
  358.         local y2 = y + height - 1\
  359.         table.insert(Drawing.Constraints, {x, y, x2, y2})\
  360.         Drawing.GetConstraint()\
  361. end\
  362. \
  363. function RemoveConstraint()\
  364.         --table.remove(Drawing.Constraints, #Drawing.Constraints)\
  365.         Drawing.Constraints[#Drawing.Constraints] = nil\
  366.         Drawing.GetConstraint()\
  367. end\
  368. \
  369. function GetConstraint()\
  370.         local x = 1\
  371.         local y = 1\
  372.         local x2 = Drawing.Screen.Width\
  373.         local y2 = Drawing.Screen.Height\
  374.         for i, c in ipairs(Drawing.Constraints) do\
  375.                 if x < c[1] then\
  376.                         x = c[1]\
  377.                 end\
  378.                 if y < c[2] then\
  379.                         y = c[2]\
  380.                 end\
  381.                 if x2 > c[3] then\
  382.                         x2 = c[3]\
  383.                 end\
  384.                 if y2 > c[4] then\
  385.                         y2 = c[4]\
  386.                 end\
  387.         end\
  388.         Drawing.CurrentConstraint = {x, y, x2, y2}\
  389. end\
  390. \
  391. function WithinContraint(x, y)\
  392.         return Drawing.IgnoreConstraint or\
  393.                   (x >= Drawing.CurrentConstraint[1] and\
  394.                    y >= Drawing.CurrentConstraint[2] and\
  395.                    x <= Drawing.CurrentConstraint[3] and\
  396.                    y <= Drawing.CurrentConstraint[4])\
  397. end\
  398. \
  399. colours.transparent = 0\
  400. colors.transparent = 0\
  401. \
  402. DrawCharacters = function (x, y, characters, textColour, bgColour)\
  403.         Drawing.WriteStringToBuffer(x, y, tostring(characters), textColour, bgColour)\
  404. end\
  405. \
  406. DrawBlankArea = function (x, y, w, h, colour)\
  407.         if colour ~= colours.transparent then\
  408.                 Drawing.DrawArea (x, y, w, h, \" \", 1, colour)\
  409.         end\
  410. end\
  411. \
  412. DrawArea = function (x, y, w, h, character, textColour, bgColour)\
  413.         --width must be greater than 1, otherwise we get problems\
  414.         if w < 0 then\
  415.                 w = w * -1\
  416.         elseif w == 0 then\
  417.                 w = 1\
  418.         end\
  419. \
  420.         for ix = 1, w do\
  421.                 local currX = x + ix - 1\
  422.                 for iy = 1, h do\
  423.                         local currY = y + iy - 1\
  424.                         Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour)\
  425.                 end\
  426.         end\
  427. end\
  428. \
  429. DrawImage = function(_x,_y,tImage, w, h)\
  430.         if tImage then\
  431.                 for y = 1, h do\
  432.                         if not tImage[y] then\
  433.                                 break\
  434.                         end\
  435.                         for x = 1, w do\
  436.                                 if not tImage[y][x] then\
  437.                                         break\
  438.                                 end\
  439.                                 local bgColour = tImage[y][x]\
  440.                     local textColour = tImage.textcol[y][x] or colours.white\
  441.                     local char = tImage.text[y][x]\
  442.                     Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour)\
  443.                         end\
  444.                 end\
  445.         elseif w and h then\
  446.                 Drawing.DrawBlankArea(_x, _y, w, h, colours.lightGrey)\
  447.         end\
  448. end\
  449. \
  450. --using .nft\
  451. LoadImage = function(path, global)\
  452.         local image = {\
  453.                 text = {},\
  454.                 textcol = {}\
  455.         }\
  456.         if fs.exists(path) then\
  457.                 local _io = io\
  458.                 if OneOS and global then\
  459.                         _io = OneOS.IO\
  460.                 end\
  461.        local file = _io.open(path, \"r\")\
  462.        if not file then\
  463.                 error('Error Occured. _io:'..tostring(_io)..' OneOS: '..tostring(OneOS)..' OneOS.IO'..tostring(OneOS.IO)..' io: '..tostring(io))\
  464.        end\
  465.        local sLine = file:read()\
  466.        local num = 1\
  467.        while sLine do  \
  468.            table.insert(image, num, {})\
  469.            table.insert(image.text, num, {})\
  470.            table.insert(image.textcol, num, {})\
  471.                                        \
  472.            --As we're no longer 1-1, we keep track of what index to write to\
  473.            local writeIndex = 1\
  474.            --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour\
  475.            local bgNext, fgNext = false, false\
  476.            --The current background and foreground colours\
  477.            local currBG, currFG = nil,nil\
  478.            for i=1,#sLine do\
  479.                    local nextChar = string.sub(sLine, i, i)\
  480.                    if nextChar:byte() == 30 then\
  481.                            bgNext = true\
  482.                    elseif nextChar:byte() == 31 then\
  483.                            fgNext = true\
  484.                    elseif bgNext then\
  485.                            currBG = Drawing.GetColour(nextChar)\
  486.                                     if currBG == nil then\
  487.                                         currBG = colours.transparent\
  488.                                     end\
  489.                            bgNext = false\
  490.                    elseif fgNext then\
  491.                            currFG = Drawing.GetColour(nextChar)\
  492.                                     if currFG == nil or currFG == colours.transparent then\
  493.                                         currFG = colours.white\
  494.                                     end\
  495.                            fgNext = false\
  496.                    else\
  497.                            if nextChar ~= \" \" and currFG == nil then\
  498.                                    currFG = colours.white\
  499.                            end\
  500.                            image[num][writeIndex] = currBG\
  501.                            image.textcol[num][writeIndex] = currFG\
  502.                            image.text[num][writeIndex] = nextChar\
  503.                            writeIndex = writeIndex + 1\
  504.                    end\
  505.            end\
  506.            num = num+1\
  507.            sLine = file:read()\
  508.        end\
  509.        file:close()\
  510.    else\
  511.         return nil\
  512.         end\
  513.         return image\
  514. end\
  515. \
  516. DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)\
  517.         w = w or Drawing.Screen.Width\
  518.         h = h or Drawing.Screen.Height\
  519.         x = x or 0\
  520.         y = y or 0\
  521.         x = math.floor((w - #characters) / 2) + x\
  522.         y = math.floor(h / 2) + y\
  523. \
  524.         Drawing.DrawCharacters(x, y, characters, textColour, bgColour)\
  525. end\
  526. \
  527. GetColour = function(hex)\
  528.         if hex == ' ' then\
  529.                 return colours.transparent\
  530.         end\
  531.    local value = tonumber(hex, 16)\
  532.    if not value then return nil end\
  533.    value = math.pow(2,value)\
  534.    return value\
  535. end\
  536. \
  537. Clear = function (_colour)\
  538.         _colour = _colour or colours.black\
  539.         Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour)\
  540. end\
  541. \
  542. Buffer = {}\
  543. BackBuffer = {}\
  544. \
  545. TryRestore = false\
  546. \
  547. \
  548. --TODO: make this quicker\
  549. -- maybe sort the pixels in order of colour so it doesn't have to set the colour each time\
  550. DrawBuffer = function()\
  551.         if TryRestore and Restore then\
  552.                 Restore()\
  553.         end\
  554. \
  555.         for y,row in pairs(Drawing.Buffer) do\
  556.                 for x,pixel in pairs(row) do\
  557.                         local shouldDraw = true\
  558.                         local hasBackBuffer = true\
  559.                         if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then\
  560.                                 hasBackBuffer = false\
  561.                         end\
  562.                         if hasBackBuffer and Drawing.BackBuffer[y][x][1] == Drawing.Buffer[y][x][1] and Drawing.BackBuffer[y][x][2] == Drawing.Buffer[y][x][2] and Drawing.BackBuffer[y][x][3] == Drawing.Buffer[y][x][3] then\
  563.                                 shouldDraw = false\
  564.                         end\
  565.                         if shouldDraw then\
  566.                                 term.setBackgroundColour(pixel[3])\
  567.                                 term.setTextColour(pixel[2])\
  568.                                 term.setCursorPos(x, y)\
  569.                                 term.write(pixel[1])\
  570.                         end\
  571.                 end\
  572.         end\
  573.         Drawing.BackBuffer = Drawing.Buffer\
  574.         Drawing.Buffer = {}\
  575. end\
  576. \
  577. ClearBuffer = function()\
  578.         Drawing.Buffer = {}\
  579. end\
  580. \
  581. WriteStringToBuffer = function (x, y, characters, textColour,bgColour)\
  582.         for i = 1, #characters do\
  583.                 local character = characters:sub(i,i)\
  584.                 Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)\
  585.         end\
  586. end\
  587. \
  588. WriteToBuffer = function(x, y, character, textColour,bgColour, cached)\
  589.         if not cached and not Drawing.WithinContraint(x, y) then\
  590.                 return\
  591.         end\
  592.         x = round(x)\
  593.         y = round(y)\
  594. \
  595.         if textColour == colours.transparent then\
  596.                 character = ' '\
  597.         end\
  598. \
  599.         if bgColour == colours.transparent then\
  600.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}\
  601.                 Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {\"\", colours.white, colours.black}\
  602.                 Drawing.Buffer[y][x][1] = character\
  603.                 Drawing.Buffer[y][x][2] = textColour\
  604.         else\
  605.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}\
  606.                 Drawing.Buffer[y][x] = {character, textColour, bgColour}\
  607.         end\
  608. \
  609.         if copyBuffer then\
  610.                 copyBuffer[y] = copyBuffer[y] or {}\
  611.                 copyBuffer[y][x] = {character, textColour, bgColour}            \
  612.         end\
  613. end\
  614. \
  615. DrawCachedBuffer = function(buffer)\
  616.         for y, row in pairs(buffer) do\
  617.                 for x, pixel in pairs(row) do\
  618.                         WriteToBuffer(x, y, pixel[1], pixel[2], pixel[3], true)\
  619.                 end\
  620.         end\
  621. end\
  622. \
  623. StartCopyBuffer = function()\
  624.         copyBuffer = {}\
  625. end\
  626. \
  627. EndCopyBuffer = function()\
  628.         local tmpCopy = copyBuffer\
  629.         copyBuffer = nil\
  630.         return tmpCopy\
  631. end\
  632. ]],\
  633. [\"Helpers\"] = [[\
  634. LongestString = function(input, key, isKey)\
  635.         local length = 0\
  636.         if isKey then\
  637.                 for k, v in pairs(input) do\
  638.                         local titleLength = string.len(k)\
  639.                         if titleLength > length then\
  640.                                 length = titleLength\
  641.                         end\
  642.                 end\
  643.         else\
  644.                 for i = 1, #input do\
  645.                         local value = input[i]\
  646.                         if key then\
  647.                                 if value[key] then\
  648.                                         value = value[key]\
  649.                                 else\
  650.                                         value = ''\
  651.                                 end\
  652.                         end\
  653.                         local titleLength = string.len(value)\
  654.                         if titleLength > length then\
  655.                                 length = titleLength\
  656.                         end\
  657.                 end\
  658.         end\
  659.         return length\
  660. end\
  661. \
  662. Split = function(str,sep)\
  663.    sep=sep or'/'\
  664.    return str:match(\"(.*\"..sep..\")\")\
  665. end\
  666. \
  667. Extension = function(path, addDot)\
  668.         if not path then\
  669.                 return nil\
  670.         elseif not string.find(fs.getName(path), '%.') then\
  671.                 if not addDot then\
  672.                         return fs.getName(path)\
  673.                 else\
  674.                         return ''\
  675.                 end\
  676.         else\
  677.                 local _path = path\
  678.                 if path:sub(#path) == '/' then\
  679.                         _path = path:sub(1,#path-1)\
  680.                 end\
  681.                 local extension = _path:gmatch('%.[0-9a-z]+$')()\
  682.                 if extension then\
  683.                         extension = extension:sub(2)\
  684.                 else\
  685.                         --extension = nil\
  686.                         return ''\
  687.                 end\
  688.                 if addDot then\
  689.                         extension = '.'..extension\
  690.                 end\
  691.                 return extension:lower()\
  692.         end\
  693. end\
  694. \
  695. RemoveExtension = function(path)\
  696. --local name = string.match(fs.getName(path), '(%a+)%.?.-')\
  697.         if path:sub(1,1) == '.' then\
  698.                 return path\
  699.         end\
  700.         local extension = Helpers.Extension(path)\
  701.         if extension == path then\
  702.                 return fs.getName(path)\
  703.         end\
  704.         return string.gsub(path, extension, ''):sub(1, -2)\
  705. end\
  706. \
  707. RemoveFileName = function(path)\
  708.         if string.sub(path, -1) == '/' then\
  709.                 path = string.sub(path, 1, -2)\
  710.         end\
  711.         local v = string.match(path, \"(.-)([^\\\\/]-%.?([^%.\\\\/]*))$\")\
  712.         if type(v) == 'string' then\
  713.                 return v\
  714.         end\
  715.         return v[1]\
  716. end\
  717. \
  718. TruncateString = function(sString, maxLength)\
  719.         if #sString > maxLength then\
  720.                 sString = sString:sub(1,maxLength-3)\
  721.                 if sString:sub(-1) == ' ' then\
  722.                         sString = sString:sub(1,maxLength-4)\
  723.                 end\
  724.                 sString = sString  .. '...'\
  725.         end\
  726.         return sString\
  727. end\
  728. \
  729. TruncateStringStart = function(sString, maxLength)\
  730.         local len = #sString\
  731.         if #sString > maxLength then\
  732.                 sString = sString:sub(len - maxLength, len - 3)\
  733.                 if sString:sub(-1) == ' ' then\
  734.                         sString = sString:sub(len - maxLength, len - 4)\
  735.                 end\
  736.                 sString = '...' .. sString\
  737.         end\
  738.         return sString\
  739. end\
  740. \
  741. WrapText = function(text, maxWidth)\
  742.         local lines = {''}\
  743.    for word, space in text:gmatch('(%S+)(%s*)') do\
  744.            local temp = lines[#lines] .. word .. space:gsub('\\n','')\
  745.            if #temp > maxWidth then\
  746.                    table.insert(lines, '')\
  747.            end\
  748.            if space:find('\\n') then\
  749.                    lines[#lines] = lines[#lines] .. word\
  750.                    \
  751.                    space = space:gsub('\\n', function()\
  752.                            table.insert(lines, '')\
  753.                            return ''\
  754.                    end)\
  755.            else\
  756.                    lines[#lines] = lines[#lines] .. word .. space\
  757.            end\
  758.    end\
  759.         return lines\
  760. end\
  761. \
  762. TidyPath = function(path)\
  763.         path = '/'..path\
  764.         if fs.exists(path) and fs.isDir(path) then\
  765.                 path = path .. '/'\
  766.         end\
  767. \
  768.         path, n = path:gsub(\"//\", \"/\")\
  769.         while n > 0 do\
  770.                 path, n = path:gsub(\"//\", \"/\")\
  771.         end\
  772.         return path\
  773. end\
  774. \
  775. Capitalise = function(str)\
  776.         return str:sub(1, 1):upper() .. str:sub(2, -1)\
  777. end\
  778. \
  779. Round = function(num, idp)\
  780.         local mult = 10^(idp or 0)\
  781.         return math.floor(num * mult + 0.5) / mult\
  782. end\
  783. ]],\
  784. [\"Object\"] = [[\
  785. X = 1\
  786. Y = 1\
  787. Width = 1\
  788. Height = 1\
  789. Parent = nil\
  790. OnClick = nil\
  791. Visible = true\
  792. IgnoreClick = false\
  793. Name = nil \
  794. ClipDrawing = true\
  795. UpdateDrawBlacklist = {}\
  796. Fixed = false\
  797. \
  798. DrawCache = {}\
  799. \
  800. NeedsDraw = function(self)\
  801.         if not self.Visible then\
  802.                 return false\
  803.         end\
  804.         \
  805.         if not self.DrawCache.Buffer or self.DrawCache.AlwaysDraw or self.DrawCache.NeedsDraw then\
  806.                 return true\
  807.         end\
  808. \
  809.         if self.OnNeedsUpdate then\
  810.                 if self.OnNeedsUpdate() then\
  811.                         return true\
  812.                 end\
  813.         end\
  814. \
  815.         if self.Children then\
  816.                 for i, v in ipairs(self.Children) do\
  817.                         if v:NeedsDraw() then\
  818.                                 return true\
  819.                         end\
  820.                 end\
  821.         end\
  822. end\
  823. \
  824. GetPosition = function(self)\
  825.         return self.Bedrock:GetAbsolutePosition(self)\
  826. end\
  827. \
  828. GetOffsetPosition = function(self)\
  829.         if not self.Parent then\
  830.                 return {X = 1, Y = 1}\
  831.         end\
  832. \
  833.         local offset = {X = 0, Y = 0}\
  834.         if not self.Fixed and self.Parent.ChildOffset then\
  835.                 offset = self.Parent.ChildOffset\
  836.         end\
  837. \
  838.         return {X = self.X + offset.X, Y = self.Y + offset.Y}\
  839. end\
  840. \
  841. Draw = function(self)\
  842.         if not self.Visible then\
  843.                 return\
  844.         end\
  845. \
  846.         self.DrawCache.NeedsDraw = false\
  847.         local pos = self:GetPosition()\
  848.         Drawing.StartCopyBuffer()\
  849. \
  850.         if self.ClipDrawing then\
  851.                 Drawing.AddConstraint(pos.X, pos.Y, self.Width, self.Height)\
  852.         end\
  853. \
  854.         if self.OnDraw then\
  855.                 self:OnDraw(pos.X, pos.Y)\
  856.         end\
  857. \
  858.         self.DrawCache.Buffer = Drawing.EndCopyBuffer()\
  859.         \
  860.         if self.Children then\
  861.                 for i, child in ipairs(self.Children) do\
  862.                         local pos = child:GetOffsetPosition()\
  863.                         if pos.Y + self.Height > 1 and pos.Y <= self.Height and pos.X + self.Width > 1 and pos.X <= self.Width then\
  864.                                 child:Draw()\
  865.                         end\
  866.                 end\
  867.         end\
  868. \
  869.         if self.ClipDrawing then\
  870.                 Drawing.RemoveConstraint()\
  871.         end     \
  872. end\
  873. \
  874. ForceDraw = function(self, ignoreChildren, ignoreParent, ignoreBedrock)\
  875.         if not ignoreBedrock and self.Bedrock then\
  876.                 self.Bedrock:ForceDraw()\
  877.         end\
  878.         self.DrawCache.NeedsDraw = true\
  879.         if not ignoreParent and self.Parent then\
  880.                 self.Parent:ForceDraw(true, nil, true)\
  881.         end\
  882.         if not ignoreChildren and self.Children then\
  883.                 for i, child in ipairs(self.Children) do\
  884.                         child:ForceDraw(nil, true, true)\
  885.                 end\
  886.         end\
  887. end\
  888. \
  889. OnRemove = function(self)\
  890.         if self == self.Bedrock:GetActiveObject() then\
  891.                 self.Bedrock:SetActiveObject()\
  892.         end\
  893. end\
  894. \
  895. local function ParseColour(value)\
  896.         if type(value) == 'string' then\
  897.                 if colours[value] and type(colours[value]) == 'number' then\
  898.                         return colours[value]\
  899.                 elseif colors[value] and type(colors[value]) == 'number' then\
  900.                         return colors[value]\
  901.                 end\
  902.         elseif type(value) == 'number' and (value == colours.transparent or (value >= colours.white and value <= colours.black)) then\
  903.                 return value\
  904.         end\
  905.         error('Invalid colour: \"'..tostring(value)..'\"')\
  906. end\
  907. \
  908. Initialise = function(self, values)\
  909.         local _new = values    -- the new instance\
  910.         _new.DrawCache = {\
  911.                 NeedsDraw = true,\
  912.                 AlwaysDraw = false,\
  913.                 Buffer = nil\
  914.         }\
  915.         setmetatable(_new, {__index = self} )\
  916. \
  917.         local new = {} -- the proxy\
  918.         setmetatable(new, {\
  919.                 __index = function(t, k)\
  920.                         if k:find('Color') then\
  921.                                 k = k:gsub('Color', 'Colour')\
  922.                         end\
  923. \
  924.                         if k:find('Colour') and type(_new[k]) ~= 'table' then\
  925.                                 if _new[k] then\
  926.                                         return ParseColour(_new[k])\
  927.                                 end\
  928.                         elseif _new[k] ~= nil then\
  929.                                 return _new[k]\
  930.                         end\
  931.                 end,\
  932. \
  933.                 __newindex = function (t,k,v)\
  934.                         if k:find('Color') then\
  935.                                 k = k:gsub('Color', 'Colour')\
  936.                         end\
  937. \
  938.                         if k == 'Width' or k == 'X' or k == 'Height' or k == 'Y' then\
  939.                                 v = new.Bedrock:ParseStringSize(new.Parent, k, v)\
  940.                         end\
  941. \
  942.                         if v ~= _new[k] then\
  943.                                 _new[k] = v\
  944.                                 if t.OnUpdate then\
  945.                                         t:OnUpdate(k)\
  946.                                 end\
  947. \
  948.                                 if t.UpdateDrawBlacklist[k] == nil then\
  949.                                         t:ForceDraw()\
  950.                                 end\
  951.                         end\
  952.                 end\
  953.         })\
  954.         if new.OnInitialise then\
  955.                 new:OnInitialise()\
  956.         end\
  957. \
  958.         return new\
  959. end\
  960. \
  961. Click = function(self, event, side, x, y)\
  962.         if self.Visible and not self.IgnoreClick then\
  963.                 if event == 'mouse_click' and self.OnClick and self:OnClick(event, side, x, y) ~= false then\
  964.                         return true\
  965.                 elseif event == 'mouse_drag' and self.OnDrag and self:OnDrag(event, side, x, y) ~= false then\
  966.                         return true\
  967.                 elseif event == 'mouse_scroll' and self.OnScroll and self:OnScroll(event, side, x, y) ~= false then\
  968.                         return true\
  969.                 else\
  970.                         return false\
  971.                 end\
  972.         else\
  973.                 return false\
  974.         end\
  975. \
  976. end\
  977. \
  978. ToggleMenu = function(self, name, x, y)\
  979.         return self.Bedrock:ToggleMenu(name, self, x, y)\
  980. end\
  981. \
  982. function OnUpdate(self, value)\
  983.         if value == 'Z' then\
  984.                 self.Bedrock:ReorderObjects()\
  985.         end\
  986. end\
  987. ]],\
  988. }\
  989. local objects = {\
  990. [\"Button\"] = [[\
  991. BackgroundColour = colours.lightGrey\
  992. ActiveBackgroundColour = colours.blue\
  993. ActiveTextColour = colours.white\
  994. TextColour = colours.black\
  995. DisabledTextColour = colours.lightGrey\
  996. Text = \"\"\
  997. Toggle = nil\
  998. Momentary = true\
  999. AutoWidthAutoWidth = true\
  1000. Align = 'Center'\
  1001. Enabled = true\
  1002. \
  1003. OnUpdate = function(self, value)\
  1004.         if value == 'Text' and self.AutoWidth then\
  1005.                 self.Width = #self.Text + 2\
  1006.         end\
  1007. end\
  1008. \
  1009. OnDraw = function(self, x, y)\
  1010.         local bg = self.BackgroundColour\
  1011. \
  1012.         if self.Toggle then\
  1013.                 bg = self.ActiveBackgroundColour\
  1014.         end\
  1015. \
  1016.         local txt = self.TextColour\
  1017.         if self.Toggle then\
  1018.                 txt = self.ActiveTextColour\
  1019.         end\
  1020.         if not self.Enabled then\
  1021.                 txt = self.DisabledTextColour\
  1022.         end\
  1023.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, bg)\
  1024. \
  1025.         local _x = 1\
  1026.    if self.Align == 'Right' then\
  1027.        _x = self.Width - #self.Text - 1\
  1028.    elseif self.Align == 'Center' then\
  1029.        _x = math.floor((self.Width - #self.Text) / 2)\
  1030.    end\
  1031. \
  1032. \
  1033.         Drawing.DrawCharacters(x + _x, y-1+math.ceil(self.Height/2), self.Text, txt, bg)\
  1034. end\
  1035. \
  1036. OnLoad = function(self)\
  1037.         if self.Toggle ~= nil then\
  1038.                 self.Momentary = false\
  1039.         end\
  1040. end\
  1041. \
  1042. Click = function(self, event, side, x, y)\
  1043.         if self.Visible and not self.IgnoreClick and self.Enabled and event ~= 'mouse_scroll' then\
  1044.                 if self.OnClick then\
  1045.                         if self.Momentary then\
  1046.                                 self.Toggle = true\
  1047.                                 self.Bedrock:StartTimer(function()self.Toggle = false end,0.25)\
  1048.                         elseif self.Toggle ~= nil then\
  1049.                                 self.Toggle = not self.Toggle\
  1050.                         end\
  1051. \
  1052.                         self:OnClick(event, side, x, y, self.Toggle)\
  1053.                 else\
  1054.                         self.Toggle = not self.Toggle\
  1055.                 end\
  1056.                 return true\
  1057.         else\
  1058.                 return false\
  1059.         end\
  1060. end\
  1061. ]],\
  1062. [\"CollectionView\"] = [[\
  1063. Inherit = 'ScrollView'\
  1064. UpdateDrawBlacklist = {['NeedsItemUpdate']=true}\
  1065. \
  1066. TextColour = colours.black\
  1067. BackgroundColour = colours.white\
  1068. Items = false\
  1069. NeedsItemUpdate = false\
  1070. SpacingX = 2\
  1071. SpacingY = 1\
  1072. \
  1073. OnDraw = function(self, x, y)\
  1074.         if self.NeedsItemUpdate then\
  1075.                 self:UpdateItems()\
  1076.                 self.NeedsItemUpdate = false\
  1077.         end\
  1078.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1079. end\
  1080. \
  1081. local function MaxIcons(self, obj)\
  1082.         local x, y = 2, 1\
  1083.         if not obj.Height or not obj.Width then\
  1084.                 error('You must provide each object\\'s height when adding to a CollectionView.')\
  1085.         end\
  1086.         local slotHeight = obj.Height + self.SpacingY\
  1087.         local slotWidth = obj.Width + self.SpacingX\
  1088.         local maxX = math.floor((self.Width - 2) / slotWidth)\
  1089.         return x, y, maxX, slotWidth, slotHeight\
  1090. end\
  1091. \
  1092. local function IconLocation(self, obj, i)\
  1093.         local x, y, maxX, slotWidth, slotHeight = MaxIcons(self, obj)\
  1094.         local rowPos = ((i - 1) % maxX)\
  1095.         local colPos = math.ceil(i / maxX) - 1\
  1096.         x = x + (slotWidth * rowPos)\
  1097.         y = y + colPos * slotHeight\
  1098.         return x, y\
  1099. end\
  1100. \
  1101. local function AddItem(self, v, i)\
  1102.         local toggle = false\
  1103.         if not self.CanSelect then\
  1104.                 toggle = nil\
  1105.         end\
  1106.         local x, y = IconLocation(self, v, i)\
  1107.         local item = {\
  1108.                 [\"X\"]=x,\
  1109.                 [\"Y\"]=y,\
  1110.                 [\"Name\"]=\"CollectionViewItem\",\
  1111.                 [\"Type\"]=\"View\",\
  1112.                 [\"TextColour\"]=self.TextColour,\
  1113.                 [\"BackgroundColour\"]=0F,\
  1114.                 OnClick = function(itm)\
  1115.                         if self.CanSelect then\
  1116.                                 for i2, _v in ipairs(self.Children) do\
  1117.                                         _v.Toggle = false\
  1118.                                 end\
  1119.                                 self.Selected = itm\
  1120.                         end\
  1121.                 end\
  1122.    }\
  1123.         for k, _v in pairs(v) do\
  1124.                 item[k] = _v\
  1125.         end\
  1126.         self:AddObject(item)\
  1127. end\
  1128. \
  1129. \
  1130. UpdateItems = function(self)\
  1131.         self:RemoveAllObjects()\
  1132.         local groupMode = false\
  1133.         for k, v in pairs(self.Items) do\
  1134.                 if type(k) == 'string' then\
  1135.                         groupMode = true\
  1136.                         break\
  1137.                 end\
  1138.         end\
  1139. \
  1140.         for i, v in ipairs(self.Items) do\
  1141.                 AddItem(self, v, i)\
  1142.         end\
  1143.         self:UpdateScroll()\
  1144. end\
  1145. \
  1146. OnUpdate = function(self, value)\
  1147.         if value == 'Items' then\
  1148.                 self.NeedsItemUpdate = true\
  1149.         end\
  1150. end\
  1151. ]],\
  1152. [\"ImageView\"] = [[\
  1153. Image = false\
  1154. \
  1155. OnDraw = function(self, x, y)\
  1156.         Drawing.DrawImage(x, y, self.Image, self.Width, self.Height)\
  1157. end\
  1158. \
  1159. OnLoad = function(self)\
  1160.         if self.Path and fs.exists(self.Path) then\
  1161.                 self.Image = Drawing.LoadImage(self.Path)\
  1162.         end\
  1163. end\
  1164. \
  1165. OnUpdate = function(self, value)\
  1166.         if value == 'Path' then\
  1167.                 if self.Path and fs.exists(self.Path) then\
  1168.                         self.Image = Drawing.LoadImage(self.Path)\
  1169.                 end\
  1170.         end\
  1171. end\
  1172. ]],\
  1173. [\"Label\"] = [[\
  1174. TextColour = colours.black\
  1175. BackgroundColour = colours.transparent\
  1176. Text = \"\"\
  1177. AutoWidth = false\
  1178. Align = 'Left'\
  1179. \
  1180. local wrapText = function(text, maxWidth)\
  1181.    local lines = {''}\
  1182.    for word, space in text:gmatch('(%S+)(%s*)') do\
  1183.        local temp = lines[#lines] .. word .. space:gsub('\\n','')\
  1184.        if #temp > maxWidth then\
  1185.            table.insert(lines, '')\
  1186.        end\
  1187.        if space:find('\\n') then\
  1188.            lines[#lines] = lines[#lines] .. word\
  1189.            \
  1190.            space = space:gsub('\\n', function()\
  1191.                    table.insert(lines, '')\
  1192.                    return ''\
  1193.            end)\
  1194.        else\
  1195.            lines[#lines] = lines[#lines] .. word .. space\
  1196.        end\
  1197.    end\
  1198.    if #lines[1] == 0 then\
  1199.        table.remove(lines,1)\
  1200.    end\
  1201.    return lines\
  1202. end\
  1203. \
  1204. OnUpdate = function(self, value)\
  1205.    if value == 'Text' then\
  1206.        if self.AutoWidth then\
  1207.            self.Width = #self.Text\
  1208.        else\
  1209.            self.Height = #wrapText(self.Text, self.Width)\
  1210.        end\
  1211.    end\
  1212. end\
  1213. \
  1214. OnDraw = function(self, x, y)\
  1215.         for i, v in ipairs(wrapText(self.Text, self.Width)) do\
  1216.        local _x = 0\
  1217.        if self.Align == 'Right' then\
  1218.            _x = self.Width - #v\
  1219.        elseif self.Align == 'Center' then\
  1220.            _x = math.floor((self.Width - #v) / 2)\
  1221.        end\
  1222.                 Drawing.DrawCharacters(x + _x, y + i - 1, v, self.TextColour, self.BackgroundColour)\
  1223.         end\
  1224. end\
  1225. ]],\
  1226. [\"ListView\"] = [[\
  1227. Inherit = 'ScrollView'\
  1228. UpdateDrawBlacklist = {['NeedsItemUpdate']=true}\
  1229. \
  1230. TextColour = colours.black\
  1231. BackgroundColour = colours.white\
  1232. HeadingColour = colours.lightGrey\
  1233. SelectionBackgroundColour = colours.blue\
  1234. SelectionTextColour = colours.white\
  1235. Items = false\
  1236. CanSelect = false\
  1237. Selected = nil\
  1238. NeedsItemUpdate = false\
  1239. ItemMargin = 1\
  1240. HeadingMargin = 0\
  1241. TopMargin = 0\
  1242. \
  1243. OnDraw = function(self, x, y)\
  1244.         if self.NeedsItemUpdate then\
  1245.                 self:UpdateItems()\
  1246.         end\
  1247.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1248. end\
  1249. \
  1250. local function AddItem(self, v, x, y, group)\
  1251.         local toggle = false\
  1252.         if not self.CanSelect then\
  1253.                 toggle = nil\
  1254.         elseif v.Selected then\
  1255.                 toggle = true\
  1256.         end\
  1257.         local item = {\
  1258.                 [\"Width\"]=self.Width,\
  1259.                 [\"X\"]=x,\
  1260.                 [\"Y\"]=y,\
  1261.                 [\"Name\"]=\"ListViewItem\",\
  1262.                 [\"Type\"]=\"Button\",\
  1263.                 [\"TextColour\"]=self.TextColour,\
  1264.                 [\"BackgroundColour\"]=0,\
  1265.                 [\"ActiveTextColour\"]=self.SelectionTextColour,\
  1266.                 [\"ActiveBackgroundColour\"]=self.SelectionBackgroundColour,\
  1267.                 [\"Align\"]='Left',\
  1268.                 [\"Toggle\"]=toggle,\
  1269.                 [\"Group\"]=group,\
  1270.                 OnClick = function(itm)\
  1271.                         if self.CanSelect then\
  1272.                                 self:SelectItem(itm)\
  1273.                         elseif self.OnSelect then\
  1274.                                 self:OnSelect(itm.Text)\
  1275.                         end\
  1276.                 end\
  1277.    }\
  1278.    if type(v) == 'table' then\
  1279.         for k, _v in pairs(v) do\
  1280.                 item[k] = _v\
  1281.         end\
  1282.    else\
  1283.                 item.Text = v\
  1284.    end\
  1285.         \
  1286.         local itm = self:AddObject(item)\
  1287.         if v.Selected then\
  1288.                 self:SelectItem(itm)\
  1289.         end\
  1290. end\
  1291. \
  1292. UpdateItems = function(self)\
  1293.         if not self.Items or type(self.Items) ~= 'table' then\
  1294.                 self.Items = {}\
  1295.         end\
  1296.         self.Selected = nil\
  1297.         self:RemoveAllObjects()\
  1298.         local groupMode = false\
  1299.         for k, v in pairs(self.Items) do\
  1300.                 if type(k) == 'string' then\
  1301.                         groupMode = true\
  1302.                         break\
  1303.                 end\
  1304.         end\
  1305. \
  1306.         if not groupMode then\
  1307.                 for i, v in ipairs(self.Items) do\
  1308.                         AddItem(self, v, self.ItemMargin, i)\
  1309.                 end\
  1310.         else\
  1311.                 local y = self.TopMargin\
  1312.                 for k, v in pairs(self.Items) do\
  1313.                         y = y + 1\
  1314.                         AddItem(self, {Text = k, TextColour = self.HeadingColour, IgnoreClick = true}, self.HeadingMargin, y)\
  1315.                         for i, _v in ipairs(v) do\
  1316.                                 y = y + 1\
  1317.                                 AddItem(self, _v, 1, y, k)\
  1318.                         end\
  1319.                         y = y + 1\
  1320.                 end\
  1321.         end\
  1322.         self:UpdateScroll()\
  1323.         self.NeedsItemUpdate = false\
  1324. end\
  1325. \
  1326. OnKeyChar = function(self, event, keychar)\
  1327.         if keychar == keys.up or keychar == keys.down then\
  1328.                 local n = self:GetIndex(self.Selected)\
  1329.                 if keychar == keys.up then\
  1330.                         n = n - 1\
  1331.                 else\
  1332.                         n = n + 1\
  1333.                 end\
  1334.                 local new = self:GetNth(n)\
  1335.                 if new then\
  1336.                         self:SelectItem(new)\
  1337.                 end\
  1338.         elseif keychar == keys.enter and self.Selected then\
  1339.                 self.Selected:Click('mouse_click', 1, 1, 1)\
  1340.         end\
  1341. end\
  1342. \
  1343. --returns the index/'n' of the given item\
  1344. GetIndex = function(self, obj)\
  1345.         local n = 1\
  1346.         for i, v in ipairs(self.Children) do\
  1347.                 if not v.IgnoreClick then\
  1348.                         if obj == v then\
  1349.                                 return n\
  1350.                         end\
  1351.                         n = n + 1\
  1352.                 end\
  1353.         end\
  1354. end\
  1355. \
  1356. --gets the 'nth' list item (does not include headings)\
  1357. GetNth = function(self, n)\
  1358.         local _n = 1\
  1359.         for i, v in ipairs(self.Children) do\
  1360.                 if not v.IgnoreClick then\
  1361.                         if n == _n then\
  1362.                                 return v\
  1363.                         end\
  1364.                         _n = _n + 1\
  1365.                 end\
  1366.         end\
  1367. end\
  1368. \
  1369. SelectItem = function(self, item)\
  1370.         for i, v in ipairs(self.Children) do\
  1371.                 v.Toggle = false\
  1372.         end\
  1373.         self.Selected = item\
  1374.         item.Toggle = true\
  1375.         if self.OnSelect then\
  1376.                 self:OnSelect(item.Text)\
  1377.         end\
  1378. end\
  1379. \
  1380. OnUpdate = function(self, value)\
  1381.         if value == 'Items' then\
  1382.                 self.NeedsItemUpdate = true\
  1383.         end\
  1384. end\
  1385. ]],\
  1386. [\"Menu\"] = [[\
  1387. Inherit = 'View'\
  1388. \
  1389. TextColour = colours.black\
  1390. BackgroundColour = colours.white\
  1391. HideTop = false\
  1392. \
  1393. OnDraw = function(self, x, y)\
  1394.         Drawing.IgnoreConstraint = true\
  1395.         Drawing.DrawBlankArea(x + 1, y + (self.HideTop and 0 or 1), self.Width, self.Height + (self.HideTop and 1 or 0), colours.grey)\
  1396.         Drawing.IgnoreConstraint = false\
  1397.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1398. end\
  1399. \
  1400. OnLoad = function(self)\
  1401.         local owner = self.Owner\
  1402.         if type(owner) == 'string' then\
  1403.                 owner = self.Bedrock:GetObject(self.Owner)\
  1404.         end\
  1405. \
  1406.         if owner then\
  1407.                 if self.X == 0 and self.Y == 0 then\
  1408.                         local pos = owner:GetPosition()\
  1409.                         self.X = pos.X\
  1410.                         self.Y = pos.Y + owner.Height\
  1411.                 end\
  1412.                 self.Owner = owner\
  1413.         else\
  1414.                 self.Owner = nil\
  1415.         end\
  1416. end\
  1417. \
  1418. OnUpdate = function(self, value)\
  1419.         if value == 'Children' then\
  1420.                 self.Width = self.Bedrock.Helpers.LongestString(self.Children, 'Text') + 2\
  1421.                 self.Height = #self.Children + 1 + (self.HideTop and 0 or 1)\
  1422.                 if not self.BaseY then\
  1423.                         self.BaseY = self.Y\
  1424.                 end\
  1425. \
  1426.                 for i, v in ipairs(self.Children) do\
  1427.                         if v.TextColour then\
  1428.                                 v.TextColour = self.TextColour\
  1429.                         end\
  1430.                         if v.BackgroundColour then\
  1431.                                 v.BackgroundColour = colours.transparent\
  1432.                         end\
  1433.                         if v.Colour then\
  1434.                                 v.Colour = colours.lightGrey\
  1435.                         end\
  1436.                         v.Align = 'Left'\
  1437.                         v.X = 1\
  1438.                         v.Y = i + (self.HideTop and 0 or 1)\
  1439.                         v.Width = self.Width\
  1440.                         v.Height = 1\
  1441.                 end\
  1442. \
  1443.                 self.Y = self.BaseY\
  1444.                 local pos = self:GetPosition()\
  1445.                 if pos.Y + self.Height + 1 > Drawing.Screen.Height then\
  1446.                         self.Y = self.BaseY - ((self.Height +  pos.Y) - Drawing.Screen.Height)\
  1447.                 end\
  1448.                 \
  1449.                 if pos.X + self.Width > Drawing.Screen.Width then\
  1450.                         self.X = Drawing.Screen.Width - self.Width\
  1451.                 end\
  1452.         end\
  1453. end\
  1454. \
  1455. Close = function(self, isBedrockCall)\
  1456.         self.Bedrock.Menu = nil\
  1457.         self.Parent:RemoveObject(self)\
  1458.         if self.Owner and self.Owner.Toggle then\
  1459.                 self.Owner.Toggle = false\
  1460.         end\
  1461.         self.Parent:ForceDraw()\
  1462.         self = nil\
  1463. end\
  1464. \
  1465. OnChildClick = function(self, child, event, side, x, y)\
  1466.         self:Close()\
  1467. end\
  1468. ]],\
  1469. [\"ProgressBar\"] = [[\
  1470. BackgroundColour = colours.lightGrey\
  1471. BarColour = colours.blue\
  1472. TextColour = colours.white\
  1473. ShowText = false\
  1474. Value = 0\
  1475. Maximum = 1\
  1476. Indeterminate = false\
  1477. AnimationStep = 0\
  1478. \
  1479. OnDraw = function(self, x, y)\
  1480.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1481. \
  1482.         -- if self.Indeterminate then\
  1483.         --      for i = 1, self.Width do\
  1484.         --              local s = x + i - 1 + self.AnimationStep\
  1485.         --              if s % 4 == 1 or s % 4 == 2 then\
  1486.         --                      Drawing.DrawBlankArea(s, y, 1, self.Height, self.BarColour)\
  1487.         --              end\
  1488.         --      end\
  1489.         --      self.AnimationStep = self.AnimationStep + 1\
  1490.         --      if self.AnimationStep >= 4 then\
  1491.         --              self.AnimationStep = 0\
  1492.         --      end\
  1493.         --      self.Bedrock:StartTimer(function()\
  1494.         --              self:Draw()\
  1495.         --      end, 0.25)\
  1496.         -- else\
  1497.                 local values = self.Value\
  1498.                 local barColours = self.BarColour\
  1499.                 if type(values) == 'number' then\
  1500.                         values = {values}\
  1501.                 end\
  1502.                 if type(barColours) == 'number' then\
  1503.                         barColours = {barColours}\
  1504.                 end\
  1505.                 local total = 0\
  1506.                 local _x = x\
  1507.                 for i, v in ipairs(values) do\
  1508.                         local width = self.Bedrock.Helpers.Round((v / self.Maximum) * self.Width)\
  1509.                         total = total + v\
  1510.                         Drawing.DrawBlankArea(_x, y, width, self.Height, barColours[((i-1)%#barColours)+1])\
  1511.                         _x = _x + width\
  1512.                 end\
  1513. \
  1514.                 if self.ShowText then\
  1515.                         local text = self.Bedrock.Helpers.Round((total / self.Maximum) * 100) .. '%'\
  1516.                         Drawing.DrawCharactersCenter(x, y, self.Width, self.Height, text, self.TextColour, colours.transparent)\
  1517.                 end\
  1518.         -- end\
  1519. end\
  1520. ]],\
  1521. [\"ScrollBar\"] = [[\
  1522. BackgroundColour = colours.lightGrey\
  1523. BarColour = colours.lightBlue\
  1524. Scroll = 0\
  1525. MaxScroll = 0\
  1526. ClickPoint = nil\
  1527. Fixed = true\
  1528. \
  1529. OnUpdate = function(self, value)\
  1530.         if value == 'Text' and self.AutoWidth then\
  1531.                 self.Width = #self.Text + 2\
  1532.         end\
  1533. end\
  1534. \
  1535. OnDraw = function(self, x, y)\
  1536.         local barHeight = self.Height * (self.Height / (self.Height + self.MaxScroll))\
  1537.    if barHeight < 3 then\
  1538.      barHeight = 3\
  1539.    end\
  1540.    local percentage = (self.Scroll/self.MaxScroll)\
  1541. \
  1542.    Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1543.    Drawing.DrawBlankArea(x, y + math.ceil(self.Height*percentage - barHeight*percentage), self.Width, barHeight, self.BarColour)\
  1544. end\
  1545. \
  1546. OnScroll = function(self, event, direction, x, y)\
  1547.         if event == 'mouse_scroll' then\
  1548.                 direction = self.Bedrock.Helpers.Round(direction * 3)\
  1549.         end\
  1550.         if self.Scroll < 0 or self.Scroll > self.MaxScroll then\
  1551.                 return false\
  1552.         end\
  1553.         local old = self.Scroll\
  1554.         self.Scroll = self.Bedrock.Helpers.Round(self.Scroll + direction)\
  1555.         if self.Scroll < 0 then\
  1556.                 self.Scroll = 0\
  1557.         elseif self.Scroll > self.MaxScroll then\
  1558.                 self.Scroll = self.MaxScroll\
  1559.         end\
  1560. \
  1561.         if self.Scroll ~= old and self.OnChange then\
  1562.                 self:OnChange()\
  1563.         end\
  1564. end\
  1565. \
  1566. OnClick = function(self, event, side, x, y)\
  1567.         if event == 'mouse_click' then\
  1568.                 self.ClickPoint = y\
  1569.         else\
  1570.                 local gapHeight = self.Height - (self.Height * (self.Height / (self.Height + self.MaxScroll)))\
  1571.                 local barHeight = self.Height * (self.Height / (self.Height + self.MaxScroll))\
  1572.                 --local delta = (self.Height + self.MaxScroll) * ((y - self.ClickPoint) / barHeight)\
  1573.                 local delta = ((y - self.ClickPoint)/gapHeight)*self.MaxScroll\
  1574.                 --l(((y - self.ClickPoint)/gapHeight))\
  1575.                 --l(delta)\
  1576.                 self.Scroll = self.Bedrock.Helpers.Round(delta)\
  1577.                 --l(self.Scroll)\
  1578.                 --l('----')\
  1579.                 if self.Scroll < 0 then\
  1580.                         self.Scroll = 0\
  1581.                 elseif self.Scroll > self.MaxScroll then\
  1582.                         self.Scroll = self.MaxScroll\
  1583.                 end\
  1584.                 if self.OnChange then\
  1585.                         self:OnChange()\
  1586.                 end\
  1587.         end\
  1588. \
  1589.         local relScroll = self.MaxScroll * ((y-1)/self.Height)\
  1590.         if y == self.Height then\
  1591.                 relScroll = self.MaxScroll\
  1592.         end\
  1593.         self.Scroll = self.Bedrock.Helpers.Round(relScroll)\
  1594. \
  1595. \
  1596. end\
  1597. \
  1598. OnDrag = OnClick\
  1599. ]],\
  1600. [\"ScrollView\"] = [[\
  1601. Inherit = 'View'\
  1602. ChildOffset = false\
  1603. ContentWidth = 0\
  1604. ContentHeight = 0\
  1605. ScrollBarBackgroundColour = colours.lightGrey\
  1606. ScrollBarColour = colours.lightBlue\
  1607. \
  1608. CalculateContentSize = function(self)\
  1609.         local function calculateObject(obj)\
  1610.                 local pos = obj:GetPosition()\
  1611.                 local x2 = pos.X + obj.Width - 1\
  1612.                 local y2 = pos.Y + obj.Height - 1\
  1613.                 if obj.Children then\
  1614.                         for i, child in ipairs(obj.Children) do\
  1615.                                 local _x2, _y2 = calculateObject(child)\
  1616.                                 if _x2 > x2 then\
  1617.                                         x2 = _x2\
  1618.                                 end\
  1619.                                 if _y2 > y2 then\
  1620.                                         y2 = _y2\
  1621.                                 end\
  1622.                         end\
  1623.                 end\
  1624.                 return x2, y2\
  1625.         end\
  1626. \
  1627.         local pos = self:GetPosition()\
  1628.         local x2, y2 = calculateObject(self)\
  1629.         self.ContentWidth = x2 - pos.X + 1\
  1630.         self.ContentHeight = y2 - pos.Y + 1\
  1631. end\
  1632. \
  1633. UpdateScroll = function(self)\
  1634.         self.ChildOffset.Y = 0\
  1635.         self:CalculateContentSize()\
  1636.         if self.ContentHeight > self.Height then\
  1637.                 if not self:GetObject('ScrollViewScrollBar') then\
  1638.                         local _scrollBar = self:AddObject({\
  1639.                                 [\"Name\"] = 'ScrollViewScrollBar',\
  1640.                                 [\"Type\"] = 'ScrollBar',\
  1641.                                 [\"X\"] = self.Width,\
  1642.                                 [\"Y\"] = 1,\
  1643.                                 [\"Width\"] = 1,\
  1644.                                 [\"Height\"] = self.Height,\
  1645.                                 [\"BackgroundColour\"] = self.ScrollBarBackgroundColour,\
  1646.                                 [\"BarColour\"] = self.ScrollBarColour,\
  1647.                                 [\"Z\"]=999\
  1648.                         })\
  1649. \
  1650.                         _scrollBar.OnChange = function(scrollBar)\
  1651.                                 self.ChildOffset.Y = -scrollBar.Scroll\
  1652.                                 for i, child in ipairs(self.Children) do\
  1653.                                         child:ForceDraw()\
  1654.                                 end\
  1655.                         end\
  1656.                 end\
  1657.                 self:GetObject('ScrollViewScrollBar').MaxScroll = self.ContentHeight - self.Height\
  1658.         else\
  1659.                 self:RemoveObject('ScrollViewScrollBar')\
  1660.         end\
  1661. end\
  1662. \
  1663. OnScroll = function(self, event, direction, x, y)\
  1664.         if self:GetObject('ScrollViewScrollBar') then\
  1665.                 self:GetObject('ScrollViewScrollBar'):OnScroll(event, direction, x, y)\
  1666.         end\
  1667. end\
  1668. \
  1669. OnLoad = function(self)\
  1670.         if not self.ChildOffset or not self.ChildOffset.X or not self.ChildOffset.Y then\
  1671.                 self.ChildOffset = {X = 0, Y = 0}\
  1672.         end\
  1673. end\
  1674. ]],\
  1675. [\"SecureTextBox\"] = [[\
  1676. Inherit = 'TextBox'\
  1677. MaskCharacter = '*'\
  1678. \
  1679. OnDraw = function(self, x, y)\
  1680.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1681.         if self.CursorPos > #self.Text then\
  1682.                 self.CursorPos = #self.Text\
  1683.         elseif self.CursorPos < 0 then\
  1684.                 self.CursorPos = 0\
  1685.         end\
  1686.         local text = ''\
  1687. \
  1688.         for i = 1, #self.Text do\
  1689.                 text = text .. self.MaskCharacter\
  1690.         end\
  1691. \
  1692.         if self.Bedrock:GetActiveObject() == self then\
  1693.                 if #text > (self.Width - 2) then\
  1694.                         text = text:sub(#text-(self.Width - 3))\
  1695.                         self.Bedrock.CursorPos = {x + 1 + self.Width-2, y}\
  1696.                 else\
  1697.                         self.Bedrock.CursorPos = {x + 1 + self.CursorPos, y}\
  1698.                 end\
  1699.                 self.Bedrock.CursorColour = self.TextColour\
  1700.         end\
  1701. \
  1702.         if #tostring(text) == 0 then\
  1703.                 Drawing.DrawCharacters(x + 1, y, self.Placeholder, self.PlaceholderTextColour, self.BackgroundColour)\
  1704.         else\
  1705.                 if not self.Selected then\
  1706.                         Drawing.DrawCharacters(x + 1, y, text, self.TextColour, self.BackgroundColour)\
  1707.                 else\
  1708.                         for i = 1, #text do\
  1709.                                 local char = text:sub(i, i)\
  1710.                                 local textColour = self.TextColour\
  1711.                                 local backgroundColour = self.BackgroundColour\
  1712.                                 if i > self.DragStart and i - 1 <= self.CursorPos then\
  1713.                                         textColour = self.SelectedTextColour\
  1714.                                         backgroundColour = self.SelectedBackgroundColour\
  1715.                                 end\
  1716.                                 Drawing.DrawCharacters(x + i, y, char, textColour, backgroundColour)\
  1717.                         end\
  1718.                 end\
  1719.         end\
  1720. end\
  1721. ]],\
  1722. [\"Separator\"] = [[\
  1723. Colour = colours.grey\
  1724. \
  1725. OnDraw = function(self, x, y)\
  1726.         local char = \"|\"\
  1727.         if self.Width > self.Height then\
  1728.                 char = '-'\
  1729.         end\
  1730.         Drawing.DrawArea(x, y, self.Width, self.Height, char, self.Colour, colours.transparent)\
  1731. end\
  1732. ]],\
  1733. [\"TextBox\"] = [[\
  1734. BackgroundColour = colours.lightGrey\
  1735. SelectedBackgroundColour = colours.blue\
  1736. SelectedTextColour = colours.white\
  1737. TextColour = colours.black\
  1738. PlaceholderTextColour = colours.grey\
  1739. Placeholder = ''\
  1740. AutoWidth = false\
  1741. Text = \"\"\
  1742. CursorPos = nil\
  1743. Numerical = false\
  1744. DragStart = nil\
  1745. Selected = false\
  1746. SelectOnClick = false\
  1747. ActualDragStart = nil\
  1748. \
  1749. OnDraw = function(self, x, y)\
  1750.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1751.         if self.CursorPos > #self.Text then\
  1752.                 self.CursorPos = #self.Text\
  1753.         elseif self.CursorPos < 0 then\
  1754.                 self.CursorPos = 0\
  1755.         end\
  1756.         local text = self.Text\
  1757.         local offset = self:TextOffset()\
  1758.         if #text > (self.Width - 2) then\
  1759.                 text = text:sub(offset+1, offset + self.Width - 2)\
  1760.                 -- self.Bedrock.CursorPos = {x + 1 + self.Width-2, y}\
  1761.         -- else\
  1762.         end\
  1763.         if self.Bedrock:GetActiveObject() == self then\
  1764.                 self.Bedrock.CursorPos = {x + 1 + self.CursorPos - offset, y}\
  1765.                 self.Bedrock.CursorColour = self.TextColour\
  1766.         else\
  1767.                 self.Selected = false\
  1768.         end\
  1769. \
  1770.         if #tostring(text) == 0 then\
  1771.                 Drawing.DrawCharacters(x + 1, y, self.Placeholder, self.PlaceholderTextColour, self.BackgroundColour)\
  1772.         else\
  1773.                 if not self.Selected then\
  1774.                         Drawing.DrawCharacters(x + 1, y, text, self.TextColour, self.BackgroundColour)\
  1775.                 else\
  1776.                         local startPos = self.DragStart - offset\
  1777.                         local endPos = self.CursorPos - offset\
  1778.                         if startPos > endPos then\
  1779.                                 startPos = self.CursorPos - offset\
  1780.                                 endPos = self.DragStart - offset\
  1781.                         end\
  1782.                         for i = 1, #text do\
  1783.                                 local char = text:sub(i, i)\
  1784.                                 local textColour = self.TextColour\
  1785.                                 local backgroundColour = self.BackgroundColour\
  1786. \
  1787.                                 if i > startPos and i - 1 <= endPos then\
  1788.                                         textColour = self.SelectedTextColour\
  1789.                                         backgroundColour = self.SelectedBackgroundColour\
  1790.                                 end\
  1791.                                 Drawing.DrawCharacters(x + i, y, char, textColour, backgroundColour)\
  1792.                         end\
  1793.                 end\
  1794.         end\
  1795. end\
  1796. \
  1797. TextOffset = function(self)\
  1798.         if #self.Text < (self.Width - 2) then\
  1799.                 return 0\
  1800.         elseif self.Bedrock:GetActiveObject() ~= self then\
  1801.                 return 0\
  1802.         else\
  1803.                 local textWidth = (self.Width - 2)\
  1804.                 local offset = self.CursorPos - textWidth\
  1805.                 if offset < 0 then\
  1806.                         offset = 0\
  1807.                 end\
  1808.                 return offset\
  1809.         end\
  1810. end\
  1811. \
  1812. OnLoad = function(self)\
  1813.         if not self.CursorPos then\
  1814.                 self.CursorPos = #self.Text\
  1815.         end\
  1816. end\
  1817. \
  1818. OnClick = function(self, event, side, x, y)\
  1819.         if self.Bedrock:GetActiveObject() ~= self and self.SelectOnClick then\
  1820.                 self.CursorPos = #self.Text - 1\
  1821.                 self.DragStart = 0\
  1822.                 self.ActualDragStart = x - 2 + self:TextOffset()\
  1823.                 self.Selected = true\
  1824.         else\
  1825.                 self.CursorPos = x - 2 + self:TextOffset()\
  1826.                 self.DragStart = self.CursorPos\
  1827.                 self.Selected = false\
  1828.         end\
  1829.         self.Bedrock:SetActiveObject(self)\
  1830. end\
  1831. \
  1832. OnDrag = function(self, event, side, x, y)\
  1833.         self.CursorPos = x - 2 + self:TextOffset()\
  1834.         if self.ActualDragStart then\
  1835.                 self.DragStart = self.ActualDragStart\
  1836.                 self.ActualDragStart = nil\
  1837.         end\
  1838.         if self.DragStart then\
  1839.                 self.Selected = true\
  1840.         end\
  1841. end\
  1842. \
  1843. OnKeyChar = function(self, event, keychar)\
  1844.         local deleteSelected = function()\
  1845.                 if self.Selected then\
  1846.                         local startPos = self.DragStart\
  1847.                         local endPos = self.CursorPos\
  1848.                         if startPos > endPos then\
  1849.                                 startPos = self.CursorPos\
  1850.                                 endPos = self.DragStart\
  1851.                         end\
  1852.                         self.Text = self.Text:sub(1, startPos) .. self.Text:sub(endPos + 2)\
  1853.                         self.CursorPos = startPos\
  1854.                         self.DragStart = nil\
  1855.                         self.Selected = false\
  1856.                         return true\
  1857.                 end\
  1858.         end\
  1859. \
  1860.         if event == 'char' then\
  1861.                 deleteSelected()\
  1862.                 if self.Numerical then\
  1863.                         keychar = tostring(tonumber(keychar))\
  1864.                 end\
  1865.                 if keychar == 'nil' then\
  1866.                         return\
  1867.                 end\
  1868.                 self.Text = string.sub(self.Text, 1, self.CursorPos ) .. keychar .. string.sub( self.Text, self.CursorPos + 1 )\
  1869.                 if self.Numerical then\
  1870.                         self.Text = tostring(tonumber(self.Text))\
  1871.                         if self.Text == 'nil' then\
  1872.                                 self.Text = '1'\
  1873.                         end\
  1874.                 end\
  1875.                 \
  1876.                 self.CursorPos = self.CursorPos + 1\
  1877.                 if self.OnChange then\
  1878.                         self:OnChange(event, keychar)\
  1879.                 end\
  1880.                 return false\
  1881.         elseif event == 'key' then\
  1882.                 if keychar == keys.enter then\
  1883.                         if self.OnChange then\
  1884.                                 self:OnChange(event, keychar)\
  1885.                         end\
  1886.                 elseif keychar == keys.left then\
  1887.                         -- Left\
  1888.                         if self.CursorPos > 0 then\
  1889.                                 if self.Selected then\
  1890.                                         self.CursorPos = self.DragStart\
  1891.                                         self.DragStart = nil\
  1892.                                         self.Selected = false\
  1893.                                 else\
  1894.                                         self.CursorPos = self.CursorPos - 1\
  1895.                                 end\
  1896.                                 if self.OnChange then\
  1897.                                         self:OnChange(event, keychar)\
  1898.                                 end\
  1899.                         end\
  1900.                         \
  1901.                 elseif keychar == keys.right then\
  1902.                         -- Right                                \
  1903.                         if self.CursorPos < string.len(self.Text) then\
  1904.                                 if self.Selected then\
  1905.                                         self.CursorPos = self.CursorPos\
  1906.                                         self.DragStart = nil\
  1907.                                         self.Selected = false\
  1908.                                 else\
  1909.                                         self.CursorPos = self.CursorPos + 1\
  1910.                                 end\
  1911.                                 if self.OnChange then\
  1912.                                         self:OnChange(event, keychar)\
  1913.                                 end\
  1914.                         end\
  1915.                 \
  1916.                 elseif keychar == keys.backspace then\
  1917.                         -- Backspace\
  1918.                         if not deleteSelected() and self.CursorPos > 0 then\
  1919.                                 self.Text = string.sub( self.Text, 1, self.CursorPos - 1 ) .. string.sub( self.Text, self.CursorPos + 1 )\
  1920.                                 self.CursorPos = self.CursorPos - 1                                     \
  1921.                                 if self.Numerical then\
  1922.                                         self.Text = tostring(tonumber(self.Text))\
  1923.                                         if self.Text == 'nil' then\
  1924.                                                 self.Text = '1'\
  1925.                                         end\
  1926.                                 end\
  1927.                                 if self.OnChange then\
  1928.                                         self:OnChange(event, keychar)\
  1929.                                 end\
  1930.                         end\
  1931.                 elseif keychar == keys.home then\
  1932.                         -- Home\
  1933.                         self.CursorPos = 0\
  1934.                         if self.OnChange then\
  1935.                                 self:OnChange(event, keychar)\
  1936.                         end\
  1937.                 elseif keychar == keys.delete then\
  1938.                         if not deleteSelected() and self.CursorPos < string.len(self.Text) then\
  1939.                                 self.Text = string.sub( self.Text, 1, self.CursorPos ) .. string.sub( self.Text, self.CursorPos + 2 )           \
  1940.                                 if self.Numerical then\
  1941.                                         self.Text = tostring(tonumber(self.Text))\
  1942.                                         if self.Text == 'nil' then\
  1943.                                                 self.Text = '1'\
  1944.                                         end\
  1945.                                 end\
  1946.                                 if self.OnChange then\
  1947.                                         self:OnChange(keychar)\
  1948.                                 end\
  1949.                         end\
  1950.                 elseif keychar == keys[\"end\"] then\
  1951.                         -- End\
  1952.                         self.CursorPos = string.len(self.Text)\
  1953.                 else\
  1954.                         if self.OnChange then\
  1955.                                 self:OnChange(event, keychar)\
  1956.                         end\
  1957.                         return false\
  1958.                 end\
  1959.         end\
  1960. end\
  1961. ]],\
  1962. [\"View\"] = [[\
  1963. BackgroundColour = colours.transparent\
  1964. Children = {}\
  1965. \
  1966. OnDraw = function(self, x, y)\
  1967.         if self.BackgroundColour then\
  1968.                 Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1969.         end\
  1970. end\
  1971. \
  1972. OnInitialise = function(self)\
  1973.         self.Children = {}\
  1974. end\
  1975. \
  1976. InitialiseFile = function(self, bedrock, file, name)\
  1977.         local _new = {}\
  1978.         _new.X = 1\
  1979.         _new.Y = 1\
  1980.         _new.Width = Drawing.Screen.Width\
  1981.         _new.Height = Drawing.Screen.Height\
  1982.         _new.BackgroundColour = file.BackgroundColour\
  1983.         _new.Name = name\
  1984.         _new.Children = {}\
  1985.         _new.Bedrock = bedrock\
  1986.         local new = self:Initialise(_new)\
  1987.         for i, obj in ipairs(file.Children) do\
  1988.                 local view = bedrock:ObjectFromFile(obj, new)\
  1989.                 if not view.Z then\
  1990.                         view.Z = i\
  1991.                 end\
  1992.                 view.Parent = new\
  1993.                 table.insert(new.Children, view)\
  1994.         end\
  1995.         return new\
  1996. end\
  1997. \
  1998. function CheckClick(self, object, x, y)\
  1999.         local offset = {X = 0, Y = 0}\
  2000.         if not object.Fixed and self.ChildOffset then\
  2001.                 offset = self.ChildOffset\
  2002.         end\
  2003.         if object.X + offset.X <= x and object.Y + offset.Y <= y and  object.X + offset.X + object.Width > x and object.Y + offset.Y + object.Height > y then\
  2004.                 return true\
  2005.         end\
  2006. end\
  2007. \
  2008. function DoClick(self, object, event, side, x, y)\
  2009.         if object then\
  2010.                 if self:CheckClick(object, x, y) then\
  2011.                         local offset = {X = 0, Y = 0}\
  2012.                         if not object.Fixed and self.ChildOffset then\
  2013.                                 offset = self.ChildOffset\
  2014.                         end\
  2015.                         return object:Click(event, side, x - object.X - offset.X + 1, y - object.Y + 1 - offset.Y)\
  2016.                 end\
  2017.         end     \
  2018. end\
  2019. \
  2020. Click = function(self, event, side, x, y, z)\
  2021.         if self.Visible and not self.IgnoreClick then\
  2022.                 for i = #self.Children, 1, -1 do --children are ordered from smallest Z to highest, so this is done in reverse\
  2023.                         local child = self.Children[i]\
  2024.                         if self:DoClick(child, event, side, x, y) then\
  2025.                                 if self.OnChildClick then\
  2026.                                         self:OnChildClick(child, event, side, x, y)\
  2027.                                 end\
  2028.                                 return true\
  2029.                         end\
  2030.                 end\
  2031.                 if event == 'mouse_click' and self.OnClick and self:OnClick(event, side, x, y) ~= false then\
  2032.                         return true\
  2033.                 elseif event == 'mouse_drag' and self.OnDrag and self:OnDrag(event, side, x, y) ~= false then\
  2034.                         return true\
  2035.                 elseif event == 'mouse_scroll' and self.OnScroll and self:OnScroll(event, side, x, y) ~= false then\
  2036.                         return true\
  2037.                 else\
  2038.                         return false\
  2039.                 end\
  2040.         else\
  2041.                 return false\
  2042.         end\
  2043. end\
  2044. \
  2045. OnRemove = function(self)\
  2046.         if self == self.Bedrock:GetActiveObject() then\
  2047.                 self.Bedrock:SetActiveObject()\
  2048.         end\
  2049.         for i, child in ipairs(self.Children) do\
  2050.                 child:OnRemove()\
  2051.         end\
  2052. end\
  2053. \
  2054. local function findObjectNamed(view, name, minI)\
  2055.         local minI = minI or 0\
  2056.         if view and view.Children then\
  2057.                 for i, child in ipairs(view.Children) do\
  2058.                         if child.Name == name or child == name then\
  2059.                                 return child, i, view\
  2060.                         elseif child.Children then\
  2061.                                 local found, index, foundView = findObjectNamed(child, name)\
  2062.                                 if found and minI <= index then\
  2063.                                         return found, index, foundView\
  2064.                                 end\
  2065.                         end\
  2066.                 end\
  2067.         end\
  2068. end\
  2069. \
  2070. function AddObject(self, info, extra)\
  2071.         if type(info) == 'string' then\
  2072.                 local h = fs.open(self.Bedrock.ViewPath..info..'.view', 'r')\
  2073.                 if h then\
  2074.                         info = textutils.unserialize(h.readAll())\
  2075.                         h.close()\
  2076.                 else\
  2077.                         error('Error in opening object: '..info)\
  2078.                 end\
  2079.         end\
  2080. \
  2081.         if extra then\
  2082.                 for k, v in pairs(extra) do\
  2083.                         if v then\
  2084.                                 info[k] = v\
  2085.                         end\
  2086.                 end\
  2087.         end\
  2088. \
  2089.         local view = self.Bedrock:ObjectFromFile(info, self)\
  2090.         if not view.Z then\
  2091.                 view.Z = #self.Children + 1\
  2092.         end\
  2093.         \
  2094.         table.insert(self.Children, view)\
  2095.         if self.Bedrock.View then\
  2096.                 self.Bedrock:ReorderObjects()\
  2097.         end\
  2098.         self:ForceDraw()\
  2099.         return view\
  2100. end\
  2101. \
  2102. function GetObject(self, name)\
  2103.         return findObjectNamed(self, name)\
  2104. end\
  2105. \
  2106. local function findObjects(view, name)\
  2107.         local objects = {}\
  2108.         if view and view.Children then\
  2109.                 for i, child in ipairs(view.Children) do\
  2110.                         if child.Name == name or child == name then\
  2111.                                 table.insert(objects, child)\
  2112.                         elseif child.Children then\
  2113.                                 local objs = findObjects(child, name)\
  2114.                                 if objs then\
  2115.                                         for i2, v in ipairs(objs) do\
  2116.                                                 table.insert(objects, v)\
  2117.                                         end\
  2118.                                 end\
  2119.                         end\
  2120.                 end\
  2121.         end\
  2122.         return objects\
  2123. end\
  2124. \
  2125. function GetObjects(self, name)\
  2126.         return findObjects(self, name)\
  2127. end\
  2128. \
  2129. function RemoveObject(self, name)\
  2130.         local obj, index, view = findObjectNamed(self, name, minI)\
  2131.         if index then\
  2132.                 view.Children[index]:OnRemove()\
  2133.                 table.remove(view.Children, index)\
  2134.                 if view.OnUpdate then\
  2135.                         view:OnUpdate('Children')\
  2136.                 end\
  2137.                 return true\
  2138.         end\
  2139.         return false\
  2140. end\
  2141. \
  2142. function RemoveObjects(self, name)\
  2143.         local i = 1\
  2144.         while self:RemoveObject(name) and i < 100 do\
  2145.                 i = i + 1\
  2146.         end\
  2147.         \
  2148. end\
  2149. \
  2150. function RemoveAllObjects(self)\
  2151.         for i, child in ipairs(self.Children) do\
  2152.                 child:OnRemove()\
  2153.                 self.Children[i] = nil\
  2154.         end\
  2155.         self:ForceDraw()\
  2156. end\
  2157. ]],\
  2158. [\"Window\"] = [[\
  2159. Inherit = 'View'\
  2160. \
  2161. ToolBarColour = colours.lightGrey\
  2162. ToolBarTextColour = colours.black\
  2163. ShadowColour = colours.grey\
  2164. Title = ''\
  2165. Flashing = false\
  2166. CanClose = true\
  2167. OnCloseButton = nil\
  2168. OldActiveObject = nil\
  2169. \
  2170. OnLoad = function(self)\
  2171.         --self:GetObject('View') = self.Bedrock:ObjectFromFile({Type = 'View',Width = 10, Height = 5, BackgroundColour = colours.red}, self)\
  2172. end\
  2173. \
  2174. LoadView = function(self)\
  2175.         local view = self:GetObject('View')\
  2176.         if view.ToolBarColour then\
  2177.                 window.ToolBarColour = view.ToolBarColour\
  2178.         end\
  2179.         if view.ToolBarTextColour then\
  2180.                 window.ToolBarTextColour = view.ToolBarTextColour\
  2181.         end\
  2182.         view.X = 1\
  2183.         view.Y = 2\
  2184. \
  2185.         view:ForceDraw()\
  2186.         self:OnUpdate('View')\
  2187.         if self.OnViewLoad then\
  2188.                 self.OnViewLoad(view)\
  2189.         end\
  2190.         self.OldActiveObject = self.Bedrock:GetActiveObject()\
  2191.         self.Bedrock:SetActiveObject(view)\
  2192. end\
  2193. \
  2194. SetView = function(self, view)\
  2195.         self:RemoveObject('View')\
  2196.         table.insert(self.Children, view)\
  2197.         view.Parent = self\
  2198.         self:LoadView()\
  2199. end\
  2200. \
  2201. Flash = function(self)\
  2202.         self.Flashing = true\
  2203.         self:ForceDraw()\
  2204.         self.Bedrock:StartTimer(function()self.Flashing = false end, 0.4)\
  2205. end\
  2206. \
  2207. OnDraw = function(self, x, y)\
  2208.         local toolBarColour = (self.Flashing and colours.white or self.ToolBarColour)\
  2209.         local toolBarTextColour = (self.Flashing and colours.black or self.ToolBarTextColour)\
  2210.         if toolBarColour then\
  2211.                 Drawing.DrawBlankArea(x, y, self.Width, 1, toolBarColour)\
  2212.         end\
  2213.         if toolBarTextColour then\
  2214.                 local title = self.Bedrock.Helpers.TruncateString(self.Title, self.Width - 2)\
  2215.                 Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, title, toolBarTextColour, toolBarColour)\
  2216.         end\
  2217.         Drawing.IgnoreConstraint = true\
  2218.         Drawing.DrawBlankArea(x + 1, y + 1, self.Width, self.Height, self.ShadowColour)\
  2219.         Drawing.IgnoreConstraint = false\
  2220. end\
  2221. \
  2222. Close = function(self)\
  2223.         self.Bedrock:SetActiveObject(self.OldActiveObject)\
  2224.         self.Bedrock.Window = nil\
  2225.         self.Bedrock:RemoveObject(self)\
  2226.         if self.OnClose then\
  2227.                 self:OnClose()\
  2228.         end\
  2229.         self = nil\
  2230. end\
  2231. \
  2232. OnUpdate = function(self, value)\
  2233.         if value == 'View' and self:GetObject('View') then\
  2234.                 self.Width = self:GetObject('View').Width\
  2235.                 self.Height = self:GetObject('View').Height + 1\
  2236.                 self.X = math.ceil((Drawing.Screen.Width - self.Width) / 2)\
  2237.                 self.Y = math.ceil((Drawing.Screen.Height - self.Height) / 2)\
  2238.         elseif value == 'CanClose' then\
  2239.                 self:RemoveObject('CloseButton')\
  2240.                 if self.CanClose then\
  2241.                         local button = self:AddObject({X = 1, Y = 1, Width = 1, Height = 1, Type = 'Button', BackgroundColour = colours.red, TextColour = colours.white, Text = 'x', Name = 'CloseButton'})\
  2242.                         button.OnClick = function(btn)\
  2243.                                 if self.OnCloseButton then\
  2244.                                         self:OnCloseButton()\
  2245.                                 end\
  2246.                                 self:Close()\
  2247.                         end\
  2248.                 end\
  2249.         end\
  2250. end\
  2251. ]],\
  2252. }\
  2253. \
  2254. BasePath = ''\
  2255. ProgramPath = nil\
  2256. \
  2257. -- Program functions...\
  2258. \
  2259. local function main(...)\
  2260.         -- Code here...\
  2261. end\
  2262. \
  2263. -- Run\
  2264. local args = {...}\
  2265. local _, err = pcall(function() main(unpack(args)) end)\
  2266. if err then\
  2267.         -- Make a nice error handling screen here...\
  2268.         term.setBackgroundColor(colors.black)\
  2269.         term.setTextColor(colors.white)\
  2270.         term.clear()\
  2271.         term.setCursorPos(1, 3)\
  2272.         print(\" An Error Has Occured! D:\\n\\n\")\
  2273.         print(\" \" .. tostring(err) .. \"\\n\\n\")\
  2274.         print(\" Press any key to exit...\")\
  2275.         os.pullEvent(\"key\")\
  2276. end\
  2277. \
  2278. \
  2279. \
  2280. function LoadAPIs(self)\
  2281.         local function loadAPI(name, content)\
  2282.                 local env = setmetatable({}, { __index = getfenv() })\
  2283.                 local func, err = loadstring(content, name..' (Bedrock API)')\
  2284.                 if not func then\
  2285.                         return false, printError(err)\
  2286.                 end\
  2287.                 setfenv(func, env)\
  2288.                 func()\
  2289.                 local api = {}\
  2290.                 for k,v in pairs(env) do\
  2291.                         api[k] = v\
  2292.                 end\
  2293.                 _G[name] = api\
  2294.                 return true\
  2295.         end\
  2296. \
  2297.         local env = getfenv()\
  2298.         local function loadObject(name, content)\
  2299.                 loadAPI(name, content)\
  2300.                 if env[name].Inherit then\
  2301.                         if not getfenv()[env[name].Inherit] then        \
  2302.                                 if objects[env[name].Inherit] then\
  2303.                                         loadObject(env[name].Inherit, objects[env[name].Inherit])\
  2304.                                 elseif fs.exists(self.ProgramPath..'/Objects/'..env[name].Inherit..'.lua') then\
  2305.                                 end\
  2306.                         end\
  2307.                         env[name].__index = getfenv()[env[name].Inherit]\
  2308.                 else\
  2309.                         env[name].__index = Object\
  2310.                 end\
  2311.                 setmetatable(env[name], env[name])\
  2312.         end\
  2313. \
  2314.         for k, v in pairs(apis) do\
  2315.                 loadAPI(k, v)\
  2316.                 if k == 'Helpers' then\
  2317.                         self.Helpers = Helpers\
  2318.                 end\
  2319.         end\
  2320. \
  2321.         for k, v in pairs(objects) do\
  2322.                 loadObject(k, v)\
  2323.         end\
  2324.         \
  2325.         local privateObjPath = self.ProgramPath..'/Objects/'\
  2326.         if fs.exists(privateObjPath) and fs.isDir(privateObjPath) then\
  2327.                 for i, v in ipairs(fs.list(privateObjPath)) do\
  2328.                         if v ~= '.DS_Store' then\
  2329.                                 local name = string.match(v, '(%a+)%.?.-')\
  2330.                                 local h = fs.open(privateObjPath..v, 'r')\
  2331.                                 loadObject(name, h.readAll())\
  2332.                                 h.close()\
  2333.                         end\
  2334.                 end\
  2335.         end\
  2336. end\
  2337. \
  2338. AllowTerminate = true\
  2339. \
  2340. View = nil\
  2341. Menu = nil\
  2342. \
  2343. ActiveObject = nil\
  2344. \
  2345. DrawTimer = nil\
  2346. DrawTimerExpiry = 0\
  2347. \
  2348. IsDrawing = false\
  2349. \
  2350. Running = true\
  2351. \
  2352. DefaultView = 'main'\
  2353. \
  2354. EventHandlers = {\
  2355.         \
  2356. }\
  2357. \
  2358. ObjectClickHandlers = {\
  2359.         \
  2360. }\
  2361. \
  2362. ObjectUpdateHandlers = {\
  2363.         \
  2364. }\
  2365. \
  2366. Timers = {\
  2367.         \
  2368. }\
  2369. \
  2370. function Initialise(self, programPath)\
  2371.         self.ProgramPath = programPath or self.ProgramPath\
  2372.         if not programPath then\
  2373.                 if self.ProgramPath then\
  2374.                         local prgPath = self.ProgramPath\
  2375.                         local prgName = fs.getName(prgPath)\
  2376.                         if prgPath:find('/') then \
  2377.                                 self.ProgramPath = prgPath:sub(1, #prgPath-#prgName-1)\
  2378.                                 self.ProgramPath = prgPath:sub(1, #prgPath-#prgName-1) \
  2379.                         else \
  2380.                                 self.ProgramPath = '' \
  2381.                         end\
  2382.                 else\
  2383.                         self.ProgramPath = ''\
  2384.                 end\
  2385.         end\
  2386.         self:LoadAPIs()\
  2387.         self.ViewPath = self.ProgramPath .. '/Views/'\
  2388.         --first, check that the barebones APIs are available\
  2389.         local requiredApis = {\
  2390.                 'Drawing',\
  2391.                 'View'\
  2392.         }\
  2393.         local env = getfenv()\
  2394.         for i,v in ipairs(requiredApis) do\
  2395.                 if not env[v] then\
  2396.                         error('The API: '..v..' is not loaded. Please make sure you load it to use Bedrock.')\
  2397.                 end\
  2398.         end\
  2399. \
  2400.         local copy = { }\
  2401.         for k, v in pairs(self) do\
  2402.                 if k ~= 'Initialise' then\
  2403.                         copy[k] = v\
  2404.                 end\
  2405.         end\
  2406.         return setmetatable(copy, getmetatable(self))\
  2407. end\
  2408. \
  2409. function HandleClick(self, event, side, x, y)\
  2410.         if self.Window then\
  2411.                 if not self.View:CheckClick(self.Window, x, y) then\
  2412.                         self.Window:Flash()\
  2413.                 else\
  2414.                         self.View:DoClick(self.Window, event, side, x, y)\
  2415.                 end\
  2416.         elseif self.Menu then\
  2417.                 if not self.View:DoClick(self.Menu, event, side, x, y) then\
  2418.                         self.Menu:Close()\
  2419.                 end\
  2420.         elseif self.View then\
  2421.                 if self.View:Click(event, side, x, y) ~= false then\
  2422.                 end             \
  2423.         end\
  2424. end\
  2425. \
  2426. function HandleKeyChar(self, event, keychar)\
  2427.         if self:GetActiveObject() then\
  2428.                 local activeObject = self:GetActiveObject()\
  2429.                 if activeObject.OnKeyChar then\
  2430.                         if activeObject:OnKeyChar(event, keychar) ~= false then\
  2431.                                 --self:Draw()\
  2432.                         end\
  2433.                 end\
  2434.         end\
  2435. end\
  2436. \
  2437. function ToggleMenu(self, name, owner, x, y)\
  2438.         if self.Menu then\
  2439.                 self.Menu:Close()\
  2440.                 return false\
  2441.         else\
  2442.                 self:SetMenu(name, owner, x, y)\
  2443.                 return true\
  2444.         end\
  2445. end\
  2446. \
  2447. function SetMenu(self, menu, owner, x, y)\
  2448.         x = x or 1\
  2449.         y = y or 1\
  2450.         if self.Menu then\
  2451.                 self.Menu:Close()\
  2452.         end     \
  2453.         if menu then\
  2454.                 local pos = owner:GetPosition()\
  2455.                 self.Menu = self:AddObject(menu, {Type = 'Menu', Owner = owner, X = pos.X + x - 1, Y = pos.Y + y})\
  2456.         end\
  2457. end\
  2458. \
  2459. function ObjectClick(self, name, func)\
  2460.         self.ObjectClickHandlers[name] = func\
  2461. end\
  2462. \
  2463. function ClickObject(self, object, event, side, x, y)\
  2464.         if self.ObjectClickHandlers[object.Name] then\
  2465.                 return self.ObjectClickHandlers[object.Name](object, event, side, x, y)\
  2466.         end\
  2467.         return false\
  2468. end\
  2469. \
  2470. function ObjectUpdate(self, name, func)\
  2471.         self.ObjectUpdateHandlers[name] = func\
  2472. end\
  2473. \
  2474. function UpdateObject(self, object, ...)\
  2475.         if self.ObjectUpdateHandlers[object.Name] then\
  2476.                 self.ObjectUpdateHandlers[object.Name](object, ...)\
  2477.                 --self:Draw()\
  2478.         end\
  2479. end\
  2480. \
  2481. function GetAbsolutePosition(self, obj)\
  2482.         if not obj.Parent then\
  2483.                 return {X = obj.X, Y = obj.Y}\
  2484.         else\
  2485.                 local pos = self:GetAbsolutePosition(obj.Parent)\
  2486.                 local x = pos.X + obj.X - 1\
  2487.                 local y = pos.Y + obj.Y - 1\
  2488.                 if not obj.Fixed and obj.Parent.ChildOffset then\
  2489.                         x = x + obj.Parent.ChildOffset.X\
  2490.                         y = y + obj.Parent.ChildOffset.Y\
  2491.                 end\
  2492.                 return {X = x, Y = y}\
  2493.         end\
  2494. end\
  2495. \
  2496. function LoadView(self, name, draw)\
  2497.         if self.View and self.OnViewClose then\
  2498.                 self.OnViewClose(self.View.Name)\
  2499.         end\
  2500.         if self.View then\
  2501.                 self.View:OnRemove()\
  2502.         end\
  2503.         local success = false\
  2504. \
  2505.         if not fs.exists(self.ViewPath..name..'.view') then\
  2506.                 error('The view: '..name..'.view does not exist.')\
  2507.         end\
  2508. \
  2509.         local h = fs.open(self.ViewPath..name..'.view', 'r')\
  2510.         if h then\
  2511.                 local view = textutils.unserialize(h.readAll())\
  2512.                 h.close()\
  2513.                 if view then\
  2514.                         self.View = View:InitialiseFile(self, view, name)\
  2515.                         self:ReorderObjects()\
  2516. \
  2517.                         if OneOS and view.ToolBarColour then\
  2518.                                 OneOS.ToolBarColour = view.ToolBarColour\
  2519.                         end\
  2520.                         if OneOS and view.ToolBarTextColour then\
  2521.                                 OneOS.ToolBarTextColour = view.ToolBarTextColour\
  2522.                         end\
  2523.                         if not self:GetActiveObject() then\
  2524.                                 self:SetActiveObject()\
  2525.                         end\
  2526.                         success = true\
  2527.                 end\
  2528.         end\
  2529. \
  2530.         if success and self.OnViewLoad then\
  2531.                 self.OnViewLoad(name)\
  2532.         end\
  2533. \
  2534.         if draw ~= false then\
  2535.                 self:Draw()\
  2536.         end\
  2537. \
  2538.         if not success then\
  2539.                 error('Failed to load view: '..name..'. It probably isn\\'t formatted correctly. Did you forget a } or ,?')\
  2540.         end\
  2541. \
  2542.         return success\
  2543. end\
  2544. \
  2545. function InheritFile(self, file, name)\
  2546.         local h = fs.open(self.ViewPath..name..'.view', 'r')\
  2547.         if h then\
  2548.                 local super = textutils.unserialize(h.readAll())\
  2549.                 if super then\
  2550.                         if type(super) ~= 'table' then\
  2551.                                 error('View: \"'..name..'.view\" is not formatted correctly.')\
  2552.                         end\
  2553. \
  2554.                         for k, v in pairs(super) do\
  2555.                                 if not file[k] then\
  2556.                                         file[k] = v\
  2557.                                 end\
  2558.                         end\
  2559.                         return file\
  2560.                 end\
  2561.         end\
  2562.         return file\
  2563. end\
  2564. \
  2565. function ParseStringSize(self, parent, k, v)\
  2566.                 local parentSize = parent.Width\
  2567.                 if k == 'Height' or k == 'Y' then\
  2568.                         parentSize = parent.Height\
  2569.                 end\
  2570.                 local parts = {v}\
  2571.                 if type(v) == 'string' and string.find(v, ',') then\
  2572.                         parts = {}\
  2573.                         for word in string.gmatch(v, '([^,]+)') do\
  2574.                             table.insert(parts, word)\
  2575.                         end\
  2576.                 end\
  2577. \
  2578.                 v = 0\
  2579.                 for i2, part in ipairs(parts) do\
  2580.                         if type(part) == 'string' and part:sub(#part) == '%' then\
  2581.                                 v = v + math.ceil(parentSize * (tonumber(part:sub(1, #part-1)) / 100))\
  2582.                         else\
  2583.                                 v = v + tonumber(part)\
  2584.                         end\
  2585.                 end\
  2586.                 return v\
  2587. end\
  2588. \
  2589. function ObjectFromFile(self, file, view)\
  2590.         local env = getfenv()\
  2591.         if env[file.Type] then\
  2592.                 if not env[file.Type].Initialise then\
  2593.                         error('Malformed Object: '..file.Type)\
  2594.                 end\
  2595.                 local object = {}\
  2596. \
  2597.                 if file.InheritView then\
  2598.                         file = self:InheritFile(file, file.InheritView)\
  2599.                 end\
  2600.                 \
  2601.                 object.AutoWidth = true\
  2602.                 for k, v in pairs(file) do\
  2603.                         if k == 'Width' or k == 'X' or k == 'Height' or k == 'Y' then\
  2604.                                 v = self:ParseStringSize(view, k, v)\
  2605.                         end\
  2606. \
  2607.                         if k == 'Width' then\
  2608.                                 object.AutoWidth = false\
  2609.                         end\
  2610.                         if k ~= 'Children' then\
  2611.                                 object[k] = v\
  2612.                         else\
  2613.                                 object[k] = {}\
  2614.                         end\
  2615.                 end\
  2616. \
  2617.                 object.Parent = view\
  2618.                 object.Bedrock = self\
  2619.                 if not object.Name then\
  2620.                         object.Name = file.Type\
  2621.                 end\
  2622. \
  2623.                 object = env[file.Type]:Initialise(object)\
  2624. \
  2625.                 if file.Children then\
  2626.                         for i, obj in ipairs(file.Children) do\
  2627.                                 local _view = self:ObjectFromFile(obj, object)\
  2628.                                 if not _view.Z then\
  2629.                                         _view.Z = i\
  2630.                                 end\
  2631.                                 _view.Parent = object\
  2632.                                 table.insert(object.Children, _view)\
  2633.                         end\
  2634.                 end\
  2635. \
  2636.                 if not object.OnClick then\
  2637.                         object.OnClick = function(...) return self:ClickObject(...) end\
  2638.                 end\
  2639.                 --object.OnUpdate = function(...) self:UpdateObject(...) end\
  2640. \
  2641.                 if object.OnUpdate then\
  2642.                         for k, v in pairs(env[file.Type]) do\
  2643.                                 object:OnUpdate(k)\
  2644.                         end\
  2645. \
  2646.                         for k, v in pairs(object.__index) do\
  2647.                                 object:OnUpdate(k)\
  2648.                         end\
  2649.                 end\
  2650. \
  2651.                 if object.Active then\
  2652.                         object.Bedrock:SetActiveObject(object)\
  2653.                 end\
  2654.                 if object.OnLoad then\
  2655.                         object:OnLoad()\
  2656.                 end\
  2657.                 return object\
  2658.         elseif not file.Type then\
  2659.                 error('No object type specified. (e.g. Type = \"Button\")')\
  2660.         else\
  2661.                 error('No Object: '..file.Type..'. The API probably isn\\'t loaded')\
  2662.         end\
  2663. end\
  2664. \
  2665. function ReorderObjects(self)\
  2666.         if self.View and self.View.Children then\
  2667.                 table.sort(self.View.Children, function(a,b)\
  2668.                         return a.Z < b.Z \
  2669.                 end)\
  2670.         end\
  2671. end\
  2672. \
  2673. function AddObject(self, info, extra)\
  2674.         return self.View:AddObject(info, extra)\
  2675. end\
  2676. \
  2677. function GetObject(self, name)\
  2678.         return self.View:GetObject(name)\
  2679. end\
  2680. \
  2681. function GetObjects(self, name)\
  2682.         return self.View:GetObjects(name)\
  2683. end\
  2684. \
  2685. function RemoveObject(self, name)\
  2686.         return self.View:RemoveObject(name)\
  2687. end\
  2688. \
  2689. function RemoveObjects(self, name)\
  2690.         return self.View:RemoveObjects(name)\
  2691. end\
  2692. \
  2693. function ForceDraw(self)\
  2694.         if not self.DrawTimer or self.DrawTimerExpiry <= os.clock() then\
  2695.                 self.DrawTimer = self:StartTimer(function()\
  2696.                         self.DrawTimer = nil\
  2697.                         self:Draw()\
  2698.                 end, 0.05)\
  2699.                 self.DrawTimerExpiry = os.clock() + 0.1\
  2700.         end\
  2701. end\
  2702. \
  2703. function DisplayWindow(self, _view, title, canClose)\
  2704.         if canClose == nil then\
  2705.                 canClose = true\
  2706.         end\
  2707.         if type(_view) == 'string' then\
  2708.                 local h = fs.open(self.ViewPath.._view..'.view', 'r')\
  2709.                 if h then\
  2710.                         _view = textutils.unserialize(h.readAll())\
  2711.                         h.close()\
  2712.                 end\
  2713.         end\
  2714. \
  2715.         self.Window = self:AddObject({Type = 'Window', Z = 999, Title = title, CanClose = canClose})\
  2716.         _view.Type = 'View'\
  2717.         _view.Name = 'View'\
  2718.         _view.BackgroundColour = _view.BackgroundColour or colours.white\
  2719.         self.Window:SetView(self:ObjectFromFile(_view, self.Window))\
  2720. end\
  2721. \
  2722. function DisplayAlertWindow(self, title, text, buttons, callback)\
  2723.         local func = function(btn)\
  2724.                 self.Window:Close()\
  2725.                 if callback then\
  2726.                         callback(btn.Text)\
  2727.                 end\
  2728.         end\
  2729.         local children = {}\
  2730.         local usedX = -1\
  2731.         if buttons then\
  2732.                 for i, text in ipairs(buttons) do\
  2733.                         usedX = usedX + 3 + #text\
  2734.                         table.insert(children, {\
  2735.                                 [\"Y\"]=\"100%,-1\",\
  2736.                                 [\"X\"]=\"100%,-\"..usedX,\
  2737.                                 [\"Name\"]=text..\"Button\",\
  2738.                                 [\"Type\"]=\"Button\",\
  2739.                                 [\"Text\"]=text,\
  2740.                                 OnClick = func\
  2741.                         })\
  2742.                 end\
  2743.         end\
  2744. \
  2745.         local width = usedX + 2\
  2746.         if width < 28 then\
  2747.                 width = 28\
  2748.         end\
  2749. \
  2750.         local canClose = true\
  2751.         if buttons and #buttons~=0 then\
  2752.                 canClose = false\
  2753.         end\
  2754. \
  2755.         local height = 0\
  2756.         if text then\
  2757.                 height = #Helpers.WrapText(text, width - 2)\
  2758.                 table.insert(children, {\
  2759.                         [\"Y\"]=2,\
  2760.                         [\"X\"]=2,\
  2761.                         [\"Width\"]=\"100%,-2\",\
  2762.                         [\"Height\"]=height,\
  2763.                         [\"Name\"]=\"Label\",\
  2764.                         [\"Type\"]=\"Label\",\
  2765.                         [\"Text\"]=text\
  2766.                 })\
  2767.         end\
  2768.         local view = {\
  2769.                 Children = children,\
  2770.                 Width=width,\
  2771.                 Height=3+height+(canClose and 0 or 1),\
  2772.                 OnKeyChar = function(_view, keychar)\
  2773.                         func({Text=buttons[1]})\
  2774.                 end\
  2775.         }\
  2776.         self:DisplayWindow(view, title, canClose)\
  2777. end\
  2778. \
  2779. function DisplayTextBoxWindow(self, title, text, callback, textboxText, cursorAtEnd)\
  2780.         textboxText = textboxText or ''\
  2781.         local func = function(btn)\
  2782.                 self.Window:Close()\
  2783.                 if callback then\
  2784.                         callback(btn.Text)\
  2785.                 end\
  2786.         end\
  2787.         local children = {\
  2788.                 {\
  2789.                         [\"Y\"]=\"100%,-1\",\
  2790.                         [\"X\"]=\"100%,-4\",\
  2791.                         [\"Name\"]=\"OkButton\",\
  2792.                         [\"Type\"]=\"Button\",\
  2793.                         [\"Text\"]=\"Ok\",\
  2794.                         OnClick = function()\
  2795.                                 local text = self.Window:GetObject('TextBox').Text\
  2796.                                 self.Window:Close()\
  2797.                                 callback(true, text)\
  2798.                         end\
  2799.                 },\
  2800.                 {\
  2801.                         [\"Y\"]=\"100%,-1\",\
  2802.                         [\"X\"]=\"100%,-13\",\
  2803.                         [\"Name\"]=\"CancelButton\",\
  2804.                         [\"Type\"]=\"Button\",\
  2805.                         [\"Text\"]=\"Cancel\",\
  2806.                         OnClick = function()\
  2807.                                 self.Window:Close()\
  2808.                                 callback(false)\
  2809.                         end\
  2810.                 }\
  2811.         }\
  2812. \
  2813.         local height = -1\
  2814.         if text and #text ~= 0 then\
  2815.                 height = #Helpers.WrapText(text, 26)\
  2816.                 table.insert(children, {\
  2817.                         [\"Y\"]=2,\
  2818.                         [\"X\"]=2,\
  2819.                         [\"Width\"]=\"100%,-2\",\
  2820.                         [\"Height\"]=height,\
  2821.                         [\"Name\"]=\"Label\",\
  2822.                         [\"Type\"]=\"Label\",\
  2823.                         [\"Text\"]=text\
  2824.                 })\
  2825.         end\
  2826.         table.insert(children,\
  2827.                 {\
  2828.                         [\"Y\"]=3+height,\
  2829.                         [\"X\"]=2,\
  2830.                         [\"Width\"]=\"100%,-2\",\
  2831.                         [\"Name\"]=\"TextBox\",\
  2832.                         [\"Type\"]=\"TextBox\",\
  2833.                         [\"Text\"]=textboxText,\
  2834.                         [\"CursorPos\"]=(cursorAtEnd and 0 or nil)\
  2835.                 })\
  2836.         local view = {\
  2837.                 Children = children,\
  2838.                 Width=28,\
  2839.                 Height=5+height+(canClose and 0 or 1),\
  2840.         }\
  2841.         self:DisplayWindow(view, title)\
  2842.         self.Window:GetObject('TextBox').OnUpdate = function(txtbox, keychar)\
  2843.                 if keychar == keys.enter then\
  2844.                         self.Window:Close()\
  2845.                         callback(true, txtbox.Text)\
  2846.                 end\
  2847.         end\
  2848.         self:SetActiveObject(self.Window:GetObject('TextBox'))\
  2849.         self.Window.OnCloseButton = function()callback(false)end\
  2850. end\
  2851. \
  2852. function DisplayOpenFileWindow(self, title, callback)\
  2853.         title = title or 'Open File'\
  2854.         local func = function(btn)\
  2855.                 self.Window:Close()\
  2856.                 if callback then\
  2857.                         callback(btn.Text)\
  2858.                 end\
  2859.         end\
  2860. \
  2861.         local sidebarItems = {}\
  2862. \
  2863.         --this is a really, really super bad way of doing it\
  2864.         local separator = '                               !'\
  2865. \
  2866.         local function addFolder(path, level)\
  2867.                 for i, v in ipairs(fs.list(path)) do\
  2868.                         local fPath = path .. '/' .. v\
  2869.                         if fPath ~= '/rom' and fs.isDir(fPath) then\
  2870.                                 table.insert(sidebarItems, level .. v..separator..fPath)\
  2871.                                 addFolder(fPath, level .. '  ')\
  2872.                         end\
  2873.                 end\
  2874.         end\
  2875.         addFolder('','')\
  2876. \
  2877.         local currentFolder = ''\
  2878.         local selectedPath = nil\
  2879. \
  2880.         local goToFolder = nil\
  2881. \
  2882.         local children = {\
  2883.                 {\
  2884.                         [\"Y\"]=\"100%,-2\",\
  2885.                         [\"X\"]=1,\
  2886.                         [\"Height\"]=3,\
  2887.                         [\"Width\"]=\"100%\",\
  2888.                         [\"BackgroundColour\"]=colours.lightGrey,\
  2889.                         [\"Name\"]=\"SidebarListView\",\
  2890.                         [\"Type\"]=\"View\"\
  2891.                 },\
  2892.                 {\
  2893.                         [\"Y\"]=\"100%,-1\",\
  2894.                         [\"X\"]=\"100%,-4\",\
  2895.                         [\"Name\"]=\"OkButton\",\
  2896.                         [\"Type\"]=\"Button\",\
  2897.                         [\"Text\"]=\"Ok\",\
  2898.                         [\"BackgroundColour\"]=colours.white,\
  2899.                         [\"Enabled\"]=false,\
  2900.                         OnClick = function()\
  2901.                                 if selectedPath then\
  2902.                                         self.Window:Close()\
  2903.                                         callback(true, Helpers.TidyPath(selectedPath))\
  2904.                                 end\
  2905.                         end\
  2906.                 },\
  2907.                 {\
  2908.                         [\"Y\"]=\"100%,-1\",\
  2909.                         [\"X\"]=\"100%,-13\",\
  2910.                         [\"Name\"]=\"CancelButton\",\
  2911.                         [\"Type\"]=\"Button\",\
  2912.                         [\"Text\"]=\"Cancel\",\
  2913.                         [\"BackgroundColour\"]=colours.white,\
  2914.                         OnClick = function()\
  2915.                                 self.Window:Close()\
  2916.                                 callback(false)\
  2917.                         end\
  2918.                 },\
  2919.                 {\
  2920.                         [\"Y\"]=1,\
  2921.                         [\"X\"]=1,\
  2922.                         [\"Height\"]=\"100%,-3\",\
  2923.                         [\"Width\"]=\"40%,-1\",\
  2924.                         [\"Name\"]=\"SidebarListView\",\
  2925.                         [\"Type\"]=\"ListView\",\
  2926.                         [\"CanSelect\"]=true,\
  2927.                         [\"Items\"]={\
  2928.                                 [\"Computer\"] = sidebarItems\
  2929.                         },\
  2930.                         OnSelect = function(listView, text)\
  2931.                                 local _,s = text:find(separator)\
  2932.                                 if s then\
  2933.                                         local path = text:sub(s + 1)\
  2934.                                         goToFolder(path)\
  2935.                                 end\
  2936.                         end,\
  2937.                         OnClick = function(listView, event, side, x, y)\
  2938.                                 if y == 1 then\
  2939.                                         goToFolder('/')\
  2940.                                 end\
  2941.                         end\
  2942.                 },\
  2943.                 {\
  2944.                         [\"Y\"]=1,\
  2945.                         [\"X\"]=\"40%\",\
  2946.                         [\"Height\"]=\"100%,-3\",\
  2947.                         [\"Width\"]=1,\
  2948.                         [\"Type\"]=\"Separator\"\
  2949.                 },\
  2950.                 {\
  2951.                         [\"Y\"]=1,\
  2952.                         [\"X\"]=\"40%,2\",\
  2953.                         [\"Width\"]=\"65%,-3\",\
  2954.                         [\"Height\"]=1,\
  2955.                         [\"Type\"]=\"Label\",\
  2956.                         [\"Name\"]=\"PathLabel\",\
  2957.                         [\"TextColour\"]=colours.lightGrey,\
  2958.                         [\"Text\"]='/hello/there'\
  2959.                 },\
  2960.                 {\
  2961.                         [\"Y\"]=2,\
  2962.                         [\"X\"]=\"40%,1\",\
  2963.                         [\"Height\"]=\"100%,-4\",\
  2964.                         [\"Width\"]=\"65%,-1\",\
  2965.                         [\"Name\"]=\"FilesListView\",\
  2966.                         [\"Type\"]=\"ListView\",\
  2967.                         [\"CanSelect\"]=true,\
  2968.                         [\"Items\"]={},\
  2969.                         OnSelect = function(listView, text)\
  2970.                                 selectedPath = Helpers.TidyPath(currentFolder .. '/' .. text)\
  2971.                                 self.Window:GetObject('OkButton').Enabled = true\
  2972.                         end,\
  2973.                         OnClick = function(listView, event, side, x, y)\
  2974.                                 if y == 1 then\
  2975.                                         goToFolder('/')\
  2976.                                 end\
  2977.                         end\
  2978.                 },\
  2979.         }\
  2980.         local view = {\
  2981.                 Children = children,\
  2982.                 Width=40,\
  2983.                 Height= Drawing.Screen.Height - 4\
  2984.         }\
  2985.         self:DisplayWindow(view, title)\
  2986. \
  2987.         goToFolder = function(path)\
  2988.                 path = Helpers.TidyPath(path)\
  2989.                 self.Window:GetObject('PathLabel').Text = path\
  2990.                 currentFolder = path\
  2991. \
  2992.                 local filesListItems = {}\
  2993.                 for i, v in ipairs(fs.list(path)) do\
  2994.                         if not fs.isDir(currentFolder .. v) then\
  2995.                                 table.insert(filesListItems, v)\
  2996.                         end\
  2997.                 end\
  2998.                 self.Window:GetObject('OkButton').Enabled = false\
  2999.                 selectedPath = nil\
  3000.                 self.Window:GetObject('FilesListView').Items = filesListItems\
  3001. \
  3002.         end\
  3003. \
  3004.         goToFolder('')\
  3005. \
  3006.         self.Window.OnCloseButton = function()callback(false)end\
  3007. end\
  3008. \
  3009. function RegisterEvent(self, event, func)\
  3010.         if not self.EventHandlers[event] then\
  3011.                 self.EventHandlers[event] = {}\
  3012.         end\
  3013.         table.insert(self.EventHandlers[event], func)\
  3014. end\
  3015. \
  3016. function StartRepeatingTimer(self, func, interval)\
  3017.         local int = interval\
  3018.         if type(int) == 'function' then\
  3019.                 int = int()\
  3020.         end\
  3021.         if not int or int <= 0 then\
  3022.                 return\
  3023.         end\
  3024.         local timer = os.startTimer(int)\
  3025. \
  3026.         self.Timers[timer] = {func, true, interval}\
  3027.         return timer\
  3028. end\
  3029. \
  3030. function StartTimer(self, func, delay)\
  3031.         local timer = os.startTimer(delay)\
  3032.         self.Timers[timer] = {func, false}\
  3033.         return timer\
  3034. end\
  3035. \
  3036. function StopTimer(self, timer)\
  3037.         if self.Timers[timer] then\
  3038.                 self.Timers[timer] = nil\
  3039.         end\
  3040. end\
  3041. \
  3042. function HandleTimer(self, event, timer)\
  3043.         if self.Timers[timer] then\
  3044.                 local oldTimer = self.Timers[timer]\
  3045.                 self.Timers[timer] = nil\
  3046.                 local new = nil\
  3047.                 if oldTimer[2] then\
  3048.                         new = self:StartRepeatingTimer(oldTimer[1], oldTimer[3])\
  3049.                 end\
  3050.                 if oldTimer and oldTimer[1] then\
  3051.                         oldTimer[1](new)\
  3052.                 end\
  3053.         elseif self.OnTimer then\
  3054.                 self.OnTimer(self, event, timer)\
  3055.         end\
  3056. end\
  3057. \
  3058. function SetActiveObject(self, object)\
  3059.         if object then\
  3060.                 if object ~= self.ActiveObject then\
  3061.                         self.ActiveObject = object\
  3062.                         object:ForceDraw()\
  3063.                 end\
  3064.         elseif self.ActiveObject ~= nil then\
  3065.                 self.ActiveObject = nil\
  3066.                 self.CursorPos = nil\
  3067.                 self.View:ForceDraw()\
  3068.         end\
  3069. end\
  3070. \
  3071. function GetActiveObject(self)\
  3072.         return self.ActiveObject\
  3073. end\
  3074. \
  3075. OnTimer = nil\
  3076. OnClick = nil\
  3077. OnKeyChar = nil\
  3078. OnDrag = nil\
  3079. OnScroll = nil\
  3080. OnViewLoad = nil\
  3081. OnViewClose = nil\
  3082. OnDraw = nil\
  3083. OnQuit = nil\
  3084. \
  3085. local eventFuncs = {\
  3086.         OnClick = {'mouse_click', 'monitor_touch'},\
  3087.         OnKeyChar = {'key', 'char'},\
  3088.         OnDrag = {'mouse_drag'},\
  3089.         OnScroll = {'mouse_scroll'},\
  3090.         HandleClick = {'mouse_click', 'mouse_drag', 'mouse_scroll', 'monitor_touch'},\
  3091.         HandleKeyChar = {'key', 'char'},\
  3092.         HandleTimer = {'timer'}\
  3093. }\
  3094. \
  3095. local drawCalls = 0\
  3096. local ignored = 0\
  3097. function Draw(self)\
  3098.         self.IsDrawing = true\
  3099.         if self.OnDraw then\
  3100.                 self:OnDraw()\
  3101.         end\
  3102. \
  3103.         if self.View and self.View:NeedsDraw() then\
  3104.                 self.View:Draw()\
  3105.                 Drawing.DrawBuffer()\
  3106.                 if isDebug then\
  3107.                         drawCalls = drawCalls + 1\
  3108.                 end\
  3109.         elseif not self.View then\
  3110.                 print('No loaded view. You need to do program:LoadView first.')\
  3111.         end     \
  3112. \
  3113.         if self:GetActiveObject() and self.CursorPos and type(self.CursorPos[1]) == 'number' and type(self.CursorPos[2]) == 'number' then\
  3114.                 term.setCursorPos(self.CursorPos[1], self.CursorPos[2])\
  3115.                 term.setTextColour(self.CursorColour)\
  3116.                 term.setCursorBlink(true)\
  3117.         else\
  3118.                 term.setCursorBlink(false)\
  3119.         end\
  3120. \
  3121.         self.IsDrawing = false\
  3122. end\
  3123. \
  3124. function EventHandler(self)\
  3125.         local event = { os.pullEventRaw() }\
  3126.         \
  3127.         if self.EventHandlers[event[1]] then\
  3128.                 for i, e in ipairs(self.EventHandlers[event[1]]) do\
  3129.                         e(self, unpack(event))\
  3130.                 end\
  3131.         end\
  3132. end\
  3133. \
  3134. function Quit(self)\
  3135.         self.Running = false\
  3136.         if self.OnQuit then\
  3137.                 self:OnQuit()\
  3138.         end\
  3139.         if OneOS then\
  3140.                 OneOS.Close()\
  3141.         end\
  3142. end\
  3143. \
  3144. function Run(self, ready)\
  3145.         for name, events in pairs(eventFuncs) do\
  3146.                 if self[name] then\
  3147.                         for i, event in ipairs(events) do\
  3148.                                 self:RegisterEvent(event, self[name])\
  3149.                         end\
  3150.                 end\
  3151.         end\
  3152. \
  3153.         if self.AllowTerminate then\
  3154.                 self:RegisterEvent('terminate', function()error('Terminated', 0) end)\
  3155.         end\
  3156. \
  3157.         if self.DefaultView and self.DefaultView ~= '' and fs.exists(self.ViewPath..self.DefaultView..'.view') then\
  3158.                 self:LoadView(self.DefaultView)\
  3159.         end\
  3160. \
  3161.         if ready then\
  3162.                 ready()\
  3163.         end\
  3164.         \
  3165.         self:Draw()\
  3166. \
  3167.         while self.Running do\
  3168.                 self:EventHandler()\
  3169.         end\
  3170. end",
  3171.   Peripheral = "GetPeripheral = function(_type)\
  3172.         for i, p in ipairs(GetPeripherals()) do\
  3173.                 if p.Type == _type then\
  3174.                         return p\
  3175.                 end\
  3176.         end\
  3177. end\
  3178. \
  3179. Call = function(type, ...)\
  3180.         local tArgs = {...}\
  3181.         local p = GetPeripheral(type)\
  3182.         peripheral.call(p.Side, unpack(tArgs))\
  3183. end\
  3184. \
  3185. local getNames = peripheral.getNames or function()\
  3186.         local tResults = {}\
  3187.         for n,sSide in ipairs( rs.getSides() ) do\
  3188.                 if peripheral.isPresent( sSide ) then\
  3189.                         table.insert( tResults, sSide )\
  3190.                         local isWireless = false\
  3191.                         if pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then\
  3192.                                 isWireless = true\
  3193.                         end     \
  3194.                         if peripheral.getType( sSide ) == \"modem\" and not isWireless then\
  3195.                                 local tRemote = peripheral.call( sSide, \"getNamesRemote\" )\
  3196.                                 for n,sName in ipairs( tRemote ) do\
  3197.                                         table.insert( tResults, sName )\
  3198.                                 end\
  3199.                         end\
  3200.                 end\
  3201.         end\
  3202.         return tResults\
  3203. end\
  3204. \
  3205. GetPeripherals = function(filterType)\
  3206.         local peripherals = {}\
  3207.         for i, side in ipairs(getNames()) do\
  3208.                 local name = peripheral.getType(side):gsub(\"^%l\", string.upper)\
  3209.                 local code = string.upper(side:sub(1,1))\
  3210.                 if side:find('_') then\
  3211.                         code = side:sub(side:find('_')+1)\
  3212.                 end\
  3213. \
  3214.                 local dupe = false\
  3215.                 for i, v in ipairs(peripherals) do\
  3216.                         if v[1] == name .. ' ' .. code then\
  3217.                                 dupe = true\
  3218.                         end\
  3219.                 end\
  3220. \
  3221.                 if not dupe then\
  3222.                         local _type = peripheral.getType(side)\
  3223.                         local formattedType = _type:sub(1, 1):upper() .. _type:sub(2, -1)\
  3224.                         local isWireless = false\
  3225.                         if _type == 'modem' then\
  3226.                                 if not pcall(function()isWireless = peripheral.call(side, 'isWireless') end) then\
  3227.                                         isWireless = true\
  3228.                                 end     \
  3229.                                 if isWireless then\
  3230.                                         _type = 'wireless_modem'\
  3231.                                         formattedType = 'Wireless Modem'\
  3232.                                         name = 'W '..name\
  3233.                                 end\
  3234.                         end\
  3235.                         if not filterType or _type == filterType then\
  3236.                                 table.insert(peripherals, {Name = name:sub(1,8) .. ' '..code, Fullname = name .. ' ('..side:sub(1, 1):upper() .. side:sub(2, -1)..')', Side = side, Type = _type, Wireless = isWireless, FormattedType = formattedType})\
  3237.                         end\
  3238.                 end\
  3239.         end\
  3240.         return peripherals\
  3241. end\
  3242. \
  3243. GetSide = function(side)\
  3244.         for i, p in ipairs(GetPeripherals()) do\
  3245.                 if p.Side == side then\
  3246.                         return p\
  3247.                 end\
  3248.         end\
  3249. end\
  3250. \
  3251. PresentNamed = function(name)\
  3252.         return peripheral.isPresent(name)\
  3253. end\
  3254. \
  3255. CallType = function(type, ...)\
  3256.         local tArgs = {...}\
  3257.         local p = GetPeripheral(type)\
  3258.         return peripheral.call(p.Side, unpack(tArgs))\
  3259. end\
  3260. \
  3261. CallNamed = function(name, ...)\
  3262.         local tArgs = {...}\
  3263.         return peripheral.call(name, unpack(tArgs))\
  3264. end\
  3265. \
  3266. GetInfo = function(p)\
  3267.         local info = {}\
  3268.         local buttons = {}\
  3269.         if p.Type == 'computer' then\
  3270.                 local id = peripheral.call(p.Side:lower(),'getID')\
  3271.                 if id then\
  3272.                         info = {\
  3273.                                 ID = tostring(id)\
  3274.                         }\
  3275.                 else\
  3276.                         info = {}\
  3277.                 end\
  3278.         elseif p.Type == 'drive' then\
  3279.                 local discType = 'No Disc'\
  3280.                 local discID = nil\
  3281.                 local mountPath = nil\
  3282.                 local discLabel = nil\
  3283.                 local songName = nil\
  3284.                 if peripheral.call(p.Side:lower(), 'isDiskPresent') then\
  3285.                         if peripheral.call(p.Side:lower(), 'hasData') then\
  3286.                                 discType = 'Data'\
  3287.                                 discID = peripheral.call(p.Side:lower(), 'getDiskID')\
  3288.                                 if discID then\
  3289.                                         discID = tostring(discID)\
  3290.                                 else\
  3291.                                         discID = 'None'\
  3292.                                 end\
  3293.                                 mountPath = '/'..peripheral.call(p.Side:lower(), 'getMountPath')..'/'\
  3294.                                 discLabel = peripheral.call(p.Side:lower(), 'getDiskLabel')\
  3295.                         else\
  3296.                                 discType = 'Audio'\
  3297.                                 songName = peripheral.call(p.Side:lower(), 'getAudioTitle')\
  3298.                         end\
  3299.                 end\
  3300.                 if mountPath then\
  3301.                         table.insert(buttons, {Text = 'View Files', OnClick = function(self, event, side, x, y)GoToPath(mountPath)end})\
  3302.                 elseif discType == 'Audio' then\
  3303.                         table.insert(buttons, {Text = 'Play', OnClick = function(self, event, side, x, y)\
  3304.                                 if self.Text == 'Play' then\
  3305.                                         disk.playAudio(p.Side:lower())\
  3306.                                         self.Text = 'Stop'\
  3307.                                 else\
  3308.                                         disk.stopAudio(p.Side:lower())\
  3309.                                         self.Text = 'Play'\
  3310.                                 end\
  3311.                         end})\
  3312.                 else\
  3313.                         diskOpenButton = nil\
  3314.                 end\
  3315.                 if discType ~= 'No Disc' then\
  3316.                         table.insert(buttons, {Text = 'Eject', OnClick = function(self, event, side, x, y)disk.eject(p.Side:lower()) sleep(0) RefreshFiles() end})\
  3317.                 end\
  3318. \
  3319.                 info = {\
  3320.                         ['Disc Type'] = discType,\
  3321.                         ['Disc Label'] = discLabel,\
  3322.                         ['Song Title'] = songName,\
  3323.                         ['Disc ID'] = discID,\
  3324.                         ['Mount Path'] = mountPath\
  3325.                 }\
  3326.         elseif p.Type == 'printer' then\
  3327.                 local pageSize = 'No Loaded Page'\
  3328.                 local _, err = pcall(function() return tostring(peripheral.call(p.Side:lower(), 'getPgaeSize')) end)\
  3329.                 if not err then\
  3330.                         pageSize = tostring(peripheral.call(p.Side:lower(), 'getPageSize'))\
  3331.                 end\
  3332.                 info = {\
  3333.                         ['Paper Level'] = tostring(peripheral.call(p.Side:lower(), 'getPaperLevel')),\
  3334.                         ['Paper Size'] = pageSize,\
  3335.                         ['Ink Level'] = tostring(peripheral.call(p.Side:lower(), 'getInkLevel'))\
  3336.                 }\
  3337.         elseif p.Type == 'modem' then\
  3338.                 info = {\
  3339.                         ['Connected Peripherals'] = tostring(#peripheral.call(p.Side:lower(), 'getNamesRemote'))\
  3340.                 }\
  3341.         elseif p.Type == 'monitor' then\
  3342.                 local w, h = peripheral.call(p.Side:lower(), 'getSize')\
  3343.                 local screenType = 'Black and White'\
  3344.                 if peripheral.call(p.Side:lower(), 'isColour') then\
  3345.                         screenType = 'Colour'\
  3346.                 end\
  3347.                 local buttonTitle = 'Use as Screen'\
  3348.                 if OneOS.Settings:GetValues()['Monitor'] == p.Side:lower() then\
  3349.                         buttonTitle = 'Use Computer Screen'\
  3350.                 end\
  3351.                 table.insert(buttons, {Text = buttonTitle, OnClick = function(self, event, side, x, y)\
  3352.                                 self.Bedrock:DisplayAlertWindow('Reboot Required', \"To change screen you'll need to reboot your computer.\", {'Reboot', 'Cancel'}, function(value)\
  3353.                                         if value == 'Reboot' then\
  3354.                                                 if buttonTitle == 'Use Computer Screen' then\
  3355.                                                         OneOS.Settings:SetValue('Monitor', nil)\
  3356.                                                 else\
  3357.                                                         OneOS.Settings:SetValue('Monitor', p.Side:lower())\
  3358.                                                 end\
  3359.                                                 OneOS.Reboot()\
  3360.                                         end\
  3361.                                 end)\
  3362.                         end\
  3363.                 })\
  3364.                 info = {\
  3365.                         ['Type'] = screenType,\
  3366.                         ['Width'] = tostring(w),\
  3367.                         ['Height'] = tostring(h),\
  3368.                 }\
  3369.         end\
  3370.         info.Buttons = buttons\
  3371.         return info\
  3372. end",
  3373.   hash = "--\
  3374. --  Thanks to GravityScore for this!\
  3375. --  http://www.computercraft.info/forums2/index.php?/topic/8169-sha-256-in-pure-lua/\
  3376. --\
  3377. --  This is used to hash passwords sent with the secure text field. It just reduces the chance of people getting hacked.\
  3378. --\
  3379. \
  3380. --  \
  3381. --  Adaptation of the Secure Hashing Algorithm (SHA-244/256)\
  3382. --  Found Here: http://lua-users.org/wiki/SecureHashAlgorithm\
  3383. --  \
  3384. --  Using an adapted version of the bit library\
  3385. --  Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua\
  3386. --  \
  3387. \
  3388. local MOD = 2^32\
  3389. local MODM = MOD-1\
  3390. \
  3391. local function memoize(f)\
  3392.         local mt = {}\
  3393.         local t = setmetatable({}, mt)\
  3394.         function mt:__index(k)\
  3395.                 local v = f(k)\
  3396.                 t[k] = v\
  3397.                 return v\
  3398.         end\
  3399.         return t\
  3400. end\
  3401. \
  3402. local function make_bitop_uncached(t, m)\
  3403.         local function bitop(a, b)\
  3404.                 local res,p = 0,1\
  3405.                 while a ~= 0 and b ~= 0 do\
  3406.                         local am, bm = a % m, b % m\
  3407.                         res = res + t[am][bm] * p\
  3408.                         a = (a - am) / m\
  3409.                         b = (b - bm) / m\
  3410.                         p = p*m\
  3411.                 end\
  3412.                 res = res + (a + b) * p\
  3413.                 return res\
  3414.         end\
  3415.         return bitop\
  3416. end\
  3417. \
  3418. local function make_bitop(t)\
  3419.         local op1 = make_bitop_uncached(t,2^1)\
  3420.         local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)\
  3421.         return make_bitop_uncached(op2, 2 ^ (t.n or 1))\
  3422. end\
  3423. \
  3424. local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})\
  3425. \
  3426. local function bxor(a, b, c, ...)\
  3427.         local z = nil\
  3428.         if b then\
  3429.                 a = a % MOD\
  3430.                 b = b % MOD\
  3431.                 z = bxor1(a, b)\
  3432.                 if c then z = bxor(z, c, ...) end\
  3433.                 return z\
  3434.         elseif a then return a % MOD\
  3435.         else return 0 end\
  3436. end\
  3437. \
  3438. local function band(a, b, c, ...)\
  3439.         local z\
  3440.         if b then\
  3441.                 a = a % MOD\
  3442.                 b = b % MOD\
  3443.                 z = ((a + b) - bxor1(a,b)) / 2\
  3444.                 if c then z = bit32_band(z, c, ...) end\
  3445.                 return z\
  3446.         elseif a then return a % MOD\
  3447.         else return MODM end\
  3448. end\
  3449. \
  3450. local function bnot(x) return (-1 - x) % MOD end\
  3451. \
  3452. local function rshift1(a, disp)\
  3453.         if disp < 0 then return lshift(a,-disp) end\
  3454.         return math.floor(a % 2 ^ 32 / 2 ^ disp)\
  3455. end\
  3456. \
  3457. local function rshift(x, disp)\
  3458.         if disp > 31 or disp < -31 then return 0 end\
  3459.         return rshift1(x % MOD, disp)\
  3460. end\
  3461. \
  3462. local function lshift(a, disp)\
  3463.         if disp < 0 then return rshift(a,-disp) end \
  3464.         return (a * 2 ^ disp) % 2 ^ 32\
  3465. end\
  3466. \
  3467. local function rrotate(x, disp)\
  3468.    x = x % MOD\
  3469.    disp = disp % 32\
  3470.    local low = band(x, 2 ^ disp - 1)\
  3471.    return rshift(x, disp) + lshift(low, 32 - disp)\
  3472. end\
  3473. \
  3474. local k = {\
  3475.         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\
  3476.         0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\
  3477.         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\
  3478.         0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\
  3479.         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\
  3480.         0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\
  3481.         0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\
  3482.         0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\
  3483.         0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\
  3484.         0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\
  3485.         0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\
  3486.         0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\
  3487.         0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\
  3488.         0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\
  3489.         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\
  3490.         0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\
  3491. }\
  3492. \
  3493. local function str2hexa(s)\
  3494.         return (string.gsub(s, \".\", function(c) return string.format(\"%02x\", string.byte(c)) end))\
  3495. end\
  3496. \
  3497. local function num2s(l, n)\
  3498.         local s = \"\"\
  3499.         for i = 1, n do\
  3500.                 local rem = l % 256\
  3501.                 s = string.char(rem) .. s\
  3502.                 l = (l - rem) / 256\
  3503.         end\
  3504.         return s\
  3505. end\
  3506. \
  3507. local function s232num(s, i)\
  3508.         local n = 0\
  3509.         for i = i, i + 3 do n = n*256 + string.byte(s, i) end\
  3510.         return n\
  3511. end\
  3512. \
  3513. local function preproc(msg, len)\
  3514.         local extra = 64 - ((len + 9) % 64)\
  3515.         len = num2s(8 * len, 8)\
  3516.         msg = msg .. \"\\128\" .. string.rep(\"\\0\", extra) .. len\
  3517.         assert(#msg % 64 == 0)\
  3518.         return msg\
  3519. end\
  3520. \
  3521. local function initH256(H)\
  3522.         H[1] = 0x6a09e667\
  3523.         H[2] = 0xbb67ae85\
  3524.         H[3] = 0x3c6ef372\
  3525.         H[4] = 0xa54ff53a\
  3526.         H[5] = 0x510e527f\
  3527.         H[6] = 0x9b05688c\
  3528.         H[7] = 0x1f83d9ab\
  3529.         H[8] = 0x5be0cd19\
  3530.         return H\
  3531. end\
  3532. \
  3533. local function digestblock(msg, i, H)\
  3534.         local w = {}\
  3535.         for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end\
  3536.         for j = 17, 64 do\
  3537.                 local v = w[j - 15]\
  3538.                 local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))\
  3539.                 v = w[j - 2]\
  3540.                 w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))\
  3541.         end\
  3542. \
  3543.         local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]\
  3544.         for i = 1, 64 do\
  3545.                 local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))\
  3546.                 local maj = bxor(band(a, b), band(a, c), band(b, c))\
  3547.                 local t2 = s0 + maj\
  3548.                 local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))\
  3549.                 local ch = bxor (band(e, f), band(bnot(e), g))\
  3550.                 local t1 = h + s1 + ch + k[i] + w[i]\
  3551.                 h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2\
  3552.         end\
  3553. \
  3554.         H[1] = band(H[1] + a)\
  3555.         H[2] = band(H[2] + b)\
  3556.         H[3] = band(H[3] + c)\
  3557.         H[4] = band(H[4] + d)\
  3558.         H[5] = band(H[5] + e)\
  3559.         H[6] = band(H[6] + f)\
  3560.         H[7] = band(H[7] + g)\
  3561.         H[8] = band(H[8] + h)\
  3562. end\
  3563. \
  3564. function sha256(msg)\
  3565.         msg = preproc(msg, #msg)\
  3566.         local H = initH256({})\
  3567.         for i = 1, #msg, 64 do digestblock(msg, i, H) end\
  3568.         return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..\
  3569.                 num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))\
  3570. end",
  3571.   r = "os.reboot()",
  3572.   Wireless = "--This is just the OneOS Wireless API\
  3573. \
  3574. --OneOS uses channels between 4200 and 4300, avoid use where possible\
  3575. \
  3576. Channels = {\
  3577.         Ignored = 4299,\
  3578.         Ping = 4200,\
  3579.         PingReply = 4201,\
  3580.         oeedPayServerAvailable = 4260,\
  3581.         oeedPayServerAvailableReply = 4261,\
  3582.         oeedPayPocketPayPing = 4262,\
  3583.         oeedPayPocketPayPingReply = 4263,\
  3584.         oeedPayPocketPayPaymentInfo = 4264,\
  3585.         oeedPayPocketPayPaymentInfoReply = 4265,\
  3586.         oeedPayValidatePayment = 4266,\
  3587.         oeedPayValidatePaymentReply = 4267,\
  3588.         oeedPayPocketPayChallenge = 4268,\
  3589.         oeedPayPocketPayChallengeReply = 4269,\
  3590.         oeedPayPocketPayChallengeAnswer = 4270,\
  3591.         oeedPayPocketPayChallengeAnswerReply = 4271,\
  3592.         oeedPayPocketPayResult = 4272,\
  3593.         oeedPayBalanceCheck = 4273,\
  3594.         oeedPayBalanceCheckReply = 4274,\
  3595.         oeedPayAPIRequest = 4275,\
  3596.         oeedPayAPIRequestReply = 4276,\
  3597.         oeedPayNewAccount = 4277,\
  3598.         oeedPayNewAccountReply = 4278,\
  3599.         oeedPayGetAccountName = 4279,\
  3600.         oeedPayGetAccountNameReply = 4280,\
  3601. }\
  3602. \
  3603. local function isOpen(channel)\
  3604.         return Peripheral.CallType('wireless_modem', 'isOpen', channel)\
  3605. end\
  3606. \
  3607. local function open(channel)\
  3608.         if not isOpen(channel) then\
  3609.                 Peripheral.CallType('wireless_modem', 'open', channel)\
  3610.         end\
  3611. end\
  3612. \
  3613. Open = open\
  3614. \
  3615. local function close(channel)\
  3616.         Peripheral.CallType('wireless_modem', 'close', channel)\
  3617. end\
  3618. \
  3619. local function closeAll()\
  3620.         Peripheral.CallType('wireless_modem', 'closeAll')\
  3621. end\
  3622. \
  3623. local function transmit(channel, replyChannel, message)\
  3624.         Peripheral.CallType('wireless_modem', 'transmit', channel, replyChannel, textutils.serialize(message))\
  3625. end\
  3626. \
  3627. function Present()\
  3628.         if Peripheral.GetPeripheral('wireless_modem') == nil then\
  3629.                 return false\
  3630.         else\
  3631.                 return true\
  3632.         end\
  3633. end\
  3634. \
  3635. local function FormatMessage(message, messageID, destinationID)\
  3636.         return {\
  3637.                 content = textutils.serialize(message),\
  3638.                 senderID = os.getComputerID(),\
  3639.                 senderName = os.getComputerLabel(),\
  3640.                 channel = channel,\
  3641.                 replyChannel = reply,\
  3642.                 messageID = messageID or math.random(10000),\
  3643.                 destinationID = destinationID\
  3644.         }\
  3645. end\
  3646. \
  3647. local Timeout = function(func, time)\
  3648.         time = time or 1\
  3649.         parallel.waitForAny(func, function()\
  3650.                 sleep(time)\
  3651.                 --log('Timeout!'..time)\
  3652.         end)\
  3653. end\
  3654. \
  3655. RecieveMessage = function(_channel, messageID, timeout)\
  3656.         open(_channel)\
  3657.         local done = false\
  3658.         local event, side, channel, replyChannel, message = nil\
  3659.         Timeout(function()\
  3660.                 while not done do\
  3661.                         event, side, channel, replyChannel, message = os.pullEvent('modem_message')\
  3662.                         if channel ~= _channel then\
  3663.                                 event, side, channel, replyChannel, message = nil\
  3664.                         else\
  3665.                                 message = textutils.unserialize(message)\
  3666.                                 message.content = textutils.unserialize(message.content)\
  3667.                                 if messageID and messageID ~= message.messageID or (message.destinationID ~= nil and message.destinationID ~= os.getComputerID()) then\
  3668.                                         event, side, channel, replyChannel, message = nil\
  3669.                                 else\
  3670.                                         done = true\
  3671.                                 end\
  3672.                         end\
  3673.                 end\
  3674.         end,\
  3675.         timeout)\
  3676.         return event, side, channel, replyChannel, message\
  3677. end\
  3678. \
  3679. Initialise = function()\
  3680.         if Present() then\
  3681.                 for i, c in pairs(Channels) do\
  3682.                         open(c)\
  3683.                 end\
  3684.         end\
  3685. end\
  3686. \
  3687. HandleMessage = function(event, side, channel, replyChannel, message, distance)\
  3688.         message = textutils.unserialize(message)\
  3689.         message.content = textutils.unserialize(message.content)\
  3690. \
  3691.         if channel == Channels.Ping then\
  3692.                 if message.content == 'Ping!' then\
  3693.                         SendMessage(replyChannel, 'Pong!', nil, message.messageID)\
  3694.                 end\
  3695.         elseif message.destinationID ~= nil and message.destinationID ~= os.getComputerID() then\
  3696.         elseif Wireless.Responder then\
  3697.                 Wireless.Responder(event, side, channel, replyChannel, message, distance)\
  3698.         end\
  3699. end\
  3700. \
  3701. SendMessage = function(channel, message, reply, messageID, destinationID)\
  3702.         reply = reply or channel + 1\
  3703.         open(channel)\
  3704.         open(reply)\
  3705.         local _message = FormatMessage(message, messageID, destinationID)\
  3706.         transmit(channel, reply, _message)\
  3707.         return _message\
  3708. end\
  3709. \
  3710. Ping = function()\
  3711.         local message = SendMessage(Channels.Ping, 'Ping!', Channels.PingReply)\
  3712.         RecieveMessage(Channels.PingReply, message.messageID)\
  3713. end",
  3714.   Objects = {
  3715.     [ "KeyboardView.lua" ] = "Inherit = 'View'\
  3716. OnDone = nil\
  3717. \
  3718. OnLoad = function(self)\
  3719.         local buttons = self:GetObjects('Button')\
  3720.         local okButton = self:GetObject('OkButton')\
  3721.         local backspaceButton = self:GetObject('BackspaceButton')\
  3722. \
  3723.         for i, v in ipairs(buttons) do\
  3724.                 v.OnClick = function(btn, event, side, x, y)\
  3725.                         local char = v.Text\
  3726.                         if char == '_' then\
  3727.                                 char = ' '\
  3728.                         end\
  3729.                         os.queueEvent('char', char)\
  3730.                 end\
  3731.         end\
  3732. \
  3733.         backspaceButton.OnClick = function(btn, event, side, x, y)\
  3734.                 os.queueEvent('key', keys.backspace)\
  3735.         end\
  3736. \
  3737.         okButton.OnClick = function(btn, event, side, x, y)\
  3738.                 if self.OnDone then\
  3739.                         self:OnDone()\
  3740.                 end\
  3741.         end\
  3742. end",
  3743.   },
  3744.   Views = {
  3745.     [ "insertold.view" ] = "{\
  3746.  [\"Children\"]={\
  3747.    [1]={\
  3748.      [\"Y\"]=1,\
  3749.      [\"X\"]=1,\
  3750.      [\"Height\"]=\"100%\",\
  3751.      [\"Width\"]=\"100%\",\
  3752.      [\"Type\"]=\"View\",\
  3753.      [\"BackgroundColour\"]=1,\
  3754.      [\"Children\"]={\
  3755.        [1]={\
  3756.          [\"Y\"]=\"100%\",\
  3757.          [\"X\"]=5,\
  3758.          [\"Type\"]=\"Label\",\
  3759.          [\"TextColour\"]=256,\
  3760.          [\"Text\"]=\"oeed\"\
  3761.        },\
  3762.        [2]={\
  3763.          [\"Y\"]=\"100%\",\
  3764.          [\"X\"]=9,\
  3765.          [\"Type\"]=\"Label\",\
  3766.          [\"TextColour\"]=128,\
  3767.          [\"Text\"]=\"Pay\"\
  3768.        },\
  3769.        [3]={\
  3770.          [\"Y\"]=2,\
  3771.          [\"X\"]=1,\
  3772.          [\"Width\"]=\"100%\",\
  3773.          [\"Type\"]=\"Label\",\
  3774.          [\"Align\"]=\"Center\",\
  3775.          [\"Text\"]=\"Insert Old Card\",\
  3776.          [\"TextColour\"]=128,\
  3777.        },\
  3778.        [4]={\
  3779.          [\"Y\"]=5,\
  3780.          [\"X\"]=1,\
  3781.          [\"Width\"]=\"100%\",\
  3782.          [\"Type\"]=\"Label\",\
  3783.          [\"Align\"]=\"Center\",\
  3784.          [\"Text\"]=\"If you've lost your card ask the bank owner.\",\
  3785.          [\"TextColour\"]=256,\
  3786.        },\
  3787.      }\
  3788.    },\
  3789.  },\
  3790.  [\"BackgroundColour\"]=1,\
  3791. }",
  3792.     [ "complete.view" ] = "{\
  3793.  [\"Children\"]={\
  3794.    [1]={\
  3795.      [\"Y\"]=\"50%,3\",\
  3796.      [\"X\"]=2,\
  3797.      [\"Width\"]=\"100%\",\
  3798.      [\"Type\"]=\"Label\",\
  3799.      [\"TextColour\"]=1,\
  3800.      [\"Text\"]=\"Registration Complete! \",\
  3801.      [\"Align\"]=\"Center\",\
  3802.    },\
  3803.    [2]={\
  3804.      [\"Y\"]=\"50%,-3\",\
  3805.      [\"X\"]=\"50%,-3\",\
  3806.      [\"Width\"]=7,\
  3807.      [\"Height\"]=5,\
  3808.      [\"Type\"]=\"ImageView\",\
  3809.      [\"Path\"]=\"tick\",\
  3810.    },\
  3811.  },\
  3812.  [\"BackgroundColour\"]=8192,\
  3813. }",
  3814.     [ "processing.view" ] = "{\
  3815.  [\"Children\"]={\
  3816.    [1]={\
  3817.      [\"Y\"]=\"50%\",\
  3818.      [\"X\"]=1,\
  3819.      [\"Width\"]=\"100%\",\
  3820.      [\"Type\"]=\"Label\",\
  3821.      [\"TextColour\"]=1,\
  3822.      [\"Text\"]=\"Processing\",\
  3823.      [\"Align\"]=\"Center\",\
  3824.      [\"Name\"]=\"ProcessingLabel\"\
  3825.    },\
  3826.  },\
  3827.  [\"BackgroundColour\"]=2048,\
  3828. }",
  3829.     [ "insertnew.view" ] = "{\
  3830.  [\"Children\"]={\
  3831.    [1]={\
  3832.      [\"Y\"]=1,\
  3833.      [\"X\"]=1,\
  3834.      [\"Height\"]=\"100%\",\
  3835.      [\"Width\"]=\"100%\",\
  3836.      [\"Type\"]=\"View\",\
  3837.      [\"BackgroundColour\"]=1,\
  3838.      [\"Children\"]={\
  3839.        [1]={\
  3840.          [\"Y\"]=\"100%\",\
  3841.          [\"X\"]=5,\
  3842.          [\"Type\"]=\"Label\",\
  3843.          [\"TextColour\"]=256,\
  3844.          [\"Text\"]=\"oeed\"\
  3845.        },\
  3846.        [2]={\
  3847.          [\"Y\"]=\"100%\",\
  3848.          [\"X\"]=9,\
  3849.          [\"Type\"]=\"Label\",\
  3850.          [\"TextColour\"]=128,\
  3851.          [\"Text\"]=\"Pay\"\
  3852.        },\
  3853.        [3]={\
  3854.          [\"Y\"]=2,\
  3855.          [\"X\"]=2,\
  3856.          [\"Width\"]=\"100%\",\
  3857.          [\"Type\"]=\"Label\",\
  3858.          [\"Align\"]=\"Center\",\
  3859.          [\"Text\"]=\"Insert Pocket Computer or Disk\",\
  3860.          [\"TextColour\"]=128,\
  3861.        },\
  3862.        [4]={\
  3863.          [\"Y\"]=6,\
  3864.          [\"X\"]=2,\
  3865.          [\"Width\"]=\"100%\",\
  3866.          [\"Type\"]=\"Label\",\
  3867.          [\"Align\"]=\"Center\",\
  3868.          [\"Text\"]=\"If you can, use a Pocket Computer\",\
  3869.          [\"TextColour\"]=256,\
  3870.        },\
  3871.      }\
  3872.    },\
  3873.  },\
  3874.  [\"BackgroundColour\"]=1,\
  3875. }",
  3876.     [ "main.view" ] = "{\
  3877.  [\"Children\"]={\
  3878.    [1]={\
  3879.      [\"Y\"]=1,\
  3880.      [\"X\"]=1,\
  3881.      [\"Height\"]=\"100%\",\
  3882.      [\"Width\"]=\"100%\",\
  3883.      [\"Type\"]=\"View\",\
  3884.      [\"BackgroundColour\"]=1,\
  3885.      [\"Children\"]={\
  3886.        [1]={\
  3887.          [\"Y\"]=2,\
  3888.          [\"X\"]=5,\
  3889.          [\"Type\"]=\"Label\",\
  3890.          [\"TextColour\"]=256,\
  3891.          [\"Text\"]=\"oeed\"\
  3892.        },\
  3893.        [2]={\
  3894.          [\"Y\"]=2,\
  3895.          [\"X\"]=9,\
  3896.          [\"Type\"]=\"Label\",\
  3897.          [\"TextColour\"]=128,\
  3898.          [\"Text\"]=\"Pay\"\
  3899.        },\
  3900.        [3]={\
  3901.          [\"Y\"]=\"100%,-5\",\
  3902.          [\"X\"]=1,\
  3903.          [\"Width\"]=\"100%\",\
  3904.          [\"Height\"]=3,\
  3905.          [\"Type\"]=\"Button\",\
  3906.          [\"Name\"]=\"NewAccountButton\",\
  3907.          [\"TextColour\"]=1,\
  3908.          [\"Align\"]=\"Center\",\
  3909.          [\"BackgroundColour\"]=8192,\
  3910.          [\"Text\"]=\"New Account\",\
  3911.        },\
  3912.        [4]={\
  3913.          [\"Y\"]=\"100%,-2\",\
  3914.          [\"X\"]=1,\
  3915.          [\"Width\"]=\"100%\",\
  3916.          [\"Height\"]=3,\
  3917.          [\"Type\"]=\"Button\",\
  3918.          [\"Name\"]=\"NewCardButton\",\
  3919.          [\"TextColour\"]=1,\
  3920.          [\"BackgroundColour\"]=2,\
  3921.          [\"Align\"]=\"Center\",\
  3922.          [\"Text\"]=\"New Card\",\
  3923.        },\
  3924.      }\
  3925.    },\
  3926.  },\
  3927.  [\"BackgroundColour\"]=1,\
  3928. }",
  3929.     [ "fail.view" ] = "{\
  3930.  [\"Children\"]={\
  3931.    [1]={\
  3932.      [\"Y\"]=\"50%,3\",\
  3933.      [\"X\"]=2,\
  3934.      [\"Width\"]=\"100%\",\
  3935.      [\"Type\"]=\"Label\",\
  3936.      [\"TextColour\"]=1,\
  3937.      [\"Text\"]=\"Failed! \",\
  3938.      [\"Align\"]=\"Center\",\
  3939.    },\
  3940.    [2]={\
  3941.      [\"Y\"]=\"50%,-3\",\
  3942.      [\"X\"]=\"50%,-2\",\
  3943.      [\"Width\"]=5,\
  3944.      [\"Height\"]=5,\
  3945.      [\"Type\"]=\"ImageView\",\
  3946.      [\"Path\"]=\"cross\",\
  3947.    },\
  3948.    [3]={\
  3949.      [\"Y\"]=\"50%,4\",\
  3950.      [\"X\"]=1,\
  3951.      [\"Width\"]=\"100%\",\
  3952.      [\"Type\"]=\"Label\",\
  3953.      [\"Name\"]=\"ReasonLabel\",\
  3954.      [\"TextColour\"]=64,\
  3955.      [\"Text\"]=\"\",\
  3956.      [\"Align\"]=\"Center\",\
  3957.    },\
  3958.  },\
  3959.  [\"BackgroundColour\"]=16384,\
  3960. }",
  3961.     [ "keyboard.view" ] = "{\
  3962.  [\"Height\"]=4,\
  3963.  [\"Children\"]={\
  3964.    {\
  3965.      Y=1,\
  3966.      X=1,\
  3967.      Width=1,\
  3968.      Type=\"Button\",\
  3969.      TextColour=1,\
  3970.      BackgroundColour=128,\
  3971.      Text=\"A\",\
  3972.    },\
  3973.    {\
  3974.      Y=1,\
  3975.      X=3,\
  3976.      Width=1,\
  3977.      Type=\"Button\",\
  3978.      TextColour=1,\
  3979.      BackgroundColour=128,\
  3980.      Text=\"B\",\
  3981.    },\
  3982.    {\
  3983.      Y=1,\
  3984.      X=5,\
  3985.      Width=1,\
  3986.      Type=\"Button\",\
  3987.      TextColour=1,\
  3988.      BackgroundColour=128,\
  3989.      Text=\"C\",\
  3990.    },\
  3991.    {\
  3992.      Y=1,\
  3993.      X=7,\
  3994.      Width=1,\
  3995.      Type=\"Button\",\
  3996.      TextColour=1,\
  3997.      BackgroundColour=128,\
  3998.      Text=\"D\",\
  3999.    },\
  4000.    {\
  4001.      Y=1,\
  4002.      X=9,\
  4003.      Width=1,\
  4004.      Type=\"Button\",\
  4005.      TextColour=1,\
  4006.      BackgroundColour=128,\
  4007.      Text=\"E\",\
  4008.    },\
  4009.    {\
  4010.      Y=1,\
  4011.      X=11,\
  4012.      Width=1,\
  4013.      Type=\"Button\",\
  4014.      TextColour=1,\
  4015.      BackgroundColour=128,\
  4016.      Text=\"F\",\
  4017.    },\
  4018.    {\
  4019.      Y=1,\
  4020.      X=13,\
  4021.      Width=1,\
  4022.      Type=\"Button\",\
  4023.      TextColour=1,\
  4024.      BackgroundColour=128,\
  4025.      Text=\"G\",\
  4026.    },\
  4027.    {\
  4028.      Y=1,\
  4029.      X=15,\
  4030.      Width=1,\
  4031.      Type=\"Button\",\
  4032.      TextColour=1,\
  4033.      BackgroundColour=128,\
  4034.      Text=\"H\",\
  4035.    },\
  4036. \
  4037. \
  4038.    {\
  4039.      Y=2,\
  4040.      X=2,\
  4041.      Width=1,\
  4042.      Type=\"Button\",\
  4043.      TextColour=1,\
  4044.      BackgroundColour=128,\
  4045.      Text=\"I\",\
  4046.    },\
  4047.    {\
  4048.      Y=2,\
  4049.      X=4,\
  4050.      Width=1,\
  4051.      Type=\"Button\",\
  4052.      TextColour=1,\
  4053.      BackgroundColour=128,\
  4054.      Text=\"J\",\
  4055.    },\
  4056.    {\
  4057.      Y=2,\
  4058.      X=6,\
  4059.      Width=1,\
  4060.      Type=\"Button\",\
  4061.      TextColour=1,\
  4062.      BackgroundColour=128,\
  4063.      Text=\"K\",\
  4064.    },\
  4065.    {\
  4066.      Y=2,\
  4067.      X=8,\
  4068.      Width=1,\
  4069.      Type=\"Button\",\
  4070.      TextColour=1,\
  4071.      BackgroundColour=128,\
  4072.      Text=\"L\",\
  4073.    },\
  4074.    {\
  4075.      Y=2,\
  4076.      X=10,\
  4077.      Width=1,\
  4078.      Type=\"Button\",\
  4079.      TextColour=1,\
  4080.      BackgroundColour=128,\
  4081.      Text=\"M\",\
  4082.    },\
  4083.    {\
  4084.      Y=2,\
  4085.      X=12,\
  4086.      Width=1,\
  4087.      Type=\"Button\",\
  4088.      TextColour=1,\
  4089.      BackgroundColour=128,\
  4090.      Text=\"N\",\
  4091.    },\
  4092.    {\
  4093.      Y=2,\
  4094.      X=14,\
  4095.      Width=1,\
  4096.      Type=\"Button\",\
  4097.      TextColour=1,\
  4098.      BackgroundColour=128,\
  4099.      Text=\"O\",\
  4100.    },\
  4101. \
  4102. \
  4103.    {\
  4104.      Y=3,\
  4105.      X=1,\
  4106.      Width=1,\
  4107.      Type=\"Button\",\
  4108.      TextColour=1,\
  4109.      BackgroundColour=128,\
  4110.      Text=\"P\",\
  4111.    },\
  4112.    {\
  4113.      Y=3,\
  4114.      X=3,\
  4115.      Width=1,\
  4116.      Type=\"Button\",\
  4117.      TextColour=1,\
  4118.      BackgroundColour=128,\
  4119.      Text=\"Q\",\
  4120.    },\
  4121.    {\
  4122.      Y=3,\
  4123.      X=5,\
  4124.      Width=1,\
  4125.      Type=\"Button\",\
  4126.      TextColour=1,\
  4127.      BackgroundColour=128,\
  4128.      Text=\"R\",\
  4129.    },\
  4130.    {\
  4131.      Y=3,\
  4132.      X=7,\
  4133.      Width=1,\
  4134.      Type=\"Button\",\
  4135.      TextColour=1,\
  4136.      BackgroundColour=128,\
  4137.      Text=\"S\",\
  4138.    },\
  4139.    {\
  4140.      Y=3,\
  4141.      X=9,\
  4142.      Width=1,\
  4143.      Type=\"Button\",\
  4144.      TextColour=1,\
  4145.      BackgroundColour=128,\
  4146.      Text=\"T\",\
  4147.    },\
  4148.    {\
  4149.      Y=3,\
  4150.      X=11,\
  4151.      Width=1,\
  4152.      Type=\"Button\",\
  4153.      TextColour=1,\
  4154.      BackgroundColour=128,\
  4155.      Text=\"U\",\
  4156.    },\
  4157.    {\
  4158.      Y=3,\
  4159.      X=13,\
  4160.      Width=1,\
  4161.      Type=\"Button\",\
  4162.      TextColour=1,\
  4163.      BackgroundColour=128,\
  4164.      Text=\"V\",\
  4165.    },\
  4166.    {\
  4167.      Y=3,\
  4168.      X=15,\
  4169.      Width=1,\
  4170.      Type=\"Button\",\
  4171.      TextColour=1,\
  4172.      BackgroundColour=128,\
  4173.      Text=\"W\",\
  4174.    },\
  4175. \
  4176. \
  4177.    {\
  4178.      Y=4,\
  4179.      X=2,\
  4180.      Width=1,\
  4181.      Type=\"Button\",\
  4182.      TextColour=1,\
  4183.      BackgroundColour=128,\
  4184.      Text=\"X\",\
  4185.    },\
  4186.    {\
  4187.      Y=4,\
  4188.      X=4,\
  4189.      Width=1,\
  4190.      Type=\"Button\",\
  4191.      TextColour=1,\
  4192.      BackgroundColour=128,\
  4193.      Text=\"Y\",\
  4194.    },\
  4195.    {\
  4196.      Y=4,\
  4197.      X=6,\
  4198.      Width=1,\
  4199.      Type=\"Button\",\
  4200.      TextColour=1,\
  4201.      BackgroundColour=128,\
  4202.      Text=\"Z\",\
  4203.    },\
  4204. \
  4205.    {\
  4206.      Y=4,\
  4207.      X=8,\
  4208.      Width=1,\
  4209.      Type=\"Button\",\
  4210.      TextColour=1,\
  4211.      BackgroundColour=128,\
  4212.      Text=\"_\",\
  4213.    },\
  4214. \
  4215.    {\
  4216.      Y=4,\
  4217.      X=10,\
  4218.      Width=2,\
  4219.      Type=\"Button\",\
  4220.      TextColour=1,\
  4221.      BackgroundColour=128,\
  4222.      Text=\"<-\",\
  4223.      Name=\"BackspaceButton\"\
  4224.    },\
  4225. \
  4226.    {\
  4227.      Y=4,\
  4228.      X=12,\
  4229.      Width=4,\
  4230.      Type=\"Button\",\
  4231.      TextColour=1,\
  4232.      BackgroundColour=8192,\
  4233.      Text=\"Ok\",\
  4234.      Name=\"OkButton\"\
  4235.    },\
  4236.  },\
  4237.  [\"BackgroundColour\"]=128,\
  4238. }",
  4239.     [ "name.view" ] = "{\
  4240.  [\"Children\"]={\
  4241.    [1]={\
  4242.      [\"Y\"]=1,\
  4243.      [\"X\"]=1,\
  4244.      [\"Height\"]=\"100%\",\
  4245.      [\"Width\"]=\"100%\",\
  4246.      [\"Type\"]=\"View\",\
  4247.      [\"BackgroundColour\"]=1,\
  4248.      [\"Children\"]={\
  4249.        [1]={\
  4250.          [\"Y\"]=1,\
  4251.          [\"X\"]=5,\
  4252.          [\"Type\"]=\"Label\",\
  4253.          [\"TextColour\"]=256,\
  4254.          [\"Text\"]=\"oeed\"\
  4255.        },\
  4256.        [2]={\
  4257.          [\"Y\"]=1,\
  4258.          [\"X\"]=9,\
  4259.          [\"Type\"]=\"Label\",\
  4260.          [\"TextColour\"]=128,\
  4261.          [\"Text\"]=\"Pay\"\
  4262.        },\
  4263.        [3]={\
  4264.          [\"Y\"]=3,\
  4265.          [\"X\"]=1,\
  4266.          [\"Type\"]=\"Label\",\
  4267.          [\"TextColour\"]=128,\
  4268.          [\"Align\"]=\"Center\",\
  4269.          [\"Text\"]=\"Enter Your Name\"\
  4270.        },\
  4271.        [4]={\
  4272.          [\"Y\"]=5,\
  4273.          [\"X\"]=1,\
  4274.          [\"Width\"]=\"100%\",\
  4275.          [\"Type\"]=\"TextBox\"\
  4276.        },\
  4277.        [5]={\
  4278.          [\"Y\"]=\"100%,-3\",\
  4279.          [\"X\"]=1,\
  4280.          [\"Width\"]=\"100%\",\
  4281.          [\"Type\"]=\"KeyboardView\",\
  4282.          [\"InheritView\"]=\"keyboard\"\
  4283.        },\
  4284.      }\
  4285.    },\
  4286.  },\
  4287.  [\"BackgroundColour\"]=1,\
  4288. }",
  4289.   },
  4290. }
  4291.  
  4292. local function run(tArgs)
  4293.  
  4294.   local fnFile, err = loadstring(files['startup'], 'startup')
  4295.   if err then
  4296.     error(err)
  4297.   end
  4298.  
  4299.   local function split(str, pat)
  4300.      local t = {}
  4301.      local fpat = "(.-)" .. pat
  4302.      local last_end = 1
  4303.      local s, e, cap = str:find(fpat, 1)
  4304.      while s do
  4305.         if s ~= 1 or cap ~= "" then
  4306.      table.insert(t,cap)
  4307.         end
  4308.         last_end = e+1
  4309.         s, e, cap = str:find(fpat, last_end)
  4310.      end
  4311.      if last_end <= #str then
  4312.         cap = str:sub(last_end)
  4313.         table.insert(t, cap)
  4314.      end
  4315.      return t
  4316.   end
  4317.  
  4318.   local function resolveTreeForPath(path, single)
  4319.     local _files = files
  4320.     local parts = split(path, '/')
  4321.     if parts then
  4322.       for i, v in ipairs(parts) do
  4323.         if #v > 0 then
  4324.           if _files[v] then
  4325.             _files = _files[v]
  4326.           else
  4327.             _files = nil
  4328.             break
  4329.           end
  4330.         end
  4331.       end
  4332.     elseif #path > 0 and path ~= '/' then
  4333.       _files = _files[path]
  4334.     end
  4335.     if not single or type(_files) == 'string' then
  4336.       return _files
  4337.     end
  4338.   end
  4339.  
  4340.   local oldFs = fs
  4341.   local env
  4342.   env = {
  4343.     fs = {
  4344.       list = function(path)
  4345.               local list = {}
  4346.               if fs.exists(path) then
  4347.             list = fs.list(path)
  4348.               end
  4349.         for k, v in pairs(resolveTreeForPath(path)) do
  4350.           if not fs.exists(path .. '/' ..k) then
  4351.             table.insert(list, k)
  4352.           end
  4353.         end
  4354.         return list
  4355.       end,
  4356.  
  4357.       exists = function(path)
  4358.         if fs.exists(path) then
  4359.           return true
  4360.         elseif resolveTreeForPath(path) then
  4361.           return true
  4362.         else
  4363.           return false
  4364.         end
  4365.       end,
  4366.  
  4367.       isDir = function(path)
  4368.         if fs.isDir(path) then
  4369.           return true
  4370.         else
  4371.           local tree = resolveTreeForPath(path)
  4372.           if tree and type(tree) == 'table' then
  4373.             return true
  4374.           else
  4375.             return false
  4376.           end
  4377.         end
  4378.       end,
  4379.  
  4380.       isReadOnly = function(path)
  4381.         if not fs.isReadOnly(path) then
  4382.           return false
  4383.         else
  4384.           return true
  4385.         end
  4386.       end,
  4387.  
  4388.       getName = fs.getName,
  4389.  
  4390.       getSize = fs.getSize,
  4391.  
  4392.       getFreespace = fs.getFreespace,
  4393.  
  4394.       makeDir = fs.makeDir,
  4395.  
  4396.       move = fs.move,
  4397.  
  4398.       copy = fs.copy,
  4399.  
  4400.       delete = fs.delete,
  4401.  
  4402.       combine = fs.combine,
  4403.  
  4404.       open = function(path, mode)
  4405.         if fs.exists(path) then
  4406.           return fs.open(path, mode)
  4407.         elseif type(resolveTreeForPath(path)) == 'string' then
  4408.           local handle = {close = function()end}
  4409.           if mode == 'r' then
  4410.             local content = resolveTreeForPath(path)
  4411.             handle.readAll = function()
  4412.               return content
  4413.             end
  4414.  
  4415.             local line = 1
  4416.             local lines = split(content, '\n')
  4417.             handle.readLine = function()
  4418.               if line > #lines then
  4419.                 return nil
  4420.               else
  4421.                 return lines[line]
  4422.               end
  4423.               line = line + 1
  4424.             end
  4425.                       return handle
  4426.           else
  4427.             error('Cannot write to read-only file (compilr archived).')
  4428.           end
  4429.         else
  4430.           return fs.open(path, mode)
  4431.         end
  4432.       end
  4433.     },
  4434.  
  4435.     io = {
  4436.       input = io.input,
  4437.       output = io.output,
  4438.       type = io.type,
  4439.       close = io.close,
  4440.       write = io.write,
  4441.       flush = io.flush,
  4442.       lines = io.lines,
  4443.       read = io.read,
  4444.       open = function(path, mode)
  4445.         if fs.exists(path) then
  4446.           return io.open(path, mode)
  4447.         elseif type(resolveTreeForPath(path)) == 'string' then
  4448.           local content = resolveTreeForPath(path)
  4449.           local f = fs.open(path, 'w')
  4450.           f.write(content)
  4451.           f.close()
  4452.           if mode == 'r' then
  4453.             return io.open(path, mode)
  4454.           else
  4455.             error('Cannot write to read-only file (compilr archived).')
  4456.           end
  4457.         else
  4458.           return io.open(path, mode)
  4459.         end
  4460.       end
  4461.     },
  4462.  
  4463.     loadfile = function( _sFile )
  4464.         local file = env.fs.open( _sFile, "r" )
  4465.         if file then
  4466.             local func, err = loadstring( file.readAll(), fs.getName( _sFile ) )
  4467.             file.close()
  4468.             return func, err
  4469.         end
  4470.         return nil, "File not found: ".._sFile
  4471.     end,
  4472.  
  4473.     dofile = function( _sFile )
  4474.         local fnFile, e = env.loadfile( _sFile )
  4475.         if fnFile then
  4476.             setfenv( fnFile, getfenv(2) )
  4477.             return fnFile()
  4478.         else
  4479.             error( e, 2 )
  4480.         end
  4481.     end
  4482.   }
  4483.  
  4484.   setmetatable( env, { __index = _G } )
  4485.  
  4486.   local tAPIsLoading = {}
  4487.   env.os.loadAPI = function( _sPath )
  4488.       local sName = fs.getName( _sPath )
  4489.       if tAPIsLoading[sName] == true then
  4490.           printError( "API "..sName.." is already being loaded" )
  4491.           return false
  4492.       end
  4493.       tAPIsLoading[sName] = true
  4494.          
  4495.       local tEnv = {}
  4496.       setmetatable( tEnv, { __index = env } )
  4497.       local fnAPI, err = env.loadfile( _sPath )
  4498.       if fnAPI then
  4499.           setfenv( fnAPI, tEnv )
  4500.           fnAPI()
  4501.       else
  4502.           printError( err )
  4503.           tAPIsLoading[sName] = nil
  4504.           return false
  4505.       end
  4506.      
  4507.       local tAPI = {}
  4508.       for k,v in pairs( tEnv ) do
  4509.           tAPI[k] =  v
  4510.       end
  4511.      
  4512.       env[sName] = tAPI    
  4513.       tAPIsLoading[sName] = nil
  4514.       return true
  4515.   end
  4516.  
  4517.   env.shell = shell
  4518.  
  4519.   setfenv( fnFile, env )
  4520.   fnFile(unpack(tArgs))
  4521. end
  4522.  
  4523. local function extract()
  4524.     local function node(path, tree)
  4525.         if type(tree) == 'table' then
  4526.             fs.makeDir(path)
  4527.             for k, v in pairs(tree) do
  4528.                 node(path .. '/' .. k, v)
  4529.             end
  4530.         else
  4531.             local f = fs.open(path, 'w')
  4532.             if f then
  4533.                 f.write(tree)
  4534.                 f.close()
  4535.             end
  4536.         end
  4537.     end
  4538.     node('', files)
  4539. end
  4540.  
  4541. local tArgs = {...}
  4542. if #tArgs == 1 and tArgs[1] == '--extract' then
  4543.   extract()
  4544. else
  4545.   run(tArgs)
  4546. end
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top