Here, we apply the model to the data collected in our Registered Report validation sample on Nov 1, 2024.

knitr::opts_chunk$set(echo = TRUE, error = T, message = F, warning = F)
# Libraries and Settings

# Libs ---------------------------
library(knitr)
library(tidyverse)
library(arrow)
library(glue)
library(psych)
library(lavaan)
library(ggplot2)
library(plotly)
library(gridExtra)
library(broom)
library(broom.mixed)
library(brms)
library(tidybayes)
library(cmdstanr)
library(cowplot)

options(mc.cores = parallel::detectCores(), 
        brms.backend = "cmdstanr", 
        brms.file_refit = "never",
        width = 6000)

theme_set(theme_bw())

model_name = "ItemSimilarityTraining-20240502-trial12"
#model_name = "item-similarity-20231018-122504"
pretrained_model_name = "all-mpnet-base-v2"

data_path = glue("./data/intermediate/")
pretrained_data_path = glue("./data/intermediate/")

set.seed(42)
source("global_functions.R")


rr_validation <- arrow::read_feather(file = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.item_correlations.feather")))

pt_rr_validation <- arrow::read_feather(file = file.path(data_path, glue("{pretrained_model_name}.raw.validation-study-2024-11-01.item_correlations.feather")))

rr_validation_mapping_data = arrow::read_feather(
  file = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.mapping2.feather"))
) %>%
  rename(scale_0 = scale0,
         scale_1 = scale1)

rr_validation_human_data = arrow::read_feather(
  file = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.human.feather"))
)

rr_validation_scales <- arrow::read_feather(file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.scales.feather"))
)

random_scales <- readRDS("data/intermediate/random_scales_rr.rds")

N <- rr_validation_human_data %>% summarise_all(~ sum(!is.na(.))) %>% min()
total_N <- nrow(rr_validation_human_data)

mapping_data <- rr_validation_mapping_data
items_by_scale <- bind_rows(
  rr_validation_scales %>% select(-keyed) %>% filter(scale_1 == "") %>% left_join(mapping_data %>% select(-scale_1), by = c("instrument", "scale_0")),
  rr_validation_scales %>% select(-keyed) %>% filter(scale_1 != "") %>% left_join(mapping_data, by = c("instrument", "scale_0", "scale_1"))
)

After exclusions, we had data on N=387 respondents. The item with the most missing values still had n=276.

Synthetic inter-item correlations

rr_validation_llm <- rr_validation %>%
  left_join(rr_validation_mapping_data %>% select(variable_1 = variable, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1)) %>%
  left_join(rr_validation_mapping_data %>% select(variable_2 = variable, InstrumentB = instrument, ScaleB = scale_0, SubscaleB = scale_1)) %>% 
  left_join(pt_rr_validation %>% select(variable_1, variable_2, pt_synthetic_r = synthetic_r))

pt_rr_validation_llm <- pt_rr_validation %>%
  left_join(rr_validation_mapping_data %>% select(variable_1 = variable, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1)) %>%
  left_join(rr_validation_mapping_data %>% select(variable_2 = variable, InstrumentB = instrument, ScaleB = scale_0, SubscaleB = scale_1))

Accuracy

se2 <- mean(rr_validation_llm$empirical_r_se^2)

r <- broom::tidy(cor.test(rr_validation_llm$empirical_r, rr_validation_llm$synthetic_r))
pt_r <- broom::tidy(cor.test(pt_rr_validation_llm$empirical_r, pt_rr_validation_llm$synthetic_r))

model <- paste0('
  # Latent variables
  PearsonLatent =~ 1*empirical_r

  # Fixing error variances based on known standard errors
  empirical_r ~~ ',se2,'*empirical_r

  # Relationship between latent variables
  PearsonLatent ~~ synthetic_r
')

fit <- sem(model, data = rr_validation_llm)
pt_fit <- sem(model, data = pt_rr_validation_llm)

pt_m_synth_r_items <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(variable_1, variable_2)),
     sigma ~ s(synthetic_r)), data = pt_rr_validation_llm, 
  file = "ignore/m_pt_synth_rr_r_items_lm")

newdata <- pt_m_synth_r_items$data %>% select(empirical_r, synthetic_r, empirical_r_se)
epreds <- epred_draws(newdata = newdata, obj = pt_m_synth_r_items, re_formula = NA, ndraws = 200)
preds <- predicted_draws(newdata = newdata, obj = pt_m_synth_r_items, re_formula = NA, ndraws = 200)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))
rm(epred_preds)

pt_accuracy_bayes_items <- by_draw %>% mean_hdci(latent_r)


m_synth_r_items <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(variable_1, variable_2)),
     sigma ~ s(synthetic_r)), data = rr_validation_llm, 
  file = "ignore/m_synth_rr_r_items_lm")

sd_synth <- sd(m_synth_r_items$data$synthetic_r)

newdata <- m_synth_r_items$data %>% select(empirical_r, synthetic_r, empirical_r_se)
epreds <- epred_draws(newdata = newdata, obj = m_synth_r_items, re_formula = NA, ndraws = 200)
preds <- predicted_draws(newdata = newdata, obj = m_synth_r_items, re_formula = NA, ndraws = 200)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(
            mae = mean(abs(.epred - .prediction)),
            .epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))
rm(epred_preds)

accuracy_bayes_items <- by_draw %>% mean_hdci(latent_r)


bind_rows(
  pt_r %>% 
    mutate(model = "pre-trained", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  standardizedsolution(pt_fit) %>% 
    filter(lhs == "PearsonLatent", rhs ==  "synthetic_r") %>% 
    mutate(model = "pre-trained", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  pt_accuracy_bayes_items %>% 
    mutate(model = "pre-trained", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  r %>% 
    mutate(model = "fine-tuned", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  standardizedsolution(fit) %>% 
    filter(lhs == "PearsonLatent", rhs ==  "synthetic_r") %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  accuracy_bayes_items %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper)
  ) %>% 
  kable(digits = 2, caption = str_c("Accuracy for k=",nrow(rr_validation_llm)," item pairs (",n_distinct(c(rr_validation_llm$variable_1, rr_validation_llm$variable_1))," items) across language models and methods"))
Accuracy for k=30135 item pairs (245 items) across language models and methods
model kind accuracy conf.low conf.high
pre-trained manifest 0.30 0.29 0.31
pre-trained latent outcome (SEM) 0.31 0.30 0.32
pre-trained latent outcome (Bayesian EIV) 0.33 0.32 0.35
fine-tuned manifest 0.57 0.56 0.58
fine-tuned latent outcome (SEM) 0.59 0.58 0.59
fine-tuned latent outcome (Bayesian EIV) 0.59 0.58 0.61

Prediction error plot according to synthetic estimate

m_synth_r_items
##  Family: gaussian
##   Links: mu = identity; sigma = log
## Formula: empirical_r | mi(empirical_r_se) ~ synthetic_r + (1 | mm(variable_1, variable_2))
##          sigma ~ s(synthetic_r)
##    Data: rr_validation_llm (Number of observations: 30135)
##   Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup draws = 4000
##
## Smooth Terms:
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sds(sigma_ssynthetic_r_1)     2.37      0.68     1.39     4.08 1.00     1802     2183
##
## Group-Level Effects:
## ~mmvariable_1variable_2 (Number of levels: 246)
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.08      0.00     0.08     0.09 1.00      991     1771
##
## Population-Level Effects:
##                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept               -0.00      0.01    -0.01     0.01 1.00      562     1131
## sigma_Intercept         -1.81      0.00    -1.82    -1.80 1.00     6796     3280
## synthetic_r              0.98      0.01     0.96     0.99 1.00     7690     3289
## sigma_ssynthetic_r_1    -2.76      1.19    -5.00    -0.40 1.00     3883     3010
##
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
pred <- conditional_effects(m_synth_r_items, method = "predict")

kable(rmse_items <- by_draw %>% mean_hdci(sigma), caption = "Average prediction error (RMSE)", digits = 2)
Average prediction error (RMSE)
sigma .lower .upper .width .point .interval
0.17 0.17 0.17 0.95 mean hdci
kable(mae_items <- by_draw %>% mean_hdci(mae), caption = "Average prediction error (MAE)", digits = 2)
Average prediction error (MAE)
mae .lower .upper .width .point .interval
0.13 0.13 0.13 0.95 mean hdci
plot_prediction_error_items <- plot(conditional_effects(m_synth_r_items, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  xlab("Synthetic inter-item correlation") + 
  ylab("Prediction error (sigma)") +
  geom_smooth(stat = "identity", color = "#a48500", fill = "#EDC951")

plot_prediction_error_items

Scatter plot

ggplot(rr_validation_llm, aes(synthetic_r, empirical_r, 
              ymin = empirical_r - empirical_r_se,
              ymax = empirical_r + empirical_r_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(color = "#00A0B0", alpha = 0.03, size = 1) +
  geom_smooth(aes(
    x = synthetic_r,
    y = estimate__,
    ymin = lower__,
    ymax = upper__,
  ), stat = "identity", 
  color = "#a48500",
  fill = "#EDC951",
  data = as.data.frame(pred$synthetic_r)) +
  xlab("Synthetic inter-item correlation") + 
  ylab("Empirical inter-item correlation") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1)) -> plot_items
plot_items

Interactive plot

This plot shows only 2000 randomly selected item pairs to conserve memory. A full interactive plot exists, but may react slowly.

item_pair_table <- rr_validation_llm %>% 
   left_join(rr_validation_mapping_data %>% select(variable_1 = variable,
                                             item_text_1 = item_text)) %>% 
   left_join(rr_validation_mapping_data %>% select(variable_2 = variable,
                                             item_text_2 = item_text))

# item_pair_table %>% filter(str_length(item_text_1) < 30, str_length(item_text_2) < 30) %>% 
#   left_join(pt_rr_validation_llm %>% rename(synthetic_r_pt = synthetic_r)) %>% 
#   select(item_text_1, item_text_2, empirical_r, synthetic_r, synthetic_r_pt) %>% View()
rio::export(item_pair_table, "ignore/item_pair_table_rr_unrounded.xlsx")
rio::export(item_pair_table, "ignore/item_pair_table_rr.feather")

(item_pair_table %>% 
  mutate(synthetic_r = round(synthetic_r, 2),
         empirical_r = round(empirical_r, 2),
         items = str_replace_all(str_c(item_text_1, "\n", item_text_2),
                                  "_+", " ")) %>% 
    sample_n(2000) %>%
ggplot(., aes(synthetic_r, empirical_r, 
              # ymin = empirical_r - empirical_r_se, 
              # ymax = empirical_r + empirical_r_se, 
              label = items)) + 
  geom_abline(linetype = "dashed") +
  geom_point(color = "#00A0B0", alpha = 0.3, size = 1) +
  xlab("Synthetic inter-item correlation") + 
  ylab("Empirical inter-item correlation") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1))) %>% 
  ggplotly()
item_pair_table_numeric <- item_pair_table

item_pair_table <- item_pair_table %>% 
  mutate(empirical_r = sprintf("%.2f±%.3f", empirical_r,
                                 empirical_r_se),
           synthetic_r = sprintf("%.2f", synthetic_r)) %>% 
  select(item_text_1, item_text_2, empirical_r, synthetic_r)
rio::export(item_pair_table, "item_pair_table_rr.xlsx")

Robustness checks

Comparing spline and polynomial models for heteroscedasticity

# For item correlations
m_synth_r_items_poly <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(variable_1, variable_2)),
     sigma ~ poly(synthetic_r, degree = 3)), data = rr_validation_llm, 
  file = "ignore/m_synth_rr_r_items_lm_poly")

newdata <- m_synth_r_items_poly$data %>% select(empirical_r, synthetic_r, empirical_r_se)
epreds <- epred_draws(newdata = newdata, obj = m_synth_r_items_poly, re_formula = NA, ndraws = 200)
preds <- predicted_draws(newdata = newdata, obj = m_synth_r_items_poly, re_formula = NA, ndraws = 200)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

accuracy_bayes_items_poly <- by_draw %>% mean_hdci(latent_r)

bind_rows(
  accuracy_bayes_items %>% 
    mutate(model = "spline", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  accuracy_bayes_items_poly %>% 
    mutate(model = "polynomial", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper)
) %>% 
  knitr::kable(digits = 2, caption = "Comparing spline and polynomial models for item correlations")
Comparing spline and polynomial models for item correlations
model kind accuracy conf.low conf.high
spline latent outcome (Bayesian EIV) 0.59 0.58 0.61
polynomial latent outcome (Bayesian EIV) 0.59 0.58 0.60
plot_prediction_error_items_poly <- plot(conditional_effects(m_synth_r_items_poly, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  xlab("Synthetic inter-item correlation") + 
  ylab("Prediction error (sigma)") +
  geom_smooth(stat = "identity", color = "#a48500", fill = "#EDC951")

plot_prediction_error_items_poly

Accuracy by subject matter

Both items from same subject matter/domain
instruments <- rio::import("rr_used_measures.xlsx") %>% as_tibble()

rr_validation_llm_domain <- rr_validation_llm %>% 
  left_join(instruments %>% select(InstrumentA = Measure, DomainA = Domain), by = "InstrumentA") %>% 
  left_join(instruments %>% select(InstrumentB = Measure, DomainB = Domain), by = "InstrumentB") 

accuracy_within_domains <- rr_validation_llm_domain %>% 
  filter(DomainA == DomainB) %>% 
  group_by(DomainA) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), rmse = sqrt(mean((empirical_r - synthetic_r)^2)), pt_rmse = sqrt(mean((empirical_r - pt_synthetic_r)^2)), sd_emp_r = sd(empirical_r), mean_abs_r = mean(abs(empirical_r)), mean_r = mean(empirical_r), pos_sign = mean(sign(empirical_r) > 0), n = n()) %>% 
  select(domain = DomainA, r = estimate, conf.low, conf.high, pt_cor, rmse, pt_rmse, n, sd_emp_r, mean_abs_r, mean_r, pos_sign) %>% 
  arrange(r)

accuracy_within_domains %>% 
  kable(digits = 2, caption = "Accuracy by domain when both items are from the same domain")
Accuracy by domain when both items are from the same domain
domain r conf.low conf.high pt_cor rmse pt_rmse n sd_emp_r mean_abs_r mean_r pos_sign
attitudes 0.34 0.23 0.43 0.18 0.26 0.36 300 0.23 0.16 0.03 0.53
personality 0.42 0.37 0.47 0.06 0.20 0.33 1035 0.21 0.16 0.02 0.55
clinical 0.50 0.48 0.52 0.37 0.25 0.29 5050 0.28 0.26 0.16 0.78
social 0.72 0.69 0.74 0.25 0.19 0.31 1081 0.27 0.21 0.06 0.58
occupational 0.75 0.70 0.79 0.48 0.28 0.41 351 0.40 0.46 0.28 0.74
Items from one domain correlated with items in other domain
accuracy_between_domains <- bind_rows(rr_validation_llm_domain %>% 
  filter(DomainA != DomainB),
  rr_validation_llm_domain %>% 
  filter(DomainA != DomainB) %>% 
  rename(DomainA = DomainB, DomainB = DomainA)) %>% 
  group_by(DomainA) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), rmse = sqrt(mean((empirical_r - synthetic_r)^2)), pt_rmse = sqrt(mean((empirical_r - pt_synthetic_r)^2)), sd_emp_r = sd(empirical_r), mean_abs_r = mean(abs(empirical_r)), mean_r = mean(empirical_r), pos_sign = mean(sign(empirical_r) > 0), n = n()) %>% 
  select(domain = DomainA, r = estimate, conf.low, conf.high, pt_cor, rmse, pt_rmse, n, sd_emp_r, mean_abs_r, mean_r, pos_sign) %>% 
  arrange(r)
accuracy_between_domains %>% 
  kable(digits = 2, caption = "Accuracy by domain when items are from different domains")
Accuracy by domain when items are from different domains
domain r conf.low conf.high pt_cor rmse pt_rmse n sd_emp_r mean_abs_r mean_r pos_sign
attitudes 0.31 0.28 0.33 0.14 0.12 0.15 5525 0.11 0.09 0.02 0.58
personality 0.48 0.46 0.49 0.13 0.16 0.24 9200 0.17 0.14 0.03 0.56
clinical 0.54 0.53 0.56 0.18 0.17 0.25 14645 0.20 0.15 0.02 0.54
social 0.59 0.58 0.61 0.23 0.16 0.23 9353 0.20 0.16 0.04 0.59
occupational 0.65 0.64 0.66 0.23 0.16 0.28 5913 0.21 0.17 0.00 0.49
library(ggrepel)
dodge <- 0.6
bind_rows(
within = accuracy_within_domains,
across = accuracy_between_domains, .id = "kind") %>% 
  mutate(kind = fct_inorder(kind)) %>% 
ggplot(aes(x = domain, r, ymin = conf.low, ymax = conf.high, shape = kind, fill = kind)) +
  geom_col(aes( group = kind), position = position_dodge(width = dodge), width = 0.4) +
  geom_col(aes(y = pt_cor, group = kind), fill = "gray", position = position_dodge(width = dodge), , width = 0.4) +
  # geom_linerange(aes(ymin = pt_cor, ymax = r, group = kind), color = "gray", position = position_dodge(width = 1)) +
  # geom_point(aes(y = pt_cor, group = kind), color = "black", position = position_dodge(width = 1), size = 2.5) +
  geom_pointrange(position = position_dodge(width = dodge)) + 
  scale_fill_manual(values = c("#a48500", "#a48500"), guide = "none") + 
  scale_shape_manual(values = c("within" = 19, "across" = 4), guide = "none") +
  # scale_color_viridis_d(end = 0.7, option = "A", guide = "none") +
  scale_y_continuous("Manifest accuracy of synthetic item pair correlations", limits = c(0, 1), expand = c(0, 0)) +
  xlab("Item domain") +
  annotate("text", label = "SBERT", x = 2.85, y = 0.24,  angle = 90) +
  annotate("text", label = "SurveyBot3000", x = 3.15, y = 0.43,  angle = 90) +
  annotate("text_repel", label = "within domain", x = 2.85, y = .745, force = 2, hjust = 1.15, vjust = -2) +
  annotate("text_repel", label = "across domains", x = 3.15, y = .65, force = 2, hjust = -.15, vjust = -2) +
  geom_text(aes(label = sprintf("%.2f", r), hjust = if_else(kind == "within", 1.3, -0.3)), vjust = -0.4, size = 3, position = position_dodge(width = dodge))

ggsave("Figure_rr_domain.png", width = 6, height = 5)

Accuracy by instrument

accuracy_between_instruments <- bind_rows(rr_validation_llm_domain %>% 
  filter(InstrumentA != InstrumentB),
  rr_validation_llm_domain %>% 
  filter(InstrumentA != InstrumentB) %>% 
  rename(InstrumentA = InstrumentB, InstrumentB = InstrumentA)) %>% 
  group_by(InstrumentA) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), sd_emp_r = sd(empirical_r), n = n()) %>% 
  select(instrument = InstrumentA, r = estimate, conf.low, conf.high, pt_cor, n, sd_emp_r) %>% 
  arrange(r) %>% 
  mutate(instrument = fct_inorder(instrument))

accuracy_between_instruments %>% 
  kable(digits = 2, caption = "Accuracy by instrument (for items belonging to other instruments)")
Accuracy by instrument (for items belonging to other instruments)
instrument r conf.low conf.high pt_cor n sd_emp_r
Authoritarianism Short Scale 0.20 0.16 0.24 0.23 2133 0.11
New Ecological Paradigm Scale 0.20 0.16 0.24 0.12 2360 0.12
Disgust Avoidance Questionnaire 0.24 0.21 0.27 0.18 3893 0.08
Perth Alexithymia Questionnaire 0.34 0.30 0.37 0.15 2360 0.17
Moral Foundations Questionnaire 0.34 0.31 0.37 0.26 2585 0.12
Attitudes Toward AI in Defense Scale 0.35 0.30 0.39 0.11 1440 0.10
HEXACO-60 0.36 0.34 0.38 0.08 6480 0.15
Fear of COVID-19 Scale 0.36 0.32 0.40 0.23 1673 0.10
Survey Attitude Scale 0.37 0.33 0.40 0.12 2133 0.10
Perceived Stress Scale 0.50 0.48 0.53 0.18 3248 0.27
Perseverative Thinking Questionnaire 0.51 0.49 0.54 0.31 3465 0.28
Obsessive–Compulsive Inventory (Revised) 0.56 0.54 0.58 0.23 4104 0.17
Chronotype Questionnaire 0.60 0.58 0.62 0.19 3680 0.21
Revised Adult Attachment Scale 0.62 0.59 0.64 0.23 2585 0.21
Work Gratitude Scale 0.67 0.65 0.69 0.36 2360 0.19
Center for Epidemiological Studies Depression Scale 0.68 0.67 0.70 0.38 4520 0.28
Utrecht Work Engagement Scale (Short Version) 0.70 0.67 0.72 0.36 2133 0.24
Oldenburg Burnout Inventory (English Translation) 0.71 0.68 0.73 0.30 1904 0.26
UCLA Loneliness Scale (Short Form) 0.72 0.69 0.74 0.33 1904 0.27
Positive and Negative Affect Schedule 0.72 0.70 0.74 0.28 1904 0.28
accuracy_within_instruments <- rr_validation_llm %>% 
  filter(InstrumentA == InstrumentB) %>% 
  left_join(items_by_scale %>% select(variable_1 = variable, keyed = keyed) %>% distinct()) %>% 
  group_by(InstrumentA) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), sd_emp_r = sd(empirical_r), n = n(), reverse_item_percentage = sum(keyed == -1, na.rm = TRUE)/n()) %>% 
  select(instrument = InstrumentA, r = estimate, conf.low, conf.high, pt_cor, n, sd_emp_r, reverse_item_percentage) %>% 
  arrange(r) %>% 
  mutate(instrument = factor(instrument, levels = levels(accuracy_between_instruments$instrument)))
  
accuracy_within_instruments %>% 
  mutate(accuracy = sprintf("%.2f [%.2f;%.2f]", r, conf.low, conf.high)) %>% 
  select(-c(r, conf.low, conf.high)) %>% 
  relocate(accuracy, .before = pt_cor) %>%
  rename(pt_accuracy = pt_cor) %>% 
  kable(digits = 2, caption = "Accuracy by instrument (within items belonging to the same instrument)")
Accuracy by instrument (within items belonging to the same instrument)
instrument accuracy pt_accuracy n sd_emp_r reverse_item_percentage
New Ecological Paradigm Scale 0.02 [-0.28;0.31] -0.08 45 0.39 0.47
Moral Foundations Questionnaire 0.03 [-0.23;0.30] 0.08 55 0.20 0.00
HEXACO-60 0.35 [0.27;0.43] 0.04 435 0.20 0.50
Fear of COVID-19 Scale 0.39 [-0.05;0.70] 0.34 21 0.07 0.00
Perseverative Thinking Questionnaire 0.45 [0.28;0.59] 0.15 105 0.09 0.00
Authoritarianism Short Scale 0.47 [0.17;0.69] 0.39 36 0.10 0.00
Perceived Stress Scale 0.50 [0.33;0.64] 0.31 91 0.50 0.48
Chronotype Questionnaire 0.57 [0.44;0.68] 0.22 120 0.38 0.62
Survey Attitude Scale 0.58 [0.31;0.76] 0.39 36 0.39 0.08
Disgust Avoidance Questionnaire 0.62 [0.50;0.71] 0.56 136 0.06 0.00
Work Gratitude Scale 0.64 [0.43;0.79] 0.41 45 0.10 0.00
Revised Adult Attachment Scale 0.71 [0.55;0.82] 0.23 55 0.49 0.44
Obsessive–Compulsive Inventory (Revised) 0.71 [0.62;0.78] 0.57 153 0.11 0.00
Utrecht Work Engagement Scale (Short Version) 0.79 [0.62;0.89] 0.62 36 0.12 0.00
Perth Alexithymia Questionnaire 0.80 [0.67;0.89] 0.70 45 0.14 0.00
Oldenburg Burnout Inventory (English Translation) 0.84 [0.68;0.92] 0.38 28 0.54 0.57
Attitudes Toward AI in Defense Scale 0.86 [0.63;0.95] 0.41 15 0.39 0.00
Center for Epidemiological Studies Depression Scale 0.87 [0.84;0.90] 0.55 190 0.50 0.21
UCLA Loneliness Scale (Short Form) 0.93 [0.85;0.97] 0.20 28 0.55 0.25
Positive and Negative Affect Schedule 0.94 [0.87;0.97] 0.50 28 0.51 0.00
bind_rows(
within = accuracy_within_instruments,
across = accuracy_between_instruments, .id = "kind") %>% 
ggplot(aes(x = instrument, r, ymin = conf.low, ymax = conf.high, shape = kind)) +
  geom_point(aes(y = pt_cor, group = kind), color = "gray", position = position_dodge(width = 0.3)) +
  geom_linerange(aes(ymin = pt_cor, ymax = r, group = kind), color = "gray", position = position_dodge(width = 0.3)) +
  geom_pointrange(position = position_dodge(width = 0.3)) + 
  scale_shape_manual(values = c("within" = 19, "across" = 4), guide = "none") +
  scale_color_viridis_d(end = 0.7, option = "A", guide = F) +
  scale_y_continuous("Manifest accuracy") +
  geom_text(aes(label = sprintf("%.2f", r)), vjust = -1, position = position_dodge(width = 0.3)) +
  coord_flip()

Accuracy by item properties

r_by_item <- rr_validation_llm %>% 
  # filter(InstrumentA == InstrumentB, SubscaleA == SubscaleB, ScaleA == ScaleB) %>% 
  left_join(items_by_scale %>% select(variable_1 = variable, keyed = keyed, item_text) %>% distinct()) %>% 
  group_by(variable_1) %>% 
  filter(n() > 3) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), sd_emp_r = sd(empirical_r), n = n(), reverse_item_percentage = sum(keyed == -1)/n(), item_text_length = first(str_length(item_text))) %>% 
  select(r = estimate, conf.low, conf.high, pt_cor, n, sd_emp_r, reverse_item_percentage, item_text_length) %>% 
  arrange(r)

r_by_item %>% ggplot(aes(item_text_length, r, color = factor(reverse_item_percentage))) + 
  scale_color_viridis_d("reversed", end = 0.8) +
  geom_point() + geom_smooth(method = "lm") +
  ylab("Accuracy (r)")

Does the item contain a first person singular pronoun
item_pair_table_numeric <- item_pair_table_numeric %>% 
  mutate(pronoun_1 = str_detect(item_text_1, "\\b(I|me|my|mine|myself|Me|My|Mine|Myself)\\b"),
         pronoun_2 = str_detect(item_text_2, "\\b(I|me|my|mine|myself|Me|My|Mine|Myself)\\b")) %>% 
  mutate(pronouns_in_item_pair = case_when(
    pronoun_1 == F & pronoun_2 == F ~ "neither",
    pronoun_1 == T & pronoun_2 == T ~ "both",
    TRUE ~ "one"
  )) %>% 
  mutate(item_text_length_1 = str_length(item_text_1),
         item_text_length_2 = str_length(item_text_2),
         item_text_length = (item_text_length_1+item_text_length_2)/2) %>% 
  left_join(items_by_scale %>% select(variable_1 = variable, keyed_1 = keyed) %>% distinct()) %>% 
  left_join(items_by_scale %>% select(variable_2 = variable, keyed_2 = keyed) %>% distinct()) %>% 
  mutate(reversed_items = case_when(
    keyed_1 == 1 & keyed_2 == 1 ~ "neither",
    keyed_1 == -1 & keyed_2 == -1 ~ "both",
    TRUE ~ "one"
  ))


options(scipen = 10)
summary(lm(empirical_r ~ synthetic_r * (pronouns_in_item_pair + reversed_items + item_text_length), item_pair_table_numeric))
##
## Call:
## lm(formula = empirical_r ~ synthetic_r * (pronouns_in_item_pair +
##     reversed_items + item_text_length), data = item_pair_table_numeric)
##
## Residuals:
##      Min       1Q   Median       3Q      Max
## -1.02473 -0.10214  0.00171  0.10758  0.76774
##
## Coefficients:
##                                             Estimate  Std. Error t value   Pr(>|t|)
## (Intercept)                              -0.01571570  0.00656285  -2.395    0.01664 *
## synthetic_r                               1.54349104  0.04100884  37.638    < 2e-16 ***
## pronouns_in_item_pairneither              0.00623656  0.00566222   1.101    0.27072
## pronouns_in_item_pairone                 -0.00669539  0.00242107  -2.765    0.00569 **
## reversed_itemsneither                     0.02400836  0.00529971   4.530 0.00000592 ***
## reversed_itemsone                        -0.01776464  0.00542131  -3.277    0.00105 **
## item_text_length                          0.00017506  0.00006971   2.511    0.01204 *
## synthetic_r:pronouns_in_item_pairneither -0.63680974  0.03385991 -18.807    < 2e-16 ***
## synthetic_r:pronouns_in_item_pairone     -0.28711562  0.02033846 -14.117    < 2e-16 ***
## synthetic_r:reversed_itemsneither        -0.15446421  0.03441803  -4.488 0.00000722 ***
## synthetic_r:reversed_itemsone            -0.33280281  0.03602897  -9.237    < 2e-16 ***
## synthetic_r:item_text_length             -0.00473406  0.00045087 -10.500    < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1767 on 30123 degrees of freedom
## Multiple R-squared:  0.3633, Adjusted R-squared:  0.363
## F-statistic:  1562 on 11 and 30123 DF,  p-value: < 2.2e-16
item_pair_table_numeric %>% 
  group_by(pronouns_in_item_pair) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), n_pairs = n()) %>% 
  mutate(accuracy = sprintf("%.2f [%.2f;%.2f]", estimate, conf.low, conf.high)) %>% 
  select(pronouns_in_item_pair, accuracy, n_pairs) %>% 
  kable(digits = 2, caption = "Accuracy for items with and without first person singular pronouns")
Accuracy for items with and without first person singular pronouns
pronouns_in_item_pair accuracy n_pairs
both 0.64 [0.64;0.65] 17955
neither 0.27 [0.22;0.32] 1540
one 0.41 [0.40;0.43] 10640
item_pair_table_numeric %>% 
  group_by(sign(empirical_r), pronouns_in_item_pair) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), n_pairs = n(), sd_e = sd(empirical_r)) %>% 
  mutate(accuracy = sprintf("%.2f [%.2f;%.2f]", estimate, conf.low, conf.high)) %>% 
  select(pronouns_in_item_pair, accuracy, n_pairs, sd_e) %>% 
  kable(digits = 2, caption = "Accuracy for items with and without first person singular pronouns")
Accuracy for items with and without first person singular pronouns
sign(empirical_r) pronouns_in_item_pair accuracy n_pairs sd_e
-1 both 0.35 [0.33;0.37] 7253 0.13
-1 neither -0.49 [-0.54;-0.42] 648 0.13
-1 one 0.08 [0.05;0.11] 4347 0.12
1 both 0.59 [0.58;0.61] 10702 0.17
1 neither 0.65 [0.61;0.69] 892 0.16
1 one 0.42 [0.40;0.44] 6293 0.13
Accuracy by whether item is reversed

Reverse items load negatively on the associated scale.

rr_validation_llm %>% 
  left_join(items_by_scale %>% select(variable_1 = variable, keyed_1 = keyed) %>% distinct()) %>% 
  left_join(items_by_scale %>% select(variable_2 = variable, keyed_2 = keyed) %>% distinct()) %>% 
  mutate(reversed_items = case_when(
    keyed_1 == 1 & keyed_2 == 1 ~ "neither",
    keyed_1 == -1 & keyed_2 == -1 ~ "both",
    TRUE ~ "one"
  )) %>% 
  group_by(reversed_items) %>% 
  summarise(broom::tidy(cor.test(empirical_r, synthetic_r)), n_pairs = n()) %>% 
  mutate(accuracy = sprintf("%.2f [%.2f;%.2f]", estimate, conf.low, conf.high)) %>% 
  select(reversed_items, accuracy, n_pairs) %>% 
  kable(digits = 2, caption = "Accuracy for reversed and non-reversed items")
Accuracy for reversed and non-reversed items
reversed_items accuracy n_pairs
both 0.64 [0.61;0.67] 1431
neither 0.62 [0.62;0.63] 18145
one 0.45 [0.44;0.47] 10559
Top/bottom 20 items
by_item <- bind_rows(item_pair_table_numeric,
  item_pair_table_numeric %>% 
  select(-variable_1, -item_text_1) %>% 
  rename(variable_1 = variable_2, item_text_1 = item_text_2)) %>% 
  group_by(variable_1, item_text_1) %>% 
  summarise(mean_rmse = sqrt(mean((empirical_r - synthetic_r)^2))) %>% 
  arrange(mean_rmse)

bind_rows(head(by_item, 20),
tail(by_item, 20)) %>% 
  kable(digits = 2, caption = "Top and bottom 20 items by RMSE")
Top and bottom 20 items by RMSE
variable_1 item_text_1 mean_rmse
HEXACO_29 People often call me a perfectionist. 0.07
MFQ_08 Justice is the most important requirement for a society. 0.09
FCV19S_04 I am afraid of losing my life because of coronavirus-19. 0.09
AAID_12 The use of AI in Defense could save lives 0.10
KSA3_04 We need strong leaders so that we can live safely in society. 0.10
FCV19S_01 I am most afraid of coronavirus-19 0.10
FCV19S_05 When watching news and stories about coronavirus-19 on social media, I become nervous or anxious. 0.10
NEPS_06 The earth has plenty of natural resources if we just learn how to develop them 0.11
PAQ_15 I prefer to focus on things I can actually see or touch, rather than my emotions. 0.11
SAS_01 I really enjoy responding to questionnaires through the mail or Internet. 0.11
SAS_02 I really enjoy being interviewed for a survey. 0.11
HEXACO_10 If I want something from someone, I will laugh at that person’s worst jokes. 0.11
HEXACO_13 I am usually quite flexible in my opinions when people disagree with me. 0.11
FCV19S_07 My heart races or palpitates when I think about getting coronavirus-19. 0.11
HEXACO_17 Even when people make a lot of mistakes, I rarely say anything negative. 0.11
AAID_14 The use of AI in Defense could protect critical national infrastructure 0.11
HEXACO_14 I would get a lot of pleasure from owning expensive luxury goods. 0.11
SAS_05 A lot can be learned from information collected through surveys. 0.11
HEXACO_27 I always try to be accurate in my work, even at the expense of time. 0.11
MFQ_07 One of the worst things a person could do is hurt a defenseless animal. 0.12
PTQ_12 Thoughts just pop into my mind. 0.26
PTQ_01 The same thoughts keep going through my mind again and again. 0.26
PSS_05 In the last month, how often have you felt that you were effectively coping with important changes that were occurring in your life? 0.26
CESD_04 I felt that I was just as good as other people. 0.26
CESD_07 I felt that everything I did was an effort. 0.27
PTQ_13 I feel driven to continue dwelling on the same issue. 0.27
CESD_16 I enjoyed life. 0.27
UWES9_09 I get carried away when I am working. 0.27
PTQ_03 I can’t stop dwelling on negative experiences or problems. 0.27
PTQ_04 I think about many problems without solving any of them. 0.28
PSS_08 In the last month, how often have you found that you could not cope with all the things that you had to do? 0.28
CQ_06 My mood stays the same throughout the day. 0.28
PSS_14 In the last month, how often have you felt difficulties were piling up so high that you could not overcome them? 0.29
PSS_06 In the last month, how often have you felt confident about your ability to handle your personal problems? 0.29
PSS_03 In the last month, how often have you felt nervous and “stressed”? 0.29
PTQ_06 My thoughts repeat themselves. 0.29
PTQ_11 I keep thinking about the same issue all the time. 0.29
PSS_10 In the last month, how often have you felt that you were on top of things? 0.34
PTQ_15 My thoughts take up all my attention. 0.34
PSS_07 In the last month, how often have you felt that things were going your way? 0.42

