local function timeTest(str, f, ...)
local clock = os.clock()
local r = f(...)
print(str, os.clock()-clock)
return r
end
function main()
local obj = {}
for i=1,500 do
obj[i] = {}
for j=1,100,3 do
obj[i][j] = math.random()
obj[i][j+1] = "n:"..math.random()
obj[i][j+2] = (math.random()>0.5 and true or false)
end
end
local s = ""
local _obj
print("Testing:")
s = timeTest("serialize():", serialize, obj)
_obj = timeTest("unserialize():", unserialize, s)
print()
s = timeTest("serialization.serialize():", serialization.serialize, obj)
_obj = timeTest("serialization.unserialize():", serialization.unserialize, s)
print()
s = timeTest("table.toString():", table.toString, obj)
_obj = timeTest("table.fromString():", table.fromString, s)
end
-- ********************************************************************************** --
-- ** Serialize table to string ** --
-- ** ** --
-- ** Modified version of http://l...content-available-to-author-only...s.org/wiki/SaveTableToFile ** --
-- ** ** --
-- ********************************************************************************** --
-- declare local variables
--// exportstring( string )
--// returns a "Lua" portable version of the string
local function exportstring( s )
return string.format("%q", s)
end
local insert = table.insert
local tostring= tostring
local ipairs = ipairs
local pairs = pairs
local type = type
--// The Save Function
function table.toString(tbl)
if type(tbl) ~= 'table' then return "" end -- Argument not a table
local charS,charE = " ","\n"
local s_tbl = {}
-- initiate variables for save procedure
local tables,lookup = { tbl },{ [tbl] = 1 }
insert(s_tbl, "return {"..charE )
for idx,t in ipairs( tables ) do
insert(s_tbl, "-- Table: {"..idx.."}"..charE )
insert(s_tbl, "{"..charE )
local thandled = {}
for i,v in ipairs( t ) do
thandled[i] = true
local stype = type( v )
-- only handle value
if stype == "table" then
if not lookup[v] then
insert( tables, v )
lookup[v] = #tables
end
insert(s_tbl, charS.."{"..lookup[v].."},"..charE )
elseif stype == "string" then
insert(s_tbl, charS..exportstring( v )..","..charE )
elseif stype == "number" or stype == "boolean" then
insert(s_tbl, charS..tostring( v )..","..charE )
end
end
for i,v in pairs( t ) do
-- escape handled values
if (not thandled[i]) then
local str = ""
local stype = type( i )
-- handle index
if stype == "table" then
if not lookup[i] then
insert( tables,i )
lookup[i] = #tables
end
str = charS.."[{"..lookup[i].."}]="
elseif stype == "string" then
str = charS.."["..exportstring( i ).."]="
elseif stype == "number" or stype == "boolean" then
str = charS.."["..tostring( i ).."]="
end
if str ~= "" then
stype = type( v )
-- handle value
if stype == "table" then
if not lookup[v] then
insert( tables,v )
lookup[v] = #tables
end
insert(s_tbl, str.."{"..lookup[v].."},"..charE )
elseif stype == "string" then
insert(s_tbl, str..exportstring( v )..","..charE )
elseif stype == "number" or stype == "boolean" then
insert(s_tbl, str..tostring( v )..","..charE )
end
end
end
end
insert(s_tbl, "},"..charE )
end
insert(s_tbl, "}" )
return table.concat(s_tbl)
end
--// The Load Function
function table.fromString(s)
if not s then return end -- Argument not string
local ftables = loadstring(s)
if not ftables then return end -- String cant be parsed into function
local tables = ftables()
for idx = 1,#tables do
local tolinki = {}
for i,v in pairs( tables[idx] ) do
if type( v ) == "table" then
tables[idx][i] = tables[v[1]]
end
if type( i ) == "table" and tables[i[1]] then
insert( tolinki,{ i,tables[i[1]] } )
end
end
-- link indices
for _,v in ipairs( tolinki ) do
tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil
end
end
return tables[1]
end
local function serializeImpl( t, tTracking )
local sType = type(t)
if sType == "table" then
if tTracking[t] ~= nil then
error( "Cannot serialize table with recursive entries" )
end
tTracking[t] = true
local result = "{"
for k,v in pairs(t) do
result = result..("["..serializeImpl(k, tTracking).."]="..serializeImpl(v, tTracking)..",")
end
result = result.."}"
return result
elseif sType == "string" then
return string.format( "%q", t )
elseif sType == "number" or sType == "boolean" or sType == "nil" then
return tostring(t)
else
error( "Cannot serialize type "..sType )
end
end
function serialize( t )
local tTracking = {}
return serializeImpl( t, tTracking )
end
function unserialize( s )
local func, e = loadstring( "return "..s, "serialize" )
if not func then
return s
else
--setfenv( func, {} )
return func()
end
end
serialization = {}
-- Important: pretty formatting will allow presenting non-serializable values
-- but may generate output that cannot be unserialized back.
function serialization.serialize(value, pretty)
local kw = {["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true,
["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true,
["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true,
["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true,
["repeat"]=true, ["return"]=true, ["then"]=true, ["true"]=true,
["until"]=true, ["while"]=true}
local id = "^[%a_][%w_]*$"
local ts = {}
local function s(v, l)
local t = type(v)
if t == "nil" then
return "nil"
elseif t == "boolean" then
return v and "true" or "false"
elseif t == "number" then
if v ~= v then
return "0/0"
elseif v == math.huge then
return "math.huge"
elseif v == -math.huge then
return "-math.huge"
else
return tostring(v)
end
elseif t == "string" then
return string.format("%q", v):gsub("\\\n","\\n")
elseif t == "table" and pretty and getmetatable(v) and getmetatable(v).__tostring then
return tostring(v)
elseif t == "table" then
if ts[v] then
if pretty then
return "recursion"
else
error("tables with cycles are not supported")
end
end
ts[v] = true
local i, r = 1, nil
local f
if pretty then
local ks, sks, oks = {}, {}, {}
for k in pairs(v) do
if type(k) == "number" then
table.insert(ks, k)
elseif type(k) == "string" then
table.insert(sks, k)
else
table.insert(oks, k)
end
end
table.sort(ks)
table.sort(sks)
for _, k in ipairs(sks) do
table.insert(ks, k)
end
for _, k in ipairs(oks) do
table.insert(ks, k)
end
local n = 0
f = table.pack(function()
n = n + 1
local k = ks[n]
if k ~= nil then
return k, v[k]
else
return nil
end
end)
else
f = table.pack(pairs(v))
end
for k, v in table.unpack(f) do
if r then
r = r .. "," .. (pretty and ("\n" .. string.rep(" ", l)) or "")
else
r = "{"
end
local tk = type(k)
if tk == "number" and k == i then
i = i + 1
r = r .. s(v, l + 1)
else
if tk == "string" and not kw[k] and string.match(k, id) then
r = r .. k
else
r = r .. "[" .. s(k, l + 1) .. "]"
end
r = r .. "=" .. s(v, l + 1)
end
end
ts[v] = nil -- allow writing same table more than once
return (r or "{") .. "}"
else
if pretty then
return tostring(t)
else
error("unsupported type: " .. t)
end
end
end
local result = s(value, 1)
local limit = type(pretty) == "number" and pretty or 10
if pretty then
local truncate = 0
while limit > 0 and truncate do
truncate = string.find(result, "\n", truncate + 1, true)
limit = limit - 1
end
if truncate then
return result:sub(1, truncate) .. "..."
end
end
return result
end
function serialization.unserialize(data)
--checkArg(1, data, "string")
local result, reason = load("return " .. data, "=data", _, {math={huge=math.huge}})
if not result then
return nil, reason
end
local ok, output = pcall(result)
if not ok then
return nil, output
end
return output
end
main()
bG9jYWwgZnVuY3Rpb24gdGltZVRlc3Qoc3RyLCBmLCAuLi4pCiAgbG9jYWwgY2xvY2sgPSBvcy5jbG9jaygpCiAgbG9jYWwgciA9IGYoLi4uKQogIHByaW50KHN0ciwgb3MuY2xvY2soKS1jbG9jaykKICByZXR1cm4gcgplbmQKCmZ1bmN0aW9uIG1haW4oKQogIGxvY2FsIG9iaiA9IHt9CiAgZm9yIGk9MSw1MDAgZG8KICAgIG9ialtpXSA9IHt9CiAgICBmb3Igaj0xLDEwMCwzIGRvCiAgICAgIG9ialtpXVtqXSA9IG1hdGgucmFuZG9tKCkKICAgICAgb2JqW2ldW2orMV0gPSAibjoiLi5tYXRoLnJhbmRvbSgpCiAgICAgIG9ialtpXVtqKzJdID0gKG1hdGgucmFuZG9tKCk+MC41IGFuZCB0cnVlIG9yIGZhbHNlKQogICAgZW5kCiAgZW5kCiAgCiAgbG9jYWwgcyA9ICIiCiAgbG9jYWwgX29iagogIHByaW50KCJUZXN0aW5nOiIpCiAgcyA9IHRpbWVUZXN0KCJzZXJpYWxpemUoKToiLCBzZXJpYWxpemUsIG9iaikKICBfb2JqID0gdGltZVRlc3QoInVuc2VyaWFsaXplKCk6IiwgdW5zZXJpYWxpemUsIHMpCiAgCiAgcHJpbnQoKQogIHMgPSB0aW1lVGVzdCgic2VyaWFsaXphdGlvbi5zZXJpYWxpemUoKToiLCBzZXJpYWxpemF0aW9uLnNlcmlhbGl6ZSwgb2JqKQogIF9vYmogPSB0aW1lVGVzdCgic2VyaWFsaXphdGlvbi51bnNlcmlhbGl6ZSgpOiIsIHNlcmlhbGl6YXRpb24udW5zZXJpYWxpemUsIHMpCiAgCiAgcHJpbnQoKQogIHMgPSB0aW1lVGVzdCgidGFibGUudG9TdHJpbmcoKToiLCB0YWJsZS50b1N0cmluZywgb2JqKQogIF9vYmogPSB0aW1lVGVzdCgidGFibGUuZnJvbVN0cmluZygpOiIsIHRhYmxlLmZyb21TdHJpbmcsIHMpCmVuZAoKLS0gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAtLQotLSAqKiAgIFNlcmlhbGl6ZSB0YWJsZSB0byBzdHJpbmcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICoqIC0tCi0tICoqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKiogLS0KLS0gKiogICBNb2RpZmllZCB2ZXJzaW9uIG9mIGh0dHA6Ly9sLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5zLm9yZy93aWtpL1NhdmVUYWJsZVRvRmlsZSAgICAgICAgICAgICAgKiogLS0KLS0gKiogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqKiAtLQotLSAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqIC0tCiAKLS0gZGVjbGFyZSBsb2NhbCB2YXJpYWJsZXMKLS0vLyBleHBvcnRzdHJpbmcoIHN0cmluZyApCi0tLy8gcmV0dXJucyBhICJMdWEiIHBvcnRhYmxlIHZlcnNpb24gb2YgdGhlIHN0cmluZwpsb2NhbCBmdW5jdGlvbiBleHBvcnRzdHJpbmcoIHMgKQogIHJldHVybiBzdHJpbmcuZm9ybWF0KCIlcSIsIHMpCmVuZAogCmxvY2FsIGluc2VydCAgPSB0YWJsZS5pbnNlcnQKbG9jYWwgdG9zdHJpbmc9IHRvc3RyaW5nCmxvY2FsIGlwYWlycyAgPSBpcGFpcnMKbG9jYWwgcGFpcnMgICA9IHBhaXJzCmxvY2FsIHR5cGUgICAgPSB0eXBlCiAKLS0vLyBUaGUgU2F2ZSBGdW5jdGlvbgpmdW5jdGlvbiB0YWJsZS50b1N0cmluZyh0YmwpCiAgaWYgdHlwZSh0YmwpIH49ICd0YWJsZScgdGhlbiByZXR1cm4gIiIgZW5kIC0tIEFyZ3VtZW50IG5vdCBhIHRhYmxlCiAKICBsb2NhbCBjaGFyUyxjaGFyRSA9ICIgICAiLCJcbiIKICBsb2NhbCBzX3RibCA9IHt9CiAKICAtLSBpbml0aWF0ZSB2YXJpYWJsZXMgZm9yIHNhdmUgcHJvY2VkdXJlCiAgbG9jYWwgdGFibGVzLGxvb2t1cCA9IHsgdGJsIH0seyBbdGJsXSA9IDEgfQogIGluc2VydChzX3RibCwgInJldHVybiB7Ii4uY2hhckUgKQogCiAgZm9yIGlkeCx0IGluIGlwYWlycyggdGFibGVzICkgZG8KICAgIGluc2VydChzX3RibCwgIi0tIFRhYmxlOiB7Ii4uaWR4Li4ifSIuLmNoYXJFICkKICAgIGluc2VydChzX3RibCwgInsiLi5jaGFyRSApCiAgICBsb2NhbCB0aGFuZGxlZCA9IHt9CiAKICAgIGZvciBpLHYgaW4gaXBhaXJzKCB0ICkgZG8KICAgICAgdGhhbmRsZWRbaV0gPSB0cnVlCiAgICAgIGxvY2FsIHN0eXBlID0gdHlwZSggdiApCiAgICAgIC0tIG9ubHkgaGFuZGxlIHZhbHVlCiAgICAgIGlmIHN0eXBlID09ICJ0YWJsZSIgdGhlbgogICAgICAgIGlmIG5vdCBsb29rdXBbdl0gdGhlbgogICAgICAgICAgaW5zZXJ0KCB0YWJsZXMsIHYgKQogICAgICAgICAgbG9va3VwW3ZdID0gI3RhYmxlcwogICAgICAgIGVuZAogICAgICAgIGluc2VydChzX3RibCwgY2hhclMuLiJ7Ii4ubG9va3VwW3ZdLi4ifSwiLi5jaGFyRSApCiAgICAgIGVsc2VpZiBzdHlwZSA9PSAic3RyaW5nIiB0aGVuCiAgICAgICAgaW5zZXJ0KHNfdGJsLCAgY2hhclMuLmV4cG9ydHN0cmluZyggdiApLi4iLCIuLmNoYXJFICkKICAgICAgZWxzZWlmIHN0eXBlID09ICJudW1iZXIiIG9yIHN0eXBlID09ICJib29sZWFuIiB0aGVuCiAgICAgICAgaW5zZXJ0KHNfdGJsLCAgY2hhclMuLnRvc3RyaW5nKCB2ICkuLiIsIi4uY2hhckUgKQogICAgICBlbmQKICAgIGVuZAogCiAgICBmb3IgaSx2IGluIHBhaXJzKCB0ICkgZG8KICAgICAgLS0gZXNjYXBlIGhhbmRsZWQgdmFsdWVzCiAgICAgIGlmIChub3QgdGhhbmRsZWRbaV0pIHRoZW4KIAogICAgICAgIGxvY2FsIHN0ciA9ICIiCiAgICAgICAgbG9jYWwgc3R5cGUgPSB0eXBlKCBpICkKICAgICAgICAtLSBoYW5kbGUgaW5kZXgKICAgICAgICBpZiBzdHlwZSA9PSAidGFibGUiIHRoZW4KICAgICAgICAgIGlmIG5vdCBsb29rdXBbaV0gdGhlbgogICAgICAgICAgICBpbnNlcnQoIHRhYmxlcyxpICkKICAgICAgICAgICAgbG9va3VwW2ldID0gI3RhYmxlcwogICAgICAgICAgZW5kCiAgICAgICAgICBzdHIgPSBjaGFyUy4uIlt7Ii4ubG9va3VwW2ldLi4ifV09IgogICAgICAgIGVsc2VpZiBzdHlwZSA9PSAic3RyaW5nIiB0aGVuCiAgICAgICAgICBzdHIgPSBjaGFyUy4uIlsiLi5leHBvcnRzdHJpbmcoIGkgKS4uIl09IgogICAgICAgIGVsc2VpZiBzdHlwZSA9PSAibnVtYmVyIiBvciBzdHlwZSA9PSAiYm9vbGVhbiIgdGhlbgogICAgICAgICAgc3RyID0gY2hhclMuLiJbIi4udG9zdHJpbmcoIGkgKS4uIl09IgogICAgICAgIGVuZAogCiAgICAgICAgaWYgc3RyIH49ICIiIHRoZW4KICAgICAgICAgIHN0eXBlID0gdHlwZSggdiApCiAgICAgICAgICAtLSBoYW5kbGUgdmFsdWUKICAgICAgICAgIGlmIHN0eXBlID09ICJ0YWJsZSIgdGhlbgogICAgICAgICAgICBpZiBub3QgbG9va3VwW3ZdIHRoZW4KICAgICAgICAgICAgICBpbnNlcnQoIHRhYmxlcyx2ICkKICAgICAgICAgICAgICBsb29rdXBbdl0gPSAjdGFibGVzCiAgICAgICAgICAgIGVuZAogICAgICAgICAgICBpbnNlcnQoc190YmwsIHN0ci4uInsiLi5sb29rdXBbdl0uLiJ9LCIuLmNoYXJFICkKICAgICAgICAgIGVsc2VpZiBzdHlwZSA9PSAic3RyaW5nIiB0aGVuCiAgICAgICAgICAgIGluc2VydChzX3RibCwgc3RyLi5leHBvcnRzdHJpbmcoIHYgKS4uIiwiLi5jaGFyRSApCiAgICAgICAgICBlbHNlaWYgc3R5cGUgPT0gIm51bWJlciIgb3Igc3R5cGUgPT0gImJvb2xlYW4iIHRoZW4KICAgICAgICAgICAgaW5zZXJ0KHNfdGJsLCBzdHIuLnRvc3RyaW5nKCB2ICkuLiIsIi4uY2hhckUgKQogICAgICAgICAgZW5kCiAgICAgICAgZW5kCiAgICAgIGVuZAogICAgZW5kCiAgICBpbnNlcnQoc190YmwsICJ9LCIuLmNoYXJFICkKICBlbmQKICBpbnNlcnQoc190YmwsICJ9IiApCiAKICByZXR1cm4gdGFibGUuY29uY2F0KHNfdGJsKQplbmQKIAotLS8vIFRoZSBMb2FkIEZ1bmN0aW9uCmZ1bmN0aW9uIHRhYmxlLmZyb21TdHJpbmcocykKICBpZiBub3QgcyB0aGVuIHJldHVybiBlbmQgLS0gQXJndW1lbnQgbm90IHN0cmluZwogIGxvY2FsIGZ0YWJsZXMgPSBsb2Fkc3RyaW5nKHMpCiAgaWYgbm90IGZ0YWJsZXMgdGhlbiByZXR1cm4gZW5kIC0tIFN0cmluZyBjYW50IGJlIHBhcnNlZCBpbnRvIGZ1bmN0aW9uCiAgbG9jYWwgdGFibGVzID0gZnRhYmxlcygpCiAgZm9yIGlkeCA9IDEsI3RhYmxlcyBkbwogICAgbG9jYWwgdG9saW5raSA9IHt9CiAgICBmb3IgaSx2IGluIHBhaXJzKCB0YWJsZXNbaWR4XSApIGRvCiAgICAgIGlmIHR5cGUoIHYgKSA9PSAidGFibGUiIHRoZW4KICAgICAgICB0YWJsZXNbaWR4XVtpXSA9IHRhYmxlc1t2WzFdXQogICAgICBlbmQKICAgICAgaWYgdHlwZSggaSApID09ICJ0YWJsZSIgYW5kIHRhYmxlc1tpWzFdXSB0aGVuCiAgICAgICAgaW5zZXJ0KCB0b2xpbmtpLHsgaSx0YWJsZXNbaVsxXV0gfSApCiAgICAgIGVuZAogICAgZW5kCiAgICAtLSBsaW5rIGluZGljZXMKICAgIGZvciBfLHYgaW4gaXBhaXJzKCB0b2xpbmtpICkgZG8KICAgICAgdGFibGVzW2lkeF1bdlsyXV0sdGFibGVzW2lkeF1bdlsxXV0gPSAgdGFibGVzW2lkeF1bdlsxXV0sbmlsCiAgICBlbmQKICBlbmQKICByZXR1cm4gdGFibGVzWzFdCmVuZAoKCgpsb2NhbCBmdW5jdGlvbiBzZXJpYWxpemVJbXBsKCB0LCB0VHJhY2tpbmcgKSAgCiAgbG9jYWwgc1R5cGUgPSB0eXBlKHQpCiAgaWYgc1R5cGUgPT0gInRhYmxlIiB0aGVuCiAgICBpZiB0VHJhY2tpbmdbdF0gfj0gbmlsIHRoZW4KICAgICAgZXJyb3IoICJDYW5ub3Qgc2VyaWFsaXplIHRhYmxlIHdpdGggcmVjdXJzaXZlIGVudHJpZXMiICkKICAgIGVuZAogICAgdFRyYWNraW5nW3RdID0gdHJ1ZQogICAgCiAgICBsb2NhbCByZXN1bHQgPSAieyIKICAgIGZvciBrLHYgaW4gcGFpcnModCkgZG8KICAgICAgcmVzdWx0ID0gcmVzdWx0Li4oIlsiLi5zZXJpYWxpemVJbXBsKGssIHRUcmFja2luZykuLiJdPSIuLnNlcmlhbGl6ZUltcGwodiwgdFRyYWNraW5nKS4uIiwiKQogICAgZW5kCiAgICByZXN1bHQgPSByZXN1bHQuLiJ9IgogICAgcmV0dXJuIHJlc3VsdAogICAgCiAgZWxzZWlmIHNUeXBlID09ICJzdHJpbmciIHRoZW4KICAgIHJldHVybiBzdHJpbmcuZm9ybWF0KCAiJXEiLCB0ICkKICAKICBlbHNlaWYgc1R5cGUgPT0gIm51bWJlciIgb3Igc1R5cGUgPT0gImJvb2xlYW4iIG9yIHNUeXBlID09ICJuaWwiIHRoZW4KICAgIHJldHVybiB0b3N0cmluZyh0KQogICAgCiAgZWxzZQogICAgZXJyb3IoICJDYW5ub3Qgc2VyaWFsaXplIHR5cGUgIi4uc1R5cGUgKQogICAgCiAgZW5kCmVuZAoKZnVuY3Rpb24gc2VyaWFsaXplKCB0ICkKICBsb2NhbCB0VHJhY2tpbmcgPSB7fQogIHJldHVybiBzZXJpYWxpemVJbXBsKCB0LCB0VHJhY2tpbmcgKQplbmQKCmZ1bmN0aW9uIHVuc2VyaWFsaXplKCBzICkKICBsb2NhbCBmdW5jLCBlID0gbG9hZHN0cmluZyggInJldHVybiAiLi5zLCAic2VyaWFsaXplIiApCiAgaWYgbm90IGZ1bmMgdGhlbgogICAgcmV0dXJuIHMKICBlbHNlCiAgICAtLXNldGZlbnYoIGZ1bmMsIHt9ICkKICAgIHJldHVybiBmdW5jKCkKICBlbmQKZW5kCgoKc2VyaWFsaXphdGlvbiA9IHt9CgotLSBJbXBvcnRhbnQ6IHByZXR0eSBmb3JtYXR0aW5nIHdpbGwgYWxsb3cgcHJlc2VudGluZyBub24tc2VyaWFsaXphYmxlIHZhbHVlcwotLSBidXQgbWF5IGdlbmVyYXRlIG91dHB1dCB0aGF0IGNhbm5vdCBiZSB1bnNlcmlhbGl6ZWQgYmFjay4KZnVuY3Rpb24gc2VyaWFsaXphdGlvbi5zZXJpYWxpemUodmFsdWUsIHByZXR0eSkKICBsb2NhbCBrdyA9ICB7WyJhbmQiXT10cnVlLCBbImJyZWFrIl09dHJ1ZSwgWyJkbyJdPXRydWUsIFsiZWxzZSJdPXRydWUsCiAgICAgICAgICAgICAgIFsiZWxzZWlmIl09dHJ1ZSwgWyJlbmQiXT10cnVlLCBbImZhbHNlIl09dHJ1ZSwgWyJmb3IiXT10cnVlLAogICAgICAgICAgICAgICBbImZ1bmN0aW9uIl09dHJ1ZSwgWyJnb3RvIl09dHJ1ZSwgWyJpZiJdPXRydWUsIFsiaW4iXT10cnVlLAogICAgICAgICAgICAgICBbImxvY2FsIl09dHJ1ZSwgWyJuaWwiXT10cnVlLCBbIm5vdCJdPXRydWUsIFsib3IiXT10cnVlLAogICAgICAgICAgICAgICBbInJlcGVhdCJdPXRydWUsIFsicmV0dXJuIl09dHJ1ZSwgWyJ0aGVuIl09dHJ1ZSwgWyJ0cnVlIl09dHJ1ZSwKICAgICAgICAgICAgICAgWyJ1bnRpbCJdPXRydWUsIFsid2hpbGUiXT10cnVlfQogIGxvY2FsIGlkID0gIl5bJWFfXVsld19dKiQiCiAgbG9jYWwgdHMgPSB7fQogIGxvY2FsIGZ1bmN0aW9uIHModiwgbCkKICAgIGxvY2FsIHQgPSB0eXBlKHYpCiAgICBpZiB0ID09ICJuaWwiIHRoZW4KICAgICAgcmV0dXJuICJuaWwiCiAgICBlbHNlaWYgdCA9PSAiYm9vbGVhbiIgdGhlbgogICAgICByZXR1cm4gdiBhbmQgInRydWUiIG9yICJmYWxzZSIKICAgIGVsc2VpZiB0ID09ICJudW1iZXIiIHRoZW4KICAgICAgaWYgdiB+PSB2IHRoZW4KICAgICAgICByZXR1cm4gIjAvMCIKICAgICAgZWxzZWlmIHYgPT0gbWF0aC5odWdlIHRoZW4KICAgICAgICByZXR1cm4gIm1hdGguaHVnZSIKICAgICAgZWxzZWlmIHYgPT0gLW1hdGguaHVnZSB0aGVuCiAgICAgICAgcmV0dXJuICItbWF0aC5odWdlIgogICAgICBlbHNlCiAgICAgICAgcmV0dXJuIHRvc3RyaW5nKHYpCiAgICAgIGVuZAogICAgZWxzZWlmIHQgPT0gInN0cmluZyIgdGhlbgogICAgICByZXR1cm4gc3RyaW5nLmZvcm1hdCgiJXEiLCB2KTpnc3ViKCJcXFxuIiwiXFxuIikKICAgIGVsc2VpZiB0ID09ICJ0YWJsZSIgYW5kIHByZXR0eSBhbmQgZ2V0bWV0YXRhYmxlKHYpIGFuZCBnZXRtZXRhdGFibGUodikuX190b3N0cmluZyB0aGVuCiAgICAgIHJldHVybiB0b3N0cmluZyh2KQogICAgZWxzZWlmIHQgPT0gInRhYmxlIiB0aGVuCiAgICAgIGlmIHRzW3ZdIHRoZW4KICAgICAgICBpZiBwcmV0dHkgdGhlbgogICAgICAgICAgcmV0dXJuICJyZWN1cnNpb24iCiAgICAgICAgZWxzZQogICAgICAgICAgZXJyb3IoInRhYmxlcyB3aXRoIGN5Y2xlcyBhcmUgbm90IHN1cHBvcnRlZCIpCiAgICAgICAgZW5kCiAgICAgIGVuZAogICAgICB0c1t2XSA9IHRydWUKICAgICAgbG9jYWwgaSwgciA9IDEsIG5pbAogICAgICBsb2NhbCBmCiAgICAgIGlmIHByZXR0eSB0aGVuCiAgICAgICAgbG9jYWwga3MsIHNrcywgb2tzID0ge30sIHt9LCB7fQogICAgICAgIGZvciBrIGluIHBhaXJzKHYpIGRvCiAgICAgICAgICBpZiB0eXBlKGspID09ICJudW1iZXIiIHRoZW4KICAgICAgICAgICAgdGFibGUuaW5zZXJ0KGtzLCBrKQogICAgICAgICAgZWxzZWlmIHR5cGUoaykgPT0gInN0cmluZyIgdGhlbgogICAgICAgICAgICB0YWJsZS5pbnNlcnQoc2tzLCBrKQogICAgICAgICAgZWxzZQogICAgICAgICAgICB0YWJsZS5pbnNlcnQob2tzLCBrKQogICAgICAgICAgZW5kCiAgICAgICAgZW5kCiAgICAgICAgdGFibGUuc29ydChrcykKICAgICAgICB0YWJsZS5zb3J0KHNrcykKICAgICAgICBmb3IgXywgayBpbiBpcGFpcnMoc2tzKSBkbwogICAgICAgICAgdGFibGUuaW5zZXJ0KGtzLCBrKQogICAgICAgIGVuZAogICAgICAgIGZvciBfLCBrIGluIGlwYWlycyhva3MpIGRvCiAgICAgICAgICB0YWJsZS5pbnNlcnQoa3MsIGspCiAgICAgICAgZW5kCiAgICAgICAgbG9jYWwgbiA9IDAKICAgICAgICBmID0gdGFibGUucGFjayhmdW5jdGlvbigpCiAgICAgICAgICBuID0gbiArIDEKICAgICAgICAgIGxvY2FsIGsgPSBrc1tuXQogICAgICAgICAgaWYgayB+PSBuaWwgdGhlbgogICAgICAgICAgICByZXR1cm4gaywgdltrXQogICAgICAgICAgZWxzZQogICAgICAgICAgICByZXR1cm4gbmlsCiAgICAgICAgICBlbmQKICAgICAgICBlbmQpCiAgICAgIGVsc2UKICAgICAgICBmID0gdGFibGUucGFjayhwYWlycyh2KSkKICAgICAgZW5kCiAgICAgIGZvciBrLCB2IGluIHRhYmxlLnVucGFjayhmKSBkbwogICAgICAgIGlmIHIgdGhlbgogICAgICAgICAgciA9IHIgLi4gIiwiIC4uIChwcmV0dHkgYW5kICgiXG4iIC4uIHN0cmluZy5yZXAoIiAiLCBsKSkgb3IgIiIpCiAgICAgICAgZWxzZQogICAgICAgICAgciA9ICJ7IgogICAgICAgIGVuZAogICAgICAgIGxvY2FsIHRrID0gdHlwZShrKQogICAgICAgIGlmIHRrID09ICJudW1iZXIiIGFuZCBrID09IGkgdGhlbgogICAgICAgICAgaSA9IGkgKyAxCiAgICAgICAgICByID0gciAuLiBzKHYsIGwgKyAxKQogICAgICAgIGVsc2UKICAgICAgICAgIGlmIHRrID09ICJzdHJpbmciIGFuZCBub3Qga3dba10gYW5kIHN0cmluZy5tYXRjaChrLCBpZCkgdGhlbgogICAgICAgICAgICByID0gciAuLiBrCiAgICAgICAgICBlbHNlCiAgICAgICAgICAgIHIgPSByIC4uICJbIiAuLiBzKGssIGwgKyAxKSAuLiAiXSIKICAgICAgICAgIGVuZAogICAgICAgICAgciA9IHIgLi4gIj0iIC4uIHModiwgbCArIDEpCiAgICAgICAgZW5kCiAgICAgIGVuZAogICAgICB0c1t2XSA9IG5pbCAtLSBhbGxvdyB3cml0aW5nIHNhbWUgdGFibGUgbW9yZSB0aGFuIG9uY2UKICAgICAgcmV0dXJuIChyIG9yICJ7IikgLi4gIn0iCiAgICBlbHNlCiAgICAgIGlmIHByZXR0eSB0aGVuCiAgICAgICAgcmV0dXJuIHRvc3RyaW5nKHQpCiAgICAgIGVsc2UKICAgICAgICBlcnJvcigidW5zdXBwb3J0ZWQgdHlwZTogIiAuLiB0KQogICAgICBlbmQKICAgIGVuZAogIGVuZAogIGxvY2FsIHJlc3VsdCA9IHModmFsdWUsIDEpCiAgbG9jYWwgbGltaXQgPSB0eXBlKHByZXR0eSkgPT0gIm51bWJlciIgYW5kIHByZXR0eSBvciAxMAogIGlmIHByZXR0eSB0aGVuCiAgICBsb2NhbCB0cnVuY2F0ZSA9IDAKICAgIHdoaWxlIGxpbWl0ID4gMCBhbmQgdHJ1bmNhdGUgZG8KICAgICAgdHJ1bmNhdGUgPSBzdHJpbmcuZmluZChyZXN1bHQsICJcbiIsIHRydW5jYXRlICsgMSwgdHJ1ZSkKICAgICAgbGltaXQgPSBsaW1pdCAtIDEKICAgIGVuZAogICAgaWYgdHJ1bmNhdGUgdGhlbgogICAgICByZXR1cm4gcmVzdWx0OnN1YigxLCB0cnVuY2F0ZSkgLi4gIi4uLiIKICAgIGVuZAogIGVuZAogIHJldHVybiByZXN1bHQKZW5kCgpmdW5jdGlvbiBzZXJpYWxpemF0aW9uLnVuc2VyaWFsaXplKGRhdGEpCiAgLS1jaGVja0FyZygxLCBkYXRhLCAic3RyaW5nIikKICBsb2NhbCByZXN1bHQsIHJlYXNvbiA9IGxvYWQoInJldHVybiAiIC4uIGRhdGEsICI9ZGF0YSIsIF8sIHttYXRoPXtodWdlPW1hdGguaHVnZX19KQogIGlmIG5vdCByZXN1bHQgdGhlbgogICAgcmV0dXJuIG5pbCwgcmVhc29uCiAgZW5kCiAgbG9jYWwgb2ssIG91dHB1dCA9IHBjYWxsKHJlc3VsdCkKICBpZiBub3Qgb2sgdGhlbgogICAgcmV0dXJuIG5pbCwgb3V0cHV0CiAgZW5kCiAgcmV0dXJuIG91dHB1dAplbmQKCgptYWluKCk=