<?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) {
}
}
}
class BaseN {
private $base;
private $radix;
private $bi256, $one, $zero;
function __construct($base) {
$this->base = $base;
$this->radix = new Math_BigInteger
(strlen($base)); $this->bi256 = new Math_BigInteger(256);
$this->zero = new Math_BigInteger(0);
$this->one = new Math_BigInteger(1);
}
public function encode($text) {
$big = $this->one;
for ($j = 0; $j < strlen($text); $j++) { $big = $big->multiply($this->bi256)->add(new Math_BigInteger
(ord($text[$j]))); }
$result = "";
while (!$this->zero->equals($big)) {
$parts = $big->divide($this->radix);
$small = intval($parts[1]->toString()); $big = $parts[0];
$result = $this->base[$small] . $result;
}
return $result;
}
public function decode($text) {
$big = $this->zero;
for ($j = 0; $j < strlen($text); $j++) { $i = strpos($this->base, $text[$j]); $big = $big->multiply($this->radix)->add(new Math_BigInteger($i));
}
$result = "";
while (!$this->zero->equals($big)) {
$parts = $big->divide($this->bi256);
$small = $parts[1]->toBytes();
$big = $parts[0];
$result = $small . $result;
}
}
}
// Passa o alfabeto como parâmetro. Tem 62 caracteres aqui, então são 62 sÃmbolos.
$k = new BaseN("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
$x = "The quick brown fox jumps over a lazy dog";
echo $x . "\n";
$c = $k->encode($x);
echo $c . "\n"; // Escreve "1u9WLfG65OMtVkQWPtWDcC6o8IjI5td5l9DzpilIK4Nyx81tKLRrStPj"
$d = $k->decode($c);
echo $d . "\n"; // Escreve "The quick brown fox jumps over a lazy dog"
?>
PD9waHAKCi8qIHZpbTogc2V0IGV4cGFuZHRhYiB0YWJzdG9wPTQgc2hpZnR3aWR0aD00IHNvZnR0YWJzdG9wPTQ6ICovCgovKiojQCsqLwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NT05UR09NRVJZJywgMCk7CmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0JBUlJFVFQnLCAxKTsKZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfUE9XRVJPRjInLCAyKTsKZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfQ0xBU1NJQycsIDMpOwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9OT05FJywgNCk7Ci8qKiNALSovCgovKiojQCsqLwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9WQUxVRScsIDApOwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9TSUdOJywgMSk7Ci8qKiNALSovCgovKiojQCsqLwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9WQVJJQUJMRScsIDApOwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9EQVRBJywgMSk7Ci8qKiNALSovCgovKiojQCsqLwpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NT0RFX0lOVEVSTkFMJywgMSk7CgpkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSCcsIDIpOwoKZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVAnLCAzKTsKLyoqI0AtKi8KCmRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0tBUkFUU1VCQV9DVVRPRkYnLCAyNSk7CgpjbGFzcyBNYXRoX0JpZ0ludGVnZXIgewogIHZhciAkdmFsdWU7CgogIHZhciAkaXNfbmVnYXRpdmUgPSBmYWxzZTsKCiAgdmFyICRwcmVjaXNpb24gPSAtMTsKCiAgdmFyICRiaXRtYXNrID0gZmFsc2U7CgogIHZhciAkaGV4OwoKICBmdW5jdGlvbiBNYXRoX0JpZ0ludGVnZXIoJHggPSAwLCAkYmFzZSA9IDEwKQogIHsKICAgIGlmICggIWRlZmluZWQoJ01BVEhfQklHSU5URUdFUl9NT0RFJykgKSB7CiAgICAgIHN3aXRjaCAodHJ1ZSkgewogICAgICAgIGNhc2UgZXh0ZW5zaW9uX2xvYWRlZCgnZ21wJyk6CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NT0RFJywgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgZXh0ZW5zaW9uX2xvYWRlZCgnYmNtYXRoJyk6CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NT0RFJywgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NT0RFJywgTUFUSF9CSUdJTlRFR0VSX01PREVfSU5URVJOQUwpOwogICAgICB9CiAgICB9CgogICAgaWYgKGZ1bmN0aW9uX2V4aXN0cygnb3BlbnNzbF9wdWJsaWNfZW5jcnlwdCcpICYmICFkZWZpbmVkKCdNQVRIX0JJR0lOVEVHRVJfT1BFTlNTTF9ESVNBQkxFJykgJiYgIWRlZmluZWQoJ01BVEhfQklHSU5URUdFUl9PUEVOU1NMX0VOQUJMRUQnKSkgewogICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9PUEVOU1NMX0VOQUJMRUQnLCB0cnVlKTsKICAgIH0KCiAgICBpZiAoIWRlZmluZWQoJ1BIUF9JTlRfU0laRScpKSB7CiAgICAgIGRlZmluZSgnUEhQX0lOVF9TSVpFJywgNCk7CiAgICB9CgogICAgaWYgKCFkZWZpbmVkKCdNQVRIX0JJR0lOVEVHRVJfQkFTRScpICYmIE1BVEhfQklHSU5URUdFUl9NT0RFID09IE1BVEhfQklHSU5URUdFUl9NT0RFX0lOVEVSTkFMKSB7CiAgICAgIHN3aXRjaCAoUEhQX0lOVF9TSVpFKSB7CiAgICAgICAgY2FzZSA4OiAvLyB1c2UgNjQtYml0IGludGVnZXJzIGlmIGludCBzaXplIGlzIDggYnl0ZXMKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0JBU0UnLCAgICAgMzEpOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMJywgIDB4ODAwMDAwMDApOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTUFYX0RJR0lUJywgIDB4N0ZGRkZGRkYpOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTVNCJywgICAgMHg0MDAwMDAwMCk7CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NQVgxMCcsICAgIDEwMDAwMDAwMDApOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTUFYMTBfTEVOJywgIDkpOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfTUFYX0RJR0lUMicsIHBvdygyLCA2MikpOwogICAgICAgICAgYnJlYWs7CiAgICAgICAgZGVmYXVsdDoKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX0JBU0UnLCAgICAgMjYpOwogICAgICAgICAgZGVmaW5lKCdNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMJywgIDB4NDAwMDAwMCk7CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NQVhfRElHSVQnLCAgMHgzRkZGRkZGKTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01TQicsICAgIDB4MjAwMDAwMCk7CiAgICAgICAgICBkZWZpbmUoJ01BVEhfQklHSU5URUdFUl9NQVgxMCcsICAgIDEwMDAwMDAwKTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01BWDEwX0xFTicsICA3KTsKICAgICAgICAgIGRlZmluZSgnTUFUSF9CSUdJTlRFR0VSX01BWF9ESUdJVDInLCBwb3coMiwgNTIpKTsKICAgICAgfQogICAgfQoKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICBpZiAoaXNfcmVzb3VyY2UoJHgpICYmIGdldF9yZXNvdXJjZV90eXBlKCR4KSA9PSAnR01QIGludGVnZXInKSB7CiAgICAgICAgICAkdGhpcy0+dmFsdWUgPSAkeDsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgJHRoaXMtPnZhbHVlID0gZ21wX2luaXQoMCk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICR0aGlzLT52YWx1ZSA9ICcwJzsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAkdGhpcy0+dmFsdWUgPSBhcnJheSgpOwogICAgfQoKICAgIGlmIChlbXB0eSgkeCkgJiYgKGFicygkYmFzZSkgIT0gMjU2IHx8ICR4ICE9PSAnMCcpKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICBzd2l0Y2ggKCRiYXNlKSB7CiAgICAgIGNhc2UgLTI1NjoKICAgICAgICBpZiAob3JkKCR4WzBdKSAmIDB4ODApIHsKICAgICAgICAgICR4ID0gfiR4OwogICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gdHJ1ZTsKICAgICAgICB9CiAgICAgIGNhc2UgIDI1NjoKICAgICAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgICAgICAkc2lnbiA9ICR0aGlzLT5pc19uZWdhdGl2ZSA/ICctJyA6ICcnOwogICAgICAgICAgICAkdGhpcy0+dmFsdWUgPSBnbXBfaW5pdCgkc2lnbiAuICcweCcgLiBiaW4yaGV4KCR4KSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgICAgICRsZW4gPSAoc3RybGVuKCR4KSArIDMpICYgMHhGRkZGRkZGQzsKCiAgICAgICAgICAgICR4ID0gc3RyX3BhZCgkeCwgJGxlbiwgY2hyKDApLCBTVFJfUEFEX0xFRlQpOwoKICAgICAgICAgICAgZm9yICgkaSA9IDA7ICRpIDwgJGxlbjsgJGkrPSA0KSB7CiAgICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gYmNtdWwoJHRoaXMtPnZhbHVlLCAnNDI5NDk2NzI5NicsIDApOwogICAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9IGJjYWRkKCR0aGlzLT52YWx1ZSwgMHgxMDAwMDAwICogb3JkKCR4WyRpXSkgKyAoKG9yZCgkeFskaSArIDFdKSA8PCAxNikgfCAob3JkKCR4WyRpICsgMl0pIDw8IDgpIHwgb3JkKCR4WyRpICsgM10pKSwgMCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGlmICgkdGhpcy0+aXNfbmVnYXRpdmUpIHsKICAgICAgICAgICAgICAkdGhpcy0+dmFsdWUgPSAnLScgLiAkdGhpcy0+dmFsdWU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgd2hpbGUgKHN0cmxlbigkeCkpIHsKICAgICAgICAgICAgICAkdGhpcy0+dmFsdWVbXSA9ICR0aGlzLT5fYnl0ZXMyaW50KCR0aGlzLT5fYmFzZTI1Nl9yc2hpZnQoJHgsIE1BVEhfQklHSU5URUdFUl9CQVNFKSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmICgkdGhpcy0+aXNfbmVnYXRpdmUpIHsKICAgICAgICAgIGlmIChNQVRIX0JJR0lOVEVHRVJfTU9ERSAhPSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9JTlRFUk5BTCkgewogICAgICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKICAgICAgICAgIH0KICAgICAgICAgICR0ZW1wID0gJHRoaXMtPmFkZChuZXcgTWF0aF9CaWdJbnRlZ2VyKCctMScpKTsKICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgIDE2OgogICAgICBjYXNlIC0xNjoKICAgICAgICBpZiAoJGJhc2UgPiAwICYmICR4WzBdID09ICctJykgewogICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gdHJ1ZTsKICAgICAgICAgICR4ID0gc3Vic3RyKCR4LCAxKTsKICAgICAgICB9CgogICAgICAgICR4ID0gcHJlZ19yZXBsYWNlKCcjXig/OjB4KT8oW0EtRmEtZjAtOV0qKS4qIycsICckMScsICR4KTsKCiAgICAgICAgJGlzX25lZ2F0aXZlID0gZmFsc2U7CiAgICAgICAgaWYgKCRiYXNlIDwgMCAmJiBoZXhkZWMoJHhbMF0pID49IDgpIHsKICAgICAgICAgICR0aGlzLT5pc19uZWdhdGl2ZSA9ICRpc19uZWdhdGl2ZSA9IHRydWU7CiAgICAgICAgICAkeCA9IGJpbjJoZXgofnBhY2soJ0gqJywgJHgpKTsKICAgICAgICB9CgogICAgICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgICAgICR0ZW1wID0gJHRoaXMtPmlzX25lZ2F0aXZlID8gJy0weCcgLiAkeCA6ICcweCcgLiAkeDsKICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gZ21wX2luaXQoJHRlbXApOwogICAgICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAgICAgJHggPSAoIHN0cmxlbigkeCkgJiAxICkgPyAnMCcgLiAkeCA6ICR4OwogICAgICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIocGFjaygnSConLCAkeCksIDI1Nik7CiAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0aGlzLT5pc19uZWdhdGl2ZSA/ICctJyAuICR0ZW1wLT52YWx1ZSA6ICR0ZW1wLT52YWx1ZTsKICAgICAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gZmFsc2U7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgJHggPSAoIHN0cmxlbigkeCkgJiAxICkgPyAnMCcgLiAkeCA6ICR4OwogICAgICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIocGFjaygnSConLCAkeCksIDI1Nik7CiAgICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICAgICAgICB9CgogICAgICAgIGlmICgkaXNfbmVnYXRpdmUpIHsKICAgICAgICAgICR0ZW1wID0gJHRoaXMtPmFkZChuZXcgTWF0aF9CaWdJbnRlZ2VyKCctMScpKTsKICAgICAgICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgIDEwOgogICAgICBjYXNlIC0xMDoKICAgICAgICAkeCA9IHByZWdfcmVwbGFjZSgnIyg/PCFeKSg/Oi0pLip8KD88PV58LSkwKnxbXi0wLTldLiojJywgJycsICR4KTsKCiAgICAgICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAgICAgJHRoaXMtPnZhbHVlID0gZ21wX2luaXQoJHgpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICAgICAkdGhpcy0+dmFsdWUgPSAkeCA9PT0gJy0nID8gJzAnIDogKHN0cmluZykgJHg7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CgogICAgICAgICAgICAkbXVsdGlwbGllciA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAgICAgJG11bHRpcGxpZXItPnZhbHVlID0gYXJyYXkoTUFUSF9CSUdJTlRFR0VSX01BWDEwKTsKCiAgICAgICAgICAgIGlmICgkeFswXSA9PSAnLScpIHsKICAgICAgICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSB0cnVlOwogICAgICAgICAgICAgICR4ID0gc3Vic3RyKCR4LCAxKTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgJHggPSBzdHJfcGFkKCR4LCBzdHJsZW4oJHgpICsgKChNQVRIX0JJR0lOVEVHRVJfTUFYMTBfTEVOIC0gMSkgKiBzdHJsZW4oJHgpKSAlIE1BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4sIDAsIFNUUl9QQURfTEVGVCk7CgogICAgICAgICAgICB3aGlsZSAoc3RybGVuKCR4KSkgewogICAgICAgICAgICAgICR0ZW1wID0gJHRlbXAtPm11bHRpcGx5KCRtdWx0aXBsaWVyKTsKICAgICAgICAgICAgICAkdGVtcCA9ICR0ZW1wLT5hZGQobmV3IE1hdGhfQmlnSW50ZWdlcigkdGhpcy0+X2ludDJieXRlcyhzdWJzdHIoJHgsIDAsIE1BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4pKSwgMjU2KSk7CiAgICAgICAgICAgICAgJHggPSBzdWJzdHIoJHgsIE1BVEhfQklHSU5URUdFUl9NQVgxMF9MRU4pOwogICAgICAgICAgICB9CgogICAgICAgICAgICAkdGhpcy0+dmFsdWUgPSAkdGVtcC0+dmFsdWU7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICBjYXNlICAyOgogICAgICBjYXNlIC0yOgogICAgICAgIGlmICgkYmFzZSA+IDAgJiYgJHhbMF0gPT0gJy0nKSB7CiAgICAgICAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSB0cnVlOwogICAgICAgICAgJHggPSBzdWJzdHIoJHgsIDEpOwogICAgICAgIH0KCiAgICAgICAgJHggPSBwcmVnX3JlcGxhY2UoJyNeKFswMV0qKS4qIycsICckMScsICR4KTsKICAgICAgICAkeCA9IHN0cl9wYWQoJHgsIHN0cmxlbigkeCkgKyAoMyAqIHN0cmxlbigkeCkpICUgNCwgMCwgU1RSX1BBRF9MRUZUKTsKCiAgICAgICAgJHN0ciA9ICcweCc7CiAgICAgICAgd2hpbGUgKHN0cmxlbigkeCkpIHsKICAgICAgICAgICRwYXJ0ID0gc3Vic3RyKCR4LCAwLCA0KTsKICAgICAgICAgICRzdHIuPSBkZWNoZXgoYmluZGVjKCRwYXJ0KSk7CiAgICAgICAgICAkeCA9IHN1YnN0cigkeCwgNCk7CiAgICAgICAgfQoKICAgICAgICBpZiAoJHRoaXMtPmlzX25lZ2F0aXZlKSB7CiAgICAgICAgICAkc3RyID0gJy0nIC4gJHN0cjsKICAgICAgICB9CgogICAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigkc3RyLCA4ICogJGJhc2UpOyAvLyBpZS4gZWl0aGVyIC0xNiBvciArMTYKICAgICAgICAkdGhpcy0+dmFsdWUgPSAkdGVtcC0+dmFsdWU7CiAgICAgICAgJHRoaXMtPmlzX25lZ2F0aXZlID0gJHRlbXAtPmlzX25lZ2F0aXZlOwoKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAvLyBiYXNlIG5vdCBzdXBwb3J0ZWQsIHNvIHdlJ2xsIGxldCAkdGhpcyA9PSAwCiAgICB9CiAgfQoKICBmdW5jdGlvbiB0b0J5dGVzKCR0d29zX2NvbXBsaW1lbnQgPSBmYWxzZSkgewogICAgaWYgKCR0d29zX2NvbXBsaW1lbnQpIHsKICAgICAgJGNvbXBhcmlzb24gPSAkdGhpcy0+Y29tcGFyZShuZXcgTWF0aF9CaWdJbnRlZ2VyKCkpOwogICAgICBpZiAoJGNvbXBhcmlzb24gPT0gMCkgewogICAgICAgIHJldHVybiAkdGhpcy0+cHJlY2lzaW9uID4gMCA/IHN0cl9yZXBlYXQoY2hyKDApLCAoJHRoaXMtPnByZWNpc2lvbiArIDEpID4+IDMpIDogJyc7CiAgICAgIH0KCiAgICAgICR0ZW1wID0gJGNvbXBhcmlzb24gPCAwID8gJHRoaXMtPmFkZChuZXcgTWF0aF9CaWdJbnRlZ2VyKDEpKSA6ICR0aGlzLT5jb3B5KCk7CiAgICAgICRieXRlcyA9ICR0ZW1wLT50b0J5dGVzKCk7CgogICAgICBpZiAoZW1wdHkoJGJ5dGVzKSkgewogICAgICAgICRieXRlcyA9IGNocigwKTsKICAgICAgfQoKICAgICAgaWYgKG9yZCgkYnl0ZXNbMF0pICYgMHg4MCkgewogICAgICAgICRieXRlcyA9IGNocigwKSAuICRieXRlczsKICAgICAgfQoKICAgICAgcmV0dXJuICRjb21wYXJpc29uIDwgMCA/IH4kYnl0ZXMgOiAkYnl0ZXM7CiAgICB9CgogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGlmIChnbXBfY21wKCR0aGlzLT52YWx1ZSwgZ21wX2luaXQoMCkpID09IDApIHsKICAgICAgICAgIHJldHVybiAkdGhpcy0+cHJlY2lzaW9uID4gMCA/IHN0cl9yZXBlYXQoY2hyKDApLCAoJHRoaXMtPnByZWNpc2lvbiArIDEpID4+IDMpIDogJyc7CiAgICAgICAgfQoKICAgICAgICAkdGVtcCA9IGdtcF9zdHJ2YWwoZ21wX2FicygkdGhpcy0+dmFsdWUpLCAxNik7CiAgICAgICAgJHRlbXAgPSAoIHN0cmxlbigkdGVtcCkgJiAxICkgPyAnMCcgLiAkdGVtcCA6ICR0ZW1wOwogICAgICAgICR0ZW1wID0gcGFjaygnSConLCAkdGVtcCk7CgogICAgICAgIHJldHVybiAkdGhpcy0+cHJlY2lzaW9uID4gMCA/CiAgICAgICAgICBzdWJzdHIoc3RyX3BhZCgkdGVtcCwgJHRoaXMtPnByZWNpc2lvbiA+PiAzLCBjaHIoMCksIFNUUl9QQURfTEVGVCksIC0oJHRoaXMtPnByZWNpc2lvbiA+PiAzKSkgOgogICAgICAgICAgbHRyaW0oJHRlbXAsIGNocigwKSk7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgIGlmICgkdGhpcy0+dmFsdWUgPT09ICcwJykgewogICAgICAgICAgcmV0dXJuICR0aGlzLT5wcmVjaXNpb24gPiAwID8gc3RyX3JlcGVhdChjaHIoMCksICgkdGhpcy0+cHJlY2lzaW9uICsgMSkgPj4gMykgOiAnJzsKICAgICAgICB9CgogICAgICAgICR2YWx1ZSA9ICcnOwogICAgICAgICRjdXJyZW50ID0gJHRoaXMtPnZhbHVlOwoKICAgICAgICBpZiAoJGN1cnJlbnRbMF0gPT0gJy0nKSB7CiAgICAgICAgICAkY3VycmVudCA9IHN1YnN0cigkY3VycmVudCwgMSk7CiAgICAgICAgfQoKICAgICAgICB3aGlsZSAoYmNjb21wKCRjdXJyZW50LCAnMCcsIDApID4gMCkgewogICAgICAgICAgJHRlbXAgPSBiY21vZCgkY3VycmVudCwgJzE2Nzc3MjE2Jyk7CiAgICAgICAgICAkdmFsdWUgPSBjaHIoJHRlbXAgPj4gMTYpIC4gY2hyKCR0ZW1wID4+IDgpIC4gY2hyKCR0ZW1wKSAuICR2YWx1ZTsKICAgICAgICAgICRjdXJyZW50ID0gYmNkaXYoJGN1cnJlbnQsICcxNjc3NzIxNicsIDApOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuICR0aGlzLT5wcmVjaXNpb24gPiAwID8KICAgICAgICAgIHN1YnN0cihzdHJfcGFkKCR2YWx1ZSwgJHRoaXMtPnByZWNpc2lvbiA+PiAzLCBjaHIoMCksIFNUUl9QQURfTEVGVCksIC0oJHRoaXMtPnByZWNpc2lvbiA+PiAzKSkgOgogICAgICAgICAgbHRyaW0oJHZhbHVlLCBjaHIoMCkpOwogICAgfQoKICAgIGlmICghY291bnQoJHRoaXMtPnZhbHVlKSkgewogICAgICByZXR1cm4gJHRoaXMtPnByZWNpc2lvbiA+IDAgPyBzdHJfcmVwZWF0KGNocigwKSwgKCR0aGlzLT5wcmVjaXNpb24gKyAxKSA+PiAzKSA6ICcnOwogICAgfQogICAgJHJlc3VsdCA9ICR0aGlzLT5faW50MmJ5dGVzKCR0aGlzLT52YWx1ZVtjb3VudCgkdGhpcy0+dmFsdWUpIC0gMV0pOwoKICAgICR0ZW1wID0gJHRoaXMtPmNvcHkoKTsKCiAgICBmb3IgKCRpID0gY291bnQoJHRlbXAtPnZhbHVlKSAtIDI7ICRpID49IDA7IC0tJGkpIHsKICAgICAgJHRlbXAtPl9iYXNlMjU2X2xzaGlmdCgkcmVzdWx0LCBNQVRIX0JJR0lOVEVHRVJfQkFTRSk7CiAgICAgICRyZXN1bHQgPSAkcmVzdWx0IHwgc3RyX3BhZCgkdGVtcC0+X2ludDJieXRlcygkdGVtcC0+dmFsdWVbJGldKSwgc3RybGVuKCRyZXN1bHQpLCBjaHIoMCksIFNUUl9QQURfTEVGVCk7CiAgICB9CgogICAgcmV0dXJuICR0aGlzLT5wcmVjaXNpb24gPiAwID8KICAgICAgc3RyX3BhZChzdWJzdHIoJHJlc3VsdCwgLSgoJHRoaXMtPnByZWNpc2lvbiArIDcpID4+IDMpKSwgKCR0aGlzLT5wcmVjaXNpb24gKyA3KSA+PiAzLCBjaHIoMCksIFNUUl9QQURfTEVGVCkgOgogICAgICAkcmVzdWx0OwogIH0KCiAgZnVuY3Rpb24gdG9IZXgoJHR3b3NfY29tcGxpbWVudCA9IGZhbHNlKSB7CiAgICByZXR1cm4gYmluMmhleCgkdGhpcy0+dG9CeXRlcygkdHdvc19jb21wbGltZW50KSk7CiAgfQoKICBmdW5jdGlvbiB0b0JpdHMoJHR3b3NfY29tcGxpbWVudCA9IGZhbHNlKSB7CiAgICAkaGV4ID0gJHRoaXMtPnRvSGV4KCR0d29zX2NvbXBsaW1lbnQpOwogICAgJGJpdHMgPSAnJzsKICAgIGZvciAoJGkgPSBzdHJsZW4oJGhleCkgLSA4LCAkc3RhcnQgPSBzdHJsZW4oJGhleCkgJiA3OyAkaSA+PSAkc3RhcnQ7ICRpLT04KSB7CiAgICAgICRiaXRzID0gc3RyX3BhZChkZWNiaW4oaGV4ZGVjKHN1YnN0cigkaGV4LCAkaSwgOCkpKSwgMzIsICcwJywgU1RSX1BBRF9MRUZUKSAuICRiaXRzOwogICAgfQogICAgaWYgKCRzdGFydCkgewogICAgICAkYml0cyA9IHN0cl9wYWQoZGVjYmluKGhleGRlYyhzdWJzdHIoJGhleCwgMCwgJHN0YXJ0KSkpLCA4LCAnMCcsIFNUUl9QQURfTEVGVCkgLiAkYml0czsKICAgIH0KICAgICRyZXN1bHQgPSAkdGhpcy0+cHJlY2lzaW9uID4gMCA/IHN1YnN0cigkYml0cywgLSR0aGlzLT5wcmVjaXNpb24pIDogbHRyaW0oJGJpdHMsICcwJyk7CgogICAgaWYgKCR0d29zX2NvbXBsaW1lbnQgJiYgJHRoaXMtPmNvbXBhcmUobmV3IE1hdGhfQmlnSW50ZWdlcigpKSA+IDAgJiYgJHRoaXMtPnByZWNpc2lvbiA8PSAwKSB7CiAgICAgIHJldHVybiAnMCcgLiAkcmVzdWx0OwogICAgfQoKICAgIHJldHVybiAkcmVzdWx0OwogIH0KCiAgZnVuY3Rpb24gdG9TdHJpbmcoKSB7CiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgcmV0dXJuIGdtcF9zdHJ2YWwoJHRoaXMtPnZhbHVlKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgaWYgKCR0aGlzLT52YWx1ZSA9PT0gJzAnKSB7CiAgICAgICAgICByZXR1cm4gJzAnOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIGx0cmltKCR0aGlzLT52YWx1ZSwgJzAnKTsKICAgIH0KCiAgICBpZiAoIWNvdW50KCR0aGlzLT52YWx1ZSkpIHsKICAgICAgcmV0dXJuICcwJzsKICAgIH0KCiAgICAkdGVtcCA9ICR0aGlzLT5jb3B5KCk7CiAgICAkdGVtcC0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKCiAgICAkZGl2aXNvciA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRkaXZpc29yLT52YWx1ZSA9IGFycmF5KE1BVEhfQklHSU5URUdFUl9NQVgxMCk7CiAgICAkcmVzdWx0ID0gJyc7CiAgICB3aGlsZSAoY291bnQoJHRlbXAtPnZhbHVlKSkgewogICAgICBsaXN0KCR0ZW1wLCAkbW9kKSA9ICR0ZW1wLT5kaXZpZGUoJGRpdmlzb3IpOwogICAgICAkcmVzdWx0ID0gc3RyX3BhZChpc3NldCgkbW9kLT52YWx1ZVswXSkgPyAkbW9kLT52YWx1ZVswXSA6ICcnLCBNQVRIX0JJR0lOVEVHRVJfTUFYMTBfTEVOLCAnMCcsIFNUUl9QQURfTEVGVCkgLiAkcmVzdWx0OwogICAgfQogICAgJHJlc3VsdCA9IGx0cmltKCRyZXN1bHQsICcwJyk7CiAgICBpZiAoZW1wdHkoJHJlc3VsdCkpIHsKICAgICAgJHJlc3VsdCA9ICcwJzsKICAgIH0KCiAgICBpZiAoJHRoaXMtPmlzX25lZ2F0aXZlKSB7CiAgICAgICRyZXN1bHQgPSAnLScgLiAkcmVzdWx0OwogICAgfQoKICAgIHJldHVybiAkcmVzdWx0OwogIH0KCiAgZnVuY3Rpb24gY29weSgpIHsKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJHRlbXAtPnZhbHVlID0gJHRoaXMtPnZhbHVlOwogICAgJHRlbXAtPmlzX25lZ2F0aXZlID0gJHRoaXMtPmlzX25lZ2F0aXZlOwogICAgJHRlbXAtPnByZWNpc2lvbiA9ICR0aGlzLT5wcmVjaXNpb247CiAgICAkdGVtcC0+Yml0bWFzayA9ICR0aGlzLT5iaXRtYXNrOwogICAgcmV0dXJuICR0ZW1wOwogIH0KCiAgZnVuY3Rpb24gX190b1N0cmluZygpIHsKICAgIHJldHVybiAkdGhpcy0+dG9TdHJpbmcoKTsKICB9CgogIGZ1bmN0aW9uIF9fY2xvbmUoKSB7CiAgICByZXR1cm4gJHRoaXMtPmNvcHkoKTsKICB9CgogIGZ1bmN0aW9uIF9fc2xlZXAoKSB7CiAgICAkdGhpcy0+aGV4ID0gJHRoaXMtPnRvSGV4KHRydWUpOwogICAgJHZhcnMgPSBhcnJheSgnaGV4Jyk7CiAgICBpZiAoJHRoaXMtPnByZWNpc2lvbiA+IDApIHsKICAgICAgJHZhcnNbXSA9ICdwcmVjaXNpb24nOwogICAgfQogICAgcmV0dXJuICR2YXJzOwoKICB9CgogIGZ1bmN0aW9uIF9fd2FrZXVwKCkgewogICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCR0aGlzLT5oZXgsIC0xNik7CiAgICAkdGhpcy0+dmFsdWUgPSAkdGVtcC0+dmFsdWU7CiAgICAkdGhpcy0+aXNfbmVnYXRpdmUgPSAkdGVtcC0+aXNfbmVnYXRpdmU7CiAgICBpZiAoJHRoaXMtPnByZWNpc2lvbiA+IDApIHsKICAgICAgJHRoaXMtPnNldFByZWNpc2lvbigkdGhpcy0+cHJlY2lzaW9uKTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIGFkZCgkeSkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICR0ZW1wLT52YWx1ZSA9IGdtcF9hZGQoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUpOwoKICAgICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY2FkZCgkdGhpcy0+dmFsdWUsICR5LT52YWx1ZSwgMCk7CgogICAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CgogICAgJHRlbXAgPSAkdGhpcy0+X2FkZCgkdGhpcy0+dmFsdWUsICR0aGlzLT5pc19uZWdhdGl2ZSwgJHktPnZhbHVlLCAkeS0+aXNfbmVnYXRpdmUpOwoKICAgICRyZXN1bHQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkcmVzdWx0LT52YWx1ZSA9ICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgICAkcmVzdWx0LT5pc19uZWdhdGl2ZSA9ICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXTsKCiAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHJlc3VsdCk7CiAgfQoKICBmdW5jdGlvbiBfYWRkKCR4X3ZhbHVlLCAkeF9uZWdhdGl2ZSwgJHlfdmFsdWUsICR5X25lZ2F0aXZlKSB7CiAgICAkeF9zaXplID0gY291bnQoJHhfdmFsdWUpOwogICAgJHlfc2l6ZSA9IGNvdW50KCR5X3ZhbHVlKTsKCiAgICBpZiAoJHhfc2l6ZSA9PSAwKSB7CiAgICAgIHJldHVybiBhcnJheSgKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHlfdmFsdWUsCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gJHlfbmVnYXRpdmUKICAgICAgKTsKICAgIH0gZWxzZSBpZiAoJHlfc2l6ZSA9PSAwKSB7CiAgICAgIHJldHVybiBhcnJheSgKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHhfdmFsdWUsCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gJHhfbmVnYXRpdmUKICAgICAgKTsKICAgIH0KCiAgICBpZiAoICR4X25lZ2F0aXZlICE9ICR5X25lZ2F0aXZlICkgewogICAgICBpZiAoICR4X3ZhbHVlID09ICR5X3ZhbHVlICkgewogICAgICAgIHJldHVybiBhcnJheSgKICAgICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiBhcnJheSgpLAogICAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gZmFsc2UKICAgICAgICApOwogICAgICB9CgogICAgICAkdGVtcCA9ICR0aGlzLT5fc3VidHJhY3QoJHhfdmFsdWUsIGZhbHNlLCAkeV92YWx1ZSwgZmFsc2UpOwogICAgICAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0gPSAkdGhpcy0+X2NvbXBhcmUoJHhfdmFsdWUsIGZhbHNlLCAkeV92YWx1ZSwgZmFsc2UpID4gMCA/ICR4X25lZ2F0aXZlIDogJHlfbmVnYXRpdmU7CgogICAgICByZXR1cm4gJHRlbXA7CiAgICB9CgogICAgaWYgKCR4X3NpemUgPCAkeV9zaXplKSB7CiAgICAgICRzaXplID0gJHhfc2l6ZTsKICAgICAgJHZhbHVlID0gJHlfdmFsdWU7CiAgICB9IGVsc2UgewogICAgICAkc2l6ZSA9ICR5X3NpemU7CiAgICAgICR2YWx1ZSA9ICR4X3ZhbHVlOwogICAgfQoKICAgICR2YWx1ZVtdID0gMDsKCiAgICAkY2FycnkgPSAwOwogICAgZm9yICgkaSA9IDAsICRqID0gMTsgJGogPCAkc2l6ZTsgJGkrPTIsICRqKz0yKSB7CiAgICAgICRzdW0gPSAkeF92YWx1ZVskal0gKiBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICsgJHhfdmFsdWVbJGldICsgJHlfdmFsdWVbJGpdICogTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCArICR5X3ZhbHVlWyRpXSArICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gJHN1bSA+PSBNQVRIX0JJR0lOVEVHRVJfTUFYX0RJR0lUMjsKICAgICAgJHN1bSA9ICRjYXJyeSA/ICRzdW0gLSBNQVRIX0JJR0lOVEVHRVJfTUFYX0RJR0lUMiA6ICRzdW07CgogICAgICAkdGVtcCA9IChpbnQpICgkc3VtIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CgogICAgICAkdmFsdWVbJGldID0gKGludCkgKCRzdW0gLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogJHRlbXApOwogICAgICAkdmFsdWVbJGpdID0gJHRlbXA7CiAgICB9CgogICAgaWYgKCRqID09ICRzaXplKSB7CiAgICAgICRzdW0gPSAkeF92YWx1ZVskaV0gKyAkeV92YWx1ZVskaV0gKyAkY2Fycnk7CiAgICAgICRjYXJyeSA9ICRzdW0gPj0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTDsKICAgICAgJHZhbHVlWyRpXSA9ICRjYXJyeSA/ICRzdW0gLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMIDogJHN1bTsKICAgICAgKyskaTsKICAgIH0KCiAgICBpZiAoJGNhcnJ5KSB7CiAgICAgIGZvciAoOyAkdmFsdWVbJGldID09IE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQ7ICsrJGkpIHsKICAgICAgICAkdmFsdWVbJGldID0gMDsKICAgICAgfQogICAgICArKyR2YWx1ZVskaV07CiAgICB9CgogICAgcmV0dXJuIGFycmF5KAogICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHRoaXMtPl90cmltKCR2YWx1ZSksCiAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+ICR4X25lZ2F0aXZlCiAgICApOwogIH0KCiAgZnVuY3Rpb24gc3VidHJhY3QoJHkpIHsKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfc3ViKCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlKTsKCiAgICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHRlbXAtPnZhbHVlID0gYmNzdWIoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUsIDApOwoKICAgICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgfQoKICAgICR0ZW1wID0gJHRoaXMtPl9zdWJ0cmFjdCgkdGhpcy0+dmFsdWUsICR0aGlzLT5pc19uZWdhdGl2ZSwgJHktPnZhbHVlLCAkeS0+aXNfbmVnYXRpdmUpOwoKICAgICRyZXN1bHQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkcmVzdWx0LT52YWx1ZSA9ICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgICAkcmVzdWx0LT5pc19uZWdhdGl2ZSA9ICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXTsKCiAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHJlc3VsdCk7CiAgfQoKICBmdW5jdGlvbiBfc3VidHJhY3QoJHhfdmFsdWUsICR4X25lZ2F0aXZlLCAkeV92YWx1ZSwgJHlfbmVnYXRpdmUpIHsKICAgICR4X3NpemUgPSBjb3VudCgkeF92YWx1ZSk7CiAgICAkeV9zaXplID0gY291bnQoJHlfdmFsdWUpOwoKICAgIGlmICgkeF9zaXplID09IDApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiAkeV92YWx1ZSwKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfU0lHTiA9PiAhJHlfbmVnYXRpdmUKICAgICAgKTsKICAgIH0gZWxzZSBpZiAoJHlfc2l6ZSA9PSAwKSB7CiAgICAgIHJldHVybiBhcnJheSgKICAgICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHhfdmFsdWUsCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gJHhfbmVnYXRpdmUKICAgICAgKTsKICAgIH0KCiAgICBpZiAoICR4X25lZ2F0aXZlICE9ICR5X25lZ2F0aXZlICkgewogICAgICAkdGVtcCA9ICR0aGlzLT5fYWRkKCR4X3ZhbHVlLCBmYWxzZSwgJHlfdmFsdWUsIGZhbHNlKTsKICAgICAgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1NJR05dID0gJHhfbmVnYXRpdmU7CgogICAgICByZXR1cm4gJHRlbXA7CiAgICB9CgogICAgJGRpZmYgPSAkdGhpcy0+X2NvbXBhcmUoJHhfdmFsdWUsICR4X25lZ2F0aXZlLCAkeV92YWx1ZSwgJHlfbmVnYXRpdmUpOwoKICAgIGlmICggISRkaWZmICkgewogICAgICByZXR1cm4gYXJyYXkoCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+IGFycmF5KCksCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gZmFsc2UKICAgICAgKTsKICAgIH0KCiAgICBpZiAoICghJHhfbmVnYXRpdmUgJiYgJGRpZmYgPCAwKSB8fCAoJHhfbmVnYXRpdmUgJiYgJGRpZmYgPiAwKSApIHsKICAgICAgJHRlbXAgPSAkeF92YWx1ZTsKICAgICAgJHhfdmFsdWUgPSAkeV92YWx1ZTsKICAgICAgJHlfdmFsdWUgPSAkdGVtcDsKCiAgICAgICR4X25lZ2F0aXZlID0gISR4X25lZ2F0aXZlOwoKICAgICAgJHhfc2l6ZSA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICAgJHlfc2l6ZSA9IGNvdW50KCR5X3ZhbHVlKTsKICAgIH0KCiAgICAkY2FycnkgPSAwOwogICAgZm9yICgkaSA9IDAsICRqID0gMTsgJGogPCAkeV9zaXplOyAkaSs9MiwgJGorPTIpIHsKICAgICAgJHN1bSA9ICR4X3ZhbHVlWyRqXSAqIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKyAkeF92YWx1ZVskaV0gLSAkeV92YWx1ZVskal0gKiBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMIC0gJHlfdmFsdWVbJGldIC0gJGNhcnJ5OwogICAgICAkY2FycnkgPSAkc3VtIDwgMDsKICAgICAgJHN1bSA9ICRjYXJyeSA/ICRzdW0gKyBNQVRIX0JJR0lOVEVHRVJfTUFYX0RJR0lUMiA6ICRzdW07CgogICAgICAkdGVtcCA9IChpbnQpICgkc3VtIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CgogICAgICAkeF92YWx1ZVskaV0gPSAoaW50KSAoJHN1bSAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAkdGVtcCk7CiAgICAgICR4X3ZhbHVlWyRqXSA9ICR0ZW1wOwogICAgfQoKICAgIGlmICgkaiA9PSAkeV9zaXplKSB7CiAgICAgICRzdW0gPSAkeF92YWx1ZVskaV0gLSAkeV92YWx1ZVskaV0gLSAkY2Fycnk7CiAgICAgICRjYXJyeSA9ICRzdW0gPCAwOwogICAgICAkeF92YWx1ZVskaV0gPSAkY2FycnkgPyAkc3VtICsgTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCA6ICRzdW07CiAgICAgICsrJGk7CiAgICB9CgogICAgaWYgKCRjYXJyeSkgewogICAgICBmb3IgKDsgISR4X3ZhbHVlWyRpXTsgKyskaSkgewogICAgICAgICR4X3ZhbHVlWyRpXSA9IE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQ7CiAgICAgIH0KICAgICAgLS0keF92YWx1ZVskaV07CiAgICB9CgogICAgcmV0dXJuIGFycmF5KAogICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHRoaXMtPl90cmltKCR4X3ZhbHVlKSwKICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gJHhfbmVnYXRpdmUKICAgICk7CiAgfQoKICBmdW5jdGlvbiBtdWx0aXBseSgkeCkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICR0ZW1wLT52YWx1ZSA9IGdtcF9tdWwoJHRoaXMtPnZhbHVlLCAkeC0+dmFsdWUpOwoKICAgICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY211bCgkdGhpcy0+dmFsdWUsICR4LT52YWx1ZSwgMCk7CgogICAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CgogICAgJHRlbXAgPSAkdGhpcy0+X211bHRpcGx5KCR0aGlzLT52YWx1ZSwgJHRoaXMtPmlzX25lZ2F0aXZlLCAkeC0+dmFsdWUsICR4LT5pc19uZWdhdGl2ZSk7CgogICAgJHByb2R1Y3QgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkcHJvZHVjdC0+dmFsdWUgPSAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdOwogICAgJHByb2R1Y3QtPmlzX25lZ2F0aXZlID0gJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1NJR05dOwoKICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkcHJvZHVjdCk7CiAgfQoKICBmdW5jdGlvbiBfbXVsdGlwbHkoJHhfdmFsdWUsICR4X25lZ2F0aXZlLCAkeV92YWx1ZSwgJHlfbmVnYXRpdmUpIHsKICAgICR4X2xlbmd0aCA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICR5X2xlbmd0aCA9IGNvdW50KCR5X3ZhbHVlKTsKCiAgICBpZiAoICEkeF9sZW5ndGggfHwgISR5X2xlbmd0aCApIHsKICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgIE1BVEhfQklHSU5URUdFUl9WQUxVRSA9PiBhcnJheSgpLAogICAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+IGZhbHNlCiAgICAgICk7CiAgICB9CgogICAgcmV0dXJuIGFycmF5KAogICAgICBNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gbWluKCR4X2xlbmd0aCwgJHlfbGVuZ3RoKSA8IDIgKiBNQVRIX0JJR0lOVEVHRVJfS0FSQVRTVUJBX0NVVE9GRiA/CiAgICAgICAgJHRoaXMtPl90cmltKCR0aGlzLT5fcmVndWxhck11bHRpcGx5KCR4X3ZhbHVlLCAkeV92YWx1ZSkpIDoKICAgICAgICAkdGhpcy0+X3RyaW0oJHRoaXMtPl9rYXJhdHN1YmEoJHhfdmFsdWUsICR5X3ZhbHVlKSksCiAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+ICR4X25lZ2F0aXZlICE9ICR5X25lZ2F0aXZlCiAgICApOwogIH0KCiAgZnVuY3Rpb24gX3JlZ3VsYXJNdWx0aXBseSgkeF92YWx1ZSwgJHlfdmFsdWUpIHsKICAgICR4X2xlbmd0aCA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICR5X2xlbmd0aCA9IGNvdW50KCR5X3ZhbHVlKTsKCiAgICBpZiAoICEkeF9sZW5ndGggfHwgISR5X2xlbmd0aCApIHsKICAgICAgcmV0dXJuIGFycmF5KCk7CiAgICB9CgogICAgaWYgKCAkeF9sZW5ndGggPCAkeV9sZW5ndGggKSB7CiAgICAgICR0ZW1wID0gJHhfdmFsdWU7CiAgICAgICR4X3ZhbHVlID0gJHlfdmFsdWU7CiAgICAgICR5X3ZhbHVlID0gJHRlbXA7CgogICAgICAkeF9sZW5ndGggPSBjb3VudCgkeF92YWx1ZSk7CiAgICAgICR5X2xlbmd0aCA9IGNvdW50KCR5X3ZhbHVlKTsKICAgIH0KCiAgICAkcHJvZHVjdF92YWx1ZSA9ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsICR4X2xlbmd0aCArICR5X2xlbmd0aCk7CgogICAgJGNhcnJ5ID0gMDsKCiAgICBmb3IgKCRqID0gMDsgJGogPCAkeF9sZW5ndGg7ICsrJGopIHsKICAgICAgJHRlbXAgPSAkeF92YWx1ZVskal0gKiAkeV92YWx1ZVswXSArICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAgICAgICRwcm9kdWN0X3ZhbHVlWyRqXSA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAkY2FycnkpOwogICAgfQoKICAgICRwcm9kdWN0X3ZhbHVlWyRqXSA9ICRjYXJyeTsKCiAgICBmb3IgKCRpID0gMTsgJGkgPCAkeV9sZW5ndGg7ICsrJGkpIHsKICAgICAgJGNhcnJ5ID0gMDsKCiAgICAgIGZvciAoJGogPSAwLCAkayA9ICRpOyAkaiA8ICR4X2xlbmd0aDsgKyskaiwgKyskaykgewogICAgICAgICR0ZW1wID0gJHByb2R1Y3RfdmFsdWVbJGtdICsgJHhfdmFsdWVbJGpdICogJHlfdmFsdWVbJGldICsgJGNhcnJ5OwogICAgICAgICRjYXJyeSA9IChpbnQpICgkdGVtcCAvIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpOwogICAgICAgICRwcm9kdWN0X3ZhbHVlWyRrXSA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAkY2FycnkpOwogICAgICB9CgogICAgICAkcHJvZHVjdF92YWx1ZVska10gPSAkY2Fycnk7CiAgICB9CgogICAgcmV0dXJuICRwcm9kdWN0X3ZhbHVlOwogIH0KCiAgZnVuY3Rpb24gX2thcmF0c3ViYSgkeF92YWx1ZSwgJHlfdmFsdWUpIHsKICAgICRtID0gbWluKGNvdW50KCR4X3ZhbHVlKSA+PiAxLCBjb3VudCgkeV92YWx1ZSkgPj4gMSk7CgogICAgaWYgKCRtIDwgTUFUSF9CSUdJTlRFR0VSX0tBUkFUU1VCQV9DVVRPRkYpIHsKICAgICAgcmV0dXJuICR0aGlzLT5fcmVndWxhck11bHRpcGx5KCR4X3ZhbHVlLCAkeV92YWx1ZSk7CiAgICB9CgogICAgJHgxID0gYXJyYXlfc2xpY2UoJHhfdmFsdWUsICRtKTsKICAgICR4MCA9IGFycmF5X3NsaWNlKCR4X3ZhbHVlLCAwLCAkbSk7CiAgICAkeTEgPSBhcnJheV9zbGljZSgkeV92YWx1ZSwgJG0pOwogICAgJHkwID0gYXJyYXlfc2xpY2UoJHlfdmFsdWUsIDAsICRtKTsKCiAgICAkejIgPSAkdGhpcy0+X2thcmF0c3ViYSgkeDEsICR5MSk7CiAgICAkejAgPSAkdGhpcy0+X2thcmF0c3ViYSgkeDAsICR5MCk7CgogICAgJHoxID0gJHRoaXMtPl9hZGQoJHgxLCBmYWxzZSwgJHgwLCBmYWxzZSk7CiAgICAkdGVtcCA9ICR0aGlzLT5fYWRkKCR5MSwgZmFsc2UsICR5MCwgZmFsc2UpOwogICAgJHoxID0gJHRoaXMtPl9rYXJhdHN1YmEoJHoxW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0pOwogICAgJHRlbXAgPSAkdGhpcy0+X2FkZCgkejIsIGZhbHNlLCAkejAsIGZhbHNlKTsKICAgICR6MSA9ICR0aGlzLT5fc3VidHJhY3QoJHoxLCBmYWxzZSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UpOwoKICAgICR6MiA9IGFycmF5X21lcmdlKGFycmF5X2ZpbGwoMCwgMiAqICRtLCAwKSwgJHoyKTsKICAgICR6MVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdID0gYXJyYXlfbWVyZ2UoYXJyYXlfZmlsbCgwLCAkbSwgMCksICR6MVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdKTsKCiAgICAkeHkgPSAkdGhpcy0+X2FkZCgkejIsIGZhbHNlLCAkejFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHoxW01BVEhfQklHSU5URUdFUl9TSUdOXSk7CiAgICAkeHkgPSAkdGhpcy0+X2FkZCgkeHlbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHh5W01BVEhfQklHSU5URUdFUl9TSUdOXSwgJHowLCBmYWxzZSk7CgogICAgcmV0dXJuICR4eVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdOwogIH0KCiAgZnVuY3Rpb24gX3NxdWFyZSgkeCA9IGZhbHNlKSB7CiAgICByZXR1cm4gY291bnQoJHgpIDwgMiAqIE1BVEhfQklHSU5URUdFUl9LQVJBVFNVQkFfQ1VUT0ZGID8KICAgICAgJHRoaXMtPl90cmltKCR0aGlzLT5fYmFzZVNxdWFyZSgkeCkpIDoKICAgICAgJHRoaXMtPl90cmltKCR0aGlzLT5fa2FyYXRzdWJhU3F1YXJlKCR4KSk7CiAgfQoKICBmdW5jdGlvbiBfYmFzZVNxdWFyZSgkdmFsdWUpIHsKICAgIGlmICggZW1wdHkoJHZhbHVlKSApIHsKICAgICAgcmV0dXJuIGFycmF5KCk7CiAgICB9CiAgICAkc3F1YXJlX3ZhbHVlID0gJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgMiAqIGNvdW50KCR2YWx1ZSkpOwoKICAgIGZvciAoJGkgPSAwLCAkbWF4X2luZGV4ID0gY291bnQoJHZhbHVlKSAtIDE7ICRpIDw9ICRtYXhfaW5kZXg7ICsrJGkpIHsKICAgICAgJGkyID0gJGkgPDwgMTsKCiAgICAgICR0ZW1wID0gJHNxdWFyZV92YWx1ZVskaTJdICsgJHZhbHVlWyRpXSAqICR2YWx1ZVskaV07CiAgICAgICRjYXJyeSA9IChpbnQpICgkdGVtcCAvIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpOwogICAgICAkc3F1YXJlX3ZhbHVlWyRpMl0gPSAoaW50KSAoJHRlbXAgLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogJGNhcnJ5KTsKCiAgICAgIC8vIG5vdGUgaG93IHdlIHN0YXJ0IGZyb20gJGkrMSBpbnN0ZWFkIG9mIDAgYXMgd2UgZG8gaW4gbXVsdGlwbGljYXRpb24uCiAgICAgIGZvciAoJGogPSAkaSArIDEsICRrID0gJGkyICsgMTsgJGogPD0gJG1heF9pbmRleDsgKyskaiwgKyskaykgewogICAgICAgICR0ZW1wID0gJHNxdWFyZV92YWx1ZVska10gKyAyICogJHZhbHVlWyRqXSAqICR2YWx1ZVskaV0gKyAkY2Fycnk7CiAgICAgICAgJGNhcnJ5ID0gKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCk7CiAgICAgICAgJHNxdWFyZV92YWx1ZVska10gPSAoaW50KSAoJHRlbXAgLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogJGNhcnJ5KTsKICAgICAgfQoKICAgICAgLy8gdGhlIGZvbGxvd2luZyBsaW5lIGNhbiB5aWVsZCB2YWx1ZXMgbGFyZ2VyIDIqKjE1LiAgYXQgdGhpcyBwb2ludCwgUEhQIHNob3VsZCBzd2l0Y2gKICAgICAgLy8gb3ZlciB0byBmbG9hdHMuCiAgICAgICRzcXVhcmVfdmFsdWVbJGkgKyAkbWF4X2luZGV4ICsgMV0gPSAkY2Fycnk7CiAgICB9CgogICAgcmV0dXJuICRzcXVhcmVfdmFsdWU7CiAgfQoKICBmdW5jdGlvbiBfa2FyYXRzdWJhU3F1YXJlKCR2YWx1ZSkgewogICAgJG0gPSBjb3VudCgkdmFsdWUpID4+IDE7CgogICAgaWYgKCRtIDwgTUFUSF9CSUdJTlRFR0VSX0tBUkFUU1VCQV9DVVRPRkYpIHsKICAgICAgcmV0dXJuICR0aGlzLT5fYmFzZVNxdWFyZSgkdmFsdWUpOwogICAgfQoKICAgICR4MSA9IGFycmF5X3NsaWNlKCR2YWx1ZSwgJG0pOwogICAgJHgwID0gYXJyYXlfc2xpY2UoJHZhbHVlLCAwLCAkbSk7CgogICAgJHoyID0gJHRoaXMtPl9rYXJhdHN1YmFTcXVhcmUoJHgxKTsKICAgICR6MCA9ICR0aGlzLT5fa2FyYXRzdWJhU3F1YXJlKCR4MCk7CgogICAgJHoxID0gJHRoaXMtPl9hZGQoJHgxLCBmYWxzZSwgJHgwLCBmYWxzZSk7CiAgICAkejEgPSAkdGhpcy0+X2thcmF0c3ViYVNxdWFyZSgkejFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSk7CiAgICAkdGVtcCA9ICR0aGlzLT5fYWRkKCR6MiwgZmFsc2UsICR6MCwgZmFsc2UpOwogICAgJHoxID0gJHRoaXMtPl9zdWJ0cmFjdCgkejEsIGZhbHNlLCAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSk7CgogICAgJHoyID0gYXJyYXlfbWVyZ2UoYXJyYXlfZmlsbCgwLCAyICogJG0sIDApLCAkejIpOwogICAgJHoxW01BVEhfQklHSU5URUdFUl9WQUxVRV0gPSBhcnJheV9tZXJnZShhcnJheV9maWxsKDAsICRtLCAwKSwgJHoxW01BVEhfQklHSU5URUdFUl9WQUxVRV0pOwoKICAgICR4eCA9ICR0aGlzLT5fYWRkKCR6MiwgZmFsc2UsICR6MVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkejFbTUFUSF9CSUdJTlRFR0VSX1NJR05dKTsKICAgICR4eCA9ICR0aGlzLT5fYWRkKCR4eFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkeHhbTUFUSF9CSUdJTlRFR0VSX1NJR05dLCAkejAsIGZhbHNlKTsKCiAgICByZXR1cm4gJHh4W01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgfQoKICBmdW5jdGlvbiBkaXZpZGUoJHkpIHsKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAkcXVvdGllbnQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHJlbWFpbmRlciA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKCiAgICAgICAgbGlzdCgkcXVvdGllbnQtPnZhbHVlLCAkcmVtYWluZGVyLT52YWx1ZSkgPSBnbXBfZGl2X3FyKCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlKTsKCiAgICAgICAgaWYgKGdtcF9zaWduKCRyZW1haW5kZXItPnZhbHVlKSA8IDApIHsKICAgICAgICAgICRyZW1haW5kZXItPnZhbHVlID0gZ21wX2FkZCgkcmVtYWluZGVyLT52YWx1ZSwgZ21wX2FicygkeS0+dmFsdWUpKTsKICAgICAgICB9CgogICAgICAgIHJldHVybiBhcnJheSgkdGhpcy0+X25vcm1hbGl6ZSgkcXVvdGllbnQpLCAkdGhpcy0+X25vcm1hbGl6ZSgkcmVtYWluZGVyKSk7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICRxdW90aWVudCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkcmVtYWluZGVyID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwoKICAgICAgICAkcXVvdGllbnQtPnZhbHVlID0gYmNkaXYoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUsIDApOwogICAgICAgICRyZW1haW5kZXItPnZhbHVlID0gYmNtb2QoJHRoaXMtPnZhbHVlLCAkeS0+dmFsdWUpOwoKICAgICAgICBpZiAoJHJlbWFpbmRlci0+dmFsdWVbMF0gPT0gJy0nKSB7CiAgICAgICAgICAkcmVtYWluZGVyLT52YWx1ZSA9IGJjYWRkKCRyZW1haW5kZXItPnZhbHVlLCAkeS0+dmFsdWVbMF0gPT0gJy0nID8gc3Vic3RyKCR5LT52YWx1ZSwgMSkgOiAkeS0+dmFsdWUsIDApOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIGFycmF5KCR0aGlzLT5fbm9ybWFsaXplKCRxdW90aWVudCksICR0aGlzLT5fbm9ybWFsaXplKCRyZW1haW5kZXIpKTsKICAgIH0KCiAgICBpZiAoY291bnQoJHktPnZhbHVlKSA9PSAxKSB7CiAgICAgIGxpc3QoJHEsICRyKSA9ICR0aGlzLT5fZGl2aWRlX2RpZ2l0KCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlWzBdKTsKICAgICAgJHF1b3RpZW50ID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcmVtYWluZGVyID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcXVvdGllbnQtPnZhbHVlID0gJHE7CiAgICAgICRyZW1haW5kZXItPnZhbHVlID0gYXJyYXkoJHIpOwogICAgICAkcXVvdGllbnQtPmlzX25lZ2F0aXZlID0gJHRoaXMtPmlzX25lZ2F0aXZlICE9ICR5LT5pc19uZWdhdGl2ZTsKICAgICAgcmV0dXJuIGFycmF5KCR0aGlzLT5fbm9ybWFsaXplKCRxdW90aWVudCksICR0aGlzLT5fbm9ybWFsaXplKCRyZW1haW5kZXIpKTsKICAgIH0KCiAgICBzdGF0aWMgJHplcm87CiAgICBpZiAoICFpc3NldCgkemVybykgKSB7CiAgICAgICR6ZXJvID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgfQoKICAgICR4ID0gJHRoaXMtPmNvcHkoKTsKICAgICR5ID0gJHktPmNvcHkoKTsKCiAgICAkeF9zaWduID0gJHgtPmlzX25lZ2F0aXZlOwogICAgJHlfc2lnbiA9ICR5LT5pc19uZWdhdGl2ZTsKCiAgICAkeC0+aXNfbmVnYXRpdmUgPSAkeS0+aXNfbmVnYXRpdmUgPSBmYWxzZTsKCiAgICAkZGlmZiA9ICR4LT5jb21wYXJlKCR5KTsKCiAgICBpZiAoICEkZGlmZiApIHsKICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICR0ZW1wLT52YWx1ZSA9IGFycmF5KDEpOwogICAgICAkdGVtcC0+aXNfbmVnYXRpdmUgPSAkeF9zaWduICE9ICR5X3NpZ247CiAgICAgIHJldHVybiBhcnJheSgkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCksICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoKSkpOwogICAgfQoKICAgIGlmICggJGRpZmYgPCAwICkgewogICAgICAvLyBpZiAkeCBpcyBuZWdhdGl2ZSwgImFkZCIgJHkuCiAgICAgIGlmICggJHhfc2lnbiApIHsKICAgICAgICAkeCA9ICR5LT5zdWJ0cmFjdCgkeCk7CiAgICAgIH0KICAgICAgcmV0dXJuIGFycmF5KCR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoKSksICR0aGlzLT5fbm9ybWFsaXplKCR4KSk7CiAgICB9CgogICAgLy8gbm9ybWFsaXplICR4IGFuZCAkeSBhcyBkZXNjcmliZWQgaW4gSEFDIDE0LjIzIC8gMTQuMjQKICAgICRtc2IgPSAkeS0+dmFsdWVbY291bnQoJHktPnZhbHVlKSAtIDFdOwogICAgZm9yICgkc2hpZnQgPSAwOyAhKCRtc2IgJiBNQVRIX0JJR0lOVEVHRVJfTVNCKTsgKyskc2hpZnQpIHsKICAgICAgJG1zYiA8PD0gMTsKICAgIH0KICAgICR4LT5fbHNoaWZ0KCRzaGlmdCk7CiAgICAkeS0+X2xzaGlmdCgkc2hpZnQpOwogICAgJHlfdmFsdWUgPSAmJHktPnZhbHVlOwoKICAgICR4X21heCA9IGNvdW50KCR4LT52YWx1ZSkgLSAxOwogICAgJHlfbWF4ID0gY291bnQoJHktPnZhbHVlKSAtIDE7CgogICAgJHF1b3RpZW50ID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJHF1b3RpZW50X3ZhbHVlID0gJiRxdW90aWVudC0+dmFsdWU7CiAgICAkcXVvdGllbnRfdmFsdWUgPSAkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkeF9tYXggLSAkeV9tYXggKyAxKTsKCiAgICBzdGF0aWMgJHRlbXAsICRsaHMsICRyaHM7CiAgICBpZiAoIWlzc2V0KCR0ZW1wKSkgewogICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJGxocyA9ICBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRyaHMgPSAgbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgfQogICAgJHRlbXBfdmFsdWUgPSAmJHRlbXAtPnZhbHVlOwogICAgJHJoc192YWx1ZSA9ICAmJHJocy0+dmFsdWU7CgogICAgLy8gJHRlbXAgPSAkeSA8PCAoJHhfbWF4IC0gJHlfbWF4LTEpIGluIGJhc2UgMioqMjYKICAgICR0ZW1wX3ZhbHVlID0gYXJyYXlfbWVyZ2UoJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgJHhfbWF4IC0gJHlfbWF4KSwgJHlfdmFsdWUpOwoKICAgIHdoaWxlICggJHgtPmNvbXBhcmUoJHRlbXApID49IDAgKSB7CiAgICAgIC8vIGNhbGN1bGF0ZSB0aGUgImNvbW1vbiByZXNpZHVlIgogICAgICArKyRxdW90aWVudF92YWx1ZVskeF9tYXggLSAkeV9tYXhdOwogICAgICAkeCA9ICR4LT5zdWJ0cmFjdCgkdGVtcCk7CiAgICAgICR4X21heCA9IGNvdW50KCR4LT52YWx1ZSkgLSAxOwogICAgfQoKICAgIGZvciAoJGkgPSAkeF9tYXg7ICRpID49ICR5X21heCArIDE7IC0tJGkpIHsKICAgICAgJHhfdmFsdWUgPSAmJHgtPnZhbHVlOwogICAgICAkeF93aW5kb3cgPSBhcnJheSgKICAgICAgICBpc3NldCgkeF92YWx1ZVskaV0pID8gJHhfdmFsdWVbJGldIDogMCwKICAgICAgICBpc3NldCgkeF92YWx1ZVskaSAtIDFdKSA/ICR4X3ZhbHVlWyRpIC0gMV0gOiAwLAogICAgICAgIGlzc2V0KCR4X3ZhbHVlWyRpIC0gMl0pID8gJHhfdmFsdWVbJGkgLSAyXSA6IDAKICAgICAgKTsKICAgICAgJHlfd2luZG93ID0gYXJyYXkoCiAgICAgICAgJHlfdmFsdWVbJHlfbWF4XSwKICAgICAgICAoICR5X21heCA+IDAgKSA/ICR5X3ZhbHVlWyR5X21heCAtIDFdIDogMAogICAgICApOwoKICAgICAgJHFfaW5kZXggPSAkaSAtICR5X21heCAtIDE7CiAgICAgIGlmICgkeF93aW5kb3dbMF0gPT0gJHlfd2luZG93WzBdKSB7CiAgICAgICAgJHF1b3RpZW50X3ZhbHVlWyRxX2luZGV4XSA9IE1BVEhfQklHSU5URUdFUl9NQVhfRElHSVQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgJHF1b3RpZW50X3ZhbHVlWyRxX2luZGV4XSA9IChpbnQpICgKICAgICAgICAgICgkeF93aW5kb3dbMF0gKiBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICsgJHhfd2luZG93WzFdKQogICAgICAgICAgLwogICAgICAgICAgJHlfd2luZG93WzBdCiAgICAgICAgKTsKICAgICAgfQoKICAgICAgJHRlbXBfdmFsdWUgPSBhcnJheSgkeV93aW5kb3dbMV0sICR5X3dpbmRvd1swXSk7CgogICAgICAkbGhzLT52YWx1ZSA9IGFycmF5KCRxdW90aWVudF92YWx1ZVskcV9pbmRleF0pOwogICAgICAkbGhzID0gJGxocy0+bXVsdGlwbHkoJHRlbXApOwoKICAgICAgJHJoc192YWx1ZSA9IGFycmF5KCR4X3dpbmRvd1syXSwgJHhfd2luZG93WzFdLCAkeF93aW5kb3dbMF0pOwoKICAgICAgd2hpbGUgKCAkbGhzLT5jb21wYXJlKCRyaHMpID4gMCApIHsKICAgICAgICAtLSRxdW90aWVudF92YWx1ZVskcV9pbmRleF07CgogICAgICAgICRsaHMtPnZhbHVlID0gYXJyYXkoJHF1b3RpZW50X3ZhbHVlWyRxX2luZGV4XSk7CiAgICAgICAgJGxocyA9ICRsaHMtPm11bHRpcGx5KCR0ZW1wKTsKICAgICAgfQoKICAgICAgJGFkanVzdCA9ICR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsICRxX2luZGV4KTsKICAgICAgJHRlbXBfdmFsdWUgPSBhcnJheSgkcXVvdGllbnRfdmFsdWVbJHFfaW5kZXhdKTsKICAgICAgJHRlbXAgPSAkdGVtcC0+bXVsdGlwbHkoJHkpOwogICAgICAkdGVtcF92YWx1ZSA9ICYkdGVtcC0+dmFsdWU7CiAgICAgICR0ZW1wX3ZhbHVlID0gYXJyYXlfbWVyZ2UoJGFkanVzdCwgJHRlbXBfdmFsdWUpOwoKICAgICAgJHggPSAkeC0+c3VidHJhY3QoJHRlbXApOwoKICAgICAgaWYgKCR4LT5jb21wYXJlKCR6ZXJvKSA8IDApIHsKICAgICAgICAkdGVtcF92YWx1ZSA9IGFycmF5X21lcmdlKCRhZGp1c3QsICR5X3ZhbHVlKTsKICAgICAgICAkeCA9ICR4LT5hZGQoJHRlbXApOwoKICAgICAgICAtLSRxdW90aWVudF92YWx1ZVskcV9pbmRleF07CiAgICAgIH0KCiAgICAgICR4X21heCA9IGNvdW50KCR4X3ZhbHVlKSAtIDE7CiAgICB9CgogICAgJHgtPl9yc2hpZnQoJHNoaWZ0KTsKCiAgICAkcXVvdGllbnQtPmlzX25lZ2F0aXZlID0gJHhfc2lnbiAhPSAkeV9zaWduOwoKICAgIGlmICggJHhfc2lnbiApIHsKICAgICAgJHktPl9yc2hpZnQoJHNoaWZ0KTsKICAgICAgJHggPSAkeS0+c3VidHJhY3QoJHgpOwogICAgfQoKICAgIHJldHVybiBhcnJheSgkdGhpcy0+X25vcm1hbGl6ZSgkcXVvdGllbnQpLCAkdGhpcy0+X25vcm1hbGl6ZSgkeCkpOwogIH0KCiAgZnVuY3Rpb24gX2RpdmlkZV9kaWdpdCgkZGl2aWRlbmQsICRkaXZpc29yKSB7CiAgICAkY2FycnkgPSAwOwogICAgJHJlc3VsdCA9IGFycmF5KCk7CgogICAgZm9yICgkaSA9IGNvdW50KCRkaXZpZGVuZCkgLSAxOyAkaSA+PSAwOyAtLSRpKSB7CiAgICAgICR0ZW1wID0gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCAqICRjYXJyeSArICRkaXZpZGVuZFskaV07CiAgICAgICRyZXN1bHRbJGldID0gKGludCkgKCR0ZW1wIC8gJGRpdmlzb3IpOwogICAgICAkY2FycnkgPSAoaW50KSAoJHRlbXAgLSAkZGl2aXNvciAqICRyZXN1bHRbJGldKTsKICAgIH0KCiAgICByZXR1cm4gYXJyYXkoJHJlc3VsdCwgJGNhcnJ5KTsKICB9CgogIGZ1bmN0aW9uIG1vZFBvdygkZSwgJG4pIHsKICAgICRuID0gJHRoaXMtPmJpdG1hc2sgIT09IGZhbHNlICYmICR0aGlzLT5iaXRtYXNrLT5jb21wYXJlKCRuKSA8IDAgPyAkdGhpcy0+Yml0bWFzayA6ICRuLT5hYnMoKTsKCiAgICBpZiAoJGUtPmNvbXBhcmUobmV3IE1hdGhfQmlnSW50ZWdlcigpKSA8IDApIHsKICAgICAgJGUgPSAkZS0+YWJzKCk7CgogICAgICAkdGVtcCA9ICR0aGlzLT5tb2RJbnZlcnNlKCRuKTsKICAgICAgaWYgKCR0ZW1wID09PSBmYWxzZSkgewogICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgfQoKICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wLT5tb2RQb3coJGUsICRuKSk7CiAgICB9CgogICAgaWYgKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVAgKSB7CiAgICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfcG93bSgkdGhpcy0+dmFsdWUsICRlLT52YWx1ZSwgJG4tPnZhbHVlKTsKCiAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CgogICAgaWYgKCR0aGlzLT5jb21wYXJlKG5ldyBNYXRoX0JpZ0ludGVnZXIoKSkgPCAwIHx8ICR0aGlzLT5jb21wYXJlKCRuKSA+IDApIHsKICAgICAgbGlzdCgsICR0ZW1wKSA9ICR0aGlzLT5kaXZpZGUoJG4pOwogICAgICByZXR1cm4gJHRlbXAtPm1vZFBvdygkZSwgJG4pOwogICAgfQoKICAgIGlmIChkZWZpbmVkKCdNQVRIX0JJR0lOVEVHRVJfT1BFTlNTTF9FTkFCTEVEJykpIHsKICAgICAgJGNvbXBvbmVudHMgPSBhcnJheSgKICAgICAgICAnbW9kdWx1cycgPT4gJG4tPnRvQnl0ZXModHJ1ZSksCiAgICAgICAgJ3B1YmxpY0V4cG9uZW50JyA9PiAkZS0+dG9CeXRlcyh0cnVlKQogICAgICApOwoKICAgICAgJGNvbXBvbmVudHMgPSBhcnJheSgKICAgICAgICAnbW9kdWx1cycgPT4gcGFjaygnQ2EqYSonLCAyLCAkdGhpcy0+X2VuY29kZUFTTjFMZW5ndGgoc3RybGVuKCRjb21wb25lbnRzWydtb2R1bHVzJ10pKSwgJGNvbXBvbmVudHNbJ21vZHVsdXMnXSksCiAgICAgICAgJ3B1YmxpY0V4cG9uZW50JyA9PiBwYWNrKCdDYSphKicsIDIsICR0aGlzLT5fZW5jb2RlQVNOMUxlbmd0aChzdHJsZW4oJGNvbXBvbmVudHNbJ3B1YmxpY0V4cG9uZW50J10pKSwgJGNvbXBvbmVudHNbJ3B1YmxpY0V4cG9uZW50J10pCiAgICAgICk7CgogICAgICAkUlNBUHVibGljS2V5ID0gcGFjaygnQ2EqYSphKicsCiAgICAgICAgNDgsICR0aGlzLT5fZW5jb2RlQVNOMUxlbmd0aChzdHJsZW4oJGNvbXBvbmVudHNbJ21vZHVsdXMnXSkgKyBzdHJsZW4oJGNvbXBvbmVudHNbJ3B1YmxpY0V4cG9uZW50J10pKSwKICAgICAgICAkY29tcG9uZW50c1snbW9kdWx1cyddLCAkY29tcG9uZW50c1sncHVibGljRXhwb25lbnQnXQogICAgICApOwoKICAgICAgJHJzYU9JRCA9IHBhY2soJ0gqJywgJzMwMGQwNjA5MmE4NjQ4ODZmNzBkMDEwMTAxMDUwMCcpOyAvLyBoZXggdmVyc2lvbiBvZiBNQTBHQ1NxR1NJYjNEUUVCQVFVQQogICAgICAkUlNBUHVibGljS2V5ID0gY2hyKDApIC4gJFJTQVB1YmxpY0tleTsKICAgICAgJFJTQVB1YmxpY0tleSA9IGNocigzKSAuICR0aGlzLT5fZW5jb2RlQVNOMUxlbmd0aChzdHJsZW4oJFJTQVB1YmxpY0tleSkpIC4gJFJTQVB1YmxpY0tleTsKCiAgICAgICRlbmNhcHN1bGF0ZWQgPSBwYWNrKCdDYSphKicsCiAgICAgICAgNDgsICR0aGlzLT5fZW5jb2RlQVNOMUxlbmd0aChzdHJsZW4oJHJzYU9JRCAuICRSU0FQdWJsaWNLZXkpKSwgJHJzYU9JRCAuICRSU0FQdWJsaWNLZXkKICAgICAgKTsKCiAgICAgICRSU0FQdWJsaWNLZXkgPSAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cclxuIiAuCiAgICAgICAgICAgICAgIGNodW5rX3NwbGl0KGJhc2U2NF9lbmNvZGUoJGVuY2Fwc3VsYXRlZCkpIC4KICAgICAgICAgICAgICAgJy0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLSc7CgogICAgICAkcGxhaW50ZXh0ID0gc3RyX3BhZCgkdGhpcy0+dG9CeXRlcygpLCBzdHJsZW4oJG4tPnRvQnl0ZXModHJ1ZSkpIC0gMSwgIlwwIiwgU1RSX1BBRF9MRUZUKTsKCiAgICAgIGlmIChvcGVuc3NsX3B1YmxpY19lbmNyeXB0KCRwbGFpbnRleHQsICRyZXN1bHQsICRSU0FQdWJsaWNLZXksIE9QRU5TU0xfTk9fUEFERElORykpIHsKICAgICAgICByZXR1cm4gbmV3IE1hdGhfQmlnSW50ZWdlcigkcmVzdWx0LCAyNTYpOwogICAgICB9CiAgICB9CgogICAgaWYgKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEggKSB7CiAgICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJHRlbXAtPnZhbHVlID0gYmNwb3dtb2QoJHRoaXMtPnZhbHVlLCAkZS0+dmFsdWUsICRuLT52YWx1ZSwgMCk7CgogICAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CgogICAgaWYgKCBlbXB0eSgkZS0+dmFsdWUpICkgewogICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJHRlbXAtPnZhbHVlID0gYXJyYXkoMSk7CiAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CgogICAgaWYgKCAkZS0+dmFsdWUgPT0gYXJyYXkoMSkgKSB7CiAgICAgIGxpc3QoLCAkdGVtcCkgPSAkdGhpcy0+ZGl2aWRlKCRuKTsKICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICAgIH0KCiAgICBpZiAoICRlLT52YWx1ZSA9PSBhcnJheSgyKSApIHsKICAgICAgJHRlbXAgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICR0ZW1wLT52YWx1ZSA9ICR0aGlzLT5fc3F1YXJlKCR0aGlzLT52YWx1ZSk7CiAgICAgIGxpc3QoLCAkdGVtcCkgPSAkdGVtcC0+ZGl2aWRlKCRuKTsKICAgICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCR0ZW1wKTsKICAgIH0KCiAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRoaXMtPl9zbGlkaW5nV2luZG93KCRlLCAkbiwgTUFUSF9CSUdJTlRFR0VSX0JBUlJFVFQpKTsKCiAgICBpZiAoICRuLT52YWx1ZVswXSAmIDEgKSB7CiAgICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGhpcy0+X3NsaWRpbmdXaW5kb3coJGUsICRuLCBNQVRIX0JJR0lOVEVHRVJfTU9OVEdPTUVSWSkpOwogICAgfQogICAgZm9yICgkaSA9IDA7ICRpIDwgY291bnQoJG4tPnZhbHVlKTsgKyskaSkgewogICAgICBpZiAoICRuLT52YWx1ZVskaV0gKSB7CiAgICAgICAgJHRlbXAgPSBkZWNiaW4oJG4tPnZhbHVlWyRpXSk7CiAgICAgICAgJGogPSBzdHJsZW4oJHRlbXApIC0gc3RycnBvcygkdGVtcCwgJzEnKSAtIDE7CiAgICAgICAgJGorPSAyNiAqICRpOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CgogICAgJG1vZDEgPSAkbi0+Y29weSgpOwogICAgJG1vZDEtPl9yc2hpZnQoJGopOwogICAgJG1vZDIgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkbW9kMi0+dmFsdWUgPSBhcnJheSgxKTsKICAgICRtb2QyLT5fbHNoaWZ0KCRqKTsKCiAgICAkcGFydDEgPSAoICRtb2QxLT52YWx1ZSAhPSBhcnJheSgxKSApID8gJHRoaXMtPl9zbGlkaW5nV2luZG93KCRlLCAkbW9kMSwgTUFUSF9CSUdJTlRFR0VSX01PTlRHT01FUlkpIDogbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJHBhcnQyID0gJHRoaXMtPl9zbGlkaW5nV2luZG93KCRlLCAkbW9kMiwgTUFUSF9CSUdJTlRFR0VSX1BPV0VST0YyKTsKCiAgICAkeTEgPSAkbW9kMi0+bW9kSW52ZXJzZSgkbW9kMSk7CiAgICAkeTIgPSAkbW9kMS0+bW9kSW52ZXJzZSgkbW9kMik7CgogICAgJHJlc3VsdCA9ICRwYXJ0MS0+bXVsdGlwbHkoJG1vZDIpOwogICAgJHJlc3VsdCA9ICRyZXN1bHQtPm11bHRpcGx5KCR5MSk7CgogICAgJHRlbXAgPSAkcGFydDItPm11bHRpcGx5KCRtb2QxKTsKICAgICR0ZW1wID0gJHRlbXAtPm11bHRpcGx5KCR5Mik7CgogICAgJHJlc3VsdCA9ICRyZXN1bHQtPmFkZCgkdGVtcCk7CiAgICBsaXN0KCwgJHJlc3VsdCkgPSAkcmVzdWx0LT5kaXZpZGUoJG4pOwoKICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkcmVzdWx0KTsKICB9CgogIGZ1bmN0aW9uIHBvd01vZCgkZSwgJG4pIHsKICAgIHJldHVybiAkdGhpcy0+bW9kUG93KCRlLCAkbik7CiAgfQoKICBmdW5jdGlvbiBfc2xpZGluZ1dpbmRvdygkZSwgJG4sICRtb2RlKSB7CiAgICBzdGF0aWMgJHdpbmRvd19yYW5nZXMgPSBhcnJheSg3LCAyNSwgODEsIDI0MSwgNjczLCAxNzkzKTsKCiAgICAkZV92YWx1ZSA9ICRlLT52YWx1ZTsKICAgICRlX2xlbmd0aCA9IGNvdW50KCRlX3ZhbHVlKSAtIDE7CiAgICAkZV9iaXRzID0gZGVjYmluKCRlX3ZhbHVlWyRlX2xlbmd0aF0pOwogICAgZm9yICgkaSA9ICRlX2xlbmd0aCAtIDE7ICRpID49IDA7IC0tJGkpIHsKICAgICAgJGVfYml0cy49IHN0cl9wYWQoZGVjYmluKCRlX3ZhbHVlWyRpXSksIE1BVEhfQklHSU5URUdFUl9CQVNFLCAnMCcsIFNUUl9QQURfTEVGVCk7CiAgICB9CgogICAgJGVfbGVuZ3RoID0gc3RybGVuKCRlX2JpdHMpOwoKICAgIGZvciAoJGkgPSAwLCAkd2luZG93X3NpemUgPSAxOyAkZV9sZW5ndGggPiAkd2luZG93X3Jhbmdlc1skaV0gJiYgJGkgPCBjb3VudCgkd2luZG93X3Jhbmdlcyk7ICsrJHdpbmRvd19zaXplLCArKyRpKTsKCiAgICAkbl92YWx1ZSA9ICRuLT52YWx1ZTsKCiAgICAkcG93ZXJzID0gYXJyYXkoKTsKICAgICRwb3dlcnNbMV0gPSAkdGhpcy0+X3ByZXBhcmVSZWR1Y2UoJHRoaXMtPnZhbHVlLCAkbl92YWx1ZSwgJG1vZGUpOwogICAgJHBvd2Vyc1syXSA9ICR0aGlzLT5fc3F1YXJlUmVkdWNlKCRwb3dlcnNbMV0sICRuX3ZhbHVlLCAkbW9kZSk7CgogICAgJHRlbXAgPSAxIDw8ICgkd2luZG93X3NpemUgLSAxKTsKICAgIGZvciAoJGkgPSAxOyAkaSA8ICR0ZW1wOyArKyRpKSB7CiAgICAgICRpMiA9ICRpIDw8IDE7CiAgICAgICRwb3dlcnNbJGkyICsgMV0gPSAkdGhpcy0+X211bHRpcGx5UmVkdWNlKCRwb3dlcnNbJGkyIC0gMV0sICRwb3dlcnNbMl0sICRuX3ZhbHVlLCAkbW9kZSk7CiAgICB9CgogICAgJHJlc3VsdCA9IGFycmF5KDEpOwogICAgJHJlc3VsdCA9ICR0aGlzLT5fcHJlcGFyZVJlZHVjZSgkcmVzdWx0LCAkbl92YWx1ZSwgJG1vZGUpOwoKICAgIGZvciAoJGkgPSAwOyAkaSA8ICRlX2xlbmd0aDsgKSB7CiAgICAgIGlmICggISRlX2JpdHNbJGldICkgewogICAgICAgICRyZXN1bHQgPSAkdGhpcy0+X3NxdWFyZVJlZHVjZSgkcmVzdWx0LCAkbl92YWx1ZSwgJG1vZGUpOwogICAgICAgICsrJGk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZm9yICgkaiA9ICR3aW5kb3dfc2l6ZSAtIDE7ICRqID4gMDsgLS0kaikgewogICAgICAgICAgaWYgKCAhZW1wdHkoJGVfYml0c1skaSArICRqXSkgKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgZm9yICgkayA9IDA7ICRrIDw9ICRqOyArKyRrKSB7Ly8gZWcuIHRoZSBsZW5ndGggb2Ygc3Vic3RyKCRlX2JpdHMsICRpLCAkaisxKQogICAgICAgICAgJHJlc3VsdCA9ICR0aGlzLT5fc3F1YXJlUmVkdWNlKCRyZXN1bHQsICRuX3ZhbHVlLCAkbW9kZSk7CiAgICAgICAgfQoKICAgICAgICAkcmVzdWx0ID0gJHRoaXMtPl9tdWx0aXBseVJlZHVjZSgkcmVzdWx0LCAkcG93ZXJzW2JpbmRlYyhzdWJzdHIoJGVfYml0cywgJGksICRqICsgMSkpXSwgJG5fdmFsdWUsICRtb2RlKTsKCiAgICAgICAgJGkrPSRqICsgMTsKICAgICAgfQogICAgfQoKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJHRlbXAtPnZhbHVlID0gJHRoaXMtPl9yZWR1Y2UoJHJlc3VsdCwgJG5fdmFsdWUsICRtb2RlKTsKCiAgICByZXR1cm4gJHRlbXA7CiAgfQoKICBmdW5jdGlvbiBfcmVkdWNlKCR4LCAkbiwgJG1vZGUpIHsKICAgIHN3aXRjaCAoJG1vZGUpIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9OVEdPTUVSWToKICAgICAgICByZXR1cm4gJHRoaXMtPl9tb250Z29tZXJ5KCR4LCAkbik7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX0JBUlJFVFQ6CiAgICAgICAgcmV0dXJuICR0aGlzLT5fYmFycmV0dCgkeCwgJG4pOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9QT1dFUk9GMjoKICAgICAgICAkbGhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICRsaHMtPnZhbHVlID0gJHg7CiAgICAgICAgJHJocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkcmhzLT52YWx1ZSA9ICRuOwogICAgICAgIHJldHVybiAkeC0+X21vZDIoJG4pOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9DTEFTU0lDOgogICAgICAgICRsaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICAgJGxocy0+dmFsdWUgPSAkeDsKICAgICAgICAkcmhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAgICRyaHMtPnZhbHVlID0gJG47CiAgICAgICAgbGlzdCgsICR0ZW1wKSA9ICRsaHMtPmRpdmlkZSgkcmhzKTsKICAgICAgICByZXR1cm4gJHRlbXAtPnZhbHVlOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9OT05FOgogICAgICAgIHJldHVybiAkeDsKICAgICAgZGVmYXVsdDoKICAgICAgICAvLyBhbiBpbnZhbGlkICRtb2RlIHdhcyBwcm92aWRlZAogICAgfQogIH0KCiAgZnVuY3Rpb24gX3ByZXBhcmVSZWR1Y2UoJHgsICRuLCAkbW9kZSkgewogICAgaWYgKCRtb2RlID09IE1BVEhfQklHSU5URUdFUl9NT05UR09NRVJZKSB7CiAgICAgIHJldHVybiAkdGhpcy0+X3ByZXBNb250Z29tZXJ5KCR4LCAkbik7CiAgICB9CiAgICByZXR1cm4gJHRoaXMtPl9yZWR1Y2UoJHgsICRuLCAkbW9kZSk7CiAgfQoKICBmdW5jdGlvbiBfbXVsdGlwbHlSZWR1Y2UoJHgsICR5LCAkbiwgJG1vZGUpIHsKICAgIGlmICgkbW9kZSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9OVEdPTUVSWSkgewogICAgICByZXR1cm4gJHRoaXMtPl9tb250Z29tZXJ5TXVsdGlwbHkoJHgsICR5LCAkbik7CiAgICB9CiAgICAkdGVtcCA9ICR0aGlzLT5fbXVsdGlwbHkoJHgsIGZhbHNlLCAkeSwgZmFsc2UpOwogICAgcmV0dXJuICR0aGlzLT5fcmVkdWNlKCR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICRuLCAkbW9kZSk7CiAgfQoKICBmdW5jdGlvbiBfc3F1YXJlUmVkdWNlKCR4LCAkbiwgJG1vZGUpIHsKICAgIGlmICgkbW9kZSA9PSBNQVRIX0JJR0lOVEVHRVJfTU9OVEdPTUVSWSkgewogICAgICByZXR1cm4gJHRoaXMtPl9tb250Z29tZXJ5TXVsdGlwbHkoJHgsICR4LCAkbik7CiAgICB9CiAgICByZXR1cm4gJHRoaXMtPl9yZWR1Y2UoJHRoaXMtPl9zcXVhcmUoJHgpLCAkbiwgJG1vZGUpOwogIH0KCiAgZnVuY3Rpb24gX21vZDIoJG4pIHsKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJHRlbXAtPnZhbHVlID0gYXJyYXkoMSk7CiAgICByZXR1cm4gJHRoaXMtPmJpdHdpc2VfYW5kKCRuLT5zdWJ0cmFjdCgkdGVtcCkpOwogIH0KCiAgZnVuY3Rpb24gX2JhcnJldHQoJG4sICRtKSB7CiAgICBzdGF0aWMgJGNhY2hlID0gYXJyYXkoCiAgICAgIE1BVEhfQklHSU5URUdFUl9WQVJJQUJMRSA9PiBhcnJheSgpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfREFUQSA9PiBhcnJheSgpCiAgICApOwoKICAgICRtX2xlbmd0aCA9IGNvdW50KCRtKTsKCiAgICBpZiAoY291bnQoJG4pID4gMiAqICRtX2xlbmd0aCkgewogICAgICAkbGhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcmhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkbGhzLT52YWx1ZSA9ICRuOwogICAgICAkcmhzLT52YWx1ZSA9ICRtOwogICAgICBsaXN0KCwgJHRlbXApID0gJGxocy0+ZGl2aWRlKCRyaHMpOwogICAgICByZXR1cm4gJHRlbXAtPnZhbHVlOwogICAgfQoKICAgIGlmICgkbV9sZW5ndGggPCA1KSB7CiAgICAgIHJldHVybiAkdGhpcy0+X3JlZ3VsYXJCYXJyZXR0KCRuLCAkbSk7CiAgICB9CgogICAgaWYgKCAoJGtleSA9IGFycmF5X3NlYXJjaCgkbSwgJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pKSA9PT0gZmFsc2UgKSB7CiAgICAgICRrZXkgPSBjb3VudCgkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXSk7CiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdW10gPSAkbTsKCiAgICAgICRsaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRsaHNfdmFsdWUgPSAmJGxocy0+dmFsdWU7CiAgICAgICRsaHNfdmFsdWUgPSAkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkbV9sZW5ndGggKyAoJG1fbGVuZ3RoID4+IDEpKTsKICAgICAgJGxoc192YWx1ZVtdID0gMTsKICAgICAgJHJocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJHJocy0+dmFsdWUgPSAkbTsKCiAgICAgIGxpc3QoJHUsICRtMSkgPSAkbGhzLT5kaXZpZGUoJHJocyk7CiAgICAgICR1ID0gJHUtPnZhbHVlOwogICAgICAkbTEgPSAkbTEtPnZhbHVlOwoKICAgICAgJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVtdID0gYXJyYXkoCiAgICAgICAgJ3UnID0+ICR1LCAvLyBtLmxlbmd0aCA+PiAxICh0ZWNobmljYWxseSAobS5sZW5ndGggPj4gMSkgKyAxKQogICAgICAgICdtMSc9PiAkbTEgLy8gbS5sZW5ndGgKICAgICAgKTsKICAgIH0gZWxzZSB7CiAgICAgIGV4dHJhY3QoJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVska2V5XSk7CiAgICB9CgogICAgJGN1dG9mZiA9ICRtX2xlbmd0aCArICgkbV9sZW5ndGggPj4gMSk7CiAgICAkbHNkID0gYXJyYXlfc2xpY2UoJG4sIDAsICRjdXRvZmYpOyAvLyBtLmxlbmd0aCArIChtLmxlbmd0aCA+PiAxKQogICAgJG1zZCA9IGFycmF5X3NsaWNlKCRuLCAkY3V0b2ZmKTsgIC8vIG0ubGVuZ3RoID4+IDEKICAgICRsc2QgPSAkdGhpcy0+X3RyaW0oJGxzZCk7CiAgICAkdGVtcCA9ICR0aGlzLT5fbXVsdGlwbHkoJG1zZCwgZmFsc2UsICRtMSwgZmFsc2UpOwogICAgJG4gPSAkdGhpcy0+X2FkZCgkbHNkLCBmYWxzZSwgJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UpOyAvLyBtLmxlbmd0aCArIChtLmxlbmd0aCA+PiAxKSArIDEKCiAgICBpZiAoJG1fbGVuZ3RoICYgMSkgewogICAgICByZXR1cm4gJHRoaXMtPl9yZWd1bGFyQmFycmV0dCgkbltNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkbSk7CiAgICB9CgogICAgJHRlbXAgPSBhcnJheV9zbGljZSgkbltNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkbV9sZW5ndGggLSAxKTsKICAgICR0ZW1wID0gJHRoaXMtPl9tdWx0aXBseSgkdGVtcCwgZmFsc2UsICR1LCBmYWxzZSk7CiAgICAkdGVtcCA9IGFycmF5X3NsaWNlKCR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICgkbV9sZW5ndGggPj4gMSkgKyAxKTsKICAgICR0ZW1wID0gJHRoaXMtPl9tdWx0aXBseSgkdGVtcCwgZmFsc2UsICRtLCBmYWxzZSk7CgogICAgJHJlc3VsdCA9ICR0aGlzLT5fc3VidHJhY3QoJG5bTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UsICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sIGZhbHNlKTsKCiAgICB3aGlsZSAoJHRoaXMtPl9jb21wYXJlKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICRtLCBmYWxzZSkgPj0gMCkgewogICAgICAkcmVzdWx0ID0gJHRoaXMtPl9zdWJ0cmFjdCgkcmVzdWx0W01BVEhfQklHSU5URUdFUl9WQUxVRV0sICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1NJR05dLCAkbSwgZmFsc2UpOwogICAgfQoKICAgIHJldHVybiAkcmVzdWx0W01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgfQoKICBmdW5jdGlvbiBfcmVndWxhckJhcnJldHQoJHgsICRuKSB7CiAgICBzdGF0aWMgJGNhY2hlID0gYXJyYXkoCiAgICAgIE1BVEhfQklHSU5URUdFUl9WQVJJQUJMRSA9PiBhcnJheSgpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfREFUQSA9PiBhcnJheSgpCiAgICApOwoKICAgICRuX2xlbmd0aCA9IGNvdW50KCRuKTsKCiAgICBpZiAoY291bnQoJHgpID4gMiAqICRuX2xlbmd0aCkgewogICAgICAkbGhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkcmhzID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgICAkbGhzLT52YWx1ZSA9ICR4OwogICAgICAkcmhzLT52YWx1ZSA9ICRuOwogICAgICBsaXN0KCwgJHRlbXApID0gJGxocy0+ZGl2aWRlKCRyaHMpOwogICAgICByZXR1cm4gJHRlbXAtPnZhbHVlOwogICAgfQoKICAgIGlmICggKCRrZXkgPSBhcnJheV9zZWFyY2goJG4sICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdKSkgPT09IGZhbHNlICkgewogICAgICAka2V5ID0gY291bnQoJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pOwogICAgICAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXVtdID0gJG47CiAgICAgICRsaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRsaHNfdmFsdWUgPSAmJGxocy0+dmFsdWU7CiAgICAgICRsaHNfdmFsdWUgPSAkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAyICogJG5fbGVuZ3RoKTsKICAgICAgJGxoc192YWx1ZVtdID0gMTsKICAgICAgJHJocyA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgJHJocy0+dmFsdWUgPSAkbjsKICAgICAgbGlzdCgkdGVtcCwgKSA9ICRsaHMtPmRpdmlkZSgkcmhzKTsKICAgICAgJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVtdID0gJHRlbXAtPnZhbHVlOwogICAgfQoKICAgICR0ZW1wID0gYXJyYXlfc2xpY2UoJHgsICRuX2xlbmd0aCAtIDEpOwogICAgJHRlbXAgPSAkdGhpcy0+X211bHRpcGx5KCR0ZW1wLCBmYWxzZSwgJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVska2V5XSwgZmFsc2UpOwogICAgJHRlbXAgPSBhcnJheV9zbGljZSgkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkbl9sZW5ndGggKyAxKTsKCiAgICAkcmVzdWx0ID0gYXJyYXlfc2xpY2UoJHgsIDAsICRuX2xlbmd0aCArIDEpOwogICAgJHRlbXAgPSAkdGhpcy0+X211bHRpcGx5TG93ZXIoJHRlbXAsIGZhbHNlLCAkbiwgZmFsc2UsICRuX2xlbmd0aCArIDEpOwoKICAgIGlmICgkdGhpcy0+X2NvbXBhcmUoJHJlc3VsdCwgZmFsc2UsICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXSkgPCAwKSB7CiAgICAgICRjb3JyZWN0b3JfdmFsdWUgPSAkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkbl9sZW5ndGggKyAxKTsKICAgICAgJGNvcnJlY3Rvcl92YWx1ZVtdID0gMTsKICAgICAgJHJlc3VsdCA9ICR0aGlzLT5fYWRkKCRyZXN1bHQsIGZhbHNlLCAkY29ycmVjdG9yX3ZhbHVlLCBmYWxzZSk7CiAgICAgICRyZXN1bHQgPSAkcmVzdWx0W01BVEhfQklHSU5URUdFUl9WQUxVRV07CiAgICB9CgogICAgJHJlc3VsdCA9ICR0aGlzLT5fc3VidHJhY3QoJHJlc3VsdCwgZmFsc2UsICR0ZW1wW01BVEhfQklHSU5URUdFUl9WQUxVRV0sICR0ZW1wW01BVEhfQklHSU5URUdFUl9TSUdOXSk7CiAgICB3aGlsZSAoJHRoaXMtPl9jb21wYXJlKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICRuLCBmYWxzZSkgPiAwKSB7CiAgICAgICRyZXN1bHQgPSAkdGhpcy0+X3N1YnRyYWN0KCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfU0lHTl0sICRuLCBmYWxzZSk7CiAgICB9CgogICAgcmV0dXJuICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXTsKICB9CgogIGZ1bmN0aW9uIF9tdWx0aXBseUxvd2VyKCR4X3ZhbHVlLCAkeF9uZWdhdGl2ZSwgJHlfdmFsdWUsICR5X25lZ2F0aXZlLCAkc3RvcCkgewogICAgJHhfbGVuZ3RoID0gY291bnQoJHhfdmFsdWUpOwogICAgJHlfbGVuZ3RoID0gY291bnQoJHlfdmFsdWUpOwoKICAgIGlmICggISR4X2xlbmd0aCB8fCAhJHlfbGVuZ3RoICkgeyAvLyBhIDAgaXMgYmVpbmcgbXVsdGlwbGllZAogICAgICByZXR1cm4gYXJyYXkoCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+IGFycmF5KCksCiAgICAgICAgTUFUSF9CSUdJTlRFR0VSX1NJR04gPT4gZmFsc2UKICAgICAgKTsKICAgIH0KCiAgICBpZiAoICR4X2xlbmd0aCA8ICR5X2xlbmd0aCApIHsKICAgICAgJHRlbXAgPSAkeF92YWx1ZTsKICAgICAgJHhfdmFsdWUgPSAkeV92YWx1ZTsKICAgICAgJHlfdmFsdWUgPSAkdGVtcDsKCiAgICAgICR4X2xlbmd0aCA9IGNvdW50KCR4X3ZhbHVlKTsKICAgICAgJHlfbGVuZ3RoID0gY291bnQoJHlfdmFsdWUpOwogICAgfQoKICAgICRwcm9kdWN0X3ZhbHVlID0gJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgJHhfbGVuZ3RoICsgJHlfbGVuZ3RoKTsKCiAgICAkY2FycnkgPSAwOwoKICAgIGZvciAoJGogPSAwOyAkaiA8ICR4X2xlbmd0aDsgKyskaikgeyAvLyBpZS4gJGkgPSAwLCAkayA9ICRpCiAgICAgICR0ZW1wID0gJHhfdmFsdWVbJGpdICogJHlfdmFsdWVbMF0gKyAkY2Fycnk7IC8vICRwcm9kdWN0X3ZhbHVlWyRrXSA9PSAwCiAgICAgICRjYXJyeSA9IChpbnQpICgkdGVtcCAvIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpOwogICAgICAkcHJvZHVjdF92YWx1ZVskal0gPSAoaW50KSAoJHRlbXAgLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogJGNhcnJ5KTsKICAgIH0KCiAgICBpZiAoJGogPCAkc3RvcCkgewogICAgICAkcHJvZHVjdF92YWx1ZVskal0gPSAkY2Fycnk7CiAgICB9CgogICAgZm9yICgkaSA9IDE7ICRpIDwgJHlfbGVuZ3RoOyArKyRpKSB7CiAgICAgICRjYXJyeSA9IDA7CgogICAgICBmb3IgKCRqID0gMCwgJGsgPSAkaTsgJGogPCAkeF9sZW5ndGggJiYgJGsgPCAkc3RvcDsgKyskaiwgKyskaykgewogICAgICAgICR0ZW1wID0gJHByb2R1Y3RfdmFsdWVbJGtdICsgJHhfdmFsdWVbJGpdICogJHlfdmFsdWVbJGldICsgJGNhcnJ5OwogICAgICAgICRjYXJyeSA9IChpbnQpICgkdGVtcCAvIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpOwogICAgICAgICRwcm9kdWN0X3ZhbHVlWyRrXSA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAkY2FycnkpOwogICAgICB9CgogICAgICBpZiAoJGsgPCAkc3RvcCkgewogICAgICAgICRwcm9kdWN0X3ZhbHVlWyRrXSA9ICRjYXJyeTsKICAgICAgfQogICAgfQoKICAgIHJldHVybiBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+ICR0aGlzLT5fdHJpbSgkcHJvZHVjdF92YWx1ZSksCiAgICAgIE1BVEhfQklHSU5URUdFUl9TSUdOID0+ICR4X25lZ2F0aXZlICE9ICR5X25lZ2F0aXZlCiAgICApOwogIH0KCiAgZnVuY3Rpb24gX21vbnRnb21lcnkoJHgsICRuKSB7CiAgICBzdGF0aWMgJGNhY2hlID0gYXJyYXkoCiAgICAgIE1BVEhfQklHSU5URUdFUl9WQVJJQUJMRSA9PiBhcnJheSgpLAogICAgICBNQVRIX0JJR0lOVEVHRVJfREFUQSA9PiBhcnJheSgpCiAgICApOwoKICAgIGlmICggKCRrZXkgPSBhcnJheV9zZWFyY2goJG4sICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdKSkgPT09IGZhbHNlICkgewogICAgICAka2V5ID0gY291bnQoJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pOwogICAgICAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXVtdID0gJHg7CiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfREFUQV1bXSA9ICR0aGlzLT5fbW9kSW52ZXJzZTY3MTA4ODY0KCRuKTsKICAgIH0KCiAgICAkayA9IGNvdW50KCRuKTsKCiAgICAkcmVzdWx0ID0gYXJyYXkoTUFUSF9CSUdJTlRFR0VSX1ZBTFVFID0+ICR4KTsKCiAgICBmb3IgKCRpID0gMDsgJGkgPCAkazsgKyskaSkgewogICAgICAkdGVtcCA9ICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXVskaV0gKiAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX0RBVEFdWyRrZXldOwogICAgICAkdGVtcCA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAoKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCkpKTsKICAgICAgJHRlbXAgPSAkdGhpcy0+X3JlZ3VsYXJNdWx0aXBseShhcnJheSgkdGVtcCksICRuKTsKICAgICAgJHRlbXAgPSBhcnJheV9tZXJnZSgkdGhpcy0+X2FycmF5X3JlcGVhdCgwLCAkaSksICR0ZW1wKTsKICAgICAgJHJlc3VsdCA9ICR0aGlzLT5fYWRkKCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UsICR0ZW1wLCBmYWxzZSk7CiAgICB9CgogICAgJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdID0gYXJyYXlfc2xpY2UoJHJlc3VsdFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAkayk7CgogICAgaWYgKCR0aGlzLT5fY29tcGFyZSgkcmVzdWx0LCBmYWxzZSwgJG4sIGZhbHNlKSA+PSAwKSB7CiAgICAgICRyZXN1bHQgPSAkdGhpcy0+X3N1YnRyYWN0KCRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UsICRuLCBmYWxzZSk7CiAgICB9CgogICAgcmV0dXJuICRyZXN1bHRbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXTsKICB9CgogIGZ1bmN0aW9uIF9tb250Z29tZXJ5TXVsdGlwbHkoJHgsICR5LCAkbSkgewogICAgJHRlbXAgPSAkdGhpcy0+X211bHRpcGx5KCR4LCBmYWxzZSwgJHksIGZhbHNlKTsKICAgIHJldHVybiAkdGhpcy0+X21vbnRnb21lcnkoJHRlbXBbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgJG0pOwoKICAgIHN0YXRpYyAkY2FjaGUgPSBhcnJheSgKICAgICAgTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFID0+IGFycmF5KCksCiAgICAgIE1BVEhfQklHSU5URUdFUl9EQVRBID0+IGFycmF5KCkKICAgICk7CgogICAgaWYgKCAoJGtleSA9IGFycmF5X3NlYXJjaCgkbSwgJGNhY2hlW01BVEhfQklHSU5URUdFUl9WQVJJQUJMRV0pKSA9PT0gZmFsc2UgKSB7CiAgICAgICRrZXkgPSBjb3VudCgkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX1ZBUklBQkxFXSk7CiAgICAgICRjYWNoZVtNQVRIX0JJR0lOVEVHRVJfVkFSSUFCTEVdW10gPSAkbTsKICAgICAgJGNhY2hlW01BVEhfQklHSU5URUdFUl9EQVRBXVtdID0gJHRoaXMtPl9tb2RJbnZlcnNlNjcxMDg4NjQoJG0pOwogICAgfQoKICAgICRuID0gbWF4KGNvdW50KCR4KSwgY291bnQoJHkpLCBjb3VudCgkbSkpOwogICAgJHggPSBhcnJheV9wYWQoJHgsICRuLCAwKTsKICAgICR5ID0gYXJyYXlfcGFkKCR5LCAkbiwgMCk7CiAgICAkbSA9IGFycmF5X3BhZCgkbSwgJG4sIDApOwogICAgJGEgPSBhcnJheShNQVRIX0JJR0lOVEVHRVJfVkFMVUUgPT4gJHRoaXMtPl9hcnJheV9yZXBlYXQoMCwgJG4gKyAxKSk7CiAgICBmb3IgKCRpID0gMDsgJGkgPCAkbjsgKyskaSkgewogICAgICAkdGVtcCA9ICRhW01BVEhfQklHSU5URUdFUl9WQUxVRV1bMF0gKyAkeFskaV0gKiAkeVswXTsKICAgICAgJHRlbXAgPSAoaW50KSAoJHRlbXAgLSBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMICogKChpbnQpICgkdGVtcCAvIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpKSk7CiAgICAgICR0ZW1wID0gJHRlbXAgKiAkY2FjaGVbTUFUSF9CSUdJTlRFR0VSX0RBVEFdWyRrZXldOwogICAgICAkdGVtcCA9IChpbnQpICgkdGVtcCAtIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwgKiAoKGludCkgKCR0ZW1wIC8gTUFUSF9CSUdJTlRFR0VSX0JBU0VfRlVMTCkpKTsKICAgICAgJHRlbXAgPSAkdGhpcy0+X2FkZCgkdGhpcy0+X3JlZ3VsYXJNdWx0aXBseShhcnJheSgkeFskaV0pLCAkeSksIGZhbHNlLCAkdGhpcy0+X3JlZ3VsYXJNdWx0aXBseShhcnJheSgkdGVtcCksICRtKSwgZmFsc2UpOwogICAgICAkYSA9ICR0aGlzLT5fYWRkKCRhW01BVEhfQklHSU5URUdFUl9WQUxVRV0sIGZhbHNlLCAkdGVtcFtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCBmYWxzZSk7CiAgICAgICRhW01BVEhfQklHSU5URUdFUl9WQUxVRV0gPSBhcnJheV9zbGljZSgkYVtNQVRIX0JJR0lOVEVHRVJfVkFMVUVdLCAxKTsKICAgIH0KICAgIGlmICgkdGhpcy0+X2NvbXBhcmUoJGFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UsICRtLCBmYWxzZSkgPj0gMCkgewogICAgICAkYSA9ICR0aGlzLT5fc3VidHJhY3QoJGFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXSwgZmFsc2UsICRtLCBmYWxzZSk7CiAgICB9CiAgICByZXR1cm4gJGFbTUFUSF9CSUdJTlRFR0VSX1ZBTFVFXTsKICB9CgogIGZ1bmN0aW9uIF9wcmVwTW9udGdvbWVyeSgkeCwgJG4pIHsKICAgICRsaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkbGhzLT52YWx1ZSA9IGFycmF5X21lcmdlKCR0aGlzLT5fYXJyYXlfcmVwZWF0KDAsIGNvdW50KCRuKSksICR4KTsKICAgICRyaHMgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkcmhzLT52YWx1ZSA9ICRuOwoKICAgIGxpc3QoLCAkdGVtcCkgPSAkbGhzLT5kaXZpZGUoJHJocyk7CiAgICByZXR1cm4gJHRlbXAtPnZhbHVlOwogIH0KCiAgZnVuY3Rpb24gX21vZEludmVyc2U2NzEwODg2NCgkeCkgLy8gMioqMjYgPT0gNjcsMTA4LDg2NAogIHsKICAgICR4ID0gLSR4WzBdOwogICAgJHJlc3VsdCA9ICR4ICYgMHgzOyAvLyB4KiotMSBtb2QgMioqMgogICAgJHJlc3VsdCA9ICgkcmVzdWx0ICogKDIgLSAkeCAqICRyZXN1bHQpKSAmIDB4RjsgLy8geCoqLTEgbW9kIDIqKjQKICAgICRyZXN1bHQgPSAoJHJlc3VsdCAqICgyIC0gKCR4ICYgMHhGRikgKiAkcmVzdWx0KSkgICYgMHhGRjsgLy8geCoqLTEgbW9kIDIqKjgKICAgICRyZXN1bHQgPSAoJHJlc3VsdCAqICgoMiAtICgkeCAmIDB4RkZGRikgKiAkcmVzdWx0KSAmIDB4RkZGRikpICYgMHhGRkZGOyAvLyB4KiotMSBtb2QgMioqMTYKICAgICRyZXN1bHQgPSBmbW9kKCRyZXN1bHQgKiAoMiAtIGZtb2QoJHggKiAkcmVzdWx0LCBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKSksIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpOyAvLyB4KiotMSBtb2QgMioqMjYKICAgIHJldHVybiAkcmVzdWx0ICYgTUFUSF9CSUdJTlRFR0VSX01BWF9ESUdJVDsKICB9CgogIGZ1bmN0aW9uIG1vZEludmVyc2UoJG4pIHsKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfaW52ZXJ0KCR0aGlzLT52YWx1ZSwgJG4tPnZhbHVlKTsKCiAgICAgICAgcmV0dXJuICggJHRlbXAtPnZhbHVlID09PSBmYWxzZSApID8gZmFsc2UgOiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgICB9CgogICAgc3RhdGljICR6ZXJvLCAkb25lOwogICAgaWYgKCFpc3NldCgkemVybykpIHsKICAgICAgJHplcm8gPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAgICRvbmUgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKDEpOwogICAgfQoKICAgIC8vICR4IG1vZCAtJG4gPT0gJHggbW9kICRuLgogICAgJG4gPSAkbi0+YWJzKCk7CgogICAgaWYgKCR0aGlzLT5jb21wYXJlKCR6ZXJvKSA8IDApIHsKICAgICAgJHRlbXAgPSAkdGhpcy0+YWJzKCk7CiAgICAgICR0ZW1wID0gJHRlbXAtPm1vZEludmVyc2UoJG4pOwogICAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJG4tPnN1YnRyYWN0KCR0ZW1wKSk7CiAgICB9CgogICAgZXh0cmFjdCgkdGhpcy0+ZXh0ZW5kZWRHQ0QoJG4pKTsKCiAgICBpZiAoISRnY2QtPmVxdWFscygkb25lKSkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgJHggPSAkeC0+Y29tcGFyZSgkemVybykgPCAwID8gJHgtPmFkZCgkbikgOiAkeDsKCiAgICByZXR1cm4gJHRoaXMtPmNvbXBhcmUoJHplcm8pIDwgMCA/ICR0aGlzLT5fbm9ybWFsaXplKCRuLT5zdWJ0cmFjdCgkeCkpIDogJHRoaXMtPl9ub3JtYWxpemUoJHgpOwogIH0KCiAgZnVuY3Rpb24gZXh0ZW5kZWRHQ0QoJG4pIHsKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICBleHRyYWN0KGdtcF9nY2RleHQoJHRoaXMtPnZhbHVlLCAkbi0+dmFsdWUpKTsKCiAgICAgICAgcmV0dXJuIGFycmF5KAogICAgICAgICAgJ2djZCcgPT4gJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigkZykpLAogICAgICAgICAgJ3gnICAgPT4gJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigkcykpLAogICAgICAgICAgJ3knICAgPT4gJHRoaXMtPl9ub3JtYWxpemUobmV3IE1hdGhfQmlnSW50ZWdlcigkdCkpCiAgICAgICAgKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgJHUgPSAkdGhpcy0+dmFsdWU7CiAgICAgICAgJHYgPSAkbi0+dmFsdWU7CgogICAgICAgICRhID0gJzEnOwogICAgICAgICRiID0gJzAnOwogICAgICAgICRjID0gJzAnOwogICAgICAgICRkID0gJzEnOwoKICAgICAgICB3aGlsZSAoYmNjb21wKCR2LCAnMCcsIDApICE9IDApIHsKICAgICAgICAgICRxID0gYmNkaXYoJHUsICR2LCAwKTsKCiAgICAgICAgICAkdGVtcCA9ICR1OwogICAgICAgICAgJHUgPSAkdjsKICAgICAgICAgICR2ID0gYmNzdWIoJHRlbXAsIGJjbXVsKCR2LCAkcSwgMCksIDApOwoKICAgICAgICAgICR0ZW1wID0gJGE7CiAgICAgICAgICAkYSA9ICRjOwogICAgICAgICAgJGMgPSBiY3N1YigkdGVtcCwgYmNtdWwoJGEsICRxLCAwKSwgMCk7CgogICAgICAgICAgJHRlbXAgPSAkYjsKICAgICAgICAgICRiID0gJGQ7CiAgICAgICAgICAkZCA9IGJjc3ViKCR0ZW1wLCBiY211bCgkYiwgJHEsIDApLCAwKTsKICAgICAgICB9CgogICAgICAgIHJldHVybiBhcnJheSgKICAgICAgICAgICdnY2QnID0+ICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoJHUpKSwKICAgICAgICAgICd4JyAgID0+ICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoJGEpKSwKICAgICAgICAgICd5JyAgID0+ICR0aGlzLT5fbm9ybWFsaXplKG5ldyBNYXRoX0JpZ0ludGVnZXIoJGIpKQogICAgICAgICk7CiAgICB9CgogICAgJHkgPSAkbi0+Y29weSgpOwogICAgJHggPSAkdGhpcy0+Y29weSgpOwogICAgJGcgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkZy0+dmFsdWUgPSBhcnJheSgxKTsKCiAgICB3aGlsZSAoICEoKCR4LT52YWx1ZVswXSAmIDEpfHwgKCR5LT52YWx1ZVswXSAmIDEpKSApIHsKICAgICAgJHgtPl9yc2hpZnQoMSk7CiAgICAgICR5LT5fcnNoaWZ0KDEpOwogICAgICAkZy0+X2xzaGlmdCgxKTsKICAgIH0KCiAgICAkdSA9ICR4LT5jb3B5KCk7CiAgICAkdiA9ICR5LT5jb3B5KCk7CgogICAgJGEgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CiAgICAkYiA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKICAgICRjID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwogICAgJGQgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKCk7CgogICAgJGEtPnZhbHVlID0gJGQtPnZhbHVlID0gJGctPnZhbHVlID0gYXJyYXkoMSk7CiAgICAkYi0+dmFsdWUgPSAkYy0+dmFsdWUgPSBhcnJheSgpOwoKICAgIHdoaWxlICggIWVtcHR5KCR1LT52YWx1ZSkgKSB7CiAgICAgIHdoaWxlICggISgkdS0+dmFsdWVbMF0gJiAxKSApIHsKICAgICAgICAkdS0+X3JzaGlmdCgxKTsKICAgICAgICBpZiAoICghZW1wdHkoJGEtPnZhbHVlKSAmJiAoJGEtPnZhbHVlWzBdICYgMSkpIHx8ICghZW1wdHkoJGItPnZhbHVlKSAmJiAoJGItPnZhbHVlWzBdICYgMSkpICkgewogICAgICAgICAgJGEgPSAkYS0+YWRkKCR5KTsKICAgICAgICAgICRiID0gJGItPnN1YnRyYWN0KCR4KTsKICAgICAgICB9CiAgICAgICAgJGEtPl9yc2hpZnQoMSk7CiAgICAgICAgJGItPl9yc2hpZnQoMSk7CiAgICAgIH0KCiAgICAgIHdoaWxlICggISgkdi0+dmFsdWVbMF0gJiAxKSApIHsKICAgICAgICAkdi0+X3JzaGlmdCgxKTsKICAgICAgICBpZiAoICghZW1wdHkoJGQtPnZhbHVlKSAmJiAoJGQtPnZhbHVlWzBdICYgMSkpIHx8ICghZW1wdHkoJGMtPnZhbHVlKSAmJiAoJGMtPnZhbHVlWzBdICYgMSkpICkgewogICAgICAgICAgJGMgPSAkYy0+YWRkKCR5KTsKICAgICAgICAgICRkID0gJGQtPnN1YnRyYWN0KCR4KTsKICAgICAgICB9CiAgICAgICAgJGMtPl9yc2hpZnQoMSk7CiAgICAgICAgJGQtPl9yc2hpZnQoMSk7CiAgICAgIH0KCiAgICAgIGlmICgkdS0+Y29tcGFyZSgkdikgPj0gMCkgewogICAgICAgICR1ID0gJHUtPnN1YnRyYWN0KCR2KTsKICAgICAgICAkYSA9ICRhLT5zdWJ0cmFjdCgkYyk7CiAgICAgICAgJGIgPSAkYi0+c3VidHJhY3QoJGQpOwogICAgICB9IGVsc2UgewogICAgICAgICR2ID0gJHYtPnN1YnRyYWN0KCR1KTsKICAgICAgICAkYyA9ICRjLT5zdWJ0cmFjdCgkYSk7CiAgICAgICAgJGQgPSAkZC0+c3VidHJhY3QoJGIpOwogICAgICB9CiAgICB9CgogICAgcmV0dXJuIGFycmF5KAogICAgICAnZ2NkJyA9PiAkdGhpcy0+X25vcm1hbGl6ZSgkZy0+bXVsdGlwbHkoJHYpKSwKICAgICAgJ3gnICAgPT4gJHRoaXMtPl9ub3JtYWxpemUoJGMpLAogICAgICAneScgICA9PiAkdGhpcy0+X25vcm1hbGl6ZSgkZCkKICAgICk7CiAgfQoKICBmdW5jdGlvbiBnY2QoJG4pIHsKICAgIGV4dHJhY3QoJHRoaXMtPmV4dGVuZGVkR0NEKCRuKSk7CiAgICByZXR1cm4gJGdjZDsKICB9CgogIGZ1bmN0aW9uIGFicygpIHsKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwoKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfYWJzKCR0aGlzLT52YWx1ZSk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfQkNNQVRIOgogICAgICAgICR0ZW1wLT52YWx1ZSA9IChiY2NvbXAoJHRoaXMtPnZhbHVlLCAnMCcsIDApIDwgMCkgPyBzdWJzdHIoJHRoaXMtPnZhbHVlLCAxKSA6ICR0aGlzLT52YWx1ZTsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSAkdGhpcy0+dmFsdWU7CiAgICB9CgogICAgcmV0dXJuICR0ZW1wOwogIH0KCiAgZnVuY3Rpb24gY29tcGFyZSgkeSkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIHJldHVybiBnbXBfY21wKCR0aGlzLT52YWx1ZSwgJHktPnZhbHVlKTsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgcmV0dXJuIGJjY29tcCgkdGhpcy0+dmFsdWUsICR5LT52YWx1ZSwgMCk7CiAgICB9CgogICAgcmV0dXJuICR0aGlzLT5fY29tcGFyZSgkdGhpcy0+dmFsdWUsICR0aGlzLT5pc19uZWdhdGl2ZSwgJHktPnZhbHVlLCAkeS0+aXNfbmVnYXRpdmUpOwogIH0KCiAgZnVuY3Rpb24gX2NvbXBhcmUoJHhfdmFsdWUsICR4X25lZ2F0aXZlLCAkeV92YWx1ZSwgJHlfbmVnYXRpdmUpIHsKICAgIGlmICggJHhfbmVnYXRpdmUgIT0gJHlfbmVnYXRpdmUgKSB7CiAgICAgIHJldHVybiAoICEkeF9uZWdhdGl2ZSAmJiAkeV9uZWdhdGl2ZSApID8gMSA6IC0xOwogICAgfQoKICAgICRyZXN1bHQgPSAkeF9uZWdhdGl2ZSA/IC0xIDogMTsKCiAgICBpZiAoIGNvdW50KCR4X3ZhbHVlKSAhPSBjb3VudCgkeV92YWx1ZSkgKSB7CiAgICAgIHJldHVybiAoIGNvdW50KCR4X3ZhbHVlKSA+IGNvdW50KCR5X3ZhbHVlKSApID8gJHJlc3VsdCA6IC0kcmVzdWx0OwogICAgfQogICAgJHNpemUgPSBtYXgoY291bnQoJHhfdmFsdWUpLCBjb3VudCgkeV92YWx1ZSkpOwoKICAgICR4X3ZhbHVlID0gYXJyYXlfcGFkKCR4X3ZhbHVlLCAkc2l6ZSwgMCk7CiAgICAkeV92YWx1ZSA9IGFycmF5X3BhZCgkeV92YWx1ZSwgJHNpemUsIDApOwoKICAgIGZvciAoJGkgPSBjb3VudCgkeF92YWx1ZSkgLSAxOyAkaSA+PSAwOyAtLSRpKSB7CiAgICAgIGlmICgkeF92YWx1ZVskaV0gIT0gJHlfdmFsdWVbJGldKSB7CiAgICAgICAgcmV0dXJuICggJHhfdmFsdWVbJGldID4gJHlfdmFsdWVbJGldICkgPyAkcmVzdWx0IDogLSRyZXN1bHQ7CiAgICAgIH0KICAgIH0KCiAgICByZXR1cm4gMDsKICB9CgogIGZ1bmN0aW9uIGVxdWFscygkeCkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIHJldHVybiBnbXBfY21wKCR0aGlzLT52YWx1ZSwgJHgtPnZhbHVlKSA9PSAwOwogICAgICBkZWZhdWx0OgogICAgICAgIHJldHVybiAkdGhpcy0+dmFsdWUgPT09ICR4LT52YWx1ZSAmJiAkdGhpcy0+aXNfbmVnYXRpdmUgPT0gJHgtPmlzX25lZ2F0aXZlOwogICAgfQogIH0KCiAgZnVuY3Rpb24gc2V0UHJlY2lzaW9uKCRiaXRzKSB7CiAgICAkdGhpcy0+cHJlY2lzaW9uID0gJGJpdHM7CiAgICBpZiAoIE1BVEhfQklHSU5URUdFUl9NT0RFICE9IE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSCApIHsKICAgICAgJHRoaXMtPmJpdG1hc2sgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKGNocigoMSA8PCAoJGJpdHMgJiAweDcpKSAtIDEpIC4gc3RyX3JlcGVhdChjaHIoMHhGRiksICRiaXRzID4+IDMpLCAyNTYpOwogICAgfSBlbHNlIHsKICAgICAgJHRoaXMtPmJpdG1hc2sgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKGJjcG93KCcyJywgJGJpdHMsIDApKTsKICAgIH0KCiAgICAkdGVtcCA9ICR0aGlzLT5fbm9ybWFsaXplKCR0aGlzKTsKICAgICR0aGlzLT52YWx1ZSA9ICR0ZW1wLT52YWx1ZTsKICB9CgogIGZ1bmN0aW9uIGJpdHdpc2VfcmlnaHRTaGlmdCgkc2hpZnQpIHsKICAgICR0ZW1wID0gbmV3IE1hdGhfQmlnSW50ZWdlcigpOwoKICAgIHN3aXRjaCAoIE1BVEhfQklHSU5URUdFUl9NT0RFICkgewogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0dNUDoKICAgICAgICBzdGF0aWMgJHR3bzsKCiAgICAgICAgaWYgKCFpc3NldCgkdHdvKSkgewogICAgICAgICAgJHR3byA9IGdtcF9pbml0KCcyJyk7CiAgICAgICAgfQoKICAgICAgICAkdGVtcC0+dmFsdWUgPSBnbXBfZGl2X3EoJHRoaXMtPnZhbHVlLCBnbXBfcG93KCR0d28sICRzaGlmdCkpOwoKICAgICAgICBicmVhazsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgJHRlbXAtPnZhbHVlID0gYmNkaXYoJHRoaXMtPnZhbHVlLCBiY3BvdygnMicsICRzaGlmdCwgMCksIDApOwoKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSAkdGhpcy0+dmFsdWU7CiAgICAgICAgJHRlbXAtPl9yc2hpZnQoJHNoaWZ0KTsKICAgIH0KCiAgICByZXR1cm4gJHRoaXMtPl9ub3JtYWxpemUoJHRlbXApOwogIH0KCiAgZnVuY3Rpb24gYml0d2lzZV9sZWZ0U2hpZnQoJHNoaWZ0KSB7CiAgICAkdGVtcCA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoKTsKCiAgICBzd2l0Y2ggKCBNQVRIX0JJR0lOVEVHRVJfTU9ERSApIHsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9HTVA6CiAgICAgICAgc3RhdGljICR0d287CgogICAgICAgIGlmICghaXNzZXQoJHR3bykpIHsKICAgICAgICAgICR0d28gPSBnbXBfaW5pdCgnMicpOwogICAgICAgIH0KCiAgICAgICAgJHRlbXAtPnZhbHVlID0gZ21wX211bCgkdGhpcy0+dmFsdWUsIGdtcF9wb3coJHR3bywgJHNoaWZ0KSk7CgogICAgICAgIGJyZWFrOwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICAkdGVtcC0+dmFsdWUgPSBiY211bCgkdGhpcy0+dmFsdWUsIGJjcG93KCcyJywgJHNoaWZ0LCAwKSwgMCk7CgogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgICR0ZW1wLT52YWx1ZSA9ICR0aGlzLT52YWx1ZTsKICAgICAgICAkdGVtcC0+X2xzaGlmdCgkc2hpZnQpOwogICAgfQoKICAgIHJldHVybiAkdGhpcy0+X25vcm1hbGl6ZSgkdGVtcCk7CiAgfQoKICBmdW5jdGlvbiBiaXR3aXNlX2xlZnRSb3RhdGUoJHNoaWZ0KSB7CiAgICAkYml0cyA9ICR0aGlzLT50b0J5dGVzKCk7CgogICAgaWYgKCR0aGlzLT5wcmVjaXNpb24gPiAwKSB7CiAgICAgICRwcmVjaXNpb24gPSAkdGhpcy0+cHJlY2lzaW9uOwogICAgICBpZiAoIE1BVEhfQklHSU5URUdFUl9NT0RFID09IE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSCApIHsKICAgICAgICAkbWFzayA9ICR0aGlzLT5iaXRtYXNrLT5zdWJ0cmFjdChuZXcgTWF0aF9CaWdJbnRlZ2VyKDEpKTsKICAgICAgICAkbWFzayA9ICRtYXNrLT50b0J5dGVzKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgJG1hc2sgPSAkdGhpcy0+Yml0bWFzay0+dG9CeXRlcygpOwogICAgICB9CiAgICB9IGVsc2UgewogICAgICAkdGVtcCA9IG9yZCgkYml0c1swXSk7CiAgICAgIGZvciAoJGkgPSAwOyAkdGVtcCA+PiAkaTsgKyskaSk7CiAgICAgICRwcmVjaXNpb24gPSA4ICogc3RybGVuKCRiaXRzKSAtIDggKyAkaTsKICAgICAgJG1hc2sgPSBjaHIoKDEgPDwgKCRwcmVjaXNpb24gJiAweDcpKSAtIDEpIC4gc3RyX3JlcGVhdChjaHIoMHhGRiksICRwcmVjaXNpb24gPj4gMyk7CiAgICB9CgogICAgaWYgKCRzaGlmdCA8IDApIHsKICAgICAgJHNoaWZ0Kz0gJHByZWNpc2lvbjsKICAgIH0KICAgICRzaGlmdCU9ICRwcmVjaXNpb247CgogICAgaWYgKCEkc2hpZnQpIHsKICAgICAgcmV0dXJuICR0aGlzLT5jb3B5KCk7CiAgICB9CgogICAgJGxlZnQgPSAkdGhpcy0+Yml0d2lzZV9sZWZ0U2hpZnQoJHNoaWZ0KTsKICAgICRsZWZ0ID0gJGxlZnQtPmJpdHdpc2VfYW5kKG5ldyBNYXRoX0JpZ0ludGVnZXIoJG1hc2ssIDI1NikpOwogICAgJHJpZ2h0ID0gJHRoaXMtPmJpdHdpc2VfcmlnaHRTaGlmdCgkcHJlY2lzaW9uIC0gJHNoaWZ0KTsKICAgICRyZXN1bHQgPSBNQVRIX0JJR0lOVEVHRVJfTU9ERSAhPSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEggPyAkbGVmdC0+Yml0d2lzZV9vcigkcmlnaHQpIDogJGxlZnQtPmFkZCgkcmlnaHQpOwogICAgcmV0dXJuICR0aGlzLT5fbm9ybWFsaXplKCRyZXN1bHQpOwogIH0KCiAgZnVuY3Rpb24gYml0d2lzZV9yaWdodFJvdGF0ZSgkc2hpZnQpIHsKICAgIHJldHVybiAkdGhpcy0+Yml0d2lzZV9sZWZ0Um90YXRlKC0kc2hpZnQpOwogIH0KCiAgZnVuY3Rpb24gX21ha2Vfb2RkKCkgewogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGdtcF9zZXRiaXQoJHRoaXMtPnZhbHVlLCAwKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSBNQVRIX0JJR0lOVEVHRVJfTU9ERV9CQ01BVEg6CiAgICAgICAgaWYgKCR0aGlzLT52YWx1ZVtzdHJsZW4oJHRoaXMtPnZhbHVlKSAtIDFdICUgMiA9PSAwKSB7CiAgICAgICAgICAkdGhpcy0+dmFsdWUgPSBiY2FkZCgkdGhpcy0+dmFsdWUsICcxJyk7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgICR0aGlzLT52YWx1ZVswXSB8PSAxOwogICAgfQogIH0KCiAgZnVuY3Rpb24gX2xzaGlmdCgkc2hpZnQpIHsKICAgIGlmICggJHNoaWZ0ID09IDAgKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICAkbnVtX2RpZ2l0cyA9IChpbnQpICgkc2hpZnQgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRSk7CiAgICAkc2hpZnQgJT0gTUFUSF9CSUdJTlRFR0VSX0JBU0U7CiAgICAkc2hpZnQgPSAxIDw8ICRzaGlmdDsKCiAgICAkY2FycnkgPSAwOwoKICAgIGZvciAoJGkgPSAwOyAkaSA8IGNvdW50KCR0aGlzLT52YWx1ZSk7ICsrJGkpIHsKICAgICAgJHRlbXAgPSAkdGhpcy0+dmFsdWVbJGldICogJHNoaWZ0ICsgJGNhcnJ5OwogICAgICAkY2FycnkgPSAoaW50KSAoJHRlbXAgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRV9GVUxMKTsKICAgICAgJHRoaXMtPnZhbHVlWyRpXSA9IChpbnQpICgkdGVtcCAtICRjYXJyeSAqIE1BVEhfQklHSU5URUdFUl9CQVNFX0ZVTEwpOwogICAgfQoKICAgIGlmICggJGNhcnJ5ICkgewogICAgICAkdGhpcy0+dmFsdWVbXSA9ICRjYXJyeTsKICAgIH0KCiAgICB3aGlsZSAoJG51bV9kaWdpdHMtLSkgewogICAgICBhcnJheV91bnNoaWZ0KCR0aGlzLT52YWx1ZSwgMCk7CiAgICB9CiAgfQoKICBmdW5jdGlvbiBfcnNoaWZ0KCRzaGlmdCkgewogICAgaWYgKCRzaGlmdCA9PSAwKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICAkbnVtX2RpZ2l0cyA9IChpbnQpICgkc2hpZnQgLyBNQVRIX0JJR0lOVEVHRVJfQkFTRSk7CiAgICAkc2hpZnQgJT0gTUFUSF9CSUdJTlRFR0VSX0JBU0U7CiAgICAkY2Fycnlfc2hpZnQgPSBNQVRIX0JJR0lOVEVHRVJfQkFTRSAtICRzaGlmdDsKICAgICRjYXJyeV9tYXNrID0gKDEgPDwgJHNoaWZ0KSAtIDE7CgogICAgaWYgKCAkbnVtX2RpZ2l0cyApIHsKICAgICAgJHRoaXMtPnZhbHVlID0gYXJyYXlfc2xpY2UoJHRoaXMtPnZhbHVlLCAkbnVtX2RpZ2l0cyk7CiAgICB9CgogICAgJGNhcnJ5ID0gMDsKCiAgICBmb3IgKCRpID0gY291bnQoJHRoaXMtPnZhbHVlKSAtIDE7ICRpID49IDA7IC0tJGkpIHsKICAgICAgJHRlbXAgPSAkdGhpcy0+dmFsdWVbJGldID4+ICRzaGlmdCB8ICRjYXJyeTsKICAgICAgJGNhcnJ5ID0gKCR0aGlzLT52YWx1ZVskaV0gJiAkY2FycnlfbWFzaykgPDwgJGNhcnJ5X3NoaWZ0OwogICAgICAkdGhpcy0+dmFsdWVbJGldID0gJHRlbXA7CiAgICB9CgogICAgJHRoaXMtPnZhbHVlID0gJHRoaXMtPl90cmltKCR0aGlzLT52YWx1ZSk7CiAgfQoKICBmdW5jdGlvbiBfbm9ybWFsaXplKCRyZXN1bHQpIHsKICAgICRyZXN1bHQtPnByZWNpc2lvbiA9ICR0aGlzLT5wcmVjaXNpb247CiAgICAkcmVzdWx0LT5iaXRtYXNrID0gJHRoaXMtPmJpdG1hc2s7CgogICAgc3dpdGNoICggTUFUSF9CSUdJTlRFR0VSX01PREUgKSB7CiAgICAgIGNhc2UgTUFUSF9CSUdJTlRFR0VSX01PREVfR01QOgogICAgICAgIGlmICghZW1wdHkoJHJlc3VsdC0+Yml0bWFzay0+dmFsdWUpKSB7CiAgICAgICAgICAkcmVzdWx0LT52YWx1ZSA9IGdtcF9hbmQoJHJlc3VsdC0+dmFsdWUsICRyZXN1bHQtPmJpdG1hc2stPnZhbHVlKTsKICAgICAgICB9CgogICAgICAgIHJldHVybiAkcmVzdWx0OwogICAgICBjYXNlIE1BVEhfQklHSU5URUdFUl9NT0RFX0JDTUFUSDoKICAgICAgICBpZiAoIWVtcHR5KCRyZXN1bHQtPmJpdG1hc2stPnZhbHVlKSkgewogICAgICAgICAgJHJlc3VsdC0+dmFsdWUgPSBiY21vZCgkcmVzdWx0LT52YWx1ZSwgJHJlc3VsdC0+Yml0bWFzay0+dmFsdWUpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuICRyZXN1bHQ7CiAgICB9CgogICAgJHZhbHVlID0gJiRyZXN1bHQtPnZhbHVlOwoKICAgIGlmICggIWNvdW50KCR2YWx1ZSkgKSB7CiAgICAgIHJldHVybiAkcmVzdWx0OwogICAgfQoKICAgICR2YWx1ZSA9ICR0aGlzLT5fdHJpbSgkdmFsdWUpOwoKICAgIGlmICghZW1wdHkoJHJlc3VsdC0+Yml0bWFzay0+dmFsdWUpKSB7CiAgICAgICRsZW5ndGggPSBtaW4oY291bnQoJHZhbHVlKSwgY291bnQoJHRoaXMtPmJpdG1hc2stPnZhbHVlKSk7CiAgICAgICR2YWx1ZSA9IGFycmF5X3NsaWNlKCR2YWx1ZSwgMCwgJGxlbmd0aCk7CgogICAgICBmb3IgKCRpID0gMDsgJGkgPCAkbGVuZ3RoOyArKyRpKSB7CiAgICAgICAgJHZhbHVlWyRpXSA9ICR2YWx1ZVskaV0gJiAkdGhpcy0+Yml0bWFzay0+dmFsdWVbJGldOwogICAgICB9CiAgICB9CgogICAgcmV0dXJuICRyZXN1bHQ7CiAgfQoKICBmdW5jdGlvbiBfdHJpbSgkdmFsdWUpIHsKICAgIGZvciAoJGkgPSBjb3VudCgkdmFsdWUpIC0gMTsgJGkgPj0gMDsgLS0kaSkgewogICAgICBpZiAoICR2YWx1ZVskaV0gKSB7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgdW5zZXQoJHZhbHVlWyRpXSk7CiAgICB9CgogICAgcmV0dXJuICR2YWx1ZTsKICB9CgogIGZ1bmN0aW9uIF9hcnJheV9yZXBlYXQoJGlucHV0LCAkbXVsdGlwbGllcikgewogICAgcmV0dXJuICgkbXVsdGlwbGllcikgPyBhcnJheV9maWxsKDAsICRtdWx0aXBsaWVyLCAkaW5wdXQpIDogYXJyYXkoKTsKICB9CgogIGZ1bmN0aW9uIF9iYXNlMjU2X2xzaGlmdCgmJHgsICRzaGlmdCkgewogICAgaWYgKCRzaGlmdCA9PSAwKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICAkbnVtX2J5dGVzID0gJHNoaWZ0ID4+IDM7IC8vIGVnLiBmbG9vcigkc2hpZnQvOCkKICAgICRzaGlmdCAmPSA3OyAvLyBlZy4gJHNoaWZ0ICUgOAoKICAgICRjYXJyeSA9IDA7CiAgICBmb3IgKCRpID0gc3RybGVuKCR4KSAtIDE7ICRpID49IDA7IC0tJGkpIHsKICAgICAgJHRlbXAgPSBvcmQoJHhbJGldKSA8PCAkc2hpZnQgfCAkY2Fycnk7CiAgICAgICR4WyRpXSA9IGNocigkdGVtcCk7CiAgICAgICRjYXJyeSA9ICR0ZW1wID4+IDg7CiAgICB9CiAgICAkY2FycnkgPSAoJGNhcnJ5ICE9IDApID8gY2hyKCRjYXJyeSkgOiAnJzsKICAgICR4ID0gJGNhcnJ5IC4gJHggLiBzdHJfcmVwZWF0KGNocigwKSwgJG51bV9ieXRlcyk7CiAgfQoKICBmdW5jdGlvbiBfYmFzZTI1Nl9yc2hpZnQoJiR4LCAkc2hpZnQpIHsKICAgIGlmICgkc2hpZnQgPT0gMCkgewogICAgICAkeCA9IGx0cmltKCR4LCBjaHIoMCkpOwogICAgICByZXR1cm4gJyc7CiAgICB9CgogICAgJG51bV9ieXRlcyA9ICRzaGlmdCA+PiAzOyAvLyBlZy4gZmxvb3IoJHNoaWZ0LzgpCiAgICAkc2hpZnQgJj0gNzsgLy8gZWcuICRzaGlmdCAlIDgKCiAgICAkcmVtYWluZGVyID0gJyc7CiAgICBpZiAoJG51bV9ieXRlcykgewogICAgICAkc3RhcnQgPSAkbnVtX2J5dGVzID4gc3RybGVuKCR4KSA/IC1zdHJsZW4oJHgpIDogLSRudW1fYnl0ZXM7CiAgICAgICRyZW1haW5kZXIgPSBzdWJzdHIoJHgsICRzdGFydCk7CiAgICAgICR4ID0gc3Vic3RyKCR4LCAwLCAtJG51bV9ieXRlcyk7CiAgICB9CgogICAgJGNhcnJ5ID0gMDsKICAgICRjYXJyeV9zaGlmdCA9IDggLSAkc2hpZnQ7CiAgICBmb3IgKCRpID0gMDsgJGkgPCBzdHJsZW4oJHgpOyArKyRpKSB7CiAgICAgICR0ZW1wID0gKG9yZCgkeFskaV0pID4+ICRzaGlmdCkgfCAkY2Fycnk7CiAgICAgICRjYXJyeSA9IChvcmQoJHhbJGldKSA8PCAkY2Fycnlfc2hpZnQpICYgMHhGRjsKICAgICAgJHhbJGldID0gY2hyKCR0ZW1wKTsKICAgIH0KICAgICR4ID0gbHRyaW0oJHgsIGNocigwKSk7CgogICAgJHJlbWFpbmRlciA9IGNocigkY2FycnkgPj4gJGNhcnJ5X3NoaWZ0KSAuICRyZW1haW5kZXI7CgogICAgcmV0dXJuIGx0cmltKCRyZW1haW5kZXIsIGNocigwKSk7CiAgfQoKICBmdW5jdGlvbiBfaW50MmJ5dGVzKCR4KSB7CiAgICByZXR1cm4gbHRyaW0ocGFjaygnTicsICR4KSwgY2hyKDApKTsKICB9CgogIGZ1bmN0aW9uIF9ieXRlczJpbnQoJHgpIHsKICAgICR0ZW1wID0gdW5wYWNrKCdOaW50Jywgc3RyX3BhZCgkeCwgNCwgY2hyKDApLCBTVFJfUEFEX0xFRlQpKTsKICAgIHJldHVybiAkdGVtcFsnaW50J107CiAgfQoKICBmdW5jdGlvbiBfZW5jb2RlQVNOMUxlbmd0aCgkbGVuZ3RoKSB7CiAgICBpZiAoJGxlbmd0aCA8PSAweDdGKSB7CiAgICAgIHJldHVybiBjaHIoJGxlbmd0aCk7CiAgICB9CgogICAgJHRlbXAgPSBsdHJpbShwYWNrKCdOJywgJGxlbmd0aCksIGNocigwKSk7CiAgICByZXR1cm4gcGFjaygnQ2EqJywgMHg4MCB8IHN0cmxlbigkdGVtcCksICR0ZW1wKTsKICB9Cn0KCmNsYXNzIEJhc2VOIHsKCiAgcHJpdmF0ZSAkYmFzZTsKICBwcml2YXRlICRyYWRpeDsKICBwcml2YXRlICRiaTI1NiwgJG9uZSwgJHplcm87CgogIGZ1bmN0aW9uIF9fY29uc3RydWN0KCRiYXNlKSB7CiAgICAkdGhpcy0+YmFzZSA9ICRiYXNlOwogICAgJHRoaXMtPnJhZGl4ID0gbmV3IE1hdGhfQmlnSW50ZWdlcihzdHJsZW4oJGJhc2UpKTsKICAgICR0aGlzLT5iaTI1NiA9IG5ldyBNYXRoX0JpZ0ludGVnZXIoMjU2KTsKICAgICR0aGlzLT56ZXJvID0gbmV3IE1hdGhfQmlnSW50ZWdlcigwKTsKICAgICR0aGlzLT5vbmUgPSBuZXcgTWF0aF9CaWdJbnRlZ2VyKDEpOwogIH0KCiAgcHVibGljIGZ1bmN0aW9uIGVuY29kZSgkdGV4dCkgewogICAgJGJpZyA9ICR0aGlzLT5vbmU7CiAgICBmb3IgKCRqID0gMDsgJGogPCBzdHJsZW4oJHRleHQpOyAkaisrKSB7CiAgICAgICRiaWcgPSAkYmlnLT5tdWx0aXBseSgkdGhpcy0+YmkyNTYpLT5hZGQobmV3IE1hdGhfQmlnSW50ZWdlcihvcmQoJHRleHRbJGpdKSkpOwogICAgfQogICAgJHJlc3VsdCA9ICIiOwogICAgd2hpbGUgKCEkdGhpcy0+emVyby0+ZXF1YWxzKCRiaWcpKSB7CiAgICAgICRwYXJ0cyA9ICRiaWctPmRpdmlkZSgkdGhpcy0+cmFkaXgpOwogICAgICAkc21hbGwgPSBpbnR2YWwoJHBhcnRzWzFdLT50b1N0cmluZygpKTsKICAgICAgJGJpZyA9ICRwYXJ0c1swXTsKICAgICAgJHJlc3VsdCA9ICR0aGlzLT5iYXNlWyRzbWFsbF0gLiAkcmVzdWx0OwogICAgfQogICAgcmV0dXJuICRyZXN1bHQ7CiAgfQoKICBwdWJsaWMgZnVuY3Rpb24gZGVjb2RlKCR0ZXh0KSB7CiAgICAkYmlnID0gJHRoaXMtPnplcm87CiAgICBmb3IgKCRqID0gMDsgJGogPCBzdHJsZW4oJHRleHQpOyAkaisrKSB7CiAgICAgICRpID0gc3RycG9zKCR0aGlzLT5iYXNlLCAkdGV4dFskal0pOwogICAgICAkYmlnID0gJGJpZy0+bXVsdGlwbHkoJHRoaXMtPnJhZGl4KS0+YWRkKG5ldyBNYXRoX0JpZ0ludGVnZXIoJGkpKTsKICAgIH0KICAgICRyZXN1bHQgPSAiIjsKICAgIHdoaWxlICghJHRoaXMtPnplcm8tPmVxdWFscygkYmlnKSkgewogICAgICAkcGFydHMgPSAkYmlnLT5kaXZpZGUoJHRoaXMtPmJpMjU2KTsKICAgICAgJHNtYWxsID0gJHBhcnRzWzFdLT50b0J5dGVzKCk7CiAgICAgICRiaWcgPSAkcGFydHNbMF07CiAgICAgICRyZXN1bHQgPSAkc21hbGwgLiAkcmVzdWx0OwogICAgfQogICAgcmV0dXJuIHN1YnN0cigkcmVzdWx0LCAxKTsKICB9Cn0KCiAgLy8gUGFzc2EgbyBhbGZhYmV0byBjb21vIHBhcsOibWV0cm8uIFRlbSA2MiBjYXJhY3RlcmVzIGFxdWksIGVudMOjbyBzw6NvIDYyIHPDrW1ib2xvcy4KICAkayA9IG5ldyBCYXNlTigiMDEyMzQ1Njc4OUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoiKTsKICAkeCA9ICJUaGUgcXVpY2sgYnJvd24gZm94IGp1bXBzIG92ZXIgYSBsYXp5IGRvZyI7CiAgZWNobyAkeCAuICJcbiI7CiAgJGMgPSAkay0+ZW5jb2RlKCR4KTsKICBlY2hvICRjIC4gIlxuIjsgLy8gRXNjcmV2ZSAiMXU5V0xmRzY1T010VmtRV1B0V0RjQzZvOElqSTV0ZDVsOUR6cGlsSUs0Tnl4ODF0S0xSclN0UGoiCiAgJGQgPSAkay0+ZGVjb2RlKCRjKTsKICBlY2hvICRkIC4gIlxuIjsgLy8gRXNjcmV2ZSAiVGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIGEgbGF6eSBkb2ciCj8+