library(readxl)
library(dplyr)
library(tidyr)
library(tibble)
raw_sheet <- read_excel(
  "Questionnaire_results_EN.xlsx",
  sheet = "Podatki",
  col_names = FALSE
)

raw_sheet
var_names <- raw_sheet |>
  slice(1) |>
  unlist(use.names = FALSE) |>
  as.character()

question_text <- raw_sheet |>
  slice(2) |>
  unlist(use.names = FALSE) |>
  as.character()

data_raw <- raw_sheet |>
  slice(-(1:2))

names(data_raw) <- var_names

data_raw <- data_raw |>
  mutate(respondent_id = row_number()) |>
  relocate(respondent_id)

glimpse(data_raw)
Rows: 338
Columns: 93
$ respondent_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,…
$ Q1            <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q2            <chr> "3", "2", "3", "2", "3", "2", "3", "3", "3", "3", "2", "2", "3…
$ Q3a           <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q3b           <chr> "1", "1", "1", "1", "0", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q3c           <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q3d           <chr> "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1…
$ Q3e           <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "0", "1…
$ Q3f           <chr> "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0…
$ Q3g           <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q3g_text      <chr> "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-…
$ Q4            <chr> "3", "2", "1", "1", "2", "2", "1", "1", "4", "2", "2", "1", "2…
$ Q4_5_text     <chr> "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-…
$ Q5a           <chr> "5", "7", "7", "4", "5", "7", "7", "4", "5", "5", "7", "7", "7…
$ Q5b           <chr> "5", "6", "5", "4", "2", "5", "2", "4", "4", "2", "2", "2", "1…
$ Q5c           <chr> "6", "6", "7", "6", "7", "7", "7", "4", "5", "6", "7", "7", "7…
$ Q5d           <chr> "6", "3", "5", "7", "5", "7", "7", "4", "6", "7", "6", "6", "4…
$ Q5e           <chr> "5", "5", "6", "1", "4", "5", "4", "4", "3", "1", "6", "5", "1…
$ Q6a           <chr> "6", "7", "7", "6", "5", "7", "6", "4", "4", "6", "6", "7", "7…
$ Q6b           <chr> "2", "6", "7", "4", "4", "4", "4", "4", "3", "5", "3", "4", "4…
$ Q6c           <chr> "6", "7", "7", "6", "5", "5", "3", "4", "6", "5", "5", "5", "4…
$ Q6d           <chr> "2", "7", "6", "4", "6", "6", "5", "4", "4", "6", "6", "5", "5…
$ Q6e           <chr> "5", "1", "7", "2", "3", "1", "2", "4", "4", "5", "2", "1", "1…
$ Q6f           <chr> "6", "5", "3", "4", "3", "1", "2", "4", "5", "5", "1", "1", "1…
$ Q6g           <chr> "6", "6", "7", "6", "5", "1", "4", "4", "6", "6", "5", "7", "4…
$ Q6h           <chr> "5", "7", "7", "6", "6", "6", "3", "4", "5", "6", "6", "6", "4…
$ Q6i           <chr> "3", "6", "5", "4", "4", "5", "3", "4", "4", "5", "2", "5", "4…
$ Q8a           <chr> "5", "7", "7", "1", "3", "3", "2", "4", "4", "6", "6", "3", "1…
$ Q8b           <chr> "7", "7", "6", "3", "3", "6", "2", "4", "3", "6", "6", "4", "4…
$ Q8c           <chr> "2", "6", "5", "1", "2", "1", "2", "4", "3", "3", "1", "1", "1…
$ Q8d           <chr> "5", "7", "7", "7", "3", "7", "2", "4", "3", "5", "5", "6", "1…
$ Q8e           <chr> "5", "6", "7", "7", "2", "2", "5", "4", "3", "7", "5", "5", "4…
$ Q10a          <chr> "7", "7", "7", "6", "3", "6", "2", "4", "1", "6", "6", "5", "4…
$ Q10b          <chr> "7", "7", "7", "5", "3", "7", "2", "4", "5", "6", "5", "5", "6…
$ Q10c          <chr> "5", "7", "5", "1", "4", "5", "2", "4", "4", "5", "5", "7", "4…
$ Q10d          <chr> "3", "3", "6", "2", "3", "2", "2", "4", "4", "5", "4", "4", "4…
$ Q11a          <chr> "4", "3", "7", "1", "1", "2", "1", "4", "4", "4", "2", "1", "1…
$ Q11b          <chr> "3", "6", "7", "1", "1", "2", "1", "4", "1", "6", "6", "2", "1…
$ Q11c          <chr> "6", "7", "5", "4", "1", "6", "1", "4", "4", "2", "3", "4", "1…
$ Q11d          <chr> "1", "2", "5", "2", "1", "2", "1", "4", "4", "5", "1", "2", "1…
$ Q11e          <chr> "1", "1", "5", "1", "1", "2", "1", "4", "4", "4", "2", "1", "1…
$ Q11f          <chr> "3", "6", "7", "4", "1", "2", "1", "4", "4", "2", "3", "6", "1…
$ Q12a          <chr> "7", "7", "7", "7", "7", "7", "7", "4", "7", "7", "7", "7", "7…
$ Q12b          <chr> "7", "7", "7", "7", "7", "7", "7", "4", "7", "7", "6", "7", "7…
$ Q12c          <chr> "7", "5", "7", "7", "7", "7", "7", "4", "7", "6", "7", "7", "7…
$ Q12d          <chr> "5", "3", "7", "7", "5", "7", "7", "4", "7", "6", "7", "7", "7…
$ Q12e          <chr> "6", "5", "7", "7", "6", "5", "7", "4", "7", "6", "4", "7", "7…
$ Q12f          <chr> "4", "3", "6", "5", "4", "5", "7", "4", "7", "6", "1", "6", "7…
$ Q12g          <chr> "7", "6", "7", "6", "6", "7", "7", "4", "7", "6", "3", "5", "7…
$ Q12h          <chr> "6", "6", "7", "5", "4", "5", "7", "4", "7", "6", "2", "5", "7…
$ Q12i          <chr> "4", "3", "7", "3", "2", "7", "7", "4", "7", "6", "7", "5", "7…
$ Q13a          <chr> "6", "4", "8", "3", "7", "2", "8", "4", "5", "4", "8", "5", "7…
$ Q13b          <chr> "8", "3", "2", "8", "5", "8", "8", "4", "8", "8", "8", "8", "1…
$ Q13c          <chr> "3", "5", "8", "6", "4", "8", "8", "4", "8", "8", "2", "8", "8…
$ Q13d          <chr> "7", "7", "8", "8", "6", "7", "6", "-1", "8", "8", "4", "8", "…
$ Q13e          <chr> "7", "7", "8", "7", "4", "8", "6", "-1", "8", "8", "8", "8", "…
$ Q13f          <chr> "8", "5", "8", "8", "4", "8", "8", "4", "8", "8", "8", "8", "8…
$ Q13g          <chr> "8", "4", "8", "8", "5", "8", "8", "4", "1", "8", "8", "8", "8…
$ Q14a          <chr> "7", "3", "8", "2", "7", "3", "8", "4", "7", "2", "8", "5", "7…
$ Q14b          <chr> "8", "4", "4", "8", "5", "8", "8", "4", "8", "8", "8", "8", "1…
$ Q14c          <chr> "8", "5", "8", "5", "4", "8", "8", "4", "8", "8", "8", "8", "-…
$ Q14d          <chr> "5", "6", "8", "8", "5", "8", "6", "4", "8", "8", "8", "8", "-…
$ Q14e          <chr> "8", "6", "8", "5", "8", "8", "5", "4", "8", "8", "8", "8", "-…
$ Q14f          <chr> "8", "5", "8", "8", "8", "8", "8", "4", "8", "8", "8", "8", "8…
$ Q14g          <chr> "8", "3", "8", "8", "8", "8", "8", "4", "1", "8", "8", "8", "8…
$ Q15a          <chr> "7", "4", "8", "3", "7", "7", "6", "4", "7", "5", "8", "6", "7…
$ Q15b          <chr> "8", "3", "5", "8", "5", "8", "8", "4", "8", "8", "8", "8", "3…
$ Q15c          <chr> "8", "5", "8", "5", "5", "8", "8", "4", "8", "8", "7", "8", "-…
$ Q15d          <chr> "7", "6", "7", "8", "5", "7", "6", "4", "8", "8", "6", "8", "8…
$ Q15e          <chr> "8", "6", "8", "6", "8", "8", "6", "4", "8", "8", "8", "8", "8…
$ Q15f          <chr> "8", "4", "8", "8", "8", "8", "-1", "4", "8", "8", "8", "8", "…
$ Q15g          <chr> "8", "3", "8", "8", "8", "8", "8", "4", "1", "8", "8", "8", "8…
$ Q17           <chr> "5", "7", "5", "1", "3", "5", "1", "-1", "4", "6", "6", "3", "…
$ Q18           <chr> "1", "1", "1", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2…
$ Q19           <chr> "1", "3", "1", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2",…
$ Q21           <chr> "2002", "2002", "2002", "2001", "2004", "2002", "2000", "2004"…
$ Q22           <chr> "2", "1", "1", "2", "1", "2", "1", "1", "1", "1", "2", "1", "1…
$ Q23           <chr> "3", "1", "1", "2", "1", "1", "1", "3", "1", "1", "3", "2", "3…
$ Q24           <chr> "6", "6", "5", "6", "5", "5", "6", "5", "6", "6", "7", "6", "6…
$ Q25a          <chr> "1", "0", "0", "0", "1", "1", "0", "1", "1", "1", "0", "1", "1…
$ Q25b          <chr> "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25c          <chr> "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0…
$ Q25d          <chr> "1", "1", "1", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0…
$ Q25e          <chr> "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25f          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25g          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25h          <chr> "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25i          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25j          <chr> "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0…
$ Q25k          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25l          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25l_text     <chr> "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-…
$ Q26           <chr> "2", "3", "3", "2", "1", "3", "5", "1", "4", "1", "1", "1", "4…
question_lookup <- tibble(
  variable = var_names,
  question = question_text
)

question_lookup
data_clean <- data_raw |>
  mutate(
    across(
      everything(),
      ~ replace(as.character(.), as.character(.) == "-1", NA)
    )
  )

glimpse(data_clean)
Rows: 338
Columns: 93
$ respondent_id <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",…
$ Q1            <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q2            <chr> "3", "2", "3", "2", "3", "2", "3", "3", "3", "3", "2", "2", "3…
$ Q3a           <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q3b           <chr> "1", "1", "1", "1", "0", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q3c           <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1…
$ Q3d           <chr> "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1…
$ Q3e           <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "0", "1…
$ Q3f           <chr> "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0…
$ Q3g           <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q3g_text      <chr> "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-…
$ Q4            <chr> "3", "2", "1", "1", "2", "2", "1", "1", "4", "2", "2", "1", "2…
$ Q4_5_text     <chr> "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-…
$ Q5a           <chr> "5", "7", "7", "4", "5", "7", "7", "4", "5", "5", "7", "7", "7…
$ Q5b           <chr> "5", "6", "5", "4", "2", "5", "2", "4", "4", "2", "2", "2", "1…
$ Q5c           <chr> "6", "6", "7", "6", "7", "7", "7", "4", "5", "6", "7", "7", "7…
$ Q5d           <chr> "6", "3", "5", "7", "5", "7", "7", "4", "6", "7", "6", "6", "4…
$ Q5e           <chr> "5", "5", "6", "1", "4", "5", "4", "4", "3", "1", "6", "5", "1…
$ Q6a           <chr> "6", "7", "7", "6", "5", "7", "6", "4", "4", "6", "6", "7", "7…
$ Q6b           <chr> "2", "6", "7", "4", "4", "4", "4", "4", "3", "5", "3", "4", "4…
$ Q6c           <chr> "6", "7", "7", "6", "5", "5", "3", "4", "6", "5", "5", "5", "4…
$ Q6d           <chr> "2", "7", "6", "4", "6", "6", "5", "4", "4", "6", "6", "5", "5…
$ Q6e           <chr> "5", "1", "7", "2", "3", "1", "2", "4", "4", "5", "2", "1", "1…
$ Q6f           <chr> "6", "5", "3", "4", "3", "1", "2", "4", "5", "5", "1", "1", "1…
$ Q6g           <chr> "6", "6", "7", "6", "5", "1", "4", "4", "6", "6", "5", "7", "4…
$ Q6h           <chr> "5", "7", "7", "6", "6", "6", "3", "4", "5", "6", "6", "6", "4…
$ Q6i           <chr> "3", "6", "5", "4", "4", "5", "3", "4", "4", "5", "2", "5", "4…
$ Q8a           <chr> "5", "7", "7", "1", "3", "3", "2", "4", "4", "6", "6", "3", "1…
$ Q8b           <chr> "7", "7", "6", "3", "3", "6", "2", "4", "3", "6", "6", "4", "4…
$ Q8c           <chr> "2", "6", "5", "1", "2", "1", "2", "4", "3", "3", "1", "1", "1…
$ Q8d           <chr> "5", "7", "7", "7", "3", "7", "2", "4", "3", "5", "5", "6", "1…
$ Q8e           <chr> "5", "6", "7", "7", "2", "2", "5", "4", "3", "7", "5", "5", "4…
$ Q10a          <chr> "7", "7", "7", "6", "3", "6", "2", "4", "1", "6", "6", "5", "4…
$ Q10b          <chr> "7", "7", "7", "5", "3", "7", "2", "4", "5", "6", "5", "5", "6…
$ Q10c          <chr> "5", "7", "5", "1", "4", "5", "2", "4", "4", "5", "5", "7", "4…
$ Q10d          <chr> "3", "3", "6", "2", "3", "2", "2", "4", "4", "5", "4", "4", "4…
$ Q11a          <chr> "4", "3", "7", "1", "1", "2", "1", "4", "4", "4", "2", "1", "1…
$ Q11b          <chr> "3", "6", "7", "1", "1", "2", "1", "4", "1", "6", "6", "2", "1…
$ Q11c          <chr> "6", "7", "5", "4", "1", "6", "1", "4", "4", "2", "3", "4", "1…
$ Q11d          <chr> "1", "2", "5", "2", "1", "2", "1", "4", "4", "5", "1", "2", "1…
$ Q11e          <chr> "1", "1", "5", "1", "1", "2", "1", "4", "4", "4", "2", "1", "1…
$ Q11f          <chr> "3", "6", "7", "4", "1", "2", "1", "4", "4", "2", "3", "6", "1…
$ Q12a          <chr> "7", "7", "7", "7", "7", "7", "7", "4", "7", "7", "7", "7", "7…
$ Q12b          <chr> "7", "7", "7", "7", "7", "7", "7", "4", "7", "7", "6", "7", "7…
$ Q12c          <chr> "7", "5", "7", "7", "7", "7", "7", "4", "7", "6", "7", "7", "7…
$ Q12d          <chr> "5", "3", "7", "7", "5", "7", "7", "4", "7", "6", "7", "7", "7…
$ Q12e          <chr> "6", "5", "7", "7", "6", "5", "7", "4", "7", "6", "4", "7", "7…
$ Q12f          <chr> "4", "3", "6", "5", "4", "5", "7", "4", "7", "6", "1", "6", "7…
$ Q12g          <chr> "7", "6", "7", "6", "6", "7", "7", "4", "7", "6", "3", "5", "7…
$ Q12h          <chr> "6", "6", "7", "5", "4", "5", "7", "4", "7", "6", "2", "5", "7…
$ Q12i          <chr> "4", "3", "7", "3", "2", "7", "7", "4", "7", "6", "7", "5", "7…
$ Q13a          <chr> "6", "4", "8", "3", "7", "2", "8", "4", "5", "4", "8", "5", "7…
$ Q13b          <chr> "8", "3", "2", "8", "5", "8", "8", "4", "8", "8", "8", "8", "1…
$ Q13c          <chr> "3", "5", "8", "6", "4", "8", "8", "4", "8", "8", "2", "8", "8…
$ Q13d          <chr> "7", "7", "8", "8", "6", "7", "6", NA, "8", "8", "4", "8", "8"…
$ Q13e          <chr> "7", "7", "8", "7", "4", "8", "6", NA, "8", "8", "8", "8", "8"…
$ Q13f          <chr> "8", "5", "8", "8", "4", "8", "8", "4", "8", "8", "8", "8", "8…
$ Q13g          <chr> "8", "4", "8", "8", "5", "8", "8", "4", "1", "8", "8", "8", "8…
$ Q14a          <chr> "7", "3", "8", "2", "7", "3", "8", "4", "7", "2", "8", "5", "7…
$ Q14b          <chr> "8", "4", "4", "8", "5", "8", "8", "4", "8", "8", "8", "8", "1…
$ Q14c          <chr> "8", "5", "8", "5", "4", "8", "8", "4", "8", "8", "8", "8", NA…
$ Q14d          <chr> "5", "6", "8", "8", "5", "8", "6", "4", "8", "8", "8", "8", NA…
$ Q14e          <chr> "8", "6", "8", "5", "8", "8", "5", "4", "8", "8", "8", "8", NA…
$ Q14f          <chr> "8", "5", "8", "8", "8", "8", "8", "4", "8", "8", "8", "8", "8…
$ Q14g          <chr> "8", "3", "8", "8", "8", "8", "8", "4", "1", "8", "8", "8", "8…
$ Q15a          <chr> "7", "4", "8", "3", "7", "7", "6", "4", "7", "5", "8", "6", "7…
$ Q15b          <chr> "8", "3", "5", "8", "5", "8", "8", "4", "8", "8", "8", "8", "3…
$ Q15c          <chr> "8", "5", "8", "5", "5", "8", "8", "4", "8", "8", "7", "8", NA…
$ Q15d          <chr> "7", "6", "7", "8", "5", "7", "6", "4", "8", "8", "6", "8", "8…
$ Q15e          <chr> "8", "6", "8", "6", "8", "8", "6", "4", "8", "8", "8", "8", "8…
$ Q15f          <chr> "8", "4", "8", "8", "8", "8", NA, "4", "8", "8", "8", "8", "8"…
$ Q15g          <chr> "8", "3", "8", "8", "8", "8", "8", "4", "1", "8", "8", "8", "8…
$ Q17           <chr> "5", "7", "5", "1", "3", "5", "1", NA, "4", "6", "6", "3", "2"…
$ Q18           <chr> "1", "1", "1", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2…
$ Q19           <chr> "1", "3", "1", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2",…
$ Q21           <chr> "2002", "2002", "2002", "2001", "2004", "2002", "2000", "2004"…
$ Q22           <chr> "2", "1", "1", "2", "1", "2", "1", "1", "1", "1", "2", "1", "1…
$ Q23           <chr> "3", "1", "1", "2", "1", "1", "1", "3", "1", "1", "3", "2", "3…
$ Q24           <chr> "6", "6", "5", "6", "5", "5", "6", "5", "6", "6", "7", "6", "6…
$ Q25a          <chr> "1", "0", "0", "0", "1", "1", "0", "1", "1", "1", "0", "1", "1…
$ Q25b          <chr> "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25c          <chr> "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "1", "0", "0…
$ Q25d          <chr> "1", "1", "1", "0", "0", "1", "1", "0", "0", "0", "1", "0", "0…
$ Q25e          <chr> "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25f          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25g          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25h          <chr> "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25i          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25j          <chr> "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0…
$ Q25k          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25l          <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0…
$ Q25l_text     <chr> "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-2", "-…
$ Q26           <chr> "2", "3", "3", "2", "1", "3", "5", "1", "4", "1", "1", "1", "4…
ids_removed <- data_clean |>
  filter(is.na(Q22) | is.na(Q23)) |>
  pull(respondent_id)

ids_removed
[1] "63"  "64"  "181" "272" "325"
data_clean <- data_clean |>
  filter(!is.na(Q22), !is.na(Q23))

nrow(data_raw)
[1] 338
nrow(data_clean)
[1] 333
missing_summary <- data_clean |>
  summarise(across(everything(), ~ sum(is.na(.)))) |>
  pivot_longer(
    cols = everything(),
    names_to = "variable",
    values_to = "n_missing"
  ) |>
  arrange(desc(n_missing))

missing_summary
question_lookup |> 
  filter(grepl("Q13|Q14|Q15", variable))
data_clean |>
  select(Q13a:Q15g) |>
  summarise(across(everything(), ~ paste(sort(unique(.)), collapse = ", "))) |>
  pivot_longer(
    cols = everything(),
    names_to = "variable",
    values_to = "values"
  )
data_clean <- data_clean |>
  mutate(
    across(
      Q13a:Q15g,
      ~ as.numeric(replace(., . == "8", NA))
    )
  )
data_clean |>
  select(Q13a:Q15g) |>
  summarise(across(everything(), ~ paste(sort(unique(.)), collapse = ", "))) |>
  pivot_longer(
    cols = everything(),
    names_to = "variable",
    values_to = "values"
  )
bank_means <- tibble(
  bank = c("OTP", "Gorenjska Banka", "NLB", "Revolut", "N26", "Intesa SanPaolo", "UniCredit"),
  innovation = c(
    mean(data_clean$Q13a, na.rm = TRUE),
    mean(data_clean$Q13b, na.rm = TRUE),
    mean(data_clean$Q13c, na.rm = TRUE),
    mean(data_clean$Q13d, na.rm = TRUE),
    mean(data_clean$Q13e, na.rm = TRUE),
    mean(data_clean$Q13f, na.rm = TRUE),
    mean(data_clean$Q13g, na.rm = TRUE)
  ),
  customer_support = c(
    mean(data_clean$Q14a, na.rm = TRUE),
    mean(data_clean$Q14b, na.rm = TRUE),
    mean(data_clean$Q14c, na.rm = TRUE),
    mean(data_clean$Q14d, na.rm = TRUE),
    mean(data_clean$Q14e, na.rm = TRUE),
    mean(data_clean$Q14f, na.rm = TRUE),
    mean(data_clean$Q14g, na.rm = TRUE)
  ),
  reliability = c(
    mean(data_clean$Q15a, na.rm = TRUE),
    mean(data_clean$Q15b, na.rm = TRUE),
    mean(data_clean$Q15c, na.rm = TRUE),
    mean(data_clean$Q15d, na.rm = TRUE),
    mean(data_clean$Q15e, na.rm = TRUE),
    mean(data_clean$Q15f, na.rm = TRUE),
    mean(data_clean$Q15g, na.rm = TRUE)
  )
)

bank_means
pca_result <- prcomp(
  bank_means[, c("innovation", "customer_support", "reliability")],
  scale. = TRUE
)

pca_result
Standard deviations (1, .., p=3):
[1] 1.6443246 0.5059028 0.2006464

Rotation (n x k) = (3 x 3):
                       PC1         PC2        PC3
innovation       0.5700010  0.66141369  0.4874739
customer_support 0.5614043 -0.74671513  0.3567095
reliability      0.5999367  0.07034521 -0.7969489
bank_coordinates <- as.data.frame(pca_result$x)
bank_coordinates$bank <- bank_means$bank

bank_coordinates
plot(
  bank_coordinates$PC1,
  bank_coordinates$PC2,
  xlab = "PC1",
  ylab = "PC2",
  main = "Perception Map of Banks",
  pch = 19
)

text(
  bank_coordinates$PC1,
  bank_coordinates$PC2,
  labels = bank_coordinates$bank,
  pos = 3
)

library(ggplot2)

ggplot(bank_coordinates, aes(x = PC1, y = PC2, label = bank)) +
  geom_point(size = 3) +
  geom_text(vjust = -0.7) +
  labs(
    title = "Perception Map of Banks",
    x = "Dimension 1",
    y = "Dimension 2"
  ) +
  theme_minimal()

library(FactoMineR)
library(factoextra)
mat <- bank_means |>
  tibble::column_to_rownames("bank") |>
  as.matrix()

pca_bank <- FactoMineR::PCA(mat, scale.unit = TRUE, graph = FALSE)

factoextra::fviz_pca_ind(
  pca_bank,
  repel = TRUE
) +
  ggplot2::ggtitle("Perceptual map of banks (Q13–Q15)")

factoextra::fviz_pca_biplot(
  pca_bank,
  repel = TRUE,
  col.var = "gray30"
) +
  ggplot2::ggtitle("Perceptual map of banks with dimensions (Q13–Q15)")

factoextra::fviz_pca_biplot(
  pca_bank,
  repel = TRUE,
  col.var = "gray35",
  col.ind = "steelblue",
  pointsize = 3
) +
  ggplot2::ggtitle("Perceptual Map of Banks") +
  ggplot2::xlab("Overall Digital Banking Performance") +
  ggplot2::ylab("Customer Support vs Innovation") +
  ggplot2::theme_minimal() +
  ggplot2::theme(
    plot.title = ggplot2::element_text(face = "bold"),
    axis.title = ggplot2::element_text(face = "bold")
  )

factoextra::fviz_pca_biplot(
  pca_bank,
  repel = TRUE,
  col.var = "gray30"
) +
  ggplot2::ggtitle("Perceptual map of banks with dimensions (Q13–Q15)") +
  ggplot2::xlab("Dim1 (90.1%): Overall Digital Banking Performance") +
  ggplot2::ylab("Dim2 (8.5%): Customer Support vs Innovation")

data_clean |>
  select(Q6a, Q6b, Q6d, Q6e, Q6h, Q6i, Q8a, Q8b, Q8c, Q8d, Q8e) |>
  summarise(across(everything(), ~ paste(sort(unique(.)), collapse = ", "))) |>
  pivot_longer(
    cols = everything(),
    names_to = "variable",
    values_to = "values"
  )
cluster_data <- data_clean |>
  select(Q6a, Q6b, Q6d, Q6e, Q6h, Q6i, Q8a, Q8b, Q8c, Q8d, Q8e) |>
  mutate(across(everything(), as.numeric))

glimpse(cluster_data)
Rows: 333
Columns: 11
$ Q6a <dbl> 6, 7, 7, 6, 5, 7, 6, 4, 4, 6, 6, 7, 7, 5, 7, 7, 6, 6, 5, 4, 6, 7, 7, 7, …
$ Q6b <dbl> 2, 6, 7, 4, 4, 4, 4, 4, 3, 5, 3, 4, 4, 2, 1, 7, NA, 6, 5, 3, 6, 2, 1, 5,…
$ Q6d <dbl> 2, 7, 6, 4, 6, 6, 5, 4, 4, 6, 6, 5, 5, 2, 5, 6, 3, 3, 5, 5, 7, 7, 7, 5, …
$ Q6e <dbl> 5, 1, 7, 2, 3, 1, 2, 4, 4, 5, 2, 1, 1, 1, 2, 5, 2, 7, 2, 5, 5, 2, 1, 2, …
$ Q6h <dbl> 5, 7, 7, 6, 6, 6, 3, 4, 5, 6, 6, 6, 4, 3, 4, 7, NA, 6, 4, 5, 6, 4, 7, 7,…
$ Q6i <dbl> 3, 6, 5, 4, 4, 5, 3, 4, 4, 5, 2, 5, 4, 2, 2, 3, 7, 4, 5, 5, 7, 4, 1, 7, …
$ Q8a <dbl> 5, 7, 7, 1, 3, 3, 2, 4, 4, 6, 6, 3, 1, 3, 1, 5, 6, 4, 4, 4, 7, 4, 1, 6, …
$ Q8b <dbl> 7, 7, 6, 3, 3, 6, 2, 4, 3, 6, 6, 4, 4, 3, 3, 6, 6, 5, 3, 5, 7, 2, 7, 6, …
$ Q8c <dbl> 2, 6, 5, 1, 2, 1, 2, 4, 3, 3, 1, 1, 1, 3, 3, 3, 1, 1, 2, 2, 7, 3, 1, 1, …
$ Q8d <dbl> 5, 7, 7, 7, 3, 7, 2, 4, 3, 5, 5, 6, 1, 3, 3, 7, 4, 1, 5, 5, 7, 6, 7, 7, …
$ Q8e <dbl> 5, 6, 7, 7, 2, 2, 5, 4, 3, 7, 5, 5, 4, 3, 5, 5, 4, 1, 6, 5, 7, 4, 7, 7, …
cluster_data |>
  summarise(across(everything(), ~ sum(is.na(.)))) |>
  pivot_longer(
    cols = everything(),
    names_to = "variable",
    values_to = "n_missing"
  )
cluster_data_complete <- cluster_data |>
  tidyr::drop_na()

nrow(cluster_data)
[1] 333
nrow(cluster_data_complete)
[1] 323
cluster_scaled <- scale(cluster_data_complete)

cluster_scaled
               Q6a        Q6b         Q6d        Q6e         Q6h         Q6i
  [1,] -0.01386611 -0.8167893 -1.71942066  0.8688513  0.01405589 -0.48919895
  [2,]  0.73259278  1.1780913  1.11411441 -1.1392987  1.14906922  1.04489097
  [3,]  0.73259278  1.6768114  0.54740739  1.8729263  1.14906922  0.53352766
  [4,] -0.01386611  0.1806510 -0.58600663 -0.6372612  0.58156256  0.02216435
  [5,] -0.76032500  0.1806510  0.54740739 -0.1352237  0.58156256  0.02216435
  [6,]  0.73259278  0.1806510  0.54740739 -1.1392987  0.58156256  0.53352766
  [7,] -0.01386611  0.1806510 -0.01929962 -0.6372612 -1.12095744 -0.48919895
  [8,] -1.50678388  0.1806510 -0.58600663  0.3668138 -0.55345077  0.02216435
  [9,] -1.50678388 -0.3180692 -0.58600663  0.3668138  0.01405589  0.02216435
 [10,] -0.01386611  0.6793711  0.54740739  0.8688513  0.58156256  0.53352766
 [11,] -0.01386611 -0.3180692  0.54740739 -0.6372612  0.58156256 -1.00056226
 [12,]  0.73259278  0.1806510 -0.01929962 -1.1392987  0.58156256  0.53352766
 [13,]  0.73259278  0.1806510 -0.01929962 -1.1392987 -0.55345077  0.02216435
 [14,] -0.76032500 -0.8167893 -1.71942066 -1.1392987 -1.12095744 -1.00056226
 [15,]  0.73259278 -1.3155095 -0.01929962 -0.6372612 -0.55345077 -1.00056226
 [16,]  0.73259278  1.6768114  0.54740739  0.8688513  1.14906922 -0.48919895
 [17,] -0.01386611  1.1780913 -1.15271365  1.8729263  0.58156256  0.02216435
 [18,] -0.76032500  0.6793711 -0.01929962 -0.6372612 -0.55345077  0.53352766
 [19,] -1.50678388 -0.3180692 -0.01929962  0.8688513  0.01405589  0.53352766
 [20,] -0.01386611  1.1780913  1.11411441  0.8688513  0.58156256  1.55625428
 [21,]  0.73259278 -0.8167893  1.11411441 -0.6372612 -0.55345077  0.02216435
 [22,]  0.73259278 -1.3155095  1.11411441 -1.1392987  1.14906922 -1.51192557
 [23,]  0.73259278  0.6793711 -0.01929962 -0.6372612  1.14906922  1.55625428
 [24,]  0.73259278 -0.8167893  0.54740739 -0.1352237  1.14906922  1.55625428
 [25,] -0.76032500 -0.3180692 -0.01929962 -0.6372612 -1.12095744  1.04489097
 [26,] -2.25324277 -0.3180692 -0.58600663 -0.6372612  0.01405589  0.02216435
 [27,]  0.73259278  1.1780913  1.11411441 -0.1352237  0.01405589  0.53352766
 [28,] -0.01386611 -0.3180692 -0.01929962  0.3668138  0.01405589 -0.48919895
 [29,]  0.73259278  0.6793711  0.54740739 -0.6372612  1.14906922  1.55625428
 [30,]  0.73259278  1.6768114  1.11411441 -0.1352237  1.14906922 -1.00056226
 [31,] -0.01386611  1.6768114 -1.71942066  0.8688513 -0.55345077  0.53352766
 [32,]  0.73259278  0.1806510  0.54740739 -0.1352237  1.14906922  0.02216435
 [33,] -0.01386611 -0.8167893 -0.01929962 -1.1392987  0.01405589 -1.00056226
 [34,]  0.73259278  1.6768114  1.11411441  0.3668138  1.14906922 -1.51192557
 [35,] -0.01386611  0.6793711 -0.58600663  1.8729263 -1.68846410 -1.00056226
 [36,]  0.73259278  1.6768114  1.11411441  0.8688513  1.14906922  1.04489097
 [37,] -0.01386611 -1.3155095  1.11411441  1.8729263  1.14906922  1.55625428
 [38,] -0.76032500  0.1806510 -0.01929962  0.3668138  0.01405589  1.04489097
 [39,]  0.73259278  1.6768114 -1.71942066 -1.1392987 -0.55345077 -1.51192557
 [40,] -0.01386611  0.1806510 -0.01929962  1.3708888  0.01405589  0.02216435
 [41,] -0.76032500  1.6768114  1.11411441  1.8729263  1.14906922  0.53352766
 [42,] -0.76032500  0.6793711 -0.01929962 -0.1352237  0.01405589  0.02216435
 [43,]  0.73259278  1.1780913  0.54740739 -0.1352237 -0.55345077  0.53352766
 [44,] -0.01386611  0.6793711 -1.15271365  0.8688513  0.01405589  1.04489097
 [45,]  0.73259278  0.6793711  0.54740739  0.3668138  1.14906922  0.02216435
 [46,] -0.01386611  0.6793711 -0.01929962 -0.6372612  0.58156256 -0.48919895
 [47,]  0.73259278 -1.3155095 -1.71942066 -0.6372612  1.14906922  1.04489097
 [48,] -0.01386611 -0.3180692 -0.01929962  0.8688513 -0.55345077  0.53352766
 [49,]  0.73259278 -1.3155095 -2.28612767 -1.1392987 -2.25597077 -1.51192557
 [50,] -0.01386611  1.1780913 -0.01929962 -0.1352237  0.01405589  0.53352766
 [51,]  0.73259278  1.6768114  1.11411441  1.3708888  1.14906922  0.02216435
 [52,] -0.76032500 -1.3155095 -0.58600663  0.8688513  0.58156256  0.53352766
 [53,] -0.76032500 -0.8167893 -0.58600663 -0.1352237  0.58156256  0.02216435
 [54,] -1.50678388 -0.8167893 -0.01929962 -0.1352237  0.58156256  0.02216435
 [55,] -0.01386611 -0.3180692 -1.71942066 -0.6372612 -0.55345077  1.55625428
 [56,] -0.01386611  0.1806510  0.54740739 -0.6372612  0.01405589 -0.48919895
 [57,] -0.01386611 -0.3180692  0.54740739 -0.1352237  0.58156256 -1.00056226
 [58,] -0.01386611 -0.3180692 -0.58600663 -0.6372612  0.01405589 -0.48919895
 [59,] -0.01386611  0.1806510 -0.01929962 -0.6372612  0.01405589 -0.48919895
 [60,]  0.73259278  1.6768114 -0.01929962  0.8688513  0.58156256 -0.48919895
 [61,] -0.01386611  0.6793711 -0.01929962  0.8688513 -1.12095744  0.02216435
 [62,] -0.76032500  1.1780913  0.54740739  0.3668138  1.14906922 -1.51192557
 [63,]  0.73259278  1.6768114  1.11411441 -0.1352237  1.14906922  1.55625428
 [64,] -0.76032500  0.1806510  0.54740739 -0.1352237  1.14906922  0.53352766
 [65,]  0.73259278  0.6793711  1.11411441  1.8729263  0.58156256 -1.51192557
 [66,]  0.73259278  1.6768114  1.11411441  1.8729263  1.14906922  1.55625428
 [67,] -1.50678388  1.6768114  1.11411441  1.8729263  1.14906922  1.55625428
 [68,]  0.73259278  1.6768114  1.11411441  1.8729263  1.14906922  1.55625428
 [69,]  0.73259278  0.1806510 -0.01929962  0.3668138  0.01405589  0.53352766
 [70,] -0.76032500 -1.3155095  0.54740739 -1.1392987  0.01405589  1.04489097
 [71,]  0.73259278  0.1806510  1.11411441  1.8729263  1.14906922  1.55625428
 [72,] -1.50678388  0.1806510  1.11411441  0.3668138 -0.55345077  0.02216435
 [73,] -2.25324277 -0.8167893  0.54740739  0.3668138  1.14906922  1.04489097
 [74,] -1.50678388  0.1806510 -0.58600663 -1.1392987 -2.25597077 -1.51192557
 [75,] -0.76032500 -0.3180692  1.11411441 -0.1352237  1.14906922 -0.48919895
 [76,]  0.73259278  1.6768114 -1.15271365 -1.1392987 -0.55345077 -1.51192557
 [77,] -0.01386611  0.1806510 -0.58600663 -0.1352237 -0.55345077  0.53352766
 [78,] -0.01386611 -0.8167893 -1.15271365 -1.1392987  0.58156256 -0.48919895
 [79,] -0.01386611 -0.3180692 -0.01929962  1.3708888  0.01405589 -0.48919895
 [80,]  0.73259278  1.6768114  1.11411441 -1.1392987  0.58156256  1.55625428
 [81,] -0.01386611  0.6793711 -0.01929962  0.8688513  0.01405589 -0.48919895
 [82,] -0.01386611 -1.3155095  1.11411441  0.8688513  0.58156256  0.02216435
 [83,]  0.73259278 -0.3180692  1.11411441 -1.1392987 -2.25597077 -1.51192557
 [84,] -0.01386611  1.1780913  0.54740739  1.3708888  0.58156256 -0.48919895
 [85,]  0.73259278  0.1806510  1.11411441  1.8729263  1.14906922  1.55625428
 [86,] -0.76032500 -1.3155095 -1.15271365  0.8688513 -0.55345077  0.53352766
 [87,]  0.73259278  1.6768114  1.11411441  1.8729263  1.14906922  1.55625428
 [88,] -0.01386611  1.6768114 -0.01929962 -1.1392987  1.14906922  0.02216435
 [89,] -0.01386611 -1.3155095 -0.01929962 -0.1352237  0.01405589 -1.00056226
 [90,] -0.01386611 -0.8167893 -1.15271365 -0.1352237 -1.12095744 -0.48919895
               Q8a        Q8b         Q8c        Q8d        Q8e
  [1,]  0.56865867  1.2364653 -0.55192981  0.1609586 -0.1379083
  [2,]  1.59766008  1.2364653  1.41251459  1.1607592  0.4053160
  [3,]  1.59766008  0.7088850  0.92140349  1.1607592  0.9485403
  [4,] -1.48934414 -0.8738559 -1.04304091  1.1607592  0.9485403
  [5,] -0.46034273 -0.8738559 -0.55192981 -0.8388419 -1.7675813
  [6,] -0.46034273  0.7088850 -1.04304091  1.1607592 -1.7675813
  [7,] -0.97484344 -1.4014362 -0.55192981 -1.3387422 -0.1379083
  [8,]  0.05415797 -0.3462756  0.43029239 -0.3389417 -0.6811327
  [9,]  0.05415797 -0.8738559 -0.06081871 -0.8388419 -1.2243570
 [10,]  1.08315937  0.7088850 -0.06081871  0.1609586  0.9485403
 [11,]  1.08315937  0.7088850 -1.04304091  0.1609586 -0.1379083
 [12,] -0.46034273 -0.3462756 -1.04304091  0.6608589 -0.1379083
 [13,] -1.48934414 -0.3462756 -1.04304091 -1.8386425 -0.6811327
 [14,] -0.46034273 -0.8738559 -0.06081871 -0.8388419 -1.2243570
 [15,] -1.48934414 -0.8738559 -0.06081871 -0.8388419 -0.1379083
 [16,]  0.56865867  0.7088850 -0.06081871  1.1607592 -0.1379083
 [17,]  0.05415797  0.1813047 -1.04304091 -1.8386425 -2.3108056
 [18,]  0.05415797 -0.8738559 -0.55192981  0.1609586  0.4053160
 [19,]  0.05415797  0.1813047 -0.55192981  0.1609586 -0.1379083
 [20,]  1.59766008  1.2364653  1.90362568  1.1607592  0.9485403
 [21,]  0.05415797 -1.4014362 -0.06081871  0.6608589 -0.6811327
 [22,] -1.48934414  1.2364653 -1.04304091  1.1607592  0.9485403
 [23,]  1.08315937  0.7088850 -1.04304091  1.1607592  0.9485403
 [24,]  1.08315937  1.2364653  0.92140349  1.1607592  0.9485403
 [25,]  1.59766008  1.2364653 -1.04304091  1.1607592 -0.6811327
 [26,]  0.05415797  0.7088850 -1.04304091  0.1609586  0.4053160
 [27,]  0.56865867  0.1813047 -0.06081871  0.6608589  0.4053160
 [28,] -0.46034273  0.1813047  0.92140349 -0.3389417 -0.1379083
 [29,]  0.56865867  1.2364653  0.43029239  1.1607592  0.9485403
 [30,] -1.48934414  0.1813047 -1.04304091  1.1607592  0.9485403
 [31,]  0.05415797  1.2364653 -1.04304091  0.6608589  0.9485403
 [32,]  1.08315937  0.1813047  0.43029239  0.1609586  0.4053160
 [33,]  0.56865867  0.1813047 -1.04304091 -0.3389417 -0.1379083
 [34,]  0.05415797  0.1813047 -1.04304091  1.1607592 -0.1379083
 [35,] -0.97484344 -1.4014362 -0.06081871 -1.3387422 -0.6811327
 [36,]  1.59766008  0.7088850  0.43029239  1.1607592  0.9485403
 [37,]  1.59766008  1.2364653  1.90362568  0.1609586  0.9485403
 [38,] -0.46034273  0.7088850 -0.55192981  0.6608589  0.4053160
 [39,] -0.97484344 -0.3462756 -1.04304091  0.6608589 -2.3108056
 [40,] -0.97484344 -0.3462756 -0.55192981 -0.3389417 -0.6811327
 [41,]  0.05415797  0.1813047 -1.04304091  0.1609586 -0.1379083
 [42,]  0.05415797  0.1813047  0.43029239  0.1609586 -0.1379083
 [43,] -0.97484344 -0.8738559  0.92140349  0.6608589  0.9485403
 [44,] -0.97484344  0.7088850 -1.04304091  1.1607592 -2.3108056
 [45,]  1.59766008  1.2364653  1.90362568  1.1607592  0.9485403
 [46,]  0.05415797  0.1813047 -0.06081871  0.1609586 -0.1379083
 [47,]  1.59766008  1.2364653 -1.04304091  1.1607592  0.9485403
 [48,]  0.05415797 -0.3462756  0.43029239 -0.3389417 -0.6811327
 [49,] -1.48934414 -1.9290165 -1.04304091 -1.8386425 -2.3108056
 [50,] -1.48934414 -0.8738559  0.43029239 -0.8388419  0.4053160
 [51,] -0.97484344  0.1813047 -1.04304091  0.1609586 -0.1379083
 [52,]  0.56865867  1.2364653 -1.04304091  1.1607592  0.4053160
 [53,] -1.48934414  0.1813047 -1.04304091  0.1609586  0.4053160
 [54,]  1.59766008  1.2364653 -1.04304091 -0.8388419 -0.1379083
 [55,] -0.46034273  0.1813047 -1.04304091  1.1607592 -0.6811327
 [56,]  1.08315937  0.7088850  0.43029239  0.1609586  0.9485403
 [57,]  1.08315937  1.2364653 -1.04304091 -0.3389417 -0.1379083
 [58,] -0.97484344 -0.3462756 -0.06081871 -0.3389417 -1.2243570
 [59,] -0.97484344  0.1813047 -1.04304091 -1.3387422  0.9485403
 [60,]  1.08315937  0.7088850  0.92140349  0.1609586  0.9485403
 [61,] -0.46034273 -0.3462756 -0.06081871  0.1609586 -0.1379083
 [62,]  0.05415797  1.2364653 -1.04304091  1.1607592  0.4053160
 [63,]  0.05415797  1.2364653 -1.04304091  1.1607592  0.9485403
 [64,]  0.56865867  0.7088850  0.92140349  1.1607592  0.4053160
 [65,] -1.48934414  1.2364653 -0.06081871  1.1607592  0.9485403
 [66,]  1.59766008  1.2364653  1.90362568  1.1607592  0.9485403
 [67,]  1.59766008  1.2364653  1.90362568  1.1607592  0.9485403
 [68,]  1.08315937  0.7088850  1.41251459  0.6608589  0.4053160
 [69,] -0.46034273  0.1813047 -0.06081871 -0.3389417 -0.1379083
 [70,]  1.08315937  0.1813047  0.43029239  0.1609586 -0.1379083
 [71,]  1.59766008  1.2364653 -1.04304091  1.1607592  0.9485403
 [72,]  0.56865867  0.7088850 -0.06081871  0.1609586  0.4053160
 [73,]  0.05415797  1.2364653 -0.55192981  1.1607592  0.4053160
 [74,] -1.48934414 -1.9290165 -1.04304091 -1.8386425 -2.3108056
 [75,] -0.46034273  1.2364653 -1.04304091  1.1607592 -0.1379083
 [76,] -1.48934414 -0.3462756 -1.04304091  0.1609586  0.9485403
 [77,]  0.05415797 -0.3462756  0.43029239 -0.3389417 -0.1379083
 [78,]  0.56865867  0.7088850 -1.04304091  0.6608589  0.9485403
 [79,]  0.05415797  1.2364653 -1.04304091  0.6608589 -0.1379083
 [80,]  0.56865867  1.2364653 -0.06081871  1.1607592  0.9485403
 [81,]  1.08315937  0.1813047  0.43029239 -0.3389417 -0.6811327
 [82,]  1.59766008  1.2364653  1.90362568  1.1607592  0.9485403
 [83,]  0.05415797  0.1813047 -1.04304091  1.1607592  0.9485403
 [84,]  1.08315937  0.7088850  1.90362568  0.6608589  0.4053160
 [85,]  0.56865867  0.1813047  0.92140349  0.1609586  0.4053160
 [86,]  0.05415797  0.1813047  0.43029239  0.6608589  0.4053160
 [87,]  1.59766008  1.2364653  1.90362568  1.1607592  0.9485403
 [88,] -1.48934414 -0.3462756 -1.04304091  1.1607592  0.9485403
 [89,] -0.97484344 -0.8738559 -1.04304091  0.6608589 -0.6811327
 [90,] -0.97484344 -0.8738559 -0.06081871 -0.8388419 -0.1379083
 [ reached 'max' / getOption("max.print") -- omitted 233 rows ]
attr(,"scaled:center")
     Q6a      Q6b      Q6d      Q6e      Q6h      Q6i      Q8a      Q8b      Q8c 
6.018576 3.637771 5.034056 3.269350 4.975232 3.956656 3.894737 4.656347 3.123839 
     Q8d      Q8e 
4.678019 5.253870 
attr(,"scaled:scale")
     Q6a      Q6b      Q6d      Q6e      Q6h      Q6i      Q8a      Q8b      Q8c 
1.339659 2.005133 1.764580 1.991883 1.762094 1.955557 1.943632 1.895446 2.036199 
     Q8d      Q8e 
2.000399 1.840860 
library(factoextra)

fviz_nbclust(cluster_scaled, kmeans, method = "wss")

fviz_nbclust(cluster_scaled, kmeans, method = "silhouette")

install.packages("NbClust")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/NbClust_3.0.1.zip'
Content type 'application/zip' length 122135 bytes (119 KB)
downloaded 119 KB
package ‘NbClust’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\frach\AppData\Local\Temp\Rtmp0giUNF\downloaded_packages
library(NbClust)

nb <- NbClust(
  data = cluster_scaled,
  distance = "euclidean",
  min.nc = 2,
  max.nc = 6,
  method = "kmeans"
)
*** : The Hubert index is a graphical method of determining the number of clusters.
                In the plot of Hubert index, we seek a significant knee that corresponds to a 
                significant increase of the value of the measure i.e the significant peak in Hubert
                index second differences plot. 
 

*** : The D index is a graphical method of determining the number of clusters. 
                In the plot of D index, we seek a significant knee (the significant peak in Dindex
                second differences plot) that corresponds to a significant increase of the value of
                the measure. 
 
******************************************************************* 
* Among all indices:                                                
* 11 proposed 2 as the best number of clusters 
* 9 proposed 3 as the best number of clusters 
* 1 proposed 4 as the best number of clusters 
* 1 proposed 5 as the best number of clusters 
* 2 proposed 6 as the best number of clusters 

                   ***** Conclusion *****                            
 
* According to the majority rule, the best number of clusters is  2 
 
 
******************************************************************* 

set.seed(123)

k2 <- kmeans(cluster_scaled, centers = 2, nstart = 25)

k2
K-means clustering with 2 clusters of sizes 238, 85

Cluster means:
          Q6a        Q6b        Q6d        Q6e        Q6h        Q6i        Q8a
1  0.05513429  0.2037010  0.2259559  0.1579831  0.3264230  0.2542116  0.3459966
2 -0.15437602 -0.5703629 -0.6326766 -0.4423526 -0.9139844 -0.7117924 -0.9687905
         Q8b        Q8c        Q8d        Q8e
1  0.4340112  0.2218797  0.4193104  0.3368423
2 -1.2152314 -0.6212631 -1.1740692 -0.9431585

Clustering vector:
  [1] 1 1 1 1 2 1 2 1 2 1 1 1 2 2 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 1
 [41] 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1
 [81] 1 1 1 1 1 1 1 1 2 2 1 1 1 2 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1
[121] 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1
[161] 1 2 2 2 2 1 2 1 2 2 1 2 2 1 1 2 1 1 2 1 2 1 1 1 1 1 2 1 2 2 2 2 2 1 1 1 1 1 2 2
[201] 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2 2 1 1 2 1 1 1 1 1 1 1 1 2 1 2 1 1 2 2 1 1 2 1 1
[241] 2 2 1 1 1 1 2 1 2 2 1 2 1 2 1 1 1 2 1 1 1 2 1 2 1 1 1 1 1 1 1 1 2 1 1 2 1 2 2 1
[281] 1 1 1 1 2 1 2 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 2 1 2 1 2 1 2 1 2 1 1 1 2 1 2 1
[321] 2 1 1

Within cluster sum of squares by cluster:
[1] 1846.8502  846.5349
 (between_SS / total_SS =  24.0 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      
cluster_profile <- cluster_data_complete |>
  mutate(cluster = factor(k2$cluster))

cluster_profile
cluster_means <- cluster_profile |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_means
cluster_means_long <- cluster_means |>
  pivot_longer(
    cols = -cluster,
    names_to = "variable",
    values_to = "mean_score"
  )

ggplot(cluster_means_long, aes(x = variable, y = mean_score, group = cluster, color = cluster)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Cluster Profiles",
    x = "Variables",
    y = "Mean score"
  ) +
  theme_minimal()

factoextra::fviz_cluster(
  k2,
  data = cluster_scaled,
  ellipse.type = "norm",
  repel = TRUE,
  show.clust.cent = TRUE
)

factoextra::fviz_cluster(
  k2,
  data = cluster_scaled,
  geom = "point",
  ellipse.type = "norm",
  show.clust.cent = TRUE
)

cor(cluster_data_complete)
            Q6a        Q6b       Q6d         Q6e       Q6h        Q6i        Q8a
Q6a  1.00000000 0.01176175 0.1389877 -0.07520157 0.1764847 0.07617645 0.03653469
Q6b  0.01176175 1.00000000 0.3414224  0.42261790 0.3745293 0.15121749 0.17824705
Q6d  0.13898774 0.34142235 1.0000000  0.31193154 0.4736980 0.13182600 0.21203009
Q6e -0.07520157 0.42261790 0.3119315  1.00000000 0.3850304 0.21827155 0.18302136
Q6h  0.17648474 0.37452926 0.4736980  0.38503042 1.0000000 0.39082943 0.38280357
Q6i  0.07617645 0.15121749 0.1318260  0.21827155 0.3908294 1.00000000 0.41059955
Q8a  0.03653469 0.17824705 0.2120301  0.18302136 0.3828036 0.41059955 1.00000000
Q8b  0.13460949 0.27520233 0.2848516  0.25079750 0.5134995 0.38807919 0.63081727
Q8c  0.04241674 0.17760187 0.1803331  0.16862760 0.1878175 0.34685944 0.48433201
Q8d  0.05438779 0.26814657 0.2617786  0.20343458 0.4461829 0.40209612 0.50086129
Q8e  0.19956982 0.29759027 0.3816634  0.14136779 0.4021385 0.20320936 0.40589447
          Q8b        Q8c        Q8d       Q8e
Q6a 0.1346095 0.04241674 0.05438779 0.1995698
Q6b 0.2752023 0.17760187 0.26814657 0.2975903
Q6d 0.2848516 0.18033308 0.26177856 0.3816634
Q6e 0.2507975 0.16862760 0.20343458 0.1413678
Q6h 0.5134995 0.18781747 0.44618285 0.4021385
Q6i 0.3880792 0.34685944 0.40209612 0.2032094
Q8a 0.6308173 0.48433201 0.50086129 0.4058945
Q8b 1.0000000 0.33453431 0.75702507 0.5697885
Q8c 0.3345343 1.00000000 0.37960444 0.3014531
Q8d 0.7570251 0.37960444 1.00000000 0.5274318
Q8e 0.5697885 0.30145309 0.52743180 1.0000000
install.packages("hopkins")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/hopkins_1.1.zip'
Content type 'application/zip' length 86999 bytes (84 KB)
downloaded 84 KB
package ‘hopkins’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\frach\AppData\Local\Temp\Rtmp0giUNF\downloaded_packages
library(hopkins)
hopkins(cluster_data_complete)
[1] 0.8835682
hc <- hclust(dist(cluster_scaled), method = "ward.D2")
plot(hc, labels = FALSE, hang = -1, main = "Dendrogram")

summary(aov(Q6a ~ cluster, data = cluster_profile))
             Df Sum Sq Mean Sq F value Pr(>F)  
cluster       1    4.9   4.934   2.764 0.0974 .
Residuals   321  573.0   1.785                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
summary(aov(Q8a ~ cluster, data = cluster_profile))
             Df Sum Sq Mean Sq F value Pr(>F)    
cluster       1  409.0   409.0   162.6 <2e-16 ***
Residuals   321  807.4     2.5                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
anova_results <- lapply(names(cluster_data_complete), function(var) {
  model <- aov(as.formula(paste(var, "~ cluster")), data = cluster_profile)
  data.frame(
    variable = var,
    p_value = summary(model)[[1]][["Pr(>F)"]][1]
  )
})

anova_results <- do.call(rbind, anova_results)

anova_results

3 groups now !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

set.seed(123)

k3 <- kmeans(cluster_scaled, centers = 3, nstart = 25)

k3
K-means clustering with 3 clusters of sizes 162, 67, 94

Cluster means:
          Q6a        Q6b        Q6d        Q6e         Q6h         Q6i         Q8a
1 -0.24886243 -0.0964158 -0.1277436 -0.1662137  0.00354651 -0.04728005  0.03827832
2  0.06412213 -0.7200228 -0.6705898 -0.5698234 -1.10401694 -0.79449048 -1.09770928
3  0.38318649  0.6793711  0.6981273  0.6926041  0.78079362  0.64776840  0.71644079
         Q8b        Q8c        Q8d         Q8e
1  0.1454813 -0.1426706  0.1424438  0.06328585
2 -1.4014362 -0.6838701 -1.3536646 -1.01355352
3  0.7481729  0.7333184  0.7193578  0.61335934

Clustering vector:
  [1] 1 3 3 1 1 1 2 1 1 3 1 1 2 2 2 3 1 1 1 3 1 1 3 3 1 1 3 1 3 1 1 3 1 3 2 3 3 1 2 1
 [41] 3 1 1 1 3 1 1 1 2 1 3 1 1 1 1 1 1 1 1 3 1 1 3 3 3 3 3 3 1 1 3 1 1 2 1 1 1 1 1 3
 [81] 1 3 1 3 3 1 3 1 1 2 3 3 1 2 3 3 1 2 3 2 1 3 1 1 3 1 3 1 1 1 1 1 2 1 1 3 3 3 3 1
[121] 1 3 1 1 1 1 1 1 1 1 1 2 3 3 1 1 3 3 1 2 3 1 3 3 1 1 3 3 1 3 3 3 3 3 3 1 3 3 2 3
[161] 1 2 2 2 2 1 2 1 2 2 1 2 2 1 1 1 1 1 2 1 1 1 3 1 1 1 2 1 2 2 2 2 2 3 1 3 1 1 2 2
[201] 1 1 1 1 3 3 1 3 3 3 1 2 2 1 2 2 2 1 3 2 3 1 3 1 1 1 3 3 1 1 2 3 3 1 2 1 1 2 3 1
[241] 2 1 1 1 1 1 2 1 2 2 1 2 1 2 1 3 3 2 1 3 1 2 1 2 1 1 1 1 3 1 3 3 2 3 3 1 3 2 2 1
[281] 3 1 3 1 2 1 2 1 1 2 1 3 3 2 1 2 1 1 1 1 1 1 3 2 2 3 1 3 2 1 2 1 2 1 1 3 2 1 1 1
[321] 2 1 3

Within cluster sum of squares by cluster:
[1] 1167.8778  632.8631  584.9675
 (between_SS / total_SS =  32.6 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      
set.seed(123)

k4 <- kmeans(cluster_scaled, centers = 4, nstart = 25)

k4
K-means clustering with 4 clusters of sizes 97, 69, 84, 73

Cluster means:
          Q6a        Q6b         Q6d        Q6e         Q6h         Q6i        Q8a
1 -0.59102504  0.3965916  0.08586251  0.4444485  0.18372283 -0.18870711 -0.2269610
2  0.09431634 -0.7517389 -0.69277752 -0.5863299 -1.06338430 -0.79305251 -1.0643218
3  0.27938560 -0.5793036 -0.14748335 -0.7030042 -0.06026046  0.09521625  0.4094085
4  0.37470153  0.8501657  0.71043270  0.7725701  0.83033260  0.89078148  0.8364810
          Q8b        Q8c         Q8d         Q8e
1 -0.05801009 -0.2684018 -0.01941779 -0.04270408
2 -1.36320575 -0.6871633 -1.28802770 -1.03540940
3  0.50790201  0.1964300  0.45256710  0.36651424
4  0.78115625  0.7801250  0.72249042  0.61367600

Clustering vector:
  [1] 3 4 4 1 1 3 2 1 1 4 3 3 2 2 2 4 1 1 1 4 3 3 4 4 3 1 4 1 4 1 1 4 3 1 2 4 4 1 2 1
 [41] 1 1 1 1 4 1 3 1 2 1 1 3 1 1 3 3 3 2 1 4 1 1 4 4 1 4 4 4 1 3 4 1 1 2 1 1 1 3 1 4
 [81] 1 4 3 4 4 3 4 1 2 2 4 4 3 2 3 4 1 2 4 2 1 4 3 1 4 3 4 1 1 3 1 1 2 1 3 1 4 1 4 1
[121] 1 3 1 3 1 3 3 1 1 1 3 2 4 1 1 1 3 4 3 2 4 3 3 4 1 3 4 4 1 4 4 1 4 4 4 3 3 4 2 3
[161] 3 2 2 2 2 3 2 1 2 2 3 2 2 3 3 1 3 3 2 3 1 1 3 3 3 3 2 3 2 2 2 2 2 4 3 4 3 3 1 2
[201] 1 3 3 1 4 4 1 4 4 4 1 2 2 1 2 2 2 3 1 2 4 1 4 1 3 1 3 4 1 1 2 4 4 1 2 1 3 2 4 1
[241] 2 1 3 1 3 1 2 1 2 2 3 2 3 2 3 3 4 2 3 4 3 2 3 2 1 3 3 3 3 1 4 4 2 4 3 3 1 2 2 3
[281] 4 3 4 1 2 3 2 3 3 2 1 4 4 2 1 2 3 1 1 1 1 1 4 2 2 4 2 4 2 1 2 3 2 1 3 4 2 3 1 3
[321] 2 3 4

Within cluster sum of squares by cluster:
[1] 687.5222 639.5021 506.3095 371.1580
 (between_SS / total_SS =  37.8 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      
cluster_profile_4 <- cluster_data_complete |>
  mutate(cluster = factor(k4$cluster))
cluster_means_4 <- cluster_profile_4 |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_means_4
factoextra::fviz_cluster(
  k4,
  data = cluster_scaled,
  geom = "point",
  ellipse.type = "none",
  show.clust.cent = TRUE
)

cluster_sizes_4 <- data.frame(table(k4$cluster))
cluster_sizes_4$percent <- round(100 * cluster_sizes_4$Freq / sum(cluster_sizes_4$Freq), 1)

cluster_sizes_4
cluster_means_4_long <- cluster_means_4 |>
  pivot_longer(
    cols = -cluster,
    names_to = "variable",
    values_to = "mean_score"
  )

ggplot(
  cluster_means_4_long,
  aes(x = variable, y = mean_score, group = cluster, color = cluster)
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Cluster Profiles (4-Cluster Solution)",
    x = "Variables",
    y = "Mean score",
    color = "Cluster"
  ) +
  theme_minimal()

pca_cluster <- prcomp(cluster_data_complete, scale. = TRUE)

summary(pca_cluster)
Importance of components:
                         PC1   PC2    PC3     PC4     PC5     PC6     PC7     PC8
Standard deviation     2.044 1.168 1.0708 0.92877 0.87763 0.80827 0.74116 0.69154
Proportion of Variance 0.380 0.124 0.1042 0.07842 0.07002 0.05939 0.04994 0.04348
Cumulative Proportion  0.380 0.504 0.6082 0.68667 0.75669 0.81608 0.86602 0.90950
                          PC9    PC10    PC11
Standard deviation     0.6465 0.61845 0.44167
Proportion of Variance 0.0380 0.03477 0.01773
Cumulative Proportion  0.9475 0.98227 1.00000
round(pca_cluster$rotation[, 1:3], 3)
      PC1    PC2    PC3
Q6a 0.086 -0.053  0.761
Q6b 0.246  0.480 -0.112
Q6d 0.262  0.409  0.239
Q6e 0.223  0.493 -0.343
Q6h 0.353  0.239  0.121
Q6i 0.276 -0.200 -0.218
Q8a 0.347 -0.314 -0.156
Q8b 0.404 -0.196  0.045
Q8c 0.265 -0.272 -0.235
Q8d 0.381 -0.213 -0.025
Q8e 0.337 -0.055  0.301
pca_scores_2 <- as.data.frame(pca_cluster$x[, 1:2])

head(pca_scores_2)
fviz_nbclust(pca_scores_2, kmeans, method = "wss")

fviz_nbclust(pca_scores_2, kmeans, method = "silhouette")

nb_pca2 <- NbClust(
  data = pca_scores_2,
  distance = "euclidean",
  min.nc = 2,
  max.nc = 6,
  method = "kmeans"
)
*** : The Hubert index is a graphical method of determining the number of clusters.
                In the plot of Hubert index, we seek a significant knee that corresponds to a 
                significant increase of the value of the measure i.e the significant peak in Hubert
                index second differences plot. 
 

*** : The D index is a graphical method of determining the number of clusters. 
                In the plot of D index, we seek a significant knee (the significant peak in Dindex
                second differences plot) that corresponds to a significant increase of the value of
                the measure. 
 
******************************************************************* 
* Among all indices:                                                
* 10 proposed 2 as the best number of clusters 
* 7 proposed 3 as the best number of clusters 
* 3 proposed 4 as the best number of clusters 
* 2 proposed 5 as the best number of clusters 
* 2 proposed 6 as the best number of clusters 

                   ***** Conclusion *****                            
 
* According to the majority rule, the best number of clusters is  2 
 
 
******************************************************************* 

set.seed(123)

k4_pca2 <- kmeans(pca_scores_2, centers = 4, nstart = 25)

k4_pca2
K-means clustering with 4 clusters of sizes 102, 69, 70, 82

Cluster means:
         PC1        PC2
1  0.1690658  0.7994389
2 -3.0310459  0.1049628
3  2.5341729  0.1558428
4  0.1768945 -1.2157828

Clustering vector:
  [1] 4 3 3 1 1 1 2 1 1 3 1 1 2 2 2 3 1 1 1 3 4 1 3 3 4 4 3 1 3 1 1 3 4 1 2 3 3 1 2 1
 [41] 1 1 1 1 3 1 4 1 2 1 1 4 1 4 4 4 1 2 1 3 1 1 3 3 1 3 3 3 1 4 3 1 3 2 1 1 4 4 1 3
 [81] 1 3 4 3 3 4 3 1 2 2 3 3 4 2 4 3 1 2 3 4 1 3 4 1 3 4 3 1 1 4 1 1 2 1 4 1 4 1 3 4
[121] 1 4 4 1 1 4 4 1 1 1 4 2 1 1 4 1 3 3 4 2 3 4 3 3 1 4 3 3 4 3 3 1 1 3 3 1 3 1 2 4
[161] 4 2 2 2 2 4 2 1 2 2 4 2 2 4 4 1 4 4 2 4 4 1 4 4 4 4 2 4 2 2 2 2 2 3 4 1 4 4 1 2
[201] 1 4 4 1 3 3 1 3 3 3 1 2 2 1 2 2 2 4 1 2 3 1 3 1 1 1 4 3 2 1 2 3 3 1 2 1 4 2 1 1
[241] 2 1 1 4 4 1 2 1 2 2 1 2 4 2 4 3 3 2 4 3 4 2 4 2 1 4 4 4 3 1 1 3 2 1 4 4 1 2 2 4
[281] 3 4 3 1 2 4 2 4 4 2 1 1 3 2 4 2 4 1 2 1 1 4 3 2 2 3 4 3 2 1 2 1 2 1 4 3 2 4 1 4
[321] 2 4 3

Within cluster sum of squares by cluster:
[1] 131.7003 167.9382 101.4012 106.3939
 (between_SS / total_SS =  71.6 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      
factoextra::fviz_cluster(
  k4_pca2,
  data = pca_scores_2,
  geom = "point",
  ellipse.type = "none",
  show.clust.cent = TRUE
)

cluster_profile_pca4 <- cluster_data_complete |>
  mutate(cluster = factor(k4_pca2$cluster))
cluster_means_pca4 <- cluster_profile_pca4 |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_means_pca4
pca_plot_data <- pca_scores_2 |>
  mutate(
    cluster = factor(
      k4_pca2$cluster,
      levels = c(1, 2, 3, 4),
      labels = c(
        "Cautious guidance seekers",
        "AI skeptics",
        "AI-enthusiastic guidance seekers",
        "Feature-oriented adopters"
      )
    )
  )

ggplot(pca_plot_data, aes(x = PC1, y = PC2, color = cluster, shape = cluster)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(
    title = "PCA-based 4-cluster solution",
    x = "PC1",
    y = "PC2",
    color = "Cluster",
    shape = "Cluster"
  ) +
  theme_minimal()

cluster_means_pca4_named <- cluster_means_pca4 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4),
      labels = c(
        "Cautious guidance seekers",
        "AI skeptics",
        "AI-enthusiastic guidance seekers",
        "Feature-oriented adopters"
      )
    )
  )

cluster_means_pca4_long <- cluster_means_pca4_named |>
  pivot_longer(
    cols = -cluster,
    names_to = "variable",
    values_to = "mean_score"
  )

ggplot(
  cluster_means_pca4_long,
  aes(x = variable, y = mean_score, group = cluster, color = cluster)
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Cluster Profiles (PCA-based 4-Cluster Solution)",
    x = "Variables",
    y = "Mean score",
    color = "Cluster"
  ) +
  theme_minimal()

cor_matrix <- cor(cluster_data_complete)

round(cor_matrix, 3)
       Q6a   Q6b   Q6d    Q6e   Q6h   Q6i   Q8a   Q8b   Q8c   Q8d   Q8e
Q6a  1.000 0.012 0.139 -0.075 0.176 0.076 0.037 0.135 0.042 0.054 0.200
Q6b  0.012 1.000 0.341  0.423 0.375 0.151 0.178 0.275 0.178 0.268 0.298
Q6d  0.139 0.341 1.000  0.312 0.474 0.132 0.212 0.285 0.180 0.262 0.382
Q6e -0.075 0.423 0.312  1.000 0.385 0.218 0.183 0.251 0.169 0.203 0.141
Q6h  0.176 0.375 0.474  0.385 1.000 0.391 0.383 0.513 0.188 0.446 0.402
Q6i  0.076 0.151 0.132  0.218 0.391 1.000 0.411 0.388 0.347 0.402 0.203
Q8a  0.037 0.178 0.212  0.183 0.383 0.411 1.000 0.631 0.484 0.501 0.406
Q8b  0.135 0.275 0.285  0.251 0.513 0.388 0.631 1.000 0.335 0.757 0.570
Q8c  0.042 0.178 0.180  0.169 0.188 0.347 0.484 0.335 1.000 0.380 0.301
Q8d  0.054 0.268 0.262  0.203 0.446 0.402 0.501 0.757 0.380 1.000 0.527
Q8e  0.200 0.298 0.382  0.141 0.402 0.203 0.406 0.570 0.301 0.527 1.000
library(corrplot)

corrplot(
  cor(cluster_data_complete),
  method = "color",
  type = "upper",
  tl.col = "black",
  tl.srt = 45
)

pca_variance <- data.frame(
  Component = paste0("PC", 1:length(pca_cluster$sdev)),
  Eigenvalue = pca_cluster$sdev^2,
  Proportion_Variance = (pca_cluster$sdev^2) / sum(pca_cluster$sdev^2),
  Cumulative_Variance = cumsum((pca_cluster$sdev^2) / sum(pca_cluster$sdev^2))
)

pca_variance$Eigenvalue <- round(pca_variance$Eigenvalue, 3)
pca_variance$Proportion_Variance <- round(pca_variance$Proportion_Variance, 3)
pca_variance$Cumulative_Variance <- round(pca_variance$Cumulative_Variance, 3)

pca_variance
pca_loadings <- as.data.frame(pca_cluster$rotation[, 1:3])

pca_loadings$Variable <- rownames(pca_loadings)
rownames(pca_loadings) <- NULL

pca_loadings <- pca_loadings[, c("Variable", "PC1", "PC2", "PC3")]

pca_loadings$PC1 <- round(pca_loadings$PC1, 3)
pca_loadings$PC2 <- round(pca_loadings$PC2, 3)
pca_loadings$PC3 <- round(pca_loadings$PC3, 3)

pca_loadings
hopkins(cluster_data_complete)
[1] 0.9490564
distance_matrix <- dist(cluster_data_complete, method = "euclidean")

distance_matrix
            1         2         3         4         5         6         7         8
2    9.797959                                                                      
3    8.717798  6.480741                                                            
4    7.745967  9.899495 10.099505                                                  
            9        10        11        12        13        14        15        16
2                                                                                  
3                                                                                  
4                                                                                  
           17        18        19        20        21        22        23        24
2                                                                                  
3                                                                                  
4                                                                                  
           25        26        27        28        29        30        31        32
2                                                                                  
3                                                                                  
4                                                                                  
           33        34        35        36        37        38        39        40
2                                                                                  
3                                                                                  
4                                                                                  
           41        42        43        44        45        46        47        48
2                                                                                  
3                                                                                  
4                                                                                  
           49        50        51        52        53        54        55        56
2                                                                                  
3                                                                                  
4                                                                                  
           57        58        59        60        61        62        63        64
2                                                                                  
3                                                                                  
4                                                                                  
           65        66        67        68        69        70        71        72
2                                                                                  
3                                                                                  
4                                                                                  
           73        74        75        76        77        78        79        80
2                                                                                  
3                                                                                  
4                                                                                  
           81        82        83        84        85        86        87        88
2                                                                                  
3                                                                                  
4                                                                                  
           89        90        91        92        93        94        95        96
2                                                                                  
3                                                                                  
4                                                                                  
           97        98        99       100       101       102       103       104
2                                                                                  
3                                                                                  
4                                                                                  
          105       106       107       108       109       110       111       112
2                                                                                  
3                                                                                  
4                                                                                  
          113       114       115       116       117       118       119       120
2                                                                                  
3                                                                                  
4                                                                                  
          121       122       123       124       125       126       127       128
2                                                                                  
3                                                                                  
4                                                                                  
          129       130       131       132       133       134       135       136
2                                                                                  
3                                                                                  
4                                                                                  
          137       138       139       140       141       142       143       144
2                                                                                  
3                                                                                  
4                                                                                  
          145       146       147       148       149       150       151       152
2                                                                                  
3                                                                                  
4                                                                                  
          153       154       155       156       157       158       159       160
2                                                                                  
3                                                                                  
4                                                                                  
          161       162       163       164       165       166       167       168
2                                                                                  
3                                                                                  
4                                                                                  
          169       170       171       172       173       174       175       176
2                                                                                  
3                                                                                  
4                                                                                  
          177       178       179       180       181       182       183       184
2                                                                                  
3                                                                                  
4                                                                                  
          185       186       187       188       189       190       191       192
2                                                                                  
3                                                                                  
4                                                                                  
          193       194       195       196       197       198       199       200
2                                                                                  
3                                                                                  
4                                                                                  
          201       202       203       204       205       206       207       208
2                                                                                  
3                                                                                  
4                                                                                  
          209       210       211       212       213       214       215       216
2                                                                                  
3                                                                                  
4                                                                                  
          217       218       219       220       221       222       223       224
2                                                                                  
3                                                                                  
4                                                                                  
          225       226       227       228       229       230       231       232
2                                                                                  
3                                                                                  
4                                                                                  
          233       234       235       236       237       238       239       240
2                                                                                  
3                                                                                  
4                                                                                  
          241       242       243       244       245       246       247       248
2                                                                                  
3                                                                                  
4                                                                                  
          249       250       251       252       253       254       255       256
2                                                                                  
3                                                                                  
4                                                                                  
          257       258       259       260       261       262       263       264
2                                                                                  
3                                                                                  
4                                                                                  
          265       266       267       268       269       270       271       272
2                                                                                  
3                                                                                  
4                                                                                  
          273       274       275       276       277       278       279       280
2                                                                                  
3                                                                                  
4                                                                                  
          281       282       283       284       285       286       287       288
2                                                                                  
3                                                                                  
4                                                                                  
          289       290       291       292       293       294       295       296
2                                                                                  
3                                                                                  
4                                                                                  
          297       298       299       300       301       302       303       304
2                                                                                  
3                                                                                  
4                                                                                  
          305       306       307       308       309       310       311       312
2                                                                                  
3                                                                                  
4                                                                                  
          313       314       315       316       317       318       319       320
2                                                                                  
3                                                                                  
4                                                                                  
          321       322
2                      
3                      
4                      
 [ reached 'max' / getOption("max.print") -- omitted 319 rows ]
distance_matrix_table <- as.matrix(distance_matrix)

distance_matrix_table[1:10, 1:10]
          1         2         3         4         5         6         7        8
1  0.000000  9.797959  8.717798  7.745967  7.745967  7.810250  8.306624 5.567764
2  9.797959  0.000000  6.480741  9.899495  9.899495  8.062258 11.269428 8.888194
3  8.717798  6.480741  0.000000 10.099505 10.295630 10.148892 11.618950 8.544004
4  7.745967  9.899495 10.099505  0.000000  7.211103  6.708204  6.557439 7.000000
5  7.745967  9.899495 10.295630  7.211103  0.000000  5.916080  5.000000 4.582576
6  7.810250  8.062258 10.148892  6.708204  5.916080  0.000000  8.246211 7.348469
7  8.306624 11.269428 11.618950  6.557439  5.000000  8.246211  0.000000 5.291503
8  5.567764  8.888194  8.544004  7.000000  4.582576  7.348469  5.291503 0.000000
9  6.082763 10.148892  9.848858  7.416198  3.316625  7.483315  5.099020 2.449490
10 6.082763  6.082763  4.358899  7.549834  7.416198  7.745967  8.366600 5.830952
           9       10
1   6.082763 6.082763
2  10.148892 6.082763
3   9.848858 4.358899
4   7.416198 7.549834
5   3.316625 7.416198
6   7.483315 7.745967
7   5.099020 8.366600
8   2.449490 5.830952
9   0.000000 6.928203
10  6.928203 0.000000
hc <- hclust(dist(cluster_data_complete), method = "ward.D2")

plot(hc, labels = FALSE, hang = -1, main = "Dendrogram")

cluster_sizes_pca4 <- data.frame(table(k4_pca2$cluster))
cluster_sizes_pca4$Percent <- round(
  100 * cluster_sizes_pca4$Freq / sum(cluster_sizes_pca4$Freq),
  1
)

names(cluster_sizes_pca4) <- c("Cluster", "Size", "Percent")

cluster_sizes_pca4
cluster_sizes_pca4 <- data.frame(table(k4_pca2$cluster))
cluster_sizes_pca4$Percent <- round(
  100 * cluster_sizes_pca4$Freq / sum(cluster_sizes_pca4$Freq),
  1
)

cluster_sizes_pca4$Cluster_Name <- c(
  "Cautious guidance seekers",
  "AI skeptics",
  "AI-enthusiastic guidance seekers",
  "Feature-oriented adopters"
)

cluster_sizes_pca4 <- cluster_sizes_pca4[, c("Var1", "Cluster_Name", "Freq", "Percent")]
names(cluster_sizes_pca4) <- c("Cluster", "Cluster_Name", "Size", "Percent")

cluster_sizes_pca4
cluster_mean_table <- cluster_means_pca4 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1,2,3,4),
      labels = c(
        "Cautious guidance seekers",
        "AI skeptics",
        "AI-enthusiastic guidance seekers",
        "Feature-oriented adopters"
      )
    )
  )

cluster_mean_table
ggplot(pca_plot_data, aes(x = PC1, y = PC2, color = cluster, shape = cluster)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(
    title = "Customer Segmentation Based on PCA Clustering",
    x = "Interest in AI banking features (PC1)",
    y = "Need for financial guidance (PC2)",
    color = "Cluster",
    shape = "Cluster"
  ) +
  theme_minimal()

set.seed(123)

k5_pca2 <- kmeans(pca_scores_2, centers = 5, nstart = 25)

k5_pca2
K-means clustering with 5 clusters of sizes 56, 99, 73, 33, 62

Cluster means:
         PC1        PC2
1 -1.7951634  0.6037454
2  0.4238399  0.6740437
3  0.3347926 -1.3280570
4 -3.9696761 -0.4418461
5  2.6633622  0.1772421

Clustering vector:
  [1] 3 5 5 2 1 2 1 1 1 5 2 2 1 4 1 5 1 2 2 5 1 2 5 5 3 3 2 2 5 2 2 2 3 2 1 5 5 2 1 2
 [41] 2 2 2 2 5 2 3 2 4 2 2 3 1 3 3 3 2 1 1 5 2 2 5 5 2 5 5 5 2 3 5 2 5 4 2 1 3 3 2 5
 [81] 2 5 3 5 5 3 5 2 1 1 5 2 3 4 3 5 2 1 5 1 2 5 3 2 5 3 5 2 2 3 2 2 4 2 3 2 3 2 5 3
[121] 2 3 3 2 2 3 3 2 2 2 3 4 2 2 3 1 3 5 3 1 5 3 2 5 2 3 5 5 3 5 5 2 2 5 5 2 5 2 1 3
[161] 3 4 1 4 4 3 4 2 4 4 3 1 4 3 3 1 3 3 4 3 1 2 3 2 3 3 1 3 4 1 4 1 1 5 3 2 3 3 1 1
[201] 2 3 3 2 5 2 2 5 5 5 2 1 1 2 4 4 4 3 2 4 5 2 2 2 2 2 3 5 1 2 4 5 5 1 4 2 3 1 2 2
[241] 1 1 2 3 3 2 1 2 4 4 2 1 3 1 3 2 5 1 3 5 3 1 2 4 2 3 3 3 5 2 2 5 1 2 3 3 2 1 4 2
[281] 5 3 5 2 4 3 1 3 3 1 2 2 5 4 1 1 3 2 1 1 2 1 5 1 4 5 1 5 1 2 4 2 4 2 2 5 4 3 1 3
[321] 4 3 5

Within cluster sum of squares by cluster:
[1]  84.46534 102.03941  90.80653  56.55989  82.57159
 (between_SS / total_SS =  76.7 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      
cluster_profile_pca5 <- cluster_data_complete |>
  mutate(cluster = factor(k5_pca2$cluster))
cluster_means_pca5 <- cluster_profile_pca5 |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_means_pca5
cluster_means_pca5_named <- cluster_means_pca5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )

cluster_means_pca5_long <- cluster_means_pca5_named |>
  pivot_longer(
    cols = -cluster,
    names_to = "variable",
    values_to = "mean_score"
  )

ggplot(
  cluster_means_pca5_long,
  aes(x = variable, y = mean_score, group = cluster, color = cluster)
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Cluster Profiles (PCA-based 5-Cluster Solution)",
    x = "Variables",
    y = "Mean score",
    color = "Cluster"
  ) +
  theme_minimal()

cluster_sizes_pca5 <- data.frame(table(k5_pca2$cluster))
cluster_sizes_pca5$Percent <- round(
  100 * cluster_sizes_pca5$Freq / sum(cluster_sizes_pca5$Freq),
  1
)

cluster_sizes_pca5$Cluster_Name <- c(
  "Skeptical support seekers",
  "Cautious guidance seekers",
  "Feature-oriented adopters",
  "AI-resistant independents",
  "AI-enthusiastic guidance seekers"
)

cluster_sizes_pca5 <- cluster_sizes_pca5[, c("Var1", "Cluster_Name", "Freq", "Percent")]
names(cluster_sizes_pca5) <- c("Cluster", "Cluster_Name", "Size", "Percent")

cluster_sizes_pca5
cluster_profile_pca5 <- cluster_data_complete |>
  mutate(cluster = factor(k5_pca2$cluster))

cluster_means_pca5 <- cluster_profile_pca5 |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_mean_table_pca5 <- cluster_means_pca5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )

cluster_mean_table_pca5
pca_plot_data_5 <- pca_scores_2 |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )

ggplot(pca_plot_data_5, aes(x = PC1, y = PC2, color = cluster, shape = cluster)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(
    title = "PCA-based 5-Cluster Solution",
    x = "PC1",
    y = "PC2",
    color = "Cluster",
    shape = "Cluster"
  ) +
  theme_minimal()

pca_plot_data_5 <- pca_scores_2 |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )

ggplot(pca_plot_data_5, aes(x = PC1, y = PC2, color = cluster, shape = cluster)) +
  geom_point(size = 2.8, alpha = 0.8) +
  labs(
    title = "Customer Segmentation (PCA-based 5-Cluster Solution)",
    x = "Interest in AI Banking Features (PC1)",
    y = "Need for Financial Guidance (PC2)",
    color = "Cluster",
    shape = "Cluster"
  ) +
  theme_minimal()

cluster_profile_pca2_5 <- pca_scores_2 |>
  mutate(cluster = factor(k5_pca2$cluster))

cluster_means_pca2_5 <- cluster_profile_pca2_5 |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_means_pca2_5_named <- cluster_means_pca2_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  rename(
    `Interest in AI Banking Features` = PC1,
    `Need for Financial Guidance` = PC2
  )

cluster_means_pca2_5_long <- cluster_means_pca2_5_named |>
  pivot_longer(
    cols = -cluster,
    names_to = "component",
    values_to = "mean_score"
  )

ggplot(
  cluster_means_pca2_5_long,
  aes(x = component, y = mean_score, group = cluster, color = cluster)
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Cluster Profiles (5-Cluster Solution Based on 2 PCs)",
    x = "Principal Components",
    y = "Mean component score",
    color = "Cluster"
  ) +
  theme_minimal()

cluster_profile_pca2_4 <- pca_scores_2 |>
  mutate(cluster = factor(k4_pca2$cluster))

cluster_means_pca2_4 <- cluster_profile_pca2_4 |>
  group_by(cluster) |>
  summarise(across(everything(), mean))

cluster_means_pca2_4_named <- cluster_means_pca2_4 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4),
      labels = c(
        "Cautious guidance seekers",
        "AI skeptics",
        "AI-enthusiastic guidance seekers",
        "Feature-oriented adopters"
      )
    )
  ) |>
  rename(
    `Interest in AI Banking Features` = PC1,
    `Need for Financial Guidance` = PC2
  )

cluster_means_pca2_4_long <- cluster_means_pca2_4_named |>
  pivot_longer(
    cols = -cluster,
    names_to = "component",
    values_to = "mean_score"
  )

ggplot(
  cluster_means_pca2_4_long,
  aes(x = component, y = mean_score, group = cluster, color = cluster)
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Cluster Profiles (4-Cluster Solution Based on 2 PCs)",
    x = "Principal Components",
    y = "Mean component score",
    color = "Cluster"
  ) +
  theme_minimal()

data_clean_complete <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  )
data_cluster_profile <- data_clean_complete |>
  mutate(cluster = factor(k4_pca2$cluster))
data_cluster_profile_5 <- data_clean_complete |>
  mutate(cluster = factor(k5_pca2$cluster))
data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(mean_age = mean(as.numeric(Q21), na.rm = TRUE))
data_cluster_profile_5 <- data_cluster_profile_5 |>
  mutate(age = 2026 - as.numeric(Q21))
data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(mean_age = mean(age, na.rm = TRUE))
data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(mobile_banking_use = mean(as.numeric(Q2), na.rm = TRUE))
data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(trust = mean(as.numeric(Q24), na.rm = TRUE))
names(data_cluster_profile_5)
 [1] "respondent_id" "Q1"            "Q2"            "Q3a"           "Q3b"          
 [6] "Q3c"           "Q3d"           "Q3e"           "Q3f"           "Q3g"          
[11] "Q3g_text"      "Q4"            "Q4_5_text"     "Q5a"           "Q5b"          
[16] "Q5c"           "Q5d"           "Q5e"           "Q6a"           "Q6b"          
[21] "Q6c"           "Q6d"           "Q6e"           "Q6f"           "Q6g"          
[26] "Q6h"           "Q6i"           "Q8a"           "Q8b"           "Q8c"          
[31] "Q8d"           "Q8e"           "Q10a"          "Q10b"          "Q10c"         
[36] "Q10d"          "Q11a"          "Q11b"          "Q11c"          "Q11d"         
[41] "Q11e"          "Q11f"          "Q12a"          "Q12b"          "Q12c"         
[46] "Q12d"          "Q12e"          "Q12f"          "Q12g"          "Q12h"         
[51] "Q12i"          "Q13a"          "Q13b"          "Q13c"          "Q13d"         
[56] "Q13e"          "Q13f"          "Q13g"          "Q14a"          "Q14b"         
[61] "Q14c"          "Q14d"          "Q14e"          "Q14f"          "Q14g"         
[66] "Q15a"          "Q15b"          "Q15c"          "Q15d"          "Q15e"         
[71] "Q15f"          "Q15g"          "Q17"           "Q18"           "Q19"          
[76] "Q21"           "Q22"           "Q23"           "Q24"           "Q25a"         
[81] "Q25b"          "Q25c"          "Q25d"          "Q25e"          "Q25f"         
[86] "Q25g"          "Q25h"          "Q25i"          "Q25j"          "Q25k"         
[91] "Q25l"          "Q25l_text"     "Q26"           "cluster"       "age"          
data_cluster_profile_5 |>
  group_by(cluster, Q22) |>
  summarise(n = n(), .groups = "drop") |>
  group_by(cluster) |>
  mutate(percent = round(100 * n / sum(n), 1))
data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(Q17_mean = mean(as.numeric(Q17), na.rm = TRUE))
gender_profile_5 <- data_cluster_profile_5 |>
  group_by(cluster, Q22) |>
  summarise(n = n(), .groups = "drop") |>
  group_by(cluster) |>
  mutate(percent = round(100 * n / sum(n), 1)) |>
  ungroup()

male_profile_5 <- gender_profile_5 |>
  filter(Q22 == "1") |>
  select(cluster, male_percent = percent)

female_profile_5 <- gender_profile_5 |>
  filter(Q22 == "2") |>
  select(cluster, female_percent = percent)

profiling_table_5 <- data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(
    mean_birth_year = mean(as.numeric(Q21), na.rm = TRUE),
    mean_age = mean(age, na.rm = TRUE),
    mobile_banking_use = mean(as.numeric(Q2), na.rm = TRUE),
    trust = mean(as.numeric(Q24), na.rm = TRUE),
    Q17_mean = mean(as.numeric(Q17), na.rm = TRUE)
  ) |>
  left_join(male_profile_5, by = "cluster") |>
  left_join(female_profile_5, by = "cluster") |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  mutate(across(-cluster, ~ round(.x, 2)))

profiling_table_5
pc_loadings <- as.data.frame(pca_cluster$rotation[, 1:2])

pc_loadings$Variable <- rownames(pc_loadings)
rownames(pc_loadings) <- NULL

pc_loadings <- pc_loadings[, c("Variable", "PC1", "PC2")]

pc_loadings$PC1 <- round(pc_loadings$PC1, 3)
pc_loadings$PC2 <- round(pc_loadings$PC2, 3)

pc_loadings
cluster_bank_counts <- data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(
    OTP = sum(Q25a == 1, na.rm = TRUE),
    Gorenjska_Banka = sum(Q25b == 1, na.rm = TRUE),
    NLB = sum(Q25c == 1, na.rm = TRUE),
    Revolut = sum(Q25d == 1, na.rm = TRUE),
    N26 = sum(Q25e == 1, na.rm = TRUE),
    Intesa = sum(Q25f == 1, na.rm = TRUE),
    UniCredit = sum(Q25g == 1, na.rm = TRUE),
    Regional_Bank = sum(Q25h == 1, na.rm = TRUE),
    Workers_Savings = sum(Q25i == 1, na.rm = TRUE),
    Sparkasse = sum(Q25j == 1, na.rm = TRUE),
    Addiko = sum(Q25k == 1, na.rm = TRUE)
  )

cluster_bank_counts
library(dplyr)
library(tidyr)
library(ggplot2)

cluster_bank_counts <- data_cluster_profile_5 |>
  group_by(cluster) |>
  summarise(
    OTP = sum(Q25a == 1, na.rm = TRUE),
    Gorenjska_Banka = sum(Q25b == 1, na.rm = TRUE),
    NLB = sum(Q25c == 1, na.rm = TRUE),
    Revolut = sum(Q25d == 1, na.rm = TRUE),
    N26 = sum(Q25e == 1, na.rm = TRUE),
    Intesa_SanPaolo = sum(Q25f == 1, na.rm = TRUE),
    UniCredit = sum(Q25g == 1, na.rm = TRUE),
    Regional_Bank = sum(Q25h == 1, na.rm = TRUE),
    Workers_Savings = sum(Q25i == 1, na.rm = TRUE),
    Sparkasse = sum(Q25j == 1, na.rm = TRUE),
    Addiko = sum(Q25k == 1, na.rm = TRUE),
    Other = sum(Q25l == 1, na.rm = TRUE)
  )

cluster_bank_counts
cluster_bank_long <- cluster_bank_counts |>
  pivot_longer(
    cols = -cluster,
    names_to = "bank",
    values_to = "count"
  )

cluster_bank_long
ggplot(cluster_bank_long, aes(x = bank, y = factor(cluster), fill = count)) +
  geom_tile(color = "white") +
  geom_text(aes(label = count), size = 4) +
  labs(
    title = "Banks Used by Each Cluster",
    x = "Bank",
    y = "Cluster",
    fill = "Count"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

cluster_bank_percent_long <- cluster_bank_long |>
  group_by(cluster) |>
  mutate(percent = round(100 * count / sum(count), 1)) |>
  ungroup()

cluster_bank_percent_long
ggplot(cluster_bank_percent_long, aes(x = bank, y = factor(cluster), fill = percent)) +
  geom_tile(color = "white") +
  geom_text(aes(label = paste0(percent, "%")), size = 4) +
  labs(
    title = "Bank Usage by Cluster (%)",
    x = "Bank",
    y = "Cluster",
    fill = "Percent"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

library(dplyr)
library(tidyr)
library(ggplot2)

cluster_bank_counts_named <- data_cluster_profile_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  filter(cluster %in% c(
    "Cautious guidance seekers",
    "Feature-oriented adopters",
    "AI-enthusiastic guidance seekers"
  )) |>
  group_by(cluster) |>
  summarise(
    OTP = sum(Q25a == 1, na.rm = TRUE),
    Gorenjska_Banka = sum(Q25b == 1, na.rm = TRUE),
    NLB = sum(Q25c == 1, na.rm = TRUE),
    Revolut = sum(Q25d == 1, na.rm = TRUE),
    N26 = sum(Q25e == 1, na.rm = TRUE),
    Intesa_SanPaolo = sum(Q25f == 1, na.rm = TRUE),
    UniCredit = sum(Q25g == 1, na.rm = TRUE),
    Regional_Bank = sum(Q25h == 1, na.rm = TRUE),
    Workers_Savings = sum(Q25i == 1, na.rm = TRUE),
    Sparkasse = sum(Q25j == 1, na.rm = TRUE),
    Addiko = sum(Q25k == 1, na.rm = TRUE),
    Other = sum(Q25l == 1, na.rm = TRUE)
  )

cluster_bank_percent_long_named <- cluster_bank_counts_named |>
  pivot_longer(
    cols = -cluster,
    names_to = "bank",
    values_to = "count"
  ) |>
  group_by(cluster) |>
  mutate(percent = round(100 * count / sum(count), 1)) |>
  ungroup()

ggplot(
  cluster_bank_percent_long_named,
  aes(x = bank, y = cluster, fill = percent)
) +
  geom_tile(color = "white") +
  geom_text(aes(label = paste0(percent, "%")), color = "white", size = 4) +
  labs(
    title = "Bank Usage by Selected Clusters (%)",
    x = "Bank",
    y = "Cluster",
    fill = "Percent"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

library(dplyr)
library(tibble)
library(FactoMineR)
library(factoextra)
library(ggplot2)

data_cluster_profile_5 <- data_clean_complete |>
  mutate(cluster = factor(k5_pca2$cluster))

make_perception_map <- function(data, cluster_values, title_text) {
  
  subset_data <- data |>
    filter(cluster %in% cluster_values) |>
    mutate(
      across(Q13a:Q15g, as.numeric)
    )
  
  bank_means <- tibble(
    bank = c("OTP", "Gorenjska Banka", "NLB", "Revolut", "N26", "Intesa SanPaolo", "UniCredit"),
    innovation = c(
      mean(subset_data$Q13a, na.rm = TRUE),
      mean(subset_data$Q13b, na.rm = TRUE),
      mean(subset_data$Q13c, na.rm = TRUE),
      mean(subset_data$Q13d, na.rm = TRUE),
      mean(subset_data$Q13e, na.rm = TRUE),
      mean(subset_data$Q13f, na.rm = TRUE),
      mean(subset_data$Q13g, na.rm = TRUE)
    ),
    customer_support = c(
      mean(subset_data$Q14a, na.rm = TRUE),
      mean(subset_data$Q14b, na.rm = TRUE),
      mean(subset_data$Q14c, na.rm = TRUE),
      mean(subset_data$Q14d, na.rm = TRUE),
      mean(subset_data$Q14e, na.rm = TRUE),
      mean(subset_data$Q14f, na.rm = TRUE),
      mean(subset_data$Q14g, na.rm = TRUE)
    ),
    reliability = c(
      mean(subset_data$Q15a, na.rm = TRUE),
      mean(subset_data$Q15b, na.rm = TRUE),
      mean(subset_data$Q15c, na.rm = TRUE),
      mean(subset_data$Q15d, na.rm = TRUE),
      mean(subset_data$Q15e, na.rm = TRUE),
      mean(subset_data$Q15f, na.rm = TRUE),
      mean(subset_data$Q15g, na.rm = TRUE)
    )
  )
  
  mat <- bank_means |>
    column_to_rownames("bank") |>
    as.matrix()
  
  pca_bank <- FactoMineR::PCA(mat, scale.unit = TRUE, graph = FALSE)
  
  factoextra::fviz_pca_biplot(
    pca_bank,
    repel = TRUE,
    col.var = "gray30"
  ) +
    ggplot2::ggtitle(title_text) +
    ggplot2::xlab("Dim1: Overall Digital Banking Performance") +
    ggplot2::ylab("Dim2: Customer Support vs Innovation")
}
make_perception_map(
  data = data_cluster_profile_5,
  cluster_values = c("2"),
  title_text = "Perceptual Map of Banks - Cluster 2"
)

make_perception_map(
  data = data_cluster_profile_5,
  cluster_values = c("3"),
  title_text = "Perceptual Map of Banks - Cluster 3"
)

make_perception_map(
  data = data_cluster_profile_5,
  cluster_values = c("5"),
  title_text = "Perceptual Map of Banks - Cluster 5"
)

make_perception_map(
  data = data_cluster_profile_5,
  cluster_values = c("2", "3", "5"),
  title_text = "Perceptual Map of Banks - Clusters 2, 3, and 5"
)

library(dplyr)
library(tidyr)
library(ggplot2)

cluster_q4_table_named <- data_cluster_profile_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  filter(cluster %in% c(
    "Cautious guidance seekers",
    "Feature-oriented adopters",
    "AI-enthusiastic guidance seekers"
  )) |>
  group_by(cluster, Q4) |>
  summarise(n = n(), .groups = "drop") |>
  group_by(cluster) |>
  mutate(percent = round(100 * n / sum(n), 1)) |>
  ungroup() |>
  mutate(
    info_source = case_when(
      Q4 == "1" ~ "Web browsers",
      Q4 == "2" ~ "Family / friends",
      Q4 == "3" ~ "Financial media",
      Q4 == "4" ~ "ChatGPT / AI models",
      Q4 == "5" ~ "Other",
      TRUE ~ as.character(Q4)
    )
  ) |>
  select(cluster, info_source, n, percent)

cluster_q4_table_named
ggplot(cluster_q4_table_named, aes(x = info_source, y = cluster, fill = percent)) +
  geom_tile(color = "white") +
  geom_text(aes(label = paste0(percent, "%")), color = "white", size = 4) +
  labs(
    title = "Information Source by Selected Clusters (%)",
    x = "Information Source",
    y = "Cluster",
    fill = "Percent"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

cluster_q4_wide <- cluster_q4_table_named |>
  select(cluster, info_source, percent) |>
  pivot_wider(
    names_from = info_source,
    values_from = percent,
    values_fill = 0
  )

cluster_q4_wide
library(dplyr)

cluster_vars <- c(
  "Q6a", "Q6b", "Q6d", "Q6e", "Q6h", "Q6i",
  "Q8a", "Q8b", "Q8c", "Q8d", "Q8e"
)

cluster_validation <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(k5_pca2$cluster),
    across(all_of(cluster_vars), as.numeric)
  )
anova_results <- lapply(cluster_vars, function(var) {
  model <- aov(as.formula(paste(var, "~ cluster")), data = cluster_validation)
  data.frame(
    variable = var,
    p_value = summary(model)[[1]][["Pr(>F)"]][1]
  )
})

anova_results <- do.call(rbind, anova_results)
anova_results$p_adjusted <- p.adjust(anova_results$p_value, method = "holm")

anova_results
cluster_means_validation <- cluster_validation |>
  group_by(cluster) |>
  summarise(
    across(all_of(cluster_vars), ~ mean(.x, na.rm = TRUE)),
    .groups = "drop"
  )

cluster_means_validation
library(dplyr)

age_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  filter(!is.na(Q21)) |>
  mutate(
    age = 2026 - as.numeric(Q21)
  )
age_summary <- age_data |>
  group_by(cluster) |>
  summarise(
    n = n(),
    mean_age = mean(age, na.rm = TRUE),
    sd_age = sd(age, na.rm = TRUE),
    median_age = median(age, na.rm = TRUE),
    min_age = min(age, na.rm = TRUE),
    max_age = max(age, na.rm = TRUE)
  )

age_summary
age_anova <- aov(age ~ cluster, data = age_data)
summary(age_anova)
             Df Sum Sq Mean Sq F value   Pr(>F)    
cluster       4  11950  2987.6   12.44 2.09e-09 ***
Residuals   316  75907   240.2                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
TukeyHSD(age_anova)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = age ~ cluster, data = age_data)

$cluster
                                                                  diff         lwr
Cautious guidance seekers-Skeptical support seekers         -7.5313131 -14.6825056
Feature-oriented adopters-Skeptical support seekers          2.1517677  -5.4632570
AI-resistant independents-Skeptical support seekers         10.4484848   1.0853761
AI-enthusiastic guidance seekers-Skeptical support seekers  -8.2035191 -16.0800102
Feature-oriented adopters-Cautious guidance seekers          9.6830808   3.0969363
AI-resistant independents-Cautious guidance seekers         17.9797980   9.4324882
AI-enthusiastic guidance seekers-Cautious guidance seekers  -0.6722059  -7.5589912
AI-resistant independents-Feature-oriented adopters          8.2967172  -0.6422734
AI-enthusiastic guidance seekers-Feature-oriented adopters -10.3552867 -17.7225697
AI-enthusiastic guidance seekers-AI-resistant independents -18.6520039 -27.8147581
                                                                  upr     p adj
Cautious guidance seekers-Skeptical support seekers        -0.3801207 0.0333606
Feature-oriented adopters-Skeptical support seekers         9.7667923 0.9375949
AI-resistant independents-Skeptical support seekers        19.8115936 0.0200832
AI-enthusiastic guidance seekers-Skeptical support seekers -0.3270279 0.0365232
Feature-oriented adopters-Cautious guidance seekers        16.2692253 0.0006548
AI-resistant independents-Cautious guidance seekers        26.5271078 0.0000002
AI-enthusiastic guidance seekers-Cautious guidance seekers  6.2145793 0.9988664
AI-resistant independents-Feature-oriented adopters        17.2357077 0.0831926
AI-enthusiastic guidance seekers-Feature-oriented adopters -2.9880037 0.0013076
AI-enthusiastic guidance seekers-AI-resistant independents -9.4892498 0.0000005
age_summary <- age_data |>
  group_by(cluster) |>
  summarise(
    n = n(),
    mean_age = mean(age, na.rm = TRUE),
    sd_age = sd(age, na.rm = TRUE),
    median_age = median(age, na.rm = TRUE),
    min_age = min(age, na.rm = TRUE),
    max_age = max(age, na.rm = TRUE)
  )

age_summary
age_summary
library(dplyr)

gender_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  filter(!is.na(Q22)) |>
  mutate(
    gender = factor(
      Q22,
      levels = c("1", "2"),
      labels = c("Male", "Female")
    )
  )
gender_table <- table(gender_data$cluster, gender_data$gender)
gender_table
                                  
                                   Male Female
  Skeptical support seekers          39     16
  Cautious guidance seekers          52     46
  Feature-oriented adopters          35     38
  AI-resistant independents          14     19
  AI-enthusiastic guidance seekers   33     29
gender_chisq <- chisq.test(gender_table)
gender_chisq

    Pearson's Chi-squared test

data:  gender_table
X-squared = 9.2334, df = 4, p-value = 0.05552
gender_chisq$expected
                                  
                                       Male   Female
  Skeptical support seekers        29.64174 25.35826
  Cautious guidance seekers        52.81620 45.18380
  Feature-oriented adopters        39.34268 33.65732
  AI-resistant independents        17.78505 15.21495
  AI-enthusiastic guidance seekers 33.41433 28.58567
library(dplyr)

mobile_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  ) |>
  filter(!is.na(Q2)) |>
  mutate(
    mobile_banking_use = as.numeric(Q2)
  )
mobile_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    mobile_banking_use = as.numeric(Q2),
    mobile_banking_use = ifelse(mobile_banking_use == -2, NA, mobile_banking_use)
  ) |>
  filter(!is.na(mobile_banking_use))
table(mobile_data$mobile_banking_use)

  1   2   3   4 
 72 112 105  20 
mobile_data |>
  count(cluster, mobile_banking_use)
mobile_summary <- mobile_data |>
  group_by(cluster) |>
  summarise(
    n = n(),
    mean_mobile_use = mean(mobile_banking_use, na.rm = TRUE),
    sd_mobile_use = sd(mobile_banking_use, na.rm = TRUE),
    median_mobile_use = median(mobile_banking_use, na.rm = TRUE),
    min_mobile_use = min(mobile_banking_use, na.rm = TRUE),
    max_mobile_use = max(mobile_banking_use, na.rm = TRUE)
  )

mobile_summary
mobile_kw <- kruskal.test(mobile_banking_use ~ cluster, data = mobile_data)
mobile_kw

    Kruskal-Wallis rank sum test

data:  mobile_banking_use by cluster
Kruskal-Wallis chi-squared = 6.9046, df = 4, p-value = 0.141
library(dplyr)

education_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1,2,3,4,5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    education = as.numeric(Q24)
  ) |>
  filter(!is.na(education))
table(education_data$education)

  3   4   5   6   7   8 
 98  34  56 104  26   2 
education_data |>
  count(cluster, education)
education_table <- table(education_data$cluster, education_data$education)

education_table
                                  
                                    3  4  5  6  7  8
  Skeptical support seekers        15  2 14 18  6  0
  Cautious guidance seekers        34 14 12 33  5  1
  Feature-oriented adopters        20  9 12 23  8  0
  AI-resistant independents         9  6  5 12  1  0
  AI-enthusiastic guidance seekers 20  3 13 18  6  1
education_chisq <- chisq.test(education_table)

education_chisq

    Pearson's Chi-squared test

data:  education_table
X-squared = 19.208, df = 20, p-value = 0.5083
education_chisq$expected
                                  
                                          3        4      5      6       7       8
  Skeptical support seekers        16.84375  5.84375  9.625 17.875 4.46875 0.34375
  Cautious guidance seekers        30.31875 10.51875 17.325 32.175 8.04375 0.61875
  Feature-oriented adopters        22.05000  7.65000 12.600 23.400 5.85000 0.45000
  AI-resistant independents        10.10625  3.50625  5.775 10.725 2.68125 0.20625
  AI-enthusiastic guidance seekers 18.68125  6.48125 10.675 19.825 4.95625 0.38125
table(education_data$education)

  3   4   5   6   7   8 
 98  34  56 104  26   2 
education_table
                                  
                                    3  4  5  6  7  8
  Skeptical support seekers        15  2 14 18  6  0
  Cautious guidance seekers        34 14 12 33  5  1
  Feature-oriented adopters        20  9 12 23  8  0
  AI-resistant independents         9  6  5 12  1  0
  AI-enthusiastic guidance seekers 20  3 13 18  6  1
education_chisq

    Pearson's Chi-squared test

data:  education_table
X-squared = 19.208, df = 20, p-value = 0.5083
income_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1,2,3,4,5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    income = as.numeric(Q26)
  ) |>
  filter(!is.na(income))
table(income_data$income)

 1  2  3  4  5  6  7  8 
43 43 58 64 49 31 12 20 
income_data |>
  count(cluster, income)
income_table <- table(income_data$cluster, income_data$income)

income_table
                                  
                                    1  2  3  4  5  6  7  8
  Skeptical support seekers         8  4 14 11 10  2  1  5
  Cautious guidance seekers        23 18 15 20  7  8  4  3
  Feature-oriented adopters         5  7 10 13 19  8  4  6
  AI-resistant independents         1  6  8  6  3  5  0  4
  AI-enthusiastic guidance seekers  6  8 11 14 10  8  3  2
income_chisq <- chisq.test(income_table)

income_chisq

    Pearson's Chi-squared test

data:  income_table
X-squared = 44.967, df = 28, p-value = 0.02223
income_chisq$expected
                                  
                                           1         2        3    4         5
  Skeptical support seekers         7.390625  7.390625  9.96875 11.0  8.421875
  Cautious guidance seekers        13.168750 13.168750 17.76250 19.6 15.006250
  Feature-oriented adopters         9.675000  9.675000 13.05000 14.4 11.025000
  AI-resistant independents         4.434375  4.434375  5.98125  6.6  5.053125
  AI-enthusiastic guidance seekers  8.331250  8.331250 11.23750 12.4  9.493750
                                  
                                          6      7      8
  Skeptical support seekers        5.328125 2.0625 3.4375
  Cautious guidance seekers        9.493750 3.6750 6.1250
  Feature-oriented adopters        6.975000 2.7000 4.5000
  AI-resistant independents        3.196875 1.2375 2.0625
  AI-enthusiastic guidance seekers 6.006250 2.3250 3.8750
table(income_data$income)

 1  2  3  4  5  6  7  8 
43 43 58 64 49 31 12 20 
income_table
                                  
                                    1  2  3  4  5  6  7  8
  Skeptical support seekers         8  4 14 11 10  2  1  5
  Cautious guidance seekers        23 18 15 20  7  8  4  3
  Feature-oriented adopters         5  7 10 13 19  8  4  6
  AI-resistant independents         1  6  8  6  3  5  0  4
  AI-enthusiastic guidance seekers  6  8 11 14 10  8  3  2
income_chisq

    Pearson's Chi-squared test

data:  income_table
X-squared = 44.967, df = 28, p-value = 0.02223
income_data_grouped <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    income = as.numeric(Q26),
    income_group = case_when(
      income %in% c(1, 2) ~ "Low income (0–999€)",
      income %in% c(3, 4) ~ "Lower-middle income (1000–1999€)",
      income %in% c(5, 6) ~ "Upper-middle income (2000–2999€)",
      income %in% c(7, 8) ~ "High income (3000€+)",
      TRUE ~ NA_character_
    )
  ) |>
  filter(!is.na(income_group))
table(income_data_grouped$income_group)

            High income (3000€+)              Low income (0–999€) 
                              32                               86 
Lower-middle income (1000–1999€) Upper-middle income (2000–2999€) 
                             122                               80 
income_data_grouped |>
  count(cluster, income_group)
income_group_table <- table(
  income_data_grouped$cluster,
  income_data_grouped$income_group
)

income_group_table
                                  
                                   High income (3000€+) Low income (0–999€)
  Skeptical support seekers                           6                  12
  Cautious guidance seekers                           7                  41
  Feature-oriented adopters                          10                  12
  AI-resistant independents                           4                   7
  AI-enthusiastic guidance seekers                    5                  14
                                  
                                   Lower-middle income (1000–1999€)
  Skeptical support seekers                                      25
  Cautious guidance seekers                                      35
  Feature-oriented adopters                                      23
  AI-resistant independents                                      14
  AI-enthusiastic guidance seekers                               25
                                  
                                   Upper-middle income (2000–2999€)
  Skeptical support seekers                                      12
  Cautious guidance seekers                                      15
  Feature-oriented adopters                                      27
  AI-resistant independents                                       8
  AI-enthusiastic guidance seekers                               18
income_group_chisq <- chisq.test(income_group_table)

income_group_chisq

    Pearson's Chi-squared test

data:  income_group_table
X-squared = 25.314, df = 12, p-value = 0.0134
income_group_chisq$expected
                                  
                                   High income (3000€+) Low income (0–999€)
  Skeptical support seekers                         5.5            14.78125
  Cautious guidance seekers                         9.8            26.33750
  Feature-oriented adopters                         7.2            19.35000
  AI-resistant independents                         3.3             8.86875
  AI-enthusiastic guidance seekers                  6.2            16.66250
                                  
                                   Lower-middle income (1000–1999€)
  Skeptical support seekers                                20.96875
  Cautious guidance seekers                                37.36250
  Feature-oriented adopters                                27.45000
  AI-resistant independents                                12.58125
  AI-enthusiastic guidance seekers                         23.63750
                                  
                                   Upper-middle income (2000–2999€)
  Skeptical support seekers                                   13.75
  Cautious guidance seekers                                   24.50
  Feature-oriented adopters                                   18.00
  AI-resistant independents                                    8.25
  AI-enthusiastic guidance seekers                            15.50
income_profile <- income_data_grouped |>
  count(cluster, income_group) |>
  group_by(cluster) |>
  mutate(percent = round(100 * n / sum(n), 1)) |>
  ungroup()

income_profile
income_profile_wide <- income_profile |>
  select(cluster, income_group, percent) |>
  tidyr::pivot_wider(
    names_from = income_group,
    values_from = percent,
    values_fill = 0
  )

income_profile_wide
bank_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1,2,3,4,5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )
bank_data <- bank_data |>
  mutate(
    across(Q25a:Q25l, ~ as.numeric(.))
  )
revolut_table <- table(bank_data$cluster, bank_data$Q25d)

revolut_table
                                  
                                    0  1
  Skeptical support seekers        44 12
  Cautious guidance seekers        68 31
  Feature-oriented adopters        55 18
  AI-resistant independents        28  4
  AI-enthusiastic guidance seekers 43 19
chisq.test(revolut_table)

    Pearson's Chi-squared test

data:  revolut_table
X-squared = 5.8418, df = 4, p-value = 0.2113
banks <- c("Q25a","Q25b","Q25c","Q25d","Q25e","Q25f","Q25g","Q25h","Q25i","Q25j","Q25k","Q25l")

bank_tests <- lapply(banks, function(var){

  tab <- table(bank_data$cluster, bank_data[[var]])
  test <- chisq.test(tab)

  data.frame(
    bank = var,
    chi_square = test$statistic,
    p_value = test$p.value
  )
})

bank_tests <- do.call(rbind, bank_tests)

bank_tests
otp_profile <- bank_data |>
  group_by(cluster) |>
  summarise(
    otp_users = sum(Q25a == 1, na.rm = TRUE),
    n = n(),
    otp_percent = round(100 * otp_users / n, 1)
  )

otp_profile
area_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1,2,3,4,5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    area = as.numeric(Q23)
  ) |>
  filter(!is.na(area))
table(area_data$area)

  1   2   3 
185  68  70 
area_table <- table(area_data$cluster, area_data$area)

area_table
                                  
                                    1  2  3
  Skeptical support seekers        36 11  9
  Cautious guidance seekers        57 22 20
  Feature-oriented adopters        38 15 20
  AI-resistant independents        15  7 11
  AI-enthusiastic guidance seekers 39 13 10
area_chisq <- chisq.test(area_table)

area_chisq

    Pearson's Chi-squared test

data:  area_table
X-squared = 7.067, df = 8, p-value = 0.5294
area_chisq$expected
                                  
                                          1         2         3
  Skeptical support seekers        32.07430 11.789474 12.136223
  Cautious guidance seekers        56.70279 20.842105 21.455108
  Feature-oriented adopters        41.81115 15.368421 15.820433
  AI-resistant independents        18.90093  6.947368  7.151703
  AI-enthusiastic guidance seekers 35.51084 13.052632 13.436533
area_profile <- area_data |>
  count(cluster, area) |>
  group_by(cluster) |>
  mutate(percent = round(100 * n / sum(n), 1))

area_profile
area_profile <- area_data |>
  count(cluster, area) |>
  group_by(cluster) |>
  mutate(percent = round(100 * n / sum(n), 1)) |>
  ungroup()

area_profile
ai_data <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  ) |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1,2,3,4,5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    ai_use = as.numeric(Q17)
  ) |>
  filter(!is.na(ai_use))
ai_summary <- ai_data |>
  group_by(cluster) |>
  summarise(
    n = n(),
    mean_ai = mean(ai_use),
    sd_ai = sd(ai_use),
    median_ai = median(ai_use),
    min_ai = min(ai_use),
    max_ai = max(ai_use)
  )

ai_summary
ai_anova <- aov(ai_use ~ cluster, data = ai_data)

summary(ai_anova)
             Df Sum Sq Mean Sq F value Pr(>F)    
cluster       4  302.8   75.71    33.2 <2e-16 ***
Residuals   294  670.4    2.28                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
TukeyHSD(ai_anova)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = ai_use ~ cluster, data = ai_data)

$cluster
                                                                 diff         lwr
Cautious guidance seekers-Skeptical support seekers         1.1444444  0.41801040
Feature-oriented adopters-Skeptical support seekers         1.9019608  1.13419826
AI-resistant independents-Skeptical support seekers        -0.5000000 -1.45365166
AI-enthusiastic guidance seekers-Skeptical support seekers  2.5500000  1.76060613
Feature-oriented adopters-Cautious guidance seekers         0.7575163  0.09155992
AI-resistant independents-Cautious guidance seekers        -1.6444444 -2.51822367
AI-enthusiastic guidance seekers-Cautious guidance seekers  1.4055556  0.71477242
AI-resistant independents-Feature-oriented adopters        -2.4019608 -3.31038966
AI-enthusiastic guidance seekers-Feature-oriented adopters  0.6480392 -0.08608217
AI-enthusiastic guidance seekers-AI-resistant independents  3.0500000  2.12321717
                                                                  upr     p adj
Cautious guidance seekers-Skeptical support seekers         1.8708785 0.0002027
Feature-oriented adopters-Skeptical support seekers         2.6697233 0.0000000
AI-resistant independents-Skeptical support seekers         0.4536517 0.6028939
AI-enthusiastic guidance seekers-Skeptical support seekers  3.3393939 0.0000000
Feature-oriented adopters-Cautious guidance seekers         1.4234728 0.0167712
AI-resistant independents-Cautious guidance seekers        -0.7706652 0.0000044
AI-enthusiastic guidance seekers-Cautious guidance seekers  2.0963387 0.0000005
AI-resistant independents-Feature-oriented adopters        -1.4935319 0.0000000
AI-enthusiastic guidance seekers-Feature-oriented adopters  1.3821606 0.1120779
AI-enthusiastic guidance seekers-AI-resistant independents  3.9767828 0.0000000
ai_summary
summary(ai_anova)
             Df Sum Sq Mean Sq F value Pr(>F)    
cluster       4  302.8   75.71    33.2 <2e-16 ***
Residuals   294  670.4    2.28                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# =========================================================
# HYPOTHESIS TEST – H1c
# Q17: Likelihood of using the AI personal banking agent
# =========================================================

# H0 (Null Hypothesis):
# There are no statistically significant differences in the likelihood
# of using the AI personal banking agent (Q17) between the clusters.

# H1c (Research Hypothesis):
# Feature-oriented adopters are more likely to use the AI personal
# banking agent than cautious guidance seekers.

# =========================================================
# 1 LOAD LIBRARIES
# =========================================================

library(dplyr)
library(ggplot2)

# =========================================================
# 2 PREPARE DATA
# =========================================================

# ensure cluster variable is factor
data_cluster_profile_5$cluster <- as.factor(data_cluster_profile_5$cluster)

# convert Q17 to numeric (Likert scale)
data_cluster_profile_5 <- data_cluster_profile_5 %>%
  mutate(Q17 = as.numeric(Q17))

# =========================================================
# 3 DESCRIPTIVE STATISTICS FOR EACH CLUSTER
# =========================================================

cluster_summary_Q17 <- data_cluster_profile_5 %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    mean = mean(Q17, na.rm = TRUE),
    median = median(Q17, na.rm = TRUE),
    sd = sd(Q17, na.rm = TRUE),
    min = min(Q17, na.rm = TRUE),
    max = max(Q17, na.rm = TRUE)
  )

print(cluster_summary_Q17)

# =========================================================
# 4 TEST DIFFERENCES BETWEEN CLUSTERS
# Kruskal–Wallis test (appropriate for Likert data)
# =========================================================

kruskal_test_Q17 <- kruskal.test(Q17 ~ cluster, data = data_cluster_profile_5)

print(kruskal_test_Q17)

    Kruskal-Wallis rank sum test

data:  Q17 by cluster
Kruskal-Wallis chi-squared = 91.782, df = 4, p-value < 2.2e-16
# =========================================================
# 5 POST-HOC TEST (PAIRWISE COMPARISON)
# =========================================================

pairwise_results_Q17 <- pairwise.wilcox.test(
  data_cluster_profile_5$Q17,
  data_cluster_profile_5$cluster,
  p.adjust.method = "bonferroni"
)

print(pairwise_results_Q17)

    Pairwise comparisons using Wilcoxon rank sum test with continuity correction 

data:  data_cluster_profile_5$Q17 and data_cluster_profile_5$cluster 

  1       2       3       4      
2 0.00079 -       -       -      
3 2.9e-07 0.00433 -       -      
4 1.00000 0.00014 1.3e-06 -      
5 1.1e-10 1.7e-08 0.03730 6.8e-09

P value adjustment method: bonferroni 
# =========================================================
# 6 VISUALIZATION
# =========================================================

ggplot(data_cluster_profile_5, aes(x = cluster, y = Q17)) +
  geom_boxplot() +
  labs(
    title = "Likelihood of Using AI Personal Banking Agent by Cluster",
    x = "Cluster",
    y = "Likelihood of Use (Q17)"
  ) +
  theme_minimal()

# =========================================================
# 4b EFFECT SIZE FOR KRUSKAL-WALLIS
# =========================================================

library(rstatix)

effect_size_Q17 <- data_cluster_profile_5 %>%
  kruskal_effsize(Q17 ~ cluster)

print(effect_size_Q17)
# =====================================================
# ASSUMPTION CHECKS – H1c
# =====================================================

shapiro.test(data_cluster_profile_5$Q17)

    Shapiro-Wilk normality test

data:  data_cluster_profile_5$Q17
W = 0.90384, p-value = 7.189e-13
ggplot(data_cluster_profile_5, aes(x = Q17)) +
  geom_histogram(binwidth = 1) +
  theme_minimal()


qqnorm(data_cluster_profile_5$Q17)
qqline(data_cluster_profile_5$Q17)


library(rstatix)

levene_test(Q17 ~ cluster, data = data_cluster_profile_5)

# =====================================================
# KRUSKAL-WALLIS TEST
# =====================================================

kruskal.test(Q17 ~ cluster, data = data_cluster_profile_5)

    Kruskal-Wallis rank sum test

data:  Q17 by cluster
Kruskal-Wallis chi-squared = 91.782, df = 4, p-value < 2.2e-16

##H1e

# =========================================================
# HYPOTHESIS TEST
# Q12g – Preference for human interaction
# =========================================================

# H0 (Null Hypothesis):
# There are no statistically significant differences in preference
# for human interaction (Q12g) between the clusters.

# H1 (Research Hypothesis):
# Cautious guidance seekers show a higher preference for human
# interaction than AI-enthusiastic guidance seekers and
# feature-oriented adopters.

# =========================================================
# 1 LOAD LIBRARIES
# =========================================================

library(dplyr)
library(ggplot2)

# =========================================================
# 2 PREPARE DATA
# =========================================================

# ensure cluster variable is factor
data_cluster_profile_5$cluster <- as.factor(data_cluster_profile_5$cluster)

# convert Likert variable to numeric
data_cluster_profile_5 <- data_cluster_profile_5 %>%
  mutate(Q12g = as.numeric(Q12g))

# =========================================================
# 3 DESCRIPTIVE STATISTICS FOR EACH CLUSTER
# =========================================================

cluster_summary <- data_cluster_profile_5 %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    mean = mean(Q12g, na.rm = TRUE),
    median = median(Q12g, na.rm = TRUE),
    sd = sd(Q12g, na.rm = TRUE),
    min = min(Q12g, na.rm = TRUE),
    max = max(Q12g, na.rm = TRUE)
  )

print(cluster_summary)

# =========================================================
# 4 TEST DIFFERENCES BETWEEN CLUSTERS
# Kruskal–Wallis test (appropriate for Likert scale)
# =========================================================

kruskal_test <- kruskal.test(Q12g ~ cluster, data = data_cluster_profile_5)

print(kruskal_test)

    Kruskal-Wallis rank sum test

data:  Q12g by cluster
Kruskal-Wallis chi-squared = 13.865, df = 4, p-value = 0.007737
# =========================================================
# 5 POST-HOC TEST (PAIRWISE COMPARISON BETWEEN CLUSTERS)
# =========================================================

pairwise_results <- pairwise.wilcox.test(
  data_cluster_profile_5$Q12g,
  data_cluster_profile_5$cluster,
  p.adjust.method = "bonferroni"
)

print(pairwise_results)

    Pairwise comparisons using Wilcoxon rank sum test with continuity correction 

data:  data_cluster_profile_5$Q12g and data_cluster_profile_5$cluster 

  1      2      3      4     
2 1.0000 -      -      -     
3 0.1240 0.3440 -      -     
4 1.0000 1.0000 1.0000 -     
5 1.0000 0.6375 0.0046 1.0000

P value adjustment method: bonferroni 
# =========================================================
# 6 VISUALIZATION OF DIFFERENCES BETWEEN CLUSTERS
# =========================================================

ggplot(data_cluster_profile_5, aes(x = cluster, y = Q12g)) +
  geom_boxplot() +
  labs(
    title = "Preference for Human Interaction by Cluster",
    x = "Cluster",
    y = "Preference for Human Interaction (Q12g)"
  ) +
  theme_minimal()

# =====================================================
# ASSUMPTION CHECKS – H1e
# =====================================================

library(ggplot2)
library(car)

# Normality test
shapiro.test(data_cluster_profile_5$Q12g)

    Shapiro-Wilk normality test

data:  data_cluster_profile_5$Q12g
W = 0.78641, p-value < 2.2e-16
# Histogram
ggplot(data_cluster_profile_5, aes(x = Q12g)) +
  geom_histogram(binwidth = 1) +
  theme_minimal()


# QQ plot
qqnorm(data_cluster_profile_5$Q12g)
qqline(data_cluster_profile_5$Q12g)


# Homogeneity of variances
leveneTest(Q12g ~ cluster, data = data_cluster_profile_5)
Levene's Test for Homogeneity of Variance (center = median)
       Df F value  Pr(>F)  
group   4  2.6236 0.03484 *
      315                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# =====================================================
# KRUSKAL-WALLIS TEST
# =====================================================

kruskal.test(Q12g ~ cluster, data = data_cluster_profile_5)

    Kruskal-Wallis rank sum test

data:  Q12g by cluster
Kruskal-Wallis chi-squared = 13.865, df = 4, p-value = 0.007737
# =========================================================
# 4b EFFECT SIZE FOR KRUSKAL-WALLIS
# =========================================================

library(rstatix)

effect_size_Q12g <- data_cluster_profile_5 %>%
  kruskal_effsize(Q12g ~ cluster)

print(effect_size_Q12g)
install.packages("coin")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/coin_1.4-3.zip'
Content type 'application/zip' length 1473035 bytes (1.4 MB)
downloaded 1.4 MB
package ‘coin’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\frach\AppData\Local\Temp\Rtmp0giUNF\downloaded_packages
library(dplyr)
library(rstatix)
library(coin)
library(purrr)

data_cluster_profile_5 <- data_cluster_profile_5 %>%
  mutate(
    cluster = as.factor(cluster),
    Q12g = as.numeric(as.character(Q12g))
  ) %>%
  filter(!is.na(cluster), !is.na(Q12g))

cluster_pairs <- combn(levels(data_cluster_profile_5$cluster), 2, simplify = FALSE)

pairwise_effects_Q12g <- map_dfr(cluster_pairs, function(x) {
  tmp <- data_cluster_profile_5 %>%
    filter(cluster %in% x) %>%
    droplevels()

  wilcox_effsize(data = tmp, Q12g ~ cluster) %>%
    mutate(comparison = paste(x, collapse = " vs "))
})

print(pairwise_effects_Q12g)
# =========================================================
# HYPOTHESIS TEST – H2d
# The higher the importance of security, the higher the
# willingness to adopt AI agents in personal banking
# Variables:
# Q12a = Importance of security
# Q17  = Willingness to use AI banking agent
# =========================================================

# H0 (Null Hypothesis):
# There is no relationship between the importance of security (Q12a)
# and willingness to adopt AI banking agents (Q17).

# H1 (Research Hypothesis):
# Higher perceived importance of security is associated with a higher
# willingness to adopt AI banking agents.

# =========================================================
# 1 LOAD LIBRARIES
# =========================================================

library(dplyr)
library(ggplot2)

# =========================================================
# 2 PREPARE DATA
# =========================================================

data_cluster_profile_5 <- data_cluster_profile_5 %>%
  mutate(
    Q12a = as.numeric(Q12a),
    Q17 = as.numeric(Q17)
  )

# =========================================================
# 3 DESCRIPTIVE STATISTICS
# =========================================================

summary_stats <- data_cluster_profile_5 %>%
  summarise(
    mean_security = mean(Q12a, na.rm = TRUE),
    sd_security = sd(Q12a, na.rm = TRUE),
    mean_AI_adoption = mean(Q17, na.rm = TRUE),
    sd_AI_adoption = sd(Q17, na.rm = TRUE)
  )

print(summary_stats)

# =========================================================
# 4 CORRELATION TEST (Spearman for ordinal data)
# =========================================================

correlation_test <- cor.test(
  data_cluster_profile_5$Q12a,
  data_cluster_profile_5$Q17,
  method = "spearman",
  use = "complete.obs"
)

print(correlation_test)

    Spearman's rank correlation rho

data:  data_cluster_profile_5$Q12a and data_cluster_profile_5$Q17
S = 4229048, p-value = 0.7115
alternative hypothesis: true rho is not equal to 0
sample estimates:
       rho 
0.02158374 
# =========================================================
# 5 VISUALIZATION
# =========================================================

ggplot(data_cluster_profile_5, aes(x = Q12a, y = Q17)) +
  geom_jitter(alpha = 0.4) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relationship Between Security Importance and AI Agent Adoption",
    x = "Importance of Security (Q12a)",
    y = "Willingness to Use AI Banking Agent (Q17)"
  ) +
  theme_minimal()

# =====================================================
# ASSUMPTION CHECKS – H2d
# =====================================================

# Normality tests
shapiro.test(data_cluster_profile_5$Q12a)

    Shapiro-Wilk normality test

data:  data_cluster_profile_5$Q12a
W = 0.62052, p-value < 2.2e-16
shapiro.test(data_cluster_profile_5$Q17)

    Shapiro-Wilk normality test

data:  data_cluster_profile_5$Q17
W = 0.90494, p-value = 1.04e-12
# Histograms
ggplot(data_cluster_profile_5, aes(x = Q12a)) +
  geom_histogram(binwidth = 1) +
  theme_minimal()


ggplot(data_cluster_profile_5, aes(x = Q17)) +
  geom_histogram(binwidth = 1) +
  theme_minimal()


# QQ plots
qqnorm(data_cluster_profile_5$Q12a)
qqline(data_cluster_profile_5$Q12a)


qqnorm(data_cluster_profile_5$Q17)
qqline(data_cluster_profile_5$Q17)


# =====================================================
# SPEARMAN CORRELATION
# =====================================================

cor.test(
  data_cluster_profile_5$Q12a,
  data_cluster_profile_5$Q17,
  method = "spearman"
)

    Spearman's rank correlation rho

data:  data_cluster_profile_5$Q12a and data_cluster_profile_5$Q17
S = 4229048, p-value = 0.7115
alternative hypothesis: true rho is not equal to 0
sample estimates:
       rho 
0.02158374 
# =========================================================
# HYPOTHESIS TEST – H2e
# AI-enthusiastic guidance seekers perceive less financial
# stress than cautious guidance seekers and feature-oriented adopters
# Variable: Q5b
# =========================================================

library(dplyr)
library(ggplot2)

# ensure cluster is factor
data_cluster_profile_5$cluster <- as.factor(data_cluster_profile_5$cluster)

# convert Likert variable to numeric
data_cluster_profile_5 <- data_cluster_profile_5 %>%
  mutate(Q5b = as.numeric(Q5b))

# =========================================================
# 1 DESCRIPTIVE STATISTICS
# =========================================================

cluster_summary_Q5b <- data_cluster_profile_5 %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    mean = mean(Q5b, na.rm = TRUE),
    median = median(Q5b, na.rm = TRUE),
    sd = sd(Q5b, na.rm = TRUE),
    min = min(Q5b, na.rm = TRUE),
    max = max(Q5b, na.rm = TRUE)
  )

print(cluster_summary_Q5b)

# =========================================================
# 2 KRUSKAL-WALLIS TEST
# =========================================================

kruskal_test_Q5b <- kruskal.test(Q5b ~ cluster, data = data_cluster_profile_5)

print(kruskal_test_Q5b)

    Kruskal-Wallis rank sum test

data:  Q5b by cluster
Kruskal-Wallis chi-squared = 51.518, df = 4, p-value = 1.74e-10
# =========================================================
# 3 POST-HOC TEST (PAIRWISE COMPARISON)
# =========================================================

pairwise_results_Q5b <- pairwise.wilcox.test(
  data_cluster_profile_5$Q5b,
  data_cluster_profile_5$cluster,
  p.adjust.method = "bonferroni"
)

print(pairwise_results_Q5b)

    Pairwise comparisons using Wilcoxon rank sum test with continuity correction 

data:  data_cluster_profile_5$Q5b and data_cluster_profile_5$cluster 

  1       2       3       4      
2 0.00228 -       -       -      
3 1.00000 0.00314 -       -      
4 0.09388 7.8e-07 0.00759 -      
5 0.00072 1.00000 0.00094 2.1e-06

P value adjustment method: bonferroni 
# =========================================================
# 4 VISUALIZATION
# =========================================================

ggplot(data_cluster_profile_5, aes(x = cluster, y = Q5b)) +
  geom_boxplot() +
  labs(
    title = "Perceived Financial Stress by Cluster",
    x = "Cluster",
    y = "Financial Stress (Q5b)"
  ) +
  theme_minimal()

# =====================================================
# ASSUMPTION CHECKS – H2e
# =====================================================

shapiro.test(data_cluster_profile_5$Q5b)

    Shapiro-Wilk normality test

data:  data_cluster_profile_5$Q5b
W = 0.92498, p-value = 1.51e-11
ggplot(data_cluster_profile_5, aes(x = Q5b)) +
  geom_histogram(binwidth = 1) +
  theme_minimal()


qqnorm(data_cluster_profile_5$Q5b)
qqline(data_cluster_profile_5$Q5b)


leveneTest(Q5b ~ cluster, data = data_cluster_profile_5)
Levene's Test for Homogeneity of Variance (center = median)
       Df F value Pr(>F)
group   4  1.5213 0.1957
      313               
# =====================================================
# KRUSKAL-WALLIS TEST
# =====================================================

kruskal.test(Q5b ~ cluster, data = data_cluster_profile_5)

    Kruskal-Wallis rank sum test

data:  Q5b by cluster
Kruskal-Wallis chi-squared = 51.518, df = 4, p-value = 1.74e-10
library(rstatix)

effect_size_Q5b <- data_cluster_profile_5 %>%
  kruskal_effsize(Q5b ~ cluster)

print(effect_size_Q5b)

##H2f

# =====================================================
# CLEAN DATA (REMOVE INVALID AND MISSING VALUES)
# =====================================================

library(dplyr)
library(ggplot2)

data_clean <- data_cluster_profile_5 %>%
  mutate(Q19 = as.numeric(Q19)) %>%   # ensure numeric
  filter(Q19 >= 1)                    # remove invalid values (<1) and NA

# =====================================================
# DESCRIPTIVE STATISTICS BY CLUSTER
# =====================================================

cluster_summary_Q19 <- data_clean %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    mean = mean(Q19, na.rm = TRUE),
    median = median(Q19, na.rm = TRUE),
    sd = sd(Q19, na.rm = TRUE),
    min = min(Q19, na.rm = TRUE),
    max = max(Q19, na.rm = TRUE)
  )

print(cluster_summary_Q19)

# =====================================================
# KRUSKAL-WALLIS TEST
# =====================================================

kruskal_test_Q19 <- kruskal.test(Q19 ~ cluster, data = data_clean)

print(kruskal_test_Q19)

    Kruskal-Wallis rank sum test

data:  Q19 by cluster
Kruskal-Wallis chi-squared = 3.9454, df = 4, p-value = 0.4134
# =====================================================
# PAIRWISE WILCOXON TEST
# =====================================================

pairwise_results_Q19 <- pairwise.wilcox.test(
  data_clean$Q19,
  data_clean$cluster,
  p.adjust.method = "bonferroni"
)

print(pairwise_results_Q19)

    Pairwise comparisons using Wilcoxon rank sum test with continuity correction 

data:  data_clean$Q19 and data_clean$cluster 

  1 2 3 4
2 1 - - -
3 1 1 - -
4 1 1 1 -
5 1 1 1 1

P value adjustment method: bonferroni 
# =====================================================
# VISUALIZATION
# =====================================================

ggplot(data_clean, aes(x = cluster, y = Q19)) +
  geom_boxplot() +
  labs(
    title = "Willingness to Pay for AI Banking Assistant by Cluster",
    x = "Cluster",
    y = "Monthly Willingness to Pay (€)"
  ) +
  theme_minimal()

# =====================================================
# ASSUMPTION CHECKS – H2f
# =====================================================

shapiro.test(data_clean$Q19)

    Shapiro-Wilk normality test

data:  data_clean$Q19
W = 0.93183, p-value = 0.002376
ggplot(data_clean, aes(x = Q19)) +
  geom_histogram(binwidth = 1) +
  theme_minimal()


qqnorm(data_clean$Q19)
qqline(data_clean$Q19)


leveneTest(Q19 ~ cluster, data = data_clean)
Levene's Test for Homogeneity of Variance (center = median)
      Df F value Pr(>F)
group  4  0.6078 0.6587
      55               
# =====================================================
# KRUSKAL-WALLIS TEST
# =====================================================

kruskal.test(Q19 ~ cluster, data = data_clean)

    Kruskal-Wallis rank sum test

data:  Q19 by cluster
Kruskal-Wallis chi-squared = 3.9454, df = 4, p-value = 0.4134
df <- data_cluster_profile_5
# =====================================================
# KRUSKAL-WALLIS TEST
# =====================================================

kruskal_test_Q19 <- kruskal.test(Q19 ~ cluster, data = data_clean)
print(kruskal_test_Q19)

    Kruskal-Wallis rank sum test

data:  Q19 by cluster
Kruskal-Wallis chi-squared = 3.9454, df = 4, p-value = 0.4134
# =====================================================
# EFFECT SIZE
# =====================================================

library(rstatix)

effect_size_Q19 <- data_clean %>%
  kruskal_effsize(Q19 ~ cluster)

print(effect_size_Q19)
library(dplyr)
library(rstatix)
library(coin)
library(purrr)

data_clean <- data_cluster_profile_5 %>%
  mutate(
    cluster = as.factor(cluster),
    Q19 = as.numeric(as.character(Q19))
  ) %>%
  filter(!is.na(cluster), !is.na(Q19), Q19 >= 1)

cluster_pairs <- combn(levels(data_clean$cluster), 2, simplify = FALSE)

pairwise_effects_Q19 <- map_dfr(cluster_pairs, function(x) {
  tmp <- data_clean %>%
    filter(cluster %in% x) %>%
    droplevels()

  wilcox_effsize(data = tmp, Q19 ~ cluster) %>%
    mutate(comparison = paste(x, collapse = " vs "))
})

print(pairwise_effects_Q19)
library(dplyr)
df <- df |>
  mutate(
    across(c(Q10a, Q10b, Q10c, Q10d,
             Q11a, Q11b, Q11c, Q11d, Q11e, Q11f,
             Q17), as.numeric),

    low_risk_delegate  = rowMeans(pick(Q11a, Q11b, Q11f), na.rm = TRUE),
    high_risk_delegate = rowMeans(pick(Q11c, Q11d, Q11e), na.rm = TRUE),

    confirm_required   = Q10c,
    autonomous_decisions = Q10d,

    trust_ai = rowMeans(pick(Q10a, Q10b, Q10c, Q10d), na.rm = TRUE),
    intention_use = Q17
  )

df$cluster <- factor(df$cluster)
table(df$cluster)

 1  2  3  4  5 
55 98 73 32 62 

Min and max

df |>
  summarise(
    h1a_low_min = min(low_risk_delegate, na.rm = TRUE),
    h1a_low_max = max(low_risk_delegate, na.rm = TRUE),
    h1a_high_min = min(high_risk_delegate, na.rm = TRUE),
    h1a_high_max = max(high_risk_delegate, na.rm = TRUE),

    h1b_confirm_min = min(confirm_required, na.rm = TRUE),
    h1b_confirm_max = max(confirm_required, na.rm = TRUE),
    h1b_auto_min = min(autonomous_decisions, na.rm = TRUE),
    h1b_auto_max = max(autonomous_decisions, na.rm = TRUE),

    h2a_trust_min = min(trust_ai, na.rm = TRUE),
    h2a_trust_max = max(trust_ai, na.rm = TRUE),

    h2c_intention_min = min(intention_use, na.rm = TRUE),
    h2c_intention_max = max(intention_use, na.rm = TRUE)
  )

H1a

h1a_results <- df |>
  group_by(cluster) |>
  do({
    sub <- .
    test <- t.test(sub$low_risk_delegate, sub$high_risk_delegate, paired = TRUE)

    tibble(
      n = nrow(sub),
      low_mean = mean(sub$low_risk_delegate, na.rm = TRUE),
      high_mean = mean(sub$high_risk_delegate, na.rm = TRUE),
      t_value = unname(test$statistic),
      p_value = test$p.value
    )
  })

h1a_results
df <- df |>
  mutate(
    h1a_diff = low_risk_delegate - high_risk_delegate
  )

Normality

by(df$h1a_diff, df$cluster, shapiro.test)
df$cluster: 1

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.88369, p-value = 7.063e-05

---------------------------------------------------------------- 
df$cluster: 2

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.95528, p-value = 0.002138

---------------------------------------------------------------- 
df$cluster: 3

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.96967, p-value = 0.07566

---------------------------------------------------------------- 
df$cluster: 4

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.74155, p-value = 3.872e-06

---------------------------------------------------------------- 
df$cluster: 5

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.94489, p-value = 0.00763

Wilcoxon signed-rank

h1a_wilcox_results <- df |>
  group_by(cluster) |>
  do({
    sub <- .
    test <- wilcox.test(sub$low_risk_delegate, sub$high_risk_delegate, paired = TRUE)

    tibble(
      n = nrow(sub),
      low_mean = mean(sub$low_risk_delegate, na.rm = TRUE),
      high_mean = mean(sub$high_risk_delegate, na.rm = TRUE),
      p_value = test$p.value
    )
  })

h1a_wilcox_results
h1a_final_results <- df |>
  group_by(cluster) |>
  do({
    sub <- .
    
    t_res <- t.test(sub$low_risk_delegate, sub$high_risk_delegate, paired = TRUE)
    w_res <- wilcox.test(sub$low_risk_delegate, sub$high_risk_delegate, paired = TRUE)
    
    diff <- sub$low_risk_delegate - sub$high_risk_delegate
    diff <- diff[!is.na(diff)]
    
    dz <- if (sd(diff) == 0) NA_real_ else mean(diff) / sd(diff)
    
    diff_nz <- diff[diff != 0]
    if (length(diff_nz) == 0) {
      rbc <- NA_real_
    } else {
      ranks <- rank(abs(diff_nz))
      W_pos <- sum(ranks[diff_nz > 0])
      W_neg <- sum(ranks[diff_nz < 0])
      rbc <- (W_pos - W_neg) / (W_pos + W_neg)
    }

    tibble(
      n = length(diff),
      low_mean = mean(sub$low_risk_delegate, na.rm = TRUE),
      high_mean = mean(sub$high_risk_delegate, na.rm = TRUE),
      mean_diff = mean(diff),
      t_value = unname(t_res$statistic),
      t_p_value = t_res$p.value,
      wilcox_p_value = w_res$p.value,
      cohen_dz = dz,
      rank_biserial = rbc
    )
  })

h1a_final_results

H1b

h1b_results <- df |>
  group_by(cluster) |>
  do({
    sub <- .
    test <- t.test(sub$confirm_required, sub$autonomous_decisions, paired = TRUE)

    tibble(
      n = nrow(sub),
      confirm_mean = mean(sub$confirm_required, na.rm = TRUE),
      autonomous_mean = mean(sub$autonomous_decisions, na.rm = TRUE),
      t_value = unname(test$statistic),
      p_value = test$p.value
    )
  })

h1b_results
df <- df |>
  mutate(
    h1b_diff = confirm_required - autonomous_decisions
  )

Normality by cluster

by(df$h1b_diff, df$cluster, shapiro.test)
df$cluster: 1

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.86987, p-value = 2.597e-05

---------------------------------------------------------------- 
df$cluster: 2

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.94847, p-value = 0.0008754

---------------------------------------------------------------- 
df$cluster: 3

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.89899, p-value = 2.478e-05

---------------------------------------------------------------- 
df$cluster: 4

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.74448, p-value = 4.324e-06

---------------------------------------------------------------- 
df$cluster: 5

    Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.87691, p-value = 1.58e-05

Wilcoxon signed-rank

h1b_wilcox_results <- df |>
  group_by(cluster) |>
  do({
    sub <- .
    test <- wilcox.test(
      sub$confirm_required,
      sub$autonomous_decisions,
      paired = TRUE,
      exact = FALSE
    )

    tibble(
      n = nrow(sub),
      confirm_mean = mean(sub$confirm_required, na.rm = TRUE),
      autonomous_mean = mean(sub$autonomous_decisions, na.rm = TRUE),
      p_value = test$p.value
    )
  })

h1b_wilcox_results
h1b_final_results <- df |>
  group_by(cluster) |>
  do({
    sub <- .
    
    t_res <- t.test(sub$confirm_required, sub$autonomous_decisions, paired = TRUE)
    w_res <- wilcox.test(
      sub$confirm_required,
      sub$autonomous_decisions,
      paired = TRUE,
      exact = FALSE
    )
    
    diff <- sub$confirm_required - sub$autonomous_decisions
    diff <- diff[!is.na(diff)]
    
    dz <- if (sd(diff) == 0) NA_real_ else mean(diff) / sd(diff)
    
    diff_nz <- diff[diff != 0]
    if (length(diff_nz) == 0) {
      rbc <- NA_real_
    } else {
      ranks <- rank(abs(diff_nz))
      W_pos <- sum(ranks[diff_nz > 0])
      W_neg <- sum(ranks[diff_nz < 0])
      rbc <- (W_pos - W_neg) / (W_pos + W_neg)
    }

    tibble(
      n = length(diff),
      confirm_mean = mean(sub$confirm_required, na.rm = TRUE),
      autonomous_mean = mean(sub$autonomous_decisions, na.rm = TRUE),
      mean_diff = mean(diff),
      t_value = unname(t_res$statistic),
      t_p_value = t_res$p.value,
      wilcox_p_value = w_res$p.value,
      cohen_dz = dz,
      rank_biserial = rbc
    )
  })

h1b_final_results
library(dplyr)

# make sure variables are in the right format
df$cluster <- as.factor(df$cluster)
df$trust_ai <- as.numeric(df$trust_ai)

## H2a
h2a_model <- aov(trust_ai ~ cluster, data = df)
summary(h2a_model)
             Df Sum Sq Mean Sq F value Pr(>F)    
cluster       4  385.0   96.26   76.05 <2e-16 ***
Residuals   315  398.7    1.27                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Post-hoc option 1: Tukey
TukeyHSD(h2a_model)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = trust_ai ~ cluster, data = df)

$cluster
          diff          lwr        upr     p adj
2-1  1.1170686  0.597018142  1.6371191 0.0000001
3-1  1.5861768  1.035043859  2.1373098 0.0000000
4-1 -1.2555398 -1.941813671 -0.5692659 0.0000086
5-1  2.5143695  1.942614555  3.0861244 0.0000000
3-2  0.4691082 -0.008110863  0.9463272 0.0566237
4-2 -2.3726084 -3.001068703 -1.7441481 0.0000000
5-2  1.3973009  0.896407469  1.8981942 0.0000000
4-3 -2.8417166 -3.496130365 -2.1873029 0.0000000
5-3  0.9281927  0.395098660  1.4612867 0.0000268
5-4  3.7699093  3.098036131  4.4417824 0.0000000
# Post-hoc option 2: pairwise t-tests with Bonferroni
pairwise.t.test(
  x = df$trust_ai,
  g = df$cluster,
  p.adjust.method = "bonferroni"
)

    Pairwise comparisons using t tests with pooled SD 

data:  df$trust_ai and df$cluster 

  1       2       3       4      
2 9.7e-08 -       -       -      
3 4.8e-13 0.074   -       -      
4 8.7e-06 < 2e-16 < 2e-16 -      
5 < 2e-16 2.4e-12 2.7e-05 < 2e-16

P value adjustment method: bonferroni 
# Descriptive means
aggregate(trust_ai ~ cluster, data = df, mean, na.rm = TRUE)
install.packages("effectsize")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/

  There is a binary version available but the source version is later:
trying URL 'https://cran.rstudio.com/src/contrib/effectsize_1.0.2.tar.gz'
Content type 'application/x-gzip' length 396056 bytes (386 KB)
downloaded 386 KB
* installing *source* package 'effectsize' ...
** this is package 'effectsize' version '1.0.2'
** package 'effectsize' successfully unpacked and MD5 sums checked
** using staged installation
** R
** data
** inst
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
*** copying figures
** building package indices
** installing vignettes
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (effectsize)

The downloaded source packages are in
    ‘C:\Users\frach\AppData\Local\Temp\Rtmp0giUNF\downloaded_packages’
library(effectsize)
library(dplyr)
library(effectsize)

df$cluster <- as.factor(df$cluster)
df$trust_ai <- as.numeric(df$trust_ai)

## H2a
h2a_model <- aov(trust_ai ~ cluster, data = df)
summary(h2a_model)
             Df Sum Sq Mean Sq F value Pr(>F)    
cluster       4  385.0   96.26   76.05 <2e-16 ***
Residuals   315  398.7    1.27                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
TukeyHSD(h2a_model)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = trust_ai ~ cluster, data = df)

$cluster
          diff          lwr        upr     p adj
2-1  1.1170686  0.597018142  1.6371191 0.0000001
3-1  1.5861768  1.035043859  2.1373098 0.0000000
4-1 -1.2555398 -1.941813671 -0.5692659 0.0000086
5-1  2.5143695  1.942614555  3.0861244 0.0000000
3-2  0.4691082 -0.008110863  0.9463272 0.0566237
4-2 -2.3726084 -3.001068703 -1.7441481 0.0000000
5-2  1.3973009  0.896407469  1.8981942 0.0000000
4-3 -2.8417166 -3.496130365 -2.1873029 0.0000000
5-3  0.9281927  0.395098660  1.4612867 0.0000268
5-4  3.7699093  3.098036131  4.4417824 0.0000000
aggregate(trust_ai ~ cluster, data = df, mean, na.rm = TRUE)

# Effect sizes
eta_squared(h2a_model)
# Effect Size for ANOVA

Parameter | Eta2 |       95% CI
-------------------------------
cluster   | 0.49 | [0.43, 1.00]

- One-sided CIs: upper bound fixed at [1.00].
omega_squared(h2a_model)
# Effect Size for ANOVA

Parameter | Omega2 |       95% CI
---------------------------------
cluster   |   0.48 | [0.42, 1.00]

- One-sided CIs: upper bound fixed at [1.00].
h2a_eta <- eta_squared(h2a_model)
print(h2a_eta)
# Effect Size for ANOVA

Parameter | Eta2 |       95% CI
-------------------------------
cluster   | 0.49 | [0.43, 1.00]

- One-sided CIs: upper bound fixed at [1.00].
h2a_omega <- omega_squared(h2a_model)
print(h2a_omega)
# Effect Size for ANOVA

Parameter | Omega2 |       95% CI
---------------------------------
cluster   |   0.48 | [0.42, 1.00]

- One-sided CIs: upper bound fixed at [1.00].

H2c

h2c_results <- lapply(levels(df$cluster), function(cl) {
  sub <- df |>
    filter(cluster == cl)

  model <- lm(intention_use ~ trust_ai, data = sub)
  coefs <- summary(model)$coefficients

  tibble(
  cluster = cl,
  b_trust = coefs["trust_ai", "Estimate"],
  p_value = coefs["trust_ai", "Pr(>|t|)"],
  r_squared = summary(model)$r.squared
)
}) |>
  bind_rows()

h2c_results

Normality of regression residuals by cluster

for(cl in levels(df$cluster)) {
  sub <- df |>
    filter(cluster == cl)

  model <- lm(intention_use ~ trust_ai, data = sub)

  cat("\n====================================\n")
  cat("CLUSTER:", cl, "\n")
  cat("====================================\n")
  print(shapiro.test(residuals(model)))
}

====================================
CLUSTER: 1 
====================================

    Shapiro-Wilk normality test

data:  residuals(model)
W = 0.96142, p-value = 0.1019


====================================
CLUSTER: 2 
====================================

    Shapiro-Wilk normality test

data:  residuals(model)
W = 0.95435, p-value = 0.003354


====================================
CLUSTER: 3 
====================================

    Shapiro-Wilk normality test

data:  residuals(model)
W = 0.95225, p-value = 0.01102


====================================
CLUSTER: 4 
====================================

    Shapiro-Wilk normality test

data:  residuals(model)
W = 0.87471, p-value = 0.002561


====================================
CLUSTER: 5 
====================================

    Shapiro-Wilk normality test

data:  residuals(model)
W = 0.86598, p-value = 9.328e-06

Spearman test

h2c_spearman <- lapply(levels(df$cluster), function(cl) {
  sub <- df |>
    filter(cluster == cl)

  test <- cor.test(sub$trust_ai, sub$intention_use, method = "spearman")

  tibble(
    cluster = cl,
    rho = unname(test$estimate),
    p_value = test$p.value
  )
}) |>
  bind_rows()

h2c_spearman
h2c_results <- lapply(levels(df$cluster), function(cl) {
  sub <- df |>
    filter(cluster == cl)

  model <- lm(intention_use ~ trust_ai, data = sub)
  coefs <- summary(model)$coefficients

  tibble(
    cluster = cl,
    b_trust = coefs["trust_ai", "Estimate"],
    p_value = coefs["trust_ai", "Pr(>|t|)"],
    r_squared = summary(model)$r.squared,
    adj_r_squared = summary(model)$adj.r.squared
  )
}) |>
  bind_rows()

h2c_results
library(dplyr)
library(tidyr)
library(purrr)
library(tibble)

data_cluster_profile_5 <- data_cluster_profile_5 |>
  mutate(
    cluster_named = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )
bank_labels <- c(
  a = "OTP",
  b = "Gorenjska Banka",
  c = "NLB",
  d = "Revolut",
  e = "N26",
  f = "Intesa SanPaolo",
  g = "UniCredit"
)

run_bank_pairwise_tests <- function(data, cluster_name) {
  
  subset_data <- data |>
    filter(cluster_named == cluster_name) |>
    mutate(across(Q13a:Q15g, as.numeric))
  
  compare_dimension <- function(df, vars, dimension_name) {
    
    pairs <- combn(vars, 2, simplify = FALSE)
    
    results <- lapply(pairs, function(pair) {
      v1 <- pair[1]
      v2 <- pair[2]
      
      x <- df[[v1]]
      y <- df[[v2]]
      
      complete_idx <- complete.cases(x, y)
      x <- x[complete_idx]
      y <- y[complete_idx]
      
      test <- wilcox.test(x, y, paired = TRUE, exact = FALSE)
      
      tibble(
        cluster = cluster_name,
        dimension = dimension_name,
        bank_1 = bank_labels[substr(v1, nchar(v1), nchar(v1))],
        bank_2 = bank_labels[substr(v2, nchar(v2), nchar(v2))],
        n = length(x),
        mean_bank_1 = mean(x, na.rm = TRUE),
        mean_bank_2 = mean(y, na.rm = TRUE),
        p_value = test$p.value
      )
    })
    
    bind_rows(results) |>
      mutate(
        p_adjusted = p.adjust(p_value, method = "bonferroni"),
        significant = ifelse(p_adjusted < 0.05, "Yes", "No")
      ) |>
      arrange(p_adjusted)
  }
  
  innovation_results <- compare_dimension(
    subset_data,
    vars = c("Q13a", "Q13b", "Q13c", "Q13d", "Q13e", "Q13f", "Q13g"),
    dimension_name = "Innovation"
  )
  
  support_results <- compare_dimension(
    subset_data,
    vars = c("Q14a", "Q14b", "Q14c", "Q14d", "Q14e", "Q14f", "Q14g"),
    dimension_name = "Customer support"
  )
  
  reliability_results <- compare_dimension(
    subset_data,
    vars = c("Q15a", "Q15b", "Q15c", "Q15d", "Q15e", "Q15f", "Q15g"),
    dimension_name = "Reliability"
  )
  
  bind_rows(
    innovation_results,
    support_results,
    reliability_results
  )
}
all_cluster_bank_tests <- bind_rows(
  run_bank_pairwise_tests(data_cluster_profile_5, "Skeptical support seekers"),
  run_bank_pairwise_tests(data_cluster_profile_5, "Cautious guidance seekers"),
  run_bank_pairwise_tests(data_cluster_profile_5, "Feature-oriented adopters"),
  run_bank_pairwise_tests(data_cluster_profile_5, "AI-resistant independents"),
  run_bank_pairwise_tests(data_cluster_profile_5, "AI-enthusiastic guidance seekers")
)

all_cluster_bank_tests
all_cluster_bank_tests_sig <- all_cluster_bank_tests |>
  filter(p_adjusted < 0.05)

all_cluster_bank_tests_sig
all_cluster_bank_tests_sig <- all_cluster_bank_tests_sig |>
  arrange(cluster, dimension, p_adjusted)

all_cluster_bank_tests_sig
all_cluster_bank_tests_sig |>
  count(cluster, dimension)
write.csv(
  all_cluster_bank_tests,
  "all_cluster_bank_pairwise_tests.csv",
  row.names = FALSE
)

write.csv(
  all_cluster_bank_tests_sig,
  "significant_cluster_bank_pairwise_tests.csv",
  row.names = FALSE
)
# Recreate readable output tables from all_cluster_bank_tests

interpretable_results <- all_cluster_bank_tests |>
  mutate(
    mean_bank_1 = round(mean_bank_1, 2),
    mean_bank_2 = round(mean_bank_2, 2),
    mean_difference = round(mean_bank_1 - mean_bank_2, 2),
    higher_rated_bank = case_when(
      mean_bank_1 > mean_bank_2 ~ bank_1,
      mean_bank_2 > mean_bank_1 ~ bank_2,
      TRUE ~ "Equal"
    ),
    interpretation = case_when(
      p_adjusted < 0.05 & mean_bank_1 > mean_bank_2 ~
        paste0(bank_1, " is rated significantly higher than ", bank_2),
      p_adjusted < 0.05 & mean_bank_2 > mean_bank_1 ~
        paste0(bank_2, " is rated significantly higher than ", bank_1),
      TRUE ~ "No significant difference"
    ),
    p_value = round(p_value, 4),
    p_adjusted = round(p_adjusted, 4)
  ) |>
  arrange(cluster, dimension, p_adjusted)

significant_results_clean <- interpretable_results |>
  filter(p_adjusted < 0.05) |>
  select(
    cluster,
    dimension,
    bank_1,
    bank_2,
    mean_bank_1,
    mean_bank_2,
    mean_difference,
    higher_rated_bank,
    p_value,
    p_adjusted,
    interpretation
  )

report_table <- significant_results_clean |>
  transmute(
    Cluster = cluster,
    Dimension = dimension,
    Comparison = paste(bank_1, "vs", bank_2),
    `Mean bank 1` = mean_bank_1,
    `Mean bank 2` = mean_bank_2,
    `Mean difference` = mean_difference,
    `Higher-rated bank` = higher_rated_bank,
    `Raw p-value` = p_value,
    `Adjusted p-value` = p_adjusted,
    Interpretation = interpretation
  )

# Show outputs
interpretable_results
significant_results_clean
report_table
all_cluster_bank_tests |>
  mutate(
    mean_bank_1 = round(mean_bank_1, 2),
    mean_bank_2 = round(mean_bank_2, 2),
    p_adjusted = round(p_adjusted, 4),
    result = case_when(
      p_adjusted < 0.05 & mean_bank_1 > mean_bank_2 ~ paste(bank_1, ">", bank_2),
      p_adjusted < 0.05 & mean_bank_2 > mean_bank_1 ~ paste(bank_2, ">", bank_1),
      TRUE ~ "No significant difference"
    )
  ) |>
  filter(p_adjusted < 0.05) |>
  select(cluster, dimension, bank_1, bank_2, mean_bank_1, mean_bank_2, p_adjusted, result) |>
  arrange(cluster, dimension, p_adjusted)
library(dplyr)

q19_cluster_summary <- data_cluster_profile_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    Q19 = as.numeric(Q19)
  ) |>
  filter(!is.na(Q19), Q19 >= 1) |>
  group_by(cluster) |>
  summarise(
    n = n(),
    mean_q19 = mean(Q19, na.rm = TRUE),
    median_q19 = median(Q19, na.rm = TRUE),
    sd_q19 = sd(Q19, na.rm = TRUE),
    min_q19 = min(Q19, na.rm = TRUE),
    max_q19 = max(Q19, na.rm = TRUE),
    .groups = "drop"
  ) |>
  mutate(
    mean_q19 = round(mean_q19, 2),
    median_q19 = round(median_q19, 2),
    sd_q19 = round(sd_q19, 2)
  ) |>
  arrange(desc(mean_q19))

q19_cluster_summary
kruskal.test(Q19 ~ cluster, data = data_cluster_profile_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    Q19 = as.numeric(Q19)
  ) |>
  filter(!is.na(Q19), Q19 >= 1)
)

    Kruskal-Wallis rank sum test

data:  Q19 by cluster
Kruskal-Wallis chi-squared = 3.9454, df = 4, p-value = 0.4134
library(dplyr)

nlb_revolut_n26_overlap <- data_cluster_profile_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    Q25c = as.numeric(Q25c),  # NLB
    Q25d = as.numeric(Q25d),  # Revolut
    Q25e = as.numeric(Q25e)   # N26
  ) |>
  group_by(cluster) |>
  summarise(
    cluster_n = n(),
    n_nlb_revolut_n26 = sum(Q25c == 1 & Q25d == 1 & Q25e == 1, na.rm = TRUE),
    percent_nlb_revolut_n26 = round(100 * n_nlb_revolut_n26 / cluster_n, 1),
    .groups = "drop"
  )

nlb_revolut_n26_overlap
library(dplyr)

nlb_revolut_n26_combinations <- data_cluster_profile_5 |>
  mutate(
    cluster = factor(
      cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    ),
    Q25c = as.numeric(Q25c),  # NLB
    Q25d = as.numeric(Q25d),  # Revolut
    Q25e = as.numeric(Q25e)   # N26
  ) |>
  mutate(
    bank_combo = case_when(
      Q25c == 1 & Q25d == 1 & Q25e == 1 ~ "NLB + Revolut + N26",
      Q25c == 1 & Q25d == 1 & (is.na(Q25e) | Q25e != 1) ~ "NLB + Revolut",
      Q25c == 1 & Q25e == 1 & (is.na(Q25d) | Q25d != 1) ~ "NLB + N26",
      Q25d == 1 & Q25e == 1 & (is.na(Q25c) | Q25c != 1) ~ "Revolut + N26",
      Q25c == 1 & (is.na(Q25d) | Q25d != 1) & (is.na(Q25e) | Q25e != 1) ~ "NLB only",
      Q25d == 1 & (is.na(Q25c) | Q25c != 1) & (is.na(Q25e) | Q25e != 1) ~ "Revolut only",
      Q25e == 1 & (is.na(Q25c) | Q25c != 1) & (is.na(Q25d) | Q25d != 1) ~ "N26 only",
      TRUE ~ "None of these three"
    )
  ) |>
  group_by(cluster, bank_combo) |>
  summarise(n = n(), .groups = "drop_last") |>
  mutate(percent = round(100 * n / sum(n), 1)) |>
  ungroup()

nlb_revolut_n26_combinations
library(dplyr)
library(tibble)
library(FactoMineR)
library(factoextra)
library(ggplot2)

cluster2_bank_means <- data_cluster_profile_5 |>
  filter(cluster == 2) |>
  mutate(
    across(Q13a:Q15g, as.numeric)
  ) |>
  summarise(
    OTP_innovation = mean(Q13a, na.rm = TRUE),
    Gorenjska_innovation = mean(Q13b, na.rm = TRUE),
    NLB_innovation = mean(Q13c, na.rm = TRUE),
    Revolut_innovation = mean(Q13d, na.rm = TRUE),
    N26_innovation = mean(Q13e, na.rm = TRUE),
    Intesa_innovation = mean(Q13f, na.rm = TRUE),
    UniCredit_innovation = mean(Q13g, na.rm = TRUE),

    OTP_support = mean(Q14a, na.rm = TRUE),
    Gorenjska_support = mean(Q14b, na.rm = TRUE),
    NLB_support = mean(Q14c, na.rm = TRUE),
    Revolut_support = mean(Q14d, na.rm = TRUE),
    N26_support = mean(Q14e, na.rm = TRUE),
    Intesa_support = mean(Q14f, na.rm = TRUE),
    UniCredit_support = mean(Q14g, na.rm = TRUE),

    OTP_reliability = mean(Q15a, na.rm = TRUE),
    Gorenjska_reliability = mean(Q15b, na.rm = TRUE),
    NLB_reliability = mean(Q15c, na.rm = TRUE),
    Revolut_reliability = mean(Q15d, na.rm = TRUE),
    N26_reliability = mean(Q15e, na.rm = TRUE),
    Intesa_reliability = mean(Q15f, na.rm = TRUE),
    UniCredit_reliability = mean(Q15g, na.rm = TRUE)
  )

cluster2_bank_means
cluster2_bank_table <- tibble(
  bank = c("OTP", "Gorenjska Banka", "NLB", "Revolut", "N26", "Intesa SanPaolo", "UniCredit"),
  innovation = c(
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13a), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13b), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13c), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13d), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13e), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13f), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q13g), na.rm = TRUE)
  ),
  customer_support = c(
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14a), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14b), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14c), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14d), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14e), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14f), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q14g), na.rm = TRUE)
  ),
  reliability = c(
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15a), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15b), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15c), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15d), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15e), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15f), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 2) |> pull(Q15g), na.rm = TRUE)
  )
)

cluster2_bank_table
cluster2_mat <- cluster2_bank_table |>
  column_to_rownames("bank") |>
  as.matrix()

pca_cluster2 <- FactoMineR::PCA(cluster2_mat, scale.unit = TRUE, graph = FALSE)
cluster2_coordinates <- as.data.frame(pca_cluster2$ind$coord)
cluster2_coordinates$bank <- rownames(cluster2_coordinates)
rownames(cluster2_coordinates) <- NULL

cluster2_coordinates
cluster2_loadings <- as.data.frame(pca_cluster2$var$coord)
cluster2_loadings$dimension <- rownames(cluster2_loadings)
rownames(cluster2_loadings) <- NULL

cluster2_loadings
cluster2_nlb_explanation <- cluster2_bank_table |>
  filter(bank == "NLB") |>
  mutate(
    Dim1_loading_innovation = pca_cluster2$var$coord["innovation", "Dim.1"],
    Dim1_loading_support = pca_cluster2$var$coord["customer_support", "Dim.1"],
    Dim1_loading_reliability = pca_cluster2$var$coord["reliability", "Dim.1"],
    Dim2_loading_innovation = pca_cluster2$var$coord["innovation", "Dim.2"],
    Dim2_loading_support = pca_cluster2$var$coord["customer_support", "Dim.2"],
    Dim2_loading_reliability = pca_cluster2$var$coord["reliability", "Dim.2"],
    NLB_Dim1 = pca_cluster2$ind$coord["NLB", "Dim.1"],
    NLB_Dim2 = pca_cluster2$ind$coord["NLB", "Dim.2"]
  )

cluster2_nlb_explanation
factoextra::fviz_pca_biplot(
  pca_cluster2,
  repel = TRUE,
  col.var = "gray30",
  col.ind = "steelblue",
  pointsize = 3
) +
  ggplot2::ggtitle("Perception Map of Banks - Cluster 2") +
  ggplot2::xlab("Dim 1") +
  ggplot2::ylab("Dim 2") +
  ggplot2::theme_minimal()

cluster2_bank_table
cluster2_coordinates
cluster2_loadings
library(dplyr)
library(tibble)
library(FactoMineR)
library(factoextra)
library(ggplot2)

# --------------------------------------------
# 1) Bank mean table for cluster 3
# --------------------------------------------
cluster3_bank_table <- tibble(
  bank = c("OTP", "Gorenjska Banka", "NLB", "Revolut", "N26", "Intesa SanPaolo", "UniCredit"),
  innovation = c(
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13a), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13b), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13c), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13d), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13e), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13f), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q13g), na.rm = TRUE)
  ),
  customer_support = c(
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14a), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14b), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14c), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14d), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14e), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14f), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q14g), na.rm = TRUE)
  ),
  reliability = c(
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15a), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15b), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15c), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15d), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15e), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15f), na.rm = TRUE),
    mean(data_cluster_profile_5 |> filter(cluster == 3) |> pull(Q15g), na.rm = TRUE)
  )
)

cluster3_bank_table
# --------------------------------------------
# 2) PCA for cluster 3
# --------------------------------------------
cluster3_mat <- cluster3_bank_table |>
  column_to_rownames("bank") |>
  as.matrix()

pca_cluster3 <- FactoMineR::PCA(cluster3_mat, scale.unit = TRUE, graph = FALSE)
# --------------------------------------------
# 3) Bank coordinates
# --------------------------------------------
cluster3_coordinates <- as.data.frame(pca_cluster3$ind$coord)
cluster3_coordinates$bank <- rownames(cluster3_coordinates)
rownames(cluster3_coordinates) <- NULL

cluster3_coordinates
# --------------------------------------------
# 4) Variable loadings
# --------------------------------------------
cluster3_loadings <- as.data.frame(pca_cluster3$var$coord)
cluster3_loadings$dimension <- rownames(cluster3_loadings)
rownames(cluster3_loadings) <- NULL

cluster3_loadings
# --------------------------------------------
# 5) NLB explanation table
# --------------------------------------------
cluster3_nlb_explanation <- cluster3_bank_table |>
  filter(bank == "NLB") |>
  mutate(
    Dim1_loading_innovation = pca_cluster3$var$coord["innovation", "Dim.1"],
    Dim1_loading_support = pca_cluster3$var$coord["customer_support", "Dim.1"],
    Dim1_loading_reliability = pca_cluster3$var$coord["reliability", "Dim.1"],
    Dim2_loading_innovation = pca_cluster3$var$coord["innovation", "Dim.2"],
    Dim2_loading_support = pca_cluster3$var$coord["customer_support", "Dim.2"],
    Dim2_loading_reliability = pca_cluster3$var$coord["reliability", "Dim.2"],
    NLB_Dim1 = pca_cluster3$ind$coord["NLB", "Dim.1"],
    NLB_Dim2 = pca_cluster3$ind$coord["NLB", "Dim.2"]
  )

cluster3_nlb_explanation
# --------------------------------------------
# 6) Plot
# --------------------------------------------
factoextra::fviz_pca_biplot(
  pca_cluster3,
  repel = TRUE,
  col.var = "gray30",
  col.ind = "steelblue",
  pointsize = 3
) +
  ggplot2::ggtitle("Perception Map of Banks - Cluster 3") +
  ggplot2::xlab("Dim 1") +
  ggplot2::ylab("Dim 2") +
  ggplot2::theme_minimal()

# --------------------------------------------
# 7) Compare NLB with Revolut and N26
# --------------------------------------------
cluster3_bank_table |>
  filter(bank %in% c("NLB", "Revolut", "N26"))
cluster3_bank_table
library(dplyr)
library(tidyr)
library(purrr)

# -----------------------------
# 1) Q12 item labels
# -----------------------------
q12_labels <- c(
  Q12a = "Security",
  Q12b = "Personal data protection",
  Q12c = "Trust in the bank",
  Q12d = "Ease of use",
  Q12e = "Transaction execution speed",
  Q12f = "Variety of functions",
  Q12g = "Availability of human support",
  Q12h = "Personalized financial insights",
  Q12i = "Understanding how the program makes decisions"
)

q12_vars <- names(q12_labels)

# -----------------------------
# 2) Attach the 5-cluster solution
# -----------------------------
cluster_labels <- c(
  "Skeptical support seekers",
  "Cautious guidance seekers",
  "Feature-oriented adopters",
  "AI-resistant independents",
  "AI-enthusiastic guidance seekers"
)

data_cluster_profile_5 <- data_clean_complete %>%
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = 1:5,
      labels = cluster_labels
    )
  )

# -----------------------------
# 3) Function to profile ONE cluster independently
# -----------------------------
profile_one_cluster_q12 <- function(data, cluster_name) {
  
  data %>%
    filter(cluster == cluster_name) %>%
    select(all_of(q12_vars)) %>%
    mutate(across(everything(), as.numeric)) %>%
    pivot_longer(
      cols = everything(),
      names_to = "item",
      values_to = "score"
    ) %>%
    group_by(item) %>%
    summarise(
      n = sum(!is.na(score)),
      mean = round(mean(score, na.rm = TRUE), 2),
      sd = round(sd(score, na.rm = TRUE), 2),
      median = round(median(score, na.rm = TRUE), 2),
      pct_6_7 = round(mean(score %in% c(6, 7), na.rm = TRUE) * 100, 1),
      pct_7 = round(mean(score == 7, na.rm = TRUE) * 100, 1),
      .groups = "drop"
    ) %>%
    mutate(
      label = q12_labels[item],
      cluster = cluster_name
    ) %>%
    select(cluster, item, label, n, mean, sd, median, pct_6_7, pct_7) %>%
    arrange(desc(mean))
}

# -----------------------------
# 4) Create a separate profile for each cluster
# -----------------------------
cluster_1_q12_profile <- profile_one_cluster_q12(
  data_cluster_profile_5,
  "Skeptical support seekers"
)

cluster_2_q12_profile <- profile_one_cluster_q12(
  data_cluster_profile_5,
  "Cautious guidance seekers"
)

cluster_3_q12_profile <- profile_one_cluster_q12(
  data_cluster_profile_5,
  "Feature-oriented adopters"
)

cluster_4_q12_profile <- profile_one_cluster_q12(
  data_cluster_profile_5,
  "AI-resistant independents"
)

cluster_5_q12_profile <- profile_one_cluster_q12(
  data_cluster_profile_5,
  "AI-enthusiastic guidance seekers"
)

# -----------------------------
# 5) View each cluster independently
# -----------------------------
cluster_1_q12_profile
cluster_2_q12_profile
cluster_3_q12_profile
cluster_4_q12_profile
cluster_5_q12_profile
cluster_q12_profiles <- setNames(
  lapply(levels(data_cluster_profile_5$cluster), function(cl) {
    profile_one_cluster_q12(data_cluster_profile_5, cl)
  }),
  levels(data_cluster_profile_5$cluster)
)

# Example:
cluster_q12_profiles[["Skeptical support seekers"]]
cluster_q12_profiles[["AI-resistant independents"]]
bank_data <- data_cluster_profile_5 |>
  mutate(across(Q25a:Q25l, as.numeric))
bank_combinations <- bank_data |>
  mutate(

    # Revolut only
    revolut_only =
      Q25d == 1 &
      rowSums(across(Q25a:Q25c)) == 0 &
      rowSums(across(Q25e:Q25l)) == 0,

    # NLB + Revolut
    nlb_revolut =
      Q25c == 1 & Q25d == 1,

    # Revolut + any other bank except NLB
    revolut_other =
      Q25d == 1 &
      rowSums(across(c(Q25a, Q25b, Q25e:Q25l))) > 0,

    # Revolut + grouped "other banks" (all except NLB)
    revolut_group_other =
      Q25d == 1 &
      rowSums(across(c(Q25a, Q25b, Q25e:Q25l))) > 0
  )
revolut_cluster_table <- bank_combinations |>
  group_by(cluster) |>
  summarise(

    n_cluster = n(),

    revolut_only = sum(revolut_only, na.rm = TRUE),
    nlb_revolut = sum(nlb_revolut, na.rm = TRUE),
    revolut_other = sum(revolut_other, na.rm = TRUE),
    revolut_group_other = sum(revolut_group_other, na.rm = TRUE),

    revolut_only_pct = round(100 * revolut_only / n_cluster, 1),
    nlb_revolut_pct = round(100 * nlb_revolut / n_cluster, 1),
    revolut_other_pct = round(100 * revolut_other / n_cluster, 1),
    revolut_group_other_pct = round(100 * revolut_group_other / n_cluster, 1)

  )

revolut_cluster_table
NA
library(tidyr)

revolut_cluster_table |>
  select(
    cluster,
    revolut_only_pct,
    nlb_revolut_pct,
    revolut_other_pct
  ) |>
  pivot_longer(
    cols = -cluster,
    names_to = "combination",
    values_to = "percent"
  )
NA
bank_data <- data_cluster_profile_5 |>
  mutate(across(Q25a:Q25l, as.numeric))
bank_groups <- bank_data |>
  mutate(

    # Revolut only
    revolut_only =
      Q25d == 1 &
      rowSums(across(c(Q25a, Q25b, Q25c, Q25e:Q25l))) == 0,

    # NLB + Revolut
    nlb_revolut =
      Q25c == 1 & Q25d == 1,

    # OTP + Revolut
    otp_revolut =
      Q25a == 1 & Q25d == 1,

    # Revolut + any other bank except NLB and OTP
    revolut_other =
      Q25d == 1 &
      rowSums(across(c(Q25b, Q25e:Q25l))) > 0
  )
revolut_cluster_summary <- bank_groups |>
  group_by(cluster) |>
  summarise(

    n_cluster = n(),

    revolut_only = sum(revolut_only, na.rm = TRUE),
    nlb_revolut = sum(nlb_revolut, na.rm = TRUE),
    otp_revolut = sum(otp_revolut, na.rm = TRUE),
    revolut_other = sum(revolut_other, na.rm = TRUE),

    revolut_only_pct = round(100 * revolut_only / n_cluster, 1),
    nlb_revolut_pct = round(100 * nlb_revolut / n_cluster, 1),
    otp_revolut_pct = round(100 * otp_revolut / n_cluster, 1),
    revolut_other_pct = round(100 * revolut_other / n_cluster, 1)

  )

revolut_cluster_summary
NA
library(tidyr)

revolut_cluster_summary |>
  select(
    cluster,
    revolut_only_pct,
    nlb_revolut_pct,
    otp_revolut_pct,
    revolut_other_pct
  ) |>
  pivot_longer(
    cols = -cluster,
    names_to = "group",
    values_to = "percent"
  )
NA
library(dplyr)

bank_segments <- data_cluster_profile_5 |>
  mutate(across(Q25a:Q25l, as.numeric)) |>
  mutate(

    segment = case_when(

      Q25c == 1 & Q25d == 0 & Q25a == 0 ~ "NLB only",
      Q25d == 1 & Q25c == 0 & Q25a == 0 ~ "Revolut only",
      Q25a == 1 & Q25c == 0 & Q25d == 0 ~ "OTP only",

      Q25c == 1 & Q25d == 1 & Q25a == 0 ~ "NLB + Revolut",
      Q25c == 1 & Q25a == 1 & Q25d == 0 ~ "NLB + OTP",
      Q25a == 1 & Q25d == 1 & Q25c == 0 ~ "OTP + Revolut",

      Q25a == 1 & Q25c == 1 & Q25d == 1 ~ "NLB + Revolut + OTP",

      TRUE ~ "None of these three"
    )
  )
segment_table <- bank_segments |>
  group_by(cluster, segment) |>
  summarise(n = n(), .groups = "drop") |>
  group_by(cluster) |>
  mutate(
    percent = round(100 * n / sum(n), 1)
  ) |>
  arrange(cluster, desc(percent))

segment_table
conversion_table <- data_cluster_profile_5 |>
  mutate(across(Q25a:Q25l, as.numeric)) |>
  group_by(cluster) |>
  summarise(

    cluster_size = n(),

    revolut_users = sum(Q25d == 1, na.rm = TRUE),
    nlb_users = sum(Q25c == 1, na.rm = TRUE),

    nlb_revolut_users = sum(Q25c == 1 & Q25d == 1, na.rm = TRUE),

    revolut_without_nlb = sum(Q25d == 1 & Q25c == 0, na.rm = TRUE),

    revolut_users_pct = round(100 * revolut_users / cluster_size, 1),

    revolut_without_nlb_pct =
      round(100 * revolut_without_nlb / cluster_size, 1)

  )

conversion_table

##Cluster 3

library(readxl)
library(dplyr)
library(tidyr)
library(tibble)
library(ggplot2)

## 1. Load and clean data ----

raw_sheet <- read_excel(
  "Questionnaire_results_EN.xlsx",
  sheet = "Podatki",
  col_names = FALSE
)

var_names <- raw_sheet |>
  slice(1) |>
  unlist(use.names = FALSE) |>
  as.character()

question_text <- raw_sheet |>
  slice(2) |>
  unlist(use.names = FALSE) |>
  as.character()

data_raw <- raw_sheet |>
  slice(-(1:2))

names(data_raw) <- var_names

data_raw <- data_raw |>
  mutate(respondent_id = row_number()) |>
  relocate(respondent_id)

data_clean <- data_raw |>
  mutate(across(everything(),
                ~ replace(as.character(.), as.character(.) == "-1", NA))) |>
  filter(!is.na(Q22), !is.na(Q23))

data_clean <- data_clean |>
  mutate(
    across(
      Q13a:Q15g,
      ~ as.numeric(replace(., . == "8", NA))
    )
  )

## 2. Rebuild the 5 respondent clusters (same logic as before) ----

cluster_data <- data_clean |>
  select(Q6a, Q6b, Q6d, Q6e, Q6h, Q6i,
         Q8a, Q8b, Q8c, Q8d, Q8e) |>
  mutate(across(everything(), as.numeric))

cluster_data_complete <- cluster_data |>
  drop_na()

pca_cluster <- prcomp(cluster_data_complete, scale. = TRUE)
pca_scores_2 <- as.data.frame(pca_cluster$x[, 1:2])

set.seed(123)
k5_pca2 <- kmeans(pca_scores_2, centers = 5, nstart = 25)

data_clean_complete <- data_clean |>
  filter(
    !is.na(Q6a), !is.na(Q6b), !is.na(Q6d), !is.na(Q6e), !is.na(Q6h), !is.na(Q6i),
    !is.na(Q8a), !is.na(Q8b), !is.na(Q8c), !is.na(Q8d), !is.na(Q8e)
  )

data_cluster <- data_clean_complete |>
  mutate(
    cluster = factor(
      k5_pca2$cluster,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Skeptical support seekers",
        "Cautious guidance seekers",
        "Feature-oriented adopters",   # cluster 3
        "AI-resistant independents",
        "AI-enthusiastic guidance seekers"
      )
    )
  )

## 3. Hard-code banks and perception items (Q13–Q15) ----

# Q13: innovation, Q14: customer support, Q15: reliability
percept_vars <- c(
  "Q13a","Q13b","Q13c","Q13d","Q13e","Q13f","Q13g",
  "Q14a","Q14b","Q14c","Q14d","Q14e","Q14f","Q14g",
  "Q15a","Q15b","Q15c","Q15d","Q15e","Q15f","Q15g"
)

# explicit mapping from column suffix (a–g) to bank name
bank_lookup <- tibble(
  bank_code  = letters[1:7],
  bank_label = c("OTP",
                 "Gorenjska Banka",
                 "NLB",
                 "Revolut",
                 "N26",
                 "Intesa SanPaolo",
                 "UniCredit")
)

# helper table describing each Q13–15 variable
qmeta <- tibble(variable = percept_vars) %>%
  mutate(
    qcode     = substr(variable, 1, 3),     # Q13, Q14, Q15
    bank_code = substr(variable, 4, 4)      # a–g
  ) %>%
  left_join(bank_lookup, by = "bank_code") %>%
  mutate(
    attribute = case_when(
      qcode == "Q13" ~ "innovation",
      qcode == "Q14" ~ "customer_support",
      qcode == "Q15" ~ "reliability",
      TRUE ~ qcode
    )
  )

## 4. Build bank x attribute matrix for cluster 3 ----

cluster3 <- data_cluster %>%
  filter(cluster == "Feature-oriented adopters")

cluster3_percept <- cluster3 %>%
  select(all_of(percept_vars)) %>%
  mutate(across(everything(), as.numeric))

means_c3 <- cluster3_percept %>%
  summarise(across(everything(), ~ mean(.x, na.rm = TRUE)))

means_long <- means_c3 %>%
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "mean_score") %>%
  left_join(qmeta, by = "variable")

bank_attr_mat <- means_long %>%
  group_by(bank_label, attribute) %>%
  summarise(mean_score = mean(mean_score), .groups = "drop") %>%
  pivot_wider(
    id_cols = bank_label,
    names_from = attribute,
    values_from = mean_score
  ) %>%
  as.data.frame()

rownames(bank_attr_mat) <- bank_attr_mat$bank_label
bank_attr_mat$bank_label <- NULL

## 5. PCA for banks (cluster 3) ----

pca_banks_c3 <- prcomp(bank_attr_mat, scale. = TRUE)

scores_c3 <- as.data.frame(pca_banks_c3$x[, 1:2])
scores_c3$bank_label <- rownames(scores_c3)

loadings_c3 <- as.data.frame(pca_banks_c3$rotation[, 1:2])
loadings_c3$attribute <- rownames(loadings_c3)

arrow_scale <- 1.5
loadings_c3 <- loadings_c3 %>%
  mutate(PC1 = PC1 * arrow_scale,
         PC2 = PC2 * arrow_scale)

## 6. Plot: perceptual map of banks – cluster 3 ----

ggplot() +
  geom_point(data = scores_c3,
             aes(x = PC1, y = PC2),
             size = 2.8, colour = "black") +
  geom_text(data = scores_c3,
            aes(x = PC1, y = PC2, label = bank_label),
            vjust = -0.7, size = 3.2) +
  geom_segment(data = loadings_c3,
               aes(x = 0, y = 0, xend = PC1, yend = PC2),
               arrow = arrow(length = unit(0.2, "cm")),
               colour = "grey40") +
  geom_text(data = loadings_c3,
            aes(x = PC1, y = PC2, label = attribute),
            hjust = 0.5, vjust = -0.4, colour = "grey40", size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", colour = "grey75") +
  geom_vline(xintercept = 0, linetype = "dashed", colour = "grey75") +
  coord_equal(xlim = c(min(scores_c3$PC1) - 0.8, max(scores_c3$PC1) + 0.8),
              ylim = c(min(scores_c3$PC2) - 0.8, max(scores_c3$PC2) + 0.8),
              expand = TRUE) +
  labs(
    title = "Perceptual Map of Banks – Cluster 3",
    x = "Overall Digital Banking Performance",
    y = "Customer Support vs. Innovation"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    panel.grid.minor = element_blank()
  )

bank_attr_mat
# loadings for each attribute on PC1 and PC2
load_table <- as.data.frame(pca_banks_c3$rotation[, 1:2])
load_table$attribute <- rownames(load_table)
rownames(load_table) <- NULL

load_table
# bank attribute means we already had:
bank_attr_mat   # rows = banks, cols = innovation, customer_support, reliability

# join with scores on PC2
bank_pc2 <- scores_c3 %>%
  select(bank_label, PC2) %>%
  left_join(
    bank_attr_mat %>%
      tibble::rownames_to_column("bank_label"),
    by = "bank_label"
  )

bank_pc2
NA
bank_pc2 <- scores_c3 %>%
  select(bank_label, PC2) %>%
  left_join(
    bank_attr_mat %>%
      tibble::rownames_to_column("bank_label"),
    by = "bank_label"
  )

bank_pc2
# load_table: columns PC1, PC2, attribute (innovation, customer_support, reliability)
load_table

# 1) put PC2 loadings into a named vector
pc2_load <- load_table$PC2
names(pc2_load) <- load_table$attribute

# 2) compute contribution scores: attribute_mean * PC2 loading
contrib_pc2 <- bank_pc2 %>%
  mutate(
    contrib_customer_support = customer_support * pc2_load["customer_support"],
    contrib_innovation       = innovation       * pc2_load["innovation"],
    contrib_reliability      = reliability      * pc2_load["reliability"]
  )

contrib_pc2
NA
contrib_pc2_long <- contrib_pc2 %>%
  select(bank_label,
         contrib_customer_support,
         contrib_innovation,
         contrib_reliability) %>%
  tidyr::pivot_longer(
    cols = starts_with("contrib_"),
    names_to = "attribute",
    values_to = "contribution"
  ) %>%
  mutate(attribute = gsub("contrib_", "", attribute))

contrib_pc2_long
NA
ggplot(contrib_pc2_long,
       aes(x = attribute, y = contribution, fill = attribute)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ bank_label) +
  theme_minimal() +
  labs(
    title = "Approximate attribute contributions to Dimension 2 (cluster 3)",
    x = "Attribute",
    y = "Contribution to Dim2"
  )

load_table3 <- as.data.frame(pca_banks_c3$rotation[, 1:2])
load_table3$attribute <- rownames(load_table3)
rownames(load_table3) <- NULL

load_table3
NA

Cluster 5

## Cluster 5: bank x attribute matrix ----

cluster5 <- data_cluster %>%
  filter(cluster == "AI-enthusiastic guidance seekers")   # cluster 5 label

cluster5_percept <- cluster5 %>%
  select(all_of(percept_vars)) %>%
  mutate(across(everything(), as.numeric))

means_c5 <- cluster5_percept %>%
  summarise(across(everything(), ~ mean(.x, na.rm = TRUE)))

means_c5_long <- means_c5 %>%
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "mean_score") %>%
  left_join(qmeta, by = "variable")

bank_attr_mat5 <- means_c5_long %>%
  group_by(bank_label, attribute) %>%
  summarise(mean_score = mean(mean_score), .groups = "drop") %>%
  pivot_wider(
    id_cols = bank_label,
    names_from = attribute,
    values_from = mean_score
  ) %>%
  as.data.frame()

rownames(bank_attr_mat5) <- bank_attr_mat5$bank_label
bank_attr_mat5$bank_label <- NULL
## PCA for banks – cluster 5 ----

pca_banks_c5 <- prcomp(bank_attr_mat5, scale. = TRUE)

scores_c5 <- as.data.frame(pca_banks_c5$x[, 1:2])
scores_c5$bank_label <- rownames(scores_c5)

loadings_c5 <- as.data.frame(pca_banks_c5$rotation[, 1:2])
loadings_c5$attribute <- rownames(loadings_c5)

arrow_scale <- 1.5
loadings_c5 <- loadings_c5 %>%
  mutate(PC1 = PC1 * arrow_scale,
         PC2 = PC2 * arrow_scale)

## Plot: perceptual map for cluster 5 ----

ggplot() +
  geom_point(data = scores_c5,
             aes(x = PC1, y = PC2),
             size = 2.8, colour = "black") +
  geom_text(data = scores_c5,
            aes(x = PC1, y = PC2, label = bank_label),
            vjust = -0.7, size = 3.2) +
  geom_segment(data = loadings_c5,
               aes(x = 0, y = 0, xend = PC1, yend = PC2),
               arrow = arrow(length = unit(0.2, "cm")),
               colour = "grey40") +
  geom_text(data = loadings_c5,
            aes(x = PC1, y = PC2, label = attribute),
            hjust = 0.5, vjust = -0.4, colour = "grey40", size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", colour = "grey75") +
  geom_vline(xintercept = 0, linetype = "dashed", colour = "grey75") +
  coord_equal(xlim = c(min(scores_c5$PC1) - 0.8, max(scores_c5$PC1) + 0.8),
              ylim = c(min(scores_c5$PC2) - 0.8, max(scores_c5$PC2) + 0.8),
              expand = TRUE) +
  labs(
    title = "Perceptual Map of Banks – Cluster 5",
    x = "Overall Digital Banking Performance",
    y = "Customer Support vs. Relaibility"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    panel.grid.minor = element_blank()
  )

## Loadings table for cluster 5 ----
load_table5 <- as.data.frame(pca_banks_c5$rotation[, 1:2])
load_table5$attribute <- rownames(load_table5)
rownames(load_table5) <- NULL

# PC2 loadings as named vector
pc2_load5 <- load_table5$PC2
names(pc2_load5) <- load_table5$attribute

# join PC2 scores with attribute means
bank_pc2_5 <- scores_c5 %>%
  select(bank_label, PC2) %>%
  left_join(
    bank_attr_mat5 %>% tibble::rownames_to_column("bank_label"),
    by = "bank_label"
  )

# contribution scores
contrib_pc2_5 <- bank_pc2_5 %>%
  mutate(
    contrib_customer_support = customer_support * pc2_load5["customer_support"],
    contrib_innovation       = innovation       * pc2_load5["innovation"],
    contrib_reliability      = reliability      * pc2_load5["reliability"]
  )

contrib_pc2_5
NA
contrib_pc2_5_long <- contrib_pc2_5 %>%
  select(bank_label,
         contrib_customer_support,
         contrib_innovation,
         contrib_reliability) %>%
  pivot_longer(
    cols = starts_with("contrib_"),
    names_to = "attribute",
    values_to = "contribution"
  ) %>%
  mutate(attribute = gsub("contrib_", "", attribute))

ggplot(contrib_pc2_5_long,
       aes(x = attribute, y = contribution, fill = attribute)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ bank_label) +
  theme_minimal() +
  labs(
    title = "Approximate attribute contributions to Dimension 2 (cluster 5)",
    x = "Attribute",
    y = "Contribution to Dim2"
  )

bank_pc2_5 <- scores_c5 %>%
  select(bank_label, PC2) %>%
  left_join(
    bank_attr_mat5 %>%
      tibble::rownames_to_column("bank_label"),
    by = "bank_label"
  )

bank_pc2_5
NA
# loadings for cluster 5 (PC1 and PC2)
load_table5 <- as.data.frame(pca_banks_c5$rotation[, 1:2])
load_table5$attribute <- rownames(load_table5)
rownames(load_table5) <- NULL

load_table5
## loadings for cluster 5 already in load_table5
# pc2_load5: named vector of PC2 loadings
pc2_load5 <- load_table5$PC2
names(pc2_load5) <- load_table5$attribute

## bank_pc2_5 already created like this:
# bank_pc2_5 <- scores_c5 %>%
#   select(bank_label, PC2) %>%
#   left_join(
#     bank_attr_mat5 %>% tibble::rownames_to_column("bank_label"),
#     by = "bank_label"
#   )

contrib_pc2_5 <- bank_pc2_5 %>%
  mutate(
    contrib_customer_support = customer_support * pc2_load5["customer_support"],
    contrib_innovation       = innovation       * pc2_load5["innovation"],
    contrib_reliability      = reliability      * pc2_load5["reliability"]
  )

contrib_pc2_5
NA

Cluster 2

## Cluster 2: bank x attribute matrix ----

cluster2 <- data_cluster %>%
  filter(cluster == "Cautious guidance seekers")   # cluster 2 label

cluster2_percept <- cluster2 %>%
  select(all_of(percept_vars)) %>%
  mutate(across(everything(), as.numeric))

means_c2 <- cluster2_percept %>%
  summarise(across(everything(), ~ mean(.x, na.rm = TRUE)))

means_c2_long <- means_c2 %>%
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "mean_score") %>%
  left_join(qmeta, by = "variable")

bank_attr_mat2 <- means_c2_long %>%
  group_by(bank_label, attribute) %>%
  summarise(mean_score = mean(mean_score), .groups = "drop") %>%
  pivot_wider(
    id_cols = bank_label,
    names_from = attribute,
    values_from = mean_score
  ) %>%
  as.data.frame()

rownames(bank_attr_mat2) <- bank_attr_mat2$bank_label
bank_attr_mat2$bank_label <- NULL
## PCA for banks – cluster 2 ----

pca_banks_c2 <- prcomp(bank_attr_mat2, scale. = TRUE)

scores_c2 <- as.data.frame(pca_banks_c2$x[, 1:2])
scores_c2$bank_label <- rownames(scores_c2)

loadings_c2 <- as.data.frame(pca_banks_c2$rotation[, 1:2])
loadings_c2$attribute <- rownames(loadings_c2)

arrow_scale <- 1.5
loadings_c2 <- loadings_c2 %>%
  mutate(PC1 = PC1 * arrow_scale,
         PC2 = PC2 * arrow_scale)

## Plot: perceptual map for cluster 2 ----

ggplot() +
  geom_point(data = scores_c2,
             aes(x = PC1, y = PC2),
             size = 2.8, colour = "black") +
  geom_text(data = scores_c2,
            aes(x = PC1, y = PC2, label = bank_label),
            vjust = -0.7, size = 3.2) +
  geom_segment(data = loadings_c2,
               aes(x = 0, y = 0, xend = PC1, yend = PC2),
               arrow = arrow(length = unit(0.2, "cm")),
               colour = "grey40") +
  geom_text(data = loadings_c2,
            aes(x = PC1, y = PC2, label = attribute),
            hjust = 0.5, vjust = -0.4, colour = "grey40", size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", colour = "grey75") +
  geom_vline(xintercept = 0, linetype = "dashed", colour = "grey75") +
  coord_equal(xlim = c(min(scores_c2$PC1) - 0.8, max(scores_c2$PC1) + 0.8),
              ylim = c(min(scores_c2$PC2) - 0.8, max(scores_c2$PC2) + 0.8),
              expand = TRUE) +
  labs(
    title = "Perceptual Map of Banks – Cluster 2",
    x = "Overall Digital Banking Performance",
    y = "Customer Support vs. Reliability"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    panel.grid.minor = element_blank()
  )

bank_pc2_2 <- scores_c2 %>%
  select(bank_label, PC2) %>%
  left_join(
    bank_attr_mat2 %>%
      tibble::rownames_to_column("bank_label"),
    by = "bank_label"
  )

bank_pc2_2
NA
load_table2 <- as.data.frame(pca_banks_c2$rotation[, 1:2])
load_table2$attribute <- rownames(load_table2)
rownames(load_table2) <- NULL

load_table2
NA
pc2_load2 <- load_table2$PC2
names(pc2_load2) <- load_table2$attribute

contrib_pc2_2 <- bank_pc2_2 %>%
  mutate(
    contrib_customer_support = customer_support * pc2_load2["customer_support"],
    contrib_innovation       = innovation       * pc2_load2["innovation"],
    contrib_reliability      = reliability      * pc2_load2["reliability"]
  )

contrib_pc2_2
NA
library(ggplot2)
library(dplyr)
library(tidyr)

## PC2 loadings for cluster 2
pc2_load2 <- load_table2$PC2
names(pc2_load2) <- load_table2$attribute

## Contribution scores table for cluster 2
contrib_pc2_2 <- bank_pc2_2 %>%
  mutate(
    contrib_customer_support = customer_support * pc2_load2["customer_support"],
    contrib_innovation       = innovation       * pc2_load2["innovation"],
    contrib_reliability      = reliability      * pc2_load2["reliability"]
  )

## Long format for plotting
contrib_pc2_2_long <- contrib_pc2_2 %>%
  select(bank_label,
         contrib_customer_support,
         contrib_innovation,
         contrib_reliability) %>%
  pivot_longer(
    cols = starts_with("contrib_"),
    names_to = "attribute",
    values_to = "contribution"
  ) %>%
  mutate(attribute = gsub("contrib_", "", attribute))

## Bar plot
ggplot(contrib_pc2_2_long,
       aes(x = attribute, y = contribution, fill = attribute)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ bank_label) +
  theme_minimal() +
  labs(
    title = "Approximate attribute contributions to Dimension 2 – Cluster 2",
    x = "Attribute",
    y = "Contribution to Dim2"
  )

library(dplyr)
library(purrr)
library(tidyr)

# make sure logical combo vars are numeric for testing
bank_groups_test <- bank_groups |>
  mutate(
    across(
      c(revolut_only, nlb_revolut, otp_revolut, revolut_other),
      ~ as.integer(.)
    )
  )

# helper: chi-square with simulated p-value fallback if expected counts are small
run_cluster_sig_test <- function(data, var_name) {
  tab <- table(data$cluster, data[[var_name]])

  chi <- suppressWarnings(chisq.test(tab))

  if (any(chi$expected < 5)) {
    chi_sim <- chisq.test(tab, simulate.p.value = TRUE, B = 10000)

    tibble(
      group = var_name,
      test = "Chi-square (simulated p-value)",
      statistic = unname(chi$statistic),
      p_value = chi_sim$p.value
    )
  } else {
    tibble(
      group = var_name,
      test = "Chi-square",
      statistic = unname(chi$statistic),
      p_value = chi$p.value
    )
  }
}

# overall significance for each bank-combo across clusters
combo_significance <- bind_rows(
  lapply(
    c("revolut_only", "nlb_revolut", "otp_revolut", "revolut_other"),
    function(x) run_cluster_sig_test(bank_groups_test, x)
  )
) |>
  mutate(p_adj_bh = p.adjust(p_value, method = "BH")) |>
  arrange(p_value)

combo_significance
pairwise_cluster_props <- function(data, var_name) {
  counts <- data |>
    group_by(cluster) |>
    summarise(
      users = sum(.data[[var_name]], na.rm = TRUE),
      n = n(),
      .groups = "drop"
    )

  pw <- pairwise.prop.test(
    x = counts$users,
    n = counts$n,
    p.adjust.method = "BH"
  )

  as.data.frame(as.table(pw$p.value)) |>
    filter(!is.na(Freq)) |>
    rename(
      cluster_1 = Var1,
      cluster_2 = Var2,
      p_adj_bh = Freq
    ) |>
    mutate(group = var_name, .before = 1)
}

pairwise_cluster_props(bank_groups_test, "revolut_only")
pairwise_cluster_props(bank_groups_test, "nlb_revolut")
pairwise_cluster_props(bank_groups_test, "otp_revolut")
pairwise_cluster_props(bank_groups_test, "revolut_other")
segment_tab <- table(bank_segments$cluster, bank_segments$segment)

segment_test <- chisq.test(segment_tab, simulate.p.value = TRUE, B = 10000)
segment_test

    Pearson's Chi-squared test with simulated p-value (based on 10000
    replicates)

data:  segment_tab
X-squared = 47.692, df = NA, p-value = 0.009699
run_segment_sig <- function(data, segment_name) {
  tmp <- data |>
    mutate(in_segment = as.integer(segment == segment_name))

  run_cluster_sig_test(tmp, "in_segment") |>
    mutate(segment = segment_name, .before = 1) |>
    select(segment, everything(), -group)
}

segment_significance <- bind_rows(
  run_segment_sig(bank_segments, "Revolut only"),
  run_segment_sig(bank_segments, "NLB + Revolut"),
  run_segment_sig(bank_segments, "OTP + Revolut")
) |>
  mutate(p_adj_bh = p.adjust(p_value, method = "BH"))

segment_significance
pairwise_segment_props <- function(data, segment_name) {
  counts <- data |>
    mutate(in_segment = as.integer(segment == segment_name)) |>
    group_by(cluster) |>
    summarise(
      users = sum(in_segment, na.rm = TRUE),
      n = n(),
      .groups = "drop"
    )

  pw <- pairwise.prop.test(
    x = counts$users,
    n = counts$n,
    p.adjust.method = "BH"
  )

  as.data.frame(as.table(pw$p.value)) |>
    filter(!is.na(Freq)) |>
    rename(
      cluster_1 = Var1,
      cluster_2 = Var2,
      p_adj_bh = Freq
    ) |>
    mutate(segment = segment_name, .before = 1)
}

pairwise_segment_props(bank_segments, "Revolut only")
pairwise_segment_props(bank_segments, "NLB + Revolut")
pairwise_segment_props(bank_segments, "OTP + Revolut")
cluster_5_wants_needs <- cluster_means_pca2_5_named |>
  filter(cluster == "AI-enthusiastic guidance seekers")

cluster_5_wants_needs
library(dplyr)
library(purrr)
library(tidyr)

# keep only clusters 2, 3, and 5
bank_groups_235 <- bank_groups |>
  filter(cluster %in% c(
    "Cautious guidance seekers",
    "Feature-oriented adopters",
    "AI-enthusiastic guidance seekers"
  )) |>
  mutate(
    cluster = droplevels(cluster),
    across(
      c(revolut_only, nlb_revolut, otp_revolut, revolut_other),
      ~ as.integer(.)
    )
  )
run_cluster_sig_test <- function(data, var_name) {
  tab <- table(data$cluster, data[[var_name]])
  chi <- suppressWarnings(chisq.test(tab))
  
  if (any(chi$expected < 5)) {
    chi_sim <- chisq.test(tab, simulate.p.value = TRUE, B = 10000)
    
    tibble(
      group = var_name,
      test = "Chi-square (simulated p-value)",
      statistic = unname(chi$statistic),
      p_value = chi_sim$p.value
    )
  } else {
    tibble(
      group = var_name,
      test = "Chi-square",
      statistic = unname(chi$statistic),
      p_value = chi$p.value
    )
  }
}

overall_sig_235 <- bind_rows(
  run_cluster_sig_test(bank_groups_235, "revolut_only"),
  run_cluster_sig_test(bank_groups_235, "nlb_revolut"),
  run_cluster_sig_test(bank_groups_235, "otp_revolut"),
  run_cluster_sig_test(bank_groups_235, "revolut_other")
) |>
  mutate(p_adj_bh = p.adjust(p_value, method = "BH")) |>
  arrange(p_value)

overall_sig_235
run_pair_test <- function(data, var_name, cl1, cl2) {
  tmp <- data |>
    filter(cluster %in% c(cl1, cl2)) |>
    mutate(cluster = droplevels(cluster))
  
  counts <- tmp |>
    group_by(cluster) |>
    summarise(
      users = sum(.data[[var_name]], na.rm = TRUE),
      n = n(),
      .groups = "drop"
    )
  
  test <- prop.test(
    x = counts$users,
    n = counts$n,
    correct = FALSE
  )
  
  tibble(
    group = var_name,
    cluster_1 = cl1,
    cluster_2 = cl2,
    users_1 = counts$users[1],
    n_1 = counts$n[1],
    pct_1 = round(100 * counts$users[1] / counts$n[1], 1),
    users_2 = counts$users[2],
    n_2 = counts$n[2],
    pct_2 = round(100 * counts$users[2] / counts$n[2], 1),
    statistic = unname(test$statistic),
    p_value = test$p.value
  )
}

cluster_pairs_235 <- list(
  c("Cautious guidance seekers", "Feature-oriented adopters"),
  c("Cautious guidance seekers", "AI-enthusiastic guidance seekers"),
  c("Feature-oriented adopters", "AI-enthusiastic guidance seekers")
)

bank_vars <- c("revolut_only", "nlb_revolut", "otp_revolut", "revolut_other")

pairwise_sig_235 <- map_dfr(bank_vars, function(v) {
  map_dfr(cluster_pairs_235, function(p) {
    run_pair_test(bank_groups_235, v, p[1], p[2])
  })
}) |>
  group_by(group) |>
  mutate(p_adj_bh = p.adjust(p_value, method = "BH")) |>
  ungroup() |>
  arrange(group, p_value)

pairwise_sig_235
pairwise_sig_235 |>
  filter(p_adj_bh < 0.05)
bank_groups_235 |>
  group_by(cluster) |>
  summarise(
    n_cluster = n(),
    revolut_only_n = sum(revolut_only, na.rm = TRUE),
    revolut_only_pct = round(100 * revolut_only_n / n_cluster, 1),
    nlb_revolut_n = sum(nlb_revolut, na.rm = TRUE),
    nlb_revolut_pct = round(100 * nlb_revolut_n / n_cluster, 1),
    otp_revolut_n = sum(otp_revolut, na.rm = TRUE),
    otp_revolut_pct = round(100 * otp_revolut_n / n_cluster, 1),
    revolut_other_n = sum(revolut_other, na.rm = TRUE),
    revolut_other_pct = round(100 * revolut_other_n / n_cluster, 1)
  )
LS0tDQp0aXRsZTogIk5MQiBQcm9qZWN0IEdyb3VwIDEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHRpYmJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KcmF3X3NoZWV0IDwtIHJlYWRfZXhjZWwoDQogICJRdWVzdGlvbm5haXJlX3Jlc3VsdHNfRU4ueGxzeCIsDQogIHNoZWV0ID0gIlBvZGF0a2kiLA0KICBjb2xfbmFtZXMgPSBGQUxTRQ0KKQ0KDQpyYXdfc2hlZXQNCmBgYA0KDQpgYGB7cn0NCnZhcl9uYW1lcyA8LSByYXdfc2hlZXQgfD4NCiAgc2xpY2UoMSkgfD4NCiAgdW5saXN0KHVzZS5uYW1lcyA9IEZBTFNFKSB8Pg0KICBhcy5jaGFyYWN0ZXIoKQ0KDQpxdWVzdGlvbl90ZXh0IDwtIHJhd19zaGVldCB8Pg0KICBzbGljZSgyKSB8Pg0KICB1bmxpc3QodXNlLm5hbWVzID0gRkFMU0UpIHw+DQogIGFzLmNoYXJhY3RlcigpDQoNCmRhdGFfcmF3IDwtIHJhd19zaGVldCB8Pg0KICBzbGljZSgtKDE6MikpDQoNCm5hbWVzKGRhdGFfcmF3KSA8LSB2YXJfbmFtZXMNCg0KZGF0YV9yYXcgPC0gZGF0YV9yYXcgfD4NCiAgbXV0YXRlKHJlc3BvbmRlbnRfaWQgPSByb3dfbnVtYmVyKCkpIHw+DQogIHJlbG9jYXRlKHJlc3BvbmRlbnRfaWQpDQoNCmdsaW1wc2UoZGF0YV9yYXcpDQpgYGANCg0KYGBge3J9DQpxdWVzdGlvbl9sb29rdXAgPC0gdGliYmxlKA0KICB2YXJpYWJsZSA9IHZhcl9uYW1lcywNCiAgcXVlc3Rpb24gPSBxdWVzdGlvbl90ZXh0DQopDQoNCnF1ZXN0aW9uX2xvb2t1cA0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiA8LSBkYXRhX3JhdyB8Pg0KICBtdXRhdGUoDQogICAgYWNyb3NzKA0KICAgICAgZXZlcnl0aGluZygpLA0KICAgICAgfiByZXBsYWNlKGFzLmNoYXJhY3RlciguKSwgYXMuY2hhcmFjdGVyKC4pID09ICItMSIsIE5BKQ0KICAgICkNCiAgKQ0KDQpnbGltcHNlKGRhdGFfY2xlYW4pDQpgYGANCg0KYGBge3J9DQppZHNfcmVtb3ZlZCA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcihpcy5uYShRMjIpIHwgaXMubmEoUTIzKSkgfD4NCiAgcHVsbChyZXNwb25kZW50X2lkKQ0KDQppZHNfcmVtb3ZlZA0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcighaXMubmEoUTIyKSwgIWlzLm5hKFEyMykpDQoNCm5yb3coZGF0YV9yYXcpDQpucm93KGRhdGFfY2xlYW4pDQpgYGANCg0KYGBge3J9DQptaXNzaW5nX3N1bW1hcnkgPC0gZGF0YV9jbGVhbiB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBzdW0oaXMubmEoLikpKSkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJuX21pc3NpbmciDQogICkgfD4NCiAgYXJyYW5nZShkZXNjKG5fbWlzc2luZykpDQoNCm1pc3Npbmdfc3VtbWFyeQ0KYGBgDQpgYGB7cn0NCnF1ZXN0aW9uX2xvb2t1cCB8PiANCiAgZmlsdGVyKGdyZXBsKCJRMTN8UTE0fFExNSIsIHZhcmlhYmxlKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2xlYW4gfD4NCiAgc2VsZWN0KFExM2E6UTE1ZykgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gcGFzdGUoc29ydCh1bmlxdWUoLikpLCBjb2xsYXBzZSA9ICIsICIpKSkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJ2YWx1ZXMiDQogICkNCmBgYA0KYGBge3J9DQpkYXRhX2NsZWFuIDwtIGRhdGFfY2xlYW4gfD4NCiAgbXV0YXRlKA0KICAgIGFjcm9zcygNCiAgICAgIFExM2E6UTE1ZywNCiAgICAgIH4gYXMubnVtZXJpYyhyZXBsYWNlKC4sIC4gPT0gIjgiLCBOQSkpDQogICAgKQ0KICApDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsZWFuIHw+DQogIHNlbGVjdChRMTNhOlExNWcpIHw+DQogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+IHBhc3RlKHNvcnQodW5pcXVlKC4pKSwgY29sbGFwc2UgPSAiLCAiKSkpIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gZXZlcnl0aGluZygpLA0KICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICB2YWx1ZXNfdG8gPSAidmFsdWVzIg0KICApDQpgYGANCmBgYHtyfQ0KYmFua19tZWFucyA8LSB0aWJibGUoDQogIGJhbmsgPSBjKCJPVFAiLCAiR29yZW5qc2thIEJhbmthIiwgIk5MQiIsICJSZXZvbHV0IiwgIk4yNiIsICJJbnRlc2EgU2FuUGFvbG8iLCAiVW5pQ3JlZGl0IiksDQogIGlubm92YXRpb24gPSBjKA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNhLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNiLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNjLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNkLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNmLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTNnLCBuYS5ybSA9IFRSVUUpDQogICksDQogIGN1c3RvbWVyX3N1cHBvcnQgPSBjKA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRhLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRiLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRjLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRkLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRmLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTRnLCBuYS5ybSA9IFRSVUUpDQogICksDQogIHJlbGlhYmlsaXR5ID0gYygNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1YSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1YiwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1YywgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1ZCwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1ZiwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2xlYW4kUTE1ZywgbmEucm0gPSBUUlVFKQ0KICApDQopDQoNCmJhbmtfbWVhbnMNCmBgYA0KDQpgYGB7cn0NCnBjYV9yZXN1bHQgPC0gcHJjb21wKA0KICBiYW5rX21lYW5zWywgYygiaW5ub3ZhdGlvbiIsICJjdXN0b21lcl9zdXBwb3J0IiwgInJlbGlhYmlsaXR5IildLA0KICBzY2FsZS4gPSBUUlVFDQopDQoNCnBjYV9yZXN1bHQNCmBgYA0KDQpgYGB7cn0NCmJhbmtfY29vcmRpbmF0ZXMgPC0gYXMuZGF0YS5mcmFtZShwY2FfcmVzdWx0JHgpDQpiYW5rX2Nvb3JkaW5hdGVzJGJhbmsgPC0gYmFua19tZWFucyRiYW5rDQoNCmJhbmtfY29vcmRpbmF0ZXMNCmBgYA0KDQpgYGB7cn0NCnBsb3QoDQogIGJhbmtfY29vcmRpbmF0ZXMkUEMxLA0KICBiYW5rX2Nvb3JkaW5hdGVzJFBDMiwNCiAgeGxhYiA9ICJQQzEiLA0KICB5bGFiID0gIlBDMiIsDQogIG1haW4gPSAiUGVyY2VwdGlvbiBNYXAgb2YgQmFua3MiLA0KICBwY2ggPSAxOQ0KKQ0KDQp0ZXh0KA0KICBiYW5rX2Nvb3JkaW5hdGVzJFBDMSwNCiAgYmFua19jb29yZGluYXRlcyRQQzIsDQogIGxhYmVscyA9IGJhbmtfY29vcmRpbmF0ZXMkYmFuaywNCiAgcG9zID0gMw0KKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KZ2dwbG90KGJhbmtfY29vcmRpbmF0ZXMsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGJhbmspKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KHZqdXN0ID0gLTAuNykgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlcmNlcHRpb24gTWFwIG9mIEJhbmtzIiwNCiAgICB4ID0gIkRpbWVuc2lvbiAxIiwNCiAgICB5ID0gIkRpbWVuc2lvbiAyIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCmBgYHtyfQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KYGBgDQpgYGB7cn0NCm1hdCA8LSBiYW5rX21lYW5zIHw+DQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJiYW5rIikgfD4NCiAgYXMubWF0cml4KCkNCg0KcGNhX2JhbmsgPC0gRmFjdG9NaW5lUjo6UENBKG1hdCwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRkFMU0UpDQoNCmZhY3RvZXh0cmE6OmZ2aXpfcGNhX2luZCgNCiAgcGNhX2JhbmssDQogIHJlcGVsID0gVFJVRQ0KKSArDQogIGdncGxvdDI6OmdndGl0bGUoIlBlcmNlcHR1YWwgbWFwIG9mIGJhbmtzIChRMTPigJNRMTUpIikNCmBgYA0KYGBge3J9DQpmYWN0b2V4dHJhOjpmdml6X3BjYV9iaXBsb3QoDQogIHBjYV9iYW5rLA0KICByZXBlbCA9IFRSVUUsDQogIGNvbC52YXIgPSAiZ3JheTMwIg0KKSArDQogIGdncGxvdDI6OmdndGl0bGUoIlBlcmNlcHR1YWwgbWFwIG9mIGJhbmtzIHdpdGggZGltZW5zaW9ucyAoUTEz4oCTUTE1KSIpDQpgYGANCmBgYHtyfQ0KZmFjdG9leHRyYTo6ZnZpel9wY2FfYmlwbG90KA0KICBwY2FfYmFuaywNCiAgcmVwZWwgPSBUUlVFLA0KICBjb2wudmFyID0gImdyYXkzNSIsDQogIGNvbC5pbmQgPSAic3RlZWxibHVlIiwNCiAgcG9pbnRzaXplID0gMw0KKSArDQogIGdncGxvdDI6OmdndGl0bGUoIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIikgKw0KICBnZ3Bsb3QyOjp4bGFiKCJPdmVyYWxsIERpZ2l0YWwgQmFua2luZyBQZXJmb3JtYW5jZSIpICsNCiAgZ2dwbG90Mjo6eWxhYigiQ3VzdG9tZXIgU3VwcG9ydCB2cyBJbm5vdmF0aW9uIikgKw0KICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkgKw0KICBnZ3Bsb3QyOjp0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikNCiAgKQ0KYGBgDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfcGNhX2JpcGxvdCgNCiAgcGNhX2JhbmssDQogIHJlcGVsID0gVFJVRSwNCiAgY29sLnZhciA9ICJncmF5MzAiDQopICsNCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiUGVyY2VwdHVhbCBtYXAgb2YgYmFua3Mgd2l0aCBkaW1lbnNpb25zIChRMTPigJNRMTUpIikgKw0KICBnZ3Bsb3QyOjp4bGFiKCJEaW0xICg5MC4xJSk6IE92ZXJhbGwgRGlnaXRhbCBCYW5raW5nIFBlcmZvcm1hbmNlIikgKw0KICBnZ3Bsb3QyOjp5bGFiKCJEaW0yICg4LjUlKTogQ3VzdG9tZXIgU3VwcG9ydCB2cyBJbm5vdmF0aW9uIikNCmBgYA0KYGBge3J9DQpkYXRhX2NsZWFuIHw+DQogIHNlbGVjdChRNmEsIFE2YiwgUTZkLCBRNmUsIFE2aCwgUTZpLCBROGEsIFE4YiwgUThjLCBROGQsIFE4ZSkgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gcGFzdGUoc29ydCh1bmlxdWUoLikpLCBjb2xsYXBzZSA9ICIsICIpKSkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJ2YWx1ZXMiDQogICkNCmBgYA0KYGBge3J9DQpjbHVzdGVyX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBzZWxlY3QoUTZhLCBRNmIsIFE2ZCwgUTZlLCBRNmgsIFE2aSwgUThhLCBROGIsIFE4YywgUThkLCBROGUpIHw+DQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5udW1lcmljKSkNCg0KZ2xpbXBzZShjbHVzdGVyX2RhdGEpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX2RhdGEgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gc3VtKGlzLm5hKC4pKSkpIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gZXZlcnl0aGluZygpLA0KICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICB2YWx1ZXNfdG8gPSAibl9taXNzaW5nIg0KICApDQpgYGANCmBgYHtyfQ0KY2x1c3Rlcl9kYXRhX2NvbXBsZXRlIDwtIGNsdXN0ZXJfZGF0YSB8Pg0KICB0aWR5cjo6ZHJvcF9uYSgpDQoNCm5yb3coY2x1c3Rlcl9kYXRhKQ0KbnJvdyhjbHVzdGVyX2RhdGFfY29tcGxldGUpDQpgYGANCmBgYHtyfQ0KY2x1c3Rlcl9zY2FsZWQgPC0gc2NhbGUoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlKQ0KDQpjbHVzdGVyX3NjYWxlZA0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoZmFjdG9leHRyYSkNCg0KZnZpel9uYmNsdXN0KGNsdXN0ZXJfc2NhbGVkLCBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKQ0KYGBgDQpgYGB7cn0NCmZ2aXpfbmJjbHVzdChjbHVzdGVyX3NjYWxlZCwga21lYW5zLCBtZXRob2QgPSAic2lsaG91ZXR0ZSIpDQpgYGANCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiTmJDbHVzdCIpDQoNCmxpYnJhcnkoTmJDbHVzdCkNCg0KbmIgPC0gTmJDbHVzdCgNCiAgZGF0YSA9IGNsdXN0ZXJfc2NhbGVkLA0KICBkaXN0YW5jZSA9ICJldWNsaWRlYW4iLA0KICBtaW4ubmMgPSAyLA0KICBtYXgubmMgPSA2LA0KICBtZXRob2QgPSAia21lYW5zIg0KKQ0KYGBgDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCg0KazIgPC0ga21lYW5zKGNsdXN0ZXJfc2NhbGVkLCBjZW50ZXJzID0gMiwgbnN0YXJ0ID0gMjUpDQoNCmsyDQpgYGANCmBgYHtyfQ0KY2x1c3Rlcl9wcm9maWxlIDwtIGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSB8Pg0KICBtdXRhdGUoY2x1c3RlciA9IGZhY3RvcihrMiRjbHVzdGVyKSkNCg0KY2x1c3Rlcl9wcm9maWxlDQpgYGANCmBgYHtyfQ0KY2x1c3Rlcl9tZWFucyA8LSBjbHVzdGVyX3Byb2ZpbGUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pKQ0KDQpjbHVzdGVyX21lYW5zDQpgYGANCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuc19sb25nIDwtIGNsdXN0ZXJfbWVhbnMgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gIm1lYW5fc2NvcmUiDQogICkNCg0KZ2dwbG90KGNsdXN0ZXJfbWVhbnNfbG9uZywgYWVzKHggPSB2YXJpYWJsZSwgeSA9IG1lYW5fc2NvcmUsIGdyb3VwID0gY2x1c3RlciwgY29sb3IgPSBjbHVzdGVyKSkgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2x1c3RlciBQcm9maWxlcyIsDQogICAgeCA9ICJWYXJpYWJsZXMiLA0KICAgIHkgPSAiTWVhbiBzY29yZSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfY2x1c3RlcigNCiAgazIsDQogIGRhdGEgPSBjbHVzdGVyX3NjYWxlZCwNCiAgZWxsaXBzZS50eXBlID0gIm5vcm0iLA0KICByZXBlbCA9IFRSVUUsDQogIHNob3cuY2x1c3QuY2VudCA9IFRSVUUNCikNCmBgYA0KYGBge3J9DQpmYWN0b2V4dHJhOjpmdml6X2NsdXN0ZXIoDQogIGsyLA0KICBkYXRhID0gY2x1c3Rlcl9zY2FsZWQsDQogIGdlb20gPSAicG9pbnQiLA0KICBlbGxpcHNlLnR5cGUgPSAibm9ybSIsDQogIHNob3cuY2x1c3QuY2VudCA9IFRSVUUNCikNCmBgYA0KYGBge3J9DQpjb3IoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlKQ0KYGBgDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiaG9wa2lucyIpDQpsaWJyYXJ5KGhvcGtpbnMpDQpgYGANCmBgYHtyfQ0KaG9wa2lucyhjbHVzdGVyX2RhdGFfY29tcGxldGUpDQpgYGANCg0KYGBge3J9DQpoYyA8LSBoY2x1c3QoZGlzdChjbHVzdGVyX3NjYWxlZCksIG1ldGhvZCA9ICJ3YXJkLkQyIikNCmBgYA0KYGBge3J9DQpwbG90KGhjLCBsYWJlbHMgPSBGQUxTRSwgaGFuZyA9IC0xLCBtYWluID0gIkRlbmRyb2dyYW0iKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShhb3YoUTZhIH4gY2x1c3RlciwgZGF0YSA9IGNsdXN0ZXJfcHJvZmlsZSkpDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KGFvdihROGEgfiBjbHVzdGVyLCBkYXRhID0gY2x1c3Rlcl9wcm9maWxlKSkNCmBgYA0KDQpgYGB7cn0NCmFub3ZhX3Jlc3VsdHMgPC0gbGFwcGx5KG5hbWVzKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSksIGZ1bmN0aW9uKHZhcikgew0KICBtb2RlbCA8LSBhb3YoYXMuZm9ybXVsYShwYXN0ZSh2YXIsICJ+IGNsdXN0ZXIiKSksIGRhdGEgPSBjbHVzdGVyX3Byb2ZpbGUpDQogIGRhdGEuZnJhbWUoDQogICAgdmFyaWFibGUgPSB2YXIsDQogICAgcF92YWx1ZSA9IHN1bW1hcnkobW9kZWwpW1sxXV1bWyJQcig+RikiXV1bMV0NCiAgKQ0KfSkNCg0KYW5vdmFfcmVzdWx0cyA8LSBkby5jYWxsKHJiaW5kLCBhbm92YV9yZXN1bHRzKQ0KDQphbm92YV9yZXN1bHRzDQpgYGANCg0KDQozIGdyb3VwcyBub3cgISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KDQprMyA8LSBrbWVhbnMoY2x1c3Rlcl9zY2FsZWQsIGNlbnRlcnMgPSAzLCBuc3RhcnQgPSAyNSkNCg0KazMNCmBgYA0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCg0KazQgPC0ga21lYW5zKGNsdXN0ZXJfc2NhbGVkLCBjZW50ZXJzID0gNCwgbnN0YXJ0ID0gMjUpDQoNCms0DQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3Byb2ZpbGVfNCA8LSBjbHVzdGVyX2RhdGFfY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazQkY2x1c3RlcikpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX21lYW5zXzQgPC0gY2x1c3Rlcl9wcm9maWxlXzQgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pKQ0KDQpjbHVzdGVyX21lYW5zXzQNCmBgYA0KDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfY2x1c3RlcigNCiAgazQsDQogIGRhdGEgPSBjbHVzdGVyX3NjYWxlZCwNCiAgZ2VvbSA9ICJwb2ludCIsDQogIGVsbGlwc2UudHlwZSA9ICJub25lIiwNCiAgc2hvdy5jbHVzdC5jZW50ID0gVFJVRQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9zaXplc180IDwtIGRhdGEuZnJhbWUodGFibGUoazQkY2x1c3RlcikpDQpjbHVzdGVyX3NpemVzXzQkcGVyY2VudCA8LSByb3VuZCgxMDAgKiBjbHVzdGVyX3NpemVzXzQkRnJlcSAvIHN1bShjbHVzdGVyX3NpemVzXzQkRnJlcSksIDEpDQoNCmNsdXN0ZXJfc2l6ZXNfNA0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuc180X2xvbmcgPC0gY2x1c3Rlcl9tZWFuc180IHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIg0KICApDQoNCmdncGxvdCgNCiAgY2x1c3Rlcl9tZWFuc180X2xvbmcsDQogIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBtZWFuX3Njb3JlLCBncm91cCA9IGNsdXN0ZXIsIGNvbG9yID0gY2x1c3RlcikNCikgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2x1c3RlciBQcm9maWxlcyAoNC1DbHVzdGVyIFNvbHV0aW9uKSIsDQogICAgeCA9ICJWYXJpYWJsZXMiLA0KICAgIHkgPSAiTWVhbiBzY29yZSIsDQogICAgY29sb3IgPSAiQ2x1c3RlciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KcGNhX2NsdXN0ZXIgPC0gcHJjb21wKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSwgc2NhbGUuID0gVFJVRSkNCg0Kc3VtbWFyeShwY2FfY2x1c3RlcikNCmBgYA0KDQpgYGB7cn0NCnJvdW5kKHBjYV9jbHVzdGVyJHJvdGF0aW9uWywgMTozXSwgMykNCmBgYA0KDQpgYGB7cn0NCnBjYV9zY29yZXNfMiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyJHhbLCAxOjJdKQ0KDQpoZWFkKHBjYV9zY29yZXNfMikNCmBgYA0KDQpgYGB7cn0NCmZ2aXpfbmJjbHVzdChwY2Ffc2NvcmVzXzIsIGttZWFucywgbWV0aG9kID0gIndzcyIpDQpgYGANCg0KYGBge3J9DQpmdml6X25iY2x1c3QocGNhX3Njb3Jlc18yLCBrbWVhbnMsIG1ldGhvZCA9ICJzaWxob3VldHRlIikNCmBgYA0KDQpgYGB7cn0NCm5iX3BjYTIgPC0gTmJDbHVzdCgNCiAgZGF0YSA9IHBjYV9zY29yZXNfMiwNCiAgZGlzdGFuY2UgPSAiZXVjbGlkZWFuIiwNCiAgbWluLm5jID0gMiwNCiAgbWF4Lm5jID0gNiwNCiAgbWV0aG9kID0gImttZWFucyINCikNCmBgYA0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCg0KazRfcGNhMiA8LSBrbWVhbnMocGNhX3Njb3Jlc18yLCBjZW50ZXJzID0gNCwgbnN0YXJ0ID0gMjUpDQoNCms0X3BjYTINCmBgYA0KDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfY2x1c3RlcigNCiAgazRfcGNhMiwNCiAgZGF0YSA9IHBjYV9zY29yZXNfMiwNCiAgZ2VvbSA9ICJwb2ludCIsDQogIGVsbGlwc2UudHlwZSA9ICJub25lIiwNCiAgc2hvdy5jbHVzdC5jZW50ID0gVFJVRQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9wcm9maWxlX3BjYTQgPC0gY2x1c3Rlcl9kYXRhX2NvbXBsZXRlIHw+DQogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGs0X3BjYTIkY2x1c3RlcikpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX21lYW5zX3BjYTQgPC0gY2x1c3Rlcl9wcm9maWxlX3BjYTQgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pKQ0KDQpjbHVzdGVyX21lYW5zX3BjYTQNCmBgYA0KDQpgYGB7cn0NCnBjYV9wbG90X2RhdGEgPC0gcGNhX3Njb3Jlc18yIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazRfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkFJIHNrZXB0aWNzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCmdncGxvdChwY2FfcGxvdF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBjbHVzdGVyLCBzaGFwZSA9IGNsdXN0ZXIpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNSwgYWxwaGEgPSAwLjgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJQQ0EtYmFzZWQgNC1jbHVzdGVyIHNvbHV0aW9uIiwNCiAgICB4ID0gIlBDMSIsDQogICAgeSA9ICJQQzIiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiLA0KICAgIHNoYXBlID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfbWVhbnNfcGNhNF9uYW1lZCA8LSBjbHVzdGVyX21lYW5zX3BjYTQgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkFJIHNrZXB0aWNzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCmNsdXN0ZXJfbWVhbnNfcGNhNF9sb25nIDwtIGNsdXN0ZXJfbWVhbnNfcGNhNF9uYW1lZCB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IC1jbHVzdGVyLA0KICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICB2YWx1ZXNfdG8gPSAibWVhbl9zY29yZSINCiAgKQ0KDQpnZ3Bsb3QoDQogIGNsdXN0ZXJfbWVhbnNfcGNhNF9sb25nLA0KICBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gbWVhbl9zY29yZSwgZ3JvdXAgPSBjbHVzdGVyLCBjb2xvciA9IGNsdXN0ZXIpDQopICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNsdXN0ZXIgUHJvZmlsZXMgKFBDQS1iYXNlZCA0LUNsdXN0ZXIgU29sdXRpb24pIiwNCiAgICB4ID0gIlZhcmlhYmxlcyIsDQogICAgeSA9ICJNZWFuIHNjb3JlIiwNCiAgICBjb2xvciA9ICJDbHVzdGVyIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpjb3JfbWF0cml4IDwtIGNvcihjbHVzdGVyX2RhdGFfY29tcGxldGUpDQoNCnJvdW5kKGNvcl9tYXRyaXgsIDMpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGNvcnJwbG90KQ0KDQpjb3JycGxvdCgNCiAgY29yKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSksDQogIG1ldGhvZCA9ICJjb2xvciIsDQogIHR5cGUgPSAidXBwZXIiLA0KICB0bC5jb2wgPSAiYmxhY2siLA0KICB0bC5zcnQgPSA0NQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KcGNhX3ZhcmlhbmNlIDwtIGRhdGEuZnJhbWUoDQogIENvbXBvbmVudCA9IHBhc3RlMCgiUEMiLCAxOmxlbmd0aChwY2FfY2x1c3RlciRzZGV2KSksDQogIEVpZ2VudmFsdWUgPSBwY2FfY2x1c3RlciRzZGV2XjIsDQogIFByb3BvcnRpb25fVmFyaWFuY2UgPSAocGNhX2NsdXN0ZXIkc2Rldl4yKSAvIHN1bShwY2FfY2x1c3RlciRzZGV2XjIpLA0KICBDdW11bGF0aXZlX1ZhcmlhbmNlID0gY3Vtc3VtKChwY2FfY2x1c3RlciRzZGV2XjIpIC8gc3VtKHBjYV9jbHVzdGVyJHNkZXZeMikpDQopDQoNCnBjYV92YXJpYW5jZSRFaWdlbnZhbHVlIDwtIHJvdW5kKHBjYV92YXJpYW5jZSRFaWdlbnZhbHVlLCAzKQ0KcGNhX3ZhcmlhbmNlJFByb3BvcnRpb25fVmFyaWFuY2UgPC0gcm91bmQocGNhX3ZhcmlhbmNlJFByb3BvcnRpb25fVmFyaWFuY2UsIDMpDQpwY2FfdmFyaWFuY2UkQ3VtdWxhdGl2ZV9WYXJpYW5jZSA8LSByb3VuZChwY2FfdmFyaWFuY2UkQ3VtdWxhdGl2ZV9WYXJpYW5jZSwgMykNCg0KcGNhX3ZhcmlhbmNlDQpgYGANCg0KYGBge3J9DQpwY2FfbG9hZGluZ3MgPC0gYXMuZGF0YS5mcmFtZShwY2FfY2x1c3RlciRyb3RhdGlvblssIDE6M10pDQoNCnBjYV9sb2FkaW5ncyRWYXJpYWJsZSA8LSByb3duYW1lcyhwY2FfbG9hZGluZ3MpDQpyb3duYW1lcyhwY2FfbG9hZGluZ3MpIDwtIE5VTEwNCg0KcGNhX2xvYWRpbmdzIDwtIHBjYV9sb2FkaW5nc1ssIGMoIlZhcmlhYmxlIiwgIlBDMSIsICJQQzIiLCAiUEMzIildDQoNCnBjYV9sb2FkaW5ncyRQQzEgPC0gcm91bmQocGNhX2xvYWRpbmdzJFBDMSwgMykNCnBjYV9sb2FkaW5ncyRQQzIgPC0gcm91bmQocGNhX2xvYWRpbmdzJFBDMiwgMykNCnBjYV9sb2FkaW5ncyRQQzMgPC0gcm91bmQocGNhX2xvYWRpbmdzJFBDMywgMykNCg0KcGNhX2xvYWRpbmdzDQpgYGANCg0KYGBge3J9DQpob3BraW5zKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSkNCmBgYA0KDQpgYGB7cn0NCmRpc3RhbmNlX21hdHJpeCA8LSBkaXN0KGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQoNCmRpc3RhbmNlX21hdHJpeA0KYGBgDQoNCmBgYHtyfQ0KZGlzdGFuY2VfbWF0cml4X3RhYmxlIDwtIGFzLm1hdHJpeChkaXN0YW5jZV9tYXRyaXgpDQoNCmRpc3RhbmNlX21hdHJpeF90YWJsZVsxOjEwLCAxOjEwXQ0KYGBgDQoNCmBgYHtyfQ0KaGMgPC0gaGNsdXN0KGRpc3QoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlKSwgbWV0aG9kID0gIndhcmQuRDIiKQ0KDQpwbG90KGhjLCBsYWJlbHMgPSBGQUxTRSwgaGFuZyA9IC0xLCBtYWluID0gIkRlbmRyb2dyYW0iKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9zaXplc19wY2E0IDwtIGRhdGEuZnJhbWUodGFibGUoazRfcGNhMiRjbHVzdGVyKSkNCmNsdXN0ZXJfc2l6ZXNfcGNhNCRQZXJjZW50IDwtIHJvdW5kKA0KICAxMDAgKiBjbHVzdGVyX3NpemVzX3BjYTQkRnJlcSAvIHN1bShjbHVzdGVyX3NpemVzX3BjYTQkRnJlcSksDQogIDENCikNCg0KbmFtZXMoY2x1c3Rlcl9zaXplc19wY2E0KSA8LSBjKCJDbHVzdGVyIiwgIlNpemUiLCAiUGVyY2VudCIpDQoNCmNsdXN0ZXJfc2l6ZXNfcGNhNA0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9zaXplc19wY2E0IDwtIGRhdGEuZnJhbWUodGFibGUoazRfcGNhMiRjbHVzdGVyKSkNCmNsdXN0ZXJfc2l6ZXNfcGNhNCRQZXJjZW50IDwtIHJvdW5kKA0KICAxMDAgKiBjbHVzdGVyX3NpemVzX3BjYTQkRnJlcSAvIHN1bShjbHVzdGVyX3NpemVzX3BjYTQkRnJlcSksDQogIDENCikNCg0KY2x1c3Rlcl9zaXplc19wY2E0JENsdXN0ZXJfTmFtZSA8LSBjKA0KICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICJBSSBza2VwdGljcyIsDQogICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIg0KKQ0KDQpjbHVzdGVyX3NpemVzX3BjYTQgPC0gY2x1c3Rlcl9zaXplc19wY2E0WywgYygiVmFyMSIsICJDbHVzdGVyX05hbWUiLCAiRnJlcSIsICJQZXJjZW50IildDQpuYW1lcyhjbHVzdGVyX3NpemVzX3BjYTQpIDwtIGMoIkNsdXN0ZXIiLCAiQ2x1c3Rlcl9OYW1lIiwgIlNpemUiLCAiUGVyY2VudCIpDQoNCmNsdXN0ZXJfc2l6ZXNfcGNhNA0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuX3RhYmxlIDwtIGNsdXN0ZXJfbWVhbnNfcGNhNCB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsMiwzLDQpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiQUkgc2tlcHRpY3MiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyINCiAgICAgICkNCiAgICApDQogICkNCg0KY2x1c3Rlcl9tZWFuX3RhYmxlDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QocGNhX3Bsb3RfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gY2x1c3Rlciwgc2hhcGUgPSBjbHVzdGVyKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyLjUsIGFscGhhID0gMC44KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ3VzdG9tZXIgU2VnbWVudGF0aW9uIEJhc2VkIG9uIFBDQSBDbHVzdGVyaW5nIiwNCiAgICB4ID0gIkludGVyZXN0IGluIEFJIGJhbmtpbmcgZmVhdHVyZXMgKFBDMSkiLA0KICAgIHkgPSAiTmVlZCBmb3IgZmluYW5jaWFsIGd1aWRhbmNlIChQQzIpIiwNCiAgICBjb2xvciA9ICJDbHVzdGVyIiwNCiAgICBzaGFwZSA9ICJDbHVzdGVyIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQoNCms1X3BjYTIgPC0ga21lYW5zKHBjYV9zY29yZXNfMiwgY2VudGVycyA9IDUsIG5zdGFydCA9IDI1KQ0KDQprNV9wY2EyDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3Byb2ZpbGVfcGNhNSA8LSBjbHVzdGVyX2RhdGFfY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazVfcGNhMiRjbHVzdGVyKSkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfbWVhbnNfcGNhNSA8LSBjbHVzdGVyX3Byb2ZpbGVfcGNhNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhNQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuc19wY2E1X25hbWVkIDwtIGNsdXN0ZXJfbWVhbnNfcGNhNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCmNsdXN0ZXJfbWVhbnNfcGNhNV9sb25nIDwtIGNsdXN0ZXJfbWVhbnNfcGNhNV9uYW1lZCB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IC1jbHVzdGVyLA0KICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICB2YWx1ZXNfdG8gPSAibWVhbl9zY29yZSINCiAgKQ0KDQpnZ3Bsb3QoDQogIGNsdXN0ZXJfbWVhbnNfcGNhNV9sb25nLA0KICBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gbWVhbl9zY29yZSwgZ3JvdXAgPSBjbHVzdGVyLCBjb2xvciA9IGNsdXN0ZXIpDQopICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNsdXN0ZXIgUHJvZmlsZXMgKFBDQS1iYXNlZCA1LUNsdXN0ZXIgU29sdXRpb24pIiwNCiAgICB4ID0gIlZhcmlhYmxlcyIsDQogICAgeSA9ICJNZWFuIHNjb3JlIiwNCiAgICBjb2xvciA9ICJDbHVzdGVyIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3NpemVzX3BjYTUgPC0gZGF0YS5mcmFtZSh0YWJsZShrNV9wY2EyJGNsdXN0ZXIpKQ0KY2x1c3Rlcl9zaXplc19wY2E1JFBlcmNlbnQgPC0gcm91bmQoDQogIDEwMCAqIGNsdXN0ZXJfc2l6ZXNfcGNhNSRGcmVxIC8gc3VtKGNsdXN0ZXJfc2l6ZXNfcGNhNSRGcmVxKSwNCiAgMQ0KKQ0KDQpjbHVzdGVyX3NpemVzX3BjYTUkQ2x1c3Rlcl9OYW1lIDwtIGMoDQogICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KKQ0KDQpjbHVzdGVyX3NpemVzX3BjYTUgPC0gY2x1c3Rlcl9zaXplc19wY2E1WywgYygiVmFyMSIsICJDbHVzdGVyX05hbWUiLCAiRnJlcSIsICJQZXJjZW50IildDQpuYW1lcyhjbHVzdGVyX3NpemVzX3BjYTUpIDwtIGMoIkNsdXN0ZXIiLCAiQ2x1c3Rlcl9OYW1lIiwgIlNpemUiLCAiUGVyY2VudCIpDQoNCmNsdXN0ZXJfc2l6ZXNfcGNhNQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9wcm9maWxlX3BjYTUgPC0gY2x1c3Rlcl9kYXRhX2NvbXBsZXRlIHw+DQogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGs1X3BjYTIkY2x1c3RlcikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhNSA8LSBjbHVzdGVyX3Byb2ZpbGVfcGNhNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbl90YWJsZV9wY2E1IDwtIGNsdXN0ZXJfbWVhbnNfcGNhNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCmNsdXN0ZXJfbWVhbl90YWJsZV9wY2E1DQpgYGANCg0KYGBge3J9DQpwY2FfcGxvdF9kYXRhXzUgPC0gcGNhX3Njb3Jlc18yIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKQ0KDQpnZ3Bsb3QocGNhX3Bsb3RfZGF0YV81LCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBjbHVzdGVyLCBzaGFwZSA9IGNsdXN0ZXIpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNSwgYWxwaGEgPSAwLjgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJQQ0EtYmFzZWQgNS1DbHVzdGVyIFNvbHV0aW9uIiwNCiAgICB4ID0gIlBDMSIsDQogICAgeSA9ICJQQzIiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiLA0KICAgIHNoYXBlID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCnBjYV9wbG90X2RhdGFfNSA8LSBwY2Ffc2NvcmVzXzIgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCmdncGxvdChwY2FfcGxvdF9kYXRhXzUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGNsdXN0ZXIsIHNoYXBlID0gY2x1c3RlcikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMi44LCBhbHBoYSA9IDAuOCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkN1c3RvbWVyIFNlZ21lbnRhdGlvbiAoUENBLWJhc2VkIDUtQ2x1c3RlciBTb2x1dGlvbikiLA0KICAgIHggPSAiSW50ZXJlc3QgaW4gQUkgQmFua2luZyBGZWF0dXJlcyAoUEMxKSIsDQogICAgeSA9ICJOZWVkIGZvciBGaW5hbmNpYWwgR3VpZGFuY2UgKFBDMikiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiLA0KICAgIHNoYXBlID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfcHJvZmlsZV9wY2EyXzUgPC0gcGNhX3Njb3Jlc18yIHw+DQogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGs1X3BjYTIkY2x1c3RlcikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhMl81IDwtIGNsdXN0ZXJfcHJvZmlsZV9wY2EyXzUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pKQ0KDQpjbHVzdGVyX21lYW5zX3BjYTJfNV9uYW1lZCA8LSBjbHVzdGVyX21lYW5zX3BjYTJfNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApIHw+DQogIHJlbmFtZSgNCiAgICBgSW50ZXJlc3QgaW4gQUkgQmFua2luZyBGZWF0dXJlc2AgPSBQQzEsDQogICAgYE5lZWQgZm9yIEZpbmFuY2lhbCBHdWlkYW5jZWAgPSBQQzINCiAgKQ0KDQpjbHVzdGVyX21lYW5zX3BjYTJfNV9sb25nIDwtIGNsdXN0ZXJfbWVhbnNfcGNhMl81X25hbWVkIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAiY29tcG9uZW50IiwNCiAgICB2YWx1ZXNfdG8gPSAibWVhbl9zY29yZSINCiAgKQ0KDQpnZ3Bsb3QoDQogIGNsdXN0ZXJfbWVhbnNfcGNhMl81X2xvbmcsDQogIGFlcyh4ID0gY29tcG9uZW50LCB5ID0gbWVhbl9zY29yZSwgZ3JvdXAgPSBjbHVzdGVyLCBjb2xvciA9IGNsdXN0ZXIpDQopICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNsdXN0ZXIgUHJvZmlsZXMgKDUtQ2x1c3RlciBTb2x1dGlvbiBCYXNlZCBvbiAyIFBDcykiLA0KICAgIHggPSAiUHJpbmNpcGFsIENvbXBvbmVudHMiLA0KICAgIHkgPSAiTWVhbiBjb21wb25lbnQgc2NvcmUiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfcHJvZmlsZV9wY2EyXzQgPC0gcGNhX3Njb3Jlc18yIHw+DQogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGs0X3BjYTIkY2x1c3RlcikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhMl80IDwtIGNsdXN0ZXJfcHJvZmlsZV9wY2EyXzQgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pKQ0KDQpjbHVzdGVyX21lYW5zX3BjYTJfNF9uYW1lZCA8LSBjbHVzdGVyX21lYW5zX3BjYTJfNCB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiQUkgc2tlcHRpY3MiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyINCiAgICAgICkNCiAgICApDQogICkgfD4NCiAgcmVuYW1lKA0KICAgIGBJbnRlcmVzdCBpbiBBSSBCYW5raW5nIEZlYXR1cmVzYCA9IFBDMSwNCiAgICBgTmVlZCBmb3IgRmluYW5jaWFsIEd1aWRhbmNlYCA9IFBDMg0KICApDQoNCmNsdXN0ZXJfbWVhbnNfcGNhMl80X2xvbmcgPC0gY2x1c3Rlcl9tZWFuc19wY2EyXzRfbmFtZWQgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJjb21wb25lbnQiLA0KICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIg0KICApDQoNCmdncGxvdCgNCiAgY2x1c3Rlcl9tZWFuc19wY2EyXzRfbG9uZywNCiAgYWVzKHggPSBjb21wb25lbnQsIHkgPSBtZWFuX3Njb3JlLCBncm91cCA9IGNsdXN0ZXIsIGNvbG9yID0gY2x1c3RlcikNCikgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2x1c3RlciBQcm9maWxlcyAoNC1DbHVzdGVyIFNvbHV0aW9uIEJhc2VkIG9uIDIgUENzKSIsDQogICAgeCA9ICJQcmluY2lwYWwgQ29tcG9uZW50cyIsDQogICAgeSA9ICJNZWFuIGNvbXBvbmVudCBzY29yZSIsDQogICAgY29sb3IgPSAiQ2x1c3RlciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbl9jb21wbGV0ZSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZSA8LSBkYXRhX2NsZWFuX2NvbXBsZXRlIHw+DQogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGs0X3BjYTIkY2x1c3RlcikpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IDwtIGRhdGFfY2xlYW5fY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazVfcGNhMiRjbHVzdGVyKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKG1lYW5fYWdlID0gbWVhbihhcy5udW1lcmljKFEyMSksIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKGFnZSA9IDIwMjYgLSBhcy5udW1lcmljKFEyMSkpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZShtZWFuX2FnZSA9IG1lYW4oYWdlLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UobW9iaWxlX2JhbmtpbmdfdXNlID0gbWVhbihhcy5udW1lcmljKFEyKSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKHRydXN0ID0gbWVhbihhcy5udW1lcmljKFEyNCksIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KYGBge3J9DQpuYW1lcyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81KQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyLCBRMjIpIHw+DQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoUTE3X21lYW4gPSBtZWFuKGFzLm51bWVyaWMoUTE3KSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpgYGB7cn0NCmdlbmRlcl9wcm9maWxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyLCBRMjIpIHw+DQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpKSB8Pg0KICB1bmdyb3VwKCkNCg0KbWFsZV9wcm9maWxlXzUgPC0gZ2VuZGVyX3Byb2ZpbGVfNSB8Pg0KICBmaWx0ZXIoUTIyID09ICIxIikgfD4NCiAgc2VsZWN0KGNsdXN0ZXIsIG1hbGVfcGVyY2VudCA9IHBlcmNlbnQpDQoNCmZlbWFsZV9wcm9maWxlXzUgPC0gZ2VuZGVyX3Byb2ZpbGVfNSB8Pg0KICBmaWx0ZXIoUTIyID09ICIyIikgfD4NCiAgc2VsZWN0KGNsdXN0ZXIsIGZlbWFsZV9wZXJjZW50ID0gcGVyY2VudCkNCg0KcHJvZmlsaW5nX3RhYmxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgbWVhbl9iaXJ0aF95ZWFyID0gbWVhbihhcy5udW1lcmljKFEyMSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbl9hZ2UgPSBtZWFuKGFnZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtb2JpbGVfYmFua2luZ191c2UgPSBtZWFuKGFzLm51bWVyaWMoUTIpLCBuYS5ybSA9IFRSVUUpLA0KICAgIHRydXN0ID0gbWVhbihhcy5udW1lcmljKFEyNCksIG5hLnJtID0gVFJVRSksDQogICAgUTE3X21lYW4gPSBtZWFuKGFzLm51bWVyaWMoUTE3KSwgbmEucm0gPSBUUlVFKQ0KICApIHw+DQogIGxlZnRfam9pbihtYWxlX3Byb2ZpbGVfNSwgYnkgPSAiY2x1c3RlciIpIHw+DQogIGxlZnRfam9pbihmZW1hbGVfcHJvZmlsZV81LCBieSA9ICJjbHVzdGVyIikgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICBtdXRhdGUoYWNyb3NzKC1jbHVzdGVyLCB+IHJvdW5kKC54LCAyKSkpDQoNCnByb2ZpbGluZ190YWJsZV81DQpgYGANCg0KYGBge3J9DQpwY19sb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyJHJvdGF0aW9uWywgMToyXSkNCg0KcGNfbG9hZGluZ3MkVmFyaWFibGUgPC0gcm93bmFtZXMocGNfbG9hZGluZ3MpDQpyb3duYW1lcyhwY19sb2FkaW5ncykgPC0gTlVMTA0KDQpwY19sb2FkaW5ncyA8LSBwY19sb2FkaW5nc1ssIGMoIlZhcmlhYmxlIiwgIlBDMSIsICJQQzIiKV0NCg0KcGNfbG9hZGluZ3MkUEMxIDwtIHJvdW5kKHBjX2xvYWRpbmdzJFBDMSwgMykNCnBjX2xvYWRpbmdzJFBDMiA8LSByb3VuZChwY19sb2FkaW5ncyRQQzIsIDMpDQoNCnBjX2xvYWRpbmdzDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX2JhbmtfY291bnRzIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KICAgIE9UUCA9IHN1bShRMjVhID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgR29yZW5qc2thX0JhbmthID0gc3VtKFEyNWIgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBOTEIgPSBzdW0oUTI1YyA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFJldm9sdXQgPSBzdW0oUTI1ZCA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIE4yNiA9IHN1bShRMjVlID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgSW50ZXNhID0gc3VtKFEyNWYgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBVbmlDcmVkaXQgPSBzdW0oUTI1ZyA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFJlZ2lvbmFsX0JhbmsgPSBzdW0oUTI1aCA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFdvcmtlcnNfU2F2aW5ncyA9IHN1bShRMjVpID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgU3Bhcmthc3NlID0gc3VtKFEyNWogPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBBZGRpa28gPSBzdW0oUTI1ayA9PSAxLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KY2x1c3Rlcl9iYW5rX2NvdW50cw0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmNsdXN0ZXJfYmFua19jb3VudHMgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgT1RQID0gc3VtKFEyNWEgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBHb3Jlbmpza2FfQmFua2EgPSBzdW0oUTI1YiA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIE5MQiA9IHN1bShRMjVjID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgUmV2b2x1dCA9IHN1bShRMjVkID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgTjI2ID0gc3VtKFEyNWUgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBJbnRlc2FfU2FuUGFvbG8gPSBzdW0oUTI1ZiA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFVuaUNyZWRpdCA9IHN1bShRMjVnID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgUmVnaW9uYWxfQmFuayA9IHN1bShRMjVoID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgV29ya2Vyc19TYXZpbmdzID0gc3VtKFEyNWkgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBTcGFya2Fzc2UgPSBzdW0oUTI1aiA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIEFkZGlrbyA9IHN1bShRMjVrID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgT3RoZXIgPSBzdW0oUTI1bCA9PSAxLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KY2x1c3Rlcl9iYW5rX2NvdW50cw0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9iYW5rX2xvbmcgPC0gY2x1c3Rlcl9iYW5rX2NvdW50cyB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IC1jbHVzdGVyLA0KICAgIG5hbWVzX3RvID0gImJhbmsiLA0KICAgIHZhbHVlc190byA9ICJjb3VudCINCiAgKQ0KDQpjbHVzdGVyX2JhbmtfbG9uZw0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGNsdXN0ZXJfYmFua19sb25nLCBhZXMoeCA9IGJhbmssIHkgPSBmYWN0b3IoY2x1c3RlciksIGZpbGwgPSBjb3VudCkpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY291bnQpLCBzaXplID0gNCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkJhbmtzIFVzZWQgYnkgRWFjaCBDbHVzdGVyIiwNCiAgICB4ID0gIkJhbmsiLA0KICAgIHkgPSAiQ2x1c3RlciIsDQogICAgZmlsbCA9ICJDb3VudCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9iYW5rX3BlcmNlbnRfbG9uZyA8LSBjbHVzdGVyX2JhbmtfbG9uZyB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKDEwMCAqIGNvdW50IC8gc3VtKGNvdW50KSwgMSkpIHw+DQogIHVuZ3JvdXAoKQ0KDQpjbHVzdGVyX2JhbmtfcGVyY2VudF9sb25nDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoY2x1c3Rlcl9iYW5rX3BlcmNlbnRfbG9uZywgYWVzKHggPSBiYW5rLCB5ID0gZmFjdG9yKGNsdXN0ZXIpLCBmaWxsID0gcGVyY2VudCkpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHBlcmNlbnQsICIlIikpLCBzaXplID0gNCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkJhbmsgVXNhZ2UgYnkgQ2x1c3RlciAoJSkiLA0KICAgIHggPSAiQmFuayIsDQogICAgeSA9ICJDbHVzdGVyIiwNCiAgICBmaWxsID0gIlBlcmNlbnQiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpDQogICkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpjbHVzdGVyX2JhbmtfY291bnRzX25hbWVkIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoY2x1c3RlciAlaW4lIGMoDQogICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICkpIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBPVFAgPSBzdW0oUTI1YSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIEdvcmVuanNrYV9CYW5rYSA9IHN1bShRMjViID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgTkxCID0gc3VtKFEyNWMgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBSZXZvbHV0ID0gc3VtKFEyNWQgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBOMjYgPSBzdW0oUTI1ZSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIEludGVzYV9TYW5QYW9sbyA9IHN1bShRMjVmID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgVW5pQ3JlZGl0ID0gc3VtKFEyNWcgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBSZWdpb25hbF9CYW5rID0gc3VtKFEyNWggPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBXb3JrZXJzX1NhdmluZ3MgPSBzdW0oUTI1aSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFNwYXJrYXNzZSA9IHN1bShRMjVqID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgQWRkaWtvID0gc3VtKFEyNWsgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBPdGhlciA9IHN1bShRMjVsID09IDEsIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQpjbHVzdGVyX2JhbmtfcGVyY2VudF9sb25nX25hbWVkIDwtIGNsdXN0ZXJfYmFua19jb3VudHNfbmFtZWQgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJiYW5rIiwNCiAgICB2YWx1ZXNfdG8gPSAiY291bnQiDQogICkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgbXV0YXRlKHBlcmNlbnQgPSByb3VuZCgxMDAgKiBjb3VudCAvIHN1bShjb3VudCksIDEpKSB8Pg0KICB1bmdyb3VwKCkNCg0KZ2dwbG90KA0KICBjbHVzdGVyX2JhbmtfcGVyY2VudF9sb25nX25hbWVkLA0KICBhZXMoeCA9IGJhbmssIHkgPSBjbHVzdGVyLCBmaWxsID0gcGVyY2VudCkNCikgKw0KICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocGVyY2VudCwgIiUiKSksIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDQpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJCYW5rIFVzYWdlIGJ5IFNlbGVjdGVkIENsdXN0ZXJzICglKSIsDQogICAgeCA9ICJCYW5rIiwNCiAgICB5ID0gIkNsdXN0ZXIiLA0KICAgIGZpbGwgPSAiUGVyY2VudCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGliYmxlKQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IDwtIGRhdGFfY2xlYW5fY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazVfcGNhMiRjbHVzdGVyKSkNCg0KbWFrZV9wZXJjZXB0aW9uX21hcCA8LSBmdW5jdGlvbihkYXRhLCBjbHVzdGVyX3ZhbHVlcywgdGl0bGVfdGV4dCkgew0KICANCiAgc3Vic2V0X2RhdGEgPC0gZGF0YSB8Pg0KICAgIGZpbHRlcihjbHVzdGVyICVpbiUgY2x1c3Rlcl92YWx1ZXMpIHw+DQogICAgbXV0YXRlKA0KICAgICAgYWNyb3NzKFExM2E6UTE1ZywgYXMubnVtZXJpYykNCiAgICApDQogIA0KICBiYW5rX21lYW5zIDwtIHRpYmJsZSgNCiAgICBiYW5rID0gYygiT1RQIiwgIkdvcmVuanNrYSBCYW5rYSIsICJOTEIiLCAiUmV2b2x1dCIsICJOMjYiLCAiSW50ZXNhIFNhblBhb2xvIiwgIlVuaUNyZWRpdCIpLA0KICAgIGlubm92YXRpb24gPSBjKA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNhLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNjLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNmLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTNnLCBuYS5ybSA9IFRSVUUpDQogICAgKSwNCiAgICBjdXN0b21lcl9zdXBwb3J0ID0gYygNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0YSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0YiwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0YywgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0ZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0ZiwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW4oc3Vic2V0X2RhdGEkUTE0ZywgbmEucm0gPSBUUlVFKQ0KICAgICksDQogICAgcmVsaWFiaWxpdHkgPSBjKA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTVhLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTViLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTVjLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTVlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTVmLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTVnLCBuYS5ybSA9IFRSVUUpDQogICAgKQ0KICApDQogIA0KICBtYXQgPC0gYmFua19tZWFucyB8Pg0KICAgIGNvbHVtbl90b19yb3duYW1lcygiYmFuayIpIHw+DQogICAgYXMubWF0cml4KCkNCiAgDQogIHBjYV9iYW5rIDwtIEZhY3RvTWluZVI6OlBDQShtYXQsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFKQ0KICANCiAgZmFjdG9leHRyYTo6ZnZpel9wY2FfYmlwbG90KA0KICAgIHBjYV9iYW5rLA0KICAgIHJlcGVsID0gVFJVRSwNCiAgICBjb2wudmFyID0gImdyYXkzMCINCiAgKSArDQogICAgZ2dwbG90Mjo6Z2d0aXRsZSh0aXRsZV90ZXh0KSArDQogICAgZ2dwbG90Mjo6eGxhYigiRGltMTogT3ZlcmFsbCBEaWdpdGFsIEJhbmtpbmcgUGVyZm9ybWFuY2UiKSArDQogICAgZ2dwbG90Mjo6eWxhYigiRGltMjogQ3VzdG9tZXIgU3VwcG9ydCB2cyBJbm5vdmF0aW9uIikNCn0NCmBgYA0KDQpgYGB7cn0NCm1ha2VfcGVyY2VwdGlvbl9tYXAoDQogIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LA0KICBjbHVzdGVyX3ZhbHVlcyA9IGMoIjIiKSwNCiAgdGl0bGVfdGV4dCA9ICJQZXJjZXB0dWFsIE1hcCBvZiBCYW5rcyAtIENsdXN0ZXIgMiINCikNCmBgYA0KDQpgYGB7cn0NCm1ha2VfcGVyY2VwdGlvbl9tYXAoDQogIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LA0KICBjbHVzdGVyX3ZhbHVlcyA9IGMoIjMiKSwNCiAgdGl0bGVfdGV4dCA9ICJQZXJjZXB0dWFsIE1hcCBvZiBCYW5rcyAtIENsdXN0ZXIgMyINCikNCmBgYA0KDQpgYGB7cn0NCm1ha2VfcGVyY2VwdGlvbl9tYXAoDQogIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LA0KICBjbHVzdGVyX3ZhbHVlcyA9IGMoIjUiKSwNCiAgdGl0bGVfdGV4dCA9ICJQZXJjZXB0dWFsIE1hcCBvZiBCYW5rcyAtIENsdXN0ZXIgNSINCikNCmBgYA0KDQpgYGB7cn0NCm1ha2VfcGVyY2VwdGlvbl9tYXAoDQogIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LA0KICBjbHVzdGVyX3ZhbHVlcyA9IGMoIjIiLCAiMyIsICI1IiksDQogIHRpdGxlX3RleHQgPSAiUGVyY2VwdHVhbCBNYXAgb2YgQmFua3MgLSBDbHVzdGVycyAyLCAzLCBhbmQgNSINCikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpjbHVzdGVyX3E0X3RhYmxlX25hbWVkIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoY2x1c3RlciAlaW4lIGMoDQogICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICkpIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIsIFE0KSB8Pg0KICBzdW1tYXJpc2UobiA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgbXV0YXRlKHBlcmNlbnQgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIG11dGF0ZSgNCiAgICBpbmZvX3NvdXJjZSA9IGNhc2Vfd2hlbigNCiAgICAgIFE0ID09ICIxIiB+ICJXZWIgYnJvd3NlcnMiLA0KICAgICAgUTQgPT0gIjIiIH4gIkZhbWlseSAvIGZyaWVuZHMiLA0KICAgICAgUTQgPT0gIjMiIH4gIkZpbmFuY2lhbCBtZWRpYSIsDQogICAgICBRNCA9PSAiNCIgfiAiQ2hhdEdQVCAvIEFJIG1vZGVscyIsDQogICAgICBRNCA9PSAiNSIgfiAiT3RoZXIiLA0KICAgICAgVFJVRSB+IGFzLmNoYXJhY3RlcihRNCkNCiAgICApDQogICkgfD4NCiAgc2VsZWN0KGNsdXN0ZXIsIGluZm9fc291cmNlLCBuLCBwZXJjZW50KQ0KDQpjbHVzdGVyX3E0X3RhYmxlX25hbWVkDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoY2x1c3Rlcl9xNF90YWJsZV9uYW1lZCwgYWVzKHggPSBpbmZvX3NvdXJjZSwgeSA9IGNsdXN0ZXIsIGZpbGwgPSBwZXJjZW50KSkgKw0KICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocGVyY2VudCwgIiUiKSksIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDQpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJJbmZvcm1hdGlvbiBTb3VyY2UgYnkgU2VsZWN0ZWQgQ2x1c3RlcnMgKCUpIiwNCiAgICB4ID0gIkluZm9ybWF0aW9uIFNvdXJjZSIsDQogICAgeSA9ICJDbHVzdGVyIiwNCiAgICBmaWxsID0gIlBlcmNlbnQiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpDQogICkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfcTRfd2lkZSA8LSBjbHVzdGVyX3E0X3RhYmxlX25hbWVkIHw+DQogIHNlbGVjdChjbHVzdGVyLCBpbmZvX3NvdXJjZSwgcGVyY2VudCkgfD4NCiAgcGl2b3Rfd2lkZXIoDQogICAgbmFtZXNfZnJvbSA9IGluZm9fc291cmNlLA0KICAgIHZhbHVlc19mcm9tID0gcGVyY2VudCwNCiAgICB2YWx1ZXNfZmlsbCA9IDANCiAgKQ0KDQpjbHVzdGVyX3E0X3dpZGUNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCmNsdXN0ZXJfdmFycyA8LSBjKA0KICAiUTZhIiwgIlE2YiIsICJRNmQiLCAiUTZlIiwgIlE2aCIsICJRNmkiLA0KICAiUThhIiwgIlE4YiIsICJROGMiLCAiUThkIiwgIlE4ZSINCikNCg0KY2x1c3Rlcl92YWxpZGF0aW9uIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoazVfcGNhMiRjbHVzdGVyKSwNCiAgICBhY3Jvc3MoYWxsX29mKGNsdXN0ZXJfdmFycyksIGFzLm51bWVyaWMpDQogICkNCmBgYA0KDQpgYGB7cn0NCmFub3ZhX3Jlc3VsdHMgPC0gbGFwcGx5KGNsdXN0ZXJfdmFycywgZnVuY3Rpb24odmFyKSB7DQogIG1vZGVsIDwtIGFvdihhcy5mb3JtdWxhKHBhc3RlKHZhciwgIn4gY2x1c3RlciIpKSwgZGF0YSA9IGNsdXN0ZXJfdmFsaWRhdGlvbikNCiAgZGF0YS5mcmFtZSgNCiAgICB2YXJpYWJsZSA9IHZhciwNCiAgICBwX3ZhbHVlID0gc3VtbWFyeShtb2RlbClbWzFdXVtbIlByKD5GKSJdXVsxXQ0KICApDQp9KQ0KDQphbm92YV9yZXN1bHRzIDwtIGRvLmNhbGwocmJpbmQsIGFub3ZhX3Jlc3VsdHMpDQphbm92YV9yZXN1bHRzJHBfYWRqdXN0ZWQgPC0gcC5hZGp1c3QoYW5vdmFfcmVzdWx0cyRwX3ZhbHVlLCBtZXRob2QgPSAiaG9sbSIpDQoNCmFub3ZhX3Jlc3VsdHMNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfbWVhbnNfdmFsaWRhdGlvbiA8LSBjbHVzdGVyX3ZhbGlkYXRpb24gfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KICAgIGFjcm9zcyhhbGxfb2YoY2x1c3Rlcl92YXJzKSwgfiBtZWFuKC54LCBuYS5ybSA9IFRSVUUpKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCg0KY2x1c3Rlcl9tZWFuc192YWxpZGF0aW9uDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KDQphZ2VfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKFEyMSkpIHw+DQogIG11dGF0ZSgNCiAgICBhZ2UgPSAyMDI2IC0gYXMubnVtZXJpYyhRMjEpDQogICkNCmBgYA0KDQpgYGB7cn0NCmFnZV9zdW1tYXJ5IDwtIGFnZV9kYXRhIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW5fYWdlID0gbWVhbihhZ2UsIG5hLnJtID0gVFJVRSksDQogICAgc2RfYWdlID0gc2QoYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbl9hZ2UgPSBtZWRpYW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbl9hZ2UgPSBtaW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1heF9hZ2UgPSBtYXgoYWdlLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KYWdlX3N1bW1hcnkNCmBgYA0KDQpgYGB7cn0NCmFnZV9hbm92YSA8LSBhb3YoYWdlIH4gY2x1c3RlciwgZGF0YSA9IGFnZV9kYXRhKQ0Kc3VtbWFyeShhZ2VfYW5vdmEpDQpgYGANCg0KYGBge3J9DQpUdWtleUhTRChhZ2VfYW5vdmEpDQpgYGANCg0KYGBge3J9DQphZ2Vfc3VtbWFyeSA8LSBhZ2VfZGF0YSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgbiA9IG4oKSwNCiAgICBtZWFuX2FnZSA9IG1lYW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkX2FnZSA9IHNkKGFnZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWRpYW5fYWdlID0gbWVkaWFuKGFnZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtaW5fYWdlID0gbWluKGFnZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtYXhfYWdlID0gbWF4KGFnZSwgbmEucm0gPSBUUlVFKQ0KICApDQoNCmFnZV9zdW1tYXJ5DQpgYGANCg0KYGBge3J9DQphZ2Vfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KZ2VuZGVyX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkgfD4NCiAgZmlsdGVyKCFpcy5uYShRMjIpKSB8Pg0KICBtdXRhdGUoDQogICAgZ2VuZGVyID0gZmFjdG9yKA0KICAgICAgUTIyLA0KICAgICAgbGV2ZWxzID0gYygiMSIsICIyIiksDQogICAgICBsYWJlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpDQogICAgKQ0KICApDQpgYGANCg0KYGBge3J9DQpnZW5kZXJfdGFibGUgPC0gdGFibGUoZ2VuZGVyX2RhdGEkY2x1c3RlciwgZ2VuZGVyX2RhdGEkZ2VuZGVyKQ0KZ2VuZGVyX3RhYmxlDQpgYGANCg0KYGBge3J9DQpnZW5kZXJfY2hpc3EgPC0gY2hpc3EudGVzdChnZW5kZXJfdGFibGUpDQpnZW5kZXJfY2hpc3ENCmBgYA0KDQpgYGB7cn0NCmdlbmRlcl9jaGlzcSRleHBlY3RlZA0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KbW9iaWxlX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkgfD4NCiAgZmlsdGVyKCFpcy5uYShRMikpIHw+DQogIG11dGF0ZSgNCiAgICBtb2JpbGVfYmFua2luZ191c2UgPSBhcy5udW1lcmljKFEyKQ0KICApDQpgYGANCg0KYGBge3J9DQptb2JpbGVfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgbW9iaWxlX2JhbmtpbmdfdXNlID0gYXMubnVtZXJpYyhRMiksDQogICAgbW9iaWxlX2JhbmtpbmdfdXNlID0gaWZlbHNlKG1vYmlsZV9iYW5raW5nX3VzZSA9PSAtMiwgTkEsIG1vYmlsZV9iYW5raW5nX3VzZSkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKG1vYmlsZV9iYW5raW5nX3VzZSkpDQpgYGANCg0KYGBge3J9DQp0YWJsZShtb2JpbGVfZGF0YSRtb2JpbGVfYmFua2luZ191c2UpDQptb2JpbGVfZGF0YSB8Pg0KICBjb3VudChjbHVzdGVyLCBtb2JpbGVfYmFua2luZ191c2UpDQpgYGANCg0KYGBge3J9DQptb2JpbGVfc3VtbWFyeSA8LSBtb2JpbGVfZGF0YSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgbiA9IG4oKSwNCiAgICBtZWFuX21vYmlsZV91c2UgPSBtZWFuKG1vYmlsZV9iYW5raW5nX3VzZSwgbmEucm0gPSBUUlVFKSwNCiAgICBzZF9tb2JpbGVfdXNlID0gc2QobW9iaWxlX2JhbmtpbmdfdXNlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbl9tb2JpbGVfdXNlID0gbWVkaWFuKG1vYmlsZV9iYW5raW5nX3VzZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtaW5fbW9iaWxlX3VzZSA9IG1pbihtb2JpbGVfYmFua2luZ191c2UsIG5hLnJtID0gVFJVRSksDQogICAgbWF4X21vYmlsZV91c2UgPSBtYXgobW9iaWxlX2JhbmtpbmdfdXNlLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KbW9iaWxlX3N1bW1hcnkNCmBgYA0KDQpgYGB7cn0NCm1vYmlsZV9rdyA8LSBrcnVza2FsLnRlc3QobW9iaWxlX2JhbmtpbmdfdXNlIH4gY2x1c3RlciwgZGF0YSA9IG1vYmlsZV9kYXRhKQ0KbW9iaWxlX2t3DQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KDQplZHVjYXRpb25fZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLDIsMyw0LDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKSwNCiAgICBlZHVjYXRpb24gPSBhcy5udW1lcmljKFEyNCkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKGVkdWNhdGlvbikpDQpgYGANCg0KYGBge3J9DQp0YWJsZShlZHVjYXRpb25fZGF0YSRlZHVjYXRpb24pDQpgYGANCg0KYGBge3J9DQplZHVjYXRpb25fZGF0YSB8Pg0KICBjb3VudChjbHVzdGVyLCBlZHVjYXRpb24pDQpgYGANCg0KYGBge3J9DQplZHVjYXRpb25fdGFibGUgPC0gdGFibGUoZWR1Y2F0aW9uX2RhdGEkY2x1c3RlciwgZWR1Y2F0aW9uX2RhdGEkZWR1Y2F0aW9uKQ0KDQplZHVjYXRpb25fdGFibGUNCmBgYA0KDQpgYGB7cn0NCmVkdWNhdGlvbl9jaGlzcSA8LSBjaGlzcS50ZXN0KGVkdWNhdGlvbl90YWJsZSkNCg0KZWR1Y2F0aW9uX2NoaXNxDQpgYGANCg0KYGBge3J9DQplZHVjYXRpb25fY2hpc3EkZXhwZWN0ZWQNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKGVkdWNhdGlvbl9kYXRhJGVkdWNhdGlvbikNCg0KZWR1Y2F0aW9uX3RhYmxlDQoNCmVkdWNhdGlvbl9jaGlzcQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwyLDMsNCw1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgaW5jb21lID0gYXMubnVtZXJpYyhRMjYpDQogICkgfD4NCiAgZmlsdGVyKCFpcy5uYShpbmNvbWUpKQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoaW5jb21lX2RhdGEkaW5jb21lKQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2RhdGEgfD4NCiAgY291bnQoY2x1c3RlciwgaW5jb21lKQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX3RhYmxlIDwtIHRhYmxlKGluY29tZV9kYXRhJGNsdXN0ZXIsIGluY29tZV9kYXRhJGluY29tZSkNCg0KaW5jb21lX3RhYmxlDQpgYGANCg0KYGBge3J9DQppbmNvbWVfY2hpc3EgPC0gY2hpc3EudGVzdChpbmNvbWVfdGFibGUpDQoNCmluY29tZV9jaGlzcQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2NoaXNxJGV4cGVjdGVkDQpgYGANCg0KYGBge3J9DQp0YWJsZShpbmNvbWVfZGF0YSRpbmNvbWUpDQoNCmluY29tZV90YWJsZQ0KDQppbmNvbWVfY2hpc3ENCmBgYA0KDQpgYGB7cn0NCmluY29tZV9kYXRhX2dyb3VwZWQgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIGluY29tZSA9IGFzLm51bWVyaWMoUTI2KSwNCiAgICBpbmNvbWVfZ3JvdXAgPSBjYXNlX3doZW4oDQogICAgICBpbmNvbWUgJWluJSBjKDEsIDIpIH4gIkxvdyBpbmNvbWUgKDDigJM5OTnigqwpIiwNCiAgICAgIGluY29tZSAlaW4lIGMoMywgNCkgfiAiTG93ZXItbWlkZGxlIGluY29tZSAoMTAwMOKAkzE5OTnigqwpIiwNCiAgICAgIGluY29tZSAlaW4lIGMoNSwgNikgfiAiVXBwZXItbWlkZGxlIGluY29tZSAoMjAwMOKAkzI5OTnigqwpIiwNCiAgICAgIGluY29tZSAlaW4lIGMoNywgOCkgfiAiSGlnaCBpbmNvbWUgKDMwMDDigqwrKSIsDQogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXw0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKGluY29tZV9ncm91cCkpDQpgYGANCg0KYGBge3J9DQp0YWJsZShpbmNvbWVfZGF0YV9ncm91cGVkJGluY29tZV9ncm91cCkNCmBgYA0KDQpgYGB7cn0NCmluY29tZV9kYXRhX2dyb3VwZWQgfD4NCiAgY291bnQoY2x1c3RlciwgaW5jb21lX2dyb3VwKQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2dyb3VwX3RhYmxlIDwtIHRhYmxlKA0KICBpbmNvbWVfZGF0YV9ncm91cGVkJGNsdXN0ZXIsDQogIGluY29tZV9kYXRhX2dyb3VwZWQkaW5jb21lX2dyb3VwDQopDQoNCmluY29tZV9ncm91cF90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2dyb3VwX2NoaXNxIDwtIGNoaXNxLnRlc3QoaW5jb21lX2dyb3VwX3RhYmxlKQ0KDQppbmNvbWVfZ3JvdXBfY2hpc3ENCmBgYA0KDQpgYGB7cn0NCmluY29tZV9ncm91cF9jaGlzcSRleHBlY3RlZA0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX3Byb2ZpbGUgPC0gaW5jb21lX2RhdGFfZ3JvdXBlZCB8Pg0KICBjb3VudChjbHVzdGVyLCBpbmNvbWVfZ3JvdXApIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIG11dGF0ZShwZXJjZW50ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSkpIHw+DQogIHVuZ3JvdXAoKQ0KDQppbmNvbWVfcHJvZmlsZQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX3Byb2ZpbGVfd2lkZSA8LSBpbmNvbWVfcHJvZmlsZSB8Pg0KICBzZWxlY3QoY2x1c3RlciwgaW5jb21lX2dyb3VwLCBwZXJjZW50KSB8Pg0KICB0aWR5cjo6cGl2b3Rfd2lkZXIoDQogICAgbmFtZXNfZnJvbSA9IGluY29tZV9ncm91cCwNCiAgICB2YWx1ZXNfZnJvbSA9IHBlcmNlbnQsDQogICAgdmFsdWVzX2ZpbGwgPSAwDQogICkNCg0KaW5jb21lX3Byb2ZpbGVfd2lkZQ0KYGBgDQoNCmBgYHtyfQ0KYmFua19kYXRhIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsMiwzLDQsNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkNCmBgYA0KDQpgYGB7cn0NCmJhbmtfZGF0YSA8LSBiYW5rX2RhdGEgfD4NCiAgbXV0YXRlKA0KICAgIGFjcm9zcyhRMjVhOlEyNWwsIH4gYXMubnVtZXJpYyguKSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KcmV2b2x1dF90YWJsZSA8LSB0YWJsZShiYW5rX2RhdGEkY2x1c3RlciwgYmFua19kYXRhJFEyNWQpDQoNCnJldm9sdXRfdGFibGUNCg0KY2hpc3EudGVzdChyZXZvbHV0X3RhYmxlKQ0KYGBgDQoNCmBgYHtyfQ0KYmFua3MgPC0gYygiUTI1YSIsIlEyNWIiLCJRMjVjIiwiUTI1ZCIsIlEyNWUiLCJRMjVmIiwiUTI1ZyIsIlEyNWgiLCJRMjVpIiwiUTI1aiIsIlEyNWsiLCJRMjVsIikNCg0KYmFua190ZXN0cyA8LSBsYXBwbHkoYmFua3MsIGZ1bmN0aW9uKHZhcil7DQoNCiAgdGFiIDwtIHRhYmxlKGJhbmtfZGF0YSRjbHVzdGVyLCBiYW5rX2RhdGFbW3Zhcl1dKQ0KICB0ZXN0IDwtIGNoaXNxLnRlc3QodGFiKQ0KDQogIGRhdGEuZnJhbWUoDQogICAgYmFuayA9IHZhciwNCiAgICBjaGlfc3F1YXJlID0gdGVzdCRzdGF0aXN0aWMsDQogICAgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZQ0KICApDQp9KQ0KDQpiYW5rX3Rlc3RzIDwtIGRvLmNhbGwocmJpbmQsIGJhbmtfdGVzdHMpDQoNCmJhbmtfdGVzdHMNCmBgYA0KDQpgYGB7cn0NCm90cF9wcm9maWxlIDwtIGJhbmtfZGF0YSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgb3RwX3VzZXJzID0gc3VtKFEyNWEgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBuID0gbigpLA0KICAgIG90cF9wZXJjZW50ID0gcm91bmQoMTAwICogb3RwX3VzZXJzIC8gbiwgMSkNCiAgKQ0KDQpvdHBfcHJvZmlsZQ0KYGBgDQoNCmBgYHtyfQ0KYXJlYV9kYXRhIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsMiwzLDQsNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIGFyZWEgPSBhcy5udW1lcmljKFEyMykNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKGFyZWEpKQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoYXJlYV9kYXRhJGFyZWEpDQpgYGANCg0KYGBge3J9DQphcmVhX3RhYmxlIDwtIHRhYmxlKGFyZWFfZGF0YSRjbHVzdGVyLCBhcmVhX2RhdGEkYXJlYSkNCg0KYXJlYV90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KYXJlYV9jaGlzcSA8LSBjaGlzcS50ZXN0KGFyZWFfdGFibGUpDQoNCmFyZWFfY2hpc3ENCmBgYA0KDQpgYGB7cn0NCmFyZWFfY2hpc3EkZXhwZWN0ZWQNCmBgYA0KDQpgYGB7cn0NCmFyZWFfcHJvZmlsZSA8LSBhcmVhX2RhdGEgfD4NCiAgY291bnQoY2x1c3RlciwgYXJlYSkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgbXV0YXRlKHBlcmNlbnQgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkNCg0KYXJlYV9wcm9maWxlDQpgYGANCg0KYGBge3J9DQphcmVhX3Byb2ZpbGUgPC0gYXJlYV9kYXRhIHw+DQogIGNvdW50KGNsdXN0ZXIsIGFyZWEpIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIG11dGF0ZShwZXJjZW50ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSkpIHw+DQogIHVuZ3JvdXAoKQ0KDQphcmVhX3Byb2ZpbGUNCmBgYA0KDQpgYGB7cn0NCmFpX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwyLDMsNCw1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgYWlfdXNlID0gYXMubnVtZXJpYyhRMTcpDQogICkgfD4NCiAgZmlsdGVyKCFpcy5uYShhaV91c2UpKQ0KYGBgDQoNCmBgYHtyfQ0KYWlfc3VtbWFyeSA8LSBhaV9kYXRhIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW5fYWkgPSBtZWFuKGFpX3VzZSksDQogICAgc2RfYWkgPSBzZChhaV91c2UpLA0KICAgIG1lZGlhbl9haSA9IG1lZGlhbihhaV91c2UpLA0KICAgIG1pbl9haSA9IG1pbihhaV91c2UpLA0KICAgIG1heF9haSA9IG1heChhaV91c2UpDQogICkNCg0KYWlfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0KYWlfYW5vdmEgPC0gYW92KGFpX3VzZSB+IGNsdXN0ZXIsIGRhdGEgPSBhaV9kYXRhKQ0KDQpzdW1tYXJ5KGFpX2Fub3ZhKQ0KYGBgDQoNCmBgYHtyfQ0KVHVrZXlIU0QoYWlfYW5vdmEpDQpgYGANCg0KYGBge3J9DQphaV9zdW1tYXJ5DQpzdW1tYXJ5KGFpX2Fub3ZhKQ0KYGBgDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgSFlQT1RIRVNJUyBURVNUIOKAkyBIMWMNCiMgUTE3OiBMaWtlbGlob29kIG9mIHVzaW5nIHRoZSBBSSBwZXJzb25hbCBiYW5raW5nIGFnZW50DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQojIEgwIChOdWxsIEh5cG90aGVzaXMpOg0KIyBUaGVyZSBhcmUgbm8gc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiB0aGUgbGlrZWxpaG9vZA0KIyBvZiB1c2luZyB0aGUgQUkgcGVyc29uYWwgYmFua2luZyBhZ2VudCAoUTE3KSBiZXR3ZWVuIHRoZSBjbHVzdGVycy4NCg0KIyBIMWMgKFJlc2VhcmNoIEh5cG90aGVzaXMpOg0KIyBGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIGFyZSBtb3JlIGxpa2VseSB0byB1c2UgdGhlIEFJIHBlcnNvbmFsDQojIGJhbmtpbmcgYWdlbnQgdGhhbiBjYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzLg0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAxIExPQUQgTElCUkFSSUVTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAyIFBSRVBBUkUgREFUQQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBlbnN1cmUgY2x1c3RlciB2YXJpYWJsZSBpcyBmYWN0b3INCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkY2x1c3RlciA8LSBhcy5mYWN0b3IoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyKQ0KDQojIGNvbnZlcnQgUTE3IHRvIG51bWVyaWMgKExpa2VydCBzY2FsZSkNCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgbXV0YXRlKFExNyA9IGFzLm51bWVyaWMoUTE3KSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgMyBERVNDUklQVElWRSBTVEFUSVNUSUNTIEZPUiBFQUNIIENMVVNURVINCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmNsdXN0ZXJfc3VtbWFyeV9RMTcgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW4gPSBtZWFuKFExNywgbmEucm0gPSBUUlVFKSwNCiAgICBtZWRpYW4gPSBtZWRpYW4oUTE3LCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkID0gc2QoUTE3LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbiA9IG1pbihRMTcsIG5hLnJtID0gVFJVRSksDQogICAgbWF4ID0gbWF4KFExNywgbmEucm0gPSBUUlVFKQ0KICApDQoNCnByaW50KGNsdXN0ZXJfc3VtbWFyeV9RMTcpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDQgVEVTVCBESUZGRVJFTkNFUyBCRVRXRUVOIENMVVNURVJTDQojIEtydXNrYWzigJNXYWxsaXMgdGVzdCAoYXBwcm9wcmlhdGUgZm9yIExpa2VydCBkYXRhKQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbF90ZXN0X1ExNyA8LSBrcnVza2FsLnRlc3QoUTE3IH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQoNCnByaW50KGtydXNrYWxfdGVzdF9RMTcpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDUgUE9TVC1IT0MgVEVTVCAoUEFJUldJU0UgQ09NUEFSSVNPTikNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCnBhaXJ3aXNlX3Jlc3VsdHNfUTE3IDwtIHBhaXJ3aXNlLndpbGNveC50ZXN0KA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNywNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyLA0KICBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSINCikNCg0KcHJpbnQocGFpcndpc2VfcmVzdWx0c19RMTcpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDYgVklTVUFMSVpBVElPTg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gY2x1c3RlciwgeSA9IFExNykpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkxpa2VsaWhvb2Qgb2YgVXNpbmcgQUkgUGVyc29uYWwgQmFua2luZyBBZ2VudCBieSBDbHVzdGVyIiwNCiAgICB4ID0gIkNsdXN0ZXIiLA0KICAgIHkgPSAiTGlrZWxpaG9vZCBvZiBVc2UgKFExNykiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDRiIEVGRkVDVCBTSVpFIEZPUiBLUlVTS0FMLVdBTExJUw0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KbGlicmFyeShyc3RhdGl4KQ0KDQplZmZlY3Rfc2l6ZV9RMTcgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAga3J1c2thbF9lZmZzaXplKFExNyB+IGNsdXN0ZXIpDQoNCnByaW50KGVmZmVjdF9zaXplX1ExNykNCmBgYA0KDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBBU1NVTVBUSU9OIENIRUNLUyDigJMgSDFjDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCnNoYXBpcm8udGVzdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNykNCg0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gUTE3KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnFxbm9ybShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNykNCnFxbGluZShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNykNCg0KbGlicmFyeShyc3RhdGl4KQ0KDQpsZXZlbmVfdGVzdChRMTcgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBLUlVTS0FMLVdBTExJUyBURVNUDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmtydXNrYWwudGVzdChRMTcgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSkNCmBgYA0KDQojI0gxZQ0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBIWVBPVEhFU0lTIFRFU1QNCiMgUTEyZyDigJMgUHJlZmVyZW5jZSBmb3IgaHVtYW4gaW50ZXJhY3Rpb24NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgSDAgKE51bGwgSHlwb3RoZXNpcyk6DQojIFRoZXJlIGFyZSBubyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIHByZWZlcmVuY2UNCiMgZm9yIGh1bWFuIGludGVyYWN0aW9uIChRMTJnKSBiZXR3ZWVuIHRoZSBjbHVzdGVycy4NCg0KIyBIMSAoUmVzZWFyY2ggSHlwb3RoZXNpcyk6DQojIENhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMgc2hvdyBhIGhpZ2hlciBwcmVmZXJlbmNlIGZvciBodW1hbg0KIyBpbnRlcmFjdGlvbiB0aGFuIEFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIGFuZA0KIyBmZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzLg0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAxIExPQUQgTElCUkFSSUVTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAyIFBSRVBBUkUgREFUQQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBlbnN1cmUgY2x1c3RlciB2YXJpYWJsZSBpcyBmYWN0b3INCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkY2x1c3RlciA8LSBhcy5mYWN0b3IoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyKQ0KDQojIGNvbnZlcnQgTGlrZXJ0IHZhcmlhYmxlIHRvIG51bWVyaWMNCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgbXV0YXRlKFExMmcgPSBhcy5udW1lcmljKFExMmcpKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAzIERFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgRk9SIEVBQ0ggQ0xVU1RFUg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2x1c3Rlcl9zdW1tYXJ5IDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgbiA9IG4oKSwNCiAgICBtZWFuID0gbWVhbihRMTJnLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbiA9IG1lZGlhbihRMTJnLCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkID0gc2QoUTEyZywgbmEucm0gPSBUUlVFKSwNCiAgICBtaW4gPSBtaW4oUTEyZywgbmEucm0gPSBUUlVFKSwNCiAgICBtYXggPSBtYXgoUTEyZywgbmEucm0gPSBUUlVFKQ0KICApDQoNCnByaW50KGNsdXN0ZXJfc3VtbWFyeSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNCBURVNUIERJRkZFUkVOQ0VTIEJFVFdFRU4gQ0xVU1RFUlMNCiMgS3J1c2thbOKAk1dhbGxpcyB0ZXN0IChhcHByb3ByaWF0ZSBmb3IgTGlrZXJ0IHNjYWxlKQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbF90ZXN0IDwtIGtydXNrYWwudGVzdChRMTJnIH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQoNCnByaW50KGtydXNrYWxfdGVzdCkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNSBQT1NULUhPQyBURVNUIChQQUlSV0lTRSBDT01QQVJJU09OIEJFVFdFRU4gQ0xVU1RFUlMpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpwYWlyd2lzZV9yZXN1bHRzIDwtIHBhaXJ3aXNlLndpbGNveC50ZXN0KA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmcsDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkY2x1c3RlciwNCiAgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiDQopDQoNCnByaW50KHBhaXJ3aXNlX3Jlc3VsdHMpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDYgVklTVUFMSVpBVElPTiBPRiBESUZGRVJFTkNFUyBCRVRXRUVOIENMVVNURVJTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBjbHVzdGVyLCB5ID0gUTEyZykpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlByZWZlcmVuY2UgZm9yIEh1bWFuIEludGVyYWN0aW9uIGJ5IENsdXN0ZXIiLA0KICAgIHggPSAiQ2x1c3RlciIsDQogICAgeSA9ICJQcmVmZXJlbmNlIGZvciBIdW1hbiBJbnRlcmFjdGlvbiAoUTEyZykiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBBU1NVTVBUSU9OIENIRUNLUyDigJMgSDFlDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY2FyKQ0KDQojIE5vcm1hbGl0eSB0ZXN0DQpzaGFwaXJvLnRlc3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTJnKQ0KDQojIEhpc3RvZ3JhbQ0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gUTEyZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIFFRIHBsb3QNCnFxbm9ybShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmcpDQpxcWxpbmUoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTJnKQ0KDQojIEhvbW9nZW5laXR5IG9mIHZhcmlhbmNlcw0KbGV2ZW5lVGVzdChRMTJnIH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgS1JVU0tBTC1XQUxMSVMgVEVTVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsLnRlc3QoUTEyZyB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81KQ0KYGBgDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNGIgRUZGRUNUIFNJWkUgRk9SIEtSVVNLQUwtV0FMTElTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KHJzdGF0aXgpDQoNCmVmZmVjdF9zaXplX1ExMmcgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAga3J1c2thbF9lZmZzaXplKFExMmcgfiBjbHVzdGVyKQ0KDQpwcmludChlZmZlY3Rfc2l6ZV9RMTJnKQ0KYGBgDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiY29pbiIpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHJzdGF0aXgpDQpsaWJyYXJ5KGNvaW4pDQpsaWJyYXJ5KHB1cnJyKQ0KDQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gYXMuZmFjdG9yKGNsdXN0ZXIpLA0KICAgIFExMmcgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihRMTJnKSkNCiAgKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShjbHVzdGVyKSwgIWlzLm5hKFExMmcpKQ0KDQpjbHVzdGVyX3BhaXJzIDwtIGNvbWJuKGxldmVscyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIpLCAyLCBzaW1wbGlmeSA9IEZBTFNFKQ0KDQpwYWlyd2lzZV9lZmZlY3RzX1ExMmcgPC0gbWFwX2RmcihjbHVzdGVyX3BhaXJzLCBmdW5jdGlvbih4KSB7DQogIHRtcCA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICAgIGZpbHRlcihjbHVzdGVyICVpbiUgeCkgJT4lDQogICAgZHJvcGxldmVscygpDQoNCiAgd2lsY294X2VmZnNpemUoZGF0YSA9IHRtcCwgUTEyZyB+IGNsdXN0ZXIpICU+JQ0KICAgIG11dGF0ZShjb21wYXJpc29uID0gcGFzdGUoeCwgY29sbGFwc2UgPSAiIHZzICIpKQ0KfSkNCg0KcHJpbnQocGFpcndpc2VfZWZmZWN0c19RMTJnKQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgSFlQT1RIRVNJUyBURVNUIOKAkyBIMmQNCiMgVGhlIGhpZ2hlciB0aGUgaW1wb3J0YW5jZSBvZiBzZWN1cml0eSwgdGhlIGhpZ2hlciB0aGUNCiMgd2lsbGluZ25lc3MgdG8gYWRvcHQgQUkgYWdlbnRzIGluIHBlcnNvbmFsIGJhbmtpbmcNCiMgVmFyaWFibGVzOg0KIyBRMTJhID0gSW1wb3J0YW5jZSBvZiBzZWN1cml0eQ0KIyBRMTcgID0gV2lsbGluZ25lc3MgdG8gdXNlIEFJIGJhbmtpbmcgYWdlbnQNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgSDAgKE51bGwgSHlwb3RoZXNpcyk6DQojIFRoZXJlIGlzIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBpbXBvcnRhbmNlIG9mIHNlY3VyaXR5IChRMTJhKQ0KIyBhbmQgd2lsbGluZ25lc3MgdG8gYWRvcHQgQUkgYmFua2luZyBhZ2VudHMgKFExNykuDQoNCiMgSDEgKFJlc2VhcmNoIEh5cG90aGVzaXMpOg0KIyBIaWdoZXIgcGVyY2VpdmVkIGltcG9ydGFuY2Ugb2Ygc2VjdXJpdHkgaXMgYXNzb2NpYXRlZCB3aXRoIGEgaGlnaGVyDQojIHdpbGxpbmduZXNzIHRvIGFkb3B0IEFJIGJhbmtpbmcgYWdlbnRzLg0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAxIExPQUQgTElCUkFSSUVTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAyIFBSRVBBUkUgREFUQQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBtdXRhdGUoDQogICAgUTEyYSA9IGFzLm51bWVyaWMoUTEyYSksDQogICAgUTE3ID0gYXMubnVtZXJpYyhRMTcpDQogICkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgMyBERVNDUklQVElWRSBTVEFUSVNUSUNTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpzdW1tYXJ5X3N0YXRzIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBtZWFuX3NlY3VyaXR5ID0gbWVhbihRMTJhLCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkX3NlY3VyaXR5ID0gc2QoUTEyYSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuX0FJX2Fkb3B0aW9uID0gbWVhbihRMTcsIG5hLnJtID0gVFJVRSksDQogICAgc2RfQUlfYWRvcHRpb24gPSBzZChRMTcsIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQpwcmludChzdW1tYXJ5X3N0YXRzKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyA0IENPUlJFTEFUSU9OIFRFU1QgKFNwZWFybWFuIGZvciBvcmRpbmFsIGRhdGEpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjb3JyZWxhdGlvbl90ZXN0IDwtIGNvci50ZXN0KA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmEsDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTE3LA0KICBtZXRob2QgPSAic3BlYXJtYW4iLA0KICB1c2UgPSAiY29tcGxldGUub2JzIg0KKQ0KDQpwcmludChjb3JyZWxhdGlvbl90ZXN0KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyA1IFZJU1VBTElaQVRJT04NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmdncGxvdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCBhZXMoeCA9IFExMmEsIHkgPSBRMTcpKSArDQogIGdlb21faml0dGVyKGFscGhhID0gMC40KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSZWxhdGlvbnNoaXAgQmV0d2VlbiBTZWN1cml0eSBJbXBvcnRhbmNlIGFuZCBBSSBBZ2VudCBBZG9wdGlvbiIsDQogICAgeCA9ICJJbXBvcnRhbmNlIG9mIFNlY3VyaXR5IChRMTJhKSIsDQogICAgeSA9ICJXaWxsaW5nbmVzcyB0byBVc2UgQUkgQmFua2luZyBBZ2VudCAoUTE3KSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBBU1NVTVBUSU9OIENIRUNLUyDigJMgSDJkDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgTm9ybWFsaXR5IHRlc3RzDQpzaGFwaXJvLnRlc3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTJhKQ0Kc2hhcGlyby50ZXN0KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTE3KQ0KDQojIEhpc3RvZ3JhbXMNCmdncGxvdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCBhZXMoeCA9IFExMmEpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gUTE3KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgUVEgcGxvdHMNCnFxbm9ybShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmEpDQpxcWxpbmUoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTJhKQ0KDQpxcW5vcm0oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTcpDQpxcWxpbmUoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTcpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgU1BFQVJNQU4gQ09SUkVMQVRJT04NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY29yLnRlc3QoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTEyYSwNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTcsDQogIG1ldGhvZCA9ICJzcGVhcm1hbiINCikNCmBgYA0KDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgSFlQT1RIRVNJUyBURVNUIOKAkyBIMmUNCiMgQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMgcGVyY2VpdmUgbGVzcyBmaW5hbmNpYWwNCiMgc3RyZXNzIHRoYW4gY2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyBhbmQgZmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycw0KIyBWYXJpYWJsZTogUTViDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIGVuc3VyZSBjbHVzdGVyIGlzIGZhY3Rvcg0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyIDwtIGFzLmZhY3RvcihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIpDQoNCiMgY29udmVydCBMaWtlcnQgdmFyaWFibGUgdG8gbnVtZXJpYw0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBtdXRhdGUoUTViID0gYXMubnVtZXJpYyhRNWIpKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAxIERFU0NSSVBUSVZFIFNUQVRJU1RJQ1MNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmNsdXN0ZXJfc3VtbWFyeV9RNWIgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW4gPSBtZWFuKFE1YiwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWRpYW4gPSBtZWRpYW4oUTViLCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkID0gc2QoUTViLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbiA9IG1pbihRNWIsIG5hLnJtID0gVFJVRSksDQogICAgbWF4ID0gbWF4KFE1YiwgbmEucm0gPSBUUlVFKQ0KICApDQoNCnByaW50KGNsdXN0ZXJfc3VtbWFyeV9RNWIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDIgS1JVU0tBTC1XQUxMSVMgVEVTVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbF90ZXN0X1E1YiA8LSBrcnVza2FsLnRlc3QoUTViIH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQoNCnByaW50KGtydXNrYWxfdGVzdF9RNWIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDMgUE9TVC1IT0MgVEVTVCAoUEFJUldJU0UgQ09NUEFSSVNPTikNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCnBhaXJ3aXNlX3Jlc3VsdHNfUTViIDwtIHBhaXJ3aXNlLndpbGNveC50ZXN0KA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFE1YiwNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyLA0KICBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSINCikNCg0KcHJpbnQocGFpcndpc2VfcmVzdWx0c19RNWIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDQgVklTVUFMSVpBVElPTg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gY2x1c3RlciwgeSA9IFE1YikpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlcmNlaXZlZCBGaW5hbmNpYWwgU3RyZXNzIGJ5IENsdXN0ZXIiLA0KICAgIHggPSAiQ2x1c3RlciIsDQogICAgeSA9ICJGaW5hbmNpYWwgU3RyZXNzIChRNWIpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEFTU1VNUFRJT04gQ0hFQ0tTIOKAkyBIMmUNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Kc2hhcGlyby50ZXN0KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTViKQ0KDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBRNWIpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KcXFub3JtKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTViKQ0KcXFsaW5lKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTViKQ0KDQpsZXZlbmVUZXN0KFE1YiB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEtSVVNLQUwtV0FMTElTIFRFU1QNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbC50ZXN0KFE1YiB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81KQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocnN0YXRpeCkNCg0KZWZmZWN0X3NpemVfUTViIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIGtydXNrYWxfZWZmc2l6ZShRNWIgfiBjbHVzdGVyKQ0KDQpwcmludChlZmZlY3Rfc2l6ZV9RNWIpDQpgYGANCg0KDQojI0gyZg0KDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgQ0xFQU4gREFUQSAoUkVNT1ZFIElOVkFMSUQgQU5EIE1JU1NJTkcgVkFMVUVTKQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpkYXRhX2NsZWFuIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIG11dGF0ZShRMTkgPSBhcy5udW1lcmljKFExOSkpICU+JSAgICMgZW5zdXJlIG51bWVyaWMNCiAgZmlsdGVyKFExOSA+PSAxKSAgICAgICAgICAgICAgICAgICAgIyByZW1vdmUgaW52YWxpZCB2YWx1ZXMgKDwxKSBhbmQgTkENCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBERVNDUklQVElWRSBTVEFUSVNUSUNTIEJZIENMVVNURVINCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2x1c3Rlcl9zdW1tYXJ5X1ExOSA8LSBkYXRhX2NsZWFuICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG4gPSBuKCksDQogICAgbWVhbiA9IG1lYW4oUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbiA9IG1lZGlhbihRMTksIG5hLnJtID0gVFJVRSksDQogICAgc2QgPSBzZChRMTksIG5hLnJtID0gVFJVRSksDQogICAgbWluID0gbWluKFExOSwgbmEucm0gPSBUUlVFKSwNCiAgICBtYXggPSBtYXgoUTE5LCBuYS5ybSA9IFRSVUUpDQogICkNCg0KcHJpbnQoY2x1c3Rlcl9zdW1tYXJ5X1ExOSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBLUlVTS0FMLVdBTExJUyBURVNUDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmtydXNrYWxfdGVzdF9RMTkgPC0ga3J1c2thbC50ZXN0KFExOSB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsZWFuKQ0KDQpwcmludChrcnVza2FsX3Rlc3RfUTE5KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIFBBSVJXSVNFIFdJTENPWE9OIFRFU1QNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KcGFpcndpc2VfcmVzdWx0c19RMTkgPC0gcGFpcndpc2Uud2lsY294LnRlc3QoDQogIGRhdGFfY2xlYW4kUTE5LA0KICBkYXRhX2NsZWFuJGNsdXN0ZXIsDQogIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIg0KKQ0KDQpwcmludChwYWlyd2lzZV9yZXN1bHRzX1ExOSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBWSVNVQUxJWkFUSU9ODQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IGNsdXN0ZXIsIHkgPSBRMTkpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJXaWxsaW5nbmVzcyB0byBQYXkgZm9yIEFJIEJhbmtpbmcgQXNzaXN0YW50IGJ5IENsdXN0ZXIiLA0KICAgIHggPSAiQ2x1c3RlciIsDQogICAgeSA9ICJNb250aGx5IFdpbGxpbmduZXNzIHRvIFBheSAo4oKsKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEFTU1VNUFRJT04gQ0hFQ0tTIOKAkyBIMmYNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Kc2hhcGlyby50ZXN0KGRhdGFfY2xlYW4kUTE5KQ0KDQpnZ3Bsb3QoZGF0YV9jbGVhbiwgYWVzKHggPSBRMTkpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KcXFub3JtKGRhdGFfY2xlYW4kUTE5KQ0KcXFsaW5lKGRhdGFfY2xlYW4kUTE5KQ0KDQpsZXZlbmVUZXN0KFExOSB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsZWFuKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEtSVVNLQUwtV0FMTElTIFRFU1QNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbC50ZXN0KFExOSB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsZWFuKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmRmIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUNCmBgYA0KDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgS1JVU0tBTC1XQUxMSVMgVEVTVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsX3Rlc3RfUTE5IDwtIGtydXNrYWwudGVzdChRMTkgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbGVhbikNCnByaW50KGtydXNrYWxfdGVzdF9RMTkpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgRUZGRUNUIFNJWkUNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KbGlicmFyeShyc3RhdGl4KQ0KDQplZmZlY3Rfc2l6ZV9RMTkgPC0gZGF0YV9jbGVhbiAlPiUNCiAga3J1c2thbF9lZmZzaXplKFExOSB+IGNsdXN0ZXIpDQoNCnByaW50KGVmZmVjdF9zaXplX1ExOSkNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShyc3RhdGl4KQ0KbGlicmFyeShjb2luKQ0KbGlicmFyeShwdXJycikNCg0KZGF0YV9jbGVhbiA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGFzLmZhY3RvcihjbHVzdGVyKSwNCiAgICBRMTkgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihRMTkpKQ0KICApICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGNsdXN0ZXIpLCAhaXMubmEoUTE5KSwgUTE5ID49IDEpDQoNCmNsdXN0ZXJfcGFpcnMgPC0gY29tYm4obGV2ZWxzKGRhdGFfY2xlYW4kY2x1c3RlciksIDIsIHNpbXBsaWZ5ID0gRkFMU0UpDQoNCnBhaXJ3aXNlX2VmZmVjdHNfUTE5IDwtIG1hcF9kZnIoY2x1c3Rlcl9wYWlycywgZnVuY3Rpb24oeCkgew0KICB0bXAgPC0gZGF0YV9jbGVhbiAlPiUNCiAgICBmaWx0ZXIoY2x1c3RlciAlaW4lIHgpICU+JQ0KICAgIGRyb3BsZXZlbHMoKQ0KDQogIHdpbGNveF9lZmZzaXplKGRhdGEgPSB0bXAsIFExOSB+IGNsdXN0ZXIpICU+JQ0KICAgIG11dGF0ZShjb21wYXJpc29uID0gcGFzdGUoeCwgY29sbGFwc2UgPSAiIHZzICIpKQ0KfSkNCg0KcHJpbnQocGFpcndpc2VfZWZmZWN0c19RMTkpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpkZiA8LSBkZiB8Pg0KICBtdXRhdGUoDQogICAgYWNyb3NzKGMoUTEwYSwgUTEwYiwgUTEwYywgUTEwZCwNCiAgICAgICAgICAgICBRMTFhLCBRMTFiLCBRMTFjLCBRMTFkLCBRMTFlLCBRMTFmLA0KICAgICAgICAgICAgIFExNyksIGFzLm51bWVyaWMpLA0KDQogICAgbG93X3Jpc2tfZGVsZWdhdGUgID0gcm93TWVhbnMocGljayhRMTFhLCBRMTFiLCBRMTFmKSwgbmEucm0gPSBUUlVFKSwNCiAgICBoaWdoX3Jpc2tfZGVsZWdhdGUgPSByb3dNZWFucyhwaWNrKFExMWMsIFExMWQsIFExMWUpLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgY29uZmlybV9yZXF1aXJlZCAgID0gUTEwYywNCiAgICBhdXRvbm9tb3VzX2RlY2lzaW9ucyA9IFExMGQsDQoNCiAgICB0cnVzdF9haSA9IHJvd01lYW5zKHBpY2soUTEwYSwgUTEwYiwgUTEwYywgUTEwZCksIG5hLnJtID0gVFJVRSksDQogICAgaW50ZW50aW9uX3VzZSA9IFExNw0KICApDQoNCmRmJGNsdXN0ZXIgPC0gZmFjdG9yKGRmJGNsdXN0ZXIpDQp0YWJsZShkZiRjbHVzdGVyKQ0KYGBgDQoNCg0KIyBNaW4gYW5kIG1heA0KYGBge3J9DQpkZiB8Pg0KICBzdW1tYXJpc2UoDQogICAgaDFhX2xvd19taW4gPSBtaW4obG93X3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgaDFhX2xvd19tYXggPSBtYXgobG93X3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgaDFhX2hpZ2hfbWluID0gbWluKGhpZ2hfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBoMWFfaGlnaF9tYXggPSBtYXgoaGlnaF9yaXNrX2RlbGVnYXRlLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgaDFiX2NvbmZpcm1fbWluID0gbWluKGNvbmZpcm1fcmVxdWlyZWQsIG5hLnJtID0gVFJVRSksDQogICAgaDFiX2NvbmZpcm1fbWF4ID0gbWF4KGNvbmZpcm1fcmVxdWlyZWQsIG5hLnJtID0gVFJVRSksDQogICAgaDFiX2F1dG9fbWluID0gbWluKGF1dG9ub21vdXNfZGVjaXNpb25zLCBuYS5ybSA9IFRSVUUpLA0KICAgIGgxYl9hdXRvX21heCA9IG1heChhdXRvbm9tb3VzX2RlY2lzaW9ucywgbmEucm0gPSBUUlVFKSwNCg0KICAgIGgyYV90cnVzdF9taW4gPSBtaW4odHJ1c3RfYWksIG5hLnJtID0gVFJVRSksDQogICAgaDJhX3RydXN0X21heCA9IG1heCh0cnVzdF9haSwgbmEucm0gPSBUUlVFKSwNCg0KICAgIGgyY19pbnRlbnRpb25fbWluID0gbWluKGludGVudGlvbl91c2UsIG5hLnJtID0gVFJVRSksDQogICAgaDJjX2ludGVudGlvbl9tYXggPSBtYXgoaW50ZW50aW9uX3VzZSwgbmEucm0gPSBUUlVFKQ0KICApDQpgYGANCg0KDQojIyBIMWENCmBgYHtyfQ0KaDFhX3Jlc3VsdHMgPC0gZGYgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgZG8oew0KICAgIHN1YiA8LSAuDQogICAgdGVzdCA8LSB0LnRlc3Qoc3ViJGxvd19yaXNrX2RlbGVnYXRlLCBzdWIkaGlnaF9yaXNrX2RlbGVnYXRlLCBwYWlyZWQgPSBUUlVFKQ0KDQogICAgdGliYmxlKA0KICAgICAgbiA9IG5yb3coc3ViKSwNCiAgICAgIGxvd19tZWFuID0gbWVhbihzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgICBoaWdoX21lYW4gPSBtZWFuKHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgICB0X3ZhbHVlID0gdW5uYW1lKHRlc3Qkc3RhdGlzdGljKSwNCiAgICAgIHBfdmFsdWUgPSB0ZXN0JHAudmFsdWUNCiAgICApDQogIH0pDQoNCmgxYV9yZXN1bHRzDQpgYGANCg0KYGBge3J9DQpkZiA8LSBkZiB8Pg0KICBtdXRhdGUoDQogICAgaDFhX2RpZmYgPSBsb3dfcmlza19kZWxlZ2F0ZSAtIGhpZ2hfcmlza19kZWxlZ2F0ZQ0KICApDQpgYGANCg0KIyBOb3JtYWxpdHkNCmBgYHtyfQ0KYnkoZGYkaDFhX2RpZmYsIGRmJGNsdXN0ZXIsIHNoYXBpcm8udGVzdCkNCmBgYA0KDQoNCiMgV2lsY294b24gc2lnbmVkLXJhbmsNCmBgYHtyfQ0KaDFhX3dpbGNveF9yZXN1bHRzIDwtIGRmIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIGRvKHsNCiAgICBzdWIgPC0gLg0KICAgIHRlc3QgPC0gd2lsY294LnRlc3Qoc3ViJGxvd19yaXNrX2RlbGVnYXRlLCBzdWIkaGlnaF9yaXNrX2RlbGVnYXRlLCBwYWlyZWQgPSBUUlVFKQ0KDQogICAgdGliYmxlKA0KICAgICAgbiA9IG5yb3coc3ViKSwNCiAgICAgIGxvd19tZWFuID0gbWVhbihzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgICBoaWdoX21lYW4gPSBtZWFuKHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlDQogICAgKQ0KICB9KQ0KDQpoMWFfd2lsY294X3Jlc3VsdHMNCmBgYA0KDQpgYGB7cn0NCmgxYV9maW5hbF9yZXN1bHRzIDwtIGRmIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIGRvKHsNCiAgICBzdWIgPC0gLg0KICAgIA0KICAgIHRfcmVzIDwtIHQudGVzdChzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIHBhaXJlZCA9IFRSVUUpDQogICAgd19yZXMgPC0gd2lsY294LnRlc3Qoc3ViJGxvd19yaXNrX2RlbGVnYXRlLCBzdWIkaGlnaF9yaXNrX2RlbGVnYXRlLCBwYWlyZWQgPSBUUlVFKQ0KICAgIA0KICAgIGRpZmYgPC0gc3ViJGxvd19yaXNrX2RlbGVnYXRlIC0gc3ViJGhpZ2hfcmlza19kZWxlZ2F0ZQ0KICAgIGRpZmYgPC0gZGlmZlshaXMubmEoZGlmZildDQogICAgDQogICAgZHogPC0gaWYgKHNkKGRpZmYpID09IDApIE5BX3JlYWxfIGVsc2UgbWVhbihkaWZmKSAvIHNkKGRpZmYpDQogICAgDQogICAgZGlmZl9ueiA8LSBkaWZmW2RpZmYgIT0gMF0NCiAgICBpZiAobGVuZ3RoKGRpZmZfbnopID09IDApIHsNCiAgICAgIHJiYyA8LSBOQV9yZWFsXw0KICAgIH0gZWxzZSB7DQogICAgICByYW5rcyA8LSByYW5rKGFicyhkaWZmX256KSkNCiAgICAgIFdfcG9zIDwtIHN1bShyYW5rc1tkaWZmX256ID4gMF0pDQogICAgICBXX25lZyA8LSBzdW0ocmFua3NbZGlmZl9ueiA8IDBdKQ0KICAgICAgcmJjIDwtIChXX3BvcyAtIFdfbmVnKSAvIChXX3BvcyArIFdfbmVnKQ0KICAgIH0NCg0KICAgIHRpYmJsZSgNCiAgICAgIG4gPSBsZW5ndGgoZGlmZiksDQogICAgICBsb3dfbWVhbiA9IG1lYW4oc3ViJGxvd19yaXNrX2RlbGVnYXRlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgaGlnaF9tZWFuID0gbWVhbihzdWIkaGlnaF9yaXNrX2RlbGVnYXRlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbl9kaWZmID0gbWVhbihkaWZmKSwNCiAgICAgIHRfdmFsdWUgPSB1bm5hbWUodF9yZXMkc3RhdGlzdGljKSwNCiAgICAgIHRfcF92YWx1ZSA9IHRfcmVzJHAudmFsdWUsDQogICAgICB3aWxjb3hfcF92YWx1ZSA9IHdfcmVzJHAudmFsdWUsDQogICAgICBjb2hlbl9keiA9IGR6LA0KICAgICAgcmFua19iaXNlcmlhbCA9IHJiYw0KICAgICkNCiAgfSkNCg0KaDFhX2ZpbmFsX3Jlc3VsdHMNCmBgYA0KDQoNCiMjIEgxYg0KYGBge3J9DQpoMWJfcmVzdWx0cyA8LSBkZiB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBkbyh7DQogICAgc3ViIDwtIC4NCiAgICB0ZXN0IDwtIHQudGVzdChzdWIkY29uZmlybV9yZXF1aXJlZCwgc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zLCBwYWlyZWQgPSBUUlVFKQ0KDQogICAgdGliYmxlKA0KICAgICAgbiA9IG5yb3coc3ViKSwNCiAgICAgIGNvbmZpcm1fbWVhbiA9IG1lYW4oc3ViJGNvbmZpcm1fcmVxdWlyZWQsIG5hLnJtID0gVFJVRSksDQogICAgICBhdXRvbm9tb3VzX21lYW4gPSBtZWFuKHN1YiRhdXRvbm9tb3VzX2RlY2lzaW9ucywgbmEucm0gPSBUUlVFKSwNCiAgICAgIHRfdmFsdWUgPSB1bm5hbWUodGVzdCRzdGF0aXN0aWMpLA0KICAgICAgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZQ0KICAgICkNCiAgfSkNCg0KaDFiX3Jlc3VsdHMNCmBgYA0KDQpgYGB7cn0NCmRmIDwtIGRmIHw+DQogIG11dGF0ZSgNCiAgICBoMWJfZGlmZiA9IGNvbmZpcm1fcmVxdWlyZWQgLSBhdXRvbm9tb3VzX2RlY2lzaW9ucw0KICApDQpgYGANCg0KDQojIE5vcm1hbGl0eSBieSBjbHVzdGVyDQpgYGB7cn0NCmJ5KGRmJGgxYl9kaWZmLCBkZiRjbHVzdGVyLCBzaGFwaXJvLnRlc3QpDQpgYGANCg0KIyBXaWxjb3hvbiBzaWduZWQtcmFuaw0KYGBge3J9DQpoMWJfd2lsY294X3Jlc3VsdHMgPC0gZGYgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgZG8oew0KICAgIHN1YiA8LSAuDQogICAgdGVzdCA8LSB3aWxjb3gudGVzdCgNCiAgICAgIHN1YiRjb25maXJtX3JlcXVpcmVkLA0KICAgICAgc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zLA0KICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgIGV4YWN0ID0gRkFMU0UNCiAgICApDQoNCiAgICB0aWJibGUoDQogICAgICBuID0gbnJvdyhzdWIpLA0KICAgICAgY29uZmlybV9tZWFuID0gbWVhbihzdWIkY29uZmlybV9yZXF1aXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgIGF1dG9ub21vdXNfbWVhbiA9IG1lYW4oc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZQ0KICAgICkNCiAgfSkNCg0KaDFiX3dpbGNveF9yZXN1bHRzDQpgYGANCg0KYGBge3J9DQpoMWJfZmluYWxfcmVzdWx0cyA8LSBkZiB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBkbyh7DQogICAgc3ViIDwtIC4NCiAgICANCiAgICB0X3JlcyA8LSB0LnRlc3Qoc3ViJGNvbmZpcm1fcmVxdWlyZWQsIHN1YiRhdXRvbm9tb3VzX2RlY2lzaW9ucywgcGFpcmVkID0gVFJVRSkNCiAgICB3X3JlcyA8LSB3aWxjb3gudGVzdCgNCiAgICAgIHN1YiRjb25maXJtX3JlcXVpcmVkLA0KICAgICAgc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zLA0KICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgIGV4YWN0ID0gRkFMU0UNCiAgICApDQogICAgDQogICAgZGlmZiA8LSBzdWIkY29uZmlybV9yZXF1aXJlZCAtIHN1YiRhdXRvbm9tb3VzX2RlY2lzaW9ucw0KICAgIGRpZmYgPC0gZGlmZlshaXMubmEoZGlmZildDQogICAgDQogICAgZHogPC0gaWYgKHNkKGRpZmYpID09IDApIE5BX3JlYWxfIGVsc2UgbWVhbihkaWZmKSAvIHNkKGRpZmYpDQogICAgDQogICAgZGlmZl9ueiA8LSBkaWZmW2RpZmYgIT0gMF0NCiAgICBpZiAobGVuZ3RoKGRpZmZfbnopID09IDApIHsNCiAgICAgIHJiYyA8LSBOQV9yZWFsXw0KICAgIH0gZWxzZSB7DQogICAgICByYW5rcyA8LSByYW5rKGFicyhkaWZmX256KSkNCiAgICAgIFdfcG9zIDwtIHN1bShyYW5rc1tkaWZmX256ID4gMF0pDQogICAgICBXX25lZyA8LSBzdW0ocmFua3NbZGlmZl9ueiA8IDBdKQ0KICAgICAgcmJjIDwtIChXX3BvcyAtIFdfbmVnKSAvIChXX3BvcyArIFdfbmVnKQ0KICAgIH0NCg0KICAgIHRpYmJsZSgNCiAgICAgIG4gPSBsZW5ndGgoZGlmZiksDQogICAgICBjb25maXJtX21lYW4gPSBtZWFuKHN1YiRjb25maXJtX3JlcXVpcmVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgYXV0b25vbW91c19tZWFuID0gbWVhbihzdWIkYXV0b25vbW91c19kZWNpc2lvbnMsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuX2RpZmYgPSBtZWFuKGRpZmYpLA0KICAgICAgdF92YWx1ZSA9IHVubmFtZSh0X3JlcyRzdGF0aXN0aWMpLA0KICAgICAgdF9wX3ZhbHVlID0gdF9yZXMkcC52YWx1ZSwNCiAgICAgIHdpbGNveF9wX3ZhbHVlID0gd19yZXMkcC52YWx1ZSwNCiAgICAgIGNvaGVuX2R6ID0gZHosDQogICAgICByYW5rX2Jpc2VyaWFsID0gcmJjDQogICAgKQ0KICB9KQ0KDQpoMWJfZmluYWxfcmVzdWx0cw0KYGBgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KDQojIG1ha2Ugc3VyZSB2YXJpYWJsZXMgYXJlIGluIHRoZSByaWdodCBmb3JtYXQNCmRmJGNsdXN0ZXIgPC0gYXMuZmFjdG9yKGRmJGNsdXN0ZXIpDQpkZiR0cnVzdF9haSA8LSBhcy5udW1lcmljKGRmJHRydXN0X2FpKQ0KDQojIyBIMmENCmgyYV9tb2RlbCA8LSBhb3YodHJ1c3RfYWkgfiBjbHVzdGVyLCBkYXRhID0gZGYpDQpzdW1tYXJ5KGgyYV9tb2RlbCkNCg0KIyBQb3N0LWhvYyBvcHRpb24gMTogVHVrZXkNClR1a2V5SFNEKGgyYV9tb2RlbCkNCg0KIyBQb3N0LWhvYyBvcHRpb24gMjogcGFpcndpc2UgdC10ZXN0cyB3aXRoIEJvbmZlcnJvbmkNCnBhaXJ3aXNlLnQudGVzdCgNCiAgeCA9IGRmJHRydXN0X2FpLA0KICBnID0gZGYkY2x1c3RlciwNCiAgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiDQopDQoNCiMgRGVzY3JpcHRpdmUgbWVhbnMNCmFnZ3JlZ2F0ZSh0cnVzdF9haSB+IGNsdXN0ZXIsIGRhdGEgPSBkZiwgbWVhbiwgbmEucm0gPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiZWZmZWN0c2l6ZSIpDQpsaWJyYXJ5KGVmZmVjdHNpemUpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGVmZmVjdHNpemUpDQoNCmRmJGNsdXN0ZXIgPC0gYXMuZmFjdG9yKGRmJGNsdXN0ZXIpDQpkZiR0cnVzdF9haSA8LSBhcy5udW1lcmljKGRmJHRydXN0X2FpKQ0KDQojIyBIMmENCmgyYV9tb2RlbCA8LSBhb3YodHJ1c3RfYWkgfiBjbHVzdGVyLCBkYXRhID0gZGYpDQpzdW1tYXJ5KGgyYV9tb2RlbCkNCg0KVHVrZXlIU0QoaDJhX21vZGVsKQ0KDQphZ2dyZWdhdGUodHJ1c3RfYWkgfiBjbHVzdGVyLCBkYXRhID0gZGYsIG1lYW4sIG5hLnJtID0gVFJVRSkNCg0KIyBFZmZlY3Qgc2l6ZXMNCmV0YV9zcXVhcmVkKGgyYV9tb2RlbCkNCm9tZWdhX3NxdWFyZWQoaDJhX21vZGVsKQ0KYGBgDQpgYGB7cn0NCmgyYV9ldGEgPC0gZXRhX3NxdWFyZWQoaDJhX21vZGVsKQ0KcHJpbnQoaDJhX2V0YSkNCg0KaDJhX29tZWdhIDwtIG9tZWdhX3NxdWFyZWQoaDJhX21vZGVsKQ0KcHJpbnQoaDJhX29tZWdhKQ0KYGBgDQoNCg0KIyMgSDJjDQpgYGB7cn0NCmgyY19yZXN1bHRzIDwtIGxhcHBseShsZXZlbHMoZGYkY2x1c3RlciksIGZ1bmN0aW9uKGNsKSB7DQogIHN1YiA8LSBkZiB8Pg0KICAgIGZpbHRlcihjbHVzdGVyID09IGNsKQ0KDQogIG1vZGVsIDwtIGxtKGludGVudGlvbl91c2UgfiB0cnVzdF9haSwgZGF0YSA9IHN1YikNCiAgY29lZnMgPC0gc3VtbWFyeShtb2RlbCkkY29lZmZpY2llbnRzDQoNCiAgdGliYmxlKA0KICBjbHVzdGVyID0gY2wsDQogIGJfdHJ1c3QgPSBjb2Vmc1sidHJ1c3RfYWkiLCAiRXN0aW1hdGUiXSwNCiAgcF92YWx1ZSA9IGNvZWZzWyJ0cnVzdF9haSIsICJQcig+fHR8KSJdLA0KICByX3NxdWFyZWQgPSBzdW1tYXJ5KG1vZGVsKSRyLnNxdWFyZWQNCikNCn0pIHw+DQogIGJpbmRfcm93cygpDQoNCmgyY19yZXN1bHRzDQpgYGANCg0KIyBOb3JtYWxpdHkgb2YgcmVncmVzc2lvbiByZXNpZHVhbHMgYnkgY2x1c3Rlcg0KDQpgYGB7cn0NCmZvcihjbCBpbiBsZXZlbHMoZGYkY2x1c3RlcikpIHsNCiAgc3ViIDwtIGRmIHw+DQogICAgZmlsdGVyKGNsdXN0ZXIgPT0gY2wpDQoNCiAgbW9kZWwgPC0gbG0oaW50ZW50aW9uX3VzZSB+IHRydXN0X2FpLCBkYXRhID0gc3ViKQ0KDQogIGNhdCgiXG49PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiIpDQogIGNhdCgiQ0xVU1RFUjoiLCBjbCwgIlxuIikNCiAgY2F0KCI9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiIpDQogIHByaW50KHNoYXBpcm8udGVzdChyZXNpZHVhbHMobW9kZWwpKSkNCn0NCmBgYA0KDQojIyBTcGVhcm1hbiB0ZXN0DQpgYGB7cn0NCmgyY19zcGVhcm1hbiA8LSBsYXBwbHkobGV2ZWxzKGRmJGNsdXN0ZXIpLCBmdW5jdGlvbihjbCkgew0KICBzdWIgPC0gZGYgfD4NCiAgICBmaWx0ZXIoY2x1c3RlciA9PSBjbCkNCg0KICB0ZXN0IDwtIGNvci50ZXN0KHN1YiR0cnVzdF9haSwgc3ViJGludGVudGlvbl91c2UsIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQoNCiAgdGliYmxlKA0KICAgIGNsdXN0ZXIgPSBjbCwNCiAgICByaG8gPSB1bm5hbWUodGVzdCRlc3RpbWF0ZSksDQogICAgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZQ0KICApDQp9KSB8Pg0KICBiaW5kX3Jvd3MoKQ0KDQpoMmNfc3BlYXJtYW4NCmBgYA0KDQpgYGB7cn0NCmgyY19yZXN1bHRzIDwtIGxhcHBseShsZXZlbHMoZGYkY2x1c3RlciksIGZ1bmN0aW9uKGNsKSB7DQogIHN1YiA8LSBkZiB8Pg0KICAgIGZpbHRlcihjbHVzdGVyID09IGNsKQ0KDQogIG1vZGVsIDwtIGxtKGludGVudGlvbl91c2UgfiB0cnVzdF9haSwgZGF0YSA9IHN1YikNCiAgY29lZnMgPC0gc3VtbWFyeShtb2RlbCkkY29lZmZpY2llbnRzDQoNCiAgdGliYmxlKA0KICAgIGNsdXN0ZXIgPSBjbCwNCiAgICBiX3RydXN0ID0gY29lZnNbInRydXN0X2FpIiwgIkVzdGltYXRlIl0sDQogICAgcF92YWx1ZSA9IGNvZWZzWyJ0cnVzdF9haSIsICJQcig+fHR8KSJdLA0KICAgIHJfc3F1YXJlZCA9IHN1bW1hcnkobW9kZWwpJHIuc3F1YXJlZCwNCiAgICBhZGpfcl9zcXVhcmVkID0gc3VtbWFyeShtb2RlbCkkYWRqLnIuc3F1YXJlZA0KICApDQp9KSB8Pg0KICBiaW5kX3Jvd3MoKQ0KDQpoMmNfcmVzdWx0cw0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHB1cnJyKQ0KbGlicmFyeSh0aWJibGUpDQoNCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3Rlcl9uYW1lZCA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApDQpgYGANCg0KYGBge3J9DQpiYW5rX2xhYmVscyA8LSBjKA0KICBhID0gIk9UUCIsDQogIGIgPSAiR29yZW5qc2thIEJhbmthIiwNCiAgYyA9ICJOTEIiLA0KICBkID0gIlJldm9sdXQiLA0KICBlID0gIk4yNiIsDQogIGYgPSAiSW50ZXNhIFNhblBhb2xvIiwNCiAgZyA9ICJVbmlDcmVkaXQiDQopDQoNCnJ1bl9iYW5rX3BhaXJ3aXNlX3Rlc3RzIDwtIGZ1bmN0aW9uKGRhdGEsIGNsdXN0ZXJfbmFtZSkgew0KICANCiAgc3Vic2V0X2RhdGEgPC0gZGF0YSB8Pg0KICAgIGZpbHRlcihjbHVzdGVyX25hbWVkID09IGNsdXN0ZXJfbmFtZSkgfD4NCiAgICBtdXRhdGUoYWNyb3NzKFExM2E6UTE1ZywgYXMubnVtZXJpYykpDQogIA0KICBjb21wYXJlX2RpbWVuc2lvbiA8LSBmdW5jdGlvbihkZiwgdmFycywgZGltZW5zaW9uX25hbWUpIHsNCiAgICANCiAgICBwYWlycyA8LSBjb21ibih2YXJzLCAyLCBzaW1wbGlmeSA9IEZBTFNFKQ0KICAgIA0KICAgIHJlc3VsdHMgPC0gbGFwcGx5KHBhaXJzLCBmdW5jdGlvbihwYWlyKSB7DQogICAgICB2MSA8LSBwYWlyWzFdDQogICAgICB2MiA8LSBwYWlyWzJdDQogICAgICANCiAgICAgIHggPC0gZGZbW3YxXV0NCiAgICAgIHkgPC0gZGZbW3YyXV0NCiAgICAgIA0KICAgICAgY29tcGxldGVfaWR4IDwtIGNvbXBsZXRlLmNhc2VzKHgsIHkpDQogICAgICB4IDwtIHhbY29tcGxldGVfaWR4XQ0KICAgICAgeSA8LSB5W2NvbXBsZXRlX2lkeF0NCiAgICAgIA0KICAgICAgdGVzdCA8LSB3aWxjb3gudGVzdCh4LCB5LCBwYWlyZWQgPSBUUlVFLCBleGFjdCA9IEZBTFNFKQ0KICAgICAgDQogICAgICB0aWJibGUoDQogICAgICAgIGNsdXN0ZXIgPSBjbHVzdGVyX25hbWUsDQogICAgICAgIGRpbWVuc2lvbiA9IGRpbWVuc2lvbl9uYW1lLA0KICAgICAgICBiYW5rXzEgPSBiYW5rX2xhYmVsc1tzdWJzdHIodjEsIG5jaGFyKHYxKSwgbmNoYXIodjEpKV0sDQogICAgICAgIGJhbmtfMiA9IGJhbmtfbGFiZWxzW3N1YnN0cih2MiwgbmNoYXIodjIpLCBuY2hhcih2MikpXSwNCiAgICAgICAgbiA9IGxlbmd0aCh4KSwNCiAgICAgICAgbWVhbl9iYW5rXzEgPSBtZWFuKHgsIG5hLnJtID0gVFJVRSksDQogICAgICAgIG1lYW5fYmFua18yID0gbWVhbih5LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlDQogICAgICApDQogICAgfSkNCiAgICANCiAgICBiaW5kX3Jvd3MocmVzdWx0cykgfD4NCiAgICAgIG11dGF0ZSgNCiAgICAgICAgcF9hZGp1c3RlZCA9IHAuYWRqdXN0KHBfdmFsdWUsIG1ldGhvZCA9ICJib25mZXJyb25pIiksDQogICAgICAgIHNpZ25pZmljYW50ID0gaWZlbHNlKHBfYWRqdXN0ZWQgPCAwLjA1LCAiWWVzIiwgIk5vIikNCiAgICAgICkgfD4NCiAgICAgIGFycmFuZ2UocF9hZGp1c3RlZCkNCiAgfQ0KICANCiAgaW5ub3ZhdGlvbl9yZXN1bHRzIDwtIGNvbXBhcmVfZGltZW5zaW9uKA0KICAgIHN1YnNldF9kYXRhLA0KICAgIHZhcnMgPSBjKCJRMTNhIiwgIlExM2IiLCAiUTEzYyIsICJRMTNkIiwgIlExM2UiLCAiUTEzZiIsICJRMTNnIiksDQogICAgZGltZW5zaW9uX25hbWUgPSAiSW5ub3ZhdGlvbiINCiAgKQ0KICANCiAgc3VwcG9ydF9yZXN1bHRzIDwtIGNvbXBhcmVfZGltZW5zaW9uKA0KICAgIHN1YnNldF9kYXRhLA0KICAgIHZhcnMgPSBjKCJRMTRhIiwgIlExNGIiLCAiUTE0YyIsICJRMTRkIiwgIlExNGUiLCAiUTE0ZiIsICJRMTRnIiksDQogICAgZGltZW5zaW9uX25hbWUgPSAiQ3VzdG9tZXIgc3VwcG9ydCINCiAgKQ0KICANCiAgcmVsaWFiaWxpdHlfcmVzdWx0cyA8LSBjb21wYXJlX2RpbWVuc2lvbigNCiAgICBzdWJzZXRfZGF0YSwNCiAgICB2YXJzID0gYygiUTE1YSIsICJRMTViIiwgIlExNWMiLCAiUTE1ZCIsICJRMTVlIiwgIlExNWYiLCAiUTE1ZyIpLA0KICAgIGRpbWVuc2lvbl9uYW1lID0gIlJlbGlhYmlsaXR5Ig0KICApDQogIA0KICBiaW5kX3Jvd3MoDQogICAgaW5ub3ZhdGlvbl9yZXN1bHRzLA0KICAgIHN1cHBvcnRfcmVzdWx0cywNCiAgICByZWxpYWJpbGl0eV9yZXN1bHRzDQogICkNCn0NCmBgYA0KDQpgYGB7cn0NCmFsbF9jbHVzdGVyX2JhbmtfdGVzdHMgPC0gYmluZF9yb3dzKA0KICBydW5fYmFua19wYWlyd2lzZV90ZXN0cyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIpLA0KICBydW5fYmFua19wYWlyd2lzZV90ZXN0cyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIpLA0KICBydW5fYmFua19wYWlyd2lzZV90ZXN0cyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIpLA0KICBydW5fYmFua19wYWlyd2lzZV90ZXN0cyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIpLA0KICBydW5fYmFua19wYWlyd2lzZV90ZXN0cyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiKQ0KKQ0KDQphbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzDQpgYGANCg0KYGBge3J9DQphbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzX3NpZyA8LSBhbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzIHw+DQogIGZpbHRlcihwX2FkanVzdGVkIDwgMC4wNSkNCg0KYWxsX2NsdXN0ZXJfYmFua190ZXN0c19zaWcNCmBgYA0KDQpgYGB7cn0NCmFsbF9jbHVzdGVyX2JhbmtfdGVzdHNfc2lnIDwtIGFsbF9jbHVzdGVyX2JhbmtfdGVzdHNfc2lnIHw+DQogIGFycmFuZ2UoY2x1c3RlciwgZGltZW5zaW9uLCBwX2FkanVzdGVkKQ0KDQphbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzX3NpZw0KYGBgDQoNCmBgYHtyfQ0KYWxsX2NsdXN0ZXJfYmFua190ZXN0c19zaWcgfD4NCiAgY291bnQoY2x1c3RlciwgZGltZW5zaW9uKQ0KYGBgDQoNCmBgYHtyfQ0Kd3JpdGUuY3N2KA0KICBhbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzLA0KICAiYWxsX2NsdXN0ZXJfYmFua19wYWlyd2lzZV90ZXN0cy5jc3YiLA0KICByb3cubmFtZXMgPSBGQUxTRQ0KKQ0KDQp3cml0ZS5jc3YoDQogIGFsbF9jbHVzdGVyX2JhbmtfdGVzdHNfc2lnLA0KICAic2lnbmlmaWNhbnRfY2x1c3Rlcl9iYW5rX3BhaXJ3aXNlX3Rlc3RzLmNzdiIsDQogIHJvdy5uYW1lcyA9IEZBTFNFDQopDQpgYGANCg0KYGBge3J9DQojIFJlY3JlYXRlIHJlYWRhYmxlIG91dHB1dCB0YWJsZXMgZnJvbSBhbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzDQoNCmludGVycHJldGFibGVfcmVzdWx0cyA8LSBhbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzIHw+DQogIG11dGF0ZSgNCiAgICBtZWFuX2JhbmtfMSA9IHJvdW5kKG1lYW5fYmFua18xLCAyKSwNCiAgICBtZWFuX2JhbmtfMiA9IHJvdW5kKG1lYW5fYmFua18yLCAyKSwNCiAgICBtZWFuX2RpZmZlcmVuY2UgPSByb3VuZChtZWFuX2JhbmtfMSAtIG1lYW5fYmFua18yLCAyKSwNCiAgICBoaWdoZXJfcmF0ZWRfYmFuayA9IGNhc2Vfd2hlbigNCiAgICAgIG1lYW5fYmFua18xID4gbWVhbl9iYW5rXzIgfiBiYW5rXzEsDQogICAgICBtZWFuX2JhbmtfMiA+IG1lYW5fYmFua18xIH4gYmFua18yLA0KICAgICAgVFJVRSB+ICJFcXVhbCINCiAgICApLA0KICAgIGludGVycHJldGF0aW9uID0gY2FzZV93aGVuKA0KICAgICAgcF9hZGp1c3RlZCA8IDAuMDUgJiBtZWFuX2JhbmtfMSA+IG1lYW5fYmFua18yIH4NCiAgICAgICAgcGFzdGUwKGJhbmtfMSwgIiBpcyByYXRlZCBzaWduaWZpY2FudGx5IGhpZ2hlciB0aGFuICIsIGJhbmtfMiksDQogICAgICBwX2FkanVzdGVkIDwgMC4wNSAmIG1lYW5fYmFua18yID4gbWVhbl9iYW5rXzEgfg0KICAgICAgICBwYXN0ZTAoYmFua18yLCAiIGlzIHJhdGVkIHNpZ25pZmljYW50bHkgaGlnaGVyIHRoYW4gIiwgYmFua18xKSwNCiAgICAgIFRSVUUgfiAiTm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSINCiAgICApLA0KICAgIHBfdmFsdWUgPSByb3VuZChwX3ZhbHVlLCA0KSwNCiAgICBwX2FkanVzdGVkID0gcm91bmQocF9hZGp1c3RlZCwgNCkNCiAgKSB8Pg0KICBhcnJhbmdlKGNsdXN0ZXIsIGRpbWVuc2lvbiwgcF9hZGp1c3RlZCkNCg0Kc2lnbmlmaWNhbnRfcmVzdWx0c19jbGVhbiA8LSBpbnRlcnByZXRhYmxlX3Jlc3VsdHMgfD4NCiAgZmlsdGVyKHBfYWRqdXN0ZWQgPCAwLjA1KSB8Pg0KICBzZWxlY3QoDQogICAgY2x1c3RlciwNCiAgICBkaW1lbnNpb24sDQogICAgYmFua18xLA0KICAgIGJhbmtfMiwNCiAgICBtZWFuX2JhbmtfMSwNCiAgICBtZWFuX2JhbmtfMiwNCiAgICBtZWFuX2RpZmZlcmVuY2UsDQogICAgaGlnaGVyX3JhdGVkX2JhbmssDQogICAgcF92YWx1ZSwNCiAgICBwX2FkanVzdGVkLA0KICAgIGludGVycHJldGF0aW9uDQogICkNCg0KcmVwb3J0X3RhYmxlIDwtIHNpZ25pZmljYW50X3Jlc3VsdHNfY2xlYW4gfD4NCiAgdHJhbnNtdXRlKA0KICAgIENsdXN0ZXIgPSBjbHVzdGVyLA0KICAgIERpbWVuc2lvbiA9IGRpbWVuc2lvbiwNCiAgICBDb21wYXJpc29uID0gcGFzdGUoYmFua18xLCAidnMiLCBiYW5rXzIpLA0KICAgIGBNZWFuIGJhbmsgMWAgPSBtZWFuX2JhbmtfMSwNCiAgICBgTWVhbiBiYW5rIDJgID0gbWVhbl9iYW5rXzIsDQogICAgYE1lYW4gZGlmZmVyZW5jZWAgPSBtZWFuX2RpZmZlcmVuY2UsDQogICAgYEhpZ2hlci1yYXRlZCBiYW5rYCA9IGhpZ2hlcl9yYXRlZF9iYW5rLA0KICAgIGBSYXcgcC12YWx1ZWAgPSBwX3ZhbHVlLA0KICAgIGBBZGp1c3RlZCBwLXZhbHVlYCA9IHBfYWRqdXN0ZWQsDQogICAgSW50ZXJwcmV0YXRpb24gPSBpbnRlcnByZXRhdGlvbg0KICApDQoNCiMgU2hvdyBvdXRwdXRzDQppbnRlcnByZXRhYmxlX3Jlc3VsdHMNCnNpZ25pZmljYW50X3Jlc3VsdHNfY2xlYW4NCnJlcG9ydF90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX2NsdXN0ZXJfYmFua190ZXN0cyB8Pg0KICBtdXRhdGUoDQogICAgbWVhbl9iYW5rXzEgPSByb3VuZChtZWFuX2JhbmtfMSwgMiksDQogICAgbWVhbl9iYW5rXzIgPSByb3VuZChtZWFuX2JhbmtfMiwgMiksDQogICAgcF9hZGp1c3RlZCA9IHJvdW5kKHBfYWRqdXN0ZWQsIDQpLA0KICAgIHJlc3VsdCA9IGNhc2Vfd2hlbigNCiAgICAgIHBfYWRqdXN0ZWQgPCAwLjA1ICYgbWVhbl9iYW5rXzEgPiBtZWFuX2JhbmtfMiB+IHBhc3RlKGJhbmtfMSwgIj4iLCBiYW5rXzIpLA0KICAgICAgcF9hZGp1c3RlZCA8IDAuMDUgJiBtZWFuX2JhbmtfMiA+IG1lYW5fYmFua18xIH4gcGFzdGUoYmFua18yLCAiPiIsIGJhbmtfMSksDQogICAgICBUUlVFIH4gIk5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UiDQogICAgKQ0KICApIHw+DQogIGZpbHRlcihwX2FkanVzdGVkIDwgMC4wNSkgfD4NCiAgc2VsZWN0KGNsdXN0ZXIsIGRpbWVuc2lvbiwgYmFua18xLCBiYW5rXzIsIG1lYW5fYmFua18xLCBtZWFuX2JhbmtfMiwgcF9hZGp1c3RlZCwgcmVzdWx0KSB8Pg0KICBhcnJhbmdlKGNsdXN0ZXIsIGRpbWVuc2lvbiwgcF9hZGp1c3RlZCkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCnExOV9jbHVzdGVyX3N1bW1hcnkgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKSwNCiAgICBRMTkgPSBhcy5udW1lcmljKFExOSkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKFExOSksIFExOSA+PSAxKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgbiA9IG4oKSwNCiAgICBtZWFuX3ExOSA9IG1lYW4oUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbl9xMTkgPSBtZWRpYW4oUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkX3ExOSA9IHNkKFExOSwgbmEucm0gPSBUUlVFKSwNCiAgICBtaW5fcTE5ID0gbWluKFExOSwgbmEucm0gPSBUUlVFKSwNCiAgICBtYXhfcTE5ID0gbWF4KFExOSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIG1lYW5fcTE5ID0gcm91bmQobWVhbl9xMTksIDIpLA0KICAgIG1lZGlhbl9xMTkgPSByb3VuZChtZWRpYW5fcTE5LCAyKSwNCiAgICBzZF9xMTkgPSByb3VuZChzZF9xMTksIDIpDQogICkgfD4NCiAgYXJyYW5nZShkZXNjKG1lYW5fcTE5KSkNCg0KcTE5X2NsdXN0ZXJfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0Ka3J1c2thbC50ZXN0KFExOSB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIFExOSA9IGFzLm51bWVyaWMoUTE5KQ0KICApIHw+DQogIGZpbHRlcighaXMubmEoUTE5KSwgUTE5ID49IDEpDQopDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KDQpubGJfcmV2b2x1dF9uMjZfb3ZlcmxhcCA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIFEyNWMgPSBhcy5udW1lcmljKFEyNWMpLCAgIyBOTEINCiAgICBRMjVkID0gYXMubnVtZXJpYyhRMjVkKSwgICMgUmV2b2x1dA0KICAgIFEyNWUgPSBhcy5udW1lcmljKFEyNWUpICAgIyBOMjYNCiAgKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgY2x1c3Rlcl9uID0gbigpLA0KICAgIG5fbmxiX3Jldm9sdXRfbjI2ID0gc3VtKFEyNWMgPT0gMSAmIFEyNWQgPT0gMSAmIFEyNWUgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBwZXJjZW50X25sYl9yZXZvbHV0X24yNiA9IHJvdW5kKDEwMCAqIG5fbmxiX3Jldm9sdXRfbjI2IC8gY2x1c3Rlcl9uLCAxKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCg0KbmxiX3Jldm9sdXRfbjI2X292ZXJsYXANCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCm5sYl9yZXZvbHV0X24yNl9jb21iaW5hdGlvbnMgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKSwNCiAgICBRMjVjID0gYXMubnVtZXJpYyhRMjVjKSwgICMgTkxCDQogICAgUTI1ZCA9IGFzLm51bWVyaWMoUTI1ZCksICAjIFJldm9sdXQNCiAgICBRMjVlID0gYXMubnVtZXJpYyhRMjVlKSAgICMgTjI2DQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGJhbmtfY29tYm8gPSBjYXNlX3doZW4oDQogICAgICBRMjVjID09IDEgJiBRMjVkID09IDEgJiBRMjVlID09IDEgfiAiTkxCICsgUmV2b2x1dCArIE4yNiIsDQogICAgICBRMjVjID09IDEgJiBRMjVkID09IDEgJiAoaXMubmEoUTI1ZSkgfCBRMjVlICE9IDEpIH4gIk5MQiArIFJldm9sdXQiLA0KICAgICAgUTI1YyA9PSAxICYgUTI1ZSA9PSAxICYgKGlzLm5hKFEyNWQpIHwgUTI1ZCAhPSAxKSB+ICJOTEIgKyBOMjYiLA0KICAgICAgUTI1ZCA9PSAxICYgUTI1ZSA9PSAxICYgKGlzLm5hKFEyNWMpIHwgUTI1YyAhPSAxKSB+ICJSZXZvbHV0ICsgTjI2IiwNCiAgICAgIFEyNWMgPT0gMSAmIChpcy5uYShRMjVkKSB8IFEyNWQgIT0gMSkgJiAoaXMubmEoUTI1ZSkgfCBRMjVlICE9IDEpIH4gIk5MQiBvbmx5IiwNCiAgICAgIFEyNWQgPT0gMSAmIChpcy5uYShRMjVjKSB8IFEyNWMgIT0gMSkgJiAoaXMubmEoUTI1ZSkgfCBRMjVlICE9IDEpIH4gIlJldm9sdXQgb25seSIsDQogICAgICBRMjVlID09IDEgJiAoaXMubmEoUTI1YykgfCBRMjVjICE9IDEpICYgKGlzLm5hKFEyNWQpIHwgUTI1ZCAhPSAxKSB+ICJOMjYgb25seSIsDQogICAgICBUUlVFIH4gIk5vbmUgb2YgdGhlc2UgdGhyZWUiDQogICAgKQ0KICApIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIsIGJhbmtfY29tYm8pIHw+DQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpIHw+DQogIG11dGF0ZShwZXJjZW50ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSkpIHw+DQogIHVuZ3JvdXAoKQ0KDQpubGJfcmV2b2x1dF9uMjZfY29tYmluYXRpb25zDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWJibGUpDQpsaWJyYXJ5KEZhY3RvTWluZVIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmNsdXN0ZXIyX2JhbmtfbWVhbnMgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8Pg0KICBtdXRhdGUoDQogICAgYWNyb3NzKFExM2E6UTE1ZywgYXMubnVtZXJpYykNCiAgKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgT1RQX2lubm92YXRpb24gPSBtZWFuKFExM2EsIG5hLnJtID0gVFJVRSksDQogICAgR29yZW5qc2thX2lubm92YXRpb24gPSBtZWFuKFExM2IsIG5hLnJtID0gVFJVRSksDQogICAgTkxCX2lubm92YXRpb24gPSBtZWFuKFExM2MsIG5hLnJtID0gVFJVRSksDQogICAgUmV2b2x1dF9pbm5vdmF0aW9uID0gbWVhbihRMTNkLCBuYS5ybSA9IFRSVUUpLA0KICAgIE4yNl9pbm5vdmF0aW9uID0gbWVhbihRMTNlLCBuYS5ybSA9IFRSVUUpLA0KICAgIEludGVzYV9pbm5vdmF0aW9uID0gbWVhbihRMTNmLCBuYS5ybSA9IFRSVUUpLA0KICAgIFVuaUNyZWRpdF9pbm5vdmF0aW9uID0gbWVhbihRMTNnLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgT1RQX3N1cHBvcnQgPSBtZWFuKFExNGEsIG5hLnJtID0gVFJVRSksDQogICAgR29yZW5qc2thX3N1cHBvcnQgPSBtZWFuKFExNGIsIG5hLnJtID0gVFJVRSksDQogICAgTkxCX3N1cHBvcnQgPSBtZWFuKFExNGMsIG5hLnJtID0gVFJVRSksDQogICAgUmV2b2x1dF9zdXBwb3J0ID0gbWVhbihRMTRkLCBuYS5ybSA9IFRSVUUpLA0KICAgIE4yNl9zdXBwb3J0ID0gbWVhbihRMTRlLCBuYS5ybSA9IFRSVUUpLA0KICAgIEludGVzYV9zdXBwb3J0ID0gbWVhbihRMTRmLCBuYS5ybSA9IFRSVUUpLA0KICAgIFVuaUNyZWRpdF9zdXBwb3J0ID0gbWVhbihRMTRnLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgT1RQX3JlbGlhYmlsaXR5ID0gbWVhbihRMTVhLCBuYS5ybSA9IFRSVUUpLA0KICAgIEdvcmVuanNrYV9yZWxpYWJpbGl0eSA9IG1lYW4oUTE1YiwgbmEucm0gPSBUUlVFKSwNCiAgICBOTEJfcmVsaWFiaWxpdHkgPSBtZWFuKFExNWMsIG5hLnJtID0gVFJVRSksDQogICAgUmV2b2x1dF9yZWxpYWJpbGl0eSA9IG1lYW4oUTE1ZCwgbmEucm0gPSBUUlVFKSwNCiAgICBOMjZfcmVsaWFiaWxpdHkgPSBtZWFuKFExNWUsIG5hLnJtID0gVFJVRSksDQogICAgSW50ZXNhX3JlbGlhYmlsaXR5ID0gbWVhbihRMTVmLCBuYS5ybSA9IFRSVUUpLA0KICAgIFVuaUNyZWRpdF9yZWxpYWJpbGl0eSA9IG1lYW4oUTE1ZywgbmEucm0gPSBUUlVFKQ0KICApDQoNCmNsdXN0ZXIyX2JhbmtfbWVhbnMNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX2JhbmtfdGFibGUgPC0gdGliYmxlKA0KICBiYW5rID0gYygiT1RQIiwgIkdvcmVuanNrYSBCYW5rYSIsICJOTEIiLCAiUmV2b2x1dCIsICJOMjYiLCAiSW50ZXNhIFNhblBhb2xvIiwgIlVuaUNyZWRpdCIpLA0KICBpbm5vdmF0aW9uID0gYygNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNhKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNiKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNjKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNkKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNlKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNmKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTNnKSwgbmEucm0gPSBUUlVFKQ0KICApLA0KICBjdXN0b21lcl9zdXBwb3J0ID0gYygNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRhKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRiKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRjKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRkKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRlKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRmKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTRnKSwgbmEucm0gPSBUUlVFKQ0KICApLA0KICByZWxpYWJpbGl0eSA9IGMoDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1YSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1YiksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1YyksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1ZCksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1ZSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1ZiksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDIpIHw+IHB1bGwoUTE1ZyksIG5hLnJtID0gVFJVRSkNCiAgKQ0KKQ0KDQpjbHVzdGVyMl9iYW5rX3RhYmxlDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyMl9tYXQgPC0gY2x1c3RlcjJfYmFua190YWJsZSB8Pg0KICBjb2x1bW5fdG9fcm93bmFtZXMoImJhbmsiKSB8Pg0KICBhcy5tYXRyaXgoKQ0KDQpwY2FfY2x1c3RlcjIgPC0gRmFjdG9NaW5lUjo6UENBKGNsdXN0ZXIyX21hdCwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRkFMU0UpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyMl9jb29yZGluYXRlcyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyMiRpbmQkY29vcmQpDQpjbHVzdGVyMl9jb29yZGluYXRlcyRiYW5rIDwtIHJvd25hbWVzKGNsdXN0ZXIyX2Nvb3JkaW5hdGVzKQ0Kcm93bmFtZXMoY2x1c3RlcjJfY29vcmRpbmF0ZXMpIDwtIE5VTEwNCg0KY2x1c3RlcjJfY29vcmRpbmF0ZXMNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX2xvYWRpbmdzIDwtIGFzLmRhdGEuZnJhbWUocGNhX2NsdXN0ZXIyJHZhciRjb29yZCkNCmNsdXN0ZXIyX2xvYWRpbmdzJGRpbWVuc2lvbiA8LSByb3duYW1lcyhjbHVzdGVyMl9sb2FkaW5ncykNCnJvd25hbWVzKGNsdXN0ZXIyX2xvYWRpbmdzKSA8LSBOVUxMDQoNCmNsdXN0ZXIyX2xvYWRpbmdzDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyMl9ubGJfZXhwbGFuYXRpb24gPC0gY2x1c3RlcjJfYmFua190YWJsZSB8Pg0KICBmaWx0ZXIoYmFuayA9PSAiTkxCIikgfD4NCiAgbXV0YXRlKA0KICAgIERpbTFfbG9hZGluZ19pbm5vdmF0aW9uID0gcGNhX2NsdXN0ZXIyJHZhciRjb29yZFsiaW5ub3ZhdGlvbiIsICJEaW0uMSJdLA0KICAgIERpbTFfbG9hZGluZ19zdXBwb3J0ID0gcGNhX2NsdXN0ZXIyJHZhciRjb29yZFsiY3VzdG9tZXJfc3VwcG9ydCIsICJEaW0uMSJdLA0KICAgIERpbTFfbG9hZGluZ19yZWxpYWJpbGl0eSA9IHBjYV9jbHVzdGVyMiR2YXIkY29vcmRbInJlbGlhYmlsaXR5IiwgIkRpbS4xIl0sDQogICAgRGltMl9sb2FkaW5nX2lubm92YXRpb24gPSBwY2FfY2x1c3RlcjIkdmFyJGNvb3JkWyJpbm5vdmF0aW9uIiwgIkRpbS4yIl0sDQogICAgRGltMl9sb2FkaW5nX3N1cHBvcnQgPSBwY2FfY2x1c3RlcjIkdmFyJGNvb3JkWyJjdXN0b21lcl9zdXBwb3J0IiwgIkRpbS4yIl0sDQogICAgRGltMl9sb2FkaW5nX3JlbGlhYmlsaXR5ID0gcGNhX2NsdXN0ZXIyJHZhciRjb29yZFsicmVsaWFiaWxpdHkiLCAiRGltLjIiXSwNCiAgICBOTEJfRGltMSA9IHBjYV9jbHVzdGVyMiRpbmQkY29vcmRbIk5MQiIsICJEaW0uMSJdLA0KICAgIE5MQl9EaW0yID0gcGNhX2NsdXN0ZXIyJGluZCRjb29yZFsiTkxCIiwgIkRpbS4yIl0NCiAgKQ0KDQpjbHVzdGVyMl9ubGJfZXhwbGFuYXRpb24NCmBgYA0KDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfcGNhX2JpcGxvdCgNCiAgcGNhX2NsdXN0ZXIyLA0KICByZXBlbCA9IFRSVUUsDQogIGNvbC52YXIgPSAiZ3JheTMwIiwNCiAgY29sLmluZCA9ICJzdGVlbGJsdWUiLA0KICBwb2ludHNpemUgPSAzDQopICsNCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiUGVyY2VwdGlvbiBNYXAgb2YgQmFua3MgLSBDbHVzdGVyIDIiKSArDQogIGdncGxvdDI6OnhsYWIoIkRpbSAxIikgKw0KICBnZ3Bsb3QyOjp5bGFiKCJEaW0gMiIpICsNCiAgZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyMl9iYW5rX3RhYmxlDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyMl9jb29yZGluYXRlcw0KYGBgDQoNCmBgYHtyfQ0KY2x1c3RlcjJfbG9hZGluZ3MNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkoZ2dwbG90MikNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAxKSBCYW5rIG1lYW4gdGFibGUgZm9yIGNsdXN0ZXIgMw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2x1c3RlcjNfYmFua190YWJsZSA8LSB0aWJibGUoDQogIGJhbmsgPSBjKCJPVFAiLCAiR29yZW5qc2thIEJhbmthIiwgIk5MQiIsICJSZXZvbHV0IiwgIk4yNiIsICJJbnRlc2EgU2FuUGFvbG8iLCAiVW5pQ3JlZGl0IiksDQogIGlubm92YXRpb24gPSBjKA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2EpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2IpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2MpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2QpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2UpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2YpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExM2cpLCBuYS5ybSA9IFRSVUUpDQogICksDQogIGN1c3RvbWVyX3N1cHBvcnQgPSBjKA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGEpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGIpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGMpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGUpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGYpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNGcpLCBuYS5ybSA9IFRSVUUpDQogICksDQogIHJlbGlhYmlsaXR5ID0gYygNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTVhKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTViKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTVjKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTVkKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTVlKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTVmKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gcHVsbChRMTVnKSwgbmEucm0gPSBUUlVFKQ0KICApDQopDQoNCmNsdXN0ZXIzX2JhbmtfdGFibGUNCmBgYA0KDQpgYGB7cn0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMikgUENBIGZvciBjbHVzdGVyIDMNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmNsdXN0ZXIzX21hdCA8LSBjbHVzdGVyM19iYW5rX3RhYmxlIHw+DQogIGNvbHVtbl90b19yb3duYW1lcygiYmFuayIpIHw+DQogIGFzLm1hdHJpeCgpDQoNCnBjYV9jbHVzdGVyMyA8LSBGYWN0b01pbmVSOjpQQ0EoY2x1c3RlcjNfbWF0LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGQUxTRSkNCmBgYA0KDQpgYGB7cn0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMykgQmFuayBjb29yZGluYXRlcw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2x1c3RlcjNfY29vcmRpbmF0ZXMgPC0gYXMuZGF0YS5mcmFtZShwY2FfY2x1c3RlcjMkaW5kJGNvb3JkKQ0KY2x1c3RlcjNfY29vcmRpbmF0ZXMkYmFuayA8LSByb3duYW1lcyhjbHVzdGVyM19jb29yZGluYXRlcykNCnJvd25hbWVzKGNsdXN0ZXIzX2Nvb3JkaW5hdGVzKSA8LSBOVUxMDQoNCmNsdXN0ZXIzX2Nvb3JkaW5hdGVzDQpgYGANCg0KYGBge3J9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDQpIFZhcmlhYmxlIGxvYWRpbmdzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyM19sb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyMyR2YXIkY29vcmQpDQpjbHVzdGVyM19sb2FkaW5ncyRkaW1lbnNpb24gPC0gcm93bmFtZXMoY2x1c3RlcjNfbG9hZGluZ3MpDQpyb3duYW1lcyhjbHVzdGVyM19sb2FkaW5ncykgPC0gTlVMTA0KDQpjbHVzdGVyM19sb2FkaW5ncw0KYGBgDQoNCmBgYHtyfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA1KSBOTEIgZXhwbGFuYXRpb24gdGFibGUNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmNsdXN0ZXIzX25sYl9leHBsYW5hdGlvbiA8LSBjbHVzdGVyM19iYW5rX3RhYmxlIHw+DQogIGZpbHRlcihiYW5rID09ICJOTEIiKSB8Pg0KICBtdXRhdGUoDQogICAgRGltMV9sb2FkaW5nX2lubm92YXRpb24gPSBwY2FfY2x1c3RlcjMkdmFyJGNvb3JkWyJpbm5vdmF0aW9uIiwgIkRpbS4xIl0sDQogICAgRGltMV9sb2FkaW5nX3N1cHBvcnQgPSBwY2FfY2x1c3RlcjMkdmFyJGNvb3JkWyJjdXN0b21lcl9zdXBwb3J0IiwgIkRpbS4xIl0sDQogICAgRGltMV9sb2FkaW5nX3JlbGlhYmlsaXR5ID0gcGNhX2NsdXN0ZXIzJHZhciRjb29yZFsicmVsaWFiaWxpdHkiLCAiRGltLjEiXSwNCiAgICBEaW0yX2xvYWRpbmdfaW5ub3ZhdGlvbiA9IHBjYV9jbHVzdGVyMyR2YXIkY29vcmRbImlubm92YXRpb24iLCAiRGltLjIiXSwNCiAgICBEaW0yX2xvYWRpbmdfc3VwcG9ydCA9IHBjYV9jbHVzdGVyMyR2YXIkY29vcmRbImN1c3RvbWVyX3N1cHBvcnQiLCAiRGltLjIiXSwNCiAgICBEaW0yX2xvYWRpbmdfcmVsaWFiaWxpdHkgPSBwY2FfY2x1c3RlcjMkdmFyJGNvb3JkWyJyZWxpYWJpbGl0eSIsICJEaW0uMiJdLA0KICAgIE5MQl9EaW0xID0gcGNhX2NsdXN0ZXIzJGluZCRjb29yZFsiTkxCIiwgIkRpbS4xIl0sDQogICAgTkxCX0RpbTIgPSBwY2FfY2x1c3RlcjMkaW5kJGNvb3JkWyJOTEIiLCAiRGltLjIiXQ0KICApDQoNCmNsdXN0ZXIzX25sYl9leHBsYW5hdGlvbg0KYGBgDQoNCmBgYHtyfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA2KSBQbG90DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpmYWN0b2V4dHJhOjpmdml6X3BjYV9iaXBsb3QoDQogIHBjYV9jbHVzdGVyMywNCiAgcmVwZWwgPSBUUlVFLA0KICBjb2wudmFyID0gImdyYXkzMCIsDQogIGNvbC5pbmQgPSAic3RlZWxibHVlIiwNCiAgcG9pbnRzaXplID0gMw0KKSArDQogIGdncGxvdDI6OmdndGl0bGUoIlBlcmNlcHRpb24gTWFwIG9mIEJhbmtzIC0gQ2x1c3RlciAzIikgKw0KICBnZ3Bsb3QyOjp4bGFiKCJEaW0gMSIpICsNCiAgZ2dwbG90Mjo6eWxhYigiRGltIDIiKSArDQogIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA3KSBDb21wYXJlIE5MQiB3aXRoIFJldm9sdXQgYW5kIE4yNg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2x1c3RlcjNfYmFua190YWJsZSB8Pg0KICBmaWx0ZXIoYmFuayAlaW4lIGMoIk5MQiIsICJSZXZvbHV0IiwgIk4yNiIpKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3RlcjNfYmFua190YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHB1cnJyKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDEpIFExMiBpdGVtIGxhYmVscw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KcTEyX2xhYmVscyA8LSBjKA0KICBRMTJhID0gIlNlY3VyaXR5IiwNCiAgUTEyYiA9ICJQZXJzb25hbCBkYXRhIHByb3RlY3Rpb24iLA0KICBRMTJjID0gIlRydXN0IGluIHRoZSBiYW5rIiwNCiAgUTEyZCA9ICJFYXNlIG9mIHVzZSIsDQogIFExMmUgPSAiVHJhbnNhY3Rpb24gZXhlY3V0aW9uIHNwZWVkIiwNCiAgUTEyZiA9ICJWYXJpZXR5IG9mIGZ1bmN0aW9ucyIsDQogIFExMmcgPSAiQXZhaWxhYmlsaXR5IG9mIGh1bWFuIHN1cHBvcnQiLA0KICBRMTJoID0gIlBlcnNvbmFsaXplZCBmaW5hbmNpYWwgaW5zaWdodHMiLA0KICBRMTJpID0gIlVuZGVyc3RhbmRpbmcgaG93IHRoZSBwcm9ncmFtIG1ha2VzIGRlY2lzaW9ucyINCikNCg0KcTEyX3ZhcnMgPC0gbmFtZXMocTEyX2xhYmVscykNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAyKSBBdHRhY2ggdGhlIDUtY2x1c3RlciBzb2x1dGlvbg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2x1c3Rlcl9sYWJlbHMgPC0gYygNCiAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQopDQoNCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbGVhbl9jb21wbGV0ZSAlPiUNCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSAxOjUsDQogICAgICBsYWJlbHMgPSBjbHVzdGVyX2xhYmVscw0KICAgICkNCiAgKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDMpIEZ1bmN0aW9uIHRvIHByb2ZpbGUgT05FIGNsdXN0ZXIgaW5kZXBlbmRlbnRseQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KcHJvZmlsZV9vbmVfY2x1c3Rlcl9xMTIgPC0gZnVuY3Rpb24oZGF0YSwgY2x1c3Rlcl9uYW1lKSB7DQogIA0KICBkYXRhICU+JQ0KICAgIGZpbHRlcihjbHVzdGVyID09IGNsdXN0ZXJfbmFtZSkgJT4lDQogICAgc2VsZWN0KGFsbF9vZihxMTJfdmFycykpICU+JQ0KICAgIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5udW1lcmljKSkgJT4lDQogICAgcGl2b3RfbG9uZ2VyKA0KICAgICAgY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICAgIG5hbWVzX3RvID0gIml0ZW0iLA0KICAgICAgdmFsdWVzX3RvID0gInNjb3JlIg0KICAgICkgJT4lDQogICAgZ3JvdXBfYnkoaXRlbSkgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgICAgbiA9IHN1bSghaXMubmEoc2NvcmUpKSwNCiAgICAgIG1lYW4gPSByb3VuZChtZWFuKHNjb3JlLCBuYS5ybSA9IFRSVUUpLCAyKSwNCiAgICAgIHNkID0gcm91bmQoc2Qoc2NvcmUsIG5hLnJtID0gVFJVRSksIDIpLA0KICAgICAgbWVkaWFuID0gcm91bmQobWVkaWFuKHNjb3JlLCBuYS5ybSA9IFRSVUUpLCAyKSwNCiAgICAgIHBjdF82XzcgPSByb3VuZChtZWFuKHNjb3JlICVpbiUgYyg2LCA3KSwgbmEucm0gPSBUUlVFKSAqIDEwMCwgMSksDQogICAgICBwY3RfNyA9IHJvdW5kKG1lYW4oc2NvcmUgPT0gNywgbmEucm0gPSBUUlVFKSAqIDEwMCwgMSksDQogICAgICAuZ3JvdXBzID0gImRyb3AiDQogICAgKSAlPiUNCiAgICBtdXRhdGUoDQogICAgICBsYWJlbCA9IHExMl9sYWJlbHNbaXRlbV0sDQogICAgICBjbHVzdGVyID0gY2x1c3Rlcl9uYW1lDQogICAgKSAlPiUNCiAgICBzZWxlY3QoY2x1c3RlciwgaXRlbSwgbGFiZWwsIG4sIG1lYW4sIHNkLCBtZWRpYW4sIHBjdF82XzcsIHBjdF83KSAlPiUNCiAgICBhcnJhbmdlKGRlc2MobWVhbikpDQp9DQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgNCkgQ3JlYXRlIGEgc2VwYXJhdGUgcHJvZmlsZSBmb3IgZWFjaCBjbHVzdGVyDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyXzFfcTEyX3Byb2ZpbGUgPC0gcHJvZmlsZV9vbmVfY2x1c3Rlcl9xMTIoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIg0KKQ0KDQpjbHVzdGVyXzJfcTEyX3Byb2ZpbGUgPC0gcHJvZmlsZV9vbmVfY2x1c3Rlcl9xMTIoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIg0KKQ0KDQpjbHVzdGVyXzNfcTEyX3Byb2ZpbGUgPC0gcHJvZmlsZV9vbmVfY2x1c3Rlcl9xMTIoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIg0KKQ0KDQpjbHVzdGVyXzRfcTEyX3Byb2ZpbGUgPC0gcHJvZmlsZV9vbmVfY2x1c3Rlcl9xMTIoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIg0KKQ0KDQpjbHVzdGVyXzVfcTEyX3Byb2ZpbGUgPC0gcHJvZmlsZV9vbmVfY2x1c3Rlcl9xMTIoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCikNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA1KSBWaWV3IGVhY2ggY2x1c3RlciBpbmRlcGVuZGVudGx5DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyXzFfcTEyX3Byb2ZpbGUNCmNsdXN0ZXJfMl9xMTJfcHJvZmlsZQ0KY2x1c3Rlcl8zX3ExMl9wcm9maWxlDQpjbHVzdGVyXzRfcTEyX3Byb2ZpbGUNCmNsdXN0ZXJfNV9xMTJfcHJvZmlsZQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9xMTJfcHJvZmlsZXMgPC0gc2V0TmFtZXMoDQogIGxhcHBseShsZXZlbHMoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyKSwgZnVuY3Rpb24oY2wpIHsNCiAgICBwcm9maWxlX29uZV9jbHVzdGVyX3ExMihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCBjbCkNCiAgfSksDQogIGxldmVscyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIpDQopDQoNCiMgRXhhbXBsZToNCmNsdXN0ZXJfcTEyX3Byb2ZpbGVzW1siU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyJdXQ0KY2x1c3Rlcl9xMTJfcHJvZmlsZXNbWyJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIl1dDQpgYGANCg0KYGBge3J9DQpiYW5rX2RhdGEgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoYWNyb3NzKFEyNWE6UTI1bCwgYXMubnVtZXJpYykpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KYmFua19jb21iaW5hdGlvbnMgPC0gYmFua19kYXRhIHw+DQogIG11dGF0ZSgNCg0KICAgICMgUmV2b2x1dCBvbmx5DQogICAgcmV2b2x1dF9vbmx5ID0NCiAgICAgIFEyNWQgPT0gMSAmDQogICAgICByb3dTdW1zKGFjcm9zcyhRMjVhOlEyNWMpKSA9PSAwICYNCiAgICAgIHJvd1N1bXMoYWNyb3NzKFEyNWU6UTI1bCkpID09IDAsDQoNCiAgICAjIE5MQiArIFJldm9sdXQNCiAgICBubGJfcmV2b2x1dCA9DQogICAgICBRMjVjID09IDEgJiBRMjVkID09IDEsDQoNCiAgICAjIFJldm9sdXQgKyBhbnkgb3RoZXIgYmFuayBleGNlcHQgTkxCDQogICAgcmV2b2x1dF9vdGhlciA9DQogICAgICBRMjVkID09IDEgJg0KICAgICAgcm93U3VtcyhhY3Jvc3MoYyhRMjVhLCBRMjViLCBRMjVlOlEyNWwpKSkgPiAwLA0KDQogICAgIyBSZXZvbHV0ICsgZ3JvdXBlZCAib3RoZXIgYmFua3MiIChhbGwgZXhjZXB0IE5MQikNCiAgICByZXZvbHV0X2dyb3VwX290aGVyID0NCiAgICAgIFEyNWQgPT0gMSAmDQogICAgICByb3dTdW1zKGFjcm9zcyhjKFEyNWEsIFEyNWIsIFEyNWU6UTI1bCkpKSA+IDANCiAgKQ0KDQpgYGANCg0KYGBge3J9DQpyZXZvbHV0X2NsdXN0ZXJfdGFibGUgPC0gYmFua19jb21iaW5hdGlvbnMgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KDQogICAgbl9jbHVzdGVyID0gbigpLA0KDQogICAgcmV2b2x1dF9vbmx5ID0gc3VtKHJldm9sdXRfb25seSwgbmEucm0gPSBUUlVFKSwNCiAgICBubGJfcmV2b2x1dCA9IHN1bShubGJfcmV2b2x1dCwgbmEucm0gPSBUUlVFKSwNCiAgICByZXZvbHV0X290aGVyID0gc3VtKHJldm9sdXRfb3RoZXIsIG5hLnJtID0gVFJVRSksDQogICAgcmV2b2x1dF9ncm91cF9vdGhlciA9IHN1bShyZXZvbHV0X2dyb3VwX290aGVyLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgcmV2b2x1dF9vbmx5X3BjdCA9IHJvdW5kKDEwMCAqIHJldm9sdXRfb25seSAvIG5fY2x1c3RlciwgMSksDQogICAgbmxiX3Jldm9sdXRfcGN0ID0gcm91bmQoMTAwICogbmxiX3Jldm9sdXQgLyBuX2NsdXN0ZXIsIDEpLA0KICAgIHJldm9sdXRfb3RoZXJfcGN0ID0gcm91bmQoMTAwICogcmV2b2x1dF9vdGhlciAvIG5fY2x1c3RlciwgMSksDQogICAgcmV2b2x1dF9ncm91cF9vdGhlcl9wY3QgPSByb3VuZCgxMDAgKiByZXZvbHV0X2dyb3VwX290aGVyIC8gbl9jbHVzdGVyLCAxKQ0KDQogICkNCg0KcmV2b2x1dF9jbHVzdGVyX3RhYmxlDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXIpDQoNCnJldm9sdXRfY2x1c3Rlcl90YWJsZSB8Pg0KICBzZWxlY3QoDQogICAgY2x1c3RlciwNCiAgICByZXZvbHV0X29ubHlfcGN0LA0KICAgIG5sYl9yZXZvbHV0X3BjdCwNCiAgICByZXZvbHV0X290aGVyX3BjdA0KICApIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAiY29tYmluYXRpb24iLA0KICAgIHZhbHVlc190byA9ICJwZXJjZW50Ig0KICApDQoNCmBgYA0KDQpgYGB7cn0NCmJhbmtfZGF0YSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZShhY3Jvc3MoUTI1YTpRMjVsLCBhcy5udW1lcmljKSkNCg0KYGBgDQoNCmBgYHtyfQ0KYmFua19ncm91cHMgPC0gYmFua19kYXRhIHw+DQogIG11dGF0ZSgNCg0KICAgICMgUmV2b2x1dCBvbmx5DQogICAgcmV2b2x1dF9vbmx5ID0NCiAgICAgIFEyNWQgPT0gMSAmDQogICAgICByb3dTdW1zKGFjcm9zcyhjKFEyNWEsIFEyNWIsIFEyNWMsIFEyNWU6UTI1bCkpKSA9PSAwLA0KDQogICAgIyBOTEIgKyBSZXZvbHV0DQogICAgbmxiX3Jldm9sdXQgPQ0KICAgICAgUTI1YyA9PSAxICYgUTI1ZCA9PSAxLA0KDQogICAgIyBPVFAgKyBSZXZvbHV0DQogICAgb3RwX3Jldm9sdXQgPQ0KICAgICAgUTI1YSA9PSAxICYgUTI1ZCA9PSAxLA0KDQogICAgIyBSZXZvbHV0ICsgYW55IG90aGVyIGJhbmsgZXhjZXB0IE5MQiBhbmQgT1RQDQogICAgcmV2b2x1dF9vdGhlciA9DQogICAgICBRMjVkID09IDEgJg0KICAgICAgcm93U3VtcyhhY3Jvc3MoYyhRMjViLCBRMjVlOlEyNWwpKSkgPiAwDQogICkNCg0KYGBgDQoNCmBgYHtyfQ0KcmV2b2x1dF9jbHVzdGVyX3N1bW1hcnkgPC0gYmFua19ncm91cHMgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KDQogICAgbl9jbHVzdGVyID0gbigpLA0KDQogICAgcmV2b2x1dF9vbmx5ID0gc3VtKHJldm9sdXRfb25seSwgbmEucm0gPSBUUlVFKSwNCiAgICBubGJfcmV2b2x1dCA9IHN1bShubGJfcmV2b2x1dCwgbmEucm0gPSBUUlVFKSwNCiAgICBvdHBfcmV2b2x1dCA9IHN1bShvdHBfcmV2b2x1dCwgbmEucm0gPSBUUlVFKSwNCiAgICByZXZvbHV0X290aGVyID0gc3VtKHJldm9sdXRfb3RoZXIsIG5hLnJtID0gVFJVRSksDQoNCiAgICByZXZvbHV0X29ubHlfcGN0ID0gcm91bmQoMTAwICogcmV2b2x1dF9vbmx5IC8gbl9jbHVzdGVyLCAxKSwNCiAgICBubGJfcmV2b2x1dF9wY3QgPSByb3VuZCgxMDAgKiBubGJfcmV2b2x1dCAvIG5fY2x1c3RlciwgMSksDQogICAgb3RwX3Jldm9sdXRfcGN0ID0gcm91bmQoMTAwICogb3RwX3Jldm9sdXQgLyBuX2NsdXN0ZXIsIDEpLA0KICAgIHJldm9sdXRfb3RoZXJfcGN0ID0gcm91bmQoMTAwICogcmV2b2x1dF9vdGhlciAvIG5fY2x1c3RlciwgMSkNCg0KICApDQoNCnJldm9sdXRfY2x1c3Rlcl9zdW1tYXJ5DQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXIpDQoNCnJldm9sdXRfY2x1c3Rlcl9zdW1tYXJ5IHw+DQogIHNlbGVjdCgNCiAgICBjbHVzdGVyLA0KICAgIHJldm9sdXRfb25seV9wY3QsDQogICAgbmxiX3Jldm9sdXRfcGN0LA0KICAgIG90cF9yZXZvbHV0X3BjdCwNCiAgICByZXZvbHV0X290aGVyX3BjdA0KICApIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAiZ3JvdXAiLA0KICAgIHZhbHVlc190byA9ICJwZXJjZW50Ig0KICApDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCmJhbmtfc2VnbWVudHMgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoYWNyb3NzKFEyNWE6UTI1bCwgYXMubnVtZXJpYykpIHw+DQogIG11dGF0ZSgNCg0KICAgIHNlZ21lbnQgPSBjYXNlX3doZW4oDQoNCiAgICAgIFEyNWMgPT0gMSAmIFEyNWQgPT0gMCAmIFEyNWEgPT0gMCB+ICJOTEIgb25seSIsDQogICAgICBRMjVkID09IDEgJiBRMjVjID09IDAgJiBRMjVhID09IDAgfiAiUmV2b2x1dCBvbmx5IiwNCiAgICAgIFEyNWEgPT0gMSAmIFEyNWMgPT0gMCAmIFEyNWQgPT0gMCB+ICJPVFAgb25seSIsDQoNCiAgICAgIFEyNWMgPT0gMSAmIFEyNWQgPT0gMSAmIFEyNWEgPT0gMCB+ICJOTEIgKyBSZXZvbHV0IiwNCiAgICAgIFEyNWMgPT0gMSAmIFEyNWEgPT0gMSAmIFEyNWQgPT0gMCB+ICJOTEIgKyBPVFAiLA0KICAgICAgUTI1YSA9PSAxICYgUTI1ZCA9PSAxICYgUTI1YyA9PSAwIH4gIk9UUCArIFJldm9sdXQiLA0KDQogICAgICBRMjVhID09IDEgJiBRMjVjID09IDEgJiBRMjVkID09IDEgfiAiTkxCICsgUmV2b2x1dCArIE9UUCIsDQoNCiAgICAgIFRSVUUgfiAiTm9uZSBvZiB0aGVzZSB0aHJlZSINCiAgICApDQogICkNCmBgYA0KDQpgYGB7cn0NCnNlZ21lbnRfdGFibGUgPC0gYmFua19zZWdtZW50cyB8Pg0KICBncm91cF9ieShjbHVzdGVyLCBzZWdtZW50KSB8Pg0KICBzdW1tYXJpc2UobiA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgbXV0YXRlKA0KICAgIHBlcmNlbnQgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKQ0KICApIHw+DQogIGFycmFuZ2UoY2x1c3RlciwgZGVzYyhwZXJjZW50KSkNCg0Kc2VnbWVudF90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KY29udmVyc2lvbl90YWJsZSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZShhY3Jvc3MoUTI1YTpRMjVsLCBhcy5udW1lcmljKSkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KDQogICAgY2x1c3Rlcl9zaXplID0gbigpLA0KDQogICAgcmV2b2x1dF91c2VycyA9IHN1bShRMjVkID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgbmxiX3VzZXJzID0gc3VtKFEyNWMgPT0gMSwgbmEucm0gPSBUUlVFKSwNCg0KICAgIG5sYl9yZXZvbHV0X3VzZXJzID0gc3VtKFEyNWMgPT0gMSAmIFEyNWQgPT0gMSwgbmEucm0gPSBUUlVFKSwNCg0KICAgIHJldm9sdXRfd2l0aG91dF9ubGIgPSBzdW0oUTI1ZCA9PSAxICYgUTI1YyA9PSAwLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgcmV2b2x1dF91c2Vyc19wY3QgPSByb3VuZCgxMDAgKiByZXZvbHV0X3VzZXJzIC8gY2x1c3Rlcl9zaXplLCAxKSwNCg0KICAgIHJldm9sdXRfd2l0aG91dF9ubGJfcGN0ID0NCiAgICAgIHJvdW5kKDEwMCAqIHJldm9sdXRfd2l0aG91dF9ubGIgLyBjbHVzdGVyX3NpemUsIDEpDQoNCiAgKQ0KDQpjb252ZXJzaW9uX3RhYmxlDQpgYGANCg0KDQoNCiMjQ2x1c3RlciAzDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkoZ2dwbG90MikNCg0KIyMgMS4gTG9hZCBhbmQgY2xlYW4gZGF0YSAtLS0tDQoNCnJhd19zaGVldCA8LSByZWFkX2V4Y2VsKA0KICAiUXVlc3Rpb25uYWlyZV9yZXN1bHRzX0VOLnhsc3giLA0KICBzaGVldCA9ICJQb2RhdGtpIiwNCiAgY29sX25hbWVzID0gRkFMU0UNCikNCg0KdmFyX25hbWVzIDwtIHJhd19zaGVldCB8Pg0KICBzbGljZSgxKSB8Pg0KICB1bmxpc3QodXNlLm5hbWVzID0gRkFMU0UpIHw+DQogIGFzLmNoYXJhY3RlcigpDQoNCnF1ZXN0aW9uX3RleHQgPC0gcmF3X3NoZWV0IHw+DQogIHNsaWNlKDIpIHw+DQogIHVubGlzdCh1c2UubmFtZXMgPSBGQUxTRSkgfD4NCiAgYXMuY2hhcmFjdGVyKCkNCg0KZGF0YV9yYXcgPC0gcmF3X3NoZWV0IHw+DQogIHNsaWNlKC0oMToyKSkNCg0KbmFtZXMoZGF0YV9yYXcpIDwtIHZhcl9uYW1lcw0KDQpkYXRhX3JhdyA8LSBkYXRhX3JhdyB8Pg0KICBtdXRhdGUocmVzcG9uZGVudF9pZCA9IHJvd19udW1iZXIoKSkgfD4NCiAgcmVsb2NhdGUocmVzcG9uZGVudF9pZCkNCg0KZGF0YV9jbGVhbiA8LSBkYXRhX3JhdyB8Pg0KICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICAgICB+IHJlcGxhY2UoYXMuY2hhcmFjdGVyKC4pLCBhcy5jaGFyYWN0ZXIoLikgPT0gIi0xIiwgTkEpKSkgfD4NCiAgZmlsdGVyKCFpcy5uYShRMjIpLCAhaXMubmEoUTIzKSkNCg0KZGF0YV9jbGVhbiA8LSBkYXRhX2NsZWFuIHw+DQogIG11dGF0ZSgNCiAgICBhY3Jvc3MoDQogICAgICBRMTNhOlExNWcsDQogICAgICB+IGFzLm51bWVyaWMocmVwbGFjZSguLCAuID09ICI4IiwgTkEpKQ0KICAgICkNCiAgKQ0KDQojIyAyLiBSZWJ1aWxkIHRoZSA1IHJlc3BvbmRlbnQgY2x1c3RlcnMgKHNhbWUgbG9naWMgYXMgYmVmb3JlKSAtLS0tDQoNCmNsdXN0ZXJfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIHNlbGVjdChRNmEsIFE2YiwgUTZkLCBRNmUsIFE2aCwgUTZpLA0KICAgICAgICAgUThhLCBROGIsIFE4YywgUThkLCBROGUpIHw+DQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5udW1lcmljKSkNCg0KY2x1c3Rlcl9kYXRhX2NvbXBsZXRlIDwtIGNsdXN0ZXJfZGF0YSB8Pg0KICBkcm9wX25hKCkNCg0KcGNhX2NsdXN0ZXIgPC0gcHJjb21wKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSwgc2NhbGUuID0gVFJVRSkNCnBjYV9zY29yZXNfMiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyJHhbLCAxOjJdKQ0KDQpzZXQuc2VlZCgxMjMpDQprNV9wY2EyIDwtIGttZWFucyhwY2Ffc2NvcmVzXzIsIGNlbnRlcnMgPSA1LCBuc3RhcnQgPSAyNSkNCg0KZGF0YV9jbGVhbl9jb21wbGV0ZSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApDQoNCmRhdGFfY2x1c3RlciA8LSBkYXRhX2NsZWFuX2NvbXBsZXRlIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsICAgIyBjbHVzdGVyIDMNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCiMjIDMuIEhhcmQtY29kZSBiYW5rcyBhbmQgcGVyY2VwdGlvbiBpdGVtcyAoUTEz4oCTUTE1KSAtLS0tDQoNCiMgUTEzOiBpbm5vdmF0aW9uLCBRMTQ6IGN1c3RvbWVyIHN1cHBvcnQsIFExNTogcmVsaWFiaWxpdHkNCnBlcmNlcHRfdmFycyA8LSBjKA0KICAiUTEzYSIsIlExM2IiLCJRMTNjIiwiUTEzZCIsIlExM2UiLCJRMTNmIiwiUTEzZyIsDQogICJRMTRhIiwiUTE0YiIsIlExNGMiLCJRMTRkIiwiUTE0ZSIsIlExNGYiLCJRMTRnIiwNCiAgIlExNWEiLCJRMTViIiwiUTE1YyIsIlExNWQiLCJRMTVlIiwiUTE1ZiIsIlExNWciDQopDQoNCiMgZXhwbGljaXQgbWFwcGluZyBmcm9tIGNvbHVtbiBzdWZmaXggKGHigJNnKSB0byBiYW5rIG5hbWUNCmJhbmtfbG9va3VwIDwtIHRpYmJsZSgNCiAgYmFua19jb2RlICA9IGxldHRlcnNbMTo3XSwNCiAgYmFua19sYWJlbCA9IGMoIk9UUCIsDQogICAgICAgICAgICAgICAgICJHb3Jlbmpza2EgQmFua2EiLA0KICAgICAgICAgICAgICAgICAiTkxCIiwNCiAgICAgICAgICAgICAgICAgIlJldm9sdXQiLA0KICAgICAgICAgICAgICAgICAiTjI2IiwNCiAgICAgICAgICAgICAgICAgIkludGVzYSBTYW5QYW9sbyIsDQogICAgICAgICAgICAgICAgICJVbmlDcmVkaXQiKQ0KKQ0KDQojIGhlbHBlciB0YWJsZSBkZXNjcmliaW5nIGVhY2ggUTEz4oCTMTUgdmFyaWFibGUNCnFtZXRhIDwtIHRpYmJsZSh2YXJpYWJsZSA9IHBlcmNlcHRfdmFycykgJT4lDQogIG11dGF0ZSgNCiAgICBxY29kZSAgICAgPSBzdWJzdHIodmFyaWFibGUsIDEsIDMpLCAgICAgIyBRMTMsIFExNCwgUTE1DQogICAgYmFua19jb2RlID0gc3Vic3RyKHZhcmlhYmxlLCA0LCA0KSAgICAgICMgYeKAk2cNCiAgKSAlPiUNCiAgbGVmdF9qb2luKGJhbmtfbG9va3VwLCBieSA9ICJiYW5rX2NvZGUiKSAlPiUNCiAgbXV0YXRlKA0KICAgIGF0dHJpYnV0ZSA9IGNhc2Vfd2hlbigNCiAgICAgIHFjb2RlID09ICJRMTMiIH4gImlubm92YXRpb24iLA0KICAgICAgcWNvZGUgPT0gIlExNCIgfiAiY3VzdG9tZXJfc3VwcG9ydCIsDQogICAgICBxY29kZSA9PSAiUTE1IiB+ICJyZWxpYWJpbGl0eSIsDQogICAgICBUUlVFIH4gcWNvZGUNCiAgICApDQogICkNCg0KIyMgNC4gQnVpbGQgYmFuayB4IGF0dHJpYnV0ZSBtYXRyaXggZm9yIGNsdXN0ZXIgMyAtLS0tDQoNCmNsdXN0ZXIzIDwtIGRhdGFfY2x1c3RlciAlPiUNCiAgZmlsdGVyKGNsdXN0ZXIgPT0gIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiKQ0KDQpjbHVzdGVyM19wZXJjZXB0IDwtIGNsdXN0ZXIzICU+JQ0KICBzZWxlY3QoYWxsX29mKHBlcmNlcHRfdmFycykpICU+JQ0KICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgYXMubnVtZXJpYykpDQoNCm1lYW5zX2MzIDwtIGNsdXN0ZXIzX3BlcmNlcHQgJT4lDQogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+IG1lYW4oLngsIG5hLnJtID0gVFJVRSkpKQ0KDQptZWFuc19sb25nIDwtIG1lYW5zX2MzICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIikgJT4lDQogIGxlZnRfam9pbihxbWV0YSwgYnkgPSAidmFyaWFibGUiKQ0KDQpiYW5rX2F0dHJfbWF0IDwtIG1lYW5zX2xvbmcgJT4lDQogIGdyb3VwX2J5KGJhbmtfbGFiZWwsIGF0dHJpYnV0ZSkgJT4lDQogIHN1bW1hcmlzZShtZWFuX3Njb3JlID0gbWVhbihtZWFuX3Njb3JlKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lDQogIHBpdm90X3dpZGVyKA0KICAgIGlkX2NvbHMgPSBiYW5rX2xhYmVsLA0KICAgIG5hbWVzX2Zyb20gPSBhdHRyaWJ1dGUsDQogICAgdmFsdWVzX2Zyb20gPSBtZWFuX3Njb3JlDQogICkgJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KDQpyb3duYW1lcyhiYW5rX2F0dHJfbWF0KSA8LSBiYW5rX2F0dHJfbWF0JGJhbmtfbGFiZWwNCmJhbmtfYXR0cl9tYXQkYmFua19sYWJlbCA8LSBOVUxMDQoNCiMjIDUuIFBDQSBmb3IgYmFua3MgKGNsdXN0ZXIgMykgLS0tLQ0KDQpwY2FfYmFua3NfYzMgPC0gcHJjb21wKGJhbmtfYXR0cl9tYXQsIHNjYWxlLiA9IFRSVUUpDQoNCnNjb3Jlc19jMyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jMyR4WywgMToyXSkNCnNjb3Jlc19jMyRiYW5rX2xhYmVsIDwtIHJvd25hbWVzKHNjb3Jlc19jMykNCg0KbG9hZGluZ3NfYzMgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzMkcm90YXRpb25bLCAxOjJdKQ0KbG9hZGluZ3NfYzMkYXR0cmlidXRlIDwtIHJvd25hbWVzKGxvYWRpbmdzX2MzKQ0KDQphcnJvd19zY2FsZSA8LSAxLjUNCmxvYWRpbmdzX2MzIDwtIGxvYWRpbmdzX2MzICU+JQ0KICBtdXRhdGUoUEMxID0gUEMxICogYXJyb3dfc2NhbGUsDQogICAgICAgICBQQzIgPSBQQzIgKiBhcnJvd19zY2FsZSkNCg0KIyMgNi4gUGxvdDogcGVyY2VwdHVhbCBtYXAgb2YgYmFua3Mg4oCTIGNsdXN0ZXIgMyAtLS0tDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gc2NvcmVzX2MzLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLCB5ID0gUEMyKSwNCiAgICAgICAgICAgICBzaXplID0gMi44LCBjb2xvdXIgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gc2NvcmVzX2MzLA0KICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gYmFua19sYWJlbCksDQogICAgICAgICAgICB2anVzdCA9IC0wLjcsIHNpemUgPSAzLjIpICsNCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBsb2FkaW5nc19jMywNCiAgICAgICAgICAgICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBQQzEsIHllbmQgPSBQQzIpLA0KICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLA0KICAgICAgICAgICAgICAgY29sb3VyID0gImdyZXk0MCIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBsb2FkaW5nc19jMywNCiAgICAgICAgICAgIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGF0dHJpYnV0ZSksDQogICAgICAgICAgICBoanVzdCA9IDAuNSwgdmp1c3QgPSAtMC40LCBjb2xvdXIgPSAiZ3JleTQwIiwgc2l6ZSA9IDMpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gImdyZXk3NSIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gImdyZXk3NSIpICsNCiAgY29vcmRfZXF1YWwoeGxpbSA9IGMobWluKHNjb3Jlc19jMyRQQzEpIC0gMC44LCBtYXgoc2NvcmVzX2MzJFBDMSkgKyAwLjgpLA0KICAgICAgICAgICAgICB5bGltID0gYyhtaW4oc2NvcmVzX2MzJFBDMikgLSAwLjgsIG1heChzY29yZXNfYzMkUEMyKSArIDAuOCksDQogICAgICAgICAgICAgIGV4cGFuZCA9IFRSVUUpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJQZXJjZXB0dWFsIE1hcCBvZiBCYW5rcyDigJMgQ2x1c3RlciAzIiwNCiAgICB4ID0gIk92ZXJhbGwgRGlnaXRhbCBCYW5raW5nIFBlcmZvcm1hbmNlIiwNCiAgICB5ID0gIkN1c3RvbWVyIFN1cHBvcnQgdnMuIElubm92YXRpb24iDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkNCiAgKQ0KDQpgYGANCmBgYHtyfQ0KYmFua19hdHRyX21hdA0KYGBgDQoNCmBgYHtyfQ0KIyBsb2FkaW5ncyBmb3IgZWFjaCBhdHRyaWJ1dGUgb24gUEMxIGFuZCBQQzINCmxvYWRfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzMkcm90YXRpb25bLCAxOjJdKQ0KbG9hZF90YWJsZSRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZF90YWJsZSkNCnJvd25hbWVzKGxvYWRfdGFibGUpIDwtIE5VTEwNCg0KbG9hZF90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KIyBiYW5rIGF0dHJpYnV0ZSBtZWFucyB3ZSBhbHJlYWR5IGhhZDoNCmJhbmtfYXR0cl9tYXQgICAjIHJvd3MgPSBiYW5rcywgY29scyA9IGlubm92YXRpb24sIGN1c3RvbWVyX3N1cHBvcnQsIHJlbGlhYmlsaXR5DQoNCiMgam9pbiB3aXRoIHNjb3JlcyBvbiBQQzINCmJhbmtfcGMyIDwtIHNjb3Jlc19jMyAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsIFBDMikgJT4lDQogIGxlZnRfam9pbigNCiAgICBiYW5rX2F0dHJfbWF0ICU+JQ0KICAgICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImJhbmtfbGFiZWwiKSwNCiAgICBieSA9ICJiYW5rX2xhYmVsIg0KICApDQoNCmJhbmtfcGMyDQoNCmBgYA0KYGBge3J9DQpiYW5rX3BjMiA8LSBzY29yZXNfYzMgJT4lDQogIHNlbGVjdChiYW5rX2xhYmVsLCBQQzIpICU+JQ0KICBsZWZ0X2pvaW4oDQogICAgYmFua19hdHRyX21hdCAlPiUNCiAgICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJiYW5rX2xhYmVsIiksDQogICAgYnkgPSAiYmFua19sYWJlbCINCiAgKQ0KDQpiYW5rX3BjMg0KYGBgDQoNCmBgYHtyfQ0KIyBsb2FkX3RhYmxlOiBjb2x1bW5zIFBDMSwgUEMyLCBhdHRyaWJ1dGUgKGlubm92YXRpb24sIGN1c3RvbWVyX3N1cHBvcnQsIHJlbGlhYmlsaXR5KQ0KbG9hZF90YWJsZQ0KDQojIDEpIHB1dCBQQzIgbG9hZGluZ3MgaW50byBhIG5hbWVkIHZlY3Rvcg0KcGMyX2xvYWQgPC0gbG9hZF90YWJsZSRQQzINCm5hbWVzKHBjMl9sb2FkKSA8LSBsb2FkX3RhYmxlJGF0dHJpYnV0ZQ0KDQojIDIpIGNvbXB1dGUgY29udHJpYnV0aW9uIHNjb3JlczogYXR0cmlidXRlX21lYW4gKiBQQzIgbG9hZGluZw0KY29udHJpYl9wYzIgPC0gYmFua19wYzIgJT4lDQogIG11dGF0ZSgNCiAgICBjb250cmliX2N1c3RvbWVyX3N1cHBvcnQgPSBjdXN0b21lcl9zdXBwb3J0ICogcGMyX2xvYWRbImN1c3RvbWVyX3N1cHBvcnQiXSwNCiAgICBjb250cmliX2lubm92YXRpb24gICAgICAgPSBpbm5vdmF0aW9uICAgICAgICogcGMyX2xvYWRbImlubm92YXRpb24iXSwNCiAgICBjb250cmliX3JlbGlhYmlsaXR5ICAgICAgPSByZWxpYWJpbGl0eSAgICAgICogcGMyX2xvYWRbInJlbGlhYmlsaXR5Il0NCiAgKQ0KDQpjb250cmliX3BjMg0KDQpgYGANCmBgYHtyfQ0KY29udHJpYl9wYzJfbG9uZyA8LSBjb250cmliX3BjMiAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsDQogICAgICAgICBjb250cmliX2N1c3RvbWVyX3N1cHBvcnQsDQogICAgICAgICBjb250cmliX2lubm92YXRpb24sDQogICAgICAgICBjb250cmliX3JlbGlhYmlsaXR5KSAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gc3RhcnRzX3dpdGgoImNvbnRyaWJfIiksDQogICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwNCiAgICB2YWx1ZXNfdG8gPSAiY29udHJpYnV0aW9uIg0KICApICU+JQ0KICBtdXRhdGUoYXR0cmlidXRlID0gZ3N1YigiY29udHJpYl8iLCAiIiwgYXR0cmlidXRlKSkNCg0KY29udHJpYl9wYzJfbG9uZw0KDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChjb250cmliX3BjMl9sb25nLA0KICAgICAgIGFlcyh4ID0gYXR0cmlidXRlLCB5ID0gY29udHJpYnV0aW9uLCBmaWxsID0gYXR0cmlidXRlKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGZhY2V0X3dyYXAofiBiYW5rX2xhYmVsKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQXBwcm94aW1hdGUgYXR0cmlidXRlIGNvbnRyaWJ1dGlvbnMgdG8gRGltZW5zaW9uIDIgKGNsdXN0ZXIgMykiLA0KICAgIHggPSAiQXR0cmlidXRlIiwNCiAgICB5ID0gIkNvbnRyaWJ1dGlvbiB0byBEaW0yIg0KICApDQpgYGANCmBgYHtyfQ0KbG9hZF90YWJsZTMgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzMkcm90YXRpb25bLCAxOjJdKQ0KbG9hZF90YWJsZTMkYXR0cmlidXRlIDwtIHJvd25hbWVzKGxvYWRfdGFibGUzKQ0Kcm93bmFtZXMobG9hZF90YWJsZTMpIDwtIE5VTEwNCg0KbG9hZF90YWJsZTMNCg0KYGBgDQoNCiMjIENsdXN0ZXIgNQ0KYGBge3J9DQojIyBDbHVzdGVyIDU6IGJhbmsgeCBhdHRyaWJ1dGUgbWF0cml4IC0tLS0NCg0KY2x1c3RlcjUgPC0gZGF0YV9jbHVzdGVyICU+JQ0KICBmaWx0ZXIoY2x1c3RlciA9PSAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiKSAgICMgY2x1c3RlciA1IGxhYmVsDQoNCmNsdXN0ZXI1X3BlcmNlcHQgPC0gY2x1c3RlcjUgJT4lDQogIHNlbGVjdChhbGxfb2YocGVyY2VwdF92YXJzKSkgJT4lDQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5udW1lcmljKSkNCg0KbWVhbnNfYzUgPC0gY2x1c3RlcjVfcGVyY2VwdCAlPiUNCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gbWVhbigueCwgbmEucm0gPSBUUlVFKSkpDQoNCm1lYW5zX2M1X2xvbmcgPC0gbWVhbnNfYzUgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm1lYW5fc2NvcmUiKSAlPiUNCiAgbGVmdF9qb2luKHFtZXRhLCBieSA9ICJ2YXJpYWJsZSIpDQoNCmJhbmtfYXR0cl9tYXQ1IDwtIG1lYW5zX2M1X2xvbmcgJT4lDQogIGdyb3VwX2J5KGJhbmtfbGFiZWwsIGF0dHJpYnV0ZSkgJT4lDQogIHN1bW1hcmlzZShtZWFuX3Njb3JlID0gbWVhbihtZWFuX3Njb3JlKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lDQogIHBpdm90X3dpZGVyKA0KICAgIGlkX2NvbHMgPSBiYW5rX2xhYmVsLA0KICAgIG5hbWVzX2Zyb20gPSBhdHRyaWJ1dGUsDQogICAgdmFsdWVzX2Zyb20gPSBtZWFuX3Njb3JlDQogICkgJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KDQpyb3duYW1lcyhiYW5rX2F0dHJfbWF0NSkgPC0gYmFua19hdHRyX21hdDUkYmFua19sYWJlbA0KYmFua19hdHRyX21hdDUkYmFua19sYWJlbCA8LSBOVUxMDQoNCmBgYA0KDQpgYGB7cn0NCiMjIFBDQSBmb3IgYmFua3Mg4oCTIGNsdXN0ZXIgNSAtLS0tDQoNCnBjYV9iYW5rc19jNSA8LSBwcmNvbXAoYmFua19hdHRyX21hdDUsIHNjYWxlLiA9IFRSVUUpDQoNCnNjb3Jlc19jNSA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jNSR4WywgMToyXSkNCnNjb3Jlc19jNSRiYW5rX2xhYmVsIDwtIHJvd25hbWVzKHNjb3Jlc19jNSkNCg0KbG9hZGluZ3NfYzUgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzUkcm90YXRpb25bLCAxOjJdKQ0KbG9hZGluZ3NfYzUkYXR0cmlidXRlIDwtIHJvd25hbWVzKGxvYWRpbmdzX2M1KQ0KDQphcnJvd19zY2FsZSA8LSAxLjUNCmxvYWRpbmdzX2M1IDwtIGxvYWRpbmdzX2M1ICU+JQ0KICBtdXRhdGUoUEMxID0gUEMxICogYXJyb3dfc2NhbGUsDQogICAgICAgICBQQzIgPSBQQzIgKiBhcnJvd19zY2FsZSkNCg0KIyMgUGxvdDogcGVyY2VwdHVhbCBtYXAgZm9yIGNsdXN0ZXIgNSAtLS0tDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gc2NvcmVzX2M1LA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLCB5ID0gUEMyKSwNCiAgICAgICAgICAgICBzaXplID0gMi44LCBjb2xvdXIgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChkYXRhID0gc2NvcmVzX2M1LA0KICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gYmFua19sYWJlbCksDQogICAgICAgICAgICB2anVzdCA9IC0wLjcsIHNpemUgPSAzLjIpICsNCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBsb2FkaW5nc19jNSwNCiAgICAgICAgICAgICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBQQzEsIHllbmQgPSBQQzIpLA0KICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLA0KICAgICAgICAgICAgICAgY29sb3VyID0gImdyZXk0MCIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBsb2FkaW5nc19jNSwNCiAgICAgICAgICAgIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGF0dHJpYnV0ZSksDQogICAgICAgICAgICBoanVzdCA9IDAuNSwgdmp1c3QgPSAtMC40LCBjb2xvdXIgPSAiZ3JleTQwIiwgc2l6ZSA9IDMpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gImdyZXk3NSIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gImdyZXk3NSIpICsNCiAgY29vcmRfZXF1YWwoeGxpbSA9IGMobWluKHNjb3Jlc19jNSRQQzEpIC0gMC44LCBtYXgoc2NvcmVzX2M1JFBDMSkgKyAwLjgpLA0KICAgICAgICAgICAgICB5bGltID0gYyhtaW4oc2NvcmVzX2M1JFBDMikgLSAwLjgsIG1heChzY29yZXNfYzUkUEMyKSArIDAuOCksDQogICAgICAgICAgICAgIGV4cGFuZCA9IFRSVUUpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJQZXJjZXB0dWFsIE1hcCBvZiBCYW5rcyDigJMgQ2x1c3RlciA1IiwNCiAgICB4ID0gIk92ZXJhbGwgRGlnaXRhbCBCYW5raW5nIFBlcmZvcm1hbmNlIiwNCiAgICB5ID0gIkN1c3RvbWVyIFN1cHBvcnQgdnMuIFJlbGFpYmlsaXR5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpDQogICkNCg0KYGBgDQpgYGB7cn0NCiMjIExvYWRpbmdzIHRhYmxlIGZvciBjbHVzdGVyIDUgLS0tLQ0KbG9hZF90YWJsZTUgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzUkcm90YXRpb25bLCAxOjJdKQ0KbG9hZF90YWJsZTUkYXR0cmlidXRlIDwtIHJvd25hbWVzKGxvYWRfdGFibGU1KQ0Kcm93bmFtZXMobG9hZF90YWJsZTUpIDwtIE5VTEwNCg0KIyBQQzIgbG9hZGluZ3MgYXMgbmFtZWQgdmVjdG9yDQpwYzJfbG9hZDUgPC0gbG9hZF90YWJsZTUkUEMyDQpuYW1lcyhwYzJfbG9hZDUpIDwtIGxvYWRfdGFibGU1JGF0dHJpYnV0ZQ0KDQojIGpvaW4gUEMyIHNjb3JlcyB3aXRoIGF0dHJpYnV0ZSBtZWFucw0KYmFua19wYzJfNSA8LSBzY29yZXNfYzUgJT4lDQogIHNlbGVjdChiYW5rX2xhYmVsLCBQQzIpICU+JQ0KICBsZWZ0X2pvaW4oDQogICAgYmFua19hdHRyX21hdDUgJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJiYW5rX2xhYmVsIiksDQogICAgYnkgPSAiYmFua19sYWJlbCINCiAgKQ0KDQojIGNvbnRyaWJ1dGlvbiBzY29yZXMNCmNvbnRyaWJfcGMyXzUgPC0gYmFua19wYzJfNSAlPiUNCiAgbXV0YXRlKA0KICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCA9IGN1c3RvbWVyX3N1cHBvcnQgKiBwYzJfbG9hZDVbImN1c3RvbWVyX3N1cHBvcnQiXSwNCiAgICBjb250cmliX2lubm92YXRpb24gICAgICAgPSBpbm5vdmF0aW9uICAgICAgICogcGMyX2xvYWQ1WyJpbm5vdmF0aW9uIl0sDQogICAgY29udHJpYl9yZWxpYWJpbGl0eSAgICAgID0gcmVsaWFiaWxpdHkgICAgICAqIHBjMl9sb2FkNVsicmVsaWFiaWxpdHkiXQ0KICApDQoNCmNvbnRyaWJfcGMyXzUNCg0KYGBgDQoNCmBgYHtyfQ0KY29udHJpYl9wYzJfNV9sb25nIDwtIGNvbnRyaWJfcGMyXzUgJT4lDQogIHNlbGVjdChiYW5rX2xhYmVsLA0KICAgICAgICAgY29udHJpYl9jdXN0b21lcl9zdXBwb3J0LA0KICAgICAgICAgY29udHJpYl9pbm5vdmF0aW9uLA0KICAgICAgICAgY29udHJpYl9yZWxpYWJpbGl0eSkgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gc3RhcnRzX3dpdGgoImNvbnRyaWJfIiksDQogICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwNCiAgICB2YWx1ZXNfdG8gPSAiY29udHJpYnV0aW9uIg0KICApICU+JQ0KICBtdXRhdGUoYXR0cmlidXRlID0gZ3N1YigiY29udHJpYl8iLCAiIiwgYXR0cmlidXRlKSkNCg0KZ2dwbG90KGNvbnRyaWJfcGMyXzVfbG9uZywNCiAgICAgICBhZXMoeCA9IGF0dHJpYnV0ZSwgeSA9IGNvbnRyaWJ1dGlvbiwgZmlsbCA9IGF0dHJpYnV0ZSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBmYWNldF93cmFwKH4gYmFua19sYWJlbCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkFwcHJveGltYXRlIGF0dHJpYnV0ZSBjb250cmlidXRpb25zIHRvIERpbWVuc2lvbiAyIChjbHVzdGVyIDUpIiwNCiAgICB4ID0gIkF0dHJpYnV0ZSIsDQogICAgeSA9ICJDb250cmlidXRpb24gdG8gRGltMiINCiAgKQ0KDQpgYGANCmBgYHtyfQ0KYmFua19wYzJfNSA8LSBzY29yZXNfYzUgJT4lDQogIHNlbGVjdChiYW5rX2xhYmVsLCBQQzIpICU+JQ0KICBsZWZ0X2pvaW4oDQogICAgYmFua19hdHRyX21hdDUgJT4lDQogICAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiYmFua19sYWJlbCIpLA0KICAgIGJ5ID0gImJhbmtfbGFiZWwiDQogICkNCg0KYmFua19wYzJfNQ0KDQpgYGANCg0KYGBge3J9DQojIGxvYWRpbmdzIGZvciBjbHVzdGVyIDUgKFBDMSBhbmQgUEMyKQ0KbG9hZF90YWJsZTUgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzUkcm90YXRpb25bLCAxOjJdKQ0KbG9hZF90YWJsZTUkYXR0cmlidXRlIDwtIHJvd25hbWVzKGxvYWRfdGFibGU1KQ0Kcm93bmFtZXMobG9hZF90YWJsZTUpIDwtIE5VTEwNCg0KbG9hZF90YWJsZTUNCmBgYA0KYGBge3J9DQojIyBsb2FkaW5ncyBmb3IgY2x1c3RlciA1IGFscmVhZHkgaW4gbG9hZF90YWJsZTUNCiMgcGMyX2xvYWQ1OiBuYW1lZCB2ZWN0b3Igb2YgUEMyIGxvYWRpbmdzDQpwYzJfbG9hZDUgPC0gbG9hZF90YWJsZTUkUEMyDQpuYW1lcyhwYzJfbG9hZDUpIDwtIGxvYWRfdGFibGU1JGF0dHJpYnV0ZQ0KDQojIyBiYW5rX3BjMl81IGFscmVhZHkgY3JlYXRlZCBsaWtlIHRoaXM6DQojIGJhbmtfcGMyXzUgPC0gc2NvcmVzX2M1ICU+JQ0KIyAgIHNlbGVjdChiYW5rX2xhYmVsLCBQQzIpICU+JQ0KIyAgIGxlZnRfam9pbigNCiMgICAgIGJhbmtfYXR0cl9tYXQ1ICU+JSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiYmFua19sYWJlbCIpLA0KIyAgICAgYnkgPSAiYmFua19sYWJlbCINCiMgICApDQoNCmNvbnRyaWJfcGMyXzUgPC0gYmFua19wYzJfNSAlPiUNCiAgbXV0YXRlKA0KICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCA9IGN1c3RvbWVyX3N1cHBvcnQgKiBwYzJfbG9hZDVbImN1c3RvbWVyX3N1cHBvcnQiXSwNCiAgICBjb250cmliX2lubm92YXRpb24gICAgICAgPSBpbm5vdmF0aW9uICAgICAgICogcGMyX2xvYWQ1WyJpbm5vdmF0aW9uIl0sDQogICAgY29udHJpYl9yZWxpYWJpbGl0eSAgICAgID0gcmVsaWFiaWxpdHkgICAgICAqIHBjMl9sb2FkNVsicmVsaWFiaWxpdHkiXQ0KICApDQoNCmNvbnRyaWJfcGMyXzUNCg0KYGBgDQoNCiMjIENsdXN0ZXIgMg0KYGBge3J9DQojIyBDbHVzdGVyIDI6IGJhbmsgeCBhdHRyaWJ1dGUgbWF0cml4IC0tLS0NCg0KY2x1c3RlcjIgPC0gZGF0YV9jbHVzdGVyICU+JQ0KICBmaWx0ZXIoY2x1c3RlciA9PSAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIpICAgIyBjbHVzdGVyIDIgbGFiZWwNCg0KY2x1c3RlcjJfcGVyY2VwdCA8LSBjbHVzdGVyMiAlPiUNCiAgc2VsZWN0KGFsbF9vZihwZXJjZXB0X3ZhcnMpKSAlPiUNCiAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIGFzLm51bWVyaWMpKQ0KDQptZWFuc19jMiA8LSBjbHVzdGVyMl9wZXJjZXB0ICU+JQ0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBtZWFuKC54LCBuYS5ybSA9IFRSVUUpKSkNCg0KbWVhbnNfYzJfbG9uZyA8LSBtZWFuc19jMiAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAibWVhbl9zY29yZSIpICU+JQ0KICBsZWZ0X2pvaW4ocW1ldGEsIGJ5ID0gInZhcmlhYmxlIikNCg0KYmFua19hdHRyX21hdDIgPC0gbWVhbnNfYzJfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoYmFua19sYWJlbCwgYXR0cmlidXRlKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fc2NvcmUgPSBtZWFuKG1lYW5fc2NvcmUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUNCiAgcGl2b3Rfd2lkZXIoDQogICAgaWRfY29scyA9IGJhbmtfbGFiZWwsDQogICAgbmFtZXNfZnJvbSA9IGF0dHJpYnV0ZSwNCiAgICB2YWx1ZXNfZnJvbSA9IG1lYW5fc2NvcmUNCiAgKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQoNCnJvd25hbWVzKGJhbmtfYXR0cl9tYXQyKSA8LSBiYW5rX2F0dHJfbWF0MiRiYW5rX2xhYmVsDQpiYW5rX2F0dHJfbWF0MiRiYW5rX2xhYmVsIDwtIE5VTEwNCg0KYGBgDQoNCmBgYHtyfQ0KIyMgUENBIGZvciBiYW5rcyDigJMgY2x1c3RlciAyIC0tLS0NCg0KcGNhX2JhbmtzX2MyIDwtIHByY29tcChiYW5rX2F0dHJfbWF0Miwgc2NhbGUuID0gVFJVRSkNCg0Kc2NvcmVzX2MyIDwtIGFzLmRhdGEuZnJhbWUocGNhX2JhbmtzX2MyJHhbLCAxOjJdKQ0Kc2NvcmVzX2MyJGJhbmtfbGFiZWwgPC0gcm93bmFtZXMoc2NvcmVzX2MyKQ0KDQpsb2FkaW5nc19jMiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jMiRyb3RhdGlvblssIDE6Ml0pDQpsb2FkaW5nc19jMiRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZGluZ3NfYzIpDQoNCmFycm93X3NjYWxlIDwtIDEuNQ0KbG9hZGluZ3NfYzIgPC0gbG9hZGluZ3NfYzIgJT4lDQogIG11dGF0ZShQQzEgPSBQQzEgKiBhcnJvd19zY2FsZSwNCiAgICAgICAgIFBDMiA9IFBDMiAqIGFycm93X3NjYWxlKQ0KDQojIyBQbG90OiBwZXJjZXB0dWFsIG1hcCBmb3IgY2x1c3RlciAyIC0tLS0NCg0KZ2dwbG90KCkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBzY29yZXNfYzIsDQogICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIpLA0KICAgICAgICAgICAgIHNpemUgPSAyLjgsIGNvbG91ciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBzY29yZXNfYzIsDQogICAgICAgICAgICBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBiYW5rX2xhYmVsKSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNywgc2l6ZSA9IDMuMikgKw0KICBnZW9tX3NlZ21lbnQoZGF0YSA9IGxvYWRpbmdzX2MyLA0KICAgICAgICAgICAgICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IFBDMSwgeWVuZCA9IFBDMiksDQogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksDQogICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTQwIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGxvYWRpbmdzX2MyLA0KICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gYXR0cmlidXRlKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCB2anVzdCA9IC0wLjQsIGNvbG91ciA9ICJncmV5NDAiLCBzaXplID0gMykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiZ3JleTc1IikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiZ3JleTc1IikgKw0KICBjb29yZF9lcXVhbCh4bGltID0gYyhtaW4oc2NvcmVzX2MyJFBDMSkgLSAwLjgsIG1heChzY29yZXNfYzIkUEMxKSArIDAuOCksDQogICAgICAgICAgICAgIHlsaW0gPSBjKG1pbihzY29yZXNfYzIkUEMyKSAtIDAuOCwgbWF4KHNjb3Jlc19jMiRQQzIpICsgMC44KSwNCiAgICAgICAgICAgICAgZXhwYW5kID0gVFJVRSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIOKAkyBDbHVzdGVyIDIiLA0KICAgIHggPSAiT3ZlcmFsbCBEaWdpdGFsIEJhbmtpbmcgUGVyZm9ybWFuY2UiLA0KICAgIHkgPSAiQ3VzdG9tZXIgU3VwcG9ydCB2cy4gUmVsaWFiaWxpdHkiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkNCiAgKQ0KDQpgYGANCg0KYGBge3J9DQpiYW5rX3BjMl8yIDwtIHNjb3Jlc19jMiAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsIFBDMikgJT4lDQogIGxlZnRfam9pbigNCiAgICBiYW5rX2F0dHJfbWF0MiAlPiUNCiAgICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJiYW5rX2xhYmVsIiksDQogICAgYnkgPSAiYmFua19sYWJlbCINCiAgKQ0KDQpiYW5rX3BjMl8yDQoNCmBgYA0KYGBge3J9DQpsb2FkX3RhYmxlMiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jMiRyb3RhdGlvblssIDE6Ml0pDQpsb2FkX3RhYmxlMiRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZF90YWJsZTIpDQpyb3duYW1lcyhsb2FkX3RhYmxlMikgPC0gTlVMTA0KDQpsb2FkX3RhYmxlMg0KDQpgYGANCg0KYGBge3J9DQpwYzJfbG9hZDIgPC0gbG9hZF90YWJsZTIkUEMyDQpuYW1lcyhwYzJfbG9hZDIpIDwtIGxvYWRfdGFibGUyJGF0dHJpYnV0ZQ0KDQpjb250cmliX3BjMl8yIDwtIGJhbmtfcGMyXzIgJT4lDQogIG11dGF0ZSgNCiAgICBjb250cmliX2N1c3RvbWVyX3N1cHBvcnQgPSBjdXN0b21lcl9zdXBwb3J0ICogcGMyX2xvYWQyWyJjdXN0b21lcl9zdXBwb3J0Il0sDQogICAgY29udHJpYl9pbm5vdmF0aW9uICAgICAgID0gaW5ub3ZhdGlvbiAgICAgICAqIHBjMl9sb2FkMlsiaW5ub3ZhdGlvbiJdLA0KICAgIGNvbnRyaWJfcmVsaWFiaWxpdHkgICAgICA9IHJlbGlhYmlsaXR5ICAgICAgKiBwYzJfbG9hZDJbInJlbGlhYmlsaXR5Il0NCiAgKQ0KDQpjb250cmliX3BjMl8yDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KDQojIyBQQzIgbG9hZGluZ3MgZm9yIGNsdXN0ZXIgMg0KcGMyX2xvYWQyIDwtIGxvYWRfdGFibGUyJFBDMg0KbmFtZXMocGMyX2xvYWQyKSA8LSBsb2FkX3RhYmxlMiRhdHRyaWJ1dGUNCg0KIyMgQ29udHJpYnV0aW9uIHNjb3JlcyB0YWJsZSBmb3IgY2x1c3RlciAyDQpjb250cmliX3BjMl8yIDwtIGJhbmtfcGMyXzIgJT4lDQogIG11dGF0ZSgNCiAgICBjb250cmliX2N1c3RvbWVyX3N1cHBvcnQgPSBjdXN0b21lcl9zdXBwb3J0ICogcGMyX2xvYWQyWyJjdXN0b21lcl9zdXBwb3J0Il0sDQogICAgY29udHJpYl9pbm5vdmF0aW9uICAgICAgID0gaW5ub3ZhdGlvbiAgICAgICAqIHBjMl9sb2FkMlsiaW5ub3ZhdGlvbiJdLA0KICAgIGNvbnRyaWJfcmVsaWFiaWxpdHkgICAgICA9IHJlbGlhYmlsaXR5ICAgICAgKiBwYzJfbG9hZDJbInJlbGlhYmlsaXR5Il0NCiAgKQ0KDQojIyBMb25nIGZvcm1hdCBmb3IgcGxvdHRpbmcNCmNvbnRyaWJfcGMyXzJfbG9uZyA8LSBjb250cmliX3BjMl8yICU+JQ0KICBzZWxlY3QoYmFua19sYWJlbCwNCiAgICAgICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCwNCiAgICAgICAgIGNvbnRyaWJfaW5ub3ZhdGlvbiwNCiAgICAgICAgIGNvbnRyaWJfcmVsaWFiaWxpdHkpICU+JQ0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IHN0YXJ0c193aXRoKCJjb250cmliXyIpLA0KICAgIG5hbWVzX3RvID0gImF0dHJpYnV0ZSIsDQogICAgdmFsdWVzX3RvID0gImNvbnRyaWJ1dGlvbiINCiAgKSAlPiUNCiAgbXV0YXRlKGF0dHJpYnV0ZSA9IGdzdWIoImNvbnRyaWJfIiwgIiIsIGF0dHJpYnV0ZSkpDQoNCiMjIEJhciBwbG90DQpnZ3Bsb3QoY29udHJpYl9wYzJfMl9sb25nLA0KICAgICAgIGFlcyh4ID0gYXR0cmlidXRlLCB5ID0gY29udHJpYnV0aW9uLCBmaWxsID0gYXR0cmlidXRlKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGZhY2V0X3dyYXAofiBiYW5rX2xhYmVsKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQXBwcm94aW1hdGUgYXR0cmlidXRlIGNvbnRyaWJ1dGlvbnMgdG8gRGltZW5zaW9uIDIg4oCTIENsdXN0ZXIgMiIsDQogICAgeCA9ICJBdHRyaWJ1dGUiLA0KICAgIHkgPSAiQ29udHJpYnV0aW9uIHRvIERpbTIiDQogICkNCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHRpZHlyKQ0KDQojIG1ha2Ugc3VyZSBsb2dpY2FsIGNvbWJvIHZhcnMgYXJlIG51bWVyaWMgZm9yIHRlc3RpbmcNCmJhbmtfZ3JvdXBzX3Rlc3QgPC0gYmFua19ncm91cHMgfD4NCiAgbXV0YXRlKA0KICAgIGFjcm9zcygNCiAgICAgIGMocmV2b2x1dF9vbmx5LCBubGJfcmV2b2x1dCwgb3RwX3Jldm9sdXQsIHJldm9sdXRfb3RoZXIpLA0KICAgICAgfiBhcy5pbnRlZ2VyKC4pDQogICAgKQ0KICApDQoNCiMgaGVscGVyOiBjaGktc3F1YXJlIHdpdGggc2ltdWxhdGVkIHAtdmFsdWUgZmFsbGJhY2sgaWYgZXhwZWN0ZWQgY291bnRzIGFyZSBzbWFsbA0KcnVuX2NsdXN0ZXJfc2lnX3Rlc3QgPC0gZnVuY3Rpb24oZGF0YSwgdmFyX25hbWUpIHsNCiAgdGFiIDwtIHRhYmxlKGRhdGEkY2x1c3RlciwgZGF0YVtbdmFyX25hbWVdXSkNCg0KICBjaGkgPC0gc3VwcHJlc3NXYXJuaW5ncyhjaGlzcS50ZXN0KHRhYikpDQoNCiAgaWYgKGFueShjaGkkZXhwZWN0ZWQgPCA1KSkgew0KICAgIGNoaV9zaW0gPC0gY2hpc3EudGVzdCh0YWIsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFLCBCID0gMTAwMDApDQoNCiAgICB0aWJibGUoDQogICAgICBncm91cCA9IHZhcl9uYW1lLA0KICAgICAgdGVzdCA9ICJDaGktc3F1YXJlIChzaW11bGF0ZWQgcC12YWx1ZSkiLA0KICAgICAgc3RhdGlzdGljID0gdW5uYW1lKGNoaSRzdGF0aXN0aWMpLA0KICAgICAgcF92YWx1ZSA9IGNoaV9zaW0kcC52YWx1ZQ0KICAgICkNCiAgfSBlbHNlIHsNCiAgICB0aWJibGUoDQogICAgICBncm91cCA9IHZhcl9uYW1lLA0KICAgICAgdGVzdCA9ICJDaGktc3F1YXJlIiwNCiAgICAgIHN0YXRpc3RpYyA9IHVubmFtZShjaGkkc3RhdGlzdGljKSwNCiAgICAgIHBfdmFsdWUgPSBjaGkkcC52YWx1ZQ0KICAgICkNCiAgfQ0KfQ0KDQojIG92ZXJhbGwgc2lnbmlmaWNhbmNlIGZvciBlYWNoIGJhbmstY29tYm8gYWNyb3NzIGNsdXN0ZXJzDQpjb21ib19zaWduaWZpY2FuY2UgPC0gYmluZF9yb3dzKA0KICBsYXBwbHkoDQogICAgYygicmV2b2x1dF9vbmx5IiwgIm5sYl9yZXZvbHV0IiwgIm90cF9yZXZvbHV0IiwgInJldm9sdXRfb3RoZXIiKSwNCiAgICBmdW5jdGlvbih4KSBydW5fY2x1c3Rlcl9zaWdfdGVzdChiYW5rX2dyb3Vwc190ZXN0LCB4KQ0KICApDQopIHw+DQogIG11dGF0ZShwX2Fkal9iaCA9IHAuYWRqdXN0KHBfdmFsdWUsIG1ldGhvZCA9ICJCSCIpKSB8Pg0KICBhcnJhbmdlKHBfdmFsdWUpDQoNCmNvbWJvX3NpZ25pZmljYW5jZQ0KYGBgDQoNCmBgYHtyfQ0KcGFpcndpc2VfY2x1c3Rlcl9wcm9wcyA8LSBmdW5jdGlvbihkYXRhLCB2YXJfbmFtZSkgew0KICBjb3VudHMgPC0gZGF0YSB8Pg0KICAgIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogICAgc3VtbWFyaXNlKA0KICAgICAgdXNlcnMgPSBzdW0oLmRhdGFbW3Zhcl9uYW1lXV0sIG5hLnJtID0gVFJVRSksDQogICAgICBuID0gbigpLA0KICAgICAgLmdyb3VwcyA9ICJkcm9wIg0KICAgICkNCg0KICBwdyA8LSBwYWlyd2lzZS5wcm9wLnRlc3QoDQogICAgeCA9IGNvdW50cyR1c2VycywNCiAgICBuID0gY291bnRzJG4sDQogICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIg0KICApDQoNCiAgYXMuZGF0YS5mcmFtZShhcy50YWJsZShwdyRwLnZhbHVlKSkgfD4NCiAgICBmaWx0ZXIoIWlzLm5hKEZyZXEpKSB8Pg0KICAgIHJlbmFtZSgNCiAgICAgIGNsdXN0ZXJfMSA9IFZhcjEsDQogICAgICBjbHVzdGVyXzIgPSBWYXIyLA0KICAgICAgcF9hZGpfYmggPSBGcmVxDQogICAgKSB8Pg0KICAgIG11dGF0ZShncm91cCA9IHZhcl9uYW1lLCAuYmVmb3JlID0gMSkNCn0NCg0KcGFpcndpc2VfY2x1c3Rlcl9wcm9wcyhiYW5rX2dyb3Vwc190ZXN0LCAicmV2b2x1dF9vbmx5IikNCnBhaXJ3aXNlX2NsdXN0ZXJfcHJvcHMoYmFua19ncm91cHNfdGVzdCwgIm5sYl9yZXZvbHV0IikNCnBhaXJ3aXNlX2NsdXN0ZXJfcHJvcHMoYmFua19ncm91cHNfdGVzdCwgIm90cF9yZXZvbHV0IikNCnBhaXJ3aXNlX2NsdXN0ZXJfcHJvcHMoYmFua19ncm91cHNfdGVzdCwgInJldm9sdXRfb3RoZXIiKQ0KYGBgDQoNCmBgYHtyfQ0Kc2VnbWVudF90YWIgPC0gdGFibGUoYmFua19zZWdtZW50cyRjbHVzdGVyLCBiYW5rX3NlZ21lbnRzJHNlZ21lbnQpDQoNCnNlZ21lbnRfdGVzdCA8LSBjaGlzcS50ZXN0KHNlZ21lbnRfdGFiLCBzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSwgQiA9IDEwMDAwKQ0Kc2VnbWVudF90ZXN0DQpgYGANCg0KYGBge3J9DQpydW5fc2VnbWVudF9zaWcgPC0gZnVuY3Rpb24oZGF0YSwgc2VnbWVudF9uYW1lKSB7DQogIHRtcCA8LSBkYXRhIHw+DQogICAgbXV0YXRlKGluX3NlZ21lbnQgPSBhcy5pbnRlZ2VyKHNlZ21lbnQgPT0gc2VnbWVudF9uYW1lKSkNCg0KICBydW5fY2x1c3Rlcl9zaWdfdGVzdCh0bXAsICJpbl9zZWdtZW50IikgfD4NCiAgICBtdXRhdGUoc2VnbWVudCA9IHNlZ21lbnRfbmFtZSwgLmJlZm9yZSA9IDEpIHw+DQogICAgc2VsZWN0KHNlZ21lbnQsIGV2ZXJ5dGhpbmcoKSwgLWdyb3VwKQ0KfQ0KDQpzZWdtZW50X3NpZ25pZmljYW5jZSA8LSBiaW5kX3Jvd3MoDQogIHJ1bl9zZWdtZW50X3NpZyhiYW5rX3NlZ21lbnRzLCAiUmV2b2x1dCBvbmx5IiksDQogIHJ1bl9zZWdtZW50X3NpZyhiYW5rX3NlZ21lbnRzLCAiTkxCICsgUmV2b2x1dCIpLA0KICBydW5fc2VnbWVudF9zaWcoYmFua19zZWdtZW50cywgIk9UUCArIFJldm9sdXQiKQ0KKSB8Pg0KICBtdXRhdGUocF9hZGpfYmggPSBwLmFkanVzdChwX3ZhbHVlLCBtZXRob2QgPSAiQkgiKSkNCg0Kc2VnbWVudF9zaWduaWZpY2FuY2UNCmBgYA0KDQpgYGB7cn0NCnBhaXJ3aXNlX3NlZ21lbnRfcHJvcHMgPC0gZnVuY3Rpb24oZGF0YSwgc2VnbWVudF9uYW1lKSB7DQogIGNvdW50cyA8LSBkYXRhIHw+DQogICAgbXV0YXRlKGluX3NlZ21lbnQgPSBhcy5pbnRlZ2VyKHNlZ21lbnQgPT0gc2VnbWVudF9uYW1lKSkgfD4NCiAgICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICAgIHN1bW1hcmlzZSgNCiAgICAgIHVzZXJzID0gc3VtKGluX3NlZ21lbnQsIG5hLnJtID0gVFJVRSksDQogICAgICBuID0gbigpLA0KICAgICAgLmdyb3VwcyA9ICJkcm9wIg0KICAgICkNCg0KICBwdyA8LSBwYWlyd2lzZS5wcm9wLnRlc3QoDQogICAgeCA9IGNvdW50cyR1c2VycywNCiAgICBuID0gY291bnRzJG4sDQogICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIg0KICApDQoNCiAgYXMuZGF0YS5mcmFtZShhcy50YWJsZShwdyRwLnZhbHVlKSkgfD4NCiAgICBmaWx0ZXIoIWlzLm5hKEZyZXEpKSB8Pg0KICAgIHJlbmFtZSgNCiAgICAgIGNsdXN0ZXJfMSA9IFZhcjEsDQogICAgICBjbHVzdGVyXzIgPSBWYXIyLA0KICAgICAgcF9hZGpfYmggPSBGcmVxDQogICAgKSB8Pg0KICAgIG11dGF0ZShzZWdtZW50ID0gc2VnbWVudF9uYW1lLCAuYmVmb3JlID0gMSkNCn0NCg0KcGFpcndpc2Vfc2VnbWVudF9wcm9wcyhiYW5rX3NlZ21lbnRzLCAiUmV2b2x1dCBvbmx5IikNCnBhaXJ3aXNlX3NlZ21lbnRfcHJvcHMoYmFua19zZWdtZW50cywgIk5MQiArIFJldm9sdXQiKQ0KcGFpcndpc2Vfc2VnbWVudF9wcm9wcyhiYW5rX3NlZ21lbnRzLCAiT1RQICsgUmV2b2x1dCIpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyXzVfd2FudHNfbmVlZHMgPC0gY2x1c3Rlcl9tZWFuc19wY2EyXzVfbmFtZWQgfD4NCiAgZmlsdGVyKGNsdXN0ZXIgPT0gIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIikNCg0KY2x1c3Rlcl81X3dhbnRzX25lZWRzDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkodGlkeXIpDQoNCiMga2VlcCBvbmx5IGNsdXN0ZXJzIDIsIDMsIGFuZCA1DQpiYW5rX2dyb3Vwc18yMzUgPC0gYmFua19ncm91cHMgfD4NCiAgZmlsdGVyKGNsdXN0ZXIgJWluJSBjKA0KICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICApKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGRyb3BsZXZlbHMoY2x1c3RlciksDQogICAgYWNyb3NzKA0KICAgICAgYyhyZXZvbHV0X29ubHksIG5sYl9yZXZvbHV0LCBvdHBfcmV2b2x1dCwgcmV2b2x1dF9vdGhlciksDQogICAgICB+IGFzLmludGVnZXIoLikNCiAgICApDQogICkNCmBgYA0KDQpgYGB7cn0NCnJ1bl9jbHVzdGVyX3NpZ190ZXN0IDwtIGZ1bmN0aW9uKGRhdGEsIHZhcl9uYW1lKSB7DQogIHRhYiA8LSB0YWJsZShkYXRhJGNsdXN0ZXIsIGRhdGFbW3Zhcl9uYW1lXV0pDQogIGNoaSA8LSBzdXBwcmVzc1dhcm5pbmdzKGNoaXNxLnRlc3QodGFiKSkNCiAgDQogIGlmIChhbnkoY2hpJGV4cGVjdGVkIDwgNSkpIHsNCiAgICBjaGlfc2ltIDwtIGNoaXNxLnRlc3QodGFiLCBzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSwgQiA9IDEwMDAwKQ0KICAgIA0KICAgIHRpYmJsZSgNCiAgICAgIGdyb3VwID0gdmFyX25hbWUsDQogICAgICB0ZXN0ID0gIkNoaS1zcXVhcmUgKHNpbXVsYXRlZCBwLXZhbHVlKSIsDQogICAgICBzdGF0aXN0aWMgPSB1bm5hbWUoY2hpJHN0YXRpc3RpYyksDQogICAgICBwX3ZhbHVlID0gY2hpX3NpbSRwLnZhbHVlDQogICAgKQ0KICB9IGVsc2Ugew0KICAgIHRpYmJsZSgNCiAgICAgIGdyb3VwID0gdmFyX25hbWUsDQogICAgICB0ZXN0ID0gIkNoaS1zcXVhcmUiLA0KICAgICAgc3RhdGlzdGljID0gdW5uYW1lKGNoaSRzdGF0aXN0aWMpLA0KICAgICAgcF92YWx1ZSA9IGNoaSRwLnZhbHVlDQogICAgKQ0KICB9DQp9DQoNCm92ZXJhbGxfc2lnXzIzNSA8LSBiaW5kX3Jvd3MoDQogIHJ1bl9jbHVzdGVyX3NpZ190ZXN0KGJhbmtfZ3JvdXBzXzIzNSwgInJldm9sdXRfb25seSIpLA0KICBydW5fY2x1c3Rlcl9zaWdfdGVzdChiYW5rX2dyb3Vwc18yMzUsICJubGJfcmV2b2x1dCIpLA0KICBydW5fY2x1c3Rlcl9zaWdfdGVzdChiYW5rX2dyb3Vwc18yMzUsICJvdHBfcmV2b2x1dCIpLA0KICBydW5fY2x1c3Rlcl9zaWdfdGVzdChiYW5rX2dyb3Vwc18yMzUsICJyZXZvbHV0X290aGVyIikNCikgfD4NCiAgbXV0YXRlKHBfYWRqX2JoID0gcC5hZGp1c3QocF92YWx1ZSwgbWV0aG9kID0gIkJIIikpIHw+DQogIGFycmFuZ2UocF92YWx1ZSkNCg0Kb3ZlcmFsbF9zaWdfMjM1DQpgYGANCg0KYGBge3J9DQpydW5fcGFpcl90ZXN0IDwtIGZ1bmN0aW9uKGRhdGEsIHZhcl9uYW1lLCBjbDEsIGNsMikgew0KICB0bXAgPC0gZGF0YSB8Pg0KICAgIGZpbHRlcihjbHVzdGVyICVpbiUgYyhjbDEsIGNsMikpIHw+DQogICAgbXV0YXRlKGNsdXN0ZXIgPSBkcm9wbGV2ZWxzKGNsdXN0ZXIpKQ0KICANCiAgY291bnRzIDwtIHRtcCB8Pg0KICAgIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogICAgc3VtbWFyaXNlKA0KICAgICAgdXNlcnMgPSBzdW0oLmRhdGFbW3Zhcl9uYW1lXV0sIG5hLnJtID0gVFJVRSksDQogICAgICBuID0gbigpLA0KICAgICAgLmdyb3VwcyA9ICJkcm9wIg0KICAgICkNCiAgDQogIHRlc3QgPC0gcHJvcC50ZXN0KA0KICAgIHggPSBjb3VudHMkdXNlcnMsDQogICAgbiA9IGNvdW50cyRuLA0KICAgIGNvcnJlY3QgPSBGQUxTRQ0KICApDQogIA0KICB0aWJibGUoDQogICAgZ3JvdXAgPSB2YXJfbmFtZSwNCiAgICBjbHVzdGVyXzEgPSBjbDEsDQogICAgY2x1c3Rlcl8yID0gY2wyLA0KICAgIHVzZXJzXzEgPSBjb3VudHMkdXNlcnNbMV0sDQogICAgbl8xID0gY291bnRzJG5bMV0sDQogICAgcGN0XzEgPSByb3VuZCgxMDAgKiBjb3VudHMkdXNlcnNbMV0gLyBjb3VudHMkblsxXSwgMSksDQogICAgdXNlcnNfMiA9IGNvdW50cyR1c2Vyc1syXSwNCiAgICBuXzIgPSBjb3VudHMkblsyXSwNCiAgICBwY3RfMiA9IHJvdW5kKDEwMCAqIGNvdW50cyR1c2Vyc1syXSAvIGNvdW50cyRuWzJdLCAxKSwNCiAgICBzdGF0aXN0aWMgPSB1bm5hbWUodGVzdCRzdGF0aXN0aWMpLA0KICAgIHBfdmFsdWUgPSB0ZXN0JHAudmFsdWUNCiAgKQ0KfQ0KDQpjbHVzdGVyX3BhaXJzXzIzNSA8LSBsaXN0KA0KICBjKCJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiKSwNCiAgYygiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyIpLA0KICBjKCJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIikNCikNCg0KYmFua192YXJzIDwtIGMoInJldm9sdXRfb25seSIsICJubGJfcmV2b2x1dCIsICJvdHBfcmV2b2x1dCIsICJyZXZvbHV0X290aGVyIikNCg0KcGFpcndpc2Vfc2lnXzIzNSA8LSBtYXBfZGZyKGJhbmtfdmFycywgZnVuY3Rpb24odikgew0KICBtYXBfZGZyKGNsdXN0ZXJfcGFpcnNfMjM1LCBmdW5jdGlvbihwKSB7DQogICAgcnVuX3BhaXJfdGVzdChiYW5rX2dyb3Vwc18yMzUsIHYsIHBbMV0sIHBbMl0pDQogIH0pDQp9KSB8Pg0KICBncm91cF9ieShncm91cCkgfD4NCiAgbXV0YXRlKHBfYWRqX2JoID0gcC5hZGp1c3QocF92YWx1ZSwgbWV0aG9kID0gIkJIIikpIHw+DQogIHVuZ3JvdXAoKSB8Pg0KICBhcnJhbmdlKGdyb3VwLCBwX3ZhbHVlKQ0KDQpwYWlyd2lzZV9zaWdfMjM1DQpgYGANCg0KYGBge3J9DQpwYWlyd2lzZV9zaWdfMjM1IHw+DQogIGZpbHRlcihwX2Fkal9iaCA8IDAuMDUpDQpgYGANCg0KYGBge3J9DQpiYW5rX2dyb3Vwc18yMzUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KICAgIG5fY2x1c3RlciA9IG4oKSwNCiAgICByZXZvbHV0X29ubHlfbiA9IHN1bShyZXZvbHV0X29ubHksIG5hLnJtID0gVFJVRSksDQogICAgcmV2b2x1dF9vbmx5X3BjdCA9IHJvdW5kKDEwMCAqIHJldm9sdXRfb25seV9uIC8gbl9jbHVzdGVyLCAxKSwNCiAgICBubGJfcmV2b2x1dF9uID0gc3VtKG5sYl9yZXZvbHV0LCBuYS5ybSA9IFRSVUUpLA0KICAgIG5sYl9yZXZvbHV0X3BjdCA9IHJvdW5kKDEwMCAqIG5sYl9yZXZvbHV0X24gLyBuX2NsdXN0ZXIsIDEpLA0KICAgIG90cF9yZXZvbHV0X24gPSBzdW0ob3RwX3Jldm9sdXQsIG5hLnJtID0gVFJVRSksDQogICAgb3RwX3Jldm9sdXRfcGN0ID0gcm91bmQoMTAwICogb3RwX3Jldm9sdXRfbiAvIG5fY2x1c3RlciwgMSksDQogICAgcmV2b2x1dF9vdGhlcl9uID0gc3VtKHJldm9sdXRfb3RoZXIsIG5hLnJtID0gVFJVRSksDQogICAgcmV2b2x1dF9vdGhlcl9wY3QgPSByb3VuZCgxMDAgKiByZXZvbHV0X290aGVyX24gLyBuX2NsdXN0ZXIsIDEpDQogICkNCmBgYA==