//---------------------------------------------------------------------------------------
#include <iostream>
#include <string>
//---------------------------------------------------------------------------------------
#define CSTR
using i8 = char ;
using u8 = unsigned char ;
using i16 = short ;
using u16 = unsigned short ;
using i32 = int ;
using u32 = unsigned int ;
using i64 = long long ;
using u64 = unsigned long long ;
using f32 = float ;
using f64 = double ;
#define rigid constexpr
//---------------------------------------------------------------------------------------
rigid u32 CHAR_BITS = 8 ;
template < typename T >
inline rigid auto msb( )
{
return sizeof ( T ) * CHAR_BITS - 1 ;
}
template < typename T >
inline rigid auto msb_value( )
{
return ( T) 1 << msb< T > ( ) ;
}
#define msb_pos( var ) msb< decltype( var ) >()
#define msb_val( var ) msb_value< decltype( var ) >()
template < typename T0, typename T1 >
inline void set_msbs( T0& dst, const T1 bits )
{
* ( ( T1* ) & dst + ( sizeof dst / sizeof bits - 1 ) ) | = bits;
}
//---------------------------------------------------------------------------------------
template < typename TR >
inline TR atou( char * & s )
{
TR value;
for ( value = 0 ; * s <= '9' && * s >= '0' ; ++ s )
value = value * 10 + ( * s & 0xF ) ;
return value;
}
template < typename TR >
inline TR atoi ( char * & s )
{
if ( * s == '-' )
return ( TR) ( - 1 * atou< TR > ( ++ s ) ) ;
return ( TR) atou< TR > ( s ) ;
}
#include <cmath>
template < typename T = f64 >
inline T atof ( char * & s )
{
char * p = s;
u32 sign = 0 ;
T digit = 0 .;
T base = 1 .;
T step = 1 .;
for ( i8 token; token = * p++ ; )
{
switch ( token )
{
case '-' :
sign = msb_val( sign ) ;
break ;
case '.' :
step = 10 ;
break ;
case 'E' :
case 'e' :
digit * = ( T) std:: pow ( 10 ., ( f64) atof < T > ( s = p ) ) ;
goto exit ;
default :
if ( token <= '9' && token >= '0' )
{
digit = digit * 10 + ( token & 0xF ) ;
base * = step;
continue ;
}
goto exit ;
}
}
exit :
if ( s < p - 1 ) s = p - 1 ;
set_msbs( digit, sign ) ;
return T( digit / base ) ;
}
//---------------------------------------------------------------------------------------
#include <string>
#include <stdarg.h>
template < const u32 MAX_SIZE = 1024 >
inline std:: string format_string( const char * format, ... )
{
char temp[ MAX_SIZE ] ;
va_list va;
va_start ( va, format ) ;
vsprintf ( temp, format, va ) ;
va_end ( va ) ;
return temp;
}
//---------------------------------------------------------------------------------------
#include <type_traits>
template < typename T >
inline rigid auto is_signed_( )
{
return std:: is_same < T, i8 > :: value || std:: is_same < T, i16 > :: value ||
std:: is_same < T, i32 > :: value || std:: is_same < T, i64 > :: value ;
}
template < typename T >
inline rigid auto is_unsigned_( )
{
return std:: is_same < T, u8 > :: value || std:: is_same < T, u16 > :: value ||
std:: is_same < T, u32 > :: value || std:: is_same < T, u64 > :: value ;
}
template < typename T >
inline rigid auto is_floating_( )
{
return std:: is_same < T, f32 > :: value || std:: is_same < T, f64 > :: value ;
}
template < typename T >
inline char * parse_number( const char * string, T& param )
{
char * s = ( char * ) string;
while ( * s <= ' ' || * s == '/' || * s == ':' ) s++ ;
if ( is_signed_< T > ( ) )
{
param = atoi < T > ( s ) ;
}
else if ( is_unsigned_< T > ( ) )
{
param = atou< T > ( s ) ;
}
else if ( is_floating_< T > ( ) )
{
param = atof < T > ( s ) ;
}
return s;
}
template < typename T, typename ... Ts >
inline char * parse_number( const char * string, T& param1, Ts& ... rest )
{
return parse_number( parse_number( string, param1 ) , rest... ) ;
}
//---------------------------------------------------------------------------------------
rigid i32 msecs_in_1sec = 1000 ;
rigid i32 secs_in_1min = 60 ;
rigid i32 mins_in_1hour = 60 ;
rigid i32 hours_in_1day = 24 ;
rigid i32 secs_in_1hour = mins_in_1hour * secs_in_1min;
rigid i32 mins_in_1day = hours_in_1day * mins_in_1hour;
rigid i32 secs_in_1day = mins_in_1day * secs_in_1min;
rigid i32 msecs_in_1day = secs_in_1day * msecs_in_1sec;
rigid i32 value_of_1day = secs_in_1day;
rigid i32 days_in_1year = 365 ;
rigid i32 days_in_4years = days_in_1year * 4 + 1 ;
rigid i32 days_in_100years = days_in_4years * 25 - 1 ;
rigid i32 days_in_400years = days_in_100years * 4 + 1 ;
rigid i32 secs_in_1year = days_in_1year * secs_in_1day;
rigid i64 years_in_bc = 100000000000LL;
rigid i64 days_in_bc = years_in_bc / 400 * days_in_400years;
rigid i64 secs_in_bc = days_in_bc * secs_in_1day;
rigid i64 days_in_bc_greg = days_in_400years * years_in_bc / 400 ;
rigid i64 days_in_bc_juli = days_in_4years * years_in_bc / 4 ;
rigid i64 juli_to_greg = days_in_bc_greg - days_in_bc_juli - 2 ;
rigid i32 final_day_fragment = ( u64) - 1 - ( u64) - 1 / value_of_1day * value_of_1day;
rigid u32 sum_days100[ 4 ] [ 14 ]
{
{ 0 , 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 , 365 , } ,
{ 0 , 365 , 396 , 424 , 455 , 485 , 516 , 546 , 577 , 608 , 638 , 669 , 699 , 730 , } ,
{ 0 , 730 , 761 , 789 , 820 , 850 , 881 , 911 , 942 , 973 , 1003 , 1034 , 1064 , 1095 , } ,
{ 0 , 1095 , 1126 , 1154 , 1185 , 1215 , 1246 , 1276 , 1307 , 1338 , 1368 , 1399 , 1429 , 1460 , } ,
} ;
rigid u32 sum_days[ 4 ] [ 14 ]
{
{ 0 , 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 , 365 , } ,
{ 0 , 365 , 396 , 424 , 455 , 485 , 516 , 546 , 577 , 608 , 638 , 669 , 699 , 730 , } ,
{ 0 , 730 , 761 , 789 , 820 , 850 , 881 , 911 , 942 , 973 , 1003 , 1034 , 1064 , 1095 , } ,
{ 0 , 1095 , 1126 , 1155 , 1186 , 1216 , 1247 , 1277 , 1308 , 1339 , 1369 , 1400 , 1430 , 1461 , } ,
} ;
const char * day_names[ ]
{
"Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" , "Sun" ,
} ;
//---------------------------------------------------------------------------------------
template < typename T0, typename T1, typename T2 >
inline auto times( const T0 hours, const T1 mins, const T2 secs )
{
return hours * secs_in_1hour + mins * secs_in_1min + secs;
}
template < typename T >
inline u64 days( const T days )
{
return days * secs_in_1day;
}
inline u64 seconds( const u64 secs )
{
return secs;
}
///--------------------------------------------------------------------------------------
enum class DATE_METHOD
{
julian,
gregorian,
} ;
template < DATE_METHOD method = DATE_METHOD:: gregorian >
class DATE_
{
private :
u64 secs;
void date_parsing( const char * date_string )
{
i64 year;
u32 month, day;
parse_number( date_string, year, month, day ) ;
encode( year, month, day ) ;
}
public :
CSTR DATE_( ) : secs( 0 )
{ }
CSTR explicit DATE_( const u64 secs ) : secs( secs )
{ }
CSTR DATE_( const i64 year, const u32 mm, const u32 dd )
{
encode( year, mm, dd ) ;
}
CSTR DATE_( const i64 year, const u32 mm, const u32 dd,
const u32 hh, const u32 nn, const u32 ss )
{
encode( year, mm, dd ) ;
secs + = times( hh, nn, ss ) ;
}
CSTR explicit DATE_( const char * date_string )
{
date_parsing( date_string ) ;
}
CSTR explicit DATE_( const std:: string date_string )
{
date_parsing( date_string.c_str ( ) ) ;
}
void encode( const i64 year, const u32 month, const u32 day )
{
u64 xx = year + years_in_bc - ( year > 0 ) ;
if ( method == DATE_METHOD:: gregorian )
{
secs = xx / 400 * days_in_400years;
u32 x2 = xx % 400 ;
u32 y1 = x2 / 100 * days_in_100years;
u32 x1 = x2 % 100 ;
u32 y0 = x1 / 4 * days_in_4years;
u32 x0 = x1 % 4 ;
auto s = sum_days[ x0 ] ;
if ( x2 ! = 399 && x1 == 99 )
s = sum_days100[ x0 ] ;
secs + = y1 + y0 + s[ month ] + day - 1 ;
}
else
{
secs = xx / 4 * days_in_4years +
( sum_days[ xx % 4 ] [ month ] + day + ( juli_to_greg - 1 ) ) ;
}
secs * = value_of_1day;
}
void decode( i64& year, u32& month, u32& day ) const
{
u64 xx = secs / value_of_1day;
u32 x, y;
year = - years_in_bc;
auto s = sum_days;
if ( method == DATE_METHOD:: gregorian )
{
year + = xx / days_in_400years * 400 ;
u32 x2 = xx % days_in_400years;
u32 y1 = x2 / days_in_100years - x2 / ( days_in_100years * 4 ) ;
u32 x1 = x2 - days_in_100years * y1;
y1 = y1 * 100 ;
u32 y0 = x1 / days_in_4years * 4 ;
x = x1 % days_in_4years;
y = x / days_in_1year - x / ( days_in_1year * 4 ) ;
if ( y1 < 300 && y0 + y == 99 )
s = sum_days100;
year + = y1 + y0 + y;
}
else
{
xx - = juli_to_greg;
u64 y0 = xx / days_in_4years * 4 ;
x = xx % days_in_4years;
y = x / days_in_1year - x / ( days_in_1year * 4 ) ;
year + = y0 + y;
}
month = ( x - y * days_in_1year ) / 29 ;
month + = x >= s[ y ] [ month + 1 ] ;
day = x - s[ y ] [ month ] + 1 ;
year + = year >= 0 ;
}
///----------------------------------------------------------------------------------
const auto name( ) const
{
return day_names[ secs / value_of_1day % 7 ] ;
}
const auto date( bool ad_bc = false ) const
{
i64 year;
u32 month, day;
decode( year, month, day ) ;
if ( ! ad_bc )
return format_string( "%lld/%02u/%02u" , year, month, day ) ;
else
return format_string( "%s.%llu/%02u/%02u" , year > 0 ? "AD" : "BC" ,
std:: abs ( year ) , month, day ) ;
}
const auto time ( bool am_pm = false ) const
{
u32 hh, mm, ss;
ss = time_seconds( ) ;
hh = ss / secs_in_1hour;
ss = ss % secs_in_1hour;
mm = ss / secs_in_1min;
ss = ss % secs_in_1min;
return format_string( "%02u:%02u:%02u" , hh, mm, ss ) +
( am_pm ? ( hh < 12 ? " am" : " pm" ) : "" ) ;
}
const auto date_time( ) const
{
return date( ) + " " + time ( ) ;
}
const auto long_date( ) const
{
return std:: string ( method == DATE_METHOD:: gregorian ? "G:" : "J:" ) +
date( true ) + " " + name( ) ;
}
const auto long_date_time( ) const
{
return long_date( ) + " " + time ( true ) ;
}
///----------------------------------------------------------------------------------
const auto seconds( ) const
{
return secs;
}
const u32 time_seconds( ) const
{
return secs % secs_in_1day;
}
const auto days( ) const
{
return secs / secs_in_1day;
}
///----------------------------------------------------------------------------------
auto & operator- = ( const DATE_& rhs )
{
return secs - = rhs.secs , * this ;
}
auto & operator+ = ( const DATE_& rhs )
{
return secs + = rhs.secs , * this ;
}
template < DATE_METHOD M >
const auto operator- ( const DATE_< M > & rhs ) const
{
return DATE_< method > ( secs - rhs.seconds ( ) ) ;
}
template < DATE_METHOD M >
const auto operator+ ( const DATE_< M > & rhs ) const
{
return DATE_< method > ( secs + rhs.seconds ( ) ) ;
}
const auto operator- ( const u64 duration ) const
{
return DATE_< method > ( secs - duration ) ;
}
const auto operator+ ( const u64 duration ) const
{
return DATE_< method > ( secs + duration ) ;
}
auto & operator- = ( const u64 duration )
{
return secs - = duration, * this ;
}
auto & operator+ = ( const u64 duration )
{
return secs + = duration, * this ;
}
auto & operator-- ( )
{
return * this - = secs_in_1day;
}
auto & operator++ ( )
{
return * this + = secs_in_1day;
}
const bool operator< ( const DATE_& rhs ) const
{
return secs < rhs.secs ;
}
friend std:: ostream & operator<< ( std:: ostream & os, const DATE_& date )
{
return os << date.long_date_time ( ) ;
}
} ;
//---------------------------------------------------------------------------------------
using DATE = DATE_< DATE_METHOD:: gregorian > ;
using DATEJ = DATE_< DATE_METHOD:: julian > ;
inline auto historical_date( const DATE gregorian_date )
{
const auto julian_to_gregorian_date = DATE( 1582 ,10 ,15 ) ;
if ( gregorian_date < julian_to_gregorian_date )
return DATEJ( gregorian_date.seconds ( ) ) .long_date ( ) ;
return gregorian_date.long_date ( ) ;
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
using namespace std;
int main( )
{
cout << sizeof ( DATE ) <<
" bytes DATE_< Julian & Gregorian > type" << endl << endl;
cout << DATEJ( 0ULL ) << " ~ " << endl;
cout << DATEJ( 0xFFFFFFFFFFFFFFFFULL ) << endl;
cout << endl;
cout << DATE( 0ULL ) << " ~ " << endl;
cout << DATE( ( u64) - 1 ) << endl;
cout << endl;
cout << -- DATEJ( 1 , 1 , 1 ) << " == " << DATEJ( - 1 , 12 , 31 ) .seconds ( ) <<
" seconds " << endl;
cout << -- DATE( "1/ 1/ 1" ) << " == " << DATE( "1/ 1/ 1" ) .seconds ( ) <<
" seconds " << endl;
cout << endl;
cout << DATEJ( 1 , 1 , 1 ) << " == " <<
DATE( DATEJ( 1 , 1 , 1 ) .seconds ( ) ) .days ( ) << " th day " << endl;
cout << DATE( 1 , 1 , 1 ) << " == " <<
DATEJ( DATE( 1 , 1 , 1 ) .seconds ( ) ) .days ( ) << " th day " << endl;
cout << endl;
cout << DATE( 1582 , 10 , 14 ) << " == " <<
historical_date( DATE( "1582/10/14" ) ) << endl;
cout << DATE( 1582 , 10 , 15 ) << " == " <<
historical_date( DATE( "1582/10/15" ) ) << endl;
cout << endl;
cout << "Time methods" << endl << endl;
cout << DATE( times( 23 , 59 , 30 ) ) .time ( ) << endl;
cout << DATE( 2016 , 3 , 30 , 9 , 50 , 45 ) << endl;
cout << ( DATE( ) + days( days_in_bc ) + times( 23 , 59 , 30 ) + seconds( 30 ) )
.date_time ( ) << endl;
cout << endl;
getchar ( ) ;
return 0 ;
}
//---------------------------------------------------------------------------------------
Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c3RyaW5nPgovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKI2RlZmluZSBDU1RSCgp1c2luZyAgIGk4ICAgICAgICAgICAgICAgICAgICAgID0gY2hhcjsKdXNpbmcgICB1OCAgICAgICAgICAgICAgICAgICAgICA9IHVuc2lnbmVkIGNoYXI7CnVzaW5nICAgaTE2ICAgICAgICAgICAgICAgICAgICAgPSBzaG9ydDsKdXNpbmcgICB1MTYgICAgICAgICAgICAgICAgICAgICA9IHVuc2lnbmVkIHNob3J0Owp1c2luZyAgIGkzMiAgICAgICAgICAgICAgICAgICAgID0gaW50Owp1c2luZyAgIHUzMiAgICAgICAgICAgICAgICAgICAgID0gdW5zaWduZWQgaW50Owp1c2luZyAgIGk2NCAgICAgICAgICAgICAgICAgICAgID0gbG9uZyBsb25nOwp1c2luZyAgIHU2NCAgICAgICAgICAgICAgICAgICAgID0gdW5zaWduZWQgbG9uZyBsb25nOwoKdXNpbmcgICBmMzIgICAgICAgICAgICAgICAgICAgICA9IGZsb2F0Owp1c2luZyAgIGY2NCAgICAgICAgICAgICAgICAgICAgID0gZG91YmxlOwoKI2RlZmluZSByaWdpZCAgICAgICAgICAgICAgICAgICBjb25zdGV4cHIKCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpyaWdpZCAgIHUzMiBDSEFSX0JJVFMgICAgICAgICAgID0gODsKCnRlbXBsYXRlPCB0eXBlbmFtZSBUID4KaW5saW5lICByaWdpZCAgIGF1dG8gICAgbXNiKCkKewogICAgcmV0dXJuICBzaXplb2YoIFQgKSAqIENIQVJfQklUUyAtIDE7Cn0KCnRlbXBsYXRlPCB0eXBlbmFtZSBUID4KaW5saW5lICByaWdpZCAgIGF1dG8gICAgbXNiX3ZhbHVlKCkKewogICAgcmV0dXJuICAoVCkxIDw8IG1zYjwgVCA+KCk7Cn0KCiNkZWZpbmUgbXNiX3BvcyggdmFyICkgbXNiPCBkZWNsdHlwZSggdmFyICkgPigpCiNkZWZpbmUgbXNiX3ZhbCggdmFyICkgbXNiX3ZhbHVlPCBkZWNsdHlwZSggdmFyICkgPigpCgp0ZW1wbGF0ZTwgdHlwZW5hbWUgVDAsIHR5cGVuYW1lIFQxID4KaW5saW5lICB2b2lkICAgIHNldF9tc2JzKCBUMCYgZHN0LCBjb25zdCBUMSBiaXRzICkKewogICAgKiggKFQxKikmZHN0ICsgKCBzaXplb2YgZHN0IC8gc2l6ZW9mIGJpdHMgLSAxICkgKSB8PSBiaXRzOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgp0ZW1wbGF0ZTwgdHlwZW5hbWUgVFIgPgppbmxpbmUgIFRSICAgICAgYXRvdSggY2hhciomIHMgKQp7CiAgICBUUiB2YWx1ZTsKICAgIGZvciggdmFsdWUgPSAwOyAqcyA8PSAnOScgJiYgKnMgPj0gJzAnOyArK3MgKQogICAgICAgIHZhbHVlID0gdmFsdWUgKiAxMCArICggKnMgJiAweEYgKTsKICAgIHJldHVybiAgdmFsdWU7Cn0KCnRlbXBsYXRlPCB0eXBlbmFtZSBUUiA+CmlubGluZSAgVFIgICAgICBhdG9pKCBjaGFyKiYgcyApCnsKICAgIGlmKCAqcyA9PSAnLScgKQogICAgICAgIHJldHVybiAgKFRSKSggLTEgKiBhdG91PCBUUiA+KCArK3MgKSApOwogICAgcmV0dXJuICAoVFIpYXRvdTwgVFIgPiggcyApOwp9CgojaW5jbHVkZSA8Y21hdGg+CnRlbXBsYXRlPCB0eXBlbmFtZSBUID0gZjY0ID4KaW5saW5lICBUICAgICAgIGF0b2YoIGNoYXIqJiBzICkKewogICAgY2hhciogcCA9IHM7CiAgICB1MzIgc2lnbiA9IDA7CiAgICBUICAgZGlnaXQgPSAwLjsKICAgIFQgICBiYXNlID0gMS47CiAgICBUICAgc3RlcCA9IDEuOwoKICAgIGZvciggaTggdG9rZW47IHRva2VuID0gKnArKzsgKQogICAgewogICAgICAgIHN3aXRjaCggdG9rZW4gKQogICAgICAgIHsKICAgICAgICBjYXNlICctJzoKICAgICAgICAgICAgc2lnbiA9IG1zYl92YWwoIHNpZ24gKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSAnLic6CiAgICAgICAgICAgIHN0ZXAgPSAxMDsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSAnRSc6CiAgICAgICAgY2FzZSAnZSc6CiAgICAgICAgICAgIGRpZ2l0ICo9IChUKXN0ZDo6cG93KCAxMC4sIChmNjQpYXRvZjwgVCA+KCBzID0gcCApICk7CiAgICAgICAgICAgIGdvdG8gZXhpdDsKICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICBpZiggdG9rZW4gPD0gJzknICYmIHRva2VuID49ICcwJyApCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGRpZ2l0ID0gZGlnaXQgKiAxMCArICggdG9rZW4gJiAweEYgKTsKICAgICAgICAgICAgICAgIGJhc2UgKj0gc3RlcDsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdvdG8gZXhpdDsKICAgICAgICB9CiAgICB9CmV4aXQ6CiAgICBpZiggcyA8IHAgLSAxICkgcyA9IHAgLSAxOwogICAgc2V0X21zYnMoIGRpZ2l0LCBzaWduICk7CiAgICByZXR1cm4gIFQoIGRpZ2l0IC8gYmFzZSApOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojaW5jbHVkZSA8c3RyaW5nPgojaW5jbHVkZSA8c3RkYXJnLmg+Cgp0ZW1wbGF0ZTwgY29uc3QgdTMyIE1BWF9TSVpFID0gMTAyNCA+CmlubGluZSAgc3RkOjpzdHJpbmcgICAgIGZvcm1hdF9zdHJpbmcoIGNvbnN0IGNoYXIqIGZvcm1hdCwgLi4uICkKewogICAgY2hhciAgICB0ZW1wWyBNQVhfU0laRSBdOwogICAgdmFfbGlzdCB2YTsKICAgIHZhX3N0YXJ0KCB2YSwgZm9ybWF0ICk7CiAgICB2c3ByaW50ZiggdGVtcCwgZm9ybWF0LCB2YSApOwogICAgdmFfZW5kKCB2YSApOwogICAgcmV0dXJuICB0ZW1wOwp9IAovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGU8IHR5cGVuYW1lIFQgPgppbmxpbmUgIHJpZ2lkICAgYXV0byAgICBpc19zaWduZWRfKCkKewogICAgcmV0dXJuICBzdGQ6OmlzX3NhbWU8IFQsIGk4ICA+Ojp2YWx1ZSB8fCBzdGQ6OmlzX3NhbWU8IFQsIGkxNiA+Ojp2YWx1ZSB8fAogICAgICAgICAgICBzdGQ6OmlzX3NhbWU8IFQsIGkzMiA+Ojp2YWx1ZSB8fCBzdGQ6OmlzX3NhbWU8IFQsIGk2NCA+Ojp2YWx1ZTsKfQoKdGVtcGxhdGU8IHR5cGVuYW1lIFQgPgppbmxpbmUgIHJpZ2lkICAgYXV0byAgICBpc191bnNpZ25lZF8oKQp7CiAgICByZXR1cm4gIHN0ZDo6aXNfc2FtZTwgVCwgdTggID46OnZhbHVlIHx8IHN0ZDo6aXNfc2FtZTwgVCwgdTE2ID46OnZhbHVlIHx8CiAgICAgICAgICAgIHN0ZDo6aXNfc2FtZTwgVCwgdTMyID46OnZhbHVlIHx8IHN0ZDo6aXNfc2FtZTwgVCwgdTY0ID46OnZhbHVlOwp9Cgp0ZW1wbGF0ZTwgdHlwZW5hbWUgVCA+CmlubGluZSAgcmlnaWQgICBhdXRvICAgIGlzX2Zsb2F0aW5nXygpCnsKICAgIHJldHVybiAgc3RkOjppc19zYW1lPCBULCBmMzIgPjo6dmFsdWUgfHwgc3RkOjppc19zYW1lPCBULCBmNjQgPjo6dmFsdWU7Cn0KCnRlbXBsYXRlPCB0eXBlbmFtZSBUID4KaW5saW5lICBjaGFyKiAgIHBhcnNlX251bWJlciggY29uc3QgY2hhciogc3RyaW5nLCBUJiBwYXJhbSApCnsKICAgIGNoYXIqIHMgPSAoY2hhciopc3RyaW5nOwogICAgd2hpbGUoICpzIDw9ICcgJyB8fCAqcyA9PSAnLycgfHwgKnMgPT0gJzonICkgcysrOwoKICAgIGlmKCBpc19zaWduZWRfPCBUID4oKSApCiAgICB7CiAgICAgICAgcGFyYW0gPSBhdG9pPCBUID4oIHMgKTsKICAgIH0KICAgIGVsc2UgaWYoIGlzX3Vuc2lnbmVkXzwgVCA+KCkgKQogICAgewogICAgICAgIHBhcmFtID0gYXRvdTwgVCA+KCBzICk7CiAgICB9CiAgICBlbHNlIGlmKCBpc19mbG9hdGluZ188IFQgPigpICkKICAgIHsgCiAgICAgICAgcGFyYW0gPSBhdG9mPCBUID4oIHMgKTsKICAgIH0KICAgIHJldHVybiAgczsKfQoKdGVtcGxhdGU8IHR5cGVuYW1lIFQsIHR5cGVuYW1lLi4uIFRzID4KaW5saW5lICBjaGFyKiAgIHBhcnNlX251bWJlciggY29uc3QgY2hhciogc3RyaW5nLCBUJiBwYXJhbTEsIFRzJi4uLiByZXN0ICkKewogICAgcmV0dXJuICBwYXJzZV9udW1iZXIoIHBhcnNlX251bWJlciggc3RyaW5nLCBwYXJhbTEgKSwgcmVzdC4uLiApOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpyaWdpZCAgIGkzMiAgbXNlY3NfaW5fMXNlYyAgICAgID0gMTAwMDsKcmlnaWQgICBpMzIgICBzZWNzX2luXzFtaW4gICAgICA9IDYwOwpyaWdpZCAgIGkzMiAgIG1pbnNfaW5fMWhvdXIgICAgID0gNjA7CnJpZ2lkICAgaTMyICBob3Vyc19pbl8xZGF5ICAgICAgPSAyNDsKcmlnaWQgICBpMzIgICBzZWNzX2luXzFob3VyICAgICA9IG1pbnNfaW5fMWhvdXIgICAgICogc2Vjc19pbl8xbWluOwpyaWdpZCAgIGkzMiAgIG1pbnNfaW5fMWRheSAgICAgID0gaG91cnNfaW5fMWRheSAgICAgKiBtaW5zX2luXzFob3VyOwpyaWdpZCAgIGkzMiAgIHNlY3NfaW5fMWRheSAgICAgID0gbWluc19pbl8xZGF5ICAgICAgKiBzZWNzX2luXzFtaW47CnJpZ2lkICAgaTMyICBtc2Vjc19pbl8xZGF5ICAgICAgPSBzZWNzX2luXzFkYXkgICAgICAqIG1zZWNzX2luXzFzZWM7CnJpZ2lkICAgaTMyICB2YWx1ZV9vZl8xZGF5ICAgICAgPSBzZWNzX2luXzFkYXk7CgpyaWdpZCAgIGkzMiAgIGRheXNfaW5fMXllYXIgICAgID0gMzY1OwpyaWdpZCAgIGkzMiAgIGRheXNfaW5fNHllYXJzICAgID0gZGF5c19pbl8xeWVhciAgICAgKiA0ICArIDE7CnJpZ2lkICAgaTMyICAgZGF5c19pbl8xMDB5ZWFycyAgPSBkYXlzX2luXzR5ZWFycyAgICAqIDI1IC0gMTsKcmlnaWQgICBpMzIgICBkYXlzX2luXzQwMHllYXJzICA9IGRheXNfaW5fMTAweWVhcnMgICogNCAgKyAxOwpyaWdpZCAgIGkzMiAgIHNlY3NfaW5fMXllYXIgICAgID0gZGF5c19pbl8xeWVhciAgICAgKiBzZWNzX2luXzFkYXk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKcmlnaWQgICBpNjQgIHllYXJzX2luX2JjICAgICAgICA9IDEwMDAwMDAwMDAwMExMOwpyaWdpZCAgIGk2NCAgIGRheXNfaW5fYmMgICAgICAgID0geWVhcnNfaW5fYmMgLyA0MDAgKiBkYXlzX2luXzQwMHllYXJzOwpyaWdpZCAgIGk2NCAgIHNlY3NfaW5fYmMgICAgICAgID0gZGF5c19pbl9iYyAgICAgICAgKiBzZWNzX2luXzFkYXk7CnJpZ2lkICAgaTY0ICAgZGF5c19pbl9iY19ncmVnICAgPSBkYXlzX2luXzQwMHllYXJzICAqIHllYXJzX2luX2JjIC8gNDAwOwpyaWdpZCAgIGk2NCAgIGRheXNfaW5fYmNfanVsaSAgID0gZGF5c19pbl80eWVhcnMgICAgKiB5ZWFyc19pbl9iYyAvIDQ7CnJpZ2lkICAgaTY0ICAganVsaV90b19ncmVnICAgICAgPSBkYXlzX2luX2JjX2dyZWcgICAtIGRheXNfaW5fYmNfanVsaSAtIDI7CgpyaWdpZCAgIGkzMiBmaW5hbF9kYXlfZnJhZ21lbnQgID0gKHU2NCktMSAtICh1NjQpLTEgLyB2YWx1ZV9vZl8xZGF5ICogdmFsdWVfb2ZfMWRheTsKCnJpZ2lkICAgdTMyIHN1bV9kYXlzMTAwWyA0IF1bIDE0IF0KewogICAgeyAwLCAgICAwLCAgIDMxLCAgIDU5LCAgIDkwLCAgMTIwLCAgMTUxLCAgMTgxLCAgMjEyLCAgMjQzLCAgMjczLCAgMzA0LCAgMzM0LCAgMzY1LCB9LAogICAgeyAwLCAgMzY1LCAgMzk2LCAgNDI0LCAgNDU1LCAgNDg1LCAgNTE2LCAgNTQ2LCAgNTc3LCAgNjA4LCAgNjM4LCAgNjY5LCAgNjk5LCAgNzMwLCB9LAogICAgeyAwLCAgNzMwLCAgNzYxLCAgNzg5LCAgODIwLCAgODUwLCAgODgxLCAgOTExLCAgOTQyLCAgOTczLCAxMDAzLCAxMDM0LCAxMDY0LCAxMDk1LCB9LAogICAgeyAwLCAxMDk1LCAxMTI2LCAxMTU0LCAxMTg1LCAxMjE1LCAxMjQ2LCAxMjc2LCAxMzA3LCAxMzM4LCAxMzY4LCAxMzk5LCAxNDI5LCAxNDYwLCB9LAp9OwoKcmlnaWQgICB1MzIgc3VtX2RheXNbIDQgXVsgMTQgXQp7CiAgICB7IDAsICAgIDAsICAgMzEsICAgNTksICAgOTAsICAxMjAsICAxNTEsICAxODEsICAyMTIsICAyNDMsICAyNzMsICAzMDQsICAzMzQsICAzNjUsIH0sCiAgICB7IDAsICAzNjUsICAzOTYsICA0MjQsICA0NTUsICA0ODUsICA1MTYsICA1NDYsICA1NzcsICA2MDgsICA2MzgsICA2NjksICA2OTksICA3MzAsIH0sCiAgICB7IDAsICA3MzAsICA3NjEsICA3ODksICA4MjAsICA4NTAsICA4ODEsICA5MTEsICA5NDIsICA5NzMsIDEwMDMsIDEwMzQsIDEwNjQsIDEwOTUsIH0sCiAgICB7IDAsIDEwOTUsIDExMjYsIDExNTUsIDExODYsIDEyMTYsIDEyNDcsIDEyNzcsIDEzMDgsIDEzMzksIDEzNjksIDE0MDAsIDE0MzAsIDE0NjEsIH0sCn07Cgpjb25zdCAgIGNoYXIqICAgZGF5X25hbWVzW10KewogICAgIk1vbiIsICJUdWUiLCAiV2VkIiwgIlRodSIsICJGcmkiLCAiU2F0IiwgIlN1biIsCn07Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgp0ZW1wbGF0ZTwgdHlwZW5hbWUgVDAsIHR5cGVuYW1lIFQxLCB0eXBlbmFtZSBUMiA+CmlubGluZSAgYXV0byAgICAgICAgICAgICAgICAgICAgdGltZXMoIGNvbnN0IFQwIGhvdXJzLCBjb25zdCBUMSBtaW5zLCBjb25zdCBUMiBzZWNzICkKewogICAgcmV0dXJuICBob3VycyAqIHNlY3NfaW5fMWhvdXIgKyBtaW5zICogc2Vjc19pbl8xbWluICsgc2VjczsKfQoKdGVtcGxhdGU8IHR5cGVuYW1lIFQgPgppbmxpbmUgIHU2NCAgICAgICAgICAgICAgICAgICAgIGRheXMoIGNvbnN0IFQgZGF5cyApCnsKICAgIHJldHVybiAgZGF5cyAqIHNlY3NfaW5fMWRheTsKfQoKaW5saW5lICB1NjQgICAgICAgICAgICAgICAgICAgICBzZWNvbmRzKCBjb25zdCB1NjQgc2VjcyApCnsKICAgIHJldHVybiAgc2VjczsKfQovLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKZW51bSAgICBjbGFzcyAgICAgICAgICAgICAgICAgICBEQVRFX01FVEhPRAp7CiAgICBqdWxpYW4sCiAgICBncmVnb3JpYW4sCn07Cgp0ZW1wbGF0ZTwgREFURV9NRVRIT0QgbWV0aG9kID0gREFURV9NRVRIT0Q6OmdyZWdvcmlhbiA+CmNsYXNzICAgREFURV8Kewpwcml2YXRlOgogICAgdTY0ICAgICAgICAgICAgICAgICAgICAgICAgIHNlY3M7CgogICAgdm9pZCAgICAgICAgICAgICAgICAgICAgICAgIGRhdGVfcGFyc2luZyggY29uc3QgY2hhciogZGF0ZV9zdHJpbmcgKQogICAgewogICAgICAgIGk2NCAgICAgeWVhcjsKICAgICAgICB1MzIgICAgIG1vbnRoLCBkYXk7CiAgICAgICAgcGFyc2VfbnVtYmVyKCBkYXRlX3N0cmluZywgeWVhciwgbW9udGgsIGRheSApOwogICAgICAgIGVuY29kZSggeWVhciwgbW9udGgsIGRheSApOwogICAgfQoKcHVibGljOgogICAgQ1NUUiAgICAgICAgICAgICAgICAgICAgICAgIERBVEVfKCkgOiBzZWNzKCAwICkKICAgIHt9CiAgICBDU1RSICAgIGV4cGxpY2l0ICAgICAgICAgICAgREFURV8oIGNvbnN0IHU2NCBzZWNzICkgOiBzZWNzKCBzZWNzICkKICAgIHt9CiAgICBDU1RSICAgICAgICAgICAgICAgICAgICAgICAgREFURV8oIGNvbnN0IGk2NCB5ZWFyLCBjb25zdCB1MzIgbW0sIGNvbnN0IHUzMiBkZCApCiAgICB7CiAgICAgICAgZW5jb2RlKCB5ZWFyLCBtbSwgZGQgKTsKICAgIH0KICAgIENTVFIgICAgICAgICAgICAgICAgICAgICAgICBEQVRFXyggY29uc3QgaTY0IHllYXIsIGNvbnN0IHUzMiBtbSwgY29uc3QgdTMyIGRkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1MzIgaGgsIGNvbnN0IHUzMiBubiwgY29uc3QgdTMyIHNzICkKICAgIHsKICAgICAgICBlbmNvZGUoIHllYXIsIG1tLCBkZCApOwogICAgICAgIHNlY3MgKz0gdGltZXMoIGhoLCBubiwgc3MgKTsKICAgIH0KCiAgICBDU1RSICAgIGV4cGxpY2l0ICAgICAgICAgICAgREFURV8oIGNvbnN0IGNoYXIqIGRhdGVfc3RyaW5nICkKICAgIHsKICAgICAgICBkYXRlX3BhcnNpbmcoIGRhdGVfc3RyaW5nICk7CiAgICB9CiAgICBDU1RSICAgIGV4cGxpY2l0ICAgICAgICAgICAgREFURV8oIGNvbnN0IHN0ZDo6c3RyaW5nIGRhdGVfc3RyaW5nICkKICAgIHsKICAgICAgICBkYXRlX3BhcnNpbmcoIGRhdGVfc3RyaW5nLmNfc3RyKCkgKTsKICAgIH0KCiAgICB2b2lkICAgICAgICAgICAgICAgICAgICAgICAgZW5jb2RlKCBjb25zdCBpNjQgeWVhciwgY29uc3QgdTMyIG1vbnRoLCBjb25zdCB1MzIgZGF5ICkKICAgIHsKICAgICAgICB1NjQgICAgIHh4ICA9IHllYXIgKyB5ZWFyc19pbl9iYyAtICggeWVhciA+IDAgKTsKICAgICAgICBpZiggbWV0aG9kID09IERBVEVfTUVUSE9EOjpncmVnb3JpYW4gKQogICAgICAgIHsKICAgICAgICAgICAgc2VjcyAgICA9IHh4IC8gNDAwICogZGF5c19pbl80MDB5ZWFyczsKICAgICAgICAgICAgdTMyIHgyICA9IHh4ICUgNDAwOwoKICAgICAgICAgICAgdTMyIHkxICA9IHgyIC8gMTAwICogZGF5c19pbl8xMDB5ZWFyczsKICAgICAgICAgICAgdTMyIHgxICA9IHgyICUgMTAwOwoKICAgICAgICAgICAgdTMyIHkwICA9IHgxIC8gNCAqIGRheXNfaW5fNHllYXJzOwogICAgICAgICAgICB1MzIgeDAgID0geDEgJSA0OwoKICAgICAgICAgICAgYXV0byBzICA9IHN1bV9kYXlzWyB4MCBdOwogICAgICAgICAgICBpZiggeDIgIT0gMzk5ICYmIHgxID09IDk5ICkKICAgICAgICAgICAgICAgICBzICA9IHN1bV9kYXlzMTAwWyB4MCBdOwoKICAgICAgICAgICAgc2VjcyAgICs9IHkxICsgeTAgKyBzWyBtb250aCBdICsgZGF5IC0gMTsKICAgICAgICB9CiAgICAgICAgZWxzZQogICAgICAgIHsKICAgICAgICAgICAgc2VjcyAgICA9IHh4IC8gNCAqIGRheXNfaW5fNHllYXJzICsKICAgICAgICAgICAgICAgICAgICAgICggc3VtX2RheXNbIHh4ICUgNCBdWyBtb250aCBdICsgZGF5ICsgKCBqdWxpX3RvX2dyZWcgLSAxICkgKTsKICAgICAgICB9CiAgICAgICAgc2VjcyAgICAgICAqPSB2YWx1ZV9vZl8xZGF5OwogICAgfQoKICAgIHZvaWQgICAgICAgICAgICAgICAgICAgICAgICBkZWNvZGUoIGk2NCYgeWVhciwgdTMyJiBtb250aCwgdTMyJiBkYXkgKSBjb25zdAogICAgewogICAgICAgIHU2NCAgICAgeHggID0gc2VjcyAvIHZhbHVlX29mXzFkYXk7CiAgICAgICAgdTMyICAgICB4LCB5OwogICAgICAgIHllYXIgICAgICAgID0gLXllYXJzX2luX2JjOwogICAgICAgIGF1dG8gICAgcyAgID0gc3VtX2RheXM7CiAgICAgICAgaWYoIG1ldGhvZCA9PSBEQVRFX01FVEhPRDo6Z3JlZ29yaWFuICkKICAgICAgICB7CiAgICAgICAgICAgIHllYXIgICArPSB4eCAvIGRheXNfaW5fNDAweWVhcnMgKiA0MDA7CiAgICAgICAgICAgIHUzMiB4MiAgPSB4eCAlIGRheXNfaW5fNDAweWVhcnM7CgogICAgICAgICAgICB1MzIgeTEgID0geDIgLyBkYXlzX2luXzEwMHllYXJzIC0geDIgLyAoIGRheXNfaW5fMTAweWVhcnMgKiA0ICk7CiAgICAgICAgICAgIHUzMiB4MSAgPSB4MiAtIGRheXNfaW5fMTAweWVhcnMgKiB5MTsKICAgICAgICAgICAgICAgIHkxICA9IHkxICogMTAwOwoKICAgICAgICAgICAgdTMyIHkwICA9IHgxIC8gZGF5c19pbl80eWVhcnMgKiA0OwogICAgICAgICAgICB4ICAgICAgID0geDEgJSBkYXlzX2luXzR5ZWFyczsKCiAgICAgICAgICAgIHkgICAgICAgPSB4IC8gZGF5c19pbl8xeWVhciAtIHggLyAoIGRheXNfaW5fMXllYXIgKiA0ICk7CgogICAgICAgICAgICBpZiggeTEgPCAzMDAgJiYgeTAgKyB5ID09IDk5ICApCiAgICAgICAgICAgICAgICBzICAgPSBzdW1fZGF5czEwMDsKCiAgICAgICAgICAgIHllYXIgICArPSB5MSArIHkwICsgeTsKICAgICAgICB9CiAgICAgICAgZWxzZQogICAgICAgIHsKICAgICAgICAgICAgeHggICAgIC09IGp1bGlfdG9fZ3JlZzsKCiAgICAgICAgICAgIHU2NCB5MCAgPSB4eCAvIGRheXNfaW5fNHllYXJzICogNDsKICAgICAgICAgICAgeCAgICAgICA9IHh4ICUgZGF5c19pbl80eWVhcnM7CgogICAgICAgICAgICB5ICAgICAgID0geCAvIGRheXNfaW5fMXllYXIgLSB4IC8gKCBkYXlzX2luXzF5ZWFyICogNCApOwoKICAgICAgICAgICAgeWVhciAgICs9IHkwICsgeTsKICAgICAgICB9CgogICAgICAgIG1vbnRoICAgICAgID0gKCB4IC0geSAqIGRheXNfaW5fMXllYXIgKSAvIDI5OwogICAgICAgIG1vbnRoICAgICAgKz0geCA+PSBzWyB5IF1bIG1vbnRoICsgMSBdOwogICAgICAgIGRheSAgICAgICAgID0geCAtIHNbIHkgXVsgbW9udGggXSArIDE7CiAgICAgICAgeWVhciAgICAgICArPSB5ZWFyID49IDA7CiAgICB9CiAgICAvLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogICAgY29uc3QgICBhdXRvICAgICAgICAgICAgICAgIG5hbWUoKSBjb25zdAogICAgewogICAgICAgIHJldHVybiAgZGF5X25hbWVzWyBzZWNzIC8gdmFsdWVfb2ZfMWRheSAlIDcgXTsKICAgIH0KCiAgICBjb25zdCAgIGF1dG8gICAgICAgICAgICAgICAgZGF0ZSggYm9vbCBhZF9iYyA9IGZhbHNlICkgY29uc3QKICAgIHsKICAgICAgICBpNjQgICAgIHllYXI7CiAgICAgICAgdTMyICAgICBtb250aCwgZGF5OwogICAgICAgIGRlY29kZSggeWVhciwgbW9udGgsIGRheSApOwogICAgICAgIGlmKCAhYWRfYmMgKQogICAgICAgICAgICByZXR1cm4gIGZvcm1hdF9zdHJpbmcoICIlbGxkLyUwMnUvJTAydSIsIHllYXIsIG1vbnRoLCBkYXkgKTsKICAgICAgICBlbHNlCiAgICAgICAgICAgIHJldHVybiAgZm9ybWF0X3N0cmluZyggIiVzLiVsbHUvJTAydS8lMDJ1IiwgeWVhciA+IDAgPyAiQUQiIDogIkJDIiwKICAgICAgICAgICAgICAgICAgICBzdGQ6OmFicyggeWVhciApLCBtb250aCwgZGF5ICk7CiAgICB9CgogICAgY29uc3QgICBhdXRvICAgICAgICAgICAgICAgIHRpbWUoIGJvb2wgYW1fcG0gPSBmYWxzZSApIGNvbnN0CiAgICB7CiAgICAgICAgdTMyICAgICBoaCwgbW0sIHNzOwogICAgICAgIHNzICAgICAgPSB0aW1lX3NlY29uZHMoKTsKICAgICAgICBoaCAgICAgID0gc3MgLyBzZWNzX2luXzFob3VyOwogICAgICAgIHNzICAgICAgPSBzcyAlIHNlY3NfaW5fMWhvdXI7CiAgICAgICAgbW0gICAgICA9IHNzIC8gc2Vjc19pbl8xbWluOwogICAgICAgIHNzICAgICAgPSBzcyAlIHNlY3NfaW5fMW1pbjsKICAgICAgICByZXR1cm4gIGZvcm1hdF9zdHJpbmcoICIlMDJ1OiUwMnU6JTAydSIsIGhoLCBtbSwgc3MgKSArCiAgICAgICAgICAgICAgICAoIGFtX3BtID8gKCBoaCA8IDEyID8gIiBhbSIgOiAiIHBtIiApIDogIiIgKTsKICAgIH0KCiAgICBjb25zdCAgIGF1dG8gICAgICAgICAgICAgICAgZGF0ZV90aW1lKCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gIGRhdGUoKSArICIgIiArIHRpbWUoKTsKICAgIH0KCiAgICBjb25zdCAgIGF1dG8gICAgICAgICAgICAgICAgbG9uZ19kYXRlKCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gIHN0ZDo6c3RyaW5nKCBtZXRob2QgPT0gREFURV9NRVRIT0Q6OmdyZWdvcmlhbiA/ICJHOiIgOiAiSjoiICkgKwogICAgICAgICAgICBkYXRlKCB0cnVlICkgKyAiICIgKyBuYW1lKCk7CiAgICB9CgogICAgY29uc3QgICBhdXRvICAgICAgICAgICAgICAgIGxvbmdfZGF0ZV90aW1lKCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gIGxvbmdfZGF0ZSgpICsgIiAiICsgdGltZSggdHJ1ZSApOwogICAgfQogICAgLy8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAgIGNvbnN0ICAgYXV0byAgICAgICAgICAgICAgICBzZWNvbmRzKCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gIHNlY3M7CiAgICB9CgogICAgY29uc3QgICB1MzIgICAgICAgICAgICAgICAgIHRpbWVfc2Vjb25kcygpIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuICBzZWNzICUgc2Vjc19pbl8xZGF5OwogICAgfQoKICAgIGNvbnN0ICAgYXV0byAgICAgICAgICAgICAgICBkYXlzKCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gIHNlY3MgLyBzZWNzX2luXzFkYXk7CiAgICB9CiAgICAvLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogICAgYXV0byYgICAgICAgICAgICAgICAgICAgICAgIG9wZXJhdG9yLT0oIGNvbnN0IERBVEVfJiByaHMgKQogICAgewogICAgICAgIHJldHVybiAgc2VjcyAtPSByaHMuc2VjcywgKnRoaXM7CiAgICB9CgogICAgYXV0byYgICAgICAgICAgICAgICAgICAgICAgIG9wZXJhdG9yKz0oIGNvbnN0IERBVEVfJiByaHMgKQogICAgewogICAgICAgIHJldHVybiAgc2VjcyArPSByaHMuc2VjcywgKnRoaXM7CiAgICB9CgogICAgdGVtcGxhdGU8IERBVEVfTUVUSE9EIE0gPgogICAgY29uc3QgICBhdXRvICAgICAgICAgICAgICAgIG9wZXJhdG9yLSggY29uc3QgREFURV88IE0gPiYgcmhzICkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4gIERBVEVfPCBtZXRob2QgPiggc2VjcyAtIHJocy5zZWNvbmRzKCkgKTsKICAgIH0KCiAgICB0ZW1wbGF0ZTwgREFURV9NRVRIT0QgTSA+CiAgICBjb25zdCAgIGF1dG8gICAgICAgICAgICAgICAgb3BlcmF0b3IrKCBjb25zdCBEQVRFXzwgTSA+JiByaHMgKSBjb25zdAogICAgewogICAgICAgIHJldHVybiAgREFURV88IG1ldGhvZCA+KCBzZWNzICsgcmhzLnNlY29uZHMoKSApOwogICAgfQoKICAgIGNvbnN0ICAgYXV0byAgICAgICAgICAgICAgICBvcGVyYXRvci0oIGNvbnN0IHU2NCBkdXJhdGlvbiApIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuICBEQVRFXzwgbWV0aG9kID4oIHNlY3MgLSBkdXJhdGlvbiApOwogICAgfQoKICAgIGNvbnN0ICAgYXV0byAgICAgICAgICAgICAgICBvcGVyYXRvcisoIGNvbnN0IHU2NCBkdXJhdGlvbiApIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuICBEQVRFXzwgbWV0aG9kID4oIHNlY3MgKyBkdXJhdGlvbiApOwogICAgfQoKICAgIGF1dG8mICAgICAgICAgICAgICAgICAgICAgICBvcGVyYXRvci09KCBjb25zdCB1NjQgZHVyYXRpb24gKQogICAgewogICAgICAgIHJldHVybiAgc2VjcyAtPSBkdXJhdGlvbiwgKnRoaXM7CiAgICB9CgogICAgYXV0byYgICAgICAgICAgICAgICAgICAgICAgIG9wZXJhdG9yKz0oIGNvbnN0IHU2NCBkdXJhdGlvbiApCiAgICB7CiAgICAgICAgcmV0dXJuICBzZWNzICs9IGR1cmF0aW9uLCAqdGhpczsKICAgIH0KCiAgICBhdXRvJiAgICAgICAgICAgICAgICAgICAgICAgb3BlcmF0b3ItLSgpCiAgICB7CiAgICAgICAgcmV0dXJuICAqdGhpcyAtPSBzZWNzX2luXzFkYXk7CiAgICB9CgogICAgYXV0byYgICAgICAgICAgICAgICAgICAgICAgIG9wZXJhdG9yKysoKQogICAgewogICAgICAgIHJldHVybiAgKnRoaXMgKz0gc2Vjc19pbl8xZGF5OwogICAgfQoKICAgIGNvbnN0ICAgYm9vbCAgICAgICAgICAgICAgICBvcGVyYXRvcjwoIGNvbnN0IERBVEVfJiByaHMgKSBjb25zdAogICAgewogICAgICAgIHJldHVybiAgc2VjcyA8IHJocy5zZWNzOwogICAgfQoKICAgIGZyaWVuZCAgc3RkOjpvc3RyZWFtJiAgICAgICBvcGVyYXRvcjw8KCBzdGQ6Om9zdHJlYW0mIG9zLCBjb25zdCBEQVRFXyYgZGF0ZSApCiAgICB7CiAgICAgICAgcmV0dXJuICBvcyA8PCBkYXRlLmxvbmdfZGF0ZV90aW1lKCk7CiAgICB9Cn07Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgp1c2luZyAgIERBVEUgID0gREFURV88IERBVEVfTUVUSE9EOjpncmVnb3JpYW4gPjsKdXNpbmcgICBEQVRFSiA9IERBVEVfPCBEQVRFX01FVEhPRDo6anVsaWFuID47CgppbmxpbmUgIGF1dG8gICAgaGlzdG9yaWNhbF9kYXRlKCBjb25zdCBEQVRFIGdyZWdvcmlhbl9kYXRlICkKewogICAgY29uc3QgICBhdXRvICAgIGp1bGlhbl90b19ncmVnb3JpYW5fZGF0ZSA9IERBVEUoIDE1ODIsMTAsMTUgKTsKICAgIGlmKCBncmVnb3JpYW5fZGF0ZSA8IGp1bGlhbl90b19ncmVnb3JpYW5fZGF0ZSApCiAgICAgICAgcmV0dXJuICBEQVRFSiggZ3JlZ29yaWFuX2RhdGUuc2Vjb25kcygpICkubG9uZ19kYXRlKCk7CiAgICByZXR1cm4gIGdyZWdvcmlhbl9kYXRlLmxvbmdfZGF0ZSgpOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgp1c2luZyAgIG5hbWVzcGFjZSAgIHN0ZDsKCmludCBtYWluKCkKewogICAgY291dCA8PCBzaXplb2YoIERBVEUgKSA8PAogICAgICAgICIgYnl0ZXMgREFURV88IEp1bGlhbiAmIEdyZWdvcmlhbiA+IHR5cGUiIDw8IGVuZGwgPDwgZW5kbDsKCiAgICBjb3V0IDw8IERBVEVKKCAwVUxMICkgPDwgIiB+ICIgPDwgZW5kbDsKICAgIGNvdXQgPDwgREFURUooIDB4RkZGRkZGRkZGRkZGRkZGRlVMTCApIDw8IGVuZGw7CiAgICBjb3V0IDw8IGVuZGw7CgogICAgY291dCA8PCBEQVRFKCAwVUxMICkgPDwgIiB+ICIgPDwgZW5kbDsKICAgIGNvdXQgPDwgREFURSggKHU2NCktMSApIDw8IGVuZGw7CiAgCiAgICBjb3V0IDw8IGVuZGw7CgogICAgY291dCA8PCAtLURBVEVKKCAxLCAxLCAxICkgIDw8ICIgPT0gIiA8PCBEQVRFSiggLTEsIDEyLCAzMSApLnNlY29uZHMoKSA8PAogICAgICAgICIgc2Vjb25kcyAiIDw8IGVuZGw7CiAgICBjb3V0IDw8IC0tREFURSggIjEvIDEvIDEiICkgPDwgIiA9PSAiIDw8ICAgREFURSggIjEvIDEvIDEiICkuc2Vjb25kcygpIDw8CiAgICAgICAgIiBzZWNvbmRzICIgPDwgZW5kbDsKCiAgICBjb3V0IDw8IGVuZGw7CgogICAgY291dCA8PCBEQVRFSiggMSwgMSwgMSApIDw8ICIgPT0gIiA8PAogICAgICAgIERBVEUoIERBVEVKKCAxLCAxLCAxICkuc2Vjb25kcygpICkuZGF5cygpIDw8ICIgdGggZGF5ICIgPDwgZW5kbDsKICAgIGNvdXQgPDwgREFURSggMSwgMSwgMSApIDw8ICIgPT0gIiA8PAogICAgICAgIERBVEVKKCBEQVRFKCAxLCAxLCAxICkuc2Vjb25kcygpICkuZGF5cygpIDw8ICIgdGggZGF5ICIgPDwgZW5kbDsKCiAgICBjb3V0IDw8IGVuZGw7CgogICAgY291dCA8PCBEQVRFKCAxNTgyLCAxMCwgMTQgKSA8PCAiID09ICIgPDwKICAgICAgICBoaXN0b3JpY2FsX2RhdGUoIERBVEUoICIxNTgyLzEwLzE0IiApICkgPDwgZW5kbDsKICAgIGNvdXQgPDwgREFURSggMTU4MiwgMTAsIDE1ICkgPDwgIiA9PSAiIDw8CiAgICAgICAgaGlzdG9yaWNhbF9kYXRlKCBEQVRFKCAiMTU4Mi8xMC8xNSIgKSApIDw8IGVuZGw7CgogICAgY291dCA8PCBlbmRsOwoKICAgIGNvdXQgPDwgIlRpbWUgbWV0aG9kcyIgPDwgZW5kbCA8PCBlbmRsOwoKICAgIGNvdXQgPDwgREFURSggdGltZXMoIDIzLCA1OSwgMzAgKSApLnRpbWUoKSA8PCBlbmRsOwogICAgY291dCA8PCBEQVRFKCAyMDE2LCAzLCAzMCwgOSwgNTAsIDQ1ICkgPDwgZW5kbDsKICAgIGNvdXQgPDwgKCBEQVRFKCkgKyBkYXlzKCBkYXlzX2luX2JjICkgKyB0aW1lcyggMjMsIDU5LCAzMCApICsgc2Vjb25kcyggMzAgKSApCiAgICAgICAgLmRhdGVfdGltZSgpIDw8IGVuZGw7CgogICAgY291dCA8PCBlbmRsOwoKICAgIGdldGNoYXIoKTsKICAgIHJldHVybiAwOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t