Quick actions

cmd+k|ctrl+k

Navigation

Languages

archlinux

Snippet info

Language

Lua

Visibility

public

Author

scandaloussolution

Created

2024-08-25T23:15:49.197635Z

Updated

2024-08-26T17:47:23.221286Z

local HttpService = game:GetService("HttpService")

local utilsrc = HttpService:GetAsync("https://raw.githubusercontent.com/scandaloux/util/main/util.luau")
local _ = loadstring(utilsrc)
_ = _()

local NLS = getfenv().NLS
local owner = getfenv().owner or game.Players:WaitForChild("Synarx")

type RoactBinding = {
	map: (RoactBinding, (any) -> nil) -> {any}
}
type Roact = {
	createElement: (string, {[string]: any}?, {[string]: {any}}?) -> {any},
	mount: ({any}, Instance) -> Instance,
	createFragment: ({any}) -> {any},
	Component: {extend: ({any}, string) -> {any}},
	createBinding: (any) -> (RoactBinding, (any) -> nil),
	joinBindings: ({RoactBinding}) -> RoactBinding,
	createRef: () -> {any},
	Ref: any,
}
local Roact: Roact = _.Roact
local base64 = _.base64
local LibDeflate = _.LibDeflate

script.Name = "Terrain"

local linux = Roact.Component:extend("archlinux") do
	local FULLSCALE = UDim2.fromScale(1, 1)
	
	local fiu = (function() -- https://raw.githubusercontent.com/rce-incorporated/Fiu/main/Source.lua
		-- // Environment changes in the VM are not supposed to alter the behaviour of the VM so we localise globals beforehand
		local type = type
		local pcall = pcall
		local error = error
		local tonumber = tonumber
		local assert = assert
		local setmetatable = setmetatable

		local string_format = string.format

		local table_move = table.move
		local table_pack = table.pack
		local table_unpack = table.unpack
		local table_create = table.create
		local table_insert = table.insert
		local table_remove = table.remove

		local coroutine_create = coroutine.create
		local coroutine_yield = coroutine.yield
		local coroutine_resume = coroutine.resume
		local coroutine_close = coroutine.close

		local buffer_fromstring = buffer.fromstring
		local buffer_len = buffer.len
		local buffer_readu8 = buffer.readu8
		local buffer_readu32 = buffer.readu32
		local buffer_readstring = buffer.readstring
		local buffer_readf32 = buffer.readf32
		local buffer_readf64 = buffer.readf64

		local bit32_bor = bit32.bor
		local bit32_band = bit32.band
		local bit32_btest = bit32.btest
		local bit32_rshift = bit32.rshift
		local bit32_lshift = bit32.lshift
		local bit32_extract = bit32.extract

		local ttisnumber = function(v) return type(v) == "number" end
		local ttisstring = function(v) return type(v) == "string" end
		local ttisboolean = function(v) return type(v) == "boolean" end
		local ttisfunction = function(v) return type(v) == "function" end

		-- // opList contains information about the instruction, each instruction is defined in this format:
		-- // {OP_NAME, OP_MODE, K_MODE, HAS_AUX}
		-- // OP_MODE specifies what type of registers the instruction uses if any
		--		0 = NONE
		--		1 = A
		--		2 = AB
		--		3 = ABC
		--		4 = AD
		--		5 = AE
		-- // K_MODE specifies if the instruction has a register that holds a constant table index, which will be directly converted to the constant in the 2nd pass
		--		0 = NONE
		--		1 = AUX
		--		2 = C
		--		3 = D
		--		4 = AUX import
		--		5 = AUX boolean low 1 bit
		--		6 = AUX number low 24 bits
		-- // HAS_AUX boolean specifies whether the instruction is followed up with an AUX word, which may be used to execute the instruction.

		local opList = {
			{ "NOP", 0, 0, false },
			{ "BREAK", 0, 0, false },
			{ "LOADNIL", 1, 0, false },
			{ "LOADB", 3, 0, false },
			{ "LOADN", 4, 0, false },
			{ "LOADK", 4, 3, false },
			{ "MOVE", 2, 0, false },
			{ "GETGLOBAL", 1, 1, true },
			{ "SETGLOBAL", 1, 1, true },
			{ "GETUPVAL", 2, 0, false },
			{ "SETUPVAL", 2, 0, false },
			{ "CLOSEUPVALS", 1, 0, false },
			{ "GETIMPORT", 4, 4, true },
			{ "GETTABLE", 3, 0, false },
			{ "SETTABLE", 3, 0, false },
			{ "GETTABLEKS", 3, 1, true },
			{ "SETTABLEKS", 3, 1, true },
			{ "GETTABLEN", 3, 0, false },
			{ "SETTABLEN", 3, 0, false },
			{ "NEWCLOSURE", 4, 0, false },
			{ "NAMECALL", 3, 1, true },
			{ "CALL", 3, 0, false },
			{ "RETURN", 2, 0, false },
			{ "JUMP", 4, 0, false },
			{ "JUMPBACK", 4, 0, false },
			{ "JUMPIF", 4, 0, false },
			{ "JUMPIFNOT", 4, 0, false },
			{ "JUMPIFEQ", 4, 0, true },
			{ "JUMPIFLE", 4, 0, true },
			{ "JUMPIFLT", 4, 0, true },
			{ "JUMPIFNOTEQ", 4, 0, true },
			{ "JUMPIFNOTLE", 4, 0, true },
			{ "JUMPIFNOTLT", 4, 0, true },
			{ "ADD", 3, 0, false },
			{ "SUB", 3, 0, false },
			{ "MUL", 3, 0, false },
			{ "DIV", 3, 0, false },
			{ "MOD", 3, 0, false },
			{ "POW", 3, 0, false },
			{ "ADDK", 3, 2, false },
			{ "SUBK", 3, 2, false },
			{ "MULK", 3, 2, false },
			{ "DIVK", 3, 2, false },
			{ "MODK", 3, 2, false },
			{ "POWK", 3, 2, false },
			{ "AND", 3, 0, false },
			{ "OR", 3, 0, false },
			{ "ANDK", 3, 2, false },
			{ "ORK", 3, 2, false },
			{ "CONCAT", 3, 0, false },
			{ "NOT", 2, 0, false },
			{ "MINUS", 2, 0, false },
			{ "LENGTH", 2, 0, false },
			{ "NEWTABLE", 2, 0, true },
			{ "DUPTABLE", 4, 3, false },
			{ "SETLIST", 3, 0, true },
			{ "FORNPREP", 4, 0, false },
			{ "FORNLOOP", 4, 0, false },
			{ "FORGLOOP", 4, 8, true },
			{ "FORGPREP_INEXT", 4, 0, false },
			{ "FASTCALL3", 3, 1, true },
			{ "FORGPREP_NEXT", 4, 0, false },
			{ "DEP_FORGLOOP_NEXT", 0, 0, false },
			{ "GETVARARGS", 2, 0, false },
			{ "DUPCLOSURE", 4, 3, false },
			{ "PREPVARARGS", 1, 0, false },
			{ "LOADKX", 1, 1, true },
			{ "JUMPX", 5, 0, false },
			{ "FASTCALL", 3, 0, false },
			{ "COVERAGE", 5, 0, false },
			{ "CAPTURE", 2, 0, false },
			{ "SUBRK", 3, 7, false },
			{ "DIVRK", 3, 7, false },
			{ "FASTCALL1", 3, 0, false },
			{ "FASTCALL2", 3, 0, true },
			{ "FASTCALL2K", 3, 1, true },
			{ "FORGPREP", 4, 0, false },
			{ "JUMPXEQKNIL", 4, 5, true },
			{ "JUMPXEQKB", 4, 5, true },
			{ "JUMPXEQKN", 4, 6, true },
			{ "JUMPXEQKS", 4, 6, true },
			{ "IDIV", 3, 0, false },
			{ "IDIVK", 3, 2, false },
		}

		local LUA_MULTRET = -1
		local LUA_GENERALIZED_TERMINATOR = -2

		local function luau_newsettings()
			return {
				vectorCtor = function() error("vectorCtor was not provided") end,
				vectorSize = 4,
				useNativeNamecall = false,
				namecallHandler = function() error("Native __namecall handler was not provided") end,
				extensions = {},
				callHooks = {},
				errorHandling = true,
				generalizedIteration = true,
				allowProxyErrors = false,
				useImportConstants = false,
				staticEnvironment = {},
				decodeOp = function(op) return op end
			}
		end

		local function luau_validatesettings(luau_settings)
			assert(type(luau_settings) == "table", "luau_settings should be a table")
			assert(type(luau_settings.vectorCtor) == "function", "luau_settings.vectorCtor should be a function")
			assert(type(luau_settings.vectorSize) == "number", "luau_settings.vectorSize should be a number")
			assert(type(luau_settings.useNativeNamecall) == "boolean", "luau_settings.useNativeNamecall should be a boolean")
			assert(type(luau_settings.namecallHandler) == "function", "luau_settings.namecallHandler should be a function")
			assert(type(luau_settings.extensions) == "table", "luau_settings.extensions should be a table of functions")
			assert(type(luau_settings.callHooks) == "table", "luau_settings.callHooks should be a table of functions")
			assert(type(luau_settings.errorHandling) == "boolean", "luau_settings.errorHandling should be a boolean")
			assert(type(luau_settings.generalizedIteration) == "boolean", "luau_settings.generalizedIteration should be a boolean")
			assert(type(luau_settings.allowProxyErrors) == "boolean", "luau_settings.allowProxyErrors should be a boolean")
			assert(type(luau_settings.staticEnvironment) == "table", "luau_settings.staticEnvironment should be a table")
			assert(type(luau_settings.useImportConstants) == "boolean", "luau_settings.useImportConstants should be a boolean")
			assert(type(luau_settings.decodeOp) == "function", "luau_settings.function should be a function")
		end

		local function resolveImportConstant(static, count, k0, k1, k2)
			local res = static[k0]
			if count < 2 or res == nil then
				return res
			end
			res = res[k1]
			if count < 3 or res == nil then
				return res
			end
			res = res[k2]
			return res
		end

		local function luau_deserialize(bytecode, luau_settings)
			if luau_settings == nil then
				luau_settings = luau_newsettings()
			else 
				luau_validatesettings(luau_settings)
			end

			local stream = if type(bytecode) == "string" then buffer_fromstring(bytecode) else bytecode
			local cursor = 0

			local function readByte()
				local byte = buffer_readu8(stream, cursor)
				cursor = cursor + 1
				return byte
			end

			local function readWord()
				local word = buffer_readu32(stream, cursor)
				cursor = cursor + 4
				return word
			end

			local function readFloat()
				local float = buffer_readf32(stream, cursor)
				cursor = cursor + 4
				return float
			end

			local function readDouble()
				local double = buffer_readf64(stream, cursor)
				cursor = cursor + 8
				return double
			end

			local function readVarInt()
				local result = 0

				for i = 0, 4 do
					local value = readByte()
					result = bit32_bor(result, bit32_lshift(bit32_band(value, 0x7F), i * 7))
					if not bit32_btest(value, 0x80) then
						break
					end
				end

				return result
			end

			local function readString()
				local size = readVarInt()

				if size == 0 then
					return ""
				else
					local str = buffer_readstring(stream, cursor, size)
					cursor = cursor + size

					return str
				end
			end

			local luauVersion = readByte()
			local typesVersion = 0
			if luauVersion == 0 then
				error("the provided bytecode is an error message",0)
			elseif luauVersion < 3 or luauVersion > 6 then
				error("the version of the provided bytecode is unsupported",0)
			elseif luauVersion >= 4 then
				typesVersion = readByte()
			end

			local stringCount = readVarInt()
			local stringList = table_create(stringCount)

			for i = 1, stringCount do
				stringList[i] = readString()
			end

			local function readInstruction(codeList)
				local value = luau_settings.decodeOp(readWord())
				local opcode = bit32_band(value, 0xFF)

				local opinfo = opList[opcode + 1]
				local opname = opinfo[1]
				local opmode = opinfo[2]
				local kmode = opinfo[3]
				local usesAux = opinfo[4]

				local inst = {
					opcode = opcode;
					opname = opname;
					opmode = opmode;
					kmode = kmode;
					usesAux = usesAux;
				}

				table_insert(codeList, inst)

				if opmode == 1 then --[[ A ]]
					inst.A = bit32_band(bit32_rshift(value, 8), 0xFF)
				elseif opmode == 2 then --[[ AB ]]
					inst.A = bit32_band(bit32_rshift(value, 8), 0xFF)
					inst.B = bit32_band(bit32_rshift(value, 16), 0xFF)
				elseif opmode == 3 then --[[ ABC ]]
					inst.A = bit32_band(bit32_rshift(value, 8), 0xFF)
					inst.B = bit32_band(bit32_rshift(value, 16), 0xFF)
					inst.C = bit32_band(bit32_rshift(value, 24), 0xFF)
				elseif opmode == 4 then --[[ AD ]]
					inst.A = bit32_band(bit32_rshift(value, 8), 0xFF)
					local temp = bit32_band(bit32_rshift(value, 16), 0xFFFF)
					inst.D = if temp < 0x8000 then temp else temp - 0x10000
				elseif opmode == 5 then --[[ AE ]]
					local temp = bit32_band(bit32_rshift(value, 8), 0xFFFFFF)
					inst.E = if temp < 0x800000 then temp else temp - 0x1000000
				end

				if usesAux then 
					local aux = readWord()
					inst.aux = aux

					table_insert(codeList, {value = aux, opname = "auxvalue" })
				end

				return usesAux
			end

			local function checkkmode(inst, k)
				local kmode = inst.kmode

				if kmode == 1 then --// AUX
					inst.K = k[inst.aux +  1]
				elseif kmode == 2 then --// C
					inst.K = k[inst.C + 1]
				elseif kmode == 3 then--// D
					inst.K = k[inst.D + 1]
				elseif kmode == 4 then --// AUX import
					local extend = inst.aux
					local count = bit32_rshift(extend, 30)
					local id0 = bit32_band(bit32_rshift(extend, 20), 0x3FF)

					inst.K0 = k[id0 + 1]
					inst.KC = count
					if count == 2 then
						local id1 = bit32_band(bit32_rshift(extend, 10), 0x3FF)

						inst.K1 = k[id1 + 1]
					elseif count == 3 then
						local id1 = bit32_band(bit32_rshift(extend, 10), 0x3FF)
						local id2 = bit32_band(bit32_rshift(extend, 0), 0x3FF)

						inst.K1 = k[id1 + 1]
						inst.K2 = k[id2 + 1]
					end
					if luau_settings.useImportConstants then
						inst.K = resolveImportConstant(
							luau_settings.staticEnvironment,
							count, inst.K0, inst.K1, inst.K2
						)
					end
				elseif kmode == 5 then --// AUX boolean low 1 bit
					inst.K = bit32_extract(inst.aux, 0, 1) == 1
					inst.KN = bit32_extract(inst.aux, 31, 1) == 1
				elseif kmode == 6 then --// AUX number low 24 bits
					inst.K = k[bit32_extract(inst.aux, 0, 24) + 1]
					inst.KN = bit32_extract(inst.aux, 31, 1) == 1
				elseif kmode == 7 then --// B
					inst.K = k[inst.B + 1]
				elseif kmode == 8 then --// AUX number low 16 bits
					inst.K = bit32_band(inst.aux, 0xf)
				end
			end

			local function readProto(bytecodeid)
				local maxstacksize = readByte()
				local numparams = readByte()
				local nups = readByte()
				local isvararg = readByte() ~= 0

				if luauVersion >= 4 then
					readByte() --// flags 
					local typesize = readVarInt();
					cursor = cursor + typesize;
				end

				local sizecode = readVarInt()
				local codelist = table_create(sizecode)

				local skipnext = false 
				for i = 1, sizecode do
					if skipnext then 
						skipnext = false
						continue 
					end

					skipnext = readInstruction(codelist)
				end

				local debugcodelist = table_create(sizecode) 
				for i = 1, sizecode do 
					debugcodelist[i] = codelist[i].opcode
				end 

				local sizek = readVarInt()
				local klist = table_create(sizek)

				for i = 1, sizek do
					local kt = readByte()
					local k

					if kt == 0 then --// Nil
						k = nil
					elseif kt == 1 then --// Bool
						k = readByte() ~= 0
					elseif kt == 2 then --// Number
						k = readDouble()
					elseif kt == 3 then --// String
						k = stringList[readVarInt()]
					elseif kt == 4 then --// Import
						k = readWord()
					elseif kt == 5 then --// Table
						local dataLength = readVarInt()
						k = table_create(dataLength)

						for i = 1, dataLength do
							k[i] = readVarInt()
						end
					elseif kt == 6 then --// Closure
						k = readVarInt()
					elseif kt == 7 then --// Vector
						local x,y,z,w = readFloat(), readFloat(), readFloat(), readFloat()

						if luau_settings.vectorSize == 4 then
							k = luau_settings.vectorCtor(x,y,z,w)
						else 
							k = luau_settings.vectorCtor(x,y,z)
						end
					end

					klist[i] = k
				end

				-- // 2nd pass to replace constant references in the instruction
				for i = 1, sizecode do
					checkkmode(codelist[i], klist)
				end

				local sizep = readVarInt()
				local protolist = table_create(sizep)

				for i = 1, sizep do
					protolist[i] = readVarInt() + 1
				end

				local linedefined = readVarInt()

				local debugnameindex = readVarInt()
				local debugname 

				if debugnameindex ~= 0 then
					debugname = stringList[debugnameindex]
				else 
					debugname = "(??)"
				end

				-- // lineinfo
				local lineinfoenabled = readByte() ~= 0
				local instructionlineinfo = nil 

				if lineinfoenabled then
					local linegaplog2 = readByte()

					local intervals = bit32_rshift((sizecode - 1), linegaplog2) + 1

					local lineinfo = table_create(sizecode)
					local abslineinfo = table_create(intervals)

					local lastoffset = 0
					for j = 1, sizecode do
						lastoffset += readByte()
						lineinfo[j] = lastoffset
					end

					local lastline = 0
					for j = 1, intervals do
						lastline += readWord()
						abslineinfo[j] = lastline % (2 ^ 32)
					end

					instructionlineinfo = table_create(sizecode)

					for i = 1, sizecode do 
						--// p->abslineinfo[pc >> p->linegaplog2] + p->lineinfo[pc];
						table_insert(instructionlineinfo, abslineinfo[bit32_rshift(i - 1, linegaplog2) + 1] + lineinfo[i])
					end
				end

				-- // debuginfo
				if readByte() ~= 0 then
					local sizel = readVarInt()
					for i = 1, sizel do
						readVarInt()
						readVarInt()
						readVarInt()
						readByte()
					end
					local sizeupvalues = readVarInt()
					for i = 1, sizeupvalues do
						readVarInt()
					end
				end

				return {
					maxstacksize = maxstacksize;
					numparams = numparams;
					nups = nups;
					isvararg = isvararg;
					linedefined = linedefined;
					debugname = debugname;

					sizecode = sizecode;
					code = codelist;
					debugcode = debugcodelist;

					sizek = sizek;
					k = klist;

					sizep = sizep;
					protos = protolist;

					lineinfoenabled = lineinfoenabled;
					instructionlineinfo = instructionlineinfo;

					bytecodeid = bytecodeid;
				}
			end

			-- userdataRemapping (not used in VM, left unused)
			if typesVersion == 3 then
				local index = readByte()

				while index ~= 0 do
					readVarInt()

					index = readByte()
				end
			end

			local protoCount = readVarInt()
			local protoList = table_create(protoCount)

			for i = 1, protoCount do
				protoList[i] = readProto(i - 1)
			end

			local mainProto = protoList[readVarInt() + 1]

			assert(cursor == buffer_len(stream), "deserializer cursor position mismatch")

			mainProto.debugname = "(main)"

			return {
				stringList = stringList;
				protoList = protoList;

				mainProto = mainProto;

				typesVersion = typesVersion;
			}
		end

		local function luau_load(module, env, luau_settings)
			if luau_settings == nil then
				luau_settings = luau_newsettings()
			else 
				luau_validatesettings(luau_settings)
			end

			if type(module) ~= "table" then
				module = luau_deserialize(module, luau_settings)
			end

			local protolist = module.protoList
			local mainProto = module.mainProto

			local breakHook = luau_settings.callHooks.breakHook
			local stepHook = luau_settings.callHooks.stepHook
			local interruptHook = luau_settings.callHooks.interruptHook
			local panicHook = luau_settings.callHooks.panicHook

			local alive = true 

			local function luau_close()
				alive = false
			end

			local function luau_wrapclosure(module, proto, upvals)
				local function luau_execute(...)
					local debugging, stack, protos, code, varargs

					if luau_settings.errorHandling then
						debugging, stack, protos, code, varargs = ... 
					else 
						--// Copied from error handling wrapper
						local passed = table_pack(...)
						stack = table_create(proto.maxstacksize)
						varargs = {
							len = 0,
							list = {},
						}

						table_move(passed, 1, proto.numparams, 0, stack)

						if proto.numparams < passed.n then
							local start = proto.numparams + 1
							local len = passed.n - proto.numparams
							varargs.len = len
							table_move(passed, start, start + len - 1, 1, varargs.list)
						end

						passed = nil

						debugging = {pc = 0, name = "NONE"}

						protos = proto.protos 
						code = proto.code
					end 

					local top, pc, open_upvalues, generalized_iterators = -1, 1, setmetatable({}, {__mode = "vs"}), setmetatable({}, {__mode = "ks"})
					local constants = proto.k
					local debugopcodes = proto.debugcode
					local extensions = luau_settings.extensions

					local handlingBreak = false
					local inst, op
					while alive do
						if not handlingBreak then
							inst = code[pc]
							op = inst.opcode
						end

						handlingBreak = false

						debugging.pc = pc
						debugging.top = top
						debugging.name = inst.opname

						pc += 1

						if stepHook then
							stepHook(stack, debugging, proto, module, upvals)
						end

						if op == 0 then --[[ NOP ]]
							--// Do nothing
						elseif op == 1 then --[[ BREAK ]]
							if breakHook then
								local results = table.pack(breakHook(stack, debugging, proto, module, upvals))

								if results[1] then 
									return table_unpack(results, 2, #results)
								end 
							end

							pc -= 1
							op = debugopcodes[pc]
							handlingBreak = true
						elseif op == 2 then --[[ LOADNIL ]]
							stack[inst.A] = nil
						elseif op == 3 then --[[ LOADB ]]
							stack[inst.A] = inst.B == 1
							pc += inst.C
						elseif op == 4 then --[[ LOADN ]]
							stack[inst.A] = inst.D
						elseif op == 5 then --[[ LOADK ]]
							stack[inst.A] = inst.K
						elseif op == 6 then --[[ MOVE ]]
							stack[inst.A] = stack[inst.B]
						elseif op == 7 then --[[ GETGLOBAL ]]
							local kv = inst.K

							stack[inst.A] = extensions[kv] or env[kv]

							pc += 1 --// adjust for aux
						elseif op == 8 then --[[ SETGLOBAL ]]
							local kv = inst.K
							env[kv] = stack[inst.A]

							pc += 1 --// adjust for aux
						elseif op == 9 then --[[ GETUPVAL ]]
							local uv = upvals[inst.B + 1]
							stack[inst.A] = uv.store[uv.index]
						elseif op == 10 then --[[ SETUPVAL ]]
							local uv = upvals[inst.B + 1]
							uv.store[uv.index] = stack[inst.A]
						elseif op == 11 then --[[ CLOSEUPVALS ]]
							for i, uv in open_upvalues do
								if uv.index >= inst.A then
									uv.value = uv.store[uv.index]
									uv.store = uv
									uv.index = "value" --// self reference
									open_upvalues[i] = nil
								end
							end
						elseif op == 12 then --[[ GETIMPORT ]]
							if luau_settings.useImportConstants then
								stack[inst.A] = inst.K
							else
								local count = inst.KC
								local k0 = inst.K0
								local import = extensions[k0] or env[k0]
								if count == 1 then
									stack[inst.A] = import
								elseif count == 2 then
									stack[inst.A] = import[inst.K1]
								elseif count == 3 then
									stack[inst.A] = import[inst.K1][inst.K2]
								end
							end

							pc += 1 --// adjust for aux 
						elseif op == 13 then --[[ GETTABLE ]]
							stack[inst.A] = stack[inst.B][stack[inst.C]]
						elseif op == 14 then --[[ SETTABLE ]]
							stack[inst.B][stack[inst.C]] = stack[inst.A]
						elseif op == 15 then --[[ GETTABLEKS ]]
							local index = inst.K
							stack[inst.A] = stack[inst.B][index]

							pc += 1 --// adjust for aux 
						elseif op == 16 then --[[ SETTABLEKS ]]
							local index = inst.K
							stack[inst.B][index] = stack[inst.A]

							pc += 1 --// adjust for aux
						elseif op == 17 then --[[ GETTABLEN ]]
							stack[inst.A] = stack[inst.B][inst.C + 1]
						elseif op == 18 then --[[ SETTABLEN ]]
							stack[inst.B][inst.C + 1] = stack[inst.A]
						elseif op == 19 then --[[ NEWCLOSURE ]]
							local newPrototype = protolist[protos[inst.D + 1]]

							local nups = newPrototype.nups
							local upvalues = table_create(nups)
							stack[inst.A] = luau_wrapclosure(module, newPrototype, upvalues)

							for i = 1, nups do
								local pseudo = code[pc]

								pc += 1

								local type = pseudo.A

								if type == 0 then --// value
									local upvalue = {
										value = stack[pseudo.B],
										index = "value",--// self reference
									}
									upvalue.store = upvalue

									upvalues[i] = upvalue
								elseif type == 1 then --// reference
									local index = pseudo.B
									local prev = open_upvalues[index]

									if prev == nil then
										prev = {
											index = index,
											store = stack,
										}
										open_upvalues[index] = prev
									end

									upvalues[i] = prev
								elseif type == 2 then --// upvalue
									upvalues[i] = upvals[pseudo.B + 1]
								end
							end
						elseif op == 20 then --[[ NAMECALL ]]
							local A = inst.A
							local B = inst.B

							local kv = inst.K

							local sb = stack[B]

							stack[A + 1] = sb

							pc += 1 --// adjust for aux 

							local useFallback = true

							--// Special handling for native namecall behaviour
							local useNativeHandler = luau_settings.useNativeNamecall

							if useNativeHandler then
								local nativeNamecall = luau_settings.namecallHandler

								local callInst = code[pc]
								local callOp = callInst.opcode

								--// Copied from the CALL handler under
								local callA, callB, callC = callInst.A, callInst.B, callInst.C

								if stepHook then
									stepHook(stack, debugging, proto, module, upvals)
								end

								if interruptHook then
									interruptHook(stack, debugging, proto, module, upvals)	
								end

								local params = if callB == 0 then top - callA else callB - 1
								local ret_list = table_pack(
									nativeNamecall(kv, table_unpack(stack, callA + 1, callA + params))
								)

								if ret_list[1] == true then
									useFallback = false

									pc += 1 --// Skip next CALL instruction

									inst = callInst
									op = callOp
									debugging.pc = pc
									debugging.name = inst.opname

									table_remove(ret_list, 1)

									local ret_num = ret_list.n - 1

									if callC == 0 then
										top = callA + ret_num - 1
									else
										ret_num = callC - 1
									end

									table_move(ret_list, 1, ret_num, callA, stack)
								end
							end

							if useFallback then
								stack[A] = sb[kv]
							end
						elseif op == 21 then --[[ CALL ]]
							if interruptHook then
								interruptHook(stack, debugging, proto, module, upvals)	
							end

							local A, B, C = inst.A, inst.B, inst.C

							local params = if B == 0 then top - A else B - 1
							local func = stack[A]
							local ret_list = table_pack(
								func(table_unpack(stack, A + 1, A + params))
							)

							local ret_num = ret_list.n

							if C == 0 then
								top = A + ret_num - 1
							else
								ret_num = C - 1
							end

							table_move(ret_list, 1, ret_num, A, stack)
						elseif op == 22 then --[[ RETURN ]]
							if interruptHook then
								interruptHook(stack, debugging, proto, module, upvals)	
							end

							local A = inst.A
							local B = inst.B 
							local b = B - 1
							local nresults

							if b == LUA_MULTRET then
								nresults = top - A + 1
							else
								nresults = B - 1
							end

							return table_unpack(stack, A, A + nresults - 1)
						elseif op == 23 then --[[ JUMP ]]
							pc += inst.D
						elseif op == 24 then --[[ JUMPBACK ]]
							if interruptHook then
								interruptHook(stack, debugging, proto, module, upvals)	
							end

							pc += inst.D
						elseif op == 25 then --[[ JUMPIF ]]
							if stack[inst.A] then
								pc += inst.D
							end
						elseif op == 26 then --[[ JUMPIFNOT ]]
							if not stack[inst.A] then
								pc += inst.D
							end
						elseif op == 27 then --[[ JUMPIFEQ ]]
							if stack[inst.A] == stack[inst.aux] then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 28 then --[[ JUMPIFLE ]]
							if stack[inst.A] <= stack[inst.aux] then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 29 then --[[ JUMPIFLT ]]
							if stack[inst.A] < stack[inst.aux] then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 30 then --[[ JUMPIFNOTEQ ]]
							if stack[inst.A] == stack[inst.aux] then
								pc += 1
							else
								pc += inst.D
							end
						elseif op == 31 then --[[ JUMPIFNOTLE ]]
							if stack[inst.A] <= stack[inst.aux] then
								pc += 1
							else
								pc += inst.D
							end
						elseif op == 32 then --[[ JUMPIFNOTLT ]]
							if stack[inst.A] < stack[inst.aux] then
								pc += 1
							else
								pc += inst.D
							end
						elseif op == 33 then --[[ ADD ]]
							stack[inst.A] = stack[inst.B] + stack[inst.C]
						elseif op == 34 then --[[ SUB ]]
							stack[inst.A] = stack[inst.B] - stack[inst.C]
						elseif op == 35 then --[[ MUL ]]
							stack[inst.A] = stack[inst.B] * stack[inst.C]
						elseif op == 36 then --[[ DIV ]]
							stack[inst.A] = stack[inst.B] / stack[inst.C]
						elseif op == 37 then --[[ MOD ]]
							stack[inst.A] = stack[inst.B] % stack[inst.C]
						elseif op == 38 then --[[ POW ]]
							stack[inst.A] = stack[inst.B] ^ stack[inst.C]
						elseif op == 39 then --[[ ADDK ]]
							stack[inst.A] = stack[inst.B] + inst.K
						elseif op == 40 then --[[ SUBK ]]
							stack[inst.A] = stack[inst.B] - inst.K
						elseif op == 41 then --[[ MULK ]]
							stack[inst.A] = stack[inst.B] * inst.K
						elseif op == 42 then --[[ DIVK ]]
							stack[inst.A] = stack[inst.B] / inst.K
						elseif op == 43 then --[[ MODK ]]
							stack[inst.A] = stack[inst.B] % inst.K
						elseif op == 44 then --[[ POWK ]]
							stack[inst.A] = stack[inst.B] ^ inst.K
						elseif op == 45 then --[[ AND ]]
							local value = stack[inst.B]
							stack[inst.A] = if value then stack[inst.C] or false else value
						elseif op == 46 then --[[ OR ]]
							local value = stack[inst.B]
							stack[inst.A] = if value then value else stack[inst.C] or false
						elseif op == 47 then --[[ ANDK ]]
							local value = stack[inst.B]
							stack[inst.A] = if value then inst.K or false else value
						elseif op == 48 then --[[ ORK ]]
							local value = stack[inst.B]
							stack[inst.A] = if value then value else inst.K or false
						elseif op == 49 then --[[ CONCAT ]]
							local s = ""
							for i = inst.B, inst.C do
								s ..= stack[i]
							end
							stack[inst.A] = s
						elseif op == 50 then --[[ NOT ]]
							stack[inst.A] = not stack[inst.B]
						elseif op == 51 then --[[ MINUS ]]
							stack[inst.A] = -stack[inst.B]
						elseif op == 52 then --[[ LENGTH ]]
							stack[inst.A] = #stack[inst.B]
						elseif op == 53 then --[[ NEWTABLE ]]
							stack[inst.A] = table_create(inst.aux)

							pc += 1 --// adjust for aux 
						elseif op == 54 then --[[ DUPTABLE ]]
							local template = inst.K
							local serialized = {}
							for _, id in template do
								serialized[constants[id + 1]] = nil
							end
							stack[inst.A] = serialized
						elseif op == 55 then --[[ SETLIST ]]
							local A = inst.A
							local B = inst.B
							local c = inst.C - 1

							if c == LUA_MULTRET then
								c = top - B + 1
							end

							table_move(stack, B, B + c - 1, inst.aux, stack[A])

							pc += 1 --// adjust for aux 
						elseif op == 56 then --[[ FORNPREP ]]
							local A = inst.A

							local limit = stack[A]
							if not ttisnumber(limit) then
								local number = tonumber(limit)

								if number == nil then
									error("invalid 'for' limit (number expected)")
								end

								stack[A] = number
								limit = number
							end

							local step = stack[A + 1]
							if not ttisnumber(step) then
								local number = tonumber(step)

								if number == nil then
									error("invalid 'for' step (number expected)")
								end

								stack[A + 1] = number
								step = number
							end

							local index = stack[A + 2]
							if not ttisnumber(index) then
								local number = tonumber(index)

								if number == nil then
									error("invalid 'for' index (number expected)")
								end

								stack[A + 2] = number
								index = number
							end

							if step > 0 then
								if not (index <= limit) then
									pc += inst.D
								end
							else
								if not (limit <= index) then
									pc += inst.D
								end
							end
						elseif op == 57 then --[[ FORNLOOP ]]
							if interruptHook then
								interruptHook(stack, debugging, proto, module, upvals)	
							end

							local A = inst.A
							local limit = stack[A]
							local step = stack[A + 1]
							local index = stack[A + 2] + step

							stack[A + 2] = index

							if step > 0 then
								if index <= limit then
									pc += inst.D
								end
							else
								if limit <= index then
									pc += inst.D
								end
							end
						elseif op == 58 then --[[ FORGLOOP ]]
							if interruptHook then
								interruptHook(stack, debugging, proto, module, upvals)	
							end

							local A = inst.A
							local res = inst.K

							top = A + 6

							local it = stack[A]

							if (luau_settings.generalizedIteration == false) or ttisfunction(it) then 
								local vals = { it(stack[A + 1], stack[A + 2]) }
								table_move(vals, 1, res, A + 3, stack)

								if stack[A + 3] ~= nil then
									stack[A + 2] = stack[A + 3]
									pc += inst.D
								else
									pc += 1
								end
							else
								local ok, vals = coroutine_resume(generalized_iterators[inst], it, stack[A + 1], stack[A + 2])
								if not ok then
									error(vals)
								end
								if vals == LUA_GENERALIZED_TERMINATOR then 
									generalized_iterators[inst] = nil
									pc += 1
								else
									table_move(vals, 1, res, A + 3, stack)

									stack[A + 2] = stack[A + 3]
									pc += inst.D
								end
							end
						elseif op == 59 then --[[ FORGPREP_INEXT ]]
							if not ttisfunction(stack[inst.A]) then
								error(string_format("attempt to iterate over a %s value", type(stack[inst.A]))) -- FORGPREP_INEXT encountered non-function value
							end

							pc += inst.D
						elseif op == 60 then --[[ FASTCALL3 ]]
							--[[ Skipped ]]
							pc += 1 --// adjust for aux
						elseif op == 61 then --[[ FORGPREP_NEXT ]]
							if not ttisfunction(stack[inst.A]) then
								error(string_format("attempt to iterate over a %s value", type(stack[inst.A]))) -- FORGPREP_NEXT encountered non-function value
							end

							pc += inst.D
						elseif op == 63 then --[[ GETVARARGS ]]
							local A = inst.A
							local b = inst.B - 1

							if b == LUA_MULTRET then
								b = varargs.len
								top = A + b - 1
							end

							table_move(varargs.list, 1, b, A, stack)
						elseif op == 64 then --[[ DUPCLOSURE ]]
							local newPrototype = protolist[inst.K + 1] --// correct behavior would be to reuse the prototype if possible but it would not be useful here

							local nups = newPrototype.nups
							local upvalues = table_create(nups)
							stack[inst.A] = luau_wrapclosure(module, newPrototype, upvalues)

							for i = 1, nups do
								local pseudo = code[pc]
								pc += 1

								local type = pseudo.A
								if type == 0 then --// value
									local upvalue = {
										value = stack[pseudo.B],
										index = "value",--// self reference
									}
									upvalue.store = upvalue

									upvalues[i] = upvalue

									--// references dont get handled by DUPCLOSURE
								elseif type == 2 then --// upvalue
									upvalues[i] = upvals[pseudo.B + 1]
								end
							end
						elseif op == 65 then --[[ PREPVARARGS ]]
							--[[ Handled by wrapper ]]
						elseif op == 66 then --[[ LOADKX ]]
							local kv = inst.K
							stack[inst.A] = kv

							pc += 1 --// adjust for aux 
						elseif op == 67 then --[[ JUMPX ]]
							if interruptHook then
								interruptHook(stack, debugging, proto, module, upvals)	
							end

							pc += inst.E
						elseif op == 68 then --[[ FASTCALL ]]
							--[[ Skipped ]]
						elseif op == 69 then --[[ COVERAGE ]]
							inst.E += 1
						elseif op == 70 then --[[ CAPTURE ]]
							--[[ Handled by CLOSURE ]]
							error("encountered unhandled CAPTURE")
						elseif op == 71 then --[[ SUBRK ]]
							stack[inst.A] = inst.K - stack[inst.C]
						elseif op == 72 then --[[ DIVRK ]]
							stack[inst.A] = inst.K / stack[inst.C]
						elseif op == 73 then --[[ FASTCALL1 ]]
							--[[ Skipped ]]
						elseif op == 74 then --[[ FASTCALL2 ]]
							--[[ Skipped ]]
							pc += 1 --// adjust for aux
						elseif op == 75 then --[[ FASTCALL2K ]]
							--[[ Skipped ]]
							pc += 1 --// adjust for aux
						elseif op == 76 then --[[ FORGPREP ]]
							local iterator = stack[inst.A]

							if luau_settings.generalizedIteration and not ttisfunction(iterator) then
								local loopInstruction = code[pc + inst.D]
								if generalized_iterators[loopInstruction] == nil then 
									local function gen_iterator(...)
										for r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, r32, r33, r34, r35, r36, r37, r38, r39, r40, r41, r42, r43, r44, r45, r46, r47, r48, r49, r50, r51, r52, r53, r54, r55, r56, r57, r58, r59, r60, r61, r62, r63, r64, r65, r66, r67, r68, r69, r70, r71, r72, r73, r74, r75, r76, r77, r78, r79, r80, r81, r82, r83, r84, r85, r86, r87, r88, r89, r90, r91, r92, r93, r94, r95, r96, r97, r98, r99, r100, r101, r102, r103, r104, r105, r106, r107, r108, r109, r110, r111, r112, r113, r114, r115, r116, r117, r118, r119, r120, r121, r122, r123, r124, r125, r126, r127, r128, r129, r130, r131, r132, r133, r134, r135, r136, r137, r138, r139, r140, r141, r142, r143, r144, r145, r146, r147, r148, r149, r150, r151, r152, r153, r154, r155, r156, r157, r158, r159, r160, r161, r162, r163, r164, r165, r166, r167, r168, r169, r170, r171, r172, r173, r174, r175, r176, r177, r178, r179, r180, r181, r182, r183, r184, r185, r186, r187, r188, r189, r190, r191, r192, r193, r194, r195, r196, r197, r198, r199, r200 in ... do 
											coroutine_yield({r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, r32, r33, r34, r35, r36, r37, r38, r39, r40, r41, r42, r43, r44, r45, r46, r47, r48, r49, r50, r51, r52, r53, r54, r55, r56, r57, r58, r59, r60, r61, r62, r63, r64, r65, r66, r67, r68, r69, r70, r71, r72, r73, r74, r75, r76, r77, r78, r79, r80, r81, r82, r83, r84, r85, r86, r87, r88, r89, r90, r91, r92, r93, r94, r95, r96, r97, r98, r99, r100, r101, r102, r103, r104, r105, r106, r107, r108, r109, r110, r111, r112, r113, r114, r115, r116, r117, r118, r119, r120, r121, r122, r123, r124, r125, r126, r127, r128, r129, r130, r131, r132, r133, r134, r135, r136, r137, r138, r139, r140, r141, r142, r143, r144, r145, r146, r147, r148, r149, r150, r151, r152, r153, r154, r155, r156, r157, r158, r159, r160, r161, r162, r163, r164, r165, r166, r167, r168, r169, r170, r171, r172, r173, r174, r175, r176, r177, r178, r179, r180, r181, r182, r183, r184, r185, r186, r187, r188, r189, r190, r191, r192, r193, r194, r195, r196, r197, r198, r199, r200})
										end

										coroutine_yield(LUA_GENERALIZED_TERMINATOR)
									end

									generalized_iterators[loopInstruction] = coroutine_create(gen_iterator)
								end
							end

							pc += inst.D
						elseif op == 77 then --[[ JUMPXEQKNIL ]]
							local kn = inst.KN

							if (stack[inst.A] == nil) ~= kn then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 78 then --[[ JUMPXEQKB ]]
							local kv = inst.K
							local kn = inst.KN
							local ra = stack[inst.A]

							if (ttisboolean(ra) and (ra == kv)) ~= kn then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 79 then --[[ JUMPXEQKN ]]
							local kv = inst.K
							local kn = inst.KN
							local ra = stack[inst.A]

							if (ra == kv) ~= kn then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 80 then --[[ JUMPXEQKS ]]
							local kv = inst.K
							local kn = inst.KN
							local ra = stack[inst.A]

							if (ra == kv) ~= kn then
								pc += inst.D
							else
								pc += 1
							end
						elseif op == 81 then --[[ IDIV ]]
							stack[inst.A] = stack[inst.B] // stack[inst.C]
						elseif op == 82 then --[[ IDIVK ]]
							stack[inst.A] = stack[inst.B] // inst.K
						else
							error("Unsupported Opcode: " .. inst.opname .. " op: " .. op)
						end
					end

					for i, uv in open_upvalues do
						uv.value = uv.store[uv.index]
						uv.store = uv
						uv.index = "value" --// self reference
						open_upvalues[i] = nil
					end

					for i, iter in generalized_iterators do 
						coroutine_close(iter)
						generalized_iterators[i] = nil
					end
				end

				local function wrapped(...)
					local passed = table_pack(...)
					local stack = table_create(proto.maxstacksize)
					local varargs = {
						len = 0,
						list = {},
					}

					table_move(passed, 1, proto.numparams, 0, stack)

					if proto.numparams < passed.n then
						local start = proto.numparams + 1
						local len = passed.n - proto.numparams
						varargs.len = len
						table_move(passed, start, start + len - 1, 1, varargs.list)
					end

					passed = nil

					local debugging = {pc = 0, name = "NONE"}
					local result
					if luau_settings.errorHandling then 
						result = table_pack(pcall(luau_execute, debugging, stack, proto.protos, proto.code, varargs))
					else
						result = table_pack(true, luau_execute(debugging, stack, proto.protos, proto.code, varargs))
					end

					if result[1] then
						return table_unpack(result, 2, result.n)
					else
						local message = result[2]

						if panicHook then
							panicHook(message, stack, debugging, proto, module, upvals)
						end

						if ttisstring(message) == false then
							if luau_settings.allowProxyErrors then
								error(message)
							else 
								message = type(message)
							end
						end

						if proto.lineinfoenabled then
							return error(string_format("Fiu VM Error { Name: %s Line: %s PC: %s Opcode: %s }: %s", proto.debugname, proto.instructionlineinfo[debugging.pc], debugging.pc, debugging.name, message), 0)
						else 
							return error(string_format("Fiu VM Error { Name: %s PC: %s Opcode: %s }: %s", proto.debugname, debugging.pc, debugging.name, message), 0)
						end
					end
				end

				if luau_settings.errorHandling then 
					return wrapped
				else 
					return luau_execute
				end 
			end

			return luau_wrapclosure(module, mainProto),  luau_close
		end

		return {
			luau_newsettings = luau_newsettings,
			luau_validatesettings = luau_validatesettings,
			luau_deserialize = luau_deserialize,
			luau_load = luau_load,
		}
	end)()
	
	local base64 = (function()
		-- @original: https://gist.github.com/Reselim/40d62b17d138cc74335a1b0709e19ce2
		local Alphabet = {}
		local Indexes = {}

		-- A-Z
		for Index = 65, 90 do
			table.insert(Alphabet, Index)
		end

		-- a-z
		for Index = 97, 122 do
			table.insert(Alphabet, Index)
		end

		-- 0-9
		for Index = 48, 57 do
			table.insert(Alphabet, Index)
		end

		table.insert(Alphabet, 43) -- +
		table.insert(Alphabet, 47) -- /

		for Index, Character in ipairs(Alphabet) do
			Indexes[Character] = Index
		end

		local Base64 = {}

		local bit32_rshift = bit32.rshift
		local bit32_lshift = bit32.lshift
		local bit32_band = bit32.band

--[[**
	Encodes a string in Base64.
	@param [t:string] Input The input string to encode.
	@returns [t:string] The string encoded in Base64.
**--]]
		function Base64.encode(Input)
			local Output = {}
			local Length = 0

			for Index = 1, #Input, 3 do
				local C1, C2, C3 = string.byte(Input, Index, Index + 2)

				local A = bit32_rshift(C1, 2)
				local B = bit32_lshift(bit32_band(C1, 3), 4) + bit32_rshift(C2 or 0, 4)
				local C = bit32_lshift(bit32_band(C2 or 0, 15), 2) + bit32_rshift(C3 or 0, 6)
				local D = bit32_band(C3 or 0, 63)

				Length = Length + 1
				Output[Length] = Alphabet[A + 1]

				Length = Length + 1
				Output[Length] = Alphabet[B + 1]

				Length = Length + 1
				Output[Length] = C2 and Alphabet[C + 1] or 61

				Length = Length + 1
				Output[Length] = C3 and Alphabet[D + 1] or 61
			end

			local NewOutput = {}
			local NewLength = 0
			local IndexAdd4096Sub1

			for Index = 1, Length, 4096 do
				NewLength = NewLength + 1
				IndexAdd4096Sub1 = Index + 4096 - 1

				NewOutput[NewLength] = string.char(table.unpack(
					Output,
					Index,
					IndexAdd4096Sub1 > Length and Length or IndexAdd4096Sub1
					))
			end

			return table.concat(NewOutput)
		end

--[[**
	Decodes a string from Base64.
	@param [t:string] Input The input string to decode.
	@returns [t:string] The newly decoded string.
**--]]
		function Base64.decode(Input)
			local Output = {}
			local Length = 0

			for Index = 1, #Input, 4 do
				local C1, C2, C3, C4 = string.byte(Input, Index, Index + 3)

				local I1 = Indexes[C1] - 1
				local I2 = Indexes[C2] - 1
				local I3 = (Indexes[C3] or 1) - 1
				local I4 = (Indexes[C4] or 1) - 1

				local A = bit32_lshift(I1, 2) + bit32_rshift(I2, 4)
				local B = bit32_lshift(bit32_band(I2, 15), 4) + bit32_rshift(I3, 2)
				local C = bit32_lshift(bit32_band(I3, 3), 6) + I4

				Length = Length + 1
				Output[Length] = A

				if C3 ~= 61 then
					Length = Length + 1
					Output[Length] = B
				end

				if C4 ~= 61 then
					Length = Length + 1
					Output[Length] = C
				end
			end

			local NewOutput = {}
			local NewLength = 0
			local IndexAdd4096Sub1

			for Index = 1, Length, 4096 do
				NewLength = NewLength + 1
				IndexAdd4096Sub1 = Index + 4096 - 1

				NewOutput[NewLength] = string.char(table.unpack(
					Output,
					Index,
					IndexAdd4096Sub1 > Length and Length or IndexAdd4096Sub1
					))
			end

			return table.concat(NewOutput)
		end

		return Base64
	end)()
	
	local env = {}
	
	local filesystem = {} do
		filesystem.__index = filesystem -- setmetatable(filesystem, cfilesystem) for filesystem wrappers
		
		local currentTime = tick
		
		local DEBUG = false
		
		filesystem.umask = 022
		filesystem.types = {
			dir = "di",
			link = "ln",
			socket = "so",
			pipe = "pi",
			exe = "ex",
			file = "fl"
		}
		
		function filesystem.extname(path)
			local dot_index = path:match(".*()%.")

			if not dot_index or dot_index == 1 then
				return ""
			end

			return path:sub(dot_index)
		end
		
		function filesystem.join(...)
			local parts = {...}
			local result = {}

			for _, path in ipairs(parts) do
				path = path:gsub("^/+", "")
				path = path:gsub("/+$", "")
				if path and path ~= "" then
					table.insert(result, path)
				end
			end

			return "/" .. table.concat(result, "/") .. "/"
		end
		
		function filesystem.basename(path)
			path = path:gsub("^/+", "")
			path = path:gsub("/+$", "")
			local base = path:match("([^/]+)$")
			return base or ""
		end
		
		local function createNode(type, content)
			return {
				type = type,
				metadata = {
					created = currentTime(),
					modified = currentTime(),
					permissions = type == "file" and 666 - filesystem.umask or 777 - filesystem.umask,
				},
				content = type == filesystem.types.file and content or nil,
				contents = type == filesystem.types.dir and (content or {}) or nil
			}
		end

		function filesystem.splitpath(path)
			local dirs = {}
			local stack = {}

			for dir in path:gmatch("[^/]+") do
				if dir == ".." then
					if #stack > 0 then
						table.remove(stack)
					end
				elseif dir ~= "." and dir ~= "" then
					table.insert(stack, dir)
				end
			end
			for i, dir in ipairs(stack) do
				table.insert(dirs, dir)
			end

			return dirs
		end
		
		function filesystem.prefix(path, prefix, dir)
			if path:sub(1, #prefix) == prefix then
				path = filesystem.join(dir, path:sub(#prefix + 1))
			end
			if path:sub(1, #prefix + 1) == "/" .. prefix or path:sub(1, #prefix + 1) == prefix .. "/" then
				path = filesystem.join(dir, path:sub(#prefix + 2))
			end
			return path
		end
		
		function filesystem.parsecontext(path, home, dir)
			path = filesystem.prefix(path, "~")
			path = filesystem.prefix(path, ".")
			path = table.concat(filesystem.splitpath(path), "/")
			if #path == 0 then
				path = "/"
			end
			return path
		end

		local function getNode(currentNode, path)
			local dirs = filesystem.splitpath(path)

			for _, dir in ipairs(dirs) do
				currentNode = currentNode.contents and currentNode.contents[dir]
				if not currentNode then
					return nil
				end
			end

			return currentNode
		end

		local function getDir(fs, path)
			local dirs = filesystem.splitpath(path)
			local parentPath = table.concat(dirs, "/", 1, #dirs - 1)
			local parentDir = getNode(fs, parentPath)

			if not parentDir or parentDir.type ~= filesystem.types.dir then
				return false, "No such directory: " .. parentPath
			end

			return true, parentDir, dirs
		end
		
		function filesystem.mkdir(fs, path)
			if DEBUG then print("mkdir", debug.traceback()) end
			
			local success, result, dirs = getDir(fs, path)
			if not success then
				return success, result
			end
			local name = dirs[#dirs]
			if result.contents[name] then
				return false, "Directory already exists: " .. path
			end
			result.contents[name] = createNode(filesystem.types.dir)
			return true
		end

		function filesystem.rmdir(fs, path)
			if DEBUG then print("rmdir", debug.traceback()) end

			local success, result, dirs = getDir(fs, path)
			if not success then
				return success, result
			end
			local name = dirs[#dirs]
			if not result.contents[name] then
				return false, "No such directory: " .. path
			end
			result.contents[name] = nil
			return true
		end

		function filesystem.create(fs, path, content, metadata)
			if DEBUG then print("create", debug.traceback()) end

			local success, result, dirs = getDir(fs, path)
			if not success then
				return success, result
			end
			local name = dirs[#dirs]
			if result.contents[name] then
				return false, "File already exists: " .. path
			end
			local node = createNode(filesystem.types.file, content)
			if metadata then
				for index, value in metadata do
					node.metadata[index] = value
				end
			end
			result.contents[name] = node
			return true
		end

		function filesystem.rm(fs, path)
			if DEBUG then print("rm", debug.traceback()) end

			local success, result, dirs = getDir(fs, path)
			if not success then
				return success, result
			end
			local name = dirs[#dirs]
			if not result.contents[name] then
				return false, "No such file: " .. path
			end
			result.contents[name] = nil
			return true
		end
		
		function filesystem.readdir(fs, path)
			if DEBUG then print("readdir", debug.traceback()) end

			local success, result, dirs = getDir(fs, path)
			if not success then
				return success, result
			end
			local contents = {}
			if path == "/" then
				contents = result.contents
			else
				local name = dirs[#dirs]
				if not result.contents[name] or result.contents[name].type ~= filesystem.types.dir then
					return false, "No such directory: " .. path
				end
				contents = result.contents[name].contents
			end
			local paths = {}
			for node in contents do
				table.insert(paths, filesystem.join(path, node))
			end
			return true, paths
		end

		function filesystem.read(fs, path)
			if DEBUG then print("read", debug.traceback()) end

			local file = getNode(fs, path)
			if file and file.type == filesystem.types.file then
				return true, file.content
			else
				return false, "No such file: " .. path
			end
		end

		function filesystem.write(fs, path, content, metadata)
			if DEBUG then print("write", debug.traceback()) end

			local file = getNode(fs, path)
			if file and file.type == filesystem.types.file then
				file.content = content
				file.metadata.modified = currentTime()
				if metadata then
					for index, value in metadata do
						file.metadata[index] = value
					end
				end
				return true
			else
				return filesystem.create(fs, path, content, metadata)
			end
		end

		function filesystem.metadata(fs, path)
			if DEBUG then print("metadata", debug.traceback()) end

			local node = getNode(fs, path)
			if node then
				local metadata = node.metadata
				metadata.type = node.type
				metadata.subtype = node.subtype
				return true, metadata
			end
			return false, "No such file or directory: " .. path
		end
		
		function filesystem.symlink(fs, path1, path2)
			local node1 = getNode(fs, path1)
			if not node1 then
				return false, "No such file or directory: " .. path1
			end
			local node2 = getNode(fs, path2)
			if not node2 then
				return false, "No such file or directory: " .. path2
			end
			
			node1.content = nil
			node1.contents = nil
			node1.subtype = filesystem.types.link
			
			setmetatable(node1, {
				__index = function(_, index)
					if index == "metadata" or index == "subtype" then
						return node1[index]
					end
					return node2[index]
				end,
				__newindex = function(_, index, value)
					node2[index] = value
				end,
			})
			
			return true
		end
		
		function filesystem.exists(fs, path)
			local node = getNode(fs, path)
			return node ~= nil and true or false
		end
		
		function filesystem.new()
			if DEBUG then print("new", debug.traceback()) end

			return createNode(filesystem.types.dir)
		end
	end
		
	local fs = filesystem.new() do		
		local rootfs = {
			"/bin",
			"/boot",
			"/dev",
			"/etc",
			"/etc/default",
			"/etc/network",
			"/etc/profile",
			"/etc/rc.d",
			"/etc/xdg",
			"/home",
			"/lib",
			"/lib64",
			"/media",
			"/mnt",
			"/opt",
			"/proc",
			"/root",
			"/run",
			"/sbin",
			"/srv",
			"/sys",
			"/tmp",
			"/usr",
			"/usr/bin",
			"/usr/lib",
			"/usr/lib64",
			"/usr/local",
			"/usr/local/bin",
			"/usr/local/etc",
			"/usr/local/games",
			"/usr/local/lib",
			"/usr/local/sbin",
			"/usr/local/share",
			"/usr/local/src",
			"/usr/sbin",
			"/usr/share",
			"/usr/share/doc",
			"/usr/share/man",
			"/usr/src",
			"/var",
			"/var/cache",
			"/var/lib",
			"/var/lib/machines",
			"/var/lib/pacman",
			"/var/lib/systemd",
			"/var/lib/dbus",
			"/var/lib/logrotate",
			"/var/local",
			"/var/lock",
			"/var/log",
			"/var/mail",
			"/var/opt",
			"/var/run",
			"/var/spool",
			"/var/tmp"
		}
		
		local failed = false
		
		local function safe(func, ...)
			local success, result = func(...)
			if not success then
				failed = true
				warn(result)
			end
			return success, result
		end
		
		for _, path in rootfs do
			safe(filesystem.mkdir, fs, path)
		end
		
		safe(filesystem.symlink, fs, "/bin", "/usr/bin")
		safe(filesystem.symlink, fs, "/lib", "/usr/lib")
		safe(filesystem.symlink, fs, "/lib64", "/usr/lib64")
		safe(filesystem.symlink, fs, "/sbin", "/usr/sbin")

		safe(filesystem.write, fs, "/etc/machine-id", HttpService:GenerateGUID(false))
		safe(filesystem.write, fs, "/etc/os-release", `NAME="Arch Linux"\nPRETTY_NAME="Arch Linux"\nID=arch\nBUILD_ID=rolling\nANSI_COLOR="38;2;23;147;209"\nHOME_URL="https://archlinux.org/"\nDOCUMENTATION_URL="https://wiki.archlinux.org/"\nSUPPORT_URL="https://bbs.archlinux.org/"\nBUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues"\nPRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"\nLOGO=archlinux-logo`)
		safe(filesystem.write, fs, "/etc/issue", "Arch Linux \r (\l)")
		
		safe(filesystem.write, fs, "/usr/bin/ls", base64.decode("BQENBGFyZ3MEc2VsZgNkaXIKZmlsZXN5c3RlbQhtZXRhZGF0YQR0eXBlBXR5cGVzB3JlYWRkaXIIYmFzZW5hbWUFdGFibGUGaW5zZXJ0BmNvbmNhdAEgAQ8AAAEAADpBAAAADAEBAAAAAEARAAEAGQACAAwABAAADCCADAEHAAAYUIAGAgAAFQECAxkBAwADAwAABgQCABYDAwAPAwJxCAAAAAwECgADJFDAHgMfAAQAAAAMAwwAACxQgAYEAAAVAwIDGgMfADUFAAAAAAAABgYEAAIHAAACCAAATAYJAAYMBQAMDQ4AADRQgAYOCgAVDQIARDQAAgwLEQAAQPCAFQsAAToG9v8CAAAAAwYBAAwHEwAASPCABggFAAUJFAAVBwMAFgYAABYAAQADAwEADAQOAAA0UIAGBQAAFQQCABYDAAAWAAEAFQMBBAAAAEADAgMDBAAMIIADBAMFBAAYUIADBgMHBAMkUMADCAQALFCAAwkEADRQgAMKAwsEAEDwgAMMBABI8IADDQABAAEYAAAAAAAAAAEAAAABAQAAAgAAAAAAAQAAAAEBAAEAAAABAAAAAAAAAAD/AAMAAAAAAAAE/wAAAAAAAQEAAAAAAA=="))
		safe(filesystem.write, fs, "/usr/bin/cat", base64.decode("BQEIBGFyZ3MKZmlsZXN5c3RlbQhtZXRhZGF0YQR0eXBlBXR5cGVzA2RpchA6IElzIGEgZGlyZWN0b3J5BHJlYWQBBwAAAQIAHEEAAAAMAQEAAAAAQBEAAQAMAQQAAAwggAYCAAAVAQIDGQEBABYCAgAPAwJxBQAAAAwECAAHGCDAHgMGAAQAAAADAwAABgUAAAUGCQAxBAUGFgMDAAwDCwAAKCCABgQAABUDAgMDBQEABgYEABYFAwAMAwEEAAAAQAMCAwMEAAwggAMEAwUDBgQHGCDAAwcDCAQAKCCAAAEAARgAAAAAAQAAAAEBAgAAAAAAAQAAAAACAAAAAQAAAQAAAAAA"))
		safe(filesystem.write, fs, "/usr/bin/clear", base64.decode("BQEDBHNlbGYFY2xlYXIpY2xlYXI6IHRlcm1pbmFsIGRvZXMgbm90IHN1cHBvcnQgY2xlYXJpbmcBAgAAAQIADkEAAAAMAAIAAAQAgBoABwAMAAMAAAAAQBQAALABAAAAFQACAQMAAQAWAAIAAwAAAAUBBAAWAAMABQMBAwIEAAQAgAQAAABAAwMAAQABGAAAAAABAAAAAAEAAgAAAQAAAAAA"))
		safe(filesystem.write, fs, "/usr/bin/cd", base64.decode("BQEHAX4EYXJncwpmaWxlc3lzdGVtBmV4aXN0cxs6IE5vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnkCY2QeZmFpbGVkOiBhcmUgeW91IGluIGEgdGVybWluYWw/AQYAAAECABxBAAAADAICAAAAEEARAQIAMAABAAwBBQAAEDCABgIAABUBAgIZAQUAAwIAAAYEAAAFBQYAMQMEBRYCAwAMAggAAABwQBoCBQAMAggAAABwQAYDAAAVAgIBFwADAAMCAAAFAwkAFgIDAAMCAQAWAgIACgMBAwIEAAAQQAMDAwQEABAwgAMFAwYEAABwQAMHAAEAARgAAAAAAAEAAAABAQAAAAACAAABAAAAAAIAAAIAAQAAAAAA"))
		safe(filesystem.write, fs, "/usr/bin/touch", base64.decode("BQEKBGFyZ3MHb3B0aW9ucwF0CG1vZGlmaWVkCmZpbGVzeXN0ZW0GZXhpc3RzBHJlYWQFd3JpdGUHY3JlYXRlZAABCQAAAQIALUEAAAAMAQEAAAAAQBEAAQAMAQQAAAwggAICAAAaAQQANgMGABABA6QFAAAABgIDAAwDCQAAIHCABgQAABUDAgIaAw0ADAMLAAAocIAGBAAAFQMCAxoDFgAMBQ0AADBwgAYGAAAGBwQABggCABUFBAAWBQAAFgABAA8DAqQFAAAAEAMC0A4AAAACAwAAEAMCpAUAAAAMAw0AADBwgAYEAAAFBQ8ABgYCABUDBAAWAwAAFgABABADAQQAAABAAwIDAwQADCCAAwQFAQUDBQMGBAAgcIADBwQAKHCAAwgEADBwgAMJAwoAAQABGAAAAAABAAEBAQEAAAMAAAAAAQAAAAEBAAAAAAAAB/wAAAABAAABAAAAAAAAAgEAAAAAAA=="))
		
		safe(filesystem.write, fs, "/usr/bin/fastfetch-icon", base64.decode("BQETBlteDQpdKwZnbWF0Y2gMXiVzKiguLSklcyokBW1hdGNoAAJeIw5eKFsld19dKyk9KC4qKQheIiguKikiJAheJyguKiknJBNwYXJzZUtleVZhbHVlU3RyaW5nCmZpbGVzeXN0ZW0EcmVhZA8vZXRjL29zLXJlbGVhc2UCaWQFcGNhbGwEaHR0cAhHZXRBc3luY0xodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZmFzdGZldGNoLWNsaS9mYXN0ZmV0Y2gvZGV2L3NyYy9sb2dvL2FzY2lpBC50eHQCDAEAAAAAKTUBAAAAAAAABQQAABQCAIgBAAAAFQIDBEwCHwAFCQIAFAcF5wMAAAAVBwMCBgUHAFAFGQAEAAAABQkFABQHBecDAAAAFQcDAhkHEwAFCQYAFAcF5wMAAAAVBwMDGgcOABoIDQAFCwcAFAkI5wMAAAAVCQMCGQkGAAULCAAUCQjnAwAAABUJAwIZCQEABgkIAAYICQAOCAEHOgLg/wEAAAAWAQIACQMBAwIDAwMEAwUDBgMHAwgDCQABCgEYAAACAAAAAAEAAAAAAQAAAAAAAAEAAAACAAEAAAAAAAAAAAAAAAH5AAwCAAAAAAsAAAECACJBAAAAQAAAAAwBAwAACBCABQIEABUBAgMaARgABgMAAAYEAgAVAwICBgIDAA8DAvQFAAAADAQHAAAAYEAMBQoAACSAgAwGCwAAAIBABQgMAAYJAwAFCg0AMQcIChUEBAMaBAMAAwYBAAYHBQAWBgMAAwYAAAYHBQAWBgMAAwMAAAYEAgAWAwMADgYAAwsDDAQACBCAAw0DDgMPBAAAYEADEAMRBAAkgIAEAACAQAMSAxMBAAEAARgAABIAAAABAQAAAAEAAQAAAAAAAAAAAAABAQAAAgAAAwAAAQAAAAAB"))
		safe(filesystem.write, fs, "/usr/bin/fastfetch-icon.luau", [[local function parseKeyValueString(str)
	local result = {}

	for line in str:gmatch("[^\r\n]+") do
		line = line:match("^%s*(.-)%s*$")
		if line ~= "" and not line:match("^#") then
			local key, value = line:match("^([%w_]+)=(.*)")

			if key and value then
				value = value:match('^"(.*)"$') or value:match("^'(.*)'$") or value
				result[key] = value
			end
		end
	end

	return result
end

local gotosrelease, osrelease = filesystem.read("/etc/os-release")
if gotosrelease then
	osrelease = parseKeyValueString(osrelease)
	local id = osrelease.ID
	if not id then
		return false, "invalid os-release parameters, missing ID"
	end
	local goticon, iconresponse = pcall(http.GetAsync, http, "https://raw.githubusercontent.com/fastfetch-cli/fastfetch/dev/src/logo/ascii/"..id..".txt")
	if goticon then
		return true, iconresponse
	else
		return false, iconresponse
	end
else
	return false, osrelease
end]])
		
		if failed then
			error("failed creating rootfs")
		end
	end

	local term = Roact.Component:extend("term") do
		local function parseCommand(commandString)
			local command, argsString = commandString:match("^(%S+)%s*(.*)")
			local args = {}

			local pos = 1
			local inQuotes = false
			local currentArg = ""

			while pos <= #argsString do
				local char = argsString:sub(pos, pos)

				if char == '"' then
					inQuotes = not inQuotes
				elseif char == ' ' and not inQuotes then
					if #currentArg > 0 then
						table.insert(args, currentArg)
						currentArg = ""
					end
				else
					currentArg = currentArg .. char
				end

				pos = pos + 1
			end

			if #currentArg > 0 then
				table.insert(args, currentArg)
			end

			return command, args
		end

		local function parseOptions(args)
			local parsedArgs = { options = {}, positional = {} }

			local function handleArg(arg)
				if arg:match("^%-%-") then
					local key, value = arg:match("^%-%-(%S+)%s*(.*)")
					parsedArgs.options[key] = value == "" and true or value
				elseif arg:match("^%-%S") then
					local key = arg:sub(2)
					parsedArgs.options[key] = true
				else
					table.insert(parsedArgs.positional, arg)
				end
			end

			for i = 1, #args do
				handleArg(args[i])
			end

			return parsedArgs
		end
		
		term.colors = {
			--basic
			[0]  = "#000000", -- Black
			[1]  = "#ff0000", -- Red
			[2]  = "#00ff00", -- Green
			[3]  = "#ffff00", -- Yellow
			[4]  = "#0000ff", -- Blue
			[5]  = "#ff00ff", -- Magenta
			[6]  = "#00ffff", -- Cyan
			[7]  = "#ffffff", -- White
			[8]  = "#808080", -- Bright Black (Gray)
			[9]  = "#ff6666", -- Bright Red
			[10] = "#66ff66", -- Bright Green
			[11] = "#ffff66", -- Bright Yellow
			[12] = "#6666ff", -- Bright Blue
			[13] = "#ff66ff", -- Bright Magenta
			[14] = "#66ffff", -- Bright Cyan
			[15] = "#ffffff", -- Bright White
			
			--extended
			[16]  = "#000000", [17] = "#800000", [18] = "#008000", [19] = "#808000",
			[20]  = "#000080", [21] = "#800080", [22] = "#008080", [23] = "#c0c0c0",
			[24]  = "#808080", [25] = "#ff0000", [26] = "#00ff00", [27] = "#ffff00",
			[28]  = "#0000ff", [29] = "#ff00ff", [30] = "#00ffff", [31] = "#ffffff",
			[32]  = "#000000", [33] = "#00005f", [34] = "#000087", [35] = "#0000af",
			[36]  = "#0000d7", [37] = "#0000ff", [38] = "#005f00", [39] = "#005f5f",
			[40]  = "#005f87", [41] = "#005faf", [42] = "#007f00", [43] = "#007f5f",
			[44]  = "#007f87", [45] = "#007faf", [46] = "#007fd7", [47] = "#007fff",
			[48]  = "#00af00", [49] = "#00af5f", [50] = "#00af87", [51] = "#00afaf",
			[52]  = "#00afd7", [53] = "#00afff", [54] = "#00d700", [55] = "#00d75f",
			[56]  = "#00d787", [57] = "#00d7af", [58] = "#00d7d7", [59] = "#00d7ff",
			[60]  = "#00ff00", [61] = "#00ff5f", [62] = "#00ff87", [63] = "#00ffaf",
			[64]  = "#00ffd7", [65] = "#00ffff", [66] = "#5f0000", [67] = "#5f005f",
			[68]  = "#5f0087", [69] = "#5f00af", [70] = "#5f00d7", [71] = "#5f00ff",
			[72]  = "#5f5f00", [73] = "#5f5f5f", [74] = "#5f5f87", [75] = "#5f5faf",
			[76]  = "#5f5fd7", [77] = "#5f5fff", [78] = "#5f8700", [79] = "#5f875f",
			[80]  = "#5f8787", [81] = "#5f87af", [82] = "#5f87d7", [83] = "#5f87ff",
			[84]  = "#5faf00", [85] = "#5faf5f", [86] = "#5faf87", [87] = "#5fafaf",
			[88]  = "#5fafd7", [89] = "#5fafff", [90] = "#5fd700", [91] = "#5fd75f",
			[92]  = "#5fd787", [93] = "#5fd7af", [94] = "#5fd7d7", [95] = "#5fd7ff",
			[96]  = "#5fff00", [97] = "#5fff5f", [98] = "#5fff87", [99] = "#5fffaf",
			[100] = "#5fffd7", [101] = "#5fffff", [102] = "#870000", [103] = "#87005f",
			[104] = "#870087", [105] = "#8700af", [106] = "#8700d7", [107] = "#8700ff",
			[108] = "#875f00", [109] = "#875f5f", [110] = "#875f87", [111] = "#875faf",
			[112] = "#875fd7", [113] = "#875fff", [114] = "#878700", [115] = "#87875f",
			[116] = "#878787", [117] = "#8787af", [118] = "#8787d7", [119] = "#8787ff",
			[120] = "#87af00", [121] = "#87af5f", [122] = "#87af87", [123] = "#87afaf",
			[124] = "#87afd7", [125] = "#87afff", [126] = "#87d700", [127] = "#87d75f",
			[128] = "#87d787", [129] = "#87d7af", [130] = "#87d7d7", [131] = "#87d7ff",
			[132] = "#87ff00", [133] = "#87ff5f", [134] = "#87ff87", [135] = "#87ffaf",
			[136] = "#87ffd7", [137] = "#87ffff", [138] = "#af0000", [139] = "#af005f",
			[140] = "#af0087", [141] = "#af00af", [142] = "#af00d7", [143] = "#af00ff",
			[144] = "#af5f00", [145] = "#af5f5f", [146] = "#af5f87", [147] = "#af5faf",
			[148] = "#af5fd7", [149] = "#af5fff", [150] = "#af8700", [151] = "#af875f",
			[152] = "#af8787", [153] = "#af87af", [154] = "#af87d7", [155] = "#af87ff",
			[156] = "#afaf00", [157] = "#afaf5f", [158] = "#afaf87", [159] = "#afafaf",
			[160] = "#afafd7", [161] = "#afafff", [162] = "#afd700", [163] = "#afd75f",
			[164] = "#afd787", [165] = "#afd7af", [166] = "#afd7d7", [167] = "#afd7ff",
			[168] = "#afff00", [169] = "#afff5f", [170] = "#afff87", [171] = "#afffaf",
			[172] = "#afffd7", [173] = "#afffff", [174] = "#d70000", [175] = "#d7005f",
			[176] = "#d70087", [177] = "#d700af", [178] = "#d700d7", [179] = "#d700ff",
			[180] = "#d75f00", [181] = "#d75f5f", [182] = "#d75f87", [183] = "#d75faf",
			[184] = "#d75fd7", [185] = "#d75fff", [186] = "#d78700", [187] = "#d7875f",
			[188] = "#d78787", [189] = "#d787af", [190] = "#d787d7", [191] = "#d787ff",
			[192] = "#d7af00", [193] = "#d7af5f", [194] = "#d7af87", [195] = "#d7afaf",
			[196] = "#d7afd7", [197] = "#d7afff", [198] = "#d7d700", [199] = "#d7d75f",
			[200] = "#d7d787", [201] = "#d7d7af", [202] = "#d7d7d7", [203] = "#d7d7ff",
			[204] = "#d7ff00", [205] = "#d7ff5f", [206] = "#d7ff87", [207] = "#d7ffaf",
			[208] = "#d7ffd7", [209] = "#d7ffff", [210] = "#ff0000", [211] = "#ff005f",
			[212] = "#ff0087", [213] = "#ff00af", [214] = "#ff00d7", [215] = "#ff00ff",
			[216] = "#ff5f00", [217] = "#ff5f5f", [218] = "#ff5f87", [219] = "#ff5faf",
			[220] = "#ff5fd7", [221] = "#ff5fff", [222] = "#ff8700", [223] = "#ff875f",
			[224] = "#ff8787", [225] = "#ff87af", [226] = "#ff87d7", [227] = "#ff87ff",
			[228] = "#ffaf00", [229] = "#ffaf5f", [230] = "#ffaf87", [231] = "#ffafaf",
			[232] = "#ffafd7", [233] = "#ffafff", [234] = "#ffd700", [235] = "#ffd75f",
			[236] = "#ffd787", [237] = "#ffd7af", [238] = "#ffd7d7", [239] = "#ffd7ff",
			[240] = "#ffff00", [241] = "#ffff5f", [242] = "#ffff87", [243] = "#ffffaf",
			[244] = "#ffffd7", [245] = "#ffffff", [246] = "#000000", [247] = "#00005f",
			[248] = "#000087", [249] = "#0000af", [250] = "#0000d7", [251] = "#0000ff",
			[252] = "#005f00", [253] = "#005f5f", [254] = "#005f87", [255] = "#005faf",
		}
		
		local function sanitizeRichText(text)
			local replace = {
				['<'] = '&lt;',
				['>'] = '&gt;',
				['"'] = '&quot;',
				["'"] = '&apos;',
				['&'] = '&amp;'
			}


			local res = string.gsub(text, "([<>'\"\&])", replace)
			return res
		end
		
		function term.parsecolors(text)
			local richText = ""
			local i = 1
			while i <= #text do
				if text:sub(i, i) == "\27" then
					local codeStart = i + 1
					local codeEnd = text:find("m", codeStart)
					if codeEnd then
						local code = tonumber(text:sub(codeStart, codeEnd - 1))
						if code then
							if code >= 0 then
								richText = richText .. string.format("<font color=\"%s\">", term.colors[code])
							elseif code == 0 then
								richText = richText .. "</font>"
							end
							i = codeEnd
						end
					end
				else
					richText = richText .. text:sub(i, i)
				end
				i = i + 1
			end
			return richText
		end
		
		function term.parse(commandString, cfilesystem, self)
			local command, args = parseCommand(commandString)
			if not command then return end
			local parsedArgs = parseOptions(args)
			local path = filesystem.join("/usr/bin", command)
			local exists, content = filesystem.read(fs, path)
			if exists then
				local lenv = getfenv()
				lenv.args = args
				lenv.options = parsedArgs
				lenv.filesystem = cfilesystem
				lenv.http = HttpService
				lenv.env = setmetatable({}, {
					__index = function(_, index)
						return env[index]
					end,
					__newindex = function(_, index, value)
						env[index] = value
					end,
					__tostring = "env"
				})
				
				if self then
					lenv.self = self
					lenv.cd = function(path)
						path = filesystem.join(self.dir, path)
						path = filesystem.parsecontext(path, self.home, self.dir)
						self.dir = path
					end
				end
				
				local extname = filesystem.basename(path):split(".")
				extname = extname[#extname]

				local success, commandsuccess, commandresponse = pcall(function()
					local func
					if extname == "luau" or extname == "lua" then
						func = loadstring(content)
						func = setfenv(func, lenv)
					else 
						func = fiu.luau_load(content, lenv)
					end
					return func()
				end)
				if not success then
					return commandsuccess
				end
				if commandsuccess then
					return commandresponse
				else
					return command .. ": ".. (commandresponse or "")
				end
			else
				return command..": command not found"
			end
		end
		
		local function getHostname()
			local success, hostname = filesystem.read(fs, "/etc/hostname")
			if not success then
				hostname = "archlinux"
			end
			return hostname
		end
		
		function term:init()
			self.textSize, self.updateTextSize = Roact.createBinding(28)
			self.root = Roact.createRef()
			self.prefix = "[%s@%s %s]$"
			self.user = "root"
			self.home = "/root/"
			self.dir = self.home
			self.lines = 0
			
			local function parsepath(path)
				return filesystem.parsecontext(path, self.home, self.dir)
			end
			
			local termfilesystem = {}
			function termfilesystem.symlink(path1, path2)
				return filesystem.symlink(fs, parsepath(path1), parsepath(path2))
			end
			function termfilesystem.metadata(path)
				return filesystem.metadata(fs, parsepath(path))
			end
			function termfilesystem.rm(path)
				return filesystem.rm(fs, parsepath(path))
			end
			function termfilesystem.rmdir(path)
				return filesystem.rmdir(fs, parsepath(path))
			end
			function termfilesystem.read(path)
				return filesystem.read(fs, parsepath(path))
			end
			function termfilesystem.mkdir(path)
				return filesystem.mkdir(fs, parsepath(path))
			end
			function termfilesystem.write(path, ...)
				return filesystem.write(fs, parsepath(path), ...)
			end
			function termfilesystem.exists(path)
				return filesystem.exists(fs, parsepath(path))
			end
			function termfilesystem.readdir(path)
				return filesystem.readdir(fs, parsepath(path))
			end
			
			setmetatable(termfilesystem, filesystem)
			
			self.filesystem = termfilesystem
		end
		
		function term:clear()
			self.lines = 0
			for _, object in self.root:getValue():GetChildren() do
				if object:IsA("TextBox") then
					object:Destroy()
				end
			end
		end
		
		function term:print(content)
			local content, update = Roact.createBinding(content)
			local ref = Roact.createRef()
			local text = Roact.createElement("TextBox", {
				Size = Roact.joinBindings({self.textSize, content}):map(function(values)
					local size, content = unpack(values)
					local _, lineCount = content:gsub("\n", "\n")
					lineCount += 1

					return UDim2.new(1, 0, 0, size * lineCount)
				end),
				TextSize = self.textSize,
				BackgroundTransparency = 1,
				Font = Enum.Font.Code,
				TextColor3 = Color3.new(1, 1, 1),
				TextXAlignment = Enum.TextXAlignment.Left,
				TextYAlignment = Enum.TextYAlignment.Top,
				Text = content,
				TextEditable = false,
				ClearTextOnFocus = false,
				MultiLine = false,

				[Roact.Ref] = ref
			})

			self.lines += 1

			Roact.mount(text, self.root:getValue())

			local object = ref:getValue()
			object:SetAttribute("line", self.lines)

			return {
				content = content,
				update = update,
				object = object
			}

		end
		
		function term:newline(initial, prefix)
			local dirname = filesystem.basename(self.dir)
			if filesystem.join(self.dir) == filesystem.join(self.home) then
				dirname = "~"
			end
			if #dirname == 0 then
				dirname = "/"
			end
			local prefix = self.prefix:format(self.user, getHostname(), dirname)
			local line = self:print(prefix .. " " .. (initial or ""))
			line.object:SetAttribute("start", #prefix + 2)
			
			local update = line.update
			line.update = function(content)
				return update(prefix .. " " .. content)
			end
						
			return line
		end
		
		function term:didMount()
			local sg = Instance.new("ScreenGui")
			sg.ResetOnSpawn = false
			sg.Parent = owner.PlayerGui
			local remote = Instance.new("RemoteEvent")
			remote.Parent = sg
			NLS([[local remote, root = ...
			local sub = string.sub
			
			local uis = game:GetService("UserInputService")
			
			local lines = {}
			local currentline
			local text = ""
			local focused = false
			
			uis.InputBegan:Connect(function(input, gp)				
				if input.KeyCode == Enum.KeyCode.Return and focused then
					focused = false
					lines[currentline]:ReleaseFocus()
					remote:FireServer("return", text)
				end
			end)
			
			local inputs = {}
			function killinputs()
				for _, connection in pairs(inputs) do
					if typeof(connection) == "function" then
						connection()
					else
						connection:Disconnect()
					end
				end
				inputs = {}
			end
			
			function inputlisten(line)
				killinputs()
				local fake = line:Clone()
				fake.TextTransparency = 0.5
				fake:SetAttribute("line", nil)
				fake:SetAttribute("start", nil)
				fake.Size = UDim2.fromScale(1, 1)
				fake.ZIndex = 2
				fake.Name = "input"
				fake.TextEditable = true
				fake.Parent = line
								
				local start = line:GetAttribute("start")
				local prefix = sub(line.Text, 1, start - 2)
				
				text = sub(line.Text, start)

				table.insert(inputs, fake:GetPropertyChangedSignal("Text"):Connect(function()
					local new = fake.Text
					if sub(new, 1, start - 1) ~= prefix .. " " then
						fake.Text = prefix .. " "
					end
					text = sub(fake.Text, start)
					remote:FireServer("update", text)
				end))
				table.insert(inputs, fake.Focused:Connect(function()
					focused = true
				end))
				table.insert(inputs, fake.FocusLost:Connect(function()
					task.wait()
					focused = false
				end))
				table.insert(inputs, function()
					fake:Destroy()
					focused = false
					text = ""
				end)
			end

			function addline(line)
				local lineValue = line:GetAttribute("line")
				if lineValue and line:GetAttribute("start") then
					lines[lineValue] = line
					if lineValue > (currentline or 0) then
						currentline = lineValue
						inputlisten(line)
					end
					line:GetPropertyChangedSignal("Parent"):Connect(function()
						if line.Parent == nil then
							lines[lineValue] = nil
							if currentline == lineValue then
								currentline = nil
								killinputs()
							end
						end
					end)
				end
			end
			
			for _, line in pairs(root:GetChildren()) do
				addline(line)
			end
			
			root.ChildAdded:Connect(addline)
			
			root.InputBegan:Connect(function(input)
				if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
					if currentline then
						lines[currentline].input:CaptureFocus()
					end
				end
			end)]], sg, remote, self.root:getValue())
			local current = self:newline()
			remote.OnServerEvent:Connect(function(sender, action, data)
				if sender ~= owner then return end
				
				if action == "update" then
					current.update(data)
				elseif action == "return" then
					local result = term.parse(data, self.filesystem, self)
					if result then
						self:print(term.parsecolors(sanitizeRichText(tostring(result))))
					end
					current.update(data)
					current = self:newline()
				end
			end)
		end
		
		function term:render()
			local root = Roact.createElement("Frame", {
				Size = FULLSCALE,
				BackgroundColor3 = Color3.new(),
				BorderSizePixel = 0,
				ZIndex = 0,
				
				[Roact.Ref] = self.root
			}, {
				list = Roact.createElement("UIListLayout")
			})
			return root
		end
	end
	
	function linux:init()
		
	end

	function linux:render()
		local root = Roact.createElement("Frame", {
			Size = FULLSCALE,
			BackgroundColor3 = Color3.new(),
			BorderSizePixel = 0,
			ZIndex = 0,
		}, {
			term = Roact.createElement(term)
		})
		return root 
	end
end

local gui, screen do
	local resolution = Vector2.new(1920, 1080)
	local screenSize = 7
	screen = Instance.new("Part")
	screen.CanCollide = false
	screen.CanTouch = false
	screen.Locked = true
	screen.Name = "Base"
	screen.Size = Vector3.new(screenSize * (resolution.X / resolution.Y), screenSize, 0)
	screen.Anchored = true
	screen.Parent = script

	task.spawn(function()
		while true do
			task.wait()		
			local char = owner.Character
			if char then
				local hrp = char:FindFirstChild("HumanoidRootPart")
				if hrp then
					screen.CFrame = hrp.CFrame * CFrame.new(0, screen.Size.Y / 2, -5)
				end
			end
		end
	end)

	gui = Roact.createElement("SurfaceGui", {
		Face = Enum.NormalId.Back,
		SizingMode = Enum.SurfaceGuiSizingMode.FixedSize,
		CanvasSize = resolution,
		ClipsDescendants = true,
		ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
		LightInfluence = 0,
	}, {
		content = Roact.createElement(linux)
	})
end

Roact.mount(gui, screen)
INFO