local w={}local function z(w)w=string.gsub(w,"\092","\092\092")w=string.gsub(w,"\"","\092\"")w=string.gsub(w,"\n","\092\110")w=string.gsub(w,"\r","\092\114")w=string.gsub(w,"\t","\092\116")return"\""..(w.."\"")end local function c(w)local z=0 local c=0 for w,o in pairs(w)do if type(w)=="\110\117\109\098\101\114"and(w>0 and math.floor(w)==w)then if w>z then z=w end c=c+1 else return false end end return z==c end local function o(w,z,c)c=c or 0 if not z[w]then return w else local l=tonumber(w)if l then local w=tostring(l+1)if c<100 then return o(w,z,c+1)else local w=tostring(math.random(100000,999999))if z[w]then return o(w,z,c+1)else return w end end else local l=w.."\049"if c<100 then return o(l,z,c+1)else local w=tostring(math.random(100000,999999))if z[w]then return o(w,z,c+1)else return w end end end end end local function l(w)local a=type(w)if a=="\110\105\108"then return"\110\117\108\108"elseif a=="\110\117\109\098\101\114"or a=="\098\111\111\108\101\097\110"then return tostring(w)elseif a=="\115\116\114\105\110\103"then return z(w)elseif a=="\116\097\098\108\101"then local a={}if c(w)then for z=1,#w,1 do table.insert(a,l(w[z]))end return"\091"..(table.concat(a,"\044").."\093")else local c={}local T=0 local U={}local Z={}for w,z in pairs(w)do T=T+1 if type(w)=="\115\116\114\105\110\103"then table.insert(U,{w;z})else table.insert(Z,{w,z})end end for w,o in ipairs(U)do local T,U=o[1],o[2]local Z=tostring(T)c[Z]=true table.insert(a,z(Z)..("\058"..l(U)))end for w,U in ipairs(Z)do local Z,K=U[1],U[2]local s=tostring(Z)if c[s]then s=o(tostring(T+1),c,0)end c[s]=true table.insert(a,z(s)..("\058"..l(K)))end return"\123"..(table.concat(a,"\044").."\125")end else error("\085\110\115\117\112\112\111\114\116\101\100 \100\097\116\097 \116\121\112\101\058 "..a)end end w.encode=l local function a(w,z)error("\074\083\079\078 \100\101\099\111\100\101 \101\114\114\111\114 \097\116 \112\111\115\105\116\105\111\110 "..(z..("\058 "..w)))end local function T(w,z)local c="\091 \n\r\t\093\042"local o,l=string.find(w,c,z)return l+1 end local U local function Z(w,z)if string.sub(w,z,z)~="\""then a("\069\120\112\101\099\116\101\100 \'\"\' \097\116 \098\101\103\105\110\110\105\110\103 \111\102 \115\116\114\105\110\103",z)end z=z+1 local c={}while z<=#w do local o=string.sub(w,z,z)if o=="\""then z=z+1 return table.concat(c),z elseif o=="\092"then z=z+1 if z>#w then a("\085\110\101\120\112\101\099\116\101\100 \101\110\100 \111\102 \115\116\114\105\110\103",z)end local o=string.sub(w,z,z)if o=="\""then table.insert(c,"\"")elseif o=="\092"then table.insert(c,"\092")elseif o=="\047"then table.insert(c,"\047")elseif o=="\098"then table.insert(c,"\b")elseif o=="\102"then table.insert(c,"\012")elseif o=="\110"then table.insert(c,"\n")elseif o=="\114"then table.insert(c,"\r")elseif o=="\116"then table.insert(c,"\t")elseif o=="\117"then local o=string.sub(w,z+1,z+4)if not o:find("\094\037\120\037\120\037\120\037\120\036")then a("\073\110\118\097\108\105\100 \117\110\105\099\111\100\101 \101\115\099\097\112\101",z)end local l=tonumber(o,16)table.insert(c,utf8.char(l))z=z+4 else a("\073\110\118\097\108\105\100 \101\115\099\097\112\101 \099\104\097\114\097\099\116\101\114\058 "..o,z)end z=z+1 else table.insert(c,o)z=z+1 end end a("\085\110\116\101\114\109\105\110\097\116\101\100 \115\116\114\105\110\103",z)end local function K(w,z)local c="\094\037-\063\037\100\043\037\046\063\037\100\042\091\101\069\093\063\091\043-\093\063\037\100\042"local o,l=string.find(w,c,z)if o then local c=string.sub(w,o,l)local T=tonumber(c)if not T then a("\073\110\118\097\108\105\100 \110\117\109\098\101\114\058 "..c,z)end return T,l+1 else a("\069\120\112\101\099\116\101\100 \110\117\109\098\101\114",z)end end local function s(w,z)local c={["\116\114\117\101"]=true;["\102\097\108\115\101"]=false;null=nil}for c,o in pairs(c)do if string.sub(w,z,(z+#c)-1)==c then return o,z+#c end end a("\085\110\101\120\112\101\099\116\101\100 \108\105\116\101\114\097\108",z)end local function W(w,z)local c={}z=z+1 z=T(w,z)if string.sub(w,z,z)=="\093"then return c,z+1 end local o=1 while z<=#w do local l l,z=U(w,z)c[o]=l o=o+1 z=T(w,z)local Z=string.sub(w,z,z)if Z=="\044"then z=z+1 z=T(w,z)elseif Z=="\093"then z=z+1 break else a("\069\120\112\101\099\116\101\100 \'\044\' \111\114 \'\093\'",z)end end return c,z end local function x(w,z)local c={}z=z+1 z=T(w,z)if string.sub(w,z,z)=="\125"then return c,z+1 end while z<=#w do if string.sub(w,z,z)~="\""then a("\069\120\112\101\099\116\101\100 \115\116\114\105\110\103 \102\111\114 \111\098\106\101\099\116 \107\101\121",z)end local o o,z=Z(w,z)z=T(w,z)if string.sub(w,z,z)~="\058"then a("\069\120\112\101\099\116\101\100 \'\058\' \097\102\116\101\114 \111\098\106\101\099\116 \107\101\121",z)end z=z+1 z=T(w,z)local l l,z=U(w,z)c[o]=l z=T(w,z)local K=string.sub(w,z,z)if K=="\044"then z=z+1 z=T(w,z)elseif K=="\125"then z=z+1 break else a("\069\120\112\101\099\116\101\100 \'\044\' \111\114 \'\125\'",z)end end return c,z end U=function(w,z)z=T(w,z)local c=string.sub(w,z,z)if c=="\123"then return x(w,z)elseif c=="\091"then return W(w,z)elseif c=="\""then return Z(w,z)elseif c=="-"or c:match("\037\100")then return K(w,z)else return s(w,z)end end local function G(w)if type(w)~="\115\116\114\105\110\103"then error("\069\120\112\101\099\116\101\100 \074\083\079\078 \115\116\114\105\110\103 \102\111\114 \100\101\099\111\100\101")end local z,c=U(w,1)c=T(w,c)if c<=#w then a("\085\110\101\120\112\101\099\116\101\100 \116\114\097\105\108\105\110\103 \099\104\097\114\097\099\116\101\114\115",c)end return z end w.decode=G return w
local Module = {}

