<?php
//Топ N самых часто встречающихся слов и словосочетаний в тексте(из 2-3-х слов)
$stopWords = array ( 'и' , 'у' , 'к' , 'с' , 'о' , 'от' , 'в' , 'же' , 'из' , 'на' ) ; $input = 'Недавно написал свой велосипед и выложил его на хабре. Вот он:
«Простейший Connection pool без DataSource в Java». Статья не из самых удачных,
только прошу больше не минусовать. Итак, чтобы не повторять такие ошибки самому и,
возможно, предостеречь кого-то от таких ошибок, решил перевести статью «Seven Things
You Should Never Code Yourself» достаточно известного в среде open-source деятеля
IT-области — Andy Lester\'а. Итак, кому интересно, прошу под кат.
Мы, программисты, любим решать задачи. Мы любим, когда идеи возникают в наших
головах, перенаправляются на наши пальцы и тем самым создаются великолепные решения.
Но порой мы слишком быстро вскакиваем и начинаем проворачивать свой код без
учета всех последствий, к которым это может привести. Мы не учитываем, что
кто-то, возможно, уже решил эту проблему, и что уже есть код, доступный для
использования, который был написан, протестирован и продебажен кем-то другим.
Иногда нам просто необходимо остановиться и подумать, прежде чем начать что-то
печатать.
Например, если вы столкнетесь с одной из этих семи задач программирования,
то почти всегда вам лучше поискать существующее решение, чем пытаться реализовывать
что-то самостоятельно:
1. Парсинг HTML или XML
Задачей, сложностью которой зачастую пренебрегают, по крайней мере на основе того,
сколько раз про него спросили на StackOverflow — является парсинг HTML или XML.
Извлечение данных из произвольного HTML выглядит обманчиво просто, но на самом деле
эта задача должна решаться применением библиотек. Скажем, вы хотите извлечь URL из
тега такого, как
К тому времени, как вы сделаете еще один цикл в поисках случаев, с которыми
ваш код не может иметь дело, при этом исправляя и тестируя свой код, вы бы могли уже
использовать нужную библиотеку и решили бы все свои проблемы.
Я вам привел наглядную историю с примерами: вы потратите намного меньше времени на
поиски существующей библиотеки и на ее изучение, нежели на попытки написать свой
велосипед, который затем придется расширять, чтобы он работал в тех случаях, о
которых вы и не думали, когда начинали его писать.
2. Парсинг CSV и JSON
CSV файлы обманчиво просты, но таят в себе некую опасность. Файлы с величинами,
разделенными запятыми тривиальны для парсинга, не так ли?
# ID, name, city
1, Queen Elizabeth II, London
Безусловно, пока вам не придется иметь дело с запятыми, заключенными в двойные
кавычки:
Вы можете справиться и с этим, пока не придется иметь дело с переводами строк в
середине записи.
JSON имеет те же самые опасности, связанные с типами данных, что и CSV, с дополнительной
проблемой, возникающей из-за возможности хранить многоуровневые структуры данных.
Уберегите себя от хлопот и неточностей. Любые данные, которые не могут быть обработаны
разделением строки по запятым должны быть обработаны библиотекой.
Если читать структурированные данные неструктурированным методом это плохая идея,
то идея изменять данные на месте еще хуже. Люди часто говорят что-то вроде
«Я хочу изменить все теги с такими-то и такими URL так, чтобы у них появивлся
новый атрибут.» Но даже такое, казалось бы, простое дело, как «Я хочу изменить
в каждом пятом поле в этом CSV имя Боб на Стив» таит в себе опасность, потому что,
как было отмечено выше, вы не сможете считывать запятые должным образом. Чтобы все
было правильно, вам необходимо прочитать данные с помощью грамотной библиотеки во
внутреннюю структуру, изменить данные, а затем записать измененные данные обратно
с помощью той же библиотеки. Ничто не представляет такой риск искажения данных,
как если их структура не соответствует вашим ожиданиям.
' ;
//Функция удаляющая слова и словосочетания являющиеся частью больших словосочений
function removeRepetition( $moreWords , $words )
{
foreach ( $moreWords as $moreWord => $moreCount ) {
foreach ( $words as $word => $count ) {
//если во втором массиве словосочетания, иначе слова
if ( ( mb_strpos ( $moreWord , $word ) !== false ) && ( $count == $moreCount ) ) { }
} else {
$severalWords = explode ( ' ' , $moreWord ) ; if ( ( count ( $matches ) != 0 ) && ( $moreCount == $count ) ) { }
}
}
}
return $words ;
}
//Удаляем лишнее - переносы, запятые, стоп слова.
foreach ( $stopWords as $word ) {
}
$sentences = preg_split ( '/\./' , $input , 0 , PREG_SPLIT_NO_EMPTY
) ;
//Формируем словосочетания
foreach ( $sentences as $sentence ) {
$words = preg_split ( '/ /' , $sentence , 0 , PREG_SPLIT_NO_EMPTY
) ; foreach ( $words as $key => $word ) {
$oneWords [ ] = $word ;
//Прерываем цикл на последнем слове.
if ( $key == ( count ( $words ) - 1 ) ) { break ;
}
$twoWords [ ] = $word . ' ' . $words [ $key + 1 ] ;
if ( $key !== 0 ) {
$threeWords [ ] = $words [ $key - 1 ] . ' ' . $word . ' ' . $words [ $key + 1 ] ;
}
}
}
//Считаем, удаляем все что было найдено 1 раз и сортируем
arsort ( $countWords , SORT_NUMERIC
) ; arsort ( $countTwoWords , SORT_NUMERIC
) ; arsort ( $countThreeWords , SORT_NUMERIC
) ;
//Удаляем слова и словосочеания являющиеся часть других
$countWords = removeRepetition( $countThreeWords , $countWords ) ;
$countWords = removeRepetition( $countTwoWords , $countWords ) ;
$countTwoWords = removeRepetition( $countThreeWords , $countTwoWords ) ;
$top = array_merge ( $countWords , $countTwoWords , $countThreeWords ) ;
//Выводим результат нашей магии
if ( $top == '' ) {
echo 'Увы, но в данном тексте нет частых слов или словосочетаний встречающихся больше одного раза :(' ;
} elseif ( count ( $top ) == 1 ) { foreach ( $top as $words => $count ) {
echo 'Самое частое слово/словосочетание: "' . $words . '", оно встречается - ' . $count .
' раз.' ;
}
} else {
echo "Самые частые слова/словосочетания:\n " ;
foreach ( $top as $words => $count ) {
echo $words . " - встречается " . $count . " раз.\n " ;
}
}
PD9waHAKLy/QotC+0L8gTiDRgdCw0LzRi9GFINGH0LDRgdGC0L4g0LLRgdGC0YDQtdGH0LDRjtGJ0LjRhdGB0Y8g0YHQu9C+0LIg0Lgg0YHQu9C+0LLQvtGB0L7Rh9C10YLQsNC90LjQuSDQsiDRgtC10LrRgdGC0LUo0LjQtyAyLTMt0YUg0YHQu9C+0LIpCm1iX2ludGVybmFsX2VuY29kaW5nKCdVdGYtOCcpOwoKJHN0b3BXb3JkcyA9IGFycmF5KCfQuCcsICfRgycsICfQuicsICfRgScsICfQvicsICfQvtGCJywgJ9CyJywgJ9C20LUnLCAn0LjQtycsICfQvdCwJyk7CiRpbnB1dCA9ICfQndC10LTQsNCy0L3QviDQvdCw0L/QuNGB0LDQuyDRgdCy0L7QuSDQstC10LvQvtGB0LjQv9C10LQg0Lgg0LLRi9C70L7QttC40Lsg0LXQs9C+INC90LAg0YXQsNCx0YDQtS4g0JLQvtGCINC+0L06IAoJwqvQn9GA0L7RgdGC0LXQudGI0LjQuSBDb25uZWN0aW9uIHBvb2wg0LHQtdC3IERhdGFTb3VyY2Ug0LIgSmF2YcK7LiDQodGC0LDRgtGM0Y8g0L3QtSDQuNC3INGB0LDQvNGL0YUg0YPQtNCw0YfQvdGL0YUsIAoJ0YLQvtC70YzQutC+INC/0YDQvtGI0YMg0LHQvtC70YzRiNC1INC90LUg0LzQuNC90YPRgdC+0LLQsNGC0YwuINCY0YLQsNC6LCDRh9GC0L7QsdGLINC90LUg0L/QvtCy0YLQvtGA0Y/RgtGMINGC0LDQutC40LUg0L7RiNC40LHQutC4INGB0LDQvNC+0LzRgyDQuCwKCdCy0L7Qt9C80L7QttC90L4sINC/0YDQtdC00L7RgdGC0LXRgNC10YfRjCDQutC+0LPQvi3RgtC+INC+0YIg0YLQsNC60LjRhSDQvtGI0LjQsdC+0LosINGA0LXRiNC40Lsg0L/QtdGA0LXQstC10YHRgtC4INGB0YLQsNGC0YzRjiDCq1NldmVuIFRoaW5ncyAKCVlvdSBTaG91bGQgTmV2ZXIgQ29kZSBZb3Vyc2VsZsK7INC00L7RgdGC0LDRgtC+0YfQvdC+INC40LfQstC10YHRgtC90L7Qs9C+INCyINGB0YDQtdC00LUgb3Blbi1zb3VyY2Ug0LTQtdGP0YLQtdC70Y8gCglJVC3QvtCx0LvQsNGB0YLQuCDigJQgQW5keSBMZXN0ZXJcJ9CwLiDQmNGC0LDQuiwg0LrQvtC80YMg0LjQvdGC0LXRgNC10YHQvdC+LCDQv9GA0L7RiNGDINC/0L7QtCDQutCw0YIuCgrQnNGLLCDQv9GA0L7Qs9GA0LDQvNC80LjRgdGC0YssINC70Y7QsdC40Lwg0YDQtdGI0LDRgtGMINC30LDQtNCw0YfQuC4g0JzRiyDQu9GO0LHQuNC8LCDQutC+0LPQtNCwINC40LTQtdC4INCy0L7Qt9C90LjQutCw0Y7RgiDQsiDQvdCw0YjQuNGFIArQs9C+0LvQvtCy0LDRhSwg0L/QtdGA0LXQvdCw0L/RgNCw0LLQu9GP0Y7RgtGB0Y8g0L3QsCDQvdCw0YjQuCDQv9Cw0LvRjNGG0Ysg0Lgg0YLQtdC8INGB0LDQvNGL0Lwg0YHQvtC30LTQsNGO0YLRgdGPINCy0LXQu9C40LrQvtC70LXQv9C90YvQtSDRgNC10YjQtdC90LjRjy4KCtCd0L4g0L/QvtGA0L7QuSDQvNGLINGB0LvQuNGI0LrQvtC8INCx0YvRgdGC0YDQviDQstGB0LrQsNC60LjQstCw0LXQvCDQuCDQvdCw0YfQuNC90LDQtdC8INC/0YDQvtCy0L7RgNCw0YfQuNCy0LDRgtGMINGB0LLQvtC5INC60L7QtCDQsdC10LcK0YPRh9C10YLQsCDQstGB0LXRhSDQv9C+0YHQu9C10LTRgdGC0LLQuNC5LCDQuiDQutC+0YLQvtGA0YvQvCDRjdGC0L4g0LzQvtC20LXRgiDQv9GA0LjQstC10YHRgtC4LiDQnNGLINC90LUg0YPRh9C40YLRi9Cy0LDQtdC8LCDRh9GC0L4K0LrRgtC+LdGC0L4sINCy0L7Qt9C80L7QttC90L4sINGD0LbQtSDRgNC10YjQuNC7INGN0YLRgyDQv9GA0L7QsdC70LXQvNGDLCDQuCDRh9GC0L4g0YPQttC1INC10YHRgtGMINC60L7QtCwg0LTQvtGB0YLRg9C/0L3Ri9C5INC00LvRjwrQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjRjywg0LrQvtGC0L7RgNGL0Lkg0LHRi9C7INC90LDQv9C40YHQsNC9LCDQv9GA0L7RgtC10YHRgtC40YDQvtCy0LDQvSDQuCDQv9GA0L7QtNC10LHQsNC20LXQvSDQutC10Lwt0YLQviDQtNGA0YPQs9C40LwuCtCY0L3QvtCz0LTQsCDQvdCw0Lwg0L/RgNC+0YHRgtC+INC90LXQvtCx0YXQvtC00LjQvNC+INC+0YHRgtCw0L3QvtCy0LjRgtGM0YHRjyDQuCDQv9C+0LTRg9C80LDRgtGMLCDQv9GA0LXQttC00LUg0YfQtdC8INC90LDRh9Cw0YLRjCDRh9GC0L4t0YLQvgrQv9C10YfQsNGC0LDRgtGMLgoK0J3QsNC/0YDQuNC80LXRgCwg0LXRgdC70Lgg0LLRiyDRgdGC0L7Qu9C60L3QtdGC0LXRgdGMINGBINC+0LTQvdC+0Lkg0LjQtyDRjdGC0LjRhSDRgdC10LzQuCDQt9Cw0LTQsNGHINC/0YDQvtCz0YDQsNC80LzQuNGA0L7QstCw0L3QuNGPLCAK0YLQviDQv9C+0YfRgtC4INCy0YHQtdCz0LTQsCDQstCw0Lwg0LvRg9GH0YjQtSDQv9C+0LjRgdC60LDRgtGMINGB0YPRidC10YHRgtCy0YPRjtGJ0LXQtSDRgNC10YjQtdC90LjQtSwg0YfQtdC8INC/0YvRgtCw0YLRjNGB0Y8g0YDQtdCw0LvQuNC30L7QstGL0LLQsNGC0YwgCtGH0YLQvi3RgtC+INGB0LDQvNC+0YHRgtC+0Y/RgtC10LvRjNC90L46CgoxLiDQn9Cw0YDRgdC40L3QsyBIVE1MINC40LvQuCBYTUwKCtCX0LDQtNCw0YfQtdC5LCDRgdC70L7QttC90L7RgdGC0YzRjiDQutC+0YLQvtGA0L7QuSDQt9Cw0YfQsNGB0YLRg9GOINC/0YDQtdC90LXQsdGA0LXQs9Cw0Y7Rgiwg0L/QviDQutGA0LDQudC90LXQuSDQvNC10YDQtSDQvdCwINC+0YHQvdC+0LLQtSDRgtC+0LPQviwK0YHQutC+0LvRjNC60L4g0YDQsNC3INC/0YDQviDQvdC10LPQviDRgdC/0YDQvtGB0LjQu9C4INC90LAgU3RhY2tPdmVyZmxvdyDigJQg0Y/QstC70Y/QtdGC0YHRjyDQv9Cw0YDRgdC40L3QsyBIVE1MINC40LvQuCBYTUwuIArQmNC30LLQu9C10YfQtdC90LjQtSDQtNCw0L3QvdGL0YUg0LjQtyDQv9GA0L7QuNC30LLQvtC70YzQvdC+0LPQviBIVE1MINCy0YvQs9C70Y/QtNC40YIg0L7QsdC80LDQvdGH0LjQstC+INC/0YDQvtGB0YLQviwg0L3QviDQvdCwINGB0LDQvNC+0Lwg0LTQtdC70LUgCtGN0YLQsCDQt9Cw0LTQsNGH0LAg0LTQvtC70LbQvdCwINGA0LXRiNCw0YLRjNGB0Y8g0L/RgNC40LzQtdC90LXQvdC40LXQvCDQsdC40LHQu9C40L7RgtC10LouINCh0LrQsNC20LXQvCwg0LLRiyDRhdC+0YLQuNGC0LUg0LjQt9Cy0LvQtdGH0YwgVVJMINC40LcgCtGC0LXQs9CwINGC0LDQutC+0LPQviwg0LrQsNC6CgoK0Jog0YLQvtC80YMg0LLRgNC10LzQtdC90LgsINC60LDQuiDQstGLINGB0LTQtdC70LDQtdGC0LUg0LXRidC1INC+0LTQuNC9INGG0LjQutC7INCyINC/0L7QuNGB0LrQsNGFINGB0LvRg9GH0LDQtdCyLCDRgSDQutC+0YLQvtGA0YvQvNC4IArQstCw0Ygg0LrQvtC0INC90LUg0LzQvtC20LXRgiDQuNC80LXRgtGMINC00LXQu9C+LCDQv9GA0Lgg0Y3RgtC+0Lwg0LjRgdC/0YDQsNCy0LvRj9GPINC4INGC0LXRgdGC0LjRgNGD0Y8g0YHQstC+0Lkg0LrQvtC0LCDQstGLINCx0Ysg0LzQvtCz0LvQuCDRg9C20LUgCtC40YHQv9C+0LvRjNC30L7QstCw0YLRjCDQvdGD0LbQvdGD0Y4g0LHQuNCx0LvQuNC+0YLQtdC60YMg0Lgg0YDQtdGI0LjQu9C4INCx0Ysg0LLRgdC1INGB0LLQvtC4INC/0YDQvtCx0LvQtdC80YsuCgrQryDQstCw0Lwg0L/RgNC40LLQtdC7INC90LDQs9C70Y/QtNC90YPRjiDQuNGB0YLQvtGA0LjRjiDRgSDQv9GA0LjQvNC10YDQsNC80Lg6INCy0Ysg0L/QvtGC0YDQsNGC0LjRgtC1INC90LDQvNC90L7Qs9C+INC80LXQvdGM0YjQtSDQstGA0LXQvNC10L3QuCDQvdCwIArQv9C+0LjRgdC60Lgg0YHRg9GJ0LXRgdGC0LLRg9GO0YnQtdC5INCx0LjQsdC70LjQvtGC0LXQutC4INC4INC90LAg0LXQtSDQuNC30YPRh9C10L3QuNC1LCDQvdC10LbQtdC70Lgg0L3QsCDQv9C+0L/Ri9GC0LrQuCDQvdCw0L/QuNGB0LDRgtGMINGB0LLQvtC5IArQstC10LvQvtGB0LjQv9C10LQsINC60L7RgtC+0YDRi9C5INC30LDRgtC10Lwg0L/RgNC40LTQtdGC0YHRjyDRgNCw0YHRiNC40YDRj9GC0YwsINGH0YLQvtCx0Ysg0L7QvSDRgNCw0LHQvtGC0LDQuyDQsiDRgtC10YUg0YHQu9GD0YfQsNGP0YUsINC+IArQutC+0YLQvtGA0YvRhSDQstGLINC4INC90LUg0LTRg9C80LDQu9C4LCDQutC+0LPQtNCwINC90LDRh9C40L3QsNC70Lgg0LXQs9C+INC/0LjRgdCw0YLRjC4KCjIuINCf0LDRgNGB0LjQvdCzIENTViDQuCBKU09OCgpDU1Yg0YTQsNC50LvRiyDQvtCx0LzQsNC90YfQuNCy0L4g0L/RgNC+0YHRgtGLLCDQvdC+INGC0LDRj9GCINCyINGB0LXQsdC1INC90LXQutGD0Y4g0L7Qv9Cw0YHQvdC+0YHRgtGMLiDQpNCw0LnQu9GLINGBINCy0LXQu9C40YfQuNC90LDQvNC4LArRgNCw0LfQtNC10LvQtdC90L3Ri9C80Lgg0LfQsNC/0Y/RgtGL0LzQuCDRgtGA0LjQstC40LDQu9GM0L3RiyDQtNC70Y8g0L/QsNGA0YHQuNC90LPQsCwg0L3QtSDRgtCw0Log0LvQuD8KCiMgSUQsIG5hbWUsIGNpdHkKMSwgUXVlZW4gRWxpemFiZXRoIElJLCBMb25kb24KCtCR0LXQt9GD0YHQu9C+0LLQvdC+LCDQv9C+0LrQsCDQstCw0Lwg0L3QtSDQv9GA0LjQtNC10YLRgdGPINC40LzQtdGC0Ywg0LTQtdC70L4g0YEg0LfQsNC/0Y/RgtGL0LzQuCwg0LfQsNC60LvRjtGH0LXQvdC90YvQvNC4INCyINC00LLQvtC50L3Ri9C1IArQutCw0LLRi9GH0LrQuDoKCQrQktGLINC80L7QttC10YLQtSDRgdC/0YDQsNCy0LjRgtGM0YHRjyDQuCDRgSDRjdGC0LjQvCwg0L/QvtC60LAg0L3QtSDQv9GA0LjQtNC10YLRgdGPINC40LzQtdGC0Ywg0LTQtdC70L4g0YEg0L/QtdGA0LXQstC+0LTQsNC80Lgg0YHRgtGA0L7QuiDQsiAK0YHQtdGA0LXQtNC40L3QtSDQt9Cw0L/QuNGB0LguCgpKU09OINC40LzQtdC10YIg0YLQtSDQttC1INGB0LDQvNGL0LUg0L7Qv9Cw0YHQvdC+0YHRgtC4LCDRgdCy0Y/Qt9Cw0L3QvdGL0LUg0YEg0YLQuNC/0LDQvNC4INC00LDQvdC90YvRhSwg0YfRgtC+INC4IENTViwg0YEg0LTQvtC/0L7Qu9C90LjRgtC10LvRjNC90L7QuQrQv9GA0L7QsdC70LXQvNC+0LksINCy0L7Qt9C90LjQutCw0Y7RidC10Lkg0LjQty3Qt9CwINCy0L7Qt9C80L7QttC90L7RgdGC0Lgg0YXRgNCw0L3QuNGC0Ywg0LzQvdC+0LPQvtGD0YDQvtCy0L3QtdCy0YvQtSDRgdGC0YDRg9C60YLRg9GA0Ysg0LTQsNC90L3Ri9GFLgoK0KPQsdC10YDQtdCz0LjRgtC1INGB0LXQsdGPINC+0YIg0YXQu9C+0L/QvtGCINC4INC90LXRgtC+0YfQvdC+0YHRgtC10LkuINCb0Y7QsdGL0LUg0LTQsNC90L3Ri9C1LCDQutC+0YLQvtGA0YvQtSDQvdC1INC80L7Qs9GD0YIg0LHRi9GC0Ywg0L7QsdGA0LDQsdC+0YLQsNC90YsK0YDQsNC30LTQtdC70LXQvdC40LXQvCDRgdGC0YDQvtC60Lgg0L/QviDQt9Cw0L/Rj9GC0YvQvCDQtNC+0LvQttC90Ysg0LHRi9GC0Ywg0L7QsdGA0LDQsdC+0YLQsNC90Ysg0LHQuNCx0LvQuNC+0YLQtdC60L7QuS4KCtCV0YHQu9C4INGH0LjRgtCw0YLRjCDRgdGC0YDRg9C60YLRg9GA0LjRgNC+0LLQsNC90L3Ri9C1INC00LDQvdC90YvQtSDQvdC10YHRgtGA0YPQutGC0YPRgNC40YDQvtCy0LDQvdC90YvQvCDQvNC10YLQvtC00L7QvCDRjdGC0L4g0L/Qu9C+0YXQsNGPINC40LTQtdGPLCAK0YLQviDQuNC00LXRjyDQuNC30LzQtdC90Y/RgtGMINC00LDQvdC90YvQtSDQvdCwINC80LXRgdGC0LUg0LXRidC1INGF0YPQttC1LiDQm9GO0LTQuCDRh9Cw0YHRgtC+INCz0L7QstC+0YDRj9GCINGH0YLQvi3RgtC+INCy0YDQvtC00LUgCsKr0K8g0YXQvtGH0YMg0LjQt9C80LXQvdC40YLRjCDQstGB0LUg0YLQtdCz0Lgg0YEg0YLQsNC60LjQvNC4LdGC0L4g0Lgg0YLQsNC60LjQvNC4IFVSTCDRgtCw0LosINGH0YLQvtCx0Ysg0YMg0L3QuNGFINC/0L7Rj9Cy0LjQstC70YHRjwrQvdC+0LLRi9C5INCw0YLRgNC40LHRg9GCLsK7INCd0L4g0LTQsNC20LUg0YLQsNC60L7QtSwg0LrQsNC30LDQu9C+0YHRjCDQsdGLLCDQv9GA0L7RgdGC0L7QtSDQtNC10LvQviwg0LrQsNC6IMKr0K8g0YXQvtGH0YMg0LjQt9C80LXQvdC40YLRjCAK0LIg0LrQsNC20LTQvtC8INC/0Y/RgtC+0Lwg0L/QvtC70LUg0LIg0Y3RgtC+0LwgQ1NWINC40LzRjyDQkdC+0LEg0L3QsCDQodGC0LjQssK7INGC0LDQuNGCINCyINGB0LXQsdC1INC+0L/QsNGB0L3QvtGB0YLRjCwg0L/QvtGC0L7QvNGDINGH0YLQviwK0LrQsNC6INCx0YvQu9C+INC+0YLQvNC10YfQtdC90L4g0LLRi9GI0LUsINCy0Ysg0L3QtSDRgdC80L7QttC10YLQtSDRgdGH0LjRgtGL0LLQsNGC0Ywg0LfQsNC/0Y/RgtGL0LUg0LTQvtC70LbQvdGL0Lwg0L7QsdGA0LDQt9C+0LwuINCn0YLQvtCx0Ysg0LLRgdC1IArQsdGL0LvQviDQv9GA0LDQstC40LvRjNC90L4sINCy0LDQvCDQvdC10L7QsdGF0L7QtNC40LzQviDQv9GA0L7Rh9C40YLQsNGC0Ywg0LTQsNC90L3Ri9C1INGBINC/0L7QvNC+0YnRjNGOINCz0YDQsNC80L7RgtC90L7QuSDQsdC40LHQu9C40L7RgtC10LrQuCDQstC+IArQstC90YPRgtGA0LXQvdC90Y7RjiDRgdGC0YDRg9C60YLRg9GA0YMsINC40LfQvNC10L3QuNGC0Ywg0LTQsNC90L3Ri9C1LCDQsCDQt9Cw0YLQtdC8INC30LDQv9C40YHQsNGC0Ywg0LjQt9C80LXQvdC10L3QvdGL0LUg0LTQsNC90L3Ri9C1INC+0LHRgNCw0YLQvdC+IArRgSDQv9C+0LzQvtGJ0YzRjiDRgtC+0Lkg0LbQtSDQsdC40LHQu9C40L7RgtC10LrQuC4g0J3QuNGH0YLQviDQvdC1INC/0YDQtdC00YHRgtCw0LLQu9GP0LXRgiDRgtCw0LrQvtC5INGA0LjRgdC6INC40YHQutCw0LbQtdC90LjRjyDQtNCw0L3QvdGL0YUsIArQutCw0Log0LXRgdC70Lgg0LjRhSDRgdGC0YDRg9C60YLRg9GA0LAg0L3QtSDRgdC+0L7RgtCy0LXRgtGB0YLQstGD0LXRgiDQstCw0YjQuNC8INC+0LbQuNC00LDQvdC40Y/QvC4JCgkKJzsKCi8v0KTRg9C90LrRhtC40Y8g0YPQtNCw0LvRj9GO0YnQsNGPINGB0LvQvtCy0LAg0Lgg0YHQu9C+0LLQvtGB0L7Rh9C10YLQsNC90LjRjyDRj9Cy0LvRj9GO0YnQuNC10YHRjyDRh9Cw0YHRgtGM0Y4g0LHQvtC70YzRiNC40YUg0YHQu9C+0LLQvtGB0L7Rh9C10L3QuNC5CmZ1bmN0aW9uIHJlbW92ZVJlcGV0aXRpb24oJG1vcmVXb3JkcywgJHdvcmRzKQp7CiAgICBmb3JlYWNoICgkbW9yZVdvcmRzIGFzICRtb3JlV29yZCA9PiAkbW9yZUNvdW50KSB7CiAgICAgICAgZm9yZWFjaCAoJHdvcmRzIGFzICR3b3JkID0+ICRjb3VudCkgewogICAgICAgICAgICAvL9C10YHQu9C4INCy0L4g0LLRgtC+0YDQvtC8INC80LDRgdGB0LjQstC1INGB0LvQvtCy0L7RgdC+0YfQtdGC0LDQvdC40Y8sINC40L3QsNGH0LUg0YHQu9C+0LLQsAogICAgICAgICAgICBpZiAocHJlZ19tYXRjaCgnL1x3KyBcdysvdScsICR3b3JkKSkgewogICAgICAgICAgICAgICAgaWYgKChtYl9zdHJwb3MoJG1vcmVXb3JkLCAkd29yZCkgIT09IGZhbHNlKSAmJiAoJGNvdW50ID09ICRtb3JlQ291bnQpKSB7CiAgICAgICAgICAgICAgICAgICAgdW5zZXQoJHdvcmRzWyR3b3JkXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAkc2V2ZXJhbFdvcmRzID0gZXhwbG9kZSgnICcsICRtb3JlV29yZCk7CiAgICAgICAgICAgICAgICAkb25lV29yZCA9IGFycmF5KCR3b3JkKTsKICAgICAgICAgICAgICAgICRtYXRjaGVzID0gYXJyYXlfaW50ZXJzZWN0KCRvbmVXb3JkLCAkc2V2ZXJhbFdvcmRzKTsKICAgICAgICAgICAgICAgIGlmICgoY291bnQoJG1hdGNoZXMpICE9IDApICYmICgkbW9yZUNvdW50ID09ICRjb3VudCkpIHsKICAgICAgICAgICAgICAgICAgICB1bnNldCgkd29yZHNbJHdvcmRdKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIHJldHVybiAkd29yZHM7Cn0KCi8v0KPQtNCw0LvRj9C10Lwg0LvQuNGI0L3QtdC1IC0g0L/QtdGA0LXQvdC+0YHRiywg0LfQsNC/0Y/RgtGL0LUsINGB0YLQvtC/INGB0LvQvtCy0LAuCiRpbnB1dCA9IG1iX3N0cnRvbG93ZXIoJGlucHV0KTsKJGlucHV0ID0gcHJlZ19yZXBsYWNlKCcvW1xcclxcbl0vJywgJyAnLCAkaW5wdXQpOwokaW5wdXQgPSBwcmVnX3JlcGxhY2UoJy8sLycsICcnLCAkaW5wdXQpOwpmb3JlYWNoICgkc3RvcFdvcmRzIGFzICR3b3JkKSB7CiAgICAkaW5wdXQgPSBwcmVnX3JlcGxhY2UoIi9cXGIkd29yZFxcYi91IiwgJycsICRpbnB1dCk7Cn0KCiRzZW50ZW5jZXMgPSBwcmVnX3NwbGl0KCcvXC4vJywgJGlucHV0LCAwLCBQUkVHX1NQTElUX05PX0VNUFRZKTsKCi8v0KTQvtGA0LzQuNGA0YPQtdC8INGB0LvQvtCy0L7RgdC+0YfQtdGC0LDQvdC40Y8KZm9yZWFjaCAoJHNlbnRlbmNlcyBhcyAkc2VudGVuY2UpIHsKICAgICR3b3JkcyA9IHByZWdfc3BsaXQoJy8gLycsICRzZW50ZW5jZSwgMCwgUFJFR19TUExJVF9OT19FTVBUWSk7CiAgICBmb3JlYWNoICgkd29yZHMgYXMgJGtleSA9PiAkd29yZCkgewogICAgICAgICRvbmVXb3Jkc1tdID0gJHdvcmQ7CiAgICAgICAgLy/Qn9GA0LXRgNGL0LLQsNC10Lwg0YbQuNC60Lsg0L3QsCDQv9C+0YHQu9C10LTQvdC10Lwg0YHQu9C+0LLQtS4KICAgICAgICBpZiAoJGtleSA9PSAoY291bnQoJHdvcmRzKSAtIDEpKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICAkdHdvV29yZHNbXSA9ICR3b3JkIC4gJyAnIC4gJHdvcmRzWyRrZXkgKyAxXTsKICAgICAgICBpZiAoJGtleSAhPT0gMCkgewogICAgICAgICAgICAkdGhyZWVXb3Jkc1tdID0gJHdvcmRzWyRrZXkgLSAxXSAuICcgJyAuICR3b3JkIC4gJyAnIC4gJHdvcmRzWyRrZXkgKyAxXTsKICAgICAgICB9CiAgICB9Cn0KCi8v0KHRh9C40YLQsNC10LwsINGD0LTQsNC70Y/QtdC8INCy0YHQtSDRh9GC0L4g0LHRi9C70L4g0L3QsNC50LTQtdC90L4gMSDRgNCw0Lcg0Lgg0YHQvtGA0YLQuNGA0YPQtdC8CiRjb3VudFdvcmRzID0gYXJyYXlfZGlmZihhcnJheV9jb3VudF92YWx1ZXMoJG9uZVdvcmRzKSwgYXJyYXkoMSkpOwokY291bnRUd29Xb3JkcyA9IGFycmF5X2RpZmYoYXJyYXlfY291bnRfdmFsdWVzKCR0d29Xb3JkcyksIGFycmF5KDEpKTsKJGNvdW50VGhyZWVXb3JkcyA9IGFycmF5X2RpZmYoYXJyYXlfY291bnRfdmFsdWVzKCR0aHJlZVdvcmRzKSwgYXJyYXkoMSkpOwphcnNvcnQoJGNvdW50V29yZHMsIFNPUlRfTlVNRVJJQyk7CmFyc29ydCgkY291bnRUd29Xb3JkcywgU09SVF9OVU1FUklDKTsKYXJzb3J0KCRjb3VudFRocmVlV29yZHMsIFNPUlRfTlVNRVJJQyk7CgovL9Cj0LTQsNC70Y/QtdC8INGB0LvQvtCy0LAg0Lgg0YHQu9C+0LLQvtGB0L7Rh9C10LDQvdC40Y8g0Y/QstC70Y/RjtGJ0LjQtdGB0Y8g0YfQsNGB0YLRjCDQtNGA0YPQs9C40YUKJGNvdW50V29yZHMgPSByZW1vdmVSZXBldGl0aW9uKCRjb3VudFRocmVlV29yZHMsICRjb3VudFdvcmRzKTsKJGNvdW50V29yZHMgPSByZW1vdmVSZXBldGl0aW9uKCRjb3VudFR3b1dvcmRzLCAkY291bnRXb3Jkcyk7CiRjb3VudFR3b1dvcmRzID0gcmVtb3ZlUmVwZXRpdGlvbigkY291bnRUaHJlZVdvcmRzLCAkY291bnRUd29Xb3Jkcyk7CgokdG9wID0gYXJyYXlfbWVyZ2UoJGNvdW50V29yZHMsICRjb3VudFR3b1dvcmRzLCAkY291bnRUaHJlZVdvcmRzKTsKCi8v0JLRi9Cy0L7QtNC40Lwg0YDQtdC30YPQu9GM0YLQsNGCINC90LDRiNC10Lkg0LzQsNCz0LjQuAppZiAoJHRvcCA9PSAnJykgewogICAgZWNobyAn0KPQstGLLCDQvdC+INCyINC00LDQvdC90L7QvCDRgtC10LrRgdGC0LUg0L3QtdGCINGH0LDRgdGC0YvRhSDRgdC70L7QsiDQuNC70Lgg0YHQu9C+0LLQvtGB0L7Rh9C10YLQsNC90LjQuSDQstGB0YLRgNC10YfQsNGO0YnQuNGF0YHRjyDQsdC+0LvRjNGI0LUg0L7QtNC90L7Qs9C+INGA0LDQt9CwIDooJzsKfSBlbHNlaWYgKGNvdW50KCR0b3ApID09IDEpIHsKICAgIGZvcmVhY2ggKCR0b3AgYXMgJHdvcmRzID0+ICRjb3VudCkgewogICAgICAgIGVjaG8gJ9Ch0LDQvNC+0LUg0YfQsNGB0YLQvtC1INGB0LvQvtCy0L4v0YHQu9C+0LLQvtGB0L7Rh9C10YLQsNC90LjQtTogIicgLiAkd29yZHMgLiAnIiwg0L7QvdC+INCy0YHRgtGA0LXRh9Cw0LXRgtGB0Y8gLSAnIC4gJGNvdW50IC4KICAgICAgICAgICAgJyDRgNCw0LcuJzsKICAgIH0KfSBlbHNlIHsKICAgIGFyc29ydCgkdG9wKTsKICAgIGVjaG8gItCh0LDQvNGL0LUg0YfQsNGB0YLRi9C1INGB0LvQvtCy0LAv0YHQu9C+0LLQvtGB0L7Rh9C10YLQsNC90LjRjzpcbiI7CiAgICBmb3JlYWNoICgkdG9wIGFzICR3b3JkcyA9PiAkY291bnQpIHsKICAgICAgICBlY2hvICR3b3JkcyAuICIgLSDQstGB0YLRgNC10YfQsNC10YLRgdGPICIgLiAkY291bnQgLiAiINGA0LDQty5cbiI7CiAgICB9Cn0=