local R=string local w=math local e=table local Q=error local S=tonumber local D=tostring local g=type local Z=setmetatable local E=pairs local y=ipairs local c=assert local t={buffer={}}function t.New(R)local w={}Z(w,R)R.__index=R w.buffer={}return w end function t.Append(w,R)w.buffer[#w.buffer+1]=R end function t.ToString(R)return e.concat(R.buffer)end local A={backslashes={["\b"]="\092\098",["\t"]="\092\116";["\n"]="\092\110";["\012"]="\092\102",["\r"]="\092\114",["\""]="\092\"",["\092"]="\092\092";["\047"]="\092\047"}}function A.New(R)local w={}w.writer=t:New()Z(w,R)R.__index=R return w end function A.Append(w,R)w.writer:Append(R)end function A.ToString(R)return R.writer:ToString()end function A.Write(w,R)local e=g(R)if e=="\110\105\108"then w:WriteNil()elseif e=="\098\111\111\108\101\097\110"then w:WriteString(R)elseif e=="\110\117\109\098\101\114"then w:WriteString(R)elseif e=="\115\116\114\105\110\103"then w:ParseString(R)elseif e=="\116\097\098\108\101"then w:WriteTable(R)elseif e=="\102\117\110\099\116\105\111\110"then w:WriteFunction(R)elseif e=="\116\104\114\101\097\100"then w:WriteError(R)elseif e=="\117\115\101\114\100\097\116\097"then w:WriteError(R)end end function A.WriteNil(R)R:Append("\110\117\108\108")end function A.WriteString(w,R)w:Append(D(R))end function A.ParseString(e,w)e:Append("\"")e:Append(R.gsub(w,"\091\037\122\037\099\092\"\047\093",function(w)local Q=e.backslashes[w]if Q then return Q end return R.format("\092\117\037\046\052\088",R.byte(w))end))e:Append("\"")end function A.IsArray(e,R)local Q=0 local S=function(R)if g(R)=="\110\117\109\098\101\114"and R>0 then if w.floor(R)==R then return true end end return false end for R,e in E(R)do if not S(R)then return false,"\123","\125"else Q=w.max(Q,R)end end return true,"\091","\093",Q end function A.WriteTable(w,R)local e,Q,S,D=w:IsArray(R)w:Append(Q)if e then for e=1,D,1 do w:Write(R[e])if e<D then w:Append("\044")end end else local e=true for R,Q in E(R)do if not e then w:Append("\044")end e=false w:ParseString(R)w:Append("\058")w:Write(Q)end end w:Append(S)end function A.WriteError(e,w)Q(R.format("\069\110\099\111\100\105\110\103 \111\102 \037\115 \117\110\115\117\112\112\111\114\116\101\100",D(w)))end function A.WriteFunction(w,R)if R==Null then w:WriteNil()else w:WriteError(R)end end local H={s="",i=0}function H.New(w,R)local e={}Z(e,w)w.__index=w e.s=R or e.s return e end function H.Peek(w)local e=w.i+1 if e<=#w.s then return R.sub(w.s,e,e)end return nil end function H.Next(w)w.i=w.i+1 if w.i<=#w.s then return R.sub(w.s,w.i,w.i)end return nil end function H.All(R)return R.s end local U={escapes={t="\t",n="\n",f="\012";r="\r";b="\b"}}function U.New(w,R)local e={}e.reader=H:New(R)Z(e,w)w.__index=w return e end function U.Read(w)w:SkipWhiteSpace()local e=w:Peek()if e==nil then Q(R.format("\078\105\108 \115\116\114\105\110\103\058 \'\037\115\'",w:All()))elseif e=="\123"then return w:ReadObject()elseif e=="\091"then return w:ReadArray()elseif e=="\""then return w:ReadString()elseif R.find(e,"\091\037\043\037-\037\100\093")then return w:ReadNumber()elseif e=="\116"then return w:ReadTrue()elseif e=="\102"then return w:ReadFalse()elseif e=="\110"then return w:ReadNull()elseif e=="\047"then w:ReadComment()return w:Read()else return nil end end function U.ReadTrue(R)R:TestReservedWord({"\116","\114","\117";"\101"})return true end function U.ReadFalse(R)R:TestReservedWord({"\102","\097","\108","\115","\101"})return false end function U.ReadNull(R)R:TestReservedWord({"\110","\117";"\108","\108"})return nil end function U.TestReservedWord(S,w)for D,g in y(w)do if S:Next()~=g then Q(R.format("\069\114\114\111\114 \114\101\097\100\105\110\103 \'\037\115\'\058 \037\115",e.concat(w),S:All()))end end end function U.ReadNumber(w)local e=w:Next()local D=w:Peek()while D~=nil and R.find(D,"\091\037\043\037-\037\100\037\046\101\069\093")do e=e..w:Next()D=w:Peek()end e=S(e)if e==nil then Q(R.format("\073\110\118\097\108\105\100 \110\117\109\098\101\114\058 \'\037\115\'",e))else return e end end function U.ReadString(w)local e=""c(w:Next()=="\"")while w:Peek()~="\""do local R=w:Next()if R=="\092"then R=w:Next()if w.escapes[R]then R=w.escapes[R]end end e=e..R end c(w:Next()=="\"")local Q=function(w)return R.char(S(w,16))end return R.gsub(e,"\117\037\120\037\120\040\037\120\037\120\041",Q)end function U.ReadComment(w)c(w:Next()=="\047")local e=w:Next()if e=="\047"then w:ReadSingleLineComment()elseif e=="\042"then w:ReadBlockComment()else Q(R.format("\073\110\118\097\108\105\100 \099\111\109\109\101\110\116\058 \037\115",w:All()))end end function U.ReadBlockComment(w)local e=false while not e do local S=w:Next()if S=="\042"and w:Peek()=="\047"then e=true end if not e and(S=="\047"and w:Peek()=="\042")then Q(R.format("\073\110\118\097\108\105\100 \099\111\109\109\101\110\116\058 \037\115\044 \'\047\042\' \105\108\108\101\103\097\108\046",w:All()))end end w:Next()end function U.ReadSingleLineComment(R)local w=R:Next()while w~="\r"and w~="\n"do w=R:Next()end end function U.ReadArray(w)local e={}c(w:Next()=="\091")local S=false if w:Peek()=="\093"then S=true end while not S do local D=w:Read()e[#e+1]=D w:SkipWhiteSpace()if w:Peek()=="\093"then S=true end if not S then local e=w:Next()if e~="\044"then Q(R.format("\073\110\118\097\108\105\100 \097\114\114\097\121\058 \'\037\115\' \100\117\101 \116\111\058 \'\037\115\'",w:All(),e))end end end c("\093"==w:Next())return e end function U.ReadObject(w)local e={}c(w:Next()=="\123")local S=false if w:Peek()=="\125"then S=true end while not S do local D=w:Read()if g(D)~="\115\116\114\105\110\103"then Q(R.format("\073\110\118\097\108\105\100 \110\111\110-\115\116\114\105\110\103 \111\098\106\101\099\116 \107\101\121\058 \037\115",D))end w:SkipWhiteSpace()local Z=w:Next()if Z~="\058"then Q(R.format("\073\110\118\097\108\105\100 \111\098\106\101\099\116\058 \'\037\115\' \100\117\101 \116\111\058 \'\037\115\'",w:All(),Z))end w:SkipWhiteSpace()local E=w:Read()e[D]=E w:SkipWhiteSpace()if w:Peek()=="\125"then S=true end if not S then Z=w:Next()if Z~="\044"then Q(R.format("\073\110\118\097\108\105\100 \097\114\114\097\121\058 \'\037\115\' \110\101\097\114\058 \'\037\115\'",w:All(),Z))end end end c(w:Next()=="\125")return e end function U.SkipWhiteSpace(w)local e=w:Peek()while e~=nil and R.find(e,"\091\037\115\047\093")do if e=="\047"then w:ReadComment()else w:Next()end e=w:Peek()end end function U.Peek(R)return R.reader:Peek()end function U.Next(R)return R.reader:Next()end function U.All(R)return R.reader:All()end function Encode(R)local w=A:New()w:Write(R)return w:ToString()end function Decode(R)local w=U:New(R)return w:Read()end function Null()return Null end


 --JSON Encoder and Parser for Lua 5.1
 --
 --Copyright 2007 Shaun Brown  (http://www.chipmunkav.com)
 --All Rights Reserved.
 
 --Permission is hereby granted, free of charge, to any person 
 --obtaining a copy of this software to deal in the Software without 
 --restriction, including without limitation the rights to use, 
 --copy, modify, merge, publish, distribute, sublicense, and/or 
 --sell copies of the Software, and to permit persons to whom the 
 --Software is furnished to do so, subject to the following conditions:
 
 --The above copyright notice and this permission notice shall be 
 --included in all copies or substantial portions of the Software.
 --If you find this software useful please give www.chipmunkav.com a mention.

 --THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 --EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 --OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 --IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 
 --ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
 --CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
 --CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
local string = string
local math = math
local table = table
local error = error
local tonumber = tonumber
local tostring = tostring
local type = type
local setmetatable = setmetatable
local pairs = pairs
local ipairs = ipairs
local assert = assert


local StringBuilder = {
	buffer = {}
}

function StringBuilder:New()
	local o = {}
	setmetatable(o, self)
	self.__index = self
	o.buffer = {}
	return o
end

function StringBuilder:Append(s)
	self.buffer[#self.buffer+1] = s
end

function StringBuilder:ToString()
	return table.concat(self.buffer)
end

local JsonWriter = {
	backslashes = {
		['\b'] = "\\b",
		['\t'] = "\\t",	
		['\n'] = "\\n", 
		['\f'] = "\\f",
		['\r'] = "\\r", 
		['"']  = "\\\"", 
		['\\'] = "\\\\", 
		['/']  = "\\/"
	}
}

function JsonWriter:New()
	local o = {}
	o.writer = StringBuilder:New()
	setmetatable(o, self)
	self.__index = self
	return o
end

function JsonWriter:Append(s)
	self.writer:Append(s)
end

function JsonWriter:ToString()
	return self.writer:ToString()
end

function JsonWriter:Write(o)
	local t = type(o)
	if t == "nil" then
		self:WriteNil()
	elseif t == "boolean" then
		self:WriteString(o)
	elseif t == "number" then
		self:WriteString(o)
	elseif t == "string" then
		self:ParseString(o)
	elseif t == "table" then
		self:WriteTable(o)
	elseif t == "function" then
		self:WriteFunction(o)
	elseif t == "thread" then
		self:WriteError(o)
	elseif t == "userdata" then
		self:WriteError(o)
	end
end

function JsonWriter:WriteNil()
	self:Append("null")
end

function JsonWriter:WriteString(o)
	self:Append(tostring(o))
end

function JsonWriter:ParseString(s)
	self:Append('"')
	self:Append(string.gsub(s, "[%z%c\\\"/]", function(n)
		local c = self.backslashes[n]
		if c then return c end
		return string.format("\\u%.4X", string.byte(n))
	end))
	self:Append('"')
end

function JsonWriter:IsArray(t)
	local count = 0
	local isindex = function(k) 
		if type(k) == "number" and k > 0 then
			if math.floor(k) == k then
				return true
			end
		end
		return false
	end
	for k,v in pairs(t) do
		if not isindex(k) then
			return false, '{', '}'
		else
			count = math.max(count, k)
		end
	end
	return true, '[', ']', count
end

function JsonWriter:WriteTable(t)
	local ba, st, et, n = self:IsArray(t)
	self:Append(st)	
	if ba then		
		for i = 1, n do
			self:Write(t[i])
			if i < n then
				self:Append(',')
			end
		end
	else
		local first = true;
		for k, v in pairs(t) do
			if not first then
				self:Append(',')
			end
			first = false;			
			self:ParseString(k)
			self:Append(':')
			self:Write(v)			
		end
	end
	self:Append(et)
end

function JsonWriter:WriteError(o)
	error(string.format(
		"Encoding of %s unsupported", 
		tostring(o)))
end

function JsonWriter:WriteFunction(o)
	if o == Null then 
		self:WriteNil()
	else
		self:WriteError(o)
	end
end

local StringReader = {
	s = "",
	i = 0
}

function StringReader:New(s)
	local o = {}
	setmetatable(o, self)
	self.__index = self
	o.s = s or o.s
	return o	
end

function StringReader:Peek()
	local i = self.i + 1
	if i <= #self.s then
		return string.sub(self.s, i, i)
	end
	return nil
end

function StringReader:Next()
	self.i = self.i+1
	if self.i <= #self.s then
		return string.sub(self.s, self.i, self.i)
	end
	return nil
end

function StringReader:All()
	return self.s
end

local JsonReader = {
	escapes = {
		['t'] = '\t',
		['n'] = '\n',
		['f'] = '\f',
		['r'] = '\r',
		['b'] = '\b',
	}
}

function JsonReader:New(s)
	local o = {}
	o.reader = StringReader:New(s)
	setmetatable(o, self)
	self.__index = self
	return o;
end

function JsonReader:Read()
	self:SkipWhiteSpace()
	local peek = self:Peek()
	if peek == nil then
		error(string.format(
			"Nil string: '%s'", 
			self:All()))
	elseif peek == '{' then
		return self:ReadObject()
	elseif peek == '[' then
		return self:ReadArray()
	elseif peek == '"' then
		return self:ReadString()
	elseif string.find(peek, "[%+%-%d]") then
		return self:ReadNumber()
	elseif peek == 't' then
		return self:ReadTrue()
	elseif peek == 'f' then
		return self:ReadFalse()
	elseif peek == 'n' then
		return self:ReadNull()
	elseif peek == '/' then
		self:ReadComment()
		return self:Read()
	else
		return nil
	end
end
		
function JsonReader:ReadTrue()
	self:TestReservedWord{'t','r','u','e'}
	return true
end

function JsonReader:ReadFalse()
	self:TestReservedWord{'f','a','l','s','e'}
	return false
end

function JsonReader:ReadNull()
	self:TestReservedWord{'n','u','l','l'}
	return nil
end

function JsonReader:TestReservedWord(t)
	for i, v in ipairs(t) do
		if self:Next() ~= v then
			 error(string.format(
				"Error reading '%s': %s", 
				table.concat(t), 
				self:All()))
		end
	end
end

function JsonReader:ReadNumber()
        local result = self:Next()
        local peek = self:Peek()
        while peek ~= nil and string.find(
		peek, 
		"[%+%-%d%.eE]") do
            result = result .. self:Next()
            peek = self:Peek()
	end
	result = tonumber(result)
	if result == nil then
	        error(string.format(
			"Invalid number: '%s'", 
			result))
	else
		return result
	end
end

function JsonReader:ReadString()
	local result = ""
	assert(self:Next() == '"')
        while self:Peek() ~= '"' do
		local ch = self:Next()
		if ch == '\\' then
			ch = self:Next()
			if self.escapes[ch] then
				ch = self.escapes[ch]
			end
		end
                result = result .. ch
	end
        assert(self:Next() == '"')
	local fromunicode = function(m)
		return string.char(tonumber(m, 16))
	end
	return string.gsub(
		result, 
		"u%x%x(%x%x)", 
		fromunicode)
end

function JsonReader:ReadComment()
        assert(self:Next() == '/')
        local second = self:Next()
        if second == '/' then
            self:ReadSingleLineComment()
        elseif second == '*' then
            self:ReadBlockComment()
        else
            error(string.format(
		"Invalid comment: %s", 
		self:All()))
	end
end

function JsonReader:ReadBlockComment()
	local done = false
	while not done do
		local ch = self:Next()		
		if ch == '*' and self:Peek() == '/' then
			done = true
                end
		if not done and 
			ch == '/' and 
			self:Peek() == "*" then
                    error(string.format(
			"Invalid comment: %s, '/*' illegal.",  
			self:All()))
		end
	end
	self:Next()
end

function JsonReader:ReadSingleLineComment()
	local ch = self:Next()
	while ch ~= '\r' and ch ~= '\n' do
		ch = self:Next()
	end
end

function JsonReader:ReadArray()
	local result = {}
	assert(self:Next() == '[')
	local done = false
	if self:Peek() == ']' then
		done = true;
	end
	while not done do
		local item = self:Read()
		result[#result+1] = item
		self:SkipWhiteSpace()
		if self:Peek() == ']' then
			done = true
		end
		if not done then
			local ch = self:Next()
			if ch ~= ',' then
				error(string.format(
					"Invalid array: '%s' due to: '%s'", 
					self:All(), ch))
			end
		end
	end
	assert(']' == self:Next())
	return result
end

function JsonReader:ReadObject()
	local result = {}
	assert(self:Next() == '{')
	local done = false
	if self:Peek() == '}' then
		done = true
	end
	while not done do
		local key = self:Read()
		if type(key) ~= "string" then
			error(string.format(
				"Invalid non-string object key: %s", 
				key))
		end
		self:SkipWhiteSpace()
		local ch = self:Next()
		if ch ~= ':' then
			error(string.format(
				"Invalid object: '%s' due to: '%s'", 
				self:All(), 
				ch))
		end
		self:SkipWhiteSpace()
		local val = self:Read()
		result[key] = val
		self:SkipWhiteSpace()
		if self:Peek() == '}' then
			done = true
		end
		if not done then
			ch = self:Next()
                	if ch ~= ',' then
				error(string.format(
					"Invalid array: '%s' near: '%s'", 
					self:All(), 
					ch))
			end
		end
	end
	assert(self:Next() == "}")
	return result
end

function JsonReader:SkipWhiteSpace()
	local p = self:Peek()
	while p ~= nil and string.find(p, "[%s/]") do
		if p == '/' then
			self:ReadComment()
		else
			self:Next()
		end
		p = self:Peek()
	end
end

function JsonReader:Peek()
	return self.reader:Peek()
end

function JsonReader:Next()
	return self.reader:Next()
end

function JsonReader:All()
	return self.reader:All()
end

function Encode(o)
	local writer = JsonWriter:New()
	writer:Write(o)
	return writer:ToString()
end

function Decode(s)
	local reader = JsonReader:New(s)
	return reader:Read()
end

function Null()
	return Null
end