#include <cstring>
#include <stdexcept>
#include <type_traits>
namespace tmp
{
template <typename T>
struct identity
{
typedef T type;
};
template <typename T, T V>
struct constant
{
static constexpr T value = V;
};
template <bool B>
struct bool_ : constant<bool, B>
{};
template <typename First, typename Second>
struct tpair
{};
template <typename Pair>
struct first;
template <typename First, typename Second>
struct first<tpair<First, Second>> : identity<First>
{};
template <typename Pair>
struct second;
template <typename First, typename Second>
struct second<tpair<First, Second>> : identity<Second>
{};
template <char... S>
struct tstring
{};
template <typename S>
struct c_str;
template <char... S>
struct c_str<tstring<S...>>
{
static char const value[];
};
template <char... S>
char const c_str<tstring<S...>>::value[] = { S..., 0 };
template <typename... List>
struct tlist : identity<tlist<List...>>
{};
template <typename List>
struct empty : bool_<false>
{};
template <>
struct empty<tlist<>> : bool_<true>
{};
template <typename T, typename List>
struct push_front;
template <typename T, typename... List>
struct push_front<T, tlist<List...>>
: tlist<T, List...>
{};
template <typename List>
struct pop_front;
template <typename Head, typename... Tail>
struct pop_front<tlist<Head, Tail...>>
: tlist<Tail...>
{};
template <typename List>
struct front;
template <typename Head, typename... Tail>
struct front<tlist<Head, Tail...>> : identity<Head>
{};
template
<
typename T,
typename List,
template <typename, typename> class Less
>
struct insert_sorted;
template
<
typename T,
template <typename, typename> class Less
>
struct insert_sorted<T, tlist<>, Less>
: tlist<T>
{};
template
<
typename T,
typename Head, typename... Tail,
template <typename, typename> class Less
>
struct insert_sorted<T, tlist<Head, Tail...>, Less>
: std::conditional
<
Less<T, Head>::value,
tlist<T, Head, Tail...>,
typename push_front<Head, typename insert_sorted<T, tlist<Tail...>, Less>::type>::type
>::type
{};
template
<
template <typename, typename> class Less,
typename List
>
struct sort;
template
<
template <typename, typename> class Less
>
struct sort<Less, tlist<>>
: tlist<>
{};
template
<
template <typename, typename> class Less,
typename Head, typename... Tail
>
struct sort<Less, tlist<Head, Tail...>>
: insert_sorted<Head, typename sort<Less, tlist<Tail...>>::type, Less>
{};
template <typename S1, typename S2>
struct string_less;
template <>
struct string_less<tstring<>, tstring<>>
: bool_<false>
{};
template <char... S>
struct string_less<tstring<S...>, tstring<>>
: bool_<false>
{};
template <char... S>
struct string_less<tstring<>, tstring<S...>>
: bool_<true>
{};
template <char Head1, char... Tail1, char Head2, char... Tail2>
struct string_less<tstring<Head1, Tail1...>, tstring<Head2, Tail2...>>
: bool_
<
Head1 == Head2
? string_less<tstring<Tail1...>, tstring<Tail2...>>::value
: (Head1 < Head2)
>
{};
template <typename Pair1, typename Pair2>
struct pair_less;
template <typename Enum1, typename String1, typename Enum2, typename String2>
struct pair_less<tpair<Enum1, String1>, tpair<Enum2, String2>>
: string_less<String1, String2>
{};
template <unsigned N, typename List>
struct take_n;
template <>
struct take_n<0, tlist<>>
{
typedef tlist<> left;
typedef tlist<> right;
};
template <typename Head, typename... Tail>
struct take_n<0, tlist<Head, Tail...>>
{
typedef tlist<> left;
typedef tlist<Head, Tail...> right;
};
template <unsigned N, typename Head, typename... Tail>
class take_n<N, tlist<Head, Tail...>>
{
typedef take_n<N - 1, tlist<Tail...>> recurse;
public:
typedef typename push_front<Head, typename recurse::left>::type left;
typedef typename recurse::right right;
};
template <typename List>
struct cut_half_with_median;
template <typename... List>
class cut_half_with_median<tlist<List...>>
{
typedef take_n<sizeof...(List) / 2, tlist<List...>> left_without_median;
typedef take_n<1, typename left_without_median::right> median_with_right;
public:
typedef typename left_without_median::left left;
typedef typename front<typename median_with_right::left>::type median;
typedef typename median_with_right::right right;
};
template <typename Enum, typename Mappings>
class decision_tree
{
typedef cut_half_with_median<Mappings> cut;
typedef typename cut::median median;
Enum not_found(std::string const& value) const
{
throw std::invalid_argument{ "string '" + value + "' has no enum value" };
}
Enum less(char const* value, bool_<true>) const
{
return not_found(value);
}
Enum less(char const* value, bool_<false>) const
{
return decision_tree<Enum, typename cut::left>()(value);
}
Enum greater(char const* value, bool_<true>) const
{
return not_found(value);
}
Enum greater(char const* value, bool_<false>) const
{
return decision_tree<Enum, typename cut::right>()(value);
}
public:
Enum operator () (char const* value) const
{
auto cmp = std::strcmp(value, c_str<typename second<median>::type>::value);
if(cmp < 0)
return less(value, bool_<empty<typename cut::left>::value>());
if(cmp > 0)
return greater(value, bool_<empty<typename cut::right>::value>());
return first<median>::type::value;
}
};
template <typename Enum, typename... Mappings>
struct enum_mapper;
template <typename Enum, typename... Strings, Enum... Values>
class enum_mapper<Enum, tpair<constant<Enum, Values>, Strings>...>
{
typedef tlist<tpair<constant<Enum, Values>, Strings>...> mappings;
typedef typename sort<pair_less, mappings>::type sorted_mappings;
public:
Enum operator () (char const* value) const
{
return decision_tree<Enum, sorted_mappings>()(value);
}
};
}
#define EMAP(E, ...) tmp::tpair<tmp::constant<decltype(E), E>, tmp::tstring<__VA_ARGS__>>
////////////////////////////////////////////////////////////////
#include <iostream>
enum struct my_enum : unsigned
{
foo,
bar,
baz,
qux,
};
std::ostream& operator << (std::ostream& os, my_enum e)
{
static char const* const table[] = { "foo", "bar", "baz", "qux" };
return os << table[static_cast<unsigned>(e)];
}
int main()
{
typedef tmp::enum_mapper
<
my_enum,
EMAP(my_enum::baz, 'b','a','z'),
EMAP(my_enum::bar, 'b','a','r'),
EMAP(my_enum::foo, 'f','o','o'),
EMAP(my_enum::qux, 'q','u','x')
> my_enum_mapper;
my_enum_mapper mapper;
std::cout << mapper("foo") << '\n';
std::cout << mapper("bar") << '\n';
std::cout << mapper("baz") << '\n';
std::cout << mapper("qux") << '\n';
try
{
std::cout << mapper("garbage") << '\n';
}
catch(std::invalid_argument const& iv)
{
std::cout << iv.what() << '\n';
}
}
I2luY2x1ZGUgPGNzdHJpbmc+CiNpbmNsdWRlIDxzdGRleGNlcHQ+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KCm5hbWVzcGFjZSB0bXAKewoJdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CglzdHJ1Y3QgaWRlbnRpdHkKCXsKCQl0eXBlZGVmIFQgdHlwZTsKCX07CgoJdGVtcGxhdGUgPHR5cGVuYW1lIFQsIFQgVj4KCXN0cnVjdCBjb25zdGFudAoJewoJCXN0YXRpYyBjb25zdGV4cHIgVCB2YWx1ZSA9IFY7Cgl9OwoKCXRlbXBsYXRlIDxib29sIEI+CglzdHJ1Y3QgYm9vbF8gOiBjb25zdGFudDxib29sLCBCPgoJe307CgoJdGVtcGxhdGUgPHR5cGVuYW1lIEZpcnN0LCB0eXBlbmFtZSBTZWNvbmQ+CglzdHJ1Y3QgdHBhaXIKCXt9OwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBQYWlyPgoJc3RydWN0IGZpcnN0OwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBGaXJzdCwgdHlwZW5hbWUgU2Vjb25kPgoJc3RydWN0IGZpcnN0PHRwYWlyPEZpcnN0LCBTZWNvbmQ+PiA6IGlkZW50aXR5PEZpcnN0PgoJe307CgoJdGVtcGxhdGUgPHR5cGVuYW1lIFBhaXI+CglzdHJ1Y3Qgc2Vjb25kOwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBGaXJzdCwgdHlwZW5hbWUgU2Vjb25kPgoJc3RydWN0IHNlY29uZDx0cGFpcjxGaXJzdCwgU2Vjb25kPj4gOiBpZGVudGl0eTxTZWNvbmQ+Cgl7fTsKCgl0ZW1wbGF0ZSA8Y2hhci4uLiBTPgoJc3RydWN0IHRzdHJpbmcKCXt9OwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBTPgoJc3RydWN0IGNfc3RyOwoKCXRlbXBsYXRlIDxjaGFyLi4uIFM+CglzdHJ1Y3QgY19zdHI8dHN0cmluZzxTLi4uPj4KCXsKCQlzdGF0aWMgY2hhciBjb25zdCB2YWx1ZVtdOwoJfTsKCgl0ZW1wbGF0ZSA8Y2hhci4uLiBTPgoJY2hhciBjb25zdCBjX3N0cjx0c3RyaW5nPFMuLi4+Pjo6dmFsdWVbXSA9IHsgUy4uLiwgMCB9OwoKCXRlbXBsYXRlIDx0eXBlbmFtZS4uLiBMaXN0PgoJc3RydWN0IHRsaXN0IDogaWRlbnRpdHk8dGxpc3Q8TGlzdC4uLj4+Cgl7fTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgTGlzdD4KCXN0cnVjdCBlbXB0eSA6IGJvb2xfPGZhbHNlPgoJe307CgoJdGVtcGxhdGUgPD4KCXN0cnVjdCBlbXB0eTx0bGlzdDw+PiA6IGJvb2xfPHRydWU+Cgl7fTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgTGlzdD4KCXN0cnVjdCBwdXNoX2Zyb250OwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBMaXN0PgoJc3RydWN0IHB1c2hfZnJvbnQ8VCwgdGxpc3Q8TGlzdC4uLj4+CgkJOiB0bGlzdDxULCBMaXN0Li4uPgoJe307CgoJdGVtcGxhdGUgPHR5cGVuYW1lIExpc3Q+CglzdHJ1Y3QgcG9wX2Zyb250OwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBIZWFkLCB0eXBlbmFtZS4uLiBUYWlsPgoJc3RydWN0IHBvcF9mcm9udDx0bGlzdDxIZWFkLCBUYWlsLi4uPj4KCQk6IHRsaXN0PFRhaWwuLi4+Cgl7fTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgTGlzdD4KCXN0cnVjdCBmcm9udDsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgSGVhZCwgdHlwZW5hbWUuLi4gVGFpbD4KCXN0cnVjdCBmcm9udDx0bGlzdDxIZWFkLCBUYWlsLi4uPj4gOiBpZGVudGl0eTxIZWFkPgoJe307CgoJdGVtcGxhdGUKCTwKCQl0eXBlbmFtZSBULAoJCXR5cGVuYW1lIExpc3QsCgkJdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZT4gY2xhc3MgTGVzcwoJPgoJc3RydWN0IGluc2VydF9zb3J0ZWQ7CgoJdGVtcGxhdGUKCTwKCQl0eXBlbmFtZSBULAoJCXRlbXBsYXRlIDx0eXBlbmFtZSwgdHlwZW5hbWU+IGNsYXNzIExlc3MKCT4KCXN0cnVjdCBpbnNlcnRfc29ydGVkPFQsIHRsaXN0PD4sIExlc3M+CgkJOiB0bGlzdDxUPgoJe307CgoJdGVtcGxhdGUKCTwKCQl0eXBlbmFtZSBULAoJCXR5cGVuYW1lIEhlYWQsIHR5cGVuYW1lLi4uIFRhaWwsCgkJdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZT4gY2xhc3MgTGVzcwoJPgoJc3RydWN0IGluc2VydF9zb3J0ZWQ8VCwgdGxpc3Q8SGVhZCwgVGFpbC4uLj4sIExlc3M+CgkJOiBzdGQ6OmNvbmRpdGlvbmFsCgkJPAoJCQlMZXNzPFQsIEhlYWQ+Ojp2YWx1ZSwKCQkJdGxpc3Q8VCwgSGVhZCwgVGFpbC4uLj4sCgkJCXR5cGVuYW1lIHB1c2hfZnJvbnQ8SGVhZCwgdHlwZW5hbWUgaW5zZXJ0X3NvcnRlZDxULCB0bGlzdDxUYWlsLi4uPiwgTGVzcz46OnR5cGU+Ojp0eXBlCgkJPjo6dHlwZQoJe307CgoJdGVtcGxhdGUKCTwKCQl0ZW1wbGF0ZSA8dHlwZW5hbWUsIHR5cGVuYW1lPiBjbGFzcyBMZXNzLAoJCXR5cGVuYW1lIExpc3QKCT4KCXN0cnVjdCBzb3J0OwoKCXRlbXBsYXRlCgk8CgkJdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZT4gY2xhc3MgTGVzcwoJPgoJc3RydWN0IHNvcnQ8TGVzcywgdGxpc3Q8Pj4KCQk6IHRsaXN0PD4KCXt9OwoKCXRlbXBsYXRlCgk8CgkJdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZT4gY2xhc3MgTGVzcywKCQl0eXBlbmFtZSBIZWFkLCB0eXBlbmFtZS4uLiBUYWlsCgk+CglzdHJ1Y3Qgc29ydDxMZXNzLCB0bGlzdDxIZWFkLCBUYWlsLi4uPj4KCQk6IGluc2VydF9zb3J0ZWQ8SGVhZCwgdHlwZW5hbWUgc29ydDxMZXNzLCB0bGlzdDxUYWlsLi4uPj46OnR5cGUsIExlc3M+Cgl7fTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgUzEsIHR5cGVuYW1lIFMyPgoJc3RydWN0IHN0cmluZ19sZXNzOwoKCXRlbXBsYXRlIDw+CglzdHJ1Y3Qgc3RyaW5nX2xlc3M8dHN0cmluZzw+LCB0c3RyaW5nPD4+CgkJOiBib29sXzxmYWxzZT4KCXt9OwoKCXRlbXBsYXRlIDxjaGFyLi4uIFM+CglzdHJ1Y3Qgc3RyaW5nX2xlc3M8dHN0cmluZzxTLi4uPiwgdHN0cmluZzw+PgoJCTogYm9vbF88ZmFsc2U+Cgl7fTsKCgl0ZW1wbGF0ZSA8Y2hhci4uLiBTPgoJc3RydWN0IHN0cmluZ19sZXNzPHRzdHJpbmc8PiwgdHN0cmluZzxTLi4uPj4KCQk6IGJvb2xfPHRydWU+Cgl7fTsKCgl0ZW1wbGF0ZSA8Y2hhciBIZWFkMSwgY2hhci4uLiBUYWlsMSwgY2hhciBIZWFkMiwgY2hhci4uLiBUYWlsMj4KCXN0cnVjdCBzdHJpbmdfbGVzczx0c3RyaW5nPEhlYWQxLCBUYWlsMS4uLj4sIHRzdHJpbmc8SGVhZDIsIFRhaWwyLi4uPj4KCQk6IGJvb2xfCgkJPAoJCQlIZWFkMSA9PSBIZWFkMgoJCQk/IHN0cmluZ19sZXNzPHRzdHJpbmc8VGFpbDEuLi4+LCB0c3RyaW5nPFRhaWwyLi4uPj46OnZhbHVlCgkJCTogKEhlYWQxIDwgSGVhZDIpCgkJPgoJe307CgoJdGVtcGxhdGUgPHR5cGVuYW1lIFBhaXIxLCB0eXBlbmFtZSBQYWlyMj4KCXN0cnVjdCBwYWlyX2xlc3M7CgoJdGVtcGxhdGUgPHR5cGVuYW1lIEVudW0xLCB0eXBlbmFtZSBTdHJpbmcxLCB0eXBlbmFtZSBFbnVtMiwgdHlwZW5hbWUgU3RyaW5nMj4KCXN0cnVjdCBwYWlyX2xlc3M8dHBhaXI8RW51bTEsIFN0cmluZzE+LCB0cGFpcjxFbnVtMiwgU3RyaW5nMj4+CgkJOiBzdHJpbmdfbGVzczxTdHJpbmcxLCBTdHJpbmcyPgoJe307CgoJdGVtcGxhdGUgPHVuc2lnbmVkIE4sIHR5cGVuYW1lIExpc3Q+CglzdHJ1Y3QgdGFrZV9uOwoKCXRlbXBsYXRlIDw+CglzdHJ1Y3QgdGFrZV9uPDAsIHRsaXN0PD4+Cgl7CgkJdHlwZWRlZiB0bGlzdDw+IGxlZnQ7CgkJdHlwZWRlZiB0bGlzdDw+IHJpZ2h0OwoJfTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgSGVhZCwgdHlwZW5hbWUuLi4gVGFpbD4KCXN0cnVjdCB0YWtlX248MCwgdGxpc3Q8SGVhZCwgVGFpbC4uLj4+Cgl7CgkJdHlwZWRlZiB0bGlzdDw+IGxlZnQ7CgkJdHlwZWRlZiB0bGlzdDxIZWFkLCBUYWlsLi4uPiByaWdodDsKCX07CgoJdGVtcGxhdGUgPHVuc2lnbmVkIE4sIHR5cGVuYW1lIEhlYWQsIHR5cGVuYW1lLi4uIFRhaWw+CgljbGFzcyB0YWtlX248TiwgdGxpc3Q8SGVhZCwgVGFpbC4uLj4+Cgl7CgkJdHlwZWRlZiB0YWtlX248TiAtIDEsIHRsaXN0PFRhaWwuLi4+PiByZWN1cnNlOwoKCXB1YmxpYzoKCQl0eXBlZGVmIHR5cGVuYW1lIHB1c2hfZnJvbnQ8SGVhZCwgdHlwZW5hbWUgcmVjdXJzZTo6bGVmdD46OnR5cGUgbGVmdDsKCQl0eXBlZGVmIHR5cGVuYW1lIHJlY3Vyc2U6OnJpZ2h0IHJpZ2h0OwoJfTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgTGlzdD4KCXN0cnVjdCBjdXRfaGFsZl93aXRoX21lZGlhbjsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4gTGlzdD4KCWNsYXNzIGN1dF9oYWxmX3dpdGhfbWVkaWFuPHRsaXN0PExpc3QuLi4+PgoJewoJCXR5cGVkZWYgdGFrZV9uPHNpemVvZi4uLihMaXN0KSAvIDIsIHRsaXN0PExpc3QuLi4+PiBsZWZ0X3dpdGhvdXRfbWVkaWFuOwoJCXR5cGVkZWYgdGFrZV9uPDEsIHR5cGVuYW1lIGxlZnRfd2l0aG91dF9tZWRpYW46OnJpZ2h0PiBtZWRpYW5fd2l0aF9yaWdodDsKCglwdWJsaWM6CgkJdHlwZWRlZiB0eXBlbmFtZSBsZWZ0X3dpdGhvdXRfbWVkaWFuOjpsZWZ0IGxlZnQ7CgkJdHlwZWRlZiB0eXBlbmFtZSBmcm9udDx0eXBlbmFtZSBtZWRpYW5fd2l0aF9yaWdodDo6bGVmdD46OnR5cGUgbWVkaWFuOwoJCXR5cGVkZWYgdHlwZW5hbWUgbWVkaWFuX3dpdGhfcmlnaHQ6OnJpZ2h0IHJpZ2h0OwoJfTsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgRW51bSwgdHlwZW5hbWUgTWFwcGluZ3M+CgljbGFzcyBkZWNpc2lvbl90cmVlCgl7CgkJdHlwZWRlZiBjdXRfaGFsZl93aXRoX21lZGlhbjxNYXBwaW5ncz4gY3V0OwoJCXR5cGVkZWYgdHlwZW5hbWUgY3V0OjptZWRpYW4gbWVkaWFuOwoKCQlFbnVtIG5vdF9mb3VuZChzdGQ6OnN0cmluZyBjb25zdCYgdmFsdWUpIGNvbnN0CgkJewoJCQl0aHJvdyBzdGQ6OmludmFsaWRfYXJndW1lbnR7ICJzdHJpbmcgJyIgKyB2YWx1ZSArICInIGhhcyBubyBlbnVtIHZhbHVlIiB9OwoJCX0KCgkJRW51bSBsZXNzKGNoYXIgY29uc3QqIHZhbHVlLCBib29sXzx0cnVlPikgY29uc3QKCQl7CgkJCXJldHVybiBub3RfZm91bmQodmFsdWUpOwoJCX0KCgkJRW51bSBsZXNzKGNoYXIgY29uc3QqIHZhbHVlLCBib29sXzxmYWxzZT4pIGNvbnN0CgkJewoJCQlyZXR1cm4gZGVjaXNpb25fdHJlZTxFbnVtLCB0eXBlbmFtZSBjdXQ6OmxlZnQ+KCkodmFsdWUpOwoJCX0KCgkJRW51bSBncmVhdGVyKGNoYXIgY29uc3QqIHZhbHVlLCBib29sXzx0cnVlPikgY29uc3QKCQl7CgkJCXJldHVybiBub3RfZm91bmQodmFsdWUpOwoJCX0KCgkJRW51bSBncmVhdGVyKGNoYXIgY29uc3QqIHZhbHVlLCBib29sXzxmYWxzZT4pIGNvbnN0CgkJewoJCQlyZXR1cm4gZGVjaXNpb25fdHJlZTxFbnVtLCB0eXBlbmFtZSBjdXQ6OnJpZ2h0PigpKHZhbHVlKTsKCQl9CgoJcHVibGljOgoJCUVudW0gb3BlcmF0b3IgKCkgKGNoYXIgY29uc3QqIHZhbHVlKSBjb25zdAoJCXsKCQkJYXV0byBjbXAgPSBzdGQ6OnN0cmNtcCh2YWx1ZSwgY19zdHI8dHlwZW5hbWUgc2Vjb25kPG1lZGlhbj46OnR5cGU+Ojp2YWx1ZSk7CgoJCQlpZihjbXAgPCAwKQoJCQkJcmV0dXJuIGxlc3ModmFsdWUsIGJvb2xfPGVtcHR5PHR5cGVuYW1lIGN1dDo6bGVmdD46OnZhbHVlPigpKTsKCgkJCWlmKGNtcCA+IDApCgkJCQlyZXR1cm4gZ3JlYXRlcih2YWx1ZSwgYm9vbF88ZW1wdHk8dHlwZW5hbWUgY3V0OjpyaWdodD46OnZhbHVlPigpKTsKCgkJCXJldHVybiBmaXJzdDxtZWRpYW4+Ojp0eXBlOjp2YWx1ZTsKCQl9Cgl9OwoKCXRlbXBsYXRlIDx0eXBlbmFtZSBFbnVtLCB0eXBlbmFtZS4uLiBNYXBwaW5ncz4KCXN0cnVjdCBlbnVtX21hcHBlcjsKCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgRW51bSwgdHlwZW5hbWUuLi4gU3RyaW5ncywgRW51bS4uLiBWYWx1ZXM+CgljbGFzcyBlbnVtX21hcHBlcjxFbnVtLCB0cGFpcjxjb25zdGFudDxFbnVtLCBWYWx1ZXM+LCBTdHJpbmdzPi4uLj4KCXsKCQl0eXBlZGVmIHRsaXN0PHRwYWlyPGNvbnN0YW50PEVudW0sIFZhbHVlcz4sIFN0cmluZ3M+Li4uPiBtYXBwaW5nczsKCQl0eXBlZGVmIHR5cGVuYW1lIHNvcnQ8cGFpcl9sZXNzLCBtYXBwaW5ncz46OnR5cGUgc29ydGVkX21hcHBpbmdzOwoKCXB1YmxpYzoKCQlFbnVtIG9wZXJhdG9yICgpIChjaGFyIGNvbnN0KiB2YWx1ZSkgY29uc3QKCQl7CgkJCXJldHVybiBkZWNpc2lvbl90cmVlPEVudW0sIHNvcnRlZF9tYXBwaW5ncz4oKSh2YWx1ZSk7CgkJfQoJfTsKfQoKI2RlZmluZSBFTUFQKEUsIC4uLikgdG1wOjp0cGFpcjx0bXA6OmNvbnN0YW50PGRlY2x0eXBlKEUpLCBFPiwgdG1wOjp0c3RyaW5nPF9fVkFfQVJHU19fPj4KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCiNpbmNsdWRlIDxpb3N0cmVhbT4KCmVudW0gc3RydWN0IG15X2VudW0gOiB1bnNpZ25lZAp7Cglmb28sCgliYXIsCgliYXosCglxdXgsCn07CgpzdGQ6Om9zdHJlYW0mIG9wZXJhdG9yIDw8IChzdGQ6Om9zdHJlYW0mIG9zLCBteV9lbnVtIGUpCnsKCXN0YXRpYyBjaGFyIGNvbnN0KiBjb25zdCB0YWJsZVtdID0geyAiZm9vIiwgImJhciIsICJiYXoiLCAicXV4IiB9OwoJcmV0dXJuIG9zIDw8IHRhYmxlW3N0YXRpY19jYXN0PHVuc2lnbmVkPihlKV07Cn0KCmludCBtYWluKCkKewoJdHlwZWRlZiB0bXA6OmVudW1fbWFwcGVyCgk8CgkJbXlfZW51bSwKCQlFTUFQKG15X2VudW06OmJheiwgJ2InLCdhJywneicpLAoJCUVNQVAobXlfZW51bTo6YmFyLCAnYicsJ2EnLCdyJyksCgkJRU1BUChteV9lbnVtOjpmb28sICdmJywnbycsJ28nKSwKCQlFTUFQKG15X2VudW06OnF1eCwgJ3EnLCd1JywneCcpCgk+IG15X2VudW1fbWFwcGVyOwoKCW15X2VudW1fbWFwcGVyIG1hcHBlcjsKCglzdGQ6OmNvdXQgPDwgbWFwcGVyKCJmb28iKSA8PCAnXG4nOwoJc3RkOjpjb3V0IDw8IG1hcHBlcigiYmFyIikgPDwgJ1xuJzsKCXN0ZDo6Y291dCA8PCBtYXBwZXIoImJheiIpIDw8ICdcbic7CglzdGQ6OmNvdXQgPDwgbWFwcGVyKCJxdXgiKSA8PCAnXG4nOwoKCXRyeQoJewoJCXN0ZDo6Y291dCA8PCBtYXBwZXIoImdhcmJhZ2UiKSA8PCAnXG4nOwoJfQoKCWNhdGNoKHN0ZDo6aW52YWxpZF9hcmd1bWVudCBjb25zdCYgaXYpCgl7CgkJc3RkOjpjb3V0IDw8IGl2LndoYXQoKSA8PCAnXG4nOwoJfQp9Cg==