Load data

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

facets <- readr::read_tsv("ignore/facets.tsv")
## Rows: 45 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): instrument1, scale0, facet, scale2
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
holdout_mapping_data <- holdout_mapping_data %>% 
  separate(variable, c("instrument1", "facet"), remove = F,extra = "drop") %>% 
  left_join(facets %>% select(instrument1, facet, scale2), by = c("instrument1", "facet")) %>% 
  mutate(scale1 = coalesce(scale1, scale2)) %>% 
  select(-instrument1, -facet, -scale2)


first_items <- bind_rows(
    holdout_mapping_data %>%
  select(variable, instrument, scale_0 = scale0, scale_1 = scale1,
         item_text) %>%
  mutate(instrument = coalesce(str_c(str_trim(instrument), " "), ""),
         scale_0 = coalesce(str_c(str_trim(scale_0), " "), ""),
         scale_1 = "",
         scale = str_replace_all(str_trim(paste0(instrument, scale_0, scale_1)), "[^a-zA-Z_0-9]", "_")
  ),
  holdout_mapping_data %>%
  select(variable, instrument, scale_0 = scale0, scale_1 = scale1,
         item_text) %>%
  mutate(instrument = coalesce(str_c(str_trim(instrument), " "), ""),
         scale_0 = coalesce(str_c(str_trim(scale_0), " "), ""),
         scale_1 = coalesce(str_trim(scale_1), ""),
         scale = str_replace_all(str_trim(paste0(instrument, scale_0, scale_1)), "[^a-zA-Z_0-9]", "_")
  )) %>% 
  group_by(scale) %>% 
  arrange(variable) %>% 
  filter(row_number() == 1) %>% 
  mutate(instrument = str_trim(instrument),
         scale_0 = str_trim(scale_0),
         scale_1 = str_trim(scale_1))

rio::export(first_items %>% 
  select(scale, item_text, variable), "ignore/first_items.xlsx")
coded <- rio::import("ignore/first_items_coded.xlsx")

scales <- first_items %>% left_join(coded) %>% 
  mutate(scale = str_replace(scale, "opennness", "openness"),
         scale_0 = str_replace(scale_0, "opennness", "openness")) %>% 
  select(-item_text, -variable)
## Joining with `by = join_by(variable, item_text, scale)`
arrow::write_feather(scales, sink = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.scales.feather"))
)

holdout_mapping_data <- holdout_mapping_data %>% 
  mutate(scale0 = str_replace(scale0, "opennness", "openness"))

arrow::write_feather(holdout_mapping_data, sink = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.mapping2.feather"))
)


# pre-trained model
pt_holdout_human_data = arrow::read_feather(
  file = file.path(data_path, glue("data/intermediate/{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.human.feather"))
)

pt_holdout_machine_data = arrow::read_feather(
  file = file.path(data_path, glue("data/intermediate/{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.machine.feather"))
)

# fine-tuned model
holdout_machine_data = arrow::read_feather(
  file = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.machine.feather"))
)

holdout_human_data = arrow::read_feather(
  file = file.path(data_path, glue("{model_name}.raw.osf-bainbridge-2021-s2-0.human.feather"))
)
# 
# # pre-trained model
# holdout_machine_data_pt = arrow::read_feather(
#   file = file.path(pretrained_data_path, glue("data/intermediate/{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.machine.feather"))
# )

Description

nrow(holdout_human_data) # respondents
## [1] 493
ncol(holdout_human_data) # items
## [1] 418
nrow(holdout_machine_data) # vector dimensions
## [1] 768
ncol(holdout_machine_data) # items
## [1] 418
n_distinct(holdout_mapping_data$instrument) # instruments
## [1] 22
n_distinct(holdout_mapping_data$scale0) # constructs
## [1] 25
n_distinct(holdout_mapping_data$instrument, holdout_mapping_data$scale0) # scales
## [1] 30
n_distinct(str_c(holdout_mapping_data$instrument, holdout_mapping_data$scale0, holdout_mapping_data$scale1)) # subscales
## [1] 84

Join pairwise item correlations

join_pairwise_correlation = function(df_human, df_machine) {
    item_pairs = combn(x = names(df_human), m = 2) %>%
        t() %>% 
      as.data.frame()
    colnames(item_pairs) <- c("variable_1", "variable_2")

    df_  = 
      item_pairs %>% 
      left_join(
      df_human %>% 
        cor(use = "p") %>% 
        reshape2::melt() %>% 
        dplyr::left_join(
          Hmisc::rcorr(as.matrix(holdout_human_data))$n %>% 
          reshape2::melt() %>% 
          dplyr::rename(pairwise_n = value),
          by = c("Var1", "Var2")
        ) %>% 
        dplyr::left_join(
            y = df_machine %>% 
            cor(use = "p") %>% 
            reshape2::melt(),
            by = c("Var1", "Var2")
        ) %>% 
        dplyr::rename(
            empirical_r = "value.x",
            synthetic_r = "value.y",
            variable_1 = Var1,
            variable_2 = Var2
        ) %>% 
        dplyr::filter(variable_1 != variable_2),
    by = c("variable_1", "variable_2"))

    df_ <- df_ %>% 
      dplyr::mutate(empirical_r_se = (1 - empirical_r^2)/sqrt(pairwise_n - 3))
    return(df_)
}

holdout_item_pairs = join_pairwise_correlation(holdout_human_data, holdout_machine_data)

arrow::write_feather(holdout_item_pairs, sink = file.path(data_path, glue("data/intermediate/{model_name}.raw.osf-bainbridge-2021-s2-0.item_correlations.feather")))

pt_holdout_item_pairs = join_pairwise_correlation(pt_holdout_human_data, pt_holdout_machine_data)

arrow::write_feather(pt_holdout_item_pairs, sink = file.path(data_path, glue("data/intermediate/{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.item_correlations.feather")))

Join pairwise scale correlations

