Load data

rr_validation_mapping_data = arrow::read_feather(
  file = "https://github.com/synth-science/surveybot3000/raw/refs/heads/main/validation_study/mapping.feather"
)

items <- rio::import("https://docs.google.com/spreadsheets/d/16QcRLP5BUn1Cmtr0e_XRdjr1Wg-EHSMSGmgZO1M3tNM/edit?gid=0#gid=0", which = 2)

# compare <- rr_validation_mapping_data %>% full_join(items %>% filter(in_survey) %>% select(id, scale, subscale, item), by = c("variable" = "id")) %>% mutate(subscale = if_else(subscale == "#N/A", NA_character_, subscale))
# compare %>% filter(item_text != item) %>% View()
# compare %>% filter((scale0 != scale | scale1 != subscale)) %>% View()
# compare %>% filter((scale0 != scale | scale1 != subscale) & !(scale1 == scale & scale0 == subscale)) %>% View()
# rr_validation_mapping_data %>% anti_join(items, by = c("scale0" = "scale", "scale1" = "subscale")) %>% View

scales <- rr_validation_mapping_data %>% 
  select(-scale0, -scale1) %>% 
  left_join(items %>% 
              filter(in_survey) %>% 
              mutate(keyed = if_else(reversed, -1, 1)) %>% 
              select(id, keyed, scale, subscale), by = c("variable" = "id")) %>% 
  rename(scale_0 = scale, scale_1 = subscale) %>% 
  mutate(scale_1 = if_else(scale_1 == "#N/A", "", scale_1))

rr_validation_mapping_data <- scales %>% 
  rename(scale0 = scale_0, scale1 = scale_1)

scales <- bind_rows(
  scales %>% 
      mutate(
        scale_1 = "",
         scale = str_replace_all(str_trim(paste0(instrument, "_", scale_0, scale_1)), "[^a-zA-Z_0-9]", "_")
  ) %>% 
    group_by(scale) %>% 
    mutate(number_of_items = n()),
  scales %>% 
    mutate(
      scale_1 = coalesce(scale_1, ""),
      scale = str_replace_all(str_trim(paste0(instrument, "_", scale_0, scale_1)), "[^a-zA-Z_0-9]", "_")) %>% 
    group_by(scale) %>% 
    mutate(number_of_items = n())
  ) %>% 
  group_by(scale) %>% 
  filter(row_number() == 1) %>% 
  ungroup() %>% 
  select(-variable, -item_text) %>% 
  filter(number_of_items > 1)

arrow::write_feather(scales, sink = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.scales.feather"))
)

arrow::write_feather(rr_validation_mapping_data, sink = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.mapping2.feather"))
)


# pre-trained model
pt_rr_validation_machine_data = rio::import("https://github.com/synth-science/surveybot3000/raw/refs/heads/main/validation_study/embeddings_all-mpnet-base-v2.feather")
pt_rr_validation_machine_data <- pt_rr_validation_machine_data %>% 
  rowwise() %>% 
  mutate(embed_id = list(1:length(embeddings))) %>% 
  unnest(cols = c(embeddings, embed_id)) %>% 
  select(-item) %>% 
  pivot_wider(names_from = id, values_from = embeddings) %>% 
  select(-embed_id)

# fine-tuned model
rr_validation_machine_data = rio::import("https://github.com/synth-science/surveybot3000/raw/refs/heads/main/validation_study/embeddings_surveybot3000.feather")
rr_validation_machine_data <- rr_validation_machine_data %>% 
  rowwise() %>% 
  mutate(embed_id = list(1:length(embeddings))) %>% 
  unnest(cols = c(embeddings, embed_id)) %>% 
  select(-item) %>% 
  pivot_wider(names_from = id, values_from = embeddings) %>% 
  select(-embed_id)
  
main_qs <- c("AAID", "PANAS", "PAQ", "PSS", "NEPS", "ULS", "FCV", "DAQ", "CESD", "HEXACO", "OCIR", "PTQ", "RAAS", "KSA", "SAS", "MFQ", "CQ", "OLBI", "UWES", "WGS")
rr_validation_human_data = rio::import("data/processed/sosci_labelled_with_exclusion_criteria.rds") %>% filter(included) %>% 
    select(starts_with(main_qs)) %>% 
    select(-ends_with("_R"))
## Warning: Missing `trust` will be set to FALSE by default for RDS in 2.0.0.
rio::export(rr_validation_human_data, file = file.path(data_path, glue("{model_name}.raw.validation-study-2024-11-01.human.feather"))
)


setdiff(colnames(rr_validation_human_data), rr_validation_mapping_data$variable)
## character(0)
setdiff(rr_validation_mapping_data$variable, colnames(rr_validation_human_data))
## character(0)

Description

