local m={}local n=game:GetService("\072\116\116\112\083\101\114\118\105\099\101")local function w(m)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")local n={}for m,L in pairs(m)do if type(L)=="\116\097\098\108\101"then n[m]=w(L)else n[m]=L end end return n end local function L(m,n)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")assert(type(n)=="\116\097\098\108\101","\083\101\099\111\110\100 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")for t,d in pairs(m)do local p=n[t]if p==nil then m[t]=nil elseif type(d)~=type(p)then if type(p)=="\116\097\098\108\101"then m[t]=w(p)else m[t]=p end elseif type(d)=="\116\097\098\108\101"then L(d,p)end end for n,L in pairs(n)do local t=m[n]if t==nil then if type(L)=="\116\097\098\108\101"then m[n]=w(L)else m[n]=L end end end end local function t(m,n)local w=#m m[n]=m[w]m[w]=nil end local function d(m,n)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")assert(type(n)=="\102\117\110\099\116\105\111\110","\083\101\099\111\110\100 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097\110 \097\114\114\097\121")local w={}for L,t in pairs(m)do w[L]=n(t,L,m)end return w end local function p(m,n)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")assert(type(n)=="\102\117\110\099\116\105\111\110","\083\101\099\111\110\100 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097\110 \097\114\114\097\121")local w={}if#m>0 then local L=0 for t=1,#m,1 do local d=m[t]if n(d,t,m)then L=L+1 w[L]=d end end else for L,t in pairs(m)do if n(t,L,m)then w[L]=t end end end return w end local function h(m,n,w)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")assert(type(n)=="\102\117\110\099\116\105\111\110","\083\101\099\111\110\100 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097\110 \097\114\114\097\121")assert(w==nil or type(w)=="\110\117\109\098\101\114","\084\104\105\114\100 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114 \111\114 \110\105\108")local L=w or 0 for w,t in pairs(m)do L=n(L,t,w,m)end return L end local function Z(m,n,w)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")assert(n==nil or type(n)=="\115\116\114\105\110\103","\083\101\099\111\110\100 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103 \111\114 \110\105\108")n=n or"\084\065\066\076\069"local L={}local t=" - "local function d(m,n)L[#L+1]=t:rep(n)..(m.."\n")end local function p(m,n)return tostring(m.k)<tostring(n.k)end local function h(m,n,L)d(L.."\058",n-1)local t={}local Z={}local v=0 for m,n in pairs(m)do if type(n)=="\116\097\098\108\101"then table.insert(Z,{k=m;v=n})else table.insert(t,{k=m;v="\091"..(typeof(n)..("\093 "..tostring(n)))})end local w=#tostring(m)+1 if w>v then v=w end end table.sort(t,p)table.sort(Z,p)for m,w in pairs(t)do d(tostring(w.k)..("\058"..((" "):rep(v-#tostring(w.k))..w.v)),n)end if w then for m,w in pairs(Z)do h(w.v,n+1,tostring(w.k)..((" "):rep(v-#tostring(w.k)).." \091\084\097\098\108\101\093"))end else for m,w in pairs(Z)do d(tostring(w.k)..("\058"..((" "):rep(v-#tostring(w.k)).."\091\084\097\098\108\101\093")),n)end end end h(m,1,n)print(table.concat(L,""))end local function v(m,n)for w=1,#m,1 do if m[w]==n then return w end end return nil end local function f(m)local n={}local w=#m for L=1,w,1 do n[L]=m[(w-L)+1]end return n end local function D(m)assert(type(m)=="\116\097\098\108\101","\070\105\114\115\116 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \116\097\098\108\101")for n=#m,2,-1 do local w=math.random(n)m[n],m[w]=m[w],m[n]end end local function s(m)return next(m)==nil end local function O(m)return n:JSONEncode(m)end local function Y(m)return n:JSONDecode(m)end local function U(m,n)local w=v(m,n)if w then t(m,w)return true,w end return false,nil end m.Copy=w m.Sync=L m.FastRemove=t m.FastRemoveFirstValue=U m.Print=Z m.Map=d m.Filter=p m.Reduce=h m.IndexOf=v m.Reverse=f m.Shuffle=D m.IsEmpty=s m.EncodeJSON=O m.DecodeJSON=Y return m




local TableUtil = {}

local http = game:GetService("HttpService")


local function CopyTable(t)
	assert(type(t) == "table", "First argument must be a table")
	local tCopy = {}
	for k,v in pairs(t) do
		if (type(v) == "table") then
			tCopy[k] = CopyTable(v)
		else
			tCopy[k] = v
		end
	end
	return tCopy
end


local function Sync(tbl, templateTbl)

	assert(type(tbl) == "table", "First argument must be a table")
	assert(type(templateTbl) == "table", "Second argument must be a table")
	
	-- If 'tbl' has something 'templateTbl' doesn't, then remove it from 'tbl'
	-- If 'tbl' has something of a different type than 'templateTbl', copy from 'templateTbl'
	-- If 'templateTbl' has something 'tbl' doesn't, then add it to 'tbl'
	for k,v in pairs(tbl) do
		
		local vTemplate = templateTbl[k]
		
		-- Remove keys not within template:
		if (vTemplate == nil) then
			tbl[k] = nil
			
		-- Synchronize data types:
		elseif (type(v) ~= type(vTemplate)) then
			if (type(vTemplate) == "table") then
				tbl[k] = CopyTable(vTemplate)
			else
				tbl[k] = vTemplate
			end
		
		-- Synchronize sub-tables:
		elseif (type(v) == "table") then
			Sync(v, vTemplate)
		end
		
	end
	
	-- Add any missing keys:
	for k,vTemplate in pairs(templateTbl) do
		
		local v = tbl[k]
		
		if (v == nil) then
			if (type(vTemplate) == "table") then
				tbl[k] = CopyTable(vTemplate)
			else
				tbl[k] = vTemplate
			end
		end
		
	end
	
