R всегда был связан с прикладным анализом данных. Познакомимся с объектом, который редко встречается в других языках программирования.

Факторы

В статистике существует раздение на качественые и количественные переменные
* Качественные факторы определяются факторами
* Фактор - это гибрид целочиесленного (integer) и строкового (character) типа вектора

Чтобы лучше понять структура факторов, приведу пример того, как они создаются:

levels <- sort(unique(x))
f <- match(x, levels)
levels(f) <- as.character(levels)
class(f) <- "factor"

Как мы видим, уровни представляют собой отсортированные уникальные значения переменной. Сам фактор — это не что иное как позиция значения с точки зрения уровней.

x <- factor(sample(1:100, 30, replace = TRUE))
x
 [1] 20 33 21 74 71 99 53 51 24 62 32 99 25 20 23 48 89 87 65 63 61 7  19 68 66 3  41 19 86 7 
Levels: 3 7 19 20 21 23 24 25 32 33 41 48 51 53 61 62 63 65 66 68 71 74 86 87 89 99

Объединить уровни факторы в один можно при помощи конструкции вида:

levels(x)[1:2] <- levels(x)[1]
x
 [1] 20 33 21 74 71 99 53 51 24 62 32 99 25 20 23 48 89 87 65 63 61 3  19 68 66 3  41 19 86 3 
Levels: 3 19 20 21 23 24 25 32 33 41 48 51 53 61 62 63 65 66 68 71 74 86 87 89 99
RNGkind(sample.kind = "Rounding")
non-uniform 'Rounding' sampler used
set.seed(1337)
f <- factor(sample(LETTERS, 30, replace = TRUE))
f
 [1] O O B L J I Y H G D Z Z V F Z A Z Y I G W S B D O Z Y X M Z
Levels: A B D F G H I J L M O S V W X Y Z

У факторов появляется дополнительная строка градации фактора. R выявляет все возможные градации и упорядочивает их

length(f)
[1] 30

Фактор - гибрид. Проверим

is.vector(f)
[1] FALSE
is.numeric(f)
[1] FALSE
is.character(f)
[1] FALSE

По формальным признакам ничего гибридного.
Но! проверим, как работает приведение типов:

as.numeric(f)
 [1] 11 11  2  9  8  7 16  6  5  3 17 17 13  4 17  1 17 16  7  5 14 12  2  3 11 17 16 15 10 17

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

as.character(f)
 [1] "O" "O" "B" "L" "J" "I" "Y" "H" "G" "D" "Z" "Z" "V" "F" "Z" "A" "Z" "Y" "I" "G" "W" "S" "B" "D"
[25] "O" "Z" "Y" "X" "M" "Z"
f[17]
[1] Z
Levels: A B D F G H I J L M O S V W X Y Z

Видим, что у каждого целого есть свое некое подставление - метки буквы латинского алфавита в данном случае

# Посмотреть не все элементы фактора ,а уникальные градации фактора
levels(f)
 [1] "A" "B" "D" "F" "G" "H" "I" "J" "L" "M" "O" "S" "V" "W" "X" "Y" "Z"
# то же, что и length для вектора
nlevels(f)
[1] 17

Уровни фактора

Фактор как наследник вектора имеет свои правила индексирования. НО! для обычного фактора определены только обозначения “==”, “!=

Поэтому к элементам фактора можно обращаться, как к элементам вектора, и не только обращаться, но и производить замену

# исключаем уровень А
# Заменяем А на Z
f[f == "A"] <- "Z"
f
 [1] O O B L J I Y H G D Z Z V F Z Z Z Y I G W S B D O Z Y X M Z
Levels: A B D F G H I J L M O S V W X Y Z

Обрати внимание! В levels фактора переменная А осталась, хотя в данных ее уже нет. Для того, что не избавиться от пустой градации фактора, то можно воспользоваться записью droplevels(f)

# заключение в скобки здесь позволяет сразу вывести результат работы 
(f <- droplevels(f)) 
 [1] O O B L J I Y H G D Z Z V F Z Z Z Y I G W S B D O Z Y X M Z
Levels: B D F G H I J L M O S V W X Y Z

Преобразование уровней фактора

levels(f) <- tolower(levels(f))
#levels(f) <- letters[LETTERS %in% levels(f)]
f
 [1] o o b l j i y h g d z z v f z z z y i g w s b d o z y x m z
Levels: b d f g h i j l m o s v w x y z

Изменились уровни, хотя соответствие осталось таким же

levels(f)[1] <- "bbb"
f
 [1] o   o   bbb l   j   i   y   h   g  
[10] d   z   z   v   f   z   z   z   y  
[19] i   g   w   s   bbb d   o   z   y  
[28] x   m   z  
16 Levels: bbb d f g h i j l m o s ... z

При этом не нужно применять функцию drop levels

Упорядоченные факторы

  1. функция ordered()
  2. ordered = TRUE для factor
temp <- c("freezing cold", "cold", "comfortable", "hot", "burning hot")
# в ответах переменной неявным образом прослеживается отношение порядка
ft <- ordered(sample(temp, 14, replace = TRUE), temp)
ft
 [1] comfortable   hot           burning hot   cold          burning hot   burning hot  
 [7] freezing cold freezing cold burning hot   comfortable   cold          comfortable  
[13] cold          hot          
Levels: freezing cold < cold < comfortable < hot < burning hot

Появились дополнительные значки порядке в levels. Теперь можно воспользоваться операторами не только == или != (не равно), но и >/</>= и т.п.
Например, хочу отобрать только те ответы, в которых хотя бы горячо, т.е. “hot”

ft[ft >= "hot"]
[1] hot         burning hot burning hot burning hot burning hot hot        
Levels: freezing cold < cold < comfortable < hot < burning hot

Получили ответы, которые расположены справа от категории hot

Преобразование количественной переменной в качетсвенную

Это может пригодится, когда есть ряд изменений, которые мы хотим разбить на ряд категории (например, количественные переменные возраста преобразовать в возрастные категории)

Например, вызовем cut на 10 нормально распределенных числах

a
 [1] -2.3438702  0.5902631  0.3191343  0.7016064 -1.3774571  0.3126459  1.1208476  0.4718309
 [9]  1.1276853  0.6777231

Указываем вектор интервалов разбиений от -5 до 5 (аргумент breaks)

cut(a, -5:5)
 [1] (-3,-2] (0,1]   (0,1]   (0,1]   (-2,-1] (0,1]   (1,2]   (0,1]   (1,2]   (0,1]  
Levels: (-5,-4] (-4,-3] (-3,-2] (-2,-1] (-1,0] (0,1] (1,2] (2,3] (3,4] (4,5]

Если в качестве аргумента breaks укзать единственное число (скаляр), то данные будут разбиты на интервалы равной длины так, чтобы крайние значения не входили в смежные интервалы (а именно границы смещаются на 0,1% интервала)

cut(a, 3)
 [1] (-2.35,-1.19]  (-0.0295,1.13] (-0.0295,1.13] (-0.0295,1.13] (-2.35,-1.19]  (-0.0295,1.13]
 [7] (-0.0295,1.13] (-0.0295,1.13] (-0.0295,1.13] (-0.0295,1.13]
Levels: (-2.35,-1.19] (-1.19,-0.0295] (-0.0295,1.13]

Если же мы будем использовать cut в свзяке с table-ом, то можем сразу посмотреть на количество вхождений в каждый конкретный интервал. Например:

table(cut(rnorm(1000), -5:5))

(-5,-4] (-4,-3] (-3,-2] (-2,-1]  (-1,0]   (0,1]   (1,2]   (2,3]   (3,4]   (4,5] 
      0       0      21     135     340     339     140      21       4       0 

Так мы можем получить элементарную осмысленную статистику - фактически мы получаем нечто похожее на гистограмму, которая в данном случае имеет вид нормального распределния (но мы и вызывали функцию rnorm, так что это ожидаемо)

Важное отступление - функция options

У сессии R есть набор активных настроек, отвечающих за подсчет и вывод результатов вычислений
*?optinons

?options

** digits - количество знаков при печати чисел
** error - повдеение при ошибке
** width - длина строки при печати векторов и матриц
Полный список достаточно большой, но есть ряд достаточно важных

Важно для факторов и строк!
По умолчанию, все строковые переменные становятся факторами. Т.е. если R встречается с переменной строкового типа, например, при считывании дата фрейма, то она автоматически превращается в фактор. Это не всегда так и может приводить к ошибочным вычислениям.

Отменить такое поведение можно вызовом
options(stringsAsFactors = FALSE)

Функция tapply

Мы уже не раз поднимали фукнции семейства apply, есть такая и для работы с факторами.
Дело в том, что факторы сами по себе несут мало смысла, они несут смысл как элементу дата фрейма. Одна из наиболее распространенных задач в анализе данных - подсчет некой статистики по группам, которые определяют факторы. Как раз для этих задач удобно пользоваться функцией tapply.
Разберем на примере массива warpbreaks (стародревний массив с данными о поломках прядильных установок в зависимости от типа волоса, с которым работал, и силы натяжения)

str(warpbreaks)
'data.frame':   54 obs. of  3 variables:
 $ breaks : num  26 30 54 25 70 52 51 26 67 18 ...
 $ wool   : Factor w/ 2 levels "A","B": 1 1 1 1 1 1 1 1 1 1 ...
 $ tension: Factor w/ 3 levels "L","M","H": 1 1 1 1 1 1 1 1 1 2 ...

wool и tension - два фактора, у каждого из которых свои градации. Допустим, хочу посмотреть, какой тип шерсти приводит к максимальному количеству поломок - для этого воспользуемся tapply:
* первый аргумент - массив, по которому будет считаться статистика
* второй аргумент - фактор, по градациям которого идет разделение
* третий - функция, которую применяем

tapply(warpbreaks$breaks, warpbreaks$wool, max)
 A  B 
70 44 

Глоссарий

?facotr
?levels, ?nlevels, ?droplevels
?ordered
?cut, ?table
?options
?tapply

Задача

Используйте показанную мной связку из двух функций, чтобы превратить количественную переменную mag (сила землетрясения в баллах по шкале Рихтера) дата фрейма quakes в качественную. Интервалы должны быть длиной в полбалла, начиная с минимального, при этом левый конец интервала включается. Теперь отсортируйте общее количество случаев, попавших в каждую категорию, в порядке убывания.
1. Посмотрю структуру дата-фрейма

str(quakes)
'data.frame':   1000 obs. of  5 variables:
 $ lat     : num  -20.4 -20.6 -26 -18 -20.4 ...
 $ long    : num  182 181 184 182 182 ...
 $ depth   : int  562 650 42 626 649 195 82 194 211 622 ...
 $ mag     : num  4.8 4.2 5.4 4.1 4 4 4.8 4.4 4.7 4.3 ...
 $ stations: int  41 15 43 19 11 12 43 15 35 19 ...
  1. Внесу дата фрейм в переменную, чтобы работать с ним
q <- quakes
summary(q$mag)
   Min. 1st Qu.  Median    Mean 3rd Qu. 
   4.00    4.30    4.60    4.62    4.90 
   Max. 
   6.40 
  1. Сгенерирую последовательность от min(q\(mag)* до *max(q\)mag) с шагом 0.5
?ceiling
#ceiling, чтобы включить верхнюю границу
a <- seq(min(q$mag), ceiling(max(q$mag)), by = 0.5)
a
[1] 4.0 4.5 5.0 5.5 6.0 6.5 7.0
  1. Разделю по сгенерированной последовательности и сразу отсортирую по количеству случаев, иначе вылезет огромный вектор
sort(table(cut(q$mag, br = a, right = FALSE)))

[6.5,7) [6,6.5) [5.5,6) [5,5.5) [4,4.5) [4.5,5) 
      0       5      33     160     377     425 

?cut ?table

Подсказки:

придётся чуть-чуть повозиться с аргументами; интервалы должны быть в точности такими, как указаны в ответах.

?cut

Вернемся к массиву avianHabitat или Дата Фрейм - часть 2

Чем больше приемов мы знаем, тем больше возможностей у нас открывается в прикладном анализе данных. Вернемся к массиву avianHabitat

str(avian)
'data.frame':   1070 obs. of  17 variables:
 $ Site    : chr  "BunkerHill27" "BunkerHill27" "BunkerHill27" "BunkerHill27" ...
 $ Observer: chr  "RA" "RA" "RA" "RA" ...
 $ Subpoint: int  1 2 3 4 5 6 7 8 9 10 ...
 $ VOR     : num  6 4.5 2 2.5 4 2 5.5 4 3.5 3.5 ...
 $ PDB     : int  3 2 4 3 4 3 3 2 2 2 ...
 $ DBHt    : num  5.2 3.1 5.5 6.2 5.4 4 5.2 4.4 5.7 4.8 ...
 $ PW      : int  0 3 1 0 0 0 2 1 1 0 ...
 $ WHt     : num  0 4.7 5.8 0 0 0 6.3 4.1 5.7 0 ...
 $ PE      : int  4 3 3 3 3 3 2 2 2 1 ...
 $ EHt     : num  2.9 4.1 3.9 4 3.5 4.1 2.6 4.3 5.2 1.7 ...
 $ PA      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ AHt     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ PH      : int  4 3 3 4 4 2 4 5 4 5 ...
 $ HHt     : num  3 3.5 7.5 5 3.7 3.5 5.8 8.2 6.9 5.7 ...
 $ PL      : int  0 2 0 0 0 0 0 0 0 0 ...
 $ LHt     : num  0 1 0 0 0 0 0 0 0 0 ...
 $ PB      : int  0 0 0 0 0 0 0 0 0 0 ...

Удостоверимся, что мы в рабочей директории находится файл проекта и исходный csv файл.

getwd()
[1] "C:/Users/Tony/Desktop/R/Mine"

Ок, я в нужной директории. Из-под Линукса, конечно, работать с диеркториями было бы удобнее. Но так или иначе к файлам из рабочей директории можно обращаться, не указывая полный путь, а просто по имени, т.е.

Готово.
Если бы у меня был уже предварительно заготовленный файл проекта.R, то функцией source можно было его считать (указава его название) и выполнить все команды прописанные в скрипте

source()
Error in source() : argument "file" is missing, with no default

Удостоверюсь, что массив записан в дата фрейма avian существует

Иногда файлы с данными настолько большие, что ни один текстовый редактор их не откроет. Чтобы найти такой файл в рабочей директории (да и любой другой, в принципе, тоже), то можно воспользоваться функцией list.files

