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

source(here("lib", "graphics.R"))
source(here("lib", "misc_funs.R"))
color_scheme_set("viridisC")

labs_exp_logged <- function(brks) {TeX(paste0("e^{", as.character(log(brks))), "}")}
labs_exp <- function(brks) {TeX(paste0("e^{", as.character(brks)), "}")}

my_seed <- 1234
set.seed(my_seed)

options(mc.cores = parallel::detectCores(),  # Use all possible cores
        brms.backend = "rstan")

CHAINS <- 4
ITER <- 2000
WARMUP <- 1000
BAYES_SEED <- 1234

# Load data
df_country_aid <- readRDS(here("data", "derived_data", "df_country_aid.rds"))
df_country_aid_laws <- filter(df_country_aid, laws)

Weight models

  • Numerator is treatment + non-varying confounders
  • Denominator is 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)

Run weight models

# Numerator ---------------------------------------------------------------
# Formulas
# Treatment ~ lag treatment + non-varying confounders
formula_h1_num_total <- bf(barriers_total ~ barriers_total_lag1 + (1 | gwcode))
formula_h1_num_advocacy <- bf(advocacy ~ advocacy_lag1 + (1 | gwcode))
formula_h1_num_entry <- bf(entry ~ entry_lag1 + (1 | gwcode))
formula_h1_num_funding <- bf(funding ~ funding_lag1 + (1 | gwcode))

# Priors
prior_num <- c(set_prior("normal(0, 10)", class = "Intercept"),
               set_prior("normal(0, 2.5)", class = "b"),
               set_prior("cauchy(0, 1)", class = "sd"))


# Denominator -------------------------------------------------------------
# Formulas
# Treatment ~ lag treatment + lag outcome + varying confounders + non-varying confounders
formula_h1_denom_total <- 
  bf(barriers_total ~ barriers_total_lag1 + total_oda_log_lag1 +
       # Human rights and politics
       v2x_polyarchy + v2x_corr + v2x_rule + v2x_civlib + v2x_clphy + v2x_clpriv +
       # Economics and development
       gdpcap_log + un_trade_pct_gdp + v2peedueq + v2pehealth + e_peinfmor +
       # Conflict and disasters
       internal_conflict_past_5 + natural_dis_count +
       (1 | gwcode))

formula_h1_denom_advocacy <- 
  bf(advocacy ~ advocacy_lag1 + total_oda_log_lag1 +
       v2x_polyarchy + v2x_corr + v2x_rule + v2x_civlib + v2x_clphy + v2x_clpriv +
       gdpcap_log + un_trade_pct_gdp + v2peedueq + v2pehealth + e_peinfmor +
       internal_conflict_past_5 + natural_dis_count +
       (1 | gwcode))

formula_h1_denom_entry <- 
  bf(entry ~ entry_lag1 + total_oda_log_lag1 +
       v2x_polyarchy + v2x_corr + v2x_rule + v2x_civlib + v2x_clphy + v2x_clpriv +
       gdpcap_log + un_trade_pct_gdp + v2peedueq + v2pehealth + e_peinfmor +
       internal_conflict_past_5 + natural_dis_count +
       (1 | gwcode))

formula_h1_denom_funding <- 
  bf(funding ~ funding_lag1 + total_oda_log_lag1 +
       v2x_polyarchy + v2x_corr + v2x_rule + v2x_civlib + v2x_clphy + v2x_clpriv +
       gdpcap_log + un_trade_pct_gdp + v2peedueq + v2pehealth + e_peinfmor +
       internal_conflict_past_5 + natural_dis_count +
       (1 | gwcode))

# Priors
prior_denom <- c(set_prior("normal(0, 10)", class = "Intercept"),
                 set_prior("normal(0, 2.5)", class = "b"),
                 set_prior("normal(0, 2.5)", class = "sd"))


# Run weighting models ----------------------------------------------------
# All models get run inside a tibble using map() magic
all_models_h1 <- tribble(
  ~model_name, ~formula_num, ~formula_denom,
  "h1_total", formula_h1_num_total, formula_h1_denom_total,
  "h1_advocacy", formula_h1_num_advocacy, formula_h1_denom_advocacy,
  "h1_entry", formula_h1_num_entry, formula_h1_denom_entry,
  "h1_funding", formula_h1_num_funding, formula_h1_denom_funding
)

# Fit models
tic()
fit_h1_all_models <- all_models_h1 %>%
  mutate(fit_num = map2(formula_num, model_name, ~brm(
    .x,
    data = df_country_aid_laws,
    prior = prior_num,
    iter = ITER, chains = CHAINS, warmup = WARMUP, seed = BAYES_SEED,
    control = list(adapt_delta = 0.99),
    file = here("analysis", "model_cache", paste0(.y, "_num.rds"))
  ))) %>%
  mutate(fit_denom = map2(formula_denom, model_name, ~brm(
    .x,
    data = df_country_aid_laws,
    prior = prior_denom,
    iter = ITER, chains = CHAINS, warmup = WARMUP, seed = BAYES_SEED,
    control = list(adapt_delta = 0.9),
    file = here("analysis", "model_cache", paste0(.y, "_denom.rds"))
  ))) 
fit_h1_all_models
toc()

Check weight models

We check a few of the numerator and denominator models for convergence and mixing and fit.

Numerator

check_total_num <- fit_h1_all_models %>% 
  filter(model_name == "h1_total") %>% pull(fit_num) %>% first()

pp_check(check_total_num, type = "dens_overlay", nsamples = 10) +
  theme_donors()

check_total_num %>% 
  posterior_samples(add_chain = TRUE) %>% 
  select(-starts_with("r_gwcode"), -starts_with("z_"), -lp__, -iter) %>% 
  mcmc_trace() +
  theme_donors() +
  theme(legend.position = c(0.72, 0.38))

Denominator

check_total_denom <- fit_h1_all_models %>% 
  filter(model_name == "h1_total") %>% pull(fit_denom) %>% first()

pp_check(check_total_denom, type = "dens_overlay", nsamples = 10) +
  theme_donors()

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

Build weights

# This is the tidybayes way to calculate predictions and residuals but holy crap
# it's sloooow and memory intensive, so we use predict.brmsfit() instead
#
# predicted_num <- df_country_aid_laws %>%
#   add_predicted_draws(fit_num) %>%
#   mutate(.residual = barriers_total - .prediction)
# 
# predicted_num_per_row <- predicted_num %>%
#   group_by(.row) %>%
#   mean_hdi(.prediction, .residual)

tic()
fit_h1_preds <- fit_h1_all_models %>%
  mutate(pred_num = map(fit_num, ~predict(.x, newdata = df_country_aid_laws, allow_new_levels = TRUE)),
         resid_num = map(fit_num, ~residuals(.x, newdata = df_country_aid_laws, allow_new_levels = TRUE)),
         pred_denom = map(fit_denom, ~predict(.x, newdata = df_country_aid_laws, allow_new_levels = TRUE)),
         resid_denom = map(fit_denom, ~residuals(.x, newdata = df_country_aid_laws, allow_new_levels = TRUE)))
toc()
## 101.157 sec elapsed
fit_h1_ipw <- fit_h1_preds %>%
  mutate(num_actual = pmap(list(form = formula_num, pred = pred_num, resid = resid_num), 
                           calc_prob_dist),
         denom_actual = pmap(list(form = formula_denom, pred = pred_denom, resid = resid_denom), 
                          calc_prob_dist)) %>% 
  mutate(df_with_weights = map2(num_actual, denom_actual, ~{
    df_country_aid_laws %>% 
      mutate(weights_sans_time = .x / .y) %>% 
      group_by(gwcode) %>% 
      mutate(ipw = cumprod_na(weights_sans_time)) %>% 
      ungroup()
  }))
fit_h1_ipw
## # A tibble: 4 x 12
##   model_name formula_num formula_denom fit_num fit_denom pred_num resid_num pred_denom
##   <chr>      <list>      <list>        <list>  <list>    <list>   <list>    <list>    
## 1 h1_total   <brmsfrml>  <brmsfrml>    <brmsf… <brmsfit> <dbl[,4… <dbl[,4]… <dbl[,4] …
## 2 h1_advoca… <brmsfrml>  <brmsfrml>    <brmsf… <brmsfit> <dbl[,4… <dbl[,4]… <dbl[,4] …
## 3 h1_entry   <brmsfrml>  <brmsfrml>    <brmsf… <brmsfit> <dbl[,4… <dbl[,4]… <dbl[,4] …
## 4 h1_funding <brmsfrml>  <brmsfrml>    <brmsf… <brmsfit> <dbl[,4… <dbl[,4]… <dbl[,4] …
## # … with 4 more variables: resid_denom <list>, num_actual <list>, denom_actual <list>,
## #   df_with_weights <list>

Outcome models

Modeling choice

Total aid has a ton of zeroes, but the zeroes are really far away from the distribution of the actual data, so rather than be zero-inflated, this represents a hurdle process. Something determines whether a country/year receives any aid, and then something else determines how much.

If we don’t take this hurdling process into account in the model, our ATE will be wrong. We don’t really care about the exact hurdling process—we care most about the ATE of laws/restrictions on aid—but we still need to deal with the hurdle.

aid_hist_original <- ggplot(df_country_aid_laws, aes(x = total_oda)) +
  geom_histogram(binwidth = 2e9, color = "white", boundary = 0) +
  scale_x_continuous(labels = scales::dollar) +
  labs(x = "Total ODA", y = "Count", 
       title = "ODA") +
  theme_donors()

aid_hist_logged <- ggplot(df_country_aid_laws, aes(x = total_oda_log)) +
  geom_histogram(binwidth = 1, color = "white", boundary = 0) +
  labs(x = "Total ODA (logged)", y = "Count", 
       title = "Logged ODA") +
  theme_donors()

aid_hist_original + aid_hist_logged

So we 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. The hurdle_lognormal() family is already built in to brms which is nice. 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.

Fortunately the lognormal family works well here, since foreign aid follows an exponential distribution and we were using log aid originally. Now we don’t have to use log aid and can model the hurdle process at the same time without relying on my own rickety hurdle_gaussian() function.

For comparison, here’s a regular gaussian model using log ODA and sans hurdling.

# Extract the data with weights for the barriers_total model
aid_data_example_wts <- fit_h1_ipw %>% 
  filter(model_name == "h1_total") %>% 
  pull(df_with_weights) %>% first()

example_normal_fit <- brm(
  bf(total_oda_log_lead1 | weights(ipw) ~ barriers_total + (1 | gwcode)),
  data = aid_data_example_wts,
  family = gaussian(), 
  iter = ITER, chains = CHAINS, warmup = WARMUP, seed = BAYES_SEED,
  file = here("analysis", "model_cache", paste0("h1_example_normal.rds"))
)

example_hu_fit <- brm(
  bf(total_oda_lead1 | weights(ipw) ~ barriers_total + (1 | gwcode), 
     hu ~ 1),
  data = aid_data_example_wts,
  # Have to use rstan because cmdstanr weirdly uses negative inits
  family = hurdle_lognormal(), backend = "rstan",
  iter = ITER * 2, chains = CHAINS, warmup = WARMUP, seed = BAYES_SEED,
  file = here("analysis", "model_cache", paste0("h1_example_hurdle.rds"))
)

Even though we just used an intercept-only model for the hurdle process, incorporating it into the overall model gives us a much better fit. Look at these posterior predictive checks:

pp_check(example_normal_fit, type = "dens_overlay", nsamples = 10) + 
  coord_cartesian(xlim = c(0, 30)) +
  scale_x_continuous(labels = labs_exp) +
  labs(title = "log(y) ~ x, gaussian family, no hurdling") +
  theme_donors()

pp_check(example_hu_fit, type = "dens_overlay", nsamples = 10) + 
  scale_x_continuous(trans = "log1p", breaks = exp(seq(0, 30, 5)),
                     labels = labs_exp_logged) +
  labs(title = "y ~ x, lognormal family, hurdle: hu ~ 1") +
  theme_donors()

Importantly, the coefficients switch directions!

example_normal_fit %>% 
  gather_draws(b_barriers_total) %>%
  mutate(.variable = dplyr::recode(.variable, 
                                   b_barriers_total = "Additional law, t")) %>% 
  ggplot(aes(y = fct_rev(.variable), x = .value, fill = fct_rev(.variable))) +
  geom_vline(xintercept = 0) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8) +
  guides(fill = FALSE) +
  scale_x_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#FF851B", "#FFDC00")) +
  labs(y = NULL, x = "% change in outcome",
       title = "log(y) ~ x, gaussian family, no hurdling") +
  theme_donors()

