Про функцию в R можно сказать, что это объект “первого класса” - т.е. это такой же объект, как и любой другой в R, например, вектор.
Функция как объект R
\*Вызовем функцию c(ombine) на двух функциях. С помощью функции str посмотрим, что получилось
str(c(mean, max))
List of 2
$ :function (x, ...)
$ :function (..., na.rm = FALSE)
Видим, что это список из двух функций Значит ли это такой список (комбинацию функций) можно, например, использовать в sapply? Да, можно 1. Запишу список-комбинацию в переменную
fun_list <- c(mean, max)
?sapply
- Использую эту комбинацию в sapply
sapply(fun_list, function(f) f(1:100))
[1] 50.5 100.0
N.B! Интересно, то, что стандартный порядок аргументов sapply как-будто бы перевнулся наизнанку. В стандартных ситуациях, которые рассматривались ранее:
* первым аргументом шел объект, к которому собирались, применить функцию
* вторым шла уже сама функция
Здесь же я вижу, что мы наоборот на функцию вбрасываем аргумент через анонимную функцию function(f), а дальше собственно аргумент f.
Функция как аргумент функции
Так, например, можно сделать функцию apply_f, а ее сделать аргументом функции sapply
apply_f <- function(f, x) f(x)
sapply(fun_list, apply_f, x = 1:100)
[1] 50.5 100.0
Получаю ответ такой же, как и в примере выше. Смысл в том, что apply_f просто применяет функцию f к аргументу x (“function(f, x) f(x)”). А в sapply эта функция, получается, просто передает функции fun_list аргумент “x = 1:100”.
Точно так же в переменную можно сохранить анонимную функцию - она ничем не хуже любой другой функции.
apply_f(function(x) sum(x^2), 1:10)
[1] 385
Т.е. в примере выше мы аргумент “1:10” передаем анонимной функции, в которой скомбинирована функция “sum(x^2)”, т.е. сумма (1:10)^2.
Как я понимаю применение анонимной функции на данном этапе? По сути анонимная функция помогает нам применять, какие-то относительные сложные комбинации нескольких функций без их записывания в память компа под видом оболочки какой-то единой функции. Т.е. вместо того, чтобы создавать функцию sum_sq и изредка применять ее, только забивая ей память
sum_sq <- function(x) {
sum(x^2)
}
sum_sq(1:10)
[1] 385
Функция как возвращаемое значение из функции (return value)
Пример: заведем функцию, которая в своем теле возвращает еще 1 функцию
square <- function() function(x) x^2
square()
function(x) x^2
<environment: 0x00000221dee6a198>
Видим, что если прописать такую пустую фнкцию без аргумента, то нам возвращается вложенная в нее функция. А значть можем открыть еще 1 скобки для того, чтобы отдать аргумент такой вложенной функции, например:
square()(5)
[1] 25
Фукнции внутри функций
Естественно функции можно определять внутри функции, а не в глобальном окружении R. Такая возможность как раз-таки полезна в случае, когда мы не зотим захламлять глобальное окружение очередной функцией - определяться и работать она будет исключительно в теле специально вызываемой нами функции.
Когда может потребоваться?
Например, когда нам приходится заводить, какую-то специальную функцию для исполнения другой. Тогда код такой функции вкладываем просто в тело зависимой функции и вуаля.
f <- function(x) {
g <- function(y) if (y >0) 1 else if (y < 0) -1 else 0
sapply(x, g)
}
Т.е. смысл такой вложенной функции из примера, что она будет дополнительно проверять знак (+/-) аргумента x (каждого элемента вектора
f(-1:3)
[1] -1 0 1 1 1
Конечно, такая функция есть и в базовом R - это функция sign
all.equal(f(-100:100), sign(-100:100))
Определение функции внутри функции - один из вариантов инкапсуляции в R. Способ спрятать функцию от глоабльного окружения
Исходный код функции или как понять, что делает функция?
Можно заглянуть в справку. Но иногда этого может быть недостаточно. Простейший случай - пропечатать имя функции без скобок. Например:
f <- function(x) x^5
f(2)
[1] 32
f
function(x) x^5
Но иногда вывод отличается от стандартного R кода. В выводе могут встретится .C, .Fortran, .External, .Internal, .Primitive - это обращенгие к уже скомпилированному коду на более низкоуровневом языке, чаще всего C - в такой ситуации нужно искать исходный код самого R. Это может быть геморно, но, в принципе, при желании возможно.
Если в выводе есть UseMethod или standardGeneric, то это значит, что происходит т.н. method dispatch для двух систем классов S3/S4 (полиморфизм, например, plot)
methods(plot)
[1] plot.acf* plot.data.frame*
[3] plot.decomposed.ts* plot.default
[5] plot.dendrogram* plot.density*
[7] plot.ecdf plot.factor*
[9] plot.formula* plot.function
[11] plot.hclust* plot.histogram*
[13] plot.HoltWinters* plot.isoreg*
[15] plot.lm* plot.medpolish*
[17] plot.mlm* plot.ppr*
[19] plot.prcomp* plot.princomp*
[21] plot.profile.nls* plot.raster*
[23] plot.spec* plot.stepfun
[25] plot.stl* plot.table*
[27] plot.ts plot.tskernel*
[29] plot.TukeyHSD*
see '?methods' for accessing help and source code
Видим, что количество объектов внутри функции plot довольно большое, т.е. для каждой определено свое поведение функции plot.
Возвращаемое значение из функции
Определяется
А) ключевым словом return:
has_na <- function(v) {
for (k in v) if (is.na(k)) return(TRUE)
return(FALSE)
}
Какое первое return в теле функции встречается и исполняется, то и выводится, в случае если их несколько
Б) либо последним вычисленным значением
Например, почитал справку по is.na и понял, что она векторизована и справится с моей задачей лучше и быстрее самопала с циклом
has_na <- function(v) any(is.na(v))
Здесь return нет, только результат is.na, который и будет возвращен
Аргументы функций по умолчанию
Можно посмотреть на аргументы по умолчанию по тому, как объявляется какая-нибудь функция. Например, возьмем seq
args(seq)
function (...)
NULL
seq(from = 1, to = 1, by = ((to - from)/(length.out - 1)), length.out = NULL, along.with = NULL, …)
- все аргументы могут иметь значения по умолчанию
- значения могут вычисляться на лету (в данном примере так происходит с аргументом by)
seq() #from = 1, to = 1
[1] 1
seq(1, 5, length.out = 11)
[1] 1.0 1.4 1.8 2.2 2.6 3.0 3.4 3.8 4.2 4.6 5.0
# то же самое, как если бы указали "by = (5-1)/(11-1)"
Правила разбора аргументов
Во многих функциях аргументов много, сложная структура, есть двоеточия и т.д.
Приведем пример
f <- function(x, pow =2) x^pow
integrate(f, 0, 1) #lower = 0, upper = 1, pow = 2
0.3333333 with absolute error < 3.7e-15
Как разбирается такая функция?
Разбор проходит в 3 этапа:
1. Точное совпадение имени аргумента - arg2, optional_arg
2. Частичное совпадение имени аргумента (только до …) - remove_na
3. Разбор аргументов по позиции - arg1
Неразобранные аргументы попадают в … - do_magic. Из этого многоточия такие пойманные аргументы можно потом достать
Аргумент … (ellipsis) - проброс аргументов
Один из случаев использования ellipsis - “произвольное количество передаваемых объектов” внутри какой-нибудь функции. Так, например, устроены функции sum, c, cbind, paste.
Другой характерный случай - “проброс аргументов”, когда функция не может прочитать какой-то аргумент (он не задан в ней по умолчанию),то этот аргумент “пробрасывается” следующей функции, аргументом которой является исходная функция. Простой пример
integrate(f, 0, 1, pow = 5)
0.1666667 with absolute error < 1.9e-15
Я хочу проинтегрировать функцию от нуля до 1, для этого можно воспользоваться функцией integrate. В примере выше, поскольку мы не указываем дополнительной информации касательно степени, то принимается значение по умолчанию. Рассмотрим пример ниже:
1 + 1
[1] 2
"+" (1, 1)
[1] 2
Все вроде бы то же самое, но теперь в аргументах функции integrate указали аргумент pow = 5 (нет даже аргумента, начинающегося с pow). Важно то, что такого аргумента фукнция integrate не знает, а значит она попытается “пробросить” его вверх по лесенке вложенной в нее функции, которая в нашем примере знает такой аргумент, принимает его и изменяет свое действие в соответствии с поступившей информацией.
Это удобный способ в R использования параметров, которые понадобятся последующим функциям
Бинарные операторы
В R можно создавать не только свои функции, но и бинарные операторы (например, арифметические, такие как “+” или "*", а также специальные операторы %in%, где между %in% символ).
Для начала о бинарных операторах - это тоже функции, которые можно вызвать аналогично другим функциям. Например, все перечисленные ниже выражения эквивалентны
1:5 %in% c(1,2,5)
[1] TRUE TRUE FALSE FALSE TRUE
"%in%" (1:5, c(1, 2,5))
[1] TRUE TRUE FALSE FALSE TRUE
1:5 %in% c(1,2,5)
[1] TRUE TRUE FALSE FALSE TRUE
Давайте проверим, есть ли вхождения x в y
"%nin%" <- function(x, y) !(x %in% y)
1:5 %nin% c(1,2,5)
[1] FALSE FALSE TRUE TRUE FALSE
А теперь хочу создать свой собственный бинарный оператор
"%nin%" <- function(x, y) !(x %in% y)
1:5 %nin% c(1,2,5)
Глоссарий: ?“function” ?methods argumet matching ellipsis (?“…”)
LS0tDQp0aXRsZTogItCk0YPQvdC60YbQuNC4IC0g0L/RgNC+0LTQstC40L3Rg9GC0YvQuSDRg9GA0L7QstC10L3RjCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQrQn9GA0L4g0YTRg9C90LrRhtC40Y4g0LIgUiDQvNC+0LbQvdC+INGB0LrQsNC30LDRgtGMLCDRh9GC0L4g0Y3RgtC+ICoq0L7QsdGK0LXQutGCICoi0L/QtdGA0LLQvtCz0L4g0LrQu9Cw0YHRgdCwIiogKiogLSDRgi7QtS4g0Y3RgtC+INGC0LDQutC+0Lkg0LbQtSDQvtCx0YrQtdC60YIsINC60LDQuiDQuCDQu9GO0LHQvtC5INC00YDRg9Cz0L7QuSDQsiBSLCDQvdCw0L/RgNC40LzQtdGALCDQstC10LrRgtC+0YAuICANCg0KIyMg0KTRg9C90LrRhtC40Y8g0LrQsNC6INC+0LHRitC10LrRgiBSDQpcXCrQktGL0LfQvtCy0LXQvCDRhNGD0L3QutGG0LjRjiBjKG9tYmluZSkg0L3QsCDQtNCy0YPRhSDRhNGD0L3QutGG0LjRj9GFLiDQoSDQv9C+0LzQvtGJ0YzRjiDRhNGD0L3QutGG0LjQuCBzdHIg0L/QvtGB0LzQvtGC0YDQuNC8LCDRh9GC0L4g0L/QvtC70YPRh9C40LvQvtGB0YwNCmBgYHtyfQ0Kc3RyKGMobWVhbiwgbWF4KSkNCmBgYA0K0JLQuNC00LjQvCwg0YfRgtC+INGN0YLQviDRgdC/0LjRgdC+0Log0LjQtyDQtNCy0YPRhSDRhNGD0L3QutGG0LjQuSDQl9C90LDRh9C40YIg0LvQuCDRjdGC0L4g0YLQsNC60L7QuSDRgdC/0LjRgdC+0LogKNC60L7QvNCx0LjQvdCw0YbQuNGOINGE0YPQvdC60YbQuNC5KSDQvNC+0LbQvdC+LCDQvdCw0L/RgNC40LzQtdGALCDQuNGB0L/QvtC70YzQt9C+0LLQsNGC0Ywg0LIgc2FwcGx5PyDQlNCwLCDQvNC+0LbQvdC+DQoxLiDQl9Cw0L/QuNGI0YMg0YHQv9C40YHQvtC6LdC60L7QvNCx0LjQvdCw0YbQuNGOINCyINC/0LXRgNC10LzQtdC90L3Rg9GODQpgYGB7cn0NCmZ1bl9saXN0IDwtIGMobWVhbiwgbWF4KQ0KP3NhcHBseQ0KYGBgDQoyLiDQmNGB0L/QvtC70YzQt9GD0Y4g0Y3RgtGDINC60L7QvNCx0LjQvdCw0YbQuNGOINCyIHNhcHBseQ0KYGBge3J9DQpzYXBwbHkoZnVuX2xpc3QsIGZ1bmN0aW9uKGYpIGYoMToxMDApKQ0KYGBgDQpOLkIhINCY0L3RgtC10YDQtdGB0L3Qviwg0YLQviwg0YfRgtC+INGB0YLQsNC90LTQsNGA0YLQvdGL0Lkg0L/QvtGA0Y/QtNC+0Log0LDRgNCz0YPQvNC10L3RgtC+0LIgc2FwcGx5INC60LDQui3QsdGD0LTRgtC+INCx0Ysg0L/QtdGA0LXQstC90YPQu9GB0Y8g0L3QsNC40LfQvdCw0L3QutGDLiDQkiDRgdGC0LDQvdC00LDRgNGC0L3Ri9GFINGB0LjRgtGD0LDRhtC40Y/RhSwg0LrQvtGC0L7RgNGL0LUg0YDQsNGB0YHQvNCw0YLRgNC40LLQsNC70LjRgdGMINGA0LDQvdC10LU6ICANCiog0L/QtdGA0LLRi9C8INCw0YDQs9GD0LzQtdC90YLQvtC8INGI0LXQuyDQvtCx0YrQtdC60YIsINC6INC60L7RgtC+0YDQvtC80YMg0YHQvtCx0LjRgNCw0LvQuNGB0YwsINC/0YDQuNC80LXQvdC40YLRjCDRhNGD0L3QutGG0LjRjiAgDQoqINCy0YLQvtGA0YvQvCDRiNC70LAg0YPQttC1INGB0LDQvNCwINGE0YPQvdC60YbQuNGPICAgDQogIA0K0JfQtNC10YHRjCDQttC1INGPINCy0LjQttGDLCDRh9GC0L4g0LzRiyDQvdCw0L7QsdC+0YDQvtGCINC90LAg0YTRg9C90LrRhtC40Y4g0LLQsdGA0LDRgdGL0LLQsNC10Lwg0LDRgNCz0YPQvNC10L3RgiDRh9C10YDQtdC3INCw0L3QvtC90LjQvNC90YPRjiDRhNGD0L3QutGG0LjRjiAqZnVuY3Rpb24oZikqLCDQsCDQtNCw0LvRjNGI0LUg0YHQvtCx0YHRgtCy0LXQvdC90L4g0LDRgNCz0YPQvNC10L3RgiAqZiouICANCiAgDQojIyDQpNGD0L3QutGG0LjRjyDQutCw0Log0LDRgNCz0YPQvNC10L3RgiDRhNGD0L3QutGG0LjQuA0K0KLQsNC6LCDQvdCw0L/RgNC40LzQtdGALCDQvNC+0LbQvdC+INGB0LTQtdC70LDRgtGMINGE0YPQvdC60YbQuNGOICphcHBseV9mKiwg0LAg0LXQtSDRgdC00LXQu9Cw0YLRjCDQsNGA0LPRg9C80LXQvdGC0L7QvCDRhNGD0L3QutGG0LjQuCAqc2FwcGx5KiANCmBgYHtyfQ0KYXBwbHlfZiA8LSBmdW5jdGlvbihmLCB4KSBmKHgpDQpzYXBwbHkoZnVuX2xpc3QsIGFwcGx5X2YsIHggPSAxOjEwMCkNCmBgYA0K0J/QvtC70YPRh9Cw0Y4g0L7RgtCy0LXRgiDRgtCw0LrQvtC5INC20LUsINC60LDQuiDQuCDQsiDQv9GA0LjQvNC10YDQtSDQstGL0YjQtS4g0KHQvNGL0YHQuyDQsiDRgtC+0LwsINGH0YLQviBhcHBseV9mINC/0YDQvtGB0YLQviDQv9GA0LjQvNC10L3Rj9C10YIg0YTRg9C90LrRhtC40Y4gZiDQuiDQsNGA0LPRg9C80LXQvdGC0YMgeCAoKiJmdW5jdGlvbihmLCB4KSBmKHgpIiopLiDQkCDQsiBzYXBwbHkg0Y3RgtCwINGE0YPQvdC60YbQuNGPLCDQv9C+0LvRg9GH0LDQtdGC0YHRjywg0L/RgNC+0YHRgtC+INC/0LXRgNC10LTQsNC10YIg0YTRg9C90LrRhtC40LggZnVuX2xpc3Qg0LDRgNCz0YPQvNC10L3RgiAieCA9IDE6MTAwIi4gICANCiAgDQrQotC+0YfQvdC+INGC0LDQuiDQttC1INCyINC/0LXRgNC10LzQtdC90L3Rg9GOINC80L7QttC90L4g0YHQvtGF0YDQsNC90LjRgtGMINCw0L3QvtC90LjQvNC90YPRjiDRhNGD0L3QutGG0LjRjiAtINC+0L3QsCDQvdC40YfQtdC8INC90LUg0YXRg9C20LUg0LvRjtCx0L7QuSDQtNGA0YPQs9C+0Lkg0YTRg9C90LrRhtC40LguIA0KYGBge3J9DQphcHBseV9mKGZ1bmN0aW9uKHgpIHN1bSh4XjIpLCAxOjEwKQ0KYGBgDQrQoi7QtS4g0LIg0L/RgNC40LzQtdGA0LUg0LLRi9GI0LUg0LzRiyDQsNGA0LPRg9C80LXQvdGCICoiMToxMCIqINC/0LXRgNC10LTQsNC10Lwg0LDQvdC+0L3QuNC80L3QvtC5INGE0YPQvdC60YbQuNC4LCDQsiDQutC+0YLQvtGA0L7QuSDRgdC60L7QvNCx0LjQvdC40YDQvtCy0LDQvdCwINGE0YPQvdC60YbQuNGPICoic3VtKHheMikiKiwg0YIu0LUuINGB0YPQvNC80LAgKDE6MTApXjIuICAgDQogIA0KKirQmtCw0Log0Y8g0L/QvtC90LjQvNCw0Y4g0L/RgNC40LzQtdC90LXQvdC40LUg0LDQvdC+0L3QuNC80L3QvtC5INGE0YPQvdC60YbQuNC4INC90LAg0LTQsNC90L3QvtC8INGN0YLQsNC/0LU/Kiog0J/QviDRgdGD0YLQuCDQsNC90L7QvdC40LzQvdCw0Y8g0YTRg9C90LrRhtC40Y8g0L/QvtC80L7Qs9Cw0LXRgiDQvdCw0Lwg0L/RgNC40LzQtdC90Y/RgtGMLCDQutCw0LrQuNC1LdGC0L4g0L7RgtC90L7RgdC40YLQtdC70YzQvdGL0LUg0YHQu9C+0LbQvdGL0LUg0LrQvtC80LHQuNC90LDRhtC40Lgg0L3QtdGB0LrQvtC70YzQutC40YUg0YTRg9C90LrRhtC40Lkg0LHQtdC3INC40YUg0LfQsNC/0LjRgdGL0LLQsNC90LjRjyDQsiDQv9Cw0LzRj9GC0Ywg0LrQvtC80L/QsCDQv9C+0LQg0LLQuNC00L7QvCDQvtCx0L7Qu9C+0YfQutC4INC60LDQutC+0Lkt0YLQviDQtdC00LjQvdC+0Lkg0YTRg9C90LrRhtC40LguINCiLtC1LiDQstC80LXRgdGC0L4g0YLQvtCz0L4sINGH0YLQvtCx0Ysg0YHQvtC30LTQsNCy0LDRgtGMINGE0YPQvdC60YbQuNGOIHN1bV9zcSDQuCDQuNC30YDQtdC00LrQsCDQv9GA0LjQvNC10L3Rj9GC0Ywg0LXQtSwg0YLQvtC70YzQutC+INC30LDQsdC40LLQsNGPINC10Lkg0L/QsNC80Y/RgtGMDQpgYGB7cn0NCnN1bV9zcSA8LSBmdW5jdGlvbih4KSB7DQogIHN1bSh4XjIpDQp9DQoNCnN1bV9zcSgxOjEwKQ0KYGBgDQojIyDQpNGD0L3QutGG0LjRjyDQutCw0Log0LLQvtC30LLRgNCw0YnQsNC10LzQvtC1INC30L3QsNGH0LXQvdC40LUg0LjQtyDRhNGD0L3QutGG0LjQuCAoKnJldHVybiB2YWx1ZSopDQrQn9GA0LjQvNC10YA6INC30LDQstC10LTQtdC8INGE0YPQvdC60YbQuNGOLCDQutC+0YLQvtGA0LDRjyDQsiDRgdCy0L7QtdC8INGC0LXQu9C1INCy0L7Qt9Cy0YDQsNGJ0LDQtdGCINC10YnQtSAxINGE0YPQvdC60YbQuNGODQpgYGB7cn0NCnNxdWFyZSA8LSBmdW5jdGlvbigpIGZ1bmN0aW9uKHgpIHheMg0Kc3F1YXJlKCkNCmBgYA0K0JLQuNC00LjQvCwg0YfRgtC+INC10YHQu9C4INC/0YDQvtC/0LjRgdCw0YLRjCDRgtCw0LrRg9GOINC/0YPRgdGC0YPRjiDRhNC90LrRhtC40Y4g0LHQtdC3INCw0YDQs9GD0LzQtdC90YLQsCwg0YLQviDQvdCw0Lwg0LLQvtC30LLRgNCw0YnQsNC10YLRgdGPINCy0LvQvtC20LXQvdC90LDRjyDQsiDQvdC10LUg0YTRg9C90LrRhtC40Y8uINCQINC30L3QsNGH0YLRjCDQvNC+0LbQtdC8INC+0YLQutGA0YvRgtGMINC10YnQtSAxINGB0LrQvtCx0LrQuCDQtNC70Y8g0YLQvtCz0L4sINGH0YLQvtCx0Ysg0L7RgtC00LDRgtGMINCw0YDQs9GD0LzQtdC90YIg0YLQsNC60L7QuSDQstC70L7QttC10L3QvdC+0Lkg0YTRg9C90LrRhtC40LgsINC90LDQv9GA0LjQvNC10YA6DQpgYGB7cn0NCnNxdWFyZSgpKDUpDQpgYGANCiMjINCk0YPQutC90YbQuNC4INCy0L3Rg9GC0YDQuCDRhNGD0L3QutGG0LjQuQ0K0JXRgdGC0LXRgdGC0LLQtdC90L3QviDRhNGD0L3QutGG0LjQuCDQvNC+0LbQvdC+INC+0L/RgNC10LTQtdC70Y/RgtGMINCy0L3Rg9GC0YDQuCDRhNGD0L3QutGG0LjQuCwg0LAg0L3QtSDQsiDQs9C70L7QsdCw0LvRjNC90L7QvCDQvtC60YDRg9C20LXQvdC40LggUi4g0KLQsNC60LDRjyDQstC+0LfQvNC+0LbQvdC+0YHRgtGMINC60LDQuiDRgNCw0Lct0YLQsNC60Lgg0L/QvtC70LXQt9C90LAg0LIg0YHQu9GD0YfQsNC1LCDQutC+0LPQtNCwINC80Ysg0L3QtSDQt9C+0YLQuNC8INC30LDRhdC70LDQvNC70Y/RgtGMINCz0LvQvtCx0LDQu9GM0L3QvtC1INC+0LrRgNGD0LbQtdC90LjQtSDQvtGH0LXRgNC10LTQvdC+0Lkg0YTRg9C90LrRhtC40LXQuSAtINC+0L/RgNC10LTQtdC70Y/RgtGM0YHRjyDQuCDRgNCw0LHQvtGC0LDRgtGMINC+0L3QsCDQsdGD0LTQtdGCINC40YHQutC70Y7Rh9C40YLQtdC70YzQvdC+INCyINGC0LXQu9C1INGB0L/QtdGG0LjQsNC70YzQvdC+INCy0YvQt9GL0LLQsNC10LzQvtC5INC90LDQvNC4INGE0YPQvdC60YbQuNC4LiAgDQogIA0KICAqKtCa0L7Qs9C00LAg0LzQvtC20LXRgiDQv9C+0YLRgNC10LHQvtCy0LDRgtGM0YHRjz8qKiAgDQrQndCw0L/RgNC40LzQtdGALCDQutC+0LPQtNCwINC90LDQvCDQv9GA0LjRhdC+0LTQuNGC0YHRjyDQt9Cw0LLQvtC00LjRgtGMLCDQutCw0LrRg9GOLdGC0L4g0YHQv9C10YbQuNCw0LvRjNC90YPRjiDRhNGD0L3QutGG0LjRjiDQtNC70Y8g0LjRgdC/0L7Qu9C90LXQvdC40Y8g0LTRgNGD0LPQvtC5LiDQotC+0LPQtNCwINC60L7QtCDRgtCw0LrQvtC5INGE0YPQvdC60YbQuNC4INCy0LrQu9Cw0LTRi9Cy0LDQtdC8INC/0YDQvtGB0YLQviDQsiDRgtC10LvQviDQt9Cw0LLQuNGB0LjQvNC+0Lkg0YTRg9C90LrRhtC40Lgg0Lgg0LLRg9Cw0LvRjy4NCmBgYHtyfQ0KZiA8LSBmdW5jdGlvbih4KSB7DQogIGcgPC0gZnVuY3Rpb24oeSkgaWYgKHkgPjApIDEgZWxzZSBpZiAoeSA8IDApIC0xIGVsc2UgMA0KICBzYXBwbHkoeCwgZykNCn0NCmBgYA0K0KIu0LUuINGB0LzRi9GB0Lsg0YLQsNC60L7QuSDQstC70L7QttC10L3QvdC+0Lkg0YTRg9C90LrRhtC40Lgg0LjQtyDQv9GA0LjQvNC10YDQsCwg0YfRgtC+INC+0L3QsCDQsdGD0LTQtdGCINC00L7Qv9C+0LvQvdC40YLQtdC70YzQvdC+INC/0YDQvtCy0LXRgNGP0YLRjCDQt9C90LDQuiAoKy8tKSDQsNGA0LPRg9C80LXQvdGC0LAgeCAo0LrQsNC20LTQvtCz0L4g0Y3Qu9C10LzQtdC90YLQsCDQstC10LrRgtC+0YDQsA0KYGBge3J9DQpmKC0xOjMpDQpgYGANCtCa0L7QvdC10YfQvdC+LCDRgtCw0LrQsNGPINGE0YPQvdC60YbQuNGPINC10YHRgtGMINC4INCyINCx0LDQt9C+0LLQvtC8IFIgLSDRjdGC0L4g0YTRg9C90LrRhtC40Y8gKnNpZ24qDQpgYGB7cn0NCmFsbC5lcXVhbChmKC0xMDA6MTAwKSwgc2lnbigtMTAwOjEwMCkpDQpgYGANCtCe0L/RgNC10LTQtdC70LXQvdC40LUg0YTRg9C90LrRhtC40Lgg0LLQvdGD0YLRgNC4INGE0YPQvdC60YbQuNC4IC0g0L7QtNC40L0g0LjQtyDQstCw0YDQuNCw0L3RgtC+0LIgKtC40L3QutCw0L/RgdGD0LvRj9GG0LjQuCog0LIgUi4g0KHQv9C+0YHQvtCxINGB0L/RgNGP0YLQsNGC0Ywg0YTRg9C90LrRhtC40Y4g0L7RgiDQs9C70L7QsNCx0LvRjNC90L7Qs9C+INC+0LrRgNGD0LbQtdC90LjRjyANCiAgDQogICANCiMjINCY0YHRhdC+0LTQvdGL0Lkg0LrQvtC0INGE0YPQvdC60YbQuNC4INC40LvQuCDQutCw0Log0L/QvtC90Y/RgtGMLCDRh9GC0L4g0LTQtdC70LDQtdGCINGE0YPQvdC60YbQuNGPPw0K0JzQvtC20L3QviDQt9Cw0LPQu9GP0L3Rg9GC0Ywg0LIg0YHQv9GA0LDQstC60YMuINCd0L4g0LjQvdC+0LPQtNCwINGN0YLQvtCz0L4g0LzQvtC20LXRgiDQsdGL0YLRjCDQvdC10LTQvtGB0YLQsNGC0L7Rh9C90L4uINCf0YDQvtGB0YLQtdC50YjQuNC5INGB0LvRg9GH0LDQuSAtINC/0YDQvtC/0LXRh9Cw0YLQsNGC0Ywg0LjQvNGPINGE0YPQvdC60YbQuNC4INCx0LXQtyDRgdC60L7QsdC+0LouINCd0LDQv9GA0LjQvNC10YA6DQpgYGB7cn0NCmYgPC0gZnVuY3Rpb24oeCkgeF41DQpmKDIpDQpmDQpgYGANCtCd0L4g0LjQvdC+0LPQtNCwINCy0YvQstC+0LQg0L7RgtC70LjRh9Cw0LXRgtGB0Y8g0L7RgiDRgdGC0LDQvdC00LDRgNGC0L3QvtCz0L4gUiDQutC+0LTQsC4g0JIg0LLRi9Cy0L7QtNC1INC80L7Qs9GD0YIg0LLRgdGC0YDQtdGC0LjRgtGB0Y8gKi5DKiwgKi5Gb3J0cmFuKiwgKi5FeHRlcm5hbCosICouSW50ZXJuYWwqLCAqLlByaW1pdGl2ZSogLSDRjdGC0L4g0L7QsdGA0LDRidC10L3Qs9C40LUg0Log0YPQttC1INGB0LrQvtC80L/QuNC70LjRgNC+0LLQsNC90L3QvtC80YMg0LrQvtC00YMg0L3QsCDQsdC+0LvQtdC1INC90LjQt9C60L7Rg9GA0L7QstC90LXQstC+0Lwg0Y/Qt9GL0LrQtSwg0YfQsNGJ0LUg0LLRgdC10LPQviBDIC0g0LIg0YLQsNC60L7QuSDRgdC40YLRg9Cw0YbQuNC4INC90YPQttC90L4g0LjRgdC60LDRgtGMINC40YHRhdC+0LTQvdGL0Lkg0LrQvtC0INGB0LDQvNC+0LPQviBSLiDQrdGC0L4g0LzQvtC20LXRgiDQsdGL0YLRjCDQs9C10LzQvtGA0L3Qviwg0L3Qviwg0LIg0L/RgNC40L3RhtC40L/QtSwg0L/RgNC4INC20LXQu9Cw0L3QuNC4INCy0L7Qt9C80L7QttC90L4uICANCiAgDQrQldGB0LvQuCDQsiDQstGL0LLQvtC00LUg0LXRgdGC0YwgKlVzZU1ldGhvZCog0LjQu9C4ICpzdGFuZGFyZEdlbmVyaWMqLCDRgtC+INGN0YLQviDQt9C90LDRh9C40YIsINGH0YLQviDQv9GA0L7QuNGB0YXQvtC00LjRgiDRgi7QvS4gKiptZXRob2QgZGlzcGF0Y2gqKiDQtNC70Y8g0LTQstGD0YUg0YHQuNGB0YLQtdC8INC60LvQsNGB0YHQvtCyIFMzL1M0ICjQv9C+0LvQuNC80L7RgNGE0LjQt9C8LCDQvdCw0L/RgNC40LzQtdGALCBwbG90KQ0KYGBge3J9DQptZXRob2RzKHBsb3QpDQpgYGANCtCS0LjQtNC40LwsINGH0YLQviDQutC+0LvQuNGH0LXRgdGC0LLQviDQvtCx0YrQtdC60YLQvtCyINCy0L3Rg9GC0YDQuCDRhNGD0L3QutGG0LjQuCBwbG90INC00L7QstC+0LvRjNC90L4g0LHQvtC70YzRiNC+0LUsINGCLtC1LiDQtNC70Y8g0LrQsNC20LTQvtC5INC+0L/RgNC10LTQtdC70LXQvdC+INGB0LLQvtC1INC/0L7QstC10LTQtdC90LjQtSDRhNGD0L3QutGG0LjQuCBwbG90LiANCg0KIyMg0JLQvtC30LLRgNCw0YnQsNC10LzQvtC1INC30L3QsNGH0LXQvdC40LUg0LjQtyDRhNGD0L3QutGG0LjQuCANCtCe0L/RgNC10LTQtdC70Y/QtdGC0YHRjyAgICANCtCQKSDQutC70Y7Rh9C10LLRi9C8INGB0LvQvtCy0L7QvCByZXR1cm46DQpgYGB7cn0NCmhhc19uYSA8LSBmdW5jdGlvbih2KSB7DQogIGZvciAoayBpbiB2KSBpZiAoaXMubmEoaykpIHJldHVybihUUlVFKQ0KICAgIHJldHVybihGQUxTRSkNCn0NCmBgYA0K0JrQsNC60L7QtSDQv9C10YDQstC+0LUgKnJldHVybiog0LIg0YLQtdC70LUg0YTRg9C90LrRhtC40Lgg0LLRgdGC0YDQtdGH0LDQtdGC0YHRjyDQuCDQuNGB0L/QvtC70L3Rj9C10YLRgdGPLCDRgtC+INC4INCy0YvQstC+0LTQuNGC0YHRjywg0LIg0YHQu9GD0YfQsNC1INC10YHQu9C4INC40YUg0L3QtdGB0LrQvtC70YzQutC+ICANCtCRKSDQu9C40LHQviDQv9C+0YHQu9C10LTQvdC40Lwg0LLRi9GH0LjRgdC70LXQvdC90YvQvCDQt9C90LDRh9C10L3QuNC10LwgIA0K0J3QsNC/0YDQuNC80LXRgCwg0L/QvtGH0LjRgtCw0Lsg0YHQv9GA0LDQstC60YMg0L/QviAqaXMubmEqINC4INC/0L7QvdGP0LssINGH0YLQviDQvtC90LAg0LLQtdC60YLQvtGA0LjQt9C+0LLQsNC90LAg0Lgg0YHQv9GA0LDQstC40YLRgdGPINGBINC80L7QtdC5INC30LDQtNCw0YfQtdC5INC70YPRh9GI0LUg0Lgg0LHRi9GB0YLRgNC10LUg0YHQsNC80L7Qv9Cw0LvQsCDRgSDRhtC40LrQu9C+0LwNCmBgYHtyfQ0KaGFzX25hIDwtIGZ1bmN0aW9uKHYpIGFueShpcy5uYSh2KSkNCmBgYA0K0JfQtNC10YHRjCByZXR1cm4g0L3QtdGCLCDRgtC+0LvRjNC60L4g0YDQtdC30YPQu9GM0YLQsNGCIGlzLm5hLCDQutC+0YLQvtGA0YvQuSDQuCDQsdGD0LTQtdGCINCy0L7Qt9Cy0YDQsNGJ0LXQvSAgIA0KICANCiAgICANCiMjINCQ0YDQs9GD0LzQtdC90YLRiyDRhNGD0L3QutGG0LjQuSDQv9C+INGD0LzQvtC70YfQsNC90LjRjiAgDQrQnNC+0LbQvdC+INC/0L7RgdC80L7RgtGA0LXRgtGMINC90LAg0LDRgNCz0YPQvNC10L3RgtGLINC/0L4g0YPQvNC+0LvRh9Cw0L3QuNGOINC/0L4g0YLQvtC80YMsINC60LDQuiDQvtCx0YrRj9Cy0LvRj9C10YLRgdGPINC60LDQutCw0Y8t0L3QuNCx0YPQtNGMINGE0YPQvdC60YbQuNGPLiDQndCw0L/RgNC40LzQtdGALCDQstC+0LfRjNC80LXQvCAqc2VxKg0KYGBge3J9DQojINGB0LzQvtGC0YDQuNC8INGB0L/RgNCw0LLQutGDDQo/c2VxDQpgYGANCnNlcShmcm9tID0gMSwgdG8gPSAxLCBieSA9ICgodG8gLSBmcm9tKS8obGVuZ3RoLm91dCAtIDEpKSwNCiAgICBsZW5ndGgub3V0ID0gTlVMTCwgYWxvbmcud2l0aCA9IE5VTEwsIC4uLikgIA0KICAgICAgDQoqINCy0YHQtSDQsNGA0LPRg9C80LXQvdGC0Ysg0LzQvtCz0YPRgiDQuNC80LXRgtGMINC30L3QsNGH0LXQvdC40Y8g0L/QviDRg9C80L7Qu9GH0LDQvdC40Y4gIA0KKiDQt9C90LDRh9C10L3QuNGPINC80L7Qs9GD0YIg0LLRi9GH0LjRgdC70Y/RgtGM0YHRjyDQvdCwINC70LXRgtGDICjQsiDQtNCw0L3QvdC+0Lwg0L/RgNC40LzQtdGA0LUg0YLQsNC6INC/0YDQvtC40YHRhdC+0LTQuNGCINGBINCw0YDQs9GD0LzQtdC90YLQvtC8IGJ5KQ0KYGBge3J9DQpzZXEoKSAjZnJvbSA9IDEsIHRvID0gMQ0KYGBgDQpgYGB7cn0NCnNlcSgxLCA1LCBsZW5ndGgub3V0ID0gMTEpIA0KDQojINGC0L4g0LbQtSDRgdCw0LzQvtC1LCDQutCw0Log0LXRgdC70Lgg0LHRiyDRg9C60LDQt9Cw0LvQuCAiYnkgPSAoNS0xKS8oMTEtMSkiDQpgYGANCiAgDQojIyDQn9GA0LDQstC40LvQsCDRgNCw0LfQsdC+0YDQsCDQsNGA0LPRg9C80LXQvdGC0L7Qsg0K0JLQviDQvNC90L7Qs9C40YUg0YTRg9C90LrRhtC40Y/RhSDQsNGA0LPRg9C80LXQvdGC0L7QsiDQvNC90L7Qs9C+LCDRgdC70L7QttC90LDRjyDRgdGC0YDRg9C60YLRg9GA0LAsINC10YHRgtGMINC00LLQvtC10YLQvtGH0LjRjyDQuCDRgi7QtC4gDQpgYGB7cn0NCtCf0YDQuNCy0LXQtNC10Lwg0L/RgNC40LzQtdGAIA0KYGBge3J9DQpmIDwtIGZ1bmN0aW9uKGFyZzEsIGFyZzIsIHJlbW92ZV9uYSA9IFRSVUUsIC4uLiwgb3B0aW9uYWxfYXJnKSB7fQ0KZigxLCBhcmcyID0gMiwgcmVtb3ZlID0gRiwgb3B0aW9uYWxfYXJnID0gNDIsIGRvX21hZ2ljID0gVFJVRSkNCmBgYA0K0JrQsNC6INGA0LDQt9Cx0LjRgNCw0LXRgtGB0Y8g0YLQsNC60LDRjyDRhNGD0L3QutGG0LjRjz8gIA0K0KDQsNC30LHQvtGAINC/0YDQvtGF0L7QtNC40YIg0LIgMyDRjdGC0LDQv9CwOiAgDQoxLiDQotC+0YfQvdC+0LUg0YHQvtCy0L/QsNC00LXQvdC40LUg0LjQvNC10L3QuCDQsNGA0LPRg9C80LXQvdGC0LAgLSBhcmcyLCBvcHRpb25hbF9hcmcgIA0KMi4g0KfQsNGB0YLQuNGH0L3QvtC1INGB0L7QstC/0LDQtNC10L3QuNC1INC40LzQtdC90Lgg0LDRgNCz0YPQvNC10L3RgtCwICjRgtC+0LvRjNC60L4g0LTQviAuLi4pIC0gcmVtb3ZlX25hICANCjMuINCg0LDQt9Cx0L7RgCDQsNGA0LPRg9C80LXQvdGC0L7QsiDQv9C+INC/0L7Qt9C40YbQuNC4IC0gYXJnMSAgIA0K0J3QtdGA0LDQt9C+0LHRgNCw0L3QvdGL0LUg0LDRgNCz0YPQvNC10L3RgtGLINC/0L7Qv9Cw0LTQsNGO0YIg0LIgLi4uIC0gZG9fbWFnaWMuINCY0Lcg0Y3RgtC+0LPQviDQvNC90L7Qs9C+0YLQvtGH0LjRjyDRgtCw0LrQuNC1INC/0L7QudC80LDQvdC90YvQtSDQsNGA0LPRg9C80LXQvdGC0Ysg0LzQvtC20L3QviDQv9C+0YLQvtC8INC00L7RgdGC0LDRgtGMICAgDQoNCiMjINCQ0YDQs9GD0LzQtdC90YIgLi4uIChlbGxpcHNpcykgLSDQv9GA0L7QsdGA0L7RgSDQsNGA0LPRg9C80LXQvdGC0L7Qsg0K0J7QtNC40L0g0LjQtyDRgdC70YPRh9Cw0LXQsiDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjRjyBlbGxpcHNpcyAtICLQv9GA0L7QuNC30LLQvtC70YzQvdC+0LUg0LrQvtC70LjRh9C10YHRgtCy0L4g0L/QtdGA0LXQtNCw0LLQsNC10LzRi9GFINC+0LHRitC10LrRgtC+0LIiINCy0L3Rg9GC0YDQuCDQutCw0LrQvtC5LdC90LjQsdGD0LTRjCDRhNGD0L3QutGG0LjQuC4g0KLQsNC6LCDQvdCw0L/RgNC40LzQtdGALCDRg9GB0YLRgNC+0LXQvdGLINGE0YPQvdC60YbQuNC4IHN1bSwgYywgY2JpbmQsIHBhc3RlLiAgDQogIA0K0JTRgNGD0LPQvtC5INGF0LDRgNCw0LrRgtC10YDQvdGL0Lkg0YHQu9GD0YfQsNC5IC0gItC/0YDQvtCx0YDQvtGBINCw0YDQs9GD0LzQtdC90YLQvtCyIiwg0LrQvtCz0LTQsCDRhNGD0L3QutGG0LjRjyDQvdC1INC80L7QttC10YIg0L/RgNC+0YfQuNGC0LDRgtGMINC60LDQutC+0Lkt0YLQviDQsNGA0LPRg9C80LXQvdGCICjQvtC9INC90LUg0LfQsNC00LDQvSDQsiDQvdC10Lkg0L/QviDRg9C80L7Qu9GH0LDQvdC40Y4pLNGC0L4g0Y3RgtC+0YIg0LDRgNCz0YPQvNC10L3RgiAi0L/RgNC+0LHRgNCw0YHRi9Cy0LDQtdGC0YHRjyIg0YHQu9C10LTRg9GO0YnQtdC5INGE0YPQvdC60YbQuNC4LCDQsNGA0LPRg9C80LXQvdGC0L7QvCDQutC+0YLQvtGA0L7QuSDRj9Cy0LvRj9C10YLRgdGPINC40YHRhdC+0LTQvdCw0Y8g0YTRg9C90LrRhtC40Y8uINCf0YDQvtGB0YLQvtC5INC/0YDQuNC80LXRgA0KYGBge3J9DQpmIDwtIGZ1bmN0aW9uKHgsIHBvdyA9IDIpIHhecG93DQppbnRlZ3JhdGUoZiwgMCwgMSkgI2xvd2VyID0gMCwgdXBwZXIgPSAxLCBwb3cgPSAyDQpgYGANCtCvINGF0L7Rh9GDINC/0YDQvtC40L3RgtC10LPRgNC40YDQvtCy0LDRgtGMINGE0YPQvdC60YbQuNGOINC+0YIg0L3Rg9C70Y8g0LTQviAxLCDQtNC70Y8g0Y3RgtC+0LPQviDQvNC+0LbQvdC+INCy0L7RgdC/0L7Qu9GM0LfQvtCy0LDRgtGM0YHRjyDRhNGD0L3QutGG0LjQtdC5IGludGVncmF0ZS4g0JIg0L/RgNC40LzQtdGA0LUg0LLRi9GI0LUsINC/0L7RgdC60L7Qu9GM0LrRgyDQvNGLINC90LUg0YPQutCw0LfRi9Cy0LDQtdC8INC00L7Qv9C+0LvQvdC40YLQtdC70YzQvdC+0Lkg0LjQvdGE0L7RgNC80LDRhtC40Lgg0LrQsNGB0LDRgtC10LvRjNC90L4g0YHRgtC10L/QtdC90LgsINGC0L4g0L/RgNC40L3QuNC80LDQtdGC0YHRjyDQt9C90LDRh9C10L3QuNC1INC/0L4g0YPQvNC+0LvRh9Cw0L3QuNGOLiDQoNCw0YHRgdC80L7RgtGA0LjQvCDQv9GA0LjQvNC10YAg0L3QuNC20LU6DQpgYGB7cn0NCmludGVncmF0ZShmLCAwLCAxLCBwb3cgPSA1KQ0KYGBgDQrQktGB0LUg0LLRgNC+0LTQtSDQsdGLINGC0L4g0LbQtSDRgdCw0LzQvtC1LCDQvdC+INGC0LXQv9C10YDRjCDQsiDQsNGA0LPRg9C80LXQvdGC0LDRhSDRhNGD0L3QutGG0LjQuCAqaW50ZWdyYXRlKiDRg9C60LDQt9Cw0LvQuCDQsNGA0LPRg9C80LXQvdGCICpwb3cgPSA1KiAo0L3QtdGCINC00LDQttC1INCw0YDQs9GD0LzQtdC90YLQsCwg0L3QsNGH0LjQvdCw0Y7RidC10LPQvtGB0Y8g0YEgcG93KS4g0JLQsNC20L3QviDRgtC+LCDRh9GC0L4g0YLQsNC60L7Qs9C+INCw0YDQs9GD0LzQtdC90YLQsCDRhNGD0LrQvdGG0LjRjyBpbnRlZ3JhdGUg0L3QtSDQt9C90LDQtdGCLCDQsCDQt9C90LDRh9C40YIg0L7QvdCwINC/0L7Qv9GL0YLQsNC10YLRgdGPICLQv9GA0L7QsdGA0L7RgdC40YLRjCIg0LXQs9C+INCy0LLQtdGA0YUg0L/QviDQu9C10YHQtdC90LrQtSDQstC70L7QttC10L3QvdC+0Lkg0LIg0L3QtdC1INGE0YPQvdC60YbQuNC4LCDQutC+0YLQvtGA0LDRjyDQsiDQvdCw0YjQtdC8INC/0YDQuNC80LXRgNC1INC30L3QsNC10YIg0YLQsNC60L7QuSDQsNGA0LPRg9C80LXQvdGCLCDQv9GA0LjQvdC40LzQsNC10YIg0LXQs9C+INC4INC40LfQvNC10L3Rj9C10YIg0YHQstC+0LUg0LTQtdC50YHRgtCy0LjQtSDQsiDRgdC+0L7RgtCy0LXRgtGB0YLQstC40Lgg0YEg0L/QvtGB0YLRg9C/0LjQstGI0LXQuSDQuNC90YTQvtGA0LzQsNGG0LjQtdC5LiAgIA0KICANCtCt0YLQviDRg9C00L7QsdC90YvQuSDRgdC/0L7RgdC+0LEg0LIgUiDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjRjyDQv9Cw0YDQsNC80LXRgtGA0L7Qsiwg0LrQvtGC0L7RgNGL0LUg0L/QvtC90LDQtNC+0LHRj9GC0YHRjyDQv9C+0YHQu9C10LTRg9GO0YnQuNC8INGE0YPQvdC60YbQuNGP0LwNCg0KIyDQkdC40L3QsNGA0L3Ri9C1INC+0L/QtdGA0LDRgtC+0YDRiyAgDQrQkiBSINC80L7QttC90L4g0YHQvtC30LTQsNCy0LDRgtGMINC90LUg0YLQvtC70YzQutC+INGB0LLQvtC4INGE0YPQvdC60YbQuNC4LCDQvdC+INC4INCx0LjQvdCw0YDQvdGL0LUg0L7Qv9C10YDQsNGC0L7RgNGLICjQvdCw0L/RgNC40LzQtdGALCDQsNGA0LjRhNC80LXRgtC40YfQtdGB0LrQuNC1LCDRgtCw0LrQuNC1INC60LDQuiAiKyIg0LjQu9C4ICIqIiwg0LAg0YLQsNC60LbQtSDRgdC/0LXRhtC40LDQu9GM0L3Ri9C1INC+0L/QtdGA0LDRgtC+0YDRiyAlaW4lLCDQs9C00LUg0LzQtdC20LTRgyAlaW4lINGB0LjQvNCy0L7QuykuICAgDQogIA0K0JTQu9GPINC90LDRh9Cw0LvQsCDQviDQsdC40L3QsNGA0L3Ri9GFINC+0L/QtdGA0LDRgtC+0YDQsNGFIC0g0Y3RgtC+INGC0L7QttC1INGE0YPQvdC60YbQuNC4LCDQutC+0YLQvtGA0YvQtSDQvNC+0LbQvdC+INCy0YvQt9Cy0LDRgtGMINCw0L3QsNC70L7Qs9C40YfQvdC+INC00YDRg9Cz0LjQvCDRhNGD0L3QutGG0LjRj9C8LiDQndCw0L/RgNC40LzQtdGALCDQstGB0LUg0L/QtdGA0LXRh9C40YHQu9C10L3QvdGL0LUg0L3QuNC20LUg0LLRi9GA0LDQttC10L3QuNGPINGN0LrQstC40LLQsNC70LXQvdGC0L3Riw0KYGBge3J9DQoxICsgMQ0KIisiICgxLCAxKQ0KYGBgDQpgYGB7cn0NCjE6NSAlaW4lIGMoMSwyLDUpDQoiJWluJSIgKDE6NSwgYygxLCAyLDUpKQ0KYGBgDQoNCiAgDQrQlNCw0LLQsNC50YLQtSDQv9GA0L7QstC10YDQuNC8LCDQtdGB0YLRjCDQu9C4INCy0YXQvtC20LTQtdC90LjRjyB4INCyIHkNCmBgYHtyfQ0KMTo1ICVpbiUgYygxLDIsNSkNCmBgYA0K0JAg0YLQtdC/0LXRgNGMINGF0L7Rh9GDINGB0L7Qt9C00LDRgtGMINGB0LLQvtC5INGB0L7QsdGB0YLQstC10L3QvdGL0Lkg0LHQuNC90LDRgNC90YvQuSDQvtC/0LXRgNCw0YLQvtGADQpgYGB7cn0NCiIlbmluJSIgPC0gZnVuY3Rpb24oeCwgeSkgISh4ICVpbiUgeSkNCjE6NSAlbmluJSBjKDEsMiw1KQ0KYGBgDQrQk9C70L7RgdGB0LDRgNC40Lk6DQo/ImZ1bmN0aW9uIg0KP21ldGhvZHMNCmFyZ3VtZXQgbWF0Y2hpbmcNCmVsbGlwc2lzICg/Ii4uLiIpDQoNCg0K