Is the accuracy lower within/across scales and instruments?

rr_validation_llm %>% 
  mutate(same_instrument = if_else(InstrumentA == InstrumentB, 1, 0,0),
         same_scale = if_else(ScaleA == ScaleB, 1,0,0),
         same_subscale = if_else(same_scale & SubscaleA == SubscaleB, 1,0,0)) %>% 
  group_by(same_scale, same_instrument, same_subscale) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), sd_emp_r = sd(empirical_r), n = n()) %>% 
  mutate(accuracy = sprintf("%.2f [%.2f;%.2f]", estimate, conf.low, conf.high)) %>% 
  select(same_instrument, same_scale, same_subscale, accuracy, n, sd_emp_r) %>% 
  arrange(same_instrument, same_scale, same_subscale) %>% 
  kable(digits = 2, caption = "Accuracy within and across scales")
Accuracy within and across scales
same_instrument same_scale same_subscale accuracy n sd_emp_r
0 0 0 0.55 [0.54;0.56] 28432 0.20
1 0 0 0.32 [0.25;0.39] 644 0.31
1 1 0 0.62 [0.56;0.66] 592 0.37
1 1 1 0.58 [0.52;0.64] 467 0.49

Is the accuracy lower for items that have low variance?

item_variances <- rr_validation_human_data %>%
  haven::zap_labels() %>% 
  summarise_all(~ sd(., na.rm = T)) %>% 
  pivot_longer(everything(), names_to = "variable", values_to = "item_sd")

by_max_cov <- rr_validation_llm %>% 
  left_join(item_variances, by = c("variable_1" = "variable")) %>% 
  left_join(item_variances, by = c("variable_2" = "variable"), suffix = c("_1", "_2")) %>% 
  mutate(max_covariance = ceiling((item_sd_1 * item_sd_2)*10)/10)

rs_by_max_cov <- by_max_cov %>% 
  group_by(max_covariance) %>% 
  filter(n() > 3) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), sd_emp_r = sd(empirical_r), n = n()) %>% 
  select(max_covariance, r = estimate, conf.low, conf.high, n, sd_emp_r) %>% 
  arrange(max_covariance)

rs_by_max_cov %>% ggplot(aes(max_covariance, r, ymin = conf.low, ymax = conf.high)) +
  geom_pointrange()

by_max_cov%>% 
  filter(max_covariance >= 2) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), sd_emp_r = sd(empirical_r), n = n()) %>% 
  kable(digits = 2, caption = "Accuracy for items with a maximal potential covariance (product of SDs) of at least 2")
Accuracy for items with a maximal potential covariance (product of SDs) of at least 2
estimate statistic p.value parameter conf.low conf.high method alternative sd_emp_r n
0.58 114.91 0 26169 0.57 0.59 Pearson’s product-moment correlation two.sided 0.23 26171

Is the accuracy lower for the pre-trained model?

ggplot(pt_rr_validation_llm, aes(synthetic_r, empirical_r, 
              ymin = empirical_r - empirical_r_se,
              ymax = empirical_r + empirical_r_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(color = "#00A0B0", alpha = 0.03, size = 1) +
  xlab("Synthetic inter-item correlation") + 
  ylab("Empirical inter-item correlation") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1)) -> pt_plot_items
pt_plot_items

Averages

rr_validation_llm %>% summarise(
  mean(synthetic_r),
  mean(empirical_r),
  mean(abs(synthetic_r)),
  mean(abs(empirical_r)),
  prop_negative = sum(empirical_r < 0)/n(),
  prop_pos = sum(empirical_r > 0)/n(),
  `prop_below_-.10` = sum(empirical_r < -0.1)/n(),
  `prop_above_.10` = sum(empirical_r > 0.1)/n(),
) %>% kable(digits = 2, caption = "Average correlations")
Average correlations
mean(synthetic_r) mean(empirical_r) mean(abs(synthetic_r)) mean(abs(empirical_r)) prop_negative prop_pos prop_below_-.10 prop_above_.10
0.06 0.05 0.1 0.17 0.41 0.59 0.22 0.38

By sign & accuracy for absolute correlations

rr_validation_llm %>% 
  summarise(mean( sign(synthetic_r) > 0), mean( sign(empirical_r) > 0))
## # A tibble: 1 × 2
##   `mean(sign(synthetic_r) > 0)` `mean(sign(empirical_r) > 0)`
##                           <dbl>                         <dbl>
## 1                         0.673                         0.594

What if a human in the loop flipped the sign?

rr_validation_llm %>% filter(abs(synthetic_r) >= .10) %>% 
  group_by(sign(synthetic_r)) %>% 
  summarise(round(1 - mean(sign(empirical_r) == sign(synthetic_r)),2))
## # A tibble: 2 × 2
##   `sign(synthetic_r)` `round(1 - mean(sign(empirical_r) == sign(synthetic_r)), 2)`
##                 <dbl>                                                        <dbl>
## 1                  -1                                                         0.16
## 2                   1                                                         0.19
rr_validation_llm %>%  
  group_by(sign(synthetic_r)) %>% 
  summarise(round(1 - mean(sign(empirical_r) == sign(synthetic_r)),2))
## # A tibble: 2 × 2
##   `sign(synthetic_r)` `round(1 - mean(sign(empirical_r) == sign(synthetic_r)), 2)`
##                 <dbl>                                                        <dbl>
## 1                  -1                                                         0.37
## 2                   1                                                         0.3
cor_switch <- rr_validation_llm %>% mutate(synthetic_r = if_else(abs(synthetic_r) <= .10 | sign(synthetic_r) == sign(empirical_r), synthetic_r,
                                                                 -1*synthetic_r)) %>% 
  { broom::tidy(cor.test(.$synthetic_r, .$empirical_r)) }
cor_switch %>% select(accuracy = estimate, conf.low, conf.high) %>% mutate(kind = "manifest") %>% kable(caption = "If a human user flipped the sign to be correct for all synthetic estimates with an absolute magnitude bigger than .10", digits = 2)
If a human user flipped the sign to be correct for all synthetic estimates with an absolute magnitude bigger than .10
accuracy conf.low conf.high kind
0.68 0.68 0.69 manifest
cor_abs <- broom::tidy(cor.test(abs(rr_validation_llm$synthetic_r), abs(rr_validation_llm$empirical_r)))
cor_neg <- rr_validation_llm %>% filter(empirical_r < 0) %>% 
 { broom::tidy(cor.test(.$synthetic_r, .$empirical_r)) }
cor_pos <- rr_validation_llm %>% filter(empirical_r > 0) %>% 
 { broom::tidy(cor.test(.$synthetic_r, .$empirical_r)) }

ggplot(rr_validation_llm, aes(abs(synthetic_r), abs(empirical_r), color = factor(sign(empirical_r)))) + 
  annotate("text", size = 3, x = 0, y = 0.98, vjust = 0, hjust = 0, label = with(cor_abs, { sprintf("accuracy absolute r = %.2f [%.2f;%.2f]", estimate, conf.low, conf.high) }), color = 'black') +
  annotate("text", size = 3, x = 0, y = 0.9, vjust = 0, hjust = 0, label = with(cor_neg, { sprintf("accuracy negative r = %.2f [%.2f;%.2f]", estimate, conf.low, conf.high) }), color = "#3366AA") +
  annotate("text", size = 3, x = 0, y = 0.82, vjust = 0, hjust = 0, label = with(cor_pos, { sprintf("accuracy positive r = %.2f [%.2f;%.2f]", estimate, conf.low, conf.high) }), color = "#00A0B0") +
  geom_abline(linetype = "dashed") +
  geom_point( alpha = 0.1, size = 1) +
  geom_smooth(method = "lm") +
  scale_color_manual("Sign of emp. r", values = c("1" = "#00A0B0", "-1" = "#3366AA")) +
  xlab("Absolute synthetic inter-item correlation") + 
  ylab("Absolute empirical inter-item correlation") +
  theme_bw() +
  coord_fixed(xlim = c(0,1), ylim = c(0,1)) -> abs_plot_items
abs_plot_items

Does it matter how we define our exclusion criteria?

main_qs <- c("AAID", "PANAS", "PAQ", "PSS", "NEPS", "ULS", "FCV", "DAQ", "CESD", "HEXACO", "OCIR", "PTQ", "RAAS", "KSA", "SAS", "MFQ", "CQ", "OLBI", "UWES", "WGS")
rr_human_data_all = rio::import("data/processed/sosci_labelled_with_exclusion_criteria.rds")

manifest_and_latent_r <- function(data) {
  data <- data %>% 
    select(starts_with(main_qs)) %>% 
    select(-ends_with("_R")) %>% 
    longcor() %>% 
    left_join(rr_validation_llm %>% select(variable_1, variable_2, synthetic_r))
  se2 <- mean(data$empirical_r_se^2)
  model <- paste0('
    # Latent variables
    PearsonLatent =~ 1*empirical_r
  
    # Fixing error variances based on known standard errors
    empirical_r ~~ ',se2,'*empirical_r
  
    # Relationship between latent variables
    PearsonLatent ~~ synthetic_r
  ')

  fit <- sem(model, data = data)
  standardizedsolution(fit) %>% 
    filter(lhs == "PearsonLatent", rhs ==  "synthetic_r") %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper) %>% 
    bind_rows(
      broom::tidy(cor.test(data$empirical_r, data$synthetic_r)) %>% 
                    mutate(kind = "manifest") %>% 
        rename(accuracy = estimate) %>% 
        mutate(model = "fine-tuned")) %>% 
    mutate(`max N` = max(data$pairwise_n))
}


r_all <- rr_human_data_all %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "No exclusions")

r_main <- rr_human_data_all %>% 
    mutate(time_per_item_outlier = time_per_item < 2,
                 even_odd_outlier = even_odd >= -.45,
                 psychsyn_outlier = psychsyn < 0.22,
                 psychant_outlier = psychant > -0.03,
                 mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .99)$flagged) %>% 
    mutate(included = !not_serious & !time_per_item_outlier & 
             !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Adapted: <br>- exclude non-serious respondents<br>- item response time < 2s<br>- odd-even r <= .45<br>- psychometric synonym r < .22<br>- psychometric antonym r > -0.03<br>- Mahalanobis distance set for 99% specificity")

r_goldammer_1 <- rr_human_data_all %>% 
    mutate(time_per_item_outlier = time_per_item < 2,
                 even_odd_outlier = even_odd > -.30,
                 psychsyn_outlier = psychsyn < 0.22,
                 psychant_outlier = psychant > -0.03,
                 mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .999)$flagged) %>% 
    mutate(included = !time_per_item_outlier & !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Goldammer heuristic: <br>- item response time < 2s<br>- odd-even r < .30<br>- psychometric synonym r < .22<br>- psychometric antonym r > -0.03<br>- Mahalanobis distance set for 999% specificity")

r_goldammer_2 <- rr_human_data_all %>% 
    mutate(time_per_item_outlier = time_per_item < 5.56,
                 even_odd_outlier = even_odd > -.42,
                 psychsyn_outlier = psychsyn < -0.03,
                 psychant_outlier = psychant > .36,
                 mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .95)$flagged) %>% 
    mutate(included = !time_per_item_outlier & !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Goldammer 95% specificity: <br>- item response time < 5.56s<br>- odd-even r < .42<br>- psychometric synonym r < -0.03<br>- psychometric antonym r > .36<br>- Mahalanobis distance set for 95% specificity")


r_goldammer_3 <- rr_human_data_all %>% 
    mutate(time_per_item_outlier = time_per_item < 4.97,
                 even_odd_outlier = even_odd > -.26,
                 psychsyn_outlier = psychsyn < -0.30,
                 psychant_outlier = psychant > .55,
                 mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .99)$flagged) %>% 
    mutate(included = !time_per_item_outlier & !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Goldammer 99% specificity: <br>- item response time < 5.56s<br>- odd-even r < .42<br>- psychometric synonym r < -0.03<br>- psychometric antonym r > .36<br>- Mahalanobis distance set for 99% specificity")

    
r_strict_reading_of_prereg <- rr_human_data_all %>% 
    mutate(psychsyn_outlier = psychsyn < 0.6,
      psychant_outlier = psychant > -0.4,
      not_us_citizen = Nationality != "United States"
      ) %>%
    filter(if_all(c(longstring_outlier, `mahal_dist_outlier_.5`, psychsyn_outlier, psychant_outlier, even_odd_outlier, not_us_citizen), ~ . == FALSE)) %>%
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Strict preregistered criteria: <br>- odd-even r < mean + 0.2 * SD<br>- psychometric synonym r < .60<br>- psychometric antonym r > -0.40<br>- Mahalanobis distance < mean + 0.5 * SD<br>-Not US citizen")


r_main_first_450 <- rr_human_data_all %>% 
    mutate(mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .99)$flagged) %>% 
  arrange(`Completed at`) %>% 
  filter(row_number () <= 450) %>% 
    mutate(time_per_item_outlier = time_per_item < 2,
                 even_odd_outlier = even_odd >= -.45,
                 psychsyn_outlier = psychsyn < 0.22,
                 psychant_outlier = psychant > -0.03) %>% 
    mutate(included = !not_serious & !time_per_item_outlier & 
             !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Adapted + Prereg N: <br>- the adapted criteria<br>- Only the first 450 participants, our preregistered sample size.")


r_main_us <- rr_human_data_all %>% 
    mutate(time_per_item_outlier = time_per_item < 2,
                 even_odd_outlier = even_odd >= -.45,
                 psychsyn_outlier = psychsyn < 0.22,
                 psychant_outlier = psychant > -0.03,
                 mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .99)$flagged,
                 us_citizen = Nationality == "United States",
                 english_first_language = Language == "English") %>% 
    mutate(included = !not_serious & !time_per_item_outlier & 
             !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged & us_citizen & english_first_language) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Adapted + US English: <br>- the adapted criteria<br>- US citizens, not just residents,- English first language")

r_main_approvals <- rr_human_data_all %>% 
    mutate(time_per_item_outlier = time_per_item < 2,
                 even_odd_outlier = even_odd >= -.45,
                 psychsyn_outlier = psychsyn < 0.22,
                 psychant_outlier = psychant > -0.03,
                 mahal_outlier = careless::mahad(rr_human_data_all %>% select(starts_with(main_qs)), plot = FALSE, flag = TRUE, confidence = .99)$flagged,
                 us_citizen = Nationality == "United States",
                 more_than_20_approvals = `Total approvals` > 20,
                 english_first_language = Language == "English") %>% 
    mutate(included = !not_serious & !time_per_item_outlier & 
             !even_odd_outlier & !psychsyn_outlier & !psychant_outlier & !mahal_flagged & us_citizen & more_than_20_approvals) %>% 
  filter(included) %>% 
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Adapted + US + > 20 approvals: <br>- the adapted criteria<br>- US citizens, not just residents,- More than 20 approvals")


r_adapted_reading_of_prereg <- rr_human_data_all %>% 
    mutate(psychsyn_outlier = psychsyn < 0.22,
      psychant_outlier = psychant > -0.03) %>%
    filter(if_all(c(`mahal_dist_outlier_.5`, psychsyn_outlier, psychant_outlier, even_odd_outlier), ~ . == FALSE)) %>%
  manifest_and_latent_r() %>% 
  mutate(`exclusion criteria` = "Corrected prereg criteria:<br>- odd-even r < mean + 0.2 * SD,<br>- psychometric synonym r < .22,<br> - psychometric antonym r > -0.03, <br>- Mahalanobis distance < mean + 0.5 * SD")

The manifest accuracy is expected to decrease slightly with sample size because it is attenuated by sampling error in the empirical correlations. The latent accuracy should only grow more uncertain with decreased sample size.

exclusion_criteria <- bind_rows(
  r_all, r_main, r_strict_reading_of_prereg, r_adapted_reading_of_prereg, 
  r_goldammer_1, r_goldammer_2, r_goldammer_3, r_main_us, r_main_approvals,
  r_main_first_450
  )
exclusion_criteria %>% 
    select(`exclusion criteria`, model, kind, accuracy, conf.low, conf.high, `max N`) %>% 
  knitr::kable(digits = 2, caption = "Accuracy when human data is filtered by different exclusion criteria", format = "markdown")
Accuracy when human data is filtered by different exclusion criteria
exclusion criteria model kind accuracy conf.low conf.high max N
No exclusions fine-tuned latent outcome (SEM) 0.59 0.58 0.59 470
No exclusions fine-tuned manifest 0.57 0.56 0.58 470
Adapted:
- exclude non-serious respondents
- item response time < 2s
- odd-even r <= .45
- psychometric synonym r < .22
- psychometric antonym r > -0.03
- Mahalanobis distance set for 99% specificity
fine-tuned latent outcome (SEM) 0.58 0.58 0.59 336
Adapted:
- exclude non-serious respondents
- item response time < 2s
- odd-even r <= .45
- psychometric synonym r < .22
- psychometric antonym r > -0.03
- Mahalanobis distance set for 99% specificity
fine-tuned manifest 0.57 0.56 0.58 336
Strict preregistered criteria:
- odd-even r < mean + 0.2 * SD
- psychometric synonym r < .60
- psychometric antonym r > -0.40
- Mahalanobis distance < mean + 0.5 * SD
-Not US citizen
fine-tuned latent outcome (SEM) 0.57 0.56 0.58 116
Strict preregistered criteria:
- odd-even r < mean + 0.2 * SD
- psychometric synonym r < .60
- psychometric antonym r > -0.40
- Mahalanobis distance < mean + 0.5 * SD
-Not US citizen
fine-tuned manifest 0.54 0.53 0.54 116
Corrected prereg criteria:
- odd-even r < mean + 0.2 * SD,
- psychometric synonym r < .22,
- psychometric antonym r > -0.03,
- Mahalanobis distance < mean + 0.5 * SD
fine-tuned latent outcome (SEM) 0.58 0.58 0.59 291
Corrected prereg criteria:
- odd-even r < mean + 0.2 * SD,
- psychometric synonym r < .22,
- psychometric antonym r > -0.03,
- Mahalanobis distance < mean + 0.5 * SD
fine-tuned manifest 0.57 0.56 0.57 291
Goldammer heuristic:
- item response time < 2s
- odd-even r < .30
- psychometric synonym r < .22
- psychometric antonym r > -0.03
- Mahalanobis distance set for 999% specificity
fine-tuned latent outcome (SEM) 0.58 0.58 0.59 341
Goldammer heuristic:
- item response time < 2s
- odd-even r < .30
- psychometric synonym r < .22
- psychometric antonym r > -0.03
- Mahalanobis distance set for 999% specificity
fine-tuned manifest 0.57 0.56 0.58 341
Goldammer 95% specificity:
- item response time < 5.56s
- odd-even r < .42
- psychometric synonym r < -0.03
- psychometric antonym r > .36
- Mahalanobis distance set for 95% specificity
fine-tuned latent outcome (SEM) 0.58 0.58 0.59 143
Goldammer 95% specificity:
- item response time < 5.56s
- odd-even r < .42
- psychometric synonym r < -0.03
- psychometric antonym r > .36
- Mahalanobis distance set for 95% specificity
fine-tuned manifest 0.54 0.53 0.55 143
Goldammer 99% specificity:
- item response time < 5.56s
- odd-even r < .42
- psychometric synonym r < -0.03
- psychometric antonym r > .36
- Mahalanobis distance set for 99% specificity
fine-tuned latent outcome (SEM) 0.58 0.57 0.59 185
Goldammer 99% specificity:
- item response time < 5.56s
- odd-even r < .42
- psychometric synonym r < -0.03
- psychometric antonym r > .36
- Mahalanobis distance set for 99% specificity
fine-tuned manifest 0.55 0.54 0.55 185
Adapted + US English:
- the adapted criteria
- US citizens, not just residents,- English first language
fine-tuned latent outcome (SEM) 0.58 0.57 0.59 284
Adapted + US English:
- the adapted criteria
- US citizens, not just residents,- English first language
fine-tuned manifest 0.56 0.56 0.57 284
Adapted + US + > 20 approvals:
- the adapted criteria
- US citizens, not just residents,- More than 20 approvals
fine-tuned latent outcome (SEM) 0.59 0.58 0.59 284
Adapted + US + > 20 approvals:
- the adapted criteria
- US citizens, not just residents,- More than 20 approvals
fine-tuned manifest 0.57 0.56 0.57 284
Adapted + Prereg N:
- the adapted criteria
- Only the first 450 participants, our preregistered sample size.
fine-tuned latent outcome (SEM) 0.58 0.58 0.59 325
Adapted + Prereg N:
- the adapted criteria
- Only the first 450 participants, our preregistered sample size.
fine-tuned manifest 0.57 0.56 0.58 325
exclusion_criteria %>% 
  mutate(`exclusion criteria` = fct_rev(fct_inorder(str_c(str_sub(`exclusion criteria`, 1, coalesce(str_locate(`exclusion criteria`, ":")[, 1]-1, -1)),", n=", `max N`)))) %>% 
ggplot(aes(x = `exclusion criteria`, accuracy, ymin = conf.low, ymax = conf.high, color = kind)) +
  geom_pointrange() + 
  scale_color_viridis_d(end = 0.7) +
  geom_text(aes(label = sprintf("%.2f", accuracy)), vjust = -1) +
  coord_flip()

Consequences of data leakage

Below, we import our search results of the SBERT training corpus. We identify validation study items with matches, investigate these matches and tabulate accuracy without potentially leaked items.

leaked <- rio::import("data/intermediate/search_results.parquet") %>% 
  mutate(item_text = str_to_lower(item_text))
leaked_items <- leaked %>% group_by(item_text) %>% summarise(n = n())


item_pair_table_l <- item_pair_table_numeric %>% 
  mutate(item_text_1l = str_to_lower(item_text_1),
         item_text_2l = str_to_lower(item_text_2))

items <- bind_rows(item_pair_table_l %>% select(Instrument = InstrumentA, item_textl = item_text_1l),
                   item_pair_table_l %>% select(Instrument = InstrumentB, item_textl = item_text_2l)) %>% 
  distinct()

# items %>% inner_join(leaked, by = c("item_textl" = "item_text")) %>% View

leaked_items_validation <- leaked_items %>% right_join(
  items, by = c("item_text" = "item_textl")) %>% 
  mutate(length = str_length(item_text),
         n = coalesce(n, 0))

leaked_items_validation %>% group_by(Instrument) %>% 
  summarise(leaked = sum(n>0), items = n(), percentage = sum(n>0)/n()*100, matches = sum(n)) %>% 
  arrange(percentage) %>% 
  kable(caption = "Number and percent of items leaked per instrument", digits = 0)
Number and percent of items leaked per instrument
Instrument leaked items percentage matches
Attitudes Toward AI in Defense Scale 0 6 0 0
Authoritarianism Short Scale 0 9 0 0
Chronotype Questionnaire 0 16 0 0
Disgust Avoidance Questionnaire 0 17 0 0
Fear of COVID-19 Scale 0 7 0 0
HEXACO-60 0 30 0 0
Obsessive–Compulsive Inventory (Revised) 0 18 0 0
Oldenburg Burnout Inventory (English Translation) 0 8 0 0
Perseverative Thinking Questionnaire 0 15 0 0
Perth Alexithymia Questionnaire 0 10 0 0
Positive and Negative Affect Schedule 0 8 0 0
Revised Adult Attachment Scale 0 11 0 0
Survey Attitude Scale 0 9 0 0
Work Gratitude Scale 0 10 0 0
Perceived Stress Scale 1 14 7 1
UCLA Loneliness Scale (Short Form) 1 8 12 13
Moral Foundations Questionnaire 2 11 18 2
Center for Epidemiological Studies Depression Scale 7 20 35 885
New Ecological Paradigm Scale 5 10 50 7
Utrecht Work Engagement Scale (Short Version) 8 9 89 64
rr_validation_llm_leakage <- item_pair_table_l %>% 
  left_join(leaked_items_validation %>% rename(n_1 = n, item_text_1l = item_text), by = "item_text_1l") %>% 
  left_join(leaked_items_validation %>% rename(n_2 = n, item_text_2l = item_text), by = "item_text_2l")

rr_validation_llm_leakage %>% 
  group_by(possibly_leaked_instrument = str_detect(InstrumentA, "(New Ecological|Utrecht Work)") |
             str_detect(InstrumentB, "(New Ecological|Utrecht Work)")) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), rmse = sqrt(mean((empirical_r - synthetic_r)^2)), pt_rmse = sqrt(mean((empirical_r - pt_synthetic_r)^2)), n = n()) %>% 
  select(possibly_leaked_instrument, r = estimate, conf.low, conf.high, pt_cor, rmse, pt_rmse, n) %>% 
  arrange(r) %>% 
  kable(caption = "Accuracy by whether the instrument plausibly leaked (>=50% items found in corpus)", digits = 2)
Accuracy by whether the instrument plausibly leaked (>=50% items found in corpus)
possibly_leaked_instrument r conf.low conf.high pt_cor rmse pt_rmse n
FALSE 0.57 0.56 0.58 0.30 0.19 0.26 25651
TRUE 0.59 0.57 0.61 0.29 0.16 0.24 4484
rr_validation_llm_leakage %>% 
  group_by(occurred = n_1 > 0 | n_2 > 0) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), pt_cor = cor(pt_synthetic_r, empirical_r), rmse = sqrt(mean((empirical_r - synthetic_r)^2)), pt_rmse = sqrt(mean((empirical_r - pt_synthetic_r)^2)), n = n()) %>% 
  select(occurred, r = estimate, conf.low, conf.high, pt_cor, rmse, pt_rmse, n) %>% 
  arrange(r) %>% 
  kable(caption = "Accuracy by whether the item occurred in corpus (including trivially short items)", digits = 2)
Accuracy by whether the item occurred in corpus (including trivially short items)
occurred r conf.low conf.high pt_cor rmse pt_rmse n
FALSE 0.53 0.52 0.54 0.29 0.18 0.25 24531
TRUE 0.69 0.67 0.70 0.35 0.19 0.28 5604

Synthetic Reliabilities

scales <- readRDS(file = file.path(data_path, glue("scales_with_alpha_se_rr.rds")))
real_scales <- scales %>% filter(type == "real")
scales <- scales %>% filter(number_of_items >= 3)

Accuracy

se2 <- mean(scales$empirical_alpha_se^2)
r <- broom::tidy(cor.test(scales$empirical_alpha, scales$synthetic_alpha))
pt_r <- broom::tidy(cor.test(scales$empirical_alpha, scales$pt_synthetic_alpha))