При этом, если файлов в директории много, то можно воспользоваться каким-нибудь регулярным выражением, чтобы обратиться к конкретным файлам.

list.files()
 [1] "avianHabitat.csv"        
 [2] "Data frame.nb.html"      
 [3] "Data frame.Rmd"          
 [4] "Data Intro.nb.html"      
 [5] "Data Intro.Rmd"          
 [6] "Factors.nb.html"         
 [7] "Factors.Rmd"             
 [8] "Intro.nb.html"           
 [9] "Intro.Rmd"               
[10] "Mtrx-and-Lsts---2.html"  
[11] "Mtrx and Lsts - 2.Rmd"   
[12] "Mtrx and Lsts.nb.html"   
[13] "Mtrx and Lsts.Rmd"       
[14] "rsconnect"               
[15] "Strings.nb.html"         
[16] "Strings.Rmd"             
[17] "Vector.nb.html"          
[18] "Vector.Rmd"              
[19] "Матрицы и списки.nb.html"

Если хочу найти только csv файлы, то вспользуюсь регулярным выражением

list.files(pattern = ".csv$")
[1] "avianHabitat.csv"

Можно сделать и более хитро, хотя в данном случае большого смысла в этом нет, например:

list.files(pattern = ".*\\.csv$")
[1] "avianHabitat.csv"
# где "." - любой символ, т.е. неважно с какого символа начинается слова
# "*" - он же, т.е. любой символ, но повторенный любое количество раз
# ".*" - значит мне не важно начало
# "\\." - это обычная точка, но чтобы она считывалась как wildcard приходится экранировать двумя бэкслешами
#"\\.csv$" - заканчивается на .csv

Но допустим, этот найденный нам нужный файл по-прежнему очень большой. Открыть его ничем не получается. Что делать?
В такой ситуации можно воспользоваться низкоуровневой функцией readLines, указав количество строк к прочтению

readLines("avianHabitat.csv", 5)
[1] "Site,Observer,Subpoint,VOR,PDB,DBHt,PW,WHt,PE,EHt,PA,AHt,PH,HHt,PL,LHt,PB"
[2] "BunkerHill27,RA,1,6,3,5.2,0,0,4,2.9,0,0,4,3,0,0,0"                        
[3] "BunkerHill27,RA,2,4.5,2,3.1,3,4.7,3,4.1,0,0,3,3.5,2,1,0"                  
[4] "BunkerHill27,RA,3,2,4,5.5,1,5.8,3,3.9,0,0,3,7.5,0,0,0"                    
[5] "BunkerHill27,RA,4,2.5,3,6.2,0,0,3,4,0,0,4,5,0,0,0"                        

Вижу, что файл корректный, а значит дальше свободно смогу воспользоваться функцией read.csv.
Что если файл был бы некорректным?
Воспользовались функцией read.table и вручную прописали бы нужные аргументы:

Результат точно такой же

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

Если нажать на стрелочку рядом с дата фреймом, то увидим выкладку по переменным

Допустим, я вижу, что переменная Observer считалась, как строка, тогда как логичнее было ее считать фактором. Тогда могу изменить ее тип

Теперь вижу, что все правильно

Вообще самая частая проблема, когда наоборот по умолчанию при считывании дата фрейма переменные строкового типа character считаются факторами (factor). Это происходит, т.к. по умолчнаию в сессии R установлена такая опция:
#options(stringsAsFactors = TRUE)
Чтобы этого не происходило перед считыванием дата фрейма лучше менять ее на FALSE, а потом уже вручную строки преобразовывать в факторы (которых обычно заведомо меньше)

Проверка диапазона значений

Возвращаемся к вопросу проверки диапазона значений. Раньше мы это делали по сути вручную

check_percent_range <- function(x) {
  any(x < 0 | x > 100)
}
check_percent_range(avian$PW)
[1] FALSE

У нас уже есть функция, написанная ранее, но что делать, когда переменная не одна, а огромное множество, и все их перепроверять вручную довольно утомительно. Автоматически все это можно сделать с помощью функции семейства apply.
Для начала пересчитаем % total coverage с помощью пакета stringr

library(stringr)
package 㤼㸱stringr㤼㸲 was built under R version 4.0.2

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

#coverage_variables <- names(avian)[-(1:4)][c(T,F)]
#avian$total_coverage <- rowSums(avian[ , coverage_variables])
coverage_variables <- names(avian)[str_detect(names(avian), "^P")]
#где в str_detect мы закинули все имена переменных, начинающихся с буквы P (регулярное выражение "^" - значит начало строки)
coverage_variables
[1] "PDB" "PW"  "PE"  "PA"  "PH"  "PL"  "PB" 

Теперь провернем то, ради чего все это затевалось

sapply(coverage_variables, function(name) check_percent_range(avian[[name]]))
  PDB    PW    PE    PA    PH    PL    PB 
FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
#где function(name) - указание о том, что будем применять анонимную функцию, после которого указываем саму функцию
##[[name]], т.к. функция на вход принимает вектор, поэтому и извлекаем вектор из дата фрейма, а не строку

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

Посмотрим на уникальные названия наблюдений под переменной Site

unique(avian$Site)
  [1] "BunkerHill27"       "BunkerHill26"       "BunkerHill25"      
  [4] "BunkerHill12"       "BunkerHill13"       "BunkerHill14"      
  [7] "BunkerHill15"       "BunkerHill16"       "BunkerHill17"      
 [10] "BunkerHill24"       "BunkerHill23"       "BunkerHill22"      
 [13] "BunkerHill21"       "BunkerHill11"       "CreteCreek18"      
 [16] "CreteCreek16"       "CreteCreek14"       "CreteCreek12"      
 [19] "CreteCreek24"       "CreteCreek22"       "CreteCreek120"     
 [22] "CreteCreek118"      "CreteCreek116"      "CreteCreek114"     
 [25] "CreteCreek112"      "CreteCreek110"      "CreteCreek21"      
 [28] "CreteCreek23"       "CreteCreek29"       "CreteCreek28"      
 [31] "CreteCreek25"       "CreteCreek26"       "CreteCreek27"      
 [34] "HortonCreek16"      "HortonCreek15"      "HortonCreek14"     
 [37] "HortonCreek13"      "HortonCreek12"      "HortonCreek11"     
 [40] "HortonCreek17"      "HortonCreek18"      "HortonCreek19"     
 [43] "HortonCreek110"     "HortonCreek111"     "HortonCreek113"    
 [46] "HortonCreek114"     "HortonCreek115"     "HortonCreek116"    
 [49] "HortonCreek126"     "HortonCreek125"     "HortonCreek124"    
 [52] "HortonCreek123"     "HortonCreek122"     "HortonCreek121"    
 [55] "HortonCreek120"     "HortonCreek119"     "HortonCreek118"    
 [58] "HortonCreek117"     "HortonCreek112"     "LivingstonCreek112"
 [61] "LivingstonCreek113" "LivingstonCreek114" "LivingstonCreek115"
 [64] "LivingstonCreek116" "LivingstonCreek211" "LivingstonCreek210"
 [67] "LivingstonCreek29"  "LivingstonCreek13"  "LivingstonCreek14" 
 [70] "LivingstonCreek15"  "LivingstonCreek16"  "LivingstonCreek17" 
 [73] "LivingstonCreek28"  "LivingstonCreek27"  "LivingstonCreek26" 
 [76] "LivingstonCreek25"  "LivingstonCreek18"  "LivingstonCreek12" 
 [79] "LivingstonCreek11"  "LivingstonCreek19"  "LivingstonCreek110"
 [82] "LivingstonCreek111" "LivingstonCreek24"  "LivingstonCreek23" 
 [85] "LivingstonCreek22"  "LivingstonCreek21"  "McAdamCreek18"     
 [88] "McAdamCreek17"      "McAdamCreek16"      "McAdamCreek15"     
 [91] "McAdamCreek14"      "McAdamCreek13"      "McAdamCreek12"     
 [94] "McAdamCreek11"      "McAdamCreek27"      "McAdamCreek26"     
 [97] "McAdamCreek25"      "McAdamCreek24"      "McAdamCreek23"     
[100] "McAdamCreek22"      "McAdamCreek21"     

Видим, что все они строятся похожим образом. Это может быть полезным, если хотим сравнить целые географические регионы между собой. Как с этим можно работать, зная методы работы со строками. На помощь опять придет пакет stringr. Заведем новую переменную

#1) где первый аргумент - это переменная
#2) далее регулярное выражение, обозначающее все цифры [:digit:]
#а "+" - wildcard, обозначающает, что символ повторен какое-то количество раз
#т.е. "[:digit:]+" - это любая цифра, повторенная какое-то произвольное количество раз
#3) третий аргумент - на что заменяем (на "", т.е. на пустую строку)
str(avian$site_name)
 chr [1:1070] "BunkerHill" "BunkerHill" "BunkerHill" "BunkerHill" "BunkerHill" ...

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

avian$site_name <- factor(str_replace(avian$site, "[:digit:]", ""))
str(avian$site_name)
 Factor w/ 5 levels "BunkerHill","CreteCreek",..: 1 1 1 1 1 1 1 1 1 1 ...
summary(avian$site_name)
     BunkerHill      CreteCreek 
            140             190 
    HortonCreek LivingstonCreek 
            260             290 
    McAdamCreek 
            190 

Видим, что теперь у нас есть переменная с 5 уровнями, каждый из которых соответсвует какому-то географическому региону. По такому фактору можно будет ориентировться при подсчете статистики

tapply(avian$DBHt, avian$site_name, mean)
     BunkerHill      CreteCreek 
      2.2578571       0.6168421 
    HortonCreek LivingstonCreek 
      0.3753846       0.4648276 
    McAdamCreek 
      0.9042105 

Это уже некий продвинутый анализ данных.
Можем так же оценить, например, регион в котором покрытие растениями (total_coverage) - наименьший

tapply(avian$total_coverage, avian$site_name, summary)
$BunkerHill
   Min. 1st Qu.  Median    Mean 
  4.000   8.000   9.000   9.236 
3rd Qu.    Max. 
 10.000  13.000 

$CreteCreek
   Min. 1st Qu.  Median    Mean 
   6.00    9.00   10.00   10.02 
3rd Qu.    Max. 
  11.00   14.00 

$HortonCreek
   Min. 1st Qu.  Median    Mean 
   3.00    9.00   10.00   10.14 
3rd Qu.    Max. 
  11.00   16.00 

$LivingstonCreek
   Min. 1st Qu.  Median    Mean 
  2.000   8.000  10.000   9.479 
3rd Qu.    Max. 
 11.000  17.000 

$McAdamCreek
   Min. 1st Qu.  Median    Mean 
  2.000   7.000   9.000   8.626 
3rd Qu.    Max. 
 10.000  15.000 

Теперь можем, например, определить, кто их ученых нашел, какие самые высокие растения из представителей своего вида. Ученых у нас три в переменной Observer, которая записана как фактор (JT, RA, RR). А вот видов растений больше: DB (карликовая берёза), W (ива), E (вереск), A (ольха), H (травяные растения), L (лишайники).
1. Найду переменные с высотой видов

names(avian)[str_detect(names(avian), ".Ht$")]
[1] "DBHt" "WHt"  "EHt"  "AHt" 
[5] "HHt"  "LHt" 
  1. Запишу их в переменную
Ht_variables
[1] "DBHt" "WHt"  "EHt"  "AHt"  "HHt"  "LHt" 
  1. С помощью sapply найду общую статистику
sapply(Ht_variables, function(name) summary(avian[[name]]))
              DBHt       WHt       EHt        AHt      HHt      LHt
Min.     0.0000000  0.000000 0.0000000  0.0000000 0.000000 0.000000
1st Qu.  0.0000000  0.000000 0.3000000  0.0000000 1.400000 0.000000
Median   0.0000000  0.400000 0.8000000  0.0000000 2.300000 0.200000
Mean     0.7827103  1.026822 0.9658879  0.1859813 2.321028 0.268514
3rd Qu.  1.2000000  1.100000 1.4000000  0.0000000 3.100000 0.500000
Max.    10.0000000 24.500000 5.3000000 31.5000000 8.200000 1.300000

Это можно сделать еще так, получив то же самое. Смысл в том, что функции saplly передаю не просто вектор строк, а имена колонок.

sapply(avian[,Ht_variables], summary)
              DBHt       WHt       EHt        AHt      HHt      LHt
Min.     0.0000000  0.000000 0.0000000  0.0000000 0.000000 0.000000
1st Qu.  0.0000000  0.000000 0.3000000  0.0000000 1.400000 0.000000
Median   0.0000000  0.400000 0.8000000  0.0000000 2.300000 0.200000
Mean     0.7827103  1.026822 0.9658879  0.1859813 2.321028 0.268514
3rd Qu.  1.2000000  1.100000 1.4000000  0.0000000 3.100000 0.500000
Max.    10.0000000 24.500000 5.3000000 31.5000000 8.200000 1.300000

Ладно, пока не понимаю, как получить выкладку через одну команду сразу по всем растениям. Сделаем по порядку:

tapply(avian$DBHt, avian$Observer, summary)
$JT
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.700   1.303   1.950   9.900 

$RA
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.0000  0.0000  0.7671  1.2000 10.0000 

$RR
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.0000  0.0000  0.5829  1.1000  5.0000 

Выигрывает Ra

tapply(avian$WHt, avian$Observer, summary)
$JT
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.000   1.207   0.800  24.500 

$RA
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.500   1.013   1.100  18.500 

$RR
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.500   0.972   1.100  22.000 

Выигрывает JT

tapply(avian$EHt, avian$Observer, summary)
$JT
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.400   0.700   1.221   1.700   5.300 

$RA
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.4000  0.8000  0.9564  1.4000  4.9000 

$RR
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.2250  0.8000  0.8708  1.3000  4.2000 
tapply(avian$AHt, avian$Observer, summary)
$JT
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.0000  0.0000  0.8967  0.0000 31.5000 

$RA
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.000   0.112   0.000  19.200 

$RR
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
0.000000 0.000000 0.000000 0.000578 0.000000 0.200000 
tapply(avian$HHt, avian$Observer, summary)
$JT
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   1.400   2.200   2.669   4.050   8.200 

$RA
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   1.400   2.300   2.244   3.000   7.500 

$RR
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   1.500   2.300   2.298   3.000   7.300 
tapply(avian$LHt, avian$Observer, summary)
$JT
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.200   0.204   0.400   0.800 

