Advertisement
Derek1017

CC Web Browser - Client

Jul 13th, 2015
358
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 165.92 KB | None | 0 0
  1. -- CC Web Browser - Client --
  2. -- Made By derekseitz --
  3.  
  4. --  To extract all the files, run: "<filename> --extract" in the Shell --
  5. local files = {["Wireless"]="--This is just the OneOS Wireless API\
  6. \
  7. --OneOS uses channels between 4200 and 4300, avoid use where possible\
  8. \
  9. Channels = {\
  10.     Ignored = 4299,\
  11.     Ping = 4200,\
  12.     PingReply = 4201,\
  13.     QuestServerRequest = 4250,\
  14.     QuestServerRequestReply = 4251,\
  15.     QuestServerNameAvailable = 4252,\
  16.     QuestServerNameAvailableReply = 4253,\
  17. }\
  18. \
  19. local function isOpen(channel)\
  20.     return Peripheral.CallType('wireless_modem', 'isOpen', channel)\
  21. end\
  22. \
  23. local function open(channel)\
  24.     if not isOpen(channel) then\
  25.         Peripheral.CallType('wireless_modem', 'open', channel)\
  26.     end\
  27. end\
  28. \
  29. Open = open\
  30. \
  31. local function close(channel)\
  32.     Peripheral.CallType('wireless_modem', 'close', channel)\
  33. end\
  34. \
  35. local function closeAll()\
  36.     Peripheral.CallType('wireless_modem', 'closeAll')\
  37. end\
  38. \
  39. local function transmit(channel, replyChannel, message)\
  40.     Peripheral.CallType('wireless_modem', 'transmit', channel, replyChannel, textutils.serialize(message))\
  41. end\
  42. \
  43. function Present()\
  44.     if Peripheral.GetPeripheral('wireless_modem') == nil then\
  45.         return false\
  46.     else\
  47.         return true\
  48.     end\
  49. end\
  50. \
  51. local function FormatMessage(message, messageID, destinationID)\
  52.     return {\
  53.         content = textutils.serialize(message),\
  54.         senderID = os.getComputerID(),\
  55.         senderName = os.getComputerLabel(),\
  56.         channel = channel,\
  57.         replyChannel = reply,\
  58.         messageID = messageID or math.random(10000),\
  59.         destinationID = destinationID\
  60.     }\
  61. end\
  62. \
  63. local Timeout = function(func, time)\
  64.     time = time or 1\
  65.     parallel.waitForAny(func, function()\
  66.         sleep(time)\
  67.         --log('Timeout!'..time)\
  68.     end)\
  69. end\
  70. \
  71. RecieveMessage = function(_channel, messageID, timeout)\
  72.     open(_channel)\
  73.     local done = false\
  74.     local event, side, channel, replyChannel, message = nil\
  75.     Timeout(function()\
  76.         while not done do\
  77.             event, side, channel, replyChannel, message = os.pullEvent('modem_message')\
  78.             if channel ~= _channel then\
  79.                 event, side, channel, replyChannel, message = nil\
  80.             else\
  81.                 message = textutils.unserialize(message)\
  82.                 message.content = textutils.unserialize(message.content)\
  83.                 if messageID and messageID ~= message.messageID or (message.destinationID ~= nil and message.destinationID ~= os.getComputerID()) then\
  84.                     event, side, channel, replyChannel, message = nil\
  85.                 else\
  86.                     done = true\
  87.                 end\
  88.             end\
  89.         end\
  90.     end,\
  91.     timeout)\
  92.     return event, side, channel, replyChannel, message\
  93. end\
  94. \
  95. Initialise = function()\
  96.     if Present() then\
  97.         for i, c in pairs(Channels) do\
  98.             open(c)\
  99.         end\
  100.     end\
  101. end\
  102. \
  103. HandleMessage = function(event, side, channel, replyChannel, message, distance)\
  104.     message = textutils.unserialize(message)\
  105.     message.content = textutils.unserialize(message.content)\
  106. \
  107.     if channel == Channels.Ping then\
  108.         if message.content == 'Ping!' then\
  109.             SendMessage(replyChannel, 'Pong!', nil, message.messageID)\
  110.         end\
  111.     elseif message.destinationID ~= nil and message.destinationID ~= os.getComputerID() then\
  112.     elseif Wireless.Responder then\
  113.         Wireless.Responder(event, side, channel, replyChannel, message, distance)\
  114.     end\
  115. end\
  116. \
  117. SendMessage = function(channel, message, reply, messageID, destinationID)\
  118.     reply = reply or channel + 1\
  119.     open(channel)\
  120.     open(reply)\
  121.     local _message = FormatMessage(message, messageID, destinationID)\
  122.     transmit(channel, reply, _message)\
  123.     return _message\
  124. end\
  125. \
  126. Ping = function()\
  127.     local message = SendMessage(Channels.Ping, 'Ping!', Channels.PingReply)\
  128.     RecieveMessage(Channels.PingReply, message.messageID)\
  129. end",["parser"]="--[[\
  130.    This API was not created by myself, it was copied from https://github.com/voidfiles/webscript-lua-modules/tree/master/html\
  131. \
  132.    It has been modified slightly to be more suitable for CCML (removed unused tags, cleaned up returned table a little, etc)\
  133. \
  134.    Original License:\
  135. \
  136.    Copyright (c) 2007 T. Kobayashi\
  137. \
  138.    Permission is hereby granted, free of charge, to any person obtaining a \
  139.    copy of this software and associated documentation files (the \
  140.    \"Software\"), to deal in the Software without restriction, including \
  141.    without limitation the rights to use, copy, modify, merge, publish, \
  142.    distribute, sublicense, and/or sell copies of the Software, and to \
  143.    permit persons to whom the Software is furnished to do so, subject to \
  144.    the following conditions: \
  145. \
  146.    The above copyright notice and this permission notice shall be included \
  147.    in all copies or substantial portions of the Software. \
  148. \
  149.    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS \
  150.    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF \
  151.    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \
  152.    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY \
  153.    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, \
  154.    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE \
  155.    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \
  156. \
  157. ]]\
  158. \
  159. entity = {\
  160.  nbsp = \" \",\
  161.  lt = \"<\",\
  162.  gt = \">\",\
  163.  quot = \"\\\"\",\
  164.  amp = \"&\",\
  165. }\
  166. \
  167. -- keep unknown entity as is\
  168. setmetatable(entity, {\
  169.  __index = function (t, key)\
  170.    return \"&\" .. key .. \";\"\
  171.  end\
  172. })\
  173. \
  174. block = {\
  175.  \"address\",\
  176.  \"blockquote\",\
  177.  \"center\",\
  178.  \"dir\", \"div\", \"dl\",\
  179.  \"fieldset\", \"form\",\
  180.  \"h\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"hr\", \
  181.  \"isindex\",\
  182.  \"menu\",\
  183.  \"noframes\",\
  184.  \"ol\",\
  185.  \"p\",\
  186.  \"pre\",\
  187.  \"table\",\
  188.  \"ul\",\
  189. }\
  190. \
  191. inline = {\
  192.  \"a\", \"abbr\", \"acronym\", \"applet\",\
  193.  \"b\", \"basefont\", \"bdo\", \"big\", \"br\", \"button\",\
  194.  \"cite\", \"code\",\
  195.  \"dfn\",\
  196.  \"em\",\
  197.  \"font\",\
  198.  \"i\", \"iframe\", \"img\", \"input\",\
  199.  \"kbd\",\
  200.  \"label\",\
  201.  \"map\",\
  202.  \"object\",\
  203.  \"q\",\
  204.  \"s\", \"samp\", \"select\", \"small\", \"span\", \"strike\", \"strong\", \"sub\", \"sup\",\
  205.  \"textarea\", \"tt\",\
  206.  \"u\",\
  207.  \"var\",\
  208. }\
  209. \
  210. tags = {\
  211.  a = { empty = false },\
  212.  abbr = {empty = false} ,\
  213.  acronym = {empty = false} ,\
  214.  address = {empty = false} ,\
  215.  applet = {empty = false} ,\
  216.  area = {empty = true} ,\
  217.  b = {empty = false} ,\
  218.  base = {empty = true} ,\
  219.  basefont = {empty = true} ,\
  220.  bdo = {empty = false} ,\
  221.  big = {empty = false} ,\
  222.  blockquote = {empty = false} ,\
  223.  body = { empty = false, },\
  224.  br = {empty = true} ,\
  225.  button = {empty = false} ,\
  226.  caption = {empty = false} ,\
  227.  center = {empty = false} ,\
  228.  cite = {empty = false} ,\
  229.  code = {empty = false} ,\
  230.  col = {empty = true} ,\
  231.  colgroup = {\
  232.    empty = false,\
  233.    optional_end = true,\
  234.    child = {\"col\",},\
  235.  },\
  236.  dd = {empty = false} ,\
  237.  del = {empty = false} ,\
  238.  dfn = {empty = false} ,\
  239.  dir = {empty = false} ,\
  240.  div = {empty = false} ,\
  241.  dl = {empty = false} ,\
  242.  dt = {\
  243.    empty = false,\
  244.    optional_end = true,\
  245.    child = {\
  246.      inline,\
  247.      \"del\",\
  248.      \"ins\",\
  249.      \"noscript\",\
  250.      \"script\",\
  251.    },\
  252.  },\
  253.  em = {empty = false} ,\
  254.  fieldset = {empty = false} ,\
  255.  font = {empty = false} ,\
  256.  form = {empty = false} ,\
  257.  frame = {empty = true} ,\
  258.  frameset = {empty = false} ,\
  259.  h1 = {empty = false} ,\
  260.  h2 = {empty = false} ,\
  261.  h3 = {empty = false} ,\
  262.  h4 = {empty = false} ,\
  263.  h5 = {empty = false} ,\
  264.  h6 = {empty = false} ,\
  265.  head = {empty = false} ,\
  266.  hr = {empty = true} ,\
  267.  html = {empty = false} ,\
  268.  i = {empty = false} ,\
  269.  iframe = {empty = false} ,\
  270.  img = {empty = true} ,\
  271.  input = {empty = true} ,\
  272.  ins = {empty = false} ,\
  273.  isindex = {empty = true} ,\
  274.  kbd = {empty = false} ,\
  275.  label = {empty = false} ,\
  276.  legend = {empty = false} ,\
  277.  li = {\
  278.    empty = false,\
  279.    optional_end = true,\
  280.    child = {\
  281.      inline,\
  282.      block,\
  283.      \"del\",\
  284.      \"ins\",\
  285.      \"noscript\",\
  286.      \"script\",\
  287.    },\
  288.  },\
  289.  link = {empty = true} ,\
  290.  map = {empty = false} ,\
  291.  menu = {empty = false} ,\
  292.  meta = {empty = true} ,\
  293.  noframes = {empty = false} ,\
  294.  noscript = {empty = false} ,\
  295.  object = {empty = false} ,\
  296.  ol = {empty = false} ,\
  297.  optgroup = {empty = false} ,\
  298.  option = {\
  299.    empty = false,\
  300.    optional_end = true,\
  301.    child = {},\
  302.  },\
  303.  p = {\
  304.    empty = false,\
  305.    optional_end = true,\
  306.    child = {\
  307.      inline,\
  308.      \"del\",\
  309.      \"ins\",\
  310.      \"noscript\",\
  311.      \"script\",\
  312.    },\
  313.  } ,\
  314.  param = {empty = true} ,\
  315.  pre = {empty = false} ,\
  316.  q = {empty = false} ,\
  317.  s =  {empty = false} ,\
  318.  samp = {empty = false} ,\
  319.  script = {empty = false} ,\
  320.  select = {empty = false} ,\
  321.  small = {empty = false} ,\
  322.  span = {empty = false} ,\
  323.  strike = {empty = false} ,\
  324.  strong = {empty = false} ,\
  325.  style = {empty = false} ,\
  326.  sub = {empty = false} ,\
  327.  sup = {empty = false} ,\
  328.  table = {empty = false} ,\
  329.  tbody = {empty = false} ,\
  330.  td = {\
  331.    empty = false,\
  332.    optional_end = true,\
  333.    child = {\
  334.      inline,\
  335.      block,\
  336.      \"del\",\
  337.      \"ins\",\
  338.      \"noscript\",\
  339.      \"script\",\
  340.    },\
  341.  },\
  342.  textarea = {empty = false} ,\
  343.  tfoot = {\
  344.    empty = false,\
  345.    optional_end = true,\
  346.    child = {\"tr\",},\
  347.  },\
  348.  th = {\
  349.    empty = false,\
  350.    optional_end = true,\
  351.    child = {\
  352.      inline,\
  353.      block,\
  354.      \"del\",\
  355.      \"ins\",\
  356.      \"noscript\",\
  357.      \"script\",\
  358.    },\
  359.  },\
  360.  thead = {\
  361.    empty = false,\
  362.    optional_end = true,\
  363.    child = {\"tr\",},\
  364.  },\
  365.  title = {empty = false} ,\
  366.  tr = {\
  367.    empty = false,\
  368.    optional_end = true,\
  369.    child = {\
  370.      \"td\", \"th\",\
  371.    },\
  372.  },\
  373.  tt = {empty = false} ,\
  374.  u = {empty = false} ,\
  375.  ul = {empty = false} ,\
  376.  var = {empty = false} ,\
  377. }\
  378. \
  379. setmetatable(tags, {\
  380.  __index = function (t, key)\
  381.    return {empty = false}\
  382.  end\
  383. })\
  384. \
  385. -- string buffer implementation\
  386. function newbuf ()\
  387.  local buf = {\
  388.    _buf = {},\
  389.    clear =   function (self) self._buf = {}; return self end,\
  390.    content = function (self) return table.concat(self._buf) end,\
  391.    append =  function (self, s)\
  392.      self._buf[#(self._buf) + 1] = s\
  393.      return self\
  394.    end,\
  395.    set =     function (self, s) self._buf = {s}; return self end,\
  396.  }\
  397.  return buf\
  398. end\
  399. \
  400. -- unescape character entities\
  401. function unescape (s)\
  402.  function entity2string (e)\
  403.    return entity[e]\
  404.  end\
  405.  return s.gsub(s, \"&(#?%w+);\", entity2string)\
  406. end\
  407. \
  408. -- iterator factory\
  409. function makeiter (f)\
  410.  local co = coroutine.create(f)\
  411.  return function ()\
  412.    local code, res = coroutine.resume(co)\
  413.    return res\
  414.  end\
  415. end\
  416. \
  417. -- constructors for token\
  418. function Tag (s) \
  419.  return string.find(s, \"^</\") and\
  420.    {type = \"End\",   value = s} or\
  421.    {type = \"Start\", value = s}\
  422. end\
  423. \
  424. function Text (s)\
  425.  local unescaped = unescape(s) \
  426.  return {type = \"Text\", value = unescaped} \
  427. end\
  428. \
  429. -- lexer: text mode\
  430. function text (f, buf)\
  431.  local c = f:read(1)\
  432.  if c == \"<\" then\
  433.    if buf:content() ~= \"\" then coroutine.yield(Text(buf:content())) end\
  434.    buf:set(c)\
  435.    return tag(f, buf)\
  436.  elseif c then\
  437.    buf:append(c)\
  438.    return text(f, buf)\
  439.  else\
  440.    if buf:content() ~= \"\" then coroutine.yield(Text(buf:content())) end\
  441.  end\
  442. end\
  443. \
  444. -- lexer: tag mode\
  445. function tag (f, buf)\
  446.  local c = f:read(1)\
  447.  if c == \">\" then\
  448.    coroutine.yield(Tag(buf:append(c):content()))\
  449.    buf:clear()\
  450.    return text(f, buf)\
  451.  elseif c then\
  452.    buf:append(c)\
  453.    return tag(f, buf)\
  454.  else\
  455.    if buf:content() ~= \"\" then coroutine.yield(Tag(buf:content())) end\
  456.  end\
  457. end\
  458. \
  459. function parse_starttag(tag)\
  460.  local tagname = string.match(tag, \"<%s*(%w+)\")\
  461.  local elem = {_attr = {}}\
  462.  elem._tag = tagname\
  463.  for key, _, val in string.gmatch(tag, \"(%w+)%s*=%s*([\\\"'])(.-)%2\", i) do\
  464.    local unescaped = unescape(val)\
  465.    elem._attr[key] = unescaped\
  466.  end\
  467.  return elem\
  468. end\
  469. \
  470. function parse_endtag(tag)\
  471.  local tagname = string.match(tag, \"<%s*/%s*(%w+)\")\
  472.  return tagname\
  473. end\
  474. \
  475. -- find last element that satisfies given predicate\
  476. function rfind(t, pred)\
  477.  local length = #t\
  478.  for i=length,1,-1 do\
  479.    if pred(t[i]) then\
  480.      return i, t[i]\
  481.    end\
  482.  end\
  483. end\
  484. \
  485. function flatten(t, acc)\
  486.  acc = acc or {}\
  487.  for i,v in ipairs(t) do\
  488.    if type(v) == \"table\" then\
  489.      flatten(v, acc)\
  490.    else\
  491.      acc[#acc + 1] = v\
  492.    end\
  493.  end\
  494.  return acc\
  495. end\
  496. \
  497. function optional_end_p(elem)\
  498.  if tags[elem._tag].optional_end then\
  499.    return true\
  500.  else\
  501.    return false\
  502.  end\
  503. end\
  504. \
  505. function valid_child_p(child, parent)\
  506.  local schema = tags[parent._tag].child\
  507.  if not schema then return true end\
  508. \
  509.  for i,v in ipairs(flatten(schema)) do\
  510.    if v == child._tag then\
  511.      return true\
  512.    end\
  513.  end\
  514. \
  515.  return false\
  516. end\
  517. \
  518. -- tree builder\
  519. function parse(f)\
  520.  local root = {_tag = \"#document\", _attr = {}}\
  521.  local stack = {root}\
  522.  for i in makeiter(function () return text(f, newbuf()) end) do\
  523.    if i.type == \"Start\" then\
  524.      local new = parse_starttag(i.value)\
  525.      local top = stack[#stack]\
  526. \
  527.      while\
  528.        top._tag ~= \"#document\" and \
  529.        optional_end_p(top) and\
  530.        not valid_child_p(new, top)\
  531.      do\
  532.        stack[#stack] = nil \
  533.        top = stack[#stack]\
  534.      end\
  535. \
  536.      top[#top+1] = new -- appendchild\
  537.      if not tags[new._tag].empty then \
  538.        stack[#stack+1] = new -- push\
  539.      end\
  540.    elseif i.type == \"End\" then\
  541.      local tag = parse_endtag(i.value)\
  542.      local openingpos = rfind(stack, function(v) \
  543.          if v._tag == tag then\
  544.            return true\
  545.          else\
  546.            return false\
  547.          end\
  548.        end)\
  549.      if openingpos then\
  550.        local length = #stack\
  551.        for j=length,openingpos,-1 do\
  552.          table.remove(stack, j)\
  553.        end\
  554.      end\
  555.    else -- Text\
  556.        if #string.gsub(string.gsub(i.value, \"%s+\", \"\"), '\\n', '') ~= 0 then\
  557.            local top = stack[#stack]\
  558.            top[#top+1] = i.value\
  559.        end\
  560.    end\
  561.  end\
  562.  return root\
  563. end\
  564. \
  565. function parsestr(s)\
  566.  local handle = {\
  567.    _content = s,\
  568.    _pos = 1,\
  569.    read = function (self, length)\
  570.      if self._pos > string.len(self._content) then return end\
  571.      local ret = string.sub(self._content, self._pos, self._pos + length - 1)\
  572.      self._pos = self._pos + length\
  573.      return ret\
  574.    end\
  575.  }\
  576.  return parse(handle)\
  577. end",["Elements"]={["SecureTextInput.lua"]="Inherit = 'TextInput'\
  578. \
  579. UpdateValue = function(self)\
  580.     self.Value = hash.sha256(self.Object.Text)\
  581. end\
  582. \
  583. OnCreateObject = function(self, parentObject, y)\
  584.     return {\
  585.         Element = self,\
  586.         Y = y,\
  587.         X = 1,\
  588.         Width = self.Width,\
  589.         Type = \"SecureTextBox\",\
  590.         Text = self.Value,\
  591.         TextColour = self.TextColour,\
  592.         BackgroundColour = self.BackgroundColour,\
  593.         SelectedBackgroundColour = self.SelectedBackgroundColour,\
  594.         SelectedTextColour = self.SelectedTextColour,\
  595.         PlaceholderTextColour = self.PlaceholderTextColour,\
  596.         Placeholder = self.Placeholder,\
  597.         InputName = self.InputName,\
  598.         OnChange = function(_self, event, keychar)\
  599.             if keychar == keys.tab or keychar == keys.enter then\
  600.                 local form = self\
  601.                 local step = 0\
  602.                 while form.Tag ~= 'form' and step < 50 do\
  603.                     form = form.Parent\
  604.                 end\
  605.                 if keychar == keys.tab then\
  606.                     if form and form.Object and form.Object.OnTab then\
  607.                         form.Object:OnTab()\
  608.                     end\
  609.                 else\
  610.                     if form and form.Submit then\
  611.                         form:Submit(true)\
  612.                     end\
  613.                 end\
  614.             end\
  615.         end\
  616.     }\
  617. end",["Image.lua"]="URL = nil\
  618. Format = nil\
  619. \
  620. OnInitialise = function(self, node)\
  621.     local attr = self.Attributes\
  622.     if attr.src then\
  623.         self.URL = attr.src\
  624.     end\
  625. \
  626.     if attr.type then\
  627.         self.Format = attr.type\
  628.     end\
  629. \
  630.     if attr.height then\
  631.         self.Height = attr.height\
  632.     end\
  633. \
  634.     if attr.width then\
  635.         self.Width = attr.width\
  636.     end\
  637. end\
  638. \
  639. OnCreateObject = function(self, parentObject, y)\
  640.     return {\
  641.         Element = self,\
  642.         Y = y,\
  643.         X = 1,\
  644.         Width = self.Width,\
  645.         Height = self.Height,\
  646.         URL = self.URL,\
  647.         Format = self.Format,\
  648.         Type = \"WebImageView\"\
  649.     }\
  650. end",["Script.lua"]="Text = nil\
  651. URL = nil\
  652. \
  653. OnInitialise = function(self, node)\
  654.     local attr = self.Attributes\
  655.     self.Text = table.concat(node, '\\n')\
  656. \
  657.     if attr.src then\
  658.         self.URL = attr.src\
  659.         self.Text = nil\
  660.     end\
  661. end\
  662. \
  663. InsertScript = function(self, webView)\
  664.     if self.Text then\
  665.         webView:LoadScript(self.Text)\
  666.     elseif self.URL then\
  667.         fetchHTTPAsync(resolveFullUrl(self.URL), function(ok, event, response)\
  668.             if ok then\
  669.                 self.Text = response.readAll()\
  670.                 webView:LoadScript(self.Text)\
  671.             end\
  672.         end)\
  673. \
  674.     end\
  675.     return nil\
  676. end",["Select.lua"]="Width = 20\
  677. InputName = ''\
  678. \
  679. OnInitialise = function(self, node)\
  680.     if attr.value then\
  681.         new.Text = attr.value\
  682.     end\
  683. \
  684.     if attr.name then\
  685.         new.InputName = attr.name\
  686.     end\
  687. end\
  688. \
  689. UpdateValue = function(self)\
  690.     self.Value = self.Object.MenuItems[self.Object.Selected].Value\
  691. end\
  692. \
  693. OnCreateObject = function(self, parentObject, y)\
  694.     return {\
  695.         Element = self,\
  696.         Y = y,\
  697.         X = 1,\
  698.         Width = self.Width,\
  699.         Type = \"SelectView\",\
  700.         TextColour = self.TextColour,\
  701.         BackgroundColour = self.BackgroundColour,\
  702.         InputName = self.InputName,\
  703.     }\
  704. end",["Paragraph.lua"]="Align = \"Left\"\
  705. \
  706. OnInitialise = function(self, node)\
  707.     local attr = self.Attributes\
  708.     self.Text = self.Text or ''\
  709.     if attr.align then\
  710.         if attr.align:lower() == 'left' or attr.align:lower() == 'center' or attr.align:lower() == 'right' then\
  711.             self.Align = attr.align:lower():gsub(\"^%l\", string.upper)\
  712.         end\
  713.     end\
  714. end\
  715. \
  716. OnCreateObject = function(self, parentObject, y)\
  717.     return {\
  718.         Element = self,\
  719.         Y = y,\
  720.         X = 1,\
  721.         Width = self.Width,\
  722.         Height = self.Height,\
  723.         Align = self.Align,\
  724.         Type = \"Label\",\
  725.         Text = self.Text,\
  726.         TextColour = self.TextColour,\
  727.         BackgroundColour = self.BackgroundColour,\
  728.         OnUpdate = function(_self, value)\
  729.             if value == 'Text' then\
  730.                 if not self.Attributes.height then\
  731.                     _self.Height = #_self.Bedrock.Helpers.WrapText(_self.Text, _self.Width)\
  732.                     _self.Bedrock:GetObject('WebView'):RepositionLayout()\
  733.                 end\
  734.             end\
  735.         end\
  736.     }\
  737. end",["HiddenInput.lua"]="InputName = ''\
  738. \
  739. OnInitialise = function(self, node)\
  740.     local attr = self.Attributes\
  741.     if attr.value then\
  742.         self.Value = attr.value\
  743.     end\
  744. \
  745.     if attr.name then\
  746.         self.InputName = attr.name\
  747.     end\
  748. end",["ButtonInput.lua"]="BackgroundColour = colours.lightGrey\
  749. TextColour = colours.black\
  750. Text = 'Submit'\
  751. InputName = ''\
  752. \
  753. OnInitialise = function(self, node)\
  754.     local attr = self.Attributes\
  755.     if attr.value then\
  756.         self.Text = attr.value\
  757.     end\
  758. \
  759.     if attr.name then\
  760.         self.InputName = attr.name\
  761.     end\
  762. \
  763.     if not attr.width then\
  764.         self.Width = #self.Text + 2\
  765.     end\
  766. end\
  767. \
  768. UpdateValue = function(self, force)\
  769.     if force then\
  770.         self.Value = self.Object.Text\
  771.     end\
  772. end\
  773. \
  774. CreateObject = function(self, parentObject, y)\
  775.     return parentObject:AddObject({\
  776.         Element = self,\
  777.         Y = y,\
  778.         X = 1,\
  779.         Width = self.Width,\
  780.         Type = \"Button\",\
  781.         Text = self.Text,\
  782.         TextColour = self.TextColour,\
  783.         BackgroundColour = self.BackgroundColour,\
  784.         InputName = self.InputName,\
  785.         OnClick = function(_self, event, side, x, y)\
  786.             local form = self\
  787.             local step = 0\
  788.             while form.Tag ~= 'form' and step < 50 do\
  789.                 form = form.Parent\
  790.             end\
  791.             self.Value = _self.Text\
  792.             if form and form.Submit then\
  793.                 form:Submit()\
  794.             end\
  795.         end\
  796.     })\
  797. end",["Float.lua"]="Align = \"Left\"\
  798. \
  799. OnInitialise = function(self, node)\
  800.     local attr = self.Attributes\
  801.     if attr.align then\
  802.         if attr.align:lower() == 'left' or attr.align:lower() == 'right' then\
  803.             self.Align = attr.align:lower():gsub(\"^%l\", string.upper)\
  804.         end\
  805.     end\
  806. end\
  807. \
  808. OnCreateObject = function(self, parentObject, y)\
  809.     return {\
  810.         Element = self,\
  811.         Y = y,\
  812.         X = 1,\
  813.         Width = self.Width,\
  814.         Height = self.Height,\
  815.         Align = self.Align,\
  816.         BackgroundColour = self.BackgroundColour,\
  817.         Type = \"FloatView\"\
  818.     }\
  819. end",["Element.lua"]="HasChildren = true\
  820. Children = nil\
  821. Tag = nil\
  822. TextColour = colours.black\
  823. BackgroundColour = colours.transparent\
  824. Text = nil\
  825. Attributes = nil\
  826. Width = \"100%\"\
  827. \
  828. Initialise = function(self, node)\
  829.     local new = {}    -- the new instance\
  830.     setmetatable( new, {__index = self} )\
  831.     local attr = node._attr\
  832.     new.Tag = node._tag\
  833.     new.Attributes = attr\
  834.     if new.HasChildren then\
  835.         new.Children = {}\
  836.     end\
  837. \
  838.     if type(node[1]) == 'string' then\
  839.         new.Text = node[1]\
  840.     end\
  841.     \
  842.     if attr.colour then\
  843.         new.TextColour = self:ParseColour(attr.colour)\
  844.     elseif attr.color then\
  845.         new.TextColour = self:ParseColour(attr.color)\
  846.     end\
  847. \
  848.     if attr.bgcolour then\
  849.         new.BackgroundColour = self:ParseColour(attr.bgcolour)\
  850.     elseif attr.bgcolor then\
  851.         new.BackgroundColour = self:ParseColour(attr.bgcolor)\
  852.     end\
  853. \
  854.     if attr.height then\
  855.         new.Height = attr.height\
  856.     end\
  857. \
  858.     if attr.width then\
  859.         new.Width = attr.width\
  860.     end\
  861. \
  862.     if new.OnInitialise then\
  863.         new:OnInitialise(node)\
  864.     end\
  865. \
  866.     return new\
  867. end\
  868. \
  869. ParseColour = function(self, str)\
  870.     if str and type(str) == 'string' then\
  871.         if colours[str] and type(colours[str]) == 'number' then\
  872.             return colours[str]\
  873.         elseif colors[str] and type(colors[str]) == 'number' then\
  874.             return colors[str]\
  875.         end\
  876.     end\
  877. end\
  878. \
  879. CreateObject = function(self, parentObject, y)\
  880.     local object\
  881.     if self.OnCreateObject then\
  882.         object = self:OnCreateObject()\
  883.     else\
  884.         object = {\
  885.             Element = self,\
  886.             Y = y,\
  887.             X = 1,\
  888.             Width = self.Width,\
  889.             Height = self.Height,\
  890.             BackgroundColour = self.BackgroundColour,\
  891.             Type = \"View\"\
  892.         }\
  893.     end\
  894. \
  895.     if object then\
  896.         return parentObject:AddObject(object, parentObject, y)\
  897.     end\
  898. end",["Divider.lua"]="Char = nil\
  899. \
  900. OnInitialise = function(self, node)\
  901.     local attr = self.Attributes\
  902.     self.Text = self.Text or ''\
  903.     if attr.char then\
  904.         if #attr.char == 1 then\
  905.             self.Char = attr.char\
  906.         end\
  907.     end\
  908. end\
  909. \
  910. OnCreateObject = function(self, parentObject, y)\
  911.     return {\
  912.         Element = self,\
  913.         Y = y,\
  914.         X = 1,\
  915.         Width = self.Width,\
  916.         Height = self.Height,\
  917.         BackgroundColour = self.BackgroundColour,\
  918.         TextColour = self.TextColour,\
  919.         Type = \"DividerView\",\
  920.         Char = self.Char\
  921.     }\
  922. end",["Link.lua"]="Align = 'Left'\
  923. Width = \"100%\"\
  924. TextColour = colours.blue\
  925. UnderlineColour = nil\
  926. UnderlineVisible = true\
  927. URL = nil\
  928. \
  929. OnInitialise = function(self, node)\
  930.     local attr = self.Attributes\
  931.     if attr.href then\
  932.         self.URL = attr.href\
  933.     end\
  934.     \
  935.     if attr.ulcolour then\
  936.         if attr.ulcolour == 'none' then\
  937.             self.UnderlineVisible = false\
  938.         else\
  939.             self.UnderlineColour = self:ParseColour(attr.ulcolour)\
  940.         end\
  941.     elseif attr.ulcolor then\
  942.         if attr.ulcolor == 'none' then\
  943.             self.UnderlineVisible = false\
  944.         else\
  945.             self.UnderlineColour = self:ParseColour(attr.ulcolor)\
  946.         end\
  947.     end\
  948. \
  949.     if attr.align then\
  950.         if attr.align:lower() == 'left' or attr.align:lower() == 'center' or attr.align:lower() == 'right' then\
  951.             self.Align = attr.align:lower():gsub(\"^%l\", string.upper)\
  952.         end\
  953.     end\
  954. end\
  955. \
  956. OnCreateObject = function(self, parentObject, y)\
  957.     return {\
  958.         Element = self,\
  959.         Y = y,\
  960.         X = 1,\
  961.         Width = self.Width,\
  962.         Align = self.Align,\
  963.         Type = \"LinkView\",\
  964.         Text = self.Text,\
  965.         TextColour = self.TextColour,\
  966.         UnderlineColour = self.UnderlineColour,\
  967.         BackgroundColour = self.BackgroundColour,\
  968.         URL = resolveFullUrl(self.URL),\
  969.         UnderlineVisible = self.UnderlineVisible\
  970.     }\
  971. end",["Center.lua"]="OnCreateObject = function(self, parentObject, y)\
  972.     return {\
  973.         Element = self,\
  974.         Y = y,\
  975.         X = 1,\
  976.         Width = \"100%\",\
  977.         Height = self.Height,\
  978.         BackgroundColour = self.BackgroundColour,\
  979.         Type = \"CenterView\"\
  980.     }\
  981. end",["Form.lua"]="Submit = function(self, onEnter)\
  982.     local values = {}\
  983.     \
  984.     local node = false\
  985.     node = function(elem)\
  986.         if (elem.Tag == 'input' or elem.Tag == 'select') and elem.InputName then\
  987.             local findSubmit = (onEnter and elem.Attributes and elem.Attributes.type == 'submit')\
  988.             if elem.UpdateValue then\
  989.                 elem:UpdateValue(findSubmit)\
  990.             end\
  991. \
  992.             if findSubmit then\
  993.                 onEnter = false\
  994.             end\
  995. \
  996.             if elem.Value then\
  997.                 values[elem.InputName] = elem.Value\
  998.             end\
  999.         end\
  1000. \
  1001.         if elem.Children then\
  1002.             for i, child in ipairs(elem.Children) do\
  1003.                 node(child)\
  1004.             end\
  1005.         end\
  1006.     end\
  1007. \
  1008.     node(self)\
  1009. \
  1010.     local url = false\
  1011.     if self.Attributes.action and #self.Attributes.action > 0 then\
  1012.         url = resolveFullUrl(self.Attributes.action) --TODO: this needs to show the fake url to the user\
  1013.     else\
  1014.         url = getCurrentFakeUrl()\
  1015.     end\
  1016.     local data = ''\
  1017.     for k, v in pairs(values) do\
  1018.         data = data .. textutils.urlEncode(k) .. '=' .. textutils.urlEncode(v) .. '&'\
  1019.     end\
  1020.     data = data:sub(1, #data - 1)\
  1021. \
  1022.     if self.Attributes.method and self.Attributes.method:lower() == 'post' then\
  1023.         goToUrl(url, data)\
  1024.     else\
  1025.         goToUrl(url .. '?' .. data)\
  1026.     end\
  1027. end\
  1028. \
  1029. OnCreateObject = function(self, parentObject, y)\
  1030.     return {\
  1031.         Element = self,\
  1032.         Y = y,\
  1033.         X = 1,\
  1034.         Width = \"100%\",\
  1035.         Height = self.Height,\
  1036.         Type = \"FormView\"\
  1037.     }\
  1038. end",["FileInput.lua"]="BackgroundColour = colours.lightGrey\
  1039. TextColour = colours.black\
  1040. Text = 'Choose File...'\
  1041. InputName = ''\
  1042. FilePath = 'test'\
  1043. \
  1044. OnInitialise = function(self, node)\
  1045.     local attr = self.Attributes\
  1046.     if attr.value then\
  1047.         self.Text = attr.value\
  1048.     end\
  1049. \
  1050.     if attr.name then\
  1051.         self.InputName = attr.name\
  1052.     end\
  1053. \
  1054.     if not attr.width then\
  1055.         self.Width = #self.Text + 2\
  1056.     end\
  1057. end\
  1058. \
  1059. UpdateValue = function(self, force)\
  1060.     if self.FilePath then\
  1061.         local f = fs.open(self.FilePath, 'r')\
  1062.         if f then\
  1063.             local content = f.readAll()\
  1064.             self.Value = '{\"name\": \"' .. fs.getName(self.FilePath):gsub('\"', '\\\\\"') .. '\", \"content\": \"' .. content:gsub('\"', '\\\\\"') .. '\"}'\
  1065.             f.close()\
  1066.         end\
  1067.     end\
  1068. end\
  1069. \
  1070. CreateObject = function(self, parentObject, y)\
  1071.     return parentObject:AddObject({\
  1072.         Element = self,\
  1073.         Y = y,\
  1074.         X = 1,\
  1075.         Width = self.Width,\
  1076.         Type = \"Button\",\
  1077.         Text = self.Text,\
  1078.         TextColour = self.TextColour,\
  1079.         BackgroundColour = self.BackgroundColour,\
  1080.         InputName = self.InputName,\
  1081.         OnClick = function(_self, event, side, x, y)\
  1082.             _self.Bedrock:DisplayOpenFileWindow(nil, function(success, path)\
  1083.                 if success then\
  1084.                     self.FilePath = path\
  1085.                     _self.Text = 'File: '..fs.getName(path)\
  1086.                     _self.Align = 'Left'\
  1087.                 end\
  1088.             end)\
  1089.         end\
  1090.     })\
  1091. end",["Heading.lua"]="Align = \"Center\"\
  1092. \
  1093. OnInitialise = function(self, node)\
  1094.     local attr = self.Attributes\
  1095.     self.Text = self.Text or ''\
  1096.     if attr.align then\
  1097.         if attr.align:lower() == 'left' or attr.align:lower() == 'center' or attr.align:lower() == 'right' then\
  1098.             self.Align = attr.align:lower():gsub(\"^%l\", string.upper)\
  1099.         end\
  1100.     end\
  1101. end\
  1102. \
  1103. OnCreateObject = function(self, parentObject, y)\
  1104.     return {\
  1105.         Element = self,\
  1106.         Y = y,\
  1107.         X = 1,\
  1108.         Width = \"100%\",\
  1109.         Align = self.Align,\
  1110.         Type = \"HeadingView\",\
  1111.         Text = self.Text,\
  1112.         TextColour = self.TextColour,\
  1113.         BackgroundColour = self.BackgroundColour\
  1114.     }\
  1115. end",["TextInput.lua"]="SelectedBackgroundColour = colours.blue\
  1116. SelectedTextColour = colours.white\
  1117. PlaceholderTextColour = colours.grey\
  1118. Placeholder = ''\
  1119. Value = nil\
  1120. Attributes = nil\
  1121. Children = nil\
  1122. Tag = nil\
  1123. Width = 20\
  1124. InputName = ''\
  1125. \
  1126. OnInitialise = function(self, node)\
  1127.     local attr = self.Attributes\
  1128.     if attr.selbgcolour then\
  1129.         self.SelectedBackgroundColour = self:ParseColour(attr.selbgcolour)\
  1130.     elseif attr.selbgcolor then\
  1131.         self.SelectedBackgroundColour = self:ParseColour(attr.selbgcolor)\
  1132.     end\
  1133. \
  1134.     if attr.selcolour then\
  1135.         self.SelectedTextColour = self:ParseColour(attr.selcolour)\
  1136.     elseif attr.selcolor then\
  1137.         self.SelectedTextColour = self:ParseColour(attr.selcolor)\
  1138.     end\
  1139. \
  1140.     if attr.plcolour then\
  1141.         self.PlaceholderTextColour = self:ParseColour(attr.plcolour)\
  1142.     elseif attr.plcolour then\
  1143.         self.PlaceholderTextColour = self:ParseColour(attr.plcolour)\
  1144.     end\
  1145. \
  1146.     if attr.value then\
  1147.         self.Value = attr.value\
  1148.     end\
  1149. \
  1150.     if attr.placeholder then\
  1151.         self.Placeholder = attr.placeholder\
  1152.     end\
  1153. \
  1154.     if attr.name then\
  1155.         self.InputName = attr.name\
  1156.     end\
  1157. end\
  1158. \
  1159. UpdateValue = function(self)\
  1160.     self.Value = self.Object.Text\
  1161. end\
  1162. \
  1163. OnCreateObject = function(self, parentObject, y)\
  1164.     return {\
  1165.         Element = self,\
  1166.         Y = y,\
  1167.         X = 1,\
  1168.         Width = self.Width,\
  1169.         Type = \"TextBox\",\
  1170.         Text = self.Value,\
  1171.         TextColour = self.TextColour,\
  1172.         BackgroundColour = self.BackgroundColour,\
  1173.         SelectedBackgroundColour = self.SelectedBackgroundColour,\
  1174.         SelectedTextColour = self.SelectedTextColour,\
  1175.         PlaceholderTextColour = self.PlaceholderTextColour,\
  1176.         Placeholder = self.Placeholder,\
  1177.         InputName = self.InputName,\
  1178.         OnChange = function(_self, event, keychar)\
  1179.             if keychar == keys.tab or keychar == keys.enter then\
  1180.                 local form = self\
  1181.                 local step = 0\
  1182.                 while form.Tag ~= 'form' and step < 50 do\
  1183.                     form = form.Parent\
  1184.                 end\
  1185.                 if keychar == keys.tab then\
  1186.                     if form and form.Object and form.Object.OnTab then\
  1187.                         form.Object:OnTab()\
  1188.                     end\
  1189.                 else\
  1190.                     if form and form.Submit then\
  1191.                         form:Submit(true)\
  1192.                     end\
  1193.                 end\
  1194.             end\
  1195.         end\
  1196.     }\
  1197. end",["ElementTree.lua"]="Tree = nil\
  1198. FailHandler = nil\
  1199. \
  1200. Initialise = function(self, html)\
  1201.     local new = {}    -- the new instance\
  1202.     setmetatable( new, {__index = self} )\
  1203.     local err = nil\
  1204.     if html:sub(1,15) ~= '<!DOCTYPE ccml>' then\
  1205.         err = Errors.InvalidDoctype\
  1206.     end\
  1207. \
  1208.     html = html:gsub(\"<!%-%-*.-%-%->\",\"\")\
  1209. \
  1210.     local rawTree\
  1211.     if not err then\
  1212.         rawTree = parser.parsestr(html)[1]\
  1213.     end\
  1214. \
  1215.     if not err then\
  1216.         _, notok = pcall(function() new:LoadTree(rawTree) end)\
  1217.         if notok then\
  1218.             error(notok)\
  1219.             err = Errors.ParseFailed\
  1220.         end\
  1221.     end\
  1222. \
  1223.     if err then\
  1224.         return nil, err\
  1225.     end\
  1226.     return new\
  1227. end\
  1228. \
  1229. LoadTree = function(self, rawTree)\
  1230.     local tree = {}\
  1231.     local node = true\
  1232.     node = function (tbl, tr, parent)\
  1233.         for i, v in ipairs(tbl) do\
  1234.             if type(v) == 'table' and v._tag then\
  1235.                 local class = self:GetElementClass(v._tag, v._attr)\
  1236.                 if not class or not class.Initialise then\
  1237.                     error('Unknown class: '..v._attr.type)\
  1238.                 end\
  1239.                 local element = class:Initialise(v)\
  1240.                 element.Parent = parent\
  1241.                 table.insert(tr, element)\
  1242.                 if element.Children then\
  1243.                     node(v, element.Children, element)\
  1244.                 end\
  1245.             end\
  1246.         end\
  1247.     end\
  1248. \
  1249.     node(rawTree, tree)\
  1250.     self.Tree = tree\
  1251. end\
  1252. \
  1253. GetElement = function(self, tag)\
  1254.     local node = true\
  1255.     node = function(tbl)\
  1256.         for i,v in ipairs(tbl) do\
  1257.             if type(v) == 'table' and v.Tag then\
  1258.                 if v.Tag == tag then\
  1259.                     return v\
  1260.                 end\
  1261.                 if v.Children then\
  1262.                     local r = node(v.Children)\
  1263.                     if r then\
  1264.                         return r\
  1265.                     end\
  1266.                 end\
  1267.             end\
  1268.         end\
  1269.     end\
  1270.     return node(self.Tree)\
  1271. end\
  1272. \
  1273. GetElementClass = function(self, tag, attr)\
  1274.     if tag == 'h' then\
  1275.         return Heading\
  1276.     elseif tag == 'div' then\
  1277.         return Divider\
  1278.     elseif tag == 'p' then\
  1279.         return Paragraph\
  1280.     elseif tag == 'center' then\
  1281.         return Center\
  1282.     elseif tag == 'img' then\
  1283.         return Image\
  1284.     elseif tag == 'a' then\
  1285.         return Link\
  1286.     elseif tag == 'float' then\
  1287.         return Float\
  1288.     elseif tag == 'br' then\
  1289.         return Element\
  1290.     elseif tag == 'input' then\
  1291.         if attr.type == 'text' then\
  1292.             return TextInput\
  1293.         elseif attr.type == 'password' then\
  1294.             return SecureTextInput\
  1295.         elseif attr.type == 'submit' or attr.type == 'button' then\
  1296.             return ButtonInput\
  1297.         elseif attr.type == 'file' then\
  1298.             return FileInput\
  1299.         elseif attr.type == 'hidden' then\
  1300.             return HiddenInput\
  1301.         else\
  1302.             return Element\
  1303.         end\
  1304.     elseif tag == 'select' then\
  1305.         return Select\
  1306.     elseif tag == 'option' then\
  1307.         return SelectOption\
  1308.     elseif tag == 'form' then\
  1309.         return Form\
  1310.     elseif tag == 'script' then\
  1311.         return Script\
  1312.     else\
  1313.         return Element\
  1314.     end\
  1315. end",["SelectOption.lua"]="Value = nil\
  1316. \
  1317. OnInitialise = function(self, node)\
  1318.     if attr.value then\
  1319.         new.Value = attr.value\
  1320.     end\
  1321. end\
  1322. \
  1323. OnCreateObject = function(self, parentObject, y)\
  1324.     if parentObject.AddMenuItem then\
  1325.         parentObject:AddMenuItem({\
  1326.             Value = self.Value,\
  1327.             Text = self.Text,\
  1328.             Type = \"Button\"\
  1329.         })\
  1330.     end\
  1331. end",},["startup"]="local QuestVersion = 'v0.9.0 Private Beta'\
  1332. if OneOS then\
  1333.     QuestVersion = QuestVersion .. '-OneOS ' .. OneOS.Version\
  1334. end\
  1335. \
  1336. -- TODO: have a much simpler API loader... not a 70+ line one\
  1337. local Extension = function(path, addDot)\
  1338.     if not path then\
  1339.         return nil\
  1340.     elseif not string.find(fs.getName(path), '%.') then\
  1341.         if not addDot then\
  1342.             return fs.getName(path)\
  1343.         else\
  1344.             return ''\
  1345.         end\
  1346.     else\
  1347.         local _path = path\
  1348.         if path:sub(#path) == '/' then\
  1349.             _path = path:sub(1,#path-1)\
  1350.         end\
  1351.         local extension = _path:gmatch('%.[0-9a-z]+$')()\
  1352.         if extension then\
  1353.             extension = extension:sub(2)\
  1354.         else\
  1355.             --extension = nil\
  1356.             return ''\
  1357.         end\
  1358.         if addDot then\
  1359.             extension = '.'..extension\
  1360.         end\
  1361.         return extension:lower()\
  1362.     end\
  1363. end\
  1364. \
  1365. local RemoveExtension = function(path)\
  1366.     if path:sub(1,1) == '.' then\
  1367.         return path\
  1368.     end\
  1369.     local extension = Extension(path)\
  1370.     if extension == path then\
  1371.         return fs.getName(path)\
  1372.     end\
  1373.     return string.gsub(path, extension, ''):sub(1, -2)\
  1374. end\
  1375. \
  1376. local tAPIsLoading = {}\
  1377. local function LoadAPI(_sPath)\
  1378.     local sName = RemoveExtension(fs.getName( _sPath ))\
  1379.     if tAPIsLoading[sName] == true then\
  1380.     end\
  1381.     tAPIsLoading[sName] = true\
  1382.         \
  1383.     local tEnv = {isStartup = true }\
  1384.     setmetatable( tEnv, { __index = getfenv()} )\
  1385.     local fnAPI, err = loadfile( _sPath )\
  1386.     if fnAPI then\
  1387.         setfenv( fnAPI, tEnv )\
  1388.         fnAPI()\
  1389.     else\
  1390.         printError( err )\
  1391.         log('Error: '..err)\
  1392.        tAPIsLoading[sName] = nil\
  1393.         return false\
  1394.     end\
  1395.     \
  1396.     local tAPI = {}\
  1397.     for k,v in pairs( tEnv ) do\
  1398.         tAPI[k] =  v\
  1399.     end\
  1400.     \
  1401.     _G[sName] = tAPI\
  1402. end\
  1403. \
  1404. _G.Errors = {\
  1405.     Unknown = 1,\
  1406.     InvalidDoctype = 2,\
  1407.     ParseFailed = 3,\
  1408.     NotFound = 404,\
  1409.     TimeoutStop = 408,\
  1410. }\
  1411. \
  1412. 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 CC Web Browser...')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\
  1413. \
  1414. os.loadAPI('parser')\
  1415. os.loadAPI('hash')\
  1416. os.loadAPI('lQuery')\
  1417. os.loadAPI('Peripheral')\
  1418. os.loadAPI('Wireless')\
  1419. \
  1420. LoadAPI('Elements/Element.lua')\
  1421. \
  1422. LoadAPI('Elements/ElementTree.lua')\
  1423. \
  1424. local elements = {\
  1425.     'Script',\
  1426.     'Center',\
  1427.     'Link',\
  1428.     'Image',\
  1429.     'Divider',\
  1430.     'Heading',\
  1431.     'Paragraph',\
  1432.     'Float',\
  1433.     'TextInput',\
  1434.     'FileInput',\
  1435.     'SecureTextInput',\
  1436.     'Select',\
  1437.     'Form',\
  1438.     'SelectOption',\
  1439.     'ButtonInput',\
  1440.     'HiddenInput',\
  1441. }\
  1442. \
  1443. for i, v in ipairs(elements) do\
  1444.     LoadAPI('Elements/' .. v .. '.lua')\
  1445.     local env = getfenv()\
  1446.     local super = Element\
  1447.     if env[v].Inherit then\
  1448.         super = env[env[v].Inherit]\
  1449.     end\
  1450.     env[v].__index = super\
  1451.     setmetatable(env[v], env[v])\
  1452. end\
  1453. \
  1454. local program = Bedrock:Initialise()\
  1455. \
  1456. local function split(str, pat)\
  1457.   local t = {}\
  1458.   local fpat = \"(.-)\" .. pat\
  1459.   local last_end = 1\
  1460.   local s, e, cap = str:find(fpat, 1)\
  1461.   while s do\
  1462.      if s ~= 1 or cap ~= \"\" then\
  1463.      table.insert(t,cap)\
  1464.      end\
  1465.      last_end = e+1\
  1466.      s, e, cap = str:find(fpat, last_end)\
  1467.   end\
  1468.   if last_end <= #str then\
  1469.      cap = str:sub(last_end)\
  1470.      table.insert(t, cap)\
  1471.   end\
  1472.   return t\
  1473. end\
  1474. \
  1475. local httpQueue = {}\
  1476. \
  1477. program:RegisterEvent('http_success', function(self, event, url, response)\
  1478.     for i, request in ipairs(httpQueue) do\
  1479.         if request[3] == url then\
  1480.             request[2](true, url, response)\
  1481.             table.remove(httpQueue, i)\
  1482.             break\
  1483.         end\
  1484.     end\
  1485. end)\
  1486. \
  1487. program:RegisterEvent('http_failure', function(self, event, url)\
  1488.     for i, request in ipairs(httpQueue) do\
  1489.         if request[3] == url then\
  1490.             request[2](false, Errors.Unknown)\
  1491.             table.remove(httpQueue, i)\
  1492.             break\
  1493.         end\
  1494.     end\
  1495. end)\
  1496. \
  1497. program:RegisterEvent('modem_message', function(self, event, side, channel, replyChannel, message, distance)\
  1498.     Wireless.HandleMessage(event, side, channel, replyChannel, message, distance)\
  1499. end)\
  1500. \
  1501. local wifiQueue = {}\
  1502. \
  1503. Wireless.Responder = function(event, side, channel, replyChannel, message, distance)\
  1504.     if channel == Wireless.Channels.QuestServerRequestReply then\
  1505.         for i, request in ipairs(wifiQueue) do\
  1506.             if request[1] == message.content.url then\
  1507.                 if message.content.content then\
  1508.                     local line = 0\
  1509.                     local lines = split(message.content.content, '\\n')\
  1510.                     local handle = {\
  1511.                         readAll = function()return message.content.content end,\
  1512.                         readLine = function()\
  1513.                             line = line + 1\
  1514.                             return lines[line]\
  1515.                         end,\
  1516.                         close = function()end\
  1517.                     }\
  1518.                     request[2](true, message.content.url, handle)\
  1519.                 else\
  1520.                     request[2](false, 404)\
  1521.                 end\
  1522.                 table.remove(wifiQueue, i)\
  1523.                 break\
  1524.             end\
  1525.         end\
  1526.     end\
  1527. end\
  1528. \
  1529. local function cancelHTTPAsync(url)\
  1530.     for i, request in ipairs(httpQueue) do\
  1531.         if request[1] == url then\
  1532.             request[2](false, Errors.TimeoutStop)\
  1533.             table.remove(httpQueue, i)\
  1534.             break\
  1535.         end\
  1536.     end\
  1537. end\
  1538. \
  1539. local settings = false\
  1540. \
  1541. local function fetchHTTPAsync(url, callback, post)\
  1542.     local components = urlComponents(url)\
  1543.     if components.protocol == 'quest' then\
  1544.         local file = fs.open(program.ProgramPath .. '/Pages/' .. components.filepathsansget, 'r')\
  1545.         callback(true, url, file)\
  1546.     elseif components.protocol == 'file' then\
  1547.         local file = fs.open(components.sansprotocol, 'r')\
  1548.         if file then\
  1549.             callback(true, url, file)\
  1550.         else\
  1551.             callback(false)\
  1552.         end\
  1553.     elseif components.protocol == 'wifi' then\
  1554.         if Wireless.Present() then\
  1555.             table.insert(wifiQueue, {url, callback})\
  1556.             Wireless.SendMessage(Wireless.Channels.QuestServerRequest, url)\
  1557.         else\
  1558.             callback(false, 7)\
  1559.         end\
  1560.     elseif components.protocol == 'http' then\
  1561.         local _url = resolveQuestHostUrl(url)\
  1562.         table.insert(httpQueue, {url, callback, _url})\
  1563. \
  1564.         if not post then\
  1565.             post = 'questClientIdentifier=' .. textutils.urlEncode(settings.ClientIdentifier)\
  1566.         else\
  1567.             post = post .. '&questClientIdentifier=' .. textutils.urlEncode(settings.ClientIdentifier)\
  1568.         end\
  1569.         http.request(_url, post, {\
  1570.             ['User-Agent'] = 'Quest/'..QuestVersion\
  1571.         })\
  1572.     end\
  1573. end\
  1574. \
  1575. local questHost = 'http://quest.net76.net/sites/'\
  1576. \
  1577. local function findLast(haystack, needle)\
  1578.    local i=haystack:match(\".*\"..needle..\"()\")\
  1579.    if i==nil then return nil else return i-1 end\
  1580. end\
  1581. \
  1582. local hex_to_char = function(x)\
  1583.  return string.char(tonumber(x, 16))\
  1584. end\
  1585. \
  1586. local function urlUnencode( str )\
  1587.     -- essentially reverses textutils.urlDecode\
  1588.    if str then\
  1589.        str = string.gsub(str, \"+\", \" \")\
  1590.        str = string.gsub(str, \"\\r\\n\", \"\\n\")\
  1591.        term.setTextColor(colors.black)\
  1592.        str = str:gsub(\"%%(%x%x)\", hex_to_char)\
  1593.    end\
  1594.    return str    \
  1595. end\
  1596. \
  1597. local function urlComponents(url)\
  1598.     if url then\
  1599.         urlUnencode(textutils.urlEncode(url))\
  1600.         local components = {}\
  1601.         local parts = split(url, '[\\\\/]+')\
  1602.         if url:find('://') and parts[1]:sub(#parts[1]) == ':' then\
  1603.             components.protocol = parts[1]:sub(1, #parts[1]-1)\
  1604.             components.sansprotocol = url:sub(#components.protocol + 4)\
  1605.             components.host = parts[2]\
  1606.             components.fullhost = components.protocol .. '://' .. parts[2] .. '/'\
  1607.             components.filepath = url:sub(#components.fullhost)\
  1608.             if components.filepath:sub(#components.filepath) ~= '/' and components.filepath:find('?') then\
  1609.                 components.filename = fs.getName(components.filepath:sub(1, components.filepath:find('?') - 1))\
  1610.             else\
  1611.                 components.filename = fs.getName(components.filepath)\
  1612.             end\
  1613.             if components.filename == 'root' or components.filename == components.host then\
  1614.                 components.filename = ''\
  1615.             end\
  1616.             components.base = url:sub(1, findLast(url, '/'))\
  1617.             components.get = {}\
  1618.             components.filepathsansget = components.sansprotocol\
  1619.             if url:find('?') then\
  1620.                 local start = url:find('?')\
  1621.                 components.filepathsansget = url:sub(#components.protocol + 4, start - 1)\
  1622.                 local getString = url:sub(start + 1)\
  1623.                 local values = split(getString, '&')\
  1624.                 for i, v in ipairs(values) do\
  1625.                     local keyvalue = split(v, '=')\
  1626.                     components.get[keyvalue[1]] =  urlUnencode(keyvalue[2])\
  1627.                 end\
  1628.             end\
  1629.             return components\
  1630.         end\
  1631.     end\
  1632. end\
  1633. \
  1634. local function resolveQuestHostUrl(url)\
  1635.     local components = urlComponents(url)\
  1636.     local hostParts = split(components.host, '%.')\
  1637.     local tld = hostParts[#hostParts]\
  1638.     if tld == 'qst' and #hostParts == 2 then\
  1639.         return questHost .. hostParts[1] .. components.filepath\
  1640.     end\
  1641.     return url\
  1642. end\
  1643. \
  1644. local function resolveFullUrl(url)\
  1645.     if url and type(url) ~= 'string' then\
  1646.     elseif url:find('://') then\
  1647.         return url\
  1648.     else\
  1649.         local components = urlComponents(program:GetObject('WebView').URL)\
  1650.         if components then\
  1651.             if url:sub(1,1) == '/' then\
  1652.                 return components.fullhost .. url:sub(2)\
  1653.             else\
  1654.                 return components.base .. url\
  1655.             end\
  1656.         end\
  1657.     end\
  1658. end\
  1659. \
  1660. local function getCurrentUrl()\
  1661.     return program:GetObject('WebView').URL\
  1662. end\
  1663. \
  1664. local function getCurrentFakeUrl()\
  1665.     return program:GetObject('WebView').FakeURL\
  1666. end\
  1667. \
  1668. local function goToUrl(url, post)\
  1669.     program:GetObject('WebView'):GoToURL(url, nil, nil, post)\
  1670. end\
  1671. \
  1672. --  Yes, it's evil and terrible, etc. But I'll hopefully change it later.\
  1673. _G.cancelHTTPAsync = cancelHTTPAsync\
  1674. _G.fetchHTTPAsync = fetchHTTPAsync\
  1675. _G.resolveFullUrl = resolveFullUrl\
  1676. _G.resolveQuestHostUrl = resolveQuestHostUrl\
  1677. _G.getCurrentUrl = getCurrentUrl\
  1678. _G.getCurrentFakeUrl = getCurrentFakeUrl\
  1679. _G.goToUrl = goToUrl\
  1680. _G.split = split\
  1681. _G.urlComponents = urlComponents\
  1682. _G.QuestVersion = QuestVersion\
  1683. \
  1684. local history = {}\
  1685. local historyItem = 0\
  1686. \
  1687. local function updateHistoryButtons()\
  1688.     if history[historyItem-1] then\
  1689.         program:GetObject('BackButton').Enabled = true\
  1690.     else\
  1691.         program:GetObject('BackButton').Enabled = false\
  1692.     end\
  1693. \
  1694.     if history[historyItem+1] then\
  1695.         program:GetObject('ForwardButton').Enabled = true\
  1696.     else\
  1697.         program:GetObject('ForwardButton').Enabled = false\
  1698.     end\
  1699. end\
  1700. \
  1701. local function addHistoryURL(url)\
  1702.     for i, v in ipairs(history) do\
  1703.         if i > historyItem then\
  1704.             history[i] = nil\
  1705.         end\
  1706.     end\
  1707.     table.insert(history, url)\
  1708.     historyItem = #history\
  1709.     updateHistoryButtons()\
  1710. end\
  1711. \
  1712. local defaultSettings = {\
  1713.     Home = 'http://thehub.qst/',\
  1714.     ClientIdentifier = nil\
  1715. }\
  1716. \
  1717. local function quit()\
  1718.     term.setBackgroundColour(colors.black)\
  1719.     shell.run('clear')\
  1720.     print('Thanks for using CC Web Browser, Created By derekseitz.')\
  1721.     program:Quit()\
  1722. end\
  1723. \
  1724. local function goHome()\
  1725.     goToUrl(settings.Home)\
  1726. end\
  1727. \
  1728. local function saveSettings()\
  1729.     local f = fs.open('.Quest.settings', 'w')\
  1730.     if f then\
  1731.         f.write(textutils.serialize(settings))\
  1732.         f.close()\
  1733.     end\
  1734. end\
  1735. \
  1736. local function generateClientIdentifier()\
  1737.     program:DisplayWindow({\
  1738.         Children = {{\
  1739.             X = 2,\
  1740.             Y = 2,\
  1741.             Type = \"Label\",\
  1742.             Width = \"100%,-2\",\
  1743.             Height = 2,\
  1744.             Text = \"Registering computer with central server...\"\
  1745.         }},\
  1746.         Width = 28,\
  1747.         Height = 4\
  1748.     }, \"Please Wait\", false)\
  1749.     program:Draw()\
  1750.     local h = http.get('http://quest.net76.net/registerClient.php')\
  1751.     program.Window:Close()\
  1752. \
  1753.     if h then\
  1754.         settings.ClientIdentifier = h.readAll()\
  1755.         saveSettings()\
  1756.         h.close()\
  1757.         goHome()\
  1758.     else\
  1759.         program:DisplayAlertWindow(\"Register Failed\", \"Quest couldn't register your computer. There was something wrong with your internet connection. Please quit and try again.\", {'Quit'}, function(value)\
  1760.             quit()\
  1761.         end)\
  1762.     end\
  1763. \
  1764. end\
  1765. \
  1766. local function loadSettings()\
  1767.     if fs.exists('.Quest.settings') then\
  1768.         local f = fs.open('.Quest.settings', 'r')\
  1769.         if f then\
  1770.             settings = textutils.unserialize(f.readAll())\
  1771.             if not settings.ClientIdentifier then\
  1772.                 generateClientIdentifier()\
  1773.             end\
  1774.             return settings\
  1775.         end\
  1776.     end\
  1777. \
  1778.     settings = defaultSettings\
  1779.     generateClientIdentifier()\
  1780. end\
  1781. \
  1782. program:Run(function()\
  1783.     local timeoutTimer = false\
  1784. \
  1785.     program:LoadView('main')\
  1786. \
  1787.     Wireless.Initialise()\
  1788. \
  1789.     loadSettings()\
  1790. \
  1791.     program:GetObject('BackButton').OnClick = function(self)\
  1792.         if history[historyItem-1] then\
  1793.             historyItem = historyItem - 1\
  1794.             program:GetObject('WebView'):GoToURL(history[historyItem], nil, true)\
  1795.             updateHistoryButtons()\
  1796.         end\
  1797.     end\
  1798. \
  1799.     program:GetObject('ForwardButton').OnClick = function(self)\
  1800.         if history[historyItem+1] then\
  1801.             historyItem = historyItem + 1\
  1802.             program:GetObject('WebView'):GoToURL(history[historyItem], nil, true)\
  1803.             updateHistoryButtons()\
  1804.         end\
  1805.     end\
  1806. \
  1807.     program:GetObject('URLTextBox').OnChange = function(self, event, keychar)\
  1808.         if keychar == keys.enter then\
  1809.             local url = self.Text\
  1810.             if not url:find('://') then\
  1811.                 if url:find(' ') or not url:find('%.') then\
  1812.                     url = 'http://thehub.qst/search.php?q='..textutils.urlEncode(url)\
  1813.                 else\
  1814.                     url = 'http://' .. url \
  1815.                 end\
  1816.                 self.Text = url\
  1817.             end\
  1818.             program:GetObject('WebView'):GoToURL(url)\
  1819.         end\
  1820.     end\
  1821. \
  1822.     program:GetObject('OptionsButton').OnClick = function(self, event, side, x, y)\
  1823.         if self:ToggleMenu('optionsmenu', x, y) then\
  1824.             program:GetObject('StopMenuItem').OnClick = function(self, event, side, x, y)\
  1825.                 program:GetObject('WebView'):Stop()\
  1826.             end\
  1827. \
  1828.             program:GetObject('ReloadMenuItem').OnClick = function(self, event, side, x, y)\
  1829.                 program:GetObject('WebView'):GoToURL(program:GetObject('WebView').URL)\
  1830.             end\
  1831. \
  1832.             program:GetObject('GoHomeMenuItem').OnClick = function(self, event, side, x, y)\
  1833.                 goHome()\
  1834.             end\
  1835. \
  1836.             program:GetObject('SetHomeMenuItem').OnClick = function(self, event, side, x, y)\
  1837.                 settings.Home = program:GetObject('WebView').FakeURL\
  1838.                 saveSettings()\
  1839.             end\
  1840. \
  1841.             program:GetObject('QuitMenuItem').OnClick = function(self, event, side, x, y)\
  1842.                 quit()\
  1843.             end\
  1844.         end\
  1845.     end\
  1846. \
  1847.     program:GetObject('WebView').OnPageLoadStart = function(self, url)\
  1848.         program:SetActiveObject()\
  1849.         -- program:GetObject('GoButton').Text = 'x'\
  1850.         program:GetObject('URLTextBox').Visible = false\
  1851.         program:GetObject('LoadingLabel').Visible = true\
  1852.         program:GetObject('PageTitleLabel').Text = ''\
  1853. \
  1854.         if url:find('http://') or url:find('https://') then\
  1855.             timeoutTimer = program:StartTimer(function()\
  1856.                 program:GetObject('WebView'):Stop()\
  1857.             end, 20)\
  1858.         else\
  1859.             timeoutTimer = program:StartTimer(function()\
  1860.                 program:GetObject('WebView'):Stop()\
  1861.             end, 1)\
  1862.         end\
  1863.     end\
  1864. \
  1865.     program:GetObject('WebView').OnPageLoadEnd = function(self, url, noHistory)\
  1866.         program:GetObject('URLTextBox').Text = url\
  1867.         program:GetObject('URLTextBox').Visible = true\
  1868.         program:GetObject('LoadingLabel').Visible = false\
  1869. \
  1870.         if self.Tree:GetElement('title') then\
  1871.             program:GetObject('PageTitleLabel').Text = self.Tree:GetElement('title').Text\
  1872.         end\
  1873. \
  1874.         if not noHistory then\
  1875.             addHistoryURL(url)\
  1876.         end\
  1877. \
  1878.         program.Timers[timeoutTimer] = nil\
  1879.     end\
  1880. \
  1881.     program:GetObject('WebView').OnPageLoadFailed = function(self, url, _error, noHistory)\
  1882.         program:GetObject('URLTextBox').Text = url\
  1883.         program:GetObject('URLTextBox').Visible = true\
  1884.         program:GetObject('LoadingLabel').Visible = false\
  1885.         program.Timers[timeoutTimer] = nil\
  1886. \
  1887.         if not noHistory then\
  1888.             addHistoryURL(url)\
  1889.         end\
  1890. \
  1891.         local get = ''\
  1892.         _error = _error or 1\
  1893.         if type(_error) == 'string' then\
  1894.             get = '?reason='..textutils.urlEncode(_error)\
  1895.             _error = 'text'\
  1896.         end\
  1897. \
  1898.         program:GetObject('WebView'):GoToURL('quest://'.._error..'.ccml'..get, true, true)\
  1899.     end\
  1900. \
  1901.     program:GetObject('Toolbar').OnClick = function(self, event, side, x, y)\
  1902.         program:SetActiveObject()\
  1903.     end\
  1904. \
  1905.     program:GetObject('WebView').OnClick = function(self, event, side, x, y)\
  1906.         program:SetActiveObject()\
  1907.     end\
  1908. \
  1909.     if settings.ClientIdentifier then\
  1910.         goHome()\
  1911.     end\
  1912. end)\
  1913. \
  1914. ",["Bedrock"]="--Bedrock Build: 262\
  1915. --This code is squished down in to one, rather hard to read file.\
  1916. --As such it is not much good for anything other than being loaded as an API.\
  1917. \
  1918. --\
  1919. --\
  1920. \
  1921. local apis = {\
  1922. [\"Drawing\"] = [[\
  1923. local round = function(num, idp)\
  1924.     local mult = 10^(idp or 0)\
  1925.     return math.floor(num * mult + 0.5) / mult\
  1926. end\
  1927. \
  1928. local _w, _h = term.getSize()\
  1929. local copyBuffer = nil\
  1930. \
  1931. Screen = {\
  1932.     Width = _w,\
  1933.     Height = _h\
  1934. }\
  1935. \
  1936. Constraints = {\
  1937.     \
  1938. }\
  1939. \
  1940. CurrentConstraint = {1,1,_w,_h}\
  1941. IgnoreConstraint = false\
  1942. \
  1943. function AddConstraint(x, y, width, height)\
  1944.     local x2 = x + width - 1\
  1945.     local y2 = y + height - 1\
  1946.     table.insert(Drawing.Constraints, {x, y, x2, y2})\
  1947.     Drawing.GetConstraint()\
  1948. end\
  1949. \
  1950. function RemoveConstraint()\
  1951.     --table.remove(Drawing.Constraints, #Drawing.Constraints)\
  1952.     Drawing.Constraints[#Drawing.Constraints] = nil\
  1953.     Drawing.GetConstraint()\
  1954. end\
  1955. \
  1956. function GetConstraint()\
  1957.     local x = 1\
  1958.     local y = 1\
  1959.     local x2 = Drawing.Screen.Width\
  1960.     local y2 = Drawing.Screen.Height\
  1961.     for i, c in ipairs(Drawing.Constraints) do\
  1962.         if x < c[1] then\
  1963.             x = c[1]\
  1964.         end\
  1965.         if y < c[2] then\
  1966.             y = c[2]\
  1967.         end\
  1968.         if x2 > c[3] then\
  1969.             x2 = c[3]\
  1970.         end\
  1971.         if y2 > c[4] then\
  1972.             y2 = c[4]\
  1973.         end\
  1974.     end\
  1975.     Drawing.CurrentConstraint = {x, y, x2, y2}\
  1976. end\
  1977. \
  1978. function WithinContraint(x, y)\
  1979.     return Drawing.IgnoreConstraint or\
  1980.           (x >= Drawing.CurrentConstraint[1] and\
  1981.            y >= Drawing.CurrentConstraint[2] and\
  1982.            x <= Drawing.CurrentConstraint[3] and\
  1983.            y <= Drawing.CurrentConstraint[4])\
  1984. end\
  1985. \
  1986. colours.transparent = 0\
  1987. colors.transparent = 0\
  1988. \
  1989. DrawCharacters = function (x, y, characters, textColour, bgColour)\
  1990.     Drawing.WriteStringToBuffer(x, y, tostring(characters), textColour, bgColour)\
  1991. end\
  1992. \
  1993. DrawBlankArea = function (x, y, w, h, colour)\
  1994.     if colour ~= colours.transparent then\
  1995.         Drawing.DrawArea (x, y, w, h, \" \", 1, colour)\
  1996.     end\
  1997. end\
  1998. \
  1999. DrawArea = function (x, y, w, h, character, textColour, bgColour)\
  2000.     --width must be greater than 1, otherwise we get problems\
  2001.     if w < 0 then\
  2002.         w = w * -1\
  2003.     elseif w == 0 then\
  2004.         w = 1\
  2005.     end\
  2006. \
  2007.     for ix = 1, w do\
  2008.         local currX = x + ix - 1\
  2009.         for iy = 1, h do\
  2010.             local currY = y + iy - 1\
  2011.             Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour)\
  2012.         end\
  2013.     end\
  2014. end\
  2015. \
  2016. DrawImage = function(_x,_y,tImage, w, h)\
  2017.     if tImage then\
  2018.         for y = 1, h do\
  2019.             if not tImage[y] then\
  2020.                 break\
  2021.             end\
  2022.             for x = 1, w do\
  2023.                 if not tImage[y][x] then\
  2024.                     break\
  2025.                 end\
  2026.                 local bgColour = tImage[y][x]\
  2027.                 local textColour = tImage.textcol[y][x] or colours.white\
  2028.                 local char = tImage.text[y][x]\
  2029.                 Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour)\
  2030.             end\
  2031.         end\
  2032.     elseif w and h then\
  2033.         Drawing.DrawBlankArea(_x, _y, w, h, colours.lightGrey)\
  2034.     end\
  2035. end\
  2036. \
  2037. --using .nft\
  2038. LoadImage = function(path, global)\
  2039.     local image = {\
  2040.         text = {},\
  2041.         textcol = {}\
  2042.     }\
  2043.     if fs.exists(path) then\
  2044.         local _io = io\
  2045.         if OneOS and global then\
  2046.             _io = OneOS.IO\
  2047.         end\
  2048.        local file = _io.open(path, \"r\")\
  2049.        if not file then\
  2050.             error('Error Occured. _io:'..tostring(_io)..' OneOS: '..tostring(OneOS)..' OneOS.IO'..tostring(OneOS.IO)..' io: '..tostring(io))\
  2051.        end\
  2052.        local sLine = file:read()\
  2053.        local num = 1\
  2054.        while sLine do  \
  2055.            table.insert(image, num, {})\
  2056.            table.insert(image.text, num, {})\
  2057.            table.insert(image.textcol, num, {})\
  2058.                                        \
  2059.            --As we're no longer 1-1, we keep track of what index to write to\
  2060.            local writeIndex = 1\
  2061.            --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour\
  2062.            local bgNext, fgNext = false, false\
  2063.            --The current background and foreground colours\
  2064.            local currBG, currFG = nil,nil\
  2065.            for i=1,#sLine do\
  2066.                    local nextChar = string.sub(sLine, i, i)\
  2067.                    if nextChar:byte() == 30 then\
  2068.                            bgNext = true\
  2069.                    elseif nextChar:byte() == 31 then\
  2070.                            fgNext = true\
  2071.                    elseif bgNext then\
  2072.                            currBG = Drawing.GetColour(nextChar)\
  2073.                             if currBG == nil then\
  2074.                                 currBG = colours.transparent\
  2075.                             end\
  2076.                            bgNext = false\
  2077.                    elseif fgNext then\
  2078.                            currFG = Drawing.GetColour(nextChar)\
  2079.                             if currFG == nil or currFG == colours.transparent then\
  2080.                                 currFG = colours.white\
  2081.                             end\
  2082.                            fgNext = false\
  2083.                    else\
  2084.                            if nextChar ~= \" \" and currFG == nil then\
  2085.                                    currFG = colours.white\
  2086.                            end\
  2087.                            image[num][writeIndex] = currBG\
  2088.                            image.textcol[num][writeIndex] = currFG\
  2089.                            image.text[num][writeIndex] = nextChar\
  2090.                            writeIndex = writeIndex + 1\
  2091.                    end\
  2092.            end\
  2093.            num = num+1\
  2094.            sLine = file:read()\
  2095.        end\
  2096.        file:close()\
  2097.    else\
  2098.         return nil\
  2099.     end\
  2100.     return image\
  2101. end\
  2102. \
  2103. DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)\
  2104.     w = w or Drawing.Screen.Width\
  2105.     h = h or Drawing.Screen.Height\
  2106.     x = x or 0\
  2107.     y = y or 0\
  2108.     x = math.floor((w - #characters) / 2) + x\
  2109.     y = math.floor(h / 2) + y\
  2110. \
  2111.     Drawing.DrawCharacters(x, y, characters, textColour, bgColour)\
  2112. end\
  2113. \
  2114. GetColour = function(hex)\
  2115.     if hex == ' ' then\
  2116.         return colours.transparent\
  2117.     end\
  2118.    local value = tonumber(hex, 16)\
  2119.    if not value then return nil end\
  2120.    value = math.pow(2,value)\
  2121.    return value\
  2122. end\
  2123. \
  2124. Clear = function (_colour)\
  2125.     _colour = _colour or colours.black\
  2126.     Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour)\
  2127. end\
  2128. \
  2129. Buffer = {}\
  2130. BackBuffer = {}\
  2131. \
  2132. TryRestore = false\
  2133. \
  2134. \
  2135. --TODO: make this quicker\
  2136. -- maybe sort the pixels in order of colour so it doesn't have to set the colour each time\
  2137. DrawBuffer = function()\
  2138.     if TryRestore and Restore then\
  2139.         Restore()\
  2140.     end\
  2141. \
  2142.     for y,row in pairs(Drawing.Buffer) do\
  2143.         for x,pixel in pairs(row) do\
  2144.             local shouldDraw = true\
  2145.             local hasBackBuffer = true\
  2146.             if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then\
  2147.                 hasBackBuffer = false\
  2148.             end\
  2149.             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\
  2150.                 shouldDraw = false\
  2151.             end\
  2152.             if shouldDraw then\
  2153.                 term.setBackgroundColour(pixel[3])\
  2154.                 term.setTextColour(pixel[2])\
  2155.                 term.setCursorPos(x, y)\
  2156.                 term.write(pixel[1])\
  2157.             end\
  2158.         end\
  2159.     end\
  2160.     Drawing.BackBuffer = Drawing.Buffer\
  2161.     Drawing.Buffer = {}\
  2162. end\
  2163. \
  2164. ClearBuffer = function()\
  2165.     Drawing.Buffer = {}\
  2166. end\
  2167. \
  2168. WriteStringToBuffer = function (x, y, characters, textColour,bgColour)\
  2169.     for i = 1, #characters do\
  2170.         local character = characters:sub(i,i)\
  2171.         Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)\
  2172.     end\
  2173. end\
  2174. \
  2175. WriteToBuffer = function(x, y, character, textColour,bgColour, cached)\
  2176.     if not cached and not Drawing.WithinContraint(x, y) then\
  2177.         return\
  2178.     end\
  2179.     x = round(x)\
  2180.     y = round(y)\
  2181. \
  2182.     if textColour == colours.transparent then\
  2183.         character = ' '\
  2184.     end\
  2185. \
  2186.     if bgColour == colours.transparent then\
  2187.         Drawing.Buffer[y] = Drawing.Buffer[y] or {}\
  2188.         Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {\"\", colours.white, colours.black}\
  2189.         Drawing.Buffer[y][x][1] = character\
  2190.         Drawing.Buffer[y][x][2] = textColour\
  2191.     else\
  2192.         Drawing.Buffer[y] = Drawing.Buffer[y] or {}\
  2193.         Drawing.Buffer[y][x] = {character, textColour, bgColour}\
  2194.     end\
  2195. \
  2196.     if copyBuffer then\
  2197.         copyBuffer[y] = copyBuffer[y] or {}\
  2198.         copyBuffer[y][x] = {character, textColour, bgColour}        \
  2199.     end\
  2200. end\
  2201. \
  2202. DrawCachedBuffer = function(buffer)\
  2203.     for y, row in pairs(buffer) do\
  2204.         for x, pixel in pairs(row) do\
  2205.             WriteToBuffer(x, y, pixel[1], pixel[2], pixel[3], true)\
  2206.         end\
  2207.     end\
  2208. end\
  2209. \
  2210. StartCopyBuffer = function()\
  2211.     copyBuffer = {}\
  2212. end\
  2213. \
  2214. EndCopyBuffer = function()\
  2215.     local tmpCopy = copyBuffer\
  2216.     copyBuffer = nil\
  2217.     return tmpCopy\
  2218. end\
  2219. ]],\
  2220. [\"Helpers\"] = [[\
  2221. LongestString = function(input, key, isKey)\
  2222.     local length = 0\
  2223.     if isKey then\
  2224.         for k, v in pairs(input) do\
  2225.             local titleLength = string.len(k)\
  2226.             if titleLength > length then\
  2227.                 length = titleLength\
  2228.             end\
  2229.         end\
  2230.     else\
  2231.         for i = 1, #input do\
  2232.             local value = input[i]\
  2233.             if key then\
  2234.                 if value[key] then\
  2235.                     value = value[key]\
  2236.                 else\
  2237.                     value = ''\
  2238.                 end\
  2239.             end\
  2240.             local titleLength = string.len(value)\
  2241.             if titleLength > length then\
  2242.                 length = titleLength\
  2243.             end\
  2244.         end\
  2245.     end\
  2246.     return length\
  2247. end\
  2248. \
  2249. Split = function(str,sep)\
  2250.    sep=sep or'/'\
  2251.    return str:match(\"(.*\"..sep..\")\")\
  2252. end\
  2253. \
  2254. Extension = function(path, addDot)\
  2255.     if not path then\
  2256.         return nil\
  2257.     elseif not string.find(fs.getName(path), '%.') then\
  2258.         if not addDot then\
  2259.             return fs.getName(path)\
  2260.         else\
  2261.             return ''\
  2262.         end\
  2263.     else\
  2264.         local _path = path\
  2265.         if path:sub(#path) == '/' then\
  2266.             _path = path:sub(1,#path-1)\
  2267.         end\
  2268.         local extension = _path:gmatch('%.[0-9a-z]+$')()\
  2269.         if extension then\
  2270.             extension = extension:sub(2)\
  2271.         else\
  2272.             --extension = nil\
  2273.             return ''\
  2274.         end\
  2275.         if addDot then\
  2276.             extension = '.'..extension\
  2277.         end\
  2278.         return extension:lower()\
  2279.     end\
  2280. end\
  2281. \
  2282. RemoveExtension = function(path)\
  2283. --local name = string.match(fs.getName(path), '(%a+)%.?.-')\
  2284.     if path:sub(1,1) == '.' then\
  2285.         return path\
  2286.     end\
  2287.     local extension = Helpers.Extension(path)\
  2288.     if extension == path then\
  2289.         return fs.getName(path)\
  2290.     end\
  2291.     return string.gsub(path, extension, ''):sub(1, -2)\
  2292. end\
  2293. \
  2294. RemoveFileName = function(path)\
  2295.     if string.sub(path, -1) == '/' then\
  2296.         path = string.sub(path, 1, -2)\
  2297.     end\
  2298.     local v = string.match(path, \"(.-)([^\\\\/]-%.?([^%.\\\\/]*))$\")\
  2299.     if type(v) == 'string' then\
  2300.         return v\
  2301.     end\
  2302.     return v[1]\
  2303. end\
  2304. \
  2305. TruncateString = function(sString, maxLength)\
  2306.     if #sString > maxLength then\
  2307.         sString = sString:sub(1,maxLength-3)\
  2308.         if sString:sub(-1) == ' ' then\
  2309.             sString = sString:sub(1,maxLength-4)\
  2310.         end\
  2311.         sString = sString  .. '...'\
  2312.     end\
  2313.     return sString\
  2314. end\
  2315. \
  2316. TruncateStringStart = function(sString, maxLength)\
  2317.     local len = #sString\
  2318.     if #sString > maxLength then\
  2319.         sString = sString:sub(len - maxLength, len - 3)\
  2320.         if sString:sub(-1) == ' ' then\
  2321.             sString = sString:sub(len - maxLength, len - 4)\
  2322.         end\
  2323.         sString = '...' .. sString\
  2324.     end\
  2325.     return sString\
  2326. end\
  2327. \
  2328. WrapText = function(text, maxWidth)\
  2329.     local lines = {''}\
  2330.    for word, space in text:gmatch('(%S+)(%s*)') do\
  2331.            local temp = lines[#lines] .. word .. space:gsub('\\n','')\
  2332.            if #temp > maxWidth then\
  2333.                    table.insert(lines, '')\
  2334.            end\
  2335.            if space:find('\\n') then\
  2336.                    lines[#lines] = lines[#lines] .. word\
  2337.                    \
  2338.                    space = space:gsub('\\n', function()\
  2339.                            table.insert(lines, '')\
  2340.                            return ''\
  2341.                    end)\
  2342.            else\
  2343.                    lines[#lines] = lines[#lines] .. word .. space\
  2344.            end\
  2345.    end\
  2346.     return lines\
  2347. end\
  2348. \
  2349. TidyPath = function(path)\
  2350.     path = '/'..path\
  2351.     if fs.exists(path) and fs.isDir(path) then\
  2352.         path = path .. '/'\
  2353.     end\
  2354. \
  2355.     path, n = path:gsub(\"//\", \"/\")\
  2356.     while n > 0 do\
  2357.         path, n = path:gsub(\"//\", \"/\")\
  2358.     end\
  2359.     return path\
  2360. end\
  2361. \
  2362. Capitalise = function(str)\
  2363.     return str:sub(1, 1):upper() .. str:sub(2, -1)\
  2364. end\
  2365. \
  2366. Round = function(num, idp)\
  2367.     local mult = 10^(idp or 0)\
  2368.     return math.floor(num * mult + 0.5) / mult\
  2369. end\
  2370. ]],\
  2371. [\"Object\"] = [[\
  2372. X = 1\
  2373. Y = 1\
  2374. Width = 1\
  2375. Height = 1\
  2376. Parent = nil\
  2377. OnClick = nil\
  2378. Visible = true\
  2379. IgnoreClick = false\
  2380. Name = nil \
  2381. ClipDrawing = true\
  2382. UpdateDrawBlacklist = {}\
  2383. Fixed = false\
  2384. \
  2385. DrawCache = {}\
  2386. \
  2387. NeedsDraw = function(self)\
  2388.     if not self.Visible then\
  2389.         return false\
  2390.     end\
  2391.     \
  2392.     if not self.DrawCache.Buffer or self.DrawCache.AlwaysDraw or self.DrawCache.NeedsDraw then\
  2393.         return true\
  2394.     end\
  2395. \
  2396.     if self.OnNeedsUpdate then\
  2397.         if self.OnNeedsUpdate() then\
  2398.             return true\
  2399.         end\
  2400.     end\
  2401. \
  2402.     if self.Children then\
  2403.         for i, v in ipairs(self.Children) do\
  2404.             if v:NeedsDraw() then\
  2405.                 return true\
  2406.             end\
  2407.         end\
  2408.     end\
  2409. end\
  2410. \
  2411. GetPosition = function(self)\
  2412.     return self.Bedrock:GetAbsolutePosition(self)\
  2413. end\
  2414. \
  2415. GetOffsetPosition = function(self)\
  2416.     if not self.Parent then\
  2417.         return {X = 1, Y = 1}\
  2418.     end\
  2419. \
  2420.     local offset = {X = 0, Y = 0}\
  2421.     if not self.Fixed and self.Parent.ChildOffset then\
  2422.         offset = self.Parent.ChildOffset\
  2423.     end\
  2424. \
  2425.     return {X = self.X + offset.X, Y = self.Y + offset.Y}\
  2426. end\
  2427. \
  2428. Draw = function(self)\
  2429.     if not self.Visible then\
  2430.         return\
  2431.     end\
  2432. \
  2433.     self.DrawCache.NeedsDraw = false\
  2434.     local pos = self:GetPosition()\
  2435.     Drawing.StartCopyBuffer()\
  2436. \
  2437.     if self.ClipDrawing then\
  2438.         Drawing.AddConstraint(pos.X, pos.Y, self.Width, self.Height)\
  2439.     end\
  2440. \
  2441.     if self.OnDraw then\
  2442.         self:OnDraw(pos.X, pos.Y)\
  2443.     end\
  2444. \
  2445.     self.DrawCache.Buffer = Drawing.EndCopyBuffer()\
  2446.     \
  2447.     if self.Children then\
  2448.         for i, child in ipairs(self.Children) do\
  2449.             local pos = child:GetOffsetPosition()\
  2450.             if pos.Y + self.Height > 1 and pos.Y <= self.Height and pos.X + self.Width > 1 and pos.X <= self.Width then\
  2451.                 child:Draw()\
  2452.             end\
  2453.         end\
  2454.     end\
  2455. \
  2456.     if self.ClipDrawing then\
  2457.         Drawing.RemoveConstraint()\
  2458.     end \
  2459. end\
  2460. \
  2461. ForceDraw = function(self, ignoreChildren, ignoreParent, ignoreBedrock)\
  2462.     if not ignoreBedrock and self.Bedrock then\
  2463.         self.Bedrock:ForceDraw()\
  2464.     end\
  2465.     self.DrawCache.NeedsDraw = true\
  2466.     if not ignoreParent and self.Parent then\
  2467.         self.Parent:ForceDraw(true, nil, true)\
  2468.     end\
  2469.     if not ignoreChildren and self.Children then\
  2470.         for i, child in ipairs(self.Children) do\
  2471.             child:ForceDraw(nil, true, true)\
  2472.         end\
  2473.     end\
  2474. end\
  2475. \
  2476. OnRemove = function(self)\
  2477.     if self == self.Bedrock:GetActiveObject() then\
  2478.         self.Bedrock:SetActiveObject()\
  2479.     end\
  2480. end\
  2481. \
  2482. local function ParseColour(value)\
  2483.     if type(value) == 'string' then\
  2484.         if colours[value] and type(colours[value]) == 'number' then\
  2485.             return colours[value]\
  2486.         elseif colors[value] and type(colors[value]) == 'number' then\
  2487.             return colors[value]\
  2488.         end\
  2489.     elseif type(value) == 'number' and (value == colours.transparent or (value >= colours.white and value <= colours.black)) then\
  2490.         return value\
  2491.     end\
  2492.     error('Invalid colour: \"'..tostring(value)..'\"')\
  2493. end\
  2494. \
  2495. Initialise = function(self, values)\
  2496.     local _new = values    -- the new instance\
  2497.     _new.DrawCache = {\
  2498.         NeedsDraw = true,\
  2499.         AlwaysDraw = false,\
  2500.         Buffer = nil\
  2501.     }\
  2502.     setmetatable(_new, {__index = self} )\
  2503. \
  2504.     local new = {} -- the proxy\
  2505.     setmetatable(new, {\
  2506.         __index = function(t, k)\
  2507.             if k:find('Color') then\
  2508.                 k = k:gsub('Color', 'Colour')\
  2509.             end\
  2510. \
  2511.             if k:find('Colour') then\
  2512.                 if _new[k] then\
  2513.                     return ParseColour(_new[k])\
  2514.                 end\
  2515.             elseif _new[k] ~= nil then\
  2516.                 return _new[k]\
  2517.             end\
  2518.         end,\
  2519. \
  2520.         __newindex = function (t,k,v)\
  2521.             if k:find('Color') then\
  2522.                 k = k:gsub('Color', 'Colour')\
  2523.             end\
  2524. \
  2525.             if k == 'Width' or k == 'X' or k == 'Height' or k == 'Y' then\
  2526.                 v = new.Bedrock:ParseStringSize(new.Parent, k, v)\
  2527.             end\
  2528. \
  2529.             if v ~= _new[k] then\
  2530.                 _new[k] = v\
  2531.                 if t.OnUpdate then\
  2532.                     t:OnUpdate(k)\
  2533.                 end\
  2534. \
  2535.                 if t.UpdateDrawBlacklist[k] == nil then\
  2536.                     t:ForceDraw()\
  2537.                 end\
  2538.             end\
  2539.         end\
  2540.     })\
  2541.     if new.OnInitialise then\
  2542.         new:OnInitialise()\
  2543.     end\
  2544. \
  2545.     return new\
  2546. end\
  2547. \
  2548. Click = function(self, event, side, x, y)\
  2549.     if self.Visible and not self.IgnoreClick then\
  2550.         if event == 'mouse_click' and self.OnClick and self:OnClick(event, side, x, y) ~= false then\
  2551.             return true\
  2552.         elseif event == 'mouse_drag' and self.OnDrag and self:OnDrag(event, side, x, y) ~= false then\
  2553.             return true\
  2554.         elseif event == 'mouse_scroll' and self.OnScroll and self:OnScroll(event, side, x, y) ~= false then\
  2555.             return true\
  2556.         else\
  2557.             return false\
  2558.         end\
  2559.     else\
  2560.         return false\
  2561.     end\
  2562. \
  2563. end\
  2564. \
  2565. ToggleMenu = function(self, name, x, y)\
  2566.     return self.Bedrock:ToggleMenu(name, self, x, y)\
  2567. end\
  2568. \
  2569. function OnUpdate(self, value)\
  2570.     if value == 'Z' then\
  2571.         self.Bedrock:ReorderObjects()\
  2572.     end\
  2573. end\
  2574. ]],\
  2575. }\
  2576. local objects = {\
  2577. [\"Button\"] = [[\
  2578. BackgroundColour = colours.lightGrey\
  2579. ActiveBackgroundColour = colours.blue\
  2580. ActiveTextColour = colours.white\
  2581. TextColour = colours.black\
  2582. DisabledTextColour = colours.lightGrey\
  2583. Text = \"\"\
  2584. Toggle = nil\
  2585. Momentary = true\
  2586. AutoWidthAutoWidth = true\
  2587. Align = 'Center'\
  2588. Enabled = true\
  2589. \
  2590. OnUpdate = function(self, value)\
  2591.     if value == 'Text' and self.AutoWidth then\
  2592.         self.Width = #self.Text + 2\
  2593.     end\
  2594. end\
  2595. \
  2596. OnDraw = function(self, x, y)\
  2597.     local bg = self.BackgroundColour\
  2598. \
  2599.     if self.Toggle then\
  2600.         bg = self.ActiveBackgroundColour\
  2601.     end\
  2602. \
  2603.     local txt = self.TextColour\
  2604.     if self.Toggle then\
  2605.         txt = self.ActiveTextColour\
  2606.     end\
  2607.     if not self.Enabled then\
  2608.         txt = self.DisabledTextColour\
  2609.     end\
  2610.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, bg)\
  2611. \
  2612.     local _x = 1\
  2613.    if self.Align == 'Right' then\
  2614.        _x = self.Width - #self.Text - 1\
  2615.    elseif self.Align == 'Center' then\
  2616.        _x = math.floor((self.Width - #self.Text) / 2)\
  2617.    end\
  2618.     Drawing.DrawCharacters(x + _x, y, self.Text, txt, bg)\
  2619. end\
  2620. \
  2621. OnLoad = function(self)\
  2622.     if self.Toggle ~= nil then\
  2623.         self.Momentary = false\
  2624.     end\
  2625. end\
  2626. \
  2627. Click = function(self, event, side, x, y)\
  2628.     if self.Visible and not self.IgnoreClick and self.Enabled and event ~= 'mouse_scroll' then\
  2629.         if self.OnClick then\
  2630.             if self.Momentary then\
  2631.                 self.Toggle = true\
  2632.                 self.Bedrock:StartTimer(function()self.Toggle = false end,0.25)\
  2633.             elseif self.Toggle ~= nil then\
  2634.                 self.Toggle = not self.Toggle\
  2635.             end\
  2636. \
  2637.             self:OnClick(event, side, x, y, self.Toggle)\
  2638.         else\
  2639.             self.Toggle = not self.Toggle\
  2640.         end\
  2641.         return true\
  2642.     else\
  2643.         return false\
  2644.     end\
  2645. end\
  2646. ]],\
  2647. [\"CollectionView\"] = [[\
  2648. Inherit = 'ScrollView'\
  2649. UpdateDrawBlacklist = {['NeedsItemUpdate']=true}\
  2650. \
  2651. TextColour = colours.black\
  2652. BackgroundColour = colours.white\
  2653. Items = false\
  2654. NeedsItemUpdate = false\
  2655. SpacingX = 2\
  2656. SpacingY = 1\
  2657. \
  2658. OnDraw = function(self, x, y)\
  2659.     if self.NeedsItemUpdate then\
  2660.         self:UpdateItems()\
  2661.         self.NeedsItemUpdate = false\
  2662.     end\
  2663.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  2664. end\
  2665. \
  2666. local function MaxIcons(self, obj)\
  2667.     local x, y = 2, 1\
  2668.     if not obj.Height or not obj.Width then\
  2669.         error('You must provide each object\\'s height when adding to a CollectionView.')\
  2670.     end\
  2671.     local slotHeight = obj.Height + self.SpacingY\
  2672.     local slotWidth = obj.Width + self.SpacingX\
  2673.     local maxX = math.floor((self.Width - 2) / slotWidth)\
  2674.     return x, y, maxX, slotWidth, slotHeight\
  2675. end\
  2676. \
  2677. local function IconLocation(self, obj, i)\
  2678.     local x, y, maxX, slotWidth, slotHeight = MaxIcons(self, obj)\
  2679.     local rowPos = ((i - 1) % maxX)\
  2680.     local colPos = math.ceil(i / maxX) - 1\
  2681.     x = x + (slotWidth * rowPos)\
  2682.     y = y + colPos * slotHeight\
  2683.     return x, y\
  2684. end\
  2685. \
  2686. local function AddItem(self, v, i)\
  2687.     local toggle = false\
  2688.     if not self.CanSelect then\
  2689.         toggle = nil\
  2690.     end\
  2691.     local x, y = IconLocation(self, v, i)\
  2692.     local item = {\
  2693.         [\"X\"]=x,\
  2694.         [\"Y\"]=y,\
  2695.         [\"Name\"]=\"CollectionViewItem\",\
  2696.         [\"Type\"]=\"View\",\
  2697.         [\"TextColour\"]=self.TextColour,\
  2698.         [\"BackgroundColour\"]=0F,\
  2699.         OnClick = function(itm)\
  2700.             if self.CanSelect then\
  2701.                 for i2, _v in ipairs(self.Children) do\
  2702.                     _v.Toggle = false\
  2703.                 end\
  2704.                 self.Selected = itm\
  2705.             end\
  2706.         end\
  2707.    }\
  2708.     for k, _v in pairs(v) do\
  2709.         item[k] = _v\
  2710.     end\
  2711.     self:AddObject(item)\
  2712. end\
  2713. \
  2714. \
  2715. UpdateItems = function(self)\
  2716.     self:RemoveAllObjects()\
  2717.     local groupMode = false\
  2718.     for k, v in pairs(self.Items) do\
  2719.         if type(k) == 'string' then\
  2720.             groupMode = true\
  2721.             break\
  2722.         end\
  2723.     end\
  2724. \
  2725.     for i, v in ipairs(self.Items) do\
  2726.         AddItem(self, v, i)\
  2727.     end\
  2728.     self:UpdateScroll()\
  2729. end\
  2730. \
  2731. OnUpdate = function(self, value)\
  2732.     if value == 'Items' then\
  2733.         self.NeedsItemUpdate = true\
  2734.     end\
  2735. end\
  2736. ]],\
  2737. [\"ImageView\"] = [[\
  2738. Image = false\
  2739. \
  2740. OnDraw = function(self, x, y)\
  2741.     Drawing.DrawImage(x, y, self.Image, self.Width, self.Height)\
  2742. end\
  2743. \
  2744. OnLoad = function(self)\
  2745.     if self.Path and fs.exists(self.Path) then\
  2746.         self.Image = Drawing.LoadImage(self.Path)\
  2747.     end\
  2748. end\
  2749. \
  2750. OnUpdate = function(self, value)\
  2751.     if value == 'Path' then\
  2752.         if self.Path and fs.exists(self.Path) then\
  2753.             self.Image = Drawing.LoadImage(self.Path)\
  2754.         end\
  2755.     end\
  2756. end\
  2757. ]],\
  2758. [\"Label\"] = [[\
  2759. TextColour = colours.black\
  2760. BackgroundColour = colours.transparent\
  2761. Text = \"\"\
  2762. AutoWidth = false\
  2763. Align = 'Left'\
  2764. \
  2765. local wrapText = function(text, maxWidth)\
  2766.    local lines = {''}\
  2767.    for word, space in text:gmatch('(%S+)(%s*)') do\
  2768.        local temp = lines[#lines] .. word .. space:gsub('\\n','')\
  2769.        if #temp > maxWidth then\
  2770.            table.insert(lines, '')\
  2771.        end\
  2772.        if space:find('\\n') then\
  2773.            lines[#lines] = lines[#lines] .. word\
  2774.            \
  2775.            space = space:gsub('\\n', function()\
  2776.                    table.insert(lines, '')\
  2777.                    return ''\
  2778.            end)\
  2779.        else\
  2780.            lines[#lines] = lines[#lines] .. word .. space\
  2781.        end\
  2782.    end\
  2783.    if #lines[1] == 0 then\
  2784.        table.remove(lines,1)\
  2785.    end\
  2786.    return lines\
  2787. end\
  2788. \
  2789. OnUpdate = function(self, value)\
  2790.    if value == 'Text' then\
  2791.        if self.AutoWidth then\
  2792.            self.Width = #self.Text\
  2793.        else\
  2794.            self.Height = #wrapText(self.Text, self.Width)\
  2795.        end\
  2796.    end\
  2797. end\
  2798. \
  2799. OnDraw = function(self, x, y)\
  2800.     for i, v in ipairs(wrapText(self.Text, self.Width)) do\
  2801.        local _x = 0\
  2802.        if self.Align == 'Right' then\
  2803.            _x = self.Width - #v\
  2804.        elseif self.Align == 'Center' then\
  2805.            _x = math.floor((self.Width - #v) / 2)\
  2806.        end\
  2807.         Drawing.DrawCharacters(x + _x, y + i - 1, v, self.TextColour, self.BackgroundColour)\
  2808.     end\
  2809. end\
  2810. ]],\
  2811. [\"ListView\"] = [[\
  2812. Inherit = 'ScrollView'\
  2813. UpdateDrawBlacklist = {['NeedsItemUpdate']=true}\
  2814. \
  2815. TextColour = colours.black\
  2816. BackgroundColour = colours.white\
  2817. HeadingColour = colours.lightGrey\
  2818. SelectionBackgroundColour = colours.blue\
  2819. SelectionTextColour = colours.white\
  2820. Items = false\
  2821. CanSelect = false\
  2822. Selected = nil\
  2823. NeedsItemUpdate = false\
  2824. ItemMargin = 1\
  2825. HeadingMargin = 0\
  2826. TopMargin = 0\
  2827. \
  2828. OnDraw = function(self, x, y)\
  2829.     if self.NeedsItemUpdate then\
  2830.         self:UpdateItems()\
  2831.     end\
  2832.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  2833. end\
  2834. \
  2835. local function AddItem(self, v, x, y, group)\
  2836.     local toggle = false\
  2837.     if not self.CanSelect then\
  2838.         toggle = nil\
  2839.     elseif v.Selected then\
  2840.         toggle = true\
  2841.     end\
  2842.     local item = {\
  2843.         [\"Width\"]=self.Width,\
  2844.         [\"X\"]=x,\
  2845.         [\"Y\"]=y,\
  2846.         [\"Name\"]=\"ListViewItem\",\
  2847.         [\"Type\"]=\"Button\",\
  2848.         [\"TextColour\"]=self.TextColour,\
  2849.         [\"BackgroundColour\"]=0,\
  2850.         [\"ActiveTextColour\"]=self.SelectionTextColour,\
  2851.         [\"ActiveBackgroundColour\"]=self.SelectionBackgroundColour,\
  2852.         [\"Align\"]='Left',\
  2853.         [\"Toggle\"]=toggle,\
  2854.         [\"Group\"]=group,\
  2855.         OnClick = function(itm)\
  2856.             if self.CanSelect then\
  2857.                 self:SelectItem(itm)\
  2858.             elseif self.OnSelect then\
  2859.                 self:OnSelect(itm.Text)\
  2860.             end\
  2861.         end\
  2862.    }\
  2863.    if type(v) == 'table' then\
  2864.         for k, _v in pairs(v) do\
  2865.             item[k] = _v\
  2866.         end\
  2867.    else\
  2868.         item.Text = v\
  2869.    end\
  2870.     \
  2871.     local itm = self:AddObject(item)\
  2872.     if v.Selected then\
  2873.         self:SelectItem(itm)\
  2874.     end\
  2875. end\
  2876. \
  2877. UpdateItems = function(self)\
  2878.     if not self.Items or type(self.Items) ~= 'table' then\
  2879.         self.Items = {}\
  2880.     end\
  2881.     self.Selected = nil\
  2882.     self:RemoveAllObjects()\
  2883.     local groupMode = false\
  2884.     for k, v in pairs(self.Items) do\
  2885.         if type(k) == 'string' then\
  2886.             groupMode = true\
  2887.             break\
  2888.         end\
  2889.     end\
  2890. \
  2891.     if not groupMode then\
  2892.         for i, v in ipairs(self.Items) do\
  2893.             AddItem(self, v, self.ItemMargin, i)\
  2894.         end\
  2895.     else\
  2896.         local y = self.TopMargin\
  2897.         for k, v in pairs(self.Items) do\
  2898.             y = y + 1\
  2899.             AddItem(self, {Text = k, TextColour = self.HeadingColour, IgnoreClick = true}, self.HeadingMargin, y)\
  2900.             for i, _v in ipairs(v) do\
  2901.                 y = y + 1\
  2902.                 AddItem(self, _v, 1, y, k)\
  2903.             end\
  2904.             y = y + 1\
  2905.         end\
  2906.     end\
  2907.     self:UpdateScroll()\
  2908.     self.NeedsItemUpdate = false\
  2909. end\
  2910. \
  2911. OnKeyChar = function(self, event, keychar)\
  2912.     if keychar == keys.up or keychar == keys.down then\
  2913.         local n = self:GetIndex(self.Selected)\
  2914.         if keychar == keys.up then\
  2915.             n = n - 1\
  2916.         else\
  2917.             n = n + 1\
  2918.         end\
  2919.         local new = self:GetNth(n)\
  2920.         if new then\
  2921.             self:SelectItem(new)\
  2922.         end\
  2923.     elseif keychar == keys.enter and self.Selected then\
  2924.         self.Selected:Click('mouse_click', 1, 1, 1)\
  2925.     end\
  2926. end\
  2927. \
  2928. --returns the index/'n' of the given item\
  2929. GetIndex = function(self, obj)\
  2930.     local n = 1\
  2931.     for i, v in ipairs(self.Children) do\
  2932.         if not v.IgnoreClick then\
  2933.             if obj == v then\
  2934.                 return n\
  2935.             end\
  2936.             n = n + 1\
  2937.         end\
  2938.     end\
  2939. end\
  2940. \
  2941. --gets the 'nth' list item (does not include headings)\
  2942. GetNth = function(self, n)\
  2943.     local _n = 1\
  2944.     for i, v in ipairs(self.Children) do\
  2945.         if not v.IgnoreClick then\
  2946.             if n == _n then\
  2947.                 return v\
  2948.             end\
  2949.             _n = _n + 1\
  2950.         end\
  2951.     end\
  2952. end\
  2953. \
  2954. SelectItem = function(self, item)\
  2955.     for i, v in ipairs(self.Children) do\
  2956.         v.Toggle = false\
  2957.     end\
  2958.     self.Selected = item\
  2959.     item.Toggle = true\
  2960.     if self.OnSelect then\
  2961.         self:OnSelect(item.Text)\
  2962.     end\
  2963. end\
  2964. \
  2965. OnUpdate = function(self, value)\
  2966.     if value == 'Items' then\
  2967.         self.NeedsItemUpdate = true\
  2968.     end\
  2969. end\
  2970. ]],\
  2971. [\"Menu\"] = [[\
  2972. Inherit = 'View'\
  2973. \
  2974. TextColour = colours.black\
  2975. BackgroundColour = colours.white\
  2976. HideTop = false\
  2977. \
  2978. OnDraw = function(self, x, y)\
  2979.     Drawing.IgnoreConstraint = true\
  2980.     Drawing.DrawBlankArea(x + 1, y + (self.HideTop and 0 or 1), self.Width, self.Height + (self.HideTop and 1 or 0), colours.grey)\
  2981.     Drawing.IgnoreConstraint = false\
  2982.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  2983. end\
  2984. \
  2985. OnLoad = function(self)\
  2986.     local owner = self.Owner\
  2987.     if type(owner) == 'string' then\
  2988.         owner = self.Bedrock:GetObject(self.Owner)\
  2989.     end\
  2990. \
  2991.     if owner then\
  2992.         if self.X == 0 and self.Y == 0 then\
  2993.             local pos = owner:GetPosition()\
  2994.             self.X = pos.X\
  2995.             self.Y = pos.Y + owner.Height\
  2996.         end\
  2997.         self.Owner = owner\
  2998.     else\
  2999.         self.Owner = nil\
  3000.     end\
  3001. end\
  3002. \
  3003. OnUpdate = function(self, value)\
  3004.     if value == 'Children' then\
  3005.         self.Width = self.Bedrock.Helpers.LongestString(self.Children, 'Text') + 2\
  3006.         self.Height = #self.Children + 1 + (self.HideTop and 0 or 1)\
  3007.         if not self.BaseY then\
  3008.             self.BaseY = self.Y\
  3009.         end\
  3010. \
  3011.         for i, v in ipairs(self.Children) do\
  3012.             if v.TextColour then\
  3013.                 v.TextColour = self.TextColour\
  3014.             end\
  3015.             if v.BackgroundColour then\
  3016.                 v.BackgroundColour = colours.transparent\
  3017.             end\
  3018.             if v.Colour then\
  3019.                 v.Colour = colours.lightGrey\
  3020.             end\
  3021.             v.Align = 'Left'\
  3022.             v.X = 1\
  3023.             v.Y = i + (self.HideTop and 0 or 1)\
  3024.             v.Width = self.Width\
  3025.             v.Height = 1\
  3026.         end\
  3027. \
  3028.         self.Y = self.BaseY\
  3029.         local pos = self:GetPosition()\
  3030.         if pos.Y + self.Height + 1 > Drawing.Screen.Height then\
  3031.             self.Y = self.BaseY - ((self.Height +  pos.Y) - Drawing.Screen.Height)\
  3032.         end\
  3033.         \
  3034.         if pos.X + self.Width > Drawing.Screen.Width then\
  3035.             self.X = Drawing.Screen.Width - self.Width\
  3036.         end\
  3037.     end\
  3038. end\
  3039. \
  3040. Close = function(self, isBedrockCall)\
  3041.     self.Bedrock.Menu = nil\
  3042.     self.Parent:RemoveObject(self)\
  3043.     if self.Owner and self.Owner.Toggle then\
  3044.         self.Owner.Toggle = false\
  3045.     end\
  3046.     self.Parent:ForceDraw()\
  3047.     self = nil\
  3048. end\
  3049. \
  3050. OnChildClick = function(self, child, event, side, x, y)\
  3051.     self:Close()\
  3052. end\
  3053. ]],\
  3054. [\"ProgressBar\"] = [[\
  3055. BackgroundColour = colours.lightGrey\
  3056. BarColour = colours.blue\
  3057. TextColour = colours.white\
  3058. ShowText = false\
  3059. Value = 0\
  3060. Maximum = 1\
  3061. Indeterminate = false\
  3062. AnimationStep = 0\
  3063. \
  3064. OnDraw = function(self, x, y)\
  3065.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  3066. \
  3067.     -- if self.Indeterminate then\
  3068.     --  for i = 1, self.Width do\
  3069.     --      local s = x + i - 1 + self.AnimationStep\
  3070.     --      if s % 4 == 1 or s % 4 == 2 then\
  3071.     --          Drawing.DrawBlankArea(s, y, 1, self.Height, self.BarColour)\
  3072.     --      end\
  3073.     --  end\
  3074.     --  self.AnimationStep = self.AnimationStep + 1\
  3075.     --  if self.AnimationStep >= 4 then\
  3076.     --      self.AnimationStep = 0\
  3077.     --  end\
  3078.     --  self.Bedrock:StartTimer(function()\
  3079.     --      self:Draw()\
  3080.     --  end, 0.25)\
  3081.     -- else\
  3082.         local values = self.Value\
  3083.         local barColours = self.BarColour\
  3084.         if type(values) == 'number' then\
  3085.             values = {values}\
  3086.         end\
  3087.         if type(barColours) == 'number' then\
  3088.             barColours = {barColours}\
  3089.         end\
  3090.         local total = 0\
  3091.         local _x = x\
  3092.         for i, v in ipairs(values) do\
  3093.             local width = self.Bedrock.Helpers.Round((v / self.Maximum) * self.Width)\
  3094.             total = total + v\
  3095.             Drawing.DrawBlankArea(_x, y, width, self.Height, barColours[((i-1)%#barColours)+1])\
  3096.             _x = _x + width\
  3097.         end\
  3098. \
  3099.         if self.ShowText then\
  3100.             local text = self.Bedrock.Helpers.Round((total / self.Maximum) * 100) .. '%'\
  3101.             Drawing.DrawCharactersCenter(x, y, self.Width, self.Height, text, self.TextColour, colours.transparent)\
  3102.         end\
  3103.     -- end\
  3104. end\
  3105. ]],\
  3106. [\"ScrollBar\"] = [[\
  3107. BackgroundColour = colours.lightGrey\
  3108. BarColour = colours.lightBlue\
  3109. Scroll = 0\
  3110. MaxScroll = 0\
  3111. ClickPoint = nil\
  3112. Fixed = true\
  3113. \
  3114. OnUpdate = function(self, value)\
  3115.     if value == 'Text' and self.AutoWidth then\
  3116.         self.Width = #self.Text + 2\
  3117.     end\
  3118. end\
  3119. \
  3120. OnDraw = function(self, x, y)\
  3121.     local barHeight = self.Height * (self.Height / (self.Height + self.MaxScroll))\
  3122.    if barHeight < 3 then\
  3123.      barHeight = 3\
  3124.    end\
  3125.    local percentage = (self.Scroll/self.MaxScroll)\
  3126. \
  3127.    Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  3128.    Drawing.DrawBlankArea(x, y + math.ceil(self.Height*percentage - barHeight*percentage), self.Width, barHeight, self.BarColour)\
  3129. end\
  3130. \
  3131. OnScroll = function(self, event, direction, x, y)\
  3132.     if event == 'mouse_scroll' then\
  3133.         direction = self.Bedrock.Helpers.Round(direction * 3)\
  3134.     end\
  3135.     if self.Scroll < 0 or self.Scroll > self.MaxScroll then\
  3136.         return false\
  3137.     end\
  3138.     local old = self.Scroll\
  3139.     self.Scroll = self.Bedrock.Helpers.Round(self.Scroll + direction)\
  3140.     if self.Scroll < 0 then\
  3141.         self.Scroll = 0\
  3142.     elseif self.Scroll > self.MaxScroll then\
  3143.         self.Scroll = self.MaxScroll\
  3144.     end\
  3145. \
  3146.     if self.Scroll ~= old and self.OnChange then\
  3147.         self:OnChange()\
  3148.     end\
  3149. end\
  3150. \
  3151. OnClick = function(self, event, side, x, y)\
  3152.     if event == 'mouse_click' then\
  3153.         self.ClickPoint = y\
  3154.     else\
  3155.         local gapHeight = self.Height - (self.Height * (self.Height / (self.Height + self.MaxScroll)))\
  3156.         local barHeight = self.Height * (self.Height / (self.Height + self.MaxScroll))\
  3157.         --local delta = (self.Height + self.MaxScroll) * ((y - self.ClickPoint) / barHeight)\
  3158.         local delta = ((y - self.ClickPoint)/gapHeight)*self.MaxScroll\
  3159.         --l(((y - self.ClickPoint)/gapHeight))\
  3160.         --l(delta)\
  3161.         self.Scroll = self.Bedrock.Helpers.Round(delta)\
  3162.         --l(self.Scroll)\
  3163.         --l('----')\
  3164.         if self.Scroll < 0 then\
  3165.             self.Scroll = 0\
  3166.         elseif self.Scroll > self.MaxScroll then\
  3167.             self.Scroll = self.MaxScroll\
  3168.         end\
  3169.         if self.OnChange then\
  3170.             self:OnChange()\
  3171.         end\
  3172.     end\
  3173. \
  3174.     local relScroll = self.MaxScroll * ((y-1)/self.Height)\
  3175.     if y == self.Height then\
  3176.         relScroll = self.MaxScroll\
  3177.     end\
  3178.     self.Scroll = self.Bedrock.Helpers.Round(relScroll)\
  3179. \
  3180. \
  3181. end\
  3182. \
  3183. OnDrag = OnClick\
  3184. ]],\
  3185. [\"ScrollView\"] = [[\
  3186. Inherit = 'View'\
  3187. ChildOffset = false\
  3188. ContentWidth = 0\
  3189. ContentHeight = 0\
  3190. \
  3191. CalculateContentSize = function(self)\
  3192.     local function calculateObject(obj)\
  3193.         local pos = obj:GetPosition()\
  3194.         local x2 = pos.X + obj.Width - 1\
  3195.         local y2 = pos.Y + obj.Height - 1\
  3196.         if obj.Children then\
  3197.             for i, child in ipairs(obj.Children) do\
  3198.                 local _x2, _y2 = calculateObject(child)\
  3199.                 if _x2 > x2 then\
  3200.                     x2 = _x2\
  3201.                 end\
  3202.                 if _y2 > y2 then\
  3203.                     y2 = _y2\
  3204.                 end\
  3205.             end\
  3206.         end\
  3207.         return x2, y2\
  3208.     end\
  3209. \
  3210.     local pos = self:GetPosition()\
  3211.     local x2, y2 = calculateObject(self)\
  3212.     self.ContentWidth = x2 - pos.X + 1\
  3213.     self.ContentHeight = y2 - pos.Y + 1\
  3214. end\
  3215. \
  3216. UpdateScroll = function(self)\
  3217.     self.ChildOffset.Y = 0\
  3218.     self:CalculateContentSize()\
  3219.     if self.ContentHeight > self.Height then\
  3220.         if not self:GetObject('ScrollViewScrollBar') then\
  3221.             local _scrollBar = self:AddObject({\
  3222.                 [\"Name\"] = 'ScrollViewScrollBar',\
  3223.                 [\"Type\"] = 'ScrollBar',\
  3224.                 [\"X\"] = self.Width,\
  3225.                 [\"Y\"] = 1,\
  3226.                 [\"Width\"] = 1,\
  3227.                 [\"Height\"] = self.Height,\
  3228.                 [\"Z\"]=999\
  3229.             })\
  3230. \
  3231.             _scrollBar.OnChange = function(scrollBar)\
  3232.                 self.ChildOffset.Y = -scrollBar.Scroll\
  3233.                 for i, child in ipairs(self.Children) do\
  3234.                     child:ForceDraw()\
  3235.                 end\
  3236.             end\
  3237.         end\
  3238.         self:GetObject('ScrollViewScrollBar').MaxScroll = self.ContentHeight - self.Height\
  3239.     else\
  3240.         self:RemoveObject('ScrollViewScrollBar')\
  3241.     end\
  3242. end\
  3243. \
  3244. OnScroll = function(self, event, direction, x, y)\
  3245.     if self:GetObject('ScrollViewScrollBar') then\
  3246.         self:GetObject('ScrollViewScrollBar'):OnScroll(event, direction, x, y)\
  3247.     end\
  3248. end\
  3249. \
  3250. OnLoad = function(self)\
  3251.     if not self.ChildOffset or not self.ChildOffset.X or not self.ChildOffset.Y then\
  3252.         self.ChildOffset = {X = 0, Y = 0}\
  3253.     end\
  3254. end\
  3255. ]],\
  3256. [\"SecureTextBox\"] = [[\
  3257. Inherit = 'TextBox'\
  3258. MaskCharacter = '*'\
  3259. \
  3260. OnDraw = function(self, x, y)\
  3261.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  3262.     if self.CursorPos > #self.Text then\
  3263.         self.CursorPos = #self.Text\
  3264.     elseif self.CursorPos < 0 then\
  3265.         self.CursorPos = 0\
  3266.     end\
  3267.     local text = ''\
  3268. \
  3269.     for i = 1, #self.Text do\
  3270.         text = text .. self.MaskCharacter\
  3271.     end\
  3272. \
  3273.     if self.Bedrock:GetActiveObject() == self then\
  3274.         if #text > (self.Width - 2) then\
  3275.             text = text:sub(#text-(self.Width - 3))\
  3276.             self.Bedrock.CursorPos = {x + 1 + self.Width-2, y}\
  3277.         else\
  3278.             self.Bedrock.CursorPos = {x + 1 + self.CursorPos, y}\
  3279.         end\
  3280.         self.Bedrock.CursorColour = self.TextColour\
  3281.     end\
  3282. \
  3283.     if #tostring(text) == 0 then\
  3284.         Drawing.DrawCharacters(x + 1, y, self.Placeholder, self.PlaceholderTextColour, self.BackgroundColour)\
  3285.     else\
  3286.         if not self.Selected then\
  3287.             Drawing.DrawCharacters(x + 1, y, text, self.TextColour, self.BackgroundColour)\
  3288.         else\
  3289.             for i = 1, #text do\
  3290.                 local char = text:sub(i, i)\
  3291.                 local textColour = self.TextColour\
  3292.                 local backgroundColour = self.BackgroundColour\
  3293.                 if i > self.DragStart and i - 1 <= self.CursorPos then\
  3294.                     textColour = self.SelectedTextColour\
  3295.                     backgroundColour = self.SelectedBackgroundColour\
  3296.                 end\
  3297.                 Drawing.DrawCharacters(x + i, y, char, textColour, backgroundColour)\
  3298.             end\
  3299.         end\
  3300.     end\
  3301. end\
  3302. ]],\
  3303. [\"Separator\"] = [[\
  3304. Colour = colours.grey\
  3305. \
  3306. OnDraw = function(self, x, y)\
  3307.     local char = \"|\"\
  3308.     if self.Width > self.Height then\
  3309.         char = '-'\
  3310.     end\
  3311.     Drawing.DrawArea(x, y, self.Width, self.Height, char, self.Colour, colours.transparent)\
  3312. end\
  3313. ]],\
  3314. [\"TextBox\"] = [[\
  3315. BackgroundColour = colours.lightGrey\
  3316. SelectedBackgroundColour = colours.blue\
  3317. SelectedTextColour = colours.white\
  3318. TextColour = colours.black\
  3319. PlaceholderTextColour = colours.grey\
  3320. Placeholder = ''\
  3321. AutoWidth = false\
  3322. Text = \"\"\
  3323. CursorPos = nil\
  3324. Numerical = false\
  3325. DragStart = nil\
  3326. Selected = false\
  3327. SelectOnClick = false\
  3328. ActualDragStart = nil\
  3329. \
  3330. OnDraw = function(self, x, y)\
  3331.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  3332.     if self.CursorPos > #self.Text then\
  3333.         self.CursorPos = #self.Text\
  3334.     elseif self.CursorPos < 0 then\
  3335.         self.CursorPos = 0\
  3336.     end\
  3337.     local text = self.Text\
  3338.     local offset = self:TextOffset()\
  3339.     if #text > (self.Width - 2) then\
  3340.         text = text:sub(offset+1, offset + self.Width - 2)\
  3341.         -- self.Bedrock.CursorPos = {x + 1 + self.Width-2, y}\
  3342.     -- else\
  3343.     end\
  3344.     if self.Bedrock:GetActiveObject() == self then\
  3345.         self.Bedrock.CursorPos = {x + 1 + self.CursorPos - offset, y}\
  3346.         self.Bedrock.CursorColour = self.TextColour\
  3347.     else\
  3348.         self.Selected = false\
  3349.     end\
  3350. \
  3351.     if #tostring(text) == 0 then\
  3352.         Drawing.DrawCharacters(x + 1, y, self.Placeholder, self.PlaceholderTextColour, self.BackgroundColour)\
  3353.     else\
  3354.         if not self.Selected then\
  3355.             Drawing.DrawCharacters(x + 1, y, text, self.TextColour, self.BackgroundColour)\
  3356.         else\
  3357.             local startPos = self.DragStart - offset\
  3358.             local endPos = self.CursorPos - offset\
  3359.             if startPos > endPos then\
  3360.                 startPos = self.CursorPos - offset\
  3361.                 endPos = self.DragStart - offset\
  3362.             end\
  3363.             for i = 1, #text do\
  3364.                 local char = text:sub(i, i)\
  3365.                 local textColour = self.TextColour\
  3366.                 local backgroundColour = self.BackgroundColour\
  3367. \
  3368.                 if i > startPos and i - 1 <= endPos then\
  3369.                     textColour = self.SelectedTextColour\
  3370.                     backgroundColour = self.SelectedBackgroundColour\
  3371.                 end\
  3372.                 Drawing.DrawCharacters(x + i, y, char, textColour, backgroundColour)\
  3373.             end\
  3374.         end\
  3375.     end\
  3376. end\
  3377. \
  3378. TextOffset = function(self)\
  3379.     if #self.Text < (self.Width - 2) then\
  3380.         return 0\
  3381.     elseif self.Bedrock:GetActiveObject() ~= self then\
  3382.         return 0\
  3383.     else\
  3384.         local textWidth = (self.Width - 2)\
  3385.         local offset = self.CursorPos - textWidth\
  3386.         if offset < 0 then\
  3387.             offset = 0\
  3388.         end\
  3389.         return offset\
  3390.     end\
  3391. end\
  3392. \
  3393. OnLoad = function(self)\
  3394.     if not self.CursorPos then\
  3395.         self.CursorPos = #self.Text\
  3396.     end\
  3397. end\
  3398. \
  3399. OnClick = function(self, event, side, x, y)\
  3400.     if self.Bedrock:GetActiveObject() ~= self and self.SelectOnClick then\
  3401.         self.CursorPos = #self.Text - 1\
  3402.         self.DragStart = 0\
  3403.         self.ActualDragStart = x - 2 + self:TextOffset()\
  3404.         self.Selected = true\
  3405.     else\
  3406.         self.CursorPos = x - 2 + self:TextOffset()\
  3407.         self.DragStart = self.CursorPos\
  3408.         self.Selected = false\
  3409.     end\
  3410.     self.Bedrock:SetActiveObject(self)\
  3411. end\
  3412. \
  3413. OnDrag = function(self, event, side, x, y)\
  3414.     self.CursorPos = x - 2 + self:TextOffset()\
  3415.     if self.ActualDragStart then\
  3416.         self.DragStart = self.ActualDragStart\
  3417.         self.ActualDragStart = nil\
  3418.     end\
  3419.     if self.DragStart then\
  3420.         self.Selected = true\
  3421.     end\
  3422. end\
  3423. \
  3424. OnKeyChar = function(self, event, keychar)\
  3425.     local deleteSelected = function()\
  3426.         if self.Selected then\
  3427.             local startPos = self.DragStart\
  3428.             local endPos = self.CursorPos\
  3429.             if startPos > endPos then\
  3430.                 startPos = self.CursorPos\
  3431.                 endPos = self.DragStart\
  3432.             end\
  3433.             self.Text = self.Text:sub(1, startPos) .. self.Text:sub(endPos + 2)\
  3434.             self.CursorPos = startPos\
  3435.             self.DragStart = nil\
  3436.             self.Selected = false\
  3437.             return true\
  3438.         end\
  3439.     end\
  3440. \
  3441.     if event == 'char' then\
  3442.         deleteSelected()\
  3443.         if self.Numerical then\
  3444.             keychar = tostring(tonumber(keychar))\
  3445.         end\
  3446.         if keychar == 'nil' then\
  3447.             return\
  3448.         end\
  3449.         self.Text = string.sub(self.Text, 1, self.CursorPos ) .. keychar .. string.sub( self.Text, self.CursorPos + 1 )\
  3450.         if self.Numerical then\
  3451.             self.Text = tostring(tonumber(self.Text))\
  3452.             if self.Text == 'nil' then\
  3453.                 self.Text = '1'\
  3454.             end\
  3455.         end\
  3456.         \
  3457.         self.CursorPos = self.CursorPos + 1\
  3458.         if self.OnChange then\
  3459.             self:OnChange(event, keychar)\
  3460.         end\
  3461.         return false\
  3462.     elseif event == 'key' then\
  3463.         if keychar == keys.enter then\
  3464.             if self.OnChange then\
  3465.                 self:OnChange(event, keychar)\
  3466.             end\
  3467.         elseif keychar == keys.left then\
  3468.             -- Left\
  3469.             if self.CursorPos > 0 then\
  3470.                 if self.Selected then\
  3471.                     self.CursorPos = self.DragStart\
  3472.                     self.DragStart = nil\
  3473.                     self.Selected = false\
  3474.                 else\
  3475.                     self.CursorPos = self.CursorPos - 1\
  3476.                 end\
  3477.                 if self.OnChange then\
  3478.                     self:OnChange(event, keychar)\
  3479.                 end\
  3480.             end\
  3481.             \
  3482.         elseif keychar == keys.right then\
  3483.             -- Right                \
  3484.             if self.CursorPos < string.len(self.Text) then\
  3485.                 if self.Selected then\
  3486.                     self.CursorPos = self.CursorPos\
  3487.                     self.DragStart = nil\
  3488.                     self.Selected = false\
  3489.                 else\
  3490.                     self.CursorPos = self.CursorPos + 1\
  3491.                 end\
  3492.                 if self.OnChange then\
  3493.                     self:OnChange(event, keychar)\
  3494.                 end\
  3495.             end\
  3496.         \
  3497.         elseif keychar == keys.backspace then\
  3498.             -- Backspace\
  3499.             if not deleteSelected() and self.CursorPos > 0 then\
  3500.                 self.Text = string.sub( self.Text, 1, self.CursorPos - 1 ) .. string.sub( self.Text, self.CursorPos + 1 )\
  3501.                 self.CursorPos = self.CursorPos - 1                 \
  3502.                 if self.Numerical then\
  3503.                     self.Text = tostring(tonumber(self.Text))\
  3504.                     if self.Text == 'nil' then\
  3505.                         self.Text = '1'\
  3506.                     end\
  3507.                 end\
  3508.                 if self.OnChange then\
  3509.                     self:OnChange(event, keychar)\
  3510.                 end\
  3511.             end\
  3512.         elseif keychar == keys.home then\
  3513.             -- Home\
  3514.             self.CursorPos = 0\
  3515.             if self.OnChange then\
  3516.                 self:OnChange(event, keychar)\
  3517.             end\
  3518.         elseif keychar == keys.delete then\
  3519.             if not deleteSelected() and self.CursorPos < string.len(self.Text) then\
  3520.                 self.Text = string.sub( self.Text, 1, self.CursorPos ) .. string.sub( self.Text, self.CursorPos + 2 )       \
  3521.                 if self.Numerical then\
  3522.                     self.Text = tostring(tonumber(self.Text))\
  3523.                     if self.Text == 'nil' then\
  3524.                         self.Text = '1'\
  3525.                     end\
  3526.                 end\
  3527.                 if self.OnChange then\
  3528.                     self:OnChange(keychar)\
  3529.                 end\
  3530.             end\
  3531.         elseif keychar == keys[\"end\"] then\
  3532.             -- End\
  3533.             self.CursorPos = string.len(self.Text)\
  3534.         else\
  3535.             if self.OnChange then\
  3536.                 self:OnChange(event, keychar)\
  3537.             end\
  3538.             return false\
  3539.         end\
  3540.     end\
  3541. end\
  3542. ]],\
  3543. [\"View\"] = [[\
  3544. BackgroundColour = colours.transparent\
  3545. Children = {}\
  3546. \
  3547. OnDraw = function(self, x, y)\
  3548.     if self.BackgroundColour then\
  3549.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  3550.     end\
  3551. end\
  3552. \
  3553. OnInitialise = function(self)\
  3554.     self.Children = {}\
  3555. end\
  3556. \
  3557. InitialiseFile = function(self, bedrock, file, name)\
  3558.     local _new = {}\
  3559.     _new.X = 1\
  3560.     _new.Y = 1\
  3561.     _new.Width = Drawing.Screen.Width\
  3562.     _new.Height = Drawing.Screen.Height\
  3563.     _new.BackgroundColour = file.BackgroundColour\
  3564.     _new.Name = name\
  3565.     _new.Children = {}\
  3566.     _new.Bedrock = bedrock\
  3567.     local new = self:Initialise(_new)\
  3568.     for i, obj in ipairs(file.Children) do\
  3569.         local view = bedrock:ObjectFromFile(obj, new)\
  3570.         if not view.Z then\
  3571.             view.Z = i\
  3572.         end\
  3573.         view.Parent = new\
  3574.         table.insert(new.Children, view)\
  3575.     end\
  3576.     return new\
  3577. end\
  3578. \
  3579. function CheckClick(self, object, x, y)\
  3580.     local offset = {X = 0, Y = 0}\
  3581.     if not object.Fixed and self.ChildOffset then\
  3582.         offset = self.ChildOffset\
  3583.     end\
  3584.     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\
  3585.         return true\
  3586.     end\
  3587. end\
  3588. \
  3589. function DoClick(self, object, event, side, x, y)\
  3590.     if object then\
  3591.         if self:CheckClick(object, x, y) then\
  3592.             local offset = {X = 0, Y = 0}\
  3593.             if not object.Fixed and self.ChildOffset then\
  3594.                 offset = self.ChildOffset\
  3595.             end\
  3596.             return object:Click(event, side, x - object.X - offset.X + 1, y - object.Y + 1 - offset.Y)\
  3597.         end\
  3598.     end \
  3599. end\
  3600. \
  3601. Click = function(self, event, side, x, y, z)\
  3602.     if self.Visible and not self.IgnoreClick then\
  3603.         for i = #self.Children, 1, -1 do --children are ordered from smallest Z to highest, so this is done in reverse\
  3604.             local child = self.Children[i]\
  3605.             if self:DoClick(child, event, side, x, y) then\
  3606.                 if self.OnChildClick then\
  3607.                     self:OnChildClick(child, event, side, x, y)\
  3608.                 end\
  3609.                 return true\
  3610.             end\
  3611.         end\
  3612.         if event == 'mouse_click' and self.OnClick and self:OnClick(event, side, x, y) ~= false then\
  3613.             return true\
  3614.         elseif event == 'mouse_drag' and self.OnDrag and self:OnDrag(event, side, x, y) ~= false then\
  3615.             return true\
  3616.         elseif event == 'mouse_scroll' and self.OnScroll and self:OnScroll(event, side, x, y) ~= false then\
  3617.             return true\
  3618.         else\
  3619.             return false\
  3620.         end\
  3621.     else\
  3622.         return false\
  3623.     end\
  3624. end\
  3625. \
  3626. OnRemove = function(self)\
  3627.     if self == self.Bedrock:GetActiveObject() then\
  3628.         self.Bedrock:SetActiveObject()\
  3629.     end\
  3630.     for i, child in ipairs(self.Children) do\
  3631.         child:OnRemove()\
  3632.     end\
  3633. end\
  3634. \
  3635. local function findObjectNamed(view, name, minI)\
  3636.     local minI = minI or 0\
  3637.     if view and view.Children then\
  3638.         for i, child in ipairs(view.Children) do\
  3639.             if child.Name == name or child == name then\
  3640.                 return child, i, view\
  3641.             elseif child.Children then\
  3642.                 local found, index, foundView = findObjectNamed(child, name)\
  3643.                 if found and minI <= index then\
  3644.                     return found, index, foundView\
  3645.                 end\
  3646.             end\
  3647.         end\
  3648.     end\
  3649. end\
  3650. \
  3651. function AddObject(self, info, extra)\
  3652.     if type(info) == 'string' then\
  3653.         local h = fs.open(self.Bedrock.ViewPath..info..'.view', 'r')\
  3654.         if h then\
  3655.             info = textutils.unserialize(h.readAll())\
  3656.             h.close()\
  3657.         else\
  3658.             error('Error in opening object: '..info)\
  3659.         end\
  3660.     end\
  3661. \
  3662.     if extra then\
  3663.         for k, v in pairs(extra) do\
  3664.             if v then\
  3665.                 info[k] = v\
  3666.             end\
  3667.         end\
  3668.     end\
  3669. \
  3670.     local view = self.Bedrock:ObjectFromFile(info, self)\
  3671.     if not view.Z then\
  3672.         view.Z = #self.Children + 1\
  3673.     end\
  3674.     \
  3675.     table.insert(self.Children, view)\
  3676.     if self.Bedrock.View then\
  3677.         self.Bedrock:ReorderObjects()\
  3678.     end\
  3679.     self:ForceDraw()\
  3680.     return view\
  3681. end\
  3682. \
  3683. function GetObject(self, name)\
  3684.     return findObjectNamed(self, name)\
  3685. end\
  3686. \
  3687. local function findObjects(view, name)\
  3688.     local objects = {}\
  3689.     if view and view.Children then\
  3690.         for i, child in ipairs(view.Children) do\
  3691.             if child.Name == name or child == name then\
  3692.                 table.insert(objects, child)\
  3693.             elseif child.Children then\
  3694.                 local objs = findObjects(child, name)\
  3695.                 if objs then\
  3696.                     for i2, v in ipairs(objs) do\
  3697.                         table.insert(objects, v)\
  3698.                     end\
  3699.                 end\
  3700.             end\
  3701.         end\
  3702.     end\
  3703.     return objects\
  3704. end\
  3705. \
  3706. function GetObjects(self, name)\
  3707.     return findObjects(self, name)\
  3708. end\
  3709. \
  3710. function RemoveObject(self, name)\
  3711.     local obj, index, view = findObjectNamed(self, name, minI)\
  3712.     if index then\
  3713.         view.Children[index]:OnRemove()\
  3714.         table.remove(view.Children, index)\
  3715.         if view.OnUpdate then\
  3716.             view:OnUpdate('Children')\
  3717.         end\
  3718.         return true\
  3719.     end\
  3720.     return false\
  3721. end\
  3722. \
  3723. function RemoveObjects(self, name)\
  3724.     local i = 1\
  3725.     while self:RemoveObject(name) and i < 100 do\
  3726.         i = i + 1\
  3727.     end\
  3728.     \
  3729. end\
  3730. \
  3731. function RemoveAllObjects(self)\
  3732.     for i, child in ipairs(self.Children) do\
  3733.         child:OnRemove()\
  3734.         self.Children[i] = nil\
  3735.     end\
  3736.     self:ForceDraw()\
  3737. end\
  3738. ]],\
  3739. [\"Window\"] = [[\
  3740. Inherit = 'View'\
  3741. \
  3742. ToolBarColour = colours.lightGrey\
  3743. ToolBarTextColour = colours.black\
  3744. ShadowColour = colours.grey\
  3745. Title = ''\
  3746. Flashing = false\
  3747. CanClose = true\
  3748. OnCloseButton = nil\
  3749. \
  3750. OnLoad = function(self)\
  3751.     --self:GetObject('View') = self.Bedrock:ObjectFromFile({Type = 'View',Width = 10, Height = 5, BackgroundColour = colours.red}, self)\
  3752. end\
  3753. \
  3754. LoadView = function(self)\
  3755.     local view = self:GetObject('View')\
  3756.     if view.ToolBarColour then\
  3757.         window.ToolBarColour = view.ToolBarColour\
  3758.     end\
  3759.     if view.ToolBarTextColour then\
  3760.         window.ToolBarTextColour = view.ToolBarTextColour\
  3761.     end\
  3762.     view.X = 1\
  3763.     view.Y = 2\
  3764. \
  3765.     view:ForceDraw()\
  3766.     self:OnUpdate('View')\
  3767.     if self.OnViewLoad then\
  3768.         self.OnViewLoad(view)\
  3769.     end\
  3770.     self.Bedrock:SetActiveObject(view)\
  3771. end\
  3772. \
  3773. SetView = function(self, view)\
  3774.     self:RemoveObject('View')\
  3775.     table.insert(self.Children, view)\
  3776.     view.Parent = self\
  3777.     self:LoadView()\
  3778. end\
  3779. \
  3780. Flash = function(self)\
  3781.     self.Flashing = true\
  3782.     self:ForceDraw()\
  3783.     self.Bedrock:StartTimer(function()self.Flashing = false end, 0.4)\
  3784. end\
  3785. \
  3786. OnDraw = function(self, x, y)\
  3787.     local toolBarColour = (self.Flashing and colours.white or self.ToolBarColour)\
  3788.     local toolBarTextColour = (self.Flashing and colours.black or self.ToolBarTextColour)\
  3789.     if toolBarColour then\
  3790.         Drawing.DrawBlankArea(x, y, self.Width, 1, toolBarColour)\
  3791.     end\
  3792.     if toolBarTextColour then\
  3793.         local title = self.Bedrock.Helpers.TruncateString(self.Title, self.Width - 2)\
  3794.         Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, title, toolBarTextColour, toolBarColour)\
  3795.     end\
  3796.     Drawing.IgnoreConstraint = true\
  3797.     Drawing.DrawBlankArea(x + 1, y + 1, self.Width, self.Height, self.ShadowColour)\
  3798.     Drawing.IgnoreConstraint = false\
  3799. end\
  3800. \
  3801. Close = function(self)\
  3802.     self.Bedrock.Window = nil\
  3803.     self.Bedrock:RemoveObject(self)\
  3804.     if self.OnClose then\
  3805.         self:OnClose()\
  3806.     end\
  3807.     self = nil\
  3808. end\
  3809. \
  3810. OnUpdate = function(self, value)\
  3811.     if value == 'View' and self:GetObject('View') then\
  3812.         self.Width = self:GetObject('View').Width\
  3813.         self.Height = self:GetObject('View').Height + 1\
  3814.         self.X = math.ceil((Drawing.Screen.Width - self.Width) / 2)\
  3815.         self.Y = math.ceil((Drawing.Screen.Height - self.Height) / 2)\
  3816.     elseif value == 'CanClose' then\
  3817.         self:RemoveObject('CloseButton')\
  3818.         if self.CanClose then\
  3819.             local button = self:AddObject({X = 1, Y = 1, Width = 1, Height = 1, Type = 'Button', BackgroundColour = colours.red, TextColour = colours.white, Text = 'x', Name = 'CloseButton'})\
  3820.             button.OnClick = function(btn)\
  3821.                 if self.OnCloseButton then\
  3822.                     self:OnCloseButton()\
  3823.                 end\
  3824.                 self:Close()\
  3825.             end\
  3826.         end\
  3827.     end\
  3828. end\
  3829. ]],\
  3830. }\
  3831. \
  3832. BasePath = ''\
  3833. ProgramPath = nil\
  3834. \
  3835. -- Program functions...\
  3836. \
  3837. local function main(...)\
  3838.     -- Code here...\
  3839. end\
  3840. \
  3841. -- Run\
  3842. local args = {...}\
  3843. local _, err = pcall(function() main(unpack(args)) end)\
  3844. if err then\
  3845.     -- Make a nice error handling screen here...\
  3846.     term.setBackgroundColor(colors.black)\
  3847.     term.setTextColor(colors.white)\
  3848.     term.clear()\
  3849.     term.setCursorPos(1, 3)\
  3850.     print(\" An Error Has Occured! D:\\n\\n\")\
  3851.     print(\" \" .. tostring(err) .. \"\\n\\n\")\
  3852.     print(\" Press any key to exit...\")\
  3853.     os.pullEvent(\"key\")\
  3854. end\
  3855. \
  3856. \
  3857. \
  3858. function LoadAPIs(self)\
  3859.     local function loadAPI(name, content)\
  3860.         local env = setmetatable({}, { __index = getfenv() })\
  3861.         local func, err = loadstring(content, name..' (Bedrock API)')\
  3862.         if not func then\
  3863.             return false, printError(err)\
  3864.         end\
  3865.         setfenv(func, env)\
  3866.         func()\
  3867.         local api = {}\
  3868.         for k,v in pairs(env) do\
  3869.             api[k] = v\
  3870.         end\
  3871.         _G[name] = api\
  3872.         return true\
  3873.     end\
  3874. \
  3875.     local env = getfenv()\
  3876.     local function loadObject(name, content)\
  3877.         loadAPI(name, content)\
  3878.         if env[name].Inherit then\
  3879.             if not getfenv()[env[name].Inherit] then    \
  3880.                 if objects[env[name].Inherit] then\
  3881.                     loadObject(env[name].Inherit, objects[env[name].Inherit])\
  3882.                 elseif fs.exists(self.ProgramPath..'/Objects/'..env[name].Inherit..'.lua') then\
  3883.                 end\
  3884.             end\
  3885.             env[name].__index = getfenv()[env[name].Inherit]\
  3886.         else\
  3887.             env[name].__index = Object\
  3888.         end\
  3889.         setmetatable(env[name], env[name])\
  3890.     end\
  3891. \
  3892.     for k, v in pairs(apis) do\
  3893.         loadAPI(k, v)\
  3894.         if k == 'Helpers' then\
  3895.             self.Helpers = Helpers\
  3896.         end\
  3897.     end\
  3898. \
  3899.     for k, v in pairs(objects) do\
  3900.         loadObject(k, v)\
  3901.     end\
  3902.     \
  3903.     local privateObjPath = self.ProgramPath..'/Objects/'\
  3904.     if fs.exists(privateObjPath) and fs.isDir(privateObjPath) then\
  3905.         for i, v in ipairs(fs.list(privateObjPath)) do\
  3906.             if v ~= '.DS_Store' then\
  3907.                 local name = string.match(v, '(%a+)%.?.-')\
  3908.                 local h = fs.open(privateObjPath..v, 'r')\
  3909.                 loadObject(name, h.readAll())\
  3910.                 h.close()\
  3911.             end\
  3912.         end\
  3913.     end\
  3914. end\
  3915. \
  3916. AllowTerminate = true\
  3917. \
  3918. View = nil\
  3919. Menu = nil\
  3920. \
  3921. ActiveObject = nil\
  3922. \
  3923. DrawTimer = nil\
  3924. DrawTimerExpiry = 0\
  3925. \
  3926. IsDrawing = false\
  3927. \
  3928. Running = true\
  3929. \
  3930. DefaultView = 'main'\
  3931. \
  3932. EventHandlers = {\
  3933.     \
  3934. }\
  3935. \
  3936. ObjectClickHandlers = {\
  3937.     \
  3938. }\
  3939. \
  3940. ObjectUpdateHandlers = {\
  3941.     \
  3942. }\
  3943. \
  3944. Timers = {\
  3945.     \
  3946. }\
  3947. \
  3948. function Initialise(self, programPath)\
  3949.     self.ProgramPath = programPath or self.ProgramPath\
  3950.     if not programPath then\
  3951.         if self.ProgramPath then\
  3952.             local prgPath = self.ProgramPath\
  3953.             local prgName = fs.getName(prgPath)\
  3954.             if prgPath:find('/') then \
  3955.                 self.ProgramPath = prgPath:sub(1, #prgPath-#prgName-1)\
  3956.                 self.ProgramPath = prgPath:sub(1, #prgPath-#prgName-1) \
  3957.             else \
  3958.                 self.ProgramPath = '' \
  3959.             end\
  3960.         else\
  3961.             self.ProgramPath = ''\
  3962.         end\
  3963.     end\
  3964.     self:LoadAPIs()\
  3965.     self.ViewPath = self.ProgramPath .. '/Views/'\
  3966.     --first, check that the barebones APIs are available\
  3967.     local requiredApis = {\
  3968.         'Drawing',\
  3969.         'View'\
  3970.     }\
  3971.     local env = getfenv()\
  3972.     for i,v in ipairs(requiredApis) do\
  3973.         if not env[v] then\
  3974.             error('The API: '..v..' is not loaded. Please make sure you load it to use Bedrock.')\
  3975.         end\
  3976.     end\
  3977. \
  3978.     local copy = { }\
  3979.     for k, v in pairs(self) do\
  3980.         if k ~= 'Initialise' then\
  3981.             copy[k] = v\
  3982.         end\
  3983.     end\
  3984.     return setmetatable(copy, getmetatable(self))\
  3985. end\
  3986. \
  3987. function HandleClick(self, event, side, x, y)\
  3988.     if self.Window then\
  3989.         if not self.View:CheckClick(self.Window, x, y) then\
  3990.             self.Window:Flash()\
  3991.         else\
  3992.             self.View:DoClick(self.Window, event, side, x, y)\
  3993.         end\
  3994.     elseif self.Menu then\
  3995.         if not self.View:DoClick(self.Menu, event, side, x, y) then\
  3996.             self.Menu:Close()\
  3997.         end\
  3998.     elseif self.View then\
  3999.         if self.View:Click(event, side, x, y) ~= false then\
  4000.         end     \
  4001.     end\
  4002. end\
  4003. \
  4004. function HandleKeyChar(self, event, keychar)\
  4005.     if self:GetActiveObject() then\
  4006.         local activeObject = self:GetActiveObject()\
  4007.         if activeObject.OnKeyChar then\
  4008.             if activeObject:OnKeyChar(event, keychar) ~= false then\
  4009.                 --self:Draw()\
  4010.             end\
  4011.         end\
  4012.     end\
  4013. end\
  4014. \
  4015. function ToggleMenu(self, name, owner, x, y)\
  4016.     if self.Menu then\
  4017.         self.Menu:Close()\
  4018.         return false\
  4019.     else\
  4020.         self:SetMenu(name, owner, x, y)\
  4021.         return true\
  4022.     end\
  4023. end\
  4024. \
  4025. function SetMenu(self, menu, owner, x, y)\
  4026.     x = x or 1\
  4027.     y = y or 1\
  4028.     if self.Menu then\
  4029.         self.Menu:Close()\
  4030.     end \
  4031.     if menu then\
  4032.         local pos = owner:GetPosition()\
  4033.         self.Menu = self:AddObject(menu, {Type = 'Menu', Owner = owner, X = pos.X + x - 1, Y = pos.Y + y})\
  4034.     end\
  4035. end\
  4036. \
  4037. function ObjectClick(self, name, func)\
  4038.     self.ObjectClickHandlers[name] = func\
  4039. end\
  4040. \
  4041. function ClickObject(self, object, event, side, x, y)\
  4042.     if self.ObjectClickHandlers[object.Name] then\
  4043.         return self.ObjectClickHandlers[object.Name](object, event, side, x, y)\
  4044.     end\
  4045.     return false\
  4046. end\
  4047. \
  4048. function ObjectUpdate(self, name, func)\
  4049.     self.ObjectUpdateHandlers[name] = func\
  4050. end\
  4051. \
  4052. function UpdateObject(self, object, ...)\
  4053.     if self.ObjectUpdateHandlers[object.Name] then\
  4054.         self.ObjectUpdateHandlers[object.Name](object, ...)\
  4055.         --self:Draw()\
  4056.     end\
  4057. end\
  4058. \
  4059. function GetAbsolutePosition(self, obj)\
  4060.     if not obj.Parent then\
  4061.         return {X = obj.X, Y = obj.Y}\
  4062.     else\
  4063.         local pos = self:GetAbsolutePosition(obj.Parent)\
  4064.         local x = pos.X + obj.X - 1\
  4065.         local y = pos.Y + obj.Y - 1\
  4066.         if not obj.Fixed and obj.Parent.ChildOffset then\
  4067.             x = x + obj.Parent.ChildOffset.X\
  4068.             y = y + obj.Parent.ChildOffset.Y\
  4069.         end\
  4070.         return {X = x, Y = y}\
  4071.     end\
  4072. end\
  4073. \
  4074. function LoadView(self, name, draw)\
  4075.     if self.View and self.OnViewClose then\
  4076.         self.OnViewClose(self.View.Name)\
  4077.     end\
  4078.     if self.View then\
  4079.         self.View:OnRemove()\
  4080.     end\
  4081.     local success = false\
  4082. \
  4083.     if not fs.exists(self.ViewPath..name..'.view') then\
  4084.         error('The view: '..name..'.view does not exist.')\
  4085.     end\
  4086. \
  4087.     local h = fs.open(self.ViewPath..name..'.view', 'r')\
  4088.     if h then\
  4089.         local view = textutils.unserialize(h.readAll())\
  4090.         h.close()\
  4091.         if view then\
  4092.             self.View = View:InitialiseFile(self, view, name)\
  4093.             self:ReorderObjects()\
  4094. \
  4095.             if OneOS and view.ToolBarColour then\
  4096.                 OneOS.ToolBarColour = view.ToolBarColour\
  4097.             end\
  4098.             if OneOS and view.ToolBarTextColour then\
  4099.                 OneOS.ToolBarTextColour = view.ToolBarTextColour\
  4100.             end\
  4101.             if not self:GetActiveObject() then\
  4102.                 self:SetActiveObject()\
  4103.             end\
  4104.             success = true\
  4105.         end\
  4106.     end\
  4107. \
  4108.     if success and self.OnViewLoad then\
  4109.         self.OnViewLoad(name)\
  4110.     end\
  4111. \
  4112.     if draw ~= false then\
  4113.         self:Draw()\
  4114.     end\
  4115. \
  4116.     if not success then\
  4117.         error('Failed to load view: '..name..'. It probably isn\\'t formatted correctly. Did you forget a } or ,?')\
  4118.     end\
  4119. \
  4120.     return success\
  4121. end\
  4122. \
  4123. function InheritFile(self, file, name)\
  4124.     local h = fs.open(self.ViewPath..name..'.view', 'r')\
  4125.     if h then\
  4126.         local super = textutils.unserialize(h.readAll())\
  4127.         if super then\
  4128.             if type(super) ~= 'table' then\
  4129.                 error('View: \"'..name..'.view\" is not formatted correctly.')\
  4130.             end\
  4131. \
  4132.             for k, v in pairs(super) do\
  4133.                 if not file[k] then\
  4134.                     file[k] = v\
  4135.                 end\
  4136.             end\
  4137.             return file\
  4138.         end\
  4139.     end\
  4140.     return file\
  4141. end\
  4142. \
  4143. function ParseStringSize(self, parent, k, v)\
  4144.         local parentSize = parent.Width\
  4145.         if k == 'Height' or k == 'Y' then\
  4146.             parentSize = parent.Height\
  4147.         end\
  4148.         local parts = {v}\
  4149.         if type(v) == 'string' and string.find(v, ',') then\
  4150.             parts = {}\
  4151.             for word in string.gmatch(v, '([^,]+)') do\
  4152.                 table.insert(parts, word)\
  4153.             end\
  4154.         end\
  4155. \
  4156.         v = 0\
  4157.         for i2, part in ipairs(parts) do\
  4158.             if type(part) == 'string' and part:sub(#part) == '%' then\
  4159.                 v = v + math.ceil(parentSize * (tonumber(part:sub(1, #part-1)) / 100))\
  4160.             else\
  4161.                 v = v + tonumber(part)\
  4162.             end\
  4163.         end\
  4164.         return v\
  4165. end\
  4166. \
  4167. function ObjectFromFile(self, file, view)\
  4168.     local env = getfenv()\
  4169.     if env[file.Type] then\
  4170.         if not env[file.Type].Initialise then\
  4171.             error('Malformed Object: '..file.Type)\
  4172.         end\
  4173.         local object = {}\
  4174. \
  4175.         if file.InheritView then\
  4176.             file = self:InheritFile(file, file.InheritView)\
  4177.         end\
  4178.         \
  4179.         object.AutoWidth = true\
  4180.         for k, v in pairs(file) do\
  4181.             if k == 'Width' or k == 'X' or k == 'Height' or k == 'Y' then\
  4182.                 v = self:ParseStringSize(view, k, v)\
  4183.             end\
  4184. \
  4185.             if k == 'Width' then\
  4186.                 object.AutoWidth = false\
  4187.             end\
  4188.             if k ~= 'Children' then\
  4189.                 object[k] = v\
  4190.             else\
  4191.                 object[k] = {}\
  4192.             end\
  4193.         end\
  4194. \
  4195.         object.Parent = view\
  4196.         object.Bedrock = self\
  4197.         if not object.Name then\
  4198.             object.Name = file.Type\
  4199.         end\
  4200. \
  4201.         object = env[file.Type]:Initialise(object)\
  4202. \
  4203.         if file.Children then\
  4204.             for i, obj in ipairs(file.Children) do\
  4205.                 local _view = self:ObjectFromFile(obj, object)\
  4206.                 if not _view.Z then\
  4207.                     _view.Z = i\
  4208.                 end\
  4209.                 _view.Parent = object\
  4210.                 table.insert(object.Children, _view)\
  4211.             end\
  4212.         end\
  4213. \
  4214.         if not object.OnClick then\
  4215.             object.OnClick = function(...) return self:ClickObject(...) end\
  4216.         end\
  4217.         --object.OnUpdate = function(...) self:UpdateObject(...) end\
  4218. \
  4219.         if object.OnUpdate then\
  4220.             for k, v in pairs(env[file.Type]) do\
  4221.                 object:OnUpdate(k)\
  4222.             end\
  4223. \
  4224.             for k, v in pairs(object.__index) do\
  4225.                 object:OnUpdate(k)\
  4226.             end\
  4227.         end\
  4228. \
  4229.         if object.Active then\
  4230.             object.Bedrock:SetActiveObject(object)\
  4231.         end\
  4232.         if object.OnLoad then\
  4233.             object:OnLoad()\
  4234.         end\
  4235.         return object\
  4236.     elseif not file.Type then\
  4237.         error('No object type specified. (e.g. Type = \"Button\")')\
  4238.     else\
  4239.         error('No Object: '..file.Type..'. The API probably isn\\'t loaded')\
  4240.     end\
  4241. end\
  4242. \
  4243. function ReorderObjects(self)\
  4244.     if self.View and self.View.Children then\
  4245.         table.sort(self.View.Children, function(a,b)\
  4246.             return a.Z < b.Z \
  4247.         end)\
  4248.     end\
  4249. end\
  4250. \
  4251. function AddObject(self, info, extra)\
  4252.     return self.View:AddObject(info, extra)\
  4253. end\
  4254. \
  4255. function GetObject(self, name)\
  4256.     return self.View:GetObject(name)\
  4257. end\
  4258. \
  4259. function GetObjects(self, name)\
  4260.     return self.View:GetObjects(name)\
  4261. end\
  4262. \
  4263. function RemoveObject(self, name)\
  4264.     return self.View:RemoveObject(name)\
  4265. end\
  4266. \
  4267. function RemoveObjects(self, name)\
  4268.     return self.View:RemoveObjects(name)\
  4269. end\
  4270. \
  4271. function ForceDraw(self)\
  4272.     if not self.DrawTimer or self.DrawTimerExpiry <= os.clock() then\
  4273.         self.DrawTimer = self:StartTimer(function()\
  4274.             self.DrawTimer = nil\
  4275.             self:Draw()\
  4276.         end, 0.05)\
  4277.         self.DrawTimerExpiry = os.clock() + 0.1\
  4278.     end\
  4279. end\
  4280. \
  4281. function DisplayWindow(self, _view, title, canClose)\
  4282.     if canClose == nil then\
  4283.         canClose = true\
  4284.     end\
  4285.     if type(_view) == 'string' then\
  4286.         local h = fs.open(self.ViewPath.._view..'.view', 'r')\
  4287.         if h then\
  4288.             _view = textutils.unserialize(h.readAll())\
  4289.             h.close()\
  4290.         end\
  4291.     end\
  4292. \
  4293.     self.Window = self:AddObject({Type = 'Window', Z = 999, Title = title, CanClose = canClose})\
  4294.     _view.Type = 'View'\
  4295.     _view.Name = 'View'\
  4296.     _view.BackgroundColour = _view.BackgroundColour or colours.white\
  4297.     self.Window:SetView(self:ObjectFromFile(_view, self.Window))\
  4298. end\
  4299. \
  4300. function DisplayAlertWindow(self, title, text, buttons, callback)\
  4301.     local func = function(btn)\
  4302.         self.Window:Close()\
  4303.         if callback then\
  4304.             callback(btn.Text)\
  4305.         end\
  4306.     end\
  4307.     local children = {}\
  4308.     local usedX = -1\
  4309.     if buttons then\
  4310.         for i, text in ipairs(buttons) do\
  4311.             usedX = usedX + 3 + #text\
  4312.             table.insert(children, {\
  4313.                 [\"Y\"]=\"100%,-1\",\
  4314.                 [\"X\"]=\"100%,-\"..usedX,\
  4315.                 [\"Name\"]=text..\"Button\",\
  4316.                 [\"Type\"]=\"Button\",\
  4317.                 [\"Text\"]=text,\
  4318.                 OnClick = func\
  4319.             })\
  4320.         end\
  4321.     end\
  4322. \
  4323.     local width = usedX + 2\
  4324.     if width < 28 then\
  4325.         width = 28\
  4326.     end\
  4327. \
  4328.     local canClose = true\
  4329.     if buttons and #buttons~=0 then\
  4330.         canClose = false\
  4331.     end\
  4332. \
  4333.     local height = 0\
  4334.     if text then\
  4335.         height = #Helpers.WrapText(text, width - 2)\
  4336.         table.insert(children, {\
  4337.             [\"Y\"]=2,\
  4338.             [\"X\"]=2,\
  4339.             [\"Width\"]=\"100%,-2\",\
  4340.             [\"Height\"]=height,\
  4341.             [\"Name\"]=\"Label\",\
  4342.             [\"Type\"]=\"Label\",\
  4343.             [\"Text\"]=text\
  4344.         })\
  4345.     end\
  4346.     local view = {\
  4347.         Children = children,\
  4348.         Width=width,\
  4349.         Height=3+height+(canClose and 0 or 1),\
  4350.         OnKeyChar = function(_view, keychar)\
  4351.             func({Text=buttons[1]})\
  4352.         end\
  4353.     }\
  4354.     self:DisplayWindow(view, title, canClose)\
  4355. end\
  4356. \
  4357. function DisplayTextBoxWindow(self, title, text, callback, textboxText, cursorAtEnd)\
  4358.     textboxText = textboxText or ''\
  4359.     local func = function(btn)\
  4360.         self.Window:Close()\
  4361.         if callback then\
  4362.             callback(btn.Text)\
  4363.         end\
  4364.     end\
  4365.     local children = {\
  4366.         {\
  4367.             [\"Y\"]=\"100%,-1\",\
  4368.             [\"X\"]=\"100%,-4\",\
  4369.             [\"Name\"]=\"OkButton\",\
  4370.             [\"Type\"]=\"Button\",\
  4371.             [\"Text\"]=\"Ok\",\
  4372.             OnClick = function()\
  4373.                 local text = self.Window:GetObject('TextBox').Text\
  4374.                 self.Window:Close()\
  4375.                 callback(true, text)\
  4376.             end\
  4377.         },\
  4378.         {\
  4379.             [\"Y\"]=\"100%,-1\",\
  4380.             [\"X\"]=\"100%,-13\",\
  4381.             [\"Name\"]=\"CancelButton\",\
  4382.             [\"Type\"]=\"Button\",\
  4383.             [\"Text\"]=\"Cancel\",\
  4384.             OnClick = function()\
  4385.                 self.Window:Close()\
  4386.                 callback(false)\
  4387.             end\
  4388.         }\
  4389.     }\
  4390. \
  4391.     local height = -1\
  4392.     if text and #text ~= 0 then\
  4393.         height = #Helpers.WrapText(text, 26)\
  4394.         table.insert(children, {\
  4395.             [\"Y\"]=2,\
  4396.             [\"X\"]=2,\
  4397.             [\"Width\"]=\"100%,-2\",\
  4398.             [\"Height\"]=height,\
  4399.             [\"Name\"]=\"Label\",\
  4400.             [\"Type\"]=\"Label\",\
  4401.             [\"Text\"]=text\
  4402.         })\
  4403.     end\
  4404.     table.insert(children,\
  4405.         {\
  4406.             [\"Y\"]=3+height,\
  4407.             [\"X\"]=2,\
  4408.             [\"Width\"]=\"100%,-2\",\
  4409.             [\"Name\"]=\"TextBox\",\
  4410.             [\"Type\"]=\"TextBox\",\
  4411.             [\"Text\"]=textboxText,\
  4412.             [\"CursorPos\"]=(cursorAtEnd and 0 or nil)\
  4413.         })\
  4414.     local view = {\
  4415.         Children = children,\
  4416.         Width=28,\
  4417.         Height=5+height+(canClose and 0 or 1),\
  4418.     }\
  4419.     self:DisplayWindow(view, title)\
  4420.     self.Window:GetObject('TextBox').OnUpdate = function(txtbox, keychar)\
  4421.         if keychar == keys.enter then\
  4422.             self.Window:Close()\
  4423.             callback(true, txtbox.Text)\
  4424.         end\
  4425.     end\
  4426.     self:SetActiveObject(self.Window:GetObject('TextBox'))\
  4427.     self.Window.OnCloseButton = function()callback(false)end\
  4428. end\
  4429. \
  4430. function DisplayOpenFileWindow(self, title, callback)\
  4431.     title = title or 'Open File'\
  4432.     local func = function(btn)\
  4433.         self.Window:Close()\
  4434.         if callback then\
  4435.             callback(btn.Text)\
  4436.         end\
  4437.     end\
  4438. \
  4439.     local sidebarItems = {}\
  4440. \
  4441.     --this is a really, really super bad way of doing it\
  4442.     local separator = '                               !'\
  4443. \
  4444.     local function addFolder(path, level)\
  4445.         for i, v in ipairs(fs.list(path)) do\
  4446.             local fPath = path .. '/' .. v\
  4447.             if fPath ~= '/rom' and fs.isDir(fPath) then\
  4448.                 table.insert(sidebarItems, level .. v..separator..fPath)\
  4449.                 addFolder(fPath, level .. '  ')\
  4450.             end\
  4451.         end\
  4452.     end\
  4453.     addFolder('','')\
  4454. \
  4455.     local currentFolder = ''\
  4456.     local selectedPath = nil\
  4457. \
  4458.     local goToFolder = nil\
  4459. \
  4460.     local children = {\
  4461.         {\
  4462.             [\"Y\"]=\"100%,-2\",\
  4463.             [\"X\"]=1,\
  4464.             [\"Height\"]=3,\
  4465.             [\"Width\"]=\"100%\",\
  4466.             [\"BackgroundColour\"]=colours.lightGrey,\
  4467.             [\"Name\"]=\"SidebarListView\",\
  4468.             [\"Type\"]=\"View\"\
  4469.         },\
  4470.         {\
  4471.             [\"Y\"]=\"100%,-1\",\
  4472.             [\"X\"]=\"100%,-4\",\
  4473.             [\"Name\"]=\"OkButton\",\
  4474.             [\"Type\"]=\"Button\",\
  4475.             [\"Text\"]=\"Ok\",\
  4476.             [\"BackgroundColour\"]=colours.white,\
  4477.             [\"Enabled\"]=false,\
  4478.             OnClick = function()\
  4479.                 if selectedPath then\
  4480.                     self.Window:Close()\
  4481.                     callback(true, Helpers.TidyPath(selectedPath))\
  4482.                 end\
  4483.             end\
  4484.         },\
  4485.         {\
  4486.             [\"Y\"]=\"100%,-1\",\
  4487.             [\"X\"]=\"100%,-13\",\
  4488.             [\"Name\"]=\"CancelButton\",\
  4489.             [\"Type\"]=\"Button\",\
  4490.             [\"Text\"]=\"Cancel\",\
  4491.             [\"BackgroundColour\"]=colours.white,\
  4492.             OnClick = function()\
  4493.                 self.Window:Close()\
  4494.                 callback(false)\
  4495.             end\
  4496.         },\
  4497.         {\
  4498.             [\"Y\"]=1,\
  4499.             [\"X\"]=1,\
  4500.             [\"Height\"]=\"100%,-3\",\
  4501.             [\"Width\"]=\"40%,-1\",\
  4502.             [\"Name\"]=\"SidebarListView\",\
  4503.             [\"Type\"]=\"ListView\",\
  4504.             [\"CanSelect\"]=true,\
  4505.             [\"Items\"]={\
  4506.                 [\"Computer\"] = sidebarItems\
  4507.             },\
  4508.             OnSelect = function(listView, text)\
  4509.                 local _,s = text:find(separator)\
  4510.                 if s then\
  4511.                     local path = text:sub(s + 1)\
  4512.                     goToFolder(path)\
  4513.                 end\
  4514.             end,\
  4515.             OnClick = function(listView, event, side, x, y)\
  4516.                 if y == 1 then\
  4517.                     goToFolder('/')\
  4518.                 end\
  4519.             end\
  4520.         },\
  4521.         {\
  4522.             [\"Y\"]=1,\
  4523.             [\"X\"]=\"40%\",\
  4524.             [\"Height\"]=\"100%,-3\",\
  4525.             [\"Width\"]=1,\
  4526.             [\"Type\"]=\"Separator\"\
  4527.         },\
  4528.         {\
  4529.             [\"Y\"]=1,\
  4530.             [\"X\"]=\"40%,2\",\
  4531.             [\"Width\"]=\"65%,-3\",\
  4532.             [\"Height\"]=1,\
  4533.             [\"Type\"]=\"Label\",\
  4534.             [\"Name\"]=\"PathLabel\",\
  4535.             [\"TextColour\"]=colours.lightGrey,\
  4536.             [\"Text\"]='/hello/there'\
  4537.         },\
  4538.         {\
  4539.             [\"Y\"]=2,\
  4540.             [\"X\"]=\"40%,1\",\
  4541.             [\"Height\"]=\"100%,-4\",\
  4542.             [\"Width\"]=\"65%,-1\",\
  4543.             [\"Name\"]=\"FilesListView\",\
  4544.             [\"Type\"]=\"ListView\",\
  4545.             [\"CanSelect\"]=true,\
  4546.             [\"Items\"]={},\
  4547.             OnSelect = function(listView, text)\
  4548.                 selectedPath = Helpers.TidyPath(currentFolder .. '/' .. text)\
  4549.                 self.Window:GetObject('OkButton').Enabled = true\
  4550.             end,\
  4551.             OnClick = function(listView, event, side, x, y)\
  4552.                 if y == 1 then\
  4553.                     goToFolder('/')\
  4554.                 end\
  4555.             end\
  4556.         },\
  4557.     }\
  4558.     local view = {\
  4559.         Children = children,\
  4560.         Width=40,\
  4561.         Height= Drawing.Screen.Height - 4\
  4562.     }\
  4563.     self:DisplayWindow(view, title)\
  4564. \
  4565.     goToFolder = function(path)\
  4566.         path = Helpers.TidyPath(path)\
  4567.         self.Window:GetObject('PathLabel').Text = path\
  4568.         currentFolder = path\
  4569. \
  4570.         local filesListItems = {}\
  4571.         for i, v in ipairs(fs.list(path)) do\
  4572.             if not fs.isDir(currentFolder .. v) then\
  4573.                 table.insert(filesListItems, v)\
  4574.             end\
  4575.         end\
  4576.         self.Window:GetObject('OkButton').Enabled = false\
  4577.         selectedPath = nil\
  4578.         self.Window:GetObject('FilesListView').Items = filesListItems\
  4579. \
  4580.     end\
  4581. \
  4582.     goToFolder('')\
  4583. \
  4584.     self.Window.OnCloseButton = function()callback(false)end\
  4585. end\
  4586. \
  4587. function RegisterEvent(self, event, func)\
  4588.     if not self.EventHandlers[event] then\
  4589.         self.EventHandlers[event] = {}\
  4590.     end\
  4591.     table.insert(self.EventHandlers[event], func)\
  4592. end\
  4593. \
  4594. function StartRepeatingTimer(self, func, interval)\
  4595.     local int = interval\
  4596.     if type(int) == 'function' then\
  4597.         int = int()\
  4598.     end\
  4599.     if not int or int <= 0 then\
  4600.         return\
  4601.     end\
  4602.     local timer = os.startTimer(int)\
  4603. \
  4604.     self.Timers[timer] = {func, true, interval}\
  4605.     return timer\
  4606. end\
  4607. \
  4608. function StartTimer(self, func, delay)\
  4609.     local timer = os.startTimer(delay)\
  4610.     self.Timers[timer] = {func, false}\
  4611.     return timer\
  4612. end\
  4613. \
  4614. function StopTimer(self, timer)\
  4615.     if self.Timers[timer] then\
  4616.         self.Timers[timer] = nil\
  4617.     end\
  4618. end\
  4619. \
  4620. function HandleTimer(self, event, timer)\
  4621.     if self.Timers[timer] then\
  4622.         local oldTimer = self.Timers[timer]\
  4623.         self.Timers[timer] = nil\
  4624.         local new = nil\
  4625.         if oldTimer[2] then\
  4626.             new = self:StartRepeatingTimer(oldTimer[1], oldTimer[3])\
  4627.         end\
  4628.         if oldTimer and oldTimer[1] then\
  4629.             oldTimer[1](new)\
  4630.         end\
  4631.     elseif self.OnTimer then\
  4632.         self.OnTimer(self, event, timer)\
  4633.     end\
  4634. end\
  4635. \
  4636. function SetActiveObject(self, object)\
  4637.     if object then\
  4638.         if object ~= self.ActiveObject then\
  4639.             self.ActiveObject = object\
  4640.             object:ForceDraw()\
  4641.         end\
  4642.     elseif self.ActiveObject ~= nil then\
  4643.         self.ActiveObject = nil\
  4644.         self.CursorPos = nil\
  4645.         self.View:ForceDraw()\
  4646.     end\
  4647. end\
  4648. \
  4649. function GetActiveObject(self)\
  4650.     return self.ActiveObject\
  4651. end\
  4652. \
  4653. OnTimer = nil\
  4654. OnClick = nil\
  4655. OnKeyChar = nil\
  4656. OnDrag = nil\
  4657. OnScroll = nil\
  4658. OnViewLoad = nil\
  4659. OnViewClose = nil\
  4660. OnDraw = nil\
  4661. OnQuit = nil\
  4662. \
  4663. local eventFuncs = {\
  4664.     OnClick = {'mouse_click'},\
  4665.     OnKeyChar = {'key', 'char'},\
  4666.     OnDrag = {'mouse_drag'},\
  4667.     OnScroll = {'mouse_scroll'},\
  4668.     HandleClick = {'mouse_click', 'mouse_drag', 'mouse_scroll'},\
  4669.     HandleKeyChar = {'key', 'char'},\
  4670.     HandleTimer = {'timer'}\
  4671. }\
  4672. \
  4673. local drawCalls = 0\
  4674. local ignored = 0\
  4675. function Draw(self)\
  4676.     self.IsDrawing = true\
  4677.     if self.OnDraw then\
  4678.         self:OnDraw()\
  4679.     end\
  4680. \
  4681.     if self.View and self.View:NeedsDraw() then\
  4682.         self.View:Draw()\
  4683.         Drawing.DrawBuffer()\
  4684.         if isDebug then\
  4685.             drawCalls = drawCalls + 1\
  4686.         end\
  4687.     elseif not self.View then\
  4688.         print('No loaded view. You need to do program:LoadView first.')\
  4689.     end \
  4690. \
  4691.     if self:GetActiveObject() and self.CursorPos and type(self.CursorPos[1]) == 'number' and type(self.CursorPos[2]) == 'number' then\
  4692.         term.setCursorPos(self.CursorPos[1], self.CursorPos[2])\
  4693.         term.setTextColour(self.CursorColour)\
  4694.         term.setCursorBlink(true)\
  4695.     else\
  4696.         term.setCursorBlink(false)\
  4697.     end\
  4698. \
  4699.     self.IsDrawing = false\
  4700. end\
  4701. \
  4702. function EventHandler(self)\
  4703.     local event = { os.pullEventRaw() }\
  4704.     \
  4705.     if self.EventHandlers[event[1]] then\
  4706.         for i, e in ipairs(self.EventHandlers[event[1]]) do\
  4707.             e(self, unpack(event))\
  4708.         end\
  4709.     end\
  4710. end\
  4711. \
  4712. function Quit(self)\
  4713.     self.Running = false\
  4714.     if self.OnQuit then\
  4715.         self:OnQuit()\
  4716.     end\
  4717.     if OneOS then\
  4718.         OneOS.Close()\
  4719.     end\
  4720. end\
  4721. \
  4722. function Run(self, ready)\
  4723.     for name, events in pairs(eventFuncs) do\
  4724.         if self[name] then\
  4725.             for i, event in ipairs(events) do\
  4726.                 self:RegisterEvent(event, self[name])\
  4727.             end\
  4728.         end\
  4729.     end\
  4730. \
  4731.     if self.AllowTerminate then\
  4732.         self:RegisterEvent('terminate', function()error('Terminated', 0) end)\
  4733.     end\
  4734. \
  4735.     if self.DefaultView and self.DefaultView ~= '' and fs.exists(self.ViewPath..self.DefaultView..'.view') then\
  4736.         self:LoadView(self.DefaultView)\
  4737.     end\
  4738. \
  4739.     if ready then\
  4740.         ready()\
  4741.     end\
  4742.     \
  4743.     self:Draw()\
  4744. \
  4745.     while self.Running do\
  4746.         self:EventHandler()\
  4747.     end\
  4748. end",[".gitignore"]=".DS_Store\
  4749. .Desktop.settings\
  4750. .OneOS.settings\
  4751. *.settings\
  4752. \
  4753. Desktop/.Desktop.settings\
  4754. \
  4755. .version",["hash"]="--\
  4756. --  Thanks to GravityScore for this!\
  4757. --  http://www.computercraft.info/forums2/index.php?/topic/8169-sha-256-in-pure-lua/\
  4758. --\
  4759. --  This is used to hash passwords sent with the secure text field. It just reduces the chance of people getting hacked.\
  4760. --\
  4761. \
  4762. --  \
  4763. --  Adaptation of the Secure Hashing Algorithm (SHA-244/256)\
  4764. --  Found Here: http://lua-users.org/wiki/SecureHashAlgorithm\
  4765. --  \
  4766. --  Using an adapted version of the bit library\
  4767. --  Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua\
  4768. --  \
  4769. \
  4770. local MOD = 2^32\
  4771. local MODM = MOD-1\
  4772. \
  4773. local function memoize(f)\
  4774.     local mt = {}\
  4775.     local t = setmetatable({}, mt)\
  4776.     function mt:__index(k)\
  4777.         local v = f(k)\
  4778.         t[k] = v\
  4779.         return v\
  4780.     end\
  4781.     return t\
  4782. end\
  4783. \
  4784. local function make_bitop_uncached(t, m)\
  4785.     local function bitop(a, b)\
  4786.         local res,p = 0,1\
  4787.         while a ~= 0 and b ~= 0 do\
  4788.             local am, bm = a % m, b % m\
  4789.             res = res + t[am][bm] * p\
  4790.             a = (a - am) / m\
  4791.             b = (b - bm) / m\
  4792.             p = p*m\
  4793.         end\
  4794.         res = res + (a + b) * p\
  4795.         return res\
  4796.     end\
  4797.     return bitop\
  4798. end\
  4799. \
  4800. local function make_bitop(t)\
  4801.     local op1 = make_bitop_uncached(t,2^1)\
  4802.     local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)\
  4803.     return make_bitop_uncached(op2, 2 ^ (t.n or 1))\
  4804. end\
  4805. \
  4806. local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})\
  4807. \
  4808. local function bxor(a, b, c, ...)\
  4809.     local z = nil\
  4810.     if b then\
  4811.         a = a % MOD\
  4812.         b = b % MOD\
  4813.         z = bxor1(a, b)\
  4814.         if c then z = bxor(z, c, ...) end\
  4815.         return z\
  4816.     elseif a then return a % MOD\
  4817.     else return 0 end\
  4818. end\
  4819. \
  4820. local function band(a, b, c, ...)\
  4821.     local z\
  4822.     if b then\
  4823.         a = a % MOD\
  4824.         b = b % MOD\
  4825.         z = ((a + b) - bxor1(a,b)) / 2\
  4826.         if c then z = bit32_band(z, c, ...) end\
  4827.         return z\
  4828.     elseif a then return a % MOD\
  4829.     else return MODM end\
  4830. end\
  4831. \
  4832. local function bnot(x) return (-1 - x) % MOD end\
  4833. \
  4834. local function rshift1(a, disp)\
  4835.     if disp < 0 then return lshift(a,-disp) end\
  4836.     return math.floor(a % 2 ^ 32 / 2 ^ disp)\
  4837. end\
  4838. \
  4839. local function rshift(x, disp)\
  4840.     if disp > 31 or disp < -31 then return 0 end\
  4841.     return rshift1(x % MOD, disp)\
  4842. end\
  4843. \
  4844. local function lshift(a, disp)\
  4845.     if disp < 0 then return rshift(a,-disp) end \
  4846.     return (a * 2 ^ disp) % 2 ^ 32\
  4847. end\
  4848. \
  4849. local function rrotate(x, disp)\
  4850.    x = x % MOD\
  4851.    disp = disp % 32\
  4852.    local low = band(x, 2 ^ disp - 1)\
  4853.    return rshift(x, disp) + lshift(low, 32 - disp)\
  4854. end\
  4855. \
  4856. local k = {\
  4857.     0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\
  4858.     0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\
  4859.     0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\
  4860.     0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\
  4861.     0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\
  4862.     0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\
  4863.     0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\
  4864.     0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\
  4865.     0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\
  4866.     0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\
  4867.     0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\
  4868.     0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\
  4869.     0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\
  4870.     0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\
  4871.     0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\
  4872.     0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\
  4873. }\
  4874. \
  4875. local function str2hexa(s)\
  4876.     return (string.gsub(s, \".\", function(c) return string.format(\"%02x\", string.byte(c)) end))\
  4877. end\
  4878. \
  4879. local function num2s(l, n)\
  4880.     local s = \"\"\
  4881.     for i = 1, n do\
  4882.         local rem = l % 256\
  4883.         s = string.char(rem) .. s\
  4884.         l = (l - rem) / 256\
  4885.     end\
  4886.     return s\
  4887. end\
  4888. \
  4889. local function s232num(s, i)\
  4890.     local n = 0\
  4891.     for i = i, i + 3 do n = n*256 + string.byte(s, i) end\
  4892.     return n\
  4893. end\
  4894. \
  4895. local function preproc(msg, len)\
  4896.     local extra = 64 - ((len + 9) % 64)\
  4897.     len = num2s(8 * len, 8)\
  4898.     msg = msg .. \"\\128\" .. string.rep(\"\\0\", extra) .. len\
  4899.     assert(#msg % 64 == 0)\
  4900.     return msg\
  4901. end\
  4902. \
  4903. local function initH256(H)\
  4904.     H[1] = 0x6a09e667\
  4905.     H[2] = 0xbb67ae85\
  4906.     H[3] = 0x3c6ef372\
  4907.     H[4] = 0xa54ff53a\
  4908.     H[5] = 0x510e527f\
  4909.     H[6] = 0x9b05688c\
  4910.     H[7] = 0x1f83d9ab\
  4911.     H[8] = 0x5be0cd19\
  4912.     return H\
  4913. end\
  4914. \
  4915. local function digestblock(msg, i, H)\
  4916.     local w = {}\
  4917.     for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end\
  4918.     for j = 17, 64 do\
  4919.         local v = w[j - 15]\
  4920.         local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))\
  4921.         v = w[j - 2]\
  4922.         w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))\
  4923.     end\
  4924. \
  4925.     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]\
  4926.     for i = 1, 64 do\
  4927.         local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))\
  4928.         local maj = bxor(band(a, b), band(a, c), band(b, c))\
  4929.         local t2 = s0 + maj\
  4930.         local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))\
  4931.         local ch = bxor (band(e, f), band(bnot(e), g))\
  4932.         local t1 = h + s1 + ch + k[i] + w[i]\
  4933.         h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2\
  4934.     end\
  4935. \
  4936.     H[1] = band(H[1] + a)\
  4937.     H[2] = band(H[2] + b)\
  4938.     H[3] = band(H[3] + c)\
  4939.     H[4] = band(H[4] + d)\
  4940.     H[5] = band(H[5] + e)\
  4941.     H[6] = band(H[6] + f)\
  4942.     H[7] = band(H[7] + g)\
  4943.     H[8] = band(H[8] + h)\
  4944. end\
  4945. \
  4946. function sha256(msg)\
  4947.     msg = preproc(msg, #msg)\
  4948.     local H = initH256({})\
  4949.     for i = 1, #msg, 64 do digestblock(msg, i, H) end\
  4950.     return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..\
  4951.         num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))\
  4952. end",["Pages"]={["404.ccml"]="<!DOCTYPE ccml>\
  4953. <html>\
  4954.     <head>\
  4955.       <title>Page Not Found</title>\
  4956.     </head>\
  4957.     <body>\
  4958.         <br/>\
  4959.         <br/>\
  4960.         <h colour=\"red\">404 Page Not Found</h>\
  4961.         <br/>\
  4962.         <center>\
  4963.             <p width=\"38\" align=\"center\">The page was not found on the server. Check the address and try again.</p>\
  4964.         </center>\
  4965.     </body>\
  4966. </html>",["6.ccml"]="<!DOCTYPE ccml>\
  4967. <html>\
  4968.     <head>\
  4969.       <title>Download Failed</title>\
  4970.     </head>\
  4971.     <body>\
  4972.         <br/>\
  4973.         <br/>\
  4974.         <h colour=\"red\">Download Failed</h>\
  4975.         <br/>\
  4976.         <center>\
  4977.             <br>\
  4978.             <p width=\"38\" align=\"center\">The file you wanted failed to download. Try again or contact the file owner.</p>\
  4979.         </center>\
  4980.     </body>\
  4981. </html>",["7.ccml"]="<!DOCTYPE ccml>\
  4982. <html>\
  4983.     <head>\
  4984.       <title>No Modem Connected</title>\
  4985.     </head>\
  4986.     <body>\
  4987.         <br/>\
  4988.         <br/>\
  4989.         <h colour=\"red\">No Modem Connected</h>\
  4990.         <br/>\
  4991.         <center>\
  4992.             <br>\
  4993.             <p width=\"38\" align=\"center\">Please attach a wirelss modem and restart Quest.</p>\
  4994.         </center>\
  4995.     </body>\
  4996. </html>",["download.ccml"]="<!DOCTYPE ccml>\
  4997. <html>\
  4998.     <head>\
  4999.         <title>Downloading File</title>\
  5000.         <script type=\"lua\">\
  5001.             if window.get.path then\
  5002.                 l('p').text('Quest is downloading your file to ' .. window.get.path .. '. Please wait a moment. Leaving this page will cancel the download.')\
  5003.             end\
  5004.         </script>\
  5005.     </head>\
  5006.     <body>\
  5007.         <br/>\
  5008.         <br/>\
  5009.         <h colour=\"blue\">Downloading File</h>\
  5010. \
  5011.         <center>\
  5012.             <br>\
  5013.             <p width=\"48\" align=\"center\"></p>\
  5014.         </center>\
  5015.     </body>\
  5016. </html>",["408.ccml"]="<!DOCTYPE ccml>\
  5017. <html>\
  5018.     <head>\
  5019.       <title>Page Not Found</title>\
  5020.     </head>\
  5021.     <body>\
  5022.         <br/>\
  5023.         <br/>\
  5024.         <h colour=\"red\">Page Load Cancelled</h>\
  5025.         <br/>\
  5026.         <center>\
  5027.             <p width=\"38\" align=\"center\">The page either took too long to load or you cancelled loading it.</p>\
  5028.         </center>\
  5029.     </body>\
  5030. </html>",["text.ccml"]="<!DOCTYPE ccml>\
  5031. <html>\
  5032.     <head>\
  5033.         <title>An Error Occured</title>\
  5034.         <script type=\"lua\">\
  5035.             if window.get.reason then\
  5036.                 l('p').text(window.get.reason)\
  5037.             end\
  5038.         </script>\
  5039.     </head>\
  5040.     <body>\
  5041.         <br/>\
  5042.         <br/>\
  5043.         <h colour=\"red\">An Error Occured</h>\
  5044.         <br/>\
  5045.         <center>\
  5046.             <br>\
  5047.             <p width=\"48\" align=\"center\">Unknown Reason</p>\
  5048.         </center>\
  5049.     </body>\
  5050. </html>",["downloaded.ccml"]="<!DOCTYPE ccml>\
  5051. <html>\
  5052.     <head>\
  5053.         <title>Download Complete</title>\
  5054.         <script type=\"lua\">\
  5055.             if window.get.path then\
  5056.                 l('p').text('Your file has been saved to ' .. window.get.path .. '. You can now leave this page (use the back button).')\
  5057.             end\
  5058.         </script>\
  5059.     </head>\
  5060.     <body>\
  5061.         <br/>\
  5062.         <br/>\
  5063.         <h colour=\"blue\">Download Complete</h>\
  5064. \
  5065.         <center>\
  5066.             <br>\
  5067.             <p width=\"48\" align=\"center\"></p>\
  5068.         </center>\
  5069.     </body>\
  5070. </html>",["1.ccml"]="<!DOCTYPE ccml>\
  5071. <html>\
  5072.     <head>\
  5073.       <title>Failed to Download Page</title>\
  5074.     </head>\
  5075.     <body>\
  5076.         <br/>\
  5077.         <br/>\
  5078.         <h colour=\"red\">Failed to Download Page</h>\
  5079.         <br/>\
  5080.         <center>\
  5081.             <br>\
  5082.             <p width=\"38\" align=\"center\">The page you requested failed to download. The page may not exist, the server may be experiencing problems or you have connection issues.</p>\
  5083.         </center>\
  5084.     </body>\
  5085. </html>",["2.ccml"]="<!DOCTYPE ccml>\
  5086. <html>\
  5087.     <head>\
  5088.       <title>Doctype Incorrect</title>\
  5089.     </head>\
  5090.     <body>\
  5091.         <br/>\
  5092.         <br/>\
  5093.         <h colour=\"red\">Doctype Incorrect</h>\
  5094.         <br/>\
  5095.         <center>\
  5096.             <br>\
  5097.             <p width=\"38\" align=\"center\">This page has an incorrect doctype and can not be rendered. Quest can not view standard web pages.</p>\
  5098.             <br>\
  5099.             <p width=\"38\" align=\"center\" color=\"grey\">If you made this page make sure the file starts with \"&lt;!DOCTYPE ccml&gt;\"</p>\
  5100.         </center>\
  5101.     </body>\
  5102. </html>",["3.ccml"]="<!DOCTYPE ccml>\
  5103. <html>\
  5104.     <head>\
  5105.       <title>Failed to Parse Page</title>\
  5106.     </head>\
  5107.     <body>\
  5108.         <br/>\
  5109.         <br/>\
  5110.         <h colour=\"red\">Failed to Parse Page</h>\
  5111.         <br/>\
  5112.         <center>\
  5113.             <br>\
  5114.             <p width=\"38\" align=\"center\">The page you requested failed to parse. It is either malformed or your browser is out of date.</p>\
  5115.         </center>\
  5116.     </body>\
  5117. </html>",["4.ccml"]="<!DOCTYPE ccml>\
  5118. <html>\
  5119.     <head>\
  5120.       <title>HTTP Not Enabled</title>\
  5121.     </head>\
  5122.     <body>\
  5123.         <br/>\
  5124.         <br/>\
  5125.         <h colour=\"red\">HTTP Not Enabled</h>\
  5126.         <br/>\
  5127.         <center>\
  5128.             <br>\
  5129.             <p width=\"38\" align=\"center\">You haven't enabled the HTTP API. To do so, take a look on the HTTP API page on the wiki for a link to a tutorial.</p>\
  5130.         </center>\
  5131.     </body>\
  5132. </html>",["5.ccml"]="<!DOCTYPE ccml>\
  5133. <html>\
  5134.     <head>\
  5135.       <title>Page Not Whitelisted</title>\
  5136.     </head>\
  5137.     <body>\
  5138.         <br/>\
  5139.         <br/>\
  5140.         <h colour=\"red\">Page Not Whitelisted</h>\
  5141.         <br/>\
  5142.         <center>\
  5143.             <br>\
  5144.             <p width=\"38\" align=\"center\">The page you are trying to open isn't whitelisted. Please take a look on the forums or the wiki as to how to fix this.</p>\
  5145.         </center>\
  5146.     </body>\
  5147. </html>",},["lQuery"]="function fn(selector)\
  5148.     if not selector then\
  5149.     else\
  5150.         local elements = lQuery.webView:ResolveElements(selector)\
  5151.         local function relayout()\
  5152.             lQuery.webView:RepositionLayout()\
  5153.         end\
  5154.         if elements and #elements > 0 then\
  5155.             local each = function(func)\
  5156.                 for i, v in ipairs(elements) do\
  5157.                     func(v, i)\
  5158.                 end\
  5159.             end\
  5160. \
  5161.             local response = {\
  5162.                 text = function(text)\
  5163.                     each(function(elem)\
  5164.                         if elem.Text then\
  5165.                             elem.Text = tostring(text)\
  5166.                         end\
  5167.                     end)\
  5168.                 end,\
  5169. \
  5170.                 width = function(width)\
  5171.                     if type(width) == 'number' then\
  5172.                         each(function(elem)\
  5173.                             elem.Width = width\
  5174.                         end)\
  5175.                         relayout()\
  5176.                     end\
  5177.                 end,\
  5178. \
  5179.                 height = function(height)\
  5180.                     if type(height) == 'number' then\
  5181.                         each(function(elem)\
  5182.                             elem.Height = height\
  5183.                         end)\
  5184.                         relayout()\
  5185.                     end\
  5186.                 end,\
  5187. \
  5188.                 colour = function(colour)\
  5189.                     if type(colour) == 'number' then\
  5190.                         each(function(elem)\
  5191.                             if elem.TextColour then\
  5192.                                 elem.TextColour = colour\
  5193.                             end\
  5194.                         end)\
  5195.                     end\
  5196.                 end,\
  5197. \
  5198.                 bgcolour = function(bgcolour)\
  5199.                     if type(bgcolour) == 'number' then\
  5200.                         each(function(elem)\
  5201.                             if elem.BackgroundColour then\
  5202.                                 elem.BackgroundColour = bgcolour\
  5203.                             end\
  5204.                         end)\
  5205.                     end\
  5206.                 end,\
  5207. \
  5208.                 align = function(align)\
  5209.                     if type(align) == 'string' and align:lower() == 'left' or align:lower() == 'center' or align:lower() == 'right'  then\
  5210.                         each(function(elem)\
  5211.                             if elem.Align then\
  5212.                                 elem.Align = align:lower():gsub(\"^%l\", string.upper)\
  5213.                             end\
  5214.                         end)\
  5215.                     end\
  5216.                 end,\
  5217. \
  5218.                 attr = function(name)\
  5219.                     local values = {}\
  5220.                     each(function(elem)\
  5221.                         if elem.Element.Attributes and elem.Element.Attributes[name] then\
  5222.                             table.insert(values, elem.Element.Attributes[name])\
  5223.                         end\
  5224.                     end)\
  5225.                     return values\
  5226.                 end,\
  5227. \
  5228.                 remove = function()\
  5229.                     each(function(elem)\
  5230.                         lQuery.webView:RemoveElement(elem)\
  5231.                         relayout()\
  5232.                     end)\
  5233.                 end,\
  5234. \
  5235.                 focus = function()\
  5236.                     each(function(elem)\
  5237.                         elem.Bedrock:SetActiveObject(elem)\
  5238.                     end)\
  5239.                 end\
  5240.             }\
  5241.             response.color = response.colour\
  5242.             response.bgcolor = response.bgcolour\
  5243. \
  5244.             return response\
  5245.         end\
  5246.     end\
  5247. end",["Peripheral"]="GetPeripheral = function(_type)\
  5248.     for i, p in ipairs(GetPeripherals()) do\
  5249.         if p.Type == _type then\
  5250.             return p\
  5251.         end\
  5252.     end\
  5253. end\
  5254. \
  5255. Call = function(type, ...)\
  5256.     local tArgs = {...}\
  5257.     local p = GetPeripheral(type)\
  5258.     peripheral.call(p.Side, unpack(tArgs))\
  5259. end\
  5260. \
  5261. local getNames = peripheral.getNames or function()\
  5262.     local tResults = {}\
  5263.     for n,sSide in ipairs( rs.getSides() ) do\
  5264.         if peripheral.isPresent( sSide ) then\
  5265.             table.insert( tResults, sSide )\
  5266.             local isWireless = false\
  5267.             if pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then\
  5268.                 isWireless = true\
  5269.             end     \
  5270.             if peripheral.getType( sSide ) == \"modem\" and not isWireless then\
  5271.                 local tRemote = peripheral.call( sSide, \"getNamesRemote\" )\
  5272.                 for n,sName in ipairs( tRemote ) do\
  5273.                     table.insert( tResults, sName )\
  5274.                 end\
  5275.             end\
  5276.         end\
  5277.     end\
  5278.     return tResults\
  5279. end\
  5280. \
  5281. GetPeripherals = function(filterType)\
  5282.     local peripherals = {}\
  5283.     for i, side in ipairs(getNames()) do\
  5284.         local name = peripheral.getType(side):gsub(\"^%l\", string.upper)\
  5285.         local code = string.upper(side:sub(1,1))\
  5286.         if side:find('_') then\
  5287.             code = side:sub(side:find('_')+1)\
  5288.         end\
  5289. \
  5290.         local dupe = false\
  5291.         for i, v in ipairs(peripherals) do\
  5292.             if v[1] == name .. ' ' .. code then\
  5293.                 dupe = true\
  5294.             end\
  5295.         end\
  5296. \
  5297.         if not dupe then\
  5298.             local _type = peripheral.getType(side)\
  5299.             local formattedType = _type:sub(1, 1):upper() .. _type:sub(2, -1)\
  5300.             local isWireless = false\
  5301.             if _type == 'modem' then\
  5302.                 if not pcall(function()isWireless = peripheral.call(side, 'isWireless') end) then\
  5303.                     isWireless = true\
  5304.                 end     \
  5305.                 if isWireless then\
  5306.                     _type = 'wireless_modem'\
  5307.                     formattedType = 'Wireless Modem'\
  5308.                     name = 'W '..name\
  5309.                 end\
  5310.             end\
  5311.             if not filterType or _type == filterType then\
  5312.                 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})\
  5313.             end\
  5314.         end\
  5315.     end\
  5316.     return peripherals\
  5317. end\
  5318. \
  5319. GetSide = function(side)\
  5320.     for i, p in ipairs(GetPeripherals()) do\
  5321.         if p.Side == side then\
  5322.             return p\
  5323.         end\
  5324.     end\
  5325. end\
  5326. \
  5327. PresentNamed = function(name)\
  5328.     return peripheral.isPresent(name)\
  5329. end\
  5330. \
  5331. CallType = function(type, ...)\
  5332.     local tArgs = {...}\
  5333.     local p = GetPeripheral(type)\
  5334.     return peripheral.call(p.Side, unpack(tArgs))\
  5335. end\
  5336. \
  5337. CallNamed = function(name, ...)\
  5338.     local tArgs = {...}\
  5339.     return peripheral.call(name, unpack(tArgs))\
  5340. end\
  5341. \
  5342. GetInfo = function(p)\
  5343.     local info = {}\
  5344.     local buttons = {}\
  5345.     if p.Type == 'computer' then\
  5346.         local id = peripheral.call(p.Side:lower(),'getID')\
  5347.         if id then\
  5348.             info = {\
  5349.                 ID = tostring(id)\
  5350.             }\
  5351.         else\
  5352.             info = {}\
  5353.         end\
  5354.     elseif p.Type == 'drive' then\
  5355.         local discType = 'No Disc'\
  5356.         local discID = nil\
  5357.         local mountPath = nil\
  5358.         local discLabel = nil\
  5359.         local songName = nil\
  5360.         if peripheral.call(p.Side:lower(), 'isDiskPresent') then\
  5361.             if peripheral.call(p.Side:lower(), 'hasData') then\
  5362.                 discType = 'Data'\
  5363.                 discID = peripheral.call(p.Side:lower(), 'getDiskID')\
  5364.                 if discID then\
  5365.                     discID = tostring(discID)\
  5366.                 else\
  5367.                     discID = 'None'\
  5368.                 end\
  5369.                 mountPath = '/'..peripheral.call(p.Side:lower(), 'getMountPath')..'/'\
  5370.                 discLabel = peripheral.call(p.Side:lower(), 'getDiskLabel')\
  5371.             else\
  5372.                 discType = 'Audio'\
  5373.                 songName = peripheral.call(p.Side:lower(), 'getAudioTitle')\
  5374.             end\
  5375.         end\
  5376.         if mountPath then\
  5377.             table.insert(buttons, {Text = 'View Files', OnClick = function(self, event, side, x, y)GoToPath(mountPath)end})\
  5378.         elseif discType == 'Audio' then\
  5379.             table.insert(buttons, {Text = 'Play', OnClick = function(self, event, side, x, y)\
  5380.                 if self.Text == 'Play' then\
  5381.                     disk.playAudio(p.Side:lower())\
  5382.                     self.Text = 'Stop'\
  5383.                 else\
  5384.                     disk.stopAudio(p.Side:lower())\
  5385.                     self.Text = 'Play'\
  5386.                 end\
  5387.             end})\
  5388.         else\
  5389.             diskOpenButton = nil\
  5390.         end\
  5391.         if discType ~= 'No Disc' then\
  5392.             table.insert(buttons, {Text = 'Eject', OnClick = function(self, event, side, x, y)disk.eject(p.Side:lower()) sleep(0) RefreshFiles() end})\
  5393.         end\
  5394. \
  5395.         info = {\
  5396.             ['Disc Type'] = discType,\
  5397.             ['Disc Label'] = discLabel,\
  5398.             ['Song Title'] = songName,\
  5399.             ['Disc ID'] = discID,\
  5400.             ['Mount Path'] = mountPath\
  5401.         }\
  5402.     elseif p.Type == 'printer' then\
  5403.         local pageSize = 'No Loaded Page'\
  5404.         local _, err = pcall(function() return tostring(peripheral.call(p.Side:lower(), 'getPgaeSize')) end)\
  5405.         if not err then\
  5406.             pageSize = tostring(peripheral.call(p.Side:lower(), 'getPageSize'))\
  5407.         end\
  5408.         info = {\
  5409.             ['Paper Level'] = tostring(peripheral.call(p.Side:lower(), 'getPaperLevel')),\
  5410.             ['Paper Size'] = pageSize,\
  5411.             ['Ink Level'] = tostring(peripheral.call(p.Side:lower(), 'getInkLevel'))\
  5412.         }\
  5413.     elseif p.Type == 'modem' then\
  5414.         info = {\
  5415.             ['Connected Peripherals'] = tostring(#peripheral.call(p.Side:lower(), 'getNamesRemote'))\
  5416.         }\
  5417.     elseif p.Type == 'monitor' then\
  5418.         local w, h = peripheral.call(p.Side:lower(), 'getSize')\
  5419.         local screenType = 'Black and White'\
  5420.         if peripheral.call(p.Side:lower(), 'isColour') then\
  5421.             screenType = 'Colour'\
  5422.         end\
  5423.         local buttonTitle = 'Use as Screen'\
  5424.         if OneOS.Settings:GetValues()['Monitor'] == p.Side:lower() then\
  5425.             buttonTitle = 'Use Computer Screen'\
  5426.         end\
  5427.         table.insert(buttons, {Text = buttonTitle, OnClick = function(self, event, side, x, y)\
  5428.                 self.Bedrock:DisplayAlertWindow('Reboot Required', \"To change screen you'll need to reboot your computer.\", {'Reboot', 'Cancel'}, function(value)\
  5429.                     if value == 'Reboot' then\
  5430.                         if buttonTitle == 'Use Computer Screen' then\
  5431.                             OneOS.Settings:SetValue('Monitor', nil)\
  5432.                         else\
  5433.                             OneOS.Settings:SetValue('Monitor', p.Side:lower())\
  5434.                         end\
  5435.                         OneOS.Reboot()\
  5436.                     end\
  5437.                 end)\
  5438.             end\
  5439.         })\
  5440.         info = {\
  5441.             ['Type'] = screenType,\
  5442.             ['Width'] = tostring(w),\
  5443.             ['Height'] = tostring(h),\
  5444.         }\
  5445.     end\
  5446.     info.Buttons = buttons\
  5447.     return info\
  5448. end",["Objects"]={["HeadingView.lua"]="Inherit = 'View'\
  5449. Height = 3\
  5450. \
  5451. OnLoad = function(self)\
  5452.     self:OnUpdate('Text')\
  5453. end\
  5454. \
  5455. OnUpdate = function(self, value)\
  5456.     if value == 'Text' then\
  5457.         self:RemoveAllObjects()\
  5458.         self:AddObject({\
  5459.             Y = 1,\
  5460.             X = 1,\
  5461.             Width = \"100%\",\
  5462.             Align = \"Center\",\
  5463.             Type = \"Label\",\
  5464.             Text = self.Text,\
  5465.             TextColour = self.TextColour,\
  5466.             BackgroundColour = self.BackgroundColour\
  5467.         })\
  5468. \
  5469.         local underline = ''\
  5470.         for i = 1, #self.Text + 2 do\
  5471.             underline = underline .. '='\
  5472.         end\
  5473.         self:AddObject({\
  5474.             Y = 2,\
  5475.             X = 1,\
  5476.             Width = \"100%\",\
  5477.             Align = \"Center\",\
  5478.             Type = \"Label\",\
  5479.             Text = underline,\
  5480.             TextColour = self.TextColour,\
  5481.             BackgroundColour = self.BackgroundColour\
  5482.         })\
  5483.     end\
  5484. end",["WebImageView.lua"]="URL = false\
  5485. Image = false\
  5486. \
  5487. OnDraw = function(self, x, y)\
  5488.     if not self.Image then\
  5489.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, colours.lightGrey)\
  5490.     elseif self.Format == 'nft' then\
  5491.         Drawing.DrawImage(x, y, self.Image, self.Width, self.Height)\
  5492.     elseif self.Format == 'nfp' or self.Format == 'paint' then\
  5493.         for _x, col in ipairs(self.Image) do\
  5494.             for _y, colour in ipairs(col) do\
  5495.                 Drawing.WriteToBuffer(x+_x-1, y+_y-1, ' ', colours.white, colour)\
  5496.             end\
  5497.         end\
  5498.     elseif self.Format == 'skch' or self.Format == 'sketch' then\
  5499.         Drawing.DrawImage(x, y, self.Image, self.Width, self.Height)\
  5500.     end\
  5501. end\
  5502. \
  5503. OnUpdate = function(self, value)\
  5504.     if value == 'URL' and self.URL then\
  5505.         fetchHTTPAsync(resolveFullUrl(self.URL), function(ok, event, response)\
  5506.             if ok then\
  5507.                 local width, height = self.Width, self.Height\
  5508. \
  5509.                 local lines = {}\
  5510.                 for line in response.readLine do\
  5511.                     table.insert(lines, line)\
  5512.                 end\
  5513.                 response.close()\
  5514.                 local content = table.concat(lines, '\\n')\
  5515. \
  5516.                 if not self.Format then\
  5517.                     self.Format = self:DetermineFormat(content)\
  5518.                 end\
  5519. \
  5520.                 if self.Format == 'nft' then\
  5521.                     self.Image, self.Width, self.Height = self:ReadNFT(lines)\
  5522.                 elseif self.Format == 'nfp' or self.Format == 'paint' then\
  5523.                     self.Image, self.Width, self.Height = self:ReadNFP(lines)\
  5524.                 elseif self.Format == 'skch' or self.Format == 'sketch' then\
  5525.                     self.Image, self.Width, self.Height = self:ReadSKCH(content)\
  5526.                 end\
  5527.                 if (width ~= self.Width or height ~= self.Height) then\
  5528.                     self.Bedrock:GetObject('WebView'):RepositionLayout()\
  5529.                 end\
  5530.             end\
  5531.         end)\
  5532.     end\
  5533. end\
  5534. \
  5535. DetermineFormat = function(self, content)\
  5536.     if type(textutils.unserialize(content)) == 'table' then\
  5537.         -- It's a serlized table, asume sketch\
  5538.         return 'skch'\
  5539.     elseif string.find(content, string.char(30)) or string.find(content, string.char(31)) then\
  5540.         -- Contains the characters that set colours, asume nft\
  5541.         return 'nft'\
  5542.     else\
  5543.         -- Otherwise asume nfp\
  5544.         return 'nfp'\
  5545.     end\
  5546. end\
  5547. \
  5548. ReadSKCH = function(self, content)\
  5549.     local _layers = textutils.unserialize(content)\
  5550.     local layers = {}\
  5551. \
  5552.     local width, height = 1, 1\
  5553. \
  5554.     for i, layer in ipairs(_layers) do\
  5555.         if layer.Visible then\
  5556.             local nft, w, h = self:ReadNFT(layer.Pixels)\
  5557.             if w > width then\
  5558.                 width = w\
  5559.             end\
  5560.             if h > height then\
  5561.                 height = h\
  5562.             end\
  5563.             table.insert(layers, nft)\
  5564.         end\
  5565.     end\
  5566. \
  5567.     --flatten the layers\
  5568.     local image = {\
  5569.         text = {},\
  5570.         textcol = {}\
  5571.     }\
  5572. \
  5573.     for i, layer in ipairs(layers) do\
  5574.         for y, row in ipairs(layer) do\
  5575.             if not image[y] then\
  5576.                 image[y] = {}\
  5577.             end\
  5578.             for x, pixel in ipairs(row) do\
  5579.                 if not image[y][x] or pixel ~= colours.transparent then\
  5580.                     image[y][x] = pixel\
  5581.                 end\
  5582.             end\
  5583.         end\
  5584.         for y, row in ipairs(layer.text) do\
  5585.             if not image.text[y] then\
  5586.                 image.text[y] = {}\
  5587.             end\
  5588.             for x, pixel in ipairs(row) do\
  5589.                 if not image.text[y][x] or pixel ~= ' ' then\
  5590.                     image.text[y][x] = pixel\
  5591.                 end\
  5592.             end\
  5593.         end\
  5594.         for y, row in ipairs(layer.textcol) do\
  5595.             if not image.textcol[y] then\
  5596.                 image.textcol[y] = {}\
  5597.             end\
  5598.             for x, pixel in ipairs(row) do\
  5599.                 if not image.textcol[y][x] or layer.text[y][x] ~= ' ' then\
  5600.                     image.textcol[y][x] = pixel\
  5601.                 end\
  5602.             end\
  5603.         end\
  5604.     end\
  5605. \
  5606.     return image, width, height\
  5607. end\
  5608. \
  5609. local function getColourOf(hex)\
  5610.     if hex == ' ' then\
  5611.         return colours.transparent\
  5612.     end\
  5613.    local value = tonumber(hex, 16)\
  5614.    if not value then return nil end\
  5615.    value = math.pow(2,value)\
  5616.    return value\
  5617. end\
  5618. \
  5619. ReadNFP = function(self, lines)\
  5620.     local image = {}\
  5621.     local y = 1\
  5622.     for y, line in ipairs(lines) do\
  5623.         for x = 1, #line do\
  5624.             if not image[x] then\
  5625.                 image[x] = {}\
  5626.             end\
  5627.             image[x][y] = getColourOf(line:sub(x,x))\
  5628.         end\
  5629.         line = file.readLine()\
  5630.     end\
  5631.     file.close()\
  5632.     return image, #image, #image[1]\
  5633. end\
  5634. \
  5635. ReadNFT = function(self, lines)\
  5636.     local image = {\
  5637.         text = {},\
  5638.         textcol = {}\
  5639.     }\
  5640.     for num, sLine in ipairs(lines) do\
  5641.        table.insert(image, num, {})\
  5642.        table.insert(image.text, num, {})\
  5643.        table.insert(image.textcol, num, {})\
  5644.        local writeIndex = 1\
  5645.        local bgNext, fgNext = false, false\
  5646.        local currBG, currFG = nil,nil\
  5647.        for i=1,#sLine do\
  5648.                local nextChar = string.sub(sLine, i, i)\
  5649.                if nextChar:byte() == 30 then\
  5650.                        bgNext = true\
  5651.                elseif nextChar:byte() == 31 then\
  5652.                        fgNext = true\
  5653.                elseif bgNext then\
  5654.                        currBG = Drawing.GetColour(nextChar)\
  5655.                         if currBG == nil then\
  5656.                             currBG = colours.transparent\
  5657.                         end\
  5658.                        bgNext = false\
  5659.                elseif fgNext then\
  5660.                        currFG = Drawing.GetColour(nextChar)\
  5661.                         if currFG == nil or currFG == colours.transparent then\
  5662.                             currFG = colours.white\
  5663.                         end\
  5664.                        fgNext = false\
  5665.                else\
  5666.                        if nextChar ~= \" \" and currFG == nil then\
  5667.                                currFG = colours.white\
  5668.                        end\
  5669.                        image[num][writeIndex] = currBG\
  5670.                        image.textcol[num][writeIndex] = currFG\
  5671.                        image.text[num][writeIndex] = nextChar\
  5672.                        writeIndex = writeIndex + 1\
  5673.                end\
  5674.        end\
  5675.    end\
  5676.     return image, #image[1], #image\
  5677. end",["CenterView.lua"]="Inherit = 'View'\
  5678. \
  5679. OnUpdate = function(self, value)\
  5680.     if value == 'Children' or value == 'Width' then\
  5681.         local y = 1\
  5682.         for i, v in ipairs(self.Children) do\
  5683.             v.Y = y\
  5684.             y = y + v.Height\
  5685.             v.X = math.floor((self.Width - v.Width) / 2) + 1\
  5686.         end\
  5687.         self.Height = y - 1\
  5688.     end\
  5689. end",["DividerView.lua"]="Inherit = 'View'\
  5690. Char = nil\
  5691. \
  5692. OnDraw = function(self, x, y)\
  5693.     if self.BackgroundColour then\
  5694.         if self.Char then\
  5695.             Drawing.DrawArea (x, y, self.Width, self.Height, self.Char, self.TextColour, self.BackgroundColour)\
  5696.         else\
  5697.             Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  5698.         end\
  5699.     end\
  5700. end",["LinkView.lua"]="Inherit = 'View'\
  5701. Height = 2\
  5702. UnderlineColour = colours.blue\
  5703. UnderlineVisible = true\
  5704. \
  5705. OnLoad = function(self)\
  5706.     if self.Text and #self.Text > 0 then\
  5707.         self:AddObject({\
  5708.             Y = 1,\
  5709.             X = 1,\
  5710.             Width = self.Width,\
  5711.             Align = self.Align,\
  5712.             Type = \"Label\",\
  5713.             Text = self.Text,\
  5714.             TextColour = self.TextColour,\
  5715.             BackgroundColour = self.BackgroundColour\
  5716.         })\
  5717.     end\
  5718. end\
  5719. \
  5720. OnRecalculateStart = function(self)\
  5721.     self:RemoveObject('UnderlineLabel')\
  5722. end\
  5723. \
  5724. OnRecalculateEnd = function(self, currentY)\
  5725.     if self.UnderlineVisible then\
  5726.         local underline = ''\
  5727.         local len = self.Width\
  5728.         if self.Text then\
  5729.             len = #self.Text\
  5730.         end\
  5731. \
  5732.         for i = 1, len do\
  5733.             underline = underline .. '-'\
  5734.         end\
  5735.         local col = self.UnderlineColour\
  5736.         if self.UnderlineColour == nil then\
  5737.             col = self.TextColour\
  5738.         end\
  5739. \
  5740.         local ul = self:AddObject({\
  5741.             Y = currentY,\
  5742.             X = 1,\
  5743.             Width = self.Width,\
  5744.             Align = self.Align,\
  5745.             Type = \"Label\",\
  5746.             Name = \"UnderlineLabel\",\
  5747.             Text = underline,\
  5748.             TextColour = col,\
  5749.             BackgroundColour = self.BackgroundColour\
  5750.         })  \
  5751.         return currentY + 1\
  5752.     else\
  5753.         return currentY\
  5754.     end\
  5755. end\
  5756. \
  5757. OnClick = function(self)\
  5758.     self.Bedrock:GetObject('WebView'):GoToURL(self.URL)\
  5759. end",["SelectView.lua"]="Inherit = 'Button'\
  5760. MenuItems = nil\
  5761. Children = {}\
  5762. Selected = nil\
  5763. \
  5764. OnUpdate = function(self, value)\
  5765.     if value == 'Height' and self.Height ~= 1 then\
  5766.         self.Height = 1\
  5767.     end\
  5768. end\
  5769. \
  5770. Select = function(self, index)\
  5771.     if self.MenuItems[index] then\
  5772.         local text = self.MenuItems[index].Text\
  5773.         for i = 1, self.Width - 3 - #text do\
  5774.             text = text .. ' '\
  5775.         end\
  5776.         text = text .. 'V'\
  5777.         self.Text = text\
  5778.         self.Selected = index\
  5779.     end\
  5780. end\
  5781. \
  5782. OnInitialise = function(self)\
  5783.     self:ClearMenuItems()\
  5784. end\
  5785. \
  5786. ClearMenuItems = function(self)\
  5787.     self.MenuItems = {}\
  5788. end\
  5789. \
  5790. AddMenuItem = function(self, item)\
  5791.     table.insert(self.MenuItems, item)\
  5792.     if not self.Selected then\
  5793.         if #self.MenuItems ~= 0 then\
  5794.             self:Select(1)\
  5795.         end\
  5796.     end\
  5797. end\
  5798. \
  5799. OnClick = function(self, event, side, x, y)\
  5800.     if self:ToggleMenu({\
  5801.         Type = \"Menu\",\
  5802.         HideTop = true,\
  5803.         Children = self.MenuItems\
  5804.     }, x, 1) then\
  5805.         for i, child in ipairs(self.Bedrock.Menu.Children) do\
  5806.             child.OnClick = function(_self, event, side, x, y)\
  5807.                 self:Select(i)\
  5808.             end\
  5809.         end\
  5810.     end\
  5811. end",["WebView.lua"]="Inherit = 'ScrollView'\
  5812. URL = nil\
  5813. FakeURL = nil\
  5814. LoadingURL = nil\
  5815. Tree = nil\
  5816. BackgroundColour = colours.white\
  5817. ScriptEnvironment = nil\
  5818. Timers = nil\
  5819. Download = nil\
  5820. \
  5821. -- TODO: strip this down to remove positioning stuff\
  5822. UpdateLayout = function(self)\
  5823.     self:RemoveAllObjects()\
  5824.     self.BackgroundColour = colours.white\
  5825.     local body = self.Tree:GetElement('body')\
  5826. \
  5827.     --TODO: check that body exists, if not redirect to an error page\
  5828. \
  5829.     if body.BackgroundColour then\
  5830.         self.BackgroundColour = body.BackgroundColour\
  5831.     end\
  5832. \
  5833.     local node = true\
  5834.     node = function(children, parentObject)\
  5835.         local currentY = 1\
  5836.         for i, v in ipairs(children) do\
  5837.             local object = v:CreateObject(parentObject, currentY)\
  5838.             if object then\
  5839.                 v.Object = object\
  5840.                 if v.Children and #v.Children > 0 and object.Children then\
  5841.                     local usedY = node(v.Children, object)\
  5842.                     if not v.Attributes.height then\
  5843.                         object.Height = usedY\
  5844.                     end\
  5845.                     object:OnUpdate('Children')\
  5846.                 end\
  5847.                 -- if not object.Height then\
  5848.                 --  for k, v in pairs(object) do\
  5849.                 --      error(v)\
  5850.                 --  end \
  5851.                 --  error('Nope')\
  5852.                 -- end\
  5853.                 currentY = currentY + object.Height\
  5854.             end\
  5855.         end\
  5856.         return currentY - 1\
  5857.     end\
  5858.     node(body.Children, self)\
  5859.     \
  5860.     self:RepositionLayout()\
  5861. \
  5862.     local head = self.Tree:GetElement('head')\
  5863.     if head then\
  5864.         for i, child in ipairs(head.Children) do\
  5865.             if child.Tag == 'script' then\
  5866.                 child:InsertScript(self)\
  5867.             end\
  5868.         end\
  5869.     end\
  5870. end\
  5871. \
  5872. RepositionLayout = function(self)\
  5873.     local node = true\
  5874.     node = function(children, isFloat, parent)\
  5875.         if parent.OnRecalculateStart then\
  5876.             parent:OnRecalculateStart()\
  5877.         end\
  5878. \
  5879.         local currentY = 1\
  5880.         local currentX = 1\
  5881.         local tallestChild = 1\
  5882.         for i, child in ipairs(children) do\
  5883.             if child.Type ~= 'ScrollBar' then\
  5884.                 if isFloat then\
  5885.                     if currentX ~= 1 and parent.Width - currentX + 1 < child.Width then\
  5886.                         currentX = 1\
  5887.                         currentY = currentY + tallestChild\
  5888.                         tallestChild = 1\
  5889.                     end\
  5890. \
  5891.                     if parent.Align == \"Left\" then\
  5892.                         child.X = currentX\
  5893.                     elseif parent.Align == \"Right\" then\
  5894.                         child.X = parent.Width - currentX - child.Width + 2\
  5895.                     end\
  5896.                 end\
  5897.                 child.Y = currentY\
  5898. \
  5899.                 if child.Children and #child.Children > 0 then\
  5900.                     local usedY = node(child.Children, child.IsFloat, child)\
  5901.                     child:OnUpdate('Children')\
  5902.                     if not child.Element.Attributes.height then\
  5903.                         child.Height = usedY\
  5904.                     end\
  5905.                 end\
  5906. \
  5907.                 if child.Height > tallestChild then\
  5908.                     tallestChild = child.Height\
  5909.                 end\
  5910. \
  5911.                 if isFloat then\
  5912.                     currentX = currentX + child.Width\
  5913.                 else\
  5914.                     currentY = currentY + child.Height\
  5915.                 end\
  5916.             end\
  5917.         end\
  5918.         if isFloat then\
  5919.             currentY = currentY + tallestChild\
  5920.         end\
  5921.         if parent.OnRecalculateEnd then\
  5922.             currentY = parent:OnRecalculateEnd(currentY)\
  5923.         end\
  5924.         return currentY - 1\
  5925.     end\
  5926.     node(self.Children, self.IsFloat, self)\
  5927. \
  5928.     self:UpdateScroll()\
  5929. end\
  5930. \
  5931. GoToURL = function(self, url, nonVerbose, noHistory, post)\
  5932.     self.BackgroundColour = colours.white\
  5933.     self:RemoveAllObjects()\
  5934.     if self.OnPageLoadStart and not nonVerbose then\
  5935.         self:OnPageLoadStart(url, noHistory)\
  5936.     end\
  5937.     self.LoadingURL = url\
  5938.     self.FakeURL = url\
  5939.     self:InitialiseScriptEnvironment()\
  5940. \
  5941.     if not http and url:find('http://') then\
  5942.         if self.OnPageLoadFailed then\
  5943.             self:OnPageLoadFailed(url, 4, noHistory)\
  5944.         end\
  5945.         return\
  5946.     end\
  5947. \
  5948.     -- error(fs.getName(url))\
  5949.     local parts = urlComponents(url)\
  5950.     -- if url:sub(#url) ~= '/' and url:find('?') then\
  5951.     --  fileName = fs.getName(url:sub(1, url:find('?') - 1))\
  5952.     -- else\
  5953.     --  fileName = fs.getName(url)\
  5954.     -- end\
  5955. \
  5956.     local fileName = parts.filename\
  5957.     local extension\
  5958.     if fileName == '' or url:sub(#url) == '/' then\
  5959.         extension = true\
  5960.     else\
  5961.         extension = fileName:match('%.[0-9a-z%?%%]+$')\
  5962.         if extension then\
  5963.             extension = extension:sub(2)\
  5964.         end\
  5965.     end\
  5966. \
  5967.     if not url:find('quest://download.ccml') and not url:find('quest://downloaded.ccml') then\
  5968.         self.Download = nil\
  5969.     else\
  5970.         extension = true\
  5971.     end\
  5972. \
  5973.     -- TODO: 404s are counted as downloads\
  5974. \
  5975.     if not extension or (extension ~= true and extension ~= '' and extension ~= 'ccml' and extension ~= 'html' and extension ~= 'php' and extension ~= 'asp' and extension ~= 'aspx' and extension ~= 'jsp' and extension ~= 'qst' and extension ~= 'com' and extension ~= 'me' and extension ~= 'net' and extension ~= 'info' and extension ~= 'au' and extension ~= 'nz') then\
  5976.         local downloadsFolder = '/Downloads/'\
  5977.         if OneOS then\
  5978.             downloadsFolder = '/Desktop/Documents/Downloads/'\
  5979.         end\
  5980.         if not fs.exists(downloadsFolder) then\
  5981.             fs.makeDir(downloadsFolder)\
  5982.         end\
  5983. \
  5984.         local downloadPath = downloadsFolder..fileName\
  5985.         local i = 1\
  5986.         while fs.exists(downloadPath) do\
  5987.             i = i + 1\
  5988.             downloadPath = downloadsFolder..fileName .. ' (' .. i .. ')'\
  5989.         end\
  5990. \
  5991.         self.Download = url\
  5992.         fetchHTTPAsync(url, function(ok, event, response)\
  5993.             if self.Download == url then\
  5994.                 self.Download = nil\
  5995.                 if ok then\
  5996.                     if response.getResponseCode then\
  5997.                         local code = response.getResponseCode()\
  5998.                         if code ~= 200 then\
  5999.                             self:OnPageLoadFailed(url, 6, noHistory)\
  6000.                             response.close()\
  6001.                             return\
  6002.                         end\
  6003.                     end\
  6004.                     local f = fs.open(downloadPath, 'w')\
  6005.                     if f then\
  6006.                         f.write(response.readAll())\
  6007.                         f.close()\
  6008.                         self:GoToURL('quest://downloaded.ccml?path='..textutils.urlEncode(downloadPath), true, true)\
  6009.                     else\
  6010.                         self:OnPageLoadFailed(url, 6, noHistory)\
  6011.                     end\
  6012.                     response.close()\
  6013.                 else\
  6014.                     self:OnPageLoadFailed(url, 6, noHistory)\
  6015.                 end\
  6016.             end\
  6017.         end)\
  6018. \
  6019.         self:GoToURL('quest://download.ccml?path='..textutils.urlEncode(downloadPath), true, true)\
  6020.         self:OnPageLoadEnd(url, noHistory)\
  6021.     else\
  6022.         fetchHTTPAsync(url, function(ok, event, response)\
  6023.             self.LoadingURL = nil\
  6024.             if ok then\
  6025.                 if response.getResponseCode then\
  6026.                     local code = response.getResponseCode()\
  6027.                     if code ~= 200 then\
  6028.                         if self.OnPageLoadFailed then\
  6029.                             self:OnPageLoadFailed(url, code, noHistory)\
  6030.                         end\
  6031.                         response.close()\
  6032.                         return\
  6033.                     end\
  6034.                 end\
  6035. \
  6036.                 self.Tree, err = ElementTree:Initialise(response.readAll())\
  6037.                 response.close()\
  6038.                 if not err then\
  6039.                     self.URL = url\
  6040.                     self:UpdateLayout()\
  6041.                     if self.OnPageLoadEnd and not nonVerbose then\
  6042.                         self:OnPageLoadEnd(url, noHistory)\
  6043.                     end\
  6044.                 else\
  6045.                     if self.OnPageLoadFailed then\
  6046.                         self:OnPageLoadFailed(url, err, noHistory)\
  6047.                     end\
  6048.                 end\
  6049.             elseif self.OnPageLoadFailed and not nonVerbose then\
  6050.                 self:OnPageLoadFailed(url, event, noHistory)\
  6051.             end\
  6052.         end, post)\
  6053.     end\
  6054. end\
  6055. \
  6056. Stop = function(self)\
  6057.     cancelHTTPAsync(self.LoadingURL)\
  6058.     if self.OnPageLoadFailed then\
  6059.         self:OnPageLoadFailed(url, Errors.TimeoutStop)\
  6060.     end\
  6061. end\
  6062. \
  6063. ResolveElements = function(self, selector)\
  6064.     local elements = {}\
  6065.     local node = true\
  6066.     local isClass = false\
  6067.     if selector:sub(1,1) == '.' then\
  6068.         isClass = true\
  6069.     end\
  6070. \
  6071.     node = function(tbl)\
  6072.         for i,v in ipairs(tbl) do\
  6073.             if type(v) == 'table' and v.Tag then\
  6074.                 if not isClass and v.Tag:lower() == selector:lower() then\
  6075.                     table.insert(elements, v.Object)\
  6076.                 elseif isClass and v.Attributes.class and v.Attributes.class:lower() == selector:lower():sub(2) then\
  6077.                     table.insert(elements, v.Object)\
  6078.                 end\
  6079.                 if v.Children then\
  6080.                     local r = node(v.Children)\
  6081.                 end\
  6082.             end\
  6083.         end\
  6084.     end\
  6085.     node(self.Tree.Tree)\
  6086.     return elements\
  6087. end\
  6088. \
  6089. InitialiseScriptEnvironment = function(self)\
  6090.     lQuery.webView = self\
  6091.     if self.Timers then\
  6092.         for i, timer in ipairs(self.Timers) do\
  6093.             -- error('clear '..timer)\
  6094.             self.Bedrock.Timers[timer] = nil\
  6095.         end\
  6096.     end\
  6097.     self.Timers = {}\
  6098. \
  6099.     local getValues = urlComponents(self.LoadingURL).get\
  6100. \
  6101.     self.ScriptEnvironment = {\
  6102.         keys = keys,\
  6103.         printError = printError, -- maybe don't have this\
  6104.         assert = assert,\
  6105.         getfenv = getfenv,\
  6106.         bit = bit,\
  6107.         rawset = rawset,\
  6108.         tonumber = tonumber,\
  6109.         loadstring = loadstring,\
  6110.         error = error, -- maybe don't have this\
  6111.         tostring = tostring,\
  6112.         type = type,\
  6113.         coroutine = coroutine,\
  6114.         next = next,\
  6115.         unpack = unpack,\
  6116.         colours = colours,\
  6117.         pcall = pcall,\
  6118.         math = math,\
  6119.         pairs = pairs,\
  6120.         rawget = rawget,\
  6121.         _G = _G,\
  6122.         __inext = __inext,\
  6123.         read = read,\
  6124.         ipairs = ipairs,\
  6125.         xpcall = xpcall,\
  6126.         rawequal = rawequal,\
  6127.         setfenv = setfenv,\
  6128.         http = http, --create an ajax thing to replace this\
  6129.         string = string,\
  6130.         setmetatable = setmetatable,\
  6131.         getmetatable = getmetatable,\
  6132.         table = table,\
  6133.         parallel = parallel, -- this mightn't work properly\
  6134.         textutils = textutils,\
  6135.         colors = colors,\
  6136.         vector = vector,\
  6137.         select = select,\
  6138.         os = {\
  6139.             version = os.version,\
  6140.             getComputerID = os.getComputerID,\
  6141.             getComputerLabel = os.getComputerLabel,\
  6142.             clock = os.clock,\
  6143.             time = os.time,\
  6144.             day = os.day,\
  6145.         },\
  6146.         lQuery = lQuery.fn,\
  6147.         l = lQuery.fn,\
  6148.         setTimeout = function(func, delay)\
  6149.             if type(func) == 'function' and type(delay) == 'number' then\
  6150.                 local t = self.Bedrock:StartTimer(func, delay)\
  6151.                 table.insert(self.Timers, t)\
  6152.                 return t\
  6153.             end\
  6154.         end,\
  6155.         setInterval = function(func, interval)\
  6156.             if type(func) == 'function' and type(interval) == 'number' then\
  6157.                 local t = self.Bedrock:StartRepeatingTimer(function(timer)\
  6158.                     table.insert(self.Timers, timer)\
  6159.                     func()\
  6160.                 end, interval)\
  6161.                 table.insert(self.Timers, t)\
  6162.                 return t\
  6163.             end\
  6164.         end,\
  6165.         clearTimeout = function(timer)\
  6166.             self.Bedrock.Timers[timer] = nil\
  6167.         end,\
  6168.         clearInterval = function(timer)\
  6169.             self.Bedrock.Timers[timer] = nil\
  6170.         end,\
  6171.         window = {\
  6172.             location = self.URL,\
  6173.             realLocation = self.LoadingURL,\
  6174.             get = getValues,\
  6175.             version = QuestVersion\
  6176.         }\
  6177.     }\
  6178. end\
  6179. \
  6180. LoadScript = function(self, script)\
  6181.     local fn, err = loadstring(script, 'Script Tag Error: '..self.URL)\
  6182.     if fn then\
  6183.         setfenv(fn, self.ScriptEnvironment)\
  6184.         fn()\
  6185.     else\
  6186.         local start = err:find(': ')\
  6187.         self:OnPageLoadFailed(url, err:sub(start + 2), noHistory)\
  6188.     end\
  6189. end\
  6190. \
  6191. RemoveElement = function(self, elem)\
  6192.     local elements = {}\
  6193.     local node = true\
  6194.     node = function(tbl)\
  6195.         for i,v in ipairs(tbl) do\
  6196.             if type(v) == 'table' then\
  6197.                 if v == elem.Element then\
  6198.                     elem.Parent:RemoveObject(elem)\
  6199.                     v = nil\
  6200.                     return\
  6201.                 end\
  6202.                 if v.Children then\
  6203.                     local r = node(v.Children)\
  6204.                 end\
  6205.             end\
  6206.         end\
  6207.     end\
  6208.     node(self.Tree.Tree)\
  6209. end",["FloatView.lua"]="Inherit = 'View'\
  6210. IsFloat = true\
  6211. Align = \"Left\"",["FormView.lua"]="Inherit = 'View'\
  6212. \
  6213. OnTab = function(self)\
  6214.     local active = self.Bedrock:GetActiveObject()\
  6215.     local selected = nil\
  6216.     local selectNext = false\
  6217.     local function node(tree)\
  6218.         for i, v in ipairs(tree) do\
  6219.             if selectNext then\
  6220.                 if v.Type == 'TextBox' or v.Type == 'SecureTextBox' then\
  6221.                     selected = v\
  6222.                     return\
  6223.                 end\
  6224.             elseif v == active then\
  6225.                 selectNext = true\
  6226.             end\
  6227.             if v.Children then\
  6228.                 node(v.Children)\
  6229.             end\
  6230.         end\
  6231.     end\
  6232.     node(self.Children)\
  6233. \
  6234.     if selected then\
  6235.         self.Bedrock:SetActiveObject(selected)\
  6236.     end\
  6237. end",},["Views"]={["main.view"]="{\
  6238.  [\"Children\"]={\
  6239.    [1]={\
  6240.      [\"Y\"]=1,\
  6241.      [\"X\"]=1,\
  6242.      [\"Name\"]=\"Toolbar\",\
  6243.      [\"Type\"]=\"View\",\
  6244.      [\"InheritView\"]=\"toolbar\"\
  6245.    },\
  6246.    [2]={\
  6247.      [\"Y\"]=4,\
  6248.      [\"X\"]=1,\
  6249.      [\"Height\"]=\"100%,-3\",\
  6250.      [\"Width\"]=\"100%\",\
  6251.      [\"Name\"]=\"WebView\",\
  6252.      [\"Type\"]=\"WebView\"\
  6253.    },\
  6254.    [3]={\
  6255.      [\"Y\"]=1,\
  6256.      [\"X\"]=1,\
  6257.      [\"Height\"]=1,\
  6258.      [\"Width\"]=\"100%\",\
  6259.      [\"Name\"]=\"PageTitleLabel\",\
  6260.      [\"Type\"]=\"Label\",\
  6261.      [\"Align\"]=\"Center\",\
  6262.      [\"TextColour\"]=128,\
  6263.    },\
  6264.  },\
  6265.  [\"BackgroundColour\"]=1,\
  6266.  [\"ToolBarColour\"]=256,\
  6267.  [\"ToolBarTextColour\"]=1\
  6268. }",["optionsmenu.view"]="{\
  6269.  [\"Type\"]=\"Menu\",\
  6270.  [\"Owner\"]=\"OptionsButton\",\
  6271.  [\"Children\"]={\
  6272.    [1]={\
  6273.      [\"Name\"]=\"StopMenuItem\",\
  6274.      [\"Type\"]=\"Button\",\
  6275.      [\"Text\"]=\"Stop\"\
  6276.    },\
  6277.    [2]={\
  6278.      [\"Name\"]=\"ReloadMenuItem\",\
  6279.      [\"Type\"]=\"Button\",\
  6280.      [\"Text\"]=\"Reload\"\
  6281.    },\
  6282.    [3]={\
  6283.      [\"Name\"]=\"GoHomeMenuItem\",\
  6284.      [\"Type\"]=\"Button\",\
  6285.      [\"Text\"]=\"Go Home\"\
  6286.    },\
  6287.    [4]={\
  6288.      [\"Name\"]=\"SetHomeMenuItem\",\
  6289.      [\"Type\"]=\"Button\",\
  6290.      [\"Text\"]=\"Set Home\"\
  6291.    },\
  6292.    [5]={\
  6293.      [\"Name\"]=\"Separator\",\
  6294.      [\"Type\"]=\"Separator\"\
  6295.    },\
  6296.    [6]={\
  6297.      [\"Name\"]=\"QuitMenuItem\",\
  6298.      [\"Type\"]=\"Button\",\
  6299.      [\"Text\"]=\"Quit\"\
  6300.    }\
  6301.  },\
  6302. }",["toolbar.view"]="{\
  6303.  [\"Width\"]=\"100%\",\
  6304.  [\"Height\"]=3,\
  6305.  [\"Type\"]=\"View\",\
  6306.  [\"BackgroundColour\"]=256,\
  6307.  [\"Children\"]={\
  6308.    [1]={\
  6309.      [\"Y\"]=2,\
  6310.      [\"X\"]=2,\
  6311.      [\"Name\"]=\"BackButton\",\
  6312.      [\"Type\"]=\"Button\",\
  6313.      [\"Enabled\"]=false,\
  6314.      [\"TextColour\"]=128,\
  6315.      [\"Text\"]=\"<\",\
  6316.      [\"BackgroundColour\"]=1\
  6317.    },\
  6318.    [2]={\
  6319.      [\"Y\"]=2,\
  6320.      [\"X\"]=6,\
  6321.      [\"Name\"]=\"ForwardButton\",\
  6322.      [\"Type\"]=\"Button\",\
  6323.      [\"Enabled\"]=false,\
  6324.      [\"TextColour\"]=128,\
  6325.      [\"Text\"]=\">\",\
  6326.      [\"BackgroundColour\"]=1\
  6327.    },\
  6328.    [3]={\
  6329.      [\"Y\"]=2,\
  6330.      [\"X\"]=10,\
  6331.      [\"Width\"]=\"100%,-14\",\
  6332.      [\"Type\"]=\"View\",\
  6333.      [\"BackgroundColour\"]=1\
  6334.    },\
  6335.    [4]={\
  6336.      [\"Y\"]=2,\
  6337.      [\"X\"]=10,\
  6338.      [\"Width\"]=\"100%,-14\",\
  6339.      [\"Name\"]=\"URLTextBox\",\
  6340.      [\"Type\"]=\"TextBox\",\
  6341.      [\"TextColour\"]=128,\
  6342.      [\"Placeholder\"]=\"Website URL...\",\
  6343.      [\"PlaceholderTextColour\"]=256,\
  6344.      [\"BackgroundColour\"]=0,\
  6345.      [\"SelectOnClick\"]=true\
  6346.    },\
  6347.    [5]={\
  6348.      [\"Y\"]=2,\
  6349.      [\"X\"]=10,\
  6350.      [\"Width\"]=\"100%,-14\",\
  6351.      [\"Name\"]=\"LoadingLabel\",\
  6352.      [\"Type\"]=\"Label\",\
  6353.      [\"TextColour\"]=256,\
  6354.      [\"Text\"]=\"Loading...\",\
  6355.      [\"BackgroundColour\"]=1,\
  6356.      [\"Align\"]=\"Center\",\
  6357.      [\"Visible\"]=false\
  6358.    },\
  6359.    [6]={\
  6360.      [\"Y\"]=2,\
  6361.      [\"X\"]=\"100%,-3\",\
  6362.      [\"Name\"]=\"OptionsButton\",\
  6363.      [\"Type\"]=\"Button\",\
  6364.      [\"Text\"]=\"V\",\
  6365.      [\"TextColour\"]=128,\
  6366.      [\"BackgroundColour\"]=1\
  6367.    },\
  6368.  },\
  6369. }",},}
  6370.  
  6371. local function run(tArgs)
  6372.  
  6373.   local fnFile, err = loadstring(files['startup'], 'startup')
  6374.   if err then
  6375.     error(err)
  6376.   end
  6377.  
  6378.   local function split(str, pat)
  6379.      local t = {}
  6380.      local fpat = "(.-)" .. pat
  6381.      local last_end = 1
  6382.      local s, e, cap = str:find(fpat, 1)
  6383.      while s do
  6384.         if s ~= 1 or cap ~= "" then
  6385.      table.insert(t,cap)
  6386.         end
  6387.         last_end = e+1
  6388.         s, e, cap = str:find(fpat, last_end)
  6389.      end
  6390.      if last_end <= #str then
  6391.         cap = str:sub(last_end)
  6392.         table.insert(t, cap)
  6393.      end
  6394.      return t
  6395.   end
  6396.  
  6397.   local function resolveTreeForPath(path, single)
  6398.     local _files = files
  6399.     local parts = split(path, '/')
  6400.     if parts then
  6401.       for i, v in ipairs(parts) do
  6402.         if #v > 0 then
  6403.           if _files[v] then
  6404.             _files = _files[v]
  6405.           else
  6406.             _files = nil
  6407.             break
  6408.           end
  6409.         end
  6410.       end
  6411.     elseif #path > 0 and path ~= '/' then
  6412.       _files = _files[path]
  6413.     end
  6414.     if not single or type(_files) == 'string' then
  6415.       return _files
  6416.     end
  6417.   end
  6418.  
  6419.   local oldFs = fs
  6420.   local env
  6421.   env = {
  6422.     fs = {
  6423.       list = function(path)
  6424.               local list = {}
  6425.               if fs.exists(path) then
  6426.             list = fs.list(path)
  6427.               end
  6428.         for k, v in pairs(resolveTreeForPath(path)) do
  6429.           if not fs.exists(path .. '/' ..k) then
  6430.             table.insert(list, k)
  6431.           end
  6432.         end
  6433.         return list
  6434.       end,
  6435.  
  6436.       exists = function(path)
  6437.         if fs.exists(path) then
  6438.           return true
  6439.         elseif resolveTreeForPath(path) then
  6440.           return true
  6441.         else
  6442.           return false
  6443.         end
  6444.       end,
  6445.  
  6446.       isDir = function(path)
  6447.         if fs.isDir(path) then
  6448.           return true
  6449.         else
  6450.           local tree = resolveTreeForPath(path)
  6451.           if tree and type(tree) == 'table' then
  6452.             return true
  6453.           else
  6454.             return false
  6455.           end
  6456.         end
  6457.       end,
  6458.  
  6459.       isReadOnly = function(path)
  6460.         if not fs.isReadOnly(path) then
  6461.           return false
  6462.         else
  6463.           return true
  6464.         end
  6465.       end,
  6466.  
  6467.       getName = fs.getName,
  6468.  
  6469.       getSize = fs.getSize,
  6470.  
  6471.       getFreespace = fs.getFreespace,
  6472.  
  6473.       makeDir = fs.makeDir,
  6474.  
  6475.       move = fs.move,
  6476.  
  6477.       copy = fs.copy,
  6478.  
  6479.       delete = fs.delete,
  6480.  
  6481.       combine = fs.combine,
  6482.  
  6483.       open = function(path, mode)
  6484.         if fs.exists(path) then
  6485.           return fs.open(path, mode)
  6486.         elseif type(resolveTreeForPath(path)) == 'string' then
  6487.           local handle = {close = function()end}
  6488.           if mode == 'r' then
  6489.             local content = resolveTreeForPath(path)
  6490.             handle.readAll = function()
  6491.               return content
  6492.             end
  6493.  
  6494.             local line = 1
  6495.             local lines = split(content, '\n')
  6496.             handle.readLine = function()
  6497.               if line > #lines then
  6498.                 return nil
  6499.               else
  6500.                 return lines[line]
  6501.               end
  6502.               line = line + 1
  6503.             end
  6504.                       return handle
  6505.           else
  6506.             error('Cannot write to read-only file (compilr archived).')
  6507.           end
  6508.         else
  6509.           return fs.open(path, mode)
  6510.         end
  6511.       end
  6512.     },
  6513.  
  6514.     loadfile = function( _sFile )
  6515.         local file = env.fs.open( _sFile, "r" )
  6516.         if file then
  6517.             local func, err = loadstring( file.readAll(), fs.getName( _sFile ) )
  6518.             file.close()
  6519.             return func, err
  6520.         end
  6521.         return nil, "File not found: ".._sFile
  6522.     end,
  6523.  
  6524.     dofile = function( _sFile )
  6525.         local fnFile, e = env.loadfile( _sFile )
  6526.         if fnFile then
  6527.             setfenv( fnFile, getfenv(2) )
  6528.             return fnFile()
  6529.         else
  6530.             error( e, 2 )
  6531.         end
  6532.     end
  6533.   }
  6534.  
  6535.   setmetatable( env, { __index = _G } )
  6536.  
  6537.   local tAPIsLoading = {}
  6538.   env.os.loadAPI = function( _sPath )
  6539.       local sName = fs.getName( _sPath )
  6540.       if tAPIsLoading[sName] == true then
  6541.           printError( "API "..sName.." is already being loaded" )
  6542.           return false
  6543.       end
  6544.       tAPIsLoading[sName] = true
  6545.          
  6546.       local tEnv = {}
  6547.       setmetatable( tEnv, { __index = env } )
  6548.       local fnAPI, err = env.loadfile( _sPath )
  6549.       if fnAPI then
  6550.           setfenv( fnAPI, tEnv )
  6551.           fnAPI()
  6552.       else
  6553.           printError( err )
  6554.           tAPIsLoading[sName] = nil
  6555.           return false
  6556.       end
  6557.      
  6558.       local tAPI = {}
  6559.       for k,v in pairs( tEnv ) do
  6560.           tAPI[k] =  v
  6561.       end
  6562.      
  6563.       env[sName] = tAPI    
  6564.       tAPIsLoading[sName] = nil
  6565.       return true
  6566.   end
  6567.  
  6568.   env.shell = shell
  6569.  
  6570.   setfenv( fnFile, env )
  6571.   fnFile(unpack(tArgs))
  6572. end
  6573.  
  6574. local function extract()
  6575.     local function node(path, tree)
  6576.         if type(tree) == 'table' then
  6577.             fs.makeDir(path)
  6578.             for k, v in pairs(tree) do
  6579.                 node(path .. '/' .. k, v)
  6580.             end
  6581.         else
  6582.             local f = fs.open(path, 'w')
  6583.             if f then
  6584.                 f.write(tree)
  6585.                 f.close()
  6586.             end
  6587.         end
  6588.     end
  6589.     node('', files)
  6590. end
  6591.  
  6592. local tArgs = {...}
  6593. if #tArgs == 1 and tArgs[1] == '--extract' then
  6594.   extract()
  6595. else
  6596.   run(tArgs)
  6597. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement