<?php
const MOUSEVISION = 9;
abstract class Animal
{
protected $x;
protected $y;
protected $icon;
protected $field;
public function __construct($coordinateX, $coordinateY, $symbol)
{
$this->x = $coordinateX;
$this->y = $coordinateY;
$this->icon = $symbol;
}
public function getCoordinateX()
{
return $this->x;
}
public function getCoordinateY()
{
return $this->y;
}
public function showCoordinates()
{
echo "Координата X = [$this->x] ";
echo "Координата Y = [$this->y]";
}
public function getIcon()
{
return $this->icon;
}
public function moveTo($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function setField(GameField $field)
{
$this->field = $field;
}
public function unsetField()
{
$this->field = null;
}
public function defineAllAvaibleTurns($x, $y)
{
'x' => $x + 1,
'y' => $y,
'score' => INF
),
'x' => $x - 1,
'y' => $y,
'score' => INF
),
'x' => $x,
'y' => $y - 1,
'score' => INF
),
'x' => $x,
'y' => $y + 1,
'score' => INF
)
);
'x' => $x,
'y' => $y,
'score' => INF
)
);
foreach ($ways as $key => $value) {
if ($this->field->canMoveTo($value['x'], $value['y'])) {
$list[$key] = $value;
}
}
return $list;
}
}
class Dog extends Animal
{
public function defineAllAvaibleTurns($x, $y)
{
'x' => $x + 2,
'y' => $y,
'score' => INF
),
'x' => $x + 2,
'y' => $y + 1,
'score' => INF
),
'x' => $x + 2,
'y' => $y - 1,
'score' => INF
),
'x' => $x - 2,
'y' => $y,
'score' => INF
),
'x' => $x - 2,
'y' => $y + 1,
'score' => INF
),
'x' => $x - 2,
'y' => $y - 1,
'score' => INF
),
'x' => $x,
'y' => $y - 2,
'score' => INF
),
'x' => $x,
'y' => $y + 2,
'score' => INF
)
);
'x' => $x,
'y' => $y,
'score' => INF
)
);
foreach ($ways as $key => $value) {
if ($this->field->canMoveTo($value['x'], $value['y'])) {
$list[$key] = $value;
}
}
return $list;
}
public function makeMove()
{
$direction = $this->defineAllAvaibleTurns($this->x, $this->y);
$this->moveTo($direction[$key]['x'], $direction[$key]['y']);
}
}
class Mouse extends Animal
{
public function findAllCats()
{
$animals = $this->field->shareAnimals();
foreach ($animals as $animal) {
if ($animal instanceof Cat
&& (abs($this->x - $animal->getCoordinateX()) <= MOUSEVISION
&& abs($this->y - $animal->getCoordinateY()) <= MOUSEVISION
)) { $cats[] = $animal;
}
}
return $cats;
}
public function findClosestCat($x, $y)
{
$cats = $this->findAllCats();
$previous = INF;
$target = null;
foreach ($cats as $cat) {
$distanceX = abs($this->x - $cat->getCoordinateX()); $distanceY = abs($this->y - $cat->getCoordinateY()); $distance = max($distanceX, $distanceY); if ($distance < $previous) {
$target = $cat;
$previous = $distance;
}
}
return $target;
}
public function calculateScore($list)
{
foreach ($list as $key => $direction) {
$cat = $this->findClosestCat($direction['x'], $direction['y']);
if ($cat) {
$distanceX = abs($cat->getCoordinateX() - $direction['x']); $distanceY = abs($cat->getCoordinateY() - $direction['y']); $distance = max($distanceX, $distanceY); $extra = min($distanceX, $distanceY); $center['y'] = round($this->field->shareWidth() / 2); $center['x'] = round($this->field->shareHeight() / 2); $distanceToCenter = abs($center['x'] - $direction['x']) + abs($center['y'] - $direction['y']); $furtherTurns = $this->defineAllAvaibleTurns($direction['x'], $direction['y']);
$list[$key]['score'] = $distance * 4 + $extra * 2 + count($furtherTurns) - ($distanceToCenter * 0.1);
}
}
return $list;
}
public function chooseBestTurn()
{
$list = $this->calculateScore($this->defineAllAvaibleTurns($this->x, $this->y));
$turn = null;
$previous = 0;
foreach ($list as $key => $value) {
if ($value['score'] > $previous) {
$turn = $value;
$previous = $value['score'];
}
}
return $turn;
}
public function makeMove()
{
$turn = $this->chooseBestTurn();
$this->moveTo($turn['x'], $turn['y']);
}
}
class Cat extends Animal
{
protected $sleepCount = 0;
protected $moveCount = 0;
public function getIcon()
{
if ($this->sleepCount == 0) {
return parent::getIcon();
} else {
return "@";
}
}
public function moveTo($x, $y)
{
if ($this->sleepCount > 0) {
return $this->sleepCount--;
}
if ($this->field->checkTile($x, $y) instanceof Mouse) {
$this->field->killAnimal($x, $y);
parent::moveTo($x, $y);
$this->fallAsleep();
} else {
parent::moveTo($x, $y);
$this->moveCount++;
}
if ($this->moveCount == 8) {
$this->fallAsleep();
}
}
public function defineAllAvaibleTurns($x, $y)
{
'x' => $x + 1,
'y' => $y,
'score' => INF
),
'x' => $x + 1,
'y' => $y + 1,
'score' => INF
),
'x' => $x + 1,
'y' => $y - 1,
'score' => INF
),
'x' => $x - 1,
'y' => $y,
'score' => INF
),
'x' => $x - 1,
'y' => $y + 1,
'score' => INF
),
'x' => $x - 1,
'y' => $y - 1,
'score' => INF
),
'x' => $x,
'y' => $y - 1,
'score' => INF
),
'x' => $x,
'y' => $y + 1,
'score' => INF
)
);
'x' => $x,
'y' => $y,
'score' => INF
)
);
foreach ($ways as $value) {
$tile = $this->field->checkTile($value['x'], $value['y']);
if ($this->field->isXOnMap($value['x']) && $this->field->isYOnMap($value['y']) && !$tile || ($tile instanceof Mouse) && !$this->field->isDogNear($value['x'], $value['y'])) {
$list[] = $value;
}
}
return $list;
}
public function calculateScore($list)
{
$mouse = $this->findClosestMouse();
foreach ($list as $key => $direction) {
if ($mouse) {
$distanceX = abs($mouse->getCoordinateX() - $direction['x']); $distanceY = abs($mouse->getCoordinateY() - $direction['y']); $distance = $distanceX + $distanceY;
$list[$key]['score'] = $distance;
}
}
return $list;
}
public function chooseBestTurn()
{
$list = $this->calculateScore($this->defineAllAvaibleTurns($this->x, $this->y));
$previous = INF;
$turn = null;
foreach ($list as $key => $value) {
if ($value['score'] < $previous) {
$turn = $value;
$previous = $value['score'];
}
}
return $turn;
}
public function fallAsleep()
{
$this->sleepCount = 1;
$this->moveCount = 0;
}
public function makeMove()
{
$turn = $this->chooseBestTurn();
$this->moveTo($turn['x'], $turn['y']);
}
public function findClosestMouse()
{
$previous = INF;
$target = 0;
foreach ($this->field->shareAnimals() as $animal) {
if (!($animal instanceof Mouse)) {
continue;
}
$distanceX = abs($this->x - $animal->getCoordinateX()); $distanceY = abs($this->y - $animal->getCoordinateY()); $distance = max($distanceX, $distanceY); if ($distance < $previous) {
$target = $animal;
$previous = $distance;
}
}
if ($target) {
return $target;
}
}
}
class GameField
{
protected $field;
protected $animals = array(); protected $height;
protected $width;
public function __construct($height, $width)
{
$this->height = $height;
$this->width = $width;
}
public function printField()
{
foreach ($this->animals as $animal) {
$x = $animal->getCoordinateX();
$y = $animal->getCoordinateY();
$this->field[$x][$y] = $animal->getIcon();
}
foreach ($this->field as $value) {
foreach ($value as $dot) {
echo " $dot ";
}
echo "\n";
}
}
public function acquireAnimal(Animal $animal)
{
$this->animals[] = $animal;
$animal->setField($this);
}
public function shareAnimals()
{
return $this->animals;
}
public function shareHeight()
{
return $this->height - 1;
}
public function shareWidth()
{
return $this->width - 1;
}
public function killAnimal($x, $y)
{
foreach ($this->animals as $key => $animal) {
if ($animal->getCoordinateX() == $x && $animal->getCoordinateY() == $y) {
$this->animals[$key]->unsetField();
unset($this->animals[$key]); }
}
}
public function checkTile($x, $y)
{
foreach ($this->animals as $animal) {
if ($animal->getCoordinateX() == $x && $animal->getCoordinateY() == $y) {
return $animal;
}
}
return false;
}
public function isXOnMap($x)
{
if ($x < 0 || $x > ($this->height - 1)) {
return false;
} else {
return true;
}
}
public function isYOnMap($y)
{
if ($y < 0 || $y > ($this->width - 1)) {
return false;
} else {
return true;
}
}
public function canMoveTo($x, $y)
{
if ($this->isXOnMap($x) && $this->isYOnMap($y) && !$this->checkTile($x, $y)) {
return true;
}
return false;
}
public function isDogNear($x, $y)
{
foreach ($this->animals as $animal) {
if ($animal instanceof Dog) {
$differenceX = abs($animal->getCoordinateX() - $x); $differenceY = abs($animal->getCoordinateY() - $y); if ($differenceX < 2 && $differenceY < 2) {
return true;
}
}
}
return false;
}
public function testTheKitty()
{
foreach ($this->animals as $animal) {
if ($animal instanceof Mouse) {
$animal->makeMove();
}
}
foreach ($this->animals as $animal) {
if ($animal instanceof Cat || $animal instanceof Dog) {
$animal->makeMove();
}
}
}
}
$test = new GameField(20, 20);
$mouse1 = new Mouse(3, 15, "1");
$mouse2 = new Mouse(5, 7, "2");
$kitty = new Cat(19, 10, "K");
$kitty2 = new Cat(15, 11, "k");
$dog = new Dog(1, 8, "D");
$test->acquireAnimal($mouse1);
$test->acquireAnimal($mouse2);
$test->acquireAnimal($kitty);
$test->acquireAnimal($kitty2);
$test->acquireAnimal($dog);
$test->printField();
echo "\n";
for ($i = 0; $i < 40; $i++) {
$test->testTheKitty();
$test->printField();
echo "\n";
}
PD9waHAKY29uc3QgTU9VU0VWSVNJT04gPSA5OwphYnN0cmFjdCBjbGFzcyBBbmltYWwKewogICAgcHJvdGVjdGVkICR4OwogICAgcHJvdGVjdGVkICR5OwogICAgcHJvdGVjdGVkICRpY29uOwogICAgcHJvdGVjdGVkICRmaWVsZDsKICAgIAogICAgcHVibGljIGZ1bmN0aW9uIF9fY29uc3RydWN0KCRjb29yZGluYXRlWCwgJGNvb3JkaW5hdGVZLCAkc3ltYm9sKQogICAgewogICAgICAgICR0aGlzLT54ICAgID0gJGNvb3JkaW5hdGVYOwogICAgICAgICR0aGlzLT55ICAgID0gJGNvb3JkaW5hdGVZOwogICAgICAgICR0aGlzLT5pY29uID0gJHN5bWJvbDsKICAgIH0KICAgIHB1YmxpYyBmdW5jdGlvbiBnZXRDb29yZGluYXRlWCgpCiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT54OwogICAgfQogICAgcHVibGljIGZ1bmN0aW9uIGdldENvb3JkaW5hdGVZKCkKICAgIHsKICAgICAgICByZXR1cm4gJHRoaXMtPnk7CiAgICB9CiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBzaG93Q29vcmRpbmF0ZXMoKQogICAgewogICAgICAgIGVjaG8gItCa0L7QvtGA0LTQuNC90LDRgtCwIFggPSAgWyR0aGlzLT54XSAiOwogICAgICAgIGVjaG8gItCa0L7QvtGA0LTQuNC90LDRgtCwIFkgPSBbJHRoaXMtPnldIjsKICAgIH0KICAgIAogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gZ2V0SWNvbigpCiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5pY29uOwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gbW92ZVRvKCR4LCAkeSkKICAgIHsKICAgICAgICAkdGhpcy0+eCA9ICR4OwogICAgICAgICR0aGlzLT55ID0gJHk7CiAgICB9CiAgICAKICAgIAogICAgcHVibGljIGZ1bmN0aW9uIHNldEZpZWxkKEdhbWVGaWVsZCAkZmllbGQpCiAgICB7CiAgICAgICAgJHRoaXMtPmZpZWxkID0gJGZpZWxkOwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gdW5zZXRGaWVsZCgpCiAgICB7CiAgICAgICAgJHRoaXMtPmZpZWxkID0gbnVsbDsKICAgIH0KICAgIHB1YmxpYyBmdW5jdGlvbiBkZWZpbmVBbGxBdmFpYmxlVHVybnMoJHgsICR5KQogICAgewogICAgICAgICR3YXlzID0gYXJyYXkoCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4ICsgMSwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4IC0gMSwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4LAogICAgICAgICAgICAgICAgJ3knID0+ICR5IC0gMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4LAogICAgICAgICAgICAgICAgJ3knID0+ICR5ICsgMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICApOwogICAgICAgICRsaXN0ID0gYXJyYXkoCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4LAogICAgICAgICAgICAgICAgJ3knID0+ICR5LAogICAgICAgICAgICAgICAgJ3Njb3JlJyA9PiBJTkYKICAgICAgICAgICAgKQogICAgICAgICk7CiAgICAgICAgCiAgICAgICAgZm9yZWFjaCAoJHdheXMgYXMgJGtleSA9PiAkdmFsdWUpIHsKICAgICAgICAgICAgCiAgICAgICAgICAgIGlmICgkdGhpcy0+ZmllbGQtPmNhbk1vdmVUbygkdmFsdWVbJ3gnXSwgJHZhbHVlWyd5J10pKSB7CiAgICAgICAgICAgICAgICAkbGlzdFska2V5XSA9ICR2YWx1ZTsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgcmV0dXJuICRsaXN0OwogICAgICAgIAogICAgfQp9CgpjbGFzcyBEb2cgZXh0ZW5kcyBBbmltYWwKewogICAgcHVibGljIGZ1bmN0aW9uIGRlZmluZUFsbEF2YWlibGVUdXJucygkeCwgJHkpCiAgICB7CiAgICAgICAgJHdheXMgPSBhcnJheSgKICAgICAgICAgICAgYXJyYXkoCiAgICAgICAgICAgICAgICAneCcgPT4gJHggKyAyLAogICAgICAgICAgICAgICAgJ3knID0+ICR5LAogICAgICAgICAgICAgICAgJ3Njb3JlJyA9PiBJTkYKICAgICAgICAgICAgKSwKICAgICAgICAgICAgYXJyYXkoCiAgICAgICAgICAgICAgICAneCcgPT4gJHggKyAyLAogICAgICAgICAgICAgICAgJ3knID0+ICR5ICsgMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4ICsgMiwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSAtIDEsCiAgICAgICAgICAgICAgICAnc2NvcmUnID0+IElORgogICAgICAgICAgICApLAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCAtIDIsCiAgICAgICAgICAgICAgICAneScgPT4gJHksCiAgICAgICAgICAgICAgICAnc2NvcmUnID0+IElORgogICAgICAgICAgICApLAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCAtIDIsCiAgICAgICAgICAgICAgICAneScgPT4gJHkgKyAxLAogICAgICAgICAgICAgICAgJ3Njb3JlJyA9PiBJTkYKICAgICAgICAgICAgKSwKICAgICAgICAgICAgYXJyYXkoCiAgICAgICAgICAgICAgICAneCcgPT4gJHggLSAyLAogICAgICAgICAgICAgICAgJ3knID0+ICR5IC0gMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSAtIDIsCiAgICAgICAgICAgICAgICAnc2NvcmUnID0+IElORgogICAgICAgICAgICApLAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSArIDIsCiAgICAgICAgICAgICAgICAnc2NvcmUnID0+IElORgogICAgICAgICAgICApCiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICAgICAgCiAgICAgICAgKTsKICAgICAgICAkbGlzdCA9IGFycmF5KAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICkKICAgICAgICApOwogICAgICAgIAogICAgICAgIGZvcmVhY2ggKCR3YXlzIGFzICRrZXkgPT4gJHZhbHVlKSB7CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAoJHRoaXMtPmZpZWxkLT5jYW5Nb3ZlVG8oJHZhbHVlWyd4J10sICR2YWx1ZVsneSddKSkgewogICAgICAgICAgICAgICAgJGxpc3RbJGtleV0gPSAkdmFsdWU7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgCiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIAogICAgICAgIAogICAgICAgIHJldHVybiAkbGlzdDsKICAgICAgICAKICAgIH0KICAgIHB1YmxpYyBmdW5jdGlvbiBtYWtlTW92ZSgpCiAgICB7CiAgICAgICAgJGRpcmVjdGlvbiA9ICR0aGlzLT5kZWZpbmVBbGxBdmFpYmxlVHVybnMoJHRoaXMtPngsICR0aGlzLT55KTsKICAgICAgICAKICAgICAgICAka2V5ID0gYXJyYXlfcmFuZCgkZGlyZWN0aW9uKTsKICAgICAgICAKICAgICAgICAkdGhpcy0+bW92ZVRvKCRkaXJlY3Rpb25bJGtleV1bJ3gnXSwgJGRpcmVjdGlvblska2V5XVsneSddKTsKICAgIH0KICAgIAp9CgpjbGFzcyBNb3VzZSBleHRlbmRzIEFuaW1hbAp7CiAgICAKICAgIAogICAgcHVibGljIGZ1bmN0aW9uIGZpbmRBbGxDYXRzKCkKICAgIHsKICAgICAgICAkY2F0cyAgICA9IGFycmF5KCk7CiAgICAgICAgJGFuaW1hbHMgPSAkdGhpcy0+ZmllbGQtPnNoYXJlQW5pbWFscygpOwogICAgICAgIGZvcmVhY2ggKCRhbmltYWxzIGFzICRhbmltYWwpIHsKICAgICAgICAgICAgaWYgKCRhbmltYWwgaW5zdGFuY2VvZiBDYXQgJiYgKGFicygkdGhpcy0+eCAtICRhbmltYWwtPmdldENvb3JkaW5hdGVYKCkpIDw9IE1PVVNFVklTSU9OICYmIGFicygkdGhpcy0+eSAtICRhbmltYWwtPmdldENvb3JkaW5hdGVZKCkpIDw9IE1PVVNFVklTSU9OKSkgewogICAgICAgICAgICAgICAgJGNhdHNbXSA9ICRhbmltYWw7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuICRjYXRzOwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gZmluZENsb3Nlc3RDYXQoJHgsICR5KQogICAgewogICAgICAgICRjYXRzICAgICA9ICR0aGlzLT5maW5kQWxsQ2F0cygpOwogICAgICAgICRwcmV2aW91cyA9IElORjsKICAgICAgICAkdGFyZ2V0ICAgPSBudWxsOwogICAgICAgIGZvcmVhY2ggKCRjYXRzIGFzICRjYXQpIHsKICAgICAgICAgICAgCiAgICAgICAgICAgIAogICAgICAgICAgICAkZGlzdGFuY2VYID0gYWJzKCR0aGlzLT54IC0gJGNhdC0+Z2V0Q29vcmRpbmF0ZVgoKSk7CiAgICAgICAgICAgICRkaXN0YW5jZVkgPSBhYnMoJHRoaXMtPnkgLSAkY2F0LT5nZXRDb29yZGluYXRlWSgpKTsKICAgICAgICAgICAgJGRpc3RhbmNlICA9IG1heCgkZGlzdGFuY2VYLCAkZGlzdGFuY2VZKTsKICAgICAgICAgICAgaWYgKCRkaXN0YW5jZSA8ICRwcmV2aW91cykgewogICAgICAgICAgICAgICAgJHRhcmdldCAgID0gJGNhdDsKICAgICAgICAgICAgICAgICRwcmV2aW91cyA9ICRkaXN0YW5jZTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgcmV0dXJuICR0YXJnZXQ7CiAgICB9CiAgICAKICAgIAogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gY2FsY3VsYXRlU2NvcmUoJGxpc3QpCiAgICB7CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICAgICAgZm9yZWFjaCAoJGxpc3QgYXMgJGtleSA9PiAkZGlyZWN0aW9uKSB7CiAgICAgICAgICAgICRjYXQgPSAkdGhpcy0+ZmluZENsb3Nlc3RDYXQoJGRpcmVjdGlvblsneCddLCAkZGlyZWN0aW9uWyd5J10pOwogICAgICAgICAgICBpZiAoJGNhdCkgewogICAgICAgICAgICAgICAgJGRpc3RhbmNlWCAgICAgICAgPSBhYnMoJGNhdC0+Z2V0Q29vcmRpbmF0ZVgoKSAtICRkaXJlY3Rpb25bJ3gnXSk7CiAgICAgICAgICAgICAgICAkZGlzdGFuY2VZICAgICAgICA9IGFicygkY2F0LT5nZXRDb29yZGluYXRlWSgpIC0gJGRpcmVjdGlvblsneSddKTsKICAgICAgICAgICAgICAgICRkaXN0YW5jZSAgICAgICAgID0gbWF4KCRkaXN0YW5jZVgsICRkaXN0YW5jZVkpOwogICAgICAgICAgICAgICAgJGV4dHJhICAgICAgICAgICAgPSBtaW4oJGRpc3RhbmNlWCwgJGRpc3RhbmNlWSk7CiAgICAgICAgICAgICAgICAkY2VudGVyWyd5J10gICAgICA9IHJvdW5kKCR0aGlzLT5maWVsZC0+c2hhcmVXaWR0aCgpIC8gMik7CiAgICAgICAgICAgICAgICAkY2VudGVyWyd4J10gICAgICA9IHJvdW5kKCR0aGlzLT5maWVsZC0+c2hhcmVIZWlnaHQoKSAvIDIpOwogICAgICAgICAgICAgICAgJGRpc3RhbmNlVG9DZW50ZXIgPSBhYnMoJGNlbnRlclsneCddIC0gJGRpcmVjdGlvblsneCddKSArIGFicygkY2VudGVyWyd5J10gLSAkZGlyZWN0aW9uWyd5J10pOwogICAgICAgICAgICAgICAgJGZ1cnRoZXJUdXJucyAgICAgPSAkdGhpcy0+ZGVmaW5lQWxsQXZhaWJsZVR1cm5zKCRkaXJlY3Rpb25bJ3gnXSwgJGRpcmVjdGlvblsneSddKTsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgJGxpc3RbJGtleV1bJ3Njb3JlJ10gPSAkZGlzdGFuY2UgKiA0ICsgJGV4dHJhICogMiArIGNvdW50KCRmdXJ0aGVyVHVybnMpIC0gKCRkaXN0YW5jZVRvQ2VudGVyICogMC4xKTsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgcmV0dXJuICRsaXN0OwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gY2hvb3NlQmVzdFR1cm4oKQogICAgewogICAgICAgICRsaXN0ID0gJHRoaXMtPmNhbGN1bGF0ZVNjb3JlKCR0aGlzLT5kZWZpbmVBbGxBdmFpYmxlVHVybnMoJHRoaXMtPngsICR0aGlzLT55KSk7CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgJHR1cm4gICAgID0gbnVsbDsKICAgICAgICAkcHJldmlvdXMgPSAwOwogICAgICAgIGZvcmVhY2ggKCRsaXN0IGFzICRrZXkgPT4gJHZhbHVlKSB7CiAgICAgICAgICAgIGlmICgkdmFsdWVbJ3Njb3JlJ10gPiAkcHJldmlvdXMpIHsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgJHR1cm4gICAgID0gJHZhbHVlOwogICAgICAgICAgICAgICAgJHByZXZpb3VzID0gJHZhbHVlWydzY29yZSddOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgIH0KICAgICAgICAKICAgICAgICAKICAgICAgICByZXR1cm4gJHR1cm47CiAgICAgICAgCiAgICB9CiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBtYWtlTW92ZSgpCiAgICB7CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICAgICAgJHR1cm4gPSAkdGhpcy0+Y2hvb3NlQmVzdFR1cm4oKTsKICAgICAgICAKICAgICAgICAkdGhpcy0+bW92ZVRvKCR0dXJuWyd4J10sICR0dXJuWyd5J10pOwogICAgICAgIAogICAgICAgIAogICAgICAgIAogICAgfQogICAgCiAgICAKICAgIAp9CgoKCgoKCmNsYXNzIENhdCBleHRlbmRzIEFuaW1hbAp7CiAgICBwcm90ZWN0ZWQgJHNsZWVwQ291bnQgPSAwOwogICAgcHJvdGVjdGVkICRtb3ZlQ291bnQgPSAwOwogICAgCiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBnZXRJY29uKCkKICAgIHsKICAgICAgICBpZiAoJHRoaXMtPnNsZWVwQ291bnQgPT0gMCkgewogICAgICAgICAgICByZXR1cm4gcGFyZW50OjpnZXRJY29uKCk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuICJAIjsKICAgICAgICB9CiAgICB9CiAgICBwdWJsaWMgZnVuY3Rpb24gbW92ZVRvKCR4LCAkeSkKICAgIHsKICAgICAgICAKICAgICAgICAKICAgICAgICAKICAgICAgICBpZiAoJHRoaXMtPnNsZWVwQ291bnQgPiAwKSB7CiAgICAgICAgICAgIHJldHVybiAkdGhpcy0+c2xlZXBDb3VudC0tOwogICAgICAgIH0KICAgICAgICBpZiAoJHRoaXMtPmZpZWxkLT5jaGVja1RpbGUoJHgsICR5KSBpbnN0YW5jZW9mIE1vdXNlKSB7CiAgICAgICAgICAgICR0aGlzLT5maWVsZC0+a2lsbEFuaW1hbCgkeCwgJHkpOwogICAgICAgICAgICBwYXJlbnQ6Om1vdmVUbygkeCwgJHkpOwogICAgICAgICAgICAkdGhpcy0+ZmFsbEFzbGVlcCgpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHBhcmVudDo6bW92ZVRvKCR4LCAkeSk7CiAgICAgICAgICAgICR0aGlzLT5tb3ZlQ291bnQrKzsKICAgICAgICB9CiAgICAgICAgaWYgKCR0aGlzLT5tb3ZlQ291bnQgPT0gOCkgewogICAgICAgICAgICAkdGhpcy0+ZmFsbEFzbGVlcCgpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gZGVmaW5lQWxsQXZhaWJsZVR1cm5zKCR4LCAkeSkKICAgIHsKICAgICAgICAkd2F5cyA9IGFycmF5KAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCArIDEsCiAgICAgICAgICAgICAgICAneScgPT4gJHksCiAgICAgICAgICAgICAgICAnc2NvcmUnID0+IElORgogICAgICAgICAgICApLAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCArIDEsCiAgICAgICAgICAgICAgICAneScgPT4gJHkgKyAxLAogICAgICAgICAgICAgICAgJ3Njb3JlJyA9PiBJTkYKICAgICAgICAgICAgKSwKICAgICAgICAgICAgYXJyYXkoCiAgICAgICAgICAgICAgICAneCcgPT4gJHggKyAxLAogICAgICAgICAgICAgICAgJ3knID0+ICR5IC0gMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4IC0gMSwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4IC0gMSwKICAgICAgICAgICAgICAgICd5JyA9PiAkeSArIDEsCiAgICAgICAgICAgICAgICAnc2NvcmUnID0+IElORgogICAgICAgICAgICApLAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICd4JyA9PiAkeCAtIDEsCiAgICAgICAgICAgICAgICAneScgPT4gJHkgLSAxLAogICAgICAgICAgICAgICAgJ3Njb3JlJyA9PiBJTkYKICAgICAgICAgICAgKSwKICAgICAgICAgICAgCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4LAogICAgICAgICAgICAgICAgJ3knID0+ICR5IC0gMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICksCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4LAogICAgICAgICAgICAgICAgJ3knID0+ICR5ICsgMSwKICAgICAgICAgICAgICAgICdzY29yZScgPT4gSU5GCiAgICAgICAgICAgICkKICAgICAgICAgICAgCiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICApOwogICAgICAgICRsaXN0ID0gYXJyYXkoCiAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgJ3gnID0+ICR4LAogICAgICAgICAgICAgICAgJ3knID0+ICR5LAogICAgICAgICAgICAgICAgJ3Njb3JlJyA9PiBJTkYKICAgICAgICAgICAgKQogICAgICAgICk7CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgZm9yZWFjaCAoJHdheXMgYXMgJHZhbHVlKSB7CiAgICAgICAgICAgICR0aWxlID0gJHRoaXMtPmZpZWxkLT5jaGVja1RpbGUoJHZhbHVlWyd4J10sICR2YWx1ZVsneSddKTsKICAgICAgICAgICAgaWYgKCR0aGlzLT5maWVsZC0+aXNYT25NYXAoJHZhbHVlWyd4J10pICYmICR0aGlzLT5maWVsZC0+aXNZT25NYXAoJHZhbHVlWyd5J10pICYmICEkdGlsZSB8fCAoJHRpbGUgaW5zdGFuY2VvZiBNb3VzZSkgJiYgISR0aGlzLT5maWVsZC0+aXNEb2dOZWFyKCR2YWx1ZVsneCddLCAkdmFsdWVbJ3knXSkpIHsKICAgICAgICAgICAgICAgICRsaXN0W10gPSAkdmFsdWU7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgcmV0dXJuICRsaXN0OwogICAgICAgIAogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gY2FsY3VsYXRlU2NvcmUoJGxpc3QpCiAgICB7CiAgICAgICAgJG1vdXNlID0gJHRoaXMtPmZpbmRDbG9zZXN0TW91c2UoKTsKICAgICAgICAKICAgICAgICBmb3JlYWNoICgkbGlzdCBhcyAka2V5ID0+ICRkaXJlY3Rpb24pIHsKICAgICAgICAgICAgCiAgICAgICAgICAgIGlmICgkbW91c2UpIHsKICAgICAgICAgICAgICAgICRkaXN0YW5jZVggPSBhYnMoJG1vdXNlLT5nZXRDb29yZGluYXRlWCgpIC0gJGRpcmVjdGlvblsneCddKTsKICAgICAgICAgICAgICAgICRkaXN0YW5jZVkgPSBhYnMoJG1vdXNlLT5nZXRDb29yZGluYXRlWSgpIC0gJGRpcmVjdGlvblsneSddKTsKICAgICAgICAgICAgICAgICRkaXN0YW5jZSAgPSAkZGlzdGFuY2VYICsgJGRpc3RhbmNlWTsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAkbGlzdFska2V5XVsnc2NvcmUnXSA9ICRkaXN0YW5jZTsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgcmV0dXJuICRsaXN0OwogICAgICAgIAogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gY2hvb3NlQmVzdFR1cm4oKQogICAgewogICAgICAgICRsaXN0ID0gJHRoaXMtPmNhbGN1bGF0ZVNjb3JlKCR0aGlzLT5kZWZpbmVBbGxBdmFpYmxlVHVybnMoJHRoaXMtPngsICR0aGlzLT55KSk7CiAgICAgICAgCiAgICAgICAgJHByZXZpb3VzID0gSU5GOwogICAgICAgICR0dXJuICAgICA9IG51bGw7CiAgICAgICAgZm9yZWFjaCAoJGxpc3QgYXMgJGtleSA9PiAkdmFsdWUpIHsKICAgICAgICAgICAgaWYgKCR2YWx1ZVsnc2NvcmUnXSA8ICRwcmV2aW91cykgewogICAgICAgICAgICAgICAgJHR1cm4gICAgID0gJHZhbHVlOwogICAgICAgICAgICAgICAgJHByZXZpb3VzID0gJHZhbHVlWydzY29yZSddOwogICAgICAgICAgICAgICAgCiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgcmV0dXJuICR0dXJuOwogICAgICAgIAogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gZmFsbEFzbGVlcCgpCiAgICB7CiAgICAgICAgJHRoaXMtPnNsZWVwQ291bnQgPSAxOwogICAgICAgIAogICAgICAgICR0aGlzLT5tb3ZlQ291bnQgPSAwOwogICAgfQogICAgCiAgICAKICAgIAogICAgcHVibGljIGZ1bmN0aW9uIG1ha2VNb3ZlKCkKICAgIHsKICAgICAgICAkdHVybiA9ICR0aGlzLT5jaG9vc2VCZXN0VHVybigpOwogICAgICAgIAogICAgICAgICR0aGlzLT5tb3ZlVG8oJHR1cm5bJ3gnXSwgJHR1cm5bJ3knXSk7CiAgICAgICAgCiAgICB9CiAgICAKICAgIAogICAgcHVibGljIGZ1bmN0aW9uIGZpbmRDbG9zZXN0TW91c2UoKQogICAgewogICAgICAgICRwcmV2aW91cyA9IElORjsKICAgICAgICAkdGFyZ2V0ICAgPSAwOwogICAgICAgIAogICAgICAgIGZvcmVhY2ggKCR0aGlzLT5maWVsZC0+c2hhcmVBbmltYWxzKCkgYXMgJGFuaW1hbCkgewogICAgICAgICAgICBpZiAoISgkYW5pbWFsIGluc3RhbmNlb2YgTW91c2UpKSB7CiAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICAkZGlzdGFuY2VYID0gYWJzKCR0aGlzLT54IC0gJGFuaW1hbC0+Z2V0Q29vcmRpbmF0ZVgoKSk7CiAgICAgICAgICAgICRkaXN0YW5jZVkgPSBhYnMoJHRoaXMtPnkgLSAkYW5pbWFsLT5nZXRDb29yZGluYXRlWSgpKTsKICAgICAgICAgICAgJGRpc3RhbmNlICA9IG1heCgkZGlzdGFuY2VYLCAkZGlzdGFuY2VZKTsKICAgICAgICAgICAgaWYgKCRkaXN0YW5jZSA8ICRwcmV2aW91cykgewogICAgICAgICAgICAgICAgJHRhcmdldCAgID0gJGFuaW1hbDsKICAgICAgICAgICAgICAgICRwcmV2aW91cyA9ICRkaXN0YW5jZTsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgaWYgKCR0YXJnZXQpIHsKICAgICAgICAgICAgcmV0dXJuICR0YXJnZXQ7CiAgICAgICAgfQogICAgfQogICAgCiAgICAKfQoKCmNsYXNzIEdhbWVGaWVsZAp7CiAgICBwcm90ZWN0ZWQgJGZpZWxkOwogICAgcHJvdGVjdGVkICRhbmltYWxzID0gYXJyYXkoKTsKICAgIHByb3RlY3RlZCAkaGVpZ2h0OwogICAgcHJvdGVjdGVkICR3aWR0aDsKICAgIAogICAgcHVibGljIGZ1bmN0aW9uIF9fY29uc3RydWN0KCRoZWlnaHQsICR3aWR0aCkKICAgIHsKICAgICAgICAkdGhpcy0+aGVpZ2h0ID0gJGhlaWdodDsKICAgICAgICAkdGhpcy0+d2lkdGggID0gJHdpZHRoOwogICAgfQogICAgcHVibGljIGZ1bmN0aW9uIHByaW50RmllbGQoKQogICAgewogICAgICAgICR0aGlzLT5maWVsZCA9IGFycmF5X2ZpbGwoMCwgJHRoaXMtPmhlaWdodCwgYXJyYXlfZmlsbCgwLCAkdGhpcy0+d2lkdGgsICIuIikpOwogICAgICAgIAogICAgICAgIGZvcmVhY2ggKCR0aGlzLT5hbmltYWxzIGFzICRhbmltYWwpIHsKICAgICAgICAgICAgJHggICAgICAgICAgICAgICAgICAgPSAkYW5pbWFsLT5nZXRDb29yZGluYXRlWCgpOwogICAgICAgICAgICAkeSAgICAgICAgICAgICAgICAgICA9ICRhbmltYWwtPmdldENvb3JkaW5hdGVZKCk7CiAgICAgICAgICAgICR0aGlzLT5maWVsZFskeF1bJHldID0gJGFuaW1hbC0+Z2V0SWNvbigpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBmb3JlYWNoICgkdGhpcy0+ZmllbGQgYXMgJHZhbHVlKSB7CiAgICAgICAgICAgIGZvcmVhY2ggKCR2YWx1ZSBhcyAkZG90KSB7CiAgICAgICAgICAgICAgICBlY2hvICIgJGRvdCAiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVjaG8gIlxuIjsKICAgICAgICB9CiAgICB9CiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBhY3F1aXJlQW5pbWFsKEFuaW1hbCAkYW5pbWFsKQogICAgewogICAgICAgICR0aGlzLT5hbmltYWxzW10gPSAkYW5pbWFsOwogICAgICAgICRhbmltYWwtPnNldEZpZWxkKCR0aGlzKTsKICAgIH0KICAgIAogICAgcHVibGljIGZ1bmN0aW9uIHNoYXJlQW5pbWFscygpCiAgICB7CiAgICAgICAgcmV0dXJuICR0aGlzLT5hbmltYWxzOwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gc2hhcmVIZWlnaHQoKQogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+aGVpZ2h0IC0gMTsKICAgIH0KICAgIAogICAgcHVibGljIGZ1bmN0aW9uIHNoYXJlV2lkdGgoKQogICAgewogICAgICAgIHJldHVybiAkdGhpcy0+d2lkdGggLSAxOwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24ga2lsbEFuaW1hbCgkeCwgJHkpCiAgICB7CiAgICAgICAgCiAgICAgICAgZm9yZWFjaCAoJHRoaXMtPmFuaW1hbHMgYXMgJGtleSA9PiAkYW5pbWFsKSB7CiAgICAgICAgICAgIGlmICgkYW5pbWFsLT5nZXRDb29yZGluYXRlWCgpID09ICR4ICYmICRhbmltYWwtPmdldENvb3JkaW5hdGVZKCkgPT0gJHkpIHsKICAgICAgICAgICAgICAgICR0aGlzLT5hbmltYWxzWyRrZXldLT51bnNldEZpZWxkKCk7CiAgICAgICAgICAgICAgICB1bnNldCgkdGhpcy0+YW5pbWFsc1ska2V5XSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICB9CiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBjaGVja1RpbGUoJHgsICR5KQogICAgewogICAgICAgIAogICAgICAgIGZvcmVhY2ggKCR0aGlzLT5hbmltYWxzIGFzICRhbmltYWwpIHsKICAgICAgICAgICAgaWYgKCRhbmltYWwtPmdldENvb3JkaW5hdGVYKCkgPT0gJHggJiYgJGFuaW1hbC0+Z2V0Q29vcmRpbmF0ZVkoKSA9PSAkeSkgewogICAgICAgICAgICAgICAgcmV0dXJuICRhbmltYWw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgfQogICAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgIAogICAgcHVibGljIGZ1bmN0aW9uIGlzWE9uTWFwKCR4KQogICAgewogICAgICAgIGlmICgkeCA8IDAgfHwgJHggPiAoJHRoaXMtPmhlaWdodCAtIDEpKSB7CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBpc1lPbk1hcCgkeSkKICAgIHsKICAgICAgICBpZiAoJHkgPCAwIHx8ICR5ID4gKCR0aGlzLT53aWR0aCAtIDEpKSB7CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIHB1YmxpYyBmdW5jdGlvbiBjYW5Nb3ZlVG8oJHgsICR5KQogICAgewogICAgICAgIGlmICgkdGhpcy0+aXNYT25NYXAoJHgpICYmICR0aGlzLT5pc1lPbk1hcCgkeSkgJiYgISR0aGlzLT5jaGVja1RpbGUoJHgsICR5KSkgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgCiAgICBwdWJsaWMgZnVuY3Rpb24gaXNEb2dOZWFyKCR4LCAkeSkKICAgIHsKICAgICAgICBmb3JlYWNoICgkdGhpcy0+YW5pbWFscyBhcyAkYW5pbWFsKSB7CiAgICAgICAgICAgIGlmICgkYW5pbWFsIGluc3RhbmNlb2YgRG9nKSB7CiAgICAgICAgICAgICAgICAkZGlmZmVyZW5jZVggPSBhYnMoJGFuaW1hbC0+Z2V0Q29vcmRpbmF0ZVgoKSAtICR4KTsKICAgICAgICAgICAgICAgICRkaWZmZXJlbmNlWSA9IGFicygkYW5pbWFsLT5nZXRDb29yZGluYXRlWSgpIC0gJHkpOwogICAgICAgICAgICAgICAgaWYgKCRkaWZmZXJlbmNlWCA8IDIgJiYgJGRpZmZlcmVuY2VZIDwgMikgewogICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgIAogICAgcHVibGljIGZ1bmN0aW9uIHRlc3RUaGVLaXR0eSgpCiAgICB7CiAgICAgICAgCiAgICAgICAgZm9yZWFjaCAoJHRoaXMtPmFuaW1hbHMgYXMgJGFuaW1hbCkgewogICAgICAgICAgICBpZiAoJGFuaW1hbCBpbnN0YW5jZW9mIE1vdXNlKSB7CiAgICAgICAgICAgICAgICAkYW5pbWFsLT5tYWtlTW92ZSgpOwogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgZm9yZWFjaCAoJHRoaXMtPmFuaW1hbHMgYXMgJGFuaW1hbCkgewogICAgICAgICAgICBpZiAoJGFuaW1hbCBpbnN0YW5jZW9mIENhdCB8fCAkYW5pbWFsIGluc3RhbmNlb2YgRG9nKSB7CiAgICAgICAgICAgICAgICAkYW5pbWFsLT5tYWtlTW92ZSgpOwogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICB9CiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICAgICAgCiAgICB9Cn0KCgokdGVzdCAgID0gbmV3IEdhbWVGaWVsZCgyMCwgMjApOwokbW91c2UxID0gbmV3IE1vdXNlKDMsIDE1LCAiMSIpOwokbW91c2UyID0gbmV3IE1vdXNlKDUsIDcsICIyIik7CiRraXR0eSAgPSBuZXcgQ2F0KDE5LCAxMCwgIksiKTsKJGtpdHR5MiA9IG5ldyBDYXQoMTUsIDExLCAiayIpOwokZG9nICAgID0gbmV3IERvZygxLCA4LCAiRCIpOwoKJHRlc3QtPmFjcXVpcmVBbmltYWwoJG1vdXNlMSk7CiR0ZXN0LT5hY3F1aXJlQW5pbWFsKCRtb3VzZTIpOwokdGVzdC0+YWNxdWlyZUFuaW1hbCgka2l0dHkpOwokdGVzdC0+YWNxdWlyZUFuaW1hbCgka2l0dHkyKTsKJHRlc3QtPmFjcXVpcmVBbmltYWwoJGRvZyk7CiR0ZXN0LT5wcmludEZpZWxkKCk7CmVjaG8gIlxuIjsKZm9yICgkaSA9IDA7ICRpIDwgNDA7ICRpKyspIHsKICAgICR0ZXN0LT50ZXN0VGhlS2l0dHkoKTsKICAgICR0ZXN0LT5wcmludEZpZWxkKCk7CiAgICBlY2hvICJcbiI7CiAgICAKICAgIAp9