Advertisement
Oeed

Quest

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