---------------------------------
-- JSON Encoding Implementation
---------------------------------

-- Escapes special characters in a string for JSON output.
local function encodeJSONString(str)
	str = string.gsub(str, '\\', '\\\\')
	str = string.gsub(str, '"', '\\"')
	str = string.gsub(str, "\n", "\\n")
	str = string.gsub(str, "\r", "\\r")
	str = string.gsub(str, "\t", "\\t")
	return '"' .. str .. '"'
end

-- Checks if a table is a "pure array" (i.e. its numeric keys form a contiguous sequence starting at 1).
local function isArray(t)
	local maxIndex = 0
	local count = 0
	for k, _ in pairs(t) do
		if type(k) == "number" and k > 0 and math.floor(k) == k then
			if k > maxIndex then
				maxIndex = k
			end
			count = count + 1
		else
			return false  -- Found a non‑numeric or non‑positive key.
		end
	end
	return maxIndex == count
end

-- Recursive helper to find a unique candidate key.
local function getUniqueCandidate(candidate, usedKeys, iteration)
	iteration = iteration or 0
	if not usedKeys[candidate] then
		return candidate
	else
		local candidateNumber = tonumber(candidate)
		if candidateNumber then
			local newCandidate = tostring(candidateNumber + 1)
			if iteration < 100 then
				return getUniqueCandidate(newCandidate, usedKeys, iteration + 1)
			else
				local randomCandidate = tostring(math.random(100000, 999999))
				if usedKeys[randomCandidate] then
					return getUniqueCandidate(randomCandidate, usedKeys, iteration + 1)
				else
					return randomCandidate
				end
			end
		else
			local newCandidate = candidate .. "1"
			if iteration < 100 then
				return getUniqueCandidate(newCandidate, usedKeys, iteration + 1)
			else
				local randomCandidate = tostring(math.random(100000, 999999))
				if usedKeys[randomCandidate] then
					return getUniqueCandidate(randomCandidate, usedKeys, iteration + 1)
				else
					return randomCandidate
				end
			end
		end
	end
