import collections
equal_class = collections.OrderedDict()
equal_class['END_EQCLS'] = {'bits': 0, 'body':[] }
equal_class['ENT_EQCLS'] = {'bits': 3, 'body':['', '{}[]:,', ' \t\r\n', '"', '-0123456789', 't', 'f', 'n']}
equal_class['STR_EQCLS'] = {'bits': 2, 'body':['', '\0', '"', '\\']}
equal_class['ESC_EQCLS'] = {'bits': 2, 'body':['', '\\rftnb"/', 'u']}
equal_class['HEX_EQCLS'] = {'bits': 1, 'body':['', '0123456789abcdefABCDEF']}
equal_class['NUM_EQCLS'] = {'bits': 2, 'body':['', '-', '0', '123456789']}
equal_class['FRAC_EQCLS'] ={'bits': 2, 'body':['', '.', 'eE', '0123456789']}
equal_class['EXP_EQCLS'] = {'bits': 2, 'body':['', '+-', '0123456789']}
equal_class['TRUE_T_EQCLS'] = {'bits': 1, 'body':['', 'r']}
equal_class['TRUE_R_EQCLS'] = {'bits': 1, 'body':['', 'u']}
equal_class['TRUE_U_EQCLS'] = {'bits': 1, 'body':['', 'e']}
equal_class['FALSE_F_EQCLS'] = {'bits': 1, 'body':['', 'a']}
equal_class['FALSE_A_EQCLS'] = {'bits': 1, 'body':['', 'l']}
equal_class['FALSE_L_EQCLS'] = {'bits': 1, 'body':['', 's']}
equal_class['FALSE_S_EQCLS'] = {'bits': 1, 'body':['', 'e']}
equal_class['NULL_N_EQCLS'] = {'bits': 1, 'body':['', 'u']}
equal_class['NULL_U_EQCLS'] = {'bits': 1, 'body':['', 'l']}
# flag : txt_inc, src_not_inc, tok_inc
states = [
{
'state': 'END',
'body': ['END'],
'flag': ['010'],
'eqcls': 'END_EQCLS'
},
{
'state': 'ENT',
'body': ['END', 'ENT', 'ENT', 'STR', 'NUM', 'TRUE_T', 'FALSE_F', 'NULL_N'],
'flag': ['010', '101', '100', '110', '010', '110', '110', '110' ],
'eqcls': 'ENT_EQCLS'
},
{
'state': 'STR',
'body': ['STR', 'END', 'ENT', 'ESC'],
'flag': ['110', '010', '101', '110'],
'eqcls': 'STR_EQCLS'
},
{
'state': 'ESC',
'body': ['END', 'STR', 'HEX'],
'flag': ['010', '110', '110'],
'eqcls': 'ESC_EQCLS'
},
{
'state': 'HEX',
'body': ['END', 'HEX1'],
'flag': ['010', '110'],
'eqcls': 'HEX_EQCLS'
},
{
'state': 'HEX1',
'body': ['END', 'HEX2'],
'flag': ['010', '110'],
'eqcls': 'HEX_EQCLS'
},
{
'state': 'HEX2',
'body': ['END', 'HEX3'],
'flag': ['010', '110'],
'eqcls': 'HEX_EQCLS'
},
{
'state': 'HEX3',
'body': ['END', 'STR'],
'flag': ['010', '110'],
'eqcls': 'HEX_EQCLS'
},
{
'state': 'NUM',
'body': ['END', 'MINUS', 'ZERO', 'ONENINE'],
'flag': ['010', '110', '110', '110' ],
'eqcls': 'NUM_EQCLS'
},
{
'state': 'MINUS',
'body': ['END', 'END', 'ZERO', 'ONENINE'],
'flag': ['010', '010', '110', '110' ],
'eqcls': 'NUM_EQCLS'
},
{
'state': 'ZERO',
'body': ['FRAC_S', 'END', 'END', 'END'],
'flag': ['010', '010', '010', '010'],
'eqcls': 'NUM_EQCLS'
},
{
'state': 'ONENINE',
'body': ['FRAC_S', 'END', 'ONENINE', 'ONENINE'],
'flag': ['010', '010', '110', '110'],
'eqcls': 'NUM_EQCLS',
},
{
'state': 'FRAC_S',
'body': ['ENT', 'FRAC_O', 'EXP_S', 'END'],
'flag': ['001', '110', '110', '010'],
'eqcls': 'FRAC_EQCLS',
},
{
'state': 'FRAC_O',
'body': ['ENT', 'END', 'EXP_S', 'FRAC_O'],
'flag': ['001', '010', '110', '110'],
'eqcls': 'FRAC_EQCLS',
},
{
'state': 'EXP_S',
'body': ['END', 'EXP_O', 'EXP_O'],
'flag': ['010', '110', '110'],
'eqcls': 'EXP_EQCLS',
},
{
'state': 'EXP_O',
'body': ['ENT', 'END', 'EXP_O'],
'flag': ['001', '010', '110'],
'eqcls': 'EXP_EQCLS',
},
{
'state': 'TRUE_T',
'body': ['END', 'TRUE_R'],
'flag': ['010', '110'],
'eqcls': 'TRUE_T_EQCLS',
},
{
'state': 'TRUE_R',
'body': ['END', 'TRUE_U'],
'flag': ['010', '110'],
'eqcls': 'TRUE_R_EQCLS',
},
{
'state': 'TRUE_U',
'body': ['END', 'ENT'],
'flag': ['010', '101'],
'eqcls': 'TRUE_U_EQCLS',
},
{
'state': 'FALSE_F',
'body': ['END', 'FALSE_A'],
'flag': ['010', '110'],
'eqcls': 'FALSE_F_EQCLS',
},
{
'state': 'FALSE_A',
'body': ['END', 'FALSE_L'],
'flag': ['010', '110'],
'eqcls': 'FALSE_A_EQCLS',
},
{
'state': 'FALSE_L',
'body': ['END', 'FALSE_S'],
'flag': ['010', '110'],
'eqcls': 'FALSE_L_EQCLS',
},
{
'state': 'FALSE_S',
'body': ['END', 'ENT'],
'flag': ['010', '101'],
'eqcls': 'FALSE_S_EQCLS',
},
{
'state': 'NULL_N',
'body': ['END', 'NULL_U'],
'flag': ['010', '110'],
'eqcls': 'NULL_N_EQCLS',
},
{
'state': 'NULL_U',
'body': ['END', 'NULL_L'],
'flag': ['010', '110'],
'eqcls': 'NULL_U_EQCLS',
},
{
'state': 'NULL_L',
'body': ['END', 'ENT'],
'flag': ['010', '101'],
'eqcls': 'NULL_U_EQCLS',
}
]
# equal class 에 shift 추가 (32비트에 순서대로 자신의 비트수만큼 점유)
def init_shift_equal_class():
cnt = 0
for k, v in equal_class.items():
v['shift'] = cnt
cnt += v['bits']
# 상태의 인덱스 MAP을 구함
def gene_state_idx_map():
ret = {}
cnt = 0
for itm in states:
ret[itm['state']] = cnt
cnt += len(itm['body'])
return ret
init_shift_equal_class()
idx_map = gene_state_idx_map()
print(idx_map)
# equal class 를 구함 256개의 값 (ASCII)
# 에 따라서 정해진 위치의 비트수만큼 equal class 를 구함
def gene_eqcls():
ret = []
for c in range(256):
ret.append('')
for k, v in equal_class.items():
if k != 'END_EQCLS':
adder = '0' * v['bits']
for i, itm in enumerate(v['body']):
if chr(c) in itm:
adder = bin(i)[2:].zfill(v['bits'])
break
ret[c] = adder + ret[c]
for i, itm in enumerate(ret):
print (i, itm)
return ret
#
generated_eqcls = gene_eqcls()
# 상태 테이블 생성 (1차원 배열)
# equal class 의 비트매스크를 정의하는 mask byte
# equal class 의 Shift 숫자 를 저장한 shift byte
# 상태에 따라 포인트증가, 토큰증가, 시작포인터증가 등을 제어하는 Flag byte
# 상태의 숫자를 기록하는 state byte
# 총 4바이트
def gene_tbl():
sep = ''
tbl = []
eq_map = {}
for state in states:
eq_map[state['state']] = state['eqcls']
for row, state in enumerate(states):
for i, itm in enumerate(state['body']):
# eqcls byte
## shift
tar = equal_class[eq_map[itm]]
#tar = equal_class[state['eqcls']]
shift_byte = bin(tar['shift'])[2:].zfill(8)
## mask
mask_byte = ('1' * tar['bits']).zfill(8)
# fail bits + flag bit = flag tyes
flag_byte = bin(row)[2:].zfill(5) + state['flag'][i]
# state byte
state_byte = bin(idx_map[itm])[2:].zfill(8)
tbl.append(
mask_byte + sep +
shift_byte + sep +
flag_byte + sep +
state_byte
)
print(tbl)
return tbl
generated_tbl = gene_tbl()
##### simulation table logic
def flag_inc(state, shift):
st = int(state,2)
r = st >> shift
r = r & 0x1
return r
def str_inc(state, l):
flag = flag_inc(state, 9)
mask = int('1' * 32, 2)
mask = bin(mask + flag)[2:]
if len(mask) > 32:
mask = mask[len(mask)-32:]
mask = int(mask, 2)
return l & mask
def get_cls(cls, state):
c = int(cls,2)
st = int(state,2)
shift = (st&0xFF0000)>>16
mask = st>>24
return (c>>shift)&mask
def get_state(state):
st = int(state,2)
return st & 0xff
def get_char(p, txt):
if p >= len(txt):
return 0
else:
return ord(txt[p])
def get_fail_flag(state):
st = int(state,2)
return (st & 0xf800) >> 11
def get_state_nm(idx):
for k, v in idx_map.items():
if v == idx:
return k
return ''
# C언어와 동일한 로직을 구현하여 동작여부 확인
def simul_jnjson(eqcls, tbl, txt):
print('start lexing:', txt)
p = 0
s = 0
t_idx = 0
t_s = s
t_len = 0
# start ,shift ,flags ,state ,
state = '00000111000000000000001000000001'
while True: # do{ } while();
p += flag_inc(state, 10)
t_s = s
t_len = p - s
t_idx += flag_inc(state, 8)
s += str_inc(state, p-s)
cls = eqcls[get_char(p, txt)]
cls = get_cls(cls, state)
idx = get_state(state) + cls
state = tbl[idx]
print('p[%s] : t[%s] .s=%s, .len=%d , %s, cls:%s nxt:%s, idx:%s %s' % (
chr(get_char(p,txt)),
t_idx,
txt[t_s],
t_len,
eqcls[get_char(p, txt)],
cls,
state,
idx,
get_state_nm(get_state(state)),
)
)
if get_state(state) > 0:
pass
else:
break
fail_row = get_fail_flag(state)
if fail_row <= 1 and get_char(p, txt) == 0:
print('DONE')
else:
print('TOKEN ERROR:', fail_row, state)
def test_cases():
cs = [
'{}[ ]:\t, ', # entry default
'[]:;', # entry error
'"hello world\\r\\n\\""', # string
'{}:,"hell\\r\\n\\""[,,,]', # string
'"hell', # string err
'"\\uabcd"', # hex
'0', # num
'-1', # num
'-12.234', # num
'-0.320E+12', # num
'false',
'true',
'null',
'fa:,[]', # err
'[]nu"ll', # err
]
for c in cs:
simul_jnjson(generated_eqcls, generated_tbl, c)
test_cases()
### generated source
def gen_c_src(eqcls, tbl):
eqcls_arr = 'int eqcls[256] = {\n'
for i, cls in enumerate(eqcls):
eqcls_arr += '%10s, '%(hex(int(cls,2)))
if (i + 1) % 8 == 0:
eqcls_arr += '\n'
eqcls_arr += '};\n'
print(eqcls_arr)
tbl_arr = 'int tbl[] = {\n'
for i, t in enumerate(tbl):
tbl_arr += '%10s, '%(hex(int(t,2)))
if (i + 1) % 8 == 0:
tbl_arr += '\n'
tbl_arr += '};\n'
print(tbl_arr)
print('//start =', hex(int('00000111000000000000001000000001',2)))
main_src = '''
char* p = in_buf;
char* s = in_buf;
jn_str_t* t = out_toks;
int state = 0x7000201;
unsigned int cls = 0;
do
{
p += (state>>10) & 0x1;
t->s = s;
t->len = p - s;
t += (state>>8) & 0x1;
s += (p - s) & (UINT_MAX + ((state>>9) & 0x1));
cls = eqcls[(unsigned char)(*p)];
cls = (cls>>((state & 0x00FF0000)>>16))&(state>>24);
state = tbl[ (state & 0x000000FF) + cls ];
}
while( (state & 0x000000FF) > 0);
'''
print(main_src)
gen_c_src(generated_eqcls, generated_tbl)
aW1wb3J0IGNvbGxlY3Rpb25zCgplcXVhbF9jbGFzcyA9IGNvbGxlY3Rpb25zLk9yZGVyZWREaWN0KCkKCmVxdWFsX2NsYXNzWydFTkRfRVFDTFMnXSA9IHsnYml0cyc6IDAsICdib2R5JzpbXSB9CmVxdWFsX2NsYXNzWydFTlRfRVFDTFMnXSA9IHsnYml0cyc6IDMsICdib2R5JzpbJycsICd7fVtdOiwnLCAnIFx0XHJcbicsICciJywgJy0wMTIzNDU2Nzg5JywgJ3QnLCAnZicsICduJ119CmVxdWFsX2NsYXNzWydTVFJfRVFDTFMnXSA9IHsnYml0cyc6IDIsICdib2R5JzpbJycsICdcMCcsICciJywgJ1xcJ119CmVxdWFsX2NsYXNzWydFU0NfRVFDTFMnXSA9IHsnYml0cyc6IDIsICdib2R5JzpbJycsICdcXHJmdG5iIi8nLCAndSddfQplcXVhbF9jbGFzc1snSEVYX0VRQ0xTJ10gPSB7J2JpdHMnOiAxLCAnYm9keSc6WycnLCAnMDEyMzQ1Njc4OWFiY2RlZkFCQ0RFRiddfQplcXVhbF9jbGFzc1snTlVNX0VRQ0xTJ10gPSB7J2JpdHMnOiAyLCAnYm9keSc6WycnLCAnLScsICcwJywgJzEyMzQ1Njc4OSddfQplcXVhbF9jbGFzc1snRlJBQ19FUUNMUyddID17J2JpdHMnOiAyLCAnYm9keSc6WycnLCAnLicsICdlRScsICcwMTIzNDU2Nzg5J119CmVxdWFsX2NsYXNzWydFWFBfRVFDTFMnXSA9IHsnYml0cyc6IDIsICdib2R5JzpbJycsICcrLScsICcwMTIzNDU2Nzg5J119CmVxdWFsX2NsYXNzWydUUlVFX1RfRVFDTFMnXSA9IHsnYml0cyc6IDEsICdib2R5JzpbJycsICdyJ119CmVxdWFsX2NsYXNzWydUUlVFX1JfRVFDTFMnXSA9IHsnYml0cyc6IDEsICdib2R5JzpbJycsICd1J119CmVxdWFsX2NsYXNzWydUUlVFX1VfRVFDTFMnXSA9IHsnYml0cyc6IDEsICdib2R5JzpbJycsICdlJ119CmVxdWFsX2NsYXNzWydGQUxTRV9GX0VRQ0xTJ10gPSB7J2JpdHMnOiAxLCAnYm9keSc6WycnLCAnYSddfQplcXVhbF9jbGFzc1snRkFMU0VfQV9FUUNMUyddID0geydiaXRzJzogMSwgJ2JvZHknOlsnJywgJ2wnXX0KZXF1YWxfY2xhc3NbJ0ZBTFNFX0xfRVFDTFMnXSA9IHsnYml0cyc6IDEsICdib2R5JzpbJycsICdzJ119CmVxdWFsX2NsYXNzWydGQUxTRV9TX0VRQ0xTJ10gPSB7J2JpdHMnOiAxLCAnYm9keSc6WycnLCAnZSddfQplcXVhbF9jbGFzc1snTlVMTF9OX0VRQ0xTJ10gPSB7J2JpdHMnOiAxLCAnYm9keSc6WycnLCAndSddfQplcXVhbF9jbGFzc1snTlVMTF9VX0VRQ0xTJ10gPSB7J2JpdHMnOiAxLCAnYm9keSc6WycnLCAnbCddfQoKIyBmbGFnIDogIHR4dF9pbmMsICBzcmNfbm90X2luYywgIHRva19pbmMKc3RhdGVzID0gWwogICAgewogICAgICAgICdzdGF0ZSc6ICdFTkQnLAogICAgICAgICdib2R5JzogWydFTkQnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ0VORF9FUUNMUycKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ0VOVCcsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdFTlQnLCAnRU5UJywgJ1NUUicsICdOVU0nLCAnVFJVRV9UJywgJ0ZBTFNFX0YnLCAnTlVMTF9OJ10sCiAgICAgICAgJ2ZsYWcnOiBbJzAxMCcsICcxMDEnLCAnMTAwJywgJzExMCcsICcwMTAnLCAnMTEwJywgICAgJzExMCcsICAgICAnMTEwJyAgIF0sCiAgICAgICAgJ2VxY2xzJzogJ0VOVF9FUUNMUycKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ1NUUicsCiAgICAgICAgJ2JvZHknOiBbJ1NUUicsICdFTkQnLCAnRU5UJywgJ0VTQyddLAogICAgICAgICdmbGFnJzogWycxMTAnLCAnMDEwJywgJzEwMScsICcxMTAnXSwKICAgICAgICAnZXFjbHMnOiAnU1RSX0VRQ0xTJwogICAgfSwKICAgIHsKICAgICAgICAnc3RhdGUnOiAnRVNDJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ1NUUicsICdIRVgnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCcsICcxMTAnXSwKICAgICAgICAnZXFjbHMnOiAnRVNDX0VRQ0xTJwogICAgfSwKICAgIHsKICAgICAgICAnc3RhdGUnOiAnSEVYJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ0hFWDEnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCddLAogICAgICAgICdlcWNscyc6ICdIRVhfRVFDTFMnCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdIRVgxJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ0hFWDInXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCddLAogICAgICAgICdlcWNscyc6ICdIRVhfRVFDTFMnCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdIRVgyJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ0hFWDMnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCddLAogICAgICAgICdlcWNscyc6ICdIRVhfRVFDTFMnCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdIRVgzJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ1NUUiddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAnMTEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ0hFWF9FUUNMUycKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ05VTScsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdNSU5VUycsICdaRVJPJywgJ09ORU5JTkUnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCcsICAgJzExMCcsICAnMTEwJyAgICBdLAogICAgICAgICdlcWNscyc6ICdOVU1fRVFDTFMnCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdNSU5VUycsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdFTkQnLCAnWkVSTycsICdPTkVOSU5FJ10sCiAgICAgICAgJ2ZsYWcnOiBbJzAxMCcsICcwMTAnLCAnMTEwJywgICcxMTAnICAgIF0sCiAgICAgICAgJ2VxY2xzJzogJ05VTV9FUUNMUycKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ1pFUk8nLAogICAgICAgICdib2R5JzogWydGUkFDX1MnLCAnRU5EJywgJ0VORCcsICdFTkQnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgICAgJzAxMCcsICcwMTAnLCAnMDEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ05VTV9FUUNMUycKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ09ORU5JTkUnLAogICAgICAgICdib2R5JzogWydGUkFDX1MnLCAnRU5EJywgJ09ORU5JTkUnLCAnT05FTklORSddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAgICAnMDEwJywgJzExMCcsICAgICAnMTEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ05VTV9FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdGUkFDX1MnLAogICAgICAgICdib2R5JzogWydFTlQnLCAnRlJBQ19PJywgJ0VYUF9TJywgJ0VORCddLAogICAgICAgICdmbGFnJzogWycwMDEnLCAnMTEwJywgJzExMCcsICcwMTAnXSwKICAgICAgICAnZXFjbHMnOiAnRlJBQ19FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdGUkFDX08nLAogICAgICAgICdib2R5JzogWydFTlQnLCAnRU5EJywgJ0VYUF9TJywgJ0ZSQUNfTyddLAogICAgICAgICdmbGFnJzogWycwMDEnLCAnMDEwJywgJzExMCcsICcxMTAnXSwKICAgICAgICAnZXFjbHMnOiAnRlJBQ19FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdFWFBfUycsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdFWFBfTycsICdFWFBfTyddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAnMTEwJywgJzExMCddLAogICAgICAgICdlcWNscyc6ICdFWFBfRVFDTFMnLAogICAgfSwKICAgIHsKICAgICAgICAnc3RhdGUnOiAnRVhQX08nLAogICAgICAgICdib2R5JzogWydFTlQnLCAnRU5EJywgJ0VYUF9PJ10sCiAgICAgICAgJ2ZsYWcnOiBbJzAwMScsICcwMTAnLCAnMTEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ0VYUF9FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdUUlVFX1QnLAogICAgICAgICdib2R5JzogWydFTkQnLCAnVFJVRV9SJ10sCiAgICAgICAgJ2ZsYWcnOiBbJzAxMCcsICcxMTAnXSwKICAgICAgICAnZXFjbHMnOiAnVFJVRV9UX0VRQ0xTJywKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ1RSVUVfUicsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdUUlVFX1UnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCddLAogICAgICAgICdlcWNscyc6ICdUUlVFX1JfRVFDTFMnLAogICAgfSwKICAgIHsKICAgICAgICAnc3RhdGUnOiAnVFJVRV9VJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ0VOVCddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAnMTAxJ10sCiAgICAgICAgJ2VxY2xzJzogJ1RSVUVfVV9FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdGQUxTRV9GJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ0ZBTFNFX0EnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzExMCddLAogICAgICAgICdlcWNscyc6ICdGQUxTRV9GX0VRQ0xTJywKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ0ZBTFNFX0EnLAogICAgICAgICdib2R5JzogWydFTkQnLCAnRkFMU0VfTCddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAnMTEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ0ZBTFNFX0FfRVFDTFMnLAogICAgfSwKICAgIHsKICAgICAgICAnc3RhdGUnOiAnRkFMU0VfTCcsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdGQUxTRV9TJ10sCiAgICAgICAgJ2ZsYWcnOiBbJzAxMCcsICcxMTAnXSwKICAgICAgICAnZXFjbHMnOiAnRkFMU0VfTF9FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdGQUxTRV9TJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ0VOVCddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAnMTAxJ10sCiAgICAgICAgJ2VxY2xzJzogJ0ZBTFNFX1NfRVFDTFMnLAogICAgfSwKICAgIHsKICAgICAgICAnc3RhdGUnOiAnTlVMTF9OJywKICAgICAgICAnYm9keSc6IFsnRU5EJywgJ05VTExfVSddLAogICAgICAgICdmbGFnJzogWycwMTAnLCAnMTEwJ10sCiAgICAgICAgJ2VxY2xzJzogJ05VTExfTl9FUUNMUycsCiAgICB9LAogICAgewogICAgICAgICdzdGF0ZSc6ICdOVUxMX1UnLAogICAgICAgICdib2R5JzogWydFTkQnLCAnTlVMTF9MJ10sCiAgICAgICAgJ2ZsYWcnOiBbJzAxMCcsICcxMTAnXSwKICAgICAgICAnZXFjbHMnOiAnTlVMTF9VX0VRQ0xTJywKICAgIH0sCiAgICB7CiAgICAgICAgJ3N0YXRlJzogJ05VTExfTCcsCiAgICAgICAgJ2JvZHknOiBbJ0VORCcsICdFTlQnXSwKICAgICAgICAnZmxhZyc6IFsnMDEwJywgJzEwMSddLAogICAgICAgICdlcWNscyc6ICdOVUxMX1VfRVFDTFMnLAogICAgfQpdCgoKIyBlcXVhbCBjbGFzcyDsl5Agc2hpZnQg7LaU6rCAICgzMuu5hO2KuOyXkCDsiJzshJzrjIDroZwg7J6Q7Iug7J2YIOu5hO2KuOyImOunjO2BvCDsoJDsnKApCmRlZiBpbml0X3NoaWZ0X2VxdWFsX2NsYXNzKCk6CiAgICBjbnQgPSAwCiAgICBmb3IgaywgdiBpbiBlcXVhbF9jbGFzcy5pdGVtcygpOgogICAgICAgIHZbJ3NoaWZ0J10gPSBjbnQKICAgICAgICBjbnQgKz0gdlsnYml0cyddCgojIOyDge2DnOydmCDsnbjrjbHsiqQgTUFQ7J2EIOq1rO2VqApkZWYgZ2VuZV9zdGF0ZV9pZHhfbWFwKCk6CiAgICByZXQgPSB7fQogICAgY250ID0gMAogICAgZm9yIGl0bSBpbiBzdGF0ZXM6CiAgICAgICAgcmV0W2l0bVsnc3RhdGUnXV0gPSBjbnQKICAgICAgICBjbnQgKz0gbGVuKGl0bVsnYm9keSddKQogICAgcmV0dXJuIHJldAoKCgppbml0X3NoaWZ0X2VxdWFsX2NsYXNzKCkKaWR4X21hcCA9IGdlbmVfc3RhdGVfaWR4X21hcCgpCgpwcmludChpZHhfbWFwKQoKCiMgZXF1YWwgY2xhc3Mg66W8IOq1rO2VqCAyNTbqsJzsnZgg6rCSIChBU0NJSSkKIyDsl5Ag65Sw65287IScIOygle2VtOynhCDsnITsuZjsnZgg67mE7Yq47IiY66eM7YG8IGVxdWFsIGNsYXNzIOulvCDqtaztlagKZGVmIGdlbmVfZXFjbHMoKToKICAgIHJldCA9IFtdCiAgICBmb3IgYyBpbiByYW5nZSgyNTYpOgogICAgICAgIHJldC5hcHBlbmQoJycpCiAgICAgICAgZm9yIGssIHYgaW4gZXF1YWxfY2xhc3MuaXRlbXMoKToKICAgICAgICAgICAgaWYgayAhPSAnRU5EX0VRQ0xTJzoKICAgICAgICAgICAgICAgIGFkZGVyID0gJzAnICogdlsnYml0cyddCiAgICAgICAgICAgICAgICBmb3IgaSwgaXRtIGluIGVudW1lcmF0ZSh2Wydib2R5J10pOgogICAgICAgICAgICAgICAgICAgIGlmIGNocihjKSBpbiBpdG06CiAgICAgICAgICAgICAgICAgICAgICAgIGFkZGVyID0gYmluKGkpWzI6XS56ZmlsbCh2WydiaXRzJ10pCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgICAgICByZXRbY10gPSBhZGRlciArIHJldFtjXQoKICAgIGZvciBpLCBpdG0gaW4gZW51bWVyYXRlKHJldCk6CiAgICAgICAgcHJpbnQgKGksIGl0bSkKCiAgICByZXR1cm4gcmV0CgoKIwpnZW5lcmF0ZWRfZXFjbHMgPSBnZW5lX2VxY2xzKCkKCiMg7IOB7YOcIO2FjOydtOu4lCDsg53shLEgKDHssKjsm5Ag67Cw7Je0KQojICBlcXVhbCBjbGFzcyDsnZgg67mE7Yq466ek7Iqk7YGs66W8IOygleydmO2VmOuKlCBtYXNrIGJ5dGUKIyAgZXF1YWwgY2xhc3Mg7J2YIFNoaWZ0IOyIq+yekCDrpbwg7KCA7J6l7ZWcIHNoaWZ0IGJ5dGUKIyAg7IOB7YOc7JeQIOuUsOudvCDtj6zsnbjtirjspp3qsIAsIO2GoO2BsOymneqwgCwg7Iuc7J6R7Y+s7J247YSw7Kad6rCAIOuTseydhCDsoJzslrTtlZjripQgRmxhZyBieXRlCiMgIOyDge2DnOydmCDsiKvsnpDrpbwg6riw66Gd7ZWY64qUICBzdGF0ZSBieXRlCiMg7LSdIDTrsJTsnbTtirgKZGVmIGdlbmVfdGJsKCk6CiAgICBzZXAgPSAnJwogICAgdGJsID0gW10KICAgIGVxX21hcCA9IHt9CgogICAgZm9yIHN0YXRlIGluIHN0YXRlczoKICAgICAgICBlcV9tYXBbc3RhdGVbJ3N0YXRlJ11dID0gc3RhdGVbJ2VxY2xzJ10KCiAgICBmb3Igcm93LCBzdGF0ZSBpbiBlbnVtZXJhdGUoc3RhdGVzKToKICAgICAgICBmb3IgaSwgaXRtIGluIGVudW1lcmF0ZShzdGF0ZVsnYm9keSddKToKCiAgICAgICAgICAgICMgZXFjbHMgYnl0ZQogICAgICAgICAgICAjIyBzaGlmdAogICAgICAgICAgICB0YXIgPSBlcXVhbF9jbGFzc1tlcV9tYXBbaXRtXV0KICAgICAgICAgICAgI3RhciA9IGVxdWFsX2NsYXNzW3N0YXRlWydlcWNscyddXQogICAgICAgICAgICBzaGlmdF9ieXRlID0gYmluKHRhclsnc2hpZnQnXSlbMjpdLnpmaWxsKDgpCiAgICAgICAgICAgICMjIG1hc2sKICAgICAgICAgICAgbWFza19ieXRlID0gKCcxJyAqIHRhclsnYml0cyddKS56ZmlsbCg4KQoKICAgICAgICAgICAgIyBmYWlsIGJpdHMgKyAgZmxhZyBiaXQgPSBmbGFnIHR5ZXMKICAgICAgICAgICAgZmxhZ19ieXRlID0gYmluKHJvdylbMjpdLnpmaWxsKDUpICsgc3RhdGVbJ2ZsYWcnXVtpXQoKICAgICAgICAgICAgIyBzdGF0ZSBieXRlCiAgICAgICAgICAgIHN0YXRlX2J5dGUgPSBiaW4oaWR4X21hcFtpdG1dKVsyOl0uemZpbGwoOCkKICAgICAgICAgICAgdGJsLmFwcGVuZCgKICAgICAgICAgICAgICAgIG1hc2tfYnl0ZSArIHNlcCArCiAgICAgICAgICAgICAgICBzaGlmdF9ieXRlICsgc2VwICsKICAgICAgICAgICAgICAgIGZsYWdfYnl0ZSArIHNlcCArCiAgICAgICAgICAgICAgICBzdGF0ZV9ieXRlCiAgICAgICAgICAgICkKCiAgICBwcmludCh0YmwpCgogICAgcmV0dXJuIHRibAoKCmdlbmVyYXRlZF90YmwgPSBnZW5lX3RibCgpCgojIyMjIyBzaW11bGF0aW9uICB0YWJsZSBsb2dpYwoKZGVmIGZsYWdfaW5jKHN0YXRlLCBzaGlmdCk6CiAgICBzdCA9IGludChzdGF0ZSwyKQogICAgciA9IHN0ID4+IHNoaWZ0CiAgICByID0gciAmIDB4MQogICAgcmV0dXJuIHIKCgpkZWYgc3RyX2luYyhzdGF0ZSwgbCk6CiAgICBmbGFnID0gZmxhZ19pbmMoc3RhdGUsIDkpCiAgICBtYXNrID0gaW50KCcxJyAqIDMyLCAyKQogICAgbWFzayA9IGJpbihtYXNrICsgZmxhZylbMjpdCiAgICBpZiBsZW4obWFzaykgPiAzMjoKICAgICAgICBtYXNrID0gbWFza1tsZW4obWFzayktMzI6XQogICAgbWFzayA9IGludChtYXNrLCAyKQogICAgcmV0dXJuIGwgJiBtYXNrCgpkZWYgZ2V0X2NscyhjbHMsIHN0YXRlKToKICAgIGMgPSBpbnQoY2xzLDIpCiAgICBzdCA9IGludChzdGF0ZSwyKQogICAgc2hpZnQgPSAoc3QmMHhGRjAwMDApPj4xNgogICAgbWFzayAgPSBzdD4+MjQKICAgIHJldHVybiAoYz4+c2hpZnQpJm1hc2sKCmRlZiBnZXRfc3RhdGUoc3RhdGUpOgogICAgc3QgPSBpbnQoc3RhdGUsMikKICAgIHJldHVybiBzdCAmIDB4ZmYKCmRlZiBnZXRfY2hhcihwLCB0eHQpOgogICAgaWYgcCA+PSBsZW4odHh0KToKICAgICAgICByZXR1cm4gMAogICAgZWxzZToKICAgICAgICByZXR1cm4gb3JkKHR4dFtwXSkKCgoKZGVmIGdldF9mYWlsX2ZsYWcoc3RhdGUpOgogICAgc3QgPSBpbnQoc3RhdGUsMikKICAgIHJldHVybiAoc3QgJiAweGY4MDApID4+IDExCgoKZGVmIGdldF9zdGF0ZV9ubShpZHgpOgogICAgZm9yIGssIHYgaW4gaWR4X21hcC5pdGVtcygpOgogICAgICAgIGlmIHYgPT0gaWR4OgogICAgICAgICAgICByZXR1cm4gawogICAgcmV0dXJuICcnCgojIEPslrjslrTsmYAg64+Z7J287ZWcIOuhnOyngeydhCDqtaztmITtlZjsl6wg64+Z7J6R7Jes67aAIO2ZleyduApkZWYgc2ltdWxfam5qc29uKGVxY2xzLCB0YmwsIHR4dCk6CiAgICBwcmludCgnc3RhcnQgbGV4aW5nOicsIHR4dCkKICAgIHAgPSAwCiAgICBzID0gMAogICAgdF9pZHggPSAwCiAgICB0X3MgPSBzCiAgICB0X2xlbiA9IDAKICAgICMgICAgICAgIHN0YXJ0ICAsc2hpZnQgICxmbGFncyAgLHN0YXRlICAsCiAgICBzdGF0ZSA9ICcwMDAwMDExMTAwMDAwMDAwMDAwMDAwMTAwMDAwMDAwMScKCiAgICB3aGlsZSBUcnVlOiAjIGRveyB9IHdoaWxlKCk7CiAgICAgICAgcCArPSBmbGFnX2luYyhzdGF0ZSwgMTApCiAgICAgICAgdF9zID0gcwogICAgICAgIHRfbGVuID0gcCAtIHMKICAgICAgICB0X2lkeCArPSBmbGFnX2luYyhzdGF0ZSwgOCkKICAgICAgICBzICs9IHN0cl9pbmMoc3RhdGUsIHAtcykKCiAgICAgICAgY2xzID0gZXFjbHNbZ2V0X2NoYXIocCwgdHh0KV0KICAgICAgICBjbHMgPSBnZXRfY2xzKGNscywgc3RhdGUpCiAgICAgICAgaWR4ID0gZ2V0X3N0YXRlKHN0YXRlKSArIGNscwogICAgICAgIHN0YXRlID0gdGJsW2lkeF0KICAgICAgICBwcmludCgncFslc10gOiB0WyVzXSAucz0lcywgLmxlbj0lZCAsICVzLCBjbHM6JXMgbnh0OiVzLCBpZHg6JXMgJXMnICUgKAogICAgICAgICAgICAgICAgY2hyKGdldF9jaGFyKHAsdHh0KSksCiAgICAgICAgICAgICAgICB0X2lkeCwKICAgICAgICAgICAgICAgIHR4dFt0X3NdLAogICAgICAgICAgICAgICAgdF9sZW4sCiAgICAgICAgICAgICAgICBlcWNsc1tnZXRfY2hhcihwLCB0eHQpXSwKICAgICAgICAgICAgICAgIGNscywKICAgICAgICAgICAgICAgIHN0YXRlLAogICAgICAgICAgICAgICAgaWR4LAogICAgICAgICAgICAgICAgZ2V0X3N0YXRlX25tKGdldF9zdGF0ZShzdGF0ZSkpLAogICAgICAgICAgICApCiAgICAgICAgKQoKICAgICAgICBpZiBnZXRfc3RhdGUoc3RhdGUpID4gMDoKICAgICAgICAgICAgcGFzcwogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGJyZWFrCgogICAgZmFpbF9yb3cgPSBnZXRfZmFpbF9mbGFnKHN0YXRlKQoKICAgIGlmIGZhaWxfcm93IDw9IDEgYW5kIGdldF9jaGFyKHAsIHR4dCkgPT0gMDoKICAgICAgICBwcmludCgnRE9ORScpCiAgICBlbHNlOgogICAgICAgIHByaW50KCdUT0tFTiBFUlJPUjonLCBmYWlsX3Jvdywgc3RhdGUpCgpkZWYgdGVzdF9jYXNlcygpOgogICAgY3MgPSBbCiAgICAgICAgJ3t9WyBdOlx0LCAnLCAjIGVudHJ5IGRlZmF1bHQKICAgICAgICAnW106OycsICMgZW50cnkgZXJyb3IKICAgICAgICAnImhlbGxvIHdvcmxkXFxyXFxuXFwiIicsICMgc3RyaW5nCiAgICAgICAgJ3t9OiwiaGVsbFxcclxcblxcIiJbLCwsXScsICAjIHN0cmluZwogICAgICAgICciaGVsbCcsICMgc3RyaW5nIGVycgogICAgICAgICciXFx1YWJjZCInLCAjIGhleAogICAgICAgICcwJywgIyBudW0KICAgICAgICAnLTEnLCAjIG51bQogICAgICAgICctMTIuMjM0JywgIyBudW0KICAgICAgICAnLTAuMzIwRSsxMicsICMgbnVtCiAgICAgICAgJ2ZhbHNlJywKICAgICAgICAndHJ1ZScsCiAgICAgICAgJ251bGwnLAogICAgICAgICdmYTosW10nLCAjIGVycgogICAgICAgICdbXW51ImxsJywgIyBlcnIKICAgIF0KICAgIGZvciBjIGluIGNzOgogICAgICAgIHNpbXVsX2puanNvbihnZW5lcmF0ZWRfZXFjbHMsIGdlbmVyYXRlZF90YmwsIGMpCgoKdGVzdF9jYXNlcygpCgoKCiMjIyBnZW5lcmF0ZWQgc291cmNlCgpkZWYgZ2VuX2Nfc3JjKGVxY2xzLCB0YmwpOgogICAgZXFjbHNfYXJyID0gJ2ludCBlcWNsc1syNTZdID0ge1xuJwogICAgZm9yIGksIGNscyBpbiBlbnVtZXJhdGUoZXFjbHMpOgogICAgICAgIGVxY2xzX2FyciArPSAnJTEwcywgJyUoaGV4KGludChjbHMsMikpKQogICAgICAgIGlmIChpICsgMSkgJSA4ID09IDA6CiAgICAgICAgICAgIGVxY2xzX2FyciArPSAnXG4nCiAgICBlcWNsc19hcnIgKz0gJ307XG4nCgogICAgcHJpbnQoZXFjbHNfYXJyKQoKICAgIHRibF9hcnIgPSAnaW50IHRibFtdID0ge1xuJwogICAgZm9yIGksIHQgaW4gZW51bWVyYXRlKHRibCk6CiAgICAgICAgdGJsX2FyciArPSAnJTEwcywgJyUoaGV4KGludCh0LDIpKSkKICAgICAgICBpZiAoaSArIDEpICUgOCA9PSAwOgogICAgICAgICAgICB0YmxfYXJyICs9ICdcbicKICAgIHRibF9hcnIgKz0gJ307XG4nCgogICAgcHJpbnQodGJsX2FycikKCiAgICBwcmludCgnLy9zdGFydCA9JywgaGV4KGludCgnMDAwMDAxMTEwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMDEnLDIpKSkKCiAgICBtYWluX3NyYyA9ICcnJwpjaGFyKiBwID0gaW5fYnVmOwpjaGFyKiBzID0gaW5fYnVmOwpqbl9zdHJfdCogdCA9IG91dF90b2tzOwppbnQgc3RhdGUgPSAweDcwMDAyMDE7CnVuc2lnbmVkIGludCBjbHMgPSAwOwpkbwp7CiAgICBwICs9IChzdGF0ZT4+MTApICYgMHgxOwogICAgdC0+cyA9IHM7CiAgICB0LT5sZW4gPSBwIC0gczsKICAgIHQgKz0gKHN0YXRlPj44KSAmIDB4MTsKICAgIHMgKz0gKHAgLSBzKSAmIChVSU5UX01BWCArICgoc3RhdGU+PjkpICYgMHgxKSk7CiAgICBjbHMgPSBlcWNsc1sodW5zaWduZWQgY2hhcikoKnApXTsKICAgIGNscyA9IChjbHM+Pigoc3RhdGUgJiAweDAwRkYwMDAwKT4+MTYpKSYoc3RhdGU+PjI0KTsKCXN0YXRlID0gdGJsWyAoc3RhdGUgJiAweDAwMDAwMEZGKSArIGNscyBdOwp9CndoaWxlKCAoc3RhdGUgJiAweDAwMDAwMEZGKSA+IDApOwogICAgJycnCgogICAgcHJpbnQobWFpbl9zcmMpCgpnZW5fY19zcmMoZ2VuZXJhdGVkX2VxY2xzLCBnZW5lcmF0ZWRfdGJsKQ==