nrow(rr_validation_human_data) # respondents
## [1] 387
ncol(rr_validation_human_data) # items
## [1] 246
nrow(rr_validation_machine_data) # vector dimensions
## [1] 768
ncol(rr_validation_machine_data) # items
## [1] 246
n_distinct(rr_validation_mapping_data$instrument) # instruments
## [1] 20
n_distinct(rr_validation_mapping_data$scale0) # constructs
## [1] 40
n_distinct(rr_validation_mapping_data$instrument, rr_validation_mapping_data$scale0) # scales
## [1] 40
n_distinct(str_c(rr_validation_mapping_data$instrument, rr_validation_mapping_data$scale0, rr_validation_mapping_data$scale1)) # subscales
## [1] 70
scales %>% tally()
## # A tibble: 1 × 1
##       n
##   <int>
## 1    80
scales %>% filter(number_of_items > 2) %>% tally()
## # A tibble: 1 × 1
##       n
##   <int>
## 1    57

Join pairwise item correlations

rr_validation_item_pairs = join_pairwise_correlation(rr_validation_human_data, rr_validation_machine_data)

arrow::write_feather(rr_validation_item_pairs, sink = file.path(data_path, glue("data/intermediate/{model_name}.raw.validation-study-2024-11-01.item_correlations.feather")))

pt_rr_validation_item_pairs = join_pairwise_correlation(rr_validation_human_data, pt_rr_validation_machine_data)

arrow::write_feather(pt_rr_validation_item_pairs, sink = file.path(data_path, glue("data/intermediate/{pretrained_model_name}.raw.validation-study-2024-11-01.item_correlations.feather")))

Join pairwise scale correlations

manifest_scores = predict_manifest_scores(rr_validation_human_data, rr_validation_machine_data, rr_validation_mapping_data, scales)
## Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if
## `.name_repair` is omitted as of tibble 2.0.0.
## ℹ Using compatibility `.name_repair`.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
arrow::write_feather(manifest_scores, sink = file.path(data_path, glue("data/intermediate/{model_name}.raw.validation-study-2024-11-01.scale_correlations.feather")))

pt_manifest_scores = predict_manifest_scores(rr_validation_human_data, pt_rr_validation_machine_data, rr_validation_mapping_data, scales)

arrow::write_feather(pt_manifest_scores, sink = file.path(data_path, glue("data/intermediate/{pretrained_model_name}.raw.validation-study-2024-11-01.scale_correlations.feather")))

Create random scales

mapping_data <- rr_validation_mapping_data %>%
  rename(scale_0 = scale0,
         scale_1 = scale1)

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

random_scales <- list()
for(i in 1:200) {
  n_items <- rpois(1, 6)
  n_items <- if_else(n_items < 3, 3, n_items)
  random_scales[[i]] <- rr_validation_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) %>% 
  distinct(items, .keep_all = TRUE) %>% 
  rowwise() %>% 
  mutate(
    reverse_items = list(randomly_choose_items_for_reversion(items))
    ) %>% 
  ungroup()
nrow(random_scales)
## [1] 200
write_rds(random_scales, file = file.path(data_path, glue("data/intermediate/random_scales_rr.rds")))


rr_validation_llm <- rr_validation_item_pairs %>%
  left_join(mapping_data %>% select(variable_1 = variable, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1)) %>%
  left_join(mapping_data %>% select(variable_2 = variable, InstrumentB = instrument, ScaleB = scale_0, SubscaleB = scale_1))
## Joining with `by = join_by(variable_1)`
## Joining with `by = join_by(variable_2)`
pt_rr_validation_llm <- pt_rr_validation_item_pairs %>%
  left_join(mapping_data %>% select(variable_1 = variable, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1)) %>%
  left_join(mapping_data %>% select(variable_2 = variable, InstrumentB = instrument, ScaleB = scale_0, SubscaleB = scale_1))
## Joining with `by = join_by(variable_1)`
## Joining with `by = join_by(variable_2)`
cors_llm <- rr_validation_item_pairs %>%
  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_rr_validation_item_pairs %>%
  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 <- rr_validation_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

real_scales <- items_by_scale %>%
  group_by(scale) %>%
  summarise(
    items = list(variable),
    reverse_items = list(variable[keyed == -1]),
    number_of_items = n_distinct(variable),
    keyed = first(keyed),
    lvn = paste(first(scale), " =~ ", paste(variable, collapse = " + "))) %>%
  drop_na() %>% 
  ungroup()

scales <- bind_rows(real = real_scales, random = random_scales, .id = "type")