end

-- Recursively encodes Lua values into JSON strings.
local function encodeJSON(value)
	local t = type(value)
	if t == "nil" then
		return "null"
	elseif t == "number" or t == "boolean" then
		return tostring(value)
	elseif t == "string" then
		return encodeJSONString(value)
	elseif t == "table" then
		local result = {}
		if isArray(value) then
			-- Encode as a JSON array.
			for i = 1, #value do
				table.insert(result, encodeJSON(value[i]))
			end
			return "[" .. table.concat(result, ",") .. "]"
		else
			-- Encode as a JSON object.
			-- First, partition the keys: string keys first, then non‑string keys.
			local usedKeys = {}
			local keyCount = 0
			local stringPairs = {}
			local nonStringPairs = {}
			for k, v in pairs(value) do
				keyCount = keyCount + 1
				if type(k) == "string" then
					table.insert(stringPairs, {k, v})
				else
					table.insert(nonStringPairs, {k, v})
				end
			end

			-- Process string keys first (they have precedence).
			for _, pair in ipairs(stringPairs) do
				local key, val = pair[1], pair[2]
				local candidate = tostring(key)  -- This should be identical to the original.
				usedKeys[candidate] = true
				table.insert(result, encodeJSONString(candidate) .. ":" .. encodeJSON(val))
			end

			-- Process non‑string keys.
			for _, pair in ipairs(nonStringPairs) do
				local key, val = pair[1], pair[2]
				local candidate = tostring(key)
				if usedKeys[candidate] then
					-- Conflict detected: use (#keys + 1) as the starting candidate.
					candidate = getUniqueCandidate(tostring(keyCount + 1), usedKeys, 0)
				end
				usedKeys[candidate] = true
				table.insert(result, encodeJSONString(candidate) .. ":" .. encodeJSON(val))
			end

			return "{" .. table.concat(result, ",") .. "}"
		end
	else
		error("Unsupported data type: " .. t)
	end
end

Module.encode = encodeJSON

---------------------------------
-- JSON Decoding Implementation
---------------------------------

-- Internal error handler for decode errors.
local function decodeError(msg, pos)
	error("JSON decode error at position " .. pos .. ": " .. msg)
end

-- Skips whitespace characters and returns the next non‑whitespace position.
local function skipWhitespace(str, pos)
	local pattern = "[ \n\r\t]*"
	local s, e = string.find(str, pattern, pos)
	return e + 1
end

-- Forward declaration for recursive descent.
local parseValue

-- Parses a JSON string (handles escapes; minimal Unicode support).
local function parseString(str, pos)
	if string.sub(str, pos, pos) ~= '"' then
		decodeError("Expected '\"' at beginning of string", pos)
	end
	pos = pos + 1
	local result = {}
	while pos <= #str do
		local char = string.sub(str, pos, pos)
		if char == '"' then
			pos = pos + 1
			return table.concat(result), pos
		elseif char == '\\' then
			pos = pos + 1
			if pos > #str then
				decodeError("Unexpected end of string", pos)
			end
			local escapeChar = string.sub(str, pos, pos)
			if escapeChar == '"' then
				table.insert(result, '"')
			elseif escapeChar == '\\' then
				table.insert(result, '\\')
			elseif escapeChar == '/' then
				table.insert(result, '/')
			elseif escapeChar == 'b' then
				table.insert(result, '\b')
			elseif escapeChar == 'f' then
				table.insert(result, '\f')
			elseif escapeChar == 'n' then
				table.insert(result, '\n')
			elseif escapeChar == 'r' then
				table.insert(result, '\r')
			elseif escapeChar == 't' then
				table.insert(result, '\t')
			elseif escapeChar == 'u' then
				-- Minimal Unicode handling: read the next 4 hex digits.
				local hex = string.sub(str, pos+1, pos+4)
				if not hex:find("^%x%x%x%x$") then
					decodeError("Invalid unicode escape", pos)
				end
				local code = tonumber(hex, 16)
				table.insert(result, utf8.char(code))
				pos = pos + 4
			else
				decodeError("Invalid escape character: " .. escapeChar, pos)
			end
			pos = pos + 1
		else
			table.insert(result, char)
			pos = pos + 1
		end
	end
	decodeError("Unterminated string", pos)
end

-- Parses a JSON number.
local function parseNumber(str, pos)
	local numberPattern = "^%-?%d+%.?%d*[eE]?[+-]?%d*"
	local s, e = string.find(str, numberPattern, pos)
	if s then
		local numStr = string.sub(str, s, e)
		local num = tonumber(numStr)
		if not num then
			decodeError("Invalid number: " .. numStr, pos)
		end
		return num, e + 1
	else
		decodeError("Expected number", pos)
	end
end

-- Parses literals: true, false, or null.
local function parseLiteral(str, pos)
	local literals = {
		["true"] = true,
		["false"] = false,
		["null"] = nil
	}
	for lit, value in pairs(literals) do
		if string.sub(str, pos, pos + #lit - 1) == lit then
			return value, pos + #lit
		end
	end
	decodeError("Unexpected literal", pos)
end

-- Parses a JSON array.
local function parseArray(str, pos)
	local result = {}
	pos = pos + 1  -- skip '['
	pos = skipWhitespace(str, pos)
	if string.sub(str, pos, pos) == ']' then
		return result, pos + 1
	end
	local index = 1
	while pos <= #str do
		local value
		value, pos = parseValue(str, pos)
		result[index] = value
		index = index + 1
		pos = skipWhitespace(str, pos)
		local char = string.sub(str, pos, pos)
		if char == ',' then
			pos = pos + 1
			pos = skipWhitespace(str, pos)
		elseif char == ']' then
			pos = pos + 1
			break
		else
			decodeError("Expected ',' or ']'", pos)
		end
	end
	return result, pos
end

-- Parses a JSON object.
local function parseObject(str, pos)
	local result = {}
	pos = pos + 1  -- skip '{'
	pos = skipWhitespace(str, pos)
	if string.sub(str, pos, pos) == '}' then
		return result, pos + 1
	end
	while pos <= #str do
		if string.sub(str, pos, pos) ~= '"' then
			decodeError("Expected string for object key", pos)
		end
		local key
		key, pos = parseString(str, pos)
		pos = skipWhitespace(str, pos)
		if string.sub(str, pos, pos) ~= ':' then
			decodeError("Expected ':' after object key", pos)
		end
		pos = pos + 1
		pos = skipWhitespace(str, pos)
		local value
		value, pos = parseValue(str, pos)
		result[key] = value
		pos = skipWhitespace(str, pos)
		local char = string.sub(str, pos, pos)
		if char == ',' then
			pos = pos + 1
			pos = skipWhitespace(str, pos)
		elseif char == '}' then
			pos = pos + 1
			break
		else
			decodeError("Expected ',' or '}'", pos)
		end
	end
	return result, pos
end

-- Parses any JSON value.
parseValue = function(str, pos)
	pos = skipWhitespace(str, pos)
	local char = string.sub(str, pos, pos)
	if char == '{' then
		return parseObject(str, pos)
	elseif char == '[' then
		return parseArray(str, pos)
	elseif char == '"' then
		return parseString(str, pos)
	elseif char == '-' or char:match("%d") then
		return parseNumber(str, pos)
	else
		return parseLiteral(str, pos)
	end
end

-- Main decoder function: converts a JSON string into a Lua table/value.
local function decodeJSON(str)
	if type(str) ~= "string" then
		error("Expected JSON string for decode")
	end
	local result, pos = parseValue(str, 1)
	pos = skipWhitespace(str, pos)
	if pos <= #str then
		decodeError("Unexpected trailing characters", pos)
	end
	return result
end

Module.decode = decodeJSON

---------------------------------
-- Return the Module
---------------------------------

return Module