predict_manifest_scores = function(human_data, machine_data, mapping_data, scale_data) {
  human_cor = human_data %>%
    cor(use = "p")

  machine_cor = machine_data %>%
    cor(use = "p")

  mapping_data <- mapping_data %>% 
                             rename(scale_0 = scale0,
                                    scale_1 = scale1)
  items_by_scale <- bind_rows(
    scale_data %>% filter(scale_1 == "") %>% left_join(mapping_data %>% select(-scale_1), by = c("instrument", "scale_0")),
    scale_data %>% filter(scale_1 != "") %>% left_join(mapping_data, by = c("instrument", "scale_0", "scale_1"))
  )

  scale_data = items_by_scale %>%
    dplyr::group_by(keyed, scale) %>%
    dplyr::summarize(
      items = list(variable)
    ) %>%
    dplyr::rowwise() %>%
    dplyr::mutate(
      human_cor = list(human_cor[items, items]),
      reverse_keyed_items = list(find_reverse_items_by_first_item(human_cor, keyed)),
    ) %>%
    dplyr::select(-human_cor) %>%
    dplyr::ungroup()


  scale_pairs = combn(x = scale_data$scale, m = 2) %>%
    t() %>% 
    as_tibble()
  
  # no pairs between subscales and their parents
  scale_pairs <- scale_pairs %>% 
    filter(! str_detect(V1, fixed(V2))) %>% 
    filter(! str_detect(V2, fixed(V1))) %>% 
    as.matrix()

  manifest_scores = tibble()

  calculate_row_means = function(data_, scale_data_) {
    data_ %>%
      dplyr::select(
        scale_data_$items %>%
          unlist() %>%
          dplyr::all_of()
      ) %>%
      dplyr::mutate_at(
        .vars = scale_data_$reverse_keyed_items %>%
          unlist(),
        .funs = function(x) max(., na.rm = TRUE) + 1 - x
      ) %>%
      rowMeans(na.rm = TRUE)
  }

  for (i in seq_len(nrow(scale_pairs))) {
    scale_a = scale_pairs[i, 1]
    scale_b = scale_pairs[i, 2]

    scale_data_a = scale_data %>%
      dplyr::filter(scale == scale_a)

    scale_data_b = scale_data %>%
      dplyr::filter(scale == scale_b)

    human_a = calculate_row_means(human_data, scale_data_a)
    human_b = calculate_row_means(human_data, scale_data_b)
    machine_a = calculate_row_means(machine_data, scale_data_a)
    machine_b = calculate_row_means(machine_data, scale_data_b)

    human_cor <- broom::tidy(cor.test(human_a, human_b))
    manifest_scores = manifest_scores %>%
      dplyr::bind_rows(
        tibble(
          scale_a = scale_a,
          scale_b = scale_b,
          empirical_r = human_cor$estimate,
          pairwise_n = human_cor$parameter + 2,
          empirical_r_se = (1 - empirical_r^2)/sqrt(pairwise_n - 3),
          synthetic_r = cor(machine_a, machine_b, use = "p")
        )
      )
  }
  return(manifest_scores)
}


manifest_scores = predict_manifest_scores(holdout_human_data, holdout_machine_data, holdout_mapping_data, scales)
## `summarise()` has grouped output by 'keyed'. You can override using the
## `.groups` argument.
## 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.osf-bainbridge-2021-s2-0.scale_correlations.feather")))

pt_manifest_scores = predict_manifest_scores(pt_holdout_human_data, pt_holdout_machine_data, holdout_mapping_data, scales)
## `summarise()` has grouped output by 'keyed'. You can override using the
## `.groups` argument.
arrow::write_feather(pt_manifest_scores, sink = file.path(data_path, glue("data/intermediate/{pretrained_model_name}.raw.osf-bainbridge-2021-s2-0.scale_correlations.feather")))

Create random scales

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

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"))
)
set.seed(05102019)

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]] <- 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()
nrow(random_scales)
## [1] 200
write_rds(random_scales, file = file.path(data_path, glue("data/intermediate/pilot_study.random_scales.rds")))


holdout_llm <- holdout_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_holdout_llm <- pt_holdout_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 <- holdout_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_holdout_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 <- 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

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

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

holdout_human_data <- holdout_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 = holdout_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(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),
    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 304 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `rel_real = list(...)`.
## ℹ In row 114.
## Caused by warning in `sqrt()`:
## ! NaNs produced
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 303 remaining warnings.
write_rds(scales, file = file.path(data_path, glue("data/intermediate/scales_with_alpha_se.rds")))
LS0tCnRpdGxlOiAiVmVjdG9yIHJlcHJlc2VudGF0aW9ucyB0byBjb3NpbmUgc2ltaWxhcml0aWVzIgpvdXRwdXQ6IGh0bWxfZG9jdW1lbnQKZGF0ZTogIjIwMjQtMDItMDkiCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0Usd2FybmluZz1GLG1lc3NhZ2U9Rn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBlcnJvciA9IFQpCgojIExpYnJhcmllcyBhbmQgU2V0dGluZ3MKCiMgTGlicyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoYXJyb3cpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShwc3ljaCkKbGlicmFyeShsYXZhYW4pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoZ3JpZEV4dHJhKQoKbW9kZWxfbmFtZSA9ICJJdGVtU2ltaWxhcml0eVRyYWluaW5nLTIwMjQwNTAyLXRyaWFsMTIiCiNtb2RlbF9uYW1lID0gIml0ZW0tc2ltaWxhcml0eS0yMDIzMTAxOC0xMjI1MDQiCnByZXRyYWluZWRfbW9kZWxfbmFtZSA9ICJhbGwtbXBuZXQtYmFzZS12MiIKCmRhdGFfcGF0aCA9IGdsdWUoIi4vIikKcHJldHJhaW5lZF9kYXRhX3BhdGggPSBnbHVlKCIuLyIpCgpzZXQuc2VlZCg0MikKc291cmNlKCJnbG9iYWxfZnVuY3Rpb25zLlIiKQpgYGAKCgojIyBMb2FkIGRhdGEKYGBge3J9CmhvbGRvdXRfbWFwcGluZ19kYXRhID0gYXJyb3c6OnJlYWRfZmVhdGhlcigKICBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAubWFwcGluZy5mZWF0aGVyIikpCikKCmZhY2V0cyA8LSByZWFkcjo6cmVhZF90c3YoImlnbm9yZS9mYWNldHMudHN2IikKaG9sZG91dF9tYXBwaW5nX2RhdGEgPC0gaG9sZG91dF9tYXBwaW5nX2RhdGEgJT4lIAogIHNlcGFyYXRlKHZhcmlhYmxlLCBjKCJpbnN0cnVtZW50MSIsICJmYWNldCIpLCByZW1vdmUgPSBGLGV4dHJhID0gImRyb3AiKSAlPiUgCiAgbGVmdF9qb2luKGZhY2V0cyAlPiUgc2VsZWN0KGluc3RydW1lbnQxLCBmYWNldCwgc2NhbGUyKSwgYnkgPSBjKCJpbnN0cnVtZW50MSIsICJmYWNldCIpKSAlPiUgCiAgbXV0YXRlKHNjYWxlMSA9IGNvYWxlc2NlKHNjYWxlMSwgc2NhbGUyKSkgJT4lIAogIHNlbGVjdCgtaW5zdHJ1bWVudDEsIC1mYWNldCwgLXNjYWxlMikKCgpmaXJzdF9pdGVtcyA8LSBiaW5kX3Jvd3MoCiAgICBob2xkb3V0X21hcHBpbmdfZGF0YSAlPiUKICBzZWxlY3QodmFyaWFibGUsIGluc3RydW1lbnQsIHNjYWxlXzAgPSBzY2FsZTAsIHNjYWxlXzEgPSBzY2FsZTEsCiAgICAgICAgIGl0ZW1fdGV4dCkgJT4lCiAgbXV0YXRlKGluc3RydW1lbnQgPSBjb2FsZXNjZShzdHJfYyhzdHJfdHJpbShpbnN0cnVtZW50KSwgIiAiKSwgIiIpLAogICAgICAgICBzY2FsZV8wID0gY29hbGVzY2Uoc3RyX2Moc3RyX3RyaW0oc2NhbGVfMCksICIgIiksICIiKSwKICAgICAgICAgc2NhbGVfMSA9ICIiLAogICAgICAgICBzY2FsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJfdHJpbShwYXN0ZTAoaW5zdHJ1bWVudCwgc2NhbGVfMCwgc2NhbGVfMSkpLCAiW15hLXpBLVpfMC05XSIsICJfIikKICApLAogIGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JQogIHNlbGVjdCh2YXJpYWJsZSwgaW5zdHJ1bWVudCwgc2NhbGVfMCA9IHNjYWxlMCwgc2NhbGVfMSA9IHNjYWxlMSwKICAgICAgICAgaXRlbV90ZXh0KSAlPiUKICBtdXRhdGUoaW5zdHJ1bWVudCA9IGNvYWxlc2NlKHN0cl9jKHN0cl90cmltKGluc3RydW1lbnQpLCAiICIpLCAiIiksCiAgICAgICAgIHNjYWxlXzAgPSBjb2FsZXNjZShzdHJfYyhzdHJfdHJpbShzY2FsZV8wKSwgIiAiKSwgIiIpLAogICAgICAgICBzY2FsZV8xID0gY29hbGVzY2Uoc3RyX3RyaW0oc2NhbGVfMSksICIiKSwKICAgICAgICAgc2NhbGUgPSBzdHJfcmVwbGFjZV9hbGwoc3RyX3RyaW0ocGFzdGUwKGluc3RydW1lbnQsIHNjYWxlXzAsIHNjYWxlXzEpKSwgIlteYS16QS1aXzAtOV0iLCAiXyIpCiAgKSkgJT4lIAogIGdyb3VwX2J5KHNjYWxlKSAlPiUgCiAgYXJyYW5nZSh2YXJpYWJsZSkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgPT0gMSkgJT4lIAogIG11dGF0ZShpbnN0cnVtZW50ID0gc3RyX3RyaW0oaW5zdHJ1bWVudCksCiAgICAgICAgIHNjYWxlXzAgPSBzdHJfdHJpbShzY2FsZV8wKSwKICAgICAgICAgc2NhbGVfMSA9IHN0cl90cmltKHNjYWxlXzEpKQoKcmlvOjpleHBvcnQoZmlyc3RfaXRlbXMgJT4lIAogIHNlbGVjdChzY2FsZSwgaXRlbV90ZXh0LCB2YXJpYWJsZSksICJpZ25vcmUvZmlyc3RfaXRlbXMueGxzeCIpCmNvZGVkIDwtIHJpbzo6aW1wb3J0KCJpZ25vcmUvZmlyc3RfaXRlbXNfY29kZWQueGxzeCIpCgpzY2FsZXMgPC0gZmlyc3RfaXRlbXMgJT4lIGxlZnRfam9pbihjb2RlZCkgJT4lIAogIG11dGF0ZShzY2FsZSA9IHN0cl9yZXBsYWNlKHNjYWxlLCAib3Blbm5uZXNzIiwgIm9wZW5uZXNzIiksCiAgICAgICAgIHNjYWxlXzAgPSBzdHJfcmVwbGFjZShzY2FsZV8wLCAib3Blbm5uZXNzIiwgIm9wZW5uZXNzIikpICU+JSAKICBzZWxlY3QoLWl0ZW1fdGV4dCwgLXZhcmlhYmxlKQoKYXJyb3c6OndyaXRlX2ZlYXRoZXIoc2NhbGVzLCBzaW5rID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAuc2NhbGVzLmZlYXRoZXIiKSkKKQoKaG9sZG91dF9tYXBwaW5nX2RhdGEgPC0gaG9sZG91dF9tYXBwaW5nX2RhdGEgJT4lIAogIG11dGF0ZShzY2FsZTAgPSBzdHJfcmVwbGFjZShzY2FsZTAsICJvcGVubm5lc3MiLCAib3Blbm5lc3MiKSkKCmFycm93Ojp3cml0ZV9mZWF0aGVyKGhvbGRvdXRfbWFwcGluZ19kYXRhLCBzaW5rID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgie21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAubWFwcGluZzIuZmVhdGhlciIpKQopCgoKIyBwcmUtdHJhaW5lZCBtb2RlbApwdF9ob2xkb3V0X2h1bWFuX2RhdGEgPSBhcnJvdzo6cmVhZF9mZWF0aGVyKAogIGZpbGUgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJpZ25vcmUue3ByZXRyYWluZWRfbW9kZWxfbmFtZX0ucmF3Lm9zZi1iYWluYnJpZGdlLTIwMjEtczItMC5odW1hbi5mZWF0aGVyIikpCikKCnB0X2hvbGRvdXRfbWFjaGluZV9kYXRhID0gYXJyb3c6OnJlYWRfZmVhdGhlcigKICBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLntwcmV0cmFpbmVkX21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAubWFjaGluZS5mZWF0aGVyIikpCikKCiMgZmluZS10dW5lZCBtb2RlbApob2xkb3V0X21hY2hpbmVfZGF0YSA9IGFycm93OjpyZWFkX2ZlYXRoZXIoCiAgZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoInttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLm1hY2hpbmUuZmVhdGhlciIpKQopCgpob2xkb3V0X2h1bWFuX2RhdGEgPSBhcnJvdzo6cmVhZF9mZWF0aGVyKAogIGZpbGUgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCBnbHVlKCJ7bW9kZWxfbmFtZX0ucmF3Lm9zZi1iYWluYnJpZGdlLTIwMjEtczItMC5odW1hbi5mZWF0aGVyIikpCikKIyAKIyAjIHByZS10cmFpbmVkIG1vZGVsCiMgaG9sZG91dF9tYWNoaW5lX2RhdGFfcHQgPSBhcnJvdzo6cmVhZF9mZWF0aGVyKAojICAgZmlsZSA9IGZpbGUucGF0aChwcmV0cmFpbmVkX2RhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLntwcmV0cmFpbmVkX21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAubWFjaGluZS5mZWF0aGVyIikpCiMgKQpgYGAKCiMjIERlc2NyaXB0aW9uCmBgYHtyfQpucm93KGhvbGRvdXRfaHVtYW5fZGF0YSkgIyByZXNwb25kZW50cwpuY29sKGhvbGRvdXRfaHVtYW5fZGF0YSkgIyBpdGVtcwpucm93KGhvbGRvdXRfbWFjaGluZV9kYXRhKSAjIHZlY3RvciBkaW1lbnNpb25zCm5jb2woaG9sZG91dF9tYWNoaW5lX2RhdGEpICMgaXRlbXMKbl9kaXN0aW5jdChob2xkb3V0X21hcHBpbmdfZGF0YSRpbnN0cnVtZW50KSAjIGluc3RydW1lbnRzCm5fZGlzdGluY3QoaG9sZG91dF9tYXBwaW5nX2RhdGEkc2NhbGUwKSAjIGNvbnN0cnVjdHMKbl9kaXN0aW5jdChob2xkb3V0X21hcHBpbmdfZGF0YSRpbnN0cnVtZW50LCBob2xkb3V0X21hcHBpbmdfZGF0YSRzY2FsZTApICMgc2NhbGVzCm5fZGlzdGluY3Qoc3RyX2MoaG9sZG91dF9tYXBwaW5nX2RhdGEkaW5zdHJ1bWVudCwgaG9sZG91dF9tYXBwaW5nX2RhdGEkc2NhbGUwLCBob2xkb3V0X21hcHBpbmdfZGF0YSRzY2FsZTEpKSAjIHN1YnNjYWxlcwpgYGAKCgojIyBKb2luIHBhaXJ3aXNlIGl0ZW0gY29ycmVsYXRpb25zCmBgYHtyfQpqb2luX3BhaXJ3aXNlX2NvcnJlbGF0aW9uID0gZnVuY3Rpb24oZGZfaHVtYW4sIGRmX21hY2hpbmUpIHsKICAgIGl0ZW1fcGFpcnMgPSBjb21ibih4ID0gbmFtZXMoZGZfaHVtYW4pLCBtID0gMikgJT4lCiAgICAgICAgdCgpICU+JSAKICAgICAgYXMuZGF0YS5mcmFtZSgpCiAgICBjb2xuYW1lcyhpdGVtX3BhaXJzKSA8LSBjKCJ2YXJpYWJsZV8xIiwgInZhcmlhYmxlXzIiKQoKICAgIGRmXyAgPSAKICAgICAgaXRlbV9wYWlycyAlPiUgCiAgICAgIGxlZnRfam9pbigKICAgICAgZGZfaHVtYW4gJT4lIAogICAgICAgIGNvcih1c2UgPSAicCIpICU+JSAKICAgICAgICByZXNoYXBlMjo6bWVsdCgpICU+JSAKICAgICAgICBkcGx5cjo6bGVmdF9qb2luKAogICAgICAgICAgSG1pc2M6OnJjb3JyKGFzLm1hdHJpeChob2xkb3V0X2h1bWFuX2RhdGEpKSRuICU+JSAKICAgICAgICAgIHJlc2hhcGUyOjptZWx0KCkgJT4lIAogICAgICAgICAgZHBseXI6OnJlbmFtZShwYWlyd2lzZV9uID0gdmFsdWUpLAogICAgICAgICAgYnkgPSBjKCJWYXIxIiwgIlZhcjIiKQogICAgICAgICkgJT4lIAogICAgICAgIGRwbHlyOjpsZWZ0X2pvaW4oCiAgICAgICAgICAgIHkgPSBkZl9tYWNoaW5lICU+JSAKICAgICAgICAgICAgY29yKHVzZSA9ICJwIikgJT4lIAogICAgICAgICAgICByZXNoYXBlMjo6bWVsdCgpLAogICAgICAgICAgICBieSA9IGMoIlZhcjEiLCAiVmFyMiIpCiAgICAgICAgKSAlPiUgCiAgICAgICAgZHBseXI6OnJlbmFtZSgKICAgICAgICAgICAgZW1waXJpY2FsX3IgPSAidmFsdWUueCIsCiAgICAgICAgICAgIHN5bnRoZXRpY19yID0gInZhbHVlLnkiLAogICAgICAgICAgICB2YXJpYWJsZV8xID0gVmFyMSwKICAgICAgICAgICAgdmFyaWFibGVfMiA9IFZhcjIKICAgICAgICApICU+JSAKICAgICAgICBkcGx5cjo6ZmlsdGVyKHZhcmlhYmxlXzEgIT0gdmFyaWFibGVfMiksCiAgICBieSA9IGMoInZhcmlhYmxlXzEiLCAidmFyaWFibGVfMiIpKQoKICAgIGRmXyA8LSBkZl8gJT4lIAogICAgICBkcGx5cjo6bXV0YXRlKGVtcGlyaWNhbF9yX3NlID0gKDEgLSBlbXBpcmljYWxfcl4yKS9zcXJ0KHBhaXJ3aXNlX24gLSAzKSkKICAgIHJldHVybihkZl8pCn0KCmhvbGRvdXRfaXRlbV9wYWlycyA9IGpvaW5fcGFpcndpc2VfY29ycmVsYXRpb24oaG9sZG91dF9odW1hbl9kYXRhLCBob2xkb3V0X21hY2hpbmVfZGF0YSkKCmFycm93Ojp3cml0ZV9mZWF0aGVyKGhvbGRvdXRfaXRlbV9wYWlycywgc2luayA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS57bW9kZWxfbmFtZX0ucmF3Lm9zZi1iYWluYnJpZGdlLTIwMjEtczItMC5pdGVtX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQoKcHRfaG9sZG91dF9pdGVtX3BhaXJzID0gam9pbl9wYWlyd2lzZV9jb3JyZWxhdGlvbihwdF9ob2xkb3V0X2h1bWFuX2RhdGEsIHB0X2hvbGRvdXRfbWFjaGluZV9kYXRhKQoKYXJyb3c6OndyaXRlX2ZlYXRoZXIocHRfaG9sZG91dF9pdGVtX3BhaXJzLCBzaW5rID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLntwcmV0cmFpbmVkX21vZGVsX25hbWV9LnJhdy5vc2YtYmFpbmJyaWRnZS0yMDIxLXMyLTAuaXRlbV9jb3JyZWxhdGlvbnMuZmVhdGhlciIpKSkKYGBgCgoKIyMgSm9pbiBwYWlyd2lzZSBzY2FsZSBjb3JyZWxhdGlvbnMKYGBge3J9CnByZWRpY3RfbWFuaWZlc3Rfc2NvcmVzID0gZnVuY3Rpb24oaHVtYW5fZGF0YSwgbWFjaGluZV9kYXRhLCBtYXBwaW5nX2RhdGEsIHNjYWxlX2RhdGEpIHsKICBodW1hbl9jb3IgPSBodW1hbl9kYXRhICU+JQogICAgY29yKHVzZSA9ICJwIikKCiAgbWFjaGluZV9jb3IgPSBtYWNoaW5lX2RhdGEgJT4lCiAgICBjb3IodXNlID0gInAiKQoKICBtYXBwaW5nX2RhdGEgPC0gbWFwcGluZ19kYXRhICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWUoc2NhbGVfMCA9IHNjYWxlMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfMSA9IHNjYWxlMSkKICBpdGVtc19ieV9zY2FsZSA8LSBiaW5kX3Jvd3MoCiAgICBzY2FsZV9kYXRhICU+JSBmaWx0ZXIoc2NhbGVfMSA9PSAiIikgJT4lIGxlZnRfam9pbihtYXBwaW5nX2RhdGEgJT4lIHNlbGVjdCgtc2NhbGVfMSksIGJ5ID0gYygiaW5zdHJ1bWVudCIsICJzY2FsZV8wIikpLAogICAgc2NhbGVfZGF0YSAlPiUgZmlsdGVyKHNjYWxlXzEgIT0gIiIpICU+JSBsZWZ0X2pvaW4obWFwcGluZ19kYXRhLCBieSA9IGMoImluc3RydW1lbnQiLCAic2NhbGVfMCIsICJzY2FsZV8xIikpCiAgKQoKICBzY2FsZV9kYXRhID0gaXRlbXNfYnlfc2NhbGUgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoa2V5ZWQsIHNjYWxlKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUoCiAgICAgIGl0ZW1zID0gbGlzdCh2YXJpYWJsZSkKICAgICkgJT4lCiAgICBkcGx5cjo6cm93d2lzZSgpICU+JQogICAgZHBseXI6Om11dGF0ZSgKICAgICAgaHVtYW5fY29yID0gbGlzdChodW1hbl9jb3JbaXRlbXMsIGl0ZW1zXSksCiAgICAgIHJldmVyc2Vfa2V5ZWRfaXRlbXMgPSBsaXN0KGZpbmRfcmV2ZXJzZV9pdGVtc19ieV9maXJzdF9pdGVtKGh1bWFuX2Nvciwga2V5ZWQpKSwKICAgICkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KC1odW1hbl9jb3IpICU+JQogICAgZHBseXI6OnVuZ3JvdXAoKQoKCiAgc2NhbGVfcGFpcnMgPSBjb21ibih4ID0gc2NhbGVfZGF0YSRzY2FsZSwgbSA9IDIpICU+JQogICAgdCgpICU+JSAKICAgIGFzX3RpYmJsZSgpCiAgCiAgIyBubyBwYWlycyBiZXR3ZWVuIHN1YnNjYWxlcyBhbmQgdGhlaXIgcGFyZW50cwogIHNjYWxlX3BhaXJzIDwtIHNjYWxlX3BhaXJzICU+JSAKICAgIGZpbHRlcighIHN0cl9kZXRlY3QoVjEsIGZpeGVkKFYyKSkpICU+JSAKICAgIGZpbHRlcighIHN0cl9kZXRlY3QoVjIsIGZpeGVkKFYxKSkpICU+JSAKICAgIGFzLm1hdHJpeCgpCgogIG1hbmlmZXN0X3Njb3JlcyA9IHRpYmJsZSgpCgogIGNhbGN1bGF0ZV9yb3dfbWVhbnMgPSBmdW5jdGlvbihkYXRhXywgc2NhbGVfZGF0YV8pIHsKICAgIGRhdGFfICU+JQogICAgICBkcGx5cjo6c2VsZWN0KAogICAgICAgIHNjYWxlX2RhdGFfJGl0ZW1zICU+JQogICAgICAgICAgdW5saXN0KCkgJT4lCiAgICAgICAgICBkcGx5cjo6YWxsX29mKCkKICAgICAgKSAlPiUKICAgICAgZHBseXI6Om11dGF0ZV9hdCgKICAgICAgICAudmFycyA9IHNjYWxlX2RhdGFfJHJldmVyc2Vfa2V5ZWRfaXRlbXMgJT4lCiAgICAgICAgICB1bmxpc3QoKSwKICAgICAgICAuZnVucyA9IGZ1bmN0aW9uKHgpIG1heCguLCBuYS5ybSA9IFRSVUUpICsgMSAtIHgKICAgICAgKSAlPiUKICAgICAgcm93TWVhbnMobmEucm0gPSBUUlVFKQogIH0KCiAgZm9yIChpIGluIHNlcV9sZW4obnJvdyhzY2FsZV9wYWlycykpKSB7CiAgICBzY2FsZV9hID0gc2NhbGVfcGFpcnNbaSwgMV0KICAgIHNjYWxlX2IgPSBzY2FsZV9wYWlyc1tpLCAyXQoKICAgIHNjYWxlX2RhdGFfYSA9IHNjYWxlX2RhdGEgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoc2NhbGUgPT0gc2NhbGVfYSkKCiAgICBzY2FsZV9kYXRhX2IgPSBzY2FsZV9kYXRhICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKHNjYWxlID09IHNjYWxlX2IpCgogICAgaHVtYW5fYSA9IGNhbGN1bGF0ZV9yb3dfbWVhbnMoaHVtYW5fZGF0YSwgc2NhbGVfZGF0YV9hKQogICAgaHVtYW5fYiA9IGNhbGN1bGF0ZV9yb3dfbWVhbnMoaHVtYW5fZGF0YSwgc2NhbGVfZGF0YV9iKQogICAgbWFjaGluZV9hID0gY2FsY3VsYXRlX3Jvd19tZWFucyhtYWNoaW5lX2RhdGEsIHNjYWxlX2RhdGFfYSkKICAgIG1hY2hpbmVfYiA9IGNhbGN1bGF0ZV9yb3dfbWVhbnMobWFjaGluZV9kYXRhLCBzY2FsZV9kYXRhX2IpCgogICAgaHVtYW5fY29yIDwtIGJyb29tOjp0aWR5KGNvci50ZXN0KGh1bWFuX2EsIGh1bWFuX2IpKQogICAgbWFuaWZlc3Rfc2NvcmVzID0gbWFuaWZlc3Rfc2NvcmVzICU+JQogICAgICBkcGx5cjo6YmluZF9yb3dzKAogICAgICAgIHRpYmJsZSgKICAgICAgICAgIHNjYWxlX2EgPSBzY2FsZV9hLAogICAgICAgICAgc2NhbGVfYiA9IHNjYWxlX2IsCiAgICAgICAgICBlbXBpcmljYWxfciA9IGh1bWFuX2NvciRlc3RpbWF0ZSwKICAgICAgICAgIHBhaXJ3aXNlX24gPSBodW1hbl9jb3IkcGFyYW1ldGVyICsgMiwKICAgICAgICAgIGVtcGlyaWNhbF9yX3NlID0gKDEgLSBlbXBpcmljYWxfcl4yKS9zcXJ0KHBhaXJ3aXNlX24gLSAzKSwKICAgICAgICAgIHN5bnRoZXRpY19yID0gY29yKG1hY2hpbmVfYSwgbWFjaGluZV9iLCB1c2UgPSAicCIpCiAgICAgICAgKQogICAgICApCiAgfQogIHJldHVybihtYW5pZmVzdF9zY29yZXMpCn0KCgptYW5pZmVzdF9zY29yZXMgPSBwcmVkaWN0X21hbmlmZXN0X3Njb3Jlcyhob2xkb3V0X2h1bWFuX2RhdGEsIGhvbGRvdXRfbWFjaGluZV9kYXRhLCBob2xkb3V0X21hcHBpbmdfZGF0YSwgc2NhbGVzKQoKYXJyb3c6OndyaXRlX2ZlYXRoZXIobWFuaWZlc3Rfc2NvcmVzLCBzaW5rID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLnttb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLnNjYWxlX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQoKcHRfbWFuaWZlc3Rfc2NvcmVzID0gcHJlZGljdF9tYW5pZmVzdF9zY29yZXMocHRfaG9sZG91dF9odW1hbl9kYXRhLCBwdF9ob2xkb3V0X21hY2hpbmVfZGF0YSwgaG9sZG91dF9tYXBwaW5nX2RhdGEsIHNjYWxlcykKCmFycm93Ojp3cml0ZV9mZWF0aGVyKHB0X21hbmlmZXN0X3Njb3Jlcywgc2luayA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS57cHJldHJhaW5lZF9tb2RlbF9uYW1lfS5yYXcub3NmLWJhaW5icmlkZ2UtMjAyMS1zMi0wLnNjYWxlX2NvcnJlbGF0aW9ucy5mZWF0aGVyIikpKQpgYGAKCgojIyBDcmVhdGUgcmFuZG9tIHNjYWxlcwpgYGB7cn0KbWFwcGluZ19kYXRhIDwtIGhvbGRvdXRfbWFwcGluZ19kYXRhICU+JQogIHJlbmFtZShzY2FsZV8wID0gc2NhbGUwLAogICAgICAgICBzY2FsZV8xID0gc2NhbGUxKQoKaXRlbXNfYnlfc2NhbGUgPC0gYmluZF9yb3dzKAogIHNjYWxlcyAlPiUgZmlsdGVyKHNjYWxlXzEgPT0gIiIpICU+JSBsZWZ0X2pvaW4obWFwcGluZ19kYXRhICU+JSBzZWxlY3QoLXNjYWxlXzEpLCBieSA9IGMoImluc3RydW1lbnQiLCAic2NhbGVfMCIpKSwKICBzY2FsZXMgJT4lIGZpbHRlcihzY2FsZV8xICE9ICIiKSAlPiUgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSwgYnkgPSBjKCJpbnN0cnVtZW50IiwgInNjYWxlXzAiLCAic2NhbGVfMSIpKQopCnNldC5zZWVkKDA1MTAyMDE5KQoKcmFuZG9tX3NjYWxlcyA8LSBsaXN0KCkKZm9yKGkgaW4gMToyMDApIHsKICBuX2l0ZW1zIDwtIHJwb2lzKDEsIDYpCiAgbl9pdGVtcyA8LSBpZl9lbHNlKG5faXRlbXMgPCAzLCAzLCBuX2l0ZW1zKQogIHJhbmRvbV9zY2FsZXNbW2ldXSA8LSBob2xkb3V0X21hcHBpbmdfZGF0YSAlPiUKICAgIHNhbXBsZV9uKG5faXRlbXMpICU+JQogICAgbXV0YXRlKHNjYWxlID0gcGFzdGUwKCJyYW5kb20iLCBpKSkgJT4lCiAgICBncm91cF9ieShzY2FsZSkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIGl0ZW1zID0gbGlzdCh2YXJpYWJsZSksCiAgICAgIG51bWJlcl9vZl9pdGVtcyA9IG5fZGlzdGluY3QodmFyaWFibGUpLAogICAgICBsdm4gPSBwYXN0ZShmaXJzdChzY2FsZSksICIgPX4gIiwgcGFzdGUodmFyaWFibGUsIGNvbGxhcHNlID0gIiArICIpKSkgJT4lCiAgICBkcm9wX25hKCkgJT4lIAogICAgbXV0YXRlKGtleWVkID0gMSkKfQoKcmFuZG9tX3NjYWxlcyA8LSBiaW5kX3Jvd3MocmFuZG9tX3NjYWxlcykgJT4lIAogIGRpc3RpbmN0KGl0ZW1zLCAua2VlcF9hbGwgPSBUUlVFKSAlPiUgCiAgcm93d2lzZSgpICU+JSAKICBtdXRhdGUoCiAgICByZXZlcnNlX2l0ZW1zID0gbGlzdChyYW5kb21seV9jaG9vc2VfaXRlbXNfZm9yX3JldmVyc2lvbihpdGVtcykpCiAgICApICU+JSAKICB1bmdyb3VwKCkKbnJvdyhyYW5kb21fc2NhbGVzKQp3cml0ZV9yZHMocmFuZG9tX3NjYWxlcywgZmlsZSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIGdsdWUoImlnbm9yZS5waWxvdF9zdHVkeS5yYW5kb21fc2NhbGVzLnJkcyIpKSkKCgpob2xkb3V0X2xsbSA8LSBob2xkb3V0X2l0ZW1fcGFpcnMgJT4lCiAgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzEgPSB2YXJpYWJsZSwgSW5zdHJ1bWVudEEgPSBpbnN0cnVtZW50LCBTY2FsZUEgPSBzY2FsZV8wLCBTdWJzY2FsZUEgPSBzY2FsZV8xKSkgJT4lCiAgbGVmdF9qb2luKG1hcHBpbmdfZGF0YSAlPiUgc2VsZWN0KHZhcmlhYmxlXzIgPSB2YXJpYWJsZSwgSW5zdHJ1bWVudEIgPSBpbnN0cnVtZW50LCBTY2FsZUIgPSBzY2FsZV8wLCBTdWJzY2FsZUIgPSBzY2FsZV8xKSkKCnB0X2hvbGRvdXRfbGxtIDwtIHB0X2hvbGRvdXRfaXRlbV9wYWlycyAlPiUKICBsZWZ0X2pvaW4obWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMSA9IHZhcmlhYmxlLCBJbnN0cnVtZW50QSA9IGluc3RydW1lbnQsIFNjYWxlQSA9IHNjYWxlXzAsIFN1YnNjYWxlQSA9IHNjYWxlXzEpKSAlPiUKICBsZWZ0X2pvaW4obWFwcGluZ19kYXRhICU+JSBzZWxlY3QodmFyaWFibGVfMiA9IHZhcmlhYmxlLCBJbnN0cnVtZW50QiA9IGluc3RydW1lbnQsIFNjYWxlQiA9IHNjYWxlXzAsIFN1YnNjYWxlQiA9IHNjYWxlXzEpKQoKY29yc19sbG0gPC0gaG9sZG91dF9pdGVtX3BhaXJzICU+JQogIHNlbGVjdCh4ID0gdmFyaWFibGVfMSwgeSA9IHZhcmlhYmxlXzIsIHIgPSBzeW50aGV0aWNfcikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpIHw+CiAgaWdyYXBoOjpncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQgPSBGQUxTRSkgfD4KICBpZ3JhcGg6OmFzX2FkamFjZW5jeV9tYXRyaXgoYXR0ciA9ICJyIiwgc3BhcnNlID0gRkFMU0UpCmRpYWcoY29yc19sbG0pIDwtIDEKCnB0X2NvcnNfbGxtIDwtIHB0X2hvbGRvdXRfaXRlbV9wYWlycyAlPiUKICBzZWxlY3QoeCA9IHZhcmlhYmxlXzEsIHkgPSB2YXJpYWJsZV8yLCByID0gc3ludGhldGljX3IpICU+JQogIGFzLmRhdGEuZnJhbWUoKSB8PgogIGlncmFwaDo6Z3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGRpcmVjdGVkID0gRkFMU0UpIHw+CiAgaWdyYXBoOjphc19hZGphY2VuY3lfbWF0cml4KGF0dHIgPSAiciIsIHNwYXJzZSA9IEZBTFNFKQpkaWFnKHB0X2NvcnNfbGxtKSA8LSAxCgpjb3JzX3JlYWwgPC0gaG9sZG91dF9sbG0gJT4lIAogIHNlbGVjdCh4ID0gdmFyaWFibGVfMSwgeSA9IHZhcmlhYmxlXzIsIHIgPSBlbXBpcmljYWxfcikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpIHw+CiAgaWdyYXBoOjpncmFwaF9mcm9tX2RhdGFfZnJhbWUoZGlyZWN0ZWQgPSBGQUxTRSkgfD4KICBpZ3JhcGg6OmFzX2FkamFjZW5jeV9tYXRyaXgoYXR0ciA9ICJyIiwgc3BhcnNlID0gRkFMU0UpCmRpYWcoY29yc19yZWFsKSA8LSAxCgpyZWFsX3NjYWxlcyA8LSBpdGVtc19ieV9zY2FsZSAlPiUKICBncm91cF9ieShzY2FsZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgaXRlbXMgPSBsaXN0KHZhcmlhYmxlKSwKICAgIG51bWJlcl9vZl9pdGVtcyA9IG5fZGlzdGluY3QodmFyaWFibGUpLAogICAga2V5ZWQgPSBmaXJzdChrZXllZCksCiAgICBsdm4gPSBwYXN0ZShmaXJzdChzY2FsZSksICIgPX4gIiwgcGFzdGUodmFyaWFibGUsIGNvbGxhcHNlID0gIiArICIpKSkgJT4lCiAgZ3JvdXBfYnkoc2NhbGUpICU+JQogIG11dGF0ZShyZXZlcnNlX2l0ZW1zID0gbGlzdChmaW5kX3JldmVyc2VfaXRlbXNfYnlfZmlyc3RfaXRlbShjb3JzX3JlYWxbdW5saXN0KGl0ZW1zKSwgdW5saXN0KGl0ZW1zKV0sIGtleWVkKSkpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIHVuZ3JvdXAoKQoKc2NhbGVzIDwtIGJpbmRfcm93cyhyZWFsID0gcmVhbF9zY2FsZXMsIHJhbmRvbSA9IHJhbmRvbV9zY2FsZXMsIC5pZCA9ICJ0eXBlIikKCmhvbGRvdXRfaHVtYW5fZGF0YSA8LSBob2xkb3V0X2h1bWFuX2RhdGEgJT4lIGhhdmVuOjp6YXBfbGFiZWxzKCkKc2NhbGVzIDwtIHNjYWxlcyAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKHB0X3JfbGxtID0gbGlzdChwdF9jb3JzX2xsbVtpdGVtcywgaXRlbXNdKSwKICAgICAgICAgcl9sbG0gPSBsaXN0KGNvcnNfbGxtW2l0ZW1zLCBpdGVtc10pLAogICAgICAgICByX3JlYWwgPSBsaXN0KGNvcnNfcmVhbFtpdGVtcywgaXRlbXNdKSwKICAgICAgICAgcmV2ZXJzZV9pdGVtc19ieV8xc3QgPSBsaXN0KGZpbmRfcmV2ZXJzZV9pdGVtc19ieV9maXJzdF9pdGVtKHJfcmVhbCwga2V5ZWQpKSwKICAgICAgICAgTl9yZWFsID0gaG9sZG91dF9pdGVtX3BhaXJzICU+JSAKICAgICAgICAgICBmaWx0ZXIodmFyaWFibGVfMSAlaW4lIGl0ZW1zLCB2YXJpYWJsZV8yICVpbiUgaXRlbXMpICU+JSAKICAgICAgICAgICBzdW1tYXJpc2UobWluX249bWluKHBhaXJ3aXNlX24pKSAlPiUgcHVsbChtaW5fbikpICU+JQogIG11dGF0ZSgKICAgIHJlbF9yZWFsID0gbGlzdChwc3ljaDo6YWxwaGEoaG9sZG91dF9odW1hbl9kYXRhWywgaXRlbXNdLCBrZXlzID0gcmV2ZXJzZV9pdGVtcywgbi5pdGVyID0gMTAwMCkpLAogICAgcmVsX2xsbSA9IGxpc3QocHN5Y2g6OmFscGhhKHJfbGxtLCBrZXlzID0gcmV2ZXJzZV9pdGVtcywgbi5vYnMgPSBOX3JlYWwpJGZlbGR0KSwKICAgIHJlbF9wdF9sbG0gPSBsaXN0KHBzeWNoOjphbHBoYShwdF9yX2xsbSwga2V5cyA9IHJldmVyc2VfaXRlbXMsIG4ub2JzID0gTl9yZWFsKSRmZWxkdCkpICU+JQogIG11dGF0ZShlbXBpcmljYWxfYWxwaGEgPSByZWxfcmVhbCRmZWxkdCRhbHBoYSRyYXdfYWxwaGEsCiAgICAgICAgIHN5bnRoZXRpY19hbHBoYSA9IHJlbF9sbG0kYWxwaGEkcmF3X2FscGhhLAogICAgICAgICBwdF9zeW50aGV0aWNfYWxwaGEgPSByZWxfcHRfbGxtJGFscGhhJHJhd19hbHBoYSkgJT4lCiAgbXV0YXRlKAogICAgZW1waXJpY2FsX2FscGhhX3NlID0gc2QocmVsX3JlYWwkYm9vdFssInJhd19hbHBoYSJdKSwKICApCgp3cml0ZV9yZHMoc2NhbGVzLCBmaWxlID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgZ2x1ZSgiaWdub3JlLnNjYWxlc193aXRoX2FscGhhX3NlLnJkcyIpKSkKYGBgCg==