#!/usr/bin/perl
use strict;
use warnings;
#use bigint;
use Getopt:: Std ;
my $ENDMARK = '--end--' ;
my $SLIMIT_DEFAULT = 10000 ;
my $CLEVEL_DEFAULT = 3 ;
my @inst = ( ) ;
my @stack = ( ) ;
my @cstack = ( ) ;
my @heap = ( ) ;
my %labels = ( ) ;
my $ip = 0 ;
my $continue = 1 ;
my $inum = 0 ;
my $bytes = 0 ;
my $step = 0 ;
my $stackhwm = 0 ;
my $ibuf = '' ;
my $codelevel ;
my $slimit ;
my $unlimited ;
sub checkStack
{
die "stack out of range\n " if @stack < $_ [ 0 ] ; }
sub updateHWM
{
$stackhwm = @stack if $stackhwm < @stack ;
}
sub wspush
{
updateHWM( ) ;
}
sub wsdup
{
updateHWM( ) ;
}
sub wscopy
{
checkStack( $pos + 1 ) ;
updateHWM( ) ;
}
sub wsswap
{
@stack [ 0 , 1 ] = @stack [ 1 , 0 ] ;
}
sub wspop
{
}
sub wsslide
{
checkStack( $num + 1 ) ;
}
sub wsadd
{
$stack [ 0 ] += $var ;
}
sub wssub
{
$stack [ 0 ] -= $var ;
}
sub wsmul
{
$stack [ 0 ] *= $var ;
}
sub checkDivider( $)
{
die "0 divide exception occurred\n " if $_ [ 0 ] == 0 ; }
sub wsdiv
{
checkDivider( $var ) ;
$stack [ 0 ] -= $stack [ 0 ] %$var ;
$stack [ 0 ] /= $var ;
}
sub wsmod
{
checkDivider( $var ) ;
$stack [ 0 ] %= $var ;
}
sub checkHeapAddress( $$ )
{
my ( $address , $doexpand ) = @_ ;
die "negative address is not allowed\n " if $address < 0 ;
die "heap out of range\n " if ! $doexpand ; push @heap , ( 0 ) x
( $address - $#heap - 1 ) ; }
sub storeheap
{
my ( $val , $addr ) = @_ ;
checkHeapAddress( $addr , 1 ) ;
$heap [ $addr ] = $val ;
}
sub wsstor
{
storeheap
( splice @stack , 0 , 2 ) ; }
sub wsretr
{
checkHeapAddress( $addr , 0 ) ;
}
sub wsmark
{
$labels { $label } -> { 'ip' } = $ip ;
}
sub wsjump_common( @ )
{
if ( exists $labels { $label } -> { 'ip' } ) {
$ip = $labels { $label } -> { 'ip' } ;
}
else
{
$skip = { 'to' => $label , 'from' => $ip } ;
}
}
sub wscall
{
wsjump_common( @_ ) ;
}
sub wsjump
{
wsjump_common( @_ ) ;
}
sub wsjzero
{
wsjump_common( @_ ) ;
}
sub wsjneg
{
wsjump_common( @_ ) ;
}
sub wsret
{
die "call stack is empty\n " unless @cstack ; }
sub wsend
{
$continue = 0 ;
}
sub wsputc
{
$c =~ /[^[:print:]\s]/
and die "output non-printable character ( $val )\n " ; }
sub wsputi
{
}
sub fillbuffer
{
$ibuf = <>;
die "detected eof on input stream\n " }
sub wsgetc
{
fillbuffer( ) if $ibuf eq '' ;
storeheap( $val , $addr ) ;
}
sub wsgeti
{
fillbuffer( ) if $ibuf eq '' ;
$ibuf =~ /^\s*([-]?\d+)\s*$/
or die "not integer data on input stream\n " ; my $val = 0 + $1 ;
$ibuf = '' ;
storeheap( $val , $addr ) ;
}
my %ops = (
'push' => { 'sub' => \&wspush , 'imp' => 's' , 'code' => 's' , 'arg' => 'int' } ,
'dup' => { 'sub' => \&wsdup , 'imp' => 's' , 'code' => 'ns' , 'arg' => 'void' , 'stackfreq' => 1 } ,
'copy' => { 'sub' => \&wscopy , 'imp' => 's' , 'code' => 'ts' , 'arg' => 'uint' } ,
'swap' => { 'sub' => \&wsswap , 'imp' => 's' , 'code' => 'nt' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'pop' => { 'sub' => \&wspop , 'imp' => 's' , 'code' => 'nn' , 'arg' => 'void' , 'stackfreq' => 1 } ,
'slide' => { 'sub' => \&wsslide , 'imp' => 's' , 'code' => 'tn' , 'arg' => 'uint' } ,
'add' => { 'sub' => \&wsadd , 'imp' => 'ts' , 'code' => 'ss' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'sub' => { 'sub' => \&wssub , 'imp' => 'ts' , 'code' => 'st' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'mul' => { 'sub' => \&wsmul , 'imp' => 'ts' , 'code' => 'sn' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'div' => { 'sub' => \&wsdiv , 'imp' => 'ts' , 'code' => 'ts' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'mod' => { 'sub' => \&wsmod , 'imp' => 'ts' , 'code' => 'tt' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'stor' => { 'sub' => \&wsstor , 'imp' => 'tt' , 'code' => 's' , 'arg' => 'void' , 'stackfreq' => 2 } ,
'retr' => { 'sub' => \&wsretr , 'imp' => 'tt' , 'code' => 't' , 'arg' => 'void' , 'stackfreq' => 1 } ,
'mark' => { 'sub' => \&wsmark , 'imp' => 'n' , 'code' => 'ss' , 'arg' => 'label' , 'dontskip' => 1 } ,
'call' => { 'sub' => \&wscall , 'imp' => 'n' , 'code' => 'st' , 'arg' => 'label' } ,
'jump' => { 'sub' => \&wsjump , 'imp' => 'n' , 'code' => 'sn' , 'arg' => 'label' } ,
'jzero' => { 'sub' => \&wsjzero , 'imp' => 'n' , 'code' => 'ts' , 'arg' => 'label' , 'stackfreq' => 1 } ,
'jneg' => { 'sub' => \&wsjneg , 'imp' => 'n' , 'code' => 'tt' , 'arg' => 'label' , 'stackfreq' => 1 } ,
'ret' => { 'sub' => \&wsret , 'imp' => 'n' , 'code' => 'tn' , 'arg' => 'void' } ,
'end' => { 'sub' => \&wsend , 'imp' => 'n' , 'code' => 'nn' , 'arg' => 'void' } ,
'putc' => { 'sub' => \&wsputc , 'imp' => 'tn' , 'code' => 'ss' , 'arg' => 'void' , 'stackfreq' => 1 } ,
'puti' => { 'sub' => \&wsputi , 'imp' => 'tn' , 'code' => 'st' , 'arg' => 'void' , 'stackfreq' => 1 } ,
'getc' => { 'sub' => \&wsgetc , 'imp' => 'tn' , 'code' => 'ts' , 'arg' => 'void' , 'stackfreq' => 1 } ,
'geti' => { 'sub' => \&wsgeti , 'imp' => 'tn' , 'code' => 'tt' , 'arg' => 'void' , 'stackfreq' => 1 } ,
) ;
sub argcode( $$ $)
{
my ( $arg , $sig , $arglen ) = @_ ;
my $nosig = '' ;
if ( $arg != 0 )
{
my @part = ( ) ;
my $base = 1 << 63 ;
for ( ; $arg >= $base ; $arg /= $base )
{
}
}
'0' x
( $arglen - length $nosig ) : '' ; }
sub convert( $)
{
if ( $codelevel == 2 )
{
$_ [ 0 ] =~ tr/+0\-1. /ssttn/d ;
}
elsif ( $codelevel >= 3 )
{
$_ [ 0 ] =~ tr/+0s\-1t.n / \t\t\t\n\n/d ;
}
}
sub compile( $)
{
my ( $lineno , $line ) = @ { $_ [ 0 ] } ;
$line =~ /^\s*(\w+)(\s+(([-+])?(\d+)(?:\((\d+)b\))?|(\w+)))?\s*$/
or die "invalid format at line $lineno\n " ; my $istr = $1 ;
die "'$istr' is unknown at line $lineno\n " my $ref = $ops { $istr } ;
my %ret = ( ) ;
my $argstr = '' ;
my $arglen = 0 ;
if ( $ref -> { 'arg' } eq 'void' )
{
die "no arguments allowed for '$istr' at line $lineno\n " }
{
my $arg = 0 + $5 ;
my $sig = $4 // '+' ;
$argstr = argcode( $arg , $sig , $6 ) ;
my $ilen = $arglen - 2 ;
$ret { 'arg' } = $ref -> { 'arg' } eq 'label' ?
"$sig$arg(${ilen}b)" :
$sig eq '-' ? - $arg : $arg ;
$ret { 'negativeargerror' } = 1
if $ref -> { 'arg' } eq 'uint' && $sig eq '-' ;
$labels { $ret { 'arg' } } -> { 'count' } ++
if $ref -> { 'arg' } eq 'label' ;
}
else
{
die "invalid argument for '$istr' at line $lineno\n " unless $ref -> { 'arg' } eq 'label' ;
{
$ret { 'arg' } = $7 ;
$ret { 'relabel' } = 1 ;
$labels { $ret { 'arg' } } -> { 'relabel' } = 1 ;
}
else
{
$ret { 'arg' } = '' ;
$argstr = '.' ;
$arglen = 1 ;
}
$labels { $ret { 'arg' } } -> { 'count' } ++;
}
if ( $codelevel > 0 )
{
my $code = join ' ' , @$ref { qw ( imp code
) } ; $code .= " $argstr" if $argstr ne '' ;
convert( $code ) ;
$ret { 'code' } = $code ;
}
$bytes += $arglen + length ( $ref -> { 'imp' } ) + length ( $ref -> { 'code' } ) ; @ret { qw ( sub dontskip stackfreq
) } = @$ref { qw ( sub dontskip stackfreq
) } ; $ret { 'line' } = $lineno ;
}
sub relabel( )
{
my $null_unused = ! exists $labels { '' } ; my ( $body , $sig , $len , $lim ) = ( 0 , '+' , 0 , 1 ) ;
my ( $lcand , $code ) ;
foreach my $label ( sort { $labels { $b } -> { 'count' } <=> $labels { $a } -> { 'count' } || $a cmp $b } {
my $newlabel ;
if ( $null_unused )
{
$newlabel = '' ;
$code = '.' ;
$null_unused = 0 ;
}
else
{
for ( my $retry = 1 ; $retry ; )
{
$newlabel = "$sig$body(${len}b)" ;
if ( ! exists $labels { $newlabel } ) {
$retry = 0 ;
$code = argcode( $body , $sig , $len ) ;
}
if ( $sig eq '+' )
{
$sig = '-' ;
}
else
{
$sig = '+' ;
if ( ++ $body >= $lim )
{
$body = 0 ;
$len ++;
$lim *= 2 ;
}
}
}
}
$labels { $label } -> { 'relabel' } = $newlabel ;
$labels { $label } -> { 'code' } = $code ;
$bytes += length ( $code ) *$labels { $label } -> { 'count' } ; }
foreach my $i ( @inst )
{
next unless exists $i -> { 'relabel' } ; my $code = ' ' . $labels { $i -> { 'arg' } } -> { 'code' } ;
convert( $code ) ;
$i -> { 'code' } .= $code ;
}
}
sub report( $)
{
my $ssize = @stack ;
my $hsize = @heap ;
my $msg = $error ? 'with an error' : 'normally' ;
relabel( ) ;
--
program ended $msg .
instructions: $inum
steps: $step
the last ip: $ip ( line $inst [ $ip - 1 ] -> { 'line' } )
src bytes: $bytes
stack size: $ssize ( final) / $stackhwm ( high water mark)
heap size: $hsize
_EOS_
print "\n label statistics:\n " ; if ( ! %labels )
{
print "no label exists\n " }
else
{
foreach my $label ( sort { $labels { $b } -> { 'count' } <=> $labels { $a } -> { 'count' } || $a cmp $b } keys %labels ) {
( $label eq '' ? '(null)' : $label ) ,
( exists $labels { $label } -> { 'relabel' } ? ' relabeled to ' . (
$labels { $label } -> { 'relabel' } eq '' ?
'(null)' : $labels { $label } -> { 'relabel' } ) :
'' ) ,
': ' , $labels { $label } -> { 'count' } , "\n " ;
}
}
print "\n the error is shown below:\n $error\n " if $error ; if ( $codelevel > 0 )
{
print join $codelevel < 2 ? "\n " : "" , map { $_ -> { 'code' } } @inst ; }
}
sub readsrc( $)
{
my @lines = ( ) ;
my $ifh = \* ARGV ;
if ( $separated )
{
or die "failed to open source file\n " ; }
my $embbedopt_end = 0 ;
while ( < $ifh > )
{
if ( $_ eq $ENDMARK )
{
die "don't use '$ENDMARK' in a separated source file\n " if $separated ;
last ;
}
if ( ! $embbedopt_end && /^#\+opt:\s*(\w+)(=(\w+))?/ )
{
if ( $1 eq 'unlimited' && ! defined $2 ) {
$unlimited = 1 ;
}
elsif ( $1 eq 'codelevel' && defined $3 ) {
$codelevel = 0 + $3 ;
}
elsif ( $1 eq 'limit' && defined $3 ) {
$slimit = 0 + $3 ;
}
else
{
warn "invalid embbed option at line $.\n " ; }
next ;
}
s/\s*(#.*)?$// ;
next unless /\S/ ;
$embbedopt_end = 1 ;
}
}
#-- main
my $usage = "Usage: $0 [-h] [-u|-l maxsteps] [-c code-level] {[merged-file] | -s srcfile [input-file]}\n " ;
my %opts = ( ) ;
getopts( 'hus:l:c:' , \%opts ) ;
$unlimited = exists $opts { 'u' } ; die $usage if $unlimited && exists $opts { 'l' } ; $slimit = $opts { 'l' } // $SLIMIT_DEFAULT ;
$codelevel = $opts { 'c' } // $CLEVEL_DEFAULT ;
my @srclines = readsrc( $opts { 's' } ) ;
{
while ( $continue )
{
die "exceeded step limit\n " if ! $unlimited && $step >= $slimit ;
$ip ++;
my $i ;
if ( $ip <= @inst )
{
$i = $inst [ $ip - 1 ] ;
}
else
{
if ( ! @srclines )
{
my $sup ;
{
$sup = "mark '$skip->{'to'}'" ;
$ip = $skip -> { 'from' } ;
}
else
{
$sup = 'end' ;
$ip --;
}
die "unexpected end of source before the $sup\n " }
{
$i = compile
( shift @srclines ) ; } ;
if ( $@ )
{
die "invalid instruction ( $@ )\n " ; }
$inum ++;
}
next if defined $skip && ! $i -> { 'dontskip' } ; {
die "negative argument is not allowed\n " if $i -> { 'negativeargerror' } ;
die $i -> { 'stackfreq' } > 1 ? "stack short\n " : "stack empty\n " if defined $i -> { 'stackfreq' } && @stack < $i -> { 'stackfreq' } ; & { $i -> { 'sub' } } ( @$i { qw ( arg
) } ) ; } ;
if ( $@ )
{
die "runtime error ( $@ at line $i->{'line'} )\n " ; }
$step ++;
}
} ;
report( $@ ) ;
IyEvdXNyL2Jpbi9wZXJsCgp1c2Ugc3RyaWN0Owp1c2Ugd2FybmluZ3M7CiN1c2UgYmlnaW50Owp1c2UgR2V0b3B0OjpTdGQ7CgpteSAkRU5ETUFSSyA9ICctLWVuZC0tJzsKbXkgJFNMSU1JVF9ERUZBVUxUPTEwMDAwOwpteSAkQ0xFVkVMX0RFRkFVTFQ9MzsKbXkgQGluc3QgPSAoKTsKbXkgQHN0YWNrID0gKCk7Cm15IEBjc3RhY2sgPSAoKTsKbXkgQGhlYXAgPSAoKTsKbXkgJWxhYmVscyA9ICgpOwpteSAkaXAgPSAwOwpteSAkY29udGludWUgPSAxOwpteSAkc2tpcCA9IHVuZGVmOwpteSAkaW51bSA9IDA7Cm15ICRieXRlcyA9IDA7Cm15ICRzdGVwID0gMDsKbXkgJHN0YWNraHdtID0gMDsKbXkgJGlidWYgPSAnJzsKbXkgJGNvZGVsZXZlbDsKbXkgJHNsaW1pdDsKbXkgJHVubGltaXRlZDsKCnN1YiBjaGVja1N0YWNrCnsKICBkaWUgInN0YWNrIG91dCBvZiByYW5nZVxuIiBpZiBAc3RhY2sgPCAkX1swXTsKfQpzdWIgdXBkYXRlSFdNCnsKICAkc3RhY2tod20gPSBAc3RhY2sgaWYgJHN0YWNraHdtIDwgQHN0YWNrOwp9CnN1YiB3c3B1c2gKewogIHVuc2hpZnQgQHN0YWNrLCBzaGlmdDsKICB1cGRhdGVIV00oKTsKfQpzdWIgd3NkdXAKewogIHVuc2hpZnQgQHN0YWNrLCAkc3RhY2tbMF07CiAgdXBkYXRlSFdNKCk7Cn0Kc3ViIHdzY29weQp7CiAgbXkgJHBvcyA9IHNoaWZ0OwogIGNoZWNrU3RhY2soJHBvcysxKTsKICB1bnNoaWZ0IEBzdGFjaywgJHN0YWNrWyRwb3NdOwogIHVwZGF0ZUhXTSgpOwp9CnN1YiB3c3N3YXAKewogIEBzdGFja1swLDFdID0gQHN0YWNrWzEsMF07Cn0Kc3ViIHdzcG9wCnsKICBzaGlmdCBAc3RhY2s7Cn0Kc3ViIHdzc2xpZGUKewogIG15ICRudW0gPSBzaGlmdDsKICBjaGVja1N0YWNrKCRudW0rMSk7CiAgc3BsaWNlIEBzdGFjaywgMSwgJG51bTsKfQpzdWIgd3NhZGQKewogIG15ICR2YXIgPSBzaGlmdCBAc3RhY2s7CiAgJHN0YWNrWzBdICs9ICR2YXI7Cn0Kc3ViIHdzc3ViCnsKICBteSAkdmFyID0gc2hpZnQgQHN0YWNrOwogICRzdGFja1swXSAtPSAkdmFyOwp9CnN1YiB3c211bAp7CiAgbXkgJHZhciA9IHNoaWZ0IEBzdGFjazsKICAkc3RhY2tbMF0gKj0gJHZhcjsKfQpzdWIgY2hlY2tEaXZpZGVyKCQpCnsKICBkaWUgIjAgZGl2aWRlIGV4Y2VwdGlvbiBvY2N1cnJlZFxuIiBpZiAkX1swXSA9PSAwOwp9CnN1YiB3c2Rpdgp7CiAgbXkgJHZhciA9IHNoaWZ0IEBzdGFjazsKICBjaGVja0RpdmlkZXIoJHZhcik7CiAgJHN0YWNrWzBdIC09ICRzdGFja1swXSUkdmFyOwogICRzdGFja1swXSAvPSAkdmFyOwp9CnN1YiB3c21vZAp7CiAgbXkgJHZhciA9IHNoaWZ0IEBzdGFjazsKICBjaGVja0RpdmlkZXIoJHZhcik7CiAgJHN0YWNrWzBdICU9ICR2YXI7Cn0Kc3ViIGNoZWNrSGVhcEFkZHJlc3MoJCQpCnsKICBteSAoICRhZGRyZXNzLCAkZG9leHBhbmQgKSA9IEBfOwogIGRpZSAibmVnYXRpdmUgYWRkcmVzcyBpcyBub3QgYWxsb3dlZFxuIgogICAgaWYgJGFkZHJlc3MgPCAwOwogIHJldHVybiBpZiAkYWRkcmVzcyA8PSAkI2hlYXA7CiAgZGllICJoZWFwIG91dCBvZiByYW5nZVxuIiBpZiAhJGRvZXhwYW5kOwogIHB1c2ggQGhlYXAsICgwKXgoJGFkZHJlc3MtJCNoZWFwLTEpOwp9CnN1YiBzdG9yZWhlYXAKewogIG15ICggJHZhbCwgJGFkZHIgKSA9IEBfOwogIGNoZWNrSGVhcEFkZHJlc3MoJGFkZHIsMSk7CiAgJGhlYXBbJGFkZHJdID0gJHZhbDsKfQpzdWIgd3NzdG9yCnsKICBzdG9yZWhlYXAoc3BsaWNlIEBzdGFjaywgMCwgMik7Cn0Kc3ViIHdzcmV0cgp7CiAgbXkgJGFkZHIgPSBzaGlmdCBAc3RhY2s7CiAgY2hlY2tIZWFwQWRkcmVzcygkYWRkciwwKTsKICB1bnNoaWZ0IEBzdGFjaywgJGhlYXBbJGFkZHJdOwp9CnN1YiB3c21hcmsKewogIG15ICRsYWJlbCA9IHNoaWZ0OwogIHJldHVybiBpZiBleGlzdHMgJGxhYmVsc3skbGFiZWx9LT57J2lwJ307CiAgJGxhYmVsc3skbGFiZWx9LT57J2lwJ30gPSAkaXA7CiAgdW5kZWYgJHNraXAgaWYgZGVmaW5lZCAkc2tpcCAmJiAkc2tpcC0+eyd0byd9IGVxICRsYWJlbDsKfQpzdWIgd3NqdW1wX2NvbW1vbihAKQp7CiAgbXkgJGxhYmVsID0gc2hpZnQ7CiAgaWYgKCBleGlzdHMgJGxhYmVsc3skbGFiZWx9LT57J2lwJ30gKQogIHsKICAgICRpcCA9ICRsYWJlbHN7JGxhYmVsfS0+eydpcCd9OwogIH0KICBlbHNlCiAgewogICAgJHNraXAgPSB7ICd0bycgPT4gJGxhYmVsLCAnZnJvbScgPT4gJGlwIH07CiAgfQp9CnN1YiB3c2NhbGwKewogIHVuc2hpZnQgQGNzdGFjaywgJGlwOwogIHdzanVtcF9jb21tb24oQF8pOwp9CnN1YiB3c2p1bXAKewogIHdzanVtcF9jb21tb24oQF8pOwp9CnN1YiB3c2p6ZXJvCnsKICByZXR1cm4gdW5sZXNzIDAgPT0gc2hpZnQgQHN0YWNrOwogIHdzanVtcF9jb21tb24oQF8pOwp9CnN1YiB3c2puZWcKewogIHJldHVybiB1bmxlc3MgMCA+IHNoaWZ0IEBzdGFjazsKICB3c2p1bXBfY29tbW9uKEBfKTsKfQpzdWIgd3NyZXQKewogIGRpZSAiY2FsbCBzdGFjayBpcyBlbXB0eVxuIiB1bmxlc3MgQGNzdGFjazsKICAkaXAgPSBzaGlmdCBAY3N0YWNrOwp9CnN1YiB3c2VuZAp7CiAgJGNvbnRpbnVlID0gMDsKfQpzdWIgd3NwdXRjCnsKICBteSAkdmFsID0gc2hpZnQgQHN0YWNrOwogIG15ICRjID0gY2hyICR2YWw7CiAgJGMgPX4gL1teWzpwcmludDpdXHNdLwogICAgYW5kIGRpZSAib3V0cHV0IG5vbi1wcmludGFibGUgY2hhcmFjdGVyICggJHZhbCApXG4iOwogIHByaW50ICRjOwp9CnN1YiB3c3B1dGkKewogIHByaW50IHNoaWZ0IEBzdGFjazsKfQpzdWIgZmlsbGJ1ZmZlcgp7CiAgJGlidWYgPSA8PjsKICBkaWUgImRldGVjdGVkIGVvZiBvbiBpbnB1dCBzdHJlYW1cbiIKICAgIHVubGVzcyBkZWZpbmVkICRpYnVmOwp9CnN1YiB3c2dldGMKewogIGZpbGxidWZmZXIoKSBpZiAkaWJ1ZiBlcSAnJzsKICBteSAkdmFsID0gb3JkIHN1YnN0ciAkaWJ1ZiwgMCwgMSwgJyc7CiAgbXkgJGFkZHIgPSBzaGlmdCBAc3RhY2s7CiAgc3RvcmVoZWFwKCR2YWwsICRhZGRyKTsKfQpzdWIgd3NnZXRpCnsKICBmaWxsYnVmZmVyKCkgaWYgJGlidWYgZXEgJyc7CiAgJGlidWYgPX4gL15ccyooWy1dP1xkKylccyokLwogICAgb3IgZGllICJub3QgaW50ZWdlciBkYXRhIG9uIGlucHV0IHN0cmVhbVxuIjsKICBteSAkdmFsID0gMCskMTsKICAkaWJ1ZiA9ICcnOwogIG15ICRhZGRyID0gc2hpZnQgQHN0YWNrOwogIHN0b3JlaGVhcCgkdmFsLCAkYWRkcik7Cn0KbXkgJW9wcyA9ICgKICAncHVzaCcgID0+IHsgJ3N1YicgPT4gXCZ3c3B1c2gsICAnaW1wJyA9PiAncycsICAnY29kZScgPT4gJ3MnLCAgJ2FyZycgPT4gJ2ludCcgfSwKICAnZHVwJyAgID0+IHsgJ3N1YicgPT4gXCZ3c2R1cCwgICAnaW1wJyA9PiAncycsICAnY29kZScgPT4gJ25zJywgJ2FyZycgPT4gJ3ZvaWQnLCAnc3RhY2tmcmVxJyA9PiAxIH0sCiAgJ2NvcHknICA9PiB7ICdzdWInID0+IFwmd3Njb3B5LCAgJ2ltcCcgPT4gJ3MnLCAgJ2NvZGUnID0+ICd0cycsICdhcmcnID0+ICd1aW50JyB9LAogICdzd2FwJyAgPT4geyAnc3ViJyA9PiBcJndzc3dhcCwgICdpbXAnID0+ICdzJywgICdjb2RlJyA9PiAnbnQnLCAnYXJnJyA9PiAndm9pZCcsICdzdGFja2ZyZXEnID0+IDIgfSwKICAncG9wJyAgID0+IHsgJ3N1YicgPT4gXCZ3c3BvcCwgICAnaW1wJyA9PiAncycsICAnY29kZScgPT4gJ25uJywgJ2FyZycgPT4gJ3ZvaWQnLCAnc3RhY2tmcmVxJyA9PiAxIH0sCiAgJ3NsaWRlJyA9PiB7ICdzdWInID0+IFwmd3NzbGlkZSwgJ2ltcCcgPT4gJ3MnLCAgJ2NvZGUnID0+ICd0bicsICdhcmcnID0+ICd1aW50JyB9LAogICdhZGQnICAgPT4geyAnc3ViJyA9PiBcJndzYWRkLCAgICdpbXAnID0+ICd0cycsICdjb2RlJyA9PiAnc3MnLCAnYXJnJyA9PiAndm9pZCcsICdzdGFja2ZyZXEnID0+IDIgfSwKICAnc3ViJyAgID0+IHsgJ3N1YicgPT4gXCZ3c3N1YiwgICAnaW1wJyA9PiAndHMnLCAnY29kZScgPT4gJ3N0JywgJ2FyZycgPT4gJ3ZvaWQnLCAnc3RhY2tmcmVxJyA9PiAyIH0sCiAgJ211bCcgICA9PiB7ICdzdWInID0+IFwmd3NtdWwsICAgJ2ltcCcgPT4gJ3RzJywgJ2NvZGUnID0+ICdzbicsICdhcmcnID0+ICd2b2lkJywgJ3N0YWNrZnJlcScgPT4gMiB9LAogICdkaXYnICAgPT4geyAnc3ViJyA9PiBcJndzZGl2LCAgICdpbXAnID0+ICd0cycsICdjb2RlJyA9PiAndHMnLCAnYXJnJyA9PiAndm9pZCcsICdzdGFja2ZyZXEnID0+IDIgfSwKICAnbW9kJyAgID0+IHsgJ3N1YicgPT4gXCZ3c21vZCwgICAnaW1wJyA9PiAndHMnLCAnY29kZScgPT4gJ3R0JywgJ2FyZycgPT4gJ3ZvaWQnLCAnc3RhY2tmcmVxJyA9PiAyIH0sCiAgJ3N0b3InICA9PiB7ICdzdWInID0+IFwmd3NzdG9yLCAgJ2ltcCcgPT4gJ3R0JywgJ2NvZGUnID0+ICdzJywgICdhcmcnID0+ICd2b2lkJywgJ3N0YWNrZnJlcScgPT4gMiB9LAogICdyZXRyJyAgPT4geyAnc3ViJyA9PiBcJndzcmV0ciwgICdpbXAnID0+ICd0dCcsICdjb2RlJyA9PiAndCcsICAnYXJnJyA9PiAndm9pZCcsICdzdGFja2ZyZXEnID0+IDEgfSwKICAnbWFyaycgID0+IHsgJ3N1YicgPT4gXCZ3c21hcmssICAnaW1wJyA9PiAnbicsICAnY29kZScgPT4gJ3NzJywgJ2FyZycgPT4gJ2xhYmVsJywgJ2RvbnRza2lwJyA9PiAxIH0sCiAgJ2NhbGwnICA9PiB7ICdzdWInID0+IFwmd3NjYWxsLCAgJ2ltcCcgPT4gJ24nLCAgJ2NvZGUnID0+ICdzdCcsICdhcmcnID0+ICdsYWJlbCcgfSwKICAnanVtcCcgID0+IHsgJ3N1YicgPT4gXCZ3c2p1bXAsICAnaW1wJyA9PiAnbicsICAnY29kZScgPT4gJ3NuJywgJ2FyZycgPT4gJ2xhYmVsJyB9LAogICdqemVybycgPT4geyAnc3ViJyA9PiBcJndzanplcm8sICdpbXAnID0+ICduJywgICdjb2RlJyA9PiAndHMnLCAnYXJnJyA9PiAnbGFiZWwnLCAnc3RhY2tmcmVxJyA9PiAxIH0sCiAgJ2puZWcnICA9PiB7ICdzdWInID0+IFwmd3NqbmVnLCAgJ2ltcCcgPT4gJ24nLCAgJ2NvZGUnID0+ICd0dCcsICdhcmcnID0+ICdsYWJlbCcsICdzdGFja2ZyZXEnID0+IDEgfSwKICAncmV0JyAgID0+IHsgJ3N1YicgPT4gXCZ3c3JldCwgICAnaW1wJyA9PiAnbicsICAnY29kZScgPT4gJ3RuJywgJ2FyZycgPT4gJ3ZvaWQnIH0sCiAgJ2VuZCcgICA9PiB7ICdzdWInID0+IFwmd3NlbmQsICAgJ2ltcCcgPT4gJ24nLCAgJ2NvZGUnID0+ICdubicsICdhcmcnID0+ICd2b2lkJyB9LAogICdwdXRjJyAgPT4geyAnc3ViJyA9PiBcJndzcHV0YywgICdpbXAnID0+ICd0bicsICdjb2RlJyA9PiAnc3MnLCAnYXJnJyA9PiAndm9pZCcsICdzdGFja2ZyZXEnID0+IDEgfSwKICAncHV0aScgID0+IHsgJ3N1YicgPT4gXCZ3c3B1dGksICAnaW1wJyA9PiAndG4nLCAnY29kZScgPT4gJ3N0JywgJ2FyZycgPT4gJ3ZvaWQnLCAnc3RhY2tmcmVxJyA9PiAxIH0sCiAgJ2dldGMnICA9PiB7ICdzdWInID0+IFwmd3NnZXRjLCAgJ2ltcCcgPT4gJ3RuJywgJ2NvZGUnID0+ICd0cycsICdhcmcnID0+ICd2b2lkJywgJ3N0YWNrZnJlcScgPT4gMSB9LAogICdnZXRpJyAgPT4geyAnc3ViJyA9PiBcJndzZ2V0aSwgICdpbXAnID0+ICd0bicsICdjb2RlJyA9PiAndHQnLCAnYXJnJyA9PiAndm9pZCcsICdzdGFja2ZyZXEnID0+IDEgfSwKKTsKc3ViIGFyZ2NvZGUoJCQkKQp7CiAgbXkgKCAkYXJnLCAkc2lnLCAkYXJnbGVuICkgPSBAXzsKICAkc2lnID0gJysnIHVubGVzcyBkZWZpbmVkICRzaWc7CiAgbXkgJG5vc2lnID0gJyc7CiAgaWYgKCAkYXJnICE9IDAgKQogIHsKICAgIG15IEBwYXJ0ID0gKCk7CiAgICBteSAkYmFzZSA9IDE8PDYzOwogICAgZm9yICggOyAkYXJnID49ICRiYXNlOyAkYXJnIC89ICRiYXNlICkKICAgIHsKICAgICAgIHVuc2hpZnQgQHBhcnQsIHNwcmludGYgJyUwNjNiJywgJGFyZyUkYmFzZTsKICAgIH0KICAgICRub3NpZyA9IGpvaW4gJycsICggc3ByaW50ZiAnJWInLCAkYXJnICksIEBwYXJ0OwogIH0KICBteSAkcGFkZGluZyA9IGRlZmluZWQgJGFyZ2xlbiAmJiAkYXJnbGVuID4gbGVuZ3RoICRub3NpZyA/CiAgICAgICAgICAgICAgICAnMCd4KCRhcmdsZW4tbGVuZ3RoJG5vc2lnKSA6ICcnOwogIHJldHVybiAiJHNpZyRwYWRkaW5nJG5vc2lnLiI7Cn0Kc3ViIGNvbnZlcnQoJCkKewogIGlmICggJGNvZGVsZXZlbCA9PSAyICkKICB7CiAgICAkX1swXSA9fiB0ci8rMFwtMS4gL3NzdHRuL2Q7CiAgfQogIGVsc2lmICggJGNvZGVsZXZlbCA+PSAzICkKICB7CiAgICAkX1swXSA9fiB0ci8rMHNcLTF0Lm4gLyAgIFx0XHRcdFxuXG4vZDsKICB9Cn0Kc3ViIGNvbXBpbGUoJCkKewogIG15ICggJGxpbmVubywgJGxpbmUgKSA9IEB7JF9bMF19OwogICRsaW5lID1+IC9eXHMqKFx3KykoXHMrKChbLStdKT8oXGQrKSg/OlwoKFxkKyliXCkpP3woXHcrKSkpP1xzKiQvCiAgICBvciBkaWUgImludmFsaWQgZm9ybWF0IGF0IGxpbmUgJGxpbmVub1xuIjsKICBteSAkaXN0ciA9ICQxOwogIGRpZSAiJyRpc3RyJyBpcyB1bmtub3duIGF0IGxpbmUgJGxpbmVub1xuIgogICAgaWYgISBleGlzdHMgJG9wc3skaXN0cn07CiAgbXkgJHJlZiA9ICRvcHN7JGlzdHJ9OwogIG15ICVyZXQgPSAoKTsKICBteSAkYXJnc3RyID0gJyc7CiAgbXkgJGFyZ2xlbiA9IDA7CiAgaWYgKCAkcmVmLT57J2FyZyd9IGVxICd2b2lkJyApCiAgewogICAgZGllICJubyBhcmd1bWVudHMgYWxsb3dlZCBmb3IgJyRpc3RyJyBhdCBsaW5lICRsaW5lbm9cbiIKICAgICAgaWYgZGVmaW5lZCAkMjsKICB9CiAgZWxzaWYgKCBkZWZpbmVkICQ1ICkKICB7CiAgICBteSAkYXJnID0gMCskNTsKICAgIG15ICRzaWcgPSAkNC8vJysnOwogICAgJGFyZ3N0ciA9IGFyZ2NvZGUoJGFyZywgJHNpZywgJDYpOwogICAgJGFyZ2xlbiA9IGxlbmd0aCAkYXJnc3RyOwogICAgbXkgJGlsZW49JGFyZ2xlbi0yOwogICAgJHJldHsnYXJnJ30gPSAkcmVmLT57J2FyZyd9IGVxICdsYWJlbCcgPwogICAgICAgICAgICAgICAgICAgICIkc2lnJGFyZygke2lsZW59YikiIDoKICAgICAgICAgICAgICAgICAgICAkc2lnIGVxICctJyA/IC0kYXJnIDogJGFyZzsKICAgICRyZXR7J25lZ2F0aXZlYXJnZXJyb3InfSA9IDEKICAgICAgaWYgJHJlZi0+eydhcmcnfSBlcSAndWludCcgJiYgJHNpZyBlcSAnLSc7CiAgICAkbGFiZWxzeyRyZXR7J2FyZyd9fS0+eydjb3VudCd9KysKICAgICAgaWYgJHJlZi0+eydhcmcnfSBlcSAnbGFiZWwnOwogIH0KICBlbHNlCiAgewogICAgZGllICJpbnZhbGlkIGFyZ3VtZW50IGZvciAnJGlzdHInIGF0IGxpbmUgJGxpbmVub1xuIgogICAgICB1bmxlc3MgJHJlZi0+eydhcmcnfSBlcSAnbGFiZWwnOwogICAgaWYgKCBkZWZpbmVkICQ3ICkKICAgIHsKICAgICAgJHJldHsnYXJnJ30gPSAkNzsKICAgICAgJHJldHsncmVsYWJlbCd9ID0gMTsKICAgICAgJGxhYmVsc3skcmV0eydhcmcnfX0tPnsncmVsYWJlbCd9ID0gMTsKICAgIH0KICAgIGVsc2UKICAgIHsKICAgICAgJHJldHsnYXJnJ30gPSAnJzsKICAgICAgJGFyZ3N0ciA9ICcuJzsKICAgICAgJGFyZ2xlbiA9IDE7CiAgICB9CiAgICAkbGFiZWxzeyRyZXR7J2FyZyd9fS0+eydjb3VudCd9Kys7CiAgfQogIGlmICggJGNvZGVsZXZlbCA+IDAgKQogIHsKICAgIG15ICRjb2RlID0gam9pbiAnICcsIEAkcmVme3F3KGltcCBjb2RlKX07CiAgICAkY29kZSAuPSAiICRhcmdzdHIiIGlmICRhcmdzdHIgbmUgJyc7CiAgICBjb252ZXJ0KCRjb2RlKTsKICAgICRyZXR7J2NvZGUnfSA9ICRjb2RlOwogIH0KICAkYnl0ZXMrPSRhcmdsZW4rbGVuZ3RoKCRyZWYtPnsnaW1wJ30pK2xlbmd0aCgkcmVmLT57J2NvZGUnfSk7CiAgQHJldHtxdyhzdWIgZG9udHNraXAgc3RhY2tmcmVxKX0gPSBAJHJlZntxdyhzdWIgZG9udHNraXAgc3RhY2tmcmVxKX07CiAgJHJldHsnbGluZSd9ID0gJGxpbmVubzsKICByZXR1cm4gXCVyZXQ7Cn0Kc3ViIHJlbGFiZWwoKQp7CiAgbXkgJG51bGxfdW51c2VkID0gIWV4aXN0cyAkbGFiZWxzeycnfTsKICBteSAoICRib2R5LCAkc2lnLCAkbGVuLCAkbGltICkgPSAoIDAsICcrJywgMCwgMSApOwogIG15ICggJGxjYW5kLCAkY29kZSApOwogIGZvcmVhY2ggbXkgJGxhYmVsICggc29ydCB7ICRsYWJlbHN7JGJ9LT57J2NvdW50J30gPD0+ICRsYWJlbHN7JGF9LT57J2NvdW50J30gfHwgJGEgY21wICRiIH0KICAgICAgICAgICAgICAgICAgICAgIGdyZXAgeyBleGlzdHMgJGxhYmVsc3skX30tPnsncmVsYWJlbCd9IH0ga2V5cyAlbGFiZWxzICkKICB7CiAgICBteSAkbmV3bGFiZWw7CiAgICBpZiAoICRudWxsX3VudXNlZCApCiAgICB7CiAgICAgICRuZXdsYWJlbCA9ICcnOwogICAgICAkY29kZSA9ICcuJzsKICAgICAgJG51bGxfdW51c2VkID0gMDsKICAgIH0KICAgIGVsc2UKICAgIHsKICAgICAgZm9yICggbXkgJHJldHJ5PTE7ICRyZXRyeTsgKQogICAgICB7CiAgICAgICAgJG5ld2xhYmVsPSIkc2lnJGJvZHkoJHtsZW59YikiOwogICAgICAgIGlmICggIWV4aXN0cyAkbGFiZWxzeyRuZXdsYWJlbH0gKQogICAgICAgIHsKICAgICAgICAgICRyZXRyeSA9IDA7CiAgICAgICAgICAkY29kZSA9IGFyZ2NvZGUoJGJvZHksJHNpZywkbGVuKTsKICAgICAgICB9CiAgICAgICAgaWYgKCAkc2lnIGVxICcrJyApCiAgICAgICAgewogICAgICAgICAgJHNpZyA9ICctJzsKICAgICAgICB9CiAgICAgICAgZWxzZQogICAgICAgIHsKICAgICAgICAgICRzaWcgPSAnKyc7CiAgICAgICAgICBpZiAoICsrJGJvZHkgPj0gJGxpbSApCiAgICAgICAgICB7CiAgICAgICAgICAgICRib2R5ID0gMDsKICAgICAgICAgICAgJGxlbisrOwogICAgICAgICAgICAkbGltKj0yOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgJGxhYmVsc3skbGFiZWx9LT57J3JlbGFiZWwnfSA9ICRuZXdsYWJlbDsKICAgICRsYWJlbHN7JGxhYmVsfS0+eydjb2RlJ30gPSAkY29kZTsKICAgICRieXRlcyArPSBsZW5ndGgoJGNvZGUpKiRsYWJlbHN7JGxhYmVsfS0+eydjb3VudCd9OwogIH0KICBmb3JlYWNoIG15ICRpICggQGluc3QgKQogIHsKICAgIG5leHQgdW5sZXNzIGV4aXN0cyAkaS0+eydyZWxhYmVsJ307CiAgICBteSAkY29kZSA9ICcgJyAuICRsYWJlbHN7JGktPnsnYXJnJ319LT57J2NvZGUnfTsKICAgIGNvbnZlcnQoJGNvZGUpOwogICAgJGktPnsnY29kZSd9IC49ICRjb2RlOwogIH0KfQpzdWIgcmVwb3J0KCQpCnsKICBteSAkZXJyb3IgPSBzaGlmdDsKICBteSAkc3NpemUgPSBAc3RhY2s7CiAgbXkgJGhzaXplID0gQGhlYXA7CiAgbXkgJG1zZyA9ICRlcnJvciA/ICd3aXRoIGFuIGVycm9yJyA6ICdub3JtYWxseSc7CiAgcmVsYWJlbCgpOwogIHByaW50IDw8X0VPU187Ci0tCnByb2dyYW0gZW5kZWQgJG1zZy4KIGluc3RydWN0aW9uczogJGludW0KIHN0ZXBzOiAgICAgICAgJHN0ZXAKIHRoZSBsYXN0IGlwOiAgJGlwICggbGluZSAkaW5zdFskaXAtMV0tPnsnbGluZSd9ICkKIHNyYyBieXRlczogICAgJGJ5dGVzCiBzdGFjayBzaXplOiAgICRzc2l6ZSAoZmluYWwpIC8gJHN0YWNraHdtIChoaWdoIHdhdGVyIG1hcmspCiBoZWFwIHNpemU6ICAgICRoc2l6ZQpfRU9TXwogIHByaW50ICJcbmxhYmVsIHN0YXRpc3RpY3M6XG4iOwogIGlmICggISVsYWJlbHMgKQogIHsKICAgIHByaW50ICJubyBsYWJlbCBleGlzdHNcbiIKICB9CiAgZWxzZQogIHsKICAgIGZvcmVhY2ggbXkgJGxhYmVsICggc29ydCB7ICRsYWJlbHN7JGJ9LT57J2NvdW50J30gPD0+ICRsYWJlbHN7JGF9LT57J2NvdW50J30gfHwgJGEgY21wICRiIH0ga2V5cyAlbGFiZWxzICkKICAgIHsKICAgICAgcHJpbnQgJyAnLAogICAgICAgICAgICAoICRsYWJlbCBlcSAnJyA/ICcobnVsbCknIDogJGxhYmVsICksCiAgICAgICAgICAgICggZXhpc3RzICRsYWJlbHN7JGxhYmVsfS0+eydyZWxhYmVsJ30gPwogICAgICAgICAgICAgICAgJyByZWxhYmVsZWQgdG8gJyAuICgKICAgICAgICAgICAgICAgICAgJGxhYmVsc3skbGFiZWx9LT57J3JlbGFiZWwnfSBlcSAnJyA/CiAgICAgICAgICAgICAgICAgICAgJyhudWxsKScgOiAkbGFiZWxzeyRsYWJlbH0tPnsncmVsYWJlbCd9ICkgOgogICAgICAgICAgICAgICAgJycgKSwKICAgICAgICAgICAgICc6ICcsICRsYWJlbHN7JGxhYmVsfS0+eydjb3VudCd9LCAiXG4iOwogICAgfQogIH0KICBwcmludCAiXG50aGUgZXJyb3IgaXMgc2hvd24gYmVsb3c6XG4kZXJyb3JcbiIgaWYgJGVycm9yOwogIGlmICggJGNvZGVsZXZlbCA+IDAgKQogIHsKICAgIHByaW50ICItLWNvZGUtLVxuIjsKICAgIHByaW50IGpvaW4gJGNvZGVsZXZlbDwyPyJcbiI6IiIsIG1hcCB7ICRfLT57J2NvZGUnfSB9IEBpbnN0OwogICAgcHJpbnQgIlxuLS1lbmQtLVxuIjsKICB9Cn0KCnN1YiByZWFkc3JjKCQpCnsKICBteSAkc3NyYyA9IHNoaWZ0OwogIG15ICRzZXBhcmF0ZWQgPSBkZWZpbmVkICRzc3JjOwogIG15IEBsaW5lcyA9ICgpOwogIG15ICRpZmggPSBcKkFSR1Y7CiAgaWYgKCAkc2VwYXJhdGVkICkKICB7CiAgICBvcGVuICRpZmgsICc8JywgJHNzcmMKICAgICAgb3IgZGllICJmYWlsZWQgdG8gb3BlbiBzb3VyY2UgZmlsZVxuIjsKICB9CiAgbXkgJGVtYmJlZG9wdF9lbmQgPSAwOwogIHdoaWxlICggPCRpZmg+ICkKICB7CiAgICBjaG9tcDsKICAgIGlmICggJF8gZXEgJEVORE1BUksgKQogICAgewogICAgICBkaWUgImRvbid0IHVzZSAnJEVORE1BUksnIGluIGEgc2VwYXJhdGVkIHNvdXJjZSBmaWxlXG4iCiAgICAgICAgaWYgJHNlcGFyYXRlZDsKICAgICAgbGFzdDsKICAgIH0KICAgIGlmICggISRlbWJiZWRvcHRfZW5kICYmIC9eI1wrb3B0OlxzKihcdyspKD0oXHcrKSk/LyApCiAgICB7CiAgICAgIGlmICggJDEgZXEgJ3VubGltaXRlZCcgJiYgIWRlZmluZWQgJDIgKQogICAgICB7CiAgICAgICAgJHVubGltaXRlZCA9IDE7CiAgICAgIH0KICAgICAgZWxzaWYgKCAkMSBlcSAnY29kZWxldmVsJyAmJiBkZWZpbmVkICQzICkKICAgICAgewogICAgICAgICRjb2RlbGV2ZWwgPSAwKyQzOwogICAgICB9CiAgICAgIGVsc2lmICggJDEgZXEgJ2xpbWl0JyAmJiBkZWZpbmVkICQzICkKICAgICAgewogICAgICAgICRzbGltaXQgPSAwKyQzOwogICAgICB9CiAgICAgIGVsc2UKICAgICAgewogICAgICAgIHdhcm4gImludmFsaWQgZW1iYmVkIG9wdGlvbiBhdCBsaW5lICQuXG4iOwogICAgICB9CiAgICAgIG5leHQ7CiAgICB9CiAgICBzL1xzKigjLiopPyQvLzsKICAgIG5leHQgdW5sZXNzIC9cUy87CiAgICBwdXNoIEBsaW5lcywgWyAkLiwgJF8gXTsKICAgICRlbWJiZWRvcHRfZW5kID0gMTsKICB9CiAgcmV0dXJuIEBsaW5lczsKfQoKIy0tIG1haW4KbXkgJHVzYWdlID0gIlVzYWdlOiAkMCBbLWhdIFstdXwtbCBtYXhzdGVwc10gWy1jIGNvZGUtbGV2ZWxdIHtbbWVyZ2VkLWZpbGVdIHwgLXMgc3JjZmlsZSBbaW5wdXQtZmlsZV19XG4iOwpteSAlb3B0cyA9ICgpOwpnZXRvcHRzKCdodXM6bDpjOicsIFwlb3B0cyk7CgpkaWUgJHVzYWdlIGlmIGV4aXN0cyAkb3B0c3snaCd9OwokdW5saW1pdGVkID0gZXhpc3RzICRvcHRzeyd1J307CmRpZSAkdXNhZ2UgaWYgJHVubGltaXRlZCAmJiBleGlzdHMgJG9wdHN7J2wnfTsKJHNsaW1pdCA9ICRvcHRzeydsJ30gLy8gJFNMSU1JVF9ERUZBVUxUOwokY29kZWxldmVsID0gJG9wdHN7J2MnfSAvLyAkQ0xFVkVMX0RFRkFVTFQ7CgpteSBAc3JjbGluZXMgPSByZWFkc3JjKCRvcHRzeydzJ30pOwoKZXZhbAp7CiAgd2hpbGUgKCAkY29udGludWUgKQogIHsKICAgIGRpZSAiZXhjZWVkZWQgc3RlcCBsaW1pdFxuIgogICAgICBpZiAhJHVubGltaXRlZCAmJiAkc3RlcD49JHNsaW1pdDsKICAgICRpcCsrOwogICAgbXkgJGk7CiAgICBpZiAoICRpcCA8PSBAaW5zdCApCiAgICB7CiAgICAgICRpID0gJGluc3RbJGlwLTFdOwogICAgfQogICAgZWxzZQogICAgewogICAgICBpZiAoICFAc3JjbGluZXMgKQogICAgICB7CiAgICAgICAgbXkgJHN1cDsKICAgICAgICBpZiAoIGRlZmluZWQgJHNraXAgKQogICAgICAgIHsKICAgICAgICAgICRzdXAgPSAibWFyayAnJHNraXAtPnsndG8nfSciOwogICAgICAgICAgJGlwID0gJHNraXAtPnsnZnJvbSd9OwogICAgICAgIH0KICAgICAgICBlbHNlCiAgICAgICAgewogICAgICAgICAgJHN1cCA9ICdlbmQnOwogICAgICAgICAgJGlwLS07CiAgICAgICAgfQogICAgICAgIGRpZSAidW5leHBlY3RlZCBlbmQgb2Ygc291cmNlIGJlZm9yZSB0aGUgJHN1cFxuIgogICAgICB9CiAgICAgIGV2YWwKICAgICAgewogICAgICAgICRpID0gY29tcGlsZShzaGlmdCBAc3JjbGluZXMpOwogICAgICB9OwogICAgICBpZiAoICRAICkKICAgICAgewogICAgICAgIGNob21wICRAOwogICAgICAgIGRpZSAiaW52YWxpZCBpbnN0cnVjdGlvbiAoICRAIClcbiI7CiAgICAgIH0KICAgICAgJGludW0rKzsKICAgICAgcHVzaCBAaW5zdCwgJGk7CiAgICB9CiAgICBuZXh0IGlmIGRlZmluZWQgJHNraXAgJiYgISRpLT57J2RvbnRza2lwJ307CiAgICBldmFsCiAgICB7CiAgICAgIGRpZSAibmVnYXRpdmUgYXJndW1lbnQgaXMgbm90IGFsbG93ZWRcbiIKICAgICAgICBpZiAkaS0+eyduZWdhdGl2ZWFyZ2Vycm9yJ307CiAgICAgIGRpZSAkaS0+eydzdGFja2ZyZXEnfT4xID8gInN0YWNrIHNob3J0XG4iIDogInN0YWNrIGVtcHR5XG4iCiAgICAgICAgaWYgZGVmaW5lZCAkaS0+eydzdGFja2ZyZXEnfSAmJiBAc3RhY2sgPCAkaS0+eydzdGFja2ZyZXEnfTsKICAgICAgJnskaS0+eydzdWInfX0oQCRpe3F3KGFyZyl9KTsKICAgIH07CiAgICBpZiAoICRAICkKICAgIHsKICAgICAgY2hvbXAgJEA7CiAgICAgIGRpZSAicnVudGltZSBlcnJvciAoICRAIGF0IGxpbmUgJGktPnsnbGluZSd9IClcbiI7CiAgICB9CiAgICAkc3RlcCsrOwogIH0KfTsKcmVwb3J0KCRAKTs=