library(tidyverse)
library(targets)
library(brms)
library(tidybayes)
library(bayesplot)
library(fixest)
library(broom)
library(broom.mixed)
library(modelsummary)
library(patchwork)
library(scales)
library(latex2exp)
library(kableExtra)
library(here)

color_scheme_set("viridisC")

my_seed <- 1234
set.seed(my_seed)

withr::with_dir(here::here(), {
  source(tar_read(plot_funs))
  source(tar_read(misc_funs))
  
  # Data
  df_country_aid <- tar_read(country_aid_final)
  df_country_aid_laws <- filter(df_country_aid, laws)
  
  # Treatment models
  tar_load(c(m_purpose_treatment_total, m_purpose_treatment_advocacy, 
             m_purpose_treatment_entry, m_purpose_treatment_funding, 
             m_purpose_treatment_ccsi))
  
  # IPTW data
  tar_load(c(df_purpose_iptw_total, df_purpose_iptw_advocacy, 
             df_purpose_iptw_entry, df_purpose_iptw_funding,
             df_purpose_iptw_ccsi))
  
  # Outcome models
  tar_load(c(m_purpose_outcome_total, m_purpose_outcome_advocacy, 
             m_purpose_outcome_entry, m_purpose_outcome_funding,
             m_purpose_outcome_ccsi))
  
  # Results tables
  tar_load(c(models_tbl_h2_treatment_num, models_tbl_h2_treatment_denom))
  tar_load(c(models_tbl_h2_outcome_dejure, models_tbl_h2_outcome_defacto))
})

Weight models

  • Numerator is lagged treatment + non-varying confounders
  • Denominator is lagged treatment + lagged outcome + time-varying confounders + non-varying confounders

\[ sw = \prod^t_{t = 1} \frac{\phi(T_{it} | T_{i, t-1}, C_i)}{\phi(T_{it} | T_{i, t-1}, D_{i, t-1}, C_i)} \]

Priors for weight models

We use generic weakly informative priors for our model parameters:

  • Intercept: \(\mathcal{N} (0, 10)\)
  • Coefficients: \(\mathcal{N} (0, 2.5)\)
  • Sigma: \(\operatorname{Cauchy} (0, 1)\)
pri_int <- ggplot() +
  stat_function(fun = dnorm, args = list(mean = 0, sd = 10),
                geom = "area", fill = "grey80", color = "black") +
  labs(x = TeX("\\textbf{Intercept (β_0)}")) +
  annotate(geom = "label", x = 0, y = 0.01, label = "N(0, 10)", size = pts(9)) +
  xlim(-40, 40) +
  theme_donors(prior = TRUE)

pri_coef <- ggplot() +
  stat_function(fun = dnorm, args = list(mean = 0, sd = 2.5),
                geom = "area", fill = "grey80", color = "black") +
  labs(x = TeX("\\textbf{Coefficients (β_x)}")) +
  annotate(geom = "label", x = 0, y = 0.04, label = "N(0, 3)", size = pts(9)) +
  xlim(-10, 10) +
  theme_donors(prior = TRUE)

pri_sigma <- ggplot() +
  stat_function(fun = dcauchy, args = list(location = 0, scale = 1),
                geom = "area", fill = "grey80", color = "black") +
  labs(x = "σ") +
  annotate(geom = "label", x = 5, y = 0.08, label = "Cauchy(0, 1)", size = pts(9)) +
  xlim(0, 10) +
  theme_donors(prior = TRUE)

(pri_int + pri_coef + pri_sigma)

Check weight models

We check one of the denominator models for convergence and mixing and fit (not the numerator, since those models are the same as the ones in H1).

pp_check(m_purpose_treatment_total$model_denom, type = "dens_overlay", nsamples = 10) +
  theme_donors()

m_purpose_treatment_total$model_denom %>% 
  posterior_samples(add_chain = TRUE) %>% 
  select(-starts_with("r_gwcode"), -starts_with("z_"), -lp__, -iter) %>% 
  mcmc_trace() +
  theme_donors() +
  theme(legend.position = "right")

Check weights

IPTWs should generally have a mean of 1 and shouldn’t be too incredibly high.

Total ODA

Eh, some of these are high, but the mean and median are fine.

summary(df_purpose_iptw_total$iptw)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##  0.00259  0.85217  0.96672  1.14836  1.04919 19.68508
df_purpose_iptw_total %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 0.5, boundary = 0) +
  theme_donors()

Advocacy

Great.

summary(df_purpose_iptw_advocacy$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.1081  0.9095  0.9759  1.0161  1.0214  7.0687
df_purpose_iptw_advocacy %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 1, boundary = 0) +
  theme_donors()

Entry

Good.

summary(df_purpose_iptw_entry$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.06705 0.90954 0.99114 1.02679 1.05879 5.80478
df_purpose_iptw_entry %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 0.5, boundary = 0) +
  theme_donors()

Funding

Some high values again, but only a handful, and the median and mean are great.

summary(df_purpose_iptw_funding$iptw)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##  0.00198  0.85995  0.95694  1.09559  1.01442 22.28486
df_purpose_iptw_funding %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 1, boundary = 0) +
  theme_donors()

Core civil society index

hahaha oh no:

summary(df_purpose_iptw_ccsi$iptw)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 0.000e+00 0.000e+00 0.000e+00 5.692e+09 1.000e+00 1.922e+12

We truncate at four different thresholds: 100, 500, 1,000, and 5,000:

plot_iptw_ccsi <- bind_rows(
  df_purpose_iptw_ccsi %>% mutate(threshold = 100, iptw = ifelse(iptw > 100, 100, iptw)),
  df_purpose_iptw_ccsi %>% mutate(threshold = 500, iptw = ifelse(iptw > 500, 500, iptw)),
  df_purpose_iptw_ccsi %>% mutate(threshold = 1000, iptw = ifelse(iptw > 1000, 1000, iptw)),
  df_purpose_iptw_ccsi %>% mutate(threshold = 5000, iptw = ifelse(iptw > 5000, 5000, iptw))
) %>% 
  mutate(threshold = paste0("Truncated at ", comma(threshold)),
         threshold = fct_inorder(threshold))

plot_iptw_ccsi %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(bins = 50, boundary = 0) +
  facet_wrap(vars(threshold), scales = "free_x") +
  theme_donors()

Results

These are less important since we just use these treatment models to generate weights and because interpreting each coefficient when trying to isolate casual effects is unimportant and a “nuisance”. But here are the results anyway:

Numerator models

# model_names <- paste0("(", 1:length(models_tbl_h2_treatment_num), ")")
model_names <- 1:length(models_tbl_h2_treatment_num)
names(models_tbl_h2_treatment_num) <- model_names

treatment_names <- c("Treatment", "Total barriers (t)", "Barriers to advocacy (t)", 
                     "Barriers to entry (t)", "Barriers to funding (t)", "CCSI (t)")
treatment_rows <- as.data.frame(t(treatment_names))
attr(treatment_rows, "position") <- 1

coef_list_num <- list(
  "b_barriers_total_lag1" = "Treatment (t − 1)",
  "b_advocacy_lag1" = "Treatment (t − 1)",
  "b_entry_lag1" = "Treatment (t − 1)",
  "b_funding_lag1" = "Treatment (t − 1)",
  "b_v2xcs_ccsi_lag1" = "Treatment (t − 1)",
  "b_Intercept" = "Intercept"
)

modelsummary(models_tbl_h2_treatment_num,
             statistic = "[{conf.low}, {conf.high}]",
             coef_map = coef_list_num,
             add_rows = treatment_rows,
             gof_omit = "ELPD",
             escape = FALSE,
             notes = list("Posterior means; 95% credible intervals in brackets"))
1 2 3 4 5
Treatment Total barriers (t) Barriers to advocacy (t) Barriers to entry (t) Barriers to funding (t) CCSI (t)
Treatment (t − 1) 0.987 0.992 0.970 0.990 0.830
[0.977, 0.995] [0.983, 1.000] [0.958, 0.982] [0.979, 0.999] [0.810, 0.848]
Intercept 0.086 0.015 0.051 0.030 0.112
[0.065, 0.108] [0.010, 0.020] [0.039, 0.063] [0.021, 0.039] [0.099, 0.126]
Num.Obs. 3153 3153 3153 3153 3267
R2 0.941 0.949 0.929 0.940 0.959
R2 Marg. 0.941 0.949 0.928 0.940 0.912
LOOIC 4139.0 -4304.5 -12.6 -387.3 -9445.1
LOOIC s.e. 546.4 633.1 458.8 699.6 337.4
WAIC 4140.9 -4299.9 -12.4 -370.8 -9445.7
RMSE 1.33 0.34 0.66 0.60 0.33
Posterior means; 95% credible intervals in brackets

Denominator models

# model_names <- paste0("(", 1:length(models_tbl_h2_treatment_denom), ")")
model_names <- 1:length(models_tbl_h2_treatment_denom)
names(models_tbl_h2_treatment_denom) <- model_names

treatment_names <- c("Treatment", "Total barriers (t)", "Barriers to advocacy (t)", 
                     "Barriers to entry (t)", "Barriers to funding (t)", "CCSI (t)")
treatment_rows <- as.data.frame(t(treatment_names))
attr(treatment_rows, "position") <- 1

coef_list_denom <- list(
  "b_barriers_total_lag1" = "Treatment (t − 1)",
  "b_advocacy_lag1" = "Treatment (t − 1)",
  "b_entry_lag1" = "Treatment (t − 1)",
  "b_funding_lag1" = "Treatment (t − 1)",
  "b_v2xcs_ccsi_lag1" = "Treatment (t − 1)",
  "b_v2x_polyarchy" = "Polyarchy",
  "b_v2x_corr" = "Corruption index",
  "b_v2x_rule" = "Rule of law index",
  "b_v2x_civlib" = "Civil liberties index",
  "b_v2x_clphy" = "Physical violence index",
  "b_v2x_clpriv" = "Private civil liberties index",
  "b_gdpcap_log" = "Log GDP/capita",
  "b_un_trade_pct_gdp" = "Percent of GDP from trade",
  "b_v2peedueq" = "Educational equality index",
  "b_v2pehealth" = "Health equality index",
  "b_e_peinfmor" = "Infant mortality rate",
  "b_internal_conflict_past_5TRUE" = "Internal conflict in past 5 years",
  "b_natural_dis_count" = "Count of natural disasters",
  "b_Intercept" = "Intercept"
)

modelsummary(models_tbl_h2_treatment_denom,
             statistic = "[{conf.low}, {conf.high}]",
             coef_map = coef_list_denom,
             add_rows = treatment_rows,
             gof_omit = "ELPD",
             escape = FALSE,
             notes = list("Posterior means; 95% credible intervals in brackets"))
