library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ------------------------ tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.1.0     v dplyr   1.0.5
v tidyr   1.1.3     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
-- Conflicts --------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(magrittr)

Attaching package: 㤼㸱magrittr㤼㸲

The following object is masked from 㤼㸱package:purrr㤼㸲:

    set_names

The following object is masked from 㤼㸱package:tidyr㤼㸲:

    extract
library(janitor)

Attaching package: 㤼㸱janitor㤼㸲

The following objects are masked from 㤼㸱package:stats㤼㸲:

    chisq.test, fisher.test
gen_RCT_dat <-
  function(total_N,
           baseline_SD,
           mean_diff,
           baseline_outcome_slope,
           outcome_resid) {
    tibble(
      treat    = rbinom(total_N, 1, 0.5),
      baseline = rnorm(total_N, 0, baseline_SD),
      uncorcov = rnorm(total_N, 0, baseline_SD),
      outcome  = mean_diff * treat +
                 baseline_outcome_slope * baseline +
                 rnorm(total_N, 0, outcome_resid)
    )
  }
get_ps <- function(mod) {
  (mod %>% summary())$coefficients[,"Pr(>|t|)"]
}

confint_includes <- function(interval, true_val) {
  stopifnot(nrow(interval) == 1)
  
  interval[1] <= true_val && true_val <= interval[2]
}
analyse_sim <- function(dat, true_mean_diff) {
  mod0 <- lm(outcome ~ treat, data = dat)
  mod1 <- lm(outcome ~ treat + baseline, data = dat)
  mod2 <- lm(outcome ~ treat + uncorcov, data = dat)
  mod3 <- lm(outcome ~ treat + baseline + uncorcov, data = dat)
  
  descriptives <- dat %>%
    group_by(treat) %>%
    summarise(
      mean_pre = mean(baseline),
      mean_post = mean(outcome),
      SD_pre = sd(baseline),
      SD_post = sd(outcome),
      n = n()
    ) %>%
    pivot_wider(names_from = treat,
                values_from = mean_pre:n)
  
  mod_coefs <- tibble(
    mod0_coef = coef(mod0)["treat"],
    mod1_coef = coef(mod1)["treat"],
    mod2_coef = coef(mod2)["treat"],
    mod3_coef = coef(mod3)["treat"],
    mod0_p    = get_ps(mod0)["treat"],
    mod1_p    = get_ps(mod1)["treat"],
    mod2_p    = get_ps(mod2)["treat"],
    mod3_p    = get_ps(mod3)["treat"],
  )  
  
  bind_cols(descriptives, mod_coefs) %>%
    mutate(
      baseline_diff = mean_pre_1 - mean_pre_0,
      treat_group_prop = n_1 / (n_0 + n_1),
      mod0_abs_error = abs(mod0_coef - true_mean_diff),
      mod1_abs_error = abs(mod1_coef - true_mean_diff),
      mod_error_diff = mod0_abs_error - mod1_abs_error,
      mod0_includes_true = confint_includes(confint(mod0)["treat",],
                                            true_mean_diff),
      mod1_includes_true = confint_includes(confint(mod1)["treat",],
                                            true_mean_diff),
      mod2_includes_true = confint_includes(confint(mod2)["treat",],
                                            true_mean_diff),
      mod3_includes_true = confint_includes(confint(mod3)["treat",],
                                            true_mean_diff)
    )  
}
run_sim <- function(total_N,
                    baseline_SD,
                    mean_diff,
                    baseline_outcome_slope,
                    outcome_resid,
                    sims = 1000) {
  1:sims %>%
    map_dfr(
      ~ gen_RCT_dat(
        total_N,
        baseline_SD,
        mean_diff,
        baseline_outcome_slope,
        outcome_resid
      ) %>%
        analyse_sim(mean_diff)
    )
}
sim_results <-
  run_sim(
    total_N = 200,
    baseline_SD = 1,
    mean_diff = 0.5,
    baseline_outcome_slope = 0.5,
    outcome_resid = 1
  )
sim_results %>%
  summarise(
    unadjusted_true_cov = mean(mod0_includes_true),
    adjusted_true_cov = mean(mod1_includes_true),
    unadjusted_significant = mean(mod0_p < .05),
    adjusted_significant = mean(mod1_p < .05)
  )
sim_results %>%
  tabyl(mod0_includes_true, mod1_includes_true)
 mod0_includes_true FALSE TRUE
              FALSE    25   16
               TRUE    23  936
