import std.stdio;
import std.string;
import std.conv;
import std.outbuffer;
import std.algorithm;
import std.array;
import std.json;
import std.xml;
import std.file;
import std.path;
void main()
{
writeln(Tree.fromJSON(`{ "users" : [
{
"name" : "John",
"age" : 30
},
{
"name" : "John",
"age" : 30
}]}`).toString());
}
class Tree
{
string name;
string value;
string baseUri;
size_t row;
size_t col;
Tree[] childs;
this(string name, string value, Tree[] childs, string baseUri = "", size_t row = 0,
size_t col = 0)
{
this.name = name;
this.value = value;
this.childs = childs;
this.baseUri = baseUri;
this.row = row;
this.col = col;
}
this(DirEntry input, string baseUri = null, size_t row = 1, size_t col = 1)
{
if (baseUri is null)
baseUri = absolutePath(input.name);
this(cast(string) read(input.name), baseUri, row, col);
}
this(File input, string baseUri = null, size_t row = 1, size_t col = 1)
{
if (baseUri is null)
baseUri = input.name.absolutePath.asNormalizedPath.array;
this(cast(string) read(input.name), baseUri, row, col);
}
unittest
{
assert(new Tree("foo\nbar\n", "").length == 2);
assert(new Tree("foo\nbar\n", "")[1].name == "bar");
assert(new Tree("foo\n\n\n", "").length == 1);
assert(new Tree("\\foo\n\\bar\n", "").value == "foo\nbar");
assert(new Tree("\\foo\n\\bar\n", "").length == 0);
assert(new Tree("foo bar \\pol", "")[0][0].value == "pol");
assert(new Tree("foo bar\n\t\\pol\n\t\\men", "")[0][0].value == "pol\nmen");
}
this(string input, string baseUri, size_t row = 1, size_t col = 1)
{
this("", null, [], baseUri, row, col);
Tree[] stack = [this];
Tree parent = this;
while (input.length)
{
auto name = input.takeUntil("\t\n \\");
if (name.length)
{
auto next = new Tree(name, null, [], baseUri, row, col);
parent.childs ~= next;
parent = next;
col += name.length + input.take(" ").length;
continue;
}
if (!input.length)
break;
if (input[0] == '\\')
{
auto value = input.takeUntil("\n")[1 .. $];
if (parent.value is null)
parent.value = value;
else
parent.value ~= "\n" ~ value;
}
if (!input.length)
break;
if (input[0] != '\n')
{
throw new Exception("Unexpected symbol (" ~ input[0] ~ ")");
}
input = input[1 .. $];
col = 1;
row += 1;
auto indent = input.take("\t").length;
col = indent;
if (indent > stack.length)
{
throw new Exception("Too many TABs " ~ row.to!string ~ ":" ~ col.to!string);
}
stack ~= parent;
stack.length = indent + 1;
parent = stack[indent];
}
}
Tree make(string name = null, string value = null, Tree[] childs = null,
string baseUri = null, size_t row = 0, size_t col = 0)
{
return new Tree(name ? name : this.name, value ? value : this.value,
childs ? childs : this.childs, baseUri ? baseUri : this.baseUri,
row ? row : this.row, col ? col : this.col);
}
static Tree fromJSON(string json)
{
return Tree.fromJSON(parseJSON(json));
}
static Tree fromJSON(JSONValue json)
{
switch (json.type)
{
case JSON_TYPE.FALSE:
return new Tree("false", "", []);
case JSON_TYPE.TRUE:
return new Tree("true", "", []);
case JSON_TYPE.NULL:
return new Tree("null", "", []);
case JSON_TYPE.FLOAT:
return new Tree("float", json.floating.to!string, []);
case JSON_TYPE.INTEGER:
return new Tree("int", json.integer.to!string, []);
case JSON_TYPE.UINTEGER:
return new Tree("int", json.uinteger.to!string, []);
case JSON_TYPE.STRING:
return new Tree("string", json.str, []);
case JSON_TYPE.ARRAY:
return new Tree("list", "",
json.array.map!(json => Tree.fromJSON(json)).array);
case JSON_TYPE.OBJECT:
Tree[] childs = [];
foreach (key, value; json.object)
{
childs ~= new Tree("*", key, [new Tree(":", "", [Tree.fromJSON(value)])]);
}
return new Tree("dict", "", childs);
default:
throw new Error("Unsupported type: " ~ json.type);
}
}
static Tree fromXML(string xml)
{
return Tree.fromXML(new Document(xml));
}
static Tree fromXML(Item xml)
{
auto el = cast(Element) xml;
if (el)
{
Tree[] attrs;
foreach (key, val; el.tag.attr)
{
attrs ~= new Tree("@", "", [new Tree(key, val)]);
}
auto childs = el.items
.map!(Tree.fromXML)
.filter!(a => a)
.array;
return new Tree(el.tag.name, "", attrs ~ childs);
}
auto com = cast(Comment) xml;
if (com)
{
return new Tree("--", com.to!string[4 .. $ - 3], []);
}
auto txt = cast(Text) xml;
if (txt)
{
if (txt.to!string
.all!(isSpace))
return null;
return new Tree("'", com.to!string, []);
}
throw new Error("Unsupported node type!");
}
OutputType pipe(OutputType)(OutputType output, string prefix = "")
{
if (this.name.length)
output.write(this.name ~ " ");
auto chunks = this.value.length ? this.value.split("\n") : [];
if (chunks.length + this.childs.length == 1)
{
if (chunks.length)
output.write("\\" ~ chunks[0] ~ "\n");
else
childs[0].pipe(output, prefix);
}
else
{
output.write("\n");
if (this.name.length)
prefix ~= "\t";
foreach (chunk; chunks)
output.write(prefix ~ "\\" ~ chunk ~ "\n");
foreach (child; this.childs)
{
output.write(prefix);
child.pipe(output, prefix);
}
}
return output;
}
override string toString()
{
OutBuffer buf = new OutBuffer;
this.pipe(buf);
return buf.to!string;
}
Tree expand()
{
return this.make(null, null, [new Tree("@", this.uri,
[])] ~ this.childs.map!(child => child.expand).array);
}
string uri()
{
return this.baseUri ~ "#" ~ this.row.to!string ~ ":" ~ this.col.to!string;
}
unittest
{
auto tree = new Tree("foo \\1\nbar \\2", "");
assert(tree["bar"][0].to!string == "bar \\2\n");
}
auto opIndex(string path)
{
return this[path.split(" ")];
}
unittest
{
assert(new Tree("foo bar \\2", "")[["foo", "bar"]].to!string == "bar \\2\n");
}
auto opIndex(string[] path)
{
Tree[] next = [this];
foreach (string name; path)
{
if (!next.length)
break;
Tree[] prev = next;
next = [];
foreach (Tree item; prev)
{
foreach (Tree child; item.childs)
{
if (child.name != name)
continue;
next ~= child;
}
}
}
return new Tree("", "", next);
}
Tree opIndex(size_t index)
{
return this.childs[index];
}
Tree[] opSlice(size_t start, size_t end)
{
return this.childs[start .. end];
}
size_t length()
{
return this.childs.length;
}
size_t opDollar()
{
return this.childs.length;
}
}
string take(ref string input, string symbols)
{
auto i = 0;
while (i < input.length)
{
auto symbol = input[i];
if (symbols.indexOf(symbol) == -1)
{
break;
}
else
{
i += 1;
}
}
auto res = input[0 .. i];
input = input[i .. $];
return res;
}
string takeUntil(ref string input, string symbols)
{
auto i = 0;
while (i < input.length)
{
auto symbol = input[i];
if (symbols.indexOf(symbol) == -1)
{
i += 1;
}
else
{
break;
}
}
auto res = input[0 .. i];
input = input[i .. $];
return res;
}
aW1wb3J0IHN0ZC5zdGRpbzsKaW1wb3J0IHN0ZC5zdHJpbmc7CmltcG9ydCBzdGQuY29udjsKaW1wb3J0IHN0ZC5vdXRidWZmZXI7CmltcG9ydCBzdGQuYWxnb3JpdGhtOwppbXBvcnQgc3RkLmFycmF5OwppbXBvcnQgc3RkLmpzb247CmltcG9ydCBzdGQueG1sOwppbXBvcnQgc3RkLmZpbGU7CmltcG9ydCBzdGQucGF0aDsKCnZvaWQgbWFpbigpCnsKICAgIHdyaXRlbG4oVHJlZS5mcm9tSlNPTihgeyAidXNlcnMiIDogWwp7CgkibmFtZSIgOiAiSm9obiIsCgkiYWdlIiA6IDMwCn0sCnsKCSJuYW1lIiA6ICJKb2huIiwKCSJhZ2UiIDogMzAKfV19YCkudG9TdHJpbmcoKSk7Cn0KCmNsYXNzIFRyZWUKewoKICAgIHN0cmluZyBuYW1lOwogICAgc3RyaW5nIHZhbHVlOwogICAgc3RyaW5nIGJhc2VVcmk7CiAgICBzaXplX3Qgcm93OwogICAgc2l6ZV90IGNvbDsKICAgIFRyZWVbXSBjaGlsZHM7CgogICAgdGhpcyhzdHJpbmcgbmFtZSwgc3RyaW5nIHZhbHVlLCBUcmVlW10gY2hpbGRzLCBzdHJpbmcgYmFzZVVyaSA9ICIiLCBzaXplX3Qgcm93ID0gMCwKICAgICAgICAgICAgc2l6ZV90IGNvbCA9IDApCiAgICB7CiAgICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgICB0aGlzLnZhbHVlID0gdmFsdWU7CiAgICAgICAgdGhpcy5jaGlsZHMgPSBjaGlsZHM7CiAgICAgICAgdGhpcy5iYXNlVXJpID0gYmFzZVVyaTsKICAgICAgICB0aGlzLnJvdyA9IHJvdzsKICAgICAgICB0aGlzLmNvbCA9IGNvbDsKICAgIH0KCiAgICB0aGlzKERpckVudHJ5IGlucHV0LCBzdHJpbmcgYmFzZVVyaSA9IG51bGwsIHNpemVfdCByb3cgPSAxLCBzaXplX3QgY29sID0gMSkKICAgIHsKICAgICAgICBpZiAoYmFzZVVyaSBpcyBudWxsKQogICAgICAgICAgICBiYXNlVXJpID0gYWJzb2x1dGVQYXRoKGlucHV0Lm5hbWUpOwogICAgICAgIHRoaXMoY2FzdChzdHJpbmcpIHJlYWQoaW5wdXQubmFtZSksIGJhc2VVcmksIHJvdywgY29sKTsKICAgIH0KCiAgICB0aGlzKEZpbGUgaW5wdXQsIHN0cmluZyBiYXNlVXJpID0gbnVsbCwgc2l6ZV90IHJvdyA9IDEsIHNpemVfdCBjb2wgPSAxKQogICAgewogICAgICAgIGlmIChiYXNlVXJpIGlzIG51bGwpCiAgICAgICAgICAgIGJhc2VVcmkgPSBpbnB1dC5uYW1lLmFic29sdXRlUGF0aC5hc05vcm1hbGl6ZWRQYXRoLmFycmF5OwogICAgICAgIHRoaXMoY2FzdChzdHJpbmcpIHJlYWQoaW5wdXQubmFtZSksIGJhc2VVcmksIHJvdywgY29sKTsKICAgIH0KCiAgICB1bml0dGVzdAogICAgewogICAgICAgIGFzc2VydChuZXcgVHJlZSgiZm9vXG5iYXJcbiIsICIiKS5sZW5ndGggPT0gMik7CiAgICAgICAgYXNzZXJ0KG5ldyBUcmVlKCJmb29cbmJhclxuIiwgIiIpWzFdLm5hbWUgPT0gImJhciIpOwogICAgICAgIGFzc2VydChuZXcgVHJlZSgiZm9vXG5cblxuIiwgIiIpLmxlbmd0aCA9PSAxKTsKCiAgICAgICAgYXNzZXJ0KG5ldyBUcmVlKCJcXGZvb1xuXFxiYXJcbiIsICIiKS52YWx1ZSA9PSAiZm9vXG5iYXIiKTsKICAgICAgICBhc3NlcnQobmV3IFRyZWUoIlxcZm9vXG5cXGJhclxuIiwgIiIpLmxlbmd0aCA9PSAwKTsKCiAgICAgICAgYXNzZXJ0KG5ldyBUcmVlKCJmb28gYmFyIFxccG9sIiwgIiIpWzBdWzBdLnZhbHVlID09ICJwb2wiKTsKICAgICAgICBhc3NlcnQobmV3IFRyZWUoImZvbyBiYXJcblx0XFxwb2xcblx0XFxtZW4iLCAiIilbMF1bMF0udmFsdWUgPT0gInBvbFxubWVuIik7CiAgICB9CgogICAgdGhpcyhzdHJpbmcgaW5wdXQsIHN0cmluZyBiYXNlVXJpLCBzaXplX3Qgcm93ID0gMSwgc2l6ZV90IGNvbCA9IDEpCiAgICB7CiAgICAgICAgdGhpcygiIiwgbnVsbCwgW10sIGJhc2VVcmksIHJvdywgY29sKTsKICAgICAgICBUcmVlW10gc3RhY2sgPSBbdGhpc107CgogICAgICAgIFRyZWUgcGFyZW50ID0gdGhpczsKICAgICAgICB3aGlsZSAoaW5wdXQubGVuZ3RoKQogICAgICAgIHsKCiAgICAgICAgICAgIGF1dG8gbmFtZSA9IGlucHV0LnRha2VVbnRpbCgiXHRcbiBcXCIpOwogICAgICAgICAgICBpZiAobmFtZS5sZW5ndGgpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGF1dG8gbmV4dCA9IG5ldyBUcmVlKG5hbWUsIG51bGwsIFtdLCBiYXNlVXJpLCByb3csIGNvbCk7CiAgICAgICAgICAgICAgICBwYXJlbnQuY2hpbGRzIH49IG5leHQ7CiAgICAgICAgICAgICAgICBwYXJlbnQgPSBuZXh0OwogICAgICAgICAgICAgICAgY29sICs9IG5hbWUubGVuZ3RoICsgaW5wdXQudGFrZSgiICIpLmxlbmd0aDsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghaW5wdXQubGVuZ3RoKQogICAgICAgICAgICAgICAgYnJlYWs7CgogICAgICAgICAgICBpZiAoaW5wdXRbMF0gPT0gJ1xcJykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgYXV0byB2YWx1ZSA9IGlucHV0LnRha2VVbnRpbCgiXG4iKVsxIC4uICRdOwogICAgICAgICAgICAgICAgaWYgKHBhcmVudC52YWx1ZSBpcyBudWxsKQogICAgICAgICAgICAgICAgICAgIHBhcmVudC52YWx1ZSA9IHZhbHVlOwogICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgIHBhcmVudC52YWx1ZSB+PSAiXG4iIH4gdmFsdWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCFpbnB1dC5sZW5ndGgpCiAgICAgICAgICAgICAgICBicmVhazsKCiAgICAgICAgICAgIGlmIChpbnB1dFswXSAhPSAnXG4nKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXhjZXB0aW9uKCJVbmV4cGVjdGVkIHN5bWJvbCAoIiB+IGlucHV0WzBdIH4gIikiKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpbnB1dCA9IGlucHV0WzEgLi4gJF07CiAgICAgICAgICAgIGNvbCA9IDE7CiAgICAgICAgICAgIHJvdyArPSAxOwoKICAgICAgICAgICAgYXV0byBpbmRlbnQgPSBpbnB1dC50YWtlKCJcdCIpLmxlbmd0aDsKICAgICAgICAgICAgY29sID0gaW5kZW50OwogICAgICAgICAgICBpZiAoaW5kZW50ID4gc3RhY2subGVuZ3RoKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXhjZXB0aW9uKCJUb28gbWFueSBUQUJzICIgfiByb3cudG8hc3RyaW5nIH4gIjoiIH4gY29sLnRvIXN0cmluZyk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHN0YWNrIH49IHBhcmVudDsKICAgICAgICAgICAgc3RhY2subGVuZ3RoID0gaW5kZW50ICsgMTsKICAgICAgICAgICAgcGFyZW50ID0gc3RhY2tbaW5kZW50XTsKICAgICAgICB9CiAgICB9CgogICAgVHJlZSBtYWtlKHN0cmluZyBuYW1lID0gbnVsbCwgc3RyaW5nIHZhbHVlID0gbnVsbCwgVHJlZVtdIGNoaWxkcyA9IG51bGwsCiAgICAgICAgICAgIHN0cmluZyBiYXNlVXJpID0gbnVsbCwgc2l6ZV90IHJvdyA9IDAsIHNpemVfdCBjb2wgPSAwKQogICAgewogICAgICAgIHJldHVybiBuZXcgVHJlZShuYW1lID8gbmFtZSA6IHRoaXMubmFtZSwgdmFsdWUgPyB2YWx1ZSA6IHRoaXMudmFsdWUsCiAgICAgICAgICAgICAgICBjaGlsZHMgPyBjaGlsZHMgOiB0aGlzLmNoaWxkcywgYmFzZVVyaSA/IGJhc2VVcmkgOiB0aGlzLmJhc2VVcmksCiAgICAgICAgICAgICAgICByb3cgPyByb3cgOiB0aGlzLnJvdywgY29sID8gY29sIDogdGhpcy5jb2wpOwogICAgfQoKICAgIHN0YXRpYyBUcmVlIGZyb21KU09OKHN0cmluZyBqc29uKQogICAgewogICAgICAgIHJldHVybiBUcmVlLmZyb21KU09OKHBhcnNlSlNPTihqc29uKSk7CiAgICB9CgogICAgc3RhdGljIFRyZWUgZnJvbUpTT04oSlNPTlZhbHVlIGpzb24pCiAgICB7CiAgICAgICAgc3dpdGNoIChqc29uLnR5cGUpCiAgICAgICAgewogICAgICAgIGNhc2UgSlNPTl9UWVBFLkZBTFNFOgogICAgICAgICAgICByZXR1cm4gbmV3IFRyZWUoImZhbHNlIiwgIiIsIFtdKTsKICAgICAgICBjYXNlIEpTT05fVFlQRS5UUlVFOgogICAgICAgICAgICByZXR1cm4gbmV3IFRyZWUoInRydWUiLCAiIiwgW10pOwogICAgICAgIGNhc2UgSlNPTl9UWVBFLk5VTEw6CiAgICAgICAgICAgIHJldHVybiBuZXcgVHJlZSgibnVsbCIsICIiLCBbXSk7CiAgICAgICAgY2FzZSBKU09OX1RZUEUuRkxPQVQ6CiAgICAgICAgICAgIHJldHVybiBuZXcgVHJlZSgiZmxvYXQiLCBqc29uLmZsb2F0aW5nLnRvIXN0cmluZywgW10pOwogICAgICAgIGNhc2UgSlNPTl9UWVBFLklOVEVHRVI6CiAgICAgICAgICAgIHJldHVybiBuZXcgVHJlZSgiaW50IiwganNvbi5pbnRlZ2VyLnRvIXN0cmluZywgW10pOwogICAgICAgIGNhc2UgSlNPTl9UWVBFLlVJTlRFR0VSOgogICAgICAgICAgICByZXR1cm4gbmV3IFRyZWUoImludCIsIGpzb24udWludGVnZXIudG8hc3RyaW5nLCBbXSk7CiAgICAgICAgY2FzZSBKU09OX1RZUEUuU1RSSU5HOgogICAgICAgICAgICByZXR1cm4gbmV3IFRyZWUoInN0cmluZyIsIGpzb24uc3RyLCBbXSk7CiAgICAgICAgY2FzZSBKU09OX1RZUEUuQVJSQVk6CiAgICAgICAgICAgIHJldHVybiBuZXcgVHJlZSgibGlzdCIsICIiLAogICAgICAgICAgICAgICAgICAgIGpzb24uYXJyYXkubWFwIShqc29uID0+IFRyZWUuZnJvbUpTT04oanNvbikpLmFycmF5KTsKICAgICAgICBjYXNlIEpTT05fVFlQRS5PQkpFQ1Q6CiAgICAgICAgICAgIFRyZWVbXSBjaGlsZHMgPSBbXTsKICAgICAgICAgICAgZm9yZWFjaCAoa2V5LCB2YWx1ZTsganNvbi5vYmplY3QpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGNoaWxkcyB+PSBuZXcgVHJlZSgiKiIsIGtleSwgW25ldyBUcmVlKCI6IiwgIiIsIFtUcmVlLmZyb21KU09OKHZhbHVlKV0pXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG5ldyBUcmVlKCJkaWN0IiwgIiIsIGNoaWxkcyk7CiAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJVbnN1cHBvcnRlZCB0eXBlOiAiIH4ganNvbi50eXBlKTsKICAgICAgICB9CiAgICB9CgogICAgc3RhdGljIFRyZWUgZnJvbVhNTChzdHJpbmcgeG1sKQogICAgewogICAgICAgIHJldHVybiBUcmVlLmZyb21YTUwobmV3IERvY3VtZW50KHhtbCkpOwogICAgfQoKICAgIHN0YXRpYyBUcmVlIGZyb21YTUwoSXRlbSB4bWwpCiAgICB7CgogICAgICAgIGF1dG8gZWwgPSBjYXN0KEVsZW1lbnQpIHhtbDsKICAgICAgICBpZiAoZWwpCiAgICAgICAgewogICAgICAgICAgICBUcmVlW10gYXR0cnM7CiAgICAgICAgICAgIGZvcmVhY2ggKGtleSwgdmFsOyBlbC50YWcuYXR0cikKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgYXR0cnMgfj0gbmV3IFRyZWUoIkAiLCAiIiwgW25ldyBUcmVlKGtleSwgdmFsKV0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGF1dG8gY2hpbGRzID0gZWwuaXRlbXMKICAgICAgICAgICAgICAgIC5tYXAhKFRyZWUuZnJvbVhNTCkKICAgICAgICAgICAgICAgIC5maWx0ZXIhKGEgPT4gYSkKICAgICAgICAgICAgICAgIC5hcnJheTsKICAgICAgICAgICAgcmV0dXJuIG5ldyBUcmVlKGVsLnRhZy5uYW1lLCAiIiwgYXR0cnMgfiBjaGlsZHMpOwogICAgICAgIH0KCiAgICAgICAgYXV0byBjb20gPSBjYXN0KENvbW1lbnQpIHhtbDsKICAgICAgICBpZiAoY29tKQogICAgICAgIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBUcmVlKCItLSIsIGNvbS50byFzdHJpbmdbNCAuLiAkIC0gM10sIFtdKTsKICAgICAgICB9CgogICAgICAgIGF1dG8gdHh0ID0gY2FzdChUZXh0KSB4bWw7CiAgICAgICAgaWYgKHR4dCkKICAgICAgICB7CiAgICAgICAgICAgIGlmICh0eHQudG8hc3RyaW5nCiAgICAgICAgICAgICAgICAgICAgLmFsbCEoaXNTcGFjZSkpCiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgcmV0dXJuIG5ldyBUcmVlKCInIiwgY29tLnRvIXN0cmluZywgW10pOwogICAgICAgIH0KCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJVbnN1cHBvcnRlZCBub2RlIHR5cGUhIik7CiAgICB9CgogICAgT3V0cHV0VHlwZSBwaXBlKE91dHB1dFR5cGUpKE91dHB1dFR5cGUgb3V0cHV0LCBzdHJpbmcgcHJlZml4ID0gIiIpCiAgICB7CiAgICAgICAgaWYgKHRoaXMubmFtZS5sZW5ndGgpCiAgICAgICAgICAgIG91dHB1dC53cml0ZSh0aGlzLm5hbWUgfiAiICIpOwoKICAgICAgICBhdXRvIGNodW5rcyA9IHRoaXMudmFsdWUubGVuZ3RoID8gdGhpcy52YWx1ZS5zcGxpdCgiXG4iKSA6IFtdOwoKICAgICAgICBpZiAoY2h1bmtzLmxlbmd0aCArIHRoaXMuY2hpbGRzLmxlbmd0aCA9PSAxKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKGNodW5rcy5sZW5ndGgpCiAgICAgICAgICAgICAgICBvdXRwdXQud3JpdGUoIlxcIiB+IGNodW5rc1swXSB+ICJcbiIpOwogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICBjaGlsZHNbMF0ucGlwZShvdXRwdXQsIHByZWZpeCk7CiAgICAgICAgfQogICAgICAgIGVsc2UKICAgICAgICB7CiAgICAgICAgICAgIG91dHB1dC53cml0ZSgiXG4iKTsKICAgICAgICAgICAgaWYgKHRoaXMubmFtZS5sZW5ndGgpCiAgICAgICAgICAgICAgICBwcmVmaXggfj0gIlx0IjsKCiAgICAgICAgICAgIGZvcmVhY2ggKGNodW5rOyBjaHVua3MpCiAgICAgICAgICAgICAgICBvdXRwdXQud3JpdGUocHJlZml4IH4gIlxcIiB+IGNodW5rIH4gIlxuIik7CgogICAgICAgICAgICBmb3JlYWNoIChjaGlsZDsgdGhpcy5jaGlsZHMpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIG91dHB1dC53cml0ZShwcmVmaXgpOwogICAgICAgICAgICAgICAgY2hpbGQucGlwZShvdXRwdXQsIHByZWZpeCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHJldHVybiBvdXRwdXQ7CiAgICB9CgogICAgb3ZlcnJpZGUgc3RyaW5nIHRvU3RyaW5nKCkKICAgIHsKICAgICAgICBPdXRCdWZmZXIgYnVmID0gbmV3IE91dEJ1ZmZlcjsKICAgICAgICB0aGlzLnBpcGUoYnVmKTsKICAgICAgICByZXR1cm4gYnVmLnRvIXN0cmluZzsKICAgIH0KCiAgICBUcmVlIGV4cGFuZCgpCiAgICB7CiAgICAgICAgcmV0dXJuIHRoaXMubWFrZShudWxsLCBudWxsLCBbbmV3IFRyZWUoIkAiLCB0aGlzLnVyaSwKICAgICAgICAgICAgICAgIFtdKV0gfiB0aGlzLmNoaWxkcy5tYXAhKGNoaWxkID0+IGNoaWxkLmV4cGFuZCkuYXJyYXkpOwogICAgfQoKICAgIHN0cmluZyB1cmkoKQogICAgewogICAgICAgIHJldHVybiB0aGlzLmJhc2VVcmkgfiAiIyIgfiB0aGlzLnJvdy50byFzdHJpbmcgfiAiOiIgfiB0aGlzLmNvbC50byFzdHJpbmc7CiAgICB9CgogICAgdW5pdHRlc3QKICAgIHsKICAgICAgICBhdXRvIHRyZWUgPSBuZXcgVHJlZSgiZm9vIFxcMVxuYmFyIFxcMiIsICIiKTsKICAgICAgICBhc3NlcnQodHJlZVsiYmFyIl1bMF0udG8hc3RyaW5nID09ICJiYXIgXFwyXG4iKTsKICAgIH0KCiAgICBhdXRvIG9wSW5kZXgoc3RyaW5nIHBhdGgpCiAgICB7CiAgICAgICAgcmV0dXJuIHRoaXNbcGF0aC5zcGxpdCgiICIpXTsKICAgIH0KCiAgICB1bml0dGVzdAogICAgewogICAgICAgIGFzc2VydChuZXcgVHJlZSgiZm9vIGJhciBcXDIiLCAiIilbWyJmb28iLCAiYmFyIl1dLnRvIXN0cmluZyA9PSAiYmFyIFxcMlxuIik7CiAgICB9CgogICAgYXV0byBvcEluZGV4KHN0cmluZ1tdIHBhdGgpCiAgICB7CiAgICAgICAgVHJlZVtdIG5leHQgPSBbdGhpc107CiAgICAgICAgZm9yZWFjaCAoc3RyaW5nIG5hbWU7IHBhdGgpCiAgICAgICAgewogICAgICAgICAgICBpZiAoIW5leHQubGVuZ3RoKQogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIFRyZWVbXSBwcmV2ID0gbmV4dDsKICAgICAgICAgICAgbmV4dCA9IFtdOwogICAgICAgICAgICBmb3JlYWNoIChUcmVlIGl0ZW07IHByZXYpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGZvcmVhY2ggKFRyZWUgY2hpbGQ7IGl0ZW0uY2hpbGRzKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZC5uYW1lICE9IG5hbWUpCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgIG5leHQgfj0gY2hpbGQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBUcmVlKCIiLCAiIiwgbmV4dCk7CiAgICB9CgogICAgVHJlZSBvcEluZGV4KHNpemVfdCBpbmRleCkKICAgIHsKICAgICAgICByZXR1cm4gdGhpcy5jaGlsZHNbaW5kZXhdOwogICAgfQoKICAgIFRyZWVbXSBvcFNsaWNlKHNpemVfdCBzdGFydCwgc2l6ZV90IGVuZCkKICAgIHsKICAgICAgICByZXR1cm4gdGhpcy5jaGlsZHNbc3RhcnQgLi4gZW5kXTsKICAgIH0KCiAgICBzaXplX3QgbGVuZ3RoKCkKICAgIHsKICAgICAgICByZXR1cm4gdGhpcy5jaGlsZHMubGVuZ3RoOwogICAgfQoKICAgIHNpemVfdCBvcERvbGxhcigpCiAgICB7CiAgICAgICAgcmV0dXJuIHRoaXMuY2hpbGRzLmxlbmd0aDsKICAgIH0KCn0KCnN0cmluZyB0YWtlKHJlZiBzdHJpbmcgaW5wdXQsIHN0cmluZyBzeW1ib2xzKQp7CiAgICBhdXRvIGkgPSAwOwogICAgd2hpbGUgKGkgPCBpbnB1dC5sZW5ndGgpCiAgICB7CiAgICAgICAgYXV0byBzeW1ib2wgPSBpbnB1dFtpXTsKICAgICAgICBpZiAoc3ltYm9scy5pbmRleE9mKHN5bWJvbCkgPT0gLTEpCiAgICAgICAgewogICAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgZWxzZQogICAgICAgIHsKICAgICAgICAgICAgaSArPSAxOwogICAgICAgIH0KICAgIH0KICAgIGF1dG8gcmVzID0gaW5wdXRbMCAuLiBpXTsKICAgIGlucHV0ID0gaW5wdXRbaSAuLiAkXTsKICAgIHJldHVybiByZXM7Cn0KCnN0cmluZyB0YWtlVW50aWwocmVmIHN0cmluZyBpbnB1dCwgc3RyaW5nIHN5bWJvbHMpCnsKICAgIGF1dG8gaSA9IDA7CiAgICB3aGlsZSAoaSA8IGlucHV0Lmxlbmd0aCkKICAgIHsKICAgICAgICBhdXRvIHN5bWJvbCA9IGlucHV0W2ldOwogICAgICAgIGlmIChzeW1ib2xzLmluZGV4T2Yoc3ltYm9sKSA9PSAtMSkKICAgICAgICB7CiAgICAgICAgICAgIGkgKz0gMTsKICAgICAgICB9CiAgICAgICAgZWxzZQogICAgICAgIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgfQogICAgYXV0byByZXMgPSBpbnB1dFswIC4uIGldOwogICAgaW5wdXQgPSBpbnB1dFtpIC4uICRdOwogICAgcmV0dXJuIHJlczsKfQ==