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_oda_treatment_total, m_oda_treatment_advocacy, 
             m_oda_treatment_entry, m_oda_treatment_funding, 
             m_oda_treatment_ccsi))
  
  # IPTW data
  tar_load(c(df_oda_iptw_total, df_oda_iptw_advocacy, 
             df_oda_iptw_entry, df_oda_iptw_funding,
             df_oda_iptw_ccsi))
  
  # Outcome models
  tar_load(c(m_oda_outcome_total, m_oda_outcome_advocacy, 
             m_oda_outcome_entry, m_oda_outcome_funding,
             m_oda_outcome_ccsi))
  
  # Results tables
  tar_load(c(models_tbl_h1_treatment_num, models_tbl_h1_treatment_denom))
  tar_load(c(models_tbl_h1_outcome_dejure, models_tbl_h1_outcome_defacto))
})

Weight models

  • Numerator is treatment ~ lagged treatment + treatment history + non-varying confounders
  • Denominator is treatment ~ lagged treatment + treatment history + 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 a couple of the numerator and denominator models for convergence and mixing and fit. They’re all pretty much the same

Numerator

pp_check(m_oda_treatment_total$model_num, type = "dens_overlay", nsamples = 10) +
  theme_donors()

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

Denominator

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

m_oda_treatment_total$model_denom %>% 
  posterior_samples(add_chain = TRUE) %>% 
  select(-starts_with("r_gwcode"), -starts_with("z_"), 
         -starts_with("r_region"), -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. When they’re big, it’s a good idea to truncate them at some level. The truncation threshold matters substantially—as seen below, the ATE when using V-Dem’s core civil society index as the treatment varies substantially at different truncation thresholds.

Total ODA

Sweet.

summary(df_oda_iptw_total$iptw)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
##  0.005716  0.854546  0.968154  1.060549  1.057472 10.769115
df_oda_iptw_total %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 0.5, boundary = 0) +
  theme_donors()

Advocacy

Lovely.

summary(df_oda_iptw_advocacy$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.1466  0.9180  0.9783  1.0159  1.0301  6.8357
df_oda_iptw_advocacy %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 1, boundary = 0) +
  theme_donors()

Entry

Fantastic.

summary(df_oda_iptw_entry$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.09036 0.91675 0.99041 1.01992 1.05431 4.22770
df_oda_iptw_entry %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 0.5, boundary = 0) +
  theme_donors()

Funding

Slightly concerning maybe (though the median is great).

summary(df_oda_iptw_funding$iptw)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
##  0.003089  0.868638  0.958812  1.089450  1.011633 27.053270
df_oda_iptw_funding %>% 
  ggplot(aes(x = iptw)) +
  geom_histogram(binwidth = 5, boundary = 0) +
  theme_donors()

Core civil society index

lol these blow up. Check out the maximum:

summary(df_oda_iptw_ccsi$iptw)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 0.000e+00 0.000e+00 0.000e+00 9.932e+09 1.000e+00 3.531e+12

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

plot_iptw_ccsi <- bind_rows(
  df_oda_iptw_ccsi %>% mutate(threshold = 100, iptw = ifelse(iptw > 100, 100, iptw)),
  df_oda_iptw_ccsi %>% mutate(threshold = 500, iptw = ifelse(iptw > 500, 500, iptw)),
  df_oda_iptw_ccsi %>% mutate(threshold = 1000, iptw = ifelse(iptw > 1000, 1000, iptw)),
  df_oda_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_h1_treatment_num), ")")