1 2 3 4 5
Treatment Total barriers (t) Barriers to advocacy (t) Barriers to entry (t) Barriers to funding (t) CCSI (t)
Treatment (t − 1) 0.974 0.986 0.964 0.977 0.504
[0.965, 0.985] [0.977, 0.995] [0.953, 0.975] [0.966, 0.987] [0.477, 0.530]
Polyarchy -0.093 0.014 -0.078 -0.040 0.010
[-0.249, 0.083] [-0.033, 0.057] [-0.166, 0.018] [-0.128, 0.038] [-0.018, 0.040]
Corruption index -0.066 -0.021 -0.023 -0.027 -0.020
[-0.234, 0.109] [-0.066, 0.022] [-0.109, 0.065] [-0.116, 0.052] [-0.054, 0.014]
Rule of law index -0.107 -0.050 -0.027 -0.033 0.029
[-0.311, 0.083] [-0.100, 0.000] [-0.128, 0.071] [-0.122, 0.063] [-0.010, 0.069]
Civil liberties index -0.386 -0.109 -0.177 -0.075 0.856
[-0.860, 0.125] [-0.244, 0.021] [-0.458, 0.085] [-0.325, 0.175] [0.775, 0.931]
Physical violence index 0.233 0.062 0.113 0.052 -0.223
[0.010, 0.450] [0.002, 0.122] [-0.009, 0.235] [-0.056, 0.162] [-0.259, -0.185]
Private civil liberties index 0.090 0.043 0.074 -0.033 -0.182
[-0.161, 0.370] [-0.026, 0.116] [-0.060, 0.222] [-0.172, 0.092] [-0.224, -0.141]
Log GDP/capita -0.013 -0.002 -0.004 -0.007 -0.008
[-0.034, 0.008] [-0.008, 0.003] [-0.015, 0.008] [-0.017, 0.004] [-0.014, -0.002]
Percent of GDP from trade -0.009 0.005 -0.011 -0.004 -0.005
[-0.053, 0.031] [-0.005, 0.016] [-0.033, 0.011] [-0.024, 0.016] [-0.013, 0.003]
Educational equality index -0.011 -0.001 -0.002 -0.009 -0.007
[-0.038, 0.016] [-0.008, 0.006] [-0.015, 0.013] [-0.022, 0.004] [-0.013, -0.002]
Health equality index 0.015 0.001 0.000 0.014 0.000
[-0.015, 0.048] [-0.008, 0.009] [-0.016, 0.016] [0.000, 0.031] [-0.006, 0.006]
Infant mortality rate -0.001 0.000 0.000 0.000 0.000
[-0.002, 0.000] [0.000, 0.000] [-0.001, 0.000] [-0.001, 0.000] [0.000, 0.000]
Internal conflict in past 5 years 0.006 0.004 0.002 0.002 0.008
[-0.035, 0.048] [-0.006, 0.015] [-0.021, 0.023] [-0.019, 0.022] [0.002, 0.013]
Count of natural disasters 0.006 0.001 0.002 0.002 0.000
[0.001, 0.011] [0.000, 0.003] [0.000, 0.005] [0.000, 0.005] [-0.001, 0.001]
Intercept 0.434 0.068 0.165 0.201 0.084
[0.191, 0.685] [0.007, 0.131] [0.035, 0.289] [0.079, 0.323] [0.025, 0.146]
Num.Obs. 3153 3153 3153 3153 3267
R2 0.942 0.949 0.929 0.941 0.970
R2 Marg. 0.942 0.949 0.928 0.941 0.948
LOOIC 4121.4 -4296.8 -16.1 -398.7 -10406.1
LOOIC s.e. 535.6 630.7 454.2 685.4 269.7
WAIC 4125.7 -4291.5 -17.5 -382.0 -10407.1
RMSE 1.33 0.34 0.66 0.60 0.33
Posterior means; 95% credible intervals in brackets

Outcome models

Modeling choice

Our dependent variable for this hypothesis is the percentage of ODA allocated for contentious purposes, again leaded by one year. We classify contentious aid as any project focused on government and civil society (DAC codes 150 and 151) or conflict prevention and resolution, peace and security (DAC code 152).

Working with proportion data, however, poses interesting mathematical and methodological challenges, since the range of possible outcomes is limited to a value between 0 and 1. Treating proportion variables in a mixed model is technically possible, but it yields predictions that go beyond the allowable range of values (1.13, -0.5, etc.). Treating the proportion as a binomial variable is also possible and is indeed one of the ways to use the glm() function in R. However, this entails considering the proportion as a ratio of success and failures. In this case, treating a dollar of contentious aid as a success feels off, especially since aid amounts aren’t independent events—it’s not like each dollar of aid goes through a probabalistic process like a coin flip.

Another solution is to use beta regression, which constrains the outcome variable to values between 0 and 1, but unfortunately does not allow for values of exactly 0 or 1. Zero-and-one inflated beta regression models, however, make adjustments for this and model the probability of being 0, being 1, and being somewhere in the middle using different processes. Matti Vuorre has an excellent overview of ZOIB models here.

However, as we found with our hurdling dilemma with H1, while it’s possible to fit a zero-inflated model (or even zero-one-inflated model), it would require separate model specifications for different parts (the zero part, the one part, and the non-zero-one parts), leaving us with three different pseudo-treatment effects, only one of which (the non-zero-one part) weighted with the IPTW, and thus adjusted with do-calculus logic.

One recommendation by Ben Bolker, the maintainer of lme4, is to use a logit transformation of the dependent variable in lmer() models. This seems to be standard practice in political science research, too. Logit transformations still can’t handle values of exactly 0 or 1, though, but it’s possible to winsorize those values by adding or subtracting 0.001 to the extremes. Stata has a guide about how to do this too.

We thus use logit-linear models of the ratio of contentious aid to non-contentious aid, like this:

\[\log \left( \frac{\text{Contentious aid}}{\text{Noncontentious aid}} \right)_{i, t+1}\]

That means that we’re comparing the ratio of contentious aid to non-contentious aid rather than the direct percent of contentious aid, and it makes for some acrobatic interpretations, but at least the results are interpretable.

Interpreting outcome models

TODO

Priors for outcome models

Here’s the full specification for the models and all priors:

\[ \begin{aligned} \log \left(\frac{\text{Contentious aid}}{\text{Noncontentious aid}} \right)_{i, t} &\sim \text{IPTW}_{i, t-1} \times \mathcal{N} (\mu_{i, t}, \sigma_m) & \text{[likelihood]}\\ \mu_{i, t} &\sim \alpha_{\text{country}[i]} + \delta_{\text{year}[k]} + \beta\ \text{Law}_{i, t-1} & \text{[marginal structural model]}\\ \alpha_j &\sim \mathcal{N} (\bar{\alpha}, \sigma_{\alpha}) \text{, for } j \text{ in } 1 .. J & \text{[country-specific intercepts]} \\ \delta_j &\sim \mathcal{N} (0, \sigma_{\delta}) \text{, for } j \text{ in } 1 .. J & \text{[year-specific intercepts]} \\ \ \\ \bar{\alpha} &\sim \mathcal{N} (0, 20) & \text{[prior population intercept]} \\ \beta &\sim \mathcal{N} (0, 3) & \text{[prior population effects]} \\ \sigma_m, \sigma_{\alpha}, \sigma_{\delta} &\sim \operatorname{Cauchy}(0, 1) & \text{[prior sd for errors]} \end{aligned} \]

Check outcome models

The traceplots all look fine. Here’s one as an example:

m_purpose_outcome_total %>% 
  posterior_samples(add_chain = TRUE) %>% 
  select(-starts_with("r_gwcode"), -starts_with("z_"), -starts_with("r_year"), -lp__, -iter) %>% 
  mcmc_trace() +
  theme_donors()

Results

ATE plots

coefs_nice <- tribble(
  ~`.variable`, ~var_nice,
  "b_barriers_total", "Additional law, t - 1",
  "b_advocacy", "Additional advocacy law, t - 1",
  "b_entry", "Additional entry law, t - 1",
  "b_funding", "Additional funding law, t - 1",
  "b_v2xcs_ccsi", "Core civil society index, t - 1"
) %>% 
  mutate(var_nice = fct_inorder(var_nice))

plot_total_data <- gather_draws(m_purpose_outcome_total, b_barriers_total)
plot_advocacy_data <- gather_draws(m_purpose_outcome_advocacy, b_advocacy)
plot_entry_data <- gather_draws(m_purpose_outcome_entry, b_entry)
plot_funding_data <- gather_draws(m_purpose_outcome_funding, b_funding) 

plot_purpose_coefs <- bind_rows(plot_total_data, plot_advocacy_data,
                                plot_entry_data, plot_funding_data) %>% 
  left_join(coefs_nice, by = ".variable") %>% 
  mutate(.value = exp(.value))

rope_sd <- exp(sd(df_purpose_iptw_total$prop_contentious_logit_lead1))

plot_rope <- tibble(xmin = 1 + (-0.05 * rope_sd), 
                    xmax = 1 + (0.05 * rope_sd))

ggplot(plot_purpose_coefs, aes(x = .value, y = fct_rev(var_nice), fill = var_nice)) +
  geom_vline(xintercept = 1) +
  geom_rect(data = plot_rope, aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf),
            fill = "#FFDC00", alpha = 0.3, inherit.aes = FALSE) +
  annotate(geom = "label", x = 1, y = 0.65, 
           label = "Region of practical equivalence\n(± 0.05 × SD y)",
           size = pts(8)) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8, point_interval = "median_hdi") +
  guides(fill = FALSE) +
  scale_y_discrete() +
  scale_fill_manual(values = c("#FF851B", "#85144b", "#3D9970", "#001f3f")) +
  labs(x = "Percent change in ratio of contentious aid in following year", y = NULL,
       caption = "Point shows posterior median; lines show 80% and 95%\ncredible highest-density-interval") +
  theme_donors()

lol what even

plot_ccsi_coefs <- m_purpose_outcome_ccsi %>% 
  map_dfr(~gather_draws(., b_v2xcs_ccsi), .id = "model") %>% 
  mutate(.value = .value / 10) %>% 
  mutate(model = comma(as.numeric(str_remove(model, "model_")))) %>% 
  mutate(model = fct_inorder(model)) %>% 
  left_join(coefs_nice, by = ".variable")

ggplot(plot_ccsi_coefs, aes(x = .value, y = fct_rev(model), fill = model)) +
  stat_halfeye(.width = c(0.8, 0.95), point_interval = "median_hdi",
               position = position_dodge(width = 0.5)) +
  guides(fill = FALSE) +
  labs(x = "Coefficient", y = "IPTW truncation point") +
  theme_donors()

Tables

# model_names <- paste0("(", 1:length(models_tbl_h2_outcome_dejure), ")")
model_names <- 1:length(models_tbl_h2_outcome_dejure)
names(models_tbl_h2_outcome_dejure) <- model_names

treatment_names <- c("Treatment", "Total barriers (t)", "Barriers to advocacy (t)", 
                     "Barriers to entry (t)", "Barriers to funding (t)")
treatment_rows <- as.data.frame(t(treatment_names))
attr(treatment_rows, "position") <- 1

