#include <stdexcept>
#include <boost/format.hpp>
#include <boost/utility/string_ref.hpp>
template < std:: size_t N>
constexpr bool checkValidFormats( const char ( & fmt) [ N] , size_t n, char c)
{
return n >= N ?
false
: fmt[ n] == c ?
true
: checkValidFormats( fmt, n + 1 , c) ;
}
template < class >
struct FormatSupportedType;
#define SUPPORTED_TYPE(T, Fmts) \
template<> \
struct FormatSupportedType<T> \
{ \
constexpr static bool supports(char c) \
{ return checkValidFormats(Fmts, 0, c) \
? true : throw std::logic_error("invalid fmt for type"); } \
}
SUPPORTED_TYPE( char , "c" ) ;
SUPPORTED_TYPE( int , "d*" ) ;
SUPPORTED_TYPE( unsigned , "u*" ) ;
SUPPORTED_TYPE( char * , "s" ) ;
SUPPORTED_TYPE( const char * , "s" ) ;
SUPPORTED_TYPE( std:: string , "s" ) ;
SUPPORTED_TYPE( boost:: string_ref , "s" ) ;
SUPPORTED_TYPE( double , "f" ) ;
SUPPORTED_TYPE( float , "f" ) ;
/////////////////
constexpr bool isDigit( char c)
{
return c >= '0' && c <= '9' ;
}
constexpr bool isModifier( char c)
{
return c == 'l' ||
c == 'h' ||
c == 'j' ||
c == 'z' ||
c == 't' ||
c == 'L' ||
c == '#' ||
c == '+' ||
c == '-' ||
c == ' ' ||
c == '\' ' ||
c == 'I' ||
c == '.' ||
c == '=' ||
isDigit( c) ;
}
template < std:: size_t N>
constexpr size_t nextNonModifier( const char ( & fmt) [ N] , std:: size_t n)
{
return
n >= N ?
throw std:: logic_error ( "invalid format string" )
: isModifier( fmt[ n] ) ?
nextNonModifier( fmt, n + 1 )
: n;
}
////////////////////
template < std:: size_t N>
constexpr bool checkFormatHelper( const char ( & fmt) [ N] , std:: size_t n) ;
template < std:: size_t N, class T, class ... Ts >
constexpr bool checkFormatHelper( const char ( & fmt) [ N] , std:: size_t n, const T& arg, const Ts& ... args ) ;
////////////////////
template < std:: size_t N, typename T1, typename T2, typename T3, typename ... Ts >
constexpr auto checkWidthAndPrecision( const char ( & fmt) [ N] , std:: size_t n, const T1& /*width*/ , const T2& /*precision*/ , const T3& /* arg */ , const Ts& ... args )
- > typename std:: enable_if <
std:: is_integral < T1> :: value &&
std:: is_integral < T2> :: value ,
bool > :: type
{
return FormatSupportedType< typename std:: decay < T3> :: type > :: supports ( fmt[ n] ) &&
checkFormatHelper( fmt, n + 1 , args...) ;
}
template < std:: size_t N, typename ... Ts >
constexpr bool checkWidthAndPrecision( const char ( & ) [ N] , std:: size_t , const Ts& ...)
{
return false ;
}
////////////////////
template < std:: size_t N, typename T1, typename T2, typename ... Ts >
constexpr auto checkWidthOrPrecision( const char ( & fmt) [ N] , std:: size_t n, const T1& /*precision*/ , const T2& /* arg */ , const Ts& ... args )
- > typename std:: enable_if <
std:: is_integral < T1> :: value ,
bool > :: type
{
return FormatSupportedType< typename std:: decay < T2> :: type > :: supports ( fmt[ n] ) &&
checkFormatHelper( fmt, n + 1 , args...) ;
}
template < std:: size_t N, typename ... Ts >
constexpr bool checkWidthOrPrecision( const char ( & ) [ N] , std:: size_t , const Ts& ...)
{
return false ;
}
////////////////////
template < std:: size_t N>
constexpr bool checkFormatHelper( const char ( & fmt) [ N] , std:: size_t n)
{
return
n>= N ?
true
: fmt[ n] ! = '%' ?
checkFormatHelper( fmt, n + 1 )
: fmt[ n + 1 ] == '%' ?
checkFormatHelper( fmt, n + 2 )
: false ;
}
template < std:: size_t N, class T, class ... Ts >
constexpr bool checkFormatHelper( const char ( & fmt) [ N] , std:: size_t n, const T& arg, const Ts& ... args )
{
return
n >= N ?
throw std:: logic_error ( "too many arguments for provided format string" )
: fmt[ n] ! = '%' ?
checkFormatHelper( fmt, n + 1 , arg, args...)
// literal percent character
: ( fmt[ n + 1 ] == '%' ) ?
checkFormatHelper( fmt, n + 2 , arg, args...)
// long-long modifier
: ( fmt[ n + 1 ] == 'l' && fmt[ n + 2 ] == 'l' ) ?
FormatSupportedType< typename std:: decay < T> :: type > :: supports ( fmt[ n + 3 ] ) &&
checkFormatHelper( fmt, n + 4 , args...)
// width & precision modifier
: ( fmt[ n + 1 ] == '*' && fmt[ n + 2 ] == '.' && fmt[ n + 3 ] == '*' ) ?
checkWidthAndPrecision( fmt, n + 4 , arg, args...)
// width or precision modifier
: ( ( fmt[ n + 1 ] == '.' && fmt[ n + 2 ] == '*' ) || ( fmt[ n + 1 ] == '*' ) ) ?
checkWidthOrPrecision( fmt, ( fmt[ n + 1 ] == '.' ? n + 3 : n + 2 ) , arg, args...)
// other modifier
: ( isModifier( fmt[ n + 1 ] ) ) ?
FormatSupportedType< typename std:: decay < T> :: type > :: supports ( fmt[ nextNonModifier( fmt, n + 2 ) ] ) &&
checkFormatHelper( fmt, nextNonModifier( fmt, n + 2 ) + 1 , args...)
// no modifier
: FormatSupportedType< typename std:: decay < T> :: type > :: supports ( fmt[ n + 1 ] ) &&
checkFormatHelper( fmt, n + 2 , args...) ;
}
template < std:: size_t N, class ... Ts >
constexpr bool checkFormat( const char ( & fmt) [ N] , const Ts& ... args )
{
return checkFormatHelper( fmt, 0 , args...) ;
}
// printing...
void add( boost:: format & )
{ }
template < typename T, typename ... Ts >
void add( boost:: format & f, const T& arg, const Ts& ... ts )
{
f % arg;
add( f, ts...) ;
}
#define LOG(fmt, ...) \
{ \
static_assert(checkFormat(fmt, ##__VA_ARGS__), "Format is incorrect"); \
boost::format f(fmt); \
add(f, ##__VA_ARGS__); \
std::cout << f.str() << std::endl; \
}
int main( )
{
// char
LOG( "%c" , 'x' ) ;
// integral
LOG( "%d" , - 123 ) ;
LOG( "%ld" , - 123 ) ;
LOG( "%u" , 123u) ;
LOG( "%lu" , 123u) ;
// strings
LOG( "%s" , "hello world" ) ;
{ const char * s = "hello world" ; LOG( "%s" , s) ; }
{ std:: string s = "hello world" ; LOG( "%s" , s) ; }
{ std:: string s = "hello world" ; boost:: string_ref r( s) ; LOG( "%s" , r) ; }
// floating point
LOG( "%f" , 1.23 ) ;
LOG( "%f" , 1.23f ) ;
// width / precision
LOG( "%02d" , 1 ) ;
LOG( "%.2d" , 123 ) ;
LOG( "% 3s" , "hello" ) ;
LOG( "% 3s" , "yo" ) ;
LOG( "%.3s" , "hello" ) ;
LOG( "%.3s" , "yo" ) ;
// incorrect format string
// LOG("%f", 1);
// LOG("%d", 1.23);
// not supported by boost::format
// LOG("%*s", 3, "yo");
// LOG("%*d", 3, 12);
// LOG("%.*s", 3, "hello");
// LOG("%.*d", 3, 12345);
// LOG("%*.*s", 3, 3, "hello");
// LOG("%*.*d", 3, 3, 12345);
}
I2luY2x1ZGUgPHN0ZGV4Y2VwdD4KI2luY2x1ZGUgPGJvb3N0L2Zvcm1hdC5ocHA+CiNpbmNsdWRlIDxib29zdC91dGlsaXR5L3N0cmluZ19yZWYuaHBwPgoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KY29uc3RleHByIGJvb2wgY2hlY2tWYWxpZEZvcm1hdHMoY29uc3QgY2hhciAoJmZtdClbTl0sIHNpemVfdCBuLCBjaGFyIGMpCnsKICAgIHJldHVybiBuID49IE4gPwogICAgICAgICAgICBmYWxzZQogICAgICAgIDogZm10W25dID09IGMgPwogICAgICAgICAgICB0cnVlCiAgICAgICAgOiBjaGVja1ZhbGlkRm9ybWF0cyhmbXQsIG4gKyAxLCBjKTsKfQoKdGVtcGxhdGU8Y2xhc3M+CnN0cnVjdCBGb3JtYXRTdXBwb3J0ZWRUeXBlOwoKI2RlZmluZSBTVVBQT1JURURfVFlQRShULCBGbXRzKSBcCnRlbXBsYXRlPD4gXApzdHJ1Y3QgRm9ybWF0U3VwcG9ydGVkVHlwZTxUPiBcCnsgXAogICAgY29uc3RleHByIHN0YXRpYyBib29sIHN1cHBvcnRzKGNoYXIgYykgXAogICAgeyByZXR1cm4gY2hlY2tWYWxpZEZvcm1hdHMoRm10cywgMCwgYykgXAogICAgICAgICAgICA/IHRydWUgOiB0aHJvdyBzdGQ6OmxvZ2ljX2Vycm9yKCJpbnZhbGlkIGZtdCBmb3IgdHlwZSIpOyB9IFwKfQoKU1VQUE9SVEVEX1RZUEUoY2hhciwgICAgICAgICAgICAgICJjIik7ClNVUFBPUlRFRF9UWVBFKGludCwgICAgICAgICAgICAgICAiZCoiKTsKU1VQUE9SVEVEX1RZUEUodW5zaWduZWQsICAgICAgICAgICJ1KiIpOwpTVVBQT1JURURfVFlQRShjaGFyKiwgICAgICAgICAgICAgInMiKTsKU1VQUE9SVEVEX1RZUEUoY29uc3QgY2hhciosICAgICAgICJzIik7ClNVUFBPUlRFRF9UWVBFKHN0ZDo6c3RyaW5nLCAgICAgICAicyIpOwpTVVBQT1JURURfVFlQRShib29zdDo6c3RyaW5nX3JlZiwgInMiKTsKU1VQUE9SVEVEX1RZUEUoZG91YmxlLCAgICAgICAgICAgICJmIik7ClNVUFBPUlRFRF9UWVBFKGZsb2F0LCAgICAgICAgICAgICAiZiIpOwoKLy8vLy8vLy8vLy8vLy8vLy8KCmNvbnN0ZXhwciBib29sIGlzRGlnaXQoY2hhciBjKQp7CiAgICByZXR1cm4gYyA+PSAnMCcgJiYgYyA8PSAnOSc7Cn0KCmNvbnN0ZXhwciBib29sIGlzTW9kaWZpZXIoY2hhciBjKQp7CiAgICByZXR1cm4gIGMgPT0gJ2wnIHx8CiAgICAgICAgICAgIGMgPT0gJ2gnIHx8CiAgICAgICAgICAgIGMgPT0gJ2onIHx8CiAgICAgICAgICAgIGMgPT0gJ3onIHx8CiAgICAgICAgICAgIGMgPT0gJ3QnIHx8CiAgICAgICAgICAgIGMgPT0gJ0wnIHx8CiAgICAgICAgICAgIGMgPT0gJyMnIHx8CiAgICAgICAgICAgIGMgPT0gJysnIHx8CiAgICAgICAgICAgIGMgPT0gJy0nIHx8CiAgICAgICAgICAgIGMgPT0gJyAnIHx8CiAgICAgICAgICAgIGMgPT0gJ1wnJyB8fAogICAgICAgICAgICBjID09ICdJJyB8fAogICAgICAgICAgICBjID09ICcuJyB8fAogICAgICAgICAgICBjID09ICc9JyB8fAogICAgICAgICAgICBpc0RpZ2l0KGMpOwp9Cgp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgpjb25zdGV4cHIgc2l6ZV90IG5leHROb25Nb2RpZmllcihjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbikKewogICAgcmV0dXJuCiAgICAgICAgbiA+PSBOID8KICAgICAgICAgICAgdGhyb3cgc3RkOjpsb2dpY19lcnJvcigiaW52YWxpZCBmb3JtYXQgc3RyaW5nIikKICAgICAgICA6IGlzTW9kaWZpZXIoZm10W25dKSA/CiAgICAgICAgICAgICAgICBuZXh0Tm9uTW9kaWZpZXIoZm10LCBuICsgMSkKICAgICAgICA6IG47Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vCgp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgpjb25zdGV4cHIgYm9vbCBjaGVja0Zvcm1hdEhlbHBlcihjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3Qgbik7CnRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4sIGNsYXNzIFQsIGNsYXNzLi4uIFRzPgpjb25zdGV4cHIgYm9vbCBjaGVja0Zvcm1hdEhlbHBlcihjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbiwgY29uc3QgVCYgYXJnLCBjb25zdCBUcyYuLi4gYXJncyk7CgovLy8vLy8vLy8vLy8vLy8vLy8vLwoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTiwgdHlwZW5hbWUgVDEsIHR5cGVuYW1lIFQyLCB0eXBlbmFtZSBUMywgdHlwZW5hbWUuLi4gVHM+CmNvbnN0ZXhwciBhdXRvIGNoZWNrV2lkdGhBbmRQcmVjaXNpb24oY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4sIGNvbnN0IFQxJiAvKndpZHRoKi8sIGNvbnN0IFQyJiAvKnByZWNpc2lvbiovLCBjb25zdCBUMyYgLyogYXJnICovLCBjb25zdCBUcyYuLi4gYXJncykKICAgIC0+IHR5cGVuYW1lIHN0ZDo6ZW5hYmxlX2lmPAogICAgICAgICAgICBzdGQ6OmlzX2ludGVncmFsPFQxPjo6dmFsdWUgJiYKICAgICAgICAgICAgc3RkOjppc19pbnRlZ3JhbDxUMj46OnZhbHVlLAogICAgICAgIGJvb2w+Ojp0eXBlCnsKICAgIHJldHVybiBGb3JtYXRTdXBwb3J0ZWRUeXBlPCB0eXBlbmFtZSBzdGQ6OmRlY2F5PFQzPjo6dHlwZT46OnN1cHBvcnRzKGZtdFtuXSkgJiYKICAgICAgICAgICAgY2hlY2tGb3JtYXRIZWxwZXIoZm10LCBuICsgMSwgYXJncy4uLik7Cn0KCnRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4sIHR5cGVuYW1lLi4uIFRzPgpjb25zdGV4cHIgYm9vbCBjaGVja1dpZHRoQW5kUHJlY2lzaW9uKGNvbnN0IGNoYXIgKCYpW05dLCBzdGQ6OnNpemVfdCwgY29uc3QgVHMmLi4uKQp7CiAgICByZXR1cm4gZmFsc2U7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vCgp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOLCB0eXBlbmFtZSBUMSwgdHlwZW5hbWUgVDIsIHR5cGVuYW1lLi4uIFRzPgpjb25zdGV4cHIgYXV0byBjaGVja1dpZHRoT3JQcmVjaXNpb24oY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4sIGNvbnN0IFQxJiAvKnByZWNpc2lvbiovLCBjb25zdCBUMiYgLyogYXJnICovLCBjb25zdCBUcyYuLi4gYXJncykKICAgIC0+IHR5cGVuYW1lIHN0ZDo6ZW5hYmxlX2lmPAogICAgICAgICAgICBzdGQ6OmlzX2ludGVncmFsPFQxPjo6dmFsdWUsCiAgICAgICAgYm9vbD46OnR5cGUKewogICAgcmV0dXJuIEZvcm1hdFN1cHBvcnRlZFR5cGU8IHR5cGVuYW1lIHN0ZDo6ZGVjYXk8VDI+Ojp0eXBlPjo6c3VwcG9ydHMoZm10W25dKSAmJgogICAgICAgICAgICBjaGVja0Zvcm1hdEhlbHBlcihmbXQsIG4gKyAxLCBhcmdzLi4uKTsKfQoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTiwgdHlwZW5hbWUuLi4gVHM+CmNvbnN0ZXhwciBib29sIGNoZWNrV2lkdGhPclByZWNpc2lvbihjb25zdCBjaGFyICgmKVtOXSwgc3RkOjpzaXplX3QsIGNvbnN0IFRzJi4uLikKewogICAgcmV0dXJuIGZhbHNlOwp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLwoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KY29uc3RleHByIGJvb2wgY2hlY2tGb3JtYXRIZWxwZXIoY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4pCnsKICAgIHJldHVybgogICAgICAgIG4+PSBOID8KICAgICAgICAgICAgdHJ1ZQogICAgICAgIDogZm10W25dICE9ICclJyA/CiAgICAgICAgICAgIGNoZWNrRm9ybWF0SGVscGVyKGZtdCwgbiArIDEpCiAgICAgICAgOiBmbXRbbiArIDFdID09ICclJyA/CiAgICAgICAgICAgIGNoZWNrRm9ybWF0SGVscGVyKGZtdCwgbiArIDIpCiAgICAgICAgOiBmYWxzZTsKfQoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTiwgY2xhc3MgVCwgY2xhc3MuLi4gVHM+CmNvbnN0ZXhwciBib29sIGNoZWNrRm9ybWF0SGVscGVyKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuLCBjb25zdCBUJiBhcmcsIGNvbnN0IFRzJi4uLiBhcmdzKQp7CiAgICByZXR1cm4KICAgICAgICBuID49IE4gPwogICAgICAgICAgICB0aHJvdyBzdGQ6OmxvZ2ljX2Vycm9yKCJ0b28gbWFueSBhcmd1bWVudHMgZm9yIHByb3ZpZGVkIGZvcm1hdCBzdHJpbmciKQoKICAgICAgICA6IGZtdFtuXSAhPSAnJScgPwogICAgICAgICAgICBjaGVja0Zvcm1hdEhlbHBlcihmbXQsIG4gKyAxLCBhcmcsIGFyZ3MuLi4pCgogICAgICAgIC8vIGxpdGVyYWwgcGVyY2VudCBjaGFyYWN0ZXIKICAgICAgICA6IChmbXRbbiArIDFdID09ICclJykgPwogICAgICAgICAgICBjaGVja0Zvcm1hdEhlbHBlcihmbXQsIG4gKyAyLCBhcmcsIGFyZ3MuLi4pCgogICAgICAgIC8vIGxvbmctbG9uZyBtb2RpZmllcgogICAgICAgIDogKGZtdFtuICsgMV0gPT0gJ2wnICYmIGZtdFtuICsgMl0gPT0gJ2wnKSA/CiAgICAgICAgICAgIEZvcm1hdFN1cHBvcnRlZFR5cGU8IHR5cGVuYW1lIHN0ZDo6ZGVjYXk8VD46OnR5cGUgPjo6c3VwcG9ydHMoZm10W24gKyAzXSkgJiYKICAgICAgICAgICAgY2hlY2tGb3JtYXRIZWxwZXIoZm10LCBuICsgNCwgYXJncy4uLikKCiAgICAgICAgLy8gd2lkdGggJiBwcmVjaXNpb24gbW9kaWZpZXIKICAgICAgICA6IChmbXRbbiArIDFdID09ICcqJyAmJiBmbXRbbiArIDJdID09ICcuJyAmJiBmbXRbbiArIDNdID09ICcqJykgPwogICAgICAgICAgICBjaGVja1dpZHRoQW5kUHJlY2lzaW9uKGZtdCwgbiArIDQsIGFyZywgYXJncy4uLikKCiAgICAgICAgLy8gd2lkdGggb3IgcHJlY2lzaW9uIG1vZGlmaWVyCiAgICAgICAgOiAoKGZtdFtuICsgMV0gPT0gJy4nICYmIGZtdFtuICsgMl0gPT0gJyonKSB8fCAoZm10W24gKyAxXSA9PSAnKicpKSA/CiAgICAgICAgICAgIGNoZWNrV2lkdGhPclByZWNpc2lvbihmbXQsIChmbXRbbiArIDFdID09ICcuJyA/IG4gKyAzIDogbiArIDIpLCBhcmcsIGFyZ3MuLi4pCgogICAgICAgIC8vIG90aGVyIG1vZGlmaWVyCiAgICAgICAgOiAoaXNNb2RpZmllcihmbXRbbiArIDFdKSkgPwogICAgICAgICAgICBGb3JtYXRTdXBwb3J0ZWRUeXBlPCB0eXBlbmFtZSBzdGQ6OmRlY2F5PFQ+Ojp0eXBlPjo6c3VwcG9ydHMoZm10W25leHROb25Nb2RpZmllcihmbXQsIG4gKyAyKV0pICYmCiAgICAgICAgICAgIGNoZWNrRm9ybWF0SGVscGVyKGZtdCwgbmV4dE5vbk1vZGlmaWVyKGZtdCwgbiArIDIpICsgMSwgYXJncy4uLikKCiAgICAgICAgLy8gbm8gbW9kaWZpZXIKICAgICAgICA6IEZvcm1hdFN1cHBvcnRlZFR5cGU8IHR5cGVuYW1lIHN0ZDo6ZGVjYXk8VD46OnR5cGU+OjpzdXBwb3J0cyhmbXRbbiArIDFdKSAmJgogICAgICAgICAgICBjaGVja0Zvcm1hdEhlbHBlcihmbXQsIG4gKyAyLCBhcmdzLi4uKTsKfQoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTiwgY2xhc3MuLi4gVHM+CmNvbnN0ZXhwciBib29sIGNoZWNrRm9ybWF0KGNvbnN0IGNoYXIgKCZmbXQpW05dLCBjb25zdCBUcyYuLi4gYXJncykKewogICAgcmV0dXJuIGNoZWNrRm9ybWF0SGVscGVyKGZtdCwgMCwgYXJncy4uLik7Cn0KCi8vIHByaW50aW5nLi4uCgp2b2lkIGFkZChib29zdDo6Zm9ybWF0JikKeyB9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBUcz4Kdm9pZCBhZGQoYm9vc3Q6OmZvcm1hdCYgZiwgY29uc3QgVCYgYXJnLCBjb25zdCBUcyYuLi4gdHMpCnsKICAgIGYgJSBhcmc7CiAgICBhZGQoZiwgdHMuLi4pOwp9CgojZGVmaW5lIExPRyhmbXQsIC4uLikgXAogICAgeyBcCiAgICAgICAgc3RhdGljX2Fzc2VydChjaGVja0Zvcm1hdChmbXQsICMjX19WQV9BUkdTX18pLCAiRm9ybWF0IGlzIGluY29ycmVjdCIpOyBcCiAgICAgICAgYm9vc3Q6OmZvcm1hdCBmKGZtdCk7IFwKICAgICAgICBhZGQoZiwgIyNfX1ZBX0FSR1NfXyk7IFwKICAgICAgICBzdGQ6OmNvdXQgPDwgZi5zdHIoKSA8PCBzdGQ6OmVuZGw7IFwKICAgIH0KCmludCBtYWluKCkKewogICAgLy8gY2hhcgogICAgTE9HKCIlYyIsICd4Jyk7CgogICAgLy8gaW50ZWdyYWwKICAgIExPRygiJWQiLCAtMTIzKTsKICAgIExPRygiJWxkIiwgLTEyMyk7CiAgICBMT0coIiV1IiwgMTIzdSk7CiAgICBMT0coIiVsdSIsIDEyM3UpOwoKICAgIC8vIHN0cmluZ3MKICAgIExPRygiJXMiLCAiaGVsbG8gd29ybGQiKTsKICAgIHsgY29uc3QgY2hhciogcyA9ICJoZWxsbyB3b3JsZCI7IExPRygiJXMiLCBzKTsgfQogICAgeyBzdGQ6OnN0cmluZyBzID0gImhlbGxvIHdvcmxkIjsgTE9HKCIlcyIsIHMpOyB9CiAgICB7IHN0ZDo6c3RyaW5nIHMgPSAiaGVsbG8gd29ybGQiOyBib29zdDo6c3RyaW5nX3JlZiByKHMpOyBMT0coIiVzIiwgcik7IH0KCiAgICAvLyBmbG9hdGluZyBwb2ludAogICAgTE9HKCIlZiIsIDEuMjMpOwogICAgTE9HKCIlZiIsIDEuMjNmKTsKCiAgICAvLyB3aWR0aCAvIHByZWNpc2lvbgogICAgTE9HKCIlMDJkIiwgMSk7CiAgICBMT0coIiUuMmQiLCAxMjMpOwogICAgTE9HKCIlIDNzIiwgImhlbGxvIik7CiAgICBMT0coIiUgM3MiLCAieW8iKTsKICAgIExPRygiJS4zcyIsICJoZWxsbyIpOwogICAgTE9HKCIlLjNzIiwgInlvIik7CiAgICAKICAgIC8vIGluY29ycmVjdCBmb3JtYXQgc3RyaW5nCiAgICAvLyBMT0coIiVmIiwgMSk7CiAgICAvLyBMT0coIiVkIiwgMS4yMyk7CiAgICAKICAgIC8vIG5vdCBzdXBwb3J0ZWQgYnkgYm9vc3Q6OmZvcm1hdAogICAgLy8gTE9HKCIlKnMiLCAzLCAieW8iKTsKICAgIC8vIExPRygiJSpkIiwgMywgMTIpOwogICAgLy8gTE9HKCIlLipzIiwgMywgImhlbGxvIik7CiAgICAvLyBMT0coIiUuKmQiLCAzLCAxMjM0NSk7CiAgICAvLyBMT0coIiUqLipzIiwgMywgMywgImhlbGxvIik7CiAgICAvLyBMT0coIiUqLipkIiwgMywgMywgMTIzNDUpOwp9Cg==