model_names <- 1:length(models_tbl_h1_treatment_num)
names(models_tbl_h1_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_h1_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.818
[0.977, 0.996] [0.983, 1.000] [0.957, 0.981] [0.980, 0.999] [0.799, 0.837]
Intercept 0.087 0.015 0.051 0.030 0.119
[0.065, 0.108] [0.010, 0.020] [0.039, 0.064] [0.022, 0.039] [0.105, 0.134]
Num.Obs. 3153 3153 3153 3153 3272
R2 0.941 0.949 0.929 0.940 0.958
R2 Marg. 0.941 0.949 0.928 0.940 0.904
LOOIC 4142.4 -4303.9 -13.2 -380.0 -9360.3
LOOIC s.e. 547.6 633.6 458.6 702.5 341.2
WAIC 4146.6 -4301.5 -12.8 -364.6 -9357.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_h1_treatment_denom), ")")
model_names <- 1:length(models_tbl_h1_treatment_denom)
names(models_tbl_h1_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_h1_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.975 0.987 0.965 0.977 0.489
[0.965, 0.985] [0.977, 0.995] [0.953, 0.975] [0.967, 0.988] [0.463, 0.514]
Polyarchy -0.095 0.014 -0.079 -0.040 0.003
[-0.258, 0.070] [-0.032, 0.058] [-0.171, 0.011] [-0.124, 0.039] [-0.027, 0.031]
Corruption index -0.073 -0.019 -0.028 -0.030 -0.022
[-0.246, 0.089] [-0.062, 0.028] [-0.118, 0.056] [-0.112, 0.058] [-0.056, 0.013]
Rule of law index -0.119 -0.048 -0.033 -0.036 0.031
[-0.289, 0.092] [-0.100, 0.001] [-0.132, 0.067] [-0.129, 0.064] [-0.009, 0.071]
Civil liberties index -0.367 -0.109 -0.162 -0.059 0.894
[-0.860, 0.119] [-0.235, 0.027] [-0.444, 0.092] [-0.325, 0.160] [0.818, 0.975]
Physical violence index 0.231 0.062 0.111 0.048 -0.231
[0.004, 0.448] [0.004, 0.118] [-0.010, 0.227] [-0.059, 0.157] [-0.266, -0.193]
Private civil liberties index 0.083 0.045 0.067 -0.039 -0.195
[-0.182, 0.344] [-0.025, 0.113] [-0.073, 0.209] [-0.169, 0.089] [-0.237, -0.152]
Log GDP/capita -0.015 -0.003 -0.005 -0.008 -0.008
[-0.036, 0.006] [-0.008, 0.003] [-0.016, 0.006] [-0.018, 0.003] [-0.014, -0.003]
Percent of GDP from trade -0.006 0.005 -0.008 -0.002 -0.006
[-0.045, 0.036] [-0.006, 0.015] [-0.031, 0.012] [-0.023, 0.018] [-0.014, 0.002]
Educational equality index -0.009 -0.001 0.000 -0.008 -0.007
[-0.036, 0.019] [-0.008, 0.006] [-0.015, 0.014] [-0.022, 0.005] [-0.012, -0.001]
Health equality index 0.013 0.000 -0.001 0.013 0.000
[-0.017, 0.045] [-0.008, 0.008] [-0.017, 0.015] [-0.002, 0.029] [-0.007, 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.005 0.004 0.001 0.001 0.008
[-0.037, 0.046] [-0.007, 0.015] [-0.022, 0.022] [-0.019, 0.022] [0.002, 0.014]
Count of natural disasters 0.006 0.001 0.002 0.002 0.000
[0.000, 0.011] [0.000, 0.003] [-0.001, 0.004] [0.000, 0.005] [-0.001, 0.001]
Intercept 0.394 0.070 0.138 0.185 0.084
[0.142, 0.647] [0.005, 0.134] [-0.002, 0.266] [0.062, 0.312] [0.022, 0.143]
Num.Obs. 3153 3153 3153 3153 3272
R2 0.942 0.949 0.929 0.941 0.970
R2 Marg. 0.942 0.949 0.928 0.941 0.946
LOOIC 4119.2 -4295.7 -16.3 -401.4 -10374.1
LOOIC s.e. 534.1 630.3 454.6 683.5 266.6
WAIC 4124.7 -4284.2 -17.2 -388.1 -10370.8
RMSE 1.33 0.34 0.66 0.60 0.33
Posterior means; 95% credible intervals in brackets

Outcome models

Modeling choices

We use logged ODA, leaded by one year, as our main outcome variable throughout this analysis. We toyed with different parameterizations of ODA because of its exponential-ish distribution. For instance, instead of logging the outcome, some papers use an \(\operatorname{arcisnh}\) transformation, but then interpretation gets tricky. It’s possible to use Poisson/negative binomial/Gamma models with dollar outcomes that are sometimes zero, but these kinds of ensemble models get unwieldy.

A simpler version of the Poisson-Gamma combination is to use a hurdle model, of which there are four types currently in brms. One of these is hurdle_lognormal(), which log-transforms the outcome variable automatically. It’s possible to create custom families like hurdle_gaussian(), but this is super hard to do. I have an implementation partially completed here, but I can’t get it to actually create posterior predictions. Ugh.

So we could fit a hurdled lognormal model, which uses a logit model to predict 0/not 0, then uses a lognormal distribution to model the rest of the data. However, this requires specifying two different models with different data-generating processes and different treatment effects, which becomes immensely unwieldy when dealing with marginal structural models and IPTWs. To simplify things, we initially tried using an intercept-only model (i.e. outcome ~ 1) for the 0/not 0 logit model and then outcome | weights(iptw) ~ treatment for the rest of the data and this worked, and the posterior predictive graphs looked phenomenal. BUT conceptually this was doing weird stuff. We were essentially ignoring all the 0s and not incorporating any of the IPTWs (or even the treatment variable!) into the models. Mathematically, this felt equivalent to just doing filter(treatment != 0).

So in the end, we go back to the standard workhorse of just logging the outcome.

Interpreting outcome models

tidy(m_oda_outcome_funding) %>%
  mutate(estimate_exp = exp(estimate)) %>% 
  filter(term == "funding") %>% 
  select(term, estimate, estimate_exp)
## # A tibble: 1 x 3
##   term    estimate estimate_exp
##   <chr>      <dbl>        <dbl>
## 1 funding   -0.274        0.760

Because our outcome is logged, the coefficients (and the ultimate ATE) represents a percent change in the outcome. The exponentiated coefficients represent percent changes for each unit increase in X. For instance, in the funding model, \(\beta_1\) is -0.274, while \(e^{\beta_1}\) is 0.76. Like exponentiated logistic regression coefficients, everything here is centered around 1, meaning that there’s a -24.0% decrease in aid for every legal barrier added. This can be also be seen as a multiplier effect. If aid is $50 million, it changes to $38,013,337 (50,000,000 × 0.76027).

Interpreting this coefficient gets a little trickier because we used a multilevel model with population and group effects. This \(\beta_1\) here is the average effect for a median cluster at each level of X. See this incredible resource for a ton more details about different ways of piecing together population- and group-level effects in a lognormal model.

Priors for outcome models

There are a ton of moving parts in these outcome models. Here’s the full specification for the models and all priors:

\[ \begin{aligned} \log (\text{Aid}_{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 good. Here’s one:

m_oda_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_oda_outcome_total, b_barriers_total)
plot_advocacy_data <- gather_draws(m_oda_outcome_advocacy, b_advocacy)
plot_entry_data <- gather_draws(m_oda_outcome_entry, b_entry)
plot_funding_data <- gather_draws(m_oda_outcome_funding, b_funding) 

plot_total_aid_coefs <- bind_rows(plot_total_data, plot_advocacy_data,
                                  plot_entry_data, plot_funding_data) %>% 
  left_join(coefs_nice, by = ".variable")

rope_sd <- sd(df_oda_iptw_total$total_oda_log_lead1)

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

ggplot(plot_total_aid_coefs, aes(x = .value, y = fct_rev(var_nice), fill = var_nice)) +
  geom_vline(xintercept = 0) +
  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 = 0, y = 0.65, 
           label = "Region of practical equivalence\n(± 0.05 × SD log foreign aid)",
           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 = "Change in log foreign aid in following year", y = NULL,
       caption = "Point shows posterior median; lines show 80% and 95%\ncredible highest-density-interval") +
  theme_donors()

plot_ccsi_coefs <- m_oda_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_h1_outcome_dejure), ")")
model_names <- 1:length(models_tbl_h1_outcome_dejure)
names(models_tbl_h1_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_h1_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: ODA (t + 1)" = 4))
Outcome: ODA (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.047 -0.828 0.367 -0.274
[-0.166, 0.071] [-1.328, -0.383] [0.148, 0.574] [-0.535, -0.008]
Intercept 18.035 18.180 17.632 17.983
[16.166, 19.811] [16.422, 19.856] [15.764, 19.328] [16.286, 19.662]
σ country intercepts 3.689 3.743 3.671 3.658
[3.258, 4.145] [3.312, 4.213] [3.251, 4.134] [3.238, 4.112]
σ year intercepts 3.931 3.881 3.959 3.893
[2.951, 5.235] [2.885, 5.147] [2.962, 5.288] [2.866, 5.192]
Num.Obs. 3293 3293 3293 3293
R2 0.740 0.743 0.738 0.738
R2 Marg. 0.000 0.005 0.003 0.002
LOOIC 17588.4 17380.8 17023.7 18112.3
LOOIC s.e. 292.6 235.9 229.1 336.5
WAIC 17587.5 17379.5 17022.9 18111.4
Posterior means; 95% credible intervals in brackets
truncation_thresholds <- names(models_tbl_h1_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_h1_outcome_defacto), ")")
model_names <- 1:length(models_tbl_h1_outcome_defacto)
names(models_tbl_h1_outcome_defacto) <- model_names

modelsummary(models_tbl_h1_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: ODA (t + 1)" = 4))
Outcome: ODA (t + 1)
1 2 3 4
IPTW truncation threshold 100 500 1,000 5,000
Core civil society index (t) -0.572 -1.483 -1.475 -0.344
[-0.770, -0.373] [-1.596, -1.371] [-1.569, -1.375] [-0.427, -0.260]
Intercept 18.773 19.444 19.379 18.567
[16.813, 20.508] [17.527, 21.340] [17.402, 21.331] [16.549, 20.559]
σ country intercepts 3.633 3.691 3.686 3.645
[3.228, 4.103] [3.235, 4.160] [3.256, 4.132] [3.226, 4.106]
σ year intercepts 4.230 4.323 4.398 4.486
[3.132, 5.606] [3.196, 5.772] [3.239, 5.802] [3.299, 5.938]
Num.Obs. 3298 3298 3298 3298
R2 0.688 0.688 0.689 0.693
R2 Marg. 0.001 0.004 0.004 0.000
LOOIC 87427.2 294827.6 497278.6 1627189.8
LOOIC s.e. 13004.5 52636.6 88637.7 289710.0
WAIC 95294.4 343009.5 588537.4 1973938.8
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)
}

make_spaghetti(m_oda_outcome_total) %>% 
  mutate(estimate__ = exp(estimate__)) %>% 
  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 = dollar, trans = pseudo_log_trans()) +
  guides(color = FALSE) +
  labs(x = "Count of total legal barriers",
       y = "Predicted total ODA in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

make_spaghetti(m_oda_outcome_advocacy) %>% 
  mutate(estimate__ = exp(estimate__)) %>%
  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 = dollar, trans = pseudo_log_trans()) +
  guides(color = FALSE) +
  labs(x = "Count of barriers to advocacy",
       y = "Predicted total ODA in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

make_spaghetti(m_oda_outcome_entry) %>% 
  mutate(estimate__ = exp(estimate__)) %>% 
  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 = dollar, trans = pseudo_log_trans()) +
  guides(color = FALSE) +
  labs(x = "Count of barriers to entry",
       y = "Predicted total ODA in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

make_spaghetti(m_oda_outcome_funding) %>% 
  mutate(estimate__ = exp(estimate__)) %>% 
  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 = dollar, trans = pseudo_log_trans()) +
  guides(color = FALSE) +
  labs(x = "Count of barriers to funding",
       y = "Predicted total ODA in following year") +
  theme_donors() +
  theme(panel.grid.major.x = element_blank())

