local function S(S,...)for z,m in ipairs({...})do for z,m in pairs(m)do S[z]=m end end return S end local function z(S,z,m)assert(type(S)=="\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(z==nil or type(z)=="\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")z=z or"\084\065\066\076\069"local r={}local Y=" - "local function O(S,z)r[#r+1]=Y:rep(z)..(S.."\n")end local function G(S,z)return tostring(S.k)<tostring(z.k)end local function I(S,z,r)O(r.."\058",z-1)local Y={}local R={}local B=0 for S,z in pairs(S)do if type(z)=="\116\097\098\108\101"then table.insert(R,{k=S,v=z})else table.insert(Y,{k=S;v="\091"..(typeof(z)..("\093 "..tostring(z)))})end local m=#tostring(S)+1 if m>B then B=m end end table.sort(Y,G)table.sort(R,G)for S,m in ipairs(Y)do O(tostring(m.k)..("\058"..((" "):rep(B-#tostring(m.k))..m.v)),z)end if m then for S,m in ipairs(R)do I(m.v,z+1,tostring(m.k)..((" "):rep(B-#tostring(m.k)).." \091\084\097\098\108\101\093"))end else for S,m in ipairs(R)do O(tostring(m.k)..("\058"..((" "):rep(B-#tostring(m.k)).."\091\084\097\098\108\101\093")),z)end end end I(S,1,z)print(table.concat(r,""))end local function m(S)local z=#S local m=table.create(z)for r=1,z,1 do m[r]=S[(z-r)+1]end return m end local function r(S)assert(type(S)=="\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 z=Random.new()for m=#S,2,-1 do local r=z:NextInteger(1,m)S[m],S[r]=S[r],S[m]end end local function Y(S)return next(S)==nil end local function O(S)return http:JSONEncode(S)end local function G(S)return http:JSONDecode(S)end local function I(S,z)local m=IndexOf(S,z)if m then FastRemove(S,m)return true,m end return false,nil end TableUtil.Copy=CopyTable TableUtil.CopyShallow=CopyTableShallow TableUtil.Sync=Sync TableUtil.FastRemove=FastRemove TableUtil.FastRemoveFirstValue=I TableUtil.Print=z TableUtil.Map=Map TableUtil.Filter=Filter TableUtil.Reduce=Reduce TableUtil.Assign=S TableUtil.IndexOf=IndexOf TableUtil.Reverse=m TableUtil.Shuffle=r TableUtil.IsEmpty=Y TableUtil.EncodeJSON=O TableUtil.DecodeJSON=G return TableUtil
-- tableUtil.Assign(Table target, ...Table sources)
local function Assign(target, ...)
	for _, src in ipairs({ ... }) do
		for k, v in pairs(src) do
			target[k] = v
		end
	end
	return target
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 ipairs(nonTbls) do
			Insert(tostring(v.k) .. ":" .. (" "):rep(keySpaces - #tostring(v.k)) .. v.v, lvl)
		end
		if deepPrint then
			for _, v in ipairs(tbls) do
				PrintTable(v.v, lvl + 1, tostring(v.k) .. (" "):rep(keySpaces - #tostring(v.k)) .. " [Table]")
			end
		else
			for _, v in ipairs(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 Reverse(tbl)
	local n = #tbl
	local tblRev = table.create(n)
	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")
	local rng = Random.new()
	for i = #tbl, 2, -1 do
		local j = rng:NextInteger(1, 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.CopyShallow = CopyTableShallow
TableUtil.Sync = Sync
TableUtil.FastRemove = FastRemove
TableUtil.FastRemoveFirstValue = FastRemoveFirstValue
TableUtil.Print = Print
TableUtil.Map = Map
TableUtil.Filter = Filter
TableUtil.Reduce = Reduce
TableUtil.Assign = Assign
TableUtil.IndexOf = IndexOf
TableUtil.Reverse = Reverse
TableUtil.Shuffle = Shuffle
TableUtil.IsEmpty = IsEmpty
TableUtil.EncodeJSON = EncodeJSON
TableUtil.DecodeJSON = DecodeJSON

return TableUtil