example_hu_fit %>% 
  gather_draws(b_barriers_total) %>%
  mutate(.value = exp(.value) - 1) %>%
  mutate(.variable = dplyr::recode(.variable, 
                                   b_barriers_total = "Additional law, t - 1")) %>% 
  ggplot(aes(y = fct_rev(.variable), x = .value, fill = fct_rev(.variable))) +
  geom_vline(xintercept = 0) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8) +
  guides(fill = FALSE) +
  scale_x_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#FF851B", "#FFDC00")) +
  labs(y = NULL, x = "% change in outcome",
       title = "y ~ x, lognormal family; hurdle: hu ~ 1") +
  theme_donors()

We thus use a lognormal family when modeling the outcome. Because we’re limiting ourselves to just observations that receive aid, our ATE theoretically only shows the effect of treatment on actually having the outcome occur. We’re not trying to model the effect of treatment on the 0/1 logit process for receiving aid in the first place.

Interpreting lognormal models

Because the outcome is pre-logged, we have to interpret these results a little differently from standard OLS, but it’s not too bad, considering that a standard approach to exponential data like aid is to model the logged outcome. When the y is logged, coefficients represent percent changes in y. Models using the lognormal family follow the same principle.

tidy(example_hu_fit) %>%
  mutate(estimate_exp = exp(estimate)) %>% 
  filter(term == "barriers_total") %>% 
  select(term, estimate, estimate_exp)
## # A tibble: 1 x 3
##   term           estimate estimate_exp
##   <chr>             <dbl>        <dbl>
## 1 barriers_total   0.0906         1.09

In the lognormal model, the exponentiated coefficients represent percent changes for each unit increase in X. For instance, \(e^\beta_1\) here is 1.09488 Like exponentiated logistic regression coefficients, everything here is centered around 1, meaning that there’s a 9.49% increase 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 $54,744,184 (50,000,000 × 1.09488).

When using brms::fitted() on the model object, brms shows data on the original scale, but to see the intuition behind the percent change, we can calculate the percent change manually. Magically, they’re all around 0.097.

example_hu_fitted_values <- fitted(
  example_hu_fit, 
  newdata = data.frame(barriers_total = seq(0, 8, 1)), 
  re_formula = NA,
  robust = TRUE
)

example_hu_fitted_values %>% 
  as.data.frame() %>% 
  mutate(pct_change = (Estimate - lag(Estimate)) / lag(Estimate))
##     Estimate Est.Error      Q2.5      Q97.5 pct_change
## 1  551061422  73995903 423779255  716564588         NA
## 2  602738400  78980958 467126166  778530995 0.09377716
## 3  660078262  86582957 511314432  854613970 0.09513225
## 4  722358081  96356479 555703369  940877605 0.09435217
## 5  792042599 111060579 601787822 1045672373 0.09646811
## 6  867880647 130321945 647577188 1168121690 0.09574996
## 7  951517880 155182324 693186719 1304630056 0.09636951
## 8 1042581150 182769751 738857268 1465192715 0.09570316
## 9 1141398163 217284639 785081899 1648918248 0.09478112

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.

I’ve never seen any paper anywhere use hurdled outcome models with MSMs, but I think it legally works here.

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} \text{Aid}_{i,t} | u_i, \text{Law}_{i, t-1} &\sim \operatorname{LogNormal} (Z_{i, t}, \text{Aid}^\star_{i, t}) & \text{[likelihood]} \\ \operatorname{logit} (Z_{i, t}) &\sim \alpha_Z & \text{[intercept-only logit if } \text{Aid}_{i, t} = 0 \text{]} \\ \log (\text{Aid}^\star_{i, t}) &\sim \mathcal{N} (\beta_0 + \beta_1 \text{Law}_{i, t-1}, \sigma^2_\epsilon, u_i) \times \text{IPW}_{i, t-1} & \text{[if } \text{Aid}_{i, t} > 0 \text{]}\\ u_i &\sim \mathcal{N} (0, \sigma^2_u) & \text{[country-specific intercepts]} \\ \ \\ \alpha_Z &\sim \operatorname{Logistic}(-2, 0.6) & \text{[prior proportion of rows where Aid = 0]} \\ \beta_0 &\sim \mathcal{N} (0, 15) & \text{[prior population intercept]} \\ \beta_1 &\sim \mathcal{N} (0, 3) & \text{[prior population effects]} \\ \sigma^2_e, \sigma^2_u &\sim \operatorname{Cauchy}(0, 1) & \text{[prior sd for population and country]} \\ \ \\ \text{IPW}_{i, t-1} &= \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)} & \text{[stabilized weights]} \end{aligned} \]

Here’s what those look like:

z_p <- ggplot() +
  stat_function(fun = dlogis, args = list(location = -2, scale = 0.6),
                geom = "area", fill = "grey80", color = "black") +
  labs(x = TeX("\\textbf{Proportion where Aid = 0 (α_Z)}")) +
  annotate(geom = "label", x = -2, y = 0.07, label = "Logistic(-2, 0.6)", size = pts(9)) +
  xlim(-8, 3) +
  theme_donors(prior = TRUE)

b0_p <- ggplot() +
  stat_function(fun = dnorm, args = list(mean = 0, sd = 15),
                geom = "area", fill = "grey80", color = "black") +
  labs(x = TeX("\\textbf{Population intercept (β_0)}")) +
  annotate(geom = "label", x = 0, y = 0.0042, label = "N(0, 15)", size = pts(9)) +
  xlim(-50, 50) +
  theme_donors(prior = TRUE)

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

sigma_p <- ggplot() +
  stat_function(fun = dcauchy, args = list(location = 0, scale = 1),
                geom = "area", fill = "grey80", color = "black") +
  labs(x = TeX("\\textbf{Population and country SD (σ_e, σ_u)}")) +
  annotate(geom = "label", x = 5, y = 0.04, label = "Cauchy(0, 1)", size = pts(9)) +
  xlim(0, 10) +
  theme_donors(prior = TRUE)

(z_p + b0_p) / (b1_p | sigma_p)

The prior for the hurdle model is a little weird. For whatever reason, brms::get_prior() says that the prior for the hu parameter is beta(0, 1), but in practice, if you run brms::prior_summary() it shows that it actually uses a default of logistic(0, 1), and Stan yells at you if you use a beta prior. Ideally, we want a beta(2, 11) prior, but we can’t specify it like that—we have to translate it to a logistic distribution instead. There’s not an easy way to do this, so we used brms::logit_scaled to show the beta distribution on the logit scale, then we played with the location and scale parameters in rlogis() until it looked roughly equivalent.

hu_prior_sim <- tibble(beta = rbeta(10000, 2, 11)) %>% 
  mutate(beta_logit_scale = brms::logit_scaled(beta)) %>% 
  mutate(logit_betaish_prior = rlogis(10000, -2, 0.6)) %>% 
  mutate(prior_probs = plogis(logit_betaish_prior))

hu_prior_plot1 <- ggplot(hu_prior_sim) +
  geom_density(aes(x = beta), fill = "grey80", color = "black") +
  labs(x = "Proportion where Aid = 0",
       subtitle = "Original Beta(2, 11) distribution") +
  coord_cartesian(xlim = c(0, 1)) +
  theme_donors(prior = TRUE)

hu_prior_plot2 <- ggplot(hu_prior_sim) +
  geom_density(aes(x = beta_logit_scale), fill = "grey80", color = "black") +
  labs(x = "Logistic value where Aid = 0",
       subtitle = "Beta(2, 11) scaled with brms::logit_scaled") +
  coord_cartesian(xlim = c(-8, 1)) +
  theme_donors(prior = TRUE)

hu_prior_plot3 <- ggplot(hu_prior_sim) +
  geom_density(aes(x = logit_betaish_prior), fill = "grey80", color = "black") +
  labs(x = "Logistic value where Aid = 0",
       subtitle = "Estimated Logistic(-2, 0.6)") +
  coord_cartesian(xlim = c(-8, 1)) +
  theme_donors(prior = TRUE)

hu_prior_plot4 <- ggplot(hu_prior_sim) +
  geom_density(aes(x = prior_probs), fill = "grey80", color = "black") +
  labs(x = "Proportion where Aid = 0",
       subtitle = "Logistic(-2, 0.6) transformed to probabilities") +
  coord_cartesian(xlim = c(0, 1)) +
  theme_donors(prior = TRUE)

(hu_prior_plot1 + hu_prior_plot2) / (hu_prior_plot3 + hu_prior_plot4)

Run outcome models

Phew. With all that out of the way, we can finally run the outcome models.

# Outcome -----------------------------------------------------------------
# Formulas
# Treatment ~ lag treatment + non-varying confounders
formula_h1_out_total <- bf(total_oda_lead1 | weights(ipw) ~ 
                             barriers_total + (1 | gwcode),
                           hu ~ 1)
formula_h1_out_advocacy <- bf(total_oda_lead1 | weights(ipw) ~ 
                             advocacy + (1 | gwcode),
                           hu ~ 1)
formula_h1_out_entry <- bf(total_oda_lead1 | weights(ipw) ~ 
                             entry + (1 | gwcode),
                           hu ~ 1)
formula_h1_out_funding <- bf(total_oda_lead1 | weights(ipw) ~ 
                             funding + (1 | gwcode),
                           hu ~ 1)

# Priors
prior_out <- c(set_prior("normal(0, 20)", class = "Intercept"),
               set_prior("normal(0, 3)", class = "b"),
               set_prior("cauchy(0, 1)", class = "sd"),
               set_prior("logistic(-2, 0.6)", class = "Intercept", dpar = "hu"))

# Run outcome models ------------------------------------------------------
tic()
fit_h1_outcomes <- fit_h1_ipw %>%
  mutate(formula_outcome = 
           list(formula_h1_out_total, formula_h1_out_advocacy, 
                formula_h1_out_entry, formula_h1_out_funding)) %>% 
  mutate(fit_outcome = 
           pmap(list(formula_outcome, df_with_weights, model_name),
                ~brm(
                  ..1,
                  data = ..2,
                  prior = prior_out,
                  family = hurdle_lognormal(),
                  iter = ITER * 2, chains = CHAINS, warmup = WARMUP, seed = BAYES_SEED,
                  # Has to be rstan instead of cmdstanr bc it inexplicably
                  # creates all sorts of nonnegative initialization errors when
                  # using cmdstanr with lognormal() :(
                  backend = "rstan",
                  file = here("analysis", "model_cache", paste0(..3, "_outcome.rds"))
                )))
fit_h1_outcomes
toc()

Check outcome models

check_total_outcome <- fit_h1_outcomes %>% 
  filter(model_name == "h1_total") %>% pull(fit_outcome) %>% first()

pp_check(check_total_outcome, type = "dens_overlay", nsamples = 10) +
  scale_x_continuous(trans = "log1p", breaks = exp(seq(0, 20, 5)),
                     labels = labs_exp_logged) +
  theme_donors()

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

Results

# Plots!
plot_total <- fit_h1_outcomes %>% 
  filter(model_name == "h1_total") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  gather_draws(b_barriers_total) %>%
  mutate(.value = exp(.value) - 1) %>% 
  mutate(.variable = dplyr::recode(.variable, 
                                   b_barriers_total = "Additional law, t - 1")) %>% 
  ggplot(aes(y = fct_rev(.variable), x = .value, fill = fct_rev(.variable))) +
  geom_vline(xintercept = 0) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8) +
  guides(fill = FALSE) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_fill_manual(values = c("#FF851B", "#FFDC00")) +
  labs(y = NULL, x = NULL) +
  theme_donors()

plot_advocacy <- fit_h1_outcomes %>% 
  filter(model_name == "h1_advocacy") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  gather_draws(b_advocacy) %>% 
  mutate(.variable = dplyr::recode(.variable, 
                                   b_advocacy = "Additional advocacy law, t - 1")) %>% 
  mutate(.value = exp(.value) - 1) %>% 
  ggplot(aes(y = fct_rev(.variable), x = .value, fill = fct_rev(.variable))) +
  geom_vline(xintercept = 0) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8) +
  guides(fill = FALSE) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_fill_manual(values = c("#85144b", "#F012BE")) +
  labs(y = NULL, x = NULL) +
  theme_donors()

plot_entry <- fit_h1_outcomes %>% 
  filter(model_name == "h1_entry") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  gather_draws(b_entry) %>% 
  mutate(.variable = dplyr::recode(.variable, 
                                   b_entry = "Additional entry law, t - 1")) %>% 
  mutate(.value = exp(.value) - 1) %>% 
  ggplot(aes(y = fct_rev(.variable), x = .value, fill = fct_rev(.variable))) +
  geom_vline(xintercept = 0) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8) +
  guides(fill = FALSE) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_fill_manual(values = c("#3D9970", "#2ECC40")) +
  labs(y = NULL, x = "% change in ODA") +
  theme_donors()

