Пример работы с данными

Этапы работы с данными

Этап 1 - Импорт данных

A. Из файла:
* Comma separated values (.csv), tab separated values - самый частый случай
* Неструктуриированный текст - readLines, scan
* XML, HTML - library(XML), library(httr)
* JSON, YAML - library(rjson), library(RJSONIO)
* Excel - library(XLConnect), library(readxl)
* SAS, Stats, SPSS, MATLAB - library(foreign), library(sas7bdat)
Т.е. для разного типа данных чаще всего есть свои пакеты для их импорта.

B. Web - library(rvest)
- доступ к API

C. Базы данных:
* Реляционные - library(BBI), library(rmongodb)
* Нереляционные - library(rmongodb)
Это не исчерпывающий список

Чтение табличных данных

Основной иснтурмент - read.table:
* file - имя файла
* header - наличие или отсутствие заголовка в первой строке
* sep - разделитель значений
* quote - символы, обозначающие кавычки (для строкового типа)
* na.strings - строки, кодирующие пропущенные значения
* colClasses - типы столбцов (для быстродействия и указания типа): строка-фактор-дата/время) - если colClasses не указан, то R попытается угадать типы данных, н оне всегда верно * comment.char - символ, обозначаюащий комментарий
* skip - количество строк, пропускаемых с начала файла (если, например, заняты дополнительной ненужной табуляцией)

Функция read.csv, read.csv2, read.delim, read.delim2 - оболочки над read.table с различными вводными по умолчанию для аргументов, перечисленных выше

Этап 2 - (пред)обработка данных

Шаги:
1. Импторт в дата фрейм (рассмотрен выше) 2. Очистка значений, проверка типов: проверяем корректность распознавания типов, корректируем при необходимости
3. Работа со строками: имена, переменные строкового типа, факторы: проверяем, чтобы перменные строкового типа и факторы не смешивались
4. Пропущенные значения: идентификация, способ обработки
5. Манипулирование переменными: преобразование, создание, удаление (например, создание новых из уже имещихся и т.д.)
6. Подсчет описательных статистик: split-apply-combine (чтобы посмотреть средние, в целом взглянуть на данные + ловим ошибки, связанные с недочищенными данными на предыдущих этапах) 7. Визуализация данных (делаем, например, ряд скатерр-плотов и убеждаемся, что нет никаких аномалий)

  1. Экспорт (экспорт очищенных данных в отдельный файл)

Очистка значений, проверка типов

Типы переменных, на которых легко ошибиться при импорте: * Числовые типы становятся строковыми
** из-за пропущенных значений, отмеченных не как NA
Чтобы избежать нужно задать отметку пропущенных значений, это в том числе может быть вектор значений

#na.strings = c("NA", "Not available", "Missing")  
Было 21 предупреждение (введите warnings() чтобы его просмотреть)

** из-за неверно указанных разделителя, десятичного знака

#sep = ",", dec = "."

N.B!В руссокой традиции часто вместо десятичной точки используется запятая, которая в .csv обычно определяет разделитель значений - отсюда проблемы

** из-за кавычек, сопроводительного текста или комментариев

#quote, comment.char, skip
  • Cтроковые типы становятся факторами либо наоборот
#as.character, as.factor
  • Тип “дата/время” остается строковым
#as.POSIXct
#as.POSIXlt
#as.Date

Как убедиться, что все в порядке?

Вряд ли будем смотреть весь массив данных, стоит прогнать через ряд функций: str, summary, head, tail

Работа с переменными

  • Функции complete.cases и na.omit для удаления наблюдений с пропущенными значениями:
#df[complete.cases(df), ] 
# или
#na.omit(df)
  • Замена NA на некоторые значения может быть потенциально опасной:
    ** заполнение средним по колонке может вносить смещение в данные
    ** заполнение нулями в большинстве случаев вообще некорректно!
  • Создание, изменение и удаление переменных выполняется конструкциями:
help()
#df$new_var <- <...>  
#df$old_var <- f(df$old_var)  
#df$old_var <- NULL  
  • Кроме того, для работы сразу с большим количеством переменных можно воспользоваться функцией within

Экспорт

Допустим, завершили предобработку данных и хотим записать файл с очищенными данными
* write.table, write.csv и write.csv2 - почти идентичные функции импоорта
* Если массив данных достаточно большой, то лучше всего отделять этап преобработки:
** отдельный файл .R до обработки
** отдельный файл с преодобработанными (“чистыми”) данными - на котором можно спускать алгоритмы, сохранять скрипт обработки и не тратить каждый раз дополнительные усилия на обработку. Так же это удобно, если исходная таблица меняется или дополняется (например, присылают вторую часть данных)

Пример дата фрейма и его анализа

Визуальная инспекция данных – важный этап предварительного анализа данных. Она позволяет заметить очевидные несоответствия и аномалии в данных, и, что немаловажно, “почувствовать” структуру дата фрейма. Какие в нём есть переменные? Что они означают? В каких единицах измеряются? Какой у них диапазон значений?

?quakes
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 ...
summary(quakes)
      lat              long           depth            mag          stations     
 Min.   :-38.59   Min.   :165.7   Min.   : 40.0   Min.   :4.00   Min.   : 10.00  
 1st Qu.:-23.47   1st Qu.:179.6   1st Qu.: 99.0   1st Qu.:4.30   1st Qu.: 18.00  
 Median :-20.30   Median :181.4   Median :247.0   Median :4.60   Median : 27.00  
 Mean   :-20.64   Mean   :179.5   Mean   :311.4   Mean   :4.62   Mean   : 33.42  
 3rd Qu.:-17.64   3rd Qu.:183.2   3rd Qu.:543.0   3rd Qu.:4.90   3rd Qu.: 42.00  
 Max.   :-10.72   Max.   :188.1   Max.   :680.0   Max.   :6.40   Max.   :132.00  
head(quakes)
tail(quakes)

Массив данных (реальный)

Загрузим реальный массив с данными для работы

?read.csv
avian <- read.csv("C:/Users/Tony/Desktop/R/Mine/avianHabitat.csv")

Проглядим, что он из себя представляет. Заодно проверяем, чтобы все типы данных считались правильно.

head(avian)

Видим, что все данные считались правильно.

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 ...

Посчитаем базовые описательные статистики. Исходя из этого можно сделать визуальную оценку данных. Таким образом, сразу можно обнаружить аномалии, например, если есть переменная, отвечающая за проценты, то сразу понимаем, что минимум не может быть меньше 0, а максимум - больше 100

summary(avian)
     Site             Observer            Subpoint           VOR              PDB              DBHt        
 Length:1070        Length:1070        Min.   : 1.000   Min.   : 0.000   Min.   :0.0000   Min.   : 0.0000  
 Class :character   Class :character   1st Qu.: 3.000   1st Qu.: 0.000   1st Qu.:0.0000   1st Qu.: 0.0000  
 Mode  :character   Mode  :character   Median : 6.000   Median : 1.000   Median :0.0000   Median : 0.0000  
                                       Mean   : 5.921   Mean   : 1.203   Mean   :0.8682   Mean   : 0.7827  
                                       3rd Qu.: 8.000   3rd Qu.: 1.500   3rd Qu.:2.0000   3rd Qu.: 1.2000  
                                       Max.   :15.000   Max.   :19.000   Max.   :5.0000   Max.   :10.0000  
       PW             WHt               PE             EHt               PA               AHt        
 Min.   :0.000   Min.   : 0.000   Min.   :0.000   Min.   :0.0000   Min.   :0.00000   Min.   : 0.000  
 1st Qu.:0.000   1st Qu.: 0.000   1st Qu.:1.000   1st Qu.:0.3000   1st Qu.:0.00000   1st Qu.: 0.000  
 Median :1.000   Median : 0.400   Median :2.000   Median :0.8000   Median :0.00000   Median : 0.000  
 Mean   :1.151   Mean   : 1.027   Mean   :2.239   Mean   :0.9659   Mean   :0.04206   Mean   : 0.186  
 3rd Qu.:2.000   3rd Qu.: 1.100   3rd Qu.:3.000   3rd Qu.:1.4000   3rd Qu.:0.00000   3rd Qu.: 0.000  
 Max.   :6.000   Max.   :24.500   Max.   :6.000   Max.   :5.3000   Max.   :6.00000   Max.   :31.500  
       PH             HHt              PL             LHt               PB        
 Min.   :0.000   Min.   :0.000   Min.   :0.000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:2.000   1st Qu.:1.400   1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :3.000   Median :2.300   Median :1.000   Median :0.2000   Median :0.0000  
 Mean   :2.867   Mean   :2.321   Mean   :1.652   Mean   :0.2685   Mean   :0.7318  
 3rd Qu.:4.000   3rd Qu.:3.100   3rd Qu.:3.000   3rd Qu.:0.5000   3rd Qu.:1.0000  
 Max.   :6.000   Max.   :8.200   Max.   :6.000   Max.   :1.3000   Max.   :6.0000  

Преодобработка данных крайне важный этап. Известный принцип GIGO: “Garbage in - Garbage out”

Отлавливаем ошибки дальше

Не всегда можно отловить все ошибки считывания данных с помощью функций str, summary и head

Есть ли пропущенные значения? Знак “!” - это логический оператор, который обознаечает NOT. Т.е. фактически мы проверяем, есть ли НЕ законченные наблюдения

any(!complete.cases(avian))
[1] FALSE

или более прямой запрос:

any(is.na(avian))
[1] FALSE

Пропусков нет - вопрос отпадает

N.B! Конструкции вида any(is.na(x)) или any(!complete.cases(data)) после версии R 3.1.0. призвана заменить конструкция anyNA. Работает она быстрее, разумеется. Приятно и то, что она работает со вложенными списками (нужно указать recursive = TRUE)
Чтобы отслеживать такую инфу полезно читать https://cran.r-project.org/src/base/NEWS после очередного релиза полезно

Проверим диапазон процентов Знак “|” - это логический оператор, обозначающий OR

any(avian$PDB < 0 | avian$PDB > 100)
[1] FALSE

Переменная PDB, отвечающая за % покрытия, прошла проверку

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

check_percent_range <- function(x) {
  any(x < 0 | x > 100)
}

Проверяем PDB

check_percent_range(avian$PDB)
[1] FALSE
check_percent_range(avian$PW)
[1] FALSE

Допустим, все проверили. Все в порядке

Преобразование переменных

Нас могут волновать, разные вопросы преобразования. В задачи преобразования переменных может входить, напрмимер:
* изменение мер измерения (например, из кг в г)
* создание новых переменных, на основе вычисления из имеющихся (например, подсчет ИМТ на основе переменных роста и веса)
* и др.

В дата фрейме avian у нас есть отдельные переменные, характеризующие процент покрытия разных видов. Например, нас интересует, какой общий процент покрытия по всем имеющимся видам. Будет ли он близок к 100%? или в каком-то диапазоне? Это осмысленный вопрос.
Для этого нам нужно:
* создать отдельную переменную
* сложить в новую переменную все имеющиеся проценты

А какие переменные у нас вообще есть? Посмотрим, какие перменные записаны в дата фрейме

names(avian)
 [1] "Site"     "Observer" "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"      
[10] "EHt"      "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      

Теперь начинаем писать код, который сделает, что мы хотим

# Можем выбросить первые четыре переменные сразу
# Дальше видим, что каждая 2-я переменная нас не интересует, поэтому можем воспользоваться конструкцией c(T,F)
coverage_variables <- names(avian)[-(1:4)][c(T, F)]

При помощи такой конструкции взяли только те типы переменных, которые содержат в себе только проценты.

N.B! Две квадратные скобки подряд
Когда допустимо применять две пары квадратных скобок при индексации?
Применять можно всегда. В случае x[1][3] вы берете первый элемент, и в этом векторе длины один пытаетесь обратиться по третьему индексу, что NULL.

Чтобы понять, как работает можно посмотреть на другие варианты

#x[1:3][3], x[c(1,2,4)][1:2][1]
coverage_variables
[1] "PDB" "PW"  "PE"  "PA"  "PH"  "PL"  "PB" 

Чтобы теперь создать новую переменную обратимся к имени с помощью знака “$”, которого в дата фрейме пока нет

# rowSums(avian[ , "колонки с нужными переменными"]) посчитает сумму
avian$total_coverage <- rowSums(avian[ , coverage_variables])

Посмотрим, что такая переменная есть теперь в дата фрейме

head(avian$total_coverage)
[1] 11 13 11 10 11  8
head(avian)

Теперь может оценить разброc по этой перменной

summary(avian$total_coverage)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   8.000  10.000   9.552  11.000  17.000 

Видим, что, например, максимальное покрытие видом составляет - 17%, что не очень много.

Можем посмотреть встречаемость тех или иных значений по переменной

table(avian$total_coverage)

  2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17 
  2   3   4   8  41  98 154 196 227 187  88  35  22   3   1   1 

А на основе этого построить бысрый график, например:

plot(table(avian$total_coverage),
     main = "Гистограмма общей площади покрытия видами",
     type = "h"
     )

Гистограму можно построить и с помощью специальной функции

hist(avian$total_coverage)

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

table(avian$Site)

      BunkerHill11       BunkerHill12       BunkerHill13       BunkerHill14       BunkerHill15 
                10                 10                 10                 10                 10 
      BunkerHill16       BunkerHill17       BunkerHill21       BunkerHill22       BunkerHill23 
                10                 10                 10                 10                 10 
      BunkerHill24       BunkerHill25       BunkerHill26       BunkerHill27      CreteCreek110 
                10                 10                 10                 10                 10 
     CreteCreek112      CreteCreek114      CreteCreek116      CreteCreek118       CreteCreek12 
                10                 10                 10                 10                 10 
     CreteCreek120       CreteCreek14       CreteCreek16       CreteCreek18       CreteCreek21 
                10                 10                 10                 10                 10 
      CreteCreek22       CreteCreek23       CreteCreek24       CreteCreek25       CreteCreek26 
                10                 10                 10                 10                 10 
      CreteCreek27       CreteCreek28       CreteCreek29      HortonCreek11     HortonCreek110 
                10                 10                 10                 10                 10 
    HortonCreek111     HortonCreek112     HortonCreek113     HortonCreek114     HortonCreek115 
                10                 10                 10                 10                 10 
    HortonCreek116     HortonCreek117     HortonCreek118     HortonCreek119      HortonCreek12 
                10                 10                 10                 10                 10 
    HortonCreek120     HortonCreek121     HortonCreek122     HortonCreek123     HortonCreek124 
                10                 10                 10                 10                 10 
    HortonCreek125     HortonCreek126      HortonCreek13      HortonCreek14      HortonCreek15 
                10                 10                 10                 10                 10 
     HortonCreek16      HortonCreek17      HortonCreek18      HortonCreek19  LivingstonCreek11 
                10                 10                 10                 10                 10 
LivingstonCreek110 LivingstonCreek111 LivingstonCreek112 LivingstonCreek113 LivingstonCreek114 
                10                 10                 10                 10                 10 
