######################################################################
# gibberish.py - python gibberish interpreter
#
# possible inconsistencies:
# - q(3) stops the entire program, not just the currently running
# piece of code, even when called from an exec'ed string
# (I took "currently-running program" to mean the entire program)
#
# - not in specification, but unfinished official interpreter seems to
# do it this way and/or given examples seem to rely on this:
# - trying to copy/move/pop past the stack results in a run-time error
# - numbers are floating point
# - numbers used for stack indexes are rounded down
# - type mismatches are run-time errors
# - the stack and selected instruction set are global across "subroutines"
# - pushing a string constant [like this] counts as one instruction
# - using x(0) to set the instruction set to one that doesn't exist
# is a run-time error
#
# - neither in specification or in unfinished official interpreter
# - but seems logical:
# - exec'ing a string of malformed code is a run-time error
#
# - numbers used for string indexes are rounded down
# (like the stack)
#
# - reading past EOF returns -1 (char) or "" ([]?) (str)
# (most other esolangs return -1 on EOF)
#
# - a line read from stdin still has its newline attached
# (to distinguish [\n] (=empty line) from [] (=EOF),
# also this is how almost everyone else does it)
#
# - logical operators consider 0.0000... to be false and everything
# else to be true
#
# - and I have no idea how else to do it:
# - lshift and rshift convert their arguments to ints first
# (can't shift something, say, 2.3 bits to the left,
# and bitshifting IEEE-754 floating point values seems monumentally
# useless in comparison with bitshifting ints)
#
# - arguments to binary and/or are converted to ints first
# (fits with lshift/rshift)
#
##########################################
from operator import *
import sys
# types used for strings and numbers
STRT = str
NUMT = float
### helper functions ###
def typedesc(type):
if type==STRT: return "string"
if type==NUMT: return "number"
return "invalid (%s)"%str(type)
# make error string
def errstr(code, error, position):
amt = max(0, position - 5)
prev = code[amt : position]
if amt!=0: prev = "..." + prev
amt = min(position + 6, len(code))
next = code[position+1 : amt]
if amt!=len(code): next += "..."
return "%s at position %d (%s ->%s<- %s)" % \
(error, position, prev, code[position], next)
# make error string with list of items
def items_errstr(code, error, position):
prev = ",".join([str(c) for c in code[max(0, position - 5) : position]])
next = ",".join([str(c) for c in code[position+1:position+6]])
return "%s at ip %s (%s ->%s<- %s)" % \
(error, position, prev, str(code[position]), next)
# return ordinal suffix (i.e. 1 => st and 4 => th)
def ordsuffix(num):
if (int(num) % 100 in (11,12,13)): return "th"
if (int(num) % 10 == 1): return "st"
if (int(num) % 10 == 2): return "nd"
if (int(num) % 10 == 3): return "rd"
return "th"
#####
# stack class
class Stack:
stack = None
def __init__(self, copystack=None):
if copystack:
self.stack = copystack[:]
else:
self.stack = []
def push(self, value):
# make sure all numbers use the same type
if type(value) in [bool, int]: value = NUMT(value)
self.stack.append(value)
def pop(self):
return self.stack.pop()
def swapn(self, n):
n=int(n)
foo = self.stack[-1-n]
self.stack[-1-n] = self.stack[-1]
self.stack[-1] = foo
swap = lambda s: s.swapn(1)
swap2 = lambda s: s.swapn(2)
swap3 = lambda s: s.swapn(3)
def copy(self, n):
n=int(n)
self.stack.append(self.stack[-1-n])
dup = lambda s: s.copy(0)
def move(self, n):
n=int(n)
self.stack.append(self.stack[-1-n])
del self.stack[-1-n]
def insert(self, n, value):
n=int(n)
self.stack.insert(-n-1, value)
# 'inverted' copy/move = copy/move counting from the bottom of the stack
def invcopy(self, n):
n=int(n)
self.stack.append(self.stack[n])
def invmove(self, n):
n=int(n)
self.stack.append(self.stack[n])
del self.stack[n]
# getitem/setitem/len
def __getitem__(self, n):
return self.stack[-1-n]
def __setitem__(self, n, val):
self.insert(n, val)
def __len__(self):
return len(self.stack)
# parser
class Parser:
CONSTANT, COMMAND = range(2)
# program will be made up of a list of these
class Item:
def __init__(self, type, value):
if type in (Parser.CONSTANT, Parser.COMMAND):
self.type=type
self.value=value
else: raise TypeError, "item type invalid: %d" % type
def __str__(self):
if self.type==Parser.COMMAND: return self.value
elif self.type==Parser.CONSTANT:
if isinstance(self.value, str): return "[%s]" % self.value
else: return str(self.value)
# takes string, returns list of items
@staticmethod
def parse(string):
items = []
i = 0
while i<len(string):
# numbers
if string[i] in "0123456789":
items.append(Parser.Item(Parser.CONSTANT, NUMT(string[i])))
# strings
elif string[i] == '[':
curstr = ''
lvl = 1
while lvl>0:
i += 1
if (i>=len(string) and lvl>0):
raise ValueError(errstr(string, "unterminated [", i-1))
if string[i] == ']': lvl -= 1
elif string[i] == '[': lvl += 1
if (lvl!=0): curstr += string[i]
items.append(Parser.Item(Parser.CONSTANT, curstr))
# whitespace is ignored
elif string[i] in ' \n\t': pass
# ] without [ == error
elif string[i] == ']':
raise ValueError(errstr(string, "] without [", i))
# not one of these == command
else:
items.append(Parser.Item(Parser.COMMAND, string[i]))
i += 1
return items
class Interpreter:
# exception to be caught if something goes wrong with the code
class CodeError(Exception): pass;
world = None
code = None
stack = None
ip = 0
activeset = 0
sets = None # command sets, see init
parent = None
def __init__(self,world,code,stack=None,ip=0,activeset=0,parent = None):
self.world = world
self.code = code
if stack==None:
self.stack = Stack()
else:
self.stack = stack
self.ip = ip
self.activeset = activeset
self.parent = None
s=self # makes the huge list less long
s.sets = [
# instruction set 0 #
{ 'e' : s.activateSet1,
'f' : s.activateSet2,
'g' : s.activateSet3,
'x' : s.cActivateSet,
'j' : s.cGetSet,
'z' : s.cNop
},
# instruction set 1 #
{ 'u' : s.cDuplicate,
'a' : s.cAdd,
's' : s.cSub,
'm' : s.cMul,
'd' : s.cDiv,
't' : s.cToStr,
'i' : s.cToNum,
'c' : s.cConcatenate,
'o' : s.cOutput,
'q' : s.cInlineOutput,
'n' : s.cReadChar,
'l' : s.cReadLine,
'h' : s.cSubstring,
'y' : s.cStrLen,
'v' : s.cDiscard,
'p' : s.cCopy,
'k' : s.cMove,
'r' : s.cStackSize
},
# instruction set 2 #
{ 'u' : s.cGT,
'd' : s.cLT,
's' : s.cSkip,
't' : s.cSkipTwo,
'p' : s.cInsert,
'a' : s.cAnd,
'o' : s.cOr,
'n' : s.cNot,
'c' : s.cExec,
'w' : s.cWhile,
'q' : s.cEqual,
'l' : s.cLshift,
'r' : s.cRshift
},
# instruction set 3 #
{ 'q' : s.cQuit,
'w' : s.cRecallWhile,
'n' : s.cIsNumber,
's' : s.cIsString,
'a' : s.cBinAnd,
'o' : s.cBinOr,
'i' : s.cInteger,
'm' : s.cMod,
't' : s.cToChar,
'c' : s.cCharAt,
'r' : s.cReplaceChar,
'p' : s.cInvertedCopy,
'k' : s.cInvertedMove,
'b' : s.cSwap,
'd' : s.cSwap2,
'h' : s.cSwap3,
}
]
# step function
# returns True if there are more steps, False if not.
def step(self):
if self.ip >= len(self.code):
return False # at the end of the code
curitem = self.code[self.ip]
# if there's a trace variable defined and true, give a trace
try:
global trace
if trace:
print "\x1b[7m",
print "trace: cur=", self.ip, str(curitem), "set=", self.activeset, "stack=", self.stack.stack,
print "\x1b[0m"
except: pass
if curitem.type == Parser.CONSTANT:
# this is a constant value, push it
self.sf(self.stack.push, [curitem.value])
else:
# it's a command
if curitem.value in self.sets[0]:
# command set 0 has priority above everything
self.sets[0][curitem.value]()
else:
# get it from selected set
if self.activeset<0 or self.activeset>=len(self.sets):
# selected set is invalid
raise Interpreter.CodeError(self.err("no such set: %d",
self.activeset))
else:
if not curitem.value in self.sets[self.activeset]:
#invalid command for selected set
raise Interpreter.CodeError(self.err(
"set %d has no command '%s'"%( self.activeset, \
curitem.value)))
else:
#yay it's good, run it
try:
self.sets[self.activeset][curitem.value]()
except ZeroDivisionError, complaint:
raise Interpreter.CodeError(self.err(
"division by zero (%s)"%complaint))
self.ip += 1
return True
# make an error string with error & current state
def err(self, error):
return items_errstr(self.code, error, self.ip)
# call stack function and catch its errors
def sf(self, func, args):
rv=None
try: rv = func(*args)
except IndexError, complaint:
raise Interpreter.CodeError(self.err("stack error (%s)"%complaint))
return rv
# raise a type error
def raiseTypeErr(self, expected, got):
raise Interpreter.CodeError(
self.err("wrong type: expected %s instead of %s" % \
(typedesc(expected), typedesc(got))))
### commands ###
# convert a function f(a) into push(f(pop())) + type checking
def unarystackf(self, f, ntype=None, pushresult=True):
def stackfunc():
a=self.sf(self.stack.pop,[])
if ntype and not isinstance(a,ntype):
self.raiseTypeErr(ntype, type(a))
res = f(a)
if pushresult: self.sf(self.stack.push,[res])
return stackfunc
# convert a function f(a,b) into b=pop(),a=pop(),push(f(a,b)) + type checking
def binstackf(self, f, atype=None, btype=None, pushresult=True):
def stackfunc():
b = self.sf(self.stack.pop,[])
a = self.sf(self.stack.pop,[])
if btype and not isinstance(b, btype):
self.raiseTypeErr(btype, type(b))
if atype and not isinstance(a, atype):
self.raiseTypeErr(atype, type(a))
res=f(a,b)
if pushresult: self.sf(self.stack.push,[res])
return stackfunc
# and now one with three arguments f(a,b,c)
def tristackf(self, f, atype=None, btype=None, ctype=None, pushresult=True):
x = self.sf
y = self.stack.pop
def stackfunc():
c = x(y,[])
b = x(y,[])
a = x(y,[])
if ctype and not isinstance(c,ctype):
self.raiseTypeErr(ctype, type(c))
if btype and not isinstance(b,btype):
self.raiseTypeErr(btype, type(b))
if atype and not isinstance(a,atype):
self.raiseTypeErr(atype, type(a))
res = f(a,b,c)
if pushresult: self.sf(self.stack.push,[res])
return stackfunc
## set 0 ##
def cActivateSet(self):
set = self.sf(self.stack.pop,[])
if not isinstance(set, NUMT):
raise Interpreter.CodeError(
self.err("wrong type: expected number"))
if len(self.sets)<=int(set) or int(set)<0:
raise Interpreter.CodeError(
self.err("no instruction set %d exists" % set))
self.activeset = int(set)
def activateSet1(self): self.activeset = 1
def activateSet2(self): self.activeset = 2
def activateSet3(self): self.activeset = 3
def cGetSet(self):
self.sf(self.stack.push,[self.activeset])
def cNop(self): pass
## set 1 ##
def cDuplicate(self): self.sf(self.stack.dup,[])
def cAdd(self): self.binstackf(add, NUMT, NUMT)()
def cSub(self): self.binstackf(sub, NUMT, NUMT)()
def cMul(self): self.binstackf(mul, NUMT, NUMT)()
def cDiv(self): self.binstackf(div, NUMT, NUMT)()
# shortest representation of value in string
def v2str(self, n):
if n=="": return n
if isinstance(n,str) and (n[0]==' ' or n[-1]==' '): return n
try: v=str(int(n))
except:
try: v=str(float(n))
except: v=str(n)
return v
def cToStr(self): self.unarystackf(self.v2str, NUMT)()
def cToNum(self):
def tonum(s):
# return a number from the string if possible,
# if not a valid number then push the string back
try: n = NUMT(s)
except ValueError: n = s
return n
self.unarystackf(tonum, STRT)()
def cConcatenate(self): self.binstackf(add, STRT, STRT)()
def cOutput(self):
self.unarystackf(
(lambda s:self.world.out(self.v2str(s)+"\n")),pushresult=False)()
def cInlineOutput(self):
self.unarystackf(
(lambda s:self.world.out(self.v2str(s))),pushresult=False)()
def cReadChar(self):
self.sf(self.stack.push, [NUMT(self.world.readchar())])
def cReadLine(self):
self.sf(self.stack.push, [self.world.readline()])
def cSubstring(self):
self.tristackf((lambda strn,start,end:strn[int(start):int(end)]),
STRT,NUMT,NUMT)()
def cStrLen(self): self.unarystackf(len, STRT)()
def cDiscard(self): self.sf(self.stack.pop, [])
def cCopy(self): self.unarystackf(self.stack.copy, NUMT, False)()
def cMove(self): self.unarystackf(self.stack.move, NUMT, False)()
def cStackSize(self):
self.sf(self.stack.push, NUMT(len(self.stack)))
## set 2 ##
def cGT(self): self.binstackf(gt)()
def cLT(self): self.binstackf(lt)()
def cSkip(self):
def skip(n): self.ip += int(n)
self.unarystackf(skip,NUMT,False)()
def cSkipTwo(self):
def skip2(n): self.ip += int(n*2)
self.unarystackf(skip2,NUMT,False)()
def cInsert(self):
def insert(thing, where): self.stack.insert(where, thing)
self.binstackf(insert, btype=NUMT, pushresult=False)()
def cAnd(self): self.binstackf(lambda a,b:NUMT(a and b and 1 or 0))()
def cOr(self): self.binstackf(lambda a,b:NUMT((a or b) and 1 or 0))()
def cNot(self): self.unarystackf(lambda a:NUMT(not a and 1 or 0))()
def execstr(self, codestr):
self.world.recurse(self, codestr)
def cExec(self): self.unarystackf(self.execstr,STRT,False)()
def cWhile(self):
while True:
# pop a value
val = self.sf(self.stack.pop,[])
if val:
# pop code, run it
code = self.sf(self.stack.pop,[])
if not isinstance(code, STRT):
self.raiseTypeErr(STRT, type(code))
else:
self.execstr(code)
else:
break
def cEqual(self): self.binstackf(eq)()
def cLshift(self): self.binstackf((lambda a,b:int(a)<<int(b)),NUMT,NUMT)()
def cRshift(self): self.binstackf((lambda a,b:int(a)>>int(b)),NUMT,NUMT)()
## set 3 ##
def cQuit(self): self.world.quit()
def cRecallWhile(self):
# pop code
code = self.sf(self.stack.pop,[])
if not isinstance(code, STRT): self.raiseTypeErr(STRT, type(code))
# while
while self.sf(self.stack.pop,[]):
self.execstr(code)
def cIsNumber(self):
self.unarystackf(lambda v: isinstance(v,NUMT) and 1 or 0)()
def cIsString(self):
self.unarystackf(lambda v: isinstance(v,STRT) and 1 or 0)()
# binary and/or use integers again
def binop(self,op): return lambda a,b: op(int(a), int(b))
def cBinAnd(self): self.binstackf(self.binop(and_), NUMT, NUMT)()
def cBinOr(self): self.binstackf(self.binop(or_), NUMT, NUMT)()
def cInteger(self): self.unarystackf(int, NUMT)()
def cMod(self): self.binstackf(mod, NUMT, NUMT)()
def cToChar(self): self.unarystackf((lambda k:chr(int(k)%256)), NUMT)()
def cCharAt(self):
def charat(strn, idx):
idx=int(idx)
if (idx<0 or idx>=len(strn)):
# nowhere in the spec it says python-style negative indexes
# are allowed...
raise Interpreter.CodeError(self.err(
("index out of bounds: tried to get %d-char string's " +\
"%d%s character") % (len(strn), idx, ordsuffix(idx)) ))
return NUMT(ord(strn[idx]))
self.binstackf(charat, STRT, NUMT)()
def cReplaceChar(self):
def replacechar(strn, idx, repl):
idx=int(idx)
if (idx<0 or idx>=len(strn)):
raise Interpreter.CodeError(self.err(
("index out of bounds: tried to change %d-char string's "+\
"%d%s character") % (len(strn), idx, ordsuffix(idx)) ))
return strn[:idx] + repl[0] + strn[idx+1:]
self.tristackf(replacechar, STRT, NUMT, STRT)()
def cInvertedCopy(self):
self.unarystackf(self.stack.invcopy, NUMT, False)()
def cInvertedMove(self):
self.unarystackf(self.stack.invmove, NUMT, False)()
def cSwap(self): self.sf(self.stack.swap, [])
def cSwap2(self): self.sf(self.stack.swap2, [])
def cSwap3(self): self.sf(self.stack.swap3, [])
# class World
# handles stepping of interpreter and input and output
# World().quit() -> ends program
# World().out("blah") -> stdout.write("blah")
# World().readchar() -> read 1 char from stdin
# World().readline() -> read 1 line from stdin
class World:
interpreter = None
def __init__(self, codestr, prevint=None):
# parse the code
self.code = Parser.parse(codestr)
if prevint:
self.interpreter = Interpreter( self, self.code,
parent=prevint,
stack=prevint.stack,
activeset=prevint.activeset )
else:
self.interpreter = Interpreter( self, self.code )
# run the interpreter until it fails or quits
def run(self):
while self.interpreter.step(): pass
# the interpreter calls these for program control
def quit(self):
sys.exit(0)
def out(self, string):
sys.stdout.write(string)
def readchar(self):
v = sys.stdin.read(1)
if not v: return -1
else: return ord(v)
def readline(self):
return sys.stdin.readline()
def recurse(self, prevint, codestr):
try:
# run the sub-interpreter in its own world
w = World(codestr, prevint=prevint)
w.run()
except ValueError, complaint:
# parsing failed
raise Interpreter.CodeError(prevint.err(
"exec: parsing of string failed: \n\t%s\n" % complaint))
except Interpreter.CodeError, complaint:
# run-time error in code
raise Interpreter.CodeError(prevint.err(
"exec: sub-interpreter runtime error: \n\t%s\n" % complaint))
except Exception, complaint:
# something else went wrong
raise Interpreter.CodeError(prevint.err(
"exec: sub-interpreter failed: %s" % str(complaint)))
###############################################################
# start the program
def main(argv):
global trace
if False:
print "usage: %s [-trace] filename | -" % argv[0]
sys.exit(2)
else:
try:
fname="-"
trace=False
if fname=='-': f = sys.stdin
else: f = file(fname, 'r')
except:
print "Can't open file %s" % argv[1]
sys.exit(3)
code = f.read()
f.close()
try:
w = World(code)
w.run()
except Interpreter.CodeError, complaint:
print "Run-time error: %s" % complaint
except ValueError, complaint:
print "Parse error: %s" % complaint
except Exception, complaint:
print "An exception occured: %s" % complaint
if __name__=="__main__": main(sys.argv)
IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGdpYmJlcmlzaC5weSAtIHB5dGhvbiBnaWJiZXJpc2ggaW50ZXJwcmV0ZXIgCiMgCiMgcG9zc2libGUgaW5jb25zaXN0ZW5jaWVzOgojICAgLSBxKDMpIHN0b3BzIHRoZSBlbnRpcmUgcHJvZ3JhbSwgbm90IGp1c3QgdGhlIGN1cnJlbnRseSBydW5uaW5nCiMgICAgIHBpZWNlIG9mIGNvZGUsIGV2ZW4gd2hlbiBjYWxsZWQgZnJvbSBhbiBleGVjJ2VkIHN0cmluZwojICAgICAoSSB0b29rICJjdXJyZW50bHktcnVubmluZyBwcm9ncmFtIiB0byBtZWFuIHRoZSBlbnRpcmUgcHJvZ3JhbSkKIwojICAgLSBub3QgaW4gc3BlY2lmaWNhdGlvbiwgYnV0IHVuZmluaXNoZWQgb2ZmaWNpYWwgaW50ZXJwcmV0ZXIgc2VlbXMgdG8gCiMgICAgIGRvIGl0IHRoaXMgd2F5IGFuZC9vciBnaXZlbiBleGFtcGxlcyBzZWVtIHRvIHJlbHkgb24gdGhpczoKIyAgICAgLSB0cnlpbmcgdG8gY29weS9tb3ZlL3BvcCBwYXN0IHRoZSBzdGFjayByZXN1bHRzIGluIGEgcnVuLXRpbWUgZXJyb3IKIyAgICAgLSBudW1iZXJzIGFyZSBmbG9hdGluZyBwb2ludAojICAgICAtIG51bWJlcnMgdXNlZCBmb3Igc3RhY2sgaW5kZXhlcyBhcmUgcm91bmRlZCBkb3duCiMgICAgIC0gdHlwZSBtaXNtYXRjaGVzIGFyZSBydW4tdGltZSBlcnJvcnMKIyAgICAgLSB0aGUgc3RhY2sgYW5kIHNlbGVjdGVkIGluc3RydWN0aW9uIHNldCBhcmUgZ2xvYmFsIGFjcm9zcyAic3Vicm91dGluZXMiCiMgICAgIC0gcHVzaGluZyBhIHN0cmluZyBjb25zdGFudCBbbGlrZSB0aGlzXSBjb3VudHMgYXMgb25lIGluc3RydWN0aW9uIAojICAgICAtIHVzaW5nIHgoMCkgdG8gc2V0IHRoZSBpbnN0cnVjdGlvbiBzZXQgdG8gb25lIHRoYXQgZG9lc24ndCBleGlzdAojICAgICAgIGlzIGEgcnVuLXRpbWUgZXJyb3IgICAgICAgCiMKIyAgIC0gbmVpdGhlciBpbiBzcGVjaWZpY2F0aW9uIG9yIGluIHVuZmluaXNoZWQgb2ZmaWNpYWwgaW50ZXJwcmV0ZXIKIyAgICAgLSBidXQgc2VlbXMgbG9naWNhbDoKIyAgICAgICAtIGV4ZWMnaW5nIGEgc3RyaW5nIG9mIG1hbGZvcm1lZCBjb2RlIGlzIGEgcnVuLXRpbWUgZXJyb3IKIwojICAgICAgIC0gbnVtYmVycyB1c2VkIGZvciBzdHJpbmcgaW5kZXhlcyBhcmUgcm91bmRlZCBkb3duCiMgICAgICAgICAobGlrZSB0aGUgc3RhY2spCiMgCiMgICAgICAgLSByZWFkaW5nIHBhc3QgRU9GIHJldHVybnMgLTEgKGNoYXIpIG9yICIiIChbXT8pIChzdHIpCiMgICAgICAgICAobW9zdCBvdGhlciBlc29sYW5ncyByZXR1cm4gLTEgb24gRU9GKSAKIwojICAgICAgIC0gYSBsaW5lIHJlYWQgZnJvbSBzdGRpbiBzdGlsbCBoYXMgaXRzIG5ld2xpbmUgYXR0YWNoZWQKIyAgICAgICAgICh0byBkaXN0aW5ndWlzaCBbXG5dICg9ZW1wdHkgbGluZSkgZnJvbSBbXSAoPUVPRiksIAojICAgICAgICAgIGFsc28gdGhpcyBpcyBob3cgYWxtb3N0IGV2ZXJ5b25lIGVsc2UgZG9lcyBpdCkKIwojICAgICAgIC0gbG9naWNhbCBvcGVyYXRvcnMgY29uc2lkZXIgMC4wMDAwLi4uIHRvIGJlIGZhbHNlIGFuZCBldmVyeXRoaW5nCiMgICAgICAgICBlbHNlIHRvIGJlIHRydWUKIyAgICAgIAojICAgICAtIGFuZCBJIGhhdmUgbm8gaWRlYSBob3cgZWxzZSB0byBkbyBpdDoKIyAgICAgICAtIGxzaGlmdCBhbmQgcnNoaWZ0IGNvbnZlcnQgdGhlaXIgYXJndW1lbnRzIHRvIGludHMgZmlyc3QKIyAgICAgICAgIChjYW4ndCBzaGlmdCBzb21ldGhpbmcsIHNheSwgMi4zIGJpdHMgdG8gdGhlIGxlZnQsCiMgICAgICAgICAgYW5kIGJpdHNoaWZ0aW5nIElFRUUtNzU0IGZsb2F0aW5nIHBvaW50IHZhbHVlcyBzZWVtcyBtb251bWVudGFsbHkKIyAgICAgICAgICB1c2VsZXNzIGluIGNvbXBhcmlzb24gd2l0aCBiaXRzaGlmdGluZyBpbnRzKQojCiMgICAgICAgLSBhcmd1bWVudHMgdG8gYmluYXJ5IGFuZC9vciBhcmUgY29udmVydGVkIHRvIGludHMgZmlyc3QKIyAgICAgICAgIChmaXRzIHdpdGggbHNoaWZ0L3JzaGlmdCkKIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgpmcm9tIG9wZXJhdG9yIGltcG9ydCAqCmltcG9ydCBzeXMKCiMgdHlwZXMgdXNlZCBmb3Igc3RyaW5ncyBhbmQgbnVtYmVycwpTVFJUID0gc3RyCk5VTVQgPSBmbG9hdAoKIyMjIGhlbHBlciBmdW5jdGlvbnMgIyMjCmRlZiB0eXBlZGVzYyh0eXBlKToKICAgaWYgdHlwZT09U1RSVDogcmV0dXJuICJzdHJpbmciCiAgIGlmIHR5cGU9PU5VTVQ6IHJldHVybiAibnVtYmVyIgogICByZXR1cm4gImludmFsaWQgKCVzKSIlc3RyKHR5cGUpCgojIG1ha2UgZXJyb3Igc3RyaW5nCmRlZiBlcnJzdHIoY29kZSwgZXJyb3IsIHBvc2l0aW9uKToKICAgYW10ID0gbWF4KDAsIHBvc2l0aW9uIC0gNSkKICAgcHJldiA9IGNvZGVbYW10IDogcG9zaXRpb25dCiAgIGlmIGFtdCE9MDogcHJldiA9ICIuLi4iICsgcHJldgogICAKICAgYW10ID0gbWluKHBvc2l0aW9uICsgNiwgbGVuKGNvZGUpKQogICBuZXh0ID0gY29kZVtwb3NpdGlvbisxIDogYW10XQogICBpZiBhbXQhPWxlbihjb2RlKTogbmV4dCArPSAiLi4uIgogICAKICAgcmV0dXJuICIlcyBhdCBwb3NpdGlvbiAlZCAoJXMgLT4lczwtICVzKSIgJSBcCiAgICAgICAgIChlcnJvciwgcG9zaXRpb24sIHByZXYsIGNvZGVbcG9zaXRpb25dLCBuZXh0KQoKIyBtYWtlIGVycm9yIHN0cmluZyB3aXRoIGxpc3Qgb2YgaXRlbXMKZGVmIGl0ZW1zX2VycnN0cihjb2RlLCBlcnJvciwgcG9zaXRpb24pOgogICBwcmV2ID0gIiwiLmpvaW4oW3N0cihjKSBmb3IgYyBpbiBjb2RlW21heCgwLCBwb3NpdGlvbiAtIDUpIDogcG9zaXRpb25dXSkKICAgbmV4dCA9ICIsIi5qb2luKFtzdHIoYykgZm9yIGMgaW4gY29kZVtwb3NpdGlvbisxOnBvc2l0aW9uKzZdXSkKCiAgIHJldHVybiAiJXMgYXQgaXAgJXMgKCVzIC0+JXM8LSAlcykiICUgXAogICAgICAgICAoZXJyb3IsIHBvc2l0aW9uLCBwcmV2LCBzdHIoY29kZVtwb3NpdGlvbl0pLCBuZXh0KQogICAgICAgICAKCiMgcmV0dXJuIG9yZGluYWwgc3VmZml4IChpLmUuIDEgPT4gc3QgYW5kIDQgPT4gdGgpCmRlZiBvcmRzdWZmaXgobnVtKToKICAgaWYgKGludChudW0pICUgMTAwIGluICgxMSwxMiwxMykpOiByZXR1cm4gInRoIgogICBpZiAoaW50KG51bSkgJSAxMCA9PSAxKTogcmV0dXJuICJzdCIKICAgaWYgKGludChudW0pICUgMTAgPT0gMik6IHJldHVybiAibmQiCiAgIGlmIChpbnQobnVtKSAlIDEwID09IDMpOiByZXR1cm4gInJkIgogICByZXR1cm4gInRoIgoKIyMjIyMKCiMgc3RhY2sgY2xhc3MKY2xhc3MgU3RhY2s6CgogICBzdGFjayA9IE5vbmUKICAgCiAgIGRlZiBfX2luaXRfXyhzZWxmLCBjb3B5c3RhY2s9Tm9uZSk6CiAgICAgIGlmIGNvcHlzdGFjazoKICAgICAgICAgc2VsZi5zdGFjayA9IGNvcHlzdGFja1s6XQogICAgICBlbHNlOgogICAgICAgICBzZWxmLnN0YWNrID0gW10KCgogICBkZWYgcHVzaChzZWxmLCB2YWx1ZSk6CiAgICAgICMgbWFrZSBzdXJlIGFsbCBudW1iZXJzIHVzZSB0aGUgc2FtZSB0eXBlCiAgICAgIGlmIHR5cGUodmFsdWUpIGluIFtib29sLCBpbnRdOiB2YWx1ZSA9IE5VTVQodmFsdWUpCiAgICAgIHNlbGYuc3RhY2suYXBwZW5kKHZhbHVlKQogCiAgIGRlZiBwb3Aoc2VsZik6CiAgICAgIHJldHVybiBzZWxmLnN0YWNrLnBvcCgpCgogICBkZWYgc3dhcG4oc2VsZiwgbik6CiAgICAgIG49aW50KG4pCiAgICAgIGZvbyA9IHNlbGYuc3RhY2tbLTEtbl0KICAgICAgc2VsZi5zdGFja1stMS1uXSA9IHNlbGYuc3RhY2tbLTFdCiAgICAgIHNlbGYuc3RhY2tbLTFdID0gZm9vCgogICBzd2FwID0gbGFtYmRhIHM6IHMuc3dhcG4oMSkKICAgc3dhcDIgPSBsYW1iZGEgczogcy5zd2FwbigyKQogICBzd2FwMyA9IGxhbWJkYSBzOiBzLnN3YXBuKDMpCiAKICAgZGVmIGNvcHkoc2VsZiwgbik6CiAgICAgIG49aW50KG4pCiAgICAgIHNlbGYuc3RhY2suYXBwZW5kKHNlbGYuc3RhY2tbLTEtbl0pCgogICBkdXAgPSBsYW1iZGEgczogcy5jb3B5KDApCiAgIAogICBkZWYgbW92ZShzZWxmLCBuKToKICAgICAgbj1pbnQobikKICAgICAgc2VsZi5zdGFjay5hcHBlbmQoc2VsZi5zdGFja1stMS1uXSkKICAgICAgZGVsIHNlbGYuc3RhY2tbLTEtbl0KCiAgIGRlZiBpbnNlcnQoc2VsZiwgbiwgdmFsdWUpOgogICAgICBuPWludChuKQogICAgICBzZWxmLnN0YWNrLmluc2VydCgtbi0xLCB2YWx1ZSkKCiAgICMgJ2ludmVydGVkJyBjb3B5L21vdmUgPSBjb3B5L21vdmUgY291bnRpbmcgZnJvbSB0aGUgYm90dG9tIG9mIHRoZSBzdGFjawogICBkZWYgaW52Y29weShzZWxmLCBuKToKICAgICAgbj1pbnQobikKICAgICAgc2VsZi5zdGFjay5hcHBlbmQoc2VsZi5zdGFja1tuXSkKICAgCiAgIGRlZiBpbnZtb3ZlKHNlbGYsIG4pOgogICAgICBuPWludChuKQogICAgICBzZWxmLnN0YWNrLmFwcGVuZChzZWxmLnN0YWNrW25dKQogICAgICBkZWwgc2VsZi5zdGFja1tuXQoKICAgIyBnZXRpdGVtL3NldGl0ZW0vbGVuCiAgIGRlZiBfX2dldGl0ZW1fXyhzZWxmLCBuKToKICAgICAgcmV0dXJuIHNlbGYuc3RhY2tbLTEtbl0KICAgZGVmIF9fc2V0aXRlbV9fKHNlbGYsIG4sIHZhbCk6CiAgICAgIHNlbGYuaW5zZXJ0KG4sIHZhbCkKICAgZGVmIF9fbGVuX18oc2VsZik6CiAgICAgIHJldHVybiBsZW4oc2VsZi5zdGFjaykKCgojIHBhcnNlcgpjbGFzcyBQYXJzZXI6CiAgIENPTlNUQU5ULCBDT01NQU5EID0gcmFuZ2UoMikKCiAgICMgcHJvZ3JhbSB3aWxsIGJlIG1hZGUgdXAgb2YgYSBsaXN0IG9mIHRoZXNlCiAgIGNsYXNzIEl0ZW06CiAgICAgIGRlZiBfX2luaXRfXyhzZWxmLCB0eXBlLCB2YWx1ZSk6CiAgICAgICAgIGlmIHR5cGUgaW4gKFBhcnNlci5DT05TVEFOVCwgUGFyc2VyLkNPTU1BTkQpOgogICAgICAgICAgICBzZWxmLnR5cGU9dHlwZQogICAgICAgICAgICBzZWxmLnZhbHVlPXZhbHVlCiAgICAgICAgIGVsc2U6IHJhaXNlIFR5cGVFcnJvciwgIml0ZW0gdHlwZSBpbnZhbGlkOiAlZCIgJSB0eXBlCiAgICAgIAogICAgICBkZWYgX19zdHJfXyhzZWxmKToKICAgICAgICAgaWYgc2VsZi50eXBlPT1QYXJzZXIuQ09NTUFORDogcmV0dXJuIHNlbGYudmFsdWUKICAgICAgICAgZWxpZiBzZWxmLnR5cGU9PVBhcnNlci5DT05TVEFOVDoKICAgICAgICAgICAgaWYgaXNpbnN0YW5jZShzZWxmLnZhbHVlLCBzdHIpOiByZXR1cm4gIlslc10iICUgc2VsZi52YWx1ZQogICAgICAgICAgICBlbHNlOiByZXR1cm4gc3RyKHNlbGYudmFsdWUpCgogICAjIHRha2VzIHN0cmluZywgcmV0dXJucyBsaXN0IG9mIGl0ZW1zCiAgIEBzdGF0aWNtZXRob2QKICAgZGVmIHBhcnNlKHN0cmluZyk6CiAgICAgIGl0ZW1zID0gW10KICAgICAgaSA9IDAKICAgICAgd2hpbGUgaTxsZW4oc3RyaW5nKToKICAgICAgICAgIyBudW1iZXJzCiAgICAgICAgIGlmIHN0cmluZ1tpXSBpbiAiMDEyMzQ1Njc4OSI6IAogICAgICAgICAgICBpdGVtcy5hcHBlbmQoUGFyc2VyLkl0ZW0oUGFyc2VyLkNPTlNUQU5ULCBOVU1UKHN0cmluZ1tpXSkpKQogICAgICAgICAjIHN0cmluZ3MKICAgICAgICAgZWxpZiBzdHJpbmdbaV0gPT0gJ1snOgogICAgICAgICAgICBjdXJzdHIgPSAnJwogICAgICAgICAgICBsdmwgPSAxCiAgICAgICAgICAgIHdoaWxlIGx2bD4wOgogICAgICAgICAgICAgICBpICs9IDEKICAgICAgICAgICAgICAgaWYgKGk+PWxlbihzdHJpbmcpIGFuZCBsdmw+MCk6CiAgICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoZXJyc3RyKHN0cmluZywgInVudGVybWluYXRlZCBbIiwgaS0xKSkKICAgICAgICAgICAgICAgaWYgc3RyaW5nW2ldID09ICddJzogbHZsIC09IDEKICAgICAgICAgICAgICAgZWxpZiBzdHJpbmdbaV0gPT0gJ1snOiBsdmwgKz0gMQogICAgICAgICAgICAgICBpZiAobHZsIT0wKTogY3Vyc3RyICs9IHN0cmluZ1tpXQogICAgICAgICAgICBpdGVtcy5hcHBlbmQoUGFyc2VyLkl0ZW0oUGFyc2VyLkNPTlNUQU5ULCBjdXJzdHIpKQogICAgICAgICAjIHdoaXRlc3BhY2UgaXMgaWdub3JlZAogICAgICAgICBlbGlmIHN0cmluZ1tpXSBpbiAnIFxuXHQnOiBwYXNzCiAgICAgICAgICMgXSB3aXRob3V0IFsgPT0gZXJyb3IKICAgICAgICAgZWxpZiBzdHJpbmdbaV0gPT0gJ10nOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKGVycnN0cihzdHJpbmcsICJdIHdpdGhvdXQgWyIsIGkpKQogICAgICAgICAjIG5vdCBvbmUgb2YgdGhlc2UgPT0gY29tbWFuZAogICAgICAgICBlbHNlOgogICAgICAgICAgICBpdGVtcy5hcHBlbmQoUGFyc2VyLkl0ZW0oUGFyc2VyLkNPTU1BTkQsIHN0cmluZ1tpXSkpCiAgICAgICAgIGkgKz0gMQogICAKICAgICAgcmV0dXJuIGl0ZW1zCgpjbGFzcyBJbnRlcnByZXRlcjoKCiAgICMgZXhjZXB0aW9uIHRvIGJlIGNhdWdodCBpZiBzb21ldGhpbmcgZ29lcyB3cm9uZyB3aXRoIHRoZSBjb2RlCiAgIGNsYXNzIENvZGVFcnJvcihFeGNlcHRpb24pOiBwYXNzOwoKICAgd29ybGQgPSBOb25lCiAgIGNvZGUgPSBOb25lCiAgIHN0YWNrID0gTm9uZQogICBpcCA9IDAKICAgYWN0aXZlc2V0ID0gMAogICBzZXRzID0gTm9uZSAjIGNvbW1hbmQgc2V0cywgc2VlIGluaXQKICAgcGFyZW50ID0gTm9uZQoKICAgZGVmIF9faW5pdF9fKHNlbGYsd29ybGQsY29kZSxzdGFjaz1Ob25lLGlwPTAsYWN0aXZlc2V0PTAscGFyZW50ID0gTm9uZSk6CiAgICAgIHNlbGYud29ybGQgPSB3b3JsZAogICAgICBzZWxmLmNvZGUgPSBjb2RlCiAgICAgIGlmIHN0YWNrPT1Ob25lOgogICAgICAgICBzZWxmLnN0YWNrID0gU3RhY2soKQogICAgICBlbHNlOgogICAgICAgICBzZWxmLnN0YWNrID0gc3RhY2sKICAgICAgc2VsZi5pcCA9IGlwIAogICAgICBzZWxmLmFjdGl2ZXNldCA9IGFjdGl2ZXNldAogICAgICBzZWxmLnBhcmVudCA9IE5vbmUKCiAgICAgIHM9c2VsZiAjIG1ha2VzIHRoZSBodWdlIGxpc3QgbGVzcyBsb25nCiAgICAgIHMuc2V0cyA9IFsKICAgICAgICAgICMgaW5zdHJ1Y3Rpb24gc2V0IDAgIwogICAgICAgICAgeyAnZScgOiBzLmFjdGl2YXRlU2V0MSwKICAgICAgICAgICAgJ2YnIDogcy5hY3RpdmF0ZVNldDIsCiAgICAgICAgICAgICdnJyA6IHMuYWN0aXZhdGVTZXQzLAogICAgICAgICAgICAneCcgOiBzLmNBY3RpdmF0ZVNldCwKICAgICAgICAgICAgJ2onIDogcy5jR2V0U2V0LAogICAgICAgICAgICAneicgOiBzLmNOb3AKICAgICAgICAgIH0sCiAgICAgICAgICAjIGluc3RydWN0aW9uIHNldCAxICMKICAgICAgICAgIHsgJ3UnIDogcy5jRHVwbGljYXRlLAogICAgICAgICAgICAnYScgOiBzLmNBZGQsCiAgICAgICAgICAgICdzJyA6IHMuY1N1YiwKICAgICAgICAgICAgJ20nIDogcy5jTXVsLAogICAgICAgICAgICAnZCcgOiBzLmNEaXYsCiAgICAgICAgICAgICd0JyA6IHMuY1RvU3RyLAogICAgICAgICAgICAnaScgOiBzLmNUb051bSwKICAgICAgICAgICAgJ2MnIDogcy5jQ29uY2F0ZW5hdGUsCiAgICAgICAgICAgICdvJyA6IHMuY091dHB1dCwKICAgICAgICAgICAgJ3EnIDogcy5jSW5saW5lT3V0cHV0LAogICAgICAgICAgICAnbicgOiBzLmNSZWFkQ2hhciwKICAgICAgICAgICAgJ2wnIDogcy5jUmVhZExpbmUsCiAgICAgICAgICAgICdoJyA6IHMuY1N1YnN0cmluZywKICAgICAgICAgICAgJ3knIDogcy5jU3RyTGVuLAogICAgICAgICAgICAndicgOiBzLmNEaXNjYXJkLAogICAgICAgICAgICAncCcgOiBzLmNDb3B5LAogICAgICAgICAgICAnaycgOiBzLmNNb3ZlLAogICAgICAgICAgICAncicgOiBzLmNTdGFja1NpemUKICAgICAgICAgIH0sCiAgICAgICAgICAjIGluc3RydWN0aW9uIHNldCAyICMKICAgICAgICAgIHsgJ3UnIDogcy5jR1QsCiAgICAgICAgICAgICdkJyA6IHMuY0xULAogICAgICAgICAgICAncycgOiBzLmNTa2lwLCAKICAgICAgICAgICAgJ3QnIDogcy5jU2tpcFR3bywKICAgICAgICAgICAgJ3AnIDogcy5jSW5zZXJ0LAogICAgICAgICAgICAnYScgOiBzLmNBbmQsCiAgICAgICAgICAgICdvJyA6IHMuY09yLAogICAgICAgICAgICAnbicgOiBzLmNOb3QsCiAgICAgICAgICAgICdjJyA6IHMuY0V4ZWMsCiAgICAgICAgICAgICd3JyA6IHMuY1doaWxlLAogICAgICAgICAgICAncScgOiBzLmNFcXVhbCwKICAgICAgICAgICAgJ2wnIDogcy5jTHNoaWZ0LAogICAgICAgICAgICAncicgOiBzLmNSc2hpZnQKICAgICAgICAgIH0sCiAgICAgICAgICAjIGluc3RydWN0aW9uIHNldCAzICMKICAgICAgICAgIHsgJ3EnIDogcy5jUXVpdCwKICAgICAgICAgICAgJ3cnIDogcy5jUmVjYWxsV2hpbGUsCiAgICAgICAgICAgICduJyA6IHMuY0lzTnVtYmVyLAogICAgICAgICAgICAncycgOiBzLmNJc1N0cmluZywKICAgICAgICAgICAgJ2EnIDogcy5jQmluQW5kLAogICAgICAgICAgICAnbycgOiBzLmNCaW5PciwKICAgICAgICAgICAgJ2knIDogcy5jSW50ZWdlciwKICAgICAgICAgICAgJ20nIDogcy5jTW9kLAogICAgICAgICAgICAndCcgOiBzLmNUb0NoYXIsCiAgICAgICAgICAgICdjJyA6IHMuY0NoYXJBdCwKICAgICAgICAgICAgJ3InIDogcy5jUmVwbGFjZUNoYXIsIAogICAgICAgICAgICAncCcgOiBzLmNJbnZlcnRlZENvcHksCiAgICAgICAgICAgICdrJyA6IHMuY0ludmVydGVkTW92ZSwgCiAgICAgICAgICAgICdiJyA6IHMuY1N3YXAsCiAgICAgICAgICAgICdkJyA6IHMuY1N3YXAyLAogICAgICAgICAgICAnaCcgOiBzLmNTd2FwMywKICAgICAgICAgIH0KICAgICAgXQogCiAgICMgc3RlcCBmdW5jdGlvbgogICAjIHJldHVybnMgVHJ1ZSBpZiB0aGVyZSBhcmUgbW9yZSBzdGVwcywgRmFsc2UgaWYgbm90LgogICBkZWYgc3RlcChzZWxmKToKICAgICAgaWYgc2VsZi5pcCA+PSBsZW4oc2VsZi5jb2RlKToKICAgICAgICAgcmV0dXJuIEZhbHNlICMgYXQgdGhlIGVuZCBvZiB0aGUgY29kZQogICAgICAKICAgICAgY3VyaXRlbSA9IHNlbGYuY29kZVtzZWxmLmlwXQogCiAgICAgICMgaWYgdGhlcmUncyBhIHRyYWNlIHZhcmlhYmxlIGRlZmluZWQgYW5kIHRydWUsIGdpdmUgYSB0cmFjZQogICAgICB0cnk6IAogICAgICAgICBnbG9iYWwgdHJhY2UKICAgICAgICAgaWYgdHJhY2U6IAogICAgICAgICAgICBwcmludCAiXHgxYls3bSIsICAKICAgICAgICAgICAgcHJpbnQgInRyYWNlOiBjdXI9Iiwgc2VsZi5pcCwgc3RyKGN1cml0ZW0pLCAic2V0PSIsIHNlbGYuYWN0aXZlc2V0LCAic3RhY2s9Iiwgc2VsZi5zdGFjay5zdGFjaywKICAgICAgICAgICAgcHJpbnQgIlx4MWJbMG0iCiAgICAgIGV4Y2VwdDogcGFzcwoKICAgICAgaWYgY3VyaXRlbS50eXBlID09IFBhcnNlci5DT05TVEFOVDoKICAgICAgICAgIyB0aGlzIGlzIGEgY29uc3RhbnQgdmFsdWUsIHB1c2ggaXQKICAgICAgICAgc2VsZi5zZihzZWxmLnN0YWNrLnB1c2gsIFtjdXJpdGVtLnZhbHVlXSkKICAgICAgZWxzZToKICAgICAgICAgIyBpdCdzIGEgY29tbWFuZAogICAgICAgICBpZiBjdXJpdGVtLnZhbHVlIGluIHNlbGYuc2V0c1swXToKICAgICAgICAgICAgIyBjb21tYW5kIHNldCAwIGhhcyBwcmlvcml0eSBhYm92ZSBldmVyeXRoaW5nCiAgICAgICAgICAgIHNlbGYuc2V0c1swXVtjdXJpdGVtLnZhbHVlXSgpCiAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICMgZ2V0IGl0IGZyb20gc2VsZWN0ZWQgc2V0CiAgICAgICAgICAgIGlmIHNlbGYuYWN0aXZlc2V0PDAgb3Igc2VsZi5hY3RpdmVzZXQ+PWxlbihzZWxmLnNldHMpOgogICAgICAgICAgICAgICAjIHNlbGVjdGVkIHNldCBpcyBpbnZhbGlkCiAgICAgICAgICAgICAgIHJhaXNlIEludGVycHJldGVyLkNvZGVFcnJvcihzZWxmLmVycigibm8gc3VjaCBzZXQ6ICVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmFjdGl2ZXNldCkpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgIGlmIG5vdCBjdXJpdGVtLnZhbHVlIGluIHNlbGYuc2V0c1tzZWxmLmFjdGl2ZXNldF06CiAgICAgICAgICAgICAgICAgICNpbnZhbGlkIGNvbW1hbmQgZm9yIHNlbGVjdGVkIHNldAogICAgICAgICAgICAgICAgICByYWlzZSBJbnRlcnByZXRlci5Db2RlRXJyb3Ioc2VsZi5lcnIoCiAgICAgICAgICAgICAgICAgICAgICAgICAic2V0ICVkIGhhcyBubyBjb21tYW5kICclcyciJSggc2VsZi5hY3RpdmVzZXQsIFwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyaXRlbS52YWx1ZSkpKSAgICAgICAgICAgCiAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAgICN5YXkgaXQncyBnb29kLCBydW4gaXQKICAgICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgICBzZWxmLnNldHNbc2VsZi5hY3RpdmVzZXRdW2N1cml0ZW0udmFsdWVdKCkKICAgICAgICAgICAgICAgICAgZXhjZXB0IFplcm9EaXZpc2lvbkVycm9yLCBjb21wbGFpbnQ6CiAgICAgICAgICAgICAgICAgICAgIHJhaXNlIEludGVycHJldGVyLkNvZGVFcnJvcihzZWxmLmVycigKICAgICAgICAgICAgICAgICAgICAgICAgICJkaXZpc2lvbiBieSB6ZXJvICglcykiJWNvbXBsYWludCkpCiAgICAgIHNlbGYuaXAgKz0gMSAgCiAgICAgIHJldHVybiBUcnVlICAgCgogICAjIG1ha2UgYW4gZXJyb3Igc3RyaW5nIHdpdGggZXJyb3IgJiBjdXJyZW50IHN0YXRlCiAgIGRlZiBlcnIoc2VsZiwgZXJyb3IpOgogICAgICByZXR1cm4gaXRlbXNfZXJyc3RyKHNlbGYuY29kZSwgZXJyb3IsIHNlbGYuaXApCgoKICAgIyBjYWxsIHN0YWNrIGZ1bmN0aW9uIGFuZCBjYXRjaCBpdHMgZXJyb3JzCiAgIGRlZiBzZihzZWxmLCBmdW5jLCBhcmdzKToKICAgICAgcnY9Tm9uZQogICAgICB0cnk6IHJ2ID0gZnVuYygqYXJncykKICAgICAgZXhjZXB0IEluZGV4RXJyb3IsIGNvbXBsYWludDoKICAgICAgICAgcmFpc2UgSW50ZXJwcmV0ZXIuQ29kZUVycm9yKHNlbGYuZXJyKCJzdGFjayBlcnJvciAoJXMpIiVjb21wbGFpbnQpKQogICAgICByZXR1cm4gcnYKCiAgICMgcmFpc2UgYSB0eXBlIGVycm9yCiAgIGRlZiByYWlzZVR5cGVFcnIoc2VsZiwgZXhwZWN0ZWQsIGdvdCk6CiAgICAgIHJhaXNlIEludGVycHJldGVyLkNvZGVFcnJvcigKICAgICAgICAgIHNlbGYuZXJyKCJ3cm9uZyB0eXBlOiBleHBlY3RlZCAlcyBpbnN0ZWFkIG9mICVzIiAlIFwKICAgICAgICAgICAgICAgICAgICAgICh0eXBlZGVzYyhleHBlY3RlZCksIHR5cGVkZXNjKGdvdCkpKSkKICAgICAKICAgIyMjIGNvbW1hbmRzICMjIwogICAKICAgIyBjb252ZXJ0IGEgZnVuY3Rpb24gZihhKSBpbnRvIHB1c2goZihwb3AoKSkpICsgdHlwZSBjaGVja2luZwogICBkZWYgdW5hcnlzdGFja2Yoc2VsZiwgZiwgbnR5cGU9Tm9uZSwgcHVzaHJlc3VsdD1UcnVlKToKICAgICAgZGVmIHN0YWNrZnVuYygpOgogICAgICAgICBhPXNlbGYuc2Yoc2VsZi5zdGFjay5wb3AsW10pCiAgICAgICAgIGlmIG50eXBlIGFuZCBub3QgaXNpbnN0YW5jZShhLG50eXBlKToKICAgICAgICAgICAgc2VsZi5yYWlzZVR5cGVFcnIobnR5cGUsIHR5cGUoYSkpCgogICAgICAgICByZXMgPSBmKGEpCiAgICAgICAgIGlmIHB1c2hyZXN1bHQ6IHNlbGYuc2Yoc2VsZi5zdGFjay5wdXNoLFtyZXNdKQogICAgICByZXR1cm4gc3RhY2tmdW5jCgogICAjIGNvbnZlcnQgYSBmdW5jdGlvbiBmKGEsYikgaW50byBiPXBvcCgpLGE9cG9wKCkscHVzaChmKGEsYikpICsgdHlwZSBjaGVja2luZwogICBkZWYgYmluc3RhY2tmKHNlbGYsIGYsIGF0eXBlPU5vbmUsIGJ0eXBlPU5vbmUsIHB1c2hyZXN1bHQ9VHJ1ZSk6CiAgICAgIGRlZiBzdGFja2Z1bmMoKToKICAgICAgICAgYiA9IHNlbGYuc2Yoc2VsZi5zdGFjay5wb3AsW10pCiAgICAgICAgIGEgPSBzZWxmLnNmKHNlbGYuc3RhY2sucG9wLFtdKQogICAgICAgICBpZiBidHlwZSBhbmQgbm90IGlzaW5zdGFuY2UoYiwgYnR5cGUpOgogICAgICAgICAgICBzZWxmLnJhaXNlVHlwZUVycihidHlwZSwgdHlwZShiKSkKICAgICAgICAgaWYgYXR5cGUgYW5kIG5vdCBpc2luc3RhbmNlKGEsIGF0eXBlKToKICAgICAgICAgICAgc2VsZi5yYWlzZVR5cGVFcnIoYXR5cGUsIHR5cGUoYSkpCiAgICAgICAgIHJlcz1mKGEsYikKICAgICAgICAgaWYgcHVzaHJlc3VsdDogc2VsZi5zZihzZWxmLnN0YWNrLnB1c2gsW3Jlc10pCiAgICAgIHJldHVybiBzdGFja2Z1bmMKICAgCiAgICMgYW5kIG5vdyBvbmUgd2l0aCB0aHJlZSBhcmd1bWVudHMgZihhLGIsYykgCiAgIGRlZiB0cmlzdGFja2Yoc2VsZiwgZiwgYXR5cGU9Tm9uZSwgYnR5cGU9Tm9uZSwgY3R5cGU9Tm9uZSwgcHVzaHJlc3VsdD1UcnVlKToKICAgICAgeCA9IHNlbGYuc2YKICAgICAgeSA9IHNlbGYuc3RhY2sucG9wCiAgICAgIGRlZiBzdGFja2Z1bmMoKToKICAgICAgICAgYyA9IHgoeSxbXSkKICAgICAgICAgYiA9IHgoeSxbXSkKICAgICAgICAgYSA9IHgoeSxbXSkKICAgICAgICAgaWYgY3R5cGUgYW5kIG5vdCBpc2luc3RhbmNlKGMsY3R5cGUpOgogICAgICAgICAgICBzZWxmLnJhaXNlVHlwZUVycihjdHlwZSwgdHlwZShjKSkKICAgICAgICAgaWYgYnR5cGUgYW5kIG5vdCBpc2luc3RhbmNlKGIsYnR5cGUpOgogICAgICAgICAgICBzZWxmLnJhaXNlVHlwZUVycihidHlwZSwgdHlwZShiKSkKICAgICAgICAgaWYgYXR5cGUgYW5kIG5vdCBpc2luc3RhbmNlKGEsYXR5cGUpOiAKICAgICAgICAgICAgc2VsZi5yYWlzZVR5cGVFcnIoYXR5cGUsIHR5cGUoYSkpCiAgICAgICAgIHJlcyA9IGYoYSxiLGMpCiAgICAgICAgIGlmIHB1c2hyZXN1bHQ6IHNlbGYuc2Yoc2VsZi5zdGFjay5wdXNoLFtyZXNdKQogICAgICByZXR1cm4gc3RhY2tmdW5jIAogICAgICAgIAogICAjIyBzZXQgMCAjIwogICBkZWYgY0FjdGl2YXRlU2V0KHNlbGYpOgogICAgICBzZXQgPSBzZWxmLnNmKHNlbGYuc3RhY2sucG9wLFtdKQogICAgICBpZiBub3QgaXNpbnN0YW5jZShzZXQsIE5VTVQpOgogICAgICAgICByYWlzZSBJbnRlcnByZXRlci5Db2RlRXJyb3IoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmVycigid3JvbmcgdHlwZTogZXhwZWN0ZWQgbnVtYmVyIikpCiAgICAgIGlmIGxlbihzZWxmLnNldHMpPD1pbnQoc2V0KSBvciBpbnQoc2V0KTwwOiAKICAgICAgICAgcmFpc2UgSW50ZXJwcmV0ZXIuQ29kZUVycm9yKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5lcnIoIm5vIGluc3RydWN0aW9uIHNldCAlZCBleGlzdHMiICUgc2V0KSkKICAgICAgc2VsZi5hY3RpdmVzZXQgPSBpbnQoc2V0KQogICAKICAgZGVmIGFjdGl2YXRlU2V0MShzZWxmKTogc2VsZi5hY3RpdmVzZXQgPSAxCiAgIGRlZiBhY3RpdmF0ZVNldDIoc2VsZik6IHNlbGYuYWN0aXZlc2V0ID0gMgogICBkZWYgYWN0aXZhdGVTZXQzKHNlbGYpOiBzZWxmLmFjdGl2ZXNldCA9IDMKCiAgIGRlZiBjR2V0U2V0KHNlbGYpOgogICAgICBzZWxmLnNmKHNlbGYuc3RhY2sucHVzaCxbc2VsZi5hY3RpdmVzZXRdKQogCiAgIGRlZiBjTm9wKHNlbGYpOiBwYXNzCgogICAjIyBzZXQgMSAjIwogICBkZWYgY0R1cGxpY2F0ZShzZWxmKTogc2VsZi5zZihzZWxmLnN0YWNrLmR1cCxbXSkKICAgZGVmIGNBZGQoc2VsZik6IHNlbGYuYmluc3RhY2tmKGFkZCwgTlVNVCwgTlVNVCkoKQogICBkZWYgY1N1YihzZWxmKTogc2VsZi5iaW5zdGFja2Yoc3ViLCBOVU1ULCBOVU1UKSgpCiAgIGRlZiBjTXVsKHNlbGYpOiBzZWxmLmJpbnN0YWNrZihtdWwsIE5VTVQsIE5VTVQpKCkKICAgZGVmIGNEaXYoc2VsZik6IHNlbGYuYmluc3RhY2tmKGRpdiwgTlVNVCwgTlVNVCkoKQoKICAgIyBzaG9ydGVzdCByZXByZXNlbnRhdGlvbiBvZiB2YWx1ZSBpbiBzdHJpbmcKICAgZGVmIHYyc3RyKHNlbGYsIG4pOgogICAgICBpZiBuPT0iIjogcmV0dXJuIG4KICAgICAgaWYgaXNpbnN0YW5jZShuLHN0cikgYW5kIChuWzBdPT0nICcgb3IgblstMV09PScgJyk6IHJldHVybiBuCiAgICAgIHRyeTogdj1zdHIoaW50KG4pKQogICAgICBleGNlcHQ6CiAgICAgICAgIHRyeTogdj1zdHIoZmxvYXQobikpCiAgICAgICAgIGV4Y2VwdDogdj1zdHIobikKICAgICAgcmV0dXJuIHYKCiAgIGRlZiBjVG9TdHIoc2VsZik6IHNlbGYudW5hcnlzdGFja2Yoc2VsZi52MnN0ciwgTlVNVCkoKQogICBkZWYgY1RvTnVtKHNlbGYpOiAKICAgICAgZGVmIHRvbnVtKHMpOgogICAgICAgICAjIHJldHVybiBhIG51bWJlciBmcm9tIHRoZSBzdHJpbmcgaWYgcG9zc2libGUsCiAgICAgICAgICMgaWYgbm90IGEgdmFsaWQgbnVtYmVyIHRoZW4gcHVzaCB0aGUgc3RyaW5nIGJhY2sKICAgICAgICAgdHJ5OiBuID0gTlVNVChzKQogICAgICAgICBleGNlcHQgVmFsdWVFcnJvcjogbiA9IHMKICAgICAgICAgcmV0dXJuIG4KICAgICAgc2VsZi51bmFyeXN0YWNrZih0b251bSwgU1RSVCkoKQogICBkZWYgY0NvbmNhdGVuYXRlKHNlbGYpOiBzZWxmLmJpbnN0YWNrZihhZGQsIFNUUlQsIFNUUlQpKCkgCiAgIGRlZiBjT3V0cHV0KHNlbGYpOiAgICAgICAgICAgICAKICAgICAgc2VsZi51bmFyeXN0YWNrZigKICAgICAgICAgICAgIChsYW1iZGEgczpzZWxmLndvcmxkLm91dChzZWxmLnYyc3RyKHMpKyJcbiIpKSxwdXNocmVzdWx0PUZhbHNlKSgpCiAgIGRlZiBjSW5saW5lT3V0cHV0KHNlbGYpOiAKICAgICAgc2VsZi51bmFyeXN0YWNrZigKICAgICAgICAgICAgIChsYW1iZGEgczpzZWxmLndvcmxkLm91dChzZWxmLnYyc3RyKHMpKSkscHVzaHJlc3VsdD1GYWxzZSkoKQogICBkZWYgY1JlYWRDaGFyKHNlbGYpOiAKICAgICAgc2VsZi5zZihzZWxmLnN0YWNrLnB1c2gsIFtOVU1UKHNlbGYud29ybGQucmVhZGNoYXIoKSldKQogICBkZWYgY1JlYWRMaW5lKHNlbGYpOgogICAgICBzZWxmLnNmKHNlbGYuc3RhY2sucHVzaCwgW3NlbGYud29ybGQucmVhZGxpbmUoKV0pCiAgICAgCiAgIGRlZiBjU3Vic3RyaW5nKHNlbGYpOgogICAgICBzZWxmLnRyaXN0YWNrZigobGFtYmRhIHN0cm4sc3RhcnQsZW5kOnN0cm5baW50KHN0YXJ0KTppbnQoZW5kKV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNUUlQsTlVNVCxOVU1UKSgpCiAgIGRlZiBjU3RyTGVuKHNlbGYpOiBzZWxmLnVuYXJ5c3RhY2tmKGxlbiwgU1RSVCkoKQogICBkZWYgY0Rpc2NhcmQoc2VsZik6IHNlbGYuc2Yoc2VsZi5zdGFjay5wb3AsIFtdKQogICBkZWYgY0NvcHkoc2VsZik6IHNlbGYudW5hcnlzdGFja2Yoc2VsZi5zdGFjay5jb3B5LCBOVU1ULCBGYWxzZSkoKQogICBkZWYgY01vdmUoc2VsZik6IHNlbGYudW5hcnlzdGFja2Yoc2VsZi5zdGFjay5tb3ZlLCBOVU1ULCBGYWxzZSkoKQogICBkZWYgY1N0YWNrU2l6ZShzZWxmKToKICAgICAgc2VsZi5zZihzZWxmLnN0YWNrLnB1c2gsIE5VTVQobGVuKHNlbGYuc3RhY2spKSkKICAgCiAgICMjIHNldCAyICMjCiAgIGRlZiBjR1Qoc2VsZik6IHNlbGYuYmluc3RhY2tmKGd0KSgpCiAgIGRlZiBjTFQoc2VsZik6IHNlbGYuYmluc3RhY2tmKGx0KSgpCiAgIGRlZiBjU2tpcChzZWxmKToKICAgICAgZGVmIHNraXAobik6IHNlbGYuaXAgKz0gaW50KG4pCiAgICAgIHNlbGYudW5hcnlzdGFja2Yoc2tpcCxOVU1ULEZhbHNlKSgpCiAgIGRlZiBjU2tpcFR3byhzZWxmKToKICAgICAgZGVmIHNraXAyKG4pOiBzZWxmLmlwICs9IGludChuKjIpCiAgICAgIHNlbGYudW5hcnlzdGFja2Yoc2tpcDIsTlVNVCxGYWxzZSkoKQogICBkZWYgY0luc2VydChzZWxmKToKICAgICAgZGVmIGluc2VydCh0aGluZywgd2hlcmUpOiBzZWxmLnN0YWNrLmluc2VydCh3aGVyZSwgdGhpbmcpCiAgICAgIHNlbGYuYmluc3RhY2tmKGluc2VydCwgYnR5cGU9TlVNVCwgcHVzaHJlc3VsdD1GYWxzZSkoKQogICBkZWYgY0FuZChzZWxmKTogc2VsZi5iaW5zdGFja2YobGFtYmRhIGEsYjpOVU1UKGEgYW5kIGIgYW5kIDEgb3IgMCkpKCkKICAgZGVmIGNPcihzZWxmKTogc2VsZi5iaW5zdGFja2YobGFtYmRhIGEsYjpOVU1UKChhIG9yIGIpIGFuZCAxIG9yIDApKSgpCiAgIGRlZiBjTm90KHNlbGYpOiBzZWxmLnVuYXJ5c3RhY2tmKGxhbWJkYSBhOk5VTVQobm90IGEgYW5kIDEgb3IgMCkpKCkKICAgCiAgCiAgIGRlZiBleGVjc3RyKHNlbGYsIGNvZGVzdHIpOgogICAgICBzZWxmLndvcmxkLnJlY3Vyc2Uoc2VsZiwgY29kZXN0cikKCiAgIGRlZiBjRXhlYyhzZWxmKTogc2VsZi51bmFyeXN0YWNrZihzZWxmLmV4ZWNzdHIsU1RSVCxGYWxzZSkoKQogICBkZWYgY1doaWxlKHNlbGYpOgogICAgICB3aGlsZSBUcnVlOgogICAgICAgICAjIHBvcCBhIHZhbHVlCiAgICAgICAgIHZhbCA9IHNlbGYuc2Yoc2VsZi5zdGFjay5wb3AsW10pCiAgICAgICAgIGlmIHZhbDogCiAgICAgICAgICAgICMgcG9wIGNvZGUsIHJ1biBpdAogICAgICAgICAgICBjb2RlID0gc2VsZi5zZihzZWxmLnN0YWNrLnBvcCxbXSkKICAgICAgICAgICAgaWYgbm90IGlzaW5zdGFuY2UoY29kZSwgU1RSVCk6CiAgICAgICAgICAgICAgIHNlbGYucmFpc2VUeXBlRXJyKFNUUlQsIHR5cGUoY29kZSkpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgIHNlbGYuZXhlY3N0cihjb2RlKQogICAgICAgICBlbHNlOgogICAgICAgICAgICBicmVhawogICBkZWYgY0VxdWFsKHNlbGYpOiBzZWxmLmJpbnN0YWNrZihlcSkoKQogICBkZWYgY0xzaGlmdChzZWxmKTogc2VsZi5iaW5zdGFja2YoKGxhbWJkYSBhLGI6aW50KGEpPDxpbnQoYikpLE5VTVQsTlVNVCkoKQogICBkZWYgY1JzaGlmdChzZWxmKTogc2VsZi5iaW5zdGFja2YoKGxhbWJkYSBhLGI6aW50KGEpPj5pbnQoYikpLE5VTVQsTlVNVCkoKQogICAKICAgIyMgc2V0IDMgIyMKICAKICAgZGVmIGNRdWl0KHNlbGYpOiBzZWxmLndvcmxkLnF1aXQoKQogICBkZWYgY1JlY2FsbFdoaWxlKHNlbGYpOgogICAgICAjIHBvcCBjb2RlCiAgICAgIGNvZGUgPSBzZWxmLnNmKHNlbGYuc3RhY2sucG9wLFtdKQogICAgICBpZiBub3QgaXNpbnN0YW5jZShjb2RlLCBTVFJUKTogc2VsZi5yYWlzZVR5cGVFcnIoU1RSVCwgdHlwZShjb2RlKSkKICAgICAgIyB3aGlsZQogICAgICB3aGlsZSBzZWxmLnNmKHNlbGYuc3RhY2sucG9wLFtdKToKICAgICAgICAgc2VsZi5leGVjc3RyKGNvZGUpCiAgIAogICBkZWYgY0lzTnVtYmVyKHNlbGYpOgogICAgICBzZWxmLnVuYXJ5c3RhY2tmKGxhbWJkYSB2OiBpc2luc3RhbmNlKHYsTlVNVCkgYW5kIDEgb3IgMCkoKQogICBkZWYgY0lzU3RyaW5nKHNlbGYpOgogICAgICBzZWxmLnVuYXJ5c3RhY2tmKGxhbWJkYSB2OiBpc2luc3RhbmNlKHYsU1RSVCkgYW5kIDEgb3IgMCkoKQogICAjIGJpbmFyeSBhbmQvb3IgdXNlIGludGVnZXJzIGFnYWluCiAgIGRlZiBiaW5vcChzZWxmLG9wKTogcmV0dXJuIGxhbWJkYSBhLGI6IG9wKGludChhKSwgaW50KGIpKQogICBkZWYgY0JpbkFuZChzZWxmKTogc2VsZi5iaW5zdGFja2Yoc2VsZi5iaW5vcChhbmRfKSwgTlVNVCwgTlVNVCkoKQogICBkZWYgY0Jpbk9yKHNlbGYpOiBzZWxmLmJpbnN0YWNrZihzZWxmLmJpbm9wKG9yXyksIE5VTVQsIE5VTVQpKCkKICAgZGVmIGNJbnRlZ2VyKHNlbGYpOiBzZWxmLnVuYXJ5c3RhY2tmKGludCwgTlVNVCkoKQogICBkZWYgY01vZChzZWxmKTogc2VsZi5iaW5zdGFja2YobW9kLCBOVU1ULCBOVU1UKSgpCiAgIGRlZiBjVG9DaGFyKHNlbGYpOiBzZWxmLnVuYXJ5c3RhY2tmKChsYW1iZGEgazpjaHIoaW50KGspJTI1NikpLCBOVU1UKSgpCiAgIGRlZiBjQ2hhckF0KHNlbGYpOiAKICAgICAgZGVmIGNoYXJhdChzdHJuLCBpZHgpOgogICAgICAgICBpZHg9aW50KGlkeCkKICAgICAgICAgaWYgKGlkeDwwIG9yIGlkeD49bGVuKHN0cm4pKToKICAgICAgICAgICAgIyBub3doZXJlIGluIHRoZSBzcGVjIGl0IHNheXMgcHl0aG9uLXN0eWxlIG5lZ2F0aXZlIGluZGV4ZXMKICAgICAgICAgICAgIyBhcmUgYWxsb3dlZC4uLgogICAgICAgICAgICByYWlzZSBJbnRlcnByZXRlci5Db2RlRXJyb3Ioc2VsZi5lcnIoCiAgICAgICAgICAgICAgICAgICAoImluZGV4IG91dCBvZiBib3VuZHM6IHRyaWVkIHRvIGdldCAlZC1jaGFyIHN0cmluZydzICIgK1wKICAgICAgICAgICAgICAgICAgICAiJWQlcyBjaGFyYWN0ZXIiKSAlIChsZW4oc3RybiksIGlkeCwgb3Jkc3VmZml4KGlkeCkpICkpCiAgICAgICAgIHJldHVybiBOVU1UKG9yZChzdHJuW2lkeF0pKQogICAgICBzZWxmLmJpbnN0YWNrZihjaGFyYXQsIFNUUlQsIE5VTVQpKCkKICAgZGVmIGNSZXBsYWNlQ2hhcihzZWxmKToKICAgICAgZGVmIHJlcGxhY2VjaGFyKHN0cm4sIGlkeCwgcmVwbCk6CiAgICAgICAgIGlkeD1pbnQoaWR4KQogICAgICAgICBpZiAoaWR4PDAgb3IgaWR4Pj1sZW4oc3RybikpOgogICAgICAgICAgICByYWlzZSBJbnRlcnByZXRlci5Db2RlRXJyb3Ioc2VsZi5lcnIoCiAgICAgICAgICAgICAgICAgICAoImluZGV4IG91dCBvZiBib3VuZHM6IHRyaWVkIHRvIGNoYW5nZSAlZC1jaGFyIHN0cmluZydzICIrXAogICAgICAgICAgICAgICAgICAgICIlZCVzIGNoYXJhY3RlciIpICUgKGxlbihzdHJuKSwgaWR4LCBvcmRzdWZmaXgoaWR4KSkgKSkKICAgICAgICAgcmV0dXJuIHN0cm5bOmlkeF0gKyByZXBsWzBdICsgc3RybltpZHgrMTpdCiAgICAgIHNlbGYudHJpc3RhY2tmKHJlcGxhY2VjaGFyLCBTVFJULCBOVU1ULCBTVFJUKSgpCiAgIGRlZiBjSW52ZXJ0ZWRDb3B5KHNlbGYpOgogICAgICBzZWxmLnVuYXJ5c3RhY2tmKHNlbGYuc3RhY2suaW52Y29weSwgTlVNVCwgRmFsc2UpKCkKICAgZGVmIGNJbnZlcnRlZE1vdmUoc2VsZik6CiAgICAgIHNlbGYudW5hcnlzdGFja2Yoc2VsZi5zdGFjay5pbnZtb3ZlLCBOVU1ULCBGYWxzZSkoKQogICBkZWYgY1N3YXAoc2VsZik6IHNlbGYuc2Yoc2VsZi5zdGFjay5zd2FwLCBbXSkKICAgZGVmIGNTd2FwMihzZWxmKTogc2VsZi5zZihzZWxmLnN0YWNrLnN3YXAyLCBbXSkKICAgZGVmIGNTd2FwMyhzZWxmKTogc2VsZi5zZihzZWxmLnN0YWNrLnN3YXAzLCBbXSkKCgogICAgIAojIGNsYXNzIFdvcmxkCiMgaGFuZGxlcyBzdGVwcGluZyBvZiBpbnRlcnByZXRlciBhbmQgaW5wdXQgYW5kIG91dHB1dAojICAgV29ybGQoKS5xdWl0KCkgLT4gZW5kcyBwcm9ncmFtCiMgICBXb3JsZCgpLm91dCgiYmxhaCIpIC0+IHN0ZG91dC53cml0ZSgiYmxhaCIpCiMgICBXb3JsZCgpLnJlYWRjaGFyKCkgLT4gcmVhZCAxIGNoYXIgZnJvbSBzdGRpbgojICAgV29ybGQoKS5yZWFkbGluZSgpIC0+IHJlYWQgMSBsaW5lIGZyb20gc3RkaW4KCmNsYXNzIFdvcmxkOgogICBpbnRlcnByZXRlciA9IE5vbmUKCiAgIGRlZiBfX2luaXRfXyhzZWxmLCBjb2Rlc3RyLCBwcmV2aW50PU5vbmUpOgogICAgICAjIHBhcnNlIHRoZSBjb2RlCiAgICAgICAKICAgICAgc2VsZi5jb2RlID0gUGFyc2VyLnBhcnNlKGNvZGVzdHIpCiAgICAgIAogIAogICAgICBpZiBwcmV2aW50OgogICAgICAgICBzZWxmLmludGVycHJldGVyID0gSW50ZXJwcmV0ZXIoIHNlbGYsIHNlbGYuY29kZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50PXByZXZpbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhY2s9cHJldmludC5zdGFjaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3RpdmVzZXQ9cHJldmludC5hY3RpdmVzZXQgKQogICAgICBlbHNlOgogICAgICAgICBzZWxmLmludGVycHJldGVyID0gSW50ZXJwcmV0ZXIoIHNlbGYsIHNlbGYuY29kZSApCiAgIAogICAjIHJ1biB0aGUgaW50ZXJwcmV0ZXIgdW50aWwgaXQgZmFpbHMgb3IgcXVpdHMKICAgZGVmIHJ1bihzZWxmKToKICAgICAgCiAgICAgIHdoaWxlIHNlbGYuaW50ZXJwcmV0ZXIuc3RlcCgpOiBwYXNzCiAgICAgCgogICAjIHRoZSBpbnRlcnByZXRlciBjYWxscyB0aGVzZSBmb3IgcHJvZ3JhbSBjb250cm9sCiAgIGRlZiBxdWl0KHNlbGYpOgogICAgICBzeXMuZXhpdCgwKQogICAKICAgZGVmIG91dChzZWxmLCBzdHJpbmcpOgogICAgICBzeXMuc3Rkb3V0LndyaXRlKHN0cmluZykKCiAgIGRlZiByZWFkY2hhcihzZWxmKToKICAgICAgdiA9IHN5cy5zdGRpbi5yZWFkKDEpCiAgICAgIGlmIG5vdCB2OiByZXR1cm4gLTEKICAgICAgZWxzZTogcmV0dXJuIG9yZCh2KQoKICAgZGVmIHJlYWRsaW5lKHNlbGYpOgogICAgICByZXR1cm4gc3lzLnN0ZGluLnJlYWRsaW5lKCkKCiAgIGRlZiByZWN1cnNlKHNlbGYsIHByZXZpbnQsIGNvZGVzdHIpOgogICAgICB0cnk6CiAgICAgICAgICMgcnVuIHRoZSBzdWItaW50ZXJwcmV0ZXIgaW4gaXRzIG93biB3b3JsZAogICAgICAgICB3ID0gV29ybGQoY29kZXN0ciwgcHJldmludD1wcmV2aW50KQogICAgICAgICB3LnJ1bigpCiAgICAgIGV4Y2VwdCBWYWx1ZUVycm9yLCBjb21wbGFpbnQ6CiAgICAgICAgICMgcGFyc2luZyBmYWlsZWQKICAgICAgICAgcmFpc2UgSW50ZXJwcmV0ZXIuQ29kZUVycm9yKHByZXZpbnQuZXJyKAogICAgICAgICAgICAgICAgICAiZXhlYzogcGFyc2luZyBvZiBzdHJpbmcgZmFpbGVkOiBcblx0JXNcbiIgJSBjb21wbGFpbnQpKQogICAgICBleGNlcHQgSW50ZXJwcmV0ZXIuQ29kZUVycm9yLCBjb21wbGFpbnQ6CiAgICAgICAgICMgcnVuLXRpbWUgZXJyb3IgaW4gY29kZQogICAgICAgICByYWlzZSBJbnRlcnByZXRlci5Db2RlRXJyb3IocHJldmludC5lcnIoCiAgICAgICAgICAgICAgICAgICJleGVjOiBzdWItaW50ZXJwcmV0ZXIgcnVudGltZSBlcnJvcjogXG5cdCVzXG4iICUgY29tcGxhaW50KSkKICAgICAgZXhjZXB0IEV4Y2VwdGlvbiwgY29tcGxhaW50OgogICAgICAgICAjIHNvbWV0aGluZyBlbHNlIHdlbnQgd3JvbmcKICAgICAgICAgcmFpc2UgSW50ZXJwcmV0ZXIuQ29kZUVycm9yKHByZXZpbnQuZXJyKAogICAgICAgICAgICAgICAgICAiZXhlYzogc3ViLWludGVycHJldGVyIGZhaWxlZDogJXMiICUgc3RyKGNvbXBsYWludCkpKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBzdGFydCB0aGUgcHJvZ3JhbQpkZWYgbWFpbihhcmd2KToKICAgZ2xvYmFsIHRyYWNlCiAgIGlmIEZhbHNlOiAKICAgICAgcHJpbnQgInVzYWdlOiAlcyBbLXRyYWNlXSBmaWxlbmFtZSB8IC0iICUgYXJndlswXQogICAgICBzeXMuZXhpdCgyKQogICBlbHNlOgogICAgICB0cnk6CiAgICAgIAkgZm5hbWU9Ii0iCiAgICAgIAkgdHJhY2U9RmFsc2UKICAgICAgICAgaWYgZm5hbWU9PSctJzogZiA9IHN5cy5zdGRpbgogICAgICAgICBlbHNlOiBmID0gZmlsZShmbmFtZSwgJ3InKQogICAgICBleGNlcHQ6CiAgICAgICAgIHByaW50ICJDYW4ndCBvcGVuIGZpbGUgJXMiICUgYXJndlsxXQogICAgICAgICBzeXMuZXhpdCgzKQogICAgICBjb2RlID0gZi5yZWFkKCkKICAgICAgZi5jbG9zZSgpCiAgICAgICAgIAogICAgICB0cnk6CiAgICAgICAgIHcgPSBXb3JsZChjb2RlKQogICAgICAgICB3LnJ1bigpCiAgICAgIGV4Y2VwdCBJbnRlcnByZXRlci5Db2RlRXJyb3IsIGNvbXBsYWludDoKICAgICAgICAgcHJpbnQgIlJ1bi10aW1lIGVycm9yOiAlcyIgJSBjb21wbGFpbnQKICAgICAgZXhjZXB0IFZhbHVlRXJyb3IsIGNvbXBsYWludDoKICAgICAgICAgcHJpbnQgIlBhcnNlIGVycm9yOiAlcyIgJSBjb21wbGFpbnQKICAgICAgZXhjZXB0IEV4Y2VwdGlvbiwgY29tcGxhaW50OgogICAgICAgICBwcmludCAiQW4gZXhjZXB0aW9uIG9jY3VyZWQ6ICVzIiAlIGNvbXBsYWludAoKaWYgX19uYW1lX189PSJfX21haW5fXyI6IG1haW4oc3lzLmFyZ3Yp