LS0tCnRpdGxlOiAiSH4xfjogRWZmZWN0IG9mIGFudGktTkdPIGNyYWNrZG93biBvbiB0b3RhbCBPREEiCmF1dGhvcjogIlN1cGFybmEgQ2hhdWRocnkgYW5kIEFuZHJldyBIZWlzcyIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUYnKWAiCmJpYmxpb2dyYXBoeTogImByIGhlcmU6OmhlcmUoJ21hbnVzY3JpcHQnLCAnYmlibGlvZ3JhcGh5LmJpYicpYCIKY3NsOiAiYHIgaGVyZTo6aGVyZSgnbWFudXNjcmlwdCcsICdwYW5kb2MnLCAnY3NsJywgJ2NoaWNhZ28tYXV0aG9yLWRhdGUuY3NsJylgIgpsaW5rLWNpdGF0aW9uczogdHJ1ZQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5yZXRpbmEgPSAzLAogICAgICAgICAgICAgICAgICAgICAgdGlkeS5vcHRzID0gbGlzdCh3aWR0aC5jdXRvZmYgPSAxMjApLCAgIyBGb3IgY29kZQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyh3aWR0aCA9IDkwKSwgICMgRm9yIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFzcCA9IDAuNjE4LCBmaWcud2lkdGggPSA3LCAKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAiODUlIikKCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKQpgYGAKCmBgYHtyIGxvYWQtbGlicmFyaWVzLWRhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRhcmdldHMpCmxpYnJhcnkoYnJtcykKbGlicmFyeSh0aWR5YmF5ZXMpCmxpYnJhcnkoYmF5ZXNwbG90KQpsaWJyYXJ5KGZpeGVzdCkKbGlicmFyeShicm9vbSkKbGlicmFyeShicm9vbS5taXhlZCkKbGlicmFyeShtb2RlbHN1bW1hcnkpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShsYXRleDJleHApCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShoZXJlKQoKY29sb3Jfc2NoZW1lX3NldCgidmlyaWRpc0MiKQoKbXlfc2VlZCA8LSAxMjM0CnNldC5zZWVkKG15X3NlZWQpCgp3aXRocjo6d2l0aF9kaXIoaGVyZTo6aGVyZSgpLCB7CiAgc291cmNlKHRhcl9yZWFkKHBsb3RfZnVucykpCiAgc291cmNlKHRhcl9yZWFkKG1pc2NfZnVucykpCiAgCiAgIyBEYXRhCiAgZGZfY291bnRyeV9haWQgPC0gdGFyX3JlYWQoY291bnRyeV9haWRfZmluYWwpCiAgZGZfY291bnRyeV9haWRfbGF3cyA8LSBmaWx0ZXIoZGZfY291bnRyeV9haWQsIGxhd3MpCiAgCiAgIyBUcmVhdG1lbnQgbW9kZWxzCiAgdGFyX2xvYWQoYyhtX29kYV90cmVhdG1lbnRfdG90YWwsIG1fb2RhX3RyZWF0bWVudF9hZHZvY2FjeSwgCiAgICAgICAgICAgICBtX29kYV90cmVhdG1lbnRfZW50cnksIG1fb2RhX3RyZWF0bWVudF9mdW5kaW5nLCAKICAgICAgICAgICAgIG1fb2RhX3RyZWF0bWVudF9jY3NpKSkKICAKICAjIElQVFcgZGF0YQogIHRhcl9sb2FkKGMoZGZfb2RhX2lwdHdfdG90YWwsIGRmX29kYV9pcHR3X2Fkdm9jYWN5LCAKICAgICAgICAgICAgIGRmX29kYV9pcHR3X2VudHJ5LCBkZl9vZGFfaXB0d19mdW5kaW5nLAogICAgICAgICAgICAgZGZfb2RhX2lwdHdfY2NzaSkpCiAgCiAgIyBPdXRjb21lIG1vZGVscwogIHRhcl9sb2FkKGMobV9vZGFfb3V0Y29tZV90b3RhbCwgbV9vZGFfb3V0Y29tZV9hZHZvY2FjeSwgCiAgICAgICAgICAgICBtX29kYV9vdXRjb21lX2VudHJ5LCBtX29kYV9vdXRjb21lX2Z1bmRpbmcsCiAgICAgICAgICAgICBtX29kYV9vdXRjb21lX2Njc2kpKQogIAogICMgUmVzdWx0cyB0YWJsZXMKICB0YXJfbG9hZChjKG1vZGVsc190YmxfaDFfdHJlYXRtZW50X251bSwgbW9kZWxzX3RibF9oMV90cmVhdG1lbnRfZGVub20pKQogIHRhcl9sb2FkKGMobW9kZWxzX3RibF9oMV9vdXRjb21lX2RlanVyZSwgbW9kZWxzX3RibF9oMV9vdXRjb21lX2RlZmFjdG8pKQp9KQpgYGAKCiMjIFdlaWdodCBtb2RlbHMKCi0gTnVtZXJhdG9yIGlzIHRyZWF0bWVudCB+IGxhZ2dlZCB0cmVhdG1lbnQgKyB0cmVhdG1lbnQgaGlzdG9yeSArIG5vbi12YXJ5aW5nIGNvbmZvdW5kZXJzCi0gRGVub21pbmF0b3IgaXMgdHJlYXRtZW50IH4gbGFnZ2VkIHRyZWF0bWVudCArIHRyZWF0bWVudCBoaXN0b3J5ICsgbGFnZ2VkIG91dGNvbWUgKyB0aW1lLXZhcnlpbmcgY29uZm91bmRlcnMgKyBub24tdmFyeWluZyBjb25mb3VuZGVycwoKJCQKc3cgPSBccHJvZF50X3t0ID0gMX0gXGZyYWN7XHBoaShUX3tpdH0gfCBUX3tpLCB0LTF9LCBDX2kpfXtccGhpKFRfe2l0fSB8IFRfe2ksIHQtMX0sIERfe2ksIHQtMX0sIENfaSl9CiQkCgojIyMgUHJpb3JzIGZvciB3ZWlnaHQgbW9kZWxzCgpXZSB1c2UgW2dlbmVyaWMgd2Vha2x5IGluZm9ybWF0aXZlIHByaW9yc10oaHR0cHM6Ly9tYy1zdGFuLm9yZy91c2Vycy9kb2N1bWVudGF0aW9uL2Nhc2Utc3R1ZGllcy93ZWFrbHlfaW5mb3JtYXRpdmVfc2hhcGVzLmh0bWwpIGZvciBvdXIgbW9kZWwgcGFyYW1ldGVyczoKCi0gSW50ZXJjZXB0OiAkXG1hdGhjYWx7Tn0gKDAsIDEwKSQKLSBDb2VmZmljaWVudHM6ICRcbWF0aGNhbHtOfSAoMCwgMi41KSQKLSBTaWdtYTogJFxvcGVyYXRvcm5hbWV7Q2F1Y2h5fSAoMCwgMSkkCgpgYGB7ciBwbG90LXdlaWdodC1wcmlvcnMsIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTYsIGZpZy5hc3A9TlVMTH0KcHJpX2ludCA8LSBnZ3Bsb3QoKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IDAsIHNkID0gMTApLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSBUZVgoIlxcdGV4dGJme0ludGVyY2VwdCAozrJfMCl9IikpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDAsIHkgPSAwLjAxLCBsYWJlbCA9ICJOKDAsIDEwKSIsIHNpemUgPSBwdHMoOSkpICsKICB4bGltKC00MCwgNDApICsKICB0aGVtZV9kb25vcnMocHJpb3IgPSBUUlVFKQoKcHJpX2NvZWYgPC0gZ2dwbG90KCkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sIGFyZ3MgPSBsaXN0KG1lYW4gPSAwLCBzZCA9IDIuNSksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoeCA9IFRlWCgiXFx0ZXh0YmZ7Q29lZmZpY2llbnRzICjOsl94KX0iKSkgKwogIGFubm90YXRlKGdlb20gPSAibGFiZWwiLCB4ID0gMCwgeSA9IDAuMDQsIGxhYmVsID0gIk4oMCwgMykiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgtMTAsIDEwKSArCiAgdGhlbWVfZG9ub3JzKHByaW9yID0gVFJVRSkKCnByaV9zaWdtYSA8LSBnZ3Bsb3QoKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkY2F1Y2h5LCBhcmdzID0gbGlzdChsb2NhdGlvbiA9IDAsIHNjYWxlID0gMSksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoeCA9ICLPgyIpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDUsIHkgPSAwLjA4LCBsYWJlbCA9ICJDYXVjaHkoMCwgMSkiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgwLCAxMCkgKwogIHRoZW1lX2Rvbm9ycyhwcmlvciA9IFRSVUUpCgoocHJpX2ludCArIHByaV9jb2VmICsgcHJpX3NpZ21hKQpgYGAKCiMjIyBDaGVjayB3ZWlnaHQgbW9kZWxzIHsudGFic2V0fQoKV2UgY2hlY2sgYSBjb3VwbGUgb2YgdGhlIG51bWVyYXRvciBhbmQgZGVub21pbmF0b3IgbW9kZWxzIGZvciBjb252ZXJnZW5jZSBhbmQgbWl4aW5nIGFuZCBmaXQuIFRoZXkncmUgYWxsIHByZXR0eSBtdWNoIHRoZSBzYW1lCgojIyMjIE51bWVyYXRvcgoKYGBge3IgaDEtY2hlY2stbnVtZXJhdG9yfQpwcF9jaGVjayhtX29kYV90cmVhdG1lbnRfdG90YWwkbW9kZWxfbnVtLCB0eXBlID0gImRlbnNfb3ZlcmxheSIsIG5zYW1wbGVzID0gMTApICsKICB0aGVtZV9kb25vcnMoKQoKbV9vZGFfdHJlYXRtZW50X3RvdGFsJG1vZGVsX251bSAlPiUgCiAgcG9zdGVyaW9yX3NhbXBsZXMoYWRkX2NoYWluID0gVFJVRSkgJT4lIAogIHNlbGVjdCgtc3RhcnRzX3dpdGgoInJfZ3djb2RlIiksIC1zdGFydHNfd2l0aCgiel8iKSwgCiAgICAgICAgIC1zdGFydHNfd2l0aCgicl9yZWdpb24iKSwgLWxwX18sIC1pdGVyKSAlPiUgCiAgbWNtY190cmFjZSgpICsKICB0aGVtZV9kb25vcnMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKYGBgCgojIyMjIERlbm9taW5hdG9yCgpgYGB7ciBoMS1jaGVjay1kZW5vbWluYXRvcn0KcHBfY2hlY2sobV9vZGFfdHJlYXRtZW50X3RvdGFsJG1vZGVsX2Rlbm9tLCB0eXBlID0gImRlbnNfb3ZlcmxheSIsIG5zYW1wbGVzID0gMTApICsKICB0aGVtZV9kb25vcnMoKQoKbV9vZGFfdHJlYXRtZW50X3RvdGFsJG1vZGVsX2Rlbm9tICU+JSAKICBwb3N0ZXJpb3Jfc2FtcGxlcyhhZGRfY2hhaW4gPSBUUlVFKSAlPiUgCiAgc2VsZWN0KC1zdGFydHNfd2l0aCgicl9nd2NvZGUiKSwgLXN0YXJ0c193aXRoKCJ6XyIpLCAKICAgICAgICAgLXN0YXJ0c193aXRoKCJyX3JlZ2lvbiIpLCAtbHBfXywgLWl0ZXIpICU+JSAKICBtY21jX3RyYWNlKCkgKwogIHRoZW1lX2Rvbm9ycygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQpgYGAKCiMjIyBDaGVjayB3ZWlnaHRzIHsudGFic2V0fQoKSVBUV3Mgc2hvdWxkIGdlbmVyYWxseSBoYXZlIGEgbWVhbiBvZiAxIGFuZCBzaG91bGRuJ3QgYmUgdG9vIGluY3JlZGlibHkgaGlnaC4gV2hlbiB0aGV5J3JlIGJpZywgaXQncyBhIGdvb2QgaWRlYSB0byB0cnVuY2F0ZSB0aGVtIGF0IHNvbWUgbGV2ZWwuIFRoZSB0cnVuY2F0aW9uIHRocmVzaG9sZCBtYXR0ZXJzIHN1YnN0YW50aWFsbHnigJRhcyBzZWVuIGJlbG93LCB0aGUgQVRFIHdoZW4gdXNpbmcgVi1EZW0ncyBjb3JlIGNpdmlsIHNvY2lldHkgaW5kZXggYXMgdGhlIHRyZWF0bWVudCB2YXJpZXMgc3Vic3RhbnRpYWxseSBhdCBkaWZmZXJlbnQgdHJ1bmNhdGlvbiB0aHJlc2hvbGRzLgoKIyMjIyBUb3RhbCBPREEKClN3ZWV0LgoKYGBge3IgaXB0d3MtdG90YWwtb2RhfQpzdW1tYXJ5KGRmX29kYV9pcHR3X3RvdGFsJGlwdHcpCgpkZl9vZGFfaXB0d190b3RhbCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gaXB0dykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuNSwgYm91bmRhcnkgPSAwKSArCiAgdGhlbWVfZG9ub3JzKCkKYGBgCgojIyMjIEFkdm9jYWN5CgpMb3ZlbHkuCgpgYGB7ciBpcHR3cy1hZHZvY2FjeX0Kc3VtbWFyeShkZl9vZGFfaXB0d19hZHZvY2FjeSRpcHR3KQoKZGZfb2RhX2lwdHdfYWR2b2NhY3kgJT4lIAogIGdncGxvdChhZXMoeCA9IGlwdHcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBib3VuZGFyeSA9IDApICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyMgRW50cnkKCkZhbnRhc3RpYy4KCmBgYHtyIGlwdHdzLWVudHJ5fQpzdW1tYXJ5KGRmX29kYV9pcHR3X2VudHJ5JGlwdHcpCgpkZl9vZGFfaXB0d19lbnRyeSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gaXB0dykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuNSwgYm91bmRhcnkgPSAwKSArCiAgdGhlbWVfZG9ub3JzKCkKYGBgCgojIyMjIEZ1bmRpbmcKClNsaWdodGx5IGNvbmNlcm5pbmcgbWF5YmUgKHRob3VnaCB0aGUgbWVkaWFuIGlzIGdyZWF0KS4KCmBgYHtyIGlwdHdzLWZ1bmRpbmd9CnN1bW1hcnkoZGZfb2RhX2lwdHdfZnVuZGluZyRpcHR3KQoKZGZfb2RhX2lwdHdfZnVuZGluZyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gaXB0dykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGJvdW5kYXJ5ID0gMCkgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKIyMjIyBDb3JlIGNpdmlsIHNvY2lldHkgaW5kZXgKCmxvbCB0aGVzZSBibG93IHVwLiBDaGVjayBvdXQgdGhlIG1heGltdW06CgpgYGB7ciBpcHR3cy1jY3NpLXN1bW1hcnl9CnN1bW1hcnkoZGZfb2RhX2lwdHdfY2NzaSRpcHR3KQpgYGAKCldlIHRydW5jYXRlIGF0IGZvdXIgZGlmZmVyZW50IHRocmVzaG9sZHM6IDEwMCwgNTAwLCAxLDAwMCwgYW5kIDUsMDAwOgoKYGBge3IgaXB0d3MtY2NzaX0KcGxvdF9pcHR3X2Njc2kgPC0gYmluZF9yb3dzKAogIGRmX29kYV9pcHR3X2Njc2kgJT4lIG11dGF0ZSh0aHJlc2hvbGQgPSAxMDAsIGlwdHcgPSBpZmVsc2UoaXB0dyA+IDEwMCwgMTAwLCBpcHR3KSksCiAgZGZfb2RhX2lwdHdfY2NzaSAlPiUgbXV0YXRlKHRocmVzaG9sZCA9IDUwMCwgaXB0dyA9IGlmZWxzZShpcHR3ID4gNTAwLCA1MDAsIGlwdHcpKSwKICBkZl9vZGFfaXB0d19jY3NpICU+JSBtdXRhdGUodGhyZXNob2xkID0gMTAwMCwgaXB0dyA9IGlmZWxzZShpcHR3ID4gMTAwMCwgMTAwMCwgaXB0dykpLAogIGRmX29kYV9pcHR3X2Njc2kgJT4lIG11dGF0ZSh0aHJlc2hvbGQgPSA1MDAwLCBpcHR3ID0gaWZlbHNlKGlwdHcgPiA1MDAwLCA1MDAwLCBpcHR3KSkKKSAlPiUgCiAgbXV0YXRlKHRocmVzaG9sZCA9IHBhc3RlMCgiVHJ1bmNhdGVkIGF0ICIsIGNvbW1hKHRocmVzaG9sZCkpLAogICAgICAgICB0aHJlc2hvbGQgPSBmY3RfaW5vcmRlcih0aHJlc2hvbGQpKQoKcGxvdF9pcHR3X2Njc2kgJT4lIAogIGdncGxvdChhZXMoeCA9IGlwdHcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBib3VuZGFyeSA9IDApICsKICBmYWNldF93cmFwKHZhcnModGhyZXNob2xkKSwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyBSZXN1bHRzIHsudGFic2V0fQoKVGhlc2UgYXJlIGxlc3MgaW1wb3J0YW50IHNpbmNlIHdlIGp1c3QgdXNlIHRoZXNlIHRyZWF0bWVudCBtb2RlbHMgdG8gZ2VuZXJhdGUgd2VpZ2h0cyAqYW5kKiBiZWNhdXNlIGludGVycHJldGluZyBlYWNoIGNvZWZmaWNpZW50IHdoZW4gdHJ5aW5nIHRvIGlzb2xhdGUgY2FzdWFsIGVmZmVjdHMgaXMgdW5pbXBvcnRhbnQgYW5kIFthICJudWlzYW5jZSJdKGh0dHBzOi8vYXJ4aXYub3JnL2Ficy8yMDA1LjEwMzE0KS4gQnV0IGhlcmUgYXJlIHRoZSByZXN1bHRzIGFueXdheToKCiMjIyMgTnVtZXJhdG9yIG1vZGVscwoKYGBge3IgdGJsLWgxLW51bX0KIyBtb2RlbF9uYW1lcyA8LSBwYXN0ZTAoIigiLCAxOmxlbmd0aChtb2RlbHNfdGJsX2gxX3RyZWF0bWVudF9udW0pLCAiKSIpCm1vZGVsX25hbWVzIDwtIDE6bGVuZ3RoKG1vZGVsc190YmxfaDFfdHJlYXRtZW50X251bSkKbmFtZXMobW9kZWxzX3RibF9oMV90cmVhdG1lbnRfbnVtKSA8LSBtb2RlbF9uYW1lcwoKdHJlYXRtZW50X25hbWVzIDwtIGMoIlRyZWF0bWVudCIsICJUb3RhbCBiYXJyaWVycyAodCkiLCAiQmFycmllcnMgdG8gYWR2b2NhY3kgKHQpIiwgCiAgICAgICAgICAgICAgICAgICAgICJCYXJyaWVycyB0byBlbnRyeSAodCkiLCAiQmFycmllcnMgdG8gZnVuZGluZyAodCkiLCAiQ0NTSSAodCkiKQp0cmVhdG1lbnRfcm93cyA8LSBhcy5kYXRhLmZyYW1lKHQodHJlYXRtZW50X25hbWVzKSkKYXR0cih0cmVhdG1lbnRfcm93cywgInBvc2l0aW9uIikgPC0gMQoKY29lZl9saXN0X251bSA8LSBsaXN0KAogICJiX2JhcnJpZXJzX3RvdGFsX2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX2Fkdm9jYWN5X2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX2VudHJ5X2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX2Z1bmRpbmdfbGFnMSIgPSAiVHJlYXRtZW50ICh0IOKIkiAxKSIsCiAgImJfdjJ4Y3NfY2NzaV9sYWcxIiA9ICJUcmVhdG1lbnQgKHQg4oiSIDEpIiwKICAiYl9JbnRlcmNlcHQiID0gIkludGVyY2VwdCIKKQoKbW9kZWxzdW1tYXJ5KG1vZGVsc190YmxfaDFfdHJlYXRtZW50X251bSwKICAgICAgICAgICAgIHN0YXRpc3RpYyA9ICJbe2NvbmYubG93fSwge2NvbmYuaGlnaH1dIiwKICAgICAgICAgICAgIGNvZWZfbWFwID0gY29lZl9saXN0X251bSwKICAgICAgICAgICAgIGFkZF9yb3dzID0gdHJlYXRtZW50X3Jvd3MsCiAgICAgICAgICAgICBnb2Zfb21pdCA9ICJFTFBEIiwKICAgICAgICAgICAgIGVzY2FwZSA9IEZBTFNFLAogICAgICAgICAgICAgbm90ZXMgPSBsaXN0KCJQb3N0ZXJpb3IgbWVhbnM7IDk1JSBjcmVkaWJsZSBpbnRlcnZhbHMgaW4gYnJhY2tldHMiKSkKYGBgCgojIyMjIERlbm9taW5hdG9yIG1vZGVscwoKYGBge3IgdGJsLWgxLWRlbm9tfQojIG1vZGVsX25hbWVzIDwtIHBhc3RlMCgiKCIsIDE6bGVuZ3RoKG1vZGVsc190YmxfaDFfdHJlYXRtZW50X2Rlbm9tKSwgIikiKQptb2RlbF9uYW1lcyA8LSAxOmxlbmd0aChtb2RlbHNfdGJsX2gxX3RyZWF0bWVudF9kZW5vbSkKbmFtZXMobW9kZWxzX3RibF9oMV90cmVhdG1lbnRfZGVub20pIDwtIG1vZGVsX25hbWVzCgp0cmVhdG1lbnRfbmFtZXMgPC0gYygiVHJlYXRtZW50IiwgIlRvdGFsIGJhcnJpZXJzICh0KSIsICJCYXJyaWVycyB0byBhZHZvY2FjeSAodCkiLCAKICAgICAgICAgICAgICAgICAgICAgIkJhcnJpZXJzIHRvIGVudHJ5ICh0KSIsICJCYXJyaWVycyB0byBmdW5kaW5nICh0KSIsICJDQ1NJICh0KSIpCnRyZWF0bWVudF9yb3dzIDwtIGFzLmRhdGEuZnJhbWUodCh0cmVhdG1lbnRfbmFtZXMpKQphdHRyKHRyZWF0bWVudF9yb3dzLCAicG9zaXRpb24iKSA8LSAxCgpjb2VmX2xpc3RfZGVub20gPC0gbGlzdCgKICAiYl9iYXJyaWVyc190b3RhbF9sYWcxIiA9ICJUcmVhdG1lbnQgKHQg4oiSIDEpIiwKICAiYl9hZHZvY2FjeV9sYWcxIiA9ICJUcmVhdG1lbnQgKHQg4oiSIDEpIiwKICAiYl9lbnRyeV9sYWcxIiA9ICJUcmVhdG1lbnQgKHQg4oiSIDEpIiwKICAiYl9mdW5kaW5nX2xhZzEiID0gIlRyZWF0bWVudCAodCDiiJIgMSkiLAogICJiX3YyeGNzX2Njc2lfbGFnMSIgPSAiVHJlYXRtZW50ICh0IOKIkiAxKSIsCiAgImJfdjJ4X3BvbHlhcmNoeSIgPSAiUG9seWFyY2h5IiwKICAiYl92MnhfY29yciIgPSAiQ29ycnVwdGlvbiBpbmRleCIsCiAgImJfdjJ4X3J1bGUiID0gIlJ1bGUgb2YgbGF3IGluZGV4IiwKICAiYl92MnhfY2l2bGliIiA9ICJDaXZpbCBsaWJlcnRpZXMgaW5kZXgiLAogICJiX3YyeF9jbHBoeSIgPSAiUGh5c2ljYWwgdmlvbGVuY2UgaW5kZXgiLAogICJiX3YyeF9jbHByaXYiID0gIlByaXZhdGUgY2l2aWwgbGliZXJ0aWVzIGluZGV4IiwKICAiYl9nZHBjYXBfbG9nIiA9ICJMb2cgR0RQL2NhcGl0YSIsCiAgImJfdW5fdHJhZGVfcGN0X2dkcCIgPSAiUGVyY2VudCBvZiBHRFAgZnJvbSB0cmFkZSIsCiAgImJfdjJwZWVkdWVxIiA9ICJFZHVjYXRpb25hbCBlcXVhbGl0eSBpbmRleCIsCiAgImJfdjJwZWhlYWx0aCIgPSAiSGVhbHRoIGVxdWFsaXR5IGluZGV4IiwKICAiYl9lX3BlaW5mbW9yIiA9ICJJbmZhbnQgbW9ydGFsaXR5IHJhdGUiLAogICJiX2ludGVybmFsX2NvbmZsaWN0X3Bhc3RfNVRSVUUiID0gIkludGVybmFsIGNvbmZsaWN0IGluIHBhc3QgNSB5ZWFycyIsCiAgImJfbmF0dXJhbF9kaXNfY291bnQiID0gIkNvdW50IG9mIG5hdHVyYWwgZGlzYXN0ZXJzIiwKICAiYl9JbnRlcmNlcHQiID0gIkludGVyY2VwdCIKKQoKbW9kZWxzdW1tYXJ5KG1vZGVsc190YmxfaDFfdHJlYXRtZW50X2Rlbm9tLAogICAgICAgICAgICAgc3RhdGlzdGljID0gIlt7Y29uZi5sb3d9LCB7Y29uZi5oaWdofV0iLAogICAgICAgICAgICAgY29lZl9tYXAgPSBjb2VmX2xpc3RfZGVub20sCiAgICAgICAgICAgICBhZGRfcm93cyA9IHRyZWF0bWVudF9yb3dzLAogICAgICAgICAgICAgZ29mX29taXQgPSAiRUxQRCIsCiAgICAgICAgICAgICBlc2NhcGUgPSBGQUxTRSwKICAgICAgICAgICAgIG5vdGVzID0gbGlzdCgiUG9zdGVyaW9yIG1lYW5zOyA5NSUgY3JlZGlibGUgaW50ZXJ2YWxzIGluIGJyYWNrZXRzIikpCmBgYAoKCiMjIE91dGNvbWUgbW9kZWxzCgojIyMgTW9kZWxpbmcgY2hvaWNlcwoKV2UgdXNlIGxvZ2dlZCBPREEsIGxlYWRlZCBieSBvbmUgeWVhciwgYXMgb3VyIG1haW4gb3V0Y29tZSB2YXJpYWJsZSB0aHJvdWdob3V0IHRoaXMgYW5hbHlzaXMuIFdlIHRveWVkIHdpdGggZGlmZmVyZW50IHBhcmFtZXRlcml6YXRpb25zIG9mIE9EQSBiZWNhdXNlIG9mIGl0cyBleHBvbmVudGlhbC1pc2ggZGlzdHJpYnV0aW9uLiBGb3IgaW5zdGFuY2UsIGluc3RlYWQgb2YgbG9nZ2luZyB0aGUgb3V0Y29tZSwgW3NvbWUgcGFwZXJzXShodHRwczovL21hcmNmYmVsbGVtYXJlLmNvbS93b3JkcHJlc3MvMTMzMjMpIHVzZSBhbiAkXG9wZXJhdG9ybmFtZXthcmNpc25ofSQgdHJhbnNmb3JtYXRpb24sIGJ1dCB0aGVuIGludGVycHJldGF0aW9uIGdldHMgdHJpY2t5LiBJdCdzIHBvc3NpYmxlIHRvIHVzZSBbUG9pc3Nvbi9uZWdhdGl2ZSBiaW5vbWlhbC9HYW1tYSBtb2RlbHMgd2l0aCBkb2xsYXIgb3V0Y29tZXMgdGhhdCBhcmUgc29tZXRpbWVzIHplcm9dKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDkzL3Bhbi9tcHMwMTgpLCBidXQgdGhlc2Uga2luZHMgb2YgZW5zZW1ibGUgbW9kZWxzIGdldCB1bndpZWxkeS4gCgpBIHNpbXBsZXIgdmVyc2lvbiBvZiB0aGUgUG9pc3Nvbi1HYW1tYSBjb21iaW5hdGlvbiBpcyB0byB1c2UgYSBodXJkbGUgbW9kZWwsIG9mIHdoaWNoIHRoZXJlIGFyZSBmb3VyIHR5cGVzIGN1cnJlbnRseSBpbiAqKmJybXMqKi4gT25lIG9mIHRoZXNlIGlzIGBodXJkbGVfbG9nbm9ybWFsKClgLCB3aGljaCBsb2ctdHJhbnNmb3JtcyB0aGUgb3V0Y29tZSB2YXJpYWJsZSBhdXRvbWF0aWNhbGx5LiBJdCdzIHBvc3NpYmxlIHRvIGNyZWF0ZSBjdXN0b20gZmFtaWxpZXMgbGlrZSBgaHVyZGxlX2dhdXNzaWFuKClgLCBidXQgdGhpcyBpcyBzdXBlciBoYXJkIHRvIGRvLiBJIGhhdmUgW2FuIGltcGxlbWVudGF0aW9uIHBhcnRpYWxseSBjb21wbGV0ZWQgaGVyZV0oaHR0cHM6Ly9kaXNjb3Vyc2UubWMtc3Rhbi5vcmcvdC9jdXN0b20tZ2F1c3NpYW4taHVyZGxlLWZhbWlseS1ub3QtcXVpdGUtd29ya2luZy1pbi1icm1zLzIxMDI4LzIpLCBidXQgSSBjYW4ndCBnZXQgaXQgdG8gYWN0dWFsbHkgY3JlYXRlIHBvc3RlcmlvciBwcmVkaWN0aW9ucy4gVWdoLgoKU28gd2UgKmNvdWxkKiBmaXQgYSBodXJkbGVkIGxvZ25vcm1hbCBtb2RlbCwgd2hpY2ggdXNlcyBhIGxvZ2l0IG1vZGVsIHRvIHByZWRpY3QgMC9ub3QgMCwgdGhlbiB1c2VzIGEgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbiB0byBtb2RlbCB0aGUgcmVzdCBvZiB0aGUgZGF0YS4gSG93ZXZlciwgdGhpcyByZXF1aXJlcyBzcGVjaWZ5aW5nIHR3byBkaWZmZXJlbnQgbW9kZWxzIHdpdGggZGlmZmVyZW50IGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzZXMgYW5kIGRpZmZlcmVudCB0cmVhdG1lbnQgZWZmZWN0cywgd2hpY2ggYmVjb21lcyAqaW1tZW5zZWx5KiB1bndpZWxkeSB3aGVuIGRlYWxpbmcgd2l0aCBtYXJnaW5hbCBzdHJ1Y3R1cmFsIG1vZGVscyBhbmQgSVBUV3MuIFRvIHNpbXBsaWZ5IHRoaW5ncywgd2UgaW5pdGlhbGx5IHRyaWVkIHVzaW5nIGFuIGludGVyY2VwdC1vbmx5IG1vZGVsIChpLmUuIGBvdXRjb21lIH4gMWApIGZvciB0aGUgMC9ub3QgMCBsb2dpdCBtb2RlbCBhbmQgdGhlbiBgb3V0Y29tZSB8IHdlaWdodHMoaXB0dykgfiB0cmVhdG1lbnRgIGZvciB0aGUgcmVzdCBvZiB0aGUgZGF0YSBhbmQgdGhpcyB3b3JrZWQsIGFuZCB0aGUgcG9zdGVyaW9yIHByZWRpY3RpdmUgZ3JhcGhzIGxvb2tlZCBwaGVub21lbmFsLiBCVVQgY29uY2VwdHVhbGx5IHRoaXMgd2FzIGRvaW5nIHdlaXJkIHN0dWZmLiBXZSB3ZXJlIGVzc2VudGlhbGx5IGlnbm9yaW5nIGFsbCB0aGUgMHMgYW5kIG5vdCBpbmNvcnBvcmF0aW5nIGFueSBvZiB0aGUgSVBUV3MgKG9yIGV2ZW4gdGhlIHRyZWF0bWVudCB2YXJpYWJsZSEpIGludG8gdGhlIG1vZGVscy4gTWF0aGVtYXRpY2FsbHksIHRoaXMgZmVsdCBlcXVpdmFsZW50IHRvIGp1c3QgZG9pbmcgYGZpbHRlcih0cmVhdG1lbnQgIT0gMClgLgoKU28gaW4gdGhlIGVuZCwgd2UgZ28gYmFjayB0byB0aGUgc3RhbmRhcmQgd29ya2hvcnNlIG9mIGp1c3QgbG9nZ2luZyB0aGUgb3V0Y29tZS4KCiMjIyBJbnRlcnByZXRpbmcgb3V0Y29tZSBtb2RlbHMKCmBgYHtyIHNob3ctbG9nbm9ybWFsLWludGVycHJldGF0aW9uLCB3YXJuaW5nPUZBTFNFfQp0aWR5KG1fb2RhX291dGNvbWVfZnVuZGluZykgJT4lCiAgbXV0YXRlKGVzdGltYXRlX2V4cCA9IGV4cChlc3RpbWF0ZSkpICU+JSAKICBmaWx0ZXIodGVybSA9PSAiZnVuZGluZyIpICU+JSAKICBzZWxlY3QodGVybSwgZXN0aW1hdGUsIGVzdGltYXRlX2V4cCkKYGBgCgpgYGB7ciBleHRyYWN0X2NvZWYsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cm1vZGVsX3N0YXRzIDwtIHRpZHkobV9vZGFfb3V0Y29tZV9mdW5kaW5nKSAlPiUgCiAgbXV0YXRlKHRlcm0gPSBqYW5pdG9yOjptYWtlX2NsZWFuX25hbWVzKHRlcm0pKSAlPiUgCiAgc3BsaXQoLiR0ZXJtKQpgYGAKCkJlY2F1c2Ugb3VyIG91dGNvbWUgaXMgbG9nZ2VkLCB0aGUgY29lZmZpY2llbnRzIChhbmQgdGhlIHVsdGltYXRlIEFURSkgcmVwcmVzZW50cyBhIHBlcmNlbnQgY2hhbmdlIGluIHRoZSBvdXRjb21lLiBUaGUgKmV4cG9uZW50aWF0ZWQqIGNvZWZmaWNpZW50cyByZXByZXNlbnQgcGVyY2VudCBjaGFuZ2VzIGZvciBlYWNoIHVuaXQgaW5jcmVhc2UgaW4gWC4gRm9yIGluc3RhbmNlLCBpbiB0aGUgZnVuZGluZyBtb2RlbCwgJFxiZXRhXzEkIGlzIGByIHJvdW5kKG1vZGVsX3N0YXRzJGZ1bmRpbmckZXN0aW1hdGUsIDMpYCwgd2hpbGUgJGVee1xiZXRhXzF9JCBpcyBgciByb3VuZChleHAobW9kZWxfc3RhdHMkZnVuZGluZyRlc3RpbWF0ZSksIDMpYC4gTGlrZSBleHBvbmVudGlhdGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLCBldmVyeXRoaW5nIGhlcmUgaXMgY2VudGVyZWQgYXJvdW5kIDEsIG1lYW5pbmcgdGhhdCB0aGVyZSdzIGEgYHIgcGVyY2VudChleHAobW9kZWxfc3RhdHMkZnVuZGluZyRlc3RpbWF0ZSkgLSAxLCBhY2N1cmFjeSA9IDAuMSlgIGRlY3JlYXNlIGluIGFpZCBmb3IgZXZlcnkgbGVnYWwgYmFycmllciBhZGRlZC4gVGhpcyBjYW4gYmUgYWxzbyBiZSBzZWVuIGFzIGEgbXVsdGlwbGllciBlZmZlY3QuIElmIGFpZCBpcyBcJDUwIG1pbGxpb24sIGl0IGNoYW5nZXMgdG8gYHIgZG9sbGFyKDUwMDAwMDAwICogZXhwKG1vZGVsX3N0YXRzJGZ1bmRpbmckZXN0aW1hdGUpKWAgKDUwLDAwMCwwMDAgw5cgYHIgcm91bmQoZXhwKG1vZGVsX3N0YXRzJGZ1bmRpbmckZXN0aW1hdGUpLCA1KWApLgoKSW50ZXJwcmV0aW5nIHRoaXMgY29lZmZpY2llbnQgZ2V0cyBhIGxpdHRsZSB0cmlja2llciBiZWNhdXNlIHdlIHVzZWQgYSBtdWx0aWxldmVsIG1vZGVsIHdpdGggcG9wdWxhdGlvbiBhbmQgZ3JvdXAgZWZmZWN0cy4gVGhpcyAkXGJldGFfMSQgaGVyZSBpcyB0aGUgKiphdmVyYWdlIGVmZmVjdCBmb3IgYSBtZWRpYW4gY2x1c3RlciBhdCBlYWNoIGxldmVsIG9mIFgqKi4gW1NlZSB0aGlzIGluY3JlZGlibGUgcmVzb3VyY2UgZm9yIGEgdG9uIG1vcmUgZGV0YWlsc10oaHR0cHM6Ly9ycHN5Y2hvbG9naXN0LmNvbS9HTE1NLXBhcnQxLWxvZ25vcm1hbCkgYWJvdXQgZGlmZmVyZW50IHdheXMgb2YgcGllY2luZyB0b2dldGhlciBwb3B1bGF0aW9uLSBhbmQgZ3JvdXAtbGV2ZWwgZWZmZWN0cyBpbiBhIGxvZ25vcm1hbCBtb2RlbC4KCiMjIyBQcmlvcnMgZm9yIG91dGNvbWUgbW9kZWxzCgpUaGVyZSBhcmUgYSAqdG9uKiBvZiBtb3ZpbmcgcGFydHMgaW4gdGhlc2Ugb3V0Y29tZSBtb2RlbHMuIEhlcmUncyB0aGUgZnVsbCBzcGVjaWZpY2F0aW9uIGZvciB0aGUgbW9kZWxzIGFuZCBhbGwgcHJpb3JzOgoKJCQKXGJlZ2lue2FsaWduZWR9Clxsb2cgKFx0ZXh0e0FpZH1fe2ksdH0pICZcc2ltIFx0ZXh0e0lQVFd9X3tpLCB0LTF9IFx0aW1lcyBcbWF0aGNhbHtOfSAoXG11X3tpLCB0fSwgXHNpZ21hX20pICYgXHRleHR7W2xpa2VsaWhvb2RdfVxcClxtdV97aSwgdH0gJlxzaW0gXGFscGhhX3tcdGV4dHtjb3VudHJ5fVtpXX0gKyBcZGVsdGFfe1x0ZXh0e3llYXJ9W2tdfSArIFxiZXRhXCBcdGV4dHtMYXd9X3tpLCB0LTF9ICYgXHRleHR7W21hcmdpbmFsIHN0cnVjdHVyYWwgbW9kZWxdfVxcClxhbHBoYV9qICZcc2ltIFxtYXRoY2Fse059IChcYmFye1xhbHBoYX0sIFxzaWdtYV97XGFscGhhfSkgXHRleHR7LCBmb3IgfSBqIFx0ZXh0eyBpbiB9IDEgLi4gSiAmIFx0ZXh0e1tjb3VudHJ5LXNwZWNpZmljIGludGVyY2VwdHNdfSBcXApcZGVsdGFfaiAmXHNpbSBcbWF0aGNhbHtOfSAoMCwgXHNpZ21hX3tcZGVsdGF9KSBcdGV4dHssIGZvciB9IGogXHRleHR7IGluIH0gMSAuLiBKICYgXHRleHR7W3llYXItc3BlY2lmaWMgaW50ZXJjZXB0c119IFxcClwgXFwKXGJhcntcYWxwaGF9ICZcc2ltIFxtYXRoY2Fse059ICgwLCAyMCkgJiBcdGV4dHtbcHJpb3IgcG9wdWxhdGlvbiBpbnRlcmNlcHRdfSBcXApcYmV0YSAmXHNpbSBcbWF0aGNhbHtOfSAoMCwgMykgJiBcdGV4dHtbcHJpb3IgcG9wdWxhdGlvbiBlZmZlY3RzXX0gXFwKXHNpZ21hX20sIFxzaWdtYV97XGFscGhhfSwgXHNpZ21hX3tcZGVsdGF9ICZcc2ltIFxvcGVyYXRvcm5hbWV7Q2F1Y2h5fSgwLCAxKSAmIFx0ZXh0e1twcmlvciBzZCBmb3IgZXJyb3JzXX0KXGVuZHthbGlnbmVkfQokJAoKIyMjIENoZWNrIG91dGNvbWUgbW9kZWxzCgpUaGUgdHJhY2VwbG90cyBhbGwgbG9vayBnb29kLiBIZXJlJ3Mgb25lOgoKYGBge3IgaDEtY2hlY2stb3V0Y29tZX0KbV9vZGFfb3V0Y29tZV90b3RhbCAlPiUgCiAgcG9zdGVyaW9yX3NhbXBsZXMoYWRkX2NoYWluID0gVFJVRSkgJT4lIAogIHNlbGVjdCgtc3RhcnRzX3dpdGgoInJfZ3djb2RlIiksIC1zdGFydHNfd2l0aCgiel8iKSwgLXN0YXJ0c193aXRoKCJyX3llYXIiKSwgLWxwX18sIC1pdGVyKSAlPiUgCiAgbWNtY190cmFjZSgpICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyBSZXN1bHRzIHsudGFic2V0fQoKIyMjIyBBVEUgcGxvdHMKCmBgYHtyIGgxLXBsb3RzLWRlanVyZSwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NSwgZmlnLmFzcD1OVUxMfQpjb2Vmc19uaWNlIDwtIHRyaWJibGUoCiAgfmAudmFyaWFibGVgLCB+dmFyX25pY2UsCiAgImJfYmFycmllcnNfdG90YWwiLCAiQWRkaXRpb25hbCBsYXcsIHQgLSAxIiwKICAiYl9hZHZvY2FjeSIsICJBZGRpdGlvbmFsIGFkdm9jYWN5IGxhdywgdCAtIDEiLAogICJiX2VudHJ5IiwgIkFkZGl0aW9uYWwgZW50cnkgbGF3LCB0IC0gMSIsCiAgImJfZnVuZGluZyIsICJBZGRpdGlvbmFsIGZ1bmRpbmcgbGF3LCB0IC0gMSIsCiAgImJfdjJ4Y3NfY2NzaSIsICJDb3JlIGNpdmlsIHNvY2lldHkgaW5kZXgsIHQgLSAxIgopICU+JSAKICBtdXRhdGUodmFyX25pY2UgPSBmY3RfaW5vcmRlcih2YXJfbmljZSkpCgpwbG90X3RvdGFsX2RhdGEgPC0gZ2F0aGVyX2RyYXdzKG1fb2RhX291dGNvbWVfdG90YWwsIGJfYmFycmllcnNfdG90YWwpCnBsb3RfYWR2b2NhY3lfZGF0YSA8LSBnYXRoZXJfZHJhd3MobV9vZGFfb3V0Y29tZV9hZHZvY2FjeSwgYl9hZHZvY2FjeSkKcGxvdF9lbnRyeV9kYXRhIDwtIGdhdGhlcl9kcmF3cyhtX29kYV9vdXRjb21lX2VudHJ5LCBiX2VudHJ5KQpwbG90X2Z1bmRpbmdfZGF0YSA8LSBnYXRoZXJfZHJhd3MobV9vZGFfb3V0Y29tZV9mdW5kaW5nLCBiX2Z1bmRpbmcpIAoKcGxvdF90b3RhbF9haWRfY29lZnMgPC0gYmluZF9yb3dzKHBsb3RfdG90YWxfZGF0YSwgcGxvdF9hZHZvY2FjeV9kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9lbnRyeV9kYXRhLCBwbG90X2Z1bmRpbmdfZGF0YSkgJT4lIAogIGxlZnRfam9pbihjb2Vmc19uaWNlLCBieSA9ICIudmFyaWFibGUiKQoKcm9wZV9zZCA8LSBzZChkZl9vZGFfaXB0d190b3RhbCR0b3RhbF9vZGFfbG9nX2xlYWQxKQoKcGxvdF9yb3BlIDwtIHRpYmJsZSh4bWluID0gLTAuMDUgKiByb3BlX3NkLCAKICAgICAgICAgICAgICAgICAgICB4bWF4ID0gMC4wNSAqIHJvcGVfc2QpCgpnZ3Bsb3QocGxvdF90b3RhbF9haWRfY29lZnMsIGFlcyh4ID0gLnZhbHVlLCB5ID0gZmN0X3Jldih2YXJfbmljZSksIGZpbGwgPSB2YXJfbmljZSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9yZWN0KGRhdGEgPSBwbG90X3JvcGUsIGFlcyh4bWluID0geG1pbiwgeG1heCA9IHhtYXgsIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mKSwKICAgICAgICAgICAgZmlsbCA9ICIjRkZEQzAwIiwgYWxwaGEgPSAwLjMsIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDAsIHkgPSAwLjY1LCAKICAgICAgICAgICBsYWJlbCA9ICJSZWdpb24gb2YgcHJhY3RpY2FsIGVxdWl2YWxlbmNlXG4owrEgMC4wNSDDlyBTRCBsb2cgZm9yZWlnbiBhaWQpIiwKICAgICAgICAgICBzaXplID0gcHRzKDgpKSArCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC44LCAwLjk1KSwgYWxwaGEgPSAwLjgsIHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9oZGkiKSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKwogIHNjYWxlX3lfZGlzY3JldGUoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0ZGODUxQiIsICIjODUxNDRiIiwgIiMzRDk5NzAiLCAiIzAwMWYzZiIpKSArCiAgbGFicyh4ID0gIkNoYW5nZSBpbiBsb2cgZm9yZWlnbiBhaWQgaW4gZm9sbG93aW5nIHllYXIiLCB5ID0gTlVMTCwKICAgICAgIGNhcHRpb24gPSAiUG9pbnQgc2hvd3MgcG9zdGVyaW9yIG1lZGlhbjsgbGluZXMgc2hvdyA4MCUgYW5kIDk1JVxuY3JlZGlibGUgaGlnaGVzdC1kZW5zaXR5LWludGVydmFsIikgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKYGBge3IgaDEtcGxvdHMtZGVmYWN0b30KcGxvdF9jY3NpX2NvZWZzIDwtIG1fb2RhX291dGNvbWVfY2NzaSAlPiUgCiAgbWFwX2Rmcih+Z2F0aGVyX2RyYXdzKC4sIGJfdjJ4Y3NfY2NzaSksIC5pZCA9ICJtb2RlbCIpICU+JSAKICBtdXRhdGUoLnZhbHVlID0gLnZhbHVlIC8gMTApICU+JSAKICBtdXRhdGUobW9kZWwgPSBjb21tYShhcy5udW1lcmljKHN0cl9yZW1vdmUobW9kZWwsICJtb2RlbF8iKSkpKSAlPiUgCiAgbXV0YXRlKG1vZGVsID0gZmN0X2lub3JkZXIobW9kZWwpKSAlPiUgCiAgbGVmdF9qb2luKGNvZWZzX25pY2UsIGJ5ID0gIi52YXJpYWJsZSIpCgpnZ3Bsb3QocGxvdF9jY3NpX2NvZWZzLCBhZXMoeCA9IC52YWx1ZSwgeSA9IGZjdF9yZXYobW9kZWwpLCBmaWxsID0gbW9kZWwpKSArCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC44LCAwLjk1KSwgcG9pbnRfaW50ZXJ2YWwgPSAibWVkaWFuX2hkaSIsCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpKSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJDb2VmZmljaWVudCIsIHkgPSAiSVBUVyB0cnVuY2F0aW9uIHBvaW50IikgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKIyMjIyBUYWJsZXMKCmBgYHtyIHRibC1oMS1kZWp1cmV9CiMgbW9kZWxfbmFtZXMgPC0gcGFzdGUwKCIoIiwgMTpsZW5ndGgobW9kZWxzX3RibF9oMV9vdXRjb21lX2RlanVyZSksICIpIikKbW9kZWxfbmFtZXMgPC0gMTpsZW5ndGgobW9kZWxzX3RibF9oMV9vdXRjb21lX2RlanVyZSkKbmFtZXMobW9kZWxzX3RibF9oMV9vdXRjb21lX2RlanVyZSkgPC0gbW9kZWxfbmFtZXMKCnRyZWF0bWVudF9uYW1lcyA8LSBjKCJUcmVhdG1lbnQiLCAiVG90YWwgYmFycmllcnMgKHQpIiwgIkJhcnJpZXJzIHRvIGFkdm9jYWN5ICh0KSIsIAogICAgICAgICAgICAgICAgICAgICAiQmFycmllcnMgdG8gZW50cnkgKHQpIiwgIkJhcnJpZXJzIHRvIGZ1bmRpbmcgKHQpIikKdHJlYXRtZW50X3Jvd3MgPC0gYXMuZGF0YS5mcmFtZSh0KHRyZWF0bWVudF9uYW1lcykpCmF0dHIodHJlYXRtZW50X3Jvd3MsICJwb3NpdGlvbiIpIDwtIDEKCmNvZWZfbGlzdF9vdXRjb21lIDwtIGxpc3QoCiAgImJfYmFycmllcnNfdG90YWwiID0gIlRyZWF0bWVudCAodCkiLAogICJiX2Fkdm9jYWN5IiA9ICJUcmVhdG1lbnQgKHQpIiwKICAiYl9lbnRyeSIgPSAiVHJlYXRtZW50ICh0KSIsCiAgImJfZnVuZGluZyIgPSAiVHJlYXRtZW50ICh0KSIsCiAgImJfdjJ4Y3NfY2NzaSIgPSAiQ29yZSBjaXZpbCBzb2NpZXR5IGluZGV4ICh0KSIsCiAgImJfSW50ZXJjZXB0IiA9ICJJbnRlcmNlcHQiLAogICJzZF9nd2NvZGVfX0ludGVyY2VwdCIgPSAiz4MgY291bnRyeSBpbnRlcmNlcHRzIiwKICAic2RfeWVhcl9fSW50ZXJjZXB0IiA9ICLPgyB5ZWFyIGludGVyY2VwdHMiCikKCm1vZGVsc3VtbWFyeShtb2RlbHNfdGJsX2gxX291dGNvbWVfZGVqdXJlLAogICAgICAgICAgICAgc3RhdGlzdGljID0gIlt7Y29uZi5sb3d9LCB7Y29uZi5oaWdofV0iLAogICAgICAgICAgICAgY29lZl9tYXAgPSBjb2VmX2xpc3Rfb3V0Y29tZSwKICAgICAgICAgICAgIGFkZF9yb3dzID0gdHJlYXRtZW50X3Jvd3MsCiAgICAgICAgICAgICBnb2Zfb21pdCA9ICJFTFBEIiwKICAgICAgICAgICAgIGVzY2FwZSA9IEZBTFNFLAogICAgICAgICAgICAgbm90ZXMgPSBsaXN0KCJQb3N0ZXJpb3IgbWVhbnM7IDk1JSBjcmVkaWJsZSBpbnRlcnZhbHMgaW4gYnJhY2tldHMiKSkgJT4lIAogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiT3V0Y29tZTogT0RBICh0ICsgMSkiID0gNCkpCmBgYAoKYGBge3IgdGJsLWgxLWRlZmFjdG99CnRydW5jYXRpb25fdGhyZXNob2xkcyA8LSBuYW1lcyhtb2RlbHNfdGJsX2gxX291dGNvbWVfZGVmYWN0bykgJT4lIAogIHN0cl9leHRyYWN0KCJfXFxkKyIpICU+JSAKICBzdHJfcmVtb3ZlKCJfIikgJT4lIAogIGFzLm51bWVyaWMoKSAlPiUgCiAgY29tbWEoKQoKdHJ1bmNhdGlvbl9uYW1lcyA8LSBjKCJJUFRXIHRydW5jYXRpb24gdGhyZXNob2xkIiwgdHJ1bmNhdGlvbl90aHJlc2hvbGRzKQp0cnVuY2F0aW9uX3Jvd3MgPC0gYXMuZGF0YS5mcmFtZSh0KHRydW5jYXRpb25fbmFtZXMpKQphdHRyKHRydW5jYXRpb25fcm93cywgInBvc2l0aW9uIikgPC0gMQoKIyBtb2RlbF9uYW1lcyA8LSBwYXN0ZTAoIigiLCAxOmxlbmd0aChtb2RlbHNfdGJsX2gxX291dGNvbWVfZGVmYWN0byksICIpIikKbW9kZWxfbmFtZXMgPC0gMTpsZW5ndGgobW9kZWxzX3RibF9oMV9vdXRjb21lX2RlZmFjdG8pCm5hbWVzKG1vZGVsc190YmxfaDFfb3V0Y29tZV9kZWZhY3RvKSA8LSBtb2RlbF9uYW1lcwoKbW9kZWxzdW1tYXJ5KG1vZGVsc190YmxfaDFfb3V0Y29tZV9kZWZhY3RvLAogICAgICAgICAgICAgc3RhdGlzdGljID0gIlt7Y29uZi5sb3d9LCB7Y29uZi5oaWdofV0iLAogICAgICAgICAgICAgY29lZl9tYXAgPSBjb2VmX2xpc3Rfb3V0Y29tZSwKICAgICAgICAgICAgIGFkZF9yb3dzID0gdHJ1bmNhdGlvbl9yb3dzLAogICAgICAgICAgICAgZ29mX29taXQgPSAiRUxQRCIsCiAgICAgICAgICAgICBlc2NhcGUgPSBGQUxTRSwKICAgICAgICAgICAgIG5vdGVzID0gbGlzdCgiUG9zdGVyaW9yIG1lYW5zOyA5NSUgY3JlZGlibGUgaW50ZXJ2YWxzIGluIGJyYWNrZXRzIikpICU+JSAKICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIk91dGNvbWU6IE9EQSAodCArIDEpIiA9IDQpKQpgYGAKCiMjIyMgTWFyZ2luYWwgZWZmZWN0cwoKYGBge3IgaDEtY29uZGl0aW9uYWwtZWZmZWN0c30KIyBicm1zOjpjb25kaXRpb25hbF9lZmZlY3RzKCkgY2FuIGNyZWF0ZSBzcGFnaGV0dGkgcGxvdHMgKHNpbmdsZSBsaW5lcyBwZXIKIyBzYW1wbGUpLCBidXQgaXQgc3RvcmVzIHRoZW0gaW4gYW4gYXR0cmlidXRlIHNsb3QgbmFtZWQgInNwYWdoZXR0aSIsIHdoaWNoIGlzCiMgdHJpY2t5IHRvIGV4dHJhY3QgZGF0YSBmcm9tLiBUaGlzIHB1bGxzIHRoZSBkYXRhIGZyYW1lIGZyb20gdGhlIGF0dHJpYnV0ZQptYWtlX3NwYWdoZXR0aSA8LSBmdW5jdGlvbihtb2RlbCkgewogIHJhd19lZmZlY3RzIDwtIGNvbmRpdGlvbmFsX2VmZmVjdHMobW9kZWwsIHNwYWdoZXR0aSA9IFRSVUUsIG5zYW1wbGVzID0gMTAwKVtbMV1dCiAgc3BhZ2hldHRpX2RhdGEgPC0gYXR0cihyYXdfZWZmZWN0cywgInNwYWdoZXR0aSIpCiAgcmV0dXJuKHNwYWdoZXR0aV9kYXRhKQp9CgptYWtlX3NwYWdoZXR0aShtX29kYV9vdXRjb21lX3RvdGFsKSAlPiUgCiAgbXV0YXRlKGVzdGltYXRlX18gPSBleHAoZXN0aW1hdGVfXykpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBlZmZlY3QxX18sIHkgPSBlc3RpbWF0ZV9fLCBncm91cCA9IHNhbXBsZV9fKSkgKwogIGdlb21fbGluZShzaXplID0gMC4yNSwgY29sb3IgPSAiI0ZGNDEzNiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMDo5KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGRvbGxhciwgdHJhbnMgPSBwc2V1ZG9fbG9nX3RyYW5zKCkpICsKICBndWlkZXMoY29sb3IgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJDb3VudCBvZiB0b3RhbCBsZWdhbCBiYXJyaWVycyIsCiAgICAgICB5ID0gIlByZWRpY3RlZCB0b3RhbCBPREEgaW4gZm9sbG93aW5nIHllYXIiKSArCiAgdGhlbWVfZG9ub3JzKCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCm1ha2Vfc3BhZ2hldHRpKG1fb2RhX291dGNvbWVfYWR2b2NhY3kpICU+JSAKICBtdXRhdGUoZXN0aW1hdGVfXyA9IGV4cChlc3RpbWF0ZV9fKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZWZmZWN0MV9fLCB5ID0gZXN0aW1hdGVfXywgZ3JvdXAgPSBzYW1wbGVfXykpICsKICBnZW9tX2xpbmUoc2l6ZSA9IDAuMjUsIGNvbG9yID0gIiNGRjQxMzYiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDA6MikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBkb2xsYXIsIHRyYW5zID0gcHNldWRvX2xvZ190cmFucygpKSArCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpICsKICBsYWJzKHggPSAiQ291bnQgb2YgYmFycmllcnMgdG8gYWR2b2NhY3kiLAogICAgICAgeSA9ICJQcmVkaWN0ZWQgdG90YWwgT0RBIGluIGZvbGxvd2luZyB5ZWFyIikgKwogIHRoZW1lX2Rvbm9ycygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpCgptYWtlX3NwYWdoZXR0aShtX29kYV9vdXRjb21lX2VudHJ5KSAlPiUgCiAgbXV0YXRlKGVzdGltYXRlX18gPSBleHAoZXN0aW1hdGVfXykpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBlZmZlY3QxX18sIHkgPSBlc3RpbWF0ZV9fLCBncm91cCA9IHNhbXBsZV9fKSkgKwogIGdlb21fbGluZShzaXplID0gMC4yNSwgY29sb3IgPSAiI0ZGNDEzNiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMDozKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGRvbGxhciwgdHJhbnMgPSBwc2V1ZG9fbG9nX3RyYW5zKCkpICsKICBndWlkZXMoY29sb3IgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJDb3VudCBvZiBiYXJyaWVycyB0byBlbnRyeSIsCiAgICAgICB5ID0gIlByZWRpY3RlZCB0b3RhbCBPREEgaW4gZm9sbG93aW5nIHllYXIiKSArCiAgdGhlbWVfZG9ub3JzKCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCm1ha2Vfc3BhZ2hldHRpKG1fb2RhX291dGNvbWVfZnVuZGluZykgJT4lIAogIG11dGF0ZShlc3RpbWF0ZV9fID0gZXhwKGVzdGltYXRlX18pKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZWZmZWN0MV9fLCB5ID0gZXN0aW1hdGVfXywgZ3JvdXAgPSBzYW1wbGVfXykpICsKICBnZW9tX2xpbmUoc2l6ZSA9IDAuMjUsIGNvbG9yID0gIiNGRjQxMzYiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDA6NSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBkb2xsYXIsIHRyYW5zID0gcHNldWRvX2xvZ190cmFucygpKSArCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpICsKICBsYWJzKHggPSAiQ291bnQgb2YgYmFycmllcnMgdG8gZnVuZGluZyIsCiAgICAgICB5ID0gIlByZWRpY3RlZCB0b3RhbCBPREEgaW4gZm9sbG93aW5nIHllYXIiKSArCiAgdGhlbWVfZG9ub3JzKCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCg==