// ausgeliehen von Sones https://g...content-available-to-author-only...b.com/bingojamigo/VTMPL
#include <cstddef>
#include <limits>
#include <type_traits>
namespace vtmpl
{
using size_type = std::size_t;
using index_type = size_type;
template<typename T>
struct identity
{
using type = T;
};
template<typename A, typename B>
struct type_pair : identity<type_pair<A,B>>
{
using first = A;
using second = B;
};
template <typename T, T...> struct value_list;
template <typename Type,
Type... args>
struct value_list_base : identity<value_list<Type, args...>>
{
static constexpr size_type length = sizeof...(args);
static constexpr size_type npos = std::numeric_limits<size_type>::max();
using value_type = Type;
static constexpr value_type arr[] { args... };
private:
static constexpr size_type _count_impl( char c, size_type index )
{
return arr[index] == c + (index == 0 ? 0 : _count_impl(c, index - 1));
}
static constexpr size_type _find_impl( char c, size_type index )
{
return index == length ? npos : c == arr[index] ? index : _find_impl(c, index + 1);
}
public:
static constexpr size_type count( char c )
{
return _count_impl( c, length - 1 );
}
static constexpr size_type find( char c )
{
return _find_impl( c, 0 );
}
};
template <typename Type,
Type... args>
constexpr Type value_list_base<Type, args...>::arr[];
template<typename Type,
Type... args>
struct value_list : value_list_base<Type, args...> {};
template<char... args>
struct value_list<char, args...> : value_list_base<char, args...>
{
static char constexpr nt_arr[] { args..., '\0' };
};
template<index_type ... args>
using index_list = value_list<index_type, args...>;
template <typename, typename> struct multiply;
template <index_type... indices, index_type... tail>
struct multiply<index_list<indices...>,
index_list<tail... >> : index_list<indices..., (sizeof...(indices)+indices)...,
(2*sizeof...(indices)+indices)...,
(3*sizeof...(indices)+indices)...,
(4*sizeof...(indices)+tail)...> {};
//! make_index_list: Essential function to generate a list of numbers, used in many other functions to avoid recursion.
// Generates a list of natural numbers. make_index_list<4> -> {0, 1, 2, 3}, for example, and make_index_list<23510> -> {0, 1, 2, 3, 4, ..., 23509}.
template <index_type N>
struct make_index_list :
multiply< typename make_index_list<N/4>::type,
typename make_index_list<N%4>::type > {};
template <> struct make_index_list<3> : index_list<0, 1, 2> {};
template <> struct make_index_list<2> : index_list<0, 1> {};
template <> struct make_index_list<1> : index_list<0> {};
template <> struct make_index_list<0> : index_list<> {};
template<char... args>
char constexpr value_list<char, args...>::nt_arr[];
template <typename,
size_type,
size_type len,
typename = typename make_index_list<len>::type> struct sub_list;
template <typename Type, Type ... args,
size_type pos,
size_type len,
index_type... indices>
struct sub_list<value_list<Type, args...>,
pos, len,
index_list<indices...>> :
value_list<Type, value_list<Type, args...>::arr[pos + indices]...> {};
/// split_at: Splits the list into to sublists as specified by the position. The value at position pos is in the first list.
template <typename list,
size_type pos> struct split_at;
template <typename val_t,
val_t ... values,
size_type pos>
struct split_at<value_list<val_t, values...>,
pos> :
type_pair< typename sub_list<value_list<val_t, values...>, 0, pos + 1>::type,
typename sub_list<value_list<val_t, values...>, pos + 1, sizeof...(values) - pos - 1>::type > {};
/// rtrim: cuts of all values after a specific one
template<typename List, typename List::value_type> struct rtrim;
template<typename Type, Type ... args, Type to_find>
struct rtrim<value_list<Type, args...>, to_find> :
split_at<value_list<Type, args...>,
value_list<Type, args...>::find( to_find )>::first {};
template<char ... args>
using const_string = value_list<char, args...>;
#define SPLIT_1(s, x) ( x < sizeof(s) ? s[x] : '\0' )
#define SPLIT_4(s, x) SPLIT_1 (s, x), SPLIT_1 (s, x+1) , SPLIT_1 (s, x+2) , SPLIT_1 (s, x+3)
#define SPLIT_16(s, x) SPLIT_4 (s, x), SPLIT_4 (s, x+4) , SPLIT_4 (s, x+8) , SPLIT_4 (s, x+12)
#define SPLIT_64(s, x) SPLIT_16 (s, x), SPLIT_16 (s, x+16) , SPLIT_16 (s, x+32) , SPLIT_16 (s, x+48)
#define SPLIT_256(s, x) SPLIT_64 (s, x), SPLIT_64 (s, x+64) , SPLIT_64 (s, x+128 , SPLIT_64 (s, x+194)
#define SPLIT_1024(s, x) SPLIT_256(s, x), SPLIT_256(s, x+256), SPLIT_256(s, x+512), SPLIT_256(s, x+768)
//!: Use this macro to create a const_string from a string literal or constant pointer
#define STRING_IMPL(str, n) vtmpl::rtrim<vtmpl::const_string<SPLIT_##n(str, 0)>, '\0'>::type
#define STRING(str) STRING_IMPL(str, 64)
#define STRING_256(str) STRING_IMPL(str, 256)
#define STRING_1024(str) STRING_IMPL(str, 1024)
}
// ende ausgeliehen
#include <string>
namespace regex_impl
{
// normales Zeichen
template <typename String>
class regex
{
public:
static bool match(bool before, std::string string)
{
using string_pair = typename vtmpl::split_at<String, String::find('\0') - 1>::type;
return regex<typename string_pair::second>::match(string.find(string_pair::first::nt_arr) != std::string::npos && before,
string);
}
};
// Ende
template <>
class regex<vtmpl::const_string<'\0'>>
{
public:
static bool match(bool before, std::string)
{
return before;
}
};
}
template <typename Regex>
class regex
{
public:
static bool match(std::string string)
{
return regex_impl::regex<Regex>::match(true, string);
}
};
#include <iostream>
int main()
{
std::cout << regex<STRING("ello")>::match("Hello World!")
<< regex<STRING("foo")>::match("Hello World!");
}
Ly8gYXVzZ2VsaWVoZW4gdm9uIFNvbmVzIGh0dHBzOi8vZy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYi5jb20vYmluZ29qYW1pZ28vVlRNUEwKI2luY2x1ZGUgPGNzdGRkZWY+CiNpbmNsdWRlIDxsaW1pdHM+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KCm5hbWVzcGFjZSB2dG1wbAp7Cgp1c2luZyBzaXplX3R5cGUgPSBzdGQ6OnNpemVfdDsKCnVzaW5nIGluZGV4X3R5cGUgPSBzaXplX3R5cGU7Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgpzdHJ1Y3QgaWRlbnRpdHkKewogICAgdXNpbmcgdHlwZSA9IFQ7Cn07Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBBLCB0eXBlbmFtZSBCPgpzdHJ1Y3QgdHlwZV9wYWlyIDogaWRlbnRpdHk8dHlwZV9wYWlyPEEsQj4+CnsKICAgIHVzaW5nIGZpcnN0ID0gQTsKICAgIHVzaW5nIHNlY29uZCA9IEI7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgVC4uLj4gc3RydWN0IHZhbHVlX2xpc3Q7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVHlwZSwKICAgICAgICAgVHlwZS4uLiBhcmdzPgpzdHJ1Y3QgdmFsdWVfbGlzdF9iYXNlIDogaWRlbnRpdHk8dmFsdWVfbGlzdDxUeXBlLCBhcmdzLi4uPj4KewogICAgc3RhdGljIGNvbnN0ZXhwciBzaXplX3R5cGUgbGVuZ3RoID0gc2l6ZW9mLi4uKGFyZ3MpOwoKICAgIHN0YXRpYyBjb25zdGV4cHIgc2l6ZV90eXBlIG5wb3MgPSBzdGQ6Om51bWVyaWNfbGltaXRzPHNpemVfdHlwZT46Om1heCgpOwoKICAgIHVzaW5nIHZhbHVlX3R5cGUgPSBUeXBlOwoKICAgIHN0YXRpYyBjb25zdGV4cHIgdmFsdWVfdHlwZSBhcnJbXSB7IGFyZ3MuLi4gfTsKCnByaXZhdGU6CgogICAgc3RhdGljIGNvbnN0ZXhwciBzaXplX3R5cGUgX2NvdW50X2ltcGwoIGNoYXIgYywgc2l6ZV90eXBlIGluZGV4ICkKICAgIHsKICAgICAgICByZXR1cm4gYXJyW2luZGV4XSA9PSBjICsgKGluZGV4ID09IDAgPyAwIDogX2NvdW50X2ltcGwoYywgaW5kZXggLSAxKSk7CiAgICB9CgogICAgc3RhdGljIGNvbnN0ZXhwciBzaXplX3R5cGUgX2ZpbmRfaW1wbCggY2hhciBjLCBzaXplX3R5cGUgaW5kZXggKQogICAgewogICAgICAgIHJldHVybiBpbmRleCA9PSBsZW5ndGggPyBucG9zIDogYyA9PSBhcnJbaW5kZXhdID8gaW5kZXggOiBfZmluZF9pbXBsKGMsIGluZGV4ICsgMSk7CiAgICB9CgpwdWJsaWM6CgogICAgc3RhdGljIGNvbnN0ZXhwciBzaXplX3R5cGUgY291bnQoIGNoYXIgYyApCiAgICB7CiAgICAgICAgcmV0dXJuIF9jb3VudF9pbXBsKCBjLCBsZW5ndGggLSAxICk7CiAgICB9CgogICAgc3RhdGljIGNvbnN0ZXhwciBzaXplX3R5cGUgZmluZCggY2hhciBjICkKICAgIHsKICAgICAgICByZXR1cm4gX2ZpbmRfaW1wbCggYywgMCApOwogICAgfQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFR5cGUsCiAgICAgICAgIFR5cGUuLi4gYXJncz4KY29uc3RleHByIFR5cGUgdmFsdWVfbGlzdF9iYXNlPFR5cGUsIGFyZ3MuLi4+OjphcnJbXTsKCnRlbXBsYXRlPHR5cGVuYW1lIFR5cGUsCiAgICAgICAgIFR5cGUuLi4gYXJncz4Kc3RydWN0IHZhbHVlX2xpc3QgOiB2YWx1ZV9saXN0X2Jhc2U8VHlwZSwgYXJncy4uLj4ge307Cgp0ZW1wbGF0ZTxjaGFyLi4uIGFyZ3M+CnN0cnVjdCB2YWx1ZV9saXN0PGNoYXIsIGFyZ3MuLi4+IDogdmFsdWVfbGlzdF9iYXNlPGNoYXIsIGFyZ3MuLi4+CnsKICAgIHN0YXRpYyBjaGFyIGNvbnN0ZXhwciBudF9hcnJbXSB7IGFyZ3MuLi4sICdcMCcgfTsKfTsKCnRlbXBsYXRlPGluZGV4X3R5cGUgLi4uIGFyZ3M+CnVzaW5nIGluZGV4X2xpc3QgPSB2YWx1ZV9saXN0PGluZGV4X3R5cGUsIGFyZ3MuLi4+OwoKdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZT4gc3RydWN0IG11bHRpcGx5Owp0ZW1wbGF0ZSA8aW5kZXhfdHlwZS4uLiBpbmRpY2VzLCBpbmRleF90eXBlLi4uIHRhaWw+CnN0cnVjdCBtdWx0aXBseTxpbmRleF9saXN0PGluZGljZXMuLi4+LAppbmRleF9saXN0PHRhaWwuLi4gPj4gOiBpbmRleF9saXN0PGluZGljZXMuLi4sIChzaXplb2YuLi4oaW5kaWNlcykraW5kaWNlcykuLi4sCiAgICAgICAgICAgKDIqc2l6ZW9mLi4uKGluZGljZXMpK2luZGljZXMpLi4uLAogICAgICAgICAgICgzKnNpemVvZi4uLihpbmRpY2VzKStpbmRpY2VzKS4uLiwKICAgICAgICAgICAoNCpzaXplb2YuLi4oaW5kaWNlcykrdGFpbCkuLi4+IHt9OwoKLy8hIG1ha2VfaW5kZXhfbGlzdDogRXNzZW50aWFsIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIGEgbGlzdCBvZiBudW1iZXJzLCB1c2VkIGluIG1hbnkgb3RoZXIgZnVuY3Rpb25zIHRvIGF2b2lkIHJlY3Vyc2lvbi4KLy8gR2VuZXJhdGVzIGEgbGlzdCBvZiBuYXR1cmFsIG51bWJlcnMuIG1ha2VfaW5kZXhfbGlzdDw0PiAtPiB7MCwgMSwgMiwgM30sIGZvciBleGFtcGxlLCBhbmQgbWFrZV9pbmRleF9saXN0PDIzNTEwPiAtPiB7MCwgMSwgMiwgMywgNCwgLi4uLCAyMzUwOX0uCgp0ZW1wbGF0ZSA8aW5kZXhfdHlwZSBOPgpzdHJ1Y3QgbWFrZV9pbmRleF9saXN0IDoKICAgICAgICBtdWx0aXBseTwgdHlwZW5hbWUgbWFrZV9pbmRleF9saXN0PE4vND46OnR5cGUsCiAgICAgICAgdHlwZW5hbWUgbWFrZV9pbmRleF9saXN0PE4lND46OnR5cGUgPiB7fTsKCnRlbXBsYXRlIDw+IHN0cnVjdCBtYWtlX2luZGV4X2xpc3Q8Mz4gOiBpbmRleF9saXN0PDAsIDEsIDI+IHt9Owp0ZW1wbGF0ZSA8PiBzdHJ1Y3QgbWFrZV9pbmRleF9saXN0PDI+IDogaW5kZXhfbGlzdDwwLCAxPiB7fTsKdGVtcGxhdGUgPD4gc3RydWN0IG1ha2VfaW5kZXhfbGlzdDwxPiA6IGluZGV4X2xpc3Q8MD4ge307CnRlbXBsYXRlIDw+IHN0cnVjdCBtYWtlX2luZGV4X2xpc3Q8MD4gOiBpbmRleF9saXN0PD4ge307Cgp0ZW1wbGF0ZTxjaGFyLi4uIGFyZ3M+CmNoYXIgY29uc3RleHByIHZhbHVlX2xpc3Q8Y2hhciwgYXJncy4uLj46Om50X2FycltdOwoKdGVtcGxhdGUgPHR5cGVuYW1lLAogICAgICAgICBzaXplX3R5cGUsCiAgICAgICAgIHNpemVfdHlwZSBsZW4sCiAgICAgICAgIHR5cGVuYW1lID0gdHlwZW5hbWUgbWFrZV9pbmRleF9saXN0PGxlbj46OnR5cGU+IHN0cnVjdCBzdWJfbGlzdDsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUeXBlLCBUeXBlIC4uLiBhcmdzLAogICAgICAgICBzaXplX3R5cGUgcG9zLAogICAgICAgICBzaXplX3R5cGUgbGVuLAogICAgICAgICBpbmRleF90eXBlLi4uIGluZGljZXM+CnN0cnVjdCBzdWJfbGlzdDx2YWx1ZV9saXN0PFR5cGUsIGFyZ3MuLi4+LAogICAgICAgIHBvcywgbGVuLAogICAgICAgIGluZGV4X2xpc3Q8aW5kaWNlcy4uLj4+IDoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZV9saXN0PFR5cGUsIHZhbHVlX2xpc3Q8VHlwZSwgYXJncy4uLj46OmFycltwb3MgKyBpbmRpY2VzXS4uLj4ge307CgovLy8gc3BsaXRfYXQ6IFNwbGl0cyB0aGUgbGlzdCBpbnRvIHRvIHN1Ymxpc3RzIGFzIHNwZWNpZmllZCBieSB0aGUgcG9zaXRpb24uIFRoZSB2YWx1ZSBhdCBwb3NpdGlvbiBwb3MgaXMgaW4gdGhlIGZpcnN0IGxpc3QuCgp0ZW1wbGF0ZSA8dHlwZW5hbWUgbGlzdCwKICAgICAgICAgc2l6ZV90eXBlIHBvcz4gc3RydWN0IHNwbGl0X2F0OwoKdGVtcGxhdGUgPHR5cGVuYW1lIHZhbF90LAogICAgICAgICB2YWxfdCAuLi4gdmFsdWVzLAogICAgICAgICBzaXplX3R5cGUgcG9zPgpzdHJ1Y3Qgc3BsaXRfYXQ8dmFsdWVfbGlzdDx2YWxfdCwgdmFsdWVzLi4uPiwKICAgICAgICBwb3M+IDoKICAgICAgICB0eXBlX3BhaXI8IHR5cGVuYW1lIHN1Yl9saXN0PHZhbHVlX2xpc3Q8dmFsX3QsIHZhbHVlcy4uLj4sIDAsIHBvcyArIDE+Ojp0eXBlLAp0eXBlbmFtZSBzdWJfbGlzdDx2YWx1ZV9saXN0PHZhbF90LCB2YWx1ZXMuLi4+LCBwb3MgKyAxLCBzaXplb2YuLi4odmFsdWVzKSAtIHBvcyAtIDE+Ojp0eXBlID4ge307CgovLy8gcnRyaW06IGN1dHMgb2YgYWxsIHZhbHVlcyBhZnRlciBhIHNwZWNpZmljIG9uZQoKdGVtcGxhdGU8dHlwZW5hbWUgTGlzdCwgdHlwZW5hbWUgTGlzdDo6dmFsdWVfdHlwZT4gc3RydWN0IHJ0cmltOwp0ZW1wbGF0ZTx0eXBlbmFtZSBUeXBlLCBUeXBlIC4uLiBhcmdzLCBUeXBlIHRvX2ZpbmQ+CnN0cnVjdCBydHJpbTx2YWx1ZV9saXN0PFR5cGUsIGFyZ3MuLi4+LCB0b19maW5kPiA6CiAgICAgICAgc3BsaXRfYXQ8dmFsdWVfbGlzdDxUeXBlLCBhcmdzLi4uPiwKdmFsdWVfbGlzdDxUeXBlLCBhcmdzLi4uPjo6ZmluZCggdG9fZmluZCApPjo6Zmlyc3Qge307Cgp0ZW1wbGF0ZTxjaGFyIC4uLiBhcmdzPgp1c2luZyBjb25zdF9zdHJpbmcgPSB2YWx1ZV9saXN0PGNoYXIsIGFyZ3MuLi4+OwoKI2RlZmluZSBTUExJVF8xKHMsIHgpICggeCA8IHNpemVvZihzKSA/IHNbeF0gOiAnXDAnICkKI2RlZmluZSBTUExJVF80KHMsIHgpIFNQTElUXzEgKHMsIHgpLCBTUExJVF8xIChzLCB4KzEpICwgU1BMSVRfMSAocywgeCsyKSAsIFNQTElUXzEgKHMsIHgrMykKI2RlZmluZSBTUExJVF8xNihzLCB4KSBTUExJVF80IChzLCB4KSwgU1BMSVRfNCAocywgeCs0KSAsIFNQTElUXzQgKHMsIHgrOCkgLCBTUExJVF80IChzLCB4KzEyKQojZGVmaW5lIFNQTElUXzY0KHMsIHgpIFNQTElUXzE2IChzLCB4KSwgU1BMSVRfMTYgKHMsIHgrMTYpICwgU1BMSVRfMTYgKHMsIHgrMzIpICwgU1BMSVRfMTYgKHMsIHgrNDgpCiNkZWZpbmUgU1BMSVRfMjU2KHMsIHgpIFNQTElUXzY0IChzLCB4KSwgU1BMSVRfNjQgKHMsIHgrNjQpICwgU1BMSVRfNjQgKHMsIHgrMTI4ICwgU1BMSVRfNjQgKHMsIHgrMTk0KQojZGVmaW5lIFNQTElUXzEwMjQocywgeCkgU1BMSVRfMjU2KHMsIHgpLCBTUExJVF8yNTYocywgeCsyNTYpLCBTUExJVF8yNTYocywgeCs1MTIpLCBTUExJVF8yNTYocywgeCs3NjgpCgovLyE6IFVzZSB0aGlzIG1hY3JvIHRvIGNyZWF0ZSBhIGNvbnN0X3N0cmluZyBmcm9tIGEgc3RyaW5nIGxpdGVyYWwgb3IgY29uc3RhbnQgcG9pbnRlcgoKI2RlZmluZSBTVFJJTkdfSU1QTChzdHIsIG4pIHZ0bXBsOjpydHJpbTx2dG1wbDo6Y29uc3Rfc3RyaW5nPFNQTElUXyMjbihzdHIsIDApPiwgJ1wwJz46OnR5cGUKCiNkZWZpbmUgU1RSSU5HKHN0cikgU1RSSU5HX0lNUEwoc3RyLCA2NCkKI2RlZmluZSBTVFJJTkdfMjU2KHN0cikgU1RSSU5HX0lNUEwoc3RyLCAyNTYpCiNkZWZpbmUgU1RSSU5HXzEwMjQoc3RyKSBTVFJJTkdfSU1QTChzdHIsIDEwMjQpCgp9Ci8vIGVuZGUgYXVzZ2VsaWVoZW4KCiNpbmNsdWRlIDxzdHJpbmc+CgpuYW1lc3BhY2UgcmVnZXhfaW1wbAp7ICAgIAovLyBub3JtYWxlcyBaZWljaGVuCnRlbXBsYXRlIDx0eXBlbmFtZSBTdHJpbmc+CmNsYXNzIHJlZ2V4CnsKcHVibGljOgogICAgc3RhdGljIGJvb2wgbWF0Y2goYm9vbCBiZWZvcmUsIHN0ZDo6c3RyaW5nIHN0cmluZykKICAgIHsKICAgICAgICB1c2luZyBzdHJpbmdfcGFpciA9IHR5cGVuYW1lIHZ0bXBsOjpzcGxpdF9hdDxTdHJpbmcsIFN0cmluZzo6ZmluZCgnXDAnKSAtIDE+Ojp0eXBlOwogICAgICAgIHJldHVybiByZWdleDx0eXBlbmFtZSBzdHJpbmdfcGFpcjo6c2Vjb25kPjo6bWF0Y2goc3RyaW5nLmZpbmQoc3RyaW5nX3BhaXI6OmZpcnN0OjpudF9hcnIpICE9IHN0ZDo6c3RyaW5nOjpucG9zICYmIGJlZm9yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZyk7CiAgICB9Cn07CgovLyBFbmRlCnRlbXBsYXRlIDw+CmNsYXNzIHJlZ2V4PHZ0bXBsOjpjb25zdF9zdHJpbmc8J1wwJz4+CnsKcHVibGljOgogICAgc3RhdGljIGJvb2wgbWF0Y2goYm9vbCBiZWZvcmUsIHN0ZDo6c3RyaW5nKQogICAgewogICAgICAgIHJldHVybiBiZWZvcmU7CiAgICB9Cn07Cn0KCnRlbXBsYXRlIDx0eXBlbmFtZSBSZWdleD4KY2xhc3MgcmVnZXgKewpwdWJsaWM6CiAgICBzdGF0aWMgYm9vbCBtYXRjaChzdGQ6OnN0cmluZyBzdHJpbmcpCiAgICB7CiAgICAgICAgcmV0dXJuIHJlZ2V4X2ltcGw6OnJlZ2V4PFJlZ2V4Pjo6bWF0Y2godHJ1ZSwgc3RyaW5nKTsKICAgIH0KfTsKCiNpbmNsdWRlIDxpb3N0cmVhbT4KCmludCBtYWluKCkKewogICAgc3RkOjpjb3V0IDw8IHJlZ2V4PFNUUklORygiZWxsbyIpPjo6bWF0Y2goIkhlbGxvIFdvcmxkISIpCiAgICAJCSAgPDwgcmVnZXg8U1RSSU5HKCJmb28iKT46Om1hdGNoKCJIZWxsbyBXb3JsZCEiKTsKfQ==