local a=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local C=require(a:WaitForChild("\078\101\118\101\114\109\111\114\101"))local P=(C("\083\116\100")).t local B={}local function Z(a)if type(a)=="\102\117\110\099\116\105\111\110"then return a else assert(type(a)=="\116\097\098\108\101","\067\097\110 \111\110\108\121 \105\116\101\114\097\116\101 \111\118\101\114 \097 \116\097\098\108\101 \111\114 \097\110 \105\116\101\114\097\116\111\114 \102\117\110\099\116\105\111\110")return pairs(a)end end function B.slice(a,C,P,B)local Z={}for C=C or 1,P or#a,B or 1 do Z[#Z+1]=a[C]end return Z end function B.get(a,C,...)local P={...}local Z,L=pcall(function()return a[C]end)if Z then if#P>0 then return B.get(L,unpack(P))else return L end end end function B.map(a,C)local P={}for a,B in Z(a)do P[a]=C(B,a)end return P end function B.mapValues(a,C)local P={}for a,B in Z(a)do table.insert(P,C(B,a))end return P end function B.mapKeys(a,C)local P={}for a,B in Z(a)do P[C(B,a)]=B end return P end function B.flatMap(a,C)local P={}for a,Z in Z(a)do local L=C(Z,a)if type(L)=="\116\097\098\108\101"then B.insertMany(P,L)else table.insert(P,L)end end return P end function B.shuffle(a)local C=B.clone(a)for a=#C,1,-1 do local P=math.random(a)C[a],C[P]=C[P],C[a]end return C end function B.filter(a,C)local P={}for a,B in Z(a)do if C(B,a)then table.insert(P,B)end end return P end function B.filterKeys(a,C)local P={}for a,B in Z(a)do if C(B,a)then P[a]=B end end return P end function B.filterKeysMap(a,C)local P={}for a,B in Z(a)do local Z=C(B,a)if Z~=nil then P[a]=Z end end return P end function B.omitBy(a,C)local P={}for a,B in Z(a)do local Z=C(B,a)if not Z then P[a]=B end end return P end function B.without(a,C)return B.filter(a,function(a)return a~=C end)end function B.compact(a)return B.filter(a,function(a)return a end)end function B.reduce(a,C,P)local B=P for a,P in Z(a)do B=C(B,P,a)end return B end function B.sum(a)return B.reduce(a,function(a,C)return a+C end,0)end function B.all(a,C)if not C then C=function(a)return a end end return not(not B.reduce(a,function(a,P,B)return a and C(P,B)end,true))end function B.any(a,C)if not C then C=function(a)return a end end return not(not B.reduce(a,function(a,P,B)return a or C(P,B)end,false))end function B.reverse(a)local C=B.clone(a)local P=1 local Z=#a while P<Z do C[P],C[Z]=C[Z],C[P]P=P+1 Z=Z-1 end return C end function B.invert(a)local C={}for a,P in Z(a)do C[P]=a end return C end function B.keyBy(a,C)local P={}for a,B in Z(a)do local Z=C(B,a)if Z~=nil then P[Z]=B end end return P end function B.groupBy(a,C)local P={}for a,B in Z(a)do local Z=C(B,a)if Z~=nil then if not P[Z]then P[Z]={}end table.insert(P[Z],B)end end return P end function B.merge(a,...)for C=1,select("\035",...),1 do local P=select(C,...)if P~=nil then for C,P in Z(P)do if type(a[C])=="\116\097\098\108\101"and type(P)=="\116\097\098\108\101"then a[C]=B.merge(a[C]or{},P)else a[C]=P end end end end return a end function B.values(a)local C={}for a,P in Z(a)do table.insert(C,P)end return C end function B.keys(a)local C={}for a,P in Z(a)do table.insert(C,a)end return C end function B.entries(a)local C={}for a,P in Z(a)do table.insert(C,{a;P})end return C end function B.find(a,C)for a,P in Z(a)do if C(P,a)then return P end end end function B.findKey(a,C)for a,P in Z(a)do if C(P,a)then return a end end end function B.includes(a,C)return B.find(a,function(a)return a==C end)~=nil end function B.keyOf(a,C)for a,P in Z(a)do if C==P then return a end end end function B.insertMany(a,C)for C,P in Z(C)do table.insert(a,P)end return a end function B.len(a)local C=0 for a in pairs(a)do C=C+1 end return C end local function L(a,C,...)for P=1,select("\035",...),1 do local B=select(P,...)if B~=nil then for P,B in Z(B)do if a or C[P]==nil then C[P]=B end end end end return C end function B.assign(a,...)return L(true,a,...)end function B.defaults(a,...)return L(false,a,...)end function B.clone(a)return B.assign({},a)end function B.isSubset(a,C)if type(a)~="\116\097\098\108\101"or type(C)~="\116\097\098\108\101"then return false else for a,P in pairs(a)do local Z=C[a]if type(P)~=type(Z)then return false elseif P~=Z then if type(P)=="\116\097\098\108\101"then if not B.isSubset(P,Z)then return false end else return false end end end end return true end function B.deepEquals(a,C)return B.isSubset(a,C)and B.isSubset(C,a)end function B.shallowEqual(a,C)if a==C then return true end if type(a)~="\116\097\098\108\101"or type(C)~="\116\097\098\108\101"then return false end local P=B.keys(a)local Z=B.keys(C)if#P~=#Z then return false end return B.all(a,function(a,P)return a==C[P]end)end function B.isOrdered(a)return#B.keys(a)==#a end function B.serialize(a,P)P=P or function(a)return tostring(a)end assert(type(a)=="\116\097\098\108\101")local Z=C(script.Parent.Functions)assert(Z.isCallable(P))return"\123"..(table.concat(B.map(a,function(a,C)return tostring(C)..("\061"..P(a))end),"\044").."\125")end function B.append(...)local a={}for C=1,select("\035",...),1 do local P=select(C,...)if type(P)=="\116\097\098\108\101"then for C,P in ipairs(P)do table.insert(a,P)end else table.insert(a,P)end end return a end function B.sort(a,B)assert(P.table(a),a)local Z=C(script.Parent.Functions)assert(B==nil or Z.isCallable(B),"\099\111\109\112\097\114\097\116\111\114 \109\117\115\116 \098\101 \099\097\108\108\097\098\108\101 \111\114 \110\105\108")B=B or function(a,C)return a<C end table.sort(a,function(a,C)local P=B(a,C)if type(P)~="\098\111\111\108\101\097\110"and P~=nil then error("\115\111\114\116 \099\111\109\112\097\114\097\116\111\114 \109\117\115\116 \114\101\116\117\114\110 \097 \098\111\111\108\101\097\110 \111\114 \110\105\108")end return P end)return a end return B
--[[
	Tables is a library to handle tables. 
	There are some reasons for this:
	* Great docs
	* Some custom

	## Examples

	For example:

		There are two ways to do this

	Right?
]]
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local require = require(ReplicatedStorage:WaitForChild("Nevermore"))
local t = require("Std").t

