Here, we apply the pre-trained model and our fine-tuned model to data not used for training, a holdout. The holdout sample was collected by Bainbridge et al. 2022.

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 = "on_change")


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

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

set.seed(42)


holdout <- arrow::read_feather(file = file.path(data_path, glue("ignore.{model_name}.raw.osf-bainbridge-2021-s2-0.item_correlations.feather")))

pt_holdout <- arrow::read_feather(file = file.path(data_path, glue("ignore.{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.item_correlations.feather")))

holdout_mapping_data = arrow::read_feather(
  file = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.mapping2.feather"))
) %>%
  rename(scale_0 = scale0,
         scale_1 = scale1)

holdout_human_data = arrow::read_feather(
  file = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.human.feather"))
)

holdout_scales <- arrow::read_feather(file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.scales.feather"))
)

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

The Bainbridge data was collected on N=493 respondents. The item with the most missing values still had n=480.

Synthetic inter-item correlations

holdout_llm <- holdout %>%
  left_join(holdout_mapping_data %>% select(variable_1 = variable, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1)) %>%
  left_join(holdout_mapping_data %>% select(variable_2 = variable, InstrumentB = instrument, ScaleB = scale_0, SubscaleB = scale_1))

pt_holdout_llm <- pt_holdout %>%
  left_join(holdout_mapping_data %>% select(variable_1 = variable, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1)) %>%
  left_join(holdout_mapping_data %>% select(variable_2 = variable, InstrumentB = instrument, ScaleB = scale_0, SubscaleB = scale_1))

Accuracy

se2 <- mean(holdout_llm$empirical_r_se^2)

r <- broom::tidy(cor.test(holdout_llm$empirical_r, holdout_llm$synthetic_r))
pt_r <- broom::tidy(cor.test(pt_holdout_llm$empirical_r, pt_holdout_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 = holdout_llm)
pt_fit <- sem(model, data = pt_holdout_llm)

m_synth_r_items <- brm(
  bf(empirical_r | mi(empirical_r_se) ~ synthetic_r + (1|mm(variable_1, variable_2)),
     sigma ~ poly(synthetic_r, degree = 3)), data = holdout_llm, 
  file = "ignore/m_synth_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(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            semi_latent_r = sqrt(.epred/.prediction))
rm(epred_preds)

accuracy_bayes_items <- by_draw %>% mean_hdci(semi_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 = "semi-latent (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.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 = "semi-latent (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  accuracy_bayes_items %>% 
    mutate(model = "fine-tuned", kind = "semi-latent (Bayesian EIV)") %>% 
    select(model, kind, accuracy = semi_latent_r, conf.low = .lower, conf.high = .upper)
  ) %>% 
  knitr::kable(digits = 2)
model kind accuracy conf.low conf.high
pre-trained manifest 0.19 0.18 0.19
pre-trained semi-latent (SEM) 0.19 0.19 0.20
fine-tuned manifest 0.67 0.67 0.68
fine-tuned semi-latent (SEM) 0.70 0.70 0.70
fine-tuned semi-latent (Bayesian EIV) 0.71 0.71 0.72

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 ~ poly(synthetic_r, degree = 3)
##    Data: holdout_llm (Number of observations: 87153) 
##   Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup draws = 4000
## 
## Group-Level Effects: 
## ~mmvariable_1variable_2 (Number of levels: 418) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.03      0.00     0.03     0.03 1.00     1359     2164
## 
## Population-Level Effects: 
##                                 Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                          -0.01      0.00    -0.01    -0.00 1.00
## sigma_Intercept                    -2.20      0.00    -2.21    -2.20 1.00
## synthetic_r                         0.79      0.00     0.78     0.80 1.00
## sigma_polysynthetic_rdegreeEQ31    19.57      0.97    17.69    21.46 1.00
## sigma_polysynthetic_rdegreeEQ32    -0.50      0.81    -2.07     1.04 1.00
## sigma_polysynthetic_rdegreeEQ33    -4.86      0.79    -6.40    -3.32 1.00
##                                 Bulk_ESS Tail_ESS
## Intercept                           1175     1946
## sigma_Intercept                     4604     3177
## synthetic_r                         5015     2985
## sigma_polysynthetic_rdegreeEQ31     4931     3401
## sigma_polysynthetic_rdegreeEQ32     6335     3209
## sigma_polysynthetic_rdegreeEQ33     6573     3101
## 
## 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")
by_draw %>% mean_hdci(sigma)
## # A tibble: 1 × 6
##   sigma .lower .upper .width .point .interval
##   <dbl>  <dbl>  <dbl>  <dbl> <chr>  <chr>    
## 1 0.111  0.110  0.113   0.95 mean   hdci
plot(conditional_effects(m_synth_r_items, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  ylab("Prediction error (sigma)")

Scatter plot

ggplot(holdout_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.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-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 <- holdout_llm %>% 
   left_join(holdout_mapping_data %>% select(variable_1 = variable,
                                             item_text_1 = item_text)) %>% 
   left_join(holdout_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_holdout_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.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 <- 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.xlsx")

Robustness checks

Is the accuracy lower within/across scales and instruments?

holdout_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()) %>% 
  select(same_instrument, same_scale, same_subscale, r = estimate, conf.low, conf.high, n, sd_emp_r) %>% 
  arrange(same_instrument, same_scale, same_subscale) %>% 
  kable()
same_instrument same_scale same_subscale r conf.low conf.high n sd_emp_r
0 0 0 0.6525977 0.6484796 0.6566776 75364 0.1537790
0 1 0 0.8269917 0.8095247 0.8429959 1376 0.2801202
0 1 1 0.8269181 0.7293619 0.8915144 64 0.4934840
1 0 0 0.6005392 0.5855629 0.6151056 7200 0.1365890
1 1 0 0.7571886 0.7404990 0.7729447 2662 0.2582187
1 1 1 0.8372433 0.8085383 0.8619731 487 0.3847884

Is the accuracy lower outside classic Big Five?

holdout_llm %>% 
  mutate(big_five = case_when(
    str_detect(InstrumentA, "(Personality|Big Five)") & str_detect(InstrumentB, "(Personality|Big Five)") ~ "both",
    str_detect(InstrumentA, "(Personality|Big Five)") | str_detect(InstrumentB, "(Personality|Big Five)") ~ "either",
    TRUE ~ "none"
         )) %>% 
  group_by(big_five) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), sd_emp_r = sd(empirical_r), n = n()) %>% 
  select(big_five, r = estimate, conf.low, conf.high, n, sd_emp_r) %>% 
  arrange(big_five) %>% 
  kable()
big_five r conf.low conf.high n sd_emp_r
both 0.7105135 0.7027822 0.7180770 16110 0.1754473
either 0.6618969 0.6565425 0.6671846 42840 0.1525947
none 0.6653591 0.6588041 0.6718132 28203 0.1697589

Is the accuracy lower for items that have low variance?

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

by_max_cov <- holdout_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%>% 
  kable()
max_covariance r conf.low conf.high n sd_emp_r
0.5 0.8845860 0.6925673 0.9595392 16 0.0841287
0.6 0.5394056 0.4566420 0.6129128 319 0.1712504
0.7 0.5773367 0.5485306 0.6047739 2162 0.1591129
0.8 0.6331256 0.6192313 0.6466235 7355 0.1524384
0.9 0.6439129 0.6346448 0.6529958 15639 0.1496275
1.0 0.6333785 0.6255374 0.6410916 22779 0.1536605
1.1 0.6791602 0.6718518 0.6863364 21261 0.1657358
1.2 0.7290679 0.7206660 0.7372557 12257 0.1799820
1.3 0.7435976 0.7298785 0.7567179 4268 0.1774902
1.4 0.7194644 0.6869514 0.7491027 930 0.1587180
1.5 0.7077049 0.6188080 0.7787043 154 0.1447413
1.6 0.8896940 0.6452603 0.9688857 12 0.1835193
rs_by_max_cov %>% ggplot(aes(max_covariance, r, ymin = conf.low, ymax = conf.high)) +
  geom_pointrange()

by_max_cov%>% 
  filter(max_covariance > .7) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), sd_emp_r = sd(empirical_r), n = n()) %>% 
  kable()
estimate statistic p.value parameter conf.low conf.high method alternative sd_emp_r n
0.6758603 266.806 0 84654 0.6721843 0.6795029 Pearson’s product-moment correlation two.sided 0.1624048 84656
holdout_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) %>% 
  filter(max_covariance > 1) %>% 
  summarise(broom::tidy(cor.test(synthetic_r, empirical_r)), sd_emp_r = sd(empirical_r), n = n()) %>% 
  select(r = estimate, conf.low, conf.high, n, sd_emp_r) %>% 
  knitr::kable()
r conf.low conf.high n sd_emp_r
0.7085118 0.7035267 0.7134273 38883 0.1726419

Is the accuracy lower for the pre-trained model?

ggplot(pt_holdout_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.1, 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

Full table of synthetic and empirical item pair correlations

Synthetic Reliabilities

cors_llm <- holdout_llm %>%
  select(x = variable_1, y = variable_2, r = synthetic_r) %>%
  as.data.frame() |>
  igraph::graph_from_data_frame(directed = FALSE) |>
  igraph::as_adjacency_matrix(attr = "r", sparse = FALSE)
diag(cors_llm) <- 1

pt_cors_llm <- pt_holdout_llm %>%
  select(x = variable_1, y = variable_2, r = synthetic_r) %>%
  as.data.frame() |>
  igraph::graph_from_data_frame(directed = FALSE) |>
  igraph::as_adjacency_matrix(attr = "r", sparse = FALSE)
diag(pt_cors_llm) <- 1

cors_real <- holdout_llm %>%
  select(x = variable_1, y = variable_2, r = empirical_r) %>%
  as.data.frame() |>
  igraph::graph_from_data_frame(directed = FALSE) |>
  igraph::as_adjacency_matrix(attr = "r", sparse = FALSE)
diag(cors_real) <- 1

mapping_data <- holdout_mapping_data
items_by_scale <- bind_rows(
  holdout_scales %>% filter(scale_1 == "") %>% left_join(mapping_data %>% select(-scale_1), by = c("instrument", "scale_0")),
  holdout_scales %>% filter(scale_1 != "") %>% left_join(mapping_data, by = c("instrument", "scale_0", "scale_1"))
)
  
scales <- items_by_scale %>%
  group_by(keyed, scale) %>%
  summarise(
    items = list(variable),
    number_of_items = n_distinct(variable),
    lvn = paste(first(scale), " =~ ", paste(variable, collapse = " + "))) %>%
  drop_na() %>% 
  ungroup()


random_scales <- list()
for(i in 1:200) {
  n_items <- rpois(1, mean(scales$number_of_items))
  n_items <- if_else(n_items < 3, 3, n_items)
  random_scales[[i]] <- holdout_mapping_data %>%
    sample_n(n_items) %>%
    mutate(scale = paste0("random", i)) %>%
    group_by(scale) %>%
    summarise(
      items = list(variable),
      number_of_items = n_distinct(variable),
      lvn = paste(first(scale), " =~ ", paste(variable, collapse = " + "))) %>%
    drop_na() %>% 
    mutate(keyed = 1)
}

random_scales <- bind_rows(random_scales)
scales <- bind_rows(scales, random_scales)

source("global_functions.R")

scales <- scales %>% filter(number_of_items >= 3)

scales <- scales %>%
  rowwise() %>%
  mutate(r_real = list(cors_real[items, items]),
         pt_r_llm = list(pt_cors_llm[items, items]),
         r_llm = list(cors_llm[items, items])) %>%
  mutate(reverse_items = list(find_reverse_items_by_first_item(r_real, keyed)),
         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))))
  )

scales <- scales %>% filter(empirical_alpha > 0)
# qplot(scales$empirical_alpha_se)
# qplot(scales$empirical_alpha, scales$empirical_alpha_se)
# qplot(scales$number_of_items, scales$empirical_alpha_se)
# qplot(scales$empirical_alpha, scales$empirical_alpha_se, color = scales$number_of_items)

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))

