#ifndef SCANNER_HPP
#define SCANNER_HPP
#include <cstdlib>
#include <stdexcept>
#include <tuple>
#include <type_traits>
template <typename T>
struct static_parser;
template <template <typename> class Parser = static_parser>
class scanner
{
const char* buf_;
public:
scanner(const char* over)
: buf_(over)
{
if (buf_ == 0) // gcc 5.1 doesn't know nullptr
throw std::logic_error("Invalid nullpointer");
}
template <typename T0>
T0 scan(const char* format)
{
auto r = scan_impl<T0>(format);
while (*buf_ && *format)
{
if (*format == '%' && *++format != '%')
{
throw std::runtime_error("Unexpected % in format string.");
}
if (*buf_++ != *format++)
throw std::runtime_error("Format string differs from buffer.");
}
if (*format)
throw std::runtime_error("Format string is longer than buffer.");
return r;
}
template <typename T0, typename T1>
std::tuple<T0, T1> scan(const char* format)
{
auto r0 = scan_impl<T0>(format);
return std::make_tuple(r0, scan<T1>(format));
}
template <typename T0, typename T1, typename T2>
std::tuple<T0, T1, T2> scan(const char* format)
{
auto r0 = scan_impl<T0>(format);
auto t = scan<T1, T2>(format);
return std::make_tuple(r0, std::get<0>(t), std::get<1>(t));
}
template <typename T0, typename T1, typename T2, typename T3>
std::tuple<T0, T1, T2, T3> scan(const char* format)
{
auto r0 = scan_impl<T0>(format);
auto t = scan<T1, T2, T3>(format);
return std::make_tuple(r0, std::get<0>(t), std::get<1>(t), std::get<2>(t));
}
template <typename T0, typename T1, typename T2, typename T3, typename T4>
std::tuple<T0, T1, T2, T3, T4> scan(const char* format)
{
auto r0 = scan_impl<T0>(format);
auto t = scan<T1, T2, T3, T4>(format);
return std::make_tuple(r0, std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
}
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
std::tuple<T0, T1, T2, T3, T4, T5> scan(const char* format)
{
auto r0 = scan_impl<T0>(format);
auto t = scan<T1, T2, T3, T4, T5>(format);
return std::make_tuple(r0, std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t), std::get<4>(t));
}
private:
template <typename T0>
T0 scan_impl(const char*& format)
{
while (*buf_ && *format)
{
if (*format == '%' && *++format != '%')
return Parser<T0>::parse(*this, buf_);
if (*buf_++ != *format++)
throw std::runtime_error("Unexpected character.");
}
throw std::runtime_error("Unexpected end.");
}
};
template <typename T>
struct static_parser
{
static T parse(scanner<>& s, const char*& buf)
{ // dummy so the compiler can only use static_assert if function is instanciated
const bool is_ = std::is_pod<T>::value;
const bool or_ = !std::is_pod<T>::value;
static_assert(is_ || or_, "No parsing function for this type.");
}
};
template <char C>
class delim
{
std::string data_;
public:
delim(std::string data)
: data_(std::move(data))
{}
operator std::string() const
{
return data_;
}
};
template <char C>
struct static_parser<delim<C>>
{
static delim<C> parse(scanner<>&, const char*& buf)
{
auto begin = buf;
while (*buf && *buf != C)
++buf;
return std::string(begin, buf);
}
};
template <>
std::string static_parser<std::string>::parse(scanner<>&, const char*& buf)
{
while (std::isspace(*buf))
++buf;
auto begin = buf;
while (*buf && !std::isspace(*buf))
++buf;
return std::string(begin, buf);
}
// Es fehlen noch: signed char, unsigned char, long long, unsigned long long, long double
template <>
char static_parser<char>::parse(scanner<>&, const char*& buf)
{
if (*buf != '\0')
return *buf++;
throw std::runtime_error("End of buffer found, could not parse character.");
}
template <>
long static_parser<long>::parse(scanner<>&, const char*& buf)
{
char* p;
auto r = std::strtol(buf, &p, 10);
if (r == 0 && p == buf)
throw std::runtime_error("Failed to parse long.");
buf = p;
return r;
}
template <>
unsigned long static_parser<unsigned long>::parse(scanner<>&, const char*& buf)
{
char* p;
auto r = std::strtoul(buf, &p, 10);
if (r == 0 && p == buf)
throw std::runtime_error("Failed to parse unsigned long.");
buf = p;
return r;
}
template <>
int static_parser<int>::parse(scanner<>& s, const char*& buf)
{ // Overflow?
return static_parser<long>::parse(s, buf);
}
template <>
unsigned static_parser<unsigned>::parse(scanner<>& s, const char*& buf)
{ // Overflow?
return static_parser<unsigned long>::parse(s, buf);
}
template <>
double static_parser<double>::parse(scanner<>&, const char*& buf)
{
char* p;
auto r = std::strtod(buf, &p);
if (r == 0.0 && p == buf)
throw std::runtime_error("Failed to parse double.");
buf = p;
return r;
}
template <>
float static_parser<float>::parse(scanner<>& s, const char*& buf)
{ // Overflow?
return static_cast<float>(static_parser<double>::parse(s, buf));
}
#endif
#include <iostream>
class person
{
std::string name_;
unsigned age_;
public:
person(std::string name, unsigned age)
: name_(std::move(name))
, age_(age)
{}
person(person&& p)
: name_(std::move(p.name_))
, age_(p.age_)
{}
const std::string& name() const
{
return name_;
}
unsigned age() const
{
return age_;
}
private:
person(const person&);
person& operator = (const person&);
};
template <>
person static_parser<person>::parse(scanner<>& s, const char*&)
{
auto t = s.scan<delim<'\n'>, int>("name: %""\nage: %\n");
return person(std::get<0>(t), std::get<1>(t));
}
int main()
{
try
{
scanner<> s("name: John Doe\n""age: 27\n");
auto p = s.scan<person>("%");
std::cout << "Hello, " << p.name() << '\n';
if (p.age() <= 30)
std::cout << "What? You are already " << p.age() << " years old? You look younger.\n";
else
std::cout << "What? You are only " << p.age() << " years old? You look older.\n";
}
catch (const std::runtime_error& e)
{
std::cerr << e.what() << '\n';
}
}
I2lmbmRlZiBTQ0FOTkVSX0hQUAojZGVmaW5lIFNDQU5ORVJfSFBQCgojaW5jbHVkZSA8Y3N0ZGxpYj4KI2luY2x1ZGUgPHN0ZGV4Y2VwdD4KI2luY2x1ZGUgPHR1cGxlPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4Kc3RydWN0IHN0YXRpY19wYXJzZXI7Cgp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHR5cGVuYW1lPiBjbGFzcyBQYXJzZXIgPSBzdGF0aWNfcGFyc2VyPgpjbGFzcyBzY2FubmVyCnsKICAgIGNvbnN0IGNoYXIqIGJ1Zl87CgpwdWJsaWM6CiAgICBzY2FubmVyKGNvbnN0IGNoYXIqIG92ZXIpCiAgICAgICAgOiBidWZfKG92ZXIpCiAgICB7CiAgICAgICAgaWYgKGJ1Zl8gPT0gMCkgLy8gIGdjYyA1LjEgZG9lc24ndCBrbm93IG51bGxwdHIKICAgICAgICAgICAgdGhyb3cgc3RkOjpsb2dpY19lcnJvcigiSW52YWxpZCBudWxscG9pbnRlciIpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUMD4KICAgIFQwIHNjYW4oY29uc3QgY2hhciogZm9ybWF0KQogICAgewogICAgICAgIGF1dG8gciA9IHNjYW5faW1wbDxUMD4oZm9ybWF0KTsKCiAgICAgICAgd2hpbGUgKCpidWZfICYmICpmb3JtYXQpCiAgICAgICAgewogICAgICAgICAgICBpZiAoKmZvcm1hdCA9PSAnJScgJiYgKisrZm9ybWF0ICE9ICclJykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJVbmV4cGVjdGVkICUgaW4gZm9ybWF0IHN0cmluZy4iKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKCpidWZfKysgIT0gKmZvcm1hdCsrKQogICAgICAgICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJGb3JtYXQgc3RyaW5nIGRpZmZlcnMgZnJvbSBidWZmZXIuIik7CiAgICAgICAgfQoKICAgICAgICBpZiAoKmZvcm1hdCkKICAgICAgICAgICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJGb3JtYXQgc3RyaW5nIGlzIGxvbmdlciB0aGFuIGJ1ZmZlci4iKTsKCiAgICAgICAgcmV0dXJuIHI7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFQwLCB0eXBlbmFtZSBUMT4KICAgIHN0ZDo6dHVwbGU8VDAsIFQxPiBzY2FuKGNvbnN0IGNoYXIqIGZvcm1hdCkKICAgIHsKICAgICAgICBhdXRvIHIwID0gc2Nhbl9pbXBsPFQwPihmb3JtYXQpOwogICAgICAgIHJldHVybiBzdGQ6Om1ha2VfdHVwbGUocjAsIHNjYW48VDE+KGZvcm1hdCkpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUMCwgdHlwZW5hbWUgVDEsIHR5cGVuYW1lIFQyPgogICAgc3RkOjp0dXBsZTxUMCwgVDEsIFQyPiBzY2FuKGNvbnN0IGNoYXIqIGZvcm1hdCkKICAgIHsKICAgICAgICBhdXRvIHIwID0gc2Nhbl9pbXBsPFQwPihmb3JtYXQpOwogICAgICAgIGF1dG8gdCA9IHNjYW48VDEsIFQyPihmb3JtYXQpOwogICAgICAgIHJldHVybiBzdGQ6Om1ha2VfdHVwbGUocjAsIHN0ZDo6Z2V0PDA+KHQpLCBzdGQ6OmdldDwxPih0KSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFQwLCB0eXBlbmFtZSBUMSwgdHlwZW5hbWUgVDIsIHR5cGVuYW1lIFQzPgogICAgc3RkOjp0dXBsZTxUMCwgVDEsIFQyLCBUMz4gc2Nhbihjb25zdCBjaGFyKiBmb3JtYXQpCiAgICB7CiAgICAgICAgYXV0byByMCA9IHNjYW5faW1wbDxUMD4oZm9ybWF0KTsKICAgICAgICBhdXRvIHQgPSBzY2FuPFQxLCBUMiwgVDM+KGZvcm1hdCk7CiAgICAgICAgcmV0dXJuIHN0ZDo6bWFrZV90dXBsZShyMCwgc3RkOjpnZXQ8MD4odCksIHN0ZDo6Z2V0PDE+KHQpLCBzdGQ6OmdldDwyPih0KSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFQwLCB0eXBlbmFtZSBUMSwgdHlwZW5hbWUgVDIsIHR5cGVuYW1lIFQzLCB0eXBlbmFtZSBUND4KICAgIHN0ZDo6dHVwbGU8VDAsIFQxLCBUMiwgVDMsIFQ0PiBzY2FuKGNvbnN0IGNoYXIqIGZvcm1hdCkKICAgIHsKICAgICAgICBhdXRvIHIwID0gc2Nhbl9pbXBsPFQwPihmb3JtYXQpOwogICAgICAgIGF1dG8gdCA9IHNjYW48VDEsIFQyLCBUMywgVDQ+KGZvcm1hdCk7CiAgICAgICAgcmV0dXJuIHN0ZDo6bWFrZV90dXBsZShyMCwgc3RkOjpnZXQ8MD4odCksIHN0ZDo6Z2V0PDE+KHQpLCBzdGQ6OmdldDwyPih0KSwgc3RkOjpnZXQ8Mz4odCkpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUMCwgdHlwZW5hbWUgVDEsIHR5cGVuYW1lIFQyLCB0eXBlbmFtZSBUMywgdHlwZW5hbWUgVDQsIHR5cGVuYW1lIFQ1PgogICAgc3RkOjp0dXBsZTxUMCwgVDEsIFQyLCBUMywgVDQsIFQ1PiBzY2FuKGNvbnN0IGNoYXIqIGZvcm1hdCkKICAgIHsKICAgICAgICBhdXRvIHIwID0gc2Nhbl9pbXBsPFQwPihmb3JtYXQpOwogICAgICAgIGF1dG8gdCA9IHNjYW48VDEsIFQyLCBUMywgVDQsIFQ1Pihmb3JtYXQpOwogICAgICAgIHJldHVybiBzdGQ6Om1ha2VfdHVwbGUocjAsIHN0ZDo6Z2V0PDA+KHQpLCBzdGQ6OmdldDwxPih0KSwgc3RkOjpnZXQ8Mj4odCksIHN0ZDo6Z2V0PDM+KHQpLCBzdGQ6OmdldDw0Pih0KSk7CiAgICB9Cgpwcml2YXRlOgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFQwPgogICAgVDAgc2Nhbl9pbXBsKGNvbnN0IGNoYXIqJiBmb3JtYXQpCiAgICB7CiAgICAgICAgd2hpbGUgKCpidWZfICYmICpmb3JtYXQpCiAgICAgICAgewogICAgICAgICAgICBpZiAoKmZvcm1hdCA9PSAnJScgJiYgKisrZm9ybWF0ICE9ICclJykKICAgICAgICAgICAgICAgIHJldHVybiBQYXJzZXI8VDA+OjpwYXJzZSgqdGhpcywgYnVmXyk7CgogICAgICAgICAgICBpZiAoKmJ1Zl8rKyAhPSAqZm9ybWF0KyspCiAgICAgICAgICAgICAgICB0aHJvdyBzdGQ6OnJ1bnRpbWVfZXJyb3IoIlVuZXhwZWN0ZWQgY2hhcmFjdGVyLiIpOwogICAgICAgIH0KICAgICAgICB0aHJvdyBzdGQ6OnJ1bnRpbWVfZXJyb3IoIlVuZXhwZWN0ZWQgZW5kLiIpOwogICAgfQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnN0cnVjdCBzdGF0aWNfcGFyc2VyCnsKICAgIHN0YXRpYyBUIHBhcnNlKHNjYW5uZXI8PiYgcywgY29uc3QgY2hhciomIGJ1ZikKICAgIHsgLy8gZHVtbXkgc28gdGhlIGNvbXBpbGVyIGNhbiBvbmx5IHVzZSBzdGF0aWNfYXNzZXJ0IGlmIGZ1bmN0aW9uIGlzIGluc3RhbmNpYXRlZAogICAgICAgIGNvbnN0IGJvb2wgaXNfID0gc3RkOjppc19wb2Q8VD46OnZhbHVlOwogICAgICAgIGNvbnN0IGJvb2wgb3JfID0gIXN0ZDo6aXNfcG9kPFQ+Ojp2YWx1ZTsKICAgICAgICBzdGF0aWNfYXNzZXJ0KGlzXyB8fCBvcl8sICJObyBwYXJzaW5nIGZ1bmN0aW9uIGZvciB0aGlzIHR5cGUuIik7CiAgICB9Cn07Cgp0ZW1wbGF0ZSA8Y2hhciBDPgpjbGFzcyBkZWxpbQp7CiAgICBzdGQ6OnN0cmluZyBkYXRhXzsKCnB1YmxpYzoKICAgIGRlbGltKHN0ZDo6c3RyaW5nIGRhdGEpCiAgICAgICAgOiBkYXRhXyhzdGQ6Om1vdmUoZGF0YSkpCiAgICB7fQoKICAgIG9wZXJhdG9yIHN0ZDo6c3RyaW5nKCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gZGF0YV87CiAgICB9Cn07Cgp0ZW1wbGF0ZSA8Y2hhciBDPgpzdHJ1Y3Qgc3RhdGljX3BhcnNlcjxkZWxpbTxDPj4KewogICAgc3RhdGljIGRlbGltPEM+IHBhcnNlKHNjYW5uZXI8PiYsIGNvbnN0IGNoYXIqJiBidWYpCiAgICB7CiAgICAgICAgYXV0byBiZWdpbiA9IGJ1ZjsKICAgICAgICB3aGlsZSAoKmJ1ZiAmJiAqYnVmICE9IEMpCiAgICAgICAgICAgICsrYnVmOwogICAgICAgIHJldHVybiBzdGQ6OnN0cmluZyhiZWdpbiwgYnVmKTsKICAgIH0KfTsKCnRlbXBsYXRlIDw+CnN0ZDo6c3RyaW5nIHN0YXRpY19wYXJzZXI8c3RkOjpzdHJpbmc+OjpwYXJzZShzY2FubmVyPD4mLCBjb25zdCBjaGFyKiYgYnVmKQp7CiAgICB3aGlsZSAoc3RkOjppc3NwYWNlKCpidWYpKQogICAgICAgICsrYnVmOwoKICAgIGF1dG8gYmVnaW4gPSBidWY7CiAgICB3aGlsZSAoKmJ1ZiAmJiAhc3RkOjppc3NwYWNlKCpidWYpKQogICAgICAgICsrYnVmOwoKICAgIHJldHVybiBzdGQ6OnN0cmluZyhiZWdpbiwgYnVmKTsKfQoKLy8gRXMgZmVobGVuIG5vY2g6IHNpZ25lZCBjaGFyLCB1bnNpZ25lZCBjaGFyLCBsb25nIGxvbmcsIHVuc2lnbmVkIGxvbmcgbG9uZywgbG9uZyBkb3VibGUKCnRlbXBsYXRlIDw+CmNoYXIgc3RhdGljX3BhcnNlcjxjaGFyPjo6cGFyc2Uoc2Nhbm5lcjw+JiwgY29uc3QgY2hhciomIGJ1ZikKewogICAgaWYgKCpidWYgIT0gJ1wwJykKICAgICAgICByZXR1cm4gKmJ1ZisrOwogICAgdGhyb3cgc3RkOjpydW50aW1lX2Vycm9yKCJFbmQgb2YgYnVmZmVyIGZvdW5kLCBjb3VsZCBub3QgcGFyc2UgY2hhcmFjdGVyLiIpOwp9Cgp0ZW1wbGF0ZSA8Pgpsb25nIHN0YXRpY19wYXJzZXI8bG9uZz46OnBhcnNlKHNjYW5uZXI8PiYsIGNvbnN0IGNoYXIqJiBidWYpCnsKICAgIGNoYXIqIHA7CiAgICBhdXRvIHIgPSBzdGQ6OnN0cnRvbChidWYsICZwLCAxMCk7CiAgICBpZiAociA9PSAwICYmIHAgPT0gYnVmKQogICAgICAgIHRocm93IHN0ZDo6cnVudGltZV9lcnJvcigiRmFpbGVkIHRvIHBhcnNlIGxvbmcuIik7CiAgICBidWYgPSBwOwogICAgcmV0dXJuIHI7Cn0KCnRlbXBsYXRlIDw+CnVuc2lnbmVkIGxvbmcgc3RhdGljX3BhcnNlcjx1bnNpZ25lZCBsb25nPjo6cGFyc2Uoc2Nhbm5lcjw+JiwgY29uc3QgY2hhciomIGJ1ZikKewogICAgY2hhciogcDsKICAgIGF1dG8gciA9IHN0ZDo6c3RydG91bChidWYsICZwLCAxMCk7CiAgICBpZiAociA9PSAwICYmIHAgPT0gYnVmKQogICAgICAgIHRocm93IHN0ZDo6cnVudGltZV9lcnJvcigiRmFpbGVkIHRvIHBhcnNlIHVuc2lnbmVkIGxvbmcuIik7CiAgICBidWYgPSBwOwogICAgcmV0dXJuIHI7Cn0KCnRlbXBsYXRlIDw+CmludCBzdGF0aWNfcGFyc2VyPGludD46OnBhcnNlKHNjYW5uZXI8PiYgcywgY29uc3QgY2hhciomIGJ1ZikKeyAvLyBPdmVyZmxvdz8KICAgIHJldHVybiBzdGF0aWNfcGFyc2VyPGxvbmc+OjpwYXJzZShzLCBidWYpOwp9Cgp0ZW1wbGF0ZSA8Pgp1bnNpZ25lZCBzdGF0aWNfcGFyc2VyPHVuc2lnbmVkPjo6cGFyc2Uoc2Nhbm5lcjw+JiBzLCBjb25zdCBjaGFyKiYgYnVmKQp7IC8vIE92ZXJmbG93PwogICAgcmV0dXJuIHN0YXRpY19wYXJzZXI8dW5zaWduZWQgbG9uZz46OnBhcnNlKHMsIGJ1Zik7Cn0KCnRlbXBsYXRlIDw+CmRvdWJsZSBzdGF0aWNfcGFyc2VyPGRvdWJsZT46OnBhcnNlKHNjYW5uZXI8PiYsIGNvbnN0IGNoYXIqJiBidWYpCnsKICAgIGNoYXIqIHA7CiAgICBhdXRvIHIgPSBzdGQ6OnN0cnRvZChidWYsICZwKTsKICAgIGlmIChyID09IDAuMCAmJiBwID09IGJ1ZikKICAgICAgICB0aHJvdyBzdGQ6OnJ1bnRpbWVfZXJyb3IoIkZhaWxlZCB0byBwYXJzZSBkb3VibGUuIik7CiAgICBidWYgPSBwOwogICAgcmV0dXJuIHI7Cn0KCnRlbXBsYXRlIDw+CmZsb2F0IHN0YXRpY19wYXJzZXI8ZmxvYXQ+OjpwYXJzZShzY2FubmVyPD4mIHMsIGNvbnN0IGNoYXIqJiBidWYpCnsgLy8gT3ZlcmZsb3c/CiAgICByZXR1cm4gc3RhdGljX2Nhc3Q8ZmxvYXQ+KHN0YXRpY19wYXJzZXI8ZG91YmxlPjo6cGFyc2UocywgYnVmKSk7Cn0KCiNlbmRpZgoKI2luY2x1ZGUgPGlvc3RyZWFtPgoKY2xhc3MgcGVyc29uCnsKICAgIHN0ZDo6c3RyaW5nIG5hbWVfOwogICAgdW5zaWduZWQgYWdlXzsKCnB1YmxpYzoKICAgIHBlcnNvbihzdGQ6OnN0cmluZyBuYW1lLCB1bnNpZ25lZCBhZ2UpCiAgICAgICAgOiBuYW1lXyhzdGQ6Om1vdmUobmFtZSkpCiAgICAgICAgLCBhZ2VfKGFnZSkKICAgIHt9CgogICAgcGVyc29uKHBlcnNvbiYmIHApCiAgICAgICAgOiBuYW1lXyhzdGQ6Om1vdmUocC5uYW1lXykpCiAgICAgICAgLCBhZ2VfKHAuYWdlXykKICAgIHt9CgogICAgY29uc3Qgc3RkOjpzdHJpbmcmIG5hbWUoKSBjb25zdAogICAgewogICAgICAgIHJldHVybiBuYW1lXzsKICAgIH0KCiAgICB1bnNpZ25lZCBhZ2UoKSBjb25zdAogICAgewogICAgICAgIHJldHVybiBhZ2VfOwogICAgfQoKcHJpdmF0ZToKICAgIHBlcnNvbihjb25zdCBwZXJzb24mKTsKICAgIHBlcnNvbiYgb3BlcmF0b3IgPSAoY29uc3QgcGVyc29uJik7Cn07CgoKdGVtcGxhdGUgPD4KcGVyc29uIHN0YXRpY19wYXJzZXI8cGVyc29uPjo6cGFyc2Uoc2Nhbm5lcjw+JiBzLCBjb25zdCBjaGFyKiYpCnsKICAgIGF1dG8gdCA9IHMuc2NhbjxkZWxpbTwnXG4nPiwgaW50PigibmFtZTogJSIiXG5hZ2U6ICVcbiIpOwogICAgcmV0dXJuIHBlcnNvbihzdGQ6OmdldDwwPih0KSwgc3RkOjpnZXQ8MT4odCkpOwp9CgppbnQgbWFpbigpCnsKICAgIHRyeQogICAgewogICAgICAgIHNjYW5uZXI8PiBzKCJuYW1lOiBKb2huIERvZVxuIiJhZ2U6IDI3XG4iKTsKICAgICAgICBhdXRvIHAgPSBzLnNjYW48cGVyc29uPigiJSIpOwogICAgICAgIHN0ZDo6Y291dCA8PCAiSGVsbG8sICIgPDwgcC5uYW1lKCkgPDwgJ1xuJzsKICAgICAgICBpZiAocC5hZ2UoKSA8PSAzMCkKICAgICAgICAgICAgc3RkOjpjb3V0IDw8ICJXaGF0PyBZb3UgYXJlIGFscmVhZHkgIiA8PCBwLmFnZSgpIDw8ICIgeWVhcnMgb2xkPyBZb3UgbG9vayB5b3VuZ2VyLlxuIjsKICAgICAgICBlbHNlCiAgICAgICAgICAgIHN0ZDo6Y291dCA8PCAiV2hhdD8gWW91IGFyZSBvbmx5ICIgPDwgcC5hZ2UoKSA8PCAiIHllYXJzIG9sZD8gWW91IGxvb2sgb2xkZXIuXG4iOwogICAgfQogICAgY2F0Y2ggKGNvbnN0IHN0ZDo6cnVudGltZV9lcnJvciYgZSkKICAgIHsKICAgICAgICBzdGQ6OmNlcnIgPDwgZS53aGF0KCkgPDwgJ1xuJzsKICAgIH0KfSA=