Задание 1
Я возьму датасет mtcars. Установлю необходимые библиотеки и
импортирую его.
library(reticulate)
py_install("pandas")
py_install("seaborn")
import pandas as pd
import seaborn as sns
df = pd.read_csv(
"https://raw.githubusercontent.com/selva86/datasets/master/mtcars.csv"
)
Задание 2
Разведочный анализ
Общая информация:
print(df.shape)
print(df.info())
(32, 14)
<class 'pandas.DataFrame'>
RangeIndex: 32 entries, 0 to 31
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 mpg 32 non-null float64
1 cyl 32 non-null int64
2 disp 32 non-null float64
3 hp 32 non-null int64
4 drat 32 non-null float64
5 wt 32 non-null float64
6 qsec 32 non-null float64
7 vs 32 non-null int64
8 am 32 non-null int64
9 gear 32 non-null int64
10 carb 32 non-null int64
11 fast 32 non-null int64
12 cars 32 non-null str
13 carname 32 non-null str
dtypes: float64(5), int64(7), str(2)
memory usage: 3.6 KB
None
Таким образом, имеем таблицу с 14 столбцами, 5 с вещественными
значениями, 7 с целочисленными, 2 со строковыми.
Описательная статистика:
print(df.describe())
mpg cyl disp ... gear carb fast
count 32.000000 32.000000 32.000000 ... 32.000000 32.0000 32.000000
mean 4.434770 6.187500 230.721875 ... 3.687500 2.8125 0.687500
std 0.661137 1.785922 123.938694 ... 0.737804 1.6152 0.470929
min 3.224903 4.000000 71.100000 ... 3.000000 1.0000 0.000000
25% 3.927432 4.000000 120.825000 ... 3.000000 2.0000 0.000000
50% 4.381780 6.000000 196.300000 ... 4.000000 2.0000 1.000000
75% 4.774935 8.000000 326.000000 ... 4.000000 4.0000 1.000000
max 5.822371 8.000000 472.000000 ... 5.000000 8.0000 1.000000
[8 rows x 12 columns]
Всего имеем 32 строки, показаны среднее, стандартное отклонение,
квартили, минимумы и максимумы.
Проверка пропусков:
print(df.isnull().sum())
Как видно, пропусков нет.
Проаназирую конкретные показатели.
Исследую распредения расхода топлива mpg (сколько миль может проехать
автомобиль на 1 галлоне топлива).
import matplotlib.pyplot as plt
plt.figure(figsize=(8,5))
sns.histplot(df["mpg"], bins=8, kde=True)
plt.title("Распределение расхода топлива")
plt.show()

Вывод: большинство автомобилей проезжают 4,5-4,8
миль за галлон.
Исследую зависимость расхода автомобиля от его массы.
plt.figure(figsize=(8,5))
sns.scatterplot(
data=df,
x="wt",
y="mpg"
)
plt.title("Зависимость расхода топлива от массы автомобиля")
plt.show()

Вывод: с увеличением массы автомобиля ухудшается его
расход.
Исследую связь кол-ва циллиндров с расходом топлива:
plt.figure(figsize=(8,5))
sns.boxplot(
data=df,
x="cyl",
y="mpg"
)
plt.title("Расход топлива для автомобилей с разным числом цилиндров")
plt.show()

Вывод: чем меньше циллиндров, тем меньше расход.
Исследую корреляционную матрицу.
plt.figure(figsize=(12,10))
sns.heatmap(
df.corr(numeric_only=True),
annot=True,
cmap="coolwarm",
fmt=".2f"
)
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)
plt.show()

Вывод: расход (mpg) отрицательно коррелирует с
массой (wt), расход (mpg) также отрицательно коррелирует с количеством
лошадиных сил (hp), а лошадиных сил (hp) положительно коррелирует с
количеством цилиндров (cyl).
Задание 3
Бустрэп - это метод исследования распределения
статистик, основанный на многократной генерации выборок на базе
имеющейся выборки.
Начну с реализации бутстрэпа на Python.
В моём датасете я разделю автомобили на две группы (с 4 цилиндрами и
8 цилиндрами), сравню расход топлива (mpg), и бутстрапом оценю
доверительный интервал для разницы.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Загрузка данных
df = pd.read_csv(
"https://raw.githubusercontent.com/selva86/datasets/master/mtcars.csv"
)
# Группы для сравнения
values_a = df[df["cyl"] == 4]["mpg"].values
values_b = df[df["cyl"] == 8]["mpg"].values
# Функция построения доверительного интервала
def get_percentile_ci(bootstrap_stats, alpha):
left, right = np.quantile(
bootstrap_stats,
[alpha / 2, 1 - alpha / 2]
)
return left, right
# параметры бутстрапа
B = 10000
alpha = 0.05
# разница средних
pe = np.mean(values_b) - np.mean(values_a)
bootstrap_stats = []
for _ in range(B):
sample_a = np.random.choice(
values_a,
size=len(values_a),
replace=True
)
sample_b = np.random.choice(
values_b,
size=len(values_b),
replace=True
)
stat = np.mean(sample_b) - np.mean(sample_a)
bootstrap_stats.append(stat)
bootstrap_stats = np.array(bootstrap_stats)
ci = get_percentile_ci(
bootstrap_stats,
alpha
)
has_effect = not (ci[0] < 0 < ci[1])
print(f"Среднее mpg для 4 цилиндров:, {np.mean(values_a):.2f}")
print(f"Среднее mpg для 8 цилиндров: {np.mean(values_b):.2f}")
print(f"Разница средних mpg: {pe:.2f}")
print(f"95% ДИ: ({ci[0]:.2f}; {ci[1]:.2f})")
print(f"Различия статистически значимы: {has_effect}")
print(f"\nДополнительная информация:")
print(f"Стандартная ошибка (SE): {bootstrap_stats.std():.3f}")
print(f"Смещение (bias): {bootstrap_stats.mean() - pe:.3f}")
print(f"Коэффициент вариации: {bootstrap_stats.std() / abs(pe):.3f}")
Среднее mpg для 4 цилиндров:, 5.15
Среднее mpg для 8 цилиндров: 3.87
Разница средних mpg: -1.27
95% ДИ: (-1.57; -0.99)
Различия статистически значимы: True
Дополнительная информация:
Стандартная ошибка (SE): 0.151
Смещение (bias): 0.000
Коэффициент вариации: 0.118
plt.figure(figsize=(8,6))
sns.boxplot(
data=df[df["cyl"].isin([4, 8])],
x="cyl",
y="mpg"
)
plt.title(
"Расход топлива у автомобилей с 4 и 8 цилиндрами"
)
plt.xlabel("Число цилиндров")
plt.ylabel("MPG")
plt.show()