rr_validation_human_data <- rr_validation_human_data %>% haven::zap_labels()
scales <- scales %>%
  rowwise() %>%
  mutate(pt_r_llm = list(pt_cors_llm[items, items]),
         r_llm = list(cors_llm[items, items]),
         r_real = list(cors_real[items, items]),
         reverse_items_by_1st = list(find_reverse_items_by_first_item(r_real, keyed)),
         N_real = rr_validation_item_pairs %>% 
           filter(variable_1 %in% items, variable_2 %in% items) %>% 
           summarise(min_n=min(pairwise_n)) %>% pull(min_n)) %>%
  mutate(
    rel_real = list(psych::alpha(rr_validation_human_data[, items], keys = reverse_items, n.iter = 1000)),
    rel_llm = list(psych::alpha(r_llm, keys = reverse_items, n.obs = N_real)$feldt),
    rel_pt_llm = list(psych::alpha(pt_r_llm, keys = reverse_items, n.obs = N_real)$feldt)) %>%
  mutate(empirical_alpha = rel_real$feldt$alpha$raw_alpha,
         synthetic_alpha = rel_llm$alpha$raw_alpha,
         pt_synthetic_alpha = rel_pt_llm$alpha$raw_alpha) %>%
  mutate(
    empirical_alpha_se = sd(rel_real$boot[,"raw_alpha"]),
  )
