#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
struct node
{
int flag;
struct node* alphabet[ 26 ] ;
} ;
struct node* root;
struct node* current; //記錄現在node產生的位置
struct node* previous; //記錄新產生node的前一個node之位置
int search_word( char * ) ;
typedef unsigned char BYTE;
typedef unsigned int UINT;
typedef UINT MD5_SUB_ARRAY[ 16 ] ;
typedef UINT MD5_TRANSORM_FUNC( UINT, UINT, UINT) ;
typedef struct
{
UINT a;
UINT b;
UINT c;
UINT d;
MD5_SUB_ARRAY sub_array;
} MD5_TRANSFORM_PARAM;
const double MAX_INT = ( double ) 0xFFFFFFFF + 1.0 ;
const UINT MD5_TRANSFORM_MATRIX[ 4 ] [ 16 ] [ 3 ] =
{
{
{ 0 , 7 , 1 } , { 1 , 12 , 2 } , { 2 , 17 , 3 } , { 3 , 22 , 4 } ,
{ 4 , 7 , 5 } , { 5 , 12 , 6 } , { 6 , 17 , 7 } , { 7 , 22 , 8 } ,
{ 8 , 7 , 9 } , { 9 , 12 , 10 } , { 10 , 17 , 11 } , { 11 , 22 , 12 } ,
{ 12 , 7 , 13 } , { 13 , 12 , 14 } , { 14 , 17 , 15 } , { 15 , 22 , 16 } ,
} ,
{
{ 1 , 5 , 17 } , { 6 , 9 , 18 } , { 11 , 14 , 19 } , { 0 , 20 , 20 } ,
{ 5 , 5 , 21 } , { 10 , 9 , 22 } , { 15 , 14 , 23 } , { 4 , 20 , 24 } ,
{ 9 , 5 , 25 } , { 14 , 9 , 26 } , { 3 , 14 , 27 } , { 8 , 20 , 28 } ,
{ 13 , 5 , 29 } , { 2 , 9 , 30 } , { 7 , 14 , 31 } , { 12 , 20 , 32 } ,
} ,
{
{ 5 , 4 , 33 } , { 8 , 11 , 34 } , { 11 , 16 , 35 } , { 14 , 23 , 36 } ,
{ 1 , 4 , 37 } , { 4 , 11 , 38 } , { 7 , 16 , 39 } , { 10 , 23 , 40 } ,
{ 13 , 4 , 41 } , { 0 , 11 , 42 } , { 3 , 16 , 43 } , { 6 , 23 , 44 } ,
{ 9 , 4 , 45 } , { 12 , 11 , 46 } , { 15 , 16 , 47 } , { 2 , 23 , 48 } ,
} ,
{
{ 0 , 6 , 49 } , { 7 , 10 , 50 } , { 14 , 15 , 51 } , { 5 , 21 , 52 } ,
{ 12 , 6 , 53 } , { 3 , 10 , 54 } , { 10 , 15 , 55 } , { 1 , 21 , 56 } ,
{ 8 , 6 , 57 } , { 15 , 10 , 58 } , { 6 , 15 , 59 } , { 13 , 21 , 60 } ,
{ 4 , 6 , 61 } , { 11 , 10 , 62 } , { 2 , 15 , 63 } , { 9 , 21 , 64 } ,
} ,
} ;
static UINT MD5_TRANSFORM_ARRAY[ 65 ] ;
void MD5_Init( )
{
int x;
for ( x = 1 ; x <= 64 ; x++ )
{
MD5_TRANSFORM_ARRAY
[ x
] = ( UINT
) ( MAX_INT
* fabs ( sin ( x
) ) ) ;
}
}
UINT F( UINT x, UINT y, UINT z)
{
return ( ( x & y) | ( ( ~x) & z) ) ;
}
UINT G( UINT x, UINT y, UINT z)
{
return ( ( x & z) | ( y & ( ~z) ) ) ;
}
UINT H( UINT x, UINT y, UINT z)
{
return ( x ^ y ^ z) ;
}
UINT I( UINT x, UINT y, UINT z)
{
return ( y ^ ( x | ( ~z) ) ) ;
}
BYTE* MD5_prepare_data( const BYTE* data, int len, int * new_len)
{
int rest, fill, size;
BYTE* new_data;
UINT bit_len;
// (1) 字節補齊
rest = len % 56 ;
if ( rest <= 56 ) fill = 56 - rest;
else fill = ( 64 - rest) + 56 ;
new_data
= ( BYTE
* ) malloc ( len
+ fill
+ 8 ) ;
if ( NULL == new_data) return NULL;
if ( len
> 0 ) memcpy ( new_data
, data
, len
) ;
if ( fill
> 0 ) memset ( new_data
+ len
, 0x80 , 1 ) ;
if ( fill
> 1 ) memset ( new_data
+ len
+ 1 , 0 , fill
- 1 ) ;
size = fill + len;
// (2) 附加數據的比特長度
bit_len = len * 8 ;
// (64位二進制數表示的)比特長度的低32位
memset ( new_data
+ size
+ 0 , ( bit_len
& 0x000000FF ) , 1 ) ;
memset ( new_data
+ size
+ 1 , ( bit_len
& 0x0000FF00 ) >> 8 , 1 ) ;
memset ( new_data
+ size
+ 2 , ( bit_len
& 0x00FF0000 ) >> 16 , 1 ) ;
memset ( new_data
+ size
+ 3 , ( bit_len
& 0xFF000000 ) >> 24 , 1 ) ;
// 不考慮比特長度超出32位無符號數表示範圍,所以高32位總是0
memset ( new_data
+ size
+ 4 , 0 , 4 ) ;
* new_len = size + 8 ;
return new_data;
}
void MD5_transform( MD5_TRANSFORM_PARAM* param, int ring, MD5_TRANSORM_FUNC func)
{
UINT a, b, c, d, s, k, i;
UINT abcd[ 4 ] ;
UINT * X,* T;
int index;
abcd[ 0 ] = param-> a;
abcd[ 1 ] = param-> b;
abcd[ 2 ] = param-> c;
abcd[ 3 ] = param-> d;
X = param-> sub_array;
T = MD5_TRANSFORM_ARRAY;
for ( index = 0 ; index < 16 ; index++ )
{
a = abcd[ ( 3 * index + 0 ) % 4 ] ;
b = abcd[ ( 3 * index + 1 ) % 4 ] ;
c = abcd[ ( 3 * index + 2 ) % 4 ] ;
d = abcd[ ( 3 * index + 3 ) % 4 ] ;
k = MD5_TRANSFORM_MATRIX[ ring] [ index] [ 0 ] ;
s = MD5_TRANSFORM_MATRIX[ ring] [ index] [ 1 ] ;
i = MD5_TRANSFORM_MATRIX[ ring] [ index] [ 2 ] ;
a = a + func( b, c, d) + X[ k] + T[ i] ;
a = ( a << s) | ( a >> ( 32 - s) ) ; // 循環左移
a = a + b;
abcd[ ( 3 * index + 0 ) % 4 ] = a;
}
param-> a = abcd[ 0 ] ;
param-> b = abcd[ 1 ] ;
param-> c = abcd[ 2 ] ;
param-> d = abcd[ 3 ] ;
}
char * MD5( const BYTE* data, int len)
{
int x, y, new_len;
MD5_TRANSFORM_PARAM param;
UINT AA, BB, CC, DD;
BYTE* buf;
MD5_Init( ) ;
buf = MD5_prepare_data( data, len,& new_len) ;
if ( buf == NULL) return NULL;
AA = 0x67452301 ;
BB = 0xefcdab89 ;
CC = 0x98badcfe ;
DD = 0x10325476 ;
for ( x = 0 ; x < new_len / 64 ; x++ )
{
param.a = AA;
param.b = BB;
param.c = CC;
param.d = DD;
for ( y = 0 ; y < 16 ; y++ )
{
param.sub_array [ y] = buf[ 64 * x + 4 * y + 0 ] ;
param.sub_array [ y] += buf[ 64 * x + 4 * y + 1 ] << 8 ;
param.sub_array [ y] += buf[ 64 * x + 4 * y + 2 ] << 16 ;
param.sub_array [ y] += buf[ 64 * x + 4 * y + 3 ] << 24 ;
}
MD5_transform( & param, 0 , F) ;
MD5_transform( & param, 1 , G) ;
MD5_transform( & param, 2 , H) ;
MD5_transform( & param, 3 , I) ;
AA += param.a ;
BB += param.b ;
CC += param.c ;
DD += param.d ;
}
//printf("MD5(\"%s\")=",data);
char * str
= malloc ( 33 * sizeof ( char ) ) ; memset ( str
, '\0 ' , 33 ) ; //對malloc出來的空間作初使化
int temp_num_1;
int temp_num_2;
int temp_num_3;
int temp_num_4;
char temp_str_1[ 4 ] ;
char temp_str_2[ 4 ] ;
char temp_str_3[ 4 ] ;
char temp_str_4[ 4 ] ;
/*printf("%02X%02X%02X%02X",
(AA & 0x000000FF),
(AA & 0x0000FF00) >> 8,
(AA & 0x00FF0000) >> 16,
(AA & 0xFF000000) >> 24);*/
/*temp_num_1=(AA & 0x000000FF);
temp_num_2=(AA & 0x000000FF)>>8;
temp_num_3=(AA & 0x000000FF)>>16;
temp_num_4=(AA & 0x000000FF)>>24;*/
sprintf ( temp_str_1
, "%02X" , ( AA
& 0x000000FF ) ) ; sprintf ( temp_str_2
, "%02X" , ( AA
& 0x0000FF00 ) >> 8 ) ; sprintf ( temp_str_3
, "%02X" , ( AA
& 0x00FF0000 ) >> 16 ) ; sprintf ( temp_str_4
, "%02X" , ( AA
& 0xFF000000 ) >> 24 ) ;
/*printf("%02X%02X%02X%02X",
(BB & 0x000000FF),
(BB & 0x0000FF00) >> 8,
(BB & 0x00FF0000) >> 16,
(BB & 0xFF000000) >> 24);*/
sprintf ( temp_str_1
, "%02X" , ( BB
& 0x000000FF ) ) ; sprintf ( temp_str_2
, "%02X" , ( BB
& 0x0000FF00 ) >> 8 ) ; sprintf ( temp_str_3
, "%02X" , ( BB
& 0x00FF0000 ) >> 16 ) ; sprintf ( temp_str_4
, "%02X" , ( BB
& 0xFF000000 ) >> 24 ) ;
/*printf("%02X%02X%02X%02X",
(CC & 0x000000FF),
(CC & 0x0000FF00) >> 8,
(CC & 0x00FF0000) >> 16,
(CC & 0xFF000000) >> 24);*/
sprintf ( temp_str_1
, "%02X" , ( CC
& 0x000000FF ) ) ; sprintf ( temp_str_2
, "%02X" , ( CC
& 0x0000FF00 ) >> 8 ) ; sprintf ( temp_str_3
, "%02X" , ( CC
& 0x00FF0000 ) >> 16 ) ; sprintf ( temp_str_4
, "%02X" , ( CC
& 0xFF000000 ) >> 24 ) ;
/*printf("%02X%02X%02X%02X",
(DD & 0x000000FF),
(DD & 0x0000FF00) >> 8,
(DD & 0x00FF0000) >> 16,
(DD & 0xFF000000) >> 24);*/
sprintf ( temp_str_1
, "%02X" , ( DD
& 0x000000FF ) ) ; sprintf ( temp_str_2
, "%02X" , ( DD
& 0x0000FF00 ) >> 8 ) ; sprintf ( temp_str_3
, "%02X" , ( DD
& 0x00FF0000 ) >> 16 ) ; sprintf ( temp_str_4
, "%02X" , ( DD
& 0xFF000000 ) >> 24 ) ;
//printf("%s",str);
return str;
}
int main( )
{
FILE* fp;
FILE* fp1;
//fp1=fopen("HashedPassword.txt","r");
fp1
= fopen ( "test.txt" , "r" ) ; char word[ 20 ] = { '\0 ' } ;
char * hash_password
= malloc ( 33 * sizeof ( char ) ) ; memset ( hash_password
, '\0 ' , 33 ) ; char * md5_result;
//char* md5_result=malloc(33*sizeof(char));//用array就不行??
//memset(md5_result,'\0',33);
int i, j, z;
char ch;
int find_password_num= 0 ;
/*md5_result=MD5("",0);
printf("md5_result=%s\n",md5_result);
printf("\n");
md5_result=MD5("123456",strlen("123456"));
printf("md5_result=%s\n",md5_result);
printf("\n");
md5_result=MD5("abc",3);
printf("md5_result=%s\n",md5_result);
printf("\n");
md5_result=MD5("message digest",14);
printf("md5_result=%s\n",md5_result);
printf("\n");
md5_result=MD5("abcdefghijklmnopqrstuvwxyz",26);
printf("md5_result=%s\n",md5_result);
printf("\n");*/
while ( fscanf ( fp
, "%s" , word
) == 1 ) {
md5_result
= MD5
( word
, strlen ( word
) ) ; while ( fscanf ( fp1
, "%s" , hash_password
) == 1 ) {
if ( stricmp( md5_result, hash_password) == 0 )
{
//printf("%s %s\n",md5_result,hash_password);
find_password_num++;
}
}
//printf("word=%s md5_result=%s\n",word,md5_result);
}
printf ( "find_password_num=%d" , find_password_num
) ;
return 0 ;
}
int search_word( char * str) //,struct node* root)
{
struct node* current= root;
char ch;
{
ch= str[ i] ;
if ( current-> alphabet[ ch- 'a' ] == NULL)
{
//printf("i=%d current->flag=%d\n",i,current->flag);
return 0 ;
}
else if ( current-> alphabet[ ch- 'a' ] != NULL)
{
current= current-> alphabet[ ch- 'a' ] ;
//printf("i=%d current->flag=%d\n",i,current->flag);
if ( i== 0 )
{
if ( current-> flag== 1 )
{
return 1 ;
}
else
{
return 0 ;
}
}
else
{
}
}
}
}
I2luY2x1ZGUgPHN0ZGlvLmg+CgojaW5jbHVkZSA8c3RkbGliLmg+CgojaW5jbHVkZSA8bWVtb3J5Lmg+CgojaW5jbHVkZSA8bWF0aC5oPgoKc3RydWN0IG5vZGUKewogICAgaW50IGZsYWc7CiAgICBzdHJ1Y3Qgbm9kZSogYWxwaGFiZXRbMjZdOyAgICAgICAKfTsKc3RydWN0IG5vZGUqIHJvb3Q7CnN0cnVjdCBub2RlKiBjdXJyZW50Oy8v6KiY6YyE54++5Zyobm9kZeeUoueUn+eahOS9jee9riAKc3RydWN0IG5vZGUqIHByZXZpb3VzOy8v6KiY6YyE5paw55Si55Sfbm9kZeeahOWJjeS4gOWAi25vZGXkuYvkvY3nva4gCgppbnQgc2VhcmNoX3dvcmQoY2hhciopOwoKCnR5cGVkZWYgdW5zaWduZWQgY2hhciBCWVRFOwoKdHlwZWRlZiB1bnNpZ25lZCBpbnQgIFVJTlQ7Cgp0eXBlZGVmIFVJTlQgTUQ1X1NVQl9BUlJBWVsxNl07Cgp0eXBlZGVmIFVJTlQgTUQ1X1RSQU5TT1JNX0ZVTkMoVUlOVCxVSU5ULFVJTlQpOwoKdHlwZWRlZiBzdHJ1Y3QKCnsKCiAgICBVSU5UICAgIGE7CgogICAgVUlOVCAgICBiOwoKICAgIFVJTlQgICAgYzsKCiAgICBVSU5UICAgIGQ7CgogICAgTUQ1X1NVQl9BUlJBWSAgIHN1Yl9hcnJheTsKCn1NRDVfVFJBTlNGT1JNX1BBUkFNOwoKCmNvbnN0IGRvdWJsZSAgICBNQVhfSU5UID0gKGRvdWJsZSkweEZGRkZGRkZGICsgMS4wOwoKCmNvbnN0IFVJTlQgTUQ1X1RSQU5TRk9STV9NQVRSSVhbNF1bMTZdWzNdID0KCnsKCgoKICAgIHsKCiAgICB7IDAsIDcsIDF9LCB7IDEsMTIsIDJ9LCB7IDIsMTcsIDN9LCB7IDMsMjIsIDR9LAoKICAgIHsgNCwgNywgNX0sIHsgNSwxMiwgNn0sIHsgNiwxNywgN30sIHsgNywyMiwgOH0sCgogICAgeyA4LCA3LCA5fSwgeyA5LDEyLDEwfSwgezEwLDE3LDExfSwgezExLDIyLDEyfSwKCiAgICB7MTIsIDcsMTN9LCB7MTMsMTIsMTR9LCB7MTQsMTcsMTV9LCB7MTUsMjIsMTZ9LAoKICAgIH0sCgoKCiAgICB7CgogICAgeyAxLCA1LDE3fSwgeyA2LCA5LDE4fSwgezExLDE0LDE5fSwgeyAwLDIwLDIwfSwKCiAgICB7IDUsIDUsMjF9LCB7MTAsIDksMjJ9LCB7MTUsMTQsMjN9LCB7IDQsMjAsMjR9LAoKICAgIHsgOSwgNSwyNX0sIHsxNCwgOSwyNn0sIHsgMywxNCwyN30sIHsgOCwyMCwyOH0sCgogICAgezEzLCA1LDI5fSwgeyAyLCA5LDMwfSwgeyA3LDE0LDMxfSwgezEyLDIwLDMyfSwKCiAgICB9LAoKCgogICAgewoKICAgIHs1LCA0LCAzM30sIHsgOCwxMSwzNH0sIHsxMSwxNiwzNX0sezE0LCAyMywzNn0sCgogICAgezEsIDQsIDM3fSwgeyA0LDExLDM4fSwgeyA3LDE2LDM5fSx7MTAsIDIzLDQwfSwKCiAgICB7MTMsNCwgNDF9LCB7IDAsMTEsNDJ9LCB7IDMsMTYsNDN9LHsgNiwgMjMsNDR9LAoKICAgIHs5LCA0LCA0NX0sIHsxMiwxMSw0Nn0sIHsxNSwxNiw0N30seyAyLCAyMyw0OH0sCgogICAgfSwKCgoKICAgIHsKCiAgICB7IDAsNiw0OX0sICB7IDcsMTAsNTB9LCB7MTQsMTUsNTF9LHsgNSwgMjEsNTJ9LAoKICAgIHsxMiw2LDUzfSwgIHsgMywxMCw1NH0sIHsxMCwxNSw1NX0seyAxLCAyMSw1Nn0sCgogICAgeyA4LDYsNTd9LCAgezE1LDEwLDU4fSwgeyA2LDE1LDU5fSx7MTMsIDIxLDYwfSwKCiAgICB7IDQsNiw2MX0sICB7MTEsMTAsNjJ9LCB7IDIsMTUsNjN9LHsgOSwgMjEsNjR9LAoKICAgIH0sCgp9OwoKCnN0YXRpYyBVSU5UIE1ENV9UUkFOU0ZPUk1fQVJSQVlbNjVdOwoKCnZvaWQgTUQ1X0luaXQoKQoKewoKICAgIGludCB4OwoKICAgIGZvcih4ID0gMTsgeCA8PSA2NDsgeCsrKQoKICAgIHsKCiAgICAgICAgTUQ1X1RSQU5TRk9STV9BUlJBWVt4XSA9IChVSU5UKShNQVhfSU5UICogZmFicyhzaW4oeCkpKTsKCiAgICB9Cgp9CgoKVUlOVCBGKFVJTlQgeCxVSU5UIHksVUlOVCB6KQoKewoKICAgIHJldHVybiAoKHggJiB5KSB8ICgofngpICYgeikpOwoKfQoKClVJTlQgRyhVSU5UIHgsVUlOVCB5LFVJTlQgeikKCnsKCiAgICByZXR1cm4gKCh4ICYgeikgfCAoeSAmICh+eikpKTsKCn0KCgpVSU5UIEgoVUlOVCB4LFVJTlQgeSxVSU5UIHopCgp7CgogICAgcmV0dXJuICh4IF4geSBeIHopOwoKfQoKClVJTlQgSShVSU5UIHgsVUlOVCB5LFVJTlQgeikKCnsKCiAgICByZXR1cm4gKHkgXiAoeCB8ICh+eikpKTsKCn0KCgoKCkJZVEUqIE1ENV9wcmVwYXJlX2RhdGEoY29uc3QgQllURSogZGF0YSxpbnQgbGVuLGludCogbmV3X2xlbikKCnsKCiAgICBpbnQgcmVzdCxmaWxsLHNpemU7CgogICAgQllURSogbmV3X2RhdGE7CgogICAgVUlOVCAgYml0X2xlbjsKCgogICAgLy8gKDEpIOWtl+evgOijnOm9igoKICAgIHJlc3QgPSBsZW4gJSA1NjsKCiAgICBpZiAocmVzdCA8PSA1NikgZmlsbCA9IDU2IC0gcmVzdDsKCiAgICBlbHNlIGZpbGwgPSAoNjQgLSByZXN0KSArIDU2OwoKCiAgICBuZXdfZGF0YSA9IChCWVRFKiltYWxsb2MobGVuICsgZmlsbCArIDgpOwoKICAgIGlmIChOVUxMID09IG5ld19kYXRhKSByZXR1cm4gTlVMTDsKCgogICAgaWYgKGxlbiA+IDApICAgIG1lbWNweShuZXdfZGF0YSxkYXRhLGxlbik7CgogICAgaWYgKGZpbGwgPiAwKSAgIG1lbXNldChuZXdfZGF0YSArIGxlbiwweDgwLDEpOwoKICAgIGlmIChmaWxsID4gMSkgICBtZW1zZXQobmV3X2RhdGEgKyBsZW4gKyAxLDAsZmlsbCAtIDEpOwoKCiAgICBzaXplID0gZmlsbCArIGxlbjsKCgogICAgLy8gKDIpIOmZhOWKoOaVuOaTmueahOavlOeJuemVt+W6pgoKICAgIGJpdF9sZW4gPSBsZW4gKiA4OwoKICAgIC8vICg2NOS9jeS6jOmAsuWItuaVuOihqOekuueahCnmr5TnibnplbfluqbnmoTkvY4zMuS9jQoKICAgIG1lbXNldChuZXdfZGF0YSArIHNpemUgKyAwLChiaXRfbGVuICYgMHgwMDAwMDBGRiksICAgICAgMSk7CgogICAgbWVtc2V0KG5ld19kYXRhICsgc2l6ZSArIDEsKGJpdF9sZW4gJiAweDAwMDBGRjAwKSA+PiA4LCAxKTsKCiAgICBtZW1zZXQobmV3X2RhdGEgKyBzaXplICsgMiwoYml0X2xlbiAmIDB4MDBGRjAwMDApID4+IDE2LDEpOwoKICAgIG1lbXNldChuZXdfZGF0YSArIHNpemUgKyAzLChiaXRfbGVuICYgMHhGRjAwMDAwMCkgPj4gMjQsMSk7CgogICAgLy8g5LiN6ICD5oWu5q+U54m56ZW35bqm6LaF5Ye6MzLkvY3nhKHnrKbomZ/mlbjooajnpLrnr4TlnI0s5omA5Lul6auYMzLkvY3nuL3mmK8wCgogICAgbWVtc2V0KG5ld19kYXRhICsgc2l6ZSArIDQsMCw0KTsKCgogICAgKm5ld19sZW4gPSBzaXplICsgODsKCgogICAgcmV0dXJuIG5ld19kYXRhOwoKfQoKCnZvaWQgTUQ1X3RyYW5zZm9ybShNRDVfVFJBTlNGT1JNX1BBUkFNKiBwYXJhbSxpbnQgcmluZyxNRDVfVFJBTlNPUk1fRlVOQyBmdW5jKQoKewoKICAgIFVJTlQgYSxiLGMsZCxzLGssaTsKCiAgICBVSU5UIGFiY2RbNF07CgogICAgVUlOVCAqWCwqVDsKCiAgICBpbnQgaW5kZXg7CgoKICAgIGFiY2RbMF0gPSBwYXJhbS0+YTsKCiAgICBhYmNkWzFdID0gcGFyYW0tPmI7CgogICAgYWJjZFsyXSA9IHBhcmFtLT5jOwoKICAgIGFiY2RbM10gPSBwYXJhbS0+ZDsKCiAgICBYID0gcGFyYW0tPnN1Yl9hcnJheTsKCiAgICBUID0gTUQ1X1RSQU5TRk9STV9BUlJBWTsKCgogICAgZm9yKGluZGV4ID0gMDsgaW5kZXggPCAxNjsgaW5kZXgrKykKCiAgICB7CgogICAgICAgIGEgPSBhYmNkWygzICogaW5kZXggKyAwKSAlIDRdOwoKICAgICAgICBiID0gYWJjZFsoMyAqIGluZGV4ICsgMSkgJSA0XTsKCiAgICAgICAgYyA9IGFiY2RbKDMgKiBpbmRleCArIDIpICUgNF07CgogICAgICAgIGQgPSBhYmNkWygzICogaW5kZXggKyAzKSAlIDRdOwoKCiAgICAgICAgayA9IE1ENV9UUkFOU0ZPUk1fTUFUUklYW3JpbmddW2luZGV4XVswXTsKCiAgICAgICAgcyA9IE1ENV9UUkFOU0ZPUk1fTUFUUklYW3JpbmddW2luZGV4XVsxXTsKCiAgICAgICAgaSA9IE1ENV9UUkFOU0ZPUk1fTUFUUklYW3JpbmddW2luZGV4XVsyXTsKCgogICAgICAgIGEgPSBhICsgZnVuYyhiLGMsZCkgKyBYW2tdICsgVFtpXTsKCiAgICAgICAgYSA9ICggYSA8PCBzKSB8ICggYSA+PiAoMzIgLSBzKSk7IC8vIOW+queSsOW3puenuwoKICAgICAgICBhID0gYSArIGI7CgoKICAgICAgICBhYmNkWygzICogaW5kZXggKyAwKSAlIDRdID0gYTsKCiAgICB9CgoKICAgIHBhcmFtLT5hID0gYWJjZFswXTsKCiAgICBwYXJhbS0+YiA9IGFiY2RbMV07CgogICAgcGFyYW0tPmMgPSBhYmNkWzJdOwoKICAgIHBhcmFtLT5kID0gYWJjZFszXTsKCn0KCgpjaGFyKiBNRDUoY29uc3QgQllURSogZGF0YSxpbnQgbGVuKQoKewoKICAgIGludCAgeCx5LG5ld19sZW47CgogICAgTUQ1X1RSQU5TRk9STV9QQVJBTSBwYXJhbTsKCiAgICBVSU5UIEFBLEJCLENDLEREOwoKICAgIEJZVEUqIGJ1ZjsKCgogICAgTUQ1X0luaXQoKTsKCgogICAgYnVmID0gTUQ1X3ByZXBhcmVfZGF0YShkYXRhLGxlbiwmbmV3X2xlbik7CgogICAgaWYgKGJ1ZiA9PSBOVUxMKSByZXR1cm4gTlVMTDsKCgogICAgQUEgPSAweDY3NDUyMzAxOwoKICAgIEJCID0gMHhlZmNkYWI4OTsKCiAgICBDQyA9IDB4OThiYWRjZmU7CgogICAgREQgPSAweDEwMzI1NDc2OwoKCiAgICBmb3IoeCA9IDA7IHggPCBuZXdfbGVuIC8gNjQ7IHgrKykKCiAgICB7CgogICAgICAgIHBhcmFtLmEgPSBBQTsKCiAgICAgICAgcGFyYW0uYiA9IEJCOwoKICAgICAgICBwYXJhbS5jID0gQ0M7CgogICAgICAgIHBhcmFtLmQgPSBERDsKCgogICAgICAgIGZvcih5ID0gMDsgeSA8IDE2OyB5KyspCgogICAgICAgIHsKCiAgICAgICAgICAgIHBhcmFtLnN1Yl9hcnJheVt5XSAgPSBidWZbNjQgKiB4ICsgNCAqIHkgKyAwXTsKCiAgICAgICAgICAgIHBhcmFtLnN1Yl9hcnJheVt5XSArPSBidWZbNjQgKiB4ICsgNCAqIHkgKyAxXSA8PCA4OwoKICAgICAgICAgICAgcGFyYW0uc3ViX2FycmF5W3ldICs9IGJ1Zls2NCAqIHggKyA0ICogeSArIDJdIDw8IDE2OwoKICAgICAgICAgICAgcGFyYW0uc3ViX2FycmF5W3ldICs9IGJ1Zls2NCAqIHggKyA0ICogeSArIDNdIDw8IDI0OwoKICAgICAgICB9CgogICAgICAgIE1ENV90cmFuc2Zvcm0oJnBhcmFtLDAsRik7CgogICAgICAgIE1ENV90cmFuc2Zvcm0oJnBhcmFtLDEsRyk7CgogICAgICAgIE1ENV90cmFuc2Zvcm0oJnBhcmFtLDIsSCk7CgogICAgICAgIE1ENV90cmFuc2Zvcm0oJnBhcmFtLDMsSSk7CgoKICAgICAgICBBQSArPSBwYXJhbS5hOwoKICAgICAgICBCQiArPSBwYXJhbS5iOwoKICAgICAgICBDQyArPSBwYXJhbS5jOwoKICAgICAgICBERCArPSBwYXJhbS5kOwoKICAgIH0KCgogICAgLy9wcmludGYoIk1ENShcIiVzXCIpPSIsZGF0YSk7CgogICAgY2hhciogc3RyPW1hbGxvYygzMypzaXplb2YoY2hhcikpOwogICAgbWVtc2V0KHN0ciwnXDAnLDMzKTsvL+WwjW1hbGxvY+WHuuS+hueahOepuumWk+S9nOWIneS9v+WMliAKICAgIAogICAgaW50IHRlbXBfbnVtXzE7CiAgICBpbnQgdGVtcF9udW1fMjsKICAgIGludCB0ZW1wX251bV8zOwogICAgaW50IHRlbXBfbnVtXzQ7CiAgICBjaGFyIHRlbXBfc3RyXzFbNF07CiAgICBjaGFyIHRlbXBfc3RyXzJbNF07CiAgICBjaGFyIHRlbXBfc3RyXzNbNF07CiAgICBjaGFyIHRlbXBfc3RyXzRbNF07CiAgICAKICAgIC8qcHJpbnRmKCIlMDJYJTAyWCUwMlglMDJYIiwKCiAgICAgICAgKEFBICYgMHgwMDAwMDBGRiksCgogICAgICAgIChBQSAmIDB4MDAwMEZGMDApID4+IDgsCgogICAgICAgIChBQSAmIDB4MDBGRjAwMDApID4+IDE2LAoKICAgICAgICAoQUEgJiAweEZGMDAwMDAwKSA+PiAyNCk7Ki8KICAgIAogICAgLyp0ZW1wX251bV8xPShBQSAmIDB4MDAwMDAwRkYpOwogICAgdGVtcF9udW1fMj0oQUEgJiAweDAwMDAwMEZGKT4+ODsKICAgIHRlbXBfbnVtXzM9KEFBICYgMHgwMDAwMDBGRik+PjE2OwogICAgdGVtcF9udW1fND0oQUEgJiAweDAwMDAwMEZGKT4+MjQ7Ki8KICAgIHNwcmludGYodGVtcF9zdHJfMSwiJTAyWCIsKEFBICYgMHgwMDAwMDBGRikpOwogICAgc3ByaW50Zih0ZW1wX3N0cl8yLCIlMDJYIiwoQUEgJiAweDAwMDBGRjAwKSA+PiA4KTsKICAgIHNwcmludGYodGVtcF9zdHJfMywiJTAyWCIsKEFBICYgMHgwMEZGMDAwMCkgPj4gMTYpOwogICAgc3ByaW50Zih0ZW1wX3N0cl80LCIlMDJYIiwoQUEgJiAweEZGMDAwMDAwKSA+PiAyNCk7CiAgICAKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfMSk7CiAgICBzdHJjYXQoc3RyLHRlbXBfc3RyXzIpOwogICAgc3RyY2F0KHN0cix0ZW1wX3N0cl8zKTsKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfNCk7CgogICAgLypwcmludGYoIiUwMlglMDJYJTAyWCUwMlgiLAoKICAgICAgICAoQkIgJiAweDAwMDAwMEZGKSwKCiAgICAgICAgKEJCICYgMHgwMDAwRkYwMCkgPj4gOCwKCiAgICAgICAgKEJCICYgMHgwMEZGMDAwMCkgPj4gMTYsCgogICAgICAgIChCQiAmIDB4RkYwMDAwMDApID4+IDI0KTsqLwoKICAgIHNwcmludGYodGVtcF9zdHJfMSwiJTAyWCIsKEJCICYgMHgwMDAwMDBGRikpOwogICAgc3ByaW50Zih0ZW1wX3N0cl8yLCIlMDJYIiwoQkIgJiAweDAwMDBGRjAwKSA+PiA4KTsKICAgIHNwcmludGYodGVtcF9zdHJfMywiJTAyWCIsKEJCICYgMHgwMEZGMDAwMCkgPj4gMTYpOwogICAgc3ByaW50Zih0ZW1wX3N0cl80LCIlMDJYIiwoQkIgJiAweEZGMDAwMDAwKSA+PiAyNCk7CiAgICAKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfMSk7CiAgICBzdHJjYXQoc3RyLHRlbXBfc3RyXzIpOwogICAgc3RyY2F0KHN0cix0ZW1wX3N0cl8zKTsKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfNCk7CgogICAgLypwcmludGYoIiUwMlglMDJYJTAyWCUwMlgiLAoKICAgICAgICAoQ0MgJiAweDAwMDAwMEZGKSwKCiAgICAgICAgKENDICYgMHgwMDAwRkYwMCkgPj4gOCwKCiAgICAgICAgKENDICYgMHgwMEZGMDAwMCkgPj4gMTYsCgogICAgICAgIChDQyAmIDB4RkYwMDAwMDApID4+IDI0KTsqLwoKICAgIHNwcmludGYodGVtcF9zdHJfMSwiJTAyWCIsKENDICYgMHgwMDAwMDBGRikpOwogICAgc3ByaW50Zih0ZW1wX3N0cl8yLCIlMDJYIiwoQ0MgJiAweDAwMDBGRjAwKSA+PiA4KTsKICAgIHNwcmludGYodGVtcF9zdHJfMywiJTAyWCIsKENDICYgMHgwMEZGMDAwMCkgPj4gMTYpOwogICAgc3ByaW50Zih0ZW1wX3N0cl80LCIlMDJYIiwoQ0MgJiAweEZGMDAwMDAwKSA+PiAyNCk7CiAgICAKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfMSk7CiAgICBzdHJjYXQoc3RyLHRlbXBfc3RyXzIpOwogICAgc3RyY2F0KHN0cix0ZW1wX3N0cl8zKTsKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfNCk7CgogICAgLypwcmludGYoIiUwMlglMDJYJTAyWCUwMlgiLAoKICAgICAgICAoREQgJiAweDAwMDAwMEZGKSwKCiAgICAgICAgKEREICYgMHgwMDAwRkYwMCkgPj4gOCwKCiAgICAgICAgKEREICYgMHgwMEZGMDAwMCkgPj4gMTYsCgogICAgICAgIChERCAmIDB4RkYwMDAwMDApID4+IDI0KTsqLwoKICAgIHNwcmludGYodGVtcF9zdHJfMSwiJTAyWCIsKEREICYgMHgwMDAwMDBGRikpOwogICAgc3ByaW50Zih0ZW1wX3N0cl8yLCIlMDJYIiwoREQgJiAweDAwMDBGRjAwKSA+PiA4KTsKICAgIHNwcmludGYodGVtcF9zdHJfMywiJTAyWCIsKEREICYgMHgwMEZGMDAwMCkgPj4gMTYpOwogICAgc3ByaW50Zih0ZW1wX3N0cl80LCIlMDJYIiwoREQgJiAweEZGMDAwMDAwKSA+PiAyNCk7CiAgICAKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfMSk7CiAgICBzdHJjYXQoc3RyLHRlbXBfc3RyXzIpOwogICAgc3RyY2F0KHN0cix0ZW1wX3N0cl8zKTsKICAgIHN0cmNhdChzdHIsdGVtcF9zdHJfNCk7CiAgICAKICAgIC8vcHJpbnRmKCIlcyIsc3RyKTsKICAgICAKICAgIHJldHVybiBzdHI7Cgp9CgoKCmludCBtYWluKCkKCnsKICAgIEZJTEUqIGZwOwogICAgRklMRSogZnAxOwogICAgZnA9Zm9wZW4oImVuZy50eHQiLCJyIik7CiAgICAvL2ZwMT1mb3BlbigiSGFzaGVkUGFzc3dvcmQudHh0IiwiciIpOwogICAgZnAxPWZvcGVuKCJ0ZXN0LnR4dCIsInIiKTsKICAgIGNoYXIgd29yZFsyMF09eydcMCd9OwogICAgY2hhciogaGFzaF9wYXNzd29yZD1tYWxsb2MoMzMqc2l6ZW9mKGNoYXIpKTsKICAgIG1lbXNldChoYXNoX3Bhc3N3b3JkLCdcMCcsMzMpOwogICAgY2hhciogbWQ1X3Jlc3VsdDsKICAgIC8vY2hhciogbWQ1X3Jlc3VsdD1tYWxsb2MoMzMqc2l6ZW9mKGNoYXIpKTsvL+eUqGFycmF55bCx5LiN6KGMPz8gCiAgICAvL21lbXNldChtZDVfcmVzdWx0LCdcMCcsMzMpOwogICAgaW50IGksaix6OwogICAgY2hhciBjaDsKICAgIGludCBmaW5kX3Bhc3N3b3JkX251bT0wOwogICAgCiAgICAvKm1kNV9yZXN1bHQ9TUQ1KCIiLDApOwogICAgcHJpbnRmKCJtZDVfcmVzdWx0PSVzXG4iLG1kNV9yZXN1bHQpOwogICAgcHJpbnRmKCJcbiIpOwogICAgCiAgICBtZDVfcmVzdWx0PU1ENSgiMTIzNDU2IixzdHJsZW4oIjEyMzQ1NiIpKTsKICAgIHByaW50ZigibWQ1X3Jlc3VsdD0lc1xuIixtZDVfcmVzdWx0KTsKICAgIHByaW50ZigiXG4iKTsKICAgIAogICAgbWQ1X3Jlc3VsdD1NRDUoImFiYyIsMyk7CiAgICBwcmludGYoIm1kNV9yZXN1bHQ9JXNcbiIsbWQ1X3Jlc3VsdCk7CiAgICBwcmludGYoIlxuIik7CiAgICAKICAgIG1kNV9yZXN1bHQ9TUQ1KCJtZXNzYWdlIGRpZ2VzdCIsMTQpOwogICAgcHJpbnRmKCJtZDVfcmVzdWx0PSVzXG4iLG1kNV9yZXN1bHQpOwogICAgcHJpbnRmKCJcbiIpOwogICAgCiAgICBtZDVfcmVzdWx0PU1ENSgiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoiLDI2KTsKICAgIHByaW50ZigibWQ1X3Jlc3VsdD0lc1xuIixtZDVfcmVzdWx0KTsKICAgIHByaW50ZigiXG4iKTsqLwogICAgCiAgICB3aGlsZShmc2NhbmYoZnAsIiVzIix3b3JkKT09MSkKICAgIHsKICAgICAgICBtZDVfcmVzdWx0PU1ENSh3b3JkLHN0cmxlbih3b3JkKSk7ICAgCiAgICAgICAgd2hpbGUoZnNjYW5mKGZwMSwiJXMiLGhhc2hfcGFzc3dvcmQpPT0xKQogICAgICAgIHsKICAgICAgICAgICAgcHJpbnRmKCIlc1xuIixoYXNoX3Bhc3N3b3JkKTsKICAgICAgICAgICAgaWYoc3RyaWNtcChtZDVfcmVzdWx0LGhhc2hfcGFzc3dvcmQpPT0wKSAgCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vcHJpbnRmKCIlcyAlc1xuIixtZDVfcmVzdWx0LGhhc2hfcGFzc3dvcmQpOwogICAgICAgICAgICAgICAgZmluZF9wYXNzd29yZF9udW0rKzsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIHN5c3RlbSgicGF1c2UiKTsKICAgICAgICByZXdpbmQoZnAxKTsKICAgICAgICAvL3ByaW50Zigid29yZD0lcyBtZDVfcmVzdWx0PSVzXG4iLHdvcmQsbWQ1X3Jlc3VsdCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAKICAgIH0KICAgIHByaW50ZigiZmluZF9wYXNzd29yZF9udW09JWQiLGZpbmRfcGFzc3dvcmRfbnVtKTsKICAgIHN5c3RlbSgicGF1c2UiKTsKCiAgICByZXR1cm4gMDsKCn0KCmludCBzZWFyY2hfd29yZChjaGFyKiBzdHIpLy8sc3RydWN0IG5vZGUqIHJvb3QpCnsKICAgIHN0cnVjdCBub2RlKiBjdXJyZW50PXJvb3Q7CiAgICBpbnQgaT1zdHJsZW4oc3RyKS0xOwogICAgY2hhciBjaDsKICAgIAogICAgZm9yKGk9c3RybGVuKHN0ciktMTtpPj0wO2ktLSkKICAgIHsKICAgICAgICBjaD1zdHJbaV07CiAgICAgICAgaWYoY3VycmVudC0+YWxwaGFiZXRbY2gtJ2EnXT09TlVMTCkKICAgICAgICB7CiAgICAgICAgICAgIC8vcHJpbnRmKCJpPSVkIGN1cnJlbnQtPmZsYWc9JWRcbiIsaSxjdXJyZW50LT5mbGFnKTsKICAgICAgICAgICAgcmV0dXJuIDA7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIGVsc2UgaWYoY3VycmVudC0+YWxwaGFiZXRbY2gtJ2EnXSE9TlVMTCkKICAgICAgICB7CiAgICAgICAgICAgIAogICAgICAgICAgICBjdXJyZW50PWN1cnJlbnQtPmFscGhhYmV0W2NoLSdhJ107CiAgICAgICAgICAgIC8vcHJpbnRmKCJpPSVkIGN1cnJlbnQtPmZsYWc9JWRcbiIsaSxjdXJyZW50LT5mbGFnKTsKICAgICAgICAgICAgaWYoaT09MCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgaWYoY3VycmVudC0+ZmxhZz09MSkKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDsgICAgCiAgICAgICAgICAgICAgICB9ICAgICAgICAgICAgCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgfSAgICAgICAgICAKICAgICAgICB9CiAgICB9Cn0KCgo=