local function G(G,...)for a,t in ipairs({...})do for a,t in pairs(t)do G[a]=t end end return G end local function a(G,a,t)assert(type(G)=="\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(a==nil or type(a)=="\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")a=a or"\084\065\066\076\069"local d={}local T=" - "local function p(G,a)d[#d+1]=T:rep(a)..(G.."\n")end local function o(G,a)return tostring(G.k)<tostring(a.k)end local function l(G,a,d)p(d.."\058",a-1)local T={}local D={}local S=0 for G,a in pairs(G)do if type(a)=="\116\097\098\108\101"then table.insert(D,{k=G;v=a})else table.insert(T,{k=G;v="\091"..(typeof(a)..("\093 "..tostring(a)))})end local t=#tostring(G)+1 if t>S then S=t end end table.sort(T,o)table.sort(D,o)for G,t in ipairs(T)do p(tostring(t.k)..("\058"..((" "):rep(S-#tostring(t.k))..t.v)),a)end if t then for G,t in ipairs(D)do l(t.v,a+1,tostring(t.k)..((" "):rep(S-#tostring(t.k)).." \091\084\097\098\108\101\093"))end else for G,t in ipairs(D)do p(tostring(t.k)..("\058"..((" "):rep(S-#tostring(t.k)).."\091\084\097\098\108\101\093")),a)end end end l(G,1,a)print(table.concat(d,""))end local function t(G)local a=#G local t=table.create(a)for d=1,a,1 do t[d]=G[(a-d)+1]end return t end local function d(G)assert(type(G)=="\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 a=Random.new()for t=#G,2,-1 do local d=a:NextInteger(1,t)G[t],G[d]=G[d],G[t]end end local function T(G)return next(G)==nil end local function p(G)return http:JSONEncode(G)end local function o(G)return http:JSONDecode(G)end local function l(G,a)local t=IndexOf(G,a)if t then FastRemove(G,t)return true,t end return false,nil end TableUtil.Copy=CopyTable TableUtil.CopyShallow=CopyTableShallow TableUtil.Sync=Sync TableUtil.FastRemove=FastRemove TableUtil.FastRemoveFirstValue=l TableUtil.Print=a TableUtil.Map=Map TableUtil.Filter=Filter TableUtil.Reduce=Reduce TableUtil.Assign=G TableUtil.IndexOf=IndexOf TableUtil.Reverse=t TableUtil.Shuffle=d TableUtil.IsEmpty=T TableUtil.EncodeJSON=p TableUtil.DecodeJSON=o return TableUtil

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