m_lmsynth_rel_scales <- brm(
  bf(empirical_alpha | mi(empirical_alpha_se) ~ synthetic_alpha,
     sigma ~ poly(synthetic_alpha, degree = 3)), data = scales, 
  file = "ignore/m_synth_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(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            semi_latent_r = sqrt(.epred/.prediction))

accuracy_bayes_rels <- by_draw %>% mean_hdci(semi_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 = "semi-latent (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.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 = "semi-latent (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  accuracy_bayes_rels %>% 
    mutate(model = "fine-tuned", kind = "semi-latent (Bayesian EIV)") %>% 
    select(model, kind, accuracy = semi_latent_r, conf.low = .lower, conf.high = .upper)
  ) %>% 
  knitr::kable(digits = 2)
model kind accuracy conf.low conf.high
pre-trained manifest 0.07 -0.04 0.18
pre-trained semi-latent (SEM) 0.08 -0.04 0.19
fine-tuned manifest 0.82 0.78 0.85
fine-tuned semi-latent (SEM) 0.87 0.83 0.90
fine-tuned semi-latent (Bayesian EIV) 0.86 0.75 0.95

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 ~ poly(synthetic_alpha, degree = 3)
##    Data: scales (Number of observations: 303) 
##   Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup draws = 4000
## 
## Population-Level Effects: 
##                                     Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                               0.25      0.01     0.22     0.28 1.00
## sigma_Intercept                        -2.35      0.06    -2.46    -2.24 1.00
## synthetic_alpha                         0.72      0.02     0.68     0.76 1.00
## sigma_polysynthetic_alphadegreeEQ31    -5.91      0.99    -7.78    -3.96 1.00
## sigma_polysynthetic_alphadegreeEQ32    -1.34      0.92    -3.09     0.53 1.00
## sigma_polysynthetic_alphadegreeEQ33    -2.81      0.83    -4.49    -1.24 1.00
##                                     Bulk_ESS Tail_ESS
## Intercept                               3860     3274
## sigma_Intercept                         2954     2904
## synthetic_alpha                         4019     3282
## sigma_polysynthetic_alphadegreeEQ31     3005     2850
## sigma_polysynthetic_alphadegreeEQ32     3919     3374
## sigma_polysynthetic_alphadegreeEQ33     4274     3355
## 
## 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_lmsynth_rel_scales, method = "predict")
by_draw %>% 
  filter(!is.nan(sigma)) %>% mean_hdci(sigma)
## # A tibble: 1 × 6
##   sigma .lower .upper .width .point .interval
##   <dbl>  <dbl>  <dbl>  <dbl> <chr>  <chr>    
## 1 0.116 0.0657  0.174   0.95 mean   hdci
plot(conditional_effects(m_lmsynth_rel_scales, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  scale_x_continuous(limits = c(0,1))+
  scale_y_continuous(limits = c(0,0.13)) +
  ylab("Prediction error (sigma)")

Scatter plot

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(0,1), ylim = c(0,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(NA,1), ylim = c(NA,1))) %>% 
  ggplotly()

Table

scales %>% 
  filter(!str_detect(scale, "^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

scales %>% 
  group_by(str_detect(scale, "^random")) %>% 
  summarise(broom::tidy(cor.test(synthetic_alpha, empirical_alpha)), sd_alpha = sd(empirical_alpha), n = n()) %>% 
  knitr::kable()
str_detect(scale, “^random”) estimate statistic p.value parameter conf.low conf.high method alternative sd_alpha n
FALSE 0.6317914 8.351973 0 105 0.5021686 0.7336481 Pearson’s product-moment correlation two.sided 0.0992460 107
TRUE 0.6932367 13.397440 0 194 0.6126040 0.7595885 Pearson’s product-moment correlation two.sided 0.1594832 196

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()
estimate statistic p.value parameter conf.low conf.high method alternative sd_alpha n
0.2366839 4.226398 3.15e-05 301 0.1274036 0.3402868 Pearson’s product-moment correlation two.sided 0.2276686 303
summary(lm(empirical_alpha ~ number_of_items, scales))
## 
## Call:
## lm(formula = empirical_alpha ~ number_of_items, data = scales)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.47673 -0.16576 -0.01129  0.20063  0.45562 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     0.415447   0.025891  16.046  < 2e-16 ***
## number_of_items 0.014174   0.003354   4.226 3.15e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2216 on 301 degrees of freedom
## Multiple R-squared:  0.05602,    Adjusted R-squared:  0.05288 
## F-statistic: 17.86 on 1 and 301 DF,  p-value: 3.152e-05
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.39508 -0.07434 -0.00318  0.07120  0.76137 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     0.232096   0.017121  13.556   <2e-16 ***
## number_of_items 0.002904   0.002036   1.427    0.155    
## synthetic_alpha 0.671944   0.028294  23.749   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1308 on 300 degrees of freedom
## Multiple R-squared:  0.6722, Adjusted R-squared:   0.67 
## F-statistic: 307.6 on 2 and 300 DF,  p-value: < 2.2e-16

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(0,1), ylim = c(0,1)) -> pt_plot_rels
pt_plot_rels

Synthetic Scale Correlations

manifest_scores = arrow::read_feather(file = file.path(data_path, glue("ignore.{model_name}.raw.osf-bainbridge-2021-s2-0.scale_correlations.feather")))
pt_manifest_scores = arrow::read_feather(file = file.path(data_path, glue("ignore.{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.scale_correlations.feather")))

n_distinct(manifest_scores$scale_a)
## [1] 112
manifest_scores <- manifest_scores %>%
 left_join(scales, by = c("scale_a" = "scale")) %>%
 left_join(scales, by = c("scale_b" = "scale"))

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)


m_lmsynth_r_scales <- 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_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(.epred = var(.epred),
            .prediction = var(.prediction),
            sigma = sqrt(.prediction - .epred),
            semi_latent_r = sqrt(.epred/.prediction))

accuracy_bayes_scales <- by_draw %>% mean_hdci(semi_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 = "semi-latent (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.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 = "semi-latent (SEM)") %>% 
    select(model, kind, accuracy = est.std, 
           conf.low = ci.lower, conf.high = ci.upper),
  accuracy_bayes_scales %>% 
    mutate(model = "fine-tuned", kind = "semi-latent (Bayesian EIV)") %>% 
    select(model, kind, accuracy = semi_latent_r, conf.low = .lower, conf.high = .upper)
  ) %>% 
  knitr::kable(digits = 2)
model kind accuracy conf.low conf.high
pre-trained manifest 0.33 0.30 0.35
pre-trained semi-latent (SEM) 0.33 0.31 0.35
fine-tuned manifest 0.87 0.86 0.87
fine-tuned semi-latent (SEM) 0.88 0.87 0.89
fine-tuned semi-latent (Bayesian EIV) 0.89 0.88 0.90

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 ~ poly(synthetic_r, degree = 3)
##    Data: manifest_scores (Number of observations: 6245) 
##   Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup draws = 4000
## 
## Group-Level Effects: 
## ~mmscale_ascale_b (Number of levels: 113) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.07      0.01     0.06     0.08 1.00     1342     2191
## 
## Population-Level Effects: 
##                                 Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                           0.01      0.01     0.00     0.03 1.01
## sigma_Intercept                    -2.15      0.01    -2.17    -2.13 1.00
## synthetic_r                         0.95      0.01     0.94     0.97 1.00
## sigma_polysynthetic_rdegreeEQ31    -0.06      1.04    -2.09     2.02 1.00
## sigma_polysynthetic_rdegreeEQ32    -6.00      0.85    -7.64    -4.29 1.00
## sigma_polysynthetic_rdegreeEQ33    -0.16      0.89    -1.87     1.58 1.00
##                                 Bulk_ESS Tail_ESS
## Intercept                            822     1443
## sigma_Intercept                     6041     2887
## synthetic_r                         6720     3387
## sigma_polysynthetic_rdegreeEQ31     3704     3465
## sigma_polysynthetic_rdegreeEQ32     5654     3555
## sigma_polysynthetic_rdegreeEQ33     5773     3703
## 
## 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).
by_draw %>% mean_hdci(sigma)
## # A tibble: 1 × 6
##   sigma .lower .upper .width .point .interval
##   <dbl>  <dbl>  <dbl>  <dbl> <chr>  <chr>    
## 1 0.118  0.111  0.124   0.95 mean   hdci
pred <- conditional_effects(m_lmsynth_r_scales, method = "predict")
plot(conditional_effects(m_lmsynth_r_scales, dpar = "sigma"), plot = F)[[1]] + 
  theme_bw() + 
  ylab("Prediction error (sigma)")

Scatter plot

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.3, 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

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

by_item_number <- manifest_scores %>%
  mutate(items = number_of_items.x + number_of_items.y) %>%
  group_by(items) %>%
  summarise(broom::tidy(cor.test(empirical_r, 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")

lm(estimate ~ items, by_item_number, weights = 1/(by_item_number$conf.high-by_item_number$conf.low))
## 
## Call:
## lm(formula = estimate ~ items, data = by_item_number, weights = 1/(by_item_number$conf.high - 
##     by_item_number$conf.low))
## 
## Coefficients:
## (Intercept)        items  
##    0.845728     0.002668
manifest_scores %>%
  filter(number_of_items.x >= 10, number_of_items.y >= 10) %>%
  summarise(cor = cor(empirical_r, synthetic_r), n())
## # A tibble: 1 × 2
##     cor `n()`
##   <dbl> <int>
## 1 0.926   300

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.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)) -> pt_plot_scales
pt_plot_scales

Combined plot

library(patchwork)
pt_plot_items2 <- pt_plot_items +
    annotate("text", size = 2.5, x = 0.5, y = -0.8, vjust = 1, hjust = 1, label = "r(I fear for the worst,\nI never worry about anything)", color = "#00A0B0") +
  annotate("segment", x = 0, y = -0.78, xend = 0.2761906, yend = -0.3459711, color = "#00A0B0", alpha = 0.7) +
  annotate("text", size = 2.5, x = -.1, y = 0.5, hjust = 1, label = "r(I get angry easily,\nI lose my temper)", color = "#00A0B0") + 
  annotate("segment", x = -.1, y = 0.5, xend = 0.6935711, yend = 0.7140546, 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]", semi_latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = 0.5, y = -0.8, vjust = 1, hjust = 1, label = "r(I fear for the worst,\nI never worry about anything)", color = "#00A0B0") +
  annotate("segment", x = 0, y = -0.78, xend = -0.1104686, yend = -0.3459711, color = "#00A0B0", alpha = 0.7) +
  annotate("text", size = 2.5, x = -.1, y = 0.5, hjust = 1, label = "r(I get angry easily,\nI lose my temper)", color = "#00A0B0") + 
  annotate("segment", x = -.1, y = 0.5, xend = 0.8031979, yend = 0.7140546, color = "#00A0B0", alpha = 0.7)
  # annotate("text", size = 2.5, x = -0.5, y = -0.8, hjust = 0, label = "r(I love life,\nI avoid crowds)", color = "#00A0B0") +
  # annotate("segment", x = -.3, y = -0.7, xend = -0.23, yend = -0.28, color = "#00A0B0", alpha = 0.7) +
  # annotate("text", size = 2.5, x = -.3, y = 0.5, hjust = 1, label = "r(I work hard,\nI am diligent)", color = "#00A0B0") +
  # annotate("segment", x = -.3, y = .5, xend = .52, yend = .58, color = "#00A0B0", alpha = 0.7)


pt_plot_rels2 <- pt_plot_rels + 
  annotate("text", size = 2.5, x = 0.61, y = 0.25, hjust = 0, label = "IPIP Extraversion", color = "#00A0B0") +
  annotate("segment", x = 0.7, y = 0.27, xend = 0.9, yend = 0.90, color = "#00A0B0", alpha = 0.7) +
  annotate("text", size = 2.5, x = -0.02, y = 0.95, hjust = 0, label = "LOT Optimism", color = "#00A0B0") +
  annotate("segment", x = 0.11, y = 0.93, xend = -1.477226, yend = 0.71, color = "#00A0B0", alpha = 0.7)

plot_rels2 <- plot_rels + 
  annotate("text", size = 3, x = 0, y = .985, vjust = 0, hjust = 0, label = with(accuracy_bayes_rels, { sprintf("accuracy = %.2f [%.2f;%.2f]", semi_latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = 0.4, y = 0.1, hjust = 0, label = "randomly formed scales", color = "#6A4A3C") +
  annotate("segment", x = 0.395, y = 0.1, xend = 0.39, yend = 0.4864297, color = "#6A4A3C", alpha = 0.7) +
  annotate("segment", x = 0.395, y = 0.1, xend = 0.285, yend = 0.2279919, color = "#6A4A3C", alpha = 0.7) +
  annotate("segment", x = 0.395, y = 0.1, xend = 0.2, yend = 0.075, color = "#6A4A3C", alpha = 0.7) +
  annotate("text", size = 2.5, x = 0.61, y = 0.4, hjust = 0, label = "IPIP Extraversion", color = "#00A0B0") +
  annotate("segment", x = 0.75, y = 0.42, xend = 0.87, yend = 0.90, color = "#00A0B0", alpha = 0.7) +
  annotate("text", size = 2.5, x = -0.02, y = 0.86, hjust = 0, label = "LOT Optimism", color = "#00A0B0") +
  annotate("segment", x = 0.11, y = 0.83, xend = 0.15, yend = 0.71, color = "#00A0B0", alpha = 0.7)

pt_plot_scales2 <- pt_plot_scales +
  annotate("text", size = 2.5, x = -0.2, y = 0.8, hjust = 1, label = "r(BFI Neuroticism,\nIPIP Neuroticism)", color = "#00A0B0") +
  annotate("segment", x = -.2, y = 0.8, xend = 0.22, yend = .84, color = "#00A0B0", alpha = 0.7) +
  annotate("text", size = 2.5, x = -.1, y = -0.9, hjust = 0, label = "r(BFI Depression facet,\nLOT Optimism)", color = "#00A0B0") +
  annotate("segment", x = -.1, y = -.9, xend = -0.17, yend = -.63, 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]", semi_latent_r, .lower, .upper) })) +
  annotate("text", size = 2.5, x = -0.1, y = 0.5, hjust = 1, label = "r(BFI Neuroticism,\nIPIP Neuroticism)", color = "#00A0B0") +
  annotate("segment", x = -.1, y = 0.5, xend = .84, yend = .84, color = "#00A0B0", alpha = 0.7) +
  annotate("text", size = 2.5, x = -.15, y = -0.7, hjust = 0, label = "r(BFI Depression facet,\nLOT Optimism)", color = "#00A0B0") +
  annotate("segment", x = -.15, y = -.7, xend = -.34, yend = -.63, color = "#00A0B0", alpha = 0.7)


(pt_plot_items2+
    pt_plot_rels2 + ggtitle("") +
    pt_plot_scales2) /


(plot_items2 +
    plot_rels2 + ggtitle("SurveyBot 3000")  +
    plot_scales2) +
  plot_annotation(
  title = 'Pre-trained model before domain adaptation and fine-tuning'
)

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



# ggsave("ignore/Figure_pilot.svg", width = 8.3, height = 5.5, device = svglite::svglite)
LS0tCnRpdGxlOiAiTGFuZ3VhZ2UgbW9kZWxzIGFjY3VyYXRlbHkgaW5mZXIgY29ycmVsYXRpb25zIGJldHdlZW4gcHN5Y2hvbG9naWNhbCBpdGVtcyBhbmQgc2NhbGVzIGZyb20gdGV4dCBhbG9uZSIKZGF0ZTogIjIwMjMtMTEtMDciCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKYGBge2NzcywgZWNobz1GQUxTRX0Kc3VtbWFyeSB7CiAgZGlzcGxheTogYmxvY2s7CiAgbWFyZ2luLWJvdHRvbTogMmVtOwp9CgpzdW1tYXJ5IGgzLCBzdW1tYXJ5IGg0IHsKICBkaXNwbGF5OiBsaXN0LWl0ZW07Cn0KYGBgCgpIZXJlLCB3ZSBhcHBseSB0aGUgcHJlLXRyYWluZWQgbW9kZWwgYW5kIG91ciBmaW5lLXR1bmVkIG1vZGVsIHRvIGRhdGEgbm90IHVzZWQgZm9yIHRyYWluaW5nLCBhIGhvbGRvdXQuIFRoZSBob2xkb3V0IHNhbXBsZSB3YXMgY29sbGVjdGVkIGJ5IEJhaW5icmlkZ2UgZXQgYWwuIDIwMjIuCgpgYGB7ciB3YXJuaW5nPUYsbWVzc2FnZT1GfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGVycm9yID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGKQoKIyBMaWJyYXJpZXMgYW5kIFNldHRpbmdzCgojIExpYnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGFycm93KQpsaWJyYXJ5KGdsdWUpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkobGF2YWFuKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShicm9vbSkKbGlicmFyeShicm9vbS5taXhlZCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShjbWRzdGFucikKbGlicmFyeShjb3dwbG90KQoKb3B0aW9ucyhtYy5jb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpLCAKICAgICAgICBicm1zLmJhY2tlbmQgPSAiY21kc3RhbnIiLCAKICAgICAgICBicm1zLmZpbGVfcmVmaXQgPSAib25fY2hhbmdlIikKCgptb2RlbF9uYW1lID0gIkl0ZW1TaW1pbGFyaXR5VHJhaW5pbmctMjAyNDA1MDItdHJpYWwxMiIKI21vZGVsX25hbWUgPSAiaXRlbS1zaW1pbGFyaXR5LTIwMjMxMDE4LTEyMjUwNCIKcHJldHJhaW5lZF9tb2RlbF9uYW1lID0gImFsbC1tcG5ldC1iYXNlLXYyIgoKZGF0YV9wYXRoID0gZ2x1ZSgiLi8iKQpwcmV0cmFpbmVkX2RhdGFfcGF0aCA9IGdsdWUoIi4vIikKCnNldC5zZWVkKDQyKQoKCmhvbGRvdXQgPC0gYXJyb3c6OnJlYWRfZmVhdGhlcihmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLnttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLml0ZW1fY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCgpwdF9ob2xkb3V0IDwtIGFycm93OjpyZWFkX2ZlYXRoZXIoZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS57cHJldHJhaW5lZF9tb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLml0ZW1fY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCgpob2xkb3V0X21hcHBpbmdfZGF0YSA9IGFycm93OjpyZWFkX2ZlYXRoZXIoCiAgZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLm1hcHBpbmcyLmZlYXRoZXIiKSkKKSAlPiUKICByZW5hbWUoc2NhbGVfMCA9IHNjYWxlMCwKICAgICAgICAgc2NhbGVfMSA9IHNjYWxlMSkKCmhvbGRvdXRfaHVtYW5fZGF0YSA9IGFycm93OjpyZWFkX2ZlYXRoZXIoCiAgZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLmh1bWFuLmZlYXRoZXIiKSkKKQoKaG9sZG91dF9zY2FsZXMgPC0gYXJyb3c6OnJlYWRfZmVhdGhlcihmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJ7bW9kZWxfbmFtZX0ucmF3Lm9zZi1iYWluYnJpZGdlLTIwMjEtczItMC5zY2FsZXMuZmVhdGhlciIpKQopCgpOIDwtIGhvbGRvdXRfaHVtYW5fZGF0YSAlPiUgc3VtbWFyaXNlX2FsbCh+IHN1bSghaXMubmEoLikpKSAlPiUgbWluKCkKdG90YWxfTiA8LSBucm93KGhvbGRvdXRfaHVtYW5fZGF0YSkKYGBgCgpUaGUgQmFpbmJyaWRnZSBkYXRhIHdhcyBjb2xsZWN0ZWQgb24gTj1gciB0b3RhbF9OYCByZXNwb25kZW50cy4gVGhlIGl0ZW0gd2l0aCB0aGUgbW9zdCBtaXNzaW5nIHZhbHVlcyBzdGlsbCBoYWQgbj1gciBOYC4KCgojIyBTeW50aGV0aWMgaW50ZXItaXRlbSBjb3JyZWxhdGlvbnMKYGBge3J9CmhvbGRvdXRfbGxtIDwtIGhvbGRvdXQgJT4lCiAgbGVmdF9qb2luKGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLCBJbnN0cnVtZW50QSA9IGluc3RydW1lbnQsIFNjYWxlQSA9IHNjYWxlXzAsIFN1YnNjYWxlQSA9IHNjYWxlXzEpKSAlPiUKICBsZWZ0X2pvaW4oaG9sZG91dF9tYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCh2YXJpYWJsZV8yID0gdmFyaWFibGUsIEluc3RydW1lbnRCID0gaW5zdHJ1bWVudCwgU2NhbGVCID0gc2NhbGVfMCwgU3Vic2NhbGVCID0gc2NhbGVfMSkpCgpwdF9ob2xkb3V0X2xsbSA8LSBwdF9ob2xkb3V0ICU+JQogIGxlZnRfam9pbihob2xkb3V0X21hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzEgPSB2YXJpYWJsZSwgSW5zdHJ1bWVudEEgPSBpbnN0cnVtZW50LCBTY2FsZUEgPSBzY2FsZV8wLCBTdWJzY2FsZUEgPSBzY2FsZV8xKSkgJT4lCiAgbGVmdF9qb2luKGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMiA9IHZhcmlhYmxlLCBJbnN0cnVtZW50QiA9IGluc3RydW1lbnQsIFNjYWxlQiA9IHNjYWxlXzAsIFN1YnNjYWxlQiA9IHNjYWxlXzEpKQpgYGAKCgojIyMgQWNjdXJhY3kKYGBge3J9CnNlMiA8LSBtZWFuKGhvbGRvdXRfbGxtJGVtcGlyaWNhbF9yX3NlXjIpCgpyIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KGhvbGRvdXRfbGxtJGVtcGlyaWNhbF9yLCBob2xkb3V0X2xsbSRzeW50aGV0aWNfcikpCnB0X3IgPC0gYnJvb206OnRpZHkoY29yLnRlc3QocHRfaG9sZG91dF9sbG0kZW1waXJpY2FsX3IsIHB0X2hvbGRvdXRfbGxtJHN5bnRoZXRpY19yKSkKCm1vZGVsIDwtIHBhc3RlMCgnCiAgIyBMYXRlbnQgdmFyaWFibGVzCiAgUGVhcnNvbkxhdGVudCA9fiAxKmVtcGlyaWNhbF9yCgogICMgRml4aW5nIGVycm9yIHZhcmlhbmNlcyBiYXNlZCBvbiBrbm93biBzdGFuZGFyZCBlcnJvcnMKICBlbXBpcmljYWxfciB+fiAnLHNlMiwnKmVtcGlyaWNhbF9yCgogICMgUmVsYXRpb25zaGlwIGJldHdlZW4gbGF0ZW50IHZhcmlhYmxlcwogIFBlYXJzb25MYXRlbnQgfn4gc3ludGhldGljX3IKJykKCmZpdCA8LSBzZW0obW9kZWwsIGRhdGEgPSBob2xkb3V0X2xsbSkKcHRfZml0IDwtIHNlbShtb2RlbCwgZGF0YSA9IHB0X2hvbGRvdXRfbGxtKQoKbV9zeW50aF9yX2l0ZW1zIDwtIGJybSgKICBiZihlbXBpcmljYWxfciB8IG1pKGVtcGlyaWNhbF9yX3NlKSB+IHN5bnRoZXRpY19yICsgKDF8bW0odmFyaWFibGVfMSwgdmFyaWFibGVfMikpLAogICAgIHNpZ21hIH4gcG9seShzeW50aGV0aWNfciwgZGVncmVlID0gMykpLCBkYXRhID0gaG9sZG91dF9sbG0sIAogIGZpbGUgPSAiaWdub3JlL21fc3ludGhfcl9pdGVtc19sbSIpCgpzZF9zeW50aCA8LSBzZChtX3N5bnRoX3JfaXRlbXMkZGF0YSRzeW50aGV0aWNfcikKCm5ld2RhdGEgPC0gbV9zeW50aF9yX2l0ZW1zJGRhdGEgJT4lIHNlbGVjdChlbXBpcmljYWxfciwgc3ludGhldGljX3IsIGVtcGlyaWNhbF9yX3NlKQplcHJlZHMgPC0gZXByZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IG1fc3ludGhfcl9pdGVtcywgcmVfZm9ybXVsYSA9IE5BLCBuZHJhd3MgPSAyMDApCnByZWRzIDwtIHByZWRpY3RlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gbV9zeW50aF9yX2l0ZW1zLCByZV9mb3JtdWxhID0gTkEsIG5kcmF3cyA9IDIwMCkKZXByZWRfcHJlZHMgPC0gZXByZWRzICU+JSBsZWZ0X2pvaW4ocHJlZHMpCmJ5X2RyYXcgPC0gZXByZWRfcHJlZHMgJT4lIGdyb3VwX2J5KC5kcmF3KSAlPiUgCiAgc3VtbWFyaXNlKC5lcHJlZCA9IHZhciguZXByZWQpLAogICAgICAgICAgICAucHJlZGljdGlvbiA9IHZhcigucHJlZGljdGlvbiksCiAgICAgICAgICAgIHNpZ21hID0gc3FydCgucHJlZGljdGlvbiAtIC5lcHJlZCksCiAgICAgICAgICAgIHNlbWlfbGF0ZW50X3IgPSBzcXJ0KC5lcHJlZC8ucHJlZGljdGlvbikpCnJtKGVwcmVkX3ByZWRzKQoKYWNjdXJhY3lfYmF5ZXNfaXRlbXMgPC0gYnlfZHJhdyAlPiUgbWVhbl9oZGNpKHNlbWlfbGF0ZW50X3IpCgpiaW5kX3Jvd3MoCiAgcHRfciAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAicHJlLXRyYWluZWQiLCBraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSwKICBzdGFuZGFyZGl6ZWRzb2x1dGlvbihwdF9maXQpICU+JSAKICAgIGZpbHRlcihsaHMgPT0gIlBlYXJzb25MYXRlbnQiLCByaHMgPT0gICJzeW50aGV0aWNfciIpICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAic2VtaS1sYXRlbnQgKFNFTSkiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0LnN0ZCwgCiAgICAgICAgICAgY29uZi5sb3cgPSBjaS5sb3dlciwgY29uZi5oaWdoID0gY2kudXBwZXIpLAogIHIgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gIm1hbmlmZXN0IikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSwKICBzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQpICU+JSAKICAgIGZpbHRlcihsaHMgPT0gIlBlYXJzb25MYXRlbnQiLCByaHMgPT0gICJzeW50aGV0aWNfciIpICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkIiwga2luZCA9ICJzZW1pLWxhdGVudCAoU0VNKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3Quc3RkLCAKICAgICAgICAgICBjb25mLmxvdyA9IGNpLmxvd2VyLCBjb25mLmhpZ2ggPSBjaS51cHBlciksCiAgYWNjdXJhY3lfYmF5ZXNfaXRlbXMgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gInNlbWktbGF0ZW50IChCYXllc2lhbiBFSVYpIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IHNlbWlfbGF0ZW50X3IsIGNvbmYubG93ID0gLmxvd2VyLCBjb25mLmhpZ2ggPSAudXBwZXIpCiAgKSAlPiUgCiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDIpCmBgYAoKCjxkZXRhaWxzPjxzdW1tYXJ5PjxoND5QcmVkaWN0aW9uIGVycm9yIHBsb3QgYWNjb3JkaW5nIHRvIHN5bnRoZXRpYyBlc3RpbWF0ZTwvaDQ+PC9zdW1tYXJ5PgoKYGBge3J9Cm1fc3ludGhfcl9pdGVtcwoKcHJlZCA8LSBjb25kaXRpb25hbF9lZmZlY3RzKG1fc3ludGhfcl9pdGVtcywgbWV0aG9kID0gInByZWRpY3QiKQpieV9kcmF3ICU+JSBtZWFuX2hkY2koc2lnbWEpCnBsb3QoY29uZGl0aW9uYWxfZWZmZWN0cyhtX3N5bnRoX3JfaXRlbXMsIGRwYXIgPSAic2lnbWEiKSwgcGxvdCA9IEYpW1sxXV0gKyAKICB0aGVtZV9idygpICsgCiAgeWxhYigiUHJlZGljdGlvbiBlcnJvciAoc2lnbWEpIikKYGBgCgo8L2RldGFpbHM+CgoKCiMjIyBTY2F0dGVyIHBsb3QKYGBge3J9CmdncGxvdChob2xkb3V0X2xsbSwgYWVzKHN5bnRoZXRpY19yLCBlbXBpcmljYWxfciwgCiAgICAgICAgICAgICAgeW1pbiA9IGVtcGlyaWNhbF9yIC0gZW1waXJpY2FsX3Jfc2UsCiAgICAgICAgICAgICAgeW1heCA9IGVtcGlyaWNhbF9yICsgZW1waXJpY2FsX3Jfc2UpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuMSwgc2l6ZSA9IDEpICsKICBnZW9tX3Ntb290aChhZXMoCiAgICB4ID0gc3ludGhldGljX3IsCiAgICB5ID0gZXN0aW1hdGVfXywKICAgIHltaW4gPSBsb3dlcl9fLAogICAgeW1heCA9IHVwcGVyX18sCiAgKSwgc3RhdCA9ICJpZGVudGl0eSIsIAogIGNvbG9yID0gIiNhNDg1MDAiLAogIGZpbGwgPSAiI0VEQzk1MSIsCiAgZGF0YSA9IGFzLmRhdGEuZnJhbWUocHJlZCRzeW50aGV0aWNfcikpICsKICB4bGFiKCJTeW50aGV0aWMgaW50ZXItaXRlbSBjb3JyZWxhdGlvbiIpICsgCiAgeWxhYigiRW1waXJpY2FsIGludGVyLWl0ZW0gY29ycmVsYXRpb24iKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoLTEsMSksIHlsaW0gPSBjKC0xLDEpKSAtPiBwbG90X2l0ZW1zCnBsb3RfaXRlbXMKYGBgCgojIyMgSW50ZXJhY3RpdmUgcGxvdApUaGlzIHBsb3Qgc2hvd3Mgb25seSAyMDAwIHJhbmRvbWx5IHNlbGVjdGVkIGl0ZW0gcGFpcnMgdG8gY29uc2VydmUgbWVtb3J5LiBBIFtmdWxsIGludGVyYWN0aXZlIHBsb3RdKDJfaW50ZXJhY3RpdmVfaXRlbV9wbG90Lmh0bWwpIGV4aXN0cywgYnV0IG1heSByZWFjdCBzbG93bHkuCgpgYGB7cn0KaXRlbV9wYWlyX3RhYmxlIDwtIGhvbGRvdXRfbGxtICU+JSAKICAgbGVmdF9qb2luKGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtX3RleHRfMSA9IGl0ZW1fdGV4dCkpICU+JSAKICAgbGVmdF9qb2luKGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMiA9IHZhcmlhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtX3RleHRfMiA9IGl0ZW1fdGV4dCkpCgojIGl0ZW1fcGFpcl90YWJsZSAlPiUgZmlsdGVyKHN0cl9sZW5ndGgoaXRlbV90ZXh0XzEpIDwgMzAsIHN0cl9sZW5ndGgoaXRlbV90ZXh0XzIpIDwgMzApICU+JSAKIyAgIGxlZnRfam9pbihwdF9ob2xkb3V0X2xsbSAlPiUgcmVuYW1lKHN5bnRoZXRpY19yX3B0ID0gc3ludGhldGljX3IpKSAlPiUgCiMgICBzZWxlY3QoaXRlbV90ZXh0XzEsIGl0ZW1fdGV4dF8yLCBlbXBpcmljYWxfciwgc3ludGhldGljX3IsIHN5bnRoZXRpY19yX3B0KSAlPiUgVmlldygpCnJpbzo6ZXhwb3J0KGl0ZW1fcGFpcl90YWJsZSwgImlnbm9yZS9pdGVtX3BhaXJfdGFibGUuZmVhdGhlciIpCgooaXRlbV9wYWlyX3RhYmxlICU+JSAKICBtdXRhdGUoc3ludGhldGljX3IgPSByb3VuZChzeW50aGV0aWNfciwgMiksCiAgICAgICAgIGVtcGlyaWNhbF9yID0gcm91bmQoZW1waXJpY2FsX3IsIDIpLAogICAgICAgICBpdGVtcyA9IHN0cl9yZXBsYWNlX2FsbChzdHJfYyhpdGVtX3RleHRfMSwgIlxuIiwgaXRlbV90ZXh0XzIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8rIiwgIiAiKSkgJT4lIAogICAgc2FtcGxlX24oMjAwMCkgJT4lCmdncGxvdCguLCBhZXMoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yLCAKICAgICAgICAgICAgICAjIHltaW4gPSBlbXBpcmljYWxfciAtIGVtcGlyaWNhbF9yX3NlLCAKICAgICAgICAgICAgICAjIHltYXggPSBlbXBpcmljYWxfciArIGVtcGlyaWNhbF9yX3NlLCAKICAgICAgICAgICAgICBsYWJlbCA9IGl0ZW1zKSkgKyAKICBnZW9tX2FibGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjMsIHNpemUgPSAxKSArCiAgeGxhYigiU3ludGhldGljIGludGVyLWl0ZW0gY29ycmVsYXRpb24iKSArIAogIHlsYWIoIkVtcGlyaWNhbCBpbnRlci1pdGVtIGNvcnJlbGF0aW9uIikgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xLDEpLCB5bGltID0gYygtMSwxKSkpICU+JSAKICBnZ3Bsb3RseSgpCgppdGVtX3BhaXJfdGFibGUgPC0gaXRlbV9wYWlyX3RhYmxlICU+JSAKICBtdXRhdGUoZW1waXJpY2FsX3IgPSBzcHJpbnRmKCIlLjJmwrElLjNmIiwgZW1waXJpY2FsX3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtcGlyaWNhbF9yX3NlKSwKICAgICAgICAgICBzeW50aGV0aWNfciA9IHNwcmludGYoIiUuMmYiLCBzeW50aGV0aWNfcikpICU+JSAKICBzZWxlY3QoaXRlbV90ZXh0XzEsIGl0ZW1fdGV4dF8yLCBlbXBpcmljYWxfciwgc3ludGhldGljX3IpCnJpbzo6ZXhwb3J0KGl0ZW1fcGFpcl90YWJsZSwgIml0ZW1fcGFpcl90YWJsZS54bHN4IikKYGBgCgo8ZGV0YWlscz48c3VtbWFyeT48aDM+Um9idXN0bmVzcyBjaGVja3M8L2gzPjwvc3VtbWFyeT4KCgpJcyB0aGUgYWNjdXJhY3kgbG93ZXIgd2l0aGluL2Fjcm9zcyBzY2FsZXMgYW5kIGluc3RydW1lbnRzPwoKYGBge3J9CmhvbGRvdXRfbGxtICU+JSAKICBtdXRhdGUoc2FtZV9pbnN0cnVtZW50ID0gaWZfZWxzZShJbnN0cnVtZW50QSA9PSBJbnN0cnVtZW50QiwgMSwgMCwwKSwKICAgICAgICAgc2FtZV9zY2FsZSA9IGlmX2Vsc2UoU2NhbGVBID09IFNjYWxlQiwgMSwwLDApLAogICAgICAgICBzYW1lX3N1YnNjYWxlID0gaWZfZWxzZShzYW1lX3NjYWxlICYgU3Vic2NhbGVBID09IFN1YnNjYWxlQiwgMSwwLDApKSAlPiUgCiAgZ3JvdXBfYnkoc2FtZV9zY2FsZSwgc2FtZV9pbnN0cnVtZW50LCBzYW1lX3N1YnNjYWxlKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19yLCBlbXBpcmljYWxfcikpLCBzZF9lbXBfciA9IHNkKGVtcGlyaWNhbF9yKSwgbiA9IG4oKSkgJT4lIAogIHNlbGVjdChzYW1lX2luc3RydW1lbnQsIHNhbWVfc2NhbGUsIHNhbWVfc3Vic2NhbGUsIHIgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCwgbiwgc2RfZW1wX3IpICU+JSAKICBhcnJhbmdlKHNhbWVfaW5zdHJ1bWVudCwgc2FtZV9zY2FsZSwgc2FtZV9zdWJzY2FsZSkgJT4lIAogIGthYmxlKCkKYGBgCgpJcyB0aGUgYWNjdXJhY3kgbG93ZXIgb3V0c2lkZSBjbGFzc2ljIEJpZyBGaXZlPwoKYGBge3J9CmhvbGRvdXRfbGxtICU+JSAKICBtdXRhdGUoYmlnX2ZpdmUgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KEluc3RydW1lbnRBLCAiKFBlcnNvbmFsaXR5fEJpZyBGaXZlKSIpICYgc3RyX2RldGVjdChJbnN0cnVtZW50QiwgIihQZXJzb25hbGl0eXxCaWcgRml2ZSkiKSB+ICJib3RoIiwKICAgIHN0cl9kZXRlY3QoSW5zdHJ1bWVudEEsICIoUGVyc29uYWxpdHl8QmlnIEZpdmUpIikgfCBzdHJfZGV0ZWN0KEluc3RydW1lbnRCLCAiKFBlcnNvbmFsaXR5fEJpZyBGaXZlKSIpIH4gImVpdGhlciIsCiAgICBUUlVFIH4gIm5vbmUiCiAgICAgICAgICkpICU+JSAKICBncm91cF9ieShiaWdfZml2ZSkgJT4lIAogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChzeW50aGV0aWNfciwgZW1waXJpY2FsX3IpKSwgc2RfZW1wX3IgPSBzZChlbXBpcmljYWxfciksIG4gPSBuKCkpICU+JSAKICBzZWxlY3QoYmlnX2ZpdmUsIHIgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCwgbiwgc2RfZW1wX3IpICU+JSAKICBhcnJhbmdlKGJpZ19maXZlKSAlPiUgCiAga2FibGUoKQpgYGAKCklzIHRoZSBhY2N1cmFjeSBsb3dlciBmb3IgaXRlbXMgdGhhdCBoYXZlIGxvdyB2YXJpYW5jZT8KCmBgYHtyfQppdGVtX3ZhcmlhbmNlcyA8LSBob2xkb3V0X2h1bWFuX2RhdGEgJT4lIHN1bW1hcmlzZV9hbGwofiBzZCguLCBuYS5ybSA9IFQpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAiaXRlbV9zZCIpCgpieV9tYXhfY292IDwtIGhvbGRvdXRfbGxtICU+JSAKICBsZWZ0X2pvaW4oaXRlbV92YXJpYW5jZXMsIGJ5ID0gYygidmFyaWFibGVfMSIgPSAidmFyaWFibGUiKSkgJT4lIAogIGxlZnRfam9pbihpdGVtX3ZhcmlhbmNlcywgYnkgPSBjKCJ2YXJpYWJsZV8yIiA9ICJ2YXJpYWJsZSIpLCBzdWZmaXggPSBjKCJfMSIsICJfMiIpKSAlPiUgCiAgbXV0YXRlKG1heF9jb3ZhcmlhbmNlID0gY2VpbGluZygoaXRlbV9zZF8xICogaXRlbV9zZF8yKSoxMCkvMTApCgpyc19ieV9tYXhfY292IDwtIGJ5X21heF9jb3YgJT4lIAogIGdyb3VwX2J5KG1heF9jb3ZhcmlhbmNlKSAlPiUgCiAgZmlsdGVyKG4oKSA+IDMpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHNkX2VtcF9yID0gc2QoZW1waXJpY2FsX3IpLCBuID0gbigpKSAlPiUgCiAgc2VsZWN0KG1heF9jb3ZhcmlhbmNlLCByID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gsIG4sIHNkX2VtcF9yKSAlPiUgCiAgYXJyYW5nZShtYXhfY292YXJpYW5jZSkKCnJzX2J5X21heF9jb3YlPiUgCiAga2FibGUoKQpyc19ieV9tYXhfY292ICU+JSBnZ3Bsb3QoYWVzKG1heF9jb3ZhcmlhbmNlLCByLCB5bWluID0gY29uZi5sb3csIHltYXggPSBjb25mLmhpZ2gpKSArCiAgZ2VvbV9wb2ludHJhbmdlKCkKCmJ5X21heF9jb3YlPiUgCiAgZmlsdGVyKG1heF9jb3ZhcmlhbmNlID4gLjcpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHNkX2VtcF9yID0gc2QoZW1waXJpY2FsX3IpLCBuID0gbigpKSAlPiUgCiAga2FibGUoKQoKaG9sZG91dF9sbG0gJT4lIAogIGxlZnRfam9pbihpdGVtX3ZhcmlhbmNlcywgYnkgPSBjKCJ2YXJpYWJsZV8xIiA9ICJ2YXJpYWJsZSIpKSAlPiUgCiAgbGVmdF9qb2luKGl0ZW1fdmFyaWFuY2VzLCBieSA9IGMoInZhcmlhYmxlXzIiID0gInZhcmlhYmxlIiksIHN1ZmZpeCA9IGMoIl8xIiwgIl8yIikpICU+JSAKICBtdXRhdGUobWF4X2NvdmFyaWFuY2UgPSBjZWlsaW5nKChpdGVtX3NkXzEgKiBpdGVtX3NkXzIpKjEwKS8xMCkgJT4lIAogIGZpbHRlcihtYXhfY292YXJpYW5jZSA+IDEpICU+JSAKICBzdW1tYXJpc2UoYnJvb206OnRpZHkoY29yLnRlc3Qoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yKSksIHNkX2VtcF9yID0gc2QoZW1waXJpY2FsX3IpLCBuID0gbigpKSAlPiUgCiAgc2VsZWN0KHIgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCwgbiwgc2RfZW1wX3IpICU+JSAKICBrbml0cjo6a2FibGUoKQpgYGAKCgoKSXMgdGhlIGFjY3VyYWN5IGxvd2VyIGZvciB0aGUgcHJlLXRyYWluZWQgbW9kZWw/CgpgYGB7cn0KZ2dwbG90KHB0X2hvbGRvdXRfbGxtLCBhZXMoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yLCAKICAgICAgICAgICAgICB5bWluID0gZW1waXJpY2FsX3IgLSBlbXBpcmljYWxfcl9zZSwKICAgICAgICAgICAgICB5bWF4ID0gZW1waXJpY2FsX3IgKyBlbXBpcmljYWxfcl9zZSkpICsgCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC4xLCBzaXplID0gMSkgKwogIHhsYWIoIlN5bnRoZXRpYyBpbnRlci1pdGVtIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJFbXBpcmljYWwgaW50ZXItaXRlbSBjb3JyZWxhdGlvbiIpICsKICB0aGVtZV9idygpICsKICBjb29yZF9maXhlZCh4bGltID0gYygtMSwxKSwgeWxpbSA9IGMoLTEsMSkpIC0+IHB0X3Bsb3RfaXRlbXMKcHRfcGxvdF9pdGVtcwpgYGAKCgo8L2RldGFpbHM+CgoKCltGdWxsIHRhYmxlIG9mIHN5bnRoZXRpYyBhbmQgZW1waXJpY2FsIGl0ZW0gcGFpciBjb3JyZWxhdGlvbnNdKGl0ZW1fcGFpcl90YWJsZS54bHN4KQoKCiMjIFN5bnRoZXRpYyBSZWxpYWJpbGl0aWVzCmBgYHtyfQpjb3JzX2xsbSA8LSBob2xkb3V0X2xsbSAlPiUKICBzZWxlY3QoeCA9IHZhcmlhYmxlXzEsIHkgPSB2YXJpYWJsZV8yLCByID0gc3ludGhldGljX3IpICU+JQogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkID0gRkFMU0UpIHw+CiAgaWdyYXBoOjphc19hZGphY2VuY3lfbWF0cml4KGF0dHIgPSAiciIsIHNwYXJzZSA9IEZBTFNFKQpkaWFnKGNvcnNfbGxtKSA8LSAxCgpwdF9jb3JzX2xsbSA8LSBwdF9ob2xkb3V0X2xsbSAlPiUKICBzZWxlY3QoeCA9IHZhcmlhYmxlXzEsIHkgPSB2YXJpYWJsZV8yLCByID0gc3ludGhldGljX3IpICU+JQogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkID0gRkFMU0UpIHw+CiAgaWdyYXBoOjphc19hZGphY2VuY3lfbWF0cml4KGF0dHIgPSAiciIsIHNwYXJzZSA9IEZBTFNFKQpkaWFnKHB0X2NvcnNfbGxtKSA8LSAxCgpjb3JzX3JlYWwgPC0gaG9sZG91dF9sbG0gJT4lCiAgc2VsZWN0KHggPSB2YXJpYWJsZV8xLCB5ID0gdmFyaWFibGVfMiwgciA9IGVtcGlyaWNhbF9yKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgfD4KICBpZ3JhcGg6OmdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZCA9IEZBTFNFKSB8PgogIGlncmFwaDo6YXNfYWRqYWNlbmN5X21hdHJpeChhdHRyID0gInIiLCBzcGFyc2UgPSBGQUxTRSkKZGlhZyhjb3JzX3JlYWwpIDwtIDEKCm1hcHBpbmdfZGF0YSA8LSBob2xkb3V0X21hcHBpbmdfZGF0YQppdGVtc19ieV9zY2FsZSA8LSBiaW5kX3Jvd3MoCiAgaG9sZG91dF9zY2FsZXMgJT4lIGZpbHRlcihzY2FsZV8xID09ICIiKSAlPiUgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KC1zY2FsZV8xKSwgYnkgPSBjKCJpbnN0cnVtZW50IiwgInNjYWxlXzAiKSksCiAgaG9sZG91dF9zY2FsZXMgJT4lIGZpbHRlcihzY2FsZV8xICE9ICIiKSAlPiUgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSwgYnkgPSBjKCJpbnN0cnVtZW50IiwgInNjYWxlXzAiLCAic2NhbGVfMSIpKQopCiAgCnNjYWxlcyA8LSBpdGVtc19ieV9zY2FsZSAlPiUKICBncm91cF9ieShrZXllZCwgc2NhbGUpICU+JQogIHN1bW1hcmlzZSgKICAgIGl0ZW1zID0gbGlzdCh2YXJpYWJsZSksCiAgICBudW1iZXJfb2ZfaXRlbXMgPSBuX2Rpc3RpbmN0KHZhcmlhYmxlKSwKICAgIGx2biA9IHBhc3RlKGZpcnN0KHNjYWxlKSwgIiA9fiAiLCBwYXN0ZSh2YXJpYWJsZSwgY29sbGFwc2UgPSAiICsgIikpKSAlPiUKICBkcm9wX25hKCkgJT4lIAogIHVuZ3JvdXAoKQoKCnJhbmRvbV9zY2FsZXMgPC0gbGlzdCgpCmZvcihpIGluIDE6MjAwKSB7CiAgbl9pdGVtcyA8LSBycG9pcygxLCBtZWFuKHNjYWxlcyRudW1iZXJfb2ZfaXRlbXMpKQogIG5faXRlbXMgPC0gaWZfZWxzZShuX2l0ZW1zIDwgMywgMywgbl9pdGVtcykKICByYW5kb21fc2NhbGVzW1tpXV0gPC0gaG9sZG91dF9tYXBwaW5nX2RhdGEgJT4lCiAgICBzYW1wbGVfbihuX2l0ZW1zKSAlPiUKICAgIG11dGF0ZShzY2FsZSA9IHBhc3RlMCgicmFuZG9tIiwgaSkpICU+JQogICAgZ3JvdXBfYnkoc2NhbGUpICU+JQogICAgc3VtbWFyaXNlKAogICAgICBpdGVtcyA9IGxpc3QodmFyaWFibGUpLAogICAgICBudW1iZXJfb2ZfaXRlbXMgPSBuX2Rpc3RpbmN0KHZhcmlhYmxlKSwKICAgICAgbHZuID0gcGFzdGUoZmlyc3Qoc2NhbGUpLCAiID1+ICIsIHBhc3RlKHZhcmlhYmxlLCBjb2xsYXBzZSA9ICIgKyAiKSkpICU+JQogICAgZHJvcF9uYSgpICU+JSAKICAgIG11dGF0ZShrZXllZCA9IDEpCn0KCnJhbmRvbV9zY2FsZXMgPC0gYmluZF9yb3dzKHJhbmRvbV9zY2FsZXMpCnNjYWxlcyA8LSBiaW5kX3Jvd3Moc2NhbGVzLCByYW5kb21fc2NhbGVzKQoKc291cmNlKCJnbG9iYWxfZnVuY3Rpb25zLlIiKQoKc2NhbGVzIDwtIHNjYWxlcyAlPiUgZmlsdGVyKG51bWJlcl9vZl9pdGVtcyA+PSAzKQoKc2NhbGVzIDwtIHNjYWxlcyAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKHJfcmVhbCA9IGxpc3QoY29yc19yZWFsW2l0ZW1zLCBpdGVtc10pLAogICAgICAgICBwdF9yX2xsbSA9IGxpc3QocHRfY29yc19sbG1baXRlbXMsIGl0ZW1zXSksCiAgICAgICAgIHJfbGxtID0gbGlzdChjb3JzX2xsbVtpdGVtcywgaXRlbXNdKSkgJT4lCiAgbXV0YXRlKHJldmVyc2VfaXRlbXMgPSBsaXN0KGZpbmRfcmV2ZXJzZV9pdGVtc19ieV9maXJzdF9pdGVtKHJfcmVhbCwga2V5ZWQpKSwKICAgICAgICAgcl9yZWFsX3JldiA9IGxpc3QocmV2ZXJzZV9pdGVtcyhyX3JlYWwsIHJldmVyc2VfaXRlbXMpKSwKICAgICAgICAgcHRfcl9sbG1fcmV2ID0gbGlzdChyZXZlcnNlX2l0ZW1zKHB0X3JfbGxtLCByZXZlcnNlX2l0ZW1zKSksCiAgICAgICAgIHJfbGxtX3JldiA9IGxpc3QocmV2ZXJzZV9pdGVtcyhyX2xsbSwgcmV2ZXJzZV9pdGVtcykpKSAlPiUKICBtdXRhdGUoCiAgICByZWxfcmVhbCA9IGxpc3QocHN5Y2g6OmFscGhhKHJfcmVhbF9yZXYsIGtleXMgPSBGLCBuLm9icyA9IE4pJGZlbGR0KSwKICAgIHJlbF9sbG0gPSBsaXN0KHBzeWNoOjphbHBoYShyX2xsbV9yZXYsIGtleXMgPSBGLCBuLm9icyA9IE4pJGZlbGR0KSwKICAgIHJlbF9wdF9sbG0gPSBsaXN0KHBzeWNoOjphbHBoYShwdF9yX2xsbV9yZXYsIGtleXMgPSBGLCBuLm9icyA9IE4pJGZlbGR0KSkgJT4lCiAgbXV0YXRlKGVtcGlyaWNhbF9hbHBoYSA9IHJlbF9yZWFsJGFscGhhJHJhd19hbHBoYSwKICAgICAgICAgc3ludGhldGljX2FscGhhID0gcmVsX2xsbSRhbHBoYSRyYXdfYWxwaGEsCiAgICAgICAgIHB0X3N5bnRoZXRpY19hbHBoYSA9IHJlbF9wdF9sbG0kYWxwaGEkcmF3X2FscGhhKSAlPiUKICBtdXRhdGUoCiAgICBlbXBpcmljYWxfYWxwaGFfc2UgPSBtZWFuKGRpZmYodW5saXN0KHBzeWNob21ldHJpYzo6YWxwaGEuQ0koZW1waXJpY2FsX2FscGhhLCBrID0gbnVtYmVyX29mX2l0ZW1zLCBOID0gTiwgbGV2ZWwgPSAwLjk1KSkpKQogICkKCnNjYWxlcyA8LSBzY2FsZXMgJT4lIGZpbHRlcihlbXBpcmljYWxfYWxwaGEgPiAwKQojIHFwbG90KHNjYWxlcyRlbXBpcmljYWxfYWxwaGFfc2UpCiMgcXBsb3Qoc2NhbGVzJGVtcGlyaWNhbF9hbHBoYSwgc2NhbGVzJGVtcGlyaWNhbF9hbHBoYV9zZSkKIyBxcGxvdChzY2FsZXMkbnVtYmVyX29mX2l0ZW1zLCBzY2FsZXMkZW1waXJpY2FsX2FscGhhX3NlKQojIHFwbG90KHNjYWxlcyRlbXBpcmljYWxfYWxwaGEsIHNjYWxlcyRlbXBpcmljYWxfYWxwaGFfc2UsIGNvbG9yID0gc2NhbGVzJG51bWJlcl9vZl9pdGVtcykKYGBgCgoKIyMjIEFjY3VyYWN5CmBgYHtyfQpzZTIgPC0gbWVhbihzY2FsZXMkZW1waXJpY2FsX2FscGhhX3NlXjIpCnIgPC0gYnJvb206OnRpZHkoY29yLnRlc3Qoc2NhbGVzJGVtcGlyaWNhbF9hbHBoYSwgc2NhbGVzJHN5bnRoZXRpY19hbHBoYSkpCnB0X3IgPC0gYnJvb206OnRpZHkoY29yLnRlc3Qoc2NhbGVzJGVtcGlyaWNhbF9hbHBoYSwgc2NhbGVzJHB0X3N5bnRoZXRpY19hbHBoYSkpCgptb2RlbCA8LSBwYXN0ZTAoJwogICMgTGF0ZW50IHZhcmlhYmxlcwogIGxhdGVudF9yZWFsX3JlbCA9fiAxKmVtcGlyaWNhbF9hbHBoYQoKICAjIEZpeGluZyBlcnJvciB2YXJpYW5jZXMgYmFzZWQgb24ga25vd24gc3RhbmRhcmQgZXJyb3JzCiAgZW1waXJpY2FsX2FscGhhIH5+ICcsc2UyLCcqZW1waXJpY2FsX2FscGhhCgogICMgUmVsYXRpb25zaGlwIGJldHdlZW4gbGF0ZW50IHZhcmlhYmxlcwogIGxhdGVudF9yZWFsX3JlbCB+fiBzeW50aGV0aWNfYWxwaGEKJykKCmZpdCA8LSBzZW0obW9kZWwsIGRhdGEgPSBzY2FsZXMpCnB0X2ZpdCA8LSBzZW0obW9kZWwsIGRhdGEgPSBzY2FsZXMgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KGVtcGlyaWNhbF9hbHBoYSwgc3ludGhldGljX2FscGhhID0gcHRfc3ludGhldGljX2FscGhhKSkKCm1fbG1zeW50aF9yZWxfc2NhbGVzIDwtIGJybSgKICBiZihlbXBpcmljYWxfYWxwaGEgfCBtaShlbXBpcmljYWxfYWxwaGFfc2UpIH4gc3ludGhldGljX2FscGhhLAogICAgIHNpZ21hIH4gcG9seShzeW50aGV0aWNfYWxwaGEsIGRlZ3JlZSA9IDMpKSwgZGF0YSA9IHNjYWxlcywgCiAgZmlsZSA9ICJpZ25vcmUvbV9zeW50aF9yZWxfbG0iKQoKbmV3ZGF0YSA8LSBtX2xtc3ludGhfcmVsX3NjYWxlcyRkYXRhICU+JSBzZWxlY3QoZW1waXJpY2FsX2FscGhhLCBzeW50aGV0aWNfYWxwaGEsIGVtcGlyaWNhbF9hbHBoYV9zZSkKZXByZWRzIDwtIGVwcmVkX2RyYXdzKG5ld2RhdGEgPSBuZXdkYXRhLCBvYmogPSBtX2xtc3ludGhfcmVsX3NjYWxlcywgcmVfZm9ybXVsYSA9IE5BKQpwcmVkcyA8LSBwcmVkaWN0ZWRfZHJhd3MobmV3ZGF0YSA9IG5ld2RhdGEsIG9iaiA9IG1fbG1zeW50aF9yZWxfc2NhbGVzLCByZV9mb3JtdWxhID0gTkEpCmVwcmVkX3ByZWRzIDwtIGVwcmVkcyAlPiUgbGVmdF9qb2luKHByZWRzKQpieV9kcmF3IDwtIGVwcmVkX3ByZWRzICU+JSBncm91cF9ieSguZHJhdykgJT4lIAogIHN1bW1hcmlzZSguZXByZWQgPSB2YXIoLmVwcmVkKSwKICAgICAgICAgICAgLnByZWRpY3Rpb24gPSB2YXIoLnByZWRpY3Rpb24pLAogICAgICAgICAgICBzaWdtYSA9IHNxcnQoLnByZWRpY3Rpb24gLSAuZXByZWQpLAogICAgICAgICAgICBzZW1pX2xhdGVudF9yID0gc3FydCguZXByZWQvLnByZWRpY3Rpb24pKQoKYWNjdXJhY3lfYmF5ZXNfcmVscyA8LSBieV9kcmF3ICU+JSBtZWFuX2hkY2koc2VtaV9sYXRlbnRfcikKCmJpbmRfcm93cygKICBwdF9yICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJwcmUtdHJhaW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIHN0YW5kYXJkaXplZHNvbHV0aW9uKHB0X2ZpdCkgJT4lIAogICAgZmlsdGVyKGxocyA9PSAibGF0ZW50X3JlYWxfcmVsIiwgcmhzID09ICAic3ludGhldGljX2FscGhhIikgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gInByZS10cmFpbmVkIiwga2luZCA9ICJzZW1pLWxhdGVudCAoU0VNKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3Quc3RkLCAKICAgICAgICAgICBjb25mLmxvdyA9IGNpLmxvd2VyLCBjb25mLmhpZ2ggPSBjaS51cHBlciksCiAgciAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAibWFuaWZlc3QiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpLAogIHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdCkgJT4lIAogICAgZmlsdGVyKGxocyA9PSAibGF0ZW50X3JlYWxfcmVsIiwgcmhzID09ICAic3ludGhldGljX2FscGhhIikgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gImZpbmUtdHVuZWQiLCBraW5kID0gInNlbWktbGF0ZW50IChTRU0pIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdC5zdGQsIAogICAgICAgICAgIGNvbmYubG93ID0gY2kubG93ZXIsIGNvbmYuaGlnaCA9IGNpLnVwcGVyKSwKICBhY2N1cmFjeV9iYXllc19yZWxzICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkIiwga2luZCA9ICJzZW1pLWxhdGVudCAoQmF5ZXNpYW4gRUlWKSIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBzZW1pX2xhdGVudF9yLCBjb25mLmxvdyA9IC5sb3dlciwgY29uZi5oaWdoID0gLnVwcGVyKQogICkgJT4lIAogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyKQpgYGAKCgo8ZGV0YWlscz48c3VtbWFyeT48aDQ+UHJlZGljdGlvbiBlcnJvciBwbG90IGFjY29yZGluZyB0byBzeW50aGV0aWMgZXN0aW1hdGU8L2g0Pjwvc3VtbWFyeT4KCmBgYHtyfQptX2xtc3ludGhfcmVsX3NjYWxlcwoKcHJlZCA8LSBjb25kaXRpb25hbF9lZmZlY3RzKG1fbG1zeW50aF9yZWxfc2NhbGVzLCBtZXRob2QgPSAicHJlZGljdCIpCmJ5X2RyYXcgJT4lIAogIGZpbHRlcighaXMubmFuKHNpZ21hKSkgJT4lIG1lYW5faGRjaShzaWdtYSkKCnBsb3QoY29uZGl0aW9uYWxfZWZmZWN0cyhtX2xtc3ludGhfcmVsX3NjYWxlcywgZHBhciA9ICJzaWdtYSIpLCBwbG90ID0gRilbWzFdXSArIAogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDAuMTMpKSArCiAgeWxhYigiUHJlZGljdGlvbiBlcnJvciAoc2lnbWEpIikKYGBgCgo8L2RldGFpbHM+CgoKCgojIyMgU2NhdHRlciBwbG90CmBgYHtyfQpnZ3Bsb3Qoc2NhbGVzLCBhZXMoc3ludGhldGljX2FscGhhLCBlbXBpcmljYWxfYWxwaGEsIAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBzdHJfZGV0ZWN0KHNjYWxlLCAiXnJhbmRvbSIpLCAKICAgICAgICAgICAgICB5bWluID0gZW1waXJpY2FsX2FscGhhIC0gZW1waXJpY2FsX2FscGhhX3NlLAogICAgICAgICAgICAgIHltYXggPSBlbXBpcmljYWxfYWxwaGEgKyBlbXBpcmljYWxfYWxwaGFfc2UpKSArIAogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBzaXplID0gMSkgKwogIGdlb21fc21vb3RoKGFlcygKICAgIHggPSBzeW50aGV0aWNfYWxwaGEsCiAgICB5ID0gZXN0aW1hdGVfXywKICAgIHltaW4gPSBsb3dlcl9fLAogICAgeW1heCA9IHVwcGVyX18sCiAgKSwgc3RhdCA9ICJpZGVudGl0eSIsIAogIGNvbG9yID0gIiNhNDg1MDAiLAogIGZpbGwgPSAiI0VEQzk1MSIsCiAgZGF0YSA9IGFzLmRhdGEuZnJhbWUocHJlZCRzeW50aGV0aWNfYWxwaGEpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMwMEEwQjAiLCAiIzZBNEEzQyIpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICJub25lIikgKwogIHhsYWIoIlN5bnRoZXRpYyBDcm9uYmFjaCdzIGFscGhhIikgKyAKICB5bGFiKCJFbXBpcmljYWwgQ3JvbmJhY2gncyBhbHBoYSIpICsKICB0aGVtZV9idygpICsKICBjb29yZF9maXhlZCh4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpKSAtPiBwbG90X3JlbHMKcGxvdF9yZWxzCmBgYAoKIyMjIEludGVyYWN0aXZlIHBsb3QKYGBge3J9CihzY2FsZXMgJT4lIAogIGZpbHRlcighc3RyX2RldGVjdChzY2FsZSwgIl5yYW5kb20iKSkgJT4lIAogIG11dGF0ZShzeW50aGV0aWNfYWxwaGEgPSByb3VuZChzeW50aGV0aWNfYWxwaGEsIDIpLAogICAgICAgICBlbXBpcmljYWxfYWxwaGEgPSByb3VuZChlbXBpcmljYWxfYWxwaGEsIDIpLAogICAgICAgICBzY2FsZSA9IHN0cl9yZXBsYWNlX2FsbChzY2FsZSwgIl8rIiwgIiAiKSkgJT4lIApnZ3Bsb3QoLiwgYWVzKHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhLCAKICAgICAgICAgICAgICAjIHltaW4gPSBlbXBpcmljYWxfciAtIGVtcGlyaWNhbF9yX3NlLCAKICAgICAgICAgICAgICAjIHltYXggPSBlbXBpcmljYWxfciArIGVtcGlyaWNhbF9yX3NlLCAKICAgICAgICAgICAgICBsYWJlbCA9IHNjYWxlKSkgKyAKICBnZW9tX2FibGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMywgc2l6ZSA9IDEsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgeGxhYigiU3ludGhldGljIENyb25iYWNoJ3MgYWxwaGEiKSArIAogIHlsYWIoIkVtcGlyaWNhbCBDcm9uYmFjaCdzIGFscGhhIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpICsgCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoTkEsMSksIHlsaW0gPSBjKE5BLDEpKSkgJT4lIAogIGdncGxvdGx5KCkKYGBgCgo8ZGV0YWlscz48c3VtbWFyeT48aDQ+VGFibGU8L2g0Pjwvc3VtbWFyeT4KCmBgYHtyfQpzY2FsZXMgJT4lIAogIGZpbHRlcighc3RyX2RldGVjdChzY2FsZSwgIl5yYW5kb20iKSkgJT4lIAogIG11dGF0ZShlbXBpcmljYWxfYWxwaGEgPSBzcHJpbnRmKCIlLjJmwrElLjNmIiwgZW1waXJpY2FsX2FscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW1waXJpY2FsX2FscGhhX3NlKSwKICAgICAgICAgc3ludGhldGljX2FscGhhID0gc3ByaW50ZigiJS4yZiIsIHN5bnRoZXRpY19hbHBoYSksCiAgICAgICAgIHNjYWxlID0gc3RyX3JlcGxhY2VfYWxsKHNjYWxlLCAiXysiLCAiICIpCiAgICAgICAgICkgJT4lIAogIHNlbGVjdChzY2FsZSwgZW1waXJpY2FsX2FscGhhLCBzeW50aGV0aWNfYWxwaGEsIG51bWJlcl9vZl9pdGVtcykgJT4lIAogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGZpbHRlciA9ICJ0b3AiKQpgYGAKCjwvZGV0YWlscz4KCgoKPGRldGFpbHM+PHN1bW1hcnk+PGgzPlJvYnVzdG5lc3MgY2hlY2tzPC9oMz48L3N1bW1hcnk+CgpgYGB7cn0Kc2NhbGVzICU+JSAKICBncm91cF9ieShzdHJfZGV0ZWN0KHNjYWxlLCAiXnJhbmRvbSIpKSAlPiUgCiAgc3VtbWFyaXNlKGJyb29tOjp0aWR5KGNvci50ZXN0KHN5bnRoZXRpY19hbHBoYSwgZW1waXJpY2FsX2FscGhhKSksIHNkX2FscGhhID0gc2QoZW1waXJpY2FsX2FscGhhKSwgbiA9IG4oKSkgJT4lIAogIGtuaXRyOjprYWJsZSgpCmBgYAoKCkFsdGhvdWdoIHRoZSBudW1iZXIgb2YgaXRlbXMgYWxvbmUgY2FuIG9mIGNvdXJzZSBwcmVkaWN0IENyb25iYWNoJ3MgYWxwaGEsIHRoZSBzeW50aGV0aWMgYWxwaGFzIGV4cGxhaW4gbXVjaCBtb3JlIHZhcmlhbmNlIGluIGVtcGlyaWNhbCBhbHBoYXMuCgpgYGB7cn0Kc2NhbGVzICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChudW1iZXJfb2ZfaXRlbXMsIGVtcGlyaWNhbF9hbHBoYSkpLCBzZF9hbHBoYSA9IHNkKGVtcGlyaWNhbF9hbHBoYSksIG4gPSBuKCkpICU+JSAKICBrbml0cjo6a2FibGUoKQoKCnN1bW1hcnkobG0oZW1waXJpY2FsX2FscGhhIH4gbnVtYmVyX29mX2l0ZW1zLCBzY2FsZXMpKQpzdW1tYXJ5KGxtKGVtcGlyaWNhbF9hbHBoYSB+IG51bWJlcl9vZl9pdGVtcyArIHN5bnRoZXRpY19hbHBoYSwgc2NhbGVzKSkKYGBgCgoKCklzIHRoZSBhY2N1cmFjeSBsb3dlciBmb3IgdGhlIHByZS10cmFpbmVkIG1vZGVsPwoKYGBge3J9CmdncGxvdChzY2FsZXMsIGFlcyhwdF9zeW50aGV0aWNfYWxwaGEsIGVtcGlyaWNhbF9hbHBoYSwgCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IHN0cl9kZXRlY3Qoc2NhbGUsICJecmFuZG9tIiksIAogICAgICAgICAgICAgIHltaW4gPSBlbXBpcmljYWxfYWxwaGEgLSBlbXBpcmljYWxfYWxwaGFfc2UsCiAgICAgICAgICAgICAgeW1heCA9IGVtcGlyaWNhbF9hbHBoYSArIGVtcGlyaWNhbF9hbHBoYV9zZSkpICsgCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIHNpemUgPSAxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMwMEEwQjAiLCAiIzZBNEEzQyIpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICJub25lIikgKwogIHhsYWIoIlN5bnRoZXRpYyBDcm9uYmFjaCdzIGFscGhhIikgKyAKICB5bGFiKCJFbXBpcmljYWwgQ3JvbmJhY2gncyBhbHBoYSIpICsKICB0aGVtZV9idygpICsKICBjb29yZF9maXhlZCh4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpKSAtPiBwdF9wbG90X3JlbHMKcHRfcGxvdF9yZWxzCmBgYAoKCjwvZGV0YWlscz4KCgoKCiMjIFN5bnRoZXRpYyBTY2FsZSBDb3JyZWxhdGlvbnMKYGBge3J9Cm1hbmlmZXN0X3Njb3JlcyA9IGFycm93OjpyZWFkX2ZlYXRoZXIoZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS57bW9kZWxfbmFtZX0ucmF3Lm9zZi1iYWluYnJpZGdlLTIwMjEtczItMC5zY2FsZV9jb3JyZWxhdGlvbnMuZmVhdGhlciIpKSkKcHRfbWFuaWZlc3Rfc2NvcmVzID0gYXJyb3c6OnJlYWRfZmVhdGhlcihmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLntwcmV0cmFpbmVkX21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAuc2NhbGVfY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCgpuX2Rpc3RpbmN0KG1hbmlmZXN0X3Njb3JlcyRzY2FsZV9hKQoKbWFuaWZlc3Rfc2NvcmVzIDwtIG1hbmlmZXN0X3Njb3JlcyAlPiUKIGxlZnRfam9pbihzY2FsZXMsIGJ5ID0gYygic2NhbGVfYSIgPSAic2NhbGUiKSkgJT4lCiBsZWZ0X2pvaW4oc2NhbGVzLCBieSA9IGMoInNjYWxlX2IiID0gInNjYWxlIikpCmBgYAoKIyMjIEFjY3VyYWN5CmBgYHtyfQpyIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KG1hbmlmZXN0X3Njb3JlcyRlbXBpcmljYWxfciwgbWFuaWZlc3Rfc2NvcmVzJHN5bnRoZXRpY19yKSkKcHRfciA8LSBicm9vbTo6dGlkeShjb3IudGVzdChwdF9tYW5pZmVzdF9zY29yZXMkZW1waXJpY2FsX3IsIHB0X21hbmlmZXN0X3Njb3JlcyRzeW50aGV0aWNfcikpCgpzZTIgPC0gbWVhbihtYW5pZmVzdF9zY29yZXMkZW1waXJpY2FsX3Jfc2VeMikKbW9kZWwgPC0gcGFzdGUwKCcKICAgICMgTGF0ZW50IHZhcmlhYmxlcwogICAgUGVhcnNvbkxhdGVudCA9fiAxKmVtcGlyaWNhbF9yCgogICAgIyBGaXhpbmcgZXJyb3IgdmFyaWFuY2VzIGJhc2VkIG9uIGtub3duIHN0YW5kYXJkIGVycm9ycwogICAgZW1waXJpY2FsX3Igfn4gJyxzZTIsJyplbXBpcmljYWxfcgoKICAgICMgUmVsYXRpb25zaGlwIGJldHdlZW4gbGF0ZW50IHZhcmlhYmxlcwogICAgUGVhcnNvbkxhdGVudCB+fiBzeW50aGV0aWNfcgogICcpCgpmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gbWFuaWZlc3Rfc2NvcmVzKQpwdF9maXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gcHRfbWFuaWZlc3Rfc2NvcmVzKQoKCm1fbG1zeW50aF9yX3NjYWxlcyA8LSBicm0oCiAgYmYoZW1waXJpY2FsX3IgfCBtaShlbXBpcmljYWxfcl9zZSkgfiBzeW50aGV0aWNfciArICgxfG1tKHNjYWxlX2EsIHNjYWxlX2IpKSwKICAgICBzaWdtYSB+IHBvbHkoc3ludGhldGljX3IsIGRlZ3JlZSA9IDMpKSwgZGF0YSA9IG1hbmlmZXN0X3Njb3JlcywgCiAgZmlsZSA9ICJpZ25vcmUvbV9zeW50aF9yX3NjYWxlc19sbTgiKQoKc2Rfc3ludGggPC0gc2QobV9sbXN5bnRoX3Jfc2NhbGVzJGRhdGEkc3ludGhldGljX3IpCgoKbmV3ZGF0YSA8LSBtX2xtc3ludGhfcl9zY2FsZXMkZGF0YSAlPiUgc2VsZWN0KGVtcGlyaWNhbF9yLCBzeW50aGV0aWNfciwgZW1waXJpY2FsX3Jfc2UpCmVwcmVkcyA8LSBlcHJlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gbV9sbXN5bnRoX3Jfc2NhbGVzLCByZV9mb3JtdWxhID0gTkEpCnByZWRzIDwtIHByZWRpY3RlZF9kcmF3cyhuZXdkYXRhID0gbmV3ZGF0YSwgb2JqID0gbV9sbXN5bnRoX3Jfc2NhbGVzLCByZV9mb3JtdWxhID0gTkEpCmVwcmVkX3ByZWRzIDwtIGVwcmVkcyAlPiUgbGVmdF9qb2luKHByZWRzKQpieV9kcmF3IDwtIGVwcmVkX3ByZWRzICU+JSBncm91cF9ieSguZHJhdykgJT4lIAogIHN1bW1hcmlzZSguZXByZWQgPSB2YXIoLmVwcmVkKSwKICAgICAgICAgICAgLnByZWRpY3Rpb24gPSB2YXIoLnByZWRpY3Rpb24pLAogICAgICAgICAgICBzaWdtYSA9IHNxcnQoLnByZWRpY3Rpb24gLSAuZXByZWQpLAogICAgICAgICAgICBzZW1pX2xhdGVudF9yID0gc3FydCguZXByZWQvLnByZWRpY3Rpb24pKQoKYWNjdXJhY3lfYmF5ZXNfc2NhbGVzIDwtIGJ5X2RyYXcgJT4lIG1lYW5faGRjaShzZW1pX2xhdGVudF9yKQoKYmluZF9yb3dzKAogIHB0X3IgJT4lIAogICAgbXV0YXRlKG1vZGVsID0gInByZS10cmFpbmVkIiwga2luZCA9ICJtYW5pZmVzdCIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCksCiAgc3RhbmRhcmRpemVkc29sdXRpb24ocHRfZml0KSAlPiUgCiAgICBmaWx0ZXIobGhzID09ICJQZWFyc29uTGF0ZW50IiwgcmhzID09ICAic3ludGhldGljX3IiKSAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAicHJlLXRyYWluZWQiLCBraW5kID0gInNlbWktbGF0ZW50IChTRU0pIikgJT4lIAogICAgc2VsZWN0KG1vZGVsLCBraW5kLCBhY2N1cmFjeSA9IGVzdC5zdGQsIAogICAgICAgICAgIGNvbmYubG93ID0gY2kubG93ZXIsIGNvbmYuaGlnaCA9IGNpLnVwcGVyKSwKICByICU+JSAKICAgIG11dGF0ZShtb2RlbCA9ICJmaW5lLXR1bmVkIiwga2luZCA9ICJtYW5pZmVzdCIpICU+JSAKICAgIHNlbGVjdChtb2RlbCwga2luZCwgYWNjdXJhY3kgPSBlc3RpbWF0ZSwgY29uZi5sb3csIGNvbmYuaGlnaCksCiAgc3RhbmRhcmRpemVkc29sdXRpb24oZml0KSAlPiUgCiAgICBmaWx0ZXIobGhzID09ICJQZWFyc29uTGF0ZW50IiwgcmhzID09ICAic3ludGhldGljX3IiKSAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAic2VtaS1sYXRlbnQgKFNFTSkiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gZXN0LnN0ZCwgCiAgICAgICAgICAgY29uZi5sb3cgPSBjaS5sb3dlciwgY29uZi5oaWdoID0gY2kudXBwZXIpLAogIGFjY3VyYWN5X2JheWVzX3NjYWxlcyAlPiUgCiAgICBtdXRhdGUobW9kZWwgPSAiZmluZS10dW5lZCIsIGtpbmQgPSAic2VtaS1sYXRlbnQgKEJheWVzaWFuIEVJVikiKSAlPiUgCiAgICBzZWxlY3QobW9kZWwsIGtpbmQsIGFjY3VyYWN5ID0gc2VtaV9sYXRlbnRfciwgY29uZi5sb3cgPSAubG93ZXIsIGNvbmYuaGlnaCA9IC51cHBlcikKICApICU+JSAKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikKYGBgCgoKPGRldGFpbHM+PHN1bW1hcnk+PGg0PlByZWRpY3Rpb24gZXJyb3IgcGxvdCBhY2NvcmRpbmcgdG8gc3ludGhldGljIGVzdGltYXRlPC9oND48L3N1bW1hcnk+CgpgYGB7cn0KbV9sbXN5bnRoX3Jfc2NhbGVzCmJ5X2RyYXcgJT4lIG1lYW5faGRjaShzaWdtYSkKCnByZWQgPC0gY29uZGl0aW9uYWxfZWZmZWN0cyhtX2xtc3ludGhfcl9zY2FsZXMsIG1ldGhvZCA9ICJwcmVkaWN0IikKcGxvdChjb25kaXRpb25hbF9lZmZlY3RzKG1fbG1zeW50aF9yX3NjYWxlcywgZHBhciA9ICJzaWdtYSIpLCBwbG90ID0gRilbWzFdXSArIAogIHRoZW1lX2J3KCkgKyAKICB5bGFiKCJQcmVkaWN0aW9uIGVycm9yIChzaWdtYSkiKQpgYGAKCgo8L2RldGFpbHM+CgoKCiMjIyBTY2F0dGVyIHBsb3QKYGBge3J9CmdncGxvdChtYW5pZmVzdF9zY29yZXMsIGFlcyhzeW50aGV0aWNfciwgZW1waXJpY2FsX3IsIAogICAgICAgICAgICAgIHltaW4gPSBlbXBpcmljYWxfciAtIGVtcGlyaWNhbF9yX3NlLAogICAgICAgICAgICAgIHltYXggPSBlbXBpcmljYWxfciArIGVtcGlyaWNhbF9yX3NlKSkgKyAKICBnZW9tX2FibGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjMsIHNpemUgPSAxKSArCiAgZ2VvbV9zbW9vdGgoYWVzKAogICAgeCA9IHN5bnRoZXRpY19yLAogICAgeSA9IGVzdGltYXRlX18sCiAgICB5bWluID0gbG93ZXJfXywKICAgIHltYXggPSB1cHBlcl9fLAogICksIHN0YXQgPSAiaWRlbnRpdHkiLCAKICBjb2xvciA9ICIjYTQ4NTAwIiwKICBmaWxsID0gIiNFREM5NTEiLAogIGRhdGEgPSBhcy5kYXRhLmZyYW1lKHByZWQkc3ludGhldGljX3IpKSArCiAgeGxhYigiU3ludGhldGljIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJFbXBpcmljYWwgaW50ZXItc2NhbGUgY29ycmVsYXRpb24iKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoLTEsMSksIHlsaW0gPSBjKC0xLDEpKSAtPiBwbG90X3NjYWxlcwpwbG90X3NjYWxlcwpgYGAKCiMjIyBJbnRlcmFjdGl2ZSBwbG90CmBgYHtyfQoobWFuaWZlc3Rfc2NvcmVzICU+JSAKICBtdXRhdGUoc3ludGhldGljX3IgPSByb3VuZChzeW50aGV0aWNfciwgMiksCiAgICAgICAgIGVtcGlyaWNhbF9yID0gcm91bmQoZW1waXJpY2FsX3IsIDIpLAogICAgICAgICBzY2FsZXMgPSBzdHJfcmVwbGFjZV9hbGwoc3RyX2Moc2NhbGVfYSwgIlxuIiwgc2NhbGVfYiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXysiLCAiICIpKSAlPiUgCmdncGxvdCguLCBhZXMoc3ludGhldGljX3IsIGVtcGlyaWNhbF9yLCAKICAgICAgICAgICAgICAjIHltaW4gPSBlbXBpcmljYWxfciAtIGVtcGlyaWNhbF9yX3NlLCAKICAgICAgICAgICAgICAjIHltYXggPSBlbXBpcmljYWxfciArIGVtcGlyaWNhbF9yX3NlLCAKICAgICAgICAgICAgICBsYWJlbCA9IHNjYWxlcykpICsgCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC4zLCBzaXplID0gMSkgKwogIHhsYWIoIlN5bnRoZXRpYyBpbnRlci1zY2FsZSBjb3JyZWxhdGlvbiIpICsgCiAgeWxhYigiRW1waXJpY2FsIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xLDEpLCB5bGltID0gYygtMSwxKSkpICU+JSAKICBnZ3Bsb3RseSgpCmBgYAoKPGRldGFpbHM+PHN1bW1hcnk+VGFibGU8L3N1bW1hcnk+CgpgYGB7cn0KbWFuaWZlc3Rfc2NvcmVzICU+JSAKICAgICAgICAgICAgICAgIG11dGF0ZShlbXBpcmljYWxfciA9IHNwcmludGYoIiUuMmbCsSUuM2YiLCBlbXBpcmljYWxfciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW1waXJpY2FsX3Jfc2UpLAogICAgICAgICAgICAgICAgICAgICAgIHN5bnRoZXRpY19yID0gc3ByaW50ZigiJS4yZiIsIHN5bnRoZXRpY19yKSwKICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9hID0gc3RyX3JlcGxhY2VfYWxsKHNjYWxlX2EsICJfKyIsICIgIiksCiAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfYiA9IHN0cl9yZXBsYWNlX2FsbChzY2FsZV9iLCAiXysiLCAiICIpCiAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICAgICAgICAgICBzZWxlY3Qoc2NhbGVfYSwgc2NhbGVfYiwgZW1waXJpY2FsX3IsIHN5bnRoZXRpY19yKSAlPiUgCiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZmlsdGVyID0gInRvcCIpCmBgYAoKPC9kZXRhaWxzPgoKCgoKPGRldGFpbHM+PHN1bW1hcnk+PGgzPlJvYnVzdG5lc3MgY2hlY2tzPC9oMz48L3N1bW1hcnk+CgpIb3cgZG9lcyBudW1iZXIgb2YgaXRlbXMgYWNyb3NzIHRoZSB0d28gc2NhbGVzIHJlbGF0ZSB0byBhY2N1cmFjeT8KCmBgYHtyfQpieV9pdGVtX251bWJlciA8LSBtYW5pZmVzdF9zY29yZXMgJT4lCiAgbXV0YXRlKGl0ZW1zID0gbnVtYmVyX29mX2l0ZW1zLnggKyBudW1iZXJfb2ZfaXRlbXMueSkgJT4lCiAgZ3JvdXBfYnkoaXRlbXMpICU+JQogIHN1bW1hcmlzZShicm9vbTo6dGlkeShjb3IudGVzdChlbXBpcmljYWxfciwgc3ludGhldGljX3IpKSwgcGFpcndpc2VfbiA9IG4oKSkgCgpieV9pdGVtX251bWJlciAlPiUgCiAgZ2dwbG90KGFlcyhpdGVtcywgZXN0aW1hdGUsIHltaW4gPSBjb25mLmxvdywgeW1heCA9IGNvbmYuaGlnaCkpICsgCiAgZ2VvbV9wb2ludHJhbmdlKCkgKwogIHNjYWxlX3lfY29udGludW91cygiTWFuaWZlc3QgYWNjdXJhY3kgKHdpdGggOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwpIikgKwogIHhsYWIoIk51bWJlciBvZiBpdGVtcyBzdW1tZWQgYWNyb3NzIHNjYWxlcyIpCgpsbShlc3RpbWF0ZSB+IGl0ZW1zLCBieV9pdGVtX251bWJlciwgd2VpZ2h0cyA9IDEvKGJ5X2l0ZW1fbnVtYmVyJGNvbmYuaGlnaC1ieV9pdGVtX251bWJlciRjb25mLmxvdykpCgptYW5pZmVzdF9zY29yZXMgJT4lCiAgZmlsdGVyKG51bWJlcl9vZl9pdGVtcy54ID49IDEwLCBudW1iZXJfb2ZfaXRlbXMueSA+PSAxMCkgJT4lCiAgc3VtbWFyaXNlKGNvciA9IGNvcihlbXBpcmljYWxfciwgc3ludGhldGljX3IpLCBuKCkpCmBgYAoKCklzIHRoZSBhY2N1cmFjeSBsb3dlciBmb3IgdGhlIHByZS10cmFpbmVkIG1vZGVsPwoKYGBge3J9CmdncGxvdChwdF9tYW5pZmVzdF9zY29yZXMsIGFlcyhzeW50aGV0aWNfciwgZW1waXJpY2FsX3IsIAogICAgICAgICAgICAgIHltaW4gPSBlbXBpcmljYWxfciAtIGVtcGlyaWNhbF9yX3NlLAogICAgICAgICAgICAgIHltYXggPSBlbXBpcmljYWxfciArIGVtcGlyaWNhbF9yX3NlKSkgKyAKICBnZW9tX2FibGluZShsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjMsIHNpemUgPSAxKSArCiAgeGxhYigiU3ludGhldGljIGludGVyLXNjYWxlIGNvcnJlbGF0aW9uIikgKyAKICB5bGFiKCJFbXBpcmljYWwgaW50ZXItc2NhbGUgY29ycmVsYXRpb24iKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZml4ZWQoeGxpbSA9IGMoLTEsMSksIHlsaW0gPSBjKC0xLDEpKSAtPiBwdF9wbG90X3NjYWxlcwpwdF9wbG90X3NjYWxlcwpgYGAKCgo8L2RldGFpbHM+CgoKCgojIyBDb21iaW5lZCBwbG90CgpgYGB7ciBmaWcud2lkdGggPSA4LjMsIGZpZy5oZWlnaHQgPSA2fQpsaWJyYXJ5KHBhdGNod29yaykKcHRfcGxvdF9pdGVtczIgPC0gcHRfcGxvdF9pdGVtcyArCiAgICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAwLjUsIHkgPSAtMC44LCB2anVzdCA9IDEsIGhqdXN0ID0gMSwgbGFiZWwgPSAicihJIGZlYXIgZm9yIHRoZSB3b3JzdCxcbkkgbmV2ZXIgd29ycnkgYWJvdXQgYW55dGhpbmcpIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLCB5ID0gLTAuNzgsIHhlbmQgPSAwLjI3NjE5MDYsIHllbmQgPSAtMC4zNDU5NzExLCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtLjEsIHkgPSAwLjUsIGhqdXN0ID0gMSwgbGFiZWwgPSAicihJIGdldCBhbmdyeSBlYXNpbHksXG5JIGxvc2UgbXkgdGVtcGVyKSIsIGNvbG9yID0gIiMwMEEwQjAiKSArIAogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IC0uMSwgeSA9IDAuNSwgeGVuZCA9IDAuNjkzNTcxMSwgeWVuZCA9IDAuNzE0MDU0NiwgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KQogIAoKcGxvdF9pdGVtczIgPC0gcGxvdF9pdGVtcyArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMywgeCA9IC0xLCB5ID0gMC45OCwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChhY2N1cmFjeV9iYXllc19pdGVtcywgeyBzcHJpbnRmKCJhY2N1cmFjeSA9ICUuMmYgWyUuMmY7JS4yZl0iLCBzZW1pX2xhdGVudF9yLCAubG93ZXIsIC51cHBlcikgfSkpICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAwLjUsIHkgPSAtMC44LCB2anVzdCA9IDEsIGhqdXN0ID0gMSwgbGFiZWwgPSAicihJIGZlYXIgZm9yIHRoZSB3b3JzdCxcbkkgbmV2ZXIgd29ycnkgYWJvdXQgYW55dGhpbmcpIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLCB5ID0gLTAuNzgsIHhlbmQgPSAtMC4xMTA0Njg2LCB5ZW5kID0gLTAuMzQ1OTcxMSwgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLS4xLCB5ID0gMC41LCBoanVzdCA9IDEsIGxhYmVsID0gInIoSSBnZXQgYW5ncnkgZWFzaWx5LFxuSSBsb3NlIG15IHRlbXBlcikiLCBjb2xvciA9ICIjMDBBMEIwIikgKyAKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjEsIHkgPSAwLjUsIHhlbmQgPSAwLjgwMzE5NzksIHllbmQgPSAwLjcxNDA1NDYsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykKICAjIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDIuNSwgeCA9IC0wLjUsIHkgPSAtMC44LCBoanVzdCA9IDAsIGxhYmVsID0gInIoSSBsb3ZlIGxpZmUsXG5JIGF2b2lkIGNyb3dkcykiLCBjb2xvciA9ICIjMDBBMEIwIikgKwogICMgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gLS4zLCB5ID0gLTAuNywgeGVuZCA9IC0wLjIzLCB5ZW5kID0gLTAuMjgsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykgKwogICMgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLS4zLCB5ID0gMC41LCBoanVzdCA9IDEsIGxhYmVsID0gInIoSSB3b3JrIGhhcmQsXG5JIGFtIGRpbGlnZW50KSIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgIyBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjMsIHkgPSAuNSwgeGVuZCA9IC41MiwgeWVuZCA9IC41OCwgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KQoKCnB0X3Bsb3RfcmVsczIgPC0gcHRfcGxvdF9yZWxzICsgCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gMC42MSwgeSA9IDAuMjUsIGhqdXN0ID0gMCwgbGFiZWwgPSAiSVBJUCBFeHRyYXZlcnNpb24iLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDAuNywgeSA9IDAuMjcsIHhlbmQgPSAwLjksIHllbmQgPSAwLjkwLCBjb2xvciA9ICIjMDBBMEIwIiwgYWxwaGEgPSAwLjcpICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtMC4wMiwgeSA9IDAuOTUsIGhqdXN0ID0gMCwgbGFiZWwgPSAiTE9UIE9wdGltaXNtIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAwLjExLCB5ID0gMC45MywgeGVuZCA9IC0xLjQ3NzIyNiwgeWVuZCA9IDAuNzEsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykKCnBsb3RfcmVsczIgPC0gcGxvdF9yZWxzICsgCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMywgeCA9IDAsIHkgPSAuOTg1LCB2anVzdCA9IDAsIGhqdXN0ID0gMCwgbGFiZWwgPSB3aXRoKGFjY3VyYWN5X2JheWVzX3JlbHMsIHsgc3ByaW50ZigiYWNjdXJhY3kgPSAlLjJmIFslLjJmOyUuMmZdIiwgc2VtaV9sYXRlbnRfciwgLmxvd2VyLCAudXBwZXIpIH0pKSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gMC40LCB5ID0gMC4xLCBoanVzdCA9IDAsIGxhYmVsID0gInJhbmRvbWx5IGZvcm1lZCBzY2FsZXMiLCBjb2xvciA9ICIjNkE0QTNDIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDAuMzk1LCB5ID0gMC4xLCB4ZW5kID0gMC4zOSwgeWVuZCA9IDAuNDg2NDI5NywgY29sb3IgPSAiIzZBNEEzQyIsIGFscGhhID0gMC43KSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMC4zOTUsIHkgPSAwLjEsIHhlbmQgPSAwLjI4NSwgeWVuZCA9IDAuMjI3OTkxOSwgY29sb3IgPSAiIzZBNEEzQyIsIGFscGhhID0gMC43KSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMC4zOTUsIHkgPSAwLjEsIHhlbmQgPSAwLjIsIHllbmQgPSAwLjA3NSwgY29sb3IgPSAiIzZBNEEzQyIsIGFscGhhID0gMC43KSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gMC42MSwgeSA9IDAuNCwgaGp1c3QgPSAwLCBsYWJlbCA9ICJJUElQIEV4dHJhdmVyc2lvbiIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMC43NSwgeSA9IDAuNDIsIHhlbmQgPSAwLjg3LCB5ZW5kID0gMC45MCwgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLTAuMDIsIHkgPSAwLjg2LCBoanVzdCA9IDAsIGxhYmVsID0gIkxPVCBPcHRpbWlzbSIsIGNvbG9yID0gIiMwMEEwQjAiKSArCiAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMC4xMSwgeSA9IDAuODMsIHhlbmQgPSAwLjE1LCB5ZW5kID0gMC43MSwgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KQoKcHRfcGxvdF9zY2FsZXMyIDwtIHB0X3Bsb3Rfc2NhbGVzICsKICBhbm5vdGF0ZSgidGV4dCIsIHNpemUgPSAyLjUsIHggPSAtMC4yLCB5ID0gMC44LCBoanVzdCA9IDEsIGxhYmVsID0gInIoQkZJIE5ldXJvdGljaXNtLFxuSVBJUCBOZXVyb3RpY2lzbSkiLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IC0uMiwgeSA9IDAuOCwgeGVuZCA9IDAuMjIsIHllbmQgPSAuODQsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykgKwogIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDIuNSwgeCA9IC0uMSwgeSA9IC0wLjksIGhqdXN0ID0gMCwgbGFiZWwgPSAicihCRkkgRGVwcmVzc2lvbiBmYWNldCxcbkxPVCBPcHRpbWlzbSkiLCBjb2xvciA9ICIjMDBBMEIwIikgKwogIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IC0uMSwgeSA9IC0uOSwgeGVuZCA9IC0wLjE3LCB5ZW5kID0gLS42MywgY29sb3IgPSAiIzAwQTBCMCIsIGFscGhhID0gMC43KQoKCnBsb3Rfc2NhbGVzMiA8LSBwbG90X3NjYWxlcyArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMywgeCA9IC0xLCB5ID0gMC45OCwgdmp1c3QgPSAwLCBoanVzdCA9IDAsIGxhYmVsID0gd2l0aChhY2N1cmFjeV9iYXllc19zY2FsZXMsIHsgc3ByaW50ZigiYWNjdXJhY3kgPSAlLjJmIFslLjJmOyUuMmZdIiwgc2VtaV9sYXRlbnRfciwgLmxvd2VyLCAudXBwZXIpIH0pKSArCiAgYW5ub3RhdGUoInRleHQiLCBzaXplID0gMi41LCB4ID0gLTAuMSwgeSA9IDAuNSwgaGp1c3QgPSAxLCBsYWJlbCA9ICJyKEJGSSBOZXVyb3RpY2lzbSxcbklQSVAgTmV1cm90aWNpc20pIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjEsIHkgPSAwLjUsIHhlbmQgPSAuODQsIHllbmQgPSAuODQsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykgKwogIGFubm90YXRlKCJ0ZXh0Iiwgc2l6ZSA9IDIuNSwgeCA9IC0uMTUsIHkgPSAtMC43LCBoanVzdCA9IDAsIGxhYmVsID0gInIoQkZJIERlcHJlc3Npb24gZmFjZXQsXG5MT1QgT3B0aW1pc20pIiwgY29sb3IgPSAiIzAwQTBCMCIpICsKICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAtLjE1LCB5ID0gLS43LCB4ZW5kID0gLS4zNCwgeWVuZCA9IC0uNjMsIGNvbG9yID0gIiMwMEEwQjAiLCBhbHBoYSA9IDAuNykKCgoocHRfcGxvdF9pdGVtczIrCiAgICBwdF9wbG90X3JlbHMyICsgZ2d0aXRsZSgiIikgKwogICAgcHRfcGxvdF9zY2FsZXMyKSAvCgoKKHBsb3RfaXRlbXMyICsKICAgIHBsb3RfcmVsczIgKyBnZ3RpdGxlKCJTdXJ2ZXlCb3QgMzAwMCIpICArCiAgICBwbG90X3NjYWxlczIpICsKICBwbG90X2Fubm90YXRpb24oCiAgdGl0bGUgPSAnUHJlLXRyYWluZWQgbW9kZWwgYmVmb3JlIGRvbWFpbiBhZGFwdGF0aW9uIGFuZCBmaW5lLXR1bmluZycKKQoKZ2dzYXZlKCJpZ25vcmUvRmlndXJlX3BpbG90LnBkZiIsIHdpZHRoID0gOC4zLCBoZWlnaHQgPSA2LCBkZXZpY2UgPSBnckRldmljZXM6OmNhaXJvX3BkZikKZ2dzYXZlKCJpZ25vcmUvRmlndXJlX3BpbG90LnBuZyIsIHdpZHRoID0gOC4zLCBoZWlnaHQgPSA2KQoKCgojIGdnc2F2ZSgiaWdub3JlL0ZpZ3VyZV9waWxvdC5zdmciLCB3aWR0aCA9IDguMywgaGVpZ2h0ID0gNS41LCBkZXZpY2UgPSBzdmdsaXRlOjpzdmdsaXRlKQpgYGAKCg==