Вывод: В качестве исследовалась переменная mpg.
Выполнено 10000 бутстрап-перевыборок с возвращением, после чего для
каждой выборки вычислялась разность средних значений.
Полученная оценка разности средних составила -1.27. Построенный 95%-й
доверительный интервал равен (-1.57; -0.99). Поскольку доверительный
интервал не содержит нулевое значение, различия между группами являются
статистически значимыми.
Стандартная ошибка оценки составила 0.151, что свидетельствует о
достаточно высокой устойчивости результата. Смещение (bias) отсутствует
и равно 0.000, следовательно бутстрап-оценка не демонстрирует
систематического отклонения. Коэффициент вариации составил 0.118, что
указывает на умеренную изменчивость полученных оценок.
Задание 4
Реализую теперь бутстрэп на R.
Линейная регрессия позволяет оценить зависимость одной переменной от
другой.
Коэффициент детерминации R^2 показывает, какую долю вариации
зависимой переменной объясняет модель.
Бутстрап позволяет оценить устойчивость оценки R^2, стандартную
ошибку, а также доверительный интервал.
Производить буду бутстрапирование коэффициента детерминации для
модели mpg~disp.
set.seed(0)
library(boot)
# функция расчета R^2
rsq_function <- function(formula, data, indices){
d <- data[indices, ]
fit <- lm(formula, data = d)
return(summary(fit)$r.squared)
}
# бутстрап
reps <- boot(
data = mtcars,
statistic = rsq_function,
R = 5000,
formula = mpg ~ disp
)
reps
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = mtcars, statistic = rsq_function, R = 5000, formula = mpg ~
disp)
Bootstrap Statistics :
original bias std. error
t1* 0.7183433 0.003270593 0.06413799
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = mtcars, statistic = rsq_function, R = 5000, formula = mpg ~
disp)
Bootstrap Statistics :
original bias std. error
t1* 0.7183433 0.003270593 0.06413799
График №1. Распределение бутстрап-оценок
hist(
reps$t,
breaks = 30,
col = "lightblue",
main = "Bootstrap distribution of R²",
xlab = "R²"
)
abline(
v = reps$t0,
col = "red",
lwd = 3
)

Красная линия показывает исходное значение
R^2.
График №2. QQ-plot
qqnorm(reps$t)
qqline(
reps$t,
col = "red",
lwd = 2
)


