local pkg = {["var"]={["linox.ver"]="Linox v0.0.1",["mpc-get-repo.rpo"]="I staple tape worms on my penis!@#&So the flesh worm will drink brainjuice from your fetus!@#&(4X)!@#&!@#&Feel the blood gushing from your anus!@#&(2X)!@#&!@#&Feel the blood gushing from your anus!@#&(4X)!@#&!@#&Tape worms on my fucking penis!!@#&Penis!!@#&Tape worms!!@#&Tape worms on my penis!!@#&Tape worms on my penis!@#&Tape worms on my peniiiiiii....!",},["etc"]={["linoxim"]=" !@#& 55555 !@#& 54445 !@#& 54e45 !@#& 54e45 555 !@#& 54e45 !@#& 54e45555555 555 55555555 55555 555 555 !@#& 54e44444445 555 55555555 55555 555 555 !@#& 54eeeeeee45 555 555 555 55 55 5555 !@#& 54444444445 555 555 555 55555 555 555 !@#& 55555555555 555 555 555 55555 555 555 !@#& !@#& !@#& !@#& !@#& !@#& !@#& ",["linoxm"]=" !@#& 55555 !@#& 54445 !@#& 54e45 !@#& 54e45 555 !@#& 54e45 !@#& 54e45555555 555 55555555 55555 555 555 !@#& 54e44444445 555 55555555 55555 555 555 !@#& 54eeeeeee45 555 555 555 55 55 5555 !@#& 54444444445 555 555 555 55555 555 555 !@#& 55555555555 555 555 555 55555 555 555 !@#& !@#& eee eee e e !@#& e e e e e e !@#& e e e e e e e !@#& e e e eeeee e eee !@#& !@#& ",["bg"]=" !@#& 55555 !@#& 54445 !@#& 54e45 !@#& 54e45 555 !@#& 54e45 !@#& 54e45555555 555 55555555 55555 555 555 !@#& 54e44444445 555 55555555 55555 555 555 !@#& 54eeeeeee45 555 555 555 55 55 55555 !@#& 54444444445 555 555 555 55555 555 555 !@#& 55555555555 555 555 555 55555 555 555 !@#& !@#& !@#& !@#& !@#& !@#& !@#& ",["mfb"]={},},["startup"]="if not os.getComputerLabel() then!@#& os.setComputerLabel(\"SEXY_BEAST\")!@#&end!@#&cua = fs.open(\"/lib/usr/users\", \"r\")!@#&if cua.readAll() == \"\" then!@#& cua.close()!@#& sua = fs.open(\"/lib/usr/users\", \"w\")!@#& sua.writeLine('{[\"admin\"]=\"d74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1\",}')!@#& sua.close()!@#&else!@#& cua.close()!@#&end!@#&motd = {\"Coded by __Hithere\", \"http://zudohackz.koding.com\", \"ALIENS\", \"[xx]* -\", \"You can only hack my penis on singleplayer!\", \"Internal stack failure, system halted?\", \"Kernel Panic!\", \"Warning: Logging in will make you a nerd\", math.random() .. \" happy customers!\"}!@#&if not term.isColor() then!@#&os.reboot()!@#&end!@#&w, h = term.getSize()!@#&function printc(str, ln)!@#& term.setCursorPos(w/2-#str/2, ln)!@#& print(str)!@#&end!@#&os.loadAPI(\"/lib/load\")!@#&os.loadAPI(\"/lib/linox\")!@#&logo = {\"c c ccc cccc c c\",!@#& \"c c c c c c c \",!@#& \"c c c c c c c \",!@#& \"c c c c c c c c \",!@#& \"ccc c c c cccc c c\"}!@#&local bar = load.init( load.STANDARD, logo, 5, w-4, 17, colors.lime, \"Splitting Uranus Atoms\", \"\", \"Starting \" .. linox.getVerNo() )!@#&help.setPath(\"/rom/help/;/lib/help\")!@#&os.loadAPI(\"/lib/p2\")!@#&function mainBoot()!@#&sleep(1)!@#&bar:triggerUpdate(\"8=========D~~~~~~~\")!@#&sleep(1)!@#&-- Begin VAR setup: change if required!@#&path = \"/bin\"!@#&-- End VAR setup!@#&os.loadAPI(\"/lib/sysconf\")!@#&shell.run(\"/bin/boot/loadapis\")!@#&sleep(1)!@#&bar:triggerUpdate(\"Initializing Anal Capacitor\")!@#&shell.setPath(shell.path() .. \":\" .. path)!@#&if http then!@#& if update.ping() then!@#& udver = update.getVerNo()!@#& if linox.getVerNo() == udver then!@#& spd.setData(\"updates\",nil)!@#& else!@#& spd.setData(\"updates\",udver)!@#& end!@#& else!@#& spd.setData(\"updates\",nil)!@#& end!@#&else!@#&end!@#&!@#&terminate.disable()!@#&sleep(1)!@#&bar:triggerUpdate(\"Smoking detached big black cocks\")!@#&fail = true!@#&sleep(1)!@#&bar:triggerUpdate(\"Raping the future\")!@#&sleep(0.5)!@#&function loginScreen()!@#&term.setBackgroundColor(colors.lightGray)!@#&term.setTextColor(colors.black)!@#&term.clear()!@#&term.setCursorPos(1,1)!@#&quit = \"Stick finger in asshole to shutdown\"!@#&term.setBackgroundColor(colors.pink)!@#&write(string.rep(\" \", w))!@#&term.setCursorPos(1,1)!@#&write(linox.getVerNo())!@#&term.setCursorPos(w-#quit, 1)!@#&write(quit)!@#&term.setTextColor(colors.white)!@#&term.setCursorPos(10, h/2-1)!@#&write(\" \")!@#&term.setCursorPos(10, h/2+1)!@#&write(\" \")!@#&term.setBackgroundColor(colors.brown)!@#&term.setCursorPos(1, h/2-1)!@#&write(\"Username: \")!@#&term.setCursorPos(1, h/2+1)!@#&write(\"Password: \")!@#&term.setCursorPos(w-15, h/2-1)!@#&write(\"ZudoHacks SUCKS\")!@#&printc(motd[math.random(1,#motd)], h-1)!@#&term.setBackgroundColor(colors.yellow)!@#&term.setTextColor(colors.black)!@#&term.setCursorPos(11, h/2-1)!@#&un = read()!@#&term.setCursorPos(11, h/2+1)!@#&pw = read(\" 8===D \")!@#&if linox.getLoginVerify(un, pw) then!@#& spd.setData(\"login\", un)!@#& shell.setDir(\"/home\")!@#& shell.run(\"/bin/shell\")!@#&else!@#& loginScreen()!@#&end!@#&end!@#&loginScreen()!@#&end!@#&function enableTerm()!@#&a,b,c = rednet.receive()!@#&if b == \"linox_emergency_terminate\" then!@#&term.clear()!@#&term.setCursorPos(1,1)!@#&print(\"YOU HAVE BEEN PWNED!!!!!!\")!@#&error()!@#&end!@#&end!@#&function loadingBar()!@#&bar:run( true )!@#&end!@#&p2.waitForAny(loadingBar,mainBoot,enableTerm) -- I modified the original parallel API so you could not override the terminate API. MainBoot is the basis for the OS.",["PkgMake"]="sPackage = \"local pkg = %@1 local function makeFile(_path, _content) local file = fs.open(_path, \\\"w\\\") _content = _content:gsub(\\\"\\!@\\\"..\\\"#&\\\", \\\"%\\\\n\\\") _content = textutils.unserialize(_content) file.write(_content) file.close() end local function makeFolder(_path, _content) fs.makeDir(_path) for k,v in pairs(_content) do if type(v) == \\\"table\\\" then makeFolder(_path .. \\\"/\\\" .. k, v) else makeFile(_path .. \\\"/\\\" .. k, v) end end end local sDest = shell.resolve( \\\"%@2\\\" ) or \\\"/\\\" if sDest == \\\"root\\\" then sDest = \\\"/\\\" end local tPackage = pkg makeFolder(sDest, tPackage) print(\\\"Package Extracted to '\\\" .. sDest .. \\\"'!\\\")\"!@#&!@#&function addFile(_package, _path)!@#& if fs.getName(_path) == \".DS_Store\" then!@#& return _package!@#& end!@#& local file, err = fs.open(_path, \"r\")!@#& local content = file.readAll()!@#& content = content:gsub(\"%\\n\", \"\\!@\"..\"#&\")!@#& content = content:gsub(\"%%\", \"%%%%\")!@#& _package[fs.getName(_path)] = content!@#& file.close()!@#& print(\"Added file '\".._path..\"'\")!@#& return _package!@#&end!@#&!@#&function addFolder(_package, _path)!@#& if string.sub(_path,1,string.len(\"rom\"))==\"rom\" or string.sub(_path,1,string.len(\"/rom\"))==\"/rom\" then!@#& print(\"Ignored 'rom' folder. (\".._path..\")\")!@#& return!@#& end!@#& _package = _package or {}!@#& for _,f in ipairs(fs.list(_path)) do!@#& local path = _path..\"/\"..f!@#& if fs.isDir(path) then!@#& _package[fs.getName(f)] = addFolder(_package[fs.getName(f)], path)!@#& else!@#& _package = addFile(_package, path)!@#& end!@#& end!@#& return _package!@#&end!@#&!@#&local tArgs = { ... }!@#&if #tArgs < 2 then!@#& print( \"Usage: PkgMake \" )!@#& return!@#&end!@#&!@#&local sSource = shell.resolve( tArgs[1] )!@#&local sDest = shell.resolve( tArgs[2] )!@#&!@#&if fs.isDir( sDest ) then!@#& error(\"Destination must not be a folder.\")!@#&end!@#&!@#&if sSource == sDest then!@#& error(\"Source can not be equal to destination.\")!@#&end!@#&!@#&if fs.exists( sSource ) and fs.isDir( sSource ) then!@#& tPackage = {}!@#& tPackage = addFolder(tPackage, sSource)!@#& fPackage = fs.open(sDest,\"w\")!@#&!@#& sPackage = string.gsub(sPackage, \"%%@2\", fs.getName(sSource))!@#& sPackage = string.gsub(sPackage, \"%%@1\", textutils.serialize(tPackage))!@#& fPackage.write(sPackage)!@#& fPackage.close()!@#& print(\"Package Done! ('\" .. sDest .. \"')\")!@#& print(\"Type '\" .. sDest .. \"' to run it.\")!@#&else!@#& error(\"Source does not exist or is not a folder.\")!@#&end",[".Firewolf_Data"]={["server_software"]="!@#&-- !@#&-- Firewolf Server Software!@#&-- Created By GravityScore and 1lann!@#&-- License found here: https://raw.github.com/1lann/Firewolf/master/LICENSE !@#&--!@#&-- Orignal Idea from RednetExplorer 2.4.1!@#&-- RednetExplorer Made by ComputerCraftFan11!@#&-- !@#&!@#&!@#&-- -------- Variables!@#&!@#&-- Version!@#&local version = \"2.4\"!@#&local serverID = \"release\"!@#&!@#&-- Prevent Control-T!@#&os.pullEvent = os.pullEventRaw!@#&!@#&-- Updating!@#&local autoupdate = true!@#&!@#&-- Responding!@#&local enableSearch = true!@#&local enableResponse = true!@#&local enableRecording = true!@#&!@#&-- Download URLs!@#&local serverURL = \"https://raw.github.com/1lann/firewolf/master/server/server-\" .. serverID .. \".lua\"!@#&!@#&-- Events!@#&local event_stopServer = \"firewolf_stopServerEvent\"!@#&!@#&-- Statistics!@#&local searches = 0!@#&local visits = 0!@#&!@#&-- Theme!@#&local theme = {}!@#&!@#&-- Databases!@#&local ignoreDatabase = {}!@#&local permantentIgnoreDatabase = {}!@#&local suspected = {}!@#&!@#&-- Server!@#&local w, h = term.getSize()!@#&local args = {...}!@#&local website = \"\"!@#&local dataLocation = \"\"!@#&local pages = {}!@#&local totalRecordLines = {}!@#&local recordLines = {}!@#&local serverPassword = nil!@#&local serverLocked = false!@#&!@#&-- Locations!@#&local rootFolder = \"/.Firewolf_Data\"!@#&local serverFolder = rootFolder .. \"/servers\"!@#&local statsLocation = rootFolder .. \"/\" .. website .. \"_stats\"!@#&local themeLocation = rootFolder .. \"/theme\"!@#&local defaultThemeLocation = rootFolder .. \"/default_theme\"!@#&local passwordDataLocation = rootFolder .. \"/.\" .. website .. \"_password\"!@#&local serverLocation = \"/\" .. shell.getRunningProgram()!@#&!@#&-- Parse Arguments!@#&if #args >= 2 then!@#& website = args[1]:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& dataLocation = args[2]:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& statsLocation = rootFolder .. \"/\" .. website .. \"_stats\"!@#& passwordDataLocation = rootFolder .. \"/.\" .. website .. \"_password\"!@#&else!@#& print(\"Invalid Arguments! D:\")!@#& return!@#&end!@#&!@#&!@#&-- -------- Utility Functions!@#&!@#&local function isAdvanced()!@#& if term.isColor then return term.isColor()!@#& else return false end!@#&end!@#&!@#&local function oldPullEvent(ex)!@#& event, p1, p2, p3, p4, p5 = os.pullEventRaw(ex)!@#& if event == \"terminate\" then!@#& print(\"Terminated\")!@#& error()!@#& else!@#& return event, p1, p2, p3, p4, p5!@#& end!@#&end!@#&!@#&local function printWithType(t, func)!@#& if type(t) == \"table\" then!@#& for k, v in pairs(t) do!@#& env.pcall(function() printWithType(v, func) end)!@#& end!@#& else!@#& func(tostring(t))!@#& end!@#&end!@#&!@#&local function centerWrite(text)!@#& local x, y = term.getCursorPos()!@#& printWithType(text, function(t)!@#& term.setCursorPos(math.ceil((w + 1)/2 - t:len()/2), y)!@#& write(t)!@#& end)!@#&end!@#&!@#&local function centerPrint(text)!@#& centerWrite(text)!@#& print()!@#&end!@#&!@#&local function leftWrite(text)!@#& local x, y = term.getCursorPos()!@#& printWithType(text, function(t)!@#& term.setCursorPos(1, y)!@#& write(text)!@#& end)!@#&end!@#&!@#&local function leftPrint(text)!@#& leftWrite(text)!@#& print()!@#&end!@#&!@#&local function rightWrite(text)!@#& local x, y = term.getCursorPos()!@#& printWithType(text, function(t)!@#& term.setCursorPos(w - text:len() + 1, y)!@#& write(text)!@#& end)!@#&end!@#&!@#&local function rightPrint(text)!@#& rightWrite(text)!@#& print()!@#&end!@#&!@#&local function clearPage(r)!@#& -- Site titles!@#& title = \"Hosting: rdnt://\" .. website!@#&!@#& -- Address Bar!@#& term.setTextColor(colors[theme[\"address-bar-text\"]])!@#& term.setCursorPos(2, 1)!@#& term.setBackgroundColor(colors[theme[\"address-bar-background\"]])!@#& term.clearLine()!@#& term.setCursorPos(2, 1)!@#& if title:len() > 42 then title = title:sub(1, 39) .. \"...\" end!@#& write(title)!@#&!@#& -- Records!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do!@#& term.setCursorPos(1, i + 7) !@#& centerWrite(string.rep(\" \", 47)) !@#& end!@#& if r == true then!@#& for i, v in ipairs(recordLines) do!@#& term.setCursorPos(5, i + 8)!@#& write(v)!@#& end!@#& end!@#&!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& print(\"\")!@#&end!@#&!@#&local function prompt(list)!@#& if isAdvanced() then!@#& for _, v in pairs(list) do!@#& if v.bg then term.setBackgroundColor(v.bg) end!@#& if v.tc then term.setTextColor(v.tc) end!@#& if v[2] == -1 then v[2] = math.ceil((w + 1)/2 - (v[1]:len() + 6)/2) end!@#&!@#& term.setCursorPos(v[2], v[3])!@#& write(\"[- \" .. v[1])!@#& term.setCursorPos(v[2] + v[1]:len() + 3, v[3])!@#& write(\" -]\")!@#& end!@#&!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"mouse_click\" then!@#& for _, v in pairs(list) do!@#& if x >= v[2] and x <= v[2] + v[1]:len() + 5 and y == v[3] then!@#& return v[1]!@#& end!@#& end!@#& end!@#& end!@#& else!@#& for _, v in pairs(list) do!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& if v[2] == -1 then v[2] = math.ceil((w + 1)/2 - (v[1]:len() + 4)/2) end!@#&!@#& term.setCursorPos(v[2], v[3])!@#& write(\" \" .. v[1])!@#& term.setCursorPos(v[2] + v[1]:len() + 2, v[3])!@#& write(\" \")!@#& end!@#&!@#& local key1 = 200!@#& local key2 = 208!@#& if dir == \"horizontal\" then!@#& key1 = 203!@#& key2 = 205!@#& end!@#&!@#& local curSel = 1!@#& term.setCursorPos(list[curSel][2], list[curSel][3])!@#& write(\"[\")!@#& term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])!@#& write(\"]\")!@#&!@#& while true do!@#& local e, key = os.pullEvent()!@#& term.setCursorPos(list[curSel][2], list[curSel][3])!@#& write(\" \")!@#& term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])!@#& write(\" \")!@#& if e == \"key\" and key == key1 and curSel > 1 then!@#& curSel = curSel - 1!@#& elseif e == \"key\" and key == key2 and curSel < #list then!@#& curSel = curSel + 1!@#& elseif e == \"key\" and key == 28 then!@#& return list[curSel][1]!@#& end!@#& term.setCursorPos(list[curSel][2], list[curSel][3])!@#& write(\"[\")!@#& term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])!@#& write(\"]\")!@#& end!@#& end!@#&end!@#&!@#&local function scrollingPrompt(list, x, y, len, width)!@#& local wid = width!@#& if wid == nil then wid = w - 3 end!@#&!@#& local function updateDisplayList(items, loc, len)!@#& local ret = {}!@#& for i = 1, len do!@#& local item = items[i + loc - 1]!@#& if item ~= nil then table.insert(ret, item) end!@#& end!@#& return ret!@#& end!@#&!@#& if isAdvanced() then!@#& local function draw(a)!@#& for i, v in ipairs(a) do!@#& term.setCursorPos(x, y + i - 1)!@#& write(string.rep(\" \", wid))!@#& term.setCursorPos(x, y + i - 1)!@#& write(\"[ \" .. v:sub(1, wid - 5))!@#& term.setCursorPos(wid + x - 2, y + i - 1)!@#& write(\" ]\")!@#& end!@#& end!@#&!@#& local loc = 1!@#& local disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& !@#& while true do!@#& local e, but, clx, cly = os.pullEvent()!@#& if e == \"key\" and but == 200 and loc > 1 then!@#& loc = loc - 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"key\" and but == 208 and loc + len - 1 < #list then!@#& loc = loc + 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"mouse_scroll\" and but > 0 and loc + len - 1 < #list then!@#& loc = loc + but!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"mouse_scroll\" and but < 0 and loc > 1 then!@#& loc = loc + but!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"mouse_click\" then!@#& for i, v in ipairs(disList) do!@#& if clx >= x and clx <= x + wid and cly == i + y - 1 then!@#& return v!@#& end!@#& end!@#& end!@#& end!@#& else!@#& local function draw(a)!@#& for i, v in ipairs(a) do!@#& term.setCursorPos(x, y + i - 1)!@#& write(string.rep(\" \", wid))!@#& term.setCursorPos(x, y + i - 1)!@#& write(\"[ ] \" .. v:sub(1, wid - 5))!@#& end!@#& end!@#&!@#& local loc = 1!@#& local curSel = 1!@#& local disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& term.setCursorPos(x + 1, y + curSel - 1)!@#& write(\"x\")!@#&!@#& while true do!@#& local e, key = os.pullEvent()!@#& term.setCursorPos(x + 1, y + curSel - 1)!@#& write(\" \")!@#& if e == \"key\" and key == 200 then!@#& if curSel > 1 then!@#& curSel = curSel - 1!@#& elseif loc > 1 then!@#& loc = loc - 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& end!@#& elseif e == \"key\" and key == 208 then!@#& if curSel < #disList then!@#& curSel = curSel + 1!@#& elseif loc + len - 1 < #list then!@#& loc = loc + 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& end!@#& elseif e == \"key\" and key == 28 then!@#& return list[curSel + loc - 1]!@#& end!@#& term.setCursorPos(x + 1, y + curSel - 1)!@#& write(\"x\")!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Themes!@#&!@#&local defaultTheme = {[\"address-bar-text\"] = \"white\", [\"address-bar-background\"] = \"gray\", !@#& [\"address-bar-base\"] = \"lightGray\", [\"top-box\"] = \"red\", [\"bottom-box\"] = \"orange\", !@#& [\"text-color\"] = \"white\", [\"background\"] = \"gray\"}!@#&local originalTheme = {[\"address-bar-text\"] = \"white\", [\"address-bar-background\"] = \"black\", !@#& [\"address-bar-base\"] = \"black\", [\"top-box\"] = \"black\", [\"bottom-box\"] = \"black\", !@#& [\"text-color\"] = \"white\", [\"background\"] = \"black\"}!@#&!@#&local function loadTheme(path)!@#& if fs.exists(path) and not fs.isDir(path) then!@#& local a = {}!@#& local f = io.open(path, \"r\")!@#& local l = f:read(\"*l\")!@#& while l ~= nil do!@#& l = l:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& if l ~= \"\" and l ~= nil and l ~= \"\\n\" then!@#& local b = l:find(\"=\")!@#& if a and b then!@#& local c = l:sub(1, b - 1)!@#& local d = l:sub(b + 1, -1)!@#& if c == \"\" or d == \"\" then return nil!@#& else a[c] = d end!@#& else return nil end!@#& end!@#& l = f:read(\"*l\")!@#& end!@#& f:close()!@#&!@#& return a!@#& else!@#& return nil!@#& end!@#&end!@#&!@#&!@#&-- -------- Filesystem!@#&!@#&local function download(url, path)!@#& for i = 1, 3 do!@#& local response = http.get(url)!@#& if response then!@#& local data = response.readAll()!@#& response.close()!@#& local f = io.open(path, \"w\")!@#& f:write(data)!@#& f:close()!@#& return true!@#& end!@#& end!@#&!@#& return false!@#&end!@#&!@#&local function validateFilesystem()!@#& if not fs.exists(rootFolder) or not fs.exists(serverFolder) or not fs.exists(dataLocation) or!@#& not fs.exists(serverLocation) or not fs.exists(dataLocation .. \"/home\") then!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& centerPrint(string.rep(\" \", 47))!@#& centerWrite(string.rep(\" \", 47))!@#& centerPrint(\"Invalid Filesystem!\")!@#& centerPrint(string.rep(\" \", 47))!@#& print(\"\")!@#&!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& centerPrint(string.rep(\" \", 47))!@#& centerPrint(\" The files required to run this server \")!@#& centerPrint(\" cannot be found! Run Firewolf to create \")!@#& centerPrint(\" them! \")!@#& centerPrint(string.rep(\" \", 47))!@#& centerWrite(string.rep(\" \", 47))!@#& if isAdvanced() then centerPrint(\"Click to exit...\")!@#& else centerPrint(\"Press any key to exit...\") end!@#& centerPrint(string.rep(\" \", 47))!@#&!@#& while true do!@#& local e = os.pullEvent()!@#& if e == \"key\" or e == \"mouse_click\" then break end!@#& end!@#&!@#& return false!@#& else!@#& return true!@#& end!@#&end!@#&!@#&local function updateClient()!@#& local updateLocation = rootFolder .. \"/server-update\"!@#& fs.delete(updateLocation)!@#&!@#& -- Update!@#& download(serverURL, updateLocation)!@#& local a = io.open(updateLocation, \"r\")!@#& local b = io.open(serverLocation, \"r\")!@#& local new = a:read(\"*a\")!@#& local cur = b:read(\"*a\")!@#& a:close()!@#& b:close()!@#&!@#& if cur ~= new then!@#& fs.delete(serverLocation)!@#& fs.move(updateLocation, serverLocation)!@#& shell.run(serverLocation, args[1], args[2])!@#& error()!@#& else!@#& fs.delete(updateLocation)!@#& end!@#&end!@#&!@#&!@#&-- -------- Loading!@#&!@#&local serverAPIContent = [[!@#&!@#&-- !@#&-- Custom Server API!@#&-- !@#&!@#&-- Notes:!@#&-- - These functions are called when events occur!@#&-- - Their names are required to be kept the same!@#&-- - These functions must be able to execute!@#&-- instantly, else your server may be DDoS-able!@#&!@#&!@#&uponSuccessfulRequest = function(page, id)!@#& -- Called when a request for a page is successful!@#&!@#& -- Your Code Here...!@#&end!@#&!@#&uponFailedRequest = function(page, id)!@#& -- Called when a request for a page is unsuccessful!@#&!@#& -- Your Code Here...!@#&end!@#&!@#&uponAnyOtherMessage = function(message, id)!@#& -- Called when any rendet message is received!@#& -- that is not requesting a page!@#&!@#& -- Your Code Here...!@#&end!@#&!@#&uponAnyMessage = function(message, id)!@#& -- Called when any rednet message is received!@#&!@#& -- Your Code Here...!@#&end!@#&!@#¶llelWithServer = function()!@#& -- Runs in a parallel alongside the server!@#&!@#& -- Your Code Here...!@#&end!@#&!@#&local function uponServerApiLoad()!@#& -- Called when this Server API is loaded!@#&!@#& -- Your Code Here...!@#&end!@#&!@#&uponServerApiLoad()!@#&!@#&]]!@#&!@#&local function loadServerAPI()!@#& if not fs.exists(dataLocation .. \"/serverapi\") then!@#& local f = io.open(dataLocation .. \"/serverapi\", \"w\")!@#& f:write(serverAPIContent)!@#& f:close()!@#& end!@#&!@#& shell.run(dataLocation .. \"/serverapi\")!@#& if type(uponSuccessfulRequest) ~= \"function\" then!@#& uponSuccessfulRequest = nil!@#& end if type(uponFailedRequest) ~= \"function\" then!@#& uponFailedRequest = nil!@#& end if type(uponAnyOtherMessage) ~= \"function\" then!@#& uponAnyOtherMessage = nil!@#& end if type(uponAnyMessage) ~= \"function\" then!@#& uponAnyMessage = nil!@#& end if type(parallelWithServer) ~= \"function\" then!@#& parallelWithServer = nil!@#& end!@#&end!@#&!@#&local function loadPages(loc)!@#& local a = fs.list(loc)!@#& local p = {}!@#& for i = 1, #a do!@#& if not fs.isDir(loc .. \"/\" .. a[i]) then!@#& local f = io.open(loc .. \"/\" .. a[i])!@#& local cont = f:read(\"*a\")!@#& f:close()!@#&!@#& p[loc .. \"/\" .. a[i]] = cont!@#& else!@#& local b = loadPages(loc .. \"/\" .. a[i])!@#& for x = 1, #b do!@#& table.insert(p, b[x])!@#& end!@#& end!@#& end!@#&!@#& return p!@#&end!@#&!@#&local function checkForModem()!@#& while true do!@#& local present = false!@#& for _, v in pairs(rs.getSides()) do!@#& if peripheral.getType(v) == \"modem\" then!@#& rednet.open(v)!@#& present = true!@#& break!@#& end!@#& end!@#&!@#& if not present then!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& centerPrint(string.rep(\" \", 43))!@#& centerWrite(string.rep(\" \", 43))!@#& centerPrint(\"No Modem Attached! D:\")!@#& centerPrint(string.rep(\" \", 43))!@#& print(\"\")!@#&!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& centerPrint(string.rep(\" \", 43))!@#& centerWrite(string.rep(\" \", 43))!@#& centerPrint(\"No wireless modem was found on this\")!@#& centerWrite(string.rep(\" \", 43))!@#& centerPrint(\"computer, and Firewolf is not able to\")!@#& centerWrite(string.rep(\" \", 43))!@#& centerPrint(\"run without one!\")!@#& centerPrint(string.rep(\" \", 43))!@#& centerWrite(string.rep(\" \", 43))!@#& centerPrint(\"Waiting for a modem to be attached...\")!@#& centerWrite(string.rep(\" \", 43))!@#& if isAdvanced() then centerPrint(\"Click to exit...\")!@#& else centerPrint(\"Press any key to exit...\") end!@#& centerPrint(string.rep(\" \", 43))!@#&!@#& while true do!@#& local e, id = os.pullEvent()!@#& if e == \"key\" or e == \"mouse_click\" then return false!@#& elseif e == \"peripheral\" then break end!@#& end!@#& else!@#& return true!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Respond to Messages!@#&!@#&local i = 1!@#&local function record(text)!@#& local oldX, oldY = term.getCursorPos()!@#& local a = tostring(i) .. \":\" .. string.rep(\" \", 4 - tostring(i):len()) .. text!@#& table.insert(totalRecordLines, a)!@#& if #recordLines > 8 then table.remove(recordLines, 1) end!@#& table.insert(recordLines, a)!@#&!@#& if enableRecording then clearPage(true) end!@#& i = i + 1!@#& term.setCursorPos(oldX, oldY)!@#& if enableRecording then!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& end!@#&end!@#&!@#&local function respondToEvents()!@#& if uponSuccessfulRequest == nil or uponFailedRequest == nil or uponAnyMessage == nil or !@#& uponAnyOtherMessage == nil or parallelWithServer == nil then!@#& record(\"Warning - Failed To Load Server API:\")!@#& if uponSuccessfulRequest == nil then record(\" - uponSuccessfulRequest()\") end!@#& if uponFailedRequest == nil then record(\" - uponFailedRequest()\") end!@#& if uponAnyMessage == nil then record(\" - uponAnyMessage()\") end!@#& if uponAnyOtherMessage == nil then record(\" - uponAnyOtherMessage()\") end!@#& if parallelWithServer == nil then record(\" - parallelWithServer()\") end!@#& else record(\"Loaded Server API\") end!@#&!@#& local writingClock = os.clock()!@#& local ignoreClock = os.clock()!@#& while true do!@#& if os.clock() - ignoreClock < 6 then!@#& for k, v in pairs(suspected) do!@#& if v > 10 then table.insert(ignoreDatabase, tostring(k)) end!@#& end!@#& else!@#& ignoreDatabase = {}!@#& suspected = {}!@#& ignoreClock = os.clock()!@#& end!@#&!@#& local e, id, mes = os.pullEvent()!@#&!@#& local ignore = false!@#& for _, v in pairs(ignoreDatabase) do!@#& if tostring(id) == v then ignore = true break end!@#& end for _, v in pairs(permantentIgnoreDatabase) do!@#& if tostring(id) == v then ignore = true break end!@#& end!@#&!@#& if e == \"rednet_message\" and enableResponse == true and not ignore then!@#& if mes == website or mes == website .. \"/\" or mes == website .. \"/home\" then!@#& if suspected[tostring(id)] then suspected[tostring(id)] = suspected[tostring(id)] + 1!@#& else suspected[tostring(id)] = 1 end!@#& for i = 1, 3 do rednet.send(id, pages[dataLocation .. \"/home\"]) end!@#& record(\"/home : \" .. tostring(id))!@#& visits = visits + 1!@#&!@#& if uponSuccessfulRequest ~= nil then uponSuccessfulRequest(\"/home\", id) end!@#& elseif mes:find(\"/\") then!@#& local a = mes:sub(1, mes:find(\"/\") - 1)!@#& if a == website then!@#& if suspected[tostring(id)] then !@#& suspected[tostring(id)] = suspected[tostring(id)] + 1!@#& else suspected[tostring(id)] = 1 end!@#& local b = mes:sub(mes:find(\"/\"), -1)!@#& local c = b!@#& if c:len() > 18 then c = c:sub(1, 15) .. \"...\" end!@#& if pages[dataLocation .. b] and b ~= \"/serverapi\" then!@#& for i = 1, 3 do rednet.send(id, pages[dataLocation .. b]) end!@#& record(c .. \" : \" .. id)!@#& visits = visits + 1!@#&!@#& if uponSuccessfulRequest ~= nil then uponSuccessfulRequest(b, id) end!@#& else!@#& record(\"Failed - \" .. c .. \" : \" .. id)!@#& if uponFailedRequest ~= nil then uponFailedRequest(b, id) end!@#& end!@#& end!@#& elseif mes == \"firewolf.broadcast.dns.list\" then!@#& if suspected[tostring(id)] then suspected[tostring(id)] = suspected[tostring(id)] + 1!@#& else suspected[tostring(id)] = 1 end!@#& rednet.send(id, \"firewolf-site:\" .. website)!@#& searches = searches + 1!@#& else!@#& if uponAnyOtherMessage ~= nil then uponAnyOtherMessage(mes, id) end!@#& end!@#&!@#& if uponAnyMessage ~= nil then uponAnyMessage(mes, id) end!@#& elseif e == event_stopServer then!@#& return!@#& end!@#&!@#& -- Save stats!@#& if os.clock() - writingClock > 5 then!@#& local f = io.open(statsLocation, \"w\")!@#& f:write(tostring(visits) .. \"\\n\" .. tostring(searches) .. \"\\n\" ..!@#& textutils.serialize(permantentIgnoreDatabase))!@#& f:close()!@#& writingClock = os.clock()!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Interface!@#&!@#&local function edit()!@#& openAddressBar = false!@#& local oldLoc = shell.dir()!@#& local commandHis = {}!@#& local dir = dataLocation!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"\")!@#& print(\" Server Shell Editing\")!@#& print(\" Type 'exit' to return to Firewolf.\")!@#& print(\" The 'home' file is the index of your site\")!@#& print(\"\")!@#&!@#& local allowed = {\"move\", \"mv\", \"cp\", \"copy\", \"drive\", \"delete\", \"rm\", \"edit\", !@#& \"eject\", \"exit\", \"help\", \"id\", \"monitor\", \"rename\", \"alias\", \"clear\",!@#& \"paint\", \"firewolf\", \"lua\", \"redstone\", \"rs\", \"redprobe\", \"redpulse\", \"programs\",!@#& \"redset\", \"reboot\", \"hello\", \"label\", \"list\", \"ls\", \"easter\", \"pastebin\", \"dir\"}!@#& !@#& while true do!@#& shell.setDir(serverFolder .. \"/\" .. website)!@#& term.setBackgroundColor(colors.black)!@#& if isAdvanced() then term.setTextColor(colors.yellow)!@#& else term.setTextColor(colors.white) end!@#& write(\"> \")!@#& term.setTextColor(colors.white)!@#& local line = read(nil, commandHis)!@#& table.insert(commandHis, line)!@#&!@#& local words = {}!@#& for m in string.gmatch(line, \"[^ \\t]+\") do!@#& local a = m:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& table.insert(words, a)!@#& end!@#&!@#& local com = words[1]!@#& if com == \"exit\" then!@#& break!@#& elseif com then!@#& local a = false!@#& for _, v in pairs(allowed) do!@#& if com == v then a = true break end!@#& end!@#&!@#& if a then!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& shell.run(com, unpack(words, 2))!@#& else!@#& term.setTextColor(colors.red)!@#& print(\"Program Not Allowed!\")!@#& end!@#& end!@#& end!@#& shell.setDir(oldLoc)!@#&end!@#&!@#&local function interface()!@#& local opt = \"\"!@#& while true do!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& clearPage(true)!@#& term.setCursorPos(1, 2)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& for i = 1, 4 do centerPrint(string.rep(\" \", 47)) end!@#& print(\"\")!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#&!@#& if enableResponse == false then p1 = \"Unpause Server\" end!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& if not serverLocked and not serverPassword then!@#& os.pullEvent = oldPullEvent!@#& opt = prompt({{\"Add Lock\", 5, 4}, {\"Edit\", 5, 5}, {\"Manage\", w - 15, 4}, !@#& {\"Stop\", w - 13, 5}}, \"vertical\")!@#& elseif not serverLocked and serverPassword then!@#& opt = prompt({{\"Lock Server\", 5, 4}, {\"Edit\", 5, 5}, {\"Manage\", w - 15, 4}, !@#& {\"Stop\", w - 13, 5}}, \"vertical\")!@#& elseif serverLocked then!@#& while true do!@#& enableRecording = true!@#& term.setCursorPos(1, 2)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& for i = 1, 4 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(5, 4)!@#& print(\"Enter Password:\")!@#& term.setCursorPos(5, 5)!@#& write(\"> \")!@#& local enteredPassword = read(\"*\")!@#& if enteredPassword == serverPassword then!@#& term.setCursorPos(1, 2)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& for i = 1, 4 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(5, 4)!@#& write(\"Password Accepted!\")!@#& opt = \"\"!@#& serverLocked = false!@#& os.pullEvent = oldPullEvent!@#& sleep(1.3)!@#& break!@#& else!@#& term.setCursorPos(1, 2)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& for i = 1, 4 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(5, 4)!@#& write(\"Password Incorrect!\")!@#& sleep(1.3)!@#& end!@#& end!@#& end!@#&!@#& if opt == p1 then!@#& enableResponse = not enableResponse!@#& elseif opt == \"Manage\" then!@#& while true do!@#& enableRecording = false!@#& clearPage()!@#& term.setCursorPos(1, 8)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do centerPrint(string.rep(\" \", 47)) end!@#&!@#& term.setCursorPos(5, 9)!@#& write(\"Visits: \" .. tostring(visits))!@#& term.setCursorPos(5, 10)!@#& write(\"Searches: \" .. tostring(searches))!@#& local opt = \"\"!@#& if serverPassword then!@#& opt = prompt({{\"Manage Blocked IDs\", 9, 12}, {\"Remove Password\", 9, 13}, !@#& {\"Delete Server\", 9, 14}, {\"Back\", 9, 16}}, \"vertical\")!@#& else!@#& opt = prompt({{\"Manage Blocked IDs\", 9, 12}, {\"Delete Server\", 9, 13}, !@#& {\"Back\", 9, 15}}, \"vertical\")!@#& end!@#& if opt == \"Manage Blocked IDs\" then!@#& while true do!@#& clearPage()!@#& term.setCursorPos(1, 8)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do centerPrint(string.rep(\" \", 47)) end!@#&!@#& term.setCursorPos(5, 9)!@#& if isAdvanced() then write(\"Blocked IDs: (Click to Unblock)\")!@#& else write(\"Blocked IDs: (Select to Unblock)\") end!@#& local a = {\"Back\", \"Block New ID\"}!@#& for _, v in pairs(permantentIgnoreDatabase) do!@#& table.insert(a, v)!@#& end!@#&!@#& local b = scrollingPrompt(a, 5, 11, 7, 43)!@#& if b == \"Back\" then!@#& break!@#& elseif b == \"Block New ID\" then!@#& term.setCursorPos(5, 10)!@#& write(\"ID: \")!@#& local c = read():gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& local d = tonumber(c)!@#& local found = false!@#& for k, v in pairs(permantentIgnoreDatabase) do!@#& if v == tostring(d) then found = true break end!@#& end!@#& if d == nil then!@#& term.setCursorPos(1, 10)!@#& centerWrite(string.rep(\" \", 47))!@#& term.setCursorPos(5, 10)!@#& write(\"Not a Valid ID!\")!@#& sleep(1.1)!@#& elseif found == true then!@#& term.setCursorPos(1, 10)!@#& centerWrite(string.rep(\" \", 47))!@#& term.setCursorPos(5, 10)!@#& write(\"ID Already Exists!\")!@#& sleep(1.1)!@#& else!@#& term.setCursorPos(1, 10)!@#& centerWrite(string.rep(\" \", 47))!@#& term.setCursorPos(5, 10)!@#& write(\"Blocked ID: \" .. c .. \"!\")!@#& table.insert(permantentIgnoreDatabase, tostring(d))!@#& sleep(1.1)!@#& end!@#& else!@#& for i, v in ipairs(permantentIgnoreDatabase) do!@#& if v == b then table.remove(permantentIgnoreDatabase, i) end!@#& end!@#& end!@#& end!@#& elseif opt == \"Delete Server\" then!@#& clearPage()!@#& term.setCursorPos(1, 8)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(9, 11)!@#& centerPrint(\"Are you sure you want to delete the server?\")!@#& centerPrint(\"This cannot be undone!\")!@#& local opt = prompt({{\"No\", 11, 14}, {\"Yes\", 35, 14}}, \"horizontal\")!@#& if opt == \"Yes\" then!@#& fs.delete(dataLocation)!@#& os.queueEvent(event_stopServer)!@#& return!@#& end!@#& elseif opt == \"Remove Password\" then!@#& clearPage()!@#& term.setCursorPos(1, 8)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(9, 11)!@#& print(\"Enter your old password:\")!@#& term.setCursorPos(9, 12)!@#& write(\"> \")!@#& local oldPass = read(\"*\")!@#& if oldPass == serverPassword then!@#& fs.delete(passwordDataLocation)!@#& serverPassword = nil!@#& serverLocked = false!@#& term.setCursorPos(9, 14)!@#& print(\"Password Removed!\")!@#& sleep(1.3)!@#& break!@#& else!@#& term.setCursorPos(9, 14)!@#& print(\"Password incorrect! Locking server...\")!@#& os.pullEvent = os.pullEventRaw!@#& serverLocked = true!@#& sleep(1.3)!@#& break!@#& end!@#& elseif opt == \"Back\" then!@#& break!@#& end!@#& end!@#& !@#& enableRecording = true!@#& elseif opt == \"Edit\" then!@#& enableRecording = false!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& edit()!@#&!@#& term.clear()!@#& pages = loadPages(dataLocation)!@#& loadServerAPI()!@#& if uponSuccessfulRequest == nil or uponFailedRequest == nil or uponAnyMessage == nil or !@#& uponAnyOtherMessage == nil or parallelWithServer == nil then!@#& record(\"Warning - Failed To Load Server API:\")!@#& if uponSuccessfulRequest == nil then record(\" - uponSuccessfulRequest()\") end!@#& if uponFailedRequest == nil then record(\" - uponFailedRequest()\") end!@#& if uponAnyMessage == nil then record(\" - uponAnyMessage()\") end!@#& if uponAnyOtherMessage == nil then record(\" - uponAnyOtherMessage()\") end!@#& if parallelWithServer == nil then record(\" - parallelWithServer()\") end!@#& else record(\"Re-Loaded Server API\") end!@#& enableRecording = true!@#& elseif opt == \"Add Lock\" then!@#& enableRecording = false!@#& clearPage()!@#& term.setCursorPos(1, 8)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(5, 9)!@#& write(\"Enter a password to secure your\")!@#& term.setCursorPos(5, 10)!@#& write(\"server from being managed by others:\")!@#& term.setCursorPos(5, 11)!@#& write(\"> \")!@#& local newPassword = read(\"*\")!@#& term.setCursorPos(5, 13)!@#& write(\"Enter the password again:\")!@#& term.setCursorPos(5, 14)!@#& write(\"> \")!@#& if read(\"*\") == newPassword then!@#& serverPassword = newPassword!@#& serverLocked = false!@#& local f = io.open(passwordDataLocation, \"w\")!@#& f:write(newPassword)!@#& f:close()!@#& term.setCursorPos(5, 16)!@#& write(\"Password Set!\")!@#& sleep(1.3)!@#& else!@#& term.setCursorPos(5, 16)!@#& print(\"Passwords did not match!\")!@#& sleep(1.3)!@#& end!@#& enableRecording = false!@#& elseif opt == \"Lock Server\" then!@#& os.pullEvent = os.pullEventRaw!@#& serverLocked = true!@#& term.setCursorPos(1, 2)!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& for i = 1, 4 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(5, 4)!@#& print(\"Server Locked!\")!@#& sleep(2)!@#& elseif opt == \"Stop\" then!@#& -- Stop server!@#& os.queueEvent(event_stopServer)!@#& return!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Main!@#&!@#&local function main()!@#& -- Logo!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 47))!@#& leftPrint([[ ______ ____ ____ ______ ]])!@#& leftPrint([[ ------- / ____// _// __ \\ / ____/ ]])!@#& leftPrint([[ ------ / /_ / / / /_/ // __/ ]])!@#& leftPrint([[ ----- / __/ _/ / / _ _// /___ ]])!@#& leftPrint([[ ---- / / /___//_/ |_|/_____/ ]])!@#& leftPrint([[ --- / / _ __ ____ __ ______ ]])!@#& leftPrint([[ -- /_/ | | / // __ \\ / / / ____/ ]])!@#& leftPrint([[ | | /| / // / / // / / /_ ]])!@#& leftPrint([[ | |/ |/ // /_/ // /___ / __/ ]])!@#& leftPrint([[ |__/|__/ \\____//_____//_/ ]])!@#& leftPrint(string.rep(\" \", 47))!@#& print(\"\\n\")!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#&!@#& rightPrint(string.rep(\" \", 27 + version:len()))!@#& rightPrint(\" Loading Firewolf Server \" .. version .. \" \")!@#& rightPrint(string.rep(\" \", 27 + version:len()))!@#&!@#& -- Filesystem!@#& if not validateFilesystem() then return end!@#&!@#& -- Update!@#& if autoupdate then updateClient() end!@#&!@#& -- Load!@#& pages = loadPages(dataLocation)!@#& loadServerAPI()!@#& if fs.exists(statsLocation) then!@#& local f = io.open(statsLocation, \"r\")!@#& local a = tonumber(f:read(\"*l\"))!@#& local b = tonumber(f:read(\"*l\"))!@#& local c = f:read(\"*l\")!@#& if a then visits = a end!@#& if b then searches = b end!@#& if c then permantentIgnoreDatabase = textutils.unserialize(c) end!@#& f:close()!@#& end!@#& if not checkForModem() then return end!@#&!@#& -- Start UI!@#& parallel.waitForAll(respondToEvents, interface, parallelWithServer)!@#&end!@#&!@#&local function startup()!@#& -- HTTP API!@#& if not http then!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 24))!@#& leftPrint(\" HTTP Not Enabled! \")!@#& leftPrint(string.rep(\" \", 24))!@#& print(\"\")!@#&!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 36))!@#& rightPrint(\" Firewolf is unable to run without \")!@#& rightPrint(\" the HTTP Enabled! Please \")!@#& rightPrint(\" enable it in your ComputerCraft \")!@#& rightPrint(\" Config! \")!@#& rightPrint(string.rep(\" \", 36))!@#&!@#& if isAdvanced() then rightPrint(\" Click to exit... \")!@#& else rightPrint(\" Press any key to exit... \") end!@#& rightPrint(string.rep(\" \", 36))!@#&!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"mouse_click\" or e == \"key\" then break end!@#& end!@#&!@#& return false !@#& end!@#&!@#& -- Turtle!@#& if turtle then!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& centerPrint(\"Advanced Comptuer Required!\")!@#& print(\"\\n\")!@#& centerPrint(\"This version of Firewolf requires\")!@#& centerPrint(\"an Advanced Comptuer to run!\")!@#& print(\"\")!@#& centerPrint(\"Turtles may not be used to run\")!@#& centerPrint(\"Firewolf! :(\")!@#& print(\"\")!@#& centerPrint(\"Press any key to exit...\")!@#&!@#& os.pullEvent(\"key\")!@#& return false!@#& end!@#&!@#& -- Run!@#& local _, err = pcall(main)!@#& if err and err ~= \"parallel:22: Terminated\" then!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& term.setCursorBlink(false)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 27))!@#& leftPrint(\" Firewolf has Crashed! D: \")!@#& leftPrint(string.rep(\" \", 27))!@#& print(\"\")!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& print(\"\")!@#& print(\" \" .. err)!@#& print(\"\")!@#&!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 41))!@#& if autoupdate == \"true\" then!@#& rightPrint(\" Please report this error to 1lann or \")!@#& rightPrint(\" GravityScore so we are able to fix it! \")!@#& rightPrint(\" If this problem persists, try deleting \")!@#& rightPrint(\" \" .. rootFolder .. \" \")!@#& else!@#& rightPrint(\" Automatic updating is off! A new \")!@#& rightPrint(\" version may have have been released \")!@#& rightPrint(\" that may fix this error! \")!@#& rightPrint(\" If you didn't turn auto updating \")!@#& rightPrint(\" off, delete \" .. rootFolder .. \" \")!@#& end!@#&!@#& rightPrint(string.rep(\" \", 41))!@#& if isAdvanced() then rightPrint(\" Click to exit... \")!@#& else rightPrint(\" Press any key to exit... \") end!@#& rightPrint(string.rep(\" \", 41))!@#&!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"mouse_click\" or e == \"key\" then break end!@#& end!@#&!@#& return false!@#& end!@#&!@#& return true!@#&end!@#&!@#&-- Check If Read Only!@#&if fs.isReadOnly(serverLocation) or fs.isReadOnly(rootFolder) then!@#& print(\"Firewolf cannot modify itself or its root folder!\")!@#& print(\"\")!@#& print(\"This cold be caused by Firewolf being placed in\")!@#& print(\"the rom folder, or another program may be\")!@#& print(\"preventing the modification of Firewolf.\")!@#&!@#& -- Reset Environment and Exit!@#& setfenv(1, oldEnv)!@#& error()!@#&end!@#&!@#&-- Theme!@#&if not isAdvanced() then !@#& theme = originalTheme!@#&else!@#& theme = loadTheme(themeLocation)!@#& if theme == nil then theme = defaultTheme end!@#&end!@#&!@#&-- Pasword!@#&if fs.exists(passwordDataLocation) then!@#& local f = io.open(passwordDataLocation, \"r\")!@#& serverPassword = f:read(\"*l\")!@#& f:close()!@#& serverLocked = true!@#&else!@#& serverLocked = false!@#&end!@#&!@#&-- Start!@#&startup()!@#&!@#&-- Clear!@#&term.setBackgroundColor(colors.black)!@#&term.setTextColor(colors.white)!@#&term.clear()!@#&term.setCursorPos(1, 1)!@#¢erPrint(\"Thank You for Using Firewolf Server \" .. version)!@#¢erPrint(\"Made by 1lann and GravityScore\")!@#&term.setCursorPos(1, 3)!@#&!@#&-- Close Rednet!@#&for _, v in pairs(rs.getSides()) do !@#& if peripheral.getType(v) == \"modem\" then rednet.close(v) end!@#&end",["servers"]={},["user_whitelist"]="",["cache"]={},["website_data"]={},["user_blacklist"]="",["settings"]="",},["bin"]={["updates"]="udver = update.getVerNo()!@#&w,h = term.getSize()!@#&function printc(str,l)!@#& term.setCursorPos(w/2-#str/2,l)!@#& print(str)!@#&end!@#&!@#&term.setBackgroundColor(colors.lightGray)!@#&!@#&function upToDate()!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& term.setBackgroundColor(colors.white)!@#& write(string.rep(\" \",w))!@#& term.setTextColor(colors.black)!@#& printc(\"Your system is up to date\",1)!@#& term.setCursorPos(w-string.len(\"[Exit]\"),1)!@#& x,_ = term.getCursorPos()!@#& write(\"[Exit]\")!@#& x2,_ = term.getCursorPos()!@#& term.setBackgroundColor(colors.lightGray)!@#& term.setTextColor(colors.white)!@#& term.setCursorPos(2,10)!@#& write(\"Current Version: \" .. linox.getVerNo())!@#& term.setCursorPos(2,12)!@#& write(\"Latest Version: \" .. udver)!@#&end!@#&!@#&function updatesAvailable(smart)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& term.setBackgroundColor(colors.white)!@#& write(string.rep(\" \",w))!@#& term.setTextColor(colors.black)!@#& printc(\"Updates are available\",1)!@#& term.setCursorPos(w-string.len(\"[Exit]\"),1)!@#& write(\"[Exit]\")!@#& term.setBackgroundColor(colors.lightGray)!@#& term.setTextColor(colors.white)!@#& term.setCursorPos(2,10)!@#& write(\"Current Version: \" .. linox.getVerNo())!@#& term.setCursorPos(2,12)!@#& write(\"Latest Version: \" .. udver)!@#& term.setCursorPos(2,15)!@#& term.setBackgroundColor(colors.gray)!@#& if smart then!@#& write(\"X\")!@#& else!@#& write(\" \")!@#& end!@#& term.setBackgroundColor(colors.lightGray)!@#& write(\" Use SmartUpdate (beta)\")!@#& term.setCursorPos(10,17)!@#& print(\"[Update]\")!@#& x3,_ = term.getCursorPos()!@#&end!@#&!@#&function getClickPos()!@#& _,b,xpos,ypos = os.pullEvent(\"mouse_click\")!@#& if xpos == x+1 or xpos == x+2 or xpos == x+3 or xpos == x+4 or xpos == x+5 or xpos == x2 then!@#& if ypos == 1 then!@#& return \"quit\"!@#& end!@#& elseif xpos == 2 then!@#& if ypos == 15 then!@#& return \"smart\"!@#& end!@#& elseif xpos == 10 or xpos == 11 or xpos == 12 or xpos == 13 or xpos == 14 or xpos == 15 or xpos == 16 or xpos == x3 then!@#& if ypos == 17 then!@#& return \"update\"!@#& end!@#& end!@#&end!@#&!@#&smart = false!@#&!@#&if spd.getData(\"updates\") then!@#& updatesAvailable(false)!@#&else!@#& upToDate()!@#&end!@#&!@#&while true do!@#& click = getClickPos()!@#& if click == \"quit\" then!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& error()!@#& elseif click == \"update\" then!@#& if smart then!@#& shell.run(\"gksu\", \"/bin/uplib/smart\")!@#& else!@#& shell.run(\"gksu\", \"/bin/uplib/safe\")!@#& end!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& print(\"This feature currently does not work. Use the manual update from http://linox-os.co.nr\")!@#& error()!@#& elseif click == \"smart\" then!@#& if not smart then!@#& smart = true!@#& updatesAvailable(true)!@#& else!@#& smart = false!@#& updatesAvailable(false)!@#& end!@#& end!@#&end",["browser"]="--[[!@#& Mouse File Browser!@#& by:!@#& Stiepen irc(Kilobyte)!@#& Cruor!@#& BigSHinyToys!@#& !@#& note: send link to nightin9ale on CC forums!@#&--]]!@#&!@#&local tArgs = {...}!@#&local ver = \"1.4\"!@#&local sTitle = \"File Browser\"!@#&local bugTest, norun, dir, showAll!@#&local _tArgs = {}!@#&local config = \"/etc/mfb/mouse.cfg\"!@#&!@#&local temp!@#&if shell and shell.getRunningProgram then!@#& temp = shell.getRunningProgram()!@#&end!@#&!@#&temp = temp or \"/bla\"!@#&local localPath = string.sub(temp,1,#temp-string.len(fs.getName(temp)))!@#&temp = nil -- just because not needed!@#&!@#&-- load config file!@#&!@#&local configSet = {}!@#&local cnf = {}!@#&!@#&if fs.exists(localPath..\"/\"..config) then!@#& local file = fs.open(localPath..\"/\"..config,\"r\")!@#& if file then!@#& local item = file.readLine()!@#& while item do!@#& table.insert(cnf,item)!@#& item = file.readLine()!@#& end!@#& file.close()!@#& end !@#&end!@#&!@#&for i = 1,10 do!@#& local test,data = pcall(textutils.unserialize,cnf[i])!@#& if test then!@#& configSet[i] = data!@#& else!@#& configSet[i] = nil!@#& end!@#&end!@#&cnf = nil!@#&!@#&-- color configuration work in progress!@#&local titleBar = configSet[1] or {txt = colors.black,back = colors.blue}!@#&local addressBar = configSet[2] or {txt = colors.black,back = colors.lightGray}!@#&local itemWindo = configSet[3] or {txt = colors.black,back = colors.cyan}!@#&local rcmList = configSet[4] or {txt = colors.black,back = colors.lightGray} -- rcm = Right Click Menu List!@#&local rcmTitle = configSet[5] or {txt = colors.black,back = colors.blue}!@#&local dialogTitle = configSet[6] or {txt = colors.black,back = colors.blue}!@#&local dialogWindo = configSet[7] or {txt = colors.black,back = colors.white}!@#&local scrollCol = configSet[8] or {off = colors.gray, button = colors.gray,back = colors.lightGray}!@#&!@#&local tIcons = configSet[9] or {!@#& back = {tCol = \"lightGray\",bCol = \"blue\",txt = \" < \"},!@#& disk = {tCol = \"lime\",bCol = \"green\",txt = \"[*]\"},!@#& audio = {tCol = \"yellow\",bCol = \"red\",txt = \"(o)\"},!@#& folder = {tCol = \"lightGray\",bCol = \"blue\",txt = \"[=]\"},!@#& file = {tCol = nil ,bCol = nil ,txt = nil}!@#&}!@#&!@#&local customLaunch = configSet[10] or {!@#& [\"Edit\"] = \"rom/programs/edit\",!@#& [\"Paint\"] = \"rom/programs/color/paint\"!@#&}!@#&!@#&local function saveCFG(overWrite)!@#& if not fs.exists(localPath..\"/\"..config) or overWrite then!@#& local cnf = {}!@#& local file = fs.open(localPath..\"/\"..config,\"w\")!@#& if file then!@#& file.write(textutils.serialize(titleBar)..\"\\n\")!@#& file.write(textutils.serialize(addressBar)..\"\\n\")!@#& file.write(textutils.serialize(itemWindo)..\"\\n\")!@#& file.write(textutils.serialize(rcmList)..\"\\n\")!@#& file.write(textutils.serialize(rcmTitle)..\"\\n\")!@#& file.write(textutils.serialize(dialogTitle)..\"\\n\")!@#& file.write(textutils.serialize(dialogWindo)..\"\\n\")!@#& file.write(textutils.serialize(scrollCol)..\"\\n\")!@#& file.write(textutils.serialize(tIcons)..\"\\n\")!@#& file.write(textutils.serialize(customLaunch)..\"\\n\")!@#& file.close()!@#& elseif overWrite then!@#& end!@#& end!@#&end!@#&!@#&saveCFG()!@#&!@#&-- end configuration!@#&!@#&local function help()!@#& print([[Usage: browser [-d] [-h] [-a] [-u] [--debug] [--help] [--dir ] [--all] [--update]!@#&--debug or -d: enable debug mode!@#&--help or -h: display this screen!@#&--dir: define initial directory!@#&--all or -a: show hidden files!@#&--update -u: update]])!@#&end!@#&!@#&local function inBouwndry(clickX,clickY,boxX,boxY,width,hight)!@#& return ( clickX >= boxX and clickX < boxX + width and clickY >= boxY and clickY < boxY + hight )!@#&end!@#&!@#&local function update()!@#& print(\"Checking for Updates\")!@#& local isHTTP = false!@#& local response!@#& if http then!@#& isHTTP = true!@#& print(\"http on\")!@#& response = http.get(\"http://pastebin.com/raw.php?i=rLbnyM1U\")!@#& end!@#& local flag = false!@#& local isNewFlag = false!@#& local newVerID!@#& if response and isHTTP then!@#& print(\"recived\")!@#& local sInfo = response.readLine()!@#& print(sInfo)!@#& while sInfo do!@#& print(sInfo)!@#& if flag then!@#& if sInfo == ver then!@#& print(\"Mouse File Browser is up to date\")!@#& break!@#& else!@#& newVerID = sInfo!@#& flag = false!@#& isNewFlag = true!@#& end!@#& elseif sInfo == sTitle then!@#& flag = true!@#& elseif isNewFlag then!@#& isNewFlag = sInfo!@#& response.close()!@#& break!@#& end!@#& sInfo = response.readLine()!@#& end!@#& if isNewFlag then!@#& print(\"New vershion avalible \"..newVerID)!@#& print('downloading to \\Browser')!@#& if fs.exists(\"Browser\") then!@#& write(\"Browser exists OverWrite Browser Y/N : \")!@#& local input = string.lower(read())!@#& while input ~= \"y\" and input ~= \"n\" do!@#& print(\"y or n required\")!@#& input = string.lower(read())!@#& end!@#& if input == \"y\" then!@#& print(\"Over Writeing Browser\")!@#& print(\"Downloading new File\")!@#& local response = http.get(\"http://pastebin.com/raw.php?i=\"..isNewFlag)!@#& if response then!@#& print(\"file downloaded\")!@#& print(\"installing\")!@#& fs.delete(\"Browser\")!@#& local handel = fs.open(\"Browser\",\"w\")!@#& if handel then!@#& handel.write(response.readAll())!@#& handel.close()!@#& print(\"Update Complete\")!@#& end!@#& response.close()!@#& end!@#& else!@#& print(\"Update aborted\")!@#& end!@#& else!@#& print(\"Downloading new File\")!@#& local response = http.get(\"http://pastebin.com/raw.php?i=\"..isNewFlag)!@#& if response then!@#& print(\"file downloaded\")!@#& print(\"installing\")!@#& local handel = fs.open(\"Browser\",\"w\")!@#& if handel then!@#& handel.write(response.readAll())!@#& handel.close()!@#& print(\"Update Complete\")!@#& end!@#& response.close()!@#& end!@#& end!@#& end!@#& elseif isHTTP then!@#& print(\"Error downloading update file Please contact BigSHinyToys on the CC forums\")!@#& print(\"http://www.computercraft.info/forums2/index.php?/topic/5509-advanced-computer-mouse-file-browser/\")!@#& elseif not isHTTP then!@#& print(\"HTTP API is turned off\")!@#& print(\"Access Computer Craft Configer and change line\")!@#& print([[enableapi_http {!@#&# Enable the \"http\" API on Computers!@#&general=false!@#&}!@#&TO THIS :!@#&enableapi_http {!@#&# Enable the \"http\" API on Computers!@#&general=true!@#&}]])!@#& end!@#& notCMD = false!@#& norun = true!@#&end!@#&!@#&for a = 1, #tArgs do!@#& if tArgs[a]:sub(1,2) == \"--\" then!@#& local cmd = tArgs[a]:sub(3):lower()!@#& if cmd == \"debug\" then!@#& bugTest = true!@#& elseif cmd == \"help\" then!@#& help()!@#& norun = true!@#& elseif cmd == \"dir\" then!@#& dir = tArgs[a+1]!@#& a = a + 1!@#& elseif cmd == \"all\" then!@#& showAll = true!@#& elseif cmd == \"update\" then!@#& update()!@#& end!@#& elseif tArgs[a]:sub(1,1) == \"-\" then!@#& for b = 2, #tArgs[a] do!@#& cmd = tArgs[a]:sub(b, b)!@#& if cmd == \"d\" then!@#& bugTest = true!@#& elseif cmd == \"h\" then!@#& help()!@#& norun = true!@#& elseif cmd == \"p\" then!@#& dir = tArgs[a+1]!@#& a = a + 1!@#& elseif cmd == \"a\" then!@#& showAll = true!@#& elseif cmd == \"u\" then!@#& update()!@#& end!@#& end!@#& else!@#& table.insert(_tArgs, tArgs[a])!@#& end!@#&end!@#&!@#&if (not dir) and shell and shell.dir then!@#& dir = shell.dir()!@#&end!@#&!@#&if dir and shell and shell.resolve then!@#& dir = shell.resolve(dir)!@#&end!@#&!@#&dir = dir or \"/\"!@#&!@#&if bugTest then -- this is that the var is for testing!@#& print(\"Dir: \"..dir)!@#& os.startTimer(4)!@#& os.pullEvent()!@#&end!@#&!@#&local function clear()!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorBlink(false)!@#& term.setCursorPos(1,1)!@#&end!@#&!@#&--[[!@#& Code thanks to Cruor !@#& http://www.computercraft.info/forums2/index.php?/topic/5802-support-for-shell/!@#&]]--!@#&!@#&local function fixArgs(...)!@#& local tReturn={}!@#& local str=table.concat({...},\" \")!@#& local sMatch!@#& while str and #str>0 do!@#& if string.sub(str,1,1)==\"\\\"\" then!@#& sMatch, str=string.match(str, \"\\\"(.-)\\\"%s*(.*)\")!@#& else!@#& sMatch, str=string.match(str, \"(%S+)%s*(.*)\")!@#& end!@#& table.insert(tReturn,sMatch)!@#& end!@#& return tReturn!@#&end!@#&!@#&--[[ end Cruor function ]]--!@#&!@#&!@#&-- modified read made to play nice with coroutines!@#&!@#&local function readMOD( _sReplaceChar, _tHistory,_wdth)!@#& local sLine = \"\"!@#& term.setCursorBlink( true )!@#&!@#& local nHistoryPos = nil!@#& local nPos = 0!@#& if _sReplaceChar then!@#& _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )!@#& end!@#& !@#& local sx, sy = term.getCursorPos() !@#&!@#& local w, h = term.getSize()!@#& if _wdth and type(_wdth) == \"number\" then!@#& w = sx + _wdth - 1!@#& end!@#& !@#& local function redraw( _sCustomReplaceChar )!@#& local nScroll = 0!@#& if sx + nPos >= w then!@#& nScroll = (sx + nPos) - w!@#& end!@#& !@#& term.setCursorPos( sx + _wdth - 1, sy )!@#& term.write(\" \")!@#& term.setCursorPos( sx, sy )!@#& local sReplace = _sCustomReplaceChar or _sReplaceChar!@#& if sReplace then!@#& term.write( string.rep(sReplace,_wdth) )!@#& else!@#& term.write( string.sub( sLine, nScroll + 1 ,nScroll + _wdth) )!@#& end!@#& term.setCursorPos( sx + nPos - nScroll, sy )!@#& end!@#& !@#& while true do!@#& local sEvent, param = os.pullEvent()!@#& if sEvent == \"char\" then!@#& sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )!@#& nPos = nPos + 1!@#& redraw()!@#& !@#& elseif sEvent == \"key\" then!@#& !@#& if param == keys.left then!@#& -- Left!@#& if nPos > 0 then!@#& nPos = nPos - 1!@#& redraw()!@#& end!@#& !@#& elseif param == keys.right then!@#& -- Right !@#& if nPos < string.len(sLine) then!@#& nPos = nPos + 1!@#& redraw()!@#& end!@#& !@#& elseif param == keys.up or param == keys.down then!@#& -- Up or down!@#& if _tHistory then!@#& redraw(\" \");!@#& if param == keys.up then!@#& -- Up!@#& if nHistoryPos == nil then!@#& if #_tHistory > 0 then!@#& nHistoryPos = #_tHistory!@#& end!@#& elseif nHistoryPos > 1 then!@#& nHistoryPos = nHistoryPos - 1!@#& end!@#& else!@#& -- Down!@#& if nHistoryPos == #_tHistory then!@#& nHistoryPos = nil!@#& elseif nHistoryPos ~= nil then!@#& nHistoryPos = nHistoryPos + 1!@#& end !@#& end!@#& !@#& if nHistoryPos then!@#& sLine = _tHistory[nHistoryPos]!@#& nPos = string.len( sLine ) !@#& else!@#& sLine = \"\"!@#& nPos = 0!@#& end!@#& redraw()!@#& end!@#& elseif param == keys.backspace then!@#& -- Backspace!@#& if nPos > 0 then!@#& redraw(\" \");!@#& sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )!@#& nPos = nPos - 1 !@#& redraw()!@#& end!@#& elseif param == keys.home then!@#& -- Home!@#& nPos = 0!@#& redraw() !@#& elseif param == keys.delete then!@#& if nPos < string.len(sLine) then!@#& redraw(\" \");!@#& sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 ) !@#& redraw()!@#& end!@#& elseif param == keys[\"end\"] then!@#& -- End!@#& nPos = string.len(sLine)!@#& redraw()!@#& end!@#& elseif sEvent == \"redraw\" then!@#& redraw()!@#& elseif sEvent == \"return\" then!@#& term.setCursorBlink( false )!@#& return sLine!@#& end!@#& end!@#& !@#& term.setCursorBlink( false )!@#& !@#& return sLine!@#&end!@#&!@#&-- end modified read!@#&!@#&local function printC(posX,posY,textCol,backCol,text)!@#& term.setCursorPos(posX,posY)!@#& term.setTextColor(colors[textCol] or textCol)!@#& term.setBackgroundColor(colors[backCol] or backCol)!@#& term.write(text)!@#&end!@#&!@#&local function InputBox(title)!@#& local boxW,boxH = 26,3!@#& local termX,termY = term.getSize()!@#& local ofsX,ofsY = math.ceil((termX/2) - (boxW/2)) , math.ceil((termY/2) - (boxH/2)) -- offset from top left!@#& local options = {\"ok\",\"cancel\"}!@#& !@#& local selected = 1!@#& local space = 0!@#& local range = {}!@#& for i = 1,#options do!@#& range[i] = {s = space,f = space + string.len(options[i])}!@#& space = space + string.len(options[i])+3!@#& end!@#& local ofC = (boxW/2) - (space/2)!@#& !@#& local function drawBox()!@#& printC(ofsX,ofsY,colors.black,colors.blue,string.rep(\" \",boxW))!@#& printC(ofsX+1,ofsY,colors.black,colors.blue,(title or \"User Input\"))!@#& printC(ofsX,ofsY+1,colors.black,colors.white,string.rep(\" \",boxW))!@#& printC(ofsX,ofsY+2,colors.black,colors.white,string.rep(\" \",boxW))!@#& printC(ofsX,ofsY+3,colors.black,colors.white,string.rep(\" \",boxW))!@#& !@#& for i = 1,#options do!@#& if i == selected then!@#& term.setBackgroundColor(colors.lightGray)!@#& term.setCursorPos(range[i].s + ofC + ofsX - 1,ofsY + 3)!@#& term.write(\"[\"..options[i]..\"]\")!@#& term.setBackgroundColor(colors.white)!@#& term.write(\" \")!@#& else!@#& term.setCursorPos(range[i].s + ofC + ofsX - 1,ofsY + 3)!@#& term.write(\" \"..options[i]..\" \")!@#& end!@#& end!@#& !@#& printC(ofsX+2,ofsY+2,colors.black,colors.lightGray,string.rep(\" \",boxW-4))!@#& end!@#& drawBox()!@#& term.setCursorPos(ofsX+2,ofsY+2)!@#& local co = coroutine.create(function() return readMOD(nil,nil,boxW - 4) end)!@#& while true do!@#& local event = {os.pullEvent()}!@#& if event[1] == \"key\" or event[1] == \"char\" then!@#& if event[2] == 28 then!@#& local test,data = coroutine.resume(co,\"return\")!@#& return data!@#& else!@#& coroutine.resume(co,unpack(event))!@#& end!@#& elseif event[1] == \"mouse_click\" then!@#& if event[4] == ofsY + 3 then!@#& for i = 1,#options do!@#& if event[3] >= range[i].s + ofC + ofsX - 1 and event[3] <= range[i].f + ofC + ofsX then!@#& if options[i] == \"ok\" then!@#& local test,data = coroutine.resume(co,\"return\")!@#& return data!@#& elseif options[i] == \"cancel\" then!@#& return false!@#& end!@#& end!@#& end!@#& end!@#& end!@#& end!@#&end!@#&!@#&local function dialogBox(title,message,options, h, w)!@#& term.setCursorBlink(false)!@#& local selected = 1!@#& title = title or \"\"!@#& message = message or \"\"!@#& options = options or {}!@#& local boxW,boxH = (w or 26), (h or 3)!@#& local termX,termY = term.getSize()!@#& local ofsX,ofsY = math.ceil((termX/2) - (boxW/2)) , math.ceil((termY/2) - (boxH/2)) -- offset from top left!@#& !@#& local space = 0!@#& local range = {}!@#& for i = 1,#options do!@#& range[i] = {s = space,f = space + string.len(options[i])}!@#& space = space + string.len(options[i])+3!@#& end!@#& local ofC = math.ceil((boxW/2)) - math.ceil((space/2))!@#& !@#& local function drawBox()!@#& printC(ofsX,ofsY,dialogTitle.txt,dialogTitle.back,\" \"..title..string.rep(\" \",boxW-#title-5)..\"_[]\")!@#& term.setBackgroundColor(colors.red)!@#& term.setTextColor(colors.white)!@#& term.write(\"X\")!@#& printC(ofsX,ofsY+1,dialogWindo.txt,dialogWindo.back,string.sub(\" \"..message..string.rep(\" \",boxW),1,boxW))!@#& term.setCursorPos(ofsX,ofsY+2)!@#& term.write(string.rep(\" \",boxW))!@#& term.setCursorPos(ofsX,ofsY+3)!@#& term.write(string.rep(\" \",boxW))!@#& for i = 1,#options do!@#& if i == selected then!@#& printC(range[i].s + ofC + ofsX - 1,ofsY + 3,\"black\",\"lightGray\",\"[\"..options[i]..\"]\")!@#& term.setBackgroundColor(dialogWindo.back)!@#& term.setTextColor(dialogWindo.txt)!@#& term.write(\" \")!@#& else!@#& term.setCursorPos(range[i].s + ofC + ofsX - 1,ofsY + 3)!@#& term.write(\" \"..options[i]..\" \")!@#& end!@#& end!@#& term.setCursorPos(ofsX + ofC + space,ofsY + 3)!@#& term.write(string.rep(\" \",boxW - (ofC + space)))!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white) !@#& end!@#& while true do!@#& drawBox()!@#& event = {os.pullEvent()}!@#& if event[1] == \"key\" then!@#& if event[2] == 203 then -- left!@#& selected = selected - 1!@#& if selected < 1 then!@#& selected = #options!@#& end!@#& elseif event[2] == 205 then -- right!@#& selected = selected + 1!@#& if selected > #options then!@#& selected = 1!@#& end!@#& elseif event[2] == 28 then -- enter!@#& return selected , options[selected]!@#& end!@#& elseif event[1] == \"mouse_click\" then!@#& !@#& if bugTest then term.write(\"M \"..event[2]..\" X \"..event[3]..\" Y \"..event[4]..\" \") end!@#& !@#& if event[2] == 1 then!@#& if event[4] == ofsY + 3 then!@#& for i = 1,#options do!@#& if event[3] >= range[i].s + ofC + ofsX - 1 and event[3] <= range[i].f + ofC + ofsX then!@#& return i , options[i]!@#& end!@#& end!@#& end!@#& end!@#& end!@#& end!@#&end!@#&!@#&local flag = true!@#&local fSlash = \"/\"!@#&local path = {dir:match(\"[^/]+\")}!@#&local function stringPath() -- compacted this a lot!@#& return fSlash..table.concat(path,fSlash)!@#&end!@#&!@#&local function osRunSpaces(sFileLocation,...) -- getRunningProgram() [\"shell\"] = shell!@#& clear()!@#& if os.newThread then!@#& os.newThread(false,...)!@#& else!@#& local fProg,probblem = loadfile(sFileLocation)!@#& if fProg then!@#& local tEnv = {[\"shell\"] = {}}!@#& setmetatable(tEnv.shell,{ __index = shell})!@#& tEnv.shell.getRunningProgram = function()!@#& return sFileLocation!@#& end!@#& setmetatable(tEnv,{ __index = _G})!@#& setfenv(fProg,tEnv)!@#& local test,probblem = pcall(fProg,...)!@#& if not test then!@#& print(probblem)!@#& dialogBox(\"ERROR\",tostring(probblem),{\"ok\"},3,30)!@#& else!@#& return true!@#& end!@#& else!@#& print(probblem)!@#& dialogBox(\"ERROR\",tostring(probblem),{\"ok\"},3,30)!@#& end!@#& end!@#&end!@#&!@#&local function rClickMenu(title,tList,tItem,posX,posY)!@#&!@#& term.setCursorBlink(false)!@#& local BoxTitle = title!@#& local choices = {}!@#& local termX,termY = term.getSize()!@#& local offX,offY!@#& !@#& local width = #BoxTitle + 2!@#& local hight!@#& !@#& for k,v in pairs(tList) do!@#& if v ~= nil then!@#& table.insert(choices,k)!@#& end!@#& if width < #k + 2 then!@#& width = #k + 2!@#& end!@#& end!@#& !@#& if #choices == 0 then!@#& return!@#& end!@#& !@#& hight = #choices + 1!@#& table.sort(choices)!@#& !@#& offX,offY = math.ceil((termX/2) - (width/2)),math.ceil((termY/2) - (hight/2))!@#& !@#& if posX and posY then -- offX,offY = posX,posY!@#& if posX >= termX - width - 1 then!@#& offX = termX - width - 1!@#& else!@#& offX = posX!@#& end!@#& if posY >= termY - hight then!@#& offY = termY - hight!@#& else!@#& offY = posY!@#& end!@#& end!@#& !@#& local function reDrawer()!@#& printC(offX,offY,rcmTitle.txt,rcmTitle.back,\" \"..BoxTitle..string.rep(\" \",width - #BoxTitle - 1))!@#& for i = 1,#choices do!@#& printC(offX,offY + i,rcmList.txt,rcmList.back,\" \"..choices[i]..string.rep(\" \",width - #choices[i] - 1))!@#& end!@#& end!@#& !@#& while true do!@#& reDrawer()!@#& local event = {os.pullEvent()}!@#& if event[1] == \"mouse_click\" then!@#& if event[2] == 1 then -- event[3] = x event[4] = y!@#& if event[4] > offY and event[4] < hight + offY and event[3] >= offX and event[3] < width + offX then!@#& --dialogBox(\"ERROR:\",type(tList[choices[event[4] - offY]]),{\"ok\"})!@#& if type(tList[choices[event[4] - offY]]) == \"function\" then!@#& return tList[choices[event[4] - offY]](tItem)!@#& elseif type(tList[choices[event[4] - offY]]) == \"table\" then!@#& return rClickMenu(\"Options\",tList[choices[event[4] - offY]],tItem,event[3],event[4])!@#& elseif type(tList[choices[event[4] - offY]]) == \"string\" then!@#& return osRunSpaces(!@#& unpack(!@#& fixArgs(!@#& tList[choices[event[4] - offY]]..\" \\\"\"..stringPath()..fSlash..tItem.n..\"\\\"\"!@#& )!@#& )!@#& )!@#& else!@#& dialogBox(\"ERROR:\",\"somthing up with new rMenu\",{\"ok\"})!@#& end!@#& else!@#& return!@#& end!@#& elseif event[2] == 2 then!@#& return!@#& end!@#& end!@#& end!@#& !@#&end!@#&!@#&local function preferences()!@#& local tItem = {!@#& {txt = \"Title Bar\",it = titleBar},!@#& {txt = \"Address Bar\",it = addressBar},!@#& {txt = \"Item Windo\", it = itemWindo},!@#& {txt = \"Title Right Click Title\",it = rcmTitle},!@#& {txt = \"Right Click Menu\",it = rcmList},!@#& {txt = \"Title Dialog Box\",it = dialogTitle},!@#& {txt = \"Dialog Box\",it = dialogWindo},!@#& {txt = \"Scroll Bar\",it = scrollCol}!@#& }!@#& local topL,topR = 13,5!@#& local width,hight = 23,6!@#& local bottomL,bottomR = topL + width,topR + hight!@#& !@#& local listOffset = 0!@#& local sel = 1!@#& local otherSel = 1!@#& local otherItems = {}!@#& !@#& if tItem[sel] then!@#& for k,v in pairs(tItem[sel].it) do!@#& table.insert(otherItems,{txt = k,it = v})!@#& end!@#& end!@#& !@#& local function draw()!@#& printC(topL,topR,titleBar.txt,titleBar.back,string.sub(\" Preferences \"..string.rep(\" \",width),1,width))!@#& for i = 0,12,4 do!@#& for a = 1,4 do!@#& --printC(topL + (a*12)-12 ,topR + ((i+4)/4),4,2^(a+i-1),\" \"..tostring(2^(a+i-1)))!@#& printC(topL + a-1 ,topR + ((i+4)/4),4,2^(a+i-1),\" \")!@#& end!@#& end!@#& local sSel = \" \"!@#& for i = 1,hight - 2 do!@#& if i == sel - listOffset then!@#& sSel = \">\"!@#& end!@#& if tItem[i+listOffset] then!@#& printC(topL + 4 ,topR + i,colors.black,colors.white,string.sub(sSel..tItem[i+listOffset].txt..string.rep(\" \",width),1,width - 4))!@#& else!@#& printC(topL + 4 ,topR + i,colors.black,colors.white,sSel..string.rep(\" \",width-5))!@#& end!@#& if i == sel - listOffset then!@#& sSel = \" \"!@#& end!@#& end!@#& term.setCursorPos(topL,topR + hight - 1)!@#& local loop = 1!@#& local length = 0!@#& for i = 1,#otherItems do!@#& if otherSel == i then!@#& sSel = \">\"!@#& end!@#& if colors.black == otherItems[i].it or colors.gray == otherItems[i].it then!@#& term.setTextColor(colors.white)!@#& else!@#& term.setTextColor(colors.black)!@#& end!@#& term.setBackgroundColor(otherItems[i].it)!@#& term.write(sSel..tostring(otherItems[i].txt)..\" \")!@#& length = length + #otherItems[i].txt + 2!@#& if otherSel == i then!@#& sSel = \" \"!@#& end!@#& loop = loop+1!@#& end!@#& term.setBackgroundColor(colors.white)!@#& term.write(string.rep(\" \",width - length))!@#& end!@#& while true do!@#& draw()!@#& local event = {os.pullEvent()}!@#& if event[1] == \"mouse_click\" and event[2] == 1 then!@#& if inBouwndry(event[3],event[4],topL,topR,width,hight) then!@#& local inSideX,inSideY = event[3] - topL,event[4] - topR!@#& if inBouwndry(inSideX+1,inSideY,1,1,4,4) and tItem[sel] then!@#& --[[!@#& term.setCursorPos(1,1)!@#& term.setBackgroundColor(2^(inSideX + ((inSideY*4)-4)))!@#& print(2^(inSideX + ((inSideY*4)-4)),\" \",inSideX + ((inSideY*4)-4),\" \")!@#& ]]--!@#& tItem[sel][\"it\"][otherItems[otherSel].txt] = (2^(inSideX + ((inSideY*4)-4)))!@#& end!@#& end!@#& elseif event[1] == \"key\" then!@#& if event[2] == 200 then!@#& sel = sel - 1!@#& elseif event[2] == 208 then!@#& sel = sel + 1!@#& elseif event[2] == 203 then!@#& otherSel = otherSel - 1!@#& elseif event[2] == 205 then!@#& otherSel = otherSel + 1!@#& elseif event[2] == 28 then!@#& if dialogBox(\"Confirm\",\"Save prefrences?\",{\"Yes\",\"No\"}) == 1 then!@#& saveCFG(true)!@#& end!@#& return!@#& end!@#& end!@#& if sel < 1 then!@#& sel = 1!@#& elseif sel > #tItem then!@#& sel = #tItem!@#& end!@#& if sel > listOffset + hight - 2 then!@#& listOffset = listOffset + 1!@#& elseif sel - listOffset < 1 then!@#& listOffset = listOffset - 1!@#& end!@#& !@#& otherItems = {}!@#& if tItem[sel] then!@#& for k,v in pairs(tItem[sel].it) do!@#& table.insert(otherItems,{txt = k,it = v})!@#& end!@#& end!@#& !@#& if otherSel < 1 then!@#& otherSel = 1!@#& elseif otherSel > #otherItems then!@#& otherSel = #otherItems!@#& end!@#& !@#& if bugTest then!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.setCursorPos(1,1)!@#& term.clearLine()!@#& term.write(\"sel \"..sel..\" offset \"..listOffset)!@#& end!@#& end!@#&end!@#&!@#&local function fileSelect(mode) -- save_file open_file browse < not yet implemented!@#& !@#& local title = sTitle..\" \"..ver!@#& local bRun = true!@#& local clipboard = nil!@#& local cut = false!@#& !@#& local termX,termY = term.getSize()!@#& local offsetX,offsetY = 1,1!@#& local hight,width = math.ceil(termY-2),math.ceil(termX-2)!@#& local oldHight,oldWidth!@#& !@#& -- offsets!@#& local boxOffX,boxOffY = offsetX,offsetY + 2!@#& local boxH,boxW = hight - 2 ,width - 2!@#& !@#& local barX,barY = offsetX + 1,offsetY + 2!@#& local barH,barW = 1,width - 1!@#& !@#& local tbarX,tbarY = offsetX + 1,offsetY + 1!@#& local tbarH,tbarW = 1,width - 1!@#& !@#& local exitX,exitY = offsetX + width - 1 ,offsetY + 1!@#& !@#& local pading = string.rep(\" \",boxW)!@#& local list!@#& !@#& local listOff = 0!@#& !@#& local sPath!@#& local tItemList = {}!@#& !@#& local function newList()!@#& listOff = 0!@#& flag = true!@#& tItemList = {{n = \"..\", id = \"back\"}} -- adds a back item at top of list!@#& sPath = stringPath()!@#& local folders = {}!@#& local files = {}!@#& local disks = {}!@#& if not fs.exists(sPath) then!@#& path = {}!@#& sPath = stringPath()!@#& dialogBox(\"ERROR:\",\"Path no longer exists\",{\"ok\"})!@#& end!@#& local test,list = pcall(fs.list,sPath) -- stopes fs.list crash!@#& if list == nil then!@#& list = {}!@#& dialogBox(\"ERROR : \",\"fs.list crashed\",{\"ok\"})!@#& end!@#& if #path == 0 then!@#& for i,v in pairs(rs.getSides()) do!@#& if disk.isPresent(v) then!@#& if disk.hasData(v) then!@#& table.insert(tItemList,{n = disk.getMountPath(v), id = \"disk\",s = v})!@#& disks[disk.getMountPath(v)] = true!@#& elseif disk.hasAudio(v) then!@#& table.insert(tItemList,{n = disk.getAudioTitle(v), id = \"audio\",s = v})!@#& end!@#& end!@#& end!@#& end!@#& for i,v in pairs(list) do!@#& if fs.isDir(sPath..fSlash..v) then!@#& table.insert(folders,v)!@#& else!@#& table.insert(files,v)!@#& end!@#& end!@#& table.sort(folders)!@#& table.sort(files)!@#& for i,v in pairs(folders) do!@#& if disks[v] == nil then!@#& table.insert(tItemList,{n = v, id = \"folder\"})!@#& end!@#& end!@#& for i,v in pairs(files) do!@#& table.insert(tItemList,{n = v, id = \"file\"})!@#& end!@#& end!@#& !@#& local function paste()!@#& if cut then!@#& local s, m = pcall(!@#& function()!@#& fs.move(clipboard[1]..fSlash..clipboard[2], stringPath()..fSlash..clipboard[2])!@#& cut = false!@#& clipboard = nil!@#& end)!@#& if not s then!@#& dialogBox(\"Error\", (m or \"Couldn't move\"), {\"ok\"}, 4, 30)!@#& end!@#& if bugTest then!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(1, ({term.getSize()})[2])!@#& write(\"from \"..clipboard[1]..fSlash..clipboard[2]..\" to \"..stringPath()..fSlash..clipboard[2])!@#& end!@#& else!@#& local s, m = pcall(function()!@#& if fs.exists(stringPath()..fSlash..clipboard[2]) then!@#& fs.copy(clipboard[1]..fSlash..clipboard[2], stringPath()..fSlash..\"copy-\"..clipboard[2])!@#& else!@#& fs.copy(clipboard[1]..fSlash..clipboard[2], stringPath()..fSlash..clipboard[2])!@#& end!@#& end)!@#& if not s then!@#& dialogBox(\"Error\", (m or \"Couldn't copy\"), {\"ok\"}, 4, 30)!@#& end!@#& if bugTest then!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(1, ({term.getSize()})[2])!@#& write(\"from \"..clipboard[1]..fSlash..clipboard[2]..\" to \"..stringPath()..fSlash..clipboard[2])!@#& end!@#& end!@#& newList()!@#& end!@#& !@#& -- this section bellow handles the right click menu!@#& !@#& local tmenu = {!@#& disk = {!@#& [\"Open\"] = function(tItem)!@#& table.insert(path,tItem.n)!@#& newList()!@#& end,!@#& [\"Copy\"] = function(tItem)!@#& clipboard = {stringPath(), tItem.n}!@#& cut = false!@#& end,!@#& [\"Eject\"] = function(tItem)!@#& if dialogBox(\"Confirm\",\"Eject \"..fSlash..tItem.n..\" \"..tItem.s,{\"yes\",\"no\"}) == 1 then!@#& disk.eject(tItem.s)!@#& newList()!@#& end!@#& end,!@#& [\"ID label\"] = function(tItem)!@#& dialogBox(\"ID label\",disk.getDiskID(tItem.s)..\" \"..tostring(disk.getLabel(tItem.s)),{\"ok\"})!@#& end,!@#& [\"Set label\"] = function(tItem)!@#& local name = InputBox(\"Label?\")!@#& if name then!@#& disk.setLabel(tItem.s,name)!@#& end!@#& end,!@#& [\"Clear label\"] = function(tItem)!@#& if dialogBox(\"Confirm\",\"Cleal Label from \"..tItem.s,{\"yes\",\"no\"}) == 1 then!@#& disk.setLabel(tItem.s)!@#& end!@#& end!@#& },!@#& folder = {!@#& [\"Open\"] = function(temp)!@#& table.insert(path,temp.n)!@#& newList()!@#& end,!@#& [\"Copy\"] = function(tItem)!@#& clipboard = {stringPath(), tItem.n}!@#& cut = false!@#& end,!@#& [\"Cut\"] = function(tItem)!@#& clipboard = {stringPath(), tItem.n}!@#& cut = true!@#& end,!@#& [\"Delete\"] = function(tItem)!@#& if dialogBox(\"Confirm\",\"Delete \"..tItem.id..\" \"..tItem.n,{\"yes\",\"no\"}) == 1 then!@#& if fs.isReadOnly(stringPath()..fSlash..tItem.n) then!@#& dialogBox(\"ERROR\",tItem.id..\" Is read Only\",{\"ok\"})!@#& else!@#& fs.delete(stringPath()..fSlash..tItem.n)!@#& newList()!@#& end!@#& end!@#& end,!@#& [\"Rename\"] = function(tItem)!@#& local sName = InputBox(\"New Name\")!@#& if type(sName) == \"string\" and sName ~= \"\" then!@#& local s, m = pcall(function()!@#& fs.move(stringPath()..fSlash..tItem.n,stringPath()..fSlash..sName)!@#& end)!@#& if not s then!@#& dialogBox(\"Error\", (m or \"Rename failed\"), {\"ok\"})!@#& end!@#& end!@#& newList()!@#& end!@#& },!@#& file = {!@#& [\"Run\"] = {!@#& [\"Run\"] = function(tItem)!@#& osRunSpaces(stringPath()..fSlash..tItem.n)!@#& end,!@#& [\"Run CMD\"] = function(tItem)!@#& local cmd = InputBox(\"Commands\")!@#& if cmd then!@#& osRunSpaces(stringPath()..fSlash..tItem.n,unpack(fixArgs(cmd)))!@#& end!@#& end,!@#& },!@#& [\"Open With\"] = customLaunch,!@#& [\"Rename\"] = function(tItem)!@#& local sName = InputBox(\"New Name\")!@#& if type(sName) == \"string\" and sName ~= \"\" then!@#& local s, m = pcall(function()!@#& fs.move(stringPath()..fSlash..tItem.n,stringPath()..fSlash..sName)!@#& end)!@#& if not s then!@#& dialogBox(\"Error\", (m or \"Rename failed\"), {\"ok\"})!@#& end!@#& end!@#& newList()!@#& end,!@#& [\"Delete\"] = function(tItem)!@#& if dialogBox(\"Confirm\",\"Delete \"..tItem.id..\" \"..tItem.n,{\"yes\",\"no\"}) == 1 then!@#& if fs.isReadOnly(stringPath()..fSlash..tItem.n) then!@#& dialogBox(\"ERROR\",tItem.id..\" Is read Only\",{\"ok\"})!@#& else!@#& fs.delete(stringPath()..fSlash..tItem.n)!@#& newList()!@#& end!@#& end!@#& end,!@#& [\"Cut\"] = function(tItem)!@#& clipboard = {stringPath(), tItem.n}!@#& cut = true!@#& end,!@#& [\"Copy\"] = function(tItem)!@#& clipboard = {stringPath(), tItem.n}!@#& cut = false!@#& end!@#& },!@#& audio = {!@#& [\"Play\"] = 1,!@#& [\"Eject\"] = 1!@#& },!@#& back = {!@#& },!@#& blank = { -- tmenu.blank.Paste = !@#& [\"Paste\"] = nil,!@#& [\"New File\"] = function()!@#& local name = InputBox()!@#& if name then!@#& if fs.exists(stringPath()..fSlash..name) then!@#& dialogBox(\"ERROR\",\"Name exists\",{\"ok\"})!@#& else!@#& local file = fs.open(stringPath()..fSlash..name,\"w\")!@#& if file then!@#& file.write(\"\")!@#& file.close()!@#& newList()!@#& else!@#& dialogBox(\"ERROR\",\"File not created\",{\"ok\"})!@#& end!@#& end!@#& end!@#& end,!@#& [\"New Folder\"] = function()!@#& local name = InputBox()!@#& if name then!@#& if fs.exists(stringPath()..fSlash..name) then!@#& dialogBox(\"ERROR\",\"Name exists\",{\"ok\"})!@#& else!@#& if pcall(fs.makeDir,stringPath()..fSlash..name) then!@#& newList()!@#& else!@#& dialogBox(\"ERROR\",\"Access Denied\",{\"ok\"})!@#& end!@#& end!@#& end!@#& end,!@#& [\"Preferences\"] = preferences!@#& },!@#& }!@#& !@#& -- end right click menu!@#& !@#& local function scrollBar(posX,posY)!@#& if posX == boxOffX+boxW+1 and posY > boxOffY and posY <= boxOffY+boxH then!@#& if #tItemList > boxH then!@#& if posY == boxOffY + 1 then!@#& listOff = 0!@#& elseif posY == boxOffY+boxH then!@#& listOff = #tItemList + 1 - boxH!@#& else!@#& listOff = math.ceil((posY - boxOffY - 1 )*(((#tItemList - boxH+2)/boxH)))!@#& end!@#& flag = true!@#& end!@#& end!@#& end!@#& !@#& newList()!@#& !@#& while bRun do!@#& if flag then!@#& flag = false!@#& -- clear!@#& if oldHight ~= hight and oldWidth ~= width then!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& oldHight,oldWidth = hight,width!@#& end!@#& -- draw top title bar!@#& local b = tbarW - #title -2!@#& if b < 0 then!@#& b = 0!@#& end!@#& printC(tbarX,tbarY,titleBar.txt,titleBar.back,string.sub(\" \"..title,1,tbarW)..string.rep(\" \",b))!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.red)!@#& term.write(\"X\")!@#& !@#& -- draw location bar!@#& local a = barW - #sPath - 1!@#& if a < 0 then!@#& a = 0!@#& end!@#& local tmppath = sPath!@#& if shell and shell.getDisplayName then!@#& tmppath = shell.getDisplayName(sPath)!@#& --dialogBox(\"yay\")!@#& else!@#& --dialogBox(\"moop\")!@#& end!@#& tmppath = tmppath or sPath!@#& local a = barW - #tmppath - 1!@#& if a < 0 then!@#& a = 0!@#& end!@#& printC(barX,barY,addressBar.txt,addressBar.back,string.sub(\" \"..tmppath,1,barW)..string.rep(\" \",a))!@#& !@#& -- draw scroll bar!@#& if #tItemList > boxH then!@#& term.setBackgroundColor(scrollCol.back)!@#& for i = 1,boxH do!@#& term.setCursorPos(boxOffX+boxW+1,i + boxOffY)!@#& local scroll = math.floor( boxH* (listOff/(#tItemList-boxH+2)) )+1!@#& if i == scroll then!@#& term.setBackgroundColor(scrollCol.button)!@#& term.write(\" \")!@#& term.setBackgroundColor(scrollCol.back)!@#& else!@#& term.write(\" \")!@#& end!@#& end!@#& else!@#& term.setBackgroundColor(scrollCol.off)!@#& for i = 1,boxH do!@#& term.setCursorPos(boxOffX+boxW+1,i + boxOffY)!@#& term.write(\" \")!@#& end!@#& end!@#& !@#& -- draw main section!@#&!@#& for i = 1,boxH do -- listOff!@#& local sel = i+listOff!@#& if tItemList[sel] then!@#& printC(1+boxOffX,i+boxOffY,(tIcons[tItemList[sel].id].tCol or itemWindo.txt),(tIcons[tItemList[sel].id].bCol or itemWindo.back),( tIcons[tItemList[sel].id].txt or \" \"))!@#& printC(4+boxOffX,i+boxOffY,itemWindo.txt,itemWindo.back,string.sub(\" \"..tItemList[sel].n..pading,1,boxW-3))!@#& else!@#& printC(1+boxOffX,i+boxOffY,itemWindo.txt,itemWindo.back,pading)!@#& end!@#& end!@#& !@#& if bugTest then!@#& printC(1,1,\"black\",\"white\",listOff..\" \"..boxOffY..\" \"..boxH)!@#& end!@#& !@#& end!@#& !@#& -- react to events!@#& local event = {os.pullEvent()}!@#& !@#& if event[1] == \"mouse_click\" then!@#& if inBouwndry(event[3],event[4],boxOffX+1,boxOffY+1,boxW,boxH) then!@#& local selected = tItemList[event[4]+listOff-boxOffY]!@#& if selected and inBouwndry(event[3],event[4],boxOffX+1,event[4],#selected.n + 4,1) then!@#& if event[2] == 1 then -- left mouse!@#& if selected.id == \"back\" then!@#& table.remove(path,#path)!@#& newList()!@#& elseif selected.id == \"folder\" or selected.id == \"disk\" then!@#& table.insert(path,selected.n)!@#& newList()!@#& elseif selected.id == \"file\" then!@#& if dialogBox(\"Run file ?\",selected.n,{\"yes\",\"no\"}) == 1 then!@#& osRunSpaces(stringPath()..fSlash..selected.n)!@#& end!@#& flag = true!@#& end!@#& elseif event[2] == 2 then -- right mouse!@#& rClickMenu(\"Options\",tmenu[selected.id],selected,event[3],event[4])!@#& flag = true!@#& end!@#& elseif event[2] == 2 then -- right clicking not on object!@#& if clipboard then!@#& tmenu.blank.Paste = paste!@#& else!@#& tmenu.blank.Paste = nil!@#& end!@#& rClickMenu(\"Options\",tmenu[\"blank\"],selected,event[3],event[4])!@#& flag = true!@#& end!@#& elseif event[2] == 1 and event[3] == exitX and event[4] == exitY then!@#& if dialogBox(\"Confirm\",\"Exit application\",{\"yes\",\"no\"}) == 1 then!@#& bRun = false!@#& end!@#& flag = true!@#& elseif event[2] == 1 then!@#& scrollBar(event[3],event[4])!@#& end!@#& elseif event[1] == \"mouse_scroll\" then -- flag this needs new math!@#& local old = listOff!@#& listOff = listOff + event[2]!@#& if listOff < 0 then!@#& listOff = 0!@#& end!@#& if #tItemList + 1 - boxH > 0 and listOff > #tItemList + 1 - boxH then!@#& listOff = #tItemList + 1 - boxH!@#& elseif listOff > 0 and #tItemList + 1 - boxH < 0 then!@#& listOff = 0!@#& end!@#& if listOff ~= old then!@#& flag = true!@#& end!@#& !@#& elseif event[1] == \"mouse_drag\" then -- scroll bar!@#& scrollBar(event[3],event[4])!@#& elseif event[1] == \"disk\" or event[1] == \"disk_eject\" then!@#& newList()!@#& elseif event[1] == \"window_resize\" then!@#& termX,termY = term.getSize()!@#& offsetX,offsetY = 1,1!@#& hight,width = math.ceil(termY-2),math.ceil(termX-2)!@#& !@#& boxOffX,boxOffY = offsetX,offsetY + 2!@#& boxH,boxW = hight - 2 ,width - 2!@#& !@#& barX,barY = offsetX + 1,offsetY + 2!@#& barH,barW = 1,width - 1!@#& !@#& tbarX,tbarY = offsetX + 1,offsetY + 1!@#& tbarH,tbarW = 1,width - 1!@#& !@#& exitX,exitY = offsetX + width - 1 ,offsetY + 1!@#& pading = string.rep(\" \",boxW)!@#& !@#& flag = true!@#& elseif event[1] == \"redraw\" then!@#& flag = true!@#& end!@#& end!@#&end!@#&!@#&local function main()!@#& if term.isColor() then!@#& clear()!@#& fileSelect()!@#& clear()!@#& else!@#& error(\"Not an Advanced Computer (gold) \")!@#& end!@#&end!@#&!@#&local trash = (norun or main())",["opts"]="",["lmail"]="sel = sysconf.theme_sel!@#&desel = sysconf.theme_desel!@#&background = sysconf.theme_background",["boot"]={["loadapis"]="list = fs.list(\"/lib/libapi/\")!@#&for i = 1,#list do!@#& api = os.loadAPI(\"/lib/libapi/\" .. list[i])!@#&end",},["optlib"]={["usrs"]="local function createNew(un)!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& write(\"Password? \")!@#& np = read(\"*\")!@#& usrs[un] = hash.sha256(np)!@#& nf = textutils.serialize(usrs)!@#& sv = fs.open(\"/lib/usr/users\", \"w\")!@#& sv.writeLine(nf)!@#& sv.close()!@#& print(\"OK!\")!@#& sleep(2)!@#& os.reboot()!@#&end!@#&!@#&local function modify(un)!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& write(\"New password? \")!@#& np = read(\"*\")!@#& usrs[un] = hash.sha256(np)!@#& nf = textutils.serialize(usrs)!@#& sv = fs.open(\"/lib/usr/users\", \"w\")!@#& sv.writeLine(nf)!@#& sv.close()!@#& print(\"OK!\")!@#& sleep(2)!@#& os.reboot()!@#&end!@#&!@#&usrs = linox.getUserFile()!@#&term.setBackgroundColor(colors.black)!@#&term.setTextColor(colors.white)!@#&term.clear()!@#&term.setCursorPos(1,1)!@#&print(\"Please enter the name of a user (it doesn't need to exist) or type exit to exit.\")!@#&user = read()!@#&if user == \"exit\" then!@#& os.reboot()!@#&end!@#&if not usrs[user] then!@#& createNew(user)!@#&else!@#& modify(user)!@#&end",["opts"]="if not sudo.isAdmin() then!@#& print(\"Privs not sufficient.\")!@#& write(\"For more information go to \")!@#& term.setTextColor(colors.yellow)!@#& print(\"http://zudohackz.kd.io\")!@#& term.setTextColor(colors.white)!@#& error()!@#&end!@#&!@#&w,h = term.getSize()!@#&function printc(str,l)!@#& term.setCursorPos(w/2-#str/2,l)!@#& print(str)!@#&end!@#&!@#&term.setBackgroundColor(colors.lightGray)!@#&term.clear()!@#&term.setCursorPos(1,1)!@#&term.setBackgroundColor(colors.white)!@#&write(string.rep(\" \",w))!@#&term.setTextColor(colors.black)!@#&printc(\"System Settings\",1)!@#&quit = \"[Quit]\"!@#&term.setCursorPos(w-#quit,1)!@#&print(quit)!@#&term.setTextColor(colors.white)!@#&term.setCursorPos(3,8)!@#&term.setBackgroundColor(colors.red)!@#&print(\" \")!@#&term.setCursorPos(3,9)!@#&print(\" PC Name \")!@#&term.setCursorPos(3,10)!@#&print(\" \")!@#&term.setBackgroundColor(colors.lime)!@#&term.setCursorPos(20,8)!@#&print(\" \")!@#&term.setCursorPos(20,9)!@#&print(\" Users \")!@#&term.setCursorPos(20,10)!@#&print(\" \")!@#&function getClickPos()!@#& _,b,xpos,ypos = os.pullEvent(\"mouse_click\")!@#& if ypos == 8 or ypos == 9 or ypos == 10 then!@#& if xpos == 3 or xpos == 4 or xpos == 5 or xpos == 6 or xpos == 7 or xpos == 8 or xpos == 9 or xpos == 10 or xpos == 11 or xpos == 12 then!@#& return \"pcname\"!@#& elseif xpos == 20 or xpos == 21 or xpos == 22 or xpos == 23 or xpos == 24 or xpos == 25 or xpos == 26 or xpos == 27 or xpos == 28 or xpos == 29 then!@#& return \"users\"!@#& end!@#& elseif ypos == 1 then!@#& if xpos == w-#quit or xpos == w-#quit+1 or xpos == w-#quit+2 or xpos == w-#quit+3 or xpos == w-#quit+4 or xpos == w-#quit+5 or w-#quit+6 then!@#& os.reboot()!@#& end!@#& end!@#&end!@#&!@#&while true do!@#& option = getClickPos()!@#& if option == \"pcname\" then!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& write(\"New Name: \")!@#& os.setComputerLabel(read())!@#& shell.run(\"opts\")!@#& elseif option == \"users\" then!@#& shell.run(\"/bin/optlib/usrs\")!@#& end!@#&end",},["clearc"]="if term.isColor() then!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.black)!@#&end!@#&term.clear()!@#&term.setCursorPos(1,1)",["plist"]="",["gksu"]="args = {...}!@#&if not sudo.isAdmin() then!@#&term.setCursorPos(w/2-l/2,h/2-2)!@#&term.setBackgroundColor(colors.red)!@#&print(\" \")!@#&term.setCursorPos(w/2-l/2,h/2-1)!@#&print(\" Password: \")!@#&term.setCursorPos(w/2-l/2,h/2)!@#&print(\" \")!@#&term.setCursorPos(w/2-l/2,h/2+1)!@#&print(\" \")!@#&term.setCursorPos(w/2-l/2,h/2+2)!@#&print(\" \")!@#&term.setCursorPos(w/2-l/2+2,h/2)!@#&pswd = read(\"*\")!@#&term.setBackgroundColor(colors.black)!@#&term.clear()!@#&term.setCursorPos(1,1)!@#&if pswd == \"\" then!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& error()!@#&end!@#&if sudo.getAdminPrivs(pswd) then!@#& fail = false!@#&else!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& error()!@#&end!@#&end!@#&shell.run(\"sudo\", args[1])",["luaide"]="!@#&-- !@#&-- Lua IDE!@#&-- Made by GravityScore!@#&-- !@#&!@#&!@#&-- -------- Variables!@#&!@#&-- Version!@#&local version = \"1.0\"!@#&local args = {...}!@#&!@#&-- Editing!@#&local w, h = term.getSize()!@#&local tabWidth = 2!@#&!@#&local autosaveInterval = 20!@#&local allowEditorEvent = true!@#&local keyboardShortcutTimeout = 0.4!@#&!@#&-- Clipboard!@#&local clipboard = nil!@#&!@#&-- Theme!@#&local theme = {}!@#&!@#&-- Language!@#&local languages = {}!@#&local curLanguage = {}!@#&!@#&-- Events!@#&local event_distract = \"luaide_distractionEvent\"!@#&!@#&-- Locations!@#&local updateURL = \"https://raw.github.com/GravityScore/LuaIDE/master/luaide.lua\"!@#&local ideLocation = \"/\" .. shell.getRunningProgram()!@#&local themeLocation = \"/.LuaIDE-Theme\"!@#&!@#&local function isAdvanced() return term.isColor and term.isColor() end!@#&!@#&!@#&-- -------- Utilities!@#&!@#&local function modRead(properties)!@#& local w, h = term.getSize()!@#& local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, !@#& liveUpdates = nil, exitOnKey = nil}!@#& if not properties then properties = {} end!@#& for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end!@#& if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end!@#& if not properties.visibleLength then properties.visibleLength = w end!@#&!@#& local sx, sy = term.getCursorPos()!@#& local line = \"\"!@#& local pos = 0!@#& local historyPos = nil!@#&!@#& local function redraw(repl)!@#& local scroll = 0!@#& if properties.visibleLength and sx + pos > properties.visibleLength + 1 then !@#& scroll = (sx + pos) - (properties.visibleLength + 1)!@#& end!@#&!@#& term.setCursorPos(sx, sy)!@#& local a = repl or properties.replaceChar!@#& if a then term.write(string.rep(a, line:len() - scroll))!@#& else term.write(line:sub(scroll + 1, -1)) end!@#& term.setCursorPos(sx + pos - scroll, sy)!@#& end!@#&!@#& local function sendLiveUpdates(event, ...)!@#& if type(properties.liveUpdates) == \"function\" then!@#& local ox, oy = term.getCursorPos()!@#& local a, data = properties.liveUpdates(line, event, ...)!@#& if a == true and data == nil then!@#& term.setCursorBlink(false)!@#& return line!@#& elseif a == true and data ~= nil then!@#& term.setCursorBlink(false)!@#& return data!@#& end!@#& term.setCursorPos(ox, oy)!@#& end!@#& end!@#&!@#& term.setCursorBlink(true)!@#& while true do!@#& local e, but, x, y, p4, p5 = os.pullEvent()!@#&!@#& if e == \"char\" then!@#& local s = false!@#& if properties.textLength and line:len() < properties.textLength then s = true!@#& elseif not properties.textLength then s = true end!@#&!@#& local canType = true!@#& if not properties.grantPrint and properties.refusePrint then!@#& local canTypeKeys = {}!@#& if type(properties.refusePrint) == \"table\" then!@#& for _, v in pairs(properties.refusePrint) do!@#& table.insert(canTypeKeys, tostring(v):sub(1, 1))!@#& end!@#& elseif type(properties.refusePrint) == \"string\" then!@#& for char in properties.refusePrint:gmatch(\".\") do!@#& table.insert(canTypeKeys, char)!@#& end!@#& end!@#& for _, v in pairs(canTypeKeys) do if but == v then canType = false end end!@#& elseif properties.grantPrint then!@#& canType = false!@#& local canTypeKeys = {}!@#& if type(properties.grantPrint) == \"table\" then!@#& for _, v in pairs(properties.grantPrint) do!@#& table.insert(canTypeKeys, tostring(v):sub(1, 1))!@#& end!@#& elseif type(properties.grantPrint) == \"string\" then!@#& for char in properties.grantPrint:gmatch(\".\") do!@#& table.insert(canTypeKeys, char)!@#& end!@#& end!@#& for _, v in pairs(canTypeKeys) do if but == v then canType = true end end!@#& end!@#&!@#& if s and canType then!@#& line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)!@#& pos = pos + 1!@#& redraw()!@#& end!@#& elseif e == \"key\" then!@#& if but == keys.enter then break!@#& elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end!@#& elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end!@#& elseif (but == keys.up or but == keys.down) and properties.history then!@#& redraw(\" \")!@#& if but == keys.up then!@#& if historyPos == nil and #properties.history > 0 then !@#& historyPos = #properties.history!@#& elseif historyPos > 1 then !@#& historyPos = historyPos - 1!@#& end!@#& elseif but == keys.down then!@#& if historyPos == #properties.history then historyPos = nil!@#& elseif historyPos ~= nil then historyPos = historyPos + 1 end!@#& end!@#&!@#& if properties.history and historyPos then!@#& line = properties.history[historyPos]!@#& pos = line:len()!@#& else!@#& line = \"\"!@#& pos = 0!@#& end!@#&!@#& redraw()!@#& local a = sendLiveUpdates(\"history\")!@#& if a then return a end!@#& elseif but == keys.backspace and pos > 0 then!@#& redraw(\" \")!@#& line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)!@#& pos = pos - 1!@#& redraw()!@#& local a = sendLiveUpdates(\"delete\")!@#& if a then return a end!@#& elseif but == keys.home then!@#& pos = 0!@#& redraw()!@#& elseif but == keys.delete and pos < line:len() then!@#& redraw(\" \")!@#& line = line:sub(1, pos) .. line:sub(pos + 2, -1)!@#& redraw()!@#& local a = sendLiveUpdates(\"delete\")!@#& if a then return a end!@#& elseif but == keys[\"end\"] then!@#& pos = line:len()!@#& redraw()!@#& elseif properties.exitOnKey then !@#& if but == properties.exitOnKey or (properties.exitOnKey == \"control\" and !@#& (but == 29 or but == 157)) then !@#& term.setCursorBlink(false)!@#& return nil!@#& end!@#& end!@#& end!@#& local a = sendLiveUpdates(e, but, x, y, p4, p5)!@#& if a then return a end!@#& end!@#&!@#& term.setCursorBlink(false)!@#& if line ~= nil then line = line:gsub(\"^%s*(.-)%s*$\", \"%1\") end!@#& return line!@#&end!@#&!@#&!@#&-- -------- Themes!@#&!@#&local defaultTheme = {!@#& background = \"gray\",!@#& backgroundHighlight = \"lightGray\",!@#& prompt = \"cyan\",!@#& promptHighlight = \"lightBlue\",!@#& err = \"red\",!@#& errHighlight = \"pink\",!@#&!@#& editorBackground = \"gray\",!@#& editorLineHightlight = \"lightBlue\",!@#& editorLineNumbers = \"gray\",!@#& editorLineNumbersHighlight = \"lightGray\",!@#& editorError = \"pink\",!@#& editorErrorHighlight = \"red\",!@#&!@#& textColor = \"white\",!@#& conditional = \"yellow\",!@#& constant = \"orange\",!@#& [\"function\"] = \"magenta\",!@#& string = \"red\",!@#& comment = \"lime\"!@#&}!@#&!@#&local normalTheme = {!@#& background = \"black\",!@#& backgroundHighlight = \"black\",!@#& prompt = \"black\",!@#& promptHighlight = \"black\",!@#& err = \"black\",!@#& errHighlight = \"black\",!@#&!@#& editorBackground = \"black\",!@#& editorLineHightlight = \"black\",!@#& editorLineNumbers = \"black\",!@#& editorLineNumbersHighlight = \"white\",!@#& editorError = \"black\",!@#& editorErrorHighlight = \"black\",!@#&!@#& textColor = \"white\",!@#& conditional = \"white\",!@#& constant = \"white\",!@#& [\"function\"] = \"white\",!@#& string = \"white\",!@#& comment = \"white\"!@#&}!@#&!@#&local availableThemes = {!@#& {\"Water (Default)\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/default.txt\"},!@#& {\"Fire\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/fire.txt\"},!@#& {\"Sublime Text 2\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/st2.txt\"},!@#& {\"Midnight\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/midnight.txt\"},!@#& {\"TheOriginalBIT\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/bit.txt\"},!@#& {\"Superaxander\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/superaxander.txt\"},!@#& {\"Forest\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/forest.txt\"},!@#& {\"Night\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/night.txt\"},!@#& {\"Original\", \"https://raw.github.com/GravityScore/LuaIDE/master/themes/original.txt\"},!@#&}!@#&!@#&local function loadTheme(path)!@#& local f = io.open(path)!@#& local l = f:read(\"*l\")!@#& local config = {}!@#& while l ~= nil do!@#& local k, v = string.match(l, \"^(%a+)=(%a+)\")!@#& if k and v then config[k] = v end!@#& l = f:read(\"*l\")!@#& end!@#& f:close()!@#& return config!@#&end!@#&!@#&-- Load Theme!@#&if isAdvanced() then theme = defaultTheme!@#&else theme = normalTheme end!@#&!@#&!@#&-- -------- Drawing!@#&!@#&local function centerPrint(text, ny)!@#& if type(text) == \"table\" then for _, v in pairs(text) do centerPrint(v) end!@#& else!@#& local x, y = term.getCursorPos()!@#& local w, h = term.getSize()!@#& term.setCursorPos(w/2 - text:len()/2 + (#text % 2 == 0 and 1 or 0), ny or y)!@#& print(text)!@#& end!@#&end!@#&!@#&local function title(t)!@#& term.setTextColor(colors[theme.textColor])!@#& term.setBackgroundColor(colors[theme.background])!@#& term.clear()!@#&!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& for i = 2, 4 do term.setCursorPos(1, i) term.clearLine() end!@#& term.setCursorPos(3, 3)!@#& term.write(t)!@#&end!@#&!@#&local function centerRead(wid, begt)!@#& local function liveUpdate(line, e, but, x, y, p4, p5)!@#& if isAdvanced() and e == \"mouse_click\" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10 !@#& and y >= 13 and y <= 15 then!@#& return true, \"\"!@#& end!@#& end!@#&!@#& if not begt then begt = \"\" end!@#& term.setTextColor(colors[theme.textColor])!@#& term.setBackgroundColor(colors[theme.promptHighlight])!@#& for i = 8, 10 do!@#& term.setCursorPos(w/2 - wid/2, i)!@#& term.write(string.rep(\" \", wid))!@#& end!@#&!@#& if isAdvanced() then!@#& term.setBackgroundColor(colors[theme.errHighlight])!@#& for i = 13, 15 do!@#& term.setCursorPos(w/2 - wid/2 + 1, i)!@#& term.write(string.rep(\" \", 10))!@#& end!@#& term.setCursorPos(w/2 - wid/2 + 2, 14)!@#& term.write(\"> Cancel\")!@#& end!@#&!@#& term.setBackgroundColor(colors[theme.promptHighlight])!@#& term.setCursorPos(w/2 - wid/2 + 1, 9)!@#& term.write(\"> \" .. begt)!@#& return modRead({visibleLength = w/2 + wid/2, liveUpdates = liveUpdate})!@#&end!@#&!@#&!@#&-- -------- Prompt!@#&!@#&local function prompt(list, dir, isGrid)!@#& local function draw(sel)!@#& for i, v in ipairs(list) do!@#& if i == sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])!@#& else term.setBackgroundColor(v.bg or colors[theme.prompt]) end!@#& term.setTextColor(v.tc or colors[theme.textColor])!@#& for i = -1, 1 do!@#& term.setCursorPos(v[2], v[3] + i)!@#& term.write(string.rep(\" \", v[1]:len() + 4))!@#& end!@#&!@#& term.setCursorPos(v[2], v[3])!@#& if i == sel then!@#& term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])!@#& term.write(\" > \")!@#& else term.write(\" - \") end!@#& term.write(v[1] .. \" \")!@#& end!@#& end!@#&!@#& local key1 = dir == \"horizontal\" and 203 or 200!@#& local key2 = dir == \"horizontal\" and 205 or 208!@#& local sel = 1!@#& draw(sel)!@#&!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"key\" and but == 28 then!@#& return list[sel][1]!@#& elseif e == \"key\" and but == key1 and sel > 1 then!@#& sel = sel - 1!@#& draw(sel)!@#& elseif e == \"key\" and but == key2 and ((err == true and sel < #list - 1) or (sel < #list)) then!@#& sel = sel + 1!@#& draw(sel)!@#& elseif isGrid and e == \"key\" and but == 203 and sel > 2 then!@#& sel = sel - 2!@#& draw(sel)!@#& elseif isGrid and e == \"key\" and but == 205 and sel < 3 then!@#& sel = sel + 2!@#& draw(sel)!@#& elseif e == \"mouse_click\" then!@#& for i, v in ipairs(list) do!@#& if x >= v[2] - 1 and x <= v[2] + v[1]:len() + 3 and y >= v[3] - 1 and y <= v[3] + 1 then!@#& return list[i][1]!@#& end!@#& end!@#& end!@#& end!@#&end!@#&!@#&local function scrollingPrompt(list)!@#& local function draw(items, sel, loc)!@#& for i, v in ipairs(items) do!@#& local bg = colors[theme.prompt]!@#& local bghigh = colors[theme.promptHighlight]!@#& if v:find(\"Back\") or v:find(\"Return\") then!@#& bg = colors[theme.err]!@#& bghigh = colors[theme.errHighlight]!@#& end!@#&!@#& if i == sel then term.setBackgroundColor(bghigh)!@#& else term.setBackgroundColor(bg) end!@#& term.setTextColor(colors[theme.textColor])!@#& for x = -1, 1 do!@#& term.setCursorPos(3, (i * 4) + x + 4)!@#& term.write(string.rep(\" \", w - 13))!@#& end!@#&!@#& term.setCursorPos(3, i * 4 + 4)!@#& if i == sel then!@#& term.setBackgroundColor(bghigh)!@#& term.write(\" > \")!@#& else term.write(\" - \") end!@#& term.write(v .. \" \")!@#& end!@#& end!@#&!@#& local function updateDisplayList(items, loc, len)!@#& local ret = {}!@#& for i = 1, len do!@#& local item = items[i + loc - 1]!@#& if item then table.insert(ret, item) end!@#& end!@#& return ret!@#& end!@#&!@#& -- Variables!@#& local sel = 1!@#& local loc = 1!@#& local len = 3!@#& local disList = updateDisplayList(list, loc, len)!@#& draw(disList, sel, loc)!@#&!@#& -- Loop!@#& while true do!@#& local e, key, x, y = os.pullEvent()!@#&!@#& if e == \"mouse_click\" then!@#& for i, v in ipairs(disList) do!@#& if x >= 3 and x <= w - 11 and y >= i * 4 + 3 and y <= i * 4 + 5 then return v end!@#& end!@#& elseif e == \"key\" and key == 200 then!@#& if sel > 1 then!@#& sel = sel - 1!@#& draw(disList, sel, loc)!@#& elseif loc > 1 then!@#& loc = loc - 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList, sel, loc)!@#& end!@#& elseif e == \"key\" and key == 208 then!@#& if sel < len then!@#& sel = sel + 1!@#& draw(disList, sel, loc)!@#& elseif loc + len - 1 < #list then!@#& loc = loc + 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList, sel, loc)!@#& end!@#& elseif e == \"mouse_scroll\" then!@#& os.queueEvent(\"key\", key == -1 and 200 or 208)!@#& elseif e == \"key\" and key == 28 then!@#& return disList[sel]!@#& end!@#& end!@#&end!@#&!@#&function monitorKeyboardShortcuts()!@#& local ta, tb = nil, nil!@#& local allowChar = false!@#& local shiftPressed = false!@#& while true do!@#& local event, char = os.pullEvent()!@#& if event == \"key\" and (char == 42 or char == 52) then!@#& shiftPressed = true!@#& tb = os.startTimer(keyboardShortcutTimeout)!@#& elseif event == \"key\" and (char == 29 or char == 157 or char == 219 or char == 220) then!@#& allowEditorEvent = false!@#& allowChar = true!@#& ta = os.startTimer(keyboardShortcutTimeout)!@#& elseif event == \"key\" and allowChar then!@#& local name = nil!@#& for k, v in pairs(keys) do!@#& if v == char then!@#& if shiftPressed then os.queueEvent(\"shortcut\", \"ctrl shift\", k:lower())!@#& else os.queueEvent(\"shortcut\", \"ctrl\", k:lower()) end!@#& sleep(0.005)!@#& allowEditorEvent = true!@#& end!@#& end!@#& if shiftPressed then os.queueEvent(\"shortcut\", \"ctrl shift\", char)!@#& else os.queueEvent(\"shortcut\", \"ctrl\", char) end!@#& elseif event == \"timer\" and char == ta then!@#& allowEditorEvent = true!@#& allowChar = false!@#& elseif event == \"timer\" and char == tb then!@#& shiftPressed = false!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Saving and Loading!@#&!@#&local function download(url, path)!@#& for i = 1, 3 do!@#& local response = http.get(url)!@#& if response then!@#& local data = response.readAll()!@#& response.close()!@#& if path then!@#& local f = io.open(path, \"w\")!@#& f:write(data)!@#& f:close()!@#& end!@#& return true!@#& end!@#& end!@#&!@#& return false!@#&end!@#&!@#&local function saveFile(path, lines)!@#& local dir = path:sub(1, path:len() - fs.getName(path):len())!@#& if not fs.exists(dir) then fs.makeDir(dir) end!@#& if not fs.isDir(path) and not fs.isReadOnly(path) then!@#& local a = \"\"!@#& for _, v in pairs(lines) do a = a .. v .. \"\\n\" end!@#&!@#& local f = io.open(path, \"w\")!@#& f:write(a)!@#& f:close()!@#& return true!@#& else return false end!@#&end!@#&!@#&local function loadFile(path)!@#& if not fs.exists(path) then!@#& local dir = path:sub(1, path:len() - fs.getName(path):len())!@#& if not fs.exists(dir) then fs.makeDir(dir) end!@#& local f = io.open(path, \"w\")!@#& f:write(\"\")!@#& f:close()!@#& end!@#&!@#& local l = {}!@#& if fs.exists(path) and not fs.isDir(path) then!@#& local f = io.open(path, \"r\")!@#& if f then!@#& local a = f:read(\"*l\")!@#& while a do!@#& table.insert(l, a)!@#& a = f:read(\"*l\")!@#& end!@#& f:close()!@#& end!@#& else return nil end!@#&!@#& if #l < 1 then table.insert(l, \"\") end!@#& return l!@#&end!@#&!@#&!@#&-- -------- Languages!@#&!@#&languages.lua = {}!@#&languages.brainfuck = {}!@#&languages.none = {}!@#&!@#&-- Lua!@#&!@#&languages.lua.helpTips = {!@#& \"A function you tried to call doesn't exist.\",!@#& \"You made a typo.\",!@#& \"The index of an array is nil.\",!@#& \"The wrong variable type was passed.\",!@#& \"A function/variable doesn't exist.\",!@#& \"You missed an 'end'.\",!@#& \"You missed a 'then'.\",!@#& \"You declared a variable incorrectly.\",!@#& \"One of your variables is mysteriously nil.\"!@#&}!@#&!@#&languages.lua.defaultHelpTips = {!@#& 2, 5!@#&}!@#&!@#&languages.lua.errors = {!@#& [\"Attempt to call nil.\"] = {1, 2},!@#& [\"Attempt to index nil.\"] = {3, 2},!@#& [\".+ expected, got .+\"] = {4, 2, 9},!@#& [\"'end' expected\"] = {6, 2},!@#& [\"'then' expected\"] = {7, 2},!@#& [\"'=' expected\"] = {8, 2}!@#&}!@#&!@#&languages.lua.keywords = {!@#& [\"and\"] = \"conditional\",!@#& [\"break\"] = \"conditional\",!@#& [\"do\"] = \"conditional\",!@#& [\"else\"] = \"conditional\",!@#& [\"elseif\"] = \"conditional\",!@#& [\"end\"] = \"conditional\",!@#& [\"for\"] = \"conditional\",!@#& [\"function\"] = \"conditional\",!@#& [\"if\"] = \"conditional\",!@#& [\"in\"] = \"conditional\",!@#& [\"local\"] = \"conditional\",!@#& [\"not\"] = \"conditional\",!@#& [\"or\"] = \"conditional\",!@#& [\"repeat\"] = \"conditional\",!@#& [\"return\"] = \"conditional\",!@#& [\"then\"] = \"conditional\",!@#& [\"until\"] = \"conditional\",!@#& [\"while\"] = \"conditional\",!@#&!@#& [\"true\"] = \"constant\",!@#& [\"false\"] = \"constant\",!@#& [\"nil\"] = \"constant\",!@#&!@#& [\"print\"] = \"function\",!@#& [\"write\"] = \"function\",!@#& [\"sleep\"] = \"function\",!@#& [\"pairs\"] = \"function\",!@#& [\"ipairs\"] = \"function\",!@#& [\"loadstring\"] = \"function\",!@#& [\"loadfile\"] = \"function\",!@#& [\"dofile\"] = \"function\",!@#& [\"rawset\"] = \"function\",!@#& [\"rawget\"] = \"function\",!@#& [\"setfenv\"] = \"function\",!@#& [\"getfenv\"] = \"function\",!@#&}!@#&!@#&languages.lua.parseError = function(e)!@#& local ret = {filename = \"unknown\", line = -1, display = \"Unknown!\", err = \"\"}!@#& if e and e ~= \"\" then!@#& ret.err = e!@#& if e:find(\":\") then!@#& ret.filename = e:sub(1, e:find(\":\") - 1):gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& -- The \"\" is needed to circumvent a CC bug!@#& e = (e:sub(e:find(\":\") + 1) .. \"\"):gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& if e:find(\":\") then!@#& ret.line = e:sub(1, e:find(\":\") - 1)!@#& e = e:sub(e:find(\":\") + 2):gsub(\"^%s*(.-)%s*$\", \"%1\") .. \"\"!@#& end!@#& end!@#& ret.display = e:sub(1, 1):upper() .. e:sub(2, -1) .. \".\"!@#& end!@#&!@#& return ret!@#&end!@#&!@#&languages.lua.getCompilerErrors = function(code)!@#& code = \"local function ee65da6af1cb6f63fee9a081246f2fd92b36ef2(...)\\n\\n\" .. code .. \"\\n\\nend\"!@#& local fn, err = loadstring(code)!@#& if not err then!@#& local _, e = pcall(fn)!@#& if e then err = e end!@#& end!@#&!@#& if err then!@#& local a = err:find(\"]\", 1, true)!@#& if a then err = \"string\" .. err:sub(a + 1, -1) end!@#& local ret = languages.lua.parseError(err)!@#& if tonumber(ret.line) then ret.line = tonumber(ret.line) end!@#& return ret!@#& else return languages.lua.parseError(nil) end!@#&end!@#&!@#&languages.lua.run = function(path, ar)!@#& local fn, err = loadfile(path)!@#& setfenv(fn, getfenv())!@#& if not err then!@#& _, err = pcall(function() fn(unpack(ar)) end)!@#& end!@#& return err!@#&end!@#&!@#&!@#&-- Brainfuck!@#&!@#&languages.brainfuck.helpTips = {!@#& \"Well idk...\",!@#& \"Isn't this the whole point of the language?\",!@#& \"Ya know... Not being able to debug it?\",!@#& \"You made a typo.\"!@#&}!@#&!@#&languages.brainfuck.defaultHelpTips = {!@#& 1, 2, 3!@#&}!@#&!@#&languages.brainfuck.errors = {!@#& [\"No matching '['\"] = {1, 2, 3, 4}!@#&}!@#&!@#&languages.brainfuck.keywords = {}!@#&!@#&languages.brainfuck.parseError = function(e)!@#& local ret = {filename = \"unknown\", line = -1, display = \"Unknown!\", err = \"\"}!@#& if e and e ~= \"\" then!@#& ret.err = e!@#& ret.line = e:sub(1, e:find(\":\") - 1)!@#& e = e:sub(e:find(\":\") + 2):gsub(\"^%s*(.-)%s*$\", \"%1\") .. \"\"!@#& ret.display = e:sub(1, 1):upper() .. e:sub(2, -1) .. \".\"!@#& end!@#&!@#& return ret!@#&end!@#&!@#&languages.brainfuck.mapLoops = function(code)!@#& -- Map loops!@#& local loopLocations = {}!@#& local loc = 1!@#& local line = 1!@#& for let in string.gmatch(code, \".\") do!@#& if let == \"[\" then!@#& loopLocations[loc] = true!@#& elseif let == \"]\" then!@#& local found = false!@#& for i = loc, 1, -1 do !@#& if loopLocations[i] == true then!@#& loopLocations[i] = loc!@#& found = true!@#& end!@#& end!@#&!@#& if not found then!@#& return line .. \": No matching '['\"!@#& end!@#& end!@#&!@#& if let == \"\\n\" then line = line + 1 end!@#& loc = loc + 1!@#& end!@#& return loopLocations!@#&end!@#&!@#&languages.brainfuck.getCompilerErrors = function(code)!@#& local a = languages.brainfuck.mapLoops(code)!@#& if type(a) == \"string\" then return languages.brainfuck.parseError(a)!@#& else return languages.brainfuck.parseError(nil) end!@#&end!@#&!@#&languages.brainfuck.run = function(path)!@#& -- Read from file!@#& local f = io.open(path, \"r\")!@#& local content = f:read(\"*a\")!@#& f:close()!@#&!@#& -- Define environment!@#& local dataCells = {}!@#& local dataPointer = 1!@#& local instructionPointer = 1!@#&!@#& -- Map loops!@#& local loopLocations = languages.brainfuck.mapLoops(content)!@#& if type(loopLocations) == \"string\" then return loopLocations end!@#&!@#& -- Execute code!@#& while true do!@#& local let = content:sub(instructionPointer, instructionPointer)!@#&!@#& if let == \">\" then!@#& dataPointer = dataPointer + 1!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& elseif let == \"<\" then!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& dataPointer = dataPointer - 1!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& elseif let == \"+\" then!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& dataCells[tostring(dataPointer)] = dataCells[tostring(dataPointer)] + 1!@#& elseif let == \"-\" then!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& dataCells[tostring(dataPointer)] = dataCells[tostring(dataPointer)] - 1!@#& elseif let == \".\" then!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& if term.getCursorPos() >= w then print(\"\") end!@#& write(string.char(math.max(1, dataCells[tostring(dataPointer)])))!@#& elseif let == \",\" then!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& term.setCursorBlink(true)!@#& local e, but = os.pullEvent(\"char\")!@#& term.setCursorBlink(false)!@#& dataCells[tostring(dataPointer)] = string.byte(but)!@#& if term.getCursorPos() >= w then print(\"\") end!@#& write(but)!@#& elseif let == \"/\" then!@#& if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end!@#& if term.getCursorPos() >= w then print(\"\") end!@#& write(dataCells[tostring(dataPointer)])!@#& elseif let == \"[\" then!@#& if dataCells[tostring(dataPointer)] == 0 then!@#& for k, v in pairs(loopLocations) do!@#& if k == instructionPointer then instructionPointer = v end!@#& end!@#& end!@#& elseif let == \"]\" then!@#& for k, v in pairs(loopLocations) do!@#& if v == instructionPointer then instructionPointer = k - 1 end!@#& end!@#& end!@#&!@#& instructionPointer = instructionPointer + 1!@#& if instructionPointer > content:len() then print(\"\") break end!@#& end!@#&end!@#&!@#&-- None!@#&!@#&languages.none.helpTips = {}!@#&languages.none.defaultHelpTips = {}!@#&languages.none.errors = {}!@#&languages.none.keywords = {}!@#&!@#&languages.none.parseError = function(err)!@#& return {filename = \"\", line = -1, display = \"\", err = \"\"}!@#&end!@#&!@#&languages.none.getCompilerErrors = function(code)!@#& return languages.none.parseError(nil)!@#&end!@#&!@#&languages.none.run = function(path) end!@#&!@#&!@#&-- Load language!@#&curLanguage = languages.lua!@#&!@#&!@#&-- -------- Run GUI!@#&!@#&local function viewErrorHelp(e)!@#& title(\"LuaIDE - Error Help\")!@#&!@#& local tips = nil!@#& for k, v in pairs(curLanguage.errors) do!@#& if e.display:find(k) then tips = v break end!@#& end!@#&!@#& term.setBackgroundColor(colors[theme.err])!@#& for i = 6, 8 do!@#& term.setCursorPos(5, i)!@#& term.write(string.rep(\" \", 35))!@#& end!@#&!@#& term.setBackgroundColor(colors[theme.prompt])!@#& for i = 10, 18 do!@#& term.setCursorPos(5, i)!@#& term.write(string.rep(\" \", 46))!@#& end!@#&!@#& if tips then!@#& term.setBackgroundColor(colors[theme.err])!@#& term.setCursorPos(6, 7)!@#& term.write(\"Error Help\")!@#&!@#& term.setBackgroundColor(colors[theme.prompt])!@#& for i, v in ipairs(tips) do!@#& term.setCursorPos(7, i + 10)!@#& term.write(\"- \" .. curLanguage.helpTips[v])!@#& end!@#& else!@#& term.setBackgroundColor(colors[theme.err])!@#& term.setCursorPos(6, 7)!@#& term.write(\"No Error Tips Available!\")!@#&!@#& term.setBackgroundColor(colors[theme.prompt])!@#& term.setCursorPos(6, 11)!@#& term.write(\"There are no error tips available, but\")!@#& term.setCursorPos(6, 12)!@#& term.write(\"you could see if it was any of these:\")!@#&!@#& for i, v in ipairs(curLanguage.defaultHelpTips) do!@#& term.setCursorPos(7, i + 12)!@#& term.write(\"- \" .. curLanguage.helpTips[v])!@#& end!@#& end!@#&!@#& prompt({{\"Back\", w - 8, 7}}, \"horizontal\")!@#&end!@#&!@#&local function run(path, lines, useArgs)!@#& local ar = {}!@#& if useArgs then!@#& title(\"LuaIDE - Run \" .. fs.getName(path))!@#& local s = centerRead(w - 13, fs.getName(path) .. \" \")!@#& for m in string.gmatch(s, \"[^ \\t]+\") do ar[#ar + 1] = m:gsub(\"^%s*(.-)%s*$\", \"%1\") end!@#& end!@#& !@#& saveFile(path, lines)!@#& term.setCursorBlink(false)!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& local err = curLanguage.run(path, ar)!@#&!@#& term.setBackgroundColor(colors.black)!@#& print(\"\\n\")!@#& if err then!@#& if isAdvanced() then term.setTextColor(colors.red) end!@#& centerPrint(\"The program has crashed!\")!@#& end!@#& term.setTextColor(colors.white)!@#& centerPrint(\"Press any key to return to LuaIDE...\")!@#& while true do!@#& local e = os.pullEvent()!@#& if e == \"key\" then break end!@#& end!@#&!@#& -- To prevent key from showing up in editor!@#& os.queueEvent(event_distract)!@#& os.pullEvent()!@#&!@#& if err then!@#& if curLanguage == languages.lua and err:find(\"]\") then!@#& err = fs.getName(path) .. err:sub(err:find(\"]\", 1, true) + 1, -1)!@#& end!@#&!@#& while true do!@#& title(\"LuaIDE - Error!\")!@#&!@#& term.setBackgroundColor(colors[theme.err])!@#& for i = 6, 8 do!@#& term.setCursorPos(3, i)!@#& term.write(string.rep(\" \", w - 5))!@#& end!@#& term.setCursorPos(4, 7)!@#& term.write(\"The program has crashed!\")!@#&!@#& term.setBackgroundColor(colors[theme.prompt])!@#& for i = 10, 14 do!@#& term.setCursorPos(3, i)!@#& term.write(string.rep(\" \", w - 5))!@#& end!@#&!@#& local formattedErr = curLanguage.parseError(err)!@#& term.setCursorPos(4, 11)!@#& term.write(\"Line: \" .. formattedErr.line)!@#& term.setCursorPos(4, 12)!@#& term.write(\"Error:\")!@#& term.setCursorPos(5, 13)!@#&!@#& local a = formattedErr.display!@#& local b = nil!@#& if a:len() > w - 8 then!@#& for i = a:len(), 1, -1 do!@#& if a:sub(i, i) == \" \" then!@#& b = a:sub(i + 1, -1)!@#& a = a:sub(1, i)!@#& break!@#& end!@#& end!@#& end!@#&!@#& term.write(a)!@#& if b then!@#& term.setCursorPos(5, 14)!@#& term.write(b)!@#& end!@#& !@#& local opt = prompt({{\"Error Help\", w/2 - 15, 17}, {\"Go To Line\", w/2 + 2, 17}},!@#& \"horizontal\")!@#& if opt == \"Error Help\" then!@#& viewErrorHelp(formattedErr)!@#& elseif opt == \"Go To Line\" then!@#& -- To prevent key from showing up in editor!@#& os.queueEvent(event_distract)!@#& os.pullEvent()!@#&!@#& return \"go to\", tonumber(formattedErr.line)!@#& end!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Functions!@#&!@#&local function goto()!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& term.write(\"Line: \")!@#& local line = modRead({visibleLength = w - 2})!@#&!@#& local num = tonumber(line)!@#& if num and num > 0 then return num!@#& else!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& term.write(\"Not a line number!\")!@#& sleep(1.6)!@#& return nil!@#& end!@#&end!@#&!@#&local function setsyntax()!@#& local opts = {!@#& \"[Lua] Brainfuck None \",!@#& \" Lua [Brainfuck] None \",!@#& \" Lua Brainfuck [None]\"!@#& }!@#& local sel = 1!@#&!@#& term.setCursorBlink(false)!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& term.write(opts[sel])!@#& while true do!@#& local e, but, x, y = os.pullEvent(\"key\")!@#& if but == 203 then!@#& sel = math.max(1, sel - 1)!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& term.write(opts[sel])!@#& elseif but == 205 then!@#& sel = math.min(#opts, sel + 1)!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& term.write(opts[sel])!@#& elseif but == 28 then!@#& if sel == 1 then curLanguage = languages.lua!@#& elseif sel == 2 then curLanguage = languages.brainfuck!@#& elseif sel == 3 then curLanguage = languages.none end!@#& term.setCursorBlink(true)!@#& return!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Re-Indenting!@#&!@#&local tabWidth = 2!@#&!@#&local comments = {}!@#&local strings = {}!@#&!@#&local increment = {!@#& \"if%s+.+%s+then%s*$\",!@#& \"for%s+.+%s+do%s*$\",!@#& \"while%s+.+%s+do%s*$\",!@#& \"repeat%s*$\",!@#& \"function%s+[a-zA-Z_0-9]\\(.*\\)%s*$\"!@#&}!@#&!@#&local decrement = {!@#& \"end\",!@#& \"until%s+.+\"!@#&}!@#&!@#&local special = {!@#& \"else%s*$\",!@#& \"elseif%s+.+%s+then%s*$\"!@#&}!@#&!@#&local function check(func)!@#& for _, v in pairs(func) do!@#& local cLineStart = v[\"lineStart\"]!@#& local cLineEnd = v[\"lineEnd\"]!@#& local cCharStart = v[\"charStart\"]!@#& local cCharEnd = v[\"charEnd\"]!@#&!@#& if line >= cLineStart and line <= cLineEnd then!@#& if line == cLineStart then return cCharStart < charNumb!@#& elseif line == cLineEnd then return cCharEnd > charNumb!@#& else return true end!@#& end!@#& end!@#&end!@#&!@#&local function isIn(line, loc)!@#& if check(comments) then return true end!@#& if check(strings) then return true end!@#& return false!@#&end!@#&!@#&local function setComment(ls, le, cs, ce)!@#& comments[#comments + 1] = {}!@#& comments[#comments].lineStart = ls!@#& comments[#comments].lineEnd = le!@#& comments[#comments].charStart = cs!@#& comments[#comments].charEnd = ce!@#&end!@#&!@#&local function setString(ls, le, cs, ce)!@#& strings[#strings + 1] = {}!@#& strings[#strings].lineStart = ls!@#& strings[#strings].lineEnd = le!@#& strings[#strings].charStart = cs!@#& strings[#strings].charEnd = ce!@#&end!@#&!@#&local function map(contents)!@#& local inCom = false!@#& local inStr = false!@#&!@#& for i = 1, #contents do!@#& if content[i]:find(\"%-%-%[%[\") and not inStr and not inCom then!@#& local cStart = content[i]:find(\"%-%-%[%[\")!@#& setComment(i, nil, cStart, nil)!@#& inCom = true!@#& elseif content[i]:find(\"%-%-%[=%[\") and not inStr and not inCom then!@#& local cStart = content[i]:find(\"%-%-%[=%[\")!@#& setComment(i, nil, cStart, nil)!@#& inCom = true!@#& elseif content[i]:find(\"%[%[\") and not inStr and not inCom then!@#& local cStart = content[i]:find(\"%[%[\")!@#& setString(i, nil, cStart, nil)!@#& inStr = true!@#& elseif content[i]:find(\"%[=%[\") and not inStr and not inCom then!@#& local cStart = content[i]:find(\"%[=%[\")!@#& setString(i, nil, cStart, nil)!@#& inStr = true!@#& end!@#&!@#& if content[i]:find(\"%]%]\") and inStr and not inCom then!@#& local cStart, cEnd = content[i]:find(\"%]%]\")!@#& strings[#strings].lineEnd = i!@#& strings[#strings].charEnd = cEnd!@#& inStr = false!@#& elseif content[i]:find(\"%]=%]\") and inStr and not inCom then!@#& local cStart, cEnd = content[i]:find(\"%]=%]\")!@#& strings[#strings].lineEnd = i!@#& strings[#strings].charEnd = cEnd!@#& inStr = false!@#& end!@#&!@#& if content[i]:find(\"%]%]\") and not inStr and inCom then!@#& local cStart, cEnd = content[i]:find(\"%]%]\")!@#& comments[#comments].lineEnd = i!@#& comments[#comments].charEnd = cEnd!@#& inCom = false!@#& elseif content[i]:find(\"%]=%]\") and not inStr and inCom then!@#& local cStart, cEnd = content[i]:find(\"%]=%]\")!@#& comments[#comments].lineEnd = i!@#& comments[#comments].charEnd = cEnd!@#& inCom = false!@#& end!@#&!@#& if content[i]:find(\"%-%-\") and not inStr and not inCom then!@#& local cStart = content[i]:find(\"%-%-\")!@#& setComment(i, i, cStart, -1)!@#& elseif content[i]:find(\"'\") and not inStr and not inCom then!@#& local cStart, cEnd = content[i]:find(\"'\")!@#& local nextChar = content[i]:sub(cEnd + 1, string.len(content[i]))!@#& local _, cEnd = nextChar:find(\"'\")!@#& setString(i, i, cStart, cEnd)!@#& elseif content[i]:find('\"') and not inStr and not inCom then!@#& local cStart, cEnd = content[i]:find('\"')!@#& local nextChar = content[i]:sub(cEnd + 1, string.len(content[i]))!@#& local _, cEnd = nextChar:find('\"')!@#& setString(i, i, cStart, cEnd)!@#& end!@#& end!@#&end!@#&!@#&local function reindent(contents)!@#& local err = nil!@#& if curLanguage ~= languages.lua then!@#& err = \"Cannot indent languages other than Lua!\"!@#& elseif curLanguage.getCompilerErrors(table.concat(contents, \"\\n\")).line ~= -1 then!@#& err = \"Cannot indent a program with errors!\"!@#& end!@#&!@#& if err then!@#& term.setCursorBlink(false)!@#& term.setCursorPos(2, 1)!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& term.clearLine()!@#& term.write(err)!@#& sleep(1.6)!@#& return contents!@#& end!@#&!@#& local new = {}!@#& local level = 0!@#& for k, v in pairs(contents) do!@#& local incrLevel = false!@#& local foundIncr = false!@#& for _, incr in pairs(increment) do!@#& if v:find(incr) and not isIn(k, v:find(incr)) then!@#& incrLevel = true!@#& end!@#& if v:find(incr:sub(1, -2)) and not isIn(k, v:find(incr)) then!@#& foundIncr = true!@#& end!@#& end!@#&!@#& local decrLevel = false!@#& if not incrLevel then!@#& for _, decr in pairs(decrement) do!@#& if v:find(decr) and not isIn(k, v:find(decr)) and not foundIncr then!@#& level = math.max(0, level - 1)!@#& decrLevel = true!@#& end!@#& end!@#& end!@#&!@#& if not decrLevel then!@#& for _, sp in pairs(special) do!@#& if v:find(sp) and not isIn(k, v:find(sp)) then!@#& incrLevel = true!@#& level = math.max(0, level - 1)!@#& end!@#& end!@#& end!@#&!@#& new[k] = string.rep(\" \", level * tabWidth) .. v!@#& if incrLevel then level = level + 1 end!@#& end!@#&!@#& return new!@#&end!@#&!@#&!@#&-- -------- Menu!@#&!@#&local menu = {!@#& [1] = {\"File\",!@#&-- \"About\",!@#&-- \"Settings\",!@#&-- \"\",!@#& \"New File ^+N\",!@#& \"Open File ^+O\",!@#& \"Save File ^+S\",!@#& \"Close ^+W\",!@#& \"Print ^+P\",!@#& \"Quit ^+Q\"!@#& }, [2] = {\"Edit\",!@#& \"Cut Line ^+X\",!@#& \"Copy Line ^+C\",!@#& \"Paste Line ^+V\",!@#& \"Delete Line\",!@#& \"Clear Line\"!@#& }, [3] = {\"Functions\",!@#& \"Go To Line ^+G\",!@#& \"Re-Indent ^+I\",!@#& \"Set Syntax ^+E\",!@#& \"Start of Line ^+<\",!@#& \"End of Line ^+>\"!@#& }, [4] = {\"Run\",!@#& \"Run Program ^+R\",!@#& \"Run w/ Args ^+Shift+R\"!@#& }!@#&}!@#&!@#&local shortcuts = {!@#& -- File!@#& [\"ctrl n\"] = \"New File ^+N\",!@#& [\"ctrl o\"] = \"Open File ^+O\",!@#& [\"ctrl s\"] = \"Save File ^+S\",!@#& [\"ctrl w\"] = \"Close ^+W\",!@#& [\"ctrl p\"] = \"Print ^+P\",!@#& [\"ctrl q\"] = \"Quit ^+Q\",!@#&!@#& -- Edit!@#& [\"ctrl x\"] = \"Cut Line ^+X\",!@#& [\"ctrl c\"] = \"Copy Line ^+C\",!@#& [\"ctrl v\"] = \"Paste Line ^+V\",!@#&!@#& -- Functions!@#& [\"ctrl g\"] = \"Go To Line ^+G\",!@#& [\"ctrl i\"] = \"Re-Indent ^+I\",!@#& [\"ctrl e\"] = \"Set Syntax ^+E\",!@#& [\"ctrl 203\"] = \"Start of Line ^+<\",!@#& [\"ctrl 205\"] = \"End of Line ^+>\",!@#&!@#& -- Run!@#& [\"ctrl r\"] = \"Run Program ^+R\",!@#& [\"ctrl shift r\"] = \"Run w/ Args ^+Shift+R\"!@#&}!@#&!@#&local menuFunctions = {!@#& -- File!@#&-- [\"About\"] = function() end,!@#&-- [\"Settings\"] = function() end,!@#& [\"New File ^+N\"] = function(path, lines) saveFile(path, lines) return \"new\" end,!@#& [\"Open File ^+O\"] = function(path, lines) saveFile(path, lines) return \"open\" end,!@#& [\"Save File ^+S\"] = function(path, lines) saveFile(path, lines) end,!@#& [\"Close ^+W\"] = function(path, lines) saveFile(path, lines) return \"menu\" end,!@#& [\"Print ^+P\"] = function(path, lines) saveFile(path, lines) return nil end,!@#& [\"Quit ^+Q\"] = function(path, lines) saveFile(path, lines) return \"exit\" end,!@#&!@#& -- Edit!@#& [\"Cut Line ^+X\"] = function(path, lines, y)!@#& clipboard = lines[y] table.remove(lines, y) return nil, lines end,!@#& [\"Copy Line ^+C\"] = function(path, lines, y) clipboard = lines[y] end,!@#& [\"Paste Line ^+V\"] = function(path, lines, y)!@#& if clipboard then table.insert(lines, y, clipboard) end return nil, lines end,!@#& [\"Delete Line\"] = function(path, lines, y) table.remove(lines, y) return nil, lines end,!@#& [\"Clear Line\"] = function(path, lines, y) lines[y] = \"\" return nil, lines, \"cursor\" end,!@#&!@#& -- Functions!@#& [\"Go To Line ^+G\"] = function() return nil, \"go to\", goto() end,!@#& [\"Re-Indent ^+I\"] = function(path, lines)!@#& local a = reindent(lines) saveFile(path, lines) return nil, a!@#& end,!@#& [\"Set Syntax ^+E\"] = function(path, lines)!@#& setsyntax()!@#& if curLanguage == languages.brainfuck and lines[1] ~= \"-- Syntax: Brainfuck\" then!@#& table.insert(lines, 1, \"-- Syntax: Brainfuck\")!@#& return nil, lines!@#& end!@#& end,!@#& [\"Start of Line ^+<\"] = function() os.queueEvent(\"key\", 199) end,!@#& [\"End of Line ^+>\"] = function() os.queueEvent(\"key\", 207) end,!@#&!@#& -- Run!@#& [\"Run Program ^+R\"] = function(path, lines)!@#& saveFile(path, lines)!@#& return nil, run(path, lines, false)!@#& end,!@#& [\"Run w/ Args ^+Shift+R\"] = function(path, lines)!@#& saveFile(path, lines)!@#& return nil, run(path, lines, true)!@#& end,!@#&}!@#&!@#&local function drawMenu(open)!@#& term.setCursorPos(1, 1)!@#& term.setTextColor(colors[theme.textColor])!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& term.clearLine()!@#& local curX = 0!@#& for _, v in pairs(menu) do!@#& term.setCursorPos(3 + curX, 1)!@#& term.write(v[1])!@#& curX = curX + v[1]:len() + 3!@#& end!@#&!@#& if open then!@#& local it = {}!@#& local x = 1!@#& for _, v in pairs(menu) do!@#& if open == v[1] then!@#& it = v!@#& break!@#& end!@#& x = x + v[1]:len() + 3!@#& end!@#& x = x + 1!@#&!@#& local items = {}!@#& for i = 2, #it do!@#& table.insert(items, it[i])!@#& end!@#&!@#& local len = 1!@#& for _, v in pairs(items) do if v:len() + 2 > len then len = v:len() + 2 end end!@#&!@#& for i, v in ipairs(items) do!@#& term.setCursorPos(x, i + 1)!@#& term.write(string.rep(\" \", len))!@#& term.setCursorPos(x + 1, i + 1)!@#& term.write(v)!@#& end!@#& term.setCursorPos(x, #items + 2)!@#& term.write(string.rep(\" \", len))!@#& return items, len!@#& end!@#&end!@#&!@#&local function triggerMenu(cx, cy)!@#& -- Determine clicked menu!@#& local curX = 0!@#& local open = nil!@#& for _, v in pairs(menu) do!@#& if cx >= curX + 3 and cx <= curX + v[1]:len() + 2 then!@#& open = v[1]!@#& break!@#& end!@#& curX = curX + v[1]:len() + 3!@#& end!@#& local menux = curX + 2!@#& if not open then return false end!@#&!@#& -- Flash menu item!@#& term.setCursorBlink(false)!@#& term.setCursorPos(menux, 1)!@#& term.setBackgroundColor(colors[theme.background])!@#& term.write(string.rep(\" \", open:len() + 2))!@#& term.setCursorPos(menux + 1, 1)!@#& term.write(open)!@#& sleep(0.1)!@#& local items, len = drawMenu(open)!@#&!@#& local ret = true!@#&!@#& -- Pull events on menu!@#& local ox, oy = term.getCursorPos()!@#& while type(ret) ~= \"string\" do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"mouse_click\" then!@#& -- If clicked outside menu!@#& if x < menux - 1 or x > menux + len - 1 then break!@#& elseif y > #items + 2 then break!@#& elseif y == 1 then break end!@#&!@#& for i, v in ipairs(items) do!@#& if y == i + 1 and x >= menux and x <= menux + len - 2 then!@#& -- Flash when clicked!@#& term.setCursorPos(menux, y)!@#& term.setBackgroundColor(colors[theme.background])!@#& term.write(string.rep(\" \", len))!@#& term.setCursorPos(menux + 1, y)!@#& term.write(v)!@#& sleep(0.1)!@#& drawMenu(open)!@#&!@#& -- Return item!@#& ret = v!@#& break!@#& end!@#& end!@#& end!@#& end!@#&!@#& term.setCursorPos(ox, oy)!@#& term.setCursorBlink(true)!@#& return ret!@#&end!@#&!@#&!@#&-- -------- Editing!@#&!@#&local standardsCompletions = {!@#& \"if%s+.+%s+then%s*$\",!@#& \"for%s+.+%s+do%s*$\",!@#& \"while%s+.+%s+do%s*$\",!@#& \"repeat%s*$\",!@#& \"function%s+[a-zA-Z_0-9]\\(.*\\)%s*$\",!@#& \"else%s*$\",!@#& \"elseif%s+.+%s+then%s*$\"!@#&}!@#&!@#&local liveCompletions = {!@#& [\"(\"] = \")\",!@#& [\"{\"] = \"}\",!@#& [\"[\"] = \"]\",!@#& [\"\\\"\"] = \"\\\"\",!@#& [\"'\"] = \"'\",!@#&}!@#&!@#&local x, y = 0, 0!@#&local edw, edh = 0, h - 1!@#&local offx, offy = 0, 1!@#&local scrollx, scrolly = 0, 0!@#&local lines = {}!@#&local liveErr = curLanguage.parseError(nil)!@#&local displayCode = true!@#&local lastEventClock = os.clock()!@#&!@#&local function attemptToHighlight(line, regex, col)!@#& local match = string.match(line, regex)!@#& if match then!@#& if type(col) == \"number\" then term.setTextColor(col)!@#& elseif type(col) == \"function\" then term.setTextColor(col(match)) end!@#& term.write(match)!@#& term.setTextColor(colors[theme.textColor])!@#& return line:sub(match:len() + 1, -1)!@#& end!@#& return nil!@#&end!@#&!@#&local function writeHighlighted(line)!@#& if curLanguage == languages.lua then!@#& while line:len() > 0 do !@#& line = attemptToHighlight(line, \"^%-%-%[%[.-%]%]\", colors[theme.comment]) or!@#& attemptToHighlight(line, \"^%-%-.*\", colors[theme.comment]) or!@#& attemptToHighlight(line, \"^\\\".*[^\\\\]\\\"\", colors[theme.string]) or!@#& attemptToHighlight(line, \"^\\'.*[^\\\\]\\'\", colors[theme.string]) or!@#& attemptToHighlight(line, \"^%[%[.-%]%]\", colors[theme.string]) or!@#& attemptToHighlight(line, \"^[%w_]+\", function(match)!@#& if curLanguage.keywords[match] then!@#& return colors[theme[curLanguage.keywords[match]]]!@#& end!@#& return colors[theme.textColor]!@#& end) or!@#& attemptToHighlight(line, \"^[^%w_]\", colors[theme.textColor])!@#& end!@#& else term.write(line) end!@#&end!@#&!@#&local function draw()!@#& -- Menu!@#& term.setTextColor(colors[theme.textColor])!@#& term.setBackgroundColor(colors[theme.editorBackground])!@#& term.clear()!@#& drawMenu()!@#&!@#& -- Line numbers!@#& offx, offy = tostring(#lines):len() + 1, 1!@#& edw, edh = w - offx, h - 1!@#&!@#& -- Draw text!@#& for i = 1, edh do!@#& local a = lines[scrolly + i]!@#& if a then!@#& local ln = string.rep(\" \", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i) !@#& local l = a:sub(scrollx + 1, edw + scrollx + 1)!@#& ln = ln .. \":\"!@#&!@#& if liveErr.line == scrolly + i then ln = string.rep(\" \", offx - 2) .. \"!:\" end!@#&!@#& term.setCursorPos(1, i + offy)!@#& term.setBackgroundColor(colors[theme.editorBackground])!@#& if scrolly + i == y then!@#& if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then!@#& term.setBackgroundColor(colors[theme.editorErrorHighlight])!@#& else term.setBackgroundColor(colors[theme.editorLineHightlight]) end!@#& term.clearLine()!@#& elseif scrolly + i == liveErr.line then!@#& term.setBackgroundColor(colors[theme.editorError])!@#& term.clearLine()!@#& end!@#&!@#& term.setCursorPos(1 - scrollx + offx, i + offy)!@#& if scrolly + i == y then!@#& if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then!@#& term.setBackgroundColor(colors[theme.editorErrorHighlight])!@#& else term.setBackgroundColor(colors[theme.editorLineHightlight]) end!@#& elseif scrolly + i == liveErr.line then term.setBackgroundColor(colors[theme.editorError])!@#& else term.setBackgroundColor(colors[theme.editorBackground]) end!@#& if scrolly + i == liveErr.line then!@#& if displayCode then term.write(a)!@#& else term.write(liveErr.display) end!@#& else writeHighlighted(a) end!@#&!@#& term.setCursorPos(1, i + offy)!@#& if scrolly + i == y then!@#& if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then!@#& term.setBackgroundColor(colors[theme.editorError])!@#& else term.setBackgroundColor(colors[theme.editorLineNumbersHighlight]) end!@#& elseif scrolly + i == liveErr.line then!@#& term.setBackgroundColor(colors[theme.editorErrorHighlight])!@#& else term.setBackgroundColor(colors[theme.editorLineNumbers]) end!@#& term.write(ln)!@#& end!@#& end!@#& term.setCursorPos(x - scrollx + offx, y - scrolly + offy)!@#&end!@#&!@#&local function drawLine(...)!@#& local ls = {...}!@#& offx = tostring(#lines):len() + 1!@#& for _, ly in pairs(ls) do!@#& local a = lines[ly]!@#& if a then!@#& local ln = string.rep(\" \", offx - 1 - tostring(ly):len()) .. tostring(ly) !@#& local l = a:sub(scrollx + 1, edw + scrollx + 1)!@#& ln = ln .. \":\"!@#&!@#& if liveErr.line == ly then ln = string.rep(\" \", offx - 2) .. \"!:\" end!@#&!@#& term.setCursorPos(1, (ly - scrolly) + offy)!@#& term.setBackgroundColor(colors[theme.editorBackground])!@#& if ly == y then!@#& if ly == liveErr.line and os.clock() - lastEventClock > 3 then!@#& term.setBackgroundColor(colors[theme.editorErrorHighlight])!@#& else term.setBackgroundColor(colors[theme.editorLineHightlight]) end!@#& elseif ly == liveErr.line then!@#& term.setBackgroundColor(colors[theme.editorError])!@#& end!@#& term.clearLine()!@#&!@#& term.setCursorPos(1 - scrollx + offx, (ly - scrolly) + offy)!@#& if ly == y then!@#& if ly == liveErr.line and os.clock() - lastEventClock > 3 then!@#& term.setBackgroundColor(colors[theme.editorErrorHighlight])!@#& else term.setBackgroundColor(colors[theme.editorLineHightlight]) end!@#& elseif ly == liveErr.line then term.setBackgroundColor(colors[theme.editorError])!@#& else term.setBackgroundColor(colors[theme.editorBackground]) end!@#& if ly == liveErr.line then!@#& if displayCode then term.write(a)!@#& else term.write(liveErr.display) end!@#& else writeHighlighted(a) end!@#&!@#& term.setCursorPos(1, (ly - scrolly) + offy)!@#& if ly == y then!@#& if ly == liveErr.line and os.clock() - lastEventClock > 3 then!@#& term.setBackgroundColor(colors[theme.editorError])!@#& else term.setBackgroundColor(colors[theme.editorLineNumbersHighlight]) end!@#& elseif ly == liveErr.line then!@#& term.setBackgroundColor(colors[theme.editorErrorHighlight])!@#& else term.setBackgroundColor(colors[theme.editorLineNumbers]) end!@#& term.write(ln)!@#& end!@#& end!@#& term.setCursorPos(x - scrollx + offx, y - scrolly + offy)!@#&end!@#&!@#&local function cursorLoc(x, y, force)!@#& local sx, sy = x - scrollx, y - scrolly!@#& local redraw = false!@#& if sx < 1 then!@#& scrollx = x - 1!@#& sx = 1!@#& redraw = true!@#& elseif sx > edw then!@#& scrollx = x - edw!@#& sx = edw!@#& redraw = true!@#& end if sy < 1 then!@#& scrolly = y - 1!@#& sy = 1!@#& redraw = true!@#& elseif sy > edh then!@#& scrolly = y - edh!@#& sy = edh!@#& redraw = true!@#& end if redraw or force then draw() end!@#& term.setCursorPos(sx + offx, sy + offy)!@#&end!@#&!@#&local function executeMenuItem(a, path)!@#& if type(a) == \"string\" and menuFunctions[a] then!@#& local opt, nl, gtln = menuFunctions[a](path, lines, y)!@#& if type(opt) == \"string\" then term.setCursorBlink(false) return opt end!@#& if type(nl) == \"table\" then!@#& if #lines < 1 then table.insert(lines, \"\") end!@#& y = math.min(y, #lines)!@#& x = math.min(x, lines[y]:len() + 1)!@#& lines = nl!@#& elseif type(nl) == \"string\" then!@#& if nl == \"go to\" and gtln then!@#& x, y = 1, math.min(#lines, gtln)!@#& cursorLoc(x, y)!@#& end!@#& end!@#& end!@#& term.setCursorBlink(true)!@#& draw()!@#& term.setCursorPos(x - scrollx + offx, y - scrolly + offy)!@#&end!@#&!@#&local function edit(path)!@#& -- Variables!@#& x, y = 1, 1!@#& offx, offy = 0, 1!@#& scrollx, scrolly = 0, 0!@#& lines = loadFile(path)!@#& if not lines then return \"menu\" end!@#&!@#& -- Enable brainfuck!@#& if lines[1] == \"-- Syntax: Brainfuck\" then!@#& curLanguage = languages.brainfuck!@#& end!@#&!@#& -- Clocks!@#& local autosaveClock = os.clock()!@#& local scrollClock = os.clock() -- To prevent redraw flicker!@#& local liveErrorClock = os.clock()!@#& local hasScrolled = false!@#&!@#& -- Draw!@#& draw()!@#& term.setCursorPos(x + offx, y + offy)!@#& term.setCursorBlink(true)!@#& !@#& -- Main loop!@#& local tid = os.startTimer(3)!@#& while true do!@#& local e, key, cx, cy = os.pullEvent()!@#& if e == \"key\" and allowEditorEvent then!@#& if key == 200 and y > 1 then!@#& -- Up!@#& x, y = math.min(x, lines[y - 1]:len() + 1), y - 1!@#& drawLine(y, y + 1)!@#& cursorLoc(x, y)!@#& elseif key == 208 and y < #lines then!@#& -- Down!@#& x, y = math.min(x, lines[y + 1]:len() + 1), y + 1!@#& drawLine(y, y - 1)!@#& cursorLoc(x, y)!@#& elseif key == 203 and x > 1 then!@#& -- Left!@#& x = x - 1!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& cursorLoc(x, y, force)!@#& elseif key == 205 and x < lines[y]:len() + 1 then!@#& -- Right!@#& x = x + 1!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& cursorLoc(x, y, force)!@#& elseif (key == 28 or key == 156) and (displayCode and true or y + scrolly - 1 ==!@#& liveErr.line) then!@#& -- Enter!@#& local f = nil!@#& for _, v in pairs(standardsCompletions) do!@#& if lines[y]:find(v) then f = v end!@#& end!@#&!@#& local _, spaces = lines[y]:find(\"^[ ]+\")!@#& if not spaces then spaces = 0 end!@#& if f then!@#& table.insert(lines, y + 1, string.rep(\" \", spaces + 2))!@#& if not f:find(\"else\", 1, true) and not f:find(\"elseif\", 1, true) then!@#& table.insert(lines, y + 2, string.rep(\" \", spaces) .. !@#& (f:find(\"repeat\", 1, true) and \"until \" or f:find(\"{\", 1, true) and \"}\" or !@#& \"end\"))!@#& end!@#& x, y = spaces + 3, y + 1!@#& cursorLoc(x, y, true)!@#& else!@#& local oldLine = lines[y]!@#&!@#& lines[y] = lines[y]:sub(1, x - 1)!@#& table.insert(lines, y + 1, string.rep(\" \", spaces) .. oldLine:sub(x, -1))!@#&!@#& x, y = spaces + 1, y + 1!@#& cursorLoc(x, y, true)!@#& end!@#& elseif key == 14 and (displayCode and true or y + scrolly - 1 == liveErr.line) then!@#& -- Backspace!@#& if x > 1 then!@#& local f = false!@#& for k, v in pairs(liveCompletions) do!@#& if lines[y]:sub(x - 1, x - 1) == k then f = true end!@#& end!@#&!@#& lines[y] = lines[y]:sub(1, x - 2) .. lines[y]:sub(x + (f and 1 or 0), -1)!@#& drawLine(y)!@#& x = x - 1!@#& cursorLoc(x, y)!@#& elseif y > 1 then!@#& local prevLen = lines[y - 1]:len() + 1!@#& lines[y - 1] = lines[y - 1] .. lines[y]!@#& table.remove(lines, y)!@#& x, y = prevLen, y - 1!@#& cursorLoc(x, y, true)!@#& end!@#& elseif key == 199 then!@#& -- Home!@#& x = 1!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& cursorLoc(x, y, force)!@#& elseif key == 207 then!@#& -- End!@#& x = lines[y]:len() + 1!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& cursorLoc(x, y, force)!@#& elseif key == 211 and (displayCode and true or y + scrolly - 1 == liveErr.line) then!@#& -- Forward Delete!@#& if x < lines[y]:len() + 1 then!@#& lines[y] = lines[y]:sub(1, x - 1) .. lines[y]:sub(x + 1)!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& drawLine(y)!@#& cursorLoc(x, y, force)!@#& elseif y < #lines then!@#& lines[y] = lines[y] .. lines[y + 1]!@#& table.remove(lines, y + 1)!@#& draw()!@#& cursorLoc(x, y)!@#& end!@#& elseif key == 15 and (displayCode and true or y + scrolly - 1 == liveErr.line) then!@#& -- Tab!@#& lines[y] = string.rep(\" \", tabWidth) .. lines[y]!@#& x = x + 2!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& drawLine(y)!@#& cursorLoc(x, y, force)!@#& elseif key == 201 then!@#& -- Page up!@#& y = math.min(math.max(y - edh, 1), #lines)!@#& x = math.min(lines[y]:len() + 1, x)!@#& cursorLoc(x, y, true)!@#& elseif key == 209 then!@#& -- Page down!@#& y = math.min(math.max(y + edh, 1), #lines)!@#& x = math.min(lines[y]:len() + 1, x)!@#& cursorLoc(x, y, true)!@#& end!@#& elseif e == \"char\" and allowEditorEvent and (displayCode and true or !@#& y + scrolly - 1 == liveErr.line) then!@#& local shouldIgnore = false!@#& for k, v in pairs(liveCompletions) do!@#& if key == v and lines[y]:find(k, 1, true) and lines[y]:sub(x, x) == v then!@#& shouldIgnore = true!@#& end!@#& end!@#&!@#& local addOne = false!@#& if not shouldIgnore then!@#& for k, v in pairs(liveCompletions) do!@#& if key == k and lines[y]:sub(x, x) ~= k then key = key .. v addOne = true end!@#& end!@#& lines[y] = lines[y]:sub(1, x - 1) .. key .. lines[y]:sub(x, -1)!@#& end!@#&!@#& x = x + (addOne and 1 or key:len())!@#& local force = false!@#& if y - scrolly + offy < offy + 1 then force = true end!@#& drawLine(y)!@#& cursorLoc(x, y, force)!@#& elseif e == \"mouse_click\" and key == 1 then!@#& if cy > 1 then!@#& if cx <= offx and cy - offy == liveErr.line - scrolly then!@#& displayCode = not displayCode!@#& drawLine(liveErr.line)!@#& else!@#& local oldy = y!@#& y = math.min(math.max(scrolly + cy - offy, 1), #lines)!@#& x = math.min(math.max(scrollx + cx - offx, 1), lines[y]:len() + 1)!@#& if oldy ~= y then drawLine(oldy, y) end!@#& cursorLoc(x, y)!@#& end!@#& else!@#& local a = triggerMenu(cx, cy)!@#& if a then!@#& local opt = executeMenuItem(a, path)!@#& if opt then return opt end!@#& end!@#& end!@#& elseif e == \"shortcut\" then!@#& local a = shortcuts[key .. \" \" .. cx]!@#& if a then!@#& local parent = nil!@#& local curx = 0!@#& for i, mv in ipairs(menu) do!@#& for _, iv in pairs(mv) do!@#& if iv == a then!@#& parent = menu[i][1]!@#& break!@#& end!@#& end!@#& if parent then break end!@#& curx = curx + mv[1]:len() + 3!@#& end!@#& local menux = curx + 2!@#&!@#& -- Flash menu item!@#& term.setCursorBlink(false)!@#& term.setCursorPos(menux, 1)!@#& term.setBackgroundColor(colors[theme.background])!@#& term.write(string.rep(\" \", parent:len() + 2))!@#& term.setCursorPos(menux + 1, 1)!@#& term.write(parent)!@#& sleep(0.1)!@#& drawMenu()!@#&!@#& -- Execute item!@#& local opt = executeMenuItem(a, path)!@#& if opt then return opt end!@#& end!@#& elseif e == \"mouse_scroll\" then!@#& if key == -1 and scrolly > 0 then!@#& scrolly = scrolly - 1!@#& if os.clock() - scrollClock > 0.0005 then!@#& draw()!@#& term.setCursorPos(x - scrollx + offx, y - scrolly + offy)!@#& end!@#& scrollClock = os.clock()!@#& hasScrolled = true!@#& elseif key == 1 and scrolly < #lines - edh then!@#& scrolly = scrolly + 1!@#& if os.clock() - scrollClock > 0.0005 then!@#& draw()!@#& term.setCursorPos(x - scrollx + offx, y - scrolly + offy)!@#& end!@#& scrollClock = os.clock()!@#& hasScrolled = true!@#& end!@#& elseif e == \"timer\" and key == tid then!@#& drawLine(y)!@#& tid = os.startTimer(3)!@#& end!@#&!@#& -- Draw!@#& if hasScrolled and os.clock() - scrollClock > 0.1 then!@#& draw()!@#& term.setCursorPos(x - scrollx + offx, y - scrolly + offy)!@#& hasScrolled = false!@#& end!@#&!@#& -- Autosave!@#& if os.clock() - autosaveClock > autosaveInterval then!@#& saveFile(path, lines)!@#& autosaveClock = os.clock()!@#& end!@#&!@#& -- Errors!@#& if os.clock() - liveErrorClock > 1 then!@#& local prevLiveErr = liveErr!@#& liveErr = curLanguage.parseError(nil)!@#& local code = \"\"!@#& for _, v in pairs(lines) do code = code .. v .. \"\\n\" end!@#&!@#& liveErr = curLanguage.getCompilerErrors(code)!@#& liveErr.line = math.min(liveErr.line - 2, #lines)!@#& if liveErr ~= prevLiveErr then draw() end!@#& liveErrorClock = os.clock()!@#& end!@#& end!@#&!@#& return \"menu\"!@#&end!@#&!@#&!@#&-- -------- Open File!@#&!@#&local function newFile()!@#& local wid = w - 13!@#&!@#& -- Get name!@#& title(\"Lua IDE - New File\")!@#& local name = centerRead(wid, \"/\")!@#& if not name or name == \"\" then return \"menu\" end!@#& name = \"/\" .. name!@#&!@#& -- Clear!@#& title(\"Lua IDE - New File\")!@#& term.setTextColor(colors[theme.textColor])!@#& term.setBackgroundColor(colors[theme.promptHighlight])!@#& for i = 8, 10 do!@#& term.setCursorPos(w/2 - wid/2, i)!@#& term.write(string.rep(\" \", wid))!@#& end!@#& term.setCursorPos(1, 9)!@#& if fs.isDir(name) then!@#& centerPrint(\"Cannot Edit a Directory!\")!@#& sleep(1.6)!@#& return \"menu\"!@#& elseif fs.exists(name) then!@#& centerPrint(\"File Already Exists!\")!@#& local opt = prompt({{\"Open\", w/2 - 9, 14}, {\"Cancel\", w/2 + 2, 14}}, \"horizontal\")!@#& if opt == \"Open\" then return \"edit\", name!@#& elseif opt == \"Cancel\" then return \"menu\" end!@#& else return \"edit\", name end!@#&end!@#&!@#&local function openFile()!@#& local wid = w - 13!@#&!@#& -- Get name!@#& title(\"Lua IDE - Open File\")!@#& local name = centerRead(wid, \"/\")!@#& if not name or name == \"\" then return \"menu\" end!@#& name = \"/\" .. name!@#&!@#& -- Clear!@#& title(\"Lua IDE - New File\")!@#& term.setTextColor(colors[theme.textColor])!@#& term.setBackgroundColor(colors[theme.promptHighlight])!@#& for i = 8, 10 do!@#& term.setCursorPos(w/2 - wid/2, i)!@#& term.write(string.rep(\" \", wid))!@#& end!@#& term.setCursorPos(1, 9)!@#& if fs.isDir(name) then!@#& centerPrint(\"Cannot Open a Directory!\")!@#& sleep(1.6)!@#& return \"menu\"!@#& elseif not fs.exists(name) then!@#& centerPrint(\"File Doesn't Exist!\")!@#& local opt = prompt({{\"Create\", w/2 - 11, 14}, {\"Cancel\", w/2 + 2, 14}}, \"horizontal\")!@#& if opt == \"Create\" then return \"edit\", name!@#& elseif opt == \"Cancel\" then return \"menu\" end!@#& else return \"edit\", name end!@#&end!@#&!@#&!@#&-- -------- Settings!@#&!@#&local function update()!@#& local function draw(status)!@#& title(\"LuaIDE - Update\")!@#& term.setBackgroundColor(colors[theme.prompt])!@#& term.setTextColor(colors[theme.textColor])!@#& for i = 8, 10 do!@#& term.setCursorPos(w/2 - (status:len() + 4), i)!@#& write(string.rep(\" \", status:len() + 4))!@#& end!@#& term.setCursorPos(w/2 - (status:len() + 4), 9)!@#& term.write(\" - \" .. status .. \" \")!@#&!@#& term.setBackgroundColor(colors[theme.errHighlight])!@#& for i = 8, 10 do!@#& term.setCursorPos(w/2 + 2, i)!@#& term.write(string.rep(\" \", 10))!@#& end!@#& term.setCursorPos(w/2 + 2, 9)!@#& term.write(\" > Cancel \")!@#& end!@#&!@#& if not http then!@#& draw(\"HTTP API Disabled!\")!@#& sleep(1.6)!@#& return \"settings\"!@#& end!@#&!@#& draw(\"Updating...\")!@#& local tID = os.startTimer(10)!@#& http.request(updateURL)!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if (e == \"key\" and but == 28) or!@#& (e == \"mouse_click\" and x >= w/2 + 2 and x <= w/2 + 12 and y == 9) then!@#& draw(\"Cancelled\")!@#& sleep(1.6)!@#& break!@#& elseif e == \"http_success\" and but == updateURL then!@#& local new = x.readAll()!@#& local curf = io.open(ideLocation, \"r\")!@#& local cur = curf:read(\"*a\")!@#& curf:close()!@#&!@#& if cur ~= new then!@#& draw(\"Update Found\")!@#& sleep(1.6)!@#& local f = io.open(ideLocation, \"w\")!@#& f:write(new)!@#& f:close()!@#&!@#& draw(\"Click to Exit\")!@#& while true do!@#& local e = os.pullEvent()!@#& if e == \"mouse_click\" or (not isAdvanced() and e == \"key\") then break end!@#& end!@#& return \"exit\"!@#& else!@#& draw(\"No Updates Found!\")!@#& sleep(1.6)!@#& break!@#& end!@#& elseif e == \"http_failure\" or (e == \"timer\" and but == tID) then!@#& draw(\"Update Failed!\")!@#& sleep(1.6)!@#& break!@#& end!@#& end!@#&!@#& return \"settings\"!@#&end!@#&!@#&local function changeTheme()!@#& title(\"LuaIDE - Theme\")!@#&!@#& if isAdvanced() then!@#& local disThemes = {\"Back\"}!@#& for _, v in pairs(availableThemes) do table.insert(disThemes, v[1]) end!@#& local t = scrollingPrompt(disThemes)!@#& local url = nil!@#& for _, v in pairs(availableThemes) do if v[1] == t then url = v[2] end end!@#&!@#& if not url then return \"settings\" end!@#& if t == \"Dawn (Default)\" then!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& term.setCursorPos(3, 3)!@#& term.clearLine()!@#& term.write(\"LuaIDE - Loaded Theme!\")!@#& sleep(1.6)!@#&!@#& fs.delete(themeLocation)!@#& theme = defaultTheme!@#& return \"menu\"!@#& end!@#&!@#& term.setBackgroundColor(colors[theme.backgroundHighlight])!@#& term.setCursorPos(3, 3)!@#& term.clearLine()!@#& term.write(\"LuaIDE - Downloading...\")!@#&!@#& fs.delete(\"/.LuaIDE_temp_theme_file\")!@#& download(url, \"/.LuaIDE_temp_theme_file\")!@#& local a = loadTheme(\"/.LuaIDE_temp_theme_file\")!@#&!@#& term.setCursorPos(3, 3)!@#& term.clearLine()!@#& if a then!@#& term.write(\"LuaIDE - Loaded Theme!\")!@#& fs.delete(themeLocation)!@#& fs.move(\"/.LuaIDE_temp_theme_file\", themeLocation)!@#& theme = a!@#& sleep(1.6)!@#& return \"menu\"!@#& end!@#& !@#& term.write(\"LuaIDE - Could Not Load Theme!\")!@#& fs.delete(\"/.LuaIDE_temp_theme_file\")!@#& sleep(1.6)!@#& return \"settings\"!@#& else!@#& term.setCursorPos(1, 8)!@#& centerPrint(\"Themes are not available on\")!@#& centerPrint(\"normal computers!\")!@#& end!@#&end!@#&!@#&local function settings()!@#& title(\"LuaIDE - Settings\")!@#&!@#& local opt = prompt({{\"Change Theme\", w/2 - 17, 8}, {\"Return to Menu\", w/2 - 22, 13},!@#& {\"Check for Updates\", w/2 + 2, 8}, {\"Exit IDE\", w/2 + 2, 13, bg = colors[theme.err], !@#& highlight = colors[theme.errHighlight]}}, \"vertical\", true)!@#& if opt == \"Change Theme\" then return changeTheme()!@#& elseif opt == \"Check for Updates\" then return update()!@#& elseif opt == \"Return to Menu\" then return \"menu\"!@#& elseif opt == \"Exit IDE\" then return \"exit\" end!@#&end!@#&!@#&!@#&-- -------- Menu!@#&!@#&local function menu()!@#& title(\"Welcome to LuaIDE \" .. version)!@#&!@#& local opt = prompt({{\"New File\", w/2 - 13, 8}, {\"Open File\", w/2 - 14, 13},!@#& {\"Settings\", w/2 + 2, 8}, {\"Exit IDE\", w/2 + 2, 13, bg = colors[theme.err],!@#& highlight = colors[theme.errHighlight]}}, \"vertical\", true)!@#& if opt == \"New File\" then return \"new\"!@#& elseif opt == \"Open File\" then return \"open\"!@#& elseif opt == \"Settings\" then return \"settings\"!@#& elseif opt == \"Exit IDE\" then return \"exit\" end!@#&end!@#&!@#&!@#&-- -------- Main!@#&!@#&local function main(arguments)!@#& local opt, data = \"menu\", nil!@#&!@#& -- Check arguments!@#& if type(arguments) == \"table\" and #arguments > 0 then!@#& local f = \"/\" .. shell.resolve(arguments[1])!@#& if fs.isDir(f) then print(\"Cannot edit a directory.\") end!@#& opt, data = \"edit\", f!@#& end!@#&!@#& -- Main run loop!@#& while true do!@#& -- Menu!@#& if opt == \"menu\" then opt = menu() end!@#&!@#& -- Other!@#& if opt == \"new\" then opt, data = newFile()!@#& elseif opt == \"open\" then opt, data = openFile()!@#& elseif opt == \"settings\" then opt = settings()!@#& end if opt == \"exit\" then break end!@#&!@#& -- Edit!@#& if opt == \"edit\" and data then opt = edit(data) end!@#& end!@#&end!@#&!@#&-- Load Theme!@#&if fs.exists(themeLocation) then theme = loadTheme(themeLocation) end!@#&if not theme and isAdvanced() then theme = defaultTheme!@#&elseif not theme then theme = normalTheme end!@#&!@#&-- Run!@#&local _, err = pcall(function()!@#& parallel.waitForAny(function() main(args) end, monitorKeyboardShortcuts)!@#&end)!@#&!@#&-- Catch errors!@#&if err and not err:find(\"Terminated\") then!@#& term.setCursorBlink(false)!@#& title(\"LuaIDE - Crash! D:\")!@#&!@#& term.setBackgroundColor(colors[theme.err])!@#& for i = 6, 8 do!@#& term.setCursorPos(5, i)!@#& term.write(string.rep(\" \", 36))!@#& end!@#& term.setCursorPos(6, 7)!@#& term.write(\"LuaIDE Has Crashed! D:\")!@#&!@#& term.setBackgroundColor(colors[theme.background])!@#& term.setCursorPos(2, 10)!@#& print(err)!@#&!@#& term.setBackgroundColor(colors[theme.prompt])!@#& local _, cy = term.getCursorPos()!@#& for i = cy + 1, cy + 4 do!@#& term.setCursorPos(5, i)!@#& term.write(string.rep(\" \", 36))!@#& end!@#& term.setCursorPos(6, cy + 2)!@#& term.write(\"Please report this error to\")!@#& term.setCursorPos(6, cy + 3)!@#& term.write(\"GravityScore! \")!@#& !@#& term.setBackgroundColor(colors[theme.background])!@#& if isAdvanced() then centerPrint(\"Click to Exit...\", h - 1)!@#& else centerPrint(\"Press Any Key to Exit...\", h - 1) end!@#& while true do!@#& local e = os.pullEvent()!@#& if e == \"mouse_click\" or (not isAdvanced() and e == \"key\") then break end!@#& end!@#&!@#& -- Prevent key from being shown!@#& os.queueEvent(event_distract)!@#& os.pullEvent()!@#&end!@#&!@#&-- Exit!@#&term.setBackgroundColor(colors.black)!@#&term.setTextColor(colors.white)!@#&term.clear()!@#&term.setCursorPos(1, 1)!@#¢erPrint(\"Thank You for Using Lua IDE \" .. version)!@#¢erPrint(\"Made by GravityScore\")",["pgen"]="local args = {...}!@#&local chars = {\"Anus\", \"Cock\", \"Dick\", \"Whore\", \"Prick\", \"Cunt\", \"Faggot\", \"Fuck\", \"Twat\", \"E\", \"f\", \"F\", \"g\", \"G\", \"h\", \"H\", \"i\", \"I\", \"j\", \"J\", \"k\", \"K\", \"l\", \"L\", \"m\", \"M\", \"n\", \"N\", \"o\", \"O\", \"p\", \"P\", \"q\", \"Q\", \"r\", \"R\", \"s\", \"S\", \"t\", \"T\", \"u\", \"U\", \"v\", \"V\", \"w\", \"W\", \"x\", \"X\", \"y\", \"Y\", \"z\", \"Z\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\", \"!\", \"@\", \"-\", \"_\", \"#\", \"%\", \"$\", \"*\", \"+\"}!@#&local pass = \"\"!@#&char = math.random(8, 32)!@#&for i = 1, char do!@#& local ranChar = math.random(1, #chars)!@#& pass = pass..chars[ranChar]!@#&end!@#&print(pass)",["lightshot"]="!@#&-- !@#&-- Lighshot Screen Recorder!@#&-- Made by GravityScore!@#&-- !@#&!@#&!@#&-- -------- Variables!@#&!@#&-- Lower the loop rate to decrease recording lag but to decrease compression!@#&-- Do not set to below 50 else the file could become really big!@#&local loopRate = 300!@#&!@#&-- Version!@#&local version = \"1.4\"!@#&!@#&-- Terminal!@#&local oldTerm = {}!@#&local newTerm = {}!@#&local w, h = term.getSize()!@#&!@#&-- Events!@#&local event_exitRecording = \"lightshot_exitRecordingEvent\"!@#&!@#&-- Locations!@#&local lightshotURL = \"https://raw.github.com/GravityScore/Lightshot/master/lightshot.lua\"!@#&local lightshotLocation = \"/\" .. shell.getRunningProgram()!@#&!@#&-- Variables!@#&local clock = 0!@#&local nfaRecording = false!@#&local recordData = [[!@#&!@#&local function sp(...) return sleep(...) end!@#&local function c(...) return term.write(...) end!@#&local function d(...) return term.setCursorPos(...) end!@#&local function e(...) return term.setBackgroundColor(...) end!@#&local function f(...) return term.setTextColor(...) end!@#&local function g(...) return term.clear(...) end!@#&local function h(...) return term.clearLine() end!@#&local function i(...) return term.setCursorBlink(...) end!@#&local function j(...) return term.scroll(...) end!@#&!@#&]]!@#&!@#&local recordHeader = [[!@#&-- !@#&-- Recorded by Lightshot!@#&-- !@#&!@#&!@#&]]!@#&!@#&!@#&-- -------- Utilities!@#&!@#&local function modRead(properties)!@#& local w, h = term.getSize()!@#& local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, !@#& liveUpdates = nil, exitOnKey = nil}!@#& if not properties then properties = {} end!@#& for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end!@#& if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end!@#& if not properties.visibleLength then properties.visibleLength = w end!@#&!@#& local sx, sy = term.getCursorPos()!@#& local line = \"\"!@#& local pos = 0!@#& local historyPos = nil!@#&!@#& local function redraw(repl)!@#& local scroll = 0!@#& if properties.visibleLength and sx + pos > properties.visibleLength + 1 then !@#& scroll = (sx + pos) - (properties.visibleLength + 1)!@#& end!@#&!@#& term.setCursorPos(sx, sy)!@#& local a = repl or properties.replaceChar!@#& if a then term.write(string.rep(a, line:len() - scroll))!@#& else term.write(line:sub(scroll + 1, -1)) end!@#& term.setCursorPos(sx + pos - scroll, sy)!@#& end!@#&!@#& local function sendLiveUpdates(event, ...)!@#& if type(properties.liveUpdates) == \"function\" then!@#& local ox, oy = term.getCursorPos()!@#& properties.liveUpdates(line, event, ...)!@#& if a == true and data == nil then!@#& term.setCursorBlink(false)!@#& return line!@#& elseif a == true and data ~= nil then!@#& term.setCursorBlink(false)!@#& return data!@#& end!@#& term.setCursorPos(ox, oy)!@#& end!@#& end!@#&!@#& term.setCursorBlink(true)!@#& while true do!@#& local e, but, x, y, p4, p5 = os.pullEvent()!@#&!@#& if e == \"char\" then!@#& local s = false!@#& if properties.textLength and line:len() < properties.textLength then s = true!@#& elseif not properties.textLength then s = true end!@#&!@#& local canType = true!@#& if not properties.grantPrint and properties.refusePrint then!@#& local canTypeKeys = {}!@#& if type(properties.refusePrint) == \"table\" then!@#& for _, v in pairs(properties.refusePrint) do!@#& table.insert(canTypeKeys, tostring(v):sub(1, 1))!@#& end!@#& elseif type(properties.refusePrint) == \"string\" then!@#& for char in properties.refusePrint:gmatch(\".\") do!@#& table.insert(canTypeKeys, char)!@#& end!@#& end!@#& for _, v in pairs(canTypeKeys) do if but == v then canType = false end end!@#& elseif properties.grantPrint then!@#& canType = false!@#& local canTypeKeys = {}!@#& if type(properties.grantPrint) == \"table\" then!@#& for _, v in pairs(properties.grantPrint) do!@#& table.insert(canTypeKeys, tostring(v):sub(1, 1))!@#& end!@#& elseif type(properties.grantPrint) == \"string\" then!@#& for char in properties.grantPrint:gmatch(\".\") do!@#& table.insert(canTypeKeys, char)!@#& end!@#& end!@#& for _, v in pairs(canTypeKeys) do if but == v then canType = true end end!@#& end!@#&!@#& if s and canType then!@#& line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)!@#& pos = pos + 1!@#& redraw()!@#& end!@#& elseif e == \"key\" then!@#& if but == keys.enter then break!@#& elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end!@#& elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end!@#& elseif (but == keys.up or but == keys.down) and properties.history then!@#& redraw(\" \")!@#& if but == keys.up then!@#& if historyPos == nil and #properties.history > 0 then !@#& historyPos = #properties.history!@#& elseif historyPos > 1 then !@#& historyPos = historyPos - 1!@#& end!@#& elseif but == keys.down then!@#& if historyPos == #properties.history then historyPos = nil!@#& elseif historyPos ~= nil then historyPos = historyPos + 1 end!@#& end!@#&!@#& if properties.history and historyPos then!@#& line = properties.history[historyPos]!@#& pos = line:len()!@#& else!@#& line = \"\"!@#& pos = 0!@#& end!@#&!@#& redraw()!@#& sendLiveUpdates(\"history\")!@#& elseif but == keys.backspace and pos > 0 then!@#& redraw(\" \")!@#& line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)!@#& pos = pos - 1!@#& redraw()!@#& sendLiveUpdates(\"delete\")!@#& elseif but == keys.home then!@#& pos = 0!@#& redraw()!@#& elseif but == keys.delete and pos < line:len() then!@#& redraw(\" \")!@#& line = line:sub(1, pos) .. line:sub(pos + 2, -1)!@#& redraw()!@#& sendLiveUpdates(\"delete\")!@#& elseif but == keys[\"end\"] then!@#& pos = line:len()!@#& redraw()!@#& elseif properties.exitOnKey then !@#& if but == properties.exitOnKey or (properties.exitOnKey == \"control\" and !@#& (but == 29 or but == 157)) then !@#& term.setCursorBlink(false)!@#& return nil!@#& end!@#& end!@#& end!@#&!@#& sendLiveUpdates(e, but, x, y, p4, p5)!@#& end!@#&!@#& term.setCursorBlink(false)!@#& if line ~= nil then line = line:gsub(\"^%s*(.-)%s*$\", \"%1\") end!@#& return line!@#&end!@#&!@#&local function centerPrint(text, ny)!@#& if type(text) == \"table\" then for _, v in pairs(text) do centerPrint(v) end!@#& else!@#& local x, y = term.getCursorPos()!@#& local w, h = term.getSize()!@#& term.setCursorPos(w/2 - text:len()/2 + (#text % 2 == 0 and 1 or 0), ny or y)!@#& print(text)!@#& end!@#&end!@#&!@#&!@#&-- -------- Updating!@#&!@#&local function download(url, path)!@#& for i = 1, 3 do!@#& local response = http.get(url)!@#& if response then!@#& local data = response.readAll()!@#& response.close()!@#& if path then!@#& local f = io.open(path, \"w\")!@#& f:write(data)!@#& f:close()!@#& end!@#& return true!@#& end!@#& end!@#&!@#& return false!@#&end!@#&!@#&local function updateClient()!@#& local updateLocation = \"/.lightshot-update\"!@#& fs.delete(updateLocation)!@#&!@#& download(lightshotURL, updateLocation)!@#& local a = io.open(updateLocation, \"r\")!@#& local b = io.open(lightshotLocation, \"r\")!@#& local new = a:read(\"*a\")!@#& local cur = b:read(\"*a\")!@#& a:close()!@#& b:close()!@#&!@#& if cur ~= new then!@#& fs.delete(lightshotLocation)!@#& fs.move(updateLocation, lightshotLocation)!@#& return true!@#& else!@#& fs.delete(updateLocation)!@#& return false!@#& end!@#&end!@#&!@#&!@#&-- -------- Compression!@#&!@#&local sD = {{}}!@#&local cD = {}!@#&!@#&local function proccessFunction(data)!@#& if data:len() < 8 then!@#& if data:sub(-1,-1) == \"]\" then return \"[[\" .. data .. \"] .. \\\"]\\\"\"!@#& else return \"[[\" .. data .. \"]]\" end!@#& end!@#& if cD[v] then return cD[v] end!@#& for k, v in pairs(sD[#sD]) do!@#& if v == data then!@#& cD[v] = (\"sD[\" .. #sD .. \"][\" .. k .. \"]\")!@#& return(\"sD[\" .. #sD .. \"][\" .. k .. \"]\")!@#& end!@#& end!@#& table.insert(sD[#sD], data)!@#& local returnData = (\"sD[\".. #sD .. \"][\" .. #sD[#sD] .. \"]\")!@#& if #sD[#sD] > loopRate then sD[#sD + 1] = {} end!@#& return returnData!@#&end!@#&!@#&!@#&-- -------- Terminal Override!@#&!@#&local bg, tc, blnk = -1, -1, nil!@#&for k, v in pairs(term.native) do oldTerm[k] = v end!@#&!@#&newTerm.write = function(...)!@#& local text = \"\"!@#& for k, v in pairs({...}) do text = text .. tostring(v) end!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#&!@#& text = proccessFunction(tostring(text))!@#& local b = \"c(\" .. text .. \")\\n\"!@#& recordData = recordData .. a .. b!@#& clock = os.clock()!@#& if not nfaRecording then return oldTerm.write(...) end!@#&end!@#&!@#&newTerm.setCursorPos = function(x, y)!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#& recordData = recordData .. a .. \"d(\" .. tostring(x) .. \", \" .. tostring(y) .. \")\\n\"!@#& clock = os.clock()!@#&!@#& return oldTerm.setCursorPos(x, y)!@#&end!@#&!@#&newTerm.getCursorPos = function(...) return oldTerm.getCursorPos(...) end!@#&!@#&newTerm.setBackgroundColor = function(col)!@#& if bg ~= col then!@#& local a = \"\"!@#& if not nfaRecording and os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#&!@#& recordData = recordData .. a .. \"e(\" .. tostring(col) .. \")\\n\"!@#& clock = os.clock()!@#& bg = col!@#& end!@#&!@#& return oldTerm.setBackgroundColor(col)!@#&end!@#&!@#&newTerm.setTextColor = function(col)!@#& if tc ~= col then!@#& local a = \"\"!@#& if not nfaRecording and os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#&!@#& recordData = recordData .. a .. \"f(\" .. tostring(col) .. \")\\n\"!@#& clock = os.clock()!@#& tc = col!@#& end!@#&!@#& return oldTerm.setTextColor(col)!@#&end!@#&!@#&newTerm.setBackgroundColour = function(col) return term.setBackgroundColor(col) end!@#&newTerm.setTextColour = function(col) return term.setTextColor(col) end!@#&!@#&newTerm.clear = function(...)!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#& recordData = recordData .. a .. \"g()\\n\"!@#& clock = os.clock()!@#&!@#& return oldTerm.clear(...)!@#&end!@#&!@#&newTerm.clearLine = function(...)!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#& recordData = recordData .. a .. \"h()\\n\"!@#& clock = os.clock()!@#&!@#& return oldTerm.clearLine(...)!@#&end!@#&!@#&newTerm.setCursorBlink = function(flag)!@#& if flag ~= blnk then!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#& recordData = recordData .. a .. \"i(\" .. tostring(flag) .. \")\\n\"!@#& clock = os.clock()!@#& blnk = flag!@#& end!@#&!@#& return oldTerm.setCursorBlink(flag)!@#&end!@#&!@#&newTerm.scroll = function(n)!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#& recordData = recordData .. a .. \"j(\" .. tostring(n) .. \")\\n\"!@#& clock = os.clock()!@#&!@#& return oldTerm.scroll(n)!@#&end!@#&!@#&newTerm.getSize = function(...) return oldTerm.getSize(...) end!@#&newTerm.redirect = function(...) return oldTerm.redirect(...) end!@#&newTerm.restore = function(...) return oldTerm.restore(...) end!@#&newTerm.isColor = function(...) return oldTerm.isColor and oldTerm.isColor(...) end!@#&newTerm.isColour = function(...) return term.isColor(...) end!@#&!@#&!@#&-- -------- Recording!@#&!@#&local function record(location)!@#& while true do!@#& local e, key = os.pullEventRaw()!@#& if (e == \"key\" and key == 59) or e == event_exitRecording or e == \"terminate\" then!@#& local a = \"\"!@#& if os.clock() - clock > 0 then a = \"sp(\" .. os.clock() - clock .. \") \" end!@#& recordData = recordData .. a!@#&!@#& recordData = recordData .. \"term.setCursorBlink(false)\\n\"!@#& recordData = recordData .. \"if term.isColor() then term.setTextColor(colors.yellow)\\n\"!@#& recordData = recordData .. \"else term.setTextColor(colors.white) end\\n\"!@#& recordData = recordData .. \"term.setBackgroundColor(colors.black)\\n\"!@#& recordData = recordData .. \"term.clear()\\n\"!@#& recordData = recordData .. \"term.setCursorPos(1, 1)\\n\"!@#& recordData = recordData .. \"print(\\\"End of Recording!\\\")\\n\"!@#&!@#& recordHeader = recordHeader .. \"local sD = \" .. textutils.serialize(sD) .. \"\\n\"!@#& recordData = recordHeader .. recordData!@#&!@#& term.restore()!@#& term.setCursorBlink(false)!@#& if term.isColor() then term.setTextColor(colors.yellow)!@#& else term.setTextColor(colors.white) end!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"Recording Saved!\")!@#& sleep(1.1)!@#&!@#& local f = io.open(location, \"w\")!@#& f:write(recordData)!@#& f:close()!@#& return!@#& end!@#& end!@#&end!@#&!@#&!@#&-- -------- Movie!@#&!@#&local function loadNfa(path)!@#& local ret = {}!@#& if fs.exists(path) and not fs.isDir(path) then!@#& local f = io.open(path, \"r\")!@#& local l = f:read(\"*l\")!@#& local curFrame = \"\"!@#& while l do!@#& if l ~= \"\" and l ~= \"~\" then curFrame = curFrame .. l .. \"\\n\"!@#& elseif l == \"~\" then!@#& table.insert(ret, curFrame)!@#& curFrame = \"\"!@#& end!@#& l = f:read(\"*l\")!@#& end!@#& f:close()!@#& end!@#&!@#& return ret!@#&end!@#&!@#&local function movie(location, duration)!@#& nfaRecording = true!@#& local frames = loadNfa(location)!@#& if frames ~= {} then!@#& for i, v in ipairs(frames) do!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#&!@#& local tempImageLocation = \"/.lightshot-temp-image\"!@#& local f = io.open(tempImageLocation, \"w\")!@#& f:write(v)!@#& f:close()!@#& local a = paintutils.loadImage(tempImageLocation)!@#& paintutils.drawImage(a, 1, 1)!@#& fs.delete(tempImageLocation)!@#& recordData = recordData .. \"sp(\" .. duration .. \")\\n\"!@#& end!@#&!@#& recordData = recordData .. \"sp(\" .. duration .. \")\\n\"!@#& end!@#&!@#& recordData = recordData .. \"term.setCursorBlink(false)\\n\"!@#& recordData = recordData .. \"if term.isColor() then term.setTextColor(colors.yellow)\\n\"!@#& recordData = recordData .. \"else term.setTextColor(colors.white) end\\n\"!@#& recordData = recordData .. \"term.setBackgroundColor(colors.black)\\n\"!@#& recordData = recordData .. \"term.clear()\\n\"!@#& recordData = recordData .. \"term.setCursorPos(1, 1)\\n\"!@#& recordData = recordData .. \"print(\\\"The End! :D\\\")\\n\"!@#&!@#& nfaRecording = false!@#& term.restore()!@#& term.setCursorBlink(false)!@#& if term.isColor() then term.setTextColor(colors.yellow)!@#& else term.setTextColor(colors.white) end!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"Movie Recorded Successfully!\")!@#&!@#& local f = io.open(location:sub(1, -5) .. \"-movie\", \"w\")!@#& f:write(recordData)!@#& f:close()!@#&end!@#&!@#&!@#&-- -------- Main!@#&!@#&local theme = {}!@#&if term.isColor and term.isColor() then!@#& theme = {!@#& [\"prompt\"] = \"cyan\",!@#& [\"promptHighlight\"] = \"lightBlue\",!@#& [\"textColor\"] = \"white\",!@#& }!@#&else!@#& theme = {!@#& [\"prompt\"] = \"black\",!@#& [\"promptHighlight\"] = \"black\",!@#& [\"textColor\"] = \"white\",!@#& }!@#&end!@#&!@#&local function drawButton(v, sel)!@#& if sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])!@#& else term.setBackgroundColor(v.bg or colors[theme.prompt]) end!@#& term.setTextColor(v.tc or colors[theme.textColor])!@#& for i = -1, 1 do!@#& term.setCursorPos(v[2], v[3] + i)!@#& term.write(string.rep(\" \", v[1]:len() + 4))!@#& end!@#&!@#& term.setCursorPos(v[2], v[3])!@#& if sel then!@#& term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])!@#& term.write(\" > \")!@#& else term.write(\" - \") end!@#& term.write(v[1] .. \" \")!@#&end!@#&!@#&local function prompt(list, dir)!@#& local function draw(sel)!@#& for i, v in ipairs(list) do!@#& if i == sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])!@#& else term.setBackgroundColor(v.bg or colors[theme.prompt]) end!@#& term.setTextColor(v.tc or colors[theme.textColor])!@#& for i = -1, 1 do!@#& term.setCursorPos(v[2], v[3] + i)!@#& term.write(string.rep(\" \", v[1]:len() + 4))!@#& end!@#&!@#& term.setCursorPos(v[2], v[3])!@#& if i == sel then!@#& term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])!@#& term.write(\" > \")!@#& else term.write(\" - \") end!@#& term.write(v[1] .. \" \")!@#& end!@#& end!@#&!@#& local sel = 1!@#& draw(sel)!@#&!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"key\" and but == 28 then return list[sel][1]!@#& elseif e == \"key\" and but == 200 and sel > 1 then!@#& sel = sel - 1!@#& draw(sel)!@#& elseif e == \"key\" and but == 208 and ((err == true and sel < #list - 1) or (sel < #list)) then!@#& sel = sel + 1!@#& draw(sel)!@#& elseif e == \"key\" and but == 203 and sel > 2 then!@#& sel = sel - 2!@#& draw(sel)!@#& elseif e == \"key\" and but == 205 and sel < 3 then!@#& sel = sel + 2!@#& draw(sel)!@#& elseif e == \"mouse_click\" then!@#& for i, v in ipairs(list) do!@#& if x >= v[2] - 1 and x <= v[2] + v[1]:len() + 3 and y >= v[3] - 1 and y <= v[3] + 1 then!@#& return list[i][1]!@#& end!@#& end!@#& end!@#& end!@#&end!@#&!@#&local function menu()!@#& term.setBackgroundColor(colors.gray)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#&!@#& term.setBackgroundColor(colors.lightGray)!@#& for i = 2, 4 do term.setCursorPos(1, i) term.clearLine() end!@#& term.setCursorPos(3, 3)!@#& term.write(\"Lightshot \" .. version)!@#&!@#& local opt = prompt({{\"Record a Video\", w/2 - 16, 9}, {\"Record an Animation\", w/2 - 21, 13},!@#& {\"Update Lightshot\", w/2 + 4, 9}, {\"Exit\", w/2 + 4, 13, bg = (term.isColor and term.isColor())!@#& and colors.red or colors.black, highlight = (term.isColor and term.isColor()) and colors.pink!@#& or colors.black}}, \"vertical\")!@#& if opt == \"Record a Video\" or opt == \"Record an Animation\" then!@#& term.setBackgroundColor(colors.gray)!@#& for i = 7, 14 do term.setCursorPos(1, i) term.clearLine() end!@#& term.setBackgroundColor(colors.cyan)!@#& for i = 8, 11 do term.setCursorPos(7, i) term.write(string.rep(\" \", w - 14)) end!@#& drawButton({\"Control to Return to Menu\", 7, 14}, true)!@#& term.setBackgroundColor(colors.cyan)!@#& term.setCursorPos(8, 9)!@#& term.write(\"Path:\")!@#& term.setCursorPos(9, 10)!@#& local loc = modRead({visibleLength = w - 14, exitOnKey = \"control\"})!@#& if not loc or loc == \"\" then return \"menu\" end!@#&!@#& term.setCursorPos(8, 9)!@#& term.write(string.rep(\" \", 5))!@#& term.setCursorPos(8, 9)!@#& loc = \"/\" .. shell.resolve(loc)!@#& if fs.isReadOnly(loc) then term.write(\"File is Read Only!\") sleep(1.6) return \"menu\"!@#& elseif opt == \"Record a Video\" then!@#& if fs.exists(loc) then fs.delete(loc) end!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(2, 5)!@#& term.write(\"Press F1 to end the recording\")!@#&!@#& if term.isColor and term.isColor() then term.setTextColor(colors.yellow) end!@#& for i = 1, 3 do!@#& term.setCursorPos(2, 3)!@#& term.clearLine()!@#& term.write(\"Recording in \" .. 4 - i .. \"...\")!@#& sleep(1)!@#& end!@#&!@#& return \"record\", loc!@#& elseif opt == \"Record an Animation\" then!@#& if loc:sub(-4, -1) ~= \".nfa\" then!@#& term.write(\"File Not An Animation!\")!@#& sleep(1.6)!@#& return \"menu\"!@#& end!@#&!@#& term.setCursorPos(8, 9)!@#& term.write(\"Duration between frames (seconds):\")!@#& term.setCursorPos(9, 10)!@#& term.write(string.rep(\" \", w - 16))!@#& term.setCursorPos(9, 10)!@#& local dur = modRead({visibleLength = w - 14, exitOnKey = \"control\"})!@#& if not dur or dur == \"\" then return \"menu\" end!@#&!@#& term.setCursorPos(8, 9)!@#& term.write(string.rep(\" \", 38))!@#& term.setCursorPos(8, 9)!@#& dur = tonumber(dur)!@#& if not dur then term.write(\"Duration must be an integer!\") sleep(1.6) return \"menu\"!@#& else return \"tomovie\", loc, dur end!@#& end!@#& elseif opt == \"Update Lightshot\" then!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.lightGray)!@#& term.setCursorPos(3, 3)!@#& term.clearLine()!@#& term.write(\"Checking for Updates...\")!@#& term.setCursorPos(3, 3)!@#& if updateClient() then!@#& term.clearLine()!@#& term.write(\"Updated!\")!@#& sleep(1.6)!@#& opt = \"Exit\"!@#& else!@#& term.clearLine()!@#& term.write(\"No Updates Found!\")!@#& sleep(1.6)!@#& return \"menu\"!@#& end!@#& end if opt == \"Exit\" then return nil end!@#&end!@#&!@#&local function main()!@#& local action, location, duration = \"menu\", nil, nil!@#& while action == \"menu\" do action, location, duration = menu() end!@#&!@#& if action and location then!@#& clock = os.clock()!@#& term.redirect(newTerm)!@#&!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& if action == \"record\" then!@#& parallel.waitForAny(function()!@#& record(location)!@#& end, function()!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& if fs.exists(\"/startup\") and not fs.isDir(\"/startup\") then shell.run(\"/startup\")!@#& else shell.run(\"/rom/programs/shell\") end!@#& os.queueEvent(event_exitRecording)!@#& end)!@#& elseif action == \"tomovie\" then!@#& movie(location, duration)!@#& end!@#& end!@#&end!@#&!@#&-- Run!@#&local oldDir = shell.dir()!@#&main()!@#&shell.setDir(oldDir)!@#&!@#&-- Exit Message!@#&term.setBackgroundColor(colors.black)!@#&term.setTextColor(colors.white)!@#&term.clear()!@#&term.setCursorPos(1, 1)!@#¢erPrint(\"Thanks for Using Lightshot \" .. version .. \"!\")!@#¢erPrint(\"Made by GravityScore and 1lann\")",["ev"]="keynos = {[\"1\"] = \"Escape\", [\"59\"] = \"Function 1\", [\"60\"] = \"Function 2\", [\"61\"] = \"Function 3\", [\"62\"] = \"Function 4\", [\"63\"] = \"Function 5\", [\"64\"] = \"Function 6\", [\"65\"] = \"Function 7\",[\"66\"] = \"Function 8\", [\"67\"] = \"Function 9\", [\"68\"] = \"Function 10\", [\"87\"] = \"Function 11\", [\"88\"] = \"Function 12\", [\"70\"] = \"Scroll Lock\", [\"197\"] = \"Pause/Break\", [\"41\"] = \"Grave Accent\"}!@#&while true do!@#& _,key = os.pullEvent(\"key\")!@#& print(\"Finger # \" .. key .. \" inserted into anus\")!@#&end",["startz"]="im = paintutils.loadImage(\"/lib/im\")!@#&w,h = term.getSize()!@#&function drawScreen()!@#& term.setBackgroundColor(colors.lightGray)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& term.setBackgroundColor(colors.white)!@#& term.setTextColor(colors.black)!@#& write(string.rep(\" \", w))!@#& term.setCursorPos(1,1)!@#& if sudo.isAdmin() then!@#& write(linox.getVerNo() .. \" (as admin)\")!@#& else!@#& write(linox.getVerNo())!@#& end!@#& term.setCursorPos(20,1)!@#& if spd.getData(\"updates\") then!@#& term.setTextColor(colors.red)!@#& else!@#& term.setTextColor(colors.lime)!@#& end!@#& term.setCursorPos(15,1)!@#& write(\"[OS updates]\")!@#& term.setTextColor(colors.black)!@#& term.setCursorPos(w-string.len(\"[Quit]\"),1)!@#& quitx, _ = term.getCursorPos()!@#& print(\"[Quit]\")!@#& quitx2, _ = term.getCursorPos()!@#& paintutils.drawImage(im, 16, 8)!@#& return quitx,quity!@#&end!@#&!@#&function drawIcons()!@#& term.setTextColor(colors.white)!@#& paintutils.drawPixel(5,6,colors.blue)!@#& paintutils.drawPixel(5,7,colors.lime)!@#& paintutils.drawPixel(6,6,colors.lime)!@#& paintutils.drawPixel(6,7,colors.blue)!@#& term.setCursorPos(2,9)!@#& term.setBackgroundColor(colors.lightGray)!@#& print(\"Programs\")!@#& paintutils.drawPixel(5,12,colors.red)!@#& paintutils.drawPixel(5,13,colors.yellow)!@#& paintutils.drawPixel(6,12,colors.yellow)!@#& paintutils.drawPixel(6,13,colors.red)!@#& term.setCursorPos(3,15)!@#& term.setBackgroundColor(colors.lightGray)!@#& print(\"Options\")!@#&end!@#&!@#&x,x2 = drawScreen()!@#&drawIcons()!@#&!@#&function getClickPos()!@#& _,b,xpos,ypos = os.pullEvent(\"mouse_click\")!@#& if xpos == 5 or xpos == 6 then!@#& if ypos == 6 or ypos == 7 then!@#& return \"apps\"!@#& elseif ypos == 12 or ypos == 13 then!@#& return \"opts\"!@#& end!@#& elseif xpos == x+1 or xpos == x+2 or xpos == x+3 or xpos == x+4 or xpos == x+5 or xpos == x2 then!@#& if ypos == 1 then!@#& return \"quit\"!@#& end!@#& elseif xpos > 15 and xpos < 27 then!@#& if ypos == 1 then!@#& return \"update\"!@#& end!@#& end!@#&end!@#&!@#&!@#&while true do!@#& button = getClickPos()!@#& if button == \"apps\" or button == \"opts\" or button == \"quit\" or button == \"update\" then!@#& break!@#& end!@#&end!@#&!@#&l = string.len(\" \")!@#&if button == \"apps\" then!@#& term.setCursorPos(w/2-l/2,h/2-2)!@#& term.setBackgroundColor(colors.red)!@#& print(\" \")!@#& term.setCursorPos(w/2-l/2,h/2-1)!@#& print(\" App name: \")!@#& term.setCursorPos(w/2-l/2,h/2)!@#& print(\" \")!@#& term.setCursorPos(w/2-l/2,h/2+1)!@#& print(\" \")!@#& term.setCursorPos(w/2-l/2,h/2+2)!@#& print(\" \")!@#& term.setCursorPos(w/2-l/2+2,h/2)!@#& app = read()!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& shell.run(app)!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& shell.run(\"startz\")!@#&elseif button == \"opts\" then!@#& shell.run(\"gksu\", \"/bin/optlib/opts\")!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#& shell.run(\"startz\")!@#&elseif button == \"quit\" then!@#& term.setBackgroundColor(colors.black)!@#& term.clear()!@#& term.setCursorPos(1,1)!@#&elseif button == \"update\" then!@#& shell.run(\"updates\")!@#& shell.run(\"startz\")!@#&end",["npaintpro"]="--[[!@#& NPaintPro!@#& By NitrogenFingers!@#&]]--!@#&!@#&--The screen size!@#&local w,h = term.getSize()!@#&--Whether or not the program is currently waiting on user input!@#&local inMenu = false!@#&--Whether or not a drop down menu is active!@#&local inDropDown = false!@#&--Whether or not animation tools are enabled (use -a to turn them on)!@#&local animated = false!@#&--Whether or not the text tools are enabled (use -t to turn them on)!@#&local textual = false!@#&--Whether or not \"blueprint\" display mode is on!@#&local blueprint = false!@#&--Whether or not the \"layer\" display is on!@#&local layerDisplay = false!@#&--Whether or not the \"direction\" display is on!@#&local printDirection = false!@#&--The tool/mode npaintpro is currently in. Default is \"paint\"!@#&--For a list of modes, check out the help file!@#&local state = \"paint\"!@#&--Whether or not the program is presently running!@#&local isRunning = true!@#&--The rednet address of the 3D printer, if one has been attached!@#&local printer = nil!@#&!@#&--The list of every frame, containing every image in the picture/animation!@#&--Note: nfp files always have the picture at frame 1!@#&local frames = { }!@#&--How many frames are currently in the given animation.!@#&local frameCount = 1!@#&--The Colour Picker column!@#&local column = {}!@#&--The currently selected left and right colours!@#&local lSel,rSel = colours.white,nil!@#&--The amount of scrolling on the X and Y axis!@#&local sx,sy = 0,0!@#&--The alpha channel colour!@#&--Change this to change default canvas colour!@#&local alphaC = colours.black!@#&--The currently selected frame. Default is 1!@#&local sFrame = 1!@#&--The contents of the image buffer- contains contents, width and height!@#&local buffer = nil!@#&--The position, width and height of the selection rectangle!@#&local selectrect = nil!@#&!@#&--Whether or not text tools are enabled for this document!@#&local textEnabled = false!@#&--The X and Y positions of the text cursor!@#&local textCurX, textCurY = 1,1!@#&!@#&--The currently calculated required materials!@#&local requiredMaterials = {}!@#&--Whether or not required materials are being displayed in the pallette!@#&local requirementsDisplayed = false!@#&--A list of the rednet ID's all in-range printers located!@#&local printerList = { }!@#&--A list of the names of all in-range printers located. Same as the printerList in reference!@#&local printerNames = { }!@#&--The selected printer!@#&local selectedPrinter = 1!@#&--The X,Y,Z and facing of the printer!@#&local px,py,pz,pfx,pfz = 0,0,0,0,0!@#&--The form of layering used!@#&local layering = \"up\"!@#&!@#&--The animation state of the selection rectangle and image buffer !@#&local rectblink = 0!@#&--The ID for the timer!@#&local recttimer = nil!@#&--The radius of the brush tool!@#&local brushsize = 3!@#&--Whether or not \"record\" mode is activated (animation mode only)!@#&local record = false!@#&--The time between each frame when in play mode (animation mode only)!@#&local animtime = 0.3!@#&!@#&--The current \"cursor position\" in text mode!@#&local cursorTexX,cursorTexY = 1,1!@#&!@#&--A list of hexidecimal conversions from numbers to hex digits!@#&local hexnums = { [10] = \"a\", [11] = \"b\", [12] = \"c\", [13] = \"d\", [14] = \"e\" , [15] = \"f\" }!@#&--The NPaintPro logo (divine, isn't it?)!@#&local logo = {!@#&\"fcc 3 339\";!@#&\" fcc 9333 33\";!@#&\" fcc 933 333 33\";!@#&\" fcc 933 33 33\";!@#&\" fcc 933 33 33\";!@#&\" c88 333 93333\";!@#&\" 888 333 9333\";!@#&\" 333 3 333 939\";!@#&}!@#&--The Layer Up and Layer Forward printing icons!@#&local layerUpIcon = {!@#& \"0000000\";!@#& \"0088880\";!@#& \"0888870\";!@#& \"07777f0\";!@#& \"0ffff00\";!@#& \"0000000\";!@#&}!@#&local layerForwardIcon = {!@#& \"0000000\";!@#& \"000fff0\";!@#& \"00777f0\";!@#& \"0888700\";!@#& \"0888000\";!@#& \"0000000\";!@#&}!@#&--The available menu options in the ctrl menu!@#&local mChoices = {\"Save\",\"Exit\"}!@#&--The available modes from the dropdown menu- tables indicate submenus (include a name!)!@#&local ddModes = { { \"paint\", \"brush\", \"pippette\", \"flood\", \"move\", \"clear\", \"select\", name = \"painting\" }, { \"alpha to left\", \"alpha to right\", name = \"display\" }, \"help\", { \"print\", \"save\", \"exit\", name = \"file\" }, name = \"menu\" }!@#&--The available modes from the selection right-click menu!@#&local srModes = { \"cut\", \"copy\", \"paste\", \"clear\", \"hide\", name = \"selection\" }!@#&--The list of available help topics for each mode 127!@#&local helpTopics = {!@#& [1] = {!@#& name = \"Paint Mode\",!@#& key = nil,!@#& animonly = false,!@#& textonly = false,!@#& message = \"The default mode for NPaintPro, for painting pixels.\"!@#& ..\" Controls here that are not overridden will apply for all other modes. Leaving a mode by selecting that mode \"!@#& ..\" again will always send the user back to paint mode.\",!@#& controls = {!@#& { \"Arrow keys\", \"Scroll the canvas\" },!@#& { \"Left Click\", \"Paint/select left colour\" },!@#& { \"Right Click\", \"Paint/select right colour\" },!@#& { \"Z Key\", \"Clear image on screen\" },!@#& { \"Tab Key\", \"Hide selection rectangle if visible\" },!@#& { \"Q Key\", \"Set alpha mask to left colour\" },!@#& { \"W Key\", \"Set alpha mask to right colour\" },!@#& { \"Number Keys\", \"Swich between frames 1-9\" },!@#& { \" keys\", \"Move to the next/last frame\" },!@#& { \"R Key\", \"Removes every frame after the current frame\"}!@#& }!@#& },!@#& [2] = {!@#& name = \"Brush Mode\",!@#& key = \"b\",!@#& animonly = false,!@#& textonly = false,!@#& message = \"Brush mode allows painting a circular area of variable diameter rather than a single pixel, working in \"..!@#& \"the exact same way as paint mode in all other regards.\",!@#& controls = {!@#& { \"Left Click\", \"Paints a brush blob with the left colour\" },!@#& { \"Right Click\", \"Paints a brush blob with the right colour\" },!@#& { \"Number Keys\", \"Changes the radius of the brush blob from 2-9\" }!@#& }!@#& },!@#& [3] = {!@#& name = \"Pippette Mode\",!@#& key = \"p\",!@#& animonly = false,!@#& textonly = false,!@#& message = \"Pippette mode allows the user to click the canvas and set the colour clicked to the left or right \"..!@#& \"selected colour, for later painting.\",!@#& controls = {!@#& { \"Left Click\", \"Sets clicked colour to the left selected colour\" },!@#& { \"Right Click\", \"Sets clicked colour to the right selected colour\" }!@#& }!@#& },!@#& [4] = {!@#& name = \"Move Mode\",!@#& key = \"m\",!@#& animonly = false,!@#& textonly = false,!@#& message = \"Mode mode allows the moving of the entire image on the screen. This is especially useful for justifying\"..!@#& \" the image to the top-left for animations or game assets.\",!@#& controls = {!@#& { \"Left/Right Click\", \"Moves top-left corner of image to selected square\" },!@#& { \"Arrow keys\", \"Moves image one pixel in any direction\" }!@#& }!@#& },!@#& [5] = {!@#& name = \"Flood Mode\",!@#& key = \"f\",!@#& animonly = false,!@#& textonly = false,!@#& message = \"Flood mode allows the changing of an area of a given colour to that of the selected colour. \"..!@#& \"The tool uses a flood4 algorithm and will not fill diagonally. Transparency cannot be flood filled.\",!@#& controls = {!@#& { \"Left Click\", \"Flood fills selected area to left colour\" },!@#& { \"Right Click\", \"Flood fills selected area to right colour\" }!@#& }!@#& },!@#& [6] = {!@#& name = \"Select Mode\",!@#& key = \"s\",!@#& animonly = false,!@#& textonly = false,!@#& message = \"Select mode allows the creation and use of the selection rectangle, to highlight specific areas on \"..!@#& \"the screen and perform operations on the selected area of the image. The selection rectangle can contain an \"..!@#& \"image on the clipboard- if it does, the image will flash inside the rectangle, and the rectangle edges will \"..!@#& \"be light grey instead of dark grey.\",!@#& controls = {!@#& { \"C Key\", \"Copy: Moves selection into the clipboard\" },!@#& { \"X Key\", \"Cut: Clears canvas under the rectangle, and moves it into the clipboard\" },!@#& { \"V Key\", \"Paste: Copys clipboard to the canvas\" },!@#& { \"Z Key\", \"Clears clipboard\" },!@#& { \"Left Click\", \"Moves top-left corner of rectangle to selected pixel\" },!@#& { \"Right Click\", \"Opens selection menu\" },!@#& { \"Arrow Keys\", \"Moves rectangle one pixel in any direction\" }!@#& }!@#& },!@#& [7] = {!@#& name = \"Corner Select Mode\",!@#& key = nil,!@#& animonly = false,!@#& textonly = false,!@#& message = \"If a selection rectangle isn't visible, this mode is selected automatically. It allows the \"..!@#& \"defining of the corners of the rectangle- one the top-left and bottom-right corners have been defined, \"..!@#& \"NPaintPro switches to selection mode. Note rectangle must be at least 2 pixels wide and high.\",!@#& controls = {!@#& { \"Left/Right Click\", \"Defines a corner of the selection rectangle\" }!@#& }!@#& },!@#& [8] = {!@#& name = \"Play Mode\",!@#& key = \"space\",!@#& animonly = true,!@#& textonly = false,!@#& message = \"Play mode will loop through each frame in your animation at a constant rate. Editing tools are \"..!@#& \"locked in this mode, and the coordinate display will turn green to indicate it is on.\",!@#& controls = {!@#& { \" Keys\", \"Increases/Decreases speed of the animation\" },!@#& { \"Space Bar\", \"Returns to paint mode\" }!@#& }!@#& },!@#& [9] = {!@#& name = \"Record Mode\",!@#& key = \"\\\\\",!@#& animonly = true,!@#& textonly = false,!@#& message = \"Record mode is not a true mode, but influences how other modes work. Changes made that modify the \"..!@#& \"canvas in record mode will affect ALL frames in the animation. The coordinates will turn red to indicate that \"..!@#& \"record mode is on.\",!@#& controls = {!@#& { \"\", \"Affects:\" },!@#& { \"- Paint Mode\", \"\" },!@#& { \"- Brush Mode\", \"\" },!@#& { \"- Cut and Paste in Select Mode\", \"\"},!@#& { \"- Move Mode\", \"\"}!@#& }!@#& },!@#& [10] = {!@#& name = \"Help Mode\",!@#& key = \"h\",!@#& animonly = false,!@#& textonly = false,!@#& message = \"Displays this help screen. Clicking on options will display help on that topic. Clicking out of the screen\"..!@#& \" will leave this mode.\",!@#& controls = {!@#& { \"Left/Right Click\", \"Displays a topic/Leaves the mode\" }!@#& }!@#& },!@#& [11] = {!@#& name = \"File Mode\",!@#& key = nil,!@#& animonly = false,!@#& textonly = false,!@#& message = \"Clicking on the mode display at the bottom of the screen will open the options menu. Here you can\"..!@#& \" activate all of the modes in the program with a simple mouse click. Pressing left control will open up the\"..!@#& \" file menu automatically.\",!@#& controls = { !@#& { \"leftCtrl\", \"Opens the file menu\" },!@#& { \"leftAlt\", \"Opens the paint menu\" }!@#& }!@#& },!@#& [12] = {!@#& name = \"Text Mode\",!@#& key = \"t\",!@#& animonly = false,!@#& textonly = true,!@#& message = \"In this mode, the user is able to type letters onto the document for display. The left colour \"..!@#& \"pallette value determines what colour the text will be, and the right determines what colour the background \"..!@#& \"will be (set either to nil to keep the same colours as already there).\",!@#& controls = {!@#& { \"Backspace\", \"Deletes the character on the previous line\" },!@#& { \"Arrow Keys\", \"Moves the cursor in any direction\" },!@#& { \"Left Click\", \"Moves the cursor to beneath the mouse cursor\" }!@#& }!@#& },!@#& [13] = {!@#& name = \"Textpaint Mode\",!@#& key = \"y\",!@#& animonly = false,!@#& textonly = true,!@#& message = \"Allows the user to paint any text on screen to the desired colour with the mouse. If affects the text colour\"..!@#& \" values rather than the background values, but operates identically to paint mode in all other regards.\",!@#& controls = {!@#& { \"Left Click\", \"Paints the text with the left colour\" },!@#& { \"Right Click\", \"Paints the text with the right colour\" }!@#& }!@#& },!@#& [14] = {!@#& name = \"About NPaintPro\",!@#& keys = nil,!@#& animonly = false,!@#& textonly = false,!@#& message = \"NPaintPro: The feature-bloated paint program for ComputerCraft by Nitrogen Fingers.\",!@#& controls = {!@#& { \"Testers:\", \" \"},!@#& { \" \", \"Faubiguy\"},!@#& { \" \", \"TheOriginalBIT\"}!@#& }!@#& }!@#&}!@#&--The \"bounds\" of the image- the first/last point on both axes where a pixel appears!@#&local toplim,botlim,leflim,riglim = nil,nil,nil,nil!@#&--The selected path!@#&local sPath = nil!@#&!@#&--[[ !@#& Section: Helpers !@#&]]--!@#&!@#&--[[Converts a colour parameter into a single-digit hex coordinate for the colour!@#& Params: colour:int = The colour to be converted!@#& Returns:string A string conversion of the colour!@#&]]--!@#&local function getHexOf(colour)!@#& if not colour or not tonumber(colour) then !@#& return \" \" !@#& end!@#& local value = math.log(colour)/math.log(2)!@#& if value > 9 then !@#& value = hexnums[value] !@#& end!@#& return value!@#&end!@#&!@#&--[[Converts a hex digit into a colour value!@#& Params: hex:?string = the hex digit to be converted!@#& Returns:string A colour value corresponding to the hex, or nil if the character is invalid!@#&]]--!@#&local function getColourOf(hex)!@#& local value = tonumber(hex, 16)!@#& if not value then return nil end!@#& value = math.pow(2,value)!@#& return value!@#&end!@#&!@#&--[[Finds the biggest and smallest bounds of the image- the outside points beyond which pixels do not appear!@#& These values are assigned to the \"lim\" parameters for access by other methods!@#& Params: forAllFrames:bool = True if all frames should be used to find bounds, otherwise false or nil!@#& Returns:nil!@#&]]--!@#&local function updateImageLims(forAllFrames)!@#& local f,l = sFrame,sFrame!@#& if forAllFrames == true then f,l = 1,framecount end!@#& !@#& toplim,botlim,leflim,riglim = nil,nil,nil,nil!@#& for locf = f,l do!@#& for y,_ in pairs(frames[locf]) do!@#& if type(y) == \"number\" then!@#& for x,_ in pairs(frames[locf][y]) do!@#& if frames[locf][y][x] ~= nil then!@#& if leflim == nil or x < leflim then leflim = x end!@#& if toplim == nil or y < toplim then toplim = y end!@#& if riglim == nil or x > riglim then riglim = x end!@#& if botlim == nil or y > botlim then botlim = y end!@#& end!@#& end!@#& end!@#& end!@#& end!@#& !@#& --There is just... no easier way to do this. It's horrible, but necessary!@#& if textEnabled then!@#& for locf = f,l do!@#& for y,_ in pairs(frames[locf].text) do!@#& for x,_ in pairs(frames[locf].text[y]) do!@#& if frames[locf].text[y][x] ~= nil then!@#& if leflim == nil or x < leflim then leflim = x end!@#& if toplim == nil or y < toplim then toplim = y end!@#& if riglim == nil or x > riglim then riglim = x end!@#& if botlim == nil or y > botlim then botlim = y end!@#& end!@#& end!@#& end!@#& for y,_ in pairs(frames[locf].textcol) do!@#& for x,_ in pairs(frames[locf].textcol[y]) do!@#& if frames[locf].textcol[y][x] ~= nil then!@#& if leflim == nil or x < leflim then leflim = x end!@#& if toplim == nil or y < toplim then toplim = y end!@#& if riglim == nil or x > riglim then riglim = x end!@#& if botlim == nil or y > botlim then botlim = y end!@#& end!@#& end!@#& end!@#& end!@#& end!@#&end!@#&!@#&--[[Determines how much of each material is required for a print. Done each time printing is called.!@#& Params: none!@#& Returns:table A complete list of how much of each material is required.!@#&]]--!@#&function calculateMaterials()!@#& updateImageLims(animated)!@#& requiredMaterials = {}!@#& for i=1,16 do !@#& requiredMaterials[i] = 0 !@#& end!@#& !@#& if not toplim then return end!@#& !@#& for i=1,#frames do!@#& for y = toplim, botlim do!@#& for x = leflim, riglim do!@#& if type(frames[i][y][x]) == \"number\" then!@#& requiredMaterials[math.log10(frames[i][y][x])/math.log10(2) + 1] = !@#& requiredMaterials[math.log10(frames[i][y][x])/math.log10(2) + 1] + 1!@#& end !@#& end!@#& end!@#& end!@#&end!@#&!@#&!@#&--[[Updates the rectangle blink timer. Should be called anywhere events are captured, along with a timer capture.!@#& Params: nil!@#& Returns:nil!@#&]]--!@#&local function updateTimer(id)!@#& if id == recttimer then!@#& recttimer = os.startTimer(0.5)!@#& rectblink = (rectblink % 2) + 1!@#& end!@#&end!@#&!@#&--[[Constructs a message based on the state currently selected!@#& Params: nil!@#& Returns:string A message regarding the state of the application!@#&]]--!@#&local function getStateMessage()!@#& local msg = \" \"..string.upper(string.sub(state, 1, 1))..string.sub(state, 2, #state)..\" mode\"!@#& if state == \"brush\" then msg = msg..\", size=\"..brushsize end!@#& return msg!@#&end!@#&!@#&--[[Calls the rednet_message event, but also looks for timer events to keep then!@#& system timer ticking.!@#& Params: timeout:number how long before the event times out!@#& Returns:number the id of the sender!@#& :number the message send!@#&]]--!@#&local function rsTimeReceive(timeout)!@#& local timerID!@#& if timeout then timerID = os.startTimer(timeout) end!@#& !@#& local id,key,msg = nil,nil!@#& while true do!@#& id,key,msg = os.pullEvent()!@#& !@#& if id == \"timer\" then!@#& if key == timerID then return!@#& else updateTimer(key) end!@#& end!@#& if id == \"rednet_message\" then !@#& return key,msg!@#& end!@#& end!@#&end!@#&!@#&--[[Draws a picture, in paint table format on the screen!@#& Params: image:table = the image to display!@#& xinit:number = the x position of the top-left corner of the image!@#& yinit:number = the y position of the top-left corner of the image!@#& alpha:number = the color to display for the alpha channel. Default is white.!@#& Returns:nil!@#&]]--!@#&local function drawPictureTable(image, xinit, yinit, alpha)!@#& if not alpha then alpha = 1 end!@#& for y=1,#image do!@#& for x=1,#image[y] do!@#& term.setCursorPos(xinit + x-1, yinit + y-1)!@#& local col = getColourOf(string.sub(image[y], x, x))!@#& if not col then col = alpha end!@#& term.setBackgroundColour(col)!@#& term.write(\" \")!@#& end!@#& end!@#&end!@#&!@#&--[[ !@#& Section: Loading !@#&]]-- !@#&!@#&--[[Loads a non-animted paint file into the program!@#& Params: path:string = The path in which the file is located!@#& Returns:nil!@#&]]--!@#&local function loadNFP(path)!@#& sFrame = 1!@#& frames[sFrame] = { }!@#& if fs.exists(path) then!@#& local file = io.open(path, \"r\" )!@#& local sLine = file:read()!@#& local num = 1!@#& while sLine do!@#& table.insert(frames[sFrame], num, {})!@#& for i=1,#sLine do!@#& frames[sFrame][num][i] = getColourOf(string.sub(sLine,i,i))!@#& end!@#& num = num+1!@#& sLine = file:read()!@#& end!@#& file:close()!@#& end!@#&end!@#&!@#&--[[Loads a text-paint file into the program!@#& Params: path:string = The path in which the file is located!@#& Returns:nil!@#&]]--!@#&local function loadNFT(path)!@#& sFrame = 1!@#& frames[sFrame] = { }!@#& frames[sFrame].text = { }!@#& frames[sFrame].textcol = { }!@#& !@#& if fs.exists(path) then!@#& local file = io.open(path, \"r\")!@#& local sLine = file:read()!@#& local num = 1!@#& while sLine do!@#& table.insert(frames[sFrame], num, {})!@#& table.insert(frames[sFrame].text, num, {})!@#& table.insert(frames[sFrame].textcol, num, {})!@#& !@#& --As we're no longer 1-1, we keep track of what index to write to!@#& local writeIndex = 1!@#& --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour!@#& local bgNext, fgNext = false, false!@#& --The current background and foreground colours!@#& local currBG, currFG = nil,nil!@#& term.setCursorPos(1,1)!@#& for i=1,#sLine do!@#& local nextChar = string.sub(sLine, i, i)!@#& if nextChar:byte() == 30 then!@#& bgNext = true!@#& elseif nextChar:byte() == 31 then!@#& fgNext = true!@#& elseif bgNext then!@#& currBG = getColourOf(nextChar)!@#& bgNext = false!@#& elseif fgNext then!@#& currFG = getColourOf(nextChar)!@#& fgNext = false!@#& else!@#& if nextChar ~= \" \" and currFG == nil then!@#& currFG = colours.white!@#& end!@#& frames[sFrame][num][writeIndex] = currBG!@#& frames[sFrame].textcol[num][writeIndex] = currFG!@#& frames[sFrame].text[num][writeIndex] = nextChar!@#& writeIndex = writeIndex + 1!@#& end!@#& end!@#& num = num+1!@#& sLine = file:read()!@#& end!@#& file:close()!@#& end!@#&end!@#&!@#&--[[Loads an animated paint file into the program!@#& Params: path:string = The path in which the file is located!@#& Returns:nil!@#&]]--!@#&local function loadNFA(path)!@#& frames[sFrame] = { }!@#& if fs.exists(path) then!@#& local file = io.open(path, \"r\" )!@#& local sLine = file:read()!@#& local num = 1!@#& while sLine do!@#& table.insert(frames[sFrame], num, {})!@#& if sLine == \"~\" then!@#& sFrame = sFrame + 1!@#& frames[sFrame] = { }!@#& num = 1!@#& else!@#& for i=1,#sLine do!@#& frames[sFrame][num][i] = getColourOf(string.sub(sLine,i,i))!@#& end!@#& num = num+1!@#& end!@#& sLine = file:read()!@#& end!@#& file:close()!@#& end!@#& framecount = sFrame!@#& sFrame = 1!@#&end!@#&!@#&--[[Saves a non-animated paint file to the specified path!@#& Params: path:string = The path to save the file to!@#& Returns:nil!@#&]]--!@#&local function saveNFP(path)!@#& local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))!@#& if not fs.exists(sDir) then!@#& fs.makeDir(sDir)!@#& end!@#&!@#& local file = io.open(path, \"w\")!@#& updateImageLims(false)!@#& if not toplim then !@#& file:close()!@#& return!@#& end!@#& for y=1,botlim do!@#& local line = \"\"!@#& if frames[sFrame][y] then !@#& for x=1,riglim do!@#& line = line..getHexOf(frames[sFrame][y][x])!@#& end!@#& end!@#& file:write(line..\"\\n\")!@#& end!@#& file:close()!@#&end!@#&!@#&--[[Saves a text-paint file to the specified path!@#& Params: path:string = The path to save the file to!@#& Returns:nil!@#&]]--!@#&local function saveNFT(path)!@#& local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))!@#& if not fs.exists(sDir) then!@#& fs.makeDir(sDir)!@#& end!@#& !@#& local file = io.open(path, \"w\")!@#& updateImageLims(false)!@#& if not toplim then!@#& file:close()!@#& return!@#& end!@#& for y=1,botlim do!@#& local line = \"\"!@#& local currBG, currFG = nil,nil!@#& for x=1,riglim do!@#& if frames[sFrame][y] and frames[sFrame][y][x] ~= currBG then!@#& line = line..string.char(30)..getHexOf(frames[sFrame][y][x])!@#& currBG = frames[sFrame][y][x]!@#& end!@#& if frames[sFrame].textcol[y] and frames[sFrame].textcol[y][x] ~= currFG then!@#& line = line..string.char(31)..getHexOf(frames[sFrame].textcol[y][x])!@#& currFG = frames[sFrame].textcol[y][x]!@#& end!@#& if frames[sFrame].text[y] then!@#& local char = frames[sFrame].text[y][x]!@#& if not char then char = \" \" end!@#& line = line..char!@#& end!@#& end!@#& file:write(line..\"\\n\")!@#& end!@#& file:close()!@#&end!@#&!@#&--[[Saves a animated paint file to the specified path!@#& Params: path:string = The path to save the file to!@#& Returns:nil!@#&]]--!@#&local function saveNFA(path)!@#& local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))!@#& if not fs.exists(sDir) then!@#& fs.makeDir(sDir)!@#& end!@#& !@#& local file = io.open(path, \"w\")!@#& updateImageLims(true)!@#& if not toplim then !@#& file:close()!@#& return!@#& end!@#& for i=1,#frames do!@#& for y=1,botlim do!@#& local line = \"\"!@#& if frames[i][y] then !@#& for x=1,riglim do!@#& line = line..getHexOf(frames[i][y][x])!@#& end!@#& end!@#& file:write(line..\"\\n\")!@#& end!@#& if i < #frames then file:write(\"~\\n\") end!@#& end!@#& file:close()!@#&end!@#&!@#&!@#&--[[Initializes the program, by loading in the paint file. Called at the start of each program.!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function init()!@#& if textEnabled then!@#& loadNFT(sPath)!@#& table.insert(ddModes, 2, { \"text\", \"textpaint\", name = \"text\"})!@#& elseif animated then !@#& loadNFA(sPath)!@#& table.insert(ddModes, #ddModes, { \"record\", \"play\", name = \"anim\" })!@#& table.insert(ddModes, #ddModes, { \"go to\", \"remove\", name = \"frames\"})!@#& table.insert(ddModes[2], #ddModes[2], \"blueprint on\")!@#& table.insert(ddModes[2], #ddModes[2], \"layers on\")!@#& else !@#& loadNFP(sPath) !@#& table.insert(ddModes[2], #ddModes[2], \"blueprint on\")!@#& end!@#&!@#& for i=0,15 do!@#& table.insert(column, math.pow(2,i))!@#& end!@#&end!@#&!@#&--[[ !@#& Section: Drawing !@#&]]--!@#&!@#&!@#&--[[Draws the rather superflous logo. Takes about 1 second, before user is able to move to the!@#& actual program.!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function drawLogo()!@#& term.setBackgroundColour(colours.white)!@#& term.clear()!@#& drawPictureTable(logo, w/2 - #logo[1]/2, h/2 - #logo/2, colours.white)!@#& term.setBackgroundColour(colours.white)!@#& term.setTextColour(colours.black)!@#& local msg = \"NPaintPro\"!@#& term.setCursorPos(w/2 - #msg/2, h-3)!@#& term.write(msg)!@#& msg = \"By NitrogenFingers\"!@#& term.setCursorPos(w/2 - #msg/2, h-2)!@#& term.write(msg)!@#& !@#& os.pullEvent()!@#&end!@#&!@#&--[[Clears the display to the alpha channel colour, draws the canvas, the image buffer and the selection!@#& rectanlge if any of these things are present.!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function drawCanvas()!@#& --We have to readjust the position of the canvas if we're printing!@#& turtlechar = \"@\"!@#& if state == \"active print\" then!@#& if layering == \"up\" then!@#& if py >= 1 and py <= #frames then!@#& sFrame = py!@#& end!@#& if pz < sy then sy = pz!@#& elseif pz > sy + h - 1 then sy = pz + h - 1 end!@#& if px < sx then sx = px!@#& elseif px > sx + w - 2 then sx = px + w - 2 end!@#& else!@#& if pz >= 1 and pz <= #frames then!@#& sFrame = pz!@#& end!@#& !@#& if py < sy then sy = py!@#& elseif py > sy + h - 1 then sy = py + h - 1 end!@#& if px < sx then sx = px!@#& elseif px > sx + w - 2 then sx = px + w - 2 end!@#& end!@#& !@#& if pfx == 1 then turtlechar = \">\"!@#& elseif pfx == -1 then turtlechar = \"<\"!@#& elseif pfz == 1 then turtlechar = \"V\"!@#& elseif pfz == -1 then turtlechar = \"^\"!@#& end!@#& end!@#&!@#& --Picture next!@#& local topLayer, botLayer!@#& if layerDisplay then!@#& topLayer = sFrame!@#& botLayer = 1!@#& else!@#& topLayer,botLayer = sFrame,sFrame!@#& end!@#& !@#& for currframe = botLayer,topLayer,1 do!@#& for y=sy+1,sy+h-1 do!@#& if frames[currframe][y] then !@#& for x=sx+1,sx+w-2 do!@#& term.setCursorPos(x-sx,y-sy)!@#& if frames[currframe][y][x] then!@#& term.setBackgroundColour(frames[currframe][y][x])!@#& if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then!@#& term.setTextColour(frames[currframe].textcol[y][x])!@#& term.write(frames[currframe].text[y][x])!@#& else!@#& term.write(\" \")!@#& end!@#& else !@#& tileExists = false!@#& for i=currframe-1,botLayer,-1 do!@#& if frames[i][y][x] then!@#& tileExists = true!@#& break!@#& end!@#& end!@#& !@#& if not tileExists then!@#& if blueprint then!@#& term.setBackgroundColour(colours.blue)!@#& term.setTextColour(colours.white)!@#& if x == sx+1 and y % 4 == 1 then!@#& term.write(\"\"..((y/4) % 10))!@#& elseif y == sy + 1 and x % 4 == 1 then!@#& term.write(\"\"..((x/4) % 10))!@#& elseif x % 2 == 1 and y % 2 == 1 then!@#& term.write(\"+\")!@#& elseif x % 2 == 1 then!@#& term.write(\"|\")!@#& elseif y % 2 == 1 then!@#& term.write(\"-\")!@#& else!@#& term.write(\" \")!@#& end!@#& else!@#& term.setBackgroundColour(alphaC) !@#& if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then!@#& term.setTextColour(frames[currframe].textcol[y][x])!@#& term.write(frames[currframe].text[y][x])!@#& else!@#& term.write(\" \")!@#& end!@#& end!@#& end!@#& end!@#& end!@#& else!@#& for x=sx+1,sx+w-2 do!@#& term.setCursorPos(x-sx,y-sy)!@#& !@#& tileExists = false!@#& for i=currframe-1,botLayer,-1 do!@#& if frames[i][y] and frames[i][y][x] then!@#& tileExists = true!@#& break!@#& end!@#& end!@#& !@#& if not tileExists then!@#& if blueprint then!@#& term.setBackgroundColour(colours.blue)!@#& term.setTextColour(colours.white)!@#& if x == sx+1 and y % 4 == 1 then!@#& term.write(\"\"..((y/4) % 10))!@#& elseif y == sy + 1 and x % 4 == 1 then!@#& term.write(\"\"..((x/4) % 10))!@#& elseif x % 2 == 1 and y % 2 == 1 then!@#& term.write(\"+\")!@#& elseif x % 2 == 1 then!@#& term.write(\"|\")!@#& elseif y % 2 == 1 then!@#& term.write(\"-\")!@#& else!@#& term.write(\" \")!@#& end!@#& else!@#& term.setBackgroundColour(alphaC) !@#& term.write(\" \")!@#& end!@#& end!@#& end!@#& end!@#& end!@#& end!@#& !@#& --Then the printer, if he's on!@#& if state == \"active print\" then!@#& local bgColour = alphaC!@#& if layering == \"up\" then!@#& term.setCursorPos(px-sx,pz-sy)!@#& if frames[sFrame] and frames[sFrame][pz-sy] and frames[sFrame][pz-sy][px-sx] then!@#& bgColour = frames[sFrame][pz-sy][px-sx]!@#& elseif blueprint then bgColour = colours.blue end!@#& else!@#& term.setCursorPos(px-sx,py-sy)!@#& if frames[sFrame] and frames[sFrame][py-sy] and frames[sFrame][py-sy][px-sx] then!@#& bgColour = frames[sFrame][py-sy][px-sx]!@#& elseif blueprint then bgColour = colours.blue end!@#& end!@#& !@#& term.setBackgroundColour(bgColour)!@#& if bgColour == colours.black then term.setTextColour(colours.white)!@#& else term.setTextColour(colours.black) end!@#& !@#& term.write(turtlechar)!@#& end!@#& !@#& --Then the buffer!@#& if selectrect then!@#& if buffer and rectblink == 1 then!@#& for y=selectrect.y1, math.min(selectrect.y2, selectrect.y1 + buffer.height-1) do!@#& for x=selectrect.x1, math.min(selectrect.x2, selectrect.x1 + buffer.width-1) do!@#& if buffer.contents[y-selectrect.y1+1][x-selectrect.x1+1] then!@#& term.setCursorPos(x+sx,y+sy)!@#& term.setBackgroundColour(buffer.contents[y-selectrect.y1+1][x-selectrect.x1+1])!@#& term.write(\" \")!@#& end!@#& end!@#& end!@#& end!@#& !@#& --This draws the \"selection\" box!@#& local add = nil!@#& if buffer then!@#& term.setBackgroundColour(colours.lightGrey)!@#& else !@#& term.setBackgroundColour(colours.grey)!@#& end!@#& for i=selectrect.x1, selectrect.x2 do!@#& add = (i + selectrect.y1 + rectblink) % 2 == 0!@#& term.setCursorPos(i-sx,selectrect.y1-sy)!@#& if add then term.write(\" \") end!@#& add = (i + selectrect.y2 + rectblink) % 2 == 0!@#& term.setCursorPos(i-sx,selectrect.y2-sy)!@#& if add then term.write(\" \") end!@#& end!@#& for i=selectrect.y1 + 1, selectrect.y2 - 1 do!@#& add = (i + selectrect.x1 + rectblink) % 2 == 0!@#& term.setCursorPos(selectrect.x1-sx,i-sy)!@#& if add then term.write(\" \") end!@#& add = (i + selectrect.x2 + rectblink) % 2 == 0!@#& term.setCursorPos(selectrect.x2-sx,i-sy)!@#& if add then term.write(\" \") end!@#& end!@#& end!@#&end!@#&!@#&--[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any !@#& messages currently being displayed!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function drawInterface()!@#& --Picker!@#& for i=1,#column do!@#& term.setCursorPos(w-1, i)!@#& term.setBackgroundColour(column[i])!@#& if state == \"print\" then!@#& if i == 16 then!@#& term.setTextColour(colours.white)!@#& else!@#& term.setTextColour(colours.black)!@#& end!@#& if requirementsDisplayed then!@#& if requiredMaterials[i] < 10 then term.write(\" \") end!@#& term.setCursorPos(w-#tostring(requiredMaterials[i])+1, i)!@#& term.write(requiredMaterials[i])!@#& else!@#& if i < 10 then term.write(\" \") end!@#& term.write(i)!@#& end!@#& else!@#& term.write(\" \")!@#& end!@#& end!@#& term.setCursorPos(w-1,#column+1)!@#& term.setBackgroundColour(colours.black)!@#& term.setTextColour(colours.red)!@#& term.write(\"XX\")!@#& --Pallette!@#& term.setCursorPos(w-1,h-1)!@#& if not lSel then!@#& term.setBackgroundColour(colours.black)!@#& term.setTextColour(colours.red)!@#& term.write(\"X\")!@#& else!@#& term.setBackgroundColour(lSel)!@#& term.setTextColour(lSel)!@#& term.write(\" \")!@#& end!@#& if not rSel then!@#& term.setBackgroundColour(colours.black)!@#& term.setTextColour(colours.red)!@#& term.write(\"X\")!@#& else!@#& term.setBackgroundColour(rSel)!@#& term.setTextColour(rSel)!@#& term.write(\" \")!@#& end!@#& --Footer!@#& if inMenu then return end!@#& !@#& term.setCursorPos(1, h)!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& term.clearLine()!@#& if inDropDown then!@#& term.write(string.rep(\" \", 6))!@#& else!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& term.write(\"menu \")!@#& end!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& term.write(getStateMessage())!@#& !@#& local coords=\"X:\"..sx..\" Y:\"..sy!@#& if animated then coords = coords..\" Frame:\"..sFrame..\"/\"..framecount..\" \" end!@#& term.setCursorPos(w-#coords+1,h)!@#& if state == \"play\" then term.setBackgroundColour(colours.lime)!@#& elseif record then term.setBackgroundColour(colours.red) end!@#& term.write(coords)!@#& !@#& if animated then!@#& term.setCursorPos(w-1,h)!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& term.write(\"<>\")!@#& end!@#&end!@#&!@#&--[[Runs an interface where users can select topics of help. Will return once the user quits the help screen.!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function drawHelpScreen()!@#& local selectedHelp = nil!@#& while true do!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.clear()!@#& if not selectedHelp then!@#& term.setCursorPos(4, 1)!@#& term.setTextColour(colours.brown)!@#& term.write(\"Available modes (click for info):\")!@#& for i=1,#helpTopics do!@#& term.setCursorPos(2, 2 + i)!@#& term.setTextColour(colours.black)!@#& term.write(helpTopics[i].name)!@#& if helpTopics[i].key then!@#& term.setTextColour(colours.red)!@#& term.write(\" (\"..helpTopics[i].key..\")\")!@#& end!@#& end!@#& term.setCursorPos(4,h)!@#& term.setTextColour(colours.black)!@#& term.write(\"Press any key to exit\")!@#& else!@#& term.setCursorPos(4,1)!@#& term.setTextColour(colours.brown)!@#& term.write(helpTopics[selectedHelp].name)!@#& if helpTopics[selectedHelp].key then!@#& term.setTextColour(colours.red)!@#& term.write(\" (\"..helpTopics[selectedHelp].key..\")\")!@#& end!@#& term.setCursorPos(1,3)!@#& term.setTextColour(colours.black)!@#& print(helpTopics[selectedHelp].message..\"\\n\")!@#& for i=1,#helpTopics[selectedHelp].controls do!@#& term.setTextColour(colours.brown)!@#& term.write(helpTopics[selectedHelp].controls[i][1]..\" \")!@#& term.setTextColour(colours.black)!@#& print(helpTopics[selectedHelp].controls[i][2])!@#& end!@#& end!@#& !@#& local id,p1,p2,p3 = os.pullEvent()!@#& !@#& if id == \"timer\" then updateTimer(p1)!@#& elseif id == \"key\" then !@#& if selectedHelp then selectedHelp = nil!@#& else break end!@#& elseif id == \"mouse_click\" then!@#& if not selectedHelp then !@#& if p3 >=3 and p3 <= 2+#helpTopics then!@#& selectedHelp = p3-2 !@#& else break end!@#& else!@#& selectedHelp = nil!@#& end!@#& end!@#& end!@#&end!@#&!@#&--[[Draws a message in the footer bar. A helper for DrawInterface, but can be called for custom messages, if the!@#& inMenu paramter is set to true while this is being done (remember to set it back when done!)!@#& Params: message:string = The message to be drawn!@#& Returns:nil!@#&]]--!@#&local function drawMessage(message)!@#& term.setCursorPos(1,h)!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& term.clearLine()!@#& term.write(message)!@#&end!@#&!@#&--[[!@#& Section: Generic Interfaces!@#&]]--!@#&!@#&!@#&--[[One of my generic text printing methods, printing a message at a specified position with width and offset.!@#& No colour materials included.!@#& Params: msg:string = The message to print off-center!@#& height:number = The starting height of the message!@#& width:number = The limit as to how many characters long each line may be!@#& offset:number = The starting width offset of the message!@#& Returns:number the number of lines used in printing the message!@#&]]--!@#&local function wprintOffCenter(msg, height, width, offset)!@#& local inc = 0!@#& local ops = 1!@#& while #msg - ops > width do!@#& local nextspace = 0!@#& while string.find(msg, \" \", ops + nextspace) and!@#& string.find(msg, \" \", ops + nextspace) - ops < width do!@#& nextspace = string.find(msg, \" \", nextspace + ops) + 1 - ops!@#& end!@#& local ox,oy = term.getCursorPos()!@#& term.setCursorPos(width/2 - (nextspace)/2 + offset, height + inc)!@#& inc = inc + 1!@#& term.write(string.sub(msg, ops, nextspace + ops - 1))!@#& ops = ops + nextspace!@#& end!@#& term.setCursorPos(width/2 - #string.sub(msg, ops)/2 + offset, height + inc)!@#& term.write(string.sub(msg, ops))!@#& !@#& return inc + 1!@#&end!@#&!@#&--[[Draws a message that must be clicked on or a key struck to be cleared. No options, so used for displaying!@#& generic information.!@#& Params: ctitle:string = The title of the confirm dialogue!@#& msg:string = The message displayed in the dialogue!@#& Returns:nil!@#&]]--!@#&local function displayConfirmDialogue(ctitle, msg)!@#& local dialogoffset = 8!@#& --We actually print twice- once to get the lines, second time to print proper. Easier this way.!@#& local lines = wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2)!@#& !@#& term.setCursorPos(dialogoffset, 3)!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& term.write(string.rep(\" \", w - dialogoffset * 2))!@#& term.setCursorPos(dialogoffset + (w - dialogoffset * 2)/2 - #ctitle/2, 3)!@#& term.write(ctitle)!@#& term.setTextColour(colours.grey)!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setCursorPos(dialogoffset, 4)!@#& term.write(string.rep(\" \", w - dialogoffset * 2))!@#& for i=5,5+lines do!@#& term.setCursorPos(dialogoffset, i) !@#& term.write(\" \"..string.rep(\" \", w - (dialogoffset) * 2 - 2)..\" \")!@#& end!@#& wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2)!@#& !@#& --In the event of a message, the player hits anything to continue!@#& while true do!@#& local id,key = os.pullEvent()!@#& if id == \"timer\" then updateTimer(key);!@#& elseif id == \"key\" or id == \"mouse_click\" or id == \"mouse_drag\" then break end!@#& end!@#&end!@#&!@#&--[[Produces a nice dropdown menu based on a table of strings. Depending on the position, this will auto-adjust the position!@#& of the menu drawn, and allows nesting of menus and sub menus. Clicking anywhere outside the menu will cancel and return nothing!@#& Params: x:int = the x position the menu should be displayed at!@#& y:int = the y position the menu should be displayed at!@#& options:table = the list of options available to the user, as strings or submenus (tables of strings, with a name parameter)!@#& Returns:string the selected menu option.!@#&]]--!@#&local function displayDropDown(x, y, options)!@#& inDropDown = true!@#& --Figures out the dimensions of our thing!@#& local longestX = #options.name!@#& for i=1,#options do!@#& local currVal = options[i]!@#& if type(currVal) == \"table\" then currVal = currVal.name end!@#& !@#& longestX = math.max(longestX, #currVal)!@#& end!@#& local xOffset = math.max(0, longestX - ((w-2) - x) + 1)!@#& local yOffset = math.max(0, #options - ((h-1) - y))!@#& !@#& local clickTimes = 0!@#& local tid = nil!@#& local selection = nil!@#& while clickTimes < 2 do!@#& drawCanvas()!@#& drawInterface()!@#& !@#& term.setCursorPos(x-xOffset,y-yOffset)!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& term.write(options.name..string.rep(\" \", longestX-#options.name + 2))!@#& !@#& for i=1,#options do!@#& term.setCursorPos(x-xOffset, y-yOffset+i)!@#& if i==selection and clickTimes % 2 == 0 then!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& else!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& end!@#& local currVal = options[i]!@#& if type(currVal) == \"table\" then !@#& term.write(currVal.name..string.rep(\" \", longestX-#currVal.name + 1))!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& term.write(\">\")!@#& else!@#& term.write(currVal..string.rep(\" \", longestX-#currVal + 2))!@#& end!@#& end!@#& !@#& local id, p1, p2, p3 = os.pullEvent()!@#& if id == \"timer\" then!@#& if p1 == tid then !@#& clickTimes = clickTimes + 1!@#& if clickTimes > 2 then !@#& break!@#& else !@#& tid = os.startTimer(0.1) !@#& end!@#& else !@#& updateTimer(p1) !@#& drawCanvas()!@#& drawInterface()!@#& end!@#& elseif id == \"mouse_click\" then!@#& if p2 >=x-xOffset and p2 <= x-xOffset + longestX + 1 and p3 >= y-yOffset+1 and p3 <= y-yOffset+#options then!@#& selection = p3-(y-yOffset)!@#& tid = os.startTimer(0.1)!@#& else!@#& selection = \"\"!@#& break!@#& end!@#& end!@#& end!@#& !@#& if type(selection) == \"number\" then!@#& selection = options[selection]!@#& end!@#& !@#& if type(selection) == \"string\" then !@#& inDropDown = false!@#& return selection!@#& elseif type(selection) == \"table\" then !@#& return displayDropDown(x, y, selection)!@#& end!@#&end!@#&!@#&--[[A custom io.read() function with a few differences- it limits the number of characters being printed,!@#& waits a 1/100th of a second so any keys still in the event library are removed before input is read and!@#& the timer for the selectionrectangle is continuously updated during the process.!@#& Params: lim:int = the number of characters input is allowed!@#& Returns:string the inputted string, trimmed of leading and tailing whitespace!@#&]]--!@#&local function readInput(lim)!@#& term.setCursorBlink(true)!@#&!@#& local inputString = \"\"!@#& if not lim or type(lim) ~= \"number\" or lim < 1 then lim = w - ox end!@#& local ox,oy = term.getCursorPos()!@#& --We only get input from the footer, so this is safe. Change if recycling!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& term.write(string.rep(\" \", lim))!@#& term.setCursorPos(ox, oy)!@#& --As events queue immediately, we may get an unwanted key... this will solve that problem!@#& local inputTimer = os.startTimer(0.01)!@#& local keysAllowed = false!@#& !@#& while true do!@#& local id,key = os.pullEvent()!@#& !@#& if keysAllowed then!@#& if id == \"key\" and key == 14 and #inputString > 0 then!@#& inputString = string.sub(inputString, 1, #inputString-1)!@#& term.setCursorPos(ox + #inputString,oy)!@#& term.write(\" \")!@#& elseif id == \"key\" and key == 28 and inputString ~= string.rep(\" \", #inputString) then !@#& break!@#& elseif id == \"key\" and key == keys.leftCtrl then!@#& return \"\"!@#& elseif id == \"char\" and #inputString < lim then!@#& inputString = inputString..key!@#& end!@#& end!@#& !@#& if id == \"timer\" then!@#& if key == inputTimer then !@#& keysAllowed = true!@#& else!@#& updateTimer(key)!@#& drawCanvas()!@#& drawInterface()!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& end!@#& end!@#& term.setCursorPos(ox,oy)!@#& term.write(inputString)!@#& term.setCursorPos(ox + #inputString, oy)!@#& end!@#& !@#& while string.sub(inputString, 1, 1) == \" \" do!@#& inputString = string.sub(inputString, 2, #inputString)!@#& end!@#& while string.sub(inputString, #inputString, #inputString) == \" \" do!@#& inputString = string.sub(inputString, 1, #inputString-1)!@#& end!@#& term.setCursorBlink(false)!@#& !@#& return inputString!@#&end!@#&!@#&--[[ !@#& Section: Image tools !@#&]]--!@#&!@#&!@#&--[[Copies all pixels beneath the selection rectangle into the image buffer. Empty buffers are converted to nil.!@#& Params: removeImage:bool = true if the image is to be erased after copying, false otherwise!@#& Returns:nil!@#&]]--!@#&local function copyToBuffer(removeImage)!@#& buffer = { width = selectrect.x2 - selectrect.x1 + 1, height = selectrect.y2 - selectrect.y1 + 1, contents = { } }!@#& !@#& local containsSomething = false!@#& for y=1,buffer.height do!@#& buffer.contents[y] = { }!@#& local f,l = sFrame,sFrame!@#& if record then f,l = 1, framecount end!@#& !@#& for fra = f,l do!@#& if frames[fra][selectrect.y1 + y - 1] then!@#& for x=1,buffer.width do!@#& buffer.contents[y][x] = frames[sFrame][selectrect.y1 + y - 1][selectrect.x1 + x - 1]!@#& if removeImage then frames[fra][selectrect.y1 + y - 1][selectrect.x1 + x - 1] = nil end!@#& if buffer.contents[y][x] then containsSomething = true end!@#& end!@#& end!@#& end!@#& end!@#& --I don't classify an empty buffer as a real buffer- confusing to the user.!@#& if not containsSomething then buffer = nil end!@#&end!@#&!@#&--[[Replaces all pixels under the selection rectangle with the image buffer (or what can be seen of it). Record-dependent.!@#& Params: removeBuffer:bool = true if the buffer is to be emptied after copying, false otherwise!@#& Returns:nil!@#&]]--!@#&local function copyFromBuffer(removeBuffer)!@#& if not buffer then return end!@#&!@#& for y = 1, math.min(buffer.height,selectrect.y2-selectrect.y1+1) do!@#& local f,l = sFrame, sFrame!@#& if record then f,l = 1, framecount end!@#& !@#& for fra = f,l do!@#& if not frames[fra][selectrect.y1+y-1] then frames[fra][selectrect.y1+y-1] = { } end!@#& for x = 1, math.min(buffer.width,selectrect.x2-selectrect.x1+1) do!@#& frames[fra][selectrect.y1+y-1][selectrect.x1+x-1] = buffer.contents[y][x]!@#& end!@#& end!@#& end!@#& !@#& if removeBuffer then buffer = nil end!@#&end!@#&!@#&--[[Moves the entire image (or entire animation) to the specified coordinates. Record-dependent.!@#& Params: newx:int = the X coordinate to move the image to!@#& newy:int = the Y coordinate to move the image to!@#& Returns:nil!@#&]]--!@#&local function moveImage(newx,newy)!@#& if not leflim or not toplim then return end!@#& if newx <=0 or newy <=0 then return end!@#& local f,l = sFrame,sFrame!@#& if record then f,l = 1,framecount end!@#& !@#& for i=f,l do!@#& local newlines = { }!@#& for y=toplim,botlim do!@#& local line = frames[i][y]!@#& if line then!@#& newlines[y-toplim+newy] = { }!@#& for x,char in pairs(line) do!@#& newlines[y-toplim+newy][x-leflim+newx] = char!@#& end!@#& end!@#& end!@#& --Exceptions that allow us to move the text as well!@#& if textEnabled then!@#& newlines.text = { }!@#& for y=toplim,botlim do!@#& local line = frames[i].text[y]!@#& if line then!@#& newlines.text[y-toplim+newy] = { }!@#& for x,char in pairs(line) do!@#& newlines.text[y-toplim+newy][x-leflim+newx] = char!@#& end!@#& end!@#& end!@#& !@#& newlines.textcol = { }!@#& for y=toplim,botlim do!@#& local line = frames[i].textcol[y]!@#& if line then!@#& newlines.textcol[y-toplim+newy] = { }!@#& for x,char in pairs(line) do!@#& newlines.textcol[y-toplim+newy][x-leflim+newx] = char!@#& end!@#& end!@#& end!@#& end!@#& !@#& frames[i] = newlines!@#& end!@#&end!@#&!@#&--[[Prompts the user to clear the current frame or all frames. Record-dependent.,!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function clearImage()!@#& inMenu = true!@#& if not animated then!@#& drawMessage(\"Clear image? Y/N: \")!@#& elseif record then!@#& drawMessage(\"Clear ALL frames? Y/N: \")!@#& else!@#& drawMessage(\"Clear current frame? Y/N :\")!@#& end!@#& if string.find(string.upper(readInput(1)), \"Y\") then!@#& local f,l = sFrame,sFrame!@#& if record then f,l = 1,framecount end!@#& !@#& for i=f,l do!@#& frames[i] = { }!@#& end!@#& end!@#& inMenu = false!@#&end!@#&!@#&--[[A recursively called method (watch out for big calls!) in which every pixel of a set colour is!@#& changed to another colour. Does not work on the nil colour, for obvious reasons.!@#& Params: x:int = The X coordinate of the colour to flood-fill!@#& y:int = The Y coordinate of the colour to flood-fill!@#& targetColour:colour = the colour that is being flood-filled!@#& newColour:colour = the colour with which to replace the target colour!@#& Returns:nil!@#&]]--!@#&local function floodFill(x, y, targetColour, newColour)!@#& if not newColour or not targetColour then return end!@#& local nodeList = { }!@#& !@#& table.insert(nodeList, {x = x, y = y})!@#& !@#& while #nodeList > 0 do!@#& local node = nodeList[1]!@#& if frames[sFrame][node.y] and frames[sFrame][node.y][node.x] == targetColour then!@#& frames[sFrame][node.y][node.x] = newColour!@#& table.insert(nodeList, { x = node.x + 1, y = node.y})!@#& table.insert(nodeList, { x = node.x, y = node.y + 1})!@#& if x > 1 then table.insert(nodeList, { x = node.x - 1, y = node.y}) end!@#& if y > 1 then table.insert(nodeList, { x = node.x, y = node.y - 1}) end!@#& end!@#& table.remove(nodeList, 1)!@#& end!@#&end!@#&!@#&--[[ !@#& Section: Animation Tools !@#&]]--!@#&!@#&--[[Enters play mode, allowing the animation to play through. Interface is restricted to allow this,!@#& and method only leaves once the player leaves play mode.!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function playAnimation()!@#& state = \"play\"!@#& selectedrect = nil!@#& !@#& local animt = os.startTimer(animtime)!@#& repeat!@#& drawCanvas()!@#& drawInterface()!@#& !@#& local id,key,_,y = os.pullEvent()!@#& !@#& if id==\"timer\" then!@#& if key == animt then!@#& animt = os.startTimer(animtime)!@#& sFrame = (sFrame % framecount) + 1!@#& else!@#& updateTimer(key)!@#& end!@#& elseif id==\"key\" then!@#& if key == keys.comma and animtime > 0.1 then animtime = animtime - 0.05!@#& elseif key == keys.period and animtime < 0.5 then animtime = animtime + 0.05!@#& elseif key == keys.space then state = \"paint\" end!@#& elseif id==\"mouse_click\" and y == h then!@#& state = \"paint\"!@#& end!@#& until state ~= \"play\"!@#& os.startTimer(0.5)!@#&end!@#&!@#&--[[Changes the selected frame (sFrame) to the chosen frame. If this frame is above the framecount,!@#& additional frames are created with a copy of the image on the selected frame.!@#& Params: newframe:int = the new frame to move to!@#& Returns:nil!@#&]]--!@#&local function changeFrame(newframe)!@#& inMenu = true!@#& if not tonumber(newframe) then!@#& term.setCursorPos(1,h)!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.grey)!@#& term.clearLine()!@#& !@#& term.write(\"Go to frame: \")!@#& newframe = tonumber(readInput(2))!@#& if not newframe or newframe <= 0 then!@#& inMenu = false!@#& return !@#& end!@#& elseif newframe <= 0 then return end!@#& !@#& if newframe > framecount then!@#& for i=framecount+1,newframe do!@#& frames[i] = {}!@#& for y,line in pairs(frames[sFrame]) do!@#& frames[i][y] = { }!@#& for x,v in pairs(line) do!@#& frames[i][y][x] = v!@#& end!@#& end!@#& end!@#& framecount = newframe!@#& end!@#& sFrame = newframe!@#& inMenu = false!@#&end!@#&!@#&--[[Removes every frame leading after the frame passed in!@#& Params: frame:int the non-inclusive lower bounds of the delete!@#& Returns:nil!@#&]]--!@#&local function removeFramesAfter(frame)!@#& inMenu = true!@#& if frame==framecount then return end!@#& drawMessage(\"Remove frames \"..(frame+1)..\"/\"..framecount..\"? Y/N :\")!@#& local answer = string.upper(readInput(1))!@#& !@#& if string.find(answer, string.upper(\"Y\")) ~= 1 then !@#& inMenu = false!@#& return !@#& end!@#& !@#& for i=frame+1, framecount do!@#& frames[i] = nil!@#& end!@#& framecount = frame!@#& inMenu = false!@#&end!@#&!@#&--[[!@#& Section: Printing Tools!@#&]]--!@#&!@#&--[[Constructs a new facing to the left of the current facing!@#& Params: curx:number = The facing on the X axis!@#& curz:number = The facing on the Z axis!@#& hand:string = The hand of the axis (\"right\" or \"left\")!@#& Returns:number,number = the new facing on the X and Z axis after a left turn!@#&]]--!@#&local function getLeft(curx, curz)!@#& local hand = \"left\"!@#& if layering == \"up\" then hand = \"right\" end!@#& !@#& if hand == \"right\" then!@#& if curx == 1 then return 0,-1 end!@#& if curx == -1 then return 0,1 end!@#& if curz == 1 then return 1,0 end!@#& if curz == -1 then return -1,0 end!@#& else!@#& if curx == 1 then return 0,1 end!@#& if curx == -1 then return 0,-1 end!@#& if curz == 1 then return -1,0 end!@#& if curz == -1 then return 1,0 end!@#& end!@#&end!@#&!@#&--[[Constructs a new facing to the right of the current facing!@#& Params: curx:number = The facing on the X axis!@#& curz:number = The facing on the Z axis!@#& hand:string = The hand of the axis (\"right\" or \"left\")!@#& Returns:number,number = the new facing on the X and Z axis after a right turn!@#&]]--!@#&local function getRight(curx, curz)!@#& local hand = \"left\"!@#& if layering == \"up\" then hand = \"right\" end!@#& !@#& if hand == \"right\" then!@#& if curx == 1 then return 0,1 end!@#& if curx == -1 then return 0,-1 end!@#& if curz == 1 then return -1,0 end!@#& if curz == -1 then return 1,0 end!@#& else!@#& if curx == 1 then return 0,-1 end!@#& if curx == -1 then return 0,1 end!@#& if curz == 1 then return 1,0 end!@#& if curz == -1 then return -1,0 end!@#& end!@#&end!@#&!@#&!@#&--[[Sends out a rednet signal requesting local printers, and will listen for any responses. Printers found are added to the!@#& printerList (for ID's) and printerNames (for names)!@#& Params: nil!@#& Returns:nil!@#&]]--!@#&local function locatePrinters()!@#& printerList = { }!@#& printerNames = { name = \"Printers\" }!@#& local oldState = state!@#& state = \"Locating printers, please wait... \"!@#& drawCanvas()!@#& drawInterface()!@#& state = oldState!@#& !@#& local modemOpened = false!@#& for k,v in pairs(rs.getSides()) do!@#& if peripheral.isPresent(v) and peripheral.getType(v) == \"modem\" then!@#& rednet.open(v)!@#& modemOpened = true!@#& break!@#& end!@#& end!@#& !@#& if not modemOpened then!@#& displayConfirmDialogue(\"Modem not found!\", \"No modem peripheral. Must have network modem to locate printers.\")!@#& return false!@#& end!@#& !@#& rednet.broadcast(\"$3DPRINT IDENTIFY\")!@#& !@#& while true do!@#& local id, msg = rsTimeReceive(1)!@#& !@#& if not id then break end!@#& if string.find(msg, \"$3DPRINT IDACK\") == 1 then!@#& msg = string.gsub(msg, \"$3DPRINT IDACK \", \"\")!@#& table.insert(printerList, id)!@#& table.insert(printerNames, msg)!@#& end!@#& end!@#& !@#& if #printerList == 0 then!@#& displayConfirmDialogue(\"Printers not found!\", \"No active printers found in proximity of this computer.\")!@#& return false!@#& else!@#& return true!@#& end!@#&end!@#&!@#&--[[Sends a request to the printer. Waits on a response and updates the state of the application accordingly.!@#& Params: command:string the command to send!@#& param:string a parameter to send, if any!@#& Returns:nil!@#&]]--!@#&local function sendPC(command,param)!@#& local msg = \"$PC \"..command!@#& if param then msg = msg..\" \"..param end!@#& rednet.send(printerList[selectedPrinter], msg)!@#& !@#& while true do!@#& local id,key = rsTimeReceive()!@#& if id == printerList[selectedPrinter] then!@#& if key == \"$3DPRINT ACK\" then!@#& break!@#& elseif key == \"$3DPRINT DEP\" then!@#& displayConfirmDialogue(\"Printer Empty\", \"The printer has exhasted a material. Please refill slot \"..param..!@#& \", and click this message when ready to continue.\")!@#& rednet.send(printerList[selectedPrinter], msg)!@#& elseif key == \"$3DPRINT OOF\" then!@#& displayConfirmDialogue(\"Printer Out of Fuel\", \"The printer has no fuel. Please replace the material \"..!@#& \"in slot 1 with a fuel source, then click this message.\")!@#& rednet.send(printerList[selectedPrinter], \"$PC SS 1\")!@#& id,key = rsTimeReceive()!@#& rednet.send(printerList[selectedPrinter], \"$PC RF\")!@#& id,key = rsTimeReceive()!@#& rednet.send(printerList[selectedPrinter], msg)!@#& end!@#& end!@#& end!@#& !@#& --Changes to position are handled after the event has been successfully completed!@#& if command == \"FW\" then!@#& px = px + pfx!@#& pz = pz + pfz!@#& elseif command == \"BK\" then!@#& px = px - pfx!@#& pz = pz - pfz!@#& elseif command == \"UP\" then!@#& if layering == \"up\" then!@#& py = py + 1!@#& else !@#& py = py - 1!@#& end!@#& elseif command == \"DW\" then!@#& if layering == \"up\" then!@#& py = py - 1!@#& else !@#& py = py + 1!@#& end!@#& elseif command == \"TL\" then!@#& pfx,pfz = getLeft(pfx,pfz)!@#& elseif command == \"TR\" then!@#& pfx,pfz = getRight(pfx,pfz)!@#& elseif command == \"TU\" then!@#& pfx = -pfx!@#& pfz = -pfz!@#& end!@#& !@#& drawCanvas()!@#& drawInterface()!@#&end!@#&!@#&--[[A printing function that commands the printer to turn to face the desired direction, if it is not already doing so!@#& Params: desx:number = the normalized x direction to face!@#& desz:number = the normalized z direction to face!@#& Returns:nil!@#&]]--!@#&local function turnToFace(desx,desz)!@#& if desx ~= 0 then!@#& if pfx ~= desx then!@#& local temppfx,_ = getLeft(pfx,pfz)!@#& if temppfx == desx then!@#& sendPC(\"TL\")!@#& elseif temppfx == -desx then!@#& sendPC(\"TR\")!@#& else!@#& sendPC(\"TU\")!@#& end!@#& end!@#& else!@#& print(\"on the z axis\")!@#& if pfz ~= desz then!@#& local _,temppfz = getLeft(pfx,pfz)!@#& if temppfz == desz then!@#& sendPC(\"TL\")!@#& elseif temppfz == -desz then!@#& sendPC(\"TR\")!@#& else!@#& sendPC(\"TU\")!@#& end!@#& end!@#& end!@#&end!@#&!@#&--[[Performs the print!@#& Params: nil!@#& Returns:nil!@#&]]--!@#&local function performPrint()!@#& state = \"active print\"!@#& if layering == \"up\" then!@#& --An up layering starts our builder bot on the bottom left corner of our build!@#& px,py,pz = leflim, 0, botlim + 1!@#& pfx,pfz = 0,-1!@#& !@#& --We move him forward and up a bit from his original position.!@#& sendPC(\"FW\")!@#& sendPC(\"UP\")!@#& --For each layer that needs to be completed, we go up by one each time!@#& for layers=1,#frames do!@#& --We first decide if we're going forwards or back, depending on what side we're on!@#& local rowbot,rowtop,rowinc = nil,nil,nil!@#& if pz == botlim then!@#& rowbot,rowtop,rowinc = botlim,toplim,-1!@#& else!@#& rowbot,rowtop,rowinc = toplim,botlim,1!@#& end!@#& !@#& for rows = rowbot,rowtop,rowinc do!@#& --Then we decide if we're going left or right, depending on what side we're on!@#& local linebot,linetop,lineinc = nil,nil,nil!@#& if px == leflim then!@#& --Facing from the left side has to be easterly- it's changed here!@#& turnToFace(1,0)!@#& linebot,linetop,lineinc = leflim,riglim,1!@#& else!@#& --Facing from the right side has to be westerly- it's changed here!@#& turnToFace(-1,0)!@#& linebot,linetop,lineinc = riglim,leflim,-1!@#& end!@#& !@#& for lines = linebot,linetop,lineinc do!@#& --We move our turtle forward, placing the right material at each step!@#& local material = frames[py][pz][px]!@#& if material then!@#& material = math.log10(frames[py][pz][px])/math.log10(2) + 1!@#& sendPC(\"SS\", material)!@#& sendPC(\"PD\")!@#& end!@#& if lines ~= linetop then!@#& sendPC(\"FW\")!@#& end!@#& end!@#& !@#& --The printer then has to do a U-turn, depending on which way he's facing and!@#& --which way he needs to go!@#& local temppfx,temppfz = getLeft(pfx,pfz)!@#& if temppfz == rowinc and rows ~= rowtop then!@#& sendPC(\"TL\")!@#& sendPC(\"FW\")!@#& sendPC(\"TL\")!@#& elseif temppfz == -rowinc and rows ~= rowtop then!@#& sendPC(\"TR\")!@#& sendPC(\"FW\")!@#& sendPC(\"TR\")!@#& end!@#& end!@#& --Now at the end of a run he does a 180 and moves up to begin the next part of the print!@#& sendPC(\"TU\")!@#& if layers ~= #frames then!@#& sendPC(\"UP\")!@#& end!@#& end!@#& --All done- now we head back to where we started.!@#& if px ~= leflim then!@#& turnToFace(-1,0)!@#& while px ~= leflim do!@#& sendPC(\"FW\")!@#& end!@#& end!@#& if pz ~= botlim then!@#& turnToFace(0,-1)!@#& while pz ~= botlim do!@#& sendPC(\"BK\")!@#& end!@#& end!@#& turnToFace(0,-1)!@#& sendPC(\"BK\")!@#& while py > 0 do!@#& sendPC(\"DW\")!@#& end!@#& else!@#& --The front facing is at the top-left corner, facing south not north!@#& px,py,pz = leflim, botlim, 1!@#& pfx,pfz = 0,1!@#& --We move the printer to the last layer- he prints from the back forwards!@#& while pz < #frames do!@#& sendPC(\"FW\")!@#& end!@#& !@#& --For each layer in the frame we build our wall, the move back!@#& for layers = 1,#frames do!@#& --We first decide if we're going left or right based on our position!@#& local rowbot,rowtop,rowinc = nil,nil,nil!@#& if px == leflim then!@#& rowbot,rowtop,rowinc = leflim,riglim,1!@#& else!@#& rowbot,rowtop,rowinc = riglim,leflim,-1!@#& end!@#& !@#& for rows = rowbot,rowtop,rowinc do!@#& --Then we decide if we're going up or down, depending on our given altitude!@#& local linebot,linetop,lineinc = nil,nil,nil!@#& if py == botlim then!@#& linebot,linetop,lineinc = botlim,toplim,-1!@#& else!@#& linebot,linetop,lineinc = toplim,botlim,1!@#& end!@#& !@#& for lines = linebot,linetop,lineinc do!@#& --We move our turtle up/down, placing the right material at each step!@#& local material = frames[pz][py][px]!@#& if material then!@#& material = math.log10(frames[pz][py][px])/math.log10(2) + 1!@#& sendPC(\"SS\", material)!@#& sendPC(\"PF\")!@#& end!@#& if lines ~= linetop then!@#& if lineinc == 1 then sendPC(\"DW\")!@#& else sendPC(\"UP\") end!@#& end!@#& end!@#& !@#& if rows ~= rowtop then!@#& turnToFace(rowinc,0)!@#& sendPC(\"FW\")!@#& turnToFace(0,1)!@#& end!@#& end!@#& !@#& if layers ~= #frames then!@#& sendPC(\"TU\")!@#& sendPC(\"FW\")!@#& sendPC(\"TU\")!@#& end!@#& end!@#& --He's easy to reset!@#& while px ~= leflim do!@#& turnToFace(-1,0)!@#& sendPC(\"FW\")!@#& end!@#& turnToFace(0,1)!@#& end!@#& !@#& sendPC(\"DE\")!@#& !@#& displayConfirmDialogue(\"Print complete\", \"The 3D print was successful.\")!@#&end!@#&!@#&--[[ !@#& Section: Interface !@#&]]--!@#&!@#&--[[Runs the printing interface. Allows users to find/select a printer, the style of printing to perform and to begin the operation!@#& Params: none!@#& Returns:boolean true if printing was started, false otherwse!@#&]]--!@#&local function runPrintInterface()!@#& calculateMaterials()!@#& --There's nothing on canvas yet!!@#& if not botlim then!@#& displayConfirmDialogue(\"Cannot Print Empty Canvas\", \"There is nothing on canvas that \"..!@#& \"can be printed, and the operation cannot be completed.\")!@#& return false!@#& end!@#& --No printers nearby!@#& if not locatePrinters() then!@#& return false!@#& end!@#& !@#& layering = \"up\"!@#& requirementsDisplayed = false!@#& selectedPrinter = 1!@#& while true do!@#& drawCanvas()!@#& term.setBackgroundColour(colours.lightGrey)!@#& for i=1,10 do!@#& term.setCursorPos(1,i)!@#& term.clearLine()!@#& end!@#& drawInterface()!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.black)!@#& !@#& local msg = \"3D Printing\"!@#& term.setCursorPos(w/2-#msg/2 - 2, 1)!@#& term.write(msg)!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& if(requirementsDisplayed) then!@#& msg = \"Count:\"!@#& else!@#& msg = \" Slot:\"!@#& end!@#& term.setCursorPos(w-3-#msg, 1)!@#& term.write(msg)!@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.black)!@#& !@#& term.setCursorPos(7, 2)!@#& term.write(\"Layering\")!@#& drawPictureTable(layerUpIcon, 3, 3, colours.white)!@#& drawPictureTable(layerForwardIcon, 12, 3, colours.white)!@#& if layering == \"up\" then!@#& term.setBackgroundColour(colours.red)!@#& else!@#& term.setBackgroundColour(colours.lightGrey)!@#& end!@#& term.setCursorPos(3, 9)!@#& term.write(\"Upwards\")!@#& if layering == \"forward\" then!@#& term.setBackgroundColour(colours.red)!@#& else!@#& term.setBackgroundColour(colours.lightGrey)!@#& end!@#& term.setCursorPos(12, 9)!@#& term.write(\"Forward\")!@#& !@#& term.setBackgroundColour(colours.lightGrey)!@#& term.setTextColour(colours.black)!@#& term.setCursorPos(31, 2)!@#& term.write(\"Printer ID\")!@#& term.setCursorPos(33, 3)!@#& if #printerList > 1 then!@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& else!@#& term.setTextColour(colours.red)!@#& end!@#& term.write(\" \"..printerNames[selectedPrinter]..\" \")!@#& !@#& term.setBackgroundColour(colours.grey)!@#& term.setTextColour(colours.lightGrey)!@#& term.setCursorPos(25, 10)!@#& term.write(\" Cancel \")!@#& term.setCursorPos(40, 10)!@#& term.write(\" Print \")!@#& !@#& local id, p1, p2, p3 = os.pullEvent()!@#& !@#& if id == \"timer\" then!@#& updateTimer(p1)!@#& elseif id == \"mouse_click\" then!@#& --Layering Buttons!@#& if p2 >= 3 and p2 <= 9 and p3 >= 3 and p3 <= 9 then!@#& layering = \"up\"!@#& elseif p2 >= 12 and p2 <= 18 and p3 >= 3 and p3 <= 9 then!@#& layering = \"forward\"!@#& --Count/Slot!@#& elseif p2 >= w - #msg - 3 and p2 <= w - 3 and p3 == 1 then!@#& requirementsDisplayed = not requirementsDisplayed!@#& --Printer ID!@#& elseif p2 >= 33 and p2 <= 33 + #printerNames[selectedPrinter] and p3 == 3 and #printerList > 1 then!@#& local chosenName = displayDropDown(33, 3, printerNames)!@#& for i=1,#printerNames do!@#& if printerNames[i] == chosenName then!@#& selectedPrinter = i!@#& break;!@#& end!@#& end!@#& --Print and Cancel!@#& elseif p2 >= 25 and p2 <= 32 and p3 == 10 then!@#& break!@#& elseif p2 >= 40 and p2 <= 46 and p3 == 10 then!@#& rednet.send(printerList[selectedPrinter], \"$3DPRINT ACTIVATE\")!@#& ready = false!@#& while true do!@#& local id,msg = rsTimeReceive(10)!@#& !@#& if id == printerList[selectedPrinter] and msg == \"$3DPRINT ACTACK\" then!@#& ready = true!@#& break!@#& end!@#& end!@#& if ready then!@#& performPrint()!@#& break!@#& else!@#& displayConfirmDialogue(\"Printer Didn't Respond\", \"The printer didn't respond to the activation command. Check to see if it's online\")!@#& end!@#& end!@#& end!@#& end!@#& state = \"paint\"!@#&end!@#&!@#&--[[This function changes the current paint program to another tool or mode, depending on user input. Handles!@#& any necessary changes in logic involved in that.!@#& Params: mode:string = the name of the mode to change to!@#& Returns:nil!@#&]]--!@#&local function performSelection(mode)!@#& if not mode or mode == \"\" then return!@#& !@#& elseif mode == \"help\" then!@#& drawHelpScreen()!@#& !@#& elseif mode == \"blueprint on\" then!@#& blueprint = true!@#& ddModes[2][3] = \"blueprint off\"!@#& !@#& elseif mode == \"blueprint off\" then!@#& blueprint = false!@#& ddModes[2][3] = \"blueprint on\"!@#& !@#& elseif mode == \"layers on\" then!@#& layerDisplay = true!@#& ddModes[2][4] = \"layers off\"!@#& !@#& elseif mode == \"layers off\" then!@#& layerDisplay = false!@#& ddModes[2][4] = \"layers on\"!@#& !@#& elseif mode == \"direction on\" then!@#& printDirection = true!@#& ddModes[2][5] = \"direction off\"!@#& !@#& elseif mode == \"direction off\" then!@#& printDirection = false!@#& ddModes[2][5] = \"direction on\"!@#& !@#& elseif mode == \"go to\" then!@#& changeFrame()!@#& !@#& elseif mode == \"remove\" then!@#& removeFramesAfter(sFrame)!@#& !@#& elseif mode == \"play\" then!@#& playAnimation()!@#& !@#& elseif mode == \"copy\" then!@#& if selectrect and selectrect.x1 ~= selectrect.x2 then!@#& copyToBuffer(false)!@#& end!@#& !@#& elseif mode == \"cut\" then!@#& if selectrect and selectrect.x1 ~= selectrect.x2 then !@#& copyToBuffer(true)!@#& end!@#& !@#& elseif mode == \"paste\" then!@#& if selectrect and selectrect.x1 ~= selectrect.x2 then !@#& copyFromBuffer(false)!@#& end!@#& !@#& elseif mode == \"hide\" then!@#& selectrect = nil!@#& if state == \"select\" then state = \"corner select\" end!@#& !@#& elseif mode == \"alpha to left\" then!@#& if lSel then alphaC = lSel end!@#& !@#& elseif mode == \"alpha to right\" then!@#& if rSel then alphaC = rSel end!@#& !@#& elseif mode == \"record\" then!@#& record = not record!@#& !@#& elseif mode == \"clear\" then!@#& if state==\"select\" then buffer = nil!@#& else clearImage() end!@#& !@#& elseif mode == \"select\" then!@#& if state==\"corner select\" or state==\"select\" then!@#& state = \"paint\"!@#& elseif selectrect and selectrect.x1 ~= selectrect.x2 then!@#& state = \"select\"!@#& else!@#& state = \"corner select\" !@#& end!@#& !@#& elseif mode == \"print\" then!@#& state = \"print\"!@#& runPrintInterface()!@#& state = \"paint\"!@#& !@#& elseif mode == \"save\" then!@#& if animated then saveNFA(sPath)!@#& elseif textEnabled then saveNFT(sPath)!@#& else saveNFP(sPath) end!@#& !@#& elseif mode == \"exit\" then!@#& isRunning = false!@#& !@#& elseif mode ~= state then state = mode!@#& else state = \"paint\"!@#& !@#& end!@#&end!@#&!@#&--[[The main function of the program, reads and handles all events and updates them accordingly. Mode changes,!@#& painting to the canvas and general selections are done here.!@#& Params: none!@#& Returns:nil!@#&]]--!@#&local function handleEvents()!@#& recttimer = os.startTimer(0.5)!@#& while isRunning do!@#& drawCanvas()!@#& drawInterface()!@#& !@#& if state == \"text\" then!@#& term.setCursorPos(textCurX - sx, textCurY - sy)!@#& term.setCursorBlink(true)!@#& end!@#& !@#& local id,p1,p2,p3 = os.pullEvent()!@#& term.setCursorBlink(false)!@#& if id==\"timer\" then!@#& updateTimer(p1)!@#& elseif id==\"mouse_click\" or id==\"mouse_drag\" then!@#& if p2 >=w-1 and p3 < #column+1 then!@#& if p1==1 then lSel = column[p3]!@#& else rSel = column[p3] end!@#& elseif p2 >=w-1 and p3==#column+1 then!@#& if p1==1 then lSel = nil!@#& else rSel = nil end!@#& elseif p2==w-1 and p3==h and animated then!@#& changeFrame(sFrame-1)!@#& elseif p2==w and p3==h and animated then!@#& changeFrame(sFrame+1)!@#& elseif p2 < w-10 and p3==h then!@#& local sel = displayDropDown(1, h-1, ddModes)!@#& performSelection(sel)!@#& elseif p2 < w-1 and p3 <= h-1 then!@#& if state==\"pippette\" then!@#& if p1==1 then!@#& if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then!@#& lSel = frames[sFrame][p3+sy][p2+sx] !@#& end!@#& elseif p1==2 then!@#& if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then!@#& rSel = frames[sFrame][p3+sy][p2+sx] !@#& end!@#& end!@#& elseif state==\"move\" then!@#& updateImageLims(record)!@#& moveImage(p2,p3)!@#& elseif state==\"flood\" then!@#& if p1 == 1 and lSel and frames[sFrame][p3+sy] then !@#& floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],lSel)!@#& elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then !@#& floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],rSel)!@#& end!@#& elseif state==\"corner select\" then!@#& if not selectrect then!@#& selectrect = { x1=p2+sx, x2=p2+sx, y1=p3+sy, y2=p3+sy }!@#& elseif selectrect.x1 ~= p2+sx and selectrect.y1 ~= p3+sy then!@#& if p2+sx w + sx - 2 then sx = textCurX - w + 2 end!@#& elseif tonumber(p1) then!@#& if state==\"brush\" and tonumber(p1) > 1 then!@#& brushsize = tonumber(p1)!@#& elseif animated and tonumber(p1) > 0 then!@#& changeFrame(tonumber(p1))!@#& end!@#& end!@#& elseif id==\"key\" then!@#& --Text needs special handlers (all other keyboard shortcuts are of course reserved for typing)!@#& if state==\"text\" then!@#& if p1==keys.backspace and textCurX > 1 then!@#& textCurX = textCurX-1!@#& if frames[sFrame].text[textCurY] then!@#& frames[sFrame].text[textCurY][textCurX] = nil!@#& frames[sFrame].textcol[textCurY][textCurX] = nil!@#& end!@#& if textCurX < sx then sx = textCurX end!@#& elseif p1==keys.left and textCurX > 1 then!@#& textCurX = textCurX-1!@#& if textCurX-1 < sx then sx = textCurX-1 end!@#& elseif p1==keys.right then!@#& textCurX = textCurX+1!@#& if textCurX > w + sx - 2 then sx = textCurX - w + 2 end!@#& elseif p1==keys.up and textCurY > 1 then!@#& textCurY = textCurY-1!@#& if textCurY-1 < sy then sy = textCurY-1 end!@#& elseif p1==keys.down then!@#& textCurY = textCurY+1!@#& if textCurY > h + sy - 1 then sy = textCurY - h + 1 end!@#& end!@#& !@#& elseif p1==keys.leftCtrl then!@#& local sel = displayDropDown(1, h-1, ddModes[#ddModes]) !@#& performSelection(sel)!@#& elseif p1==keys.leftAlt then!@#& local sel = displayDropDown(1, h-1, ddModes[1]) !@#& performSelection(sel)!@#& elseif p1==keys.h then !@#& performSelection(\"help\")!@#& elseif p1==keys.x then !@#& performSelection(\"cut\")!@#& elseif p1==keys.c then!@#& performSelection(\"copy\")!@#& elseif p1==keys.v then!@#& performSelection(\"paste\")!@#& elseif p1==keys.z then!@#& performSelection(\"clear\")!@#& elseif p1==keys.s then!@#& performSelection(\"select\")!@#& elseif p1==keys.tab then!@#& performSelection(\"hide\")!@#& elseif p1==keys.q then!@#& performSelection(\"alpha to left\")!@#& elseif p1==keys.w then!@#& performSelection(\"alpha to right\")!@#& elseif p1==keys.f then!@#& performSelection(\"flood\")!@#& elseif p1==keys.b then!@#& performSelection(\"brush\")!@#& elseif p1==keys.m then!@#& performSelection(\"move\")!@#& elseif p1==keys.backslash and animated then!@#& performSelection(\"record\")!@#& elseif p1==keys.p then!@#& performSelection(\"pippette\")!@#& elseif p1==keys.g and animated then!@#& performSelection(\"go to\")!@#& elseif p1==keys.period and animated then!@#& changeFrame(sFrame+1)!@#& elseif p1==keys.comma and animated then!@#& changeFrame(sFrame-1)!@#& elseif p1==keys.r and animated then!@#& performSelection(\"remove\")!@#& elseif p1==keys.space and animated then!@#& performSelection(\"play\")!@#& elseif p1==keys.t and textEnabled then!@#& performSelection(\"text\")!@#& sleep(0.01)!@#& elseif p1==keys.y and textEnabled then!@#& performSelection(\"textpaint\")!@#& elseif p1==keys.left then!@#& if state == \"move\" and toplim then!@#& updateImageLims(record)!@#& if toplim and leflim then!@#& moveImage(leflim-1,toplim)!@#& end!@#& elseif state==\"select\" and selectrect.x1 > 1 then!@#& selectrect.x1 = selectrect.x1-1!@#& selectrect.x2 = selectrect.x2-1!@#& elseif sx > 0 then sx=sx-1 end!@#& elseif p1==keys.right then!@#& if state == \"move\" then!@#& updateImageLims(record)!@#& if toplim and leflim then!@#& moveImage(leflim+1,toplim)!@#& end!@#& elseif state==\"select\" then!@#& selectrect.x1 = selectrect.x1+1!@#& selectrect.x2 = selectrect.x2+1!@#& else sx=sx+1 end!@#& elseif p1==keys.up then!@#& if state == \"move\" then!@#& updateImageLims(record)!@#& if toplim and leflim then!@#& moveImage(leflim,toplim-1)!@#& end!@#& elseif state==\"select\" and selectrect.y1 > 1 then!@#& selectrect.y1 = selectrect.y1-1!@#& selectrect.y2 = selectrect.y2-1!@#& elseif sy > 0 then sy=sy-1 end!@#& elseif p1==keys.down then !@#& if state == \"move\" then!@#& updateImageLims(record)!@#& if toplim and leflim then!@#& moveImage(leflim,toplim+1)!@#& end!@#& elseif state==\"select\" then!@#& selectrect.y1 = selectrect.y1+1!@#& selectrect.y2 = selectrect.y2+1!@#& else sy=sy+1 end!@#& end!@#& end!@#& end!@#&end!@#&!@#&--[[!@#& Section: Main !@#&]]--!@#&!@#&if not term.isColour() then!@#& print(\"For colour computers only\")!@#& return!@#&end!@#&!@#&--Taken almost directly from edit (for consistency)!@#&local tArgs = {...}!@#&!@#&local ca = 1!@#&!@#&if tArgs[ca] == \"-a\" then!@#& animated = true!@#& ca = ca + 1!@#&end!@#&!@#&if tArgs[ca] == \"-t\" then!@#& textEnabled = true!@#& ca = ca + 1!@#&end!@#&!@#&if #tArgs < ca then!@#& print(\"Usage: npaintpro [-a,-t] \")!@#& return!@#&end!@#&!@#&--Yeah you can't have animated text files YET... I haven't supported that, maybe later?!@#&if animated and textEnabled then!@#& print(\"No support for animated text files- cannot have both -a and -t\")!@#&end!@#&!@#&sPath = shell.resolve(tArgs[ca])!@#&local bReadOnly = fs.isReadOnly(sPath)!@#&if fs.exists(sPath) then!@#& if fs.isDir(sPath) then!@#& print(\"Cannot edit a directory.\")!@#& return!@#& elseif string.find(sPath, \".nfp\") ~= #sPath-3 and string.find(sPath, \".nfa\") ~= #sPath-3 and!@#& string.find(sPath, \".nft\") ~= #sPath-3 then!@#& print(\"Can only edit .nfp, .nft and .nfa files:\",string.find(sPath, \".nfp\"),#sPath-3)!@#& return!@#& end!@#& !@#& if string.find(sPath, \".nfa\") == #sPath-3 then!@#& animated = true!@#& end!@#& !@#& if string.find(sPath, \".nft\") == #sPath-3 then!@#& textEnabled = true!@#& end !@#& !@#& if string.find(sPath, \".nfp\") == #sPath-3 and animated then!@#& print(\"Convert to nfa? Y/N\")!@#& if string.find(string.lower(io.read()), \"y\") then!@#& local nsPath = string.sub(sPath, 1, #sPath-1)..\"a\"!@#& fs.move(sPath, nsPath)!@#& sPath = nsPath!@#& else!@#& animated = false!@#& end!@#& end!@#& !@#& --Again this is possible, I just haven't done it. Maybe I will?!@#& if textEnabled and (string.find(sPath, \".nfp\") == #sPath-3 or string.find(sPath, \".nfa\") == #sPath-3) then!@#& print(\"Cannot convert to nft\")!@#& end!@#&else!@#& if not animated and not textEnabled and string.find(sPath, \".nfp\") ~= #sPath-3 then !@#& sPath = sPath..\".nfp\"!@#& elseif animated and string.find(sPath, \".nfa\") ~= #sPath-3 then !@#& sPath = sPath..\".nfa\"!@#& elseif textEnabled and string.find(sPath, \".nft\") ~= #sPath-3 then!@#& sPath = sPath..\".nft\"!@#& end!@#&end !@#&!@#&drawLogo()!@#&init()!@#&handleEvents()!@#&!@#&term.setBackgroundColour(colours.black)!@#&shell.run(\"clear\")",["gitdl"]="args = {...}!@#&if not #args == 2 then!@#& print(\"Usage: gitdl \")!@#& error()!@#&else!@#& h2f = fs.open(args[2], \"w\")!@#& h2f.write(http.get(\"https://raw.github.com/\" .. args[1]).readAll())!@#& h2f.close()!@#&end",["sudo"]="args = {...}!@#&fail = true!@#&if not sudo.isAdmin() then!@#&while fail do!@#& write(\"[sudo] password for \" .. spd.getData(\"login\").. \": \")!@#& pswd = read(\"*\")!@#& if pswd == \"\" then!@#& error()!@#& end!@#& if sudo.getAdminPrivs(pswd) then!@#& fail = false!@#& else!@#& print(\"sorry, try again\")!@#& end!@#&end!@#&end!@#&shell.run(args[1])!@#&sudo.setPrivID(2,pswd)",["shell"]="w, h = term.getSize()!@#&!@#&local function printc(str, ln)!@#& term.setCursorPos(w/2-#str/2, ln)!@#& print(str)!@#&end!@#&!@#&local commandHistory = {\"startz\"}!@#&!@#&if sysconf.z_auto then!@#& shell.run(\"startz\")!@#&end!@#&!@#&local function execute()!@#& shell.run(program)!@#& return true!@#&end!@#&!@#&while true do!@#& term.setTextColor(colors.lime)!@#& write(spd.getData(\"login\") .. \"@\" .. os.getComputerLabel())!@#& term.setTextColor(colors.blue)!@#& write(\": /\" .. shell.dir() .. \" $ \")!@#& term.setTextColor(colors.white)!@#& program = read(nil,commandHistory)!@#& table.insert(commandHistory,program)!@#& local ok, err = pcall(execute)!@#&end!@#&!@#&if not ok then!@#& term.setBackgroundColor(colors.lightGray)!@#& term.clear()!@#& printc(\"This program has encountered an error!\", 1)!@#& printc(\"Error:\", h/2-1)!@#& printc(err, h/2)!@#& printc(\"Press any key to reboot!\", h-1)!@#& os.pullEvent(\"key\")!@#& os.reboot()!@#&end!@#& ",["cat"]="args = {...}!@#&file = args[1]!@#&h = fs.open(file,\"r\")!@#&print(h.readAll())",["ehelp"]="args = {...}!@#&if not args[1] then!@#& print(\"Usage: rape \")!@#&else!@#& shell.run(\"ev\")!@#&end",["getapis"]="for k,v in pairs(_G) do!@#& if type(v) == 'table' and k ~= '_G' then!@#& print(k)!@#& sleep(0.1)!@#& end!@#&end",["crash"]="poo face : lol",["uplib"]={["smart"]="",["safe"]="",},["pkgmake"]="sPackage = \"local pkg = %@1 local function makeFile(_path, _content) local file = fs.open(_path, \\\"w\\\") _content = _content:gsub(\\\"\\!@\\\"..\\\"#&\\\", \\\"%\\\\n\\\") _content = textutils.unserialize(_content) file.write(_content) file.close() end local function makeFolder(_path, _content) fs.makeDir(_path) for k,v in pairs(_content) do if type(v) == \\\"table\\\" then makeFolder(_path .. \\\"/\\\" .. k, v) else makeFile(_path .. \\\"/\\\" .. k, v) end end end local sDest = shell.resolve( \\\"%@2\\\" ) or \\\"/\\\" if sDest == \\\"root\\\" then sDest = \\\"/\\\" end local tPackage = pkg makeFolder(sDest, tPackage) print(\\\"Package Extracted to '\\\" .. sDest .. \\\"'!\\\")\"!@#&!@#&function addFile(_package, _path)!@#& if fs.getName(_path) == \".DS_Store\" then!@#& return _package!@#& end!@#& local file, err = fs.open(_path, \"r\")!@#& local content = file.readAll()!@#& content = content:gsub(\"%\\n\", \"\\!@\"..\"#&\")!@#& content = content:gsub(\"%%\", \"%%%%\")!@#& _package[fs.getName(_path)] = content!@#& file.close()!@#& print(\"Added file '\".._path..\"'\")!@#& return _package!@#&end!@#&!@#&function addFolder(_package, _path)!@#& if string.sub(_path,1,string.len(\"rom\"))==\"rom\" or string.sub(_path,1,string.len(\"/rom\"))==\"/rom\" then!@#& print(\"Ignored 'rom' folder. (\".._path..\")\")!@#& return!@#& end!@#& _package = _package or {}!@#& for _,f in ipairs(fs.list(_path)) do!@#& local path = _path..\"/\"..f!@#& if fs.isDir(path) then!@#& _package[fs.getName(f)] = addFolder(_package[fs.getName(f)], path)!@#& else!@#& _package = addFile(_package, path)!@#& end!@#& end!@#& return _package!@#&end!@#&!@#&local tArgs = { ... }!@#&if #tArgs < 2 then!@#& print( \"Usage: PkgMake \" )!@#& return!@#&end!@#&!@#&local sSource = shell.resolve( tArgs[1] )!@#&local sDest = shell.resolve( tArgs[2] )!@#&!@#&if fs.isDir( sDest ) then!@#& error(\"Destination must not be a folder.\")!@#&end!@#&!@#&if sSource == sDest then!@#& error(\"Source can not be equal to destination.\")!@#&end!@#&!@#&if fs.exists( sSource ) and fs.isDir( sSource ) then!@#& tPackage = {}!@#& tPackage = addFolder(tPackage, sSource)!@#& fPackage = fs.open(sDest,\"w\")!@#&!@#& sPackage = string.gsub(sPackage, \"%%@2\", fs.getName(sSource))!@#& sPackage = string.gsub(sPackage, \"%%@1\", textutils.serialize(tPackage))!@#& fPackage.write(sPackage)!@#& fPackage.close()!@#& print(\"Package Done! ('\" .. sDest .. \"')\")!@#& print(\"Type '\" .. sDest .. \"' to run it.\")!@#&else!@#& error(\"Source does not exist or is not a folder.\")!@#&end",["mpc-get"]="repolist = \"/var/mpc-get-repo.rpo\"!@#&repos = {}!@#&local file = fs.open(repolist, \"r\")!@#&if file then!@#& repos = {}!@#& local line = file.readLine()!@#& while line do!@#& table.insert(repos, line)!@#& line = file.readLine()!@#& end!@#& file.close()!@#&end!@#&!@#&textutils.tabulate(repos)",},["firewolf"]="if fs.isReadOnly(shell.getRunningProgram()) then!@#& fs.delete(\"/firewolf\")!@#& fs.copy(shell.getRunningProgram(),\"/firewolf\")!@#& error()!@#&end!@#&-- !@#&-- Firewolf Website Browser!@#&-- Made by GravityScore and 1lann!@#&-- License found here: https://raw.github.com/1lann/Firewolf/master/LICENSE!@#&-- !@#&-- Original Concept From RednetExplorer 2.4.1!@#&-- RednetExplorer Made by ComputerCraftFan11!@#&-- !@#& !@#& !@#&-- -------- Variables!@#& !@#&-- Version!@#&local version = \"2.4\"!@#&local build = 29!@#&local browserAgentTemplate = \"Firewolf \" .. version!@#&browserAgent = browserAgentTemplate!@#&local tArgs = {...}!@#& !@#&-- Server Identification!@#&local serverID = \"other\"!@#&local serverList = {experimental = \"Experimental\", other = \"Other\"}!@#& !@#&-- Updating!@#&local autoupdate = \"true\"!@#&local noInternet = false!@#& !@#&-- Resources!@#&local graphics = {}!@#&local files = {}!@#&local w, h = term.getSize()!@#& !@#&-- Debugging!@#&local debugFile = nil!@#& !@#&-- Environment!@#&local oldpullevent = os.pullEvent!@#&local oldEnv = {}!@#&local env = {}!@#&local backupEnv = {}!@#& !@#&local api = {}!@#&local override = {}!@#&local antivirus = {}!@#& !@#&-- Themes!@#&local theme = {}!@#& !@#&-- Databases!@#&local blacklist = {}!@#&local whitelist = {}!@#&local dnsDatabase = {[1] = {}, [2] = {}}!@#& !@#&-- Website Loading!@#&local pages = {}!@#&local errorPages = {}!@#& !@#&local website = \"\"!@#&local homepage = \"\"!@#&local timeout = 0.2!@#&local loadingRate = 0!@#&local openAddressBar = true!@#&local clickableAddressBar = true!@#&local menuBarOpen = false!@#& !@#&-- Protocols!@#&local curProtocol = {}!@#&local protocols = {}!@#& !@#&-- History!@#&local addressBarHistory = {}!@#& !@#&-- Events!@#&local event_loadWebsite = \"firewolf_loadWebsiteEvent\"!@#&local event_exitWebsite = \"firewolf_exitWebsiteEvent\"!@#&local event_redirect = \"firewolf_redirectEvent\"!@#&local event_exitApp = \"firewolf_exitAppEvent\"!@#& !@#&-- Download URLs!@#&local firewolfURL = \"https://raw.github.com/1lann/firewolf/master/entities/\" .. serverID .. \".lua\"!@#&local a = \"release\"!@#&if serverID == \"experimental\" then a = \"experimental\" end!@#&local serverURL = \"https://raw.github.com/1lann/firewolf/master/server/server-\" .. a .. \".lua\"!@#&local buildURL = \"https://raw.github.com/1lann/firewolf/master/build\"!@#& !@#&-- Data Locations!@#&local rootFolder = \"/.Firewolf_Data\"!@#&local cacheFolder = rootFolder .. \"/cache\"!@#&local serverFolder = rootFolder .. \"/servers\"!@#&local websiteDataFolder = rootFolder .. \"/website_data\"!@#&local themeLocation = rootFolder .. \"/theme\"!@#&local serverLocation = rootFolder .. \"/server_software\"!@#&local settingsLocation = rootFolder .. \"/settings\"!@#&local debugLogLocation = \"/firewolf-log\"!@#&local firewolfLocation = \"/\" .. shell.getRunningProgram()!@#& !@#&local userBlacklist = rootFolder .. \"/user_blacklist\"!@#&local userWhitelist = rootFolder .. \"/user_whitelist\"!@#& !@#& !@#&-- -------- Utilities!@#& !@#&local function debugLog(n, ...)!@#& local lArgs = {...}!@#& if debugFile then!@#& if n == nil then n = \"\" end!@#& debugFile:write(\"\\n\" .. tostring(n) .. \" : \")!@#& for k, v in pairs(lArgs) do!@#& if type(v) == \"string\" or type(v) == \"number\" or type(v) == nil or!@#& type(v) == \"boolean\" then!@#& debugFile:write(tostring(v) .. \", \")!@#& else debugFile:write(\"type-\" .. type(v) .. \", \") end!@#& end!@#& end!@#&end!@#& !@#&local function modRead(properties)!@#& local w, h = term.getSize()!@#& local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil,!@#& liveUpdates = nil, exitOnKey = nil}!@#& if not properties then properties = {} end!@#& for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end!@#& if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end!@#& if not properties.visibleLength then properties.visibleLength = w end!@#& !@#& local sx, sy = term.getCursorPos()!@#& local line = \"\"!@#& local pos = 0!@#& local historyPos = nil!@#& !@#& local function redraw(repl)!@#& local scroll = 0!@#& if properties.visibleLength and sx + pos > properties.visibleLength + 1 then!@#& scroll = (sx + pos) - (properties.visibleLength + 1)!@#& end!@#& !@#& term.setCursorPos(sx, sy)!@#& local a = repl or properties.replaceChar!@#& if a then term.write(string.rep(a, line:len() - scroll))!@#& else term.write(line:sub(scroll + 1, -1)) end!@#& term.setCursorPos(sx + pos - scroll, sy)!@#& end!@#& !@#& local function sendLiveUpdates(event, ...)!@#& if type(properties.liveUpdates) == \"function\" then!@#& local ox, oy = term.getCursorPos()!@#& local a, data = properties.liveUpdates(line, event, ...)!@#& if a == true and data == nil then!@#& term.setCursorBlink(false)!@#& return line!@#& elseif a == true and data ~= nil then!@#& term.setCursorBlink(false)!@#& return data!@#& end!@#& term.setCursorPos(ox, oy)!@#& end!@#& end!@#& !@#& local a = sendLiveUpdates(\"delete\")!@#& if a then return a end!@#& term.setCursorBlink(true)!@#& while true do!@#& local e, but, x, y, p4, p5 = os.pullEvent()!@#& !@#& if e == \"char\" then!@#& local s = false!@#& if properties.textLength and line:len() < properties.textLength then s = true!@#& elseif not properties.textLength then s = true end!@#& !@#& local canType = true!@#& if not properties.grantPrint and properties.refusePrint then!@#& local canTypeKeys = {}!@#& if type(properties.refusePrint) == \"table\" then!@#& for _, v in pairs(properties.refusePrint) do!@#& table.insert(canTypeKeys, tostring(v):sub(1, 1))!@#& end!@#& elseif type(properties.refusePrint) == \"string\" then!@#& for char in properties.refusePrint:gmatch(\".\") do!@#& table.insert(canTypeKeys, char)!@#& end!@#& end!@#& for _, v in pairs(canTypeKeys) do if but == v then canType = false end end!@#& elseif properties.grantPrint then!@#& canType = false!@#& local canTypeKeys = {}!@#& if type(properties.grantPrint) == \"table\" then!@#& for _, v in pairs(properties.grantPrint) do!@#& table.insert(canTypeKeys, tostring(v):sub(1, 1))!@#& end!@#& elseif type(properties.grantPrint) == \"string\" then!@#& for char in properties.grantPrint:gmatch(\".\") do!@#& table.insert(canTypeKeys, char)!@#& end!@#& end!@#& for _, v in pairs(canTypeKeys) do if but == v then canType = true end end!@#& end!@#& !@#& if s and canType then!@#& line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)!@#& pos = pos + 1!@#& redraw()!@#& end!@#& elseif e == \"key\" then!@#& if but == keys.enter then!@#& break!@#& elseif but == keys.left then!@#& if pos > 0 then pos = pos - 1 redraw() end!@#& elseif but == keys.right then!@#& if pos < line:len() then pos = pos + 1 redraw() end!@#& elseif (but == keys.up or but == keys.down) and properties.history and!@#& #properties.history > 0 then!@#& redraw(\" \")!@#& if but == keys.up then!@#& if historyPos == nil and #properties.history > 0 then!@#& historyPos = #properties.history!@#& elseif historyPos > 1 then!@#& historyPos = historyPos - 1!@#& end!@#& elseif but == keys.down then!@#& if historyPos == #properties.history then historyPos = nil!@#& elseif historyPos ~= nil then historyPos = historyPos + 1 end!@#& end!@#& !@#& if properties.history and historyPos then!@#& line = properties.history[historyPos]!@#& pos = line:len()!@#& else!@#& line = \"\"!@#& pos = 0!@#& end!@#& !@#& redraw()!@#& local a = sendLiveUpdates(\"history\")!@#& if a then return a end!@#& elseif but == keys.backspace and pos > 0 then!@#& redraw(\" \")!@#& line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)!@#& pos = pos - 1!@#& redraw()!@#& local a = sendLiveUpdates(\"delete\")!@#& if a then return a end!@#& elseif but == keys.home then!@#& pos = 0!@#& redraw()!@#& elseif but == keys.delete and pos < line:len() then!@#& redraw(\" \")!@#& line = line:sub(1, pos) .. line:sub(pos + 2, -1)!@#& redraw()!@#& local a = sendLiveUpdates(\"delete\")!@#& if a then return a end!@#& elseif but == keys[\"end\"] then!@#& pos = line:len()!@#& redraw()!@#& elseif properties.exitOnKey then!@#& if but == properties.exitOnKey or (properties.exitOnKey == \"control\" and!@#& (but == 29 or but == 157)) then!@#& term.setCursorBlink(false)!@#& return nil!@#& end!@#& end!@#& end!@#& !@#& local a = sendLiveUpdates(e, but, x, y, p4, p5)!@#& if a then return a end!@#& end!@#& !@#& term.setCursorBlink(false)!@#& if line ~= nil then line = line:gsub(\"^%s*(.-)%s*$\", \"%1\") end!@#& return line!@#&end!@#& !@#& !@#&-- -------- Environment and APIs!@#& !@#&local function isAdvanced()!@#& return term.isColor and term.isColor()!@#&end!@#& !@#&local function clearPage(site, color, redraw, tcolor)!@#& -- Site titles!@#& local titles = {firewolf = \"Firewolf Homepage\", [\"server/rdnt\"] = \"RDNT Server Management\",!@#& [\"server/http\"] = \"HTTP Server Management\", help = \"Firewolf Help\",!@#& settings = \"Firewolf Settings\", credits = \"Firewolf Credits\",!@#& crash = \"Website Has Crashed!\", overspeed = \"Too Fast!\"}!@#& local title = titles[site]!@#& !@#& -- Clear!@#& term.setBackgroundColor(color or colors.black)!@#& term.setTextColor(colors[theme[\"address-bar-text\"]])!@#& if redraw ~= true then term.clear() end!@#& !@#& if not menuBarOpen then!@#& term.setBackgroundColor(colors[theme[\"address-bar-background\"]])!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& local a = site!@#& if a:len() > w - 10 then a = a:sub(1, 38) .. \"...\" end!@#& if curProtocol == protocols.rdnt then write(\"rdnt://\" .. a)!@#& elseif curProtocol == protocols.http then write(\"http://\" .. a) end!@#& !@#& if title ~= nil then!@#& term.setCursorPos(w - title:len() - 1, 1)!@#& write(title)!@#& end if isAdvanced() then!@#& term.setCursorPos(w, 1)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& write(\"<\")!@#& end!@#& !@#& term.setBackgroundColor(color or colors.black)!@#& term.setTextColor(tcolor or colors.white)!@#& else!@#& term.setCursorPos(1, 1)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.clearLine()!@#& write(\"> [- Exit Firewolf -] \")!@#& end!@#& !@#& print(\"\")!@#&end!@#& !@#&local function printWithType(t, func)!@#& if type(t) == \"table\" then!@#& for k, v in pairs(t) do!@#& env.pcall(function() printWithType(v, func) end)!@#& end!@#& else!@#& func(tostring(t))!@#& end!@#&end!@#& !@#&-- Drawing Functions!@#&api.centerWrite = function(text)!@#& printWithType(text, function(t)!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(math.ceil((w + 1)/2 - t:len()/2), y)!@#& write(t)!@#& end)!@#&end!@#& !@#&api.centerPrint = function(text)!@#& printWithType(text, function(t)!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(math.ceil((w + 1)/2 - t:len()/2), y)!@#& print(t)!@#& end)!@#&end!@#& !@#&api.leftWrite = function(text)!@#& printWithType(text, function(t)!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(1, y)!@#& write(t)!@#& end)!@#&end!@#& !@#&api.leftPrint = function(text)!@#& printWithType(text, function(t)!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(1, y)!@#& print(t)!@#& end)!@#&end!@#& !@#&api.rightWrite = function(text)!@#& printWithType(text, function(t)!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(w - t:len() + 1, y)!@#& write(t)!@#& end)!@#&end!@#& !@#&api.rightPrint = function(text)!@#& printWithType(text, function(t)!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(w - t:len() + 1, y)!@#& print(t)!@#& end)!@#&end!@#& !@#&-- Server Interation Functions!@#& !@#&api.loadFileFromServer = function(path)!@#& if type(path) ~= \"string\" then error(\"loadFile: expected string\") end!@#& sleep(0.05)!@#& if path:sub(1, 1) == \"/\" then path = path:sub(2, -1) end!@#& local id, content = curProtocol.getWebsite(website .. \"/\" .. path)!@#& if id then!@#& return content!@#& end!@#& return nil!@#&end!@#& !@#&api.ioReadFileFromServer = function(path)!@#& local content = api.loadFileFromServer(path)!@#& if content then!@#& local f = env.io.open(rootFolder .. \"/temp_file\", \"w\")!@#& f:write(content)!@#& f:close()!@#& local fi = env.io.open(rootFolder .. \"/temp_file\", \"r\")!@#& return fi!@#& end!@#& return nil!@#&end!@#& !@#&api.loadImageFromServer = function(path)!@#& local content = api.loadFileFromServer(path)!@#& if content then!@#& local f = env.io.open(rootFolder .. \"/temp_file\", \"w\")!@#& f:write(content)!@#& f:close()!@#& !@#& local image = paintutils.loadImage(rootFolder .. \"/temp_file\")!@#& env.fs.delete(\"/temp_file\")!@#& return image!@#& end!@#& return nil!@#&end!@#& !@#&api.writeDataFile = function(path, content)!@#& if type(path) ~= \"string\" or type(content) ~= \"string\" then!@#& error(\"writeDataFile: expected string, string\") end!@#& if path:sub(1, 1) == \"/\" then path = path:sub(2, -1) end!@#& local dataPath = websiteDataFolder .. \"/\" .. path:gsub(\"/\", \"$slazh$\")!@#& !@#& if env.fs.isReadOnly(dataPath) then return false end!@#& if env.fs.exists(dataPath) then env.fs.delete(dataPath) end!@#& local f = env.io.open(dataPath, \"w\")!@#& if not f then return false end!@#& f:write(content)!@#& f:close()!@#& return true!@#&end!@#& !@#&api.readDataFile = function(path)!@#& if type(path) ~= \"string\" then error(\"readDataFile: expected string\") end!@#& if path:sub(1, 1) == \"/\" then path = path:sub(2, -1) end!@#& local dataPath = websiteDataFolder .. \"/\" .. path:gsub(\"/\", \"$slazh$\")!@#& !@#& if env.fs.isDir(dataPath) then env.fs.delete(dataPath) end!@#& if env.fs.exists(dataPath) then!@#& local f = env.io.open(dataPath, \"r\")!@#& local cont = f:read(\"*a\")!@#& f:close()!@#& return cont!@#& end!@#& return nil!@#&end!@#& !@#&api.saveFileToUserComputer = function(content)!@#& if type(content) ~= \"string\" then error(\"saveFileToUserComputer: expected string\") end!@#& local oldback, oldtext = term.getBackgroundColor(), term.getTextColor()!@#& local ox, oy = term.getCursorPos()!@#& !@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 20))!@#& leftPrint(\" Save File Request \")!@#& leftPrint(string.rep(\" \", 20))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do rightPrint(string.rep(\" \", 36)) end!@#& term.setCursorPos(1, 7)!@#& rightPrint(\"The website: \")!@#& rightPrint(website .. \" \")!@#& rightPrint(\"Is requesting to save a file \")!@#& rightPrint(\"to your computer. \")!@#& !@#& local ret = nil!@#& local opt = prompt({{\"Save File\", w - 16, 12}, {\"Cancel\", w - 13, 13}}, \"vertical\")!@#& if opt == \"Save File\" then!@#& while true do!@#& term.setCursorPos(1, 15)!@#& rightWrite(string.rep(\" \", 36))!@#& term.setCursorPos(w - 34, 15)!@#& write(\"Path: /\")!@#& local p = read()!@#& !@#& term.setCursorPos(1, 15)!@#& rightWrite(string.rep(\" \", 36))!@#& if p == \"\" or p == nil then!@#& rightWrite(\"File Name Empty! Cancelling... \")!@#& break!@#& elseif fs.exists(\"/\" .. p) then!@#& rightWrite(\"File Already Exists! \")!@#& else!@#& rightWrite(\"File Saved! \")!@#& ret = \"/\" .. p!@#& break!@#& end!@#& !@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& end!@#& elseif opt == \"Cancel\" then!@#& term.setCursorPos(1, 15)!@#& rightWrite(\"Saving Cancelled! \")!@#& end!@#& !@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& !@#& term.setBackgroundColor(oldback or colors.black)!@#& term.setTextColor(oldtext or colors.white)!@#& term.clear()!@#& term.setCursorPos(ox, oy)!@#& return ret!@#&end!@#& !@#&api.urlDownload = function(url)!@#& if type(url) ~= \"string\" then error(\"download: expected string\") end!@#& local source = nil!@#& http.request(url)!@#& local a = os.startTimer(10)!@#& while true do!@#& local e, surl, handle = os.pullEvent()!@#& if e == \"http_success\" then!@#& source = handle.readAll()!@#& break!@#& elseif e == \"http_failure\" or (e == \"timer\" and surl == a) then!@#& break!@#& end!@#& end!@#& !@#& if type(source) == \"string\" then!@#& local saveFunc = api.saveFileToUserComputer!@#& env.setfenv(saveFunc, override)!@#& return saveFunc(source)!@#& else return nil end!@#&end!@#& !@#&api.pastebinDownload = function(code)!@#& return api.urlDownload(\"http://pastebin.com/raw.php?i=\" .. tostring(code))!@#&end!@#& !@#&-- Redirect!@#&api.redirect = function(url)!@#& if type(url) ~= \"string\" then url = \"home\" end!@#& os.queueEvent(event_redirect, url:gsub(\"rdnt://\"):gsub(\"http://\"))!@#& error()!@#&end!@#& !@#&-- Theme Function!@#&api.themeColor = function(tag, default)!@#& if type(tag) ~= \"string\" then error(\"themeColor: expected string\") end!@#& if theme[tag] then!@#& return colors[theme[tag]]!@#& elseif defaultTheme[tag] then!@#& return colors[defaultTheme[tag]]!@#& else!@#& return default or colors.white!@#& end!@#&end!@#& !@#&api.themeColour = function(tag, default)!@#& return api.themeColor(tag, default)!@#&end!@#& !@#&-- Prompt Software!@#&api.prompt = function(list, dir)!@#& if isAdvanced() then!@#& for _, v in pairs(list) do!@#& if v.bg then term.setBackgroundColor(v.bg) end!@#& if v.tc then term.setTextColor(v.tc) end!@#& if v[2] == -1 then v[2] = math.ceil((w + 1)/2 - (v[1]:len() + 6)/2) end!@#& !@#& term.setCursorPos(v[2], v[3])!@#& write(\"[- \" .. v[1])!@#& term.setCursorPos(v[2] + v[1]:len() + 3, v[3])!@#& write(\" -]\")!@#& end!@#& !@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"mouse_click\" then!@#& for _, v in pairs(list) do!@#& if x >= v[2] and x <= v[2] + v[1]:len() + 5 and y == v[3] then!@#& return v[1]!@#& end!@#& end!@#& end!@#& end!@#& else!@#& for _, v in pairs(list) do!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& if v[2] == -1 then v[2] = math.ceil((w + 1)/2 - (v[1]:len() + 4)/2) end!@#& !@#& term.setCursorPos(v[2], v[3])!@#& write(\" \" .. v[1])!@#& term.setCursorPos(v[2] + v[1]:len() + 2, v[3])!@#& write(\" \")!@#& end!@#& !@#& local key1, key2 = 200, 208!@#& if dir == \"horizontal\" then key1, key2 = 203, 205 end!@#& !@#& local curSel = 1!@#& term.setCursorPos(list[curSel][2], list[curSel][3])!@#& write(\"[\")!@#& term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])!@#& write(\"]\")!@#& !@#& while true do!@#& local e, key = os.pullEvent()!@#& term.setCursorPos(list[curSel][2], list[curSel][3])!@#& write(\" \")!@#& term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])!@#& write(\" \")!@#& if e == \"key\" and key == key1 and curSel > 1 then!@#& curSel = curSel - 1!@#& elseif e == \"key\" and key == key2 and curSel < #list then!@#& curSel = curSel + 1!@#& elseif e == \"key\" and key == 28 then!@#& return list[curSel][1]!@#& end!@#& term.setCursorPos(list[curSel][2], list[curSel][3])!@#& write(\"[\")!@#& term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])!@#& write(\"]\")!@#& end!@#& end!@#&end!@#& !@#&api.scrollingPrompt = function(list, x, y, len, width)!@#& local wid = width!@#& if wid == nil then wid = w - 3 end!@#& !@#& local function updateDisplayList(items, loc, len)!@#& local ret = {}!@#& for i = 1, len do!@#& local item = items[i + loc - 1]!@#& if item ~= nil then table.insert(ret, item) end!@#& end!@#& return ret!@#& end!@#& !@#& if isAdvanced() then!@#& local function draw(a)!@#& for i, v in ipairs(a) do!@#& term.setCursorPos(x, y + i - 1)!@#& write(string.rep(\" \", wid))!@#& term.setCursorPos(x, y + i - 1)!@#& write(\"[ \" .. v:sub(1, wid - 5))!@#& term.setCursorPos(wid + x - 2, y + i - 1)!@#& write(\" ]\")!@#& end!@#& end!@#& !@#& local loc = 1!@#& local disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& !@#& while true do!@#& local e, but, clx, cly = os.pullEvent()!@#& if e == \"key\" and but == 200 and loc > 1 then!@#& loc = loc - 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"key\" and but == 208 and loc + len - 1 < #list then!@#& loc = loc + 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"mouse_scroll\" and but > 0 and loc + len - 1 < #list then!@#& loc = loc + but!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"mouse_scroll\" and but < 0 and loc > 1 then!@#& loc = loc + but!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& elseif e == \"mouse_click\" then!@#& for i, v in ipairs(disList) do!@#& if clx >= x and clx <= x + wid and cly == i + y - 1 then!@#& return v!@#& end!@#& end!@#& end!@#& end!@#& else!@#& local function draw(a)!@#& for i, v in ipairs(a) do!@#& term.setCursorPos(x, y + i - 1)!@#& write(string.rep(\" \", wid))!@#& term.setCursorPos(x, y + i - 1)!@#& write(\"[ ] \" .. v:sub(1, wid - 5))!@#& end!@#& end!@#& !@#& local loc = 1!@#& local curSel = 1!@#& local disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& term.setCursorPos(x + 1, y + curSel - 1)!@#& write(\"x\")!@#& !@#& while true do!@#& local e, key = os.pullEvent()!@#& term.setCursorPos(x + 1, y + curSel - 1)!@#& write(\" \")!@#& if e == \"key\" and key == 200 then!@#& if curSel > 1 then!@#& curSel = curSel - 1!@#& elseif loc > 1 then!@#& loc = loc - 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& end!@#& elseif e == \"key\" and key == 208 then!@#& if curSel < #disList then!@#& curSel = curSel + 1!@#& elseif loc + len - 1 < #list then!@#& loc = loc + 1!@#& disList = updateDisplayList(list, loc, len)!@#& draw(disList)!@#& end!@#& elseif e == \"key\" and key == 28 then!@#& return list[curSel + loc - 1]!@#& end!@#& term.setCursorPos(x + 1, y + curSel - 1)!@#& write(\"x\")!@#& end!@#& end!@#&end!@#& !@#&api.clearArea = function() api.clearPage(website) end!@#&api.cPrint = function(text) api.centerPrint(text) end!@#&api.cWrite = function(text) api.centerWrite(text) end!@#&api.lPrint = function(text) api.leftPrint(text) end!@#&api.lWrite = function(text) api.leftWrite(text) end!@#&api.rPrint = function(text) api.rightPrint(text) end!@#&api.rWrite = function(text) api.rightWrite(text) end!@#& !@#&local pullevent = function(data)!@#& while true do!@#& local e, p1, p2, p3, p4, p5 = os.pullEventRaw()!@#& if e == event_exitWebsite or e == \"terminate\" then!@#& error()!@#& end!@#& !@#& if data then!@#& if e == data then return e, p1, p2, p3, p4, p5 end!@#& else return e, p1, p2, p3, p4, p5 end!@#& end!@#&end!@#& !@#&-- Set Environment!@#&for k, v in pairs(getfenv(0)) do env[k] = v end!@#&for k, v in pairs(getfenv(1)) do env[k] = v end!@#&for k, v in pairs(env) do oldEnv[k] = v end!@#&for k, v in pairs(api) do env[k] = v end!@#&for k, v in pairs(env) do backupEnv[k] = v end!@#& !@#&oldEnv[\"os\"][\"pullEvent\"] = oldpullevent!@#&env[\"os\"][\"pullEvent\"] = pullevent!@#&os.pullEvent = pullevent!@#& !@#& !@#&-- -------- Website Overrides!@#& !@#&for k, v in pairs(env) do override[k] = v end!@#&local curtext, curbackground = colors.white, colors.black!@#&override.term = {}!@#&for k, v in pairs(env.term) do override.term[k] = v end!@#&override.os = {}!@#&for k, v in pairs(env.os) do override.os[k] = v end!@#& !@#&override.write = function( sText )!@#& local w,h = override.term.getSize() !@#& local x,y = override.term.getCursorPos()!@#& !@#& local nLinesPrinted = 0!@#& local function newLine()!@#& if y + 1 <= h then!@#& override.term.setCursorPos(1, y + 1)!@#& else!@#& override.term.setCursorPos(1, h)!@#& override.term.scroll(1)!@#& end!@#& x, y = override.term.getCursorPos()!@#& nLinesPrinted = nLinesPrinted + 1!@#& end!@#& !@#& -- Print the line with proper word wrapping!@#& while string.len(sText) > 0 do!@#& local whitespace = string.match( sText, \"^[ \\t]+\" )!@#& if whitespace then!@#& -- Print whitespace!@#& term.write( whitespace )!@#& x,y = override.term.getCursorPos()!@#& sText = string.sub( sText, string.len(whitespace) + 1 )!@#& end!@#& !@#& local newline = string.match( sText, \"^\\n\" )!@#& if newline then!@#& -- Print newlines!@#& newLine()!@#& sText = string.sub( sText, 2 )!@#& end!@#& !@#& local text = string.match( sText, \"^[^ \\t\\n]+\" )!@#& if text then!@#& sText = string.sub( sText, string.len(text) + 1 )!@#& if string.len(text) > w then!@#& -- Print a multiline word !@#& while string.len( text ) > 0 do!@#& if x > w then!@#& newLine()!@#& end!@#& term.write( text )!@#& text = string.sub( text, (w-x) + 2 )!@#& x,y = override.term.getCursorPos()!@#& end!@#& else!@#& -- Print a word normally!@#& if x + string.len(text) - 1 > w then!@#& newLine()!@#& end!@#& term.write( text )!@#& x,y = override.term.getCursorPos()!@#& end!@#& end!@#& end!@#& !@#& return nLinesPrinted!@#&end!@#& !@#&override.print = function( ... )!@#& local nLinesPrinted = 0!@#& for n,v in ipairs( { ... } ) do!@#& nLinesPrinted = nLinesPrinted + override.write( tostring( v ) )!@#& end!@#& nLinesPrinted = nLinesPrinted + override.write( \"\\n\" )!@#& return nLinesPrinted!@#&end!@#& !@#&override.term.getSize = function()!@#& local a, b = env.term.getSize()!@#& return a, b - 1!@#&end!@#& !@#&override.term.setCursorPos = function(x, y)!@#& if y < 1 then!@#& return env.term.setCursorPos(x, 2)!@#& else!@#& return env.term.setCursorPos(x, y+1)!@#& end!@#&end!@#& !@#&override.term.getCursorPos = function()!@#& local x, y = env.term.getCursorPos()!@#& return x, y - 1!@#&end!@#& !@#&override.term.getBackgroundColor = function()!@#& return curbackground!@#&end!@#& !@#&override.term.getBackgroundColour = function()!@#& return override.term.getBackgroundColor()!@#&end!@#& !@#&override.term.setBackgroundColor = function(col)!@#& curbackground = col!@#& return env.term.setBackgroundColor(col)!@#&end!@#& !@#&override.term.setBackgroundColour = function(col)!@#& return override.term.setBackgroundColor(col)!@#&end!@#& !@#&override.term.getTextColor = function()!@#& return curtext!@#&end!@#& !@#&override.term.getTextColour = function()!@#& return override.term.getTextColor()!@#&end!@#& !@#&override.term.setTextColor = function(col)!@#& curtext = col!@#& return env.term.setTextColor(col)!@#&end!@#& !@#&override.term.setTextColour = function(col)!@#& return override.term.setTextColor(col)!@#&end!@#& !@#&override.term.clear = function()!@#& local x, y = term.getCursorPos()!@#& local oldbackground = override.term.getBackgroundColor()!@#& local oldtext = override.term.getTextColor()!@#& clearPage(website, curbackground)!@#& !@#& term.setBackgroundColor(oldbackground)!@#& term.setTextColor(oldtext)!@#& term.setCursorPos(x, y)!@#&end!@#& !@#&override.term.scroll = function(n)!@#& local x, y = term.getCursorPos()!@#& local oldbackground = override.term.getBackgroundColor()!@#& local oldtext = override.term.getTextColor()!@#& !@#& env.term.scroll(n)!@#& clearPage(website, curbackground, true)!@#& term.setBackgroundColor(oldbackground)!@#& term.setTextColor(oldtext)!@#& term.setCursorPos(x, y)!@#&end!@#& !@#&override.term.isColor = function() return isAdvanced() end!@#&override.term.isColour = function() return override.term.isColor() end!@#& !@#&override.os.queueEvent = function(event, ...)!@#& if event == \"terminate\" or event == event_exitApp then!@#& os.queueEvent(event_exitWebsite)!@#& else!@#& env.os.queueEvent(event, ...)!@#& end!@#&end!@#& !@#&override.os.pullEvent = function(data)!@#& while true do!@#& local e, p1, p2, p3, p4, p5 = os.pullEventRaw()!@#& if e == event_exitWebsite or e == \"terminate\" then!@#& error()!@#& elseif (e == \"mouse_click\" or e == \"mouse_drag\") and not data then!@#& return e, p1, p2, p3 - 1!@#& elseif e == \"mouse_click\" and data == \"mouse_click\" then!@#& return e, p1, p2, p3 - 1!@#& elseif e == \"mouse_drag\" and data == \"mouse_drag\" then!@#& return e, p1, p2, p3 - 1!@#& end!@#& !@#& if data then!@#& if e == data then return e, p1, p2, p3, p4, p5 end!@#& else return e, p1, p2, p3, p4, p5 end!@#& end!@#&end!@#& !@#&local overridePullEvent = override.os.pullEvent!@#& !@#&override.prompt = function(list, dir)!@#& local a = {}!@#& for k, v in pairs(list) do!@#& table.insert(a, {v[1], v[2], v[3] + 1, tc = v.tc or curtext, bg = v.bg or curbackground})!@#& end!@#& return env.prompt(a, dir)!@#&end!@#& !@#&override.scrollingPrompt = function(list, x, y, len, width)!@#& return env.scrollingPrompt(list, x, y + 1, len, width)!@#&end!@#& !@#&local barTerm = {}!@#&for k, v in pairs(override.term) do barTerm[k] = v end!@#& !@#&barTerm.clear = override.term.clear!@#&barTerm.scroll = override.term.scroll!@#& !@#&local safeTerm = {}!@#&for k, v in pairs(term) do safeTerm[k] = v end!@#& !@#&override.showBar = function()!@#& clickableAddressBar = true!@#& os.pullEvent = overridePullEvent!@#& return os.pullEvent, barTerm!@#&end!@#& !@#&override.hideBar = function()!@#& clickableAddressBar = false!@#& os.pullEvent = pullevent!@#& return os.pullEvent, safeTerm!@#&end!@#& !@#& !@#&-- -------- Antivirus System!@#& !@#&-- Overrides!@#&local antivirusOverrides = {!@#& [\"Run Files\"] = {\"shell.run\", \"os.run\"},!@#& [\"Modify System\"] = {\"shell.setAlias\", \"shell.clearAlias\", \"os.setComputerLabel\", \"shell.setDir\",!@#& \"shell.setPath\"},!@#& [\"Modify Files\"] = {\"fs.makeDir\", \"fs.move\", \"fs.copy\", \"fs.delete\", \"fs.open\",!@#& \"io.open\", \"io.write\", \"io.read\", \"io.close\"},!@#& [\"Shutdown Computer\"] = {\"os.shutdown\", \"os.reboot\", \"shell.exit\"},!@#& [\"Use pcall\"] = {\"pcall\"},!@#&}!@#& !@#&local antivirusDestroy = {!@#& \"rawset\", \"rawget\", \"setfenv\", \"loadfile\", \"loadstring\", \"dofile\"!@#&}!@#& !@#&-- Graphical Function!@#&local function triggerAntivirus(offence, onlyCancel)!@#& local oldback, oldtext = curbackground, curtext!@#& !@#& local ox, oy = term.getCursorPos()!@#& openAddressBar = false!@#& term.setBackgroundColor(colors[theme[\"address-bar-background\"]])!@#& term.setTextColor(colors[theme[\"address-bar-text\"]])!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& write(\"Request: \" .. offence)!@#& local a = {{\"Allow\", w - 24, 1}, {\"Cancel\", w - 12, 1}}!@#& if onlyCancel == true then a = {{\"Cancel\", w - 12, 1}} end!@#& local opt = prompt(a, \"horizontal\")!@#& !@#& clearPage(website, nil, true)!@#& term.setTextColor(colors.white)!@#& term.setBackgroundColor(colors.black)!@#& term.setCursorPos(ox, oy)!@#& term.setBackgroundColor(oldback)!@#& term.setTextColor(oldtext)!@#& if opt == \"Allow\" then!@#& -- To prevent the menu bar from opening!@#& os.queueEvent(\"firewolf_requiredEvent\")!@#& os.pullEvent()!@#& !@#& openAddressBar = true!@#& return true!@#& elseif opt == \"Cancel\" then!@#& redirect(\"home\")!@#& end!@#&end!@#& !@#&-- Copy from override!@#&for k, v in pairs(override) do antivirus[k] = v end!@#& !@#&antivirus.shell = {}!@#&for k, v in pairs(override.shell) do antivirus.shell[k] = v end!@#&antivirus.os = {}!@#&for k, v in pairs(override.os) do antivirus.os[k] = v end!@#&antivirus.fs = {}!@#&for k, v in pairs(override.fs) do antivirus.fs[k] = v end!@#&antivirus.io = {}!@#&for k, v in pairs(override.io) do antivirus.io[k] = v end!@#& !@#&-- Override malicious functions!@#&for warning, v in pairs(antivirusOverrides) do!@#& for k, func in pairs(v) do!@#& if func:find(\".\", 1, true) then!@#& -- Functions in another table!@#& local table = func:sub(1, func:find(\".\", 1, true) - 1)!@#& local funcname = func:sub(func:find(\".\", 1, true) + 1, -1)!@#& !@#& antivirus[table][funcname] = function(...)!@#& env.setfenv(triggerAntivirus, env)!@#& if triggerAntivirus(warning) then!@#& return override[table][funcname](...)!@#& end!@#& end!@#& else!@#& -- Plain functions!@#& antivirus[func] = function(...)!@#& env.setfenv(triggerAntivirus, env)!@#& if triggerAntivirus(warning) then!@#& return override[func](...)!@#& end!@#& end!@#& end!@#& end!@#&end!@#& !@#&-- Override functions to destroy!@#&for k, v in pairs(antivirusDestroy) do!@#& antivirus[v] = function(...)!@#& env.setfenv(triggerAntivirus, env)!@#& triggerAntivirus(\"Destory your System! D:\", true)!@#& return nil!@#& end!@#&end!@#& !@#&antivirus.pcall = function(...)!@#& local suc, err = env.pcall(...)!@#& if err:lower():find(\"terminate\") then!@#& error(\"terminate\")!@#& elseif err:lower():find(event_exitWebsite) then!@#& error(event_exitWebsite)!@#& end!@#& !@#& return suc, err!@#&end!@#& !@#& !@#&-- -------- Graphics and Files!@#& !@#&graphics.githubImage = [[!@#&f f!@#&fffffffff!@#&fffffffff!@#&f4244424f!@#&f4444444f!@#&fffffefffe!@#& fffe e!@#& fffff e !@#&ff f fe e!@#& e e!@#&]]!@#& !@#&files.availableThemes = [[!@#&https://raw.github.com/1lann/firewolf/master/themes/default.txt| |Fire (default)!@#&https://raw.github.com/1lann/firewolf/master/themes/ice.txt| |Ice!@#&https://raw.github.com/1lann/firewolf/master/themes/carbon.txt| |Carbon!@#&https://raw.github.com/1lann/firewolf/master/themes/christmas.txt| |Christmas!@#&https://raw.github.com/1lann/firewolf/master/themes/original.txt| |Original!@#&https://raw.github.com/1lann/firewolf/master/themes/ocean.txt| |Ocean!@#&https://raw.github.com/1lann/firewolf/master/themes/forest.txt| |Forest!@#&https://raw.github.com/1lann/firewolf/master/themes/pinky.txt| |Pinky!@#&https://raw.github.com/1lann/firewolf/master/themes/azhftech.txt| |AzhfTech!@#&]]!@#& !@#&files.newTheme = [[!@#&-- Text color of the address bar!@#&address-bar-text=!@#& !@#&-- Background color of the address bar!@#&address-bar-background=!@#& !@#&-- Color of separator bar when live searching!@#&address-bar-base=!@#& !@#&-- Top box color!@#&top-box=!@#& !@#&-- Bottom box color!@#&bottom-box=!@#& !@#&-- Background color!@#&background=!@#& !@#&-- Main text color!@#&text-color=!@#& !@#&]]!@#& !@#& !@#&-- -------- Themes!@#& !@#&local defaultTheme = {[\"address-bar-text\"] = \"white\", [\"address-bar-background\"] = \"gray\",!@#& [\"address-bar-base\"] = \"lightGray\", [\"top-box\"] = \"red\", [\"bottom-box\"] = \"orange\",!@#& [\"text-color\"] = \"white\", [\"background\"] = \"gray\"}!@#&local originalTheme = {[\"address-bar-text\"] = \"white\", [\"address-bar-background\"] = \"black\",!@#& [\"address-bar-base\"] = \"black\", [\"top-box\"] = \"black\", [\"bottom-box\"] = \"black\",!@#& [\"text-color\"] = \"white\", [\"background\"] = \"black\"}!@#& !@#&local function loadTheme(path)!@#& if fs.exists(path) and not fs.isDir(path) then!@#& local a = {}!@#& local f = io.open(path, \"r\")!@#& local l = f:read(\"*l\")!@#& while l ~= nil do!@#& l = l:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& if l ~= \"\" and l ~= nil and l ~= \"\\n\" and l:sub(1, 2) ~= \"--\" then!@#& local b = l:find(\"=\")!@#& if a and b then!@#& local c = l:sub(1, b - 1)!@#& local d = l:sub(b + 1, -1)!@#& if c == \"\" or d == \"\" then return nil!@#& else a[c] = d end!@#& else return nil end!@#& end!@#& l = f:read(\"*l\")!@#& end!@#& f:close()!@#& !@#& return a!@#& end!@#&end!@#& !@#& !@#&-- -------- Filesystem and HTTP!@#& !@#&local function download(url, path)!@#& for i = 1, 3 do!@#& local response = http.get(url)!@#& if response then!@#& local data = response.readAll()!@#& response.close()!@#& if path then!@#& local f = io.open(path, \"w\")!@#& f:write(data)!@#& f:close()!@#& end!@#& return true!@#& end!@#& end!@#& !@#& return false !@#&end!@#& !@#&local function updateClient()!@#& local skipNormal = false!@#& if serverID ~= \"experimental\" then!@#& http.request(buildURL)!@#& local a = os.startTimer(10)!@#& while true do!@#& local e, url, handle = os.pullEvent()!@#& if e == \"http_success\" then!@#& if tonumber(handle.readAll()) > build then break!@#& else return false end!@#& elseif e == \"http_failure\" or (e == \"timer\" and url == a) then!@#& skipNormal = true!@#& break!@#& end!@#& end!@#& end!@#& !@#& local source = nil!@#& !@#& if not skipNormal then!@#& local _, y = term.getCursorPos()!@#& term.setCursorPos(1, y - 2)!@#& rightWrite(string.rep(\" \", 32))!@#& rightWrite(\"Updating Firewolf... \")!@#& !@#& http.request(firewolfURL)!@#& local a = os.startTimer(10)!@#& while true do!@#& local e, url, handle = os.pullEvent()!@#& if e == \"http_success\" then!@#& source = handle!@#& break!@#& elseif e == \"http_failure\" or (e == \"timer\" and url == a) then!@#& break!@#& end!@#& end!@#& end!@#& !@#& if not source then!@#& if isAdvanced() then!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& if not fs.exists(rootFolder) then fs.makeDir(rootFolder) end!@#& local f = io.open(rootFolder .. \"/temp_file\", \"w\")!@#& f:write(graphics.githubImage)!@#& f:close()!@#& local a = paintutils.loadImage(rootFolder .. \"/temp_file\")!@#& paintutils.drawImage(a, 5, 5)!@#& fs.delete(rootFolder .. \"/temp_file\")!@#& !@#& term.setCursorPos(19, 4)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& write(string.rep(\" \", 32))!@#& term.setCursorPos(19, 5)!@#& write(\" Could Not Connect to GitHub! \")!@#& term.setCursorPos(19, 6)!@#& write(string.rep(\" \", 32))!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& term.setCursorPos(19, 8)!@#& write(string.rep(\" \", 32))!@#& term.setCursorPos(19, 9)!@#& write(\" Sorry, Firewolf could not \")!@#& term.setCursorPos(19, 10)!@#& write(\" connect to GitHub to download \")!@#& term.setCursorPos(19, 11)!@#& write(\" necessary files. Please check: \")!@#& term.setCursorPos(19, 12)!@#& write(\" http://status.github.com \")!@#& term.setCursorPos(19, 13)!@#& write(string.rep(\" \", 32))!@#& term.setCursorPos(19, 14)!@#& write(\" Click to exit... \")!@#& term.setCursorPos(19, 15)!@#& write(string.rep(\" \", 32))!@#& else!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& print(\"\\n\")!@#& centerPrint(\"Could not connect to GitHub!\")!@#& print(\"\")!@#& centerPrint(\"Sorry, Firewolf could not connect to\")!@#& centerPrint(\"GitHub to download necessary files.\")!@#& centerPrint(\"Please check:\")!@#& centerPrint(\"http://status.github.com\")!@#& print(\"\")!@#& centerPrint(\"Press any key to exit...\")!@#& end!@#& !@#& while true do!@#& local e = oldpullevent()!@#& if e == \"mouse_click\" or e == \"key\" then break end!@#& end!@#& !@#& return false!@#& elseif source and autoupdate == \"true\" then!@#& local b = io.open(firewolfLocation, \"r\")!@#& local new = source.readAll()!@#& local cur = b:read(\"*a\")!@#& source.close()!@#& b:close()!@#& !@#& if cur ~= new then!@#& fs.delete(firewolfLocation)!@#& local f = io.open(firewolfLocation, \"w\")!@#& f:write(new)!@#& f:close()!@#& return true!@#& else!@#& return false!@#& end!@#& end!@#&end!@#& !@#&local function resetFilesystem()!@#& -- Migrate!@#& fs.delete(rootFolder .. \"/available_themes\")!@#& fs.delete(rootFolder .. \"/default_theme\")!@#& !@#& -- Reset!@#& if not fs.exists(rootFolder) then fs.makeDir(rootFolder)!@#& elseif not fs.isDir(rootFolder) then fs.move(rootFolder, \"/Firewolf_Data.old\") end!@#& !@#& if not fs.isDir(serverFolder) then fs.delete(serverFolder) end!@#& if not fs.exists(serverFolder) then fs.makeDir(serverFolder) end!@#& if not fs.isDir(cacheFolder) then fs.delete(cacheFolder) end!@#& if not fs.exists(cacheFolder) then fs.makeDir(cacheFolder) end!@#& if not fs.isDir(websiteDataFolder) then fs.delete(websiteDataFolder) end!@#& if not fs.exists(websiteDataFolder) then fs.makeDir(websiteDataFolder) end!@#& !@#& if fs.isDir(settingsLocation) then fs.delete(settingsLocation) end!@#& if fs.isDir(serverLocation) then fs.delete(serverLocation) end!@#& !@#& if not fs.exists(settingsLocation) then!@#& local f = io.open(settingsLocation, \"w\")!@#& f:write(textutils.serialize({auto = \"true\", incog = \"false\", home = \"firewolf\"}))!@#& f:close()!@#& end!@#& !@#& if not fs.exists(serverLocation) then!@#& download(serverURL, serverLocation)!@#& end!@#& !@#& fs.delete(rootFolder .. \"/temp_file\")!@#& !@#& for _, v in pairs({userWhitelist, userBlacklist}) do!@#& if fs.isDir(v) then fs.delete(v) end!@#& if not fs.exists(v) then!@#& local f = io.open(v, \"w\")!@#& f:write(\"\")!@#& f:close()!@#& end!@#& end!@#&end!@#& !@#&local function checkForModem(display)!@#& while true do!@#& local present = false!@#& for _, v in pairs(rs.getSides()) do!@#& if peripheral.getType(v) == \"modem\" then!@#& rednet.open(v)!@#& present = true!@#& break!@#& end!@#& end!@#& !@#& if not present and type(display) == \"function\" then!@#& display()!@#& os.pullEvent(\"peripheral\")!@#& else!@#& return true!@#& end!@#& end!@#&end!@#& !@#& !@#&-- -------- Databases!@#& !@#&local function loadDatabases()!@#& -- Blacklist!@#& if fs.exists(userBlacklist) and not fs.isDir(userBlacklist) then!@#& local bf = io.open(userBlacklist, \"r\")!@#& local l = bf:read(\"*l\")!@#& while l ~= nil do!@#& if l ~= nil and l ~= \"\" and l ~= \"\\n\" then!@#& l = l:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& table.insert(blacklist, l)!@#& end!@#& l = bf:read(\"*l\")!@#& end!@#& bf:close()!@#& end!@#& !@#& -- Whitelist!@#& if fs.exists(userWhitelist) and not fs.isDir(userWhitelist) then!@#& local wf = io.open(userWhitelist, \"r\")!@#& local l = wf:read(\"*l\")!@#& while l ~= nil do!@#& if l ~= nil and l ~= \"\" and l ~= \"\\n\" then!@#& l = l:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& local a, b = l:find(\"| |\")!@#& table.insert(whitelist, {l:sub(1, a - 1), l:sub(b + 1, -1)})!@#& end!@#& l = wf:read(\"*l\")!@#& end!@#& wf:close()!@#& end!@#&end!@#& !@#&local function verifyBlacklist(id)!@#& for _, v in pairs(blacklist) do!@#& if tostring(id) == v then return true end!@#& end!@#& return false!@#&end!@#& !@#&local function verifyWhitelist(id, url)!@#& for _, v in pairs(whitelist) do!@#& if v[2] == tostring(args[1]) and v[1] == tostring(args[2]) then!@#& return true!@#& end!@#& end!@#& return false!@#&end!@#& !@#& !@#&-- -------- Protocols!@#& !@#&protocols.rdnt = {}!@#&protocols.http = {}!@#& !@#&protocols.rdnt.getSearchResults = function()!@#& dnsDatabase = {[1] = {}, [2] = {}}!@#& local resultIDs = {}!@#& local conflict = {}!@#& !@#& rednet.broadcast(\"firewolf.broadcast.dns.list\")!@#& local startClock = os.clock()!@#& while os.clock() - startClock < timeout do!@#& local id, i = rednet.receive(timeout)!@#& if id then!@#& if i:sub(1, 14) == \"firewolf-site:\" then!@#& i = i:sub(15, -1)!@#& local bl, wl = verifyBlacklist(id), verifyWhitelist(id, i)!@#& if not i:find(\" \") and i:len() < 40 and (not bl or (bl and wl)) then!@#& if not resultIDs[tostring(id)] then resultIDs[tostring(id)] = 1!@#& else resultIDs[tostring(id)] = resultIDs[tostring(id)] + 1!@#& end!@#& !@#& if not i:find(\"rdnt://\") then i = (\"rdnt://\" .. i) end!@#& local x = false!@#& if conflict[i] then!@#& x = true!@#& table.insert(conflict[i], id)!@#& else!@#& for m, n in pairs(dnsDatabase[1]) do!@#& if n:lower() == i:lower() then!@#& x = true!@#& table.remove(dnsDatabase[1], m)!@#& table.remove(dnsDatabase[2], m)!@#& if conflict[i] then!@#& table.insert(conflict[i], id)!@#& else!@#& conflict[i] = {}!@#& table.insert(conflict[i], id)!@#& end!@#& break!@#& end!@#& end!@#& end!@#& !@#& if not x and resultIDs[tostring(id)] <= 3 then!@#& table.insert(dnsDatabase[1], i)!@#& table.insert(dnsDatabase[2], id)!@#& end!@#& end!@#& end!@#& else!@#& break!@#& end!@#& end!@#& for k,v in pairs(conflict) do!@#& table.sort(v)!@#& table.insert(dnsDatabase[1], k)!@#& table.insert(dnsDatabase[2], v[1])!@#& end!@#& !@#& return dnsDatabase[1]!@#&end!@#& !@#&protocols.rdnt.getWebsite = function(site)!@#& local id, content, status = nil, nil, nil!@#& local clock = os.clock()!@#& local websiteID = nil!@#& for k, v in pairs(dnsDatabase[1]) do!@#& local web = site:gsub(\"rdnt://\", \"\")!@#& if web:find(\"/\") then web = web:sub(1, web:find(\"/\") - 1) end!@#& if web == v:gsub(\"rdnt://\", \"\") then!@#& websiteID = dnsDatabase[2][k]!@#& break!@#& end!@#& end!@#& if not websiteID then return nil, nil, nil end!@#& !@#& sleep(timeout)!@#& rednet.send(websiteID, site)!@#& clock = os.clock()!@#& while os.clock() - clock < timeout do!@#& id, content = rednet.receive(timeout)!@#& if id then!@#& if id == websiteID then!@#& local bl = verifyBlacklist(id)!@#& local wl = verifyWhitelist(id, site)!@#& status = nil!@#& if (bl and not wl) or site == \"\" or site == \".\" or site == \"..\" then!@#& -- Ignore!@#& elseif wl then!@#& status = \"whitelist\"!@#& break!@#& else!@#& status = \"safe\"!@#& break!@#& end!@#& end!@#& end!@#& end!@#& !@#& return id, content, status!@#&end!@#& !@#&protocols.http.getSearchResults = function()!@#& dnsDatabase = {[1] = {}, [2] = {}}!@#& return dnsDatabase[1]!@#&end!@#& !@#&protocols.http.getWebsite = function()!@#& return nil, nil, nil!@#&end!@#& !@#& !@#&-- -------- Homepage!@#& !@#&pages[\"firewolf\"] = function(site)!@#& openAddressBar = true!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 42))!@#& leftPrint([[ _,-='\"-.__ /\\_/\\ ]])!@#& leftPrint([[ -.} =._,.-==-._., @ @._, ]])!@#& leftPrint([[ -.__ __,-. ) _,.-' ]])!@#& leftPrint([[ Firewolf ]] .. version .. string.rep(\" \", 8 - version:len()) ..!@#& [[\" G..m-\"^m m' ]])!@#& leftPrint(string.rep(\" \", 42))!@#& print(\"\\n\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 42))!@#& if isAdvanced() then rightPrint(\" News: [- Sites -] \")!@#& else rightPrint(\" News: \") end!@#& rightPrint(\" Firewolf 2.4 is out! It cuts out 1500 \")!@#& rightPrint(\" lines, and contains many improvements! \")!@#& rightPrint(string.rep(\" \", 42))!@#& rightPrint(\" Firewolf 3.0 will be out soon! It will \")!@#& rightPrint(\" bring the long awaited HTTP support! \")!@#& rightPrint(string.rep(\" \", 42))!@#& !@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if isAdvanced() and e == \"mouse_click\" and x >= 40 and x <= 50 and y == 11 then!@#& redirect(\"firewolf/sites\")!@#& end!@#& end!@#&end!@#& !@#&pages[\"firefox\"] = function(site) redirect(\"firewolf\") end!@#& !@#&pages[\"firewolf/sites\"] = function(site)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\\n\")!@#& leftPrint(string.rep(\" \", 17))!@#& leftPrint(\" Built-In Sites \")!@#& leftPrint(string.rep(\" \", 17))!@#& !@#& local sx = 8!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& term.setCursorPos(1, sx)!@#& rightPrint(string.rep(\" \", 40))!@#& rightPrint(\" rdnt://firewolf Homepage \")!@#& rightPrint(\" rdnt://firewolf/sites Sites \")!@#& rightPrint(\" rdnt://server Server Management \")!@#& rightPrint(\" rdnt://help Help Page \")!@#& rightPrint(\" rdnt://settings Settings \")!@#& rightPrint(\" rdnt://credits Credits \")!@#& rightPrint(\" rdnt://exit Exit \")!@#& rightPrint(string.rep(\" \", 40))!@#& !@#& local a = {\"firewolf\", \"firewolf/sites\", \"server\", \"help\", \"settings\", \"credits\", \"exit\"}!@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if isAdvanced() and e == \"mouse_click\" and x >= 14 and x <= 50 then!@#& for i, v in ipairs(a) do!@#& if y == sx + i then!@#& if v == \"exit\" then return true end!@#& redirect(v)!@#& end!@#& end!@#& end!@#& end!@#&end!@#& !@#&pages[\"sites\"] = function(site) redirect(\"firewolf/sites\") end!@#& !@#& !@#&-- -------- Server Management!@#& !@#&local function manageServers(site, protocol, functionList, startServerName)!@#& local servers = functionList[\"reload servers\"]()!@#& local sy = 7!@#& !@#& if startServerName == nil then startServerName = \"Start\" end!@#& if isAdvanced() then!@#& local function draw(l, sel)!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& term.setCursorPos(4, sy)!@#& write(\"[- New Server -]\")!@#& for i, v in ipairs(l) do!@#& term.setCursorPos(3, i + sy)!@#& write(string.rep(\" \", 24))!@#& term.setCursorPos(4, i + sy)!@#& local nv = v!@#& if nv:len() > 18 then nv = nv:sub(1, 15) .. \"...\" end!@#& if i == sel then write(\"[ \" .. nv .. \" ]\")!@#& else write(\" \" .. nv) end!@#& end!@#& if #l < 1 then!@#& term.setCursorPos(4, sy + 2)!@#& write(\"A website is literally\")!@#& term.setCursorPos(4, sy + 3)!@#& write(\"just a lua script!\")!@#& term.setCursorPos(4, sy + 4)!@#& write(\"Go ahead and make one!\")!@#& term.setCursorPos(4, sy + 6)!@#& write(\"Also, be sure to check\")!@#& term.setCursorPos(4, sy + 7)!@#& write(\"out Firewolf's APIs to\")!@#& term.setCursorPos(4, sy + 8)!@#& write(\"help you make your\")!@#& term.setCursorPos(4, sy + 9)!@#& write(\"site, at rdnt://help\")!@#& end!@#& !@#& term.setCursorPos(30, sy)!@#& write(string.rep(\" \", 19))!@#& term.setCursorPos(30, sy)!@#& if l[sel] then!@#& local nl = l[sel]!@#& if nl:len() > 19 then nl = nl:sub(1, 16) .. \"...\" end!@#& write(nl)!@#& else write(\"No Server Selected!\") end!@#& term.setCursorPos(30, sy + 2)!@#& write(\"[- \" .. startServerName .. \" -]\")!@#& term.setCursorPos(30, sy + 4)!@#& write(\"[- Edit -]\")!@#& term.setCursorPos(30, sy + 6)!@#& if functionList[\"run on boot\"] then write(\"[- Run on Boot -]\") end!@#& term.setCursorPos(30, sy + 8)!@#& write(\"[- Delete -]\")!@#& end!@#& !@#& local function updateDisplayList(items, loc, len)!@#& local ret = {}!@#& for i = 1, len do!@#& if items[i + loc - 1] then table.insert(ret, items[i + loc - 1]) end!@#& end!@#& return ret!@#& end!@#& !@#& while true do!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 27))!@#& leftPrint(\" Server Management - \" .. protocol:upper() .. \" \")!@#& leftPrint(string.rep(\" \", 27))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 12 do!@#& term.setCursorPos(3, i + sy - 2)!@#& write(string.rep(\" \", 24))!@#& term.setCursorPos(29, i + sy - 2)!@#& write(string.rep(\" \", 21))!@#& end!@#& !@#& local sel = 1!@#& local loc = 1!@#& local len = 10!@#& local disList = updateDisplayList(servers, loc, len)!@#& draw(disList, sel)!@#& !@#& while true do!@#& local e, but, x, y = os.pullEvent()!@#& if e == \"key\" and but == 200 and #servers > 0 and loc > 1 then!@#& loc = loc - 1!@#& disList = updateDisplayList(servers, loc, len)!@#& draw(disList, sel)!@#& elseif e == \"key\" and but == 208 and #servers > 0 and loc + len - 1 < #servers then!@#& loc = loc + 1!@#& disList = updateDisplayList(servers, loc, len)!@#& draw(disList, sel)!@#& elseif e == \"mouse_click\" then!@#& if x >= 4 and x <= 25 then!@#& if y == 7 then!@#& functionList[\"new server\"]()!@#& servers = functionList[\"reload servers\"]()!@#& break!@#& elseif #servers > 0 then!@#& for i, v in ipairs(disList) do!@#& if y == i + 7 then!@#& sel = i!@#& draw(disList, sel)!@#& end!@#& end!@#& end!@#& elseif x >= 30 and x <= 40 and y == 9 and #servers > 0 then!@#& functionList[\"start\"](disList[sel])!@#& servers = functionList[\"reload servers\"]()!@#& break!@#& elseif x >= 30 and x <= 39 and y == 11 and #servers > 0 then!@#& functionList[\"edit\"](disList[sel])!@#& servers = functionList[\"reload servers\"]()!@#& break!@#& elseif x >= 30 and x <= 46 and y == 13 and #servers > 0 and!@#& functionList[\"run on boot\"] then!@#& functionList[\"run on boot\"](disList[sel])!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& term.setCursorPos(32, 15)!@#& write(\"Will Run on Boot!\")!@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& term.setCursorPos(32, 15)!@#& write(string.rep(\" \", 18))!@#& break!@#& elseif x >= 30 and x <= 41 and y == 15 and #servers > 0 then!@#& functionList[\"delete\"](disList[sel])!@#& servers = functionList[\"reload servers\"]()!@#& break!@#& end!@#& end!@#& end!@#& end!@#& else!@#& while true do!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& centerPrint(string.rep(\" \", 27))!@#& centerPrint(\" Server Management - \" .. protocol:upper() .. \" \")!@#& centerPrint(string.rep(\" \", 27))!@#& print(\"\")!@#& !@#& local a = {\"New Server\"}!@#& for _, v in pairs(servers) do table.insert(a, v) end!@#& local server = scrollingPrompt(a, 4, 7, 10)!@#& if server == \"New Server\" then!@#& functionList[\"new server\"]()!@#& servers = functionList[\"reload servers\"]()!@#& else!@#& term.setCursorPos(30, 8)!@#& write(server)!@#& local a = {{\"Start\", 30, 9}, {\"Edit\", 30, 11}, {\"Run on Boot\", 30, 12},!@#& {\"Delete\", 30, 13}, {\"Back\", 30, 15}}!@#& if not functionList[\"run on boot\"] then!@#& a = {{\"Start\", 30, 9}, {\"Edit\", 30, 11}, {\"Delete\", 30, 13}, {\"Back\", 30, 15}}!@#& end!@#& local opt = prompt(a, \"vertical\")!@#& if opt == \"Start\" then!@#& functionList[\"start\"](server)!@#& servers = functionList[\"reload servers\"]()!@#& elseif opt == \"Edit\" then!@#& functionList[\"edit\"](server)!@#& servers = functionList[\"reload servers\"](server)!@#& elseif opt == \"Run on Boot\" and functionList[\"run on boot\"] then!@#& functionList[\"run on boot\"](server)!@#& term.setCursorPos(32, 16)!@#& write(\"Will Run on Boot!\")!@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& elseif opt == \"Delete\" then!@#& functionList[\"delete\"](server)!@#& servers = functionList[\"reload servers\"]()!@#& end!@#& end!@#& end!@#& end!@#&end!@#& !@#&local function editPages(dir)!@#& local oldLoc = shell.dir()!@#& local commandHis = {}!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"\")!@#& print(\" Server Shell Editing\")!@#& print(\" Type 'exit' to return to Firewolf.\")!@#& print(\" The 'home' file is the index of your site.\")!@#& print(\"\")!@#& !@#& local allowed = {\"move\", \"mv\", \"cp\", \"copy\", \"drive\", \"delete\", \"rm\", \"edit\",!@#& \"eject\", \"exit\", \"help\", \"id\", \"monitor\", \"rename\", \"alias\", \"clear\",!@#& \"paint\", \"firewolf\", \"lua\", \"redstone\", \"rs\", \"redprobe\", \"redpulse\", \"programs\",!@#& \"redset\", \"reboot\", \"hello\", \"label\", \"list\", \"ls\", \"easter\", \"pastebin\", \"dir\"}!@#& !@#& while true do!@#& shell.setDir(dir)!@#& term.setBackgroundColor(colors.black)!@#& if isAdvanced() then term.setTextColor(colors.yellow)!@#& else term.setTextColor(colors.white) end!@#& write(\"> \")!@#& term.setTextColor(colors.white)!@#& local line = read(nil, commandHis)!@#& table.insert(commandHis, line)!@#& !@#& local words = {}!@#& for m in string.gmatch(line, \"[^ \\t]+\") do!@#& local a = m:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& table.insert(words, a)!@#& end!@#& !@#& local com = words[1]!@#& if com == \"exit\" then!@#& break!@#& elseif com then!@#& local a = false!@#& for _, v in pairs(allowed) do!@#& if com == v then a = true break end!@#& end!@#& !@#& if a then!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& shell.run(com, unpack(words, 2))!@#& else!@#& term.setTextColor(colors.red)!@#& print(\"Program Not Allowed!\")!@#& end!@#& end!@#& end!@#& shell.setDir(oldLoc)!@#&end!@#& !@#&local function newServer(onCreate)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& for i = 1, 12 do!@#& term.setCursorPos(3, i + 5)!@#& term.clearLine()!@#& end!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& term.setCursorPos(1, 7)!@#& for i = 1, 8 do centerPrint(string.rep(\" \", 47)) end!@#& term.setCursorPos(5, 8)!@#& write(\"Name: \")!@#& local name = modRead({refusePrint = \"`\", visibleLength = w - 4, textLength = 200})!@#& term.setCursorPos(5, 10)!@#& write(\"URL:\")!@#& term.setCursorPos(8, 11)!@#& write(\"rdnt://\")!@#& local url = modRead({grantPrint = \"abcdefghijklmnopqrstuvwxyz1234567890-_.+\",!@#& visibleLength = w - 4, textLength = 200})!@#& url = url:gsub(\" \", \"\")!@#& if name == \"\" or url == \"\" then!@#& term.setCursorPos(5, 13)!@#& write(\"URL or Name is Empty!\")!@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& else!@#& local c = onCreate(name, url)!@#& !@#& term.setCursorPos(5, 13)!@#& if c and c == \"true\" then!@#& write(\"Successfully Created Server!\")!@#& elseif c == \"false\" or c == nil then!@#& write(\"Server Creation Failed!\")!@#& else!@#& write(c)!@#& end!@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& end!@#&end!@#& !@#&pages[\"server/rdnt\"] = function(site)!@#& manageServers(site, \"rdnt\", {[\"reload servers\"] = function()!@#& local servers = {}!@#& for _, v in pairs(fs.list(serverFolder)) do!@#& if fs.isDir(serverFolder .. \"/\" .. v) then table.insert(servers, v) end!@#& end!@#& !@#& return servers!@#& end, [\"new server\"] = function()!@#& newServer(function(name, url)!@#& if fs.exists(serverFolder .. \"/\" .. url) then!@#& return \"Server Already Exists!\"!@#& end!@#& !@#& fs.makeDir(serverFolder .. \"/\" .. url)!@#& local f = io.open(serverFolder .. \"/\" .. url .. \"/home\", \"w\")!@#& f:write(\"print(\\\"\\\")\\ncenterPrint(\\\"Welcome To \" .. name .. \"!\\\")\\n\\n\")!@#& f:close()!@#& return \"true\"!@#& end)!@#& end, [\"start\"] = function(server)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& openAddressBar = false!@#& setfenv(1, oldEnv)!@#& shell.run(serverLocation, server, serverFolder .. \"/\" .. server)!@#& setfenv(1, override)!@#& openAddressBar = true!@#& checkForModem()!@#& end, [\"edit\"] = function(server)!@#& openAddressBar = false!@#& editPages(serverFolder .. \"/\" .. server)!@#& openAddressBar = true!@#& if not fs.exists(serverFolder .. \"/\" .. server .. \"/home\") then!@#& local f = io.open(serverFolder .. \"/\" .. server .. \"/home\", \"w\")!@#& f:write(\"print(\\\"\\\")\\ncenterPrint(\\\"Welcome To \" .. server .. \"!\\\")\\n\\n\")!@#& f:close()!@#& end!@#& end, [\"run on boot\"] = function(server)!@#& fs.delete(\"/old-startup\")!@#& if fs.exists(\"/startup\") then fs.move(\"/startup\", \"/old-startup\") end!@#& local f = io.open(\"/startup\", \"w\")!@#& f:write(\"shell.run(\\\"\" .. serverLocation .. \"\\\", \\\"\" .. server .. \"\\\", \\\"\" ..!@#& serverFolder .. \"/\" .. server .. \"\\\")\")!@#& f:close()!@#& end, [\"delete\"] = function(server)!@#& fs.delete(serverFolder .. \"/\" .. server)!@#& end})!@#&end!@#& !@#&pages[\"server/http\"] = function(site)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& print(\"\\n\\n\")!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& centerPrint(string.rep(\" \", 17))!@#& centerPrint(\" Comming Soon! \")!@#& centerPrint(string.rep(\" \", 17))!@#&end!@#& !@#&pages[\"server\"] = function(site)!@#& setfenv(manageServers, override)!@#& setfenv(newServer, override)!@#& setfenv(editPages, env)!@#& if curProtocol == protocols.rdnt then redirect(\"server/rdnt\")!@#& elseif curProtocol == protocols.http then redirect(\"server/http\") end!@#&end!@#& !@#& !@#&-- -------- Help!@#& !@#&pages[\"help\"] = function(site)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 16))!@#& leftPrint(\" Firewolf Help \")!@#& leftPrint(string.rep(\" \", 16))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 12 do rightPrint(string.rep(\" \", 41)) end!@#& term.setCursorPos(1, 15)!@#& rightPrint(\" View the full documentation here: \")!@#& rightPrint(\" https://github.com/1lann/Firewolf/wiki \")!@#& !@#& local opt = prompt({{\"Getting Started\", w - 21, 8}, {\"Making a Theme\", w - 20, 10},!@#& {\"API Documentation\", w - 23, 12}}, \"vertical\")!@#& local pages = {}!@#& if opt == \"Getting Started\" then!@#& pages[1] = {title = \"Getting Started - Intoduction\", content = {!@#& \"Hey there!\",!@#& \"\",!@#& \"Firewolf is an app that allows you to create\",!@#& \"and visit websites! Each site has an address\",!@#& \"(the URL) which you can type into the address\",!@#& \"bar above, and then visit the site.\",!@#& \"\",!@#& \"You can open the address bar by clicking on\",!@#& \"it, or by pressing control.\"!@#& }} pages[2] = {title = \"Getting Started - Searching\", content = {!@#& \"The address bar can be also be used to\",!@#& \"search for sites, by simply typing in the\",!@#& \"search term.\",!@#& \"\",!@#& \"To view all sites, just open it and hit\",!@#& \"enter (leave the field blank).\"!@#& }} pages[3] = {title = \"Getting Started - Built-In Websites\", content = {!@#& \"Firewolf has a set of built-in websites\",!@#& \"available for use:\",!@#& \"\",!@#& \"rdnt://firewolf Normal hompage\",!@#& \"rdnt://sites Built-In Site\",!@#& \"rdnt://server Create websites\",!@#& \"rdnt://help Help and documentation\"!@#& }} pages[4] = {title = \"Getting Started - Built-In Websites\", content = {!@#& \"More built-in websites:\",!@#& \"\",!@#& \"rdnt://settings Firewolf settings\",!@#& \"rdnt://credits View the credits\",!@#& \"rdnt://exit Exit the app\"!@#& }}!@#& elseif opt == \"Making a Theme\" then!@#& pages[1] = {title = \"Making a Theme - Introduction\", content = {!@#& \"Firewolf themes are files that tell Firewolf\",!@#& \"to color which things what.\",!@#& \"Several themes can already be downloaded for\",!@#& \"Firewolf from rdnt://settings/themes.\",!@#& \"\",!@#& \"You can also make your own theme, use it in\",!@#& \"your copy of Firewolf.Your theme can also be\",!@#& \"submitted it to the themes list!\"!@#& }} pages[2] = {title = \"Making a Theme - Example\", content = {!@#& \"A theme file consists of several lines of\",!@#& \"text. Here is the default theme file:\",!@#& \"address-bar-text=white\",!@#& \"address-bar-background=gray\",!@#& \"address-bar-base=lightGray\",!@#& \"top-box=red\",!@#& \"bottom-box=orange\",!@#& \"background=gray\",!@#& \"text-color=white\"!@#& }} pages[3] = {title = \"Making a Theme - Explanation\", content = {!@#& \"On each line of the example, something is\",!@#& \"given a color, like on the last line, the\",!@#& \"text of the page is told to be white.\",!@#& \"\",!@#& \"The color specified after the = is the same\",!@#& \"as when you call colors.[color name].\",!@#& \"For example, specifying 'red' after the =\",!@#& \"colors that object red.\"!@#& }} pages[4] = {title = \"Making a Theme - Have a Go\", content = {!@#& \"Themes can be made at rdnt://settings/themes,\",!@#& \"click on 'Change Theme' button, and click on\",!@#& \"'New Theme'.\",!@#& \"\",!@#& \"Enter a theme name, then exit Firewolf and\",!@#& \"edit the newly created file\",!@#& \"Specify the colors for each of the keys,\",!@#& \"and return to the themes section of the\",!@#& \"downloads center. Click 'Load Theme'.\"!@#& }} pages[5] = {title = \"Making a Theme - Submitting\", content = {!@#& \"To submit a theme to the theme list,\",!@#& \"send GravityScore a message on the CCForums\",!@#& \"that contains your theme file and name.\",!@#& \"\",!@#& \"He will message you back saying whether your\",!@#& \"theme has been added, or if anything needs to\",!@#& \"be changed before it is added.\"!@#& }}!@#& elseif opt == \"API Documentation\" then!@#& pages[1] = {title = \"API Documentation - 1\", content = {!@#& \"The Firewolf API is a bunch of global\",!@#& \"functions that aim to simplify your life when\",!@#& \"designing and coding websites.\",!@#& \"\",!@#& \"For a full documentation on these functions,\",!@#& \"visit the Firewolf Wiki Page here:\",!@#& \"https://github.com/1lann/Firewolf/wiki\"!@#& }} pages[2] = {title = \"API Documentation - 2\", content = {!@#& \"centerPrint(string text)\",!@#& \"cPrint(string text)\",!@#& \"centerWrite(string text)\",!@#& \"cWrite(string text)\",!@#& \"\",!@#& \"leftPrint(string text)\",!@#& \"lPrint(string text)\",!@#& }} pages[3] = {title = \"API Documentation - 3\", content = {!@#& \"leftWrite(string text)\",!@#& \"lWrite(string text)\",!@#& \"\",!@#& \"rightPrint(string text)\",!@#& \"rPrint(string text)\",!@#& \"rightWrite(string text)\",!@#& \"rWrite(string text)\"!@#& }} pages[4] = {title = \"API Documentation - 4\", content = {!@#& \"prompt(table list, string direction)\",!@#& \"scrollingPrompt(table list, integer x,\",!@#& \" integer y, integer length[,\",!@#& \" integer width])\",!@#& \"\",!@#& \"urlDownload(string url)\",!@#& \"pastebinDownload(string code)\",!@#& \"redirect(string site)\",!@#& }} pages[5] = {title = \"API Documentation - 5\", content = {!@#& \"loadImageFromServer(string imagePath)\",!@#& \"ioReadFileFromServer(string filePath)\",!@#& \"fileFileFromServer(string filePath)\",!@#& \"saveFileToUserComputer(string content)\",!@#& \"\",!@#& \"writeDataFile(string path, string contents)\",!@#& \"readDataFile(string path)\"!@#& }}!@#& end!@#& !@#& local function drawPage(page)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", page.title:len() + 3))!@#& leftPrint(\" \" .. page.title .. \" \")!@#& leftPrint(string.rep(\" \", page.title:len() + 3))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 12 do print(string.rep(\" \", w)) end!@#& for i, v in ipairs(page.content) do!@#& term.setCursorPos(4, i + 7)!@#& write(v)!@#& end!@#& end!@#& !@#& local curPage = 1!@#& local a = {{\"Prev\", 26, 17}, {\"Next\", 38, 17}, {\"Back\", 14, 17}}!@#& drawPage(pages[curPage])!@#& !@#& while true do!@#& local b = {a[3]}!@#& if curPage == 1 then table.insert(b, a[2])!@#& elseif curPage == #pages then table.insert(b, a[1])!@#& else table.insert(b, a[1]) table.insert(b, a[2]) end!@#& !@#& local opt = prompt(b, \"horizontal\")!@#& if opt == \"Prev\" then!@#& curPage = curPage - 1!@#& elseif opt == \"Next\" then!@#& curPage = curPage + 1!@#& elseif opt == \"Back\" then!@#& break!@#& end!@#& !@#& drawPage(pages[curPage])!@#& end!@#& !@#& redirect(\"help\")!@#&end!@#& !@#& !@#&-- -------- Settings!@#& !@#&pages[\"settings/themes\"] = function(site)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 17))!@#& leftPrint(\" Theme Settings \")!@#& leftPrint(string.rep(\" \", 17))!@#& print(\"\")!@#& !@#& if isAdvanced() then!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 12 do rightPrint(string.rep(\" \", 36)) end!@#& !@#& local themes = {}!@#& local themenames = {\"Back\", \"New Theme\", \"Load Theme\"}!@#& local f = io.open(rootFolder .. \"/temp_file\", \"w\")!@#& f:write(files.availableThemes)!@#& f:close()!@#& local f = io.open(rootFolder .. \"/temp_file\", \"r\")!@#& local l = f:read(\"*l\")!@#& while l do!@#& l = l:gsub(\"^%s*(.-)%s*$\", \"%1\")!@#& local a, b = l:find(\"| |\")!@#& table.insert(themenames, l:sub(b + 1, -1))!@#& table.insert(themes, {name = l:sub(b + 1, -1), url = l:sub(1, a - 1)})!@#& l = f:read(\"*l\")!@#& end!@#& f:close()!@#& fs.delete(rootFolder .. \"/temp_file\")!@#& !@#& local t = scrollingPrompt(themenames, w - 33, 7, 10, 32)!@#& if t == \"Back\" then!@#& redirect(\"settings\")!@#& elseif t == \"New Theme\" then!@#& term.setCursorPos(w - 33, 17)!@#& write(\"Path: /\")!@#& local n = modRead({visibleLength = w - 2, textLength = 100})!@#& if n ~= \"\" and n ~= nil then!@#& n = \"/\" .. n!@#& local f = io.open(n, \"w\")!@#& f:write(files.newTheme)!@#& f:close()!@#& !@#& term.setCursorPos(1, 17)!@#& rightWrite(string.rep(\" \", 36))!@#& term.setCursorPos(1, 17)!@#& rightWrite(\"File Created! \")!@#& openAddressBar = false!@#& sleep(1.1)!@#& openAddressBar = true!@#& end!@#& elseif t == \"Load Theme\" then!@#& term.setCursorPos(w - 33, 17)!@#& write(\"Path: /\")!@#& local n = modRead({visibleLength = w - 2, textLength = 100})!@#& if n ~= \"\" and n ~= nil then!@#& n = \"/\" .. n!@#& term.setCursorPos(1, 17)!@#& rightWrite(string.rep(\" \", 36))!@#& !@#& term.setCursorPos(1, 17)!@#& if fs.exists(n) and not fs.isDir(n) then!@#& local a = loadTheme(n)!@#& if a ~= nil then!@#& fs.delete(themeLocation)!@#& fs.copy(n, themeLocation)!@#& theme = a!@#& rightWrite(\"Theme File Loaded! :D \")!@#& else!@#& rightWrite(\"Theme File is Corrupt! D: \")!@#& end!@#& elseif not fs.exists(n) then!@#& rightWrite(\"File does not exist! \")!@#& elseif fs.isDir(n) then!@#& rightWrite(\"File is a directory! \")!@#& end!@#& !@#& openAddressBar = false!@#& sleep(1.1)!@#& openAddressBar = true!@#& end!@#& else!@#& local url = \"\"!@#& for _, v in pairs(themes) do if v.name == t then url = v.url break end end!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& term.setCursorPos(1, 3)!@#& leftWrite(string.rep(\" \", 17))!@#& leftWrite(\" Downloading... \")!@#& !@#& fs.delete(rootFolder .. \"/temp_file\")!@#& download(url, rootFolder .. \"/temp_file\")!@#& local th = loadTheme(rootFolder .. \"/temp_file\")!@#& if th == nil then!@#& term.setCursorPos(1, 3)!@#& leftWrite(string.rep(\" \", 17))!@#& leftWrite(\" Theme Corrupt! \")!@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& !@#& fs.delete(rootFolder .. \"/temp_file\")!@#& else!@#& term.setCursorPos(1, 3)!@#& leftWrite(string.rep(\" \", 17))!@#& leftWrite(\" Theme Loaded! \")!@#& openAddressBar = false!@#& sleep(1.3)!@#& openAddressBar = true!@#& !@#& fs.delete(themeLocation)!@#& fs.move(rootFolder .. \"/temp_file\", themeLocation)!@#& theme = th!@#& redirect(\"home\")!@#& end!@#& end!@#& else!@#& print(\"\")!@#& rightPrint(string.rep(\" \", 30))!@#& rightPrint(\" Themes are not available on \")!@#& rightPrint(\" normal computers! :( \")!@#& rightPrint(string.rep(\" \", 30))!@#& end!@#&end!@#& !@#&pages[\"downloads\"] = function(site) redirect(\"settings/themes\") end!@#& !@#&pages[\"settings\"] = function(site)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 17 + serverList[serverID]:len()))!@#& leftPrint(\" Firewolf Settings \" .. string.rep(\" \", serverList[serverID]:len() - 3))!@#& leftPrint(\" Designed For: \" .. serverList[serverID] .. \" \")!@#& leftPrint(string.rep(\" \", 17 + serverList[serverID]:len()))!@#& print(\"\\n\")!@#& !@#& local a = \"Automatic Updating - On\"!@#& if autoupdate == \"false\" then a = \"Automatic Updating - Off\" end!@#& local b = \"Home - rdnt://\" .. homepage!@#& if b:len() >= 28 then b = b:sub(1, 24) .. \"...\" end!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 9 do rightPrint(string.rep(\" \", 36)) end!@#& local c = {{a, w - a:len() - 6, 9}, {\"Change Theme\", w - 18, 11}, {b, w - b:len() - 6, 13},!@#& {\"Reset Firewolf\", w - 20, 15}}!@#& if not isAdvanced() then!@#& c = {{a, w - a:len(), 9}, {b, w - b:len(), 11}, {\"Reset Firewolf\", w - 14, 13}}!@#& end!@#& !@#& local opt = prompt(c, \"vertical\")!@#& if opt == a then!@#& if autoupdate == \"true\" then autoupdate = \"false\"!@#& elseif autoupdate == \"false\" then autoupdate = \"true\" end!@#& elseif opt == \"Change Theme\" and isAdvanced() then!@#& redirect(\"settings/themes\")!@#& elseif opt == b then!@#& if isAdvanced() then term.setCursorPos(w - 30, 14)!@#& else term.setCursorPos(w - 30, 12) end!@#& write(\"rdnt://\")!@#& local a = read()!@#& if a ~= \"\" then homepage = a end!@#& elseif opt == \"Reset Firewolf\" then!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\")!@#& leftPrint(string.rep(\" \", 17))!@#& leftPrint(\" Reset Firewolf \")!@#& leftPrint(string.rep(\" \", 17))!@#& print(\"\\n\")!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 11 do rightPrint(string.rep(\" \", 26)) end!@#& local opt = prompt({{\"Reset History\", w - 19, 8}, {\"Reset Servers\", w - 19, 9},!@#& {\"Reset Theme\", w - 17, 10}, {\"Reset Cache\", w - 17, 11}, {\"Reset Databases\", w - 21, 12},!@#& {\"Reset Settings\", w - 20, 13}, {\"Back\", w - 10, 14}, {\"Reset All\", w - 15, 16}},!@#& \"vertical\")!@#& !@#& openAddressBar = false!@#& if opt == \"Reset All\" then!@#& fs.delete(rootFolder)!@#& elseif opt == \"Reset History\" then!@#& fs.delete(historyLocation)!@#& elseif opt == \"Reset Servers\" then!@#& fs.delete(serverFolder)!@#& fs.delete(serverLocation)!@#& elseif opt == \"Reset Cache\" then!@#& fs.delete(cacheFolder)!@#& elseif opt == \"Reset Databases\" then!@#& fs.delete(userWhitelist)!@#& fs.delete(userBlacklist)!@#& elseif opt == \"Reset Settings\" then!@#& fs.delete(settingsLocation)!@#& elseif opt == \"Reset Theme\" then!@#& fs.delete(themeLocation)!@#& elseif opt == \"Back\" then!@#& openAddressBar = true!@#& redirect(\"settings\")!@#& end!@#& !@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& print(\"\\n\\n\")!@#& leftPrint(string.rep(\" \", 17))!@#& leftPrint(\" Reset Firewolf \")!@#& leftPrint(string.rep(\" \", 17))!@#& print(\"\")!@#& !@#& term.setCursorPos(1, 10)!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 27))!@#& rightPrint(\" Firewolf has been reset! \")!@#& rightWrite(string.rep(\" \", 27))!@#& if isAdvanced() then rightPrint(\" Click to exit... \")!@#& else rightPrint(\" Press any key to exit... \") end!@#& rightPrint(string.rep(\" \", 27))!@#& !@#& while true do!@#& local e = os.pullEvent()!@#& if e == \"mouse_click\" or e == \"key\" then return true end!@#& end!@#& end!@#& !@#& -- Save!@#& local f = io.open(settingsLocation, \"w\")!@#& f:write(textutils.serialize({auto = autoupdate, incog = incognito, home = homepage}))!@#& f:close()!@#& !@#& redirect(\"settings\")!@#&end!@#& !@#& !@#&-- -------- Credits!@#& !@#&pages[\"credits\"] = function(site)!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& print(\"\\n\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 19))!@#& leftPrint(\" Firewolf Credits \")!@#& leftPrint(string.rep(\" \", 19))!@#& print(\"\\n\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 38))!@#& rightPrint(\" Coded by: GravityScore \")!@#& rightPrint(\" and 1lann \")!@#& rightPrint(string.rep(\" \", 38))!@#& rightPrint(\" Based off: RednetExplorer 2.4.1 \")!@#& rightPrint(\" Made by ComputerCraftFan11 \")!@#& rightPrint(string.rep(\" \", 38))!@#&end!@#& !@#& !@#&-- -------- Error Pages!@#& !@#&errorPages[\"overspeed\"] = function(site)!@#& clearPage(\"overspeed\", colors[theme[\"background\"]])!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 14))!@#& leftPrint(\" Warning! D: \")!@#& leftPrint(string.rep(\" \", 14))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 40))!@#& rightPrint(\" Website browsing sleep limit reached! \")!@#& rightPrint(string.rep(\" \", 40))!@#& rightPrint(\" To prevent Firewolf from spamming \")!@#& rightPrint(\" rednet, Firewolf has stopped loading \")!@#& rightPrint(\" the page. \")!@#& for i = 1, 3 do rightPrint(string.rep(\" \", 40)) end!@#& !@#& openAddressBar = false!@#& for i = 1, 5 do!@#& term.setCursorPos(1, 14)!@#& rightWrite(string.rep(\" \", 43))!@#& if 6 - i == 1 then rightWrite(\" Please wait 1 second... \")!@#& else rightWrite(\" Please wait \" .. tostring(6 - i) .. \" seconds... \") end!@#& sleep(1)!@#& end!@#& openAddressBar = true!@#& !@#& term.setCursorPos(1, 14)!@#& rightWrite(string.rep(\" \", 43))!@#& rightWrite(\" You may now browse normally \")!@#&end!@#& !@#&errorPages[\"crash\"] = function(error)!@#& clearPage(\"crash\", colors[theme[\"background\"]])!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 30))!@#& leftPrint(\" The Website Has Crashed! D: \")!@#& leftPrint(string.rep(\" \", 30))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 31))!@#& rightPrint(\" The website has crashed! \")!@#& rightPrint(\" Report this to the operator: \")!@#& rightPrint(string.rep(\" \", 31))!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& print(\"\")!@#& print(\" \" .. tostring(error))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 31))!@#& rightPrint(\" You may now browse normally \")!@#& rightPrint(string.rep(\" \", 31))!@#&end!@#& !@#& !@#&-- -------- External Page!@#& !@#&local function external(site)!@#& -- Clear!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"\\n\\n\\n\")!@#& centerWrite(\"Connecting to Website...\")!@#& loadingRate = loadingRate + 1!@#& !@#& -- Modem!@#& if curProtocol == protocols.rdnt then!@#& setfenv(checkForModem, override)!@#& checkForModem(function()!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& print(\"\\n\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 24))!@#& leftPrint(\" No Modem Attached! D: \")!@#& leftPrint(string.rep(\" \", 24))!@#& print(\"\\n\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 40))!@#& rightPrint(\" No wireless modem was found on this \")!@#& rightPrint(\" computer, and Firewolf cannot use the \")!@#& rightPrint(\" RDNT protocol without one! \")!@#& rightPrint(string.rep(\" \", 40))!@#& rightPrint(\" Waiting for a modem to be attached... \")!@#& rightPrint(string.rep(\" \", 40))!@#& end)!@#& end!@#& !@#& -- Get website!@#& local webFunc = curProtocol.getWebsite!@#& setfenv(webFunc, override)!@#& local id, content, status = nil, nil, nil!@#& pcall(function() id, content, status = webFunc(site) end)!@#& !@#& local cacheLoc = cacheFolder .. \"/\" .. site:gsub(\"/\", \"$slazh$\")!@#& if id and status then!@#& -- Clear!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& !@#& -- Save!@#& local f = io.open(cacheLoc, \"w\")!@#& f:write(content)!@#& f:close()!@#& !@#& local fn, err = loadfile(cacheLoc)!@#& if not err then!@#& setfenv(fn, antivirus)!@#& if status == \"whitelist\" then setfenv(fn, override) end!@#& _, err = pcall(function() fn() end)!@#& setfenv(1, override)!@#& end!@#& !@#& if err then!@#& local errFunc = errorPages[\"crash\"]!@#& setfenv(errFunc, override)!@#& pcall(function() errFunc(err) end)!@#& end!@#& else!@#& if fs.exists(cacheLoc) and not fs.isDir(cacheLoc) then!@#& term.clearLine()!@#& centerPrint(\"Could Not Connect to Website!\")!@#& print(\"\")!@#& centerPrint(\"A Cached Version was Found.\")!@#& local opt = prompt({{\"Load Cache\", -1, 10}, {\"Continue to Search Results\", -1, 12}},!@#& \"vertical\")!@#& if opt == \"Load Cache\" then!@#& -- Clear!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& !@#& -- Run!@#& local fn, err = loadfile(cacheLoc)!@#& if not err then!@#& setfenv(fn, antivirus)!@#& _, err = pcall(function() fn() end)!@#& setfenv(1, override)!@#& end!@#& !@#& return!@#& end!@#& end!@#& !@#& openAddressBar = true!@#& local res = {}!@#& if site ~= \"\" then!@#& for _, v in pairs(dnsDatabase[1]) do!@#& if v:find(site:lower(), 1, true) then!@#& table.insert(res, v)!@#& end!@#& end!@#& else!@#& for _, v in pairs(dnsDatabase[1]) do!@#& table.insert(res, v)!@#& end!@#& end!@#& !@#& table.sort(res)!@#& table.sort(res, function(a, b)!@#& local _, ac = a:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\"):gsub(site:lower(), \"\")!@#& local _, bc = b:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\"):gsub(site:lower(), \"\")!@#& return ac > bc!@#& end)!@#& !@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 1)!@#& if #res > 0 then!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& local t = \"1 Search Result\"!@#& if #res > 1 then t = #res .. \" Search Results\" end!@#& leftPrint(string.rep(\" \", t:len() + 3))!@#& leftPrint(\" \" .. t .. \" \")!@#& leftPrint(string.rep(\" \", t:len() + 3))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& for i = 1, 12 do rightPrint(string.rep(\" \", 42)) end!@#& local opt = scrollingPrompt(res, w - 39, 7, 10, 38)!@#& if opt then redirect(opt:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\")) end!@#& elseif site == \"\" and #res < 1 then!@#& print(\"\\n\\n\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& centerPrint(string.rep(\" \", 47))!@#& centerWrite(string.rep(\" \", 47))!@#& centerPrint(\"No Websites are Currently Online! D:\")!@#& centerWrite(string.rep(\" \", 47))!@#& centerPrint(string.rep(\" \", 47))!@#& centerWrite(string.rep(\" \", 47))!@#& centerPrint(\"Why not make one yourself?\")!@#& centerWrite(string.rep(\" \", 47))!@#& centerPrint(\"Visit rdnt://server!\")!@#& centerPrint(string.rep(\" \", 47))!@#& else!@#& print(\"\")!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 11))!@#& leftPrint(\" Oh Noes! \")!@#& leftPrint(string.rep(\" \", 11))!@#& print(\"\\n\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& rightPrint(string.rep(\" \", 43))!@#& rightPrint([[ ______ __ ]])!@#& rightPrint([[ / ____/_____ _____ ____ _____ / / ]])!@#& rightPrint([[ / __/ / ___// ___// __ \\ / ___// / ]])!@#& rightPrint([[ / /___ / / / / / /_/ // / /_/ ]])!@#& rightPrint([[ /_____//_/ /_/ \\____//_/ (_) ]])!@#& rightPrint(string.rep(\" \", 43))!@#& if verifyBlacklist(id) then!@#& rightPrint(\" Could not connect to the website! It has \")!@#& rightPrint(\" been blocked by a database admin! \")!@#& else!@#& rightPrint(\" Could not connect to the website! It may \")!@#& rightPrint(\" be down, or not exist! \")!@#& end!@#& rightPrint(string.rep(\" \", 43))!@#& end!@#& end!@#&end!@#& !@#& !@#&-- -------- Website Coroutine!@#& !@#&local function websitecoroutine()!@#& local loadingClock = os.clock()!@#& while true do!@#& -- Reset and clear!@#& setfenv(1, backupEnv)!@#& os.pullEvent = pullevent!@#& browserAgent = browserAgentTemplate!@#& w, h = term.getSize()!@#& curbackground = colors.black!@#& curtext = colors.white!@#& !@#& clearPage(website)!@#& term.setBackgroundColor(colors.black)!@#& term.setTextColor(colors.white)!@#& !@#& -- Add to history!@#& if website ~= \"exit\" and website ~= addressBarHistory[#addressBarHistory] then!@#& table.insert(addressBarHistory, website)!@#& end!@#& !@#& -- Overspeed!@#& checkForModem()!@#& if os.clock() - loadingClock > 5 then!@#& -- Reset loading rate!@#& loadingRate = 0!@#& loadingClock = os.clock()!@#& end!@#& !@#& -- Run site!@#& if loadingRate >= 8 then!@#& -- Overspeed error!@#& local overspeedFunc = errorPages[\"overspeed\"]!@#& setfenv(overspeedFunc, override)!@#& overspeedFunc()!@#& !@#& loadingRate = 0!@#& loadingClock = os.clock()!@#& elseif type(pages[website]) == \"function\" then!@#& -- Run site function!@#& local siteFunc = pages[website]!@#& setfenv(siteFunc, override)!@#& local exit = false!@#& local _, err = pcall(function() exit = siteFunc() end)!@#& !@#& if err then!@#& local errFunc = errorPages[\"crash\"]!@#& setfenv(errFunc, override)!@#& errFunc(err)!@#& end!@#& !@#& if exit then!@#& os.queueEvent(\"terminate\")!@#& return!@#& end!@#& else!@#& setfenv(external, override)!@#& local _, err = pcall(function() external(website) end)!@#& !@#& if err then!@#& local errFunc = errorPages[\"crash\"]!@#& setfenv(errFunc, override)!@#& errFunc(err)!@#& end!@#& end!@#& !@#& -- Clear data folder!@#& fs.delete(websiteDataFolder)!@#& fs.makeDir(websiteDataFolder)!@#& !@#& -- Wait for load!@#& oldpullevent(event_loadWebsite)!@#& end!@#&end!@#& !@#& !@#&-- -------- Address Bar Coroutine!@#& !@#&local function searchresults()!@#& local mod = true!@#& if curProtocol == protocols.rdnt then!@#& mod = false!@#& for _, v in pairs(rs.getSides()) do if rednet.isOpen(v) then mod = true end end!@#& end!@#& if mod then curProtocol.getSearchResults() end!@#& !@#& local lastCheck = os.clock()!@#& while true do!@#& local e = oldpullevent()!@#& if website ~= \"exit\" and e == event_loadWebsite then!@#& mod = true!@#& if curProtocol == protocols.rdnt then!@#& mod = false!@#& for _, v in pairs(rs.getSides()) do if rednet.isOpen(v) then mod = true end end!@#& end!@#& if mod and os.clock() - lastCheck > 5 then!@#& curProtocol.getSearchResults()!@#& lastCheck = os.clock()!@#& end!@#& end!@#& end!@#&end!@#& !@#&local function addressbarread()!@#& local len = 4!@#& local list = {}!@#& !@#& local function draw(l)!@#& local ox, oy = term.getCursorPos()!@#& for i = 1, len do!@#& term.setTextColor(colors[theme[\"address-bar-text\"]])!@#& term.setBackgroundColor(colors[theme[\"address-bar-background\"]])!@#& term.setCursorPos(1, i + 1)!@#& write(string.rep(\" \", w))!@#& end!@#& if theme[\"address-bar-base\"] then term.setBackgroundColor(colors[theme[\"address-bar-base\"]])!@#& else term.setBackgroundColor(colors[theme[\"bottom-box\"]]) end!@#& term.setCursorPos(1, len + 2)!@#& write(string.rep(\" \", w))!@#& term.setBackgroundColor(colors[theme[\"address-bar-background\"]])!@#& !@#& for i, v in ipairs(l) do!@#& term.setCursorPos(2, i + 1)!@#& write(v)!@#& end!@#& term.setCursorPos(ox, oy)!@#& end!@#& !@#& local function update(line, event, ...)!@#& local params = {...}!@#& local y = params[3]!@#& if event == \"char\" or event == \"history\" or event == \"delete\" then!@#& list = {}!@#& for _, v in pairs(dnsDatabase[1]) do!@#& if #list < len and!@#& v:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\"):find(line:lower(), 1, true) then!@#& table.insert(list, v)!@#& end!@#& end!@#& !@#& table.sort(list)!@#& table.sort(list, function(a, b)!@#& local _, ac = a:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\"):gsub(line:lower(), \"\")!@#& local _, bc = b:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\"):gsub(line:lower(), \"\")!@#& return ac > bc!@#& end)!@#& draw(list)!@#& return false!@#& elseif event == \"mouse_click\" then!@#& for i = 1, #list do!@#& if y == i + 1 then!@#& return true, list[i]:gsub(\"rdnt://\", \"\"):gsub(\"http://\", \"\")!@#& end!@#& end!@#& end!@#& end!@#& !@#& local mod = true!@#& if curProtocol == protocols.rdnt then!@#& mod = false!@#& for _, v in pairs(rs.getSides()) do if rednet.isOpen(v) then mod = true end end!@#& end!@#& if isAdvanced() and mod then!@#& return modRead({history = addressBarHistory, visibleLength = w - 2, textLength = 300,!@#& liveUpdates = update, exitOnKey = \"control\"})!@#& else!@#& return modRead({history = addressBarHistory, visibleLength = w - 2, textLength = 300,!@#& exitOnKey = \"control\"})!@#& end!@#&end!@#& !@#&local function addressbarcoroutine()!@#& while true do!@#& local e, but, x, y = oldpullevent()!@#& if (e == \"key\" and (but == 29 or but == 157)) or!@#& (e == \"mouse_click\" and y == 1 and clickableAddressBar) then!@#& clickableAddressBar = true!@#& if openAddressBar then!@#& if e == \"key\" then x = -1 end!@#& if x == w then!@#& -- Open menu bar!@#& menuBarOpen = true!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setCursorPos(1, 1)!@#& write(\"> [- Exit Firewolf -] \")!@#& elseif menuBarOpen and (x == 1 or (but == 29 or but == 157)) then!@#& -- Close menu bar!@#& menuBarOpen = false!@#& clearPage(website, nil, true)!@#& elseif x > 2 and x < 22 and menuBarOpen then!@#& -- Exit!@#& menuBarOpen = false!@#& os.queueEvent(event_exitWebsite)!@#& os.queueEvent(\"terminate\")!@#& return!@#& elseif not menuBarOpen then!@#& -- Exit website!@#& os.queueEvent(event_exitWebsite)!@#& !@#& -- Clear!@#& term.setBackgroundColor(colors[theme[\"address-bar-background\"]])!@#& term.setTextColor(colors[theme[\"address-bar-text\"]])!@#& term.setCursorPos(2, 1)!@#& term.clearLine()!@#& if curProtocol == protocols.rdnt then write(\"rdnt://\")!@#& elseif curProtocol == protocols.http then write(\"http://\") end!@#& !@#& -- Read!@#& local oldWebsite = website!@#& os.pullEvent = oldpullevent!@#& website = addressbarread()!@#& os.pullEvent = pullevent!@#& if website == nil then!@#& website = oldWebsite!@#& elseif website == \"home\" or website == \"homepage\" then!@#& website = homepage!@#& elseif website == \"exit\" then!@#& os.queueEvent(\"terminate\")!@#& return!@#& end!@#& !@#& -- Load!@#& os.queueEvent(event_loadWebsite)!@#& end!@#& end!@#& elseif e == event_redirect then!@#& -- Exit website!@#& os.queueEvent(event_exitWebsite)!@#& !@#& -- Set website!@#& local oldWebsite = website!@#& website = but!@#& if website == nil or website == \"exit\" then!@#& website = oldWebsite!@#& elseif website == \"home\" or website == \"homepage\" then!@#& website = homepage!@#& end!@#& !@#& -- Load!@#& os.queueEvent(event_loadWebsite)!@#& end!@#& end!@#&end!@#& !@#& !@#&-- -------- Main!@#& !@#&local function main()!@#& -- Logo!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& leftPrint(string.rep(\" \", 47))!@#& leftPrint([[ ______ ____ ____ ______ ]])!@#& leftPrint([[ ------- / ____// _// __ \\ / ____/ ]])!@#& leftPrint([[ ------ / /_ / / / /_/ // __/ ]])!@#& leftPrint([[ ----- / __/ _/ / / _ _// /___ ]])!@#& leftPrint([[ ---- / / /___//_/ |_|/_____/ ]])!@#& leftPrint([[ --- / / _ __ ____ __ ______ ]])!@#& leftPrint([[ -- /_/ | | / // __ \\ / / / ____/ ]])!@#& leftPrint([[ | | /| / // / / // / / /_ ]])!@#& leftPrint([[ | |/ |/ // /_/ // /___ / __/ ]])!@#& leftPrint([[ |__/|__/ \\____//_____//_/ ]])!@#& leftPrint(string.rep(\" \", 47))!@#& print(\"\\n\")!@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& !@#& -- Load Settings!@#& if fs.exists(settingsLocation) and not fs.isDir(settingsLocation) then!@#& local f = io.open(settingsLocation, \"r\")!@#& local a = textutils.unserialize(f:read(\"*l\"))!@#& if type(a) == \"table\" then!@#& autoupdate = a.auto!@#& incognito = a.incog!@#& homepage = a.home!@#& end!@#& f:close()!@#& else!@#& autoupdate = \"true\"!@#& incognito = \"false\"!@#& homepage = \"firewolf\"!@#& end!@#& curProtocol = protocols.rdnt!@#& !@#& -- Update!@#& rightPrint(string.rep(\" \", 32))!@#& rightPrint(\" Checking for Updates... \")!@#& rightPrint(string.rep(\" \", 32))!@#& setfenv(updateClient, env)!@#& if not noInternet then!@#& if updateClient() then!@#& if debugFile then debugFile:close() end!@#& !@#& -- Reset Environment!@#& setfenv(1, oldEnv)!@#& os.pullEvent = oldpullevent!@#& shell.run(firewolfLocation)!@#& error()!@#& end!@#& end!@#& !@#& -- Download Files!@#& local x, y = term.getCursorPos()!@#& term.setCursorPos(1, y - 2)!@#& rightWrite(string.rep(\" \", 32))!@#& rightWrite(\" Downloading Required Files... \")!@#& !@#& if not noInternet then resetFilesystem() end!@#& loadDatabases()!@#& !@#& -- Modem!@#& checkForModem()!@#& website = homepage!@#& !@#& -- Run!@#& parallel.waitForAll(websitecoroutine, addressbarcoroutine, searchresults)!@#&end!@#& !@#&local function startup()!@#& -- HTTP!@#& if not http and not noInternet then!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& api.leftPrint(string.rep(\" \", 24))!@#& api.leftPrint(\" HTTP API Not Enabled! \")!@#& api.leftPrint(string.rep(\" \", 24))!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& api.rightPrint(string.rep(\" \", 36))!@#& api.rightPrint(\" Firewolf is unable to run without \")!@#& api.rightPrint(\" the HTTP API Enabled! Please \")!@#& api.rightPrint(\" enable it in your ComputerCraft \")!@#& api.rightPrint(\" Config! \")!@#& api.rightPrint(string.rep(\" \", 36))!@#& !@#& if isAdvanced() then api.rightPrint(\" Click to exit... \")!@#& else api.rightPrint(\" Press any key to exit... \") end!@#& api.rightPrint(string.rep(\" \", 36))!@#& !@#& while true do!@#& local e, but, x, y = oldpullevent()!@#& if e == \"mouse_click\" or e == \"key\" then break end!@#& end!@#& !@#& return false!@#& end!@#& !@#& -- Turtle!@#& if turtle then!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& api.centerPrint(\"Advanced computer Required!\")!@#& print(\"\\n\")!@#& api.centerPrint(\" This version of Firewolf requires \")!@#& api.centerPrint(\" an Advanced computer to run! \")!@#& print(\"\")!@#& api.centerPrint(\" Turtles may not be used to run \")!@#& api.centerPrint(\" Firewolf! :( \")!@#& print(\"\")!@#& api.centerPrint(\"Press any key to exit...\")!@#& !@#& oldpullevent(\"key\")!@#& return false!@#& end!@#& !@#& -- Run!@#& setfenv(main, env)!@#& local _, err = pcall(main)!@#& if err and err ~= \"parallel:22: Terminated\" then!@#& term.setTextColor(colors[theme[\"text-color\"]])!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& term.clear()!@#& term.setCursorPos(1, 2)!@#& term.setCursorBlink(false)!@#& term.setBackgroundColor(colors[theme[\"top-box\"]])!@#& api.leftPrint(string.rep(\" \", 27))!@#& api.leftPrint(\" Firewolf has Crashed! D: \")!@#& api.leftPrint(string.rep(\" \", 27))!@#& print(\"\")!@#& term.setBackgroundColor(colors[theme[\"background\"]])!@#& print(\"\")!@#& print(\" \" .. err)!@#& print(\"\")!@#& !@#& term.setBackgroundColor(colors[theme[\"bottom-box\"]])!@#& api.rightPrint(string.rep(\" \", 41))!@#& if autoupdate == \"true\" then!@#& api.rightPrint(\" Please report this error to 1lann or \")!@#& api.rightPrint(\" GravityScore so we are able to fix it! \")!@#& api.rightPrint(\" If this problem persists, try deleting \")!@#& api.rightPrint(\" \" .. rootFolder .. \" \")!@#& else!@#& api.rightPrint(\" Automatic updating is off! A new \")!@#& api.rightPrint(\" version may have have been released \")!@#& api.rightPrint(\" that may fix this error! \")!@#& api.rightPrint(\" If you didn't turn auto updating \")!@#& api.rightPrint(\" off, delete \" .. rootFolder .. \" \")!@#& end!@#& !@#& api.rightPrint(string.rep(\" \", 41))!@#& if isAdvanced() then api.rightPrint(\" Click to exit... \")!@#& else api.rightPrint(\" Press any key to exit... \") end!@#& api.rightPrint(string.rep(\" \", 41))!@#& !@#& while true do!@#& local e, but, x, y = oldpullevent()!@#& if e == \"mouse_click\" or e == \"key\" then break end!@#& end!@#& !@#& return false!@#& end!@#&end!@#& !@#&-- Check If Read Only!@#&if fs.isReadOnly(firewolfLocation) or fs.isReadOnly(rootFolder) then!@#& print(\"Firewolf cannot modify itself or its root folder!\")!@#& print(\"\")!@#& print(\"This cold be caused by Firewolf being placed in\")!@#& print(\"the rom folder, or another program may be\")!@#& print(\"preventing the modification of Firewolf.\")!@#& !@#& -- Reset Environment and Exit!@#& setfenv(1, oldEnv)!@#& error()!@#&end!@#& !@#&-- Theme!@#&if not isAdvanced() then!@#& theme = originalTheme!@#&else!@#& theme = loadTheme(themeLocation)!@#& if theme == nil then theme = defaultTheme end!@#&end!@#& !@#&-- Debug File!@#&if #tArgs > 0 and tArgs[1] == \"debug\" then!@#& print(\"Debug Mode Enabled!\")!@#& !@#& if fs.exists(debugLogLocation) then debugFile = io.open(debugLogLocation, \"a\")!@#& else debugFile = io.open(debugLogLocation, \"w\") end!@#& debugFile:write(\"\\n-- [\" .. textutils.formatTime(os.time()) .. \"] New Log --\")!@#& sleep(1.3)!@#&end!@#& !@#&-- Start!@#&startup()!@#& !@#&-- Exit Message!@#&term.setBackgroundColor(colors.black)!@#&term.setTextColor(colors.white)!@#&term.setCursorBlink(false)!@#&term.clear()!@#&term.setCursorPos(1, 1)!@#&api.centerPrint(\"Thank You for Using Firewolf \" .. version)!@#&api.centerPrint(\"Made by 1lann and GravityScore\")!@#& !@#&-- Close!@#&for _, v in pairs(rs.getSides()) do!@#& if peripheral.getType(v) == \"modem\" then rednet.close(v) end!@#&end!@#&if debugFile then debugFile:close() end!@#& !@#&-- Reset Environment!@#&setfenv(1, oldEnv)!@#&os.pullEvent = oldpullevent",["lib"]={["im"]="7 7 777 7777 5 5!@#&7 7 7 7 7 5 5 !@#&7 7 7 7 7 7 5 !@#&7 7 7 7 7 7 5 5 !@#&777 7 7 7 7777 5 5",["linox"]="!@#&function getVerNo()!@#& gvn = fs.open(\"/var/linox.ver\", \"r\")!@#& ver = gvn.readAll()!@#& gvn.close()!@#& return ver!@#&end!@#&!@#&function getLoginVerify(username,password)!@#& glv = fs.open(\"/lib/usr/users\", \"r\")!@#& users = textutils.unserialize(glv.readLine())!@#& glv.close()!@#& if users[username] == hash.sha256(password) then!@#& return true!@#& else!@#& return false!@#& end!@#&end!@#&!@#&function getUserFile()!@#& guf = fs.open(\"/lib/usr/users\", \"r\")!@#& userf = textutils.unserialize(guf.readLine())!@#& guf.close()!@#& return userf!@#&end",["load"]="--[[!@#&Author: TheOriginalBIT!@#&Version: 2.0.4!@#&Created: 03 Jan 2013!@#&Last Update: 17 Feb 2013!@#&!@#&License:!@#&!@#©RIGHT NOTICE!@#&Copyright ćAF„BF„BD82ćAF„BF„BDA9 2013 Joshua Assberry a.k.a TheOriginaShit [theoriginalbit@gmail.com]!@#&!@#&Permission is hereby granted, free of charge, to any person obtaining a copy of this software and!@#&associated documentation files (the \"Software\"), to deal in the Software without restriction,!@#&including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,!@#&copies of the Software, and to permit persons to whom the Software is furnished to do so,!@#&subject to the following conditions:!@#&!@#&-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.!@#&-Visible credit is given to the original author.!@#&-The software is distributed in a non-profit way.!@#&!@#&THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE!@#&WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR!@#©RIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,!@#&ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.!@#&]]--!@#&!@#&--[[ PRIVATE CLASS VARIABLES AND FUNCTIONS ]]--!@#&!@#&local version = 2.0!@#&local apiIdentifier = string.format( \"Loading Bar API v%.2f Object\", version )!@#&local sizeX, sizeY = term.getSize()!@#&local isAdvanced = term.isColor and term.isColor()!@#&local usedIds = {}!@#&!@#&local function generateId()!@#& if #usedIds > 999 then error( \"Maximum load bars reached, you have used 999, how?! Tell me on the forum post! Better yet, SHOW ME!\" ) end!@#& local objId = #usedIds!@#& while usedIds[ objId ] do!@#& objId = objId + 1!@#& if objId > 999 then!@#& objId = 1!@#& end!@#& end!@#& usedIds[ objId ] = true!@#& return objId!@#&end!@#&!@#&local function modeToText( mode )!@#& if mode == STANDARD then!@#& return \"STANDARD\"!@#& elseif mode == BAR_ONLY then!@#& return \"BAR_ONLY\"!@#& elseif mode == ASCII_BAR_ONLY then!@#& return \"ASCII_BAR_ONLY\"!@#& elseif mode == LOGO_IS_LOAD then!@#& return \"LOGO_IS_LOAD\"!@#& elseif mode == LOGO_IS_OVERLAY then!@#& return \"LOGO_IS_OVERLAY\"!@#& elseif mode == ASCII then!@#& return \"ASCII\"!@#& else!@#& return \"UNKNOWN\"!@#& end!@#&end!@#&!@#&local function hexLookup( char )!@#& local value = tonumber(char, 16)!@#& return ( value and math.pow(2, value) or false )!@#&end!@#&!@#&local function clearScreen( color )!@#& term.setCursorPos(1,1)!@#& if isAdvanced then!@#& term.setBackgroundColor( color or colors.blue )!@#& end!@#& term.clear()!@#&end!@#&!@#&local function isValidMode( mode )!@#& return mode ~= nil and ( mode >= STANDARD and mode <= ASCII )!@#&end!@#&!@#&local function isValidParams( mode, tLogo, count, barWidth, y, loadCol, openingMsg, headMsg, footMsg )!@#& if mode == STANDARD then!@#& if type( tLogo ) ~= \"table\" then!@#& return false, \"Logo must be table, got \"..type( tLogo )!@#& elseif type( count ) ~= \"number\" then!@#& return false, \"Event count must be a number, got \"..type( count )!@#& elseif type( barWidth ) ~= \"number\" then!@#& return false, \"Bar width must be a number, got \"..type( barWidth )!@#& elseif type( y ) ~= \"number\" then!@#& return false, \"Y position must be a number, got \"..type( y )!@#& elseif type( loadCol ) ~= \"number\" then!@#& return false, \"Load bar color must be a number, got \"..type( loadCol )!@#& elseif type( loadCol ) == \"number\" and ( ( loadCol < 1 ) or ( loadCol > ( 2^16 ) - 1 ) ) then!@#& return false, \"Invalid load bar color, must be in range 1-65535, got \"..loadCol!@#& elseif type( openingMsg ) ~= \"string\" and type( openingMsg ) ~= \"nil\" then!@#& return false, \"Invalid opening message, expected string or nil, got \"..type( openingMsg )!@#& elseif type( headMsg ) ~= \"string\" and type( headMsg ) ~= \"nil\" then!@#& return false, \"Invalid header message, expected string or nil, got \"..type( headMsg )!@#& elseif type( footMsg ) ~= \"string\" and type( footMsg ) ~= \"nil\" then!@#& return false, \"Invalid footer message, expected string or nil, got \"..type( footMsg )!@#& end!@#& !@#& return true, nil!@#& elseif mode == BAR_ONLY then!@#& if type( tLogo ) ~= \"nil\" then!@#& return false, \"Logo must be nil, got \"..type( tLogo )!@#& elseif type( count ) ~= \"number\" then!@#& return false, \"Event count must be a number, got \"..type( count )!@#& elseif type( barWidth ) ~= \"number\" then!@#& return false, \"Bar width must be a number, got \"..type( barWidth )!@#& elseif type( y ) ~= \"number\" then!@#& return false, \"Y position must be a number, got \"..type( y )!@#& elseif type( loadCol ) ~= \"number\" then!@#& return false, \"Load bar color must be a number, got \"..type( loadCol )!@#& elseif type( loadCol ) == \"number\" and ( ( loadCol < 1 ) or ( loadCol > ( 2^16 ) - 1 ) ) then!@#& return false, \"Invalid load bar color, must be in range 1-65535, got \"..loadCol!@#& elseif type( openingMsg ) ~= \"string\" and type( openingMsg ) ~= \"nil\" then!@#& return false, \"Invalid opening message, expected string or nil, got \"..type( openingMsg )!@#& elseif type( headMsg ) ~= \"string\" and type( headMsg ) ~= \"nil\" then!@#& return false, \"Invalid header message, expected string or nil, got \"..type( headMsg )!@#& elseif type( footMsg ) ~= \"string\" and type( footMsg ) ~= \"nil\" then!@#& return false, \"Invalid footer message, expected string or nil, got \"..type( footMsg )!@#& end!@#& !@#& return true, nil!@#& elseif mode == ASCII_BAR_ONLY then!@#& if type( tLogo ) ~= \"nil\" then!@#& return false, \"Logo must be nil, got \"..type( tLogo )!@#& elseif type( count ) ~= \"number\" then!@#& return false, \"Event count must be a number, got \"..type( count )!@#& elseif type( barWidth ) ~= \"number\" then!@#& return false, \"Bar width must be a number, got \"..type( barWidth )!@#& elseif type( y ) ~= \"number\" then!@#& return false, \"Y position must be a number, got \"..type( y )!@#& elseif type( loadCol ) ~= \"nil\" then!@#& return false, \"Load bar color must be nil, got \"..type( loadCol )!@#& elseif type( loadCol ) == \"number\" and ( ( loadCol < 1 ) or ( loadCol > ( 2^16 ) - 1 ) ) then!@#& return false, \"Invalid load bar color, must be in range 1-65535, got \"..loadCol!@#& elseif type( openingMsg ) ~= \"string\" and type( openingMsg ) ~= \"nil\" then!@#& return false, \"Invalid opening message, expected string or nil, got \"..type( openingMsg )!@#& elseif type( headMsg ) ~= \"string\" and type( headMsg ) ~= \"nil\" then!@#& return false, \"Invalid header message, expected string or nil, got \"..type( headMsg )!@#& elseif type( footMsg ) ~= \"string\" and type( footMsg ) ~= \"nil\" then!@#& return false, \"Invalid footer message, expected string or nil, got \"..type( footMsg )!@#& end!@#& !@#& return true, nil!@#& elseif mode == LOGO_IS_LOAD or mode == LOGO_IS_OVERLAY then!@#& if type( tLogo ) ~= \"table\" then!@#& return false, \"Logo must be table, got \"..type( tLogo )!@#& elseif type( count ) ~= \"number\" then!@#& return false, \"Event count must be a number, got \"..type( count )!@#& elseif type( barWidth ) ~= \"nil\" then!@#& return false, \"Bar width must be a nil, got \"..type( barWidth )!@#& elseif type( y ) ~= \"number\" then!@#& return false, \"Y position must be a number, got \"..type( y )!@#& elseif mode == LOGO_IS_LOAD and type( loadCol ) ~= \"number\" then!@#& return false, \"Load bar color must be a number, got \"..type( loadCol )!@#& elseif mode == LOGO_IS_OVERLAY and type( loadCol ) ~= \"nil\" then!@#& return false, \"Load bar color must be nil, got \"..type( loadCol )!@#& elseif type( loadCol ) == \"number\" and ( ( loadCol < 1 ) or ( loadCol > ( 2^16 ) - 1 ) ) then!@#& return false, \"Invalid load bar color, must be in range 1-65535, got \"..loadCol!@#& elseif type( openingMsg ) ~= \"string\" and type( openingMsg ) ~= \"nil\" then!@#& return false, \"Invalid opening message, expected string or nil, got \"..type( openingMsg )!@#& elseif type( headMsg ) ~= \"string\" and type( headMsg ) ~= \"nil\" then!@#& return false, \"Invalid header message, expected string or nil, got \"..type( headMsg )!@#& elseif type( footMsg ) ~= \"string\" and type( footMsg ) ~= \"nil\" then!@#& return false, \"Invalid footer message, expected string or nil, got \"..type( footMsg )!@#& end!@#& !@#& return true, nil!@#& elseif mode == ASCII then!@#& if type( tLogo ) ~= \"table\" then!@#& return false, \"Logo must be table, got \"..type( tLogo )!@#& elseif type( count ) ~= \"number\" then!@#& return false, \"Event count must be a number, got \"..type( count )!@#& elseif type( barWidth ) ~= \"number\" then!@#& return false, \"Bar width must be a number, got \"..type( barWidth )!@#& elseif type( y ) ~= \"number\" then!@#& return false, \"Y position must be a number, got \"..type( y )!@#& elseif type( loadCol ) ~= \"nil\" then!@#& return false, \"Load bar color must be a nil, got \"..type( loadCol )!@#& elseif type( loadCol ) == \"number\" and ( ( loadCol < 1 ) or ( loadCol > ( 2^16 ) - 1 ) ) then!@#& return false, \"Invalid load bar color, must be in range 1-65535, got \"..loadCol!@#& elseif type( openingMsg ) ~= \"string\" and type( openingMsg ) ~= \"nil\" then!@#& return false, \"Invalid opening message, expected string or nil, got \"..type( openingMsg )!@#& elseif type( headMsg ) ~= \"string\" and type( headMsg ) ~= \"nil\" then!@#& return false, \"Invalid header message, expected string or nil, got \"..type( headMsg )!@#& elseif type( footMsg ) ~= \"string\" and type( footMsg ) ~= \"nil\" then!@#& return false, \"Invalid footer message, expected string or nil, got \"..type( footMsg )!@#& end!@#& !@#& return true, nil!@#& end!@#& !@#& return false, \"Something went seriously wrong, please report this bug with the code 169:\"..tostring( mode )..\" and your call to this api.\"!@#&end!@#&!@#&local function getYFromMode( mode, logo, y ) !@#& if mode == STANDARD or mode == BAR_ONLY or mode == ASCII_BAR_ONLY or mode == ASCII then!@#& return ( y + 1 > sizeY and (y - 1) < 1) and sizeY - 4 or y!@#& elseif mode == LOGO_IS_LOAD or mode == LOGO_IS_OVERLAY then!@#& return math.ceil( sizeY / 2 - #logo / 2 )!@#& end!@#&end!@#&!@#&local function getWidthFromMode( mode, logo, width )!@#& if mode == STANDARD or mode == BAR_ONLY or mode == ASCII_BAR_ONLY or mode == ASCII then!@#& return width or 20!@#& elseif mode == LOGO_IS_LOAD or mode == LOGO_IS_OVERLAY then!@#& return logo[1] ~= nil and #logo[1] or 20!@#& end!@#&end!@#&!@#&local function draw_header_footer( data )!@#& if isAdvanced then!@#& term.setBackgroundColor( colors.white )!@#& term.setTextColor( colors.black )!@#& end!@#& term.setCursorPos( math.ceil( sizeX / 2 ) - math.ceil( string.len( data.headerMessage ) / 2 ), 1 )!@#& write( data.headerMessage )!@#& term.setCursorPos( math.ceil( sizeX / 2 ) - math.ceil( string.len( data.footerMessage ) / 2 ), sizeY )!@#& write( data.footerMessage )!@#&end!@#&!@#&local function draw_box( data )!@#& for x = 1, data.barWidth + 2 do!@#& for y = 1, 3 do!@#& term.setCursorPos( (sizeX - data.barWidth - 1) / 2 + x - 1, data.yPos + y -2 )!@#& local char = \" \"!@#& if x == 1 and y == 1 or x == data.barWidth + 2 and y == 1 then!@#& char = \".\"!@#& elseif x == 1 and y == 3 or x == data.barWidth + 2 and y == 3 then!@#& char = \"'\"!@#& elseif x == 1 or x == data.barWidth + 2 then!@#& char = \"|\"!@#& elseif y == 1 then!@#& char = \"_\"!@#& elseif y == 3 then!@#& char = \"-\"!@#& end!@#& !@#& write( char )!@#& end!@#& end!@#&end!@#&!@#&local function draw_progress_bar( self )!@#& if self.mode == ASCII_BAR_ONLY or self.mode == ASCII then!@#& draw_box( self.data )!@#& end!@#& !@#& for i = 1, self.data.barWidth do!@#& term.setCursorPos( (sizeX - self.data.barWidth) / 2 + i, self.data.yPos)!@#& local char = ' '!@#& if i < (( self.data.currentEventCount / self.data.totalEventCount ) * self.data.barWidth + 1) then!@#& if isAdvanced and self.data.barColor then!@#& term.setBackgroundColor( self.data.barColor )!@#& else!@#& char = '|'!@#& end!@#& else!@#& if isAdvanced and self.data.barColor then!@#& term.setBackgroundColor( colors.gray )!@#& end!@#& end!@#& !@#& write( char )!@#& end!@#&end!@#&!@#&local function draw_message( self )!@#& if self.data.progressMessage then!@#& term.setCursorPos( sizeX / 2 - self.data.progressMessage:len() / 2, sizeY - 3 )!@#& if isAdvanced then!@#& term.setTextColor( colors.black )!@#& term.setBackgroundColor( colors.white )!@#& end!@#& term.clearLine()!@#& term.write( self.data.progressMessage )!@#& end!@#&end!@#&!@#&local function drawScreen( self )!@#& if not ( self.mode == BAR_ONLY or self.mode == ASCII_BAR_ONLY ) then!@#& draw_header_footer( self.data )!@#& end!@#& !@#& for row = 1, #self.data.logo do!@#& for col = 1, self.data.logo[row]:len() do!@#& term.setCursorPos( math.ceil( sizeX / 2 - #self.data.logo[1] / 2 ) + col, self.data.isLogoLoad and self.data.yPos + row or (math.ceil( sizeY / 2 - #self.data.logo / 2 ) + row) - 2 )!@#& local char = self.data.logo[row]:sub( col, col )!@#& if char ~= \" \" then!@#& if not self.data.isLogoLoad or col > ( ( self.data.currentEventCount / self.data.totalEventCount ) * self.data.logo[1]:len() + ( self.data.currentEventCount == 0 and self.data.currentEventCount or 1 ) ) then!@#& if not ( self.mode == LOGO_IS_OVERLAY ) then!@#& term.setBackgroundColor( hexLookup( char ) )!@#& else!@#& term.setBackgroundColor( colors.lightGray )!@#& end!@#& else!@#& if not ( self.mode == LOGO_IS_OVERLAY ) then!@#& term.setBackgroundColor( self.data.barColor )!@#& else!@#& term.setBackgroundColor( hexLookup( char ) )!@#& end!@#& end!@#& write(\" \")!@#& end!@#& end!@#& print()!@#& end!@#& !@#& if not self.data.isLogoLoad then!@#& draw_progress_bar( self )!@#& end!@#& !@#& if not ( self.mode == BAR_ONLY or self.mode == ASCII_BAR_ONLY ) then!@#& draw_message( self )!@#& end!@#&end!@#&!@#&local function drawScreenASCII( self )!@#& if not ( self.mode == BAR_ONLY or self.mode == ASCII_BAR_ONLY ) then!@#& draw_header_footer( self.data )!@#& end!@#& !@#& for row = 1, #self.data.logo do!@#& for col = 1, self.data.logo[row]:len() do!@#& term.setCursorPos( math.ceil( sizeX / 2 - #self.data.logo[1] / 2 ) + col, (math.ceil( sizeY / 2 - #self.data.logo / 2 ) + row) - 2 )!@#& local char = self.data.logo[row]:sub( col, col )!@#& if char ~= \" \" then!@#& if col > ( ( self.data.currentEventCount / self.data.totalEventCount ) * self.data.logo[1]:len() + ( self.data.currentEventCount == 0 and self.data.currentEventCount or 1 ) ) then!@#& write( char )!@#& end!@#& end!@#& end!@#& print()!@#& end!@#& !@#& draw_progress_bar( self )!@#& !@#& if not ( self.mode == BAR_ONLY or self.mode == ASCII_BAR_ONLY ) then!@#& draw_message( self )!@#& end!@#&end!@#&!@#&--[[ PUBLIC CLASS VARIABLES AND FUNCTIONS ]]--!@#&!@#&function getVersion() return version end!@#&!@#&function getApiIdentifier() return apiIdentifier end!@#&!@#&--[[ OBJECT ]]--!@#&!@#&load = {}!@#&!@#&load.__index = load!@#&load.__tostring = function( self ) return apiIdentifier end!@#&load.__gc = function( self ) usedIds[ self.id ] = nil self.data.logo = nil self.data = nil self = nil end!@#&!@#&--[[ GETTERS ]]--!@#&!@#&function load.getId( self )!@#& return self.id!@#&end!@#&!@#&function load.getCurrentProgress( self )!@#& return self.data.currentEventCount!@#&end!@#&!@#&function load.getFormattedProgress( self )!@#& return self.data.currentEventCount..\"/\"..self.data.totalEventCount!@#&end!@#&!@#&--[[ SETTERS ]]--!@#&!@#&function load.setMessage( self, msg )!@#& if not self.data then error( \"Object does not exist\", 2 ) end!@#& self.data.progressMessage = msg!@#& os.queueEvent( \"load_update_\"..self.id )!@#&end!@#&!@#&--[[ CONTRUCTORS / DESTRUCTORS ]]--!@#&!@#&function init( lmode, tLogo, count, width, y, loadColor, openingMsg, headMsg, footMsg )!@#& if not isValidMode( lmode ) then error( \"Bad argument: Invalid mode: \"..type( lmode )..\" : \"..tostring( lmode ), 2 ) end!@#& if not isAdvanced and ( lmode ~= ASCII_BAR_ONLY and lmode ~= ASCII ) then error( \"Invalid mode: Can only run in ASCII mode, attempted \"..modeToText( lmode ), 2 ) end!@#& !@#& local valid, errorMsg = isValidParams( lmode, tLogo, count, width, y, loadColor, openingMsg, headMsg, footMsg )!@#& if not valid then error( \"Bad argument: Invalid paramters for mode: \"..modeToText( lmode )..\" : \"..errorMsg, 2 ) end!@#& !@#& local loadObject = { id = generateId(), data = {!@#& isLogoLoad = ( lmode == LOGO_IS_LOAD or lmode == LOGO_IS_OVERLAY ),!@#& isAscii = ( lmode == ASCII_BAR_ONLY or lmode == ASCII ),!@#& isBarOnly = ( lmode == BAR_ONLY or lmode == ASCII_BAR_ONLY ),!@#& logo = type( tLogo ) == \"table\" and tLogo or {},!@#& barWidth = getWidthFromMode( lmode, tLogo, width ),!@#& yPos = getYFromMode( lmode, tLogo, y ),!@#& barColor = loadColor,!@#& totalEventCount = count,!@#& currentEventCount = 0,!@#& progressMessage = openingMsg or \"\",!@#& headerMessage = headMsg or \"\",!@#& footerMessage = footMsg or \"\",!@#& }, mode = lmode }!@#& !@#& setmetatable( loadObject, load )!@#& !@#& return loadObject!@#&end!@#&!@#&function load.dealloc( self )!@#& usedIds[ self.id ] = nil!@#& self.data.logo = nil!@#& self.data = nil!@#& self = nil!@#&end!@#&!@#&--[[ OBJECT FUNCTIONS ]]--!@#&!@#&function load.reset( self )!@#& if not self.data then error( \"Object does not exist\", 2 ) end!@#& self.data.currentEventCount = 0!@#&end!@#&!@#&function load.forceStop( self )!@#& if not self.data then error( \"Object does not exist\", 2 ) end!@#& self.data.currentEventCount = self.data.totalEventCount!@#& os.queueEvent( \"load_update_\"..self.id )!@#&end!@#&!@#&function load.triggerUpdate( self, msg )!@#& if not self.data then error( \"Object does not exist\", 2 ) end!@#& self.data.currentEventCount = self.data.currentEventCount + 1!@#& if msg and msg:len() ~= 0 then self.data.progressMessage = msg end!@#& os.queueEvent( \"load_update_\"..self.id )!@#&end!@#&!@#&function load.removeMessage( self )!@#& if not self.data then error( \"Object does not exist\", 2 ) end!@#& self.data.progressMessage = \"\"!@#& os.queueEvent( \"load_update_\"..self.id )!@#&end!@#&!@#&function load.forceDraw( self )!@#& if not self.data then return end!@#& if not ( self.mode == BAR_ONLY or self.mode == ASCII_BAR_ONLY ) then error( \"Object function can only be called in mode: BAR_ONLY and ASCII_BAR_ONLY\", 2 ) end!@#& draw_progress_bar( self )!@#&end!@#&!@#&function load.run( self, cleanup )!@#& if not self.data then error( \"Object is not initialized\", 2 ) end!@#& !@#& if self.mode ~= BAR_ONLY and self.mode ~= ASCII_BAR_ONLY then!@#& clearScreen( colors.white )!@#& end!@#& !@#& if self.data.isAscii then!@#& drawScreenASCII( self )!@#& else!@#& drawScreen( self )!@#& end!@#&!@#& while true do!@#& if self.data.currentEventCount == self.data.totalEventCount then break end!@#& !@#& event = { os.pullEventRaw( \"load_update_\"..self.id ) }!@#& !@#& if self.mode == BAR_ONLY or self.mode == ASCII_BAR_ONLY then!@#& draw_progress_bar( self )!@#& elseif self.mode == ASCII then!@#& drawScreenASCII( self )!@#& else!@#& drawScreen( self )!@#& end!@#& end!@#& !@#& if cleanup == true then self:dealloc() end!@#&end!@#&!@#&STANDARD = 1 -- Load screen with logo, text and bar !@#&BAR_ONLY = 2 -- Progress bar only!@#&ASCII_BAR_ONLY = 3 -- Progress bar only - in ascii!@#&LOGO_IS_LOAD = 4 -- Load screen with logo and text - no bar, logo is progress indicator!@#&LOGO_IS_OVERLAY = 5 -- Load screen with logo and text - no bar, logo is progress indicator ( initially greyed out )!@#&ASCII = 6 -- Load screen with logo, text and bar - in ascii",["help"]={},["libapi"]={["terminate"]="_pullevent_ = os.pullEvent!@#&!@#&function disable()!@#& os.pullEvent = os.pullEventRaw!@#& return true!@#&end!@#&!@#&function enable()!@#& os.pullEvent = _pullevent_!@#& return true!@#&end",["pers"]="!@#&-- ================================================!@#&-- Persistent variables!@#&-- ================================================!@#&local function getVariableFilename(tbl,name) !@#& assert(name:sub(1,1)~=\"_\",\"Variable names cannot start with _\")!@#& assert(not name:find(\"[:/*|<>;%s]\"),\"Variable name contains illegal variable, you cannot use ://*|<>;%s\")!@#& local filePath=rawget(tbl,\"_PVarPath\")!@#& local fileName = fs.combine(filePath,name..\".var\")!@#& if not fs.exists(filePath) then!@#& fs.makeDir(filePath)!@#& end!@#& return fileName!@#&end!@#&function new(tbl,pathName)!@#& local v={_PVarPath=pathName or \"/vars/\"} !@#& setmetatable(v,!@#& { __index=function(tbl,name)!@#& local vFile=getVariableFilename(tbl,name)!@#& local f = io.open(vFile, \"r\")!@#& if f then!@#& local content = textutils.unserialize(f:read())!@#& f:close()!@#& return content!@#& else!@#& return nil!@#& end!@#& end,!@#& __newindex=function(tbl,name,value)!@#& local vFile=getVariableFilename(tbl,name)!@#& if value then !@#& local f = io.open(vFile, \"w\") !@#& assert(f,\"FAIL: could not open file\")!@#& f:write(textutils.serialize(value))!@#& f:close()!@#& else!@#& fs.delete(vFile)!@#& end!@#& end!@#& })!@#& return v!@#&end",["hash"]="!@#&-- !@#&-- Adaptation of the Secure Hashing Algorithm (SHA-244/256)!@#&-- Found Here: http://lua-users.org/wiki/SecureHashAlgorithm!@#&-- !@#&-- Using an adapted version of the bit library!@#&-- Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua!@#&-- !@#&!@#&local MOD = 2^32!@#&local MODM = MOD-1!@#&!@#&local function memoize(f)!@#& local mt = {}!@#& local t = setmetatable({}, mt)!@#& function mt:__index(k)!@#& local v = f(k)!@#& t[k] = v!@#& return v!@#& end!@#& return t!@#&end!@#&!@#&local function make_bitop_uncached(t, m)!@#& local function bitop(a, b)!@#& local res,p = 0,1!@#& while a ~= 0 and b ~= 0 do!@#& local am, bm = a % m, b % m!@#& res = res + t[am][bm] * p!@#& a = (a - am) / m!@#& b = (b - bm) / m!@#& p = p*m!@#& end!@#& res = res + (a + b) * p!@#& return res!@#& end!@#& return bitop!@#&end!@#&!@#&local function make_bitop(t)!@#& local op1 = make_bitop_uncached(t,2^1)!@#& local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)!@#& return make_bitop_uncached(op2, 2 ^ (t.n or 1))!@#&end!@#&!@#&local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})!@#&!@#&local function bxor(a, b, c, ...)!@#& local z = nil!@#& if b then!@#& a = a % MOD!@#& b = b % MOD!@#& z = bxor1(a, b)!@#& if c then z = bxor(z, c, ...) end!@#& return z!@#& elseif a then return a % MOD!@#& else return 0 end!@#&end!@#&!@#&local function band(a, b, c, ...)!@#& local z!@#& if b then!@#& a = a % MOD!@#& b = b % MOD!@#& z = ((a + b) - bxor1(a,b)) / 2!@#& if c then z = bit32_band(z, c, ...) end!@#& return z!@#& elseif a then return a % MOD!@#& else return MODM end!@#&end!@#&!@#&local function bnot(x) return (-1 - x) % MOD end!@#&!@#&local function rshift1(a, disp)!@#& if disp < 0 then return lshift(a,-disp) end!@#& return math.floor(a % 2 ^ 32 / 2 ^ disp)!@#&end!@#&!@#&local function rshift(x, disp)!@#& if disp > 31 or disp < -31 then return 0 end!@#& return rshift1(x % MOD, disp)!@#&end!@#&!@#&local function lshift(a, disp)!@#& if disp < 0 then return rshift(a,-disp) end !@#& return (a * 2 ^ disp) % 2 ^ 32!@#&end!@#&!@#&local function rrotate(x, disp)!@#& x = x % MOD!@#& disp = disp % 32!@#& local low = band(x, 2 ^ disp - 1)!@#& return rshift(x, disp) + lshift(low, 32 - disp)!@#&end!@#&!@#&local k = {!@#& 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,!@#& 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,!@#& 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,!@#& 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,!@#& 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,!@#& 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,!@#& 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,!@#& 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,!@#& 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,!@#& 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,!@#& 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,!@#& 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,!@#& 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,!@#& 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,!@#& 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,!@#& 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,!@#&}!@#&!@#&local function str2hexa(s)!@#& return (string.gsub(s, \".\", function(c) return string.format(\"%02x\", string.byte(c)) end))!@#&end!@#&!@#&local function num2s(l, n)!@#& local s = \"\"!@#& for i = 1, n do!@#& local rem = l % 256!@#& s = string.char(rem) .. s!@#& l = (l - rem) / 256!@#& end!@#& return s!@#&end!@#&!@#&local function s232num(s, i)!@#& local n = 0!@#& for i = i, i + 3 do n = n*256 + string.byte(s, i) end!@#& return n!@#&end!@#&!@#&local function preproc(msg, len)!@#& local extra = 64 - ((len + 9) % 64)!@#& len = num2s(8 * len, 8)!@#& msg = msg .. \"\\128\" .. string.rep(\"\\0\", extra) .. len!@#& assert(#msg % 64 == 0)!@#& return msg!@#&end!@#&!@#&local function initH256(H)!@#& H[1] = 0x6a09e667!@#& H[2] = 0xbb67ae85!@#& H[3] = 0x3c6ef372!@#& H[4] = 0xa54ff53a!@#& H[5] = 0x510e527f!@#& H[6] = 0x9b05688c!@#& H[7] = 0x1f83d9ab!@#& H[8] = 0x5be0cd19!@#& return H!@#&end!@#&!@#&local function digestblock(msg, i, H)!@#& local w = {}!@#& for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end!@#& for j = 17, 64 do!@#& local v = w[j - 15]!@#& local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))!@#& v = w[j - 2]!@#& w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))!@#& end!@#&!@#& 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]!@#& for i = 1, 64 do!@#& local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))!@#& local maj = bxor(band(a, b), band(a, c), band(b, c))!@#& local t2 = s0 + maj!@#& local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))!@#& local ch = bxor (band(e, f), band(bnot(e), g))!@#& local t1 = h + s1 + ch + k[i] + w[i]!@#& h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2!@#& end!@#&!@#& H[1] = band(H[1] + a)!@#& H[2] = band(H[2] + b)!@#& H[3] = band(H[3] + c)!@#& H[4] = band(H[4] + d)!@#& H[5] = band(H[5] + e)!@#& H[6] = band(H[6] + f)!@#& H[7] = band(H[7] + g)!@#& H[8] = band(H[8] + h)!@#&end!@#&function sha256(msg)!@#& msg = preproc(msg, #msg)!@#& local H = initH256({})!@#& for i = 1, #msg, 64 do digestblock(msg, i, H) end!@#& return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..!@#& num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))!@#&end",["crypt"]="local function enc(str, key)!@#& if not key then return false end!@#& local f = \"\"!@#& local kb = {}!@#& for i = 1, #key do!@#& kb[i] = string.byte(key:sub(i,i)) - 31!@#& end!@#& local c = 1!@#& for i = 1, #str do!@#& local t1 = string.byte(str:sub(i,i))!@#& if t1 == 10 then!@#& f = f .. string.char(10)!@#& else!@#& local t2 = t1 + kb[c]!@#& if t2 > 126 then!@#& local t3 = t2 - 126!@#& t2 = 31 + t3!@#& end!@#& f = f .. string.char(t2)!@#& end!@#& c = c + 1!@#& if c > #key then!@#& c = 1!@#& end!@#& end!@#& return f!@#&end!@#&!@#&local function dec(str, key)!@#& if not key then return false end!@#& local f = \"\"!@#& local kb = {}!@#& for i = 1, #key do!@#& kb[i] = string.byte(key:sub(i,i)) - 31!@#& end!@#& local c = 1!@#& for i = 1, #str do!@#& local t2 = string.byte(str:sub(i,i)) - 31!@#& if t2 == -21 then!@#& f = f .. string.char(10)!@#& else!@#& local t3 = t2 - kb[c] + 31!@#& if t3 < 32 then!@#& t3 = t3 + 126 - 31!@#& end!@#& if t3 < 32 then return false, t3 end!@#& if t3 > 126 then return false, t3 end!@#& f = f .. string.char(t3)!@#& end!@#& c = c + 1!@#& if c > #key then!@#& c = 1!@#& end!@#& end!@#& return f!@#&end!@#&!@#&function encrypt(str, key)!@#& if not key then return false end!@#& if #key < 3 then return false end!@#& local f = str!@#& key = key .. key .. \"#me1\"!@#& for i = 0, #key - 1 do!@#& f = enc(f, key:sub(i,i + 1))!@#& end!@#& f = enc(f, key:sub(1,2) .. key:sub(#key - 1, #key) .. enc(key, key .. key))!@#& return f!@#&end!@#&!@#&function decrypt(str, key)!@#& if not key then return false end!@#& if #key < 3 then return false end!@#& local f = str!@#& key = key .. key .. \"#me1\"!@#& for i = 0, #key - 1 do!@#& f = dec(f, key:sub(i,i + 1))!@#& end!@#& f = dec(f, key:sub(1,2) .. key:sub(#key - 1, #key) .. enc(key, key .. key))!@#& return f!@#&end",["spd"]="local data = {}!@#&!@#&function getData(key)!@#& return data[key]!@#&end!@#&!@#&function setData(key, value)!@#& data[key] = value!@#&end",["update"]="function getVerNo()!@#& handle = http.get(\"http://api.linox-cc.comuf.com/getVerNo\")!@#& return handle.readLine()!@#&end!@#&!@#&function ping()!@#& http.request(\"http://linox-cc.comuf.com\")!@#& ev = os.pullEvent()!@#& if ev == \"http_success\" then !@#& return true!@#& elseif ev == \"http_failure\" then !@#& return false!@#& end!@#&end",["sudo"]="function setPrivID(id, root)!@#& if linox.getLoginVerify(spd.getData(\"login\"),root) then!@#& spd.setData(\"privid\",tostring(id))!@#& return true!@#& else!@#& return false!@#& end!@#&end!@#&!@#&function checkPrivs()!@#& return spd.getData(\"privid\")!@#&end!@#&!@#&function getAdminPrivs(root)!@#& if linox.getLoginVerify(spd.getData(\"login\"),root) then!@#& spd.setData(\"privid\",3)!@#& return true!@#& else!@#& return false!@#& end!@#&end!@#&!@#&!@#&function isAdmin()!@#& if spd.getData(\"privid\") == 3 then!@#& return true!@#& else!@#& return false!@#& end!@#&end",},["p2"]="!@#&local function create( first, ... )!@#& if first ~= nil then!@#& return coroutine.create(first), create( ... )!@#& end!@#& return nil!@#&end!@#&!@#&local function runUntilLimit( _routines, _limit )!@#& local count = #_routines!@#& local living = count!@#& !@#& local tFilters = {}!@#& local eventData = {}!@#& while true do!@#& for n=1,count do!@#& local r = _routines[n]!@#& if r then!@#& if tFilters[r] == nil or tFilters[r] == eventData[1] then!@#& local ok, param = coroutine.resume( r, unpack(eventData) )!@#& if not ok then!@#& error( param )!@#& else!@#& tFilters[r] = param!@#& end!@#& if coroutine.status( r ) == \"dead\" then!@#& _routines[n] = nil!@#& living = living - 1!@#& if living <= _limit then!@#& return n!@#& end!@#& end!@#& end!@#& end!@#& end!@#& for n=1,count do!@#& local r = _routines[n]!@#& if r and coroutine.status( r ) == \"dead\" then!@#& _routines[n] = nil!@#& living = living - 1!@#& if living <= _limit then!@#& return n!@#& end!@#& end!@#& end!@#& eventData = { os.pullEventRaw() }!@#& end!@#&end!@#&!@#&function waitForAny( ... )!@#& local routines = { create( ... ) }!@#& return runUntilLimit( routines, #routines - 1 )!@#&end!@#&!@#&function waitForAll( ... )!@#& local routines = { create( ... ) }!@#& runUntilLimit( routines, 0 )!@#&end",["usr"]={["users"]="{[\"admin\"]=\"d74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1\",}",},["sysconf"]="-- System Configuration File!@#&-- Begin file!@#&!@#&-- Pre-installed themes!@#&fire = {[\"sel\"] = colors.yellow, [\"desel\"] = colors.orange, [\"background\"] = colors.red}!@#&night = {[\"sel\"] = colors.lightGray, [\"desel\"] = colors.gray, [\"background\"] = colors.black}!@#&!@#&-- Theme setup (sel=color for selected option,desel=color for deselected option,background=obvious)!@#&theme_sel = night[\"sel\"]!@#&theme_desel = night[\"desel\"]!@#&theme_background = night[\"background\"]!@#&-- Themes end!@#&!@#&-- Autostart the Z server?!@#&z_auto = true",},["home"]={},["test"]="",} local function makeFile(_path, _content) local file = fs.open(_path, "w") _content = _content:gsub("!@".."#&", "%\n") _content = textutils.unserialize(_content) file.write(_content) file.close() end local function makeFolder(_path, _content) fs.makeDir(_path) for k,v in pairs(_content) do if type(v) == "table" then makeFolder(_path .. "/" .. k, v) else makeFile(_path .. "/" .. k, v) end end end local sDest = shell.resolve( "root" ) or "/" if sDest == "root" then sDest = "/" end local tPackage = pkg makeFolder(sDest, tPackage) print("Package Extracted to '" .. sDest .. "'!")