local function W(Q,i)if typeof(Q)~=typeof(i)then local W=("\123\049\125 \105\115 \111\102 \116\121\112\101 \037\115\044 \098\117\116 \123\050\125 \105\115 \111\102 \116\121\112\101 \037\115"):format(typeof(Q),typeof(i))return false,W end if typeof(Q)=="\116\097\098\108\101"then local f={}for Q,F in pairs(Q)do f[Q]=true local N,y=W(F,i[Q])if not N then local W=(y:gsub("\123\049\125",("\123\049\125\091\037\115\093"):format(tostring(Q)))):gsub("\123\050\125",("\123\050\125\091\037\115\093"):format(tostring(Q)))return false,W end end for i,F in pairs(i)do if not f[i]then local f,N=W(F,Q[i])if not f then local W=(N:gsub("\123\049\125",("\123\049\125\091\037\115\093"):format(tostring(i)))):gsub("\123\050\125",("\123\050\125\091\037\115\093"):format(tostring(i)))return false,W end end end return true end if Q==i then return true end local f="\123\049\125 ~\061 \123\050\125"return false,f end local function Q(Q,i)local f,F=W(Q,i)if not f then local W=(F:gsub("\123\049\125","\102\105\114\115\116")):gsub("\123\050\125","\115\101\099\111\110\100")local Q=("\086\097\108\117\101\115 \119\101\114\101 \110\111\116 \100\101\101\112-\101\113\117\097\108\046\n\037\115"):format(W)error(Q,2)end end return Q


local function deepEqual(a, b)
	if typeof(a) ~= typeof(b) then
		local message = ("{1} is of type %s, but {2} is of type %s"):format(typeof(a), typeof(b))
		return false, message
	end

	if typeof(a) == "table" then
		local visitedKeys = {}

		for key, value in pairs(a) do
			visitedKeys[key] = true

			local success, innerMessage = deepEqual(value, b[key])
			if not success then
				local message = innerMessage
					:gsub("{1}", ("{1}[%s]"):format(tostring(key)))
					:gsub("{2}", ("{2}[%s]"):format(tostring(key)))

				return false, message
			end
		end

		for key, value in pairs(b) do
			if not visitedKeys[key] then
				local success, innerMessage = deepEqual(value, a[key])

				if not success then
					local message = innerMessage
						:gsub("{1}", ("{1}[%s]"):format(tostring(key)))
						:gsub("{2}", ("{2}[%s]"):format(tostring(key)))

					return false, message
				end
			end
		end

		return true
	end

	if a == b then
		return true
	end

	local message = "{1} ~= {2}"
	return false, message
end

local function assertDeepEqual(a, b)
	local success, innerMessageTemplate = deepEqual(a, b)

	if not success then
		local innerMessage = innerMessageTemplate:gsub("{1}", "first"):gsub("{2}", "second")

		local message = ("Values were not deep-equal.\n%s"):format(innerMessage)

		error(message, 2)
	end
end

return assertDeepEqual