coef_list_outcome <- list(
  "b_barriers_total" = "Treatment (t)",
  "b_advocacy" = "Treatment (t)",
  "b_entry" = "Treatment (t)",
  "b_funding" = "Treatment (t)",
  "b_v2xcs_ccsi" = "Core civil society index (t)",
  "b_Intercept" = "Intercept",
  "sd_gwcode__Intercept" = "σ country intercepts",
  "sd_year__Intercept" = "σ year intercepts"
)

modelsummary(models_tbl_h2_outcome_dejure,
             statistic = "[{conf.low}, {conf.high}]",
             coef_map = coef_list_outcome,
             add_rows = treatment_rows,
             gof_omit = "ELPD",
             escape = FALSE,
             notes = list("Posterior means; 95% credible intervals in brackets")) %>% 
  add_header_above(c(" " = 1, "Outcome: Logit prop contentious (t + 1)" = 4))
Outcome: Logit prop contentious (t + 1)
1 2 3 4
Treatment Total barriers (t) Barriers to advocacy (t) Barriers to entry (t) Barriers to funding (t)
Treatment (t) 0.072 0.060 0.227 0.058
[0.023, 0.124] [-0.141, 0.252] [0.132, 0.323] [-0.053, 0.171]
Intercept -3.904 -3.810 -3.976 -3.840
[-4.355, -3.429] [-4.254, -3.363] [-4.426, -3.525] [-4.320, -3.382]
σ country intercepts 1.216 1.194 1.192 1.197
[1.078, 1.377] [1.052, 1.354] [1.049, 1.347] [1.053, 1.349]
σ year intercepts 0.978 0.962 0.965 0.960
[0.741, 1.311] [0.711, 1.279] [0.705, 1.293] [0.711, 1.288]
Num.Obs. 3293 3293 3293 3293
R2 0.548 0.542 0.546 0.541
R2 Marg. 0.005 0.000 0.010 0.001
LOOIC 12772.0 11593.3 11726.7 12330.7
LOOIC s.e. 274.2 145.5 173.9 213.9
WAIC 12769.7 11592.3 11725.5 12328.7
Posterior means; 95% credible intervals in brackets

TODO: This is a mess

truncation_thresholds <- names(models_tbl_h2_outcome_defacto) %>% 
  str_extract("_\\d+") %>% 
  str_remove("_") %>% 
  as.numeric() %>% 
  comma()

truncation_names <- c("IPTW truncation threshold", truncation_thresholds)
truncation_rows <- as.data.frame(t(truncation_names))
attr(truncation_rows, "position") <- 1

# model_names <- paste0("(", 1:length(models_tbl_h2_outcome_defacto), ")")
model_names <- 1:length(models_tbl_h2_outcome_defacto)
names(models_tbl_h2_outcome_defacto) <- model_names

modelsummary(models_tbl_h2_outcome_defacto,
             statistic = "[{conf.low}, {conf.high}]",
             coef_map = coef_list_outcome,
             add_rows = truncation_rows,
             gof_omit = "ELPD",
             escape = FALSE,
             notes = list("Posterior means; 95% credible intervals in brackets")) %>% 
  add_header_above(c(" " = 1, "Outcome: Outcome: Logit prop contentious (t + 1)" = 4))
Outcome: Outcome: Logit prop contentious (t + 1)
1 2 3 4
IPTW truncation threshold 100 500 1,000 5,000
Core civil society index (t) -0.277 -0.277 -0.277 -0.277
[-1.631, 1.001] [-1.631, 1.001] [-1.631, 1.001] [-1.631, 1.001]
Intercept 0.283 0.283 0.283 0.283
[-1.968, 2.757] [-1.968, 2.757] [-1.968, 2.757] [-1.968, 2.757]
Num.Obs. 3293 3293 3293 3293
R2 0.010 0.010 0.010 0.010
LOOIC 1.077603e+14 1.077603e+14 1.077603e+14 1.077603e+14
LOOIC s.e. 2.971661e+13 2.971661e+13 2.971661e+13 2.971661e+13
WAIC 1.904286e+25 1.904286e+25 1.904286e+25 1.904286e+25
Posterior means; 95% credible intervals in brackets

Marginal effects

# brms::conditional_effects() can create spaghetti plots (single lines per
# sample), but it stores them in an attribute slot named "spaghetti", which is
# tricky to extract data from. This pulls the data frame from the attribute
make_spaghetti <- function(model) {
  raw_effects <- conditional_effects(model, spaghetti = TRUE, nsamples = 100)[[1]]
  spaghetti_data <- attr(raw_effects, "spaghetti")
  return(spaghetti_data)
}

inv_logit <- function(f, a) {
  a <- (1 - 2 * a)
  (a * (1 + exp(f)) + (exp(f) - 1)) / (2 * a * (1 + exp(f)))
}