LivingstonCreek115 LivingstonCreek116  LivingstonCreek12  LivingstonCreek13  LivingstonCreek14 
                10                 10                 10                 15                 15 
 LivingstonCreek15  LivingstonCreek16  LivingstonCreek17  LivingstonCreek18  LivingstonCreek19 
                10                 10                 15                 15                 10 
 LivingstonCreek21 LivingstonCreek210 LivingstonCreek211  LivingstonCreek22  LivingstonCreek23 
                10                 10                 10                 10                 10 
 LivingstonCreek24  LivingstonCreek25  LivingstonCreek26  LivingstonCreek27  LivingstonCreek28 
                10                 10                 10                 10                 10 
 LivingstonCreek29      McAdamCreek11      McAdamCreek12      McAdamCreek13      McAdamCreek14 
                10                 15                 15                 15                 15 
     McAdamCreek15      McAdamCreek16      McAdamCreek17      McAdamCreek18      McAdamCreek21 
                15                 15                 15                 15                 10 
     McAdamCreek22      McAdamCreek23      McAdamCreek24      McAdamCreek25      McAdamCreek26 
                10                 10                 10                 10                 10 
     McAdamCreek27 
                10 

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

grep("BunkerHill", avian$Site)
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25
 [26]  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50
 [51]  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75
 [76]  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100
[101] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
[126] 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

Теперь тэйблом снова смотрю, что я находу так только интересующую меня строку

table(avian$Site[grep("BunkerHill", avian$Site)])

BunkerHill11 BunkerHill12 BunkerHill13 BunkerHill14 BunkerHill15 BunkerHill16 BunkerHill17 BunkerHill21 
          10           10           10           10           10           10           10           10 
BunkerHill22 BunkerHill23 BunkerHill24 BunkerHill25 BunkerHill26 BunkerHill27 
          10           10           10           10           10           10 

Попробую построить гистограму площади покрытия для Bunker Hill-a

hist(avian$total_coverage[grep("BunkerHill", avian$Site)])

Теперь, например, для Livingston Creek

hist(avian$total_coverage[grep("LivingstonCreek", avian$Site)])

Еще какое-то время назад мы ничего не могли сказать о дата фрейме. Простейшее преобразование помогает нам задавать осмысленные вопросы.

Задача

Нужно вбить кусок недостающих данных, которые не прислал нам Карлош Линнейс

avian_rest <-  read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv")

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

head(avian_rest)

Вижу, что данные вообще считались некоректно. Первые 4 строки явно лишние

str(avian_rest)
'data.frame':   23 obs. of  2 variables:
 $ Dear.Sir.or.Madam: chr  "Here's the rest of our data" "With best regards" "Carlos Linayas" "----data starts from here!----" ...
 $ X                : chr  " sorry for the delay!" " " "" "" ...

Попробую пропустить первые 4 строки при повторном считывании

avian_rest <-  read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv", skip = 4)

Проверяю

head(avian_rest)

Лишние строки успешно пропущены, но замечаю, что в дата фрейме в качестве разделителя используется “;”. По умолчанию аргумент sep = “,”. Сделаю замену.

avian_rest <-  read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv", skip = 4, sep = ";")
Ошибка в read.table(file = file, header = header, sep = sep, quote = quote,  :
  больше колонок, чем имен для них

Что-то не так с числом колонок. Колонок с данными больше, чем имен. Кажется есть еще 1 лишняя строка. Пробую:

avian_rest <-  read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv", skip = 5, sep = ";")
head(avian_rest)

Сравню с исходным файлом

head(avian)

Преобразование почему-то не сработало. Пробую дальше. Нахожу комментарий к данным при просмотре таблицы вручную и дурацкую подпись в последней колонке. Пробую закоментировать подпись к данным в таблице

avian_rest <-  read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv", skip = 5, sep = ";", quote = "%")

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

avian_rest["PB...I.removed.Observer.column.since.all.measurements.are.mine"] <- "PB"

Произошла какая-то хрень. Переделаю сначал

avian_rest <-  read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv", skip = 5, sep = ";", quote = "%")

Исправилось частично. В последней колонке куча хрени.Пробую снова. Надеюсь правильно

avian_rest$PB..I.removed..Observer..column.since.all.measurements.are.mine.HortonCreek111.1.3.0.0.0.0.4.3.5.0.0.3.5.0.0.0.HortonCreek111.2.3.0.0.4.18.5.0.0.0.0.4.5.7.0.0.0.HortonCreek111.3.2.0.0.3.11.3.2.3.0.0.4.4.9.1.0.2.0.HortonCreek111.4.3.5.0.0.4.15.8.0.0.0.0.3.4.2.0.0.0.HortonCreek111.5.0.1.0.3.2.0.5.4.0.4.0.0.2.1.4.5.0.3.0.HortonCreek111.6.0.2.0.7.3.0.5.4.0.5.0.0.1.1.6.3.0.5.1.HortonCreek111.7.0.2.0.3.0.0.5.0.4.0.0.2.1.8.5.0.3.0.HortonCreek111.Don.t.remember.0.2.0.7.0.0.5.0.6.0.0.1.1.6.4.0.2.1.....Sorry.about.that..I.messed.up <- avian_rest$PB
??"data.frame" 

Читаю справку по дата фрейму. Вроде понимаю, как надо

dimnames(avian_rest$PB..I.removed..Observer..column.since.all.measurements.are.mine.HortonCreek111.1.3.0.0.0.0.4.3.5.0.0.3.5.0.0.0.HortonCreek111.2.3.0.0.4.18.5.0.0.0.0.4.5.7.0.0.0.HortonCreek111.3.2.0.0.3.11.3.2.3.0.0.4.4.9.1.0.2.0.HortonCreek111.4.3.5.0.0.4.15.8.0.0.0.0.3.4.2.0.0.0.HortonCreek111.5.0.1.0.3.2.0.5.4.0.4.0.0.2.1.4.5.0.3.0.HortonCreek111.6.0.2.0.7.3.0.5.4.0.5.0.0.1.1.6.3.0.5.1.HortonCreek111.7.0.2.0.3.0.0.5.0.4.0.0.2.1.8.5.0.3.0.HortonCreek111.Don.t.remember.0.2.0.7.0.0.5.0.6.0.0.1.1.6.4.0.2.1.....Sorry.about.that..I.messed.up) <- "PB"
Ошибка в dimnames(avian_rest$PB..I.removed..Observer..column.since.all.measurements.are.mine.HortonCreek111.1.3.0.0.0.0.4.3.5.0.0.3.5.0.0.0.HortonCreek111.2.3.0.0.4.18.5.0.0.0.0.4.5.7.0.0.0.HortonCreek111.3.2.0.0.3.11.3.2.3.0.0.4.4.9.1.0.2.0.HortonCreek111.4.3.5.0.0.4.15.8.0.0.0.0.3.4.2.0.0.0.HortonCreek111.5.0.1.0.3.2.0.5.4.0.4.0.0.2.1.4.5.0.3.0.HortonCreek111.6.0.2.0.7.3.0.5.4.0.5.0.0.1.1.6.3.0.5.1.HortonCreek111.7.0.2.0.3.0.0.5.0.4.0.0.2.1.8.5.0.3.0.HortonCreek111.Don.t.remember.0.2.0.7.0.0.5.0.6.0.0.1.1.6.4.0.2.1.....Sorry.about.that..I.messed.up) <- "PB" :
  'dimnames' применены для не-многомерной матрицы
names(avian_rest)
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      
names(avian_rest$PB..I.removed..Observer..column.since.all.measurements.are.mine.HortonCreek111.1.3.0.0.0.0.4.3.5.0.0.3.5.0.0.0.HortonCreek111.2.3.0.0.4.18.5.0.0.0.0.4.5.7.0.0.0.HortonCreek111.3.2.0.0.3.11.3.2.3.0.0.4.4.9.1.0.2.0.HortonCreek111.4.3.5.0.0.4.15.8.0.0.0.0.3.4.2.0.0.0.HortonCreek111.5.0.1.0.3.2.0.5.4.0.4.0.0.2.1.4.5.0.3.0.HortonCreek111.6.0.2.0.7.3.0.5.4.0.5.0.0.1.1.6.3.0.5.1.HortonCreek111.7.0.2.0.3.0.0.5.0.4.0.0.2.1.8.5.0.3.0.HortonCreek111.Don.t.remember.0.2.0.7.0.0.5.0.6.0.0.1.1.6.4.0.2.1.....Sorry.about.that..I.messed.up) <- "PB"
Ошибка в names(avian_rest$PB..I.removed..Observer..column.since.all.measurements.are.mine.HortonCreek111.1.3.0.0.0.0.4.3.5.0.0.3.5.0.0.0.HortonCreek111.2.3.0.0.4.18.5.0.0.0.0.4.5.7.0.0.0.HortonCreek111.3.2.0.0.3.11.3.2.3.0.0.4.4.9.1.0.2.0.HortonCreek111.4.3.5.0.0.4.15.8.0.0.0.0.3.4.2.0.0.0.HortonCreek111.5.0.1.0.3.2.0.5.4.0.4.0.0.2.1.4.5.0.3.0.HortonCreek111.6.0.2.0.7.3.0.5.4.0.5.0.0.1.1.6.3.0.5.1.HortonCreek111.7.0.2.0.3.0.0.5.0.4.0.0.2.1.8.5.0.3.0.HortonCreek111.Don.t.remember.0.2.0.7.0.0.5.0.6.0.0.1.1.6.4.0.2.1.....Sorry.about.that..I.messed.up) <- "PB" :
  попытка присвоения атрибута на NULL
names(avian_rest) 
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      

В итоге гуглю, нахожу статью на Stackoverflow

colnames(avian_rest)
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      
colnames(avian_rest)[16] <- "PB"
colnames(avian_rest)
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      

Получилось! Ура.

head(avian_rest)

Теперь видно, почему не работало преобразование на subpoint в integer. В дата фрейме есть пропущенные значения. Попробую их заменить на NA

??data.frame-missing
Ошибка в help.search(c("-", "data.frame", "missing"), package = NULL) :
  аргумент ‘pattern’ должен быть одной текстовой строкой

Снова быстро нахожу ответ на Stackoverflow. Пробую

avian_rest <- replace(avian_rest, any(avian_rest) == "Don`t remember", NA)
Ошибка в FUN(X[[i]], ...) :
  определено только для таблиц данных со всеми числовыми переменными

Проверю

head(avian_rest)

Замены не произошло. Способ не работает для типа character. Нахожу способ для character

avian_rest[avian_rest == "Don`t remember"] <- NA
head(avian_rest)

Снова не работает.
Стоп.
Приглядываюсь.
Апостроф не тот. Копирую и пробую еще раз

avian_rest[avian_rest == "Don't remember"] <- NA
head(avian_rest)

Ура! На этот раз получилось. Преобразую

as.integer(avian_rest$Subpoint)
 [1] NA  1  2  3  4  5  6  7  8  9
head(avian_rest)

Преобразование не сработало, но и хрен с ним, наверное. Остается главная проблема, как это все подшить, учитывая, что нет колонки. Попробую сделать новую

avian_rest[]

Попробую их соедиить так. Может обойдется

merge(avian, avian_rest, by.x = "Subpoint")
Ошибка в merge.data.frame(avian, avian_rest, by.x = "Subpoint") :
  'by.x' и 'by.y' определяют разные номера колонок

Из готовых функций нахожу такую только в пакете dplyr ` Остается нерешенной проблема преобразования. Снова нахожу способ на Stack-е

avian_rest$Subpoint <- as.integer(as.character(avian_rest$Subpoint))
library(dplyr)
Было 12 предупреждений (введите warnings() чтобы их просмотреть)
dplyr::bind_rows(avian, avian_rest)

Ура! Теперь наконец-то могу пересчитать показатели. Интересно, как выглядит хвост?

str(avian)
'data.frame':   1070 obs. of  18 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 ...
 $ total_coverage: num  11 13 11 10 11 8 11 10 9 8 ...

Но у меня что-то не так с количеством наблюдений. У меня 1080, а должно быть 1088. Может dplyr не объединяет их окончательно. Хз. На данном этапе все слишком запутано. Попробую изначально прочитать файл по-нормальному без заморочек, как предлагается в комментариях

read.csv(sep = ";", skip = 5, header = T, comment.char = "%", quote = "", na.strings = "Don't remember", file = 'https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv')

Попробую теперь объединить dplyr-ом

dplyr::bind_rows(avian, avian_rest)

1080 наблюдений. Бля

str(bind_rows(avian, avian_rest))
'data.frame':   1080 obs. of  18 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 ...
 $ total_coverage: num  11 13 11 10 11 8 11 10 9 8 ...

В общем, нормально он не объединяет в таком формате почему-то.

str(avian_rest)
'data.frame':   10 obs. of  16 variables:
 $ Site    : chr  "HortonCreek111" "HortonCreek112" "HortonCreek112" "HortonCreek112" ...
 $ Subpoint: int  NA 1 2 3 4 5 6 7 8 9
 $ VOR     : int  0 0 0 0 0 0 0 0 0 0
 $ PDB     : int  1 1 2 1 2 0 0 0 3 0
 $ DBHt    : num  0.4 0.8 0.5 0.1 0.3 0 0 0 0.7 0
 $ PW      : int  2 0 0 0 0 0 0 2 0 0
 $ WHt     : num  0.3 0 0 0 0 0 0 0.3 0 0
 $ PE      : int  3 3 3 3 3 4 2 3 0 2
 $ EHt     : num  0.3 0.3 0.4 0.2 0.2 0.7 0.3 0.3 0 0.2
 $ PA      : int  0 0 0 0 0 0 0 0 0 0
 $ AHt     : int  0 0 0 0 0 0 0 0 0 0
 $ PH      : int  2 1 2 1 1 1 2 2 1 2
 $ HHt     : num  1.3 0.9 0.7 0.5 0.5 0.5 0.7 0.8 3.1 0.7
 $ PL      : int  5 4 3 4 4 2 3 4 5 1
 $ LHt     : num  0.4 0.4 0.1 0.1 0.1 0.1 0.3 0.4 0.5 0.3
 $ PB      : int  0 1 1 2 1 2 3 2 0 4

Куда-то делись 8 наблюдений. Перечитаю заново

read.csv(sep = ";", skip = 5, comment.char = "%", quote = "", na.strings = "Don't remember", file = 'https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv')
str(avian_rest)
'data.frame':   10 obs. of  16 variables:
 $ Site    : chr  "HortonCreek111" "HortonCreek112" "HortonCreek112" "HortonCreek112" ...
 $ Subpoint: int  NA 1 2 3 4 5 6 7 8 9
 $ VOR     : int  0 0 0 0 0 0 0 0 0 0
 $ PDB     : int  1 1 2 1 2 0 0 0 3 0
 $ DBHt    : num  0.4 0.8 0.5 0.1 0.3 0 0 0 0.7 0
 $ PW      : int  2 0 0 0 0 0 0 2 0 0
 $ WHt     : num  0.3 0 0 0 0 0 0 0.3 0 0
 $ PE      : int  3 3 3 3 3 4 2 3 0 2
 $ EHt     : num  0.3 0.3 0.4 0.2 0.2 0.7 0.3 0.3 0 0.2
 $ PA      : int  0 0 0 0 0 0 0 0 0 0
 $ AHt     : int  0 0 0 0 0 0 0 0 0 0
 $ PH      : int  2 1 2 1 1 1 2 2 1 2
 $ HHt     : num  1.3 0.9 0.7 0.5 0.5 0.5 0.7 0.8 3.1 0.7
 $ PL      : int  5 4 3 4 4 2 3 4 5 1
 $ LHt     : num  0.4 0.4 0.1 0.1 0.1 0.1 0.3 0.4 0.5 0.3
 $ PB      : int  0 1 1 2 1 2 3 2 0 4

Почему-то все время пишет 10 наблюдений. Может, считает количество полных наблюдений? Хотя, если посчитать вручную, то получаетс я 18. Не понимаю. Ладно, пофиг надо объединять.

av_fin <- dplyr::bind_rows(avian, avian_rest)
av_fin
coverage_variables <- names(av_fin)[-(1:4)][c(T, F)]
av_fin$total_coverage <- rowSums(av_fin[ , coverage_variables])
summary(av_fin$total_coverage)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   8.000  10.000   9.562  11.000  17.000 

av_fin

av_fin$total_coveragei <- NULL
av_fin

Все-таки подозреваю проблему в объединении. Буду пробовать по-другому.

read.csv(sep = ";", skip = 5, comment.char = "%", quote = "", na.strings = "Don't remember", file = 'https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv')
colnames(avian_rest)
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      
colnames(avian_rest[2]) <- "Observer"
colnames(avian_rest)
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"      
avian_rest$Observer <- "KL"
head(avian_rest)
colnames(avian_rest)
 [1] "Site"     "Subpoint" "VOR"      "PDB"      "DBHt"     "PW"       "WHt"      "PE"       "EHt"     
[10] "PA"       "AHt"      "PH"       "HHt"      "PL"       "LHt"      "PB"       "Observer"
avian_rest <- avian_rest[ , c("Site", "Observer", "Subpoint", "VOR", "PDB",      "DBHt", "PW", "WHt", "PE", "EHt" ,"PA",   "AHt",    "PH", "HHt",  "PL", "LHt", "PB")]
avian_rest
av <- merge(avian, avian_rest, all = T)
av
av$total_coveragei <- NULL
av
coverage_variables <- names(av)[-(1:4)][c(T, F)]
av$total_coverage <- rowSums(av[ , coverage_variables])
summary(av$total_coverage)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   8.000  10.000   9.562  11.000  17.000 
av

Фух. Решил таки задачу. В итоге ответ мне не засчитывали, тыкнул просто на подбор.

avian <- read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat.csv")
coverage_variables <- names(avian)[-(1:4)][c(T, F)]
avian2 <- read.csv("https://raw.githubusercontent.com/tonytonov/Rcourse/master/R%20programming/avianHabitat2.csv",
                   sep = ";", na.strings = "Don't remember", skip = 5, comment.char = "%")
avian2
avian2$Observer <- "CL" # для красоты
avian2
avian3 <- merge(avian, avian2, all = T)
avian3
avian3$total_coverage = rowSums(avian3[coverage_variables])
summary(avian3)[4, "total_coverage"]
[1] "Mean   : 9.572  "
avian3

Задача 2

На массиве avianHabitat найдите максимальные высоты по каждому виду растений и отсортируйте эти виды по убыванию, от самого высокого к самому низкому
Общий глоссарий для этого урока:

avian$total_coveragei <- NULL
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 ...
heights <- avian[-c(1:5)][c(T, F)]
heights_max <- apply(heights, 2, max)
sort(heights_max, decreasing = T)
 AHt  WHt DBHt  HHt  EHt  LHt 
31.5 24.5 10.0  8.2  5.3  1.3 

Глоссарий

?data.frame
?str
?rownames, ?colnames, ?dimnames, ?nrow, ?ncol, ?dim
?subset, ?rbind, ?cbind, ?merge
?read.table (?read.csv, ?read.delim)
?write.table (?write.csv, ?write.delim)
?complete.cases, ?na.omit
?write.table (?write.csv)

LS0tDQp0aXRsZTogItCg0LDQsdC+0YLQsCDRgSDQtNCw0L3QvdGL0LzQuCDQsiBSIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KIyDQn9GA0LjQvNC10YAg0YDQsNCx0L7RgtGLINGBINC00LDQvdC90YvQvNC4ICANCiMjINCt0YLQsNC/0Ysg0YDQsNCx0L7RgtGLINGBINC00LDQvdC90YvQvNC4DQojIyMg0K3RgtCw0L8gMSAtINCY0LzQv9C+0YDRgiDQtNCw0L3QvdGL0YUNCkEuINCY0Lcg0YTQsNC50LvQsDogIA0KKiBDb21tYSBzZXBhcmF0ZWQgdmFsdWVzICguY3N2KSwgdGFiIHNlcGFyYXRlZCB2YWx1ZXMgLSDRgdCw0LzRi9C5INGH0LDRgdGC0YvQuSDRgdC70YPRh9Cw0LkgIA0KKiDQndC10YHRgtGA0YPQutGC0YPRgNC40LjRgNC+0LLQsNC90L3Ri9C5INGC0LXQutGB0YIgLSByZWFkTGluZXMsIHNjYW4gIA0KKiBYTUwsIEhUTUwgLSBsaWJyYXJ5KFhNTCksIGxpYnJhcnkoaHR0cikgIA0KKiBKU09OLCBZQU1MIC0gbGlicmFyeShyanNvbiksIGxpYnJhcnkoUkpTT05JTykgIA0KKiBFeGNlbCAtIGxpYnJhcnkoWExDb25uZWN0KSwgbGlicmFyeShyZWFkeGwpICANCiogU0FTLCBTdGF0cywgU1BTUywgTUFUTEFCIC0gbGlicmFyeShmb3JlaWduKSwgbGlicmFyeShzYXM3YmRhdCkgIA0K0KIu0LUuINC00LvRjyDRgNCw0LfQvdC+0LPQviDRgtC40L/QsCDQtNCw0L3QvdGL0YUg0YfQsNGJ0LUg0LLRgdC10LPQviDQtdGB0YLRjCDRgdCy0L7QuCDQv9Cw0LrQtdGC0Ysg0LTQu9GPINC40YUg0LjQvNC/0L7RgNGC0LAuIA0KDQpCLiBXZWIgLSBsaWJyYXJ5KHJ2ZXN0KSAgDQotINC00L7RgdGC0YPQvyDQuiBBUEkNCiAgDQogIA0KQy4g0JHQsNC30Ysg0LTQsNC90L3Ri9GFOiAgDQoqINCg0LXQu9GP0YbQuNC+0L3QvdGL0LUgLSBsaWJyYXJ5KEJCSSksIGxpYnJhcnkocm1vbmdvZGIpICANCiog0J3QtdGA0LXQu9GP0YbQuNC+0L3QvdGL0LUgLSBsaWJyYXJ5KHJtb25nb2RiKSAgDQrQrdGC0L4g0L3QtSDQuNGB0YfQtdGA0L/Ri9Cy0LDRjtGJ0LjQuSDRgdC/0LjRgdC+0LogIA0KDQojIyMg0KfRgtC10L3QuNC1INGC0LDQsdC70LjRh9C90YvRhSDQtNCw0L3QvdGL0YUNCtCe0YHQvdC+0LLQvdC+0Lkg0LjRgdC90YLRg9GA0LzQtdC90YIgLSAqcmVhZC50YWJsZSo6ICANCiogZmlsZSAtINC40LzRjyDRhNCw0LnQu9CwICANCiogaGVhZGVyIC0g0L3QsNC70LjRh9C40LUg0LjQu9C4INC+0YLRgdGD0YLRgdGC0LLQuNC1INC30LDQs9C+0LvQvtCy0LrQsCDQsiDQv9C10YDQstC+0Lkg0YHRgtGA0L7QutC1ICANCiogc2VwIC0g0YDQsNC30LTQtdC70LjRgtC10LvRjCDQt9C90LDRh9C10L3QuNC5ICANCiogcXVvdGUgLSDRgdC40LzQstC+0LvRiywg0L7QsdC+0LfQvdCw0YfQsNGO0YnQuNC1INC60LDQstGL0YfQutC4ICjQtNC70Y8g0YHRgtGA0L7QutC+0LLQvtCz0L4g0YLQuNC/0LApICANCiogbmEuc3RyaW5ncyAtINGB0YLRgNC+0LrQuCwg0LrQvtC00LjRgNGD0Y7RidC40LUg0L/RgNC+0L/Rg9GJ0LXQvdC90YvQtSDQt9C90LDRh9C10L3QuNGPICANCiogY29sQ2xhc3NlcyAtINGC0LjQv9GLINGB0YLQvtC70LHRhtC+0LIgKNC00LvRjyDQsdGL0YHRgtGA0L7QtNC10LnRgdGC0LLQuNGPINC4INGD0LrQsNC30LDQvdC40Y8g0YLQuNC/0LApOiDRgdGC0YDQvtC60LAt0YTQsNC60YLQvtGALdC00LDRgtCwL9Cy0YDQtdC80Y8pIC0g0LXRgdC70LggY29sQ2xhc3NlcyDQvdC1INGD0LrQsNC30LDQvSwg0YLQviBSINC/0L7Qv9GL0YLQsNC10YLRgdGPINGD0LPQsNC00LDRgtGMINGC0LjQv9GLINC00LDQvdC90YvRhSwg0L0g0L7QvdC1INCy0YHQtdCz0LTQsCDQstC10YDQvdC+IA0KKiBjb21tZW50LmNoYXIgLSDRgdC40LzQstC+0LssINC+0LHQvtC30L3QsNGH0LDRjtCw0YnQuNC5INC60L7QvNC80LXQvdGC0LDRgNC40LkgIA0KKiBza2lwIC0g0LrQvtC70LjRh9C10YHRgtCy0L4g0YHRgtGA0L7Quiwg0L/RgNC+0L/Rg9GB0LrQsNC10LzRi9GFINGBINC90LDRh9Cw0LvQsCDRhNCw0LnQu9CwICjQtdGB0LvQuCwg0L3QsNC/0YDQuNC80LXRgCwg0LfQsNC90Y/RgtGLINC00L7Qv9C+0LvQvdC40YLQtdC70YzQvdC+0Lkg0L3QtdC90YPQttC90L7QuSDRgtCw0LHRg9C70Y/RhtC40LXQuSkgIA0KICANCtCk0YPQvdC60YbQuNGPICpyZWFkLmNzdiosICpyZWFkLmNzdjIqLCAqcmVhZC5kZWxpbSosICpyZWFkLmRlbGltMiogLSDQvtCx0L7Qu9C+0YfQutC4INC90LDQtCAqcmVhZC50YWJsZSog0YEg0YDQsNC30LvQuNGH0L3Ri9C80Lgg0LLQstC+0LTQvdGL0LzQuCDQv9C+INGD0LzQvtC70YfQsNC90LjRjiDQtNC70Y8g0LDRgNCz0YPQvNC10L3RgtC+0LIsINC/0LXRgNC10YfQuNGB0LvQtdC90L3Ri9GFINCy0YvRiNC1ICANCiAgDQojIyMg0K3RgtCw0L8gMiAtICjQv9GA0LXQtCnQvtCx0YDQsNCx0L7RgtC60LAg0LTQsNC90L3Ri9GFIA0K0KjQsNCz0Lg6ICANCjEuINCY0LzQv9GC0L7RgNGCINCyINC00LDRgtCwINGE0YDQtdC50LwgICjRgNCw0YHRgdC80L7RgtGA0LXQvSDQstGL0YjQtSkNCjIuINCe0YfQuNGB0YLQutCwINC30L3QsNGH0LXQvdC40LksINC/0YDQvtCy0LXRgNC60LAg0YLQuNC/0L7Qsjog0L/RgNC+0LLQtdGA0Y/QtdC8INC60L7RgNGA0LXQutGC0L3QvtGB0YLRjCDRgNCw0YHQv9C+0LfQvdCw0LLQsNC90LjRjyDRgtC40L/QvtCyLCDQutC+0YDRgNC10LrRgtC40YDRg9C10Lwg0L/RgNC4INC90LXQvtCx0YXQvtC00LjQvNC+0YHRgtC4ICAgDQozLiDQoNCw0LHQvtGC0LAg0YHQviDRgdGC0YDQvtC60LDQvNC4OiDQuNC80LXQvdCwLCDQv9C10YDQtdC80LXQvdC90YvQtSDRgdGC0YDQvtC60L7QstC+0LPQviDRgtC40L/QsCwg0YTQsNC60YLQvtGA0Ys6INC/0YDQvtCy0LXRgNGP0LXQvCwg0YfRgtC+0LHRiyDQv9C10YDQvNC10L3QvdGL0LUg0YHRgtGA0L7QutC+0LLQvtCz0L4g0YLQuNC/0LAg0Lgg0YTQsNC60YLQvtGA0Ysg0L3QtSDRgdC80LXRiNC40LLQsNC70LjRgdGMICANCjQuINCf0YDQvtC/0YPRidC10L3QvdGL0LUg0LfQvdCw0YfQtdC90LjRjzog0LjQtNC10L3RgtC40YTQuNC60LDRhtC40Y8sINGB0L/QvtGB0L7QsSDQvtCx0YDQsNCx0L7RgtC60LggIA0KNS4g0JzQsNC90LjQv9GD0LvQuNGA0L7QstCw0L3QuNC1INC/0LXRgNC10LzQtdC90L3Ri9C80Lg6INC/0YDQtdC+0LHRgNCw0LfQvtCy0LDQvdC40LUsINGB0L7Qt9C00LDQvdC40LUsINGD0LTQsNC70LXQvdC40LUgKNC90LDQv9GA0LjQvNC10YAsINGB0L7Qt9C00LDQvdC40LUg0L3QvtCy0YvRhSDQuNC3INGD0LbQtSDQuNC80LXRidC40YXRgdGPINC4INGCLtC0LikgIA0KNi4g0J/QvtC00YHRh9C10YIg0L7Qv9C40YHQsNGC0LXQu9GM0L3Ri9GFINGB0YLQsNGC0LjRgdGC0LjQujogc3BsaXQtYXBwbHktY29tYmluZSAo0YfRgtC+0LHRiyDQv9C+0YHQvNC+0YLRgNC10YLRjCDRgdGA0LXQtNC90LjQtSwg0LIg0YbQtdC70L7QvCDQstC30LPQu9GP0L3Rg9GC0Ywg0L3QsCDQtNCw0L3QvdGL0LUgKyDQu9C+0LLQuNC8INC+0YjQuNCx0LrQuCwg0YHQstGP0LfQsNC90L3Ri9C1INGBINC90LXQtNC+0YfQuNGJ0LXQvdC90YvQvNC4INC00LDQvdC90YvQvNC4INC90LAg0L/RgNC10LTRi9C00YPRidC40YUg0Y3RgtCw0L/QsNGFKSANCjcuINCS0LjQt9GD0LDQu9C40LfQsNGG0LjRjyDQtNCw0L3QvdGL0YUgKNC00LXQu9Cw0LXQvCwg0L3QsNC/0YDQuNC80LXRgCwg0YDRj9C0INGB0LrQsNGC0LXRgNGALdC/0LvQvtGC0L7QsiDQuCDRg9Cx0LXQttC00LDQtdC80YHRjywg0YfRgtC+INC90LXRgiDQvdC40LrQsNC60LjRhSDQsNC90L7QvNCw0LvQuNC5KSAgDQogIA0KOC4g0K3QutGB0L/QvtGA0YIgKNGN0LrRgdC/0L7RgNGCINC+0YfQuNGJ0LXQvdC90YvRhSDQtNCw0L3QvdGL0YUg0LIg0L7RgtC00LXQu9GM0L3Ri9C5INGE0LDQudC7KSAgDQogIA0KIyMg0J7Rh9C40YHRgtC60LAg0LfQvdCw0YfQtdC90LjQuSwg0L/RgNC+0LLQtdGA0LrQsCDRgtC40L/QvtCyICANCtCi0LjQv9GLINC/0LXRgNC10LzQtdC90L3Ri9GFLCDQvdCwINC60L7RgtC+0YDRi9GFINC70LXQs9C60L4g0L7RiNC40LHQuNGC0YzRgdGPINC/0YDQuCDQuNC80L/QvtGA0YLQtToNCiog0KfQuNGB0LvQvtCy0YvQtSDRgtC40L/RiyDRgdGC0LDQvdC+0LLRj9GC0YHRjyDRgdGC0YDQvtC60L7QstGL0LzQuCAgDQoqKiDQuNC3LdC30LAg0L/RgNC+0L/Rg9GJ0LXQvdC90YvRhSDQt9C90LDRh9C10L3QuNC5LCDQvtGC0LzQtdGH0LXQvdC90YvRhSDQvdC1INC60LDQuiAqTkEqICANCtCn0YLQvtCx0Ysg0LjQt9Cx0LXQttCw0YLRjCDQvdGD0LbQvdC+INC30LDQtNCw0YLRjCDQvtGC0LzQtdGC0LrRgyDQv9GA0L7Qv9GD0YnQtdC90L3Ri9GFINC30L3QsNGH0LXQvdC40LksINGN0YLQviDQsiDRgtC+0Lwg0YfQuNGB0LvQtSDQvNC+0LbQtdGCINCx0YvRgtGMINCy0LXQutGC0L7RgCDQt9C90LDRh9C10L3QuNC5DQpgYGB7cn0NCiNuYS5zdHJpbmdzID0gYygiTkEiLCAiTm90IGF2YWlsYWJsZSIsICJNaXNzaW5nIikgIA0KYGBgDQoqKiDQuNC3LdC30LAg0L3QtdCy0LXRgNC90L4g0YPQutCw0LfQsNC90L3Ri9GFINGA0LDQt9C00LXQu9C40YLQtdC70Y8sINC00LXRgdGP0YLQuNGH0L3QvtCz0L4g0LfQvdCw0LrQsCANCmBgYHtyfQ0KI3NlcCA9ICIsIiwgZGVjID0gIi4iDQpgYGANCk4uQiEq0JIg0YDRg9GB0YHQvtC60L7QuSDRgtGA0LDQtNC40YbQuNC4INGH0LDRgdGC0L4g0LLQvNC10YHRgtC+INC00LXRgdGP0YLQuNGH0L3QvtC5INGC0L7Rh9C60Lgg0LjRgdC/0L7Qu9GM0LfRg9C10YLRgdGPINC30LDQv9GP0YLQsNGPLCDQutC+0YLQvtGA0LDRjyDQsiAuY3N2INC+0LHRi9GH0L3QviDQvtC/0YDQtdC00LXQu9GP0LXRgiDRgNCw0LfQtNC10LvQuNGC0LXQu9GMINC30L3QsNGH0LXQvdC40LkgLSDQvtGC0YHRjtC00LAg0L/RgNC+0LHQu9C10LzRiyoNCg0KKiog0LjQty3Qt9CwINC60LDQstGL0YfQtdC6LCDRgdC+0L/RgNC+0LLQvtC00LjRgtC10LvRjNC90L7Qs9C+INGC0LXQutGB0YLQsCDQuNC70Lgg0LrQvtC80LzQtdC90YLQsNGA0LjQtdCyIA0KYGBge3J9DQojcXVvdGUsIGNvbW1lbnQuY2hhciwgc2tpcA0KYGBgDQoqIEPRgtGA0L7QutC+0LLRi9C1INGC0LjQv9GLINGB0YLQsNC90L7QstGP0YLRgdGPINGE0LDQutGC0L7RgNCw0LzQuCDQu9C40LHQviDQvdCw0L7QsdC+0YDQvtGCICANCmBgYHtyfQ0KI2FzLmNoYXJhY3RlciwgYXMuZmFjdG9yDQpgYGANCiog0KLQuNC/ICLQtNCw0YLQsC/QstGA0LXQvNGPIiDQvtGB0YLQsNC10YLRgdGPINGB0YLRgNC+0LrQvtCy0YvQvA0KYGBge3J9DQojYXMuUE9TSVhjdA0KI2FzLlBPU0lYbHQNCiNhcy5EYXRlDQpgYGANCg0KIyMjINCa0LDQuiDRg9Cx0LXQtNC40YLRjNGB0Y8sINGH0YLQviDQstGB0LUg0LIg0L/QvtGA0Y/QtNC60LU/IA0K0JLRgNGP0LQg0LvQuCDQsdGD0LTQtdC8INGB0LzQvtGC0YDQtdGC0Ywg0LLQtdGB0Ywg0LzQsNGB0YHQuNCyINC00LDQvdC90YvRhSwg0YHRgtC+0LjRgiDQv9GA0L7Qs9C90LDRgtGMINGH0LXRgNC10Lcg0YDRj9C0INGE0YPQvdC60YbQuNC5OiBzdHIsIHN1bW1hcnksIGhlYWQsIHRhaWwNCg0KDQojIyDQoNCw0LHQvtGC0LAg0YEg0L/QtdGA0LXQvNC10L3QvdGL0LzQuA0KKiDQpNGD0L3QutGG0LjQuCAqY29tcGxldGUuY2FzZXMqINC4ICpuYS5vbWl0KiDQtNC70Y8g0YPQtNCw0LvQtdC90LjRjyDQvdCw0LHQu9GO0LTQtdC90LjQuSDRgSDQv9GA0L7Qv9GD0YnQtdC90L3Ri9C80Lgg0LfQvdCw0YfQtdC90LjRj9C80Lg6DQpgYGB7cn0NCiNkZltjb21wbGV0ZS5jYXNlcyhkZiksIF0gDQojINC40LvQuA0KI25hLm9taXQoZGYpDQpgYGANCiog0JfQsNC80LXQvdCwIE5BINC90LAg0L3QtdC60L7RgtC+0YDRi9C1INC30L3QsNGH0LXQvdC40Y8g0LzQvtC20LXRgiDQsdGL0YLRjCDQv9C+0YLQtdC90YbQuNCw0LvRjNC90L4g0L7Qv9Cw0YHQvdC+0Lk6ICANCioqINC30LDQv9C+0LvQvdC10L3QuNC1INGB0YDQtdC00L3QuNC8INC/0L4g0LrQvtC70L7QvdC60LUg0LzQvtC20LXRgiDQstC90L7RgdC40YLRjCDRgdC80LXRidC10L3QuNC1INCyINC00LDQvdC90YvQtSAgDQoqKiDQt9Cw0L/QvtC70L3QtdC90LjQtSDQvdGD0LvRj9C80Lgg0LIg0LHQvtC70YzRiNC40L3RgdGC0LLQtSDRgdC70YPRh9Cw0LXQsiDQstC+0L7QsdGJ0LUg0L3QtdC60L7RgNGA0LXQutGC0L3QviEgIA0KKiDQodC+0LfQtNCw0L3QuNC1LCDQuNC30LzQtdC90LXQvdC40LUg0Lgg0YPQtNCw0LvQtdC90LjQtSDQv9C10YDQtdC80LXQvdC90YvRhSDQstGL0L/QvtC70L3Rj9C10YLRgdGPINC60L7QvdGB0YLRgNGD0LrRhtC40Y/QvNC4OiANCmBgYHtyfQ0KaGVscCgpDQojZGYkbmV3X3ZhciA8LSA8Li4uPiAgDQojZGYkb2xkX3ZhciA8LSBmKGRmJG9sZF92YXIpICANCiNkZiRvbGRfdmFyIDwtIE5VTEwgIA0KYGBgDQogIA0KKiDQmtGA0L7QvNC1INGC0L7Qs9C+LCDQtNC70Y8g0YDQsNCx0L7RgtGLINGB0YDQsNC30YMg0YEg0LHQvtC70YzRiNC40Lwg0LrQvtC70LjRh9C10YHRgtCy0L7QvCDQv9C10YDQtdC80LXQvdC90YvRhSDQvNC+0LbQvdC+INCy0L7RgdC/0L7Qu9GM0LfQvtCy0LDRgtGM0YHRjyDRhNGD0L3QutGG0LjQtdC5IHdpdGhpbiAgDQogIA0KIyDQrdC60YHQv9C+0YDRgg0K0JTQvtC/0YPRgdGC0LjQvCwg0LfQsNCy0LXRgNGI0LjQu9C4INC/0YDQtdC00L7QsdGA0LDQsdC+0YLQutGDINC00LDQvdC90YvRhSDQuCDRhdC+0YLQuNC8INC30LDQv9C40YHQsNGC0Ywg0YTQsNC50Lsg0YEg0L7Rh9C40YnQtdC90L3Ri9C80Lgg0LTQsNC90L3Ri9C80LggIA0KKiAqd3JpdGUudGFibGUqLCAqd3JpdGUuY3N2KiDQuCAqd3JpdGUuY3N2MiogLSDQv9C+0YfRgtC4INC40LTQtdC90YLQuNGH0L3Ri9C1INGE0YPQvdC60YbQuNC4INC40LzQv9C+0L7RgNGC0LAgIA0KKiDQldGB0LvQuCDQvNCw0YHRgdC40LIg0LTQsNC90L3Ri9GFINC00L7RgdGC0LDRgtC+0YfQvdC+INCx0L7Qu9GM0YjQvtC5LCDRgtC+INC70YPRh9GI0LUg0LLRgdC10LPQviDQvtGC0LTQtdC70Y/RgtGMINGN0YLQsNC/INC/0YDQtdC+0LHRgNCw0LHQvtGC0LrQuDogIA0KKiog0L7RgtC00LXQu9GM0L3Ri9C5INGE0LDQudC7IC5SINC00L4g0L7QsdGA0LDQsdC+0YLQutC4ICANCioqINC+0YLQtNC10LvRjNC90YvQuSDRhNCw0LnQuyDRgSDQv9GA0LXQvtC00L7QsdGA0LDQsdC+0YLQsNC90L3Ri9C80LggKCoi0YfQuNGB0YLRi9C80LgiKikg0LTQsNC90L3Ri9C80LggLSDQvdCwINC60L7RgtC+0YDQvtC8INC80L7QttC90L4g0YHQv9GD0YHQutCw0YLRjCDQsNC70LPQvtGA0LjRgtC80YssINGB0L7RhdGA0LDQvdGP0YLRjCDRgdC60YDQuNC/0YIg0L7QsdGA0LDQsdC+0YLQutC4INC4INC90LUg0YLRgNCw0YLQuNGC0Ywg0LrQsNC20LTRi9C5INGA0LDQtyDQtNC+0L/QvtC70L3QuNGC0LXQu9GM0L3Ri9C1INGD0YHQuNC70LjRjyDQvdCwINC+0LHRgNCw0LHQvtGC0LrRgy4g0KLQsNC6INC20LUg0Y3RgtC+INGD0LTQvtCx0L3Qviwg0LXRgdC70Lgg0LjRgdGF0L7QtNC90LDRjyDRgtCw0LHQu9C40YbQsCDQvNC10L3Rj9C10YLRgdGPINC40LvQuCDQtNC+0L/QvtC70L3Rj9C10YLRgdGPICjQvdCw0L/RgNC40LzQtdGALCDQv9GA0LjRgdGL0LvQsNGO0YIg0LLRgtC+0YDRg9GOINGH0LDRgdGC0Ywg0LTQsNC90L3Ri9GFKQ0KDQojIyDQn9GA0LjQvNC10YAg0LTQsNGC0LAg0YTRgNC10LnQvNCwINC4INC10LPQviDQsNC90LDQu9C40LfQsA0KICDQktC40LfRg9Cw0LvRjNC90LDRjyDQuNC90YHQv9C10LrRhtC40Y8g0LTQsNC90L3Ri9GFIC0tINCy0LDQttC90YvQuSDRjdGC0LDQvyDQv9GA0LXQtNCy0LDRgNC40YLQtdC70YzQvdC+0LPQviDQsNC90LDQu9C40LfQsCDQtNCw0L3QvdGL0YUuINCe0L3QsCDQv9C+0LfQstC+0LvRj9C10YIg0LfQsNC80LXRgtC40YLRjCDQvtGH0LXQstC40LTQvdGL0LUg0L3QtdGB0L7QvtGC0LLQtdGC0YHRgtCy0LjRjyDQuCDQsNC90L7QvNCw0LvQuNC4INCyINC00LDQvdC90YvRhSwg0LgsINGH0YLQviDQvdC10LzQsNC70L7QstCw0LbQvdC+LCAi0L/QvtGH0YPQstGB0YLQstC+0LLQsNGC0YwiINGB0YLRgNGD0LrRgtGD0YDRgyDQtNCw0YLQsCDRhNGA0LXQudC80LAuINCa0LDQutC40LUg0LIg0L3RkdC8INC10YHRgtGMINC/0LXRgNC10LzQtdC90L3Ri9C1PyDQp9GC0L4g0L7QvdC4INC+0LfQvdCw0YfQsNGO0YI/INCSINC60LDQutC40YUg0LXQtNC40L3QuNGG0LDRhSDQuNC30LzQtdGA0Y/RjtGC0YHRjz8g0JrQsNC60L7QuSDRgyDQvdC40YUg0LTQuNCw0L/QsNC30L7QvSDQt9C90LDRh9C10L3QuNC5PyANCmBgYHtyfQ0KP3F1YWtlcw0Kc3RyKHF1YWtlcykNCmBgYA0KYGBge3J9DQpzdW1tYXJ5KHF1YWtlcykNCmBgYA0KDQpgYGB7cn0NCmhlYWQocXVha2VzKQ0KYGBgDQpgYGB7cn0NCnRhaWwocXVha2VzKQ0KYGBgDQoNCg0KIyMg0JzQsNGB0YHQuNCyINC00LDQvdC90YvRhSAo0YDQtdCw0LvRjNC90YvQuSkNCtCX0LDQs9GA0YPQt9C40Lwg0YDQtdCw0LvRjNC90YvQuSDQvNCw0YHRgdC40LIg0YEg0LTQsNC90L3Ri9C80Lgg0LTQu9GPINGA0LDQsdC+0YLRiw0KYGBge3J9DQo/cmVhZC5jc3YNCmF2aWFuIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9Ub255L0Rlc2t0b3AvUi9NaW5lL2F2aWFuSGFiaXRhdC5jc3YiKQ0KYGBgDQrQn9GA0L7Qs9C70Y/QtNC40LwsINGH0YLQviDQvtC9INC40Lcg0YHQtdCx0Y8g0L/RgNC10LTRgdGC0LDQstC70Y/QtdGCLiDQl9Cw0L7QtNC90L4g0L/RgNC+0LLQtdGA0Y/QtdC8LCDRh9GC0L7QsdGLINCy0YHQtSDRgtC40L/RiyDQtNCw0L3QvdGL0YUg0YHRh9C40YLQsNC70LjRgdGMINC/0YDQsNCy0LjQu9GM0L3Qvi4NCmBgYHtyfQ0KaGVhZChhdmlhbikNCmBgYA0K0JLQuNC00LjQvCwg0YfRgtC+INCy0YHQtSDQtNCw0L3QvdGL0LUg0YHRh9C40YLQsNC70LjRgdGMINC/0YDQsNCy0LjQu9GM0L3Qvi4gDQpgYGB7cn0NCnN0cihhdmlhbikNCmBgYA0K0J/QvtGB0YfQuNGC0LDQtdC8INCx0LDQt9C+0LLRi9C1INC+0L/QuNGB0LDRgtC10LvRjNC90YvQtSDRgdGC0LDRgtC40YHRgtC40LrQuC4g0JjRgdGF0L7QtNGPINC40Lcg0Y3RgtC+0LPQviDQvNC+0LbQvdC+INGB0LTQtdC70LDRgtGMINCy0LjQt9GD0LDQu9GM0L3Rg9GOINC+0YbQtdC90LrRgyDQtNCw0L3QvdGL0YUuINCi0LDQutC40Lwg0L7QsdGA0LDQt9C+0LwsINGB0YDQsNC30YMg0LzQvtC20L3QviDQvtCx0L3QsNGA0YPQttC40YLRjCDQsNC90L7QvNCw0LvQuNC4LCDQvdCw0L/RgNC40LzQtdGALCDQtdGB0LvQuCDQtdGB0YLRjCDQv9C10YDQtdC80LXQvdC90LDRjywg0L7RgtCy0LXRh9Cw0Y7RidCw0Y8g0LfQsCDQv9GA0L7RhtC10L3RgtGLLCDRgtC+INGB0YDQsNC30YMg0L/QvtC90LjQvNCw0LXQvCwg0YfRgtC+INC80LjQvdC40LzRg9C8INC90LUg0LzQvtC20LXRgiDQsdGL0YLRjCDQvNC10L3RjNGI0LUgMCwg0LAg0LzQsNC60YHQuNC80YPQvCAtINCx0L7Qu9GM0YjQtSAxMDANCmBgYHtyfQ0Kc3VtbWFyeShhdmlhbikNCmBgYA0K0J/RgNC10L7QtNC+0LHRgNCw0LHQvtGC0LrQsCDQtNCw0L3QvdGL0YUg0LrRgNCw0LnQvdC1INCy0LDQttC90YvQuSDRjdGC0LDQvy4g0JjQt9Cy0LXRgdGC0L3Ri9C5INC/0YDQuNC90YbQuNC/ICoqR0lHTyoqOiAqIkdhcmJhZ2UgaW4gLSBHYXJiYWdlIG91dCIqICANCg0KIyMjINCe0YLQu9Cw0LLQu9C40LLQsNC10Lwg0L7RiNC40LHQutC4INC00LDQu9GM0YjQtQ0K0J3QtSDQstGB0LXQs9C00LAg0LzQvtC20L3QviDQvtGC0LvQvtCy0LjRgtGMINCy0YHQtSDQvtGI0LjQsdC60Lgg0YHRh9C40YLRi9Cy0LDQvdC40Y8g0LTQsNC90L3Ri9GFINGBINC/0L7QvNC+0YnRjNGOINGE0YPQvdC60YbQuNC5IHN0ciwgc3VtbWFyeSDQuCBoZWFkICANCiAgDQogIA0KKirQldGB0YLRjCDQu9C4INC/0YDQvtC/0YPRidC10L3QvdGL0LUg0LfQvdCw0YfQtdC90LjRjz8qKiANCtCX0L3QsNC6ICIhIiAtINGN0YLQviDQu9C+0LPQuNGH0LXRgdC60LjQuSDQvtC/0LXRgNCw0YLQvtGALCDQutC+0YLQvtGA0YvQuSDQvtCx0L7Qt9C90LDQtdGH0LDQtdGCIE5PVC4g0KIu0LUuINGE0LDQutGC0LjRh9C10YHQutC4INC80Ysg0L/RgNC+0LLQtdGA0Y/QtdC8LCDQtdGB0YLRjCDQu9C4INCd0JUg0LfQsNC60L7QvdGH0LXQvdC90YvQtSDQvdCw0LHQu9GO0LTQtdC90LjRjw0KYGBge3J9DQphbnkoIWNvbXBsZXRlLmNhc2VzKGF2aWFuKSkNCmBgYA0K0LjQu9C4INCx0L7Qu9C10LUg0L/RgNGP0LzQvtC5INC30LDQv9GA0L7RgToNCmBgYHtyfQ0KYW55KGlzLm5hKGF2aWFuKSkNCmBgYA0K0J/RgNC+0L/Rg9GB0LrQvtCyINC90LXRgiAtINCy0L7Qv9GA0L7RgSDQvtGC0L/QsNC00LDQtdGCICANCiAgDQoqKk4uQiEqKiDQmtC+0L3RgdGC0YDRg9C60YbQuNC4INCy0LjQtNCwIGFueShpcy5uYSh4KSkg0LjQu9C4IGFueSghY29tcGxldGUuY2FzZXMoZGF0YSkpINC/0L7RgdC70LUg0LLQtdGA0YHQuNC4IFIgMy4xLjAuINC/0YDQuNC30LLQsNC90LAg0LfQsNC80LXQvdC40YLRjCDQutC+0L3RgdGC0YDRg9C60YbQuNGPICphbnlOQSouINCg0LDQsdC+0YLQsNC10YIg0L7QvdCwINCx0YvRgdGC0YDQtdC1LCDRgNCw0LfRg9C80LXQtdGC0YHRjy4g0J/RgNC40Y/RgtC90L4g0Lgg0YLQviwg0YfRgtC+INC+0L3QsCDRgNCw0LHQvtGC0LDQtdGCINGB0L4g0LLQu9C+0LbQtdC90L3Ri9C80Lgg0YHQv9C40YHQutCw0LzQuCAo0L3Rg9C20L3QviDRg9C60LDQt9Cw0YLRjCByZWN1cnNpdmUgPSBUUlVFKSAgDQrQp9GC0L7QsdGLINC+0YLRgdC70LXQttC40LLQsNGC0Ywg0YLQsNC60YPRjiDQuNC90YTRgyDQv9C+0LvQtdC30L3QviDRh9C40YLQsNGC0YwgaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvc3JjL2Jhc2UvTkVXUyDQv9C+0YHQu9C1INC+0YfQtdGA0LXQtNC90L7Qs9C+INGA0LXQu9C40LfQsCDQv9C+0LvQtdC30L3Qvg0KDQoqKtCf0YDQvtCy0LXRgNC40Lwg0LTQuNCw0L/QsNC30L7QvSDQv9GA0L7RhtC10L3RgtC+0LIqKg0K0JfQvdCw0LogInwiIC0g0Y3RgtC+INC70L7Qs9C40YfQtdGB0LrQuNC5INC+0L/QtdGA0LDRgtC+0YAsINC+0LHQvtC30L3QsNGH0LDRjtGJ0LjQuSBPUg0KYGBge3J9DQphbnkoYXZpYW4kUERCIDwgMCB8IGF2aWFuJFBEQiA+IDEwMCkNCmBgYA0K0J/QtdGA0LXQvNC10L3QvdCw0Y8gUERCLCDQvtGC0LLQtdGH0LDRjtGJ0LDRjyDQt9CwICUg0L/QvtC60YDRi9GC0LjRjywg0L/RgNC+0YjQu9CwINC/0YDQvtCy0LXRgNC60YMgIA0KICANCiAgICANCioq0JPQvtGC0L7QstC40Lwg0YTRg9C90LrRhtC40Y4g0LTQu9GPINCy0YvQv9C+0LvQvdC10L3QuNGPINC/0L7QstGC0L7RgNGP0Y7RidC40YXRgdGPINC+0L/QtdGA0LDRhtC40LkqKiAgDQrQndC1INCy0YHQtdCz0LTQsCDRg9C00L7QsdC90L4g0L/RgNC+0LLQtdGA0Y/RgtGMINCy0YHQtSDQv9C10YDQtdC80LXQvdC90YvQtSDQv9C+0LTRgNGP0LQuINCV0YHRgtGMINC+0YLQu9Cw0LbQtdC90L3Ri9C5INC80LXRhdCw0L3QuNC30LwsINC60L7Qs9C00LAg0L/QvtCy0YLQvtGA0Y/RjtGJ0LjQtdGB0Y8g0LTQtdC50YHRgtCy0LjRjyDQt9Cw0LrQu9GO0YfQsNC10Lwg0LIg0YTRg9C90LrRhtC40Y4uDQpgYGB7cn0NCmNoZWNrX3BlcmNlbnRfcmFuZ2UgPC0gZnVuY3Rpb24oeCkgew0KICBhbnkoeCA8IDAgfCB4ID4gMTAwKQ0KfQ0KYGBgDQrQn9GA0L7QstC10YDRj9C10LwgUERCDQpgYGB7cn0NCmNoZWNrX3BlcmNlbnRfcmFuZ2UoYXZpYW4kUERCKQ0KYGBgDQpgYGB7cn0NCmNoZWNrX3BlcmNlbnRfcmFuZ2UoYXZpYW4kUFcpDQpgYGANCtCU0L7Qv9GD0YHRgtC40LwsINCy0YHQtSDQv9GA0L7QstC10YDQuNC70LguINCS0YHQtSDQsiDQv9C+0YDRj9C00LrQtQ0KDQojIyMg0J/RgNC10L7QsdGA0LDQt9C+0LLQsNC90LjQtSDQv9C10YDQtdC80LXQvdC90YvRhSAgDQrQndCw0YEg0LzQvtCz0YPRgiDQstC+0LvQvdC+0LLQsNGC0YwsINGA0LDQt9C90YvQtSDQstC+0L/RgNC+0YHRiyDQv9GA0LXQvtCx0YDQsNC30L7QstCw0L3QuNGPLiDQkiDQt9Cw0LTQsNGH0Lgg0L/RgNC10L7QsdGA0LDQt9C+0LLQsNC90LjRjyDQv9C10YDQtdC80LXQvdC90YvRhSDQvNC+0LbQtdGCINCy0YXQvtC00LjRgtGMLCDQvdCw0L/RgNC80LjQvNC10YA6ICANCiog0LjQt9C80LXQvdC10L3QuNC1INC80LXRgCDQuNC30LzQtdGA0LXQvdC40Y8gKNC90LDQv9GA0LjQvNC10YAsINC40Lcg0LrQsyDQsiDQsykgIA0KKiDRgdC+0LfQtNCw0L3QuNC1INC90L7QstGL0YUg0L/QtdGA0LXQvNC10L3QvdGL0YUsINC90LAg0L7RgdC90L7QstC1INCy0YvRh9C40YHQu9C10L3QuNGPINC40Lcg0LjQvNC10Y7RidC40YXRgdGPICjQvdCw0L/RgNC40LzQtdGALCDQv9C+0LTRgdGH0LXRgiDQmNCc0KIg0L3QsCDQvtGB0L3QvtCy0LUg0L/QtdGA0LXQvNC10L3QvdGL0YUg0YDQvtGB0YLQsCDQuCDQstC10YHQsCkgIA0KKiDQuCDQtNGALiAgDQogIA0K0JIg0LTQsNGC0LAg0YTRgNC10LnQvNC1IGF2aWFuINGDINC90LDRgSDQtdGB0YLRjCDQvtGC0LTQtdC70YzQvdGL0LUg0L/QtdGA0LXQvNC10L3QvdGL0LUsINGF0LDRgNCw0LrRgtC10YDQuNC30YPRjtGJ0LjQtSDQv9GA0L7RhtC10L3RgiDQv9C+0LrRgNGL0YLQuNGPINGA0LDQt9C90YvRhSDQstC40LTQvtCyLiDQndCw0L/RgNC40LzQtdGALCDQvdCw0YEg0LjQvdGC0LXRgNC10YHRg9C10YIsINC60LDQutC+0Lkg0L7QsdGJ0LjQuSDQv9GA0L7RhtC10L3RgiDQv9C+0LrRgNGL0YLQuNGPINC/0L4g0LLRgdC10Lwg0LjQvNC10Y7RidC40LzRgdGPINCy0LjQtNCw0LwuINCR0YPQtNC10YIg0LvQuCDQvtC9INCx0LvQuNC30L7QuiDQuiAxMDAlPyDQuNC70Lgg0LIg0LrQsNC60L7QvC3RgtC+INC00LjQsNC/0LDQt9C+0L3QtT8g0K3RgtC+INC+0YHQvNGL0YHQu9C10L3QvdGL0Lkg0LLQvtC/0YDQvtGBLiAgDQrQlNC70Y8g0Y3RgtC+0LPQviDQvdCw0Lwg0L3Rg9C20L3QvjogIA0KKiDRgdC+0LfQtNCw0YLRjCDQvtGC0LTQtdC70YzQvdGD0Y4g0L/QtdGA0LXQvNC10L3QvdGD0Y4gIA0KKiDRgdC70L7QttC40YLRjCDQsiDQvdC+0LLRg9GOINC/0LXRgNC10LzQtdC90L3Rg9GOINCy0YHQtSDQuNC80LXRjtGJ0LjQtdGB0Y8g0L/RgNC+0YbQtdC90YLRiyAgDQogIA0KKirQkCDQutCw0LrQuNC1INC/0LXRgNC10LzQtdC90L3Ri9C1INGDINC90LDRgSDQstC+0L7QsdGJ0LUg0LXRgdGC0Yw/KioNCtCf0L7RgdC80L7RgtGA0LjQvCwg0LrQsNC60LjQtSDQv9C10YDQvNC10L3QvdGL0LUg0LfQsNC/0LjRgdCw0L3RiyDQsiDQtNCw0YLQsCDRhNGA0LXQudC80LUNCmBgYHtyfQ0KbmFtZXMoYXZpYW4pDQpgYGANCtCi0LXQv9C10YDRjCDQvdCw0YfQuNC90LDQtdC8INC/0LjRgdCw0YLRjCDQutC+0LQsINC60L7RgtC+0YDRi9C5INGB0LTQtdC70LDQtdGCLCDRh9GC0L4g0LzRiyDRhdC+0YLQuNC8DQpgYGB7cn0NCiMg0JzQvtC20LXQvCDQstGL0LHRgNC+0YHQuNGC0Ywg0L/QtdGA0LLRi9C1INGH0LXRgtGL0YDQtSDQv9C10YDQtdC80LXQvdC90YvQtSDRgdGA0LDQt9GDDQojINCU0LDQu9GM0YjQtSDQstC40LTQuNC8LCDRh9GC0L4g0LrQsNC20LTQsNGPIDIt0Y8g0L/QtdGA0LXQvNC10L3QvdCw0Y8g0L3QsNGBINC90LUg0LjQvdGC0LXRgNC10YHRg9C10YIsINC/0L7RjdGC0L7QvNGDINC80L7QttC10Lwg0LLQvtGB0L/QvtC70YzQt9C+0LLQsNGC0YzRgdGPINC60L7QvdGB0YLRgNGD0LrRhtC40LXQuSBjKFQsRikNCmNvdmVyYWdlX3ZhcmlhYmxlcyA8LSBuYW1lcyhhdmlhbilbLSgxOjQpXVtjKFQsIEYpXQ0KYGBgDQrQn9GA0Lgg0L/QvtC80L7RidC4INGC0LDQutC+0Lkg0LrQvtC90YHRgtGA0YPQutGG0LjQuCDQstC30Y/Qu9C4INGC0L7Qu9GM0LrQviDRgtC1INGC0LjQv9GLINC/0LXRgNC10LzQtdC90L3Ri9GFLCDQutC+0YLQvtGA0YvQtSDRgdC+0LTQtdGA0LbQsNGCINCyINGB0LXQsdC1INGC0L7Qu9GM0LrQviDQv9GA0L7RhtC10L3RgtGLLiAgDQogIA0KKipOLkIhKiogKirQlNCy0LUg0LrQstCw0LTRgNCw0YLQvdGL0LUg0YHQutC+0LHQutC4INC/0L7QtNGA0Y/QtCoqICANCtCa0L7Qs9C00LAg0LTQvtC/0YPRgdGC0LjQvNC+INC/0YDQuNC80LXQvdGP0YLRjCDQtNCy0LUg0L/QsNGA0Ysg0LrQstCw0LTRgNCw0YLQvdGL0YUg0YHQutC+0LHQvtC6INC/0YDQuCDQuNC90LTQtdC60YHQsNGG0LjQuD8gIA0K0J/RgNC40LzQtdC90Y/RgtGMINC80L7QttC90L4g0LLRgdC10LPQtNCwLiDQkiDRgdC70YPRh9Cw0LUgeFsxXVszXSDQstGLINCx0LXRgNC10YLQtSDQv9C10YDQstGL0Lkg0Y3Qu9C10LzQtdC90YIsINC4INCyINGN0YLQvtC8INCy0LXQutGC0L7RgNC1INC00LvQuNC90Ysg0L7QtNC40L0g0L/Ri9GC0LDQtdGC0LXRgdGMINC+0LHRgNCw0YLQuNGC0YzRgdGPINC/0L4g0YLRgNC10YLRjNC10LzRgyDQuNC90LTQtdC60YHRgywg0YfRgtC+IE5VTEwuICANCiAgDQrQp9GC0L7QsdGLINC/0L7QvdGP0YLRjCwg0LrQsNC6INGA0LDQsdC+0YLQsNC10YIg0LzQvtC20L3QviDQv9C+0YHQvNC+0YLRgNC10YLRjCDQvdCwINC00YDRg9Cz0LjQtSDQstCw0YDQuNCw0L3RgtGLDQpgYGB7cn0NCiN4WzE6M11bM10sIHhbYygxLDIsNCldWzE6Ml1bMV0NCmBgYA0KDQoNCmBgYHtyfQ0KY292ZXJhZ2VfdmFyaWFibGVzDQpgYGANCtCn0YLQvtCx0Ysg0YLQtdC/0LXRgNGMINGB0L7Qt9C00LDRgtGMINC90L7QstGD0Y4g0L/QtdGA0LXQvNC10L3QvdGD0Y4g0L7QsdGA0LDRgtC40LzRgdGPINC6INC40LzQtdC90Lgg0YEg0L/QvtC80L7RidGM0Y4g0LfQvdCw0LrQsCAiKiQqIiwg0LrQvtGC0L7RgNC+0LPQviDQsiDQtNCw0YLQsCDRhNGA0LXQudC80LUg0L/QvtC60LAg0L3QtdGCDQpgYGB7cn0NCiMgcm93U3VtcyhhdmlhblsgLCAi0LrQvtC70L7QvdC60Lgg0YEg0L3Rg9C20L3Ri9C80Lgg0L/QtdGA0LXQvNC10L3QvdGL0LzQuCJdKSDQv9C+0YHRh9C40YLQsNC10YIg0YHRg9C80LzRgw0KYXZpYW4kdG90YWxfY292ZXJhZ2UgPC0gcm93U3VtcyhhdmlhblsgLCBjb3ZlcmFnZV92YXJpYWJsZXNdKQ0KYGBgDQrQn9C+0YHQvNC+0YLRgNC40LwsINGH0YLQviDRgtCw0LrQsNGPINC/0LXRgNC10LzQtdC90L3QsNGPINC10YHRgtGMINGC0LXQv9C10YDRjCDQsiDQtNCw0YLQsCDRhNGA0LXQudC80LUNCmBgYHtyfQ0KaGVhZChhdmlhbiR0b3RhbF9jb3ZlcmFnZSkNCmBgYA0KYGBge3J9DQpoZWFkKGF2aWFuKQ0KYGBgDQoNCtCi0LXQv9C10YDRjCDQvNC+0LbQtdGCINC+0YbQtdC90LjRgtGMINGA0LDQt9Cx0YDQvmMg0L/QviDRjdGC0L7QuSDQv9C10YDQvNC10L3QvdC+0LkNCmBgYHtyfQ0Kc3VtbWFyeShhdmlhbiR0b3RhbF9jb3ZlcmFnZSkNCmBgYA0K0JLQuNC00LjQvCwg0YfRgtC+LCDQvdCw0L/RgNC40LzQtdGALCDQvNCw0LrRgdC40LzQsNC70YzQvdC+0LUg0L/QvtC60YDRi9GC0LjQtSDQstC40LTQvtC8INGB0L7RgdGC0LDQstC70Y/QtdGCIC0gMTclLCDRh9GC0L4g0L3QtSDQvtGH0LXQvdGMINC80L3QvtCz0L4uICANCg0K0JzQvtC20LXQvCDQv9C+0YHQvNC+0YLRgNC10YLRjCDQstGB0YLRgNC10YfQsNC10LzQvtGB0YLRjCDRgtC10YUg0LjQu9C4INC40L3Ri9GFINC30L3QsNGH0LXQvdC40Lkg0L/QviDQv9C10YDQtdC80LXQvdC90L7QuQ0KYGBge3J9DQp0YWJsZShhdmlhbiR0b3RhbF9jb3ZlcmFnZSkNCmBgYA0K0JAg0L3QsCDQvtGB0L3QvtCy0LUg0Y3RgtC+0LPQviDQv9C+0YHRgtGA0L7QuNGC0Ywg0LHRi9GB0YDRi9C5INCz0YDQsNGE0LjQuiwg0L3QsNC/0YDQuNC80LXRgDoNCmBgYHtyfQ0KcGxvdCh0YWJsZShhdmlhbiR0b3RhbF9jb3ZlcmFnZSksDQogICAgIG1haW4gPSAi0JPQuNGB0YLQvtCz0YDQsNC80LzQsCDQvtCx0YnQtdC5INC/0LvQvtGJ0LDQtNC4INC/0L7QutGA0YvRgtC40Y8g0LLQuNC00LDQvNC4IiwNCiAgICAgdHlwZSA9ICJoIg0KICAgICApDQpgYGANCtCT0LjRgdGC0L7Qs9GA0LDQvNGDINC80L7QttC90L4g0L/QvtGB0YLRgNC+0LjRgtGMINC4INGBINC/0L7QvNC+0YnRjNGOINGB0L/QtdGG0LjQsNC70YzQvdC+0Lkg0YTRg9C90LrRhtC40LgNCmBgYHtyfQ0KaGlzdChhdmlhbiR0b3RhbF9jb3ZlcmFnZSkNCmBgYA0K0JzQvtC20L3QviDQv9C+0L/RgNC+0LHQvtCy0LDRgtGMINGA0LDQt9C00LXQu9C40YLRjCDQs9GA0LDRhNC40LjQutC4INGA0LDRgdC/0YDQtdC00LXQu9C10L3QuNGPINCyINC30LDQstC40YHQuNC80L7RgdGC0Lgg0L7RgiDQvNC10YHRgtCwINGB0LHQvtGA0LAg0LjQvdGE0L7RgNC80LDRhtC40LguINCU0LvRjyDQvdCw0YfQsNC70LAg0LLRi9GP0YHQvdGOLCDQvtGC0LrRg9C00LAg0LLQvtC+0LHRidC1INGB0L7QsdC40YDQsNC70Lgg0LjQvdGE0L7RgNC80LDRhtC40Y4NCmBgYHtyfQ0KdGFibGUoYXZpYW4kU2l0ZSkNCmBgYA0K0JzQvtCz0YMg0L/QvtC/0YDQvtCx0L7QstCw0YLRjCDRgdGA0LXQtNC4INGN0YLQvtCz0L4g0LzRj9GB0LAg0LLRi9GH0LvQtdC90LjRgtGMICoq0LjQvdC00LXQutGB0YsqKiDRgdGC0YDQvtC6LCDRgdC+0LTQtdGA0LbQsNGJ0LjQtSDRh9Cw0YHRgtC40YfQvdGL0LUg0YHQvtCy0L/QsNC00LXQvdC40Y8sINGBINC/0L7QvNC+0YnRjNGOINGE0YPQvdC60YbQuNC4ICpncmVwKg0KYGBge3J9DQpncmVwKCJCdW5rZXJIaWxsIiwgYXZpYW4kU2l0ZSkNCmBgYA0K0KLQtdC/0LXRgNGMINGC0Y3QudCx0LvQvtC8INGB0L3QvtCy0LAg0YHQvNC+0YLRgNGOLCDRh9GC0L4g0Y8g0L3QsNGF0L7QtNGDINGC0LDQuiDRgtC+0LvRjNC60L4g0LjQvdGC0LXRgNC10YHRg9GO0YnRg9GOINC80LXQvdGPINGB0YLRgNC+0LrRgw0KYGBge3J9DQp0YWJsZShhdmlhbiRTaXRlW2dyZXAoIkJ1bmtlckhpbGwiLCBhdmlhbiRTaXRlKV0pDQpgYGANCtCf0L7Qv9GA0L7QsdGD0Y4g0L/QvtGB0YLRgNC+0LjRgtGMINCz0LjRgdGC0L7Qs9GA0LDQvNGDINC/0LvQvtGJ0LDQtNC4INC/0L7QutGA0YvRgtC40Y8g0LTQu9GPIEJ1bmtlciBIaWxsLWENCmBgYHtyfQ0KaGlzdChhdmlhbiR0b3RhbF9jb3ZlcmFnZVtncmVwKCJCdW5rZXJIaWxsIiwgYXZpYW4kU2l0ZSldKQ0KYGBgDQrQotC10L/QtdGA0YwsINC90LDQv9GA0LjQvNC10YAsINC00LvRjyBMaXZpbmdzdG9uIENyZWVrDQpgYGB7cn0NCmhpc3QoYXZpYW4kdG90YWxfY292ZXJhZ2VbZ3JlcCgiTGl2aW5nc3RvbkNyZWVrIiwgYXZpYW4kU2l0ZSldKQ0KYGBgDQrQldGJ0LUg0LrQsNC60L7QtS3RgtC+INCy0YDQtdC80Y8g0L3QsNC30LDQtCDQvNGLINC90LjRh9C10LPQviDQvdC1INC80L7Qs9C70Lgg0YHQutCw0LfQsNGC0Ywg0L4g0LTQsNGC0LAg0YTRgNC10LnQvNC1LiDQn9GA0L7RgdGC0LXQudGI0LXQtSDQv9GA0LXQvtCx0YDQsNC30L7QstCw0L3QuNC1INC/0L7QvNC+0LPQsNC10YIg0L3QsNC8INC30LDQtNCw0LLQsNGC0Ywg0L7RgdC80YvRgdC70LXQvdC90YvQtSDQstC+0L/RgNC+0YHRiy4gDQoNCg0KIyDQl9Cw0LTQsNGH0LANCtCd0YPQttC90L4g0LLQsdC40YLRjCDQutGD0YHQvtC6INC90LXQtNC+0YHRgtCw0Y7RidC40YUg0LTQsNC90L3Ri9GFLCDQutC+0YLQvtGA0YvQtSDQvdC1INC/0YDQuNGB0LvQsNC7INC90LDQvCDQmtCw0YDQu9C+0Ygg0JvQuNC90L3QtdC50YEgIA0KYGBge3J9DQphdmlhbl9yZXN0IDwtICByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Rvbnl0b25vdi9SY291cnNlL21hc3Rlci9SJTIwcHJvZ3JhbW1pbmcvYXZpYW5IYWJpdGF0Mi5jc3YiKQ0KYGBgDQrQn9C+0YHQvNC+0YLRgNC40LwsINC10YHRgtGMINC70Lgg0YDQsNC30L3QuNGG0LAg0YEg0YPQttC1INC40LzQtdGO0YnQuNC80LjRgdGPINC00LDQvdC90YvQvNC4INC4INC90YPQttC90L4g0LvQuCDQvdCw0Lwg0LrQsNC60LjQtS3RgtC+INCy0L3QvtGB0LjRgtGMINC40LfQvNC10L3QtdC90LjRjw0KYGBge3J9DQpoZWFkKGF2aWFuX3Jlc3QpDQpgYGANCtCS0LjQttGDLCDRh9GC0L4g0LTQsNC90L3Ri9C1INCy0L7QvtCx0YnQtSDRgdGH0LjRgtCw0LvQuNGB0Ywg0L3QtdC60L7RgNC10LrRgtC90L4uINCf0LXRgNCy0YvQtSA0INGB0YLRgNC+0LrQuCDRj9Cy0L3QviDQu9C40YjQvdC40LUNCmBgYHtyfQ0Kc3RyKGF2aWFuX3Jlc3QpDQpgYGANCtCf0L7Qv9GA0L7QsdGD0Y4g0L/RgNC+0L/Rg9GB0YLQuNGC0Ywg0L/QtdGA0LLRi9C1IDQg0YHRgtGA0L7QutC4INC/0YDQuCDQv9C+0LLRgtC+0YDQvdC+0Lwg0YHRh9C40YLRi9Cy0LDQvdC40LgNCmBgYHtyfQ0KYXZpYW5fcmVzdCA8LSAgcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90b255dG9ub3YvUmNvdXJzZS9tYXN0ZXIvUiUyMHByb2dyYW1taW5nL2F2aWFuSGFiaXRhdDIuY3N2Iiwgc2tpcCA9IDQpDQpgYGANCtCf0YDQvtCy0LXRgNGP0Y4NCmBgYHtyfQ0KaGVhZChhdmlhbl9yZXN0KQ0KYGBgDQrQm9C40YjQvdC40LUg0YHRgtGA0L7QutC4INGD0YHQv9C10YjQvdC+INC/0YDQvtC/0YPRidC10L3Riywg0L3QviDQt9Cw0LzQtdGH0LDRjiwg0YfRgtC+INCyINC00LDRgtCwINGE0YDQtdC50LzQtSDQsiDQutCw0YfQtdGB0YLQstC1INGA0LDQt9C00LXQu9C40YLQtdC70Y8g0LjRgdC/0L7Qu9GM0LfRg9C10YLRgdGPICI7Ii4g0J/QviDRg9C80L7Qu9GH0LDQvdC40Y4g0LDRgNCz0YPQvNC10L3RgiAqc2VwID0gIiwiKi4g0KHQtNC10LvQsNGOINC30LDQvNC10L3Rgy4NCmBgYHtyfQ0KYXZpYW5fcmVzdCA8LSAgcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90b255dG9ub3YvUmNvdXJzZS9tYXN0ZXIvUiUyMHByb2dyYW1taW5nL2F2aWFuSGFiaXRhdDIuY3N2Iiwgc2tpcCA9IDQsIHNlcCA9ICI7IikNCmBgYA0K0KfRgtC+LdGC0L4g0L3QtSDRgtCw0Log0YEg0YfQuNGB0LvQvtC8INC60L7Qu9C+0L3QvtC6LiDQmtC+0LvQvtC90L7QuiDRgSDQtNCw0L3QvdGL0LzQuCDQsdC+0LvRjNGI0LUsINGH0LXQvCDQuNC80LXQvS4g0JrQsNC20LXRgtGB0Y8g0LXRgdGC0Ywg0LXRidC1IDEg0LvQuNGI0L3Rj9GPINGB0YLRgNC+0LrQsC4g0J/RgNC+0LHRg9GOOg0KYGBge3J9DQphdmlhbl9yZXN0IDwtICByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Rvbnl0b25vdi9SY291cnNlL21hc3Rlci9SJTIwcHJvZ3JhbW1pbmcvYXZpYW5IYWJpdGF0Mi5jc3YiLCBza2lwID0gNSwgc2VwID0gIjsiKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChhdmlhbl9yZXN0KQ0KYGBgDQrQodGA0LDQstC90Y4g0YEg0LjRgdGF0L7QtNC90YvQvCDRhNCw0LnQu9C+0LwNCmBgYHtyfQ0KaGVhZChhdmlhbikNCmBgYA0K0J/RgNC10L7QsdGA0LDQt9C+0LLQsNC90LjQtSDQv9C+0YfQtdC80YMt0YLQviDQvdC1INGB0YDQsNCx0L7RgtCw0LvQvi4g0J/RgNC+0LHRg9GOINC00LDQu9GM0YjQtS4g0J3QsNGF0L7QttGDINC60L7QvNC80LXQvdGC0LDRgNC40Lkg0Log0LTQsNC90L3Ri9C8INC/0YDQuCDQv9GA0L7RgdC80L7RgtGA0LUg0YLQsNCx0LvQuNGG0Ysg0LLRgNGD0YfQvdGD0Y4g0Lgg0LTRg9GA0LDRhtC60YPRjiDQv9C+0LTQv9C40YHRjCDQsiDQv9C+0YHQu9C10LTQvdC10Lkg0LrQvtC70L7QvdC60LUuINCf0YDQvtCx0YPRjiDQt9Cw0LrQvtC80LXQvdGC0LjRgNC+0LLQsNGC0Ywg0L/QvtC00L/QuNGB0Ywg0Log0LTQsNC90L3Ri9C8INCyINGC0LDQsdC70LjRhtC1DQpgYGB7cn0NCmF2aWFuX3Jlc3QgPC0gIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdG9ueXRvbm92L1Jjb3Vyc2UvbWFzdGVyL1IlMjBwcm9ncmFtbWluZy9hdmlhbkhhYml0YXQyLmNzdiIsIHNraXAgPSA1LCBzZXAgPSAiOyIsIHF1b3RlID0gIiUiKQ0KYGBgDQrQn9GA0Lgg0L/RgNC+0YHQvNC+0YLRgNC1INCy0LjQttGDLCDRh9GC0L4g0LrQvtC80LzQtdC90YLQsNGA0LjQuSDQuNGB0YfQtdC3LiDQmNC30LHQsNCy0LvRj9GO0YHRjCDQvtGCINC/0L7QtNC/0LjRgdC4DQpgYGB7cn0NCmF2aWFuX3Jlc3RbIlBCLi4uSS5yZW1vdmVkLk9ic2VydmVyLmNvbHVtbi5zaW5jZS5hbGwubWVhc3VyZW1lbnRzLmFyZS5taW5lIl0gPC0gIlBCIg0KYGBgDQrQn9GA0L7QuNC30L7RiNC70LAg0LrQsNC60LDRjy3RgtC+INGF0YDQtdC90YwuINCf0LXRgNC10LTQtdC70LDRjiDRgdC90LDRh9Cw0LsNCmBgYHtyfQ0KYXZpYW5fcmVzdCA8LSAgcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90b255dG9ub3YvUmNvdXJzZS9tYXN0ZXIvUiUyMHByb2dyYW1taW5nL2F2aWFuSGFiaXRhdDIuY3N2Iiwgc2tpcCA9IDUsIHNlcCA9ICI7IiwgcXVvdGUgPSAiJSIpDQpgYGANCtCY0YHQv9GA0LDQstC40LvQvtGB0Ywg0YfQsNGB0YLQuNGH0L3Qvi4g0JIg0L/QvtGB0LvQtdC00L3QtdC5INC60L7Qu9C+0L3QutC1INC60YPRh9CwINGF0YDQtdC90Lgu0J/RgNC+0LHRg9GOINGB0L3QvtCy0LAuINCd0LDQtNC10Y7RgdGMINC/0YDQsNCy0LjQu9GM0L3Qvg0KYGBge3J9DQphdmlhbl9yZXN0JFBCLi5JLnJlbW92ZWQuLk9ic2VydmVyLi5jb2x1bW4uc2luY2UuYWxsLm1lYXN1cmVtZW50cy5hcmUubWluZS5Ib3J0b25DcmVlazExMS4xLjMuMC4wLjAuMC40LjMuNS4wLjAuMy41LjAuMC4wLkhvcnRvbkNyZWVrMTExLjIuMy4wLjAuNC4xOC41LjAuMC4wLjAuNC41LjcuMC4wLjAuSG9ydG9uQ3JlZWsxMTEuMy4yLjAuMC4zLjExLjMuMi4zLjAuMC40LjQuOS4xLjAuMi4wLkhvcnRvbkNyZWVrMTExLjQuMy41LjAuMC40LjE1LjguMC4wLjAuMC4zLjQuMi4wLjAuMC5Ib3J0b25DcmVlazExMS41LjAuMS4wLjMuMi4wLjUuNC4wLjQuMC4wLjIuMS40LjUuMC4zLjAuSG9ydG9uQ3JlZWsxMTEuNi4wLjIuMC43LjMuMC41LjQuMC41LjAuMC4xLjEuNi4zLjAuNS4xLkhvcnRvbkNyZWVrMTExLjcuMC4yLjAuMy4wLjAuNS4wLjQuMC4wLjIuMS44LjUuMC4zLjAuSG9ydG9uQ3JlZWsxMTEuRG9uLnQucmVtZW1iZXIuMC4yLjAuNy4wLjAuNS4wLjYuMC4wLjEuMS42LjQuMC4yLjEuLi4uLlNvcnJ5LmFib3V0LnRoYXQuLkkubWVzc2VkLnVwIDwtIGF2aWFuX3Jlc3QkUEINCmBgYA0KYGBge3J9DQo/PyJkYXRhLmZyYW1lIiANCmBgYA0K0KfQuNGC0LDRjiDRgdC/0YDQsNCy0LrRgyDQv9C+INC00LDRgtCwINGE0YDQtdC50LzRgy4g0JLRgNC+0LTQtSDQv9C+0L3QuNC80LDRjiwg0LrQsNC6INC90LDQtNC+DQpgYGB7cn0NCmRpbW5hbWVzKGF2aWFuX3Jlc3QkUEIuLkkucmVtb3ZlZC4uT2JzZXJ2ZXIuLmNvbHVtbi5zaW5jZS5hbGwubWVhc3VyZW1lbnRzLmFyZS5taW5lLkhvcnRvbkNyZWVrMTExLjEuMy4wLjAuMC4wLjQuMy41LjAuMC4zLjUuMC4wLjAuSG9ydG9uQ3JlZWsxMTEuMi4zLjAuMC40LjE4LjUuMC4wLjAuMC40LjUuNy4wLjAuMC5Ib3J0b25DcmVlazExMS4zLjIuMC4wLjMuMTEuMy4yLjMuMC4wLjQuNC45LjEuMC4yLjAuSG9ydG9uQ3JlZWsxMTEuNC4zLjUuMC4wLjQuMTUuOC4wLjAuMC4wLjMuNC4yLjAuMC4wLkhvcnRvbkNyZWVrMTExLjUuMC4xLjAuMy4yLjAuNS40LjAuNC4wLjAuMi4xLjQuNS4wLjMuMC5Ib3J0b25DcmVlazExMS42LjAuMi4wLjcuMy4wLjUuNC4wLjUuMC4wLjEuMS42LjMuMC41LjEuSG9ydG9uQ3JlZWsxMTEuNy4wLjIuMC4zLjAuMC41LjAuNC4wLjAuMi4xLjguNS4wLjMuMC5Ib3J0b25DcmVlazExMS5Eb24udC5yZW1lbWJlci4wLjIuMC43LjAuMC41LjAuNi4wLjAuMS4xLjYuNC4wLjIuMS4uLi4uU29ycnkuYWJvdXQudGhhdC4uSS5tZXNzZWQudXApIDwtICJQQiINCmBgYA0KYGBge3J9DQpuYW1lcyhhdmlhbl9yZXN0KQ0KYGBgDQpgYGB7cn0NCm5hbWVzKGF2aWFuX3Jlc3QkUEIuLkkucmVtb3ZlZC4uT2JzZXJ2ZXIuLmNvbHVtbi5zaW5jZS5hbGwubWVhc3VyZW1lbnRzLmFyZS5taW5lLkhvcnRvbkNyZWVrMTExLjEuMy4wLjAuMC4wLjQuMy41LjAuMC4zLjUuMC4wLjAuSG9ydG9uQ3JlZWsxMTEuMi4zLjAuMC40LjE4LjUuMC4wLjAuMC40LjUuNy4wLjAuMC5Ib3J0b25DcmVlazExMS4zLjIuMC4wLjMuMTEuMy4yLjMuMC4wLjQuNC45LjEuMC4yLjAuSG9ydG9uQ3JlZWsxMTEuNC4zLjUuMC4wLjQuMTUuOC4wLjAuMC4wLjMuNC4yLjAuMC4wLkhvcnRvbkNyZWVrMTExLjUuMC4xLjAuMy4yLjAuNS40LjAuNC4wLjAuMi4xLjQuNS4wLjMuMC5Ib3J0b25DcmVlazExMS42LjAuMi4wLjcuMy4wLjUuNC4wLjUuMC4wLjEuMS42LjMuMC41LjEuSG9ydG9uQ3JlZWsxMTEuNy4wLjIuMC4zLjAuMC41LjAuNC4wLjAuMi4xLjguNS4wLjMuMC5Ib3J0b25DcmVlazExMS5Eb24udC5yZW1lbWJlci4wLjIuMC43LjAuMC41LjAuNi4wLjAuMS4xLjYuNC4wLjIuMS4uLi4uU29ycnkuYWJvdXQudGhhdC4uSS5tZXNzZWQudXApIDwtICJQQiINCmBgYA0KYGBge3J9DQpuYW1lcyhhdmlhbl9yZXN0KSANCmBgYA0K0JIg0LjRgtC+0LPQtSDQs9GD0LPQu9GOLCDQvdCw0YXQvtC20YMg0YHRgtCw0YLRjNGOINC90LAgU3RhY2tvdmVyZmxvdw0KYGBge3J9DQpjb2xuYW1lcyhhdmlhbl9yZXN0KQ0KYGBgDQpgYGB7cn0NCmNvbG5hbWVzKGF2aWFuX3Jlc3QpWzE2XSA8LSAiUEIiDQpjb2xuYW1lcyhhdmlhbl9yZXN0KQ0KYGBgDQrQn9C+0LvRg9GH0LjQu9C+0YHRjCEg0KPRgNCwLg0KYGBge3J9DQpoZWFkKGF2aWFuX3Jlc3QpDQpgYGANCtCi0LXQv9C10YDRjCDQstC40LTQvdC+LCDQv9C+0YfQtdC80YMg0L3QtSDRgNCw0LHQvtGC0LDQu9C+INC/0YDQtdC+0LHRgNCw0LfQvtCy0LDQvdC40LUg0L3QsCBzdWJwb2ludCDQsiBpbnRlZ2VyLiDQkiDQtNCw0YLQsCDRhNGA0LXQudC80LUg0LXRgdGC0Ywg0L/RgNC+0L/Rg9GJ0LXQvdC90YvQtSDQt9C90LDRh9C10L3QuNGPLiDQn9C+0L/RgNC+0LHRg9GOINC40YUg0LfQsNC80LXQvdC40YLRjCDQvdCwIE5BDQpgYGB7cn0NCj8/ZGF0YS5mcmFtZS1taXNzaW5nDQpgYGANCtCh0L3QvtCy0LAg0LHRi9GB0YLRgNC+INC90LDRhdC+0LbRgyDQvtGC0LLQtdGCINC90LAgU3RhY2tvdmVyZmxvdy4g0J/RgNC+0LHRg9GODQpgYGB7cn0NCmF2aWFuX3Jlc3QgPC0gcmVwbGFjZShhdmlhbl9yZXN0LCBhdmlhbl9yZXN0ID09ICJEb25gdCByZW1lbWJlciIsIE5BKQ0KYGBgDQrQn9GA0L7QstC10YDRjg0KYGBge3J9DQpoZWFkKGF2aWFuX3Jlc3QpDQpgYGANCtCX0LDQvNC10L3RiyDQvdC1INC/0YDQvtC40LfQvtGI0LvQvi4g0KHQv9C+0YHQvtCxINC90LUg0YDQsNCx0L7RgtCw0LXRgiDQtNC70Y8g0YLQuNC/0LAgY2hhcmFjdGVyLiDQndCw0YXQvtC20YMg0YHQv9C+0YHQvtCxINC00LvRjyBjaGFyYWN0ZXINCmBgYHtyfQ0KYXZpYW5fcmVzdFthdmlhbl9yZXN0ID09ICJEb25gdCByZW1lbWJlciJdIDwtIE5BDQpgYGANCmBgYHtyfQ0KaGVhZChhdmlhbl9yZXN0KQ0KYGBgDQrQodC90L7QstCwINC90LUg0YDQsNCx0L7RgtCw0LXRgi4gIA0K0KHRgtC+0L8uICANCtCf0YDQuNCz0LvRj9C00YvQstCw0Y7RgdGMLiAgDQrQkNC/0L7RgdGC0YDQvtGEINC90LUg0YLQvtGCLiDQmtC+0L/QuNGA0YPRjiDQuCDQv9GA0L7QsdGD0Y4g0LXRidC1INGA0LDQtw0KYGBge3J9DQphdmlhbl9yZXN0W2F2aWFuX3Jlc3QgPT0gIkRvbid0IHJlbWVtYmVyIl0gPC0gTkENCmBgYA0KYGBge3J9DQpoZWFkKGF2aWFuX3Jlc3QpDQpgYGANCtCj0YDQsCEg0J3QsCDRjdGC0L7RgiDRgNCw0Lcg0L/QvtC70YPRh9C40LvQvtGB0YwuINCf0YDQtdC+0LHRgNCw0LfRg9GODQpgYGB7cn0NCmFzLmludGVnZXIoYXZpYW5fcmVzdCRTdWJwb2ludCkNCmBgYA0KYGBge3J9DQpoZWFkKGF2aWFuX3Jlc3QpDQpgYGANCtCf0YDQtdC+0LHRgNCw0LfQvtCy0LDQvdC40LUg0L3QtSDRgdGA0LDQsdC+0YLQsNC70L4sINC90L4g0Lgg0YXRgNC10L0g0YEg0L3QuNC8LCDQvdCw0LLQtdGA0L3QvtC1LiDQntGB0YLQsNC10YLRgdGPINCz0LvQsNCy0L3QsNGPINC/0YDQvtCx0LvQtdC80LAsINC60LDQuiDRjdGC0L4g0LLRgdC1INC/0L7QtNGI0LjRgtGMLCDRg9GH0LjRgtGL0LLQsNGPLCDRh9GC0L4g0L3QtdGCINC60L7Qu9C+0L3QutC4LiDQn9C+0L/RgNC+0LHRg9GOINGB0LTQtdC70LDRgtGMINC90L7QstGD0Y4NCmBgYHtyfQ0KYXZpYW5fcmVzdFtdDQpgYGANCtCf0L7Qv9GA0L7QsdGD0Y4g0LjRhSDRgdC+0LXQtNC40LjRgtGMINGC0LDQui4g0JzQvtC20LXRgiDQvtCx0L7QudC00LXRgtGB0Y8gDQpgYGB7cn0NCm1lcmdlKGF2aWFuLCBhdmlhbl9yZXN0LCBieS54ID0gIlN1YnBvaW50IikNCmBgYA0K0JjQtyDQs9C+0YLQvtCy0YvRhSDRhNGD0L3QutGG0LjQuSDQvdCw0YXQvtC20YMg0YLQsNC60YPRjiDRgtC+0LvRjNC60L4g0LIg0L/QsNC60LXRgtC1IGRwbHlyDQpgDQrQntGB0YLQsNC10YLRgdGPINC90LXRgNC10YjQtdC90L3QvtC5INC/0YDQvtCx0LvQtdC80LAg0L/RgNC10L7QsdGA0LDQt9C+0LLQsNC90LjRjy4g0KHQvdC+0LLQsCDQvdCw0YXQvtC20YMg0YHQv9C+0YHQvtCxINC90LAgU3RhY2st0LUNCmBgYHtyfQ0KYXZpYW5fcmVzdCRTdWJwb2ludCA8LSBhcy5pbnRlZ2VyKGFzLmNoYXJhY3Rlcihhdmlhbl9yZXN0JFN1YnBvaW50KSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpkcGx5cjo6YmluZF9yb3dzKGF2aWFuLCBhdmlhbl9yZXN0KQ0KYGBgDQoNCtCj0YDQsCEg0KLQtdC/0LXRgNGMINC90LDQutC+0L3QtdGGLdGC0L4g0LzQvtCz0YMg0L/QtdGA0LXRgdGH0LjRgtCw0YLRjCDQv9C+0LrQsNC30LDRgtC10LvQuC4g0JjQvdGC0LXRgNC10YHQvdC+LCDQutCw0Log0LLRi9Cz0LvRj9C00LjRgiDRhdCy0L7RgdGCPw0KYGBge3J9DQpzdHIoYXZpYW4pDQpgYGANCtCd0L4g0YMg0LzQtdC90Y8g0YfRgtC+LdGC0L4g0L3QtSDRgtCw0Log0YEg0LrQvtC70LjRh9C10YHRgtCy0L7QvCDQvdCw0LHQu9GO0LTQtdC90LjQuS4g0KMg0LzQtdC90Y8gMTA4MCwg0LAg0LTQvtC70LbQvdC+INCx0YvRgtGMIDEwODguDQrQnNC+0LbQtdGCIGRwbHlyINC90LUg0L7QsdGK0LXQtNC40L3Rj9C10YIg0LjRhSDQvtC60L7QvdGH0LDRgtC10LvRjNC90L4uINCl0LcuINCd0LAg0LTQsNC90L3QvtC8INGN0YLQsNC/0LUg0LLRgdC1INGB0LvQuNGI0LrQvtC8INC30LDQv9GD0YLQsNC90L4uINCf0L7Qv9GA0L7QsdGD0Y4g0LjQt9C90LDRh9Cw0LvRjNC90L4g0L/RgNC+0YfQuNGC0LDRgtGMINGE0LDQudC7INC/0L4t0L3QvtGA0LzQsNC70YzQvdC+0LzRgyDQsdC10Lcg0LfQsNC80L7RgNC+0YfQtdC6LCDQutCw0Log0L/RgNC10LTQu9Cw0LPQsNC10YLRgdGPINCyINC60L7QvNC80LXQvdGC0LDRgNC40Y/RhQ0KYGBge3J9DQpyZWFkLmNzdihzZXAgPSAiOyIsIHNraXAgPSA1LCBoZWFkZXIgPSBULCBjb21tZW50LmNoYXIgPSAiJSIsIHF1b3RlID0gIiIsIG5hLnN0cmluZ3MgPSAiRG9uJ3QgcmVtZW1iZXIiLCBmaWxlID0gJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90b255dG9ub3YvUmNvdXJzZS9tYXN0ZXIvUiUyMHByb2dyYW1taW5nL2F2aWFuSGFiaXRhdDIuY3N2JykNCmBgYA0K0J/QvtC/0YDQvtCx0YPRjiDRgtC10L/QtdGA0Ywg0L7QsdGK0LXQtNC40L3QuNGC0YwgZHBseXIt0L7QvA0KYGBge3J9DQpkcGx5cjo6YmluZF9yb3dzKGF2aWFuLCBhdmlhbl9yZXN0KQ0KYGBgDQoxMDgwINC90LDQsdC70Y7QtNC10L3QuNC5LiDQkdC70Y8NCmBgYHtyfQ0Kc3RyKGJpbmRfcm93cyhhdmlhbiwgYXZpYW5fcmVzdCkpDQpgYGANCtCSINC+0LHRidC10LwsINC90L7RgNC80LDQu9GM0L3QviDQvtC9INC90LUg0L7QsdGK0LXQtNC40L3Rj9C10YIg0LIg0YLQsNC60L7QvCDRhNC+0YDQvNCw0YLQtSDQv9C+0YfQtdC80YMt0YLQvi4NCmBgYHtyfQ0Kc3RyKGF2aWFuX3Jlc3QpDQpgYGANCtCa0YPQtNCwLdGC0L4g0LTQtdC70LjRgdGMIDgg0L3QsNCx0LvRjtC00LXQvdC40LkuINCf0LXRgNC10YfQuNGC0LDRjiDQt9Cw0L3QvtCy0L4NCmBgYHtyfQ0KcmVhZC5jc3Yoc2VwID0gIjsiLCBza2lwID0gNSwgY29tbWVudC5jaGFyID0gIiUiLCBxdW90ZSA9ICIiLCBuYS5zdHJpbmdzID0gIkRvbid0IHJlbWVtYmVyIiwgZmlsZSA9ICdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdG9ueXRvbm92L1Jjb3Vyc2UvbWFzdGVyL1IlMjBwcm9ncmFtbWluZy9hdmlhbkhhYml0YXQyLmNzdicpDQpgYGANCmBgYHtyfQ0Kc3RyKGF2aWFuX3Jlc3QpDQpgYGANCtCf0L7Rh9C10LzRgy3RgtC+INCy0YHQtSDQstGA0LXQvNGPINC/0LjRiNC10YIgMTAg0L3QsNCx0LvRjtC00LXQvdC40LkuINCc0L7QttC10YIsINGB0YfQuNGC0LDQtdGCINC60L7Qu9C40YfQtdGB0YLQstC+INC/0L7Qu9C90YvRhSDQvdCw0LHQu9GO0LTQtdC90LjQuT8g0KXQvtGC0Y8sINC10YHQu9C4INC/0L7RgdGH0LjRgtCw0YLRjCDQstGA0YPRh9C90YPRjiwg0YLQviDQv9C+0LvRg9GH0LDQtdGC0YEg0Y8gMTguINCd0LUg0L/QvtC90LjQvNCw0Y4uINCb0LDQtNC90L4sINC/0L7RhNC40LMg0L3QsNC00L4g0L7QsdGK0LXQtNC40L3Rj9GC0YwuDQpgYGB7cn0NCmF2X2ZpbiA8LSBkcGx5cjo6YmluZF9yb3dzKGF2aWFuLCBhdmlhbl9yZXN0KQ0KYXZfZmluDQpgYGANCg0KYGBge3J9DQpjb3ZlcmFnZV92YXJpYWJsZXMgPC0gbmFtZXMoYXZfZmluKVstKDE6NCldW2MoVCwgRildDQphdl9maW4kdG90YWxfY292ZXJhZ2UgPC0gcm93U3Vtcyhhdl9maW5bICwgY292ZXJhZ2VfdmFyaWFibGVzXSkNCnN1bW1hcnkoYXZfZmluJHRvdGFsX2NvdmVyYWdlKQ0KYGBgDQphdl9maW4NCmBgYHtyfQ0KYXZfZmluJHRvdGFsX2NvdmVyYWdlaSA8LSBOVUxMDQphdl9maW4NCmBgYA0K0JLRgdC1LdGC0LDQutC4INC/0L7QtNC+0LfRgNC10LLQsNGOINC/0YDQvtCx0LvQtdC80YMg0LIg0L7QsdGK0LXQtNC40L3QtdC90LjQuC4g0JHRg9C00YMg0L/RgNC+0LHQvtCy0LDRgtGMINC/0L4t0LTRgNGD0LPQvtC80YMuDQpgYGB7cn0NCnJlYWQuY3N2KHNlcCA9ICI7Iiwgc2tpcCA9IDUsIGNvbW1lbnQuY2hhciA9ICIlIiwgcXVvdGUgPSAiIiwgbmEuc3RyaW5ncyA9ICJEb24ndCByZW1lbWJlciIsIGZpbGUgPSAnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Rvbnl0b25vdi9SY291cnNlL21hc3Rlci9SJTIwcHJvZ3JhbW1pbmcvYXZpYW5IYWJpdGF0Mi5jc3YnKQ0KYGBgDQoNCmBgYHtyfQ0KY29sbmFtZXMoYXZpYW5fcmVzdCkNCmBgYA0KYGBge3J9DQpjb2xuYW1lcyhhdmlhbl9yZXN0WzJdKSA8LSAiT2JzZXJ2ZXIiDQpgYGANCmBgYHtyfQ0KY29sbmFtZXMoYXZpYW5fcmVzdCkNCmBgYA0KYGBge3J9DQphdmlhbl9yZXN0JE9ic2VydmVyIDwtICJLTCINCmhlYWQoYXZpYW5fcmVzdCkNCmBgYA0KYGBge3J9DQpjb2xuYW1lcyhhdmlhbl9yZXN0KQ0KYGBgDQpgYGB7cn0NCmF2aWFuX3Jlc3QgPC0gYXZpYW5fcmVzdFsgLCBjKCJTaXRlIiwgIk9ic2VydmVyIiwgIlN1YnBvaW50IiwgIlZPUiIsICJQREIiLCAgICAgICJEQkh0IiwgIlBXIiwgIldIdCIsICJQRSIsICJFSHQiICwiUEEiLCAgICJBSHQiLCAgICAiUEgiLCAiSEh0IiwgICJQTCIsICJMSHQiLCAiUEIiKV0NCmF2aWFuX3Jlc3QNCmBgYA0KYGBge3J9DQphdiA8LSBtZXJnZShhdmlhbiwgYXZpYW5fcmVzdCwgYWxsID0gVCkNCmF2DQphdiR0b3RhbF9jb3ZlcmFnZWkgPC0gTlVMTA0KYXYNCmBgYA0KDQpgYGB7cn0NCmNvdmVyYWdlX3ZhcmlhYmxlcyA8LSBuYW1lcyhhdilbLSgxOjQpXVtjKFQsIEYpXQ0KYXYkdG90YWxfY292ZXJhZ2UgPC0gcm93U3VtcyhhdlsgLCBjb3ZlcmFnZV92YXJpYWJsZXNdKQ0Kc3VtbWFyeShhdiR0b3RhbF9jb3ZlcmFnZSkNCmBgYA0KYGBge3J9DQphdg0KYGBgDQoNCtCk0YPRhS4g0KDQtdGI0LjQuyDRgtCw0LrQuCDQt9Cw0LTQsNGH0YMuINCSINC40YLQvtCz0LUg0L7RgtCy0LXRgiDQvNC90LUg0L3QtSDQt9Cw0YHRh9C40YLRi9Cy0LDQu9C4LCDRgtGL0LrQvdGD0Lsg0L/RgNC+0YHRgtC+INC90LAg0L/QvtC00LHQvtGALg0KDQpgYGB7cn0NCmF2aWFuIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdG9ueXRvbm92L1Jjb3Vyc2UvbWFzdGVyL1IlMjBwcm9ncmFtbWluZy9hdmlhbkhhYml0YXQuY3N2IikNCmNvdmVyYWdlX3ZhcmlhYmxlcyA8LSBuYW1lcyhhdmlhbilbLSgxOjQpXVtjKFQsIEYpXQ0KYXZpYW4yIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdG9ueXRvbm92L1Jjb3Vyc2UvbWFzdGVyL1IlMjBwcm9ncmFtbWluZy9hdmlhbkhhYml0YXQyLmNzdiIsDQogICAgICAgICAgICAgICAgICAgc2VwID0gIjsiLCBuYS5zdHJpbmdzID0gIkRvbid0IHJlbWVtYmVyIiwgc2tpcCA9IDUsIGNvbW1lbnQuY2hhciA9ICIlIikNCmF2aWFuMiRPYnNlcnZlciA8LSAiQ0wiICMg0LTQu9GPINC60YDQsNGB0L7RgtGLDQphdmlhbjMgPC0gbWVyZ2UoYXZpYW4sIGF2aWFuMiwgYWxsID0gVCkNCmF2aWFuMyR0b3RhbF9jb3ZlcmFnZSA9IHJvd1N1bXMoYXZpYW4zW2NvdmVyYWdlX3ZhcmlhYmxlc10pDQpzdW1tYXJ5KGF2aWFuMylbNCwgInRvdGFsX2NvdmVyYWdlIl0NCmF2aWFuMw0KYGBgDQoNCiMjIyDQl9Cw0LTQsNGH0LAgMiANCg0K0J3QsCDQvNCw0YHRgdC40LLQtSBhdmlhbkhhYml0YXQg0L3QsNC50LTQuNGC0LUg0LzQsNC60YHQuNC80LDQu9GM0L3Ri9C1INCy0YvRgdC+0YLRiyDQv9C+INC60LDQttC00L7QvNGDINCy0LjQtNGDINGA0LDRgdGC0LXQvdC40Lkg0Lgg0L7RgtGB0L7RgNGC0LjRgNGD0LnRgtC1INGN0YLQuCDQstC40LTRiyDQv9C+INGD0LHRi9Cy0LDQvdC40Y4sINC+0YIg0YHQsNC80L7Qs9C+INCy0YvRgdC+0LrQvtCz0L4g0Log0YHQsNC80L7QvNGDINC90LjQt9C60L7QvNGDICANCtCe0LHRidC40Lkg0LPQu9C+0YHRgdCw0YDQuNC5INC00LvRjyDRjdGC0L7Qs9C+INGD0YDQvtC60LA6DQpgYGB7cn0NCmF2aWFuJHRvdGFsX2NvdmVyYWdlaSA8LSBOVUxMDQpzdHIoYXZpYW4pDQpgYGANCmBgYHtyfQ0KaGVpZ2h0cyA8LSBhdmlhblstYygxOjUpXVtjKFQsIEYpXQ0KaGVpZ2h0c19tYXggPC0gYXBwbHkoaGVpZ2h0cywgMiwgbWF4KQ0Kc29ydChoZWlnaHRzX21heCwgZGVjcmVhc2luZyA9IFQpDQpgYGANCg0KIyMg0JPQu9C+0YHRgdCw0YDQuNC5DQo/ZGF0YS5mcmFtZSAgDQo/c3RyICANCj9yb3duYW1lcywgP2NvbG5hbWVzLCA/ZGltbmFtZXMsID9ucm93LCA/bmNvbCwgP2RpbSAgDQo/c3Vic2V0LCA/cmJpbmQsID9jYmluZCwgP21lcmdlICANCj9yZWFkLnRhYmxlICg/cmVhZC5jc3YsID9yZWFkLmRlbGltKSAgDQo/d3JpdGUudGFibGUgKD93cml0ZS5jc3YsID93cml0ZS5kZWxpbSkgIA0KP2NvbXBsZXRlLmNhc2VzLCA/bmEub21pdCAgDQo/d3JpdGUudGFibGUgKD93cml0ZS5jc3Yp