sim_results %>%
  ggplot(aes(baseline_diff, mod_error_diff)) +
  geom_point(alpha = 0.5) +
  labs(x = "Baseline imbalance",
       y = "Unadjusted minus adjusted error")

do_one_sim <- function(baseline_slope, diff, total_n) {
  run_sim(
    total_N = total_n,
    baseline_SD = 1,
    mean_diff = diff,
    baseline_outcome_slope = baseline_slope,
    outcome_resid = 1
  ) %>%
    summarise(
      # 95% confidence interval coverage
      unadjust_true_cov        = mean(mod0_includes_true),
      adjust_base_true_cov     = mean(mod1_includes_true),
      adjust_uncor_true_cov    = mean(mod2_includes_true),
      adjust_both_true_cov     = mean(mod3_includes_true),
      # % statistically significant
      unadjust_significant     = mean(mod0_p < .05),
      adjust_base_significant  = mean(mod1_p < .05),
      adjust_uncor_significant = mean(mod2_p < .05),
      adjust_both_significant  = mean(mod3_p < .05),
    )
}
sim_setup <- expand.grid(
  baseline_slope = seq(0, 2, 0.5),
  diff = c(0, 0.25, 0.5),
  total_n = c(50, 100)
)
results <- pmap_dfr(sim_setup, do_one_sim)
results_by_param <- bind_cols(sim_setup, results) %>%
  arrange(diff, total_n, baseline_slope)
results_by_param %>%
  pivot_longer(cols = ends_with("significant")) %>%
  mutate(name = recode(name,
    unadjust_significant     = "1. None",
    adjust_base_significant  = "2. Baseline",
    adjust_uncor_significant = "3. Uncorrelated covariate",
    adjust_both_significant  = "4. Both",
    )) %>%
  ggplot(aes(baseline_slope, value, colour = name)) +
  geom_line() +
  geom_point() +
  facet_grid(cols = vars(diff), rows = vars(total_n)) +
  labs(x = "True baseline coefficient",
       y = "Proportion",
       title = "Effect of adjusting for covariates",
       subtitle = "Proportion of simulated studies with p < .05",
       colour = "Adjustment",
       caption = "Note: True treatment effect in columns, sample size in rows") +
  theme(panel.spacing = unit(1, "lines"),
        legend.position = "bottom") +
  ylim(0,1)

results_by_param %>%
  pivot_longer(cols = ends_with("true_cov")) %>%
  mutate(name = recode(name,
    unadjust_true_cov     = "1. None",
    adjust_base_true_cov  = "2. Baseline",
    adjust_uncor_true_cov = "3. Uncorrelated covariate",
    adjust_both_true_cov  = "4. Both",
    )) %>%
  ggplot(aes(baseline_slope, value, colour = name)) +
  geom_line() +
  geom_point() +
  facet_grid(cols = vars(diff), rows = vars(total_n)) +
  labs(x = "True baseline coefficient",
       y = "Proportion",
       title = "Effect of adjusting for covariates",
       subtitle = "Proportion of 95% CIs including true value",
       colour = "Adjustment",
       caption = "Note: True treatment effect in columns, sample size in rows") +
  theme(panel.spacing = unit(1, "lines"),
        legend.position = "bottom") +
  ylim(0,1)

