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

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

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