The following precision simulations all follow the same
structure.
- We randomly redraw from our holdout data to get realistic
distributions of empirical estimates. SEs are estimated based on our
planned N of 400.
- We repeat this random drawing process many times.
- We adjust for sampling error/the standard error of the empirical
estimate to get the semi-latent accuracy.
- The target quantity is the average standard error of the semi-latent
accuracy with which the synthetic estimates predicts the empirical
estimates. We also report the maximal standard error across
simulations.
We begin with item correlations, then reliabilities, then scale
correlations.
knitr::opts_chunk$set(echo = TRUE, error = T, warning = F, message = F)
# Libraries and Settings
# Libs ---------------------------
library(tidyverse)
library(arrow)
library(glue)
library(psych)
library(lavaan)
library(ggplot2)
library(plotly)
library(gridExtra)
library(semTools)
library(semPlot)
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)
number_of_items <- 246
number_of_scales <- 76
number_of_scales_with_more_than_3_items <- 56
combinations_items <- choose(number_of_items, 2)
combinations_scales <- choose(number_of_scales_with_more_than_3_items, 2)
scale_subscale_pairs <- 38
combinations_scales <- combinations_scales - scale_subscale_pairs # after eliminating scale-subscale pairs
planned_N <- 400
Precision simulation for synthetic inter-item correlations
holdout <- arrow::read_feather(file = file.path(data_path, glue("data/intermediate/{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)
scales <- arrow::read_feather(file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.scales.feather"))
)
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, InstrumentA = instrument, ScaleA = scale_0, SubscaleA = scale_1))
sim_results <- tibble()
library(lavaan)
for(i in 1:500) {
items <- holdout %>% select(variable_1) %>% distinct() %>% sample_n(number_of_items) %>% pull(variable_1)
subset <- holdout %>% filter(variable_1 %in% items, variable_2 %in% items)
N <- planned_N
subset <- subset %>% mutate(se = (1 - empirical_r^2)/sqrt(N - 3))
se2 <- mean(subset$se^2)
r <- broom::tidy(cor.test(subset$empirical_r, subset$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 = subset)
sim_results <- bind_rows(sim_results,
standardizedsolution(fit) %>% filter(lhs == "PearsonLatent", rhs == "synthetic_r")
)
}
sim_results %>% summarise(semi_latent_r = mean(est.std), mean_se = sqrt(mean(se^2)), max_se = max(se)) %>%
knitr::kable()
0.707866 |
0.00316 |
0.0035834 |
Precision simulation for synthetic reliabilities
source("global_functions.R")
holdout_human_data = arrow::read_feather(
file = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.human.feather"))
)
holdout_human_data <- holdout_human_data %>% haven::zap_labels()
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
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(
scales %>% filter(scale_1 == "") %>% left_join(mapping_data %>% select(-scale_1), by = c("instrument", "scale_0")),
scales %>% filter(scale_1 != "") %>% left_join(mapping_data, by = c("instrument", "scale_0", "scale_1"))
)
real_scales <- items_by_scale %>%
group_by(scale) %>%
summarise(
items = list(variable),
number_of_items = n_distinct(variable),
keyed = first(keyed),
lvn = paste(first(scale), " =~ ", paste(variable, collapse = " + "))) %>%
group_by(scale) %>%
mutate(reverse_items = list(find_reverse_items_by_first_item(cors_real[unlist(items), unlist(items)], keyed))) %>%
drop_na() %>%
ungroup()
random_scales <- list()
for(i in 1:1000) {
n_items <- rpois(1, mean(real_scales$number_of_items,na.rm = T))
n_items <- if_else(n_items < 3, 3, n_items, 3)
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) %>%
distinct(items, .keep_all = TRUE) %>%
rowwise() %>%
mutate(
reverse_items = list(randomly_choose_items_for_reversion(items))
) %>%
ungroup()
scales <- bind_rows(real = real_scales, random = random_scales, .id = "type")
n_distinct(scales$scale)
## [1] 1113
scales <- scales %>% filter(number_of_items >= 3)
scales <- scales %>%
rowwise() %>%
mutate(r_llm = list(cors_llm[items, items]),
r_real = list(cors_real[items, items]),
N_real = holdout %>%
filter(variable_1 %in% items, variable_2 %in% items) %>%
summarise(min_n=min(pairwise_n)) %>% pull(min_n)) %>%
mutate(
rel_real = list(psych::alpha(holdout_human_data[, items], keys = reverse_items, n.iter = 1000)),
rel_llm = list(psych::alpha(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) %>%
mutate(
alpha_se = mean(diff(unlist(psychometric::alpha.CI(empirical_alpha, k = number_of_items, N = planned_N, level = 0.95)))/1.96)
)
realistic_scales <- scales %>% ungroup()
sim_results <- tibble()
for(i in 1:500) {
picked_scales <- realistic_scales %>% filter(!str_detect(scale, "random")) %>% sample_n(number_of_scales_with_more_than_3_items)
subset <-
bind_rows(picked_scales,
realistic_scales %>% filter(str_detect(scale, "random")) %>% sample_n(200)
)
se2 <- mean(subset$alpha_se^2)
r <- broom::tidy(cor.test(subset$empirical_alpha, subset$synthetic_alpha))
(r$conf.high - r$conf.low)/2
model <- paste0('
# Latent variables
PearsonLatent =~ 1*empirical_alpha
# Fixing error variances based on known standard errors
empirical_alpha ~~ ',se2,'*empirical_alpha
# Relationship between latent variables
PearsonLatent ~~ synthetic_alpha
')
fit <- sem(model, data = subset)
sim_results <- bind_rows(sim_results,
standardizedsolution(fit) %>% filter(lhs == "PearsonLatent", rhs == "synthetic_alpha")
)
}
sim_results %>% summarise(semi_latent_r = mean(est.std), mean_se = sqrt(mean(se^2)), max_se = max(se)) %>%
knitr::kable()
0.8798027 |
0.0153378 |
0.0191323 |
Precision simulation for synthetic scale correlations
manifest_scores = arrow::read_feather(file = file.path(data_path, glue("data/intermediate/{model_name}.raw.osf-bainbridge-2021-s2-0.scale_correlations.feather")))
sim_results <- tibble()
library(lavaan)
for(i in 1:500) {
scales <- manifest_scores %>% select(scale_a) %>% distinct() %>% pull(scale_a)
subset <- manifest_scores %>% filter(scale_a %in% scales, scale_b %in% scales) %>%
sample_n(combinations_scales)
N <- planned_N
subset <- subset %>% mutate(se = (1 - empirical_r^2)/sqrt(N - 3))
se2 <- mean(subset$se^2)
r <- broom::tidy(cor.test(subset$empirical_r, subset$synthetic_r))
(r$conf.high - r$conf.low)/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 = subset)
sim_results <- bind_rows(sim_results,
standardizedsolution(fit) %>% filter(lhs == "PearsonLatent", rhs == "synthetic_r")
)
}
sim_results %>% summarise(semi_latent_r = mean(est.std), mean_se = sqrt(mean(se^2)), max_se = max(se)) %>%
knitr::kable()
0.8802321 |
0.006223 |
0.0070053 |
LS0tCnRpdGxlOiAiUHJlY2lzaW9uIHNpbXVsYXRpb25zIgphdXRob3I6ICJSdWJlbiBBcnNsYW4iCmRhdGU6ICIyMDIzLTExLTA3IgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCgpUaGUgZm9sbG93aW5nIHByZWNpc2lvbiBzaW11bGF0aW9ucyBhbGwgZm9sbG93IHRoZSBzYW1lIHN0cnVjdHVyZS4KCi0gV2UgcmFuZG9tbHkgcmVkcmF3IGZyb20gb3VyIGhvbGRvdXQgZGF0YSB0byBnZXQgcmVhbGlzdGljIGRpc3RyaWJ1dGlvbnMKICBvZiBlbXBpcmljYWwgZXN0aW1hdGVzLiBTRXMgYXJlIGVzdGltYXRlZCBiYXNlZCBvbiBvdXIgcGxhbm5lZCBOIG9mIDQwMC4KLSBXZSByZXBlYXQgdGhpcyByYW5kb20gZHJhd2luZyBwcm9jZXNzIG1hbnkgdGltZXMuCi0gV2UgYWRqdXN0IGZvciBzYW1wbGluZyBlcnJvci90aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIGVtcGlyaWNhbCBlc3RpbWF0ZSB0byBnZXQgdGhlIHNlbWktbGF0ZW50IGFjY3VyYWN5LgotIFRoZSB0YXJnZXQgcXVhbnRpdHkgaXMgdGhlIGF2ZXJhZ2Ugc3RhbmRhcmQgZXJyb3Igb2YgdGhlIHNlbWktbGF0ZW50IGFjY3VyYWN5IHdpdGggd2hpY2ggdGhlIHN5bnRoZXRpYyBlc3RpbWF0ZXMgcHJlZGljdHMgdGhlIGVtcGlyaWNhbCBlc3RpbWF0ZXMuIFdlIGFsc28gcmVwb3J0IHRoZSBtYXhpbWFsIHN0YW5kYXJkIGVycm9yIGFjcm9zcyBzaW11bGF0aW9ucy4KCldlIGJlZ2luIHdpdGggaXRlbSBjb3JyZWxhdGlvbnMsIHRoZW4gcmVsaWFiaWxpdGllcywgdGhlbiBzY2FsZSBjb3JyZWxhdGlvbnMuCgpgYGB7ciB3YXJuaW5nPUYsbWVzc2FnZT1GfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGVycm9yID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGKQoKIyBMaWJyYXJpZXMgYW5kIFNldHRpbmdzCgojIExpYnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGFycm93KQpsaWJyYXJ5KGdsdWUpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkobGF2YWFuKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShzZW1Ub29scykKbGlicmFyeShzZW1QbG90KQoKbW9kZWxfbmFtZSA9ICJJdGVtU2ltaWxhcml0eVRyYWluaW5nLTIwMjQwNTAyLXRyaWFsMTIiCiNtb2RlbF9uYW1lID0gIml0ZW0tc2ltaWxhcml0eS0yMDIzMTAxOC0xMjI1MDQiCnByZXRyYWluZWRfbW9kZWxfbmFtZSA9ICJhbGwtbXBuZXQtYmFzZS12MiIKCmRhdGFfcGF0aCA9IGdsdWUoIi4vIikKcHJldHJhaW5lZF9kYXRhX3BhdGggPSBnbHVlKCIuLyIpCgpzZXQuc2VlZCg0MikKCm51bWJlcl9vZl9pdGVtcyA8LSAyNDYKbnVtYmVyX29mX3NjYWxlcyA8LSA3NgpudW1iZXJfb2Zfc2NhbGVzX3dpdGhfbW9yZV90aGFuXzNfaXRlbXMgPC0gNTYKY29tYmluYXRpb25zX2l0ZW1zIDwtIGNob29zZShudW1iZXJfb2ZfaXRlbXMsIDIpCmNvbWJpbmF0aW9uc19zY2FsZXMgPC0gY2hvb3NlKG51bWJlcl9vZl9zY2FsZXNfd2l0aF9tb3JlX3RoYW5fM19pdGVtcywgMikKc2NhbGVfc3Vic2NhbGVfcGFpcnMgPC0gMzgKY29tYmluYXRpb25zX3NjYWxlcyA8LSBjb21iaW5hdGlvbnNfc2NhbGVzIC0gc2NhbGVfc3Vic2NhbGVfcGFpcnMgIyBhZnRlciBlbGltaW5hdGluZyBzY2FsZS1zdWJzY2FsZSBwYWlycwpwbGFubmVkX04gPC0gNDAwCmBgYAoKCiMjIFByZWNpc2lvbiBzaW11bGF0aW9uIGZvciBzeW50aGV0aWMgaW50ZXItaXRlbSBjb3JyZWxhdGlvbnMKYGBge3J9CmhvbGRvdXQgPC0gYXJyb3c6OnJlYWRfZmVhdGhlcihmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLnttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLml0ZW1fY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCgpob2xkb3V0X21hcHBpbmdfZGF0YSA9IGFycm93OjpyZWFkX2ZlYXRoZXIoCiAgZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLm1hcHBpbmcyLmZlYXRoZXIiKSkKKSAlPiUKICByZW5hbWUoc2NhbGVfMCA9IHNjYWxlMCwKICAgICAgICAgc2NhbGVfMSA9IHNjYWxlMSkKCnNjYWxlcyA8LSBhcnJvdzo6cmVhZF9mZWF0aGVyKGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLnNjYWxlcy5mZWF0aGVyIikpCikKCmhvbGRvdXRfbGxtIDwtIGhvbGRvdXQgJT4lCiAgbGVmdF9qb2luKGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLCBJbnN0cnVtZW50QSA9IGluc3RydW1lbnQsIFNjYWxlQSA9IHNjYWxlXzAsIFN1YnNjYWxlQSA9IHNjYWxlXzEpKSAlPiUKICBsZWZ0X2pvaW4oaG9sZG91dF9tYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCh2YXJpYWJsZV8yID0gdmFyaWFibGUsIEluc3RydW1lbnRBID0gaW5zdHJ1bWVudCwgU2NhbGVBID0gc2NhbGVfMCwgU3Vic2NhbGVBID0gc2NhbGVfMSkpCgpzaW1fcmVzdWx0cyA8LSB0aWJibGUoKQpsaWJyYXJ5KGxhdmFhbikKCmZvcihpIGluIDE6NTAwKSB7CiAgaXRlbXMgPC0gaG9sZG91dCAlPiUgc2VsZWN0KHZhcmlhYmxlXzEpICU+JSBkaXN0aW5jdCgpICU+JSBzYW1wbGVfbihudW1iZXJfb2ZfaXRlbXMpICU+JSBwdWxsKHZhcmlhYmxlXzEpCgogIHN1YnNldCA8LSBob2xkb3V0ICU+JSBmaWx0ZXIodmFyaWFibGVfMSAlaW4lIGl0ZW1zLCB2YXJpYWJsZV8yICVpbiUgaXRlbXMpCgogIE4gPC0gcGxhbm5lZF9OCiAgc3Vic2V0IDwtIHN1YnNldCAlPiUgbXV0YXRlKHNlID0gKDEgLSBlbXBpcmljYWxfcl4yKS9zcXJ0KE4gLSAzKSkKICBzZTIgPC0gbWVhbihzdWJzZXQkc2VeMikKCiAgciA8LSBicm9vbTo6dGlkeShjb3IudGVzdChzdWJzZXQkZW1waXJpY2FsX3IsIHN1YnNldCRzeW50aGV0aWNfcikpCgogIG1vZGVsIDwtIHBhc3RlMCgnCiAgICAjIExhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgPX4gMSplbXBpcmljYWxfcgoKICAgICMgRml4aW5nIGVycm9yIHZhcmlhbmNlcyBiYXNlZCBvbiBrbm93biBzdGFuZGFyZCBlcnJvcnMKICAgIGVtcGlyaWNhbF9yIH5+ICcsc2UyLCcqZW1waXJpY2FsX3IKCiAgICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgfn4gc3ludGhldGljX3IKICAnKQoKICBmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gc3Vic2V0KQoKICBzaW1fcmVzdWx0cyA8LSBiaW5kX3Jvd3Moc2ltX3Jlc3VsdHMsCiAgICBzdGFuZGFyZGl6ZWRzb2x1dGlvbihmaXQpICU+JSBmaWx0ZXIobGhzID09ICJQZWFyc29uTGF0ZW50IiwgcmhzID09ICAic3ludGhldGljX3IiKQogICkKfQoKc2ltX3Jlc3VsdHMgJT4lIHN1bW1hcmlzZShzZW1pX2xhdGVudF9yID0gbWVhbihlc3Quc3RkKSwgbWVhbl9zZSA9IHNxcnQobWVhbihzZV4yKSksIG1heF9zZSA9IG1heChzZSkpICU+JSAKICBrbml0cjo6a2FibGUoKQpgYGAKCgojIyBQcmVjaXNpb24gc2ltdWxhdGlvbiBmb3Igc3ludGhldGljIHJlbGlhYmlsaXRpZXMKYGBge3J9CnNvdXJjZSgiZ2xvYmFsX2Z1bmN0aW9ucy5SIikKaG9sZG91dF9odW1hbl9kYXRhID0gYXJyb3c6OnJlYWRfZmVhdGhlcigKICBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAuaHVtYW4uZmVhdGhlciIpKQopCmhvbGRvdXRfaHVtYW5fZGF0YSA8LSBob2xkb3V0X2h1bWFuX2RhdGEgJT4lIGhhdmVuOjp6YXBfbGFiZWxzKCkKCmNvcnNfbGxtIDwtIGhvbGRvdXRfbGxtICU+JQogIHNlbGVjdCh4ID0gdmFyaWFibGVfMSwgeSA9IHZhcmlhYmxlXzIsIHIgPSBzeW50aGV0aWNfcikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpIHw+CiAgaWdyYXBoOjpncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQgPSBGQUxTRSkgfD4KICBpZ3JhcGg6OmFzX2FkamFjZW5jeV9tYXRyaXgoYXR0ciA9ICJyIiwgc3BhcnNlID0gRkFMU0UpCmRpYWcoY29yc19sbG0pIDwtIDEKCmNvcnNfcmVhbCA8LSBob2xkb3V0X2xsbSAlPiUKICBzZWxlY3QoeCA9IHZhcmlhYmxlXzEsIHkgPSB2YXJpYWJsZV8yLCByID0gZW1waXJpY2FsX3IpICU+JQogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkID0gRkFMU0UpIHw+CiAgaWdyYXBoOjphc19hZGphY2VuY3lfbWF0cml4KGF0dHIgPSAiciIsIHNwYXJzZSA9IEZBTFNFKQpkaWFnKGNvcnNfcmVhbCkgPC0gMQoKbWFwcGluZ19kYXRhIDwtIGhvbGRvdXRfbWFwcGluZ19kYXRhCml0ZW1zX2J5X3NjYWxlIDwtIGJpbmRfcm93cygKICBzY2FsZXMgJT4lIGZpbHRlcihzY2FsZV8xID09ICIiKSAlPiUgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KC1zY2FsZV8xKSwgYnkgPSBjKCJpbnN0cnVtZW50IiwgInNjYWxlXzAiKSksCiAgc2NhbGVzICU+JSBmaWx0ZXIoc2NhbGVfMSAhPSAiIikgJT4lIGxlZnRfam9pbihtYXBwaW5nX2RhdGEsIGJ5ID0gYygiaW5zdHJ1bWVudCIsICJzY2FsZV8wIiwgInNjYWxlXzEiKSkKKQoKcmVhbF9zY2FsZXMgPC0gaXRlbXNfYnlfc2NhbGUgJT4lCiAgZ3JvdXBfYnkoc2NhbGUpICU+JQogIHN1bW1hcmlzZSgKICAgIGl0ZW1zID0gbGlzdCh2YXJpYWJsZSksCiAgICBudW1iZXJfb2ZfaXRlbXMgPSBuX2Rpc3RpbmN0KHZhcmlhYmxlKSwKICAgIGtleWVkID0gZmlyc3Qoa2V5ZWQpLAogICAgbHZuID0gcGFzdGUoZmlyc3Qoc2NhbGUpLCAiID1+ICIsIHBhc3RlKHZhcmlhYmxlLCBjb2xsYXBzZSA9ICIgKyAiKSkpICU+JQogIGdyb3VwX2J5KHNjYWxlKSAlPiUKICBtdXRhdGUocmV2ZXJzZV9pdGVtcyA9IGxpc3QoZmluZF9yZXZlcnNlX2l0ZW1zX2J5X2ZpcnN0X2l0ZW0oY29yc19yZWFsW3VubGlzdChpdGVtcyksIHVubGlzdChpdGVtcyldLCBrZXllZCkpKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICB1bmdyb3VwKCkKCnJhbmRvbV9zY2FsZXMgPC0gbGlzdCgpCmZvcihpIGluIDE6MTAwMCkgewogIG5faXRlbXMgPC0gcnBvaXMoMSwgbWVhbihyZWFsX3NjYWxlcyRudW1iZXJfb2ZfaXRlbXMsbmEucm0gPSBUKSkKICBuX2l0ZW1zIDwtIGlmX2Vsc2Uobl9pdGVtcyA8IDMsIDMsIG5faXRlbXMsIDMpCiAgcmFuZG9tX3NjYWxlc1tbaV1dIDwtIGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JQogICAgc2FtcGxlX24obl9pdGVtcykgJT4lCiAgICBtdXRhdGUoc2NhbGUgPSBwYXN0ZTAoInJhbmRvbSIsIGkpKSAlPiUKICAgIGdyb3VwX2J5KHNjYWxlKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgaXRlbXMgPSBsaXN0KHZhcmlhYmxlKSwKICAgICAgbnVtYmVyX29mX2l0ZW1zID0gbl9kaXN0aW5jdCh2YXJpYWJsZSksCiAgICAgIGx2biA9IHBhc3RlKGZpcnN0KHNjYWxlKSwgIiA9fiAiLCBwYXN0ZSh2YXJpYWJsZSwgY29sbGFwc2UgPSAiICsgIikpKSAlPiUKICAgIGRyb3BfbmEoKSAlPiUgCiAgICBtdXRhdGUoa2V5ZWQgPSAxKQp9CgpyYW5kb21fc2NhbGVzIDwtIGJpbmRfcm93cyhyYW5kb21fc2NhbGVzKSAlPiUgCiAgZGlzdGluY3QoaXRlbXMsIC5rZWVwX2FsbCA9IFRSVUUpICU+JSAKICByb3d3aXNlKCkgJT4lIAogIG11dGF0ZSgKICAgIHJldmVyc2VfaXRlbXMgPSBsaXN0KHJhbmRvbWx5X2Nob29zZV9pdGVtc19mb3JfcmV2ZXJzaW9uKGl0ZW1zKSkKICAgICkgJT4lIAogIHVuZ3JvdXAoKQoKc2NhbGVzIDwtIGJpbmRfcm93cyhyZWFsID0gcmVhbF9zY2FsZXMsIHJhbmRvbSA9IHJhbmRvbV9zY2FsZXMsIC5pZCA9ICJ0eXBlIikKbl9kaXN0aW5jdChzY2FsZXMkc2NhbGUpCgpzY2FsZXMgPC0gc2NhbGVzICU+JSBmaWx0ZXIobnVtYmVyX29mX2l0ZW1zID49IDMpCnNjYWxlcyA8LSBzY2FsZXMgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShyX2xsbSA9IGxpc3QoY29yc19sbG1baXRlbXMsIGl0ZW1zXSksCiAgICAgICAgIHJfcmVhbCA9IGxpc3QoY29yc19yZWFsW2l0ZW1zLCBpdGVtc10pLAogICAgICAgICBOX3JlYWwgPSBob2xkb3V0ICU+JSAKICAgICAgICAgICBmaWx0ZXIodmFyaWFibGVfMSAlaW4lIGl0ZW1zLCB2YXJpYWJsZV8yICVpbiUgaXRlbXMpICU+JSAKICAgICAgICAgICBzdW1tYXJpc2UobWluX249bWluKHBhaXJ3aXNlX24pKSAlPiUgcHVsbChtaW5fbikpICU+JQogIG11dGF0ZSgKICAgIHJlbF9yZWFsID0gbGlzdChwc3ljaDo6YWxwaGEoaG9sZG91dF9odW1hbl9kYXRhWywgaXRlbXNdLCBrZXlzID0gcmV2ZXJzZV9pdGVtcywgbi5pdGVyID0gMTAwMCkpLAogICAgcmVsX2xsbSA9IGxpc3QocHN5Y2g6OmFscGhhKHJfbGxtLCBrZXlzID0gcmV2ZXJzZV9pdGVtcywgbi5vYnMgPSBOX3JlYWwpJGZlbGR0KSkgJT4lCiAgbXV0YXRlKGVtcGlyaWNhbF9hbHBoYSA9IHJlbF9yZWFsJGZlbGR0JGFscGhhJHJhd19hbHBoYSwKICAgICAgICAgc3ludGhldGljX2FscGhhID0gcmVsX2xsbSRhbHBoYSRyYXdfYWxwaGEpICU+JQogIG11dGF0ZSgKICAgIGFscGhhX3NlID0gbWVhbihkaWZmKHVubGlzdChwc3ljaG9tZXRyaWM6OmFscGhhLkNJKGVtcGlyaWNhbF9hbHBoYSwgayA9IG51bWJlcl9vZl9pdGVtcywgTiA9IHBsYW5uZWRfTiwgbGV2ZWwgPSAwLjk1KSkpLzEuOTYpCiAgKQoKcmVhbGlzdGljX3NjYWxlcyA8LSBzY2FsZXMgJT4lIHVuZ3JvdXAoKQoKc2ltX3Jlc3VsdHMgPC0gdGliYmxlKCkKZm9yKGkgaW4gMTo1MDApIHsKICBwaWNrZWRfc2NhbGVzIDwtIHJlYWxpc3RpY19zY2FsZXMgJT4lIGZpbHRlcighc3RyX2RldGVjdChzY2FsZSwgInJhbmRvbSIpKSAlPiUgc2FtcGxlX24obnVtYmVyX29mX3NjYWxlc193aXRoX21vcmVfdGhhbl8zX2l0ZW1zKQogIHN1YnNldCA8LQogICAgYmluZF9yb3dzKHBpY2tlZF9zY2FsZXMsCiAgICAgICAgICAgICAgcmVhbGlzdGljX3NjYWxlcyAlPiUgZmlsdGVyKHN0cl9kZXRlY3Qoc2NhbGUsICJyYW5kb20iKSkgJT4lIHNhbXBsZV9uKDIwMCkKICApCgogIHNlMiA8LSBtZWFuKHN1YnNldCRhbHBoYV9zZV4yKQoKICByIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KHN1YnNldCRlbXBpcmljYWxfYWxwaGEsIHN1YnNldCRzeW50aGV0aWNfYWxwaGEpKQogIChyJGNvbmYuaGlnaCAtIHIkY29uZi5sb3cpLzIKCiAgbW9kZWwgPC0gcGFzdGUwKCcKICAgICMgTGF0ZW50IHZhcmlhYmxlcwogICAgUGVhcnNvbkxhdGVudCA9fiAxKmVtcGlyaWNhbF9hbHBoYQoKICAgICMgRml4aW5nIGVycm9yIHZhcmlhbmNlcyBiYXNlZCBvbiBrbm93biBzdGFuZGFyZCBlcnJvcnMKICAgIGVtcGlyaWNhbF9hbHBoYSB+fiAnLHNlMiwnKmVtcGlyaWNhbF9hbHBoYQoKICAgICMgUmVsYXRpb25zaGlwIGJldHdlZW4gbGF0ZW50IHZhcmlhYmxlcwogICAgUGVhcnNvbkxhdGVudCB+fiBzeW50aGV0aWNfYWxwaGEKICAnKQoKICBmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gc3Vic2V0KQoKICBzaW1fcmVzdWx0cyA8LSBiaW5kX3Jvd3Moc2ltX3Jlc3VsdHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdCkgJT4lIGZpbHRlcihsaHMgPT0gIlBlYXJzb25MYXRlbnQiLCByaHMgPT0gICJzeW50aGV0aWNfYWxwaGEiKQogICkKfQpzaW1fcmVzdWx0cyAlPiUgc3VtbWFyaXNlKHNlbWlfbGF0ZW50X3IgPSBtZWFuKGVzdC5zdGQpLCBtZWFuX3NlID0gc3FydChtZWFuKHNlXjIpKSwgbWF4X3NlID0gbWF4KHNlKSkgJT4lIAogIGtuaXRyOjprYWJsZSgpCmBgYAoKCiMjIFByZWNpc2lvbiBzaW11bGF0aW9uIGZvciBzeW50aGV0aWMgc2NhbGUgY29ycmVsYXRpb25zCmBgYHtyfQptYW5pZmVzdF9zY29yZXMgPSBhcnJvdzo6cmVhZF9mZWF0aGVyKGZpbGUgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJpZ25vcmUue21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAuc2NhbGVfY29ycmVsYXRpb25zLmZlYXRoZXIiKSkpCgoKc2ltX3Jlc3VsdHMgPC0gdGliYmxlKCkKbGlicmFyeShsYXZhYW4pCgpmb3IoaSBpbiAxOjUwMCkgewogIHNjYWxlcyA8LSBtYW5pZmVzdF9zY29yZXMgJT4lIHNlbGVjdChzY2FsZV9hKSAlPiUgZGlzdGluY3QoKSAlPiUgcHVsbChzY2FsZV9hKQoKICBzdWJzZXQgPC0gbWFuaWZlc3Rfc2NvcmVzICU+JSBmaWx0ZXIoc2NhbGVfYSAlaW4lIHNjYWxlcywgc2NhbGVfYiAlaW4lIHNjYWxlcykgJT4lIAogICAgc2FtcGxlX24oY29tYmluYXRpb25zX3NjYWxlcykKCiAgTiA8LSBwbGFubmVkX04KICBzdWJzZXQgPC0gc3Vic2V0ICU+JSBtdXRhdGUoc2UgPSAoMSAtIGVtcGlyaWNhbF9yXjIpL3NxcnQoTiAtIDMpKQogIHNlMiA8LSBtZWFuKHN1YnNldCRzZV4yKQoKICByIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KHN1YnNldCRlbXBpcmljYWxfciwgc3Vic2V0JHN5bnRoZXRpY19yKSkKICAociRjb25mLmhpZ2ggLSByJGNvbmYubG93KS8yCgogIG1vZGVsIDwtIHBhc3RlMCgnCiAgICAjIExhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgPX4gMSplbXBpcmljYWxfcgoKICAgICMgRml4aW5nIGVycm9yIHZhcmlhbmNlcyBiYXNlZCBvbiBrbm93biBzdGFuZGFyZCBlcnJvcnMKICAgIGVtcGlyaWNhbF9yIH5+ICcsc2UyLCcqZW1waXJpY2FsX3IKCiAgICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxhdGVudCB2YXJpYWJsZXMKICAgIFBlYXJzb25MYXRlbnQgfn4gc3ludGhldGljX3IKICAnKQoKICBmaXQgPC0gc2VtKG1vZGVsLCBkYXRhID0gc3Vic2V0KQoKICBzaW1fcmVzdWx0cyA8LSBiaW5kX3Jvd3Moc2ltX3Jlc3VsdHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkaXplZHNvbHV0aW9uKGZpdCkgJT4lIGZpbHRlcihsaHMgPT0gIlBlYXJzb25MYXRlbnQiLCByaHMgPT0gICJzeW50aGV0aWNfciIpCiAgKQp9CgpzaW1fcmVzdWx0cyAlPiUgc3VtbWFyaXNlKHNlbWlfbGF0ZW50X3IgPSBtZWFuKGVzdC5zdGQpLCBtZWFuX3NlID0gc3FydChtZWFuKHNlXjIpKSwgbWF4X3NlID0gbWF4KHNlKSkgJT4lIAogIGtuaXRyOjprYWJsZSgpCmBgYAo=