make_spaghetti(m_purpose_outcome_total) %>% 
  mutate(estimate__ = inv_logit(estimate__, a = 0.001)) %>% 
  ggplot(aes(x = effect1__, y = estimate__, group = sample__)) +
  geom_line(size = 0.25, color = "#FF4136") +
  scale_x_continuous(breaks = 0:9) +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  guides(color = FALSE) +
  labs(x = "Count of total legal barriers",
       y = "Predicted proportion of\ncontentious aid in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

make_spaghetti(m_purpose_outcome_advocacy) %>% 
  mutate(estimate__ = inv_logit(estimate__, a = 0.001)) %>% 
  ggplot(aes(x = effect1__, y = estimate__, group = sample__)) +
  geom_line(size = 0.25, color = "#FF4136") +
  scale_x_continuous(breaks = 0:2) +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  guides(color = FALSE) +
  labs(x = "Count of barriers to advocacy",
       y = "Predicted proportion of\ncontentious aid in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

make_spaghetti(m_purpose_outcome_entry) %>% 
  mutate(estimate__ = inv_logit(estimate__, a = 0.001)) %>% 
  ggplot(aes(x = effect1__, y = estimate__, group = sample__)) +
  geom_line(size = 0.25, color = "#FF4136") +
  scale_x_continuous(breaks = 0:3) +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  guides(color = FALSE) +
  labs(x = "Count of barriers to entry",
       y = "Predicted proportion of\ncontentious aid in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

make_spaghetti(m_purpose_outcome_funding) %>% 
  mutate(estimate__ = inv_logit(estimate__, a = 0.001)) %>% 
  ggplot(aes(x = effect1__, y = estimate__, group = sample__)) +
  geom_line(size = 0.25, color = "#FF4136") +
  scale_x_continuous(breaks = 0:5) +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  guides(color = FALSE) +
  labs(x = "Count of barriers to funding",
       y = "Predicted proportion of\ncontentious aid in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

LS0tCnRpdGxlOiAiSH4yfjogRWZmZWN0IG9mIGFudGktTkdPIGNyYWNrZG93biBvbiBhaWQgY29udGVudGlvdXNuZXNzIgphdXRob3I6ICJTdXBhcm5hIENoYXVkaHJ5IGFuZCBBbmRyZXcgSGVpc3MiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVGJylgIgpiaWJsaW9ncmFwaHk6ICJgciBoZXJlOjpoZXJlKCdtYW51c2NyaXB0JywgJ2JpYmxpb2dyYXBoeS5iaWInKWAiCmNzbDogImByIGhlcmU6OmhlcmUoJ21hbnVzY3JpcHQnLCAncGFuZG9jJywgJ2NzbCcsICdjaGljYWdvLWF1dGhvci1kYXRlLmNzbCcpYCIKbGluay1jaXRhdGlvbnM6IHRydWUKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcucmV0aW5hID0gMywKICAgICAgICAgICAgICAgICAgICAgIHRpZHkub3B0cyA9IGxpc3Qod2lkdGguY3V0b2ZmID0gMTIwKSwgICMgRm9yIGNvZGUKICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMod2lkdGggPSA5MCksICAjIEZvciBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hc3AgPSAwLjYxOCwgZmlnLndpZHRoID0gNywgCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gIjg1JSIpCgpvcHRpb25zKGRwbHlyLnN1bW1hcmlzZS5pbmZvcm0gPSBGQUxTRSkKYGBgCgpgYGB7ciBsb2FkLWxpYnJhcmllcywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGFyZ2V0cykKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShiYXllc3Bsb3QpCmxpYnJhcnkoZml4ZXN0KQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGJyb29tLm1peGVkKQpsaWJyYXJ5KG1vZGVsc3VtbWFyeSkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGxhdGV4MmV4cCkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGhlcmUpCgpjb2xvcl9zY2hlbWVfc2V0KCJ2aXJpZGlzQyIpCgpteV9zZWVkIDwtIDEyMzQKc2V0LnNlZWQobXlfc2VlZCkKCndpdGhyOjp3aXRoX2RpcihoZXJlOjpoZXJlKCksIHsKICBzb3VyY2UodGFyX3JlYWQocGxvdF9mdW5zKSkKICBzb3VyY2UodGFyX3JlYWQobWlzY19mdW5zKSkKICAKICAjIERhdGEKICBkZl9jb3VudHJ5X2FpZCA8LSB0YXJfcmVhZChjb3VudHJ5X2FpZF9maW5hbCkKICBkZl9jb3VudHJ5X2FpZF9sYXdzIDwtIGZpbHRlcihkZl9jb3VudHJ5X2FpZCwgbGF3cykKICAKICAjIFRyZWF0bWVudCBtb2RlbHMKICB0YXJfbG9hZChjKG1fcHVycG9zZV90cmVhdG1lbnRfdG90YWwsIG1fcHVycG9zZV90cmVhdG1lbnRfYWR2b2NhY3ksIAogICAgICAgICAgICAgbV9wdXJwb3NlX3RyZWF0bWVudF9lbnRyeSwgbV9wdXJwb3NlX3RyZWF0bWVudF9mdW5kaW5nLCAKICAgICAgICAgICAgIG1fcHVycG9zZV90cmVhdG1lbnRfY2NzaSkpCiAgCiAgIyBJUFRXIGRhdGEKICB0YXJfbG9hZChjKGRmX3B1cnBvc2VfaXB0d190b3RhbCwgZGZfcHVycG9zZV9pcHR3X2Fkdm9jYWN5LCAKICAgICAgICAgICAgIGRmX3B1cnBvc2VfaXB0d19lbnRyeSwgZGZfcHVycG9zZV9pcHR3X2Z1bmRpbmcsCiAgICAgICAgICAgICBkZl9wdXJwb3NlX2lwdHdfY2NzaSkpCiAgCiAgIyBPdXRjb21lIG1vZGVscwogIHRhcl9sb2FkKGMobV9wdXJwb3NlX291dGNvbWVfdG90YWwsIG1fcHVycG9zZV9vdXRjb21lX2Fkdm9jYWN5LCAKICAgICAgICAgICAgIG1fcHVycG9zZV9vdXRjb21lX2VudHJ5LCBtX3B1cnBvc2Vfb3V0Y29tZV9mdW5kaW5nLAogICAgICAgICAgICAgbV9wdXJwb3NlX291dGNvbWVfY2NzaSkpCiAgCiAgIyBSZXN1bHRzIHRhYmxlcwogIHRhcl9sb2FkKGMobW9kZWxzX3RibF9oMl90cmVhdG1lbnRfbnVtLCBtb2RlbHNfdGJsX2gyX3RyZWF0bWVudF9kZW5vbSkpCiAgdGFyX2xvYWQoYyhtb2RlbHNfdGJsX2gyX291dGNvbWVfZGVqdXJlLCBtb2RlbHNfdGJsX2gyX291dGNvbWVfZGVmYWN0bykpCn0pCmBgYAoKIyMgV2VpZ2h0IG1vZGVscwoKLSBOdW1lcmF0b3IgaXMgbGFnZ2VkIHRyZWF0bWVudCArIG5vbi12YXJ5aW5nIGNvbmZvdW5kZXJzCi0gRGVub21pbmF0b3IgaXMgbGFnZ2VkIHRyZWF0bWVudCArIGxhZ2dlZCBvdXRjb21lICsgdGltZS12YXJ5aW5nIGNvbmZvdW5kZXJzICsgbm9uLXZhcnlpbmcgY29uZm91bmRlcnMKCiQkCnN3ID0gXHByb2RedF97dCA9IDF9IFxmcmFje1xwaGkoVF97aXR9IHwgVF97aSwgdC0xfSwgQ19pKX17XHBoaShUX3tpdH0gfCBUX3tpLCB0LTF9LCBEX3tpLCB0LTF9LCBDX2kpfQokJAoKIyMjIFByaW9ycyBmb3Igd2VpZ2h0IG1vZGVscwoKV2UgdXNlIFtnZW5lcmljIHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnNdKGh0dHBzOi8vbWMtc3Rhbi5vcmcvdXNlcnMvZG9jdW1lbnRhdGlvbi9jYXNlLXN0dWRpZXMvd2Vha2x5X2luZm9ybWF0aXZlX3NoYXBlcy5odG1sKSBmb3Igb3VyIG1vZGVsIHBhcmFtZXRlcnM6CgotIEludGVyY2VwdDogJFxtYXRoY2Fse059ICgwLCAxMCkkCi0gQ29lZmZpY2llbnRzOiAkXG1hdGhjYWx7Tn0gKDAsIDIuNSkkCi0gU2lnbWE6ICRcb3BlcmF0b3JuYW1le0NhdWNoeX0gKDAsIDEpJAoKYGBge3IgcGxvdC13ZWlnaHQtcHJpb3JzLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD02LCBmaWcuYXNwPU5VTEx9CnByaV9pbnQgPC0gZ2dwbG90KCkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sIGFyZ3MgPSBsaXN0KG1lYW4gPSAwLCBzZCA9IDEwKSwKICAgICAgICAgICAgICAgIGdlb20gPSAiYXJlYSIsIGZpbGwgPSAiZ3JleTgwIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh4ID0gVGVYKCJcXHRleHRiZntJbnRlcmNlcHQgKM6yXzApfSIpKSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJsYWJlbCIsIHggPSAwLCB5ID0gMC4wMSwgbGFiZWwgPSAiTigwLCAxMCkiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgtNDAsIDQwKSArCiAgdGhlbWVfZG9ub3JzKHByaW9yID0gVFJVRSkKCnByaV9jb2VmIDwtIGdncGxvdCgpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gMCwgc2QgPSAyLjUpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSBUZVgoIlxcdGV4dGJme0NvZWZmaWNpZW50cyAozrJfeCl9IikpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDAsIHkgPSAwLjA0LCBsYWJlbCA9ICJOKDAsIDMpIiwgc2l6ZSA9IHB0cyg5KSkgKwogIHhsaW0oLTEwLCAxMCkgKwogIHRoZW1lX2Rvbm9ycyhwcmlvciA9IFRSVUUpCgpwcmlfc2lnbWEgPC0gZ2dwbG90KCkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZGNhdWNoeSwgYXJncyA9IGxpc3QobG9jYXRpb24gPSAwLCBzY2FsZSA9IDEpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSAiz4MiKSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJsYWJlbCIsIHggPSA1LCB5ID0gMC4wOCwgbGFiZWwgPSAiQ2F1Y2h5KDAsIDEpIiwgc2l6ZSA9IHB0cyg5KSkgKwogIHhsaW0oMCwgMTApICsKICB0aGVtZV9kb25vcnMocHJpb3IgPSBUUlVFKQoKKHByaV9pbnQgKyBwcmlfY29lZiArIHByaV9zaWdtYSkKYGBgCgojIyMgQ2hlY2sgd2VpZ2h0IG1vZGVscwoKV2UgY2hlY2sgb25lIG9mIHRoZSBkZW5vbWluYXRvciBtb2RlbHMgZm9yIGNvbnZlcmdlbmNlIGFuZCBtaXhpbmcgYW5kIGZpdCAobm90IHRoZSBudW1lcmF0b3IsIHNpbmNlIHRob3NlIG1vZGVscyBhcmUgdGhlIHNhbWUgYXMgdGhlIG9uZXMgaW4gSDEpLgoKYGBge3IgaDItY2hlY2stZGVub21pbmF0b3J9CnBwX2NoZWNrKG1fcHVycG9zZV90cmVhdG1lbnRfdG90YWwkbW9kZWxfZGVub20sIHR5cGUgPSAiZGVuc19vdmVybGF5IiwgbnNhbXBsZXMgPSAxMCkgKwogIHRoZW1lX2Rvbm9ycygpCgptX3B1cnBvc2VfdHJlYXRtZW50X3RvdGFsJG1vZGVsX2Rlbm9tICU+JSAKICBwb3N0ZXJpb3Jfc2FtcGxlcyhhZGRfY2hhaW4gPSBUUlVFKSAlPiUgCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgicl9nd2NvZGUiKSwgLXN0YXJ0c193aXRoKCJ6XyIpLCAtbHBfXywgLWl0ZXIpICU+JSAKICBtY21jX3RyYWNlKCkgKwogIHRoZW1lX2Rvbm9ycygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQpgYGAKCiMjIyBDaGVjayB3ZWlnaHRzIHsudGFic2V0fQoKSVBUV3Mgc2hvdWxkIGdlbmVyYWxseSBoYXZlIGEgbWVhbiBvZiAxIGFuZCBzaG91bGRuJ3QgYmUgdG9vIGluY3JlZGlibHkgaGlnaC4gCgojIyMjIFRvdGFsIE9EQQoKRWgsIHNvbWUgb2YgdGhlc2UgYXJlIGhpZ2gsIGJ1dCB0aGUgbWVhbiBhbmQgbWVkaWFuIGFyZSBmaW5lLgoKYGBge3IgaXB0d3MtdG90YWwtb2RhfQpzdW1tYXJ5KGRmX3B1cnBvc2VfaXB0d190b3RhbCRpcHR3KQoKZGZfcHVycG9zZV9pcHR3X3RvdGFsICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBpcHR3KSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC41LCBib3VuZGFyeSA9IDApICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyMgQWR2b2NhY3kKCkdyZWF0LgoKYGBge3IgaXB0d3MtYWR2b2NhY3l9CnN1bW1hcnkoZGZfcHVycG9zZV9pcHR3X2Fkdm9jYWN5JGlwdHcpCgpkZl9wdXJwb3NlX2lwdHdfYWR2b2NhY3kgJT4lIAogIGdncGxvdChhZXMoeCA9IGlwdHcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBib3VuZGFyeSA9IDApICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyMgRW50cnkKCkdvb2QuCgpgYGB7ciBpcHR3cy1lbnRyeX0Kc3VtbWFyeShkZl9wdXJwb3NlX2lwdHdfZW50cnkkaXB0dykKCmRmX3B1cnBvc2VfaXB0d19lbnRyeSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gaXB0dykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuNSwgYm91bmRhcnkgPSAwKSArCiAgdGhlbWVfZG9ub3JzKCkKYGBgCgojIyMjIEZ1bmRpbmcKClNvbWUgaGlnaCB2YWx1ZXMgYWdhaW4sIGJ1dCBvbmx5IGEgaGFuZGZ1bCwgYW5kIHRoZSBtZWRpYW4gYW5kIG1lYW4gYXJlIGdyZWF0LgoKYGBge3IgaXB0d3MtZnVuZGluZ30Kc3VtbWFyeShkZl9wdXJwb3NlX2lwdHdfZnVuZGluZyRpcHR3KQoKZGZfcHVycG9zZV9pcHR3X2Z1bmRpbmcgJT4lIAogIGdncGxvdChhZXMoeCA9IGlwdHcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBib3VuZGFyeSA9IDApICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyMgQ29yZSBjaXZpbCBzb2NpZXR5IGluZGV4CgpoYWhhaGEgb2ggbm86CgpgYGB7ciBpcHR3cy1jY3NpLXN1bW1hcnl9CnN1bW1hcnkoZGZfcHVycG9zZV9pcHR3X2Njc2kkaXB0dykKYGBgCgpXZSB0cnVuY2F0ZSBhdCBmb3VyIGRpZmZlcmVudCB0aHJlc2hvbGRzOiAxMDAsIDUwMCwgMSwwMDAsIGFuZCA1LDAwMDoKCmBgYHtyIGlwdHdzLWNjc2l9CnBsb3RfaXB0d19jY3NpIDwtIGJpbmRfcm93cygKICBkZl9wdXJwb3NlX2lwdHdfY2NzaSAlPiUgbXV0YXRlKHRocmVzaG9sZCA9IDEwMCwgaXB0dyA9IGlmZWxzZShpcHR3ID4gMTAwLCAxMDAsIGlwdHcpKSwKICBkZl9wdXJwb3NlX2lwdHdfY2NzaSAlPiUgbXV0YXRlKHRocmVzaG9sZCA9IDUwMCwgaXB0dyA9IGlmZWxzZShpcHR3ID4gNTAwLCA1MDAsIGlwdHcpKSwKICBkZl9wdXJwb3NlX2lwdHdfY2NzaSAlPiUgbXV0YXRlKHRocmVzaG9sZCA9IDEwMDAsIGlwdHcgPSBpZmVsc2UoaXB0dyA+IDEwMDAsIDEwMDAsIGlwdHcpKSwKICBkZl9wdXJwb3NlX2lwdHdfY2NzaSAlPiUgbXV0YXRlKHRocmVzaG9sZCA9IDUwMDAsIGlwdHcgPSBpZmVsc2UoaXB0dyA+IDUwMDAsIDUwMDAsIGlwdHcpKQopICU+JSAKICBtdXRhdGUodGhyZXNob2xkID0gcGFzdGUwKCJUcnVuY2F0ZWQgYXQgIiwgY29tbWEodGhyZXNob2xkKSksCiAgICAgICAgIHRocmVzaG9sZCA9IGZjdF9pbm9yZGVyKHRocmVzaG9sZCkpCgpwbG90X2lwdHdfY2NzaSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gaXB0dykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGJvdW5kYXJ5ID0gMCkgKwogIGZhY2V0X3dyYXAodmFycyh0aHJlc2hvbGQpLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKIyMjIFJlc3VsdHMgey50YWJzZXR9CgpUaGVzZSBhcmUgbGVzcyBpbXBvcnRhbnQgc2luY2Ugd2UganVzdCB1c2UgdGhlc2UgdHJlYXRtZW50IG1vZGVscyB0byBnZW5lcmF0ZSB3ZWlnaHRzICphbmQqIGJlY2F1c2UgaW50ZXJwcmV0aW5nIGVhY2ggY29lZmZpY2llbnQgd2hlbiB0cnlpbmcgdG8gaXNvbGF0ZSBjYXN1YWwgZWZmZWN0cyBpcyB1bmltcG9ydGFudCBhbmQgW2EgIm51aXNhbmNlIl0oaHR0cHM6Ly9hcnhpdi5vcmcvYWJzLzIwMDUuMTAzMTQpLiBCdXQgaGVyZSBhcmUgdGhlIHJlc3VsdHMgYW55d2F5OgoKIyMjIyBOdW1lcmF0b3IgbW9kZWxzCgpgYGB7ciB0YmwtaDItbnVtfQojIG1vZGVsX25hbWVzIDwtIHBhc3RlMCgiKCIsIDE6bGVuZ3RoKG1vZGVsc190YmxfaDJfdHJlYXRtZW50X251bSksICIpIikKbW9kZWxfbmFtZXMgPC0gMTpsZW5ndGgobW9kZWxzX3RibF9oMl90cmVhdG1lbnRfbnVtKQpuYW1lcyhtb2RlbHNfdGJsX2gyX3RyZWF0bWVudF9udW0pIDwtIG1vZGVsX25hbWVzCgp0cmVhdG1lbnRfbmFtZXMgPC0gYygiVHJlYXRtZW50IiwgIlRvdGFsIGJhcnJpZXJzICh0KSIsICJCYXJyaWVycyB0byBhZHZvY2FjeSAodCkiLCAKICAgICAgICAgICAgICAgICAgICAgIkJhcnJpZXJzIHRvIGVudHJ5ICh0KSIsICJCYXJyaWVycyB0byBmdW5kaW5nICh0KSIsICJDQ1NJICh0KSIpCnRyZWF0bWVudF9yb3dzIDwtIGFzLmRhdGEuZnJhbWUodCh0cmVhdG1lbnRfbmFtZXMpKQphdHRyKHRyZWF0bWVudF9yb3dzLCAicG9zaXRpb24iKSA8LSAxCgpjb2VmX2xpc3RfbnVtIDwtIGxpc3QoCiAgImJfYmFycmllcnNfdG90YWxfbGFnMSIgPSAiVHJlYXRtZW50ICh0IOKIkiAxKSIsCiAgImJfYWR2b2NhY3lfbGFnMSIgPSAiVHJlYXRtZW50ICh0IOKIkiAxKSIsCiAgImJfZW50cnlfbGFnMSIgPSAiVHJlYXRtZW50ICh0IOKIkiAxKSIsCiAgImJfZnVuZGluZ19sYWcxIiA9ICJUcmVhdG1lbnQgKHQg4oiSIDEpIiwKICAiYl92Mnhjc19jY3NpX2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX0ludGVyY2VwdCIgPSAiSW50ZXJjZXB0IgopCgptb2RlbHN1bW1hcnkobW9kZWxzX3RibF9oMl90cmVhdG1lbnRfbnVtLAogICAgICAgICAgICAgc3RhdGlzdGljID0gIlt7Y29uZi5sb3d9LCB7Y29uZi5oaWdofV0iLAogICAgICAgICAgICAgY29lZl9tYXAgPSBjb2VmX2xpc3RfbnVtLAogICAgICAgICAgICAgYWRkX3Jvd3MgPSB0cmVhdG1lbnRfcm93cywKICAgICAgICAgICAgIGdvZl9vbWl0ID0gIkVMUEQiLAogICAgICAgICAgICAgZXNjYXBlID0gRkFMU0UsCiAgICAgICAgICAgICBub3RlcyA9IGxpc3QoIlBvc3RlcmlvciBtZWFuczsgOTUlIGNyZWRpYmxlIGludGVydmFscyBpbiBicmFja2V0cyIpKQpgYGAKCiMjIyMgRGVub21pbmF0b3IgbW9kZWxzCgpgYGB7ciB0YmwtaDItZGVub219CiMgbW9kZWxfbmFtZXMgPC0gcGFzdGUwKCIoIiwgMTpsZW5ndGgobW9kZWxzX3RibF9oMl90cmVhdG1lbnRfZGVub20pLCAiKSIpCm1vZGVsX25hbWVzIDwtIDE6bGVuZ3RoKG1vZGVsc190YmxfaDJfdHJlYXRtZW50X2Rlbm9tKQpuYW1lcyhtb2RlbHNfdGJsX2gyX3RyZWF0bWVudF9kZW5vbSkgPC0gbW9kZWxfbmFtZXMKCnRyZWF0bWVudF9uYW1lcyA8LSBjKCJUcmVhdG1lbnQiLCAiVG90YWwgYmFycmllcnMgKHQpIiwgIkJhcnJpZXJzIHRvIGFkdm9jYWN5ICh0KSIsIAogICAgICAgICAgICAgICAgICAgICAiQmFycmllcnMgdG8gZW50cnkgKHQpIiwgIkJhcnJpZXJzIHRvIGZ1bmRpbmcgKHQpIiwgIkNDU0kgKHQpIikKdHJlYXRtZW50X3Jvd3MgPC0gYXMuZGF0YS5mcmFtZSh0KHRyZWF0bWVudF9uYW1lcykpCmF0dHIodHJlYXRtZW50X3Jvd3MsICJwb3NpdGlvbiIpIDwtIDEKCmNvZWZfbGlzdF9kZW5vbSA8LSBsaXN0KAogICJiX2JhcnJpZXJzX3RvdGFsX2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX2Fkdm9jYWN5X2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX2VudHJ5X2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX2Z1bmRpbmdfbGFnMSIgPSAiVHJlYXRtZW50ICh0IOKIkiAxKSIsCiAgImJfdjJ4Y3NfY2NzaV9sYWcxIiA9ICJUcmVhdG1lbnQgKHQg4oiSIDEpIiwKICAiYl92MnhfcG9seWFyY2h5IiA9ICJQb2x5YXJjaHkiLAogICJiX3YyeF9jb3JyIiA9ICJDb3JydXB0aW9uIGluZGV4IiwKICAiYl92MnhfcnVsZSIgPSAiUnVsZSBvZiBsYXcgaW5kZXgiLAogICJiX3YyeF9jaXZsaWIiID0gIkNpdmlsIGxpYmVydGllcyBpbmRleCIsCiAgImJfdjJ4X2NscGh5IiA9ICJQaHlzaWNhbCB2aW9sZW5jZSBpbmRleCIsCiAgImJfdjJ4X2NscHJpdiIgPSAiUHJpdmF0ZSBjaXZpbCBsaWJlcnRpZXMgaW5kZXgiLAogICJiX2dkcGNhcF9sb2ciID0gIkxvZyBHRFAvY2FwaXRhIiwKICAiYl91bl90cmFkZV9wY3RfZ2RwIiA9ICJQZXJjZW50IG9mIEdEUCBmcm9tIHRyYWRlIiwKICAiYl92MnBlZWR1ZXEiID0gIkVkdWNhdGlvbmFsIGVxdWFsaXR5IGluZGV4IiwKICAiYl92MnBlaGVhbHRoIiA9ICJIZWFsdGggZXF1YWxpdHkgaW5kZXgiLAogICJiX2VfcGVpbmZtb3IiID0gIkluZmFudCBtb3J0YWxpdHkgcmF0ZSIsCiAgImJfaW50ZXJuYWxfY29uZmxpY3RfcGFzdF81VFJVRSIgPSAiSW50ZXJuYWwgY29uZmxpY3QgaW4gcGFzdCA1IHllYXJzIiwKICAiYl9uYXR1cmFsX2Rpc19jb3VudCIgPSAiQ291bnQgb2YgbmF0dXJhbCBkaXNhc3RlcnMiLAogICJiX0ludGVyY2VwdCIgPSAiSW50ZXJjZXB0IgopCgptb2RlbHN1bW1hcnkobW9kZWxzX3RibF9oMl90cmVhdG1lbnRfZGVub20sCiAgICAgICAgICAgICBzdGF0aXN0aWMgPSAiW3tjb25mLmxvd30sIHtjb25mLmhpZ2h9XSIsCiAgICAgICAgICAgICBjb2VmX21hcCA9IGNvZWZfbGlzdF9kZW5vbSwKICAgICAgICAgICAgIGFkZF9yb3dzID0gdHJlYXRtZW50X3Jvd3MsCiAgICAgICAgICAgICBnb2Zfb21pdCA9ICJFTFBEIiwKICAgICAgICAgICAgIGVzY2FwZSA9IEZBTFNFLAogICAgICAgICAgICAgbm90ZXMgPSBsaXN0KCJQb3N0ZXJpb3IgbWVhbnM7IDk1JSBjcmVkaWJsZSBpbnRlcnZhbHMgaW4gYnJhY2tldHMiKSkKYGBgCgoKIyMgT3V0Y29tZSBtb2RlbHMKCiMjIyBNb2RlbGluZyBjaG9pY2UKCk91ciBkZXBlbmRlbnQgdmFyaWFibGUgZm9yIHRoaXMgaHlwb3RoZXNpcyBpcyB0aGUgcGVyY2VudGFnZSBvZiBPREEgYWxsb2NhdGVkIGZvciBjb250ZW50aW91cyBwdXJwb3NlcywgYWdhaW4gbGVhZGVkIGJ5IG9uZSB5ZWFyLiBXZSBjbGFzc2lmeSBjb250ZW50aW91cyBhaWQgYXMgYW55IHByb2plY3QgZm9jdXNlZCBvbiBnb3Zlcm5tZW50IGFuZCBjaXZpbCBzb2NpZXR5IChEQUMgY29kZXMgMTUwIGFuZCAxNTEpIG9yIGNvbmZsaWN0IHByZXZlbnRpb24gYW5kIHJlc29sdXRpb24sIHBlYWNlIGFuZCBzZWN1cml0eSAoREFDIGNvZGUgMTUyKS4KCldvcmtpbmcgd2l0aCBwcm9wb3J0aW9uIGRhdGEsIGhvd2V2ZXIsIHBvc2VzIGludGVyZXN0aW5nIG1hdGhlbWF0aWNhbCBhbmQgbWV0aG9kb2xvZ2ljYWwgY2hhbGxlbmdlcywgc2luY2UgdGhlIHJhbmdlIG9mIHBvc3NpYmxlIG91dGNvbWVzIGlzIGxpbWl0ZWQgdG8gYSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDEuIFRyZWF0aW5nIHByb3BvcnRpb24gdmFyaWFibGVzIGluIGEgbWl4ZWQgbW9kZWwgaXMgdGVjaG5pY2FsbHkgcG9zc2libGUsIGJ1dCBpdCB5aWVsZHMgcHJlZGljdGlvbnMgdGhhdCBnbyBiZXlvbmQgdGhlIGFsbG93YWJsZSByYW5nZSBvZiB2YWx1ZXMgKDEuMTMsIC0wLjUsIGV0Yy4pLiBUcmVhdGluZyB0aGUgcHJvcG9ydGlvbiBhcyBhIGJpbm9taWFsIHZhcmlhYmxlIGlzIGFsc28gcG9zc2libGUgYW5kIGlzIGluZGVlZCBbb25lIG9mIHRoZSB3YXlzIHRvIHVzZSB0aGUgYGdsbSgpYCBmdW5jdGlvbl0oaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvOTExMTkwNC8xMjA4OTgpIGluIFIuIEhvd2V2ZXIsIHRoaXMgZW50YWlscyBjb25zaWRlcmluZyB0aGUgcHJvcG9ydGlvbiBhcyBhIHJhdGlvIG9mIHN1Y2Nlc3MgYW5kIGZhaWx1cmVzLiBJbiB0aGlzIGNhc2UsIHRyZWF0aW5nIGEgZG9sbGFyIG9mIGNvbnRlbnRpb3VzIGFpZCBhcyBhIHN1Y2Nlc3MgZmVlbHMgb2ZmLCBlc3BlY2lhbGx5IHNpbmNlIGFpZCBhbW91bnRzIGFyZW4ndCBpbmRlcGVuZGVudCBldmVudHPigJRpdCdzIG5vdCBsaWtlIGVhY2ggZG9sbGFyIG9mIGFpZCBnb2VzIHRocm91Z2ggYSBwcm9iYWJhbGlzdGljIHByb2Nlc3MgbGlrZSBhIGNvaW4gZmxpcC4gCgpBbm90aGVyIHNvbHV0aW9uIGlzIHRvIHVzZSBbYmV0YSByZWdyZXNzaW9uXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9wYWNrYWdlPWJldGFyZWcpLCB3aGljaCBbY29uc3RyYWlucyB0aGUgb3V0Y29tZSB2YXJpYWJsZSB0byB2YWx1ZXMgYmV0d2VlbiAwIGFuZCAxXShodHRwOi8vd3d3LnRoZWFuYWx5c2lzZmFjdG9yLmNvbS96ZXJvLW9uZS1pbmZsYXRlZC1iZXRhLW1vZGVscy1mb3ItcHJvcG9ydGlvbi1kYXRhLyksIGJ1dCB1bmZvcnR1bmF0ZWx5IGRvZXMgbm90IGFsbG93IGZvciB2YWx1ZXMgb2YgZXhhY3RseSAwIG9yIDEuIFplcm8tYW5kLW9uZSBpbmZsYXRlZCBiZXRhIHJlZ3Jlc3Npb24gbW9kZWxzLCBob3dldmVyLCBtYWtlIGFkanVzdG1lbnRzIGZvciB0aGlzIGFuZCBtb2RlbCB0aGUgcHJvYmFiaWxpdHkgb2YgYmVpbmcgMCwgYmVpbmcgMSwgYW5kIGJlaW5nIHNvbWV3aGVyZSBpbiB0aGUgbWlkZGxlIHVzaW5nIGRpZmZlcmVudCBwcm9jZXNzZXMuIE1hdHRpIFZ1b3JyZSBoYXMgW2FuIGV4Y2VsbGVudCBvdmVydmlldyBvZiBaT0lCIG1vZGVscyBoZXJlXShodHRwczovL3Z1b3JyZS5uZXRsaWZ5LmFwcC9wb3N0LzIwMTkvMDIvMTgvYW5hbHl6ZS1hbmFsb2ctc2NhbGUtcmF0aW5ncy13aXRoLXplcm8tb25lLWluZmxhdGVkLWJldGEtbW9kZWxzLykuCgpIb3dldmVyLCBhcyB3ZSBmb3VuZCB3aXRoIFtvdXIgaHVyZGxpbmcgZGlsZW1tYSB3aXRoIEh+MX5dKDAzX2gxLXRvdGFsLWFpZC5odG1sI01vZGVsaW5nX2Nob2ljZXMpLCB3aGlsZSBpdCdzIHBvc3NpYmxlIHRvIGZpdCBhIHplcm8taW5mbGF0ZWQgbW9kZWwgKG9yIGV2ZW4gemVyby1vbmUtaW5mbGF0ZWQgbW9kZWwpLCBpdCB3b3VsZCByZXF1aXJlIHNlcGFyYXRlIG1vZGVsIHNwZWNpZmljYXRpb25zIGZvciBkaWZmZXJlbnQgcGFydHMgKHRoZSB6ZXJvIHBhcnQsIHRoZSBvbmUgcGFydCwgYW5kIHRoZSBub24temVyby1vbmUgcGFydHMpLCBsZWF2aW5nIHVzIHdpdGggdGhyZWUgZGlmZmVyZW50IHBzZXVkby10cmVhdG1lbnQgZWZmZWN0cywgb25seSBvbmUgb2Ygd2hpY2ggKHRoZSBub24temVyby1vbmUgcGFydCkgd2VpZ2h0ZWQgd2l0aCB0aGUgSVBUVywgYW5kIHRodXMgYWRqdXN0ZWQgd2l0aCBkby1jYWxjdWx1cyBsb2dpYy4KCltPbmUgcmVjb21tZW5kYXRpb24gYnkgQmVuIEJvbGtlcl0oaHR0cHM6Ly9zdGF0LmV0aHouY2gvcGlwZXJtYWlsL3Itc2lnLW1peGVkLW1vZGVscy8yMDExcTEvMDE1NDIyLmh0bWwpLCB0aGUgbWFpbnRhaW5lciBvZiBbYGxtZTRgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9wYWNrYWdlPWxtZTQpLCBpcyB0byB1c2UgYSBsb2dpdCB0cmFuc2Zvcm1hdGlvbiBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGluIGBsbWVyKClgIG1vZGVscy4gVGhpcyBzZWVtcyB0byBiZSBbc3RhbmRhcmQgcHJhY3RpY2UgaW4gcG9saXRpY2FsIHNjaWVuY2UgcmVzZWFyY2hdKGh0dHBzOi8vYWNyb3dpbmdoZW4uY29tLzIwMTQvMDQvMjQvaW50ZXJwcmV0aW5nLWNvZWZmaWNpZW50cy1mcm9tLWEtbG9naXQtbGluZWFyLW1vZGVsLXdpdGgtYS1wcm9wb3J0aW9uYWwtZGVwZW5kZW50LXZhcmlhYmxlLyksIHRvby4gTG9naXQgdHJhbnNmb3JtYXRpb25zIHN0aWxsIGNhbid0IGhhbmRsZSB2YWx1ZXMgb2YgZXhhY3RseSAwIG9yIDEsIHRob3VnaCwgYnV0IGl0J3MgcG9zc2libGUgdG8gW3dpbnNvcml6ZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2luc29yaXppbmcpIHRob3NlIHZhbHVlcyBieSBhZGRpbmcgb3Igc3VidHJhY3RpbmcgMC4wMDEgdG8gdGhlIGV4dHJlbWVzLiBbU3RhdGEgaGFzIGEgZ3VpZGVdKGh0dHBzOi8vd3d3LnN0YXRhLmNvbS9zdXBwb3J0L2ZhcXMvc3RhdGlzdGljcy9sb2dpdC10cmFuc2Zvcm1hdGlvbi8pIGFib3V0IGhvdyB0byBkbyB0aGlzIHRvby4KCldlIHRodXMgdXNlIGxvZ2l0LWxpbmVhciBtb2RlbHMgb2YgdGhlIHJhdGlvIG9mIGNvbnRlbnRpb3VzIGFpZCB0byBub24tY29udGVudGlvdXMgYWlkLCBsaWtlIHRoaXM6IAoKJCRcbG9nIFxsZWZ0KCBcZnJhY3tcdGV4dHtDb250ZW50aW91cyBhaWR9fXtcdGV4dHtOb25jb250ZW50aW91cyBhaWR9fSBccmlnaHQpX3tpLCB0KzF9JCQKClRoYXQgbWVhbnMgdGhhdCB3ZSdyZSBjb21wYXJpbmcgdGhlIHJhdGlvIG9mIGNvbnRlbnRpb3VzIGFpZCB0byBub24tY29udGVudGlvdXMgYWlkIHJhdGhlciB0aGFuIHRoZSBkaXJlY3QgcGVyY2VudCBvZiBjb250ZW50aW91cyBhaWQsIGFuZCBpdCBtYWtlcyBmb3Igc29tZSBhY3JvYmF0aWMgaW50ZXJwcmV0YXRpb25zLCBidXQgYXQgbGVhc3QgdGhlIHJlc3VsdHMgYXJlIGludGVycHJldGFibGUuCgojIyMgSW50ZXJwcmV0aW5nIG91dGNvbWUgbW9kZWxzCgpUT0RPCgoKIyMjIFByaW9ycyBmb3Igb3V0Y29tZSBtb2RlbHMKCkhlcmUncyB0aGUgZnVsbCBzcGVjaWZpY2F0aW9uIGZvciB0aGUgbW9kZWxzIGFuZCBhbGwgcHJpb3JzOgoKJCQKXGJlZ2lue2FsaWduZWR9Clxsb2cgXGxlZnQoXGZyYWN7XHRleHR7Q29udGVudGlvdXMgYWlkfX17XHRleHR7Tm9uY29udGVudGlvdXMgYWlkfX0gXHJpZ2h0KV97aSwgdH0gJlxzaW0gXHRleHR7SVBUV31fe2ksIHQtMX0gXHRpbWVzIFxtYXRoY2Fse059IChcbXVfe2ksIHR9LCBcc2lnbWFfbSkgJiBcdGV4dHtbbGlrZWxpaG9vZF19XFwKXG11X3tpLCB0fSAmXHNpbSBcYWxwaGFfe1x0ZXh0e2NvdW50cnl9W2ldfSArIFxkZWx0YV97XHRleHR7eWVhcn1ba119ICsgXGJldGFcIFx0ZXh0e0xhd31fe2ksIHQtMX0gJiBcdGV4dHtbbWFyZ2luYWwgc3RydWN0dXJhbCBtb2RlbF19XFwKXGFscGhhX2ogJlxzaW0gXG1hdGhjYWx7Tn0gKFxiYXJ7XGFscGhhfSwgXHNpZ21hX3tcYWxwaGF9KSBcdGV4dHssIGZvciB9IGogXHRleHR7IGluIH0gMSAuLiBKICYgXHRleHR7W2NvdW50cnktc3BlY2lmaWMgaW50ZXJjZXB0c119IFxcClxkZWx0YV9qICZcc2ltIFxtYXRoY2Fse059ICgwLCBcc2lnbWFfe1xkZWx0YX0pIFx0ZXh0eywgZm9yIH0gaiBcdGV4dHsgaW4gfSAxIC4uIEogJiBcdGV4dHtbeWVhci1zcGVjaWZpYyBpbnRlcmNlcHRzXX0gXFwKXCBcXApcYmFye1xhbHBoYX0gJlxzaW0gXG1hdGhjYWx7Tn0gKDAsIDIwKSAmIFx0ZXh0e1twcmlvciBwb3B1bGF0aW9uIGludGVyY2VwdF19IFxcClxiZXRhICZcc2ltIFxtYXRoY2Fse059ICgwLCAzKSAmIFx0ZXh0e1twcmlvciBwb3B1bGF0aW9uIGVmZmVjdHNdfSBcXApcc2lnbWFfbSwgXHNpZ21hX3tcYWxwaGF9LCBcc2lnbWFfe1xkZWx0YX0gJlxzaW0gXG9wZXJhdG9ybmFtZXtDYXVjaHl9KDAsIDEpICYgXHRleHR7W3ByaW9yIHNkIGZvciBlcnJvcnNdfQpcZW5ke2FsaWduZWR9CiQkCgojIyMgQ2hlY2sgb3V0Y29tZSBtb2RlbHMKClRoZSB0cmFjZXBsb3RzIGFsbCBsb29rIGZpbmUuIEhlcmUncyBvbmUgYXMgYW4gZXhhbXBsZToKCmBgYHtyIGgyLWNoZWNrLW91dGNvbWV9Cm1fcHVycG9zZV9vdXRjb21lX3RvdGFsICU+JSAKICBwb3N0ZXJpb3Jfc2FtcGxlcyhhZGRfY2hhaW4gPSBUUlVFKSAlPiUgCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgicl9nd2NvZGUiKSwgLXN0YXJ0c193aXRoKCJ6XyIpLCAtc3RhcnRzX3dpdGgoInJfeWVhciIpLCAtbHBfXywgLWl0ZXIpICU+JSAKICBtY21jX3RyYWNlKCkgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKIyMjIFJlc3VsdHMgey50YWJzZXR9CgojIyMjIEFURSBwbG90cwoKYGBge3IgaDItcGxvdHMtZGVqdXJlLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01LCBmaWcuYXNwPU5VTEx9CmNvZWZzX25pY2UgPC0gdHJpYmJsZSgKICB+YC52YXJpYWJsZWAsIH52YXJfbmljZSwKICAiYl9iYXJyaWVyc190b3RhbCIsICJBZGRpdGlvbmFsIGxhdywgdCAtIDEiLAogICJiX2Fkdm9jYWN5IiwgIkFkZGl0aW9uYWwgYWR2b2NhY3kgbGF3LCB0IC0gMSIsCiAgImJfZW50cnkiLCAiQWRkaXRpb25hbCBlbnRyeSBsYXcsIHQgLSAxIiwKICAiYl9mdW5kaW5nIiwgIkFkZGl0aW9uYWwgZnVuZGluZyBsYXcsIHQgLSAxIiwKICAiYl92Mnhjc19jY3NpIiwgIkNvcmUgY2l2aWwgc29jaWV0eSBpbmRleCwgdCAtIDEiCikgJT4lIAogIG11dGF0ZSh2YXJfbmljZSA9IGZjdF9pbm9yZGVyKHZhcl9uaWNlKSkKCnBsb3RfdG90YWxfZGF0YSA8LSBnYXRoZXJfZHJhd3MobV9wdXJwb3NlX291dGNvbWVfdG90YWwsIGJfYmFycmllcnNfdG90YWwpCnBsb3RfYWR2b2NhY3lfZGF0YSA8LSBnYXRoZXJfZHJhd3MobV9wdXJwb3NlX291dGNvbWVfYWR2b2NhY3ksIGJfYWR2b2NhY3kpCnBsb3RfZW50cnlfZGF0YSA8LSBnYXRoZXJfZHJhd3MobV9wdXJwb3NlX291dGNvbWVfZW50cnksIGJfZW50cnkpCnBsb3RfZnVuZGluZ19kYXRhIDwtIGdhdGhlcl9kcmF3cyhtX3B1cnBvc2Vfb3V0Y29tZV9mdW5kaW5nLCBiX2Z1bmRpbmcpIAoKcGxvdF9wdXJwb3NlX2NvZWZzIDwtIGJpbmRfcm93cyhwbG90X3RvdGFsX2RhdGEsIHBsb3RfYWR2b2NhY3lfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2VudHJ5X2RhdGEsIHBsb3RfZnVuZGluZ19kYXRhKSAlPiUgCiAgbGVmdF9qb2luKGNvZWZzX25pY2UsIGJ5ID0gIi52YXJpYWJsZSIpICU+JSAKICBtdXRhdGUoLnZhbHVlID0gZXhwKC52YWx1ZSkpCgpyb3BlX3NkIDwtIGV4cChzZChkZl9wdXJwb3NlX2lwdHdfdG90YWwkcHJvcF9jb250ZW50aW91c19sb2dpdF9sZWFkMSkpCgpwbG90X3JvcGUgPC0gdGliYmxlKHhtaW4gPSAxICsgKC0wLjA1ICogcm9wZV9zZCksIAogICAgICAgICAgICAgICAgICAgIHhtYXggPSAxICsgKDAuMDUgKiByb3BlX3NkKSkKCmdncGxvdChwbG90X3B1cnBvc2VfY29lZnMsIGFlcyh4ID0gLnZhbHVlLCB5ID0gZmN0X3Jldih2YXJfbmljZSksIGZpbGwgPSB2YXJfbmljZSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxKSArCiAgZ2VvbV9yZWN0KGRhdGEgPSBwbG90X3JvcGUsIGFlcyh4bWluID0geG1pbiwgeG1heCA9IHhtYXgsIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mKSwKICAgICAgICAgICAgZmlsbCA9ICIjRkZEQzAwIiwgYWxwaGEgPSAwLjMsIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDEsIHkgPSAwLjY1LCAKICAgICAgICAgICBsYWJlbCA9ICJSZWdpb24gb2YgcHJhY3RpY2FsIGVxdWl2YWxlbmNlXG4owrEgMC4wNSDDlyBTRCB5KSIsCiAgICAgICAgICAgc2l6ZSA9IHB0cyg4KSkgKwogIHN0YXRfaGFsZmV5ZSgud2lkdGggPSBjKDAuOCwgMC45NSksIGFscGhhID0gMC44LCBwb2ludF9pbnRlcnZhbCA9ICJtZWRpYW5faGRpIikgKwogIGd1aWRlcyhmaWxsID0gRkFMU0UpICsKICBzY2FsZV95X2Rpc2NyZXRlKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjg1MUIiLCAiIzg1MTQ0YiIsICIjM0Q5OTcwIiwgIiMwMDFmM2YiKSkgKwogIGxhYnMoeCA9ICJQZXJjZW50IGNoYW5nZSBpbiByYXRpbyBvZiBjb250ZW50aW91cyBhaWQgaW4gZm9sbG93aW5nIHllYXIiLCB5ID0gTlVMTCwKICAgICAgIGNhcHRpb24gPSAiUG9pbnQgc2hvd3MgcG9zdGVyaW9yIG1lZGlhbjsgbGluZXMgc2hvdyA4MCUgYW5kIDk1JVxuY3JlZGlibGUgaGlnaGVzdC1kZW5zaXR5LWludGVydmFsIikgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKbG9sIHdoYXQgZXZlbgoKYGBge3IgaDItcGxvdHMtZGVmYWN0b30KcGxvdF9jY3NpX2NvZWZzIDwtIG1fcHVycG9zZV9vdXRjb21lX2Njc2kgJT4lIAogIG1hcF9kZnIofmdhdGhlcl9kcmF3cyguLCBiX3YyeGNzX2Njc2kpLCAuaWQgPSAibW9kZWwiKSAlPiUgCiAgbXV0YXRlKC52YWx1ZSA9IC52YWx1ZSAvIDEwKSAlPiUgCiAgbXV0YXRlKG1vZGVsID0gY29tbWEoYXMubnVtZXJpYyhzdHJfcmVtb3ZlKG1vZGVsLCAibW9kZWxfIikpKSkgJT4lIAogIG11dGF0ZShtb2RlbCA9IGZjdF9pbm9yZGVyKG1vZGVsKSkgJT4lIAogIGxlZnRfam9pbihjb2Vmc19uaWNlLCBieSA9ICIudmFyaWFibGUiKQoKZ2dwbG90KHBsb3RfY2NzaV9jb2VmcywgYWVzKHggPSAudmFsdWUsIHkgPSBmY3RfcmV2KG1vZGVsKSwgZmlsbCA9IG1vZGVsKSkgKwogIHN0YXRfaGFsZmV5ZSgud2lkdGggPSBjKDAuOCwgMC45NSksIHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9oZGkiLAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkgKwogIGd1aWRlcyhmaWxsID0gRkFMU0UpICsKICBsYWJzKHggPSAiQ29lZmZpY2llbnQiLCB5ID0gIklQVFcgdHJ1bmNhdGlvbiBwb2ludCIpICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyMgVGFibGVzCgpgYGB7ciB0YmwtaDItZGVqdXJlfQojIG1vZGVsX25hbWVzIDwtIHBhc3RlMCgiKCIsIDE6bGVuZ3RoKG1vZGVsc190YmxfaDJfb3V0Y29tZV9kZWp1cmUpLCAiKSIpCm1vZGVsX25hbWVzIDwtIDE6bGVuZ3RoKG1vZGVsc190YmxfaDJfb3V0Y29tZV9kZWp1cmUpCm5hbWVzKG1vZGVsc190YmxfaDJfb3V0Y29tZV9kZWp1cmUpIDwtIG1vZGVsX25hbWVzCgp0cmVhdG1lbnRfbmFtZXMgPC0gYygiVHJlYXRtZW50IiwgIlRvdGFsIGJhcnJpZXJzICh0KSIsICJCYXJyaWVycyB0byBhZHZvY2FjeSAodCkiLCAKICAgICAgICAgICAgICAgICAgICAgIkJhcnJpZXJzIHRvIGVudHJ5ICh0KSIsICJCYXJyaWVycyB0byBmdW5kaW5nICh0KSIpCnRyZWF0bWVudF9yb3dzIDwtIGFzLmRhdGEuZnJhbWUodCh0cmVhdG1lbnRfbmFtZXMpKQphdHRyKHRyZWF0bWVudF9yb3dzLCAicG9zaXRpb24iKSA8LSAxCgpjb2VmX2xpc3Rfb3V0Y29tZSA8LSBsaXN0KAogICJiX2JhcnJpZXJzX3RvdGFsIiA9ICJUcmVhdG1lbnQgKHQpIiwKICAiYl9hZHZvY2FjeSIgPSAiVHJlYXRtZW50ICh0KSIsCiAgImJfZW50cnkiID0gIlRyZWF0bWVudCAodCkiLAogICJiX2Z1bmRpbmciID0gIlRyZWF0bWVudCAodCkiLAogICJiX3YyeGNzX2Njc2kiID0gIkNvcmUgY2l2aWwgc29jaWV0eSBpbmRleCAodCkiLAogICJiX0ludGVyY2VwdCIgPSAiSW50ZXJjZXB0IiwKICAic2RfZ3djb2RlX19JbnRlcmNlcHQiID0gIs+DIGNvdW50cnkgaW50ZXJjZXB0cyIsCiAgInNkX3llYXJfX0ludGVyY2VwdCIgPSAiz4MgeWVhciBpbnRlcmNlcHRzIgopCgptb2RlbHN1bW1hcnkobW9kZWxzX3RibF9oMl9vdXRjb21lX2RlanVyZSwKICAgICAgICAgICAgIHN0YXRpc3RpYyA9ICJbe2NvbmYubG93fSwge2NvbmYuaGlnaH1dIiwKICAgICAgICAgICAgIGNvZWZfbWFwID0gY29lZl9saXN0X291dGNvbWUsCiAgICAgICAgICAgICBhZGRfcm93cyA9IHRyZWF0bWVudF9yb3dzLAogICAgICAgICAgICAgZ29mX29taXQgPSAiRUxQRCIsCiAgICAgICAgICAgICBlc2NhcGUgPSBGQUxTRSwKICAgICAgICAgICAgIG5vdGVzID0gbGlzdCgiUG9zdGVyaW9yIG1lYW5zOyA5NSUgY3JlZGlibGUgaW50ZXJ2YWxzIGluIGJyYWNrZXRzIikpICU+JSAKICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIk91dGNvbWU6IExvZ2l0IHByb3AgY29udGVudGlvdXMgKHQgKyAxKSIgPSA0KSkKYGBgCgpUT0RPOiBUaGlzIGlzIGEgbWVzcwoKYGBge3IgdGJsLWgyLWRlZmFjdG99CnRydW5jYXRpb25fdGhyZXNob2xkcyA8LSBuYW1lcyhtb2RlbHNfdGJsX2gyX291dGNvbWVfZGVmYWN0bykgJT4lIAogIHN0cl9leHRyYWN0KCJfXFxkKyIpICU+JSAKICBzdHJfcmVtb3ZlKCJfIikgJT4lIAogIGFzLm51bWVyaWMoKSAlPiUgCiAgY29tbWEoKQoKdHJ1bmNhdGlvbl9uYW1lcyA8LSBjKCJJUFRXIHRydW5jYXRpb24gdGhyZXNob2xkIiwgdHJ1bmNhdGlvbl90aHJlc2hvbGRzKQp0cnVuY2F0aW9uX3Jvd3MgPC0gYXMuZGF0YS5mcmFtZSh0KHRydW5jYXRpb25fbmFtZXMpKQphdHRyKHRydW5jYXRpb25fcm93cywgInBvc2l0aW9uIikgPC0gMQoKIyBtb2RlbF9uYW1lcyA8LSBwYXN0ZTAoIigiLCAxOmxlbmd0aChtb2RlbHNfdGJsX2gyX291dGNvbWVfZGVmYWN0byksICIpIikKbW9kZWxfbmFtZXMgPC0gMTpsZW5ndGgobW9kZWxzX3RibF9oMl9vdXRjb21lX2RlZmFjdG8pCm5hbWVzKG1vZGVsc190YmxfaDJfb3V0Y29tZV9kZWZhY3RvKSA8LSBtb2RlbF9uYW1lcwoKbW9kZWxzdW1tYXJ5KG1vZGVsc190YmxfaDJfb3V0Y29tZV9kZWZhY3RvLAogICAgICAgICAgICAgc3RhdGlzdGljID0gIlt7Y29uZi5sb3d9LCB7Y29uZi5oaWdofV0iLAogICAgICAgICAgICAgY29lZl9tYXAgPSBjb2VmX2xpc3Rfb3V0Y29tZSwKICAgICAgICAgICAgIGFkZF9yb3dzID0gdHJ1bmNhdGlvbl9yb3dzLAogICAgICAgICAgICAgZ29mX29taXQgPSAiRUxQRCIsCiAgICAgICAgICAgICBlc2NhcGUgPSBGQUxTRSwKICAgICAgICAgICAgIG5vdGVzID0gbGlzdCgiUG9zdGVyaW9yIG1lYW5zOyA5NSUgY3JlZGlibGUgaW50ZXJ2YWxzIGluIGJyYWNrZXRzIikpICU+JSAKICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIk91dGNvbWU6IE91dGNvbWU6IExvZ2l0IHByb3AgY29udGVudGlvdXMgKHQgKyAxKSIgPSA0KSkKYGBgCgoKIyMjIyBNYXJnaW5hbCBlZmZlY3RzCgpgYGB7ciBoMi1jb25kaXRpb25hbC1lZmZlY3RzfQojIGJybXM6OmNvbmRpdGlvbmFsX2VmZmVjdHMoKSBjYW4gY3JlYXRlIHNwYWdoZXR0aSBwbG90cyAoc2luZ2xlIGxpbmVzIHBlcgojIHNhbXBsZSksIGJ1dCBpdCBzdG9yZXMgdGhlbSBpbiBhbiBhdHRyaWJ1dGUgc2xvdCBuYW1lZCAic3BhZ2hldHRpIiwgd2hpY2ggaXMKIyB0cmlja3kgdG8gZXh0cmFjdCBkYXRhIGZyb20uIFRoaXMgcHVsbHMgdGhlIGRhdGEgZnJhbWUgZnJvbSB0aGUgYXR0cmlidXRlCm1ha2Vfc3BhZ2hldHRpIDwtIGZ1bmN0aW9uKG1vZGVsKSB7CiAgcmF3X2VmZmVjdHMgPC0gY29uZGl0aW9uYWxfZWZmZWN0cyhtb2RlbCwgc3BhZ2hldHRpID0gVFJVRSwgbnNhbXBsZXMgPSAxMDApW1sxXV0KICBzcGFnaGV0dGlfZGF0YSA8LSBhdHRyKHJhd19lZmZlY3RzLCAic3BhZ2hldHRpIikKICByZXR1cm4oc3BhZ2hldHRpX2RhdGEpCn0KCmludl9sb2dpdCA8LSBmdW5jdGlvbihmLCBhKSB7CiAgYSA8LSAoMSAtIDIgKiBhKQogIChhICogKDEgKyBleHAoZikpICsgKGV4cChmKSAtIDEpKSAvICgyICogYSAqICgxICsgZXhwKGYpKSkKfQoKbWFrZV9zcGFnaGV0dGkobV9wdXJwb3NlX291dGNvbWVfdG90YWwpICU+JSAKICBtdXRhdGUoZXN0aW1hdGVfXyA9IGludl9sb2dpdChlc3RpbWF0ZV9fLCBhID0gMC4wMDEpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZWZmZWN0MV9fLCB5ID0gZXN0aW1hdGVfXywgZ3JvdXAgPSBzYW1wbGVfXykpICsKICBnZW9tX2xpbmUoc2l6ZSA9IDAuMjUsIGNvbG9yID0gIiNGRjQxMzYiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDA6OSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpICsKICBsYWJzKHggPSAiQ291bnQgb2YgdG90YWwgbGVnYWwgYmFycmllcnMiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgcHJvcG9ydGlvbiBvZlxuY29udGVudGlvdXMgYWlkIGluIGZvbGxvd2luZyB5ZWFyIikgKwogIHRoZW1lX2Rvbm9ycygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpCgptYWtlX3NwYWdoZXR0aShtX3B1cnBvc2Vfb3V0Y29tZV9hZHZvY2FjeSkgJT4lIAogIG11dGF0ZShlc3RpbWF0ZV9fID0gaW52X2xvZ2l0KGVzdGltYXRlX18sIGEgPSAwLjAwMSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBlZmZlY3QxX18sIHkgPSBlc3RpbWF0ZV9fLCBncm91cCA9IHNhbXBsZV9fKSkgKwogIGdlb21fbGluZShzaXplID0gMC4yNSwgY29sb3IgPSAiI0ZGNDEzNiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMDoyKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBndWlkZXMoY29sb3IgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJDb3VudCBvZiBiYXJyaWVycyB0byBhZHZvY2FjeSIsCiAgICAgICB5ID0gIlByZWRpY3RlZCBwcm9wb3J0aW9uIG9mXG5jb250ZW50aW91cyBhaWQgaW4gZm9sbG93aW5nIHllYXIiKSArCiAgdGhlbWVfZG9ub3JzKCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCm1ha2Vfc3BhZ2hldHRpKG1fcHVycG9zZV9vdXRjb21lX2VudHJ5KSAlPiUgCiAgbXV0YXRlKGVzdGltYXRlX18gPSBpbnZfbG9naXQoZXN0aW1hdGVfXywgYSA9IDAuMDAxKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGVmZmVjdDFfXywgeSA9IGVzdGltYXRlX18sIGdyb3VwID0gc2FtcGxlX18pKSArCiAgZ2VvbV9saW5lKHNpemUgPSAwLjI1LCBjb2xvciA9ICIjRkY0MTM2IikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAwOjMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGd1aWRlcyhjb2xvciA9IEZBTFNFKSArCiAgbGFicyh4ID0gIkNvdW50IG9mIGJhcnJpZXJzIHRvIGVudHJ5IiwKICAgICAgIHkgPSAiUHJlZGljdGVkIHByb3BvcnRpb24gb2ZcbmNvbnRlbnRpb3VzIGFpZCBpbiBmb2xsb3dpbmcgeWVhciIpICsKICB0aGVtZV9kb25vcnMoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKQoKbWFrZV9zcGFnaGV0dGkobV9wdXJwb3NlX291dGNvbWVfZnVuZGluZykgJT4lIAogIG11dGF0ZShlc3RpbWF0ZV9fID0gaW52X2xvZ2l0KGVzdGltYXRlX18sIGEgPSAwLjAwMSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBlZmZlY3QxX18sIHkgPSBlc3RpbWF0ZV9fLCBncm91cCA9IHNhbXBsZV9fKSkgKwogIGdlb21fbGluZShzaXplID0gMC4yNSwgY29sb3IgPSAiI0ZGNDEzNiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMDo1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBndWlkZXMoY29sb3IgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJDb3VudCBvZiBiYXJyaWVycyB0byBmdW5kaW5nIiwKICAgICAgIHkgPSAiUHJlZGljdGVkIHByb3BvcnRpb24gb2ZcbmNvbnRlbnRpb3VzIGFpZCBpbiBmb2xsb3dpbmcgeWVhciIpICsKICB0aGVtZV9kb25vcnMoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAK