<?php
/* http://d...content-available-to-author-only...2.net/ */
define ( 'SUBWAY' , "едешь на метро" ) ; define ( 'FOOT' , "идешь пешком" ) ; define ( 'BUS' , "едешь на автобусе" ) ;
/* Чтобы не писать много раз array('time' => ..., 'by' => ...), используем функцию.
«canGet» переводится как «можно попасть» */
function canGet( $time , $byWhat ) {
return array ( 'time' => $time , 'by' => $byWhat ) ; }
P_PET => 'ст. м. Петроградская' ,
P_CHK => 'ст. м. Чкаловская' ,
P_GOR => 'ст. м. Горьковская' ,
P_SPO => 'ст. м. Спортивная' ,
P_VAS => 'ст. м. Василеостровская' ,
P_KRE => 'Петропавловская крепость' ,
P_LET => 'Летний сад' ,
P_DVO => 'Дворцовая площадь' ,
P_ISA => 'Исакиевский собор' ,
P_NOV => 'Новая Голландия' ,
P_RAS => 'Дом Раскольникова' ,
P_GOS => 'Гостиный Двор' ,
P_SEN => 'Сенная Площадь' ,
P_VLA => 'ст. м. Владимирская' ,
P_VIT => 'Витебский вокзал' ,
P_TEH => 'Технологический Институт'
) ;
P_CHK => canGet( 10 , BUS) ,
P_GOR => canGet( 3 , SUBWAY)
) ,
P_PET => canGet( 10 , BUS) ,
P_SPO => canGet( 3 , SUBWAY)
) ,
P_PET => canGet( 3 , BUS) ,
P_KRE => canGet( 5 , FOOT) ,
P_GOS => canGet( 6 , SUBWAY)
) ,
P_CHK => canGet( 3 , SUBWAY) ,
P_VAS => canGet( 10 , BUS) ,
P_SEN => canGet( 7 , SUBWAY)
) ,
P_SPO => canGet( 10 , BUS) ,
P_GOS => canGet( 7 , SUBWAY) ,
P_NOV => canGet( 11 , FOOT)
) ,
P_GOR => canGet( 5 , FOOT)
) ,
P_DVO => canGet( 6 , FOOT) ,
P_GOS => canGet( 7 , FOOT)
) ,
P_ISA => canGet( 6 , FOOT) ,
P_GOS => canGet( 6 , FOOT) ,
P_LET => canGet( 6 , FOOT)
) ,
P_DVO => canGet( 6 , FOOT) ,
P_NOV => canGet( 5 , FOOT)
) ,
P_VAS => canGet( 11 , FOOT) ,
P_ISA => canGet( 5 , FOOT) ,
P_RAS => canGet( 7 , BUS)
) ,
P_NOV => canGet( 7 , BUS) ,
P_SEN => canGet( 3 , FOOT)
) ,
P_VAS => canGet( 7 , SUBWAY) ,
P_SEN => canGet( 3 , SUBWAY) ,
P_DVO => canGet( 6 , FOOT) ,
P_GOR => canGet( 6 , SUBWAY) ,
P_LET => canGet( 7 , FOOT) ,
P_VLA => canGet( 7 , FOOT)
) ,
P_RAS => canGet( 3 , FOOT) ,
P_SPO => canGet( 7 , SUBWAY) ,
P_GOS => canGet( 3 , SUBWAY) ,
P_VLA => canGet( 4 , SUBWAY) ,
P_VIT => canGet( 2 , SUBWAY) ,
P_TEH => canGet( 3 , SUBWAY)
) ,
P_SEN => canGet( 4 , SUBWAY) ,
P_GOS => canGet( 7 , FOOT) ,
P_VIT => canGet( 3 , SUBWAY)
) ,
P_SEN => canGet( 2 , SUBWAY) ,
P_TEH => canGet( 2 , SUBWAY) ,
P_VLA => canGet( 3 , SUBWAY)
) ,
P_SEN => canGet( 3 , SUBWAY) ,
P_VIT => canGet( 2 , SUBWAY)
)
) ;
/*Функция построения кратчайшего пути.
Возвращает NULL, если кратчайший путь не содержит промежуточных нодов.
Иначе, возвращает массив промежуточных нодов.
*/
function getPath( $start , $end , $interimStep ) {
if ( $interimStep [ $start ] [ $end ] == INF) {
return NULL ;
}
$temp = $end ;
while ( $temp != UNKNOWN) {
$temp = $interimStep [ $start ] [ $temp ] ;
}
return $shortestPath ;
}
/*
Функция вывода пути.
*/
function printPath( $startPoint , $endPoint , $shortestPath , $paths , $pointNames ) {
echo "Начальная точка: \" {$pointNames [$startPoint ]}\" \n " ;
$temp = $startPoint ;
if ( $shortestPath != NULL ) {
$temp = $startPoint ;
foreach ( $shortestPath as $node ) {
echo "Из нее {$paths [$temp ][$node ]['by']} до точки \" {$pointNames [$node ]}\" {$paths [$temp ][$node ]['time']} мин.\n " ;
$temp = $node ;
}
}
echo "Из нее {$paths [$temp ][$endPoint ]['by']} до точки \" {$pointNames [$endPoint ]}\" {$paths [$temp ][$endPoint ]['time']} мин.\n " ;
echo "В итоге ты попадешь в точку \" {$pointNames [$endPoint ]}\" за {$paths [$startPoint ][$endPoint ]['time']} мин. Приятной поездки!\n \n " ;
}
$numberOfNodes = count ( $pointNames ) ;
/*Делаем квадратную матрицу путей размера $numberOfNodes, которая будет содержать время кратчайшего пути.
Если путь не существует, то присваиваем ему значение бесконечности.
*/
foreach ( $paths as $i => $array ) {
for ( $j = 0 ; $j < $numberOfNodes ; $j ++ ) {
if ( isset ( $paths [ $i ] [ $j ] [ 'time' ] ) == NULL ) { $paths [ $i ] [ $j ] [ 'time' ] = INF;
}
}
}
//Массив, который будет содержать предпоследний шаг кратчайшего пути.
for ( $i = 0 ; $i < $numberOfNodes ; $i ++ ) {
$interimStep [ $i ] = array_fill ( 0 , $numberOfNodes , UNKNOWN
) ; }
//Алгоритм Флойда-Уоршелла.
for ( $k = 0 ; $k < $numberOfNodes ; $k ++ ) {
for ( $i = 0 ; $i < $numberOfNodes ; $i ++ ) {
for ( $j = 0 ; $j < $numberOfNodes ; $j ++ ) {
if ( ( $paths [ $i ] [ $k ] [ 'time' ] + $paths [ $k ] [ $j ] [ 'time' ] ) < $paths [ $i ] [ $j ] [ 'time' ] ) {
$paths [ $i ] [ $j ] [ 'time' ] = $paths [ $i ] [ $k ] [ 'time' ] + $paths [ $k ] [ $j ] [ 'time' ] ;
$interimStep [ $i ] [ $j ] = $k ;
}
}
}
}
//Тут вылетает предпоследняя нода (дом Раскольникова), но время всего пути выводится корректно.
$startPoint = 0 ; // Петроградская
$endPoint = 9 ; // Новая Голландия
$shortestPath = getPath( $startPoint , $endPoint , $interimStep ) ;
printPath( $startPoint , $endPoint , $shortestPath , $paths , $pointNames ) ;
//Сенная Площадь -> Новая Голландия
//Тут все выводится корректно.
$startPoint = 12 ;
$endPoint = 9 ;
$shortestPath = getPath( $startPoint , $endPoint , $interimStep ) ;
printPath( $startPoint , $endPoint , $shortestPath , $paths , $pointNames ) ;
$startPoint = P_VIT;
$endPoint = P_NOV;
$shortestPath = getPath( $startPoint , $endPoint , $interimStep ) ;
printPath( $startPoint , $endPoint , $shortestPath , $paths , $pointNames ) ;
$startPoint = P_TEH;
$endPoint = P_NOV;
$shortestPath = getPath( $startPoint , $endPoint , $interimStep ) ;
printPath( $startPoint , $endPoint , $shortestPath , $paths , $pointNames ) ;
PD9waHAKIAplcnJvcl9yZXBvcnRpbmcoLTEpOwovKiBodHRwOi8vZC4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uMi5uZXQvICovCiAKZGVmaW5lKCdTVUJXQVknLCAi0LXQtNC10YjRjCDQvdCwINC80LXRgtGA0L4iKTsKZGVmaW5lKCdGT09UJywgItC40LTQtdGI0Ywg0L/QtdGI0LrQvtC8Iik7CmRlZmluZSgnQlVTJywgItC10LTQtdGI0Ywg0L3QsCDQsNCy0YLQvtCx0YPRgdC1Iik7CgpkZWZpbmUoJ1BfUEVUJywgMCk7CmRlZmluZSgnUF9DSEsnLCAxKTsKZGVmaW5lKCdQX0dPUicsIDIpOwpkZWZpbmUoJ1BfU1BPJywgMyk7CmRlZmluZSgnUF9WQVMnLCA0KTsKZGVmaW5lKCdQX0tSRScsIDUpOwpkZWZpbmUoJ1BfTEVUJywgNik7CmRlZmluZSgnUF9EVk8nLCA3KTsKZGVmaW5lKCdQX0lTQScsIDgpOwpkZWZpbmUoJ1BfTk9WJywgOSk7CmRlZmluZSgnUF9SQVMnLCAxMCk7CmRlZmluZSgnUF9HT1MnLCAxMSk7CmRlZmluZSgnUF9TRU4nLCAxMik7CmRlZmluZSgnUF9WTEEnLCAxMyk7CmRlZmluZSgnUF9WSVQnLCAxNCk7CmRlZmluZSgnUF9URUgnLCAxNSk7CgpkZWZpbmUoJ1VOS05PV04nLCAtMSk7CgovKiDQp9GC0L7QsdGLINC90LUg0L/QuNGB0LDRgtGMINC80L3QvtCz0L4g0YDQsNC3IGFycmF5KCd0aW1lJyA9PiAuLi4sICdieScgPT4gLi4uKSwg0LjRgdC/0L7Qu9GM0LfRg9C10Lwg0YTRg9C90LrRhtC40Y4uIAogICAgwqtjYW5HZXTCuyDQv9C10YDQtdCy0L7QtNC40YLRgdGPINC60LDQuiDCq9C80L7QttC90L4g0L/QvtC/0LDRgdGC0YzCuyAqLwpmdW5jdGlvbiBjYW5HZXQoJHRpbWUsICRieVdoYXQpIHsKICAgIHJldHVybiBhcnJheSgndGltZScgICAgID0+ICAkdGltZSwgJ2J5JyA9PiAgJGJ5V2hhdCk7Cn0KCiRwb2ludE5hbWVzID0gYXJyYXkoCiAgICBQX1BFVCAgID0+ICAn0YHRgi4g0LwuINCf0LXRgtGA0L7Qs9GA0LDQtNGB0LrQsNGPJywKICAgIFBfQ0hLICAgPT4gICfRgdGCLiDQvC4g0KfQutCw0LvQvtCy0YHQutCw0Y8nLAogICAgUF9HT1IgICA9PiAgJ9GB0YIuINC8LiDQk9C+0YDRjNC60L7QstGB0LrQsNGPJywKICAgIFBfU1BPICAgPT4gICfRgdGCLiDQvC4g0KHQv9C+0YDRgtC40LLQvdCw0Y8nLAogICAgUF9WQVMgICA9PiAgJ9GB0YIuINC8LiDQktCw0YHQuNC70LXQvtGB0YLRgNC+0LLRgdC60LDRjycsCiAgICBQX0tSRSAgID0+ICAn0J/QtdGC0YDQvtC/0LDQstC70L7QstGB0LrQsNGPINC60YDQtdC/0L7RgdGC0YwnLAogICAgUF9MRVQgICA9PiAgJ9Cb0LXRgtC90LjQuSDRgdCw0LQnLAogICAgUF9EVk8gICA9PiAgJ9CU0LLQvtGA0YbQvtCy0LDRjyDQv9C70L7RidCw0LTRjCcsCiAgICBQX0lTQSAgID0+ICAn0JjRgdCw0LrQuNC10LLRgdC60LjQuSDRgdC+0LHQvtGAJywKICAgIFBfTk9WICAgPT4gICfQndC+0LLQsNGPINCT0L7Qu9C70LDQvdC00LjRjycsCiAgICBQX1JBUyAgID0+ICAn0JTQvtC8INCg0LDRgdC60L7Qu9GM0L3QuNC60L7QstCwJywKICAgIFBfR09TICAgPT4gICfQk9C+0YHRgtC40L3Ri9C5INCU0LLQvtGAJywKICAgIFBfU0VOICAgPT4gICfQodC10L3QvdCw0Y8g0J/Qu9C+0YnQsNC00YwnLAogICAgUF9WTEEgICA9PiAgJ9GB0YIuINC8LiDQktC70LDQtNC40LzQuNGA0YHQutCw0Y8nLAogICAgUF9WSVQgICA9PiAgJ9CS0LjRgtC10LHRgdC60LjQuSDQstC+0LrQt9Cw0LsnLAogICAgUF9URUggICA9PiAgJ9Ci0LXRhdC90L7Qu9C+0LPQuNGH0LXRgdC60LjQuSDQmNC90YHRgtC40YLRg9GCJwopOwoKJHBhdGhzID0gYXJyYXkoCiAgICBQX1BFVCAgID0+ICBhcnJheSgKICAgICAgICBQX0NISyAgID0+ICBjYW5HZXQoMTAsIEJVUyksCiAgICAgICAgUF9HT1IgICA9PiAgY2FuR2V0KDMsIFNVQldBWSkKICAgICksCiAKICAgIFBfQ0hLICAgPT4gIGFycmF5KAogICAgICAgIFBfUEVUICAgPT4gIGNhbkdldCgxMCwgQlVTKSwKICAgICAgICBQX1NQTyAgID0+ICBjYW5HZXQoMywgU1VCV0FZKQogICAgKSwKIAogICAgUF9HT1IgICA9PiAgYXJyYXkoCiAgICAgICAgUF9QRVQgICA9PiAgY2FuR2V0KDMsIEJVUyksCiAgICAgICAgUF9LUkUgICA9PiAgY2FuR2V0KDUsIEZPT1QpLAogICAgICAgIFBfR09TICAgPT4gIGNhbkdldCg2LCBTVUJXQVkpCiAgICApLAogCiAgICBQX1NQTyAgID0+ICBhcnJheSgKICAgICAgICBQX0NISyAgID0+ICBjYW5HZXQoMywgU1VCV0FZKSwKICAgICAgICBQX1ZBUyAgID0+ICBjYW5HZXQoMTAsIEJVUyksCiAgICAgICAgUF9TRU4gICA9PiAgY2FuR2V0KDcsIFNVQldBWSkKICAgICksCiAKICAgIFBfVkFTICAgPT4gIGFycmF5KAogICAgICAgIFBfU1BPICAgPT4gIGNhbkdldCgxMCwgQlVTKSwKICAgICAgICBQX0dPUyAgID0+ICBjYW5HZXQoNywgU1VCV0FZKSwKICAgICAgICBQX05PViAgID0+ICBjYW5HZXQoMTEsIEZPT1QpCiAgICApLAogCiAgICBQX0tSRSAgID0+ICBhcnJheSgKICAgICAgICBQX0dPUiAgID0+ICBjYW5HZXQoNSwgRk9PVCkKICAgICksCiAKICAgIFBfTEVUICAgPT4gIGFycmF5KAogICAgICAgIFBfRFZPICAgPT4gIGNhbkdldCg2LCBGT09UKSwKICAgICAgICBQX0dPUyAgID0+ICBjYW5HZXQoNywgRk9PVCkKICAgICksCiAKICAgIFBfRFZPICAgPT4gIGFycmF5KAogICAgICAgIFBfSVNBICAgPT4gIGNhbkdldCg2LCBGT09UKSwKICAgICAgICBQX0dPUyAgID0+ICBjYW5HZXQoNiwgRk9PVCksCiAgICAgICAgUF9MRVQgICA9PiAgY2FuR2V0KDYsIEZPT1QpCiAgICApLAogCiAgICBQX0lTQSAgID0+ICBhcnJheSgKICAgICAgICBQX0RWTyAgID0+ICBjYW5HZXQoNiwgRk9PVCksCiAgICAgICAgUF9OT1YgICA9PiAgY2FuR2V0KDUsIEZPT1QpCiAgICApLAogCiAgICBQX05PViAgID0+ICBhcnJheSgKICAgICAgICBQX1ZBUyAgID0+ICBjYW5HZXQoMTEsIEZPT1QpLAogICAgICAgIFBfSVNBICAgPT4gIGNhbkdldCg1LCBGT09UKSwKICAgICAgICBQX1JBUyAgID0+ICBjYW5HZXQoNywgQlVTKQogICAgKSwKIAogICAgUF9SQVMgICA9PiAgYXJyYXkoCiAgICAgICAgUF9OT1YgICA9PiAgY2FuR2V0KDcsIEJVUyksCiAgICAgICAgUF9TRU4gICA9PiAgY2FuR2V0KDMsIEZPT1QpCiAgICApLAogCiAgICBQX0dPUyAgID0+ICBhcnJheSgKICAgICAgICBQX1ZBUyAgID0+ICBjYW5HZXQoNywgU1VCV0FZKSwKICAgICAgICBQX1NFTiAgID0+ICBjYW5HZXQoMywgU1VCV0FZKSwKICAgICAgICBQX0RWTyAgID0+ICBjYW5HZXQoNiwgRk9PVCksCiAgICAgICAgUF9HT1IgICA9PiAgY2FuR2V0KDYsIFNVQldBWSksCiAgICAgICAgUF9MRVQgICA9PiAgY2FuR2V0KDcsIEZPT1QpLAogICAgICAgIFBfVkxBICAgPT4gIGNhbkdldCg3LCBGT09UKSAgICAgICAgCiAgICApLAogCiAgICBQX1NFTiAgID0+ICBhcnJheSgKICAgICAgICBQX1JBUyAgID0+ICBjYW5HZXQoMywgRk9PVCksCiAgICAgICAgUF9TUE8gICA9PiAgY2FuR2V0KDcsIFNVQldBWSksCiAgICAgICAgUF9HT1MgICA9PiAgY2FuR2V0KDMsIFNVQldBWSksCiAgICAgICAgUF9WTEEgICA9PiAgY2FuR2V0KDQsIFNVQldBWSksCiAgICAgICAgUF9WSVQgICA9PiAgY2FuR2V0KDIsIFNVQldBWSksCiAgICAgICAgUF9URUggICA9PiAgY2FuR2V0KDMsIFNVQldBWSkKICAgICksCiAKICAgIFBfVkxBICAgPT4gIGFycmF5KAogICAgICAgIFBfU0VOICAgPT4gIGNhbkdldCg0LCBTVUJXQVkpLAogICAgICAgIFBfR09TICAgPT4gIGNhbkdldCg3LCBGT09UKSwKICAgICAgICBQX1ZJVCAgID0+ICBjYW5HZXQoMywgU1VCV0FZKQogICAgKSwKIAogICAgUF9WSVQgICA9PiAgYXJyYXkoCiAgICAgICAgUF9TRU4gICA9PiAgY2FuR2V0KDIsIFNVQldBWSksCiAgICAgICAgUF9URUggICA9PiAgY2FuR2V0KDIsIFNVQldBWSksCiAgICAgICAgUF9WTEEgICA9PiAgY2FuR2V0KDMsIFNVQldBWSkKICAgICksCiAKICAgIFBfVEVIICAgPT4gIGFycmF5KAogICAgICAgIFBfU0VOICAgPT4gIGNhbkdldCgzLCBTVUJXQVkpLAogICAgICAgIFBfVklUICAgPT4gIGNhbkdldCgyLCBTVUJXQVkpICAgICAgICAKICAgICkKKTsKIAoKLyrQpNGD0L3QutGG0LjRjyDQv9C+0YHRgtGA0L7QtdC90LjRjyDQutGA0LDRgtGH0LDQudGI0LXQs9C+INC/0YPRgtC4LgrQktC+0LfQstGA0LDRidCw0LXRgiBOVUxMLCDQtdGB0LvQuCDQutGA0LDRgtGH0LDQudGI0LjQuSDQv9GD0YLRjCDQvdC1INGB0L7QtNC10YDQttC40YIg0L/RgNC+0LzQtdC20YPRgtC+0YfQvdGL0YUg0L3QvtC00L7Qsi4K0JjQvdCw0YfQtSwg0LLQvtC30LLRgNCw0YnQsNC10YIg0LzQsNGB0YHQuNCyINC/0YDQvtC80LXQttGD0YLQvtGH0L3Ri9GFINC90L7QtNC+0LIuCiovCmZ1bmN0aW9uIGdldFBhdGgoJHN0YXJ0LCAkZW5kLCAkaW50ZXJpbVN0ZXApewogICAgaWYgKCRpbnRlcmltU3RlcFskc3RhcnRdWyRlbmRdID09IElORikgewogICAgICAgIHJldHVybiBOVUxMOwogICAgfQogICAgJHNob3J0ZXN0UGF0aCA9IGFycmF5KCk7CiAgICAkdGVtcCA9ICRlbmQ7CiAgICB3aGlsZSAoJHRlbXAgIT0gVU5LTk9XTikgewogICAgICAgICR0ZW1wID0gJGludGVyaW1TdGVwWyRzdGFydF1bJHRlbXBdOwogICAgICAgIGFycmF5X3Vuc2hpZnQoJHNob3J0ZXN0UGF0aCwgJHRlbXApOwogICAgfQogICAgdW5zZXQoJHNob3J0ZXN0UGF0aFswXSk7CiAgICByZXR1cm4gJHNob3J0ZXN0UGF0aDsKfQoKLyoK0KTRg9C90LrRhtC40Y8g0LLRi9Cy0L7QtNCwINC/0YPRgtC4LgoqLwpmdW5jdGlvbiBwcmludFBhdGgoJHN0YXJ0UG9pbnQsICRlbmRQb2ludCwgJHNob3J0ZXN0UGF0aCwgJHBhdGhzLCAkcG9pbnROYW1lcyl7CiAgICBlY2hvICLQndCw0YfQsNC70YzQvdCw0Y8g0YLQvtGH0LrQsDogXCJ7JHBvaW50TmFtZXNbJHN0YXJ0UG9pbnRdfVwiXG4iOwogICAgJHRlbXAgPSAkc3RhcnRQb2ludDsKICAgIGlmICgkc2hvcnRlc3RQYXRoICE9IE5VTEwpIHsKICAgICAgICAkdGVtcCA9ICRzdGFydFBvaW50OwogICAgICAgIGZvcmVhY2ggKCRzaG9ydGVzdFBhdGggYXMgJG5vZGUpIHsKICAgICAgICAgICAgZWNobyAi0JjQtyDQvdC10LUgeyRwYXRoc1skdGVtcF1bJG5vZGVdWydieSddfSDQtNC+INGC0L7Rh9C60LggXCJ7JHBvaW50TmFtZXNbJG5vZGVdfVwiIHskcGF0aHNbJHRlbXBdWyRub2RlXVsndGltZSddfSDQvNC40L0uXG4iOwogICAgICAgICAgICAkdGVtcCA9ICRub2RlOwogICAgICAgIH0KICAgIH0KICAgIGVjaG8gItCY0Lcg0L3QtdC1IHskcGF0aHNbJHRlbXBdWyRlbmRQb2ludF1bJ2J5J119INC00L4g0YLQvtGH0LrQuCBcInskcG9pbnROYW1lc1skZW5kUG9pbnRdfVwiIHskcGF0aHNbJHRlbXBdWyRlbmRQb2ludF1bJ3RpbWUnXX0g0LzQuNC9LlxuIjsKICAgIGVjaG8gItCSINC40YLQvtCz0LUg0YLRiyDQv9C+0L/QsNC00LXRiNGMINCyINGC0L7Rh9C60YMgXCJ7JHBvaW50TmFtZXNbJGVuZFBvaW50XX1cIiDQt9CwIHskcGF0aHNbJHN0YXJ0UG9pbnRdWyRlbmRQb2ludF1bJ3RpbWUnXX0g0LzQuNC9LiDQn9GA0LjRj9GC0L3QvtC5INC/0L7QtdC30LTQutC4IVxuXG4iOwp9CgokbnVtYmVyT2ZOb2RlcyA9IGNvdW50KCRwb2ludE5hbWVzKTsKCi8q0JTQtdC70LDQtdC8INC60LLQsNC00YDQsNGC0L3Rg9GOINC80LDRgtGA0LjRhtGDINC/0YPRgtC10Lkg0YDQsNC30LzQtdGA0LAgJG51bWJlck9mTm9kZXMsINC60L7RgtC+0YDQsNGPINCx0YPQtNC10YIg0YHQvtC00LXRgNC20LDRgtGMINCy0YDQtdC80Y8g0LrRgNCw0YLRh9Cw0LnRiNC10LPQviDQv9GD0YLQuC4K0JXRgdC70Lgg0L/Rg9GC0Ywg0L3QtSDRgdGD0YnQtdGB0YLQstGD0LXRgiwg0YLQviDQv9GA0LjRgdCy0LDQuNCy0LDQtdC8INC10LzRgyDQt9C90LDRh9C10L3QuNC1INCx0LXRgdC60L7QvdC10YfQvdC+0YHRgtC4LgoqLwpmb3JlYWNoICgkcGF0aHMgYXMgJGkgPT4gJGFycmF5KSB7CiAgICBmb3IgKCRqID0gMDsgJGogPCAkbnVtYmVyT2ZOb2RlczsgJGorKykgewogICAgICAgIGlmIChpc3NldCgkcGF0aHNbJGldWyRqXVsndGltZSddKSA9PSBOVUxMKSB7CiAgICAgICAgICAgICRwYXRoc1skaV1bJGpdWyd0aW1lJ10gPSBJTkY7CiAgICAgICAgfQogICAgfQp9CgovL9Cc0LDRgdGB0LjQsiwg0LrQvtGC0L7RgNGL0Lkg0LHRg9C00LXRgiDRgdC+0LTQtdGA0LbQsNGC0Ywg0L/RgNC10LTQv9C+0YHQu9C10LTQvdC40Lkg0YjQsNCzINC60YDQsNGC0YfQsNC50YjQtdCz0L4g0L/Rg9GC0LguCiRpbnRlcmltU3RlcCA9IGFycmF5KCk7CmZvciAoJGkgPSAwOyAkaSA8ICRudW1iZXJPZk5vZGVzOyAkaSsrKSB7CiAgICAkaW50ZXJpbVN0ZXBbJGldID0gYXJyYXlfZmlsbCgwLCAkbnVtYmVyT2ZOb2RlcywgVU5LTk9XTik7Cn0KCi8v0JDQu9Cz0L7RgNC40YLQvCDQpNC70L7QudC00LAt0KPQvtGA0YjQtdC70LvQsC4KZm9yICgkayA9IDA7ICRrIDwgJG51bWJlck9mTm9kZXM7ICRrKyspIHsKICAgIGZvciAoJGkgPSAwOyAkaSA8ICRudW1iZXJPZk5vZGVzOyAkaSsrKSB7CiAgICAgICAgZm9yICgkaiA9IDA7ICRqIDwgJG51bWJlck9mTm9kZXM7ICRqKyspIHsKICAgICAgICAgICAgaWYgKCgkcGF0aHNbJGldWyRrXVsndGltZSddICsgJHBhdGhzWyRrXVskal1bJ3RpbWUnXSkgPCAkcGF0aHNbJGldWyRqXVsndGltZSddKSB7CiAgICAgICAgICAgICAgICAkcGF0aHNbJGldWyRqXVsndGltZSddID0gJHBhdGhzWyRpXVska11bJ3RpbWUnXSArICRwYXRoc1ska11bJGpdWyd0aW1lJ107CiAgICAgICAgICAgICAgICAkaW50ZXJpbVN0ZXBbJGldWyRqXSA9ICRrOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CgovL9Ci0YPRgiDQstGL0LvQtdGC0LDQtdGCINC/0YDQtdC00L/QvtGB0LvQtdC00L3Rj9GPINC90L7QtNCwICjQtNC+0Lwg0KDQsNGB0LrQvtC70YzQvdC40LrQvtCy0LApLCDQvdC+INCy0YDQtdC80Y8g0LLRgdC10LPQviDQv9GD0YLQuCDQstGL0LLQvtC00LjRgtGB0Y8g0LrQvtGA0YDQtdC60YLQvdC+Lgokc3RhcnRQb2ludCA9IDA7IC8vINCf0LXRgtGA0L7Qs9GA0LDQtNGB0LrQsNGPCiRlbmRQb2ludCA9IDk7IC8vINCd0L7QstCw0Y8g0JPQvtC70LvQsNC90LTQuNGPCiRzaG9ydGVzdFBhdGggPSBnZXRQYXRoKCRzdGFydFBvaW50LCAkZW5kUG9pbnQsICRpbnRlcmltU3RlcCk7CnByaW50UGF0aCgkc3RhcnRQb2ludCwgJGVuZFBvaW50LCAkc2hvcnRlc3RQYXRoLCAkcGF0aHMsICRwb2ludE5hbWVzKTsKCi8v0KHQtdC90L3QsNGPINCf0LvQvtGJ0LDQtNGMIC0+INCd0L7QstCw0Y8g0JPQvtC70LvQsNC90LTQuNGPCi8v0KLRg9GCINCy0YHQtSDQstGL0LLQvtC00LjRgtGB0Y8g0LrQvtGA0YDQtdC60YLQvdC+Lgokc3RhcnRQb2ludCA9IDEyOwokZW5kUG9pbnQgPSA5Owokc2hvcnRlc3RQYXRoID0gZ2V0UGF0aCgkc3RhcnRQb2ludCwgJGVuZFBvaW50LCAkaW50ZXJpbVN0ZXApOwpwcmludFBhdGgoJHN0YXJ0UG9pbnQsICRlbmRQb2ludCwgJHNob3J0ZXN0UGF0aCwgJHBhdGhzLCAkcG9pbnROYW1lcyk7Cgokc3RhcnRQb2ludCA9IFBfVklUOwokZW5kUG9pbnQgPSBQX05PVjsKJHNob3J0ZXN0UGF0aCA9IGdldFBhdGgoJHN0YXJ0UG9pbnQsICRlbmRQb2ludCwgJGludGVyaW1TdGVwKTsKcHJpbnRQYXRoKCRzdGFydFBvaW50LCAkZW5kUG9pbnQsICRzaG9ydGVzdFBhdGgsICRwYXRocywgJHBvaW50TmFtZXMpOwoKJHN0YXJ0UG9pbnQgPSBQX1RFSDsKJGVuZFBvaW50ID0gUF9OT1Y7CiRzaG9ydGVzdFBhdGggPSBnZXRQYXRoKCRzdGFydFBvaW50LCAkZW5kUG9pbnQsICRpbnRlcmltU3RlcCk7CnByaW50UGF0aCgkc3RhcnRQb2ludCwgJGVuZFBvaW50LCAkc2hvcnRlc3RQYXRoLCAkcGF0aHMsICRwb2ludE5hbWVzKTsK