Строки
Строки - один из ключевых объектов в любом языке программирования
В реальных данных могут встречаться строковые данные
Оперирование именами в подразделах датафрейма - суть, работа со строкой
Итак Строка:
* Строка (string) - элемент вектора типа character
* Большинство функций, оперирующих на строках, векторизированы
s <- c("Терпение и труд все перетрут",
"Кончил дело - гуляй смело",
"Без труда не вытащишь и рыбку из пруда",
"Работа не волк, в лес не убежит")
s
[1] "Терпение и труд все перетрут"
[2] "Кончил дело - гуляй смело"
[3] "Без труда не вытащишь и рыбку из пруда"
[4] "Работа не волк, в лес не убежит"
- Для объявления о начале строки используются знаки " или *‘* - в коде их лучше не мешать, смешивание может пригодится в случае по типу ’Операция “Ы”’. Тогда для корректного выведения нужно экранировать внутренние кавычки бэкслешем
eg <- 'Операция \"Ы\"'
eg
[1] "Операция \"Ы\""
Экранирование помогает отличать открывающие и закрывающие кавычки
Функция paste/paste0
- Выполнябт конкатенацию строковых векторово с учеом правил переписывания
- Аргумент sep - разделитель между элементами (для paste по умолчанию пробел, для paste0 - пустая строка)
- Аргумент collapse - “схлопывает” вектор в одну строку
Пример 1
paste
function (..., sep = " ", collapse = NULL)
.Internal(paste(list(...), sep, collapse))
<bytecode: 0x000002148c329e68>
<environment: namespace:base>
paste(c("углексилый", "веселящий"), "газ")
[1] "углексилый газ" "веселящий газ"
paste0
function (..., collapse = NULL)
.Internal(paste0(list(...), collapse))
<bytecode: 0x000002148c14e988>
<environment: namespace:base>
paste0(c("углексилый", "веселящий"), "газ")
[1] "углексилыйгаз" "веселящийгаз"
paste(c("прокариотическая", "эукариотическая"), "клетка")
[1] "прокариотическая клетка"
[2] "эукариотическая клетка"
paste("зачем", "тебе", "data science?")
[1] "зачем тебе data science?"
paste0("зачем", "тебе", "data science?")
[1] "зачемтебеdata science?"
Пример 2 - аргумент sep
paste(c("веселящий", "углекислый"), "газ", sep = "_")
[1] "веселящий_газ" "углекислый_газ"
Есть ли разница с paste0, если задать такой же аргумент sep?
paste0(c("веселящий", "углекислый"), "газ", sep = "_")
[1] "веселящийгаз_" "углекислыйгаз_"
Да, он всопроизвел *_* как часть строки в конце. По итогу, paste0 – это paste с аргументом sep = ""
Функция strsplit - разбиение
- Выполняет разбиение строкового вектора
- Результат - список
strsplit
function (x, split, fixed = FALSE, perl = FALSE, useBytes = FALSE)
.Internal(strsplit(x, as.character(split), fixed, perl, useBytes))
<bytecode: 0x000002148c3780c8>
<environment: namespace:base>
N.B! Обрати внимание, что пробелы, заключенные в кавычки, несут смысловую нагрузку…
strsplit(s," и ", fixed = TRUE)
[[1]]
[1] "Терпение"
[2] "труд все перетрут"
[[2]]
[1] "Кончил дело - гуляй смело"
[[3]]
[1] "Без труда не вытащишь"
[2] "рыбку из пруда"
[[4]]
[1] "Работа не волк, в лес не убежит"
…иначе разбиение шло бы еще и внутри слов
strsplit(s,"и", fixed = TRUE)
[[1]]
[1] "Терпен"
[2] "е "
[3] " труд все перетрут"
[[2]]
[1] "Конч"
[2] "л дело - гуляй смело"
[[3]]
[1] "Без труда не вытащ"
[2] "шь "
[3] " рыбку "
[4] "з пруда"
[[4]]
[1] "Работа не волк, в лес не убеж"
[2] "т"
Аргумент fixed
Если его не указывать (по умолчанию FALSE), то строка по которой проводится разбиение, будет рассматриваться как регулярное выражение. Про регулярные выражения дальше. Вообще это важный аспект любого языка программироания
Пример
Используем группу, в которой содержатся все знаки препинания. Без агумента fixed, группа воспринимается как регулярное выражение и разбиение происходит по всем знакам препинания.
strsplit(s, "[[:punct:]]")
[[1]]
[1] "Терпение и труд все перетрут"
[[2]]
[1] "Кон" "ил дело "
[3] " гуляй смело"
[[3]]
[1] "Без труда не вытащишь и рыбку из пруда"
[[4]]
[1] "Работа не волк" " в лес не убежит"
Регулярные выражения
- “Метаязык” поиска и манипуляции подстроками, который работает сходным образом во всех языках программирования с некоторыми нюансами
- Так сделано, потому что работа со строками сложная часть программирования, которая требовала некооторой достройки, для того, чтобы с ней комфортно рабоать
- Образец для поиска может включать обычные символы и т.н. wildcards
Идея такая - есть строка, в которой нужно заменить выражение. Есть специальные функции низкоуровнего доступа к регулярным выражениям
**Пример 1 - находим вхождение строк*
grep("труд", s)
[1] 1 3
Пример 2 - находим наличие вхождение по строкам
grepl("труд", s)
[1] TRUE FALSE TRUE FALSE
Пример 3 - сложное регулярное выражение
# Аргумент 1 - находим шаблон
# Аругмент 2 - на что заменяем шаблон
# Аргумент 3 - где ищем и заменяем
gsub("\\b[[:alpha:]][4,5]\\b", "####", s )
[1] "Терпение и труд все перетрут"
[2] "Кончил дело - гуляй смело"
[3] "Без труда не вытащишь и рыбку из пруда"
[4] "Работа не волк, в лес не убежит"
У меня работает не корректно. Возможно проблема с локалью, нужно будет перепроверить на линуксе. На винде не знаю, как поправить
Пакет stringr
Работа со строками с низкоуровневыми функциями не всегда удобна. На помощь, как всегда, приходят пакеты. Удобный пакет для работы со строками - stringr
#install.packages("stringr")
library(stringr)
В пакете множество функций для работы со строками. Функции пакета векторизованы, а также они consistent (последовательны)
В чем же состоит consistency (последовательность)?:
* все функции именуются сходным образом (все начинаются с str)
* похожий порядок аргументов
* возвращают результатым единообразным способом
str_extract(s, "н.")
[1] "ни" "нч" "не" "не"
В таком варианте возвращается только первое вхождение
str_replace(s, "[иа]", "?")
[1] "Терпен?е и труд все перетрут"
[2] "Конч?л дело - гуляй смело"
[3] "Без труд? не вытащишь и рыбку из пруда"
[4] "Р?бота не волк, в лес не убежит"
Почти ко всем функциям пакета можно добавить аргумент *_all*, тогда будут возвращаться все вхождения, а не только первое
str_extract_all(s, "н.")
[[1]]
[1] "ни"
[[2]]
[1] "нч"
[[3]]
[1] "не"
[[4]]
[1] "не" "не"
str_replace_all(s, "[иае]", "?")
[1] "Т?рп?н?? ? труд вс? п?р?трут"
[2] "Конч?л д?ло - гуляй см?ло"
[3] "Б?з труд? н? выт?щ?шь ? рыбку ?з пруд?"
[4] "Р?бот? н? волк, в л?с н? уб?ж?т"
Возвращаемся к базовому R
Функции tolower/touper
Манипулирование регистром в верхний и нижний регистр. Возьмем стандартный массив данных месяцев
month.name
[1] "January" "February" "March"
[4] "April" "May" "June"
[7] "July" "August" "September"
[10] "October" "November" "December"
#
month.abb
[1] "Jan" "Feb" "Mar" "Apr" "May" "Jun"
[7] "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
tolower(month.name)
[1] "january" "february" "march"
[4] "april" "may" "june"
[7] "july" "august" "september"
[10] "october" "november" "december"
toupper(month.abb)
[1] "JAN" "FEB" "MAR" "APR" "MAY" "JUN"
[7] "JUL" "AUG" "SEP" "OCT" "NOV" "DEC"
Обрати внимание, что если к строке сначала применить toupper, а потом tolower, то результатом не обязательно будет исходная строка
Когда это может пригодится?
Пригодится может в задачах, где ожидаются входные данные от пользователя или сети, т.е. могут прийти на вход данные разного формата, например “ExIT”, “coPy” и как проверить что “ExIT” это “exit”, вот тут помогут tolower или toupper. Ещё может быть что у вас в базе свойство некоторого объекта записано в нижнем регистре, а ответ от сервера с json, где то же поле, но в верхнем регистре, а вам нужно все это дело смаппить
На что еще обратить внимание при работе со строками
Что будет, если мы посмотрим длину следующей строки?
length("Аэрофотосъёмка ландшафта уже выявила земли богачей и процветающих крестьян.")
[1] 1
Тому, кто знаком со структурой R - вывод функции length в данном случае понятен, фактически мы получаем ответ на вопрос, “а сколько здесь строк?”
Чтобы получить длину (т.е. количество символов) строки в базовом R есть функция nchar
nchar("Аэрофотосъёмка ландшафта уже выявила земли богачей и процветающих крестьян.")
[1] 75
При этом, если применить nchar к NA, то получим…
nchar(NA)
[1] NA
В функции из ответа есть логический аргумент keepNA, который сейчас по умолчанию принимает значение TRUE, а раньше (в R <=3.2.0), судя по справке, принимал значение FALSE. И возвращалось 2
Глоссарий
Функции:
* ?paste, ?paste0, ?strsplit
* ?grep, ?grepl, ?gsub
* library(stringr): ?str_extract, ?str_replace, +_all
* ?tolower, ?toupper
Задача
library(stringr)
hamlet <- "To be, or not to be: that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles,
And by opposing end them?"
hamlet <- str_replace_all(hamlet, "[:punct:]", "")
hamlet
[1] "To be or not to be that is the question\nWhether tis nobler in the mind to suffer\nThe slings and arrows of outrageous fortune\nOr to take arms against a sea of troubles\nAnd by opposing end them"
hamlet <- tolower(unlist(str_split(hamlet, "[:space:]")))
hamlet
[1] "to" "be" "or" "not" "to" "be" "that" "is"
[9] "the" "question" "whether" "tis" "nobler" "in" "the" "mind"
[17] "to" "suffer" "the" "slings" "and" "arrows" "of" "outrageous"
[25] "fortune" "or" "to" "take" "arms" "against" "a" "sea"
[33] "of" "troubles" "and" "by" "opposing" "end" "them"
Вопросы?
* Количество слов to
?str_extract
str_count(hamlet, "to")
[1] 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
sum(str_count(hamlet, "to"))
[1] 4
или
находим непосредственно номера строк
grep("to", hamlet, fixed = TRUE)
[1] 1 5 17 27
или
hamlet[grep("to", hamlet, fixed = TRUE)]
[1] "to" "to" "to" "to"
- Количество слов, содержаших любую букву из f,q,w
sum(str_count(hamlet, "[fwq]+"))
[1] 7
Насчитал вручную 8, но что-то не так, где-то, кажется, есть повтор * Количество слов, содержащих букву b, после которой - любой другой символ
str_count(hamlet, "[b.]")
[1] 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0
sum(str_count(hamlet, "[b.]"))
[1] 5
- Количество слов ровно из семи букв
sum(str_count(hamlet, "^[a-z]{7}$"))
[1] 3
Быстро разобраться с регулярными выражениями поможет https://regexone.com/lesson/introduction_abcs
Подробнее можно почитать: “Фридл - Регулярные выражения”
LS0tDQp0aXRsZTogItCh0YLRgNC+0LrQuCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIyDQodGC0YDQvtC60LgNCiog0KHRgtGA0L7QutC4IC0g0L7QtNC40L0g0LjQtyDQutC70Y7Rh9C10LLRi9GFINC+0LHRitC10LrRgtC+0LIgINCyINC70Y7QsdC+0Lwg0Y/Qt9GL0LrQtSDQv9GA0L7Qs9GA0LDQvNC80LjRgNC+0LLQsNC90LjRjyAgDQoNCiog0JIg0YDQtdCw0LvRjNC90YvRhSDQtNCw0L3QvdGL0YUg0LzQvtCz0YPRgiDQstGB0YLRgNC10YfQsNGC0YzRgdGPINGB0YLRgNC+0LrQvtCy0YvQtSDQtNCw0L3QvdGL0LUgIA0KKiDQntC/0LXRgNC40YDQvtCy0LDQvdC40LUg0LjQvNC10L3QsNC80Lgg0LIg0L/QvtC00YDQsNC30LTQtdC70LDRhSDQtNCw0YLQsNGE0YDQtdC50LzQsCAtINGB0YPRgtGMLCDRgNCw0LHQvtGC0LAg0YHQviDRgdGC0YDQvtC60L7QuQ0KDQrQmNGC0LDQuiAqKtCh0YLRgNC+0LrQsCoqOiAgDQoqICoq0KHRgtGA0L7QutCwKiogKHN0cmluZykgLSDRjdC70LXQvNC10L3RgiDQstC10LrRgtC+0YDQsCDRgtC40L/QsCBjaGFyYWN0ZXIgIA0KKiDQkdC+0LvRjNGI0LjQvdGB0YLQstC+INGE0YPQvdC60YbQuNC5LCDQvtC/0LXRgNC40YDRg9GO0YnQuNGFINC90LAg0YHRgtGA0L7QutCw0YUsINCy0LXQutGC0L7RgNC40LfQuNGA0L7QstCw0L3RiyAgDQpgYGB7cn0NCnMgPC0gYygi0KLQtdGA0L/QtdC90LjQtSDQuCDRgtGA0YPQtCDQstGB0LUg0L/QtdGA0LXRgtGA0YPRgiIsDQogICAgICAgItCa0L7QvdGH0LjQuyDQtNC10LvQviAtINCz0YPQu9GP0Lkg0YHQvNC10LvQviIsDQogICAgICAgItCR0LXQtyDRgtGA0YPQtNCwINC90LUg0LLRi9GC0LDRidC40YjRjCDQuCDRgNGL0LHQutGDINC40Lcg0L/RgNGD0LTQsCIsDQogICAgICAgItCg0LDQsdC+0YLQsCDQvdC1INCy0L7Qu9C6LCDQsiDQu9C10YEg0L3QtSDRg9Cx0LXQttC40YIiKQ0Kcw0KYGBgDQoqINCU0LvRjyDQvtCx0YrRj9Cy0LvQtdC90LjRjyDQviDQvdCw0YfQsNC70LUg0YHRgtGA0L7QutC4INC40YHQv9C+0LvRjNC30YPRjtGC0YHRjyDQt9C90LDQutC4ICoiKiDQuNC70LggKicqIC0g0LIg0LrQvtC00LUg0LjRhSDQu9GD0YfRiNC1INC90LUg0LzQtdGI0LDRgtGMLCDRgdC80LXRiNC40LLQsNC90LjQtSDQvNC+0LbQtdGCINC/0YDQuNCz0L7QtNC40YLRgdGPINCyINGB0LvRg9GH0LDQtSDQv9C+INGC0LjQv9GDICfQntC/0LXRgNCw0YbQuNGPICLQqyIgJy4g0KLQvtCz0LTQsCDQtNC70Y8g0LrQvtGA0YDQtdC60YLQvdC+0LPQviDQstGL0LLQtdC00LXQvdC40Y8g0L3Rg9C20L3QviDRjdC60YDQsNC90LjRgNC+0LLQsNGC0Ywg0LLQvdGD0YLRgNC10L3QvdC40LUg0LrQsNCy0YvRh9C60Lgg0LHRjdC60YHQu9C10YjQtdC8DQpgYGB7cn0NCmVnIDwtICfQntC/0LXRgNCw0YbQuNGPIFwi0KtcIicNCmVnDQpgYGANCtCt0LrRgNCw0L3QuNGA0L7QstCw0L3QuNC1INC/0L7QvNC+0LPQsNC10YIg0L7RgtC70LjRh9Cw0YLRjCDQvtGC0LrRgNGL0LLQsNGO0YnQuNC1INC4INC30LDQutGA0YvQstCw0Y7RidC40LUg0LrQsNCy0YvRh9C60LggDQoNCiMjIyDQpNGD0L3QutGG0LjRjyAqcGFzdGUvcGFzdGUwKg0KKiDQktGL0L/QvtC70L3Rj9Cx0YIg0LrQvtC90LrQsNGC0LXQvdCw0YbQuNGOINGB0YLRgNC+0LrQvtCy0YvRhSDQstC10LrRgtC+0YDQvtCy0L4g0YEg0YPRh9C10L7QvCDQv9GA0LDQstC40Lsg0L/QtdGA0LXQv9C40YHRi9Cy0LDQvdC40Y8gIA0KKiDQkNGA0LPRg9C80LXQvdGCICpzZXAqIC0g0YDQsNC30LTQtdC70LjRgtC10LvRjCDQvNC10LbQtNGDINGN0LvQtdC80LXQvdGC0LDQvNC4ICjQtNC70Y8gcGFzdGUg0L/QviDRg9C80L7Qu9GH0LDQvdC40Y4g0L/RgNC+0LHQtdC7LCDQtNC70Y8gcGFzdGUwIC0g0L/Rg9GB0YLQsNGPINGB0YLRgNC+0LrQsCkgIA0KKiDQkNGA0LPRg9C80LXQvdGCICpjb2xsYXBzZSogLSAi0YHRhdC70L7Qv9GL0LLQsNC10YIiINCy0LXQutGC0L7RgCDQsiDQvtC00L3RgyDRgdGC0YDQvtC60YMgIA0KDQoqKtCf0YDQuNC80LXRgCAxKioNCmBgYHtyfQ0KcGFzdGUNCmBgYA0KDQpgYGB7cn0NCnBhc3RlKGMoItGD0LPQu9C10LrRgdC40LvRi9C5IiwgItCy0LXRgdC10LvRj9GJ0LjQuSIpLCAi0LPQsNC3IikNCmBgYA0KYGBge3J9DQpwYXN0ZTANCmBgYA0KDQpgYGB7cn0NCnBhc3RlMChjKCLRg9Cz0LvQtdC60YHQuNC70YvQuSIsICLQstC10YHQtdC70Y/RidC40LkiKSwgItCz0LDQtyIpDQpgYGANCg0KYGBge3J9DQpwYXN0ZShjKCLQv9GA0L7QutCw0YDQuNC+0YLQuNGH0LXRgdC60LDRjyIsICLRjdGD0LrQsNGA0LjQvtGC0LjRh9C10YHQutCw0Y8iKSwgItC60LvQtdGC0LrQsCIpDQpgYGANCmBgYHtyfQ0KcGFzdGUoItC30LDRh9C10LwiLCAi0YLQtdCx0LUiLCAiZGF0YSBzY2llbmNlPyIpDQpgYGANCmBgYHtyfQ0KcGFzdGUwKCLQt9Cw0YfQtdC8IiwgItGC0LXQsdC1IiwgImRhdGEgc2NpZW5jZT8iKQ0KYGBgDQoNCioq0J/RgNC40LzQtdGAIDIgLSDQsNGA0LPRg9C80LXQvdGCIHNlcCoqICANCmBgYHtyfQ0KcGFzdGUoYygi0LLQtdGB0LXQu9GP0YnQuNC5IiwgItGD0LPQu9C10LrQuNGB0LvRi9C5IiksICLQs9Cw0LciLCBzZXAgPSAiXyIpDQpgYGANCtCV0YHRgtGMINC70Lgg0YDQsNC30L3QuNGG0LAg0YEgcGFzdGUwLCDQtdGB0LvQuCDQt9Cw0LTQsNGC0Ywg0YLQsNC60L7QuSDQttC1INCw0YDQs9GD0LzQtdC90YIgc2VwPw0KYGBge3J9DQpwYXN0ZTAoYygi0LLQtdGB0LXQu9GP0YnQuNC5IiwgItGD0LPQu9C10LrQuNGB0LvRi9C5IiksICLQs9Cw0LciLCBzZXAgPSAiXyIpDQpgYGANCtCU0LAsINC+0L0g0LLRgdC+0L/RgNC+0LjQt9Cy0LXQuyAqXyog0LrQsNC6INGH0LDRgdGC0Ywg0YHRgtGA0L7QutC4INCyINC60L7QvdGG0LUuINCf0L4g0LjRgtC+0LPRgywgcGFzdGUwIC0tINGN0YLQviBwYXN0ZSDRgSDQsNGA0LPRg9C80LXQvdGC0L7QvCBzZXAgPSAiIg0KDQojIyMg0KTRg9C90LrRhtC40Y8gKnN0cnNwbGl0KiAtINGA0LDQt9Cx0LjQtdC90LjQtQ0KKiDQktGL0L/QvtC70L3Rj9C10YIg0YDQsNC30LHQuNC10L3QuNC1INGB0YLRgNC+0LrQvtCy0L7Qs9C+INCy0LXQutGC0L7RgNCwICANCiog0KDQtdC30YPQu9GM0YLQsNGCIC0g0YHQv9C40YHQvtC6IA0KYGBge3J9DQpzdHJzcGxpdA0KYGBgDQoqKk4uQiEqKiDQntCx0YDQsNGC0Lgg0LLQvdC40LzQsNC90LjQtSwg0YfRgtC+INC/0YDQvtCx0LXQu9GLLCDQt9Cw0LrQu9GO0YfQtdC90L3Ri9C1INCyINC60LDQstGL0YfQutC4LCDQvdC10YHRg9GCINGB0LzRi9GB0LvQvtCy0YPRjiDQvdCw0LPRgNGD0LfQutGDLi4uDQpgYGB7cn0NCnN0cnNwbGl0KHMsIiDQuCAiLCBmaXhlZCA9IFRSVUUpDQpgYGANCi4uLtC40L3QsNGH0LUg0YDQsNC30LHQuNC10L3QuNC1INGI0LvQviDQsdGLINC10YnQtSDQuCDQstC90YPRgtGA0Lgg0YHQu9C+0LINCmBgYHtyfQ0Kc3Ryc3BsaXQocywi0LgiLCBmaXhlZCA9IFRSVUUpDQpgYGANCioq0JDRgNCz0YPQvNC10L3RgiBmaXhlZCoqICANCtCV0YHQu9C4INC10LPQviDQvdC1INGD0LrQsNC30YvQstCw0YLRjCAo0L/QviDRg9C80L7Qu9GH0LDQvdC40Y4gRkFMU0UpLCDRgtC+INGB0YLRgNC+0LrQsCDQv9C+INC60L7RgtC+0YDQvtC5INC/0YDQvtCy0L7QtNC40YLRgdGPINGA0LDQt9Cx0LjQtdC90LjQtSwg0LHRg9C00LXRgiDRgNCw0YHRgdC80LDRgtGA0LjQstCw0YLRjNGB0Y8g0LrQsNC6ICrRgNC10LPRg9C70Y/RgNC90L7QtSDQstGL0YDQsNC20LXQvdC40LUqLiDQn9GA0L4gKirRgNC10LPRg9C70Y/RgNC90YvQtSDQstGL0YDQsNC20LXQvdC40Y8qKiDQtNCw0LvRjNGI0LUuINCS0L7QvtCx0YnQtSDRjdGC0L4g0LLQsNC20L3Ri9C5INCw0YHQv9C10LrRgiDQu9GO0LHQvtCz0L4g0Y/Qt9GL0LrQsCDQv9GA0L7Qs9GA0LDQvNC80LjRgNC+0LDQvdC40Y8gIA0KKirQn9GA0LjQvNC10YAqKiAgDQrQmNGB0L/QvtC70YzQt9GD0LXQvCDQs9GA0YPQv9C/0YMsINCyINC60L7RgtC+0YDQvtC5INGB0L7QtNC10YDQttCw0YLRgdGPINCy0YHQtSDQt9C90LDQutC4INC/0YDQtdC/0LjQvdCw0L3QuNGPLiDQkdC10Lcg0LDQs9GD0LzQtdC90YLQsCBmaXhlZCwg0LPRgNGD0L/Qv9CwINCy0L7RgdC/0YDQuNC90LjQvNCw0LXRgtGB0Y8g0LrQsNC6INGA0LXQs9GD0LvRj9GA0L3QvtC1INCy0YvRgNCw0LbQtdC90LjQtSDQuCDRgNCw0LfQsdC40LXQvdC40LUg0L/RgNC+0LjRgdGF0L7QtNC40YIg0L/QviDQstGB0LXQvCDQt9C90LDQutCw0Lwg0L/RgNC10L/QuNC90LDQvdC40Y8uDQpgYGB7cn0NCnN0cnNwbGl0KHMsICJbWzpwdW5jdDpdXSIpDQpgYGANCg0KIyMg0KDQtdCz0YPQu9GP0YDQvdGL0LUg0LLRi9GA0LDQttC10L3QuNGPIA0KKiAi0JzQtdGC0LDRj9C30YvQuiIg0L/QvtC40YHQutCwINC4INC80LDQvdC40L/Rg9C70Y/RhtC40Lgg0L/QvtC00YHRgtGA0L7QutCw0LzQuCwg0LrQvtGC0L7RgNGL0Lkg0YDQsNCx0L7RgtCw0LXRgiDRgdGF0L7QtNC90YvQvCDQvtCx0YDQsNC30L7QvCDQstC+INCy0YHQtdGFINGP0LfRi9C60LDRhSDQv9GA0L7Qs9GA0LDQvNC80LjRgNC+0LLQsNC90LjRjyDRgSDQvdC10LrQvtGC0L7RgNGL0LzQuCDQvdGO0LDQvdGB0LDQvNC4ICANCiog0KLQsNC6INGB0LTQtdC70LDQvdC+LCDQv9C+0YLQvtC80YMg0YfRgtC+INGA0LDQsdC+0YLQsCDRgdC+INGB0YLRgNC+0LrQsNC80Lgg0YHQu9C+0LbQvdCw0Y8g0YfQsNGB0YLRjCDQv9GA0L7Qs9GA0LDQvNC80LjRgNC+0LLQsNC90LjRjywg0LrQvtGC0L7RgNCw0Y8g0YLRgNC10LHQvtCy0LDQu9CwINC90LXQutC+0L7RgtC+0YDQvtC5INC00L7RgdGC0YDQvtC50LrQuCwg0LTQu9GPINGC0L7Qs9C+LCDRh9GC0L7QsdGLINGBINC90LXQuSDQutC+0LzRhNC+0YDRgtC90L4g0YDQsNCx0L7QsNGC0YwgIA0KKiDQntCx0YDQsNC30LXRhiDQtNC70Y8g0L/QvtC40YHQutCwINC80L7QttC10YIg0LLQutC70Y7Rh9Cw0YLRjCDQvtCx0YvRh9C90YvQtSDRgdC40LzQstC+0LvRiyDQuCDRgi7QvS4gKndpbGRjYXJkcyogIA0K0JjQtNC10Y8g0YLQsNC60LDRjyAtINC10YHRgtGMINGB0YLRgNC+0LrQsCwg0LIg0LrQvtGC0L7RgNC+0Lkg0L3Rg9C20L3QviDQt9Cw0LzQtdC90LjRgtGMINCy0YvRgNCw0LbQtdC90LjQtS4g0JXRgdGC0Ywg0YHQv9C10YbQuNCw0LvRjNC90YvQtSDRhNGD0L3QutGG0LjQuCDQvdC40LfQutC+0YPRgNC+0LLQvdC10LPQviDQtNC+0YHRgtGD0L/QsCDQuiDRgNC10LPRg9C70Y/RgNC90YvQvCDQstGL0YDQsNC20LXQvdC40Y/QvCAgDQoqKtCf0YDQuNC80LXRgCAxIC0g0L3QsNGF0L7QtNC40Lwg0LLRhdC+0LbQtNC10L3QuNC1INGB0YLRgNC+0LoqDQpgYGB7cn0NCmdyZXAoItGC0YDRg9C0IiwgcykNCmBgYA0KKirQn9GA0LjQvNC10YAgMiAtINC90LDRhdC+0LTQuNC8INC90LDQu9C40YfQuNC1INCy0YXQvtC20LTQtdC90LjQtSDQv9C+INGB0YLRgNC+0LrQsNC8KioNCmBgYHtyfQ0KZ3JlcGwoItGC0YDRg9C0IiwgcykNCmBgYA0KKirQn9GA0LjQvNC10YAgMyAtINGB0LvQvtC20L3QvtC1INGA0LXQs9GD0LvRj9GA0L3QvtC1INCy0YvRgNCw0LbQtdC90LjQtSoqDQpgYGB7cn0NCiMg0JDRgNCz0YPQvNC10L3RgiAxIC0g0L3QsNGF0L7QtNC40Lwg0YjQsNCx0LvQvtC9DQojINCQ0YDRg9Cz0LzQtdC90YIgMiAtINC90LAg0YfRgtC+INC30LDQvNC10L3Rj9C10Lwg0YjQsNCx0LvQvtC9ICANCiMg0JDRgNCz0YPQvNC10L3RgiAzIC0g0LPQtNC1INC40YnQtdC8INC4INC30LDQvNC10L3Rj9C10LwNCmdzdWIoIlxcYltbOmFscGhhOl1dWzQsNV1cXGIiLCAiIyMjIyIsIHMgKQ0KYGBgDQrQoyDQvNC10L3RjyDRgNCw0LHQvtGC0LDQtdGCINC90LUg0LrQvtGA0YDQtdC60YLQvdC+LiDQktC+0LfQvNC+0LbQvdC+INC/0YDQvtCx0LvQtdC80LAg0YEg0LvQvtC60LDQu9GM0Y4sINC90YPQttC90L4g0LHRg9C00LXRgiDQv9C10YDQtdC/0YDQvtCy0LXRgNC40YLRjCDQvdCwINC70LjQvdGD0LrRgdC1LiDQndCwINCy0LjQvdC00LUg0L3QtSDQt9C90LDRjiwg0LrQsNC6INC/0L7Qv9GA0LDQstC40YLRjCAgDQoNCiMjINCf0LDQutC10YIgKnN0cmluZ3IqICANCtCg0LDQsdC+0YLQsCDRgdC+INGB0YLRgNC+0LrQsNC80Lgg0YEg0L3QuNC30LrQvtGD0YDQvtCy0L3QtdCy0YvQvNC4INGE0YPQvdC60YbQuNGP0LzQuCDQvdC1INCy0YHQtdCz0LTQsCDRg9C00L7QsdC90LAuINCd0LAg0L/QvtC80L7RidGMLCDQutCw0Log0LLRgdC10LPQtNCwLCDQv9GA0LjRhdC+0LTRj9GCINC/0LDQutC10YLRiy4g0KPQtNC+0LHQvdGL0Lkg0L/QsNC60LXRgiDQtNC70Y8g0YDQsNCx0L7RgtGLINGB0L4g0YHRgtGA0L7QutCw0LzQuCAtICpzdHJpbmdyKiAgDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJzdHJpbmdyIikNCmxpYnJhcnkoc3RyaW5ncikNCmBgYA0K0JIg0L/QsNC60LXRgtC1INC80L3QvtC20LXRgdGC0LLQviDRhNGD0L3QutGG0LjQuSDQtNC70Y8g0YDQsNCx0L7RgtGLINGB0L4g0YHRgtGA0L7QutCw0LzQuC4g0KTRg9C90LrRhtC40Lgg0L/QsNC60LXRgtCwINCy0LXQutGC0L7RgNC40LfQvtCy0LDQvdGLLCDQsCDRgtCw0LrQttC1INC+0L3QuCAqY29uc2lzdGVudCogKNC/0L7RgdC70LXQtNC+0LLQsNGC0LXQu9GM0L3RiykgIA0K0JIg0YfQtdC8INC20LUg0YHQvtGB0YLQvtC40YIgY29uc2lzdGVuY3kgKNC/0L7RgdC70LXQtNC+0LLQsNGC0LXQu9GM0L3QvtGB0YLRjCk/OiAgDQoqINCy0YHQtSDRhNGD0L3QutGG0LjQuCDQuNC80LXQvdGD0Y7RgtGB0Y8g0YHRhdC+0LTQvdGL0Lwg0L7QsdGA0LDQt9C+0LwgKNCy0YHQtSDQvdCw0YfQuNC90LDRjtGC0YHRjyDRgSAqc3RyKikgIA0KKiDQv9C+0YXQvtC20LjQuSDQv9C+0YDRj9C00L7QuiDQsNGA0LPRg9C80LXQvdGC0L7QsiAgDQoqINCy0L7Qt9Cy0YDQsNGJ0LDRjtGCINGA0LXQt9GD0LvRjNGC0LDRgtGL0Lwg0LXQtNC40L3QvtC+0LHRgNCw0LfQvdGL0Lwg0YHQv9C+0YHQvtCx0L7QvCANCmBgYHtyfQ0KIyDRgtC+0YfQutCwINC/0L7RgdC70LUg0L0gLSDRjdGC0L4g0Lgg0LXRgdGC0Ywgd2lsZGNhcmQsINGCLtC1LiDQstC+0LfQstGA0LDRidCw0LXQvCAi0L0iINC4INC70Y7QsdC+0Lkg0LTRgNGD0LPQvtC5INGB0LjQvNCy0L7Quywg0LjQtNGD0YnQuNC5INGBICLQvSINCnN0cl9leHRyYWN0KHMsICLQvS4iKQ0KYGBgDQrQkiDRgtCw0LrQvtC8INCy0LDRgNC40LDQvdGC0LUg0LLQvtC30LLRgNCw0YnQsNC10YLRgdGPINGC0L7Qu9GM0LrQviDQv9C10YDQstC+0LUg0LLRhdC+0LbQtNC10L3QuNC1DQpgYGB7cn0NCiMg0JzQtdC90Y/QtdC8INGB0LjQvNCy0L7Qu9GLINC70LjQsdC+ICLQuCIsINC70LjQsdC+ICLQsCIg0L3QsCDQt9C90LDQuiDQstC+0L/RgNC+0YHQsA0Kc3RyX3JlcGxhY2UocywgIlvQuNCwXSIsICI/IikNCmBgYA0K0J/QvtGH0YLQuCDQutC+INCy0YHQtdC8INGE0YPQvdC60YbQuNGP0Lwg0L/QsNC60LXRgtCwINC80L7QttC90L4g0LTQvtCx0LDQstC40YLRjCDQsNGA0LPRg9C80LXQvdGCICpfYWxsKiwg0YLQvtCz0LTQsCDQsdGD0LTRg9GCINCy0L7Qt9Cy0YDQsNGJ0LDRgtGM0YHRjyDQstGB0LUg0LLRhdC+0LbQtNC10L3QuNGPLCDQsCDQvdC1INGC0L7Qu9GM0LrQviDQv9C10YDQstC+0LUgDQpgYGB7cn0NCnN0cl9leHRyYWN0X2FsbChzLCAi0L0uIikNCmBgYA0KYGBge3J9DQpzdHJfcmVwbGFjZV9hbGwocywgIlvQuNCw0LVdIiwgIj8iKQ0KYGBgDQoNCtCS0L7Qt9Cy0YDQsNGJ0LDQtdC80YHRjyDQuiDQsdCw0LfQvtCy0L7QvNGDIFINCg0KIyMjINCk0YPQvdC60YbQuNC4ICp0b2xvd2VyL3RvdXBlcioNCtCc0LDQvdC40L/Rg9C70LjRgNC+0LLQsNC90LjQtSDRgNC10LPQuNGB0YLRgNC+0Lwg0LIg0LLQtdGA0YXQvdC40Lkg0Lgg0L3QuNC20L3QuNC5INGA0LXQs9C40YHRgtGALiDQktC+0LfRjNC80LXQvCDRgdGC0LDQvdC00LDRgNGC0L3Ri9C5INC80LDRgdGB0LjQsiDQtNCw0L3QvdGL0YUg0LzQtdGB0Y/RhtC10LIgDQpgYGB7cn0NCiMg0J3QsNGH0LjQvdCw0LXRgtGB0Y8g0YEg0LfQsNCz0LvQsNCy0L3QvtC5INCx0YPQutCy0YsNCm1vbnRoLm5hbWUNCmBgYA0KYGBge3J9DQojINCi0LDQuiDQttC1INC90LDRh9C40L3QsNC10YLRgdGPINGBINC30LDQs9C70LDQstC90L7QuQ0KbW9udGguYWJiDQpgYGANCmBgYHtyfQ0KdG9sb3dlcihtb250aC5uYW1lKQ0KYGBgDQpgYGB7cn0NCnRvdXBwZXIobW9udGguYWJiKQ0KYGBgDQrQntCx0YDQsNGC0Lgg0LLQvdC40LzQsNC90LjQtSwg0YfRgtC+INC10YHQu9C4INC6INGB0YLRgNC+0LrQtSDRgdC90LDRh9Cw0LvQsCDQv9GA0LjQvNC10L3QuNGC0YwgdG91cHBlciwg0LAg0L/QvtGC0L7QvCB0b2xvd2VyLCDRgtC+INGA0LXQt9GD0LvRjNGC0LDRgtC+0Lwg0L3QtSDQvtCx0Y/Qt9Cw0YLQtdC70YzQvdC+INCx0YPQtNC10YIg0LjRgdGF0L7QtNC90LDRjyDRgdGC0YDQvtC60LAgIA0KDQoNCioq0JrQvtCz0LTQsCDRjdGC0L4g0LzQvtC20LXRgiDQv9GA0LjQs9C+0LTQuNGC0YHRjz8qKiAgDQrQn9GA0LjQs9C+0LTQuNGC0YHRjyDQvNC+0LbQtdGCINCyINC30LDQtNCw0YfQsNGFLCDQs9C00LUg0L7QttC40LTQsNGO0YLRgdGPINCy0YXQvtC00L3Ri9C1INC00LDQvdC90YvQtSDQvtGCINC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjyDQuNC70Lgg0YHQtdGC0LgsINGCLtC1LiDQvNC+0LPRg9GCINC/0YDQuNC50YLQuCDQvdCwINCy0YXQvtC0INC00LDQvdC90YvQtSDRgNCw0LfQvdC+0LPQviDRhNC+0YDQvNCw0YLQsCwg0L3QsNC/0YDQuNC80LXRgCAiRXhJVCIsICJjb1B5IiDQuCDQutCw0Log0L/RgNC+0LLQtdGA0LjRgtGMINGH0YLQviAgIkV4SVQiINGN0YLQviAiZXhpdCIsINCy0L7RgiDRgtGD0YIg0L/QvtC80L7Qs9GD0YIgIHRvbG93ZXIg0LjQu9C4IHRvdXBwZXIuINCV0YnRkSDQvNC+0LbQtdGCINCx0YvRgtGMINGH0YLQviDRgyDQstCw0YEg0LIg0LHQsNC30LUg0YHQstC+0LnRgdGC0LLQviDQvdC10LrQvtGC0L7RgNC+0LPQviDQvtCx0YrQtdC60YLQsCDQt9Cw0L/QuNGB0LDQvdC+INCyINC90LjQttC90LXQvCDRgNC10LPQuNGB0YLRgNC1LCDQsCDQvtGC0LLQtdGCINC+0YIg0YHQtdGA0LLQtdGA0LAg0YEganNvbiwg0LPQtNC1INGC0L4g0LbQtSDQv9C+0LvQtSwg0L3QviDQsiDQstC10YDRhdC90LXQvCDRgNC10LPQuNGB0YLRgNC1LCDQsCDQstCw0Lwg0L3Rg9C20L3QviDQstGB0LUg0Y3RgtC+INC00LXQu9C+INGB0LzQsNC/0L/QuNGC0YwNCg0KIyMjINCd0LAg0YfRgtC+INC10YnQtSDQvtCx0YDQsNGC0LjRgtGMINCy0L3QuNC80LDQvdC40LUg0L/RgNC4INGA0LDQsdC+0YLQtSDRgdC+INGB0YLRgNC+0LrQsNC80LgNCtCn0YLQviDQsdGD0LTQtdGCLCDQtdGB0LvQuCDQvNGLINC/0L7RgdC80L7RgtGA0LjQvCDQtNC70LjQvdGDINGB0LvQtdC00YPRjtGJ0LXQuSDRgdGC0YDQvtC60Lg/DQpgYGB7cn0NCmxlbmd0aCgi0JDRjdGA0L7RhNC+0YLQvtGB0YrRkdC80LrQsCDQu9Cw0L3QtNGI0LDRhNGC0LAg0YPQttC1INCy0YvRj9Cy0LjQu9CwINC30LXQvNC70Lgg0LHQvtCz0LDRh9C10Lkg0Lgg0L/RgNC+0YbQstC10YLQsNGO0YnQuNGFINC60YDQtdGB0YLRjNGP0L0uIikNCmBgYA0K0KLQvtC80YMsINC60YLQviDQt9C90LDQutC+0Lwg0YHQviDRgdGC0YDRg9C60YLRg9GA0L7QuSBSIC0g0LLRi9Cy0L7QtCDRhNGD0L3QutGG0LjQuCBsZW5ndGgg0LIg0LTQsNC90L3QvtC8INGB0LvRg9GH0LDQtSDQv9C+0L3Rj9GC0LXQvSwg0YTQsNC60YLQuNGH0LXRgdC60Lgg0LzRiyDQv9C+0LvRg9GH0LDQtdC8INC+0YLQstC10YIg0L3QsCDQstC+0L/RgNC+0YEsICLQsCDRgdC60L7Qu9GM0LrQviDQt9C00LXRgdGMINGB0YLRgNC+0Lo/IiAgDQogIA0K0KfRgtC+0LHRiyDQv9C+0LvRg9GH0LjRgtGMINC00LvQuNC90YMgKNGCLtC1LiDQutC+0LvQuNGH0LXRgdGC0LLQviDRgdC40LzQstC+0LvQvtCyKSDRgdGC0YDQvtC60Lgg0LIg0LHQsNC30L7QstC+0LwgUiDQtdGB0YLRjCDRhNGD0L3QutGG0LjRjyAqbmNoYXIqDQpgYGB7cn0NCm5jaGFyKCLQkNGN0YDQvtGE0L7RgtC+0YHRitGR0LzQutCwINC70LDQvdC00YjQsNGE0YLQsCDRg9C20LUg0LLRi9GP0LLQuNC70LAg0LfQtdC80LvQuCDQsdC+0LPQsNGH0LXQuSDQuCDQv9GA0L7RhtCy0LXRgtCw0Y7RidC40YUg0LrRgNC10YHRgtGM0Y/QvS4iKQ0KYGBgDQrQn9GA0Lgg0Y3RgtC+0LwsINC10YHQu9C4INC/0YDQuNC80LXQvdC40YLRjCBuY2hhciDQuiBOQSwg0YLQviDQv9C+0LvRg9GH0LjQvC4uLg0KYGBge3J9DQpuY2hhcihOQSkNCmBgYA0K0JIg0YTRg9C90LrRhtC40Lgg0LjQtyDQvtGC0LLQtdGC0LAg0LXRgdGC0Ywg0LvQvtCz0LjRh9C10YHQutC40Lkg0LDRgNCz0YPQvNC10L3RgiBrZWVwTkEsINC60L7RgtC+0YDRi9C5INGB0LXQudGH0LDRgSDQv9C+INGD0LzQvtC70YfQsNC90LjRjiDQv9GA0LjQvdC40LzQsNC10YIg0LfQvdCw0YfQtdC90LjQtSBUUlVFLCDQsCDRgNCw0L3RjNGI0LUgKNCyIFIgPD0zLjIuMCksINGB0YPQtNGPINC/0L4g0YHQv9GA0LDQstC60LUsINC/0YDQuNC90LjQvNCw0Lsg0LfQvdCw0YfQtdC90LjQtSBGQUxTRS4g0Jgg0LLQvtC30LLRgNCw0YnQsNC70L7RgdGMIDINCg0KIyMjINCT0LvQvtGB0YHQsNGA0LjQuSAgDQrQpNGD0L3QutGG0LjQuDogIA0KKiA/cGFzdGUsID9wYXN0ZTAsID9zdHJzcGxpdCAgDQoqID9ncmVwLCA/Z3JlcGwsICA/Z3N1YiAgDQoqIGxpYnJhcnkoc3RyaW5ncik6ID9zdHJfZXh0cmFjdCwgP3N0cl9yZXBsYWNlLCArX2FsbCAgDQoqID90b2xvd2VyLCA/dG91cHBlciAgIA0KICANCiAgICANCiMjIyDQl9Cw0LTQsNGH0LAgDQpgYGB7cn0NCmxpYnJhcnkoc3RyaW5ncikNCg0KaGFtbGV0IDwtICJUbyBiZSwgb3Igbm90IHRvIGJlOiB0aGF0IGlzIHRoZSBxdWVzdGlvbjoNCldoZXRoZXIgJ3RpcyBub2JsZXIgaW4gdGhlIG1pbmQgdG8gc3VmZmVyDQpUaGUgc2xpbmdzIGFuZCBhcnJvd3Mgb2Ygb3V0cmFnZW91cyBmb3J0dW5lLA0KT3IgdG8gdGFrZSBhcm1zIGFnYWluc3QgYSBzZWEgb2YgdHJvdWJsZXMsDQpBbmQgYnkgb3Bwb3NpbmcgZW5kIHRoZW0/Ig0KDQoNCmBgYA0KDQpgYGB7cn0NCmhhbWxldCA8LSBzdHJfcmVwbGFjZV9hbGwoaGFtbGV0LCAiWzpwdW5jdDpdIiwgIiIpDQpoYW1sZXQNCg0KYGBgDQoNCmBgYHtyfQ0KaGFtbGV0IDwtIHRvbG93ZXIodW5saXN0KHN0cl9zcGxpdChoYW1sZXQsICJbOnNwYWNlOl0iKSkpDQpoYW1sZXQNCmBgYA0K0JLQvtC/0YDQvtGB0Ys/ICANCiog0JrQvtC70LjRh9C10YHRgtCy0L4g0YHQu9C+0LIgKnRvKiAgDQpgYGB7cn0NCj9zdHJfZXh0cmFjdA0Kc3RyX2NvdW50KGhhbWxldCwgInRvIikNCnN1bShzdHJfY291bnQoaGFtbGV0LCAidG8iKSkNCmBgYA0KKtC40LvQuCogIA0K0L3QsNGF0L7QtNC40Lwg0L3QtdC/0L7RgdGA0LXQtNGB0YLQstC10L3QvdC+INC90L7QvNC10YDQsCDRgdGC0YDQvtC6DQpgYGB7cn0NCmdyZXAoInRvIiwgaGFtbGV0LCBmaXhlZCA9IFRSVUUpDQpgYGANCirQuNC70LgqICANCmBgYHtyfQ0KaGFtbGV0W2dyZXAoInRvIiwgaGFtbGV0LCBmaXhlZCA9IFRSVUUpXQ0KYGBgDQoqINCa0L7Qu9C40YfQtdGB0YLQstC+INGB0LvQvtCyLCDRgdC+0LTQtdGA0LbQsNGI0LjRhSDQu9GO0LHRg9GOINCx0YPQutCy0YMg0LjQtyBmLHEsdyAgDQpgYGB7cn0NCnN1bShzdHJfY291bnQoaGFtbGV0LCAiW2Z3cV0rIikpDQpgYGANCg0K0J3QsNGB0YfQuNGC0LDQuyDQstGA0YPRh9C90YPRjiA4LCDQvdC+INGH0YLQvi3RgtC+INC90LUg0YLQsNC6LCDQs9C00LUt0YLQviwg0LrQsNC20LXRgtGB0Y8sINC10YHRgtGMINC/0L7QstGC0L7RgA0KKiDQmtC+0LvQuNGH0LXRgdGC0LLQviDRgdC70L7Qsiwg0YHQvtC00LXRgNC20LDRidC40YUg0LHRg9C60LLRgyBiLCDQv9C+0YHQu9C1INC60L7RgtC+0YDQvtC5IC0g0LvRjtCx0L7QuSDQtNGA0YPQs9C+0Lkg0YHQuNC80LLQvtC7ICAgIA0KYGBge3J9DQpzdHJfY291bnQoaGFtbGV0LCAiW2IuXSIpDQpzdW0oc3RyX2NvdW50KGhhbWxldCwgIltiLl0iKSkNCmBgYA0KDQoqINCa0L7Qu9C40YfQtdGB0YLQstC+INGB0LvQvtCyINGA0L7QstC90L4g0LjQtyDRgdC10LzQuCDQsdGD0LrQsg0KYGBge3J9DQpzdW0oc3RyX2NvdW50KGhhbWxldCwgIl5bYS16XXs3fSQiKSkNCmBgYA0K0JHRi9GB0YLRgNC+INGA0LDQt9C+0LHRgNCw0YLRjNGB0Y8g0YEg0YDQtdCz0YPQu9GP0YDQvdGL0LzQuCDQstGL0YDQsNC20LXQvdC40Y/QvNC4INC/0L7QvNC+0LbQtdGCIGh0dHBzOi8vcmVnZXhvbmUuY29tL2xlc3Nvbi9pbnRyb2R1Y3Rpb25fYWJjcyAgDQogIA0K0J/QvtC00YDQvtCx0L3QtdC1INC80L7QttC90L4g0L/QvtGH0LjRgtCw0YLRjDogItCk0YDQuNC00LsgLSDQoNC10LPRg9C70Y/RgNC90YvQtSDQstGL0YDQsNC20LXQvdC40Y8iDQoNCg0KDQo=