<?php
SUBWAY => 'едешь на метро' ,
FOOT => 'идешь пешком' ,
BUS => 'едешь на автобусе'
) ;
$startPoint = 'pet' ; // Петроградская
$endPoint = 'nov' ; // Новая Голландия
'pet' => 'ст. м. Петроградская' ,
'chk' => 'ст. м. Чкаловская' ,
'gor' => 'ст. м. Горьковская' ,
'spo' => 'ст. м. Спортивная' ,
'vas' => 'ст. м. Василеостровская' ,
'kre' => 'Петропавловская крепость' ,
'let' => 'Летний сад' ,
'dvo' => 'Дворцовая площадь' ,
'isa' => 'Исакиевский собор' ,
'nov' => 'Новая Голландия' ,
'ras' => 'Дом Раскольникова' ,
'gos' => 'Гостиный Двор' ,
'sen' => 'Сенная Площадь' ,
'vla' => 'ст. м. Владимирская' ,
'vit' => 'Витебский вокзал' ,
'teh' => 'Технологический Институт'
) ;
'chk' => canGet( 10 , BUS) ,
'gor' => canGet( 3 , SUBWAY)
) ,
'pet' => canGet( 10 , BUS) ,
'spo' => canGet( 3 , SUBWAY)
) ,
'pet' => canGet( 3 , BUS) ,
'kre' => canGet( 5 , FOOT) ,
'gos' => canGet( 6 , SUBWAY)
) ,
'chk' => canGet( 3 , SUBWAY) ,
'vas' => canGet( 10 , BUS) ,
'sen' => canGet( 7 , SUBWAY)
) ,
'spo' => canGet( 10 , BUS) ,
'gos' => canGet( 7 , SUBWAY) ,
'nov' => canGet( 11 , FOOT)
) ,
'gor' => canGet( 5 , FOOT)
) ,
'dvo' => canGet( 6 , FOOT) ,
'gos' => canGet( 7 , FOOT)
) ,
'isa' => canGet( 6 , FOOT) ,
'gos' => canGet( 6 , FOOT) ,
'let' => canGet( 6 , FOOT)
) ,
'dvo' => canGet( 6 , FOOT) ,
'nov' => canGet( 5 , FOOT)
) ,
'vas' => canGet( 11 , FOOT) ,
'isa' => canGet( 5 , FOOT) ,
'ras' => canGet( 7 , BUS)
) ,
'nov' => canGet( 7 , BUS) ,
'sen' => canGet( 3 , FOOT)
) ,
'vas' => canGet( 7 , SUBWAY) ,
'sen' => canGet( 3 , SUBWAY) ,
'dvo' => canGet( 6 , FOOT) ,
'gor' => canGet( 6 , SUBWAY) ,
'let' => canGet( 7 , FOOT) ,
'vla' => canGet( 7 , FOOT)
) ,
'ras' => canGet( 3 , FOOT) ,
'spo' => canGet( 7 , SUBWAY) ,
'gos' => canGet( 3 , SUBWAY) ,
'vla' => canGet( 4 , SUBWAY) ,
'vit' => canGet( 2 , SUBWAY) ,
'teh' => canGet( 3 , SUBWAY)
) ,
'sen' => canGet( 4 , SUBWAY) ,
'gos' => canGet( 7 , FOOT) ,
'vit' => canGet( 3 , SUBWAY)
) ,
'sen' => canGet( 2 , SUBWAY) ,
'teh' => canGet( 2 , SUBWAY) ,
'vla' => canGet( 3 , SUBWAY)
) ,
'sen' => canGet( 3 , SUBWAY) ,
'vit' => canGet( 2 , SUBWAY)
)
) ;
function canGet( $time , $byWhat )
{
return array ( 'time' => $time , 'by' => $byWhat ) ; }
/**
* Функция для инициализации начальных данных
*
* Функция принимает на вход начальную вершину, создает массивы для меток вершин
* и фиксирования посещения вершины, и возвращает их
*
* @global array $paths Глобальный массив вершин
* @param string $startPoint Начальная вершина
* @return array Чистый массив меток и посещений
*/
function initAlgorithm( $startPoint )
{
global $paths ;
/** Массив фиксирующий посещение метки */
/** Массив меток для вершин. Метка начальной вершины - 0, остальный - inf */
foreach ( $paths as $point => $pointValue ) {
$labels [ $point ] = PHP_INT_MAX;
$visited [ $point ] = false ;
}
$labels [ $startPoint ] = 0 ;
$result [ 'labels' ] = $labels ;
$result [ 'visited' ] = $visited ;
return $result ;
}
/**
* Функция выполняющая алгоритм Дейскры
*
* @global $paths Глобальный массив вершин
* @param array $labels Массив меток вершин
* @param array $visited Массив посещения вершин
* @return array
*/
function doAlgorithmDijstra( $labels , $visited )
{
global $paths ;
/** Количество вершин */
$countPoint = count ( $paths ) ;
for ( $i = 0 ; $i < $countPoint ; $i ++ ) {
/** Поиск вершины с наименьшей меткой */
$minLabel = PHP_INT_MAX;
/** Вершина с которой работаем в данный момент */
$workPoint = NULL ;
foreach ( $labels as $label => $value ) {
if ( ( $value < $minLabel ) && ( ! $visited [ $label ] ) ) {
$minLabel = $value ;
$workPoint = $label ;
}
}
/** Получение всех вершин, которые соединяются с текущей */
$nextPoint = $paths [ $workPoint ] ;
/** Перерасчет меток соседних вершин */
foreach ( $nextPoint as $point => $valuePoint ) {
$newLabel = $labels [ $workPoint ] + $nextPoint [ $point ] [ 'time' ] ;
if ( $labels [ $point ] > $newLabel ) {
$labels [ $point ] = $newLabel ;
}
}
/** Помечаем вершину, как посещенную */
$visited [ $workPoint ] = true ;
}
return $labels ;
}
/**
* Функция восстановления пути по массиву меток
*
* @global $paths Глобальный массив вершин
* @param string $startPoint Начальная вершина
* @param string $endPoint Конечная вершина
* @param array $labels Массив меток вершин
* @return array Искомый путь
*/
function restorationPath( $startPoint , $endPoint , $labels )
{
global $paths ;
/** Текущая вершина */
$currentPoint = $endPoint ;
$targetPath = array ( $currentPoint ) ;
while ( $currentPoint != $startPoint ) {
foreach ( $paths [ $currentPoint ] as $nextPoint => $nextPointValue ) {
if ( $labels [ $currentPoint ] - $paths [ $currentPoint ] [ $nextPoint ] [ 'time' ] == $labels [ $nextPoint ] ) {
$targetPath [ ] = $nextPoint ;
$currentPoint = $nextPoint ;
break ;
}
}
}
return $targetPath ;
}
/**
* Функция печати оптимального пути
*
* Функция принимает начальную и конечную вершину пути,
* массив меток, массив оптимального пути, и выводит последний
*
* @global $paths Глобальный массив вершин
* @global $pointNames Глобальный массив "человеческих" названий вершин
* @global $transportName Глобальны массив передвижения из точки А в точку Б
* @param string $startPoint Начальная вершина
* @param string $endPoint Конечная вершина
* @param array $targetPath Массив оптимального пути
* @param array $finalLabel Массив итоговых меток
* @return void
*/
function printTargetPath( $startPoint , $endPoint , $targetPath , $finalLabel )
{
global $paths ;
global $pointNames ;
global $transportName ;
$countTargetPoint = count ( $targetPath ) ;
echo "Начальная точка: {$pointNames [$startPoint ]}\n " ;
for ( $i = 0 ; $i < $countTargetPoint - 1 ; $i ++ ) {
/** Определение випа транспорта */
$nmtransport = $transportName [ $paths [ $targetPath [ $i ] ] [ $targetPath [ $i + 1 ] ] [ 'by' ] ] ;
echo "Из нее {$nmtransport} до точки {$pointNames [$targetPath [$i + 1]]} {$paths [$targetPath [$i ]][$targetPath [$i + 1]]['time']} минут\n " ;
}
echo "В итоге ты попадаешь в точку " . $pointNames [ $endPoint ] . " за " . $finalLabel [ $endPoint ] . " минут. Приятной поездки!" ;
}
/** Массив меток и посещений*/
$cleanLabel = initAlgorithm( $startPoint ) ;
/** Результат работы алгоритма */
$finalLabel = doAlgorithmDijstra( $cleanLabel [ 'labels' ] , $cleanLabel [ 'visited' ] ) ;
/** Оптимальный путь */
$targetPath = restorationPath( $startPoint , $endPoint , $finalLabel ) ;
printTargetPath( $startPoint , $endPoint , $targetPath , $finalLabel ) ;
?>
PD9waHAKICAgIGVycm9yX3JlcG9ydGluZygtMSk7CiAgICAKICAgIGRlZmluZSgnU1VCV0FZJywgJ3N1YicpOwogICAgZGVmaW5lKCdGT09UJywgJ2Zvb3QnKTsKICAgIGRlZmluZSgnQlVTJywgJ2J1cycpOwoKICAgICR0cmFuc3BvcnROYW1lID0gYXJyYXkoCiAgICAgICAgU1VCV0FZICA9PiAgJ9C10LTQtdGI0Ywg0L3QsCDQvNC10YLRgNC+JywKICAgICAgICBGT09UICAgID0+ICAn0LjQtNC10YjRjCDQv9C10YjQutC+0LwnLAogICAgICAgIEJVUyAgICAgPT4gICfQtdC00LXRiNGMINC90LAg0LDQstGC0L7QsdGD0YHQtScKICAgICk7CiAgICAgCiAgICAkc3RhcnRQb2ludCA9ICdwZXQnOyAvLyDQn9C10YLRgNC+0LPRgNCw0LTRgdC60LDRjwogICAgJGVuZFBvaW50ID0gJ25vdic7IC8vINCd0L7QstCw0Y8g0JPQvtC70LvQsNC90LTQuNGPCiAgICAgCiAgICAkcG9pbnROYW1lcyA9IGFycmF5KAogICAgICAgICdwZXQnICAgPT4gICfRgdGCLiDQvC4g0J/QtdGC0YDQvtCz0YDQsNC00YHQutCw0Y8nLAogICAgICAgICdjaGsnICAgPT4gICfRgdGCLiDQvC4g0KfQutCw0LvQvtCy0YHQutCw0Y8nLAogICAgICAgICdnb3InICAgPT4gICfRgdGCLiDQvC4g0JPQvtGA0YzQutC+0LLRgdC60LDRjycsCiAgICAgICAgJ3NwbycgICA9PiAgJ9GB0YIuINC8LiDQodC/0L7RgNGC0LjQstC90LDRjycsCiAgICAgICAgJ3ZhcycgICA9PiAgJ9GB0YIuINC8LiDQktCw0YHQuNC70LXQvtGB0YLRgNC+0LLRgdC60LDRjycsCiAgICAgICAgJ2tyZScgICA9PiAgJ9Cf0LXRgtGA0L7Qv9Cw0LLQu9C+0LLRgdC60LDRjyDQutGA0LXQv9C+0YHRgtGMJywKICAgICAgICAnbGV0JyAgID0+ICAn0JvQtdGC0L3QuNC5INGB0LDQtCcsCiAgICAgICAgJ2R2bycgICA9PiAgJ9CU0LLQvtGA0YbQvtCy0LDRjyDQv9C70L7RidCw0LTRjCcsCiAgICAgICAgJ2lzYScgICA9PiAgJ9CY0YHQsNC60LjQtdCy0YHQutC40Lkg0YHQvtCx0L7RgCcsCiAgICAgICAgJ25vdicgICA9PiAgJ9Cd0L7QstCw0Y8g0JPQvtC70LvQsNC90LTQuNGPJywKICAgICAgICAncmFzJyAgID0+ICAn0JTQvtC8INCg0LDRgdC60L7Qu9GM0L3QuNC60L7QstCwJywKICAgICAgICAnZ29zJyAgID0+ICAn0JPQvtGB0YLQuNC90YvQuSDQlNCy0L7RgCcsCiAgICAgICAgJ3NlbicgICA9PiAgJ9Ch0LXQvdC90LDRjyDQn9C70L7RidCw0LTRjCcsCiAgICAgICAgJ3ZsYScgICA9PiAgJ9GB0YIuINC8LiDQktC70LDQtNC40LzQuNGA0YHQutCw0Y8nLAogICAgICAgICd2aXQnICAgPT4gICfQktC40YLQtdCx0YHQutC40Lkg0LLQvtC60LfQsNC7JywKICAgICAgICAndGVoJyAgID0+ICAn0KLQtdGF0L3QvtC70L7Qs9C40YfQtdGB0LrQuNC5INCY0L3RgdGC0LjRgtGD0YInCiAgICApOwogICAgIAogICAgJHBhdGhzID0gYXJyYXkoCiAgICAgICAgJ3BldCcgICA9PiAgYXJyYXkoCiAgICAgICAgICAgICdjaGsnICAgPT4gIGNhbkdldCgxMCwgQlVTKSwKICAgICAgICAgICAgJ2dvcicgICA9PiAgY2FuR2V0KDMsIFNVQldBWSkKICAgICAgICApLAogICAgIAogICAgICAgICdjaGsnICAgPT4gIGFycmF5KAogICAgICAgICAgICAncGV0JyAgID0+ICBjYW5HZXQoMTAsIEJVUyksCiAgICAgICAgICAgICdzcG8nICAgPT4gIGNhbkdldCgzLCBTVUJXQVkpCiAgICAgICAgKSwKICAgICAKICAgICAgICAnZ29yJyAgID0+ICBhcnJheSgKICAgICAgICAgICAgJ3BldCcgICA9PiAgY2FuR2V0KDMsIEJVUyksCiAgICAgICAgICAgICdrcmUnICAgPT4gIGNhbkdldCg1LCBGT09UKSwKICAgICAgICAgICAgJ2dvcycgICA9PiAgY2FuR2V0KDYsIFNVQldBWSkKICAgICAgICApLAogICAgIAogICAgICAgICdzcG8nICAgPT4gIGFycmF5KAogICAgICAgICAgICAnY2hrJyAgID0+ICBjYW5HZXQoMywgU1VCV0FZKSwKICAgICAgICAgICAgJ3ZhcycgICA9PiAgY2FuR2V0KDEwLCBCVVMpLAogICAgICAgICAgICAnc2VuJyAgID0+ICBjYW5HZXQoNywgU1VCV0FZKQogICAgICAgICksCiAgICAgCiAgICAgICAgJ3ZhcycgICA9PiAgYXJyYXkoCiAgICAgICAgICAgICdzcG8nICAgPT4gIGNhbkdldCgxMCwgQlVTKSwKICAgICAgICAgICAgJ2dvcycgICA9PiAgY2FuR2V0KDcsIFNVQldBWSksCiAgICAgICAgICAgICdub3YnICAgPT4gIGNhbkdldCgxMSwgRk9PVCkKICAgICAgICApLAogICAgIAogICAgICAgICdrcmUnICAgPT4gIGFycmF5KAogICAgICAgICAgICAnZ29yJyAgID0+ICBjYW5HZXQoNSwgRk9PVCkKICAgICAgICApLAogICAgIAogICAgICAgICdsZXQnICAgPT4gIGFycmF5KAogICAgICAgICAgICAnZHZvJyAgID0+ICBjYW5HZXQoNiwgRk9PVCksCiAgICAgICAgICAgICdnb3MnICAgPT4gIGNhbkdldCg3LCBGT09UKQogICAgICAgICksCiAgICAgCiAgICAgICAgJ2R2bycgICA9PiAgYXJyYXkoCiAgICAgICAgICAgICdpc2EnICAgPT4gIGNhbkdldCg2LCBGT09UKSwKICAgICAgICAgICAgJ2dvcycgICA9PiAgY2FuR2V0KDYsIEZPT1QpLAogICAgICAgICAgICAnbGV0JyAgID0+ICBjYW5HZXQoNiwgRk9PVCkKICAgICAgICApLAogICAgIAogICAgICAgICdpc2EnICAgPT4gIGFycmF5KAogICAgICAgICAgICAnZHZvJyAgID0+ICBjYW5HZXQoNiwgRk9PVCksCiAgICAgICAgICAgICdub3YnICAgPT4gIGNhbkdldCg1LCBGT09UKQogICAgICAgICksCiAgICAgCiAgICAgICAgJ25vdicgICA9PiAgYXJyYXkoCiAgICAgICAgICAgICd2YXMnICAgPT4gIGNhbkdldCgxMSwgRk9PVCksCiAgICAgICAgICAgICdpc2EnICAgPT4gIGNhbkdldCg1LCBGT09UKSwKICAgICAgICAgICAgJ3JhcycgICA9PiAgY2FuR2V0KDcsIEJVUykKICAgICAgICApLAogICAgIAogICAgICAgICdyYXMnICAgPT4gIGFycmF5KAogICAgICAgICAgICAnbm92JyAgID0+ICBjYW5HZXQoNywgQlVTKSwKICAgICAgICAgICAgJ3NlbicgICA9PiAgY2FuR2V0KDMsIEZPT1QpCiAgICAgICAgKSwKICAgICAKICAgICAgICAnZ29zJyAgID0+ICBhcnJheSgKICAgICAgICAgICAgJ3ZhcycgICA9PiAgY2FuR2V0KDcsIFNVQldBWSksCiAgICAgICAgICAgICdzZW4nICAgPT4gIGNhbkdldCgzLCBTVUJXQVkpLAogICAgICAgICAgICAnZHZvJyAgID0+ICBjYW5HZXQoNiwgRk9PVCksCiAgICAgICAgICAgICdnb3InICAgPT4gIGNhbkdldCg2LCBTVUJXQVkpLAogICAgICAgICAgICAnbGV0JyAgID0+ICBjYW5HZXQoNywgRk9PVCksCiAgICAgICAgICAgICd2bGEnICAgPT4gIGNhbkdldCg3LCBGT09UKSAgICAgICAgCiAgICAgICAgKSwKICAgICAKICAgICAgICAnc2VuJyAgID0+ICBhcnJheSgKICAgICAgICAgICAgJ3JhcycgICA9PiAgY2FuR2V0KDMsIEZPT1QpLAogICAgICAgICAgICAnc3BvJyAgID0+ICBjYW5HZXQoNywgU1VCV0FZKSwKICAgICAgICAgICAgJ2dvcycgICA9PiAgY2FuR2V0KDMsIFNVQldBWSksCiAgICAgICAgICAgICd2bGEnICAgPT4gIGNhbkdldCg0LCBTVUJXQVkpLAogICAgICAgICAgICAndml0JyAgID0+ICBjYW5HZXQoMiwgU1VCV0FZKSwKICAgICAgICAgICAgJ3RlaCcgICA9PiAgY2FuR2V0KDMsIFNVQldBWSkKICAgICAgICApLAogICAgIAogICAgICAgICd2bGEnICAgPT4gIGFycmF5KAogICAgICAgICAgICAnc2VuJyAgID0+ICBjYW5HZXQoNCwgU1VCV0FZKSwKICAgICAgICAgICAgJ2dvcycgICA9PiAgY2FuR2V0KDcsIEZPT1QpLAogICAgICAgICAgICAndml0JyAgID0+ICBjYW5HZXQoMywgU1VCV0FZKQogICAgICAgICksCiAgICAgCiAgICAgICAgJ3ZpdCcgICA9PiAgYXJyYXkoCiAgICAgICAgICAgICdzZW4nICAgPT4gIGNhbkdldCgyLCBTVUJXQVkpLAogICAgICAgICAgICAndGVoJyAgID0+ICBjYW5HZXQoMiwgU1VCV0FZKSwKICAgICAgICAgICAgJ3ZsYScgICA9PiAgY2FuR2V0KDMsIFNVQldBWSkKICAgICAgICApLAogICAgIAogICAgICAgICd0ZWgnICAgPT4gIGFycmF5KAogICAgICAgICAgICAnc2VuJyAgID0+ICBjYW5HZXQoMywgU1VCV0FZKSwKICAgICAgICAgICAgJ3ZpdCcgICA9PiAgY2FuR2V0KDIsIFNVQldBWSkgICAgICAgIAogICAgICAgICkKICAgICk7CgogICAgZnVuY3Rpb24gY2FuR2V0KCR0aW1lLCAkYnlXaGF0KSAKICAgIHsKICAgICAgICByZXR1cm4gYXJyYXkoJ3RpbWUnICAgICA9PiAgJHRpbWUsICdieScgPT4gICRieVdoYXQpOwogICAgfQogICAgCiAgICAvKioKICAgICAqICDQpNGD0L3QutGG0LjRjyDQtNC70Y8g0LjQvdC40YbQuNCw0LvQuNC30LDRhtC40Lgg0L3QsNGH0LDQu9GM0L3Ri9GFINC00LDQvdC90YvRhQogICAgICogCiAgICAgKiAg0KTRg9C90LrRhtC40Y8g0L/RgNC40L3QuNC80LDQtdGCINC90LAg0LLRhdC+0LQg0L3QsNGH0LDQu9GM0L3Rg9GOINCy0LXRgNGI0LjQvdGDLCDRgdC+0LfQtNCw0LXRgiDQvNCw0YHRgdC40LLRiyDQtNC70Y8g0LzQtdGC0L7QuiDQstC10YDRiNC40L0KICAgICAqICDQuCDRhNC40LrRgdC40YDQvtCy0LDQvdC40Y8g0L/QvtGB0LXRidC10L3QuNGPINCy0LXRgNGI0LjQvdGLLCDQuCDQstC+0LfQstGA0LDRidCw0LXRgiDQuNGFCiAgICAgKgogICAgICogIEBnbG9iYWwgYXJyYXkgJHBhdGhzICAgICAg0JPQu9C+0LHQsNC70YzQvdGL0Lkg0LzQsNGB0YHQuNCyINCy0LXRgNGI0LjQvQogICAgICogIEBwYXJhbSBzdHJpbmcgJHN0YXJ0UG9pbnQg0J3QsNGH0LDQu9GM0L3QsNGPINCy0LXRgNGI0LjQvdCwCiAgICAgKiAgQHJldHVybiBhcnJheSAgICAgICAgICAgICDQp9C40YHRgtGL0Lkg0LzQsNGB0YHQuNCyINC80LXRgtC+0Log0Lgg0L/QvtGB0LXRidC10L3QuNC5CiAgICAgKi8KICAgIGZ1bmN0aW9uIGluaXRBbGdvcml0aG0oJHN0YXJ0UG9pbnQpCiAgICB7CiAgICAgICAgZ2xvYmFsICRwYXRoczsKCiAgICAgICAgLyoqINCc0LDRgdGB0LjQsiDRhNC40LrRgdC40YDRg9GO0YnQuNC5INC/0L7RgdC10YnQtdC90LjQtSDQvNC10YLQutC4ICovCiAgICAgICAgJHZpc2l0ZWQgPSBhcnJheSgpOwogICAgICAgIAogICAgICAgIC8qKiDQnNCw0YHRgdC40LIg0LzQtdGC0L7QuiDQtNC70Y8g0LLQtdGA0YjQuNC9LiDQnNC10YLQutCwINC90LDRh9Cw0LvRjNC90L7QuSDQstC10YDRiNC40L3RiyAtIDAsINC+0YHRgtCw0LvRjNC90YvQuSAtIGluZiAqLwogICAgICAgICRsYWJlbHMgPSBhcnJheSgpOwogICAgICAgIAogICAgICAgIGZvcmVhY2ggKCRwYXRocyBhcyAkcG9pbnQgPT4gJHBvaW50VmFsdWUpIHsKICAgICAgICAgICAgJGxhYmVsc1skcG9pbnRdID0gUEhQX0lOVF9NQVg7CiAgICAgICAgICAgICR2aXNpdGVkWyRwb2ludF0gPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgJGxhYmVsc1skc3RhcnRQb2ludF0gPSAwOwogICAgICAgIAogICAgICAgICRyZXN1bHQgPSBhcnJheSgpOwogICAgICAgICRyZXN1bHRbJ2xhYmVscyddID0gJGxhYmVsczsKICAgICAgICAkcmVzdWx0Wyd2aXNpdGVkJ10gPSAkdmlzaXRlZDsKICAgICAgICAKICAgICAgICByZXR1cm4gJHJlc3VsdDsKICAgIH0KICAgICAKICAgIC8qKgogICAgICogINCk0YPQvdC60YbQuNGPINCy0YvQv9C+0LvQvdGP0Y7RidCw0Y8g0LDQu9Cz0L7RgNC40YLQvCDQlNC10LnRgdC60YDRiwogICAgICoKICAgICAqICBAZ2xvYmFsICRwYXRocyAgICAgICAgICDQk9C70L7QsdCw0LvRjNC90YvQuSDQvNCw0YHRgdC40LIg0LLQtdGA0YjQuNC9CiAgICAgKiAgQHBhcmFtIGFycmF5ICRsYWJlbHMgICAg0JzQsNGB0YHQuNCyINC80LXRgtC+0Log0LLQtdGA0YjQuNC9CiAgICAgKiAgQHBhcmFtIGFycmF5ICR2aXNpdGVkICAg0JzQsNGB0YHQuNCyINC/0L7RgdC10YnQtdC90LjRjyDQstC10YDRiNC40L0KICAgICAqICBAcmV0dXJuIGFycmF5CiAgICAgKi8KICAgIGZ1bmN0aW9uIGRvQWxnb3JpdGhtRGlqc3RyYSgkbGFiZWxzLCAkdmlzaXRlZCkKICAgIHsKICAgICAgICBnbG9iYWwgJHBhdGhzOwogICAgICAgIAogICAgICAgIC8qKiDQmtC+0LvQuNGH0LXRgdGC0LLQviDQstC10YDRiNC40L0gKi8KICAgICAgICAkY291bnRQb2ludCA9IGNvdW50KCRwYXRocyk7CiAgICAgICAgCiAgICAgICAgZm9yICgkaSA9IDA7ICRpIDwgJGNvdW50UG9pbnQ7ICRpKyspIHsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8qKiDQn9C+0LjRgdC6INCy0LXRgNGI0LjQvdGLINGBINC90LDQuNC80LXQvdGM0YjQtdC5INC80LXRgtC60L7QuSAqLwogICAgICAgICAgICAkbWluTGFiZWwgPSBQSFBfSU5UX01BWDsKICAgICAgICAgICAgCiAgICAgICAgICAgIC8qKiDQktC10YDRiNC40L3QsCDRgSDQutC+0YLQvtGA0L7QuSDRgNCw0LHQvtGC0LDQtdC8INCyINC00LDQvdC90YvQuSDQvNC+0LzQtdC90YIgKi8KICAgICAgICAgICAgJHdvcmtQb2ludCA9IE5VTEw7CiAgICAgICAgICAgIAogICAgICAgICAgICBmb3JlYWNoICgkbGFiZWxzIGFzICRsYWJlbCA9PiAkdmFsdWUpIHsKICAgICAgICAgICAgICAgIGlmICgoJHZhbHVlIDwgJG1pbkxhYmVsKSAmJiAoISR2aXNpdGVkWyRsYWJlbF0pKSB7CiAgICAgICAgICAgICAgICAgICAgJG1pbkxhYmVsID0gJHZhbHVlOwogICAgICAgICAgICAgICAgICAgICR3b3JrUG9pbnQgPSAkbGFiZWw7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIC8qKiDQn9C+0LvRg9GH0LXQvdC40LUg0LLRgdC10YUg0LLQtdGA0YjQuNC9LCDQutC+0YLQvtGA0YvQtSDRgdC+0LXQtNC40L3Rj9GO0YLRgdGPINGBINGC0LXQutGD0YnQtdC5ICovCiAgICAgICAgICAgICRuZXh0UG9pbnQgPSAkcGF0aHNbJHdvcmtQb2ludF07CiAgICAgICAgICAgIAogICAgICAgICAgICAvKiog0J/QtdGA0LXRgNCw0YHRh9C10YIg0LzQtdGC0L7QuiDRgdC+0YHQtdC00L3QuNGFINCy0LXRgNGI0LjQvSAqLwogICAgICAgICAgICBmb3JlYWNoICgkbmV4dFBvaW50IGFzICRwb2ludCA9PiAkdmFsdWVQb2ludCkgewogICAgICAgICAgICAgICAgJG5ld0xhYmVsID0gJGxhYmVsc1skd29ya1BvaW50XSArICRuZXh0UG9pbnRbJHBvaW50XVsndGltZSddOwogICAgICAgICAgICAgICAgaWYgKCRsYWJlbHNbJHBvaW50XSA+ICRuZXdMYWJlbCkgewogICAgICAgICAgICAgICAgICAgICRsYWJlbHNbJHBvaW50XSA9ICRuZXdMYWJlbDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgLyoqINCf0L7QvNC10YfQsNC10Lwg0LLQtdGA0YjQuNC90YMsINC60LDQuiDQv9C+0YHQtdGJ0LXQvdC90YPRjiAqLwogICAgICAgICAgICAkdmlzaXRlZFskd29ya1BvaW50XSA9IHRydWU7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIHJldHVybiAkbGFiZWxzOwogICAgfQoKICAgIC8qKgogICAgICogINCk0YPQvdC60YbQuNGPINCy0L7RgdGB0YLQsNC90L7QstC70LXQvdC40Y8g0L/Rg9GC0Lgg0L/QviDQvNCw0YHRgdC40LLRgyDQvNC10YLQvtC6CiAgICAgKgogICAgICogIEBnbG9iYWwgJHBhdGhzICAgICAgICAgICAg0JPQu9C+0LHQsNC70YzQvdGL0Lkg0LzQsNGB0YHQuNCyINCy0LXRgNGI0LjQvQogICAgICogIEBwYXJhbSBzdHJpbmcgJHN0YXJ0UG9pbnQg0J3QsNGH0LDQu9GM0L3QsNGPINCy0LXRgNGI0LjQvdCwCiAgICAgKiAgQHBhcmFtIHN0cmluZyAkZW5kUG9pbnQgICDQmtC+0L3QtdGH0L3QsNGPINCy0LXRgNGI0LjQvdCwCiAgICAgKiAgQHBhcmFtIGFycmF5ICRsYWJlbHMgICAgICDQnNCw0YHRgdC40LIg0LzQtdGC0L7QuiDQstC10YDRiNC40L0KICAgICAqICBAcmV0dXJuIGFycmF5ICAgICAgICAgICAgINCY0YHQutC+0LzRi9C5INC/0YPRgtGMCiAgICAgKi8KICAgIGZ1bmN0aW9uIHJlc3RvcmF0aW9uUGF0aCgkc3RhcnRQb2ludCwgJGVuZFBvaW50LCAkbGFiZWxzKQogICAgewogICAgICAgIGdsb2JhbCAkcGF0aHM7CiAgICAgICAgCiAgICAgICAgLyoqINCi0LXQutGD0YnQsNGPINCy0LXRgNGI0LjQvdCwICovCiAgICAgICAgJGN1cnJlbnRQb2ludCA9ICRlbmRQb2ludDsKICAgICAgICAkdGFyZ2V0UGF0aCA9IGFycmF5KCRjdXJyZW50UG9pbnQpOwogICAgICAgIAogICAgICAgIHdoaWxlICgkY3VycmVudFBvaW50ICE9ICRzdGFydFBvaW50KSB7CiAgICAgICAgICAgIGZvcmVhY2ggKCRwYXRoc1skY3VycmVudFBvaW50XSBhcyAkbmV4dFBvaW50ID0+ICRuZXh0UG9pbnRWYWx1ZSkgewogICAgICAgICAgICAgICAgaWYgKCRsYWJlbHNbJGN1cnJlbnRQb2ludF0gLSAkcGF0aHNbJGN1cnJlbnRQb2ludF1bJG5leHRQb2ludF1bJ3RpbWUnXSA9PSAkbGFiZWxzWyRuZXh0UG9pbnRdKSB7CiAgICAgICAgICAgICAgICAgICAgJHRhcmdldFBhdGhbXSA9ICRuZXh0UG9pbnQ7CiAgICAgICAgICAgICAgICAgICAgJGN1cnJlbnRQb2ludCA9ICRuZXh0UG9pbnQ7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgJHRhcmdldFBhdGggPSBhcnJheV9yZXZlcnNlKCR0YXJnZXRQYXRoKTsKICAgICAgICByZXR1cm4gJHRhcmdldFBhdGg7CiAgICB9CiAgICAKCiAgICAvKioKICAgICAqICDQpNGD0L3QutGG0LjRjyDQv9C10YfQsNGC0Lgg0L7Qv9GC0LjQvNCw0LvRjNC90L7Qs9C+INC/0YPRgtC4CiAgICAgKgogICAgICogINCk0YPQvdC60YbQuNGPINC/0YDQuNC90LjQvNCw0LXRgiDQvdCw0YfQsNC70YzQvdGD0Y4g0Lgg0LrQvtC90LXRh9C90YPRjiDQstC10YDRiNC40L3RgyDQv9GD0YLQuCwgCiAgICAgKiAg0LzQsNGB0YHQuNCyINC80LXRgtC+0LosINC80LDRgdGB0LjQsiDQvtC/0YLQuNC80LDQu9GM0L3QvtCz0L4g0L/Rg9GC0LgsINC4INCy0YvQstC+0LTQuNGCINC/0L7RgdC70LXQtNC90LjQuQogICAgICoKICAgICAqICBAZ2xvYmFsICRwYXRocyAgICAgICAgICAgICDQk9C70L7QsdCw0LvRjNC90YvQuSDQvNCw0YHRgdC40LIg0LLQtdGA0YjQuNC9CiAgICAgKiAgQGdsb2JhbCAkcG9pbnROYW1lcyAgICAgICAg0JPQu9C+0LHQsNC70YzQvdGL0Lkg0LzQsNGB0YHQuNCyICLRh9C10LvQvtCy0LXRh9C10YHQutC40YUiINC90LDQt9Cy0LDQvdC40Lkg0LLQtdGA0YjQuNC9CiAgICAgKiAgQGdsb2JhbCAkdHJhbnNwb3J0TmFtZSAgICAg0JPQu9C+0LHQsNC70YzQvdGLINC80LDRgdGB0LjQsiDQv9C10YDQtdC00LLQuNC20LXQvdC40Y8g0LjQtyDRgtC+0YfQutC4INCQINCyINGC0L7Rh9C60YMg0JEKICAgICAqICBAcGFyYW0gc3RyaW5nICRzdGFydFBvaW50ICDQndCw0YfQsNC70YzQvdCw0Y8g0LLQtdGA0YjQuNC90LAKICAgICAqICBAcGFyYW0gc3RyaW5nICRlbmRQb2ludCAgICDQmtC+0L3QtdGH0L3QsNGPINCy0LXRgNGI0LjQvdCwCiAgICAgKiAgQHBhcmFtIGFycmF5ICR0YXJnZXRQYXRoICAg0JzQsNGB0YHQuNCyINC+0L/RgtC40LzQsNC70YzQvdC+0LPQviDQv9GD0YLQuAogICAgICogIEBwYXJhbSBhcnJheSAkZmluYWxMYWJlbCAgINCc0LDRgdGB0LjQsiDQuNGC0L7Qs9C+0LLRi9GFINC80LXRgtC+0LoKICAgICAqICBAcmV0dXJuIHZvaWQKICAgICAqLwogICAgZnVuY3Rpb24gcHJpbnRUYXJnZXRQYXRoKCRzdGFydFBvaW50LCAkZW5kUG9pbnQsICR0YXJnZXRQYXRoLCAkZmluYWxMYWJlbCkKICAgIHsKICAgICAgICBnbG9iYWwgJHBhdGhzOwogICAgICAgIGdsb2JhbCAkcG9pbnROYW1lczsKICAgICAgICBnbG9iYWwgJHRyYW5zcG9ydE5hbWU7CiAgICAgICAgCiAgICAgICAgJGNvdW50VGFyZ2V0UG9pbnQgPSBjb3VudCgkdGFyZ2V0UGF0aCk7CiAgICAKICAgICAgICBlY2hvICLQndCw0YfQsNC70YzQvdCw0Y8g0YLQvtGH0LrQsDogeyRwb2ludE5hbWVzWyRzdGFydFBvaW50XX1cbiI7CiAgICAgICAgZm9yICgkaSA9IDA7ICRpIDwgJGNvdW50VGFyZ2V0UG9pbnQgLSAxOyAkaSsrKSB7CiAgICAgICAgICAgIC8qKiDQntC/0YDQtdC00LXQu9C10L3QuNC1INCy0LjQv9CwINGC0YDQsNC90YHQv9C+0YDRgtCwICovCiAgICAgICAgICAgICRubXRyYW5zcG9ydCA9ICR0cmFuc3BvcnROYW1lWyRwYXRoc1skdGFyZ2V0UGF0aFskaV1dWyR0YXJnZXRQYXRoWyRpICsgMV1dWydieSddXTsKICAgICAgICAgICAgZWNobyAi0JjQtyDQvdC10LUgeyRubXRyYW5zcG9ydH0g0LTQviDRgtC+0YfQutC4IHskcG9pbnROYW1lc1skdGFyZ2V0UGF0aFskaSArIDFdXX0geyRwYXRoc1skdGFyZ2V0UGF0aFskaV1dWyR0YXJnZXRQYXRoWyRpICsgMV1dWyd0aW1lJ119INC80LjQvdGD0YJcbiI7CiAgICAgICAgfQogICAgICAgIGVjaG8gItCSINC40YLQvtCz0LUg0YLRiyDQv9C+0L/QsNC00LDQtdGI0Ywg0LIg0YLQvtGH0LrRgyAiIC4gJHBvaW50TmFtZXNbJGVuZFBvaW50XSAuICIg0LfQsCAiIC4gJGZpbmFsTGFiZWxbJGVuZFBvaW50XSAuICIg0LzQuNC90YPRgi4g0J/RgNC40Y/RgtC90L7QuSDQv9C+0LXQt9C00LrQuCEiIDsKICAgIH0KICAgICAgCiAgICAvKiog0JzQsNGB0YHQuNCyINC80LXRgtC+0Log0Lgg0L/QvtGB0LXRidC10L3QuNC5Ki8KICAgICRjbGVhbkxhYmVsID0gYXJyYXkoKTsKICAgICRjbGVhbkxhYmVsID0gaW5pdEFsZ29yaXRobSgkc3RhcnRQb2ludCk7CiAgICAKICAgIC8qKiDQoNC10LfRg9C70YzRgtCw0YIg0YDQsNCx0L7RgtGLINCw0LvQs9C+0YDQuNGC0LzQsCAqLwogICAgJGZpbmFsTGFiZWwgPSBhcnJheSgpOwogICAgJGZpbmFsTGFiZWwgPSAgZG9BbGdvcml0aG1EaWpzdHJhKCRjbGVhbkxhYmVsWydsYWJlbHMnXSwgJGNsZWFuTGFiZWxbJ3Zpc2l0ZWQnXSk7CiAgICAKICAgIC8qKiDQntC/0YLQuNC80LDQu9GM0L3Ri9C5INC/0YPRgtGMICovCiAgICAkdGFyZ2V0UGF0aCA9IGFycmF5KCk7CiAgICAkdGFyZ2V0UGF0aCA9IHJlc3RvcmF0aW9uUGF0aCgkc3RhcnRQb2ludCwgJGVuZFBvaW50LCAkZmluYWxMYWJlbCk7CiAgICBwcmludFRhcmdldFBhdGgoJHN0YXJ0UG9pbnQsICRlbmRQb2ludCwgJHRhcmdldFBhdGgsICRmaW5hbExhYmVsKTsKPz4=