ДАТА ФРЕЙМЫ

Дата фреймы (data frame) - прямоугольная двумерная таблица с данными (Exctl spreadsheet, SQL-таблица).
По сути дата фреймы - это стандартный способ хранения данных в формате “наблюдения/переменные”: строки соотвествуют наблюдениям, а столбцы - изучаемым переменным.
Пример:

n <- 10
l <- list(rnorm(n), runif(n))
names(l) <- c("V1", "V2")
class(l) <- "data.frame"
rownames(l) <- 1:n
l

Этот способ создания таблицы намного эффективнее (быстрее) чем стандартный data.frame, но тут отсутствуют всевозможные проверки «от дурака», что может приводить к неожиданным результатам, если вы точно не контролируете входные данные.

Data frame наследует свойства матрицы (прямоугольная форма) и списка (перменные могут быть разных типов) - этакий гибрид матрица-список.

Формально, data.frame — это именованный список (см. typeof(data.frame)), все элементы которого имеют одинаковую длину и который имеет атрибут row.names

Создание data frame

Одноименная функция. Синтаксис напоминает синтаксис создания именованных списков или векторов:
* первый аргумент: имя = значения
* второй аргумент: имя = значения
* третий аргумент и т.д.
N.B! Как и в списке, здесь можем хранить данные разных типов

df <- data.frame(x = 1:4, y = LETTERS[1:4], z = c(T, F)); df

Обратите вниание на аргумент z - в качестве значений подается только два значения (True и False), а строк в дата фрейме задается 4 - значит сработают правила переписывания и значения будут повторены необходимое количество раз

Как получить краткую сводку об объекте?

О любом объекте в R можно получить краткую сводку с помощью функции str - сокр. от structure:
* тип объекта
* количество перменных
* краткая сводка по переменным

str(df)
'data.frame':   4 obs. of  3 variables:
 $ x: int  1 2 3 4
 $ y: chr  "A" "B" "C" "D"
 $ z: logi  TRUE FALSE TRUE FALSE

Имена строк и столбцов

При создании data frame по умолчанию задаем имена перменных, т.е. столбцов.
Чтобы установить имя наблюдения, т.е. ряда, есть аргумент row.names

df <- data.frame(x = 1:4, y = LETTERS[1:4], z = c(T,F),
      row.names = c("Alpha", "Bravo", "Charlie", "Delta")); df

Доступ к именам, как и для матрицы, можно получить функцией row.names и col.names

rownames(df)
[1] "Alpha"   "Bravo"   "Charlie" "Delta"  
colnames(df)
[1] "x" "y" "z"

Фукнция dimnames возвращает список из имен строк и столбцов

dimnames(df)
[[1]]
[1] "Alpha"   "Bravo"   "Charlie" "Delta"  

[[2]]
[1] "x" "y" "z"

Размерности

У дата фрейма есть определенная размерность:
* это прямоугольная двумерная таблица
* у нее есть определенное количество строк и столбцов

Доступ к количеству строк и столбцов

Как и в случае с матрицой, осуществляется через функции nrow, ncol, dim

nrow(df)
[1] 4
ncol(df)
[1] 3
dim(df) #Вектор из двух элементов
[1] 4 3

Особенности, чреватые ошибками

  1. length(df) - возвращает количество столбцов (переменных), а не общее количество элементов
length(df)
[1] 3

Если сравнивать с матрицей, то…

m <- matrix(0, 3, 2); m
     [,1] [,2]
[1,]    0    0
[2,]    0    0
[3,]    0    0
length(m)
[1] 6

length(m) - возвращает количество всех элементов матрицы.

Это происходит потому, что, по сути, дата фрейм - это список, уложенный по столбцам. А length(списка) - количество элементов списка

l <- list(a = 1:3, x = letters[1:2], "chap"); l
$a
[1] 1 2 3

$x
[1] "a" "b"

[[3]]
[1] "chap"
length(l)
[1] 3
  1. names(df) - также вернет имена столбцов
names(df)
[1] "x" "y" "z"
colnames(df)
[1] "x" "y" "z"
rownames(df)
[1] "Alpha"   "Bravo"   "Charlie" "Delta"  

Чтобы получить общее количетсво элементов в дата фрейме, нужно умножить nrow на ncol. Логично

length(df)
[1] 3
ncol(df)
[1] 3
nrow(df) * ncol(df)
[1] 12

Предостережение!

Чтобы избежать распространенных ошибок, следует избегать применения функции *length** и names на дата фрейме. Это убережет от ошибок и сделает код более удобочитаемым

Индексация data frame

Дата фрейм наследует некоторые особенности от списка, а некоторые от матрицы - это касается и правил индексирования.

А) Индексация в матричном стиле

  • положительная
  • отрицательная
  • логическая
  • по именам

Пример 1: хочу выбрать 3 и 4 ряд и все колонки, кроме первой - воспользуемся положительной и отрицательной индексацией

df[3:4, -1]

Пример 2: индексация по именам и логическая

df[c(F, T), c("z", "x")]

N.B! *Здесь также работает правило переписывания

Если хочу обратиться к конкретной колонке

df[ , 1]
[1] 1 2 3 4

То происходит то же, что и с матрицей - размерность схлопывается. Но схлопывание по умолчанию можно отменить - тогда получим дата фрейм из 1 столбца

df[ , 1, drop = FALSE]

Обращение в столбцу

Чаще всего самый удобный вариант в обращении к определенному столбцу - обращение через частичное дополнение (работает одинаково), т.е. значок $. Например:

df$z
[1]  TRUE FALSE  TRUE FALSE