$RA
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.0000  0.2000  0.2532  0.4000  1.3000 

$RR
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   0.300   0.322   0.500   1.100 

Прочитал на форуме решений, что ту выкладку, которую я получал, можно было очень просто разделить по фактора. Глобально все так.

max_height <- sapply(avian[,Ht_variables], max)
data.frame(max_height, avian$Observer[max_height])

или так

aggregate(list(avian[,Ht_variables]), by = list(avian$Observer), max)

используется функция aggregate - аналог tapply только для нескольких столбцов

https://stackoverflow.com/questions/7029800/how-to-run-tapply-on-multiple-columns-of-data-frame-using-r

Общий глоссарий для этого урока:

  • ?paste (?paste0), ?strsplit

  • Regular expressions

  • ?grep (?grepl, ?gsub)

  • library(stringr): ?str_extract, ?str_replace

  • ?tolower, ?toupper

  • ?getwd, ?setwd, ?list.files, ?list.dirs

  • ?formatC, ?cat

  • ?factor

  • ?levels, ?nlevels, ?droplevels

  • ?ordered

  • ?cut, ?table

  • ?options

  • ?tapply

LS0tDQp0aXRsZTogItCk0LDQutGC0L7RgNGLIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KUiDQstGB0LXQs9C00LAg0LHRi9C7INGB0LLRj9C30LDQvSDRgSDQv9GA0LjQutC70LDQtNC90YvQvCDQsNC90LDQu9C40LfQvtC8INC00LDQvdC90YvRhS4g0J/QvtC30L3QsNC60L7QvNC40LzRgdGPINGBINC+0LHRitC10LrRgtC+0LwsINC60L7RgtC+0YDRi9C5INGA0LXQtNC60L4g0LLRgdGC0YDQtdGH0LDQtdGC0YHRjyDQsiDQtNGA0YPQs9C40YUg0Y/Qt9GL0LrQsNGFINC/0YDQvtCz0YDQsNC80LzQuNGA0L7QstCw0L3QuNGPLiAgDQoNCiMjINCk0LDQutGC0L7RgNGLDQrQkiDRgdGC0LDRgtC40YHRgtC40LrQtSDRgdGD0YnQtdGB0YLQstGD0LXRgiDRgNCw0LfQtNC10L3QuNC1INC90LAgKtC60LDRh9C10YHRgtCy0LXQvdGL0LUqINC4ICrQutC+0LvQuNGH0LXRgdGC0LLQtdC90L3Ri9C1KiDQv9C10YDQtdC80LXQvdC90YvQtSAgDQoqINCa0LDRh9C10YHRgtCy0LXQvdC90YvQtSDRhNCw0LrRgtC+0YDRiyDQvtC/0YDQtdC00LXQu9GP0Y7RgtGB0Y8gKtGE0LDQutGC0L7RgNCw0LzQuCogIA0KKiAqKtCk0LDQutGC0L7RgCoqIC0g0Y3RgtC+INCz0LjQsdGA0LjQtCDRhtC10LvQvtGH0LjQtdGB0LvQtdC90L3QvtCz0L4gKGludGVnZXIpINC4INGB0YLRgNC+0LrQvtCy0L7Qs9C+IChjaGFyYWN0ZXIpINGC0LjQv9CwINCy0LXQutGC0L7RgNCwICANCiAgDQpgYGB7cn0NClN5cy5zZXRlbnYoTEFORyA9ICJlbiIpDQpgYGANCiAgDQrQp9GC0L7QsdGLINC70YPRh9GI0LUg0L/QvtC90Y/RgtGMINGB0YLRgNGD0LrRgtGD0YDQsCDRhNCw0LrRgtC+0YDQvtCyLCDQv9GA0LjQstC10LTRgyDQv9GA0LjQvNC10YAg0YLQvtCz0L4sINC60LDQuiDQvtC90Lgg0YHQvtC30LTQsNGO0YLRgdGPOg0KYGBge3J9DQpsZXZlbHMgPC0gc29ydCh1bmlxdWUoeCkpDQpmIDwtIG1hdGNoKHgsIGxldmVscykNCmxldmVscyhmKSA8LSBhcy5jaGFyYWN0ZXIobGV2ZWxzKQ0KY2xhc3MoZikgPC0gImZhY3RvciINCmBgYA0K0JrQsNC6INC80Ysg0LLQuNC00LjQvCwg0YPRgNC+0LLQvdC4INC/0YDQtdC00YHRgtCw0LLQu9GP0Y7RgiDRgdC+0LHQvtC5INC+0YLRgdC+0YDRgtC40YDQvtCy0LDQvdC90YvQtSDRg9C90LjQutCw0LvRjNC90YvQtSDQt9C90LDRh9C10L3QuNGPINC/0LXRgNC10LzQtdC90L3QvtC5LiDQodCw0Lwg0YTQsNC60YLQvtGAIOKAlCDRjdGC0L4g0L3QtSDRh9GC0L4g0LjQvdC+0LUg0LrQsNC6INC/0L7Qt9C40YbQuNGPINC30L3QsNGH0LXQvdC40Y8g0YEg0YLQvtGH0LrQuCDQt9GA0LXQvdC40Y8g0YPRgNC+0LLQvdC10LkuICANCiAgDQoNCmBgYHtyfQ0KeCA8LSBmYWN0b3Ioc2FtcGxlKDE6MTAwLCAzMCwgcmVwbGFjZSA9IFRSVUUpKQ0KeA0KYGBgDQrQntCx0YrQtdC00LjQvdC40YLRjCDRg9GA0L7QstC90Lgg0YTQsNC60YLQvtGA0Ysg0LIg0L7QtNC40L0g0LzQvtC20L3QviDQv9GA0Lgg0L/QvtC80L7RidC4INC60L7QvdGB0YLRgNGD0LrRhtC40Lgg0LLQuNC00LA6DQpgYGB7cn0NCmxldmVscyh4KVsxOjJdIDwtIGxldmVscyh4KVsxXQ0KeA0KYGBgDQoNCmBgYHtyfQ0KUk5Ha2luZChzYW1wbGUua2luZCA9ICJSb3VuZGluZyIpDQpzZXQuc2VlZCgxMzM3KQ0KZiA8LSBmYWN0b3Ioc2FtcGxlKExFVFRFUlMsIDMwLCByZXBsYWNlID0gVFJVRSkpDQpgYGANCmBgYHtyfQ0KZg0KYGBgDQrQoyDRhNCw0LrRgtC+0YDQvtCyINC/0L7Rj9Cy0LvRj9C10YLRgdGPINC00L7Qv9C+0LvQvdC40YLQtdC70YzQvdCw0Y8g0YHRgtGA0L7QutCwICrQs9GA0LDQtNCw0YbQuNC4KiDRhNCw0LrRgtC+0YDQsC4gUiDQstGL0Y/QstC70Y/QtdGCINCy0YHQtSDQstC+0LfQvNC+0LbQvdGL0LUg0LPRgNCw0LTQsNGG0LjQuCDQuCDRg9C/0L7RgNGP0LTQvtGH0LjQstCw0LXRgiDQuNGFDQpgYGB7cn0NCmxlbmd0aChmKQ0KYGBgDQoqKtCk0LDQutGC0L7RgCoqIC0g0LPQuNCx0YDQuNC0LiDQn9GA0L7QstC10YDQuNC8DQpgYGB7cn0NCmlzLnZlY3RvcihmKQ0KYGBgDQpgYGB7cn0NCmlzLm51bWVyaWMoZikNCmBgYA0KYGBge3J9DQppcy5jaGFyYWN0ZXIoZikNCmBgYA0K0J/QviDRhNC+0YDQvNCw0LvRjNC90YvQvCDQv9GA0LjQt9C90LDQutCw0Lwg0L3QuNGH0LXQs9C+INCz0LjQsdGA0LjQtNC90L7Qs9C+LiAgDQoqKtCd0L4hKiog0L/RgNC+0LLQtdGA0LjQvCwg0LrQsNC6INGA0LDQsdC+0YLQsNC10YIg0L/RgNC40LLQtdC00LXQvdC40LUg0YLQuNC/0L7QsjoNCmBgYHtyfQ0KYXMubnVtZXJpYyhmKQ0KYGBgDQrQktC40LTQuNC8LCDRh9GC0L4g0YEg0L7QtNC90L7QuSDRgdGC0L7RgNC+0L3RiyDRhNCw0LrRgtC+0YAgLSDRhtC10LvQvtGH0LjRgdC70LXQvdC90YvQuSDRgtC40L8sINGH0YLQviDQt9C90LDRh9C40YIsINGH0YLQviDQutCw0LbQtNGL0Lkg0Y3Qu9C10LzQtdC90YIg0YTQsNC60YLQvtGA0LAg0LzQvtC20LXRgiDQsdGL0YLRjCDQt9Cw0LrQvtC00LjRgNC+0LLQsNC9INGBINC/0L7QvNC+0YnRjNGOINGG0LXQu9C+0YfQuNGB0LvQtdC90L3QvtCz0L4g0YLQuNC/0LAgIA0KYGBge3J9DQphcy5jaGFyYWN0ZXIoZikNCmBgYA0KYGBge3J9DQpmWzE3XQ0KYGBgDQrQktC40LTQuNC8LCDRh9GC0L4g0YMg0LrQsNC20LTQvtCz0L4g0YbQtdC70L7Qs9C+INC10YHRgtGMINGB0LLQvtC1INC90LXQutC+0LUg0L/QvtC00YHRgtCw0LLQu9C10L3QuNC1IC0g0LzQtdGC0LrQuCDQsdGD0LrQstGLINC70LDRgtC40L3RgdC60L7Qs9C+INCw0LvRhNCw0LLQuNGC0LAg0LIg0LTQsNC90L3QvtC8INGB0LvRg9GH0LDQtQ0KYGBge3J9DQojINCf0L7RgdC80L7RgtGA0LXRgtGMINC90LUg0LLRgdC1INGN0LvQtdC80LXQvdGC0Ysg0YTQsNC60YLQvtGA0LAgLNCwINGD0L3QuNC60LDQu9GM0L3Ri9C1INCz0YDQsNC00LDRhtC40Lgg0YTQsNC60YLQvtGA0LANCmxldmVscyhmKQ0KYGBgDQpgYGB7cn0NCiMg0YLQviDQttC1LCDRh9GC0L4g0LggbGVuZ3RoINC00LvRjyDQstC10LrRgtC+0YDQsA0KbmxldmVscyhmKQ0KYGBgDQojIyDQo9GA0L7QstC90Lgg0YTQsNC60YLQvtGA0LANCtCk0LDQutGC0L7RgCDQutCw0Log0L3QsNGB0LvQtdC00L3QuNC6INCy0LXQutGC0L7RgNCwINC40LzQtdC10YIg0YHQstC+0Lgg0L/RgNCw0LLQuNC70LAg0LjQvdC00LXQutGB0LjRgNC+0LLQsNC90LjRjy4gKtCd0J4hKiDQtNC70Y8g0L7QsdGL0YfQvdC+0LPQviDRhNCw0LrRgtC+0YDQsCDQvtC/0YDQtdC00LXQu9C10L3RiyDRgtC+0LvRjNC60L4g0L7QsdC+0LfQvdCw0YfQtdC90LjRjyAiKj09KiIsICIqIT0qIiAgDQogIA0K0J/QvtGN0YLQvtC80YMg0Log0Y3Qu9C10LzQtdC90YLQsNC8INGE0LDQutGC0L7RgNCwINC80L7QttC90L4g0L7QsdGA0LDRidCw0YLRjNGB0Y8sINC60LDQuiDQuiDRjdC70LXQvNC10L3RgtCw0Lwg0LLQtdC60YLQvtGA0LAsINC4INC90LUg0YLQvtC70YzQutC+INC+0LHRgNCw0YnQsNGC0YzRgdGPLCDQvdC+INC4INC/0YDQvtC40LfQstC+0LTQuNGC0Ywg0LfQsNC80LXQvdGDDQpgYGB7cn0NCiMg0LjRgdC60LvRjtGH0LDQtdC8INGD0YDQvtCy0LXQvdGMINCQDQojINCX0LDQvNC10L3Rj9C10Lwg0JAg0L3QsCBaDQpmW2YgPT0gIkEiXSA8LSAiWiINCmYNCmBgYA0K0J7QsdGA0LDRgtC4INCy0L3QuNC80LDQvdC40LUhINCSIGxldmVscyDRhNCw0LrRgtC+0YDQsCDQv9C10YDQtdC80LXQvdC90LDRjyDQkCDQvtGB0YLQsNC70LDRgdGMLCDRhdC+0YLRjyDQsiDQtNCw0L3QvdGL0YUg0LXQtSDRg9C20LUg0L3QtdGCLiDQlNC70Y8g0YLQvtCz0L4sINGH0YLQviDQvdC1INC40LfQsdCw0LLQuNGC0YzRgdGPINC+0YIg0L/Rg9GB0YLQvtC5INCz0YDQsNC00LDRhtC40Lgg0YTQsNC60YLQvtGA0LAsINGC0L4g0LzQvtC20L3QviDQstC+0YHQv9C+0LvRjNC30L7QstCw0YLRjNGB0Y8g0LfQsNC/0LjRgdGM0Y4gKmRyb3BsZXZlbHMoZikqDQpgYGB7cn0NCiMg0LfQsNC60LvRjtGH0LXQvdC40LUg0LIg0YHQutC+0LHQutC4INC30LTQtdGB0Ywg0L/QvtC30LLQvtC70Y/QtdGCINGB0YDQsNC30YMg0LLRi9Cy0LXRgdGC0Lgg0YDQtdC30YPQu9GM0YLQsNGCINGA0LDQsdC+0YLRiyANCihmIDwtIGRyb3BsZXZlbHMoZikpIA0KYGBgDQoNCiMjINCf0YDQtdC+0LHRgNCw0LfQvtCy0LDQvdC40LUg0YPRgNC+0LLQvdC10Lkg0YTQsNC60YLQvtGA0LAgDQpgYGB7cn0NCmxldmVscyhmKSA8LSB0b2xvd2VyKGxldmVscyhmKSkNCiNsZXZlbHMoZikgPC0gbGV0dGVyc1tMRVRURVJTICVpbiUgbGV2ZWxzKGYpXQ0KZg0KYGBgDQrQmNC30LzQtdC90LjQu9C40YHRjCDRg9GA0L7QstC90LgsINGF0L7RgtGPINGB0L7QvtGC0LLQtdGC0YHRgtCy0LjQtSDQvtGB0YLQsNC70L7RgdGMINGC0LDQutC40Lwg0LbQtSANCmBgYHtyfQ0KbGV2ZWxzKGYpWzFdIDwtICJiYmIiDQpmDQpgYGANCtCf0YDQuCDRjdGC0L7QvCDQvdC1INC90YPQttC90L4g0L/RgNC40LzQtdC90Y/RgtGMINGE0YPQvdC60YbQuNGOIGRyb3AgbGV2ZWxzDQoNCiMjINCj0L/QvtGA0Y/QtNC+0YfQtdC90L3Ri9C1INGE0LDQutGC0L7RgNGLDQoqINCY0L3QvtCz0LTQsCDQutCw0YLQtdCz0L7RgNC40Lgg0L7QsdC70LDQtNCw0Y7RgiDQvtGC0L3QvtGI0LXQvdC40LXQvCDQv9C+0YDRj9C00LrQsCAtINGC0LDQutCw0Y8g0LrQvtC90YHRgtGA0YPQutGG0LjRjyDQvdCw0LfRi9Cy0LDQtdGC0YHRjyAqKtGD0L/QvtGA0Y/QtNC+0YfQtdC90L3Ri9C5INGE0LDQutGC0L7RgCoqLCDRgi7QtS4g0LrQsNGC0LXQs9C+0YDQuNGPINC60LDRh9C10YHRgtCy0LXQvdC90L7QuSDQv9C10YDQtdC80LXQvdC90L7QuSDRg9C/0L7RgNGP0LTQvtGH0LXQvdCwICjQvdCw0L/RgNC40LzQtdGALCDRgdGC0LDQtNC40Y8g0LfQsNCx0L7Qu9C10LLQsNC90LjRjykNCiogKirQo9C/0L7RgNGP0LTQvtGH0LXQvdC90YvQuSDRhNCw0LrRgtC+0YAqKiAtINC60LDQuiDRgdC+0LfQtNCw0YLRjD8gIA0KMS4g0YTRg9C90LrRhtC40Y8gb3JkZXJlZCgpICANCjIuIG9yZGVyZWQgID0gVFJVRSDQtNC70Y8gZmFjdG9yIA0KYGBge3J9DQp0ZW1wIDwtIGMoImZyZWV6aW5nIGNvbGQiLCAiY29sZCIsICJjb21mb3J0YWJsZSIsICJob3QiLCAiYnVybmluZyBob3QiKQ0KIyDQsiDQvtGC0LLQtdGC0LDRhSDQv9C10YDQtdC80LXQvdC90L7QuSDQvdC10Y/QstC90YvQvCDQvtCx0YDQsNC30L7QvCDQv9GA0L7RgdC70LXQttC40LLQsNC10YLRgdGPINC+0YLQvdC+0YjQtdC90LjQtSDQv9C+0YDRj9C00LrQsA0KZnQgPC0gb3JkZXJlZChzYW1wbGUodGVtcCwgMTQsIHJlcGxhY2UgPSBUUlVFKSwgdGVtcCkNCmZ0DQpgYGANCtCf0L7Rj9Cy0LjQu9C40YHRjCDQtNC+0L/QvtC70L3QuNGC0LXQu9GM0L3Ri9C1INC30L3QsNGH0LrQuCDQv9C+0YDRj9C00LrQtSDQsiBsZXZlbHMuINCi0LXQv9C10YDRjCDQvNC+0LbQvdC+INCy0L7RgdC/0L7Qu9GM0LfQvtCy0LDRgtGM0YHRjyDQvtC/0LXRgNCw0YLQvtGA0LDQvNC4INC90LUg0YLQvtC70YzQutC+ID09INC40LvQuCAhPSAo0L3QtSDRgNCw0LLQvdC+KSwg0L3QviDQuCA+LzwvPj0g0Lgg0YIu0L8uICANCtCd0LDQv9GA0LjQvNC10YAsINGF0L7Rh9GDINC+0YLQvtCx0YDQsNGC0Ywg0YLQvtC70YzQutC+INGC0LUg0L7RgtCy0LXRgtGLLCDQsiDQutC+0YLQvtGA0YvRhSDRhdC+0YLRjyDQsdGLINCz0L7RgNGP0YfQviwg0YIu0LUuICJob3QiDQpgYGB7cn0NCmZ0W2Z0ID49ICJob3QiXQ0KYGBgDQrQn9C+0LvRg9GH0LjQu9C4INC+0YLQstC10YLRiywg0LrQvtGC0L7RgNGL0LUg0YDQsNGB0L/QvtC70L7QttC10L3RiyDRgdC/0YDQsNCy0LAg0L7RgiDQutCw0YLQtdCz0L7RgNC40LggaG90ICANCiAgDQojIyDQn9GA0LXQvtCx0YDQsNC30L7QstCw0L3QuNC1INC60L7Qu9C40YfQtdGB0YLQstC10L3QvdC+0Lkg0L/QtdGA0LXQvNC10L3QvdC+0Lkg0LIg0LrQsNGH0LXRgtGB0LLQtdC90L3Rg9GOICANCtCt0YLQviDQvNC+0LbQtdGCINC/0YDQuNCz0L7QtNC40YLRgdGPLCDQutC+0LPQtNCwINC10YHRgtGMINGA0Y/QtCDQuNC30LzQtdC90LXQvdC40LksINC60L7RgtC+0YDRi9C1INC80Ysg0YXQvtGC0LjQvCDRgNCw0LfQsdC40YLRjCDQvdCwINGA0Y/QtCDQutCw0YLQtdCz0L7RgNC40LggKNC90LDQv9GA0LjQvNC10YAsINC60L7Qu9C40YfQtdGB0YLQstC10L3QvdGL0LUg0L/QtdGA0LXQvNC10L3QvdGL0LUg0LLQvtC30YDQsNGB0YLQsCDQv9GA0LXQvtCx0YDQsNC30L7QstCw0YLRjCDQsiDQstC+0LfRgNCw0YHRgtC90YvQtSDQutCw0YLQtdCz0L7RgNC40LgpICANCg0KKiAqY3V0KiDRgNCw0LfQsdC40LLQsNC10YIgKm51bWVyaWMqINCy0LXQutGC0L7RgCDQvdCwINC40L3RgtC10YDQstCw0LvRiyAgDQoqICp0YWJsZSog0L/RgNC+0LjQt9Cy0L7QtNC40YIg0L/QvtC00YHRh9C10YIg0LrQvtC70LjRh9C10YHRgtCy0LAg0Y3Qu9C10LzQtdC90YLQvtCyINC00LvRjyDQutCw0LbQtNC+0LPQviDRg9GA0L7QstC90Y8g0YTQsNC60YLQvtGA0LAgICANCtCU0LLQtSDRjdGC0Lgg0YTRg9C90LrRhtC40Lgg0YPQtNC+0LHQvdC+INC40YHQv9C+0LvRjNC30L7QstCw0YLRjCDQsiDRgdCy0Y/Qt9C60LUsINGCLtC6LiB0YWJsZSDQv9C+0LTRgdGH0LjRgtCw0LXRgiDQutC+0LvQuNGH0LXRgdGC0LLQviDQstGB0LXRhSDQstGF0L7QttC00LXQvdC40Lkg0LIg0L7Qv9GA0LXQtNC10LvQtdC90L3Ri9C1INC60LDRgtC10LPQvtGA0LjQuCAgDQogIA0KKirQndCw0L/RgNC40LzQtdGAKiosINCy0YvQt9C+0LLQtdC8ICpjdXQqINC90LAgMTAg0L3QvtGA0LzQsNC70YzQvdC+INGA0LDRgdC/0YDQtdC00LXQu9C10L3QvdGL0YUg0YfQuNGB0LvQsNGFDQpgYGB7cn0NCmEgPC0gcm5vcm0oMTApDQphDQpgYGANCtCj0LrQsNC30YvQstCw0LXQvCDQstC10LrRgtC+0YAg0LjQvdGC0LXRgNCy0LDQu9C+0LIg0YDQsNC30LHQuNC10L3QuNC5INC+0YIgLTUg0LTQviA1ICjQsNGA0LPRg9C80LXQvdGCICpicmVha3MqKQ0KYGBge3J9DQpjdXQoYSwgLTU6NSkNCmBgYA0K0JXRgdC70Lgg0LIg0LrQsNGH0LXRgdGC0LLQtSDQsNGA0LPRg9C80LXQvdGC0LAgYnJlYWtzINGD0LrQt9Cw0YLRjCDQtdC00LjQvdGB0YLQstC10L3QvdC+0LUg0YfQuNGB0LvQviAo0YHQutCw0LvRj9GAKSwg0YLQviDQtNCw0L3QvdGL0LUg0LHRg9C00YPRgiDRgNCw0LfQsdC40YLRiyDQvdCwINC40L3RgtC10YDQstCw0LvRiyDRgNCw0LLQvdC+0Lkg0LTQu9C40L3RiyDRgtCw0LosINGH0YLQvtCx0Ysg0LrRgNCw0LnQvdC40LUg0LfQvdCw0YfQtdC90LjRjyDQvdC1INCy0YXQvtC00LjQu9C4INCyINGB0LzQtdC20L3Ri9C1INC40L3RgtC10YDQstCw0LvRiyAo0LAg0LjQvNC10L3QvdC+INCz0YDQsNC90LjRhtGLINGB0LzQtdGJ0LDRjtGC0YHRjyDQvdCwIDAsMSUg0LjQvdGC0LXRgNCy0LDQu9CwKQ0KYGBge3J9DQpjdXQoYSwgMykNCmBgYA0K0JXRgdC70Lgg0LbQtSDQvNGLINCx0YPQtNC10Lwg0LjRgdC/0L7Qu9GM0LfQvtCy0LDRgtGMIGN1dCDQsiDRgdCy0LfRj9C60LUg0YEgdGFibGUt0L7QvCwg0YLQviDQvNC+0LbQtdC8INGB0YDQsNC30YMg0L/QvtGB0LzQvtGC0YDQtdGC0Ywg0L3QsCDQutC+0LvQuNGH0LXRgdGC0LLQviDQstGF0L7QttC00LXQvdC40Lkg0LIg0LrQsNC20LTRi9C5INC60L7QvdC60YDQtdGC0L3Ri9C5INC40L3RgtC10YDQstCw0LsuINCd0LDQv9GA0LjQvNC10YA6DQpgYGB7cn0NCnRhYmxlKGN1dChybm9ybSgxMDAwKSwgLTU6NSkpDQpgYGANCtCi0LDQuiDQvNGLINC80L7QttC10Lwg0L/QvtC70YPRh9C40YLRjCDRjdC70LXQvNC10L3RgtCw0YDQvdGD0Y4g0L7RgdC80YvRgdC70LXQvdC90YPRjiDRgdGC0LDRgtC40YHRgtC40LrRgyAtINGE0LDQutGC0LjRh9C10YHQutC4INC80Ysg0L/QvtC70YPRh9Cw0LXQvCDQvdC10YfRgtC+INC/0L7RhdC+0LbQtdC1INC90LAg0LPQuNGB0YLQvtCz0YDQsNC80LzRgywg0LrQvtGC0L7RgNCw0Y8g0LIg0LTQsNC90L3QvtC8INGB0LvRg9GH0LDQtSDQuNC80LXQtdGCINCy0LjQtCDQvdC+0YDQvNCw0LvRjNC90L7Qs9C+INGA0LDRgdC/0YDQtdC00LXQu9C90LjRjyAo0L3QviDQvNGLINC4INCy0YvQt9GL0LLQsNC70Lgg0YTRg9C90LrRhtC40Y4gcm5vcm0sINGC0LDQuiDRh9GC0L4g0Y3RgtC+INC+0LbQuNC00LDQtdC80L4pICANCiAgDQojIyDQktCw0LbQvdC+0LUg0L7RgtGB0YLRg9C/0LvQtdC90LjQtSAtINGE0YPQvdC60YbQuNGPICpvcHRpb25zKiAgDQrQoyDRgdC10YHRgdC40LggUiDQtdGB0YLRjCDQvdCw0LHQvtGAINCw0LrRgtC40LLQvdGL0YUg0L3QsNGB0YLRgNC+0LXQuiwg0L7RgtCy0LXRh9Cw0Y7RidC40YUg0LfQsCDQv9C+0LTRgdGH0LXRgiDQuCDQstGL0LLQvtC0INGA0LXQt9GD0LvRjNGC0LDRgtC+0LIg0LLRi9GH0LjRgdC70LXQvdC40LkgIA0KKj9vcHRpbm9ucw0KYGBge3J9DQo/b3B0aW9ucw0KYGBgDQoqKiBkaWdpdHMgLSDQutC+0LvQuNGH0LXRgdGC0LLQviDQt9C90LDQutC+0LIg0L/RgNC4INC/0LXRh9Cw0YLQuCDRh9C40YHQtdC7ICANCioqIGVycm9yIC0g0L/QvtCy0LTQtdC10L3QuNC1INC/0YDQuCDQvtGI0LjQsdC60LUgIA0KKiogd2lkdGggLSDQtNC70LjQvdCwINGB0YLRgNC+0LrQuCDQv9GA0Lgg0L/QtdGH0LDRgtC4INCy0LXQutGC0L7RgNC+0LIg0Lgg0LzQsNGC0YDQuNGGICANCtCf0L7Qu9C90YvQuSDRgdC/0LjRgdC+0Log0LTQvtGB0YLQsNGC0L7Rh9C90L4g0LHQvtC70YzRiNC+0LksINC90L4g0LXRgdGC0Ywg0YDRj9C0INC00L7RgdGC0LDRgtC+0YfQvdC+INCy0LDQttC90YvRhQ0KICANCioq0JLQsNC20L3QviDQtNC70Y8g0YTQsNC60YLQvtGA0L7QsiDQuCDRgdGC0YDQvtC6ISoqICANCtCf0L4g0YPQvNC+0LvRh9Cw0L3QuNGOLCDQstGB0LUg0YHRgtGA0L7QutC+0LLRi9C1INC/0LXRgNC10LzQtdC90L3Ri9C1INGB0YLQsNC90L7QstGP0YLRgdGPINGE0LDQutGC0L7RgNCw0LzQuC4g0KIu0LUuINC10YHQu9C4IFIg0LLRgdGC0YDQtdGH0LDQtdGC0YHRjyDRgSDQv9C10YDQtdC80LXQvdC90L7QuSDRgdGC0YDQvtC60L7QstC+0LPQviDRgtC40L/QsCwg0L3QsNC/0YDQuNC80LXRgCwg0L/RgNC4INGB0YfQuNGC0YvQstCw0L3QuNC4INC00LDRgtCwINGE0YDQtdC50LzQsCwg0YLQviDQvtC90LAg0LDQstGC0L7QvNCw0YLQuNGH0LXRgdC60Lgg0L/RgNC10LLRgNCw0YnQsNC10YLRgdGPINCyINGE0LDQutGC0L7RgC4gINCt0YLQviDQvdC1INCy0YHQtdCz0LTQsCDRgtCw0Log0Lgg0LzQvtC20LXRgiDQv9GA0LjQstC+0LTQuNGC0Ywg0Log0L7RiNC40LHQvtGH0L3Ri9C8INCy0YvRh9C40YHQu9C10L3QuNGP0LwuICANCg0K0J7RgtC80LXQvdC40YLRjCDRgtCw0LrQvtC1INC/0L7QstC10LTQtdC90LjQtSDQvNC+0LbQvdC+INCy0YvQt9C+0LLQvtC8ICAgDQpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgIA0KICANCiMjINCk0YPQvdC60YbQuNGPIHRhcHBseSANCtCc0Ysg0YPQttC1INC90LUg0YDQsNC3INC/0L7QtNC90LjQvNCw0LvQuCDRhNGD0LrQvdGG0LjQuCDRgdC10LzQtdC50YHRgtCy0LAgYXBwbHksINC10YHRgtGMINGC0LDQutCw0Y8g0Lgg0LTQu9GPINGA0LDQsdC+0YLRiyDRgSDRhNCw0LrRgtC+0YDQsNC80LguICANCtCU0LXQu9C+INCyINGC0L7QvCwg0YfRgtC+INGE0LDQutGC0L7RgNGLINGB0LDQvNC4INC/0L4g0YHQtdCx0LUg0L3QtdGB0YPRgiDQvNCw0LvQviDRgdC80YvRgdC70LAsINC+0L3QuCDQvdC10YHRg9GCINGB0LzRi9GB0Lsg0LrQsNC6INGN0LvQtdC80LXQvdGC0YMg0LTQsNGC0LAg0YTRgNC10LnQvNCwLiDQntC00L3QsCDQuNC3INC90LDQuNCx0L7Qu9C10LUg0YDQsNGB0L/RgNC+0YHRgtGA0LDQvdC10L3QvdGL0YUg0LfQsNC00LDRhyDQsiDQsNC90LDQu9C40LfQtSDQtNCw0L3QvdGL0YUgLSDQv9C+0LTRgdGH0LXRgiDQvdC10LrQvtC5INGB0YLQsNGC0LjRgdGC0LjQutC4INC/0L4g0LPRgNGD0L/Qv9Cw0LwsINC60L7RgtC+0YDRi9C1INC+0L/RgNC10LTQtdC70Y/RjtGCINGE0LDQutGC0L7RgNGLLiDQmtCw0Log0YDQsNC3INC00LvRjyDRjdGC0LjRhSDQt9Cw0LTQsNGHINGD0LTQvtCx0L3QviDQv9C+0LvRjNC30L7QstCw0YLRjNGB0Y8g0YTRg9C90LrRhtC40LXQuSAqKnRhcHBseSoqLiAgIA0K0KDQsNC30LHQtdGA0LXQvCDQvdCwINC/0YDQuNC80LXRgNC1INC80LDRgdGB0LjQstCwIHdhcnBicmVha3MgKNGB0YLQsNGA0L7QtNGA0LXQstC90LjQuSDQvNCw0YHRgdC40LIg0YEg0LTQsNC90L3Ri9C80Lgg0L4g0L/QvtC70L7QvNC60LDRhSDQv9GA0Y/QtNC40LvRjNC90YvRhSDRg9GB0YLQsNC90L7QstC+0Log0LIg0LfQsNCy0LjRgdC40LzQvtGB0YLQuCDQvtGCINGC0LjQv9CwINCy0L7Qu9C+0YHQsCwg0YEg0LrQvtGC0L7RgNGL0Lwg0YDQsNCx0L7RgtCw0LssINC4INGB0LjQu9GLINC90LDRgtGP0LbQtdC90LjRjykNCmBgYHtyfQ0Kc3RyKHdhcnBicmVha3MpDQpgYGANCndvb2wg0LggdGVuc2lvbiAtINC00LLQsCDRhNCw0LrRgtC+0YDQsCwg0YMg0LrQsNC20LTQvtCz0L4g0LjQtyDQutC+0YLQvtGA0YvRhSDRgdCy0L7QuCDQs9GA0LDQtNCw0YbQuNC4LiDQlNC+0L/Rg9GB0YLQuNC8LCDRhdC+0YfRgyDQv9C+0YHQvNC+0YLRgNC10YLRjCwg0LrQsNC60L7QuSDRgtC40L8g0YjQtdGA0YHRgtC4INC/0YDQuNCy0L7QtNC40YIg0Log0LzQsNC60YHQuNC80LDQu9GM0L3QvtC80YMg0LrQvtC70LjRh9C10YHRgtCy0YMg0L/QvtC70L7QvNC+0LogLSDQtNC70Y8g0Y3RgtC+0LPQviDQstC+0YHQv9C+0LvRjNC30YPQtdC80YHRjyB0YXBwbHk6ICANCiog0L/QtdGA0LLRi9C5INCw0YDQs9GD0LzQtdC90YIgLSDQvNCw0YHRgdC40LIsINC/0L4g0LrQvtGC0L7RgNC+0LzRgyDQsdGD0LTQtdGCINGB0YfQuNGC0LDRgtGM0YHRjyDRgdGC0LDRgtC40YHRgtC40LrQsCAgDQoqINCy0YLQvtGA0L7QuSDQsNGA0LPRg9C80LXQvdGCIC0g0YTQsNC60YLQvtGALCDQv9C+INCz0YDQsNC00LDRhtC40Y/QvCDQutC+0YLQvtGA0L7Qs9C+INC40LTQtdGCINGA0LDQt9C00LXQu9C10L3QuNC1ICANCiog0YLRgNC10YLQuNC5IC0g0YTRg9C90LrRhtC40Y8sINC60L7RgtC+0YDRg9GOINC/0YDQuNC80LXQvdGP0LXQvA0KYGBge3J9DQp0YXBwbHkod2FycGJyZWFrcyRicmVha3MsIHdhcnBicmVha3Mkd29vbCwgbWF4KQ0KYGBgDQojIyMg0JPQu9C+0YHRgdCw0YDQuNC5ICANCj9mYWNvdHIgIA0KP2xldmVscywgP25sZXZlbHMsID9kcm9wbGV2ZWxzICANCj9vcmRlcmVkICANCj9jdXQsID90YWJsZSAgDQo/b3B0aW9ucyAgDQo/dGFwcGx5ICANCiAgDQogICAgDQojIyMg0JfQsNC00LDRh9CwIA0K0JjRgdC/0L7Qu9GM0LfRg9C50YLQtSDQv9C+0LrQsNC30LDQvdC90YPRjiDQvNC90L7QuSDRgdCy0Y/Qt9C60YMg0LjQtyDQtNCy0YPRhSDRhNGD0L3QutGG0LjQuSwg0YfRgtC+0LHRiyDQv9GA0LXQstGA0LDRgtC40YLRjCDQutC+0LvQuNGH0LXRgdGC0LLQtdC90L3Rg9GOINC/0LXRgNC10LzQtdC90L3Rg9GOIG1hZyAo0YHQuNC70LAg0LfQtdC80LvQtdGC0YDRj9GB0LXQvdC40Y8g0LIg0LHQsNC70LvQsNGFINC/0L4g0YjQutCw0LvQtSDQoNC40YXRgtC10YDQsCkg0LTQsNGC0LAg0YTRgNC10LnQvNCwIHF1YWtlcyDQsiDQutCw0YfQtdGB0YLQstC10L3QvdGD0Y4uINCY0L3RgtC10YDQstCw0LvRiyDQtNC+0LvQttC90Ysg0LHRi9GC0Ywg0LTQu9C40L3QvtC5INCyINC/0L7Qu9Cx0LDQu9C70LAsINC90LDRh9C40L3QsNGPINGBINC80LjQvdC40LzQsNC70YzQvdC+0LPQviwg0L/RgNC4INGN0YLQvtC8INC70LXQstGL0Lkg0LrQvtC90LXRhiDQuNC90YLQtdGA0LLQsNC70LAg0LLQutC70Y7Rh9Cw0LXRgtGB0Y8uINCi0LXQv9C10YDRjCDQvtGC0YHQvtGA0YLQuNGA0YPQudGC0LUg0L7QsdGJ0LXQtSDQutC+0LvQuNGH0LXRgdGC0LLQviDRgdC70YPRh9Cw0LXQsiwg0L/QvtC/0LDQstGI0LjRhSDQsiDQutCw0LbQtNGD0Y4g0LrQsNGC0LXQs9C+0YDQuNGOLCDQsiDQv9C+0YDRj9C00LrQtSDRg9Cx0YvQstCw0L3QuNGPLiAgDQoxLiDQn9C+0YHQvNC+0YLRgNGOINGB0YLRgNGD0LrRgtGD0YDRgyDQtNCw0YLQsC3RhNGA0LXQudC80LANCmBgYHtyfQ0Kc3RyKHF1YWtlcykNCmBgYA0KMi4g0JLQvdC10YHRgyDQtNCw0YLQsCDRhNGA0LXQudC8INCyINC/0LXRgNC10LzQtdC90L3Rg9GOLCDRh9GC0L7QsdGLINGA0LDQsdC+0YLQsNGC0Ywg0YEg0L3QuNC8DQpgYGB7cn0NCnEgPC0gcXVha2VzDQpzdW1tYXJ5KHEkbWFnKQ0KYGBgDQozLiDQodCz0LXQvdC10YDQuNGA0YPRjiDQv9C+0YHQu9C10LTQvtCy0LDRgtC10LvRjNC90L7RgdGC0Ywg0L7RgiAqbWluKHEkbWFnKSog0LTQviAqbWF4KHEkbWFnKSog0YEg0YjQsNCz0L7QvCAwLjUNCmBgYHtyfQ0KP2NlaWxpbmcNCiNjZWlsaW5nLCDRh9GC0L7QsdGLINCy0LrQu9GO0YfQuNGC0Ywg0LLQtdGA0YXQvdGO0Y4g0LPRgNCw0L3QuNGG0YMNCmEgPC0gc2VxKG1pbihxJG1hZyksIGNlaWxpbmcobWF4KHEkbWFnKSksIGJ5ID0gMC41KQ0KYQ0KYGBgDQo0LiDQoNCw0LfQtNC10LvRjiDQv9C+INGB0LPQtdC90LXRgNC40YDQvtCy0LDQvdC90L7QuSDQv9C+0YHQu9C10LTQvtCy0LDRgtC10LvRjNC90L7RgdGC0Lgg0Lgg0YHRgNCw0LfRgyDQvtGC0YHQvtGA0YLQuNGA0YPRjiDQv9C+INC60L7Qu9C40YfQtdGB0YLQstGDINGB0LvRg9GH0LDQtdCyLCDQuNC90LDRh9C1INCy0YvQu9C10LfQtdGCINC+0LPRgNC+0LzQvdGL0Lkg0LLQtdC60YLQvtGADQpgYGB7cn0NCnNvcnQodGFibGUoY3V0KHEkbWFnLCBiciA9IGEsIHJpZ2h0ID0gRkFMU0UpKSkNCmBgYA0KDQo/Y3V0DQo/dGFibGUNCg0K0J/QvtC00YHQutCw0LfQutC4Og0KDQrQv9GA0LjQtNGR0YLRgdGPINGH0YPRgtGMLdGH0YPRgtGMINC/0L7QstC+0LfQuNGC0YzRgdGPINGBINCw0YDQs9GD0LzQtdC90YLQsNC80Lg7DQrQuNC90YLQtdGA0LLQsNC70Ysg0LTQvtC70LbQvdGLINCx0YvRgtGMINCyINGC0L7Rh9C90L7RgdGC0Lgg0YLQsNC60LjQvNC4LCDQutCw0Log0YPQutCw0LfQsNC90Ysg0LIg0L7RgtCy0LXRgtCw0YUuDQpgYGB7cn0NCj9jdXQNCmBgYA0KDQoNCiAgDQojIyDQktC10YDQvdC10LzRgdGPINC6INC80LDRgdGB0LjQstGDIGF2aWFuSGFiaXRhdCDQuNC70Lgg0JTQsNGC0LAg0KTRgNC10LnQvCAtINGH0LDRgdGC0YwgMg0K0KfQtdC8INCx0L7Qu9GM0YjQtSDQv9GA0LjQtdC80L7QsiDQvNGLINC30L3QsNC10LwsINGC0LXQvCDQsdC+0LvRjNGI0LUg0LLQvtC30LzQvtC20L3QvtGB0YLQtdC5INGDINC90LDRgSDQvtGC0LrRgNGL0LLQsNC10YLRgdGPINCyINC/0YDQuNC60LvQsNC00L3QvtC8INCw0L3QsNC70LjQt9C1INC00LDQvdC90YvRhS4g0JLQtdGA0L3QtdC80YHRjyDQuiDQvNCw0YHRgdC40LLRgyBhdmlhbkhhYml0YXQNCmBgYHtyfQ0KYXZpYW4gPC0gcmVhZC5jc3YoIkM6L1VzZXJzL1RvbnkvRGVza3RvcC9SL01pbmUvYXZpYW5IYWJpdGF0LmNzdiIpDQpzdHIoYXZpYW4pDQpgYGANCtCj0LTQvtGB0YLQvtCy0LXRgNC40LzRgdGPLCDRh9GC0L4g0LzRiyDQsiDRgNCw0LHQvtGH0LXQuSDQtNC40YDQtdC60YLQvtGA0LjQuCDQvdCw0YXQvtC00LjRgtGB0Y8g0YTQsNC50Lsg0L/RgNC+0LXQutGC0LAg0Lgg0LjRgdGF0L7QtNC90YvQuSBjc3Yg0YTQsNC50LsuDQpgYGB7cn0NCmdldHdkKCkNCmBgYCAgIA0K0J7Quiwg0Y8g0LIg0L3Rg9C20L3QvtC5INC00LjRgNC10LrRgtC+0YDQuNC4LiDQmNC3LdC/0L7QtCDQm9C40L3Rg9C60YHQsCwg0LrQvtC90LXRh9C90L4sINGA0LDQsdC+0YLQsNGC0Ywg0YEg0LTQuNC10YDQutGC0L7RgNC40Y/QvNC4INCx0YvQu9C+INCx0Ysg0YPQtNC+0LHQvdC10LUuINCd0L4g0YLQsNC6INC40LvQuCDQuNC90LDRh9C1INC6INGE0LDQudC70LDQvCDQuNC3INGA0LDQsdC+0YfQtdC5INC00LjRgNC10LrRgtC+0YDQuNC4INC80L7QttC90L4g0L7QsdGA0LDRidCw0YLRjNGB0Y8sINC90LUg0YPQutCw0LfRi9Cy0LDRjyDQv9C+0LvQvdGL0Lkg0L/Rg9GC0YwsINCwINC/0YDQvtGB0YLQviDQv9C+INC40LzQtdC90LgsINGCLtC1LiANCmBgYHtyfQ0KYXZpYW4gPC0gcmVhZC5jc3YoImF2aWFuSGFiaXRhdC5jc3YiKQ0KYGBgDQrQk9C+0YLQvtCy0L4uICANCtCV0YHQu9C4INCx0Ysg0YMg0LzQtdC90Y8g0LHRi9C7INGD0LbQtSDQv9GA0LXQtNCy0LDRgNC40YLQtdC70YzQvdC+INC30LDQs9C+0YLQvtCy0LvQtdC90L3Ri9C5INGE0LDQudC7INC/0YDQvtC10LrRgtCwLlIsINGC0L4g0YTRg9C90LrRhtC40LXQuSBzb3VyY2Ug0LzQvtC20L3QviDQsdGL0LvQviDQtdCz0L4g0YHRh9C40YLQsNGC0YwgKNGD0LrQsNC30LDQstCwINC10LPQviDQvdCw0LfQstCw0L3QuNC1KSDQuCDQstGL0L/QvtC70L3QuNGC0Ywg0LLRgdC1INC60L7QvNCw0L3QtNGLINC/0YDQvtC/0LjRgdCw0L3QvdGL0LUg0LIg0YHQutGA0LjQv9GC0LUNCmBgYHtyfQ0KP3NvdXJjZQ0KYGBgDQoNCtCj0LTQvtGB0YLQvtCy0LXRgNGO0YHRjCwg0YfRgtC+INC80LDRgdGB0LjQsiDQt9Cw0L/QuNGB0LDQvSDQsiDQtNCw0YLQsCDRhNGA0LXQudC80LAgYXZpYW4g0YHRg9GJ0LXRgdGC0LLRg9C10YINCmBgYHtyfQ0KaGVhZChhdmlhbikNCmBgYA0K0JjQvdC+0LPQtNCwINGE0LDQudC70Ysg0YEg0LTQsNC90L3Ri9C80Lgg0L3QsNGB0YLQvtC70YzQutC+INCx0L7Qu9GM0YjQuNC1LCDRh9GC0L4g0L3QuCDQvtC00LjQvSDRgtC10LrRgdGC0L7QstGL0Lkg0YDQtdC00LDQutGC0L7RgCDQuNGFINC90LUg0L7RgtC60YDQvtC10YIuINCn0YLQvtCx0Ysg0L3QsNC50YLQuCDRgtCw0LrQvtC5INGE0LDQudC7INCyINGA0LDQsdC+0YfQtdC5INC00LjRgNC10LrRgtC+0YDQuNC4ICjQtNCwINC4INC70Y7QsdC+0Lkg0LTRgNGD0LPQvtC5LCDQsiDQv9GA0LjQvdGG0LjQv9C1LCDRgtC+0LbQtSksINGC0L4g0LzQvtC20L3QviDQstC+0YHQv9C+0LvRjNC30L7QstCw0YLRjNGB0Y8g0YTRg9C90LrRhtC40LXQuSAqbGlzdC5maWxlcyoNCmBgYHtyfQ0KP2xpc3QuZmlsZXMNCmBgYA0K0J/RgNC4INGN0YLQvtC8LCDQtdGB0LvQuCDRhNCw0LnQu9C+0LIg0LIg0LTQuNGA0LXQutGC0L7RgNC40Lgg0LzQvdC+0LPQviwg0YLQviDQvNC+0LbQvdC+INCy0L7RgdC/0L7Qu9GM0LfQvtCy0LDRgtGM0YHRjyDQutCw0LrQuNC8LdC90LjQsdGD0LTRjCAq0YDQtdCz0YPQu9GP0YDQvdGL0Lwg0LLRi9GA0LDQttC10L3QuNC10LwqLCDRh9GC0L7QsdGLINC+0LHRgNCw0YLQuNGC0YzRgdGPINC6INC60L7QvdC60YDQtdGC0L3Ri9C8INGE0LDQudC70LDQvC4NCmBgYHtyfQ0KbGlzdC5maWxlcygpDQpgYGANCtCV0YHQu9C4INGF0L7Rh9GDINC90LDQudGC0Lgg0YLQvtC70YzQutC+IGNzdiDRhNCw0LnQu9GLLCDRgtC+INCy0YHQv9C+0LvRjNC30YPRjtGB0Ywg0YDQtdCz0YPQu9GP0YDQvdGL0Lwg0LLRi9GA0LDQttC10L3QuNC10LwNCmBgYHtyfQ0KbGlzdC5maWxlcyhwYXR0ZXJuID0gIi5jc3YkIikNCiMg0LPQtNC1ICIuIiAtINGN0YLQviB3aWxkY2FyZCAtINC+0LHQvtC30L3QsNGH0LDQtdGCINC70Y7QsdC+0Lkg0YHQuNC80LLQvtC7DQojINCwICQgLSDQutC+0L3QtdGGINGB0YLRgNC+0LrQuA0KYGBgDQrQnNC+0LbQvdC+INGB0LTQtdC70LDRgtGMINC4INCx0L7Qu9C10LUg0YXQuNGC0YDQviwg0YXQvtGC0Y8g0LIg0LTQsNC90L3QvtC8INGB0LvRg9GH0LDQtSDQsdC+0LvRjNGI0L7Qs9C+INGB0LzRi9GB0LvQsCDQsiDRjdGC0L7QvCDQvdC10YIsINC90LDQv9GA0LjQvNC10YA6DQpgYGB7cn0NCmxpc3QuZmlsZXMocGF0dGVybiA9ICIuKlxcLmNzdiQiKQ0KIyDQs9C00LUgIi4iIC0g0LvRjtCx0L7QuSDRgdC40LzQstC+0LssINGCLtC1LiDQvdC10LLQsNC20L3QviDRgSDQutCw0LrQvtCz0L4g0YHQuNC80LLQvtC70LAg0L3QsNGH0LjQvdCw0LXRgtGB0Y8g0YHQu9C+0LLQsA0KIyAiKiIgLSDQvtC9INC20LUsINGCLtC1LiDQu9GO0LHQvtC5INGB0LjQvNCy0L7Quywg0L3QviDQv9C+0LLRgtC+0YDQtdC90L3Ri9C5INC70Y7QsdC+0LUg0LrQvtC70LjRh9C10YHRgtCy0L4g0YDQsNC3DQojICIuKiIgLSDQt9C90LDRh9C40YIg0LzQvdC1INC90LUg0LLQsNC20L3QviDQvdCw0YfQsNC70L4g0LjQvNC10L3QuA0KIyAiXFwuIiAtINGN0YLQviDQvtCx0YvRh9C90LDRjyDRgtC+0YfQutCwLCDQvdC+INGH0YLQvtCx0Ysg0L7QvdCwINGB0YfQuNGC0YvQstCw0LvQsNGB0Ywg0LrQsNC6IHdpbGRjYXJkINC/0YDQuNGF0L7QtNC40YLRgdGPINGN0LrRgNCw0L3QuNGA0L7QstCw0YLRjCDQtNCy0YPQvNGPINCx0Y3QutGB0LvQtdGI0LDQvNC4DQojIlxcLmNzdiQiIC0g0LfQsNC60LDQvdGH0LjQstCw0LXRgtGB0Y8g0L3QsCAuY3N2DQpgYGANCtCd0L4g0LTQvtC/0YPRgdGC0LjQvCwg0Y3RgtC+0YIg0L3QsNC50LTQtdC90L3Ri9C5INC90LDQvCDQvdGD0LbQvdGL0Lkg0YTQsNC50Lsg0L/Qvi3Qv9GA0LXQttC90LXQvNGDINC+0YfQtdC90Ywg0LHQvtC70YzRiNC+0LkuINCe0YLQutGA0YvRgtGMINC10LPQviDQvdC40YfQtdC8INC90LUg0L/QvtC70YPRh9Cw0LXRgtGB0Y8uINCn0YLQviDQtNC10LvQsNGC0Yw/ICANCtCSINGC0LDQutC+0Lkg0YHQuNGC0YPQsNGG0LjQuCDQvNC+0LbQvdC+INCy0L7RgdC/0L7Qu9GM0LfQvtCy0LDRgtGM0YHRjyDQvdC40LfQutC+0YPRgNC+0LLQvdC10LLQvtC5INGE0YPQvdC60YbQuNC10LkgKnJlYWRMaW5lcyosINGD0LrQsNC30LDQsiDQutC+0LvQuNGH0LXRgdGC0LLQviDRgdGC0YDQvtC6INC6INC/0YDQvtGH0YLQtdC90LjRjiANCmBgYHtyfQ0KP3JlYWRMaW5lcw0KcmVhZExpbmVzKCJhdmlhbkhhYml0YXQuY3N2IiwgNSkNCmBgYA0K0JLQuNC20YMsINGH0YLQviDRhNCw0LnQuyDQutC+0YDRgNC10LrRgtC90YvQuSwg0LAg0LfQvdCw0YfQuNGCINC00LDQu9GM0YjQtSDRgdCy0L7QsdC+0LTQvdC+INGB0LzQvtCz0YMg0LLQvtGB0L/QvtC70YzQt9C+0LLQsNGC0YzRgdGPINGE0YPQvdC60YbQuNC10LkgKnJlYWQuY3N2Ki4gIA0KKirQp9GC0L4g0LXRgdC70Lgg0YTQsNC50Lsg0LHRi9C7INCx0Ysg0L3QtdC60L7RgNGA0LXQutGC0L3Ri9C8PyoqICANCtCS0L7RgdC/0L7Qu9GM0LfQvtCy0LDQu9C40YHRjCDRhNGD0L3QutGG0LjQtdC5IHJlYWQudGFibGUg0Lgg0LLRgNGD0YfQvdGD0Y4g0L/RgNC+0L/QuNGB0LDQu9C4INCx0Ysg0L3Rg9C20L3Ri9C1INCw0YDQs9GD0LzQtdC90YLRizoNCmBgYHtyfQ0KYXZpYW4gPC0gcmVhZC50YWJsZSgiYXZpYW5IYWJpdGF0LmNzdiIsIGhlYWRlciA9IFQsIHNlcCA9ICIsIiwgZGVjID0gIi4iKQ0KYGBgDQrQoNC10LfRg9C70YzRgtCw0YIg0YLQvtGH0L3QviDRgtCw0LrQvtC5INC20LUNCmBgYHtyfQ0KaGVhZChhdmlhbikNCmBgYA0K0KLQtdC/0LXRgNGMLCDQutC+0LPQtNCwINC80Ysg0LfQvdCw0LXQvCDQviDRhNCw0LrRgtC+0YDQsNGFINC4INGB0YLRgNC+0LrQsNGFLCDQv9C+0LvQtdC30L3Ri9C8INCx0YPQtNC10Lwg0L/RgNC+0LLQtdGA0Y/RgtGMINCyINGB0L/QtdGG0LjQsNC70YzQvdC+0Lkg0LLQutC70LDQtNC60LUgUnN0dWRpbyDQstCy0LXRgNGF0YMg0YHQv9GA0LDQstCwLCDRh9GC0L4g0LLRgdC1INC00LDQvdC90YvQtSDRgdGH0LjRgtCw0LvQuNGB0Ywg0L/RgNCw0LLQuNC70YzQvdC+LiAgDQoNCiFb0JXRgdC70Lgg0L3QsNC20LDRgtGMINC90LAg0YHRgtGA0LXQu9C+0YfQutGDINGA0Y/QtNC+0Lwg0YEg0LTQsNGC0LAg0YTRgNC10LnQvNC+0LwsINGC0L4g0YPQstC40LTQuNC8INCy0YvQutC70LDQtNC60YMg0L/QviDQv9C10YDQtdC80LXQvdC90YvQvF0oQzpcVXNlcnNcVG9ueVxEZXNrdG9wXFJcTWluZVxkYXRhLnBuZykgIA0KICANCtCU0L7Qv9GD0YHRgtC40LwsINGPINCy0LjQttGDLCDRh9GC0L4g0L/QtdGA0LXQvNC10L3QvdCw0Y8gT2JzZXJ2ZXIg0YHRh9C40YLQsNC70LDRgdGMLCDQutCw0Log0YHRgtGA0L7QutCwLCDRgtC+0LPQtNCwINC60LDQuiDQu9C+0LPQuNGH0L3QtdC1INCx0YvQu9C+INC10LUg0YHRh9C40YLQsNGC0Ywg0YTQsNC60YLQvtGA0L7QvC4g0KLQvtCz0LTQsCDQvNC+0LPRgyDQuNC30LzQtdC90LjRgtGMINC10LUg0YLQuNC/DQpgYGB7cn0NCmF2aWFuJE9ic2VydmVyIDwtIGFzLmZhY3RvcihhdmlhbiRPYnMpDQpgYGANCiFb0KLQtdC/0LXRgNGMINCy0LjQttGDLCDRh9GC0L4g0LLRgdC1INC/0YDQsNCy0LjQu9GM0L3Qvl0oQzpcVXNlcnNcVG9ueVxEZXNrdG9wXFJcTWluZVxkYXRhMi5wbmcpICANCiAgDQogIA0K0JLQvtC+0LHRidC1INGB0LDQvNCw0Y8g0YfQsNGB0YLQsNGPINC/0YDQvtCx0LvQtdC80LAsINC60L7Qs9C00LAg0L3QsNC+0LHQvtGA0L7RgiDQv9C+INGD0LzQvtC70YfQsNC90LjRjiDQv9GA0Lgg0YHRh9C40YLRi9Cy0LDQvdC40Lgg0LTQsNGC0LAg0YTRgNC10LnQvNCwINC/0LXRgNC10LzQtdC90L3Ri9C1INGB0YLRgNC+0LrQvtCy0L7Qs9C+INGC0LjQv9CwIGNoYXJhY3RlciDRgdGH0LjRgtCw0Y7RgtGB0Y8g0YTQsNC60YLQvtGA0LDQvNC4IChmYWN0b3IpLiDQrdGC0L4g0L/RgNC+0LjRgdGF0L7QtNC40YIsINGCLtC6LiDQv9C+INGD0LzQvtC70YfQvdCw0LjRjiDQsiDRgdC10YHRgdC40LggUiDRg9GB0YLQsNC90L7QstC70LXQvdCwINGC0LDQutCw0Y8g0L7Qv9GG0LjRjzogIA0KI29wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpICANCtCn0YLQvtCx0Ysg0Y3RgtC+0LPQviDQvdC1INC/0YDQvtC40YHRhdC+0LTQuNC70L4g0L/QtdGA0LXQtCDRgdGH0LjRgtGL0LLQsNC90LjQtdC8INC00LDRgtCwINGE0YDQtdC50LzQsCDQu9GD0YfRiNC1INC80LXQvdGP0YLRjCDQtdC1INC90LAgRkFMU0UsINCwINC/0L7RgtC+0Lwg0YPQttC1INCy0YDRg9GH0L3Rg9GOINGB0YLRgNC+0LrQuCDQv9GA0LXQvtCx0YDQsNC30L7QstGL0LLQsNGC0Ywg0LIg0YTQsNC60YLQvtGA0YsgKNC60L7RgtC+0YDRi9GFINC+0LHRi9GH0L3QviDQt9Cw0LLQtdC00L7QvNC+INC80LXQvdGM0YjQtSkgIA0KICANCiMjIyDQn9GA0L7QstC10YDQutCwINC00LjQsNC/0LDQt9C+0L3QsCDQt9C90LDRh9C10L3QuNC5DQrQktC+0LfQstGA0LDRidCw0LXQvNGB0Y8g0Log0LLQvtC/0YDQvtGB0YMg0L/RgNC+0LLQtdGA0LrQuCDQtNC40LDQv9Cw0LfQvtC90LAg0LfQvdCw0YfQtdC90LjQuS4g0KDQsNC90YzRiNC1INC80Ysg0Y3RgtC+INC00LXQu9Cw0LvQuCDQv9C+INGB0YPRgtC4INCy0YDRg9GH0L3Rg9GOIA0KYGBge3J9DQpjaGVja19wZXJjZW50X3JhbmdlIDwtIGZ1bmN0aW9uKHgpIHsNCiAgYW55KHggPCAwIHwgeCA+IDEwMCkNCn0NCmBgYA0KYGBge3J9DQpjaGVja19wZXJjZW50X3JhbmdlKGF2aWFuJFBXKQ0KYGBgDQrQoyDQvdCw0YEg0YPQttC1INC10YHRgtGMINGE0YPQvdC60YbQuNGPLCDQvdCw0L/QuNGB0LDQvdC90LDRjyDRgNCw0L3QtdC1LCDQvdC+INGH0YLQviDQtNC10LvQsNGC0YwsINC60L7Qs9C00LAg0L/QtdGA0LXQvNC10L3QvdCw0Y8g0L3QtSDQvtC00L3QsCwg0LAg0L7Qs9GA0L7QvNC90L7QtSDQvNC90L7QttC10YHRgtCy0L4sINC4INCy0YHQtSDQuNGFINC/0LXRgNC10L/RgNC+0LLQtdGA0Y/RgtGMINCy0YDRg9GH0L3Rg9GOINC00L7QstC+0LvRjNC90L4g0YPRgtC+0LzQuNGC0LXQu9GM0L3Qvi4g0JDQstGC0L7QvNCw0YLQuNGH0LXRgdC60Lgg0LLRgdC1INGN0YLQviDQvNC+0LbQvdC+INGB0LTQtdC70LDRgtGMINGBINC/0L7QvNC+0YnRjNGOINGE0YPQvdC60YbQuNC4INGB0LXQvNC10LnRgdGC0LLQsCBhcHBseS4gIA0K0JTQu9GPINC90LDRh9Cw0LvQsCDQv9C10YDQtdGB0YfQuNGC0LDQtdC8ICUgdG90YWwgY292ZXJhZ2Ug0YEg0L/QvtC80L7RidGM0Y4g0L/QsNC60LXRgtCwIHN0cmluZ3IgDQpgYGB7cn0NCmxpYnJhcnkoc3RyaW5naSkNCmBgYA0K0KLQtdC/0LXRgNGMINCy0LzQtdGB0YLQviDQv9C+0LvRg9GA0YPRh9C90L7Qs9C+INC40L3QtNC10LrRgdC40YDQvtCy0LDQvdC40Y8sINC80L7QttC90L4g0YEg0L/QvtC80L7RidGM0Y4g0YTRg9C90LrRhtC40LkgKnN0cl8qINGB0LTQtdC70LDRgtGMINCy0YHQtSDQsNC60LrRg9GA0LDRgtC90LXQtSDQuCDQsdGL0YHRgtGA0LXQtQ0KYGBge3J9DQojY292ZXJhZ2VfdmFyaWFibGVzIDwtIG5hbWVzKGF2aWFuKVstKDE6NCldW2MoVCxGKV0NCiNhdmlhbiR0b3RhbF9jb3ZlcmFnZSA8LSByb3dTdW1zKGF2aWFuWyAsIGNvdmVyYWdlX3ZhcmlhYmxlc10pDQpjb3ZlcmFnZV92YXJpYWJsZXMgPC0gbmFtZXMoYXZpYW4pW3N0cl9kZXRlY3QobmFtZXMoYXZpYW4pLCAiXlAiKV0NCiPQs9C00LUg0LIgc3RyX2RldGVjdCDQvNGLINC30LDQutC40L3Rg9C70Lgg0LLRgdC1INC40LzQtdC90LAg0L/QtdGA0LXQvNC10L3QvdGL0YUsINC90LDRh9C40L3QsNGO0YnQuNGF0YHRjyDRgSDQsdGD0LrQstGLIFAgKNGA0LXQs9GD0LvRj9GA0L3QvtC1INCy0YvRgNCw0LbQtdC90LjQtSAiXiIgLSDQt9C90LDRh9C40YIg0L3QsNGH0LDQu9C+INGB0YLRgNC+0LrQuCkNCmNvdmVyYWdlX3ZhcmlhYmxlcw0KYGBgDQpgYGB7cn0NCmF2aWFuJHRvdGFsX2NvdmVyYWdlIDwtIHJvd1N1bXMoYXZpYW5bICwgY292ZXJhZ2VfdmFyaWFibGVzXSkNCmBgYA0KDQrQotC10L/QtdGA0Ywg0L/RgNC+0LLQtdGA0L3QtdC8INGC0L4sINGA0LDQtNC4INGH0LXQs9C+INCy0YHQtSDRjdGC0L4g0LfQsNGC0LXQstCw0LvQvtGB0YwNCmBgYHtyfQ0Kc2FwcGx5KGNvdmVyYWdlX3ZhcmlhYmxlcywgZnVuY3Rpb24obmFtZSkgY2hlY2tfcGVyY2VudF9yYW5nZShhdmlhbltbbmFtZV1dKSkNCiPQs9C00LUgZnVuY3Rpb24obmFtZSkgLSDRg9C60LDQt9Cw0L3QuNC1INC+INGC0L7QvCwg0YfRgtC+INCx0YPQtNC10Lwg0L/RgNC40LzQtdC90Y/RgtGMINCw0L3QvtC90LjQvNC90YPRjiDRhNGD0L3QutGG0LjRjiwg0L/QvtGB0LvQtSDQutC+0YLQvtGA0L7Qs9C+INGD0LrQsNC30YvQstCw0LXQvCDRgdCw0LzRgyDRhNGD0L3QutGG0LjRjg0KIyNbW25hbWVdXSwg0YIu0LouINGE0YPQvdC60YbQuNGPINC90LAg0LLRhdC+0LQg0L/RgNC40L3QuNC80LDQtdGCINCy0LXQutGC0L7RgCwg0L/QvtGN0YLQvtC80YMg0Lgg0LjQt9Cy0LvQtdC60LDQtdC8INCy0LXQutGC0L7RgCDQuNC3INC00LDRgtCwINGE0YDQtdC50LzQsCwg0LAg0L3QtSDRgdGC0YDQvtC60YMNCiMg0YIu0LUuINC80Ysg0LjQtyDQuNC80LXQvdC4INC/0L7Qu9GD0YfQsNC10Lwg0LLQtdC60YLQvtGAINC/0L4g0Y3RgtC+0LzRgyDQuNC80LXQvdC4LCDQuCDQv9GA0LjQvNC10L3Rj9C10Lwg0Log0L3QtdC80YMg0YTRg9C90LrRhtC40Y4NCmBgYA0K0JDQstGC0L7QvNCw0YLQuNGH0LXRgdC60Lgg0L/RgNC+0LLQtdGA0LjQu9C4INCy0YHQtSwg0L/QvtC00L7Qt9GA0LjRgtC10LvRjNC90YvQtSDQv9C10YDQtdC80LXQvdC90YvQtSDQv9C+0LzQvtGJ0YzRjiDRjdGC0L7QuSDQutC+0L3RgdGC0YDRg9C60YbQuNC4LiDQotCw0LrQsNGPINC60L7QvdGB0YLRgNGD0LrRhtC40Y8gLSDRg9C20LUg0YXQvtGA0L7RiNC40Lkg0YPRgNC+0LLQtdC90Ywg0L/RgNC+0LPRgNCw0LzQvNC40YDQvtCy0LDQvdC40Y8sINC+0L3QsCDRgdC90LjQvNCw0LXRgiDQvdC10L7QsdGF0L7QtNC40LzQvtGB0YLRjCDQtNC10LvQsNGC0Ywg0YfRgtC+LdGC0L4g0YDRg9C60LDQvNC4LiDQnNC+0LbQvdC+INC/0L7QstC10YDRhSDQv9C+0LLQtdGB0LjRgtGMINGD0YHQu9C+0LLQuNC1IGlmLCDRh9GC0L7QsdGLINGB0LjQs9C90LDQu9C40LfQuNGA0L7QstCw0YLRjCDQutCw0LrQuNC8LdGC0L4g0L7QsdGA0LDQt9C+0Lwg0L4g0L/RgNC+0LHQu9C10LzQtSwg0LXRgdC70Lgg0LHRg9C00LXQvCDRgNCw0LHQvtCw0YLRjCDRgSDQvdC+0LLRi9C8INGE0LDQudC70L7QvCAtINC90LDQv9GA0LjQvNC10YAsINCy0YvQstC+0LTQuNGC0Ywg0YHQvtC+0LHRidC10L3QuNC1INC+0LEg0L7RiNC40LHQutC1INC4INC/0YDQtdC60YDQsNGJ0LDRgtGMINC00LDQu9GM0L3QtdGI0LjQtSDQstGL0YfQuNGB0LvQtdC90LjRjyAgDQogIA0K0J/QvtGB0LzQvtGC0YDQuNC8INC90LAg0YPQvdC40LrQsNC70YzQvdGL0LUg0L3QsNC30LLQsNC90LjRjyDQvdCw0LHQu9GO0LTQtdC90LjQuSDQv9C+0LQg0L/QtdGA0LXQvNC10L3QvdC+0LkgU2l0ZQ0KYGBge3J9DQp1bmlxdWUoYXZpYW4kU2l0ZSkNCmBgYA0K0JLQuNC00LjQvCwg0YfRgtC+INCy0YHQtSDQvtC90Lgg0YHRgtGA0L7Rj9GC0YHRjyDQv9C+0YXQvtC20LjQvCDQvtCx0YDQsNC30L7QvC4g0K3RgtC+INC80L7QttC10YIg0LHRi9GC0Ywg0L/QvtC70LXQt9C90YvQvCwg0LXRgdC70Lgg0YXQvtGC0LjQvCDRgdGA0LDQstC90LjRgtGMINGG0LXQu9GL0LUg0LPQtdC+0LPRgNCw0YTQuNGH0LXRgdC60LjQtSDRgNC10LPQuNC+0L3RiyDQvNC10LbQtNGDINGB0L7QsdC+0LkuINCa0LDQuiDRgSDRjdGC0LjQvCDQvNC+0LbQvdC+INGA0LDQsdC+0YLQsNGC0YwsINC30L3QsNGPINC80LXRgtC+0LTRiyDRgNCw0LHQvtGC0Ysg0YHQviDRgdGC0YDQvtC60LDQvNC4LiDQndCwINC/0L7QvNC+0YnRjCDQvtC/0Y/RgtGMINC/0YDQuNC00LXRgiDQv9Cw0LrQtdGCIHN0cmluZ3IuINCX0LDQstC10LTQtdC8INC90L7QstGD0Y4g0L/QtdGA0LXQvNC10L3QvdGD0Y4NCg0KYGBge3J9DQphdmlhbiRzaXRlX25hbWUgPC0gc3RyX3JlcGxhY2UoYXZpYW4kU2l0ZSwgIls6ZGlnaXQ6XSsiLCAiIikNCiMxKSDQs9C00LUg0L/QtdGA0LLRi9C5INCw0YDQs9GD0LzQtdC90YIgLSDRjdGC0L4g0L/QtdGA0LXQvNC10L3QvdCw0Y8NCiMyKSDQtNCw0LvQtdC1INGA0LXQs9GD0LvRj9GA0L3QvtC1INCy0YvRgNCw0LbQtdC90LjQtSwg0L7QsdC+0LfQvdCw0YfQsNGO0YnQtdC1INCy0YHQtSDRhtC40YTRgNGLIFs6ZGlnaXQ6XQ0KI9CwICIrIiAtIHdpbGRjYXJkLCDQvtCx0L7Qt9C90LDRh9Cw0Y7RidCw0LXRgiwg0YfRgtC+INGB0LjQvNCy0L7QuyDQv9C+0LLRgtC+0YDQtdC9INC60LDQutC+0LUt0YLQviDQutC+0LvQuNGH0LXRgdGC0LLQviDRgNCw0LcNCiPRgi7QtS4gIls6ZGlnaXQ6XSsiIC0g0Y3RgtC+INC70Y7QsdCw0Y8g0YbQuNGE0YDQsCwg0L/QvtCy0YLQvtGA0LXQvdC90LDRjyDQutCw0LrQvtC1LdGC0L4g0L/RgNC+0LjQt9Cy0L7Qu9GM0L3QvtC1INC60L7Qu9C40YfQtdGB0YLQstC+INGA0LDQtw0KIzMpINGC0YDQtdGC0LjQuSDQsNGA0LPRg9C80LXQvdGCIC0g0L3QsCDRh9GC0L4g0LfQsNC80LXQvdGP0LXQvCAo0L3QsCAiIiwg0YIu0LUuINC90LAg0L/Rg9GB0YLRg9GOINGB0YLRgNC+0LrRgykNCnN0cihhdmlhbiRzaXRlX25hbWUpDQpgYGANCtCf0L7Qu9GD0YfQuNC70LgsINC/0LXRgNC10LzQtdC90L3Rg9GOINGBINC+0YfQuNGJ0LXQvdC90YvQvNC4INC+0YIg0YbQuNGE0YAg0L3QsNCx0LvRjtC00LXQvdC40Y/QvNC4LCDQsCDQt9C90LDRh9C40YIg0LLRgdC1INGN0YLQviDRgtC10L/QtdGA0Ywg0LzQvtC20L3QviDQt9Cw0LLQtdGA0L3Rg9GC0Ywg0LIg0YTQsNC60YLQvtGAINC00LvRjyDRg9C00L7QsdGB0YLQstCwINGA0LDQsdC+0YLRiyDRgSDQvdC40LzQuA0KYGBge3J9DQphdmlhbiRzaXRlX25hbWUgPC0gZmFjdG9yKHN0cl9yZXBsYWNlKGF2aWFuJHNpdGUsICJbOmRpZ2l0Ol0iLCAiIikpDQpzdHIoYXZpYW4kc2l0ZV9uYW1lKQ0Kc3VtbWFyeShhdmlhbiRzaXRlX25hbWUpDQpgYGANCtCS0LjQtNC40LwsINGH0YLQviDRgtC10L/QtdGA0Ywg0YMg0L3QsNGBINC10YHRgtGMINC/0LXRgNC10LzQtdC90L3QsNGPINGBIDUg0YPRgNC+0LLQvdGP0LzQuCwg0LrQsNC20LTRi9C5INC40Lcg0LrQvtGC0L7RgNGL0YUg0YHQvtC+0YLQstC10YLRgdCy0YPQtdGCINC60LDQutC+0LzRgy3RgtC+INCz0LXQvtCz0YDQsNGE0LjRh9C10YHQutC+0LzRgyDRgNC10LPQuNC+0L3Rgy4g0J/QviDRgtCw0LrQvtC80YMg0YTQsNC60YLQvtGA0YMg0LzQvtC20L3QviDQsdGD0LTQtdGCINC+0YDQuNC10L3RgtC40YDQvtCy0YLRjNGB0Y8g0L/RgNC4INC/0L7QtNGB0YfQtdGC0LUg0YHRgtCw0YLQuNGB0YLQuNC60LgNCmBgYHtyfQ0KdGFwcGx5KGF2aWFuJERCSHQsIGF2aWFuJHNpdGVfbmFtZSwgbWVhbikNCiMxKSDQv9C10YDQstGL0Lkg0LDRgNCz0YPQvNC10L3RgiAtINGB0YDQsNCy0L3QuNCy0LDQtdC80LDRjyDQv9C10YDQtdC80LXQvdC90LDRjyAo0LzQsNC60YHQuNC80LDQu9GM0L3Ri9C5INGA0L7RgdGCINGA0LDRgdGC0LXQvdC40Y8pDQojMikg0LLRgtC+0YDQvtC5IC0g0YTQsNC60YLQvtGAINGA0LDQt9C00LXQu9C10L3QuNGPIA0KIzMpINGC0YDQtdGC0LjQuSAtINGB0YLQsNGC0LjRgdGC0LjQutCwICjQt9C00LXRgSDRgdGA0LXQtNC90LXQtSkNCmBgYA0K0K3RgtC+INGD0LbQtSDQvdC10LrQuNC5INC/0YDQvtC00LLQuNC90YPRgtGL0Lkg0LDQvdCw0LvQuNC3INC00LDQvdC90YvRhS4gIA0K0JzQvtC20LXQvCDRgtCw0Log0LbQtSDQvtGG0LXQvdC40YLRjCwg0L3QsNC/0YDQuNC80LXRgCwg0YDQtdCz0LjQvtC9INCyINC60L7RgtC+0YDQvtC8INC/0L7QutGA0YvRgtC40LUg0YDQsNGB0YLQtdC90LjRj9C80LggKHRvdGFsX2NvdmVyYWdlKSAtINC90LDQuNC80LXQvdGM0YjQuNC5DQoNCmBgYHtyfQ0KdGFwcGx5KGF2aWFuJHRvdGFsX2NvdmVyYWdlLCBhdmlhbiRzaXRlX25hbWUsIHN1bW1hcnkpDQpgYGANCtCi0LXQv9C10YDRjCDQvNC+0LbQtdC8LCDQvdCw0L/RgNC40LzQtdGALCDQvtC/0YDQtdC00LXQu9C40YLRjCwg0LrRgtC+INC40YUg0YPRh9C10L3Ri9GFINC90LDRiNC10LssINC60LDQutC40LUg0YHQsNC80YvQtSDQstGL0YHQvtC60LjQtSDRgNCw0YHRgtC10L3QuNGPINC40Lcg0L/RgNC10LTRgdGC0LDQstC40YLQtdC70LXQuSDRgdCy0L7QtdCz0L4g0LLQuNC00LAuINCj0YfQtdC90YvRhSDRgyDQvdCw0YEg0YLRgNC4INCyINC/0LXRgNC10LzQtdC90L3QvtC5IE9ic2VydmVyLCDQutC+0YLQvtGA0LDRjyDQt9Cw0L/QuNGB0LDQvdCwINC60LDQuiDRhNCw0LrRgtC+0YAgKEpULCBSQSwgUlIpLiDQkCDQstC+0YIg0LLQuNC00L7QsiDRgNCw0YHRgtC10L3QuNC5INCx0L7Qu9GM0YjQtTogREIgKNC60LDRgNC70LjQutC+0LLQsNGPINCx0LXRgNGR0LfQsCksIFcgKNC40LLQsCksIEUgKNCy0LXRgNC10YHQuiksIEEgKNC+0LvRjNGF0LApLCBIICjRgtGA0LDQstGP0L3Ri9C1INGA0LDRgdGC0LXQvdC40Y8pLCBMICjQu9C40YjQsNC50L3QuNC60LgpLiAgIA0KMS4g0J3QsNC50LTRgyDQv9C10YDQtdC80LXQvdC90YvQtSDRgSDQstGL0YHQvtGC0L7QuSDQstC40LTQvtCyDQpgYGB7cn0NCm5hbWVzKGF2aWFuKVtzdHJfZGV0ZWN0KG5hbWVzKGF2aWFuKSwgIi5IdCQiKV0NCmBgYA0KMi4g0JfQsNC/0LjRiNGDINC40YUg0LIg0L/QtdGA0LXQvNC10L3QvdGD0Y4NCmBgYHtyfQ0KSHRfdmFyaWFibGVzIDwtIG5hbWVzKGF2aWFuKVtzdHJfZGV0ZWN0KG5hbWVzKGF2aWFuKSwgIi5IdCQiKV0NCkh0X3ZhcmlhYmxlcw0KYGBgDQoNCjMuINChINC/0L7QvNC+0YnRjNGOIHNhcHBseSDQvdCw0LnQtNGDINC+0LHRidGD0Y4g0YHRgtCw0YLQuNGB0YLQuNC60YMNCmBgYHtyfQ0Kc2FwcGx5KEh0X3ZhcmlhYmxlcywgZnVuY3Rpb24obmFtZSkgc3VtbWFyeShhdmlhbltbbmFtZV1dKSkNCmBgYA0K0K3RgtC+INC80L7QttC90L4g0YHQtNC10LvQsNGC0Ywg0LXRidC1INGC0LDQuiwg0L/QvtC70YPRh9C40LIg0YLQviDQttC1INGB0LDQvNC+0LUuINCh0LzRi9GB0Lsg0LIg0YLQvtC8LCDRh9GC0L4g0YTRg9C90LrRhtC40Lggc2FwbGx5INC/0LXRgNC10LTQsNGOINC90LUg0L/RgNC+0YHRgtC+INCy0LXQutGC0L7RgCDRgdGC0YDQvtC6LCDQsCDQuNC80LXQvdCwINC60L7Qu9C+0L3QvtC6Lg0KYGBge3J9DQpzYXBwbHkoYXZpYW5bLEh0X3ZhcmlhYmxlc10sIHN1bW1hcnkpDQpgYGANCg0K0JvQsNC00L3Qviwg0L/QvtC60LAg0L3QtSDQv9C+0L3QuNC80LDRjiwg0LrQsNC6INC/0L7Qu9GD0YfQuNGC0Ywg0LLRi9C60LvQsNC00LrRgyDRh9C10YDQtdC3INC+0LTQvdGDINC60L7QvNCw0L3QtNGDINGB0YDQsNC30YMg0L/QviDQstGB0LXQvCDRgNCw0YHRgtC10L3QuNGP0LwuINCh0LTQtdC70LDQtdC8INC/0L4g0L/QvtGA0Y/QtNC60YM6ICAgDQpgYGB7cn0NCnRhcHBseShhdmlhbiREQkh0LCBhdmlhbiRPYnNlcnZlciwgc3VtbWFyeSkNCmBgYA0K0JLRi9C40LPRgNGL0LLQsNC10YIgUmENCmBgYHtyfQ0KdGFwcGx5KGF2aWFuJFdIdCwgYXZpYW4kT2JzZXJ2ZXIsIHN1bW1hcnkpDQpgYGANCtCS0YvQuNCz0YDRi9Cy0LDQtdGCIEpUDQpgYGB7cn0NCnRhcHBseShhdmlhbiRFSHQsIGF2aWFuJE9ic2VydmVyLCBzdW1tYXJ5KQ0KYGBgDQpgYGB7cn0NCnRhcHBseShhdmlhbiRBSHQsIGF2aWFuJE9ic2VydmVyLCBzdW1tYXJ5KQ0KYGBgDQpgYGB7cn0NCnRhcHBseShhdmlhbiRISHQsIGF2aWFuJE9ic2VydmVyLCBzdW1tYXJ5KQ0KYGBgDQpgYGB7cn0NCnRhcHBseShhdmlhbiRMSHQsIGF2aWFuJE9ic2VydmVyLCBzdW1tYXJ5KQ0KYGBgDQrQn9GA0L7Rh9C40YLQsNC7INC90LAg0YTQvtGA0YPQvNC1INGA0LXRiNC10L3QuNC5LCDRh9GC0L4g0YLRgyDQstGL0LrQu9Cw0LTQutGDLCDQutC+0YLQvtGA0YPRjiDRjyDQv9C+0LvRg9GH0LDQuywg0LzQvtC20L3QviDQsdGL0LvQviDQvtGH0LXQvdGMINC/0YDQvtGB0YLQviDRgNCw0LfQtNC10LvQuNGC0Ywg0L/QviDRhNCw0LrRgtC+0YDQsC4g0JPQu9C+0LHQsNC70YzQvdC+INCy0YHQtSDRgtCw0LouDQpgYGB7cn0NCm1heF9oZWlnaHQgPC0gc2FwcGx5KGF2aWFuWyxIdF92YXJpYWJsZXNdLCBtYXgpDQpkYXRhLmZyYW1lKG1heF9oZWlnaHQsIGF2aWFuJE9ic2VydmVyW21heF9oZWlnaHRdKQ0KYGBgDQoNCtC40LvQuCDRgtCw0LoNCmBgYHtyfQ0KYWdncmVnYXRlKGxpc3QoYXZpYW5bLEh0X3ZhcmlhYmxlc10pLCBieSA9IGxpc3QoYXZpYW4kT2JzZXJ2ZXIpLCBtYXgpDQpgYGANCmBgYHtyfQ0KP2FnZ3JlZ2F0ZQ0KYGBgDQrQuNGB0L/QvtC70YzQt9GD0LXRgtGB0Y8g0YTRg9C90LrRhtC40Y8gYWdncmVnYXRlIC0g0LDQvdCw0LvQvtCzIHRhcHBseSDRgtC+0LvRjNC60L4g0LTQu9GPINC90LXRgdC60L7Qu9GM0LrQuNGFINGB0YLQvtC70LHRhtC+0LINCg0KaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNzAyOTgwMC9ob3ctdG8tcnVuLXRhcHBseS1vbi1tdWx0aXBsZS1jb2x1bW5zLW9mLWRhdGEtZnJhbWUtdXNpbmctcg0KDQojIyMg0J7QsdGJ0LjQuSDQs9C70L7RgdGB0LDRgNC40Lkg0LTQu9GPINGN0YLQvtCz0L4g0YPRgNC+0LrQsDogIA0KDQoqID9wYXN0ZSAoP3Bhc3RlMCksID9zdHJzcGxpdCAgIA0KDQoqICoqUmVndWxhciBleHByZXNzaW9ucyoqICANCg0KKiA/Z3JlcCAoP2dyZXBsLCA/Z3N1YikgIA0KDQoqIGxpYnJhcnkoc3RyaW5ncik6ID9zdHJfZXh0cmFjdCwgP3N0cl9yZXBsYWNlICANCg0KKiA/dG9sb3dlciwgP3RvdXBwZXIgIA0KDQoqID9nZXR3ZCwgP3NldHdkLCA/bGlzdC5maWxlcywgP2xpc3QuZGlycyAgDQoNCiogP2Zvcm1hdEMsID9jYXQgIA0KDQoqID9mYWN0b3IgIA0KDQoqID9sZXZlbHMsID9ubGV2ZWxzLCA/ZHJvcGxldmVscyAgDQoNCiogP29yZGVyZWQgIA0KDQoqID9jdXQsID90YWJsZSAgDQoNCiogP29wdGlvbnMgIA0KDQoqID90YXBwbHkgIA0KDQo=