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,1000 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()
bG9jYWwgZnVuY3Rpb24gdGltZVRlc3Qoc3RyLCBmLCAuLi4pCiAgbG9jYWwgY2xvY2sgPSBvcy5jbG9jaygpCiAgbG9jYWwgciA9IGYoLi4uKQogIHByaW50KHN0ciwgb3MuY2xvY2soKS1jbG9jaykKICByZXR1cm4gcgplbmQKCmZ1bmN0aW9uIG1haW4oKQogIGxvY2FsIG9iaiA9IHt9CiAgZm9yIGk9MSwxMDAwIGRvCiAgICBvYmpbaV0gPSB7fQogICAgZm9yIGo9MSwxMDAsMyBkbwogICAgICBvYmpbaV1bal0gPSBtYXRoLnJhbmRvbSgpCiAgICAgIG9ialtpXVtqKzFdID0gIm46Ii4ubWF0aC5yYW5kb20oKQogICAgICBvYmpbaV1baisyXSA9IChtYXRoLnJhbmRvbSgpPjAuNSBhbmQgdHJ1ZSBvciBmYWxzZSkKICAgIGVuZAogIGVuZAogIAogIGxvY2FsIHMgPSAiIgogIGxvY2FsIF9vYmoKICBwcmludCgiVGVzdGluZzoiKQogIC0tcyA9IHRpbWVUZXN0KCJzZXJpYWxpemUoKToiLCBzZXJpYWxpemUsIG9iaikKICAtLV9vYmogPSB0aW1lVGVzdCgidW5zZXJpYWxpemUoKToiLCB1bnNlcmlhbGl6ZSwgcykKICAKICAtLXByaW50KCkKICAtLXMgPSB0aW1lVGVzdCgic2VyaWFsaXphdGlvbi5zZXJpYWxpemUoKToiLCBzZXJpYWxpemF0aW9uLnNlcmlhbGl6ZSwgb2JqKQogIC0tX29iaiA9IHRpbWVUZXN0KCJzZXJpYWxpemF0aW9uLnVuc2VyaWFsaXplKCk6Iiwgc2VyaWFsaXphdGlvbi51bnNlcmlhbGl6ZSwgcykKICAKICAtLXByaW50KCkKICBzID0gdGltZVRlc3QoInRhYmxlLnRvU3RyaW5nKCk6IiwgdGFibGUudG9TdHJpbmcsIG9iaikKICBfb2JqID0gdGltZVRlc3QoInRhYmxlLmZyb21TdHJpbmcoKToiLCB0YWJsZS5mcm9tU3RyaW5nLCBzKQplbmQKCi0tICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogLS0KLS0gKiogICBTZXJpYWxpemUgdGFibGUgdG8gc3RyaW5nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqKiAtLQotLSAqKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICoqIC0tCi0tICoqICAgTW9kaWZpZWQgdmVyc2lvbiBvZiBodHRwOi8vbC4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ucy5vcmcvd2lraS9TYXZlVGFibGVUb0ZpbGUgICAgICAgICAgICAgICoqIC0tCi0tICoqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKiogLS0KLS0gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAtLQogCi0tIGRlY2xhcmUgbG9jYWwgdmFyaWFibGVzCi0tLy8gZXhwb3J0c3RyaW5nKCBzdHJpbmcgKQotLS8vIHJldHVybnMgYSAiTHVhIiBwb3J0YWJsZSB2ZXJzaW9uIG9mIHRoZSBzdHJpbmcKbG9jYWwgZnVuY3Rpb24gZXhwb3J0c3RyaW5nKCBzICkKICByZXR1cm4gc3RyaW5nLmZvcm1hdCgiJXEiLCBzKQplbmQKIApsb2NhbCBpbnNlcnQgID0gdGFibGUuaW5zZXJ0CmxvY2FsIHRvc3RyaW5nPSB0b3N0cmluZwpsb2NhbCBpcGFpcnMgID0gaXBhaXJzCmxvY2FsIHBhaXJzICAgPSBwYWlycwpsb2NhbCB0eXBlICAgID0gdHlwZQogCi0tLy8gVGhlIFNhdmUgRnVuY3Rpb24KZnVuY3Rpb24gdGFibGUudG9TdHJpbmcodGJsKQogIGlmIHR5cGUodGJsKSB+PSAndGFibGUnIHRoZW4gcmV0dXJuICIiIGVuZCAtLSBBcmd1bWVudCBub3QgYSB0YWJsZQogCiAgbG9jYWwgY2hhclMsY2hhckUgPSAiICAgIiwiXG4iCiAgbG9jYWwgc190YmwgPSB7fQogCiAgLS0gaW5pdGlhdGUgdmFyaWFibGVzIGZvciBzYXZlIHByb2NlZHVyZQogIGxvY2FsIHRhYmxlcyxsb29rdXAgPSB7IHRibCB9LHsgW3RibF0gPSAxIH0KICBpbnNlcnQoc190YmwsICJyZXR1cm4geyIuLmNoYXJFICkKIAogIGZvciBpZHgsdCBpbiBpcGFpcnMoIHRhYmxlcyApIGRvCiAgICBpbnNlcnQoc190YmwsICItLSBUYWJsZTogeyIuLmlkeC4uIn0iLi5jaGFyRSApCiAgICBpbnNlcnQoc190YmwsICJ7Ii4uY2hhckUgKQogICAgbG9jYWwgdGhhbmRsZWQgPSB7fQogCiAgICBmb3IgaSx2IGluIGlwYWlycyggdCApIGRvCiAgICAgIHRoYW5kbGVkW2ldID0gdHJ1ZQogICAgICBsb2NhbCBzdHlwZSA9IHR5cGUoIHYgKQogICAgICAtLSBvbmx5IGhhbmRsZSB2YWx1ZQogICAgICBpZiBzdHlwZSA9PSAidGFibGUiIHRoZW4KICAgICAgICBpZiBub3QgbG9va3VwW3ZdIHRoZW4KICAgICAgICAgIGluc2VydCggdGFibGVzLCB2ICkKICAgICAgICAgIGxvb2t1cFt2XSA9ICN0YWJsZXMKICAgICAgICBlbmQKICAgICAgICBpbnNlcnQoc190YmwsIGNoYXJTLi4ieyIuLmxvb2t1cFt2XS4uIn0sIi4uY2hhckUgKQogICAgICBlbHNlaWYgc3R5cGUgPT0gInN0cmluZyIgdGhlbgogICAgICAgIGluc2VydChzX3RibCwgIGNoYXJTLi5leHBvcnRzdHJpbmcoIHYgKS4uIiwiLi5jaGFyRSApCiAgICAgIGVsc2VpZiBzdHlwZSA9PSAibnVtYmVyIiBvciBzdHlwZSA9PSAiYm9vbGVhbiIgdGhlbgogICAgICAgIGluc2VydChzX3RibCwgIGNoYXJTLi50b3N0cmluZyggdiApLi4iLCIuLmNoYXJFICkKICAgICAgZW5kCiAgICBlbmQKIAogICAgZm9yIGksdiBpbiBwYWlycyggdCApIGRvCiAgICAgIC0tIGVzY2FwZSBoYW5kbGVkIHZhbHVlcwogICAgICBpZiAobm90IHRoYW5kbGVkW2ldKSB0aGVuCiAKICAgICAgICBsb2NhbCBzdHIgPSAiIgogICAgICAgIGxvY2FsIHN0eXBlID0gdHlwZSggaSApCiAgICAgICAgLS0gaGFuZGxlIGluZGV4CiAgICAgICAgaWYgc3R5cGUgPT0gInRhYmxlIiB0aGVuCiAgICAgICAgICBpZiBub3QgbG9va3VwW2ldIHRoZW4KICAgICAgICAgICAgaW5zZXJ0KCB0YWJsZXMsaSApCiAgICAgICAgICAgIGxvb2t1cFtpXSA9ICN0YWJsZXMKICAgICAgICAgIGVuZAogICAgICAgICAgc3RyID0gY2hhclMuLiJbeyIuLmxvb2t1cFtpXS4uIn1dPSIKICAgICAgICBlbHNlaWYgc3R5cGUgPT0gInN0cmluZyIgdGhlbgogICAgICAgICAgc3RyID0gY2hhclMuLiJbIi4uZXhwb3J0c3RyaW5nKCBpICkuLiJdPSIKICAgICAgICBlbHNlaWYgc3R5cGUgPT0gIm51bWJlciIgb3Igc3R5cGUgPT0gImJvb2xlYW4iIHRoZW4KICAgICAgICAgIHN0ciA9IGNoYXJTLi4iWyIuLnRvc3RyaW5nKCBpICkuLiJdPSIKICAgICAgICBlbmQKIAogICAgICAgIGlmIHN0ciB+PSAiIiB0aGVuCiAgICAgICAgICBzdHlwZSA9IHR5cGUoIHYgKQogICAgICAgICAgLS0gaGFuZGxlIHZhbHVlCiAgICAgICAgICBpZiBzdHlwZSA9PSAidGFibGUiIHRoZW4KICAgICAgICAgICAgaWYgbm90IGxvb2t1cFt2XSB0aGVuCiAgICAgICAgICAgICAgaW5zZXJ0KCB0YWJsZXMsdiApCiAgICAgICAgICAgICAgbG9va3VwW3ZdID0gI3RhYmxlcwogICAgICAgICAgICBlbmQKICAgICAgICAgICAgaW5zZXJ0KHNfdGJsLCBzdHIuLiJ7Ii4ubG9va3VwW3ZdLi4ifSwiLi5jaGFyRSApCiAgICAgICAgICBlbHNlaWYgc3R5cGUgPT0gInN0cmluZyIgdGhlbgogICAgICAgICAgICBpbnNlcnQoc190YmwsIHN0ci4uZXhwb3J0c3RyaW5nKCB2ICkuLiIsIi4uY2hhckUgKQogICAgICAgICAgZWxzZWlmIHN0eXBlID09ICJudW1iZXIiIG9yIHN0eXBlID09ICJib29sZWFuIiB0aGVuCiAgICAgICAgICAgIGluc2VydChzX3RibCwgc3RyLi50b3N0cmluZyggdiApLi4iLCIuLmNoYXJFICkKICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgICBlbmQKICAgIGVuZAogICAgaW5zZXJ0KHNfdGJsLCAifSwiLi5jaGFyRSApCiAgZW5kCiAgaW5zZXJ0KHNfdGJsLCAifSIgKQogCiAgcmV0dXJuIHRhYmxlLmNvbmNhdChzX3RibCkKZW5kCiAKLS0vLyBUaGUgTG9hZCBGdW5jdGlvbgpmdW5jdGlvbiB0YWJsZS5mcm9tU3RyaW5nKHMpCiAgaWYgbm90IHMgdGhlbiByZXR1cm4gZW5kIC0tIEFyZ3VtZW50IG5vdCBzdHJpbmcKICBsb2NhbCBmdGFibGVzID0gbG9hZHN0cmluZyhzKQogIGlmIG5vdCBmdGFibGVzIHRoZW4gcmV0dXJuIGVuZCAtLSBTdHJpbmcgY2FudCBiZSBwYXJzZWQgaW50byBmdW5jdGlvbgogIGxvY2FsIHRhYmxlcyA9IGZ0YWJsZXMoKQogIGZvciBpZHggPSAxLCN0YWJsZXMgZG8KICAgIGxvY2FsIHRvbGlua2kgPSB7fQogICAgZm9yIGksdiBpbiBwYWlycyggdGFibGVzW2lkeF0gKSBkbwogICAgICBpZiB0eXBlKCB2ICkgPT0gInRhYmxlIiB0aGVuCiAgICAgICAgdGFibGVzW2lkeF1baV0gPSB0YWJsZXNbdlsxXV0KICAgICAgZW5kCiAgICAgIGlmIHR5cGUoIGkgKSA9PSAidGFibGUiIGFuZCB0YWJsZXNbaVsxXV0gdGhlbgogICAgICAgIGluc2VydCggdG9saW5raSx7IGksdGFibGVzW2lbMV1dIH0gKQogICAgICBlbmQKICAgIGVuZAogICAgLS0gbGluayBpbmRpY2VzCiAgICBmb3IgXyx2IGluIGlwYWlycyggdG9saW5raSApIGRvCiAgICAgIHRhYmxlc1tpZHhdW3ZbMl1dLHRhYmxlc1tpZHhdW3ZbMV1dID0gIHRhYmxlc1tpZHhdW3ZbMV1dLG5pbAogICAgZW5kCiAgZW5kCiAgcmV0dXJuIHRhYmxlc1sxXQplbmQKCgoKbG9jYWwgZnVuY3Rpb24gc2VyaWFsaXplSW1wbCggdCwgdFRyYWNraW5nICkgIAogIGxvY2FsIHNUeXBlID0gdHlwZSh0KQogIGlmIHNUeXBlID09ICJ0YWJsZSIgdGhlbgogICAgaWYgdFRyYWNraW5nW3RdIH49IG5pbCB0aGVuCiAgICAgIGVycm9yKCAiQ2Fubm90IHNlcmlhbGl6ZSB0YWJsZSB3aXRoIHJlY3Vyc2l2ZSBlbnRyaWVzIiApCiAgICBlbmQKICAgIHRUcmFja2luZ1t0XSA9IHRydWUKICAgIAogICAgbG9jYWwgcmVzdWx0ID0gInsiCiAgICBmb3Igayx2IGluIHBhaXJzKHQpIGRvCiAgICAgIHJlc3VsdCA9IHJlc3VsdC4uKCJbIi4uc2VyaWFsaXplSW1wbChrLCB0VHJhY2tpbmcpLi4iXT0iLi5zZXJpYWxpemVJbXBsKHYsIHRUcmFja2luZykuLiIsIikKICAgIGVuZAogICAgcmVzdWx0ID0gcmVzdWx0Li4ifSIKICAgIHJldHVybiByZXN1bHQKICAgIAogIGVsc2VpZiBzVHlwZSA9PSAic3RyaW5nIiB0aGVuCiAgICByZXR1cm4gc3RyaW5nLmZvcm1hdCggIiVxIiwgdCApCiAgCiAgZWxzZWlmIHNUeXBlID09ICJudW1iZXIiIG9yIHNUeXBlID09ICJib29sZWFuIiBvciBzVHlwZSA9PSAibmlsIiB0aGVuCiAgICByZXR1cm4gdG9zdHJpbmcodCkKICAgIAogIGVsc2UKICAgIGVycm9yKCAiQ2Fubm90IHNlcmlhbGl6ZSB0eXBlICIuLnNUeXBlICkKICAgIAogIGVuZAplbmQKCmZ1bmN0aW9uIHNlcmlhbGl6ZSggdCApCiAgbG9jYWwgdFRyYWNraW5nID0ge30KICByZXR1cm4gc2VyaWFsaXplSW1wbCggdCwgdFRyYWNraW5nICkKZW5kCgpmdW5jdGlvbiB1bnNlcmlhbGl6ZSggcyApCiAgbG9jYWwgZnVuYywgZSA9IGxvYWRzdHJpbmcoICJyZXR1cm4gIi4ucywgInNlcmlhbGl6ZSIgKQogIGlmIG5vdCBmdW5jIHRoZW4KICAgIHJldHVybiBzCiAgZWxzZQogICAgLS1zZXRmZW52KCBmdW5jLCB7fSApCiAgICByZXR1cm4gZnVuYygpCiAgZW5kCmVuZAoKCnNlcmlhbGl6YXRpb24gPSB7fQoKLS0gSW1wb3J0YW50OiBwcmV0dHkgZm9ybWF0dGluZyB3aWxsIGFsbG93IHByZXNlbnRpbmcgbm9uLXNlcmlhbGl6YWJsZSB2YWx1ZXMKLS0gYnV0IG1heSBnZW5lcmF0ZSBvdXRwdXQgdGhhdCBjYW5ub3QgYmUgdW5zZXJpYWxpemVkIGJhY2suCmZ1bmN0aW9uIHNlcmlhbGl6YXRpb24uc2VyaWFsaXplKHZhbHVlLCBwcmV0dHkpCiAgbG9jYWwga3cgPSAge1siYW5kIl09dHJ1ZSwgWyJicmVhayJdPXRydWUsIFsiZG8iXT10cnVlLCBbImVsc2UiXT10cnVlLAogICAgICAgICAgICAgICBbImVsc2VpZiJdPXRydWUsIFsiZW5kIl09dHJ1ZSwgWyJmYWxzZSJdPXRydWUsIFsiZm9yIl09dHJ1ZSwKICAgICAgICAgICAgICAgWyJmdW5jdGlvbiJdPXRydWUsIFsiZ290byJdPXRydWUsIFsiaWYiXT10cnVlLCBbImluIl09dHJ1ZSwKICAgICAgICAgICAgICAgWyJsb2NhbCJdPXRydWUsIFsibmlsIl09dHJ1ZSwgWyJub3QiXT10cnVlLCBbIm9yIl09dHJ1ZSwKICAgICAgICAgICAgICAgWyJyZXBlYXQiXT10cnVlLCBbInJldHVybiJdPXRydWUsIFsidGhlbiJdPXRydWUsIFsidHJ1ZSJdPXRydWUsCiAgICAgICAgICAgICAgIFsidW50aWwiXT10cnVlLCBbIndoaWxlIl09dHJ1ZX0KICBsb2NhbCBpZCA9ICJeWyVhX11bJXdfXSokIgogIGxvY2FsIHRzID0ge30KICBsb2NhbCBmdW5jdGlvbiBzKHYsIGwpCiAgICBsb2NhbCB0ID0gdHlwZSh2KQogICAgaWYgdCA9PSAibmlsIiB0aGVuCiAgICAgIHJldHVybiAibmlsIgogICAgZWxzZWlmIHQgPT0gImJvb2xlYW4iIHRoZW4KICAgICAgcmV0dXJuIHYgYW5kICJ0cnVlIiBvciAiZmFsc2UiCiAgICBlbHNlaWYgdCA9PSAibnVtYmVyIiB0aGVuCiAgICAgIGlmIHYgfj0gdiB0aGVuCiAgICAgICAgcmV0dXJuICIwLzAiCiAgICAgIGVsc2VpZiB2ID09IG1hdGguaHVnZSB0aGVuCiAgICAgICAgcmV0dXJuICJtYXRoLmh1Z2UiCiAgICAgIGVsc2VpZiB2ID09IC1tYXRoLmh1Z2UgdGhlbgogICAgICAgIHJldHVybiAiLW1hdGguaHVnZSIKICAgICAgZWxzZQogICAgICAgIHJldHVybiB0b3N0cmluZyh2KQogICAgICBlbmQKICAgIGVsc2VpZiB0ID09ICJzdHJpbmciIHRoZW4KICAgICAgcmV0dXJuIHN0cmluZy5mb3JtYXQoIiVxIiwgdik6Z3N1YigiXFxcbiIsIlxcbiIpCiAgICBlbHNlaWYgdCA9PSAidGFibGUiIGFuZCBwcmV0dHkgYW5kIGdldG1ldGF0YWJsZSh2KSBhbmQgZ2V0bWV0YXRhYmxlKHYpLl9fdG9zdHJpbmcgdGhlbgogICAgICByZXR1cm4gdG9zdHJpbmcodikKICAgIGVsc2VpZiB0ID09ICJ0YWJsZSIgdGhlbgogICAgICBpZiB0c1t2XSB0aGVuCiAgICAgICAgaWYgcHJldHR5IHRoZW4KICAgICAgICAgIHJldHVybiAicmVjdXJzaW9uIgogICAgICAgIGVsc2UKICAgICAgICAgIGVycm9yKCJ0YWJsZXMgd2l0aCBjeWNsZXMgYXJlIG5vdCBzdXBwb3J0ZWQiKQogICAgICAgIGVuZAogICAgICBlbmQKICAgICAgdHNbdl0gPSB0cnVlCiAgICAgIGxvY2FsIGksIHIgPSAxLCBuaWwKICAgICAgbG9jYWwgZgogICAgICBpZiBwcmV0dHkgdGhlbgogICAgICAgIGxvY2FsIGtzLCBza3MsIG9rcyA9IHt9LCB7fSwge30KICAgICAgICBmb3IgayBpbiBwYWlycyh2KSBkbwogICAgICAgICAgaWYgdHlwZShrKSA9PSAibnVtYmVyIiB0aGVuCiAgICAgICAgICAgIHRhYmxlLmluc2VydChrcywgaykKICAgICAgICAgIGVsc2VpZiB0eXBlKGspID09ICJzdHJpbmciIHRoZW4KICAgICAgICAgICAgdGFibGUuaW5zZXJ0KHNrcywgaykKICAgICAgICAgIGVsc2UKICAgICAgICAgICAgdGFibGUuaW5zZXJ0KG9rcywgaykKICAgICAgICAgIGVuZAogICAgICAgIGVuZAogICAgICAgIHRhYmxlLnNvcnQoa3MpCiAgICAgICAgdGFibGUuc29ydChza3MpCiAgICAgICAgZm9yIF8sIGsgaW4gaXBhaXJzKHNrcykgZG8KICAgICAgICAgIHRhYmxlLmluc2VydChrcywgaykKICAgICAgICBlbmQKICAgICAgICBmb3IgXywgayBpbiBpcGFpcnMob2tzKSBkbwogICAgICAgICAgdGFibGUuaW5zZXJ0KGtzLCBrKQogICAgICAgIGVuZAogICAgICAgIGxvY2FsIG4gPSAwCiAgICAgICAgZiA9IHRhYmxlLnBhY2soZnVuY3Rpb24oKQogICAgICAgICAgbiA9IG4gKyAxCiAgICAgICAgICBsb2NhbCBrID0ga3Nbbl0KICAgICAgICAgIGlmIGsgfj0gbmlsIHRoZW4KICAgICAgICAgICAgcmV0dXJuIGssIHZba10KICAgICAgICAgIGVsc2UKICAgICAgICAgICAgcmV0dXJuIG5pbAogICAgICAgICAgZW5kCiAgICAgICAgZW5kKQogICAgICBlbHNlCiAgICAgICAgZiA9IHRhYmxlLnBhY2socGFpcnModikpCiAgICAgIGVuZAogICAgICBmb3IgaywgdiBpbiB0YWJsZS51bnBhY2soZikgZG8KICAgICAgICBpZiByIHRoZW4KICAgICAgICAgIHIgPSByIC4uICIsIiAuLiAocHJldHR5IGFuZCAoIlxuIiAuLiBzdHJpbmcucmVwKCIgIiwgbCkpIG9yICIiKQogICAgICAgIGVsc2UKICAgICAgICAgIHIgPSAieyIKICAgICAgICBlbmQKICAgICAgICBsb2NhbCB0ayA9IHR5cGUoaykKICAgICAgICBpZiB0ayA9PSAibnVtYmVyIiBhbmQgayA9PSBpIHRoZW4KICAgICAgICAgIGkgPSBpICsgMQogICAgICAgICAgciA9IHIgLi4gcyh2LCBsICsgMSkKICAgICAgICBlbHNlCiAgICAgICAgICBpZiB0ayA9PSAic3RyaW5nIiBhbmQgbm90IGt3W2tdIGFuZCBzdHJpbmcubWF0Y2goaywgaWQpIHRoZW4KICAgICAgICAgICAgciA9IHIgLi4gawogICAgICAgICAgZWxzZQogICAgICAgICAgICByID0gciAuLiAiWyIgLi4gcyhrLCBsICsgMSkgLi4gIl0iCiAgICAgICAgICBlbmQKICAgICAgICAgIHIgPSByIC4uICI9IiAuLiBzKHYsIGwgKyAxKQogICAgICAgIGVuZAogICAgICBlbmQKICAgICAgdHNbdl0gPSBuaWwgLS0gYWxsb3cgd3JpdGluZyBzYW1lIHRhYmxlIG1vcmUgdGhhbiBvbmNlCiAgICAgIHJldHVybiAociBvciAieyIpIC4uICJ9IgogICAgZWxzZQogICAgICBpZiBwcmV0dHkgdGhlbgogICAgICAgIHJldHVybiB0b3N0cmluZyh0KQogICAgICBlbHNlCiAgICAgICAgZXJyb3IoInVuc3VwcG9ydGVkIHR5cGU6ICIgLi4gdCkKICAgICAgZW5kCiAgICBlbmQKICBlbmQKICBsb2NhbCByZXN1bHQgPSBzKHZhbHVlLCAxKQogIGxvY2FsIGxpbWl0ID0gdHlwZShwcmV0dHkpID09ICJudW1iZXIiIGFuZCBwcmV0dHkgb3IgMTAKICBpZiBwcmV0dHkgdGhlbgogICAgbG9jYWwgdHJ1bmNhdGUgPSAwCiAgICB3aGlsZSBsaW1pdCA+IDAgYW5kIHRydW5jYXRlIGRvCiAgICAgIHRydW5jYXRlID0gc3RyaW5nLmZpbmQocmVzdWx0LCAiXG4iLCB0cnVuY2F0ZSArIDEsIHRydWUpCiAgICAgIGxpbWl0ID0gbGltaXQgLSAxCiAgICBlbmQKICAgIGlmIHRydW5jYXRlIHRoZW4KICAgICAgcmV0dXJuIHJlc3VsdDpzdWIoMSwgdHJ1bmNhdGUpIC4uICIuLi4iCiAgICBlbmQKICBlbmQKICByZXR1cm4gcmVzdWx0CmVuZAoKZnVuY3Rpb24gc2VyaWFsaXphdGlvbi51bnNlcmlhbGl6ZShkYXRhKQogIC0tY2hlY2tBcmcoMSwgZGF0YSwgInN0cmluZyIpCiAgbG9jYWwgcmVzdWx0LCByZWFzb24gPSBsb2FkKCJyZXR1cm4gIiAuLiBkYXRhLCAiPWRhdGEiLCBfLCB7bWF0aD17aHVnZT1tYXRoLmh1Z2V9fSkKICBpZiBub3QgcmVzdWx0IHRoZW4KICAgIHJldHVybiBuaWwsIHJlYXNvbgogIGVuZAogIGxvY2FsIG9rLCBvdXRwdXQgPSBwY2FsbChyZXN1bHQpCiAgaWYgbm90IG9rIHRoZW4KICAgIHJldHVybiBuaWwsIG91dHB1dAogIGVuZAogIHJldHVybiBvdXRwdXQKZW5kCgoKbWFpbigp