#include <cstddef>
#include <cstdio>
#include <stdexcept>
#include <boost/utility/string_ref.hpp>
#include <boost/format.hpp>
#ifndef BOOST_PP_VARIADICS
# define BOOST_PP_VARIADICS
#endif
#include <boost/preprocessor.hpp>
template < typename ... Ts >
struct Format
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n) ;
} ;
//////////////////////
template < std:: size_t N>
constexpr bool checkValidFormats( const char ( & fmt) [ N] , size_t n, char c)
{
return n >= N ?
throw std:: logic_error ( "invalid format for type" )
: fmt[ n] == c ?
true
: checkValidFormats( fmt, n + 1 , c) ;
}
template < class >
struct Type;
#define SUPPORTED_TYPE(T, Fmts) \
template<> \
struct Type<T> \
{ \
template<std::size_t N> \
constexpr static bool check(const char (&fmt)[N], std::size_t n) \
{ \
return n >= N ? \
throw std::logic_error("invalid format for type") \
: checkValidFormats(Fmts, 0, fmt[n]); \
} \
}
SUPPORTED_TYPE( char , "c" ) ;
SUPPORTED_TYPE( int8_t , "cd" ) ;
SUPPORTED_TYPE( uint8_t , "cu" ) ;
SUPPORTED_TYPE( int16_t , "d" ) ;
SUPPORTED_TYPE( uint16_t , "u" ) ;
SUPPORTED_TYPE( int32_t , "d" ) ;
SUPPORTED_TYPE( uint32_t , "u" ) ;
SUPPORTED_TYPE( char * , "s" ) ;
SUPPORTED_TYPE( unsigned 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" ) ;
#define SUPPORTED_LL_TYPE(T, C) \
template<> \
struct Type<T> \
{ \
template<std::size_t N> \
static constexpr bool check(const char (&fmt)[N], std::size_t n) \
{ \
return n < N && \
n - 2 >= 0 && \
fmt[n] == C && \
fmt[n - 1] == 'l' && \
fmt[n - 2] == 'l' ? \
true \
: throw std::logic_error("invalid format for type"); \
} \
}
SUPPORTED_LL_TYPE( int64_t , 'd' ) ;
SUPPORTED_LL_TYPE( uint64_t , 'u' ) ;
template < typename ... Ts >
struct Argument
{
template < std:: size_t N>
static constexpr bool check( const char ( & ) [ N] , std:: size_t )
{
return false ;
}
} ;
template < typename T, typename ... Ts >
struct Argument< T, Ts...>
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
// %[<flags>][<width>][.<precision>][<length>]<specifier>
// specifier := d|i|u|o|x|X|f|F|e|E|g|G|a|A|c|s|p|n
return Type< typename std:: decay < T> :: type > :: check ( fmt, n) &&
Format< Ts...> :: check ( fmt, n + 1 ) ;
}
} ;
///////////////////////////
template < size_t N>
constexpr bool isDoubleLengthSpecifier( const char ( & fmt) [ N] , std:: size_t n)
{
// hh | ll
return n + 2 < N &&
( ( fmt[ n] == 'h' && fmt[ n + 1 ] == 'h' ) ||
( fmt[ n] == 'l' && fmt[ n + 1 ] == 'l' ) ) ;
}
template < size_t N>
constexpr bool isSingleLengthSpecifier( const char ( & fmt) [ N] , std:: size_t n)
{
// h | l | j | z | t | L
return n + 1 < N &&
( fmt[ n] == 'h' ||
fmt[ n] == 'l' ||
fmt[ n] == 'j' ||
fmt[ n] == 'z' ||
fmt[ n] == 't' ||
fmt[ n] == 'L' ) ;
}
template < size_t N>
constexpr size_t nextNonLengthSpecifier( const char ( & fmt) [ N] , std:: size_t n)
{
return
isDoubleLengthSpecifier( fmt, n) ? n + 2
: isSingleLengthSpecifier( fmt, n) ? n + 1
: n;
}
template < typename ... Ts >
struct Length
{
template < std:: size_t N>
static constexpr bool check( const char ( & ) [ N] , std:: size_t )
{
return false ;
}
} ;
template < typename T, typename ... Ts >
struct Length< T, Ts...>
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
// %[<flags>][<width>][.<precision>][<length>]<specifier>
// length := hh|h|l|ll|j|z|t|L
return Argument< T, Ts...> :: check ( fmt, nextNonLengthSpecifier( fmt, n) ) ;
}
} ;
///////////////////////////
template < std:: size_t N>
constexpr size_t nextNonLiteralPrecision( const char ( & fmt) [ N] , std:: size_t n)
{
return
n >= N ?
throw std:: logic_error ( "invalid format string - parsing precision" )
: fmt[ n] >= '0' && fmt[ n] <= '9' ?
nextNonLiteralPrecision( fmt, n + 1 )
: n;
}
template < typename ... Ts >
struct Precision
{
template < std:: size_t N>
static constexpr bool check( const char ( & ) [ N] , std:: size_t )
{
return false ;
}
} ;
template < typename T, typename ... Ts >
struct Precision< T, Ts...>
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
// %[<flags>][<width>][.<precision>][<length>]<specifier>
// precision := <number>|'*' // A number or a '*'
// if precision is a provided argument, validate it is integral
return n + 1 < N && fmt[ n] == '.' && fmt[ n + 1 ] == '*' ?
std:: is_integral < T> :: value && Length< Ts...> :: check ( fmt, n + 2 )
// otherwise skip over any literal precision
: n + 1 < N && fmt[ n] == '.' ?
Length< T, Ts...> :: check ( fmt, nextNonLiteralPrecision( fmt, n + 1 ) )
: Length< T, Ts...> :: check ( fmt, n) ;
}
} ;
///////////////////////////
template < std:: size_t N>
constexpr size_t nextNonLiteralWidth( const char ( & fmt) [ N] , std:: size_t n)
{
return
n >= N ?
throw std:: logic_error ( "invalid format string - parsing width" )
: fmt[ n] >= '0' && fmt[ n] <= '9' ?
nextNonLiteralWidth( fmt, n + 1 )
: n;
}
template < typename ... Ts >
struct Width
{
template < std:: size_t N>
static constexpr bool check( const char ( & ) [ N] , std:: size_t )
{
return false ;
}
} ;
template < typename T, typename ... Ts >
struct Width< T, Ts...>
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
// %[<flags>][<width>][.<precision>][<length>]<specifier>
// width := <number>|'*' // A number or a '*'
// if width is a provided argument, validate it is integral
return fmt[ n] == '*' ?
std:: is_integral < T> :: value && Precision< Ts...> :: check ( fmt, n + 1 )
// otherwise skip over any literal width
: Precision< T, Ts...> :: check ( fmt, nextNonLiteralWidth( fmt, n) ) ;
}
} ;
///////////////////////////
template < size_t N>
constexpr bool isFlag( const char ( & fmt) [ N] , std:: size_t n)
{
return n + 1 < N &&
( fmt[ n] == '-' ||
fmt[ n] == '+' ||
fmt[ n] == ' ' ||
fmt[ n] == '#' ||
fmt[ n] == '0' ) ;
}
template < std:: size_t N>
constexpr size_t nextNonFlag( const char ( & fmt) [ N] , std:: size_t n)
{
return
n >= N ?
throw std:: logic_error ( "invalid format string" )
: isFlag( fmt, n) ?
nextNonFlag( fmt, n + 1 )
: n;
}
template < typename T, typename ... Ts >
struct Flags
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
// %[<flags>][<width>][.<precision>][<length>]<specifier>
// flags := [-+ #0]* // Zero or more
return Width< T, Ts...> :: check ( fmt, nextNonFlag( fmt, n) ) ;
}
} ;
///////////////////////////
template < size_t N>
constexpr bool isLiteralPercent( const char ( & fmt) [ N] , std:: size_t n)
{
return n + 1 <= N && fmt[ n] == '%' && fmt[ n + 1 ] == '%' ;
}
template < typename T, typename ... Ts >
struct Format< T, Ts...>
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
return
n >= N ?
throw std:: logic_error ( "too many arguments for provided format string" )
// skip non-format specifiers (ie: not a % character)
: fmt[ n] ! = '%' ?
Format< T, Ts...> :: check ( fmt, n + 1 )
// %%
: isLiteralPercent( fmt, n) ?
Format< T, Ts...> :: check ( fmt, n + 2 )
// we've found a format specifier
: Flags< T, Ts...> :: check ( fmt, n + 1 ) ;
}
} ;
template <>
struct Format<>
{
template < std:: size_t N>
static constexpr bool check( const char ( & fmt) [ N] , std:: size_t n)
{
return
n>= N ?
true
: fmt[ n] ! = '%' ?
check( fmt, n + 1 )
: fmt[ n + 1 ] == '%' ?
check( fmt, n + 2 )
: throw std:: logic_error ( "too few arguments for provided format string" ) ;
}
} ;
////////////////
// 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 PP_PARENTHESISE_WITH_TOKEN(r, token, i, e) \
BOOST_PP_COMMA_IF(i) token(e)
#define PP_CSV_SEQ_PARENTHESISE_WITH_TOKEN(...) \
BOOST_PP_SEQ_FOR_EACH_I(PP_PARENTHESISE_WITH_TOKEN, decltype, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define PP_PERFORM_LOG_FORMAT_CHECK(fmt, ...) \
Format<BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_TUPLE_SIZE((,##__VA_ARGS__)), 1), \
BOOST_PP_EXPAND, PP_CSV_SEQ_PARENTHESISE_WITH_TOKEN)(__VA_ARGS__)>::check(fmt, 0)
#define LOG(fmt, ...) \
{ \
static_assert(PP_PERFORM_LOG_FORMAT_CHECK(fmt, ##__VA_ARGS__), ""); \
boost::format f(fmt); \
add(f, ##__VA_ARGS__); \
std::cout << f.str() << std::endl; \
}
int main( )
{
// nothing
LOG( "hello world" ) ;
// char
LOG( "%c" , 'x' ) ;
// integral
LOG( "%d" , - 123 ) ;
LOG( "%ld" , - 123 ) ;
LOG( "%u" , 123u) ;
LOG( "%lu" , 123u) ;
// strings
LOG( "%s" , "hello world" ) ;
LOG( "%-s" , "hello world" ) ;
LOG( "%s" , std:: string ( "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( "% 3s" , "hello" ) ;
LOG( "% 3s" , "yo" ) ;
LOG( "%.2d" , 123 ) ;
LOG( "%.2f" , 1.2345 ) ;
LOG( "%2f" , 1.23456789 ) ;
LOG( "%02f" , 0.1 ) ;
LOG( "%02.2f" , 0.1 ) ;
// width & precision as arguments
// not supported by boost::format
// LOG("%*d", 3, 12);
// LOG("%.*s", 3, "hello");
// LOG("%.*d", 3, 12345);
// LOG("%*.*s", 3, 3, "hello");
// LOG("%*.*d", 3, 3, 12345);
// mix of multiple different arguments
LOG( "%s" , "hi" ) ;
LOG( "%s %d" , "hi" , 1 ) ;
LOG( "%s %d %u %lf %f %c" , "hi" , - 1 , 12u, 1.23 , 1.33 , 'c' ) ;
// too few arguments
// LOG("%s %d %u %lf %f %c", "hi", -1, 12u, 1.23, 1.33);
// too many arguments
// LOG("%s %d %u %lf %f %c", "hi", -1, 12u, 1.23, 1.33, 'c', 1);
// incorrect argument for format string
// LOG("%s %d %u %lf %f %c", "hi", -1, 12u, 1, 1.33, 'c');
}
I2luY2x1ZGUgPGNzdGRkZWY+CiNpbmNsdWRlIDxjc3RkaW8+CiNpbmNsdWRlIDxzdGRleGNlcHQ+CiNpbmNsdWRlIDxib29zdC91dGlsaXR5L3N0cmluZ19yZWYuaHBwPgojaW5jbHVkZSA8Ym9vc3QvZm9ybWF0LmhwcD4KCiNpZm5kZWYgQk9PU1RfUFBfVkFSSUFESUNTCiMgICAgZGVmaW5lIEJPT1NUX1BQX1ZBUklBRElDUwojZW5kaWYKI2luY2x1ZGUgPGJvb3N0L3ByZXByb2Nlc3Nvci5ocHA+Cgp0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBUcz4Kc3RydWN0IEZvcm1hdAp7CiAgICB0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgogICAgc3RhdGljIGNvbnN0ZXhwciBib29sIGNoZWNrKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKTsKfTsKCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCnRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CmNvbnN0ZXhwciBib29sIGNoZWNrVmFsaWRGb3JtYXRzKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzaXplX3QgbiwgY2hhciBjKQp7CiAgICByZXR1cm4gbiA+PSBOID8KICAgICAgICAgICAgdGhyb3cgc3RkOjpsb2dpY19lcnJvcigiaW52YWxpZCBmb3JtYXQgZm9yIHR5cGUiKQogICAgICAgIDogZm10W25dID09IGMgPwogICAgICAgICAgICB0cnVlCiAgICAgICAgOiBjaGVja1ZhbGlkRm9ybWF0cyhmbXQsIG4gKyAxLCBjKTsKfQoKdGVtcGxhdGU8Y2xhc3M+CnN0cnVjdCBUeXBlOwoKI2RlZmluZSBTVVBQT1JURURfVFlQRShULCBGbXRzKSBcCnRlbXBsYXRlPD4gXApzdHJ1Y3QgVHlwZTxUPiBcCnsgXAogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4gXAogICAgY29uc3RleHByIHN0YXRpYyBib29sIGNoZWNrKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKSBcCiAgICB7IFwKICAgICAgICByZXR1cm4gbiA+PSBOID8gXAogICAgICAgICAgICAgICAgdGhyb3cgc3RkOjpsb2dpY19lcnJvcigiaW52YWxpZCBmb3JtYXQgZm9yIHR5cGUiKSBcCiAgICAgICAgICAgIDogY2hlY2tWYWxpZEZvcm1hdHMoRm10cywgMCwgZm10W25dKTsgXAogICAgfSBcCn0KClNVUFBPUlRFRF9UWVBFKGNoYXIsICAgICAgICAgICAgICAiYyIpOwpTVVBQT1JURURfVFlQRShpbnQ4X3QsICAgICAgICAgICAgImNkIik7ClNVUFBPUlRFRF9UWVBFKHVpbnQ4X3QsICAgICAgICAgICAiY3UiKTsKU1VQUE9SVEVEX1RZUEUoaW50MTZfdCwgICAgICAgICAgICJkIik7ClNVUFBPUlRFRF9UWVBFKHVpbnQxNl90LCAgICAgICAgICAidSIpOwpTVVBQT1JURURfVFlQRShpbnQzMl90LCAgICAgICAgICAgImQiKTsKU1VQUE9SVEVEX1RZUEUodWludDMyX3QsICAgICAgICAgICJ1Iik7ClNVUFBPUlRFRF9UWVBFKGNoYXIqLCAgICAgICAgICAgICAicyIpOwpTVVBQT1JURURfVFlQRSh1bnNpZ25lZCBjaGFyKiwgICAgInMiKTsKU1VQUE9SVEVEX1RZUEUoY29uc3QgY2hhciosICAgICAgICJzIik7ClNVUFBPUlRFRF9UWVBFKHN0ZDo6c3RyaW5nLCAgICAgICAicyIpOwpTVVBQT1JURURfVFlQRShib29zdDo6c3RyaW5nX3JlZiwgInMiKTsKU1VQUE9SVEVEX1RZUEUoZG91YmxlLCAgICAgICAgICAgICJmIik7ClNVUFBPUlRFRF9UWVBFKGZsb2F0LCAgICAgICAgICAgICAiZiIpOwoKI2RlZmluZSBTVVBQT1JURURfTExfVFlQRShULCBDKSBcCnRlbXBsYXRlPD4gXApzdHJ1Y3QgVHlwZTxUPiBcCnsgXAogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4gXAogICAgc3RhdGljIGNvbnN0ZXhwciBib29sIGNoZWNrKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKSBcCiAgICB7IFwKICAgICAgICByZXR1cm4gbiA8IE4gJiYgXAogICAgICAgICAgICAgICBuIC0gMiA+PSAwICYmIFwKICAgICAgICAgICAgICAgZm10W25dICAgICA9PSBDICAgJiYgXAogICAgICAgICAgICAgICBmbXRbbiAtIDFdID09ICdsJyAmJiBcCiAgICAgICAgICAgICAgIGZtdFtuIC0gMl0gPT0gJ2wnID8gXAogICAgICAgICAgICAgICAgICAgIHRydWUgXAogICAgICAgICAgICA6IHRocm93IHN0ZDo6bG9naWNfZXJyb3IoImludmFsaWQgZm9ybWF0IGZvciB0eXBlIik7IFwKICAgIH0gXAp9CgpTVVBQT1JURURfTExfVFlQRShpbnQ2NF90LCAgJ2QnKTsKU1VQUE9SVEVEX0xMX1RZUEUodWludDY0X3QsICd1Jyk7Cgp0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBUcz4Kc3RydWN0IEFyZ3VtZW50CnsKICAgIHRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CiAgICBzdGF0aWMgY29uc3RleHByIGJvb2wgY2hlY2soY29uc3QgY2hhciAoJilbTl0sIHN0ZDo6c2l6ZV90KQogICAgewogICAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KfTsKCnRlbXBsYXRlPHR5cGVuYW1lIFQsIHR5cGVuYW1lLi4uIFRzPgpzdHJ1Y3QgQXJndW1lbnQ8VCwgVHMuLi4+CnsKICAgIHRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CiAgICBzdGF0aWMgY29uc3RleHByIGJvb2wgY2hlY2soY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4pCiAgICB7CiAgICAgICAgLy8gICAgJVs8ZmxhZ3M+XVs8d2lkdGg+XVsuPHByZWNpc2lvbj5dWzxsZW5ndGg+XTxzcGVjaWZpZXI+CiAgICAgICAgLy8gICAgICAgIHNwZWNpZmllciA6PSBkfGl8dXxvfHh8WHxmfEZ8ZXxFfGd8R3xhfEF8Y3xzfHB8bgogICAgICAgIHJldHVybiBUeXBlPCB0eXBlbmFtZSBzdGQ6OmRlY2F5PFQ+Ojp0eXBlPjo6Y2hlY2soZm10LCBuKSAmJgogICAgICAgICAgICAgICAgRm9ybWF0PFRzLi4uPjo6Y2hlY2soZm10LCBuICsgMSk7CiAgICB9Cn07CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCnRlbXBsYXRlPHNpemVfdCBOPgpjb25zdGV4cHIgYm9vbCBpc0RvdWJsZUxlbmd0aFNwZWNpZmllcihjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbikKewogICAgLy8gaGggfCBsbAogICAgcmV0dXJuIG4gKyAyIDwgTiAmJgogICAgICAgICAgICgoZm10W25dID09ICdoJyAmJiBmbXRbbiArIDFdID09ICdoJykgfHwKICAgICAgICAgICAgKGZtdFtuXSA9PSAnbCcgJiYgZm10W24gKyAxXSA9PSAnbCcpKTsKfQoKdGVtcGxhdGU8c2l6ZV90IE4+CmNvbnN0ZXhwciBib29sIGlzU2luZ2xlTGVuZ3RoU3BlY2lmaWVyKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKQp7CiAgICAvLyBoIHwgbCB8IGogfCB6IHwgdCB8IEwKICAgIHJldHVybiBuICsgMSA8IE4gJiYKICAgICAgICAgICAoZm10W25dID09ICdoJyB8fAogICAgICAgICAgICBmbXRbbl0gPT0gJ2wnIHx8CiAgICAgICAgICAgIGZtdFtuXSA9PSAnaicgfHwKICAgICAgICAgICAgZm10W25dID09ICd6JyB8fAogICAgICAgICAgICBmbXRbbl0gPT0gJ3QnIHx8CiAgICAgICAgICAgIGZtdFtuXSA9PSAnTCcpOwp9Cgp0ZW1wbGF0ZTxzaXplX3QgTj4KY29uc3RleHByIHNpemVfdCBuZXh0Tm9uTGVuZ3RoU3BlY2lmaWVyKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKQp7CiAgICByZXR1cm4KICAgICAgICAgICAgaXNEb3VibGVMZW5ndGhTcGVjaWZpZXIoZm10LCBuKSA/IG4gKyAyCiAgICAgICAgICA6IGlzU2luZ2xlTGVuZ3RoU3BlY2lmaWVyKGZtdCwgbikgPyBuICsgMQogICAgICAgICAgOiBuOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBUcz4Kc3RydWN0IExlbmd0aAp7CiAgICB0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgogICAgc3RhdGljIGNvbnN0ZXhwciBib29sIGNoZWNrKGNvbnN0IGNoYXIgKCYpW05dLCBzdGQ6OnNpemVfdCkKICAgIHsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICB9Cn07Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBUcz4Kc3RydWN0IExlbmd0aDxULCBUcy4uLj4KewogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KICAgIHN0YXRpYyBjb25zdGV4cHIgYm9vbCBjaGVjayhjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbikKICAgIHsKICAgICAgICAvLyAgICAlWzxmbGFncz5dWzx3aWR0aD5dWy48cHJlY2lzaW9uPl1bPGxlbmd0aD5dPHNwZWNpZmllcj4KICAgICAgICAvLyAgICAgICAgbGVuZ3RoICAgIDo9IGhofGh8bHxsbHxqfHp8dHxMCiAgICAgICAgcmV0dXJuIEFyZ3VtZW50PFQsIFRzLi4uPjo6Y2hlY2soZm10LCBuZXh0Tm9uTGVuZ3RoU3BlY2lmaWVyKGZtdCwgbikpOwogICAgfQp9OwoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgpjb25zdGV4cHIgc2l6ZV90IG5leHROb25MaXRlcmFsUHJlY2lzaW9uKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKQp7CiAgICByZXR1cm4KICAgICAgICBuID49IE4gPwogICAgICAgICAgICB0aHJvdyBzdGQ6OmxvZ2ljX2Vycm9yKCJpbnZhbGlkIGZvcm1hdCBzdHJpbmcgLSBwYXJzaW5nIHByZWNpc2lvbiIpCiAgICAgICAgOiBmbXRbbl0gPj0gJzAnICYmIGZtdFtuXSA8PSAnOScgPwogICAgICAgICAgICAgICAgbmV4dE5vbkxpdGVyYWxQcmVjaXNpb24oZm10LCBuICsgMSkKICAgICAgICA6IG47Cn0KCnRlbXBsYXRlPHR5cGVuYW1lLi4uIFRzPgpzdHJ1Y3QgUHJlY2lzaW9uCnsKICAgIHRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CiAgICBzdGF0aWMgY29uc3RleHByIGJvb2wgY2hlY2soY29uc3QgY2hhciAoJilbTl0sIHN0ZDo6c2l6ZV90KQogICAgewogICAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KfTsKCnRlbXBsYXRlPHR5cGVuYW1lIFQsIHR5cGVuYW1lLi4uIFRzPgpzdHJ1Y3QgUHJlY2lzaW9uPFQsIFRzLi4uPgp7CiAgICB0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgogICAgc3RhdGljIGNvbnN0ZXhwciBib29sIGNoZWNrKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKQogICAgewogICAgICAgIC8vICAgICVbPGZsYWdzPl1bPHdpZHRoPl1bLjxwcmVjaXNpb24+XVs8bGVuZ3RoPl08c3BlY2lmaWVyPgogICAgICAgIC8vICAgICAgICBwcmVjaXNpb24gOj0gPG51bWJlcj58JyonICAgICAgICAvLyBBIG51bWJlciBvciBhICcqJwoKICAgICAgICAvLyBpZiBwcmVjaXNpb24gaXMgYSBwcm92aWRlZCBhcmd1bWVudCwgdmFsaWRhdGUgaXQgaXMgaW50ZWdyYWwKICAgICAgICByZXR1cm4gbiArIDEgPCBOICYmIGZtdFtuXSA9PSAnLicgJiYgZm10W24gKyAxXSA9PSAnKicgPwogICAgICAgICAgICAgICAgc3RkOjppc19pbnRlZ3JhbDxUPjo6dmFsdWUgJiYgTGVuZ3RoPFRzLi4uPjo6Y2hlY2soZm10LCBuICsgMikKCiAgICAgICAgLy8gb3RoZXJ3aXNlIHNraXAgb3ZlciBhbnkgbGl0ZXJhbCBwcmVjaXNpb24KICAgICAgICA6IG4gKyAxIDwgTiAmJiBmbXRbbl0gPT0gJy4nID8KICAgICAgICAgICAgICAgIExlbmd0aDxULCBUcy4uLj46OmNoZWNrKGZtdCwgbmV4dE5vbkxpdGVyYWxQcmVjaXNpb24oZm10LCBuICsgMSkpCgogICAgICAgIDogTGVuZ3RoPFQsIFRzLi4uPjo6Y2hlY2soZm10LCBuKTsKICAgIH0KfTsKCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KY29uc3RleHByIHNpemVfdCBuZXh0Tm9uTGl0ZXJhbFdpZHRoKGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKQp7CiAgICByZXR1cm4KICAgICAgICBuID49IE4gPwogICAgICAgICAgICB0aHJvdyBzdGQ6OmxvZ2ljX2Vycm9yKCJpbnZhbGlkIGZvcm1hdCBzdHJpbmcgLSBwYXJzaW5nIHdpZHRoIikKICAgICAgICA6IGZtdFtuXSA+PSAnMCcgJiYgZm10W25dIDw9ICc5JyA/CiAgICAgICAgICAgIG5leHROb25MaXRlcmFsV2lkdGgoZm10LCBuICsgMSkKICAgICAgICA6IG47Cn0KCnRlbXBsYXRlPHR5cGVuYW1lLi4uIFRzPgpzdHJ1Y3QgV2lkdGgKewogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KICAgIHN0YXRpYyBjb25zdGV4cHIgYm9vbCBjaGVjayhjb25zdCBjaGFyICgmKVtOXSwgc3RkOjpzaXplX3QpCiAgICB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQp9OwoKdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUuLi4gVHM+CnN0cnVjdCBXaWR0aDxULCBUcy4uLj4KewogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KICAgIHN0YXRpYyBjb25zdGV4cHIgYm9vbCBjaGVjayhjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbikKICAgIHsKICAgICAgICAvLyAgICAlWzxmbGFncz5dWzx3aWR0aD5dWy48cHJlY2lzaW9uPl1bPGxlbmd0aD5dPHNwZWNpZmllcj4KICAgICAgICAvLyAgICAgICAgd2lkdGggICAgIDo9IDxudW1iZXI+fCcqJyAgICAgICAgLy8gQSBudW1iZXIgb3IgYSAnKicKCiAgICAgICAgLy8gaWYgd2lkdGggaXMgYSBwcm92aWRlZCBhcmd1bWVudCwgdmFsaWRhdGUgaXQgaXMgaW50ZWdyYWwKICAgICAgICByZXR1cm4gZm10W25dID09ICcqJyA/CiAgICAgICAgICAgICAgICBzdGQ6OmlzX2ludGVncmFsPFQ+Ojp2YWx1ZSAmJiBQcmVjaXNpb248VHMuLi4+OjpjaGVjayhmbXQsIG4gKyAxKQoKICAgICAgICAvLyBvdGhlcndpc2Ugc2tpcCBvdmVyIGFueSBsaXRlcmFsIHdpZHRoCiAgICAgICAgOiBQcmVjaXNpb248VCwgVHMuLi4+OjpjaGVjayhmbXQsIG5leHROb25MaXRlcmFsV2lkdGgoZm10LCBuKSk7CiAgICB9Cn07CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCnRlbXBsYXRlPHNpemVfdCBOPgpjb25zdGV4cHIgYm9vbCBpc0ZsYWcoY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4pCnsKICAgIHJldHVybiBuICsgMSA8IE4gJiYKICAgICAgICAgIChmbXRbbl0gPT0gJy0nIHx8CiAgICAgICAgICAgZm10W25dID09ICcrJyB8fAogICAgICAgICAgIGZtdFtuXSA9PSAnICcgfHwKICAgICAgICAgICBmbXRbbl0gPT0gJyMnIHx8CiAgICAgICAgICAgZm10W25dID09ICcwJyk7Cn0KCnRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CmNvbnN0ZXhwciBzaXplX3QgbmV4dE5vbkZsYWcoY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4pCnsKICAgIHJldHVybgogICAgICAgIG4gPj0gTiA/CiAgICAgICAgICAgIHRocm93IHN0ZDo6bG9naWNfZXJyb3IoImludmFsaWQgZm9ybWF0IHN0cmluZyIpCiAgICAgICAgOiBpc0ZsYWcoZm10LCBuKSA/CiAgICAgICAgICAgIG5leHROb25GbGFnKGZtdCwgbiArIDEpCiAgICAgICAgOiBuOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBUcz4Kc3RydWN0IEZsYWdzCnsKICAgIHRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CiAgICBzdGF0aWMgY29uc3RleHByIGJvb2wgY2hlY2soY29uc3QgY2hhciAoJmZtdClbTl0sIHN0ZDo6c2l6ZV90IG4pCiAgICB7CiAgICAgICAgLy8gICAgJVs8ZmxhZ3M+XVs8d2lkdGg+XVsuPHByZWNpc2lvbj5dWzxsZW5ndGg+XTxzcGVjaWZpZXI+CiAgICAgICAgLy8gICAgICAgIGZsYWdzICAgICA6PSBbLSsgIzBdKiAgICAgICAgICAgIC8vIFplcm8gb3IgbW9yZQogICAgICAgIHJldHVybiBXaWR0aDxULCBUcy4uLj46OmNoZWNrKGZtdCwgbmV4dE5vbkZsYWcoZm10LCBuKSk7CiAgICB9Cn07CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCnRlbXBsYXRlPHNpemVfdCBOPgpjb25zdGV4cHIgYm9vbCBpc0xpdGVyYWxQZXJjZW50KGNvbnN0IGNoYXIgKCZmbXQpW05dLCBzdGQ6OnNpemVfdCBuKQp7CiAgICByZXR1cm4gbiArIDEgPD0gTiAmJiBmbXRbbl0gPT0gJyUnICYmIGZtdFtuICsgMV0gPT0gJyUnOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBUcz4Kc3RydWN0IEZvcm1hdDxULCBUcy4uLj4KewogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KICAgIHN0YXRpYyBjb25zdGV4cHIgYm9vbCBjaGVjayhjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbikKICAgIHsKICAgICAgICByZXR1cm4KICAgICAgICAgICAgbiA+PSBOID8KICAgICAgICAgICAgICAgIHRocm93IHN0ZDo6bG9naWNfZXJyb3IoInRvbyBtYW55IGFyZ3VtZW50cyBmb3IgcHJvdmlkZWQgZm9ybWF0IHN0cmluZyIpCgogICAgICAgICAgICAvLyBza2lwIG5vbi1mb3JtYXQgc3BlY2lmaWVycyAoaWU6IG5vdCBhICUgY2hhcmFjdGVyKQogICAgICAgICAgICA6IGZtdFtuXSAhPSAnJScgPwogICAgICAgICAgICAgICAgRm9ybWF0PFQsIFRzLi4uPjo6Y2hlY2soZm10LCBuICsgMSkKCiAgICAgICAgICAgIC8vICUlCiAgICAgICAgICAgIDogaXNMaXRlcmFsUGVyY2VudChmbXQsIG4pID8KICAgICAgICAgICAgICAgIEZvcm1hdDxULCBUcy4uLj46OmNoZWNrKGZtdCwgbiArIDIpCgogICAgICAgICAgICAvLyB3ZSd2ZSBmb3VuZCBhIGZvcm1hdCBzcGVjaWZpZXIKICAgICAgICAgICAgOiBGbGFnczxULCBUcy4uLj46OmNoZWNrKGZtdCwgbiArIDEpOwogICAgfQp9OwoKdGVtcGxhdGU8PgpzdHJ1Y3QgRm9ybWF0PD4KewogICAgdGVtcGxhdGU8c3RkOjpzaXplX3QgTj4KICAgIHN0YXRpYyBjb25zdGV4cHIgYm9vbCBjaGVjayhjb25zdCBjaGFyICgmZm10KVtOXSwgc3RkOjpzaXplX3QgbikKICAgIHsKICAgICAgICByZXR1cm4KICAgICAgICAgICAgbj49IE4gPwogICAgICAgICAgICAgICAgdHJ1ZQogICAgICAgICAgICA6IGZtdFtuXSAhPSAnJScgPwogICAgICAgICAgICAgICAgY2hlY2soZm10LCBuICsgMSkKICAgICAgICAgICAgOiBmbXRbbiArIDFdID09ICclJyA/CiAgICAgICAgICAgICAgICBjaGVjayhmbXQsIG4gKyAyKQogICAgICAgICAgICA6IHRocm93IHN0ZDo6bG9naWNfZXJyb3IoInRvbyBmZXcgYXJndW1lbnRzIGZvciBwcm92aWRlZCBmb3JtYXQgc3RyaW5nIik7CiAgICB9Cn07CgovLy8vLy8vLy8vLy8vLy8vCgovLyBwcmludGluZy4uLgoKdm9pZCBhZGQoYm9vc3Q6OmZvcm1hdCYpCnsgfQoKdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUuLi4gVHM+CnZvaWQgYWRkKGJvb3N0Ojpmb3JtYXQmIGYsIGNvbnN0IFQmIGFyZywgY29uc3QgVHMmLi4uIHRzKQp7CiAgICBmICUgYXJnOwogICAgYWRkKGYsIHRzLi4uKTsKfQoKLy8vLy8vLy8vLy8vLy8vLwoKI2RlZmluZSBQUF9QQVJFTlRIRVNJU0VfV0lUSF9UT0tFTihyLCB0b2tlbiwgaSwgZSkgXAogICAgQk9PU1RfUFBfQ09NTUFfSUYoaSkgdG9rZW4oZSkKCiNkZWZpbmUgUFBfQ1NWX1NFUV9QQVJFTlRIRVNJU0VfV0lUSF9UT0tFTiguLi4pIFwKICAgIEJPT1NUX1BQX1NFUV9GT1JfRUFDSF9JKFBQX1BBUkVOVEhFU0lTRV9XSVRIX1RPS0VOLCBkZWNsdHlwZSwgQk9PU1RfUFBfVkFSSUFESUNfVE9fU0VRKF9fVkFfQVJHU19fKSkKCiNkZWZpbmUgUFBfUEVSRk9STV9MT0dfRk9STUFUX0NIRUNLKGZtdCwgLi4uKSBcCiAgICBGb3JtYXQ8Qk9PU1RfUFBfSUYoQk9PU1RfUFBfRVFVQUwoQk9PU1RfUFBfVFVQTEVfU0laRSgoLCMjX19WQV9BUkdTX18pKSwgMSksIFwKICAgICAgICAgICAgQk9PU1RfUFBfRVhQQU5ELCBQUF9DU1ZfU0VRX1BBUkVOVEhFU0lTRV9XSVRIX1RPS0VOKShfX1ZBX0FSR1NfXyk+OjpjaGVjayhmbXQsIDApCgojZGVmaW5lIExPRyhmbXQsIC4uLikgXAogICAgeyBcCiAgICAgICAgc3RhdGljX2Fzc2VydChQUF9QRVJGT1JNX0xPR19GT1JNQVRfQ0hFQ0soZm10LCAjI19fVkFfQVJHU19fKSwgIiIpOyBcCiAgICAgICAgYm9vc3Q6OmZvcm1hdCBmKGZtdCk7IFwKICAgICAgICBhZGQoZiwgIyNfX1ZBX0FSR1NfXyk7IFwKICAgICAgICBzdGQ6OmNvdXQgPDwgZi5zdHIoKSA8PCBzdGQ6OmVuZGw7IFwKICAgIH0KCmludCBtYWluKCkKewogICAgLy8gbm90aGluZwogICAgTE9HKCJoZWxsbyB3b3JsZCIpOwoKICAgIC8vIGNoYXIKICAgIExPRygiJWMiLCAneCcpOwoKICAgIC8vIGludGVncmFsCiAgICBMT0coIiVkIiwgLTEyMyk7CiAgICBMT0coIiVsZCIsIC0xMjMpOwogICAgTE9HKCIldSIsIDEyM3UpOwogICAgTE9HKCIlbHUiLCAxMjN1KTsKCiAgICAvLyBzdHJpbmdzCiAgICBMT0coIiVzIiwgImhlbGxvIHdvcmxkIik7CiAgICBMT0coIiUtcyIsICJoZWxsbyB3b3JsZCIpOwogICAgTE9HKCIlcyIsIHN0ZDo6c3RyaW5nKCJoZWxsbyB3b3JsZCIpKTsKICAgIHsgY29uc3QgY2hhciogcyA9ICJoZWxsbyB3b3JsZCI7IExPRygiJXMiLCBzKTsgfQogICAgeyBzdGQ6OnN0cmluZyBzID0gImhlbGxvIHdvcmxkIjsgTE9HKCIlcyIsIHMpOyB9CiAgICB7IHN0ZDo6c3RyaW5nIHMgPSAiaGVsbG8gd29ybGQiOyBib29zdDo6c3RyaW5nX3JlZiByKHMpOyBMT0coIiVzIiwgcik7IH0KCiAgICAvLyBmbG9hdGluZyBwb2ludAogICAgTE9HKCIlZiIsIDEuMjMpOwogICAgTE9HKCIlZiIsIDEuMjNmKTsKCiAgICAvLyB3aWR0aCAmIHByZWNpc2lvbgogICAgTE9HKCIlMDJkIiwgMSk7CiAgICBMT0coIiUgM3MiLCAiaGVsbG8iKTsKICAgIExPRygiJSAzcyIsICJ5byIpOwogICAgTE9HKCIlLjJkIiwgMTIzKTsKICAgIExPRygiJS4yZiIsIDEuMjM0NSk7CiAgICBMT0coIiUyZiIsIDEuMjM0NTY3ODkpOwogICAgTE9HKCIlMDJmIiwgMC4xKTsKICAgIExPRygiJTAyLjJmIiwgMC4xKTsKCiAgICAvLyB3aWR0aCAmIHByZWNpc2lvbiBhcyBhcmd1bWVudHMKICAgIC8vIG5vdCBzdXBwb3J0ZWQgYnkgYm9vc3Q6OmZvcm1hdAovLyAgICBMT0coIiUqZCIsIDMsIDEyKTsKLy8gICAgTE9HKCIlLipzIiwgMywgImhlbGxvIik7Ci8vICAgIExPRygiJS4qZCIsIDMsIDEyMzQ1KTsKLy8gICAgTE9HKCIlKi4qcyIsIDMsIDMsICJoZWxsbyIpOwovLyAgICBMT0coIiUqLipkIiwgMywgMywgMTIzNDUpOwoKICAgIC8vIG1peCBvZiBtdWx0aXBsZSBkaWZmZXJlbnQgYXJndW1lbnRzCiAgICBMT0coIiVzIiwgImhpIik7CiAgICBMT0coIiVzICVkIiwgImhpIiwgMSk7CiAgICBMT0coIiVzICVkICV1ICVsZiAlZiAlYyIsICJoaSIsIC0xLCAxMnUsIDEuMjMsIDEuMzMsICdjJyk7CgogICAgLy8gdG9vIGZldyBhcmd1bWVudHMKLy8gICAgTE9HKCIlcyAlZCAldSAlbGYgJWYgJWMiLCAiaGkiLCAtMSwgMTJ1LCAxLjIzLCAxLjMzKTsKCiAgICAvLyB0b28gbWFueSBhcmd1bWVudHMKLy8gICAgTE9HKCIlcyAlZCAldSAlbGYgJWYgJWMiLCAiaGkiLCAtMSwgMTJ1LCAxLjIzLCAxLjMzLCAnYycsIDEpOwoKICAgIC8vIGluY29ycmVjdCBhcmd1bWVudCBmb3IgZm9ybWF0IHN0cmluZwovLyAgICBMT0coIiVzICVkICV1ICVsZiAlZiAlYyIsICJoaSIsIC0xLCAxMnUsIDEsIDEuMzMsICdjJyk7Cn0=