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