Використання оператора циклів for(), що є характерним для мов низького рівня програмування типу Basic, вважається поганим стилем програмування на мові R, орієнтованою на векторизацію обчислень. Замість виконання послідовно скалярних операцій над кожним з елементів масиву, значно ефективніше виконувати паралельні обчислення, за яких програма обробляє одночасно весь масив (вектор) цілком або поелементно в кожен момент часу. Очевидно, що такий підхід потенційно може призвести до значного прискорення однотипних обчислень над великими масивами даних.
Розглянемо найпростіший приклад векторизованих обчислень в R. Припустимо, у нас є вектор з 10 додатних чисел, і ми хочемо обрахувати квадратний корінь кожного із них. Замість написання циклу для почергового виконання цієї операції над кожним елементом, ми просто подаємо весь цей вектор на вхід функції sqrt(), яка повертає вектор із результатами обчислень:
x <- 1:10
sqrt(x)
[1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751
[8] 2.828427 3.000000 3.162278
Принцип векторизованих обчислень застосовують до більш складних об’єктів R – матриць, списків і таблиць даних (для мови R немає різниці між останніми двома типами об’єктів: фактично таблиця даних є списком із декількох компонентів – векторів однакового розміру). У базовій комплектації R є ціле сімейство функцій, призначених для організації векторизованих обчислень над такими об’єктами. У назві всіх цих функцій є слово apply (з англ. застосувати), якому передує літера, що вказує на принцип роботи тієї чи іншої функції (див. докладніше в довідковому файлі ?apply). За такої умови:
- apply() на відміну від for() можна легко розпаралелити, перейменувавши функцію в її паралельну версію з пакету snow;
- алгоритми, записані без циклів, легше змінювати, містять менше помилок і легше набираються в командному рядку;
- результат роботи apply() може бути аргументом функції; крім того, будь-яка функція може бути вставлена в якості аргументу в apply(). Нижче надамо огляд apply-функцій із прикладами використання.
apply()
Функція apply() використовується у випадках, коли необхідно застосувати будь-яку функцію до всіх рядків або стовпців матриці (або масивів більшої розмірності):
apply(x, MARGIN, FUN, ...)
де x – це перетворений об’єкт; MARGIN – індекс, що позначає напрямок процесу обчислень (стовпцями або рядками); FUN – функція, що використовуються для обчислень; … – це будь-які інші параметри функції FUN. Для матриці або таблиці даних MARGIN=1 позначає рядки, а MARGIN=2 – стовпці. Оскільки FUN означає будь-яку функцію R, то функція apply() – це потужний засіб модульної обробки даних. Створимо звичайну двовимірну матрицю:
M <- matrix(seq(1,16), 4, 4)
# Знайдемо мінімальні значення в кожному рядку матриці:
apply(M, 1, min)
[1] 1 2 3 4
# Знайдемо мінімальні значення в кожному стовпці матриці
apply(M, 2, max)
[1] 4 8 12 16
# Приклад із тривимірним масивом:
M <- array(seq(32), dim=c(4,4,2))
# Застосуємо функцію sum() до кожного елементу M[*,],
# тобто виконаємо додавання за вимірами 2 і 3:
apply(M, 1, sum)
[1] 120 128 136 144
# Результат – одновимірний вектор:
# Застосуємо функцію sum() до кожного елементу M[*, *,],
# – тобто виконаємо додавання за третім виміром:
apply(M, c(1,2), sum)
[,1] [,2] [,3] [,4]
[1,] 18 26 34 42
[2,] 20 28 36 44
[3,] 22 30 38 46
[4,] 24 32 40 48
# Результат – матриця:
У разі потреби обчислення суми і середніх значень за рядками або стовпчиках матриць використовувати дуже швидкі і спеціально оптимізовані для цього функції colSums(), rowSums(), colMeans() і rowMeans().
lapply()
Функція lapply() використовується за потреби застосування певної функції до кожної компоненти списку. У такому випадку одержують результат у вигляді списку (буква “l” в назві lapply() означає list – “список”).
# Створимо список із трьома компонентами-векторами:
x <- list(a=1, b=1:3, c=10:100)
# З’ясуємо розмір кожної компоненти списку х (функція length()):
lapply(x, FUN=length)
$a
[1] 1
$b
[1] 3
$c
[1] 91
# Виконаємо додавання елементів у кожній компоненті списку х:
lapply(x, FUN=sum)
$a
[1] 1
$b
[1] 6
$c
[1] 5005
sapply()
Функція sapply() використовується, якщо потрібно застосувати деяку функцію до кожної компоненти списку, і отримати резульат у вигляді вектору (буква “s” в назві sapply() означає simplify – “спростити”).
# Список із трьох компоненті:
x <- list(a=1, b=1:3, c=10:100)
# З’ясуємо розмір кожної компоненти списку х:
sapply(x, FUN=length)
a b c
1 3 91
# Додавання всіх елементів у кожній компоненті списку х:
sapply(x, FUN=sum)
a b c
1 6 5005
У деяких більш “просунутих” випадках sapply() може видати результат у вигляді багатовимірного масиву. Наприклад, якщо застосовувана функція повертає вектори однакової довжини, sapply() об’єднає ці вектори в матрицю (по стовпцях):
sapply(1:5, function(x) rnorm(3, x))
[,1] [,2] [,3] [,4] [,5]
[1,] 1.858850 3.217806 3.908056 3.431791 6.384863
[2,] 1.453731 2.875744 3.221383 5.675227 6.743612
[3,] 1.485595 1.580141 4.426198 2.820517 5.828481
Якщо застосовувана функція повертає матрицю, то sapply() перетворить кожну матрицю у вектор і об’єднає такі вектори в одну велику матрицю:
sapply(1:5, function(x) matrix(x, 2, 2))
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 1 2 3 4 5
[3,] 1 2 3 4 5
[4,] 1 2 3 4 5
Роботу функції sapply(), що наведено в останньому прикладі, можна скасувати з допомогою аргументу simplify="array" – у цьому випадку матриці будуть об’єднані в один багатовимірний масив:
sapply(1:5, function(x) matrix(x,2,2), simplify="array")
, , 1
[,1] [,2]
[1,] 1 1
[2,] 1 1
, , 2
[,1] [,2]
[1,] 2 2
[2,] 2 2
, , 3
[,1] [,2]
[1,] 3 3
[2,] 3 3
, , 4
[,1] [,2]
[1,] 4 4
[2,] 4 4
, , 5
[,1] [,2]
[1,] 5 5
[2,] 5 5
replicate()
Функція replicate() є свого роду “обгорткою” для функції sapply() і дозволяє провести серію обчислень із метою генерації набору чисел відповідно до заданого алгоритму. Синтаксис функції має вигляд:
replicate(n, expr, simplify=TRUE)
де n – число повторів, expr – функція або група виразів, які треба повторити n раз, simplify=TRUE – необов’язковий параметр, який пробує спростити результат і представити його у вигляді вектору або матриці значень.
Розглянемо приклад використання функції replicate() для перевірки статистичної гіпотези про рівність медіан двох вибірок бутстреп-методом (див. розділ 2.7). Створена нами функція boot_med() з кожної вихідної вибірки x і y вилучає по N псевдовибірок, використовуючи алгоритм “випадкового вибору з поверненням”, і знаходить різницю їхніх медіан. Тут функція sample.int() формує цілочисельні набори випадкових індексів indx і indy для кожного з порівнюваних векторів:
boot_med <- function(x, y, N=100) {
replicate(N, {
indx <- sample.int(length(x), length(x), replace=T)
indy <- sample.int(length(y), length(y), replace=T)
median(x[indx]) - median(y[indy])
})
}
Для тестування функції перевіримо однорідність медіан для двох випадкових вибірок із нормального розподілу із середнім mean=10 і стандартним відхиленням sd=4:
Y <- rnorm(100, sd=4, mean=10)
X <- rnorm(100, sd=4, mean=10)
quantile(boot_med(Y, X, 10000), probs=c(0.025, 0.975))
2.5% 97.5%
-0.3757855 1.9518084
Оскільки довірчий інтервал різниці медіан включає 0, то нульову гіпотезу відкидати не слід.
vapply()
Функція vapply() схожа з sapply(), але працює трохи швидше завдяки тому, що користувач однозначно вказує тип значень, що повертаються (буква “v” в назві vapply() означає velocity – “швидкість”). Такий підхід дозволяє також уникати повідомлень про помилки (і переривання обчислень), що виникають під час роботи з sapply() у деяких ситуаціях. Під час виклику vapply() користувач повинен навести приклад очікуваного типу значень, що повертаються. Для цього служить аргумент FUN.VALUE:
# Аргументу FUN.VALUE присвоєно логічне значення FALSE.
# Цим задається тип значень, що повертаються функцією
a <- vapply(NULL, is.factor, FUN.VALUE=FALSE)
# Функція sapply() застосована до того ж NULL-об’єкту:
b <- sapply(NULL, is.factor)
# Перевірка типу змінних:
is.logical(a)
[1] TRUE
is.logical(b)
[1] FALSE
mapply()
Функція mapply() використовується за потреби поелементного застосування будь-якої функції одночасно до декількох об’єктів (наприклад, отримати суму перших елементів векторів, потім суму других елементів векторів, і т.ін.). Результат повертається у вигляді вектору або масиву іншої розмірності (див. приклади для sapply() вище). Буква “m” в назві mapply() означає multivariate – “багатовимірний” (мається на увазі одночасне виконання обчислень над елементами декількох об’єктів).
mapply(sum, 1:5, 1:5, 1:5)
[1] 3 6 9 12 15
Функція rapply() використовується у випадках, коли необхідно застосувати якусь функцію до компонентів вкладеного списку (буква “r” в назві rapply() означає recursively – “рекурсивно”).
# Функція користувача, яка додає ! до елементу
# об’єкту x якщо цей елемент є текстовим виразом,
# або додає 1 якщо цей елемент є числом:
myFun <- function(x) {
if (is.character(x)) {
return(paste(x, "!", sep=""))
}
else {
return(x + 1)
}
}
# Приклад вкладеного списку:
l <- list(a=list(a1="Boo", b1=2, c1="Eeek"),
b=3, c="Yikes",
d=list(a2=1, b2=list(a="Hey", b3=5)))
# Рекурсивне застосування функції myFun до списку l:
rapply(l, myFun)
a.a1 a.b1 a.c1 b c d.a2 d.b2.a
"Boo!" "3" "Eeek!" "4" "Yikes!" "2" "Hey!"
d.b2.b3
"6"
# Якщо необхідно повернути результат у вигляді вкладеного списку,
# можна скористатися аргументом how=“replace”. У цьому випадку # вихідні значення в списку 1 будуть замінені на нові:
rapply(l, myFun, how="replace")
$a
$a$a1
[1] "Boo!"
$a$b1
[1] 3
$a$c1
[1] "Eeek!"
$b
[1] 4
$c
[1] "Yikes!"
$d
$d$a2
[1] 2
$d$b2
$d$b2$a
[1] "Hey!"
$d$b2$b3
[1] 6
tapply()
Функція tapply() використовується у випадках, коли необхідно застосувати будь-яку функцію fun() до окремих груп елементів вектору x, що заданий відповідно до рівнів будь-якого фактору group:
tapply(x, group, fun, ...)
Наприклад, у такому фрагменті коду функція sample() використовується для створення двох випадкових вибірок: з 50 значень цілих чисел від 1 до 4 і пов’язаних із ними міток чотирьох груп A-D. Функція tapply() підраховує суми х для кожного зі значень фактору:
x <- sample(1:4, size=50, replace=T)
gr <- as.factor(sample(c("A", "B", "C", "D"), size=50, replace=T))
tapply(x, gr, sum)
A B C D
29 21 44 33
by()
Функція by() є свого роду аналогом функції tapply(), з тією різницею, що вона застосовується для таблиць. Таблиця data поділяється відповідно до заданого стовпця-фактору group на підмножину підтаблиць і для обробки кожної такої частини визначається функція fun():
by(data, group, fun, ...)
Розглянемо приклад із таблицею Молюски, яка представлена в розділі 1.3, і розрахуємо середні значення довжини раковини ZMlength і чисельності інфузорій CAnumber для кожного з трьох обстежених озер Lake(Баторіно, Мястро й Нарочь):
outer()
Функція outer() дозволяє виконати комбінаторну операцію fun() над елементами двох масивів або векторів x і у, не вдаючись до явного використання “подвійного” циклу:
outer(x, y, fun="*",...)
За умовчанням здійснюється операція попарного перемноження
x <- 1:5
y <- 1:5
outer(x,y)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 4 6 8 10
[3,] 3 6 9 12 15
[4,] 4 8 12 16 20
[5,] 5 10 15 20 25
Використовуючи, наприклад, функцію outer() разом із функцією paste(), можна згенерувати всі можливі попарні комбінації “зв’язок” елементів символьного й цілочисельного векторів:
x <- c("A", "B", "C", "D")
y <- 1:10
outer(x, y, paste, sep="")
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] "A1" "A2" "A3" "A4" "A5" "A6" "A7" "A8" "A9" "A10"
[2,] "B1" "B2" "B3" "B4" "B5" "B6" "B7" "B8" "B9" "B10"
[3,] "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" "C9" "C10"
[4,] "D1" "D2" "D3" "D4" "D5" "D6" "D7" "D8" "D9" "D10"
LS0tDQp0aXRsZTogItCb0LXQutGG0ZbRjyA3LiDQktC10LrRgtC+0YDQuNC30L7QstCw0L3RliDQvtCx0YfQuNGB0LvQtdC90L3RjyDQsiBSINC3INCy0LjQutC+0YDQuNGB0YLQsNC90L3Rj9C8IGFwcGx5LdGE0YPQvdC60YbRltC5Ig0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUNCi0tLQ0KPHN0eWxlPg0KYm9keSB7DQp0ZXh0LWFsaWduOiBqdXN0aWZ5fQ0KPC9zdHlsZT4NCg0KYGBge3IgcGF0aCBhc3NpZ25tZW50LCBlY2hvID0gIkZBTFNFIn0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpvcHRpb25zKGtuaXRyLnRhYmxlLmZvcm1hdCA9ICJodG1sIikNCmBgYA0KDQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgDQrQktC40LrQvtGA0LjRgdGC0LDQvdC90Y8g0L7Qv9C10YDQsNGC0L7RgNCwINGG0LjQutC70ZbQsiBgZm9yKClgLCDRidC+INGUINGF0LDRgNCw0LrRgtC10YDQvdC40Lwg0LTQu9GPINC80L7QsiDQvdC40LfRjNC60L7Qs9C+INGA0ZbQstC90Y8g0L/RgNC+0LPRgNCw0LzRg9Cy0LDQvdC90Y8g0YLQuNC/0YMgQmFzaWMsINCy0LLQsNC20LDRlNGC0YzRgdGPINC/0L7Qs9Cw0L3QuNC8INGB0YLQuNC70LXQvCDQv9GA0L7Qs9GA0LDQvNGD0LLQsNC90L3RjyDQvdCwINC80L7QstGWIFIsINC+0YDRltGU0L3RgtC+0LLQsNC90L7RjiDQvdCwINCy0LXQutGC0L7RgNC40LfQsNGG0ZbRjiDQvtCx0YfQuNGB0LvQtdC90YwuINCX0LDQvNGW0YHRgtGMINCy0LjQutC+0L3QsNC90L3RjyDQv9C+0YHQu9GW0LTQvtCy0L3QviDRgdC60LDQu9GP0YDQvdC40YUg0L7Qv9C10YDQsNGG0ZbQuSDQvdCw0LQg0LrQvtC20L3QuNC8INC3INC10LvQtdC80LXQvdGC0ZbQsiDQvNCw0YHQuNCy0YMsINC30L3QsNGH0L3QviDQtdGE0LXQutGC0LjQstC90ZbRiNC1INCy0LjQutC+0L3Rg9Cy0LDRgtC4INC/0LDRgNCw0LvQtdC70YzQvdGWINC+0LHRh9C40YHQu9C10L3QvdGPLCDQt9CwINGP0LrQuNGFINC/0YDQvtCz0YDQsNC80LAg0L7QsdGA0L7QsdC70Y/RlCDQvtC00L3QvtGH0LDRgdC90L4g0LLQtdGB0Ywg0LzQsNGB0LjQsiAo0LLQtdC60YLQvtGAKSDRhtGW0LvQutC+0Lwg0LDQsdC+INC/0L7QtdC70LXQvNC10L3RgtC90L4g0LIg0LrQvtC20LXQvSDQvNC+0LzQtdC90YIg0YfQsNGB0YMuINCe0YfQtdCy0LjQtNC90L4sINGJ0L4g0YLQsNC60LjQuSDQv9GW0LTRhdGW0LQg0L/QvtGC0LXQvdGG0ZbQudC90L4g0LzQvtC20LUg0L/RgNC40LfQstC10YHRgtC4INC00L4g0LfQvdCw0YfQvdC+0LPQviDQv9GA0LjRgdC60L7RgNC10L3QvdGPINC+0LTQvdC+0YLQuNC/0L3QuNGFINC+0LHRh9C40YHQu9C10L3RjCDQvdCw0LQg0LLQtdC70LjQutC40LzQuCDQvNCw0YHQuNCy0LDQvNC4INC00LDQvdC40YUuDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0KDQvtC30LPQu9GP0L3QtdC80L4g0L3QsNC50L/RgNC+0YHRgtGW0YjQuNC5INC/0YDQuNC60LvQsNC0INCy0LXQutGC0L7RgNC40LfQvtCy0LDQvdC40YUg0L7QsdGH0LjRgdC70LXQvdGMINCyIFIuINCf0YDQuNC/0YPRgdGC0LjQvNC+LCDRgyDQvdCw0YEg0ZQg0LLQtdC60YLQvtGAINC3IDEwINC00L7QtNCw0YLQvdC40YUg0YfQuNGB0LXQuywg0ZYg0LzQuCDRhdC+0YfQtdC80L4g0L7QsdGA0LDRhdGD0LLQsNGC0Lgg0LrQstCw0LTRgNCw0YLQvdC40Lkg0LrQvtGA0ZbQvdGMINC60L7QttC90L7Qs9C+INGW0Lcg0L3QuNGFLiDQl9Cw0LzRltGB0YLRjCDQvdCw0L/QuNGB0LDQvdC90Y8g0YbQuNC60LvRgyDQtNC70Y8g0L/QvtGH0LXRgNCz0L7QstC+0LPQviDQstC40LrQvtC90LDQvdC90Y8g0YbRltGU0Zcg0L7Qv9C10YDQsNGG0ZbRlyDQvdCw0LQg0LrQvtC20L3QuNC8INC10LvQtdC80LXQvdGC0L7QvCwg0LzQuCDQv9GA0L7RgdGC0L4g0L/QvtC00LDRlNC80L4g0LLQtdGB0Ywg0YbQtdC5INCy0LXQutGC0L7RgCDQvdCwINCy0YXRltC0INGE0YPQvdC60YbRltGXIHNxcnQoKSwg0Y/QutCwINC/0L7QstC10YDRgtCw0ZQg0LLQtdC60YLQvtGAINGW0Lcg0YDQtdC30YPQu9GM0YLQsNGC0LDQvNC4INC+0LHRh9C40YHQu9C10L3RjDoNCg0KYGBge3J9DQp4IDwtIDE6MTANCnNxcnQoeCkNCmBgYA0KDQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCf0YDQuNC90YbQuNC/INCy0LXQutGC0L7RgNC40LfQvtCy0LDQvdC40YUg0L7QsdGH0LjRgdC70LXQvdGMINC30LDRgdGC0L7RgdC+0LLRg9GO0YLRjCDQtNC+INCx0ZbQu9GM0Ygg0YHQutC70LDQtNC90LjRhSDQvtCx4oCZ0ZTQutGC0ZbQsiBSIOKAkyDQvNCw0YLRgNC40YbRjCwg0YHQv9C40YHQutGW0LIg0ZYg0YLQsNCx0LvQuNGG0Ywg0LTQsNC90LjRhSAo0LTQu9GPINC80L7QstC4IFIg0L3QtdC80LDRlCDRgNGW0LfQvdC40YbRliDQvNGW0LYg0L7RgdGC0LDQvdC90ZbQvNC4INC00LLQvtC80LAg0YLQuNC/0LDQvNC4INC+0LHigJnRlNC60YLRltCyOiDRhNCw0LrRgtC40YfQvdC+INGC0LDQsdC70LjRhtGPINC00LDQvdC40YUg0ZQg0YHQv9C40YHQutC+0Lwg0ZbQtyDQtNC10LrRltC70YzQutC+0YUg0LrQvtC80L/QvtC90LXQvdGC0ZbQsiDigJMg0LLQtdC60YLQvtGA0ZbQsiDQvtC00L3QsNC60L7QstC+0LPQviDRgNC+0LfQvNGW0YDRgykuINCjINCx0LDQt9C+0LLRltC5INC60L7QvNC/0LvQtdC60YLQsNGG0ZbRlyBSINGUINGG0ZbQu9C1INGB0ZbQvNC10LnRgdGC0LLQviDRhNGD0L3QutGG0ZbQuSwg0L/RgNC40LfQvdCw0YfQtdC90LjRhSDQtNC70Y8g0L7RgNCz0LDQvdGW0LfQsNGG0ZbRlyDQstC10LrRgtC+0YDQuNC30L7QstCw0L3QuNGFINC+0LHRh9C40YHQu9C10L3RjCDQvdCw0LQg0YLQsNC60LjQvNC4INC+0LHigJnRlNC60YLQsNC80LguINCjINC90LDQt9Cy0ZYg0LLRgdGW0YUg0YbQuNGFINGE0YPQvdC60YbRltC5INGUINGB0LvQvtCy0L4gYGFwcGx5YCAo0Lcg0LDQvdCz0LsuICrQt9Cw0YHRgtC+0YHRg9Cy0LDRgtC4KiksINGP0LrQvtC80YMg0L/QtdGA0LXQtNGD0ZQg0LvRltGC0LXRgNCwLCDRidC+INCy0LrQsNC30YPRlCDQvdCwINC/0YDQuNC90YbQuNC/INGA0L7QsdC+0YLQuCDRgtGW0ZTRlyDRh9C4INGW0L3RiNC+0Zcg0YTRg9C90LrRhtGW0ZcgKNC00LjQsi4g0LTQvtC60LvQsNC00L3RltGI0LUg0LIg0LTQvtCy0ZbQtNC60L7QstC+0LzRgyDRhNCw0LnQu9GWIGA/YXBwbHlgKS4g0JfQsCDRgtCw0LrQvtGXINGD0LzQvtCy0Lg6DQoNCiAgKiBhcHBseSgpINC90LAg0LLRltC00LzRltC90YMg0LLRltC0IGZvcigpINC80L7QttC90LAg0LvQtdCz0LrQviDRgNC+0LfQv9Cw0YDQsNC70LXQu9C40YLQuCwg0L/QtdGA0LXQudC80LXQvdGD0LLQsNCy0YjQuCDRhNGD0L3QutGG0ZbRjiDQsiDRl9GXINC/0LDRgNCw0LvQtdC70YzQvdGDINCy0LXRgNGB0ZbRjiDQtyDQv9Cw0LrQtdGC0YMgc25vdzsNCiAgKiDQsNC70LPQvtGA0LjRgtC80LgsINC30LDQv9C40YHQsNC90ZYg0LHQtdC3INGG0LjQutC70ZbQsiwg0LvQtdCz0YjQtSDQt9C80ZbQvdGO0LLQsNGC0LgsINC80ZbRgdGC0Y/RgtGMINC80LXQvdGI0LUg0L/QvtC80LjQu9C+0Log0ZYg0LvQtdCz0YjQtSDQvdCw0LHQuNGA0LDRjtGC0YzRgdGPINCyINC60L7QvNCw0L3QtNC90L7QvNGDINGA0Y/QtNC60YM7DQogICog0YDQtdC30YPQu9GM0YLQsNGCINGA0L7QsdC+0YLQuCBhcHBseSgpINC80L7QttC1INCx0YPRgtC4INCw0YDQs9GD0LzQtdC90YLQvtC8INGE0YPQvdC60YbRltGXOyDQutGA0ZbQvCDRgtC+0LPQviwg0LHRg9C00Ywt0Y/QutCwINGE0YPQvdC60YbRltGPINC80L7QttC1INCx0YPRgtC4INCy0YHRgtCw0LLQu9C10L3QsCDQsiDRj9C60L7RgdGC0ZYg0LDRgNCz0YPQvNC10L3RgtGDINCyIGFwcGx5KCkuDQrQndC40LbRh9C1INC90LDQtNCw0LzQviDQvtCz0LvRj9C0IGFwcGx5LdGE0YPQvdC60YbRltC5INGW0Lcg0L/RgNC40LrQu9Cw0LTQsNC80Lgg0LLQuNC60L7RgNC40YHRgtCw0L3QvdGPLg0KDQojIyNhcHBseSgpDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0KTRg9C90LrRhtGW0Y8gYGFwcGx5KClgINCy0LjQutC+0YDQuNGB0YLQvtCy0YPRlNGC0YzRgdGPINGDINCy0LjQv9Cw0LTQutCw0YUsINC60L7Qu9C4INC90LXQvtCx0YXRltC00L3QviDQt9Cw0YHRgtC+0YHRg9Cy0LDRgtC4INCx0YPQtNGMLdGP0LrRgyDRhNGD0L3QutGG0ZbRjiDQtNC+INCy0YHRltGFINGA0Y/QtNC60ZbQsiDQsNCx0L4g0YHRgtC+0LLQv9GG0ZbQsiDQvNCw0YLRgNC40YbRliAo0LDQsdC+INC80LDRgdC40LLRltCyINCx0ZbQu9GM0YjQvtGXINGA0L7Qt9C80ZbRgNC90L7RgdGC0ZYpOg0KDQpgYGB7cn0NCmFwcGx5KHgsIE1BUkdJTiwgRlVOLCAuLi4pDQpgYGANCg0K0LTQtSBgeGAg4oCTINGG0LUg0L/QtdGA0LXRgtCy0L7RgNC10L3QuNC5INC+0LHigJnRlNC60YI7IGBNQVJHSU5gIOKAkyDRltC90LTQtdC60YEsINGJ0L4g0L/QvtC30L3QsNGH0LDRlCDQvdCw0L/RgNGP0LzQvtC6INC/0YDQvtGG0LXRgdGDINC+0LHRh9C40YHQu9C10L3RjCAo0YHRgtC+0LLQv9GG0Y/QvNC4INCw0LHQviDRgNGP0LTQutCw0LzQuCk7IGBGVU5gIOKAkyDRhNGD0L3QutGG0ZbRjywg0YnQviDQstC40LrQvtGA0LjRgdGC0L7QstGD0Y7RgtGM0YHRjyDQtNC70Y8g0L7QsdGH0LjRgdC70LXQvdGMOyBg4oCmYCDigJMg0YbQtSDQsdGD0LTRjC3Rj9C60ZYg0ZbQvdGI0ZYg0L/QsNGA0LDQvNC10YLRgNC4INGE0YPQvdC60YbRltGXIGBGVU5gLiDQlNC70Y8g0LzQsNGC0YDQuNGG0ZYg0LDQsdC+INGC0LDQsdC70LjRhtGWIGDQtNCw0L3QuNGFIE1BUkdJTj0xYCDQv9C+0LfQvdCw0YfQsNGUINGA0Y/QtNC60LgsINCwIGBNQVJHSU49MmAg4oCTINGB0YLQvtCy0L/RhtGWLiDQntGB0LrRltC70YzQutC4IGBGVU5gINC+0LfQvdCw0YfQsNGUINCx0YPQtNGMLdGP0LrRgyDRhNGD0L3QutGG0ZbRjiBSLCDRgtC+INGE0YPQvdC60YbRltGPIGBhcHBseSgpYCDigJMg0YbQtSDQv9C+0YLRg9C20L3QuNC5INC30LDRgdGW0LEg0LzQvtC00YPQu9GM0L3QvtGXINC+0LHRgNC+0LHQutC4INC00LDQvdC40YUuINCh0YLQstC+0YDQuNC80L4g0LfQstC40YfQsNC50L3RgyDQtNCy0L7QstC40LzRltGA0L3RgyDQvNCw0YLRgNC40YbRjjoNCg0KYGBge3J9DQpNIDwtIG1hdHJpeChzZXEoMSwxNiksIDQsIDQpDQoNCiMg0JfQvdCw0LnQtNC10LzQviDQvNGW0L3RltC80LDQu9GM0L3RliDQt9C90LDRh9C10L3QvdGPINCyINC60L7QttC90L7QvNGDINGA0Y/QtNC60YMg0LzQsNGC0YDQuNGG0ZY6DQphcHBseShNLCAxLCBtaW4pDQoNCiMg0JfQvdCw0LnQtNC10LzQviDQvNGW0L3RltC80LDQu9GM0L3RliDQt9C90LDRh9C10L3QvdGPINCyINC60L7QttC90L7QvNGDINGB0YLQvtCy0L/RhtGWINC80LDRgtGA0LjRhtGWDQphcHBseShNLCAyLCBtYXgpDQoNCiMg0J/RgNC40LrQu9Cw0LQg0ZbQtyDRgtGA0LjQstC40LzRltGA0L3QuNC8INC80LDRgdC40LLQvtC8Og0KTSA8LSBhcnJheShzZXEoMzIpLCBkaW09Yyg0LDQsMikpDQoNCiMg0JfQsNGB0YLQvtGB0YPRlNC80L4g0YTRg9C90LrRhtGW0Y4gc3VtKCkg0LTQviDQutC+0LbQvdC+0LPQviDQtdC70LXQvNC10L3RgtGDIE1bKixdLA0KIyDRgtC+0LHRgtC+INCy0LjQutC+0L3QsNGU0LzQviDQtNC+0LTQsNCy0LDQvdC90Y8g0LfQsCDQstC40LzRltGA0LDQvNC4IDIg0ZYgMzoNCmFwcGx5KE0sIDEsIHN1bSkNCg0KIyDQoNC10LfRg9C70YzRgtCw0YIg4oCTINC+0LTQvdC+0LLQuNC80ZbRgNC90LjQuSDQstC10LrRgtC+0YA6DQojINCX0LDRgdGC0L7RgdGD0ZTQvNC+INGE0YPQvdC60YbRltGOIHN1bSgpINC00L4g0LrQvtC20L3QvtCz0L4g0LXQu9C10LzQtdC90YLRgyBNWyosICosXSwNCiMg4oCTINGC0L7QsdGC0L4g0LLQuNC60L7QvdCw0ZTQvNC+INC00L7QtNCw0LLQsNC90L3RjyDQt9CwINGC0YDQtdGC0ZbQvCDQstC40LzRltGA0L7QvDoNCmFwcGx5KE0sIGMoMSwyKSwgc3VtKQ0KDQojINCg0LXQt9GD0LvRjNGC0LDRgiDigJMg0LzQsNGC0YDQuNGG0Y86DQpgYGANCg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7DQrQoyDRgNCw0LfRliDQv9C+0YLRgNC10LHQuCDQvtCx0YfQuNGB0LvQtdC90L3RjyDRgdGD0LzQuCDRliDRgdC10YDQtdC00L3RltGFINC30L3QsNGH0LXQvdGMINC30LAg0YDRj9C00LrQsNC80Lgg0LDQsdC+INGB0YLQvtCy0L/Rh9C40LrQsNGFINC80LDRgtGA0LjRhtGMINCy0LjQutC+0YDQuNGB0YLQvtCy0YPQstCw0YLQuCDQtNGD0LbQtSDRiNCy0LjQtNC60ZYg0ZYg0YHQv9C10YbRltCw0LvRjNC90L4g0L7Qv9GC0LjQvNGW0LfQvtCy0LDQvdGWINC00LvRjyDRhtGM0L7Qs9C+INGE0YPQvdC60YbRltGXIGBjb2xTdW1zKClgLCBgcm93U3VtcygpYCwgYGNvbE1lYW5zKClgINGWIGByb3dNZWFucygpYC4NCg0KIyMjbGFwcGx5KCkNCg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7DQrQpNGD0L3QutGG0ZbRjyBgbGFwcGx5KClgINCy0LjQutC+0YDQuNGB0YLQvtCy0YPRlNGC0YzRgdGPINC30LAg0L/QvtGC0YDQtdCx0Lgg0LfQsNGB0YLQvtGB0YPQstCw0L3QvdGPINC/0LXQstC90L7RlyDRhNGD0L3QutGG0ZbRlyDQtNC+INC60L7QttC90L7RlyDQutC+0LzQv9C+0L3QtdC90YLQuCDRgdC/0LjRgdC60YMuINCjINGC0LDQutC+0LzRgyDQstC40L/QsNC00LrRgyDQvtC00LXRgNC20YPRjtGC0Ywg0YDQtdC30YPQu9GM0YLQsNGCINGDINCy0LjQs9C70Y/QtNGWINGB0L/QuNGB0LrRgyAo0LHRg9C60LLQsCDigJxs4oCdINCyINC90LDQt9Cy0ZYgYGxhcHBseSgpYCDQvtC30L3QsNGH0LDRlCAqbGlzdCog4oCTIOKAnNGB0L/QuNGB0L7QuuKAnSkuDQoNCmBgYHtyfQ0KIyDQodGC0LLQvtGA0LjQvNC+INGB0L/QuNGB0L7QuiDRltC3INGC0YDRjNC+0LzQsCDQutC+0LzQv9C+0L3QtdC90YLQsNC80Lgt0LLQtdC60YLQvtGA0LDQvNC4Og0KeCA8LSBsaXN0KGE9MSwgYj0xOjMsIGM9MTA6MTAwKQ0KDQojINCX4oCZ0Y/RgdGD0ZTQvNC+INGA0L7Qt9C80ZbRgCDQutC+0LbQvdC+0Zcg0LrQvtC80L/QvtC90LXQvdGC0Lgg0YHQv9C40YHQutGDINGFICjRhNGD0L3QutGG0ZbRjyBsZW5ndGgoKSk6DQpsYXBwbHkoeCwgRlVOPWxlbmd0aCkNCg0KIyDQktC40LrQvtC90LDRlNC80L4g0LTQvtC00LDQstCw0L3QvdGPINC10LvQtdC80LXQvdGC0ZbQsiDRgyDQutC+0LbQvdGW0Lkg0LrQvtC80L/QvtC90LXQvdGC0ZYg0YHQv9C40YHQutGDINGFOg0KbGFwcGx5KHgsIEZVTj1zdW0pDQpgYGANCg0KIyMjc2FwcGx5KCkNCg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IA0K0KTRg9C90LrRhtGW0Y8gYHNhcHBseSgpYCDQstC40LrQvtGA0LjRgdGC0L7QstGD0ZTRgtGM0YHRjywg0Y/QutGJ0L4g0L/QvtGC0YDRltCx0L3QviDQt9Cw0YHRgtC+0YHRg9Cy0LDRgtC4INC00LXRj9C60YMg0YTRg9C90LrRhtGW0Y4g0LTQviDQutC+0LbQvdC+0Zcg0LrQvtC80L/QvtC90LXQvdGC0Lgg0YHQv9C40YHQutGDLCDRliDQvtGC0YDQuNC80LDRgtC4INGA0LXQt9GD0LvRjNCw0YIg0YMg0LLQuNCz0LvRj9C00ZYg0LLQtdC60YLQvtGA0YMgKNCx0YPQutCy0LAg4oCcc+KAnSDQsiDQvdCw0LfQstGWIGBzYXBwbHkoKWAg0L7Qt9C90LDRh9Cw0ZQgKnNpbXBsaWZ5KiDigJMg4oCc0YHQv9GA0L7RgdGC0LjRgtC44oCdKS4NCg0KYGBge3J9DQojINCh0L/QuNGB0L7QuiDRltC3INGC0YDRjNC+0YUg0LrQvtC80L/QvtC90LXQvdGC0ZY6DQp4IDwtIGxpc3QoYT0xLCBiPTE6MywgYz0xMDoxMDApDQoNCiMg0JfigJnRj9GB0YPRlNC80L4g0YDQvtC30LzRltGAINC60L7QttC90L7RlyDQutC+0LzQv9C+0L3QtdC90YLQuCDRgdC/0LjRgdC60YMg0YU6DQpzYXBwbHkoeCwgRlVOPWxlbmd0aCkNCg0KIyDQlNC+0LTQsNCy0LDQvdC90Y8g0LLRgdGW0YUg0LXQu9C10LzQtdC90YLRltCyINGDINC60L7QttC90ZbQuSDQutC+0LzQv9C+0L3QtdC90YLRliDRgdC/0LjRgdC60YMg0YU6DQpzYXBwbHkoeCwgRlVOPXN1bSkNCmBgYA0KDQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCjINC00LXRj9C60LjRhSDQsdGW0LvRjNGIIOKAnNC/0YDQvtGB0YPQvdGD0YLQuNGF4oCdINCy0LjQv9Cw0LTQutCw0YUgYHNhcHBseSgpYCDQvNC+0LbQtSDQstC40LTQsNGC0Lgg0YDQtdC30YPQu9GM0YLQsNGCINGDINCy0LjQs9C70Y/QtNGWINCx0LDQs9Cw0YLQvtCy0LjQvNGW0YDQvdC+0LPQviDQvNCw0YHQuNCy0YMuINCd0LDQv9GA0LjQutC70LDQtCwg0Y/QutGJ0L4g0LfQsNGB0YLQvtGB0L7QstGD0LLQsNC90LAg0YTRg9C90LrRhtGW0Y8g0L/QvtCy0LXRgNGC0LDRlCDQstC10LrRgtC+0YDQuCDQvtC00L3QsNC60L7QstC+0Zcg0LTQvtCy0LbQuNC90LgsIGBzYXBwbHkoKWAg0L7QseKAmdGU0LTQvdCw0ZQg0YbRliDQstC10LrRgtC+0YDQuCDQsiDQvNCw0YLRgNC40YbRjiAo0L/QviDRgdGC0L7QstC/0YbRj9GFKToNCg0KYGBge3J9DQpzYXBwbHkoMTo1LCBmdW5jdGlvbih4KSBybm9ybSgzLCB4KSkNCmBgYA0KDQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCv0LrRidC+INC30LDRgdGC0L7RgdC+0LLRg9Cy0LDQvdCwINGE0YPQvdC60YbRltGPINC/0L7QstC10YDRgtCw0ZQg0LzQsNGC0YDQuNGG0Y4sINGC0L4gYHNhcHBseSgpYCDQv9C10YDQtdGC0LLQvtGA0LjRgtGMINC60L7QttC90YMg0LzQsNGC0YDQuNGG0Y4g0YMg0LLQtdC60YLQvtGAINGWINC+0LHigJnRlNC00L3QsNGUINGC0LDQutGWINCy0LXQutGC0L7RgNC4INCyINC+0LTQvdGDINCy0LXQu9C40LrRgyDQvNCw0YLRgNC40YbRjjoNCg0KYGBge3J9DQpzYXBwbHkoMTo1LCBmdW5jdGlvbih4KSBtYXRyaXgoeCwgMiwgMikpDQpgYGANCg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7DQrQoNC+0LHQvtGC0YMg0YTRg9C90LrRhtGW0ZcgYHNhcHBseSgpYCwg0YnQviDQvdCw0LLQtdC00LXQvdC+INCyINC+0YHRgtCw0L3QvdGM0L7QvNGDINC/0YDQuNC60LvQsNC00ZYsINC80L7QttC90LAg0YHQutCw0YHRg9Cy0LDRgtC4INC3INC00L7Qv9C+0LzQvtCz0L7RjiDQsNGA0LPRg9C80LXQvdGC0YMgYHNpbXBsaWZ5PSJhcnJheSJgIOKAkyDRgyDRhtGM0L7QvNGDINCy0LjQv9Cw0LTQutGDINC80LDRgtGA0LjRhtGWINCx0YPQtNGD0YLRjCDQvtCx4oCZ0ZTQtNC90LDQvdGWINCyINC+0LTQuNC9INCx0LDQs9Cw0YLQvtCy0LjQvNGW0YDQvdC40Lkg0LzQsNGB0LjQsjoNCg0KYGBge3J9DQpzYXBwbHkoMTo1LCBmdW5jdGlvbih4KSBtYXRyaXgoeCwyLDIpLCBzaW1wbGlmeT0iYXJyYXkiKQ0KYGBgDQoNCiMjI3JlcGxpY2F0ZSgpDQogDQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCk0YPQvdC60YbRltGPIGByZXBsaWNhdGUoKWAg0ZQg0YHQstC+0LPQviDRgNC+0LTRgyDigJzQvtCx0LPQvtGA0YLQutC+0Y7igJ0g0LTQu9GPINGE0YPQvdC60YbRltGXIGBzYXBwbHkoKWAg0ZYg0LTQvtC30LLQvtC70Y/RlCDQv9GA0L7QstC10YHRgtC4INGB0LXRgNGW0Y4g0L7QsdGH0LjRgdC70LXQvdGMINGW0Lcg0LzQtdGC0L7RjiDQs9C10L3QtdGA0LDRhtGW0Zcg0L3QsNCx0L7RgNGDINGH0LjRgdC10Lsg0LLRltC00L/QvtCy0ZbQtNC90L4g0LTQviDQt9Cw0LTQsNC90L7Qs9C+INCw0LvQs9C+0YDQuNGC0LzRgy4g0KHQuNC90YLQsNC60YHQuNGBINGE0YPQvdC60YbRltGXINC80LDRlCDQstC40LPQu9GP0LQ6DQoNCmBgYHtyfQ0KcmVwbGljYXRlKG4sIGV4cHIsIHNpbXBsaWZ5PVRSVUUpDQpgYGANCg0K0LTQtSBgbmAg4oCTINGH0LjRgdC70L4g0L/QvtCy0YLQvtGA0ZbQsiwgYGV4cHJgIOKAkyDRhNGD0L3QutGG0ZbRjyDQsNCx0L4g0LPRgNGD0L/QsCDQstC40YDQsNC30ZbQsiwg0Y/QutGWINGC0YDQtdCx0LAg0L/QvtCy0YLQvtGA0LjRgtC4IGBuYCDRgNCw0LcsIGBzaW1wbGlmeT1UUlVFYCDigJMg0L3QtdC+0LHQvtCy4oCZ0Y/Qt9C60L7QstC40Lkg0L/QsNGA0LDQvNC10YLRgCwg0Y/QutC40Lkg0L/RgNC+0LHRg9GUINGB0L/RgNC+0YHRgtC40YLQuCDRgNC10LfRg9C70YzRgtCw0YIg0ZYg0L/RgNC10LTRgdGC0LDQstC40YLQuCDQudC+0LPQviDRgyDQstC40LPQu9GP0LTRliDQstC10LrRgtC+0YDRgyDQsNCx0L4g0LzQsNGC0YDQuNGG0ZYg0LfQvdCw0YfQtdC90YwuDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0KDQvtC30LPQu9GP0L3QtdC80L4g0L/RgNC40LrQu9Cw0LQg0LLQuNC60L7RgNC40YHRgtCw0L3QvdGPINGE0YPQvdC60YbRltGXIGByZXBsaWNhdGUoKWAg0LTQu9GPINC/0LXRgNC10LLRltGA0LrQuCDRgdGC0LDRgtC40YHRgtC40YfQvdC+0Zcg0LPRltC/0L7RgtC10LfQuCDQv9GA0L4g0YDRltCy0L3RltGB0YLRjCDQvNC10LTRltCw0L0g0LTQstC+0YUg0LLQuNCx0ZbRgNC+0Log0LHRg9GC0YHRgtGA0LXQvy3QvNC10YLQvtC00L7QvCAoKirQtNC40LIuINGA0L7Qt9C00ZbQuyAyLjcqKikuINCh0YLQstC+0YDQtdC90LAg0L3QsNC80Lgg0YTRg9C90LrRhtGW0Y8gYGJvb3RfbWVkKClgINC3INC60L7QttC90L7RlyDQstC40YXRltC00L3QvtGXINCy0LjQsdGW0YDQutC4IGB4YCDRliBgeWAg0LLQuNC70YPRh9Cw0ZQg0L/QviBgTmAg0L/RgdC10LLQtNC+0LLQuNCx0ZbRgNC+0LosINCy0LjQutC+0YDQuNGB0YLQvtCy0YPRjtGH0Lgg0LDQu9Cz0L7RgNC40YLQvCDigJzQstC40L/QsNC00LrQvtCy0L7Qs9C+INCy0LjQsdC+0YDRgyDQtyDQv9C+0LLQtdGA0L3QtdC90L3Rj9C84oCdLCDRliDQt9C90LDRhdC+0LTQuNGC0Ywg0YDRltC30L3QuNGG0Y4g0ZfRhdC90ZbRhSDQvNC10LTRltCw0L0uINCi0YPRgiDRhNGD0L3QutGG0ZbRjyBgc2FtcGxlLmludCgpYCDRhNC+0YDQvNGD0ZQg0YbRltC70L7Rh9C40YHQtdC70YzQvdGWINC90LDQsdC+0YDQuCDQstC40L/QsNC00LrQvtCy0LjRhSDRltC90LTQtdC60YHRltCyIGluZHgg0ZYgaW5keSDQtNC70Y8g0LrQvtC20L3QvtCz0L4g0Lcg0L/QvtGA0ZbQstC90Y7QstCw0L3QuNGFINCy0LXQutGC0L7RgNGW0LI6DQoNCmBgYHtyfQ0KYm9vdF9tZWQgPC0gZnVuY3Rpb24oeCwgeSwgTj0xMDApIHsNCiAgcmVwbGljYXRlKE4sIHsNCiAgICBpbmR4IDwtIHNhbXBsZS5pbnQobGVuZ3RoKHgpLCBsZW5ndGgoeCksIHJlcGxhY2U9VCkNCiAgICBpbmR5IDwtIHNhbXBsZS5pbnQobGVuZ3RoKHkpLCBsZW5ndGgoeSksIHJlcGxhY2U9VCkNCiAgICBtZWRpYW4oeFtpbmR4XSkgLSBtZWRpYW4oeVtpbmR5XSkNCiAgICB9KQ0KICB9DQpgYGANCg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7DQrQlNC70Y8g0YLQtdGB0YLRg9Cy0LDQvdC90Y8g0YTRg9C90LrRhtGW0Zcg0L/QtdGA0LXQstGW0YDQuNC80L4g0L7QtNC90L7RgNGW0LTQvdGW0YHRgtGMINC80LXQtNGW0LDQvSDQtNC70Y8g0LTQstC+0YUg0LLQuNC/0LDQtNC60L7QstC40YUg0LLQuNCx0ZbRgNC+0Log0ZbQtyDQvdC+0YDQvNCw0LvRjNC90L7Qs9C+INGA0L7Qt9C/0L7QtNGW0LvRgyDRltC3INGB0LXRgNC10LTQvdGW0LwgYG1lYW49MTBgINGWINGB0YLQsNC90LTQsNGA0YLQvdC40Lwg0LLRltC00YXQuNC70LXQvdC90Y/QvCBgc2Q9NGA6DQoNCmBgYHtyfQ0KWSA8LSBybm9ybSgxMDAsIHNkPTQsIG1lYW49MTApDQpYIDwtIHJub3JtKDEwMCwgc2Q9NCwgbWVhbj0xMCkNCnF1YW50aWxlKGJvb3RfbWVkKFksIFgsIDEwMDAwKSwgcHJvYnM9YygwLjAyNSwgMC45NzUpKQ0KYGBgDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0J7RgdC60ZbQu9GM0LrQuCDQtNC+0LLRltGA0YfQuNC5INGW0L3RgtC10YDQstCw0Lsg0YDRltC30L3QuNGG0ZYg0LzQtdC00ZbQsNC9INCy0LrQu9GO0YfQsNGUIDAsINGC0L4g0L3Rg9C70YzQvtCy0YMg0LPRltC/0L7RgtC10LfRgyDQstGW0LTQutC40LTQsNGC0Lgg0L3QtSDRgdC70ZbQtC4NCg0KIyMjdmFwcGx5KCkNCg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7DQrQpNGD0L3QutGG0ZbRjyBgdmFwcGx5KClgINGB0YXQvtC20LAg0LcgYHNhcHBseSgpYCwg0LDQu9C1INC/0YDQsNGG0Y7RlCDRgtGA0L7RhdC4INGI0LLQuNC00YjQtSDQt9Cw0LLQtNGP0LrQuCDRgtC+0LzRgywg0YnQviDQutC+0YDQuNGB0YLRg9Cy0LDRhyDQvtC00L3QvtC30L3QsNGH0L3QviDQstC60LDQt9GD0ZQg0YLQuNC/INC30L3QsNGH0LXQvdGMLCDRidC+INC/0L7QstC10YDRgtCw0Y7RgtGM0YHRjyAo0LHRg9C60LLQsCDigJx24oCdINCyINC90LDQt9Cy0ZYgYHZhcHBseSgpYCDQvtC30L3QsNGH0LDRlCAqdmVsb2NpdHkqIOKAkyDigJzRiNCy0LjQtNC60ZbRgdGC0YzigJ0pLiDQotCw0LrQuNC5INC/0ZbQtNGF0ZbQtCDQtNC+0LfQstC+0LvRj9GUINGC0LDQutC+0LYg0YPQvdC40LrQsNGC0Lgg0L/QvtCy0ZbQtNC+0LzQu9C10L3RjCDQv9GA0L4g0L/QvtC80LjQu9C60LggKNGWINC/0LXRgNC10YDQuNCy0LDQvdC90Y8g0L7QsdGH0LjRgdC70LXQvdGMKSwg0YnQviDQstC40L3QuNC60LDRjtGC0Ywg0L/RltC0INGH0LDRgSDRgNC+0LHQvtGC0Lgg0LcgYHNhcHBseSgpYCDRgyDQtNC10Y/QutC40YUg0YHQuNGC0YPQsNGG0ZbRj9GFLiDQn9GW0LQg0YfQsNGBINCy0LjQutC70LjQutGDIGB2YXBwbHkoKWAg0LrQvtGA0LjRgdGC0YPQstCw0Ycg0L/QvtCy0LjQvdC10L0g0L3QsNCy0LXRgdGC0Lgg0L/RgNC40LrQu9Cw0LQg0L7Rh9GW0LrRg9Cy0LDQvdC+0LPQviDRgtC40L/RgyDQt9C90LDRh9C10L3RjCwg0YnQviDQv9C+0LLQtdGA0YLQsNGO0YLRjNGB0Y8uINCU0LvRjyDRhtGM0L7Qs9C+INGB0LvRg9C20LjRgtGMINCw0YDQs9GD0LzQtdC90YIgYEZVTi5WQUxVRWA6DQoNCmBgYHtyfQ0KIyDQkNGA0LPRg9C80LXQvdGC0YMgRlVOLlZBTFVFINC/0YDQuNGB0LLQvtGU0L3QviDQu9C+0LPRltGH0L3QtSDQt9C90LDRh9C10L3QvdGPIEZBTFNFLg0KIyDQptC40Lwg0LfQsNC00LDRlNGC0YzRgdGPINGC0LjQvyDQt9C90LDRh9C10L3RjCwg0YnQviDQv9C+0LLQtdGA0YLQsNGO0YLRjNGB0Y8g0YTRg9C90LrRhtGW0ZTRjg0KYSA8LSB2YXBwbHkoTlVMTCwgaXMuZmFjdG9yLCBGVU4uVkFMVUU9RkFMU0UpDQoNCiMg0KTRg9C90LrRhtGW0Y8gc2FwcGx5KCkg0LfQsNGB0YLQvtGB0L7QstCw0L3QsCDQtNC+INGC0L7Qs9C+INC2IE5VTEwt0L7QseKAmdGU0LrRgtGDOg0KYiA8LSBzYXBwbHkoTlVMTCwgaXMuZmFjdG9yKQ0KDQojINCf0LXRgNC10LLRltGA0LrQsCDRgtC40L/RgyDQt9C80ZbQvdC90LjRhToNCmlzLmxvZ2ljYWwoYSkNCmlzLmxvZ2ljYWwoYikNCmBgYA0KDQojIyNtYXBwbHkoKQ0KDQogJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7DQrQpNGD0L3QutGG0ZbRjyBgbWFwcGx5KClgINCy0LjQutC+0YDQuNGB0YLQvtCy0YPRlNGC0YzRgdGPINC30LAg0L/QvtGC0YDQtdCx0Lgg0L/QvtC10LvQtdC80LXQvdGC0L3QvtCz0L4g0LfQsNGB0YLQvtGB0YPQstCw0L3QvdGPINCx0YPQtNGMLdGP0LrQvtGXINGE0YPQvdC60YbRltGXINC+0LTQvdC+0YfQsNGB0L3QviDQtNC+INC00LXQutGW0LvRjNC60L7RhSDQvtCx4oCZ0ZTQutGC0ZbQsiAo0L3QsNC/0YDQuNC60LvQsNC0LCDQvtGC0YDQuNC80LDRgtC4INGB0YPQvNGDINC/0LXRgNGI0LjRhSDQtdC70LXQvNC10L3RgtGW0LIg0LLQtdC60YLQvtGA0ZbQsiwg0L/QvtGC0ZbQvCDRgdGD0LzRgyDQtNGA0YPQs9C40YUg0LXQu9C10LzQtdC90YLRltCyINCy0LXQutGC0L7RgNGW0LIsINGWINGCLtGW0L0uKS4g0KDQtdC30YPQu9GM0YLQsNGCINC/0L7QstC10YDRgtCw0ZTRgtGM0YHRjyDRgyDQstC40LPQu9GP0LTRliDQstC10LrRgtC+0YDRgyDQsNCx0L4g0LzQsNGB0LjQstGDINGW0L3RiNC+0Zcg0YDQvtC30LzRltGA0L3QvtGB0YLRliAo0LTQuNCyLiDQv9GA0LjQutC70LDQtNC4INC00LvRjyBgc2FwcGx5KClgINCy0LjRidC1KS4g0JHRg9C60LLQsCDigJxt4oCdINCyINC90LDQt9Cy0ZYgYG1hcHBseSgpYCDQvtC30L3QsNGH0LDRlCAqbXVsdGl2YXJpYXRlKiDigJMg4oCc0LHQsNCz0LDRgtC+0LLQuNC80ZbRgNC90LjQueKAnSAo0LzQsNGU0YLRjNGB0Y8g0L3QsCDRg9Cy0LDQt9GWINC+0LTQvdC+0YfQsNGB0L3QtSDQstC40LrQvtC90LDQvdC90Y8g0L7QsdGH0LjRgdC70LXQvdGMINC90LDQtCDQtdC70LXQvNC10L3RgtCw0LzQuCDQtNC10LrRltC70YzQutC+0YUg0L7QseKAmdGU0LrRgtGW0LIpLg0KDQpgYGB7cn0NCm1hcHBseShzdW0sIDE6NSwgMTo1LCAxOjUpDQpgYGANCiANCiAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCk0YPQvdC60YbRltGPIGByYXBwbHkoKWAg0LLQuNC60L7RgNC40YHRgtC+0LLRg9GU0YLRjNGB0Y8g0YMg0LLQuNC/0LDQtNC60LDRhSwg0LrQvtC70Lgg0L3QtdC+0LHRhdGW0LTQvdC+INC30LDRgdGC0L7RgdGD0LLQsNGC0Lgg0Y/QutGD0YHRjCDRhNGD0L3QutGG0ZbRjiDQtNC+INC60L7QvNC/0L7QvdC10L3RgtGW0LIg0LLQutC70LDQtNC10L3QvtCz0L4g0YHQv9C40YHQutGDICjQsdGD0LrQstCwIOKAnHLigJ0g0LIg0L3QsNC30LLRliBgcmFwcGx5KClgINC+0LfQvdCw0YfQsNGUICpyZWN1cnNpdmVseSog4oCTIOKAnNGA0LXQutGD0YDRgdC40LLQvdC+4oCdKS4NCg0KYGBge3J9DQojINCk0YPQvdC60YbRltGPINC60L7RgNC40YHRgtGD0LLQsNGH0LAsINGP0LrQsCDQtNC+0LTQsNGUICEg0LTQviDQtdC70LXQvNC10L3RgtGDDQojINC+0LHigJnRlNC60YLRgyB4INGP0LrRidC+INGG0LXQuSDQtdC70LXQvNC10L3RgiDRlCDRgtC10LrRgdGC0L7QstC40Lwg0LLQuNGA0LDQt9C+0LwsDQojINCw0LHQviDQtNC+0LTQsNGUIDEg0Y/QutGJ0L4g0YbQtdC5INC10LvQtdC80LXQvdGCINGUINGH0LjRgdC70L7QvDoNCm15RnVuIDwtIGZ1bmN0aW9uKHgpIHsNCiAgaWYgKGlzLmNoYXJhY3Rlcih4KSkgew0KICAgIHJldHVybihwYXN0ZSh4LCAiISIsIHNlcD0iIikpDQogICAgfQ0KICBlbHNlIHsNCiAgICByZXR1cm4oeCArIDEpDQogICAgfQ0KICB9DQpgYGANCg0KYGBge3J9DQojINCf0YDQuNC60LvQsNC0INCy0LrQu9Cw0LTQtdC90L7Qs9C+INGB0L/QuNGB0LrRgzoNCmwgPC0gbGlzdChhPWxpc3QoYTE9IkJvbyIsIGIxPTIsIGMxPSJFZWVrIiksDQogICAgICAgICAgYj0zLCBjPSJZaWtlcyIsDQogICAgICAgICAgZD1saXN0KGEyPTEsIGIyPWxpc3QoYT0iSGV5IiwgYjM9NSkpKQ0KYGBgDQogDQpgYGB7cn0NCiMg0KDQtdC60YPRgNGB0LjQstC90LUg0LfQsNGB0YLQvtGB0YPQstCw0L3QvdGPINGE0YPQvdC60YbRltGXIG15RnVuINC00L4g0YHQv9C40YHQutGDIGw6DQpyYXBwbHkobCwgbXlGdW4pDQpgYGANCiANCmBgYHtyfQ0KIyDQr9C60YnQviDQvdC10L7QsdGF0ZbQtNC90L4g0L/QvtCy0LXRgNC90YPRgtC4INGA0LXQt9GD0LvRjNGC0LDRgiDRgyDQstC40LPQu9GP0LTRliDQstC60LvQsNC00LXQvdC+0LPQviDRgdC/0LjRgdC60YMsDQojINC80L7QttC90LAg0YHQutC+0YDQuNGB0YLQsNGC0LjRgdGPINCw0YDQs9GD0LzQtdC90YLQvtC8IGhvdz3igJxyZXBsYWNl4oCdLiDQoyDRhtGM0L7QvNGDINCy0LjQv9Cw0LTQutGDICMg0LLQuNGF0ZbQtNC90ZYg0LfQvdCw0YfQtdC90L3RjyDQsiDRgdC/0LjRgdC60YMgMSDQsdGD0LTRg9GC0Ywg0LfQsNC80ZbQvdC10L3RliDQvdCwINC90L7QstGWOg0KcmFwcGx5KGwsIG15RnVuLCBob3c9InJlcGxhY2UiKQ0KYGBgDQoNCiMjI3RhcHBseSgpDQoNCiAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCk0YPQvdC60YbRltGPIGB0YXBwbHkoKWAg0LLQuNC60L7RgNC40YHRgtC+0LLRg9GU0YLRjNGB0Y8g0YMg0LLQuNC/0LDQtNC60LDRhSwg0LrQvtC70Lgg0L3QtdC+0LHRhdGW0LTQvdC+INC30LDRgdGC0L7RgdGD0LLQsNGC0Lgg0LHRg9C00Ywt0Y/QutGDINGE0YPQvdC60YbRltGOIGBmdW4oKWAg0LTQviDQvtC60YDQtdC80LjRhSDQs9GA0YPQvyDQtdC70LXQvNC10L3RgtGW0LIg0LLQtdC60YLQvtGA0YMgYHhgLCDRidC+INC30LDQtNCw0L3QuNC5INCy0ZbQtNC/0L7QstGW0LTQvdC+INC00L4g0YDRltCy0L3RltCyINCx0YPQtNGMLdGP0LrQvtCz0L4g0YTQsNC60YLQvtGA0YMgYGdyb3VwYDoNCg0KYGBge3J9DQp0YXBwbHkoeCwgZ3JvdXAsIGZ1biwgLi4uKQ0KYGBgDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0J3QsNC/0YDQuNC60LvQsNC0LCDRgyDRgtCw0LrQvtC80YMg0YTRgNCw0LPQvNC10L3RgtGWINC60L7QtNGDINGE0YPQvdC60YbRltGPIGBzYW1wbGUoKWAg0LLQuNC60L7RgNC40YHRgtC+0LLRg9GU0YLRjNGB0Y8g0LTQu9GPINGB0YLQstC+0YDQtdC90L3RjyDQtNCy0L7RhSDQstC40L/QsNC00LrQvtCy0LjRhSDQstC40LHRltGA0L7Qujog0LcgNTAg0LfQvdCw0YfQtdC90Ywg0YbRltC70LjRhSDRh9C40YHQtdC7INCy0ZbQtCAxINC00L4gNCDRliDQv9C+0LLigJnRj9C30LDQvdC40YUg0ZbQtyDQvdC40LzQuCDQvNGW0YLQvtC6INGH0L7RgtC40YDRjNC+0YUg0LPRgNGD0L8gQS1ELiDQpNGD0L3QutGG0ZbRjyBgdGFwcGx5KClgINC/0ZbQtNGA0LDRhdC+0LLRg9GUINGB0YPQvNC4IGDRhWAg0LTQu9GPINC60L7QttC90L7Qs9C+INC30ZYg0LfQvdCw0YfQtdC90Ywg0YTQsNC60YLQvtGA0YM6DQoNCmBgYHtyfQ0KeCA8LSBzYW1wbGUoMTo0LCBzaXplPTUwLCByZXBsYWNlPVQpDQpnciA8LSBhcy5mYWN0b3Ioc2FtcGxlKGMoIkEiLCAiQiIsICJDIiwgIkQiKSwgc2l6ZT01MCwgcmVwbGFjZT1UKSkNCnRhcHBseSh4LCBnciwgc3VtKQ0KYGBgDQogDQojIyNieSgpDQoNCiAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCk0YPQvdC60YbRltGPIGBieSgpYCDRlCDRgdCy0L7Qs9C+INGA0L7QtNGDINCw0L3QsNC70L7Qs9C+0Lwg0YTRg9C90LrRhtGW0ZcgYHRhcHBseSgpYCwg0Lcg0YLRltGU0Y4g0YDRltC30L3QuNGG0LXRjiwg0YnQviDQstC+0L3QsCDQt9Cw0YHRgtC+0YHQvtCy0YPRlNGC0YzRgdGPINC00LvRjyDRgtCw0LHQu9C40YbRjC4g0KLQsNCx0LvQuNGG0Y8gYGRhdGFgINC/0L7QtNGW0LvRj9GU0YLRjNGB0Y8g0LLRltC00L/QvtCy0ZbQtNC90L4g0LTQviDQt9Cw0LTQsNC90L7Qs9C+INGB0YLQvtCy0L/RhtGPLdGE0LDQutGC0L7RgNGDIGBncm91cGAg0L3QsCDQv9GW0LTQvNC90L7QttC40L3RgyDQv9GW0LTRgtCw0LHQu9C40YbRjCDRliDQtNC70Y8g0L7QsdGA0L7QsdC60Lgg0LrQvtC20L3QvtGXINGC0LDQutC+0Zcg0YfQsNGB0YLQuNC90Lgg0LLQuNC30L3QsNGH0LDRlNGC0YzRgdGPINGE0YPQvdC60YbRltGPIGBmdW4oKWA6DQoNCmBgYHtyfQ0KYnkoZGF0YSwgZ3JvdXAsIGZ1biwgLi4uKQ0KYGBgDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0KDQvtC30LPQu9GP0L3QtdC80L4g0L/RgNC40LrQu9Cw0LQg0ZbQtyDRgtCw0LHQu9C40YbQtdGOINCc0L7Qu9GO0YHQutC4LCDRj9C60LAg0L/RgNC10LTRgdGC0LDQstC70LXQvdCwICrQsiDRgNC+0LfQtNGW0LvRliAxLjMqLCDRliDRgNC+0LfRgNCw0YXRg9GU0LzQviDRgdC10YDQtdC00L3RliDQt9C90LDRh9C10L3QvdGPINC00L7QstC20LjQvdC4INGA0LDQutC+0LLQuNC90LggYFpNbGVuZ3RoYCDRliDRh9C40YHQtdC70YzQvdC+0YHRgtGWINGW0L3RhNGD0LfQvtGA0ZbQuSBgQ0FudW1iZXJgINC00LvRjyDQutC+0LbQvdC+0LPQviDQtyDRgtGA0YzQvtGFINC+0LHRgdGC0LXQttC10L3QuNGFINC+0LfQtdGAIGBMYWtlKNCR0LDRgtC+0YDRltC90L4sINCc0Y/RgdGC0YDQviDQuSDQndCw0YDQvtGH0YwpYDoNCg0KYGBge3J9DQpDbGFtcyA8LQ0KcmVhZC50YWJsZSgiaHR0cDovL2ZpZ3NoYXJlLmNvbS9tZWRpYS9kb3dubG9hZC85ODkyMy85Nzk4NyIsDQpoZWFkZXI9VFJVRSwgc2VwPSJcdCIsIG5hLnN0cmluZ3M9Ik5BIiwgc3RyaXAud2hpdGU9VFJVRSkNCmJ5KENsYW1zWywgNDo1XSwgQ2xhbXMkTGFrZSwgY29sTWVhbnMpDQpgYGANCiANCiMjI291dGVyKCkNCiANCiAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCk0YPQvdC60YbRltGPIGBvdXRlcigpYCDQtNC+0LfQstC+0LvRj9GUINCy0LjQutC+0L3QsNGC0Lgg0LrQvtC80LHRltC90LDRgtC+0YDQvdGDINC+0L/QtdGA0LDRhtGW0Y4gYGZ1bigpYCDQvdCw0LQg0LXQu9C10LzQtdC90YLQsNC80Lgg0LTQstC+0YUg0LzQsNGB0LjQstGW0LIg0LDQsdC+INCy0LXQutGC0L7RgNGW0LIgYHhgINGWIGDRg2AsINC90LUg0LLQtNCw0Y7Rh9C40YHRjCDQtNC+INGP0LLQvdC+0LPQviDQstC40LrQvtGA0LjRgdGC0LDQvdC90Y8g4oCc0L/QvtC00LLRltC50L3QvtCz0L7igJ0g0YbQuNC60LvRgzoNCg0KYGBge3J9DQpvdXRlcih4LCB5LCBmdW49IioiLC4uLikNCmBgYA0KDQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCtCX0LAg0YPQvNC+0LLRh9Cw0L3QvdGP0Lwg0LfQtNGW0LnRgdC90Y7RlNGC0YzRgdGPINC+0L/QtdGA0LDRhtGW0Y8g0L/QvtC/0LDRgNC90L7Qs9C+INC/0LXRgNC10LzQvdC+0LbQtdC90L3Rjw0KDQpgYGB7cn0NCnggPC0gMTo1DQp5IDwtIDE6NQ0Kb3V0ZXIoeCx5KQ0KYGBgDQoNCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOw0K0JLQuNC60L7RgNC40YHRgtC+0LLRg9GO0YfQuCwg0L3QsNC/0YDQuNC60LvQsNC0LCDRhNGD0L3QutGG0ZbRjiBgb3V0ZXIoKWAg0YDQsNC30L7QvCDRltC3INGE0YPQvdC60YbRltGU0Y4gYHBhc3RlKClgLCDQvNC+0LbQvdCwINC30LPQtdC90LXRgNGD0LLQsNGC0Lgg0LLRgdGWINC80L7QttC70LjQstGWINC/0L7Qv9Cw0YDQvdGWINC60L7QvNCx0ZbQvdCw0YbRltGXIOKAnNC30LLigJnRj9C30L7QuuKAnSDQtdC70LXQvNC10L3RgtGW0LIg0YHQuNC80LLQvtC70YzQvdC+0LPQviDQuSDRhtGW0LvQvtGH0LjRgdC10LvRjNC90L7Qs9C+INCy0LXQutGC0L7RgNGW0LI6DQoNCmBgYHtyfQ0KeCA8LSBjKCJBIiwgIkIiLCAiQyIsICJEIikNCnkgPC0gMToxMA0Kb3V0ZXIoeCwgeSwgcGFzdGUsIHNlcD0iIikNCmBgYA0K