<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**#@+*/
define('MATH_BIGINTEGER_MONTGOMERY', 0); define('MATH_BIGINTEGER_BARRETT', 1); define('MATH_BIGINTEGER_POWEROF2', 2); define('MATH_BIGINTEGER_CLASSIC', 3); define('MATH_BIGINTEGER_NONE', 4); /**#@-*/
/**#@+*/
define('MATH_BIGINTEGER_VALUE', 0); define('MATH_BIGINTEGER_SIGN', 1); /**#@-*/
/**#@+*/
define('MATH_BIGINTEGER_VARIABLE', 0); define('MATH_BIGINTEGER_DATA', 1); /**#@-*/
/**#@+*/
define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
define('MATH_BIGINTEGER_MODE_BCMATH', 2);
define('MATH_BIGINTEGER_MODE_GMP', 3); /**#@-*/
define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
class Math_BigInteger {
var $value;
var $is_negative = false;
var $precision = -1;
var $bitmask = false;
var $hex;
function Math_BigInteger($x = 0, $base = 10)
{
if ( !defined('MATH_BIGINTEGER_MODE') ) { switch (true) {
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP
); break;
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH
); break;
default:
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL
); }
}
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true); }
}
if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE
== MATH_BIGINTEGER_MODE_INTERNAL
) { switch (PHP_INT_SIZE) {
case 8: // use 64-bit integers if int size is 8 bytes
define('MATH_BIGINTEGER_BASE', 31); define('MATH_BIGINTEGER_BASE_FULL', 0x80000000); define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF); define('MATH_BIGINTEGER_MSB', 0x40000000); define('MATH_BIGINTEGER_MAX10', 1000000000); define('MATH_BIGINTEGER_MAX10_LEN', 9); define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62)); break;
default:
define('MATH_BIGINTEGER_BASE', 26); define('MATH_BIGINTEGER_BASE_FULL', 0x4000000); define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF); define('MATH_BIGINTEGER_MSB', 0x2000000); define('MATH_BIGINTEGER_MAX10', 10000000); define('MATH_BIGINTEGER_MAX10_LEN', 7); define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52)); }
}
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$this->value = $x;
return;
}
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$this->value = '0';
break;
default:
}
if (empty($x) && (abs($base) != 256 || $x !== '0')) { return;
}
switch ($base) {
case -256:
$x = ~$x;
$this->is_negative = true;
}
case 256:
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$sign = $this->is_negative ? '-' : '';
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$len = (strlen($x) + 3) & 0xFFFFFFFC;
for ($i = 0; $i < $len; $i+= 4) {
$this->value = bcmul($this->value, '4294967296', 0); $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0); }
if ($this->is_negative) {
$this->value = '-' . $this->value;
}
break;
default:
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
}
}
if ($this->is_negative) {
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
$this->is_negative = false;
}
$temp = $this->add(new Math_BigInteger('-1'));
$this->value = $temp->value;
}
break;
case 16:
case -16:
if ($base > 0 && $x[0] == '-') {
$this->is_negative = true;
}
$is_negative = false;
if ($base < 0 && hexdec($x[0]) >= 8) { $this->is_negative = $is_negative = true;
}
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
$this->is_negative = false;
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$x = ( strlen($x) & 1 ) ?
'0' . $x : $x; $temp = new Math_BigInteger
(pack('H*', $x), 256); $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
$this->is_negative = false;
break;
default:
$x = ( strlen($x) & 1 ) ?
'0' . $x : $x; $temp = new Math_BigInteger
(pack('H*', $x), 256); $this->value = $temp->value;
}
if ($is_negative) {
$temp = $this->add(new Math_BigInteger('-1'));
$this->value = $temp->value;
}
break;
case 10:
case -10:
$x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$this->value = $x === '-' ? '0' : (string) $x;
break;
default:
$temp = new Math_BigInteger();
$multiplier = new Math_BigInteger();
$multiplier->value = array(MATH_BIGINTEGER_MAX10
);
if ($x[0] == '-') {
$this->is_negative = true;
}
$x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN
- 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN
, 0, STR_PAD_LEFT
);
$temp = $temp->multiply($multiplier);
$temp = $temp->add(new Math_BigInteger
($this->_int2bytes
(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN
)), 256)); $x = substr($x, MATH_BIGINTEGER_MAX10_LEN
); }
$this->value = $temp->value;
}
break;
case 2:
case -2:
if ($base > 0 && $x[0] == '-') {
$this->is_negative = true;
}
$str = '0x';
}
if ($this->is_negative) {
$str = '-' . $str;
}
$temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
$this->value = $temp->value;
$this->is_negative = $temp->is_negative;
break;
default:
// base not supported, so we'll let $this == 0
}
}
function toBytes($twos_compliment = false) {
if ($twos_compliment) {
$comparison = $this->compare(new Math_BigInteger());
if ($comparison == 0) {
return $this->precision > 0 ?
str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; }
$temp = $comparison < 0 ?
$this->add(new Math_BigInteger
(1)) : $this->copy(); $bytes = $temp->toBytes();
}
if (ord($bytes[0]) & 0x80) { $bytes = chr(0) . $bytes; }
return $comparison < 0 ? ~$bytes : $bytes;
}
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
return $this->precision > 0 ?
str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; }
$temp = ( strlen($temp) & 1 ) ?
'0' . $temp : $temp; $temp = pack('H*', $temp);
return $this->precision > 0 ?
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT
), -($this->precision >> 3)) : case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value === '0') {
return $this->precision > 0 ?
str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; }
$value = '';
$current = $this->value;
if ($current[0] == '-') {
$current = substr($current, 1); }
while (bccomp($current, '0', 0) > 0) { $temp = bcmod($current, '16777216'); $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; $current = bcdiv($current, '16777216', 0); }
return $this->precision > 0 ?
substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT
), -($this->precision >> 3)) : }
if (!count($this->value)) { return $this->precision > 0 ?
str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; }
$result = $this->_int2bytes
($this->value[count($this->value) - 1]);
for ($i = count($temp->value) - 2; $i >= 0; --$i) { $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
$result = $result | str_pad($temp->_int2bytes
($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT
); }
return $this->precision > 0 ?
str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT
) : $result;
}
function toHex($twos_compliment = false) {
return bin2hex($this->toBytes($twos_compliment)); }
function toBits($twos_compliment = false) {
$hex = $this->toHex($twos_compliment);
$bits = '';
for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) { }
if ($start) {
}
$result = $this->precision > 0 ?
substr($bits, -$this->precision) : ltrim($bits, '0');
if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
return '0' . $result;
}
return $result;
}
function toString() {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value === '0') {
return '0';
}
return ltrim($this->value, '0'); }
if (!count($this->value)) { return '0';
}
$temp->is_negative = false;
$divisor = new Math_BigInteger();
$divisor->value = array(MATH_BIGINTEGER_MAX10
); $result = '';
while (count($temp->value)) { list($temp, $mod) = $temp->divide($divisor); $result = str_pad(isset($mod->value[0]) ?
$mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN
, '0', STR_PAD_LEFT
) . $result; }
$result = ltrim($result, '0'); $result = '0';
}
if ($this->is_negative) {
$result = '-' . $result;
}
return $result;
}
$temp = new Math_BigInteger();
$temp->value = $this->value;
$temp->is_negative = $this->is_negative;
$temp->precision = $this->precision;
$temp->bitmask = $this->bitmask;
return $temp;
}
function __toString() {
return $this->toString();
}
function __clone() {
}
function __sleep() {
$this->hex = $this->toHex(true);
if ($this->precision > 0) {
$vars[] = 'precision';
}
return $vars;
}
function __wakeup() {
$temp = new Math_BigInteger($this->hex, -16);
$this->value = $temp->value;
$this->is_negative = $temp->is_negative;
if ($this->precision > 0) {
$this->setPrecision($this->precision);
}
}
function add($y) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_add($this->value, $y->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$temp = new Math_BigInteger();
$temp->value = bcadd($this->value, $y->value, 0);
return $this->_normalize($temp);
}
$temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
$result = new Math_BigInteger();
$result->value = $temp[MATH_BIGINTEGER_VALUE];
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
return $this->_normalize($result);
}
function _add($x_value, $x_negative, $y_value, $y_negative) {
$x_size = count($x_value); $y_size = count($y_value);
if ($x_size == 0) {
MATH_BIGINTEGER_VALUE => $y_value,
MATH_BIGINTEGER_SIGN => $y_negative
);
} else if ($y_size == 0) {
MATH_BIGINTEGER_VALUE => $x_value,
MATH_BIGINTEGER_SIGN => $x_negative
);
}
if ( $x_negative != $y_negative ) {
if ( $x_value == $y_value ) {
MATH_BIGINTEGER_VALUE
=> array(), MATH_BIGINTEGER_SIGN => false
);
}
$temp = $this->_subtract($x_value, false, $y_value, false);
$temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? $x_negative : $y_negative;
return $temp;
}
if ($x_size < $y_size) {
$size = $x_size;
$value = $y_value;
} else {
$size = $y_size;
$value = $x_value;
}
$value[] = 0;
$carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2;
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
$value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
$value[$j] = $temp;
}
if ($j == $size) {
$sum = $x_value[$i] + $y_value[$i] + $carry;
$carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
$value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
++$i;
}
if ($carry) {
for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
$value[$i] = 0;
}
++$value[$i];
}
MATH_BIGINTEGER_VALUE => $this->_trim($value),
MATH_BIGINTEGER_SIGN => $x_negative
);
}
function subtract($y) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_sub($this->value, $y->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$temp = new Math_BigInteger();
$temp->value = bcsub($this->value, $y->value, 0);
return $this->_normalize($temp);
}
$temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
$result = new Math_BigInteger();
$result->value = $temp[MATH_BIGINTEGER_VALUE];
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
return $this->_normalize($result);
}
function _subtract($x_value, $x_negative, $y_value, $y_negative) {
$x_size = count($x_value); $y_size = count($y_value);
if ($x_size == 0) {
MATH_BIGINTEGER_VALUE => $y_value,
MATH_BIGINTEGER_SIGN => !$y_negative
);
} else if ($y_size == 0) {
MATH_BIGINTEGER_VALUE => $x_value,
MATH_BIGINTEGER_SIGN => $x_negative
);
}
if ( $x_negative != $y_negative ) {
$temp = $this->_add($x_value, false, $y_value, false);
$temp[MATH_BIGINTEGER_SIGN] = $x_negative;
return $temp;
}
$diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
if ( !$diff ) {
MATH_BIGINTEGER_VALUE
=> array(), MATH_BIGINTEGER_SIGN => false
);
}
if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;
$x_negative = !$x_negative;
$x_size = count($x_value); $y_size = count($y_value); }
$carry = 0;
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
$carry = $sum < 0;
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
$x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
$x_value[$j] = $temp;
}
if ($j == $y_size) {
$sum = $x_value[$i] - $y_value[$i] - $carry;
$carry = $sum < 0;
$x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
++$i;
}
if ($carry) {
for (; !$x_value[$i]; ++$i) {
$x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
}
--$x_value[$i];
}
MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
MATH_BIGINTEGER_SIGN => $x_negative
);
}
function multiply($x) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_mul($this->value, $x->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$temp = new Math_BigInteger();
$temp->value = bcmul($this->value, $x->value, 0);
return $this->_normalize($temp);
}
$temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
$product = new Math_BigInteger();
$product->value = $temp[MATH_BIGINTEGER_VALUE];
$product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
return $this->_normalize($product);
}
function _multiply($x_value, $x_negative, $y_value, $y_negative) {
$x_length = count($x_value); $y_length = count($y_value);
if ( !$x_length || !$y_length ) {
MATH_BIGINTEGER_VALUE
=> array(), MATH_BIGINTEGER_SIGN => false
);
}
MATH_BIGINTEGER_VALUE
=> min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
$this->_trim($this->_regularMultiply($x_value, $y_value)) :
$this->_trim($this->_karatsuba($x_value, $y_value)),
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
);
}
function _regularMultiply($x_value, $y_value) {
$x_length = count($x_value); $y_length = count($y_value);
if ( !$x_length || !$y_length ) {
}
if ( $x_length < $y_length ) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;
$x_length = count($x_value); $y_length = count($y_value); }
$product_value = $this->_array_repeat(0, $x_length + $y_length);
$carry = 0;
for ($j = 0; $j < $x_length; ++$j) {
$temp = $x_value[$j] * $y_value[0] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
$product_value[$j] = $carry;
for ($i = 1; $i < $y_length; ++$i) {
$carry = 0;
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
$product_value[$k] = $carry;
}
return $product_value;
}
function _karatsuba($x_value, $y_value) {
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
return $this->_regularMultiply($x_value, $y_value);
}
$z2 = $this->_karatsuba($x1, $y1);
$z0 = $this->_karatsuba($x0, $y0);
$z1 = $this->_add($x1, false, $x0, false);
$temp = $this->_add($y1, false, $y0, false);
$z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
$temp = $this->_add($z2, false, $z0, false);
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
$xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
$xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
return $xy[MATH_BIGINTEGER_VALUE];
}
function _square($x = false) {
return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
$this->_trim($this->_baseSquare($x)) :
$this->_trim($this->_karatsubaSquare($x));
}
function _baseSquare($value) {
}
$square_value = $this->_array_repeat
(0, 2 * count($value));
for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { $i2 = $i << 1;
$temp = $square_value[$i2] + $value[$i] * $value[$i];
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
// note how we start from $i+1 instead of 0 as we do in multiplication.
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
// the following line can yield values larger 2**15. at this point, PHP should switch
// over to floats.
$square_value[$i + $max_index + 1] = $carry;
}
return $square_value;
}
function _karatsubaSquare($value) {
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
return $this->_baseSquare($value);
}
$z2 = $this->_karatsubaSquare($x1);
$z0 = $this->_karatsubaSquare($x0);
$z1 = $this->_add($x1, false, $x0, false);
$z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
$temp = $this->_add($z2, false, $z0, false);
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
$xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
$xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
return $xx[MATH_BIGINTEGER_VALUE];
}
function divide($y) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$quotient = new Math_BigInteger();
$remainder = new Math_BigInteger();
list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
}
return array($this->_normalize
($quotient), $this->_normalize
($remainder)); case MATH_BIGINTEGER_MODE_BCMATH:
$quotient = new Math_BigInteger();
$remainder = new Math_BigInteger();
$quotient->value = bcdiv($this->value, $y->value, 0); $remainder->value = bcmod($this->value, $y->value);
if ($remainder->value[0] == '-') {
$remainder->value = bcadd($remainder->value, $y->value[0] == '-' ?
substr($y->value, 1) : $y->value, 0); }
return array($this->_normalize
($quotient), $this->_normalize
($remainder)); }
if (count($y->value) == 1) { list($q, $r) = $this->_divide_digit
($this->value, $y->value[0]); $quotient = new Math_BigInteger();
$remainder = new Math_BigInteger();
$quotient->value = $q;
$remainder->value = array($r); $quotient->is_negative = $this->is_negative != $y->is_negative;
return array($this->_normalize
($quotient), $this->_normalize
($remainder)); }
static $zero;
$zero = new Math_BigInteger();
}
$x_sign = $x->is_negative;
$y_sign = $y->is_negative;
$x->is_negative = $y->is_negative = false;
$diff = $x->compare($y);
if ( !$diff ) {
$temp = new Math_BigInteger();
$temp->is_negative = $x_sign != $y_sign;
return array($this->_normalize
($temp), $this->_normalize
(new Math_BigInteger
())); }
if ( $diff < 0 ) {
// if $x is negative, "add" $y.
if ( $x_sign ) {
$x = $y->subtract($x);
}
return array($this->_normalize
(new Math_BigInteger
()), $this->_normalize
($x)); }
// normalize $x and $y as described in HAC 14.23 / 14.24
$msb = $y->value[count($y->value) - 1]; for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
$msb <<= 1;
}
$x->_lshift($shift);
$y->_lshift($shift);
$y_value = &$y->value;
$x_max = count($x->value) - 1; $y_max = count($y->value) - 1;
$quotient = new Math_BigInteger();
$quotient_value = &$quotient->value;
$quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
static $temp, $lhs, $rhs;
$temp = new Math_BigInteger();
$lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
}
$temp_value = &$temp->value;
$rhs_value = &$rhs->value;
// $temp = $y << ($x_max - $y_max-1) in base 2**26
$temp_value = array_merge($this->_array_repeat
(0, $x_max - $y_max), $y_value);
while ( $x->compare($temp) >= 0 ) {
// calculate the "common residue"
++$quotient_value[$x_max - $y_max];
$x = $x->subtract($temp);
$x_max = count($x->value) - 1; }
for ($i = $x_max; $i >= $y_max + 1; --$i) {
$x_value = &$x->value;
isset($x_value[$i]) ?
$x_value[$i] : 0, isset($x_value[$i - 1]) ?
$x_value[$i - 1] : 0, isset($x_value[$i - 2]) ?
$x_value[$i - 2] : 0 );
$y_value[$y_max],
( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
);
$q_index = $i - $y_max - 1;
if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
} else {
$quotient_value[$q_index] = (int) (
($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1])
/
$y_window[0]
);
}
$temp_value = array($y_window[1], $y_window[0]);
$lhs->value = array($quotient_value[$q_index]); $lhs = $lhs->multiply($temp);
$rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
while ( $lhs->compare($rhs) > 0 ) {
--$quotient_value[$q_index];
$lhs->value = array($quotient_value[$q_index]); $lhs = $lhs->multiply($temp);
}
$adjust = $this->_array_repeat(0, $q_index);
$temp_value = array($quotient_value[$q_index]); $temp = $temp->multiply($y);
$temp_value = &$temp->value;
$x = $x->subtract($temp);
if ($x->compare($zero) < 0) {
$x = $x->add($temp);
--$quotient_value[$q_index];
}
$x_max = count($x_value) - 1; }
$x->_rshift($shift);
$quotient->is_negative = $x_sign != $y_sign;
if ( $x_sign ) {
$y->_rshift($shift);
$x = $y->subtract($x);
}
return array($this->_normalize
($quotient), $this->_normalize
($x)); }
function _divide_digit($dividend, $divisor) {
$carry = 0;
for ($i = count($dividend) - 1; $i >= 0; --$i) { $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
$result[$i] = (int) ($temp / $divisor);
$carry = (int) ($temp - $divisor * $result[$i]);
}
return array($result, $carry); }
function modPow($e, $n) {
$n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ?
$this->bitmask : $n->abs();
if ($e->compare(new Math_BigInteger()) < 0) {
$temp = $this->modInverse($n);
if ($temp === false) {
return false;
}
return $this->_normalize($temp->modPow($e, $n));
}
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
$temp = new Math_BigInteger();
$temp->value = gmp_powm($this->value, $e->value, $n->value);
return $this->_normalize($temp);
}
if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
list(, $temp) = $this->divide($n); return $temp->modPow($e, $n);
}
if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { 'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true)
);
'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length
(strlen($components['modulus'])), $components['modulus']), 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length
(strlen($components['publicExponent'])), $components['publicExponent']) );
$RSAPublicKey = pack('Ca*a*a*', 48, $this->_encodeASN1Length
(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent']
);
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(3) . $this->_encodeASN1Length
(strlen($RSAPublicKey)) . $RSAPublicKey;
$encapsulated = pack('Ca*a*', 48, $this->_encodeASN1Length
(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey );
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
'-----END PUBLIC KEY-----';
$plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT
);
return new Math_BigInteger($result, 256);
}
}
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
$temp = new Math_BigInteger();
$temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
return $this->_normalize($temp);
}
if ( empty($e->value) ) { $temp = new Math_BigInteger();
return $this->_normalize($temp);
}
if ( $e->value == array(1) ) { list(, $temp) = $this->divide($n); return $this->_normalize($temp);
}
if ( $e->value == array(2) ) { $temp = new Math_BigInteger();
$temp->value = $this->_square($this->value);
list(, $temp) = $temp->divide($n); return $this->_normalize($temp);
}
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
if ( $n->value[0] & 1 ) {
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
}
for ($i = 0; $i < count($n->value); ++$i) { if ( $n->value[$i] ) {
$temp = decbin($n->value[$i]); $j+= 26 * $i;
break;
}
}
$mod1->_rshift($j);
$mod2 = new Math_BigInteger();
$mod2->_lshift($j);
$part1 = ( $mod1->value != array(1) ) ?
$this->_slidingWindow
($e, $mod1, MATH_BIGINTEGER_MONTGOMERY
) : new Math_BigInteger
(); $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
$y1 = $mod2->modInverse($mod1);
$y2 = $mod1->modInverse($mod2);
$result = $part1->multiply($mod2);
$result = $result->multiply($y1);
$temp = $part2->multiply($mod1);
$temp = $temp->multiply($y2);
$result = $result->add($temp);
list(, $result) = $result->divide($n);
return $this->_normalize($result);
}
function powMod($e, $n) {
return $this->modPow($e, $n);
}
function _slidingWindow($e, $n, $mode) {
static
$window_ranges = array(7, 25, 81, 241, 673, 1793);
$e_value = $e->value;
$e_length = count($e_value) - 1; $e_bits = decbin($e_value[$e_length]); for ($i = $e_length - 1; $i >= 0; --$i) {
$e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE
, '0', STR_PAD_LEFT
); }
for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
$n_value = $n->value;
$powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
$powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
$temp = 1 << ($window_size - 1);
for ($i = 1; $i < $temp; ++$i) {
$i2 = $i << 1;
$powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
}
$result = $this->_prepareReduce($result, $n_value, $mode);
for ($i = 0; $i < $e_length; ) {
if ( !$e_bits[$i] ) {
$result = $this->_squareReduce($result, $n_value, $mode);
++$i;
} else {
for ($j = $window_size - 1; $j > 0; --$j) {
if ( !empty($e_bits[$i + $j]) ) { break;
}
}
for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
$result = $this->_squareReduce($result, $n_value, $mode);
}
$result = $this->_multiplyReduce
($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
$i+=$j + 1;
}
}
$temp = new Math_BigInteger();
$temp->value = $this->_reduce($result, $n_value, $mode);
return $temp;
}
function _reduce($x, $n, $mode) {
switch ($mode) {
case MATH_BIGINTEGER_MONTGOMERY:
return $this->_montgomery($x, $n);
case MATH_BIGINTEGER_BARRETT:
return $this->_barrett($x, $n);
case MATH_BIGINTEGER_POWEROF2:
$lhs = new Math_BigInteger();
$lhs->value = $x;
$rhs = new Math_BigInteger();
$rhs->value = $n;
return $x->_mod2($n);
case MATH_BIGINTEGER_CLASSIC:
$lhs = new Math_BigInteger();
$lhs->value = $x;
$rhs = new Math_BigInteger();
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs); return $temp->value;
case MATH_BIGINTEGER_NONE:
return $x;
default:
// an invalid $mode was provided
}
}
function _prepareReduce($x, $n, $mode) {
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
return $this->_prepMontgomery($x, $n);
}
return $this->_reduce($x, $n, $mode);
}
function _multiplyReduce($x, $y, $n, $mode) {
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
return $this->_montgomeryMultiply($x, $y, $n);
}
$temp = $this->_multiply($x, false, $y, false);
return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
}
function _squareReduce($x, $n, $mode) {
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
return $this->_montgomeryMultiply($x, $x, $n);
}
return $this->_reduce($this->_square($x), $n, $mode);
}
function _mod2($n) {
$temp = new Math_BigInteger();
return $this->bitwise_and($n->subtract($temp));
}
function _barrett($n, $m) {
MATH_BIGINTEGER_VARIABLE
=> array(), MATH_BIGINTEGER_DATA
=> array() );
if (count($n) > 2 * $m_length) { $lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
$lhs->value = $n;
$rhs->value = $m;
list(, $temp) = $lhs->divide($rhs); return $temp->value;
}
if ($m_length < 5) {
return $this->_regularBarrett($n, $m);
}
if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE
])) === false ) { $key = count($cache[MATH_BIGINTEGER_VARIABLE
]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
$lhs = new Math_BigInteger();
$lhs_value = &$lhs->value;
$lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
$lhs_value[] = 1;
$rhs = new Math_BigInteger();
$rhs->value = $m;
list($u, $m1) = $lhs->divide($rhs); $u = $u->value;
$m1 = $m1->value;
$cache[MATH_BIGINTEGER_DATA
][] = array( 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
'm1'=> $m1 // m.length
);
} else {
extract($cache[MATH_BIGINTEGER_DATA
][$key]); }
$cutoff = $m_length + ($m_length >> 1);
$lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1) $lsd = $this->_trim($lsd);
$temp = $this->_multiply($msd, false, $m1, false);
$n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
if ($m_length & 1) {
return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
}
$temp = array_slice($n[MATH_BIGINTEGER_VALUE
], $m_length - 1); $temp = $this->_multiply($temp, false, $u, false);
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE
], ($m_length >> 1) + 1); $temp = $this->_multiply($temp, false, $m, false);
$result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
}
return $result[MATH_BIGINTEGER_VALUE];
}
function _regularBarrett($x, $n) {
MATH_BIGINTEGER_VARIABLE
=> array(), MATH_BIGINTEGER_DATA
=> array() );
if (count($x) > 2 * $n_length) { $lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
$lhs->value = $x;
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs); return $temp->value;
}
if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE
])) === false ) { $key = count($cache[MATH_BIGINTEGER_VARIABLE
]); $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
$lhs = new Math_BigInteger();
$lhs_value = &$lhs->value;
$lhs_value = $this->_array_repeat(0, 2 * $n_length);
$lhs_value[] = 1;
$rhs = new Math_BigInteger();
$rhs->value = $n;
list($temp, ) = $lhs->divide($rhs); $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
}
$temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE
], $n_length + 1);
$temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
$corrector_value = $this->_array_repeat(0, $n_length + 1);
$corrector_value[] = 1;
$result = $this->_add($result, false, $corrector_value, false);
$result = $result[MATH_BIGINTEGER_VALUE];
}
$result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
}
return $result[MATH_BIGINTEGER_VALUE];
}
function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) {
$x_length = count($x_value); $y_length = count($y_value);
if ( !$x_length || !$y_length ) { // a 0 is being multiplied
MATH_BIGINTEGER_VALUE
=> array(), MATH_BIGINTEGER_SIGN => false
);
}
if ( $x_length < $y_length ) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;
$x_length = count($x_value); $y_length = count($y_value); }
$product_value = $this->_array_repeat(0, $x_length + $y_length);
$carry = 0;
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
if ($j < $stop) {
$product_value[$j] = $carry;
}
for ($i = 1; $i < $y_length; ++$i) {
$carry = 0;
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
if ($k < $stop) {
$product_value[$k] = $carry;
}
}
MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
);
}
function _montgomery($x, $n) {
MATH_BIGINTEGER_VARIABLE
=> array(), MATH_BIGINTEGER_DATA
=> array() );
if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE
])) === false ) { $key = count($cache[MATH_BIGINTEGER_VARIABLE
]); $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
$cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
}
$result = array(MATH_BIGINTEGER_VALUE
=> $x);
for ($i = 0; $i < $k; ++$i) {
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
$temp = $this->_regularMultiply
(array($temp), $n); $temp = array_merge($this->_array_repeat
(0, $i), $temp); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
}
$result[MATH_BIGINTEGER_VALUE
] = array_slice($result[MATH_BIGINTEGER_VALUE
], $k);
if ($this->_compare($result, false, $n, false) >= 0) {
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
}
return $result[MATH_BIGINTEGER_VALUE];
}
function _montgomeryMultiply($x, $y, $m) {
$temp = $this->_multiply($x, false, $y, false);
return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
MATH_BIGINTEGER_VARIABLE
=> array(), MATH_BIGINTEGER_DATA
=> array() );
if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE
])) === false ) { $key = count($cache[MATH_BIGINTEGER_VARIABLE
]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
$cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
}
$a = array(MATH_BIGINTEGER_VALUE
=> $this->_array_repeat
(0, $n + 1)); for ($i = 0; $i < $n; ++$i) {
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
$temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
$temp = $this->_add
($this->_regularMultiply
(array($x[$i]), $y), false, $this->_regularMultiply
(array($temp), $m), false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
$a[MATH_BIGINTEGER_VALUE
] = array_slice($a[MATH_BIGINTEGER_VALUE
], 1); }
if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
$a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
}
return $a[MATH_BIGINTEGER_VALUE];
}
function _prepMontgomery($x, $n) {
$lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs); return $temp->value;
}
function _modInverse67108864($x) // 2**26 == 67,108,864
{
$x = -$x[0];
$result = $x & 0x3; // x**-1 mod 2**2
$result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
$result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
$result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
$result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL
)), MATH_BIGINTEGER_BASE_FULL
); // x**-1 mod 2**26 return $result & MATH_BIGINTEGER_MAX_DIGIT;
}
function modInverse($n) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_invert($this->value, $n->value);
return ( $temp->value === false ) ? false : $this->_normalize($temp);
}
static $zero, $one;
$zero = new Math_BigInteger();
$one = new Math_BigInteger(1);
}
// $x mod -$n == $x mod $n.
if ($this->compare($zero) < 0) {
$temp = $temp->modInverse($n);
return $this->_normalize($n->subtract($temp));
}
if (!$gcd->equals($one)) {
return false;
}
$x = $x->compare($zero) < 0 ? $x->add($n) : $x;
return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
}
function extendedGCD($n) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
'gcd' => $this->_normalize(new Math_BigInteger($g)),
'x' => $this->_normalize(new Math_BigInteger($s)),
'y' => $this->_normalize(new Math_BigInteger($t))
);
case MATH_BIGINTEGER_MODE_BCMATH:
$u = $this->value;
$v = $n->value;
$a = '1';
$b = '0';
$c = '0';
$d = '1';
while (bccomp($v, '0', 0) != 0) {
$temp = $u;
$u = $v;
$temp = $a;
$a = $c;
$temp = $b;
$b = $d;
}
'gcd' => $this->_normalize(new Math_BigInteger($u)),
'x' => $this->_normalize(new Math_BigInteger($a)),
'y' => $this->_normalize(new Math_BigInteger($b))
);
}
$g = new Math_BigInteger();
while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
$x->_rshift(1);
$y->_rshift(1);
$g->_lshift(1);
}
$a = new Math_BigInteger();
$b = new Math_BigInteger();
$c = new Math_BigInteger();
$d = new Math_BigInteger();
$a->value = $d->value = $g->value = array(1); $b->value = $c->value = array();
while ( !empty($u->value) ) { while ( !($u->value[0] & 1) ) {
$u->_rshift(1);
if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) { $a = $a->add($y);
$b = $b->subtract($x);
}
$a->_rshift(1);
$b->_rshift(1);
}
while ( !($v->value[0] & 1) ) {
$v->_rshift(1);
if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) { $c = $c->add($y);
$d = $d->subtract($x);
}
$c->_rshift(1);
$d->_rshift(1);
}
if ($u->compare($v) >= 0) {
$u = $u->subtract($v);
$a = $a->subtract($c);
$b = $b->subtract($d);
} else {
$v = $v->subtract($u);
$c = $c->subtract($a);
$d = $d->subtract($b);
}
}
'gcd' => $this->_normalize($g->multiply($v)),
'x' => $this->_normalize($c),
'y' => $this->_normalize($d)
);
}
function gcd($n) {
return $gcd;
}
$temp = new Math_BigInteger();
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
$temp->value = gmp_abs($this->value); break;
case MATH_BIGINTEGER_MODE_BCMATH:
$temp->value = (bccomp($this->value, '0', 0) < 0) ?
substr($this->value, 1) : $this->value; break;
default:
$temp->value = $this->value;
}
return $temp;
}
function compare($y) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
return gmp_cmp($this->value, $y->value); case MATH_BIGINTEGER_MODE_BCMATH:
return bccomp($this->value, $y->value, 0); }
return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
}
function _compare($x_value, $x_negative, $y_value, $y_negative) {
if ( $x_negative != $y_negative ) {
return ( !$x_negative && $y_negative ) ? 1 : -1;
}
$result = $x_negative ? -1 : 1;
return ( count($x_value) > count($y_value) ) ?
$result : -$result; }
for ($i = count($x_value) - 1; $i >= 0; --$i) { if ($x_value[$i] != $y_value[$i]) {
return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
}
}
return 0;
}
function equals($x) {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
return gmp_cmp($this->value, $x->value) == 0; default:
return $this->value === $x->value && $this->is_negative == $x->is_negative;
}
}
function setPrecision($bits) {
$this->precision = $bits;
if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
$this->bitmask = new Math_BigInteger
(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); } else {
$this->bitmask = new Math_BigInteger
(bcpow('2', $bits, 0)); }
$temp = $this->_normalize($this);
$this->value = $temp->value;
}
function bitwise_rightShift($shift) {
$temp = new Math_BigInteger();
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
static $two;
}
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
break;
default:
$temp->value = $this->value;
$temp->_rshift($shift);
}
return $this->_normalize($temp);
}
function bitwise_leftShift($shift) {
$temp = new Math_BigInteger();
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
static $two;
}
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
break;
default:
$temp->value = $this->value;
$temp->_lshift($shift);
}
return $this->_normalize($temp);
}
function bitwise_leftRotate($shift) {
$bits = $this->toBytes();
if ($this->precision > 0) {
$precision = $this->precision;
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
$mask = $this->bitmask->subtract(new Math_BigInteger(1));
$mask = $mask->toBytes();
} else {
$mask = $this->bitmask->toBytes();
}
} else {
for ($i = 0; $temp >> $i; ++$i);
$precision = 8 * strlen($bits) - 8 + $i; $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); }
if ($shift < 0) {
$shift+= $precision;
}
$shift%= $precision;
if (!$shift) {
}
$left = $this->bitwise_leftShift($shift);
$left = $left->bitwise_and(new Math_BigInteger($mask, 256));
$right = $this->bitwise_rightShift($precision - $shift);
$result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
return $this->_normalize($result);
}
function bitwise_rightRotate($shift) {
return $this->bitwise_leftRotate(-$shift);
}
function _make_odd() {
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
break;
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value[strlen($this->value) - 1] % 2 == 0) { $this->value = bcadd($this->value, '1'); }
break;
default:
$this->value[0] |= 1;
}
}
function _lshift($shift) {
if ( $shift == 0 ) {
return;
}
$num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
$shift %= MATH_BIGINTEGER_BASE;
$shift = 1 << $shift;
$carry = 0;
for ($i = 0; $i < count($this->value); ++$i) { $temp = $this->value[$i] * $shift + $carry;
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
$this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
}
if ( $carry ) {
$this->value[] = $carry;
}
while ($num_digits--) {
}
}
function _rshift($shift) {
if ($shift == 0) {
return;
}
$num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
$shift %= MATH_BIGINTEGER_BASE;
$carry_shift = MATH_BIGINTEGER_BASE - $shift;
$carry_mask = (1 << $shift) - 1;
if ( $num_digits ) {
}
$carry = 0;
for ($i = count($this->value) - 1; $i >= 0; --$i) { $temp = $this->value[$i] >> $shift | $carry;
$carry = ($this->value[$i] & $carry_mask) << $carry_shift;
$this->value[$i] = $temp;
}
$this->value = $this->_trim($this->value);
}
function _normalize($result) {
$result->precision = $this->precision;
$result->bitmask = $this->bitmask;
switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP:
if (!empty($result->bitmask->value)) { $result->value = gmp_and($result->value, $result->bitmask->value); }
return $result;
case MATH_BIGINTEGER_MODE_BCMATH:
if (!empty($result->bitmask->value)) { $result->value = bcmod($result->value, $result->bitmask->value); }
return $result;
}
$value = &$result->value;
return $result;
}
$value = $this->_trim($value);
if (!empty($result->bitmask->value)) {
for ($i = 0; $i < $length; ++$i) {
$value[$i] = $value[$i] & $this->bitmask->value[$i];
}
}
return $result;
}
function _trim($value) {
for ($i = count($value) - 1; $i >= 0; --$i) { if ( $value[$i] ) {
break;
}
}
return $value;
}
function _array_repeat($input, $multiplier) {
}
function _base256_lshift(&$x, $shift) {
if ($shift == 0) {
return;
}
$num_bytes = $shift >> 3; // eg. floor($shift/8)
$shift &= 7; // eg. $shift % 8
$carry = 0;
for ($i = strlen($x) - 1; $i >= 0; --$i) { $temp = ord($x[$i]) << $shift | $carry; $carry = $temp >> 8;
}
$carry = ($carry != 0) ?
chr($carry) : ''; }
function _base256_rshift(&$x, $shift) {
if ($shift == 0) {
return '';
}
$num_bytes = $shift >> 3; // eg. floor($shift/8)
$shift &= 7; // eg. $shift % 8
$remainder = '';
if ($num_bytes) {
$start = $num_bytes > strlen($x) ?
-strlen($x) : -$num_bytes; $remainder = substr($x, $start); $x = substr($x, 0, -$num_bytes); }
$carry = 0;
$carry_shift = 8 - $shift;
for ($i = 0; $i < strlen($x); ++$i) { $temp = (ord($x[$i]) >> $shift) | $carry; $carry = (ord($x[$i]) << $carry_shift) & 0xFF; }
$remainder = chr($carry >> $carry_shift) . $remainder;
}
function _int2bytes($x) {
}
function _bytes2int($x) {
return $temp['int'];
}
function _encodeASN1Length($length) {
if ($length <= 0x7F) {
}
}
}
function toHex($n) {
$zero = new Math_BigInteger(0);
if ($n->compare($zero) == 0) return "0";
$base = "0123456789ABCDEF";
$dezesseis = new Math_BigInteger(16);
$result = "";
while ($n->compare($zero) > 0) {
list($n, $r) = $n->divide($dezesseis); $result = $base[intval($r->toString())] . $result; }
return $result;
}
function milliToHex() {
$temp = new Math_BigInteger
(time()); $mil = new Math_BigInteger(1000);
$ret = toHex($temp->multiply($mil));
return str_pad($ret, 16, "0", STR_PAD_LEFT
); }
echo milliToHex();
?>
PD9waHAKCi8qIHZpbTogc2V0IGV4cGFuZHRhYiB0YWJzdG9wPTQgc2hpZnR3aWR0aD00IHNvZnR0YWJzdG9wPTQ6ICovCiAKLyoqI0ArKi8KZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9OVEdPTUVSWScsIDApOwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9CQVJSRVRUJywgMSk7CmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX1BPV0VST0YyJywgMik7CmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0NMQVNTSUMnLCAzKTsKZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTk9ORScsIDQpOwovKiojQC0qLwogCi8qKiNAKyovCmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX1ZBTFVFJywgMCk7CmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX1NJR04nLCAxKTsKLyoqI0AtKi8KIAovKiojQCsqLwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9WQVJJQUJMRScsIDApOwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9EQVRBJywgMSk7Ci8qKiNALSovCiAKLyoqI0ArKi8KZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9ERV9JTlRFUk5BTCcsIDEpOwogCmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIJywgMik7CiAKZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVAnLCAzKTsKLyoqI0AtKi8KIApkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9LQVJBVFNVQkFfQ1VUT0ZGJywgMjUpOwogCmNsYXNzIE1hdGhfQmlnSW50ZWdlciB7CiAgdmFyICR2YWx1ZTsKIAogIHZhciAkaXNfbmVnYXRpdmUgPSBmYWxzZTsKIAogIHZhciAkcHJlY2lzaW9uID0gLTE7CiAKICB2YXIgJGJpdG1hc2sgPSBmYWxzZTsKIAogIHZhciAkaGV4OwogCiAgZnVuY3Rpb24gTWF0aF9CaWdJbnRlZ2VyKCR4ID0gMCwgJGJhc2UgPSAxMCkKICB7CiAgICBpZiAoICFkZWZpbmVkKCdNQVRIX0JJR0lOVEVHRVJfTU9ERScpICkgewogICAgICBzd2l0Y2ggKHRydWUpIHsKICAgICAgICBjYXNlIGV4dGVuc2lvbl9sb2FkZWQoJ2dtcCcpOgogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9ERScsIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUCk7CiAgICAgICAgICBicmVhazsKICAgICAgICBjYXNlIGV4dGVuc2lvbl9sb2FkZWQoJ2JjbWF0aCcpOgogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9ERScsIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSCk7CiAgICAgICAgICBicmVhazsKICAgICAgICBkZWZhdWx0OgogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9ERScsIE1BVEhfQklHSU5URUdFUl9NT0RFX0lOVEVSTkFMKTsKICAgICAgfQogICAgfQogCiAgICBpZiAoZnVuY3Rpb25fZXhpc3RzKCdvcGVuc3NsX3B1YmxpY19lbmNyeXB0JykgJiYgIWRlZmluZWQoJ01BVEhfQklHSU5URUdFUl9PUEVOU1NMX0RJU0FCTEUnKSAmJiAhZGVmaW5lZCgnTUFUSF9CSUdJTlRFR0VSX09QRU5TU0xfRU5BQkxFRCcpKSB7CiAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX09QRU5TU0xfRU5BQkxFRCcsIHRydWUpOwogICAgfQogCiAgICBpZiAoIWRlZmluZWQoJ1BIUF9JTlRfU0laRScpKSB7CiAgICAgIGRlZmluZSgnUEhQX0lOVF9TSVpFJywgNCk7CiAgICB9CiAKICAgIGlmICghZGVmaW5lZCgnTUFUSF9CSUdJTlRFR0VSX0JBU0UnKSAmJiBNQVRIX0JJR0lOVEVHRVJfTU9ERSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9JTlRFUk5BTCkgewogICAgICBzd2l0Y2ggKFBIUF9JTlRfU0laRSkgewogICAgICAgIGNhc2UgODogLy8gdXNlIDY0LWJpdCBpbnRlZ2VycyBpZiBpbnQgc2l6ZSBpcyA4IGJ5dGVzCiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9CQVNFJywgICAgIDMxKTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCcsICAweDgwMDAwMDAwKTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01BWF9ESUdJVCcsICAweDdGRkZGRkZGKTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01TQicsICAgIDB4NDAwMDAwMDApOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTUFYMTAnLCAgICAxMDAwMDAwMDAwKTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01BWDEwX0xFTicsICA5KTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01BWF9ESUdJVDInLCBwb3coMiwgNjIpKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9CQVNFJywgICAgIDI2KTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCcsICAweDQwMDAwMDApOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTUFYX0RJR0lUJywgIDB4M0ZGRkZGRik7CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NU0InLCAgICAweDIwMDAwMDApOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTUFYMTAnLCAgICAxMDAwMDAwMCk7CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4nLCAgNyk7CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NQVhfRElHSVQyJywgcG93KDIsIDUyKSk7CiAgICAgIH0KICAgIH0KIAogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGlmIChpc19yZXNvdXJjZSgkeCkgJiYgZ2V0X3Jlc291cmNlX3R5cGUoJHgpID09ICdHTVAgaW50ZWdlcicpIHsKICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR4OwogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICAkdGhpcy0+dmFsdWUgPSBnbXBfaW5pdCgwKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgJHRoaXMtPnZhbHVlID0gJzAnOwogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgICR0aGlzLT52YWx1ZSA9IGFycmF5KCk7CiAgICB9CiAKICAgIGlmIChlbXB0eSgkeCkgJiYgKGFicygkYmFzZSkgIT0gMjU2IHx8ICR4ICE9PSAnMCcpKSB7CiAgICAgIHJldHVybjsKICAgIH0KIAogICAgc3dpdGNoICgkYmFzZSkgewogICAgICBjYXNlIC0yNTY6CiAgICAgICAgaWYgKG9yZCgkeFswXSkgJiAweDgwKSB7CiAgICAgICAgICAkeCA9IH4keDsKICAgICAgICAgICR0aGlzLT5pc19uZWdhdGl2ZSA9IHRydWU7CiAgICAgICAgfQogICAgICBjYXNlICAyNTY6CiAgICAgICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAgICAgJHNpZ24gPSAkdGhpcy0+aXNfbmVnYXRpdmUgPyAnLScgOiAnJzsKICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gZ21wX2luaXQoJHNpZ24gLiAnMHgnIC4gYmluMmhleCgkeCkpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICAgICAkbGVuID0gKHN0cmxlbigkeCkgKyAzKSAmIDB4RkZGRkZGRkM7CiAKICAgICAgICAgICAgJHggPSBzdHJfcGFkKCR4LCAkbGVuLCBjaHIoMCksIFNUUl9QQURfTEVGVCk7CiAKICAgICAgICAgICAgZm9yICgkaSA9IDA7ICRpIDwgJGxlbjsgJGkrPSA0KSB7CiAgICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gYmNtdWwoJHRoaXMtPnZhbHVlLCAnNDI5NDk2NzI5NicsIDApOwogICAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9IGJjYWRkKCR0aGlzLT52YWx1ZSwgMHgxMDAwMDAwICogb3JkKCR4WyRpXSkgKyAoKG9yZCgkeFskaSArIDFdKSA8PCAxNikgfCAob3JkKCR4WyRpICsgMl0pIDw8IDgpIHwgb3JkKCR4WyRpICsgM10pKSwgMCk7CiAgICAgICAgICAgIH0KIAogICAgICAgICAgICBpZiAoJHRoaXMtPmlzX25lZ2F0aXZlKSB7CiAgICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gJy0nIC4gJHRoaXMtPnZhbHVlOwogICAgICAgICAgICB9CiAKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICB3aGlsZSAoc3RybGVuKCR4KSkgewogICAgICAgICAgICAgICR0aGlzLT52YWx1ZVtdID0gJHRoaXMtPl9ieXRlczJpbnQoJHRoaXMtPl9iYXNlMjU2X3JzaGlmdCgkeCwgTUFUSF9CSUdJTlRFR0VSX0JBU0UpKTsKICAgICAgICAgICAgfQogICAgICAgIH0KIAogICAgICAgIGlmICgkdGhpcy0+aXNfbmVnYXRpdmUpIHsKICAgICAgICAgIGlmIChNQVRIX0JJR0lOVEVHRVJfTU9ERSAhPSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9JTlRFUk5BTCkgewogICAgICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKICAgICAgICAgIH0KICAgICAgICAgICR0ZW1wID0gJHRoaXMtPmFkZChuZXcgTWF0aF9CaWdJbnRlZ2VyKCctMScpKTsKICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgIDE2OgogICAgICBjYXNlIC0xNjoKICAgICAgICBpZiAoJGJhc2UgPiAwICYmICR4WzBdID09ICctJykgewogICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gdHJ1ZTsKICAgICAgICAgICR4ID0gc3Vic3RyKCR4LCAxKTsKICAgICAgICB9CiAKICAgICAgICAkeCA9IHByZWdfcmVwbGFjZSgnI14oPzoweCk/KFtBLUZhLWYwLTldKikuKiMnLCAnJDEnLCAkeCk7CiAKICAgICAgICAkaXNfbmVnYXRpdmUgPSBmYWxzZTsKICAgICAgICBpZiAoJGJhc2UgPCAwICYmIGhleGRlYygkeFswXSkgPj0gOCkgewogICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gJGlzX25lZ2F0aXZlID0gdHJ1ZTsKICAgICAgICAgICR4ID0gYmluMmhleCh+cGFjaygnSConLCAkeCkpOwogICAgICAgIH0KIAogICAgICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgICAgICR0ZW1wID0gJHRoaXMtPmlzX25lZ2F0aXZlID8gJy0weCcgLiAkeCA6ICcweCcgLiAkeDsKICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gZ21wX2luaXQoJHRlbXApOwogICAgICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAgICAgJHggPSAoIHN0cmxlbigkeCkgJiAxICkgPyAnMCcgLiAkeCA6ICR4OwogICAgICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIocGFjaygnSConLCAkeCksIDI1Nik7CiAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0aGlzLT5pc19uZWdhdGl2ZSA/ICctJyAuICR0ZW1wLT52YWx1ZSA6ICR0ZW1wLT52YWx1ZTsKICAgICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gZmFsc2U7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgJHggPSAoIHN0cmxlbigkeCkgJiAxICkgPyAnMCcgLiAkeCA6ICR4OwogICAgICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIocGFjaygnSConLCAkeCksIDI1Nik7CiAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICAgICAgICB9CiAKICAgICAgICBpZiAoJGlzX25lZ2F0aXZlKSB7CiAgICAgICAgICAkdGVtcCA9ICR0aGlzLT5hZGQobmV3IE1hdGhfQmlnSW50ZWdlcignLTEnKSk7CiAgICAgICAgICAkdGhpcy0+dmFsdWUgPSAkdGVtcC0+dmFsdWU7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICBjYXNlICAxMDoKICAgICAgY2FzZSAtMTA6CiAgICAgICAgJHggPSBwcmVnX3JlcGxhY2UoJyMoPzwhXikoPzotKS4qfCg/PD1efC0pMCp8W14tMC05XS4qIycsICcnLCAkeCk7CiAKICAgICAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgICAgICAkdGhpcy0+dmFsdWUgPSBnbXBfaW5pdCgkeCk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR4ID09PSAnLScgPyAnMCcgOiAoc3RyaW5nKSAkeDsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKIAogICAgICAgICAgICAkbXVsdGlwbGllciA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAgICAgJG11bHRpcGxpZXItPnZhbHVlID0gYXJyYXkoTUFUSF9CSUdJTlRFR0VSX01BWDEwKTsKIAogICAgICAgICAgICBpZiAoJHhbMF0gPT0gJy0nKSB7CiAgICAgICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgICAkeCA9IHN1YnN0cigkeCwgMSk7CiAgICAgICAgICAgIH0KIAogICAgICAgICAgICAkeCA9IHN0cl9wYWQoJHgsIHN0cmxlbigkeCkgKyAoKE1BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4gLSAxKSAqIHN0cmxlbigkeCkpICUgTUFUSF9CSUdJTlRFR0VSX01BWDEwX0xFTiwgMCwgU1RSX1BBRF9MRUZUKTsKIAogICAgICAgICAgICB3aGlsZSAoc3RybGVuKCR4KSkgewogICAgICAgICAgICAgICR0ZW1wID0gJHRlbXAtPm11bHRpcGx5KCRtdWx0aXBsaWVyKTsKICAgICAgICAgICAgICAkdGVtcCA9ICR0ZW1wLT5hZGQobmV3IE1hdGhfQmlnSW50ZWdlcigkdGhpcy0+X2ludDJieXRlcyhzdWJzdHIoJHgsIDAsIE1BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4pKSwgMjU2KSk7CiAgICAgICAgICAgICAgJHggPSBzdWJzdHIoJHgsIE1BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4pOwogICAgICAgICAgICB9CiAKICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gJHRlbXAtPnZhbHVlOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgICAgY2FzZSAgMjoKICAgICAgY2FzZSAtMjoKICAgICAgICBpZiAoJGJhc2UgPiAwICYmICR4WzBdID09ICctJykgewogICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gdHJ1ZTsKICAgICAgICAgICR4ID0gc3Vic3RyKCR4LCAxKTsKICAgICAgICB9CiAKICAgICAgICAkeCA9IHByZWdfcmVwbGFjZSgnI14oWzAxXSopLiojJywgJyQxJywgJHgpOwogICAgICAgICR4ID0gc3RyX3BhZCgkeCwgc3RybGVuKCR4KSArICgzICogc3RybGVuKCR4KSkgJSA0LCAwLCBTVFJfUEFEX0xFRlQpOwogCiAgICAgICAgJHN0ciA9ICcweCc7CiAgICAgICAgd2hpbGUgKHN0cmxlbigkeCkpIHsKICAgICAgICAgICRwYXJ0ID0gc3Vic3RyKCR4LCAwLCA0KTsKICAgICAgICAgICRzdHIuPSBkZWNoZXgoYmluZGVjKCRwYXJ0KSk7CiAgICAgICAgICAkeCA9IHN1YnN0cigkeCwgNCk7CiAgICAgICAgfQogCiAgICAgICAgaWYgKCR0aGlzLT5pc19uZWdhdGl2ZSkgewogICAgICAgICAgJHN0ciA9ICctJyAuICRzdHI7CiAgICAgICAgfQogCiAgICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCRzdHIsIDggKiAkYmFzZSk7IC8vIGllLiBlaXRoZXIgLTE2IG9yICsxNgogICAgICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSAkdGVtcC0+aXNfbmVnYXRpdmU7CiAKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAvLyBiYXNlIG5vdCBzdXBwb3J0ZWQsIHNvIHdlJ2xsIGxldCAkdGhpcyA9PSAwCiAgICB9CiAgfQogCiAgZnVuY3Rpb24gdG9CeXRlcygkdHdvc19jb21wbGltZW50ID0gZmFsc2UpIHsKICAgIGlmICgkdHdvc19jb21wbGltZW50KSB7CiAgICAgICRjb21wYXJpc29uID0gJHRoaXMtPmNvbXBhcmUobmV3IE1hdGhfQmlnSW50ZWdlcigpKTsKICAgICAgaWYgKCRjb21wYXJpc29uID09IDApIHsKICAgICAgICByZXR1cm4gJHRoaXMtPnByZWNpc2lvbiA+IDAgPyBzdHJfcmVwZWF0KGNocigwKSwgKCR0aGlzLT5wcmVjaXNpb24gKyAxKSA+PiAzKSA6ICcnOwogICAgICB9CiAKICAgICAgJHRlbXAgPSAkY29tcGFyaXNvbiA8IDAgPyAkdGhpcy0+YWRkKG5ldyBNYXRoX0JpZ0ludGVnZXIoMSkpIDogJHRoaXMtPmNvcHkoKTsKICAgICAgJGJ5dGVzID0gJHRlbXAtPnRvQnl0ZXMoKTsKIAogICAgICBpZiAoZW1wdHkoJGJ5dGVzKSkgewogICAgICAgICRieXRlcyA9IGNocigwKTsKICAgICAgfQogCiAgICAgIGlmIChvcmQoJGJ5dGVzWzBdKSAmIDB4ODApIHsKICAgICAgICAkYnl0ZXMgPSBjaHIoMCkgLiAkYnl0ZXM7CiAgICAgIH0KIAogICAgICByZXR1cm4gJGNvbXBhcmlzb24gPCAwID8gfiRieXRlcyA6ICRieXRlczsKICAgIH0KIAogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGlmIChnbXBfY21wKCR0aGlzLT52YWx1ZSwgZ21wX2luaXQoMCkpID09IDApIHsKICAgICAgICAgIHJldHVybiAkdGhpcy0+cHJlY2lzaW9uID4gMCA/IHN0cl9yZXBlYXQoY2hyKDApLCAoJHRoaXMtPnByZWNpc2lvbiArIDEpID4+IDMpIDogJyc7CiAgICAgICAgfQogCiAgICAgICAgJHRlbXAgPSBnbXBfc3RydmFsKGdtcF9hYnMoJHRoaXMtPnZhbHVlKSwgMTYpOwogICAgICAgICR0ZW1wID0gKCBzdHJsZW4oJHRlbXApICYgMSApID8gJzAnIC4gJHRlbXAgOiAkdGVtcDsKICAgICAgICAkdGVtcCA9IHBhY2soJ0gqJywgJHRlbXApOwogCiAgICAgICAgcmV0dXJuICR0aGlzLT5wcmVjaXNpb24gPiAwID8KICAgICAgICAgIHN1YnN0cihzdHJfcGFkKCR0ZW1wLCAkdGhpcy0+cHJlY2lzaW9uID4+IDMsIGNocigwKSwgU1RSX1BBRF9MRUZUKSwgLSgkdGhpcy0+cHJlY2lzaW9uID4+IDMpKSA6CiAgICAgICAgICBsdHJpbSgkdGVtcCwgY2hyKDApKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgaWYgKCR0aGlzLT52YWx1ZSA9PT0gJzAnKSB7CiAgICAgICAgICByZXR1cm4gJHRoaXMtPnByZWNpc2lvbiA+IDAgPyBzdHJfcmVwZWF0KGNocigwKSwgKCR0aGlzLT5wcmVjaXNpb24gKyAxKSA+PiAzKSA6ICcnOwogICAgICAgIH0KIAogICAgICAgICR2YWx1ZSA9ICcnOwogICAgICAgICRjdXJyZW50ID0gJHRoaXMtPnZhbHVlOwogCiAgICAgICAgaWYgKCRjdXJyZW50WzBdID09ICctJykgewogICAgICAgICAgJGN1cnJlbnQgPSBzdWJzdHIoJGN1cnJlbnQsIDEpOwogICAgICAgIH0KIAogICAgICAgIHdoaWxlIChiY2NvbXAoJGN1cnJlbnQsICcwJywgMCkgPiAwKSB7CiAgICAgICAgICAkdGVtcCA9IGJjbW9kKCRjdXJyZW50LCAnMTY3NzcyMTYnKTsKICAgICAgICAgICR2YWx1ZSA9IGNocigkdGVtcCA+PiAxNikgLiBjaHIoJHRlbXAgPj4gOCkgLiBjaHIoJHRlbXApIC4gJHZhbHVlOwogICAgICAgICAgJGN1cnJlbnQgPSBiY2RpdigkY3VycmVudCwgJzE2Nzc3MjE2JywgMCk7CiAgICAgICAgfQogCiAgICAgICAgcmV0dXJuICR0aGlzLT5wcmVjaXNpb24gPiAwID8KICAgICAgICAgIHN1YnN0cihzdHJfcGFkKCR2YWx1ZSwgJHRoaXMtPnByZWNpc2lvbiA+PiAzLCBjaHIoMCksIFNUUl9QQURfTEVGVCksIC0oJHRoaXMtPnByZWNpc2lvbiA+PiAzKSkgOgogICAgICAgICAgbHRyaW0oJHZhbHVlLCBjaHIoMCkpOwogICAgfQogCiAgICBpZiAoIWNvdW50KCR0aGlzLT52YWx1ZSkpIHsKICAgICAgcmV0dXJuICR0aGlzLT5wcmVjaXNpb24gPiAwID8gc3RyX3JlcGVhdChjaHIoMCksICgkdGhpcy0+cHJlY2lzaW9uICsgMSkgPj4gMykgOiAnJzsKICAgIH0KICAgICRyZXN1bHQgPSAkdGhpcy0+X2ludDJieXRlcygkdGhpcy0+dmFsdWVbY291bnQoJHRoaXMtPnZhbHVlKSAtIDFdKTsKIAogICAgJHRlbXAgPSAkdGhpcy0+Y29weSgpOwogCiAgICBmb3IgKCRpID0gY291bnQoJHRlbXAtPnZhbHVlKSAtIDI7ICRpID49IDA7IC0tJGkpIHsKICAgICAgJHRlbXAtPl9iYXNlMjU2X2xzaGlmdCgkcmVzdWx0LCBNQVRIX0JJR0lOVEVHRVJfQkFTRSk7CiAgICAgICRyZXN1bHQgPSAkcmVzdWx0IHwgc3RyX3BhZCgkdGVtcC0+X2ludDJieXRlcygkdGVtcC0+dmFsdWVbJGldKSwgc3RybGVuKCRyZXN1bHQpLCBjaHIoMCksIFNUUl9QQURfTEVGVCk7CiAgICB9CiAKICAgIHJldHVybiAkdGhpcy0+cHJlY2lzaW9uID4gMCA/CiAgICAgIHN0cl9wYWQoc3Vic3RyKCRyZXN1bHQsIC0oKCR0aGlzLT5wcmVjaXNpb24gKyA3KSA+PiAzKSksICgkdGhpcy0+cHJlY2lzaW9uICsgNykgPj4gMywgY2hyKDApLCBTVFJfUEFEX0xFRlQpIDoKICAgICAgJHJlc3VsdDsKICB9CiAKICBmdW5jdGlvbiB0b0hleCgkdHdvc19jb21wbGltZW50ID0gZmFsc2UpIHsKICAgIHJldHVybiBiaW4yaGV4KCR0aGlzLT50b0J5dGVzKCR0d29zX2NvbXBsaW1lbnQpKTsKICB9CiAKICBmdW5jdGlvbiB0b0JpdHMoJHR3b3NfY29tcGxpbWVudCA9IGZhbHNlKSB7CiAgICAkaGV4ID0gJHRoaXMtPnRvSGV4KCR0d29zX2NvbXBsaW1lbnQpOwogICAgJGJpdHMgPSAnJzsKICAgIGZvciAoJGkgPSBzdHJsZW4oJGhleCkgLSA4LCAkc3RhcnQgPSBzdHJsZW4oJGhleCkgJiA3OyAkaSA+PSAkc3RhcnQ7ICRpLT04KSB7CiAgICAgICRiaXRzID0gc3RyX3BhZChkZWNiaW4oaGV4ZGVjKHN1YnN0cigkaGV4LCAkaSwgOCkpKSwgMzIsICcwJywgU1RSX1BBRF9MRUZUKSAuICRiaXRzOwogICAgfQogICAgaWYgKCRzdGFydCkgewogICAgICAkYml0cyA9IHN0cl9wYWQoZGVjYmluKGhleGRlYyhzdWJzdHIoJGhleCwgMCwgJHN0YXJ0KSkpLCA4LCAnMCcsIFNUUl9QQURfTEVGVCkgLiAkYml0czsKICAgIH0KICAgICRyZXN1bHQgPSAkdGhpcy0+cHJlY2lzaW9uID4gMCA/IHN1YnN0cigkYml0cywgLSR0aGlzLT5wcmVjaXNpb24pIDogbHRyaW0oJGJpdHMsICcwJyk7CiAKICAgIGlmICgkdHdvc19jb21wbGltZW50ICYmICR0aGlzLT5jb21wYXJlKG5ldyBNYXRoX0JpZ0ludGVnZXIoKSkgPiAwICYmICR0aGlzLT5wcmVjaXNpb24gPD0gMCkgewogICAgICByZXR1cm4gJzAnIC4gJHJlc3VsdDsKICAgIH0KIAogICAgcmV0dXJuICRyZXN1bHQ7CiAgfQogCiAgZnVuY3Rpb24gdG9TdHJpbmcoKSB7CiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgcmV0dXJuIGdtcF9zdHJ2YWwoJHRoaXMtPnZhbHVlKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgaWYgKCR0aGlzLT52YWx1ZSA9PT0gJzAnKSB7CiAgICAgICAgICByZXR1cm4gJzAnOwogICAgICAgIH0KIAogICAgICAgIHJldHVybiBsdHJpbSgkdGhpcy0+dmFsdWUsICcwJyk7CiAgICB9CiAKICAgIGlmICghY291bnQoJHRoaXMtPnZhbHVlKSkgewogICAgICByZXR1cm4gJzAnOwogICAgfQogCiAgICAkdGVtcCA9ICR0aGlzLT5jb3B5KCk7CiAgICAkdGVtcC0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKIAogICAgJGRpdmlzb3IgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkZGl2aXNvci0+dmFsdWUgPSBhcnJheShNQVRIX0JJR0lOVEVHRVJfTUFYMTApOwogICAgJHJlc3VsdCA9ICcnOwogICAgd2hpbGUgKGNvdW50KCR0ZW1wLT52YWx1ZSkpIHsKICAgICAgbGlzdCgkdGVtcCwgJG1vZCkgPSAkdGVtcC0+ZGl2aWRlKCRkaXZpc29yKTsKICAgICAgJHJlc3VsdCA9IHN0cl9wYWQoaXNzZXQoJG1vZC0+dmFsdWVbMF0pID8gJG1vZC0+dmFsdWVbMF0gOiAnJywgTUFUSF9CSUdJTlRFR0VSX01BWDEwX0xFTiwgJzAnLCBTVFJfUEFEX0xFRlQpIC4gJHJlc3VsdDsKICAgIH0KICAgICRyZXN1bHQgPSBsdHJpbSgkcmVzdWx0LCAnMCcpOwogICAgaWYgKGVtcHR5KCRyZXN1bHQpKSB7CiAgICAgICRyZXN1bHQgPSAnMCc7CiAgICB9CiAKICAgIGlmICgkdGhpcy0+aXNfbmVnYXRpdmUpIHsKICAgICAgJHJlc3VsdCA9ICctJyAuICRyZXN1bHQ7CiAgICB9CiAKICAgIHJldHVybiAkcmVzdWx0OwogIH0KIAogIGZ1bmN0aW9uIGNvcHkoKSB7CiAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICR0ZW1wLT52YWx1ZSA9ICR0aGlzLT52YWx1ZTsKICAgICR0ZW1wLT5pc19uZWdhdGl2ZSA9ICR0aGlzLT5pc19uZWdhdGl2ZTsKICAgICR0ZW1wLT5wcmVjaXNpb24gPSAkdGhpcy0+cHJlY2lzaW9uOwogICAgJHRlbXAtPmJpdG1hc2sgPSAkdGhpcy0+Yml0bWFzazsKICAgIHJldHVybiAkdGVtcDsKICB9CiAKICBmdW5jdGlvbiBfX3RvU3RyaW5nKCkgewogICAgcmV0dXJuICR0aGlzLT50b1N0cmluZygpOwogIH0KIAogIGZ1bmN0aW9uIF9fY2xvbmUoKSB7CiAgICByZXR1cm4gJHRoaXMtPmNvcHkoKTsKICB9CiAKICBmdW5jdGlvbiBfX3NsZWVwKCkgewogICAgJHRoaXMtPmhleCA9ICR0aGlzLT50b0hleCh0cnVlKTsKICAgICR2YXJzID0gYXJyYXkoJ2hleCcpOwogICAgaWYgKCR0aGlzLT5wcmVjaXNpb24gPiAwKSB7CiAgICAgICR2YXJzW10gPSAncHJlY2lzaW9uJzsKICAgIH0KICAgIHJldHVybiAkdmFyczsKIAogIH0KIAogIGZ1bmN0aW9uIF9fd2FrZXVwKCkgewogICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCR0aGlzLT5oZXgsIC0xNik7CiAgICAkdGhpcy0+dmFsdWUgPSAkdGVtcC0+dmFsdWU7CiAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSAkdGVtcC0+aXNfbmVnYXRpdmU7CiAgICBpZiAoJHRoaXMtPnByZWNpc2lvbiA+IDApIHsKICAgICAgJHRoaXMtPnNldFByZWNpc2lvbigkdGhpcy0+cHJlY2lzaW9uKTsKICAgIH0KICB9CiAKICBmdW5jdGlvbiBhZGQoJHkpIHsKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfYWRkKCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlKTsKIAogICAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICR0ZW1wLT52YWx1ZSA9IGJjYWRkKCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlLCAwKTsKIAogICAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CiAKICAgICR0ZW1wID0gJHRoaXMtPl9hZGQoJHRoaXMtPnZhbHVlLCAkdGhpcy0+aXNfbmVnYXRpdmUsICR5LT52YWx1ZSwgJHktPmlzX25lZ2F0aXZlKTsKIAogICAgJHJlc3VsdCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRyZXN1bHQtPnZhbHVlID0gJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXTsKICAgICRyZXN1bHQtPmlzX25lZ2F0aXZlID0gJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1NJR05dOwogCiAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHJlc3VsdCk7CiAgfQogCiAgZnVuY3Rpb24gX2FkZCgkeF92YWx1ZSwgJHhfbmVnYXRpdmUsICR5X3ZhbHVlLCAkeV9uZWdhdGl2ZSkgewogICAgJHhfc2l6ZSA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICR5X3NpemUgPSBjb3VudCgkeV92YWx1ZSk7CiAKICAgIGlmICgkeF9zaXplID09IDApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiAkeV92YWx1ZSwKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAkeV9uZWdhdGl2ZQogICAgICApOwogICAgfSBlbHNlIGlmICgkeV9zaXplID09IDApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiAkeF92YWx1ZSwKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAkeF9uZWdhdGl2ZQogICAgICApOwogICAgfQogCiAgICBpZiAoICR4X25lZ2F0aXZlICE9ICR5X25lZ2F0aXZlICkgewogICAgICBpZiAoICR4X3ZhbHVlID09ICR5X3ZhbHVlICkgewogICAgICAgIHJldHVybiBhcnJheSgKICAgICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiBhcnJheSgpLAogICAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gZmFsc2UKICAgICAgICApOwogICAgICB9CiAKICAgICAgJHRlbXAgPSAkdGhpcy0+X3N1YnRyYWN0KCR4X3ZhbHVlLCBmYWxzZSwgJHlfdmFsdWUsIGZhbHNlKTsKICAgICAgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1NJR05dID0gJHRoaXMtPl9jb21wYXJlKCR4X3ZhbHVlLCBmYWxzZSwgJHlfdmFsdWUsIGZhbHNlKSA+IDAgPyAkeF9uZWdhdGl2ZSA6ICR5X25lZ2F0aXZlOwogCiAgICAgIHJldHVybiAkdGVtcDsKICAgIH0KIAogICAgaWYgKCR4X3NpemUgPCAkeV9zaXplKSB7CiAgICAgICRzaXplID0gJHhfc2l6ZTsKICAgICAgJHZhbHVlID0gJHlfdmFsdWU7CiAgICB9IGVsc2UgewogICAgICAkc2l6ZSA9ICR5X3NpemU7CiAgICAgICR2YWx1ZSA9ICR4X3ZhbHVlOwogICAgfQogCiAgICAkdmFsdWVbXSA9IDA7CiAKICAgICRjYXJyeSA9IDA7CiAgICBmb3IgKCRpID0gMCwgJGogPSAxOyAkaiA8ICRzaXplOyAkaSs9MiwgJGorPTIpIHsKICAgICAgJHN1bSA9ICR4X3ZhbHVlWyRqXSAqIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKyAkeF92YWx1ZVskaV0gKyAkeV92YWx1ZVskal0gKiBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICsgJHlfdmFsdWVbJGldICsgJGNhcnJ5OwogICAgICAkY2FycnkgPSAkc3VtID49IE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQyOwogICAgICAkc3VtID0gJGNhcnJ5ID8gJHN1bSAtIE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQyIDogJHN1bTsKIAogICAgICAkdGVtcCA9IChpbnQpICgkc3VtIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAKICAgICAgJHZhbHVlWyRpXSA9IChpbnQpICgkc3VtIC0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICR0ZW1wKTsKICAgICAgJHZhbHVlWyRqXSA9ICR0ZW1wOwogICAgfQogCiAgICBpZiAoJGogPT0gJHNpemUpIHsKICAgICAgJHN1bSA9ICR4X3ZhbHVlWyRpXSArICR5X3ZhbHVlWyRpXSArICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gJHN1bSA+PSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMOwogICAgICAkdmFsdWVbJGldID0gJGNhcnJ5ID8gJHN1bSAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgOiAkc3VtOwogICAgICArKyRpOwogICAgfQogCiAgICBpZiAoJGNhcnJ5KSB7CiAgICAgIGZvciAoOyAkdmFsdWVbJGldID09IE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQ7ICsrJGkpIHsKICAgICAgICAkdmFsdWVbJGldID0gMDsKICAgICAgfQogICAgICArKyR2YWx1ZVskaV07CiAgICB9CiAKICAgIHJldHVybiBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+ICR0aGlzLT5fdHJpbSgkdmFsdWUpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAkeF9uZWdhdGl2ZQogICAgKTsKICB9CiAKICBmdW5jdGlvbiBzdWJ0cmFjdCgkeSkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICR0ZW1wLT52YWx1ZSA9IGdtcF9zdWIoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUpOwogCiAgICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHRlbXAtPnZhbHVlID0gYmNzdWIoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUsIDApOwogCiAgICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICAgIH0KIAogICAgJHRlbXAgPSAkdGhpcy0+X3N1YnRyYWN0KCR0aGlzLT52YWx1ZSwgJHRoaXMtPmlzX25lZ2F0aXZlLCAkeS0+dmFsdWUsICR5LT5pc19uZWdhdGl2ZSk7CiAKICAgICRyZXN1bHQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkcmVzdWx0LT52YWx1ZSA9ICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgICAkcmVzdWx0LT5pc19uZWdhdGl2ZSA9ICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXTsKIAogICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCRyZXN1bHQpOwogIH0KIAogIGZ1bmN0aW9uIF9zdWJ0cmFjdCgkeF92YWx1ZSwgJHhfbmVnYXRpdmUsICR5X3ZhbHVlLCAkeV9uZWdhdGl2ZSkgewogICAgJHhfc2l6ZSA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICR5X3NpemUgPSBjb3VudCgkeV92YWx1ZSk7CiAKICAgIGlmICgkeF9zaXplID09IDApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiAkeV92YWx1ZSwKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAhJHlfbmVnYXRpdmUKICAgICAgKTsKICAgIH0gZWxzZSBpZiAoJHlfc2l6ZSA9PSAwKSB7CiAgICAgIHJldHVybiBhcnJheSgKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHhfdmFsdWUsCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gJHhfbmVnYXRpdmUKICAgICAgKTsKICAgIH0KIAogICAgaWYgKCAkeF9uZWdhdGl2ZSAhPSAkeV9uZWdhdGl2ZSApIHsKICAgICAgJHRlbXAgPSAkdGhpcy0+X2FkZCgkeF92YWx1ZSwgZmFsc2UsICR5X3ZhbHVlLCBmYWxzZSk7CiAgICAgICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXSA9ICR4X25lZ2F0aXZlOwogCiAgICAgIHJldHVybiAkdGVtcDsKICAgIH0KIAogICAgJGRpZmYgPSAkdGhpcy0+X2NvbXBhcmUoJHhfdmFsdWUsICR4X25lZ2F0aXZlLCAkeV92YWx1ZSwgJHlfbmVnYXRpdmUpOwogCiAgICBpZiAoICEkZGlmZiApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiBhcnJheSgpLAogICAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+IGZhbHNlCiAgICAgICk7CiAgICB9CiAKICAgIGlmICggKCEkeF9uZWdhdGl2ZSAmJiAkZGlmZiA8IDApIHx8ICgkeF9uZWdhdGl2ZSAmJiAkZGlmZiA+IDApICkgewogICAgICAkdGVtcCA9ICR4X3ZhbHVlOwogICAgICAkeF92YWx1ZSA9ICR5X3ZhbHVlOwogICAgICAkeV92YWx1ZSA9ICR0ZW1wOwogCiAgICAgICR4X25lZ2F0aXZlID0gISR4X25lZ2F0aXZlOwogCiAgICAgICR4X3NpemUgPSBjb3VudCgkeF92YWx1ZSk7CiAgICAgICR5X3NpemUgPSBjb3VudCgkeV92YWx1ZSk7CiAgICB9CiAKICAgICRjYXJyeSA9IDA7CiAgICBmb3IgKCRpID0gMCwgJGogPSAxOyAkaiA8ICR5X3NpemU7ICRpKz0yLCAkais9MikgewogICAgICAkc3VtID0gJHhfdmFsdWVbJGpdICogTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCArICR4X3ZhbHVlWyRpXSAtICR5X3ZhbHVlWyRqXSAqIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgLSAkeV92YWx1ZVskaV0gLSAkY2Fycnk7CiAgICAgICRjYXJyeSA9ICRzdW0gPCAwOwogICAgICAkc3VtID0gJGNhcnJ5ID8gJHN1bSArIE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQyIDogJHN1bTsKIAogICAgICAkdGVtcCA9IChpbnQpICgkc3VtIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAKICAgICAgJHhfdmFsdWVbJGldID0gKGludCkgKCRzdW0gLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogJHRlbXApOwogICAgICAkeF92YWx1ZVskal0gPSAkdGVtcDsKICAgIH0KIAogICAgaWYgKCRqID09ICR5X3NpemUpIHsKICAgICAgJHN1bSA9ICR4X3ZhbHVlWyRpXSAtICR5X3ZhbHVlWyRpXSAtICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gJHN1bSA8IDA7CiAgICAgICR4X3ZhbHVlWyRpXSA9ICRjYXJyeSA/ICRzdW0gKyBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMIDogJHN1bTsKICAgICAgKyskaTsKICAgIH0KIAogICAgaWYgKCRjYXJyeSkgewogICAgICBmb3IgKDsgISR4X3ZhbHVlWyRpXTsgKyskaSkgewogICAgICAgICR4X3ZhbHVlWyRpXSA9IE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQ7CiAgICAgIH0KICAgICAgLS0keF92YWx1ZVskaV07CiAgICB9CiAKICAgIHJldHVybiBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+ICR0aGlzLT5fdHJpbSgkeF92YWx1ZSksCiAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+ICR4X25lZ2F0aXZlCiAgICApOwogIH0KIAogIGZ1bmN0aW9uIG11bHRpcGx5KCR4KSB7CiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHRlbXAtPnZhbHVlID0gZ21wX211bCgkdGhpcy0+dmFsdWUsICR4LT52YWx1ZSk7CiAKICAgICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY211bCgkdGhpcy0+dmFsdWUsICR4LT52YWx1ZSwgMCk7CiAKICAgICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgfQogCiAgICAkdGVtcCA9ICR0aGlzLT5fbXVsdGlwbHkoJHRoaXMtPnZhbHVlLCAkdGhpcy0+aXNfbmVnYXRpdmUsICR4LT52YWx1ZSwgJHgtPmlzX25lZ2F0aXZlKTsKIAogICAgJHByb2R1Y3QgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkcHJvZHVjdC0+dmFsdWUgPSAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdOwogICAgJHByb2R1Y3QtPmlzX25lZ2F0aXZlID0gJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1NJR05dOwogCiAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHByb2R1Y3QpOwogIH0KIAogIGZ1bmN0aW9uIF9tdWx0aXBseSgkeF92YWx1ZSwgJHhfbmVnYXRpdmUsICR5X3ZhbHVlLCAkeV9uZWdhdGl2ZSkgewogICAgJHhfbGVuZ3RoID0gY291bnQoJHhfdmFsdWUpOwogICAgJHlfbGVuZ3RoID0gY291bnQoJHlfdmFsdWUpOwogCiAgICBpZiAoICEkeF9sZW5ndGggfHwgISR5X2xlbmd0aCApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiBhcnJheSgpLAogICAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+IGZhbHNlCiAgICAgICk7CiAgICB9CiAKICAgIHJldHVybiBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+IG1pbigkeF9sZW5ndGgsICR5X2xlbmd0aCkgPCAyICogTUFUSF9CSUdJTlRFR0VSX0tBUkFUU1VCQV9DVVRPRkYgPwogICAgICAgICR0aGlzLT5fdHJpbSgkdGhpcy0+X3JlZ3VsYXJNdWx0aXBseSgkeF92YWx1ZSwgJHlfdmFsdWUpKSA6CiAgICAgICAgJHRoaXMtPl90cmltKCR0aGlzLT5fa2FyYXRzdWJhKCR4X3ZhbHVlLCAkeV92YWx1ZSkpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAkeF9uZWdhdGl2ZSAhPSAkeV9uZWdhdGl2ZQogICAgKTsKICB9CiAKICBmdW5jdGlvbiBfcmVndWxhck11bHRpcGx5KCR4X3ZhbHVlLCAkeV92YWx1ZSkgewogICAgJHhfbGVuZ3RoID0gY291bnQoJHhfdmFsdWUpOwogICAgJHlfbGVuZ3RoID0gY291bnQoJHlfdmFsdWUpOwogCiAgICBpZiAoICEkeF9sZW5ndGggfHwgISR5X2xlbmd0aCApIHsKICAgICAgcmV0dXJuIGFycmF5KCk7CiAgICB9CiAKICAgIGlmICggJHhfbGVuZ3RoIDwgJHlfbGVuZ3RoICkgewogICAgICAkdGVtcCA9ICR4X3ZhbHVlOwogICAgICAkeF92YWx1ZSA9ICR5X3ZhbHVlOwogICAgICAkeV92YWx1ZSA9ICR0ZW1wOwogCiAgICAgICR4X2xlbmd0aCA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICAgJHlfbGVuZ3RoID0gY291bnQoJHlfdmFsdWUpOwogICAgfQogCiAgICAkcHJvZHVjdF92YWx1ZSA9ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsICR4X2xlbmd0aCArICR5X2xlbmd0aCk7CiAKICAgICRjYXJyeSA9IDA7CiAKICAgIGZvciAoJGogPSAwOyAkaiA8ICR4X2xlbmd0aDsgKyskaikgewogICAgICAkdGVtcCA9ICR4X3ZhbHVlWyRqXSAqICR5X3ZhbHVlWzBdICsgJGNhcnJ5OwogICAgICAkY2FycnkgPSAoaW50KSAoJHRlbXAgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKTsKICAgICAgJHByb2R1Y3RfdmFsdWVbJGpdID0gKGludCkgKCR0ZW1wIC0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICRjYXJyeSk7CiAgICB9CiAKICAgICRwcm9kdWN0X3ZhbHVlWyRqXSA9ICRjYXJyeTsKIAogICAgZm9yICgkaSA9IDE7ICRpIDwgJHlfbGVuZ3RoOyArKyRpKSB7CiAgICAgICRjYXJyeSA9IDA7CiAKICAgICAgZm9yICgkaiA9IDAsICRrID0gJGk7ICRqIDwgJHhfbGVuZ3RoOyArKyRqLCArKyRrKSB7CiAgICAgICAgJHRlbXAgPSAkcHJvZHVjdF92YWx1ZVska10gKyAkeF92YWx1ZVskal0gKiAkeV92YWx1ZVskaV0gKyAkY2Fycnk7CiAgICAgICAgJGNhcnJ5ID0gKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAgICAgICAgJHByb2R1Y3RfdmFsdWVbJGtdID0gKGludCkgKCR0ZW1wIC0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICRjYXJyeSk7CiAgICAgIH0KIAogICAgICAkcHJvZHVjdF92YWx1ZVska10gPSAkY2Fycnk7CiAgICB9CiAKICAgIHJldHVybiAkcHJvZHVjdF92YWx1ZTsKICB9CiAKICBmdW5jdGlvbiBfa2FyYXRzdWJhKCR4X3ZhbHVlLCAkeV92YWx1ZSkgewogICAgJG0gPSBtaW4oY291bnQoJHhfdmFsdWUpID4+IDEsIGNvdW50KCR5X3ZhbHVlKSA+PiAxKTsKIAogICAgaWYgKCRtIDwgTUFUSF9CSUdJTlRFR0VSX0tBUkFUU1VCQV9DVVRPRkYpIHsKICAgICAgcmV0dXJuICR0aGlzLT5fcmVndWxhck11bHRpcGx5KCR4X3ZhbHVlLCAkeV92YWx1ZSk7CiAgICB9CiAKICAgICR4MSA9IGFycmF5X3NsaWNlKCR4X3ZhbHVlLCAkbSk7CiAgICAkeDAgPSBhcnJheV9zbGljZSgkeF92YWx1ZSwgMCwgJG0pOwogICAgJHkxID0gYXJyYXlfc2xpY2UoJHlfdmFsdWUsICRtKTsKICAgICR5MCA9IGFycmF5X3NsaWNlKCR5X3ZhbHVlLCAwLCAkbSk7CiAKICAgICR6MiA9ICR0aGlzLT5fa2FyYXRzdWJhKCR4MSwgJHkxKTsKICAgICR6MCA9ICR0aGlzLT5fa2FyYXRzdWJhKCR4MCwgJHkwKTsKIAogICAgJHoxID0gJHRoaXMtPl9hZGQoJHgxLCBmYWxzZSwgJHgwLCBmYWxzZSk7CiAgICAkdGVtcCA9ICR0aGlzLT5fYWRkKCR5MSwgZmFsc2UsICR5MCwgZmFsc2UpOwogICAgJHoxID0gJHRoaXMtPl9rYXJhdHN1YmEoJHoxW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0pOwogICAgJHRlbXAgPSAkdGhpcy0+X2FkZCgkejIsIGZhbHNlLCAkejAsIGZhbHNlKTsKICAgICR6MSA9ICR0aGlzLT5fc3VidHJhY3QoJHoxLCBmYWxzZSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UpOwogCiAgICAkejIgPSBhcnJheV9tZXJnZShhcnJheV9maWxsKDAsIDIgKiAkbSwgMCksICR6Mik7CiAgICAkejFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSA9IGFycmF5X21lcmdlKGFycmF5X2ZpbGwoMCwgJG0sIDApLCAkejFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSk7CiAKICAgICR4eSA9ICR0aGlzLT5fYWRkKCR6MiwgZmFsc2UsICR6MVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkejFbTUFUSF9CSUdJTlRFR0VSX1NJR05dKTsKICAgICR4eSA9ICR0aGlzLT5fYWRkKCR4eVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkeHlbTUFUSF9CSUdJTlRFR0VSX1NJR05dLCAkejAsIGZhbHNlKTsKIAogICAgcmV0dXJuICR4eVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdOwogIH0KIAogIGZ1bmN0aW9uIF9zcXVhcmUoJHggPSBmYWxzZSkgewogICAgcmV0dXJuIGNvdW50KCR4KSA8IDIgKiBNQVRIX0JJR0lOVEVHRVJfS0FSQVRTVUJBX0NVVE9GRiA/CiAgICAgICR0aGlzLT5fdHJpbSgkdGhpcy0+X2Jhc2VTcXVhcmUoJHgpKSA6CiAgICAgICR0aGlzLT5fdHJpbSgkdGhpcy0+X2thcmF0c3ViYVNxdWFyZSgkeCkpOwogIH0KIAogIGZ1bmN0aW9uIF9iYXNlU3F1YXJlKCR2YWx1ZSkgewogICAgaWYgKCBlbXB0eSgkdmFsdWUpICkgewogICAgICByZXR1cm4gYXJyYXkoKTsKICAgIH0KICAgICRzcXVhcmVfdmFsdWUgPSAkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAyICogY291bnQoJHZhbHVlKSk7CiAKICAgIGZvciAoJGkgPSAwLCAkbWF4X2luZGV4ID0gY291bnQoJHZhbHVlKSAtIDE7ICRpIDw9ICRtYXhfaW5kZXg7ICsrJGkpIHsKICAgICAgJGkyID0gJGkgPDwgMTsKIAogICAgICAkdGVtcCA9ICRzcXVhcmVfdmFsdWVbJGkyXSArICR2YWx1ZVskaV0gKiAkdmFsdWVbJGldOwogICAgICAkY2FycnkgPSAoaW50KSAoJHRlbXAgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKTsKICAgICAgJHNxdWFyZV92YWx1ZVskaTJdID0gKGludCkgKCR0ZW1wIC0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICRjYXJyeSk7CiAKICAgICAgLy8gbm90ZSBob3cgd2Ugc3RhcnQgZnJvbSAkaSsxIGluc3RlYWQgb2YgMCBhcyB3ZSBkbyBpbiBtdWx0aXBsaWNhdGlvbi4KICAgICAgZm9yICgkaiA9ICRpICsgMSwgJGsgPSAkaTIgKyAxOyAkaiA8PSAkbWF4X2luZGV4OyArKyRqLCArKyRrKSB7CiAgICAgICAgJHRlbXAgPSAkc3F1YXJlX3ZhbHVlWyRrXSArIDIgKiAkdmFsdWVbJGpdICogJHZhbHVlWyRpXSArICRjYXJyeTsKICAgICAgICAkY2FycnkgPSAoaW50KSAoJHRlbXAgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKTsKICAgICAgICAkc3F1YXJlX3ZhbHVlWyRrXSA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAkY2FycnkpOwogICAgICB9CiAKICAgICAgLy8gdGhlIGZvbGxvd2luZyBsaW5lIGNhbiB5aWVsZCB2YWx1ZXMgbGFyZ2VyIDIqKjE1LiAgYXQgdGhpcyBwb2ludCwgUEhQIHNob3VsZCBzd2l0Y2gKICAgICAgLy8gb3ZlciB0byBmbG9hdHMuCiAgICAgICRzcXVhcmVfdmFsdWVbJGkgKyAkbWF4X2luZGV4ICsgMV0gPSAkY2Fycnk7CiAgICB9CiAKICAgIHJldHVybiAkc3F1YXJlX3ZhbHVlOwogIH0KIAogIGZ1bmN0aW9uIF9rYXJhdHN1YmFTcXVhcmUoJHZhbHVlKSB7CiAgICAkbSA9IGNvdW50KCR2YWx1ZSkgPj4gMTsKIAogICAgaWYgKCRtIDwgTUFUSF9CSUdJTlRFR0VSX0tBUkFUU1VCQV9DVVRPRkYpIHsKICAgICAgcmV0dXJuICR0aGlzLT5fYmFzZVNxdWFyZSgkdmFsdWUpOwogICAgfQogCiAgICAkeDEgPSBhcnJheV9zbGljZSgkdmFsdWUsICRtKTsKICAgICR4MCA9IGFycmF5X3NsaWNlKCR2YWx1ZSwgMCwgJG0pOwogCiAgICAkejIgPSAkdGhpcy0+X2thcmF0c3ViYVNxdWFyZSgkeDEpOwogICAgJHowID0gJHRoaXMtPl9rYXJhdHN1YmFTcXVhcmUoJHgwKTsKIAogICAgJHoxID0gJHRoaXMtPl9hZGQoJHgxLCBmYWxzZSwgJHgwLCBmYWxzZSk7CiAgICAkejEgPSAkdGhpcy0+X2thcmF0c3ViYVNxdWFyZSgkejFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSk7CiAgICAkdGVtcCA9ICR0aGlzLT5fYWRkKCR6MiwgZmFsc2UsICR6MCwgZmFsc2UpOwogICAgJHoxID0gJHRoaXMtPl9zdWJ0cmFjdCgkejEsIGZhbHNlLCAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSk7CiAKICAgICR6MiA9IGFycmF5X21lcmdlKGFycmF5X2ZpbGwoMCwgMiAqICRtLCAwKSwgJHoyKTsKICAgICR6MVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdID0gYXJyYXlfbWVyZ2UoYXJyYXlfZmlsbCgwLCAkbSwgMCksICR6MVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdKTsKIAogICAgJHh4ID0gJHRoaXMtPl9hZGQoJHoyLCBmYWxzZSwgJHoxW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR6MVtNQVRIX0JJR0lOVEVHRVJfU0lHTl0pOwogICAgJHh4ID0gJHRoaXMtPl9hZGQoJHh4W01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR4eFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICR6MCwgZmFsc2UpOwogCiAgICByZXR1cm4gJHh4W01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgfQogCiAgZnVuY3Rpb24gZGl2aWRlKCR5KSB7CiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgJHF1b3RpZW50ID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICRyZW1haW5kZXIgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAKICAgICAgICBsaXN0KCRxdW90aWVudC0+dmFsdWUsICRyZW1haW5kZXItPnZhbHVlKSA9IGdtcF9kaXZfcXIoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUpOwogCiAgICAgICAgaWYgKGdtcF9zaWduKCRyZW1haW5kZXItPnZhbHVlKSA8IDApIHsKICAgICAgICAgICRyZW1haW5kZXItPnZhbHVlID0gZ21wX2FkZCgkcmVtYWluZGVyLT52YWx1ZSwgZ21wX2FicygkeS0+dmFsdWUpKTsKICAgICAgICB9CiAKICAgICAgICByZXR1cm4gYXJyYXkoJHRoaXMtPl9ub3JtYWxpemUoJHF1b3RpZW50KSwgJHRoaXMtPl9ub3JtYWxpemUoJHJlbWFpbmRlcikpOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkcXVvdGllbnQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHJlbWFpbmRlciA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKIAogICAgICAgICRxdW90aWVudC0+dmFsdWUgPSBiY2RpdigkdGhpcy0+dmFsdWUsICR5LT52YWx1ZSwgMCk7CiAgICAgICAgJHJlbWFpbmRlci0+dmFsdWUgPSBiY21vZCgkdGhpcy0+dmFsdWUsICR5LT52YWx1ZSk7CiAKICAgICAgICBpZiAoJHJlbWFpbmRlci0+dmFsdWVbMF0gPT0gJy0nKSB7CiAgICAgICAgICAkcmVtYWluZGVyLT52YWx1ZSA9IGJjYWRkKCRyZW1haW5kZXItPnZhbHVlLCAkeS0+dmFsdWVbMF0gPT0gJy0nID8gc3Vic3RyKCR5LT52YWx1ZSwgMSkgOiAkeS0+dmFsdWUsIDApOwogICAgICAgIH0KIAogICAgICAgIHJldHVybiBhcnJheSgkdGhpcy0+X25vcm1hbGl6ZSgkcXVvdGllbnQpLCAkdGhpcy0+X25vcm1hbGl6ZSgkcmVtYWluZGVyKSk7CiAgICB9CiAKICAgIGlmIChjb3VudCgkeS0+dmFsdWUpID09IDEpIHsKICAgICAgbGlzdCgkcSwgJHIpID0gJHRoaXMtPl9kaXZpZGVfZGlnaXQoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWVbMF0pOwogICAgICAkcXVvdGllbnQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRyZW1haW5kZXIgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRxdW90aWVudC0+dmFsdWUgPSAkcTsKICAgICAgJHJlbWFpbmRlci0+dmFsdWUgPSBhcnJheSgkcik7CiAgICAgICRxdW90aWVudC0+aXNfbmVnYXRpdmUgPSAkdGhpcy0+aXNfbmVnYXRpdmUgIT0gJHktPmlzX25lZ2F0aXZlOwogICAgICByZXR1cm4gYXJyYXkoJHRoaXMtPl9ub3JtYWxpemUoJHF1b3RpZW50KSwgJHRoaXMtPl9ub3JtYWxpemUoJHJlbWFpbmRlcikpOwogICAgfQogCiAgICBzdGF0aWMgJHplcm87CiAgICBpZiAoICFpc3NldCgkemVybykgKSB7CiAgICAgICR6ZXJvID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgfQogCiAgICAkeCA9ICR0aGlzLT5jb3B5KCk7CiAgICAkeSA9ICR5LT5jb3B5KCk7CiAKICAgICR4X3NpZ24gPSAkeC0+aXNfbmVnYXRpdmU7CiAgICAkeV9zaWduID0gJHktPmlzX25lZ2F0aXZlOwogCiAgICAkeC0+aXNfbmVnYXRpdmUgPSAkeS0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKIAogICAgJGRpZmYgPSAkeC0+Y29tcGFyZSgkeSk7CiAKICAgIGlmICggISRkaWZmICkgewogICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJHRlbXAtPnZhbHVlID0gYXJyYXkoMSk7CiAgICAgICR0ZW1wLT5pc19uZWdhdGl2ZSA9ICR4X3NpZ24gIT0gJHlfc2lnbjsKICAgICAgcmV0dXJuIGFycmF5KCR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKSwgJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigpKSk7CiAgICB9CiAKICAgIGlmICggJGRpZmYgPCAwICkgewogICAgICAvLyBpZiAkeCBpcyBuZWdhdGl2ZSwgImFkZCIgJHkuCiAgICAgIGlmICggJHhfc2lnbiApIHsKICAgICAgICAkeCA9ICR5LT5zdWJ0cmFjdCgkeCk7CiAgICAgIH0KICAgICAgcmV0dXJuIGFycmF5KCR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoKSksICR0aGlzLT5fbm9ybWFsaXplKCR4KSk7CiAgICB9CiAKICAgIC8vIG5vcm1hbGl6ZSAkeCBhbmQgJHkgYXMgZGVzY3JpYmVkIGluIEhBQyAxNC4yMyAvIDE0LjI0CiAgICAkbXNiID0gJHktPnZhbHVlW2NvdW50KCR5LT52YWx1ZSkgLSAxXTsKICAgIGZvciAoJHNoaWZ0ID0gMDsgISgkbXNiICYgTUFUSF9CSUdJTlRFR0VSX01TQik7ICsrJHNoaWZ0KSB7CiAgICAgICRtc2IgPDw9IDE7CiAgICB9CiAgICAkeC0+X2xzaGlmdCgkc2hpZnQpOwogICAgJHktPl9sc2hpZnQoJHNoaWZ0KTsKICAgICR5X3ZhbHVlID0gJiR5LT52YWx1ZTsKIAogICAgJHhfbWF4ID0gY291bnQoJHgtPnZhbHVlKSAtIDE7CiAgICAkeV9tYXggPSBjb3VudCgkeS0+dmFsdWUpIC0gMTsKIAogICAgJHF1b3RpZW50ID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJHF1b3RpZW50X3ZhbHVlID0gJiRxdW90aWVudC0+dmFsdWU7CiAgICAkcXVvdGllbnRfdmFsdWUgPSAkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkeF9tYXggLSAkeV9tYXggKyAxKTsKIAogICAgc3RhdGljICR0ZW1wLCAkbGhzLCAkcmhzOwogICAgaWYgKCFpc3NldCgkdGVtcCkpIHsKICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRsaHMgPSAgbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcmhzID0gIG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgIH0KICAgICR0ZW1wX3ZhbHVlID0gJiR0ZW1wLT52YWx1ZTsKICAgICRyaHNfdmFsdWUgPSAgJiRyaHMtPnZhbHVlOwogCiAgICAvLyAkdGVtcCA9ICR5IDw8ICgkeF9tYXggLSAkeV9tYXgtMSkgaW4gYmFzZSAyKioyNgogICAgJHRlbXBfdmFsdWUgPSBhcnJheV9tZXJnZSgkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkeF9tYXggLSAkeV9tYXgpLCAkeV92YWx1ZSk7CiAKICAgIHdoaWxlICggJHgtPmNvbXBhcmUoJHRlbXApID49IDAgKSB7CiAgICAgIC8vIGNhbGN1bGF0ZSB0aGUgImNvbW1vbiByZXNpZHVlIgogICAgICArKyRxdW90aWVudF92YWx1ZVskeF9tYXggLSAkeV9tYXhdOwogICAgICAkeCA9ICR4LT5zdWJ0cmFjdCgkdGVtcCk7CiAgICAgICR4X21heCA9IGNvdW50KCR4LT52YWx1ZSkgLSAxOwogICAgfQogCiAgICBmb3IgKCRpID0gJHhfbWF4OyAkaSA+PSAkeV9tYXggKyAxOyAtLSRpKSB7CiAgICAgICR4X3ZhbHVlID0gJiR4LT52YWx1ZTsKICAgICAgJHhfd2luZG93ID0gYXJyYXkoCiAgICAgICAgaXNzZXQoJHhfdmFsdWVbJGldKSA/ICR4X3ZhbHVlWyRpXSA6IDAsCiAgICAgICAgaXNzZXQoJHhfdmFsdWVbJGkgLSAxXSkgPyAkeF92YWx1ZVskaSAtIDFdIDogMCwKICAgICAgICBpc3NldCgkeF92YWx1ZVskaSAtIDJdKSA/ICR4X3ZhbHVlWyRpIC0gMl0gOiAwCiAgICAgICk7CiAgICAgICR5X3dpbmRvdyA9IGFycmF5KAogICAgICAgICR5X3ZhbHVlWyR5X21heF0sCiAgICAgICAgKCAkeV9tYXggPiAwICkgPyAkeV92YWx1ZVskeV9tYXggLSAxXSA6IDAKICAgICAgKTsKIAogICAgICAkcV9pbmRleCA9ICRpIC0gJHlfbWF4IC0gMTsKICAgICAgaWYgKCR4X3dpbmRvd1swXSA9PSAkeV93aW5kb3dbMF0pIHsKICAgICAgICAkcXVvdGllbnRfdmFsdWVbJHFfaW5kZXhdID0gTUFUSF9CSUdJTlRFR0VSX01BWF9ESUdJVDsKICAgICAgfSBlbHNlIHsKICAgICAgICAkcXVvdGllbnRfdmFsdWVbJHFfaW5kZXhdID0gKGludCkgKAogICAgICAgICAgKCR4X3dpbmRvd1swXSAqIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKyAkeF93aW5kb3dbMV0pCiAgICAgICAgICAvCiAgICAgICAgICAkeV93aW5kb3dbMF0KICAgICAgICApOwogICAgICB9CiAKICAgICAgJHRlbXBfdmFsdWUgPSBhcnJheSgkeV93aW5kb3dbMV0sICR5X3dpbmRvd1swXSk7CiAKICAgICAgJGxocy0+dmFsdWUgPSBhcnJheSgkcXVvdGllbnRfdmFsdWVbJHFfaW5kZXhdKTsKICAgICAgJGxocyA9ICRsaHMtPm11bHRpcGx5KCR0ZW1wKTsKIAogICAgICAkcmhzX3ZhbHVlID0gYXJyYXkoJHhfd2luZG93WzJdLCAkeF93aW5kb3dbMV0sICR4X3dpbmRvd1swXSk7CiAKICAgICAgd2hpbGUgKCAkbGhzLT5jb21wYXJlKCRyaHMpID4gMCApIHsKICAgICAgICAtLSRxdW90aWVudF92YWx1ZVskcV9pbmRleF07CiAKICAgICAgICAkbGhzLT52YWx1ZSA9IGFycmF5KCRxdW90aWVudF92YWx1ZVskcV9pbmRleF0pOwogICAgICAgICRsaHMgPSAkbGhzLT5tdWx0aXBseSgkdGVtcCk7CiAgICAgIH0KIAogICAgICAkYWRqdXN0ID0gJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgJHFfaW5kZXgpOwogICAgICAkdGVtcF92YWx1ZSA9IGFycmF5KCRxdW90aWVudF92YWx1ZVskcV9pbmRleF0pOwogICAgICAkdGVtcCA9ICR0ZW1wLT5tdWx0aXBseSgkeSk7CiAgICAgICR0ZW1wX3ZhbHVlID0gJiR0ZW1wLT52YWx1ZTsKICAgICAgJHRlbXBfdmFsdWUgPSBhcnJheV9tZXJnZSgkYWRqdXN0LCAkdGVtcF92YWx1ZSk7CiAKICAgICAgJHggPSAkeC0+c3VidHJhY3QoJHRlbXApOwogCiAgICAgIGlmICgkeC0+Y29tcGFyZSgkemVybykgPCAwKSB7CiAgICAgICAgJHRlbXBfdmFsdWUgPSBhcnJheV9tZXJnZSgkYWRqdXN0LCAkeV92YWx1ZSk7CiAgICAgICAgJHggPSAkeC0+YWRkKCR0ZW1wKTsKIAogICAgICAgIC0tJHF1b3RpZW50X3ZhbHVlWyRxX2luZGV4XTsKICAgICAgfQogCiAgICAgICR4X21heCA9IGNvdW50KCR4X3ZhbHVlKSAtIDE7CiAgICB9CiAKICAgICR4LT5fcnNoaWZ0KCRzaGlmdCk7CiAKICAgICRxdW90aWVudC0+aXNfbmVnYXRpdmUgPSAkeF9zaWduICE9ICR5X3NpZ247CiAKICAgIGlmICggJHhfc2lnbiApIHsKICAgICAgJHktPl9yc2hpZnQoJHNoaWZ0KTsKICAgICAgJHggPSAkeS0+c3VidHJhY3QoJHgpOwogICAgfQogCiAgICByZXR1cm4gYXJyYXkoJHRoaXMtPl9ub3JtYWxpemUoJHF1b3RpZW50KSwgJHRoaXMtPl9ub3JtYWxpemUoJHgpKTsKICB9CiAKICBmdW5jdGlvbiBfZGl2aWRlX2RpZ2l0KCRkaXZpZGVuZCwgJGRpdmlzb3IpIHsKICAgICRjYXJyeSA9IDA7CiAgICAkcmVzdWx0ID0gYXJyYXkoKTsKIAogICAgZm9yICgkaSA9IGNvdW50KCRkaXZpZGVuZCkgLSAxOyAkaSA+PSAwOyAtLSRpKSB7CiAgICAgICR0ZW1wID0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICRjYXJyeSArICRkaXZpZGVuZFskaV07CiAgICAgICRyZXN1bHRbJGldID0gKGludCkgKCR0ZW1wIC8gJGRpdmlzb3IpOwogICAgICAkY2FycnkgPSAoaW50KSAoJHRlbXAgLSAkZGl2aXNvciAqICRyZXN1bHRbJGldKTsKICAgIH0KIAogICAgcmV0dXJuIGFycmF5KCRyZXN1bHQsICRjYXJyeSk7CiAgfQogCiAgZnVuY3Rpb24gbW9kUG93KCRlLCAkbikgewogICAgJG4gPSAkdGhpcy0+Yml0bWFzayAhPT0gZmFsc2UgJiYgJHRoaXMtPmJpdG1hc2stPmNvbXBhcmUoJG4pIDwgMCA/ICR0aGlzLT5iaXRtYXNrIDogJG4tPmFicygpOwogCiAgICBpZiAoJGUtPmNvbXBhcmUobmV3IE1hdGhfQmlnSW50ZWdlcigpKSA8IDApIHsKICAgICAgJGUgPSAkZS0+YWJzKCk7CiAKICAgICAgJHRlbXAgPSAkdGhpcy0+bW9kSW52ZXJzZSgkbik7CiAgICAgIGlmICgkdGVtcCA9PT0gZmFsc2UpIHsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0KIAogICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXAtPm1vZFBvdygkZSwgJG4pKTsKICAgIH0KIAogICAgaWYgKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVAgKSB7CiAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfcG93bSgkdGhpcy0+dmFsdWUsICRlLT52YWx1ZSwgJG4tPnZhbHVlKTsKIAogICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgfQogCiAgICBpZiAoJHRoaXMtPmNvbXBhcmUobmV3IE1hdGhfQmlnSW50ZWdlcigpKSA8IDAgfHwgJHRoaXMtPmNvbXBhcmUoJG4pID4gMCkgewogICAgICBsaXN0KCwgJHRlbXApID0gJHRoaXMtPmRpdmlkZSgkbik7CiAgICAgIHJldHVybiAkdGVtcC0+bW9kUG93KCRlLCAkbik7CiAgICB9CiAKICAgIGlmIChkZWZpbmVkKCdNQVRIX0JJR0lOVEVHRVJfT1BFTlNTTF9FTkFCTEVEJykpIHsKICAgICAgJGNvbXBvbmVudHMgPSBhcnJheSgKICAgICAgICAnbW9kdWx1cycgPT4gJG4tPnRvQnl0ZXModHJ1ZSksCiAgICAgICAgJ3B1YmxpY0V4cG9uZW50JyA9PiAkZS0+dG9CeXRlcyh0cnVlKQogICAgICApOwogCiAgICAgICRjb21wb25lbnRzID0gYXJyYXkoCiAgICAgICAgJ21vZHVsdXMnID0+IHBhY2soJ0NhKmEqJywgMiwgJHRoaXMtPl9lbmNvZGVBU04xTGVuZ3RoKHN0cmxlbigkY29tcG9uZW50c1snbW9kdWx1cyddKSksICRjb21wb25lbnRzWydtb2R1bHVzJ10pLAogICAgICAgICdwdWJsaWNFeHBvbmVudCcgPT4gcGFjaygnQ2EqYSonLCAyLCAkdGhpcy0+X2VuY29kZUFTTjFMZW5ndGgoc3RybGVuKCRjb21wb25lbnRzWydwdWJsaWNFeHBvbmVudCddKSksICRjb21wb25lbnRzWydwdWJsaWNFeHBvbmVudCddKQogICAgICApOwogCiAgICAgICRSU0FQdWJsaWNLZXkgPSBwYWNrKCdDYSphKmEqJywKICAgICAgICA0OCwgJHRoaXMtPl9lbmNvZGVBU04xTGVuZ3RoKHN0cmxlbigkY29tcG9uZW50c1snbW9kdWx1cyddKSArIHN0cmxlbigkY29tcG9uZW50c1sncHVibGljRXhwb25lbnQnXSkpLAogICAgICAgICRjb21wb25lbnRzWydtb2R1bHVzJ10sICRjb21wb25lbnRzWydwdWJsaWNFeHBvbmVudCddCiAgICAgICk7CiAKICAgICAgJHJzYU9JRCA9IHBhY2soJ0gqJywgJzMwMGQwNjA5MmE4NjQ4ODZmNzBkMDEwMTAxMDUwMCcpOyAvLyBoZXggdmVyc2lvbiBvZiBNQTBHQ1NxR1NJYjNEUUVCQVFVQQogICAgICAkUlNBUHVibGljS2V5ID0gY2hyKDApIC4gJFJTQVB1YmxpY0tleTsKICAgICAgJFJTQVB1YmxpY0tleSA9IGNocigzKSAuICR0aGlzLT5fZW5jb2RlQVNOMUxlbmd0aChzdHJsZW4oJFJTQVB1YmxpY0tleSkpIC4gJFJTQVB1YmxpY0tleTsKIAogICAgICAkZW5jYXBzdWxhdGVkID0gcGFjaygnQ2EqYSonLAogICAgICAgIDQ4LCAkdGhpcy0+X2VuY29kZUFTTjFMZW5ndGgoc3RybGVuKCRyc2FPSUQgLiAkUlNBUHVibGljS2V5KSksICRyc2FPSUQgLiAkUlNBUHVibGljS2V5CiAgICAgICk7CiAKICAgICAgJFJTQVB1YmxpY0tleSA9ICItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxyXG4iIC4KICAgICAgICAgICAgICAgY2h1bmtfc3BsaXQoYmFzZTY0X2VuY29kZSgkZW5jYXBzdWxhdGVkKSkgLgogICAgICAgICAgICAgICAnLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tJzsKIAogICAgICAkcGxhaW50ZXh0ID0gc3RyX3BhZCgkdGhpcy0+dG9CeXRlcygpLCBzdHJsZW4oJG4tPnRvQnl0ZXModHJ1ZSkpIC0gMSwgIlwwIiwgU1RSX1BBRF9MRUZUKTsKIAogICAgICBpZiAob3BlbnNzbF9wdWJsaWNfZW5jcnlwdCgkcGxhaW50ZXh0LCAkcmVzdWx0LCAkUlNBUHVibGljS2V5LCBPUEVOU1NMX05PX1BBRERJTkcpKSB7CiAgICAgICAgcmV0dXJuIG5ldyBNYXRoX0JpZ0ludGVnZXIoJHJlc3VsdCwgMjU2KTsKICAgICAgfQogICAgfQogCiAgICBpZiAoIE1BVEhfQklHSU5URUdFUl9NT0RFID09IE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSCApIHsKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY3Bvd21vZCgkdGhpcy0+dmFsdWUsICRlLT52YWx1ZSwgJG4tPnZhbHVlLCAwKTsKIAogICAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CiAKICAgIGlmICggZW1wdHkoJGUtPnZhbHVlKSApIHsKICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICR0ZW1wLT52YWx1ZSA9IGFycmF5KDEpOwogICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgfQogCiAgICBpZiAoICRlLT52YWx1ZSA9PSBhcnJheSgxKSApIHsKICAgICAgbGlzdCgsICR0ZW1wKSA9ICR0aGlzLT5kaXZpZGUoJG4pOwogICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgfQogCiAgICBpZiAoICRlLT52YWx1ZSA9PSBhcnJheSgyKSApIHsKICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICR0ZW1wLT52YWx1ZSA9ICR0aGlzLT5fc3F1YXJlKCR0aGlzLT52YWx1ZSk7CiAgICAgIGxpc3QoLCAkdGVtcCkgPSAkdGVtcC0+ZGl2aWRlKCRuKTsKICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICAgIH0KIAogICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0aGlzLT5fc2xpZGluZ1dpbmRvdygkZSwgJG4sIE1BVEhfQklHSU5URUdFUl9CQVJSRVRUKSk7CiAKICAgIGlmICggJG4tPnZhbHVlWzBdICYgMSApIHsKICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0aGlzLT5fc2xpZGluZ1dpbmRvdygkZSwgJG4sIE1BVEhfQklHSU5URUdFUl9NT05UR09NRVJZKSk7CiAgICB9CiAgICBmb3IgKCRpID0gMDsgJGkgPCBjb3VudCgkbi0+dmFsdWUpOyArKyRpKSB7CiAgICAgIGlmICggJG4tPnZhbHVlWyRpXSApIHsKICAgICAgICAkdGVtcCA9IGRlY2Jpbigkbi0+dmFsdWVbJGldKTsKICAgICAgICAkaiA9IHN0cmxlbigkdGVtcCkgLSBzdHJycG9zKCR0ZW1wLCAnMScpIC0gMTsKICAgICAgICAkais9IDI2ICogJGk7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH0KIAogICAgJG1vZDEgPSAkbi0+Y29weSgpOwogICAgJG1vZDEtPl9yc2hpZnQoJGopOwogICAgJG1vZDIgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkbW9kMi0+dmFsdWUgPSBhcnJheSgxKTsKICAgICRtb2QyLT5fbHNoaWZ0KCRqKTsKIAogICAgJHBhcnQxID0gKCAkbW9kMS0+dmFsdWUgIT0gYXJyYXkoMSkgKSA/ICR0aGlzLT5fc2xpZGluZ1dpbmRvdygkZSwgJG1vZDEsIE1BVEhfQklHSU5URUdFUl9NT05UR09NRVJZKSA6IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRwYXJ0MiA9ICR0aGlzLT5fc2xpZGluZ1dpbmRvdygkZSwgJG1vZDIsIE1BVEhfQklHSU5URUdFUl9QT1dFUk9GMik7CiAKICAgICR5MSA9ICRtb2QyLT5tb2RJbnZlcnNlKCRtb2QxKTsKICAgICR5MiA9ICRtb2QxLT5tb2RJbnZlcnNlKCRtb2QyKTsKIAogICAgJHJlc3VsdCA9ICRwYXJ0MS0+bXVsdGlwbHkoJG1vZDIpOwogICAgJHJlc3VsdCA9ICRyZXN1bHQtPm11bHRpcGx5KCR5MSk7CiAKICAgICR0ZW1wID0gJHBhcnQyLT5tdWx0aXBseSgkbW9kMSk7CiAgICAkdGVtcCA9ICR0ZW1wLT5tdWx0aXBseSgkeTIpOwogCiAgICAkcmVzdWx0ID0gJHJlc3VsdC0+YWRkKCR0ZW1wKTsKICAgIGxpc3QoLCAkcmVzdWx0KSA9ICRyZXN1bHQtPmRpdmlkZSgkbik7CiAKICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkcmVzdWx0KTsKICB9CiAKICBmdW5jdGlvbiBwb3dNb2QoJGUsICRuKSB7CiAgICByZXR1cm4gJHRoaXMtPm1vZFBvdygkZSwgJG4pOwogIH0KIAogIGZ1bmN0aW9uIF9zbGlkaW5nV2luZG93KCRlLCAkbiwgJG1vZGUpIHsKICAgIHN0YXRpYyAkd2luZG93X3JhbmdlcyA9IGFycmF5KDcsIDI1LCA4MSwgMjQxLCA2NzMsIDE3OTMpOwogCiAgICAkZV92YWx1ZSA9ICRlLT52YWx1ZTsKICAgICRlX2xlbmd0aCA9IGNvdW50KCRlX3ZhbHVlKSAtIDE7CiAgICAkZV9iaXRzID0gZGVjYmluKCRlX3ZhbHVlWyRlX2xlbmd0aF0pOwogICAgZm9yICgkaSA9ICRlX2xlbmd0aCAtIDE7ICRpID49IDA7IC0tJGkpIHsKICAgICAgJGVfYml0cy49IHN0cl9wYWQoZGVjYmluKCRlX3ZhbHVlWyRpXSksIE1BVEhfQklHSU5URUdFUl9CQVNFLCAnMCcsIFNUUl9QQURfTEVGVCk7CiAgICB9CiAKICAgICRlX2xlbmd0aCA9IHN0cmxlbigkZV9iaXRzKTsKIAogICAgZm9yICgkaSA9IDAsICR3aW5kb3dfc2l6ZSA9IDE7ICRlX2xlbmd0aCA+ICR3aW5kb3dfcmFuZ2VzWyRpXSAmJiAkaSA8IGNvdW50KCR3aW5kb3dfcmFuZ2VzKTsgKyskd2luZG93X3NpemUsICsrJGkpOwogCiAgICAkbl92YWx1ZSA9ICRuLT52YWx1ZTsKIAogICAgJHBvd2VycyA9IGFycmF5KCk7CiAgICAkcG93ZXJzWzFdID0gJHRoaXMtPl9wcmVwYXJlUmVkdWNlKCR0aGlzLT52YWx1ZSwgJG5fdmFsdWUsICRtb2RlKTsKICAgICRwb3dlcnNbMl0gPSAkdGhpcy0+X3NxdWFyZVJlZHVjZSgkcG93ZXJzWzFdLCAkbl92YWx1ZSwgJG1vZGUpOwogCiAgICAkdGVtcCA9IDEgPDwgKCR3aW5kb3dfc2l6ZSAtIDEpOwogICAgZm9yICgkaSA9IDE7ICRpIDwgJHRlbXA7ICsrJGkpIHsKICAgICAgJGkyID0gJGkgPDwgMTsKICAgICAgJHBvd2Vyc1skaTIgKyAxXSA9ICR0aGlzLT5fbXVsdGlwbHlSZWR1Y2UoJHBvd2Vyc1skaTIgLSAxXSwgJHBvd2Vyc1syXSwgJG5fdmFsdWUsICRtb2RlKTsKICAgIH0KIAogICAgJHJlc3VsdCA9IGFycmF5KDEpOwogICAgJHJlc3VsdCA9ICR0aGlzLT5fcHJlcGFyZVJlZHVjZSgkcmVzdWx0LCAkbl92YWx1ZSwgJG1vZGUpOwogCiAgICBmb3IgKCRpID0gMDsgJGkgPCAkZV9sZW5ndGg7ICkgewogICAgICBpZiAoICEkZV9iaXRzWyRpXSApIHsKICAgICAgICAkcmVzdWx0ID0gJHRoaXMtPl9zcXVhcmVSZWR1Y2UoJHJlc3VsdCwgJG5fdmFsdWUsICRtb2RlKTsKICAgICAgICArKyRpOwogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoJGogPSAkd2luZG93X3NpemUgLSAxOyAkaiA+IDA7IC0tJGopIHsKICAgICAgICAgIGlmICggIWVtcHR5KCRlX2JpdHNbJGkgKyAkal0pICkgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAKICAgICAgICBmb3IgKCRrID0gMDsgJGsgPD0gJGo7ICsrJGspIHsvLyBlZy4gdGhlIGxlbmd0aCBvZiBzdWJzdHIoJGVfYml0cywgJGksICRqKzEpCiAgICAgICAgICAkcmVzdWx0ID0gJHRoaXMtPl9zcXVhcmVSZWR1Y2UoJHJlc3VsdCwgJG5fdmFsdWUsICRtb2RlKTsKICAgICAgICB9CiAKICAgICAgICAkcmVzdWx0ID0gJHRoaXMtPl9tdWx0aXBseVJlZHVjZSgkcmVzdWx0LCAkcG93ZXJzW2JpbmRlYyhzdWJzdHIoJGVfYml0cywgJGksICRqICsgMSkpXSwgJG5fdmFsdWUsICRtb2RlKTsKIAogICAgICAgICRpKz0kaiArIDE7CiAgICAgIH0KICAgIH0KIAogICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkdGVtcC0+dmFsdWUgPSAkdGhpcy0+X3JlZHVjZSgkcmVzdWx0LCAkbl92YWx1ZSwgJG1vZGUpOwogCiAgICByZXR1cm4gJHRlbXA7CiAgfQogCiAgZnVuY3Rpb24gX3JlZHVjZSgkeCwgJG4sICRtb2RlKSB7CiAgICBzd2l0Y2ggKCRtb2RlKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PTlRHT01FUlk6CiAgICAgICAgcmV0dXJuICR0aGlzLT5fbW9udGdvbWVyeSgkeCwgJG4pOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9CQVJSRVRUOgogICAgICAgIHJldHVybiAkdGhpcy0+X2JhcnJldHQoJHgsICRuKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfUE9XRVJPRjI6CiAgICAgICAgJGxocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkbGhzLT52YWx1ZSA9ICR4OwogICAgICAgICRyaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHJocy0+dmFsdWUgPSAkbjsKICAgICAgICByZXR1cm4gJHgtPl9tb2QyKCRuKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfQ0xBU1NJQzoKICAgICAgICAkbGhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICRsaHMtPnZhbHVlID0gJHg7CiAgICAgICAgJHJocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkcmhzLT52YWx1ZSA9ICRuOwogICAgICAgIGxpc3QoLCAkdGVtcCkgPSAkbGhzLT5kaXZpZGUoJHJocyk7CiAgICAgICAgcmV0dXJuICR0ZW1wLT52YWx1ZTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTk9ORToKICAgICAgICByZXR1cm4gJHg7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgLy8gYW4gaW52YWxpZCAkbW9kZSB3YXMgcHJvdmlkZWQKICAgIH0KICB9CiAKICBmdW5jdGlvbiBfcHJlcGFyZVJlZHVjZSgkeCwgJG4sICRtb2RlKSB7CiAgICBpZiAoJG1vZGUgPT0gTUFUSF9CSUdJTlRFR0VSX01PTlRHT01FUlkpIHsKICAgICAgcmV0dXJuICR0aGlzLT5fcHJlcE1vbnRnb21lcnkoJHgsICRuKTsKICAgIH0KICAgIHJldHVybiAkdGhpcy0+X3JlZHVjZSgkeCwgJG4sICRtb2RlKTsKICB9CiAKICBmdW5jdGlvbiBfbXVsdGlwbHlSZWR1Y2UoJHgsICR5LCAkbiwgJG1vZGUpIHsKICAgIGlmICgkbW9kZSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9OVEdPTUVSWSkgewogICAgICByZXR1cm4gJHRoaXMtPl9tb250Z29tZXJ5TXVsdGlwbHkoJHgsICR5LCAkbik7CiAgICB9CiAgICAkdGVtcCA9ICR0aGlzLT5fbXVsdGlwbHkoJHgsIGZhbHNlLCAkeSwgZmFsc2UpOwogICAgcmV0dXJuICR0aGlzLT5fcmVkdWNlKCR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICRuLCAkbW9kZSk7CiAgfQogCiAgZnVuY3Rpb24gX3NxdWFyZVJlZHVjZSgkeCwgJG4sICRtb2RlKSB7CiAgICBpZiAoJG1vZGUgPT0gTUFUSF9CSUdJTlRFR0VSX01PTlRHT01FUlkpIHsKICAgICAgcmV0dXJuICR0aGlzLT5fbW9udGdvbWVyeU11bHRpcGx5KCR4LCAkeCwgJG4pOwogICAgfQogICAgcmV0dXJuICR0aGlzLT5fcmVkdWNlKCR0aGlzLT5fc3F1YXJlKCR4KSwgJG4sICRtb2RlKTsKICB9CiAKICBmdW5jdGlvbiBfbW9kMigkbikgewogICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkdGVtcC0+dmFsdWUgPSBhcnJheSgxKTsKICAgIHJldHVybiAkdGhpcy0+Yml0d2lzZV9hbmQoJG4tPnN1YnRyYWN0KCR0ZW1wKSk7CiAgfQogCiAgZnVuY3Rpb24gX2JhcnJldHQoJG4sICRtKSB7CiAgICBzdGF0aWMgJGNhY2hlID0gYXJyYXkoCiAgICAgIE1BVEhfQklHSU5URUdFUl9WQVJJQUJMRSA9PiBhcnJheSgpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfREFUQSA9PiBhcnJheSgpCiAgICApOwogCiAgICAkbV9sZW5ndGggPSBjb3VudCgkbSk7CiAKICAgIGlmIChjb3VudCgkbikgPiAyICogJG1fbGVuZ3RoKSB7CiAgICAgICRsaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRyaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRsaHMtPnZhbHVlID0gJG47CiAgICAgICRyaHMtPnZhbHVlID0gJG07CiAgICAgIGxpc3QoLCAkdGVtcCkgPSAkbGhzLT5kaXZpZGUoJHJocyk7CiAgICAgIHJldHVybiAkdGVtcC0+dmFsdWU7CiAgICB9CiAKICAgIGlmICgkbV9sZW5ndGggPCA1KSB7CiAgICAgIHJldHVybiAkdGhpcy0+X3JlZ3VsYXJCYXJyZXR0KCRuLCAkbSk7CiAgICB9CiAKICAgIGlmICggKCRrZXkgPSBhcnJheV9zZWFyY2goJG0sICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdKSkgPT09IGZhbHNlICkgewogICAgICAka2V5ID0gY291bnQoJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pOwogICAgICAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXVtdID0gJG07CiAKICAgICAgJGxocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJGxoc192YWx1ZSA9ICYkbGhzLT52YWx1ZTsKICAgICAgJGxoc192YWx1ZSA9ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsICRtX2xlbmd0aCArICgkbV9sZW5ndGggPj4gMSkpOwogICAgICAkbGhzX3ZhbHVlW10gPSAxOwogICAgICAkcmhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcmhzLT52YWx1ZSA9ICRtOwogCiAgICAgIGxpc3QoJHUsICRtMSkgPSAkbGhzLT5kaXZpZGUoJHJocyk7CiAgICAgICR1ID0gJHUtPnZhbHVlOwogICAgICAkbTEgPSAkbTEtPnZhbHVlOwogCiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfREFUQV1bXSA9IGFycmF5KAogICAgICAgICd1JyA9PiAkdSwgLy8gbS5sZW5ndGggPj4gMSAodGVjaG5pY2FsbHkgKG0ubGVuZ3RoID4+IDEpICsgMSkKICAgICAgICAnbTEnPT4gJG0xIC8vIG0ubGVuZ3RoCiAgICAgICk7CiAgICB9IGVsc2UgewogICAgICBleHRyYWN0KCRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfREFUQV1bJGtleV0pOwogICAgfQogCiAgICAkY3V0b2ZmID0gJG1fbGVuZ3RoICsgKCRtX2xlbmd0aCA+PiAxKTsKICAgICRsc2QgPSBhcnJheV9zbGljZSgkbiwgMCwgJGN1dG9mZik7IC8vIG0ubGVuZ3RoICsgKG0ubGVuZ3RoID4+IDEpCiAgICAkbXNkID0gYXJyYXlfc2xpY2UoJG4sICRjdXRvZmYpOyAgLy8gbS5sZW5ndGggPj4gMQogICAgJGxzZCA9ICR0aGlzLT5fdHJpbSgkbHNkKTsKICAgICR0ZW1wID0gJHRoaXMtPl9tdWx0aXBseSgkbXNkLCBmYWxzZSwgJG0xLCBmYWxzZSk7CiAgICAkbiA9ICR0aGlzLT5fYWRkKCRsc2QsIGZhbHNlLCAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSk7IC8vIG0ubGVuZ3RoICsgKG0ubGVuZ3RoID4+IDEpICsgMQogCiAgICBpZiAoJG1fbGVuZ3RoICYgMSkgewogICAgICByZXR1cm4gJHRoaXMtPl9yZWd1bGFyQmFycmV0dCgkbltNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkbSk7CiAgICB9CiAKICAgICR0ZW1wID0gYXJyYXlfc2xpY2UoJG5bTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJG1fbGVuZ3RoIC0gMSk7CiAgICAkdGVtcCA9ICR0aGlzLT5fbXVsdGlwbHkoJHRlbXAsIGZhbHNlLCAkdSwgZmFsc2UpOwogICAgJHRlbXAgPSBhcnJheV9zbGljZSgkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAoJG1fbGVuZ3RoID4+IDEpICsgMSk7CiAgICAkdGVtcCA9ICR0aGlzLT5fbXVsdGlwbHkoJHRlbXAsIGZhbHNlLCAkbSwgZmFsc2UpOwogCiAgICAkcmVzdWx0ID0gJHRoaXMtPl9zdWJ0cmFjdCgkbltNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UpOwogCiAgICB3aGlsZSAoJHRoaXMtPl9jb21wYXJlKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICRtLCBmYWxzZSkgPj0gMCkgewogICAgICAkcmVzdWx0ID0gJHRoaXMtPl9zdWJ0cmFjdCgkcmVzdWx0W01BVEhfQklHSU5URUdFUl9WQUxVRV0sICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1NJR05dLCAkbSwgZmFsc2UpOwogICAgfQogCiAgICByZXR1cm4gJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdOwogIH0KIAogIGZ1bmN0aW9uIF9yZWd1bGFyQmFycmV0dCgkeCwgJG4pIHsKICAgIHN0YXRpYyAkY2FjaGUgPSBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFID0+IGFycmF5KCksCiAgICAgIE1BVEhfQklHSU5URUdFUl9EQVRBID0+IGFycmF5KCkKICAgICk7CiAKICAgICRuX2xlbmd0aCA9IGNvdW50KCRuKTsKIAogICAgaWYgKGNvdW50KCR4KSA+IDIgKiAkbl9sZW5ndGgpIHsKICAgICAgJGxocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJHJocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJGxocy0+dmFsdWUgPSAkeDsKICAgICAgJHJocy0+dmFsdWUgPSAkbjsKICAgICAgbGlzdCgsICR0ZW1wKSA9ICRsaHMtPmRpdmlkZSgkcmhzKTsKICAgICAgcmV0dXJuICR0ZW1wLT52YWx1ZTsKICAgIH0KIAogICAgaWYgKCAoJGtleSA9IGFycmF5X3NlYXJjaCgkbiwgJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pKSA9PT0gZmFsc2UgKSB7CiAgICAgICRrZXkgPSBjb3VudCgkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXSk7CiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdW10gPSAkbjsKICAgICAgJGxocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJGxoc192YWx1ZSA9ICYkbGhzLT52YWx1ZTsKICAgICAgJGxoc192YWx1ZSA9ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsIDIgKiAkbl9sZW5ndGgpOwogICAgICAkbGhzX3ZhbHVlW10gPSAxOwogICAgICAkcmhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcmhzLT52YWx1ZSA9ICRuOwogICAgICBsaXN0KCR0ZW1wLCApID0gJGxocy0+ZGl2aWRlKCRyaHMpOwogICAgICAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX0RBVEFdW10gPSAkdGVtcC0+dmFsdWU7CiAgICB9CiAKICAgICR0ZW1wID0gYXJyYXlfc2xpY2UoJHgsICRuX2xlbmd0aCAtIDEpOwogICAgJHRlbXAgPSAkdGhpcy0+X211bHRpcGx5KCR0ZW1wLCBmYWxzZSwgJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVska2V5XSwgZmFsc2UpOwogICAgJHRlbXAgPSBhcnJheV9zbGljZSgkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkbl9sZW5ndGggKyAxKTsKIAogICAgJHJlc3VsdCA9IGFycmF5X3NsaWNlKCR4LCAwLCAkbl9sZW5ndGggKyAxKTsKICAgICR0ZW1wID0gJHRoaXMtPl9tdWx0aXBseUxvd2VyKCR0ZW1wLCBmYWxzZSwgJG4sIGZhbHNlLCAkbl9sZW5ndGggKyAxKTsKIAogICAgaWYgKCR0aGlzLT5fY29tcGFyZSgkcmVzdWx0LCBmYWxzZSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1NJR05dKSA8IDApIHsKICAgICAgJGNvcnJlY3Rvcl92YWx1ZSA9ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsICRuX2xlbmd0aCArIDEpOwogICAgICAkY29ycmVjdG9yX3ZhbHVlW10gPSAxOwogICAgICAkcmVzdWx0ID0gJHRoaXMtPl9hZGQoJHJlc3VsdCwgZmFsc2UsICRjb3JyZWN0b3JfdmFsdWUsIGZhbHNlKTsKICAgICAgJHJlc3VsdCA9ICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXTsKICAgIH0KIAogICAgJHJlc3VsdCA9ICR0aGlzLT5fc3VidHJhY3QoJHJlc3VsdCwgZmFsc2UsICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXSk7CiAgICB3aGlsZSAoJHRoaXMtPl9jb21wYXJlKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICRuLCBmYWxzZSkgPiAwKSB7CiAgICAgICRyZXN1bHQgPSAkdGhpcy0+X3N1YnRyYWN0KCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICRuLCBmYWxzZSk7CiAgICB9CiAKICAgIHJldHVybiAkcmVzdWx0W01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgfQogCiAgZnVuY3Rpb24gX211bHRpcGx5TG93ZXIoJHhfdmFsdWUsICR4X25lZ2F0aXZlLCAkeV92YWx1ZSwgJHlfbmVnYXRpdmUsICRzdG9wKSB7CiAgICAkeF9sZW5ndGggPSBjb3VudCgkeF92YWx1ZSk7CiAgICAkeV9sZW5ndGggPSBjb3VudCgkeV92YWx1ZSk7CiAKICAgIGlmICggISR4X2xlbmd0aCB8fCAhJHlfbGVuZ3RoICkgeyAvLyBhIDAgaXMgYmVpbmcgbXVsdGlwbGllZAogICAgICByZXR1cm4gYXJyYXkoCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+IGFycmF5KCksCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gZmFsc2UKICAgICAgKTsKICAgIH0KIAogICAgaWYgKCAkeF9sZW5ndGggPCAkeV9sZW5ndGggKSB7CiAgICAgICR0ZW1wID0gJHhfdmFsdWU7CiAgICAgICR4X3ZhbHVlID0gJHlfdmFsdWU7CiAgICAgICR5X3ZhbHVlID0gJHRlbXA7CiAKICAgICAgJHhfbGVuZ3RoID0gY291bnQoJHhfdmFsdWUpOwogICAgICAkeV9sZW5ndGggPSBjb3VudCgkeV92YWx1ZSk7CiAgICB9CiAKICAgICRwcm9kdWN0X3ZhbHVlID0gJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgJHhfbGVuZ3RoICsgJHlfbGVuZ3RoKTsKIAogICAgJGNhcnJ5ID0gMDsKIAogICAgZm9yICgkaiA9IDA7ICRqIDwgJHhfbGVuZ3RoOyArKyRqKSB7IC8vIGllLiAkaSA9IDAsICRrID0gJGkKICAgICAgJHRlbXAgPSAkeF92YWx1ZVskal0gKiAkeV92YWx1ZVswXSArICRjYXJyeTsgLy8gJHByb2R1Y3RfdmFsdWVbJGtdID09IDAKICAgICAgJGNhcnJ5ID0gKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAgICAgICRwcm9kdWN0X3ZhbHVlWyRqXSA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAkY2FycnkpOwogICAgfQogCiAgICBpZiAoJGogPCAkc3RvcCkgewogICAgICAkcHJvZHVjdF92YWx1ZVskal0gPSAkY2Fycnk7CiAgICB9CiAKICAgIGZvciAoJGkgPSAxOyAkaSA8ICR5X2xlbmd0aDsgKyskaSkgewogICAgICAkY2FycnkgPSAwOwogCiAgICAgIGZvciAoJGogPSAwLCAkayA9ICRpOyAkaiA8ICR4X2xlbmd0aCAmJiAkayA8ICRzdG9wOyArKyRqLCArKyRrKSB7CiAgICAgICAgJHRlbXAgPSAkcHJvZHVjdF92YWx1ZVska10gKyAkeF92YWx1ZVskal0gKiAkeV92YWx1ZVskaV0gKyAkY2Fycnk7CiAgICAgICAgJGNhcnJ5ID0gKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAgICAgICAgJHByb2R1Y3RfdmFsdWVbJGtdID0gKGludCkgKCR0ZW1wIC0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICRjYXJyeSk7CiAgICAgIH0KIAogICAgICBpZiAoJGsgPCAkc3RvcCkgewogICAgICAgICRwcm9kdWN0X3ZhbHVlWyRrXSA9ICRjYXJyeTsKICAgICAgfQogICAgfQogCiAgICByZXR1cm4gYXJyYXkoCiAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiAkdGhpcy0+X3RyaW0oJHByb2R1Y3RfdmFsdWUpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAkeF9uZWdhdGl2ZSAhPSAkeV9uZWdhdGl2ZQogICAgKTsKICB9CiAKICBmdW5jdGlvbiBfbW9udGdvbWVyeSgkeCwgJG4pIHsKICAgIHN0YXRpYyAkY2FjaGUgPSBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFID0+IGFycmF5KCksCiAgICAgIE1BVEhfQklHSU5URUdFUl9EQVRBID0+IGFycmF5KCkKICAgICk7CiAKICAgIGlmICggKCRrZXkgPSBhcnJheV9zZWFyY2goJG4sICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdKSkgPT09IGZhbHNlICkgewogICAgICAka2V5ID0gY291bnQoJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pOwogICAgICAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXVtdID0gJHg7CiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfREFUQV1bXSA9ICR0aGlzLT5fbW9kSW52ZXJzZTY3MTA4ODY0KCRuKTsKICAgIH0KIAogICAgJGsgPSBjb3VudCgkbik7CiAKICAgICRyZXN1bHQgPSBhcnJheShNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHgpOwogCiAgICBmb3IgKCRpID0gMDsgJGkgPCAkazsgKyskaSkgewogICAgICAkdGVtcCA9ICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXVskaV0gKiAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX0RBVEFdWyRrZXldOwogICAgICAkdGVtcCA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAoKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCkpKTsKICAgICAgJHRlbXAgPSAkdGhpcy0+X3JlZ3VsYXJNdWx0aXBseShhcnJheSgkdGVtcCksICRuKTsKICAgICAgJHRlbXAgPSBhcnJheV9tZXJnZSgkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkaSksICR0ZW1wKTsKICAgICAgJHJlc3VsdCA9ICR0aGlzLT5fYWRkKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UsICR0ZW1wLCBmYWxzZSk7CiAgICB9CiAKICAgICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSA9IGFycmF5X3NsaWNlKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJGspOwogCiAgICBpZiAoJHRoaXMtPl9jb21wYXJlKCRyZXN1bHQsIGZhbHNlLCAkbiwgZmFsc2UpID49IDApIHsKICAgICAgJHJlc3VsdCA9ICR0aGlzLT5fc3VidHJhY3QoJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSwgJG4sIGZhbHNlKTsKICAgIH0KIAogICAgcmV0dXJuICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXTsKICB9CiAKICBmdW5jdGlvbiBfbW9udGdvbWVyeU11bHRpcGx5KCR4LCAkeSwgJG0pIHsKICAgICR0ZW1wID0gJHRoaXMtPl9tdWx0aXBseSgkeCwgZmFsc2UsICR5LCBmYWxzZSk7CiAgICByZXR1cm4gJHRoaXMtPl9tb250Z29tZXJ5KCR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICRtKTsKIAogICAgc3RhdGljICRjYWNoZSA9IGFycmF5KAogICAgICBNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEUgPT4gYXJyYXkoKSwKICAgICAgTUFUSF9CSUdJTlRFR0VSX0RBVEEgPT4gYXJyYXkoKQogICAgKTsKIAogICAgaWYgKCAoJGtleSA9IGFycmF5X3NlYXJjaCgkbSwgJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pKSA9PT0gZmFsc2UgKSB7CiAgICAgICRrZXkgPSBjb3VudCgkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXSk7CiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdW10gPSAkbTsKICAgICAgJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVtdID0gJHRoaXMtPl9tb2RJbnZlcnNlNjcxMDg4NjQoJG0pOwogICAgfQogCiAgICAkbiA9IG1heChjb3VudCgkeCksIGNvdW50KCR5KSwgY291bnQoJG0pKTsKICAgICR4ID0gYXJyYXlfcGFkKCR4LCAkbiwgMCk7CiAgICAkeSA9IGFycmF5X3BhZCgkeSwgJG4sIDApOwogICAgJG0gPSBhcnJheV9wYWQoJG0sICRuLCAwKTsKICAgICRhID0gYXJyYXkoTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsICRuICsgMSkpOwogICAgZm9yICgkaSA9IDA7ICRpIDwgJG47ICsrJGkpIHsKICAgICAgJHRlbXAgPSAkYVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdWzBdICsgJHhbJGldICogJHlbMF07CiAgICAgICR0ZW1wID0gKGludCkgKCR0ZW1wIC0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICgoaW50KSAoJHRlbXAgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKSkpOwogICAgICAkdGVtcCA9ICR0ZW1wICogJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVska2V5XTsKICAgICAgJHRlbXAgPSAoaW50KSAoJHRlbXAgLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogKChpbnQpICgkdGVtcCAvIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpKSk7CiAgICAgICR0ZW1wID0gJHRoaXMtPl9hZGQoJHRoaXMtPl9yZWd1bGFyTXVsdGlwbHkoYXJyYXkoJHhbJGldKSwgJHkpLCBmYWxzZSwgJHRoaXMtPl9yZWd1bGFyTXVsdGlwbHkoYXJyYXkoJHRlbXApLCAkbSksIGZhbHNlKTsKICAgICAgJGEgPSAkdGhpcy0+X2FkZCgkYVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UpOwogICAgICAkYVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdID0gYXJyYXlfc2xpY2UoJGFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgMSk7CiAgICB9CiAgICBpZiAoJHRoaXMtPl9jb21wYXJlKCRhW01BVEhfQklHSU5URUdFUl9WQUxVRV0sIGZhbHNlLCAkbSwgZmFsc2UpID49IDApIHsKICAgICAgJGEgPSAkdGhpcy0+X3N1YnRyYWN0KCRhW01BVEhfQklHSU5URUdFUl9WQUxVRV0sIGZhbHNlLCAkbSwgZmFsc2UpOwogICAgfQogICAgcmV0dXJuICRhW01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgfQogCiAgZnVuY3Rpb24gX3ByZXBNb250Z29tZXJ5KCR4LCAkbikgewogICAgJGxocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRsaHMtPnZhbHVlID0gYXJyYXlfbWVyZ2UoJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgY291bnQoJG4pKSwgJHgpOwogICAgJHJocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRyaHMtPnZhbHVlID0gJG47CiAKICAgIGxpc3QoLCAkdGVtcCkgPSAkbGhzLT5kaXZpZGUoJHJocyk7CiAgICByZXR1cm4gJHRlbXAtPnZhbHVlOwogIH0KIAogIGZ1bmN0aW9uIF9tb2RJbnZlcnNlNjcxMDg4NjQoJHgpIC8vIDIqKjI2ID09IDY3LDEwOCw4NjQKICB7CiAgICAkeCA9IC0keFswXTsKICAgICRyZXN1bHQgPSAkeCAmIDB4MzsgLy8geCoqLTEgbW9kIDIqKjIKICAgICRyZXN1bHQgPSAoJHJlc3VsdCAqICgyIC0gJHggKiAkcmVzdWx0KSkgJiAweEY7IC8vIHgqKi0xIG1vZCAyKio0CiAgICAkcmVzdWx0ID0gKCRyZXN1bHQgKiAoMiAtICgkeCAmIDB4RkYpICogJHJlc3VsdCkpICAmIDB4RkY7IC8vIHgqKi0xIG1vZCAyKio4CiAgICAkcmVzdWx0ID0gKCRyZXN1bHQgKiAoKDIgLSAoJHggJiAweEZGRkYpICogJHJlc3VsdCkgJiAweEZGRkYpKSAmIDB4RkZGRjsgLy8geCoqLTEgbW9kIDIqKjE2CiAgICAkcmVzdWx0ID0gZm1vZCgkcmVzdWx0ICogKDIgLSBmbW9kKCR4ICogJHJlc3VsdCwgTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCkpLCBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKTsgLy8geCoqLTEgbW9kIDIqKjI2CiAgICByZXR1cm4gJHJlc3VsdCAmIE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQ7CiAgfQogCiAgZnVuY3Rpb24gbW9kSW52ZXJzZSgkbikgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICR0ZW1wLT52YWx1ZSA9IGdtcF9pbnZlcnQoJHRoaXMtPnZhbHVlLCAkbi0+dmFsdWUpOwogCiAgICAgICAgcmV0dXJuICggJHRlbXAtPnZhbHVlID09PSBmYWxzZSApID8gZmFsc2UgOiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CiAKICAgIHN0YXRpYyAkemVybywgJG9uZTsKICAgIGlmICghaXNzZXQoJHplcm8pKSB7CiAgICAgICR6ZXJvID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkb25lID0gbmV3IE1hdGhfQmlnSW50ZWdlcigxKTsKICAgIH0KIAogICAgLy8gJHggbW9kIC0kbiA9PSAkeCBtb2QgJG4uCiAgICAkbiA9ICRuLT5hYnMoKTsKIAogICAgaWYgKCR0aGlzLT5jb21wYXJlKCR6ZXJvKSA8IDApIHsKICAgICAgJHRlbXAgPSAkdGhpcy0+YWJzKCk7CiAgICAgICR0ZW1wID0gJHRlbXAtPm1vZEludmVyc2UoJG4pOwogICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJG4tPnN1YnRyYWN0KCR0ZW1wKSk7CiAgICB9CiAKICAgIGV4dHJhY3QoJHRoaXMtPmV4dGVuZGVkR0NEKCRuKSk7CiAKICAgIGlmICghJGdjZC0+ZXF1YWxzKCRvbmUpKSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KIAogICAgJHggPSAkeC0+Y29tcGFyZSgkemVybykgPCAwID8gJHgtPmFkZCgkbikgOiAkeDsKIAogICAgcmV0dXJuICR0aGlzLT5jb21wYXJlKCR6ZXJvKSA8IDAgPyAkdGhpcy0+X25vcm1hbGl6ZSgkbi0+c3VidHJhY3QoJHgpKSA6ICR0aGlzLT5fbm9ybWFsaXplKCR4KTsKICB9CiAKICBmdW5jdGlvbiBleHRlbmRlZEdDRCgkbikgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGV4dHJhY3QoZ21wX2djZGV4dCgkdGhpcy0+dmFsdWUsICRuLT52YWx1ZSkpOwogCiAgICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgICAgJ2djZCcgPT4gJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigkZykpLAogICAgICAgICAgJ3gnICAgPT4gJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigkcykpLAogICAgICAgICAgJ3knICAgPT4gJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigkdCkpCiAgICAgICAgKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgJHUgPSAkdGhpcy0+dmFsdWU7CiAgICAgICAgJHYgPSAkbi0+dmFsdWU7CiAKICAgICAgICAkYSA9ICcxJzsKICAgICAgICAkYiA9ICcwJzsKICAgICAgICAkYyA9ICcwJzsKICAgICAgICAkZCA9ICcxJzsKIAogICAgICAgIHdoaWxlIChiY2NvbXAoJHYsICcwJywgMCkgIT0gMCkgewogICAgICAgICAgJHEgPSBiY2RpdigkdSwgJHYsIDApOwogCiAgICAgICAgICAkdGVtcCA9ICR1OwogICAgICAgICAgJHUgPSAkdjsKICAgICAgICAgICR2ID0gYmNzdWIoJHRlbXAsIGJjbXVsKCR2LCAkcSwgMCksIDApOwogCiAgICAgICAgICAkdGVtcCA9ICRhOwogICAgICAgICAgJGEgPSAkYzsKICAgICAgICAgICRjID0gYmNzdWIoJHRlbXAsIGJjbXVsKCRhLCAkcSwgMCksIDApOwogCiAgICAgICAgICAkdGVtcCA9ICRiOwogICAgICAgICAgJGIgPSAkZDsKICAgICAgICAgICRkID0gYmNzdWIoJHRlbXAsIGJjbXVsKCRiLCAkcSwgMCksIDApOwogICAgICAgIH0KIAogICAgICAgIHJldHVybiBhcnJheSgKICAgICAgICAgICdnY2QnID0+ICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoJHUpKSwKICAgICAgICAgICd4JyAgID0+ICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoJGEpKSwKICAgICAgICAgICd5JyAgID0+ICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoJGIpKQogICAgICAgICk7CiAgICB9CiAKICAgICR5ID0gJG4tPmNvcHkoKTsKICAgICR4ID0gJHRoaXMtPmNvcHkoKTsKICAgICRnID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJGctPnZhbHVlID0gYXJyYXkoMSk7CiAKICAgIHdoaWxlICggISgoJHgtPnZhbHVlWzBdICYgMSl8fCAoJHktPnZhbHVlWzBdICYgMSkpICkgewogICAgICAkeC0+X3JzaGlmdCgxKTsKICAgICAgJHktPl9yc2hpZnQoMSk7CiAgICAgICRnLT5fbHNoaWZ0KDEpOwogICAgfQogCiAgICAkdSA9ICR4LT5jb3B5KCk7CiAgICAkdiA9ICR5LT5jb3B5KCk7CiAKICAgICRhID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJGIgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkYyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRkID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogCiAgICAkYS0+dmFsdWUgPSAkZC0+dmFsdWUgPSAkZy0+dmFsdWUgPSBhcnJheSgxKTsKICAgICRiLT52YWx1ZSA9ICRjLT52YWx1ZSA9IGFycmF5KCk7CiAKICAgIHdoaWxlICggIWVtcHR5KCR1LT52YWx1ZSkgKSB7CiAgICAgIHdoaWxlICggISgkdS0+dmFsdWVbMF0gJiAxKSApIHsKICAgICAgICAkdS0+X3JzaGlmdCgxKTsKICAgICAgICBpZiAoICghZW1wdHkoJGEtPnZhbHVlKSAmJiAoJGEtPnZhbHVlWzBdICYgMSkpIHx8ICghZW1wdHkoJGItPnZhbHVlKSAmJiAoJGItPnZhbHVlWzBdICYgMSkpICkgewogICAgICAgICAgJGEgPSAkYS0+YWRkKCR5KTsKICAgICAgICAgICRiID0gJGItPnN1YnRyYWN0KCR4KTsKICAgICAgICB9CiAgICAgICAgJGEtPl9yc2hpZnQoMSk7CiAgICAgICAgJGItPl9yc2hpZnQoMSk7CiAgICAgIH0KIAogICAgICB3aGlsZSAoICEoJHYtPnZhbHVlWzBdICYgMSkgKSB7CiAgICAgICAgJHYtPl9yc2hpZnQoMSk7CiAgICAgICAgaWYgKCAoIWVtcHR5KCRkLT52YWx1ZSkgJiYgKCRkLT52YWx1ZVswXSAmIDEpKSB8fCAoIWVtcHR5KCRjLT52YWx1ZSkgJiYgKCRjLT52YWx1ZVswXSAmIDEpKSApIHsKICAgICAgICAgICRjID0gJGMtPmFkZCgkeSk7CiAgICAgICAgICAkZCA9ICRkLT5zdWJ0cmFjdCgkeCk7CiAgICAgICAgfQogICAgICAgICRjLT5fcnNoaWZ0KDEpOwogICAgICAgICRkLT5fcnNoaWZ0KDEpOwogICAgICB9CiAKICAgICAgaWYgKCR1LT5jb21wYXJlKCR2KSA+PSAwKSB7CiAgICAgICAgJHUgPSAkdS0+c3VidHJhY3QoJHYpOwogICAgICAgICRhID0gJGEtPnN1YnRyYWN0KCRjKTsKICAgICAgICAkYiA9ICRiLT5zdWJ0cmFjdCgkZCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgJHYgPSAkdi0+c3VidHJhY3QoJHUpOwogICAgICAgICRjID0gJGMtPnN1YnRyYWN0KCRhKTsKICAgICAgICAkZCA9ICRkLT5zdWJ0cmFjdCgkYik7CiAgICAgIH0KICAgIH0KIAogICAgcmV0dXJuIGFycmF5KAogICAgICAnZ2NkJyA9PiAkdGhpcy0+X25vcm1hbGl6ZSgkZy0+bXVsdGlwbHkoJHYpKSwKICAgICAgJ3gnICAgPT4gJHRoaXMtPl9ub3JtYWxpemUoJGMpLAogICAgICAneScgICA9PiAkdGhpcy0+X25vcm1hbGl6ZSgkZCkKICAgICk7CiAgfQogCiAgZnVuY3Rpb24gZ2NkKCRuKSB7CiAgICBleHRyYWN0KCR0aGlzLT5leHRlbmRlZEdDRCgkbikpOwogICAgcmV0dXJuICRnY2Q7CiAgfQogCiAgZnVuY3Rpb24gYWJzKCkgewogICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfYWJzKCR0aGlzLT52YWx1ZSk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICR0ZW1wLT52YWx1ZSA9IChiY2NvbXAoJHRoaXMtPnZhbHVlLCAnMCcsIDApIDwgMCkgPyBzdWJzdHIoJHRoaXMtPnZhbHVlLCAxKSA6ICR0aGlzLT52YWx1ZTsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSAkdGhpcy0+dmFsdWU7CiAgICB9CiAKICAgIHJldHVybiAkdGVtcDsKICB9CiAKICBmdW5jdGlvbiBjb21wYXJlKCR5KSB7CiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgcmV0dXJuIGdtcF9jbXAoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUpOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICByZXR1cm4gYmNjb21wKCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlLCAwKTsKICAgIH0KIAogICAgcmV0dXJuICR0aGlzLT5fY29tcGFyZSgkdGhpcy0+dmFsdWUsICR0aGlzLT5pc19uZWdhdGl2ZSwgJHktPnZhbHVlLCAkeS0+aXNfbmVnYXRpdmUpOwogIH0KIAogIGZ1bmN0aW9uIF9jb21wYXJlKCR4X3ZhbHVlLCAkeF9uZWdhdGl2ZSwgJHlfdmFsdWUsICR5X25lZ2F0aXZlKSB7CiAgICBpZiAoICR4X25lZ2F0aXZlICE9ICR5X25lZ2F0aXZlICkgewogICAgICByZXR1cm4gKCAhJHhfbmVnYXRpdmUgJiYgJHlfbmVnYXRpdmUgKSA/IDEgOiAtMTsKICAgIH0KIAogICAgJHJlc3VsdCA9ICR4X25lZ2F0aXZlID8gLTEgOiAxOwogCiAgICBpZiAoIGNvdW50KCR4X3ZhbHVlKSAhPSBjb3VudCgkeV92YWx1ZSkgKSB7CiAgICAgIHJldHVybiAoIGNvdW50KCR4X3ZhbHVlKSA+IGNvdW50KCR5X3ZhbHVlKSApID8gJHJlc3VsdCA6IC0kcmVzdWx0OwogICAgfQogICAgJHNpemUgPSBtYXgoY291bnQoJHhfdmFsdWUpLCBjb3VudCgkeV92YWx1ZSkpOwogCiAgICAkeF92YWx1ZSA9IGFycmF5X3BhZCgkeF92YWx1ZSwgJHNpemUsIDApOwogICAgJHlfdmFsdWUgPSBhcnJheV9wYWQoJHlfdmFsdWUsICRzaXplLCAwKTsKIAogICAgZm9yICgkaSA9IGNvdW50KCR4X3ZhbHVlKSAtIDE7ICRpID49IDA7IC0tJGkpIHsKICAgICAgaWYgKCR4X3ZhbHVlWyRpXSAhPSAkeV92YWx1ZVskaV0pIHsKICAgICAgICByZXR1cm4gKCAkeF92YWx1ZVskaV0gPiAkeV92YWx1ZVskaV0gKSA/ICRyZXN1bHQgOiAtJHJlc3VsdDsKICAgICAgfQogICAgfQogCiAgICByZXR1cm4gMDsKICB9CiAKICBmdW5jdGlvbiBlcXVhbHMoJHgpIHsKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICByZXR1cm4gZ21wX2NtcCgkdGhpcy0+dmFsdWUsICR4LT52YWx1ZSkgPT0gMDsKICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4gJHRoaXMtPnZhbHVlID09PSAkeC0+dmFsdWUgJiYgJHRoaXMtPmlzX25lZ2F0aXZlID09ICR4LT5pc19uZWdhdGl2ZTsKICAgIH0KICB9CiAKICBmdW5jdGlvbiBzZXRQcmVjaXNpb24oJGJpdHMpIHsKICAgICR0aGlzLT5wcmVjaXNpb24gPSAkYml0czsKICAgIGlmICggTUFUSF9CSUdJTlRFR0VSX01PREUgIT0gTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIICkgewogICAgICAkdGhpcy0+Yml0bWFzayA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoY2hyKCgxIDw8ICgkYml0cyAmIDB4NykpIC0gMSkgLiBzdHJfcmVwZWF0KGNocigweEZGKSwgJGJpdHMgPj4gMyksIDI1Nik7CiAgICB9IGVsc2UgewogICAgICAkdGhpcy0+Yml0bWFzayA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoYmNwb3coJzInLCAkYml0cywgMCkpOwogICAgfQogCiAgICAkdGVtcCA9ICR0aGlzLT5fbm9ybWFsaXplKCR0aGlzKTsKICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICB9CiAKICBmdW5jdGlvbiBiaXR3aXNlX3JpZ2h0U2hpZnQoJHNoaWZ0KSB7CiAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKIAogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIHN0YXRpYyAkdHdvOwogCiAgICAgICAgaWYgKCFpc3NldCgkdHdvKSkgewogICAgICAgICAgJHR3byA9IGdtcF9pbml0KCcyJyk7CiAgICAgICAgfQogCiAgICAgICAgJHRlbXAtPnZhbHVlID0gZ21wX2Rpdl9xKCR0aGlzLT52YWx1ZSwgZ21wX3BvdygkdHdvLCAkc2hpZnQpKTsKIAogICAgICAgIGJyZWFrOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY2RpdigkdGhpcy0+dmFsdWUsIGJjcG93KCcyJywgJHNoaWZ0LCAwKSwgMCk7CiAKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSAkdGhpcy0+dmFsdWU7CiAgICAgICAgJHRlbXAtPl9yc2hpZnQoJHNoaWZ0KTsKICAgIH0KIAogICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICB9CiAKICBmdW5jdGlvbiBiaXR3aXNlX2xlZnRTaGlmdCgkc2hpZnQpIHsKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogCiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgc3RhdGljICR0d287CiAKICAgICAgICBpZiAoIWlzc2V0KCR0d28pKSB7CiAgICAgICAgICAkdHdvID0gZ21wX2luaXQoJzInKTsKICAgICAgICB9CiAKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfbXVsKCR0aGlzLT52YWx1ZSwgZ21wX3BvdygkdHdvLCAkc2hpZnQpKTsKIAogICAgICAgIGJyZWFrOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY211bCgkdGhpcy0+dmFsdWUsIGJjcG93KCcyJywgJHNoaWZ0LCAwKSwgMCk7CiAKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSAkdGhpcy0+dmFsdWU7CiAgICAgICAgJHRlbXAtPl9sc2hpZnQoJHNoaWZ0KTsKICAgIH0KIAogICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICB9CiAKICBmdW5jdGlvbiBiaXR3aXNlX2xlZnRSb3RhdGUoJHNoaWZ0KSB7CiAgICAkYml0cyA9ICR0aGlzLT50b0J5dGVzKCk7CiAKICAgIGlmICgkdGhpcy0+cHJlY2lzaW9uID4gMCkgewogICAgICAkcHJlY2lzaW9uID0gJHRoaXMtPnByZWNpc2lvbjsKICAgICAgaWYgKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEggKSB7CiAgICAgICAgJG1hc2sgPSAkdGhpcy0+Yml0bWFzay0+c3VidHJhY3QobmV3IE1hdGhfQmlnSW50ZWdlcigxKSk7CiAgICAgICAgJG1hc2sgPSAkbWFzay0+dG9CeXRlcygpOwogICAgICB9IGVsc2UgewogICAgICAgICRtYXNrID0gJHRoaXMtPmJpdG1hc2stPnRvQnl0ZXMoKTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgJHRlbXAgPSBvcmQoJGJpdHNbMF0pOwogICAgICBmb3IgKCRpID0gMDsgJHRlbXAgPj4gJGk7ICsrJGkpOwogICAgICAkcHJlY2lzaW9uID0gOCAqIHN0cmxlbigkYml0cykgLSA4ICsgJGk7CiAgICAgICRtYXNrID0gY2hyKCgxIDw8ICgkcHJlY2lzaW9uICYgMHg3KSkgLSAxKSAuIHN0cl9yZXBlYXQoY2hyKDB4RkYpLCAkcHJlY2lzaW9uID4+IDMpOwogICAgfQogCiAgICBpZiAoJHNoaWZ0IDwgMCkgewogICAgICAkc2hpZnQrPSAkcHJlY2lzaW9uOwogICAgfQogICAgJHNoaWZ0JT0gJHByZWNpc2lvbjsKIAogICAgaWYgKCEkc2hpZnQpIHsKICAgICAgcmV0dXJuICR0aGlzLT5jb3B5KCk7CiAgICB9CiAKICAgICRsZWZ0ID0gJHRoaXMtPmJpdHdpc2VfbGVmdFNoaWZ0KCRzaGlmdCk7CiAgICAkbGVmdCA9ICRsZWZ0LT5iaXR3aXNlX2FuZChuZXcgTWF0aF9CaWdJbnRlZ2VyKCRtYXNrLCAyNTYpKTsKICAgICRyaWdodCA9ICR0aGlzLT5iaXR3aXNlX3JpZ2h0U2hpZnQoJHByZWNpc2lvbiAtICRzaGlmdCk7CiAgICAkcmVzdWx0ID0gTUFUSF9CSUdJTlRFR0VSX01PREUgIT0gTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIID8gJGxlZnQtPmJpdHdpc2Vfb3IoJHJpZ2h0KSA6ICRsZWZ0LT5hZGQoJHJpZ2h0KTsKICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkcmVzdWx0KTsKICB9CiAKICBmdW5jdGlvbiBiaXR3aXNlX3JpZ2h0Um90YXRlKCRzaGlmdCkgewogICAgcmV0dXJuICR0aGlzLT5iaXR3aXNlX2xlZnRSb3RhdGUoLSRzaGlmdCk7CiAgfQogCiAgZnVuY3Rpb24gX21ha2Vfb2RkKCkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGdtcF9zZXRiaXQoJHRoaXMtPnZhbHVlLCAwKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgaWYgKCR0aGlzLT52YWx1ZVtzdHJsZW4oJHRoaXMtPnZhbHVlKSAtIDFdICUgMiA9PSAwKSB7CiAgICAgICAgICAkdGhpcy0+dmFsdWUgPSBiY2FkZCgkdGhpcy0+dmFsdWUsICcxJyk7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgICR0aGlzLT52YWx1ZVswXSB8PSAxOwogICAgfQogIH0KIAogIGZ1bmN0aW9uIF9sc2hpZnQoJHNoaWZ0KSB7CiAgICBpZiAoICRzaGlmdCA9PSAwICkgewogICAgICByZXR1cm47CiAgICB9CiAKICAgICRudW1fZGlnaXRzID0gKGludCkgKCRzaGlmdCAvIE1BVEhfQklHSU5URUdFUl9CQVNFKTsKICAgICRzaGlmdCAlPSBNQVRIX0JJR0lOVEVHRVJfQkFTRTsKICAgICRzaGlmdCA9IDEgPDwgJHNoaWZ0OwogCiAgICAkY2FycnkgPSAwOwogCiAgICBmb3IgKCRpID0gMDsgJGkgPCBjb3VudCgkdGhpcy0+dmFsdWUpOyArKyRpKSB7CiAgICAgICR0ZW1wID0gJHRoaXMtPnZhbHVlWyRpXSAqICRzaGlmdCArICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAgICAgICR0aGlzLT52YWx1ZVskaV0gPSAoaW50KSAoJHRlbXAgLSAkY2FycnkgKiBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKTsKICAgIH0KIAogICAgaWYgKCAkY2FycnkgKSB7CiAgICAgICR0aGlzLT52YWx1ZVtdID0gJGNhcnJ5OwogICAgfQogCiAgICB3aGlsZSAoJG51bV9kaWdpdHMtLSkgewogICAgICBhcnJheV91bnNoaWZ0KCR0aGlzLT52YWx1ZSwgMCk7CiAgICB9CiAgfQogCiAgZnVuY3Rpb24gX3JzaGlmdCgkc2hpZnQpIHsKICAgIGlmICgkc2hpZnQgPT0gMCkgewogICAgICByZXR1cm47CiAgICB9CiAKICAgICRudW1fZGlnaXRzID0gKGludCkgKCRzaGlmdCAvIE1BVEhfQklHSU5URUdFUl9CQVNFKTsKICAgICRzaGlmdCAlPSBNQVRIX0JJR0lOVEVHRVJfQkFTRTsKICAgICRjYXJyeV9zaGlmdCA9IE1BVEhfQklHSU5URUdFUl9CQVNFIC0gJHNoaWZ0OwogICAgJGNhcnJ5X21hc2sgPSAoMSA8PCAkc2hpZnQpIC0gMTsKIAogICAgaWYgKCAkbnVtX2RpZ2l0cyApIHsKICAgICAgJHRoaXMtPnZhbHVlID0gYXJyYXlfc2xpY2UoJHRoaXMtPnZhbHVlLCAkbnVtX2RpZ2l0cyk7CiAgICB9CiAKICAgICRjYXJyeSA9IDA7CiAKICAgIGZvciAoJGkgPSBjb3VudCgkdGhpcy0+dmFsdWUpIC0gMTsgJGkgPj0gMDsgLS0kaSkgewogICAgICAkdGVtcCA9ICR0aGlzLT52YWx1ZVskaV0gPj4gJHNoaWZ0IHwgJGNhcnJ5OwogICAgICAkY2FycnkgPSAoJHRoaXMtPnZhbHVlWyRpXSAmICRjYXJyeV9tYXNrKSA8PCAkY2Fycnlfc2hpZnQ7CiAgICAgICR0aGlzLT52YWx1ZVskaV0gPSAkdGVtcDsKICAgIH0KIAogICAgJHRoaXMtPnZhbHVlID0gJHRoaXMtPl90cmltKCR0aGlzLT52YWx1ZSk7CiAgfQogCiAgZnVuY3Rpb24gX25vcm1hbGl6ZSgkcmVzdWx0KSB7CiAgICAkcmVzdWx0LT5wcmVjaXNpb24gPSAkdGhpcy0+cHJlY2lzaW9uOwogICAgJHJlc3VsdC0+Yml0bWFzayA9ICR0aGlzLT5iaXRtYXNrOwogCiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgaWYgKCFlbXB0eSgkcmVzdWx0LT5iaXRtYXNrLT52YWx1ZSkpIHsKICAgICAgICAgICRyZXN1bHQtPnZhbHVlID0gZ21wX2FuZCgkcmVzdWx0LT52YWx1ZSwgJHJlc3VsdC0+Yml0bWFzay0+dmFsdWUpOwogICAgICAgIH0KIAogICAgICAgIHJldHVybiAkcmVzdWx0OwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICBpZiAoIWVtcHR5KCRyZXN1bHQtPmJpdG1hc2stPnZhbHVlKSkgewogICAgICAgICAgJHJlc3VsdC0+dmFsdWUgPSBiY21vZCgkcmVzdWx0LT52YWx1ZSwgJHJlc3VsdC0+Yml0bWFzay0+dmFsdWUpOwogICAgICAgIH0KIAogICAgICAgIHJldHVybiAkcmVzdWx0OwogICAgfQogCiAgICAkdmFsdWUgPSAmJHJlc3VsdC0+dmFsdWU7CiAKICAgIGlmICggIWNvdW50KCR2YWx1ZSkgKSB7CiAgICAgIHJldHVybiAkcmVzdWx0OwogICAgfQogCiAgICAkdmFsdWUgPSAkdGhpcy0+X3RyaW0oJHZhbHVlKTsKIAogICAgaWYgKCFlbXB0eSgkcmVzdWx0LT5iaXRtYXNrLT52YWx1ZSkpIHsKICAgICAgJGxlbmd0aCA9IG1pbihjb3VudCgkdmFsdWUpLCBjb3VudCgkdGhpcy0+Yml0bWFzay0+dmFsdWUpKTsKICAgICAgJHZhbHVlID0gYXJyYXlfc2xpY2UoJHZhbHVlLCAwLCAkbGVuZ3RoKTsKIAogICAgICBmb3IgKCRpID0gMDsgJGkgPCAkbGVuZ3RoOyArKyRpKSB7CiAgICAgICAgJHZhbHVlWyRpXSA9ICR2YWx1ZVskaV0gJiAkdGhpcy0+Yml0bWFzay0+dmFsdWVbJGldOwogICAgICB9CiAgICB9CiAKICAgIHJldHVybiAkcmVzdWx0OwogIH0KIAogIGZ1bmN0aW9uIF90cmltKCR2YWx1ZSkgewogICAgZm9yICgkaSA9IGNvdW50KCR2YWx1ZSkgLSAxOyAkaSA+PSAwOyAtLSRpKSB7CiAgICAgIGlmICggJHZhbHVlWyRpXSApIHsKICAgICAgICBicmVhazsKICAgICAgfQogICAgICB1bnNldCgkdmFsdWVbJGldKTsKICAgIH0KIAogICAgcmV0dXJuICR2YWx1ZTsKICB9CiAKICBmdW5jdGlvbiBfYXJyYXlfcmVwZWF0KCRpbnB1dCwgJG11bHRpcGxpZXIpIHsKICAgIHJldHVybiAoJG11bHRpcGxpZXIpID8gYXJyYXlfZmlsbCgwLCAkbXVsdGlwbGllciwgJGlucHV0KSA6IGFycmF5KCk7CiAgfQogCiAgZnVuY3Rpb24gX2Jhc2UyNTZfbHNoaWZ0KCYkeCwgJHNoaWZ0KSB7CiAgICBpZiAoJHNoaWZ0ID09IDApIHsKICAgICAgcmV0dXJuOwogICAgfQogCiAgICAkbnVtX2J5dGVzID0gJHNoaWZ0ID4+IDM7IC8vIGVnLiBmbG9vcigkc2hpZnQvOCkKICAgICRzaGlmdCAmPSA3OyAvLyBlZy4gJHNoaWZ0ICUgOAogCiAgICAkY2FycnkgPSAwOwogICAgZm9yICgkaSA9IHN0cmxlbigkeCkgLSAxOyAkaSA+PSAwOyAtLSRpKSB7CiAgICAgICR0ZW1wID0gb3JkKCR4WyRpXSkgPDwgJHNoaWZ0IHwgJGNhcnJ5OwogICAgICAkeFskaV0gPSBjaHIoJHRlbXApOwogICAgICAkY2FycnkgPSAkdGVtcCA+PiA4OwogICAgfQogICAgJGNhcnJ5ID0gKCRjYXJyeSAhPSAwKSA/IGNocigkY2FycnkpIDogJyc7CiAgICAkeCA9ICRjYXJyeSAuICR4IC4gc3RyX3JlcGVhdChjaHIoMCksICRudW1fYnl0ZXMpOwogIH0KIAogIGZ1bmN0aW9uIF9iYXNlMjU2X3JzaGlmdCgmJHgsICRzaGlmdCkgewogICAgaWYgKCRzaGlmdCA9PSAwKSB7CiAgICAgICR4ID0gbHRyaW0oJHgsIGNocigwKSk7CiAgICAgIHJldHVybiAnJzsKICAgIH0KIAogICAgJG51bV9ieXRlcyA9ICRzaGlmdCA+PiAzOyAvLyBlZy4gZmxvb3IoJHNoaWZ0LzgpCiAgICAkc2hpZnQgJj0gNzsgLy8gZWcuICRzaGlmdCAlIDgKIAogICAgJHJlbWFpbmRlciA9ICcnOwogICAgaWYgKCRudW1fYnl0ZXMpIHsKICAgICAgJHN0YXJ0ID0gJG51bV9ieXRlcyA+IHN0cmxlbigkeCkgPyAtc3RybGVuKCR4KSA6IC0kbnVtX2J5dGVzOwogICAgICAkcmVtYWluZGVyID0gc3Vic3RyKCR4LCAkc3RhcnQpOwogICAgICAkeCA9IHN1YnN0cigkeCwgMCwgLSRudW1fYnl0ZXMpOwogICAgfQogCiAgICAkY2FycnkgPSAwOwogICAgJGNhcnJ5X3NoaWZ0ID0gOCAtICRzaGlmdDsKICAgIGZvciAoJGkgPSAwOyAkaSA8IHN0cmxlbigkeCk7ICsrJGkpIHsKICAgICAgJHRlbXAgPSAob3JkKCR4WyRpXSkgPj4gJHNoaWZ0KSB8ICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gKG9yZCgkeFskaV0pIDw8ICRjYXJyeV9zaGlmdCkgJiAweEZGOwogICAgICAkeFskaV0gPSBjaHIoJHRlbXApOwogICAgfQogICAgJHggPSBsdHJpbSgkeCwgY2hyKDApKTsKIAogICAgJHJlbWFpbmRlciA9IGNocigkY2FycnkgPj4gJGNhcnJ5X3NoaWZ0KSAuICRyZW1haW5kZXI7CiAKICAgIHJldHVybiBsdHJpbSgkcmVtYWluZGVyLCBjaHIoMCkpOwogIH0KIAogIGZ1bmN0aW9uIF9pbnQyYnl0ZXMoJHgpIHsKICAgIHJldHVybiBsdHJpbShwYWNrKCdOJywgJHgpLCBjaHIoMCkpOwogIH0KIAogIGZ1bmN0aW9uIF9ieXRlczJpbnQoJHgpIHsKICAgICR0ZW1wID0gdW5wYWNrKCdOaW50Jywgc3RyX3BhZCgkeCwgNCwgY2hyKDApLCBTVFJfUEFEX0xFRlQpKTsKICAgIHJldHVybiAkdGVtcFsnaW50J107CiAgfQogCiAgZnVuY3Rpb24gX2VuY29kZUFTTjFMZW5ndGgoJGxlbmd0aCkgewogICAgaWYgKCRsZW5ndGggPD0gMHg3RikgewogICAgICByZXR1cm4gY2hyKCRsZW5ndGgpOwogICAgfQogCiAgICAkdGVtcCA9IGx0cmltKHBhY2soJ04nLCAkbGVuZ3RoKSwgY2hyKDApKTsKICAgIHJldHVybiBwYWNrKCdDYSonLCAweDgwIHwgc3RybGVuKCR0ZW1wKSwgJHRlbXApOwogIH0KfQoKZnVuY3Rpb24gdG9IZXgoJG4pIHsKICAgICR6ZXJvID0gbmV3IE1hdGhfQmlnSW50ZWdlcigwKTsKICAgIGlmICgkbi0+Y29tcGFyZSgkemVybykgPT0gMCkgcmV0dXJuICIwIjsKICAgICRiYXNlID0gIjAxMjM0NTY3ODlBQkNERUYiOwogICAgJGRlemVzc2VpcyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoMTYpOwogICAgJHJlc3VsdCA9ICIiOwogICAgd2hpbGUgKCRuLT5jb21wYXJlKCR6ZXJvKSA+IDApIHsKICAgICAgICBsaXN0KCRuLCAkcikgPSAkbi0+ZGl2aWRlKCRkZXplc3NlaXMpOwogICAgICAgICRyZXN1bHQgPSAkYmFzZVtpbnR2YWwoJHItPnRvU3RyaW5nKCkpXSAuICRyZXN1bHQ7CiAgICB9CiAgICByZXR1cm4gJHJlc3VsdDsKfQoKZnVuY3Rpb24gbWlsbGlUb0hleCgpIHsKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcih0aW1lKCkpOwogICAgJG1pbCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoMTAwMCk7CiAgICAkcmV0ID0gdG9IZXgoJHRlbXAtPm11bHRpcGx5KCRtaWwpKTsKICAgIHJldHVybiBzdHJfcGFkKCRyZXQsIDE2LCAiMCIsIFNUUl9QQURfTEVGVCk7Cn0KCmVjaG8gbWlsbGlUb0hleCgpOwoKPz4=