## Warning: There were 330 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `rel_real = list(...)`.
## ℹ In row 81.
## Caused by warning in `sqrt()`:
## ! NaNs produced
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 329 remaining warnings.
write_rds(scales, file = file.path(data_path, glue("data/intermediate/scales_with_alpha_se_rr.rds")))
LS0tCnRpdGxlOiAiVmVjdG9yIHJlcHJlc2VudGF0aW9ucyB0byBjb3NpbmUgc2ltaWxhcml0aWVzIgpvdXRwdXQ6IGh0bWxfZG9jdW1lbnQKZGF0ZTogIjIwMjQtMDItMDkiCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0Usd2FybmluZz1GLG1lc3NhZ2U9Rn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBlcnJvciA9IFQpCgojIExpYnJhcmllcyBhbmQgU2V0dGluZ3MKCiMgTGlicyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoYXJyb3cpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShwc3ljaCkKbGlicmFyeShsYXZhYW4pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoZ3JpZEV4dHJhKQoKbW9kZWxfbmFtZSA9ICJJdGVtU2ltaWxhcml0eVRyYWluaW5nLTIwMjQwNTAyLXRyaWFsMTIiCiNtb2RlbF9uYW1lID0gIml0ZW0tc2ltaWxhcml0eS0yMDIzMTAxOC0xMjI1MDQiCnByZXRyYWluZWRfbW9kZWxfbmFtZSA9ICJhbGwtbXBuZXQtYmFzZS12MiIKCmRhdGFfcGF0aCA9IGdsdWUoIi4vIikKcHJldHJhaW5lZF9kYXRhX3BhdGggPSBnbHVlKCIuLyIpCgpzZXQuc2VlZCg0MikKc291cmNlKCJnbG9iYWxfZnVuY3Rpb25zLlIiKQpgYGAKCgojIyBMb2FkIGRhdGEKYGBge3J9CnJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhID0gYXJyb3c6OnJlYWRfZmVhdGhlcigKICBmaWxlID0gImh0dHBzOi8vZ2l0aHViLmNvbS9zeW50aC1zY2llbmNlL3N1cnZleWJvdDMwMDAvcmF3L3JlZnMvaGVhZHMvbWFpbi92YWxpZGF0aW9uX3N0dWR5L21hcHBpbmcuZmVhdGhlciIKKQoKaXRlbXMgPC0gcmlvOjppbXBvcnQoImh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzE2UWNSTFA1QlVuMUNtdHIwZV9YUmRqcjFXZy1FSFNNU0dtZ1pPMU0zdE5NL2VkaXQ/Z2lkPTAjZ2lkPTAiLCB3aGljaCA9IDIpCgojIGNvbXBhcmUgPC0gcnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEgJT4lIGZ1bGxfam9pbihpdGVtcyAlPiUgZmlsdGVyKGluX3N1cnZleSkgJT4lIHNlbGVjdChpZCwgc2NhbGUsIHN1YnNjYWxlLCBpdGVtKSwgYnkgPSBjKCJ2YXJpYWJsZSIgPSAiaWQiKSkgJT4lIG11dGF0ZShzdWJzY2FsZSA9IGlmX2Vsc2Uoc3Vic2NhbGUgPT0gIiNOL0EiLCBOQV9jaGFyYWN0ZXJfLCBzdWJzY2FsZSkpCiMgY29tcGFyZSAlPiUgZmlsdGVyKGl0ZW1fdGV4dCAhPSBpdGVtKSAlPiUgVmlldygpCiMgY29tcGFyZSAlPiUgZmlsdGVyKChzY2FsZTAgIT0gc2NhbGUgfCBzY2FsZTEgIT0gc3Vic2NhbGUpKSAlPiUgVmlldygpCiMgY29tcGFyZSAlPiUgZmlsdGVyKChzY2FsZTAgIT0gc2NhbGUgfCBzY2FsZTEgIT0gc3Vic2NhbGUpICYgIShzY2FsZTEgPT0gc2NhbGUgJiBzY2FsZTAgPT0gc3Vic2NhbGUpKSAlPiUgVmlldygpCiMgcnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEgJT4lIGFudGlfam9pbihpdGVtcywgYnkgPSBjKCJzY2FsZTAiID0gInNjYWxlIiwgInNjYWxlMSIgPSAic3Vic2NhbGUiKSkgJT4lIFZpZXcKCnNjYWxlcyA8LSBycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSAlPiUgCiAgc2VsZWN0KC1zY2FsZTAsIC1zY2FsZTEpICU+JSAKICBsZWZ0X2pvaW4oaXRlbXMgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihpbl9zdXJ2ZXkpICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoa2V5ZWQgPSBpZl9lbHNlKHJldmVyc2VkLCAtMSwgMSkpICU+JSAKICAgICAgICAgICAgICBzZWxlY3QoaWQsIGtleWVkLCBzY2FsZSwgc3Vic2NhbGUpLCBieSA9IGMoInZhcmlhYmxlIiA9ICJpZCIpKSAlPiUgCiAgcmVuYW1lKHNjYWxlXzAgPSBzY2FsZSwgc2NhbGVfMSA9IHN1YnNjYWxlKSAlPiUgCiAgbXV0YXRlKHNjYWxlXzEgPSBpZl9lbHNlKHNjYWxlXzEgPT0gIiNOL0EiLCAiIiwgc2NhbGVfMSkpCgpycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSA8LSBzY2FsZXMgJT4lIAogIHJlbmFtZShzY2FsZTAgPSBzY2FsZV8wLCBzY2FsZTEgPSBzY2FsZV8xKQoKc2NhbGVzIDwtIGJpbmRfcm93cygKICBzY2FsZXMgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgc2NhbGVfMSA9ICIiLAogICAgICAgICBzY2FsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJfdHJpbShwYXN0ZTAoaW5zdHJ1bWVudCwgIl8iLCBzY2FsZV8wLCBzY2FsZV8xKSksICJbXmEtekEtWl8wLTldIiwgIl8iKQogICkgJT4lIAogICAgZ3JvdXBfYnkoc2NhbGUpICU+JSAKICAgIG11dGF0ZShudW1iZXJfb2ZfaXRlbXMgPSBuKCkpLAogIHNjYWxlcyAlPiUgCiAgICBtdXRhdGUoCiAgICAgIHNjYWxlXzEgPSBjb2FsZXNjZShzY2FsZV8xLCAiIiksCiAgICAgIHNjYWxlID0gc3RyX3JlcGxhY2VfYWxsKHN0cl90cmltKHBhc3RlMChpbnN0cnVtZW50LCAiXyIsIHNjYWxlXzAsIHNjYWxlXzEpKSwgIlteYS16QS1aXzAtOV0iLCAiXyIpKSAlPiUgCiAgICBncm91cF9ieShzY2FsZSkgJT4lIAogICAgbXV0YXRlKG51bWJlcl9vZl9pdGVtcyA9IG4oKSkKICApICU+JSAKICBncm91cF9ieShzY2FsZSkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgPT0gMSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KC12YXJpYWJsZSwgLWl0ZW1fdGV4dCkgJT4lIAogIGZpbHRlcihudW1iZXJfb2ZfaXRlbXMgPiAxKQoKYXJyb3c6OndyaXRlX2ZlYXRoZXIoc2NhbGVzLCBzaW5rID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy52YWxpZGF0aW9uLXN0dWR5LTIwMjQtMTEtMDEuc2NhbGVzLmZlYXRoZXIiKSkKKQoKYXJyb3c6OndyaXRlX2ZlYXRoZXIocnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEsIHNpbmsgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJ7bW9kZWxfbmFtZX0ucmF3LnZhbGlkYXRpb24tc3R1ZHktMjAyNC0xMS0wMS5tYXBwaW5nMi5mZWF0aGVyIikpCikKCgojIHByZS10cmFpbmVkIG1vZGVsCnB0X3JyX3ZhbGlkYXRpb25fbWFjaGluZV9kYXRhID0gcmlvOjppbXBvcnQoImh0dHBzOi8vZ2l0aHViLmNvbS9zeW50aC1zY2llbmNlL3N1cnZleWJvdDMwMDAvcmF3L3JlZnMvaGVhZHMvbWFpbi92YWxpZGF0aW9uX3N0dWR5L2VtYmVkZGluZ3NfYWxsLW1wbmV0LWJhc2UtdjIuZmVhdGhlciIpCnB0X3JyX3ZhbGlkYXRpb25fbWFjaGluZV9kYXRhIDwtIHB0X3JyX3ZhbGlkYXRpb25fbWFjaGluZV9kYXRhICU+JSAKICByb3d3aXNlKCkgJT4lIAogIG11dGF0ZShlbWJlZF9pZCA9IGxpc3QoMTpsZW5ndGgoZW1iZWRkaW5ncykpKSAlPiUgCiAgdW5uZXN0KGNvbHMgPSBjKGVtYmVkZGluZ3MsIGVtYmVkX2lkKSkgJT4lIAogIHNlbGVjdCgtaXRlbSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpZCwgdmFsdWVzX2Zyb20gPSBlbWJlZGRpbmdzKSAlPiUgCiAgc2VsZWN0KC1lbWJlZF9pZCkKCiMgZmluZS10dW5lZCBtb2RlbApycl92YWxpZGF0aW9uX21hY2hpbmVfZGF0YSA9IHJpbzo6aW1wb3J0KCJodHRwczovL2dpdGh1Yi5jb20vc3ludGgtc2NpZW5jZS9zdXJ2ZXlib3QzMDAwL3Jhdy9yZWZzL2hlYWRzL21haW4vdmFsaWRhdGlvbl9zdHVkeS9lbWJlZGRpbmdzX3N1cnZleWJvdDMwMDAuZmVhdGhlciIpCnJyX3ZhbGlkYXRpb25fbWFjaGluZV9kYXRhIDwtIHJyX3ZhbGlkYXRpb25fbWFjaGluZV9kYXRhICU+JSAKICByb3d3aXNlKCkgJT4lIAogIG11dGF0ZShlbWJlZF9pZCA9IGxpc3QoMTpsZW5ndGgoZW1iZWRkaW5ncykpKSAlPiUgCiAgdW5uZXN0KGNvbHMgPSBjKGVtYmVkZGluZ3MsIGVtYmVkX2lkKSkgJT4lIAogIHNlbGVjdCgtaXRlbSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpZCwgdmFsdWVzX2Zyb20gPSBlbWJlZGRpbmdzKSAlPiUgCiAgc2VsZWN0KC1lbWJlZF9pZCkKICAKbWFpbl9xcyA8LSBjKCJBQUlEIiwgIlBBTkFTIiwgIlBBUSIsICJQU1MiLCAiTkVQUyIsICJVTFMiLCAiRkNWIiwgIkRBUSIsICJDRVNEIiwgIkhFWEFDTyIsICJPQ0lSIiwgIlBUUSIsICJSQUFTIiwgIktTQSIsICJTQVMiLCAiTUZRIiwgIkNRIiwgIk9MQkkiLCAiVVdFUyIsICJXR1MiKQpycl92YWxpZGF0aW9uX2h1bWFuX2RhdGEgPSByaW86OmltcG9ydCgiLi4vc3ludGgtcmVwLWRhdGFzZXQvZGF0YS9wcm9jZXNzZWQvc29zY2lfbGFiZWxsZWRfd2l0aF9leGNsdXNpb25fY3JpdGVyaWEucmRzIikgJT4lIGZpbHRlcihpbmNsdWRlZCkgJT4lIAoJc2VsZWN0KHN0YXJ0c193aXRoKG1haW5fcXMpKSAlPiUgCglzZWxlY3QoLWVuZHNfd2l0aCgiX1IiKSkKCnJpbzo6ZXhwb3J0KHJyX3ZhbGlkYXRpb25faHVtYW5fZGF0YSwgZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLmh1bWFuLmZlYXRoZXIiKSkKKQoKCnNldGRpZmYoY29sbmFtZXMocnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhKSwgcnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEkdmFyaWFibGUpCnNldGRpZmYocnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEkdmFyaWFibGUsIGNvbG5hbWVzKHJyX3ZhbGlkYXRpb25faHVtYW5fZGF0YSkpCmBgYAoKIyMgRGVzY3JpcHRpb24KYGBge3J9Cm5yb3cocnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhKSAjIHJlc3BvbmRlbnRzCm5jb2wocnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhKSAjIGl0ZW1zCm5yb3cocnJfdmFsaWRhdGlvbl9tYWNoaW5lX2RhdGEpICMgdmVjdG9yIGRpbWVuc2lvbnMKbmNvbChycl92YWxpZGF0aW9uX21hY2hpbmVfZGF0YSkgIyBpdGVtcwpuX2Rpc3RpbmN0KHJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhJGluc3RydW1lbnQpICMgaW5zdHJ1bWVudHMKbl9kaXN0aW5jdChycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSRzY2FsZTApICMgY29uc3RydWN0cwpuX2Rpc3RpbmN0KHJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhJGluc3RydW1lbnQsIHJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhJHNjYWxlMCkgIyBzY2FsZXMKbl9kaXN0aW5jdChzdHJfYyhycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSRpbnN0cnVtZW50LCBycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSRzY2FsZTAsIHJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhJHNjYWxlMSkpICMgc3Vic2NhbGVzCnNjYWxlcyAlPiUgdGFsbHkoKQpzY2FsZXMgJT4lIGZpbHRlcihudW1iZXJfb2ZfaXRlbXMgPiAyKSAlPiUgdGFsbHkoKQpgYGAKCgojIyBKb2luIHBhaXJ3aXNlIGl0ZW0gY29ycmVsYXRpb25zCmBgYHtyfQpycl92YWxpZGF0aW9uX2l0ZW1fcGFpcnMgPSBqb2luX3BhaXJ3aXNlX2NvcnJlbGF0aW9uKHJyX3ZhbGlkYXRpb25faHVtYW5fZGF0YSwgcnJfdmFsaWRhdGlvbl9tYWNoaW5lX2RhdGEpCgphcnJvdzo6d3JpdGVfZmVhdGhlcihycl92YWxpZGF0aW9uX2l0ZW1fcGFpcnMsIHNpbmsgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJpZ25vcmUue21vZGVsX25hbWV9LnJhdy52YWxpZGF0aW9uLXN0dWR5LTIwMjQtMTEtMDEuaXRlbV9jb3JyZWxhdGlvbnMuZmVhdGhlciIpKSkKCnB0X3JyX3ZhbGlkYXRpb25faXRlbV9wYWlycyA9IGpvaW5fcGFpcndpc2VfY29ycmVsYXRpb24ocnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhLCBwdF9ycl92YWxpZGF0aW9uX21hY2hpbmVfZGF0YSkKCmFycm93Ojp3cml0ZV9mZWF0aGVyKHB0X3JyX3ZhbGlkYXRpb25faXRlbV9wYWlycywgc2luayA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS57cHJldHJhaW5lZF9tb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLml0ZW1fY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCmBgYAoKCiMjIEpvaW4gcGFpcndpc2Ugc2NhbGUgY29ycmVsYXRpb25zCmBgYHtyfQptYW5pZmVzdF9zY29yZXMgPSBwcmVkaWN0X21hbmlmZXN0X3Njb3Jlcyhycl92YWxpZGF0aW9uX2h1bWFuX2RhdGEsIHJyX3ZhbGlkYXRpb25fbWFjaGluZV9kYXRhLCBycl92YWxpZGF0aW9uX21hcHBpbmdfZGF0YSwgc2NhbGVzKQoKYXJyb3c6OndyaXRlX2ZlYXRoZXIobWFuaWZlc3Rfc2NvcmVzLCBzaW5rID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLnttb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLnNjYWxlX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQoKcHRfbWFuaWZlc3Rfc2NvcmVzID0gcHJlZGljdF9tYW5pZmVzdF9zY29yZXMocnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhLCBwdF9ycl92YWxpZGF0aW9uX21hY2hpbmVfZGF0YSwgcnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEsIHNjYWxlcykKCmFycm93Ojp3cml0ZV9mZWF0aGVyKHB0X21hbmlmZXN0X3Njb3Jlcywgc2luayA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS57cHJldHJhaW5lZF9tb2RlbF9uYW1lfS5yYXcudmFsaWRhdGlvbi1zdHVkeS0yMDI0LTExLTAxLnNjYWxlX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQpgYGAKCgojIyBDcmVhdGUgcmFuZG9tIHNjYWxlcwpgYGB7cn0KbWFwcGluZ19kYXRhIDwtIHJyX3ZhbGlkYXRpb25fbWFwcGluZ19kYXRhICU+JQogIHJlbmFtZShzY2FsZV8wID0gc2NhbGUwLAogICAgICAgICBzY2FsZV8xID0gc2NhbGUxKQoKaXRlbXNfYnlfc2NhbGUgPC0gYmluZF9yb3dzKAogIHNjYWxlcyAlPiUgc2VsZWN0KC1rZXllZCkgJT4lIGZpbHRlcihzY2FsZV8xID09ICIiKSAlPiUgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KC1zY2FsZV8xKSwgYnkgPSBjKCJpbnN0cnVtZW50IiwgInNjYWxlXzAiKSksCiAgc2NhbGVzICU+JSBzZWxlY3QoLWtleWVkKSAlPiUgZmlsdGVyKHNjYWxlXzEgIT0gIiIpICU+JSBsZWZ0X2pvaW4obWFwcGluZ19kYXRhLCBieSA9IGMoImluc3RydW1lbnQiLCAic2NhbGVfMCIsICJzY2FsZV8xIikpCikKCnJhbmRvbV9zY2FsZXMgPC0gbGlzdCgpCmZvcihpIGluIDE6MjAwKSB7CiAgbl9pdGVtcyA8LSBycG9pcygxLCA2KQogIG5faXRlbXMgPC0gaWZfZWxzZShuX2l0ZW1zIDwgMywgMywgbl9pdGVtcykKICByYW5kb21fc2NhbGVzW1tpXV0gPC0gcnJfdmFsaWRhdGlvbl9tYXBwaW5nX2RhdGEgJT4lCiAgICBzYW1wbGVfbihuX2l0ZW1zKSAlPiUKICAgIG11dGF0ZShzY2FsZSA9IHBhc3RlMCgicmFuZG9tIiwgaSkpICU+JQogICAgZ3JvdXBfYnkoc2NhbGUpICU+JQogICAgc3VtbWFyaXNlKAogICAgICBpdGVtcyA9IGxpc3QodmFyaWFibGUpLAogICAgICBudW1iZXJfb2ZfaXRlbXMgPSBuX2Rpc3RpbmN0KHZhcmlhYmxlKSwKICAgICAgbHZuID0gcGFzdGUoZmlyc3Qoc2NhbGUpLCAiID1+ICIsIHBhc3RlKHZhcmlhYmxlLCBjb2xsYXBzZSA9ICIgKyAiKSkpICU+JQogICAgZHJvcF9uYSgpICU+JSAKICAgIG11dGF0ZShrZXllZCA9IDEpCn0KCnJhbmRvbV9zY2FsZXMgPC0gYmluZF9yb3dzKHJhbmRvbV9zY2FsZXMpICU+JSAKICBkaXN0aW5jdChpdGVtcywgLmtlZXBfYWxsID0gVFJVRSkgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgbXV0YXRlKAogICAgcmV2ZXJzZV9pdGVtcyA9IGxpc3QocmFuZG9tbHlfY2hvb3NlX2l0ZW1zX2Zvcl9yZXZlcnNpb24oaXRlbXMpKQogICAgKSAlPiUgCiAgdW5ncm91cCgpCm5yb3cocmFuZG9tX3NjYWxlcykKd3JpdGVfcmRzKHJhbmRvbV9zY2FsZXMsIGZpbGUgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJpZ25vcmUucmFuZG9tX3NjYWxlc19yci5yZHMiKSkpCgoKcnJfdmFsaWRhdGlvbl9sbG0gPC0gcnJfdmFsaWRhdGlvbl9pdGVtX3BhaXJzICU+JQogIGxlZnRfam9pbihtYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCh2YXJpYWJsZV8xID0gdmFyaWFibGUsIEluc3RydW1lbnRBID0gaW5zdHJ1bWVudCwgU2NhbGVBID0gc2NhbGVfMCwgU3Vic2NhbGVBID0gc2NhbGVfMSkpICU+JQogIGxlZnRfam9pbihtYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCh2YXJpYWJsZV8yID0gdmFyaWFibGUsIEluc3RydW1lbnRCID0gaW5zdHJ1bWVudCwgU2NhbGVCID0gc2NhbGVfMCwgU3Vic2NhbGVCID0gc2NhbGVfMSkpCgpwdF9ycl92YWxpZGF0aW9uX2xsbSA8LSBwdF9ycl92YWxpZGF0aW9uX2l0ZW1fcGFpcnMgJT4lCiAgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzEgPSB2YXJpYWJsZSwgSW5zdHJ1bWVudEEgPSBpbnN0cnVtZW50LCBTY2FsZUEgPSBzY2FsZV8wLCBTdWJzY2FsZUEgPSBzY2FsZV8xKSkgJT4lCiAgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzIgPSB2YXJpYWJsZSwgSW5zdHJ1bWVudEIgPSBpbnN0cnVtZW50LCBTY2FsZUIgPSBzY2FsZV8wLCBTdWJzY2FsZUIgPSBzY2FsZV8xKSkKCmNvcnNfbGxtIDwtIHJyX3ZhbGlkYXRpb25faXRlbV9wYWlycyAlPiUKICBzZWxlY3QoeCA9IHZhcmlhYmxlXzEsIHkgPSB2YXJpYWJsZV8yLCByID0gc3ludGhldGljX3IpICU+JQogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkID0gRkFMU0UpIHw+CiAgaWdyYXBoOjphc19hZGphY2VuY3lfbWF0cml4KGF0dHIgPSAiciIsIHNwYXJzZSA9IEZBTFNFKQpkaWFnKGNvcnNfbGxtKSA8LSAxCgpwdF9jb3JzX2xsbSA8LSBwdF9ycl92YWxpZGF0aW9uX2l0ZW1fcGFpcnMgJT4lCiAgc2VsZWN0KHggPSB2YXJpYWJsZV8xLCB5ID0gdmFyaWFibGVfMiwgciA9IHN5bnRoZXRpY19yKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgfD4KICBpZ3JhcGg6OmdyYXBoX2Zyb21fZGF0YV9mcmFtZShkaXJlY3RlZCA9IEZBTFNFKSB8PgogIGlncmFwaDo6YXNfYWRqYWNlbmN5X21hdHJpeChhdHRyID0gInIiLCBzcGFyc2UgPSBGQUxTRSkKZGlhZyhwdF9jb3JzX2xsbSkgPC0gMQoKY29yc19yZWFsIDwtIHJyX3ZhbGlkYXRpb25fbGxtICU+JSAKICBzZWxlY3QoeCA9IHZhcmlhYmxlXzEsIHkgPSB2YXJpYWJsZV8yLCByID0gZW1waXJpY2FsX3IpICU+JQogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkID0gRkFMU0UpIHw+CiAgaWdyYXBoOjphc19hZGphY2VuY3lfbWF0cml4KGF0dHIgPSAiciIsIHNwYXJzZSA9IEZBTFNFKQpkaWFnKGNvcnNfcmVhbCkgPC0gMQoKcmVhbF9zY2FsZXMgPC0gaXRlbXNfYnlfc2NhbGUgJT4lCiAgZ3JvdXBfYnkoc2NhbGUpICU+JQogIHN1bW1hcmlzZSgKICAgIGl0ZW1zID0gbGlzdCh2YXJpYWJsZSksCiAgICByZXZlcnNlX2l0ZW1zID0gbGlzdCh2YXJpYWJsZVtrZXllZCA9PSAtMV0pLAogICAgbnVtYmVyX29mX2l0ZW1zID0gbl9kaXN0aW5jdCh2YXJpYWJsZSksCiAgICBrZXllZCA9IGZpcnN0KGtleWVkKSwKICAgIGx2biA9IHBhc3RlKGZpcnN0KHNjYWxlKSwgIiA9fiAiLCBwYXN0ZSh2YXJpYWJsZSwgY29sbGFwc2UgPSAiICsgIikpKSAlPiUKICBkcm9wX25hKCkgJT4lIAogIHVuZ3JvdXAoKQoKc2NhbGVzIDwtIGJpbmRfcm93cyhyZWFsID0gcmVhbF9zY2FsZXMsIHJhbmRvbSA9IHJhbmRvbV9zY2FsZXMsIC5pZCA9ICJ0eXBlIikKCnJyX3ZhbGlkYXRpb25faHVtYW5fZGF0YSA8LSBycl92YWxpZGF0aW9uX2h1bWFuX2RhdGEgJT4lIGhhdmVuOjp6YXBfbGFiZWxzKCkKc2NhbGVzIDwtIHNjYWxlcyAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKHB0X3JfbGxtID0gbGlzdChwdF9jb3JzX2xsbVtpdGVtcywgaXRlbXNdKSwKICAgICAgICAgcl9sbG0gPSBsaXN0KGNvcnNfbGxtW2l0ZW1zLCBpdGVtc10pLAogICAgICAgICByX3JlYWwgPSBsaXN0KGNvcnNfcmVhbFtpdGVtcywgaXRlbXNdKSwKICAgICAgICAgcmV2ZXJzZV9pdGVtc19ieV8xc3QgPSBsaXN0KGZpbmRfcmV2ZXJzZV9pdGVtc19ieV9maXJzdF9pdGVtKHJfcmVhbCwga2V5ZWQpKSwKICAgICAgICAgTl9yZWFsID0gcnJfdmFsaWRhdGlvbl9pdGVtX3BhaXJzICU+JSAKICAgICAgICAgICBmaWx0ZXIodmFyaWFibGVfMSAlaW4lIGl0ZW1zLCB2YXJpYWJsZV8yICVpbiUgaXRlbXMpICU+JSAKICAgICAgICAgICBzdW1tYXJpc2UobWluX249bWluKHBhaXJ3aXNlX24pKSAlPiUgcHVsbChtaW5fbikpICU+JQogIG11dGF0ZSgKICAgIHJlbF9yZWFsID0gbGlzdChwc3ljaDo6YWxwaGEocnJfdmFsaWRhdGlvbl9odW1hbl9kYXRhWywgaXRlbXNdLCBrZXlzID0gcmV2ZXJzZV9pdGVtcywgbi5pdGVyID0gMTAwMCkpLAogICAgcmVsX2xsbSA9IGxpc3QocHN5Y2g6OmFscGhhKHJfbGxtLCBrZXlzID0gcmV2ZXJzZV9pdGVtcywgbi5vYnMgPSBOX3JlYWwpJGZlbGR0KSwKICAgIHJlbF9wdF9sbG0gPSBsaXN0KHBzeWNoOjphbHBoYShwdF9yX2xsbSwga2V5cyA9IHJldmVyc2VfaXRlbXMsIG4ub2JzID0gTl9yZWFsKSRmZWxkdCkpICU+JQogIG11dGF0ZShlbXBpcmljYWxfYWxwaGEgPSByZWxfcmVhbCRmZWxkdCRhbHBoYSRyYXdfYWxwaGEsCiAgICAgICAgIHN5bnRoZXRpY19hbHBoYSA9IHJlbF9sbG0kYWxwaGEkcmF3X2FscGhhLAogICAgICAgICBwdF9zeW50aGV0aWNfYWxwaGEgPSByZWxfcHRfbGxtJGFscGhhJHJhd19hbHBoYSkgJT4lCiAgbXV0YXRlKAogICAgZW1waXJpY2FsX2FscGhhX3NlID0gc2QocmVsX3JlYWwkYm9vdFssInJhd19hbHBoYSJdKSwKICApCgp3cml0ZV9yZHMoc2NhbGVzLCBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLnNjYWxlc193aXRoX2FscGhhX3NlX3JyLnJkcyIpKSkKYGBgCgo=