--  
--  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