model <- paste0('
  # Latent variables
  latent_real_rel =~ 1*empirical_alpha

  # Fixing error variances based on known standard errors
  empirical_alpha ~~ ',se2,'*empirical_alpha

  # Relationship between latent variables
  latent_real_rel ~~ synthetic_alpha
')

fit <- sem(model, data = scales)
pt_fit <- sem(model, data = scales %>% 
                select(empirical_alpha, synthetic_alpha = pt_synthetic_alpha))

# Bayesian EIV PT
pt_m_lmsynth_rel_scales <- brm(
  bf(empirical_alpha | mi(empirical_alpha_se) ~ synthetic_alpha,
     sigma ~ s(synthetic_alpha)), data = scales %>% 
                select(empirical_alpha, synthetic_alpha = pt_synthetic_alpha, empirical_alpha_se), 
  file = "ignore/pt_m_synth_rr_rel_lm")

newdata <- pt_m_lmsynth_rel_scales$data %>% select(empirical_alpha, synthetic_alpha, empirical_alpha_se)
epreds <- epred_draws(newdata = newdata, obj = pt_m_lmsynth_rel_scales, re_formula = NA)
preds <- predicted_draws(newdata = newdata, obj = pt_m_lmsynth_rel_scales, re_formula = NA)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

pt_accuracy_bayes_rels <- by_draw %>% mean_hdci(latent_r)

# Bayesian EIV FT
m_lmsynth_rel_scales <- brm(
  bf(empirical_alpha | mi(empirical_alpha_se) ~ synthetic_alpha,
     sigma ~ s(synthetic_alpha)), data = scales, 
  iter = 6000, 
  file = "ignore/m_synth_rr_rel_lm")

newdata <- m_lmsynth_rel_scales$data %>% select(empirical_alpha, synthetic_alpha, empirical_alpha_se)
epreds <- epred_draws(newdata = newdata, obj = m_lmsynth_rel_scales, re_formula = NA)
preds <- predicted_draws(newdata = newdata, obj = m_lmsynth_rel_scales, re_formula = NA)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(
             mae = mean(abs(.epred - .prediction)),
            .epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

accuracy_bayes_rels <- by_draw %>% mean_hdci(latent_r)

bind_rows(
  pt_r %>% 
    mutate(model = "pre-trained", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  standardizedsolution(pt_fit) %>% 
    filter(lhs == "latent_real_rel", rhs ==  "synthetic_alpha") %>% 
    mutate(model = "pre-trained", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  pt_accuracy_bayes_rels %>% 
      mutate(model = "pre-trained", kind = "latent outcome (Bayesian EIV)") %>% 
      select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  r %>% 
    mutate(model = "fine-tuned", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  standardizedsolution(fit) %>% 
    filter(lhs == "latent_real_rel", rhs ==  "synthetic_alpha") %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  accuracy_bayes_rels %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper)
  ) %>% 
  kable(digits = 2, caption = "Accuracy across language models and methods")
Accuracy across language models and methods
model kind accuracy conf.low conf.high
pre-trained manifest 0.64 0.56 0.71
pre-trained latent outcome (SEM) 0.65 0.58 0.73
pre-trained latent outcome (Bayesian EIV) 0.70 0.61 0.79
fine-tuned manifest 0.85 0.81 0.88
fine-tuned latent outcome (SEM) 0.86 0.83 0.90
fine-tuned latent outcome (Bayesian EIV) 0.84 0.79 0.90

Prediction error plot according to synthetic estimate

m_lmsynth_rel_scales
##  Family: gaussian
##   Links: mu = identity; sigma = log
## Formula: empirical_alpha | mi(empirical_alpha_se) ~ synthetic_alpha
##          sigma ~ s(synthetic_alpha)
##    Data: scales (Number of observations: 257)
##   Draws: 4 chains, each with iter = 6000; warmup = 3000; thin = 1;
##          total post-warmup draws = 12000
##
## Smooth Terms:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sds(sigma_ssynthetic_alpha_1)     3.53      1.68     1.12     7.57 1.00     1756     1034
##
## Population-Level Effects:
##                          Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept                   -0.02      0.02    -0.05     0.02 1.00     7806     7356
## sigma_Intercept             -1.44      0.05    -1.54    -1.34 1.00     8401     7731
## synthetic_alpha              1.15      0.03     1.09     1.22 1.00     4029     1530
## sigma_ssynthetic_alpha_1     1.28      6.46    -8.91    15.77 1.00     1524      574
##
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
kable(rmse_alpha <- by_draw %>% mean_hdci(sigma), caption = "Average prediction error (RMSE)", digits = 2)
Average prediction error (RMSE)
sigma .lower .upper .width .point .interval
0.27 0.21 0.33 0.95 mean hdci
kable(mae_alpha <- by_draw %>% mean_hdci(mae), caption = "Average prediction error (MAE)", digits = 2)
Average prediction error (MAE)
mae .lower .upper .width .point .interval
0.21 0.18 0.24 0.95 mean hdci
plot_prediction_error_alpha <- plot(conditional_effects(m_lmsynth_rel_scales, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  geom_smooth(stat = "identity", color = "#a48500", fill = "#EDC951") + 
  xlab("Synthetic Cronbach's alpha") + 
  ylab("Prediction error (sigma)") +
  coord_cartesian(xlim = c(-1, 1), ylim = c(0, 0.35))
plot_prediction_error_alpha

Scatter plot

pred <- conditional_effects(m_lmsynth_rel_scales, method = "predict")
ggplot(scales, aes(synthetic_alpha, empirical_alpha, 
                   color = str_detect(scale, "^random"), 
              ymin = empirical_alpha - empirical_alpha_se,
              ymax = empirical_alpha + empirical_alpha_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(alpha = 0.6, size = 1) +
  geom_smooth(aes(
    x = synthetic_alpha,
    y = estimate__,
    ymin = lower__,
    ymax = upper__,
  ), stat = "identity", 
  color = "#a48500",
  fill = "#EDC951",
  data = as.data.frame(pred$synthetic_alpha)) +
  scale_color_manual(values = c("#00A0B0", "#6A4A3C"),
                     guide = "none") +
  xlab("Synthetic Cronbach's alpha") + 
  ylab("Empirical Cronbach's alpha") +
  theme_bw() +
  coord_fixed(xlim = c(-1, 1), ylim = c(-1,1))  -> plot_rels
plot_rels

Interactive plot

(scales %>% 
  filter(!str_detect(scale, "^random")) %>%
  mutate(synthetic_alpha = round(synthetic_alpha, 2),
         empirical_alpha = round(empirical_alpha, 2),
         scale = str_replace_all(scale, "_+", " ")) %>% 
ggplot(., aes(synthetic_alpha, empirical_alpha, 
              # ymin = empirical_r - empirical_r_se, 
              # ymax = empirical_r + empirical_r_se, 
              label = scale)) + 
  geom_abline(linetype = "dashed") +
  geom_point(alpha = 0.3, size = 1, color = "#00A0B0") +
  xlab("Synthetic Cronbach's alpha") + 
  ylab("Empirical Cronbach's alpha") +
  theme_bw() +
  theme(legend.position='none') + 
   coord_fixed(xlim = c(-1,1), ylim = c(-1,1))) %>% 
  ggplotly()

Table

scales %>% 
  filter(type != "random") %>% 
  mutate(empirical_alpha = sprintf("%.2f±%.3f", empirical_alpha,
                               empirical_alpha_se),
         synthetic_alpha = sprintf("%.2f", synthetic_alpha),
         scale = str_replace_all(scale, "_+", " ")
         ) %>% 
  select(scale, empirical_alpha, synthetic_alpha, number_of_items) %>% 
  DT::datatable(rownames = FALSE,
                filter = "top")

Robustness checks

Accuracy by whether scales were real or random

The SurveyBot3000 does not “know” whether scales were published in the literature or formed at random. Knowing what we do about the research literature in psychology, we can infer that published scales will usually exceed the Nunnally threshold of .70. Hence, we know that the synthetic alphas for published scales should rarely be below .70. If we regress synthetic alphas on empirical alphas separately for the scales taken from the literature, we see this as a bias (a positive regression intercept of .68 and a slope ≠ 1, .26). Still, the synthetic alpha estimates are predictive of empirical alphas with an accuracy of .65.

There is no clear bias for the random scales. When both are analyzed jointly, the clear selection bias for the published scales is mostly averaged out but is reflected in the slope exceeding 1.

scales %>% 
  group_by(type) %>% 
  summarise(broom::tidy(cor.test(synthetic_alpha, empirical_alpha)), sd_alpha = sd(empirical_alpha), n = n()) %>% 
  knitr::kable(digits = 2, caption = "Accuracy shown separately for randomly formed and real scales")
Accuracy shown separately for randomly formed and real scales
type estimate statistic p.value parameter conf.low conf.high method alternative sd_alpha n
random 0.63 11.47 0 198 0.54 0.71 Pearson’s product-moment correlation two.sided 0.37 200
real 0.64 6.11 0 55 0.45 0.77 Pearson’s product-moment correlation two.sided 0.10 57
scales %>% 
  group_by(type) %>% 
  summarise(broom::tidy(lm(empirical_alpha ~ synthetic_alpha)), n = n()) %>% 
  knitr::kable(digits = 2, caption = "Regression intercepts and slopes for randomly formed and real scales")
Regression intercepts and slopes for randomly formed and real scales
type term estimate std.error statistic p.value n
random (Intercept) -0.08 0.02 -3.44 0 200
random synthetic_alpha 1.15 0.10 11.47 0 200
real (Intercept) 0.68 0.03 23.76 0 57
real synthetic_alpha 0.26 0.04 6.11 0 57

As in our Stage 1 submission

Here are the results if we calculate the accuracy and prediction error as in the Stage 1 submission. We now think this approach, by conditioning on random variation in the empirical correlations, gave a misleading picture of the accuracy and bias of the synthetic Cronbach’s alphas. Here we report the results if we conduct the analysis as in Stage 1 (but with the corrected SE of empirical alphas).

s1_scales <- scales %>%
  filter(number_of_items > 2) %>% 
  rowwise() %>%
  mutate(reverse_items = if_else(type == "random", list(reverse_items_by_1st), list(reverse_items)),
         r_real_rev = list(reverse_items(r_real, reverse_items)),
         pt_r_llm_rev = list(reverse_items(pt_r_llm, reverse_items)),
         r_llm_rev = list(reverse_items(r_llm, reverse_items))) %>%
  mutate(
    rel_real = list(psych::alpha(r_real_rev, keys = F, n.obs = N)$feldt),
    rel_llm = list(psych::alpha(r_llm_rev, keys = F, n.obs = N)$feldt),
    rel_pt_llm = list(psych::alpha(pt_r_llm_rev, keys = F, n.obs = N)$feldt)) %>%
  mutate(empirical_alpha = rel_real$alpha$raw_alpha,
         synthetic_alpha = rel_llm$alpha$raw_alpha,
         pt_synthetic_alpha = rel_pt_llm$alpha$raw_alpha) %>%
  mutate(
    empirical_alpha_se = mean(diff(unlist(psychometric::alpha.CI(empirical_alpha, k = number_of_items, N = N, level = 0.95))))/1.96) %>% 
      filter(empirical_alpha > 0)

s1_r <- broom::tidy(cor.test(s1_scales$empirical_alpha, s1_scales$synthetic_alpha))
m_lmsynth_rel_scales_s1 <- brm(
  bf(empirical_alpha | mi(empirical_alpha_se) ~ synthetic_alpha,
     sigma ~ poly(synthetic_alpha, degree = 3)), data = s1_scales, 
  iter = 6000, control = list(adapt_delta = 0.9),
  file = "ignore/m_synth_rr_rel_lm_as_stage_1")

pred <- conditional_effects(m_lmsynth_rel_scales_s1, method = "predict")
ggplot(s1_scales, aes(synthetic_alpha, empirical_alpha, 
                   color = str_detect(scale, "^random"), 
              ymin = empirical_alpha - empirical_alpha_se,
              ymax = empirical_alpha + empirical_alpha_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(alpha = 0.6, size = 1) +
  geom_smooth(aes(
    x = synthetic_alpha,
    y = estimate__,
    ymin = lower__,
    ymax = upper__,
  ), stat = "identity", 
  color = "#a48500",
  fill = "#EDC951",
  data = as.data.frame(pred$synthetic_alpha)) +  scale_color_manual(values = c("#00A0B0", "#6A4A3C"),
                     guide = "none") +
  xlab("Synthetic Cronbach's alpha") + 
  ylab("Empirical Cronbach's alpha") +
  theme_bw() +
  coord_fixed(xlim = c(-1, 1), ylim = c(-1,1))  -> s1_plot_rels

newdata <- m_lmsynth_rel_scales_s1$data %>% select(empirical_alpha, synthetic_alpha, empirical_alpha_se)
epreds <- epred_draws(newdata = newdata, obj = m_lmsynth_rel_scales_s1, re_formula = NA)
preds <- predicted_draws(newdata = newdata, obj = m_lmsynth_rel_scales_s1, re_formula = NA)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(
             mae = mean(abs(.epred - .prediction)),
            .epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

accuracy_bayes_rels_poly <- by_draw %>% mean_hdci(latent_r)

s1_plot_rels

bind_rows(
  r %>% 
    mutate(model = "fine-tuned", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  s1_r %>% 
    mutate(model = "fine-tuned, conditioned on empirical r", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  accuracy_bayes_rels %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  accuracy_bayes_rels_poly %>% 
    mutate(model = "fine-tuned, conditioned on empirical r", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  ) %>% 
  knitr::kable(digits = 2, caption = "Accuracy of synthetic alphas when empirical alphas are biased upward through adaptive item reversion and selection on positive alphas")
Accuracy of synthetic alphas when empirical alphas are biased upward through adaptive item reversion and selection on positive alphas
model kind accuracy conf.low conf.high
fine-tuned manifest 0.85 0.81 0.88
fine-tuned, conditioned on empirical r manifest 0.74 0.68 0.80
fine-tuned latent outcome (Bayesian EIV) 0.84 0.79 0.90
fine-tuned, conditioned on empirical r latent outcome (Bayesian EIV) 0.77 0.69 0.85

Number of items as a trivial predictor

Although the number of items alone can of course predict Cronbach’s alpha, the synthetic alphas explain much more variance in empirical alphas.

scales %>% 
  ungroup() %>% 
  summarise(broom::tidy(cor.test(number_of_items, empirical_alpha)), sd_alpha = sd(empirical_alpha), n = n()) %>% 
  knitr::kable(digits = 2)
estimate statistic p.value parameter conf.low conf.high method alternative sd_alpha n
0.04 0.67 0.5 255 -0.08 0.16 Pearson’s product-moment correlation two.sided 0.54 257
summary(lm(empirical_alpha ~ number_of_items, scales))
##
## Call:
## lm(formula = empirical_alpha ~ number_of_items, data = scales)
##
## Residuals:
##     Min      1Q  Median      3Q     Max
## -1.4908 -0.3462 -0.0713  0.3084  0.9129
##
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)
## (Intercept)     -0.015196   0.080899  -0.188    0.851
## number_of_items  0.008388   0.012503   0.671    0.503
##
## Residual standard error: 0.5448 on 255 degrees of freedom
## Multiple R-squared:  0.001762,   Adjusted R-squared:  -0.002153
## F-statistic:  0.45 on 1 and 255 DF,  p-value: 0.5029
summary(lm(empirical_alpha ~ number_of_items + synthetic_alpha, scales))
##
## Call:
## lm(formula = empirical_alpha ~ number_of_items + synthetic_alpha,
##     data = scales)
##
## Residuals:
##      Min       1Q   Median       3Q      Max
## -0.94552 -0.14535 -0.01649  0.15466  0.81161
##
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)
## (Intercept)     -0.024067   0.043008  -0.560    0.576
## number_of_items -0.002373   0.006660  -0.356    0.722
## synthetic_alpha  1.256941   0.049366  25.462   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2896 on 254 degrees of freedom
## Multiple R-squared:  0.719,  Adjusted R-squared:  0.7168
## F-statistic: 324.9 on 2 and 254 DF,  p-value: < 2.2e-16

Deattenuating accuracy

scales %>% ungroup() %>% 
  summarise(mean(empirical_alpha), sd(empirical_alpha)) %>% 
  kable(digits = 2, caption = "Accuracy across all scales")
Accuracy across all scales
mean(empirical_alpha) sd(empirical_alpha)
0.03 0.54
scales %>% group_by(type) %>% 
  summarise(mean_alpha = mean(empirical_alpha), 
            sd_alpha = sd(empirical_alpha),
            broom::tidy(cor.test(synthetic_alpha, empirical_alpha)), 
            n = n()) %>% 
  kable(digits = 2, caption = "Accuracy separated by random/real")
Accuracy separated by random/real
type mean_alpha sd_alpha estimate statistic p.value parameter conf.low conf.high method alternative n
random -0.20 0.37 0.63 11.47 0 198 0.54 0.71 Pearson’s product-moment correlation two.sided 200
real 0.84 0.10 0.64 6.11 0 55 0.45 0.77 Pearson’s product-moment correlation two.sided 57
psychometric::cRRr(0.647, 0.102, 0.514) %>% 
  kable(digits = 2, caption = "Accuracy for real scales disattenuated for variance restriction")
Accuracy for real scales disattenuated for variance restriction
unrestricted
0.97

Pre-trained model

Is the accuracy lower for the pre-trained model?

ggplot(scales, aes(pt_synthetic_alpha, empirical_alpha, 
                   color = str_detect(scale, "^random"), 
              ymin = empirical_alpha - empirical_alpha_se,
              ymax = empirical_alpha + empirical_alpha_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(alpha = 0.6, size = 1) +
  scale_color_manual(values = c("#00A0B0", "#6A4A3C"),
                     guide = "none") +
  xlab("Synthetic Cronbach's alpha") + 
  ylab("Empirical Cronbach's alpha") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1)) -> pt_plot_rels
pt_plot_rels

Synthetic Scale Correlations

manifest_scores = arrow::read_feather(file = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.scale_correlations.feather")))
pt_manifest_scores = arrow::read_feather(file = file.path(data_path, glue("{pretrained_model_name}.raw.validation-study-2024-11-01.scale_correlations.feather")))

manifest_scores <- manifest_scores %>%
 left_join(real_scales, by = c("scale_a" = "scale")) %>%
 left_join(real_scales, by = c("scale_b" = "scale")) %>% 
  left_join(pt_manifest_scores %>% select(scale_a, scale_b, pt_synthetic_r = synthetic_r), by = c("scale_a", "scale_b"))

pt_manifest_scores <- pt_manifest_scores %>%
 left_join(real_scales, by = c("scale_a" = "scale")) %>%
 left_join(real_scales, by = c("scale_b" = "scale"))

manifest_scores_all <- manifest_scores
pt_manifest_scores_all <- pt_manifest_scores
manifest_scores <- manifest_scores %>% filter(number_of_items.x >= 3, number_of_items.y >= 3)
pt_manifest_scores <- pt_manifest_scores %>% filter(number_of_items.x >= 3, number_of_items.y >= 3)

Accuracy

r <- broom::tidy(cor.test(manifest_scores$empirical_r, manifest_scores$synthetic_r))
pt_r <- broom::tidy(cor.test(pt_manifest_scores$empirical_r, pt_manifest_scores$synthetic_r))

se2 <- mean(manifest_scores$empirical_r_se^2)
model <- paste0('
    # Latent variables
    PearsonLatent =~ 1*empirical_r

    # Fixing error variances based on known standard errors
    empirical_r ~~ ',se2,'*empirical_r

    # Relationship between latent variables
    PearsonLatent ~~ synthetic_r
  ')

fit <- sem(model, data = manifest_scores)
pt_fit <- sem(model, data = pt_manifest_scores)


pt_m_lmsynth_r_scales <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(scale_a, scale_b)),
     sigma ~ s(synthetic_r)), data = pt_manifest_scores, 
  file = "ignore/pt_m_synth_rr_r_scales_lm8")

newdata <- pt_m_lmsynth_r_scales$data %>% select(empirical_r, synthetic_r, empirical_r_se)
epreds <- epred_draws(newdata = newdata, obj = pt_m_lmsynth_r_scales, re_formula = NA)
preds <- predicted_draws(newdata = newdata, obj = pt_m_lmsynth_r_scales, re_formula = NA)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

pt_accuracy_bayes_scales <- by_draw %>% mean_hdci(latent_r)

m_lmsynth_r_scales <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(scale_a, scale_b)),
     sigma ~ s(synthetic_r)), data = manifest_scores, 
  file = "ignore/m_synth_rr_r_scales_lm8")

sd_synth <- sd(m_lmsynth_r_scales$data$synthetic_r)


newdata <- m_lmsynth_r_scales$data %>% select(empirical_r, synthetic_r, empirical_r_se)
epreds <- epred_draws(newdata = newdata, obj = m_lmsynth_r_scales, re_formula = NA)
preds <- predicted_draws(newdata = newdata, obj = m_lmsynth_r_scales, re_formula = NA)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(
            mae = mean(abs(.epred - .prediction)),
            .epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

accuracy_bayes_scales <- by_draw %>% mean_hdci(latent_r)

bind_rows(
  pt_r %>% 
    mutate(model = "pre-trained", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  standardizedsolution(pt_fit) %>% 
    filter(lhs == "PearsonLatent", rhs ==  "synthetic_r") %>% 
    mutate(model = "pre-trained", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  pt_accuracy_bayes_scales %>% 
    mutate(model = "pre-trained", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  r %>% 
    mutate(model = "fine-tuned", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high),
  standardizedsolution(fit) %>% 
    filter(lhs == "PearsonLatent", rhs ==  "synthetic_r") %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  accuracy_bayes_scales %>% 
    mutate(model = "fine-tuned", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper)
  ) %>% 
  kable(digits = 2, caption = str_c("Accuracy for k=",nrow(manifest_scores)," scale pairs (",n_distinct(c(manifest_scores$scale_a, manifest_scores$scale_b))," scales) across language models and methods"))
Accuracy for k=1568 scale pairs (57 scales) across language models and methods
model kind accuracy conf.low conf.high
pre-trained manifest 0.50 0.46 0.54
pre-trained latent outcome (SEM) 0.51 0.47 0.55
pre-trained latent outcome (Bayesian EIV) 0.61 0.56 0.66
fine-tuned manifest 0.83 0.81 0.85
fine-tuned latent outcome (SEM) 0.84 0.83 0.86
fine-tuned latent outcome (Bayesian EIV) 0.84 0.82 0.87

Prediction error plot according to synthetic estimate

m_lmsynth_r_scales
##  Family: gaussian
##   Links: mu = identity; sigma = log
## Formula: empirical_r | mi(empirical_r_se) ~ synthetic_r + (1 | mm(scale_a, scale_b))
##          sigma ~ s(synthetic_r)
##    Data: manifest_scores (Number of observations: 1568)
##   Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup draws = 4000
##
## Smooth Terms:
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sds(sigma_ssynthetic_r_1)     1.15      0.66     0.17     2.67 1.00      795     1059
##
## Group-Level Effects:
## ~mmscale_ascale_b (Number of levels: 57)
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.06      0.01     0.04     0.08 1.00     1294     1706
##
## Population-Level Effects:
##                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept               -0.00      0.01    -0.02     0.02 1.00     1297     2114
## sigma_Intercept         -1.86      0.02    -1.90    -1.82 1.00     3551     2614
## synthetic_r              1.20      0.02     1.16     1.24 1.00     3469     2920
## sigma_ssynthetic_r_1    -1.30      2.28    -6.44     2.16 1.00      989      993
##
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
kable(rmse_scales <- by_draw %>% mean_hdci(sigma), caption = "Average prediction error (RMSE)", digits = 2)
Average prediction error (RMSE)
sigma .lower .upper .width .point .interval
0.16 0.14 0.17 0.95 mean hdci
kable(mae_scales <- by_draw %>% mean_hdci(mae), caption = "Average prediction error (MAE)", digits = 2)
Average prediction error (MAE)
mae .lower .upper .width .point .interval
0.13 0.12 0.13 0.95 mean hdci
plot_prediction_error_scales <- plot(conditional_effects(m_lmsynth_r_scales, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  geom_smooth(stat = "identity", color = "#a48500", fill = "#EDC951") + 
  xlab("Synthetic inter-scale correlation") + 
  ylab("Prediction error (sigma)")
plot_prediction_error_scales

Scatter plot

pred <- conditional_effects(m_lmsynth_r_scales, method = "predict")
ggplot(manifest_scores, aes(synthetic_r, empirical_r, 
              ymin = empirical_r - empirical_r_se,
              ymax = empirical_r + empirical_r_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(color = "#00A0B0", alpha = 0.1, size = 1) +
  geom_smooth(aes(
    x = synthetic_r,
    y = estimate__,
    ymin = lower__,
    ymax = upper__,
  ), stat = "identity", 
  color = "#a48500",
  fill = "#EDC951",
  data = as.data.frame(pred$synthetic_r)) +
  xlab("Synthetic inter-scale correlation") + 
  ylab("Empirical inter-scale correlation") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1)) -> plot_scales
plot_scales

Interactive plot

(manifest_scores %>% 
  mutate(synthetic_r = round(synthetic_r, 2),
         empirical_r = round(empirical_r, 2),
         scales = str_replace_all(str_c(scale_a, "\n", scale_b),
                                  "_+", " ")) %>% 
ggplot(., aes(synthetic_r, empirical_r, 
              # ymin = empirical_r - empirical_r_se, 
              # ymax = empirical_r + empirical_r_se, 
              label = scales)) + 
  geom_abline(linetype = "dashed") +
  geom_point(color = "#00A0B0", alpha = 0.3, size = 1) +
  xlab("Synthetic inter-scale correlation") + 
  ylab("Empirical inter-scale correlation") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1))) %>% 
  ggplotly()

Table

manifest_scores %>% 
                mutate(empirical_r = sprintf("%.2f±%.3f", empirical_r,
                                             empirical_r_se),
                       synthetic_r = sprintf("%.2f", synthetic_r),
                       scale_a = str_replace_all(scale_a, "_+", " "),
                       scale_b = str_replace_all(scale_b, "_+", " ")
                       ) %>% 
                select(scale_a, scale_b, empirical_r, synthetic_r) %>% 
  DT::datatable(rownames = FALSE,
                filter = "top")

Robustness checks

Comparing spline and polynomial models for heteroscedasticity

# For scale correlations
m_lmsynth_r_scales_poly <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(scale_a, scale_b)),
     sigma ~ poly(synthetic_r, degree = 3)), data = manifest_scores, 
  file = "ignore/m_synth_rr_r_scales_lm_poly")

newdata <- m_lmsynth_r_scales_poly$data %>% select(empirical_r, synthetic_r, empirical_r_se)
epreds <- epred_draws(newdata = newdata, obj = m_lmsynth_r_scales_poly, re_formula = NA)
preds <- predicted_draws(newdata = newdata, obj = m_lmsynth_r_scales_poly, re_formula = NA)
epred_preds <- epreds %>% left_join(preds)
by_draw <- epred_preds %>% group_by(.draw) %>% 
  summarise(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            latent_r = sqrt(.epred/.prediction))

accuracy_bayes_scales_poly <- by_draw %>% mean_hdci(latent_r)

bind_rows(
  accuracy_bayes_scales %>% 
    mutate(model = "spline", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper),
  accuracy_bayes_scales_poly %>% 
    mutate(model = "polynomial", kind = "latent outcome (Bayesian EIV)") %>% 
    select(model, kind, accuracy = latent_r, conf.low = .lower, conf.high = .upper)
) %>% 
  knitr::kable(digits = 2, caption = "Comparing spline and polynomial models for scale correlations")
Comparing spline and polynomial models for scale correlations
model kind accuracy conf.low conf.high
spline latent outcome (Bayesian EIV) 0.84 0.82 0.87
polynomial latent outcome (Bayesian EIV) 0.85 0.82 0.87
plot_prediction_error_scales_poly <- plot(conditional_effects(m_lmsynth_r_scales_poly, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  geom_smooth(stat = "identity", color = "#a48500", fill = "#EDC951") + 
  xlab("Synthetic inter-scale correlation") + 
  ylab("Prediction error (sigma)")
plot_prediction_error_scales_poly

How does number of items across the two scales relate to accuracy?

by_item_number <- manifest_scores_all %>%
  mutate(items = number_of_items.x + number_of_items.y) %>%
  group_by(items) %>%
  filter(n() > 10) %>% 
  summarise(broom::tidy(cor.test(empirical_r, synthetic_r)), pt_cor = cor(empirical_r, pt_synthetic_r), pairwise_n = n()) 

by_item_number %>% 
  ggplot(aes(items, estimate, ymin = conf.low, ymax = conf.high)) + 
  geom_pointrange() +
  scale_y_continuous("Manifest accuracy (with 95% confidence interval)") +
  xlab("Number of items summed across scales")

Averages
real_scales %>% ungroup() %>% 
  filter(number_of_items >= 3) %>% 
  summarise(median(number_of_items),
            mean(number_of_items))
## # A tibble: 1 × 2
##   `median(number_of_items)` `mean(number_of_items)`
##                       <int>                   <dbl>
## 1                         4                    5.75
Accuracy including 2-item scales
r_2item <- broom::tidy(cor.test(manifest_scores_all$empirical_r, manifest_scores_all$synthetic_r))
pt_r_2item <- broom::tidy(cor.test(pt_manifest_scores_all$empirical_r, pt_manifest_scores_all$synthetic_r))

bind_rows(
  pt_r %>% 
    mutate(model = "pre-trained", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high) %>% 
    mutate(items = ">= 3"),
  r %>% 
    mutate(model = "fine-tuned", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high) %>% 
    mutate(items = ">= 3"),
  pt_r_2item %>% 
    mutate(model = "pre-trained", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high) %>% 
    mutate(items = ">= 2"),
  r_2item %>% 
    mutate(model = "fine-tuned", kind = "manifest") %>% 
    select(model, kind, accuracy = estimate, conf.low, conf.high) %>% 
    mutate(items = ">= 2"),
  ) %>% 
  kable(digits = 2, caption = "Accuracy across language models and methods")
Accuracy across language models and methods
model kind accuracy conf.low conf.high items
pre-trained manifest 0.50 0.46 0.54 >= 3
fine-tuned manifest 0.83 0.81 0.85 >= 3
pre-trained manifest 0.47 0.44 0.49 >= 2
fine-tuned manifest 0.75 0.73 0.76 >= 2
broom::tidy(lm(estimate ~ items, by_item_number, weights = 1/(by_item_number$conf.high-by_item_number$conf.low))) %>% 
  kable(digits = 2, caption = "Accuracy increase with number of items")
Accuracy increase with number of items
term estimate std.error statistic p.value
(Intercept) 0.62 0.04 15.62 0
items 0.01 0.00 4.29 0
manifest_scores %>%
  filter(number_of_items.x >= 5, number_of_items.y >= 5) %>%
  summarise(cor = cor(empirical_r, synthetic_r), n()) %>% 
  kable(digits = 2, caption = "Accuracy when both scales have at least 5 items")
Accuracy when both scales have at least 5 items
cor n()
0.88 228
manifest_scores %>%
  filter(number_of_items.x >= 10, number_of_items.y >= 10) %>%
  summarise(cor = cor(empirical_r, synthetic_r), n()) %>% 
  kable(digits = 2, caption = "Accuracy when both scales have at least 10 items")
Accuracy when both scales have at least 10 items
cor n()
0.87 36

Is the accuracy lower for the pre-trained model?

ggplot(pt_manifest_scores, aes(synthetic_r, empirical_r, 
              ymin = empirical_r - empirical_r_se,
              ymax = empirical_r + empirical_r_se)) + 
  geom_abline(linetype = "dashed") +
  geom_point(color = "#00A0B0", alpha = 0.1, size = 1) +
  xlab("Synthetic inter-scale correlation") + 
  ylab("Empirical inter-scale correlation") +
  theme_bw() +
  coord_fixed(xlim = c(-1,1), ylim = c(-1,1)) -> pt_plot_scales
pt_plot_scales

Combined plots

Accuracy scatterplots

library(patchwork)
pt_plot_items2 <- pt_plot_items +
  annotate("text", size = 3, x = -1, y = 0.98, vjust = 0, hjust = 0, label = with(pt_accuracy_bayes_items, { sprintf("accuracy = %.2f [%.2f;%.2f]", latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = -.1, y = 0.5, vjust = 1, hjust = 1, label = "r(CESD_10,19)", color = "#00A0B0") +
  annotate("segment", x = -.1, y = 0.5, xend = 0.4185763, yend = 0.5875796, color = "#00A0B0", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = 0, y = -0.9, hjust = 0.5, label = "r(RAAS_02,05)", color = "#00A0B0") + 
  annotate("segment", x = 0, y = -0.83, xend = 0.5842606, yend = -0.7020895, color = "#00A0B0", alpha = 0.7)
  
plot_items2 <- plot_items +
  annotate("text", size = 3, x = -1, y = 0.98, vjust = 0, hjust = 0, label = with(accuracy_bayes_items, { sprintf("accuracy = %.2f [%.2f;%.2f]", latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = -.1, y = 0.5, vjust = 1, hjust = 1, label = "r(CESD_10,19)", color = "#00A0B0") +
  annotate("segment", x = -.1, y = 0.5, xend = 0.5369071, yend = 0.5875796, color = "#00A0B0", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = 0, y = -0.9, hjust = 0.5, label = "r(RAAS_02,05)", color = "#00A0B0") + 
  annotate("segment", x = 0, y = -0.83, xend = 0.09218573, yend = -0.7020895, color = "#00A0B0", alpha = 0.7)

pt_plot_rels2 <- pt_plot_rels + 
  annotate("text", size = 3, x = -1, y = .98, vjust = 0, hjust = 0, label = with(pt_accuracy_bayes_rels, { sprintf("accuracy = %.2f [%.2f;%.2f]", latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5,  x = 0.68, y = 0, hjust = 0.5, label = "Fear of COVID", color = "#00A0B0") +
  annotate("segment",  x = 0.68, y = 0.05, xend = 0.9563192, yend = 0.9262542, color = "#00A0B0", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = -1, y = 0.5, hjust = 0, label = "HEXACO fairness", color = "#00A0B0") +
  annotate("segment", x = -0.65, y = 0.55,  xend = -0.3262759, yend = 0.8217475, color = "#00A0B0", alpha = 0.7)


get_scale_point <- function(data, synthetic_approx, empirical_approx) {
  data %>%
    ungroup() %>% 
    # Find closest point to target coordinates
    mutate(dist = sqrt((synthetic_alpha - synthetic_approx)^2 + 
                      (empirical_alpha - empirical_approx)^2)) %>%
    arrange(dist) %>%
    slice(1) %>%
    select(synthetic_alpha, empirical_alpha)
}
p1 <- get_scale_point(scales, 0.30, 0.22)
p2 <- get_scale_point(scales, 0.12, -0.36) 
p3 <- get_scale_point(scales, -0.4, -0.90)

plot_rels2 <- plot_rels + 
  annotate("text", size = 3, x = -1, y = .98, vjust = 0, hjust = 0, label = with(accuracy_bayes_rels, { sprintf("accuracy = %.2f [%.2f;%.2f]", latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = -0.2, y = -0.9, hjust = 0, label = "randomly formed scales", color = "#6A4A3C") +
  annotate("segment", x = 0.4, y = -0.85, xend = p1$synthetic_alpha, yend = p1$empirical_alpha, color = "#6A4A3C", alpha = 0.7) +
  annotate("segment", x = 0.4, y = -0.85, xend = p2$synthetic_alpha, yend = p2$empirical_alpha, color = "#6A4A3C", alpha = 0.7) +
  annotate("segment", x = 0.4, y = -0.85, xend = p3$synthetic_alpha, yend = p3$empirical_alpha, color = "#6A4A3C", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = 0.68, y = 0, hjust = 0.5, label = "Fear of COVID", color = "#00A0B0") +
  annotate("segment", x = 0.68, y = 0.05, xend = 0.8864024, yend = 0.9262542, color = "#00A0B0", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = -1, y = 0.5, hjust = 0,label = "HEXACO fairness", color = "#00A0B0") +
  annotate("segment", x = -0.65, y = 0.55, xend = 0.0305553, yend = 0.8217475, color = "#00A0B0", alpha = 0.7)


pt_plot_scales2 <- pt_plot_scales +
  annotate("text", size = 3, x = -1, y = 0.98, vjust = 0, hjust = 0, label = with(pt_accuracy_bayes_scales, { sprintf("accuracy = %.2f [%.2f;%.2f]", latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = -0.4, y = 0.5, hjust = 1, label = "r(UWES vigor,\nWGS)", color = "#00A0B0") +
  annotate("segment", x = -.38, y = 0.45, xend = 0.6586402, yend = 0.5683167, color = "#00A0B0", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = -.1, y = -0.9, hjust = 0.5, label = "r(CES-D well-being,\nCES-D depressive affect)", color = "#00A0B0") +
  annotate("segment", x = -0.2, y = -.75, xend = 0.4963392, yend = -0.7583637, color = "#00A0B0", alpha = 0.7)


plot_scales2 <- plot_scales +
  annotate("text", size = 3, x = -1, y = 0.98, vjust = 0, hjust = 0, label = with(accuracy_bayes_scales, { sprintf("accuracy = %.2f [%.2f;%.2f]", latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = -0.4, y = 0.5, hjust = 1, label = "r(UWES vigor,\nWGS)", color = "#00A0B0") +
  annotate("segment", x = -.38, y = 0.45, xend = .55, yend = 0.5683167, color = "#00A0B0", alpha = 0.7) +
  
  annotate("text", size = 2.5, x = -.1, y = -0.9, hjust = 0.5, label = "r(CES-D well-being,\nCES-D depressive affect)", color = "#00A0B0") +
  annotate("segment", x = -0.2, y = -.75, xend = 0.02, yend = -0.7583637, color = "#00A0B0", alpha = 0.7)


(pt_plot_items2 + ggtitle("Pre-trained model before domain adaptation and fine-tuning") +
    pt_plot_rels2 +
    pt_plot_scales2) /


(plot_items2 + ggtitle("SurveyBot 3000") +
    plot_rels2  +
    plot_scales2)

ggsave("Figure_rr.pdf", width = 8.3, height = 6, device = grDevices::cairo_pdf)
ggsave("Figure_rr.png", width = 8.3, height = 6)

Prediction error plots

library(patchwork)

(plot_prediction_error_items + 
    coord_cartesian(xlim = c(-1, 1), ylim = c(0, 0.4)) +
    annotate("text", size = 3, x = -1, y = 0.4, vjust = 0, hjust = 0, label = with(rmse_items, { sprintf("RMSE = %.2f [%.2f;%.2f]", sigma, .lower, .upper) })) +
    
    plot_prediction_error_alpha + 
    coord_cartesian(xlim = c(-1, 1), ylim = c(0, 0.4))  +
    annotate("text", size = 3, x = -1, y = 0.4, vjust = 0, hjust = 0, label = with(rmse_alpha, { sprintf("RMSE = %.2f [%.2f;%.2f]", sigma, .lower, .upper) })) +
    
    plot_prediction_error_scales + 
    coord_cartesian(xlim = c(-1, 1), ylim = c(0, 0.4)) +
    annotate("text", size = 3, x = -1, y = 0.4, vjust = 0, hjust = 0, label = with(rmse_scales, { sprintf("RMSE = %.2f [%.2f;%.2f]", sigma, .lower, .upper) }))
)

ggsave("ignore/Figure_prediction_error_rr.pdf", width = 8.3, height = 3, device = grDevices::cairo_pdf)
ggsave("ignore/Figure_prediction_error_rr.png", width = 8.3, height = 3)
LS0tCnRpdGxlOiAiTGFuZ3VhZ2UgbW9kZWxzIGFjY3VyYXRlbHkgaW5mZXIgY29ycmVsYXRpb25zIGJldHdlZW4gcHN5Y2hvbG9naWNhbCBpdGVtcyBhbmQgPSBmcm9tIHRleHQgYWxvbmUiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNzczogc3R5bGUuY3NzIAotLS0KCkhlcmUsIHdlIGFwcGx5IHRoZSBtb2RlbCB0byB0aGUgZGF0YSBjb2xsZWN0ZWQgaW4gb3VyIFJlZ2lzdGVyZWQgUmVwb3J0IHZhbGlkYXRpb24gc2FtcGxlIG9uIE5vdiAxLCAyMDI0LgoKCmBgYHtyIHdhcm5pbmc9RixtZXNzYWdlPUZ9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXJyb3IgPSBULCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEYpCiMgTGlicmFyaWVzIGFuZCBTZXR0aW5ncwoKIyBMaWJzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShhcnJvdykKbGlicmFyeShnbHVlKQpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KGxhdmFhbikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkoYnJtcykKbGlicmFyeSh0aWR5YmF5ZXMpCmxpYnJhcnkoY21kc3RhbnIpCmxpYnJhcnkoY293cGxvdCkKCm9wdGlvbnMobWMuY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSwgCiAgICAgICAgYnJtcy5iYWNrZW5kID0gImNtZHN0YW5yIiwgCiAgICAgICAgYnJtcy5maWxlX3JlZml0ID0gIm5ldmVyIiwKICAgICAgICB3aWR0aCA9IDYwMDApCgp0aGVtZV9zZXQodGhlbWVfYncoKSkKCm1vZGVsX25hbWUgPSAiSXRlbVNpbWlsYXJpdHlUcmFpbmluZy0yMDI0MDUwMi10cmlhbDEyIgojbW9kZWxfbmFtZSA9ICJpdGVtLXNpbWlsYXJpdHktMjAyMzEwMTgtMTIyNTA0IgpwcmV0cmFpbmVkX21vZGVsX25hbWUgPSAiYWxsLW1wbmV0LWJhc2UtdjIiCgpkYXRhX3BhdGggPSBnbHVlKCIuL2RhdGEvaW50ZXJtZWRpYXRlLyIpCnByZXRyYWluZWRfZGF0YV9wYXRoID0gZ2x1ZSgiLi9kYXRhL2ludGVybWVkaWF0ZS8iKQoKc2V0LnNlZWQoNDIpCnNvdXJjZSgiZ2xvYmFsX2Z1bmN0aW9ucy5SIikKCgpycl92YWxpZGF0aW9uIDwtIGFycm93OjpyZWFkX2ZlYXRoZXIoZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLml0ZW1fY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCgpwdF9ycl92YWxpZGF0aW9uIDwtIGFycm93OjpyZWFkX2ZlYXRoZXIoZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoIntwcmV0cmFpbmVkX21vZGVsX25hbWV9LnJhdy52YWxpZGF0aW9uLXN0dWR5LTIwMjQtMTEtMDEuaXRlbV9jb3JyZWxhdGlvbnMuZmVhdGhlciIpKSkKCnJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhID0gYXJyb3c6OnJlYWRfZmVhdGhlcigKICBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy52YWxpZGF0aW9uLXN0dWR5LTIwMjQtMTEtMDEubWFwcGluZzIuZmVhdGhlciIpKQopICU+JQogIHJlbmFtZShzY2FsZV8wID0gc2NhbGUwLAogICAgICAgICBzY2FsZV8xID0gc2NhbGUxKQoKcnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhID0gYXJyb3c6OnJlYWRfZmVhdGhlcigKICBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy52YWxpZGF0aW9uLXN0dWR5LTIwMjQtMTEtMDEuaHVtYW4uZmVhdGhlciIpKQopCgpycl92YWxpZGF0aW9uX3NjYWxlcyA8LSBhcnJvdzo6cmVhZF9mZWF0aGVyKGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLnNjYWxlcy5mZWF0aGVyIikpCikKCnJhbmRvbV9zY2FsZXMgPC0gcmVhZFJEUygiZGF0YS9pbnRlcm1lZGlhdGUvcmFuZG9tX3NjYWxlc19yci5yZHMiKQoKTiA8LSBycl92YWxpZGF0aW9uX2h1bWFuX2RhdGEgJT4lIHN1bW1hcmlzZV9hbGwofiBzdW0oIWlzLm5hKC4pKSkgJT4lIG1pbigpCnRvdGFsX04gPC0gbnJvdyhycl92YWxpZGF0aW9uX2h1bWFuX2RhdGEpCgptYXBwaW5nX2RhdGEgPC0gcnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEKaXRlbXNfYnlfc2NhbGUgPC0gYmluZF9yb3dzKAogIHJyX3ZhbGlkYXRpb25fc2NhbGVzICU+JSBzZWxlY3QoLWtleWVkKSAlPiUgZmlsdGVyKHNjYWxlXzEgPT0gIiIpICU+JSBsZWZ0X2pvaW4obWFwcGluZ19kYXRhICU+JSBzZWxlY3QoLXNjYWxlXzEpLCBieSA9IGMoImluc3RydW1lbnQiLCAic2NhbGVfMCIpKSwKICBycl92YWxpZGF0aW9uX3NjYWxlcyAlPiUgc2VsZWN0KC1rZXllZCkgJT4lIGZpbHRlcihzY2FsZV8xICE9ICIiKSAlPiUgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSwgYnkgPSBjKCJpbnN0cnVtZW50IiwgInNjYWxlXzAiLCAic2NhbGVfMSIpKQopCmBgYAoKQWZ0ZXIgZXhjbHVzaW9ucywgd2UgaGFkIGRhdGEgb24gTj1gciB0b3RhbF9OYCByZXNwb25kZW50cy4gVGhlIGl0ZW0gd2l0aCB0aGUgbW9zdCBtaXNzaW5nIHZhbHVlcyBzdGlsbCBoYWQgbj1gciBOYC4KCgojIyBTeW50aGV0aWMgaW50ZXItaXRlbSBjb3JyZWxhdGlvbnMKYGBge3J9CnJyX3ZhbGlkYXRpb25fbGxtIDwtIHJyX3ZhbGlkYXRpb24gJT4lCiAgbGVmdF9qb2luKHJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLCBJbnN0cnVtZW50QSA9IGluc3RydW1lbnQsIFNjYWxlQSA9IHNjYWxlXzAsIFN1YnNjYWxlQSA9IHNjYWxlXzEpKSAlPiUKICBsZWZ0X2pvaW4ocnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCh2YXJpYWJsZV8yID0gdmFyaWFibGUsIEluc3RydW1lbnRCID0gaW5zdHJ1bWVudCwgU2NhbGVCID0gc2NhbGVfMCwgU3Vic2NhbGVCID0gc2NhbGVfMSkpICU+JSAKICBsZWZ0X2pvaW4ocHRfcnJfdmFsaWRhdGlvbiAlPiUgc2VsZWN0KHZhcmlhYmxlXzEsIHZhcmlhYmxlXzIsIHB0X3N5bnRoZXRpY19yID0gc3ludGhldGljX3IpKQoKcHRfcnJfdmFsaWRhdGlvbl9sbG0gPC0gcHRfcnJfdmFsaWRhdGlvbiAlPiUKICBsZWZ0X2pvaW4ocnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCh2YXJpYWJsZV8xID0gdmFyaWFibGUsIEluc3RydW1lbnRBID0gaW5zdHJ1bWVudCwgU2NhbGVBID0gc2NhbGVfMCwgU3Vic2NhbGVBID0gc2NhbGVfMSkpICU+JQogIGxlZnRfam9pbihycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzIgPSB2YXJpYWJsZSwgSW5zdHJ1bWVudEIgPSBpbnN0cnVtZW50LCBTY2FsZUIgPSBzY2FsZV8wLCBTdWJzY2FsZUIgPSBzY2FsZV8xKSkKYGBgCgoKIyMjIEFjY3VyYWN5CmBgYHtyfQpzZTIgPC0gbWVhbihycl92YWxpZGF0aW9uX2xsbSRlbXBpcmljYWxfcl9zZV4yKQoKciA8LSBicm9vbTo6dGlkeShjb3IudGVzdChycl92YWxpZGF0aW9uX2xsbSRlbXBpcmljYWxfciwgcnJfdmFsaWRhdGlvbl9sbG0kc3ludGhldGljX3IpKQpwdF9yIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KHB0X3JyX3ZhbGlkYXRpb25fbGxtJGVtcGlyaWNhbF9yLCBwdF9ycl92YWxpZGF0aW9uX2xsbSRzeW50aGV0aWNfcikpCgptb2RlbCA8LSBwYXN0ZTAoJwogICMgTGF0ZW50IHZhcmlhYmxlcwogIFBlYXJzb25MYXRlbnQgPX4gMSplbXBpcmljYWxfcgoKICAjIEZpeGluZyBlcnJvciB2YXJpYW5jZXMgYmFzZWQgb24ga25vd24gc3RhbmRhcmQgZXJyb3JzCiAgZW1waXJpY2FsX3Igfn4gJyxzZTIsJyplbXBpcmljYWxfcgoKICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxhdGVudCB2YXJpYWJsZXMKICBQZWFyc29uTGF0ZW50IH5+IHN5bnRoZXRpY19yCicpCgpmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gcnJfdmFsaWRhdGlvbl9sbG0pCnB0X2ZpdCA8LSBzZW0obW9kZWwsIGRhdGEgPSBwdF9ycl92YWxpZGF0aW9uX2xsbSkKCnB0X21fc3ludGhfcl9pdGVtcyA8LSBicm0oCiAgYmYoZW1waXJpY2FsX3IgfCBtaShlbXBpcmljYWxfcl9zZSkgfiBzeW50aGV0aWNfciArICgxfG1tKHZhcmlhYmxlXzEsIHZhcmlhYmxlXzIpKSwKICAgICBzaWdtYSB+IHMoc3ludGhldGljX3IpKSwgZGF0YSA9IHB0X3JyX3ZhbGlkYXRpb25fbGxtLCAKICBmaWxlID0gImlnbm9yZS9tX3B0X3N5bnRoX3JyX3JfaXRlbXNfbG0iKQoKbmV3ZGF0YSA8LSBwdF9tX3N5bnRoX3JfaXRlbXMkZGF0YSAlPiUgc2VsZWN0KGVtcGlyaWNhbF9yLCBzeW50aGV0aWNfciwgZW1waXJpY2FsX3Jfc2UpCmVwcmVkcyA8LSBlcHJlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gcHRfbV9zeW50aF9yX2l0ZW1zLCByZV9mb3JtdWxhID0gTkEsIG5kcmF3cyA9IDIwMCkKcHJlZHMgPC0gcHJlZGljdGVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBwdF9tX3N5bnRoX3JfaXRlbXMsIHJlX2Zvcm11bGEgPSBOQSwgbmRyYXdzID0gMjAwKQplcHJlZF9wcmVkcyA8LSBlcHJlZHMgJT4lIGxlZnRfam9pbihwcmVkcykKYnlfZHJhdyA8LSBlcHJlZF9wcmVkcyAlPiUgZ3JvdXBfYnkoLmRyYXcpICU+JSAKICBzdW1tYXJpc2UoLmVwcmVkID0gdmFyKC5lcHJlZCksCiAgICAgICAgICAgIC5wcmVkaWN0aW9uID0gdmFyKC5wcmVkaWN0aW9uKSwKICAgICAgICAgICAgc2lnbWEgPSBzcXJ0KC5wcmVkaWN0aW9uIC0gLmVwcmVkKSwKICAgICAgICAgICAgbGF0ZW50X3IgPSBzcXJ0KC5lcHJlZC8ucHJlZGljdGlvbikpCnJtKGVwcmVkX3ByZWRzKQoKcHRfYWNjdXJhY3lfYmF5ZXNfaXRlbXMgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKGxhdGVudF9yKQoKCm1fc3ludGhfcl9pdGVtcyA8LSBicm0oCiAgYmYoZW1waXJpY2FsX3IgfCBtaShlbXBpcmljYWxfcl9zZSkgfiBzeW50aGV0aWNfciArICgxfG1tKHZhcmlhYmxlXzEsIHZhcmlhYmxlXzIpKSwKICAgICBzaWdtYSB+IHMoc3ludGhldGljX3IpKSwgZGF0YSA9IHJyX3ZhbGlkYXRpb25fbGxtLCAKICBmaWxlID0gImlnbm9yZS9tX3N5bnRoX3JyX3JfaXRlbXNfbG0iKQoKc2Rfc3ludGggPC0gc2QobV9zeW50aF9yX2l0ZW1zJGRhdGEkc3ludGhldGljX3IpCgpuZXdkYXRhIDwtIG1fc3ludGhfcl9pdGVtcyRkYXRhICU+JSBzZWxlY3QoZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcl9zZSkKZXByZWRzIDwtIGVwcmVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBtX3N5bnRoX3JfaXRlbXMsIHJlX2Zvcm11bGEgPSBOQSwgbmRyYXdzID0gMjAwKQpwcmVkcyA8LSBwcmVkaWN0ZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IG1fc3ludGhfcl9pdGVtcywgcmVfZm9ybXVsYSA9IE5BLCBuZHJhd3MgPSAyMDApCmVwcmVkX3ByZWRzIDwtIGVwcmVkcyAlPiUgbGVmdF9qb2luKHByZWRzKQpieV9kcmF3IDwtIGVwcmVkX3ByZWRzICU+JSBncm91cF9ieSguZHJhdykgJT4lIAogIHN1bW1hcmlzZSgKICAgICAgICAgICAgbWFlID0gbWVhbihhYnMoLmVwcmVkIC0gLnByZWRpY3Rpb24pKSwKICAgICAgICAgICAgLmVwcmVkID0gdmFyKC5lcHJlZCksCiAgICAgICAgICAgIC5wcmVkaWN0aW9uID0gdmFyKC5wcmVkaWN0aW9uKSwKICAgICAgICAgICAgc2lnbWEgPSBzcXJ0KC5wcmVkaWN0aW9uIC0gLmVwcmVkKSwKICAgICAgICAgICAgbGF0ZW50X3IgPSBzcXJ0KC5lcHJlZC8ucHJlZGljdGlvbikpCnJtKGVwcmVkX3ByZWRzKQoKYWNjdXJhY3lfYmF5ZXNfaXRlbXMgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKGxhdGVudF9yKQoKCmJpbmRfcm93cygKICBwdF9yICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIHN0YW5kYXJkaXplZHNvbHV0aW9uKHB0X2ZpdCkgJT4lIAogICAgZmlsdGVyKGxocyA9PSAiUGVhcnNvbkxhdGVudCIsIHJocyA9PSAgInN5bnRoZXRpY19yIikgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gInByZS10cmFpbmVkIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoU0VNKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3Quc3RkLCAKICAgICAgICAgICBjb25mLmxvdyA9IGNpLmxvd2VyLCBjb25mLmhpZ2ggPSBjaS51cHBlciksCiAgcHRfYWNjdXJhY3lfYmF5ZXNfaXRlbXMgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gInByZS10cmFpbmVkIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoQmF5ZXNpYW4gRUlWKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBsYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlciksCiAgciAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdCkgJT4lIAogICAgZmlsdGVyKGxocyA9PSAiUGVhcnNvbkxhdGVudCIsIHJocyA9PSAgInN5bnRoZXRpY19yIikgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gImxhdGVudCBvdXRjb21lIChTRU0pIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdC5zdGQsIAogICAgICAgICAgIGNvbmYubG93ID0gY2kubG93ZXIsIGNvbmYuaGlnaCA9IGNpLnVwcGVyKSwKICBhY2N1cmFjeV9iYXllc19pdGVtcyAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibGF0ZW50IG91dGNvbWUgKEJheWVzaWFuIEVJVikiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gbGF0ZW50X3IsIGNvbmYubG93ID0gLmxvd2VyLCBjb25mLmhpZ2ggPSAudXBwZXIpCiAgKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9IHN0cl9jKCJBY2N1cmFjeSBmb3Igaz0iLG5yb3cocnJfdmFsaWRhdGlvbl9sbG0pLCIgaXRlbSBwYWlycyAoIixuX2Rpc3RpbmN0KGMocnJfdmFsaWRhdGlvbl9sbG0kdmFyaWFibGVfMSwgcnJfdmFsaWRhdGlvbl9sbG0kdmFyaWFibGVfMSkpLCIgaXRlbXMpIGFjcm9zcyBsYW5ndWFnZSBtb2RlbHMgYW5kIG1ldGhvZHMiKSkKYGBgCgoKPGRldGFpbHM+CjxzdW1tYXJ5Pgo8aDQ+UHJlZGljdGlvbiBlcnJvciBwbG90IGFjY29yZGluZyB0byBzeW50aGV0aWMgZXN0aW1hdGU8L2g0Pgo8L3N1bW1hcnk+CgpgYGB7cn0KbV9zeW50aF9yX2l0ZW1zCgpwcmVkIDwtIGNvbmRpdGlvbmFsX2VmZmVjdHMobV9zeW50aF9yX2l0ZW1zLCBtZXRob2QgPSAicHJlZGljdCIpCgprYWJsZShybXNlX2l0ZW1zIDwtIGJ5X2RyYXcgJT4lIG1lYW5faGRjaShzaWdtYSksIGNhcHRpb24gPSAiQXZlcmFnZSBwcmVkaWN0aW9uIGVycm9yIChSTVNFKSIsIGRpZ2l0cyA9IDIpCmthYmxlKG1hZV9pdGVtcyA8LSBieV9kcmF3ICU+JSBtZWFuX2hkY2kobWFlKSwgY2FwdGlvbiA9ICJBdmVyYWdlIHByZWRpY3Rpb24gZXJyb3IgKE1BRSkiLCBkaWdpdHMgPSAyKQoKcGxvdF9wcmVkaWN0aW9uX2Vycm9yX2l0ZW1zIDwtIHBsb3QoY29uZGl0aW9uYWxfZWZmZWN0cyhtX3N5bnRoX3JfaXRlbXMsIGRwYXIgPSAic2lnbWEiKSwgcGxvdCA9IEYpW1sxXV0gKyAKICB0aGVtZV9idygpICsgCiAgeGxhYigiU3ludGhldGljIGludGVyLWl0ZW0gY29ycmVsYXRpb24iKSArIAogIHlsYWIoIlByZWRpY3Rpb24gZXJyb3IgKHNpZ21hKSIpICsKICBnZW9tX3Ntb290aChzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiI2E0ODUwMCIsIGZpbGwgPSAiI0VEQzk1MSIpCgpwbG90X3ByZWRpY3Rpb25fZXJyb3JfaXRlbXMKYGBgCgo8L2RldGFpbHM+CgoKCiMjIyBTY2F0dGVyIHBsb3QKYGBge3J9CmdncGxvdChycl92YWxpZGF0aW9uX2xsbSwgYWVzKHN5bnRoZXRpY19yLCBlbXBpcmljYWxfciwgCiAgICAgICAgICAgICAgeW1pbiA9IGVtcGlyaWNhbF9yIC0gZW1waXJpY2FsX3Jfc2UsCiAgICAgICAgICAgICAgeW1heCA9IGVtcGlyaWNhbF9yICsgZW1waXJpY2FsX3Jfc2UpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuMDMsIHNpemUgPSAxKSArCiAgZ2VvbV9zbW9vdGgoYWVzKAogICAgeCA9IHN5bnRoZXRpY19yLAogICAgeSA9IGVzdGltYXRlX18sCiAgICB5bWluID0gbG93ZXJfXywKICAgIHltYXggPSB1cHBlcl9fLAogICksIHN0YXQgPSAiaWRlbnRpdHkiLCAKICBjb2xvciA9ICIjYTQ4NTAwIiwKICBmaWxsID0gIiNFREM5NTEiLAogIGRhdGEgPSBhcy5kYXRhLmZyYW1lKHByZWQkc3ludGhldGljX3IpKSArCiAgeGxhYigiU3ludGhldGljIGludGVyLWl0ZW0gY29ycmVsYXRpb24iKSArIAogIHlsYWIoIkVtcGlyaWNhbCBpbnRlci1pdGVtIGNvcnJlbGF0aW9uIikgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xLDEpLCB5bGltID0gYygtMSwxKSkgLT4gcGxvdF9pdGVtcwpwbG90X2l0ZW1zCmBgYAoKIyMjIEludGVyYWN0aXZlIHBsb3QKVGhpcyBwbG90IHNob3dzIG9ubHkgMjAwMCByYW5kb21seSBzZWxlY3RlZCBpdGVtIHBhaXJzIHRvIGNvbnNlcnZlIG1lbW9yeS4gQSBbZnVsbCBpbnRlcmFjdGl2ZSBwbG90XSgyX2ludGVyYWN0aXZlX2l0ZW1fcGxvdF9yci5odG1sKSBleGlzdHMsIGJ1dCBtYXkgcmVhY3Qgc2xvd2x5LgoKYGBge3J9Cml0ZW1fcGFpcl90YWJsZSA8LSBycl92YWxpZGF0aW9uX2xsbSAlPiUgCiAgIGxlZnRfam9pbihycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzEgPSB2YXJpYWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbV90ZXh0XzEgPSBpdGVtX3RleHQpKSAlPiUgCiAgIGxlZnRfam9pbihycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzIgPSB2YXJpYWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbV90ZXh0XzIgPSBpdGVtX3RleHQpKQoKIyBpdGVtX3BhaXJfdGFibGUgJT4lIGZpbHRlcihzdHJfbGVuZ3RoKGl0ZW1fdGV4dF8xKSA8IDMwLCBzdHJfbGVuZ3RoKGl0ZW1fdGV4dF8yKSA8IDMwKSAlPiUgCiMgICBsZWZ0X2pvaW4ocHRfcnJfdmFsaWRhdGlvbl9sbG0gJT4lIHJlbmFtZShzeW50aGV0aWNfcl9wdCA9IHN5bnRoZXRpY19yKSkgJT4lIAojICAgc2VsZWN0KGl0ZW1fdGV4dF8xLCBpdGVtX3RleHRfMiwgZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yLCBzeW50aGV0aWNfcl9wdCkgJT4lIFZpZXcoKQpyaW86OmV4cG9ydChpdGVtX3BhaXJfdGFibGUsICJpZ25vcmUvaXRlbV9wYWlyX3RhYmxlX3JyX3Vucm91bmRlZC54bHN4IikKcmlvOjpleHBvcnQoaXRlbV9wYWlyX3RhYmxlLCAiaWdub3JlL2l0ZW1fcGFpcl90YWJsZV9yci5mZWF0aGVyIikKCihpdGVtX3BhaXJfdGFibGUgJT4lIAogIG11dGF0ZShzeW50aGV0aWNfciA9IHJvdW5kKHN5bnRoZXRpY19yLCAyKSwKICAgICAgICAgZW1waXJpY2FsX3IgPSByb3VuZChlbXBpcmljYWxfciwgMiksCiAgICAgICAgIGl0ZW1zID0gc3RyX3JlcGxhY2VfYWxsKHN0cl9jKGl0ZW1fdGV4dF8xLCAiXG4iLCBpdGVtX3RleHRfMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXysiLCAiICIpKSAlPiUgCiAgICBzYW1wbGVfbigyMDAwKSAlPiUKZ2dwbG90KC4sIGFlcyhzeW50aGV0aWNfciwgZW1waXJpY2FsX3IsIAogICAgICAgICAgICAgICMgeW1pbiA9IGVtcGlyaWNhbF9yIC0gZW1waXJpY2FsX3Jfc2UsIAogICAgICAgICAgICAgICMgeW1heCA9IGVtcGlyaWNhbF9yICsgZW1waXJpY2FsX3Jfc2UsIAogICAgICAgICAgICAgIGxhYmVsID0gaXRlbXMpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuMywgc2l6ZSA9IDEpICsKICB4bGFiKCJTeW50aGV0aWMgaW50ZXItaXRlbSBjb3JyZWxhdGlvbiIpICsgCiAgeWxhYigiRW1waXJpY2FsIGludGVyLWl0ZW0gY29ycmVsYXRpb24iKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoLTEsMSksIHlsaW0gPSBjKC0xLDEpKSkgJT4lIAogIGdncGxvdGx5KCkKCml0ZW1fcGFpcl90YWJsZV9udW1lcmljIDwtIGl0ZW1fcGFpcl90YWJsZQoKaXRlbV9wYWlyX3RhYmxlIDwtIGl0ZW1fcGFpcl90YWJsZSAlPiUgCiAgbXV0YXRlKGVtcGlyaWNhbF9yID0gc3ByaW50ZigiJS4yZsKxJS4zZiIsIGVtcGlyaWNhbF9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbXBpcmljYWxfcl9zZSksCiAgICAgICAgICAgc3ludGhldGljX3IgPSBzcHJpbnRmKCIlLjJmIiwgc3ludGhldGljX3IpKSAlPiUgCiAgc2VsZWN0KGl0ZW1fdGV4dF8xLCBpdGVtX3RleHRfMiwgZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yKQpyaW86OmV4cG9ydChpdGVtX3BhaXJfdGFibGUsICJpdGVtX3BhaXJfdGFibGVfcnIueGxzeCIpCmBgYAoKPGRldGFpbHM+CjxzdW1tYXJ5Pgo8aDM+Um9idXN0bmVzcyBjaGVja3M8L2gzPgo8L3N1bW1hcnk+CgoKIyMjIyBDb21wYXJpbmcgc3BsaW5lIGFuZCBwb2x5bm9taWFsIG1vZGVscyBmb3IgaGV0ZXJvc2NlZGFzdGljaXR5CmBgYHtyfQojIEZvciBpdGVtIGNvcnJlbGF0aW9ucwptX3N5bnRoX3JfaXRlbXNfcG9seSA8LSBicm0oCiAgYmYoZW1waXJpY2FsX3IgfCBtaShlbXBpcmljYWxfcl9zZSkgfiBzeW50aGV0aWNfciArICgxfG1tKHZhcmlhYmxlXzEsIHZhcmlhYmxlXzIpKSwKICAgICBzaWdtYSB+IHBvbHkoc3ludGhldGljX3IsIGRlZ3JlZSA9IDMpKSwgZGF0YSA9IHJyX3ZhbGlkYXRpb25fbGxtLCAKICBmaWxlID0gImlnbm9yZS9tX3N5bnRoX3JyX3JfaXRlbXNfbG1fcG9seSIpCgpuZXdkYXRhIDwtIG1fc3ludGhfcl9pdGVtc19wb2x5JGRhdGEgJT4lIHNlbGVjdChlbXBpcmljYWxfciwgc3ludGhldGljX3IsIGVtcGlyaWNhbF9yX3NlKQplcHJlZHMgPC0gZXByZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IG1fc3ludGhfcl9pdGVtc19wb2x5LCByZV9mb3JtdWxhID0gTkEsIG5kcmF3cyA9IDIwMCkKcHJlZHMgPC0gcHJlZGljdGVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBtX3N5bnRoX3JfaXRlbXNfcG9seSwgcmVfZm9ybXVsYSA9IE5BLCBuZHJhd3MgPSAyMDApCmVwcmVkX3ByZWRzIDwtIGVwcmVkcyAlPiUgbGVmdF9qb2luKHByZWRzKQpieV9kcmF3IDwtIGVwcmVkX3ByZWRzICU+JSBncm91cF9ieSguZHJhdykgJT4lIAogIHN1bW1hcmlzZSguZXByZWQgPSB2YXIoLmVwcmVkKSwKICAgICAgICAgICAgLnByZWRpY3Rpb24gPSB2YXIoLnByZWRpY3Rpb24pLAogICAgICAgICAgICBzaWdtYSA9IHNxcnQoLnByZWRpY3Rpb24gLSAuZXByZWQpLAogICAgICAgICAgICBsYXRlbnRfciA9IHNxcnQoLmVwcmVkLy5wcmVkaWN0aW9uKSkKCmFjY3VyYWN5X2JheWVzX2l0ZW1zX3BvbHkgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKGxhdGVudF9yKQoKYmluZF9yb3dzKAogIGFjY3VyYWN5X2JheWVzX2l0ZW1zICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJzcGxpbmUiLCBraW5kID0gImxhdGVudCBvdXRjb21lIChCYXllc2lhbiBFSVYpIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGxhdGVudF9yLCBjb25mLmxvdyA9IC5sb3dlciwgY29uZi5oaWdoID0gLnVwcGVyKSwKICBhY2N1cmFjeV9iYXllc19pdGVtc19wb2x5ICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwb2x5bm9taWFsIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoQmF5ZXNpYW4gRUlWKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBsYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlcikKKSAlPiUgCiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQ29tcGFyaW5nIHNwbGluZSBhbmQgcG9seW5vbWlhbCBtb2RlbHMgZm9yIGl0ZW0gY29ycmVsYXRpb25zIikKYGBgCgpgYGB7cn0KcGxvdF9wcmVkaWN0aW9uX2Vycm9yX2l0ZW1zX3BvbHkgPC0gcGxvdChjb25kaXRpb25hbF9lZmZlY3RzKG1fc3ludGhfcl9pdGVtc19wb2x5LCBkcGFyID0gInNpZ21hIiksIHBsb3QgPSBGKVtbMV1dICsgCiAgdGhlbWVfYncoKSArIAogIHhsYWIoIlN5bnRoZXRpYyBpbnRlci1pdGVtIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJQcmVkaWN0aW9uIGVycm9yIChzaWdtYSkiKSArCiAgZ2VvbV9zbW9vdGgoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gIiNhNDg1MDAiLCBmaWxsID0gIiNFREM5NTEiKQoKcGxvdF9wcmVkaWN0aW9uX2Vycm9yX2l0ZW1zX3BvbHkKYGBgCgoKIyMjIyBBY2N1cmFjeSBieSBzdWJqZWN0IG1hdHRlcgojIyMjIyBCb3RoIGl0ZW1zIGZyb20gc2FtZSBzdWJqZWN0IG1hdHRlci9kb21haW4KYGBge3J9Cmluc3RydW1lbnRzIDwtIHJpbzo6aW1wb3J0KCJycl91c2VkX21lYXN1cmVzLnhsc3giKSAlPiUgYXNfdGliYmxlKCkKCnJyX3ZhbGlkYXRpb25fbGxtX2RvbWFpbiA8LSBycl92YWxpZGF0aW9uX2xsbSAlPiUgCiAgbGVmdF9qb2luKGluc3RydW1lbnRzICU+JSBzZWxlY3QoSW5zdHJ1bWVudEEgPSBNZWFzdXJlLCBEb21haW5BID0gRG9tYWluKSwgYnkgPSAiSW5zdHJ1bWVudEEiKSAlPiUgCiAgbGVmdF9qb2luKGluc3RydW1lbnRzICU+JSBzZWxlY3QoSW5zdHJ1bWVudEIgPSBNZWFzdXJlLCBEb21haW5CID0gRG9tYWluKSwgYnkgPSAiSW5zdHJ1bWVudEIiKSAKCmFjY3VyYWN5X3dpdGhpbl9kb21haW5zIDwtIHJyX3ZhbGlkYXRpb25fbGxtX2RvbWFpbiAlPiUgCiAgZmlsdGVyKERvbWFpbkEgPT0gRG9tYWluQikgJT4lIAogIGdyb3VwX2J5KERvbWFpbkEpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHB0X2NvciA9IGNvcihwdF9zeW50aGV0aWNfciwgZW1waXJpY2FsX3IpLCBybXNlID0gc3FydChtZWFuKChlbXBpcmljYWxfciAtIHN5bnRoZXRpY19yKV4yKSksIHB0X3Jtc2UgPSBzcXJ0KG1lYW4oKGVtcGlyaWNhbF9yIC0gcHRfc3ludGhldGljX3IpXjIpKSwgc2RfZW1wX3IgPSBzZChlbXBpcmljYWxfciksIG1lYW5fYWJzX3IgPSBtZWFuKGFicyhlbXBpcmljYWxfcikpLCBtZWFuX3IgPSBtZWFuKGVtcGlyaWNhbF9yKSwgcG9zX3NpZ24gPSBtZWFuKHNpZ24oZW1waXJpY2FsX3IpID4gMCksIG4gPSBuKCkpICU+JSAKICBzZWxlY3QoZG9tYWluID0gRG9tYWluQSwgciA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoLCBwdF9jb3IsIHJtc2UsIHB0X3Jtc2UsIG4sIHNkX2VtcF9yLCBtZWFuX2Fic19yLCBtZWFuX3IsIHBvc19zaWduKSAlPiUgCiAgYXJyYW5nZShyKQoKYWNjdXJhY3lfd2l0aGluX2RvbWFpbnMgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgYnkgZG9tYWluIHdoZW4gYm90aCBpdGVtcyBhcmUgZnJvbSB0aGUgc2FtZSBkb21haW4iKQpgYGAKCiMjIyMjIEl0ZW1zIGZyb20gb25lIGRvbWFpbiBjb3JyZWxhdGVkIHdpdGggaXRlbXMgaW4gb3RoZXIgZG9tYWluCmBgYHtyfQphY2N1cmFjeV9iZXR3ZWVuX2RvbWFpbnMgPC0gYmluZF9yb3dzKHJyX3ZhbGlkYXRpb25fbGxtX2RvbWFpbiAlPiUgCiAgZmlsdGVyKERvbWFpbkEgIT0gRG9tYWluQiksCiAgcnJfdmFsaWRhdGlvbl9sbG1fZG9tYWluICU+JSAKICBmaWx0ZXIoRG9tYWluQSAhPSBEb21haW5CKSAlPiUgCiAgcmVuYW1lKERvbWFpbkEgPSBEb21haW5CLCBEb21haW5CID0gRG9tYWluQSkpICU+JSAKICBncm91cF9ieShEb21haW5BKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcikpLCBwdF9jb3IgPSBjb3IocHRfc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSwgcm1zZSA9IHNxcnQobWVhbigoZW1waXJpY2FsX3IgLSBzeW50aGV0aWNfcileMikpLCBwdF9ybXNlID0gc3FydChtZWFuKChlbXBpcmljYWxfciAtIHB0X3N5bnRoZXRpY19yKV4yKSksIHNkX2VtcF9yID0gc2QoZW1waXJpY2FsX3IpLCBtZWFuX2Fic19yID0gbWVhbihhYnMoZW1waXJpY2FsX3IpKSwgbWVhbl9yID0gbWVhbihlbXBpcmljYWxfciksIHBvc19zaWduID0gbWVhbihzaWduKGVtcGlyaWNhbF9yKSA+IDApLCBuID0gbigpKSAlPiUgCiAgc2VsZWN0KGRvbWFpbiA9IERvbWFpbkEsIHIgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCwgcHRfY29yLCBybXNlLCBwdF9ybXNlLCBuLCBzZF9lbXBfciwgbWVhbl9hYnNfciwgbWVhbl9yLCBwb3Nfc2lnbikgJT4lIAogIGFycmFuZ2UocikKYWNjdXJhY3lfYmV0d2Vlbl9kb21haW5zICU+JSAKICBrYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkFjY3VyYWN5IGJ5IGRvbWFpbiB3aGVuIGl0ZW1zIGFyZSBmcm9tIGRpZmZlcmVudCBkb21haW5zIikKYGBgCgpgYGB7cn0KbGlicmFyeShnZ3JlcGVsKQpkb2RnZSA8LSAwLjYKYmluZF9yb3dzKAp3aXRoaW4gPSBhY2N1cmFjeV93aXRoaW5fZG9tYWlucywKYWNyb3NzID0gYWNjdXJhY3lfYmV0d2Vlbl9kb21haW5zLCAuaWQgPSAia2luZCIpICU+JSAKICBtdXRhdGUoa2luZCA9IGZjdF9pbm9yZGVyKGtpbmQpKSAlPiUgCmdncGxvdChhZXMoeCA9IGRvbWFpbiwgciwgeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoLCBzaGFwZSA9IGtpbmQsIGZpbGwgPSBraW5kKSkgKwogIGdlb21fY29sKGFlcyggZ3JvdXAgPSBraW5kKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlKSwgd2lkdGggPSAwLjQpICsKICBnZW9tX2NvbChhZXMoeSA9IHB0X2NvciwgZ3JvdXAgPSBraW5kKSwgZmlsbCA9ICJncmF5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlKSwgLCB3aWR0aCA9IDAuNCkgKwogICMgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBwdF9jb3IsIHltYXggPSByLCBncm91cCA9IGtpbmQpLCBjb2xvciA9ICJncmF5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArCiAgIyBnZW9tX3BvaW50KGFlcyh5ID0gcHRfY29yLCBncm91cCA9IGtpbmQpLCBjb2xvciA9ICJibGFjayIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgc2l6ZSA9IDIuNSkgKwogIGdlb21fcG9pbnRyYW5nZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2UpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNhNDg1MDAiLCAiI2E0ODUwMCIpLCBndWlkZSA9ICJub25lIikgKyAKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygid2l0aGluIiA9IDE5LCAiYWNyb3NzIiA9IDQpLCBndWlkZSA9ICJub25lIikgKwogICMgc2NhbGVfY29sb3JfdmlyaWRpc19kKGVuZCA9IDAuNywgb3B0aW9uID0gIkEiLCBndWlkZSA9ICJub25lIikgKwogIHNjYWxlX3lfY29udGludW91cygiTWFuaWZlc3QgYWNjdXJhY3kgb2Ygc3ludGhldGljIGl0ZW0gcGFpciBjb3JyZWxhdGlvbnMiLCBsaW1pdHMgPSBjKDAsIDEpLCBleHBhbmQgPSBjKDAsIDApKSArCiAgeGxhYigiSXRlbSBkb21haW4iKSArCiAgYW5ub3RhdGUoInRleHQiLCBsYWJlbCA9ICJTQkVSVCIsIHggPSAyLjg1LCB5ID0gMC4yNCwgIGFuZ2xlID0gOTApICsKICBhbm5vdGF0ZSgidGV4dCIsIGxhYmVsID0gIlN1cnZleUJvdDMwMDAiLCB4ID0gMy4xNSwgeSA9IDAuNDMsICBhbmdsZSA9IDkwKSArCiAgYW5ub3RhdGUoInRleHRfcmVwZWwiLCBsYWJlbCA9ICJ3aXRoaW4gZG9tYWluIiwgeCA9IDIuODUsIHkgPSAuNzQ1LCBmb3JjZSA9IDIsIGhqdXN0ID0gMS4xNSwgdmp1c3QgPSAtMikgKwogIGFubm90YXRlKCJ0ZXh0X3JlcGVsIiwgbGFiZWwgPSAiYWNyb3NzIGRvbWFpbnMiLCB4ID0gMy4xNSwgeSA9IC42NSwgZm9yY2UgPSAyLCBoanVzdCA9IC0uMTUsIHZqdXN0ID0gLTIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIHIpLCBoanVzdCA9IGlmX2Vsc2Uoa2luZCA9PSAid2l0aGluIiwgMS4zLCAtMC4zKSksIHZqdXN0ID0gLTAuNCwgc2l6ZSA9IDMsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZSkpCmdnc2F2ZSgiRmlndXJlX3JyX2RvbWFpbi5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpCmBgYAoKCgojIyMjIEFjY3VyYWN5IGJ5IGluc3RydW1lbnQKCmBgYHtyfQphY2N1cmFjeV9iZXR3ZWVuX2luc3RydW1lbnRzIDwtIGJpbmRfcm93cyhycl92YWxpZGF0aW9uX2xsbV9kb21haW4gJT4lIAogIGZpbHRlcihJbnN0cnVtZW50QSAhPSBJbnN0cnVtZW50QiksCiAgcnJfdmFsaWRhdGlvbl9sbG1fZG9tYWluICU+JSAKICBmaWx0ZXIoSW5zdHJ1bWVudEEgIT0gSW5zdHJ1bWVudEIpICU+JSAKICByZW5hbWUoSW5zdHJ1bWVudEEgPSBJbnN0cnVtZW50QiwgSW5zdHJ1bWVudEIgPSBJbnN0cnVtZW50QSkpICU+JSAKICBncm91cF9ieShJbnN0cnVtZW50QSkgJT4lIAogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChzeW50aGV0aWNfciwgZW1waXJpY2FsX3IpKSwgcHRfY29yID0gY29yKHB0X3N5bnRoZXRpY19yLCBlbXBpcmljYWxfciksIHNkX2VtcF9yID0gc2QoZW1waXJpY2FsX3IpLCBuID0gbigpKSAlPiUgCiAgc2VsZWN0KGluc3RydW1lbnQgPSBJbnN0cnVtZW50QSwgciA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoLCBwdF9jb3IsIG4sIHNkX2VtcF9yKSAlPiUgCiAgYXJyYW5nZShyKSAlPiUgCiAgbXV0YXRlKGluc3RydW1lbnQgPSBmY3RfaW5vcmRlcihpbnN0cnVtZW50KSkKCmFjY3VyYWN5X2JldHdlZW5faW5zdHJ1bWVudHMgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgYnkgaW5zdHJ1bWVudCAoZm9yIGl0ZW1zIGJlbG9uZ2luZyB0byBvdGhlciBpbnN0cnVtZW50cykiKQoKYWNjdXJhY3lfd2l0aGluX2luc3RydW1lbnRzIDwtIHJyX3ZhbGlkYXRpb25fbGxtICU+JSAKICBmaWx0ZXIoSW5zdHJ1bWVudEEgPT0gSW5zdHJ1bWVudEIpICU+JSAKICBsZWZ0X2pvaW4oaXRlbXNfYnlfc2NhbGUgJT4lIHNlbGVjdCh2YXJpYWJsZV8xID0gdmFyaWFibGUsIGtleWVkID0ga2V5ZWQpICU+JSBkaXN0aW5jdCgpKSAlPiUgCiAgZ3JvdXBfYnkoSW5zdHJ1bWVudEEpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHB0X2NvciA9IGNvcihwdF9zeW50aGV0aWNfciwgZW1waXJpY2FsX3IpLCBzZF9lbXBfciA9IHNkKGVtcGlyaWNhbF9yKSwgbiA9IG4oKSwgcmV2ZXJzZV9pdGVtX3BlcmNlbnRhZ2UgPSBzdW0oa2V5ZWQgPT0gLTEsIG5hLnJtID0gVFJVRSkvbigpKSAlPiUgCiAgc2VsZWN0KGluc3RydW1lbnQgPSBJbnN0cnVtZW50QSwgciA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoLCBwdF9jb3IsIG4sIHNkX2VtcF9yLCByZXZlcnNlX2l0ZW1fcGVyY2VudGFnZSkgJT4lIAogIGFycmFuZ2UocikgJT4lIAogIG11dGF0ZShpbnN0cnVtZW50ID0gZmFjdG9yKGluc3RydW1lbnQsIGxldmVscyA9IGxldmVscyhhY2N1cmFjeV9iZXR3ZWVuX2luc3RydW1lbnRzJGluc3RydW1lbnQpKSkKICAKYWNjdXJhY3lfd2l0aGluX2luc3RydW1lbnRzICU+JSAKICBtdXRhdGUoYWNjdXJhY3kgPSBzcHJpbnRmKCIlLjJmIFslLjJmOyUuMmZdIiwgciwgY29uZi5sb3csIGNvbmYuaGlnaCkpICU+JSAKICBzZWxlY3QoLWMociwgY29uZi5sb3csIGNvbmYuaGlnaCkpICU+JSAKICByZWxvY2F0ZShhY2N1cmFjeSwgLmJlZm9yZSA9IHB0X2NvcikgJT4lCiAgcmVuYW1lKHB0X2FjY3VyYWN5ID0gcHRfY29yKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJBY2N1cmFjeSBieSBpbnN0cnVtZW50ICh3aXRoaW4gaXRlbXMgYmVsb25naW5nIHRvIHRoZSBzYW1lIGluc3RydW1lbnQpIikKCmJpbmRfcm93cygKd2l0aGluID0gYWNjdXJhY3lfd2l0aGluX2luc3RydW1lbnRzLAphY3Jvc3MgPSBhY2N1cmFjeV9iZXR3ZWVuX2luc3RydW1lbnRzLCAuaWQgPSAia2luZCIpICU+JSAKZ2dwbG90KGFlcyh4ID0gaW5zdHJ1bWVudCwgciwgeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoLCBzaGFwZSA9IGtpbmQpKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IHB0X2NvciwgZ3JvdXAgPSBraW5kKSwgY29sb3IgPSAiZ3JheSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjMpKSArCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBwdF9jb3IsIHltYXggPSByLCBncm91cCA9IGtpbmQpLCBjb2xvciA9ICJncmF5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsKICBnZW9tX3BvaW50cmFuZ2UocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsgCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIndpdGhpbiIgPSAxOSwgImFjcm9zcyIgPSA0KSwgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoZW5kID0gMC43LCBvcHRpb24gPSAiQSIsIGd1aWRlID0gRikgKwogIHNjYWxlX3lfY29udGludW91cygiTWFuaWZlc3QgYWNjdXJhY3kiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMmYiLCByKSksIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjMpKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjIyBBY2N1cmFjeSBieSBpdGVtIHByb3BlcnRpZXMKYGBge3J9CnJfYnlfaXRlbSA8LSBycl92YWxpZGF0aW9uX2xsbSAlPiUgCiAgIyBmaWx0ZXIoSW5zdHJ1bWVudEEgPT0gSW5zdHJ1bWVudEIsIFN1YnNjYWxlQSA9PSBTdWJzY2FsZUIsIFNjYWxlQSA9PSBTY2FsZUIpICU+JSAKICBsZWZ0X2pvaW4oaXRlbXNfYnlfc2NhbGUgJT4lIHNlbGVjdCh2YXJpYWJsZV8xID0gdmFyaWFibGUsIGtleWVkID0ga2V5ZWQsIGl0ZW1fdGV4dCkgJT4lIGRpc3RpbmN0KCkpICU+JSAKICBncm91cF9ieSh2YXJpYWJsZV8xKSAlPiUgCiAgZmlsdGVyKG4oKSA+IDMpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHB0X2NvciA9IGNvcihwdF9zeW50aGV0aWNfciwgZW1waXJpY2FsX3IpLCBzZF9lbXBfciA9IHNkKGVtcGlyaWNhbF9yKSwgbiA9IG4oKSwgcmV2ZXJzZV9pdGVtX3BlcmNlbnRhZ2UgPSBzdW0oa2V5ZWQgPT0gLTEpL24oKSwgaXRlbV90ZXh0X2xlbmd0aCA9IGZpcnN0KHN0cl9sZW5ndGgoaXRlbV90ZXh0KSkpICU+JSAKICBzZWxlY3QociA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoLCBwdF9jb3IsIG4sIHNkX2VtcF9yLCByZXZlcnNlX2l0ZW1fcGVyY2VudGFnZSwgaXRlbV90ZXh0X2xlbmd0aCkgJT4lIAogIGFycmFuZ2UocikKCnJfYnlfaXRlbSAlPiUgZ2dwbG90KGFlcyhpdGVtX3RleHRfbGVuZ3RoLCByLCBjb2xvciA9IGZhY3RvcihyZXZlcnNlX2l0ZW1fcGVyY2VudGFnZSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgicmV2ZXJzZWQiLCBlbmQgPSAwLjgpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgeWxhYigiQWNjdXJhY3kgKHIpIikKYGBgCgoKIyMjIyMgRG9lcyB0aGUgaXRlbSBjb250YWluIGEgZmlyc3QgcGVyc29uIHNpbmd1bGFyIHByb25vdW4KYGBge3J9Cml0ZW1fcGFpcl90YWJsZV9udW1lcmljIDwtIGl0ZW1fcGFpcl90YWJsZV9udW1lcmljICU+JSAKICBtdXRhdGUocHJvbm91bl8xID0gc3RyX2RldGVjdChpdGVtX3RleHRfMSwgIlxcYihJfG1lfG15fG1pbmV8bXlzZWxmfE1lfE15fE1pbmV8TXlzZWxmKVxcYiIpLAogICAgICAgICBwcm9ub3VuXzIgPSBzdHJfZGV0ZWN0KGl0ZW1fdGV4dF8yLCAiXFxiKEl8bWV8bXl8bWluZXxteXNlbGZ8TWV8TXl8TWluZXxNeXNlbGYpXFxiIikpICU+JSAKICBtdXRhdGUocHJvbm91bnNfaW5faXRlbV9wYWlyID0gY2FzZV93aGVuKAogICAgcHJvbm91bl8xID09IEYgJiBwcm9ub3VuXzIgPT0gRiB+ICJuZWl0aGVyIiwKICAgIHByb25vdW5fMSA9PSBUICYgcHJvbm91bl8yID09IFQgfiAiYm90aCIsCiAgICBUUlVFIH4gIm9uZSIKICApKSAlPiUgCiAgbXV0YXRlKGl0ZW1fdGV4dF9sZW5ndGhfMSA9IHN0cl9sZW5ndGgoaXRlbV90ZXh0XzEpLAogICAgICAgICBpdGVtX3RleHRfbGVuZ3RoXzIgPSBzdHJfbGVuZ3RoKGl0ZW1fdGV4dF8yKSwKICAgICAgICAgaXRlbV90ZXh0X2xlbmd0aCA9IChpdGVtX3RleHRfbGVuZ3RoXzEraXRlbV90ZXh0X2xlbmd0aF8yKS8yKSAlPiUgCiAgbGVmdF9qb2luKGl0ZW1zX2J5X3NjYWxlICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLCBrZXllZF8xID0ga2V5ZWQpICU+JSBkaXN0aW5jdCgpKSAlPiUgCiAgbGVmdF9qb2luKGl0ZW1zX2J5X3NjYWxlICU+JSBzZWxlY3QodmFyaWFibGVfMiA9IHZhcmlhYmxlLCBrZXllZF8yID0ga2V5ZWQpICU+JSBkaXN0aW5jdCgpKSAlPiUgCiAgbXV0YXRlKHJldmVyc2VkX2l0ZW1zID0gY2FzZV93aGVuKAogICAga2V5ZWRfMSA9PSAxICYga2V5ZWRfMiA9PSAxIH4gIm5laXRoZXIiLAogICAga2V5ZWRfMSA9PSAtMSAmIGtleWVkXzIgPT0gLTEgfiAiYm90aCIsCiAgICBUUlVFIH4gIm9uZSIKICApKQoKCm9wdGlvbnMoc2NpcGVuID0gMTApCnN1bW1hcnkobG0oZW1waXJpY2FsX3IgfiBzeW50aGV0aWNfciAqIChwcm9ub3Vuc19pbl9pdGVtX3BhaXIgKyByZXZlcnNlZF9pdGVtcyArIGl0ZW1fdGV4dF9sZW5ndGgpLCBpdGVtX3BhaXJfdGFibGVfbnVtZXJpYykpCgppdGVtX3BhaXJfdGFibGVfbnVtZXJpYyAlPiUgCiAgZ3JvdXBfYnkocHJvbm91bnNfaW5faXRlbV9wYWlyKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcikpLCBuX3BhaXJzID0gbigpKSAlPiUgCiAgbXV0YXRlKGFjY3VyYWN5ID0gc3ByaW50ZigiJS4yZiBbJS4yZjslLjJmXSIsIGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSkgJT4lIAogIHNlbGVjdChwcm9ub3Vuc19pbl9pdGVtX3BhaXIsIGFjY3VyYWN5LCBuX3BhaXJzKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJBY2N1cmFjeSBmb3IgaXRlbXMgd2l0aCBhbmQgd2l0aG91dCBmaXJzdCBwZXJzb24gc2luZ3VsYXIgcHJvbm91bnMiKQoKCml0ZW1fcGFpcl90YWJsZV9udW1lcmljICU+JSAKICBncm91cF9ieShzaWduKGVtcGlyaWNhbF9yKSwgcHJvbm91bnNfaW5faXRlbV9wYWlyKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcikpLCBuX3BhaXJzID0gbigpLCBzZF9lID0gc2QoZW1waXJpY2FsX3IpKSAlPiUgCiAgbXV0YXRlKGFjY3VyYWN5ID0gc3ByaW50ZigiJS4yZiBbJS4yZjslLjJmXSIsIGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSkgJT4lIAogIHNlbGVjdChwcm9ub3Vuc19pbl9pdGVtX3BhaXIsIGFjY3VyYWN5LCBuX3BhaXJzLCBzZF9lKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJBY2N1cmFjeSBmb3IgaXRlbXMgd2l0aCBhbmQgd2l0aG91dCBmaXJzdCBwZXJzb24gc2luZ3VsYXIgcHJvbm91bnMiKQpgYGAKCiMjIyMjIEFjY3VyYWN5IGJ5IHdoZXRoZXIgaXRlbSBpcyByZXZlcnNlZApSZXZlcnNlIGl0ZW1zIGxvYWQgbmVnYXRpdmVseSBvbiB0aGUgYXNzb2NpYXRlZCBzY2FsZS4KCmBgYHtyfQpycl92YWxpZGF0aW9uX2xsbSAlPiUgCiAgbGVmdF9qb2luKGl0ZW1zX2J5X3NjYWxlICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLCBrZXllZF8xID0ga2V5ZWQpICU+JSBkaXN0aW5jdCgpKSAlPiUgCiAgbGVmdF9qb2luKGl0ZW1zX2J5X3NjYWxlICU+JSBzZWxlY3QodmFyaWFibGVfMiA9IHZhcmlhYmxlLCBrZXllZF8yID0ga2V5ZWQpICU+JSBkaXN0aW5jdCgpKSAlPiUgCiAgbXV0YXRlKHJldmVyc2VkX2l0ZW1zID0gY2FzZV93aGVuKAogICAga2V5ZWRfMSA9PSAxICYga2V5ZWRfMiA9PSAxIH4gIm5laXRoZXIiLAogICAga2V5ZWRfMSA9PSAtMSAmIGtleWVkXzIgPT0gLTEgfiAiYm90aCIsCiAgICBUUlVFIH4gIm9uZSIKICApKSAlPiUgCiAgZ3JvdXBfYnkocmV2ZXJzZWRfaXRlbXMpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3QoZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yKSksIG5fcGFpcnMgPSBuKCkpICU+JSAKICBtdXRhdGUoYWNjdXJhY3kgPSBzcHJpbnRmKCIlLjJmIFslLjJmOyUuMmZdIiwgZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpKSAlPiUgCiAgc2VsZWN0KHJldmVyc2VkX2l0ZW1zLCBhY2N1cmFjeSwgbl9wYWlycykgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgZm9yIHJldmVyc2VkIGFuZCBub24tcmV2ZXJzZWQgaXRlbXMiKQpgYGAKCiMjIyMjIFRvcC9ib3R0b20gMjAgaXRlbXMKYGBge3J9CmJ5X2l0ZW0gPC0gYmluZF9yb3dzKGl0ZW1fcGFpcl90YWJsZV9udW1lcmljLAogIGl0ZW1fcGFpcl90YWJsZV9udW1lcmljICU+JSAKICBzZWxlY3QoLXZhcmlhYmxlXzEsIC1pdGVtX3RleHRfMSkgJT4lIAogIHJlbmFtZSh2YXJpYWJsZV8xID0gdmFyaWFibGVfMiwgaXRlbV90ZXh0XzEgPSBpdGVtX3RleHRfMikpICU+JSAKICBncm91cF9ieSh2YXJpYWJsZV8xLCBpdGVtX3RleHRfMSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX3Jtc2UgPSBzcXJ0KG1lYW4oKGVtcGlyaWNhbF9yIC0gc3ludGhldGljX3IpXjIpKSkgJT4lIAogIGFycmFuZ2UobWVhbl9ybXNlKQoKYmluZF9yb3dzKGhlYWQoYnlfaXRlbSwgMjApLAp0YWlsKGJ5X2l0ZW0sIDIwKSkgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiVG9wIGFuZCBib3R0b20gMjAgaXRlbXMgYnkgUk1TRSIpCmBgYAoKIyMjIyBJcyB0aGUgYWNjdXJhY3kgbG93ZXIgd2l0aGluL2Fjcm9zcyBzY2FsZXMgYW5kIGluc3RydW1lbnRzPwoKYGBge3J9CnJyX3ZhbGlkYXRpb25fbGxtICU+JSAKICBtdXRhdGUoc2FtZV9pbnN0cnVtZW50ID0gaWZfZWxzZShJbnN0cnVtZW50QSA9PSBJbnN0cnVtZW50QiwgMSwgMCwwKSwKICAgICAgICAgc2FtZV9zY2FsZSA9IGlmX2Vsc2UoU2NhbGVBID09IFNjYWxlQiwgMSwwLDApLAogICAgICAgICBzYW1lX3N1YnNjYWxlID0gaWZfZWxzZShzYW1lX3NjYWxlICYgU3Vic2NhbGVBID09IFN1YnNjYWxlQiwgMSwwLDApKSAlPiUgCiAgZ3JvdXBfYnkoc2FtZV9zY2FsZSwgc2FtZV9pbnN0cnVtZW50LCBzYW1lX3N1YnNjYWxlKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcikpLCBzZF9lbXBfciA9IHNkKGVtcGlyaWNhbF9yKSwgbiA9IG4oKSkgJT4lIAogIG11dGF0ZShhY2N1cmFjeSA9IHNwcmludGYoIiUuMmYgWyUuMmY7JS4yZl0iLCBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCkpICU+JSAKICBzZWxlY3Qoc2FtZV9pbnN0cnVtZW50LCBzYW1lX3NjYWxlLCBzYW1lX3N1YnNjYWxlLCBhY2N1cmFjeSwgbiwgc2RfZW1wX3IpICU+JSAKICBhcnJhbmdlKHNhbWVfaW5zdHJ1bWVudCwgc2FtZV9zY2FsZSwgc2FtZV9zdWJzY2FsZSkgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgd2l0aGluIGFuZCBhY3Jvc3Mgc2NhbGVzIikKYGBgCgojIyMjIElzIHRoZSBhY2N1cmFjeSBsb3dlciBmb3IgaXRlbXMgdGhhdCBoYXZlIGxvdyB2YXJpYW5jZT8KCmBgYHtyfQppdGVtX3ZhcmlhbmNlcyA8LSBycl92YWxpZGF0aW9uX2h1bWFuX2RhdGEgJT4lCiAgaGF2ZW46OnphcF9sYWJlbHMoKSAlPiUgCiAgc3VtbWFyaXNlX2FsbCh+IHNkKC4sIG5hLnJtID0gVCkpICU+JSAKICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJpdGVtX3NkIikKCmJ5X21heF9jb3YgPC0gcnJfdmFsaWRhdGlvbl9sbG0gJT4lIAogIGxlZnRfam9pbihpdGVtX3ZhcmlhbmNlcywgYnkgPSBjKCJ2YXJpYWJsZV8xIiA9ICJ2YXJpYWJsZSIpKSAlPiUgCiAgbGVmdF9qb2luKGl0ZW1fdmFyaWFuY2VzLCBieSA9IGMoInZhcmlhYmxlXzIiID0gInZhcmlhYmxlIiksIHN1ZmZpeCA9IGMoIl8xIiwgIl8yIikpICU+JSAKICBtdXRhdGUobWF4X2NvdmFyaWFuY2UgPSBjZWlsaW5nKChpdGVtX3NkXzEgKiBpdGVtX3NkXzIpKjEwKS8xMCkKCnJzX2J5X21heF9jb3YgPC0gYnlfbWF4X2NvdiAlPiUgCiAgZ3JvdXBfYnkobWF4X2NvdmFyaWFuY2UpICU+JSAKICBmaWx0ZXIobigpID4gMykgJT4lIAogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChzeW50aGV0aWNfciwgZW1waXJpY2FsX3IpKSwgc2RfZW1wX3IgPSBzZChlbXBpcmljYWxfciksIG4gPSBuKCkpICU+JSAKICBzZWxlY3QobWF4X2NvdmFyaWFuY2UsIHIgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCwgbiwgc2RfZW1wX3IpICU+JSAKICBhcnJhbmdlKG1heF9jb3ZhcmlhbmNlKQoKcnNfYnlfbWF4X2NvdiAlPiUgZ2dwbG90KGFlcyhtYXhfY292YXJpYW5jZSwgciwgeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoKSkgKwogIGdlb21fcG9pbnRyYW5nZSgpCgpieV9tYXhfY292JT4lIAogIGZpbHRlcihtYXhfY292YXJpYW5jZSA+PSAyKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcikpLCBzZF9lbXBfciA9IHNkKGVtcGlyaWNhbF9yKSwgbiA9IG4oKSkgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgZm9yIGl0ZW1zIHdpdGggYSBtYXhpbWFsIHBvdGVudGlhbCBjb3ZhcmlhbmNlIChwcm9kdWN0IG9mIFNEcykgb2YgYXQgbGVhc3QgMiIpCmBgYAoKCgoKIyMjIyBJcyB0aGUgYWNjdXJhY3kgbG93ZXIgZm9yIHRoZSBwcmUtdHJhaW5lZCBtb2RlbD8KCmBgYHtyfQpnZ3Bsb3QocHRfcnJfdmFsaWRhdGlvbl9sbG0sIGFlcyhzeW50aGV0aWNfciwgZW1waXJpY2FsX3IsIAogICAgICAgICAgICAgIHltaW4gPSBlbXBpcmljYWxfciAtIGVtcGlyaWNhbF9yX3NlLAogICAgICAgICAgICAgIHltYXggPSBlbXBpcmljYWxfciArIGVtcGlyaWNhbF9yX3NlKSkgKyAKICBnZW9tX2FibGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjAzLCBzaXplID0gMSkgKwogIHhsYWIoIlN5bnRoZXRpYyBpbnRlci1pdGVtIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJFbXBpcmljYWwgaW50ZXItaXRlbSBjb3JyZWxhdGlvbiIpICsKICB0aGVtZV9idygpICsKICBjb29yZF9maXhlZCh4bGltID0gYygtMSwxKSwgeWxpbSA9IGMoLTEsMSkpIC0+IHB0X3Bsb3RfaXRlbXMKcHRfcGxvdF9pdGVtcwpgYGAKCiMjIyMgQXZlcmFnZXMKYGBge3J9CnJyX3ZhbGlkYXRpb25fbGxtICU+JSBzdW1tYXJpc2UoCiAgbWVhbihzeW50aGV0aWNfciksCiAgbWVhbihlbXBpcmljYWxfciksCiAgbWVhbihhYnMoc3ludGhldGljX3IpKSwKICBtZWFuKGFicyhlbXBpcmljYWxfcikpLAogIHByb3BfbmVnYXRpdmUgPSBzdW0oZW1waXJpY2FsX3IgPCAwKS9uKCksCiAgcHJvcF9wb3MgPSBzdW0oZW1waXJpY2FsX3IgPiAwKS9uKCksCiAgYHByb3BfYmVsb3dfLS4xMGAgPSBzdW0oZW1waXJpY2FsX3IgPCAtMC4xKS9uKCksCiAgYHByb3BfYWJvdmVfLjEwYCA9IHN1bShlbXBpcmljYWxfciA+IDAuMSkvbigpLAopICU+JSBrYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkF2ZXJhZ2UgY29ycmVsYXRpb25zIikKYGBgCgojIyMjIEJ5IHNpZ24gJiBhY2N1cmFjeSBmb3IgYWJzb2x1dGUgY29ycmVsYXRpb25zCmBgYHtyfQpycl92YWxpZGF0aW9uX2xsbSAlPiUgCiAgc3VtbWFyaXNlKG1lYW4oIHNpZ24oc3ludGhldGljX3IpID4gMCksIG1lYW4oIHNpZ24oZW1waXJpY2FsX3IpID4gMCkpCmBgYAoKV2hhdCBpZiBhIGh1bWFuIGluIHRoZSBsb29wIGZsaXBwZWQgdGhlIHNpZ24/CgpgYGB7cn0KcnJfdmFsaWRhdGlvbl9sbG0gJT4lIGZpbHRlcihhYnMoc3ludGhldGljX3IpID49IC4xMCkgJT4lIAogIGdyb3VwX2J5KHNpZ24oc3ludGhldGljX3IpKSAlPiUgCiAgc3VtbWFyaXNlKHJvdW5kKDEgLSBtZWFuKHNpZ24oZW1waXJpY2FsX3IpID09IHNpZ24oc3ludGhldGljX3IpKSwyKSkKCnJyX3ZhbGlkYXRpb25fbGxtICU+JSAgCiAgZ3JvdXBfYnkoc2lnbihzeW50aGV0aWNfcikpICU+JSAKICBzdW1tYXJpc2Uocm91bmQoMSAtIG1lYW4oc2lnbihlbXBpcmljYWxfcikgPT0gc2lnbihzeW50aGV0aWNfcikpLDIpKQoKY29yX3N3aXRjaCA8LSBycl92YWxpZGF0aW9uX2xsbSAlPiUgbXV0YXRlKHN5bnRoZXRpY19yID0gaWZfZWxzZShhYnMoc3ludGhldGljX3IpIDw9IC4xMCB8IHNpZ24oc3ludGhldGljX3IpID09IHNpZ24oZW1waXJpY2FsX3IpLCBzeW50aGV0aWNfciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtMSpzeW50aGV0aWNfcikpICU+JSAKICB7IGJyb29tOjp0aWR5KGNvci50ZXN0KC4kc3ludGhldGljX3IsIC4kZW1waXJpY2FsX3IpKSB9CmNvcl9zd2l0Y2ggJT4lIHNlbGVjdChhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSAlPiUgbXV0YXRlKGtpbmQgPSAibWFuaWZlc3QiKSAlPiUga2FibGUoY2FwdGlvbiA9ICJJZiBhIGh1bWFuIHVzZXIgZmxpcHBlZCB0aGUgc2lnbiB0byBiZSBjb3JyZWN0IGZvciBhbGwgc3ludGhldGljIGVzdGltYXRlcyB3aXRoIGFuIGFic29sdXRlIG1hZ25pdHVkZSBiaWdnZXIgdGhhbiAuMTAiLCBkaWdpdHMgPSAyKQpgYGAKCgpgYGB7cn0KY29yX2FicyA8LSBicm9vbTo6dGlkeShjb3IudGVzdChhYnMocnJfdmFsaWRhdGlvbl9sbG0kc3ludGhldGljX3IpLCBhYnMocnJfdmFsaWRhdGlvbl9sbG0kZW1waXJpY2FsX3IpKSkKY29yX25lZyA8LSBycl92YWxpZGF0aW9uX2xsbSAlPiUgZmlsdGVyKGVtcGlyaWNhbF9yIDwgMCkgJT4lIAogeyBicm9vbTo6dGlkeShjb3IudGVzdCguJHN5bnRoZXRpY19yLCAuJGVtcGlyaWNhbF9yKSkgfQpjb3JfcG9zIDwtIHJyX3ZhbGlkYXRpb25fbGxtICU+JSBmaWx0ZXIoZW1waXJpY2FsX3IgPiAwKSAlPiUgCiB7IGJyb29tOjp0aWR5KGNvci50ZXN0KC4kc3ludGhldGljX3IsIC4kZW1waXJpY2FsX3IpKSB9CgpnZ3Bsb3QocnJfdmFsaWRhdGlvbl9sbG0sIGFlcyhhYnMoc3ludGhldGljX3IpLCBhYnMoZW1waXJpY2FsX3IpLCBjb2xvciA9IGZhY3RvcihzaWduKGVtcGlyaWNhbF9yKSkpKSArIAogIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDMsIHggPSAwLCB5ID0gMC45OCwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChjb3JfYWJzLCB7IHNwcmludGYoImFjY3VyYWN5IGFic29sdXRlIHIgPSAlLjJmIFslLjJmOyUuMmZdIiwgZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpIH0pLCBjb2xvciA9ICdibGFjaycpICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAzLCB4ID0gMCwgeSA9IDAuOSwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChjb3JfbmVnLCB7IHNwcmludGYoImFjY3VyYWN5IG5lZ2F0aXZlIHIgPSAlLjJmIFslLjJmOyUuMmZdIiwgZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpIH0pLCBjb2xvciA9ICIjMzM2NkFBIikgKwogIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDMsIHggPSAwLCB5ID0gMC44Miwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChjb3JfcG9zLCB7IHNwcmludGYoImFjY3VyYWN5IHBvc2l0aXZlIHIgPSAlLjJmIFslLjJmOyUuMmZdIiwgZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpIH0pLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KCBhbHBoYSA9IDAuMSwgc2l6ZSA9IDEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCJTaWduIG9mIGVtcC4gciIsIHZhbHVlcyA9IGMoIjEiID0gIiMwMEEwQjAiLCAiLTEiID0gIiMzMzY2QUEiKSkgKwogIHhsYWIoIkFic29sdXRlIHN5bnRoZXRpYyBpbnRlci1pdGVtIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJBYnNvbHV0ZSBlbXBpcmljYWwgaW50ZXItaXRlbSBjb3JyZWxhdGlvbiIpICsKICB0aGVtZV9idygpICsKICBjb29yZF9maXhlZCh4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpKSAtPiBhYnNfcGxvdF9pdGVtcwphYnNfcGxvdF9pdGVtcwpgYGAKCiMjIyMgRG9lcyBpdCBtYXR0ZXIgaG93IHdlIGRlZmluZSBvdXIgZXhjbHVzaW9uIGNyaXRlcmlhPwpgYGB7cn0KbWFpbl9xcyA8LSBjKCJBQUlEIiwgIlBBTkFTIiwgIlBBUSIsICJQU1MiLCAiTkVQUyIsICJVTFMiLCAiRkNWIiwgIkRBUSIsICJDRVNEIiwgIkhFWEFDTyIsICJPQ0lSIiwgIlBUUSIsICJSQUFTIiwgIktTQSIsICJTQVMiLCAiTUZRIiwgIkNRIiwgIk9MQkkiLCAiVVdFUyIsICJXR1MiKQpycl9odW1hbl9kYXRhX2FsbCA9IHJpbzo6aW1wb3J0KCJkYXRhL3Byb2Nlc3NlZC9zb3NjaV9sYWJlbGxlZF93aXRoX2V4Y2x1c2lvbl9jcml0ZXJpYS5yZHMiKQoKbWFuaWZlc3RfYW5kX2xhdGVudF9yIDwtIGZ1bmN0aW9uKGRhdGEpIHsKICBkYXRhIDwtIGRhdGEgJT4lIAogICAgc2VsZWN0KHN0YXJ0c193aXRoKG1haW5fcXMpKSAlPiUgCiAgICBzZWxlY3QoLWVuZHNfd2l0aCgiX1IiKSkgJT4lIAogICAgbG9uZ2NvcigpICU+JSAKICAgIGxlZnRfam9pbihycl92YWxpZGF0aW9uX2xsbSAlPiUgc2VsZWN0KHZhcmlhYmxlXzEsIHZhcmlhYmxlXzIsIHN5bnRoZXRpY19yKSkKICBzZTIgPC0gbWVhbihkYXRhJGVtcGlyaWNhbF9yX3NlXjIpCiAgbW9kZWwgPC0gcGFzdGUwKCcKICAgICMgTGF0ZW50IHZhcmlhYmxlcwogICAgUGVhcnNvbkxhdGVudCA9fiAxKmVtcGlyaWNhbF9yCiAgCiAgICAjIEZpeGluZyBlcnJvciB2YXJpYW5jZXMgYmFzZWQgb24ga25vd24gc3RhbmRhcmQgZXJyb3JzCiAgICBlbXBpcmljYWxfciB+fiAnLHNlMiwnKmVtcGlyaWNhbF9yCiAgCiAgICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgfn4gc3ludGhldGljX3IKICAnKQoKICBmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gZGF0YSkKICBzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQpICU+JSAKICAgIGZpbHRlcihsaHMgPT0gIlBlYXJzb25MYXRlbnQiLCByaHMgPT0gICJzeW50aGV0aWNfciIpICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoU0VNKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3Quc3RkLCAKICAgICAgICAgICBjb25mLmxvdyA9IGNpLmxvd2VyLCBjb25mLmhpZ2ggPSBjaS51cHBlcikgJT4lIAogICAgYmluZF9yb3dzKAogICAgICBicm9vbTo6dGlkeShjb3IudGVzdChkYXRhJGVtcGlyaWNhbF9yLCBkYXRhJHN5bnRoZXRpY19yKSkgJT4lIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZShraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgICAgIHJlbmFtZShhY2N1cmFjeSA9IGVzdGltYXRlKSAlPiUgCiAgICAgICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiKSkgJT4lIAogICAgbXV0YXRlKGBtYXggTmAgPSBtYXgoZGF0YSRwYWlyd2lzZV9uKSkKfQoKCnJfYWxsIDwtIHJyX2h1bWFuX2RhdGFfYWxsICU+JSAKICBtYW5pZmVzdF9hbmRfbGF0ZW50X3IoKSAlPiUgCiAgbXV0YXRlKGBleGNsdXNpb24gY3JpdGVyaWFgID0gIk5vIGV4Y2x1c2lvbnMiKQoKcl9tYWluIDwtIHJyX2h1bWFuX2RhdGFfYWxsICU+JSAKCW11dGF0ZSh0aW1lX3Blcl9pdGVtX291dGxpZXIgPSB0aW1lX3Blcl9pdGVtIDwgMiwKCQkJCSBldmVuX29kZF9vdXRsaWVyID0gZXZlbl9vZGQgPj0gLS40NSwKCQkJCSBwc3ljaHN5bl9vdXRsaWVyID0gcHN5Y2hzeW4gPCAwLjIyLAoJCQkJIHBzeWNoYW50X291dGxpZXIgPSBwc3ljaGFudCA+IC0wLjAzLAoJCQkJIG1haGFsX291dGxpZXIgPSBjYXJlbGVzczo6bWFoYWQocnJfaHVtYW5fZGF0YV9hbGwgJT4lIHNlbGVjdChzdGFydHNfd2l0aChtYWluX3FzKSksIHBsb3QgPSBGQUxTRSwgZmxhZyA9IFRSVUUsIGNvbmZpZGVuY2UgPSAuOTkpJGZsYWdnZWQpICU+JSAKCW11dGF0ZShpbmNsdWRlZCA9ICFub3Rfc2VyaW91cyAmICF0aW1lX3Blcl9pdGVtX291dGxpZXIgJiAKCSAgICAgICAgICFldmVuX29kZF9vdXRsaWVyICYgIXBzeWNoc3luX291dGxpZXIgJiAhcHN5Y2hhbnRfb3V0bGllciAmICFtYWhhbF9mbGFnZ2VkKSAlPiUgCiAgZmlsdGVyKGluY2x1ZGVkKSAlPiUgCiAgbWFuaWZlc3RfYW5kX2xhdGVudF9yKCkgJT4lIAogIG11dGF0ZShgZXhjbHVzaW9uIGNyaXRlcmlhYCA9ICJBZGFwdGVkOiA8YnI+LSBleGNsdWRlIG5vbi1zZXJpb3VzIHJlc3BvbmRlbnRzPGJyPi0gaXRlbSByZXNwb25zZSB0aW1lIDwgMnM8YnI+LSBvZGQtZXZlbiByIDw9IC40NTxicj4tIHBzeWNob21ldHJpYyBzeW5vbnltIHIgPCAuMjI8YnI+LSBwc3ljaG9tZXRyaWMgYW50b255bSByID4gLTAuMDM8YnI+LSBNYWhhbGFub2JpcyBkaXN0YW5jZSBzZXQgZm9yIDk5JSBzcGVjaWZpY2l0eSIpCgpyX2dvbGRhbW1lcl8xIDwtIHJyX2h1bWFuX2RhdGFfYWxsICU+JSAKCW11dGF0ZSh0aW1lX3Blcl9pdGVtX291dGxpZXIgPSB0aW1lX3Blcl9pdGVtIDwgMiwKCQkJCSBldmVuX29kZF9vdXRsaWVyID0gZXZlbl9vZGQgPiAtLjMwLAoJCQkJIHBzeWNoc3luX291dGxpZXIgPSBwc3ljaHN5biA8IDAuMjIsCgkJCQkgcHN5Y2hhbnRfb3V0bGllciA9IHBzeWNoYW50ID4gLTAuMDMsCgkJCQkgbWFoYWxfb3V0bGllciA9IGNhcmVsZXNzOjptYWhhZChycl9odW1hbl9kYXRhX2FsbCAlPiUgc2VsZWN0KHN0YXJ0c193aXRoKG1haW5fcXMpKSwgcGxvdCA9IEZBTFNFLCBmbGFnID0gVFJVRSwgY29uZmlkZW5jZSA9IC45OTkpJGZsYWdnZWQpICU+JSAKCW11dGF0ZShpbmNsdWRlZCA9ICF0aW1lX3Blcl9pdGVtX291dGxpZXIgJiAhZXZlbl9vZGRfb3V0bGllciAmICFwc3ljaHN5bl9vdXRsaWVyICYgIXBzeWNoYW50X291dGxpZXIgJiAhbWFoYWxfZmxhZ2dlZCkgJT4lIAogIGZpbHRlcihpbmNsdWRlZCkgJT4lIAogIG1hbmlmZXN0X2FuZF9sYXRlbnRfcigpICU+JSAKICBtdXRhdGUoYGV4Y2x1c2lvbiBjcml0ZXJpYWAgPSAiR29sZGFtbWVyIGhldXJpc3RpYzogPGJyPi0gaXRlbSByZXNwb25zZSB0aW1lIDwgMnM8YnI+LSBvZGQtZXZlbiByIDwgLjMwPGJyPi0gcHN5Y2hvbWV0cmljIHN5bm9ueW0gciA8IC4yMjxicj4tIHBzeWNob21ldHJpYyBhbnRvbnltIHIgPiAtMC4wMzxicj4tIE1haGFsYW5vYmlzIGRpc3RhbmNlIHNldCBmb3IgOTk5JSBzcGVjaWZpY2l0eSIpCgpyX2dvbGRhbW1lcl8yIDwtIHJyX2h1bWFuX2RhdGFfYWxsICU+JSAKCW11dGF0ZSh0aW1lX3Blcl9pdGVtX291dGxpZXIgPSB0aW1lX3Blcl9pdGVtIDwgNS41NiwKCQkJCSBldmVuX29kZF9vdXRsaWVyID0gZXZlbl9vZGQgPiAtLjQyLAoJCQkJIHBzeWNoc3luX291dGxpZXIgPSBwc3ljaHN5biA8IC0wLjAzLAoJCQkJIHBzeWNoYW50X291dGxpZXIgPSBwc3ljaGFudCA+IC4zNiwKCQkJCSBtYWhhbF9vdXRsaWVyID0gY2FyZWxlc3M6Om1haGFkKHJyX2h1bWFuX2RhdGFfYWxsICU+JSBzZWxlY3Qoc3RhcnRzX3dpdGgobWFpbl9xcykpLCBwbG90ID0gRkFMU0UsIGZsYWcgPSBUUlVFLCBjb25maWRlbmNlID0gLjk1KSRmbGFnZ2VkKSAlPiUgCgltdXRhdGUoaW5jbHVkZWQgPSAhdGltZV9wZXJfaXRlbV9vdXRsaWVyICYgIWV2ZW5fb2RkX291dGxpZXIgJiAhcHN5Y2hzeW5fb3V0bGllciAmICFwc3ljaGFudF9vdXRsaWVyICYgIW1haGFsX2ZsYWdnZWQpICU+JSAKICBmaWx0ZXIoaW5jbHVkZWQpICU+JSAKICBtYW5pZmVzdF9hbmRfbGF0ZW50X3IoKSAlPiUgCiAgbXV0YXRlKGBleGNsdXNpb24gY3JpdGVyaWFgID0gIkdvbGRhbW1lciA5NSUgc3BlY2lmaWNpdHk6IDxicj4tIGl0ZW0gcmVzcG9uc2UgdGltZSA8IDUuNTZzPGJyPi0gb2RkLWV2ZW4gciA8IC40Mjxicj4tIHBzeWNob21ldHJpYyBzeW5vbnltIHIgPCAtMC4wMzxicj4tIHBzeWNob21ldHJpYyBhbnRvbnltIHIgPiAuMzY8YnI+LSBNYWhhbGFub2JpcyBkaXN0YW5jZSBzZXQgZm9yIDk1JSBzcGVjaWZpY2l0eSIpCgoKcl9nb2xkYW1tZXJfMyA8LSBycl9odW1hbl9kYXRhX2FsbCAlPiUgCgltdXRhdGUodGltZV9wZXJfaXRlbV9vdXRsaWVyID0gdGltZV9wZXJfaXRlbSA8IDQuOTcsCgkJCQkgZXZlbl9vZGRfb3V0bGllciA9IGV2ZW5fb2RkID4gLS4yNiwKCQkJCSBwc3ljaHN5bl9vdXRsaWVyID0gcHN5Y2hzeW4gPCAtMC4zMCwKCQkJCSBwc3ljaGFudF9vdXRsaWVyID0gcHN5Y2hhbnQgPiAuNTUsCgkJCQkgbWFoYWxfb3V0bGllciA9IGNhcmVsZXNzOjptYWhhZChycl9odW1hbl9kYXRhX2FsbCAlPiUgc2VsZWN0KHN0YXJ0c193aXRoKG1haW5fcXMpKSwgcGxvdCA9IEZBTFNFLCBmbGFnID0gVFJVRSwgY29uZmlkZW5jZSA9IC45OSkkZmxhZ2dlZCkgJT4lIAoJbXV0YXRlKGluY2x1ZGVkID0gIXRpbWVfcGVyX2l0ZW1fb3V0bGllciAmICFldmVuX29kZF9vdXRsaWVyICYgIXBzeWNoc3luX291dGxpZXIgJiAhcHN5Y2hhbnRfb3V0bGllciAmICFtYWhhbF9mbGFnZ2VkKSAlPiUgCiAgZmlsdGVyKGluY2x1ZGVkKSAlPiUgCiAgbWFuaWZlc3RfYW5kX2xhdGVudF9yKCkgJT4lIAogIG11dGF0ZShgZXhjbHVzaW9uIGNyaXRlcmlhYCA9ICJHb2xkYW1tZXIgOTklIHNwZWNpZmljaXR5OiA8YnI+LSBpdGVtIHJlc3BvbnNlIHRpbWUgPCA1LjU2czxicj4tIG9kZC1ldmVuIHIgPCAuNDI8YnI+LSBwc3ljaG9tZXRyaWMgc3lub255bSByIDwgLTAuMDM8YnI+LSBwc3ljaG9tZXRyaWMgYW50b255bSByID4gLjM2PGJyPi0gTWFoYWxhbm9iaXMgZGlzdGFuY2Ugc2V0IGZvciA5OSUgc3BlY2lmaWNpdHkiKQoKCQpyX3N0cmljdF9yZWFkaW5nX29mX3ByZXJlZyA8LSBycl9odW1hbl9kYXRhX2FsbCAlPiUgCiAgICBtdXRhdGUocHN5Y2hzeW5fb3V0bGllciA9IHBzeWNoc3luIDwgMC42LAogICAgICBwc3ljaGFudF9vdXRsaWVyID0gcHN5Y2hhbnQgPiAtMC40LAogICAgICBub3RfdXNfY2l0aXplbiA9IE5hdGlvbmFsaXR5ICE9ICJVbml0ZWQgU3RhdGVzIgogICAgICApICU+JQogICAgZmlsdGVyKGlmX2FsbChjKGxvbmdzdHJpbmdfb3V0bGllciwgYG1haGFsX2Rpc3Rfb3V0bGllcl8uNWAsIHBzeWNoc3luX291dGxpZXIsIHBzeWNoYW50X291dGxpZXIsIGV2ZW5fb2RkX291dGxpZXIsIG5vdF91c19jaXRpemVuKSwgfiAuID09IEZBTFNFKSkgJT4lCiAgbWFuaWZlc3RfYW5kX2xhdGVudF9yKCkgJT4lIAogIG11dGF0ZShgZXhjbHVzaW9uIGNyaXRlcmlhYCA9ICJTdHJpY3QgcHJlcmVnaXN0ZXJlZCBjcml0ZXJpYTogPGJyPi0gb2RkLWV2ZW4gciA8IG1lYW4gKyAwLjIgKiBTRDxicj4tIHBzeWNob21ldHJpYyBzeW5vbnltIHIgPCAuNjA8YnI+LSBwc3ljaG9tZXRyaWMgYW50b255bSByID4gLTAuNDA8YnI+LSBNYWhhbGFub2JpcyBkaXN0YW5jZSA8IG1lYW4gKyAwLjUgKiBTRDxicj4tTm90IFVTIGNpdGl6ZW4iKQoKCnJfbWFpbl9maXJzdF80NTAgPC0gcnJfaHVtYW5fZGF0YV9hbGwgJT4lIAoJbXV0YXRlKG1haGFsX291dGxpZXIgPSBjYXJlbGVzczo6bWFoYWQocnJfaHVtYW5fZGF0YV9hbGwgJT4lIHNlbGVjdChzdGFydHNfd2l0aChtYWluX3FzKSksIHBsb3QgPSBGQUxTRSwgZmxhZyA9IFRSVUUsIGNvbmZpZGVuY2UgPSAuOTkpJGZsYWdnZWQpICU+JSAKICBhcnJhbmdlKGBDb21wbGV0ZWQgYXRgKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIgKCkgPD0gNDUwKSAlPiUgCgltdXRhdGUodGltZV9wZXJfaXRlbV9vdXRsaWVyID0gdGltZV9wZXJfaXRlbSA8IDIsCgkJCQkgZXZlbl9vZGRfb3V0bGllciA9IGV2ZW5fb2RkID49IC0uNDUsCgkJCQkgcHN5Y2hzeW5fb3V0bGllciA9IHBzeWNoc3luIDwgMC4yMiwKCQkJCSBwc3ljaGFudF9vdXRsaWVyID0gcHN5Y2hhbnQgPiAtMC4wMykgJT4lIAoJbXV0YXRlKGluY2x1ZGVkID0gIW5vdF9zZXJpb3VzICYgIXRpbWVfcGVyX2l0ZW1fb3V0bGllciAmIAoJICAgICAgICAgIWV2ZW5fb2RkX291dGxpZXIgJiAhcHN5Y2hzeW5fb3V0bGllciAmICFwc3ljaGFudF9vdXRsaWVyICYgIW1haGFsX2ZsYWdnZWQpICU+JSAKICBmaWx0ZXIoaW5jbHVkZWQpICU+JSAKICBtYW5pZmVzdF9hbmRfbGF0ZW50X3IoKSAlPiUgCiAgbXV0YXRlKGBleGNsdXNpb24gY3JpdGVyaWFgID0gIkFkYXB0ZWQgKyBQcmVyZWcgTjogPGJyPi0gdGhlIGFkYXB0ZWQgY3JpdGVyaWE8YnI+LSBPbmx5IHRoZSBmaXJzdCA0NTAgcGFydGljaXBhbnRzLCBvdXIgcHJlcmVnaXN0ZXJlZCBzYW1wbGUgc2l6ZS4iKQoKCnJfbWFpbl91cyA8LSBycl9odW1hbl9kYXRhX2FsbCAlPiUgCgltdXRhdGUodGltZV9wZXJfaXRlbV9vdXRsaWVyID0gdGltZV9wZXJfaXRlbSA8IDIsCgkJCQkgZXZlbl9vZGRfb3V0bGllciA9IGV2ZW5fb2RkID49IC0uNDUsCgkJCQkgcHN5Y2hzeW5fb3V0bGllciA9IHBzeWNoc3luIDwgMC4yMiwKCQkJCSBwc3ljaGFudF9vdXRsaWVyID0gcHN5Y2hhbnQgPiAtMC4wMywKCQkJCSBtYWhhbF9vdXRsaWVyID0gY2FyZWxlc3M6Om1haGFkKHJyX2h1bWFuX2RhdGFfYWxsICU+JSBzZWxlY3Qoc3RhcnRzX3dpdGgobWFpbl9xcykpLCBwbG90ID0gRkFMU0UsIGZsYWcgPSBUUlVFLCBjb25maWRlbmNlID0gLjk5KSRmbGFnZ2VkLAoJCQkJIHVzX2NpdGl6ZW4gPSBOYXRpb25hbGl0eSA9PSAiVW5pdGVkIFN0YXRlcyIsCgkJCQkgZW5nbGlzaF9maXJzdF9sYW5ndWFnZSA9IExhbmd1YWdlID09ICJFbmdsaXNoIikgJT4lIAoJbXV0YXRlKGluY2x1ZGVkID0gIW5vdF9zZXJpb3VzICYgIXRpbWVfcGVyX2l0ZW1fb3V0bGllciAmIAoJICAgICAgICAgIWV2ZW5fb2RkX291dGxpZXIgJiAhcHN5Y2hzeW5fb3V0bGllciAmICFwc3ljaGFudF9vdXRsaWVyICYgIW1haGFsX2ZsYWdnZWQgJiB1c19jaXRpemVuICYgZW5nbGlzaF9maXJzdF9sYW5ndWFnZSkgJT4lIAogIGZpbHRlcihpbmNsdWRlZCkgJT4lIAogIG1hbmlmZXN0X2FuZF9sYXRlbnRfcigpICU+JSAKICBtdXRhdGUoYGV4Y2x1c2lvbiBjcml0ZXJpYWAgPSAiQWRhcHRlZCArIFVTIEVuZ2xpc2g6IDxicj4tIHRoZSBhZGFwdGVkIGNyaXRlcmlhPGJyPi0gVVMgY2l0aXplbnMsIG5vdCBqdXN0IHJlc2lkZW50cywtIEVuZ2xpc2ggZmlyc3QgbGFuZ3VhZ2UiKQoKcl9tYWluX2FwcHJvdmFscyA8LSBycl9odW1hbl9kYXRhX2FsbCAlPiUgCgltdXRhdGUodGltZV9wZXJfaXRlbV9vdXRsaWVyID0gdGltZV9wZXJfaXRlbSA8IDIsCgkJCQkgZXZlbl9vZGRfb3V0bGllciA9IGV2ZW5fb2RkID49IC0uNDUsCgkJCQkgcHN5Y2hzeW5fb3V0bGllciA9IHBzeWNoc3luIDwgMC4yMiwKCQkJCSBwc3ljaGFudF9vdXRsaWVyID0gcHN5Y2hhbnQgPiAtMC4wMywKCQkJCSBtYWhhbF9vdXRsaWVyID0gY2FyZWxlc3M6Om1haGFkKHJyX2h1bWFuX2RhdGFfYWxsICU+JSBzZWxlY3Qoc3RhcnRzX3dpdGgobWFpbl9xcykpLCBwbG90ID0gRkFMU0UsIGZsYWcgPSBUUlVFLCBjb25maWRlbmNlID0gLjk5KSRmbGFnZ2VkLAoJCQkJIHVzX2NpdGl6ZW4gPSBOYXRpb25hbGl0eSA9PSAiVW5pdGVkIFN0YXRlcyIsCgkJCQkgbW9yZV90aGFuXzIwX2FwcHJvdmFscyA9IGBUb3RhbCBhcHByb3ZhbHNgID4gMjAsCgkJCQkgZW5nbGlzaF9maXJzdF9sYW5ndWFnZSA9IExhbmd1YWdlID09ICJFbmdsaXNoIikgJT4lIAoJbXV0YXRlKGluY2x1ZGVkID0gIW5vdF9zZXJpb3VzICYgIXRpbWVfcGVyX2l0ZW1fb3V0bGllciAmIAoJICAgICAgICAgIWV2ZW5fb2RkX291dGxpZXIgJiAhcHN5Y2hzeW5fb3V0bGllciAmICFwc3ljaGFudF9vdXRsaWVyICYgIW1haGFsX2ZsYWdnZWQgJiB1c19jaXRpemVuICYgbW9yZV90aGFuXzIwX2FwcHJvdmFscykgJT4lIAogIGZpbHRlcihpbmNsdWRlZCkgJT4lIAogIG1hbmlmZXN0X2FuZF9sYXRlbnRfcigpICU+JSAKICBtdXRhdGUoYGV4Y2x1c2lvbiBjcml0ZXJpYWAgPSAiQWRhcHRlZCArIFVTICsgPiAyMCBhcHByb3ZhbHM6IDxicj4tIHRoZSBhZGFwdGVkIGNyaXRlcmlhPGJyPi0gVVMgY2l0aXplbnMsIG5vdCBqdXN0IHJlc2lkZW50cywtIE1vcmUgdGhhbiAyMCBhcHByb3ZhbHMiKQoKCnJfYWRhcHRlZF9yZWFkaW5nX29mX3ByZXJlZyA8LSBycl9odW1hbl9kYXRhX2FsbCAlPiUgCiAgICBtdXRhdGUocHN5Y2hzeW5fb3V0bGllciA9IHBzeWNoc3luIDwgMC4yMiwKICAgICAgcHN5Y2hhbnRfb3V0bGllciA9IHBzeWNoYW50ID4gLTAuMDMpICU+JQogICAgZmlsdGVyKGlmX2FsbChjKGBtYWhhbF9kaXN0X291dGxpZXJfLjVgLCBwc3ljaHN5bl9vdXRsaWVyLCBwc3ljaGFudF9vdXRsaWVyLCBldmVuX29kZF9vdXRsaWVyKSwgfiAuID09IEZBTFNFKSkgJT4lCiAgbWFuaWZlc3RfYW5kX2xhdGVudF9yKCkgJT4lIAogIG11dGF0ZShgZXhjbHVzaW9uIGNyaXRlcmlhYCA9ICJDb3JyZWN0ZWQgcHJlcmVnIGNyaXRlcmlhOjxicj4tIG9kZC1ldmVuIHIgPCBtZWFuICsgMC4yICogU0QsPGJyPi0gcHN5Y2hvbWV0cmljIHN5bm9ueW0gciA8IC4yMiw8YnI+IC0gcHN5Y2hvbWV0cmljIGFudG9ueW0gciA+IC0wLjAzLCA8YnI+LSBNYWhhbGFub2JpcyBkaXN0YW5jZSA8IG1lYW4gKyAwLjUgKiBTRCIpCmBgYAoKClRoZSBtYW5pZmVzdCBhY2N1cmFjeSBpcyBleHBlY3RlZCB0byBkZWNyZWFzZSBzbGlnaHRseSB3aXRoIHNhbXBsZSBzaXplIGJlY2F1c2UgaXQgaXMgYXR0ZW51YXRlZCBieSBzYW1wbGluZyBlcnJvciBpbiB0aGUgZW1waXJpY2FsIGNvcnJlbGF0aW9ucy4gVGhlIGxhdGVudCBhY2N1cmFjeSBzaG91bGQgb25seSBncm93IG1vcmUgdW5jZXJ0YWluIHdpdGggZGVjcmVhc2VkIHNhbXBsZSBzaXplLgoKYGBge3J9CmV4Y2x1c2lvbl9jcml0ZXJpYSA8LSBiaW5kX3Jvd3MoCiAgcl9hbGwsIHJfbWFpbiwgcl9zdHJpY3RfcmVhZGluZ19vZl9wcmVyZWcsIHJfYWRhcHRlZF9yZWFkaW5nX29mX3ByZXJlZywgCiAgcl9nb2xkYW1tZXJfMSwgcl9nb2xkYW1tZXJfMiwgcl9nb2xkYW1tZXJfMywgcl9tYWluX3VzLCByX21haW5fYXBwcm92YWxzLAogIHJfbWFpbl9maXJzdF80NTAKICApCmV4Y2x1c2lvbl9jcml0ZXJpYSAlPiUgCiAgICBzZWxlY3QoYGV4Y2x1c2lvbiBjcml0ZXJpYWAsIG1vZGVsLCBraW5kLCBhY2N1cmFjeSwgY29uZi5sb3csIGNvbmYuaGlnaCwgYG1heCBOYCkgJT4lIAogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkFjY3VyYWN5IHdoZW4gaHVtYW4gZGF0YSBpcyBmaWx0ZXJlZCBieSBkaWZmZXJlbnQgZXhjbHVzaW9uIGNyaXRlcmlhIiwgZm9ybWF0ID0gIm1hcmtkb3duIikKCmV4Y2x1c2lvbl9jcml0ZXJpYSAlPiUgCiAgbXV0YXRlKGBleGNsdXNpb24gY3JpdGVyaWFgID0gZmN0X3JldihmY3RfaW5vcmRlcihzdHJfYyhzdHJfc3ViKGBleGNsdXNpb24gY3JpdGVyaWFgLCAxLCBjb2FsZXNjZShzdHJfbG9jYXRlKGBleGNsdXNpb24gY3JpdGVyaWFgLCAiOiIpWywgMV0tMSwgLTEpKSwiLCBuPSIsIGBtYXggTmApKSkpICU+JSAKZ2dwbG90KGFlcyh4ID0gYGV4Y2x1c2lvbiBjcml0ZXJpYWAsIGFjY3VyYWN5LCB5bWluID0gY29uZi5sb3csIHltYXggPSBjb25mLmhpZ2gsIGNvbG9yID0ga2luZCkpICsKICBnZW9tX3BvaW50cmFuZ2UoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChlbmQgPSAwLjcpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGFjY3VyYWN5KSksIHZqdXN0ID0gLTEpICsKICBjb29yZF9mbGlwKCkKYGBgCgoKIyMjIyBDb25zZXF1ZW5jZXMgb2YgZGF0YSBsZWFrYWdlCkJlbG93LCB3ZSBpbXBvcnQgb3VyIHNlYXJjaCByZXN1bHRzIG9mIHRoZSBTQkVSVCB0cmFpbmluZyBjb3JwdXMuIFdlIGlkZW50aWZ5IHZhbGlkYXRpb24gc3R1ZHkgaXRlbXMgd2l0aCBtYXRjaGVzLCBpbnZlc3RpZ2F0ZSB0aGVzZSBtYXRjaGVzIGFuZCB0YWJ1bGF0ZSBhY2N1cmFjeSB3aXRob3V0IHBvdGVudGlhbGx5IGxlYWtlZCBpdGVtcy4KCmBgYHtyfQpsZWFrZWQgPC0gcmlvOjppbXBvcnQoImRhdGEvaW50ZXJtZWRpYXRlL3NlYXJjaF9yZXN1bHRzLnBhcnF1ZXQiKSAlPiUgCiAgbXV0YXRlKGl0ZW1fdGV4dCA9IHN0cl90b19sb3dlcihpdGVtX3RleHQpKQpsZWFrZWRfaXRlbXMgPC0gbGVha2VkICU+JSBncm91cF9ieShpdGVtX3RleHQpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkKCgppdGVtX3BhaXJfdGFibGVfbCA8LSBpdGVtX3BhaXJfdGFibGVfbnVtZXJpYyAlPiUgCiAgbXV0YXRlKGl0ZW1fdGV4dF8xbCA9IHN0cl90b19sb3dlcihpdGVtX3RleHRfMSksCiAgICAgICAgIGl0ZW1fdGV4dF8ybCA9IHN0cl90b19sb3dlcihpdGVtX3RleHRfMikpCgppdGVtcyA8LSBiaW5kX3Jvd3MoaXRlbV9wYWlyX3RhYmxlX2wgJT4lIHNlbGVjdChJbnN0cnVtZW50ID0gSW5zdHJ1bWVudEEsIGl0ZW1fdGV4dGwgPSBpdGVtX3RleHRfMWwpLAogICAgICAgICAgICAgICAgICAgaXRlbV9wYWlyX3RhYmxlX2wgJT4lIHNlbGVjdChJbnN0cnVtZW50ID0gSW5zdHJ1bWVudEIsIGl0ZW1fdGV4dGwgPSBpdGVtX3RleHRfMmwpKSAlPiUgCiAgZGlzdGluY3QoKQoKIyBpdGVtcyAlPiUgaW5uZXJfam9pbihsZWFrZWQsIGJ5ID0gYygiaXRlbV90ZXh0bCIgPSAiaXRlbV90ZXh0IikpICU+JSBWaWV3CgpsZWFrZWRfaXRlbXNfdmFsaWRhdGlvbiA8LSBsZWFrZWRfaXRlbXMgJT4lIHJpZ2h0X2pvaW4oCiAgaXRlbXMsIGJ5ID0gYygiaXRlbV90ZXh0IiA9ICJpdGVtX3RleHRsIikpICU+JSAKICBtdXRhdGUobGVuZ3RoID0gc3RyX2xlbmd0aChpdGVtX3RleHQpLAogICAgICAgICBuID0gY29hbGVzY2UobiwgMCkpCgpsZWFrZWRfaXRlbXNfdmFsaWRhdGlvbiAlPiUgZ3JvdXBfYnkoSW5zdHJ1bWVudCkgJT4lIAogIHN1bW1hcmlzZShsZWFrZWQgPSBzdW0obj4wKSwgaXRlbXMgPSBuKCksIHBlcmNlbnRhZ2UgPSBzdW0obj4wKS9uKCkqMTAwLCBtYXRjaGVzID0gc3VtKG4pKSAlPiUgCiAgYXJyYW5nZShwZXJjZW50YWdlKSAlPiUgCiAga2FibGUoY2FwdGlvbiA9ICJOdW1iZXIgYW5kIHBlcmNlbnQgb2YgaXRlbXMgbGVha2VkIHBlciBpbnN0cnVtZW50IiwgZGlnaXRzID0gMCkKCnJyX3ZhbGlkYXRpb25fbGxtX2xlYWthZ2UgPC0gaXRlbV9wYWlyX3RhYmxlX2wgJT4lIAogIGxlZnRfam9pbihsZWFrZWRfaXRlbXNfdmFsaWRhdGlvbiAlPiUgcmVuYW1lKG5fMSA9IG4sIGl0ZW1fdGV4dF8xbCA9IGl0ZW1fdGV4dCksIGJ5ID0gIml0ZW1fdGV4dF8xbCIpICU+JSAKICBsZWZ0X2pvaW4obGVha2VkX2l0ZW1zX3ZhbGlkYXRpb24gJT4lIHJlbmFtZShuXzIgPSBuLCBpdGVtX3RleHRfMmwgPSBpdGVtX3RleHQpLCBieSA9ICJpdGVtX3RleHRfMmwiKQoKcnJfdmFsaWRhdGlvbl9sbG1fbGVha2FnZSAlPiUgCiAgZ3JvdXBfYnkocG9zc2libHlfbGVha2VkX2luc3RydW1lbnQgPSBzdHJfZGV0ZWN0KEluc3RydW1lbnRBLCAiKE5ldyBFY29sb2dpY2FsfFV0cmVjaHQgV29yaykiKSB8CiAgICAgICAgICAgICBzdHJfZGV0ZWN0KEluc3RydW1lbnRCLCAiKE5ldyBFY29sb2dpY2FsfFV0cmVjaHQgV29yaykiKSkgJT4lIAogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChzeW50aGV0aWNfciwgZW1waXJpY2FsX3IpKSwgcHRfY29yID0gY29yKHB0X3N5bnRoZXRpY19yLCBlbXBpcmljYWxfciksIHJtc2UgPSBzcXJ0KG1lYW4oKGVtcGlyaWNhbF9yIC0gc3ludGhldGljX3IpXjIpKSwgcHRfcm1zZSA9IHNxcnQobWVhbigoZW1waXJpY2FsX3IgLSBwdF9zeW50aGV0aWNfcileMikpLCBuID0gbigpKSAlPiUgCiAgc2VsZWN0KHBvc3NpYmx5X2xlYWtlZF9pbnN0cnVtZW50LCByID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gsIHB0X2Nvciwgcm1zZSwgcHRfcm1zZSwgbikgJT4lIAogIGFycmFuZ2UocikgJT4lIAogIGthYmxlKGNhcHRpb24gPSAiQWNjdXJhY3kgYnkgd2hldGhlciB0aGUgaW5zdHJ1bWVudCBwbGF1c2libHkgbGVha2VkICg+PTUwJSBpdGVtcyBmb3VuZCBpbiBjb3JwdXMpIiwgZGlnaXRzID0gMikKCnJyX3ZhbGlkYXRpb25fbGxtX2xlYWthZ2UgJT4lIAogIGdyb3VwX2J5KG9jY3VycmVkID0gbl8xID4gMCB8IG5fMiA+IDApICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHB0X2NvciA9IGNvcihwdF9zeW50aGV0aWNfciwgZW1waXJpY2FsX3IpLCBybXNlID0gc3FydChtZWFuKChlbXBpcmljYWxfciAtIHN5bnRoZXRpY19yKV4yKSksIHB0X3Jtc2UgPSBzcXJ0KG1lYW4oKGVtcGlyaWNhbF9yIC0gcHRfc3ludGhldGljX3IpXjIpKSwgbiA9IG4oKSkgJT4lIAogIHNlbGVjdChvY2N1cnJlZCwgciA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoLCBwdF9jb3IsIHJtc2UsIHB0X3Jtc2UsIG4pICU+JSAKICBhcnJhbmdlKHIpICU+JSAKICBrYWJsZShjYXB0aW9uID0gIkFjY3VyYWN5IGJ5IHdoZXRoZXIgdGhlIGl0ZW0gb2NjdXJyZWQgaW4gY29ycHVzIChpbmNsdWRpbmcgdHJpdmlhbGx5IHNob3J0IGl0ZW1zKSIsIGRpZ2l0cyA9IDIpCmBgYAoKCjwvZGV0YWlscz4KCgojIyMjIEZ1bGwgdGFibGUKW0Z1bGwgdGFibGUgb2Ygc3ludGhldGljIGFuZCBlbXBpcmljYWwgaXRlbSBwYWlyIGNvcnJlbGF0aW9uc10oaXRlbV9wYWlyX3RhYmxlX3JyLnhsc3gpCgoKCgoKIyMgU3ludGhldGljIFJlbGlhYmlsaXRpZXMKYGBge3J9CnNjYWxlcyA8LSByZWFkUkRTKGZpbGUgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJzY2FsZXNfd2l0aF9hbHBoYV9zZV9yci5yZHMiKSkpCnJlYWxfc2NhbGVzIDwtIHNjYWxlcyAlPiUgZmlsdGVyKHR5cGUgPT0gInJlYWwiKQpzY2FsZXMgPC0gc2NhbGVzICU+JSBmaWx0ZXIobnVtYmVyX29mX2l0ZW1zID49IDMpCmBgYAoKCiMjIyBBY2N1cmFjeQpgYGB7cn0Kc2UyIDwtIG1lYW4oc2NhbGVzJGVtcGlyaWNhbF9hbHBoYV9zZV4yKQpyIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KHNjYWxlcyRlbXBpcmljYWxfYWxwaGEsIHNjYWxlcyRzeW50aGV0aWNfYWxwaGEpKQpwdF9yIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KHNjYWxlcyRlbXBpcmljYWxfYWxwaGEsIHNjYWxlcyRwdF9zeW50aGV0aWNfYWxwaGEpKQoKbW9kZWwgPC0gcGFzdGUwKCcKICAjIExhdGVudCB2YXJpYWJsZXMKICBsYXRlbnRfcmVhbF9yZWwgPX4gMSplbXBpcmljYWxfYWxwaGEKCiAgIyBGaXhpbmcgZXJyb3IgdmFyaWFuY2VzIGJhc2VkIG9uIGtub3duIHN0YW5kYXJkIGVycm9ycwogIGVtcGlyaWNhbF9hbHBoYSB+fiAnLHNlMiwnKmVtcGlyaWNhbF9hbHBoYQoKICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxhdGVudCB2YXJpYWJsZXMKICBsYXRlbnRfcmVhbF9yZWwgfn4gc3ludGhldGljX2FscGhhCicpCgpmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gc2NhbGVzKQpwdF9maXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gc2NhbGVzICU+JSAKICAgICAgICAgICAgICAgIHNlbGVjdChlbXBpcmljYWxfYWxwaGEsIHN5bnRoZXRpY19hbHBoYSA9IHB0X3N5bnRoZXRpY19hbHBoYSkpCgojIEJheWVzaWFuIEVJViBQVApwdF9tX2xtc3ludGhfcmVsX3NjYWxlcyA8LSBicm0oCiAgYmYoZW1waXJpY2FsX2FscGhhIHwgbWkoZW1waXJpY2FsX2FscGhhX3NlKSB+IHN5bnRoZXRpY19hbHBoYSwKICAgICBzaWdtYSB+IHMoc3ludGhldGljX2FscGhhKSksIGRhdGEgPSBzY2FsZXMgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KGVtcGlyaWNhbF9hbHBoYSwgc3ludGhldGljX2FscGhhID0gcHRfc3ludGhldGljX2FscGhhLCBlbXBpcmljYWxfYWxwaGFfc2UpLCAKICBmaWxlID0gImlnbm9yZS9wdF9tX3N5bnRoX3JyX3JlbF9sbSIpCgpuZXdkYXRhIDwtIHB0X21fbG1zeW50aF9yZWxfc2NhbGVzJGRhdGEgJT4lIHNlbGVjdChlbXBpcmljYWxfYWxwaGEsIHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhX3NlKQplcHJlZHMgPC0gZXByZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IHB0X21fbG1zeW50aF9yZWxfc2NhbGVzLCByZV9mb3JtdWxhID0gTkEpCnByZWRzIDwtIHByZWRpY3RlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gcHRfbV9sbXN5bnRoX3JlbF9zY2FsZXMsIHJlX2Zvcm11bGEgPSBOQSkKZXByZWRfcHJlZHMgPC0gZXByZWRzICU+JSBsZWZ0X2pvaW4ocHJlZHMpCmJ5X2RyYXcgPC0gZXByZWRfcHJlZHMgJT4lIGdyb3VwX2J5KC5kcmF3KSAlPiUgCiAgc3VtbWFyaXNlKC5lcHJlZCA9IHZhciguZXByZWQpLAogICAgICAgICAgICAucHJlZGljdGlvbiA9IHZhcigucHJlZGljdGlvbiksCiAgICAgICAgICAgIHNpZ21hID0gc3FydCgucHJlZGljdGlvbiAtIC5lcHJlZCksCiAgICAgICAgICAgIGxhdGVudF9yID0gc3FydCguZXByZWQvLnByZWRpY3Rpb24pKQoKcHRfYWNjdXJhY3lfYmF5ZXNfcmVscyA8LSBieV9kcmF3ICU+JSBtZWFuX2hkY2kobGF0ZW50X3IpCgojIEJheWVzaWFuIEVJViBGVAptX2xtc3ludGhfcmVsX3NjYWxlcyA8LSBicm0oCiAgYmYoZW1waXJpY2FsX2FscGhhIHwgbWkoZW1waXJpY2FsX2FscGhhX3NlKSB+IHN5bnRoZXRpY19hbHBoYSwKICAgICBzaWdtYSB+IHMoc3ludGhldGljX2FscGhhKSksIGRhdGEgPSBzY2FsZXMsIAogIGl0ZXIgPSA2MDAwLCAKICBmaWxlID0gImlnbm9yZS9tX3N5bnRoX3JyX3JlbF9sbSIpCgpuZXdkYXRhIDwtIG1fbG1zeW50aF9yZWxfc2NhbGVzJGRhdGEgJT4lIHNlbGVjdChlbXBpcmljYWxfYWxwaGEsIHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhX3NlKQplcHJlZHMgPC0gZXByZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IG1fbG1zeW50aF9yZWxfc2NhbGVzLCByZV9mb3JtdWxhID0gTkEpCnByZWRzIDwtIHByZWRpY3RlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gbV9sbXN5bnRoX3JlbF9zY2FsZXMsIHJlX2Zvcm11bGEgPSBOQSkKZXByZWRfcHJlZHMgPC0gZXByZWRzICU+JSBsZWZ0X2pvaW4ocHJlZHMpCmJ5X2RyYXcgPC0gZXByZWRfcHJlZHMgJT4lIGdyb3VwX2J5KC5kcmF3KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgICAgICAgICAgbWFlID0gbWVhbihhYnMoLmVwcmVkIC0gLnByZWRpY3Rpb24pKSwKICAgICAgICAgICAgLmVwcmVkID0gdmFyKC5lcHJlZCksCiAgICAgICAgICAgIC5wcmVkaWN0aW9uID0gdmFyKC5wcmVkaWN0aW9uKSwKICAgICAgICAgICAgc2lnbWEgPSBzcXJ0KC5wcmVkaWN0aW9uIC0gLmVwcmVkKSwKICAgICAgICAgICAgbGF0ZW50X3IgPSBzcXJ0KC5lcHJlZC8ucHJlZGljdGlvbikpCgphY2N1cmFjeV9iYXllc19yZWxzIDwtIGJ5X2RyYXcgJT4lIG1lYW5faGRjaShsYXRlbnRfcikKCmJpbmRfcm93cygKICBwdF9yICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIHN0YW5kYXJkaXplZHNvbHV0aW9uKHB0X2ZpdCkgJT4lIAogICAgZmlsdGVyKGxocyA9PSAibGF0ZW50X3JlYWxfcmVsIiwgcmhzID09ICAic3ludGhldGljX2FscGhhIikgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gInByZS10cmFpbmVkIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoU0VNKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3Quc3RkLCAKICAgICAgICAgICBjb25mLmxvdyA9IGNpLmxvd2VyLCBjb25mLmhpZ2ggPSBjaS51cHBlciksCiAgcHRfYWNjdXJhY3lfYmF5ZXNfcmVscyAlPiUgCiAgICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAibGF0ZW50IG91dGNvbWUgKEJheWVzaWFuIEVJVikiKSAlPiUgCiAgICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBsYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlciksCiAgciAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdCkgJT4lIAogICAgZmlsdGVyKGxocyA9PSAibGF0ZW50X3JlYWxfcmVsIiwgcmhzID09ICAic3ludGhldGljX2FscGhhIikgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gImxhdGVudCBvdXRjb21lIChTRU0pIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdC5zdGQsIAogICAgICAgICAgIGNvbmYubG93ID0gY2kubG93ZXIsIGNvbmYuaGlnaCA9IGNpLnVwcGVyKSwKICBhY2N1cmFjeV9iYXllc19yZWxzICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoQmF5ZXNpYW4gRUlWKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBsYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlcikKICApICU+JSAKICBrYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkFjY3VyYWN5IGFjcm9zcyBsYW5ndWFnZSBtb2RlbHMgYW5kIG1ldGhvZHMiKQpgYGAKCgo8ZGV0YWlscz4KPHN1bW1hcnk+CjxoND5QcmVkaWN0aW9uIGVycm9yIHBsb3QgYWNjb3JkaW5nIHRvIHN5bnRoZXRpYyBlc3RpbWF0ZTwvaDQ+Cjwvc3VtbWFyeT4KCgpgYGB7cn0KbV9sbXN5bnRoX3JlbF9zY2FsZXMKYGBgCgoKYGBge3J9CmthYmxlKHJtc2VfYWxwaGEgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKHNpZ21hKSwgY2FwdGlvbiA9ICJBdmVyYWdlIHByZWRpY3Rpb24gZXJyb3IgKFJNU0UpIiwgZGlnaXRzID0gMikKa2FibGUobWFlX2FscGhhIDwtIGJ5X2RyYXcgJT4lIG1lYW5faGRjaShtYWUpLCBjYXB0aW9uID0gIkF2ZXJhZ2UgcHJlZGljdGlvbiBlcnJvciAoTUFFKSIsIGRpZ2l0cyA9IDIpCgpwbG90X3ByZWRpY3Rpb25fZXJyb3JfYWxwaGEgPC0gcGxvdChjb25kaXRpb25hbF9lZmZlY3RzKG1fbG1zeW50aF9yZWxfc2NhbGVzLCBkcGFyID0gInNpZ21hIiksIHBsb3QgPSBGKVtbMV1dICsgCiAgdGhlbWVfYncoKSArIAogIGdlb21fc21vb3RoKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICIjYTQ4NTAwIiwgZmlsbCA9ICIjRURDOTUxIikgKyAKICB4bGFiKCJTeW50aGV0aWMgQ3JvbmJhY2gncyBhbHBoYSIpICsgCiAgeWxhYigiUHJlZGljdGlvbiBlcnJvciAoc2lnbWEpIikgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMSwgMSksIHlsaW0gPSBjKDAsIDAuMzUpKQpwbG90X3ByZWRpY3Rpb25fZXJyb3JfYWxwaGEKYGBgCgo8L2RldGFpbHM+CgoKCgojIyMgU2NhdHRlciBwbG90CmBgYHtyfQpwcmVkIDwtIGNvbmRpdGlvbmFsX2VmZmVjdHMobV9sbXN5bnRoX3JlbF9zY2FsZXMsIG1ldGhvZCA9ICJwcmVkaWN0IikKZ2dwbG90KHNjYWxlcywgYWVzKHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhLCAKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gc3RyX2RldGVjdChzY2FsZSwgIl5yYW5kb20iKSwgCiAgICAgICAgICAgICAgeW1pbiA9IGVtcGlyaWNhbF9hbHBoYSAtIGVtcGlyaWNhbF9hbHBoYV9zZSwKICAgICAgICAgICAgICB5bWF4ID0gZW1waXJpY2FsX2FscGhhICsgZW1waXJpY2FsX2FscGhhX3NlKSkgKyAKICBnZW9tX2FibGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNiwgc2l6ZSA9IDEpICsKICBnZW9tX3Ntb290aChhZXMoCiAgICB4ID0gc3ludGhldGljX2FscGhhLAogICAgeSA9IGVzdGltYXRlX18sCiAgICB5bWluID0gbG93ZXJfXywKICAgIHltYXggPSB1cHBlcl9fLAogICksIHN0YXQgPSAiaWRlbnRpdHkiLCAKICBjb2xvciA9ICIjYTQ4NTAwIiwKICBmaWxsID0gIiNFREM5NTEiLAogIGRhdGEgPSBhcy5kYXRhLmZyYW1lKHByZWQkc3ludGhldGljX2FscGhhKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDBBMEIwIiwgIiM2QTRBM0MiKSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAibm9uZSIpICsKICB4bGFiKCJTeW50aGV0aWMgQ3JvbmJhY2gncyBhbHBoYSIpICsgCiAgeWxhYigiRW1waXJpY2FsIENyb25iYWNoJ3MgYWxwaGEiKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoLTEsIDEpLCB5bGltID0gYygtMSwxKSkgIC0+IHBsb3RfcmVscwpwbG90X3JlbHMKYGBgCgojIyMgSW50ZXJhY3RpdmUgcGxvdApgYGB7cn0KKHNjYWxlcyAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHNjYWxlLCAiXnJhbmRvbSIpKSAlPiUKICBtdXRhdGUoc3ludGhldGljX2FscGhhID0gcm91bmQoc3ludGhldGljX2FscGhhLCAyKSwKICAgICAgICAgZW1waXJpY2FsX2FscGhhID0gcm91bmQoZW1waXJpY2FsX2FscGhhLCAyKSwKICAgICAgICAgc2NhbGUgPSBzdHJfcmVwbGFjZV9hbGwoc2NhbGUsICJfKyIsICIgIikpICU+JSAKZ2dwbG90KC4sIGFlcyhzeW50aGV0aWNfYWxwaGEsIGVtcGlyaWNhbF9hbHBoYSwgCiAgICAgICAgICAgICAgIyB5bWluID0gZW1waXJpY2FsX3IgLSBlbXBpcmljYWxfcl9zZSwgCiAgICAgICAgICAgICAgIyB5bWF4ID0gZW1waXJpY2FsX3IgKyBlbXBpcmljYWxfcl9zZSwgCiAgICAgICAgICAgICAgbGFiZWwgPSBzY2FsZSkpICsgCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMsIHNpemUgPSAxLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIHhsYWIoIlN5bnRoZXRpYyBDcm9uYmFjaCdzIGFscGhhIikgKyAKICB5bGFiKCJFbXBpcmljYWwgQ3JvbmJhY2gncyBhbHBoYSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSArIAogICBjb29yZF9maXhlZCh4bGltID0gYygtMSwxKSwgeWxpbSA9IGMoLTEsMSkpKSAlPiUgCiAgZ2dwbG90bHkoKQpgYGAKCjxkZXRhaWxzPgo8c3VtbWFyeT4KPGg0PlRhYmxlPC9oND4KPC9zdW1tYXJ5PgoKYGBge3J9CnNjYWxlcyAlPiUgCiAgZmlsdGVyKHR5cGUgIT0gInJhbmRvbSIpICU+JSAKICBtdXRhdGUoZW1waXJpY2FsX2FscGhhID0gc3ByaW50ZigiJS4yZsKxJS4zZiIsIGVtcGlyaWNhbF9hbHBoYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtcGlyaWNhbF9hbHBoYV9zZSksCiAgICAgICAgIHN5bnRoZXRpY19hbHBoYSA9IHNwcmludGYoIiUuMmYiLCBzeW50aGV0aWNfYWxwaGEpLAogICAgICAgICBzY2FsZSA9IHN0cl9yZXBsYWNlX2FsbChzY2FsZSwgIl8rIiwgIiAiKQogICAgICAgICApICU+JSAKICBzZWxlY3Qoc2NhbGUsIGVtcGlyaWNhbF9hbHBoYSwgc3ludGhldGljX2FscGhhLCBudW1iZXJfb2ZfaXRlbXMpICU+JSAKICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICBmaWx0ZXIgPSAidG9wIikKYGBgCgoKPC9kZXRhaWxzPgoKCgo8ZGV0YWlscz4KPHN1bW1hcnk+CjxoMz5Sb2J1c3RuZXNzIGNoZWNrczwvaDM+Cjwvc3VtbWFyeT4KCiMjIyMgQWNjdXJhY3kgYnkgd2hldGhlciBzY2FsZXMgd2VyZSByZWFsIG9yIHJhbmRvbQpUaGUgU3VydmV5Qm90MzAwMCBkb2VzIG5vdCAia25vdyIgd2hldGhlciBzY2FsZXMgd2VyZSBwdWJsaXNoZWQgaW4gdGhlIGxpdGVyYXR1cmUgb3IgZm9ybWVkIGF0IHJhbmRvbS4gS25vd2luZyB3aGF0IHdlIGRvIGFib3V0IHRoZSByZXNlYXJjaCBsaXRlcmF0dXJlIGluIHBzeWNob2xvZ3ksIHdlIGNhbiBpbmZlciB0aGF0IHB1Ymxpc2hlZCBzY2FsZXMgd2lsbCB1c3VhbGx5IGV4Y2VlZCB0aGUgTnVubmFsbHkgdGhyZXNob2xkIG9mIC43MC4gSGVuY2UsIHdlIGtub3cgdGhhdCB0aGUgc3ludGhldGljIGFscGhhcyBmb3IgcHVibGlzaGVkIHNjYWxlcyBzaG91bGQgcmFyZWx5IGJlIGJlbG93IC43MC4gSWYgd2UgcmVncmVzcyBzeW50aGV0aWMgYWxwaGFzIG9uIGVtcGlyaWNhbCBhbHBoYXMgc2VwYXJhdGVseSBmb3IgdGhlIHNjYWxlcyB0YWtlbiBmcm9tIHRoZSBsaXRlcmF0dXJlLCB3ZSBzZWUgdGhpcyBhcyBhIGJpYXMgKGEgcG9zaXRpdmUgcmVncmVzc2lvbiBpbnRlcmNlcHQgb2YgLjY4IGFuZCBhIHNsb3BlIOKJoCAxLCAuMjYpLiBTdGlsbCwgdGhlIHN5bnRoZXRpYyBhbHBoYSBlc3RpbWF0ZXMgYXJlIHByZWRpY3RpdmUgb2YgZW1waXJpY2FsIGFscGhhcyB3aXRoIGFuIGFjY3VyYWN5IG9mIC42NS4gCgpUaGVyZSBpcyBubyBjbGVhciBiaWFzIGZvciB0aGUgcmFuZG9tIHNjYWxlcy4gV2hlbiBib3RoIGFyZSBhbmFseXplZCBqb2ludGx5LCB0aGUgY2xlYXIgc2VsZWN0aW9uIGJpYXMgZm9yIHRoZSBwdWJsaXNoZWQgc2NhbGVzIGlzIG1vc3RseSBhdmVyYWdlZCBvdXQgYnV0IGlzIHJlZmxlY3RlZCBpbiB0aGUgc2xvcGUgZXhjZWVkaW5nIDEuCgpgYGB7cn0Kc2NhbGVzICU+JSAKICBncm91cF9ieSh0eXBlKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhKSksIHNkX2FscGhhID0gc2QoZW1waXJpY2FsX2FscGhhKSwgbiA9IG4oKSkgJT4lIAogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkFjY3VyYWN5IHNob3duIHNlcGFyYXRlbHkgZm9yIHJhbmRvbWx5IGZvcm1lZCBhbmQgcmVhbCBzY2FsZXMiKQpgYGAKCmBgYHtyfQpzY2FsZXMgJT4lIAogIGdyb3VwX2J5KHR5cGUpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkobG0oZW1waXJpY2FsX2FscGhhIH4gc3ludGhldGljX2FscGhhKSksIG4gPSBuKCkpICU+JSAKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJSZWdyZXNzaW9uIGludGVyY2VwdHMgYW5kIHNsb3BlcyBmb3IgcmFuZG9tbHkgZm9ybWVkIGFuZCByZWFsIHNjYWxlcyIpCmBgYAoKIyMjIyBBcyBpbiBvdXIgU3RhZ2UgMSBzdWJtaXNzaW9uCkhlcmUgYXJlIHRoZSByZXN1bHRzIGlmIHdlIGNhbGN1bGF0ZSB0aGUgYWNjdXJhY3kgYW5kIHByZWRpY3Rpb24gZXJyb3IgYXMgaW4gdGhlIFN0YWdlIDEgc3VibWlzc2lvbi4gV2Ugbm93IHRoaW5rIHRoaXMgYXBwcm9hY2gsIGJ5IGNvbmRpdGlvbmluZyBvbiByYW5kb20gdmFyaWF0aW9uIGluIHRoZSBlbXBpcmljYWwgY29ycmVsYXRpb25zLCBnYXZlIGEgbWlzbGVhZGluZyBwaWN0dXJlIG9mIHRoZSBhY2N1cmFjeSBhbmQgYmlhcyBvZiB0aGUgc3ludGhldGljIENyb25iYWNoJ3MgYWxwaGFzLiBIZXJlIHdlIHJlcG9ydCB0aGUgcmVzdWx0cyBpZiB3ZSBjb25kdWN0IHRoZSBhbmFseXNpcyBhcyBpbiBTdGFnZSAxIChidXQgd2l0aCB0aGUgY29ycmVjdGVkIFNFIG9mIGVtcGlyaWNhbCBhbHBoYXMpLgoKYGBge3J9CnMxX3NjYWxlcyA8LSBzY2FsZXMgJT4lCiAgZmlsdGVyKG51bWJlcl9vZl9pdGVtcyA+IDIpICU+JSAKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKHJldmVyc2VfaXRlbXMgPSBpZl9lbHNlKHR5cGUgPT0gInJhbmRvbSIsIGxpc3QocmV2ZXJzZV9pdGVtc19ieV8xc3QpLCBsaXN0KHJldmVyc2VfaXRlbXMpKSwKICAgICAgICAgcl9yZWFsX3JldiA9IGxpc3QocmV2ZXJzZV9pdGVtcyhyX3JlYWwsIHJldmVyc2VfaXRlbXMpKSwKICAgICAgICAgcHRfcl9sbG1fcmV2ID0gbGlzdChyZXZlcnNlX2l0ZW1zKHB0X3JfbGxtLCByZXZlcnNlX2l0ZW1zKSksCiAgICAgICAgIHJfbGxtX3JldiA9IGxpc3QocmV2ZXJzZV9pdGVtcyhyX2xsbSwgcmV2ZXJzZV9pdGVtcykpKSAlPiUKICBtdXRhdGUoCiAgICByZWxfcmVhbCA9IGxpc3QocHN5Y2g6OmFscGhhKHJfcmVhbF9yZXYsIGtleXMgPSBGLCBuLm9icyA9IE4pJGZlbGR0KSwKICAgIHJlbF9sbG0gPSBsaXN0KHBzeWNoOjphbHBoYShyX2xsbV9yZXYsIGtleXMgPSBGLCBuLm9icyA9IE4pJGZlbGR0KSwKICAgIHJlbF9wdF9sbG0gPSBsaXN0KHBzeWNoOjphbHBoYShwdF9yX2xsbV9yZXYsIGtleXMgPSBGLCBuLm9icyA9IE4pJGZlbGR0KSkgJT4lCiAgbXV0YXRlKGVtcGlyaWNhbF9hbHBoYSA9IHJlbF9yZWFsJGFscGhhJHJhd19hbHBoYSwKICAgICAgICAgc3ludGhldGljX2FscGhhID0gcmVsX2xsbSRhbHBoYSRyYXdfYWxwaGEsCiAgICAgICAgIHB0X3N5bnRoZXRpY19hbHBoYSA9IHJlbF9wdF9sbG0kYWxwaGEkcmF3X2FscGhhKSAlPiUKICBtdXRhdGUoCiAgICBlbXBpcmljYWxfYWxwaGFfc2UgPSBtZWFuKGRpZmYodW5saXN0KHBzeWNob21ldHJpYzo6YWxwaGEuQ0koZW1waXJpY2FsX2FscGhhLCBrID0gbnVtYmVyX29mX2l0ZW1zLCBOID0gTiwgbGV2ZWwgPSAwLjk1KSkpKS8xLjk2KSAlPiUgCiAgICAgIGZpbHRlcihlbXBpcmljYWxfYWxwaGEgPiAwKQoKczFfciA8LSBicm9vbTo6dGlkeShjb3IudGVzdChzMV9zY2FsZXMkZW1waXJpY2FsX2FscGhhLCBzMV9zY2FsZXMkc3ludGhldGljX2FscGhhKSkKYGBgCgoKYGBge3J9Cm1fbG1zeW50aF9yZWxfc2NhbGVzX3MxIDwtIGJybSgKICBiZihlbXBpcmljYWxfYWxwaGEgfCBtaShlbXBpcmljYWxfYWxwaGFfc2UpIH4gc3ludGhldGljX2FscGhhLAogICAgIHNpZ21hIH4gcG9seShzeW50aGV0aWNfYWxwaGEsIGRlZ3JlZSA9IDMpKSwgZGF0YSA9IHMxX3NjYWxlcywgCiAgaXRlciA9IDYwMDAsIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45KSwKICBmaWxlID0gImlnbm9yZS9tX3N5bnRoX3JyX3JlbF9sbV9hc19zdGFnZV8xIikKCnByZWQgPC0gY29uZGl0aW9uYWxfZWZmZWN0cyhtX2xtc3ludGhfcmVsX3NjYWxlc19zMSwgbWV0aG9kID0gInByZWRpY3QiKQpnZ3Bsb3QoczFfc2NhbGVzLCBhZXMoc3ludGhldGljX2FscGhhLCBlbXBpcmljYWxfYWxwaGEsIAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBzdHJfZGV0ZWN0KHNjYWxlLCAiXnJhbmRvbSIpLCAKICAgICAgICAgICAgICB5bWluID0gZW1waXJpY2FsX2FscGhhIC0gZW1waXJpY2FsX2FscGhhX3NlLAogICAgICAgICAgICAgIHltYXggPSBlbXBpcmljYWxfYWxwaGEgKyBlbXBpcmljYWxfYWxwaGFfc2UpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBzaXplID0gMSkgKwogIGdlb21fc21vb3RoKGFlcygKICAgIHggPSBzeW50aGV0aWNfYWxwaGEsCiAgICB5ID0gZXN0aW1hdGVfXywKICAgIHltaW4gPSBsb3dlcl9fLAogICAgeW1heCA9IHVwcGVyX18sCiAgKSwgc3RhdCA9ICJpZGVudGl0eSIsIAogIGNvbG9yID0gIiNhNDg1MDAiLAogIGZpbGwgPSAiI0VEQzk1MSIsCiAgZGF0YSA9IGFzLmRhdGEuZnJhbWUocHJlZCRzeW50aGV0aWNfYWxwaGEpKSArICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzAwQTBCMCIsICIjNkE0QTNDIiksCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gIm5vbmUiKSArCiAgeGxhYigiU3ludGhldGljIENyb25iYWNoJ3MgYWxwaGEiKSArIAogIHlsYWIoIkVtcGlyaWNhbCBDcm9uYmFjaCdzIGFscGhhIikgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xLCAxKSwgeWxpbSA9IGMoLTEsMSkpICAtPiBzMV9wbG90X3JlbHMKCm5ld2RhdGEgPC0gbV9sbXN5bnRoX3JlbF9zY2FsZXNfczEkZGF0YSAlPiUgc2VsZWN0KGVtcGlyaWNhbF9hbHBoYSwgc3ludGhldGljX2FscGhhLCBlbXBpcmljYWxfYWxwaGFfc2UpCmVwcmVkcyA8LSBlcHJlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gbV9sbXN5bnRoX3JlbF9zY2FsZXNfczEsIHJlX2Zvcm11bGEgPSBOQSkKcHJlZHMgPC0gcHJlZGljdGVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBtX2xtc3ludGhfcmVsX3NjYWxlc19zMSwgcmVfZm9ybXVsYSA9IE5BKQplcHJlZF9wcmVkcyA8LSBlcHJlZHMgJT4lIGxlZnRfam9pbihwcmVkcykKYnlfZHJhdyA8LSBlcHJlZF9wcmVkcyAlPiUgZ3JvdXBfYnkoLmRyYXcpICU+JSAKICBzdW1tYXJpc2UoCiAgICAgICAgICAgICBtYWUgPSBtZWFuKGFicyguZXByZWQgLSAucHJlZGljdGlvbikpLAogICAgICAgICAgICAuZXByZWQgPSB2YXIoLmVwcmVkKSwKICAgICAgICAgICAgLnByZWRpY3Rpb24gPSB2YXIoLnByZWRpY3Rpb24pLAogICAgICAgICAgICBzaWdtYSA9IHNxcnQoLnByZWRpY3Rpb24gLSAuZXByZWQpLAogICAgICAgICAgICBsYXRlbnRfciA9IHNxcnQoLmVwcmVkLy5wcmVkaWN0aW9uKSkKCmFjY3VyYWN5X2JheWVzX3JlbHNfcG9seSA8LSBieV9kcmF3ICU+JSBtZWFuX2hkY2kobGF0ZW50X3IpCgpzMV9wbG90X3JlbHMKYGBgCgpgYGB7cn0KYmluZF9yb3dzKAogIHIgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSwKICBzMV9yICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkLCBjb25kaXRpb25lZCBvbiBlbXBpcmljYWwgciIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIGFjY3VyYWN5X2JheWVzX3JlbHMgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gImxhdGVudCBvdXRjb21lIChCYXllc2lhbiBFSVYpIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGxhdGVudF9yLCBjb25mLmxvdyA9IC5sb3dlciwgY29uZi5oaWdoID0gLnVwcGVyKSwKICBhY2N1cmFjeV9iYXllc19yZWxzX3BvbHkgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQsIGNvbmRpdGlvbmVkIG9uIGVtcGlyaWNhbCByIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoQmF5ZXNpYW4gRUlWKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBsYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlciksCiAgKSAlPiUgCiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgb2Ygc3ludGhldGljIGFscGhhcyB3aGVuIGVtcGlyaWNhbCBhbHBoYXMgYXJlIGJpYXNlZCB1cHdhcmQgdGhyb3VnaCBhZGFwdGl2ZSBpdGVtIHJldmVyc2lvbiBhbmQgc2VsZWN0aW9uIG9uIHBvc2l0aXZlIGFscGhhcyIpCmBgYAoKCgojIyMjIE51bWJlciBvZiBpdGVtcyBhcyBhIHRyaXZpYWwgcHJlZGljdG9yCkFsdGhvdWdoIHRoZSBudW1iZXIgb2YgaXRlbXMgYWxvbmUgY2FuIG9mIGNvdXJzZSBwcmVkaWN0IENyb25iYWNoJ3MgYWxwaGEsIHRoZSBzeW50aGV0aWMgYWxwaGFzIGV4cGxhaW4gbXVjaCBtb3JlIHZhcmlhbmNlIGluIGVtcGlyaWNhbCBhbHBoYXMuCgpgYGB7cn0Kc2NhbGVzICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChudW1iZXJfb2ZfaXRlbXMsIGVtcGlyaWNhbF9hbHBoYSkpLCBzZF9hbHBoYSA9IHNkKGVtcGlyaWNhbF9hbHBoYSksIG4gPSBuKCkpICU+JSAKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikKCgpzdW1tYXJ5KGxtKGVtcGlyaWNhbF9hbHBoYSB+IG51bWJlcl9vZl9pdGVtcywgc2NhbGVzKSkKc3VtbWFyeShsbShlbXBpcmljYWxfYWxwaGEgfiBudW1iZXJfb2ZfaXRlbXMgKyBzeW50aGV0aWNfYWxwaGEsIHNjYWxlcykpCmBgYAoKCiMjIyMgRGVhdHRlbnVhdGluZyBhY2N1cmFjeQpgYGB7cn0Kc2NhbGVzICU+JSB1bmdyb3VwKCkgJT4lIAogIHN1bW1hcmlzZShtZWFuKGVtcGlyaWNhbF9hbHBoYSksIHNkKGVtcGlyaWNhbF9hbHBoYSkpICU+JSAKICBrYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkFjY3VyYWN5IGFjcm9zcyBhbGwgc2NhbGVzIikKc2NhbGVzICU+JSBncm91cF9ieSh0eXBlKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fYWxwaGEgPSBtZWFuKGVtcGlyaWNhbF9hbHBoYSksIAogICAgICAgICAgICBzZF9hbHBoYSA9IHNkKGVtcGlyaWNhbF9hbHBoYSksCiAgICAgICAgICAgIGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhKSksIAogICAgICAgICAgICBuID0gbigpKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJBY2N1cmFjeSBzZXBhcmF0ZWQgYnkgcmFuZG9tL3JlYWwiKQpwc3ljaG9tZXRyaWM6OmNSUnIoMC42NDcsIDAuMTAyLCAwLjUxNCkgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgZm9yIHJlYWwgc2NhbGVzIGRpc2F0dGVudWF0ZWQgZm9yIHZhcmlhbmNlIHJlc3RyaWN0aW9uIikKYGBgCgoKIyMjIyBQcmUtdHJhaW5lZCBtb2RlbApJcyB0aGUgYWNjdXJhY3kgbG93ZXIgZm9yIHRoZSBwcmUtdHJhaW5lZCBtb2RlbD8KCmBgYHtyfQpnZ3Bsb3Qoc2NhbGVzLCBhZXMocHRfc3ludGhldGljX2FscGhhLCBlbXBpcmljYWxfYWxwaGEsIAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBzdHJfZGV0ZWN0KHNjYWxlLCAiXnJhbmRvbSIpLCAKICAgICAgICAgICAgICB5bWluID0gZW1waXJpY2FsX2FscGhhIC0gZW1waXJpY2FsX2FscGhhX3NlLAogICAgICAgICAgICAgIHltYXggPSBlbXBpcmljYWxfYWxwaGEgKyBlbXBpcmljYWxfYWxwaGFfc2UpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBzaXplID0gMSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDBBMEIwIiwgIiM2QTRBM0MiKSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAibm9uZSIpICsKICB4bGFiKCJTeW50aGV0aWMgQ3JvbmJhY2gncyBhbHBoYSIpICsgCiAgeWxhYigiRW1waXJpY2FsIENyb25iYWNoJ3MgYWxwaGEiKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoLTEsMSksIHlsaW0gPSBjKC0xLDEpKSAtPiBwdF9wbG90X3JlbHMKcHRfcGxvdF9yZWxzCmBgYAoKCgo8L2RldGFpbHM+CgoKCgoKCiMjIFN5bnRoZXRpYyBTY2FsZSBDb3JyZWxhdGlvbnMKYGBge3J9Cm1hbmlmZXN0X3Njb3JlcyA9IGFycm93OjpyZWFkX2ZlYXRoZXIoZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLnNjYWxlX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQpwdF9tYW5pZmVzdF9zY29yZXMgPSBhcnJvdzo6cmVhZF9mZWF0aGVyKGZpbGUgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJ7cHJldHJhaW5lZF9tb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLnNjYWxlX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQoKbWFuaWZlc3Rfc2NvcmVzIDwtIG1hbmlmZXN0X3Njb3JlcyAlPiUKIGxlZnRfam9pbihyZWFsX3NjYWxlcywgYnkgPSBjKCJzY2FsZV9hIiA9ICJzY2FsZSIpKSAlPiUKIGxlZnRfam9pbihyZWFsX3NjYWxlcywgYnkgPSBjKCJzY2FsZV9iIiA9ICJzY2FsZSIpKSAlPiUgCiAgbGVmdF9qb2luKHB0X21hbmlmZXN0X3Njb3JlcyAlPiUgc2VsZWN0KHNjYWxlX2EsIHNjYWxlX2IsIHB0X3N5bnRoZXRpY19yID0gc3ludGhldGljX3IpLCBieSA9IGMoInNjYWxlX2EiLCAic2NhbGVfYiIpKQoKcHRfbWFuaWZlc3Rfc2NvcmVzIDwtIHB0X21hbmlmZXN0X3Njb3JlcyAlPiUKIGxlZnRfam9pbihyZWFsX3NjYWxlcywgYnkgPSBjKCJzY2FsZV9hIiA9ICJzY2FsZSIpKSAlPiUKIGxlZnRfam9pbihyZWFsX3NjYWxlcywgYnkgPSBjKCJzY2FsZV9iIiA9ICJzY2FsZSIpKQoKbWFuaWZlc3Rfc2NvcmVzX2FsbCA8LSBtYW5pZmVzdF9zY29yZXMKcHRfbWFuaWZlc3Rfc2NvcmVzX2FsbCA8LSBwdF9tYW5pZmVzdF9zY29yZXMKbWFuaWZlc3Rfc2NvcmVzIDwtIG1hbmlmZXN0X3Njb3JlcyAlPiUgZmlsdGVyKG51bWJlcl9vZl9pdGVtcy54ID49IDMsIG51bWJlcl9vZl9pdGVtcy55ID49IDMpCnB0X21hbmlmZXN0X3Njb3JlcyA8LSBwdF9tYW5pZmVzdF9zY29yZXMgJT4lIGZpbHRlcihudW1iZXJfb2ZfaXRlbXMueCA+PSAzLCBudW1iZXJfb2ZfaXRlbXMueSA+PSAzKQpgYGAKCiMjIyBBY2N1cmFjeQpgYGB7cn0KciA8LSBicm9vbTo6dGlkeShjb3IudGVzdChtYW5pZmVzdF9zY29yZXMkZW1waXJpY2FsX3IsIG1hbmlmZXN0X3Njb3JlcyRzeW50aGV0aWNfcikpCnB0X3IgPC0gYnJvb206OnRpZHkoY29yLnRlc3QocHRfbWFuaWZlc3Rfc2NvcmVzJGVtcGlyaWNhbF9yLCBwdF9tYW5pZmVzdF9zY29yZXMkc3ludGhldGljX3IpKQoKc2UyIDwtIG1lYW4obWFuaWZlc3Rfc2NvcmVzJGVtcGlyaWNhbF9yX3NlXjIpCm1vZGVsIDwtIHBhc3RlMCgnCiAgICAjIExhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgPX4gMSplbXBpcmljYWxfcgoKICAgICMgRml4aW5nIGVycm9yIHZhcmlhbmNlcyBiYXNlZCBvbiBrbm93biBzdGFuZGFyZCBlcnJvcnMKICAgIGVtcGlyaWNhbF9yIH5+ICcsc2UyLCcqZW1waXJpY2FsX3IKCiAgICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgfn4gc3ludGhldGljX3IKICAnKQoKZml0IDwtIHNlbShtb2RlbCwgZGF0YSA9IG1hbmlmZXN0X3Njb3JlcykKcHRfZml0IDwtIHNlbShtb2RlbCwgZGF0YSA9IHB0X21hbmlmZXN0X3Njb3JlcykKCgpwdF9tX2xtc3ludGhfcl9zY2FsZXMgPC0gYnJtKAogIGJmKGVtcGlyaWNhbF9yIHwgbWkoZW1waXJpY2FsX3Jfc2UpIH4gc3ludGhldGljX3IgKyAoMXxtbShzY2FsZV9hLCBzY2FsZV9iKSksCiAgICAgc2lnbWEgfiBzKHN5bnRoZXRpY19yKSksIGRhdGEgPSBwdF9tYW5pZmVzdF9zY29yZXMsIAogIGZpbGUgPSAiaWdub3JlL3B0X21fc3ludGhfcnJfcl9zY2FsZXNfbG04IikKCm5ld2RhdGEgPC0gcHRfbV9sbXN5bnRoX3Jfc2NhbGVzJGRhdGEgJT4lIHNlbGVjdChlbXBpcmljYWxfciwgc3ludGhldGljX3IsIGVtcGlyaWNhbF9yX3NlKQplcHJlZHMgPC0gZXByZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IHB0X21fbG1zeW50aF9yX3NjYWxlcywgcmVfZm9ybXVsYSA9IE5BKQpwcmVkcyA8LSBwcmVkaWN0ZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IHB0X21fbG1zeW50aF9yX3NjYWxlcywgcmVfZm9ybXVsYSA9IE5BKQplcHJlZF9wcmVkcyA8LSBlcHJlZHMgJT4lIGxlZnRfam9pbihwcmVkcykKYnlfZHJhdyA8LSBlcHJlZF9wcmVkcyAlPiUgZ3JvdXBfYnkoLmRyYXcpICU+JSAKICBzdW1tYXJpc2UoLmVwcmVkID0gdmFyKC5lcHJlZCksCiAgICAgICAgICAgIC5wcmVkaWN0aW9uID0gdmFyKC5wcmVkaWN0aW9uKSwKICAgICAgICAgICAgc2lnbWEgPSBzcXJ0KC5wcmVkaWN0aW9uIC0gLmVwcmVkKSwKICAgICAgICAgICAgbGF0ZW50X3IgPSBzcXJ0KC5lcHJlZC8ucHJlZGljdGlvbikpCgpwdF9hY2N1cmFjeV9iYXllc19zY2FsZXMgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKGxhdGVudF9yKQoKbV9sbXN5bnRoX3Jfc2NhbGVzIDwtIGJybSgKICBiZihlbXBpcmljYWxfciB8IG1pKGVtcGlyaWNhbF9yX3NlKSB+IHN5bnRoZXRpY19yICsgKDF8bW0oc2NhbGVfYSwgc2NhbGVfYikpLAogICAgIHNpZ21hIH4gcyhzeW50aGV0aWNfcikpLCBkYXRhID0gbWFuaWZlc3Rfc2NvcmVzLCAKICBmaWxlID0gImlnbm9yZS9tX3N5bnRoX3JyX3Jfc2NhbGVzX2xtOCIpCgpzZF9zeW50aCA8LSBzZChtX2xtc3ludGhfcl9zY2FsZXMkZGF0YSRzeW50aGV0aWNfcikKCgpuZXdkYXRhIDwtIG1fbG1zeW50aF9yX3NjYWxlcyRkYXRhICU+JSBzZWxlY3QoZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcl9zZSkKZXByZWRzIDwtIGVwcmVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBtX2xtc3ludGhfcl9zY2FsZXMsIHJlX2Zvcm11bGEgPSBOQSkKcHJlZHMgPC0gcHJlZGljdGVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBtX2xtc3ludGhfcl9zY2FsZXMsIHJlX2Zvcm11bGEgPSBOQSkKZXByZWRfcHJlZHMgPC0gZXByZWRzICU+JSBsZWZ0X2pvaW4ocHJlZHMpCmJ5X2RyYXcgPC0gZXByZWRfcHJlZHMgJT4lIGdyb3VwX2J5KC5kcmF3KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgICAgICAgICBtYWUgPSBtZWFuKGFicyguZXByZWQgLSAucHJlZGljdGlvbikpLAogICAgICAgICAgICAuZXByZWQgPSB2YXIoLmVwcmVkKSwKICAgICAgICAgICAgLnByZWRpY3Rpb24gPSB2YXIoLnByZWRpY3Rpb24pLAogICAgICAgICAgICBzaWdtYSA9IHNxcnQoLnByZWRpY3Rpb24gLSAuZXByZWQpLAogICAgICAgICAgICBsYXRlbnRfciA9IHNxcnQoLmVwcmVkLy5wcmVkaWN0aW9uKSkKCmFjY3VyYWN5X2JheWVzX3NjYWxlcyA8LSBieV9kcmF3ICU+JSBtZWFuX2hkY2kobGF0ZW50X3IpCgpiaW5kX3Jvd3MoCiAgcHRfciAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAicHJlLXRyYWluZWQiLCBraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSwKICBzdGFuZGFyZGl6ZWRzb2x1dGlvbihwdF9maXQpICU+JSAKICAgIGZpbHRlcihsaHMgPT0gIlBlYXJzb25MYXRlbnQiLCByaHMgPT0gICJzeW50aGV0aWNfciIpICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAibGF0ZW50IG91dGNvbWUgKFNFTSkiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0LnN0ZCwgCiAgICAgICAgICAgY29uZi5sb3cgPSBjaS5sb3dlciwgY29uZi5oaWdoID0gY2kudXBwZXIpLAogIHB0X2FjY3VyYWN5X2JheWVzX3NjYWxlcyAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAicHJlLXRyYWluZWQiLCBraW5kID0gImxhdGVudCBvdXRjb21lIChCYXllc2lhbiBFSVYpIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGxhdGVudF9yLCBjb25mLmxvdyA9IC5sb3dlciwgY29uZi5oaWdoID0gLnVwcGVyKSwKICByICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkIiwga2luZCA9ICJtYW5pZmVzdCIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCksCiAgc3RhbmRhcmRpemVkc29sdXRpb24oZml0KSAlPiUgCiAgICBmaWx0ZXIobGhzID09ICJQZWFyc29uTGF0ZW50IiwgcmhzID09ICAic3ludGhldGljX3IiKSAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibGF0ZW50IG91dGNvbWUgKFNFTSkiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0LnN0ZCwgCiAgICAgICAgICAgY29uZi5sb3cgPSBjaS5sb3dlciwgY29uZi5oaWdoID0gY2kudXBwZXIpLAogIGFjY3VyYWN5X2JheWVzX3NjYWxlcyAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibGF0ZW50IG91dGNvbWUgKEJheWVzaWFuIEVJVikiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gbGF0ZW50X3IsIGNvbmYubG93ID0gLmxvd2VyLCBjb25mLmhpZ2ggPSAudXBwZXIpCiAgKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9IHN0cl9jKCJBY2N1cmFjeSBmb3Igaz0iLG5yb3cobWFuaWZlc3Rfc2NvcmVzKSwiIHNjYWxlIHBhaXJzICgiLG5fZGlzdGluY3QoYyhtYW5pZmVzdF9zY29yZXMkc2NhbGVfYSwgbWFuaWZlc3Rfc2NvcmVzJHNjYWxlX2IpKSwiIHNjYWxlcykgYWNyb3NzIGxhbmd1YWdlIG1vZGVscyBhbmQgbWV0aG9kcyIpKQpgYGAKCgo8ZGV0YWlscz4KPHN1bW1hcnk+CjxoND5QcmVkaWN0aW9uIGVycm9yIHBsb3QgYWNjb3JkaW5nIHRvIHN5bnRoZXRpYyBlc3RpbWF0ZTwvaDQ+Cjwvc3VtbWFyeT4KCmBgYHtyfQptX2xtc3ludGhfcl9zY2FsZXMKCmthYmxlKHJtc2Vfc2NhbGVzIDwtIGJ5X2RyYXcgJT4lIG1lYW5faGRjaShzaWdtYSksIGNhcHRpb24gPSAiQXZlcmFnZSBwcmVkaWN0aW9uIGVycm9yIChSTVNFKSIsIGRpZ2l0cyA9IDIpCmthYmxlKG1hZV9zY2FsZXMgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKG1hZSksIGNhcHRpb24gPSAiQXZlcmFnZSBwcmVkaWN0aW9uIGVycm9yIChNQUUpIiwgZGlnaXRzID0gMikKCnBsb3RfcHJlZGljdGlvbl9lcnJvcl9zY2FsZXMgPC0gcGxvdChjb25kaXRpb25hbF9lZmZlY3RzKG1fbG1zeW50aF9yX3NjYWxlcywgZHBhciA9ICJzaWdtYSIpLCBwbG90ID0gRilbWzFdXSArIAogIHRoZW1lX2J3KCkgKyAKICBnZW9tX3Ntb290aChzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiI2E0ODUwMCIsIGZpbGwgPSAiI0VEQzk1MSIpICsgCiAgeGxhYigiU3ludGhldGljIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJQcmVkaWN0aW9uIGVycm9yIChzaWdtYSkiKQpwbG90X3ByZWRpY3Rpb25fZXJyb3Jfc2NhbGVzCmBgYAoKCjwvZGV0YWlscz4KCgoKIyMjIFNjYXR0ZXIgcGxvdApgYGB7cn0KcHJlZCA8LSBjb25kaXRpb25hbF9lZmZlY3RzKG1fbG1zeW50aF9yX3NjYWxlcywgbWV0aG9kID0gInByZWRpY3QiKQpnZ3Bsb3QobWFuaWZlc3Rfc2NvcmVzLCBhZXMoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yLCAKICAgICAgICAgICAgICB5bWluID0gZW1waXJpY2FsX3IgLSBlbXBpcmljYWxfcl9zZSwKICAgICAgICAgICAgICB5bWF4ID0gZW1waXJpY2FsX3IgKyBlbXBpcmljYWxfcl9zZSkpICsgCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC4xLCBzaXplID0gMSkgKwogIGdlb21fc21vb3RoKGFlcygKICAgIHggPSBzeW50aGV0aWNfciwKICAgIHkgPSBlc3RpbWF0ZV9fLAogICAgeW1pbiA9IGxvd2VyX18sCiAgICB5bWF4ID0gdXBwZXJfXywKICApLCBzdGF0ID0gImlkZW50aXR5IiwgCiAgY29sb3IgPSAiI2E0ODUwMCIsCiAgZmlsbCA9ICIjRURDOTUxIiwKICBkYXRhID0gYXMuZGF0YS5mcmFtZShwcmVkJHN5bnRoZXRpY19yKSkgKwogIHhsYWIoIlN5bnRoZXRpYyBpbnRlci1zY2FsZSBjb3JyZWxhdGlvbiIpICsgCiAgeWxhYigiRW1waXJpY2FsIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xLDEpLCB5bGltID0gYygtMSwxKSkgLT4gcGxvdF9zY2FsZXMKcGxvdF9zY2FsZXMKYGBgCgojIyMgSW50ZXJhY3RpdmUgcGxvdApgYGB7cn0KKG1hbmlmZXN0X3Njb3JlcyAlPiUgCiAgbXV0YXRlKHN5bnRoZXRpY19yID0gcm91bmQoc3ludGhldGljX3IsIDIpLAogICAgICAgICBlbXBpcmljYWxfciA9IHJvdW5kKGVtcGlyaWNhbF9yLCAyKSwKICAgICAgICAgc2NhbGVzID0gc3RyX3JlcGxhY2VfYWxsKHN0cl9jKHNjYWxlX2EsICJcbiIsIHNjYWxlX2IpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8rIiwgIiAiKSkgJT4lIApnZ3Bsb3QoLiwgYWVzKHN5bnRoZXRpY19yLCBlbXBpcmljYWxfciwgCiAgICAgICAgICAgICAgIyB5bWluID0gZW1waXJpY2FsX3IgLSBlbXBpcmljYWxfcl9zZSwgCiAgICAgICAgICAgICAgIyB5bWF4ID0gZW1waXJpY2FsX3IgKyBlbXBpcmljYWxfcl9zZSwgCiAgICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXMpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuMywgc2l6ZSA9IDEpICsKICB4bGFiKCJTeW50aGV0aWMgaW50ZXItc2NhbGUgY29ycmVsYXRpb24iKSArIAogIHlsYWIoIkVtcGlyaWNhbCBpbnRlci1zY2FsZSBjb3JyZWxhdGlvbiIpICsKICB0aGVtZV9idygpICsKICBjb29yZF9maXhlZCh4bGltID0gYygtMSwxKSwgeWxpbSA9IGMoLTEsMSkpKSAlPiUgCiAgZ2dwbG90bHkoKQpgYGAKCjxkZXRhaWxzPgo8c3VtbWFyeT4KPGg0PlRhYmxlPC9oND4KPC9zdW1tYXJ5PgoKYGBge3J9Cm1hbmlmZXN0X3Njb3JlcyAlPiUgCiAgICAgICAgICAgICAgICBtdXRhdGUoZW1waXJpY2FsX3IgPSBzcHJpbnRmKCIlLjJmwrElLjNmIiwgZW1waXJpY2FsX3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtcGlyaWNhbF9yX3NlKSwKICAgICAgICAgICAgICAgICAgICAgICBzeW50aGV0aWNfciA9IHNwcmludGYoIiUuMmYiLCBzeW50aGV0aWNfciksCiAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfYSA9IHN0cl9yZXBsYWNlX2FsbChzY2FsZV9hLCAiXysiLCAiICIpLAogICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2IgPSBzdHJfcmVwbGFjZV9hbGwoc2NhbGVfYiwgIl8rIiwgIiAiKQogICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KHNjYWxlX2EsIHNjYWxlX2IsIGVtcGlyaWNhbF9yLCBzeW50aGV0aWNfcikgJT4lIAogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGZpbHRlciA9ICJ0b3AiKQpgYGAKCjwvZGV0YWlscz4KCgoKCjxkZXRhaWxzPgo8c3VtbWFyeT4KPGgzPlJvYnVzdG5lc3MgY2hlY2tzPC9oMz4KPC9zdW1tYXJ5PgoKIyMjIyBDb21wYXJpbmcgc3BsaW5lIGFuZCBwb2x5bm9taWFsIG1vZGVscyBmb3IgaGV0ZXJvc2NlZGFzdGljaXR5CmBgYHtyfQojIEZvciBzY2FsZSBjb3JyZWxhdGlvbnMKbV9sbXN5bnRoX3Jfc2NhbGVzX3BvbHkgPC0gYnJtKAogIGJmKGVtcGlyaWNhbF9yIHwgbWkoZW1waXJpY2FsX3Jfc2UpIH4gc3ludGhldGljX3IgKyAoMXxtbShzY2FsZV9hLCBzY2FsZV9iKSksCiAgICAgc2lnbWEgfiBwb2x5KHN5bnRoZXRpY19yLCBkZWdyZWUgPSAzKSksIGRhdGEgPSBtYW5pZmVzdF9zY29yZXMsIAogIGZpbGUgPSAiaWdub3JlL21fc3ludGhfcnJfcl9zY2FsZXNfbG1fcG9seSIpCgpuZXdkYXRhIDwtIG1fbG1zeW50aF9yX3NjYWxlc19wb2x5JGRhdGEgJT4lIHNlbGVjdChlbXBpcmljYWxfciwgc3ludGhldGljX3IsIGVtcGlyaWNhbF9yX3NlKQplcHJlZHMgPC0gZXByZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IG1fbG1zeW50aF9yX3NjYWxlc19wb2x5LCByZV9mb3JtdWxhID0gTkEpCnByZWRzIDwtIHByZWRpY3RlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gbV9sbXN5bnRoX3Jfc2NhbGVzX3BvbHksIHJlX2Zvcm11bGEgPSBOQSkKZXByZWRfcHJlZHMgPC0gZXByZWRzICU+JSBsZWZ0X2pvaW4ocHJlZHMpCmJ5X2RyYXcgPC0gZXByZWRfcHJlZHMgJT4lIGdyb3VwX2J5KC5kcmF3KSAlPiUgCiAgc3VtbWFyaXNlKC5lcHJlZCA9IHZhciguZXByZWQpLAogICAgICAgICAgICAucHJlZGljdGlvbiA9IHZhcigucHJlZGljdGlvbiksCiAgICAgICAgICAgIHNpZ21hID0gc3FydCgucHJlZGljdGlvbiAtIC5lcHJlZCksCiAgICAgICAgICAgIGxhdGVudF9yID0gc3FydCguZXByZWQvLnByZWRpY3Rpb24pKQoKYWNjdXJhY3lfYmF5ZXNfc2NhbGVzX3BvbHkgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKGxhdGVudF9yKQoKYmluZF9yb3dzKAogIGFjY3VyYWN5X2JheWVzX3NjYWxlcyAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAic3BsaW5lIiwga2luZCA9ICJsYXRlbnQgb3V0Y29tZSAoQmF5ZXNpYW4gRUlWKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBsYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlciksCiAgYWNjdXJhY3lfYmF5ZXNfc2NhbGVzX3BvbHkgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gInBvbHlub21pYWwiLCBraW5kID0gImxhdGVudCBvdXRjb21lIChCYXllc2lhbiBFSVYpIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGxhdGVudF9yLCBjb25mLmxvdyA9IC5sb3dlciwgY29uZi5oaWdoID0gLnVwcGVyKQopICU+JSAKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJDb21wYXJpbmcgc3BsaW5lIGFuZCBwb2x5bm9taWFsIG1vZGVscyBmb3Igc2NhbGUgY29ycmVsYXRpb25zIikKYGBgCgpgYGB7cn0KcGxvdF9wcmVkaWN0aW9uX2Vycm9yX3NjYWxlc19wb2x5IDwtIHBsb3QoY29uZGl0aW9uYWxfZWZmZWN0cyhtX2xtc3ludGhfcl9zY2FsZXNfcG9seSwgZHBhciA9ICJzaWdtYSIpLCBwbG90ID0gRilbWzFdXSArIAogIHRoZW1lX2J3KCkgKyAKICBnZW9tX3Ntb290aChzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiI2E0ODUwMCIsIGZpbGwgPSAiI0VEQzk1MSIpICsgCiAgeGxhYigiU3ludGhldGljIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJQcmVkaWN0aW9uIGVycm9yIChzaWdtYSkiKQpwbG90X3ByZWRpY3Rpb25fZXJyb3Jfc2NhbGVzX3BvbHkKYGBgCgoKIyMjIyBIb3cgZG9lcyBudW1iZXIgb2YgaXRlbXMgYWNyb3NzIHRoZSB0d28gc2NhbGVzIHJlbGF0ZSB0byBhY2N1cmFjeT8KCmBgYHtyfQpieV9pdGVtX251bWJlciA8LSBtYW5pZmVzdF9zY29yZXNfYWxsICU+JQogIG11dGF0ZShpdGVtcyA9IG51bWJlcl9vZl9pdGVtcy54ICsgbnVtYmVyX29mX2l0ZW1zLnkpICU+JQogIGdyb3VwX2J5KGl0ZW1zKSAlPiUKICBmaWx0ZXIobigpID4gMTApICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3QoZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yKSksIHB0X2NvciA9IGNvcihlbXBpcmljYWxfciwgcHRfc3ludGhldGljX3IpLCBwYWlyd2lzZV9uID0gbigpKSAKCmJ5X2l0ZW1fbnVtYmVyICU+JSAKICBnZ3Bsb3QoYWVzKGl0ZW1zLCBlc3RpbWF0ZSwgeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoKSkgKyAKICBnZW9tX3BvaW50cmFuZ2UoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJNYW5pZmVzdCBhY2N1cmFjeSAod2l0aCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCkiKSArCiAgeGxhYigiTnVtYmVyIG9mIGl0ZW1zIHN1bW1lZCBhY3Jvc3Mgc2NhbGVzIikKYGBgCgojIyMjIyBBdmVyYWdlcwpgYGB7cn0KcmVhbF9zY2FsZXMgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKG51bWJlcl9vZl9pdGVtcyA+PSAzKSAlPiUgCiAgc3VtbWFyaXNlKG1lZGlhbihudW1iZXJfb2ZfaXRlbXMpLAogICAgICAgICAgICBtZWFuKG51bWJlcl9vZl9pdGVtcykpCmBgYAoKCiMjIyMjIEFjY3VyYWN5IGluY2x1ZGluZyAyLWl0ZW0gc2NhbGVzCgpgYGB7cn0Kcl8yaXRlbSA8LSBicm9vbTo6dGlkeShjb3IudGVzdChtYW5pZmVzdF9zY29yZXNfYWxsJGVtcGlyaWNhbF9yLCBtYW5pZmVzdF9zY29yZXNfYWxsJHN5bnRoZXRpY19yKSkKcHRfcl8yaXRlbSA8LSBicm9vbTo6dGlkeShjb3IudGVzdChwdF9tYW5pZmVzdF9zY29yZXNfYWxsJGVtcGlyaWNhbF9yLCBwdF9tYW5pZmVzdF9zY29yZXNfYWxsJHN5bnRoZXRpY19yKSkKCmJpbmRfcm93cygKICBwdF9yICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpICU+JSAKICAgIG11dGF0ZShpdGVtcyA9ICI+PSAzIiksCiAgciAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpICU+JSAKICAgIG11dGF0ZShpdGVtcyA9ICI+PSAzIiksCiAgcHRfcl8yaXRlbSAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAicHJlLXRyYWluZWQiLCBraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSAlPiUgCiAgICBtdXRhdGUoaXRlbXMgPSAiPj0gMiIpLAogIHJfMml0ZW0gJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSAlPiUgCiAgICBtdXRhdGUoaXRlbXMgPSAiPj0gMiIpLAogICkgJT4lIAogIGthYmxlKGRpZ2l0cyA9IDIsIGNhcHRpb24gPSAiQWNjdXJhY3kgYWNyb3NzIGxhbmd1YWdlIG1vZGVscyBhbmQgbWV0aG9kcyIpCmBgYAoKCmBgYHtyfQpicm9vbTo6dGlkeShsbShlc3RpbWF0ZSB+IGl0ZW1zLCBieV9pdGVtX251bWJlciwgd2VpZ2h0cyA9IDEvKGJ5X2l0ZW1fbnVtYmVyJGNvbmYuaGlnaC1ieV9pdGVtX251bWJlciRjb25mLmxvdykpKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJBY2N1cmFjeSBpbmNyZWFzZSB3aXRoIG51bWJlciBvZiBpdGVtcyIpCmBgYAoKYGBge3J9Cm1hbmlmZXN0X3Njb3JlcyAlPiUKICBmaWx0ZXIobnVtYmVyX29mX2l0ZW1zLnggPj0gNSwgbnVtYmVyX29mX2l0ZW1zLnkgPj0gNSkgJT4lCiAgc3VtbWFyaXNlKGNvciA9IGNvcihlbXBpcmljYWxfciwgc3ludGhldGljX3IpLCBuKCkpICU+JSAKICBrYWJsZShkaWdpdHMgPSAyLCBjYXB0aW9uID0gIkFjY3VyYWN5IHdoZW4gYm90aCBzY2FsZXMgaGF2ZSBhdCBsZWFzdCA1IGl0ZW1zIikKYGBgCgpgYGB7cn0KbWFuaWZlc3Rfc2NvcmVzICU+JQogIGZpbHRlcihudW1iZXJfb2ZfaXRlbXMueCA+PSAxMCwgbnVtYmVyX29mX2l0ZW1zLnkgPj0gMTApICU+JQogIHN1bW1hcmlzZShjb3IgPSBjb3IoZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yKSwgbigpKSAlPiUgCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJBY2N1cmFjeSB3aGVuIGJvdGggc2NhbGVzIGhhdmUgYXQgbGVhc3QgMTAgaXRlbXMiKQpgYGAKCgpJcyB0aGUgYWNjdXJhY3kgbG93ZXIgZm9yIHRoZSBwcmUtdHJhaW5lZCBtb2RlbD8KCmBgYHtyfQpnZ3Bsb3QocHRfbWFuaWZlc3Rfc2NvcmVzLCBhZXMoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yLCAKICAgICAgICAgICAgICB5bWluID0gZW1waXJpY2FsX3IgLSBlbXBpcmljYWxfcl9zZSwKICAgICAgICAgICAgICB5bWF4ID0gZW1waXJpY2FsX3IgKyBlbXBpcmljYWxfcl9zZSkpICsgCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC4xLCBzaXplID0gMSkgKwogIHhsYWIoIlN5bnRoZXRpYyBpbnRlci1zY2FsZSBjb3JyZWxhdGlvbiIpICsgCiAgeWxhYigiRW1waXJpY2FsIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xLDEpLCB5bGltID0gYygtMSwxKSkgLT4gcHRfcGxvdF9zY2FsZXMKcHRfcGxvdF9zY2FsZXMKYGBgCgoKPC9kZXRhaWxzPgoKCgoKIyMgQ29tYmluZWQgcGxvdHMKCiMjIyBBY2N1cmFjeSBzY2F0dGVycGxvdHMKCmBgYHtyIGZpZy53aWR0aCA9IDguMywgZmlnLmhlaWdodCA9IDZ9CmxpYnJhcnkocGF0Y2h3b3JrKQpwdF9wbG90X2l0ZW1zMiA8LSBwdF9wbG90X2l0ZW1zICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAzLCB4ID0gLTEsIHkgPSAwLjk4LCB2anVzdCA9IDAsIGhqdXN0ID0gMCwgbGFiZWwgPSB3aXRoKHB0X2FjY3VyYWN5X2JheWVzX2l0ZW1zLCB7IHNwcmludGYoImFjY3VyYWN5ID0gJS4yZiBbJS4yZjslLjJmXSIsIGxhdGVudF9yLCAubG93ZXIsIC51cHBlcikgfSkpICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtLjEsIHkgPSAwLjUsIHZqdXN0ID0gMSwgaGp1c3QgPSAxLCBsYWJlbCA9ICJyKENFU0RfMTAsMTkpIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjEsIHkgPSAwLjUsIHhlbmQgPSAwLjQxODU3NjMsIHllbmQgPSAwLjU4NzU3OTYsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykgKwogIAogIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDIuNSwgeCA9IDAsIHkgPSAtMC45LCBoanVzdCA9IDAuNSwgbGFiZWwgPSAicihSQUFTXzAyLDA1KSIsIGNvbG9yID0gIiMwMEEwQjAiKSArIAogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDAsIHkgPSAtMC44MywgeGVuZCA9IDAuNTg0MjYwNiwgeWVuZCA9IC0wLjcwMjA4OTUsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykKICAKcGxvdF9pdGVtczIgPC0gcGxvdF9pdGVtcyArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMywgeCA9IC0xLCB5ID0gMC45OCwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChhY2N1cmFjeV9iYXllc19pdGVtcywgeyBzcHJpbnRmKCJhY2N1cmFjeSA9ICUuMmYgWyUuMmY7JS4yZl0iLCBsYXRlbnRfciwgLmxvd2VyLCAudXBwZXIpIH0pKSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLS4xLCB5ID0gMC41LCB2anVzdCA9IDEsIGhqdXN0ID0gMSwgbGFiZWwgPSAicihDRVNEXzEwLDE5KSIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gLS4xLCB5ID0gMC41LCB4ZW5kID0gMC41MzY5MDcxLCB5ZW5kID0gMC41ODc1Nzk2LCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpICsKICAKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAwLCB5ID0gLTAuOSwgaGp1c3QgPSAwLjUsIGxhYmVsID0gInIoUkFBU18wMiwwNSkiLCBjb2xvciA9ICIjMDBBMEIwIikgKyAKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLCB5ID0gLTAuODMsIHhlbmQgPSAwLjA5MjE4NTczLCB5ZW5kID0gLTAuNzAyMDg5NSwgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KQoKcHRfcGxvdF9yZWxzMiA8LSBwdF9wbG90X3JlbHMgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAzLCB4ID0gLTEsIHkgPSAuOTgsIHZqdXN0ID0gMCwgaGp1c3QgPSAwLCBsYWJlbCA9IHdpdGgocHRfYWNjdXJhY3lfYmF5ZXNfcmVscywgeyBzcHJpbnRmKCJhY2N1cmFjeSA9ICUuMmYgWyUuMmY7JS4yZl0iLCBsYXRlbnRfciwgLmxvd2VyLCAudXBwZXIpIH0pKSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCAgeCA9IDAuNjgsIHkgPSAwLCBoanVzdCA9IDAuNSwgbGFiZWwgPSAiRmVhciBvZiBDT1ZJRCIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCAgeCA9IDAuNjgsIHkgPSAwLjA1LCB4ZW5kID0gMC45NTYzMTkyLCB5ZW5kID0gMC45MjYyNTQyLCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpICsKICAKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtMSwgeSA9IDAuNSwgaGp1c3QgPSAwLCBsYWJlbCA9ICJIRVhBQ08gZmFpcm5lc3MiLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IC0wLjY1LCB5ID0gMC41NSwgIHhlbmQgPSAtMC4zMjYyNzU5LCB5ZW5kID0gMC44MjE3NDc1LCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpCgoKZ2V0X3NjYWxlX3BvaW50IDwtIGZ1bmN0aW9uKGRhdGEsIHN5bnRoZXRpY19hcHByb3gsIGVtcGlyaWNhbF9hcHByb3gpIHsKICBkYXRhICU+JQogICAgdW5ncm91cCgpICU+JSAKICAgICMgRmluZCBjbG9zZXN0IHBvaW50IHRvIHRhcmdldCBjb29yZGluYXRlcwogICAgbXV0YXRlKGRpc3QgPSBzcXJ0KChzeW50aGV0aWNfYWxwaGEgLSBzeW50aGV0aWNfYXBwcm94KV4yICsgCiAgICAgICAgICAgICAgICAgICAgICAoZW1waXJpY2FsX2FscGhhIC0gZW1waXJpY2FsX2FwcHJveCleMikpICU+JQogICAgYXJyYW5nZShkaXN0KSAlPiUKICAgIHNsaWNlKDEpICU+JQogICAgc2VsZWN0KHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhKQp9CnAxIDwtIGdldF9zY2FsZV9wb2ludChzY2FsZXMsIDAuMzAsIDAuMjIpCnAyIDwtIGdldF9zY2FsZV9wb2ludChzY2FsZXMsIDAuMTIsIC0wLjM2KSAKcDMgPC0gZ2V0X3NjYWxlX3BvaW50KHNjYWxlcywgLTAuNCwgLTAuOTApCgpwbG90X3JlbHMyIDwtIHBsb3RfcmVscyArIAogIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDMsIHggPSAtMSwgeSA9IC45OCwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChhY2N1cmFjeV9iYXllc19yZWxzLCB7IHNwcmludGYoImFjY3VyYWN5ID0gJS4yZiBbJS4yZjslLjJmXSIsIGxhdGVudF9yLCAubG93ZXIsIC51cHBlcikgfSkpICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtMC4yLCB5ID0gLTAuOSwgaGp1c3QgPSAwLCBsYWJlbCA9ICJyYW5kb21seSBmb3JtZWQgc2NhbGVzIiwgY29sb3IgPSAiIzZBNEEzQyIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLjQsIHkgPSAtMC44NSwgeGVuZCA9IHAxJHN5bnRoZXRpY19hbHBoYSwgeWVuZCA9IHAxJGVtcGlyaWNhbF9hbHBoYSwgY29sb3IgPSAiIzZBNEEzQyIsIGFscGhhID0gMC43KSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMC40LCB5ID0gLTAuODUsIHhlbmQgPSBwMiRzeW50aGV0aWNfYWxwaGEsIHllbmQgPSBwMiRlbXBpcmljYWxfYWxwaGEsIGNvbG9yID0gIiM2QTRBM0MiLCBhbHBoYSA9IDAuNykgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDAuNCwgeSA9IC0wLjg1LCB4ZW5kID0gcDMkc3ludGhldGljX2FscGhhLCB5ZW5kID0gcDMkZW1waXJpY2FsX2FscGhhLCBjb2xvciA9ICIjNkE0QTNDIiwgYWxwaGEgPSAwLjcpICsKICAKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAwLjY4LCB5ID0gMCwgaGp1c3QgPSAwLjUsIGxhYmVsID0gIkZlYXIgb2YgQ09WSUQiLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDAuNjgsIHkgPSAwLjA1LCB4ZW5kID0gMC44ODY0MDI0LCB5ZW5kID0gMC45MjYyNTQyLCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpICsKICAKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtMSwgeSA9IDAuNSwgaGp1c3QgPSAwLGxhYmVsID0gIkhFWEFDTyBmYWlybmVzcyIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gLTAuNjUsIHkgPSAwLjU1LCB4ZW5kID0gMC4wMzA1NTUzLCB5ZW5kID0gMC44MjE3NDc1LCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpCgoKcHRfcGxvdF9zY2FsZXMyIDwtIHB0X3Bsb3Rfc2NhbGVzICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAzLCB4ID0gLTEsIHkgPSAwLjk4LCB2anVzdCA9IDAsIGhqdXN0ID0gMCwgbGFiZWwgPSB3aXRoKHB0X2FjY3VyYWN5X2JheWVzX3NjYWxlcywgeyBzcHJpbnRmKCJhY2N1cmFjeSA9ICUuMmYgWyUuMmY7JS4yZl0iLCBsYXRlbnRfciwgLmxvd2VyLCAudXBwZXIpIH0pKSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLTAuNCwgeSA9IDAuNSwgaGp1c3QgPSAxLCBsYWJlbCA9ICJyKFVXRVMgdmlnb3IsXG5XR1MpIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjM4LCB5ID0gMC40NSwgeGVuZCA9IDAuNjU4NjQwMiwgeWVuZCA9IDAuNTY4MzE2NywgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KSArCiAgCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLS4xLCB5ID0gLTAuOSwgaGp1c3QgPSAwLjUsIGxhYmVsID0gInIoQ0VTLUQgd2VsbC1iZWluZyxcbkNFUy1EIGRlcHJlc3NpdmUgYWZmZWN0KSIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gLTAuMiwgeSA9IC0uNzUsIHhlbmQgPSAwLjQ5NjMzOTIsIHllbmQgPSAtMC43NTgzNjM3LCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpCgoKcGxvdF9zY2FsZXMyIDwtIHBsb3Rfc2NhbGVzICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAzLCB4ID0gLTEsIHkgPSAwLjk4LCB2anVzdCA9IDAsIGhqdXN0ID0gMCwgbGFiZWwgPSB3aXRoKGFjY3VyYWN5X2JheWVzX3NjYWxlcywgeyBzcHJpbnRmKCJhY2N1cmFjeSA9ICUuMmYgWyUuMmY7JS4yZl0iLCBsYXRlbnRfciwgLmxvd2VyLCAudXBwZXIpIH0pKSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLTAuNCwgeSA9IDAuNSwgaGp1c3QgPSAxLCBsYWJlbCA9ICJyKFVXRVMgdmlnb3IsXG5XR1MpIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjM4LCB5ID0gMC40NSwgeGVuZCA9IC41NSwgeWVuZCA9IDAuNTY4MzE2NywgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KSArCiAgCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLS4xLCB5ID0gLTAuOSwgaGp1c3QgPSAwLjUsIGxhYmVsID0gInIoQ0VTLUQgd2VsbC1iZWluZyxcbkNFUy1EIGRlcHJlc3NpdmUgYWZmZWN0KSIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gLTAuMiwgeSA9IC0uNzUsIHhlbmQgPSAwLjAyLCB5ZW5kID0gLTAuNzU4MzYzNywgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KQoKCihwdF9wbG90X2l0ZW1zMiArIGdndGl0bGUoIlByZS10cmFpbmVkIG1vZGVsIGJlZm9yZSBkb21haW4gYWRhcHRhdGlvbiBhbmQgZmluZS10dW5pbmciKSArCiAgICBwdF9wbG90X3JlbHMyICsKICAgIHB0X3Bsb3Rfc2NhbGVzMikgLwoKCihwbG90X2l0ZW1zMiArIGdndGl0bGUoIlN1cnZleUJvdCAzMDAwIikgKwogICAgcGxvdF9yZWxzMiAgKwogICAgcGxvdF9zY2FsZXMyKQoKZ2dzYXZlKCJGaWd1cmVfcnIucGRmIiwgd2lkdGggPSA4LjMsIGhlaWdodCA9IDYsIGRldmljZSA9IGdyRGV2aWNlczo6Y2Fpcm9fcGRmKQpnZ3NhdmUoIkZpZ3VyZV9yci5wbmciLCB3aWR0aCA9IDguMywgaGVpZ2h0ID0gNikKYGBgCgojIyMgUHJlZGljdGlvbiBlcnJvciBwbG90cwpgYGB7ciBmaWcud2lkdGggPSA4LjMsIGZpZy5oZWlnaHQgPSAzfQpsaWJyYXJ5KHBhdGNod29yaykKCihwbG90X3ByZWRpY3Rpb25fZXJyb3JfaXRlbXMgKyAKICAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMSwgMSksIHlsaW0gPSBjKDAsIDAuNCkpICsKICAgIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDMsIHggPSAtMSwgeSA9IDAuNCwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChybXNlX2l0ZW1zLCB7IHNwcmludGYoIlJNU0UgPSAlLjJmIFslLjJmOyUuMmZdIiwgc2lnbWEsIC5sb3dlciwgLnVwcGVyKSB9KSkgKwogICAgCiAgICBwbG90X3ByZWRpY3Rpb25fZXJyb3JfYWxwaGEgKyAKICAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMSwgMSksIHlsaW0gPSBjKDAsIDAuNCkpICArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAzLCB4ID0gLTEsIHkgPSAwLjQsIHZqdXN0ID0gMCwgaGp1c3QgPSAwLCBsYWJlbCA9IHdpdGgocm1zZV9hbHBoYSwgeyBzcHJpbnRmKCJSTVNFID0gJS4yZiBbJS4yZjslLjJmXSIsIHNpZ21hLCAubG93ZXIsIC51cHBlcikgfSkpICsKICAgIAogICAgcGxvdF9wcmVkaWN0aW9uX2Vycm9yX3NjYWxlcyArIAogICAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC0xLCAxKSwgeWxpbSA9IGMoMCwgMC40KSkgKwogICAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMywgeCA9IC0xLCB5ID0gMC40LCB2anVzdCA9IDAsIGhqdXN0ID0gMCwgbGFiZWwgPSB3aXRoKHJtc2Vfc2NhbGVzLCB7IHNwcmludGYoIlJNU0UgPSAlLjJmIFslLjJmOyUuMmZdIiwgc2lnbWEsIC5sb3dlciwgLnVwcGVyKSB9KSkKKQoKZ2dzYXZlKCJpZ25vcmUvRmlndXJlX3ByZWRpY3Rpb25fZXJyb3JfcnIucGRmIiwgd2lkdGggPSA4LjMsIGhlaWdodCA9IDMsIGRldmljZSA9IGdyRGV2aWNlczo6Y2Fpcm9fcGRmKQpnZ3NhdmUoImlnbm9yZS9GaWd1cmVfcHJlZGljdGlvbl9lcnJvcl9yci5wbmciLCB3aWR0aCA9IDguMywgaGVpZ2h0ID0gMykKYGBgCgoKCg==