plot_funding <- fit_h1_outcomes %>% 
  filter(model_name == "h1_funding") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  gather_draws(b_funding) %>% 
  mutate(.variable = dplyr::recode(.variable, 
                                   b_funding = "Additional funding law, t - 1")) %>% 
  mutate(.value = exp(.value) - 1) %>% 
  ggplot(aes(y = fct_rev(.variable), x = .value, fill = fct_rev(.variable))) +
  geom_vline(xintercept = 0) +
  stat_halfeye(.width = c(0.8, 0.95), alpha = 0.8) +
  guides(fill = FALSE) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_fill_manual(values = c("#001f3f", "#0074D9")) +
  labs(y = NULL, x = "% change in ODA") +
  theme_donors()

(plot_total + plot_advocacy) / (plot_entry + plot_funding)

fit_h1_outcomes %>% 
  filter(model_name == "h1_total") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  conditional_effects()

fit_h1_outcomes %>% 
  filter(model_name == "h1_advocacy") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  conditional_effects()

fit_h1_outcomes %>% 
  filter(model_name == "h1_entry") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  conditional_effects()

fit_h1_outcomes %>% 
  filter(model_name == "h1_funding") %>% 
  pull(fit_outcome) %>% nth(1) %>% 
  conditional_effects()

LS0tCnRpdGxlOiAiSH4xfjogRWZmZWN0IG9mIGFudGktTkdPIGNyYWNrZG93biBvbiB0b3RhbCBPREEiCmF1dGhvcjogIlN1cGFybmEgQ2hhdWRocnkgYW5kIEFuZHJldyBIZWlzcyIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUYnKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZm9sZGluZzogc2hvdwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5yZXRpbmEgPSAzLAogICAgICAgICAgICAgICAgICAgICAgdGlkeS5vcHRzID0gbGlzdCh3aWR0aC5jdXRvZmYgPSAxMjApLCAgIyBGb3IgY29kZQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyh3aWR0aCA9IDkwKSwgICMgRm9yIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFzcCA9IDAuNjE4LCBmaWcud2lkdGggPSA3LCAKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAiODUlIikKCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKQpgYGAKCmBgYHtyIGxvYWQtbGlicmFyaWVzLWRhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGJybXMpCmxpYnJhcnkodGlkeWJheWVzKQpsaWJyYXJ5KGJheWVzcGxvdCkKbGlicmFyeShmaXhlc3QpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkobW9kZWxzdW1tYXJ5KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeSh0aWN0b2MpCmxpYnJhcnkobGF0ZXgyZXhwKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShoZXJlKQoKc291cmNlKGhlcmUoImxpYiIsICJncmFwaGljcy5SIikpCnNvdXJjZShoZXJlKCJsaWIiLCAibWlzY19mdW5zLlIiKSkKY29sb3Jfc2NoZW1lX3NldCgidmlyaWRpc0MiKQoKbGFic19leHBfbG9nZ2VkIDwtIGZ1bmN0aW9uKGJya3MpIHtUZVgocGFzdGUwKCJlXnsiLCBhcy5jaGFyYWN0ZXIobG9nKGJya3MpKSksICJ9Iil9CmxhYnNfZXhwIDwtIGZ1bmN0aW9uKGJya3MpIHtUZVgocGFzdGUwKCJlXnsiLCBhcy5jaGFyYWN0ZXIoYnJrcykpLCAifSIpfQoKbXlfc2VlZCA8LSAxMjM0CnNldC5zZWVkKG15X3NlZWQpCgpvcHRpb25zKG1jLmNvcmVzID0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCksICAjIFVzZSBhbGwgcG9zc2libGUgY29yZXMKICAgICAgICBicm1zLmJhY2tlbmQgPSAicnN0YW4iKQoKQ0hBSU5TIDwtIDQKSVRFUiA8LSAyMDAwCldBUk1VUCA8LSAxMDAwCkJBWUVTX1NFRUQgPC0gMTIzNAoKIyBMb2FkIGRhdGEKZGZfY291bnRyeV9haWQgPC0gcmVhZFJEUyhoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJkZl9jb3VudHJ5X2FpZC5yZHMiKSkKZGZfY291bnRyeV9haWRfbGF3cyA8LSBmaWx0ZXIoZGZfY291bnRyeV9haWQsIGxhd3MpCmBgYAoKIyMgV2VpZ2h0IG1vZGVscwoKLSBOdW1lcmF0b3IgaXMgdHJlYXRtZW50ICsgbm9uLXZhcnlpbmcgY29uZm91bmRlcnMKLSBEZW5vbWluYXRvciBpcyB0cmVhdG1lbnQgKyBsYWdnZWQgb3V0Y29tZSArIHRpbWUtdmFyeWluZyBjb25mb3VuZGVycyArIG5vbi12YXJ5aW5nIGNvbmZvdW5kZXJzCgokJApzdyA9IFxwcm9kXnRfe3QgPSAxfSBcZnJhY3tccGhpKFRfe2l0fSB8IFRfe2ksIHQtMX0sIENfaSl9e1xwaGkoVF97aXR9IHwgVF97aSwgdC0xfSwgRF97aSwgdC0xfSwgQ19pKX0KJCQKCiMjIyBQcmlvcnMgZm9yIHdlaWdodCBtb2RlbHMKCldlIHVzZSBbZ2VuZXJpYyB3ZWFrbHkgaW5mb3JtYXRpdmUgcHJpb3JzXSgpIGZvciBvdXIgbW9kZWwgcGFyYW1ldGVyczoKCi0gSW50ZXJjZXB0OiAkXG1hdGhjYWx7Tn0gKDAsIDEwKSQKLSBDb2VmZmljaWVudHM6ICRcbWF0aGNhbHtOfSAoMCwgMi41KSQKLSBTaWdtYTogJFxvcGVyYXRvcm5hbWV7Q2F1Y2h5fSAoMCwgMSkkCgpgYGB7ciBwbG90LXdlaWdodC1wcmlvcnMsIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTYsIGZpZy5hc3A9TlVMTH0KcHJpX2ludCA8LSBnZ3Bsb3QoKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IDAsIHNkID0gMTApLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSBUZVgoIlxcdGV4dGJme0ludGVyY2VwdCAozrJfMCl9IikpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDAsIHkgPSAwLjAxLCBsYWJlbCA9ICJOKDAsIDEwKSIsIHNpemUgPSBwdHMoOSkpICsKICB4bGltKC00MCwgNDApICsKICB0aGVtZV9kb25vcnMocHJpb3IgPSBUUlVFKQoKcHJpX2NvZWYgPC0gZ2dwbG90KCkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sIGFyZ3MgPSBsaXN0KG1lYW4gPSAwLCBzZCA9IDIuNSksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoeCA9IFRlWCgiXFx0ZXh0YmZ7Q29lZmZpY2llbnRzICjOsl94KX0iKSkgKwogIGFubm90YXRlKGdlb20gPSAibGFiZWwiLCB4ID0gMCwgeSA9IDAuMDQsIGxhYmVsID0gIk4oMCwgMykiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgtMTAsIDEwKSArCiAgdGhlbWVfZG9ub3JzKHByaW9yID0gVFJVRSkKCnByaV9zaWdtYSA8LSBnZ3Bsb3QoKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkY2F1Y2h5LCBhcmdzID0gbGlzdChsb2NhdGlvbiA9IDAsIHNjYWxlID0gMSksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoeCA9ICLPgyIpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IDUsIHkgPSAwLjA4LCBsYWJlbCA9ICJDYXVjaHkoMCwgMSkiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgwLCAxMCkgKwogIHRoZW1lX2Rvbm9ycyhwcmlvciA9IFRSVUUpCgoocHJpX2ludCArIHByaV9jb2VmICsgcHJpX3NpZ21hKQpgYGAKCiMjIyBSdW4gd2VpZ2h0IG1vZGVscwoKYGBge3IgaDEtd2VpZ2h0LW1vZGVscywgcmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0V9CiMgTnVtZXJhdG9yIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEZvcm11bGFzCiMgVHJlYXRtZW50IH4gbGFnIHRyZWF0bWVudCArIG5vbi12YXJ5aW5nIGNvbmZvdW5kZXJzCmZvcm11bGFfaDFfbnVtX3RvdGFsIDwtIGJmKGJhcnJpZXJzX3RvdGFsIH4gYmFycmllcnNfdG90YWxfbGFnMSArICgxIHwgZ3djb2RlKSkKZm9ybXVsYV9oMV9udW1fYWR2b2NhY3kgPC0gYmYoYWR2b2NhY3kgfiBhZHZvY2FjeV9sYWcxICsgKDEgfCBnd2NvZGUpKQpmb3JtdWxhX2gxX251bV9lbnRyeSA8LSBiZihlbnRyeSB+IGVudHJ5X2xhZzEgKyAoMSB8IGd3Y29kZSkpCmZvcm11bGFfaDFfbnVtX2Z1bmRpbmcgPC0gYmYoZnVuZGluZyB+IGZ1bmRpbmdfbGFnMSArICgxIHwgZ3djb2RlKSkKCiMgUHJpb3JzCnByaW9yX251bSA8LSBjKHNldF9wcmlvcigibm9ybWFsKDAsIDEwKSIsIGNsYXNzID0gIkludGVyY2VwdCIpLAogICAgICAgICAgICAgICBzZXRfcHJpb3IoIm5vcm1hbCgwLCAyLjUpIiwgY2xhc3MgPSAiYiIpLAogICAgICAgICAgICAgICBzZXRfcHJpb3IoImNhdWNoeSgwLCAxKSIsIGNsYXNzID0gInNkIikpCgoKIyBEZW5vbWluYXRvciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgRm9ybXVsYXMKIyBUcmVhdG1lbnQgfiBsYWcgdHJlYXRtZW50ICsgbGFnIG91dGNvbWUgKyB2YXJ5aW5nIGNvbmZvdW5kZXJzICsgbm9uLXZhcnlpbmcgY29uZm91bmRlcnMKZm9ybXVsYV9oMV9kZW5vbV90b3RhbCA8LSAKICBiZihiYXJyaWVyc190b3RhbCB+IGJhcnJpZXJzX3RvdGFsX2xhZzEgKyB0b3RhbF9vZGFfbG9nX2xhZzEgKwogICAgICAgIyBIdW1hbiByaWdodHMgYW5kIHBvbGl0aWNzCiAgICAgICB2MnhfcG9seWFyY2h5ICsgdjJ4X2NvcnIgKyB2MnhfcnVsZSArIHYyeF9jaXZsaWIgKyB2MnhfY2xwaHkgKyB2MnhfY2xwcml2ICsKICAgICAgICMgRWNvbm9taWNzIGFuZCBkZXZlbG9wbWVudAogICAgICAgZ2RwY2FwX2xvZyArIHVuX3RyYWRlX3BjdF9nZHAgKyB2MnBlZWR1ZXEgKyB2MnBlaGVhbHRoICsgZV9wZWluZm1vciArCiAgICAgICAjIENvbmZsaWN0IGFuZCBkaXNhc3RlcnMKICAgICAgIGludGVybmFsX2NvbmZsaWN0X3Bhc3RfNSArIG5hdHVyYWxfZGlzX2NvdW50ICsKICAgICAgICgxIHwgZ3djb2RlKSkKCmZvcm11bGFfaDFfZGVub21fYWR2b2NhY3kgPC0gCiAgYmYoYWR2b2NhY3kgfiBhZHZvY2FjeV9sYWcxICsgdG90YWxfb2RhX2xvZ19sYWcxICsKICAgICAgIHYyeF9wb2x5YXJjaHkgKyB2MnhfY29yciArIHYyeF9ydWxlICsgdjJ4X2NpdmxpYiArIHYyeF9jbHBoeSArIHYyeF9jbHByaXYgKwogICAgICAgZ2RwY2FwX2xvZyArIHVuX3RyYWRlX3BjdF9nZHAgKyB2MnBlZWR1ZXEgKyB2MnBlaGVhbHRoICsgZV9wZWluZm1vciArCiAgICAgICBpbnRlcm5hbF9jb25mbGljdF9wYXN0XzUgKyBuYXR1cmFsX2Rpc19jb3VudCArCiAgICAgICAoMSB8IGd3Y29kZSkpCgpmb3JtdWxhX2gxX2Rlbm9tX2VudHJ5IDwtIAogIGJmKGVudHJ5IH4gZW50cnlfbGFnMSArIHRvdGFsX29kYV9sb2dfbGFnMSArCiAgICAgICB2MnhfcG9seWFyY2h5ICsgdjJ4X2NvcnIgKyB2MnhfcnVsZSArIHYyeF9jaXZsaWIgKyB2MnhfY2xwaHkgKyB2MnhfY2xwcml2ICsKICAgICAgIGdkcGNhcF9sb2cgKyB1bl90cmFkZV9wY3RfZ2RwICsgdjJwZWVkdWVxICsgdjJwZWhlYWx0aCArIGVfcGVpbmZtb3IgKwogICAgICAgaW50ZXJuYWxfY29uZmxpY3RfcGFzdF81ICsgbmF0dXJhbF9kaXNfY291bnQgKwogICAgICAgKDEgfCBnd2NvZGUpKQoKZm9ybXVsYV9oMV9kZW5vbV9mdW5kaW5nIDwtIAogIGJmKGZ1bmRpbmcgfiBmdW5kaW5nX2xhZzEgKyB0b3RhbF9vZGFfbG9nX2xhZzEgKwogICAgICAgdjJ4X3BvbHlhcmNoeSArIHYyeF9jb3JyICsgdjJ4X3J1bGUgKyB2MnhfY2l2bGliICsgdjJ4X2NscGh5ICsgdjJ4X2NscHJpdiArCiAgICAgICBnZHBjYXBfbG9nICsgdW5fdHJhZGVfcGN0X2dkcCArIHYycGVlZHVlcSArIHYycGVoZWFsdGggKyBlX3BlaW5mbW9yICsKICAgICAgIGludGVybmFsX2NvbmZsaWN0X3Bhc3RfNSArIG5hdHVyYWxfZGlzX2NvdW50ICsKICAgICAgICgxIHwgZ3djb2RlKSkKCiMgUHJpb3JzCnByaW9yX2Rlbm9tIDwtIGMoc2V0X3ByaW9yKCJub3JtYWwoMCwgMTApIiwgY2xhc3MgPSAiSW50ZXJjZXB0IiksCiAgICAgICAgICAgICAgICAgc2V0X3ByaW9yKCJub3JtYWwoMCwgMi41KSIsIGNsYXNzID0gImIiKSwKICAgICAgICAgICAgICAgICBzZXRfcHJpb3IoIm5vcm1hbCgwLCAyLjUpIiwgY2xhc3MgPSAic2QiKSkKCgojIFJ1biB3ZWlnaHRpbmcgbW9kZWxzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBBbGwgbW9kZWxzIGdldCBydW4gaW5zaWRlIGEgdGliYmxlIHVzaW5nIG1hcCgpIG1hZ2ljCmFsbF9tb2RlbHNfaDEgPC0gdHJpYmJsZSgKICB+bW9kZWxfbmFtZSwgfmZvcm11bGFfbnVtLCB+Zm9ybXVsYV9kZW5vbSwKICAiaDFfdG90YWwiLCBmb3JtdWxhX2gxX251bV90b3RhbCwgZm9ybXVsYV9oMV9kZW5vbV90b3RhbCwKICAiaDFfYWR2b2NhY3kiLCBmb3JtdWxhX2gxX251bV9hZHZvY2FjeSwgZm9ybXVsYV9oMV9kZW5vbV9hZHZvY2FjeSwKICAiaDFfZW50cnkiLCBmb3JtdWxhX2gxX251bV9lbnRyeSwgZm9ybXVsYV9oMV9kZW5vbV9lbnRyeSwKICAiaDFfZnVuZGluZyIsIGZvcm11bGFfaDFfbnVtX2Z1bmRpbmcsIGZvcm11bGFfaDFfZGVub21fZnVuZGluZwopCgojIEZpdCBtb2RlbHMKdGljKCkKZml0X2gxX2FsbF9tb2RlbHMgPC0gYWxsX21vZGVsc19oMSAlPiUKICBtdXRhdGUoZml0X251bSA9IG1hcDIoZm9ybXVsYV9udW0sIG1vZGVsX25hbWUsIH5icm0oCiAgICAueCwKICAgIGRhdGEgPSBkZl9jb3VudHJ5X2FpZF9sYXdzLAogICAgcHJpb3IgPSBwcmlvcl9udW0sCiAgICBpdGVyID0gSVRFUiwgY2hhaW5zID0gQ0hBSU5TLCB3YXJtdXAgPSBXQVJNVVAsIHNlZWQgPSBCQVlFU19TRUVELAogICAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGEgPSAwLjk5KSwKICAgIGZpbGUgPSBoZXJlKCJhbmFseXNpcyIsICJtb2RlbF9jYWNoZSIsIHBhc3RlMCgueSwgIl9udW0ucmRzIikpCiAgKSkpICU+JQogIG11dGF0ZShmaXRfZGVub20gPSBtYXAyKGZvcm11bGFfZGVub20sIG1vZGVsX25hbWUsIH5icm0oCiAgICAueCwKICAgIGRhdGEgPSBkZl9jb3VudHJ5X2FpZF9sYXdzLAogICAgcHJpb3IgPSBwcmlvcl9kZW5vbSwKICAgIGl0ZXIgPSBJVEVSLCBjaGFpbnMgPSBDSEFJTlMsIHdhcm11cCA9IFdBUk1VUCwgc2VlZCA9IEJBWUVTX1NFRUQsCiAgICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOSksCiAgICBmaWxlID0gaGVyZSgiYW5hbHlzaXMiLCAibW9kZWxfY2FjaGUiLCBwYXN0ZTAoLnksICJfZGVub20ucmRzIikpCiAgKSkpIApmaXRfaDFfYWxsX21vZGVscwp0b2MoKQpgYGAKCiMjIyBDaGVjayB3ZWlnaHQgbW9kZWxzCgpXZSBjaGVjayBhIGZldyBvZiB0aGUgbnVtZXJhdG9yIGFuZCBkZW5vbWluYXRvciBtb2RlbHMgZm9yIGNvbnZlcmdlbmNlIGFuZCBtaXhpbmcgYW5kIGZpdC4KCiMjIyMgTnVtZXJhdG9yCgpgYGB7ciBoMS1jaGVjay1udW1lcmF0b3J9CmNoZWNrX3RvdGFsX251bSA8LSBmaXRfaDFfYWxsX21vZGVscyAlPiUgCiAgZmlsdGVyKG1vZGVsX25hbWUgPT0gImgxX3RvdGFsIikgJT4lIHB1bGwoZml0X251bSkgJT4lIGZpcnN0KCkKCnBwX2NoZWNrKGNoZWNrX3RvdGFsX251bSwgdHlwZSA9ICJkZW5zX292ZXJsYXkiLCBuc2FtcGxlcyA9IDEwKSArCiAgdGhlbWVfZG9ub3JzKCkKCmNoZWNrX3RvdGFsX251bSAlPiUgCiAgcG9zdGVyaW9yX3NhbXBsZXMoYWRkX2NoYWluID0gVFJVRSkgJT4lIAogIHNlbGVjdCgtc3RhcnRzX3dpdGgoInJfZ3djb2RlIiksIC1zdGFydHNfd2l0aCgiel8iKSwgLWxwX18sIC1pdGVyKSAlPiUgCiAgbWNtY190cmFjZSgpICsKICB0aGVtZV9kb25vcnMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjcyLCAwLjM4KSkKYGBgCgojIyMjIERlbm9taW5hdG9yCgpgYGB7ciBoMS1jaGVjay1kZW5vbWluYXRvcn0KY2hlY2tfdG90YWxfZGVub20gPC0gZml0X2gxX2FsbF9tb2RlbHMgJT4lIAogIGZpbHRlcihtb2RlbF9uYW1lID09ICJoMV90b3RhbCIpICU+JSBwdWxsKGZpdF9kZW5vbSkgJT4lIGZpcnN0KCkKCnBwX2NoZWNrKGNoZWNrX3RvdGFsX2Rlbm9tLCB0eXBlID0gImRlbnNfb3ZlcmxheSIsIG5zYW1wbGVzID0gMTApICsKICB0aGVtZV9kb25vcnMoKQoKY2hlY2tfdG90YWxfZGVub20gJT4lIAogIHBvc3Rlcmlvcl9zYW1wbGVzKGFkZF9jaGFpbiA9IFRSVUUpICU+JSAKICBzZWxlY3QoLXN0YXJ0c193aXRoKCJyX2d3Y29kZSIpLCAtc3RhcnRzX3dpdGgoInpfIiksIC1scF9fLCAtaXRlcikgJT4lIAogIG1jbWNfdHJhY2UoKSArCiAgdGhlbWVfZG9ub3JzKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCmBgYAoKIyMgQnVpbGQgd2VpZ2h0cwoKYGBge3IgaDEtYnVpbGQtd2VpZ2h0cywgY2FjaGU9VFJVRX0KIyBUaGlzIGlzIHRoZSB0aWR5YmF5ZXMgd2F5IHRvIGNhbGN1bGF0ZSBwcmVkaWN0aW9ucyBhbmQgcmVzaWR1YWxzIGJ1dCBob2x5IGNyYXAKIyBpdCdzIHNsb29vb3cgYW5kIG1lbW9yeSBpbnRlbnNpdmUsIHNvIHdlIHVzZSBwcmVkaWN0LmJybXNmaXQoKSBpbnN0ZWFkCiMKIyBwcmVkaWN0ZWRfbnVtIDwtIGRmX2NvdW50cnlfYWlkX2xhd3MgJT4lCiMgICBhZGRfcHJlZGljdGVkX2RyYXdzKGZpdF9udW0pICU+JQojICAgbXV0YXRlKC5yZXNpZHVhbCA9IGJhcnJpZXJzX3RvdGFsIC0gLnByZWRpY3Rpb24pCiMgCiMgcHJlZGljdGVkX251bV9wZXJfcm93IDwtIHByZWRpY3RlZF9udW0gJT4lCiMgICBncm91cF9ieSgucm93KSAlPiUKIyAgIG1lYW5faGRpKC5wcmVkaWN0aW9uLCAucmVzaWR1YWwpCgp0aWMoKQpmaXRfaDFfcHJlZHMgPC0gZml0X2gxX2FsbF9tb2RlbHMgJT4lCiAgbXV0YXRlKHByZWRfbnVtID0gbWFwKGZpdF9udW0sIH5wcmVkaWN0KC54LCBuZXdkYXRhID0gZGZfY291bnRyeV9haWRfbGF3cywgYWxsb3dfbmV3X2xldmVscyA9IFRSVUUpKSwKICAgICAgICAgcmVzaWRfbnVtID0gbWFwKGZpdF9udW0sIH5yZXNpZHVhbHMoLngsIG5ld2RhdGEgPSBkZl9jb3VudHJ5X2FpZF9sYXdzLCBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRSkpLAogICAgICAgICBwcmVkX2Rlbm9tID0gbWFwKGZpdF9kZW5vbSwgfnByZWRpY3QoLngsIG5ld2RhdGEgPSBkZl9jb3VudHJ5X2FpZF9sYXdzLCBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRSkpLAogICAgICAgICByZXNpZF9kZW5vbSA9IG1hcChmaXRfZGVub20sIH5yZXNpZHVhbHMoLngsIG5ld2RhdGEgPSBkZl9jb3VudHJ5X2FpZF9sYXdzLCBhbGxvd19uZXdfbGV2ZWxzID0gVFJVRSkpKQp0b2MoKQoKZml0X2gxX2lwdyA8LSBmaXRfaDFfcHJlZHMgJT4lCiAgbXV0YXRlKG51bV9hY3R1YWwgPSBwbWFwKGxpc3QoZm9ybSA9IGZvcm11bGFfbnVtLCBwcmVkID0gcHJlZF9udW0sIHJlc2lkID0gcmVzaWRfbnVtKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGNfcHJvYl9kaXN0KSwKICAgICAgICAgZGVub21fYWN0dWFsID0gcG1hcChsaXN0KGZvcm0gPSBmb3JtdWxhX2Rlbm9tLCBwcmVkID0gcHJlZF9kZW5vbSwgcmVzaWQgPSByZXNpZF9kZW5vbSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNhbGNfcHJvYl9kaXN0KSkgJT4lIAogIG11dGF0ZShkZl93aXRoX3dlaWdodHMgPSBtYXAyKG51bV9hY3R1YWwsIGRlbm9tX2FjdHVhbCwgfnsKICAgIGRmX2NvdW50cnlfYWlkX2xhd3MgJT4lIAogICAgICBtdXRhdGUod2VpZ2h0c19zYW5zX3RpbWUgPSAueCAvIC55KSAlPiUgCiAgICAgIGdyb3VwX2J5KGd3Y29kZSkgJT4lIAogICAgICBtdXRhdGUoaXB3ID0gY3VtcHJvZF9uYSh3ZWlnaHRzX3NhbnNfdGltZSkpICU+JSAKICAgICAgdW5ncm91cCgpCiAgfSkpCmZpdF9oMV9pcHcKYGBgCgojIyBPdXRjb21lIG1vZGVscwoKIyMjIE1vZGVsaW5nIGNob2ljZQoKVG90YWwgYWlkIGhhcyBhIHRvbiBvZiB6ZXJvZXMsIGJ1dCB0aGUgemVyb2VzIGFyZSByZWFsbHkgZmFyIGF3YXkgZnJvbSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBhY3R1YWwgZGF0YSwgc28gcmF0aGVyIHRoYW4gYmUgemVyby1pbmZsYXRlZCwgdGhpcyByZXByZXNlbnRzIGEgaHVyZGxlIHByb2Nlc3MuIFNvbWV0aGluZyBkZXRlcm1pbmVzIHdoZXRoZXIgYSBjb3VudHJ5L3llYXIgcmVjZWl2ZXMgYW55IGFpZCwgYW5kIHRoZW4gc29tZXRoaW5nIGVsc2UgZGV0ZXJtaW5lcyBob3cgbXVjaC4KCklmIHdlIGRvbid0IHRha2UgdGhpcyBodXJkbGluZyBwcm9jZXNzIGludG8gYWNjb3VudCBpbiB0aGUgbW9kZWwsIG91ciBBVEUgd2lsbCBiZSB3cm9uZy4gV2UgZG9uJ3QgcmVhbGx5IGNhcmUgYWJvdXQgdGhlIGV4YWN0IGh1cmRsaW5nIHByb2Nlc3PigJR3ZSBjYXJlIG1vc3QgYWJvdXQgdGhlIEFURSBvZiBsYXdzL3Jlc3RyaWN0aW9ucyBvbiBhaWTigJRidXQgd2Ugc3RpbGwgbmVlZCB0byBkZWFsIHdpdGggdGhlIGh1cmRsZS4KCmBgYHtyIHNob3ctb3V0Y29tZS1kaXN0fQphaWRfaGlzdF9vcmlnaW5hbCA8LSBnZ3Bsb3QoZGZfY291bnRyeV9haWRfbGF3cywgYWVzKHggPSB0b3RhbF9vZGEpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAyZTksIGNvbG9yID0gIndoaXRlIiwgYm91bmRhcnkgPSAwKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSArCiAgbGFicyh4ID0gIlRvdGFsIE9EQSIsIHkgPSAiQ291bnQiLCAKICAgICAgIHRpdGxlID0gIk9EQSIpICsKICB0aGVtZV9kb25vcnMoKQoKYWlkX2hpc3RfbG9nZ2VkIDwtIGdncGxvdChkZl9jb3VudHJ5X2FpZF9sYXdzLCBhZXMoeCA9IHRvdGFsX29kYV9sb2cpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBjb2xvciA9ICJ3aGl0ZSIsIGJvdW5kYXJ5ID0gMCkgKwogIGxhYnMoeCA9ICJUb3RhbCBPREEgKGxvZ2dlZCkiLCB5ID0gIkNvdW50IiwgCiAgICAgICB0aXRsZSA9ICJMb2dnZWQgT0RBIikgKwogIHRoZW1lX2Rvbm9ycygpCgphaWRfaGlzdF9vcmlnaW5hbCArIGFpZF9oaXN0X2xvZ2dlZApgYGAKClNvIHdlIGZpdCBhIGh1cmRsZWQgbG9nbm9ybWFsIG1vZGVsLCB3aGljaCB1c2VzIGEgbG9naXQgbW9kZWwgdG8gcHJlZGljdCAwL25vdCAwLCB0aGVuIHVzZXMgYSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uIHRvIG1vZGVsIHRoZSByZXN0IG9mIHRoZSBkYXRhLiBUaGUgYGh1cmRsZV9sb2dub3JtYWwoKWAgZmFtaWx5IGlzIGFscmVhZHkgYnVpbHQgaW4gdG8gKipicm1zKiogd2hpY2ggaXMgbmljZS4gSXQncyBwb3NzaWJsZSB0byBjcmVhdGUgY3VzdG9tIGZhbWlsaWVzIGxpa2UgYGh1cmRsZV9nYXVzc2lhbigpYCwgYnV0IHRoaXMgaXMgc3VwZXIgaGFyZCB0byBkby4gSSBoYXZlIFthbiBpbXBsZW1lbnRhdGlvbiBwYXJ0aWFsbHkgY29tcGxldGVkIGhlcmVdKGh0dHBzOi8vZGlzY291cnNlLm1jLXN0YW4ub3JnL3QvY3VzdG9tLWdhdXNzaWFuLWh1cmRsZS1mYW1pbHktbm90LXF1aXRlLXdvcmtpbmctaW4tYnJtcy8yMTAyOC8yKSwgYnV0IEkgY2FuJ3QgZ2V0IGl0IHRvIGFjdHVhbGx5IGNyZWF0ZSBwb3N0ZXJpb3IgcHJlZGljdGlvbnMuIFVnaC4KCkZvcnR1bmF0ZWx5IHRoZSBsb2dub3JtYWwgZmFtaWx5IHdvcmtzIHdlbGwgaGVyZSwgc2luY2UgZm9yZWlnbiBhaWQgZm9sbG93cyBhbiBleHBvbmVudGlhbCBkaXN0cmlidXRpb24gYW5kIHdlIHdlcmUgdXNpbmcgbG9nIGFpZCBvcmlnaW5hbGx5LiBOb3cgd2UgZG9uJ3QgaGF2ZSB0byB1c2UgbG9nIGFpZCBhbmQgY2FuIG1vZGVsIHRoZSBodXJkbGUgcHJvY2VzcyBhdCB0aGUgc2FtZSB0aW1lIHdpdGhvdXQgcmVseWluZyBvbiBteSBvd24gcmlja2V0eSBgaHVyZGxlX2dhdXNzaWFuKClgIGZ1bmN0aW9uLgoKRm9yIGNvbXBhcmlzb24sIGhlcmUncyBhIHJlZ3VsYXIgZ2F1c3NpYW4gbW9kZWwgdXNpbmcgbG9nIE9EQSBhbmQgc2FucyBodXJkbGluZy4KCmBgYHtyIGNvbXBhcmUtaHVyZGxlLW5vdC1odXJkbGUsIHJlc3VsdHM9ImhpZGUiLCBtZXNzYWdlPUZBTFNFfQojIEV4dHJhY3QgdGhlIGRhdGEgd2l0aCB3ZWlnaHRzIGZvciB0aGUgYmFycmllcnNfdG90YWwgbW9kZWwKYWlkX2RhdGFfZXhhbXBsZV93dHMgPC0gZml0X2gxX2lwdyAlPiUgCiAgZmlsdGVyKG1vZGVsX25hbWUgPT0gImgxX3RvdGFsIikgJT4lIAogIHB1bGwoZGZfd2l0aF93ZWlnaHRzKSAlPiUgZmlyc3QoKQoKZXhhbXBsZV9ub3JtYWxfZml0IDwtIGJybSgKICBiZih0b3RhbF9vZGFfbG9nX2xlYWQxIHwgd2VpZ2h0cyhpcHcpIH4gYmFycmllcnNfdG90YWwgKyAoMSB8IGd3Y29kZSkpLAogIGRhdGEgPSBhaWRfZGF0YV9leGFtcGxlX3d0cywKICBmYW1pbHkgPSBnYXVzc2lhbigpLCAKICBpdGVyID0gSVRFUiwgY2hhaW5zID0gQ0hBSU5TLCB3YXJtdXAgPSBXQVJNVVAsIHNlZWQgPSBCQVlFU19TRUVELAogIGZpbGUgPSBoZXJlKCJhbmFseXNpcyIsICJtb2RlbF9jYWNoZSIsIHBhc3RlMCgiaDFfZXhhbXBsZV9ub3JtYWwucmRzIikpCikKCmV4YW1wbGVfaHVfZml0IDwtIGJybSgKICBiZih0b3RhbF9vZGFfbGVhZDEgfCB3ZWlnaHRzKGlwdykgfiBiYXJyaWVyc190b3RhbCArICgxIHwgZ3djb2RlKSwgCiAgICAgaHUgfiAxKSwKICBkYXRhID0gYWlkX2RhdGFfZXhhbXBsZV93dHMsCiAgIyBIYXZlIHRvIHVzZSByc3RhbiBiZWNhdXNlIGNtZHN0YW5yIHdlaXJkbHkgdXNlcyBuZWdhdGl2ZSBpbml0cwogIGZhbWlseSA9IGh1cmRsZV9sb2dub3JtYWwoKSwgYmFja2VuZCA9ICJyc3RhbiIsCiAgaXRlciA9IElURVIgKiAyLCBjaGFpbnMgPSBDSEFJTlMsIHdhcm11cCA9IFdBUk1VUCwgc2VlZCA9IEJBWUVTX1NFRUQsCiAgZmlsZSA9IGhlcmUoImFuYWx5c2lzIiwgIm1vZGVsX2NhY2hlIiwgcGFzdGUwKCJoMV9leGFtcGxlX2h1cmRsZS5yZHMiKSkKKQpgYGAKCkV2ZW4gdGhvdWdoIHdlIGp1c3QgdXNlZCBhbiBpbnRlcmNlcHQtb25seSBtb2RlbCBmb3IgdGhlIGh1cmRsZSBwcm9jZXNzLCBpbmNvcnBvcmF0aW5nIGl0IGludG8gdGhlIG92ZXJhbGwgbW9kZWwgZ2l2ZXMgdXMgYSAqbXVjaCogYmV0dGVyIGZpdC4gTG9vayBhdCB0aGVzZSBwb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVja3M6CgpgYGB7ciBjaGVjay1ub3JtYWwtaHVyZGxlLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpwcF9jaGVjayhleGFtcGxlX25vcm1hbF9maXQsIHR5cGUgPSAiZGVuc19vdmVybGF5IiwgbnNhbXBsZXMgPSAxMCkgKyAKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMzApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGxhYnNfZXhwKSArCiAgbGFicyh0aXRsZSA9ICJsb2coeSkgfiB4LCBnYXVzc2lhbiBmYW1pbHksIG5vIGh1cmRsaW5nIikgKwogIHRoZW1lX2Rvbm9ycygpCgpwcF9jaGVjayhleGFtcGxlX2h1X2ZpdCwgdHlwZSA9ICJkZW5zX292ZXJsYXkiLCBuc2FtcGxlcyA9IDEwKSArIAogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cxcCIsIGJyZWFrcyA9IGV4cChzZXEoMCwgMzAsIDUpKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gbGFic19leHBfbG9nZ2VkKSArCiAgbGFicyh0aXRsZSA9ICJ5IH4geCwgbG9nbm9ybWFsIGZhbWlseSwgaHVyZGxlOiBodSB+IDEiKSArCiAgdGhlbWVfZG9ub3JzKCkKYGBgCgpJbXBvcnRhbnRseSwgdGhlIGNvZWZmaWNpZW50cyBzd2l0Y2ggZGlyZWN0aW9ucyEKCmBgYHtyIGh1cmRsZS1ub3JtYWwtc3dpdGNofQpleGFtcGxlX25vcm1hbF9maXQgJT4lIAogIGdhdGhlcl9kcmF3cyhiX2JhcnJpZXJzX3RvdGFsKSAlPiUKICBtdXRhdGUoLnZhcmlhYmxlID0gZHBseXI6OnJlY29kZSgudmFyaWFibGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJfYmFycmllcnNfdG90YWwgPSAiQWRkaXRpb25hbCBsYXcsIHQiKSkgJT4lIAogIGdncGxvdChhZXMoeSA9IGZjdF9yZXYoLnZhcmlhYmxlKSwgeCA9IC52YWx1ZSwgZmlsbCA9IGZjdF9yZXYoLnZhcmlhYmxlKSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC44LCAwLjk1KSwgYWxwaGEgPSAwLjgpICsKICBndWlkZXMoZmlsbCA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjg1MUIiLCAiI0ZGREMwMCIpKSArCiAgbGFicyh5ID0gTlVMTCwgeCA9ICIlIGNoYW5nZSBpbiBvdXRjb21lIiwKICAgICAgIHRpdGxlID0gImxvZyh5KSB+IHgsIGdhdXNzaWFuIGZhbWlseSwgbm8gaHVyZGxpbmciKSArCiAgdGhlbWVfZG9ub3JzKCkKCmV4YW1wbGVfaHVfZml0ICU+JSAKICBnYXRoZXJfZHJhd3MoYl9iYXJyaWVyc190b3RhbCkgJT4lCiAgbXV0YXRlKC52YWx1ZSA9IGV4cCgudmFsdWUpIC0gMSkgJT4lCiAgbXV0YXRlKC52YXJpYWJsZSA9IGRwbHlyOjpyZWNvZGUoLnZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiX2JhcnJpZXJzX3RvdGFsID0gIkFkZGl0aW9uYWwgbGF3LCB0IC0gMSIpKSAlPiUgCiAgZ2dwbG90KGFlcyh5ID0gZmN0X3JldigudmFyaWFibGUpLCB4ID0gLnZhbHVlLCBmaWxsID0gZmN0X3JldigudmFyaWFibGUpKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBzdGF0X2hhbGZleWUoLndpZHRoID0gYygwLjgsIDAuOTUpLCBhbHBoYSA9IDAuOCkgKwogIGd1aWRlcyhmaWxsID0gRkFMU0UpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0ZGODUxQiIsICIjRkZEQzAwIikpICsKICBsYWJzKHkgPSBOVUxMLCB4ID0gIiUgY2hhbmdlIGluIG91dGNvbWUiLAogICAgICAgdGl0bGUgPSAieSB+IHgsIGxvZ25vcm1hbCBmYW1pbHk7IGh1cmRsZTogaHUgfiAxIikgKwogIHRoZW1lX2Rvbm9ycygpCmBgYAoKV2UgdGh1cyB1c2UgYSBsb2dub3JtYWwgZmFtaWx5IHdoZW4gbW9kZWxpbmcgdGhlIG91dGNvbWUuIEJlY2F1c2Ugd2UncmUgbGltaXRpbmcgb3Vyc2VsdmVzIHRvIGp1c3Qgb2JzZXJ2YXRpb25zIHRoYXQgcmVjZWl2ZSBhaWQsIG91ciBBVEUgdGhlb3JldGljYWxseSBvbmx5IHNob3dzIHRoZSBlZmZlY3Qgb2YgdHJlYXRtZW50IG9uIGFjdHVhbGx5IGhhdmluZyB0aGUgb3V0Y29tZSBvY2N1ci4gV2UncmUgKm5vdCogdHJ5aW5nIHRvIG1vZGVsIHRoZSBlZmZlY3Qgb2YgdHJlYXRtZW50IG9uIHRoZSAwLzEgbG9naXQgcHJvY2VzcyBmb3IgcmVjZWl2aW5nIGFpZCBpbiB0aGUgZmlyc3QgcGxhY2UuCgoKIyMjIEludGVycHJldGluZyBsb2dub3JtYWwgbW9kZWxzCgpCZWNhdXNlIHRoZSBvdXRjb21lIGlzIHByZS1sb2dnZWQsIHdlIGhhdmUgdG8gaW50ZXJwcmV0IHRoZXNlIHJlc3VsdHMgYSBsaXR0bGUgZGlmZmVyZW50bHkgZnJvbSBzdGFuZGFyZCBPTFMsIGJ1dCBpdCdzIG5vdCB0b28gYmFkLCBjb25zaWRlcmluZyB0aGF0IGEgc3RhbmRhcmQgYXBwcm9hY2ggdG8gZXhwb25lbnRpYWwgZGF0YSBsaWtlIGFpZCBpcyB0byBtb2RlbCB0aGUgbG9nZ2VkIG91dGNvbWUuIFdoZW4gdGhlIHkgaXMgbG9nZ2VkLCBjb2VmZmljaWVudHMgcmVwcmVzZW50IHBlcmNlbnQgY2hhbmdlcyBpbiB5LiBNb2RlbHMgdXNpbmcgdGhlIGxvZ25vcm1hbCBmYW1pbHkgZm9sbG93IHRoZSBzYW1lIHByaW5jaXBsZS4KCmBgYHtyIHNob3ctbG9nbm9ybWFsLWludGVycHJldGF0aW9uLCB3YXJuaW5nPUZBTFNFfQp0aWR5KGV4YW1wbGVfaHVfZml0KSAlPiUKICBtdXRhdGUoZXN0aW1hdGVfZXhwID0gZXhwKGVzdGltYXRlKSkgJT4lIAogIGZpbHRlcih0ZXJtID09ICJiYXJyaWVyc190b3RhbCIpICU+JSAKICBzZWxlY3QodGVybSwgZXN0aW1hdGUsIGVzdGltYXRlX2V4cCkKYGBgCgpgYGB7ciBleHRyYWN0X2NvZWYsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cmh1X3N0YXRzIDwtIHRpZHkoZXhhbXBsZV9odV9maXQpICU+JSAKICBtdXRhdGUodGVybSA9IGphbml0b3I6Om1ha2VfY2xlYW5fbmFtZXModGVybSkpICU+JSAKICBzcGxpdCguJHRlcm0pCmBgYAoKSW4gdGhlIGxvZ25vcm1hbCBtb2RlbCwgdGhlICpleHBvbmVudGlhdGVkKiBjb2VmZmljaWVudHMgcmVwcmVzZW50IHBlcmNlbnQgY2hhbmdlcyBmb3IgZWFjaCB1bml0IGluY3JlYXNlIGluIFguIEZvciBpbnN0YW5jZSwgJGVeXGJldGFfMSQgaGVyZSBpcyBgciByb3VuZChleHAoaHVfc3RhdHMkYmFycmllcnNfdG90YWwkZXN0aW1hdGUpLCA1KWAgTGlrZSBleHBvbmVudGlhdGVkIGxvZ2lzdGljIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLCBldmVyeXRoaW5nIGhlcmUgaXMgY2VudGVyZWQgYXJvdW5kIDEsIG1lYW5pbmcgdGhhdCB0aGVyZSdzIGEgYHIgcGVyY2VudChleHAoaHVfc3RhdHMkYmFycmllcnNfdG90YWwkZXN0aW1hdGUpIC0gMSwgYWNjdXJhY3kgPSAwLjAxKWAgaW5jcmVhc2UgaW4gYWlkIGZvciBldmVyeSBsZWdhbCBiYXJyaWVyIGFkZGVkLiBUaGlzIGNhbiBiZSBhbHNvIGJlIHNlZW4gYXMgYSBtdWx0aXBsaWVyIGVmZmVjdC4gSWYgYWlkIGlzIFwkNTAgbWlsbGlvbiwgaXQgY2hhbmdlcyB0byBgciBkb2xsYXIoNTAwMDAwMDAgKiBleHAoaHVfc3RhdHMkYmFycmllcnNfdG90YWwkZXN0aW1hdGUpKWAgKDUwLDAwMCwwMDAgw5cgYHIgcm91bmQoZXhwKGh1X3N0YXRzJGJhcnJpZXJzX3RvdGFsJGVzdGltYXRlKSwgNSlgKS4KCldoZW4gdXNpbmcgYGJybXM6OmZpdHRlZCgpYCBvbiB0aGUgbW9kZWwgb2JqZWN0LCBicm1zIHNob3dzIGRhdGEgb24gdGhlIG9yaWdpbmFsIHNjYWxlLCBidXQgdG8gc2VlIHRoZSBpbnR1aXRpb24gYmVoaW5kIHRoZSBwZXJjZW50IGNoYW5nZSwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgcGVyY2VudCBjaGFuZ2UgbWFudWFsbHkuIE1hZ2ljYWxseSwgdGhleSdyZSBhbGwgYXJvdW5kIDAuMDk3LgoKYGBge3IgbG9nbm9ybWFsLWludGVycHJldC1maXR0ZWR9CmV4YW1wbGVfaHVfZml0dGVkX3ZhbHVlcyA8LSBmaXR0ZWQoCiAgZXhhbXBsZV9odV9maXQsIAogIG5ld2RhdGEgPSBkYXRhLmZyYW1lKGJhcnJpZXJzX3RvdGFsID0gc2VxKDAsIDgsIDEpKSwgCiAgcmVfZm9ybXVsYSA9IE5BLAogIHJvYnVzdCA9IFRSVUUKKQoKZXhhbXBsZV9odV9maXR0ZWRfdmFsdWVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIG11dGF0ZShwY3RfY2hhbmdlID0gKEVzdGltYXRlIC0gbGFnKEVzdGltYXRlKSkgLyBsYWcoRXN0aW1hdGUpKQpgYGAKCkludGVycHJldGluZyB0aGlzIGNvZWZmaWNpZW50IGdldHMgYSBsaXR0bGUgdHJpY2tpZXIgYmVjYXVzZSB3ZSB1c2VkIGEgbXVsdGlsZXZlbCBtb2RlbCB3aXRoIHBvcHVsYXRpb24gYW5kIGdyb3VwIGVmZmVjdHMuIFRoaXMgJFxiZXRhXzEkIGhlcmUgaXMgdGhlICoqYXZlcmFnZSBlZmZlY3QgZm9yIGEgbWVkaWFuIGNsdXN0ZXIgYXQgZWFjaCBsZXZlbCBvZiBYKiouIFtTZWUgdGhpcyBpbmNyZWRpYmxlIHJlc291cmNlIGZvciBhIHRvbiBtb3JlIGRldGFpbHNdKGh0dHBzOi8vcnBzeWNob2xvZ2lzdC5jb20vR0xNTS1wYXJ0MS1sb2dub3JtYWwpIGFib3V0IGRpZmZlcmVudCB3YXlzIG9mIHBpZWNpbmcgdG9nZXRoZXIgcG9wdWxhdGlvbi0gYW5kIGdyb3VwLWxldmVsIGVmZmVjdHMgaW4gYSBsb2dub3JtYWwgbW9kZWwuCgpJJ3ZlIG5ldmVyIHNlZW4gYW55IHBhcGVyIGFueXdoZXJlIHVzZSBodXJkbGVkIG91dGNvbWUgbW9kZWxzIHdpdGggTVNNcywgYnV0IEkgdGhpbmsgaXQgbGVnYWxseSB3b3JrcyBoZXJlLgoKIyMjIFByaW9ycyBmb3Igb3V0Y29tZSBtb2RlbHMKClRoZXJlIGFyZSBhICp0b24qIG9mIG1vdmluZyBwYXJ0cyBpbiB0aGVzZSBvdXRjb21lIG1vZGVscy4gSGVyZSdzIHRoZSBmdWxsIHNwZWNpZmljYXRpb24gZm9yIHRoZSBtb2RlbHMgYW5kIGFsbCBwcmlvcnM6CgokJApcYmVnaW57YWxpZ25lZH0KXHRleHR7QWlkfV97aSx0fSB8IHVfaSwgXHRleHR7TGF3fV97aSwgdC0xfSAmXHNpbSBcb3BlcmF0b3JuYW1le0xvZ05vcm1hbH0gKFpfe2ksIHR9LCBcdGV4dHtBaWR9XlxzdGFyX3tpLCB0fSkgJiBcdGV4dHtbbGlrZWxpaG9vZF19IFxcClxvcGVyYXRvcm5hbWV7bG9naXR9IChaX3tpLCB0fSkgJlxzaW0gXGFscGhhX1ogJiBcdGV4dHtbaW50ZXJjZXB0LW9ubHkgbG9naXQgaWYgfSBcdGV4dHtBaWR9X3tpLCB0fSA9IDAgXHRleHR7XX0gXFwKXGxvZyAoXHRleHR7QWlkfV5cc3Rhcl97aSwgdH0pICZcc2ltIFxtYXRoY2Fse059IChcYmV0YV8wICsgXGJldGFfMSBcdGV4dHtMYXd9X3tpLCB0LTF9LCBcc2lnbWFeMl9cZXBzaWxvbiwgdV9pKSBcdGltZXMgXHRleHR7SVBXfV97aSwgdC0xfSAmIFx0ZXh0e1tpZiB9IFx0ZXh0e0FpZH1fe2ksIHR9ID4gMCBcdGV4dHtdfVxcCnVfaSAmXHNpbSBcbWF0aGNhbHtOfSAoMCwgXHNpZ21hXjJfdSkgJiBcdGV4dHtbY291bnRyeS1zcGVjaWZpYyBpbnRlcmNlcHRzXX0gXFwKXCBcXApcYWxwaGFfWiAmXHNpbSBcb3BlcmF0b3JuYW1le0xvZ2lzdGljfSgtMiwgMC42KSAmIFx0ZXh0e1twcmlvciBwcm9wb3J0aW9uIG9mIHJvd3Mgd2hlcmUgQWlkID0gMF19IFxcClxiZXRhXzAgJlxzaW0gXG1hdGhjYWx7Tn0gKDAsIDE1KSAmIFx0ZXh0e1twcmlvciBwb3B1bGF0aW9uIGludGVyY2VwdF19IFxcClxiZXRhXzEgJlxzaW0gXG1hdGhjYWx7Tn0gKDAsIDMpICYgXHRleHR7W3ByaW9yIHBvcHVsYXRpb24gZWZmZWN0c119IFxcClxzaWdtYV4yX2UsIFxzaWdtYV4yX3UgJlxzaW0gXG9wZXJhdG9ybmFtZXtDYXVjaHl9KDAsIDEpICYgXHRleHR7W3ByaW9yIHNkIGZvciBwb3B1bGF0aW9uIGFuZCBjb3VudHJ5XX0gXFwKXCBcXApcdGV4dHtJUFd9X3tpLCB0LTF9ICY9IFxwcm9kXnRfe3QgPSAxfSBcZnJhY3tccGhpKFRfe2l0fSB8IFRfe2ksIHQtMX0sIENfaSl9e1xwaGkoVF97aXR9IHwgVF97aSwgdC0xfSwgRF97aSwgdC0xfSwgQ19pKX0gJiBcdGV4dHtbc3RhYmlsaXplZCB3ZWlnaHRzXX0KXGVuZHthbGlnbmVkfQokJAoKSGVyZSdzIHdoYXQgdGhvc2UgbG9vayBsaWtlOgoKYGBge3IgaDEtc2hvdy1wcmlvcnMsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTQsIGZpZy5hc3A9TlVMTH0Kel9wIDwtIGdncGxvdCgpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRsb2dpcywgYXJncyA9IGxpc3QobG9jYXRpb24gPSAtMiwgc2NhbGUgPSAwLjYpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSBUZVgoIlxcdGV4dGJme1Byb3BvcnRpb24gd2hlcmUgQWlkID0gMCAozrFfWil9IikpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IC0yLCB5ID0gMC4wNywgbGFiZWwgPSAiTG9naXN0aWMoLTIsIDAuNikiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgtOCwgMykgKwogIHRoZW1lX2Rvbm9ycyhwcmlvciA9IFRSVUUpCgpiMF9wIDwtIGdncGxvdCgpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gMCwgc2QgPSAxNSksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoeCA9IFRlWCgiXFx0ZXh0YmZ7UG9wdWxhdGlvbiBpbnRlcmNlcHQgKM6yXzApfSIpKSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJsYWJlbCIsIHggPSAwLCB5ID0gMC4wMDQyLCBsYWJlbCA9ICJOKDAsIDE1KSIsIHNpemUgPSBwdHMoOSkpICsKICB4bGltKC01MCwgNTApICsKICB0aGVtZV9kb25vcnMocHJpb3IgPSBUUlVFKQoKYjFfcCA8LSBnZ3Bsb3QoKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IDAsIHNkID0gMyksCiAgICAgICAgICAgICAgICBnZW9tID0gImFyZWEiLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnMoeCA9IFRlWCgiXFx0ZXh0YmZ7UG9wdWxhdGlvbiBlZmZlY3RzICjOsl8xKX0iKSkgKwogIGFubm90YXRlKGdlb20gPSAibGFiZWwiLCB4ID0gMCwgeSA9IDAuMDIsIGxhYmVsID0gIk4oMCwgMykiLCBzaXplID0gcHRzKDkpKSArCiAgeGxpbSgtMTAsIDEwKSArCiAgdGhlbWVfZG9ub3JzKHByaW9yID0gVFJVRSkKCnNpZ21hX3AgPC0gZ2dwbG90KCkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZGNhdWNoeSwgYXJncyA9IGxpc3QobG9jYXRpb24gPSAwLCBzY2FsZSA9IDEpLAogICAgICAgICAgICAgICAgZ2VvbSA9ICJhcmVhIiwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSBUZVgoIlxcdGV4dGJme1BvcHVsYXRpb24gYW5kIGNvdW50cnkgU0QgKM+DX2UsIM+DX3UpfSIpKSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJsYWJlbCIsIHggPSA1LCB5ID0gMC4wNCwgbGFiZWwgPSAiQ2F1Y2h5KDAsIDEpIiwgc2l6ZSA9IHB0cyg5KSkgKwogIHhsaW0oMCwgMTApICsKICB0aGVtZV9kb25vcnMocHJpb3IgPSBUUlVFKQoKKHpfcCArIGIwX3ApIC8gKGIxX3AgfCBzaWdtYV9wKQpgYGAKClRoZSBwcmlvciBmb3IgdGhlIGh1cmRsZSBtb2RlbCBpcyBhIGxpdHRsZSB3ZWlyZC4gRm9yIHdoYXRldmVyIHJlYXNvbiwgYGJybXM6OmdldF9wcmlvcigpYCBzYXlzIHRoYXQgdGhlIHByaW9yIGZvciB0aGUgYGh1YCBwYXJhbWV0ZXIgaXMgYGJldGEoMCwgMSlgLCBidXQgaW4gcHJhY3RpY2UsIGlmIHlvdSBydW4gYGJybXM6OnByaW9yX3N1bW1hcnkoKWAgaXQgc2hvd3MgdGhhdCBpdCBhY3R1YWxseSB1c2VzIGEgZGVmYXVsdCBvZiBgbG9naXN0aWMoMCwgMSlgLCBhbmQgU3RhbiB5ZWxscyBhdCB5b3UgaWYgeW91IHVzZSBhIGJldGEgcHJpb3IuIElkZWFsbHksIHdlIHdhbnQgYSBgYmV0YSgyLCAxMSlgIHByaW9yLCBidXQgd2UgY2FuJ3Qgc3BlY2lmeSBpdCBsaWtlIHRoYXTigJR3ZSBoYXZlIHRvIHRyYW5zbGF0ZSBpdCB0byBhIGxvZ2lzdGljIGRpc3RyaWJ1dGlvbiBpbnN0ZWFkLiBUaGVyZSdzIG5vdCBhbiBlYXN5IHdheSB0byBkbyB0aGlzLCBzbyB3ZSB1c2VkIGBicm1zOjpsb2dpdF9zY2FsZWRgIHRvIHNob3cgdGhlIGJldGEgZGlzdHJpYnV0aW9uIG9uIHRoZSBsb2dpdCBzY2FsZSwgdGhlbiB3ZSBwbGF5ZWQgd2l0aCB0aGUgbG9jYXRpb24gYW5kIHNjYWxlIHBhcmFtZXRlcnMgaW4gYHJsb2dpcygpYCB1bnRpbCBpdCBsb29rZWQgcm91Z2hseSBlcXVpdmFsZW50LgoKYGBge3IgaHUtcHJpb3Itd2VpcmRuZXNzfQpodV9wcmlvcl9zaW0gPC0gdGliYmxlKGJldGEgPSByYmV0YSgxMDAwMCwgMiwgMTEpKSAlPiUgCiAgbXV0YXRlKGJldGFfbG9naXRfc2NhbGUgPSBicm1zOjpsb2dpdF9zY2FsZWQoYmV0YSkpICU+JSAKICBtdXRhdGUobG9naXRfYmV0YWlzaF9wcmlvciA9IHJsb2dpcygxMDAwMCwgLTIsIDAuNikpICU+JSAKICBtdXRhdGUocHJpb3JfcHJvYnMgPSBwbG9naXMobG9naXRfYmV0YWlzaF9wcmlvcikpCgpodV9wcmlvcl9wbG90MSA8LSBnZ3Bsb3QoaHVfcHJpb3Jfc2ltKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gYmV0YSksIGZpbGwgPSAiZ3JleTgwIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh4ID0gIlByb3BvcnRpb24gd2hlcmUgQWlkID0gMCIsCiAgICAgICBzdWJ0aXRsZSA9ICJPcmlnaW5hbCBCZXRhKDIsIDExKSBkaXN0cmlidXRpb24iKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEpKSArCiAgdGhlbWVfZG9ub3JzKHByaW9yID0gVFJVRSkKCmh1X3ByaW9yX3Bsb3QyIDwtIGdncGxvdChodV9wcmlvcl9zaW0pICsKICBnZW9tX2RlbnNpdHkoYWVzKHggPSBiZXRhX2xvZ2l0X3NjYWxlKSwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSAiTG9naXN0aWMgdmFsdWUgd2hlcmUgQWlkID0gMCIsCiAgICAgICBzdWJ0aXRsZSA9ICJCZXRhKDIsIDExKSBzY2FsZWQgd2l0aCBicm1zOjpsb2dpdF9zY2FsZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC04LCAxKSkgKwogIHRoZW1lX2Rvbm9ycyhwcmlvciA9IFRSVUUpCgpodV9wcmlvcl9wbG90MyA8LSBnZ3Bsb3QoaHVfcHJpb3Jfc2ltKSArCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gbG9naXRfYmV0YWlzaF9wcmlvciksIGZpbGwgPSAiZ3JleTgwIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh4ID0gIkxvZ2lzdGljIHZhbHVlIHdoZXJlIEFpZCA9IDAiLAogICAgICAgc3VidGl0bGUgPSAiRXN0aW1hdGVkIExvZ2lzdGljKC0yLCAwLjYpIikgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtOCwgMSkpICsKICB0aGVtZV9kb25vcnMocHJpb3IgPSBUUlVFKQoKaHVfcHJpb3JfcGxvdDQgPC0gZ2dwbG90KGh1X3ByaW9yX3NpbSkgKwogIGdlb21fZGVuc2l0eShhZXMoeCA9IHByaW9yX3Byb2JzKSwgZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHggPSAiUHJvcG9ydGlvbiB3aGVyZSBBaWQgPSAwIiwKICAgICAgIHN1YnRpdGxlID0gIkxvZ2lzdGljKC0yLCAwLjYpIHRyYW5zZm9ybWVkIHRvIHByb2JhYmlsaXRpZXMiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEpKSArCiAgdGhlbWVfZG9ub3JzKHByaW9yID0gVFJVRSkKCihodV9wcmlvcl9wbG90MSArIGh1X3ByaW9yX3Bsb3QyKSAvIChodV9wcmlvcl9wbG90MyArIGh1X3ByaW9yX3Bsb3Q0KQpgYGAKCiMjIyBSdW4gb3V0Y29tZSBtb2RlbHMKClBoZXcuIFdpdGggYWxsIHRoYXQgb3V0IG9mIHRoZSB3YXksIHdlIGNhbiBmaW5hbGx5IHJ1biB0aGUgb3V0Y29tZSBtb2RlbHMuCgpgYGB7ciBoMS1vdXRjb21lLW1vZGVscywgcmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0V9CiMgT3V0Y29tZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEZvcm11bGFzCiMgVHJlYXRtZW50IH4gbGFnIHRyZWF0bWVudCArIG5vbi12YXJ5aW5nIGNvbmZvdW5kZXJzCmZvcm11bGFfaDFfb3V0X3RvdGFsIDwtIGJmKHRvdGFsX29kYV9sZWFkMSB8IHdlaWdodHMoaXB3KSB+IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcnJpZXJzX3RvdGFsICsgKDEgfCBnd2NvZGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBodSB+IDEpCmZvcm11bGFfaDFfb3V0X2Fkdm9jYWN5IDwtIGJmKHRvdGFsX29kYV9sZWFkMSB8IHdlaWdodHMoaXB3KSB+IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkdm9jYWN5ICsgKDEgfCBnd2NvZGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBodSB+IDEpCmZvcm11bGFfaDFfb3V0X2VudHJ5IDwtIGJmKHRvdGFsX29kYV9sZWFkMSB8IHdlaWdodHMoaXB3KSB+IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudHJ5ICsgKDEgfCBnd2NvZGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBodSB+IDEpCmZvcm11bGFfaDFfb3V0X2Z1bmRpbmcgPC0gYmYodG90YWxfb2RhX2xlYWQxIHwgd2VpZ2h0cyhpcHcpIH4gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuZGluZyArICgxIHwgZ3djb2RlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaHUgfiAxKQoKIyBQcmlvcnMKcHJpb3Jfb3V0IDwtIGMoc2V0X3ByaW9yKCJub3JtYWwoMCwgMjApIiwgY2xhc3MgPSAiSW50ZXJjZXB0IiksCiAgICAgICAgICAgICAgIHNldF9wcmlvcigibm9ybWFsKDAsIDMpIiwgY2xhc3MgPSAiYiIpLAogICAgICAgICAgICAgICBzZXRfcHJpb3IoImNhdWNoeSgwLCAxKSIsIGNsYXNzID0gInNkIiksCiAgICAgICAgICAgICAgIHNldF9wcmlvcigibG9naXN0aWMoLTIsIDAuNikiLCBjbGFzcyA9ICJJbnRlcmNlcHQiLCBkcGFyID0gImh1IikpCgojIFJ1biBvdXRjb21lIG1vZGVscyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KdGljKCkKZml0X2gxX291dGNvbWVzIDwtIGZpdF9oMV9pcHcgJT4lCiAgbXV0YXRlKGZvcm11bGFfb3V0Y29tZSA9IAogICAgICAgICAgIGxpc3QoZm9ybXVsYV9oMV9vdXRfdG90YWwsIGZvcm11bGFfaDFfb3V0X2Fkdm9jYWN5LCAKICAgICAgICAgICAgICAgIGZvcm11bGFfaDFfb3V0X2VudHJ5LCBmb3JtdWxhX2gxX291dF9mdW5kaW5nKSkgJT4lIAogIG11dGF0ZShmaXRfb3V0Y29tZSA9IAogICAgICAgICAgIHBtYXAobGlzdChmb3JtdWxhX291dGNvbWUsIGRmX3dpdGhfd2VpZ2h0cywgbW9kZWxfbmFtZSksCiAgICAgICAgICAgICAgICB+YnJtKAogICAgICAgICAgICAgICAgICAuLjEsCiAgICAgICAgICAgICAgICAgIGRhdGEgPSAuLjIsCiAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3Jfb3V0LAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBodXJkbGVfbG9nbm9ybWFsKCksCiAgICAgICAgICAgICAgICAgIGl0ZXIgPSBJVEVSICogMiwgY2hhaW5zID0gQ0hBSU5TLCB3YXJtdXAgPSBXQVJNVVAsIHNlZWQgPSBCQVlFU19TRUVELAogICAgICAgICAgICAgICAgICAjIEhhcyB0byBiZSByc3RhbiBpbnN0ZWFkIG9mIGNtZHN0YW5yIGJjIGl0IGluZXhwbGljYWJseQogICAgICAgICAgICAgICAgICAjIGNyZWF0ZXMgYWxsIHNvcnRzIG9mIG5vbm5lZ2F0aXZlIGluaXRpYWxpemF0aW9uIGVycm9ycyB3aGVuCiAgICAgICAgICAgICAgICAgICMgdXNpbmcgY21kc3RhbnIgd2l0aCBsb2dub3JtYWwoKSA6KAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gInJzdGFuIiwKICAgICAgICAgICAgICAgICAgZmlsZSA9IGhlcmUoImFuYWx5c2lzIiwgIm1vZGVsX2NhY2hlIiwgcGFzdGUwKC4uMywgIl9vdXRjb21lLnJkcyIpKQogICAgICAgICAgICAgICAgKSkpCmZpdF9oMV9vdXRjb21lcwp0b2MoKQpgYGAKCiMjIyBDaGVjayBvdXRjb21lIG1vZGVscwoKYGBge3IgaDEtY2hlY2stb3V0Y29tZX0KY2hlY2tfdG90YWxfb3V0Y29tZSA8LSBmaXRfaDFfb3V0Y29tZXMgJT4lIAogIGZpbHRlcihtb2RlbF9uYW1lID09ICJoMV90b3RhbCIpICU+JSBwdWxsKGZpdF9vdXRjb21lKSAlPiUgZmlyc3QoKQoKcHBfY2hlY2soY2hlY2tfdG90YWxfb3V0Y29tZSwgdHlwZSA9ICJkZW5zX292ZXJsYXkiLCBuc2FtcGxlcyA9IDEwKSArCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzFwIiwgYnJlYWtzID0gZXhwKHNlcSgwLCAyMCwgNSkpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBsYWJzX2V4cF9sb2dnZWQpICsKICB0aGVtZV9kb25vcnMoKQoKY2hlY2tfdG90YWxfb3V0Y29tZSAlPiUgCiAgcG9zdGVyaW9yX3NhbXBsZXMoYWRkX2NoYWluID0gVFJVRSkgJT4lIAogIHNlbGVjdCgtc3RhcnRzX3dpdGgoInJfZ3djb2RlIiksIC1zdGFydHNfd2l0aCgiel8iKSwgLWxwX18sIC1pdGVyKSAlPiUgCiAgbWNtY190cmFjZSgpICsKICB0aGVtZV9kb25vcnMoKQpgYGAKCiMjIyBSZXN1bHRzCgpgYGB7ciBoMS1wbG90cywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NSwgZmlnLmFzcD1OVUxMfQojIFBsb3RzIQpwbG90X3RvdGFsIDwtIGZpdF9oMV9vdXRjb21lcyAlPiUgCiAgZmlsdGVyKG1vZGVsX25hbWUgPT0gImgxX3RvdGFsIikgJT4lIAogIHB1bGwoZml0X291dGNvbWUpICU+JSBudGgoMSkgJT4lIAogIGdhdGhlcl9kcmF3cyhiX2JhcnJpZXJzX3RvdGFsKSAlPiUKICBtdXRhdGUoLnZhbHVlID0gZXhwKC52YWx1ZSkgLSAxKSAlPiUgCiAgbXV0YXRlKC52YXJpYWJsZSA9IGRwbHlyOjpyZWNvZGUoLnZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiX2JhcnJpZXJzX3RvdGFsID0gIkFkZGl0aW9uYWwgbGF3LCB0IC0gMSIpKSAlPiUgCiAgZ2dwbG90KGFlcyh5ID0gZmN0X3JldigudmFyaWFibGUpLCB4ID0gLnZhbHVlLCBmaWxsID0gZmN0X3JldigudmFyaWFibGUpKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBzdGF0X2hhbGZleWUoLndpZHRoID0gYygwLjgsIDAuOTUpLCBhbHBoYSA9IDAuOCkgKwogIGd1aWRlcyhmaWxsID0gRkFMU0UpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjg1MUIiLCAiI0ZGREMwMCIpKSArCiAgbGFicyh5ID0gTlVMTCwgeCA9IE5VTEwpICsKICB0aGVtZV9kb25vcnMoKQoKcGxvdF9hZHZvY2FjeSA8LSBmaXRfaDFfb3V0Y29tZXMgJT4lIAogIGZpbHRlcihtb2RlbF9uYW1lID09ICJoMV9hZHZvY2FjeSIpICU+JSAKICBwdWxsKGZpdF9vdXRjb21lKSAlPiUgbnRoKDEpICU+JSAKICBnYXRoZXJfZHJhd3MoYl9hZHZvY2FjeSkgJT4lIAogIG11dGF0ZSgudmFyaWFibGUgPSBkcGx5cjo6cmVjb2RlKC52YXJpYWJsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYl9hZHZvY2FjeSA9ICJBZGRpdGlvbmFsIGFkdm9jYWN5IGxhdywgdCAtIDEiKSkgJT4lIAogIG11dGF0ZSgudmFsdWUgPSBleHAoLnZhbHVlKSAtIDEpICU+JSAKICBnZ3Bsb3QoYWVzKHkgPSBmY3RfcmV2KC52YXJpYWJsZSksIHggPSAudmFsdWUsIGZpbGwgPSBmY3RfcmV2KC52YXJpYWJsZSkpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIHN0YXRfaGFsZmV5ZSgud2lkdGggPSBjKDAuOCwgMC45NSksIGFscGhhID0gMC44KSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzg1MTQ0YiIsICIjRjAxMkJFIikpICsKICBsYWJzKHkgPSBOVUxMLCB4ID0gTlVMTCkgKwogIHRoZW1lX2Rvbm9ycygpCgpwbG90X2VudHJ5IDwtIGZpdF9oMV9vdXRjb21lcyAlPiUgCiAgZmlsdGVyKG1vZGVsX25hbWUgPT0gImgxX2VudHJ5IikgJT4lIAogIHB1bGwoZml0X291dGNvbWUpICU+JSBudGgoMSkgJT4lIAogIGdhdGhlcl9kcmF3cyhiX2VudHJ5KSAlPiUgCiAgbXV0YXRlKC52YXJpYWJsZSA9IGRwbHlyOjpyZWNvZGUoLnZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiX2VudHJ5ID0gIkFkZGl0aW9uYWwgZW50cnkgbGF3LCB0IC0gMSIpKSAlPiUgCiAgbXV0YXRlKC52YWx1ZSA9IGV4cCgudmFsdWUpIC0gMSkgJT4lIAogIGdncGxvdChhZXMoeSA9IGZjdF9yZXYoLnZhcmlhYmxlKSwgeCA9IC52YWx1ZSwgZmlsbCA9IGZjdF9yZXYoLnZhcmlhYmxlKSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC44LCAwLjk1KSwgYWxwaGEgPSAwLjgpICsKICBndWlkZXMoZmlsbCA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjM0Q5OTcwIiwgIiMyRUNDNDAiKSkgKwogIGxhYnMoeSA9IE5VTEwsIHggPSAiJSBjaGFuZ2UgaW4gT0RBIikgKwogIHRoZW1lX2Rvbm9ycygpCgpwbG90X2Z1bmRpbmcgPC0gZml0X2gxX291dGNvbWVzICU+JSAKICBmaWx0ZXIobW9kZWxfbmFtZSA9PSAiaDFfZnVuZGluZyIpICU+JSAKICBwdWxsKGZpdF9vdXRjb21lKSAlPiUgbnRoKDEpICU+JSAKICBnYXRoZXJfZHJhd3MoYl9mdW5kaW5nKSAlPiUgCiAgbXV0YXRlKC52YXJpYWJsZSA9IGRwbHlyOjpyZWNvZGUoLnZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiX2Z1bmRpbmcgPSAiQWRkaXRpb25hbCBmdW5kaW5nIGxhdywgdCAtIDEiKSkgJT4lIAogIG11dGF0ZSgudmFsdWUgPSBleHAoLnZhbHVlKSAtIDEpICU+JSAKICBnZ3Bsb3QoYWVzKHkgPSBmY3RfcmV2KC52YXJpYWJsZSksIHggPSAudmFsdWUsIGZpbGwgPSBmY3RfcmV2KC52YXJpYWJsZSkpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIHN0YXRfaGFsZmV5ZSgud2lkdGggPSBjKDAuOCwgMC45NSksIGFscGhhID0gMC44KSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzAwMWYzZiIsICIjMDA3NEQ5IikpICsKICBsYWJzKHkgPSBOVUxMLCB4ID0gIiUgY2hhbmdlIGluIE9EQSIpICsKICB0aGVtZV9kb25vcnMoKQoKKHBsb3RfdG90YWwgKyBwbG90X2Fkdm9jYWN5KSAvIChwbG90X2VudHJ5ICsgcGxvdF9mdW5kaW5nKQpgYGAKCmBgYHtyIGgxLWNvbmRpdGlvbmFsLWVmZmVjdHN9CmZpdF9oMV9vdXRjb21lcyAlPiUgCiAgZmlsdGVyKG1vZGVsX25hbWUgPT0gImgxX3RvdGFsIikgJT4lIAogIHB1bGwoZml0X291dGNvbWUpICU+JSBudGgoMSkgJT4lIAogIGNvbmRpdGlvbmFsX2VmZmVjdHMoKQoKZml0X2gxX291dGNvbWVzICU+JSAKICBmaWx0ZXIobW9kZWxfbmFtZSA9PSAiaDFfYWR2b2NhY3kiKSAlPiUgCiAgcHVsbChmaXRfb3V0Y29tZSkgJT4lIG50aCgxKSAlPiUgCiAgY29uZGl0aW9uYWxfZWZmZWN0cygpCgpmaXRfaDFfb3V0Y29tZXMgJT4lIAogIGZpbHRlcihtb2RlbF9uYW1lID09ICJoMV9lbnRyeSIpICU+JSAKICBwdWxsKGZpdF9vdXRjb21lKSAlPiUgbnRoKDEpICU+JSAKICBjb25kaXRpb25hbF9lZmZlY3RzKCkKCmZpdF9oMV9vdXRjb21lcyAlPiUgCiAgZmlsdGVyKG1vZGVsX25hbWUgPT0gImgxX2Z1bmRpbmciKSAlPiUgCiAgcHVsbChmaXRfb3V0Y29tZSkgJT4lIG50aCgxKSAlPiUgCiAgY29uZGl0aW9uYWxfZWZmZWN0cygpCmBgYAo=