Способы df[[3]] и df[["z]] будут работать, однако $ - самый удобный спооб

Фильтрация элементов по условию

Точно так же, как для матрицы, для дата фрейма возможен выбор элементов, соответсвующих определенным логическим условиям

df[df$x > 2, ]

subset

Иногда для таких фильтраций удобно ползоваться функцией subset. Чем примечательна эта функция? - не нужно дублировать название data frame, не нужно ничего заключать в кавычки. Такой же subset, что и выше, можно получить следующим образом

subset(df, x > 2)

У функции есть еще 1 доп аргумент - select - при помощи которого, можно указать условие на отбор столбцов, при этом также имена не труебуют кавычки

subset(df, x > 2, select = c(x, z))

Результат такой же, но с фильтрацией по колонкам

Комбинирование data frame

Как и для матриц, работают функции rbind, cbind. Например, хочу к дф присоединить еще 1 дф, который я создал на лету. Имена в df и нового df должны совпадать в точности

rbind(df, data.frame(x = 5:6, y = c("K", "Z"), z = TRUE, row.names = c("Kappa", "Zulu")))

Аналогично действует и функция cbind

cbind(df, data.frame(season = c("Summer", "Autumn", "Winter", "Spring"), temp = c(20, 5, -10, 5)))

Функция merge

Более сложный случай комбинирования дата фреймов - комбинирование по ключу.
Вспомним наш оригинальный дата фрейм

df

df = это 3 переменных и 4 наблюдения. Допустим, что переменная x - некий ключ, который однозначно определяет ту или ину запись.
Допустим, есть другой дата фрейм df_salary, который содержит набор ключей x в каком-то порядке и дополнительные колонки, как например, зарпалата (salary)

df_salary <- data.frame(x = c(3, 2, 6, 1), salary = c(100, 1000, 300, 500))
df_salary

Теперь хотим создать новый дата фрейм из двух старых, записи которых будут объединены по ключу x - воспользуемся функцией merge, в качестве первых двух аргументов укажем дата фреймы, из которых лепим новый, а третьим - обозначаем ключ

merge(df, df_salary, by = "x")

Результат - новый дата фрейм, со всеми полными записями из двух предыдущих дата фреймов, определяемых по ключу x.

Для тех, кто знаком с SQL - эта операция соответсвует inner join.

В R есть и остальные виды джоинов (left, right, outer, cross join), которые легко найти на stackoverflow по запросу “r joins”

#Глоссарий ?data.frame
?str
?rownames, ?colnames, ?dimnames, ?nrow, ?ncol, ? dim
?subset, ?rbind, ?cbind, ?merge

Задача

Дата фрейм attitude – встроенный массив данных, содержащий рейтинг департаментов одной финансовой компании, составленный сотрудниками. Представьте, что вы хотите устраиваться как раз в эту компанию, и дата фрейм (совершенно случайно!) оказался в вашем распоряжении.

Вы решили, что самое главное для вас – это возможность учиться новому (learning). Возьмите 5 топовых департаментов по этому показателю. Из этого набора вам более всего подойдёт тот департамент, который имеет наибольшую сумму баллов по трём показателям: реакция на жалобы работников (complaints), надбавки в зависимости от результатов работы (raises) и возможность продвижения (advance).

Какой же департамент вам выбрать? Напишите его номер XX (номер строки в дата фрейме)

head(attitude)

Алгоритм
1. Найти топ-5 показателей learning

attitude$learning[1:5]
[1] 39 54 69 47 66
  1. Найти номера наблюдений с топ-5 показателем learning
order(-attitude$learning)[1:5]
[1] 18 27 15 16 29
  1. Обратиться по логическому индексированию к части дата фрейма по топ-5 по learning
attitude[order(-attitude$learning)[1:5], ]
  1. Вывести часть дата фрейма по топ-5 в learning без столбца learning
attitude[order(-attitude$learning),][1:5,][c("complaints","raises","advance")]
  1. Посчитать сумму рядов по трем оставшимся показателям в выведенной части дата фрейма
rowSums(attitude[order(-attitude$learning)[1:5],c("complaints","raises","advance")])
 18  27  15  16  29 
175 204 202 186 217 
  1. Найти максимальное значение
which.max(rowSums(attitude[order(-attitude$learning)[1:5],c("complaints","raises","advance")]))
29 
 5 
# или
which.max(rowSums(attitude[order(-attitude$learning),][1:5,][c("complaints","raises","advance")]))
29 
 5 

Не очень пойму, как работает order и такое сложное логическое индексирование

Cпособы обращения к строкам, соответсвующие определенным условиям

Нижеуказанными способами можно выбрать только те строки, которые соответствуют департаментам с рейтингом (rating) ниже пятидесяти, при этом сохранив все столбцы, кроме rating
Способ 1 - алгоритм:
1. Используем функцию subset (подгруппа) к дата фрейму attitude,
2. аргументом указываем вывести определенные строки (rating < 50)

  1. исключаем столбец rating (-rating)
subset(attitude, rating < 50, -rating)

Способ 2 - алгоритм:
1. Используем функцию subset (подгруппа) к дата фрейму attitude (только выносим аргументом в конец)
2. Выбираем исключить столбец rating, сокращая select (sel = -rating)

subset(sel = -rating, attitude)
  1. Выводим строки подгруппой с rating < 50 (subset = rating < 50)
subset(sel = -rating, sub = rating < 50, attitude)

Способ 3 - алгоритм:
1. Обращаемся к определенному индексу дата фрейма attitude
2. Используем логическое индексирование 3. Выводим строки, соответсвующие логическому индексу [attitude$rating < 50] 4. Выводим строки без столбца rating [names(attitude) != “rating”]

attitude[attitude$rating < 50, ]
attitude[attitude$rating < 50, names(attitude) != "rating"]
LS0tDQp0aXRsZTogItCU0LDRgtCwINGE0YDQtdC50LzRiyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojINCU0JDQotCQINCk0KDQldCZ0JzQqw0K0JTQsNGC0LAg0YTRgNC10LnQvNGLIChkYXRhIGZyYW1lKSAtINC/0YDRj9C80L7Rg9Cz0L7Qu9GM0L3QsNGPINC00LLRg9C80LXRgNC90LDRjyDRgtCw0LHQu9C40YbQsCDRgSDQtNCw0L3QvdGL0LzQuCAoRXhjdGwgc3ByZWFkc2hlZXQsIFNRTC3RgtCw0LHQu9C40YbQsCkuICANCtCf0L4g0YHRg9GC0Lgg0LTQsNGC0LAg0YTRgNC10LnQvNGLIC0g0Y3RgtC+INGB0YLQsNC90LTQsNGA0YLQvdGL0Lkg0YHQv9C+0YHQvtCxINGF0YDQsNC90LXQvdC40Y8g0LTQsNC90L3Ri9GFINCyINGE0L7RgNC80LDRgtC1ICLQvdCw0LHQu9GO0LTQtdC90LjRjy/Qv9C10YDQtdC80LXQvdC90YvQtSI6INGB0YLRgNC+0LrQuCDRgdC+0L7RgtCy0LXRgdGC0LLRg9GO0YIg0L3QsNCx0LvRjtC00LXQvdC40Y/QvCwg0LAg0YHRgtC+0LvQsdGG0YsgLSDQuNC30YPRh9Cw0LXQvNGL0Lwg0L/QtdGA0LXQvNC10L3QvdGL0LwuICANCioq0J/RgNC40LzQtdGAKio6DQpgYGB7cn0NCm4gPC0gMTANCmwgPC0gbGlzdChybm9ybShuKSwgcnVuaWYobikpDQpuYW1lcyhsKSA8LSBjKCJWMSIsICJWMiIpDQpjbGFzcyhsKSA8LSAiZGF0YS5mcmFtZSINCnJvd25hbWVzKGwpIDwtIDE6bg0KbA0KYGBgDQrQrdGC0L7RgiDRgdC/0L7RgdC+0LEg0YHQvtC30LTQsNC90LjRjyDRgtCw0LHQu9C40YbRiyDQvdCw0LzQvdC+0LPQviDRjdGE0YTQtdC60YLQuNCy0L3QtdC1ICjQsdGL0YHRgtGA0LXQtSkg0YfQtdC8INGB0YLQsNC90LTQsNGA0YLQvdGL0LkgZGF0YS5mcmFtZSwg0L3QviDRgtGD0YIg0L7RgtGB0YPRgtGB0YLQstGD0Y7RgiDQstGB0LXQstC+0LfQvNC+0LbQvdGL0LUg0L/RgNC+0LLQtdGA0LrQuCDCq9C+0YIg0LTRg9GA0LDQutCwwrssINGH0YLQviDQvNC+0LbQtdGCINC/0YDQuNCy0L7QtNC40YLRjCDQuiDQvdC10L7QttC40LTQsNC90L3Ri9C8INGA0LXQt9GD0LvRjNGC0LDRgtCw0LwsINC10YHQu9C4INCy0Ysg0YLQvtGH0L3QviDQvdC1INC60L7QvdGC0YDQvtC70LjRgNGD0LXRgtC1INCy0YXQvtC00L3Ri9C1INC00LDQvdC90YvQtS4NCg0KICANCkRhdGEgZnJhbWUg0L3QsNGB0LvQtdC00YPQtdGCINGB0LLQvtC50YHRgtCy0LAg0LzQsNGC0YDQuNGG0YsgKNC/0YDRj9C80L7Rg9Cz0L7Qu9GM0L3QsNGPINGE0L7RgNC80LApINC4INGB0L/QuNGB0LrQsCAo0L/QtdGA0LzQtdC90L3Ri9C1INC80L7Qs9GD0YIg0LHRi9GC0Ywg0YDQsNC30L3Ri9GFINGC0LjQv9C+0LIpIC0g0Y3RgtCw0LrQuNC5INCz0LjQsdGA0LjQtCDQvNCw0YLRgNC40YbQsC3RgdC/0LjRgdC+0LouICANCiAgDQrQpNC+0YDQvNCw0LvRjNC90L4sIGRhdGEuZnJhbWUg4oCUINGN0YLQviDQuNC80LXQvdC+0LLQsNC90L3Ri9C5INGB0L/QuNGB0L7QuiAo0YHQvC4gdHlwZW9mKGRhdGEuZnJhbWUpKSwgINCy0YHQtSDRjdC70LXQvNC10L3RgtGLINC60L7RgtC+0YDQvtCz0L4g0LjQvNC10Y7RgiDQvtC00LjQvdCw0LrQvtCy0YPRjiDQtNC70LjQvdGDINC4INC60L7RgtC+0YDRi9C5INC40LzQtdC10YIg0LDRgtGA0LjQsdGD0YIgcm93Lm5hbWVzDQoNCiMg0KHQvtC30LTQsNC90LjQtSBkYXRhIGZyYW1lIA0K0J7QtNC90L7QuNC80LXQvdC90LDRjyDRhNGD0L3QutGG0LjRjy4g0KHQuNC90YLQsNC60YHQuNGBINC90LDQv9C+0LzQuNC90LDQtdGCINGB0LjQvdGC0LDQutGB0LjRgSDRgdC+0LfQtNCw0L3QuNGPINC40LzQtdC90L7QstCw0L3QvdGL0YUg0YHQv9C40YHQutC+0LIg0LjQu9C4INCy0LXQutGC0L7RgNC+0LI6ICANCiog0L/QtdGA0LLRi9C5INCw0YDQs9GD0LzQtdC90YI6INC40LzRjyA9INC30L3QsNGH0LXQvdC40Y8gIA0KKiDQstGC0L7RgNC+0Lkg0LDRgNCz0YPQvNC10L3Rgjog0LjQvNGPID0g0LfQvdCw0YfQtdC90LjRjyAgDQoqINGC0YDQtdGC0LjQuSDQsNGA0LPRg9C80LXQvdGCINC4INGCLtC0LiAgDQpOLkIhICrQmtCw0Log0Lgg0LIg0YHQv9C40YHQutC1LCDQt9C00LXRgdGMINC80L7QttC10Lwg0YXRgNCw0L3QuNGC0Ywg0LTQsNC90L3Ri9C1INGA0LDQt9C90YvRhSDRgtC40L/QvtCyKg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKHggPSAxOjQsIHkgPSBMRVRURVJTWzE6NF0sIHogPSBjKFQsIEYpKTsgZGYNCmBgYA0KKtCe0LHRgNCw0YLQuNGC0LUg0LLQvdC40LDQvdC40LUg0L3QsCDQsNGA0LPRg9C80LXQvdGCIHogLSDQsiDQutCw0YfQtdGB0YLQstC1INC30L3QsNGH0LXQvdC40Lkg0L/QvtC00LDQtdGC0YHRjyDRgtC+0LvRjNC60L4g0LTQstCwINC30L3QsNGH0LXQvdC40Y8gKFRydWUg0LggRmFsc2UpLCDQsCDRgdGC0YDQvtC6INCyINC00LDRgtCwINGE0YDQtdC50LzQtSDQt9Cw0LTQsNC10YLRgdGPIDQgLSDQt9C90LDRh9C40YIg0YHRgNCw0LHQvtGC0LDRjtGCINC/0YDQsNCy0LjQu9CwINC/0LXRgNC10L/QuNGB0YvQstCw0L3QuNGPINC4INC30L3QsNGH0LXQvdC40Y8g0LHRg9C00YPRgiDQv9C+0LLRgtC+0YDQtdC90Ysg0L3QtdC+0LHRhdC+0LTQuNC80L7QtSDQutC+0LvQuNGH0LXRgdGC0LLQviDRgNCw0LcqICANCiAgDQojIyDQmtCw0Log0L/QvtC70YPRh9C40YLRjCDQutGA0LDRgtC60YPRjiDRgdCy0L7QtNC60YMg0L7QsSDQvtCx0YrQtdC60YLQtT8NCtCeINC70Y7QsdC+0Lwg0L7QsdGK0LXQutGC0LUg0LIgUiDQvNC+0LbQvdC+INC/0L7Qu9GD0YfQuNGC0Ywg0LrRgNCw0YLQutGD0Y4g0YHQstC+0LTQutGDINGBINC/0L7QvNC+0YnRjNGOINGE0YPQvdC60YbQuNC4ICpzdHIqIC0g0YHQvtC60YAuINC+0YIgc3RydWN0dXJlOiAgDQoqINGC0LjQvyDQvtCx0YrQtdC60YLQsCAgDQoqINC60L7Qu9C40YfQtdGB0YLQstC+INC/0LXRgNC80LXQvdC90YvRhSAgDQoqINC60YDQsNGC0LrQsNGPINGB0LLQvtC00LrQsCDQv9C+INC/0LXRgNC10LzQtdC90L3Ri9C8DQpgYGB7cn0NCnN0cihkZikNCmBgYA0KIyDQmNC80LXQvdCwINGB0YLRgNC+0Log0Lgg0YHRgtC+0LvQsdGG0L7Qsg0K0J/RgNC4INGB0L7Qt9C00LDQvdC40LggZGF0YSBmcmFtZSDQv9C+INGD0LzQvtC70YfQsNC90LjRjiDQt9Cw0LTQsNC10Lwg0LjQvNC10L3QsCDQv9C10YDQvNC10L3QvdGL0YUsINGCLtC1LiDRgdGC0L7Qu9Cx0YbQvtCyLiAgDQrQp9GC0L7QsdGLINGD0YHRgtCw0L3QvtCy0LjRgtGMINC40LzRjyDQvdCw0LHQu9GO0LTQtdC90LjRjywg0YIu0LUuINGA0Y/QtNCwLCDQtdGB0YLRjCDQsNGA0LPRg9C80LXQvdGCICpyb3cubmFtZXMqDQpgYGB7cn0NCmRmIDwtIGRhdGEuZnJhbWUoeCA9IDE6NCwgeSA9IExFVFRFUlNbMTo0XSwgeiA9IGMoVCxGKSwNCiAgICAgIHJvdy5uYW1lcyA9IGMoIkFscGhhIiwgIkJyYXZvIiwgIkNoYXJsaWUiLCAiRGVsdGEiKSk7IGRmDQpgYGANCtCU0L7RgdGC0YPQvyDQuiDQuNC80LXQvdCw0LwsINC60LDQuiDQuCDQtNC70Y8g0LzQsNGC0YDQuNGG0YssINC80L7QttC90L4g0L/QvtC70YPRh9C40YLRjCDRhNGD0L3QutGG0LjQtdC5ICpyb3cubmFtZXMqINC4ICpjb2wubmFtZXMqDQpgYGB7cn0NCnJvd25hbWVzKGRmKQ0KY29sbmFtZXMoZGYpDQpgYGANCtCk0YPQutC90YbQuNGPICpkaW1uYW1lcyog0LLQvtC30LLRgNCw0YnQsNC10YIg0YHQv9C40YHQvtC6INC40Lcg0LjQvNC10L0g0YHRgtGA0L7QuiDQuCDRgdGC0L7Qu9Cx0YbQvtCyDQpgYGB7cn0NCmRpbW5hbWVzKGRmKQ0KYGBgDQojINCg0LDQt9C80LXRgNC90L7RgdGC0LgNCtCjINC00LDRgtCwINGE0YDQtdC50LzQsCDQtdGB0YLRjCDQvtC/0YDQtdC00LXQu9C10L3QvdCw0Y8g0YDQsNC30LzQtdGA0L3QvtGB0YLRjDogIA0KKiDRjdGC0L4g0L/RgNGP0LzQvtGD0LPQvtC70YzQvdCw0Y8g0LTQstGD0LzQtdGA0L3QsNGPINGC0LDQsdC70LjRhtCwICANCiog0YMg0L3QtdC1INC10YHRgtGMINC+0L/RgNC10LTQtdC70LXQvdC90L7QtSDQutC+0LvQuNGH0LXRgdGC0LLQviDRgdGC0YDQvtC6INC4INGB0YLQvtC70LHRhtC+0LIgIA0KICANCiMjIyDQlNC+0YHRgtGD0L8g0Log0LrQvtC70LjRh9C10YHRgtCy0YMg0YHRgtGA0L7QuiDQuCDRgdGC0L7Qu9Cx0YbQvtCyIA0K0JrQsNC6INC4INCyINGB0LvRg9GH0LDQtSDRgSDQvNCw0YLRgNC40YbQvtC5LCDQvtGB0YPRidC10YHRgtCy0LvRj9C10YLRgdGPINGH0LXRgNC10Lcg0YTRg9C90LrRhtC40LggKm5yb3cqLCAqbmNvbCosICpkaW0qDQpgYGB7cn0NCm5yb3coZGYpDQpuY29sKGRmKQ0KZGltKGRmKSAj0JLQtdC60YLQvtGAINC40Lcg0LTQstGD0YUg0Y3Qu9C10LzQtdC90YLQvtCyDQpgYGANCiMg0J7RgdC+0LHQtdC90L3QvtGB0YLQuCwg0YfRgNC10LLQsNGC0YvQtSDQvtGI0LjQsdC60LDQvNC4DQoxLiAqbGVuZ3RoKGRmKSogLSDQstC+0LfQstGA0LDRidCw0LXRgiDQutC+0LvQuNGH0LXRgdGC0LLQviAq0YHRgtC+0LvQsdGG0L7QsiogKNC/0LXRgNC10LzQtdC90L3Ri9GFKSwg0LAg0L3QtSDQvtCx0YnQtdC1INC60L7Qu9C40YfQtdGB0YLQstC+INGN0LvQtdC80LXQvdGC0L7QsiANCmBgYHtyfQ0KbGVuZ3RoKGRmKQ0KYGBgDQrQldGB0LvQuCDRgdGA0LDQstC90LjQstCw0YLRjCDRgSDQvNCw0YLRgNC40YbQtdC5LCDRgtC+Li4uDQpgYGB7cn0NCm0gPC0gbWF0cml4KDAsIDMsIDIpOyBtDQpsZW5ndGgobSkNCmBgYA0KbGVuZ3RoKG0pIC0g0LLQvtC30LLRgNCw0YnQsNC10YIg0LrQvtC70LjRh9C10YHRgtCy0L4g0LLRgdC10YUg0Y3Qu9C10LzQtdC90YLQvtCyINC80LDRgtGA0LjRhtGLLiAgDQogIA0K0K3RgtC+INC/0YDQvtC40YHRhdC+0LTQuNGCINC/0L7RgtC+0LzRgywg0YfRgtC+LCDQv9C+INGB0YPRgtC4LCDQtNCw0YLQsCDRhNGA0LXQudC8IC0g0Y3RgtC+INGB0L/QuNGB0L7Quiwg0YPQu9C+0LbQtdC90L3Ri9C5INC/0L4g0YHRgtC+0LvQsdGG0LDQvC4g0JAgKmxlbmd0aCjRgdC/0LjRgdC60LApKiAtINC60L7Qu9C40YfQtdGB0YLQstC+INGN0LvQtdC80LXQvdGC0L7QsiDRgdC/0LjRgdC60LANCmBgYHtyfQ0KbCA8LSBsaXN0KGEgPSAxOjMsIHggPSBsZXR0ZXJzWzE6Ml0sICJjaGFwIik7IGwNCmxlbmd0aChsKQ0KYGBgDQoNCiAgDQoyLiBuYW1lcyhkZikgLSDRgtCw0LrQttC1INCy0LXRgNC90LXRgiDQuNC80LXQvdCwINGB0YLQvtC70LHRhtC+0LIgDQpgYGB7cn0NCm5hbWVzKGRmKQ0KY29sbmFtZXMoZGYpDQpyb3duYW1lcyhkZikNCmBgYA0K0KfRgtC+0LHRiyDQv9C+0LvRg9GH0LjRgtGMINC+0LHRidC10LUg0LrQvtC70LjRh9C10YLRgdCy0L4g0Y3Qu9C10LzQtdC90YLQvtCyINCyINC00LDRgtCwINGE0YDQtdC50LzQtSwg0L3Rg9C20L3QviDRg9C80L3QvtC20LjRgtGMICpucm93KiDQvdCwICpuY29sKi4g0JvQvtCz0LjRh9C90L4NCmBgYHtyfQ0KbGVuZ3RoKGRmKQ0KbmNvbChkZikNCm5yb3coZGYpICogbmNvbChkZikNCmBgYA0KIyMjINCf0YDQtdC00L7RgdGC0LXRgNC10LbQtdC90LjQtSENCtCn0YLQvtCx0Ysg0LjQt9Cx0LXQttCw0YLRjCDRgNCw0YHQv9GA0L7RgdGC0YDQsNC90LXQvdC90YvRhSDQvtGI0LjQsdC+0LosINGB0LvQtdC00YPQtdGCINC40LfQsdC10LPQsNGC0Ywg0L/RgNC40LzQtdC90LXQvdC40Y8g0YTRg9C90LrRhtC40LggKmxlbmd0aCoqINC4ICpuYW1lcyog0L3QsCDQtNCw0YLQsCDRhNGA0LXQudC80LUuINCt0YLQviDRg9Cx0LXRgNC10LbQtdGCINC+0YIg0L7RiNC40LHQvtC6INC4INGB0LTQtdC70LDQtdGCINC60L7QtCDQsdC+0LvQtdC1INGD0LTQvtCx0L7Rh9C40YLQsNC10LzRi9C8DQoNCiMg0JjQvdC00LXQutGB0LDRhtC40Y8gZGF0YSBmcmFtZQ0K0JTQsNGC0LAg0YTRgNC10LnQvCDQvdCw0YHQu9C10LTRg9C10YIg0L3QtdC60L7RgtC+0YDRi9C1INC+0YHQvtCx0LXQvdC90L7RgdGC0Lgg0L7RgiDRgdC/0LjRgdC60LAsINCwINC90LXQutC+0YLQvtGA0YvQtSDQvtGCINC80LDRgtGA0LjRhtGLIC0g0Y3RgtC+INC60LDRgdCw0LXRgtGB0Y8g0Lgg0L/RgNCw0LLQuNC7INC40L3QtNC10LrRgdC40YDQvtCy0LDQvdC40Y8uICANCiAgDQojIyMg0JApINCY0L3QtNC10LrRgdCw0YbQuNGPINCyINC80LDRgtGA0LjRh9C90L7QvCDRgdGC0LjQu9C1DQoqINC/0L7Qu9C+0LbQuNGC0LXQu9GM0L3QsNGPICANCiog0L7RgtGA0LjRhtCw0YLQtdC70YzQvdCw0Y8gDQoqINC70L7Qs9C40YfQtdGB0LrQsNGPICANCiog0L/QviDQuNC80LXQvdCw0LwgIA0KICANCiAgDQoqKtCf0YDQuNC80LXRgCAxKio6INGF0L7Rh9GDINCy0YvQsdGA0LDRgtGMIDMg0LggNCDRgNGP0LQg0Lgg0LLRgdC1INC60L7Qu9C+0L3QutC4LCDQutGA0L7QvNC1INC/0LXRgNCy0L7QuSAtINCy0L7RgdC/0L7Qu9GM0LfRg9C10LzRgdGPINC/0L7Qu9C+0LbQuNGC0LXQu9GM0L3QvtC5INC4INC+0YLRgNC40YbQsNGC0LXQu9GM0L3QvtC5INC40L3QtNC10LrRgdCw0YbQuNC10LkNCmBgYHtyfQ0KZGZbMzo0LCAtMV0NCmBgYA0KKirQn9GA0LjQvNC10YAgMioqOiDQuNC90LTQtdC60YHQsNGG0LjRjyDQv9C+INC40LzQtdC90LDQvCDQuCDQu9C+0LPQuNGH0LXRgdC60LDRjw0KYGBge3J9DQpkZltjKEYsIFQpLCBjKCJ6IiwgIngiKV0NCmBgYA0KKk4uQiEqICrQl9C00LXRgdGMINGC0LDQutC20LUg0YDQsNCx0L7RgtCw0LXRgiDQv9GA0LDQstC40LvQviDQv9C10YDQtdC/0LjRgdGL0LLQsNC90LjRjyANCiAgDQrQldGB0LvQuCDRhdC+0YfRgyDQvtCx0YDQsNGC0LjRgtGM0YHRjyDQuiDQutC+0L3QutGA0LXRgtC90L7QuSDQutC+0LvQvtC90LrQtQ0KYGBge3J9DQpkZlsgLCAxXQ0KYGBgDQrQotC+INC/0YDQvtC40YHRhdC+0LTQuNGCINGC0L4g0LbQtSwg0YfRgtC+INC4INGBINC80LDRgtGA0LjRhtC10LkgLSDRgNCw0LfQvNC10YDQvdC+0YHRgtGMINGB0YXQu9C+0L/Ri9Cy0LDQtdGC0YHRjy4g0J3QviDRgdGF0LvQvtC/0YvQstCw0L3QuNC1INC/0L4g0YPQvNC+0LvRh9Cw0L3QuNGOINC80L7QttC90L4g0L7RgtC80LXQvdC40YLRjCAtINGC0L7Qs9C00LAg0L/QvtC70YPRh9C40Lwg0LTQsNGC0LAg0YTRgNC10LnQvCDQuNC3IDEg0YHRgtC+0LvQsdGG0LANCmBgYHtyfQ0KZGZbICwgMSwgZHJvcCA9IEZBTFNFXQ0KYGBgDQojIyDQntCx0YDQsNGJ0LXQvdC40LUg0LIg0YHRgtC+0LvQsdGG0YMNCtCn0LDRidC1INCy0YHQtdCz0L4g0YHQsNC80YvQuSDRg9C00L7QsdC90YvQuSDQstCw0YDQuNCw0L3RgiDQsiDQvtCx0YDQsNGJ0LXQvdC40Lgg0Log0L7Qv9GA0LXQtNC10LvQtdC90L3QvtC80YMg0YHRgtC+0LvQsdGG0YMgLSDQvtCx0YDQsNGJ0LXQvdC40LUg0YfQtdGA0LXQtyDRh9Cw0YHRgtC40YfQvdC+0LUg0LTQvtC/0L7Qu9C90LXQvdC40LUgKNGA0LDQsdC+0YLQsNC10YIg0L7QtNC40L3QsNC60L7QstC+KSwg0YIu0LUuINC30L3QsNGH0L7QuiAqKiQqKi4g0J3QsNC/0YDQuNC80LXRgDoNCmBgYHtyfQ0KZGYkeg0KYGBgDQrQodC/0L7RgdC+0LHRiyAqZGZbWzNdXSog0LggKmRmW1siel1dKiDQsdGD0LTRg9GCINGA0LDQsdC+0YLQsNGC0YwsINC+0LTQvdCw0LrQviAqJCogLSDRgdCw0LzRi9C5INGD0LTQvtCx0L3Ri9C5INGB0L/QvtC+0LEgDQoNCiMg0KTQuNC70YzRgtGA0LDRhtC40Y8g0Y3Qu9C10LzQtdC90YLQvtCyINC/0L4g0YPRgdC70L7QstC40Y4NCtCi0L7Rh9C90L4g0YLQsNC6INC20LUsINC60LDQuiDQtNC70Y8g0LzQsNGC0YDQuNGG0YssINC00LvRjyDQtNCw0YLQsCDRhNGA0LXQudC80LAg0LLQvtC30LzQvtC20LXQvSDQstGL0LHQvtGAINGN0LvQtdC80LXQvdGC0L7Qsiwg0YHQvtC+0YLQstC10YLRgdCy0YPRjtGJ0LjRhSDQvtC/0YDQtdC00LXQu9C10L3QvdGL0Lwg0LvQvtCz0LjRh9C10YHQutC40Lwg0YPRgdC70L7QstC40Y/QvA0KYGBge3J9DQpkZltkZiR4ID4gMiwgXQ0KYGBgDQoNCiMjIyBzdWJzZXQNCtCY0L3QvtCz0LTQsCDQtNC70Y8g0YLQsNC60LjRhSDRhNC40LvRjNGC0YDQsNGG0LjQuSDRg9C00L7QsdC90L4g0L/QvtC70LfQvtCy0LDRgtGM0YHRjyDRhNGD0L3QutGG0LjQtdC5ICpzdWJzZXQqLiDQp9C10Lwg0L/RgNC40LzQtdGH0LDRgtC10LvRjNC90LAg0Y3RgtCwINGE0YPQvdC60YbQuNGPPyAgLSDQvdC1INC90YPQttC90L4g0LTRg9Cx0LvQuNGA0L7QstCw0YLRjCDQvdCw0LfQstCw0L3QuNC1IGRhdGEgZnJhbWUsINC90LUg0L3Rg9C20L3QviDQvdC40YfQtdCz0L4g0LfQsNC60LvRjtGH0LDRgtGMINCyINC60LDQstGL0YfQutC4LiDQotCw0LrQvtC5INC20LUgc3Vic2V0LCDRh9GC0L4g0Lgg0LLRi9GI0LUsINC80L7QttC90L4g0L/QvtC70YPRh9C40YLRjCDRgdC70LXQtNGD0Y7RidC40Lwg0L7QsdGA0LDQt9C+0LwNCmBgYHtyfQ0Kc3Vic2V0KGRmLCB4ID4gMikNCmBgYA0K0KMg0YTRg9C90LrRhtC40Lgg0LXRgdGC0Ywg0LXRidC1IDEg0LTQvtC/INCw0YDQs9GD0LzQtdC90YIgLSAqc2VsZWN0KiAtINC/0YDQuCDQv9C+0LzQvtGJ0Lgg0LrQvtGC0L7RgNC+0LPQviwg0LzQvtC20L3QviDRg9C60LDQt9Cw0YLRjCDRg9GB0LvQvtCy0LjQtSDQvdCwINC+0YLQsdC+0YAg0YHRgtC+0LvQsdGG0L7Qsiwg0L/RgNC4INGN0YLQvtC8INGC0LDQutC20LUg0LjQvNC10L3QsCDQvdC1INGC0YDRg9C10LHRg9GO0YIg0LrQsNCy0YvRh9C60LgNCmBgYHtyfQ0Kc3Vic2V0KGRmLCB4ID4gMiwgc2VsZWN0ID0gYyh4LCB6KSkNCmBgYA0K0KDQtdC30YPQu9GM0YLQsNGCINGC0LDQutC+0Lkg0LbQtSwg0L3QviDRgSDRhNC40LvRjNGC0YDQsNGG0LjQtdC5INC/0L4g0LrQvtC70L7QvdC60LDQvCAgDQogIA0KIyDQmtC+0LzQsdC40L3QuNGA0L7QstCw0L3QuNC1IGRhdGEgZnJhbWUNCtCa0LDQuiDQuCDQtNC70Y8g0LzQsNGC0YDQuNGGLCDRgNCw0LHQvtGC0LDRjtGCINGE0YPQvdC60YbQuNC4IHJiaW5kLCBjYmluZC4g0J3QsNC/0YDQuNC80LXRgCwg0YXQvtGH0YMg0Log0LTRhCDQv9GA0LjRgdC+0LXQtNC40L3QuNGC0Ywg0LXRidC1IDEg0LTRhCwg0LrQvtGC0L7RgNGL0Lkg0Y8g0YHQvtC30LTQsNC7INC90LAg0LvQtdGC0YMuINCY0LzQtdC90LAg0LIgZGYg0Lgg0L3QvtCy0L7Qs9C+IGRmINC00L7Qu9C20L3RiyDRgdC+0LLQv9Cw0LTQsNGC0Ywg0LIg0YLQvtGH0L3QvtGB0YLQuA0KYGBge3J9DQpyYmluZChkZiwgZGF0YS5mcmFtZSh4ID0gNTo2LCB5ID0gYygiSyIsICJaIiksIHogPSBUUlVFLCByb3cubmFtZXMgPSBjKCJLYXBwYSIsICJadWx1IikpKQ0KYGBgDQrQkNC90LDQu9C+0LPQuNGH0L3QviDQtNC10LnRgdGC0LLRg9C10YIg0Lgg0YTRg9C90LrRhtC40Y8gY2JpbmQNCmBgYHtyfQ0KY2JpbmQoZGYsIGRhdGEuZnJhbWUoc2Vhc29uID0gYygiU3VtbWVyIiwgIkF1dHVtbiIsICJXaW50ZXIiLCAiU3ByaW5nIiksIHRlbXAgPSBjKDIwLCA1LCAtMTAsIDUpKSkNCmBgYA0KIyMg0KTRg9C90LrRhtC40Y8gKiptZXJnZSoqDQrQkdC+0LvQtdC1INGB0LvQvtC20L3Ri9C5INGB0LvRg9GH0LDQuSDQutC+0LzQsdC40L3QuNGA0L7QstCw0L3QuNGPINC00LDRgtCwINGE0YDQtdC50LzQvtCyIC0g0LrQvtC80LHQuNC90LjRgNC+0LLQsNC90LjQtSDQv9C+INC60LvRjtGH0YMuICANCtCS0YHQv9C+0LzQvdC40Lwg0L3QsNGIINC+0YDQuNCz0LjQvdCw0LvRjNC90YvQuSDQtNCw0YLQsCDRhNGA0LXQudC8DQpgYGB7cn0NCmRmDQpgYGANCmRmID0g0Y3RgtC+IDMg0L/QtdGA0LXQvNC10L3QvdGL0YUg0LggNCDQvdCw0LHQu9GO0LTQtdC90LjRjy4g0JTQvtC/0YPRgdGC0LjQvCwg0YfRgtC+INC/0LXRgNC10LzQtdC90L3QsNGPICoqeCoqIC0g0L3QtdC60LjQuSDQutC70Y7Rhywg0LrQvtGC0L7RgNGL0Lkg0L7QtNC90L7Qt9C90LDRh9C90L4g0L7Qv9GA0LXQtNC10LvRj9C10YIg0YLRgyDQuNC70Lgg0LjQvdGDINC30LDQv9C40YHRjC4gIA0K0JTQvtC/0YPRgdGC0LjQvCwg0LXRgdGC0Ywg0LTRgNGD0LPQvtC5INC00LDRgtCwINGE0YDQtdC50LwgKmRmX3NhbGFyeSosINC60L7RgtC+0YDRi9C5INGB0L7QtNC10YDQttC40YIg0L3QsNCx0L7RgCDQutC70Y7Rh9C10LkgeCDQsiDQutCw0LrQvtC8LdGC0L4g0L/QvtGA0Y/QtNC60LUg0Lgg0LTQvtC/0L7Qu9C90LjRgtC10LvRjNC90YvQtSDQutC+0LvQvtC90LrQuCwg0LrQsNC6INC90LDQv9GA0LjQvNC10YAsINC30LDRgNC/0LDQu9Cw0YLQsCAoc2FsYXJ5KQ0KYGBge3J9DQpkZl9zYWxhcnkgPC0gZGF0YS5mcmFtZSh4ID0gYygzLCAyLCA2LCAxKSwgc2FsYXJ5ID0gYygxMDAsIDEwMDAsIDMwMCwgNTAwKSkNCmRmX3NhbGFyeQ0KYGBgDQrQotC10L/QtdGA0Ywg0YXQvtGC0LjQvCDRgdC+0LfQtNCw0YLRjCDQvdC+0LLRi9C5INC00LDRgtCwINGE0YDQtdC50Lwg0LjQtyDQtNCy0YPRhSDRgdGC0LDRgNGL0YUsINC30LDQv9C40YHQuCDQutC+0YLQvtGA0YvRhSDQsdGD0LTRg9GCINC+0LHRitC10LTQuNC90LXQvdGLINC/0L4g0LrQu9GO0YfRgyAqKngqKiAtINCy0L7RgdC/0L7Qu9GM0LfRg9C10LzRgdGPINGE0YPQvdC60YbQuNC10LkgKm1lcmdlKiwg0LIg0LrQsNGH0LXRgdGC0LLQtSDQv9C10YDQstGL0YUg0LTQstGD0YUg0LDRgNCz0YPQvNC10L3RgtC+0LIg0YPQutCw0LbQtdC8INC00LDRgtCwINGE0YDQtdC50LzRiywg0LjQtyDQutC+0YLQvtGA0YvRhSDQu9C10L/QuNC8INC90L7QstGL0LksINCwINGC0YDQtdGC0YzQuNC8IC0g0L7QsdC+0LfQvdCw0YfQsNC10Lwg0LrQu9GO0YcNCmBgYHtyfQ0KbWVyZ2UoZGYsIGRmX3NhbGFyeSwgYnkgPSAieCIpDQpgYGANCtCg0LXQt9GD0LvRjNGC0LDRgiAtINC90L7QstGL0Lkg0LTQsNGC0LAg0YTRgNC10LnQvCwg0YHQviDQstGB0LXQvNC4INC/0L7Qu9C90YvQvNC4INC30LDQv9C40YHRj9C80Lgg0LjQtyDQtNCy0YPRhSDQv9GA0LXQtNGL0LTRg9GJ0LjRhSDQtNCw0YLQsCDRhNGA0LXQudC80L7Qsiwg0L7Qv9GA0LXQtNC10LvRj9C10LzRi9GFINC/0L4g0LrQu9GO0YfRgyAqKngqKi4gIA0KICANCtCU0LvRjyDRgtC10YUsINC60YLQviDQt9C90LDQutC+0Lwg0YEgU1FMIC0g0Y3RgtCwINC+0L/QtdGA0LDRhtC40Y8g0YHQvtC+0YLQstC10YLRgdCy0YPQtdGCICppbm5lciBqb2luKi4gIA0KICANCtCSIFIg0LXRgdGC0Ywg0Lgg0L7RgdGC0LDQu9GM0L3Ri9C1INCy0LjQtNGLINC00LbQvtC40L3QvtCyIChsZWZ0LCByaWdodCwgb3V0ZXIsIGNyb3NzIGpvaW4pLCDQutC+0YLQvtGA0YvQtSDQu9C10LPQutC+INC90LDQudGC0Lgg0L3QsCBzdGFja292ZXJmbG93INC/0L4g0LfQsNC/0YDQvtGB0YMgKiJyIGpvaW5zIioNCg0KI9CT0LvQvtGB0YHQsNGA0LjQuQ0KP2RhdGEuZnJhbWUgIA0KP3N0ciAgDQo/cm93bmFtZXMsID9jb2xuYW1lcywgP2RpbW5hbWVzLCA/bnJvdywgP25jb2wsID8gZGltICANCj9zdWJzZXQsID9yYmluZCwgP2NiaW5kLCA/bWVyZ2UNCg0KIyDQl9Cw0LTQsNGH0LANCtCU0LDRgtCwINGE0YDQtdC50LwgYXR0aXR1ZGUgLS0g0LLRgdGC0YDQvtC10L3QvdGL0Lkg0LzQsNGB0YHQuNCyINC00LDQvdC90YvRhSwg0YHQvtC00LXRgNC20LDRidC40Lkg0YDQtdC50YLQuNC90LMg0LTQtdC/0LDRgNGC0LDQvNC10L3RgtC+0LIg0L7QtNC90L7QuSDRhNC40L3QsNC90YHQvtCy0L7QuSDQutC+0LzQv9Cw0L3QuNC4LCDRgdC+0YHRgtCw0LLQu9C10L3QvdGL0Lkg0YHQvtGC0YDRg9C00L3QuNC60LDQvNC4LiDQn9GA0LXQtNGB0YLQsNCy0YzRgtC1LCDRh9GC0L4g0LLRiyDRhdC+0YLQuNGC0LUg0YPRgdGC0YDQsNC40LLQsNGC0YzRgdGPINC60LDQuiDRgNCw0Lcg0LIg0Y3RgtGDINC60L7QvNC/0LDQvdC40Y4sINC4INC00LDRgtCwINGE0YDQtdC50LwgKNGB0L7QstC10YDRiNC10L3QvdC+INGB0LvRg9GH0LDQudC90L4hKSDQvtC60LDQt9Cw0LvRgdGPINCyINCy0LDRiNC10Lwg0YDQsNGB0L/QvtGA0Y/QttC10L3QuNC4LiANCg0K0JLRiyDRgNC10YjQuNC70LgsINGH0YLQviDRgdCw0LzQvtC1INCz0LvQsNCy0L3QvtC1INC00LvRjyDQstCw0YEgLS0g0Y3RgtC+INCy0L7Qt9C80L7QttC90L7RgdGC0Ywg0YPRh9C40YLRjNGB0Y8g0L3QvtCy0L7QvNGDIChsZWFybmluZykuINCS0L7Qt9GM0LzQuNGC0LUgNSDRgtC+0L/QvtCy0YvRhSDQtNC10L/QsNGA0YLQsNC80LXQvdGC0L7QsiDQv9C+INGN0YLQvtC80YMg0L/QvtC60LDQt9Cw0YLQtdC70Y4uINCY0Lcg0Y3RgtC+0LPQviDQvdCw0LHQvtGA0LAg0LLQsNC8INCx0L7Qu9C10LUg0LLRgdC10LPQviDQv9C+0LTQvtC50LTRkdGCINGC0L7RgiDQtNC10L/QsNGA0YLQsNC80LXQvdGCLCDQutC+0YLQvtGA0YvQuSDQuNC80LXQtdGCINC90LDQuNCx0L7Qu9GM0YjRg9GOINGB0YPQvNC80YMg0LHQsNC70LvQvtCyINC/0L4g0YLRgNGR0Lwg0L/QvtC60LDQt9Cw0YLQtdC70Y/QvDog0YDQtdCw0LrRhtC40Y8g0L3QsCDQttCw0LvQvtCx0Ysg0YDQsNCx0L7RgtC90LjQutC+0LIgKGNvbXBsYWludHMpLCDQvdCw0LTQsdCw0LLQutC4INCyINC30LDQstC40YHQuNC80L7RgdGC0Lgg0L7RgiDRgNC10LfRg9C70YzRgtCw0YLQvtCyINGA0LDQsdC+0YLRiyAocmFpc2VzKSDQuCDQstC+0LfQvNC+0LbQvdC+0YHRgtGMINC/0YDQvtC00LLQuNC20LXQvdC40Y8gKGFkdmFuY2UpLg0KDQrQmtCw0LrQvtC5INC20LUg0LTQtdC/0LDRgNGC0LDQvNC10L3RgiDQstCw0Lwg0LLRi9Cx0YDQsNGC0Yw/INCd0LDQv9C40YjQuNGC0LUg0LXQs9C+INC90L7QvNC10YAgWFggKNC90L7QvNC10YAg0YHRgtGA0L7QutC4INCyINC00LDRgtCwINGE0YDQtdC50LzQtSkNCmBgYHtyfQ0KaGVhZChhdHRpdHVkZSkNCmBgYA0KKirQkNC70LPQvtGA0LjRgtC8KiogIA0KMS4g0J3QsNC50YLQuCDRgtC+0L8tNSDQv9C+0LrQsNC30LDRgtC10LvQtdC5IGxlYXJuaW5nDQpgYGB7cn0NCmF0dGl0dWRlJGxlYXJuaW5nWzE6NV0NCmBgYA0KMi4g0J3QsNC50YLQuCDQvdC+0LzQtdGA0LAg0L3QsNCx0LvRjtC00LXQvdC40Lkg0YEg0YLQvtC/LTUg0L/QvtC60LDQt9Cw0YLQtdC70LXQvCBsZWFybmluZw0KYGBge3J9DQpvcmRlcigtYXR0aXR1ZGUkbGVhcm5pbmcpWzE6NV0NCmBgYA0KMy4g0J7QsdGA0LDRgtC40YLRjNGB0Y8g0L/QviDQu9C+0LPQuNGH0LXRgdC60L7QvNGDINC40L3QtNC10LrRgdC40YDQvtCy0LDQvdC40Y4g0Log0YfQsNGB0YLQuCDQtNCw0YLQsCDRhNGA0LXQudC80LAg0L/QviDRgtC+0L8tNSDQv9C+IGxlYXJuaW5nDQpgYGB7cn0NCmF0dGl0dWRlW29yZGVyKC1hdHRpdHVkZSRsZWFybmluZylbMTo1XSwgXQ0KYGBgDQo0LiDQktGL0LLQtdGB0YLQuCDRh9Cw0YHRgtGMINC00LDRgtCwINGE0YDQtdC50LzQsCDQv9C+INGC0L7Qvy01INCyIGxlYXJuaW5nINCx0LXQtyDRgdGC0L7Qu9Cx0YbQsCBsZWFybmluZw0KYGBge3J9DQphdHRpdHVkZVtvcmRlcigtYXR0aXR1ZGUkbGVhcm5pbmcpLF1bMTo1LF1bYygiY29tcGxhaW50cyIsInJhaXNlcyIsImFkdmFuY2UiKV0NCmBgYA0KNS4g0J/QvtGB0YfQuNGC0LDRgtGMINGB0YPQvNC80YMg0YDRj9C00L7QsiDQv9C+INGC0YDQtdC8INC+0YHRgtCw0LLRiNC40LzRgdGPINC/0L7QutCw0LfQsNGC0LXQu9GP0Lwg0LIg0LLRi9Cy0LXQtNC10L3QvdC+0Lkg0YfQsNGB0YLQuCDQtNCw0YLQsCDRhNGA0LXQudC80LANCmBgYHtyfQ0Kcm93U3VtcyhhdHRpdHVkZVtvcmRlcigtYXR0aXR1ZGUkbGVhcm5pbmcpWzE6NV0sYygiY29tcGxhaW50cyIsInJhaXNlcyIsImFkdmFuY2UiKV0pDQpgYGANCjYuINCd0LDQudGC0Lgg0LzQsNC60YHQuNC80LDQu9GM0L3QvtC1INC30L3QsNGH0LXQvdC40LUNCg0KYGBge3J9DQp3aGljaC5tYXgocm93U3VtcyhhdHRpdHVkZVtvcmRlcigtYXR0aXR1ZGUkbGVhcm5pbmcpWzE6NV0sYygiY29tcGxhaW50cyIsInJhaXNlcyIsImFkdmFuY2UiKV0pKQ0KIyDQuNC70LgNCndoaWNoLm1heChyb3dTdW1zKGF0dGl0dWRlW29yZGVyKC1hdHRpdHVkZSRsZWFybmluZyksXVsxOjUsXVtjKCJjb21wbGFpbnRzIiwicmFpc2VzIiwiYWR2YW5jZSIpXSkpDQpgYGANCtCd0LUg0L7Rh9C10L3RjCDQv9C+0LnQvNGDLCDQutCw0Log0YDQsNCx0L7RgtCw0LXRgiBvcmRlciDQuCDRgtCw0LrQvtC1INGB0LvQvtC20L3QvtC1INC70L7Qs9C40YfQtdGB0LrQvtC1INC40L3QtNC10LrRgdC40YDQvtCy0LDQvdC40LUgDQoNCiMgQ9C/0L7RgdC+0LHRiyDQvtCx0YDQsNGJ0LXQvdC40Y8g0Log0YHRgtGA0L7QutCw0LwsINGB0L7QvtGC0LLQtdGC0YHQstGD0Y7RidC40LUg0L7Qv9GA0LXQtNC10LvQtdC90L3Ri9C8INGD0YHQu9C+0LLQuNGP0LwNCtCd0LjQttC10YPQutCw0LfQsNC90L3Ri9C80Lgg0YHQv9C+0YHQvtCx0LDQvNC4INC80L7QttC90L4g0LLRi9Cx0YDQsNGC0Ywg0YLQvtC70YzQutC+INGC0LUg0YHRgtGA0L7QutC4LCDQutC+0YLQvtGA0YvQtSDRgdC+0L7RgtCy0LXRgtGB0YLQstGD0Y7RgiDQtNC10L/QsNGA0YLQsNC80LXQvdGC0LDQvCDRgSDRgNC10LnRgtC40L3Qs9C+0LwgKHJhdGluZykg0L3QuNC20LUg0L/Rj9GC0LjQtNC10YHRj9GC0LgsINC/0YDQuCDRjdGC0L7QvCDRgdC+0YXRgNCw0L3QuNCyINCy0YHQtSDRgdGC0L7Qu9Cx0YbRiywg0LrRgNC+0LzQtSByYXRpbmcgIA0KKirQodC/0L7RgdC+0LEgMSoqIC0g0LDQu9Cz0L7RgNC40YLQvDogIA0KMS4g0JjRgdC/0L7Qu9GM0LfRg9C10Lwg0YTRg9C90LrRhtC40Y4gc3Vic2V0ICjQv9C+0LTQs9GA0YPQv9C/0LApINC6INC00LDRgtCwINGE0YDQtdC50LzRgyBhdHRpdHVkZSwgIA0KMi4g0LDRgNCz0YPQvNC10L3RgtC+0Lwg0YPQutCw0LfRi9Cy0LDQtdC8INCy0YvQstC10YHRgtC4INC+0L/RgNC10LTQtdC70LXQvdC90YvQtSDRgdGC0YDQvtC60LggKHJhdGluZyA8IDUwKQ0KYGBge3J9DQpzdWJzZXQoYXR0aXR1ZGUsIHJhdGluZyA8IDUwKQ0KYGBgDQoNCjMuINC40YHQutC70Y7Rh9Cw0LXQvCDRgdGC0L7Qu9Cx0LXRhiByYXRpbmcgKC1yYXRpbmcpDQpgYGB7cn0NCnN1YnNldChhdHRpdHVkZSwgcmF0aW5nIDwgNTAsIC1yYXRpbmcpDQpgYGANCioq0KHQv9C+0YHQvtCxIDIqKiAtINCw0LvQs9C+0YDQuNGC0Lw6ICANCjEuINCY0YHQv9C+0LvRjNC30YPQtdC8INGE0YPQvdC60YbQuNGOIHN1YnNldCAo0L/QvtC00LPRgNGD0L/Qv9CwKSDQuiDQtNCw0YLQsCDRhNGA0LXQudC80YMgYXR0aXR1ZGUgKNGC0L7Qu9GM0LrQviDQstGL0L3QvtGB0LjQvCDQsNGA0LPRg9C80LXQvdGC0L7QvCDQsiDQutC+0L3QtdGGKSAgDQoyLiDQktGL0LHQuNGA0LDQtdC8INC40YHQutC70Y7Rh9C40YLRjCDRgdGC0L7Qu9Cx0LXRhiByYXRpbmcsINGB0L7QutGA0LDRidCw0Y8gc2VsZWN0IChzZWwgPSAtcmF0aW5nKSAgDQpgYGB7cn0NCnN1YnNldChzZWwgPSAtcmF0aW5nLCBhdHRpdHVkZSkNCmBgYA0KDQozLiDQktGL0LLQvtC00LjQvCDRgdGC0YDQvtC60Lgg0L/QvtC00LPRgNGD0L/Qv9C+0Lkg0YEgcmF0aW5nIDwgNTAgKHN1YnNldCA9IHJhdGluZyA8IDUwKQ0KYGBge3J9DQpzdWJzZXQoc2VsID0gLXJhdGluZywgc3ViID0gcmF0aW5nIDwgNTAsIGF0dGl0dWRlKQ0KYGBgDQoqKtCh0L/QvtGB0L7QsSAzKiogLSDQsNC70LPQvtGA0LjRgtC8OiAgDQoxLiDQntCx0YDQsNGJ0LDQtdC80YHRjyDQuiDQvtC/0YDQtdC00LXQu9C10L3QvdC+0LzRgyDQuNC90LTQtdC60YHRgyDQtNCw0YLQsCDRhNGA0LXQudC80LAgYXR0aXR1ZGUgIA0KMi4g0JjRgdC/0L7Qu9GM0LfRg9C10Lwg0LvQvtCz0LjRh9C10YHQutC+0LUg0LjQvdC00LXQutGB0LjRgNC+0LLQsNC90LjQtQ0KMy4g0JLRi9Cy0L7QtNC40Lwg0YHRgtGA0L7QutC4LCDRgdC+0L7RgtCy0LXRgtGB0LLRg9GO0YnQuNC1INC70L7Qs9C40YfQtdGB0LrQvtC80YMg0LjQvdC00LXQutGB0YMgW2F0dGl0dWRlJHJhdGluZyA8IDUwXQ0KNC4g0JLRi9Cy0L7QtNC40Lwg0YHRgtGA0L7QutC4INCx0LXQtyDRgdGC0L7Qu9Cx0YbQsCByYXRpbmcgW25hbWVzKGF0dGl0dWRlKSAhPSAicmF0aW5nIl0NCmBgYHtyfQ0KYXR0aXR1ZGVbYXR0aXR1ZGUkcmF0aW5nIDwgNTAsIF0NCmBgYA0KYGBge3J9DQphdHRpdHVkZVthdHRpdHVkZSRyYXRpbmcgPCA1MCwgbmFtZXMoYXR0aXR1ZGUpICE9ICJyYXRpbmciXQ0KYGBgDQoNCg==