This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

plot(cars)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

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)
  )
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQpwbG90KGNhcnMpDQpgYGANCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg0KVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLg0KDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkodGliYmxlKQ0KYGBgDQoNCg0KYGBge3J9DQpyYXdfc2hlZXQgPC0gcmVhZF9leGNlbCgNCiAgIlF1ZXN0aW9ubmFpcmVfcmVzdWx0c19FTi54bHN4IiwNCiAgc2hlZXQgPSAiUG9kYXRraSIsDQogIGNvbF9uYW1lcyA9IEZBTFNFDQopDQoNCnJhd19zaGVldA0KYGBgDQoNCmBgYHtyfQ0KdmFyX25hbWVzIDwtIHJhd19zaGVldCB8Pg0KICBzbGljZSgxKSB8Pg0KICB1bmxpc3QodXNlLm5hbWVzID0gRkFMU0UpIHw+DQogIGFzLmNoYXJhY3RlcigpDQoNCnF1ZXN0aW9uX3RleHQgPC0gcmF3X3NoZWV0IHw+DQogIHNsaWNlKDIpIHw+DQogIHVubGlzdCh1c2UubmFtZXMgPSBGQUxTRSkgfD4NCiAgYXMuY2hhcmFjdGVyKCkNCg0KZGF0YV9yYXcgPC0gcmF3X3NoZWV0IHw+DQogIHNsaWNlKC0oMToyKSkNCg0KbmFtZXMoZGF0YV9yYXcpIDwtIHZhcl9uYW1lcw0KDQpkYXRhX3JhdyA8LSBkYXRhX3JhdyB8Pg0KICBtdXRhdGUocmVzcG9uZGVudF9pZCA9IHJvd19udW1iZXIoKSkgfD4NCiAgcmVsb2NhdGUocmVzcG9uZGVudF9pZCkNCg0KZ2xpbXBzZShkYXRhX3JhdykNCmBgYA0KDQpgYGB7cn0NCnF1ZXN0aW9uX2xvb2t1cCA8LSB0aWJibGUoDQogIHZhcmlhYmxlID0gdmFyX25hbWVzLA0KICBxdWVzdGlvbiA9IHF1ZXN0aW9uX3RleHQNCikNCg0KcXVlc3Rpb25fbG9va3VwDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsZWFuIDwtIGRhdGFfcmF3IHw+DQogIG11dGF0ZSgNCiAgICBhY3Jvc3MoDQogICAgICBldmVyeXRoaW5nKCksDQogICAgICB+IHJlcGxhY2UoYXMuY2hhcmFjdGVyKC4pLCBhcy5jaGFyYWN0ZXIoLikgPT0gIi0xIiwgTkEpDQogICAgKQ0KICApDQoNCmdsaW1wc2UoZGF0YV9jbGVhbikNCmBgYA0KDQpgYGB7cn0NCmlkc19yZW1vdmVkIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKGlzLm5hKFEyMikgfCBpcy5uYShRMjMpKSB8Pg0KICBwdWxsKHJlc3BvbmRlbnRfaWQpDQoNCmlkc19yZW1vdmVkDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsZWFuIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKCFpcy5uYShRMjIpLCAhaXMubmEoUTIzKSkNCg0KbnJvdyhkYXRhX3JhdykNCm5yb3coZGF0YV9jbGVhbikNCmBgYA0KDQpgYGB7cn0NCm1pc3Npbmdfc3VtbWFyeSA8LSBkYXRhX2NsZWFuIHw+DQogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+IHN1bShpcy5uYSguKSkpKSB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gIm5fbWlzc2luZyINCiAgKSB8Pg0KICBhcnJhbmdlKGRlc2Mobl9taXNzaW5nKSkNCg0KbWlzc2luZ19zdW1tYXJ5DQpgYGANCmBgYHtyfQ0KcXVlc3Rpb25fbG9va3VwIHw+IA0KICBmaWx0ZXIoZ3JlcGwoIlExM3xRMTR8UTE1IiwgdmFyaWFibGUpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiB8Pg0KICBzZWxlY3QoUTEzYTpRMTVnKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBwYXN0ZShzb3J0KHVuaXF1ZSguKSksIGNvbGxhcHNlID0gIiwgIikpKSB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gInZhbHVlcyINCiAgKQ0KYGBgDQpgYGB7cn0NCmRhdGFfY2xlYW4gPC0gZGF0YV9jbGVhbiB8Pg0KICBtdXRhdGUoDQogICAgYWNyb3NzKA0KICAgICAgUTEzYTpRMTVnLA0KICAgICAgfiBhcy5udW1lcmljKHJlcGxhY2UoLiwgLiA9PSAiOCIsIE5BKSkNCiAgICApDQogICkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2xlYW4gfD4NCiAgc2VsZWN0KFExM2E6UTE1ZykgfD4NCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gcGFzdGUoc29ydCh1bmlxdWUoLikpLCBjb2xsYXBzZSA9ICIsICIpKSkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJ2YWx1ZXMiDQogICkNCmBgYA0KYGBge3J9DQpiYW5rX21lYW5zIDwtIHRpYmJsZSgNCiAgYmFuayA9IGMoIk9UUCIsICJHb3Jlbmpza2EgQmFua2EiLCAiTkxCIiwgIlJldm9sdXQiLCAiTjI2IiwgIkludGVzYSBTYW5QYW9sbyIsICJVbmlDcmVkaXQiKSwNCiAgaW5ub3ZhdGlvbiA9IGMoDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2EsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2IsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2MsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2QsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2UsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2YsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExM2csIG5hLnJtID0gVFJVRSkNCiAgKSwNCiAgY3VzdG9tZXJfc3VwcG9ydCA9IGMoDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGEsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGIsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGMsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGQsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGUsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGYsIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsZWFuJFExNGcsIG5hLnJtID0gVFJVRSkNCiAgKSwNCiAgcmVsaWFiaWxpdHkgPSBjKA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTVhLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTViLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTVjLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTVkLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTVlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTVmLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbGVhbiRRMTVnLCBuYS5ybSA9IFRSVUUpDQogICkNCikNCg0KYmFua19tZWFucw0KYGBgDQoNCmBgYHtyfQ0KcGNhX3Jlc3VsdCA8LSBwcmNvbXAoDQogIGJhbmtfbWVhbnNbLCBjKCJpbm5vdmF0aW9uIiwgImN1c3RvbWVyX3N1cHBvcnQiLCAicmVsaWFiaWxpdHkiKV0sDQogIHNjYWxlLiA9IFRSVUUNCikNCg0KcGNhX3Jlc3VsdA0KYGBgDQoNCmBgYHtyfQ0KYmFua19jb29yZGluYXRlcyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9yZXN1bHQkeCkNCmJhbmtfY29vcmRpbmF0ZXMkYmFuayA8LSBiYW5rX21lYW5zJGJhbmsNCg0KYmFua19jb29yZGluYXRlcw0KYGBgDQoNCmBgYHtyfQ0KcGxvdCgNCiAgYmFua19jb29yZGluYXRlcyRQQzEsDQogIGJhbmtfY29vcmRpbmF0ZXMkUEMyLA0KICB4bGFiID0gIlBDMSIsDQogIHlsYWIgPSAiUEMyIiwNCiAgbWFpbiA9ICJQZXJjZXB0aW9uIE1hcCBvZiBCYW5rcyIsDQogIHBjaCA9IDE5DQopDQoNCnRleHQoDQogIGJhbmtfY29vcmRpbmF0ZXMkUEMxLA0KICBiYW5rX2Nvb3JkaW5hdGVzJFBDMiwNCiAgbGFiZWxzID0gYmFua19jb29yZGluYXRlcyRiYW5rLA0KICBwb3MgPSAzDQopDQpgYGANCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoYmFua19jb29yZGluYXRlcywgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gYmFuaykpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMykgKw0KICBnZW9tX3RleHQodmp1c3QgPSAtMC43KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUGVyY2VwdGlvbiBNYXAgb2YgQmFua3MiLA0KICAgIHggPSAiRGltZW5zaW9uIDEiLA0KICAgIHkgPSAiRGltZW5zaW9uIDIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KEZhY3RvTWluZVIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpgYGANCmBgYHtyfQ0KbWF0IDwtIGJhbmtfbWVhbnMgfD4NCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoImJhbmsiKSB8Pg0KICBhcy5tYXRyaXgoKQ0KDQpwY2FfYmFuayA8LSBGYWN0b01pbmVSOjpQQ0EobWF0LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGQUxTRSkNCg0KZmFjdG9leHRyYTo6ZnZpel9wY2FfaW5kKA0KICBwY2FfYmFuaywNCiAgcmVwZWwgPSBUUlVFDQopICsNCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiUGVyY2VwdHVhbCBtYXAgb2YgYmFua3MgKFExM+KAk1ExNSkiKQ0KYGBgDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfcGNhX2JpcGxvdCgNCiAgcGNhX2JhbmssDQogIHJlcGVsID0gVFJVRSwNCiAgY29sLnZhciA9ICJncmF5MzAiDQopICsNCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiUGVyY2VwdHVhbCBtYXAgb2YgYmFua3Mgd2l0aCBkaW1lbnNpb25zIChRMTPigJNRMTUpIikNCmBgYA0KYGBge3J9DQpmYWN0b2V4dHJhOjpmdml6X3BjYV9iaXBsb3QoDQogIHBjYV9iYW5rLA0KICByZXBlbCA9IFRSVUUsDQogIGNvbC52YXIgPSAiZ3JheTM1IiwNCiAgY29sLmluZCA9ICJzdGVlbGJsdWUiLA0KICBwb2ludHNpemUgPSAzDQopICsNCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiUGVyY2VwdHVhbCBNYXAgb2YgQmFua3MiKSArDQogIGdncGxvdDI6OnhsYWIoIk92ZXJhbGwgRGlnaXRhbCBCYW5raW5nIFBlcmZvcm1hbmNlIikgKw0KICBnZ3Bsb3QyOjp5bGFiKCJDdXN0b21lciBTdXBwb3J0IHZzIElubm92YXRpb24iKSArDQogIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKQ0KICApDQpgYGANCmBgYHtyfQ0KZmFjdG9leHRyYTo6ZnZpel9wY2FfYmlwbG90KA0KICBwY2FfYmFuaywNCiAgcmVwZWwgPSBUUlVFLA0KICBjb2wudmFyID0gImdyYXkzMCINCikgKw0KICBnZ3Bsb3QyOjpnZ3RpdGxlKCJQZXJjZXB0dWFsIG1hcCBvZiBiYW5rcyB3aXRoIGRpbWVuc2lvbnMgKFExM+KAk1ExNSkiKSArDQogIGdncGxvdDI6OnhsYWIoIkRpbTEgKDkwLjElKTogT3ZlcmFsbCBEaWdpdGFsIEJhbmtpbmcgUGVyZm9ybWFuY2UiKSArDQogIGdncGxvdDI6OnlsYWIoIkRpbTIgKDguNSUpOiBDdXN0b21lciBTdXBwb3J0IHZzIElubm92YXRpb24iKQ0KYGBgDQpgYGB7cn0NCmRhdGFfY2xlYW4gfD4NCiAgc2VsZWN0KFE2YSwgUTZiLCBRNmQsIFE2ZSwgUTZoLCBRNmksIFE4YSwgUThiLCBROGMsIFE4ZCwgUThlKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBwYXN0ZShzb3J0KHVuaXF1ZSguKSksIGNvbGxhcHNlID0gIiwgIikpKSB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gInZhbHVlcyINCiAgKQ0KYGBgDQpgYGB7cn0NCmNsdXN0ZXJfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIHNlbGVjdChRNmEsIFE2YiwgUTZkLCBRNmUsIFE2aCwgUTZpLCBROGEsIFE4YiwgUThjLCBROGQsIFE4ZSkgfD4NCiAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIGFzLm51bWVyaWMpKQ0KDQpnbGltcHNlKGNsdXN0ZXJfZGF0YSkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfZGF0YSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBzdW0oaXMubmEoLikpKSkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJuX21pc3NpbmciDQogICkNCmBgYA0KYGBge3J9DQpjbHVzdGVyX2RhdGFfY29tcGxldGUgPC0gY2x1c3Rlcl9kYXRhIHw+DQogIHRpZHlyOjpkcm9wX25hKCkNCg0KbnJvdyhjbHVzdGVyX2RhdGEpDQpucm93KGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSkNCmBgYA0KYGBge3J9DQpjbHVzdGVyX3NjYWxlZCA8LSBzY2FsZShjbHVzdGVyX2RhdGFfY29tcGxldGUpDQoNCmNsdXN0ZXJfc2NhbGVkDQpgYGANCmBgYHtyfQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KDQpmdml6X25iY2x1c3QoY2x1c3Rlcl9zY2FsZWQsIGttZWFucywgbWV0aG9kID0gIndzcyIpDQpgYGANCmBgYHtyfQ0KZnZpel9uYmNsdXN0KGNsdXN0ZXJfc2NhbGVkLCBrbWVhbnMsIG1ldGhvZCA9ICJzaWxob3VldHRlIikNCmBgYA0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJOYkNsdXN0IikNCg0KbGlicmFyeShOYkNsdXN0KQ0KDQpuYiA8LSBOYkNsdXN0KA0KICBkYXRhID0gY2x1c3Rlcl9zY2FsZWQsDQogIGRpc3RhbmNlID0gImV1Y2xpZGVhbiIsDQogIG1pbi5uYyA9IDIsDQogIG1heC5uYyA9IDYsDQogIG1ldGhvZCA9ICJrbWVhbnMiDQopDQpgYGANCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KDQprMiA8LSBrbWVhbnMoY2x1c3Rlcl9zY2FsZWQsIGNlbnRlcnMgPSAyLCBuc3RhcnQgPSAyNSkNCg0KazINCmBgYA0KYGBge3J9DQpjbHVzdGVyX3Byb2ZpbGUgPC0gY2x1c3Rlcl9kYXRhX2NvbXBsZXRlIHw+DQogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGsyJGNsdXN0ZXIpKQ0KDQpjbHVzdGVyX3Byb2ZpbGUNCmBgYA0KYGBge3J9DQpjbHVzdGVyX21lYW5zIDwtIGNsdXN0ZXJfcHJvZmlsZSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbnMNCmBgYA0KYGBge3J9DQpjbHVzdGVyX21lYW5zX2xvbmcgPC0gY2x1c3Rlcl9tZWFucyB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IC1jbHVzdGVyLA0KICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICB2YWx1ZXNfdG8gPSAibWVhbl9zY29yZSINCiAgKQ0KDQpnZ3Bsb3QoY2x1c3Rlcl9tZWFuc19sb25nLCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gbWVhbl9zY29yZSwgZ3JvdXAgPSBjbHVzdGVyLCBjb2xvciA9IGNsdXN0ZXIpKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDbHVzdGVyIFByb2ZpbGVzIiwNCiAgICB4ID0gIlZhcmlhYmxlcyIsDQogICAgeSA9ICJNZWFuIHNjb3JlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCmBgYHtyfQ0KZmFjdG9leHRyYTo6ZnZpel9jbHVzdGVyKA0KICBrMiwNCiAgZGF0YSA9IGNsdXN0ZXJfc2NhbGVkLA0KICBlbGxpcHNlLnR5cGUgPSAibm9ybSIsDQogIHJlcGVsID0gVFJVRSwNCiAgc2hvdy5jbHVzdC5jZW50ID0gVFJVRQ0KKQ0KYGBgDQpgYGB7cn0NCmZhY3RvZXh0cmE6OmZ2aXpfY2x1c3RlcigNCiAgazIsDQogIGRhdGEgPSBjbHVzdGVyX3NjYWxlZCwNCiAgZ2VvbSA9ICJwb2ludCIsDQogIGVsbGlwc2UudHlwZSA9ICJub3JtIiwNCiAgc2hvdy5jbHVzdC5jZW50ID0gVFJVRQ0KKQ0KYGBgDQpgYGB7cn0NCmNvcihjbHVzdGVyX2RhdGFfY29tcGxldGUpDQpgYGANCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJob3BraW5zIikNCmxpYnJhcnkoaG9wa2lucykNCmBgYA0KYGBge3J9DQpob3BraW5zKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSkNCmBgYA0KDQpgYGB7cn0NCmhjIDwtIGhjbHVzdChkaXN0KGNsdXN0ZXJfc2NhbGVkKSwgbWV0aG9kID0gIndhcmQuRDIiKQ0KYGBgDQpgYGB7cn0NCnBsb3QoaGMsIGxhYmVscyA9IEZBTFNFLCBoYW5nID0gLTEsIG1haW4gPSAiRGVuZHJvZ3JhbSIpDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KGFvdihRNmEgfiBjbHVzdGVyLCBkYXRhID0gY2x1c3Rlcl9wcm9maWxlKSkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoYW92KFE4YSB+IGNsdXN0ZXIsIGRhdGEgPSBjbHVzdGVyX3Byb2ZpbGUpKQ0KYGBgDQoNCmBgYHtyfQ0KYW5vdmFfcmVzdWx0cyA8LSBsYXBwbHkobmFtZXMoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlKSwgZnVuY3Rpb24odmFyKSB7DQogIG1vZGVsIDwtIGFvdihhcy5mb3JtdWxhKHBhc3RlKHZhciwgIn4gY2x1c3RlciIpKSwgZGF0YSA9IGNsdXN0ZXJfcHJvZmlsZSkNCiAgZGF0YS5mcmFtZSgNCiAgICB2YXJpYWJsZSA9IHZhciwNCiAgICBwX3ZhbHVlID0gc3VtbWFyeShtb2RlbClbWzFdXVtbIlByKD5GKSJdXVsxXQ0KICApDQp9KQ0KDQphbm92YV9yZXN1bHRzIDwtIGRvLmNhbGwocmJpbmQsIGFub3ZhX3Jlc3VsdHMpDQoNCmFub3ZhX3Jlc3VsdHMNCmBgYA0KDQoNCjMgZ3JvdXBzIG5vdyAhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISENCg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQoNCmszIDwtIGttZWFucyhjbHVzdGVyX3NjYWxlZCwgY2VudGVycyA9IDMsIG5zdGFydCA9IDI1KQ0KDQprMw0KYGBgDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KDQprNCA8LSBrbWVhbnMoY2x1c3Rlcl9zY2FsZWQsIGNlbnRlcnMgPSA0LCBuc3RhcnQgPSAyNSkNCg0KazQNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfcHJvZmlsZV80IDwtIGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSB8Pg0KICBtdXRhdGUoY2x1c3RlciA9IGZhY3RvcihrNCRjbHVzdGVyKSkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfbWVhbnNfNCA8LSBjbHVzdGVyX3Byb2ZpbGVfNCB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbnNfNA0KYGBgDQoNCmBgYHtyfQ0KZmFjdG9leHRyYTo6ZnZpel9jbHVzdGVyKA0KICBrNCwNCiAgZGF0YSA9IGNsdXN0ZXJfc2NhbGVkLA0KICBnZW9tID0gInBvaW50IiwNCiAgZWxsaXBzZS50eXBlID0gIm5vbmUiLA0KICBzaG93LmNsdXN0LmNlbnQgPSBUUlVFDQopDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3NpemVzXzQgPC0gZGF0YS5mcmFtZSh0YWJsZShrNCRjbHVzdGVyKSkNCmNsdXN0ZXJfc2l6ZXNfNCRwZXJjZW50IDwtIHJvdW5kKDEwMCAqIGNsdXN0ZXJfc2l6ZXNfNCRGcmVxIC8gc3VtKGNsdXN0ZXJfc2l6ZXNfNCRGcmVxKSwgMSkNCg0KY2x1c3Rlcl9zaXplc180DQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX21lYW5zXzRfbG9uZyA8LSBjbHVzdGVyX21lYW5zXzQgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gIm1lYW5fc2NvcmUiDQogICkNCg0KZ2dwbG90KA0KICBjbHVzdGVyX21lYW5zXzRfbG9uZywNCiAgYWVzKHggPSB2YXJpYWJsZSwgeSA9IG1lYW5fc2NvcmUsIGdyb3VwID0gY2x1c3RlciwgY29sb3IgPSBjbHVzdGVyKQ0KKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDbHVzdGVyIFByb2ZpbGVzICg0LUNsdXN0ZXIgU29sdXRpb24pIiwNCiAgICB4ID0gIlZhcmlhYmxlcyIsDQogICAgeSA9ICJNZWFuIHNjb3JlIiwNCiAgICBjb2xvciA9ICJDbHVzdGVyIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpwY2FfY2x1c3RlciA8LSBwcmNvbXAoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlLCBzY2FsZS4gPSBUUlVFKQ0KDQpzdW1tYXJ5KHBjYV9jbHVzdGVyKQ0KYGBgDQoNCmBgYHtyfQ0Kcm91bmQocGNhX2NsdXN0ZXIkcm90YXRpb25bLCAxOjNdLCAzKQ0KYGBgDQoNCmBgYHtyfQ0KcGNhX3Njb3Jlc18yIDwtIGFzLmRhdGEuZnJhbWUocGNhX2NsdXN0ZXIkeFssIDE6Ml0pDQoNCmhlYWQocGNhX3Njb3Jlc18yKQ0KYGBgDQoNCmBgYHtyfQ0KZnZpel9uYmNsdXN0KHBjYV9zY29yZXNfMiwga21lYW5zLCBtZXRob2QgPSAid3NzIikNCmBgYA0KDQpgYGB7cn0NCmZ2aXpfbmJjbHVzdChwY2Ffc2NvcmVzXzIsIGttZWFucywgbWV0aG9kID0gInNpbGhvdWV0dGUiKQ0KYGBgDQoNCmBgYHtyfQ0KbmJfcGNhMiA8LSBOYkNsdXN0KA0KICBkYXRhID0gcGNhX3Njb3Jlc18yLA0KICBkaXN0YW5jZSA9ICJldWNsaWRlYW4iLA0KICBtaW4ubmMgPSAyLA0KICBtYXgubmMgPSA2LA0KICBtZXRob2QgPSAia21lYW5zIg0KKQ0KYGBgDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KDQprNF9wY2EyIDwtIGttZWFucyhwY2Ffc2NvcmVzXzIsIGNlbnRlcnMgPSA0LCBuc3RhcnQgPSAyNSkNCg0KazRfcGNhMg0KYGBgDQoNCmBgYHtyfQ0KZmFjdG9leHRyYTo6ZnZpel9jbHVzdGVyKA0KICBrNF9wY2EyLA0KICBkYXRhID0gcGNhX3Njb3Jlc18yLA0KICBnZW9tID0gInBvaW50IiwNCiAgZWxsaXBzZS50eXBlID0gIm5vbmUiLA0KICBzaG93LmNsdXN0LmNlbnQgPSBUUlVFDQopDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3Byb2ZpbGVfcGNhNCA8LSBjbHVzdGVyX2RhdGFfY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazRfcGNhMiRjbHVzdGVyKSkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfbWVhbnNfcGNhNCA8LSBjbHVzdGVyX3Byb2ZpbGVfcGNhNCB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhNA0KYGBgDQoNCmBgYHtyfQ0KcGNhX3Bsb3RfZGF0YSA8LSBwY2Ffc2NvcmVzXzIgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNF9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiQUkgc2tlcHRpY3MiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyINCiAgICAgICkNCiAgICApDQogICkNCg0KZ2dwbG90KHBjYV9wbG90X2RhdGEsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGNsdXN0ZXIsIHNoYXBlID0gY2x1c3RlcikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMi41LCBhbHBoYSA9IDAuOCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBDQS1iYXNlZCA0LWNsdXN0ZXIgc29sdXRpb24iLA0KICAgIHggPSAiUEMxIiwNCiAgICB5ID0gIlBDMiIsDQogICAgY29sb3IgPSAiQ2x1c3RlciIsDQogICAgc2hhcGUgPSAiQ2x1c3RlciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuc19wY2E0X25hbWVkIDwtIGNsdXN0ZXJfbWVhbnNfcGNhNCB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiQUkgc2tlcHRpY3MiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyINCiAgICAgICkNCiAgICApDQogICkNCg0KY2x1c3Rlcl9tZWFuc19wY2E0X2xvbmcgPC0gY2x1c3Rlcl9tZWFuc19wY2E0X25hbWVkIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIg0KICApDQoNCmdncGxvdCgNCiAgY2x1c3Rlcl9tZWFuc19wY2E0X2xvbmcsDQogIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBtZWFuX3Njb3JlLCBncm91cCA9IGNsdXN0ZXIsIGNvbG9yID0gY2x1c3RlcikNCikgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2x1c3RlciBQcm9maWxlcyAoUENBLWJhc2VkIDQtQ2x1c3RlciBTb2x1dGlvbikiLA0KICAgIHggPSAiVmFyaWFibGVzIiwNCiAgICB5ID0gIk1lYW4gc2NvcmUiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmNvcl9tYXRyaXggPC0gY29yKGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSkNCg0Kcm91bmQoY29yX21hdHJpeCwgMykNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoY29ycnBsb3QpDQoNCmNvcnJwbG90KA0KICBjb3IoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlKSwNCiAgbWV0aG9kID0gImNvbG9yIiwNCiAgdHlwZSA9ICJ1cHBlciIsDQogIHRsLmNvbCA9ICJibGFjayIsDQogIHRsLnNydCA9IDQ1DQopDQpgYGANCg0KYGBge3J9DQpwY2FfdmFyaWFuY2UgPC0gZGF0YS5mcmFtZSgNCiAgQ29tcG9uZW50ID0gcGFzdGUwKCJQQyIsIDE6bGVuZ3RoKHBjYV9jbHVzdGVyJHNkZXYpKSwNCiAgRWlnZW52YWx1ZSA9IHBjYV9jbHVzdGVyJHNkZXZeMiwNCiAgUHJvcG9ydGlvbl9WYXJpYW5jZSA9IChwY2FfY2x1c3RlciRzZGV2XjIpIC8gc3VtKHBjYV9jbHVzdGVyJHNkZXZeMiksDQogIEN1bXVsYXRpdmVfVmFyaWFuY2UgPSBjdW1zdW0oKHBjYV9jbHVzdGVyJHNkZXZeMikgLyBzdW0ocGNhX2NsdXN0ZXIkc2Rldl4yKSkNCikNCg0KcGNhX3ZhcmlhbmNlJEVpZ2VudmFsdWUgPC0gcm91bmQocGNhX3ZhcmlhbmNlJEVpZ2VudmFsdWUsIDMpDQpwY2FfdmFyaWFuY2UkUHJvcG9ydGlvbl9WYXJpYW5jZSA8LSByb3VuZChwY2FfdmFyaWFuY2UkUHJvcG9ydGlvbl9WYXJpYW5jZSwgMykNCnBjYV92YXJpYW5jZSRDdW11bGF0aXZlX1ZhcmlhbmNlIDwtIHJvdW5kKHBjYV92YXJpYW5jZSRDdW11bGF0aXZlX1ZhcmlhbmNlLCAzKQ0KDQpwY2FfdmFyaWFuY2UNCmBgYA0KDQpgYGB7cn0NCnBjYV9sb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyJHJvdGF0aW9uWywgMTozXSkNCg0KcGNhX2xvYWRpbmdzJFZhcmlhYmxlIDwtIHJvd25hbWVzKHBjYV9sb2FkaW5ncykNCnJvd25hbWVzKHBjYV9sb2FkaW5ncykgPC0gTlVMTA0KDQpwY2FfbG9hZGluZ3MgPC0gcGNhX2xvYWRpbmdzWywgYygiVmFyaWFibGUiLCAiUEMxIiwgIlBDMiIsICJQQzMiKV0NCg0KcGNhX2xvYWRpbmdzJFBDMSA8LSByb3VuZChwY2FfbG9hZGluZ3MkUEMxLCAzKQ0KcGNhX2xvYWRpbmdzJFBDMiA8LSByb3VuZChwY2FfbG9hZGluZ3MkUEMyLCAzKQ0KcGNhX2xvYWRpbmdzJFBDMyA8LSByb3VuZChwY2FfbG9hZGluZ3MkUEMzLCAzKQ0KDQpwY2FfbG9hZGluZ3MNCmBgYA0KDQpgYGB7cn0NCmhvcGtpbnMoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlKQ0KYGBgDQoNCmBgYHtyfQ0KZGlzdGFuY2VfbWF0cml4IDwtIGRpc3QoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlLCBtZXRob2QgPSAiZXVjbGlkZWFuIikNCg0KZGlzdGFuY2VfbWF0cml4DQpgYGANCg0KYGBge3J9DQpkaXN0YW5jZV9tYXRyaXhfdGFibGUgPC0gYXMubWF0cml4KGRpc3RhbmNlX21hdHJpeCkNCg0KZGlzdGFuY2VfbWF0cml4X3RhYmxlWzE6MTAsIDE6MTBdDQpgYGANCg0KYGBge3J9DQpoYyA8LSBoY2x1c3QoZGlzdChjbHVzdGVyX2RhdGFfY29tcGxldGUpLCBtZXRob2QgPSAid2FyZC5EMiIpDQoNCnBsb3QoaGMsIGxhYmVscyA9IEZBTFNFLCBoYW5nID0gLTEsIG1haW4gPSAiRGVuZHJvZ3JhbSIpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3NpemVzX3BjYTQgPC0gZGF0YS5mcmFtZSh0YWJsZShrNF9wY2EyJGNsdXN0ZXIpKQ0KY2x1c3Rlcl9zaXplc19wY2E0JFBlcmNlbnQgPC0gcm91bmQoDQogIDEwMCAqIGNsdXN0ZXJfc2l6ZXNfcGNhNCRGcmVxIC8gc3VtKGNsdXN0ZXJfc2l6ZXNfcGNhNCRGcmVxKSwNCiAgMQ0KKQ0KDQpuYW1lcyhjbHVzdGVyX3NpemVzX3BjYTQpIDwtIGMoIkNsdXN0ZXIiLCAiU2l6ZSIsICJQZXJjZW50IikNCg0KY2x1c3Rlcl9zaXplc19wY2E0DQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3NpemVzX3BjYTQgPC0gZGF0YS5mcmFtZSh0YWJsZShrNF9wY2EyJGNsdXN0ZXIpKQ0KY2x1c3Rlcl9zaXplc19wY2E0JFBlcmNlbnQgPC0gcm91bmQoDQogIDEwMCAqIGNsdXN0ZXJfc2l6ZXNfcGNhNCRGcmVxIC8gc3VtKGNsdXN0ZXJfc2l6ZXNfcGNhNCRGcmVxKSwNCiAgMQ0KKQ0KDQpjbHVzdGVyX3NpemVzX3BjYTQkQ2x1c3Rlcl9OYW1lIDwtIGMoDQogICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgIkFJIHNrZXB0aWNzIiwNCiAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiDQopDQoNCmNsdXN0ZXJfc2l6ZXNfcGNhNCA8LSBjbHVzdGVyX3NpemVzX3BjYTRbLCBjKCJWYXIxIiwgIkNsdXN0ZXJfTmFtZSIsICJGcmVxIiwgIlBlcmNlbnQiKV0NCm5hbWVzKGNsdXN0ZXJfc2l6ZXNfcGNhNCkgPC0gYygiQ2x1c3RlciIsICJDbHVzdGVyX05hbWUiLCAiU2l6ZSIsICJQZXJjZW50IikNCg0KY2x1c3Rlcl9zaXplc19wY2E0DQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX21lYW5fdGFibGUgPC0gY2x1c3Rlcl9tZWFuc19wY2E0IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwyLDMsNCksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJBSSBza2VwdGljcyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKQ0KDQpjbHVzdGVyX21lYW5fdGFibGUNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChwY2FfcGxvdF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBjbHVzdGVyLCBzaGFwZSA9IGNsdXN0ZXIpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNSwgYWxwaGEgPSAwLjgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDdXN0b21lciBTZWdtZW50YXRpb24gQmFzZWQgb24gUENBIENsdXN0ZXJpbmciLA0KICAgIHggPSAiSW50ZXJlc3QgaW4gQUkgYmFua2luZyBmZWF0dXJlcyAoUEMxKSIsDQogICAgeSA9ICJOZWVkIGZvciBmaW5hbmNpYWwgZ3VpZGFuY2UgKFBDMikiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiLA0KICAgIHNoYXBlID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCg0KazVfcGNhMiA8LSBrbWVhbnMocGNhX3Njb3Jlc18yLCBjZW50ZXJzID0gNSwgbnN0YXJ0ID0gMjUpDQoNCms1X3BjYTINCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfcHJvZmlsZV9wY2E1IDwtIGNsdXN0ZXJfZGF0YV9jb21wbGV0ZSB8Pg0KICBtdXRhdGUoY2x1c3RlciA9IGZhY3RvcihrNV9wY2EyJGNsdXN0ZXIpKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuc19wY2E1IDwtIGNsdXN0ZXJfcHJvZmlsZV9wY2E1IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCBtZWFuKSkNCg0KY2x1c3Rlcl9tZWFuc19wY2E1DQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX21lYW5zX3BjYTVfbmFtZWQgPC0gY2x1c3Rlcl9tZWFuc19wY2E1IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkNCg0KY2x1c3Rlcl9tZWFuc19wY2E1X2xvbmcgPC0gY2x1c3Rlcl9tZWFuc19wY2E1X25hbWVkIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIg0KICApDQoNCmdncGxvdCgNCiAgY2x1c3Rlcl9tZWFuc19wY2E1X2xvbmcsDQogIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBtZWFuX3Njb3JlLCBncm91cCA9IGNsdXN0ZXIsIGNvbG9yID0gY2x1c3RlcikNCikgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2x1c3RlciBQcm9maWxlcyAoUENBLWJhc2VkIDUtQ2x1c3RlciBTb2x1dGlvbikiLA0KICAgIHggPSAiVmFyaWFibGVzIiwNCiAgICB5ID0gIk1lYW4gc2NvcmUiLA0KICAgIGNvbG9yID0gIkNsdXN0ZXIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfc2l6ZXNfcGNhNSA8LSBkYXRhLmZyYW1lKHRhYmxlKGs1X3BjYTIkY2x1c3RlcikpDQpjbHVzdGVyX3NpemVzX3BjYTUkUGVyY2VudCA8LSByb3VuZCgNCiAgMTAwICogY2x1c3Rlcl9zaXplc19wY2E1JEZyZXEgLyBzdW0oY2x1c3Rlcl9zaXplc19wY2E1JEZyZXEpLA0KICAxDQopDQoNCmNsdXN0ZXJfc2l6ZXNfcGNhNSRDbHVzdGVyX05hbWUgPC0gYygNCiAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQopDQoNCmNsdXN0ZXJfc2l6ZXNfcGNhNSA8LSBjbHVzdGVyX3NpemVzX3BjYTVbLCBjKCJWYXIxIiwgIkNsdXN0ZXJfTmFtZSIsICJGcmVxIiwgIlBlcmNlbnQiKV0NCm5hbWVzKGNsdXN0ZXJfc2l6ZXNfcGNhNSkgPC0gYygiQ2x1c3RlciIsICJDbHVzdGVyX05hbWUiLCAiU2l6ZSIsICJQZXJjZW50IikNCg0KY2x1c3Rlcl9zaXplc19wY2E1DQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3Byb2ZpbGVfcGNhNSA8LSBjbHVzdGVyX2RhdGFfY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazVfcGNhMiRjbHVzdGVyKSkNCg0KY2x1c3Rlcl9tZWFuc19wY2E1IDwtIGNsdXN0ZXJfcHJvZmlsZV9wY2E1IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCBtZWFuKSkNCg0KY2x1c3Rlcl9tZWFuX3RhYmxlX3BjYTUgPC0gY2x1c3Rlcl9tZWFuc19wY2E1IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkNCg0KY2x1c3Rlcl9tZWFuX3RhYmxlX3BjYTUNCmBgYA0KDQpgYGB7cn0NCnBjYV9wbG90X2RhdGFfNSA8LSBwY2Ffc2NvcmVzXzIgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApDQoNCmdncGxvdChwY2FfcGxvdF9kYXRhXzUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGNsdXN0ZXIsIHNoYXBlID0gY2x1c3RlcikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMi41LCBhbHBoYSA9IDAuOCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBDQS1iYXNlZCA1LUNsdXN0ZXIgU29sdXRpb24iLA0KICAgIHggPSAiUEMxIiwNCiAgICB5ID0gIlBDMiIsDQogICAgY29sb3IgPSAiQ2x1c3RlciIsDQogICAgc2hhcGUgPSAiQ2x1c3RlciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KcGNhX3Bsb3RfZGF0YV81IDwtIHBjYV9zY29yZXNfMiB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkNCg0KZ2dwbG90KHBjYV9wbG90X2RhdGFfNSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gY2x1c3Rlciwgc2hhcGUgPSBjbHVzdGVyKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyLjgsIGFscGhhID0gMC44KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ3VzdG9tZXIgU2VnbWVudGF0aW9uIChQQ0EtYmFzZWQgNS1DbHVzdGVyIFNvbHV0aW9uKSIsDQogICAgeCA9ICJJbnRlcmVzdCBpbiBBSSBCYW5raW5nIEZlYXR1cmVzIChQQzEpIiwNCiAgICB5ID0gIk5lZWQgZm9yIEZpbmFuY2lhbCBHdWlkYW5jZSAoUEMyKSIsDQogICAgY29sb3IgPSAiQ2x1c3RlciIsDQogICAgc2hhcGUgPSAiQ2x1c3RlciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9wcm9maWxlX3BjYTJfNSA8LSBwY2Ffc2NvcmVzXzIgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazVfcGNhMiRjbHVzdGVyKSkNCg0KY2x1c3Rlcl9tZWFuc19wY2EyXzUgPC0gY2x1c3Rlcl9wcm9maWxlX3BjYTJfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhMl81X25hbWVkIDwtIGNsdXN0ZXJfbWVhbnNfcGNhMl81IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkgfD4NCiAgcmVuYW1lKA0KICAgIGBJbnRlcmVzdCBpbiBBSSBCYW5raW5nIEZlYXR1cmVzYCA9IFBDMSwNCiAgICBgTmVlZCBmb3IgRmluYW5jaWFsIEd1aWRhbmNlYCA9IFBDMg0KICApDQoNCmNsdXN0ZXJfbWVhbnNfcGNhMl81X2xvbmcgPC0gY2x1c3Rlcl9tZWFuc19wY2EyXzVfbmFtZWQgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJjb21wb25lbnQiLA0KICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIg0KICApDQoNCmdncGxvdCgNCiAgY2x1c3Rlcl9tZWFuc19wY2EyXzVfbG9uZywNCiAgYWVzKHggPSBjb21wb25lbnQsIHkgPSBtZWFuX3Njb3JlLCBncm91cCA9IGNsdXN0ZXIsIGNvbG9yID0gY2x1c3RlcikNCikgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ2x1c3RlciBQcm9maWxlcyAoNS1DbHVzdGVyIFNvbHV0aW9uIEJhc2VkIG9uIDIgUENzKSIsDQogICAgeCA9ICJQcmluY2lwYWwgQ29tcG9uZW50cyIsDQogICAgeSA9ICJNZWFuIGNvbXBvbmVudCBzY29yZSIsDQogICAgY29sb3IgPSAiQ2x1c3RlciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9wcm9maWxlX3BjYTJfNCA8LSBwY2Ffc2NvcmVzXzIgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazRfcGNhMiRjbHVzdGVyKSkNCg0KY2x1c3Rlcl9tZWFuc19wY2EyXzQgPC0gY2x1c3Rlcl9wcm9maWxlX3BjYTJfNCB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpDQoNCmNsdXN0ZXJfbWVhbnNfcGNhMl80X25hbWVkIDwtIGNsdXN0ZXJfbWVhbnNfcGNhMl80IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJBSSBza2VwdGljcyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICByZW5hbWUoDQogICAgYEludGVyZXN0IGluIEFJIEJhbmtpbmcgRmVhdHVyZXNgID0gUEMxLA0KICAgIGBOZWVkIGZvciBGaW5hbmNpYWwgR3VpZGFuY2VgID0gUEMyDQogICkNCg0KY2x1c3Rlcl9tZWFuc19wY2EyXzRfbG9uZyA8LSBjbHVzdGVyX21lYW5zX3BjYTJfNF9uYW1lZCB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IC1jbHVzdGVyLA0KICAgIG5hbWVzX3RvID0gImNvbXBvbmVudCIsDQogICAgdmFsdWVzX3RvID0gIm1lYW5fc2NvcmUiDQogICkNCg0KZ2dwbG90KA0KICBjbHVzdGVyX21lYW5zX3BjYTJfNF9sb25nLA0KICBhZXMoeCA9IGNvbXBvbmVudCwgeSA9IG1lYW5fc2NvcmUsIGdyb3VwID0gY2x1c3RlciwgY29sb3IgPSBjbHVzdGVyKQ0KKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDbHVzdGVyIFByb2ZpbGVzICg0LUNsdXN0ZXIgU29sdXRpb24gQmFzZWQgb24gMiBQQ3MpIiwNCiAgICB4ID0gIlByaW5jaXBhbCBDb21wb25lbnRzIiwNCiAgICB5ID0gIk1lYW4gY29tcG9uZW50IHNjb3JlIiwNCiAgICBjb2xvciA9ICJDbHVzdGVyIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsZWFuX2NvbXBsZXRlIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2x1c3Rlcl9wcm9maWxlIDwtIGRhdGFfY2xlYW5fY29tcGxldGUgfD4NCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoazRfcGNhMiRjbHVzdGVyKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbGVhbl9jb21wbGV0ZSB8Pg0KICBtdXRhdGUoY2x1c3RlciA9IGZhY3RvcihrNV9wY2EyJGNsdXN0ZXIpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UobWVhbl9hZ2UgPSBtZWFuKGFzLm51bWVyaWMoUTIxKSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoYWdlID0gMjAyNiAtIGFzLm51bWVyaWMoUTIxKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKG1lYW5fYWdlID0gbWVhbihhZ2UsIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZShtb2JpbGVfYmFua2luZ191c2UgPSBtZWFuKGFzLm51bWVyaWMoUTIpLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UodHJ1c3QgPSBtZWFuKGFzLm51bWVyaWMoUTI0KSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpgYGB7cn0NCm5hbWVzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIsIFEyMikgfD4NCiAgc3VtbWFyaXNlKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIG11dGF0ZShwZXJjZW50ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSkpDQpgYGANCg0KYGBge3J9DQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZShRMTdfbWVhbiA9IG1lYW4oYXMubnVtZXJpYyhRMTcpLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCmBgYHtyfQ0KZ2VuZGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIsIFEyMikgfD4NCiAgc3VtbWFyaXNlKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIG11dGF0ZShwZXJjZW50ID0gcm91bmQoMTAwICogbiAvIHN1bShuKSwgMSkpIHw+DQogIHVuZ3JvdXAoKQ0KDQptYWxlX3Byb2ZpbGVfNSA8LSBnZW5kZXJfcHJvZmlsZV81IHw+DQogIGZpbHRlcihRMjIgPT0gIjEiKSB8Pg0KICBzZWxlY3QoY2x1c3RlciwgbWFsZV9wZXJjZW50ID0gcGVyY2VudCkNCg0KZmVtYWxlX3Byb2ZpbGVfNSA8LSBnZW5kZXJfcHJvZmlsZV81IHw+DQogIGZpbHRlcihRMjIgPT0gIjIiKSB8Pg0KICBzZWxlY3QoY2x1c3RlciwgZmVtYWxlX3BlcmNlbnQgPSBwZXJjZW50KQ0KDQpwcm9maWxpbmdfdGFibGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBtZWFuX2JpcnRoX3llYXIgPSBtZWFuKGFzLm51bWVyaWMoUTIxKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuX2FnZSA9IG1lYW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1vYmlsZV9iYW5raW5nX3VzZSA9IG1lYW4oYXMubnVtZXJpYyhRMiksIG5hLnJtID0gVFJVRSksDQogICAgdHJ1c3QgPSBtZWFuKGFzLm51bWVyaWMoUTI0KSwgbmEucm0gPSBUUlVFKSwNCiAgICBRMTdfbWVhbiA9IG1lYW4oYXMubnVtZXJpYyhRMTcpLCBuYS5ybSA9IFRSVUUpDQogICkgfD4NCiAgbGVmdF9qb2luKG1hbGVfcHJvZmlsZV81LCBieSA9ICJjbHVzdGVyIikgfD4NCiAgbGVmdF9qb2luKGZlbWFsZV9wcm9maWxlXzUsIGJ5ID0gImNsdXN0ZXIiKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApIHw+DQogIG11dGF0ZShhY3Jvc3MoLWNsdXN0ZXIsIH4gcm91bmQoLngsIDIpKSkNCg0KcHJvZmlsaW5nX3RhYmxlXzUNCmBgYA0KDQpgYGB7cn0NCnBjX2xvYWRpbmdzIDwtIGFzLmRhdGEuZnJhbWUocGNhX2NsdXN0ZXIkcm90YXRpb25bLCAxOjJdKQ0KDQpwY19sb2FkaW5ncyRWYXJpYWJsZSA8LSByb3duYW1lcyhwY19sb2FkaW5ncykNCnJvd25hbWVzKHBjX2xvYWRpbmdzKSA8LSBOVUxMDQoNCnBjX2xvYWRpbmdzIDwtIHBjX2xvYWRpbmdzWywgYygiVmFyaWFibGUiLCAiUEMxIiwgIlBDMiIpXQ0KDQpwY19sb2FkaW5ncyRQQzEgPC0gcm91bmQocGNfbG9hZGluZ3MkUEMxLCAzKQ0KcGNfbG9hZGluZ3MkUEMyIDwtIHJvdW5kKHBjX2xvYWRpbmdzJFBDMiwgMykNCg0KcGNfbG9hZGluZ3MNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfYmFua19jb3VudHMgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgT1RQID0gc3VtKFEyNWEgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBHb3Jlbmpza2FfQmFua2EgPSBzdW0oUTI1YiA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIE5MQiA9IHN1bShRMjVjID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgUmV2b2x1dCA9IHN1bShRMjVkID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgTjI2ID0gc3VtKFEyNWUgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBJbnRlc2EgPSBzdW0oUTI1ZiA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFVuaUNyZWRpdCA9IHN1bShRMjVnID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgUmVnaW9uYWxfQmFuayA9IHN1bShRMjVoID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgV29ya2Vyc19TYXZpbmdzID0gc3VtKFEyNWkgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBTcGFya2Fzc2UgPSBzdW0oUTI1aiA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIEFkZGlrbyA9IHN1bShRMjVrID09IDEsIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQpjbHVzdGVyX2JhbmtfY291bnRzDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZ2dwbG90MikNCg0KY2x1c3Rlcl9iYW5rX2NvdW50cyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBPVFAgPSBzdW0oUTI1YSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIEdvcmVuanNrYV9CYW5rYSA9IHN1bShRMjViID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgTkxCID0gc3VtKFEyNWMgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBSZXZvbHV0ID0gc3VtKFEyNWQgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBOMjYgPSBzdW0oUTI1ZSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIEludGVzYV9TYW5QYW9sbyA9IHN1bShRMjVmID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgVW5pQ3JlZGl0ID0gc3VtKFEyNWcgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBSZWdpb25hbF9CYW5rID0gc3VtKFEyNWggPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBXb3JrZXJzX1NhdmluZ3MgPSBzdW0oUTI1aSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFNwYXJrYXNzZSA9IHN1bShRMjVqID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgQWRkaWtvID0gc3VtKFEyNWsgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBPdGhlciA9IHN1bShRMjVsID09IDEsIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQpjbHVzdGVyX2JhbmtfY291bnRzDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX2JhbmtfbG9uZyA8LSBjbHVzdGVyX2JhbmtfY291bnRzIHw+DQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWNsdXN0ZXIsDQogICAgbmFtZXNfdG8gPSAiYmFuayIsDQogICAgdmFsdWVzX3RvID0gImNvdW50Ig0KICApDQoNCmNsdXN0ZXJfYmFua19sb25nDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoY2x1c3Rlcl9iYW5rX2xvbmcsIGFlcyh4ID0gYmFuaywgeSA9IGZhY3RvcihjbHVzdGVyKSwgZmlsbCA9IGNvdW50KSkgKw0KICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb3VudCksIHNpemUgPSA0KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQmFua3MgVXNlZCBieSBFYWNoIENsdXN0ZXIiLA0KICAgIHggPSAiQmFuayIsDQogICAgeSA9ICJDbHVzdGVyIiwNCiAgICBmaWxsID0gIkNvdW50Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKQ0KICApDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX2JhbmtfcGVyY2VudF9sb25nIDwtIGNsdXN0ZXJfYmFua19sb25nIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIG11dGF0ZShwZXJjZW50ID0gcm91bmQoMTAwICogY291bnQgLyBzdW0oY291bnQpLCAxKSkgfD4NCiAgdW5ncm91cCgpDQoNCmNsdXN0ZXJfYmFua19wZXJjZW50X2xvbmcNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChjbHVzdGVyX2JhbmtfcGVyY2VudF9sb25nLCBhZXMoeCA9IGJhbmssIHkgPSBmYWN0b3IoY2x1c3RlciksIGZpbGwgPSBwZXJjZW50KSkgKw0KICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocGVyY2VudCwgIiUiKSksIHNpemUgPSA0KSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQmFuayBVc2FnZSBieSBDbHVzdGVyICglKSIsDQogICAgeCA9ICJCYW5rIiwNCiAgICB5ID0gIkNsdXN0ZXIiLA0KICAgIGZpbGwgPSAiUGVyY2VudCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmNsdXN0ZXJfYmFua19jb3VudHNfbmFtZWQgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApIHw+DQogIGZpbHRlcihjbHVzdGVyICVpbiUgYygNCiAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgKSkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KICAgIE9UUCA9IHN1bShRMjVhID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgR29yZW5qc2thX0JhbmthID0gc3VtKFEyNWIgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBOTEIgPSBzdW0oUTI1YyA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFJldm9sdXQgPSBzdW0oUTI1ZCA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIE4yNiA9IHN1bShRMjVlID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgSW50ZXNhX1NhblBhb2xvID0gc3VtKFEyNWYgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBVbmlDcmVkaXQgPSBzdW0oUTI1ZyA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFJlZ2lvbmFsX0JhbmsgPSBzdW0oUTI1aCA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIFdvcmtlcnNfU2F2aW5ncyA9IHN1bShRMjVpID09IDEsIG5hLnJtID0gVFJVRSksDQogICAgU3Bhcmthc3NlID0gc3VtKFEyNWogPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBBZGRpa28gPSBzdW0oUTI1ayA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIE90aGVyID0gc3VtKFEyNWwgPT0gMSwgbmEucm0gPSBUUlVFKQ0KICApDQoNCmNsdXN0ZXJfYmFua19wZXJjZW50X2xvbmdfbmFtZWQgPC0gY2x1c3Rlcl9iYW5rX2NvdW50c19uYW1lZCB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IC1jbHVzdGVyLA0KICAgIG5hbWVzX3RvID0gImJhbmsiLA0KICAgIHZhbHVlc190byA9ICJjb3VudCINCiAgKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKDEwMCAqIGNvdW50IC8gc3VtKGNvdW50KSwgMSkpIHw+DQogIHVuZ3JvdXAoKQ0KDQpnZ3Bsb3QoDQogIGNsdXN0ZXJfYmFua19wZXJjZW50X2xvbmdfbmFtZWQsDQogIGFlcyh4ID0gYmFuaywgeSA9IGNsdXN0ZXIsIGZpbGwgPSBwZXJjZW50KQ0KKSArDQogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChwZXJjZW50LCAiJSIpKSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gNCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkJhbmsgVXNhZ2UgYnkgU2VsZWN0ZWQgQ2x1c3RlcnMgKCUpIiwNCiAgICB4ID0gIkJhbmsiLA0KICAgIHkgPSAiQ2x1c3RlciIsDQogICAgZmlsbCA9ICJQZXJjZW50Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKQ0KICApDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWJibGUpDQpsaWJyYXJ5KEZhY3RvTWluZVIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbGVhbl9jb21wbGV0ZSB8Pg0KICBtdXRhdGUoY2x1c3RlciA9IGZhY3RvcihrNV9wY2EyJGNsdXN0ZXIpKQ0KDQptYWtlX3BlcmNlcHRpb25fbWFwIDwtIGZ1bmN0aW9uKGRhdGEsIGNsdXN0ZXJfdmFsdWVzLCB0aXRsZV90ZXh0KSB7DQogIA0KICBzdWJzZXRfZGF0YSA8LSBkYXRhIHw+DQogICAgZmlsdGVyKGNsdXN0ZXIgJWluJSBjbHVzdGVyX3ZhbHVlcykgfD4NCiAgICBtdXRhdGUoDQogICAgICBhY3Jvc3MoUTEzYTpRMTVnLCBhcy5udW1lcmljKQ0KICAgICkNCiAgDQogIGJhbmtfbWVhbnMgPC0gdGliYmxlKA0KICAgIGJhbmsgPSBjKCJPVFAiLCAiR29yZW5qc2thIEJhbmthIiwgIk5MQiIsICJSZXZvbHV0IiwgIk4yNiIsICJJbnRlc2EgU2FuUGFvbG8iLCAiVW5pQ3JlZGl0IiksDQogICAgaW5ub3ZhdGlvbiA9IGMoDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2EsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2IsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2MsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2QsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2UsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2YsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExM2csIG5hLnJtID0gVFJVRSkNCiAgICApLA0KICAgIGN1c3RvbWVyX3N1cHBvcnQgPSBjKA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRhLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRjLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRmLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbWVhbihzdWJzZXRfZGF0YSRRMTRnLCBuYS5ybSA9IFRSVUUpDQogICAgKSwNCiAgICByZWxpYWJpbGl0eSA9IGMoDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWEsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWIsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWMsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWQsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWUsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWYsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuKHN1YnNldF9kYXRhJFExNWcsIG5hLnJtID0gVFJVRSkNCiAgICApDQogICkNCiAgDQogIG1hdCA8LSBiYW5rX21lYW5zIHw+DQogICAgY29sdW1uX3RvX3Jvd25hbWVzKCJiYW5rIikgfD4NCiAgICBhcy5tYXRyaXgoKQ0KICANCiAgcGNhX2JhbmsgPC0gRmFjdG9NaW5lUjo6UENBKG1hdCwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRkFMU0UpDQogIA0KICBmYWN0b2V4dHJhOjpmdml6X3BjYV9iaXBsb3QoDQogICAgcGNhX2JhbmssDQogICAgcmVwZWwgPSBUUlVFLA0KICAgIGNvbC52YXIgPSAiZ3JheTMwIg0KICApICsNCiAgICBnZ3Bsb3QyOjpnZ3RpdGxlKHRpdGxlX3RleHQpICsNCiAgICBnZ3Bsb3QyOjp4bGFiKCJEaW0xOiBPdmVyYWxsIERpZ2l0YWwgQmFua2luZyBQZXJmb3JtYW5jZSIpICsNCiAgICBnZ3Bsb3QyOjp5bGFiKCJEaW0yOiBDdXN0b21lciBTdXBwb3J0IHZzIElubm92YXRpb24iKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KbWFrZV9wZXJjZXB0aW9uX21hcCgNCiAgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogIGNsdXN0ZXJfdmFsdWVzID0gYygiMiIpLA0KICB0aXRsZV90ZXh0ID0gIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIC0gQ2x1c3RlciAyIg0KKQ0KYGBgDQoNCmBgYHtyfQ0KbWFrZV9wZXJjZXB0aW9uX21hcCgNCiAgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogIGNsdXN0ZXJfdmFsdWVzID0gYygiMyIpLA0KICB0aXRsZV90ZXh0ID0gIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIC0gQ2x1c3RlciAzIg0KKQ0KYGBgDQoNCmBgYHtyfQ0KbWFrZV9wZXJjZXB0aW9uX21hcCgNCiAgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogIGNsdXN0ZXJfdmFsdWVzID0gYygiNSIpLA0KICB0aXRsZV90ZXh0ID0gIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIC0gQ2x1c3RlciA1Ig0KKQ0KYGBgDQoNCmBgYHtyfQ0KbWFrZV9wZXJjZXB0aW9uX21hcCgNCiAgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsDQogIGNsdXN0ZXJfdmFsdWVzID0gYygiMiIsICIzIiwgIjUiKSwNCiAgdGl0bGVfdGV4dCA9ICJQZXJjZXB0dWFsIE1hcCBvZiBCYW5rcyAtIENsdXN0ZXJzIDIsIDMsIGFuZCA1Ig0KKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmNsdXN0ZXJfcTRfdGFibGVfbmFtZWQgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApIHw+DQogIGZpbHRlcihjbHVzdGVyICVpbiUgYygNCiAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgKSkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlciwgUTQpIHw+DQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpKSB8Pg0KICB1bmdyb3VwKCkgfD4NCiAgbXV0YXRlKA0KICAgIGluZm9fc291cmNlID0gY2FzZV93aGVuKA0KICAgICAgUTQgPT0gIjEiIH4gIldlYiBicm93c2VycyIsDQogICAgICBRNCA9PSAiMiIgfiAiRmFtaWx5IC8gZnJpZW5kcyIsDQogICAgICBRNCA9PSAiMyIgfiAiRmluYW5jaWFsIG1lZGlhIiwNCiAgICAgIFE0ID09ICI0IiB+ICJDaGF0R1BUIC8gQUkgbW9kZWxzIiwNCiAgICAgIFE0ID09ICI1IiB+ICJPdGhlciIsDQogICAgICBUUlVFIH4gYXMuY2hhcmFjdGVyKFE0KQ0KICAgICkNCiAgKSB8Pg0KICBzZWxlY3QoY2x1c3RlciwgaW5mb19zb3VyY2UsIG4sIHBlcmNlbnQpDQoNCmNsdXN0ZXJfcTRfdGFibGVfbmFtZWQNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChjbHVzdGVyX3E0X3RhYmxlX25hbWVkLCBhZXMoeCA9IGluZm9fc291cmNlLCB5ID0gY2x1c3RlciwgZmlsbCA9IHBlcmNlbnQpKSArDQogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChwZXJjZW50LCAiJSIpKSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gNCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkluZm9ybWF0aW9uIFNvdXJjZSBieSBTZWxlY3RlZCBDbHVzdGVycyAoJSkiLA0KICAgIHggPSAiSW5mb3JtYXRpb24gU291cmNlIiwNCiAgICB5ID0gIkNsdXN0ZXIiLA0KICAgIGZpbGwgPSAiUGVyY2VudCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9xNF93aWRlIDwtIGNsdXN0ZXJfcTRfdGFibGVfbmFtZWQgfD4NCiAgc2VsZWN0KGNsdXN0ZXIsIGluZm9fc291cmNlLCBwZXJjZW50KSB8Pg0KICBwaXZvdF93aWRlcigNCiAgICBuYW1lc19mcm9tID0gaW5mb19zb3VyY2UsDQogICAgdmFsdWVzX2Zyb20gPSBwZXJjZW50LA0KICAgIHZhbHVlc19maWxsID0gMA0KICApDQoNCmNsdXN0ZXJfcTRfd2lkZQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KY2x1c3Rlcl92YXJzIDwtIGMoDQogICJRNmEiLCAiUTZiIiwgIlE2ZCIsICJRNmUiLCAiUTZoIiwgIlE2aSIsDQogICJROGEiLCAiUThiIiwgIlE4YyIsICJROGQiLCAiUThlIg0KKQ0KDQpjbHVzdGVyX3ZhbGlkYXRpb24gPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcihrNV9wY2EyJGNsdXN0ZXIpLA0KICAgIGFjcm9zcyhhbGxfb2YoY2x1c3Rlcl92YXJzKSwgYXMubnVtZXJpYykNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KYW5vdmFfcmVzdWx0cyA8LSBsYXBwbHkoY2x1c3Rlcl92YXJzLCBmdW5jdGlvbih2YXIpIHsNCiAgbW9kZWwgPC0gYW92KGFzLmZvcm11bGEocGFzdGUodmFyLCAifiBjbHVzdGVyIikpLCBkYXRhID0gY2x1c3Rlcl92YWxpZGF0aW9uKQ0KICBkYXRhLmZyYW1lKA0KICAgIHZhcmlhYmxlID0gdmFyLA0KICAgIHBfdmFsdWUgPSBzdW1tYXJ5KG1vZGVsKVtbMV1dW1siUHIoPkYpIl1dWzFdDQogICkNCn0pDQoNCmFub3ZhX3Jlc3VsdHMgPC0gZG8uY2FsbChyYmluZCwgYW5vdmFfcmVzdWx0cykNCmFub3ZhX3Jlc3VsdHMkcF9hZGp1c3RlZCA8LSBwLmFkanVzdChhbm92YV9yZXN1bHRzJHBfdmFsdWUsIG1ldGhvZCA9ICJob2xtIikNCg0KYW5vdmFfcmVzdWx0cw0KYGBgDQoNCmBgYHtyfQ0KY2x1c3Rlcl9tZWFuc192YWxpZGF0aW9uIDwtIGNsdXN0ZXJfdmFsaWRhdGlvbiB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgYWNyb3NzKGFsbF9vZihjbHVzdGVyX3ZhcnMpLCB+IG1lYW4oLngsIG5hLnJtID0gVFJVRSkpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQpjbHVzdGVyX21lYW5zX3ZhbGlkYXRpb24NCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCmFnZV9kYXRhIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKQ0KICApIHw+DQogIGZpbHRlcighaXMubmEoUTIxKSkgfD4NCiAgbXV0YXRlKA0KICAgIGFnZSA9IDIwMjYgLSBhcy5udW1lcmljKFEyMSkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KYWdlX3N1bW1hcnkgPC0gYWdlX2RhdGEgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KICAgIG4gPSBuKCksDQogICAgbWVhbl9hZ2UgPSBtZWFuKGFnZSwgbmEucm0gPSBUUlVFKSwNCiAgICBzZF9hZ2UgPSBzZChhZ2UsIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuX2FnZSA9IG1lZGlhbihhZ2UsIG5hLnJtID0gVFJVRSksDQogICAgbWluX2FnZSA9IG1pbihhZ2UsIG5hLnJtID0gVFJVRSksDQogICAgbWF4X2FnZSA9IG1heChhZ2UsIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQphZ2Vfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0KYWdlX2Fub3ZhIDwtIGFvdihhZ2UgfiBjbHVzdGVyLCBkYXRhID0gYWdlX2RhdGEpDQpzdW1tYXJ5KGFnZV9hbm92YSkNCmBgYA0KDQpgYGB7cn0NClR1a2V5SFNEKGFnZV9hbm92YSkNCmBgYA0KDQpgYGB7cn0NCmFnZV9zdW1tYXJ5IDwtIGFnZV9kYXRhIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW5fYWdlID0gbWVhbihhZ2UsIG5hLnJtID0gVFJVRSksDQogICAgc2RfYWdlID0gc2QoYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbl9hZ2UgPSBtZWRpYW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbl9hZ2UgPSBtaW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1heF9hZ2UgPSBtYXgoYWdlLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KYWdlX3N1bW1hcnkNCmBgYA0KDQpgYGB7cn0NCmFnZV9zdW1tYXJ5DQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KDQpnZW5kZXJfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKFEyMikpIHw+DQogIG11dGF0ZSgNCiAgICBnZW5kZXIgPSBmYWN0b3IoDQogICAgICBRMjIsDQogICAgICBsZXZlbHMgPSBjKCIxIiwgIjIiKSwNCiAgICAgIGxhYmVscyA9IGMoIk1hbGUiLCAiRmVtYWxlIikNCiAgICApDQogICkNCmBgYA0KDQpgYGB7cn0NCmdlbmRlcl90YWJsZSA8LSB0YWJsZShnZW5kZXJfZGF0YSRjbHVzdGVyLCBnZW5kZXJfZGF0YSRnZW5kZXIpDQpnZW5kZXJfdGFibGUNCmBgYA0KDQpgYGB7cn0NCmdlbmRlcl9jaGlzcSA8LSBjaGlzcS50ZXN0KGdlbmRlcl90YWJsZSkNCmdlbmRlcl9jaGlzcQ0KYGBgDQoNCmBgYHtyfQ0KZ2VuZGVyX2NoaXNxJGV4cGVjdGVkDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KDQptb2JpbGVfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKFEyKSkgfD4NCiAgbXV0YXRlKA0KICAgIG1vYmlsZV9iYW5raW5nX3VzZSA9IGFzLm51bWVyaWMoUTIpDQogICkNCmBgYA0KDQpgYGB7cn0NCm1vYmlsZV9kYXRhIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKSwNCiAgICBtb2JpbGVfYmFua2luZ191c2UgPSBhcy5udW1lcmljKFEyKSwNCiAgICBtb2JpbGVfYmFua2luZ191c2UgPSBpZmVsc2UobW9iaWxlX2JhbmtpbmdfdXNlID09IC0yLCBOQSwgbW9iaWxlX2JhbmtpbmdfdXNlKQ0KICApIHw+DQogIGZpbHRlcighaXMubmEobW9iaWxlX2JhbmtpbmdfdXNlKSkNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKG1vYmlsZV9kYXRhJG1vYmlsZV9iYW5raW5nX3VzZSkNCm1vYmlsZV9kYXRhIHw+DQogIGNvdW50KGNsdXN0ZXIsIG1vYmlsZV9iYW5raW5nX3VzZSkNCmBgYA0KDQpgYGB7cn0NCm1vYmlsZV9zdW1tYXJ5IDwtIG1vYmlsZV9kYXRhIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW5fbW9iaWxlX3VzZSA9IG1lYW4obW9iaWxlX2JhbmtpbmdfdXNlLCBuYS5ybSA9IFRSVUUpLA0KICAgIHNkX21vYmlsZV91c2UgPSBzZChtb2JpbGVfYmFua2luZ191c2UsIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuX21vYmlsZV91c2UgPSBtZWRpYW4obW9iaWxlX2JhbmtpbmdfdXNlLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbl9tb2JpbGVfdXNlID0gbWluKG1vYmlsZV9iYW5raW5nX3VzZSwgbmEucm0gPSBUUlVFKSwNCiAgICBtYXhfbW9iaWxlX3VzZSA9IG1heChtb2JpbGVfYmFua2luZ191c2UsIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQptb2JpbGVfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0KbW9iaWxlX2t3IDwtIGtydXNrYWwudGVzdChtb2JpbGVfYmFua2luZ191c2UgfiBjbHVzdGVyLCBkYXRhID0gbW9iaWxlX2RhdGEpDQptb2JpbGVfa3cNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCmVkdWNhdGlvbl9kYXRhIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsMiwzLDQsNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIGVkdWNhdGlvbiA9IGFzLm51bWVyaWMoUTI0KQ0KICApIHw+DQogIGZpbHRlcighaXMubmEoZWR1Y2F0aW9uKSkNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKGVkdWNhdGlvbl9kYXRhJGVkdWNhdGlvbikNCmBgYA0KDQpgYGB7cn0NCmVkdWNhdGlvbl9kYXRhIHw+DQogIGNvdW50KGNsdXN0ZXIsIGVkdWNhdGlvbikNCmBgYA0KDQpgYGB7cn0NCmVkdWNhdGlvbl90YWJsZSA8LSB0YWJsZShlZHVjYXRpb25fZGF0YSRjbHVzdGVyLCBlZHVjYXRpb25fZGF0YSRlZHVjYXRpb24pDQoNCmVkdWNhdGlvbl90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KZWR1Y2F0aW9uX2NoaXNxIDwtIGNoaXNxLnRlc3QoZWR1Y2F0aW9uX3RhYmxlKQ0KDQplZHVjYXRpb25fY2hpc3ENCmBgYA0KDQpgYGB7cn0NCmVkdWNhdGlvbl9jaGlzcSRleHBlY3RlZA0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoZWR1Y2F0aW9uX2RhdGEkZWR1Y2F0aW9uKQ0KDQplZHVjYXRpb25fdGFibGUNCg0KZWR1Y2F0aW9uX2NoaXNxDQpgYGANCg0KYGBge3J9DQppbmNvbWVfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLDIsMyw0LDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKSwNCiAgICBpbmNvbWUgPSBhcy5udW1lcmljKFEyNikNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKGluY29tZSkpDQpgYGANCg0KYGBge3J9DQp0YWJsZShpbmNvbWVfZGF0YSRpbmNvbWUpDQpgYGANCg0KYGBge3J9DQppbmNvbWVfZGF0YSB8Pg0KICBjb3VudChjbHVzdGVyLCBpbmNvbWUpDQpgYGANCg0KYGBge3J9DQppbmNvbWVfdGFibGUgPC0gdGFibGUoaW5jb21lX2RhdGEkY2x1c3RlciwgaW5jb21lX2RhdGEkaW5jb21lKQ0KDQppbmNvbWVfdGFibGUNCmBgYA0KDQpgYGB7cn0NCmluY29tZV9jaGlzcSA8LSBjaGlzcS50ZXN0KGluY29tZV90YWJsZSkNCg0KaW5jb21lX2NoaXNxDQpgYGANCg0KYGBge3J9DQppbmNvbWVfY2hpc3EkZXhwZWN0ZWQNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKGluY29tZV9kYXRhJGluY29tZSkNCg0KaW5jb21lX3RhYmxlDQoNCmluY29tZV9jaGlzcQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2RhdGFfZ3JvdXBlZCA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgaW5jb21lID0gYXMubnVtZXJpYyhRMjYpLA0KICAgIGluY29tZV9ncm91cCA9IGNhc2Vfd2hlbigNCiAgICAgIGluY29tZSAlaW4lIGMoMSwgMikgfiAiTG93IGluY29tZSAoMOKAkzk5OeKCrCkiLA0KICAgICAgaW5jb21lICVpbiUgYygzLCA0KSB+ICJMb3dlci1taWRkbGUgaW5jb21lICgxMDAw4oCTMTk5OeKCrCkiLA0KICAgICAgaW5jb21lICVpbiUgYyg1LCA2KSB+ICJVcHBlci1taWRkbGUgaW5jb21lICgyMDAw4oCTMjk5OeKCrCkiLA0KICAgICAgaW5jb21lICVpbiUgYyg3LCA4KSB+ICJIaWdoIGluY29tZSAoMzAwMOKCrCspIiwNCiAgICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfDQogICAgKQ0KICApIHw+DQogIGZpbHRlcighaXMubmEoaW5jb21lX2dyb3VwKSkNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKGluY29tZV9kYXRhX2dyb3VwZWQkaW5jb21lX2dyb3VwKQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2RhdGFfZ3JvdXBlZCB8Pg0KICBjb3VudChjbHVzdGVyLCBpbmNvbWVfZ3JvdXApDQpgYGANCg0KYGBge3J9DQppbmNvbWVfZ3JvdXBfdGFibGUgPC0gdGFibGUoDQogIGluY29tZV9kYXRhX2dyb3VwZWQkY2x1c3RlciwNCiAgaW5jb21lX2RhdGFfZ3JvdXBlZCRpbmNvbWVfZ3JvdXANCikNCg0KaW5jb21lX2dyb3VwX3RhYmxlDQpgYGANCg0KYGBge3J9DQppbmNvbWVfZ3JvdXBfY2hpc3EgPC0gY2hpc3EudGVzdChpbmNvbWVfZ3JvdXBfdGFibGUpDQoNCmluY29tZV9ncm91cF9jaGlzcQ0KYGBgDQoNCmBgYHtyfQ0KaW5jb21lX2dyb3VwX2NoaXNxJGV4cGVjdGVkDQpgYGANCg0KYGBge3J9DQppbmNvbWVfcHJvZmlsZSA8LSBpbmNvbWVfZGF0YV9ncm91cGVkIHw+DQogIGNvdW50KGNsdXN0ZXIsIGluY29tZV9ncm91cCkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgbXV0YXRlKHBlcmNlbnQgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkgfD4NCiAgdW5ncm91cCgpDQoNCmluY29tZV9wcm9maWxlDQpgYGANCg0KYGBge3J9DQppbmNvbWVfcHJvZmlsZV93aWRlIDwtIGluY29tZV9wcm9maWxlIHw+DQogIHNlbGVjdChjbHVzdGVyLCBpbmNvbWVfZ3JvdXAsIHBlcmNlbnQpIHw+DQogIHRpZHlyOjpwaXZvdF93aWRlcigNCiAgICBuYW1lc19mcm9tID0gaW5jb21lX2dyb3VwLA0KICAgIHZhbHVlc19mcm9tID0gcGVyY2VudCwNCiAgICB2YWx1ZXNfZmlsbCA9IDANCiAgKQ0KDQppbmNvbWVfcHJvZmlsZV93aWRlDQpgYGANCg0KYGBge3J9DQpiYW5rX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwyLDMsNCw1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KYmFua19kYXRhIDwtIGJhbmtfZGF0YSB8Pg0KICBtdXRhdGUoDQogICAgYWNyb3NzKFEyNWE6UTI1bCwgfiBhcy5udW1lcmljKC4pKQ0KICApDQpgYGANCg0KYGBge3J9DQpyZXZvbHV0X3RhYmxlIDwtIHRhYmxlKGJhbmtfZGF0YSRjbHVzdGVyLCBiYW5rX2RhdGEkUTI1ZCkNCg0KcmV2b2x1dF90YWJsZQ0KDQpjaGlzcS50ZXN0KHJldm9sdXRfdGFibGUpDQpgYGANCg0KYGBge3J9DQpiYW5rcyA8LSBjKCJRMjVhIiwiUTI1YiIsIlEyNWMiLCJRMjVkIiwiUTI1ZSIsIlEyNWYiLCJRMjVnIiwiUTI1aCIsIlEyNWkiLCJRMjVqIiwiUTI1ayIsIlEyNWwiKQ0KDQpiYW5rX3Rlc3RzIDwtIGxhcHBseShiYW5rcywgZnVuY3Rpb24odmFyKXsNCg0KICB0YWIgPC0gdGFibGUoYmFua19kYXRhJGNsdXN0ZXIsIGJhbmtfZGF0YVtbdmFyXV0pDQogIHRlc3QgPC0gY2hpc3EudGVzdCh0YWIpDQoNCiAgZGF0YS5mcmFtZSgNCiAgICBiYW5rID0gdmFyLA0KICAgIGNoaV9zcXVhcmUgPSB0ZXN0JHN0YXRpc3RpYywNCiAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlDQogICkNCn0pDQoNCmJhbmtfdGVzdHMgPC0gZG8uY2FsbChyYmluZCwgYmFua190ZXN0cykNCg0KYmFua190ZXN0cw0KYGBgDQoNCmBgYHtyfQ0Kb3RwX3Byb2ZpbGUgPC0gYmFua19kYXRhIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBvdHBfdXNlcnMgPSBzdW0oUTI1YSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIG4gPSBuKCksDQogICAgb3RwX3BlcmNlbnQgPSByb3VuZCgxMDAgKiBvdHBfdXNlcnMgLyBuLCAxKQ0KICApDQoNCm90cF9wcm9maWxlDQpgYGANCg0KYGBge3J9DQphcmVhX2RhdGEgPC0gZGF0YV9jbGVhbiB8Pg0KICBmaWx0ZXIoDQogICAgIWlzLm5hKFE2YSksICFpcy5uYShRNmIpLCAhaXMubmEoUTZkKSwgIWlzLm5hKFE2ZSksICFpcy5uYShRNmgpLCAhaXMubmEoUTZpKSwNCiAgICAhaXMubmEoUThhKSwgIWlzLm5hKFE4YiksICFpcy5uYShROGMpLCAhaXMubmEoUThkKSwgIWlzLm5hKFE4ZSkNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwyLDMsNCw1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgYXJlYSA9IGFzLm51bWVyaWMoUTIzKQ0KICApIHw+DQogIGZpbHRlcighaXMubmEoYXJlYSkpDQpgYGANCg0KYGBge3J9DQp0YWJsZShhcmVhX2RhdGEkYXJlYSkNCmBgYA0KDQpgYGB7cn0NCmFyZWFfdGFibGUgPC0gdGFibGUoYXJlYV9kYXRhJGNsdXN0ZXIsIGFyZWFfZGF0YSRhcmVhKQ0KDQphcmVhX3RhYmxlDQpgYGANCg0KYGBge3J9DQphcmVhX2NoaXNxIDwtIGNoaXNxLnRlc3QoYXJlYV90YWJsZSkNCg0KYXJlYV9jaGlzcQ0KYGBgDQoNCmBgYHtyfQ0KYXJlYV9jaGlzcSRleHBlY3RlZA0KYGBgDQoNCmBgYHtyfQ0KYXJlYV9wcm9maWxlIDwtIGFyZWFfZGF0YSB8Pg0KICBjb3VudChjbHVzdGVyLCBhcmVhKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUocGVyY2VudCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpKQ0KDQphcmVhX3Byb2ZpbGUNCmBgYA0KDQpgYGB7cn0NCmFyZWFfcHJvZmlsZSA8LSBhcmVhX2RhdGEgfD4NCiAgY291bnQoY2x1c3RlciwgYXJlYSkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgbXV0YXRlKHBlcmNlbnQgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkgfD4NCiAgdW5ncm91cCgpDQoNCmFyZWFfcHJvZmlsZQ0KYGBgDQoNCmBgYHtyfQ0KYWlfZGF0YSA8LSBkYXRhX2NsZWFuIHw+DQogIGZpbHRlcigNCiAgICAhaXMubmEoUTZhKSwgIWlzLm5hKFE2YiksICFpcy5uYShRNmQpLCAhaXMubmEoUTZlKSwgIWlzLm5hKFE2aCksICFpcy5uYShRNmkpLA0KICAgICFpcy5uYShROGEpLCAhaXMubmEoUThiKSwgIWlzLm5hKFE4YyksICFpcy5uYShROGQpLCAhaXMubmEoUThlKQ0KICApIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgazVfcGNhMiRjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLDIsMyw0LDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAgICAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiLA0KICAgICAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICAgICApDQogICAgKSwNCiAgICBhaV91c2UgPSBhcy5udW1lcmljKFExNykNCiAgKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKGFpX3VzZSkpDQpgYGANCg0KYGBge3J9DQphaV9zdW1tYXJ5IDwtIGFpX2RhdGEgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgc3VtbWFyaXNlKA0KICAgIG4gPSBuKCksDQogICAgbWVhbl9haSA9IG1lYW4oYWlfdXNlKSwNCiAgICBzZF9haSA9IHNkKGFpX3VzZSksDQogICAgbWVkaWFuX2FpID0gbWVkaWFuKGFpX3VzZSksDQogICAgbWluX2FpID0gbWluKGFpX3VzZSksDQogICAgbWF4X2FpID0gbWF4KGFpX3VzZSkNCiAgKQ0KDQphaV9zdW1tYXJ5DQpgYGANCg0KYGBge3J9DQphaV9hbm92YSA8LSBhb3YoYWlfdXNlIH4gY2x1c3RlciwgZGF0YSA9IGFpX2RhdGEpDQoNCnN1bW1hcnkoYWlfYW5vdmEpDQpgYGANCg0KYGBge3J9DQpUdWtleUhTRChhaV9hbm92YSkNCmBgYA0KDQpgYGB7cn0NCmFpX3N1bW1hcnkNCnN1bW1hcnkoYWlfYW5vdmEpDQpgYGANCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBIWVBPVEhFU0lTIFRFU1Qg4oCTIEgxYw0KIyBRMTc6IExpa2VsaWhvb2Qgb2YgdXNpbmcgdGhlIEFJIHBlcnNvbmFsIGJhbmtpbmcgYWdlbnQNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgSDAgKE51bGwgSHlwb3RoZXNpcyk6DQojIFRoZXJlIGFyZSBubyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIHRoZSBsaWtlbGlob29kDQojIG9mIHVzaW5nIHRoZSBBSSBwZXJzb25hbCBiYW5raW5nIGFnZW50IChRMTcpIGJldHdlZW4gdGhlIGNsdXN0ZXJzLg0KDQojIEgxYyAoUmVzZWFyY2ggSHlwb3RoZXNpcyk6DQojIEZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMgYXJlIG1vcmUgbGlrZWx5IHRvIHVzZSB0aGUgQUkgcGVyc29uYWwNCiMgYmFua2luZyBhZ2VudCB0aGFuIGNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMuDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDEgTE9BRCBMSUJSQVJJRVMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDIgUFJFUEFSRSBEQVRBDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQojIGVuc3VyZSBjbHVzdGVyIHZhcmlhYmxlIGlzIGZhY3Rvcg0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyIDwtIGFzLmZhY3RvcihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIpDQoNCiMgY29udmVydCBRMTcgdG8gbnVtZXJpYyAoTGlrZXJ0IHNjYWxlKQ0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBtdXRhdGUoUTE3ID0gYXMubnVtZXJpYyhRMTcpKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAzIERFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgRk9SIEVBQ0ggQ0xVU1RFUg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2x1c3Rlcl9zdW1tYXJ5X1ExNyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG4gPSBuKCksDQogICAgbWVhbiA9IG1lYW4oUTE3LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbiA9IG1lZGlhbihRMTcsIG5hLnJtID0gVFJVRSksDQogICAgc2QgPSBzZChRMTcsIG5hLnJtID0gVFJVRSksDQogICAgbWluID0gbWluKFExNywgbmEucm0gPSBUUlVFKSwNCiAgICBtYXggPSBtYXgoUTE3LCBuYS5ybSA9IFRSVUUpDQogICkNCg0KcHJpbnQoY2x1c3Rlcl9zdW1tYXJ5X1ExNykNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNCBURVNUIERJRkZFUkVOQ0VTIEJFVFdFRU4gQ0xVU1RFUlMNCiMgS3J1c2thbOKAk1dhbGxpcyB0ZXN0IChhcHByb3ByaWF0ZSBmb3IgTGlrZXJ0IGRhdGEpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsX3Rlc3RfUTE3IDwtIGtydXNrYWwudGVzdChRMTcgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSkNCg0KcHJpbnQoa3J1c2thbF90ZXN0X1ExNykNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNSBQT1NULUhPQyBURVNUIChQQUlSV0lTRSBDT01QQVJJU09OKQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KcGFpcndpc2VfcmVzdWx0c19RMTcgPC0gcGFpcndpc2Uud2lsY294LnRlc3QoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTE3LA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIsDQogIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIg0KKQ0KDQpwcmludChwYWlyd2lzZV9yZXN1bHRzX1ExNykNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNiBWSVNVQUxJWkFUSU9ODQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBjbHVzdGVyLCB5ID0gUTE3KSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTGlrZWxpaG9vZCBvZiBVc2luZyBBSSBQZXJzb25hbCBCYW5raW5nIEFnZW50IGJ5IENsdXN0ZXIiLA0KICAgIHggPSAiQ2x1c3RlciIsDQogICAgeSA9ICJMaWtlbGlob29kIG9mIFVzZSAoUTE3KSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNGIgRUZGRUNUIFNJWkUgRk9SIEtSVVNLQUwtV0FMTElTDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KHJzdGF0aXgpDQoNCmVmZmVjdF9zaXplX1ExNyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBrcnVza2FsX2VmZnNpemUoUTE3IH4gY2x1c3RlcikNCg0KcHJpbnQoZWZmZWN0X3NpemVfUTE3KQ0KYGBgDQoNCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEFTU1VNUFRJT04gQ0hFQ0tTIOKAkyBIMWMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Kc2hhcGlyby50ZXN0KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTE3KQ0KDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBRMTcpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KcXFub3JtKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTE3KQ0KcXFsaW5lKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTE3KQ0KDQpsaWJyYXJ5KHJzdGF0aXgpDQoNCmxldmVuZV90ZXN0KFExNyB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEtSVVNLQUwtV0FMTElTIFRFU1QNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbC50ZXN0KFExNyB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81KQ0KYGBgDQoNCiMjSDFlDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEhZUE9USEVTSVMgVEVTVA0KIyBRMTJnIOKAkyBQcmVmZXJlbmNlIGZvciBodW1hbiBpbnRlcmFjdGlvbg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBIMCAoTnVsbCBIeXBvdGhlc2lzKToNCiMgVGhlcmUgYXJlIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgaW4gcHJlZmVyZW5jZQ0KIyBmb3IgaHVtYW4gaW50ZXJhY3Rpb24gKFExMmcpIGJldHdlZW4gdGhlIGNsdXN0ZXJzLg0KDQojIEgxIChSZXNlYXJjaCBIeXBvdGhlc2lzKToNCiMgQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyBzaG93IGEgaGlnaGVyIHByZWZlcmVuY2UgZm9yIGh1bWFuDQojIGludGVyYWN0aW9uIHRoYW4gQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMgYW5kDQojIGZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMuDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDEgTE9BRCBMSUJSQVJJRVMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDIgUFJFUEFSRSBEQVRBDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQojIGVuc3VyZSBjbHVzdGVyIHZhcmlhYmxlIGlzIGZhY3Rvcg0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyIDwtIGFzLmZhY3RvcihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIpDQoNCiMgY29udmVydCBMaWtlcnQgdmFyaWFibGUgdG8gbnVtZXJpYw0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBtdXRhdGUoUTEyZyA9IGFzLm51bWVyaWMoUTEyZykpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDMgREVTQ1JJUFRJVkUgU1RBVElTVElDUyBGT1IgRUFDSCBDTFVTVEVSDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjbHVzdGVyX3N1bW1hcnkgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW4gPSBtZWFuKFExMmcsIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuID0gbWVkaWFuKFExMmcsIG5hLnJtID0gVFJVRSksDQogICAgc2QgPSBzZChRMTJnLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbiA9IG1pbihRMTJnLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1heCA9IG1heChRMTJnLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KcHJpbnQoY2x1c3Rlcl9zdW1tYXJ5KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyA0IFRFU1QgRElGRkVSRU5DRVMgQkVUV0VFTiBDTFVTVEVSUw0KIyBLcnVza2Fs4oCTV2FsbGlzIHRlc3QgKGFwcHJvcHJpYXRlIGZvciBMaWtlcnQgc2NhbGUpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsX3Rlc3QgPC0ga3J1c2thbC50ZXN0KFExMmcgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSkNCg0KcHJpbnQoa3J1c2thbF90ZXN0KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyA1IFBPU1QtSE9DIFRFU1QgKFBBSVJXSVNFIENPTVBBUklTT04gQkVUV0VFTiBDTFVTVEVSUykNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCnBhaXJ3aXNlX3Jlc3VsdHMgPC0gcGFpcndpc2Uud2lsY294LnRlc3QoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTEyZywNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRjbHVzdGVyLA0KICBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSINCikNCg0KcHJpbnQocGFpcndpc2VfcmVzdWx0cykNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNiBWSVNVQUxJWkFUSU9OIE9GIERJRkZFUkVOQ0VTIEJFVFdFRU4gQ0xVU1RFUlMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmdncGxvdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCBhZXMoeCA9IGNsdXN0ZXIsIHkgPSBRMTJnKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUHJlZmVyZW5jZSBmb3IgSHVtYW4gSW50ZXJhY3Rpb24gYnkgQ2x1c3RlciIsDQogICAgeCA9ICJDbHVzdGVyIiwNCiAgICB5ID0gIlByZWZlcmVuY2UgZm9yIEh1bWFuIEludGVyYWN0aW9uIChRMTJnKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEFTU1VNUFRJT04gQ0hFQ0tTIOKAkyBIMWUNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShjYXIpDQoNCiMgTm9ybWFsaXR5IHRlc3QNCnNoYXBpcm8udGVzdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmcpDQoNCiMgSGlzdG9ncmFtDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBRMTJnKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgUVEgcGxvdA0KcXFub3JtKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTEyZykNCnFxbGluZShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmcpDQoNCiMgSG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VzDQpsZXZlbmVUZXN0KFExMmcgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBLUlVTS0FMLVdBTExJUyBURVNUDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmtydXNrYWwudGVzdChRMTJnIH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQpgYGANCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyA0YiBFRkZFQ1QgU0laRSBGT1IgS1JVU0tBTC1XQUxMSVMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkocnN0YXRpeCkNCg0KZWZmZWN0X3NpemVfUTEyZyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBrcnVza2FsX2VmZnNpemUoUTEyZyB+IGNsdXN0ZXIpDQoNCnByaW50KGVmZmVjdF9zaXplX1ExMmcpDQpgYGANCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJjb2luIikNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocnN0YXRpeCkNCmxpYnJhcnkoY29pbikNCmxpYnJhcnkocHVycnIpDQoNCmRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBhcy5mYWN0b3IoY2x1c3RlciksDQogICAgUTEyZyA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFExMmcpKQ0KICApICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGNsdXN0ZXIpLCAhaXMubmEoUTEyZykpDQoNCmNsdXN0ZXJfcGFpcnMgPC0gY29tYm4obGV2ZWxzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkY2x1c3RlciksIDIsIHNpbXBsaWZ5ID0gRkFMU0UpDQoNCnBhaXJ3aXNlX2VmZmVjdHNfUTEyZyA8LSBtYXBfZGZyKGNsdXN0ZXJfcGFpcnMsIGZ1bmN0aW9uKHgpIHsNCiAgdG1wIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogICAgZmlsdGVyKGNsdXN0ZXIgJWluJSB4KSAlPiUNCiAgICBkcm9wbGV2ZWxzKCkNCg0KICB3aWxjb3hfZWZmc2l6ZShkYXRhID0gdG1wLCBRMTJnIH4gY2x1c3RlcikgJT4lDQogICAgbXV0YXRlKGNvbXBhcmlzb24gPSBwYXN0ZSh4LCBjb2xsYXBzZSA9ICIgdnMgIikpDQp9KQ0KDQpwcmludChwYWlyd2lzZV9lZmZlY3RzX1ExMmcpDQpgYGANCg0KDQoNCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBIWVBPVEhFU0lTIFRFU1Qg4oCTIEgyZA0KIyBUaGUgaGlnaGVyIHRoZSBpbXBvcnRhbmNlIG9mIHNlY3VyaXR5LCB0aGUgaGlnaGVyIHRoZQ0KIyB3aWxsaW5nbmVzcyB0byBhZG9wdCBBSSBhZ2VudHMgaW4gcGVyc29uYWwgYmFua2luZw0KIyBWYXJpYWJsZXM6DQojIFExMmEgPSBJbXBvcnRhbmNlIG9mIHNlY3VyaXR5DQojIFExNyAgPSBXaWxsaW5nbmVzcyB0byB1c2UgQUkgYmFua2luZyBhZ2VudA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBIMCAoTnVsbCBIeXBvdGhlc2lzKToNCiMgVGhlcmUgaXMgbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGltcG9ydGFuY2Ugb2Ygc2VjdXJpdHkgKFExMmEpDQojIGFuZCB3aWxsaW5nbmVzcyB0byBhZG9wdCBBSSBiYW5raW5nIGFnZW50cyAoUTE3KS4NCg0KIyBIMSAoUmVzZWFyY2ggSHlwb3RoZXNpcyk6DQojIEhpZ2hlciBwZXJjZWl2ZWQgaW1wb3J0YW5jZSBvZiBzZWN1cml0eSBpcyBhc3NvY2lhdGVkIHdpdGggYSBoaWdoZXINCiMgd2lsbGluZ25lc3MgdG8gYWRvcHQgQUkgYmFua2luZyBhZ2VudHMuDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDEgTE9BRCBMSUJSQVJJRVMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDIgUFJFUEFSRSBEQVRBDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIG11dGF0ZSgNCiAgICBRMTJhID0gYXMubnVtZXJpYyhRMTJhKSwNCiAgICBRMTcgPSBhcy5udW1lcmljKFExNykNCiAgKQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAzIERFU0NSSVBUSVZFIFNUQVRJU1RJQ1MNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCnN1bW1hcnlfc3RhdHMgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5fc2VjdXJpdHkgPSBtZWFuKFExMmEsIG5hLnJtID0gVFJVRSksDQogICAgc2Rfc2VjdXJpdHkgPSBzZChRMTJhLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW5fQUlfYWRvcHRpb24gPSBtZWFuKFExNywgbmEucm0gPSBUUlVFKSwNCiAgICBzZF9BSV9hZG9wdGlvbiA9IHNkKFExNywgbmEucm0gPSBUUlVFKQ0KICApDQoNCnByaW50KHN1bW1hcnlfc3RhdHMpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDQgQ09SUkVMQVRJT04gVEVTVCAoU3BlYXJtYW4gZm9yIG9yZGluYWwgZGF0YSkNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmNvcnJlbGF0aW9uX3Rlc3QgPC0gY29yLnRlc3QoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTEyYSwNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTcsDQogIG1ldGhvZCA9ICJzcGVhcm1hbiIsDQogIHVzZSA9ICJjb21wbGV0ZS5vYnMiDQopDQoNCnByaW50KGNvcnJlbGF0aW9uX3Rlc3QpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDUgVklTVUFMSVpBVElPTg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gUTEyYSwgeSA9IFExNykpICsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjQpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJlbGF0aW9uc2hpcCBCZXR3ZWVuIFNlY3VyaXR5IEltcG9ydGFuY2UgYW5kIEFJIEFnZW50IEFkb3B0aW9uIiwNCiAgICB4ID0gIkltcG9ydGFuY2Ugb2YgU2VjdXJpdHkgKFExMmEpIiwNCiAgICB5ID0gIldpbGxpbmduZXNzIHRvIFVzZSBBSSBCYW5raW5nIEFnZW50IChRMTcpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEFTU1VNUFRJT04gQ0hFQ0tTIOKAkyBIMmQNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBOb3JtYWxpdHkgdGVzdHMNCnNoYXBpcm8udGVzdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmEpDQpzaGFwaXJvLnRlc3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTcpDQoNCiMgSGlzdG9ncmFtcw0KZ2dwbG90KGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGFlcyh4ID0gUTEyYSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBRMTcpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBRUSBwbG90cw0KcXFub3JtKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTEyYSkNCnFxbGluZShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExMmEpDQoNCnFxbm9ybShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNykNCnFxbGluZShkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNykNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBTUEVBUk1BTiBDT1JSRUxBVElPTg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjb3IudGVzdCgNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRMTJhLA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JFExNywNCiAgbWV0aG9kID0gInNwZWFybWFuIg0KKQ0KYGBgDQoNCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBIWVBPVEhFU0lTIFRFU1Qg4oCTIEgyZQ0KIyBBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyBwZXJjZWl2ZSBsZXNzIGZpbmFuY2lhbA0KIyBzdHJlc3MgdGhhbiBjYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIGFuZCBmZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzDQojIFZhcmlhYmxlOiBRNWINCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgZW5zdXJlIGNsdXN0ZXIgaXMgZmFjdG9yDQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIgPC0gYXMuZmFjdG9yKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkY2x1c3RlcikNCg0KIyBjb252ZXJ0IExpa2VydCB2YXJpYWJsZSB0byBudW1lcmljDQpkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIG11dGF0ZShRNWIgPSBhcy5udW1lcmljKFE1YikpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDEgREVTQ1JJUFRJVkUgU1RBVElTVElDUw0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2x1c3Rlcl9zdW1tYXJ5X1E1YiA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81ICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG4gPSBuKCksDQogICAgbWVhbiA9IG1lYW4oUTViLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbiA9IG1lZGlhbihRNWIsIG5hLnJtID0gVFJVRSksDQogICAgc2QgPSBzZChRNWIsIG5hLnJtID0gVFJVRSksDQogICAgbWluID0gbWluKFE1YiwgbmEucm0gPSBUUlVFKSwNCiAgICBtYXggPSBtYXgoUTViLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KcHJpbnQoY2x1c3Rlcl9zdW1tYXJ5X1E1YikNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgMiBLUlVTS0FMLVdBTExJUyBURVNUDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsX3Rlc3RfUTViIDwtIGtydXNrYWwudGVzdChRNWIgfiBjbHVzdGVyLCBkYXRhID0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSkNCg0KcHJpbnQoa3J1c2thbF90ZXN0X1E1YikNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgMyBQT1NULUhPQyBURVNUIChQQUlSV0lTRSBDT01QQVJJU09OKQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KcGFpcndpc2VfcmVzdWx0c19RNWIgPC0gcGFpcndpc2Uud2lsY294LnRlc3QoDQogIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkUTViLA0KICBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIsDQogIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIg0KKQ0KDQpwcmludChwYWlyd2lzZV9yZXN1bHRzX1E1YikNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNCBWSVNVQUxJWkFUSU9ODQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpnZ3Bsb3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwgYWVzKHggPSBjbHVzdGVyLCB5ID0gUTViKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUGVyY2VpdmVkIEZpbmFuY2lhbCBTdHJlc3MgYnkgQ2x1c3RlciIsDQogICAgeCA9ICJDbHVzdGVyIiwNCiAgICB5ID0gIkZpbmFuY2lhbCBTdHJlc3MgKFE1YikiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgQVNTVU1QVElPTiBDSEVDS1Mg4oCTIEgyZQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpzaGFwaXJvLnRlc3QoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRNWIpDQoNCmdncGxvdChkYXRhX2NsdXN0ZXJfcHJvZmlsZV81LCBhZXMoeCA9IFE1YikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpxcW5vcm0oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRNWIpDQpxcWxpbmUoZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSRRNWIpDQoNCmxldmVuZVRlc3QoUTViIH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgS1JVU0tBTC1XQUxMSVMgVEVTVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsLnRlc3QoUTViIH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUpDQpgYGANCmBgYHtyfQ0KbGlicmFyeShyc3RhdGl4KQ0KDQplZmZlY3Rfc2l6ZV9RNWIgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAga3J1c2thbF9lZmZzaXplKFE1YiB+IGNsdXN0ZXIpDQoNCnByaW50KGVmZmVjdF9zaXplX1E1YikNCmBgYA0KDQoNCiMjSDJmDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBDTEVBTiBEQVRBIChSRU1PVkUgSU5WQUxJRCBBTkQgTUlTU0lORyBWQUxVRVMpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmRhdGFfY2xlYW4gPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSAlPiUNCiAgbXV0YXRlKFExOSA9IGFzLm51bWVyaWMoUTE5KSkgJT4lICAgIyBlbnN1cmUgbnVtZXJpYw0KICBmaWx0ZXIoUTE5ID49IDEpICAgICAgICAgICAgICAgICAgICAjIHJlbW92ZSBpbnZhbGlkIHZhbHVlcyAoPDEpIGFuZCBOQQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIERFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgQlkgQ0xVU1RFUg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjbHVzdGVyX3N1bW1hcnlfUTE5IDwtIGRhdGFfY2xlYW4gJT4lDQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgbiA9IG4oKSwNCiAgICBtZWFuID0gbWVhbihRMTksIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuID0gbWVkaWFuKFExOSwgbmEucm0gPSBUUlVFKSwNCiAgICBzZCA9IHNkKFExOSwgbmEucm0gPSBUUlVFKSwNCiAgICBtaW4gPSBtaW4oUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1heCA9IG1heChRMTksIG5hLnJtID0gVFJVRSkNCiAgKQ0KDQpwcmludChjbHVzdGVyX3N1bW1hcnlfUTE5KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIEtSVVNLQUwtV0FMTElTIFRFU1QNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0Ka3J1c2thbF90ZXN0X1ExOSA8LSBrcnVza2FsLnRlc3QoUTE5IH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2xlYW4pDQoNCnByaW50KGtydXNrYWxfdGVzdF9RMTkpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgUEFJUldJU0UgV0lMQ09YT04gVEVTVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpwYWlyd2lzZV9yZXN1bHRzX1ExOSA8LSBwYWlyd2lzZS53aWxjb3gudGVzdCgNCiAgZGF0YV9jbGVhbiRRMTksDQogIGRhdGFfY2xlYW4kY2x1c3RlciwNCiAgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiDQopDQoNCnByaW50KHBhaXJ3aXNlX3Jlc3VsdHNfUTE5KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIFZJU1VBTElaQVRJT04NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KZ2dwbG90KGRhdGFfY2xlYW4sIGFlcyh4ID0gY2x1c3RlciwgeSA9IFExOSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIldpbGxpbmduZXNzIHRvIFBheSBmb3IgQUkgQmFua2luZyBBc3Npc3RhbnQgYnkgQ2x1c3RlciIsDQogICAgeCA9ICJDbHVzdGVyIiwNCiAgICB5ID0gIk1vbnRobHkgV2lsbGluZ25lc3MgdG8gUGF5ICjigqwpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgQVNTVU1QVElPTiBDSEVDS1Mg4oCTIEgyZg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpzaGFwaXJvLnRlc3QoZGF0YV9jbGVhbiRRMTkpDQoNCmdncGxvdChkYXRhX2NsZWFuLCBhZXMoeCA9IFExOSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpxcW5vcm0oZGF0YV9jbGVhbiRRMTkpDQpxcWxpbmUoZGF0YV9jbGVhbiRRMTkpDQoNCmxldmVuZVRlc3QoUTE5IH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2xlYW4pDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgS1JVU0tBTC1XQUxMSVMgVEVTVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQprcnVza2FsLnRlc3QoUTE5IH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2xlYW4pDQpgYGANCg0KDQoNCmBgYHtyfQ0KZGYgPC0gZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNQ0KYGBgDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBLUlVTS0FMLVdBTExJUyBURVNUDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmtydXNrYWxfdGVzdF9RMTkgPC0ga3J1c2thbC50ZXN0KFExOSB+IGNsdXN0ZXIsIGRhdGEgPSBkYXRhX2NsZWFuKQ0KcHJpbnQoa3J1c2thbF90ZXN0X1ExOSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBFRkZFQ1QgU0laRQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KHJzdGF0aXgpDQoNCmVmZmVjdF9zaXplX1ExOSA8LSBkYXRhX2NsZWFuICU+JQ0KICBrcnVza2FsX2VmZnNpemUoUTE5IH4gY2x1c3RlcikNCg0KcHJpbnQoZWZmZWN0X3NpemVfUTE5KQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHJzdGF0aXgpDQpsaWJyYXJ5KGNvaW4pDQpsaWJyYXJ5KHB1cnJyKQ0KDQpkYXRhX2NsZWFuIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgJT4lDQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gYXMuZmFjdG9yKGNsdXN0ZXIpLA0KICAgIFExOSA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFExOSkpDQogICkgJT4lDQogIGZpbHRlcighaXMubmEoY2x1c3RlciksICFpcy5uYShRMTkpLCBRMTkgPj0gMSkNCg0KY2x1c3Rlcl9wYWlycyA8LSBjb21ibihsZXZlbHMoZGF0YV9jbGVhbiRjbHVzdGVyKSwgMiwgc2ltcGxpZnkgPSBGQUxTRSkNCg0KcGFpcndpc2VfZWZmZWN0c19RMTkgPC0gbWFwX2RmcihjbHVzdGVyX3BhaXJzLCBmdW5jdGlvbih4KSB7DQogIHRtcCA8LSBkYXRhX2NsZWFuICU+JQ0KICAgIGZpbHRlcihjbHVzdGVyICVpbiUgeCkgJT4lDQogICAgZHJvcGxldmVscygpDQoNCiAgd2lsY294X2VmZnNpemUoZGF0YSA9IHRtcCwgUTE5IH4gY2x1c3RlcikgJT4lDQogICAgbXV0YXRlKGNvbXBhcmlzb24gPSBwYXN0ZSh4LCBjb2xsYXBzZSA9ICIgdnMgIikpDQp9KQ0KDQpwcmludChwYWlyd2lzZV9lZmZlY3RzX1ExOSkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmRmIDwtIGRmIHw+DQogIG11dGF0ZSgNCiAgICBhY3Jvc3MoYyhRMTBhLCBRMTBiLCBRMTBjLCBRMTBkLA0KICAgICAgICAgICAgIFExMWEsIFExMWIsIFExMWMsIFExMWQsIFExMWUsIFExMWYsDQogICAgICAgICAgICAgUTE3KSwgYXMubnVtZXJpYyksDQoNCiAgICBsb3dfcmlza19kZWxlZ2F0ZSAgPSByb3dNZWFucyhwaWNrKFExMWEsIFExMWIsIFExMWYpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGhpZ2hfcmlza19kZWxlZ2F0ZSA9IHJvd01lYW5zKHBpY2soUTExYywgUTExZCwgUTExZSksIG5hLnJtID0gVFJVRSksDQoNCiAgICBjb25maXJtX3JlcXVpcmVkICAgPSBRMTBjLA0KICAgIGF1dG9ub21vdXNfZGVjaXNpb25zID0gUTEwZCwNCg0KICAgIHRydXN0X2FpID0gcm93TWVhbnMocGljayhRMTBhLCBRMTBiLCBRMTBjLCBRMTBkKSwgbmEucm0gPSBUUlVFKSwNCiAgICBpbnRlbnRpb25fdXNlID0gUTE3DQogICkNCg0KZGYkY2x1c3RlciA8LSBmYWN0b3IoZGYkY2x1c3RlcikNCnRhYmxlKGRmJGNsdXN0ZXIpDQpgYGANCg0KDQojIE1pbiBhbmQgbWF4DQpgYGB7cn0NCmRmIHw+DQogIHN1bW1hcmlzZSgNCiAgICBoMWFfbG93X21pbiA9IG1pbihsb3dfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBoMWFfbG93X21heCA9IG1heChsb3dfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBoMWFfaGlnaF9taW4gPSBtaW4oaGlnaF9yaXNrX2RlbGVnYXRlLCBuYS5ybSA9IFRSVUUpLA0KICAgIGgxYV9oaWdoX21heCA9IG1heChoaWdoX3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQoNCiAgICBoMWJfY29uZmlybV9taW4gPSBtaW4oY29uZmlybV9yZXF1aXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICBoMWJfY29uZmlybV9tYXggPSBtYXgoY29uZmlybV9yZXF1aXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICBoMWJfYXV0b19taW4gPSBtaW4oYXV0b25vbW91c19kZWNpc2lvbnMsIG5hLnJtID0gVFJVRSksDQogICAgaDFiX2F1dG9fbWF4ID0gbWF4KGF1dG9ub21vdXNfZGVjaXNpb25zLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgaDJhX3RydXN0X21pbiA9IG1pbih0cnVzdF9haSwgbmEucm0gPSBUUlVFKSwNCiAgICBoMmFfdHJ1c3RfbWF4ID0gbWF4KHRydXN0X2FpLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgaDJjX2ludGVudGlvbl9taW4gPSBtaW4oaW50ZW50aW9uX3VzZSwgbmEucm0gPSBUUlVFKSwNCiAgICBoMmNfaW50ZW50aW9uX21heCA9IG1heChpbnRlbnRpb25fdXNlLCBuYS5ybSA9IFRSVUUpDQogICkNCmBgYA0KDQoNCiMjIEgxYQ0KYGBge3J9DQpoMWFfcmVzdWx0cyA8LSBkZiB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBkbyh7DQogICAgc3ViIDwtIC4NCiAgICB0ZXN0IDwtIHQudGVzdChzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIHBhaXJlZCA9IFRSVUUpDQoNCiAgICB0aWJibGUoDQogICAgICBuID0gbnJvdyhzdWIpLA0KICAgICAgbG93X21lYW4gPSBtZWFuKHN1YiRsb3dfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIGhpZ2hfbWVhbiA9IG1lYW4oc3ViJGhpZ2hfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIHRfdmFsdWUgPSB1bm5hbWUodGVzdCRzdGF0aXN0aWMpLA0KICAgICAgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZQ0KICAgICkNCiAgfSkNCg0KaDFhX3Jlc3VsdHMNCmBgYA0KDQpgYGB7cn0NCmRmIDwtIGRmIHw+DQogIG11dGF0ZSgNCiAgICBoMWFfZGlmZiA9IGxvd19yaXNrX2RlbGVnYXRlIC0gaGlnaF9yaXNrX2RlbGVnYXRlDQogICkNCmBgYA0KDQojIE5vcm1hbGl0eQ0KYGBge3J9DQpieShkZiRoMWFfZGlmZiwgZGYkY2x1c3Rlciwgc2hhcGlyby50ZXN0KQ0KYGBgDQoNCg0KIyBXaWxjb3hvbiBzaWduZWQtcmFuaw0KYGBge3J9DQpoMWFfd2lsY294X3Jlc3VsdHMgPC0gZGYgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgZG8oew0KICAgIHN1YiA8LSAuDQogICAgdGVzdCA8LSB3aWxjb3gudGVzdChzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIHBhaXJlZCA9IFRSVUUpDQoNCiAgICB0aWJibGUoDQogICAgICBuID0gbnJvdyhzdWIpLA0KICAgICAgbG93X21lYW4gPSBtZWFuKHN1YiRsb3dfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIGhpZ2hfbWVhbiA9IG1lYW4oc3ViJGhpZ2hfcmlza19kZWxlZ2F0ZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIHBfdmFsdWUgPSB0ZXN0JHAudmFsdWUNCiAgICApDQogIH0pDQoNCmgxYV93aWxjb3hfcmVzdWx0cw0KYGBgDQoNCmBgYHtyfQ0KaDFhX2ZpbmFsX3Jlc3VsdHMgPC0gZGYgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgZG8oew0KICAgIHN1YiA8LSAuDQogICAgDQogICAgdF9yZXMgPC0gdC50ZXN0KHN1YiRsb3dfcmlza19kZWxlZ2F0ZSwgc3ViJGhpZ2hfcmlza19kZWxlZ2F0ZSwgcGFpcmVkID0gVFJVRSkNCiAgICB3X3JlcyA8LSB3aWxjb3gudGVzdChzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIHBhaXJlZCA9IFRSVUUpDQogICAgDQogICAgZGlmZiA8LSBzdWIkbG93X3Jpc2tfZGVsZWdhdGUgLSBzdWIkaGlnaF9yaXNrX2RlbGVnYXRlDQogICAgZGlmZiA8LSBkaWZmWyFpcy5uYShkaWZmKV0NCiAgICANCiAgICBkeiA8LSBpZiAoc2QoZGlmZikgPT0gMCkgTkFfcmVhbF8gZWxzZSBtZWFuKGRpZmYpIC8gc2QoZGlmZikNCiAgICANCiAgICBkaWZmX256IDwtIGRpZmZbZGlmZiAhPSAwXQ0KICAgIGlmIChsZW5ndGgoZGlmZl9ueikgPT0gMCkgew0KICAgICAgcmJjIDwtIE5BX3JlYWxfDQogICAgfSBlbHNlIHsNCiAgICAgIHJhbmtzIDwtIHJhbmsoYWJzKGRpZmZfbnopKQ0KICAgICAgV19wb3MgPC0gc3VtKHJhbmtzW2RpZmZfbnogPiAwXSkNCiAgICAgIFdfbmVnIDwtIHN1bShyYW5rc1tkaWZmX256IDwgMF0pDQogICAgICByYmMgPC0gKFdfcG9zIC0gV19uZWcpIC8gKFdfcG9zICsgV19uZWcpDQogICAgfQ0KDQogICAgdGliYmxlKA0KICAgICAgbiA9IGxlbmd0aChkaWZmKSwNCiAgICAgIGxvd19tZWFuID0gbWVhbihzdWIkbG93X3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgICBoaWdoX21lYW4gPSBtZWFuKHN1YiRoaWdoX3Jpc2tfZGVsZWdhdGUsIG5hLnJtID0gVFJVRSksDQogICAgICBtZWFuX2RpZmYgPSBtZWFuKGRpZmYpLA0KICAgICAgdF92YWx1ZSA9IHVubmFtZSh0X3JlcyRzdGF0aXN0aWMpLA0KICAgICAgdF9wX3ZhbHVlID0gdF9yZXMkcC52YWx1ZSwNCiAgICAgIHdpbGNveF9wX3ZhbHVlID0gd19yZXMkcC52YWx1ZSwNCiAgICAgIGNvaGVuX2R6ID0gZHosDQogICAgICByYW5rX2Jpc2VyaWFsID0gcmJjDQogICAgKQ0KICB9KQ0KDQpoMWFfZmluYWxfcmVzdWx0cw0KYGBgDQoNCg0KIyMgSDFiDQpgYGB7cn0NCmgxYl9yZXN1bHRzIDwtIGRmIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIGRvKHsNCiAgICBzdWIgPC0gLg0KICAgIHRlc3QgPC0gdC50ZXN0KHN1YiRjb25maXJtX3JlcXVpcmVkLCBzdWIkYXV0b25vbW91c19kZWNpc2lvbnMsIHBhaXJlZCA9IFRSVUUpDQoNCiAgICB0aWJibGUoDQogICAgICBuID0gbnJvdyhzdWIpLA0KICAgICAgY29uZmlybV9tZWFuID0gbWVhbihzdWIkY29uZmlybV9yZXF1aXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgIGF1dG9ub21vdXNfbWVhbiA9IG1lYW4oc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgdF92YWx1ZSA9IHVubmFtZSh0ZXN0JHN0YXRpc3RpYyksDQogICAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlDQogICAgKQ0KICB9KQ0KDQpoMWJfcmVzdWx0cw0KYGBgDQoNCmBgYHtyfQ0KZGYgPC0gZGYgfD4NCiAgbXV0YXRlKA0KICAgIGgxYl9kaWZmID0gY29uZmlybV9yZXF1aXJlZCAtIGF1dG9ub21vdXNfZGVjaXNpb25zDQogICkNCmBgYA0KDQoNCiMgTm9ybWFsaXR5IGJ5IGNsdXN0ZXINCmBgYHtyfQ0KYnkoZGYkaDFiX2RpZmYsIGRmJGNsdXN0ZXIsIHNoYXBpcm8udGVzdCkNCmBgYA0KDQojIFdpbGNveG9uIHNpZ25lZC1yYW5rDQpgYGB7cn0NCmgxYl93aWxjb3hfcmVzdWx0cyA8LSBkZiB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBkbyh7DQogICAgc3ViIDwtIC4NCiAgICB0ZXN0IDwtIHdpbGNveC50ZXN0KA0KICAgICAgc3ViJGNvbmZpcm1fcmVxdWlyZWQsDQogICAgICBzdWIkYXV0b25vbW91c19kZWNpc2lvbnMsDQogICAgICBwYWlyZWQgPSBUUlVFLA0KICAgICAgZXhhY3QgPSBGQUxTRQ0KICAgICkNCg0KICAgIHRpYmJsZSgNCiAgICAgIG4gPSBucm93KHN1YiksDQogICAgICBjb25maXJtX21lYW4gPSBtZWFuKHN1YiRjb25maXJtX3JlcXVpcmVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgYXV0b25vbW91c19tZWFuID0gbWVhbihzdWIkYXV0b25vbW91c19kZWNpc2lvbnMsIG5hLnJtID0gVFJVRSksDQogICAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlDQogICAgKQ0KICB9KQ0KDQpoMWJfd2lsY294X3Jlc3VsdHMNCmBgYA0KDQpgYGB7cn0NCmgxYl9maW5hbF9yZXN1bHRzIDwtIGRmIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIGRvKHsNCiAgICBzdWIgPC0gLg0KICAgIA0KICAgIHRfcmVzIDwtIHQudGVzdChzdWIkY29uZmlybV9yZXF1aXJlZCwgc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zLCBwYWlyZWQgPSBUUlVFKQ0KICAgIHdfcmVzIDwtIHdpbGNveC50ZXN0KA0KICAgICAgc3ViJGNvbmZpcm1fcmVxdWlyZWQsDQogICAgICBzdWIkYXV0b25vbW91c19kZWNpc2lvbnMsDQogICAgICBwYWlyZWQgPSBUUlVFLA0KICAgICAgZXhhY3QgPSBGQUxTRQ0KICAgICkNCiAgICANCiAgICBkaWZmIDwtIHN1YiRjb25maXJtX3JlcXVpcmVkIC0gc3ViJGF1dG9ub21vdXNfZGVjaXNpb25zDQogICAgZGlmZiA8LSBkaWZmWyFpcy5uYShkaWZmKV0NCiAgICANCiAgICBkeiA8LSBpZiAoc2QoZGlmZikgPT0gMCkgTkFfcmVhbF8gZWxzZSBtZWFuKGRpZmYpIC8gc2QoZGlmZikNCiAgICANCiAgICBkaWZmX256IDwtIGRpZmZbZGlmZiAhPSAwXQ0KICAgIGlmIChsZW5ndGgoZGlmZl9ueikgPT0gMCkgew0KICAgICAgcmJjIDwtIE5BX3JlYWxfDQogICAgfSBlbHNlIHsNCiAgICAgIHJhbmtzIDwtIHJhbmsoYWJzKGRpZmZfbnopKQ0KICAgICAgV19wb3MgPC0gc3VtKHJhbmtzW2RpZmZfbnogPiAwXSkNCiAgICAgIFdfbmVnIDwtIHN1bShyYW5rc1tkaWZmX256IDwgMF0pDQogICAgICByYmMgPC0gKFdfcG9zIC0gV19uZWcpIC8gKFdfcG9zICsgV19uZWcpDQogICAgfQ0KDQogICAgdGliYmxlKA0KICAgICAgbiA9IGxlbmd0aChkaWZmKSwNCiAgICAgIGNvbmZpcm1fbWVhbiA9IG1lYW4oc3ViJGNvbmZpcm1fcmVxdWlyZWQsIG5hLnJtID0gVFJVRSksDQogICAgICBhdXRvbm9tb3VzX21lYW4gPSBtZWFuKHN1YiRhdXRvbm9tb3VzX2RlY2lzaW9ucywgbmEucm0gPSBUUlVFKSwNCiAgICAgIG1lYW5fZGlmZiA9IG1lYW4oZGlmZiksDQogICAgICB0X3ZhbHVlID0gdW5uYW1lKHRfcmVzJHN0YXRpc3RpYyksDQogICAgICB0X3BfdmFsdWUgPSB0X3JlcyRwLnZhbHVlLA0KICAgICAgd2lsY294X3BfdmFsdWUgPSB3X3JlcyRwLnZhbHVlLA0KICAgICAgY29oZW5fZHogPSBkeiwNCiAgICAgIHJhbmtfYmlzZXJpYWwgPSByYmMNCiAgICApDQogIH0pDQoNCmgxYl9maW5hbF9yZXN1bHRzDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCiMgbWFrZSBzdXJlIHZhcmlhYmxlcyBhcmUgaW4gdGhlIHJpZ2h0IGZvcm1hdA0KZGYkY2x1c3RlciA8LSBhcy5mYWN0b3IoZGYkY2x1c3RlcikNCmRmJHRydXN0X2FpIDwtIGFzLm51bWVyaWMoZGYkdHJ1c3RfYWkpDQoNCiMjIEgyYQ0KaDJhX21vZGVsIDwtIGFvdih0cnVzdF9haSB+IGNsdXN0ZXIsIGRhdGEgPSBkZikNCnN1bW1hcnkoaDJhX21vZGVsKQ0KDQojIFBvc3QtaG9jIG9wdGlvbiAxOiBUdWtleQ0KVHVrZXlIU0QoaDJhX21vZGVsKQ0KDQojIFBvc3QtaG9jIG9wdGlvbiAyOiBwYWlyd2lzZSB0LXRlc3RzIHdpdGggQm9uZmVycm9uaQ0KcGFpcndpc2UudC50ZXN0KA0KICB4ID0gZGYkdHJ1c3RfYWksDQogIGcgPSBkZiRjbHVzdGVyLA0KICBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSINCikNCg0KIyBEZXNjcmlwdGl2ZSBtZWFucw0KYWdncmVnYXRlKHRydXN0X2FpIH4gY2x1c3RlciwgZGF0YSA9IGRmLCBtZWFuLCBuYS5ybSA9IFRSVUUpDQpgYGANCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJlZmZlY3RzaXplIikNCmxpYnJhcnkoZWZmZWN0c2l6ZSkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZWZmZWN0c2l6ZSkNCg0KZGYkY2x1c3RlciA8LSBhcy5mYWN0b3IoZGYkY2x1c3RlcikNCmRmJHRydXN0X2FpIDwtIGFzLm51bWVyaWMoZGYkdHJ1c3RfYWkpDQoNCiMjIEgyYQ0KaDJhX21vZGVsIDwtIGFvdih0cnVzdF9haSB+IGNsdXN0ZXIsIGRhdGEgPSBkZikNCnN1bW1hcnkoaDJhX21vZGVsKQ0KDQpUdWtleUhTRChoMmFfbW9kZWwpDQoNCmFnZ3JlZ2F0ZSh0cnVzdF9haSB+IGNsdXN0ZXIsIGRhdGEgPSBkZiwgbWVhbiwgbmEucm0gPSBUUlVFKQ0KDQojIEVmZmVjdCBzaXplcw0KZXRhX3NxdWFyZWQoaDJhX21vZGVsKQ0Kb21lZ2Ffc3F1YXJlZChoMmFfbW9kZWwpDQpgYGANCmBgYHtyfQ0KaDJhX2V0YSA8LSBldGFfc3F1YXJlZChoMmFfbW9kZWwpDQpwcmludChoMmFfZXRhKQ0KDQpoMmFfb21lZ2EgPC0gb21lZ2Ffc3F1YXJlZChoMmFfbW9kZWwpDQpwcmludChoMmFfb21lZ2EpDQpgYGANCg0KDQojIyBIMmMNCmBgYHtyfQ0KaDJjX3Jlc3VsdHMgPC0gbGFwcGx5KGxldmVscyhkZiRjbHVzdGVyKSwgZnVuY3Rpb24oY2wpIHsNCiAgc3ViIDwtIGRmIHw+DQogICAgZmlsdGVyKGNsdXN0ZXIgPT0gY2wpDQoNCiAgbW9kZWwgPC0gbG0oaW50ZW50aW9uX3VzZSB+IHRydXN0X2FpLCBkYXRhID0gc3ViKQ0KICBjb2VmcyA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHMNCg0KICB0aWJibGUoDQogIGNsdXN0ZXIgPSBjbCwNCiAgYl90cnVzdCA9IGNvZWZzWyJ0cnVzdF9haSIsICJFc3RpbWF0ZSJdLA0KICBwX3ZhbHVlID0gY29lZnNbInRydXN0X2FpIiwgIlByKD58dHwpIl0sDQogIHJfc3F1YXJlZCA9IHN1bW1hcnkobW9kZWwpJHIuc3F1YXJlZA0KKQ0KfSkgfD4NCiAgYmluZF9yb3dzKCkNCg0KaDJjX3Jlc3VsdHMNCmBgYA0KDQojIE5vcm1hbGl0eSBvZiByZWdyZXNzaW9uIHJlc2lkdWFscyBieSBjbHVzdGVyDQoNCmBgYHtyfQ0KZm9yKGNsIGluIGxldmVscyhkZiRjbHVzdGVyKSkgew0KICBzdWIgPC0gZGYgfD4NCiAgICBmaWx0ZXIoY2x1c3RlciA9PSBjbCkNCg0KICBtb2RlbCA8LSBsbShpbnRlbnRpb25fdXNlIH4gdHJ1c3RfYWksIGRhdGEgPSBzdWIpDQoNCiAgY2F0KCJcbj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuIikNCiAgY2F0KCJDTFVTVEVSOiIsIGNsLCAiXG4iKQ0KICBjYXQoIj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuIikNCiAgcHJpbnQoc2hhcGlyby50ZXN0KHJlc2lkdWFscyhtb2RlbCkpKQ0KfQ0KYGBgDQoNCiMjIFNwZWFybWFuIHRlc3QNCmBgYHtyfQ0KaDJjX3NwZWFybWFuIDwtIGxhcHBseShsZXZlbHMoZGYkY2x1c3RlciksIGZ1bmN0aW9uKGNsKSB7DQogIHN1YiA8LSBkZiB8Pg0KICAgIGZpbHRlcihjbHVzdGVyID09IGNsKQ0KDQogIHRlc3QgPC0gY29yLnRlc3Qoc3ViJHRydXN0X2FpLCBzdWIkaW50ZW50aW9uX3VzZSwgbWV0aG9kID0gInNwZWFybWFuIikNCg0KICB0aWJibGUoDQogICAgY2x1c3RlciA9IGNsLA0KICAgIHJobyA9IHVubmFtZSh0ZXN0JGVzdGltYXRlKSwNCiAgICBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlDQogICkNCn0pIHw+DQogIGJpbmRfcm93cygpDQoNCmgyY19zcGVhcm1hbg0KYGBgDQoNCmBgYHtyfQ0KaDJjX3Jlc3VsdHMgPC0gbGFwcGx5KGxldmVscyhkZiRjbHVzdGVyKSwgZnVuY3Rpb24oY2wpIHsNCiAgc3ViIDwtIGRmIHw+DQogICAgZmlsdGVyKGNsdXN0ZXIgPT0gY2wpDQoNCiAgbW9kZWwgPC0gbG0oaW50ZW50aW9uX3VzZSB+IHRydXN0X2FpLCBkYXRhID0gc3ViKQ0KICBjb2VmcyA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHMNCg0KICB0aWJibGUoDQogICAgY2x1c3RlciA9IGNsLA0KICAgIGJfdHJ1c3QgPSBjb2Vmc1sidHJ1c3RfYWkiLCAiRXN0aW1hdGUiXSwNCiAgICBwX3ZhbHVlID0gY29lZnNbInRydXN0X2FpIiwgIlByKD58dHwpIl0sDQogICAgcl9zcXVhcmVkID0gc3VtbWFyeShtb2RlbCkkci5zcXVhcmVkLA0KICAgIGFkal9yX3NxdWFyZWQgPSBzdW1tYXJ5KG1vZGVsKSRhZGouci5zcXVhcmVkDQogICkNCn0pIHw+DQogIGJpbmRfcm93cygpDQoNCmgyY19yZXN1bHRzDQpgYGANCg0KDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHRpYmJsZSkNCg0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyX25hbWVkID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkNCmBgYA0KDQpgYGB7cn0NCmJhbmtfbGFiZWxzIDwtIGMoDQogIGEgPSAiT1RQIiwNCiAgYiA9ICJHb3Jlbmpza2EgQmFua2EiLA0KICBjID0gIk5MQiIsDQogIGQgPSAiUmV2b2x1dCIsDQogIGUgPSAiTjI2IiwNCiAgZiA9ICJJbnRlc2EgU2FuUGFvbG8iLA0KICBnID0gIlVuaUNyZWRpdCINCikNCg0KcnVuX2JhbmtfcGFpcndpc2VfdGVzdHMgPC0gZnVuY3Rpb24oZGF0YSwgY2x1c3Rlcl9uYW1lKSB7DQogIA0KICBzdWJzZXRfZGF0YSA8LSBkYXRhIHw+DQogICAgZmlsdGVyKGNsdXN0ZXJfbmFtZWQgPT0gY2x1c3Rlcl9uYW1lKSB8Pg0KICAgIG11dGF0ZShhY3Jvc3MoUTEzYTpRMTVnLCBhcy5udW1lcmljKSkNCiAgDQogIGNvbXBhcmVfZGltZW5zaW9uIDwtIGZ1bmN0aW9uKGRmLCB2YXJzLCBkaW1lbnNpb25fbmFtZSkgew0KICAgIA0KICAgIHBhaXJzIDwtIGNvbWJuKHZhcnMsIDIsIHNpbXBsaWZ5ID0gRkFMU0UpDQogICAgDQogICAgcmVzdWx0cyA8LSBsYXBwbHkocGFpcnMsIGZ1bmN0aW9uKHBhaXIpIHsNCiAgICAgIHYxIDwtIHBhaXJbMV0NCiAgICAgIHYyIDwtIHBhaXJbMl0NCiAgICAgIA0KICAgICAgeCA8LSBkZltbdjFdXQ0KICAgICAgeSA8LSBkZltbdjJdXQ0KICAgICAgDQogICAgICBjb21wbGV0ZV9pZHggPC0gY29tcGxldGUuY2FzZXMoeCwgeSkNCiAgICAgIHggPC0geFtjb21wbGV0ZV9pZHhdDQogICAgICB5IDwtIHlbY29tcGxldGVfaWR4XQ0KICAgICAgDQogICAgICB0ZXN0IDwtIHdpbGNveC50ZXN0KHgsIHksIHBhaXJlZCA9IFRSVUUsIGV4YWN0ID0gRkFMU0UpDQogICAgICANCiAgICAgIHRpYmJsZSgNCiAgICAgICAgY2x1c3RlciA9IGNsdXN0ZXJfbmFtZSwNCiAgICAgICAgZGltZW5zaW9uID0gZGltZW5zaW9uX25hbWUsDQogICAgICAgIGJhbmtfMSA9IGJhbmtfbGFiZWxzW3N1YnN0cih2MSwgbmNoYXIodjEpLCBuY2hhcih2MSkpXSwNCiAgICAgICAgYmFua18yID0gYmFua19sYWJlbHNbc3Vic3RyKHYyLCBuY2hhcih2MiksIG5jaGFyKHYyKSldLA0KICAgICAgICBuID0gbGVuZ3RoKHgpLA0KICAgICAgICBtZWFuX2JhbmtfMSA9IG1lYW4oeCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgbWVhbl9iYW5rXzIgPSBtZWFuKHksIG5hLnJtID0gVFJVRSksDQogICAgICAgIHBfdmFsdWUgPSB0ZXN0JHAudmFsdWUNCiAgICAgICkNCiAgICB9KQ0KICAgIA0KICAgIGJpbmRfcm93cyhyZXN1bHRzKSB8Pg0KICAgICAgbXV0YXRlKA0KICAgICAgICBwX2FkanVzdGVkID0gcC5hZGp1c3QocF92YWx1ZSwgbWV0aG9kID0gImJvbmZlcnJvbmkiKSwNCiAgICAgICAgc2lnbmlmaWNhbnQgPSBpZmVsc2UocF9hZGp1c3RlZCA8IDAuMDUsICJZZXMiLCAiTm8iKQ0KICAgICAgKSB8Pg0KICAgICAgYXJyYW5nZShwX2FkanVzdGVkKQ0KICB9DQogIA0KICBpbm5vdmF0aW9uX3Jlc3VsdHMgPC0gY29tcGFyZV9kaW1lbnNpb24oDQogICAgc3Vic2V0X2RhdGEsDQogICAgdmFycyA9IGMoIlExM2EiLCAiUTEzYiIsICJRMTNjIiwgIlExM2QiLCAiUTEzZSIsICJRMTNmIiwgIlExM2ciKSwNCiAgICBkaW1lbnNpb25fbmFtZSA9ICJJbm5vdmF0aW9uIg0KICApDQogIA0KICBzdXBwb3J0X3Jlc3VsdHMgPC0gY29tcGFyZV9kaW1lbnNpb24oDQogICAgc3Vic2V0X2RhdGEsDQogICAgdmFycyA9IGMoIlExNGEiLCAiUTE0YiIsICJRMTRjIiwgIlExNGQiLCAiUTE0ZSIsICJRMTRmIiwgIlExNGciKSwNCiAgICBkaW1lbnNpb25fbmFtZSA9ICJDdXN0b21lciBzdXBwb3J0Ig0KICApDQogIA0KICByZWxpYWJpbGl0eV9yZXN1bHRzIDwtIGNvbXBhcmVfZGltZW5zaW9uKA0KICAgIHN1YnNldF9kYXRhLA0KICAgIHZhcnMgPSBjKCJRMTVhIiwgIlExNWIiLCAiUTE1YyIsICJRMTVkIiwgIlExNWUiLCAiUTE1ZiIsICJRMTVnIiksDQogICAgZGltZW5zaW9uX25hbWUgPSAiUmVsaWFiaWxpdHkiDQogICkNCiAgDQogIGJpbmRfcm93cygNCiAgICBpbm5vdmF0aW9uX3Jlc3VsdHMsDQogICAgc3VwcG9ydF9yZXN1bHRzLA0KICAgIHJlbGlhYmlsaXR5X3Jlc3VsdHMNCiAgKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX2NsdXN0ZXJfYmFua190ZXN0cyA8LSBiaW5kX3Jvd3MoDQogIHJ1bl9iYW5rX3BhaXJ3aXNlX3Rlc3RzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiksDQogIHJ1bl9iYW5rX3BhaXJ3aXNlX3Rlc3RzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiksDQogIHJ1bl9iYW5rX3BhaXJ3aXNlX3Rlc3RzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiksDQogIHJ1bl9iYW5rX3BhaXJ3aXNlX3Rlc3RzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiksDQogIHJ1bl9iYW5rX3BhaXJ3aXNlX3Rlc3RzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyIpDQopDQoNCmFsbF9jbHVzdGVyX2JhbmtfdGVzdHMNCmBgYA0KDQpgYGB7cn0NCmFsbF9jbHVzdGVyX2JhbmtfdGVzdHNfc2lnIDwtIGFsbF9jbHVzdGVyX2JhbmtfdGVzdHMgfD4NCiAgZmlsdGVyKHBfYWRqdXN0ZWQgPCAwLjA1KQ0KDQphbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzX3NpZw0KYGBgDQoNCmBgYHtyfQ0KYWxsX2NsdXN0ZXJfYmFua190ZXN0c19zaWcgPC0gYWxsX2NsdXN0ZXJfYmFua190ZXN0c19zaWcgfD4NCiAgYXJyYW5nZShjbHVzdGVyLCBkaW1lbnNpb24sIHBfYWRqdXN0ZWQpDQoNCmFsbF9jbHVzdGVyX2JhbmtfdGVzdHNfc2lnDQpgYGANCg0KYGBge3J9DQphbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzX3NpZyB8Pg0KICBjb3VudChjbHVzdGVyLCBkaW1lbnNpb24pDQpgYGANCg0KYGBge3J9DQp3cml0ZS5jc3YoDQogIGFsbF9jbHVzdGVyX2JhbmtfdGVzdHMsDQogICJhbGxfY2x1c3Rlcl9iYW5rX3BhaXJ3aXNlX3Rlc3RzLmNzdiIsDQogIHJvdy5uYW1lcyA9IEZBTFNFDQopDQoNCndyaXRlLmNzdigNCiAgYWxsX2NsdXN0ZXJfYmFua190ZXN0c19zaWcsDQogICJzaWduaWZpY2FudF9jbHVzdGVyX2JhbmtfcGFpcndpc2VfdGVzdHMuY3N2IiwNCiAgcm93Lm5hbWVzID0gRkFMU0UNCikNCmBgYA0KDQpgYGB7cn0NCiMgUmVjcmVhdGUgcmVhZGFibGUgb3V0cHV0IHRhYmxlcyBmcm9tIGFsbF9jbHVzdGVyX2JhbmtfdGVzdHMNCg0KaW50ZXJwcmV0YWJsZV9yZXN1bHRzIDwtIGFsbF9jbHVzdGVyX2JhbmtfdGVzdHMgfD4NCiAgbXV0YXRlKA0KICAgIG1lYW5fYmFua18xID0gcm91bmQobWVhbl9iYW5rXzEsIDIpLA0KICAgIG1lYW5fYmFua18yID0gcm91bmQobWVhbl9iYW5rXzIsIDIpLA0KICAgIG1lYW5fZGlmZmVyZW5jZSA9IHJvdW5kKG1lYW5fYmFua18xIC0gbWVhbl9iYW5rXzIsIDIpLA0KICAgIGhpZ2hlcl9yYXRlZF9iYW5rID0gY2FzZV93aGVuKA0KICAgICAgbWVhbl9iYW5rXzEgPiBtZWFuX2JhbmtfMiB+IGJhbmtfMSwNCiAgICAgIG1lYW5fYmFua18yID4gbWVhbl9iYW5rXzEgfiBiYW5rXzIsDQogICAgICBUUlVFIH4gIkVxdWFsIg0KICAgICksDQogICAgaW50ZXJwcmV0YXRpb24gPSBjYXNlX3doZW4oDQogICAgICBwX2FkanVzdGVkIDwgMC4wNSAmIG1lYW5fYmFua18xID4gbWVhbl9iYW5rXzIgfg0KICAgICAgICBwYXN0ZTAoYmFua18xLCAiIGlzIHJhdGVkIHNpZ25pZmljYW50bHkgaGlnaGVyIHRoYW4gIiwgYmFua18yKSwNCiAgICAgIHBfYWRqdXN0ZWQgPCAwLjA1ICYgbWVhbl9iYW5rXzIgPiBtZWFuX2JhbmtfMSB+DQogICAgICAgIHBhc3RlMChiYW5rXzIsICIgaXMgcmF0ZWQgc2lnbmlmaWNhbnRseSBoaWdoZXIgdGhhbiAiLCBiYW5rXzEpLA0KICAgICAgVFJVRSB+ICJObyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIg0KICAgICksDQogICAgcF92YWx1ZSA9IHJvdW5kKHBfdmFsdWUsIDQpLA0KICAgIHBfYWRqdXN0ZWQgPSByb3VuZChwX2FkanVzdGVkLCA0KQ0KICApIHw+DQogIGFycmFuZ2UoY2x1c3RlciwgZGltZW5zaW9uLCBwX2FkanVzdGVkKQ0KDQpzaWduaWZpY2FudF9yZXN1bHRzX2NsZWFuIDwtIGludGVycHJldGFibGVfcmVzdWx0cyB8Pg0KICBmaWx0ZXIocF9hZGp1c3RlZCA8IDAuMDUpIHw+DQogIHNlbGVjdCgNCiAgICBjbHVzdGVyLA0KICAgIGRpbWVuc2lvbiwNCiAgICBiYW5rXzEsDQogICAgYmFua18yLA0KICAgIG1lYW5fYmFua18xLA0KICAgIG1lYW5fYmFua18yLA0KICAgIG1lYW5fZGlmZmVyZW5jZSwNCiAgICBoaWdoZXJfcmF0ZWRfYmFuaywNCiAgICBwX3ZhbHVlLA0KICAgIHBfYWRqdXN0ZWQsDQogICAgaW50ZXJwcmV0YXRpb24NCiAgKQ0KDQpyZXBvcnRfdGFibGUgPC0gc2lnbmlmaWNhbnRfcmVzdWx0c19jbGVhbiB8Pg0KICB0cmFuc211dGUoDQogICAgQ2x1c3RlciA9IGNsdXN0ZXIsDQogICAgRGltZW5zaW9uID0gZGltZW5zaW9uLA0KICAgIENvbXBhcmlzb24gPSBwYXN0ZShiYW5rXzEsICJ2cyIsIGJhbmtfMiksDQogICAgYE1lYW4gYmFuayAxYCA9IG1lYW5fYmFua18xLA0KICAgIGBNZWFuIGJhbmsgMmAgPSBtZWFuX2JhbmtfMiwNCiAgICBgTWVhbiBkaWZmZXJlbmNlYCA9IG1lYW5fZGlmZmVyZW5jZSwNCiAgICBgSGlnaGVyLXJhdGVkIGJhbmtgID0gaGlnaGVyX3JhdGVkX2JhbmssDQogICAgYFJhdyBwLXZhbHVlYCA9IHBfdmFsdWUsDQogICAgYEFkanVzdGVkIHAtdmFsdWVgID0gcF9hZGp1c3RlZCwNCiAgICBJbnRlcnByZXRhdGlvbiA9IGludGVycHJldGF0aW9uDQogICkNCg0KIyBTaG93IG91dHB1dHMNCmludGVycHJldGFibGVfcmVzdWx0cw0Kc2lnbmlmaWNhbnRfcmVzdWx0c19jbGVhbg0KcmVwb3J0X3RhYmxlDQpgYGANCg0KYGBge3J9DQphbGxfY2x1c3Rlcl9iYW5rX3Rlc3RzIHw+DQogIG11dGF0ZSgNCiAgICBtZWFuX2JhbmtfMSA9IHJvdW5kKG1lYW5fYmFua18xLCAyKSwNCiAgICBtZWFuX2JhbmtfMiA9IHJvdW5kKG1lYW5fYmFua18yLCAyKSwNCiAgICBwX2FkanVzdGVkID0gcm91bmQocF9hZGp1c3RlZCwgNCksDQogICAgcmVzdWx0ID0gY2FzZV93aGVuKA0KICAgICAgcF9hZGp1c3RlZCA8IDAuMDUgJiBtZWFuX2JhbmtfMSA+IG1lYW5fYmFua18yIH4gcGFzdGUoYmFua18xLCAiPiIsIGJhbmtfMiksDQogICAgICBwX2FkanVzdGVkIDwgMC4wNSAmIG1lYW5fYmFua18yID4gbWVhbl9iYW5rXzEgfiBwYXN0ZShiYW5rXzIsICI+IiwgYmFua18xKSwNCiAgICAgIFRSVUUgfiAiTm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSINCiAgICApDQogICkgfD4NCiAgZmlsdGVyKHBfYWRqdXN0ZWQgPCAwLjA1KSB8Pg0KICBzZWxlY3QoY2x1c3RlciwgZGltZW5zaW9uLCBiYW5rXzEsIGJhbmtfMiwgbWVhbl9iYW5rXzEsIG1lYW5fYmFua18yLCBwX2FkanVzdGVkLCByZXN1bHQpIHw+DQogIGFycmFuZ2UoY2x1c3RlciwgZGltZW5zaW9uLCBwX2FkanVzdGVkKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KcTE5X2NsdXN0ZXJfc3VtbWFyeSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIFExOSA9IGFzLm51bWVyaWMoUTE5KQ0KICApIHw+DQogIGZpbHRlcighaXMubmEoUTE5KSwgUTE5ID49IDEpIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBuID0gbigpLA0KICAgIG1lYW5fcTE5ID0gbWVhbihRMTksIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuX3ExOSA9IG1lZGlhbihRMTksIG5hLnJtID0gVFJVRSksDQogICAgc2RfcTE5ID0gc2QoUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1pbl9xMTkgPSBtaW4oUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1heF9xMTkgPSBtYXgoUTE5LCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgbWVhbl9xMTkgPSByb3VuZChtZWFuX3ExOSwgMiksDQogICAgbWVkaWFuX3ExOSA9IHJvdW5kKG1lZGlhbl9xMTksIDIpLA0KICAgIHNkX3ExOSA9IHJvdW5kKHNkX3ExOSwgMikNCiAgKSB8Pg0KICBhcnJhbmdlKGRlc2MobWVhbl9xMTkpKQ0KDQpxMTlfY2x1c3Rlcl9zdW1tYXJ5DQpgYGANCg0KYGBge3J9DQprcnVza2FsLnRlc3QoUTE5IH4gY2x1c3RlciwgZGF0YSA9IGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgUTE5ID0gYXMubnVtZXJpYyhRMTkpDQogICkgfD4NCiAgZmlsdGVyKCFpcy5uYShRMTkpLCBRMTkgPj0gMSkNCikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCm5sYl9yZXZvbHV0X24yNl9vdmVybGFwIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBjbHVzdGVyLA0KICAgICAgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwNCiAgICAgIGxhYmVscyA9IGMoDQogICAgICAgICJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIiwNCiAgICAgICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICAgICAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIsDQogICAgICAgICJBSS1yZXNpc3RhbnQgaW5kZXBlbmRlbnRzIiwNCiAgICAgICAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KICAgICAgKQ0KICAgICksDQogICAgUTI1YyA9IGFzLm51bWVyaWMoUTI1YyksICAjIE5MQg0KICAgIFEyNWQgPSBhcy5udW1lcmljKFEyNWQpLCAgIyBSZXZvbHV0DQogICAgUTI1ZSA9IGFzLm51bWVyaWMoUTI1ZSkgICAjIE4yNg0KICApIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogIHN1bW1hcmlzZSgNCiAgICBjbHVzdGVyX24gPSBuKCksDQogICAgbl9ubGJfcmV2b2x1dF9uMjYgPSBzdW0oUTI1YyA9PSAxICYgUTI1ZCA9PSAxICYgUTI1ZSA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KICAgIHBlcmNlbnRfbmxiX3Jldm9sdXRfbjI2ID0gcm91bmQoMTAwICogbl9ubGJfcmV2b2x1dF9uMjYgLyBjbHVzdGVyX24sIDEpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQpubGJfcmV2b2x1dF9uMjZfb3ZlcmxhcA0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KbmxiX3Jldm9sdXRfbjI2X2NvbWJpbmF0aW9ucyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZmFjdG9yKA0KICAgICAgY2x1c3RlciwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSksDQogICAgICBsYWJlbHMgPSBjKA0KICAgICAgICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICAgICAgICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgICAgICAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApLA0KICAgIFEyNWMgPSBhcy5udW1lcmljKFEyNWMpLCAgIyBOTEINCiAgICBRMjVkID0gYXMubnVtZXJpYyhRMjVkKSwgICMgUmV2b2x1dA0KICAgIFEyNWUgPSBhcy5udW1lcmljKFEyNWUpICAgIyBOMjYNCiAgKSB8Pg0KICBtdXRhdGUoDQogICAgYmFua19jb21ibyA9IGNhc2Vfd2hlbigNCiAgICAgIFEyNWMgPT0gMSAmIFEyNWQgPT0gMSAmIFEyNWUgPT0gMSB+ICJOTEIgKyBSZXZvbHV0ICsgTjI2IiwNCiAgICAgIFEyNWMgPT0gMSAmIFEyNWQgPT0gMSAmIChpcy5uYShRMjVlKSB8IFEyNWUgIT0gMSkgfiAiTkxCICsgUmV2b2x1dCIsDQogICAgICBRMjVjID09IDEgJiBRMjVlID09IDEgJiAoaXMubmEoUTI1ZCkgfCBRMjVkICE9IDEpIH4gIk5MQiArIE4yNiIsDQogICAgICBRMjVkID09IDEgJiBRMjVlID09IDEgJiAoaXMubmEoUTI1YykgfCBRMjVjICE9IDEpIH4gIlJldm9sdXQgKyBOMjYiLA0KICAgICAgUTI1YyA9PSAxICYgKGlzLm5hKFEyNWQpIHwgUTI1ZCAhPSAxKSAmIChpcy5uYShRMjVlKSB8IFEyNWUgIT0gMSkgfiAiTkxCIG9ubHkiLA0KICAgICAgUTI1ZCA9PSAxICYgKGlzLm5hKFEyNWMpIHwgUTI1YyAhPSAxKSAmIChpcy5uYShRMjVlKSB8IFEyNWUgIT0gMSkgfiAiUmV2b2x1dCBvbmx5IiwNCiAgICAgIFEyNWUgPT0gMSAmIChpcy5uYShRMjVjKSB8IFEyNWMgIT0gMSkgJiAoaXMubmEoUTI1ZCkgfCBRMjVkICE9IDEpIH4gIk4yNiBvbmx5IiwNCiAgICAgIFRSVUUgfiAiTm9uZSBvZiB0aGVzZSB0aHJlZSINCiAgICApDQogICkgfD4NCiAgZ3JvdXBfYnkoY2x1c3RlciwgYmFua19jb21ibykgfD4NCiAgc3VtbWFyaXNlKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikgfD4NCiAgbXV0YXRlKHBlcmNlbnQgPSByb3VuZCgxMDAgKiBuIC8gc3VtKG4pLCAxKSkgfD4NCiAgdW5ncm91cCgpDQoNCm5sYl9yZXZvbHV0X24yNl9jb21iaW5hdGlvbnMNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkoZ2dwbG90MikNCg0KY2x1c3RlcjJfYmFua19tZWFucyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIGZpbHRlcihjbHVzdGVyID09IDIpIHw+DQogIG11dGF0ZSgNCiAgICBhY3Jvc3MoUTEzYTpRMTVnLCBhcy5udW1lcmljKQ0KICApIHw+DQogIHN1bW1hcmlzZSgNCiAgICBPVFBfaW5ub3ZhdGlvbiA9IG1lYW4oUTEzYSwgbmEucm0gPSBUUlVFKSwNCiAgICBHb3Jlbmpza2FfaW5ub3ZhdGlvbiA9IG1lYW4oUTEzYiwgbmEucm0gPSBUUlVFKSwNCiAgICBOTEJfaW5ub3ZhdGlvbiA9IG1lYW4oUTEzYywgbmEucm0gPSBUUlVFKSwNCiAgICBSZXZvbHV0X2lubm92YXRpb24gPSBtZWFuKFExM2QsIG5hLnJtID0gVFJVRSksDQogICAgTjI2X2lubm92YXRpb24gPSBtZWFuKFExM2UsIG5hLnJtID0gVFJVRSksDQogICAgSW50ZXNhX2lubm92YXRpb24gPSBtZWFuKFExM2YsIG5hLnJtID0gVFJVRSksDQogICAgVW5pQ3JlZGl0X2lubm92YXRpb24gPSBtZWFuKFExM2csIG5hLnJtID0gVFJVRSksDQoNCiAgICBPVFBfc3VwcG9ydCA9IG1lYW4oUTE0YSwgbmEucm0gPSBUUlVFKSwNCiAgICBHb3Jlbmpza2Ffc3VwcG9ydCA9IG1lYW4oUTE0YiwgbmEucm0gPSBUUlVFKSwNCiAgICBOTEJfc3VwcG9ydCA9IG1lYW4oUTE0YywgbmEucm0gPSBUUlVFKSwNCiAgICBSZXZvbHV0X3N1cHBvcnQgPSBtZWFuKFExNGQsIG5hLnJtID0gVFJVRSksDQogICAgTjI2X3N1cHBvcnQgPSBtZWFuKFExNGUsIG5hLnJtID0gVFJVRSksDQogICAgSW50ZXNhX3N1cHBvcnQgPSBtZWFuKFExNGYsIG5hLnJtID0gVFJVRSksDQogICAgVW5pQ3JlZGl0X3N1cHBvcnQgPSBtZWFuKFExNGcsIG5hLnJtID0gVFJVRSksDQoNCiAgICBPVFBfcmVsaWFiaWxpdHkgPSBtZWFuKFExNWEsIG5hLnJtID0gVFJVRSksDQogICAgR29yZW5qc2thX3JlbGlhYmlsaXR5ID0gbWVhbihRMTViLCBuYS5ybSA9IFRSVUUpLA0KICAgIE5MQl9yZWxpYWJpbGl0eSA9IG1lYW4oUTE1YywgbmEucm0gPSBUUlVFKSwNCiAgICBSZXZvbHV0X3JlbGlhYmlsaXR5ID0gbWVhbihRMTVkLCBuYS5ybSA9IFRSVUUpLA0KICAgIE4yNl9yZWxpYWJpbGl0eSA9IG1lYW4oUTE1ZSwgbmEucm0gPSBUUlVFKSwNCiAgICBJbnRlc2FfcmVsaWFiaWxpdHkgPSBtZWFuKFExNWYsIG5hLnJtID0gVFJVRSksDQogICAgVW5pQ3JlZGl0X3JlbGlhYmlsaXR5ID0gbWVhbihRMTVnLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KY2x1c3RlcjJfYmFua19tZWFucw0KYGBgDQoNCmBgYHtyfQ0KY2x1c3RlcjJfYmFua190YWJsZSA8LSB0aWJibGUoDQogIGJhbmsgPSBjKCJPVFAiLCAiR29yZW5qc2thIEJhbmthIiwgIk5MQiIsICJSZXZvbHV0IiwgIk4yNiIsICJJbnRlc2EgU2FuUGFvbG8iLCAiVW5pQ3JlZGl0IiksDQogIGlubm92YXRpb24gPSBjKA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2EpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2IpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2MpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2QpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2UpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2YpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExM2cpLCBuYS5ybSA9IFRSVUUpDQogICksDQogIGN1c3RvbWVyX3N1cHBvcnQgPSBjKA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGEpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGIpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGMpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGUpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGYpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAyKSB8PiBwdWxsKFExNGcpLCBuYS5ybSA9IFRSVUUpDQogICksDQogIHJlbGlhYmlsaXR5ID0gYygNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTVhKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTViKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTVjKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTVkKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTVlKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTVmKSwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWFuKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4gZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gcHVsbChRMTVnKSwgbmEucm0gPSBUUlVFKQ0KICApDQopDQoNCmNsdXN0ZXIyX2JhbmtfdGFibGUNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX21hdCA8LSBjbHVzdGVyMl9iYW5rX3RhYmxlIHw+DQogIGNvbHVtbl90b19yb3duYW1lcygiYmFuayIpIHw+DQogIGFzLm1hdHJpeCgpDQoNCnBjYV9jbHVzdGVyMiA8LSBGYWN0b01pbmVSOjpQQ0EoY2x1c3RlcjJfbWF0LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGQUxTRSkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX2Nvb3JkaW5hdGVzIDwtIGFzLmRhdGEuZnJhbWUocGNhX2NsdXN0ZXIyJGluZCRjb29yZCkNCmNsdXN0ZXIyX2Nvb3JkaW5hdGVzJGJhbmsgPC0gcm93bmFtZXMoY2x1c3RlcjJfY29vcmRpbmF0ZXMpDQpyb3duYW1lcyhjbHVzdGVyMl9jb29yZGluYXRlcykgPC0gTlVMTA0KDQpjbHVzdGVyMl9jb29yZGluYXRlcw0KYGBgDQoNCmBgYHtyfQ0KY2x1c3RlcjJfbG9hZGluZ3MgPC0gYXMuZGF0YS5mcmFtZShwY2FfY2x1c3RlcjIkdmFyJGNvb3JkKQ0KY2x1c3RlcjJfbG9hZGluZ3MkZGltZW5zaW9uIDwtIHJvd25hbWVzKGNsdXN0ZXIyX2xvYWRpbmdzKQ0Kcm93bmFtZXMoY2x1c3RlcjJfbG9hZGluZ3MpIDwtIE5VTEwNCg0KY2x1c3RlcjJfbG9hZGluZ3MNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX25sYl9leHBsYW5hdGlvbiA8LSBjbHVzdGVyMl9iYW5rX3RhYmxlIHw+DQogIGZpbHRlcihiYW5rID09ICJOTEIiKSB8Pg0KICBtdXRhdGUoDQogICAgRGltMV9sb2FkaW5nX2lubm92YXRpb24gPSBwY2FfY2x1c3RlcjIkdmFyJGNvb3JkWyJpbm5vdmF0aW9uIiwgIkRpbS4xIl0sDQogICAgRGltMV9sb2FkaW5nX3N1cHBvcnQgPSBwY2FfY2x1c3RlcjIkdmFyJGNvb3JkWyJjdXN0b21lcl9zdXBwb3J0IiwgIkRpbS4xIl0sDQogICAgRGltMV9sb2FkaW5nX3JlbGlhYmlsaXR5ID0gcGNhX2NsdXN0ZXIyJHZhciRjb29yZFsicmVsaWFiaWxpdHkiLCAiRGltLjEiXSwNCiAgICBEaW0yX2xvYWRpbmdfaW5ub3ZhdGlvbiA9IHBjYV9jbHVzdGVyMiR2YXIkY29vcmRbImlubm92YXRpb24iLCAiRGltLjIiXSwNCiAgICBEaW0yX2xvYWRpbmdfc3VwcG9ydCA9IHBjYV9jbHVzdGVyMiR2YXIkY29vcmRbImN1c3RvbWVyX3N1cHBvcnQiLCAiRGltLjIiXSwNCiAgICBEaW0yX2xvYWRpbmdfcmVsaWFiaWxpdHkgPSBwY2FfY2x1c3RlcjIkdmFyJGNvb3JkWyJyZWxpYWJpbGl0eSIsICJEaW0uMiJdLA0KICAgIE5MQl9EaW0xID0gcGNhX2NsdXN0ZXIyJGluZCRjb29yZFsiTkxCIiwgIkRpbS4xIl0sDQogICAgTkxCX0RpbTIgPSBwY2FfY2x1c3RlcjIkaW5kJGNvb3JkWyJOTEIiLCAiRGltLjIiXQ0KICApDQoNCmNsdXN0ZXIyX25sYl9leHBsYW5hdGlvbg0KYGBgDQoNCmBgYHtyfQ0KZmFjdG9leHRyYTo6ZnZpel9wY2FfYmlwbG90KA0KICBwY2FfY2x1c3RlcjIsDQogIHJlcGVsID0gVFJVRSwNCiAgY29sLnZhciA9ICJncmF5MzAiLA0KICBjb2wuaW5kID0gInN0ZWVsYmx1ZSIsDQogIHBvaW50c2l6ZSA9IDMNCikgKw0KICBnZ3Bsb3QyOjpnZ3RpdGxlKCJQZXJjZXB0aW9uIE1hcCBvZiBCYW5rcyAtIENsdXN0ZXIgMiIpICsNCiAgZ2dwbG90Mjo6eGxhYigiRGltIDEiKSArDQogIGdncGxvdDI6OnlsYWIoIkRpbSAyIikgKw0KICBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX2JhbmtfdGFibGUNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXIyX2Nvb3JkaW5hdGVzDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyMl9sb2FkaW5ncw0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGliYmxlKQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDEpIEJhbmsgbWVhbiB0YWJsZSBmb3IgY2x1c3RlciAzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyM19iYW5rX3RhYmxlIDwtIHRpYmJsZSgNCiAgYmFuayA9IGMoIk9UUCIsICJHb3Jlbmpza2EgQmFua2EiLCAiTkxCIiwgIlJldm9sdXQiLCAiTjI2IiwgIkludGVzYSBTYW5QYW9sbyIsICJVbmlDcmVkaXQiKSwNCiAgaW5ub3ZhdGlvbiA9IGMoDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzYSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzYiksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzYyksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzZCksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzZSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzZiksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTEzZyksIG5hLnJtID0gVFJVRSkNCiAgKSwNCiAgY3VzdG9tZXJfc3VwcG9ydCA9IGMoDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0YSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0YiksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0YyksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0ZCksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0ZSksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0ZiksIG5hLnJtID0gVFJVRSksDQogICAgbWVhbihkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+IGZpbHRlcihjbHVzdGVyID09IDMpIHw+IHB1bGwoUTE0ZyksIG5hLnJtID0gVFJVRSkNCiAgKSwNCiAgcmVsaWFiaWxpdHkgPSBjKA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWEpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWIpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWMpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWUpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWYpLCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lYW4oZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSB8PiBmaWx0ZXIoY2x1c3RlciA9PSAzKSB8PiBwdWxsKFExNWcpLCBuYS5ybSA9IFRSVUUpDQogICkNCikNCg0KY2x1c3RlcjNfYmFua190YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAyKSBQQ0EgZm9yIGNsdXN0ZXIgMw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2x1c3RlcjNfbWF0IDwtIGNsdXN0ZXIzX2JhbmtfdGFibGUgfD4NCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJiYW5rIikgfD4NCiAgYXMubWF0cml4KCkNCg0KcGNhX2NsdXN0ZXIzIDwtIEZhY3RvTWluZVI6OlBDQShjbHVzdGVyM19tYXQsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAzKSBCYW5rIGNvb3JkaW5hdGVzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyM19jb29yZGluYXRlcyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9jbHVzdGVyMyRpbmQkY29vcmQpDQpjbHVzdGVyM19jb29yZGluYXRlcyRiYW5rIDwtIHJvd25hbWVzKGNsdXN0ZXIzX2Nvb3JkaW5hdGVzKQ0Kcm93bmFtZXMoY2x1c3RlcjNfY29vcmRpbmF0ZXMpIDwtIE5VTEwNCg0KY2x1c3RlcjNfY29vcmRpbmF0ZXMNCmBgYA0KDQpgYGB7cn0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgNCkgVmFyaWFibGUgbG9hZGluZ3MNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmNsdXN0ZXIzX2xvYWRpbmdzIDwtIGFzLmRhdGEuZnJhbWUocGNhX2NsdXN0ZXIzJHZhciRjb29yZCkNCmNsdXN0ZXIzX2xvYWRpbmdzJGRpbWVuc2lvbiA8LSByb3duYW1lcyhjbHVzdGVyM19sb2FkaW5ncykNCnJvd25hbWVzKGNsdXN0ZXIzX2xvYWRpbmdzKSA8LSBOVUxMDQoNCmNsdXN0ZXIzX2xvYWRpbmdzDQpgYGANCg0KYGBge3J9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDUpIE5MQiBleHBsYW5hdGlvbiB0YWJsZQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2x1c3RlcjNfbmxiX2V4cGxhbmF0aW9uIDwtIGNsdXN0ZXIzX2JhbmtfdGFibGUgfD4NCiAgZmlsdGVyKGJhbmsgPT0gIk5MQiIpIHw+DQogIG11dGF0ZSgNCiAgICBEaW0xX2xvYWRpbmdfaW5ub3ZhdGlvbiA9IHBjYV9jbHVzdGVyMyR2YXIkY29vcmRbImlubm92YXRpb24iLCAiRGltLjEiXSwNCiAgICBEaW0xX2xvYWRpbmdfc3VwcG9ydCA9IHBjYV9jbHVzdGVyMyR2YXIkY29vcmRbImN1c3RvbWVyX3N1cHBvcnQiLCAiRGltLjEiXSwNCiAgICBEaW0xX2xvYWRpbmdfcmVsaWFiaWxpdHkgPSBwY2FfY2x1c3RlcjMkdmFyJGNvb3JkWyJyZWxpYWJpbGl0eSIsICJEaW0uMSJdLA0KICAgIERpbTJfbG9hZGluZ19pbm5vdmF0aW9uID0gcGNhX2NsdXN0ZXIzJHZhciRjb29yZFsiaW5ub3ZhdGlvbiIsICJEaW0uMiJdLA0KICAgIERpbTJfbG9hZGluZ19zdXBwb3J0ID0gcGNhX2NsdXN0ZXIzJHZhciRjb29yZFsiY3VzdG9tZXJfc3VwcG9ydCIsICJEaW0uMiJdLA0KICAgIERpbTJfbG9hZGluZ19yZWxpYWJpbGl0eSA9IHBjYV9jbHVzdGVyMyR2YXIkY29vcmRbInJlbGlhYmlsaXR5IiwgIkRpbS4yIl0sDQogICAgTkxCX0RpbTEgPSBwY2FfY2x1c3RlcjMkaW5kJGNvb3JkWyJOTEIiLCAiRGltLjEiXSwNCiAgICBOTEJfRGltMiA9IHBjYV9jbHVzdGVyMyRpbmQkY29vcmRbIk5MQiIsICJEaW0uMiJdDQogICkNCg0KY2x1c3RlcjNfbmxiX2V4cGxhbmF0aW9uDQpgYGANCg0KYGBge3J9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDYpIFBsb3QNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmZhY3RvZXh0cmE6OmZ2aXpfcGNhX2JpcGxvdCgNCiAgcGNhX2NsdXN0ZXIzLA0KICByZXBlbCA9IFRSVUUsDQogIGNvbC52YXIgPSAiZ3JheTMwIiwNCiAgY29sLmluZCA9ICJzdGVlbGJsdWUiLA0KICBwb2ludHNpemUgPSAzDQopICsNCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiUGVyY2VwdGlvbiBNYXAgb2YgQmFua3MgLSBDbHVzdGVyIDMiKSArDQogIGdncGxvdDI6OnhsYWIoIkRpbSAxIikgKw0KICBnZ3Bsb3QyOjp5bGFiKCJEaW0gMiIpICsNCiAgZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDcpIENvbXBhcmUgTkxCIHdpdGggUmV2b2x1dCBhbmQgTjI2DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyM19iYW5rX3RhYmxlIHw+DQogIGZpbHRlcihiYW5rICVpbiUgYygiTkxCIiwgIlJldm9sdXQiLCAiTjI2IikpDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyM19iYW5rX3RhYmxlDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocHVycnIpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMSkgUTEyIGl0ZW0gbGFiZWxzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpxMTJfbGFiZWxzIDwtIGMoDQogIFExMmEgPSAiU2VjdXJpdHkiLA0KICBRMTJiID0gIlBlcnNvbmFsIGRhdGEgcHJvdGVjdGlvbiIsDQogIFExMmMgPSAiVHJ1c3QgaW4gdGhlIGJhbmsiLA0KICBRMTJkID0gIkVhc2Ugb2YgdXNlIiwNCiAgUTEyZSA9ICJUcmFuc2FjdGlvbiBleGVjdXRpb24gc3BlZWQiLA0KICBRMTJmID0gIlZhcmlldHkgb2YgZnVuY3Rpb25zIiwNCiAgUTEyZyA9ICJBdmFpbGFiaWxpdHkgb2YgaHVtYW4gc3VwcG9ydCIsDQogIFExMmggPSAiUGVyc29uYWxpemVkIGZpbmFuY2lhbCBpbnNpZ2h0cyIsDQogIFExMmkgPSAiVW5kZXJzdGFuZGluZyBob3cgdGhlIHByb2dyYW0gbWFrZXMgZGVjaXNpb25zIg0KKQ0KDQpxMTJfdmFycyA8LSBuYW1lcyhxMTJfbGFiZWxzKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDIpIEF0dGFjaCB0aGUgNS1jbHVzdGVyIHNvbHV0aW9uDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjbHVzdGVyX2xhYmVscyA8LSBjKA0KICAiU2tlcHRpY2FsIHN1cHBvcnQgc2Vla2VycyIsDQogICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwNCiAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLA0KICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCikNCg0KZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSA8LSBkYXRhX2NsZWFuX2NvbXBsZXRlICU+JQ0KICBtdXRhdGUoDQogICAgY2x1c3RlciA9IGZhY3RvcigNCiAgICAgIGs1X3BjYTIkY2x1c3RlciwNCiAgICAgIGxldmVscyA9IDE6NSwNCiAgICAgIGxhYmVscyA9IGNsdXN0ZXJfbGFiZWxzDQogICAgKQ0KICApDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMykgRnVuY3Rpb24gdG8gcHJvZmlsZSBPTkUgY2x1c3RlciBpbmRlcGVuZGVudGx5DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpwcm9maWxlX29uZV9jbHVzdGVyX3ExMiA8LSBmdW5jdGlvbihkYXRhLCBjbHVzdGVyX25hbWUpIHsNCiAgDQogIGRhdGEgJT4lDQogICAgZmlsdGVyKGNsdXN0ZXIgPT0gY2x1c3Rlcl9uYW1lKSAlPiUNCiAgICBzZWxlY3QoYWxsX29mKHExMl92YXJzKSkgJT4lDQogICAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIGFzLm51bWVyaWMpKSAlPiUNCiAgICBwaXZvdF9sb25nZXIoDQogICAgICBjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgbmFtZXNfdG8gPSAiaXRlbSIsDQogICAgICB2YWx1ZXNfdG8gPSAic2NvcmUiDQogICAgKSAlPiUNCiAgICBncm91cF9ieShpdGVtKSAlPiUNCiAgICBzdW1tYXJpc2UoDQogICAgICBuID0gc3VtKCFpcy5uYShzY29yZSkpLA0KICAgICAgbWVhbiA9IHJvdW5kKG1lYW4oc2NvcmUsIG5hLnJtID0gVFJVRSksIDIpLA0KICAgICAgc2QgPSByb3VuZChzZChzY29yZSwgbmEucm0gPSBUUlVFKSwgMiksDQogICAgICBtZWRpYW4gPSByb3VuZChtZWRpYW4oc2NvcmUsIG5hLnJtID0gVFJVRSksIDIpLA0KICAgICAgcGN0XzZfNyA9IHJvdW5kKG1lYW4oc2NvcmUgJWluJSBjKDYsIDcpLCBuYS5ybSA9IFRSVUUpICogMTAwLCAxKSwNCiAgICAgIHBjdF83ID0gcm91bmQobWVhbihzY29yZSA9PSA3LCBuYS5ybSA9IFRSVUUpICogMTAwLCAxKSwNCiAgICAgIC5ncm91cHMgPSAiZHJvcCINCiAgICApICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIGxhYmVsID0gcTEyX2xhYmVsc1tpdGVtXSwNCiAgICAgIGNsdXN0ZXIgPSBjbHVzdGVyX25hbWUNCiAgICApICU+JQ0KICAgIHNlbGVjdChjbHVzdGVyLCBpdGVtLCBsYWJlbCwgbiwgbWVhbiwgc2QsIG1lZGlhbiwgcGN0XzZfNywgcGN0XzcpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhtZWFuKSkNCn0NCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA0KSBDcmVhdGUgYSBzZXBhcmF0ZSBwcm9maWxlIGZvciBlYWNoIGNsdXN0ZXINCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmNsdXN0ZXJfMV9xMTJfcHJvZmlsZSA8LSBwcm9maWxlX29uZV9jbHVzdGVyX3ExMigNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwNCiAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiDQopDQoNCmNsdXN0ZXJfMl9xMTJfcHJvZmlsZSA8LSBwcm9maWxlX29uZV9jbHVzdGVyX3ExMigNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwNCiAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiDQopDQoNCmNsdXN0ZXJfM19xMTJfcHJvZmlsZSA8LSBwcm9maWxlX29uZV9jbHVzdGVyX3ExMigNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwNCiAgIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiDQopDQoNCmNsdXN0ZXJfNF9xMTJfcHJvZmlsZSA8LSBwcm9maWxlX29uZV9jbHVzdGVyX3ExMigNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwNCiAgIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiDQopDQoNCmNsdXN0ZXJfNV9xMTJfcHJvZmlsZSA8LSBwcm9maWxlX29uZV9jbHVzdGVyX3ExMigNCiAgZGF0YV9jbHVzdGVyX3Byb2ZpbGVfNSwNCiAgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIg0KKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDUpIFZpZXcgZWFjaCBjbHVzdGVyIGluZGVwZW5kZW50bHkNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmNsdXN0ZXJfMV9xMTJfcHJvZmlsZQ0KY2x1c3Rlcl8yX3ExMl9wcm9maWxlDQpjbHVzdGVyXzNfcTEyX3Byb2ZpbGUNCmNsdXN0ZXJfNF9xMTJfcHJvZmlsZQ0KY2x1c3Rlcl81X3ExMl9wcm9maWxlDQpgYGANCg0KYGBge3J9DQpjbHVzdGVyX3ExMl9wcm9maWxlcyA8LSBzZXROYW1lcygNCiAgbGFwcGx5KGxldmVscyhkYXRhX2NsdXN0ZXJfcHJvZmlsZV81JGNsdXN0ZXIpLCBmdW5jdGlvbihjbCkgew0KICAgIHByb2ZpbGVfb25lX2NsdXN0ZXJfcTEyKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUsIGNsKQ0KICB9KSwNCiAgbGV2ZWxzKGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUkY2x1c3RlcikNCikNCg0KIyBFeGFtcGxlOg0KY2x1c3Rlcl9xMTJfcHJvZmlsZXNbWyJTa2VwdGljYWwgc3VwcG9ydCBzZWVrZXJzIl1dDQpjbHVzdGVyX3ExMl9wcm9maWxlc1tbIkFJLXJlc2lzdGFudCBpbmRlcGVuZGVudHMiXV0NCmBgYA0KDQpgYGB7cn0NCmJhbmtfZGF0YSA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZShhY3Jvc3MoUTI1YTpRMjVsLCBhcy5udW1lcmljKSkNCg0KYGBgDQoNCg0KYGBge3J9DQpiYW5rX2NvbWJpbmF0aW9ucyA8LSBiYW5rX2RhdGEgfD4NCiAgbXV0YXRlKA0KDQogICAgIyBSZXZvbHV0IG9ubHkNCiAgICByZXZvbHV0X29ubHkgPQ0KICAgICAgUTI1ZCA9PSAxICYNCiAgICAgIHJvd1N1bXMoYWNyb3NzKFEyNWE6UTI1YykpID09IDAgJg0KICAgICAgcm93U3VtcyhhY3Jvc3MoUTI1ZTpRMjVsKSkgPT0gMCwNCg0KICAgICMgTkxCICsgUmV2b2x1dA0KICAgIG5sYl9yZXZvbHV0ID0NCiAgICAgIFEyNWMgPT0gMSAmIFEyNWQgPT0gMSwNCg0KICAgICMgUmV2b2x1dCArIGFueSBvdGhlciBiYW5rIGV4Y2VwdCBOTEINCiAgICByZXZvbHV0X290aGVyID0NCiAgICAgIFEyNWQgPT0gMSAmDQogICAgICByb3dTdW1zKGFjcm9zcyhjKFEyNWEsIFEyNWIsIFEyNWU6UTI1bCkpKSA+IDAsDQoNCiAgICAjIFJldm9sdXQgKyBncm91cGVkICJvdGhlciBiYW5rcyIgKGFsbCBleGNlcHQgTkxCKQ0KICAgIHJldm9sdXRfZ3JvdXBfb3RoZXIgPQ0KICAgICAgUTI1ZCA9PSAxICYNCiAgICAgIHJvd1N1bXMoYWNyb3NzKGMoUTI1YSwgUTI1YiwgUTI1ZTpRMjVsKSkpID4gMA0KICApDQoNCmBgYA0KDQpgYGB7cn0NCnJldm9sdXRfY2x1c3Rlcl90YWJsZSA8LSBiYW5rX2NvbWJpbmF0aW9ucyB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQoNCiAgICBuX2NsdXN0ZXIgPSBuKCksDQoNCiAgICByZXZvbHV0X29ubHkgPSBzdW0ocmV2b2x1dF9vbmx5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG5sYl9yZXZvbHV0ID0gc3VtKG5sYl9yZXZvbHV0LCBuYS5ybSA9IFRSVUUpLA0KICAgIHJldm9sdXRfb3RoZXIgPSBzdW0ocmV2b2x1dF9vdGhlciwgbmEucm0gPSBUUlVFKSwNCiAgICByZXZvbHV0X2dyb3VwX290aGVyID0gc3VtKHJldm9sdXRfZ3JvdXBfb3RoZXIsIG5hLnJtID0gVFJVRSksDQoNCiAgICByZXZvbHV0X29ubHlfcGN0ID0gcm91bmQoMTAwICogcmV2b2x1dF9vbmx5IC8gbl9jbHVzdGVyLCAxKSwNCiAgICBubGJfcmV2b2x1dF9wY3QgPSByb3VuZCgxMDAgKiBubGJfcmV2b2x1dCAvIG5fY2x1c3RlciwgMSksDQogICAgcmV2b2x1dF9vdGhlcl9wY3QgPSByb3VuZCgxMDAgKiByZXZvbHV0X290aGVyIC8gbl9jbHVzdGVyLCAxKSwNCiAgICByZXZvbHV0X2dyb3VwX290aGVyX3BjdCA9IHJvdW5kKDEwMCAqIHJldm9sdXRfZ3JvdXBfb3RoZXIgLyBuX2NsdXN0ZXIsIDEpDQoNCiAgKQ0KDQpyZXZvbHV0X2NsdXN0ZXJfdGFibGUNCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5cikNCg0KcmV2b2x1dF9jbHVzdGVyX3RhYmxlIHw+DQogIHNlbGVjdCgNCiAgICBjbHVzdGVyLA0KICAgIHJldm9sdXRfb25seV9wY3QsDQogICAgbmxiX3Jldm9sdXRfcGN0LA0KICAgIHJldm9sdXRfb3RoZXJfcGN0DQogICkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJjb21iaW5hdGlvbiIsDQogICAgdmFsdWVzX3RvID0gInBlcmNlbnQiDQogICkNCg0KYGBgDQoNCmBgYHtyfQ0KYmFua19kYXRhIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKGFjcm9zcyhRMjVhOlEyNWwsIGFzLm51bWVyaWMpKQ0KDQpgYGANCg0KYGBge3J9DQpiYW5rX2dyb3VwcyA8LSBiYW5rX2RhdGEgfD4NCiAgbXV0YXRlKA0KDQogICAgIyBSZXZvbHV0IG9ubHkNCiAgICByZXZvbHV0X29ubHkgPQ0KICAgICAgUTI1ZCA9PSAxICYNCiAgICAgIHJvd1N1bXMoYWNyb3NzKGMoUTI1YSwgUTI1YiwgUTI1YywgUTI1ZTpRMjVsKSkpID09IDAsDQoNCiAgICAjIE5MQiArIFJldm9sdXQNCiAgICBubGJfcmV2b2x1dCA9DQogICAgICBRMjVjID09IDEgJiBRMjVkID09IDEsDQoNCiAgICAjIE9UUCArIFJldm9sdXQNCiAgICBvdHBfcmV2b2x1dCA9DQogICAgICBRMjVhID09IDEgJiBRMjVkID09IDEsDQoNCiAgICAjIFJldm9sdXQgKyBhbnkgb3RoZXIgYmFuayBleGNlcHQgTkxCIGFuZCBPVFANCiAgICByZXZvbHV0X290aGVyID0NCiAgICAgIFEyNWQgPT0gMSAmDQogICAgICByb3dTdW1zKGFjcm9zcyhjKFEyNWIsIFEyNWU6UTI1bCkpKSA+IDANCiAgKQ0KDQpgYGANCg0KYGBge3J9DQpyZXZvbHV0X2NsdXN0ZXJfc3VtbWFyeSA8LSBiYW5rX2dyb3VwcyB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQoNCiAgICBuX2NsdXN0ZXIgPSBuKCksDQoNCiAgICByZXZvbHV0X29ubHkgPSBzdW0ocmV2b2x1dF9vbmx5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG5sYl9yZXZvbHV0ID0gc3VtKG5sYl9yZXZvbHV0LCBuYS5ybSA9IFRSVUUpLA0KICAgIG90cF9yZXZvbHV0ID0gc3VtKG90cF9yZXZvbHV0LCBuYS5ybSA9IFRSVUUpLA0KICAgIHJldm9sdXRfb3RoZXIgPSBzdW0ocmV2b2x1dF9vdGhlciwgbmEucm0gPSBUUlVFKSwNCg0KICAgIHJldm9sdXRfb25seV9wY3QgPSByb3VuZCgxMDAgKiByZXZvbHV0X29ubHkgLyBuX2NsdXN0ZXIsIDEpLA0KICAgIG5sYl9yZXZvbHV0X3BjdCA9IHJvdW5kKDEwMCAqIG5sYl9yZXZvbHV0IC8gbl9jbHVzdGVyLCAxKSwNCiAgICBvdHBfcmV2b2x1dF9wY3QgPSByb3VuZCgxMDAgKiBvdHBfcmV2b2x1dCAvIG5fY2x1c3RlciwgMSksDQogICAgcmV2b2x1dF9vdGhlcl9wY3QgPSByb3VuZCgxMDAgKiByZXZvbHV0X290aGVyIC8gbl9jbHVzdGVyLCAxKQ0KDQogICkNCg0KcmV2b2x1dF9jbHVzdGVyX3N1bW1hcnkNCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5cikNCg0KcmV2b2x1dF9jbHVzdGVyX3N1bW1hcnkgfD4NCiAgc2VsZWN0KA0KICAgIGNsdXN0ZXIsDQogICAgcmV2b2x1dF9vbmx5X3BjdCwNCiAgICBubGJfcmV2b2x1dF9wY3QsDQogICAgb3RwX3Jldm9sdXRfcGN0LA0KICAgIHJldm9sdXRfb3RoZXJfcGN0DQogICkgfD4NCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtY2x1c3RlciwNCiAgICBuYW1lc190byA9ICJncm91cCIsDQogICAgdmFsdWVzX3RvID0gInBlcmNlbnQiDQogICkNCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KYmFua19zZWdtZW50cyA8LSBkYXRhX2NsdXN0ZXJfcHJvZmlsZV81IHw+DQogIG11dGF0ZShhY3Jvc3MoUTI1YTpRMjVsLCBhcy5udW1lcmljKSkgfD4NCiAgbXV0YXRlKA0KDQogICAgc2VnbWVudCA9IGNhc2Vfd2hlbigNCg0KICAgICAgUTI1YyA9PSAxICYgUTI1ZCA9PSAwICYgUTI1YSA9PSAwIH4gIk5MQiBvbmx5IiwNCiAgICAgIFEyNWQgPT0gMSAmIFEyNWMgPT0gMCAmIFEyNWEgPT0gMCB+ICJSZXZvbHV0IG9ubHkiLA0KICAgICAgUTI1YSA9PSAxICYgUTI1YyA9PSAwICYgUTI1ZCA9PSAwIH4gIk9UUCBvbmx5IiwNCg0KICAgICAgUTI1YyA9PSAxICYgUTI1ZCA9PSAxICYgUTI1YSA9PSAwIH4gIk5MQiArIFJldm9sdXQiLA0KICAgICAgUTI1YyA9PSAxICYgUTI1YSA9PSAxICYgUTI1ZCA9PSAwIH4gIk5MQiArIE9UUCIsDQogICAgICBRMjVhID09IDEgJiBRMjVkID09IDEgJiBRMjVjID09IDAgfiAiT1RQICsgUmV2b2x1dCIsDQoNCiAgICAgIFEyNWEgPT0gMSAmIFEyNWMgPT0gMSAmIFEyNWQgPT0gMSB+ICJOTEIgKyBSZXZvbHV0ICsgT1RQIiwNCg0KICAgICAgVFJVRSB+ICJOb25lIG9mIHRoZXNlIHRocmVlIg0KICAgICkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0Kc2VnbWVudF90YWJsZSA8LSBiYW5rX3NlZ21lbnRzIHw+DQogIGdyb3VwX2J5KGNsdXN0ZXIsIHNlZ21lbnQpIHw+DQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBtdXRhdGUoDQogICAgcGVyY2VudCA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obiksIDEpDQogICkgfD4NCiAgYXJyYW5nZShjbHVzdGVyLCBkZXNjKHBlcmNlbnQpKQ0KDQpzZWdtZW50X3RhYmxlDQpgYGANCg0KYGBge3J9DQpjb252ZXJzaW9uX3RhYmxlIDwtIGRhdGFfY2x1c3Rlcl9wcm9maWxlXzUgfD4NCiAgbXV0YXRlKGFjcm9zcyhRMjVhOlEyNWwsIGFzLm51bWVyaWMpKSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQoNCiAgICBjbHVzdGVyX3NpemUgPSBuKCksDQoNCiAgICByZXZvbHV0X3VzZXJzID0gc3VtKFEyNWQgPT0gMSwgbmEucm0gPSBUUlVFKSwNCiAgICBubGJfdXNlcnMgPSBzdW0oUTI1YyA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgbmxiX3Jldm9sdXRfdXNlcnMgPSBzdW0oUTI1YyA9PSAxICYgUTI1ZCA9PSAxLCBuYS5ybSA9IFRSVUUpLA0KDQogICAgcmV2b2x1dF93aXRob3V0X25sYiA9IHN1bShRMjVkID09IDEgJiBRMjVjID09IDAsIG5hLnJtID0gVFJVRSksDQoNCiAgICByZXZvbHV0X3VzZXJzX3BjdCA9IHJvdW5kKDEwMCAqIHJldm9sdXRfdXNlcnMgLyBjbHVzdGVyX3NpemUsIDEpLA0KDQogICAgcmV2b2x1dF93aXRob3V0X25sYl9wY3QgPQ0KICAgICAgcm91bmQoMTAwICogcmV2b2x1dF93aXRob3V0X25sYiAvIGNsdXN0ZXJfc2l6ZSwgMSkNCg0KICApDQoNCmNvbnZlcnNpb25fdGFibGUNCmBgYA0KDQoNCg0KIyNDbHVzdGVyIDMNCmBgYHtyfQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkodGliYmxlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIyAxLiBMb2FkIGFuZCBjbGVhbiBkYXRhIC0tLS0NCg0KcmF3X3NoZWV0IDwtIHJlYWRfZXhjZWwoDQogICJRdWVzdGlvbm5haXJlX3Jlc3VsdHNfRU4ueGxzeCIsDQogIHNoZWV0ID0gIlBvZGF0a2kiLA0KICBjb2xfbmFtZXMgPSBGQUxTRQ0KKQ0KDQp2YXJfbmFtZXMgPC0gcmF3X3NoZWV0IHw+DQogIHNsaWNlKDEpIHw+DQogIHVubGlzdCh1c2UubmFtZXMgPSBGQUxTRSkgfD4NCiAgYXMuY2hhcmFjdGVyKCkNCg0KcXVlc3Rpb25fdGV4dCA8LSByYXdfc2hlZXQgfD4NCiAgc2xpY2UoMikgfD4NCiAgdW5saXN0KHVzZS5uYW1lcyA9IEZBTFNFKSB8Pg0KICBhcy5jaGFyYWN0ZXIoKQ0KDQpkYXRhX3JhdyA8LSByYXdfc2hlZXQgfD4NCiAgc2xpY2UoLSgxOjIpKQ0KDQpuYW1lcyhkYXRhX3JhdykgPC0gdmFyX25hbWVzDQoNCmRhdGFfcmF3IDwtIGRhdGFfcmF3IHw+DQogIG11dGF0ZShyZXNwb25kZW50X2lkID0gcm93X251bWJlcigpKSB8Pg0KICByZWxvY2F0ZShyZXNwb25kZW50X2lkKQ0KDQpkYXRhX2NsZWFuIDwtIGRhdGFfcmF3IHw+DQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgIH4gcmVwbGFjZShhcy5jaGFyYWN0ZXIoLiksIGFzLmNoYXJhY3RlciguKSA9PSAiLTEiLCBOQSkpKSB8Pg0KICBmaWx0ZXIoIWlzLm5hKFEyMiksICFpcy5uYShRMjMpKQ0KDQpkYXRhX2NsZWFuIDwtIGRhdGFfY2xlYW4gfD4NCiAgbXV0YXRlKA0KICAgIGFjcm9zcygNCiAgICAgIFExM2E6UTE1ZywNCiAgICAgIH4gYXMubnVtZXJpYyhyZXBsYWNlKC4sIC4gPT0gIjgiLCBOQSkpDQogICAgKQ0KICApDQoNCiMjIDIuIFJlYnVpbGQgdGhlIDUgcmVzcG9uZGVudCBjbHVzdGVycyAoc2FtZSBsb2dpYyBhcyBiZWZvcmUpIC0tLS0NCg0KY2x1c3Rlcl9kYXRhIDwtIGRhdGFfY2xlYW4gfD4NCiAgc2VsZWN0KFE2YSwgUTZiLCBRNmQsIFE2ZSwgUTZoLCBRNmksDQogICAgICAgICBROGEsIFE4YiwgUThjLCBROGQsIFE4ZSkgfD4NCiAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIGFzLm51bWVyaWMpKQ0KDQpjbHVzdGVyX2RhdGFfY29tcGxldGUgPC0gY2x1c3Rlcl9kYXRhIHw+DQogIGRyb3BfbmEoKQ0KDQpwY2FfY2x1c3RlciA8LSBwcmNvbXAoY2x1c3Rlcl9kYXRhX2NvbXBsZXRlLCBzY2FsZS4gPSBUUlVFKQ0KcGNhX3Njb3Jlc18yIDwtIGFzLmRhdGEuZnJhbWUocGNhX2NsdXN0ZXIkeFssIDE6Ml0pDQoNCnNldC5zZWVkKDEyMykNCms1X3BjYTIgPC0ga21lYW5zKHBjYV9zY29yZXNfMiwgY2VudGVycyA9IDUsIG5zdGFydCA9IDI1KQ0KDQpkYXRhX2NsZWFuX2NvbXBsZXRlIDwtIGRhdGFfY2xlYW4gfD4NCiAgZmlsdGVyKA0KICAgICFpcy5uYShRNmEpLCAhaXMubmEoUTZiKSwgIWlzLm5hKFE2ZCksICFpcy5uYShRNmUpLCAhaXMubmEoUTZoKSwgIWlzLm5hKFE2aSksDQogICAgIWlzLm5hKFE4YSksICFpcy5uYShROGIpLCAhaXMubmEoUThjKSwgIWlzLm5hKFE4ZCksICFpcy5uYShROGUpDQogICkNCg0KZGF0YV9jbHVzdGVyIDwtIGRhdGFfY2xlYW5fY29tcGxldGUgfD4NCiAgbXV0YXRlKA0KICAgIGNsdXN0ZXIgPSBmYWN0b3IoDQogICAgICBrNV9wY2EyJGNsdXN0ZXIsDQogICAgICBsZXZlbHMgPSBjKDEsIDIsIDMsIDQsIDUpLA0KICAgICAgbGFiZWxzID0gYygNCiAgICAgICAgIlNrZXB0aWNhbCBzdXBwb3J0IHNlZWtlcnMiLA0KICAgICAgICAiQ2F1dGlvdXMgZ3VpZGFuY2Ugc2Vla2VycyIsDQogICAgICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwgICAjIGNsdXN0ZXIgMw0KICAgICAgICAiQUktcmVzaXN0YW50IGluZGVwZW5kZW50cyIsDQogICAgICAgICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyINCiAgICAgICkNCiAgICApDQogICkNCg0KIyMgMy4gSGFyZC1jb2RlIGJhbmtzIGFuZCBwZXJjZXB0aW9uIGl0ZW1zIChRMTPigJNRMTUpIC0tLS0NCg0KIyBRMTM6IGlubm92YXRpb24sIFExNDogY3VzdG9tZXIgc3VwcG9ydCwgUTE1OiByZWxpYWJpbGl0eQ0KcGVyY2VwdF92YXJzIDwtIGMoDQogICJRMTNhIiwiUTEzYiIsIlExM2MiLCJRMTNkIiwiUTEzZSIsIlExM2YiLCJRMTNnIiwNCiAgIlExNGEiLCJRMTRiIiwiUTE0YyIsIlExNGQiLCJRMTRlIiwiUTE0ZiIsIlExNGciLA0KICAiUTE1YSIsIlExNWIiLCJRMTVjIiwiUTE1ZCIsIlExNWUiLCJRMTVmIiwiUTE1ZyINCikNCg0KIyBleHBsaWNpdCBtYXBwaW5nIGZyb20gY29sdW1uIHN1ZmZpeCAoYeKAk2cpIHRvIGJhbmsgbmFtZQ0KYmFua19sb29rdXAgPC0gdGliYmxlKA0KICBiYW5rX2NvZGUgID0gbGV0dGVyc1sxOjddLA0KICBiYW5rX2xhYmVsID0gYygiT1RQIiwNCiAgICAgICAgICAgICAgICAgIkdvcmVuanNrYSBCYW5rYSIsDQogICAgICAgICAgICAgICAgICJOTEIiLA0KICAgICAgICAgICAgICAgICAiUmV2b2x1dCIsDQogICAgICAgICAgICAgICAgICJOMjYiLA0KICAgICAgICAgICAgICAgICAiSW50ZXNhIFNhblBhb2xvIiwNCiAgICAgICAgICAgICAgICAgIlVuaUNyZWRpdCIpDQopDQoNCiMgaGVscGVyIHRhYmxlIGRlc2NyaWJpbmcgZWFjaCBRMTPigJMxNSB2YXJpYWJsZQ0KcW1ldGEgPC0gdGliYmxlKHZhcmlhYmxlID0gcGVyY2VwdF92YXJzKSAlPiUNCiAgbXV0YXRlKA0KICAgIHFjb2RlICAgICA9IHN1YnN0cih2YXJpYWJsZSwgMSwgMyksICAgICAjIFExMywgUTE0LCBRMTUNCiAgICBiYW5rX2NvZGUgPSBzdWJzdHIodmFyaWFibGUsIDQsIDQpICAgICAgIyBh4oCTZw0KICApICU+JQ0KICBsZWZ0X2pvaW4oYmFua19sb29rdXAsIGJ5ID0gImJhbmtfY29kZSIpICU+JQ0KICBtdXRhdGUoDQogICAgYXR0cmlidXRlID0gY2FzZV93aGVuKA0KICAgICAgcWNvZGUgPT0gIlExMyIgfiAiaW5ub3ZhdGlvbiIsDQogICAgICBxY29kZSA9PSAiUTE0IiB+ICJjdXN0b21lcl9zdXBwb3J0IiwNCiAgICAgIHFjb2RlID09ICJRMTUiIH4gInJlbGlhYmlsaXR5IiwNCiAgICAgIFRSVUUgfiBxY29kZQ0KICAgICkNCiAgKQ0KDQojIyA0LiBCdWlsZCBiYW5rIHggYXR0cmlidXRlIG1hdHJpeCBmb3IgY2x1c3RlciAzIC0tLS0NCg0KY2x1c3RlcjMgPC0gZGF0YV9jbHVzdGVyICU+JQ0KICBmaWx0ZXIoY2x1c3RlciA9PSAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIpDQoNCmNsdXN0ZXIzX3BlcmNlcHQgPC0gY2x1c3RlcjMgJT4lDQogIHNlbGVjdChhbGxfb2YocGVyY2VwdF92YXJzKSkgJT4lDQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5udW1lcmljKSkNCg0KbWVhbnNfYzMgPC0gY2x1c3RlcjNfcGVyY2VwdCAlPiUNCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gbWVhbigueCwgbmEucm0gPSBUUlVFKSkpDQoNCm1lYW5zX2xvbmcgPC0gbWVhbnNfYzMgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm1lYW5fc2NvcmUiKSAlPiUNCiAgbGVmdF9qb2luKHFtZXRhLCBieSA9ICJ2YXJpYWJsZSIpDQoNCmJhbmtfYXR0cl9tYXQgPC0gbWVhbnNfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoYmFua19sYWJlbCwgYXR0cmlidXRlKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fc2NvcmUgPSBtZWFuKG1lYW5fc2NvcmUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUNCiAgcGl2b3Rfd2lkZXIoDQogICAgaWRfY29scyA9IGJhbmtfbGFiZWwsDQogICAgbmFtZXNfZnJvbSA9IGF0dHJpYnV0ZSwNCiAgICB2YWx1ZXNfZnJvbSA9IG1lYW5fc2NvcmUNCiAgKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQoNCnJvd25hbWVzKGJhbmtfYXR0cl9tYXQpIDwtIGJhbmtfYXR0cl9tYXQkYmFua19sYWJlbA0KYmFua19hdHRyX21hdCRiYW5rX2xhYmVsIDwtIE5VTEwNCg0KIyMgNS4gUENBIGZvciBiYW5rcyAoY2x1c3RlciAzKSAtLS0tDQoNCnBjYV9iYW5rc19jMyA8LSBwcmNvbXAoYmFua19hdHRyX21hdCwgc2NhbGUuID0gVFJVRSkNCg0Kc2NvcmVzX2MzIDwtIGFzLmRhdGEuZnJhbWUocGNhX2JhbmtzX2MzJHhbLCAxOjJdKQ0Kc2NvcmVzX2MzJGJhbmtfbGFiZWwgPC0gcm93bmFtZXMoc2NvcmVzX2MzKQ0KDQpsb2FkaW5nc19jMyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jMyRyb3RhdGlvblssIDE6Ml0pDQpsb2FkaW5nc19jMyRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZGluZ3NfYzMpDQoNCmFycm93X3NjYWxlIDwtIDEuNQ0KbG9hZGluZ3NfYzMgPC0gbG9hZGluZ3NfYzMgJT4lDQogIG11dGF0ZShQQzEgPSBQQzEgKiBhcnJvd19zY2FsZSwNCiAgICAgICAgIFBDMiA9IFBDMiAqIGFycm93X3NjYWxlKQ0KDQojIyA2LiBQbG90OiBwZXJjZXB0dWFsIG1hcCBvZiBiYW5rcyDigJMgY2x1c3RlciAzIC0tLS0NCg0KZ2dwbG90KCkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBzY29yZXNfYzMsDQogICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIpLA0KICAgICAgICAgICAgIHNpemUgPSAyLjgsIGNvbG91ciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBzY29yZXNfYzMsDQogICAgICAgICAgICBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBiYW5rX2xhYmVsKSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNywgc2l6ZSA9IDMuMikgKw0KICBnZW9tX3NlZ21lbnQoZGF0YSA9IGxvYWRpbmdzX2MzLA0KICAgICAgICAgICAgICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IFBDMSwgeWVuZCA9IFBDMiksDQogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksDQogICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTQwIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGxvYWRpbmdzX2MzLA0KICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gYXR0cmlidXRlKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCB2anVzdCA9IC0wLjQsIGNvbG91ciA9ICJncmV5NDAiLCBzaXplID0gMykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiZ3JleTc1IikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiZ3JleTc1IikgKw0KICBjb29yZF9lcXVhbCh4bGltID0gYyhtaW4oc2NvcmVzX2MzJFBDMSkgLSAwLjgsIG1heChzY29yZXNfYzMkUEMxKSArIDAuOCksDQogICAgICAgICAgICAgIHlsaW0gPSBjKG1pbihzY29yZXNfYzMkUEMyKSAtIDAuOCwgbWF4KHNjb3Jlc19jMyRQQzIpICsgMC44KSwNCiAgICAgICAgICAgICAgZXhwYW5kID0gVFJVRSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIOKAkyBDbHVzdGVyIDMiLA0KICAgIHggPSAiT3ZlcmFsbCBEaWdpdGFsIEJhbmtpbmcgUGVyZm9ybWFuY2UiLA0KICAgIHkgPSAiQ3VzdG9tZXIgU3VwcG9ydCB2cy4gSW5ub3ZhdGlvbiINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQ0KICApDQoNCmBgYA0KYGBge3J9DQpiYW5rX2F0dHJfbWF0DQpgYGANCg0KYGBge3J9DQojIGxvYWRpbmdzIGZvciBlYWNoIGF0dHJpYnV0ZSBvbiBQQzEgYW5kIFBDMg0KbG9hZF90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jMyRyb3RhdGlvblssIDE6Ml0pDQpsb2FkX3RhYmxlJGF0dHJpYnV0ZSA8LSByb3duYW1lcyhsb2FkX3RhYmxlKQ0Kcm93bmFtZXMobG9hZF90YWJsZSkgPC0gTlVMTA0KDQpsb2FkX3RhYmxlDQpgYGANCg0KYGBge3J9DQojIGJhbmsgYXR0cmlidXRlIG1lYW5zIHdlIGFscmVhZHkgaGFkOg0KYmFua19hdHRyX21hdCAgICMgcm93cyA9IGJhbmtzLCBjb2xzID0gaW5ub3ZhdGlvbiwgY3VzdG9tZXJfc3VwcG9ydCwgcmVsaWFiaWxpdHkNCg0KIyBqb2luIHdpdGggc2NvcmVzIG9uIFBDMg0KYmFua19wYzIgPC0gc2NvcmVzX2MzICU+JQ0KICBzZWxlY3QoYmFua19sYWJlbCwgUEMyKSAlPiUNCiAgbGVmdF9qb2luKA0KICAgIGJhbmtfYXR0cl9tYXQgJT4lDQogICAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiYmFua19sYWJlbCIpLA0KICAgIGJ5ID0gImJhbmtfbGFiZWwiDQogICkNCg0KYmFua19wYzINCg0KYGBgDQpgYGB7cn0NCmJhbmtfcGMyIDwtIHNjb3Jlc19jMyAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsIFBDMikgJT4lDQogIGxlZnRfam9pbigNCiAgICBiYW5rX2F0dHJfbWF0ICU+JQ0KICAgICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImJhbmtfbGFiZWwiKSwNCiAgICBieSA9ICJiYW5rX2xhYmVsIg0KICApDQoNCmJhbmtfcGMyDQpgYGANCg0KYGBge3J9DQojIGxvYWRfdGFibGU6IGNvbHVtbnMgUEMxLCBQQzIsIGF0dHJpYnV0ZSAoaW5ub3ZhdGlvbiwgY3VzdG9tZXJfc3VwcG9ydCwgcmVsaWFiaWxpdHkpDQpsb2FkX3RhYmxlDQoNCiMgMSkgcHV0IFBDMiBsb2FkaW5ncyBpbnRvIGEgbmFtZWQgdmVjdG9yDQpwYzJfbG9hZCA8LSBsb2FkX3RhYmxlJFBDMg0KbmFtZXMocGMyX2xvYWQpIDwtIGxvYWRfdGFibGUkYXR0cmlidXRlDQoNCiMgMikgY29tcHV0ZSBjb250cmlidXRpb24gc2NvcmVzOiBhdHRyaWJ1dGVfbWVhbiAqIFBDMiBsb2FkaW5nDQpjb250cmliX3BjMiA8LSBiYW5rX3BjMiAlPiUNCiAgbXV0YXRlKA0KICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCA9IGN1c3RvbWVyX3N1cHBvcnQgKiBwYzJfbG9hZFsiY3VzdG9tZXJfc3VwcG9ydCJdLA0KICAgIGNvbnRyaWJfaW5ub3ZhdGlvbiAgICAgICA9IGlubm92YXRpb24gICAgICAgKiBwYzJfbG9hZFsiaW5ub3ZhdGlvbiJdLA0KICAgIGNvbnRyaWJfcmVsaWFiaWxpdHkgICAgICA9IHJlbGlhYmlsaXR5ICAgICAgKiBwYzJfbG9hZFsicmVsaWFiaWxpdHkiXQ0KICApDQoNCmNvbnRyaWJfcGMyDQoNCmBgYA0KYGBge3J9DQpjb250cmliX3BjMl9sb25nIDwtIGNvbnRyaWJfcGMyICU+JQ0KICBzZWxlY3QoYmFua19sYWJlbCwNCiAgICAgICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCwNCiAgICAgICAgIGNvbnRyaWJfaW5ub3ZhdGlvbiwNCiAgICAgICAgIGNvbnRyaWJfcmVsaWFiaWxpdHkpICU+JQ0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBzdGFydHNfd2l0aCgiY29udHJpYl8iKSwNCiAgICBuYW1lc190byA9ICJhdHRyaWJ1dGUiLA0KICAgIHZhbHVlc190byA9ICJjb250cmlidXRpb24iDQogICkgJT4lDQogIG11dGF0ZShhdHRyaWJ1dGUgPSBnc3ViKCJjb250cmliXyIsICIiLCBhdHRyaWJ1dGUpKQ0KDQpjb250cmliX3BjMl9sb25nDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGNvbnRyaWJfcGMyX2xvbmcsDQogICAgICAgYWVzKHggPSBhdHRyaWJ1dGUsIHkgPSBjb250cmlidXRpb24sIGZpbGwgPSBhdHRyaWJ1dGUpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgZmFjZXRfd3JhcCh+IGJhbmtfbGFiZWwpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJBcHByb3hpbWF0ZSBhdHRyaWJ1dGUgY29udHJpYnV0aW9ucyB0byBEaW1lbnNpb24gMiAoY2x1c3RlciAzKSIsDQogICAgeCA9ICJBdHRyaWJ1dGUiLA0KICAgIHkgPSAiQ29udHJpYnV0aW9uIHRvIERpbTIiDQogICkNCmBgYA0KYGBge3J9DQpsb2FkX3RhYmxlMyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jMyRyb3RhdGlvblssIDE6Ml0pDQpsb2FkX3RhYmxlMyRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZF90YWJsZTMpDQpyb3duYW1lcyhsb2FkX3RhYmxlMykgPC0gTlVMTA0KDQpsb2FkX3RhYmxlMw0KDQpgYGANCg0KIyMgQ2x1c3RlciA1DQpgYGB7cn0NCiMjIENsdXN0ZXIgNTogYmFuayB4IGF0dHJpYnV0ZSBtYXRyaXggLS0tLQ0KDQpjbHVzdGVyNSA8LSBkYXRhX2NsdXN0ZXIgJT4lDQogIGZpbHRlcihjbHVzdGVyID09ICJBSS1lbnRodXNpYXN0aWMgZ3VpZGFuY2Ugc2Vla2VycyIpICAgIyBjbHVzdGVyIDUgbGFiZWwNCg0KY2x1c3RlcjVfcGVyY2VwdCA8LSBjbHVzdGVyNSAlPiUNCiAgc2VsZWN0KGFsbF9vZihwZXJjZXB0X3ZhcnMpKSAlPiUNCiAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIGFzLm51bWVyaWMpKQ0KDQptZWFuc19jNSA8LSBjbHVzdGVyNV9wZXJjZXB0ICU+JQ0KICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBtZWFuKC54LCBuYS5ybSA9IFRSVUUpKSkNCg0KbWVhbnNfYzVfbG9uZyA8LSBtZWFuc19jNSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAibWVhbl9zY29yZSIpICU+JQ0KICBsZWZ0X2pvaW4ocW1ldGEsIGJ5ID0gInZhcmlhYmxlIikNCg0KYmFua19hdHRyX21hdDUgPC0gbWVhbnNfYzVfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoYmFua19sYWJlbCwgYXR0cmlidXRlKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fc2NvcmUgPSBtZWFuKG1lYW5fc2NvcmUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUNCiAgcGl2b3Rfd2lkZXIoDQogICAgaWRfY29scyA9IGJhbmtfbGFiZWwsDQogICAgbmFtZXNfZnJvbSA9IGF0dHJpYnV0ZSwNCiAgICB2YWx1ZXNfZnJvbSA9IG1lYW5fc2NvcmUNCiAgKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQoNCnJvd25hbWVzKGJhbmtfYXR0cl9tYXQ1KSA8LSBiYW5rX2F0dHJfbWF0NSRiYW5rX2xhYmVsDQpiYW5rX2F0dHJfbWF0NSRiYW5rX2xhYmVsIDwtIE5VTEwNCg0KYGBgDQoNCmBgYHtyfQ0KIyMgUENBIGZvciBiYW5rcyDigJMgY2x1c3RlciA1IC0tLS0NCg0KcGNhX2JhbmtzX2M1IDwtIHByY29tcChiYW5rX2F0dHJfbWF0NSwgc2NhbGUuID0gVFJVRSkNCg0Kc2NvcmVzX2M1IDwtIGFzLmRhdGEuZnJhbWUocGNhX2JhbmtzX2M1JHhbLCAxOjJdKQ0Kc2NvcmVzX2M1JGJhbmtfbGFiZWwgPC0gcm93bmFtZXMoc2NvcmVzX2M1KQ0KDQpsb2FkaW5nc19jNSA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jNSRyb3RhdGlvblssIDE6Ml0pDQpsb2FkaW5nc19jNSRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZGluZ3NfYzUpDQoNCmFycm93X3NjYWxlIDwtIDEuNQ0KbG9hZGluZ3NfYzUgPC0gbG9hZGluZ3NfYzUgJT4lDQogIG11dGF0ZShQQzEgPSBQQzEgKiBhcnJvd19zY2FsZSwNCiAgICAgICAgIFBDMiA9IFBDMiAqIGFycm93X3NjYWxlKQ0KDQojIyBQbG90OiBwZXJjZXB0dWFsIG1hcCBmb3IgY2x1c3RlciA1IC0tLS0NCg0KZ2dwbG90KCkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBzY29yZXNfYzUsDQogICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIpLA0KICAgICAgICAgICAgIHNpemUgPSAyLjgsIGNvbG91ciA9ICJibGFjayIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBzY29yZXNfYzUsDQogICAgICAgICAgICBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBiYW5rX2xhYmVsKSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNywgc2l6ZSA9IDMuMikgKw0KICBnZW9tX3NlZ21lbnQoZGF0YSA9IGxvYWRpbmdzX2M1LA0KICAgICAgICAgICAgICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IFBDMSwgeWVuZCA9IFBDMiksDQogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksDQogICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTQwIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGxvYWRpbmdzX2M1LA0KICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gYXR0cmlidXRlKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMC41LCB2anVzdCA9IC0wLjQsIGNvbG91ciA9ICJncmV5NDAiLCBzaXplID0gMykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiZ3JleTc1IikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvdXIgPSAiZ3JleTc1IikgKw0KICBjb29yZF9lcXVhbCh4bGltID0gYyhtaW4oc2NvcmVzX2M1JFBDMSkgLSAwLjgsIG1heChzY29yZXNfYzUkUEMxKSArIDAuOCksDQogICAgICAgICAgICAgIHlsaW0gPSBjKG1pbihzY29yZXNfYzUkUEMyKSAtIDAuOCwgbWF4KHNjb3Jlc19jNSRQQzIpICsgMC44KSwNCiAgICAgICAgICAgICAgZXhwYW5kID0gVFJVRSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlcmNlcHR1YWwgTWFwIG9mIEJhbmtzIOKAkyBDbHVzdGVyIDUiLA0KICAgIHggPSAiT3ZlcmFsbCBEaWdpdGFsIEJhbmtpbmcgUGVyZm9ybWFuY2UiLA0KICAgIHkgPSAiQ3VzdG9tZXIgU3VwcG9ydCB2cy4gUmVsYWliaWxpdHkiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkNCiAgKQ0KDQpgYGANCmBgYHtyfQ0KIyMgTG9hZGluZ3MgdGFibGUgZm9yIGNsdXN0ZXIgNSAtLS0tDQpsb2FkX3RhYmxlNSA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jNSRyb3RhdGlvblssIDE6Ml0pDQpsb2FkX3RhYmxlNSRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZF90YWJsZTUpDQpyb3duYW1lcyhsb2FkX3RhYmxlNSkgPC0gTlVMTA0KDQojIFBDMiBsb2FkaW5ncyBhcyBuYW1lZCB2ZWN0b3INCnBjMl9sb2FkNSA8LSBsb2FkX3RhYmxlNSRQQzINCm5hbWVzKHBjMl9sb2FkNSkgPC0gbG9hZF90YWJsZTUkYXR0cmlidXRlDQoNCiMgam9pbiBQQzIgc2NvcmVzIHdpdGggYXR0cmlidXRlIG1lYW5zDQpiYW5rX3BjMl81IDwtIHNjb3Jlc19jNSAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsIFBDMikgJT4lDQogIGxlZnRfam9pbigNCiAgICBiYW5rX2F0dHJfbWF0NSAlPiUgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImJhbmtfbGFiZWwiKSwNCiAgICBieSA9ICJiYW5rX2xhYmVsIg0KICApDQoNCiMgY29udHJpYnV0aW9uIHNjb3Jlcw0KY29udHJpYl9wYzJfNSA8LSBiYW5rX3BjMl81ICU+JQ0KICBtdXRhdGUoDQogICAgY29udHJpYl9jdXN0b21lcl9zdXBwb3J0ID0gY3VzdG9tZXJfc3VwcG9ydCAqIHBjMl9sb2FkNVsiY3VzdG9tZXJfc3VwcG9ydCJdLA0KICAgIGNvbnRyaWJfaW5ub3ZhdGlvbiAgICAgICA9IGlubm92YXRpb24gICAgICAgKiBwYzJfbG9hZDVbImlubm92YXRpb24iXSwNCiAgICBjb250cmliX3JlbGlhYmlsaXR5ICAgICAgPSByZWxpYWJpbGl0eSAgICAgICogcGMyX2xvYWQ1WyJyZWxpYWJpbGl0eSJdDQogICkNCg0KY29udHJpYl9wYzJfNQ0KDQpgYGANCg0KYGBge3J9DQpjb250cmliX3BjMl81X2xvbmcgPC0gY29udHJpYl9wYzJfNSAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsDQogICAgICAgICBjb250cmliX2N1c3RvbWVyX3N1cHBvcnQsDQogICAgICAgICBjb250cmliX2lubm92YXRpb24sDQogICAgICAgICBjb250cmliX3JlbGlhYmlsaXR5KSAlPiUNCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBzdGFydHNfd2l0aCgiY29udHJpYl8iKSwNCiAgICBuYW1lc190byA9ICJhdHRyaWJ1dGUiLA0KICAgIHZhbHVlc190byA9ICJjb250cmlidXRpb24iDQogICkgJT4lDQogIG11dGF0ZShhdHRyaWJ1dGUgPSBnc3ViKCJjb250cmliXyIsICIiLCBhdHRyaWJ1dGUpKQ0KDQpnZ3Bsb3QoY29udHJpYl9wYzJfNV9sb25nLA0KICAgICAgIGFlcyh4ID0gYXR0cmlidXRlLCB5ID0gY29udHJpYnV0aW9uLCBmaWxsID0gYXR0cmlidXRlKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGZhY2V0X3dyYXAofiBiYW5rX2xhYmVsKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQXBwcm94aW1hdGUgYXR0cmlidXRlIGNvbnRyaWJ1dGlvbnMgdG8gRGltZW5zaW9uIDIgKGNsdXN0ZXIgNSkiLA0KICAgIHggPSAiQXR0cmlidXRlIiwNCiAgICB5ID0gIkNvbnRyaWJ1dGlvbiB0byBEaW0yIg0KICApDQoNCmBgYA0KYGBge3J9DQpiYW5rX3BjMl81IDwtIHNjb3Jlc19jNSAlPiUNCiAgc2VsZWN0KGJhbmtfbGFiZWwsIFBDMikgJT4lDQogIGxlZnRfam9pbigNCiAgICBiYW5rX2F0dHJfbWF0NSAlPiUNCiAgICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJiYW5rX2xhYmVsIiksDQogICAgYnkgPSAiYmFua19sYWJlbCINCiAgKQ0KDQpiYW5rX3BjMl81DQoNCmBgYA0KDQpgYGB7cn0NCiMgbG9hZGluZ3MgZm9yIGNsdXN0ZXIgNSAoUEMxIGFuZCBQQzIpDQpsb2FkX3RhYmxlNSA8LSBhcy5kYXRhLmZyYW1lKHBjYV9iYW5rc19jNSRyb3RhdGlvblssIDE6Ml0pDQpsb2FkX3RhYmxlNSRhdHRyaWJ1dGUgPC0gcm93bmFtZXMobG9hZF90YWJsZTUpDQpyb3duYW1lcyhsb2FkX3RhYmxlNSkgPC0gTlVMTA0KDQpsb2FkX3RhYmxlNQ0KYGBgDQpgYGB7cn0NCiMjIGxvYWRpbmdzIGZvciBjbHVzdGVyIDUgYWxyZWFkeSBpbiBsb2FkX3RhYmxlNQ0KIyBwYzJfbG9hZDU6IG5hbWVkIHZlY3RvciBvZiBQQzIgbG9hZGluZ3MNCnBjMl9sb2FkNSA8LSBsb2FkX3RhYmxlNSRQQzINCm5hbWVzKHBjMl9sb2FkNSkgPC0gbG9hZF90YWJsZTUkYXR0cmlidXRlDQoNCiMjIGJhbmtfcGMyXzUgYWxyZWFkeSBjcmVhdGVkIGxpa2UgdGhpczoNCiMgYmFua19wYzJfNSA8LSBzY29yZXNfYzUgJT4lDQojICAgc2VsZWN0KGJhbmtfbGFiZWwsIFBDMikgJT4lDQojICAgbGVmdF9qb2luKA0KIyAgICAgYmFua19hdHRyX21hdDUgJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJiYW5rX2xhYmVsIiksDQojICAgICBieSA9ICJiYW5rX2xhYmVsIg0KIyAgICkNCg0KY29udHJpYl9wYzJfNSA8LSBiYW5rX3BjMl81ICU+JQ0KICBtdXRhdGUoDQogICAgY29udHJpYl9jdXN0b21lcl9zdXBwb3J0ID0gY3VzdG9tZXJfc3VwcG9ydCAqIHBjMl9sb2FkNVsiY3VzdG9tZXJfc3VwcG9ydCJdLA0KICAgIGNvbnRyaWJfaW5ub3ZhdGlvbiAgICAgICA9IGlubm92YXRpb24gICAgICAgKiBwYzJfbG9hZDVbImlubm92YXRpb24iXSwNCiAgICBjb250cmliX3JlbGlhYmlsaXR5ICAgICAgPSByZWxpYWJpbGl0eSAgICAgICogcGMyX2xvYWQ1WyJyZWxpYWJpbGl0eSJdDQogICkNCg0KY29udHJpYl9wYzJfNQ0KDQpgYGANCg0KIyMgQ2x1c3RlciAyDQpgYGB7cn0NCiMjIENsdXN0ZXIgMjogYmFuayB4IGF0dHJpYnV0ZSBtYXRyaXggLS0tLQ0KDQpjbHVzdGVyMiA8LSBkYXRhX2NsdXN0ZXIgJT4lDQogIGZpbHRlcihjbHVzdGVyID09ICJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIikgICAjIGNsdXN0ZXIgMiBsYWJlbA0KDQpjbHVzdGVyMl9wZXJjZXB0IDwtIGNsdXN0ZXIyICU+JQ0KICBzZWxlY3QoYWxsX29mKHBlcmNlcHRfdmFycykpICU+JQ0KICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgYXMubnVtZXJpYykpDQoNCm1lYW5zX2MyIDwtIGNsdXN0ZXIyX3BlcmNlcHQgJT4lDQogIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+IG1lYW4oLngsIG5hLnJtID0gVFJVRSkpKQ0KDQptZWFuc19jMl9sb25nIDwtIG1lYW5zX2MyICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJtZWFuX3Njb3JlIikgJT4lDQogIGxlZnRfam9pbihxbWV0YSwgYnkgPSAidmFyaWFibGUiKQ0KDQpiYW5rX2F0dHJfbWF0MiA8LSBtZWFuc19jMl9sb25nICU+JQ0KICBncm91cF9ieShiYW5rX2xhYmVsLCBhdHRyaWJ1dGUpICU+JQ0KICBzdW1tYXJpc2UobWVhbl9zY29yZSA9IG1lYW4obWVhbl9zY29yZSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQ0KICBwaXZvdF93aWRlcigNCiAgICBpZF9jb2xzID0gYmFua19sYWJlbCwNCiAgICBuYW1lc19mcm9tID0gYXR0cmlidXRlLA0KICAgIHZhbHVlc19mcm9tID0gbWVhbl9zY29yZQ0KICApICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkNCg0Kcm93bmFtZXMoYmFua19hdHRyX21hdDIpIDwtIGJhbmtfYXR0cl9tYXQyJGJhbmtfbGFiZWwNCmJhbmtfYXR0cl9tYXQyJGJhbmtfbGFiZWwgPC0gTlVMTA0KDQpgYGANCg0KYGBge3J9DQojIyBQQ0EgZm9yIGJhbmtzIOKAkyBjbHVzdGVyIDIgLS0tLQ0KDQpwY2FfYmFua3NfYzIgPC0gcHJjb21wKGJhbmtfYXR0cl9tYXQyLCBzY2FsZS4gPSBUUlVFKQ0KDQpzY29yZXNfYzIgPC0gYXMuZGF0YS5mcmFtZShwY2FfYmFua3NfYzIkeFssIDE6Ml0pDQpzY29yZXNfYzIkYmFua19sYWJlbCA8LSByb3duYW1lcyhzY29yZXNfYzIpDQoNCmxvYWRpbmdzX2MyIDwtIGFzLmRhdGEuZnJhbWUocGNhX2JhbmtzX2MyJHJvdGF0aW9uWywgMToyXSkNCmxvYWRpbmdzX2MyJGF0dHJpYnV0ZSA8LSByb3duYW1lcyhsb2FkaW5nc19jMikNCg0KYXJyb3dfc2NhbGUgPC0gMS41DQpsb2FkaW5nc19jMiA8LSBsb2FkaW5nc19jMiAlPiUNCiAgbXV0YXRlKFBDMSA9IFBDMSAqIGFycm93X3NjYWxlLA0KICAgICAgICAgUEMyID0gUEMyICogYXJyb3dfc2NhbGUpDQoNCiMjIFBsb3Q6IHBlcmNlcHR1YWwgbWFwIGZvciBjbHVzdGVyIDIgLS0tLQ0KDQpnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IHNjb3Jlc19jMiwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMSwgeSA9IFBDMiksDQogICAgICAgICAgICAgc2l6ZSA9IDIuOCwgY29sb3VyID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IHNjb3Jlc19jMiwNCiAgICAgICAgICAgIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGJhbmtfbGFiZWwpLA0KICAgICAgICAgICAgdmp1c3QgPSAtMC43LCBzaXplID0gMy4yKSArDQogIGdlb21fc2VnbWVudChkYXRhID0gbG9hZGluZ3NfYzIsDQogICAgICAgICAgICAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gUEMxLCB5ZW5kID0gUEMyKSwNCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwNCiAgICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NDAiKSArDQogIGdlb21fdGV4dChkYXRhID0gbG9hZGluZ3NfYzIsDQogICAgICAgICAgICBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBhdHRyaWJ1dGUpLA0KICAgICAgICAgICAgaGp1c3QgPSAwLjUsIHZqdXN0ID0gLTAuNCwgY29sb3VyID0gImdyZXk0MCIsIHNpemUgPSAzKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG91ciA9ICJncmV5NzUiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG91ciA9ICJncmV5NzUiKSArDQogIGNvb3JkX2VxdWFsKHhsaW0gPSBjKG1pbihzY29yZXNfYzIkUEMxKSAtIDAuOCwgbWF4KHNjb3Jlc19jMiRQQzEpICsgMC44KSwNCiAgICAgICAgICAgICAgeWxpbSA9IGMobWluKHNjb3Jlc19jMiRQQzIpIC0gMC44LCBtYXgoc2NvcmVzX2MyJFBDMikgKyAwLjgpLA0KICAgICAgICAgICAgICBleHBhbmQgPSBUUlVFKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUGVyY2VwdHVhbCBNYXAgb2YgQmFua3Mg4oCTIENsdXN0ZXIgMiIsDQogICAgeCA9ICJPdmVyYWxsIERpZ2l0YWwgQmFua2luZyBQZXJmb3JtYW5jZSIsDQogICAgeSA9ICJDdXN0b21lciBTdXBwb3J0IHZzLiBSZWxpYWJpbGl0eSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQ0KICApDQoNCmBgYA0KDQpgYGB7cn0NCmJhbmtfcGMyXzIgPC0gc2NvcmVzX2MyICU+JQ0KICBzZWxlY3QoYmFua19sYWJlbCwgUEMyKSAlPiUNCiAgbGVmdF9qb2luKA0KICAgIGJhbmtfYXR0cl9tYXQyICU+JQ0KICAgICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImJhbmtfbGFiZWwiKSwNCiAgICBieSA9ICJiYW5rX2xhYmVsIg0KICApDQoNCmJhbmtfcGMyXzINCg0KYGBgDQpgYGB7cn0NCmxvYWRfdGFibGUyIDwtIGFzLmRhdGEuZnJhbWUocGNhX2JhbmtzX2MyJHJvdGF0aW9uWywgMToyXSkNCmxvYWRfdGFibGUyJGF0dHJpYnV0ZSA8LSByb3duYW1lcyhsb2FkX3RhYmxlMikNCnJvd25hbWVzKGxvYWRfdGFibGUyKSA8LSBOVUxMDQoNCmxvYWRfdGFibGUyDQoNCmBgYA0KDQpgYGB7cn0NCnBjMl9sb2FkMiA8LSBsb2FkX3RhYmxlMiRQQzINCm5hbWVzKHBjMl9sb2FkMikgPC0gbG9hZF90YWJsZTIkYXR0cmlidXRlDQoNCmNvbnRyaWJfcGMyXzIgPC0gYmFua19wYzJfMiAlPiUNCiAgbXV0YXRlKA0KICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCA9IGN1c3RvbWVyX3N1cHBvcnQgKiBwYzJfbG9hZDJbImN1c3RvbWVyX3N1cHBvcnQiXSwNCiAgICBjb250cmliX2lubm92YXRpb24gICAgICAgPSBpbm5vdmF0aW9uICAgICAgICogcGMyX2xvYWQyWyJpbm5vdmF0aW9uIl0sDQogICAgY29udHJpYl9yZWxpYWJpbGl0eSAgICAgID0gcmVsaWFiaWxpdHkgICAgICAqIHBjMl9sb2FkMlsicmVsaWFiaWxpdHkiXQ0KICApDQoNCmNvbnRyaWJfcGMyXzINCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQoNCiMjIFBDMiBsb2FkaW5ncyBmb3IgY2x1c3RlciAyDQpwYzJfbG9hZDIgPC0gbG9hZF90YWJsZTIkUEMyDQpuYW1lcyhwYzJfbG9hZDIpIDwtIGxvYWRfdGFibGUyJGF0dHJpYnV0ZQ0KDQojIyBDb250cmlidXRpb24gc2NvcmVzIHRhYmxlIGZvciBjbHVzdGVyIDINCmNvbnRyaWJfcGMyXzIgPC0gYmFua19wYzJfMiAlPiUNCiAgbXV0YXRlKA0KICAgIGNvbnRyaWJfY3VzdG9tZXJfc3VwcG9ydCA9IGN1c3RvbWVyX3N1cHBvcnQgKiBwYzJfbG9hZDJbImN1c3RvbWVyX3N1cHBvcnQiXSwNCiAgICBjb250cmliX2lubm92YXRpb24gICAgICAgPSBpbm5vdmF0aW9uICAgICAgICogcGMyX2xvYWQyWyJpbm5vdmF0aW9uIl0sDQogICAgY29udHJpYl9yZWxpYWJpbGl0eSAgICAgID0gcmVsaWFiaWxpdHkgICAgICAqIHBjMl9sb2FkMlsicmVsaWFiaWxpdHkiXQ0KICApDQoNCiMjIExvbmcgZm9ybWF0IGZvciBwbG90dGluZw0KY29udHJpYl9wYzJfMl9sb25nIDwtIGNvbnRyaWJfcGMyXzIgJT4lDQogIHNlbGVjdChiYW5rX2xhYmVsLA0KICAgICAgICAgY29udHJpYl9jdXN0b21lcl9zdXBwb3J0LA0KICAgICAgICAgY29udHJpYl9pbm5vdmF0aW9uLA0KICAgICAgICAgY29udHJpYl9yZWxpYWJpbGl0eSkgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gc3RhcnRzX3dpdGgoImNvbnRyaWJfIiksDQogICAgbmFtZXNfdG8gPSAiYXR0cmlidXRlIiwNCiAgICB2YWx1ZXNfdG8gPSAiY29udHJpYnV0aW9uIg0KICApICU+JQ0KICBtdXRhdGUoYXR0cmlidXRlID0gZ3N1YigiY29udHJpYl8iLCAiIiwgYXR0cmlidXRlKSkNCg0KIyMgQmFyIHBsb3QNCmdncGxvdChjb250cmliX3BjMl8yX2xvbmcsDQogICAgICAgYWVzKHggPSBhdHRyaWJ1dGUsIHkgPSBjb250cmlidXRpb24sIGZpbGwgPSBhdHRyaWJ1dGUpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgZmFjZXRfd3JhcCh+IGJhbmtfbGFiZWwpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJBcHByb3hpbWF0ZSBhdHRyaWJ1dGUgY29udHJpYnV0aW9ucyB0byBEaW1lbnNpb24gMiDigJMgQ2x1c3RlciAyIiwNCiAgICB4ID0gIkF0dHJpYnV0ZSIsDQogICAgeSA9ICJDb250cmlidXRpb24gdG8gRGltMiINCiAgKQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkodGlkeXIpDQoNCiMgbWFrZSBzdXJlIGxvZ2ljYWwgY29tYm8gdmFycyBhcmUgbnVtZXJpYyBmb3IgdGVzdGluZw0KYmFua19ncm91cHNfdGVzdCA8LSBiYW5rX2dyb3VwcyB8Pg0KICBtdXRhdGUoDQogICAgYWNyb3NzKA0KICAgICAgYyhyZXZvbHV0X29ubHksIG5sYl9yZXZvbHV0LCBvdHBfcmV2b2x1dCwgcmV2b2x1dF9vdGhlciksDQogICAgICB+IGFzLmludGVnZXIoLikNCiAgICApDQogICkNCg0KIyBoZWxwZXI6IGNoaS1zcXVhcmUgd2l0aCBzaW11bGF0ZWQgcC12YWx1ZSBmYWxsYmFjayBpZiBleHBlY3RlZCBjb3VudHMgYXJlIHNtYWxsDQpydW5fY2x1c3Rlcl9zaWdfdGVzdCA8LSBmdW5jdGlvbihkYXRhLCB2YXJfbmFtZSkgew0KICB0YWIgPC0gdGFibGUoZGF0YSRjbHVzdGVyLCBkYXRhW1t2YXJfbmFtZV1dKQ0KDQogIGNoaSA8LSBzdXBwcmVzc1dhcm5pbmdzKGNoaXNxLnRlc3QodGFiKSkNCg0KICBpZiAoYW55KGNoaSRleHBlY3RlZCA8IDUpKSB7DQogICAgY2hpX3NpbSA8LSBjaGlzcS50ZXN0KHRhYiwgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAxMDAwMCkNCg0KICAgIHRpYmJsZSgNCiAgICAgIGdyb3VwID0gdmFyX25hbWUsDQogICAgICB0ZXN0ID0gIkNoaS1zcXVhcmUgKHNpbXVsYXRlZCBwLXZhbHVlKSIsDQogICAgICBzdGF0aXN0aWMgPSB1bm5hbWUoY2hpJHN0YXRpc3RpYyksDQogICAgICBwX3ZhbHVlID0gY2hpX3NpbSRwLnZhbHVlDQogICAgKQ0KICB9IGVsc2Ugew0KICAgIHRpYmJsZSgNCiAgICAgIGdyb3VwID0gdmFyX25hbWUsDQogICAgICB0ZXN0ID0gIkNoaS1zcXVhcmUiLA0KICAgICAgc3RhdGlzdGljID0gdW5uYW1lKGNoaSRzdGF0aXN0aWMpLA0KICAgICAgcF92YWx1ZSA9IGNoaSRwLnZhbHVlDQogICAgKQ0KICB9DQp9DQoNCiMgb3ZlcmFsbCBzaWduaWZpY2FuY2UgZm9yIGVhY2ggYmFuay1jb21ibyBhY3Jvc3MgY2x1c3RlcnMNCmNvbWJvX3NpZ25pZmljYW5jZSA8LSBiaW5kX3Jvd3MoDQogIGxhcHBseSgNCiAgICBjKCJyZXZvbHV0X29ubHkiLCAibmxiX3Jldm9sdXQiLCAib3RwX3Jldm9sdXQiLCAicmV2b2x1dF9vdGhlciIpLA0KICAgIGZ1bmN0aW9uKHgpIHJ1bl9jbHVzdGVyX3NpZ190ZXN0KGJhbmtfZ3JvdXBzX3Rlc3QsIHgpDQogICkNCikgfD4NCiAgbXV0YXRlKHBfYWRqX2JoID0gcC5hZGp1c3QocF92YWx1ZSwgbWV0aG9kID0gIkJIIikpIHw+DQogIGFycmFuZ2UocF92YWx1ZSkNCg0KY29tYm9fc2lnbmlmaWNhbmNlDQpgYGANCg0KYGBge3J9DQpwYWlyd2lzZV9jbHVzdGVyX3Byb3BzIDwtIGZ1bmN0aW9uKGRhdGEsIHZhcl9uYW1lKSB7DQogIGNvdW50cyA8LSBkYXRhIHw+DQogICAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgICBzdW1tYXJpc2UoDQogICAgICB1c2VycyA9IHN1bSguZGF0YVtbdmFyX25hbWVdXSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG4gPSBuKCksDQogICAgICAuZ3JvdXBzID0gImRyb3AiDQogICAgKQ0KDQogIHB3IDwtIHBhaXJ3aXNlLnByb3AudGVzdCgNCiAgICB4ID0gY291bnRzJHVzZXJzLA0KICAgIG4gPSBjb3VudHMkbiwNCiAgICBwLmFkanVzdC5tZXRob2QgPSAiQkgiDQogICkNCg0KICBhcy5kYXRhLmZyYW1lKGFzLnRhYmxlKHB3JHAudmFsdWUpKSB8Pg0KICAgIGZpbHRlcighaXMubmEoRnJlcSkpIHw+DQogICAgcmVuYW1lKA0KICAgICAgY2x1c3Rlcl8xID0gVmFyMSwNCiAgICAgIGNsdXN0ZXJfMiA9IFZhcjIsDQogICAgICBwX2Fkal9iaCA9IEZyZXENCiAgICApIHw+DQogICAgbXV0YXRlKGdyb3VwID0gdmFyX25hbWUsIC5iZWZvcmUgPSAxKQ0KfQ0KDQpwYWlyd2lzZV9jbHVzdGVyX3Byb3BzKGJhbmtfZ3JvdXBzX3Rlc3QsICJyZXZvbHV0X29ubHkiKQ0KcGFpcndpc2VfY2x1c3Rlcl9wcm9wcyhiYW5rX2dyb3Vwc190ZXN0LCAibmxiX3Jldm9sdXQiKQ0KcGFpcndpc2VfY2x1c3Rlcl9wcm9wcyhiYW5rX2dyb3Vwc190ZXN0LCAib3RwX3Jldm9sdXQiKQ0KcGFpcndpc2VfY2x1c3Rlcl9wcm9wcyhiYW5rX2dyb3Vwc190ZXN0LCAicmV2b2x1dF9vdGhlciIpDQpgYGANCg0KYGBge3J9DQpzZWdtZW50X3RhYiA8LSB0YWJsZShiYW5rX3NlZ21lbnRzJGNsdXN0ZXIsIGJhbmtfc2VnbWVudHMkc2VnbWVudCkNCg0Kc2VnbWVudF90ZXN0IDwtIGNoaXNxLnRlc3Qoc2VnbWVudF90YWIsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFLCBCID0gMTAwMDApDQpzZWdtZW50X3Rlc3QNCmBgYA0KDQpgYGB7cn0NCnJ1bl9zZWdtZW50X3NpZyA8LSBmdW5jdGlvbihkYXRhLCBzZWdtZW50X25hbWUpIHsNCiAgdG1wIDwtIGRhdGEgfD4NCiAgICBtdXRhdGUoaW5fc2VnbWVudCA9IGFzLmludGVnZXIoc2VnbWVudCA9PSBzZWdtZW50X25hbWUpKQ0KDQogIHJ1bl9jbHVzdGVyX3NpZ190ZXN0KHRtcCwgImluX3NlZ21lbnQiKSB8Pg0KICAgIG11dGF0ZShzZWdtZW50ID0gc2VnbWVudF9uYW1lLCAuYmVmb3JlID0gMSkgfD4NCiAgICBzZWxlY3Qoc2VnbWVudCwgZXZlcnl0aGluZygpLCAtZ3JvdXApDQp9DQoNCnNlZ21lbnRfc2lnbmlmaWNhbmNlIDwtIGJpbmRfcm93cygNCiAgcnVuX3NlZ21lbnRfc2lnKGJhbmtfc2VnbWVudHMsICJSZXZvbHV0IG9ubHkiKSwNCiAgcnVuX3NlZ21lbnRfc2lnKGJhbmtfc2VnbWVudHMsICJOTEIgKyBSZXZvbHV0IiksDQogIHJ1bl9zZWdtZW50X3NpZyhiYW5rX3NlZ21lbnRzLCAiT1RQICsgUmV2b2x1dCIpDQopIHw+DQogIG11dGF0ZShwX2Fkal9iaCA9IHAuYWRqdXN0KHBfdmFsdWUsIG1ldGhvZCA9ICJCSCIpKQ0KDQpzZWdtZW50X3NpZ25pZmljYW5jZQ0KYGBgDQoNCmBgYHtyfQ0KcGFpcndpc2Vfc2VnbWVudF9wcm9wcyA8LSBmdW5jdGlvbihkYXRhLCBzZWdtZW50X25hbWUpIHsNCiAgY291bnRzIDwtIGRhdGEgfD4NCiAgICBtdXRhdGUoaW5fc2VnbWVudCA9IGFzLmludGVnZXIoc2VnbWVudCA9PSBzZWdtZW50X25hbWUpKSB8Pg0KICAgIGdyb3VwX2J5KGNsdXN0ZXIpIHw+DQogICAgc3VtbWFyaXNlKA0KICAgICAgdXNlcnMgPSBzdW0oaW5fc2VnbWVudCwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG4gPSBuKCksDQogICAgICAuZ3JvdXBzID0gImRyb3AiDQogICAgKQ0KDQogIHB3IDwtIHBhaXJ3aXNlLnByb3AudGVzdCgNCiAgICB4ID0gY291bnRzJHVzZXJzLA0KICAgIG4gPSBjb3VudHMkbiwNCiAgICBwLmFkanVzdC5tZXRob2QgPSAiQkgiDQogICkNCg0KICBhcy5kYXRhLmZyYW1lKGFzLnRhYmxlKHB3JHAudmFsdWUpKSB8Pg0KICAgIGZpbHRlcighaXMubmEoRnJlcSkpIHw+DQogICAgcmVuYW1lKA0KICAgICAgY2x1c3Rlcl8xID0gVmFyMSwNCiAgICAgIGNsdXN0ZXJfMiA9IFZhcjIsDQogICAgICBwX2Fkal9iaCA9IEZyZXENCiAgICApIHw+DQogICAgbXV0YXRlKHNlZ21lbnQgPSBzZWdtZW50X25hbWUsIC5iZWZvcmUgPSAxKQ0KfQ0KDQpwYWlyd2lzZV9zZWdtZW50X3Byb3BzKGJhbmtfc2VnbWVudHMsICJSZXZvbHV0IG9ubHkiKQ0KcGFpcndpc2Vfc2VnbWVudF9wcm9wcyhiYW5rX3NlZ21lbnRzLCAiTkxCICsgUmV2b2x1dCIpDQpwYWlyd2lzZV9zZWdtZW50X3Byb3BzKGJhbmtfc2VnbWVudHMsICJPVFAgKyBSZXZvbHV0IikNCmBgYA0KDQpgYGB7cn0NCmNsdXN0ZXJfNV93YW50c19uZWVkcyA8LSBjbHVzdGVyX21lYW5zX3BjYTJfNV9uYW1lZCB8Pg0KICBmaWx0ZXIoY2x1c3RlciA9PSAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiKQ0KDQpjbHVzdGVyXzVfd2FudHNfbmVlZHMNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHB1cnJyKQ0KbGlicmFyeSh0aWR5cikNCg0KIyBrZWVwIG9ubHkgY2x1c3RlcnMgMiwgMywgYW5kIDUNCmJhbmtfZ3JvdXBzXzIzNSA8LSBiYW5rX2dyb3VwcyB8Pg0KICBmaWx0ZXIoY2x1c3RlciAlaW4lIGMoDQogICAgIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLA0KICAgICJGZWF0dXJlLW9yaWVudGVkIGFkb3B0ZXJzIiwNCiAgICAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiDQogICkpIHw+DQogIG11dGF0ZSgNCiAgICBjbHVzdGVyID0gZHJvcGxldmVscyhjbHVzdGVyKSwNCiAgICBhY3Jvc3MoDQogICAgICBjKHJldm9sdXRfb25seSwgbmxiX3Jldm9sdXQsIG90cF9yZXZvbHV0LCByZXZvbHV0X290aGVyKSwNCiAgICAgIH4gYXMuaW50ZWdlciguKQ0KICAgICkNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KcnVuX2NsdXN0ZXJfc2lnX3Rlc3QgPC0gZnVuY3Rpb24oZGF0YSwgdmFyX25hbWUpIHsNCiAgdGFiIDwtIHRhYmxlKGRhdGEkY2x1c3RlciwgZGF0YVtbdmFyX25hbWVdXSkNCiAgY2hpIDwtIHN1cHByZXNzV2FybmluZ3MoY2hpc3EudGVzdCh0YWIpKQ0KICANCiAgaWYgKGFueShjaGkkZXhwZWN0ZWQgPCA1KSkgew0KICAgIGNoaV9zaW0gPC0gY2hpc3EudGVzdCh0YWIsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFLCBCID0gMTAwMDApDQogICAgDQogICAgdGliYmxlKA0KICAgICAgZ3JvdXAgPSB2YXJfbmFtZSwNCiAgICAgIHRlc3QgPSAiQ2hpLXNxdWFyZSAoc2ltdWxhdGVkIHAtdmFsdWUpIiwNCiAgICAgIHN0YXRpc3RpYyA9IHVubmFtZShjaGkkc3RhdGlzdGljKSwNCiAgICAgIHBfdmFsdWUgPSBjaGlfc2ltJHAudmFsdWUNCiAgICApDQogIH0gZWxzZSB7DQogICAgdGliYmxlKA0KICAgICAgZ3JvdXAgPSB2YXJfbmFtZSwNCiAgICAgIHRlc3QgPSAiQ2hpLXNxdWFyZSIsDQogICAgICBzdGF0aXN0aWMgPSB1bm5hbWUoY2hpJHN0YXRpc3RpYyksDQogICAgICBwX3ZhbHVlID0gY2hpJHAudmFsdWUNCiAgICApDQogIH0NCn0NCg0Kb3ZlcmFsbF9zaWdfMjM1IDwtIGJpbmRfcm93cygNCiAgcnVuX2NsdXN0ZXJfc2lnX3Rlc3QoYmFua19ncm91cHNfMjM1LCAicmV2b2x1dF9vbmx5IiksDQogIHJ1bl9jbHVzdGVyX3NpZ190ZXN0KGJhbmtfZ3JvdXBzXzIzNSwgIm5sYl9yZXZvbHV0IiksDQogIHJ1bl9jbHVzdGVyX3NpZ190ZXN0KGJhbmtfZ3JvdXBzXzIzNSwgIm90cF9yZXZvbHV0IiksDQogIHJ1bl9jbHVzdGVyX3NpZ190ZXN0KGJhbmtfZ3JvdXBzXzIzNSwgInJldm9sdXRfb3RoZXIiKQ0KKSB8Pg0KICBtdXRhdGUocF9hZGpfYmggPSBwLmFkanVzdChwX3ZhbHVlLCBtZXRob2QgPSAiQkgiKSkgfD4NCiAgYXJyYW5nZShwX3ZhbHVlKQ0KDQpvdmVyYWxsX3NpZ18yMzUNCmBgYA0KDQpgYGB7cn0NCnJ1bl9wYWlyX3Rlc3QgPC0gZnVuY3Rpb24oZGF0YSwgdmFyX25hbWUsIGNsMSwgY2wyKSB7DQogIHRtcCA8LSBkYXRhIHw+DQogICAgZmlsdGVyKGNsdXN0ZXIgJWluJSBjKGNsMSwgY2wyKSkgfD4NCiAgICBtdXRhdGUoY2x1c3RlciA9IGRyb3BsZXZlbHMoY2x1c3RlcikpDQogIA0KICBjb3VudHMgPC0gdG1wIHw+DQogICAgZ3JvdXBfYnkoY2x1c3RlcikgfD4NCiAgICBzdW1tYXJpc2UoDQogICAgICB1c2VycyA9IHN1bSguZGF0YVtbdmFyX25hbWVdXSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIG4gPSBuKCksDQogICAgICAuZ3JvdXBzID0gImRyb3AiDQogICAgKQ0KICANCiAgdGVzdCA8LSBwcm9wLnRlc3QoDQogICAgeCA9IGNvdW50cyR1c2VycywNCiAgICBuID0gY291bnRzJG4sDQogICAgY29ycmVjdCA9IEZBTFNFDQogICkNCiAgDQogIHRpYmJsZSgNCiAgICBncm91cCA9IHZhcl9uYW1lLA0KICAgIGNsdXN0ZXJfMSA9IGNsMSwNCiAgICBjbHVzdGVyXzIgPSBjbDIsDQogICAgdXNlcnNfMSA9IGNvdW50cyR1c2Vyc1sxXSwNCiAgICBuXzEgPSBjb3VudHMkblsxXSwNCiAgICBwY3RfMSA9IHJvdW5kKDEwMCAqIGNvdW50cyR1c2Vyc1sxXSAvIGNvdW50cyRuWzFdLCAxKSwNCiAgICB1c2Vyc18yID0gY291bnRzJHVzZXJzWzJdLA0KICAgIG5fMiA9IGNvdW50cyRuWzJdLA0KICAgIHBjdF8yID0gcm91bmQoMTAwICogY291bnRzJHVzZXJzWzJdIC8gY291bnRzJG5bMl0sIDEpLA0KICAgIHN0YXRpc3RpYyA9IHVubmFtZSh0ZXN0JHN0YXRpc3RpYyksDQogICAgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZQ0KICApDQp9DQoNCmNsdXN0ZXJfcGFpcnNfMjM1IDwtIGxpc3QoDQogIGMoIkNhdXRpb3VzIGd1aWRhbmNlIHNlZWtlcnMiLCAiRmVhdHVyZS1vcmllbnRlZCBhZG9wdGVycyIpLA0KICBjKCJDYXV0aW91cyBndWlkYW5jZSBzZWVrZXJzIiwgIkFJLWVudGh1c2lhc3RpYyBndWlkYW5jZSBzZWVrZXJzIiksDQogIGMoIkZlYXR1cmUtb3JpZW50ZWQgYWRvcHRlcnMiLCAiQUktZW50aHVzaWFzdGljIGd1aWRhbmNlIHNlZWtlcnMiKQ0KKQ0KDQpiYW5rX3ZhcnMgPC0gYygicmV2b2x1dF9vbmx5IiwgIm5sYl9yZXZvbHV0IiwgIm90cF9yZXZvbHV0IiwgInJldm9sdXRfb3RoZXIiKQ0KDQpwYWlyd2lzZV9zaWdfMjM1IDwtIG1hcF9kZnIoYmFua192YXJzLCBmdW5jdGlvbih2KSB7DQogIG1hcF9kZnIoY2x1c3Rlcl9wYWlyc18yMzUsIGZ1bmN0aW9uKHApIHsNCiAgICBydW5fcGFpcl90ZXN0KGJhbmtfZ3JvdXBzXzIzNSwgdiwgcFsxXSwgcFsyXSkNCiAgfSkNCn0pIHw+DQogIGdyb3VwX2J5KGdyb3VwKSB8Pg0KICBtdXRhdGUocF9hZGpfYmggPSBwLmFkanVzdChwX3ZhbHVlLCBtZXRob2QgPSAiQkgiKSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIGFycmFuZ2UoZ3JvdXAsIHBfdmFsdWUpDQoNCnBhaXJ3aXNlX3NpZ18yMzUNCmBgYA0KDQpgYGB7cn0NCnBhaXJ3aXNlX3NpZ18yMzUgfD4NCiAgZmlsdGVyKHBfYWRqX2JoIDwgMC4wNSkNCmBgYA0KDQpgYGB7cn0NCmJhbmtfZ3JvdXBzXzIzNSB8Pg0KICBncm91cF9ieShjbHVzdGVyKSB8Pg0KICBzdW1tYXJpc2UoDQogICAgbl9jbHVzdGVyID0gbigpLA0KICAgIHJldm9sdXRfb25seV9uID0gc3VtKHJldm9sdXRfb25seSwgbmEucm0gPSBUUlVFKSwNCiAgICByZXZvbHV0X29ubHlfcGN0ID0gcm91bmQoMTAwICogcmV2b2x1dF9vbmx5X24gLyBuX2NsdXN0ZXIsIDEpLA0KICAgIG5sYl9yZXZvbHV0X24gPSBzdW0obmxiX3Jldm9sdXQsIG5hLnJtID0gVFJVRSksDQogICAgbmxiX3Jldm9sdXRfcGN0ID0gcm91bmQoMTAwICogbmxiX3Jldm9sdXRfbiAvIG5fY2x1c3RlciwgMSksDQogICAgb3RwX3Jldm9sdXRfbiA9IHN1bShvdHBfcmV2b2x1dCwgbmEucm0gPSBUUlVFKSwNCiAgICBvdHBfcmV2b2x1dF9wY3QgPSByb3VuZCgxMDAgKiBvdHBfcmV2b2x1dF9uIC8gbl9jbHVzdGVyLCAxKSwNCiAgICByZXZvbHV0X290aGVyX24gPSBzdW0ocmV2b2x1dF9vdGhlciwgbmEucm0gPSBUUlVFKSwNCiAgICByZXZvbHV0X290aGVyX3BjdCA9IHJvdW5kKDEwMCAqIHJldm9sdXRfb3RoZXJfbiAvIG5fY2x1c3RlciwgMSkNCiAgKQ0KYGBg