#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <stdexcept>
#include <map>
// Die ist ganz nützlich.
template<typename CharT,
typename Traits>
inline std::basic_string<CharT, Traits>& rtrim(std::basic_string<CharT, Traits>& s, std::ctype<CharT> const& facet)
{
s.erase( std::find_if(s.rbegin(), s.rend(), [&](CharT ch){ return !facet.is( std::ctype_base::space, ch ); }).base(), std::end(s) );
return s;
}
template<typename Exception = std::logic_error>
void Assert( bool b, std::string const& what = std::string() )
{
if(!b)
throw Exception(what);
}
template<typename CharT,
typename Traits,
typename Alloc>
inline std::basic_istream<CharT, Traits>& checked_getline( std::basic_istream<CharT, Traits>& is, std::basic_string<CharT, Traits, Alloc>& str, CharT delim, CharT NotAllowed )
{
typedef std::basic_istream<CharT, Traits> istream_t;
typedef std::basic_string<CharT, Traits, Alloc> string_t;
typename string_t::size_type extracted = 0;
const typename string_t::size_type max_size = str.max_size();
typename std::ios_base::iostate err = std::ios_base::goodbit;
typename istream_t::sentry sentry(is, true);
if (sentry)
try
{
str.erase();
const typename Traits::int_type eof = Traits::eof();
typename Traits::int_type ich = is.rdbuf()->sgetc();
#define BREAK_WITH(a,b) \
if( a ) \
{ \
b; \
break; \
}
while( extracted < max_size )
{
BREAK_WITH( Traits::eq_int_type(ich, eof),
err |= std::ios_base::eofbit )
auto ch = Traits::to_char_type(ich);
BREAK_WITH( Traits::eq(ch, delim),
(++extracted, is.rdbuf()->sbumpc()) )
BREAK_WITH( Traits::eq(ch, NotAllowed),
err |= std::ios_base::failbit )
str += ch;
++extracted;
ich = is.rdbuf()->snextc();
}
}
catch(...)
{
is.setstate(std::ios_base::badbit);
}
if (extracted == 0)
err |= std::ios_base::failbit;
if (err != std::ios_base::goodbit)
is.setstate(err);
return is;
}
#include <memory>
template<typename CharT,
typename Traits = std::char_traits<CharT>,
typename ValueT = std::basic_string<CharT, Traits> >
struct Node
{
typedef CharT char_type;
typedef Traits traits_type;
typedef std::basic_string<CharT, Traits> key_type;
typedef ValueT value_type;
std::basic_string<CharT, Traits> const name;
Node( std::basic_string<CharT, Traits> const& name = "Root" ):
name(name) {}
std::map<key_type, value_type> entries;
std::vector<std::shared_ptr<Node>> child_nodes; // Darf *nicht* verändert werden - Inhalt wird gelöscht
};
template<typename CharT,
typename Traits>
std::basic_istream<CharT, Traits>& ws_facet(std::basic_istream<CharT, Traits>& is, std::ctype<CharT> const& facet)
{
typename std::basic_istream<CharT, Traits>::sentry sentry(is, true);
if( sentry )
{
typename Traits::int_type const eof = Traits::eof();
typename Traits::int_type ch = is.rdbuf()->sgetc();
while( !Traits::eq_int_type(ch, eof)
&& facet.is( std::ctype_base::space, Traits::to_char_type(ch) ) )
ch = is.rdbuf()->snextc();
if( Traits::eq_int_type(ch, eof) )
is.setstate( std::ios_base::eofbit );
}
return is;
}
template<typename CharT,
typename Traits,
typename ValueT>
std::basic_istream<CharT, Traits>& operator>>( std::basic_istream<CharT, Traits>& is, Node<CharT, Traits, ValueT>& node )
{
typedef std::basic_string<CharT, Traits> string_t;
typedef Node<CharT, Traits, ValueT> node_t;
auto const& ctype_facet = std::use_facet<std::ctype<CharT>>( is.getloc() );
typename Traits::int_type const open_brace = Traits::to_int_type(ctype_facet.widen('[')),
comment_char = Traits::to_int_type(ctype_facet.widen('#')),
forward_slash = Traits::to_int_type(ctype_facet.widen('/'));
CharT const separator = ctype_facet.widen('='),
close_brace = ctype_facet.widen(']'),
newline = ctype_facet.widen('\n');
while( ws_facet(is, ctype_facet).good() )
{
typename Traits::int_type ch = is.rdbuf()->sgetc();
if( Traits::eq_int_type(ch, comment_char) )
is.ignore( std::numeric_limits<std::streamsize>::max(), newline );
else if( Traits::eq_int_type(ch, open_brace) ) /// Entweder eine neue Node wird eingeleitet, oder diese wird geschlossen ( [/...] )
{
ws_facet(is.ignore(), ctype_facet);
if( Traits::eq_int_type(is.rdbuf()->sgetc(), forward_slash) )
{
ws_facet(is.ignore(), ctype_facet);
for( auto const& c : node.name )
Assert( Traits::eq_int_type( is.rdbuf()->sbumpc(), Traits::to_int_type(c) ), "Invalid closing tag!" );
ws_facet(is, ctype_facet);
Assert( Traits::eq_int_type( is.rdbuf()->sbumpc(), Traits::to_int_type(close_brace) ), "Missing ']' character at closing tag!" );
break; /// Beenden.
}
else // Eine neue, verschachtelte Node
{
string_t name;
checked_getline( is, name, close_brace, newline );
Assert( is.good(), "Invalid syntax in node title!" );
Assert( !rtrim(name, ctype_facet).empty(), "Empty node title!" );
node.child_nodes.push_back( std::shared_ptr<node_t>{new node_t{name}} );
Assert( is >> *node.child_nodes.back(), "Error while parsing sub-node!" );
}
}
else /// Eine Key-Value zuweisung
{
std::pair<string_t, ValueT> pair;
checked_getline( is, pair.first, separator, newline );
Assert( is.good(), "Invalid syntax in key-value assignment!" );
Assert( !rtrim(pair.first, ctype_facet).empty(), "Empty key!" );
Assert( is >> pair.second, "Error while reading value type!" ); /// Hier wird der value eingelesen.
node.entries.insert( std::move(pair) );
}
}
return is;
}
#include <sstream>
int main()
{
std::istringstream stream{
R"(
[Schurke]
Str=12
Dex= 17
Int=4
[/Schurke]
[Krieger]
Str=18
Dex=10
Int=2
[/Krieger]
)" };
Node<char> node;
stream >> node;
for( auto sub_node : node.child_nodes )
{
std::cout << "Name: " << sub_node->name << '\n';
for( auto const& pair : sub_node->entries )
std::cout << pair.first << " : " << pair.second << '\n';
}
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8YWxnb3JpdGhtPgojaW5jbHVkZSA8ZnVuY3Rpb25hbD4KI2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPHN0ZGV4Y2VwdD4KI2luY2x1ZGUgPG1hcD4KCi8vIERpZSBpc3QgZ2FueiBuw7x0emxpY2guCnRlbXBsYXRlPHR5cGVuYW1lIENoYXJULAogICAgICAgICB0eXBlbmFtZSBUcmFpdHM+CmlubGluZSBzdGQ6OmJhc2ljX3N0cmluZzxDaGFyVCwgVHJhaXRzPiYgcnRyaW0oc3RkOjpiYXNpY19zdHJpbmc8Q2hhclQsIFRyYWl0cz4mIHMsIHN0ZDo6Y3R5cGU8Q2hhclQ+IGNvbnN0JiBmYWNldCkKewogICAgcy5lcmFzZSggc3RkOjpmaW5kX2lmKHMucmJlZ2luKCksIHMucmVuZCgpLCBbJl0oQ2hhclQgY2gpeyByZXR1cm4gIWZhY2V0LmlzKCBzdGQ6OmN0eXBlX2Jhc2U6OnNwYWNlLCBjaCApOyB9KS5iYXNlKCksIHN0ZDo6ZW5kKHMpICk7CiAgICByZXR1cm4gczsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgRXhjZXB0aW9uID0gc3RkOjpsb2dpY19lcnJvcj4Kdm9pZCBBc3NlcnQoIGJvb2wgYiwgc3RkOjpzdHJpbmcgY29uc3QmIHdoYXQgPSBzdGQ6OnN0cmluZygpICkKewogICAgaWYoIWIpCiAgICAgICAgdGhyb3cgRXhjZXB0aW9uKHdoYXQpOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBDaGFyVCwKICAgICAgICAgdHlwZW5hbWUgVHJhaXRzLAogICAgICAgICB0eXBlbmFtZSBBbGxvYz4KaW5saW5lIHN0ZDo6YmFzaWNfaXN0cmVhbTxDaGFyVCwgVHJhaXRzPiYgY2hlY2tlZF9nZXRsaW5lKCBzdGQ6OmJhc2ljX2lzdHJlYW08Q2hhclQsIFRyYWl0cz4mIGlzLCBzdGQ6OmJhc2ljX3N0cmluZzxDaGFyVCwgVHJhaXRzLCBBbGxvYz4mIHN0ciwgQ2hhclQgZGVsaW0sIENoYXJUIE5vdEFsbG93ZWQgKQp7CiAgICB0eXBlZGVmIHN0ZDo6YmFzaWNfaXN0cmVhbTxDaGFyVCwgVHJhaXRzPiBpc3RyZWFtX3Q7Cgl0eXBlZGVmIHN0ZDo6YmFzaWNfc3RyaW5nPENoYXJULCBUcmFpdHMsIEFsbG9jPiBzdHJpbmdfdDsKCgl0eXBlbmFtZSBzdHJpbmdfdDo6c2l6ZV90eXBlIGV4dHJhY3RlZCA9IDA7Cgljb25zdCB0eXBlbmFtZSBzdHJpbmdfdDo6c2l6ZV90eXBlIG1heF9zaXplID0gc3RyLm1heF9zaXplKCk7CgoJdHlwZW5hbWUgc3RkOjppb3NfYmFzZTo6aW9zdGF0ZSBlcnIgPSBzdGQ6Omlvc19iYXNlOjpnb29kYml0OwoJdHlwZW5hbWUgaXN0cmVhbV90OjpzZW50cnkgc2VudHJ5KGlzLCB0cnVlKTsKCglpZiAoc2VudHJ5KQoJCXRyeQoJCXsKCQkJc3RyLmVyYXNlKCk7CgoJCQljb25zdCB0eXBlbmFtZSBUcmFpdHM6OmludF90eXBlIGVvZiA9IFRyYWl0czo6ZW9mKCk7CgoJCQl0eXBlbmFtZSBUcmFpdHM6OmludF90eXBlIGljaCA9IGlzLnJkYnVmKCktPnNnZXRjKCk7CgoJCQkjZGVmaW5lIEJSRUFLX1dJVEgoYSxiKSBcCgkJCQlpZiggYSApIFwKCQkJCXsgXAoJCQkJCWI7IFwKCQkJCQlicmVhazsgXAoJCQkJfQoKCQkJd2hpbGUoIGV4dHJhY3RlZCA8IG1heF9zaXplICkKCQkJewoJCQkJQlJFQUtfV0lUSCggVHJhaXRzOjplcV9pbnRfdHlwZShpY2gsIGVvZiksCgkJCQkJICAgICAgICBlcnIgfD0gc3RkOjppb3NfYmFzZTo6ZW9mYml0ICkKCgkJCQlhdXRvIGNoID0gVHJhaXRzOjp0b19jaGFyX3R5cGUoaWNoKTsKCgkJCQlCUkVBS19XSVRIKCBUcmFpdHM6OmVxKGNoLCBkZWxpbSksCgkJCQkJICAgICAgICAoKytleHRyYWN0ZWQsIGlzLnJkYnVmKCktPnNidW1wYygpKSApCgoJCQkJQlJFQUtfV0lUSCggVHJhaXRzOjplcShjaCwgTm90QWxsb3dlZCksCgkJCQkJICAgICAgICBlcnIgfD0gc3RkOjppb3NfYmFzZTo6ZmFpbGJpdCApCgoJCQkJc3RyICs9IGNoOwoKCQkJCSsrZXh0cmFjdGVkOwoKCQkJCWljaCA9IGlzLnJkYnVmKCktPnNuZXh0YygpOwoJCQl9CgkJfQoJCWNhdGNoKC4uLikKCQl7CgkJCWlzLnNldHN0YXRlKHN0ZDo6aW9zX2Jhc2U6OmJhZGJpdCk7CgkJfQoKCglpZiAoZXh0cmFjdGVkID09IDApCgkJZXJyIHw9IHN0ZDo6aW9zX2Jhc2U6OmZhaWxiaXQ7CgoJaWYgKGVyciAhPSBzdGQ6Omlvc19iYXNlOjpnb29kYml0KQoJCWlzLnNldHN0YXRlKGVycik7CgoJcmV0dXJuIGlzOwp9CgojaW5jbHVkZSA8bWVtb3J5PgoKdGVtcGxhdGU8dHlwZW5hbWUgQ2hhclQsCiAgICAgICAgIHR5cGVuYW1lIFRyYWl0cyA9IHN0ZDo6Y2hhcl90cmFpdHM8Q2hhclQ+LAogICAgICAgICB0eXBlbmFtZSBWYWx1ZVQgPSBzdGQ6OmJhc2ljX3N0cmluZzxDaGFyVCwgVHJhaXRzPiA+CnN0cnVjdCBOb2RlCnsKICAgIHR5cGVkZWYgQ2hhclQgY2hhcl90eXBlOwogICAgdHlwZWRlZiBUcmFpdHMgdHJhaXRzX3R5cGU7CgogICAgdHlwZWRlZiBzdGQ6OmJhc2ljX3N0cmluZzxDaGFyVCwgVHJhaXRzPiBrZXlfdHlwZTsKICAgIHR5cGVkZWYgVmFsdWVUIHZhbHVlX3R5cGU7CgogICAgc3RkOjpiYXNpY19zdHJpbmc8Q2hhclQsIFRyYWl0cz4gY29uc3QgbmFtZTsKCiAgICBOb2RlKCBzdGQ6OmJhc2ljX3N0cmluZzxDaGFyVCwgVHJhaXRzPiBjb25zdCYgbmFtZSA9ICJSb290IiApOgogICAgICAgIG5hbWUobmFtZSkge30KCiAgICBzdGQ6Om1hcDxrZXlfdHlwZSwgdmFsdWVfdHlwZT4gZW50cmllczsKCiAgICBzdGQ6OnZlY3RvcjxzdGQ6OnNoYXJlZF9wdHI8Tm9kZT4+IGNoaWxkX25vZGVzOyAvLyBEYXJmICpuaWNodCogdmVyw6RuZGVydCB3ZXJkZW4gLSBJbmhhbHQgd2lyZCBnZWzDtnNjaHQKfTsKCnRlbXBsYXRlPHR5cGVuYW1lIENoYXJULAogICAgICAgICB0eXBlbmFtZSBUcmFpdHM+CnN0ZDo6YmFzaWNfaXN0cmVhbTxDaGFyVCwgVHJhaXRzPiYgd3NfZmFjZXQoc3RkOjpiYXNpY19pc3RyZWFtPENoYXJULCBUcmFpdHM+JiBpcywgc3RkOjpjdHlwZTxDaGFyVD4gY29uc3QmIGZhY2V0KQp7Cgl0eXBlbmFtZSBzdGQ6OmJhc2ljX2lzdHJlYW08Q2hhclQsIFRyYWl0cz46OnNlbnRyeSBzZW50cnkoaXMsIHRydWUpOwoKCWlmKCBzZW50cnkgKQoJewoJCXR5cGVuYW1lIFRyYWl0czo6aW50X3R5cGUgY29uc3QgZW9mID0gVHJhaXRzOjplb2YoKTsKCgkJdHlwZW5hbWUgVHJhaXRzOjppbnRfdHlwZSBjaCA9IGlzLnJkYnVmKCktPnNnZXRjKCk7CgoJCXdoaWxlKCAhVHJhaXRzOjplcV9pbnRfdHlwZShjaCwgZW9mKQoJCQkmJiBmYWNldC5pcyggc3RkOjpjdHlwZV9iYXNlOjpzcGFjZSwgVHJhaXRzOjp0b19jaGFyX3R5cGUoY2gpICkgKQoJCQljaCA9IGlzLnJkYnVmKCktPnNuZXh0YygpOwoKCQlpZiggVHJhaXRzOjplcV9pbnRfdHlwZShjaCwgZW9mKSApCgkJCWlzLnNldHN0YXRlKCBzdGQ6Omlvc19iYXNlOjplb2ZiaXQgKTsKCX0KCglyZXR1cm4gaXM7Cn0KCnRlbXBsYXRlPHR5cGVuYW1lIENoYXJULAogICAgICAgICB0eXBlbmFtZSBUcmFpdHMsCiAgICAgICAgIHR5cGVuYW1lIFZhbHVlVD4Kc3RkOjpiYXNpY19pc3RyZWFtPENoYXJULCBUcmFpdHM+JiBvcGVyYXRvcj4+KCBzdGQ6OmJhc2ljX2lzdHJlYW08Q2hhclQsIFRyYWl0cz4mIGlzLCBOb2RlPENoYXJULCBUcmFpdHMsIFZhbHVlVD4mIG5vZGUgKQp7CiAgICB0eXBlZGVmIHN0ZDo6YmFzaWNfc3RyaW5nPENoYXJULCBUcmFpdHM+IHN0cmluZ190OwoKICAgIHR5cGVkZWYgTm9kZTxDaGFyVCwgVHJhaXRzLCBWYWx1ZVQ+IG5vZGVfdDsKCglhdXRvIGNvbnN0JiBjdHlwZV9mYWNldCA9IHN0ZDo6dXNlX2ZhY2V0PHN0ZDo6Y3R5cGU8Q2hhclQ+PiggaXMuZ2V0bG9jKCkgKTsKCgl0eXBlbmFtZSBUcmFpdHM6OmludF90eXBlIGNvbnN0IG9wZW5fYnJhY2UgPSBUcmFpdHM6OnRvX2ludF90eXBlKGN0eXBlX2ZhY2V0LndpZGVuKCdbJykpLAoJICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tZW50X2NoYXIgPSBUcmFpdHM6OnRvX2ludF90eXBlKGN0eXBlX2ZhY2V0LndpZGVuKCcjJykpLAoJICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3J3YXJkX3NsYXNoID0gVHJhaXRzOjp0b19pbnRfdHlwZShjdHlwZV9mYWNldC53aWRlbignLycpKTsKCiAgICBDaGFyVCBjb25zdCBzZXBhcmF0b3IgPSBjdHlwZV9mYWNldC53aWRlbignPScpLAogICAgICAgICAgICAgICAgY2xvc2VfYnJhY2UgPSBjdHlwZV9mYWNldC53aWRlbignXScpLAogICAgICAgICAgICAgICAgbmV3bGluZSA9IGN0eXBlX2ZhY2V0LndpZGVuKCdcbicpOwoKICAgIHdoaWxlKCB3c19mYWNldChpcywgY3R5cGVfZmFjZXQpLmdvb2QoKSApCiAgICB7CiAgICAJdHlwZW5hbWUgVHJhaXRzOjppbnRfdHlwZSBjaCA9IGlzLnJkYnVmKCktPnNnZXRjKCk7CgogICAgICAgIGlmKCBUcmFpdHM6OmVxX2ludF90eXBlKGNoLCBjb21tZW50X2NoYXIpICkKICAgICAgICAgICAgaXMuaWdub3JlKCBzdGQ6Om51bWVyaWNfbGltaXRzPHN0ZDo6c3RyZWFtc2l6ZT46Om1heCgpLCBuZXdsaW5lICk7CgogICAgICAgIGVsc2UgaWYoIFRyYWl0czo6ZXFfaW50X3R5cGUoY2gsIG9wZW5fYnJhY2UpICkgLy8vIEVudHdlZGVyIGVpbmUgbmV1ZSBOb2RlIHdpcmQgZWluZ2VsZWl0ZXQsIG9kZXIgZGllc2Ugd2lyZCBnZXNjaGxvc3NlbiAoIFsvLi4uXSApCiAgICAgICAgewogICAgICAgIAl3c19mYWNldChpcy5pZ25vcmUoKSwgY3R5cGVfZmFjZXQpOwoKICAgICAgICAgICAgaWYoIFRyYWl0czo6ZXFfaW50X3R5cGUoaXMucmRidWYoKS0+c2dldGMoKSwgZm9yd2FyZF9zbGFzaCkgKQogICAgICAgICAgICB7CgkJCQl3c19mYWNldChpcy5pZ25vcmUoKSwgY3R5cGVfZmFjZXQpOwoKICAgICAgICAgICAgICAgIGZvciggYXV0byBjb25zdCYgYyA6IG5vZGUubmFtZSApCiAgICAgICAgICAgICAgICAgICAgQXNzZXJ0KCBUcmFpdHM6OmVxX2ludF90eXBlKCBpcy5yZGJ1ZigpLT5zYnVtcGMoKSwgVHJhaXRzOjp0b19pbnRfdHlwZShjKSApLCAiSW52YWxpZCBjbG9zaW5nIHRhZyEiICk7CgogICAgICAgICAgICAgICAgd3NfZmFjZXQoaXMsIGN0eXBlX2ZhY2V0KTsKCiAgICAgICAgICAgICAgICBBc3NlcnQoIFRyYWl0czo6ZXFfaW50X3R5cGUoIGlzLnJkYnVmKCktPnNidW1wYygpLCBUcmFpdHM6OnRvX2ludF90eXBlKGNsb3NlX2JyYWNlKSApLCAiTWlzc2luZyAnXScgY2hhcmFjdGVyIGF0IGNsb3NpbmcgdGFnISIgKTsKCiAgICAgICAgICAgICAgICBicmVhazsgLy8vIEJlZW5kZW4uCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSAvLyBFaW5lIG5ldWUsIHZlcnNjaGFjaHRlbHRlIE5vZGUKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgc3RyaW5nX3QgbmFtZTsKCiAgICAgICAgICAgICAgICBjaGVja2VkX2dldGxpbmUoIGlzLCBuYW1lLCBjbG9zZV9icmFjZSwgbmV3bGluZSApOwoKICAgICAgICAgICAgICAgIEFzc2VydCggaXMuZ29vZCgpLCAiSW52YWxpZCBzeW50YXggaW4gbm9kZSB0aXRsZSEiICk7CgogICAgICAgICAgICAgICAgQXNzZXJ0KCAhcnRyaW0obmFtZSwgY3R5cGVfZmFjZXQpLmVtcHR5KCksICJFbXB0eSBub2RlIHRpdGxlISIgKTsKCiAgICAgICAgICAgICAgICBub2RlLmNoaWxkX25vZGVzLnB1c2hfYmFjayggc3RkOjpzaGFyZWRfcHRyPG5vZGVfdD57bmV3IG5vZGVfdHtuYW1lfX0gKTsKCiAgICAgICAgICAgICAgICBBc3NlcnQoIGlzID4+ICpub2RlLmNoaWxkX25vZGVzLmJhY2soKSwgIkVycm9yIHdoaWxlIHBhcnNpbmcgc3ViLW5vZGUhIiApOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGVsc2UgLy8vIEVpbmUgS2V5LVZhbHVlIHp1d2Vpc3VuZwogICAgICAgIHsKICAgICAgICAgICAgc3RkOjpwYWlyPHN0cmluZ190LCBWYWx1ZVQ+IHBhaXI7CgogICAgICAgICAgICBjaGVja2VkX2dldGxpbmUoIGlzLCBwYWlyLmZpcnN0LCBzZXBhcmF0b3IsIG5ld2xpbmUgKTsKCgkJCUFzc2VydCggaXMuZ29vZCgpLCAiSW52YWxpZCBzeW50YXggaW4ga2V5LXZhbHVlIGFzc2lnbm1lbnQhIiApOwoKICAgICAgICAgICAgQXNzZXJ0KCAhcnRyaW0ocGFpci5maXJzdCwgY3R5cGVfZmFjZXQpLmVtcHR5KCksICJFbXB0eSBrZXkhIiApOwoKICAgICAgICAgICAgQXNzZXJ0KCBpcyA+PiBwYWlyLnNlY29uZCwgIkVycm9yIHdoaWxlIHJlYWRpbmcgdmFsdWUgdHlwZSEiICk7IC8vLyBIaWVyIHdpcmQgZGVyIHZhbHVlIGVpbmdlbGVzZW4uCgogICAgICAgICAgICBub2RlLmVudHJpZXMuaW5zZXJ0KCBzdGQ6Om1vdmUocGFpcikgKTsKICAgICAgICB9CiAgICB9CgogICAgcmV0dXJuIGlzOwp9CgojaW5jbHVkZSA8c3N0cmVhbT4KCmludCBtYWluKCkKewogICAgc3RkOjppc3RyaW5nc3RyZWFtIHN0cmVhbXsKUiIoCltTY2h1cmtlXQpTdHI9MTIKRGV4PSAxNwpJbnQ9NApbL1NjaHVya2VdCgpbS3JpZWdlcl0KU3RyPTE4CkRleD0xMApJbnQ9MgpbL0tyaWVnZXJdCikiIH07CgogICAgTm9kZTxjaGFyPiBub2RlOwogICAgc3RyZWFtID4+IG5vZGU7CgogICAgZm9yKCBhdXRvIHN1Yl9ub2RlIDogbm9kZS5jaGlsZF9ub2RlcyApCiAgICB7CiAgICAgICAgc3RkOjpjb3V0IDw8ICJOYW1lOiAiIDw8IHN1Yl9ub2RlLT5uYW1lIDw8ICdcbic7CiAgICAgICAgZm9yKCBhdXRvIGNvbnN0JiBwYWlyIDogc3ViX25vZGUtPmVudHJpZXMgKQogICAgICAgICAgICBzdGQ6OmNvdXQgPDwgcGFpci5maXJzdCA8PCAiIDogIiA8PCBwYWlyLnNlY29uZCA8PCAnXG4nOwogICAgfQp9Cg==