#define RAND() ((unsigned int)((rand() & 0xff) | ((rand() & 0xff) << 8) | ((rand() & 0xff) << 16) | ((rand() & 0xff) << 24)))
#define GIGA (uint64_t)((uint64_t)0x400*(uint64_t)0x400*(uint64_t)0x400)
#define MAX_LENGTH_SECTION 0x1f
#define MAX_LENGTH_TEXT 0x7f
#define MAX_LENGTH_BUF 0xff
static char const * asz_mon[ 12 ] = {
"Jan" ,"Feb" ,"Mar" ,"Apr" ,"May" ,"Jun" ,
"Jul" ,"Aug" ,"Sep" ,"Oct" ,"Nov" ,"Dec" } ;
static char * gen_string1( char * sz_string, size_t u_length) {
unsigned char * psz_string = ( unsigned char * ) sz_string;
unsigned char * psz_string_end = ( unsigned char * ) sz_string + u_length;
for ( ; psz_string < psz_string_end; ++ psz_string) {
* psz_string = 0x21 + ( RAND( ) % 94 ) ;
}
* psz_string = '\0 ' ;
return sz_string;
}
static char * gen_string2( char * sz_string, size_t u_length) {
unsigned char c;
char * psz_string = sz_string;
char * psz_string_end = sz_string + u_length;
for ( ; psz_string < psz_string_end; ++ psz_string) {
c = RAND( ) % 52 ;
if ( c < 26 ) {
* psz_string = 'A' + c;
} else {
* psz_string = 'a' + ( c - 26 ) ;
}
}
* psz_string = '\0 ' ;
return sz_string;
}
int gen_data( FILE * fp, size_t u_GiB) {
char sz_buf[ MAX_LENGTH_BUF+ 1 ] ;
unsigned int u_string_recs;
unsigned int u_hatena;
unsigned int u_xy_recs;
unsigned int u_num_recs;
char x_or_y;
uint64_t u_pos;
time_t u_time = time ( NULL ) ;
tm * pt_tm = :: localtime ( & u_time) ;
char sz_timestamp[ 0x20 ] ;
:: sprintf ( sz_timestamp, "%s %.2d %02d:%02d:%02d %d" , asz_mon[ pt_tm- > tm_mon] , pt_tm- > tm_mday, pt_tm- > tm_hour, pt_tm- > tm_min, pt_tm- > tm_sec, pt_tm- > tm_year+ 1900 ) ;
char sz_qq_buf[ MAX_LENGTH_BUF+ 0x40 + 1 ] ;
// タイトル、倍率(mag)。(この係数を使って④の数値から割る、正の整数。unsigned int)
:: srand ( ( unsigned int ) time ( NULL ) ) ;
:: fprintf ( fp, "%s %u\x0a " , gen_string2( sz_buf, 1 + ( RAND( ) % MAX_LENGTH_SECTION) ) , RAND( ) ) ;
for ( ;; ) {
// ①セクション名
// ex. SECTION_NAME ①
:: fprintf ( fp, "%s\x0a " , gen_string2( sz_buf, 1 + ( RAND( ) % MAX_LENGTH_SECTION) ) ) ;
// ②セクション集計値
// ex. 11200 11200 2 Jun 9 23:23:00 2018 ②
// u_xy_recs = RAND() % 0x8000000 + 1;
u_xy_recs = RAND( ) % 0x8000 + 1 ;
u_hatena = u_xy_recs;
u_string_recs = RAND( ) % 0x20 + 1 ;
:: fprintf ( fp, "%u %u %u %s\x0a " , u_xy_recs, u_hatena, u_string_recs, sz_timestamp) ;
// ③テキスト
// ex. This is pen. ③
// hello world. ③
for ( unsigned int j = 0 ; j < u_string_recs; ++ j) {
:: fprintf ( fp, "%s\x0a " , gen_string1( sz_buf, 1 + ( RAND( ) % MAX_LENGTH_TEXT) ) ) ;
}
// ④数値
// ex. x 1 2 ④
for ( unsigned int j = 0 ; j < u_xy_recs; ++ j) {
x_or_y = ( RAND( ) % 2 ) ? 'x' : 'y' ;
// u_num_recs = RAND() % 0x400 + 1;
u_num_recs = RAND( ) % 0x100 + 1 ;
switch ( RAND( ) % 3 ) {
case 0 :
// ⑤QQ 謎の行
// QQ subname -1 0 0 1 -21000000 600000 2
// →この行が無いファイルもある。
// →7,8カラムは1行目の倍率数字で割る(数値行と同じ計算)
// →3~6カラムは -1, 0, 1, のいずれか。この4つの組み合わせであとで計算に使うことがある。
// 1 0 0 1 →TYPE_A
// 0 1 -1 0 →TYPE_B
// -1 0 0 -1 →TYPE_C
// 0 -1 1 0 →TYPE_D
// -1 0 0 1 →TYPE_E
// 0 -1 -1 0 →TYPE_F
// 1 0 0 -1 →TYPE_G
// 0 1 1 0 →TYPE_H
// →9カラム目は正の整数。(unsigned int)
// →下記6つのバリエーションがあります。
// QQ subname
// QQ subname c
// QQ subname -1 0 0 1 -21000000 600000
// QQ subname -1 0 0 1 -21000000 600000 2
// QQ subname c -1 0 0 1 -21000000 600000
// QQ subname c -1 0 0 1 -21000000 600000 2
// ※cはcという文字列固定
// ※1つのファイルに存在するのはいずれか1つのフォーマット
switch ( RAND( ) % 3 ) {
case 0 :
:: sprintf ( sz_qq_buf, "%s" ,
RAND( ) % 2 ? " c" : "" ) ;
break ;
case 1 :
:: sprintf ( sz_qq_buf, "%s %d %d %d %d %d %d" ,
RAND( ) % 2 ? " c" : "" ,
( int ) ( RAND( ) % 3 ) - 1 , ( int ) ( RAND( ) % 3 ) - 1 , ( int ) ( RAND( ) % 3 ) - 1 , ( int ) ( RAND( ) % 3 ) - 1 ,
( int32_t ) RAND( ) , ( int32_t ) RAND( ) ) ;
break ;
default :
:: sprintf ( sz_qq_buf, "%s %d %d %d %d %d %d %u" ,
RAND( ) % 2 ? " c" : "" ,
( int ) ( RAND( ) % 3 ) - 1 , ( int ) ( RAND( ) % 3 ) - 1 , ( int ) ( RAND( ) % 3 ) - 1 , ( int ) ( RAND( ) % 3 ) - 1 ,
( int32_t ) RAND( ) , ( int32_t ) RAND( ) , RAND( ) ) ;
break ;
}
// 上記QQ行は先頭のQQがなくなってx, y行に存在することがあります。
// 1つのファイル内でQQ行とx, yの後ろにくるパターンの両方は存在せず、片方が出てきたらもう片方は出てきません。
// x, yと同じ行にくる場合のフォーマットもQQ行の規則と同じです。
// x 1 234 subname -1 0 0 1 -21000000 600000 2
// y 2 234 subname -1 0 0 1 -21000000 600000 2
if ( RAND( ) % 2 ) {
:: fprintf ( fp, "%c %u %u%s\x0a " , x_or_y, j + 1 , u_num_recs, sz_qq_buf) ;
} else {
:: fprintf ( fp, "%c %u %u\x0a " , x_or_y, j + 1 , u_num_recs) ;
:: fprintf ( fp, "QQ %s%s\x0a " , gen_string2( sz_buf, 1 + ( RAND( ) % MAX_LENGTH_SECTION) ) , sz_qq_buf) ;
}
break ;
case 1 :
// RR行があります。
// これもQQ同様x, yの次の行にあったりなかったりします。
// QQとRRが一緒に出てくることは無いと思います。
// フォーマットは「RR 正の整数」でQQのようにx,yの後ろに来ることはありません。
:: fprintf ( fp, "%c %u %u\x0a " , x_or_y, j + 1 , u_num_recs) ;
:: fprintf ( fp, "RR %u\x0a " , RAND( ) ) ;
break ;
default :
:: fprintf ( fp, "%c %u %u\x0a " , x_or_y, j + 1 , u_num_recs) ;
break ;
}
if ( x_or_y == 'x' ) {
for ( unsigned int k = 0 ; k < u_num_recs; ++ k) {
// 100 1 -2000 10
:: fprintf ( fp, "%d %d %d %d\x0a " ,
( int32_t ) RAND( ) , ( int32_t ) RAND( ) , ( int32_t ) RAND( ) , ( int32_t ) RAND( ) ) ;
}
} else {
for ( unsigned int k = 0 ; k < u_num_recs; ++ k) {
// -100 10000
:: fprintf ( fp, "%d %d\x0a " ,
( int32_t ) RAND( ) , ( int32_t ) RAND( ) ) ;
}
}
}
u_pos = ftello( fp) ;
if ( u_pos > GIGA * ( uint64_t ) u_GiB) {
break ;
}
}
return 0 ;
}
int main( int argc, char ** argv) {
if ( argc ! = 3 ) {
:: fprintf ( stderr , "Usage: %s <filepath> <GiB size>\n " , argv[ 0 ] ) ;
return 1 ;
}
char * filename = argv[ 1 ] ;
size_t u_GiB = :: strtoul ( argv[ 2 ] , NULL , 10 ) ;;
if ( u_GiB == 0 ) {
:: fprintf ( stderr , "Usage: %s <filepath> <GiB size>\n " , argv[ 0 ] ) ;
:: fprintf ( stderr , "<GiB size> must be greater than zero\n " ) ;
return 1 ;
}
FILE * fp = :: fopen ( filename, "wb" ) ;
if ( fp == NULL ) {
:: fprintf ( stderr , "fatal error: open file error \" %s\" \n " , filename) ;
return 1 ;
}
if ( :: gen_data ( fp, u_GiB) < 0 ) { fclose ( fp) ; return - 1 ; }
fclose ( fp) ;
return 0 ;
}
CiNkZWZpbmUgUkFORCgpICgodW5zaWduZWQgaW50KSgocmFuZCgpICYgMHhmZikgfCAoKHJhbmQoKSAmIDB4ZmYpIDw8IDgpIHwgKChyYW5kKCkgJiAweGZmKSA8PCAxNikgfCAoKHJhbmQoKSAmIDB4ZmYpIDw8IDI0KSkpCiNkZWZpbmUgR0lHQSAgICAgICAgICAgICAgICh1aW50NjRfdCkoKHVpbnQ2NF90KTB4NDAwKih1aW50NjRfdCkweDQwMCoodWludDY0X3QpMHg0MDApCiNkZWZpbmUgTUFYX0xFTkdUSF9TRUNUSU9OIDB4MWYKI2RlZmluZSBNQVhfTEVOR1RIX1RFWFQgICAgMHg3ZgojZGVmaW5lIE1BWF9MRU5HVEhfQlVGICAgICAweGZmCgpzdGF0aWMgY2hhciBjb25zdCogYXN6X21vblsxMl0gPSB7CiJKYW4iLCJGZWIiLCJNYXIiLCJBcHIiLCJNYXkiLCJKdW4iLAoiSnVsIiwiQXVnIiwiU2VwIiwiT2N0IiwiTm92IiwiRGVjIn07CgpzdGF0aWMgY2hhciogZ2VuX3N0cmluZzEoY2hhciogc3pfc3RyaW5nLCBzaXplX3QgdV9sZW5ndGgpIHsKCQoJdW5zaWduZWQgY2hhciogcHN6X3N0cmluZyA9ICh1bnNpZ25lZCBjaGFyKilzel9zdHJpbmc7Cgl1bnNpZ25lZCBjaGFyKiBwc3pfc3RyaW5nX2VuZCA9ICh1bnNpZ25lZCBjaGFyKilzel9zdHJpbmcgKyB1X2xlbmd0aDsKCglmb3IgKDsgcHN6X3N0cmluZyA8IHBzel9zdHJpbmdfZW5kOyArK3Bzel9zdHJpbmcpIHsKCQkqcHN6X3N0cmluZyA9IDB4MjEgKyAoUkFORCgpICUgOTQpOwoJfQoKCSpwc3pfc3RyaW5nID0gJ1wwJzsKCXJldHVybiBzel9zdHJpbmc7Cn0KCnN0YXRpYyBjaGFyKiBnZW5fc3RyaW5nMihjaGFyKiBzel9zdHJpbmcsIHNpemVfdCB1X2xlbmd0aCkgewoJCgl1bnNpZ25lZCBjaGFyIGM7CgljaGFyKiBwc3pfc3RyaW5nID0gc3pfc3RyaW5nOwoJY2hhciogcHN6X3N0cmluZ19lbmQgPSBzel9zdHJpbmcgKyB1X2xlbmd0aDsKCglmb3IgKDsgcHN6X3N0cmluZyA8IHBzel9zdHJpbmdfZW5kOyArK3Bzel9zdHJpbmcpIHsKCQljID0gUkFORCgpICUgNTI7CgkJaWYgKGMgPCAyNikgewoJCQkqcHN6X3N0cmluZyA9ICdBJyArIGM7CgkJfSBlbHNlIHsKCQkJKnBzel9zdHJpbmcgPSAnYScgKyAoYyAtMjYpOwoJCX0KCX0KCgkqcHN6X3N0cmluZyA9ICdcMCc7CglyZXR1cm4gc3pfc3RyaW5nOwp9CgppbnQgZ2VuX2RhdGEoRklMRSogZnAsIHNpemVfdCB1X0dpQikgewoKCWNoYXIgc3pfYnVmW01BWF9MRU5HVEhfQlVGKzFdOwoKCXVuc2lnbmVkIGludCB1X3N0cmluZ19yZWNzOwoJdW5zaWduZWQgaW50IHVfaGF0ZW5hOwoJdW5zaWduZWQgaW50IHVfeHlfcmVjczsKCXVuc2lnbmVkIGludCB1X251bV9yZWNzOwoJY2hhciB4X29yX3k7Cgl1aW50NjRfdCB1X3BvczsKCgl0aW1lX3QgdV90aW1lID0gdGltZShOVUxMKTsKCXRtKiAgICBwdF90bSA9IDo6bG9jYWx0aW1lKCZ1X3RpbWUpOwoJY2hhciBzel90aW1lc3RhbXBbMHgyMF07Cgk6OnNwcmludGYoc3pfdGltZXN0YW1wLCAiJXMgJS4yZCAlMDJkOiUwMmQ6JTAyZCAlZCIsIGFzel9tb25bcHRfdG0tPnRtX21vbl0sIHB0X3RtLT50bV9tZGF5LCBwdF90bS0+dG1faG91ciwgcHRfdG0tPnRtX21pbiwgcHRfdG0tPnRtX3NlYywgcHRfdG0tPnRtX3llYXIrMTkwMCk7CgoJY2hhciBzel9xcV9idWZbTUFYX0xFTkdUSF9CVUYrMHg0MCsxXTsKCgkvLyDjgr/jgqTjg4jjg6vjgIHlgI3njocobWFnKeOAgijjgZPjga7kv4LmlbDjgpLkvb/jgaPjgabikaPjga7mlbDlgKTjgYvjgonlibLjgovjgIHmraPjga7mlbTmlbDjgIJ1bnNpZ25lZCBpbnQpCgk6OnNyYW5kKCh1bnNpZ25lZCBpbnQpdGltZShOVUxMKSk7Cgk6OmZwcmludGYoZnAsICIlcyAldVx4MGEiLCBnZW5fc3RyaW5nMihzel9idWYsIDEgKyAoUkFORCgpICUgTUFYX0xFTkdUSF9TRUNUSU9OKSksIFJBTkQoKSk7CgoJZm9yICg7OykgewoJCS8vIOKRoO+9vu+9uO+9vO+9ru++neWQjQoJCS8vIGV4LiBTRUNUSU9OX05BTUXjgIDikaAKCQk6OmZwcmludGYoZnAsICIlc1x4MGEiLCBnZW5fc3RyaW5nMihzel9idWYsIDEgKyAoUkFORCgpICUgTUFYX0xFTkdUSF9TRUNUSU9OKSkpOwoKCQkvLyDikaHvvb7vvbjvvbzvva7vvp3pm4boqIjlgKQKCQkvLyBleC4gMTEyMDAgMTEyMDAgMiBKdW4gIDkgMjM6MjM6MDAgMjAxOOOAgOKRoQovLwkJdV94eV9yZWNzID0gUkFORCgpICUgMHg4MDAwMDAwICsgMTsKCQl1X3h5X3JlY3MgPSBSQU5EKCkgJSAweDgwMDAgKyAxOwoJCXVfaGF0ZW5hICA9IHVfeHlfcmVjczsKCQl1X3N0cmluZ19yZWNzID0gUkFORCgpICUgMHgyMCArIDE7CgoJCTo6ZnByaW50ZihmcCwgIiV1ICV1ICV1ICVzXHgwYSIsIHVfeHlfcmVjcywgdV9oYXRlbmEsIHVfc3RyaW5nX3JlY3MsIHN6X3RpbWVzdGFtcCk7CgkKCQkvLyDikaLvvoPvvbfvvb3vvoQKCQkvLyBleC4gVGhpcyBpcyBwZW4u44CA4pGiCgkJLy8gICAgIGhlbGxvIHdvcmxkLuOAgOKRogoJCWZvciAodW5zaWduZWQgaW50IGogPSAwOyBqIDwgdV9zdHJpbmdfcmVjczsgKytqKSB7CgkJCTo6ZnByaW50ZihmcCwgIiVzXHgwYSIsIGdlbl9zdHJpbmcxKHN6X2J1ZiwgMSArIChSQU5EKCkgJSBNQVhfTEVOR1RIX1RFWFQpKSk7CgkJfQoKCQkvLyDikaPmlbDlgKQKCQkvLyBleC4geCAxIDLjgIDikaMKCQlmb3IgKHVuc2lnbmVkIGludCBqID0gMDsgaiA8IHVfeHlfcmVjczsgKytqKSB7CgkJCXhfb3JfeSA9IChSQU5EKCkgJSAyKSA/ICd4JyA6ICd5JzsKLy8JCQl1X251bV9yZWNzID0gUkFORCgpICUgMHg0MDAgKyAxOwoJCQl1X251bV9yZWNzID0gUkFORCgpICUgMHgxMDAgKyAxOwoKCQkJc3dpdGNoIChSQU5EKCkgJSAzKSB7CgoJCQkJY2FzZSAwOgoJCQkJCS8vIOKRpFFRIOisjuOBruihjAoJCQkJCS8vIFFRIHN1Ym5hbWUgLTEgMCAwIDEgLTIxMDAwMDAwIDYwMDAwMCAyCgkJCQkJLy8g4oaS44GT44Gu6KGM44GM54Sh44GE44OV44Kh44Kk44Or44KC44GC44KL44CCCgkJCQkJLy8g4oaSNyw444Kr44Op44Og44GvMeihjOebruOBruWAjeeOh+aVsOWtl+OBp+WJsuOCi++8iOaVsOWApOihjOOBqOWQjOOBmOioiOeul++8iQoJCQkJCS8vIOKGkjPvvZ4244Kr44Op44Og44GvIC0xLCAwLCAxLCDjga7jgYTjgZrjgozjgYvjgILjgZPjga4044Gk44Gu57WE44G/5ZCI44KP44Gb44Gn44GC44Go44Gn6KiI566X44Gr5L2/44GG44GT44Go44GM44GC44KL44CCCgkJCQkJLy8gMSAwIDAgMSDihpJUWVBFX0EKCQkJCQkvLyAwIDEgLTEgMCDihpJUWVBFX0IKCQkJCQkvLyAtMSAwIDAgLTEg4oaSVFlQRV9DCgkJCQkJLy8gMCAtMSAxIDAg4oaSVFlQRV9ECgkJCQkJLy8gLTEgMCAwIDEg4oaSVFlQRV9FCgkJCQkJLy8gMCAtMSAtMSAwIOKGklRZUEVfRgoJCQkJCS8vIDEgMCAwIC0xIOKGklRZUEVfRwoJCQkJCS8vIDAgMSAxIDAg4oaSVFlQRV9ICgkJCQkJLy8g4oaSOeOCq+ODqeODoOebruOBr+ato+OBruaVtOaVsOOAgih1bnNpZ25lZCBpbnQpCgkJCQkJLy8g4oaS5LiL6KiYNuOBpOOBruODkOODquOCqOODvOOCt+ODp+ODs+OBjOOBguOCiuOBvuOBmeOAggoJCQkJCS8vIFFRIHN1Ym5hbWUKCQkJCQkvLyBRUSBzdWJuYW1lIGMKCQkJCQkvLyBRUSBzdWJuYW1lIC0xIDAgMCAxIC0yMTAwMDAwMCA2MDAwMDAKCQkJCQkvLyBRUSBzdWJuYW1lIC0xIDAgMCAxIC0yMTAwMDAwMCA2MDAwMDAgMgoJCQkJCS8vIFFRIHN1Ym5hbWUgYyAtMSAwIDAgMSAtMjEwMDAwMDAgNjAwMDAwCgkJCQkJLy8gUVEgc3VibmFtZSBjIC0xIDAgMCAxIC0yMTAwMDAwMCA2MDAwMDAgMgoJCQkJCS8vIOKAu2Pjga9j44Go44GE44GG5paH5a2X5YiX5Zu65a6aCgkJCQkJLy8g4oC7MeOBpOOBruODleOCoeOCpOODq+OBq+WtmOWcqOOBmeOCi+OBruOBr+OBhOOBmuOCjOOBizHjgaTjga7jg5Xjgqnjg7zjg57jg4Pjg4gKCQkJCQlzd2l0Y2ggKFJBTkQoKSAlIDMpIHsKCQkJCQkJY2FzZSAwOgoJCQkJCQkJOjpzcHJpbnRmKHN6X3FxX2J1ZiwgIiVzIiwKCQkJCQkJCVJBTkQoKSAlIDIgPyAiIGMiIDogIiIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgMToKCQkJCQkJCTo6c3ByaW50Zihzel9xcV9idWYsICIlcyAlZCAlZCAlZCAlZCAlZCAlZCIsCgkJCQkJCQlSQU5EKCkgJSAyID8gIiBjIiA6ICIiLAoJCQkJCQkJKGludCkoUkFORCgpICUgMykgLSAxLCAoaW50KShSQU5EKCkgJSAzKSAtIDEsIChpbnQpKFJBTkQoKSAlIDMpIC0gMSwgKGludCkoUkFORCgpICUgMykgLSAxLAoJCQkJCQkJKGludDMyX3QpUkFORCgpLCAoaW50MzJfdClSQU5EKCkpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWRlZmF1bHQ6CgkJCQkJCQk6OnNwcmludGYoc3pfcXFfYnVmLCAiJXMgJWQgJWQgJWQgJWQgJWQgJWQgJXUiLAoJCQkJCQkJUkFORCgpICUgMiA/ICIgYyIgOiAiIiwKCQkJCQkJCShpbnQpKFJBTkQoKSAlIDMpIC0gMSwgKGludCkoUkFORCgpICUgMykgLSAxLCAoaW50KShSQU5EKCkgJSAzKSAtIDEsIChpbnQpKFJBTkQoKSAlIDMpIC0gMSwKCQkJCQkJCShpbnQzMl90KVJBTkQoKSwgKGludDMyX3QpUkFORCgpLCBSQU5EKCkpOwoJCQkJCQkJYnJlYWs7CgkJCQkJfQoJCQkJCS8vIOS4iuiomFFR6KGM44Gv5YWI6aCt44GuUVHjgYzjgarjgY/jgarjgaPjgaZ4LCB56KGM44Gr5a2Y5Zyo44GZ44KL44GT44Go44GM44GC44KK44G+44GZ44CCCgkJCQkJLy8gMeOBpOOBruODleOCoeOCpOODq+WGheOBp1FR6KGM44GoeCwgeeOBruW+jOOCjeOBq+OBj+OCi+ODkeOCv+ODvOODs+OBruS4oeaWueOBr+WtmOWcqOOBm+OBmuOAgeeJh+aWueOBjOWHuuOBpuOBjeOBn+OCieOCguOBhueJh+aWueOBr+WHuuOBpuOBjeOBvuOBm+OCk+OAggoJCQkJCS8vIHgsIHnjgajlkIzjgZjooYzjgavjgY/jgovloLTlkIjjga7jg5Xjgqnjg7zjg57jg4Pjg4jjgoJRUeihjOOBruimj+WJh+OBqOWQjOOBmOOBp+OBmeOAggoJCQkJCS8vIHggMSAyMzQgc3VibmFtZSAtMSAwIDAgMSAtMjEwMDAwMDAgNjAwMDAwIDIKCQkJCQkvLyB5IDIgMjM0IHN1Ym5hbWUgLTEgMCAwIDEgLTIxMDAwMDAwIDYwMDAwMCAyCgkJCQkJaWYgKFJBTkQoKSAlIDIpIHsKCQkJCQkJOjpmcHJpbnRmKGZwLCAiJWMgJXUgJXUlc1x4MGEiLCB4X29yX3ksIGogKyAxLCB1X251bV9yZWNzLCBzel9xcV9idWYpOwoJCQkJCX0gZWxzZSB7CgkJCQkJCTo6ZnByaW50ZihmcCwgIiVjICV1ICV1XHgwYSIsIHhfb3JfeSwgaiArIDEsIHVfbnVtX3JlY3MpOwoJCQkJCQk6OmZwcmludGYoZnAsICJRUSAlcyVzXHgwYSIsIGdlbl9zdHJpbmcyKHN6X2J1ZiwgMSArIChSQU5EKCkgJSBNQVhfTEVOR1RIX1NFQ1RJT04pKSwgc3pfcXFfYnVmKTsKCQkJCQl9CgkJCQkJYnJlYWs7CgoJCQkJY2FzZSAxOgoJCQkJCS8vIFJS6KGM44GM44GC44KK44G+44GZ44CCCgkJCQkJLy8g44GT44KM44KCUVHlkIzmp5h4LCB544Gu5qyh44Gu6KGM44Gr44GC44Gj44Gf44KK44Gq44GL44Gj44Gf44KK44GX44G+44GZ44CCCgkJCQkJLy8gUVHjgahSUuOBjOS4gOe3kuOBq+WHuuOBpuOBj+OCi+OBk+OBqOOBr+eEoeOBhOOBqOaAneOBhOOBvuOBmeOAggoJCQkJCS8vIOODleOCqeODvOODnuODg+ODiOOBr+OAjFJSIOato+OBruaVtOaVsOOAjeOBp1FR44Gu44KI44GG44GreCx544Gu5b6M44KN44Gr5p2l44KL44GT44Go44Gv44GC44KK44G+44Gb44KT44CCCgkJCQkJOjpmcHJpbnRmKGZwLCAiJWMgJXUgJXVceDBhIiwgeF9vcl95LCBqICsgMSwgdV9udW1fcmVjcyk7CgkJCQkJOjpmcHJpbnRmKGZwLCAiUlIgJXVceDBhIiwgUkFORCgpKTsKCQkJCQlicmVhazsKCgkJCQlkZWZhdWx0OgoJCQkJCTo6ZnByaW50ZihmcCwgIiVjICV1ICV1XHgwYSIsIHhfb3JfeSwgaiArIDEsIHVfbnVtX3JlY3MpOwoJCQkJCWJyZWFrOwoJCQl9CgoJCQlpZiAoeF9vcl95ID09ICd4JykgewoJCQkJZm9yICh1bnNpZ25lZCBpbnQgayA9IDA7IGsgPCB1X251bV9yZWNzOyArK2spIHsKCQkJCQkvLyAxMDAgMSAtMjAwMCAxMAoJCQkJCTo6ZnByaW50ZihmcCwgIiVkICVkICVkICVkXHgwYSIsCgkJCQkJCShpbnQzMl90KVJBTkQoKSwgKGludDMyX3QpUkFORCgpLCAoaW50MzJfdClSQU5EKCksIChpbnQzMl90KVJBTkQoKSk7CgkJCQl9CgkJCX0gZWxzZSB7CgkJCQlmb3IgKHVuc2lnbmVkIGludCBrID0gMDsgayA8IHVfbnVtX3JlY3M7ICsraykgewoJCQkJCS8vIC0xMDAgMTAwMDAKCQkJCQk6OmZwcmludGYoZnAsICIlZCAlZFx4MGEiLAoJCQkJCQkoaW50MzJfdClSQU5EKCksIChpbnQzMl90KVJBTkQoKSk7CgkJCQl9CgkJCX0KCQl9CgoJCXVfcG9zID0gZnRlbGxvKGZwKTsKCgkJaWYgKHVfcG9zID4gR0lHQSAqICh1aW50NjRfdCl1X0dpQikgewoJCQlicmVhazsKCQl9Cgl9CgoJcmV0dXJuIDA7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyKiogYXJndikgewoKCWlmIChhcmdjICE9IDMpIHsKCQk6OmZwcmludGYoc3RkZXJyLCAiVXNhZ2U6ICVzIDxmaWxlcGF0aD4gPEdpQiBzaXplPlxuIiwgYXJndlswXSk7CgkJcmV0dXJuIDE7Cgl9CgoJY2hhciogZmlsZW5hbWUgPSBhcmd2WzFdOwoJc2l6ZV90IHVfR2lCID0gOjpzdHJ0b3VsKGFyZ3ZbMl0sIE5VTEwsIDEwKTs7CgoJaWYgKHVfR2lCID09IDApIHsKCQk6OmZwcmludGYoc3RkZXJyLCAiVXNhZ2U6ICVzIDxmaWxlcGF0aD4gPEdpQiBzaXplPlxuIiwgYXJndlswXSk7CgkJOjpmcHJpbnRmKHN0ZGVyciwgIjxHaUIgc2l6ZT4gbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyb1xuIik7CgkJcmV0dXJuIDE7Cgl9CgoJRklMRSogZnAgPSA6OmZvcGVuKGZpbGVuYW1lLCAid2IiKTsKCWlmIChmcCA9PSBOVUxMKSB7CgkJOjpmcHJpbnRmKHN0ZGVyciwgImZhdGFsIGVycm9yOiBvcGVuIGZpbGUgZXJyb3IgXCIlc1wiXG4iLCBmaWxlbmFtZSk7CgkJcmV0dXJuIDE7Cgl9CgoJaWYgKDo6Z2VuX2RhdGEoZnAsIHVfR2lCKSA8IDApIHtmY2xvc2UoZnApOyByZXR1cm4gLTE7fQoJZmNsb3NlKGZwKTsKCXJldHVybiAwOwp9Cg==