График показывает близость распределения бутстрап-оценок к
нормальному.
Выведу доверительный интервал и дополнительные показатели.
boot.ci(
reps,
type = "bca"
)
bias <- mean(reps$t) - reps$t0
se <- sd(reps$t)
cv <- se / mean(reps$t)
cat("Bias =", bias, "\n")
cat("SE =", se, "\n")
cat("CV =", cv, "\n")
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 5000 bootstrap replicates
CALL :
boot.ci(boot.out = reps, type = "bca")
Intervals :
Level BCa
95% ( 0.5499, 0.8195 )
Calculations and Intervals on Original Scale
Bias = 0.003270593
SE = 0.06413799
CV = 0.08888131
Вывод
Для модели mpg∼disp выполнено 5000 бутстрап-перевыборок. Получен
95%-й BCa-доверительный интервал для коэффициента детерминации R^2:
(0.5499; 0.8195). Смещение мало (Bias = 0.0033), стандартная ошибка
составляет 0.0641. Это подтверждает устойчивость оценки и наличие
достаточно сильной связи между объёмом двигателя и расходом топлива.
Выводы по работе
Проведён разведочный анализ датасета автомобилей и реализован метод
бутстрапа в Python и R. В Python подтверждены статистически значимые
различия между исследуемыми группами автомобилей. В R оценена
устойчивость коэффициента детерминации регрессионной модели и построен
доверительный интервал для R^2. Результаты показывают, что бутстрап
позволяет надёжно оценивать статистические характеристики и их
доверительные интервалы без предположения о нормальности исходных
данных.
LS0tDQp0aXRsZTogItCQ0L3QsNC70LjQtyDQtNCw0L3QvdGL0YUsINC70LDQsdC+0YDQsNGC0L7RgNC90LDRjyDRgNCw0LHQvtGC0LAg4oSWNi4g0KDQtdCw0LvQuNC30LDRhtC40Y8g0LHRg9GC0YHRgtGA0LDQv9CwINC90LAg0Y/Qt9GL0LrQsNGFIFIg0LggUHl0aG9uIg0KYXV0aG9yOiAi0KHQvNC10LvQutC+0LIg0J7Qu9C10LMsIDIzMS0zMzMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyDQl9Cw0LTQsNC90LjQtSAxDQoNCtCvINCy0L7Qt9GM0LzRgyDQtNCw0YLQsNGB0LXRgiBtdGNhcnMuINCj0YHRgtCw0L3QvtCy0LvRjiDQvdC10L7QsdGF0L7QtNC40LzRi9C1INCx0LjQsdC70LjQvtGC0LXQutC4INC4INC40LzQv9C+0YDRgtC40YDRg9GOINC10LPQvi4NCg0KYGBge3J9DQpsaWJyYXJ5KHJldGljdWxhdGUpDQoNCnB5X2luc3RhbGwoInBhbmRhcyIpDQpweV9pbnN0YWxsKCJzZWFib3JuIikNCmBgYA0KDQpgYGB7cHl0aG9ufQ0KDQppbXBvcnQgcGFuZGFzIGFzIHBkDQppbXBvcnQgc2VhYm9ybiBhcyBzbnMNCg0KZGYgPSBwZC5yZWFkX2NzdigNCiAgICAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NlbHZhODYvZGF0YXNldHMvbWFzdGVyL210Y2Fycy5jc3YiDQopDQpgYGANCg0KIyMg0JfQsNC00LDQvdC40LUgMg0KDQojIyMg0KDQsNC30LLQtdC00L7Rh9C90YvQuSDQsNC90LDQu9C40LcNCg0K0J7QsdGJ0LDRjyDQuNC90YTQvtGA0LzQsNGG0LjRjzoNCg0KYGBge3B5dGhvbn0NCnByaW50KGRmLnNoYXBlKQ0KcHJpbnQoZGYuaW5mbygpKQ0KYGBgDQoNCmBgYCAgICAgICAgIA0KKDMyLCAxNCkNCjxjbGFzcyAncGFuZGFzLkRhdGFGcmFtZSc+IA0KUmFuZ2VJbmRleDogMzIgZW50cmllcywgMCB0byAzMSANCkRhdGEgY29sdW1ucyAodG90YWwgMTQgY29sdW1ucyk6ICANCiAjICAgQ29sdW1uICAgTm9uLU51bGwgQ291bnQgIER0eXBlIA0KLS0tICAtLS0tLS0gICAtLS0tLS0tLS0tLS0tLSAgLS0tLS0NCiAwICAgbXBnICAgICAgMzIgbm9uLW51bGwgICAgIGZsb2F0NjQNCiAxICAgY3lsICAgICAgMzIgbm9uLW51bGwgICAgIGludDY0ICAgIA0KIDIgICBkaXNwICAgICAzMiBub24tbnVsbCAgICAgZmxvYXQ2NCAgDQogMyAgIGhwICAgICAgIDMyIG5vbi1udWxsICAgICBpbnQ2NCAgICANCiA0ICAgZHJhdCAgICAgMzIgbm9uLW51bGwgICAgIGZsb2F0NjQgIA0KIDUgICB3dCAgICAgICAzMiBub24tbnVsbCAgICAgZmxvYXQ2NCAgDQogNiAgIHFzZWMgICAgIDMyIG5vbi1udWxsICAgICBmbG9hdDY0ICANCiA3ICAgdnMgICAgICAgMzIgbm9uLW51bGwgICAgIGludDY0ICAgIA0KIDggICBhbSAgICAgICAzMiBub24tbnVsbCAgICAgaW50NjQgICAgDQogOSAgIGdlYXIgICAgIDMyIG5vbi1udWxsICAgICBpbnQ2NCAgICANCiAxMCAgY2FyYiAgICAgMzIgbm9uLW51bGwgICAgIGludDY0ICAgIA0KIDExICBmYXN0ICAgICAzMiBub24tbnVsbCAgICAgaW50NjQgICAgDQogMTIgIGNhcnMgICAgIDMyIG5vbi1udWxsICAgICBzdHIgICAgICANCiAxMyAgY2FybmFtZSAgMzIgbm9uLW51bGwgICAgIHN0ciAgICAgDQpkdHlwZXM6IGZsb2F0NjQoNSksIGludDY0KDcpLCBzdHIoMikgDQptZW1vcnkgdXNhZ2U6IDMuNiBLQiANCk5vbmUNCmBgYA0KDQrQotCw0LrQuNC8INC+0LHRgNCw0LfQvtC8LCDQuNC80LXQtdC8INGC0LDQsdC70LjRhtGDINGBIDE0INGB0YLQvtC70LHRhtCw0LzQuCwgNSDRgSDQstC10YnQtdGB0YLQstC10L3QvdGL0LzQuCDQt9C90LDRh9C10L3QuNGP0LzQuCwgNyDRgSDRhtC10LvQvtGH0LjRgdC70LXQvdC90YvQvNC4LCAyINGB0L4g0YHRgtGA0L7QutC+0LLRi9C80LguDQoNCtCe0L/QuNGB0LDRgtC10LvRjNC90LDRjyDRgdGC0LDRgtC40YHRgtC40LrQsDoNCg0KYGBge3B5dGhvbn0NCnByaW50KGRmLmRlc2NyaWJlKCkpDQpgYGANCg0KYGBgICAgICAgICAgDQogICAgICAgICAgICAgbXBnICAgICAgICBjeWwgICAgICAgIGRpc3AgIC4uLiAgICAgICBnZWFyICAgICBjYXJiICAgICAgIGZhc3QNCmNvdW50ICAzMi4wMDAwMDAgIDMyLjAwMDAwMCAgIDMyLjAwMDAwMCAgLi4uICAzMi4wMDAwMDAgIDMyLjAwMDAgIDMyLjAwMDAwMCANCm1lYW4gICAgNC40MzQ3NzAgICA2LjE4NzUwMCAgMjMwLjcyMTg3NSAgLi4uICAgMy42ODc1MDAgICAyLjgxMjUgICAwLjY4NzUwMCANCnN0ZCAgICAgMC42NjExMzcgICAxLjc4NTkyMiAgMTIzLjkzODY5NCAgLi4uICAgMC43Mzc4MDQgICAxLjYxNTIgICAwLjQ3MDkyOSANCm1pbiAgICAgMy4yMjQ5MDMgICA0LjAwMDAwMCAgIDcxLjEwMDAwMCAgLi4uICAgMy4wMDAwMDAgICAxLjAwMDAgICAwLjAwMDAwMCANCjI1JSAgICAgMy45Mjc0MzIgICA0LjAwMDAwMCAgMTIwLjgyNTAwMCAgLi4uICAgMy4wMDAwMDAgICAyLjAwMDAgICAwLjAwMDAwMCANCjUwJSAgICAgNC4zODE3ODAgICA2LjAwMDAwMCAgMTk2LjMwMDAwMCAgLi4uICAgNC4wMDAwMDAgICAyLjAwMDAgICAxLjAwMDAwMCANCjc1JSAgICAgNC43NzQ5MzUgICA4LjAwMDAwMCAgMzI2LjAwMDAwMCAgLi4uICAgNC4wMDAwMDAgICA0LjAwMDAgICAxLjAwMDAwMCANCm1heCAgICAgNS44MjIzNzEgICA4LjAwMDAwMCAgNDcyLjAwMDAwMCAgLi4uICAgNS4wMDAwMDAgICA4LjAwMDAgICAxLjAwMDAwMCANCg0KWzggcm93cyB4IDEyIGNvbHVtbnNdDQpgYGANCg0K0JLRgdC10LPQviDQuNC80LXQtdC8IDMyINGB0YLRgNC+0LrQuCwg0L/QvtC60LDQt9Cw0L3RiyDRgdGA0LXQtNC90LXQtSwg0YHRgtCw0L3QtNCw0YDRgtC90L7QtSDQvtGC0LrQu9C+0L3QtdC90LjQtSwg0LrQstCw0YDRgtC40LvQuCwg0LzQuNC90LjQvNGD0LzRiyDQuCDQvNCw0LrRgdC40LzRg9C80YsuDQoNCtCf0YDQvtCy0LXRgNC60LAg0L/RgNC+0L/Rg9GB0LrQvtCyOg0KDQpgYGB7cHl0aG9ufQ0KcHJpbnQoZGYuaXNudWxsKCkuc3VtKCkpDQpgYGANCg0K0JrQsNC6INCy0LjQtNC90L4sINC/0YDQvtC/0YPRgdC60L7QsiDQvdC10YIuDQoNCtCf0YDQvtCw0L3QsNC30LjRgNGD0Y4g0LrQvtC90LrRgNC10YLQvdGL0LUg0L/QvtC60LDQt9Cw0YLQtdC70LguDQoNCtCY0YHRgdC70LXQtNGD0Y4g0YDQsNGB0L/RgNC10LTQtdC90LjRjyDRgNCw0YHRhdC+0LTQsCDRgtC+0L/Qu9C40LLQsCBtcGcgKNGB0LrQvtC70YzQutC+INC80LjQu9GMINC80L7QttC10YIg0L/RgNC+0LXRhdCw0YLRjCDQsNCy0YLQvtC80L7QsdC40LvRjCDQvdCwIDEg0LPQsNC70LvQvtC90LUg0YLQvtC/0LvQuNCy0LApLg0KDQpgYGB7cHl0aG9ufQ0KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdA0KDQpwbHQuZmlndXJlKGZpZ3NpemU9KDgsNSkpDQpzbnMuaGlzdHBsb3QoZGZbIm1wZyJdLCBiaW5zPTgsIGtkZT1UcnVlKQ0KDQpwbHQudGl0bGUoItCg0LDRgdC/0YDQtdC00LXQu9C10L3QuNC1INGA0LDRgdGF0L7QtNCwINGC0L7Qv9C70LjQstCwIikNCnBsdC5zaG93KCkNCmBgYA0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0xMTY1OTI0ODcwLnBuZykNCg0KKirQktGL0LLQvtC0OioqINCx0L7Qu9GM0YjQuNC90YHRgtCy0L4g0LDQstGC0L7QvNC+0LHQuNC70LXQuSDQv9GA0L7QtdC30LbQsNGO0YIgNCw1LTQsOCDQvNC40LvRjCDQt9CwINCz0LDQu9C70L7QvS4NCg0K0JjRgdGB0LvQtdC00YPRjiDQt9Cw0LLQuNGB0LjQvNC+0YHRgtGMINGA0LDRgdGF0L7QtNCwINCw0LLRgtC+0LzQvtCx0LjQu9GPINC+0YIg0LXQs9C+INC80LDRgdGB0YsuDQoNCmBgYHtweXRob259DQpwbHQuZmlndXJlKGZpZ3NpemU9KDgsNSkpDQoNCnNucy5zY2F0dGVycGxvdCgNCiAgICBkYXRhPWRmLA0KICAgIHg9Ind0IiwNCiAgICB5PSJtcGciDQopDQoNCnBsdC50aXRsZSgi0JfQsNCy0LjRgdC40LzQvtGB0YLRjCDRgNCw0YHRhdC+0LTQsCDRgtC+0L/Qu9C40LLQsCDQvtGCINC80LDRgdGB0Ysg0LDQstGC0L7QvNC+0LHQuNC70Y8iKQ0KcGx0LnNob3coKQ0KYGBgDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTE5MDIxODkzOTUucG5nKQ0KDQoqKtCS0YvQstC+0LQ6Kiog0YEg0YPQstC10LvQuNGH0LXQvdC40LXQvCDQvNCw0YHRgdGLINCw0LLRgtC+0LzQvtCx0LjQu9GPINGD0YXRg9C00YjQsNC10YLRgdGPINC10LPQviDRgNCw0YHRhdC+0LQuDQoNCtCY0YHRgdC70LXQtNGD0Y4g0YHQstGP0LfRjCDQutC+0Lst0LLQsCDRhtC40LvQu9C40L3QtNGA0L7QsiDRgSDRgNCw0YHRhdC+0LTQvtC8INGC0L7Qv9C70LjQstCwOg0KDQpgYGB7cHl0aG9ufQ0KcGx0LmZpZ3VyZShmaWdzaXplPSg4LDUpKQ0KDQpzbnMuYm94cGxvdCgNCiAgICBkYXRhPWRmLA0KICAgIHg9ImN5bCIsDQogICAgeT0ibXBnIg0KKQ0KDQpwbHQudGl0bGUoItCg0LDRgdGF0L7QtCDRgtC+0L/Qu9C40LLQsCDQtNC70Y8g0LDQstGC0L7QvNC+0LHQuNC70LXQuSDRgSDRgNCw0LfQvdGL0Lwg0YfQuNGB0LvQvtC8INGG0LjQu9C40L3QtNGA0L7QsiIpDQpwbHQuc2hvdygpDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMzIzNDYwNTc2OC5wbmcpDQoNCioq0JLRi9Cy0L7QtDoqKiDRh9C10Lwg0LzQtdC90YzRiNC1INGG0LjQu9C70LjQvdC00YDQvtCyLCDRgtC10Lwg0LzQtdC90YzRiNC1INGA0LDRgdGF0L7QtC4NCg0K0JjRgdGB0LvQtdC00YPRjiDQutC+0YDRgNC10LvRj9GG0LjQvtC90L3Rg9GOINC80LDRgtGA0LjRhtGDLg0KDQpgYGB7cHl0aG9ufQ0KcGx0LmZpZ3VyZShmaWdzaXplPSgxMiwxMCkpDQoNCnNucy5oZWF0bWFwKA0KICAgIGRmLmNvcnIobnVtZXJpY19vbmx5PVRydWUpLA0KICAgIGFubm90PVRydWUsDQogICAgY21hcD0iY29vbHdhcm0iLA0KICAgIGZtdD0iLjJmIg0KKQ0KDQpwbHQueHRpY2tzKHJvdGF0aW9uPTQ1LCBoYT0ncmlnaHQnKQ0KcGx0Lnl0aWNrcyhyb3RhdGlvbj0wKQ0KDQpwbHQuc2hvdygpDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMjc0MDE4ODYyMC5wbmcpDQoNCioq0JLRi9Cy0L7QtDoqKiDRgNCw0YHRhdC+0LQgKG1wZykg0L7RgtGA0LjRhtCw0YLQtdC70YzQvdC+INC60L7RgNGA0LXQu9C40YDRg9C10YIg0YEg0LzQsNGB0YHQvtC5ICh3dCksINGA0LDRgdGF0L7QtCAobXBnKSDRgtCw0LrQttC1INC+0YLRgNC40YbQsNGC0LXQu9GM0L3QviDQutC+0YDRgNC10LvQuNGA0YPQtdGCINGBINC60L7Qu9C40YfQtdGB0YLQstC+0Lwg0LvQvtGI0LDQtNC40L3Ri9GFINGB0LjQuyAoaHApLCDQsCDQu9C+0YjQsNC00LjQvdGL0YUg0YHQuNC7IChocCkg0L/QvtC70L7QttC40YLQtdC70YzQvdC+INC60L7RgNGA0LXQu9C40YDRg9C10YIg0YEg0LrQvtC70LjRh9C10YHRgtCy0L7QvCDRhtC40LvQuNC90LTRgNC+0LIgKGN5bCkuDQoNCiMjINCX0LDQtNCw0L3QuNC1IDMNCg0KKirQkdGD0YHRgtGA0Y3QvyoqIC0g0Y3RgtC+INC80LXRgtC+0LQg0LjRgdGB0LvQtdC00L7QstCw0L3QuNGPINGA0LDRgdC/0YDQtdC00LXQu9C10L3QuNGPINGB0YLQsNGC0LjRgdGC0LjQuiwg0L7RgdC90L7QstCw0L3QvdGL0Lkg0L3QsCDQvNC90L7Qs9C+0LrRgNCw0YLQvdC+0Lkg0LPQtdC90LXRgNCw0YbQuNC4INCy0YvQsdC+0YDQvtC6INC90LAg0LHQsNC30LUg0LjQvNC10Y7RidC10LnRgdGPINCy0YvQsdC+0YDQutC4Lg0KDQrQndCw0YfQvdGDINGBINGA0LXQsNC70LjQt9Cw0YbQuNC4INCx0YPRgtGB0YLRgNGN0L/QsCDQvdCwIFB5dGhvbi4NCg0K0JIg0LzQvtGR0Lwg0LTQsNGC0LDRgdC10YLQtSDRjyDRgNCw0LfQtNC10LvRjiDQsNCy0YLQvtC80L7QsdC40LvQuCDQvdCwINC00LLQtSDQs9GA0YPQv9C/0YsgKNGBIDQg0YbQuNC70LjQvdC00YDQsNC80Lgg0LggOCDRhtC40LvQuNC90LTRgNCw0LzQuCksINGB0YDQsNCy0L3RjiDRgNCw0YHRhdC+0LQg0YLQvtC/0LvQuNCy0LAgKG1wZyksINC4INCx0YPRgtGB0YLRgNCw0L/QvtC8INC+0YbQtdC90Y4g0LTQvtCy0LXRgNC40YLQtdC70YzQvdGL0Lkg0LjQvdGC0LXRgNCy0LDQuyDQtNC70Y8g0YDQsNC30L3QuNGG0YsuDQoNCmBgYHtweXRob259DQppbXBvcnQgbnVtcHkgYXMgbnANCmltcG9ydCBwYW5kYXMgYXMgcGQNCmltcG9ydCBzZWFib3JuIGFzIHNucw0KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdA0KDQojINCX0LDQs9GA0YPQt9C60LAg0LTQsNC90L3Ri9GFDQpkZiA9IHBkLnJlYWRfY3N2KA0KICAgICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc2VsdmE4Ni9kYXRhc2V0cy9tYXN0ZXIvbXRjYXJzLmNzdiINCikNCg0KIyDQk9GA0YPQv9C/0Ysg0LTQu9GPINGB0YDQsNCy0L3QtdC90LjRjw0KdmFsdWVzX2EgPSBkZltkZlsiY3lsIl0gPT0gNF1bIm1wZyJdLnZhbHVlcw0KdmFsdWVzX2IgPSBkZltkZlsiY3lsIl0gPT0gOF1bIm1wZyJdLnZhbHVlcw0KDQojINCk0YPQvdC60YbQuNGPINC/0L7RgdGC0YDQvtC10L3QuNGPINC00L7QstC10YDQuNGC0LXQu9GM0L3QvtCz0L4g0LjQvdGC0LXRgNCy0LDQu9CwDQpkZWYgZ2V0X3BlcmNlbnRpbGVfY2koYm9vdHN0cmFwX3N0YXRzLCBhbHBoYSk6DQoNCiAgICBsZWZ0LCByaWdodCA9IG5wLnF1YW50aWxlKA0KICAgICAgICBib290c3RyYXBfc3RhdHMsDQogICAgICAgIFthbHBoYSAvIDIsIDEgLSBhbHBoYSAvIDJdDQogICAgKQ0KDQogICAgcmV0dXJuIGxlZnQsIHJpZ2h0DQoNCiMg0L/QsNGA0LDQvNC10YLRgNGLINCx0YPRgtGB0YLRgNCw0L/QsA0KQiA9IDEwMDAwDQphbHBoYSA9IDAuMDUNCg0KIyDRgNCw0LfQvdC40YbQsCDRgdGA0LXQtNC90LjRhQ0KcGUgPSBucC5tZWFuKHZhbHVlc19iKSAtIG5wLm1lYW4odmFsdWVzX2EpDQoNCmJvb3RzdHJhcF9zdGF0cyA9IFtdDQoNCmZvciBfIGluIHJhbmdlKEIpOg0KDQogICAgc2FtcGxlX2EgPSBucC5yYW5kb20uY2hvaWNlKA0KICAgICAgICB2YWx1ZXNfYSwNCiAgICAgICAgc2l6ZT1sZW4odmFsdWVzX2EpLA0KICAgICAgICByZXBsYWNlPVRydWUNCiAgICApDQoNCiAgICBzYW1wbGVfYiA9IG5wLnJhbmRvbS5jaG9pY2UoDQogICAgICAgIHZhbHVlc19iLA0KICAgICAgICBzaXplPWxlbih2YWx1ZXNfYiksDQogICAgICAgIHJlcGxhY2U9VHJ1ZQ0KICAgICkNCg0KICAgIHN0YXQgPSBucC5tZWFuKHNhbXBsZV9iKSAtIG5wLm1lYW4oc2FtcGxlX2EpDQoNCiAgICBib290c3RyYXBfc3RhdHMuYXBwZW5kKHN0YXQpDQoNCmJvb3RzdHJhcF9zdGF0cyA9IG5wLmFycmF5KGJvb3RzdHJhcF9zdGF0cykNCg0KY2kgPSBnZXRfcGVyY2VudGlsZV9jaSgNCiAgICBib290c3RyYXBfc3RhdHMsDQogICAgYWxwaGENCikNCg0KaGFzX2VmZmVjdCA9IG5vdCAoY2lbMF0gPCAwIDwgY2lbMV0pDQoNCnByaW50KGYi0KHRgNC10LTQvdC10LUgbXBnINC00LvRjyA0INGG0LjQu9C40L3QtNGA0L7QsjosIHtucC5tZWFuKHZhbHVlc19hKTouMmZ9IikNCnByaW50KGYi0KHRgNC10LTQvdC10LUgbXBnINC00LvRjyA4INGG0LjQu9C40L3QtNGA0L7Qsjoge25wLm1lYW4odmFsdWVzX2IpOi4yZn0iKQ0KcHJpbnQoZiLQoNCw0LfQvdC40YbQsCDRgdGA0LXQtNC90LjRhSBtcGc6IHtwZTouMmZ9IikNCnByaW50KGYiOTUlINCU0Jg6ICh7Y2lbMF06LjJmfTsge2NpWzFdOi4yZn0pIikNCnByaW50KGYi0KDQsNC30LvQuNGH0LjRjyDRgdGC0LDRgtC40YHRgtC40YfQtdGB0LrQuCDQt9C90LDRh9C40LzRizoge2hhc19lZmZlY3R9IikNCg0KcHJpbnQoZiJcbtCU0L7Qv9C+0LvQvdC40YLQtdC70YzQvdCw0Y8g0LjQvdGE0L7RgNC80LDRhtC40Y86IikNCnByaW50KGYi0KHRgtCw0L3QtNCw0YDRgtC90LDRjyDQvtGI0LjQsdC60LAgKFNFKToge2Jvb3RzdHJhcF9zdGF0cy5zdGQoKTouM2Z9IikNCnByaW50KGYi0KHQvNC10YnQtdC90LjQtSAoYmlhcyk6IHtib290c3RyYXBfc3RhdHMubWVhbigpIC0gcGU6LjNmfSIpDQpwcmludChmItCa0L7RjdGE0YTQuNGG0LjQtdC90YIg0LLQsNGA0LjQsNGG0LjQuDoge2Jvb3RzdHJhcF9zdGF0cy5zdGQoKSAvIGFicyhwZSk6LjNmfSIpDQpgYGANCg0KYGBgICAgICAgICAgDQrQodGA0LXQtNC90LXQtSBtcGcg0LTQu9GPIDQg0YbQuNC70LjQvdC00YDQvtCyOiwgNS4xNQ0K0KHRgNC10LTQvdC10LUgbXBnINC00LvRjyA4INGG0LjQu9C40L3QtNGA0L7QsjogMy44Nw0K0KDQsNC30L3QuNGG0LAg0YHRgNC10LTQvdC40YUgbXBnOiAtMS4yNw0KOTUlINCU0Jg6ICgtMS41NzsgLTAuOTkpDQrQoNCw0LfQu9C40YfQuNGPINGB0YLQsNGC0LjRgdGC0LjRh9C10YHQutC4INC30L3QsNGH0LjQvNGLOiBUcnVlDQoNCtCU0L7Qv9C+0LvQvdC40YLQtdC70YzQvdCw0Y8g0LjQvdGE0L7RgNC80LDRhtC40Y86DQrQodGC0LDQvdC00LDRgNGC0L3QsNGPINC+0YjQuNCx0LrQsCAoU0UpOiAwLjE1MQ0K0KHQvNC10YnQtdC90LjQtSAoYmlhcyk6IDAuMDAwDQrQmtC+0Y3RhNGE0LjRhtC40LXQvdGCINCy0LDRgNC40LDRhtC40Lg6IDAuMTE4DQpgYGANCg0KYGBge3B5dGhvbn0NCnBsdC5maWd1cmUoZmlnc2l6ZT0oOCw2KSkNCg0Kc25zLmJveHBsb3QoDQogICAgZGF0YT1kZltkZlsiY3lsIl0uaXNpbihbNCwgOF0pXSwNCiAgICB4PSJjeWwiLA0KICAgIHk9Im1wZyINCikNCg0KcGx0LnRpdGxlKA0KICAgICLQoNCw0YHRhdC+0LQg0YLQvtC/0LvQuNCy0LAg0YMg0LDQstGC0L7QvNC+0LHQuNC70LXQuSDRgSA0INC4IDgg0YbQuNC70LjQvdC00YDQsNC80LgiDQopDQoNCnBsdC54bGFiZWwoItCn0LjRgdC70L4g0YbQuNC70LjQvdC00YDQvtCyIikNCg0KcGx0LnlsYWJlbCgiTVBHIikNCg0KcGx0LnNob3coKQ0KYGBgDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTMzODYyNDY0MjEucG5nKQ0KDQoqKtCS0YvQstC+0LQ6Kiog0JIg0LrQsNGH0LXRgdGC0LLQtSDQuNGB0YHQu9C10LTQvtCy0LDQu9Cw0YHRjCDQv9C10YDQtdC80LXQvdC90LDRjyBtcGcuINCS0YvQv9C+0LvQvdC10L3QviAxMDAwMCDQsdGD0YLRgdGC0YDQsNC/LdC/0LXRgNC10LLRi9Cx0L7RgNC+0Log0YEg0LLQvtC30LLRgNCw0YnQtdC90LjQtdC8LCDQv9C+0YHQu9C1INGH0LXQs9C+INC00LvRjyDQutCw0LbQtNC+0Lkg0LLRi9Cx0L7RgNC60Lgg0LLRi9GH0LjRgdC70Y/Qu9Cw0YHRjCDRgNCw0LfQvdC+0YHRgtGMINGB0YDQtdC00L3QuNGFINC30L3QsNGH0LXQvdC40LkuDQoNCtCf0L7Qu9GD0YfQtdC90L3QsNGPINC+0YbQtdC90LrQsCDRgNCw0LfQvdC+0YHRgtC4INGB0YDQtdC00L3QuNGFINGB0L7RgdGC0LDQstC40LvQsCAtMS4yNy4g0J/QvtGB0YLRgNC+0LXQvdC90YvQuSA5NSUt0Lkg0LTQvtCy0LXRgNC40YLQtdC70YzQvdGL0Lkg0LjQvdGC0LXRgNCy0LDQuyDRgNCw0LLQtdC9ICgtMS41NzsgLTAuOTkpLiDQn9C+0YHQutC+0LvRjNC60YMg0LTQvtCy0LXRgNC40YLQtdC70YzQvdGL0Lkg0LjQvdGC0LXRgNCy0LDQuyDQvdC1INGB0L7QtNC10YDQttC40YIg0L3Rg9C70LXQstC+0LUg0LfQvdCw0YfQtdC90LjQtSwg0YDQsNC30LvQuNGH0LjRjyDQvNC10LbQtNGDINCz0YDRg9C/0L/QsNC80Lgg0Y/QstC70Y/RjtGC0YHRjyDRgdGC0LDRgtC40YHRgtC40YfQtdGB0LrQuCDQt9C90LDRh9C40LzRi9C80LguDQoNCtCh0YLQsNC90LTQsNGA0YLQvdCw0Y8g0L7RiNC40LHQutCwINC+0YbQtdC90LrQuCDRgdC+0YHRgtCw0LLQuNC70LAgMC4xNTEsINGH0YLQviDRgdCy0LjQtNC10YLQtdC70YzRgdGC0LLRg9C10YIg0L4g0LTQvtGB0YLQsNGC0L7Rh9C90L4g0LLRi9GB0L7QutC+0Lkg0YPRgdGC0L7QudGH0LjQstC+0YHRgtC4INGA0LXQt9GD0LvRjNGC0LDRgtCwLiDQodC80LXRidC10L3QuNC1IChiaWFzKSDQvtGC0YHRg9GC0YHRgtCy0YPQtdGCINC4INGA0LDQstC90L4gMC4wMDAsINGB0LvQtdC00L7QstCw0YLQtdC70YzQvdC+INCx0YPRgtGB0YLRgNCw0L8t0L7RhtC10L3QutCwINC90LUg0LTQtdC80L7QvdGB0YLRgNC40YDRg9C10YIg0YHQuNGB0YLQtdC80LDRgtC40YfQtdGB0LrQvtCz0L4g0L7RgtC60LvQvtC90LXQvdC40Y8uINCa0L7RjdGE0YTQuNGG0LjQtdC90YIg0LLQsNGA0LjQsNGG0LjQuCDRgdC+0YHRgtCw0LLQuNC7IDAuMTE4LCDRh9GC0L4g0YPQutCw0LfRi9Cy0LDQtdGCINC90LAg0YPQvNC10YDQtdC90L3Rg9GOINC40LfQvNC10L3Rh9C40LLQvtGB0YLRjCDQv9C+0LvRg9GH0LXQvdC90YvRhSDQvtGG0LXQvdC+0LouDQoNCiMjINCX0LDQtNCw0L3QuNC1IDQNCg0K0KDQtdCw0LvQuNC30YPRjiDRgtC10L/QtdGA0Ywg0LHRg9GC0YHRgtGA0Y3QvyDQvdCwIFIuDQoNCtCb0LjQvdC10LnQvdCw0Y8g0YDQtdCz0YDQtdGB0YHQuNGPINC/0L7Qt9Cy0L7Qu9GP0LXRgiDQvtGG0LXQvdC40YLRjCDQt9Cw0LLQuNGB0LjQvNC+0YHRgtGMINC+0LTQvdC+0Lkg0L/QtdGA0LXQvNC10L3QvdC+0Lkg0L7RgiDQtNGA0YPQs9C+0LkuDQoNCtCa0L7RjdGE0YTQuNGG0LjQtdC90YIg0LTQtdGC0LXRgNC80LjQvdCw0YbQuNC4IFJcXjIg0L/QvtC60LDQt9GL0LLQsNC10YIsINC60LDQutGD0Y4g0LTQvtC70Y4g0LLQsNGA0LjQsNGG0LjQuCDQt9Cw0LLQuNGB0LjQvNC+0Lkg0L/QtdGA0LXQvNC10L3QvdC+0Lkg0L7QsdGK0Y/RgdC90Y/QtdGCINC80L7QtNC10LvRjC4NCg0K0JHRg9GC0YHRgtGA0LDQvyDQv9C+0LfQstC+0LvRj9C10YIg0L7RhtC10L3QuNGC0Ywg0YPRgdGC0L7QudGH0LjQstC+0YHRgtGMINC+0YbQtdC90LrQuCBSXF4yLCDRgdGC0LDQvdC00LDRgNGC0L3Rg9GOINC+0YjQuNCx0LrRgywg0LAg0YLQsNC60LbQtSDQtNC+0LLQtdGA0LjRgtC10LvRjNC90YvQuSDQuNC90YLQtdGA0LLQsNC7Lg0KDQrQn9GA0L7QuNC30LLQvtC00LjRgtGMINCx0YPQtNGDINCx0YPRgtGB0YLRgNCw0L/QuNGA0L7QstCw0L3QuNC1INC60L7RjdGE0YTQuNGG0LjQtdC90YLQsCDQtNC10YLQtdGA0LzQuNC90LDRhtC40Lgg0LTQu9GPINC80L7QtNC10LvQuCBtcGdcfmRpc3AuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMCkNCg0KbGlicmFyeShib290KQ0KDQojINGE0YPQvdC60YbQuNGPINGA0LDRgdGH0LXRgtCwIFJeMg0KcnNxX2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKGZvcm11bGEsIGRhdGEsIGluZGljZXMpew0KDQogIGQgPC0gZGF0YVtpbmRpY2VzLCBdDQoNCiAgZml0IDwtIGxtKGZvcm11bGEsIGRhdGEgPSBkKQ0KDQogIHJldHVybihzdW1tYXJ5KGZpdCkkci5zcXVhcmVkKQ0KfQ0KDQojINCx0YPRgtGB0YLRgNCw0L8NCnJlcHMgPC0gYm9vdCgNCiAgZGF0YSA9IG10Y2FycywNCiAgc3RhdGlzdGljID0gcnNxX2Z1bmN0aW9uLA0KICBSID0gNTAwMCwNCiAgZm9ybXVsYSA9IG1wZyB+IGRpc3ANCikNCg0KcmVwcw0KYGBgDQoNCmBgYCAgICAgICAgIA0KT1JESU5BUlkgTk9OUEFSQU1FVFJJQyBCT09UU1RSQVAgICANCg0KQ2FsbDogDQpib290KGRhdGEgPSBtdGNhcnMsIHN0YXRpc3RpYyA9IHJzcV9mdW5jdGlvbiwgUiA9IDUwMDAsIGZvcm11bGEgPSBtcGcgfg0KICAgIGRpc3ApICAgDQoNCkJvb3RzdHJhcCBTdGF0aXN0aWNzIDoNCiAgICAgIG9yaWdpbmFsICAgICAgYmlhcyAgICBzdGQuIGVycm9yDQogdDEqIDAuNzE4MzQzMyAwLjAwMzI3MDU5MyAgMC4wNjQxMzc5OQ0KYGBgDQoNCtCT0YDQsNGE0LjQuiDihJYxLiDQoNCw0YHQv9GA0LXQtNC10LvQtdC90LjQtSDQsdGD0YLRgdGC0YDQsNC/LdC+0YbQtdC90L7Qug0KDQpgYGB7cn0NCmhpc3QoDQogIHJlcHMkdCwNCiAgYnJlYWtzID0gMzAsDQogIGNvbCA9ICJsaWdodGJsdWUiLA0KICBtYWluID0gIkJvb3RzdHJhcCBkaXN0cmlidXRpb24gb2YgUsKyIiwNCiAgeGxhYiA9ICJSwrIiDQopDQoNCmFibGluZSgNCiAgdiA9IHJlcHMkdDAsDQogIGNvbCA9ICJyZWQiLA0KICBsd2QgPSAzDQopDQpgYGANCg0KIVvQmtGA0LDRgdC90LDRjyDQu9C40L3QuNGPINC/0L7QutCw0LfRi9Cy0LDQtdGCINC40YHRhdC+0LTQvdC+0LUg0LfQvdCw0YfQtdC90LjQtSBSXF4yLl0oaW1hZ2VzL2NsaXBib2FyZC0yNjEzOTkyMzc5LnBuZykNCg0K0JPRgNCw0YTQuNC6IOKEljIuIFFRLXBsb3QNCg0KYGBge3J9DQpxcW5vcm0ocmVwcyR0KQ0KDQpxcWxpbmUoDQogIHJlcHMkdCwNCiAgY29sID0gInJlZCIsDQogIGx3ZCA9IDINCikNCmBgYA0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0xOTYwOTk3NzA4LnBuZykNCg0K0JPRgNCw0YTQuNC6INC/0L7QutCw0LfRi9Cy0LDQtdGCINCx0LvQuNC30L7RgdGC0Ywg0YDQsNGB0L/RgNC10LTQtdC70LXQvdC40Y8g0LHRg9GC0YHRgtGA0LDQvy3QvtGG0LXQvdC+0Log0Log0L3QvtGA0LzQsNC70YzQvdC+0LzRgy4NCg0K0JLRi9Cy0LXQtNGDINC00L7QstC10YDQuNGC0LXQu9GM0L3Ri9C5INC40L3RgtC10YDQstCw0Lsg0Lgg0LTQvtC/0L7Qu9C90LjRgtC10LvRjNC90YvQtSDQv9C+0LrQsNC30LDRgtC10LvQuC4NCg0KYGBge3J9DQpib290LmNpKA0KICByZXBzLA0KICB0eXBlID0gImJjYSINCikNCg0KYmlhcyA8LSBtZWFuKHJlcHMkdCkgLSByZXBzJHQwDQoNCnNlIDwtIHNkKHJlcHMkdCkNCg0KY3YgPC0gc2UgLyBtZWFuKHJlcHMkdCkNCg0KY2F0KCJCaWFzID0iLCBiaWFzLCAiXG4iKQ0KY2F0KCJTRSA9Iiwgc2UsICJcbiIpDQpjYXQoIkNWID0iLCBjdiwgIlxuIikNCmBgYA0KDQpgYGAgICAgICAgICANCkJPT1RTVFJBUCBDT05GSURFTkNFIElOVEVSVkFMIENBTENVTEFUSU9OUw0KQmFzZWQgb24gNTAwMCBib290c3RyYXAgcmVwbGljYXRlcyAgDQoNCkNBTEwgOiAgDQpib290LmNpKGJvb3Qub3V0ID0gcmVwcywgdHlwZSA9ICJiY2EiKSAgDQoNCkludGVydmFscyA6ICANCkxldmVsICAgICAgIEJDYSAgICAgICAgICAgDQo5NSUgICAoIDAuNTQ5OSwgIDAuODE5NSApIA0KDQpDYWxjdWxhdGlvbnMgYW5kIEludGVydmFscyBvbiBPcmlnaW5hbCBTY2FsZQ0KDQpCaWFzID0gMC4wMDMyNzA1OTMgIA0KU0UgPSAwLjA2NDEzNzk5ICANCkNWID0gMC4wODg4ODEzMSANCmBgYA0KDQojIyMg0JLRi9Cy0L7QtA0KDQrQlNC70Y8g0LzQvtC00LXQu9C4IG1wZ+KIvGRpc3Ag0LLRi9C/0L7Qu9C90LXQvdC+IDUwMDAg0LHRg9GC0YHRgtGA0LDQvy3Qv9C10YDQtdCy0YvQsdC+0YDQvtC6LiDQn9C+0LvRg9GH0LXQvSA5NSUt0LkgQkNhLdC00L7QstC10YDQuNGC0LXQu9GM0L3Ri9C5INC40L3RgtC10YDQstCw0Lsg0LTQu9GPINC60L7RjdGE0YTQuNGG0LjQtdC90YLQsCDQtNC10YLQtdGA0LzQuNC90LDRhtC40LggUlxeMjogKDAuNTQ5OTsgMC44MTk1KS4g0KHQvNC10YnQtdC90LjQtSDQvNCw0LvQviAoQmlhcyA9IDAuMDAzMyksINGB0YLQsNC90LTQsNGA0YLQvdCw0Y8g0L7RiNC40LHQutCwINGB0L7RgdGC0LDQstC70Y/QtdGCIDAuMDY0MS4g0K3RgtC+INC/0L7QtNGC0LLQtdGA0LbQtNCw0LXRgiDRg9GB0YLQvtC50YfQuNCy0L7RgdGC0Ywg0L7RhtC10L3QutC4INC4INC90LDQu9C40YfQuNC1INC00L7RgdGC0LDRgtC+0YfQvdC+INGB0LjQu9GM0L3QvtC5INGB0LLRj9C30Lgg0LzQtdC20LTRgyDQvtCx0YrRkdC80L7QvCDQtNCy0LjQs9Cw0YLQtdC70Y8g0Lgg0YDQsNGB0YXQvtC00L7QvCDRgtC+0L/Qu9C40LLQsC4NCg0KIyMg0JLRi9Cy0L7QtNGLINC/0L4g0YDQsNCx0L7RgtC1DQoNCtCf0YDQvtCy0LXQtNGR0L0g0YDQsNC30LLQtdC00L7Rh9C90YvQuSDQsNC90LDQu9C40Lcg0LTQsNGC0LDRgdC10YLQsCDQsNCy0YLQvtC80L7QsdC40LvQtdC5INC4INGA0LXQsNC70LjQt9C+0LLQsNC9INC80LXRgtC+0LQg0LHRg9GC0YHRgtGA0LDQv9CwINCyIFB5dGhvbiDQuCBSLiDQkiBQeXRob24g0L/QvtC00YLQstC10YDQttC00LXQvdGLINGB0YLQsNGC0LjRgdGC0LjRh9C10YHQutC4INC30L3QsNGH0LjQvNGL0LUg0YDQsNC30LvQuNGH0LjRjyDQvNC10LbQtNGDINC40YHRgdC70LXQtNGD0LXQvNGL0LzQuCDQs9GA0YPQv9C/0LDQvNC4INCw0LLRgtC+0LzQvtCx0LjQu9C10LkuINCSIFIg0L7RhtC10L3QtdC90LAg0YPRgdGC0L7QudGH0LjQstC+0YHRgtGMINC60L7RjdGE0YTQuNGG0LjQtdC90YLQsCDQtNC10YLQtdGA0LzQuNC90LDRhtC40Lgg0YDQtdCz0YDQtdGB0YHQuNC+0L3QvdC+0Lkg0LzQvtC00LXQu9C4INC4INC/0L7RgdGC0YDQvtC10L0g0LTQvtCy0LXRgNC40YLQtdC70YzQvdGL0Lkg0LjQvdGC0LXRgNCy0LDQuyDQtNC70Y8gUlxeMi4g0KDQtdC30YPQu9GM0YLQsNGC0Ysg0L/QvtC60LDQt9GL0LLQsNGO0YIsINGH0YLQviDQsdGD0YLRgdGC0YDQsNC/INC/0L7Qt9Cy0L7Qu9GP0LXRgiDQvdCw0LTRkdC20L3QviDQvtGG0LXQvdC40LLQsNGC0Ywg0YHRgtCw0YLQuNGB0YLQuNGH0LXRgdC60LjQtSDRhdCw0YDQsNC60YLQtdGA0LjRgdGC0LjQutC4INC4INC40YUg0LTQvtCy0LXRgNC40YLQtdC70YzQvdGL0LUg0LjQvdGC0LXRgNCy0LDQu9GLINCx0LXQtyDQv9GA0LXQtNC/0L7Qu9C+0LbQtdC90LjRjyDQviDQvdC+0YDQvNCw0LvRjNC90L7RgdGC0Lgg0LjRgdGF0L7QtNC90YvRhSDQtNCw0L3QvdGL0YUuDQo=