if lOS and lOS.started then
    error("LevelOS is already running, silly!")
end

changecolors = false
purecolors = false
local ranstartup = false
if purecolors == true then
    term.setPaletteColor(colors.white,1,1,1)
    term.setPaletteColor(colors.orange,1,0.5,0)
    -- magenta
    -- light blue
    term.setPaletteColor(colors.yellow,1,1,0)
    term.setPaletteColor(colors.lime,0,1,0)
    term.setPaletteColor(colors.pink,1,0.5,1)
    -- gray
    -- light gray
    term.setPaletteColor(colors.cyan,0,1,1)
    term.setPaletteColor(colors.purple,0.8,0,1)
    term.setPaletteColor(colors.blue,0,0,1)
    -- brown
    term.setPaletteColor(colors.green,0,0.6,0)
    term.setPaletteColor(colors.red,1,0,0)
    term.setPaletteColor(colors.black,0,0,0)
end
if changecolors == true then
    allcolors = {}
    for t=0,15,1 do
        allcolors[#allcolors+1] = {term.getPaletteColor(2^t)}
        term.setPaletteColor(2^t,0,0,0)
    end
end
if not lOS then
    _G.lOS = {}
end
lOS.started = false
if fs.exists("LevelOS/data/settings.lconf") then
    local f = fs.open("LevelOS/data/settings.lconf","r")
    local s = f.readAll()
    f.close()
    lOS.settings = textutils.unserialize(s)
else
    lOS.settings = {maxAll=false} -- load from file usually
end
lOS.tbSize = 0
lOS.lMenu = false
lOS.log = ""
lOS.doasearch = false
lOS.notifications = {}
if fs.exists("AppData") == false then
    fs.makeDir("AppData")
end

if fs.exists("AppData") and fs.exists("AppData/Shapescape") and fs.exists("AppData/Shapescape/temp") then
    local f = fs.list("AppData/Shapescape/temp")
    for t=1,#f do
        fs.delete(fs.combine("AppData/Shapescape/temp",f[t]))
    end
end
lOS.oldterm = term.current()
local oldterm = lOS.oldterm
local w,h = term.getSize()

local function log(txt)
    --lOS.log = lOS.log..txt.."\n"
end


local function fread(file)
    local f = fs.open(file,"r")
    local o = f.readAll()
    f.close()
    return o
end

lOS.processes = {}


lOS.noEvents = false


lOS.wins = {}

lOS.wAll = window.create(oldterm,1,1,w,h,false) -- window all (window object containing all window objects)
local wAll = lOS.wAll
lOS.depWin = window.create(wAll,1,1,w,h,false) -- window where windowless processes will draw objects to. (Does not get saved)

shell.run("LevelOS/startup/lUtils")
local function login()
    if fs.exists("LevelOS/data/account.txt") then
        while not lOS.userID do pcall(function() dofile("LevelOS/Login_screen.sgui") end) end
    elseif fs.exists("LevelOS/startup/LevelCloud.lua") then
        --while not lOS.userID do pcall(function() dofile("LevelOS/Global_Login.lua") end) end
        --while not lOS.userID do pcall(function() lOS.userID,lOS.username = dofile("LevelOS/login.lua") end) end
    end
end
local boterm = term.current()
local buffer = window.create(boterm,1,1,w,h,false)
local bufcor = coroutine.create(login)
if lOS.checkinternet() ~= 0 then
    os.startTimer(0)
    while coroutine.status(bufcor) ~= "dead" do
        local e = table.pack(os.pullEventRaw())
        term.redirect(buffer)
        coroutine.resume(bufcor, table.unpack(e, 1, e.n))
        term.redirect(boterm)
        buffer.setVisible(true)
        buffer.setVisible(false)
    end
end
term.redirect(boterm)
for c=0,15,1 do
    wAll.setPaletteColor(2^c,buffer.getPaletteColor(2^c))
end

os.startTimer(0)

local proc = lOS.processes
--proc[0] = {coroutine.create(function() shell.run("LevelOS/desktop.lua") end),title="Desktop",win=window.create(wAll,1,1,w,h,false),winMode="background"}
proc[0] = {title="Desktop",win=window.create(wAll,1,1,w,h,false),winMode="screen"}
proc[0][1] = coroutine.create(function() local ok,err = lOS.run("LevelOS/desktop.lua",proc[0]) if not ok then lOS.bsod(err) end end)
if fs.exists("LevelOS/data/changelog.lconf") then
    local w,h = term.getSize()
    local offset = 2
    local offsetY = 2
    if w > 60 then
        offset = 2+math.ceil((w-60)/3)
    end
    if h > 40 then
        offsetY = 2+math.ceil((h-40)/3)
    end
    proc[2] = {coroutine.create(function() shell.run("LevelOS/Changelog.lua") end),title="Changelog",win=window.create(wAll,1+offset,1+offsetY,w-(offset*2),(h-2)-(offsetY*2),false),winMode="widget"}
end

-- FOR DEBUGGING PURPOSES ONLY!!!!!
--proc[2] = {coroutine.create(function() shell.run("LevelOS/Task_Manager.lua") end),title="Task Manager",win=window.create(wAll,3,3,35,14,false),winMode="windowed"}
--proc[3] = {coroutine.create(function() shell.run("User/Scripts/log.lua") end),title="Log",win=window.create(wAll,5,5,35,14,false),winMode="windowed"}
--proc[3] = {coroutine.create(function() shell.run("rom/programs/shell.lua") end),title="Shell",win=window.create(wAll,7,7,35,14,false),winMode="windowed"}
--proc[4] = {coroutine.create(function() shell.run("rom/programs/shell.lua") end),win=window.create(wAll,1,1,51,17,false),winMode="borderless"}
--proc[4] = {coroutine.create(function() shell.run("rom/programs/shell.lua") end),title="Pastebin",win=window.create(wAll,9,9,35,14,false),winMode="borderless"}

_G.wButton = 0

lOS.wins[0] = proc[0]
lOS.focusWin = lOS.wins[0]
lOS.wins[1] = proc[2]
--lOS.wins[1] = proc[2]
--lOS.wins[2] = proc[3]
--lOS.wins[3] = proc[3]
--lOS.wins[4] = proc[4]
--table.insert(lOS.wins,1,proc[4])


--[[for t=1,#lOS.wins do
    if lOS.wins[t].snap == nil then
        lOS.wins[t].snap = "none"
    end
end]]



local lTime = 0

local sysErr
local sysEnabled = false

function lOS.bsod(msg)
    sysErr = msg
end

function lOS.sysUpdate(v)
    if v then
        sysEnabled = true
    else
        sysEnabled = false
    end
end

local sysTimer

local function system()
    local timer = 0
    lOS.sysUI = lOS.execute("LevelOS/SystemUI.lua","background")

    local response,err = http.post("https://old.leveloper.cc/sGet.php","path="..textutils.urlEncode("").."&name="..textutils.urlEncode("LevelOS_Beta_1251278571250123"),{Cookie=lOS.userID})
    if response then
        local f = response.readAll()
        local vtemp = lUtils.getField(f,"version")
        local servertimestamp = tonumber(vtemp)
        local clienttimestamp
        if fs.exists("LevelOS/data/version.txt") then
            clienttimestamp = tonumber(fread("LevelOS/data/version.txt"))
        end
        if not clienttimestamp then
            clienttimestamp = 0
        end
        if servertimestamp > clienttimestamp then
            if fs.exists("LevelOS/Beta_Updater.lua") then
                fs.delete("LevelOS/Beta_Updater.lua")
            end
            shell.run("lStore get Beta_Updater LevelOS/Beta_Updater.lua")
            os.sleep(1)
            if fs.exists("LevelOS/Beta_Updater.lua") then
                lOS.execute("LevelOS/Beta_Updater.lua")
            end
        end
    end

    --[[if not fs.exists("rom/apis/http/http.lua") then
        local function wrapRequest(_url, ...)
            local ok, err = http.request(...)
            if ok then
                while true do
                    local e = {os.pullEvent()}
                    if e[1] == "http_success" and e[2] == _url then
                        return e[3]
                    elseif event == "http_failure" and e[2] == _url then
                        return nil, e[3], e[4]
                    end
                end
            end
            return nil, err
        end

        function http.post(_url, _post, _headers, _binary)
            if type(_url) == "table" then
                return wrapRequest(_url.url, _url)
            else
                return wrapRequest(_url, _url, _post, _headers, _binary)
            end
        end

        function http.get(_url, _headers, _binary)
            if type(_url) == "table" then
                return wrapRequest(_url.url, _url)
            else
                return wrapRequest(_url, _url, nil, _headers, _binary)
            end
        end
    end]]

    while true do
        if ranstartup == false and lOS.fadeComplete then
            local sProgs = fs.list("LevelOS/startup")
            for t=1,#sProgs do
                if sProgs[t] ~= "lUtils.lua" and not string.find(sProgs[t],"updater") then
                    --print("Running "..sProgs[t].."...")
                    lOS.execute(fs.combine("LevelOS/startup",sProgs[t]),"background")
                end
            end
            ranstartup = true
        end
        if sysEnabled then
            local nsysTimer = os.startTimer(0.1)
            local ev = {}
            while ev[1] ~= "timer" or ev[2] ~= nsysTimer do
                ev = table.pack(os.pullEventRaw())
            end
            sysTimer = nsysTimer
            lTime = lTime+0.02
        else
            coroutine.yield()
        end
        if not lOS.sysUI.env then
            error("SystemUI: CRITICAL_PROCESS_DIED",0)
        end
        if sysErr then
            error(tostring(sysErr),0)
        end
    end
end



proc[1] = {coroutine.create(system),title="System",path="LevelOS/system.lua",win=window.create(wAll,1,1,51,19,false),winMode="background"}
lOS.system = proc[1]


local function getPixel(win,x,y)
    theline = {win.getLine(y)}
    return string.sub(theline[1],x,x),string.sub(theline[2],x,x),string.sub(theline[3],x,x)
end

local set = lOS.settings

local previewrect


--for p=0,#proc do
    --coroutine.resume(process[1])
--end

local cProc = 0

function lOS.execute(path,mode,wX,wY,wW,wH,focus)
    local aliases = {
        ["LevelOS/explorer.lua"] = "Program_Files/LevelOS/Explorer",
        ["LevelOS/LevelCloud.lua"] = "Program_Files/LevelOS/Cloud",
        ["LevelOS/notepad.lua"] = "Program_Files/LevelOS/Notepad",
        ["LevelOS/Pigeon.lua"] = "Program_Files/Pigeon",
    }
    _G.debugpath = path
    local tempargs
    if type(path) == "table" then
        tempargs = path
        path = tempargs[1]
        table.remove(tempargs,1)
    end

    local tPath = ""
    local rPath
    local args
    if not tempargs then
        rPath = string.sub(path,string.find(path,"%S+"))
        local b,e = string.find(path,"%S+")
        tPath = string.sub(path,e+2,string.len(path))
        args = {}
        for i in string.gmatch(tPath,"%S+") do
            if i ~= nil and i ~= "" then
                args[#args+1] = i
            end
        end
    else
        rPath = path
        args = tempargs
    end
    _G.debugargs = args
    if lUtils.getFileType(rPath) == ".llnk" then
        local link = lUtils.asset.load(rPath)
        if link[1] and fs.exists(link[1]) then
            local cmd = link[1]
            local args2 = link.args
            if args2 and #args > 0 then
                cmd = cmd.." "..table.concat(args2, " ")
            end
            if args and #args > 0 then
                cmd = cmd.." "..table.concat(args," ")
            end
            return lOS.execute(cmd,mode,wX,wY,wW,wH,focus)
        end
    end
    if aliases[rPath] then
        rPath = aliases[rPath]
    end
    if fs.isDir(rPath) then
        local files = fs.list(rPath)
        local runfile = false
        if fs.exists(fs.combine(rPath,"main.lua")) then
            runfile = true
            rPath = fs.combine(rPath,"main.lua")
        else
            for f=1,#files do
                local fP = fs.combine(rPath,files[f])
                if not fs.isDir(fP) then
                    if lUtils.getFileType(files[f]) == ".lua" then
                        rPath = fP
                        runfile = true
                        break
                    end
                end
            end
        end
        if not runfile then
            return false,"No lua file found in this folder."
        end
    end

    local w,h = oldterm.getSize()
    local thewin
    if mode == "maximized" then
        local tw,th = lOS.wAll.getSize()
        thewin = window.create(oldterm,1,2,tw,th-1-lOS.tbSize)
        mode = "windowed"
    elseif wX and wY and wW and wH then
        thewin = window.create(oldterm,wX,wY,wW,wH,false)
    elseif w <= 60 or h < 21 or (set.maxAll == true) then
        thewin = window.create(oldterm,1,2,w,h-3,false)
    else
        local x,y = 7,7
        local w,h = 51,19
        local tw,th = lOS.wAll.getSize()
        if lOS.tbSize then
            th = th-(lOS.tbSize-1)
        end
        for i,proc in ipairs(lOS.wins) do
            if proc.path == rPath then
                local nx,ny,nw,nh
                if not proc.snap then
                    nx,ny = proc.win.getPosition()
                    nw,nh = proc.win.getSize()
                else
                    nx,ny = unpack(proc.snap.oPos)
                    nw,nh = unpack(proc.snap.oSize)
                end
                w,h = nw,nh
                if nx+nw >= tw or ny+nh >= th then
                    x,y = 3,3
                else
                    x,y = nx+2,ny+1
                end
            end
        end
        thewin = window.create(oldterm,x,y,w,h,false)
    end
    local nPath = rPath
    if fs.getName(nPath) == "main.lua" then
        nPath = fs.getDir(nPath)
    end
    local t = lUtils.getFileName(nPath)
    t = t:sub(1,1):upper()..t:sub(2)
    local process = {title=t,win=thewin,winMode=mode or "windowed",path=rPath}
    local function func()
        local oWin = thewin
        local a = {lOS.run(rPath,process,table.unpack(args))}
        if a[1] == false then
            if process.winMode ~= "background" then
                term.redirect(oWin)
                local b = {lUtils.popup(fs.getName(rPath),fs.getName(rPath).." has stopped working.",29,9,{"OK","View Error"})}
                if b[3] == "View Error" then
                    lUtils.popup(fs.getName(rPath),a[2],31,nil,{"OK"})
                end
            else
                lOS.notification(fs.getName(rPath).." has stopped working.")
            end
        end
    end
    process[1] = coroutine.create(func)
    for i = 0, 15 do process.win.setPaletteColor(2^i, lOS.wins[0].win.getPaletteColor(2^i)) end
    table.insert(lOS.processes,process)
    local oterm = term.current()
    term.redirect(process.win)
    local oldcproc = cProc
    cProc = #lOS.processes
    process.id = cProc
    coroutine.resume(process[1])
    cProc = oldcproc
    term.redirect(oterm)
    if mode ~= "background" then
        os.queueEvent("window_open",#lOS.processes,tostring(process),focus)
    end
    return process
end

term.redirect(proc[0].win)
function lOS.getRunningProcess()
    return proc[cProc]
end
coroutine.resume(proc[0][1])
term.redirect(oldterm)

local oldwin = {}
local isFullscreen = false
local tbSize
lOS.nYieldTime = 0
lOS.eventsPassed = 0
local oYieldTime = os.epoch("utc")

local forceResumeID = 0
function lOS.queueForceResume()
    forceResumeID = forceResumeID + 1
    os.queueEvent("levelos_force_resume", forceResumeID)
    return forceResumeID
end

local function hook(event)
    local proc = lOS.getRunningProcess()
    if proc then
        local cStat = coroutine.status(proc[1])
        if cStat == "running" or cStat == "normal" then
            if os.epoch("utc") > proc.lastYield+1000 then
                if os.epoch("utc") > proc.lastYield+5000 then
                    proc.unresponsive = true
                end
                if not proc.eventQueue then
                    proc.eventQueue = {}
                end
                if not proc.systemYield then
                    proc.systemYield = lOS.queueForceResume()
                end
                proc.lastInterrupt = os.epoch("utc")
                while true do
                    local e = table.pack(coroutine.yield())
                    if e[1] == "levelos_force_resume" then
                        proc.systemYield = nil
                        proc.unresponsive = nil
                        break
                    else
                        table.insert(proc.eventQueue, e)
                    end
                end
            end
        end
    end
end

local requestCache
if fs.exists("rom/apis/http/http.lua") then
    local nativeHTTPRequest = http.request

    requestCache = {}
    lOS.requestCache = requestCache

    function http.request(_url, _post, _headers, _binary)
        local data
        if type(_url) == "table" then
            data = _url
        else
            data = {url=_url, body=_post, headers=_headers, binary=_binary}
        end
        local oldURL = data.url
        while requestCache[data.url] do
            if data.url:find("#", nil, true) then
                data.url = data.url.."0"
            else
                data.url = data.url.."#"
            end
        end
        requestCache[data.url] = {url=oldURL, binary=data.binary, process=lOS.getRunningProcess()}

        data.binary = true
        local ok, err = nativeHTTPRequest(data)
        if not ok then
            os.queueEvent("http_failure", data.url, err)
        end

        return ok, err
    end

    local restore = {
        checkURL = http.checkURL,
        websocket = http.websocket,
        websocketAsync = http.websocketAsync,
    }
    os.loadAPI("rom/apis/http/http.lua")
    for key, value in pairs(restore) do
        http[key] = value
    end
else
    
end

local function resumeProcess(process, e)
    if not (process.sFilter and process.sFilter ~= e[1]) then
        if process.eventQueue and not process.systemYield then
            local queue = process.eventQueue
            process.eventQueue = nil
            for i, event in ipairs(queue) do
                process.lastYield = os.epoch("utc")
                resumeProcess(process, event)
            end
        end

        if not process.systemYield then
            process.lastYield = os.epoch("utc")
        end

        local cSuccess,cFilter = coroutine.resume(process[1],table.unpack(e, 1, e.n))
        if cSuccess then
            process.sFilter = cFilter
        elseif process == lOS.system or process == lOS.systemUI then
            _G.theSystemError = cFilter
            error(cFilter,0)
        end
    end
end

local function increaseBrightness(colors, brightnessFactor)
    local brightenedColors = {}

    for _, color in ipairs(colors) do
        local brightenedColor = {
            math.min(color[1] + brightnessFactor, 1),
            math.min(color[2] + brightnessFactor, 1),
            math.min(color[3] + brightnessFactor, 1)
        }
        table.insert(brightenedColors, brightenedColor)
    end

    return brightenedColors
end

local function colorDistance(color1, color2)
    if type(color1) == "number" then
        color1 = {term.getPaletteColor(color1)}
    end
    if type(color2) == "number" then
        color2 = {term.getPaletteColor(color2)}
    end
    local rDiff = color1[1]+0.2 - color2[1]
    local gDiff = color1[2]+0.2 - color2[2]
    local bDiff = color1[3]+0.2 - color2[3]
    return (rDiff * rDiff + gDiff * gDiff + bDiff * bDiff) ^ 0.5
end

local function findClosestColor(targetColor, colorArray)
    local closestColor = nil
    local minDistance = math.huge

    for _, color in ipairs(colorArray) do
        local distance = colorDistance(targetColor, color)
        if distance < minDistance then
            minDistance = distance
            closestColor = color
        end
    end

    return closestColor
end

local function genGrayscale(win)
    local replace = {}
    local grays = {colors.black, colors.gray, colors.lightGray, colors.white}
    for i=0,15 do
        replace[lUtils.toBlit(2^i)] = lUtils.toBlit(findClosestColor(2^i, grays))
    end
    
    local lines = {}
    local w,h = win.getSize()
    for y=1,h do
        local line = {win.getLine(y)}
        for i=2,3 do
            line[i] = line[i]:gsub(".", function(str) return replace[str] end)
        end
        table.insert(lines, line)
    end
    return lines
end

_G.genGrayscale = genGrayscale

local function refreshProc(e)
    term.redirect(wAll)
    local w,h = term.getSize()
    --for i = 0, 15 do term.setPaletteColor(2^i, term.nativePaletteColor(2^i)) end
    local topwin
    local oTime = os.epoch("utc")
    local nTime = oTime
    for p=0,#proc do
        cProc = p
        local oProcTime = os.epoch("utc")
        if proc[p] == nil then break end
        proc[p].id = p
        local process = proc[p]
        if not process.hasHook then
            debug.sethook(process[1], hook, "", 50)
        end
        if process.win ~= nil then
            if not process.owin then
                process.owin = process.win
            end
            term.redirect(process.owin)
            if process.winMode == "fullscreen" and process.minimized then
                process.win.setVisible(false)
            end
        else
            term.redirect(lOS.depWin)
        end
        -- filter events
        local cWin
        lOS.cWin = nil
        local n = #lOS.wins
        while lOS.wins[n] ~= nil do
            if lOS.wins[n] == process then
                cWin = n
                lOS.cWin = cWin
                break
            else
                n = n-1
            end
        end
        local alreadydone = false
        if e[1] == "levelos_force_resume" then
            alreadydone = true
            --_G.debugforceresume = e
            if process.systemYield == e[2] then
                --_G.debugforceres = e
                local cSuccess, cFilter = coroutine.resume(process[1], table.unpack(e, 1, e.n))
                if cSuccess then
                    process.sFilter = cFilter
                elseif process == lOS.system or process == lOS.systemUI then
                    _G.theSystemError = cFilter
                    error(cFilter, 0)
                end
            end
        elseif (e[1] == "http_success" or e[1] == "http_failure") and requestCache then
            if not requestCache[e[2]] then
                lOS.notification("Error!", "Invalid request to "..e[2])
                break
            else
                --alreadydone = true
                break
            end
        elseif process == lOS.focusWin or not (e[1] == "key" or e[1] == "key_up" or e[1] == "char" or e[1] == "paste" or e[1] == "terminate" or e[1] == "term_resize" or (sysTimer and e[1] == "timer" and e[2] == sysTimer and process ~= lOS.system)) then
            local a = lUtils.instantiate(e)
            if string.find(a[1],"mouse") and ((a[1] ~= "mouse_up" and a[1] ~= "mouse_drag") or process == lOS.focusWin) and process.winMode ~= "background" and cWin and e[4] and e[4] < h-(lOS.tbSize-1) then
                local winX,winY = process.win.getPosition()
                local winW,winH = process.win.getSize()
                if (e[3] >= winX and e[4] >= winY and e[3] < winX+winW and e[4] < winY+winH) or (process.winMode == "windowed" and e[3] >= winX-1 and e[4] >= winY-1 and e[3] < winX+winW+1 and e[4] < winY+winH+1) then -- actually it does work
                    if topwin == nil then
                        topwin = process
                        if not (e[3] >= winX and e[4] >= winY and e[3] < winX+winW and e[4] < winY+winH) then
                            topwin = nil
                        end
                    else
                        for b=0,#lOS.wins do
                            if lOS.wins[b] == process then
                                break
                            elseif lOS.wins[b] == topwin then
                                topwin = process
                                if not (e[3] >= winX and e[4] >= winY and e[3] < winX+winW and e[4] < winY+winH) then
                                    --lOS.notification("Detected border press! Topwin canceled.")
                                    topwin = nil
                                end
                                break
                            end
                        end
                    end
                elseif process.winMode == "widget" and e[1] == "mouse_click" then
                    process[1] = coroutine.create(function() return end)
                end
            elseif not string.find(a[1],"mouse") and not (lOS.noEvents and process == lOS.focusWin and (e[1] == "key" or e[1] == "key_up" or e[1] == "char" or e[1] == "paste" or e[1] == "terminate" or e[1] == "term_resize")) then
                if not (process.events and process.events == "all") then
                    alreadydone = true
                    resumeProcess(process, e)
                end
            end
        end
        if e[1] ~= "levelos_force_resume" and process.events and process.events == "all" and not alreadydone then
            if not (process.sFilter and process.sFilter ~= e[1]) then
                resumeProcess(process, e)
            end
        end
        if process.win then
            process.owin = term.current()
        end
        local nProcTime = os.epoch("utc")
        if topwin ~= process then
            if not process.timeCounter then
                process.timeCounter = 0
            end
            process.timeCounter = process.timeCounter+(nProcTime-oProcTime)
            nTime = nTime+(nProcTime-oProcTime)
        end
    end
    if lOS.noEvents then
        topwin = nil
    end
    if requestCache and (e[1] == "http_success" or e[1] == "http_failure") and requestCache[e[2]] then
        local req = requestCache[e[2]]
        requestCache[e[2]] = nil
        local ev = table.pack(table.unpack(e, 1, e.n))
        ev[2] = req.url
        if e[1] == "http_success" and not req.binary then
            ev[3] = {}
            for k,v in pairs(e[3]) do
                ev[3][k] = function(...) return lOS.utf8.decodeAll(v(lOS.utf8.encodeAll(...))) end
            end
        end
        cProc = req.process.id
        local process = req.process
        local oterm = term.current()
        if process.win ~= nil then
            if not process.owin then
                process.owin = process.win
            end
            term.redirect(process.owin)
            if process.winMode == "fullscreen" and process.minimized then
                process.win.setVisible(false)
            end
        else
            term.redirect(lOS.depWin)
        end
        resumeProcess(process, ev)
        term.redirect(oterm)
        if not lOS.reqlog then lOS.reqlog = {} end
        req.event = ev
        table.insert(lOS.reqlog, req)
    elseif e[1] ~= "levelos_force_resume" and topwin ~= nil then
        term.redirect(topwin.owin)
        local winX,winY = topwin.win.getPosition()
        if topwin.owin ~= topwin.win and topwin.owin.getPosition then
            local winX2,winY2 = topwin.owin.getPosition()
            winX = winX+(winX2-1)
            winY = winY+(winY2-1)
        end
        local winW,winH = topwin.owin.getSize()
        local a = lUtils.instantiate(e)
        a[3] = a[3]-winX+1
        a[4] = a[4]-winY+1
        if not (topwin.events and topwin.events == "all") then
            if not (topwin.sFilter and topwin.sFilter ~= a[1] and topwin.sFilter ~= "terminate") then
                local cWin
                lOS.cWin = nil
                local n = #lOS.wins
                while lOS.wins[n] ~= nil do
                    if lOS.wins[n] == topwin then
                        cWin = n
                        lOS.cWin = cWin
                        break
                    else
                        n = n-1
                    end
                end
                local oProcTime = os.epoch("utc")
                cProc = topwin.id
                resumeProcess(topwin, a)
                topwin.owin = term.current()
                local nProcTime = os.epoch("utc")
                if not topwin.timeCounter then
                    topwin.timeCounter = 0
                end
                topwin.timeCounter = topwin.timeCounter+(nProcTime-oProcTime)
                nTime = nTime+(nProcTime-oProcTime)
            end
        end
        if topwin.title ~= nil then
            --lOS.notification("You clicked on process "..topwin.title)
        end
    end
    cProc = 0
    for w=0,#lOS.wins do
        while lOS.wins[w] ~= nil and lOS.wins[w].winMode == "background" do
            table.remove(lOS.wins,w)
        end
    end

    if lOS.focusWin and lOS.focusWin.winMode == "fullscreen" then
        local win = lOS.focusWin.win
        term.redirect(oldterm)
        local winW,winH = win.getSize()
        local winX,winY = win.getPosition()
        local totW,totH = oldterm.getSize()
        if not lOS.focusWin.fullscreen then
            lOS.focusWin.fullscreen = {pos={winX,winY},size={winW,winH}}
        end
        if winX ~= 1 or winY ~= 1 or winW ~= totW or winH ~= totH or isFullscreen == false then
            win.reposition(1,1,totW,totH,oldterm)
            win.setVisible(true)
            os.queueEvent("term_resize")
            if not isFullscreen then
                win.redraw()
                isFullscreen = true
                tbSize = lOS.tbSize
                lOS.tbSize = 0
            end
        end
    else
        if tbSize then
            lOS.tbSize = tbSize
            tbSize = nil
        end
        term.redirect(wAll)
        --[[local twrite = term.write
        local tblit = term.blit
        function term.write(...)
            if ({term.getCursorPos()})[2] <= ({term.getSize()})[2] then
                return twrite(...)
            end
        end
        function term.blit(...)
            if ({term.getCursorPos()})[2] <= ({term.getSize()})[2] then
                return tblit(...)
            end
        end]]
        for w=0,#lOS.wins do
            log("Processing window "..w)
            local winW,winH = lOS.wins[w].win.getSize()
            local winX,winY = lOS.wins[w].win.getPosition()
            if w == lOS.focusWin and previewrect ~= nil then
                term.setCursorPos(previewrect.x,previewrect.y)
                term.setTextColor(colors.lightBlue)
                for a=1,previewrect.w do
                    term.setBackgroundColor(lUtils.toColor(({getPixel(wAll,previewrect.x+(a-1),previewrect.y)})[3]))
                    term.write("\129")
                end
                for a=1,previewrect.h do
                    term.setBackgroundColor(lUtils.toColor(({getPixel(wAll,previewrect.x,previewrect.y+(a-1))})[3]))
                    term.setCursorPos(previewrect.x,previewrect.y+(a-1))
                    term.write("\132")
                    term.setBackgroundColor(lUtils.toColor(({getPixel(wAll,previewrect.x+(previewrect.w-1),previewrect.y+(a-1))})[3]))
                    term.setCursorPos(previewrect.x+(previewrect.w-1),previewrect.y+(a-1))
                    term.write("\136")
                end
                term.setCursorPos(previewrect.x,previewrect.y+(previewrect.h-1))
                for a=1,previewrect.w do
                    term.setBackgroundColor(lUtils.toColor(({getPixel(wAll,previewrect.x+(a-1),previewrect.y+(previewrect.h-1))})[3]))
                    term.write("\144")
                end
            end
            if lOS.wins[w].winMode == "fullscreen" and w ~= lOS.focusWin then
                -- minimize
                os.queueEvent("window_minimize",w,tostring(lOS.wins[w]))
            elseif lOS.wins[w].winMode == "screen" then
                for l=1,winH do
                    term.setCursorPos(1,l)
                    term.blit(lOS.wins[w].win.getLine(l))
                end
            elseif lOS.wins[w].winMode == "borderless" or lOS.wins[w].winMode == "widget" then
                --log("Drawing borderless window "..w.." from line "..(winY-winY+1).." to "..((winY+(winH-1))-winY+1))
                for l=winY,winY+(winH-1) do
                    term.setCursorPos(winX,l)
                    term.blit(lOS.wins[w].win.getLine(l-winY+1))
                end
            elseif lOS.wins[w].winMode == "windowed" then
                local width = winW+2
                local height = winH+2
                winX = winX-1
                winY = winY-1
                local bPos = 1
                --local w,h = wAll.getSize()
                local wW,wH = wAll.getSize()
                if (winX + (width-1)) > wW then
                --if lOS.wins[w].maximized == true then
                    bPos = 0
                end
                local wincolor = colors.lightGray
                if lOS.wins[w].winColor then
                    wincolor = lOS.wins[w].winColor
                elseif lOS.wins[w] == lOS.focusWin and not (lOS.noEvents and lOS.noEvents ~= 2) then
                    wincolor = colors.gray
                end
                term.setBackgroundColor(wincolor)
                term.setCursorPos(winX,winY)
                for t=1,width-(10-bPos) do
                    term.write(" ")
                end
                term.setTextColor(colors.white)
                if lOS.wins[w].resizable == nil then
                    lOS.wins[w].resizable = true
                end
                term.setTextColor(colors.white)
                if lOS.wins[w] == lOS.focusWin and not (lOS.noEvents and lOS.noEvents ~= 2) then
                    if wButton == 1 then
                        term.setBackgroundColor(colors.lightGray)
                    else
                        term.setBackgroundColor(wincolor)
                    end
                    term.write(" - ")
                    if wButton == 2 then
                        term.setBackgroundColor(colors.lightGray)
                    else
                        term.setBackgroundColor(wincolor)
                    end
                    if lOS.wins[w].resizable == false then
                        term.setTextColor(colors.lightGray)
                    else
                        term.setTextColor(colors.white)
                    end
                    term.write(" + ")
                    term.setTextColor(colors.white)
                    if wButton == 3 then
                        term.setBackgroundColor(colors.red)
                    else
                        term.setBackgroundColor(wincolor)
                    end
                    term.write(" × ")
                    term.setBackgroundColor(wincolor)
                else
                    term.setBackgroundColor(wincolor)
                    term.setTextColor(colors.gray)
                    term.write(" -  +  × ")
                end
                if bPos == 0 then
                    term.write(" ")
                end
                term.setCursorPos(winX+1,winY)
                if lOS.wins[w].icon ~= nil then
                    if type(lOS.wins[w].icon) == "table" then
                        term.blit(lOS.wins[w].icon[1],(lOS.wins[w].icon[2] or lUtils.toBlit(term.getBackgroundColor())),(lOS.wins[w].icon[3] or lUtils.toBlit(term.getBackgroundColor())))
                    elseif type(lOS.wins[w].icon) == "string" then
                        term.write(lOS.wins[w].icon)
                    end
                    term.write(" ")
                end
                if lOS.wins[w].title ~= nil then
                    term.write(lOS.wins[w].title)
                end
                if lOS.wins[w].unresponsive then
                    term.write(" (Not responding)")
                end
                term.setTextColor(wincolor)
                local progWin = lOS.wins[w].win

                local lines = {}
                if lOS.wins[w].unresponsive then
                    lines = genGrayscale(progWin)
                    _G.debuglines = lines
                else
                    for i=1,height-2 do
                        lines[i] = {progWin.getLine(i)}
                    end
                end

                local function pixel(x, y)
                    return lines[y][1]:sub(x,x), lines[y][2]:sub(x,x), lines[y][3]:sub(x,x)
                end


                for i=1,height-2 do
                    term.setCursorPos(winX,winY+i)
                    term.blit(string.char(149),lUtils.toBlit(wincolor),({pixel(1,i)})[3])
                    term.blit(table.unpack(lines[i]))
                    term.blit(string.char(149),({pixel(width-2,i)})[3],lUtils.toBlit(wincolor))
                end
                local bottomline = {string.char(138),({pixel(1,height-2)})[3],lUtils.toBlit(wincolor)}
                for i=1,width-2 do
                    bottomline[1] = bottomline[1]..string.char(143)
                    bottomline[2] = bottomline[2]..({pixel(i,height-2)})[3]
                    bottomline[3] = bottomline[3]..lUtils.toBlit(wincolor)
                end
                bottomline[1] = bottomline[1]..string.char(133)
                bottomline[2] = bottomline[2]..({pixel(width-2,height-2)})[3]
                bottomline[3] = bottomline[3]..lUtils.toBlit(wincolor)
                term.setCursorPos(winX,winY+(height-1))
                term.blit(table.unpack(bottomline))
            else
                log("Something went wrong with window "..w)
            end
        end
        for w=0,#proc do
            if proc[w].env ~= nil and proc[w].env.LevelOS ~= nil and proc[w].env.LevelOS.overlay ~= nil then
                coroutine.resume(coroutine.create(proc[w].env.LevelOS.overlay))
            end
        end
        local w,h = term.getSize()
        term.setCursorPos(1,1)
        --[[if #lOS.notifications > 0 then
            term.setBackgroundColor(colors.orange)
            term.setTextColor(colors.white)
            lUtils.textbox(lOS.notifications[1].txt,w-20,h-7,w,h-5)
        end]]
        term.redirect(oldterm)
        if lOS.focusWin then
            for i = 0, 15 do term.setPaletteColor(2^i, lOS.focusWin.win.getPaletteColor(2^i)) end
        end
        --local w,h = oldterm.getSize()
        --term.setBackgroundColor(colors.orange)
        --term.setTextColor(colors.white)
        --lOS.boxClear(w-20,h-7,w,h-5)
        --term.setCursorPos(w-19,h-6)
        --term.write(textutils.serialize(lOS.wins))
        --term.write("Yooo")
        --term.redirect(oldterm)
        for l=1,({wAll.getSize()})[2] do
            if isFullscreen or oldwin[l] == nil or lUtils.compare(oldwin[l],{wAll.getLine(l)}) == false then
                term.setCursorPos(1,l)
                oldwin[l] = {wAll.getLine(l)}
                term.blit(unpack(oldwin[l]))
            end
        end
        if isFullscreen then
            isFullscreen = false
        end
        --[[for t=1,h do
            oldwin[t] = {wAll.getLine(t)}
        end]]

        --term.setCursorPos(1,1)
        --term.setBackgroundColor(colors.black)
        --term.setTextColor(colors.white)
        --write(lOS.log)
        --[[taskbar(e)]]
        --for i = 0, 15 do term.setPaletteColor(2^i, term.nativePaletteColor(2^i)) end
    end
    lOS.nYieldTime = lOS.nYieldTime+(nTime-oTime)
    lOS.eventsPassed = lOS.eventsPassed+1
    if os.epoch("utc") >= oYieldTime+5000 then
        lOS.yieldTime = lOS.nYieldTime/lOS.eventsPassed
        for i,process in ipairs(lOS.processes) do
            if process.timeCounter then
                process.yieldTime = process.timeCounter/lOS.eventsPassed
                process.timeCounter = 0
            end
        end
        lOS.nYieldTime = 0
        lOS.eventsPassed = 0
        oYieldTime = os.epoch("utc")
    end
end

local holding = {}

if lUtils then
    lUtils.isHolding = nil
end

local function manage()
    if lUtils ~= nil and lUtils.isHolding == nil then
        function lUtils.isHolding(key)
            if type(key) == "string" then
                key = keys[key]
            end
            if holding[key] == nil or holding[key] == false then
                return false
            else
                return true
            end
        end
    end
    local dragging
    local dragon = false -- i can not come up with more variable names ffs
    local dragSide
    local dragX,dragY = false,false
    local DRx,DRy
    local OGw,OGh
    local OGx,OGy
    while true do
        if lOS.focusWin then
            local tempX,tempY = lOS.focusWin.win.getPosition()
            local tempW,tempH = lOS.focusWin.win.getSize()
            local tempX2,tempY2 = (tempX-1)+({lOS.focusWin.win.getCursorPos()})[1],(tempY-1)+({lOS.focusWin.win.getCursorPos()})[2]
            if tempY2 <= ({term.getSize()})[2] and tempX2 >= tempX and tempY2 >= tempY and tempX2 <= tempX+(tempW-1) and tempY2 <= tempY+(tempH-1) then
                lOS.focusWin.win.restoreCursor()
                term.setCursorBlink(lOS.focusWin.win.getCursorBlink())
                term.setCursorPos(tempX2,tempY2)
                term.setTextColor(lOS.focusWin.win.getTextColor())
            else
                term.setCursorBlink(false)
            end
        end
        for t=1,#lOS.processes do
            if coroutine.status(lOS.processes[t][1]) == "dead" then
                local win
                for n=1,#lOS.wins do
                    if lOS.wins[n] == lOS.processes[t] then
                        --table.remove(lOS.wins,n)
                        win = n
                        break
                    end
                end
                if win and not lOS.wins[win].isClosing then
                    if not lOS.sysUIlog then
                        lOS.sysUIlog = {}
                    end
                    table.insert(lOS.sysUIlog,"Closed win "..t.." because the process died.")
                    os.queueEvent("window_close",win,tostring(lOS.wins[win]),"system closed cuz ded")
                    lOS.wins[win].isClosing = true
                else
                    table.remove(lOS.processes,t)
                    break
                end
            end
        end
        if lOS.focusWin then
            for i = 0, 15 do term.setPaletteColor(2^i, lOS.focusWin.win.getPaletteColor(2^i)) end
        end
        local e = table.pack(os.pullEventRaw())

        local systemPresent = false
        local sysUIPresent = false
        for p=1,#lOS.processes do
            if lOS.processes[p] == lOS.system then
                systemPresent = true
            elseif lOS.processes[p] == lOS.sysUI then
                sysUIPresent = true
            end
        end
        if not systemPresent then
            error("CRITICAL_PROCESS_DIED",0)
        elseif lOS.sysUI and lOS.sysUI.env and not sysUIPresent then
            error("SystemUI: CRITICAL_PROCESS_DIED",0)
        end
        if e[1] == "term_resize" then
            local w1,h1 = term.getSize()
            local w2,h2 = lOS.wAll.getSize()
            if w1 ~= w2 or h1 ~= h2 then
                lOS.wAll.reposition(1,1,w1,h1)
                lOS.depWin.reposition(1,1,w1,h1)
                oldwin = {}
                local totalW,totalH = lOS.wAll.getSize()
                if lOS.tbSize then
                    totalH = totalH-lOS.tbSize
                end
                lOS.wins[0].win.reposition(1,1,w1,h1)
                for i,win in ipairs(lOS.wins) do
                    local oldX, oldY = win.win.getPosition()
                    local oldWidth, oldHeight = win.win.getSize()
                    local newX, newY
                    local newWidth, newHeight

                    if win.snap then
                        if win.snap.x then
                            newWidth = totalW
                        end

                        if win.snap.y then
                            if win.winMode == "windowed" then
                                newHeight = totalH-1
                            else
                                newHeight = totalH
                            end
                        end
                    end

                    local width, height = newWidth or oldWidth, newHeight or oldHeight

                    if oldX >= totalW or oldY >= totalH or oldX+width-1 <= 1 or oldY+height-1 <= 1 then
                        newX, newY = 4,4
                    end

                    win.win.reposition(newX or oldX, newY or oldY, width, height)
                end
            end
        end
    if e[1] == "paste" and e[2] == " " then
        e[2] = ""
    end
        if e[1] == "key" then
            holding[e[2]] = true
        elseif e[1] == "key_up" then
            holding[e[2]] = false
        end
        --for i = 0, 15 do term.setPaletteColor(2^i, term.nativePaletteColor(2^i)) end
        if e[1] == "mouse_move" then
            hX,hY = e[3],e[4]
        end
        local tempW,tempH = term.getSize()
        if string.find(e[1],"mouse") and (e[3] ~= nil and e[4] <= (tempH-lOS.tbSize)) and not lOS.noEvents then
            local focusWin = 0
            for t=1,#lOS.wins do
                local winX,winY = lOS.wins[t].win.getPosition()
                local winW,winH = lOS.wins[t].win.getSize()
                local w,h = wAll.getSize()
                if lOS.tbSize then
                    h = h-lOS.tbSize
                end
                if (e[3] >= winX and e[4] >= winY and e[3] < winX+winW and e[4] < winY+winH) or (lOS.wins[t].winMode == "windowed" and e[3] >= winX-1 and e[4] >= winY-1 and e[3] < winX+winW+1 and e[4] < winY+winH+1) then -- fixed
                    focusWin = t
                end
            end
            local bPos = 1
            local tempwin = lOS.wins[focusWin]
            local winX,winY = tempwin.win.getPosition()
            local winW,winH = tempwin.win.getSize()
            local totalW,totalH = lOS.wAll.getSize()
            if lOS.tbSize then
                totalH = totalH-lOS.tbSize
            end
            if winX+(winW-1) >= totalW --[[tempwin.maximized ~= nil and tempwin.maximized == true]] then
                bPos = 0
            end
            if e[1] == "mouse_click" and focusWin > 0 and (tempwin ~= lOS.focusWin) then
                table.remove(lOS.wins,focusWin)
                lOS.wins[#lOS.wins+1] = tempwin
                lOS.focusWin = tempwin
            end
            if e[1] == "mouse_drag" and dragging ~= nil then
                local winX,winY = dragging.win.getPosition()
                local winW,winH = dragging.win.getSize()
                if dragon == true then
                    if dragging.snap and (dragging.snap.x and dragging.snap.y) then
                        local rx = (DRx-(winX-1))/(winW-9)
                        winX = e[3]-math.ceil(rx*(dragging.snap.oSize[1]-9))
                        winW = dragging.snap.oSize[1]
                        winH = dragging.snap.oSize[2]
                        dragging.snap = nil
                        OGx,OGy = winX,winY
                    else
                        winX = OGx-(DRx-e[3])
                    end
                    if dragging.snap and dragging.snap.y then
                        if DRy-e[4] <= -2 then
                            winY = OGy-(DRy-e[4])
                            dragging.snap = nil
                            dragging.win.reposition(winX,winY,winW,h-7)
                        end
                    else
                        winY = OGy-(DRy-e[4])
                    end

                    local w,h = totalW,totalH

                    -- ALL THE RIGHT SIDE STUFF IS TEMP, TO SEE WHAT POSITION IT SHOULD BE ON. IT SHOULD BE RELATIVE TO THE SIZE OF A POTENTIAL LEFT SIDE SPLITSCREENED WINDOW

                    if e[3] == w and e[4] == 1 then
                        previewrect = {x=math.ceil(w/2)+1,y=2,w=math.floor(w/2)-1,h=math.floor((h)/2)-2}
                    elseif e[3] == w and e[4] == h then
                        previewrect = {x=math.ceil(w/2)+1,y=math.floor((h)/2)+2,w=math.floor(w/2)-1,h=math.floor((h)/2)-2}
                    elseif e[3] == w then
                        previewrect = {x=math.ceil(w/2)+1,y=2,w=math.floor(w/2)-1,h=h-2}


                    elseif e[3] == 1 and e[4] == 1 then
                        previewrect = {x=2,y=2,w=math.floor(w/2)-2,h=math.floor((h)/2)-2}
                    elseif e[3] == 1 and e[4] == h then
                        previewrect = {x=2,y=math.floor((h)/2)+2,w=math.floor(w/2)-2,h=math.floor((h)/2)-2}
                    elseif e[3] == 1 then
                        previewrect = {x=2,y=2,w=math.floor(w/2)-2,h=h-2}
                    elseif e[4] == 1 then
                        --previewrect = {x=2,y=2,w=w-2,h=h-4}
                    else
                        previewrect = nil
                    end
                end
                if dragX == true then
                    if dragSide == 1 then
                        if OGw+(DRx-e[3]) >= 10 then
                            winW = OGw+(DRx-e[3])
                            winX = OGx-(DRx-e[3])
                        end
                    else
                        if OGw-(DRx-e[3]) >= 10 then
                            winW = OGw-(DRx-e[3])
                        end
                    end
                end
                if dragY == true then
                    if OGh-(DRy-e[4]) >= 4 then
                        winH = OGh-(DRy-e[4])
                    end
                end
                local wW,wH = dragging.win.getSize()
                local resized = false
                if wW ~= winW or wH ~= winH then
                    resized = true
                end
                dragging.win.reposition(winX,winY,winW,winH)
                if resized then
                    os.queueEvent("term_resize")
                end
            end
            local winX,winY = tempwin.win.getPosition()
            local winW,winH = tempwin.win.getSize()
            if focusWin > 0 then
                if tempwin.winMode == "windowed" and (e[1] == "mouse_click" or e[1] == "mouse_up") then
                    if e[4] == winY-1 then
                        if e[3] <= bPos+winX+winW-1 and e[3] >= bPos+winX+winW-3 then
                            if e[1] == "mouse_click" then
                                wButton = 3
                            else
                                os.queueEvent("window_close",focusWin,tostring(tempwin),"system closed cuz button click")
                            end
                        elseif e[3] <= bPos+winX+winW-4 and e[3] >= bPos+winX+winW-6 then
                            if e[1] == "mouse_click" then
                                wButton = 2
                            elseif (tempwin.resizable == nil or tempwin.resizable == true) then
                                if tempwin.snap then
                                    --tempwin.win.reposition(tempwin.snap.oPos[1],tempwin.snap.oPos[2],unpack(tempwin.snap.oSize))
                                    os.queueEvent("window_reposition",focusWin,tostring(tempwin),tempwin.snap.oPos[1],tempwin.snap.oPos[2],unpack(tempwin.snap.oSize))
                                    tempwin.snap = nil
                                else
                                    tempwin.snap = {x=true,y=true,oPos={tempwin.win.getPosition()},oSize={tempwin.win.getSize()}}
                                    --tempwin.win.reposition(1,2,totalW,totalH-1)
                                    os.queueEvent("window_reposition",focusWin,tostring(tempwin),1,2,totalW,totalH-1)
                                end
                                --os.queueEvent("term_resize")
                            end
                        elseif e[3] <= bPos+winX+winW-7 and e[3] >= bPos+winX+winW-9 then
                            if e[1] == "mouse_click" then
                                wButton = 1
                            else
                                --oop im dumb

                                -- why tf would u do this
                                --[[local n=-1
                                while lOS.wins[n] ~= nil do
                                    n = n-1
                                end
                                lOS.wins[n] = tempwin]]
                                --lOS.wins[#lOS.wins] = nil
                                os.queueEvent("window_minimize",focusWin,tostring(tempwin))
                                -- plz work
                            end
                        elseif e[1] == "mouse_click" then
                            if tempwin.dragtimestamp and tempwin.dragtimestamp+500 > os.epoch("utc") then
                                if tempwin.snap then
                                    os.queueEvent("window_reposition",focusWin,tostring(tempwin),tempwin.snap.oPos[1],tempwin.snap.oPos[2],unpack(tempwin.snap.oSize))
                                else
                                    tempwin.snap = {x=true,y=true,oPos={tempwin.win.getPosition()},oSize={tempwin.win.getSize()}}
                                    --tempwin.win.reposition(1,2,totalW,totalH-1)
                                    os.queueEvent("window_reposition",focusWin,tostring(tempwin),1,2,totalW,totalH-1)
                                end
                            else
                                dragging = tempwin
                                dragging.dragtimestamp = os.epoch("utc")
                                dragon = true
                                DRx,DRy = e[3],e[4]
                                OGx,OGy = winX,winY
                            end
                        end
                    end
                    if e[4] >= winY and e[4] <= winY+winH and (e[3] == winX-1 or e[3] == winX+winW) and e[1] == "mouse_click" and (tempwin.resizable == nil or tempwin.resizable == true) then
                        dragging = tempwin
                        DRx = e[3]
                        OGw = winW
                        OGx = winX
                        dragX = true
                        if e[3] == winX-1 then
                            dragSide = 1
                        else
                            dragSide = 2
                        end
                    end
                    if e[4] == winY+(winH) and e[3] >= winX-1 and e[3] <= winX+(winW) and e[1] == "mouse_click" and (tempwin.resizable == nil or tempwin.resizable == true) then
                        dragY = true
                        DRy = e[4]
                        OGh = winH
                        dragging = tempwin
                    end
                end
            end
            if e[1] == "mouse_up" then
                if dragon == true then
                    local w,h = totalW,totalH
                    dragging.snap = {x=false,y=true,oPos={dragging.win.getPosition()},oSize={dragging.win.getSize()}}
                    if e[3] == w and e[4] == 1 then
                        os.queueEvent("window_reposition",focusWin,tostring(tempwin),math.ceil(w/2)+1,2,math.floor(w/2),math.floor((h)/2)-2)
                        -- whenever im not super lazy, make this window 1 pixel higher on the bottom and then don't draw the bottom line. that way it connects nicely to the window below.
                    elseif e[3] == w and e[4] == h then
                        os.queueEvent("window_reposition",focusWin,tostring(tempwin),math.ceil(w/2)+1,math.floor((h)/2)+2,math.floor(w/2),math.floor((h)/2)-1)
                    elseif e[3] == w then
                        os.queueEvent("window_reposition",focusWin,tostring(tempwin),math.ceil(w/2)+1,2,math.floor(w/2),h-1)
                    elseif e[3] == 1 and e[4] == 1 then
                        os.queueEvent("window_reposition",focusWin,tostring(tempwin),1,2,math.floor(w/2)-1,math.floor((h)/2)-2)
                    elseif e[3] == 1 and e[4] == h then
                        os.queueEvent("window_reposition",focusWin,tostring(tempwin),1,math.floor((h)/2)+2,math.floor(w/2)-1,math.floor((h)/2)-1)
                    elseif e[3] == 1 then
                        os.queueEvent("window_reposition",focusWin,tostring(tempwin),1,2,math.floor(w/2)-1,h-1)
                    else
                        dragging.snap = nil
                    end
                    os.queueEvent("term_resize")
                end
                previewrect = nil
                dragon = false
                dragging = nil
                dragX,dragY = false,false
                wButton = 0
            end
        end
        if e[1] == "key_up" and lUtils.isHolding(keys.leftCtrl) and e[2] == keys.w and #lOS.wins > 0 and lOS.focusWin and lOS.focusWin ~= lOS.wins[0] and not lOS.focusWin.noShortcuts then
            local focusWin
            for t=#lOS.wins,1,-1 do
                if lOS.wins[t] == lOS.focusWin then
                    focusWin = t
                    break
                end
            end
            os.queueEvent("window_close",focusWin,tostring(lOS.focusWin),"system closed cuz ctrl + w")
        elseif e[1] ~= "mouse_move" or e[3] ~= nil then
            refreshProc(e)
        end
    end
end




local hover = false
function lOS.isHover()
    return hover
end



local function hoverevent()
    local timerID = os.startTimer(3)
    while true do
        e = table.pack(os.pullEventRaw("mouse_move"))
        if e[1] == "mouse_move" then
            os.cancelTimer(timerID)
            timerID = os.startTimer(3)
            hX,hY = e[3],e[4]
            hover = false
        elseif e[1] == "timer" and e[2] == timerID then
            os.queueEvent("mouse_hover",1,hX,hY)
            log("Hovering at "..hX..","..hY)
            hover = true
        end
    end
end
lOS.notifWins = {}
function lOS.notification(title,txt,programpath,duration)
    lOS.notifications[#lOS.notifications+1] = {title,txt,programpath,duration}

    local w,h = lOS.wAll.getSize()
    local y = h-5-lOS.tbSize
    local continue = false
    while not continue do
        continue = true
        for k,v in pairs(lOS.notifWins) do
            if coroutine.status(v[1]) ~= "dead" then
                local c1 = false
                for k1,v1 in pairs(lOS.processes) do
                    if v1 == v then
                        c1 = true
                    end
                end
                if c1 == false then
                    lOS.notifWins[k] = nil
                else
                    local tx,ty = v.win.getPosition()
                    if ty-6 <= y then
                        y = ty-6
                    end
                end
            else
                lOS.notifWins[k] = nil
            end
        end
    end
    lOS.execute({"LevelOS/Notification.lua",title,txt,programpath,duration},"widget",w-31,y,32,5,false)
end
--parallel.waitForAny(manage,notifications,hoverevent)
manage()