end


local function FastRemove(t, i)
	local n = #t
	t[i] = t[n]
	t[n] = nil
end


local function Map(t, f)
	assert(type(t) == "table", "First argument must be a table")
	assert(type(f) == "function", "Second argument must be an array")
	local newT = {}
	for k,v in pairs(t) do
		newT[k] = f(v, k, t)
	end
	return newT
end


local function Filter(t, f)
	assert(type(t) == "table", "First argument must be a table")
	assert(type(f) == "function", "Second argument must be an array")
	local newT = {}
	if (#t > 0) then
		local n = 0
		for i = 1,#t do
			local v = t[i]
			if (f(v, i, t)) then
				n = (n + 1)
				newT[n] = v
			end
		end
	else
		for k,v in pairs(t) do
			if (f(v, k, t)) then
				newT[k] = v
			end
		end
	end
	return newT
end


local function Reduce(t, f, init)
	assert(type(t) == "table", "First argument must be a table")
	assert(type(f) == "function", "Second argument must be an array")
	assert(init == nil or type(init) == "number", "Third argument must be a number or nil")
	local result = (init or 0)
	for k,v in pairs(t) do
		result = f(result, v, k, t)
	end
	return result
end


local function Print(tbl, label, deepPrint)

	assert(type(tbl) == "table", "First argument must be a table")
	assert(label == nil or type(label) == "string", "Second argument must be a string or nil")
	
	label = (label or "TABLE")
	
	local strTbl = {}
	local indent = " - "
	
	-- Insert(string, indentLevel)
	local function Insert(s, l)
		strTbl[#strTbl + 1] = (indent:rep(l) .. s .. "\n")
	end
	
	local function AlphaKeySort(a, b)
		return (tostring(a.k) < tostring(b.k))
	end
	
	local function PrintTable(t, lvl, lbl)
		Insert(lbl .. ":", lvl - 1)
		local nonTbls = {}
		local tbls = {}
		local keySpaces = 0
		for k,v in pairs(t) do
			if (type(v) == "table") then
				table.insert(tbls, {k = k, v = v})
			else
				table.insert(nonTbls, {k = k, v = "[" .. typeof(v) .. "] " .. tostring(v)})
			end
			local spaces = #tostring(k) + 1
			if (spaces > keySpaces) then
				keySpaces = spaces
			end
		end
		table.sort(nonTbls, AlphaKeySort)
		table.sort(tbls, AlphaKeySort)
		for _,v in pairs(nonTbls) do
			Insert(tostring(v.k) .. ":" .. (" "):rep(keySpaces - #tostring(v.k)) .. v.v, lvl)
		end
		if (deepPrint) then
			for _,v in pairs(tbls) do
				PrintTable(v.v, lvl + 1, tostring(v.k) .. (" "):rep(keySpaces - #tostring(v.k)) .. " [Table]")
			end
		else
			for _,v in pairs(tbls) do
				Insert(tostring(v.k) .. ":" .. (" "):rep(keySpaces - #tostring(v.k)) .. "[Table]", lvl)
			end
		end
	end
	
	PrintTable(tbl, 1, label)
	
	print(table.concat(strTbl, ""))
	
end


local function IndexOf(tbl, item)
	for i = 1,#tbl do
		if (tbl[i] == item) then
			return i
		end
	end
	return nil
end


local function Reverse(tbl)
	local tblRev = {}
	local n = #tbl
	for i = 1,n do
		tblRev[i] = tbl[n - i + 1]
	end
	return tblRev
end


local function Shuffle(tbl)
	assert(type(tbl) == "table", "First argument must be a table")
	for i = #tbl, 2, -1 do
		local j = math.random(i)
		tbl[i], tbl[j] = tbl[j], tbl[i]
	end
end


local function IsEmpty(tbl)
	return (next(tbl) == nil)
end


local function EncodeJSON(tbl)
	return http:JSONEncode(tbl)
end


local function DecodeJSON(str)
	return http:JSONDecode(str)
end


local function FastRemoveFirstValue(t, v)
	local index = IndexOf(t, v)
	if (index) then
		FastRemove(t, index)
		return true, index
	end
	return false, nil
end


TableUtil.Copy = CopyTable
TableUtil.Sync = Sync
TableUtil.FastRemove = FastRemove
TableUtil.FastRemoveFirstValue = FastRemoveFirstValue
TableUtil.Print = Print
TableUtil.Map = Map
TableUtil.Filter = Filter
TableUtil.Reduce = Reduce
TableUtil.IndexOf = IndexOf
TableUtil.Reverse = Reverse
TableUtil.Shuffle = Shuffle
TableUtil.IsEmpty = IsEmpty
TableUtil.EncodeJSON = EncodeJSON
TableUtil.DecodeJSON = DecodeJSON


return TableUtil