LS0tDQp0aXRsZTogIlBsYXlpbmcgYXJvdW5kIHdpdGggYmFzZWxpbmUgYWRqdXN0ZWQgdnMuIHVuYWRqdXN0ZWQgUkNUIGFuYWx5c2lzIg0KYXV0aG9yOiBBbmRpIEZ1Z2FyZA0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KGphbml0b3IpDQpgYGANCg0KDQpgYGB7cn0NCmdlbl9SQ1RfZGF0IDwtDQogIGZ1bmN0aW9uKHRvdGFsX04sDQogICAgICAgICAgIGJhc2VsaW5lX1NELA0KICAgICAgICAgICBtZWFuX2RpZmYsDQogICAgICAgICAgIGJhc2VsaW5lX291dGNvbWVfc2xvcGUsDQogICAgICAgICAgIG91dGNvbWVfcmVzaWQpIHsNCiAgICB0aWJibGUoDQogICAgICB0cmVhdCAgICA9IHJiaW5vbSh0b3RhbF9OLCAxLCAwLjUpLA0KICAgICAgYmFzZWxpbmUgPSBybm9ybSh0b3RhbF9OLCAwLCBiYXNlbGluZV9TRCksDQogICAgICB1bmNvcmNvdiA9IHJub3JtKHRvdGFsX04sIDAsIGJhc2VsaW5lX1NEKSwNCiAgICAgIG91dGNvbWUgID0gbWVhbl9kaWZmICogdHJlYXQgKw0KICAgICAgICAgICAgICAgICBiYXNlbGluZV9vdXRjb21lX3Nsb3BlICogYmFzZWxpbmUgKw0KICAgICAgICAgICAgICAgICBybm9ybSh0b3RhbF9OLCAwLCBvdXRjb21lX3Jlc2lkKQ0KICAgICkNCiAgfQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmdldF9wcyA8LSBmdW5jdGlvbihtb2QpIHsNCiAgKG1vZCAlPiUgc3VtbWFyeSgpKSRjb2VmZmljaWVudHNbLCJQcig+fHR8KSJdDQp9DQoNCmNvbmZpbnRfaW5jbHVkZXMgPC0gZnVuY3Rpb24oaW50ZXJ2YWwsIHRydWVfdmFsKSB7DQogIHN0b3BpZm5vdChucm93KGludGVydmFsKSA9PSAxKQ0KICANCiAgaW50ZXJ2YWxbMV0gPD0gdHJ1ZV92YWwgJiYgdHJ1ZV92YWwgPD0gaW50ZXJ2YWxbMl0NCn0NCmBgYA0KDQoNCmBgYHtyfQ0KYW5hbHlzZV9zaW0gPC0gZnVuY3Rpb24oZGF0LCB0cnVlX21lYW5fZGlmZikgew0KICBtb2QwIDwtIGxtKG91dGNvbWUgfiB0cmVhdCwgZGF0YSA9IGRhdCkNCiAgbW9kMSA8LSBsbShvdXRjb21lIH4gdHJlYXQgKyBiYXNlbGluZSwgZGF0YSA9IGRhdCkNCiAgbW9kMiA8LSBsbShvdXRjb21lIH4gdHJlYXQgKyB1bmNvcmNvdiwgZGF0YSA9IGRhdCkNCiAgbW9kMyA8LSBsbShvdXRjb21lIH4gdHJlYXQgKyBiYXNlbGluZSArIHVuY29yY292LCBkYXRhID0gZGF0KQ0KICANCiAgZGVzY3JpcHRpdmVzIDwtIGRhdCAlPiUNCiAgICBncm91cF9ieSh0cmVhdCkgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgICAgbWVhbl9wcmUgPSBtZWFuKGJhc2VsaW5lKSwNCiAgICAgIG1lYW5fcG9zdCA9IG1lYW4ob3V0Y29tZSksDQogICAgICBTRF9wcmUgPSBzZChiYXNlbGluZSksDQogICAgICBTRF9wb3N0ID0gc2Qob3V0Y29tZSksDQogICAgICBuID0gbigpDQogICAgKSAlPiUNCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdHJlYXQsDQogICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBtZWFuX3ByZTpuKQ0KICANCiAgbW9kX2NvZWZzIDwtIHRpYmJsZSgNCiAgICBtb2QwX2NvZWYgPSBjb2VmKG1vZDApWyJ0cmVhdCJdLA0KICAgIG1vZDFfY29lZiA9IGNvZWYobW9kMSlbInRyZWF0Il0sDQogICAgbW9kMl9jb2VmID0gY29lZihtb2QyKVsidHJlYXQiXSwNCiAgICBtb2QzX2NvZWYgPSBjb2VmKG1vZDMpWyJ0cmVhdCJdLA0KICAgIG1vZDBfcCAgICA9IGdldF9wcyhtb2QwKVsidHJlYXQiXSwNCiAgICBtb2QxX3AgICAgPSBnZXRfcHMobW9kMSlbInRyZWF0Il0sDQogICAgbW9kMl9wICAgID0gZ2V0X3BzKG1vZDIpWyJ0cmVhdCJdLA0KICAgIG1vZDNfcCAgICA9IGdldF9wcyhtb2QzKVsidHJlYXQiXSwNCiAgKSAgDQogIA0KICBiaW5kX2NvbHMoZGVzY3JpcHRpdmVzLCBtb2RfY29lZnMpICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIGJhc2VsaW5lX2RpZmYgPSBtZWFuX3ByZV8xIC0gbWVhbl9wcmVfMCwNCiAgICAgIHRyZWF0X2dyb3VwX3Byb3AgPSBuXzEgLyAobl8wICsgbl8xKSwNCiAgICAgIG1vZDBfYWJzX2Vycm9yID0gYWJzKG1vZDBfY29lZiAtIHRydWVfbWVhbl9kaWZmKSwNCiAgICAgIG1vZDFfYWJzX2Vycm9yID0gYWJzKG1vZDFfY29lZiAtIHRydWVfbWVhbl9kaWZmKSwNCiAgICAgIG1vZF9lcnJvcl9kaWZmID0gbW9kMF9hYnNfZXJyb3IgLSBtb2QxX2Fic19lcnJvciwNCiAgICAgIG1vZDBfaW5jbHVkZXNfdHJ1ZSA9IGNvbmZpbnRfaW5jbHVkZXMoY29uZmludChtb2QwKVsidHJlYXQiLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWVfbWVhbl9kaWZmKSwNCiAgICAgIG1vZDFfaW5jbHVkZXNfdHJ1ZSA9IGNvbmZpbnRfaW5jbHVkZXMoY29uZmludChtb2QxKVsidHJlYXQiLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWVfbWVhbl9kaWZmKSwNCiAgICAgIG1vZDJfaW5jbHVkZXNfdHJ1ZSA9IGNvbmZpbnRfaW5jbHVkZXMoY29uZmludChtb2QyKVsidHJlYXQiLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWVfbWVhbl9kaWZmKSwNCiAgICAgIG1vZDNfaW5jbHVkZXNfdHJ1ZSA9IGNvbmZpbnRfaW5jbHVkZXMoY29uZmludChtb2QzKVsidHJlYXQiLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWVfbWVhbl9kaWZmKQ0KICAgICkgIA0KfQ0KYGBgDQoNCg0KYGBge3J9DQpydW5fc2ltIDwtIGZ1bmN0aW9uKHRvdGFsX04sDQogICAgICAgICAgICAgICAgICAgIGJhc2VsaW5lX1NELA0KICAgICAgICAgICAgICAgICAgICBtZWFuX2RpZmYsDQogICAgICAgICAgICAgICAgICAgIGJhc2VsaW5lX291dGNvbWVfc2xvcGUsDQogICAgICAgICAgICAgICAgICAgIG91dGNvbWVfcmVzaWQsDQogICAgICAgICAgICAgICAgICAgIHNpbXMgPSAxMDAwKSB7DQogIDE6c2ltcyAlPiUNCiAgICBtYXBfZGZyKA0KICAgICAgfiBnZW5fUkNUX2RhdCgNCiAgICAgICAgdG90YWxfTiwNCiAgICAgICAgYmFzZWxpbmVfU0QsDQogICAgICAgIG1lYW5fZGlmZiwNCiAgICAgICAgYmFzZWxpbmVfb3V0Y29tZV9zbG9wZSwNCiAgICAgICAgb3V0Y29tZV9yZXNpZA0KICAgICAgKSAlPiUNCiAgICAgICAgYW5hbHlzZV9zaW0obWVhbl9kaWZmKQ0KICAgICkNCn0NCmBgYA0KDQoNCg0KYGBge3J9DQpzaW1fcmVzdWx0cyA8LQ0KICBydW5fc2ltKA0KICAgIHRvdGFsX04gPSAyMDAsDQogICAgYmFzZWxpbmVfU0QgPSAxLA0KICAgIG1lYW5fZGlmZiA9IDAuNSwNCiAgICBiYXNlbGluZV9vdXRjb21lX3Nsb3BlID0gMC41LA0KICAgIG91dGNvbWVfcmVzaWQgPSAxDQogICkNCmBgYA0KDQoNCmBgYHtyfQ0Kc2ltX3Jlc3VsdHMgJT4lDQogIHN1bW1hcmlzZSgNCiAgICB1bmFkanVzdGVkX3RydWVfY292ID0gbWVhbihtb2QwX2luY2x1ZGVzX3RydWUpLA0KICAgIGFkanVzdGVkX3RydWVfY292ID0gbWVhbihtb2QxX2luY2x1ZGVzX3RydWUpLA0KICAgIHVuYWRqdXN0ZWRfc2lnbmlmaWNhbnQgPSBtZWFuKG1vZDBfcCA8IC4wNSksDQogICAgYWRqdXN0ZWRfc2lnbmlmaWNhbnQgPSBtZWFuKG1vZDFfcCA8IC4wNSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0Kc2ltX3Jlc3VsdHMgJT4lDQogIHRhYnlsKG1vZDBfaW5jbHVkZXNfdHJ1ZSwgbW9kMV9pbmNsdWRlc190cnVlKQ0KYGBgDQoNCg0KDQpgYGB7ciBkcGk9MzAwfQ0Kc2ltX3Jlc3VsdHMgJT4lDQogIGdncGxvdChhZXMoYmFzZWxpbmVfZGlmZiwgbW9kX2Vycm9yX2RpZmYpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgbGFicyh4ID0gIkJhc2VsaW5lIGltYmFsYW5jZSIsDQogICAgICAgeSA9ICJVbmFkanVzdGVkIG1pbnVzIGFkanVzdGVkIGVycm9yIikNCmBgYA0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCmRvX29uZV9zaW0gPC0gZnVuY3Rpb24oYmFzZWxpbmVfc2xvcGUsIGRpZmYsIHRvdGFsX24pIHsNCiAgcnVuX3NpbSgNCiAgICB0b3RhbF9OID0gdG90YWxfbiwNCiAgICBiYXNlbGluZV9TRCA9IDEsDQogICAgbWVhbl9kaWZmID0gZGlmZiwNCiAgICBiYXNlbGluZV9vdXRjb21lX3Nsb3BlID0gYmFzZWxpbmVfc2xvcGUsDQogICAgb3V0Y29tZV9yZXNpZCA9IDENCiAgKSAlPiUNCiAgICBzdW1tYXJpc2UoDQogICAgICAjIDk1JSBjb25maWRlbmNlIGludGVydmFsIGNvdmVyYWdlDQogICAgICB1bmFkanVzdF90cnVlX2NvdiAgICAgICAgPSBtZWFuKG1vZDBfaW5jbHVkZXNfdHJ1ZSksDQogICAgICBhZGp1c3RfYmFzZV90cnVlX2NvdiAgICAgPSBtZWFuKG1vZDFfaW5jbHVkZXNfdHJ1ZSksDQogICAgICBhZGp1c3RfdW5jb3JfdHJ1ZV9jb3YgICAgPSBtZWFuKG1vZDJfaW5jbHVkZXNfdHJ1ZSksDQogICAgICBhZGp1c3RfYm90aF90cnVlX2NvdiAgICAgPSBtZWFuKG1vZDNfaW5jbHVkZXNfdHJ1ZSksDQogICAgICAjICUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudA0KICAgICAgdW5hZGp1c3Rfc2lnbmlmaWNhbnQgICAgID0gbWVhbihtb2QwX3AgPCAuMDUpLA0KICAgICAgYWRqdXN0X2Jhc2Vfc2lnbmlmaWNhbnQgID0gbWVhbihtb2QxX3AgPCAuMDUpLA0KICAgICAgYWRqdXN0X3VuY29yX3NpZ25pZmljYW50ID0gbWVhbihtb2QyX3AgPCAuMDUpLA0KICAgICAgYWRqdXN0X2JvdGhfc2lnbmlmaWNhbnQgID0gbWVhbihtb2QzX3AgPCAuMDUpLA0KICAgICkNCn0NCmBgYA0KDQpgYGB7cn0NCnNpbV9zZXR1cCA8LSBleHBhbmQuZ3JpZCgNCiAgYmFzZWxpbmVfc2xvcGUgPSBzZXEoMCwgMiwgMC41KSwNCiAgZGlmZiA9IGMoMCwgMC4yNSwgMC41KSwNCiAgdG90YWxfbiA9IGMoNTAsIDEwMCkNCikNCmBgYA0KDQpgYGB7cn0NCnJlc3VsdHMgPC0gcG1hcF9kZnIoc2ltX3NldHVwLCBkb19vbmVfc2ltKQ0KcmVzdWx0c19ieV9wYXJhbSA8LSBiaW5kX2NvbHMoc2ltX3NldHVwLCByZXN1bHRzKSAlPiUNCiAgYXJyYW5nZShkaWZmLCB0b3RhbF9uLCBiYXNlbGluZV9zbG9wZSkNCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTYsIGRwaT0zMDB9DQpyZXN1bHRzX2J5X3BhcmFtICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGVuZHNfd2l0aCgic2lnbmlmaWNhbnQiKSkgJT4lDQogIG11dGF0ZShuYW1lID0gcmVjb2RlKG5hbWUsDQogICAgdW5hZGp1c3Rfc2lnbmlmaWNhbnQgICAgID0gIjEuIE5vbmUiLA0KICAgIGFkanVzdF9iYXNlX3NpZ25pZmljYW50ICA9ICIyLiBCYXNlbGluZSIsDQogICAgYWRqdXN0X3VuY29yX3NpZ25pZmljYW50ID0gIjMuIFVuY29ycmVsYXRlZCBjb3ZhcmlhdGUiLA0KICAgIGFkanVzdF9ib3RoX3NpZ25pZmljYW50ICA9ICI0LiBCb3RoIiwNCiAgICApKSAlPiUNCiAgZ2dwbG90KGFlcyhiYXNlbGluZV9zbG9wZSwgdmFsdWUsIGNvbG91ciA9IG5hbWUpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhkaWZmKSwgcm93cyA9IHZhcnModG90YWxfbikpICsNCiAgbGFicyh4ID0gIlRydWUgYmFzZWxpbmUgY29lZmZpY2llbnQiLA0KICAgICAgIHkgPSAiUHJvcG9ydGlvbiIsDQogICAgICAgdGl0bGUgPSAiRWZmZWN0IG9mIGFkanVzdGluZyBmb3IgY292YXJpYXRlcyIsDQogICAgICAgc3VidGl0bGUgPSAiUHJvcG9ydGlvbiBvZiBzaW11bGF0ZWQgc3R1ZGllcyB3aXRoIHAgPCAuMDUiLA0KICAgICAgIGNvbG91ciA9ICJBZGp1c3RtZW50IiwNCiAgICAgICBjYXB0aW9uID0gIk5vdGU6IFRydWUgdHJlYXRtZW50IGVmZmVjdCBpbiBjb2x1bW5zLCBzYW1wbGUgc2l6ZSBpbiByb3dzIikgKw0KICB0aGVtZShwYW5lbC5zcGFjaW5nID0gdW5pdCgxLCAibGluZXMiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgeWxpbSgwLDEpDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD02LCBkcGk9MzAwfQ0KcmVzdWx0c19ieV9wYXJhbSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBlbmRzX3dpdGgoInRydWVfY292IikpICU+JQ0KICBtdXRhdGUobmFtZSA9IHJlY29kZShuYW1lLA0KICAgIHVuYWRqdXN0X3RydWVfY292ICAgICA9ICIxLiBOb25lIiwNCiAgICBhZGp1c3RfYmFzZV90cnVlX2NvdiAgPSAiMi4gQmFzZWxpbmUiLA0KICAgIGFkanVzdF91bmNvcl90cnVlX2NvdiA9ICIzLiBVbmNvcnJlbGF0ZWQgY292YXJpYXRlIiwNCiAgICBhZGp1c3RfYm90aF90cnVlX2NvdiAgPSAiNC4gQm90aCIsDQogICAgKSkgJT4lDQogIGdncGxvdChhZXMoYmFzZWxpbmVfc2xvcGUsIHZhbHVlLCBjb2xvdXIgPSBuYW1lKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoZGlmZiksIHJvd3MgPSB2YXJzKHRvdGFsX24pKSArDQogIGxhYnMoeCA9ICJUcnVlIGJhc2VsaW5lIGNvZWZmaWNpZW50IiwNCiAgICAgICB5ID0gIlByb3BvcnRpb24iLA0KICAgICAgIHRpdGxlID0gIkVmZmVjdCBvZiBhZGp1c3RpbmcgZm9yIGNvdmFyaWF0ZXMiLA0KICAgICAgIHN1YnRpdGxlID0gIlByb3BvcnRpb24gb2YgOTUlIENJcyBpbmNsdWRpbmcgdHJ1ZSB2YWx1ZSIsDQogICAgICAgY29sb3VyID0gIkFkanVzdG1lbnQiLA0KICAgICAgIGNhcHRpb24gPSAiTm90ZTogVHJ1ZSB0cmVhdG1lbnQgZWZmZWN0IGluIGNvbHVtbnMsIHNhbXBsZSBzaXplIGluIHJvd3MiKSArDQogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDEsICJsaW5lcyIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICB5bGltKDAsMSkNCmBgYA0KDQoNCg0K