local Tables = {}

local function getIterator(source)
	if type(source) == "function" then
		return source
	else
		assert(type(source) == "table", "Can only iterate over a table or an iterator function")
		return pairs(source)
	end
end

--: <T>(T[], int?, int?, int?) -> T[]
function Tables.slice(source, first, last, step)
	local sliced = {}

	for i = first or 1, last or #source, step or 1 do
		sliced[#sliced + 1] = source[i]
	end

	return sliced
end

--[[
	Get a child or descendant of a table, returning nil if any errors are generated.
	@param ... 
	@trait Chainable
]]
--: <T: Iterable<K, V>>(T, ...K) -> V
function Tables.get(source, key, ...)
	local tailkeys = {...}
	local ok, value =
		pcall(
		function()
			return source[key]
		end
	)
	if ok then
		if #tailkeys > 0 then
			return Tables.get(value, unpack(tailkeys))
		else
			return value
		end
	end
end

--: <T: Iterable<K,V>, R: Iterable<K,V2>((T, (element: V, key: K) -> V2) -> R)
function Tables.map(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		result[i] = handler(v, i)
	end
	return result
end

--: <T: Iterable<K,V>, R: Iterable<K,V2>((T, (element: V, key: K) -> V2) -> R)
function Tables.mapValues(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		table.insert(result, handler(v, i))
	end
	return result
end

--: <T: Iterable<K,V>, R: Iterable<K,V2>((T, (element: V, key: K) -> V2) -> R)
function Tables.mapKeys(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		result[handler(v, i)] = v
	end
	return result
end

--: <T: Iterable<K,V>, U>((T, (element: V, key: K) -> U[] | U) -> U[])
function Tables.flatMap(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		local list = handler(v, i)
		if type(list) == "table" then
			Tables.insertMany(result, list)
		else
			table.insert(result, list)
		end
	end
	return result
end

--: <T: Iterable>(T -> T)
function Tables.shuffle(source)
	local result = Tables.clone(source)
	for i = #result, 1, -1 do
		local j = math.random(i)
		result[i], result[j] = result[j], result[i]
	end
	return result
end

--: <T: Iterable<K,V>>(T, (element: V, key: K -> bool) -> V[])
function Tables.filter(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		if handler(v, i) then
			table.insert(result, v)
		end
	end
	return result
end

--: <T: Iterable<K,V>>(T, (element: V, key: K -> bool) -> T)
function Tables.filterKeys(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		if handler(v, i) then
			result[i] = v
		end
	end
	return result
end

--: <T: Iterable<K,V>, R: Iterable<K,U>>(T, (element: V, key: K -> U) -> R
function Tables.filterKeysMap(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		local value = handler(v, i)
		if value ~= nil then
			result[i] = value
		end
	end
	return result
end

function Tables.omitBy(source, handler)
	local result = {}

	for i, v in getIterator(source) do
		local value = handler(v, i)
		if not value then
			result[i] = v
		end
	end
	return result
end

--: <T: Iterable<K,V>>(T, V -> T)
function Tables.without(source, element)
	return Tables.filter(
		source,
		function(child)
			return child ~= element
		end
	)
end

--: <T: Iterable<K,V>>(T, T)
function Tables.compact(source)
	return Tables.filter(
		source,
		function(value)
			return value
		end
	)
end

--: <T, R>(T[], (acc: R, current: T, key: int -> R), R) -> R
function Tables.reduce(source, handler, init)
	local result = init
	for i, v in getIterator(source) do
		result = handler(result, v, i)
	end
	return result
end

function Tables.sum(source)
	return Tables.reduce(
		source,
		function(current, value)
			return current + value
		end,
		0
	)
end

--[[
	Wow
]]
--: <T: Iterable<K,V>>(T -> bool)
function Tables.all(source, handler)
	if not handler then
		handler = function(x)
			return x
		end
	end
	-- Use double negation to coerce the type to a boolean, as there is
	-- no toboolean() or equivalent in Lua.
	return not (not Tables.reduce(
		source,
		function(acc, value, key)
			return acc and handler(value, key)
		end,
		true
	))
end
--: <T: Iterable<K,V>>(T -> bool)
function Tables.any(source, handler)
	if not handler then
		handler = function(x)
			return x
		end
	end
	-- Use double negation to coerce the type to a boolean, as there is
	-- no toboolean() or equivalent in Lua.
	return not (not Tables.reduce(
		source,
		function(acc, value, key)
			return acc or handler(value, key)
		end,
		false
	))
end

--[[
	Summary ends with a period.
	Some description, can be over
	several lines.
	```
	local test = {}
	```
]]
--: <T>(T[] -> T[])
function Tables.reverse(source)
	local output = Tables.clone(source)
	local i = 1
	local j = #source
	while i < j do
		output[i], output[j] = output[j], output[i]
		i = i + 1
		j = j - 1
	end
	return output
end

--: <K: Key, V>(Iterable<K,V> -> Iterable<V,K>)
function Tables.invert(source)
	local result = {}
	for i, v in getIterator(source) do
		result[v] = i
	end
	return result
end

--: <T, K: Key>(T[], (T -> K) -> Iterable<K,V>)
function Tables.keyBy(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		local key = handler(v, i)
		if key ~= nil then
			result[key] = v
		end
	end
	return result
end

--[[
	Summary ends with a period.
	This extracts the shortest common substring from the strings _s1_ and _s2_
	```function M.common_substring(s1,s2)```
	several lines.
	@string source first parameter
	@tparam string->int handler parameter
	@treturn string a string value
]]
--: <T: Iterable<K,V>, I: Key>((value: T, key: K) -> I) -> Iterable<I, Iterable<K,V>>)
function Tables.groupBy(source, handler)
	local result = {}
	for i, v in getIterator(source) do
		local key = handler(v, i)
		if key ~= nil then
			if not result[key] then
				result[key] = {}
			end
			table.insert(result[key], v)
		end
	end
	return result
end

function Tables.merge(target, ...)
	-- Use select here so that nil arguments can be supported. If instead we
	-- iterated over ipairs({...}), any arguments after the first nil one
	-- would be ignored.
	for i = 1, select("#", ...) do
		local source = select(i, ...)
		if source ~= nil then
			for key, value in getIterator(source) do
				if type(target[key]) == "table" and type(value) == "table" then
					target[key] = Tables.merge(target[key] or {}, value)
				else
					target[key] = value
				end
			end
		end
	end
	return target
end

--: table -> any[]
function Tables.values(source)
	local result = {}
	for i, v in getIterator(source) do
		table.insert(result, v)
	end
	return result
end

--: table -> any[]
function Tables.keys(source)
	local result = {}
	for i, v in getIterator(source) do
		table.insert(result, i)
	end
	return result
end

--: table -> [string | int, any][]
function Tables.entries(source)
	local result = {}
	for i, v in getIterator(source) do
		table.insert(result, {i, v})
	end
	return result
end

--: <T: Iterable<K,V>>((T, (element: V, key: K) -> bool) -> V)
function Tables.find(source, handler)
	for i, v in getIterator(source) do
		if (handler(v, i)) then
			return v
		end
	end
end

--: <T: Iterable<K,V>>((T, (element: V, key: K) -> bool) -> K)
function Tables.findKey(source, handler)
	for i, v in getIterator(source) do
		if (handler(v, i)) then
			return i
		end
	end
end

--: table, any -> boolean
function Tables.includes(source, item)
	return Tables.find(
		source,
		function(value)
			return value == item
		end
	) ~= nil
end

--: (table, any) -> int?
function Tables.keyOf(source, value)
	for k, v in getIterator(source) do
		if (value == v) then
			return k
		end
	end
end

--: (any[], any[]) -> any[]
function Tables.insertMany(target, items)
	for _, v in getIterator(items) do
		table.insert(target, v)
	end
	return target
end

--: (table) -> int
function Tables.len(table)
	local count = 0
	for _ in pairs(table) do
		count = count + 1
	end
	return count
end

local function assign(overwriteTarget, target, ...)
	-- Use select here so that nil arguments can be supported. If instead we
	-- iterated over ipairs({...}), any arguments after the first nil one
	-- would be ignored.
	for i = 1, select("#", ...) do
		local source = select(i, ...)
		if source ~= nil then
			for key, value in getIterator(source) do
				if overwriteTarget or target[key] == nil then
					target[key] = value
				end
			end
		end
	end
	return target
end

function Tables.assign(target, ...)
	return assign(true, target, ...)
end

function Tables.defaults(target, ...)
	return assign(false, target, ...)
end

--: (table) -> table
function Tables.clone(tbl)
	return Tables.assign({}, tbl)
end

function Tables.isSubset(a, b)
	if type(a) ~= "table" or type(b) ~= "table" then
		return false
	else
		for key, aValue in pairs(a) do
			local bValue = b[key]
			if type(aValue) ~= type(bValue) then
				return false
			elseif aValue ~= bValue then
				if type(aValue) == "table" then
					-- The values are tables, so we need to recurse for a deep comparison.
					if not Tables.isSubset(aValue, bValue) then
						return false
					end
				else
					return false
				end
			end
		end
	end
	return true
end

function Tables.deepEquals(a, b)
	return Tables.isSubset(a, b) and Tables.isSubset(b, a)
end

-- Based on https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/using_should_component_update.html
function Tables.shallowEqual(left, right)
	if left == right then
		return true
	end
	if type(left) ~= "table" or type(right) ~= "table" then
		return false
	end
	local leftKeys = Tables.keys(left)
	local rightKeys = Tables.keys(right)
	if #leftKeys ~= #rightKeys then
		return false
	end
	return Tables.all(
		left,
		function(value, key)
			return value == right[key]
		end
	)
end

function Tables.isOrdered(source)
	return #Tables.keys(source) == #source
end

function Tables.serialize(source, serializer)
	serializer = serializer or function(value)
			return tostring(value)
		end
	assert(type(source) == "table")
	local Functions = require(script.Parent.Functions)
	assert(Functions.isCallable(serializer))
	return "{" ..
		table.concat(
			Tables.map(
				source,
				function(element, i)
					return tostring(i) .. "=" .. serializer(element)
				end
			),
			","
		) ..
			"}"
end

function Tables.append(...)
	local result = {}
	for i = 1, select("#", ...) do
		local x = select(i, ...)
		if type(x) == "table" then
			for _, y in ipairs(x) do
				table.insert(result, y)
			end
		else
			table.insert(result, x)
		end
	end

	return result
end

function Tables.sort(input, comparator)
	assert(t.table(input), input)

	local Functions = require(script.Parent.Functions)
	assert(comparator == nil or Functions.isCallable(comparator), "comparator must be callable or nil")

	comparator = comparator or function(a, b)
			return a < b
		end

	table.sort(
		input,
		function(a, b)
			local result = comparator(a, b)

			if type(result) ~= "boolean" and result ~= nil then
				error("sort comparator must return a boolean or nil")
			end

			return result
		end
	)

	return input
end

return Tables