<?php
class TextUtil {
private $max = 99;
public static function escape($str) {
}
public static function raw($str) {
}
public static function escapeAndLinkify($text) {
self::getUrlRegex(),
array(new self, 'replace'), self::escape($text)
);
}
private function __construct() { }
private function replace($m) {
if (
$p['host'] === 'www.nicovideo.jp' &&
preg_match('@^/++watch/++([sn]m\d++)/*+$@', $p['path'], $n) || $p['host'] === 'nico.ms' &&
preg_match('@^/++([sn]m\d++)/*+$@', $p['path'], $n) and
$this->max-- > 0
) {
return self::buildTag(
'script',
'type' => 'text/javascript',
'src' => 'http://e...content-available-to-author-only...o.jp/thumb_watch/' . $n[1],
)
);
}
if (
$p['host'] === 'youtu.be' &&
preg_match('@^/++([\w-]++)/*+$@', $p['path'], $n) || in_array($p['host'], array('www.youtube.com', 'youtube.com', 'jp.youtube.com'), true) && preg_match('@(?:^|&)v=([\w-]++)(?:$|&)@', $p['query'], $n) and
$this->max-- > 0
) {
return self::buildTag(
'iframe',
'width' => 420,
'height' => 315,
'src' => 'http://w...content-available-to-author-only...e.com/embed/' . $n[1],
'frameborder' => 0,
'allowfullscreen' => 'allowfullscreen',
)
);
}
return self::buildTag(
'a',
'href' => $m[0],
'target' => '_blank',
),
$m[0]
);
}
private static
function buildTag
($name, array $attributes = array(), $value = '') { $tag = '<' . $name;
foreach ($attributes as $k => $v) {
$tag .= $k === $v ? ' ' . $k : ' ' . $k . '="' . $v . '"';
}
$tag .=
!$value && $value !== '' ?
' />' :
'>' . $value . '</' . $name . '>'
;
return $tag;
}
private static function getUrlRegex() {
return
'`https?+:(?://(?:(?:[-.0-9_a-z~]|%[0-9a-f][0-9a-f]' .
'|[!$&-,:;=])*+@)?+(?:\[(?:(?:[0-9a-f]{1,4}:){6}(?:' .
'[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:\d|[1-9]\d|1\d{2}|2' .
'[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25' .
'[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?' .
':\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))|::(?:[0-9a-f' .
']{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:\d|[1' .
'-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{' .
'2}|2[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\\' .
'd|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])' .
')|(?:[0-9a-f]{1,4})?+::(?:[0-9a-f]{1,4}:){4}(?:[0-' .
'9a-f]{1,4}:[0-9a-f]{1,4}|(?:\d|[1-9]\d|1\d{2}|2[0-' .
'4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-' .
'5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?:\d' .
'|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))|(?:(?:[0-9a-f]{' .
'1,4}:)?+[0-9a-f]{1,4})?+::(?:[0-9a-f]{1,4}:){3}(?:' .
'[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:\d|[1-9]\d|1\d{2}|2' .
'[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25' .
'[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?' .
':\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))|(?:(?:[0-9a-' .
'f]{1,4}:){0,2}[0-9a-f]{1,4})?+::(?:[0-9a-f]{1,4}:)' .
'{2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:\d|[1-9]\d|1\\' .
'd{2}|2[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4' .
']\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5' .
'])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))|(?:(?:' .
'[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?+::[0-9a-f]{1,4' .
'}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:\d|[1-9]\d|1\d' .
'{2}|2[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]' .
'\d|25[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]' .
')\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))|(?:(?:[' .
'0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?+::(?:[0-9a-f]{1' .
',4}:[0-9a-f]{1,4}|(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25' .
'[0-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?' .
':\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?:\d|[1-9]\\' .
'd|1\d{2}|2[0-4]\d|25[0-5]))|(?:(?:[0-9a-f]{1,4}:){' .
'0,5}[0-9a-f]{1,4})?+::[0-9a-f]{1,4}|(?:(?:[0-9a-f]' .
'{1,4}:){0,6}[0-9a-f]{1,4})?+::|v[0-9a-f]++\.[!$&-.' .
'0-;=_a-z~]++)\]|(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0' .
'-5])\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?:\\' .
'd|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(?:\d|[1-9]\d|' .
'1\d{2}|2[0-4]\d|25[0-5])|(?:[-.0-9_a-z~]|%[0-9a-f]' .
'[0-9a-f]|[!$&-,;=])*+)(?::\d*+)?+(?:/(?:[-.0-9_a-z' .
'~]|%[0-9a-f][0-9a-f]|[!$&-,:;=@])*+)*+|/(?:(?:[-.0' .
'-9_a-z~]|%[0-9a-f][0-9a-f]|[!$&-,:;=@])++(?:/(?:[-' .
'.0-9_a-z~]|%[0-9a-f][0-9a-f]|[!$&-,:;=@])*+)*+)?+|' .
'(?:[-.0-9_a-z~]|%[0-9a-f][0-9a-f]|[!$&-,:;=@])++(?' .
':/(?:[-.0-9_a-z~]|%[0-9a-f][0-9a-f]|[!$&-,:;=@])*+' .
')*+)?+(?:\?+(?:[-.0-9_a-z~]|%[0-9a-f][0-9a-f]|[!$&' .
'-,/:;=?+@])*+)?+(?:#(?:[-.0-9_a-z~]|%[0-9a-f][0-9a' .
'-f]|[!$&-,/:;=?+@])*+)?+`i'
;
}
}
$text = <<<EOD
Youtubeにはhttp://w...content-available-to-author-only...e.com/watch?v=s0SE8GMgeEIとか
http://y...content-available-to-author-only...u.be/s0SE8GMgeEIのようなURLフォーマットがあります。
http://w...content-available-to-author-only...e.com/watch?foo=hoge&v=s0SE8GMgeEI&bar=hogeのように
余分なクエリがついていてもちゃんと処理すべきでしょう。
日本に限定するならば
http://j...content-available-to-author-only...e.com/watch?v=s0SE8GMgeEIもちゃんと処理すべきですね。
一方ニコニコ動画には
http://w...content-available-to-author-only...o.jp/watch/sm1136355だけではなく
http://w...content-available-to-author-only...o.jp/watch/nm4308389のように、
「n」と「m」両方が来る可能性があります。また、
http://n...content-available-to-author-only...o.ms/sm1136355のような短縮URLもあります。
これらにはちゃんと対応すべきです。
とはいっても、無効なURLもちゃんと判別しなければなりません。
例えばhttp://y...content-available-to-author-only...u.be/s0SE8GMgeEI/hogehoge?a=bとかは明らかにおかしいし、
http://w...content-available-to-author-only...o.jp/watch/nm11363abcもニコニコ動画の仕様としてはおかしいです。
こういったものは無視する必要があります。当然、関係ないものはエスケープして表示させましょう。
「&」「<」「>」といった文字がちゃんとエスケープされるか確認してください。
EOD;
echo TextUtil::escapeAndLinkify($text);
PD9waHAKCmNsYXNzIFRleHRVdGlsIHsKICAgIAogICAgcHJpdmF0ZSAkbWF4ID0gOTk7CiAgICAKICAgIHB1YmxpYyBzdGF0aWMgZnVuY3Rpb24gZXNjYXBlKCRzdHIpIHsKICAgICAgICByZXR1cm4gaHRtbHNwZWNpYWxjaGFycygkc3RyLCBFTlRfUVVPVEVTLCAnVVRGLTgnKTsKICAgIH0KICAgIAogICAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiByYXcoJHN0cikgewogICAgICAgIHJldHVybiBodG1sc3BlY2lhbGNoYXJzX2RlY29kZSgkc3RyLCBFTlRfUVVPVEVTKTsKICAgIH0KICAgIAogICAgcHVibGljIHN0YXRpYyBmdW5jdGlvbiBlc2NhcGVBbmRMaW5raWZ5KCR0ZXh0KSB7CiAgICAgICAgcmV0dXJuIHByZWdfcmVwbGFjZV9jYWxsYmFjaygKICAgICAgICAgICAgc2VsZjo6Z2V0VXJsUmVnZXgoKSwKICAgICAgICAgICAgYXJyYXkobmV3IHNlbGYsICdyZXBsYWNlJyksCiAgICAgICAgICAgIHNlbGY6OmVzY2FwZSgkdGV4dCkKICAgICAgICApOwogICAgfQogICAgCiAgICBwcml2YXRlIGZ1bmN0aW9uIF9fY29uc3RydWN0KCkgeyB9CiAgICAKICAgIHByaXZhdGUgZnVuY3Rpb24gcmVwbGFjZSgkbSkgewogICAgICAgICRwID0gcGFyc2VfdXJsKHNlbGY6OnJhdygkbVswXSkpICsgYXJyYXlfZmlsbF9rZXlzKGFycmF5KCdwYXRoJywgJ3F1ZXJ5JyksICcnKTsKICAgICAgICBpZiAoCiAgICAgICAgICAgICRwWydob3N0J10gPT09ICd3d3cubmljb3ZpZGVvLmpwJyAmJgogICAgICAgICAgICBwcmVnX21hdGNoKCdAXi8rK3dhdGNoLysrKFtzbl1tXGQrKykvKiskQCcsICRwWydwYXRoJ10sICRuKSB8fAogICAgICAgICAgICAkcFsnaG9zdCddID09PSAnbmljby5tcycgJiYKICAgICAgICAgICAgcHJlZ19tYXRjaCgnQF4vKysoW3NuXW1cZCsrKS8qKyRAJywgJHBbJ3BhdGgnXSwgJG4pIGFuZAogICAgICAgICAgICAkdGhpcy0+bWF4LS0gPiAwCiAgICAgICAgKSB7CiAgICAgICAgICAgIHJldHVybiBzZWxmOjpidWlsZFRhZygKICAgICAgICAgICAgICAgICdzY3JpcHQnLAogICAgICAgICAgICAgICAgYXJyYXkoCiAgICAgICAgICAgICAgICAgICAgJ3R5cGUnID0+ICd0ZXh0L2phdmFzY3JpcHQnLAogICAgICAgICAgICAgICAgICAgICdzcmMnID0+ICdodHRwOi8vZS4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uby5qcC90aHVtYl93YXRjaC8nIC4gJG5bMV0sCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGlmICgKICAgICAgICAgICAgJHBbJ2hvc3QnXSA9PT0gJ3lvdXR1LmJlJyAmJgogICAgICAgICAgICBwcmVnX21hdGNoKCdAXi8rKyhbXHctXSsrKS8qKyRAJywgJHBbJ3BhdGgnXSwgJG4pIHx8CiAgICAgICAgICAgIGluX2FycmF5KCRwWydob3N0J10sIGFycmF5KCd3d3cueW91dHViZS5jb20nLCAneW91dHViZS5jb20nLCAnanAueW91dHViZS5jb20nKSwgdHJ1ZSkgJiYKICAgICAgICAgICAgcHJlZ19tYXRjaCgnQCg/Ol58Jil2PShbXHctXSsrKSg/OiR8JilAJywgJHBbJ3F1ZXJ5J10sICRuKSBhbmQKICAgICAgICAgICAgJHRoaXMtPm1heC0tID4gMAogICAgICAgICkgewogICAgICAgICAgICByZXR1cm4gc2VsZjo6YnVpbGRUYWcoCiAgICAgICAgICAgICAgICAnaWZyYW1lJywKICAgICAgICAgICAgICAgIGFycmF5KAogICAgICAgICAgICAgICAgICAgICd3aWR0aCcgPT4gNDIwLAogICAgICAgICAgICAgICAgICAgICdoZWlnaHQnID0+IDMxNSwKICAgICAgICAgICAgICAgICAgICAnc3JjJyA9PiAnaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmUuY29tL2VtYmVkLycgLiAkblsxXSwKICAgICAgICAgICAgICAgICAgICAnZnJhbWVib3JkZXInID0+IDAsCiAgICAgICAgICAgICAgICAgICAgJ2FsbG93ZnVsbHNjcmVlbicgPT4gJ2FsbG93ZnVsbHNjcmVlbicsCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzZWxmOjpidWlsZFRhZygKICAgICAgICAgICAgJ2EnLAogICAgICAgICAgICBhcnJheSgKICAgICAgICAgICAgICAgICdocmVmJyA9PiAkbVswXSwKICAgICAgICAgICAgICAgICd0YXJnZXQnID0+ICdfYmxhbmsnLAogICAgICAgICAgICApLAogICAgICAgICAgICAkbVswXQogICAgICAgICk7CiAgICB9CiAgICAKICAgIHByaXZhdGUgc3RhdGljIGZ1bmN0aW9uIGJ1aWxkVGFnKCRuYW1lLCBhcnJheSAkYXR0cmlidXRlcyA9IGFycmF5KCksICR2YWx1ZSA9ICcnKSB7CiAgICAgICAgJHRhZyA9ICc8JyAuICRuYW1lOwogICAgICAgIGZvcmVhY2ggKCRhdHRyaWJ1dGVzIGFzICRrID0+ICR2KSB7CiAgICAgICAgICAgICR0YWcgLj0gJGsgPT09ICR2ID8gJyAnIC4gJGsgOiAnICcgLiAkayAuICc9IicgLiAkdiAuICciJzsKICAgICAgICB9CiAgICAgICAgJHRhZyAuPQogICAgICAgICAgICAhJHZhbHVlICYmICR2YWx1ZSAhPT0gJycgPwogICAgICAgICAgICAnIC8+JyA6CiAgICAgICAgICAgICc+JyAuICR2YWx1ZSAuICc8LycgLiAkbmFtZSAuICc+JwogICAgICAgIDsKICAgICAgICByZXR1cm4gJHRhZzsKICAgIH0KICAgIAogICAgcHJpdmF0ZSBzdGF0aWMgZnVuY3Rpb24gZ2V0VXJsUmVnZXgoKSB7CiAgICAgICAgcmV0dXJuCiAgICAgICAgICAgICdgaHR0cHM/KzooPzovLyg/Oig/OlstLjAtOV9hLXp+XXwlWzAtOWEtZl1bMC05YS1mXScgLgogICAgICAgICAgICAnfFshJCYtLDo7PV0pKitAKT8rKD86XFsoPzooPzpbMC05YS1mXXsxLDR9Oil7Nn0oPzonIC4KICAgICAgICAgICAgJ1swLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpcZHxbMS05XVxkfDFcZHsyfXwyJyAuCiAgICAgICAgICAgICdbMC00XVxkfDI1WzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNScgLgogICAgICAgICAgICAnWzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKVwuKD8nIC4KICAgICAgICAgICAgJzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKSl8OjooPzpbMC05YS1mJyAuCiAgICAgICAgICAgICddezEsNH06KXs1fSg/OlswLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpcZHxbMScgLgogICAgICAgICAgICAnLTldXGR8MVxkezJ9fDJbMC00XVxkfDI1WzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsnIC4KICAgICAgICAgICAgJzJ9fDJbMC00XVxkfDI1WzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cXCcgLgogICAgICAgICAgICAnZHwyNVswLTVdKVwuKD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLTRdXGR8MjVbMC01XSknIC4KICAgICAgICAgICAgJyl8KD86WzAtOWEtZl17MSw0fSk/Kzo6KD86WzAtOWEtZl17MSw0fTopezR9KD86WzAtJyAuCiAgICAgICAgICAgICc5YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLScgLgogICAgICAgICAgICAnNF1cZHwyNVswLTVdKVwuKD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLTRdXGR8MjVbMC0nIC4KICAgICAgICAgICAgJzVdKVwuKD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLTRdXGR8MjVbMC01XSlcLig/OlxkJyAuCiAgICAgICAgICAgICd8WzEtOV1cZHwxXGR7Mn18MlswLTRdXGR8MjVbMC01XSkpfCg/Oig/OlswLTlhLWZdeycgLgogICAgICAgICAgICAnMSw0fTopPytbMC05YS1mXXsxLDR9KT8rOjooPzpbMC05YS1mXXsxLDR9Oil7M30oPzonIC4KICAgICAgICAgICAgJ1swLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpcZHxbMS05XVxkfDFcZHsyfXwyJyAuCiAgICAgICAgICAgICdbMC00XVxkfDI1WzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNScgLgogICAgICAgICAgICAnWzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKVwuKD8nIC4KICAgICAgICAgICAgJzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKSl8KD86KD86WzAtOWEtJyAuCiAgICAgICAgICAgICdmXXsxLDR9Oil7MCwyfVswLTlhLWZdezEsNH0pPys6Oig/OlswLTlhLWZdezEsNH06KScgLgogICAgICAgICAgICAnezJ9KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9fCg/OlxkfFsxLTldXGR8MVxcJyAuCiAgICAgICAgICAgICdkezJ9fDJbMC00XVxkfDI1WzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNCcgLgogICAgICAgICAgICAnXVxkfDI1WzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTUnIC4KICAgICAgICAgICAgJ10pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKSl8KD86KD86JyAuCiAgICAgICAgICAgICdbMC05YS1mXXsxLDR9Oil7MCwzfVswLTlhLWZdezEsNH0pPys6OlswLTlhLWZdezEsNCcgLgogICAgICAgICAgICAnfTooPzpbMC05YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86XGR8WzEtOV1cZHwxXGQnIC4KICAgICAgICAgICAgJ3syfXwyWzAtNF1cZHwyNVswLTVdKVwuKD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLTRdJyAuCiAgICAgICAgICAgICdcZHwyNVswLTVdKVwuKD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLTRdXGR8MjVbMC01XScgLgogICAgICAgICAgICAnKVwuKD86XGR8WzEtOV1cZHwxXGR7Mn18MlswLTRdXGR8MjVbMC01XSkpfCg/Oig/OlsnIC4KICAgICAgICAgICAgJzAtOWEtZl17MSw0fTopezAsNH1bMC05YS1mXXsxLDR9KT8rOjooPzpbMC05YS1mXXsxJyAuCiAgICAgICAgICAgICcsNH06WzAtOWEtZl17MSw0fXwoPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNScgLgogICAgICAgICAgICAnWzAtNV0pXC4oPzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKVwuKD8nIC4KICAgICAgICAgICAgJzpcZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKVwuKD86XGR8WzEtOV1cXCcgLgogICAgICAgICAgICAnZHwxXGR7Mn18MlswLTRdXGR8MjVbMC01XSkpfCg/Oig/OlswLTlhLWZdezEsNH06KXsnIC4KICAgICAgICAgICAgJzAsNX1bMC05YS1mXXsxLDR9KT8rOjpbMC05YS1mXXsxLDR9fCg/Oig/OlswLTlhLWZdJyAuCiAgICAgICAgICAgICd7MSw0fTopezAsNn1bMC05YS1mXXsxLDR9KT8rOjp8dlswLTlhLWZdKytcLlshJCYtLicgLgogICAgICAgICAgICAnMC07PV9hLXp+XSsrKVxdfCg/OlxkfFsxLTldXGR8MVxkezJ9fDJbMC00XVxkfDI1WzAnIC4KICAgICAgICAgICAgJy01XSlcLig/OlxkfFsxLTldXGR8MVxkezJ9fDJbMC00XVxkfDI1WzAtNV0pXC4oPzpcXCcgLgogICAgICAgICAgICAnZHxbMS05XVxkfDFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKVwuKD86XGR8WzEtOV1cZHwnIC4KICAgICAgICAgICAgJzFcZHsyfXwyWzAtNF1cZHwyNVswLTVdKXwoPzpbLS4wLTlfYS16fl18JVswLTlhLWZdJyAuCiAgICAgICAgICAgICdbMC05YS1mXXxbISQmLSw7PV0pKispKD86OlxkKispPysoPzovKD86Wy0uMC05X2EteicgLgogICAgICAgICAgICAnfl18JVswLTlhLWZdWzAtOWEtZl18WyEkJi0sOjs9QF0pKispKit8Lyg/Oig/OlstLjAnIC4KICAgICAgICAgICAgJy05X2Eten5dfCVbMC05YS1mXVswLTlhLWZdfFshJCYtLDo7PUBdKSsrKD86Lyg/OlstJyAuCiAgICAgICAgICAgICcuMC05X2Eten5dfCVbMC05YS1mXVswLTlhLWZdfFshJCYtLDo7PUBdKSorKSorKT8rfCcgLgogICAgICAgICAgICAnKD86Wy0uMC05X2Eten5dfCVbMC05YS1mXVswLTlhLWZdfFshJCYtLDo7PUBdKSsrKD8nIC4KICAgICAgICAgICAgJzovKD86Wy0uMC05X2Eten5dfCVbMC05YS1mXVswLTlhLWZdfFshJCYtLDo7PUBdKSorJyAuCiAgICAgICAgICAgICcpKispPysoPzpcPysoPzpbLS4wLTlfYS16fl18JVswLTlhLWZdWzAtOWEtZl18WyEkJicgLgogICAgICAgICAgICAnLSwvOjs9PytAXSkqKyk/Kyg/OiMoPzpbLS4wLTlfYS16fl18JVswLTlhLWZdWzAtOWEnIC4KICAgICAgICAgICAgJy1mXXxbISQmLSwvOjs9PytAXSkqKyk/K2BpJwogICAgICAgIDsKICAgIH0KICAgIAp9CgokdGV4dCA9IDw8PEVPRApZb3V0dWJl44Gr44GvaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmUuY29tL3dhdGNoP3Y9czBTRThHTWdlRUnjgajjgYsKaHR0cDovL3kuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnUuYmUvczBTRThHTWdlRUnjga7jgojjgYbjgapVUkzjg5Xjgqnjg7zjg57jg4Pjg4jjgYzjgYLjgorjgb7jgZnjgIIKaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmUuY29tL3dhdGNoP2Zvbz1ob2dlJnY9czBTRThHTWdlRUkmYmFyPWhvZ2Xjga7jgojjgYbjgasK5L2Z5YiG44Gq44Kv44Ko44Oq44GM44Gk44GE44Gm44GE44Gm44KC44Gh44KD44KT44Go5Yem55CG44GZ44G544GN44Gn44GX44KH44GG44CCCuaXpeacrOOBq+mZkOWumuOBmeOCi+OBquOCieOBsApodHRwOi8vai4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uZS5jb20vd2F0Y2g/dj1zMFNFOEdNZ2VFSeOCguOBoeOCg+OCk+OBqOWHpueQhuOBmeOBueOBjeOBp+OBmeOBreOAggogCuS4gOaWueODi+OCs+ODi+OCs+WLleeUu+OBq+OBrwpodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uby5qcC93YXRjaC9zbTExMzYzNTXjgaDjgZHjgafjga/jgarjgY8KaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLm8uanAvd2F0Y2gvbm00MzA4Mzg544Gu44KI44GG44Gr44CBCuOAjG7jgI3jgajjgIxt44CN5Lih5pa544GM5p2l44KL5Y+v6IO95oCn44GM44GC44KK44G+44GZ44CC44G+44Gf44CBCmh0dHA6Ly9uLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5vLm1zL3NtMTEzNjM1NeOBruOCiOOBhuOBquefree4rlVSTOOCguOBguOCiuOBvuOBmeOAggrjgZPjgozjgonjgavjga/jgaHjgoPjgpPjgajlr77lv5zjgZnjgbnjgY3jgafjgZnjgIIKIArjgajjga/jgYTjgaPjgabjgoLjgIHnhKHlirnjgapVUkzjgoLjgaHjgoPjgpPjgajliKTliKXjgZfjgarjgZHjgozjgbDjgarjgorjgb7jgZvjgpPjgIIK5L6L44GI44GwaHR0cDovL3kuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnUuYmUvczBTRThHTWdlRUkvaG9nZWhvZ2U/YT1i44Go44GL44Gv5piO44KJ44GL44Gr44GK44GL44GX44GE44GX44CBCmh0dHA6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5vLmpwL3dhdGNoL25tMTEzNjNhYmPjgoLjg4vjgrPjg4vjgrPli5XnlLvjga7ku5Xmp5jjgajjgZfjgabjga/jgYrjgYvjgZfjgYTjgafjgZnjgIIK44GT44GG44GE44Gj44Gf44KC44Gu44Gv54Sh6KaW44GZ44KL5b+F6KaB44GM44GC44KK44G+44GZ44CC5b2T54S244CB6Zai5L+C44Gq44GE44KC44Gu44Gv44Ko44K544Kx44O844OX44GX44Gm6KGo56S644GV44Gb44G+44GX44KH44GG44CCCuOAjCbjgI3jgIw844CN44CMPuOAjeOBqOOBhOOBo+OBn+aWh+Wtl+OBjOOBoeOCg+OCk+OBqOOCqOOCueOCseODvOODl+OBleOCjOOCi+OBi+eiuuiqjeOBl+OBpuOBj+OBoOOBleOBhOOAggpFT0Q7CiAKZWNobyBUZXh0VXRpbDo6ZXNjYXBlQW5kTGlua2lmeSgkdGV4dCk7