library(tidyverse)
library(targets)
library(yardstick)
library(broom)
library(patchwork)
library(scales)
library(here)
# Load data
# Need to use this withr thing because tar_read() and tar_load() need to see the
# _targets folder in the current directory, but this .Rmd file is in a subfolder
withr::with_dir(here::here(), {
source(tar_read(plot_funs))
canary_testing_lagged <- tar_read(panel_testing_lagged)
# Load big list of models
model_df <- tar_read(model_df) %>%
filter(str_detect(model, "baseline") | str_detect(model, "v2csreprss"))
# Load actual model objects
tar_load(c(m_pts_baseline_train, m_pts_v2csreprss_train,
m_pts_total_train, m_pts_advocacy_train,
m_pts_entry_train, m_pts_funding_train,
m_lhr_baseline_train, m_lhr_v2csreprss_train,
m_lhr_total_train, m_lhr_advocacy_train,
m_lhr_entry_train, m_lhr_funding_train))
})
pts_levels <- levels(canary_testing_lagged$PTS_factor)
# Returns a data frame of predicted probabilities with actual = 1
# when the response outcome happens
match_actual <- function(x, pred, actual) {
pred %>%
select(fitted = {{x}}) %>%
mutate(actual = as.numeric(actual == colnames(pred[x])),
plot_level = colnames(pred[x]))
}
E1a: NGO laws and political terror
seed_pts_prediction <- 5494 # From random.org
set.seed(seed_pts_prediction)
pred_pts_baseline <- predict(
m_pts_baseline_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
set.seed(seed_pts_prediction)
pred_pts_total <- predict(
m_pts_total_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
set.seed(seed_pts_prediction)
pred_pts_advocacy <- predict(
m_pts_advocacy_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
set.seed(seed_pts_prediction)
pred_pts_entry <- predict(
m_pts_entry_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
set.seed(seed_pts_prediction)
pred_pts_funding <- predict(
m_pts_funding_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
Separation plots
Baseline models
# Match each column in pred_mat (predicted probabilities for each response level)
pred_long_list <- lapply(1:ncol(pred_pts_baseline),
FUN = match_actual,
pred = pred_pts_baseline,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_baseline)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Models with NGO laws
Total legal barriers
# Match each column in pred_mat (predicted probabilities for each response level)
pred_long_list <- lapply(1:ncol(pred_pts_total),
FUN = match_actual,
pred = pred_pts_total,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_total)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Barriers to advocacy
# Match each column in pred_mat (predicted probabilities for each response level)
pred_long_list <- lapply(1:ncol(pred_pts_advocacy),
FUN = match_actual,
pred = pred_pts_advocacy,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_advocacy)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Barriers to entry
# Match each column in pred_mat (predicted probabilities for each response level)
pred_long_list <- lapply(1:ncol(pred_pts_entry),
FUN = match_actual,
pred = pred_pts_entry,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_entry)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Barriers to funding
# Match each column in pred_mat (predicted probabilities for each response level)
pred_long_list <- lapply(1:ncol(pred_pts_funding),
FUN = match_actual,
pred = pred_pts_funding,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_funding)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Prediction diagnostics
pred_pts_baseline_categories <- pred_pts_baseline %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pred_pts_total_categories <- pred_pts_total %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pred_pts_advocacy_categories <- pred_pts_advocacy %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pred_pts_entry_categories <- pred_pts_entry %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pred_pts_funding_categories <- pred_pts_funding %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pts_cat_preds <- canary_testing_lagged %>%
select(country, year, actual = PTS_factor_lead1) %>%
mutate(pred_baseline = pred_pts_baseline_categories$predicted,
pred_total = pred_pts_total_categories$predicted,
pred_advocacy = pred_pts_advocacy_categories$predicted,
pred_entry = pred_pts_entry_categories$predicted,
pred_funding = pred_pts_funding_categories$predicted) %>%
filter(!is.na(actual)) %>%
mutate(is_correct_baseline = actual == pred_baseline,
is_correct_total = actual == pred_total,
is_correct_advocacy = actual == pred_advocacy,
is_correct_entry = actual == pred_entry,
is_correct_funding = actual == pred_funding)
# Improved predictions
pts_improved_total <- pts_cat_preds %>%
filter(!is_correct_baseline & is_correct_total) %>%
select(Country = country, Year = year, Actual = actual,
`CS repression included` = pred_total,
`Baseline` = pred_baseline)
pts_improved_advocacy <- pts_cat_preds %>%
filter(!is_correct_baseline & is_correct_advocacy) %>%
select(Country = country, Year = year, Actual = actual,
`CS repression included` = pred_advocacy,
`Baseline` = pred_baseline)
pts_improved_entry <- pts_cat_preds %>%
filter(!is_correct_baseline & is_correct_entry) %>%
select(Country = country, Year = year, Actual = actual,
`CS repression included` = pred_entry,
`Baseline` = pred_baseline)
pts_improved_funding <- pts_cat_preds %>%
filter(!is_correct_baseline & is_correct_funding) %>%
select(Country = country, Year = year, Actual = actual,
`CS repression included` = pred_funding,
`Baseline` = pred_baseline)
pts_improved_total %>%
kbl(caption = "Cases improved with total legal barriers") %>%
kable_styling()
Cases improved with total legal barriers
Country
|
Year
|
Actual
|
CS repression included
|
Baseline
|
Guatemala
|
2013
|
Level 3
|
Level 3
|
Level 2
|
Kosovo
|
2012
|
Level 1
|
Level 1
|
Level 2
|
Greece
|
2011
|
Level 2
|
Level 2
|
Level 3
|
Sierra Leone
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Congo - Brazzaville
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Somalia
|
2013
|
Level 5
|
Level 5
|
Level 4
|
Bahrain
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2013
|
Level 3
|
Level 3
|
Level 2
|
pts_improved_advocacy %>%
kbl(caption = "Cases improved with barriers to advocacy") %>%
kable_styling()
Cases improved with barriers to advocacy
Country
|
Year
|
Actual
|
CS repression included
|
Baseline
|
Guatemala
|
2013
|
Level 3
|
Level 3
|
Level 2
|
Bulgaria
|
2012
|
Level 2
|
Level 2
|
Level 1
|
Congo - Brazzaville
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2013
|
Level 3
|
Level 3
|
Level 2
|
pts_improved_entry %>%
kbl(caption = "Cases improved with barriers to entry") %>%
kable_styling()
Cases improved with barriers to entry
Country
|
Year
|
Actual
|
CS repression included
|
Baseline
|
Guatemala
|
2013
|
Level 3
|
Level 3
|
Level 2
|
Kosovo
|
2012
|
Level 1
|
Level 1
|
Level 2
|
Greece
|
2011
|
Level 2
|
Level 2
|
Level 3
|
Sierra Leone
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2013
|
Level 3
|
Level 3
|
Level 2
|
pts_improved_funding %>%
kbl(caption = "Cases improved with barriers to funding") %>%
kable_styling()
Cases improved with barriers to funding
Country
|
Year
|
Actual
|
CS repression included
|
Baseline
|
Guatemala
|
2013
|
Level 3
|
Level 3
|
Level 2
|
Bulgaria
|
2012
|
Level 2
|
Level 2
|
Level 1
|
Sierra Leone
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Congo - Brazzaville
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Tunisia
|
2013
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2013
|
Level 3
|
Level 3
|
Level 2
|
correct_lookup <- tribble(
~name, ~nice_name,
"is_correct_total", "Total legal barriers included",
"is_correct_advocacy", "Barriers to advocacy included",
"is_correct_entry", "Barriers to entry included",
"is_correct_funding", "Barriers to funding included",
"is_correct_baseline", "Baseline"
) %>% mutate(nice_name = fct_inorder(nice_name, ordered = TRUE))
pts_pred_table <- pts_cat_preds %>%
pivot_longer(starts_with("is_correct")) %>%
group_by(name, value) %>%
summarize(n = n()) %>%
ungroup() %>%
left_join(correct_lookup, by = "name") %>%
mutate(Prediction = ifelse(value == TRUE, "Correct", "Wrong")) %>%
arrange(nice_name) %>%
select(-name, -value) %>%
pivot_wider(names_from = "nice_name", values_from = "n")
pts_pred_table %>%
kbl(align = "lccccc") %>%
kable_styling()
Prediction
|
Total legal barriers included
|
Barriers to advocacy included
|
Barriers to entry included
|
Barriers to funding included
|
Baseline
|
Wrong
|
107
|
110
|
108
|
108
|
109
|
Correct
|
378
|
375
|
377
|
377
|
376
|
E1b: NGO laws and latent human rights
seed_lhr_prediction <- 3207 # From random.org
set.seed(seed_lhr_prediction)
pred_lhr_baseline <- predict(m_lhr_baseline_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
set.seed(seed_lhr_prediction)
pred_lhr_total <- predict(m_lhr_total_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
set.seed(seed_lhr_prediction)
pred_lhr_advocacy <- predict(m_lhr_advocacy_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
set.seed(seed_lhr_prediction)
pred_lhr_entry <- predict(m_lhr_entry_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
set.seed(seed_lhr_prediction)
pred_lhr_funding <- predict(m_lhr_funding_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
pred_lhr_baseline_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_baseline)) %>%
filter(!is.na(latent_hr_mean_lead1))
pred_lhr_total_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_total)) %>%
filter(!is.na(latent_hr_mean_lead1))
pred_lhr_advocacy_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_advocacy)) %>%
filter(!is.na(latent_hr_mean_lead1))
pred_lhr_entry_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_entry)) %>%
filter(!is.na(latent_hr_mean_lead1))
pred_lhr_funding_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_funding)) %>%
filter(!is.na(latent_hr_mean_lead1))
Improvement from baseline models
plot_baseline <- ggplot(pred_lhr_baseline_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Baseline",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
plot_total <- ggplot(pred_lhr_total_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Total legal barriers",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
plot_advocacy <- ggplot(pred_lhr_advocacy_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Barriers to advocacy",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
plot_entry <- ggplot(pred_lhr_entry_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Barriers to entry",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
plot_funding <- ggplot(pred_lhr_funding_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Barriers to funding",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
(plot_baseline | plot_total) / (plot_advocacy | plot_entry | plot_funding)
lotsa_metrics <- metric_set(rmse, rsq, mae, ccc)
bind_rows(lotsa_metrics(pred_lhr_baseline_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Baseline"),
lotsa_metrics(pred_lhr_total_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Total legal barriers"),
lotsa_metrics(pred_lhr_advocacy_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Barriers to advocacy"),
lotsa_metrics(pred_lhr_entry_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Barriers to entry"),
lotsa_metrics(pred_lhr_funding_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Barriers to funding")) %>%
select(Model, .metric, .estimate) %>%
pivot_wider(names_from = ".metric", values_from = ".estimate")
Model
|
rmse
|
rsq
|
mae
|
ccc
|
Baseline
|
0.1862156
|
0.9822788
|
0.1080593
|
0.9887926
|
Total legal barriers
|
0.1872181
|
0.9819975
|
0.1085471
|
0.9886937
|
Barriers to advocacy
|
0.1872011
|
0.9819955
|
0.1088119
|
0.9886847
|
Barriers to entry
|
0.1862635
|
0.9821720
|
0.1075320
|
0.9887725
|
Barriers to funding
|
0.1879768
|
0.9818439
|
0.1094280
|
0.9886148
|
Most improved countries
Total legal barriers
most_improved_lhr_total <- bind_cols(
pred_lhr_baseline_test %>%
mutate(error_baseline = Estimate - latent_hr_mean_lead1) %>%
select(country, gwcode, year, latent_hr_mean_lead1,
estimate_baseline = Estimate, error_baseline),
pred_lhr_total_test %>%
mutate(error_total = Estimate - latent_hr_mean_lead1) %>%
select(estimate_total = Estimate, error_total)
) %>%
mutate(improved = error_total < 0 & abs(error_total) < abs(error_baseline)) %>%
mutate(diff = error_total - error_baseline) %>%
mutate(abs_diff = abs(diff)) %>%
filter(improved) %>%
arrange(desc(abs_diff))
nrow(most_improved_lhr_total)
## [1] 135
most_improved_lhr_total %>%
select(Country = country, Year = year,
`Actual latent human rights value (t + 1)` = latent_hr_mean_lead1,
`Predicted (baseline)` = estimate_baseline,
`Predicted (CS repression)` = estimate_total,
`|CS repression − baseline|` = abs_diff) %>%
head(5) %>%
kbl(digits = 3, align = "lccccc") %>%
kable_styling()
Country
|
Year
|
Actual latent human rights value (t + 1)
|
Predicted (baseline)
|
Predicted (CS repression)
|
|CS repression − baseline|
|
Cuba
|
2011
|
-0.069
|
-0.021
|
-0.070
|
0.049
|
Hungary
|
2013
|
1.555
|
1.596
|
1.551
|
0.045
|
Indonesia
|
2013
|
-0.214
|
-0.177
|
-0.217
|
0.040
|
Belarus
|
2012
|
0.208
|
0.245
|
0.207
|
0.037
|
North Korea
|
2012
|
-1.669
|
-1.637
|
-1.671
|
0.034
|
Barriers to advocacy
most_improved_lhr_advocacy <- bind_cols(
pred_lhr_baseline_test %>%
mutate(error_baseline = Estimate - latent_hr_mean_lead1) %>%
select(country, gwcode, year, latent_hr_mean_lead1,
estimate_baseline = Estimate, error_baseline),
pred_lhr_advocacy_test %>%
mutate(error_advocacy = Estimate - latent_hr_mean_lead1) %>%
select(estimate_advocacy = Estimate, error_advocacy)
) %>%
mutate(improved = error_advocacy < 0 & abs(error_advocacy) < abs(error_baseline)) %>%
mutate(diff = error_advocacy - error_baseline) %>%
mutate(abs_diff = abs(diff)) %>%
filter(improved) %>%
arrange(desc(abs_diff))
nrow(most_improved_lhr_advocacy)
## [1] 133
most_improved_lhr_advocacy %>%
select(Country = country, Year = year,
`Actual latent human rights value (t + 1)` = latent_hr_mean_lead1,
`Predicted (baseline)` = estimate_baseline,
`Predicted (CS repression)` = estimate_advocacy,
`|CS repression − baseline|` = abs_diff) %>%
head(5) %>%
kbl(digits = 3, align = "lccccc") %>%
kable_styling()
Country
|
Year
|
Actual latent human rights value (t + 1)
|
Predicted (baseline)
|
Predicted (CS repression)
|
|CS repression − baseline|
|
Belarus
|
2012
|
0.208
|
0.245
|
0.207
|
0.037
|
North Korea
|
2012
|
-1.669
|
-1.637
|
-1.670
|
0.033
|
Cuba
|
2012
|
-0.078
|
-0.054
|
-0.087
|
0.033
|
Algeria
|
2012
|
0.469
|
0.484
|
0.455
|
0.029
|
Bhutan
|
2013
|
1.728
|
1.492
|
1.515
|
0.023
|
Barriers to entry
most_improved_lhr_entry <- bind_cols(
pred_lhr_baseline_test %>%
mutate(error_baseline = Estimate - latent_hr_mean_lead1) %>%
select(country, gwcode, year, latent_hr_mean_lead1,
estimate_baseline = Estimate, error_baseline),
pred_lhr_entry_test %>%
mutate(error_entry = Estimate - latent_hr_mean_lead1) %>%
select(estimate_entry = Estimate, error_entry)
) %>%
mutate(improved = error_entry < 0 & abs(error_entry) < abs(error_baseline)) %>%
mutate(diff = error_entry - error_baseline) %>%
mutate(abs_diff = abs(diff)) %>%
filter(improved) %>%
arrange(desc(abs_diff))
nrow(most_improved_lhr_entry)
## [1] 116
most_improved_lhr_entry %>%
select(Country = country, Year = year,
`Actual latent human rights value (t + 1)` = latent_hr_mean_lead1,
`Predicted (baseline)` = estimate_baseline,
`Predicted (CS repression)` = estimate_entry,
`|CS repression − baseline|` = abs_diff) %>%
head(5) %>%
kbl(digits = 3, align = "lccccc") %>%
kable_styling()
Country
|
Year
|
Actual latent human rights value (t + 1)
|
Predicted (baseline)
|
Predicted (CS repression)
|
|CS repression − baseline|
|
Tunisia
|
2011
|
0.261
|
0.149
|
0.174
|
0.026
|
New Zealand
|
2012
|
3.605
|
3.536
|
3.559
|
0.023
|
Cuba
|
2013
|
-0.072
|
-0.061
|
-0.073
|
0.012
|
Syria
|
2012
|
-2.156
|
-2.208
|
-2.196
|
0.012
|
Solomon Islands
|
2013
|
4.001
|
3.911
|
3.923
|
0.012
|
Barriers to funding
most_improved_lhr_funding <- bind_cols(
pred_lhr_baseline_test %>%
mutate(error_baseline = Estimate - latent_hr_mean_lead1) %>%
select(country, gwcode, year, latent_hr_mean_lead1,
estimate_baseline = Estimate, error_baseline),
pred_lhr_funding_test %>%
mutate(error_funding = Estimate - latent_hr_mean_lead1) %>%
select(estimate_funding = Estimate, error_funding)
) %>%
mutate(improved = error_funding < 0 & abs(error_funding) < abs(error_baseline)) %>%
mutate(diff = error_funding - error_baseline) %>%
mutate(abs_diff = abs(diff)) %>%
filter(improved) %>%
arrange(desc(abs_diff))
nrow(most_improved_lhr_funding)
## [1] 150
most_improved_lhr_funding %>%
select(Country = country, Year = year,
`Actual latent human rights value (t + 1)` = latent_hr_mean_lead1,
`Predicted (baseline)` = estimate_baseline,
`Predicted (CS repression)` = estimate_funding,
`|CS repression − baseline|` = abs_diff) %>%
head(5) %>%
kbl(digits = 3, align = "lccccc") %>%
kable_styling()
Country
|
Year
|
Actual latent human rights value (t + 1)
|
Predicted (baseline)
|
Predicted (CS repression)
|
|CS repression − baseline|
|
North Korea
|
2013
|
-1.687
|
-1.632
|
-1.695
|
0.063
|
Cuba
|
2011
|
-0.069
|
-0.021
|
-0.078
|
0.057
|
Eritrea
|
2011
|
-1.314
|
-1.261
|
-1.318
|
0.057
|
Eritrea
|
2013
|
-1.341
|
-1.298
|
-1.355
|
0.057
|
Eritrea
|
2012
|
-1.319
|
-1.288
|
-1.345
|
0.057
|
E2a: Civil society environment and political terror
seed_pts_prediction <- 5494 # From random.org
set.seed(seed_pts_prediction)
pred_pts_baseline <- predict(
m_pts_baseline_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
set.seed(seed_pts_prediction)
pred_pts_v2csreprss <- predict(
m_pts_v2csreprss_train,
newdata = select(canary_testing_lagged, -PTS_factor_lead1),
allow_new_levels = TRUE
) %>%
as_tibble() %>%
magrittr::set_colnames(pts_levels)
Separation plots
Baseline model
# Match each column in pred_mat (predicted probabilities for each response level)
pred_long_list <- lapply(1:ncol(pred_pts_baseline),
FUN = match_actual,
pred = pred_pts_baseline,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_baseline)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Model with civil society repression
pred_long_list <- lapply(1:ncol(pred_pts_v2csreprss),
FUN = match_actual,
pred = pred_pts_v2csreprss,
actual = as.character(canary_testing_lagged$PTS_factor_lead1))
plot_data <- pred_long_list %>%
bind_rows() %>%
filter(!is.nan(fitted), !is.na(actual)) %>%
group_by(plot_level) %>%
arrange(plot_level, fitted) %>%
mutate(index = row_number()) %>%
ungroup()
markers <- plot_data %>%
group_by(plot_level) %>%
summarize(obs = n(), expected = sum(fitted),
marker = obs - expected + 1)
n_in_group <- nrow(pred_pts_v2csreprss)
plot_data_condensed <- plot_data %>%
# rle(), dplyr-style: https://stackoverflow.com/a/33510765/120898
mutate(rleid = (actual != lag(actual, 1, default = 0))) %>%
mutate(rleid = cumsum(rleid)) %>%
group_by(plot_level, rleid) %>%
slice(1) %>%
group_by(plot_level) %>%
mutate(xmin = index, xmax = lead(index, default = n_in_group)) %>%
ungroup()
ggplot(plot_data_condensed) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = 0, ymax = 1, fill = as.factor(actual))) +
geom_line(aes(x = index, y = fitted), size = 0.3) +
geom_point(data = markers, aes(x = marker, y = -0.05), shape = 17, size = 3) +
scale_fill_manual(values = c("grey90", "#2ECC40")) +
guides(fill = "none") +
facet_wrap(vars(plot_level), ncol = 1, scales = "free_x") +
theme_void(base_family = "Inter Bold")
Prediction diagnostics
pred_pts_baseline_categories <- pred_pts_baseline %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pred_pts_v2csreprss_categories <- pred_pts_v2csreprss %>%
rownames_to_column() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
filter(rank(-value, ties.method = "last") == 1) %>%
ungroup() %>%
select(predicted = name)
pts_cat_preds <- canary_testing_lagged %>%
select(country, year, actual = PTS_factor_lead1) %>%
mutate(pred_baseline = pred_pts_baseline_categories$predicted,
pred_v2csreprss = pred_pts_v2csreprss_categories$predicted) %>%
filter(!is.na(actual)) %>%
mutate(is_correct_baseline = actual == pred_baseline,
is_correct_v2csreprss = actual == pred_v2csreprss)
# Improved predictions
pts_improved <- pts_cat_preds %>%
filter(!is_correct_baseline & is_correct_v2csreprss) %>%
select(Country = country, Year = year, Actual = actual,
`CS repression included` = pred_v2csreprss,
`Baseline` = pred_baseline)
pts_improved %>%
kbl() %>%
kable_styling()
Country
|
Year
|
Actual
|
CS repression included
|
Baseline
|
Guatemala
|
2013
|
Level 3
|
Level 3
|
Level 2
|
Kosovo
|
2012
|
Level 1
|
Level 1
|
Level 2
|
Congo - Brazzaville
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Libya
|
2011
|
Level 4
|
Level 4
|
Level 5
|
Bahrain
|
2011
|
Level 3
|
Level 3
|
Level 2
|
Bahrain
|
2013
|
Level 3
|
Level 3
|
Level 2
|
correct_lookup <- tribble(
~name, ~nice_name,
"is_correct_v2csreprss", "CS repression included",
"is_correct_baseline", "Baseline"
) %>% mutate(nice_name = fct_inorder(nice_name, ordered = TRUE))
pts_pred_table <- pts_cat_preds %>%
pivot_longer(starts_with("is_correct")) %>%
group_by(name, value) %>%
summarize(n = n()) %>%
ungroup() %>%
left_join(correct_lookup, by = "name") %>%
mutate(Prediction = ifelse(value == TRUE, "Correct", "Wrong")) %>%
arrange(nice_name) %>%
select(-name, -value) %>%
pivot_wider(names_from = "nice_name", values_from = "n")
pts_pred_table %>%
kbl(align = "lcc") %>%
kable_styling()
Prediction
|
CS repression included
|
Baseline
|
Wrong
|
111
|
109
|
Correct
|
374
|
376
|
E2b: Civil society environment and latent human rights
seed_lhr_prediction <- 3207 # From random.org
set.seed(seed_lhr_prediction)
pred_lhr_baseline <- predict(m_lhr_baseline_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
set.seed(seed_lhr_prediction)
pred_lhr_v2csreprss <- predict(m_lhr_v2csreprss_train,
newdata = select(canary_testing_lagged, -latent_hr_mean_lead1),
allow_new_levels = TRUE)
pred_lhr_baseline_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_baseline)) %>%
filter(!is.na(latent_hr_mean_lead1))
pred_lhr_v2csreprss_test <- canary_testing_lagged %>%
select(country, gwcode, year, latent_hr_mean_lead1) %>%
bind_cols(as_tibble(pred_lhr_v2csreprss)) %>%
filter(!is.na(latent_hr_mean_lead1))
Improvement from baseline models
plot_baseline <- ggplot(pred_lhr_baseline_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Baseline",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
plot_v2csreprss <- ggplot(pred_lhr_v2csreprss_test,
aes(x = latent_hr_mean_lead1, y = Estimate)) +
geom_abline(lty = 2) +
geom_point(alpha = 0.5) +
labs(title = "Added predictor",
x = "Actual latent human rights value (t + 1)",
y = "Predicted latent human rights value (t + 1)") +
coord_equal() +
theme_ngo()
plot_baseline | plot_v2csreprss
lotsa_metrics <- metric_set(rmse, rsq, mae, ccc)
bind_rows(lotsa_metrics(pred_lhr_baseline_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Baseline"),
lotsa_metrics(pred_lhr_v2csreprss_test,
truth = latent_hr_mean_lead1,
estimate = Estimate) %>%
mutate(Model = "Added predictor")) %>%
select(Model, .metric, .estimate) %>%
pivot_wider(names_from = ".metric", values_from = ".estimate")
Model
|
rmse
|
rsq
|
mae
|
ccc
|
Baseline
|
0.1862156
|
0.9822788
|
0.1080593
|
0.9887926
|
Added predictor
|
0.1857038
|
0.9823449
|
0.1077390
|
0.9888036
|
Most improved countries
most_improved_lhr <- bind_cols(
pred_lhr_baseline_test %>%
mutate(error_baseline = Estimate - latent_hr_mean_lead1) %>%
select(country, gwcode, year, latent_hr_mean_lead1,
estimate_baseline = Estimate, error_baseline),
pred_lhr_v2csreprss_test %>%
mutate(error_v2csreprss = Estimate - latent_hr_mean_lead1) %>%
select(estimate_v2csreprss = Estimate, error_v2csreprss)
) %>%
# mutate(across(starts_with("error"), ~round(., 4))) %>%
mutate(improved = error_v2csreprss < 0 & abs(error_v2csreprss) < abs(error_baseline)) %>%
mutate(diff = error_v2csreprss - error_baseline) %>%
mutate(abs_diff = abs(diff)) %>%
filter(improved) %>%
arrange(desc(abs_diff))
nrow(most_improved_lhr)
## [1] 127
most_improved_lhr %>%
select(Country = country, Year = year,
`Actual latent human rights value (t + 1)` = latent_hr_mean_lead1,
`Predicted (baseline)` = estimate_baseline,
`Predicted (CS repression)` = estimate_v2csreprss,
`|CS repression − baseline|` = abs_diff) %>%
head(5) %>%
kbl(digits = 3, align = "lccccc") %>%
kable_styling()
Country
|
Year
|
Actual latent human rights value (t + 1)
|
Predicted (baseline)
|
Predicted (CS repression)
|
|CS repression − baseline|
|
Libya
|
2011
|
-1.395
|
-1.818
|
-1.676
|
0.142
|
Fiji
|
2013
|
1.672
|
1.377
|
1.428
|
0.051
|
Mauritania
|
2013
|
0.558
|
0.595
|
0.555
|
0.040
|
Colombia
|
2011
|
-1.013
|
-1.090
|
-1.051
|
0.039
|
Slovakia
|
2011
|
2.019
|
1.908
|
1.943
|
0.035
|
LS0tCnRpdGxlOiAiUHJlZGljdGlvbnMiCmF1dGhvcjogIlN1cGFybmEgQ2hhdWRocnkgYW5kIEFuZHJldyBIZWlzcyIKZGF0ZTogIkxhc3QgcnVuOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVGJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKa25pdF9wcmludC5kYXRhLmZyYW1lIDwtIGZ1bmN0aW9uKHgsIC4uLikgewogIHJlcyA8LSBwYXN0ZShjKCcnLCAnJywga2FibGVfc3R5bGluZyhrYWJsZSh4LCBib29rdGFicyA9IFRSVUUpKSksIGNvbGxhcHNlID0gJ1xuJykKICBhc2lzX291dHB1dChyZXMpCn0KCnJlZ2lzdGVyUzNtZXRob2QoImtuaXRfcHJpbnQiLCAiZGF0YS5mcmFtZSIsIGtuaXRfcHJpbnQuZGF0YS5mcmFtZSkKcmVnaXN0ZXJTM21ldGhvZCgia25pdF9wcmludCIsICJncm91cGVkX2RmIiwga25pdF9wcmludC5kYXRhLmZyYW1lKQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5yZXRpbmEgPSAzLAogICAgICAgICAgICAgICAgICAgICAgdGlkeS5vcHRzID0gbGlzdCh3aWR0aC5jdXRvZmYgPSAxMjApLCAgIyBGb3IgY29kZQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyh3aWR0aCA9IDkwKSwgICMgRm9yIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFzcCA9IDAuNjE4LCBmaWcud2lkdGggPSA3LCAKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAiODUlIikKCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFLAogICAgICAgIGtuaXRyLmthYmxlLk5BID0gIiIpCmBgYAoKYGBge3IgbG9hZC1saWJyYXJpZXMtZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGFyZ2V0cykKbGlicmFyeSh5YXJkc3RpY2spCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShoZXJlKQoKIyBMb2FkIGRhdGEKIyBOZWVkIHRvIHVzZSB0aGlzIHdpdGhyIHRoaW5nIGJlY2F1c2UgdGFyX3JlYWQoKSBhbmQgdGFyX2xvYWQoKSBuZWVkIHRvIHNlZSB0aGUKIyBfdGFyZ2V0cyBmb2xkZXIgaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5LCBidXQgdGhpcyAuUm1kIGZpbGUgaXMgaW4gYSBzdWJmb2xkZXIKd2l0aHI6OndpdGhfZGlyKGhlcmU6OmhlcmUoKSwgewogIHNvdXJjZSh0YXJfcmVhZChwbG90X2Z1bnMpKQogIAogIGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCA8LSB0YXJfcmVhZChwYW5lbF90ZXN0aW5nX2xhZ2dlZCkKICAKICAjIExvYWQgYmlnIGxpc3Qgb2YgbW9kZWxzCiAgbW9kZWxfZGYgPC0gdGFyX3JlYWQobW9kZWxfZGYpICU+JSAKICAgIGZpbHRlcihzdHJfZGV0ZWN0KG1vZGVsLCAiYmFzZWxpbmUiKSB8IHN0cl9kZXRlY3QobW9kZWwsICJ2MmNzcmVwcnNzIikpCiAgCiAgIyBMb2FkIGFjdHVhbCBtb2RlbCBvYmplY3RzCiAgdGFyX2xvYWQoYyhtX3B0c19iYXNlbGluZV90cmFpbiwgbV9wdHNfdjJjc3JlcHJzc190cmFpbiwKICAgICAgICAgICAgIG1fcHRzX3RvdGFsX3RyYWluLCBtX3B0c19hZHZvY2FjeV90cmFpbiwgCiAgICAgICAgICAgICBtX3B0c19lbnRyeV90cmFpbiwgbV9wdHNfZnVuZGluZ190cmFpbiwKICAgICAgICAgICAgIG1fbGhyX2Jhc2VsaW5lX3RyYWluLCBtX2xocl92MmNzcmVwcnNzX3RyYWluLAogICAgICAgICAgICAgbV9saHJfdG90YWxfdHJhaW4sIG1fbGhyX2Fkdm9jYWN5X3RyYWluLCAKICAgICAgICAgICAgIG1fbGhyX2VudHJ5X3RyYWluLCBtX2xocl9mdW5kaW5nX3RyYWluKSkKfSkKCnB0c19sZXZlbHMgPC0gbGV2ZWxzKGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCRQVFNfZmFjdG9yKQoKIyBSZXR1cm5zIGEgZGF0YSBmcmFtZSBvZiBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyB3aXRoIGFjdHVhbCA9IDEgCiMgd2hlbiB0aGUgcmVzcG9uc2Ugb3V0Y29tZSBoYXBwZW5zCm1hdGNoX2FjdHVhbCA8LSBmdW5jdGlvbih4LCBwcmVkLCBhY3R1YWwpIHsKICBwcmVkICU+JSAKICAgIHNlbGVjdChmaXR0ZWQgPSB7e3h9fSkgJT4lIAogICAgbXV0YXRlKGFjdHVhbCA9IGFzLm51bWVyaWMoYWN0dWFsID09IGNvbG5hbWVzKHByZWRbeF0pKSwKICAgICAgICAgICBwbG90X2xldmVsID0gY29sbmFtZXMocHJlZFt4XSkpCn0KYGBgCgojIEV+MWF+OiBOR08gbGF3cyBhbmQgcG9saXRpY2FsIHRlcnJvcgoKYGBge3IgZTFhLXByZWRpY3Rpb25zLCB3YXJuaW5nPUZBTFNFfQpzZWVkX3B0c19wcmVkaWN0aW9uIDwtIDU0OTQgICMgRnJvbSByYW5kb20ub3JnCgpzZXQuc2VlZChzZWVkX3B0c19wcmVkaWN0aW9uKQpwcmVkX3B0c19iYXNlbGluZSA8LSBwcmVkaWN0KAogIG1fcHRzX2Jhc2VsaW5lX3RyYWluLCAKICBuZXdkYXRhID0gc2VsZWN0KGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCwgLVBUU19mYWN0b3JfbGVhZDEpLAogIGFsbG93X25ld19sZXZlbHMgPSBUUlVFCikgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtYWdyaXR0cjo6c2V0X2NvbG5hbWVzKHB0c19sZXZlbHMpCgpzZXQuc2VlZChzZWVkX3B0c19wcmVkaWN0aW9uKQpwcmVkX3B0c190b3RhbCA8LSBwcmVkaWN0KAogIG1fcHRzX3RvdGFsX3RyYWluLCAKICBuZXdkYXRhID0gc2VsZWN0KGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCwgLVBUU19mYWN0b3JfbGVhZDEpLAogIGFsbG93X25ld19sZXZlbHMgPSBUUlVFCikgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtYWdyaXR0cjo6c2V0X2NvbG5hbWVzKHB0c19sZXZlbHMpCgpzZXQuc2VlZChzZWVkX3B0c19wcmVkaWN0aW9uKQpwcmVkX3B0c19hZHZvY2FjeSA8LSBwcmVkaWN0KAogIG1fcHRzX2Fkdm9jYWN5X3RyYWluLCAKICBuZXdkYXRhID0gc2VsZWN0KGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCwgLVBUU19mYWN0b3JfbGVhZDEpLAogIGFsbG93X25ld19sZXZlbHMgPSBUUlVFCikgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtYWdyaXR0cjo6c2V0X2NvbG5hbWVzKHB0c19sZXZlbHMpCgpzZXQuc2VlZChzZWVkX3B0c19wcmVkaWN0aW9uKQpwcmVkX3B0c19lbnRyeSA8LSBwcmVkaWN0KAogIG1fcHRzX2VudHJ5X3RyYWluLCAKICBuZXdkYXRhID0gc2VsZWN0KGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCwgLVBUU19mYWN0b3JfbGVhZDEpLAogIGFsbG93X25ld19sZXZlbHMgPSBUUlVFCikgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtYWdyaXR0cjo6c2V0X2NvbG5hbWVzKHB0c19sZXZlbHMpCgpzZXQuc2VlZChzZWVkX3B0c19wcmVkaWN0aW9uKQpwcmVkX3B0c19mdW5kaW5nIDwtIHByZWRpY3QoCiAgbV9wdHNfZnVuZGluZ190cmFpbiwgCiAgbmV3ZGF0YSA9IHNlbGVjdChjYW5hcnlfdGVzdGluZ19sYWdnZWQsIC1QVFNfZmFjdG9yX2xlYWQxKSwKICBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRQopICU+JSAKICBhc190aWJibGUoKSAlPiUgCiAgbWFncml0dHI6OnNldF9jb2xuYW1lcyhwdHNfbGV2ZWxzKQpgYGAKCiMjIFNlcGFyYXRpb24gcGxvdHMKCiMjIyBCYXNlbGluZSBtb2RlbHMKCmBgYHtyIGUxYS1zZXBhcmF0aW9uLWJhc2VsaW5lfQojIE1hdGNoIGVhY2ggY29sdW1uIGluIHByZWRfbWF0IChwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBmb3IgZWFjaCByZXNwb25zZSBsZXZlbCkKcHJlZF9sb25nX2xpc3QgPC0gbGFwcGx5KDE6bmNvbChwcmVkX3B0c19iYXNlbGluZSksIAogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWF0Y2hfYWN0dWFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHByZWQgPSBwcmVkX3B0c19iYXNlbGluZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBhY3R1YWwgPSBhcy5jaGFyYWN0ZXIoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkJFBUU19mYWN0b3JfbGVhZDEpKQoKcGxvdF9kYXRhIDwtIHByZWRfbG9uZ19saXN0ICU+JSAKICBiaW5kX3Jvd3MoKSAlPiUgCiAgZmlsdGVyKCFpcy5uYW4oZml0dGVkKSwgIWlzLm5hKGFjdHVhbCkpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUgCiAgYXJyYW5nZShwbG90X2xldmVsLCBmaXR0ZWQpICU+JSAKICBtdXRhdGUoaW5kZXggPSByb3dfbnVtYmVyKCkpICU+JSAKICB1bmdyb3VwKCkKCm1hcmtlcnMgPC0gcGxvdF9kYXRhICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUKICBzdW1tYXJpemUob2JzID0gbigpLCBleHBlY3RlZCA9IHN1bShmaXR0ZWQpLAogICAgICAgICAgICBtYXJrZXIgPSBvYnMgLSBleHBlY3RlZCArIDEpCgpuX2luX2dyb3VwIDwtIG5yb3cocHJlZF9wdHNfYmFzZWxpbmUpCgpwbG90X2RhdGFfY29uZGVuc2VkIDwtIHBsb3RfZGF0YSAlPiUgCiAgIyBybGUoKSwgZHBseXItc3R5bGU6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zMzUxMDc2NS8xMjA4OTgKICBtdXRhdGUocmxlaWQgPSAoYWN0dWFsICE9IGxhZyhhY3R1YWwsIDEsIGRlZmF1bHQgPSAwKSkpICU+JQogIG11dGF0ZShybGVpZCA9IGN1bXN1bShybGVpZCkpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsLCBybGVpZCkgJT4lIAogIHNsaWNlKDEpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUgCiAgbXV0YXRlKHhtaW4gPSBpbmRleCwgeG1heCA9IGxlYWQoaW5kZXgsIGRlZmF1bHQgPSBuX2luX2dyb3VwKSkgJT4lIAogIHVuZ3JvdXAoKQoKZ2dwbG90KHBsb3RfZGF0YV9jb25kZW5zZWQpICsKICBnZW9tX3JlY3QoYWVzKHhtaW4gPSB4bWluLCB4bWF4ID0geG1heCwgeW1pbiA9IDAsIHltYXggPSAxLCBmaWxsID0gYXMuZmFjdG9yKGFjdHVhbCkpKSArIAogIGdlb21fbGluZShhZXMoeCA9IGluZGV4LCB5ID0gZml0dGVkKSwgc2l6ZSA9IDAuMykgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1hcmtlcnMsIGFlcyh4ID0gbWFya2VyLCB5ID0gLTAuMDUpLCBzaGFwZSA9IDE3LCBzaXplID0gMykgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5OTAiLCAiIzJFQ0M0MCIpKSArCiAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICBmYWNldF93cmFwKHZhcnMocGxvdF9sZXZlbCksIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX3ZvaWQoYmFzZV9mYW1pbHkgPSAiSW50ZXIgQm9sZCIpCmBgYAoKIyMjIE1vZGVscyB3aXRoIE5HTyBsYXdzCgojIyMjIFRvdGFsIGxlZ2FsIGJhcnJpZXJzCgpgYGB7ciBlMWEtc2VwYXJhdGlvbi10b3RhbH0KIyBNYXRjaCBlYWNoIGNvbHVtbiBpbiBwcmVkX21hdCAocHJlZGljdGVkIHByb2JhYmlsaXRpZXMgZm9yIGVhY2ggcmVzcG9uc2UgbGV2ZWwpCnByZWRfbG9uZ19saXN0IDwtIGxhcHBseSgxOm5jb2wocHJlZF9wdHNfdG90YWwpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1hdGNoX2FjdHVhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwcmVkID0gcHJlZF9wdHNfdG90YWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgYWN0dWFsID0gYXMuY2hhcmFjdGVyKGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCRQVFNfZmFjdG9yX2xlYWQxKSkKCnBsb3RfZGF0YSA8LSBwcmVkX2xvbmdfbGlzdCAlPiUgCiAgYmluZF9yb3dzKCkgJT4lIAogIGZpbHRlcighaXMubmFuKGZpdHRlZCksICFpcy5uYShhY3R1YWwpKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lIAogIGFycmFuZ2UocGxvdF9sZXZlbCwgZml0dGVkKSAlPiUgCiAgbXV0YXRlKGluZGV4ID0gcm93X251bWJlcigpKSAlPiUgCiAgdW5ncm91cCgpCgptYXJrZXJzIDwtIHBsb3RfZGF0YSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lCiAgc3VtbWFyaXplKG9icyA9IG4oKSwgZXhwZWN0ZWQgPSBzdW0oZml0dGVkKSwKICAgICAgICAgICAgbWFya2VyID0gb2JzIC0gZXhwZWN0ZWQgKyAxKQoKbl9pbl9ncm91cCA8LSBucm93KHByZWRfcHRzX3RvdGFsKQoKcGxvdF9kYXRhX2NvbmRlbnNlZCA8LSBwbG90X2RhdGEgJT4lIAogICMgcmxlKCksIGRwbHlyLXN0eWxlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzM1MTA3NjUvMTIwODk4CiAgbXV0YXRlKHJsZWlkID0gKGFjdHVhbCAhPSBsYWcoYWN0dWFsLCAxLCBkZWZhdWx0ID0gMCkpKSAlPiUKICBtdXRhdGUocmxlaWQgPSBjdW1zdW0ocmxlaWQpKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCwgcmxlaWQpICU+JSAKICBzbGljZSgxKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lIAogIG11dGF0ZSh4bWluID0gaW5kZXgsIHhtYXggPSBsZWFkKGluZGV4LCBkZWZhdWx0ID0gbl9pbl9ncm91cCkpICU+JSAKICB1bmdyb3VwKCkKCmdncGxvdChwbG90X2RhdGFfY29uZGVuc2VkKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0geG1pbiwgeG1heCA9IHhtYXgsIHltaW4gPSAwLCB5bWF4ID0gMSwgZmlsbCA9IGFzLmZhY3RvcihhY3R1YWwpKSkgKyAKICBnZW9tX2xpbmUoYWVzKHggPSBpbmRleCwgeSA9IGZpdHRlZCksIHNpemUgPSAwLjMpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtYXJrZXJzLCBhZXMoeCA9IG1hcmtlciwgeSA9IC0wLjA1KSwgc2hhcGUgPSAxNywgc2l6ZSA9IDMpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JleTkwIiwgIiMyRUNDNDAiKSkgKwogIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCh2YXJzKHBsb3RfbGV2ZWwpLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV92b2lkKGJhc2VfZmFtaWx5ID0gIkludGVyIEJvbGQiKQpgYGAKCiMjIyMgQmFycmllcnMgdG8gYWR2b2NhY3kKCmBgYHtyIGUxYS1zZXBhcmF0aW9uLWFkdm9jYWN5fQojIE1hdGNoIGVhY2ggY29sdW1uIGluIHByZWRfbWF0IChwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBmb3IgZWFjaCByZXNwb25zZSBsZXZlbCkKcHJlZF9sb25nX2xpc3QgPC0gbGFwcGx5KDE6bmNvbChwcmVkX3B0c19hZHZvY2FjeSksIAogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWF0Y2hfYWN0dWFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHByZWQgPSBwcmVkX3B0c19hZHZvY2FjeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBhY3R1YWwgPSBhcy5jaGFyYWN0ZXIoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkJFBUU19mYWN0b3JfbGVhZDEpKQoKcGxvdF9kYXRhIDwtIHByZWRfbG9uZ19saXN0ICU+JSAKICBiaW5kX3Jvd3MoKSAlPiUgCiAgZmlsdGVyKCFpcy5uYW4oZml0dGVkKSwgIWlzLm5hKGFjdHVhbCkpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUgCiAgYXJyYW5nZShwbG90X2xldmVsLCBmaXR0ZWQpICU+JSAKICBtdXRhdGUoaW5kZXggPSByb3dfbnVtYmVyKCkpICU+JSAKICB1bmdyb3VwKCkKCm1hcmtlcnMgPC0gcGxvdF9kYXRhICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUKICBzdW1tYXJpemUob2JzID0gbigpLCBleHBlY3RlZCA9IHN1bShmaXR0ZWQpLAogICAgICAgICAgICBtYXJrZXIgPSBvYnMgLSBleHBlY3RlZCArIDEpCgpuX2luX2dyb3VwIDwtIG5yb3cocHJlZF9wdHNfYWR2b2NhY3kpCgpwbG90X2RhdGFfY29uZGVuc2VkIDwtIHBsb3RfZGF0YSAlPiUgCiAgIyBybGUoKSwgZHBseXItc3R5bGU6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zMzUxMDc2NS8xMjA4OTgKICBtdXRhdGUocmxlaWQgPSAoYWN0dWFsICE9IGxhZyhhY3R1YWwsIDEsIGRlZmF1bHQgPSAwKSkpICU+JQogIG11dGF0ZShybGVpZCA9IGN1bXN1bShybGVpZCkpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsLCBybGVpZCkgJT4lIAogIHNsaWNlKDEpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUgCiAgbXV0YXRlKHhtaW4gPSBpbmRleCwgeG1heCA9IGxlYWQoaW5kZXgsIGRlZmF1bHQgPSBuX2luX2dyb3VwKSkgJT4lIAogIHVuZ3JvdXAoKQoKZ2dwbG90KHBsb3RfZGF0YV9jb25kZW5zZWQpICsKICBnZW9tX3JlY3QoYWVzKHhtaW4gPSB4bWluLCB4bWF4ID0geG1heCwgeW1pbiA9IDAsIHltYXggPSAxLCBmaWxsID0gYXMuZmFjdG9yKGFjdHVhbCkpKSArIAogIGdlb21fbGluZShhZXMoeCA9IGluZGV4LCB5ID0gZml0dGVkKSwgc2l6ZSA9IDAuMykgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1hcmtlcnMsIGFlcyh4ID0gbWFya2VyLCB5ID0gLTAuMDUpLCBzaGFwZSA9IDE3LCBzaXplID0gMykgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5OTAiLCAiIzJFQ0M0MCIpKSArCiAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICBmYWNldF93cmFwKHZhcnMocGxvdF9sZXZlbCksIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX3ZvaWQoYmFzZV9mYW1pbHkgPSAiSW50ZXIgQm9sZCIpCmBgYAoKIyMjIyBCYXJyaWVycyB0byBlbnRyeQoKYGBge3IgZTFhLXNlcGFyYXRpb24tZW50cnl9CiMgTWF0Y2ggZWFjaCBjb2x1bW4gaW4gcHJlZF9tYXQgKHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIGZvciBlYWNoIHJlc3BvbnNlIGxldmVsKQpwcmVkX2xvbmdfbGlzdCA8LSBsYXBwbHkoMTpuY29sKHByZWRfcHRzX2VudHJ5KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBtYXRjaF9hY3R1YWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgcHJlZCA9IHByZWRfcHRzX2VudHJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGFjdHVhbCA9IGFzLmNoYXJhY3RlcihjYW5hcnlfdGVzdGluZ19sYWdnZWQkUFRTX2ZhY3Rvcl9sZWFkMSkpCgpwbG90X2RhdGEgPC0gcHJlZF9sb25nX2xpc3QgJT4lIAogIGJpbmRfcm93cygpICU+JSAKICBmaWx0ZXIoIWlzLm5hbihmaXR0ZWQpLCAhaXMubmEoYWN0dWFsKSkgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwpICU+JSAKICBhcnJhbmdlKHBsb3RfbGV2ZWwsIGZpdHRlZCkgJT4lIAogIG11dGF0ZShpbmRleCA9IHJvd19udW1iZXIoKSkgJT4lIAogIHVuZ3JvdXAoKQoKbWFya2VycyA8LSBwbG90X2RhdGEgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwpICU+JQogIHN1bW1hcml6ZShvYnMgPSBuKCksIGV4cGVjdGVkID0gc3VtKGZpdHRlZCksCiAgICAgICAgICAgIG1hcmtlciA9IG9icyAtIGV4cGVjdGVkICsgMSkKCm5faW5fZ3JvdXAgPC0gbnJvdyhwcmVkX3B0c19lbnRyeSkKCnBsb3RfZGF0YV9jb25kZW5zZWQgPC0gcGxvdF9kYXRhICU+JSAKICAjIHJsZSgpLCBkcGx5ci1zdHlsZTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzMzNTEwNzY1LzEyMDg5OAogIG11dGF0ZShybGVpZCA9IChhY3R1YWwgIT0gbGFnKGFjdHVhbCwgMSwgZGVmYXVsdCA9IDApKSkgJT4lCiAgbXV0YXRlKHJsZWlkID0gY3Vtc3VtKHJsZWlkKSkgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwsIHJsZWlkKSAlPiUgCiAgc2xpY2UoMSkgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwpICU+JSAKICBtdXRhdGUoeG1pbiA9IGluZGV4LCB4bWF4ID0gbGVhZChpbmRleCwgZGVmYXVsdCA9IG5faW5fZ3JvdXApKSAlPiUgCiAgdW5ncm91cCgpCgpnZ3Bsb3QocGxvdF9kYXRhX2NvbmRlbnNlZCkgKwogIGdlb21fcmVjdChhZXMoeG1pbiA9IHhtaW4sIHhtYXggPSB4bWF4LCB5bWluID0gMCwgeW1heCA9IDEsIGZpbGwgPSBhcy5mYWN0b3IoYWN0dWFsKSkpICsgCiAgZ2VvbV9saW5lKGFlcyh4ID0gaW5kZXgsIHkgPSBmaXR0ZWQpLCBzaXplID0gMC4zKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWFya2VycywgYWVzKHggPSBtYXJrZXIsIHkgPSAtMC4wNSksIHNoYXBlID0gMTcsIHNpemUgPSAzKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk5MCIsICIjMkVDQzQwIikpICsKICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogIGZhY2V0X3dyYXAodmFycyhwbG90X2xldmVsKSwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgdGhlbWVfdm9pZChiYXNlX2ZhbWlseSA9ICJJbnRlciBCb2xkIikKYGBgCgojIyMjIEJhcnJpZXJzIHRvIGZ1bmRpbmcKCmBgYHtyIGUxYS1zZXBhcmF0aW9uLWZ1bmRpbmd9CiMgTWF0Y2ggZWFjaCBjb2x1bW4gaW4gcHJlZF9tYXQgKHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIGZvciBlYWNoIHJlc3BvbnNlIGxldmVsKQpwcmVkX2xvbmdfbGlzdCA8LSBsYXBwbHkoMTpuY29sKHByZWRfcHRzX2Z1bmRpbmcpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1hdGNoX2FjdHVhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwcmVkID0gcHJlZF9wdHNfZnVuZGluZywgCiAgICAgICAgICAgICAgICAgICAgICAgICBhY3R1YWwgPSBhcy5jaGFyYWN0ZXIoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkJFBUU19mYWN0b3JfbGVhZDEpKQoKcGxvdF9kYXRhIDwtIHByZWRfbG9uZ19saXN0ICU+JSAKICBiaW5kX3Jvd3MoKSAlPiUgCiAgZmlsdGVyKCFpcy5uYW4oZml0dGVkKSwgIWlzLm5hKGFjdHVhbCkpICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUgCiAgYXJyYW5nZShwbG90X2xldmVsLCBmaXR0ZWQpICU+JSAKICBtdXRhdGUoaW5kZXggPSByb3dfbnVtYmVyKCkpICU+JSAKICB1bmdyb3VwKCkKCm1hcmtlcnMgPC0gcGxvdF9kYXRhICU+JSAKICBncm91cF9ieShwbG90X2xldmVsKSAlPiUKICBzdW1tYXJpemUob2JzID0gbigpLCBleHBlY3RlZCA9IHN1bShmaXR0ZWQpLAogICAgICAgICAgICBtYXJrZXIgPSBvYnMgLSBleHBlY3RlZCArIDEpCgpuX2luX2dyb3VwIDwtIG5yb3cocHJlZF9wdHNfZnVuZGluZykKCnBsb3RfZGF0YV9jb25kZW5zZWQgPC0gcGxvdF9kYXRhICU+JSAKICAjIHJsZSgpLCBkcGx5ci1zdHlsZTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzMzNTEwNzY1LzEyMDg5OAogIG11dGF0ZShybGVpZCA9IChhY3R1YWwgIT0gbGFnKGFjdHVhbCwgMSwgZGVmYXVsdCA9IDApKSkgJT4lCiAgbXV0YXRlKHJsZWlkID0gY3Vtc3VtKHJsZWlkKSkgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwsIHJsZWlkKSAlPiUgCiAgc2xpY2UoMSkgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwpICU+JSAKICBtdXRhdGUoeG1pbiA9IGluZGV4LCB4bWF4ID0gbGVhZChpbmRleCwgZGVmYXVsdCA9IG5faW5fZ3JvdXApKSAlPiUgCiAgdW5ncm91cCgpCgpnZ3Bsb3QocGxvdF9kYXRhX2NvbmRlbnNlZCkgKwogIGdlb21fcmVjdChhZXMoeG1pbiA9IHhtaW4sIHhtYXggPSB4bWF4LCB5bWluID0gMCwgeW1heCA9IDEsIGZpbGwgPSBhcy5mYWN0b3IoYWN0dWFsKSkpICsgCiAgZ2VvbV9saW5lKGFlcyh4ID0gaW5kZXgsIHkgPSBmaXR0ZWQpLCBzaXplID0gMC4zKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWFya2VycywgYWVzKHggPSBtYXJrZXIsIHkgPSAtMC4wNSksIHNoYXBlID0gMTcsIHNpemUgPSAzKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk5MCIsICIjMkVDQzQwIikpICsKICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogIGZhY2V0X3dyYXAodmFycyhwbG90X2xldmVsKSwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgdGhlbWVfdm9pZChiYXNlX2ZhbWlseSA9ICJJbnRlciBCb2xkIikKYGBgCgojIyBQcmVkaWN0aW9uIGRpYWdub3N0aWNzCgpgYGB7ciBlMWEtaW1wcm92ZWQtY2FzZXN9CnByZWRfcHRzX2Jhc2VsaW5lX2NhdGVnb3JpZXMgPC0gcHJlZF9wdHNfYmFzZWxpbmUgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBwaXZvdF9sb25nZXIoLXJvd25hbWUpICU+JSAKICBncm91cF9ieShyb3duYW1lKSAlPiUgCiAgZmlsdGVyKHJhbmsoLXZhbHVlLCB0aWVzLm1ldGhvZCA9ICJsYXN0IikgPT0gMSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KHByZWRpY3RlZCA9IG5hbWUpCgpwcmVkX3B0c190b3RhbF9jYXRlZ29yaWVzIDwtIHByZWRfcHRzX3RvdGFsICU+JSAKICByb3duYW1lc190b19jb2x1bW4oKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1yb3duYW1lKSAlPiUgCiAgZ3JvdXBfYnkocm93bmFtZSkgJT4lIAogIGZpbHRlcihyYW5rKC12YWx1ZSwgdGllcy5tZXRob2QgPSAibGFzdCIpID09IDEpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdChwcmVkaWN0ZWQgPSBuYW1lKQoKcHJlZF9wdHNfYWR2b2NhY3lfY2F0ZWdvcmllcyA8LSBwcmVkX3B0c19hZHZvY2FjeSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogIHBpdm90X2xvbmdlcigtcm93bmFtZSkgJT4lIAogIGdyb3VwX2J5KHJvd25hbWUpICU+JSAKICBmaWx0ZXIocmFuaygtdmFsdWUsIHRpZXMubWV0aG9kID0gImxhc3QiKSA9PSAxKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QocHJlZGljdGVkID0gbmFtZSkKCnByZWRfcHRzX2VudHJ5X2NhdGVnb3JpZXMgPC0gcHJlZF9wdHNfZW50cnkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBwaXZvdF9sb25nZXIoLXJvd25hbWUpICU+JSAKICBncm91cF9ieShyb3duYW1lKSAlPiUgCiAgZmlsdGVyKHJhbmsoLXZhbHVlLCB0aWVzLm1ldGhvZCA9ICJsYXN0IikgPT0gMSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KHByZWRpY3RlZCA9IG5hbWUpCgpwcmVkX3B0c19mdW5kaW5nX2NhdGVnb3JpZXMgPC0gcHJlZF9wdHNfZnVuZGluZyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogIHBpdm90X2xvbmdlcigtcm93bmFtZSkgJT4lIAogIGdyb3VwX2J5KHJvd25hbWUpICU+JSAKICBmaWx0ZXIocmFuaygtdmFsdWUsIHRpZXMubWV0aG9kID0gImxhc3QiKSA9PSAxKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QocHJlZGljdGVkID0gbmFtZSkKCgpwdHNfY2F0X3ByZWRzIDwtIGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCAlPiUgCiAgc2VsZWN0KGNvdW50cnksIHllYXIsIGFjdHVhbCA9IFBUU19mYWN0b3JfbGVhZDEpICU+JSAKICBtdXRhdGUocHJlZF9iYXNlbGluZSA9IHByZWRfcHRzX2Jhc2VsaW5lX2NhdGVnb3JpZXMkcHJlZGljdGVkLAogICAgICAgICBwcmVkX3RvdGFsID0gcHJlZF9wdHNfdG90YWxfY2F0ZWdvcmllcyRwcmVkaWN0ZWQsCiAgICAgICAgIHByZWRfYWR2b2NhY3kgPSBwcmVkX3B0c19hZHZvY2FjeV9jYXRlZ29yaWVzJHByZWRpY3RlZCwKICAgICAgICAgcHJlZF9lbnRyeSA9IHByZWRfcHRzX2VudHJ5X2NhdGVnb3JpZXMkcHJlZGljdGVkLAogICAgICAgICBwcmVkX2Z1bmRpbmcgPSBwcmVkX3B0c19mdW5kaW5nX2NhdGVnb3JpZXMkcHJlZGljdGVkKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShhY3R1YWwpKSAlPiUKICBtdXRhdGUoaXNfY29ycmVjdF9iYXNlbGluZSA9IGFjdHVhbCA9PSBwcmVkX2Jhc2VsaW5lLAogICAgICAgICBpc19jb3JyZWN0X3RvdGFsID0gYWN0dWFsID09IHByZWRfdG90YWwsCiAgICAgICAgIGlzX2NvcnJlY3RfYWR2b2NhY3kgPSBhY3R1YWwgPT0gcHJlZF9hZHZvY2FjeSwKICAgICAgICAgaXNfY29ycmVjdF9lbnRyeSA9IGFjdHVhbCA9PSBwcmVkX2VudHJ5LAogICAgICAgICBpc19jb3JyZWN0X2Z1bmRpbmcgPSBhY3R1YWwgPT0gcHJlZF9mdW5kaW5nKQoKIyBJbXByb3ZlZCBwcmVkaWN0aW9ucwpwdHNfaW1wcm92ZWRfdG90YWwgPC0gcHRzX2NhdF9wcmVkcyAlPiUgCiAgZmlsdGVyKCFpc19jb3JyZWN0X2Jhc2VsaW5lICYgaXNfY29ycmVjdF90b3RhbCkgJT4lIAogIHNlbGVjdChDb3VudHJ5ID0gY291bnRyeSwgWWVhciA9IHllYXIsIEFjdHVhbCA9IGFjdHVhbCwKICAgICAgICAgYENTIHJlcHJlc3Npb24gaW5jbHVkZWRgID0gcHJlZF90b3RhbCwKICAgICAgICAgYEJhc2VsaW5lYCA9IHByZWRfYmFzZWxpbmUpCgpwdHNfaW1wcm92ZWRfYWR2b2NhY3kgPC0gcHRzX2NhdF9wcmVkcyAlPiUgCiAgZmlsdGVyKCFpc19jb3JyZWN0X2Jhc2VsaW5lICYgaXNfY29ycmVjdF9hZHZvY2FjeSkgJT4lIAogIHNlbGVjdChDb3VudHJ5ID0gY291bnRyeSwgWWVhciA9IHllYXIsIEFjdHVhbCA9IGFjdHVhbCwKICAgICAgICAgYENTIHJlcHJlc3Npb24gaW5jbHVkZWRgID0gcHJlZF9hZHZvY2FjeSwKICAgICAgICAgYEJhc2VsaW5lYCA9IHByZWRfYmFzZWxpbmUpCgpwdHNfaW1wcm92ZWRfZW50cnkgPC0gcHRzX2NhdF9wcmVkcyAlPiUgCiAgZmlsdGVyKCFpc19jb3JyZWN0X2Jhc2VsaW5lICYgaXNfY29ycmVjdF9lbnRyeSkgJT4lIAogIHNlbGVjdChDb3VudHJ5ID0gY291bnRyeSwgWWVhciA9IHllYXIsIEFjdHVhbCA9IGFjdHVhbCwKICAgICAgICAgYENTIHJlcHJlc3Npb24gaW5jbHVkZWRgID0gcHJlZF9lbnRyeSwKICAgICAgICAgYEJhc2VsaW5lYCA9IHByZWRfYmFzZWxpbmUpCgpwdHNfaW1wcm92ZWRfZnVuZGluZyA8LSBwdHNfY2F0X3ByZWRzICU+JSAKICBmaWx0ZXIoIWlzX2NvcnJlY3RfYmFzZWxpbmUgJiBpc19jb3JyZWN0X2Z1bmRpbmcpICU+JSAKICBzZWxlY3QoQ291bnRyeSA9IGNvdW50cnksIFllYXIgPSB5ZWFyLCBBY3R1YWwgPSBhY3R1YWwsCiAgICAgICAgIGBDUyByZXByZXNzaW9uIGluY2x1ZGVkYCA9IHByZWRfZnVuZGluZywKICAgICAgICAgYEJhc2VsaW5lYCA9IHByZWRfYmFzZWxpbmUpCgpwdHNfaW1wcm92ZWRfdG90YWwgJT4lIAogIGtibChjYXB0aW9uID0gIkNhc2VzIGltcHJvdmVkIHdpdGggdG90YWwgbGVnYWwgYmFycmllcnMiKSAlPiUgCiAga2FibGVfc3R5bGluZygpCgpwdHNfaW1wcm92ZWRfYWR2b2NhY3kgJT4lIAogIGtibChjYXB0aW9uID0gIkNhc2VzIGltcHJvdmVkIHdpdGggYmFycmllcnMgdG8gYWR2b2NhY3kiKSAlPiUgCiAga2FibGVfc3R5bGluZygpCgpwdHNfaW1wcm92ZWRfZW50cnkgJT4lIAogIGtibChjYXB0aW9uID0gIkNhc2VzIGltcHJvdmVkIHdpdGggYmFycmllcnMgdG8gZW50cnkiKSAlPiUgCiAga2FibGVfc3R5bGluZygpCgpwdHNfaW1wcm92ZWRfZnVuZGluZyAlPiUgCiAga2JsKGNhcHRpb24gPSAiQ2FzZXMgaW1wcm92ZWQgd2l0aCBiYXJyaWVycyB0byBmdW5kaW5nIikgJT4lIAogIGthYmxlX3N0eWxpbmcoKQpgYGAKCmBgYHtyIGUxYS1jb3JyZWN0LW5vdC1jb3JyZWN0fQpjb3JyZWN0X2xvb2t1cCA8LSB0cmliYmxlKAogIH5uYW1lLCB+bmljZV9uYW1lLAogICJpc19jb3JyZWN0X3RvdGFsIiwgIlRvdGFsIGxlZ2FsIGJhcnJpZXJzIGluY2x1ZGVkIiwKICAiaXNfY29ycmVjdF9hZHZvY2FjeSIsICJCYXJyaWVycyB0byBhZHZvY2FjeSBpbmNsdWRlZCIsCiAgImlzX2NvcnJlY3RfZW50cnkiLCAiQmFycmllcnMgdG8gZW50cnkgaW5jbHVkZWQiLAogICJpc19jb3JyZWN0X2Z1bmRpbmciLCAiQmFycmllcnMgdG8gZnVuZGluZyBpbmNsdWRlZCIsCiAgImlzX2NvcnJlY3RfYmFzZWxpbmUiLCAiQmFzZWxpbmUiCikgJT4lIG11dGF0ZShuaWNlX25hbWUgPSBmY3RfaW5vcmRlcihuaWNlX25hbWUsIG9yZGVyZWQgPSBUUlVFKSkKCnB0c19wcmVkX3RhYmxlIDwtIHB0c19jYXRfcHJlZHMgJT4lIAogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgiaXNfY29ycmVjdCIpKSAlPiUgCiAgZ3JvdXBfYnkobmFtZSwgdmFsdWUpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbGVmdF9qb2luKGNvcnJlY3RfbG9va3VwLCBieSA9ICJuYW1lIikgJT4lIAogIG11dGF0ZShQcmVkaWN0aW9uID0gaWZlbHNlKHZhbHVlID09IFRSVUUsICJDb3JyZWN0IiwgIldyb25nIikpICU+JSAKICBhcnJhbmdlKG5pY2VfbmFtZSkgJT4lIAogIHNlbGVjdCgtbmFtZSwgLXZhbHVlKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJuaWNlX25hbWUiLCB2YWx1ZXNfZnJvbSA9ICJuIikKCnB0c19wcmVkX3RhYmxlICU+JSAKICBrYmwoYWxpZ24gPSAibGNjY2NjIikgJT4lIAogIGthYmxlX3N0eWxpbmcoKQpgYGAKClwgCgojIEV+MWJ+OiBOR08gbGF3cyBhbmQgbGF0ZW50IGh1bWFuIHJpZ2h0cwoKYGBge3IgZTFkLXByZWRpY3Rpb25zLCB3YXJuaW5nPUZBTFNFfQpzZWVkX2xocl9wcmVkaWN0aW9uIDwtIDMyMDcgICMgRnJvbSByYW5kb20ub3JnCgpzZXQuc2VlZChzZWVkX2xocl9wcmVkaWN0aW9uKQpwcmVkX2xocl9iYXNlbGluZSA8LSBwcmVkaWN0KG1fbGhyX2Jhc2VsaW5lX3RyYWluLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gc2VsZWN0KGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCwgLWxhdGVudF9ocl9tZWFuX2xlYWQxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRSkKCnNldC5zZWVkKHNlZWRfbGhyX3ByZWRpY3Rpb24pCnByZWRfbGhyX3RvdGFsIDwtIHByZWRpY3QobV9saHJfdG90YWxfdHJhaW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBzZWxlY3QoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkLCAtbGF0ZW50X2hyX21lYW5fbGVhZDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93X25ld19sZXZlbHMgPSBUUlVFKQoKc2V0LnNlZWQoc2VlZF9saHJfcHJlZGljdGlvbikKcHJlZF9saHJfYWR2b2NhY3kgPC0gcHJlZGljdChtX2xocl9hZHZvY2FjeV90cmFpbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHNlbGVjdChjYW5hcnlfdGVzdGluZ19sYWdnZWQsIC1sYXRlbnRfaHJfbWVhbl9sZWFkMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dfbmV3X2xldmVscyA9IFRSVUUpCgpzZXQuc2VlZChzZWVkX2xocl9wcmVkaWN0aW9uKQpwcmVkX2xocl9lbnRyeSA8LSBwcmVkaWN0KG1fbGhyX2VudHJ5X3RyYWluLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gc2VsZWN0KGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCwgLWxhdGVudF9ocl9tZWFuX2xlYWQxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRSkKCnNldC5zZWVkKHNlZWRfbGhyX3ByZWRpY3Rpb24pCnByZWRfbGhyX2Z1bmRpbmcgPC0gcHJlZGljdChtX2xocl9mdW5kaW5nX3RyYWluLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBzZWxlY3QoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkLCAtbGF0ZW50X2hyX21lYW5fbGVhZDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dfbmV3X2xldmVscyA9IFRSVUUpCgpwcmVkX2xocl9iYXNlbGluZV90ZXN0IDwtIGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCAlPiUgCiAgc2VsZWN0KGNvdW50cnksIGd3Y29kZSwgeWVhciwgbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICBiaW5kX2NvbHMoYXNfdGliYmxlKHByZWRfbGhyX2Jhc2VsaW5lKSkgJT4lIAogIGZpbHRlcighaXMubmEobGF0ZW50X2hyX21lYW5fbGVhZDEpKQoKcHJlZF9saHJfdG90YWxfdGVzdCA8LSBjYW5hcnlfdGVzdGluZ19sYWdnZWQgJT4lIAogIHNlbGVjdChjb3VudHJ5LCBnd2NvZGUsIHllYXIsIGxhdGVudF9ocl9tZWFuX2xlYWQxKSAlPiUgCiAgYmluZF9jb2xzKGFzX3RpYmJsZShwcmVkX2xocl90b3RhbCkpICU+JSAKICBmaWx0ZXIoIWlzLm5hKGxhdGVudF9ocl9tZWFuX2xlYWQxKSkKCnByZWRfbGhyX2Fkdm9jYWN5X3Rlc3QgPC0gY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkICU+JSAKICBzZWxlY3QoY291bnRyeSwgZ3djb2RlLCB5ZWFyLCBsYXRlbnRfaHJfbWVhbl9sZWFkMSkgJT4lIAogIGJpbmRfY29scyhhc190aWJibGUocHJlZF9saHJfYWR2b2NhY3kpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShsYXRlbnRfaHJfbWVhbl9sZWFkMSkpCgpwcmVkX2xocl9lbnRyeV90ZXN0IDwtIGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCAlPiUgCiAgc2VsZWN0KGNvdW50cnksIGd3Y29kZSwgeWVhciwgbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICBiaW5kX2NvbHMoYXNfdGliYmxlKHByZWRfbGhyX2VudHJ5KSkgJT4lIAogIGZpbHRlcighaXMubmEobGF0ZW50X2hyX21lYW5fbGVhZDEpKQoKcHJlZF9saHJfZnVuZGluZ190ZXN0IDwtIGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCAlPiUgCiAgc2VsZWN0KGNvdW50cnksIGd3Y29kZSwgeWVhciwgbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICBiaW5kX2NvbHMoYXNfdGliYmxlKHByZWRfbGhyX2Z1bmRpbmcpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShsYXRlbnRfaHJfbWVhbl9sZWFkMSkpCmBgYAoKIyMgSW1wcm92ZW1lbnQgZnJvbSBiYXNlbGluZSBtb2RlbHMKCmBgYHtyIGUxZC1wcmVkLXBsb3RzLCB3YXJuaW5nPUZBTFNFfQpwbG90X2Jhc2VsaW5lIDwtIGdncGxvdChwcmVkX2xocl9iYXNlbGluZV90ZXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgeSA9IEVzdGltYXRlKSkgKwogIGdlb21fYWJsaW5lKGx0eSA9IDIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJCYXNlbGluZSIsCiAgICAgICB4ID0gIkFjdHVhbCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpIikgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lX25nbygpCgpwbG90X3RvdGFsIDwtIGdncGxvdChwcmVkX2xocl90b3RhbF90ZXN0LCAKICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgeSA9IEVzdGltYXRlKSkgKwogIGdlb21fYWJsaW5lKGx0eSA9IDIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBsZWdhbCBiYXJyaWVycyIsCiAgICAgICB4ID0gIkFjdHVhbCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpIikgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lX25nbygpCgpwbG90X2Fkdm9jYWN5IDwtIGdncGxvdChwcmVkX2xocl9hZHZvY2FjeV90ZXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgeSA9IEVzdGltYXRlKSkgKwogIGdlb21fYWJsaW5lKGx0eSA9IDIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJCYXJyaWVycyB0byBhZHZvY2FjeSIsCiAgICAgICB4ID0gIkFjdHVhbCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpIikgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lX25nbygpCgpwbG90X2VudHJ5IDwtIGdncGxvdChwcmVkX2xocl9lbnRyeV90ZXN0LCAKICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgeSA9IEVzdGltYXRlKSkgKwogIGdlb21fYWJsaW5lKGx0eSA9IDIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJCYXJyaWVycyB0byBlbnRyeSIsCiAgICAgICB4ID0gIkFjdHVhbCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpIikgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lX25nbygpCgpwbG90X2Z1bmRpbmcgPC0gZ2dwbG90KHByZWRfbGhyX2Z1bmRpbmdfdGVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgeSA9IEVzdGltYXRlKSkgKwogIGdlb21fYWJsaW5lKGx0eSA9IDIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJCYXJyaWVycyB0byBmdW5kaW5nIiwKICAgICAgIHggPSAiQWN0dWFsIGxhdGVudCBodW1hbiByaWdodHMgdmFsdWUgKHQgKyAxKSIsCiAgICAgICB5ID0gIlByZWRpY3RlZCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWVfbmdvKCkKCihwbG90X2Jhc2VsaW5lIHwgcGxvdF90b3RhbCkgLyAocGxvdF9hZHZvY2FjeSB8IHBsb3RfZW50cnkgfCBwbG90X2Z1bmRpbmcpCmBgYAoKYGBge3IgZTFkLW1ldHJpY3N9CmxvdHNhX21ldHJpY3MgPC0gbWV0cmljX3NldChybXNlLCByc3EsIG1hZSwgY2NjKQoKYmluZF9yb3dzKGxvdHNhX21ldHJpY3MocHJlZF9saHJfYmFzZWxpbmVfdGVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRydXRoID0gbGF0ZW50X2hyX21lYW5fbGVhZDEsIAogICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZSA9IEVzdGltYXRlKSAlPiUgCiAgICAgICAgICAgIG11dGF0ZShNb2RlbCA9ICJCYXNlbGluZSIpLAogICAgICAgICAgbG90c2FfbWV0cmljcyhwcmVkX2xocl90b3RhbF90ZXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgdHJ1dGggPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlID0gRXN0aW1hdGUpICU+JSAKICAgICAgICAgICAgbXV0YXRlKE1vZGVsID0gIlRvdGFsIGxlZ2FsIGJhcnJpZXJzIiksCiAgICAgICAgICBsb3RzYV9tZXRyaWNzKHByZWRfbGhyX2Fkdm9jYWN5X3Rlc3QsIAogICAgICAgICAgICAgICAgICAgICAgICB0cnV0aCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLCAKICAgICAgICAgICAgICAgICAgICAgICAgZXN0aW1hdGUgPSBFc3RpbWF0ZSkgJT4lIAogICAgICAgICAgICBtdXRhdGUoTW9kZWwgPSAiQmFycmllcnMgdG8gYWR2b2NhY3kiKSwKICAgICAgICAgIGxvdHNhX21ldHJpY3MocHJlZF9saHJfZW50cnlfdGVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRydXRoID0gbGF0ZW50X2hyX21lYW5fbGVhZDEsIAogICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZSA9IEVzdGltYXRlKSAlPiUgCiAgICAgICAgICAgIG11dGF0ZShNb2RlbCA9ICJCYXJyaWVycyB0byBlbnRyeSIpLAogICAgICAgICAgbG90c2FfbWV0cmljcyhwcmVkX2xocl9mdW5kaW5nX3Rlc3QsIAogICAgICAgICAgICAgICAgICAgICAgICB0cnV0aCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLCAKICAgICAgICAgICAgICAgICAgICAgICAgZXN0aW1hdGUgPSBFc3RpbWF0ZSkgJT4lIAogICAgICAgICAgICBtdXRhdGUoTW9kZWwgPSAiQmFycmllcnMgdG8gZnVuZGluZyIpKSAlPiUgCiAgc2VsZWN0KE1vZGVsLCAubWV0cmljLCAuZXN0aW1hdGUpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gIi5tZXRyaWMiLCB2YWx1ZXNfZnJvbSA9ICIuZXN0aW1hdGUiKQpgYGAKCiMjIE1vc3QgaW1wcm92ZWQgY291bnRyaWVzCgojIyMgVG90YWwgbGVnYWwgYmFycmllcnMKCmBgYHtyIGUxZC1tb3N0LWltcHJvdmVkLXRvdGFsfQptb3N0X2ltcHJvdmVkX2xocl90b3RhbCA8LSBiaW5kX2NvbHMoCiAgcHJlZF9saHJfYmFzZWxpbmVfdGVzdCAlPiUgCiAgICBtdXRhdGUoZXJyb3JfYmFzZWxpbmUgPSBFc3RpbWF0ZSAtIGxhdGVudF9ocl9tZWFuX2xlYWQxKSAlPiUgCiAgICBzZWxlY3QoY291bnRyeSwgZ3djb2RlLCB5ZWFyLCBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgCiAgICAgICAgICAgZXN0aW1hdGVfYmFzZWxpbmUgPSBFc3RpbWF0ZSwgZXJyb3JfYmFzZWxpbmUpLAogIHByZWRfbGhyX3RvdGFsX3Rlc3QgJT4lIAogICAgbXV0YXRlKGVycm9yX3RvdGFsID0gRXN0aW1hdGUgLSBsYXRlbnRfaHJfbWVhbl9sZWFkMSkgJT4lIAogICAgc2VsZWN0KGVzdGltYXRlX3RvdGFsID0gRXN0aW1hdGUsIGVycm9yX3RvdGFsKQopICU+JSAKICBtdXRhdGUoaW1wcm92ZWQgPSBlcnJvcl90b3RhbCA8IDAgJiBhYnMoZXJyb3JfdG90YWwpIDwgYWJzKGVycm9yX2Jhc2VsaW5lKSkgJT4lIAogIG11dGF0ZShkaWZmID0gZXJyb3JfdG90YWwgLSBlcnJvcl9iYXNlbGluZSkgJT4lIAogIG11dGF0ZShhYnNfZGlmZiA9IGFicyhkaWZmKSkgJT4lIAogIGZpbHRlcihpbXByb3ZlZCkgJT4lIAogIGFycmFuZ2UoZGVzYyhhYnNfZGlmZikpCgpucm93KG1vc3RfaW1wcm92ZWRfbGhyX3RvdGFsKQoKbW9zdF9pbXByb3ZlZF9saHJfdG90YWwgJT4lIAogIHNlbGVjdChDb3VudHJ5ID0gY291bnRyeSwgWWVhciA9IHllYXIsIAogICAgICAgICBgQWN0dWFsIGxhdGVudCBodW1hbiByaWdodHMgdmFsdWUgKHQgKyAxKWAgPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwKICAgICAgICAgYFByZWRpY3RlZCAoYmFzZWxpbmUpYCA9IGVzdGltYXRlX2Jhc2VsaW5lLAogICAgICAgICBgUHJlZGljdGVkIChDUyByZXByZXNzaW9uKWAgPSBlc3RpbWF0ZV90b3RhbCwKICAgICAgICAgYHxDUyByZXByZXNzaW9uIOKIkiBiYXNlbGluZXxgID0gYWJzX2RpZmYpICU+JSAKICBoZWFkKDUpICU+JSAKICBrYmwoZGlnaXRzID0gMywgYWxpZ24gPSAibGNjY2NjIikgJT4lIAogIGthYmxlX3N0eWxpbmcoKQpgYGAKCiMjIyBCYXJyaWVycyB0byBhZHZvY2FjeQoKYGBge3IgZTFkLW1vc3QtaW1wcm92ZWQtYWR2b2NhY3l9Cm1vc3RfaW1wcm92ZWRfbGhyX2Fkdm9jYWN5IDwtIGJpbmRfY29scygKICBwcmVkX2xocl9iYXNlbGluZV90ZXN0ICU+JSAKICAgIG11dGF0ZShlcnJvcl9iYXNlbGluZSA9IEVzdGltYXRlIC0gbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICAgIHNlbGVjdChjb3VudHJ5LCBnd2NvZGUsIHllYXIsIGxhdGVudF9ocl9tZWFuX2xlYWQxLCAKICAgICAgICAgICBlc3RpbWF0ZV9iYXNlbGluZSA9IEVzdGltYXRlLCBlcnJvcl9iYXNlbGluZSksCiAgcHJlZF9saHJfYWR2b2NhY3lfdGVzdCAlPiUgCiAgICBtdXRhdGUoZXJyb3JfYWR2b2NhY3kgPSBFc3RpbWF0ZSAtIGxhdGVudF9ocl9tZWFuX2xlYWQxKSAlPiUgCiAgICBzZWxlY3QoZXN0aW1hdGVfYWR2b2NhY3kgPSBFc3RpbWF0ZSwgZXJyb3JfYWR2b2NhY3kpCikgJT4lIAogIG11dGF0ZShpbXByb3ZlZCA9IGVycm9yX2Fkdm9jYWN5IDwgMCAmIGFicyhlcnJvcl9hZHZvY2FjeSkgPCBhYnMoZXJyb3JfYmFzZWxpbmUpKSAlPiUgCiAgbXV0YXRlKGRpZmYgPSBlcnJvcl9hZHZvY2FjeSAtIGVycm9yX2Jhc2VsaW5lKSAlPiUgCiAgbXV0YXRlKGFic19kaWZmID0gYWJzKGRpZmYpKSAlPiUgCiAgZmlsdGVyKGltcHJvdmVkKSAlPiUgCiAgYXJyYW5nZShkZXNjKGFic19kaWZmKSkKCm5yb3cobW9zdF9pbXByb3ZlZF9saHJfYWR2b2NhY3kpCgptb3N0X2ltcHJvdmVkX2xocl9hZHZvY2FjeSAlPiUgCiAgc2VsZWN0KENvdW50cnkgPSBjb3VudHJ5LCBZZWFyID0geWVhciwgCiAgICAgICAgIGBBY3R1YWwgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpYCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLAogICAgICAgICBgUHJlZGljdGVkIChiYXNlbGluZSlgID0gZXN0aW1hdGVfYmFzZWxpbmUsCiAgICAgICAgIGBQcmVkaWN0ZWQgKENTIHJlcHJlc3Npb24pYCA9IGVzdGltYXRlX2Fkdm9jYWN5LAogICAgICAgICBgfENTIHJlcHJlc3Npb24g4oiSIGJhc2VsaW5lfGAgPSBhYnNfZGlmZikgJT4lIAogIGhlYWQoNSkgJT4lIAogIGtibChkaWdpdHMgPSAzLCBhbGlnbiA9ICJsY2NjY2MiKSAlPiUgCiAga2FibGVfc3R5bGluZygpCmBgYAoKIyMjIEJhcnJpZXJzIHRvIGVudHJ5CgpgYGB7ciBlMWQtbW9zdC1pbXByb3ZlZC1lbnRyeX0KbW9zdF9pbXByb3ZlZF9saHJfZW50cnkgPC0gYmluZF9jb2xzKAogIHByZWRfbGhyX2Jhc2VsaW5lX3Rlc3QgJT4lIAogICAgbXV0YXRlKGVycm9yX2Jhc2VsaW5lID0gRXN0aW1hdGUgLSBsYXRlbnRfaHJfbWVhbl9sZWFkMSkgJT4lIAogICAgc2VsZWN0KGNvdW50cnksIGd3Y29kZSwgeWVhciwgbGF0ZW50X2hyX21lYW5fbGVhZDEsIAogICAgICAgICAgIGVzdGltYXRlX2Jhc2VsaW5lID0gRXN0aW1hdGUsIGVycm9yX2Jhc2VsaW5lKSwKICBwcmVkX2xocl9lbnRyeV90ZXN0ICU+JSAKICAgIG11dGF0ZShlcnJvcl9lbnRyeSA9IEVzdGltYXRlIC0gbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICAgIHNlbGVjdChlc3RpbWF0ZV9lbnRyeSA9IEVzdGltYXRlLCBlcnJvcl9lbnRyeSkKKSAlPiUgCiAgbXV0YXRlKGltcHJvdmVkID0gZXJyb3JfZW50cnkgPCAwICYgYWJzKGVycm9yX2VudHJ5KSA8IGFicyhlcnJvcl9iYXNlbGluZSkpICU+JSAKICBtdXRhdGUoZGlmZiA9IGVycm9yX2VudHJ5IC0gZXJyb3JfYmFzZWxpbmUpICU+JSAKICBtdXRhdGUoYWJzX2RpZmYgPSBhYnMoZGlmZikpICU+JSAKICBmaWx0ZXIoaW1wcm92ZWQpICU+JSAKICBhcnJhbmdlKGRlc2MoYWJzX2RpZmYpKQoKbnJvdyhtb3N0X2ltcHJvdmVkX2xocl9lbnRyeSkKCm1vc3RfaW1wcm92ZWRfbGhyX2VudHJ5ICU+JSAKICBzZWxlY3QoQ291bnRyeSA9IGNvdW50cnksIFllYXIgPSB5ZWFyLCAKICAgICAgICAgYEFjdHVhbCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSlgID0gbGF0ZW50X2hyX21lYW5fbGVhZDEsCiAgICAgICAgIGBQcmVkaWN0ZWQgKGJhc2VsaW5lKWAgPSBlc3RpbWF0ZV9iYXNlbGluZSwKICAgICAgICAgYFByZWRpY3RlZCAoQ1MgcmVwcmVzc2lvbilgID0gZXN0aW1hdGVfZW50cnksCiAgICAgICAgIGB8Q1MgcmVwcmVzc2lvbiDiiJIgYmFzZWxpbmV8YCA9IGFic19kaWZmKSAlPiUgCiAgaGVhZCg1KSAlPiUgCiAga2JsKGRpZ2l0cyA9IDMsIGFsaWduID0gImxjY2NjYyIpICU+JSAKICBrYWJsZV9zdHlsaW5nKCkKYGBgCgojIyMgQmFycmllcnMgdG8gZnVuZGluZwoKYGBge3IgZTFkLW1vc3QtaW1wcm92ZWQtZnVuZGluZ30KbW9zdF9pbXByb3ZlZF9saHJfZnVuZGluZyA8LSBiaW5kX2NvbHMoCiAgcHJlZF9saHJfYmFzZWxpbmVfdGVzdCAlPiUgCiAgICBtdXRhdGUoZXJyb3JfYmFzZWxpbmUgPSBFc3RpbWF0ZSAtIGxhdGVudF9ocl9tZWFuX2xlYWQxKSAlPiUgCiAgICBzZWxlY3QoY291bnRyeSwgZ3djb2RlLCB5ZWFyLCBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgCiAgICAgICAgICAgZXN0aW1hdGVfYmFzZWxpbmUgPSBFc3RpbWF0ZSwgZXJyb3JfYmFzZWxpbmUpLAogIHByZWRfbGhyX2Z1bmRpbmdfdGVzdCAlPiUgCiAgICBtdXRhdGUoZXJyb3JfZnVuZGluZyA9IEVzdGltYXRlIC0gbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICAgIHNlbGVjdChlc3RpbWF0ZV9mdW5kaW5nID0gRXN0aW1hdGUsIGVycm9yX2Z1bmRpbmcpCikgJT4lIAogIG11dGF0ZShpbXByb3ZlZCA9IGVycm9yX2Z1bmRpbmcgPCAwICYgYWJzKGVycm9yX2Z1bmRpbmcpIDwgYWJzKGVycm9yX2Jhc2VsaW5lKSkgJT4lIAogIG11dGF0ZShkaWZmID0gZXJyb3JfZnVuZGluZyAtIGVycm9yX2Jhc2VsaW5lKSAlPiUgCiAgbXV0YXRlKGFic19kaWZmID0gYWJzKGRpZmYpKSAlPiUgCiAgZmlsdGVyKGltcHJvdmVkKSAlPiUgCiAgYXJyYW5nZShkZXNjKGFic19kaWZmKSkKCm5yb3cobW9zdF9pbXByb3ZlZF9saHJfZnVuZGluZykKCm1vc3RfaW1wcm92ZWRfbGhyX2Z1bmRpbmcgJT4lIAogIHNlbGVjdChDb3VudHJ5ID0gY291bnRyeSwgWWVhciA9IHllYXIsIAogICAgICAgICBgQWN0dWFsIGxhdGVudCBodW1hbiByaWdodHMgdmFsdWUgKHQgKyAxKWAgPSBsYXRlbnRfaHJfbWVhbl9sZWFkMSwKICAgICAgICAgYFByZWRpY3RlZCAoYmFzZWxpbmUpYCA9IGVzdGltYXRlX2Jhc2VsaW5lLAogICAgICAgICBgUHJlZGljdGVkIChDUyByZXByZXNzaW9uKWAgPSBlc3RpbWF0ZV9mdW5kaW5nLAogICAgICAgICBgfENTIHJlcHJlc3Npb24g4oiSIGJhc2VsaW5lfGAgPSBhYnNfZGlmZikgJT4lIAogIGhlYWQoNSkgJT4lIAogIGtibChkaWdpdHMgPSAzLCBhbGlnbiA9ICJsY2NjY2MiKSAlPiUgCiAga2FibGVfc3R5bGluZygpCmBgYAoKXCAKCi0tLQoKXCAKCiMgRX4yYX46IENpdmlsIHNvY2lldHkgZW52aXJvbm1lbnQgYW5kIHBvbGl0aWNhbCB0ZXJyb3IKCmBgYHtyIGUyYS1wcmVkaWN0aW9ucywgd2FybmluZz1GQUxTRX0Kc2VlZF9wdHNfcHJlZGljdGlvbiA8LSA1NDk0ICAjIEZyb20gcmFuZG9tLm9yZwoKc2V0LnNlZWQoc2VlZF9wdHNfcHJlZGljdGlvbikKcHJlZF9wdHNfYmFzZWxpbmUgPC0gcHJlZGljdCgKICBtX3B0c19iYXNlbGluZV90cmFpbiwgCiAgbmV3ZGF0YSA9IHNlbGVjdChjYW5hcnlfdGVzdGluZ19sYWdnZWQsIC1QVFNfZmFjdG9yX2xlYWQxKSwKICBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRQopICU+JSAKICBhc190aWJibGUoKSAlPiUgCiAgbWFncml0dHI6OnNldF9jb2xuYW1lcyhwdHNfbGV2ZWxzKQoKc2V0LnNlZWQoc2VlZF9wdHNfcHJlZGljdGlvbikKcHJlZF9wdHNfdjJjc3JlcHJzcyA8LSBwcmVkaWN0KAogIG1fcHRzX3YyY3NyZXByc3NfdHJhaW4sIAogIG5ld2RhdGEgPSBzZWxlY3QoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkLCAtUFRTX2ZhY3Rvcl9sZWFkMSksCiAgYWxsb3dfbmV3X2xldmVscyA9IFRSVUUKKSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIG1hZ3JpdHRyOjpzZXRfY29sbmFtZXMocHRzX2xldmVscykKYGBgCgoKIyMgU2VwYXJhdGlvbiBwbG90cwoKIyMjIEJhc2VsaW5lIG1vZGVsCgpgYGB7ciBlMmEtc2VwYXJhdGlvbi1iYXNlbGluZX0KIyBNYXRjaCBlYWNoIGNvbHVtbiBpbiBwcmVkX21hdCAocHJlZGljdGVkIHByb2JhYmlsaXRpZXMgZm9yIGVhY2ggcmVzcG9uc2UgbGV2ZWwpCnByZWRfbG9uZ19saXN0IDwtIGxhcHBseSgxOm5jb2wocHJlZF9wdHNfYmFzZWxpbmUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1hdGNoX2FjdHVhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwcmVkID0gcHJlZF9wdHNfYmFzZWxpbmUsIAogICAgICAgICAgICAgICAgICAgICAgICAgYWN0dWFsID0gYXMuY2hhcmFjdGVyKGNhbmFyeV90ZXN0aW5nX2xhZ2dlZCRQVFNfZmFjdG9yX2xlYWQxKSkKCnBsb3RfZGF0YSA8LSBwcmVkX2xvbmdfbGlzdCAlPiUgCiAgYmluZF9yb3dzKCkgJT4lIAogIGZpbHRlcighaXMubmFuKGZpdHRlZCksICFpcy5uYShhY3R1YWwpKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lIAogIGFycmFuZ2UocGxvdF9sZXZlbCwgZml0dGVkKSAlPiUgCiAgbXV0YXRlKGluZGV4ID0gcm93X251bWJlcigpKSAlPiUgCiAgdW5ncm91cCgpCgptYXJrZXJzIDwtIHBsb3RfZGF0YSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lCiAgc3VtbWFyaXplKG9icyA9IG4oKSwgZXhwZWN0ZWQgPSBzdW0oZml0dGVkKSwKICAgICAgICAgICAgbWFya2VyID0gb2JzIC0gZXhwZWN0ZWQgKyAxKQoKbl9pbl9ncm91cCA8LSBucm93KHByZWRfcHRzX2Jhc2VsaW5lKQoKcGxvdF9kYXRhX2NvbmRlbnNlZCA8LSBwbG90X2RhdGEgJT4lIAogICMgcmxlKCksIGRwbHlyLXN0eWxlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzM1MTA3NjUvMTIwODk4CiAgbXV0YXRlKHJsZWlkID0gKGFjdHVhbCAhPSBsYWcoYWN0dWFsLCAxLCBkZWZhdWx0ID0gMCkpKSAlPiUKICBtdXRhdGUocmxlaWQgPSBjdW1zdW0ocmxlaWQpKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCwgcmxlaWQpICU+JSAKICBzbGljZSgxKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lIAogIG11dGF0ZSh4bWluID0gaW5kZXgsIHhtYXggPSBsZWFkKGluZGV4LCBkZWZhdWx0ID0gbl9pbl9ncm91cCkpICU+JSAKICB1bmdyb3VwKCkKCmdncGxvdChwbG90X2RhdGFfY29uZGVuc2VkKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0geG1pbiwgeG1heCA9IHhtYXgsIHltaW4gPSAwLCB5bWF4ID0gMSwgZmlsbCA9IGFzLmZhY3RvcihhY3R1YWwpKSkgKyAKICBnZW9tX2xpbmUoYWVzKHggPSBpbmRleCwgeSA9IGZpdHRlZCksIHNpemUgPSAwLjMpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtYXJrZXJzLCBhZXMoeCA9IG1hcmtlciwgeSA9IC0wLjA1KSwgc2hhcGUgPSAxNywgc2l6ZSA9IDMpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JleTkwIiwgIiMyRUNDNDAiKSkgKwogIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCh2YXJzKHBsb3RfbGV2ZWwpLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV92b2lkKGJhc2VfZmFtaWx5ID0gIkludGVyIEJvbGQiKQpgYGAKCiMjIyBNb2RlbCB3aXRoIGNpdmlsIHNvY2lldHkgcmVwcmVzc2lvbgoKYGBge3IgZTJhLXNlcGFyYXRpb24tY3N9CnByZWRfbG9uZ19saXN0IDwtIGxhcHBseSgxOm5jb2wocHJlZF9wdHNfdjJjc3JlcHJzcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWF0Y2hfYWN0dWFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHByZWQgPSBwcmVkX3B0c192MmNzcmVwcnNzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGFjdHVhbCA9IGFzLmNoYXJhY3RlcihjYW5hcnlfdGVzdGluZ19sYWdnZWQkUFRTX2ZhY3Rvcl9sZWFkMSkpCgpwbG90X2RhdGEgPC0gcHJlZF9sb25nX2xpc3QgJT4lIAogIGJpbmRfcm93cygpICU+JSAKICBmaWx0ZXIoIWlzLm5hbihmaXR0ZWQpLCAhaXMubmEoYWN0dWFsKSkgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwpICU+JSAKICBhcnJhbmdlKHBsb3RfbGV2ZWwsIGZpdHRlZCkgJT4lIAogIG11dGF0ZShpbmRleCA9IHJvd19udW1iZXIoKSkgJT4lIAogIHVuZ3JvdXAoKQoKbWFya2VycyA8LSBwbG90X2RhdGEgJT4lIAogIGdyb3VwX2J5KHBsb3RfbGV2ZWwpICU+JQogIHN1bW1hcml6ZShvYnMgPSBuKCksIGV4cGVjdGVkID0gc3VtKGZpdHRlZCksCiAgICAgICAgICAgIG1hcmtlciA9IG9icyAtIGV4cGVjdGVkICsgMSkKCm5faW5fZ3JvdXAgPC0gbnJvdyhwcmVkX3B0c192MmNzcmVwcnNzKQoKcGxvdF9kYXRhX2NvbmRlbnNlZCA8LSBwbG90X2RhdGEgJT4lIAogICMgcmxlKCksIGRwbHlyLXN0eWxlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzM1MTA3NjUvMTIwODk4CiAgbXV0YXRlKHJsZWlkID0gKGFjdHVhbCAhPSBsYWcoYWN0dWFsLCAxLCBkZWZhdWx0ID0gMCkpKSAlPiUKICBtdXRhdGUocmxlaWQgPSBjdW1zdW0ocmxlaWQpKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCwgcmxlaWQpICU+JSAKICBzbGljZSgxKSAlPiUgCiAgZ3JvdXBfYnkocGxvdF9sZXZlbCkgJT4lIAogIG11dGF0ZSh4bWluID0gaW5kZXgsIHhtYXggPSBsZWFkKGluZGV4LCBkZWZhdWx0ID0gbl9pbl9ncm91cCkpICU+JSAKICB1bmdyb3VwKCkKCmdncGxvdChwbG90X2RhdGFfY29uZGVuc2VkKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0geG1pbiwgeG1heCA9IHhtYXgsIHltaW4gPSAwLCB5bWF4ID0gMSwgZmlsbCA9IGFzLmZhY3RvcihhY3R1YWwpKSkgKyAKICBnZW9tX2xpbmUoYWVzKHggPSBpbmRleCwgeSA9IGZpdHRlZCksIHNpemUgPSAwLjMpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtYXJrZXJzLCBhZXMoeCA9IG1hcmtlciwgeSA9IC0wLjA1KSwgc2hhcGUgPSAxNywgc2l6ZSA9IDMpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JleTkwIiwgIiMyRUNDNDAiKSkgKwogIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCh2YXJzKHBsb3RfbGV2ZWwpLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV92b2lkKGJhc2VfZmFtaWx5ID0gIkludGVyIEJvbGQiKQpgYGAKCiMjIFByZWRpY3Rpb24gZGlhZ25vc3RpY3MKCmBgYHtyIGUyYS1pbXByb3ZlZC1jYXNlc30KcHJlZF9wdHNfYmFzZWxpbmVfY2F0ZWdvcmllcyA8LSBwcmVkX3B0c19iYXNlbGluZSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogIHBpdm90X2xvbmdlcigtcm93bmFtZSkgJT4lIAogIGdyb3VwX2J5KHJvd25hbWUpICU+JSAKICBmaWx0ZXIocmFuaygtdmFsdWUsIHRpZXMubWV0aG9kID0gImxhc3QiKSA9PSAxKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QocHJlZGljdGVkID0gbmFtZSkKCnByZWRfcHRzX3YyY3NyZXByc3NfY2F0ZWdvcmllcyA8LSBwcmVkX3B0c192MmNzcmVwcnNzICU+JSAKICByb3duYW1lc190b19jb2x1bW4oKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1yb3duYW1lKSAlPiUgCiAgZ3JvdXBfYnkocm93bmFtZSkgJT4lIAogIGZpbHRlcihyYW5rKC12YWx1ZSwgdGllcy5tZXRob2QgPSAibGFzdCIpID09IDEpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdChwcmVkaWN0ZWQgPSBuYW1lKQoKcHRzX2NhdF9wcmVkcyA8LSBjYW5hcnlfdGVzdGluZ19sYWdnZWQgJT4lIAogIHNlbGVjdChjb3VudHJ5LCB5ZWFyLCBhY3R1YWwgPSBQVFNfZmFjdG9yX2xlYWQxKSAlPiUgCiAgbXV0YXRlKHByZWRfYmFzZWxpbmUgPSBwcmVkX3B0c19iYXNlbGluZV9jYXRlZ29yaWVzJHByZWRpY3RlZCwKICAgICAgICAgcHJlZF92MmNzcmVwcnNzID0gcHJlZF9wdHNfdjJjc3JlcHJzc19jYXRlZ29yaWVzJHByZWRpY3RlZCkgJT4lIAogIGZpbHRlcighaXMubmEoYWN0dWFsKSkgJT4lCiAgbXV0YXRlKGlzX2NvcnJlY3RfYmFzZWxpbmUgPSBhY3R1YWwgPT0gcHJlZF9iYXNlbGluZSwKICAgICAgICAgaXNfY29ycmVjdF92MmNzcmVwcnNzID0gYWN0dWFsID09IHByZWRfdjJjc3JlcHJzcykKCiMgSW1wcm92ZWQgcHJlZGljdGlvbnMKcHRzX2ltcHJvdmVkIDwtIHB0c19jYXRfcHJlZHMgJT4lIAogIGZpbHRlcighaXNfY29ycmVjdF9iYXNlbGluZSAmIGlzX2NvcnJlY3RfdjJjc3JlcHJzcykgJT4lIAogIHNlbGVjdChDb3VudHJ5ID0gY291bnRyeSwgWWVhciA9IHllYXIsIEFjdHVhbCA9IGFjdHVhbCwKICAgICAgICAgYENTIHJlcHJlc3Npb24gaW5jbHVkZWRgID0gcHJlZF92MmNzcmVwcnNzLAogICAgICAgICBgQmFzZWxpbmVgID0gcHJlZF9iYXNlbGluZSkKCnB0c19pbXByb3ZlZCAlPiUgCiAga2JsKCkgJT4lIAogIGthYmxlX3N0eWxpbmcoKQpgYGAKCmBgYHtyIGUyYS1jb3JyZWN0LW5vdC1jb3JyZWN0fQpjb3JyZWN0X2xvb2t1cCA8LSB0cmliYmxlKAogIH5uYW1lLCB+bmljZV9uYW1lLAogICJpc19jb3JyZWN0X3YyY3NyZXByc3MiLCAiQ1MgcmVwcmVzc2lvbiBpbmNsdWRlZCIsCiAgImlzX2NvcnJlY3RfYmFzZWxpbmUiLCAiQmFzZWxpbmUiCikgJT4lIG11dGF0ZShuaWNlX25hbWUgPSBmY3RfaW5vcmRlcihuaWNlX25hbWUsIG9yZGVyZWQgPSBUUlVFKSkKCnB0c19wcmVkX3RhYmxlIDwtIHB0c19jYXRfcHJlZHMgJT4lIAogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgiaXNfY29ycmVjdCIpKSAlPiUgCiAgZ3JvdXBfYnkobmFtZSwgdmFsdWUpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbGVmdF9qb2luKGNvcnJlY3RfbG9va3VwLCBieSA9ICJuYW1lIikgJT4lIAogIG11dGF0ZShQcmVkaWN0aW9uID0gaWZlbHNlKHZhbHVlID09IFRSVUUsICJDb3JyZWN0IiwgIldyb25nIikpICU+JSAKICBhcnJhbmdlKG5pY2VfbmFtZSkgJT4lIAogIHNlbGVjdCgtbmFtZSwgLXZhbHVlKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJuaWNlX25hbWUiLCB2YWx1ZXNfZnJvbSA9ICJuIikKCnB0c19wcmVkX3RhYmxlICU+JSAKICBrYmwoYWxpZ24gPSAibGNjIikgJT4lIAogIGthYmxlX3N0eWxpbmcoKQpgYGAKClwgCgojIEV+MmJ+OiBDaXZpbCBzb2NpZXR5IGVudmlyb25tZW50IGFuZCBsYXRlbnQgaHVtYW4gcmlnaHRzCgpgYGB7ciBlMmItcHJlZGljdGlvbnMsIHdhcm5pbmc9RkFMU0V9CnNlZWRfbGhyX3ByZWRpY3Rpb24gPC0gMzIwNyAgIyBGcm9tIHJhbmRvbS5vcmcKCnNldC5zZWVkKHNlZWRfbGhyX3ByZWRpY3Rpb24pCnByZWRfbGhyX2Jhc2VsaW5lIDwtIHByZWRpY3QobV9saHJfYmFzZWxpbmVfdHJhaW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBzZWxlY3QoY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkLCAtbGF0ZW50X2hyX21lYW5fbGVhZDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93X25ld19sZXZlbHMgPSBUUlVFKQoKc2V0LnNlZWQoc2VlZF9saHJfcHJlZGljdGlvbikKcHJlZF9saHJfdjJjc3JlcHJzcyA8LSBwcmVkaWN0KG1fbGhyX3YyY3NyZXByc3NfdHJhaW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHNlbGVjdChjYW5hcnlfdGVzdGluZ19sYWdnZWQsIC1sYXRlbnRfaHJfbWVhbl9sZWFkMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRSkKCnByZWRfbGhyX2Jhc2VsaW5lX3Rlc3QgPC0gY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkICU+JSAKICBzZWxlY3QoY291bnRyeSwgZ3djb2RlLCB5ZWFyLCBsYXRlbnRfaHJfbWVhbl9sZWFkMSkgJT4lIAogIGJpbmRfY29scyhhc190aWJibGUocHJlZF9saHJfYmFzZWxpbmUpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShsYXRlbnRfaHJfbWVhbl9sZWFkMSkpCgpwcmVkX2xocl92MmNzcmVwcnNzX3Rlc3QgPC0gY2FuYXJ5X3Rlc3RpbmdfbGFnZ2VkICU+JSAKICBzZWxlY3QoY291bnRyeSwgZ3djb2RlLCB5ZWFyLCBsYXRlbnRfaHJfbWVhbl9sZWFkMSkgJT4lIAogIGJpbmRfY29scyhhc190aWJibGUocHJlZF9saHJfdjJjc3JlcHJzcykpICU+JSAKICBmaWx0ZXIoIWlzLm5hKGxhdGVudF9ocl9tZWFuX2xlYWQxKSkKYGBgCgojIyBJbXByb3ZlbWVudCBmcm9tIGJhc2VsaW5lIG1vZGVscwoKYGBge3IgZTJiLXByZWQtcGxvdHMsIHdhcm5pbmc9RkFMU0V9CnBsb3RfYmFzZWxpbmUgPC0gZ2dwbG90KHByZWRfbGhyX2Jhc2VsaW5lX3Rlc3QsIAogICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLCB5ID0gRXN0aW1hdGUpKSArCiAgZ2VvbV9hYmxpbmUobHR5ID0gMikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBsYWJzKHRpdGxlID0gIkJhc2VsaW5lIiwKICAgICAgIHggPSAiQWN0dWFsIGxhdGVudCBodW1hbiByaWdodHMgdmFsdWUgKHQgKyAxKSIsCiAgICAgICB5ID0gIlByZWRpY3RlZCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWVfbmdvKCkKCnBsb3RfdjJjc3JlcHJzcyA8LSBnZ3Bsb3QocHJlZF9saHJfdjJjc3JlcHJzc190ZXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLCB5ID0gRXN0aW1hdGUpKSArCiAgZ2VvbV9hYmxpbmUobHR5ID0gMikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBsYWJzKHRpdGxlID0gIkFkZGVkIHByZWRpY3RvciIsCiAgICAgICB4ID0gIkFjdHVhbCBsYXRlbnQgaHVtYW4gcmlnaHRzIHZhbHVlICh0ICsgMSkiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpIikgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lX25nbygpCgpwbG90X2Jhc2VsaW5lIHwgcGxvdF92MmNzcmVwcnNzCmBgYAoKYGBge3IgZTJiLW1ldHJpY3N9CmxvdHNhX21ldHJpY3MgPC0gbWV0cmljX3NldChybXNlLCByc3EsIG1hZSwgY2NjKQoKYmluZF9yb3dzKGxvdHNhX21ldHJpY3MocHJlZF9saHJfYmFzZWxpbmVfdGVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRydXRoID0gbGF0ZW50X2hyX21lYW5fbGVhZDEsIAogICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZSA9IEVzdGltYXRlKSAlPiUgCiAgICAgICAgICAgIG11dGF0ZShNb2RlbCA9ICJCYXNlbGluZSIpLAogICAgICAgICAgbG90c2FfbWV0cmljcyhwcmVkX2xocl92MmNzcmVwcnNzX3Rlc3QsIAogICAgICAgICAgICAgICAgICAgICAgICB0cnV0aCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLCAKICAgICAgICAgICAgICAgICAgICAgICAgZXN0aW1hdGUgPSBFc3RpbWF0ZSkgJT4lIAogICAgICAgICAgICBtdXRhdGUoTW9kZWwgPSAiQWRkZWQgcHJlZGljdG9yIikpICU+JSAKICBzZWxlY3QoTW9kZWwsIC5tZXRyaWMsIC5lc3RpbWF0ZSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiLm1ldHJpYyIsIHZhbHVlc19mcm9tID0gIi5lc3RpbWF0ZSIpCmBgYAoKIyMgTW9zdCBpbXByb3ZlZCBjb3VudHJpZXMKCmBgYHtyIGUyYi1tb3N0LWltcHJvdmVkfQptb3N0X2ltcHJvdmVkX2xociA8LSBiaW5kX2NvbHMoCiAgcHJlZF9saHJfYmFzZWxpbmVfdGVzdCAlPiUgCiAgICBtdXRhdGUoZXJyb3JfYmFzZWxpbmUgPSBFc3RpbWF0ZSAtIGxhdGVudF9ocl9tZWFuX2xlYWQxKSAlPiUgCiAgICBzZWxlY3QoY291bnRyeSwgZ3djb2RlLCB5ZWFyLCBsYXRlbnRfaHJfbWVhbl9sZWFkMSwgCiAgICAgICAgICAgZXN0aW1hdGVfYmFzZWxpbmUgPSBFc3RpbWF0ZSwgZXJyb3JfYmFzZWxpbmUpLAogIHByZWRfbGhyX3YyY3NyZXByc3NfdGVzdCAlPiUgCiAgICBtdXRhdGUoZXJyb3JfdjJjc3JlcHJzcyA9IEVzdGltYXRlIC0gbGF0ZW50X2hyX21lYW5fbGVhZDEpICU+JSAKICAgIHNlbGVjdChlc3RpbWF0ZV92MmNzcmVwcnNzID0gRXN0aW1hdGUsIGVycm9yX3YyY3NyZXByc3MpCikgJT4lIAogICMgbXV0YXRlKGFjcm9zcyhzdGFydHNfd2l0aCgiZXJyb3IiKSwgfnJvdW5kKC4sIDQpKSkgJT4lIAogIG11dGF0ZShpbXByb3ZlZCA9IGVycm9yX3YyY3NyZXByc3MgPCAwICYgYWJzKGVycm9yX3YyY3NyZXByc3MpIDwgYWJzKGVycm9yX2Jhc2VsaW5lKSkgJT4lIAogIG11dGF0ZShkaWZmID0gZXJyb3JfdjJjc3JlcHJzcyAtIGVycm9yX2Jhc2VsaW5lKSAlPiUgCiAgbXV0YXRlKGFic19kaWZmID0gYWJzKGRpZmYpKSAlPiUgCiAgZmlsdGVyKGltcHJvdmVkKSAlPiUgCiAgYXJyYW5nZShkZXNjKGFic19kaWZmKSkKCm5yb3cobW9zdF9pbXByb3ZlZF9saHIpCgptb3N0X2ltcHJvdmVkX2xociAlPiUgCiAgc2VsZWN0KENvdW50cnkgPSBjb3VudHJ5LCBZZWFyID0geWVhciwgCiAgICAgICAgIGBBY3R1YWwgbGF0ZW50IGh1bWFuIHJpZ2h0cyB2YWx1ZSAodCArIDEpYCA9IGxhdGVudF9ocl9tZWFuX2xlYWQxLAogICAgICAgICBgUHJlZGljdGVkIChiYXNlbGluZSlgID0gZXN0aW1hdGVfYmFzZWxpbmUsCiAgICAgICAgIGBQcmVkaWN0ZWQgKENTIHJlcHJlc3Npb24pYCA9IGVzdGltYXRlX3YyY3NyZXByc3MsCiAgICAgICAgIGB8Q1MgcmVwcmVzc2lvbiDiiJIgYmFzZWxpbmV8YCA9IGFic19kaWZmKSAlPiUgCiAgaGVhZCg1KSAlPiUgCiAga2JsKGRpZ2l0cyA9IDMsIGFsaWduID0gImxjY2NjYyIpICU+JSAKICBrYWJsZV9zdHlsaW5nKCkKYGBgCg==