1 Define functions

## Define function that recodes to numeric, but watches out to coercion to not introduce NAs
colstonumeric <- function(df){
  tryCatch({
    df_num <- as.data.frame(
      lapply(df,
             function(x) { as.numeric(as.character(x))})) 
  },warning = function(stop_on_warning) {
    message("Stoped the execution of numeric conversion: ", conditionMessage(stop_on_warning))
  }) 
}
##
## Define function that reverse codes items
ReverseCode <- function(df, tonumeric = FALSE, min = NULL, max = NULL) {
  if(tonumeric) df <- colstonumeric(df)
  df <- (max + min) - df
}
##
## Define function that scores only rows with less than 10% NAs (returns NA if all or above threshold percentage of rows are NA); can reverse code if vector of column indexes and min, max are provided.
ScoreLikert <- function(df, napercent = .1, tonumeric = FALSE, reversecols = NULL, min = NULL, max = NULL, engine = "sum") {
  reverse_list <- list(reversecols = reversecols, min = min, max = max)
  reverse_check <- !sapply(reverse_list, is.null)
  
  # Recode to numeric, but watch out to coercion to not introduce NAs
  colstonumeric <- function(df){
    tryCatch({
      df_num <- as.data.frame(
        lapply(df,
               function(x) { as.numeric(as.character(x))})) 
    },warning = function(stop_on_warning) {
      message("Stoped the execution of numeric conversion: ", conditionMessage(stop_on_warning))
    }) 
  }
  
  if(tonumeric) df <- colstonumeric(df)
  
  if(all(reverse_check)){
    df[ ,reversecols] <- (max + min) - df[ ,reversecols]
  }else if(any(reverse_check)){
    stop("Insuficient info for reversing. Please provide: ", paste(names(reverse_list)[!reverse_check], collapse = ", "))
  }
  
  if(engine == "sum") {
    return(
      ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
             NA,
             rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
      )
    )  
  }
  
  if(engine == "mean") {
    return(
      ifelse(rowMeans(is.na(df)) > ncol(df) * napercent,
             NA,
             rowMeans(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
      )       
    )
  }
  
    if(engine == "mean_na") {
      df[is.na(df)] <- 0
      rowMeans(df)
    }
}
quick_score_hist <- function(x, xlab = "X", na.rm = TRUE, cut_into_bins = TRUE) {
  if(na.rm) {x = x[!is.na(x)]}
  brx <- pretty(range(x, na.rm = TRUE), 
    n = nclass.Sturges(x), min.n = 1)
  df <- data.frame(x = x)
  if(cut_into_bins) {df <- data.frame(x = cut(x, brx, ordered_result = TRUE))}
  df %>% 
  # mutate(x = as.factor(as.character(x))) %>%
  count(x) %>%
  mutate(pct = prop.table(n),
         Percent = paste0(round(pct * 100, 2), " %")) %>% 
  ggplot(aes(x = x, y = pct, label = scales::percent(pct))) + 
     geom_bar(stat = "identity") +
     geom_text(aes(label = Percent), vjust = -0.25) +
     scale_y_continuous(labels = scales::percent) +
     ylab("Percentage %") +  xlab(xlab)    
}

2 Read survey structure

folder <- here::here("Rsyntax&data_650")
data_name <- "survey_686732_R_data_file.csv"
script_name <- "survey_686732_R_syntax_file.R"
  
# Check most recent .csv file
last_csv_file <- 
  dir(folder, pattern = ".*csv", full.names = TRUE) %>% 
  file.info() %>%
  dplyr::arrange(dplyr::desc(ctime)) %>%
  dplyr::slice(1) %>%
  row.names()
if(identical(last_csv_file, file.path(folder, data_name))) {
  cat("Most recent .csv is used.")
} else {
  cat("NOT using the most recent .csv!")
}

# -------------------------------------------------------------------------
# Read data
library(limonaid)
library(sticky)  # need this for sticky labels

df <- limonaid::ls_import_data(
  datafile = file.path(folder, data_name),
  scriptfile = file.path(folder, script_name),
  massConvertToNumeric = FALSE
)

df_compl <-
  df %>%
  filter(lastpage == 17)

# -------------------------------------------------------------------------
# Labels to factor levels levels ("label" = question text; "labels" = response options text)
# library(labelled)
# library(sjlabelled)
# sjlabelled::get_labels(df$G01Q59_SQ008, attr.only = TRUE, values = "as.prefix")
# sjlabelled::get_values(df$G01Q59_SQ008)
# sjlabelled::as_label(df$G01Q59_SQ008, prefix = TRUE, keep.labels = TRUE) 
# sjlabelled::as_character(df$G01Q59_SQ008, prefix = TRUE, keep.labels = TRUE)
# labelled::var_label(df$G01Q59_SQ008)
# labelled::to_factor(df$G01Q59_SQ008, levels = "values")

lime_label_recode <- function (x, prefix = FALSE) {
  labels <- attr(x, "labels", exact = TRUE)
  if (is.null(labels)) {
    x
  } else {
    labels <- unname(labels)
    values <- names(attr(x, "labels", exact = TRUE))
    if (prefix) {
      labels <- sprintf("[%s] %s", values, labels)
    }
    # No recoding solution preserve attributes, even with sticky
      x_rec <- c(labels, x)[match(x, c(values, x))]
    attributes(x_rec) <- attributes(x)  # reattach attributes
    x_rec
  }
}
# test_df <- cbind(df$G02Q02_SQ021, lime_label_recode(df$G02Q02_SQ021))
# lime_label_recode(df$G01Q59_SQ008)
# lime_label_recode(df$G04Q05_SQ001)

# -------------------------------------------------------------------------
# Recode using labels
# cols_to_recode <- lapply(df, function(x) {!is.null(attr(x, "labels", exact = TRUE))})
# cols_to_recode <- which(unlist(cols_to_recode))

# df_recoded <- df
# list_recoded <- lapply(df_recoded[, cols_to_recode], lime_label_recode)
# df_recoded[, cols_to_recode] <- as.data.frame(do.call(cbind, list_recoded))

# df_recoded <-
#   df %>%
#   mutate(across(all_of(cols_to_recode), lime_label_recode)) 

df_recoded <-
  df %>%
  mutate(across(everything(), lime_label_recode)) %>%   # some values have same labels: df$G01Q60_SQ006
  mutate(across(where(is.character), function(col) iconv(col, to="UTF-8")))  # encoding: df_recoded$G01Q56

3 Score 3 Questionnaires

# ------------------------------------------------------------------------------
# Define 3 scales
# ------------------------------------------------------------------------------
# ATSPPH - 10 items (likert 0-3) total sum
atspph_idx <- 184:193  # grep("G06Q13", names(df));  df[, grep("G06Q13", names(df), value = TRUE)]
atspph_labs <- unique(lapply(df[, atspph_idx], attr, "labels"))
atspph_rev <- c(2, 4, 8, 9, 10)

atspph_recode <- function(df, rev) {
  df %>%
    mutate(
      across(everything(),
        ~ case_when(
          . == "AO02" ~ 0,
          . == "AO03" ~ 1,
          . == "AO04" ~ 2,
          . == "AO05" ~ 3
        )
      )       
    ) %>%
    mutate(   # here reverse code
      across(rev,
      ~ 3 - .x 
      )
    )
}  # atspph_recode(df_compl[, atspph_idx], atspph_rev)

# FSozU - 6 items (likert 1-5) total mean
fsozu_idx <- 222:227 # grep("G12Q45", names(df)); df[, grep("G12Q45", names(df), value = TRUE)]  
fsozu_labs <- unique(lapply(df[, fsozu_idx], attr, "labels"))  

fsozu_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
        ~ case_when(
          . == "AO01" ~ 1,
          . == "AO02" ~ 2,
          . == "AO03" ~ 3,
          . == "AO04" ~ 4,
          . == "AO05" ~ 5
        )
      )       
    ) 
}  # fsozu_recode(df_compl[, fsozu_idx])

# PMHSS - 24 items (likert 1-5) subscale sum
pmhss_idx <- 228:251   # grep("G13Q46", names(df)); df[, grep("G13Q46", names(df), value = TRUE)]
pmhss_labs <- unique(lapply(df[, pmhss_idx], attr, "labels"))

pmhss_aware <- c(2, 4, 5, 6, 8, 10, 11, 12)  
pmhss_agree <- c(14, 16, 17, 18, 20, 22, 23, 24) 
pmhss_posit <- c(1, 3, 7, 9, 13, 15, 19, 21)

pmhss_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
        ~ case_when(
          . == "AO01" ~ 1,
          . == "AO02" ~ 2,
          . == "AO03" ~ 3,
          . == "AO04" ~ 4,
          . == "AO05" ~ 5
        )
      )       
    )
}  # pmhss_recode(df_compl[, pmhss_idx])

# ------------------------------------------------------------------------------
# Recode & Score
df_compl[, atspph_idx] <- atspph_recode(df_compl[, atspph_idx], atspph_rev)
df_compl[, fsozu_idx] <- fsozu_recode(df_compl[, fsozu_idx])
df_compl[, pmhss_idx] <- pmhss_recode(df_compl[, pmhss_idx])

df_compl$help_seek <- ScoreLikert(df_compl[, atspph_idx], napercent = .5, engine = "sum")
df_compl$soc_supp <- ScoreLikert(df_compl[, fsozu_idx], napercent = .5, engine = "mean")

df_compl$aware <- ScoreLikert(df_compl[, pmhss_idx][pmhss_aware], napercent = .5, engine = "sum") 
df_compl$agree <- ScoreLikert(df_compl[, pmhss_idx][pmhss_agree], napercent = .5, engine = "sum")
df_compl$posit <- ScoreLikert(df_compl[, pmhss_idx][pmhss_posit], napercent = .5, engine = "sum")

4 Some analyses on 3 Questionnaires

4.0.1 Just checks

# find_mod(df_scales)
# moderation_model_list #1,2,3,6,7,10,11,12

mod_synth <-
  moderation_model_list %>%
  purrr::pluck("Syntax") %>%
  stringr::str_match("# Regressions\\\n(.*?)\\\n\\\n#") %>%   # string between "# Regressions\n" and "\n\n#"
  as.data.frame() %>%
  dplyr::pull(2) %>% 
  stringr::str_remove_all(fixed("b0*1 + ")) 

mod_tabl <- 
  moderation_model_list %>%
  purrr::pluck("Model")

for(i in seq_len(length(mod_tabl))) {print(mod_synth[i]); print(mod_tabl[[i]])}

4.0.2 Med - just check

# find_med(df_scales)
# mediation_model_list

for(i in seq_len(length(mediation_model_list$MedEs))) {print(mediation_model_list$MedEs[i]); print(mediation_model_list$PathEs[[i]])}

–>

4.0.3 Odd stigma patterns

ggplot(df_scales, aes(aware, agree, color = posit)) +
  geom_smooth(method = "loess", formula = y ~ x, se = TRUE, alpha = 0.1, color = "red", fill = "red") +
  geom_point() +
  scale_colour_distiller(palette = "Blues", direction = 1)


df_scales %>%
  mutate(posit_cat = cut(posit,
    breaks = c(5, 10, 20, 30, 40))
  ) %>%
  ggplot(aes(aware, agree, color = posit_cat)) +
  geom_point() -> plot_stigma1
plotly::ggplotly(plot_stigma1)

ggplot(df_scales, aes(posit, agree, color = aware)) +
  geom_smooth(method = "loess", formula = y ~ x, se = TRUE, alpha = 0.1, color = "red", fill = "red") +
  geom_point() +
  scale_colour_distiller(palette = "Blues", direction = 1)


df_scales %>%
  mutate(aware_cat = cut(posit,
    breaks = c(5, 10, 20, 30, 40))
  ) %>%
  ggplot(aes(posit, agree, color = aware_cat)) +
  geom_point() -> plot_stigma2
plotly::ggplotly(plot_stigma2)

coplot(agree ~ posit | aware, overlap = 0, data = df_scales,
  panel = function(x, y, ...) {
          points(x, y, ...)
          abline(lm(y ~ x), col = "red")}
)

 Missing rows: 23, 26, 28, 29, 30, 42, 76, 80, 134, 136, 137, 138, 139, 142, 182, 185, 188, 224, 230, 237, 271, 284, 285, 333, 378, 403, 405, 408, 417, 419, 429, 431, 432, 467, 476, 579, 580, 587, 612, 613, 615, 632, 640, 653 

4.0.4 Partial correlations stigma (partial everything from everything)

psych::lowerMat(psych::partial.r(df_scales[, c("agree", "aware", "posit")]))
      agree aware posit
agree 1.00             
aware 0.57  1.00       
posit 0.03  0.39  1.00 

4.0.5 Interaction stigma

df_agree <- na.omit(df_scales[, c("agree", "sex", "age", "resid", "aware", "soc_supp", "posit")])

mod_stigma_interac <- lm(agree ~ aware * posit, data = df_agree)
interactions::interact_plot(mod_stigma_interac, pred = posit, modx = aware)

# interactions::sim_slopes(mod_stigma_interac, pred = posit, modx = aware)

4.0.6 Gender diff stigma

ggstatsplot::ggbetweenstats(df_agree, x = sex, y = agree)

ggstatsplot::ggbetweenstats(df_agree, x = sex, y = aware)

ggstatsplot::ggbetweenstats(df_agree, x = sex, y = posit)

4.0.7 Silly model that works smh (0 m, 1 fem)

df_scales %>% 
  mutate(sex = as.numeric(as.factor(sex)) - 1) %>% 
  psych::mediate(posit ~ sex + aware:agree + (aware), data = .)

Mediation/Moderation Analysis 
Call: psych::mediate(y = posit ~ sex + aware:agree + (aware), data = .)

The DV (Y) was  posit . The IV (X) was  sex agree aware*agree . The mediating variable(s) =  aware .

Total effect(c) of  sex  on  posit  =  -2.35   S.E. =  0.5  t  =  -4.71  df=  653   with p =  0.0000031
Direct effect (c') of  sex  on  posit  removing  aware  =  -1.66   S.E. =  0.49  t  =  -3.42  df=  652   with p =  0.00067
Indirect effect (ab) of  sex  on  posit  through  aware   =  -0.69 
Mean bootstrapped indirect effect =  -0.68  with standard error =  0.18  Lower CI =  -1.06    Upper CI =  -0.35

Total effect(c) of  agree  on  posit  =  0.33   S.E. =  0.04  t  =  8.85  df=  653   with p =  0.0000000000000000082
Direct effect (c') of  agree  on  posit  removing  aware  =  0.09   S.E. =  0.05  t  =  1.91  df=  652   with p =  0.056
Indirect effect (ab) of  agree  on  posit  through  aware   =  0.24 
Mean bootstrapped indirect effect =  0.24  with standard error =  0.04  Lower CI =  0.16    Upper CI =  0.32

Total effect(c) of  aware*agree  on  posit  =  -0.03   S.E. =  0  t  =  -6.89  df=  653   with p =  0.000000000013
Direct effect (c') of  aware*agree  on  posit  removing  aware  =  -0.02   S.E. =  0  t  =  -3.6  df=  652   with p =  0.00034
Indirect effect (ab) of  aware*agree  on  posit  through  aware   =  -0.01 
Mean bootstrapped indirect effect =  -0.01  with standard error =  0  Lower CI =  -0.02    Upper CI =  -0.01
R = 0.52 R2 = 0.27   F = 59.98 on 4 and 652 DF   p-value:  0.00000000000000000000000000000000000000000000000000213 

 To see the longer output, specify short = FALSE in the print statement or ask for the summary

# psych::mediate(agree ~ posit + (aware), data = df_scales) # silly but works
# psych::mediate(agree ~ posit * aware, data = df_scales)

4.0.8 Reg step - everything about stigma is wacky

mod_agree <- lm(agree ~ sex + age + resid + aware + soc_supp, data = df_agree)
best_mod_agree <- step(mod_agree, scope = help_seek ~ .^2, direction = "both", data = mod_agree$model, trace = 0) # BIC with k = log(nrow(mod_agree$model))
summary(best_mod_agree)

Call:
lm(formula = agree ~ sex + aware + soc_supp + sex:aware, data = df_agree)

Residuals:
     Min       1Q   Median       3Q      Max 
-22.8090  -2.9789   0.4495   3.1011  15.5731 

Coefficients:
                  Estimate Std. Error t value             Pr(>|t|)    
(Intercept)        6.81884    1.14539   5.953        0.00000000446 ***
sexMasculin       -3.60276    1.32908  -2.711               0.0069 ** 
aware              0.48422    0.03922  12.346 < 0.0000000000000002 ***
soc_supp           0.34104    0.18238   1.870               0.0620 .  
sexMasculin:aware  0.23489    0.05816   4.039        0.00006065122 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.129 on 604 degrees of freedom
Multiple R-squared:  0.4256,    Adjusted R-squared:  0.4218 
F-statistic: 111.9 on 4 and 604 DF,  p-value: < 0.00000000000000022
df_helpseek <- na.omit(df_scales[, c("help_seek", "sex", "age", "agree", "aware", "soc_supp", "agree", "posit")])
mod_helpseek <- lm(help_seek ~ sex + age + agree  + aware + soc_supp, data = df_helpseek)
best_mod_helpseek <- step(mod_helpseek, scope = help_seek ~ .^2, direction = "both", data = mod_helpseek$model, trace = 0) # BIC with k = log(nrow(mod_helpseek$model))
summary(best_mod_helpseek)


summary(lm(help_seek ~ sex + age * aware, data = df_scales)) 

4.1 Demographics

demo_sex <- 
  df_scales %>% 
  mutate(sex = as.factor(as.character(sex))) %>%
  group_by(sex) %>%
  dplyr::summarise(counts = n()) %>%
  mutate(prop = round(counts*100/sum(counts), 1),
         lab.ypos = cumsum(prop) - .5*prop,
         Percent = paste0(prop, " %")) 
demo_sex

demo_sex %>%
  ggpubr::ggpie(x = "prop", label = "Percent",
                fill = "sex", color = "white", 
                lab.pos = "in", lab.font = list(color = "white"),
                palette = "grey")

demo_resid <- 
  df_scales %>% 
  mutate(sex = as.factor(as.character(resid))) %>%
  group_by(resid) %>%
  dplyr::summarise(counts = n()) %>%
  mutate(prop = round(counts*100/sum(counts), 1),
         lab.ypos = cumsum(prop) - .5*prop,
         Percent = paste0(prop, " %")) 
demo_resid

demo_resid %>%
  ggpubr::ggpie(x = "prop", label = "Percent",
                fill = "resid", color = "white", 
                lab.pos = "in", lab.font = list(color = "white"),
                palette = "grey")

demo_residsex <- 
  df_scales %>% 
  mutate(sex = as.factor(as.character(sex))) %>%
  mutate(resid = as.factor(as.character(resid))) %>%
  dplyr::count(resid, sex, .drop = FALSE) %>%         # Group by, then count number in each group (dont drop 0 counts)
  mutate(pct = prop.table(n),                            # Calculate percent within each var
         Percent = paste0(round(pct * 100, 2), " %"))
demo_residsex

df_scales %>% 
  mutate(sex = as.factor(as.character(sex))) %>%
  mutate(resid = as.factor(as.character(resid))) %>%
  ggstatsplot::grouped_ggpiestats(
    x = sex,
    grouping.var = resid,
    package = "RColorBrewer",
    palette = "Greys",
    bf.message = FALSE,
    ggplot.component = list(scale_fill_grey())
  )

demo_age <- 
  df_scales %>% 
  mutate(age = as.factor(as.character(age))) %>%
  count(age) %>%
  mutate(pct = prop.table(n),
         Percent = paste0(round(pct * 100, 2), " %"))
demo_age

demo_age %>%
  ggplot(aes(x = age, y = pct, label = scales::percent(pct))) + 
     geom_bar(stat = "identity") +
     geom_text(aes(label = Percent), vjust = -0.25) +
     scale_y_continuous(labels = scales::percent) +
     ylab("Percentage %") +  xlab("")  

NA
demo_agesex <-
  df_scales %>% 
  mutate(sex = as.factor(as.character(sex))) %>%
  mutate(age = as.factor(as.character(age))) %>%
  dplyr::count(age, sex, .drop = FALSE) %>%         # Group by, then count number in each group (dont drop 0 counts)
  mutate(pct = prop.table(n),                            # Calculate percent within each var
         Percent = paste0(round(pct * 100, 2), " %"))
demo_agesex

demo_agesex %>%     
  ggplot(aes(x = age, y = pct, fill = sex, label = scales::percent(pct))) + 
      geom_col(position = position_dodge(preserve = "single"), stat = "identity",) +    # Don't drop zero count
      geom_text(position = position_dodge(width = .9),      # move to center of bars
                vjust = -0.5,                               # nudge above top of bar
                size = 3) + 
      scale_y_continuous(labels = scales::percent) +
      ggtitle("") +
      xlab("Varsta") + ylab("Percentage %") + 
      guides(fill = guide_legend(title = "Gen", ncol = 1)) + 
      scale_fill_grey(start = 0.8, end = 0.2, na.value = "red", aesthetics = "fill") +
      theme(legend.position = "right", legend.direction = "vertical", 
            legend.justification = c(0, 1), panel.border = element_rect(fill = NA, colour = "black"))

4.2 Mental Health scales scoring

# ------------------------------------------------------------------------------
# Mental Health scales
# ------------------------------------------------------------------------------

# Screening  DSM-5-TR 11-17 (22 items likert 0-4; 3 items 1/0; 1 item 1/0)
# https://www.psychiatry.org/getmedia/9352851c-d69f-411a-8933-3212e8c29063/APA-DSM5TR-Level1MeasureChildAge11To17.pdf
screen_1_idx <- 59:80 # grep("G02Q02", names(df)); df[, grep("G02Q02", names(df), value = TRUE)]  
screen_1_labs <- unique(lapply(df[, screen_1_idx], attr, "labels"))  
screen_2_idx <- 81:84 # grep("G02Q47|G02Q48", names(df)); df[, grep("G02Q47|G02Q48", names(df), value = TRUE)];   
screen_2_labs <- unique(lapply(df[, screen_2_idx], attr, "labels"))   # 84 is suicide item

# df[, screen_1_idx] %>% map(~ attr(.x, "label"))  # get item text

screen_1_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
             ~ case_when(
               . == "AO01" ~ 0,
               . == "AO02" ~ 1,
               . == "AO03" ~ 2,
               . == "AO04" ~ 3,
               . == "AO05" ~ 4
             )
      )       
    ) 
}  # screen_1_recode(df_compl[, screen_1_idx])

screen_2_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
             ~ case_when(
               . == "AO01" ~ 1,
               . == "AO02" ~ 0
             )
      )       
    ) 
}  # screen_2_recode(df_compl[, screen_2_idx])



# ------------------------------------------------------------------------------
# ADHD - 8 items (likert 5-1) total sum;
adhd_idx <- 114:120 # grep("G03Q03", names(df)); df[, grep("G03Q03", names(df), value = TRUE)]  
adhd_labs <- unique(lapply(df[, adhd_idx], attr, "labels"))  

adhd_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
             ~ case_when(
               . == "AO01" ~ 5,
               . == "AO02" ~ 4,
               . == "AO03" ~ 3,
               . == "AO04" ~ 2,
               . == "AO05" ~ 1
             )
      )       
    ) 
}  # adhd_recode(df_compl[, adhd_idx])

# ------------------------------------------------------------------------------
# Depresie (PHQ-9) – v. versiunea modificata pentru adolescenți (likert 0-3) total sum; cutoff 11
# https://www.childrenshospital.org/sites/default/files/2022-03/PHQ%20Form.pdf
phq_idx <- 85:94 # grep("G09Q39", names(df)); df[, grep("G09Q39", names(df), value = TRUE)]  
phq_labs <- unique(lapply(df[, phq_idx], attr, "labels"))  

phq_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
             ~ case_when(
               . == "AO02" ~ 0,
               . == "AO03" ~ 1,
               . == "AO04" ~ 2,
               . == "AO05" ~ 3
             )
      )       
    ) 
}  # phq_recode(df_compl[, phq_idx])

# ------------------------------------------------------------------------------
# Anxietate (GAD-7) (likert 0-3) total sum; cutoff 10
gad_idx <- 96:102 # grep("G10Q41", names(df)); df[, grep("G10Q41", names(df), value = TRUE)]
gad_labs <- unique(lapply(df[, gad_idx], attr, "labels"))  

gad_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
             ~ case_when(
               . == "AO02" ~ 0,
               . == "AO03" ~ 1,
               . == "AO04" ~ 2,
               . == "AO05" ~ 3
             )
      )       
    ) 
}  # gad_recode(df_compl[, gad_idx])

# ------------------------------------------------------------------------------
# Anxietate socială SMSAD 11-17 (likert 0-4) total sum; cutoff 20
# https://www.psychiatry.org/File%20Library/Psychiatrists/Practice/DSM/APA_DSM5_Severity-Measure-For-Social-Anxiety-Disorder-Child-Age-11-to-17.pdf
smsad_idx <- 104:113 # grep("G11Q42", names(df)); df[, grep("G11Q42", names(df), value = TRUE)]; 
smsad_labs <- unique(lapply(df[, smsad_idx], attr, "labels"))  

smsad_recode <- function(df) {
  df %>%
    mutate(
      across(everything(),
             ~ case_when(
               . == "AO02" ~ 0,
               . == "AO03" ~ 1,
               . == "AO04" ~ 2,
               . == "AO05" ~ 3,
               . == "AO06" ~ 4
             )
      )       
    ) 
}  # smsad_recode(df_compl[, smsad_idx])

# ------------------------------------------------------------------------------
# Tulburări de alimentație (NEDA) (slider 0-100) total sum - also has likert items but didnt consider them here 
neda_part1_idx <- 201:205 # grep("G08Q36", names(df)); df[, grep("G08Q36", names(df), value = TRUE)]; 
neda_part1_labs <- unique(lapply(df[, neda_part1_idx], attr, "labels"))  
# --- complicated scoring

# ------------------------------------------------------------------------------
# ACE (likert ) part 1: 10 items, part 2: 9 items; total sum
ace_part1_idx <- 163:172 # grep("G04Q05", names(df)); df[, grep("G04Q05", names(df), value = TRUE)]; 
ace_part2_idx <- 174:182 # grep("G04Q07", names(df)); df[, grep("G04Q07", names(df), value = TRUE)];
ace_idx <- c(ace_part1_idx, ace_part2_idx)
ace_labs <- unique(lapply(df[, ace_idx], attr, "labels")) 




# ------------------------------------------------------------------------------
# Recode & Score
df_compl[, screen_1_idx] <- screen_1_recode(df_compl[, screen_1_idx])
df_compl[, screen_2_idx] <- screen_2_recode(df_compl[, screen_2_idx])

df_compl[, adhd_idx] <- adhd_recode(df_compl[, adhd_idx])
df_compl$adhd <- ScoreLikert(df_compl[, adhd_idx], napercent = .5, engine = "sum")

df_compl[, phq_idx] <- phq_recode(df_compl[, phq_idx])
df_compl$phq <- ScoreLikert(df_compl[, phq_idx], napercent = .5, engine = "sum")

df_compl[, gad_idx] <- gad_recode(df_compl[, gad_idx])
df_compl$gad <- ScoreLikert(df_compl[, gad_idx], napercent = .5, engine = "sum")

df_compl[, smsad_idx] <- smsad_recode(df_compl[, smsad_idx])
df_compl$smsad <- ScoreLikert(df_compl[, smsad_idx], napercent = .5, engine = "sum")

df_compl$ace_part1 <- ScoreLikert(df_compl[, ace_part1_idx], napercent = .5, engine = "sum")
df_compl$ace_part2 <- ScoreLikert(df_compl[, ace_part2_idx], napercent = .5, engine = "sum")
df_compl$ace <- ScoreLikert(df_compl[, ace_idx], napercent = .5, engine = "sum")

# df_compl$neda_part1 <- ScoreLikert(df_compl[, neda_part1_idx], napercent = .5, engine = "sum")

4.3 Mental Health descriptives

4.3.1 Screening

df[, screen_1_idx] %>%     # map(~ attr(.x, "label"))  # get item text
  setNames(
    purrr::map(., ~ attr(.x, "label")) %>% 
      str_replace("În ultimele DOUĂ.*$", "") %>%  
      str_wrap(60)
  ) %>% 
  screen_1_recode() %>% 
  mutate_all(as.factor) %>% 
  likert() %>% 
  plot() +
  theme(# text = element_text(size = 20),
        axis.text.y = element_text(size = 10),
        legend.position = "none") 


df[, screen_2_idx] %>%     # map(~ attr(.x, "label"))  # get item text
  setNames(
    purrr::map(., ~ attr(.x, "label")) %>% 
      str_replace("În ultimele DOUĂ.*$", "") %>%  
      str_wrap(60)
  ) %>% 
  screen_2_recode() %>% 
  mutate_all(as.factor) %>% 
  likert() %>% 
  plot() +
  theme(# text = element_text(size = 20),
        axis.text.y = element_text(size = 10),
        legend.position = "none") 

4.3.2 Same plot without Suicide


df[, screen_2_idx] %>%     # map(~ attr(.x, "label"))  # get item text
  select(-G02Q48) %>%  # remove the suicide item
  setNames(
    purrr::map(., ~ attr(.x, "label")) %>% 
      str_replace("În ultimele DOUĂ.*$", "") %>%  
      str_wrap(60)
  ) %>% 
  screen_2_recode() %>% 
  mutate_all(as.factor) %>% 
  likert() %>% 
  plot() +
  theme(# text = element_text(size = 20),
        axis.text.y = element_text(size = 10),
        legend.position = "none") 

4.3.3 ADHD

df_compl$adhd %>% 
  quick_score_hist("ADHD")

4.3.4 PHQ-9

df_compl$phq %>% 
  quick_score_hist(xlab = "Depresie", na.rm = TRUE) + 
  geom_vline(xintercept = "(10,12]", color = "red")  # cutoff 11

4.3.5 GAD-7

df_compl$gad %>% 
  quick_score_hist(xlab = "Depresie", na.rm = TRUE) + 
  geom_vline(xintercept = "(8,10]", color = "red")  # cutoff 10

4.3.6 SMSAD

df_compl$smsad %>% 
  quick_score_hist(xlab = "Depresie", na.rm = TRUE) + 
  geom_vline(xintercept = "(20,25]", color = "red")  # cutoff 20


5 Session Info

R version 4.3.2 (2023-10-31 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 11 x64 (build 22621)

Matrix products: default


locale:
[1] LC_COLLATE=English_United Kingdom.utf8  LC_CTYPE=English_United Kingdom.utf8    LC_MONETARY=English_United Kingdom.utf8
[4] LC_NUMERIC=C                            LC_TIME=English_United Kingdom.utf8    

time zone: Europe/Bucharest
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] likert_1.3.5       xtable_1.8-4       sticky_0.5.6.1     limonaid_0.1.5     gtsummary_1.7.2    report_0.5.7       scales_1.3.0      
 [8] ggstatsplot_0.12.5 psych_2.3.9        rio_1.0.1          conflicted_1.2.0   fs_1.6.3           papaja_0.1.2       tinylabels_0.2.4  
[15] lubridate_1.9.3    forcats_1.0.0      stringr_1.5.1      dplyr_1.1.4        purrr_1.0.2        readr_2.1.4        tidyr_1.3.0       
[22] tibble_3.2.1       ggplot2_3.5.1      tidyverse_2.0.0    pacman_0.5.1      

loaded via a namespace (and not attached):
  [1] RColorBrewer_1.1-3         rstudioapi_0.15.0          jsonlite_1.8.7             datawizard_0.13.0          correlation_0.8.6         
  [6] magrittr_2.0.3             TH.data_1.1-2              estimability_1.4.1         rmarkdown_2.25             farver_2.1.1              
 [11] vctrs_0.6.4                memoise_2.0.1              paletteer_1.6.0            base64enc_0.1-3            effectsize_0.8.9          
 [16] rstatix_0.7.2              htmltools_0.5.7            broom_1.0.5                Formula_1.2-5              sass_0.4.7                
 [21] parallelly_1.37.1          bslib_0.5.1                htmlwidgets_1.6.2          interactions_1.2.0         plyr_1.8.9                
 [26] sandwich_3.1-0             emmeans_1.9.0              plotly_4.10.4              zoo_1.8-12                 cachem_1.0.8              
 [31] gt_0.10.0                  lifecycle_1.0.4            pkgconfig_2.0.3            Matrix_1.6-5               R6_2.5.1                  
 [36] fastmap_1.1.1              future_1.33.1              BayesFactor_0.9.12-4.7     digest_0.6.33              colorspace_2.1-0          
 [41] GGally_2.2.1               furrr_0.3.1                rematch2_2.1.2             patchwork_1.3.0            rprojroot_2.0.4           
 [46] prismatic_1.1.1            Hmisc_5.1-1                crosstalk_1.2.0            ggpubr_0.6.0               labeling_0.4.3            
 [51] fansi_1.0.5                timechange_0.2.0           abind_1.4-5                httr_1.4.7                 mgcv_1.9-0                
 [56] compiler_4.3.2             here_1.0.1                 withr_3.0.2                pander_0.6.5               htmlTable_2.4.2           
 [61] backports_1.4.1            carData_3.0-5              ggstats_0.6.0              R.utils_2.12.3             ggsignif_0.6.4            
 [66] broom.mixed_0.2.9.4        MASS_7.3-60                PerformanceAnalytics_2.0.4 tools_4.3.2                foreign_0.8-85            
 [71] statsExpressions_1.6.1     nnet_7.3-19                R.oo_1.25.0                glue_1.8.0                 quadprog_1.5-8            
 [76] nlme_3.1-163               grid_4.3.2                 checkmate_2.3.1            cluster_2.1.4              reshape2_1.4.4            
 [81] generics_0.1.3             gtable_0.3.4               tzdb_0.4.0                 R.methodsS3_1.8.2          data.table_1.14.8         
 [86] hms_1.1.3                  car_3.1-2                  xml2_1.3.5                 utf8_1.2.4                 ggrepel_0.9.6             
 [91] pillar_1.9.0               splines_4.3.2              lattice_0.21-9             survival_3.5-7             tidyselect_1.2.0          
 [96] pbapply_1.7-2              knitr_1.45                 gridExtra_2.3              xfun_0.41                  stringi_1.8.1             
[101] lazyeval_0.2.2             yaml_2.3.7                 evaluate_0.23              codetools_0.2-19           cli_3.6.1                 
[106] rpart_4.1.21               parameters_0.23.0          jquerylib_0.1.4            munsell_0.5.0              Rcpp_1.0.11               
[111] globals_0.16.2             zeallot_0.1.0              coda_0.19-4                parallel_4.3.2             MatrixModels_0.5-3        
[116] ellipsis_0.3.2             bayestestR_0.15.0          listenv_0.9.1              broom.helpers_1.14.0       viridisLite_0.4.2         
[121] mvtnorm_1.2-3              xts_0.13.1                 insight_0.20.5             crayon_1.5.2               rlang_1.1.4               
[126] multcomp_1.4-25            mnormt_2.1.1               jtools_2.3.0              
 

A work by Claudiu Papasteri

 

LS0tDQp0aXRsZTogIjxicj4gU2Nob2xhcnMgd2F2ZSAxIC0gcGFydGlhbCBkYXRhIiANCnN1YnRpdGxlOiAiSW5pdGlhbCBBbmFseXNpcyINCmF1dGhvcjogIjxicj4gQ2xhdWRpdSBQYXBhc3RlcmkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlbSAlWScpYCINCm91dHB1dDogDQogICAgaHRtbF9ub3RlYm9vazoNCiAgICAgICAgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgdGhlbWU6IHNwYWNlbGFiDQogICAgICAgICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwNCiAgICAgICAgICAgIGZpZ193aWR0aDogMTANCiAgICAgICAgICAgIGZpZ19oZWlnaHQ6IDkNCiAgICAjIHBkZl9kb2N1bWVudDogDQogICAgICAgICAgICAjIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgIyB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICAjIGZvbnRzaXplOiAxMXB0DQogICAgICAgICAgICAjIGdlb21ldHJ5OiBtYXJnaW49MWluDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNw0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA2DQogICAgICAgICAgICAjIGZpZ19jYXB0aW9uOiB0cnVlDQogICAgIyBnaXRodWJfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjIGh0bWxfcHJldmlldzogZmFsc2UNCiAgICAgICAgICAgICMgZmlnX3dpZHRoOiA1DQogICAgICAgICAgICAjIGZpZ19oZWlnaHQ6IDUNCiAgICAgICAgICAgICMgZGV2OiBqcGVnDQotLS0NCg0KDQo8IS0tIFNldHVwIC0tPg0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBHZW5lcmFsIFIgb3B0aW9ucw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQpvcHRpb25zKHJlcG9zID0gYyhnZXRPcHRpb24oInJlcG9zIilbIkNSQU4iXSwgQ1JBTmV4dHJhID0gImh0dHBzOi8vbWlycm9yLmNsaWVudHZwcy5jb20vQ1JBTi8iKSkgICMgdXNlIENSQU4gYXMgZGVmYXVsdCwgc2V0IENSQU5leHRyYSB0byBOw7xybmJlcmcgbWlycm9yDQoNCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KcGFja2FnZXMgPC0gYygNCiAgInBhcGFqYSIsDQogICJoZXJlIiwgImZzIiwNCiAgImNvbmZsaWN0ZWQiLA0KICAicmlvIiwNCiAgInBzeWNoIiwgICAgICAgICAgDQogICJnZ3N0YXRzcGxvdCIsDQogICJnZ3Bsb3QyIiwgInNjYWxlcyIsDQogICJyZXBvcnQiLA0KICAiZ3RzdW1tYXJ5IiwNCiAgImxpbW9uYWlkIiwgInN0aWNreSIsDQogICJsaWtlcnQiDQogICMgLCAuLi4NCikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcywgdXBkYXRlID0gRkFMU0UpDQoNCiMgU2V0IGhlcmUgdG8gUm5vdGVib29rIGRpcmVjdG9yeQ0KaGVyZTo6c2V0X2hlcmUoKQ0KdW5sb2FkTmFtZXNwYWNlKCJoZXJlIikgICAgICAgICAgICAgICAgICAgIyBuZWVkIG5ldyBSIHNlc3Npb24gb3IgdW5sb2FkIG5hbWVzcGFjZSBmb3IgLmhlcmUgZmlsZSB0byB0YWtlIHByZWNlZGVuY2Ugb3ZlciAuUnByb2oNCm5vdGVib29rX25hbWUgPC0gZnM6OnBhdGhfZmlsZShoZXJlOjpoZXJlKCkpDQoNCiMgU29sdmUgY29uZmxpY3RzIGluIGZhdm9yIG9mIHRpZHl2ZXJzZQ0KY29uZmxpY3RlZDo6Y29uZmxpY3RfcHJlZmVyKCJmaWx0ZXIiLCB3aW5uZXIgPSAiZHBseXIiKQ0KY29uZmxpY3RlZDo6Y29uZmxpY3RfcHJlZmVyKCJzZWxlY3QiLCB3aW5uZXIgPSAiZHBseXIiKQ0KY29uZmxpY3RlZDo6Y29uZmxpY3RfcHJlZmVyKCJzbGljZSIsIHdpbm5lciA9ICJkcGx5ciIpDQpjb25mbGljdGVkOjpjb25mbGljdF9wcmVmZXIoInJlbmFtZSIsIHdpbm5lciA9ICJkcGx5ciIpDQpjb25mbGljdGVkOjpjb25mbGljdF9wcmVmZXIoImNvdW50Iiwgd2lubmVyID0gImRwbHlyIikNCmNvbmZsaWN0ZWQ6OmNvbmZsaWN0X3ByZWZlcigicmVjb2RlIiwgd2lubmVyID0gImRwbHlyIikNCmNvbmZsaWN0ZWQ6OmNvbmZsaWN0X3ByZWZlcigiZmlsbCIsIHdpbm5lciA9ICJ0aWR5ciIpDQoNCiMgU2V0IGtpbnRyIG9wdGlvbnMgaW5jbHVkaW5nIHJvb3QuZGlyIHBvaW50aW5nIHRvIHRoZSAuaGVyZSBmaWxlIGluIFJub3RlYm9vayBkaXJlY3RvcnkNCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgcm9vdC5kaXIgPSBoZXJlOjpoZXJlKCksDQogICNmaWcud2lkdGggPSA1LCBmaWcuYXNwID0gMS8zLCANCiAgY29tbWVudCA9ICIjIiwNCiAgY29sbGFwc2UgPSBUUlVFLA0KICBlY2hvID0gVFJVRSwgd2FybmluZyA9IFRSVUUsIG1lc3NhZ2UgPSBUUlVFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdHRpbmcgKGhlcmUgdXNlZCBBUEEgc3R5bGUpDQp0aGVtZV9zZXQocGFwYWphOjp0aGVtZV9hcGEoKSkNCmBgYA0KDQoNCg0KDQoNCjwhLS0gRnVuY3Rpb25zIC0tPg0KDQojIERlZmluZSBmdW5jdGlvbnMNCg0KYGBge3J9DQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCByZWNvZGVzIHRvIG51bWVyaWMsIGJ1dCB3YXRjaGVzIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KY29sc3RvbnVtZXJpYyA8LSBmdW5jdGlvbihkZil7DQogIHRyeUNhdGNoKHsNCiAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgIGxhcHBseShkZiwNCiAgICAgICAgICAgICBmdW5jdGlvbih4KSB7IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKX0pKSANCiAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgbWVzc2FnZSgiU3RvcGVkIHRoZSBleGVjdXRpb24gb2YgbnVtZXJpYyBjb252ZXJzaW9uOiAiLCBjb25kaXRpb25NZXNzYWdlKHN0b3Bfb25fd2FybmluZykpDQogIH0pIA0KfQ0KIyMNCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJldmVyc2UgY29kZXMgaXRlbXMNClJldmVyc2VDb2RlIDwtIGZ1bmN0aW9uKGRmLCB0b251bWVyaWMgPSBGQUxTRSwgbWluID0gTlVMTCwgbWF4ID0gTlVMTCkgew0KICBpZih0b251bWVyaWMpIGRmIDwtIGNvbHN0b251bWVyaWMoZGYpDQogIGRmIDwtIChtYXggKyBtaW4pIC0gZGYNCn0NCiMjDQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBzY29yZXMgb25seSByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXMgKHJldHVybnMgTkEgaWYgYWxsIG9yIGFib3ZlIHRocmVzaG9sZCBwZXJjZW50YWdlIG9mIHJvd3MgYXJlIE5BKTsgY2FuIHJldmVyc2UgY29kZSBpZiB2ZWN0b3Igb2YgY29sdW1uIGluZGV4ZXMgYW5kIG1pbiwgbWF4IGFyZSBwcm92aWRlZC4NClNjb3JlTGlrZXJ0IDwtIGZ1bmN0aW9uKGRmLCBuYXBlcmNlbnQgPSAuMSwgdG9udW1lcmljID0gRkFMU0UsIHJldmVyc2Vjb2xzID0gTlVMTCwgbWluID0gTlVMTCwgbWF4ID0gTlVMTCwgZW5naW5lID0gInN1bSIpIHsNCiAgcmV2ZXJzZV9saXN0IDwtIGxpc3QocmV2ZXJzZWNvbHMgPSByZXZlcnNlY29scywgbWluID0gbWluLCBtYXggPSBtYXgpDQogIHJldmVyc2VfY2hlY2sgPC0gIXNhcHBseShyZXZlcnNlX2xpc3QsIGlzLm51bGwpDQogIA0KICAjIFJlY29kZSB0byBudW1lcmljLCBidXQgd2F0Y2ggb3V0IHRvIGNvZXJjaW9uIHRvIG5vdCBpbnRyb2R1Y2UgTkFzDQogIGNvbHN0b251bWVyaWMgPC0gZnVuY3Rpb24oZGYpew0KICAgIHRyeUNhdGNoKHsNCiAgICAgIGRmX251bSA8LSBhcy5kYXRhLmZyYW1lKA0KICAgICAgICBsYXBwbHkoZGYsDQogICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKX0pKSANCiAgICB9LHdhcm5pbmcgPSBmdW5jdGlvbihzdG9wX29uX3dhcm5pbmcpIHsNCiAgICAgIG1lc3NhZ2UoIlN0b3BlZCB0aGUgZXhlY3V0aW9uIG9mIG51bWVyaWMgY29udmVyc2lvbjogIiwgY29uZGl0aW9uTWVzc2FnZShzdG9wX29uX3dhcm5pbmcpKQ0KICAgIH0pIA0KICB9DQogIA0KICBpZih0b251bWVyaWMpIGRmIDwtIGNvbHN0b251bWVyaWMoZGYpDQogIA0KICBpZihhbGwocmV2ZXJzZV9jaGVjaykpew0KICAgIGRmWyAscmV2ZXJzZWNvbHNdIDwtIChtYXggKyBtaW4pIC0gZGZbICxyZXZlcnNlY29sc10NCiAgfWVsc2UgaWYoYW55KHJldmVyc2VfY2hlY2spKXsNCiAgICBzdG9wKCJJbnN1ZmljaWVudCBpbmZvIGZvciByZXZlcnNpbmcuIFBsZWFzZSBwcm92aWRlOiAiLCBwYXN0ZShuYW1lcyhyZXZlcnNlX2xpc3QpWyFyZXZlcnNlX2NoZWNrXSwgY29sbGFwc2UgPSAiLCAiKSkNCiAgfQ0KICANCiAgaWYoZW5naW5lID09ICJzdW0iKSB7DQogICAgcmV0dXJuKA0KICAgICAgaWZlbHNlKHJvd1N1bXMoaXMubmEoZGYpKSA+IG5jb2woZGYpICogbmFwZXJjZW50LA0KICAgICAgICAgICAgIE5BLA0KICAgICAgICAgICAgIHJvd1N1bXMoZGYsIG5hLnJtID0gVFJVRSkgKiBOQSBeIChyb3dTdW1zKCFpcy5uYShkZikpID09IDApDQogICAgICApDQogICAgKSAgDQogIH0NCiAgDQogIGlmKGVuZ2luZSA9PSAibWVhbiIpIHsNCiAgICByZXR1cm4oDQogICAgICBpZmVsc2Uocm93TWVhbnMoaXMubmEoZGYpKSA+IG5jb2woZGYpICogbmFwZXJjZW50LA0KICAgICAgICAgICAgIE5BLA0KICAgICAgICAgICAgIHJvd01lYW5zKGRmLCBuYS5ybSA9IFRSVUUpICogTkEgXiAocm93U3VtcyghaXMubmEoZGYpKSA9PSAwKQ0KICAgICAgKSAgICAgICANCiAgICApDQogIH0NCiAgDQogICAgaWYoZW5naW5lID09ICJtZWFuX25hIikgew0KICAgICAgZGZbaXMubmEoZGYpXSA8LSAwDQogICAgICByb3dNZWFucyhkZikNCiAgICB9DQp9DQpgYGANCg0KDQpgYGB7cn0NCnF1aWNrX3Njb3JlX2hpc3QgPC0gZnVuY3Rpb24oeCwgeGxhYiA9ICJYIiwgbmEucm0gPSBUUlVFLCBjdXRfaW50b19iaW5zID0gVFJVRSkgew0KICBpZihuYS5ybSkge3ggPSB4WyFpcy5uYSh4KV19DQogIGJyeCA8LSBwcmV0dHkocmFuZ2UoeCwgbmEucm0gPSBUUlVFKSwgDQogICAgbiA9IG5jbGFzcy5TdHVyZ2VzKHgpLCBtaW4ubiA9IDEpDQogIGRmIDwtIGRhdGEuZnJhbWUoeCA9IHgpDQogIGlmKGN1dF9pbnRvX2JpbnMpIHtkZiA8LSBkYXRhLmZyYW1lKHggPSBjdXQoeCwgYnJ4LCBvcmRlcmVkX3Jlc3VsdCA9IFRSVUUpKX0NCiAgZGYgJT4lIA0KICBjb3VudCh4KSAlPiUNCiAgbXV0YXRlKHBjdCA9IHByb3AudGFibGUobiksDQogICAgICAgICBQZXJjZW50ID0gcGFzdGUwKHJvdW5kKHBjdCAqIDEwMCwgMiksICIgJSIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHgsIHkgPSBwY3QsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KHBjdCkpKSArIA0KICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gUGVyY2VudCksIHZqdXN0ID0gLTAuMjUpICsNCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICAgICB5bGFiKCJQZXJjZW50YWdlICUiKSArICB4bGFiKHhsYWIpICAgIA0KfQ0KYGBgDQoNCg0KPCEtLSBSZXBvcnQgLS0+DQoNCiMgUmVhZCBzdXJ2ZXkgc3RydWN0dXJlDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZm9sZGVyIDwtIGhlcmU6OmhlcmUoIlJzeW50YXgmZGF0YV82NTAiKQ0KZGF0YV9uYW1lIDwtICJzdXJ2ZXlfNjg2NzMyX1JfZGF0YV9maWxlLmNzdiINCnNjcmlwdF9uYW1lIDwtICJzdXJ2ZXlfNjg2NzMyX1Jfc3ludGF4X2ZpbGUuUiINCiAgDQojIENoZWNrIG1vc3QgcmVjZW50IC5jc3YgZmlsZQ0KbGFzdF9jc3ZfZmlsZSA8LSANCiAgZGlyKGZvbGRlciwgcGF0dGVybiA9ICIuKmNzdiIsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUgDQogIGZpbGUuaW5mbygpICU+JQ0KICBkcGx5cjo6YXJyYW5nZShkcGx5cjo6ZGVzYyhjdGltZSkpICU+JQ0KICBkcGx5cjo6c2xpY2UoMSkgJT4lDQogIHJvdy5uYW1lcygpDQppZihpZGVudGljYWwobGFzdF9jc3ZfZmlsZSwgZmlsZS5wYXRoKGZvbGRlciwgZGF0YV9uYW1lKSkpIHsNCiAgY2F0KCJNb3N0IHJlY2VudCAuY3N2IGlzIHVzZWQuIikNCn0gZWxzZSB7DQogIGNhdCgiTk9UIHVzaW5nIHRoZSBtb3N0IHJlY2VudCAuY3N2ISIpDQp9DQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBSZWFkIGRhdGENCmxpYnJhcnkobGltb25haWQpDQpsaWJyYXJ5KHN0aWNreSkgICMgbmVlZCB0aGlzIGZvciBzdGlja3kgbGFiZWxzDQoNCmRmIDwtIGxpbW9uYWlkOjpsc19pbXBvcnRfZGF0YSgNCiAgZGF0YWZpbGUgPSBmaWxlLnBhdGgoZm9sZGVyLCBkYXRhX25hbWUpLA0KICBzY3JpcHRmaWxlID0gZmlsZS5wYXRoKGZvbGRlciwgc2NyaXB0X25hbWUpLA0KICBtYXNzQ29udmVydFRvTnVtZXJpYyA9IEZBTFNFDQopDQoNCmRmX2NvbXBsIDwtDQogIGRmICU+JQ0KICBmaWx0ZXIobGFzdHBhZ2UgPT0gMTcpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBMYWJlbHMgdG8gZmFjdG9yIGxldmVscyBsZXZlbHMgKCJsYWJlbCIgPSBxdWVzdGlvbiB0ZXh0OyAibGFiZWxzIiA9IHJlc3BvbnNlIG9wdGlvbnMgdGV4dCkNCiMgbGlicmFyeShsYWJlbGxlZCkNCiMgbGlicmFyeShzamxhYmVsbGVkKQ0KIyBzamxhYmVsbGVkOjpnZXRfbGFiZWxzKGRmJEcwMVE1OV9TUTAwOCwgYXR0ci5vbmx5ID0gVFJVRSwgdmFsdWVzID0gImFzLnByZWZpeCIpDQojIHNqbGFiZWxsZWQ6OmdldF92YWx1ZXMoZGYkRzAxUTU5X1NRMDA4KQ0KIyBzamxhYmVsbGVkOjphc19sYWJlbChkZiRHMDFRNTlfU1EwMDgsIHByZWZpeCA9IFRSVUUsIGtlZXAubGFiZWxzID0gVFJVRSkgDQojIHNqbGFiZWxsZWQ6OmFzX2NoYXJhY3RlcihkZiRHMDFRNTlfU1EwMDgsIHByZWZpeCA9IFRSVUUsIGtlZXAubGFiZWxzID0gVFJVRSkNCiMgbGFiZWxsZWQ6OnZhcl9sYWJlbChkZiRHMDFRNTlfU1EwMDgpDQojIGxhYmVsbGVkOjp0b19mYWN0b3IoZGYkRzAxUTU5X1NRMDA4LCBsZXZlbHMgPSAidmFsdWVzIikNCg0KbGltZV9sYWJlbF9yZWNvZGUgPC0gZnVuY3Rpb24gKHgsIHByZWZpeCA9IEZBTFNFKSB7DQogIGxhYmVscyA8LSBhdHRyKHgsICJsYWJlbHMiLCBleGFjdCA9IFRSVUUpDQogIGlmIChpcy5udWxsKGxhYmVscykpIHsNCiAgICB4DQogIH0gZWxzZSB7DQogICAgbGFiZWxzIDwtIHVubmFtZShsYWJlbHMpDQogICAgdmFsdWVzIDwtIG5hbWVzKGF0dHIoeCwgImxhYmVscyIsIGV4YWN0ID0gVFJVRSkpDQogICAgaWYgKHByZWZpeCkgew0KICAgICAgbGFiZWxzIDwtIHNwcmludGYoIlslc10gJXMiLCB2YWx1ZXMsIGxhYmVscykNCiAgICB9DQogICAgIyBObyByZWNvZGluZyBzb2x1dGlvbiBwcmVzZXJ2ZSBhdHRyaWJ1dGVzLCBldmVuIHdpdGggc3RpY2t5DQogICAgICB4X3JlYyA8LSBjKGxhYmVscywgeClbbWF0Y2goeCwgYyh2YWx1ZXMsIHgpKV0NCiAgICBhdHRyaWJ1dGVzKHhfcmVjKSA8LSBhdHRyaWJ1dGVzKHgpICAjIHJlYXR0YWNoIGF0dHJpYnV0ZXMNCiAgICB4X3JlYw0KICB9DQp9DQojIHRlc3RfZGYgPC0gY2JpbmQoZGYkRzAyUTAyX1NRMDIxLCBsaW1lX2xhYmVsX3JlY29kZShkZiRHMDJRMDJfU1EwMjEpKQ0KIyBsaW1lX2xhYmVsX3JlY29kZShkZiRHMDFRNTlfU1EwMDgpDQojIGxpbWVfbGFiZWxfcmVjb2RlKGRmJEcwNFEwNV9TUTAwMSkNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFJlY29kZSB1c2luZyBsYWJlbHMNCiMgY29sc190b19yZWNvZGUgPC0gbGFwcGx5KGRmLCBmdW5jdGlvbih4KSB7IWlzLm51bGwoYXR0cih4LCAibGFiZWxzIiwgZXhhY3QgPSBUUlVFKSl9KQ0KIyBjb2xzX3RvX3JlY29kZSA8LSB3aGljaCh1bmxpc3QoY29sc190b19yZWNvZGUpKQ0KDQojIGRmX3JlY29kZWQgPC0gZGYNCiMgbGlzdF9yZWNvZGVkIDwtIGxhcHBseShkZl9yZWNvZGVkWywgY29sc190b19yZWNvZGVdLCBsaW1lX2xhYmVsX3JlY29kZSkNCiMgZGZfcmVjb2RlZFssIGNvbHNfdG9fcmVjb2RlXSA8LSBhcy5kYXRhLmZyYW1lKGRvLmNhbGwoY2JpbmQsIGxpc3RfcmVjb2RlZCkpDQoNCiMgZGZfcmVjb2RlZCA8LQ0KIyAgIGRmICU+JQ0KIyAgIG11dGF0ZShhY3Jvc3MoYWxsX29mKGNvbHNfdG9fcmVjb2RlKSwgbGltZV9sYWJlbF9yZWNvZGUpKSANCg0KZGZfcmVjb2RlZCA8LQ0KICBkZiAlPiUNCiAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIGxpbWVfbGFiZWxfcmVjb2RlKSkgJT4lICAgIyBzb21lIHZhbHVlcyBoYXZlIHNhbWUgbGFiZWxzOiBkZiRHMDFRNjBfU1EwMDYNCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCBmdW5jdGlvbihjb2wpIGljb252KGNvbCwgdG89IlVURi04IikpKSAgIyBlbmNvZGluZzogZGZfcmVjb2RlZCRHMDFRNTYNCmBgYA0KDQoNCg0KIyBTY29yZSAzIFF1ZXN0aW9ubmFpcmVzDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgRGVmaW5lIDMgc2NhbGVzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBVFNQUEggLSAxMCBpdGVtcyAobGlrZXJ0IDAtMykgdG90YWwgc3VtDQphdHNwcGhfaWR4IDwtIDE4NDoxOTMgICMgZ3JlcCgiRzA2UTEzIiwgbmFtZXMoZGYpKTsgIGRmWywgZ3JlcCgiRzA2UTEzIiwgbmFtZXMoZGYpLCB2YWx1ZSA9IFRSVUUpXQ0KYXRzcHBoX2xhYnMgPC0gdW5pcXVlKGxhcHBseShkZlssIGF0c3BwaF9pZHhdLCBhdHRyLCAibGFiZWxzIikpDQphdHNwcGhfcmV2IDwtIGMoMiwgNCwgOCwgOSwgMTApDQoNCmF0c3BwaF9yZWNvZGUgPC0gZnVuY3Rpb24oZGYsIHJldikgew0KICBkZiAlPiUNCiAgICBtdXRhdGUoDQogICAgICBhY3Jvc3MoZXZlcnl0aGluZygpLA0KICAgICAgICB+IGNhc2Vfd2hlbigNCiAgICAgICAgICAuID09ICJBTzAyIiB+IDAsDQogICAgICAgICAgLiA9PSAiQU8wMyIgfiAxLA0KICAgICAgICAgIC4gPT0gIkFPMDQiIH4gMiwNCiAgICAgICAgICAuID09ICJBTzA1IiB+IDMNCiAgICAgICAgKQ0KICAgICAgKSAgICAgICANCiAgICApICU+JQ0KICAgIG11dGF0ZSggICAjIGhlcmUgcmV2ZXJzZSBjb2RlDQogICAgICBhY3Jvc3MocmV2LA0KICAgICAgfiAzIC0gLnggDQogICAgICApDQogICAgKQ0KfSAgIyBhdHNwcGhfcmVjb2RlKGRmX2NvbXBsWywgYXRzcHBoX2lkeF0sIGF0c3BwaF9yZXYpDQoNCiMgRlNvelUgLSA2IGl0ZW1zIChsaWtlcnQgMS01KSB0b3RhbCBtZWFuDQpmc296dV9pZHggPC0gMjIyOjIyNyAjIGdyZXAoIkcxMlE0NSIsIG5hbWVzKGRmKSk7IGRmWywgZ3JlcCgiRzEyUTQ1IiwgbmFtZXMoZGYpLCB2YWx1ZSA9IFRSVUUpXSAgDQpmc296dV9sYWJzIDwtIHVuaXF1ZShsYXBwbHkoZGZbLCBmc296dV9pZHhdLCBhdHRyLCAibGFiZWxzIikpICANCg0KZnNvenVfcmVjb2RlIDwtIGZ1bmN0aW9uKGRmKSB7DQogIGRmICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIGFjcm9zcyhldmVyeXRoaW5nKCksDQogICAgICAgIH4gY2FzZV93aGVuKA0KICAgICAgICAgIC4gPT0gIkFPMDEiIH4gMSwNCiAgICAgICAgICAuID09ICJBTzAyIiB+IDIsDQogICAgICAgICAgLiA9PSAiQU8wMyIgfiAzLA0KICAgICAgICAgIC4gPT0gIkFPMDQiIH4gNCwNCiAgICAgICAgICAuID09ICJBTzA1IiB+IDUNCiAgICAgICAgKQ0KICAgICAgKSAgICAgICANCiAgICApIA0KfSAgIyBmc296dV9yZWNvZGUoZGZfY29tcGxbLCBmc296dV9pZHhdKQ0KDQojIFBNSFNTIC0gMjQgaXRlbXMgKGxpa2VydCAxLTUpIHN1YnNjYWxlIHN1bQ0KcG1oc3NfaWR4IDwtIDIyODoyNTEgICAjIGdyZXAoIkcxM1E0NiIsIG5hbWVzKGRmKSk7IGRmWywgZ3JlcCgiRzEzUTQ2IiwgbmFtZXMoZGYpLCB2YWx1ZSA9IFRSVUUpXQ0KcG1oc3NfbGFicyA8LSB1bmlxdWUobGFwcGx5KGRmWywgcG1oc3NfaWR4XSwgYXR0ciwgImxhYmVscyIpKQ0KDQpwbWhzc19hd2FyZSA8LSBjKDIsIDQsIDUsIDYsIDgsIDEwLCAxMSwgMTIpICANCnBtaHNzX2FncmVlIDwtIGMoMTQsIDE2LCAxNywgMTgsIDIwLCAyMiwgMjMsIDI0KSANCnBtaHNzX3Bvc2l0IDwtIGMoMSwgMywgNywgOSwgMTMsIDE1LCAxOSwgMjEpDQoNCnBtaHNzX3JlY29kZSA8LSBmdW5jdGlvbihkZikgew0KICBkZiAlPiUNCiAgICBtdXRhdGUoDQogICAgICBhY3Jvc3MoZXZlcnl0aGluZygpLA0KICAgICAgICB+IGNhc2Vfd2hlbigNCiAgICAgICAgICAuID09ICJBTzAxIiB+IDEsDQogICAgICAgICAgLiA9PSAiQU8wMiIgfiAyLA0KICAgICAgICAgIC4gPT0gIkFPMDMiIH4gMywNCiAgICAgICAgICAuID09ICJBTzA0IiB+IDQsDQogICAgICAgICAgLiA9PSAiQU8wNSIgfiA1DQogICAgICAgICkNCiAgICAgICkgICAgICAgDQogICAgKQ0KfSAgIyBwbWhzc19yZWNvZGUoZGZfY29tcGxbLCBwbWhzc19pZHhdKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBSZWNvZGUgJiBTY29yZQ0KZGZfY29tcGxbLCBhdHNwcGhfaWR4XSA8LSBhdHNwcGhfcmVjb2RlKGRmX2NvbXBsWywgYXRzcHBoX2lkeF0sIGF0c3BwaF9yZXYpDQpkZl9jb21wbFssIGZzb3p1X2lkeF0gPC0gZnNvenVfcmVjb2RlKGRmX2NvbXBsWywgZnNvenVfaWR4XSkNCmRmX2NvbXBsWywgcG1oc3NfaWR4XSA8LSBwbWhzc19yZWNvZGUoZGZfY29tcGxbLCBwbWhzc19pZHhdKQ0KDQpkZl9jb21wbCRoZWxwX3NlZWsgPC0gU2NvcmVMaWtlcnQoZGZfY29tcGxbLCBhdHNwcGhfaWR4XSwgbmFwZXJjZW50ID0gLjUsIGVuZ2luZSA9ICJzdW0iKQ0KZGZfY29tcGwkc29jX3N1cHAgPC0gU2NvcmVMaWtlcnQoZGZfY29tcGxbLCBmc296dV9pZHhdLCBuYXBlcmNlbnQgPSAuNSwgZW5naW5lID0gIm1lYW4iKQ0KDQpkZl9jb21wbCRhd2FyZSA8LSBTY29yZUxpa2VydChkZl9jb21wbFssIHBtaHNzX2lkeF1bcG1oc3NfYXdhcmVdLCBuYXBlcmNlbnQgPSAuNSwgZW5naW5lID0gInN1bSIpIA0KZGZfY29tcGwkYWdyZWUgPC0gU2NvcmVMaWtlcnQoZGZfY29tcGxbLCBwbWhzc19pZHhdW3BtaHNzX2FncmVlXSwgbmFwZXJjZW50ID0gLjUsIGVuZ2luZSA9ICJzdW0iKQ0KZGZfY29tcGwkcG9zaXQgPC0gU2NvcmVMaWtlcnQoZGZfY29tcGxbLCBwbWhzc19pZHhdW3BtaHNzX3Bvc2l0XSwgbmFwZXJjZW50ID0gLjUsIGVuZ2luZSA9ICJzdW0iKQ0KYGBgDQoNCg0KIyBTb21lIGFuYWx5c2VzIG9uIDMgUXVlc3Rpb25uYWlyZXMNCg0KYGBge3IsIGVjaG89RkFMU0V9DQp2YXJzX2RlbW9nIDwtIGMoIlEwMCIsICJHMDFRMjMiLCAiRzAxUTI0IiwgIkcwMVEyNiIpDQp2YXJzX2RlbW9nX25hbWVzIDwtIGMoInNleCIsICJ5ZWFyX2JpcnRoIiwgImdyYWRlIiwgInJlc2lkIikNCmxhcHBseShkZl9jb21wbFssIHZhcnNfZGVtb2ddLCBhdHRyLCAibGFiZWwiKQ0KDQpkZl9zY2FsZXMgPC0gDQogIGRmX2NvbXBsICU+JQ0KICAjIGxhYmVsbGVkOjpyZW1vdmVfYXR0cmlidXRlcygibGFiZWwiKSAlPiUNCiAgIyBsYWJlbGxlZDo6cmVtb3ZlX2F0dHJpYnV0ZXMoImxhYmVscyIpICU+JQ0KICByZW5hbWVfd2l0aCh+IGModmFyc19kZW1vZ19uYW1lcyksIGFsbF9vZih2YXJzX2RlbW9nKSkgJT4lDQogIHNlbGVjdChhbGxfb2YodmFyc19kZW1vZ19uYW1lcyksDQogICAgICAgICBoZWxwX3NlZWssIHNvY19zdXBwLCBhd2FyZSwgYWdyZWUsIHBvc2l0KSAlPiUNCiAgbXV0YXRlKGFjcm9zcyhhbGxfb2YodmFyc19kZW1vZ19uYW1lcyksIGxpbWVfbGFiZWxfcmVjb2RlKSkgJT4lDQogIG11dGF0ZShhZ2UgPSAyMDIzIC0gYXMubnVtZXJpYyh5ZWFyX2JpcnRoKSkNCmBgYA0KDQojIyMgSnVzdCBjaGVja3MNCg0KYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0NCnBsb3Rfc2NhbGVzIDwtIEdHYWxseTo6Z2dwYWlycyhkZl9zY2FsZXNbLCBjKDEsIDEwLCAzOjkpXSwgcHJvZ3Jlc3MgPSBGQUxTRSkNCnBsb3Rfc2NhbGVzDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTd9DQpwbG90X3NjYWxlczIgPC0gUGVyZm9ybWFuY2VBbmFseXRpY3M6OmNoYXJ0LkNvcnJlbGF0aW9uKGRmX3NjYWxlc1ssIGMoMTAsIDU6OSldKQ0KcGxvdF9zY2FsZXMyDQpgYGANCg0KPCEtLQ0KDQojIyMgTW9kIC0ganVzdCBjaGVjaw0KDQpgYGB7ciBtb2QsIGNhY2hlPVRSVUV9DQojIGZpbmRfbW9kKGRmX3NjYWxlcykNCiMgbW9kZXJhdGlvbl9tb2RlbF9saXN0ICMxLDIsMyw2LDcsMTAsMTEsMTINCg0KbW9kX3N5bnRoIDwtDQogIG1vZGVyYXRpb25fbW9kZWxfbGlzdCAlPiUNCiAgcHVycnI6OnBsdWNrKCJTeW50YXgiKSAlPiUNCiAgc3RyaW5ncjo6c3RyX21hdGNoKCIjIFJlZ3Jlc3Npb25zXFxcbiguKj8pXFxcblxcXG4jIikgJT4lICAgIyBzdHJpbmcgYmV0d2VlbiAiIyBSZWdyZXNzaW9uc1xuIiBhbmQgIlxuXG4jIg0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGRwbHlyOjpwdWxsKDIpICU+JSANCiAgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoZml4ZWQoImIwKjEgKyAiKSkgDQoNCm1vZF90YWJsIDwtIA0KICBtb2RlcmF0aW9uX21vZGVsX2xpc3QgJT4lDQogIHB1cnJyOjpwbHVjaygiTW9kZWwiKQ0KDQpmb3IoaSBpbiBzZXFfbGVuKGxlbmd0aChtb2RfdGFibCkpKSB7cHJpbnQobW9kX3N5bnRoW2ldKTsgcHJpbnQobW9kX3RhYmxbW2ldXSl9DQpgYGANCg0KIyMjIE1lZCAtIGp1c3QgY2hlY2sNCg0KYGBge3IgbWVkLCBjYWNoZT1UUlVFfQ0KIyBmaW5kX21lZChkZl9zY2FsZXMpDQojIG1lZGlhdGlvbl9tb2RlbF9saXN0DQoNCmZvcihpIGluIHNlcV9sZW4obGVuZ3RoKG1lZGlhdGlvbl9tb2RlbF9saXN0JE1lZEVzKSkpIHtwcmludChtZWRpYXRpb25fbW9kZWxfbGlzdCRNZWRFc1tpXSk7IHByaW50KG1lZGlhdGlvbl9tb2RlbF9saXN0JFBhdGhFc1tbaV1dKX0NCmBgYA0KDQotLT4NCg0KIyMjIE9kZCBzdGlnbWEgcGF0dGVybnMNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTd9DQpnZ3Bsb3QoZGZfc2NhbGVzLCBhZXMoYXdhcmUsIGFncmVlLCBjb2xvciA9IHBvc2l0KSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBmb3JtdWxhID0geSB+IHgsIHNlID0gVFJVRSwgYWxwaGEgPSAwLjEsIGNvbG9yID0gInJlZCIsIGZpbGwgPSAicmVkIikgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV9jb2xvdXJfZGlzdGlsbGVyKHBhbGV0dGUgPSAiQmx1ZXMiLCBkaXJlY3Rpb24gPSAxKQ0KDQpkZl9zY2FsZXMgJT4lDQogIG11dGF0ZShwb3NpdF9jYXQgPSBjdXQocG9zaXQsDQogICAgYnJlYWtzID0gYyg1LCAxMCwgMjAsIDMwLCA0MCkpDQogICkgJT4lDQogIGdncGxvdChhZXMoYXdhcmUsIGFncmVlLCBjb2xvciA9IHBvc2l0X2NhdCkpICsNCiAgZ2VvbV9wb2ludCgpIC0+IHBsb3Rfc3RpZ21hMQ0KcGxvdGx5OjpnZ3Bsb3RseShwbG90X3N0aWdtYTEpDQoNCmdncGxvdChkZl9zY2FsZXMsIGFlcyhwb3NpdCwgYWdyZWUsIGNvbG9yID0gYXdhcmUpKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGZvcm11bGEgPSB5IH4geCwgc2UgPSBUUlVFLCBhbHBoYSA9IDAuMSwgY29sb3IgPSAicmVkIiwgZmlsbCA9ICJyZWQiKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX2NvbG91cl9kaXN0aWxsZXIocGFsZXR0ZSA9ICJCbHVlcyIsIGRpcmVjdGlvbiA9IDEpDQoNCmRmX3NjYWxlcyAlPiUNCiAgbXV0YXRlKGF3YXJlX2NhdCA9IGN1dChwb3NpdCwNCiAgICBicmVha3MgPSBjKDUsIDEwLCAyMCwgMzAsIDQwKSkNCiAgKSAlPiUNCiAgZ2dwbG90KGFlcyhwb3NpdCwgYWdyZWUsIGNvbG9yID0gYXdhcmVfY2F0KSkgKw0KICBnZW9tX3BvaW50KCkgLT4gcGxvdF9zdGlnbWEyDQpwbG90bHk6OmdncGxvdGx5KHBsb3Rfc3RpZ21hMikNCg0KY29wbG90KGFncmVlIH4gcG9zaXQgfCBhd2FyZSwgb3ZlcmxhcCA9IDAsIGRhdGEgPSBkZl9zY2FsZXMsDQogIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7DQogICAgICAgICAgcG9pbnRzKHgsIHksIC4uLikNCiAgICAgICAgICBhYmxpbmUobG0oeSB+IHgpLCBjb2wgPSAicmVkIil9DQopDQpgYGANCg0KIyMjIFBhcnRpYWwgY29ycmVsYXRpb25zIHN0aWdtYSAocGFydGlhbCBldmVyeXRoaW5nIGZyb20gZXZlcnl0aGluZykNCg0KYGBge3J9DQpwc3ljaDo6bG93ZXJNYXQocHN5Y2g6OnBhcnRpYWwucihkZl9zY2FsZXNbLCBjKCJhZ3JlZSIsICJhd2FyZSIsICJwb3NpdCIpXSkpDQpgYGANCg0KDQojIyMgSW50ZXJhY3Rpb24gc3RpZ21hDQoNCmBgYHtyfQ0KZGZfYWdyZWUgPC0gbmEub21pdChkZl9zY2FsZXNbLCBjKCJhZ3JlZSIsICJzZXgiLCAiYWdlIiwgInJlc2lkIiwgImF3YXJlIiwgInNvY19zdXBwIiwgInBvc2l0IildKQ0KDQptb2Rfc3RpZ21hX2ludGVyYWMgPC0gbG0oYWdyZWUgfiBhd2FyZSAqIHBvc2l0LCBkYXRhID0gZGZfYWdyZWUpDQppbnRlcmFjdGlvbnM6OmludGVyYWN0X3Bsb3QobW9kX3N0aWdtYV9pbnRlcmFjLCBwcmVkID0gcG9zaXQsIG1vZHggPSBhd2FyZSkNCiMgaW50ZXJhY3Rpb25zOjpzaW1fc2xvcGVzKG1vZF9zdGlnbWFfaW50ZXJhYywgcHJlZCA9IHBvc2l0LCBtb2R4ID0gYXdhcmUpDQpgYGANCg0KIyMjIEdlbmRlciBkaWZmIHN0aWdtYQ0KDQpgYGB7cn0NCmdnc3RhdHNwbG90OjpnZ2JldHdlZW5zdGF0cyhkZl9hZ3JlZSwgeCA9IHNleCwgeSA9IGFncmVlKQ0KZ2dzdGF0c3Bsb3Q6OmdnYmV0d2VlbnN0YXRzKGRmX2FncmVlLCB4ID0gc2V4LCB5ID0gYXdhcmUpDQpnZ3N0YXRzcGxvdDo6Z2diZXR3ZWVuc3RhdHMoZGZfYWdyZWUsIHggPSBzZXgsIHkgPSBwb3NpdCkNCmBgYA0KDQojIyMgU2lsbHkgbW9kZWwgdGhhdCB3b3JrcyBzbWggKDAgbSwgMSBmZW0pDQoNCmBgYHtyfQ0KZGZfc2NhbGVzICU+JSANCiAgbXV0YXRlKHNleCA9IGFzLm51bWVyaWMoYXMuZmFjdG9yKHNleCkpIC0gMSkgJT4lIA0KICBwc3ljaDo6bWVkaWF0ZShwb3NpdCB+IHNleCArIGF3YXJlOmFncmVlICsgKGF3YXJlKSwgZGF0YSA9IC4pDQoNCiMgcHN5Y2g6Om1lZGlhdGUoYWdyZWUgfiBwb3NpdCArIChhd2FyZSksIGRhdGEgPSBkZl9zY2FsZXMpICMgc2lsbHkgYnV0IHdvcmtzDQojIHBzeWNoOjptZWRpYXRlKGFncmVlIH4gcG9zaXQgKiBhd2FyZSwgZGF0YSA9IGRmX3NjYWxlcykNCmBgYA0KDQojIyMgUmVnIHN0ZXAgLSBldmVyeXRoaW5nIGFib3V0IHN0aWdtYSBpcyB3YWNreQ0KDQpgYGB7cn0NCm1vZF9hZ3JlZSA8LSBsbShhZ3JlZSB+IHNleCArIGFnZSArIHJlc2lkICsgYXdhcmUgKyBzb2Nfc3VwcCwgZGF0YSA9IGRmX2FncmVlKQ0KYmVzdF9tb2RfYWdyZWUgPC0gc3RlcChtb2RfYWdyZWUsIHNjb3BlID0gaGVscF9zZWVrIH4gLl4yLCBkaXJlY3Rpb24gPSAiYm90aCIsIGRhdGEgPSBtb2RfYWdyZWUkbW9kZWwsIHRyYWNlID0gMCkgIyBCSUMgd2l0aCBrID0gbG9nKG5yb3cobW9kX2FncmVlJG1vZGVsKSkNCnN1bW1hcnkoYmVzdF9tb2RfYWdyZWUpDQpgYGANCg0KDQpgYGB7cn0NCmRmX2hlbHBzZWVrIDwtIG5hLm9taXQoZGZfc2NhbGVzWywgYygiaGVscF9zZWVrIiwgInNleCIsICJhZ2UiLCAiYWdyZWUiLCAiYXdhcmUiLCAic29jX3N1cHAiLCAiYWdyZWUiLCAicG9zaXQiKV0pDQptb2RfaGVscHNlZWsgPC0gbG0oaGVscF9zZWVrIH4gc2V4ICsgYWdlICsgYWdyZWUgICsgYXdhcmUgKyBzb2Nfc3VwcCwgZGF0YSA9IGRmX2hlbHBzZWVrKQ0KYmVzdF9tb2RfaGVscHNlZWsgPC0gc3RlcChtb2RfaGVscHNlZWssIHNjb3BlID0gaGVscF9zZWVrIH4gLl4yLCBkaXJlY3Rpb24gPSAiYm90aCIsIGRhdGEgPSBtb2RfaGVscHNlZWskbW9kZWwsIHRyYWNlID0gMCkgIyBCSUMgd2l0aCBrID0gbG9nKG5yb3cobW9kX2hlbHBzZWVrJG1vZGVsKSkNCnN1bW1hcnkoYmVzdF9tb2RfaGVscHNlZWspDQoNCg0Kc3VtbWFyeShsbShoZWxwX3NlZWsgfiBzZXggKyBhZ2UgKiBhd2FyZSwgZGF0YSA9IGRmX3NjYWxlcykpIA0KDQoNCmBgYA0KDQojIyBEZW1vZ3JhcGhpY3MNCg0KYGBge3J9DQpkZW1vX3NleCA8LSANCiAgZGZfc2NhbGVzICU+JSANCiAgbXV0YXRlKHNleCA9IGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoc2V4KSkpICU+JQ0KICBncm91cF9ieShzZXgpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKGNvdW50cyA9IG4oKSkgJT4lDQogIG11dGF0ZShwcm9wID0gcm91bmQoY291bnRzKjEwMC9zdW0oY291bnRzKSwgMSksDQogICAgICAgICBsYWIueXBvcyA9IGN1bXN1bShwcm9wKSAtIC41KnByb3AsDQogICAgICAgICBQZXJjZW50ID0gcGFzdGUwKHByb3AsICIgJSIpKSANCmRlbW9fc2V4DQoNCmRlbW9fc2V4ICU+JQ0KICBnZ3B1YnI6OmdncGllKHggPSAicHJvcCIsIGxhYmVsID0gIlBlcmNlbnQiLA0KICAgICAgICAgICAgICAgIGZpbGwgPSAic2V4IiwgY29sb3IgPSAid2hpdGUiLCANCiAgICAgICAgICAgICAgICBsYWIucG9zID0gImluIiwgbGFiLmZvbnQgPSBsaXN0KGNvbG9yID0gIndoaXRlIiksDQogICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJncmV5IikNCmBgYA0KDQpgYGB7cn0NCmRlbW9fcmVzaWQgPC0gDQogIGRmX3NjYWxlcyAlPiUgDQogIG11dGF0ZShzZXggPSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKHJlc2lkKSkpICU+JQ0KICBncm91cF9ieShyZXNpZCkgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UoY291bnRzID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSByb3VuZChjb3VudHMqMTAwL3N1bShjb3VudHMpLCAxKSwNCiAgICAgICAgIGxhYi55cG9zID0gY3Vtc3VtKHByb3ApIC0gLjUqcHJvcCwNCiAgICAgICAgIFBlcmNlbnQgPSBwYXN0ZTAocHJvcCwgIiAlIikpIA0KZGVtb19yZXNpZA0KDQpkZW1vX3Jlc2lkICU+JQ0KICBnZ3B1YnI6OmdncGllKHggPSAicHJvcCIsIGxhYmVsID0gIlBlcmNlbnQiLA0KICAgICAgICAgICAgICAgIGZpbGwgPSAicmVzaWQiLCBjb2xvciA9ICJ3aGl0ZSIsIA0KICAgICAgICAgICAgICAgIGxhYi5wb3MgPSAiaW4iLCBsYWIuZm9udCA9IGxpc3QoY29sb3IgPSAid2hpdGUiKSwNCiAgICAgICAgICAgICAgICBwYWxldHRlID0gImdyZXkiKQ0KYGBgDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05fQ0KZGVtb19yZXNpZHNleCA8LSANCiAgZGZfc2NhbGVzICU+JSANCiAgbXV0YXRlKHNleCA9IGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoc2V4KSkpICU+JQ0KICBtdXRhdGUocmVzaWQgPSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKHJlc2lkKSkpICU+JQ0KICBkcGx5cjo6Y291bnQocmVzaWQsIHNleCwgLmRyb3AgPSBGQUxTRSkgJT4lICAgICAgICAgIyBHcm91cCBieSwgdGhlbiBjb3VudCBudW1iZXIgaW4gZWFjaCBncm91cCAoZG9udCBkcm9wIDAgY291bnRzKQ0KICBtdXRhdGUocGN0ID0gcHJvcC50YWJsZShuKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBDYWxjdWxhdGUgcGVyY2VudCB3aXRoaW4gZWFjaCB2YXINCiAgICAgICAgIFBlcmNlbnQgPSBwYXN0ZTAocm91bmQocGN0ICogMTAwLCAyKSwgIiAlIikpDQpkZW1vX3Jlc2lkc2V4DQoNCmRmX3NjYWxlcyAlPiUgDQogIG11dGF0ZShzZXggPSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKHNleCkpKSAlPiUNCiAgbXV0YXRlKHJlc2lkID0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihyZXNpZCkpKSAlPiUNCiAgZ2dzdGF0c3Bsb3Q6Omdyb3VwZWRfZ2dwaWVzdGF0cygNCiAgICB4ID0gc2V4LA0KICAgIGdyb3VwaW5nLnZhciA9IHJlc2lkLA0KICAgIHBhY2thZ2UgPSAiUkNvbG9yQnJld2VyIiwNCiAgICBwYWxldHRlID0gIkdyZXlzIiwNCiAgICBiZi5tZXNzYWdlID0gRkFMU0UsDQogICAgZ2dwbG90LmNvbXBvbmVudCA9IGxpc3Qoc2NhbGVfZmlsbF9ncmV5KCkpDQogICkNCmBgYA0KDQoNCg0KYGBge3J9DQpkZW1vX2FnZSA8LSANCiAgZGZfc2NhbGVzICU+JSANCiAgbXV0YXRlKGFnZSA9IGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIoYWdlKSkpICU+JQ0KICBjb3VudChhZ2UpICU+JQ0KICBtdXRhdGUocGN0ID0gcHJvcC50YWJsZShuKSwNCiAgICAgICAgIFBlcmNlbnQgPSBwYXN0ZTAocm91bmQocGN0ICogMTAwLCAyKSwgIiAlIikpDQpkZW1vX2FnZQ0KDQpkZW1vX2FnZSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gYWdlLCB5ID0gcGN0LCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudChwY3QpKSkgKyANCiAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFBlcmNlbnQpLCB2anVzdCA9IC0wLjI1KSArDQogICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgICAgeWxhYigiUGVyY2VudGFnZSAlIikgKyAgeGxhYigiIikgIA0KICANCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9DQpkZW1vX2FnZXNleCA8LQ0KICBkZl9zY2FsZXMgJT4lIA0KICBtdXRhdGUoc2V4ID0gYXMuZmFjdG9yKGFzLmNoYXJhY3RlcihzZXgpKSkgJT4lDQogIG11dGF0ZShhZ2UgPSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGFnZSkpKSAlPiUNCiAgZHBseXI6OmNvdW50KGFnZSwgc2V4LCAuZHJvcCA9IEZBTFNFKSAlPiUgICAgICAgICAjIEdyb3VwIGJ5LCB0aGVuIGNvdW50IG51bWJlciBpbiBlYWNoIGdyb3VwIChkb250IGRyb3AgMCBjb3VudHMpDQogIG11dGF0ZShwY3QgPSBwcm9wLnRhYmxlKG4pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENhbGN1bGF0ZSBwZXJjZW50IHdpdGhpbiBlYWNoIHZhcg0KICAgICAgICAgUGVyY2VudCA9IHBhc3RlMChyb3VuZChwY3QgKiAxMDAsIDIpLCAiICUiKSkNCmRlbW9fYWdlc2V4DQoNCmRlbW9fYWdlc2V4ICU+JSAgICAgDQogIGdncGxvdChhZXMoeCA9IGFnZSwgeSA9IHBjdCwgZmlsbCA9IHNleCwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocGN0KSkpICsgDQogICAgICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHByZXNlcnZlID0gInNpbmdsZSIpLCBzdGF0ID0gImlkZW50aXR5IiwpICsgICAgIyBEb24ndCBkcm9wIHplcm8gY291bnQNCiAgICAgIGdlb21fdGV4dChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLCAgICAgICMgbW92ZSB0byBjZW50ZXIgb2YgYmFycw0KICAgICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBudWRnZSBhYm92ZSB0b3Agb2YgYmFyDQogICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsgDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICAgICBnZ3RpdGxlKCIiKSArDQogICAgICB4bGFiKCJWYXJzdGEiKSArIHlsYWIoIlBlcmNlbnRhZ2UgJSIpICsgDQogICAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJHZW4iLCBuY29sID0gMSkpICsgDQogICAgICBzY2FsZV9maWxsX2dyZXkoc3RhcnQgPSAwLjgsIGVuZCA9IDAuMiwgbmEudmFsdWUgPSAicmVkIiwgYWVzdGhldGljcyA9ICJmaWxsIikgKw0KICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsIA0KICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLCBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBjb2xvdXIgPSAiYmxhY2siKSkNCmBgYA0KDQoNCiMjIE1lbnRhbCBIZWFsdGggc2NhbGVzIHNjb3JpbmcNCg0KYGBge3J9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBNZW50YWwgSGVhbHRoIHNjYWxlcw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBTY3JlZW5pbmcgIERTTS01LVRSIDExLTE3ICgyMiBpdGVtcyBsaWtlcnQgMC00OyAzIGl0ZW1zIDEvMDsgMSBpdGVtIDEvMCkNCiMgaHR0cHM6Ly93d3cucHN5Y2hpYXRyeS5vcmcvZ2V0bWVkaWEvOTM1Mjg1MWMtZDY5Zi00MTFhLTg5MzMtMzIxMmU4YzI5MDYzL0FQQS1EU001VFItTGV2ZWwxTWVhc3VyZUNoaWxkQWdlMTFUbzE3LnBkZg0Kc2NyZWVuXzFfaWR4IDwtIDU5OjgwICMgZ3JlcCgiRzAyUTAyIiwgbmFtZXMoZGYpKTsgZGZbLCBncmVwKCJHMDJRMDIiLCBuYW1lcyhkZiksIHZhbHVlID0gVFJVRSldICANCnNjcmVlbl8xX2xhYnMgPC0gdW5pcXVlKGxhcHBseShkZlssIHNjcmVlbl8xX2lkeF0sIGF0dHIsICJsYWJlbHMiKSkgIA0Kc2NyZWVuXzJfaWR4IDwtIDgxOjg0ICMgZ3JlcCgiRzAyUTQ3fEcwMlE0OCIsIG5hbWVzKGRmKSk7IGRmWywgZ3JlcCgiRzAyUTQ3fEcwMlE0OCIsIG5hbWVzKGRmKSwgdmFsdWUgPSBUUlVFKV07ICAgDQpzY3JlZW5fMl9sYWJzIDwtIHVuaXF1ZShsYXBwbHkoZGZbLCBzY3JlZW5fMl9pZHhdLCBhdHRyLCAibGFiZWxzIikpICAgIyA4NCBpcyBzdWljaWRlIGl0ZW0NCg0KIyBkZlssIHNjcmVlbl8xX2lkeF0gJT4lIG1hcCh+IGF0dHIoLngsICJsYWJlbCIpKSAgIyBnZXQgaXRlbSB0ZXh0DQoNCnNjcmVlbl8xX3JlY29kZSA8LSBmdW5jdGlvbihkZikgew0KICBkZiAlPiUNCiAgICBtdXRhdGUoDQogICAgICBhY3Jvc3MoZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgIH4gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wMSIgfiAwLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wMiIgfiAxLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wMyIgfiAyLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wNCIgfiAzLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wNSIgfiA0DQogICAgICAgICAgICAgKQ0KICAgICAgKSAgICAgICANCiAgICApIA0KfSAgIyBzY3JlZW5fMV9yZWNvZGUoZGZfY29tcGxbLCBzY3JlZW5fMV9pZHhdKQ0KDQpzY3JlZW5fMl9yZWNvZGUgPC0gZnVuY3Rpb24oZGYpIHsNCiAgZGYgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICB+IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDEiIH4gMSwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDIiIH4gMA0KICAgICAgICAgICAgICkNCiAgICAgICkgICAgICAgDQogICAgKSANCn0gICMgc2NyZWVuXzJfcmVjb2RlKGRmX2NvbXBsWywgc2NyZWVuXzJfaWR4XSkNCg0KDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEFESEQgLSA4IGl0ZW1zIChsaWtlcnQgNS0xKSB0b3RhbCBzdW07DQphZGhkX2lkeCA8LSAxMTQ6MTIwICMgZ3JlcCgiRzAzUTAzIiwgbmFtZXMoZGYpKTsgZGZbLCBncmVwKCJHMDNRMDMiLCBuYW1lcyhkZiksIHZhbHVlID0gVFJVRSldICANCmFkaGRfbGFicyA8LSB1bmlxdWUobGFwcGx5KGRmWywgYWRoZF9pZHhdLCBhdHRyLCAibGFiZWxzIikpICANCg0KYWRoZF9yZWNvZGUgPC0gZnVuY3Rpb24oZGYpIHsNCiAgZGYgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICB+IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDEiIH4gNSwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDIiIH4gNCwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDMiIH4gMywNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDQiIH4gMiwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDUiIH4gMQ0KICAgICAgICAgICAgICkNCiAgICAgICkgICAgICAgDQogICAgKSANCn0gICMgYWRoZF9yZWNvZGUoZGZfY29tcGxbLCBhZGhkX2lkeF0pDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIERlcHJlc2llIChQSFEtOSkg4oCTIHYuIHZlcnNpdW5lYSBtb2RpZmljYXRhIHBlbnRydSBhZG9sZXNjZW7Im2kgKGxpa2VydCAwLTMpIHRvdGFsIHN1bTsgY3V0b2ZmIDExDQojIGh0dHBzOi8vd3d3LmNoaWxkcmVuc2hvc3BpdGFsLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzLzIwMjItMDMvUEhRJTIwRm9ybS5wZGYNCnBocV9pZHggPC0gODU6OTQgIyBncmVwKCJHMDlRMzkiLCBuYW1lcyhkZikpOyBkZlssIGdyZXAoIkcwOVEzOSIsIG5hbWVzKGRmKSwgdmFsdWUgPSBUUlVFKV0gIA0KcGhxX2xhYnMgPC0gdW5pcXVlKGxhcHBseShkZlssIHBocV9pZHhdLCBhdHRyLCAibGFiZWxzIikpICANCg0KcGhxX3JlY29kZSA8LSBmdW5jdGlvbihkZikgew0KICBkZiAlPiUNCiAgICBtdXRhdGUoDQogICAgICBhY3Jvc3MoZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgIH4gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wMiIgfiAwLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wMyIgfiAxLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wNCIgfiAyLA0KICAgICAgICAgICAgICAgLiA9PSAiQU8wNSIgfiAzDQogICAgICAgICAgICAgKQ0KICAgICAgKSAgICAgICANCiAgICApIA0KfSAgIyBwaHFfcmVjb2RlKGRmX2NvbXBsWywgcGhxX2lkeF0pDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEFueGlldGF0ZSAoR0FELTcpIChsaWtlcnQgMC0zKSB0b3RhbCBzdW07IGN1dG9mZiAxMA0KZ2FkX2lkeCA8LSA5NjoxMDIgIyBncmVwKCJHMTBRNDEiLCBuYW1lcyhkZikpOyBkZlssIGdyZXAoIkcxMFE0MSIsIG5hbWVzKGRmKSwgdmFsdWUgPSBUUlVFKV0NCmdhZF9sYWJzIDwtIHVuaXF1ZShsYXBwbHkoZGZbLCBnYWRfaWR4XSwgYXR0ciwgImxhYmVscyIpKSAgDQoNCmdhZF9yZWNvZGUgPC0gZnVuY3Rpb24oZGYpIHsNCiAgZGYgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICB+IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDIiIH4gMCwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDMiIH4gMSwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDQiIH4gMiwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDUiIH4gMw0KICAgICAgICAgICAgICkNCiAgICAgICkgICAgICAgDQogICAgKSANCn0gICMgZ2FkX3JlY29kZShkZl9jb21wbFssIGdhZF9pZHhdKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBbnhpZXRhdGUgc29jaWFsxIMgU01TQUQgMTEtMTcgKGxpa2VydCAwLTQpIHRvdGFsIHN1bTsgY3V0b2ZmIDIwDQojIGh0dHBzOi8vd3d3LnBzeWNoaWF0cnkub3JnL0ZpbGUlMjBMaWJyYXJ5L1BzeWNoaWF0cmlzdHMvUHJhY3RpY2UvRFNNL0FQQV9EU001X1NldmVyaXR5LU1lYXN1cmUtRm9yLVNvY2lhbC1BbnhpZXR5LURpc29yZGVyLUNoaWxkLUFnZS0xMS10by0xNy5wZGYNCnNtc2FkX2lkeCA8LSAxMDQ6MTEzICMgZ3JlcCgiRzExUTQyIiwgbmFtZXMoZGYpKTsgZGZbLCBncmVwKCJHMTFRNDIiLCBuYW1lcyhkZiksIHZhbHVlID0gVFJVRSldOyANCnNtc2FkX2xhYnMgPC0gdW5pcXVlKGxhcHBseShkZlssIHNtc2FkX2lkeF0sIGF0dHIsICJsYWJlbHMiKSkgIA0KDQpzbXNhZF9yZWNvZGUgPC0gZnVuY3Rpb24oZGYpIHsNCiAgZGYgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwNCiAgICAgICAgICAgICB+IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDIiIH4gMCwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDMiIH4gMSwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDQiIH4gMiwNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDUiIH4gMywNCiAgICAgICAgICAgICAgIC4gPT0gIkFPMDYiIH4gNA0KICAgICAgICAgICAgICkNCiAgICAgICkgICAgICAgDQogICAgKSANCn0gICMgc21zYWRfcmVjb2RlKGRmX2NvbXBsWywgc21zYWRfaWR4XSkNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgVHVsYnVyxINyaSBkZSBhbGltZW50YcibaWUgKE5FREEpIChzbGlkZXIgMC0xMDApIHRvdGFsIHN1bSAtIGFsc28gaGFzIGxpa2VydCBpdGVtcyBidXQgZGlkbnQgY29uc2lkZXIgdGhlbSBoZXJlIA0KbmVkYV9wYXJ0MV9pZHggPC0gMjAxOjIwNSAjIGdyZXAoIkcwOFEzNiIsIG5hbWVzKGRmKSk7IGRmWywgZ3JlcCgiRzA4UTM2IiwgbmFtZXMoZGYpLCB2YWx1ZSA9IFRSVUUpXTsgDQpuZWRhX3BhcnQxX2xhYnMgPC0gdW5pcXVlKGxhcHBseShkZlssIG5lZGFfcGFydDFfaWR4XSwgYXR0ciwgImxhYmVscyIpKSAgDQojIC0tLSBjb21wbGljYXRlZCBzY29yaW5nDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEFDRSAobGlrZXJ0ICkgcGFydCAxOiAxMCBpdGVtcywgcGFydCAyOiA5IGl0ZW1zOyB0b3RhbCBzdW0NCmFjZV9wYXJ0MV9pZHggPC0gMTYzOjE3MiAjIGdyZXAoIkcwNFEwNSIsIG5hbWVzKGRmKSk7IGRmWywgZ3JlcCgiRzA0UTA1IiwgbmFtZXMoZGYpLCB2YWx1ZSA9IFRSVUUpXTsgDQphY2VfcGFydDJfaWR4IDwtIDE3NDoxODIgIyBncmVwKCJHMDRRMDciLCBuYW1lcyhkZikpOyBkZlssIGdyZXAoIkcwNFEwNyIsIG5hbWVzKGRmKSwgdmFsdWUgPSBUUlVFKV07DQphY2VfaWR4IDwtIGMoYWNlX3BhcnQxX2lkeCwgYWNlX3BhcnQyX2lkeCkNCmFjZV9sYWJzIDwtIHVuaXF1ZShsYXBwbHkoZGZbLCBhY2VfaWR4XSwgYXR0ciwgImxhYmVscyIpKSANCg0KDQoNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUmVjb2RlICYgU2NvcmUNCmRmX2NvbXBsWywgc2NyZWVuXzFfaWR4XSA8LSBzY3JlZW5fMV9yZWNvZGUoZGZfY29tcGxbLCBzY3JlZW5fMV9pZHhdKQ0KZGZfY29tcGxbLCBzY3JlZW5fMl9pZHhdIDwtIHNjcmVlbl8yX3JlY29kZShkZl9jb21wbFssIHNjcmVlbl8yX2lkeF0pDQoNCmRmX2NvbXBsWywgYWRoZF9pZHhdIDwtIGFkaGRfcmVjb2RlKGRmX2NvbXBsWywgYWRoZF9pZHhdKQ0KZGZfY29tcGwkYWRoZCA8LSBTY29yZUxpa2VydChkZl9jb21wbFssIGFkaGRfaWR4XSwgbmFwZXJjZW50ID0gLjUsIGVuZ2luZSA9ICJzdW0iKQ0KDQpkZl9jb21wbFssIHBocV9pZHhdIDwtIHBocV9yZWNvZGUoZGZfY29tcGxbLCBwaHFfaWR4XSkNCmRmX2NvbXBsJHBocSA8LSBTY29yZUxpa2VydChkZl9jb21wbFssIHBocV9pZHhdLCBuYXBlcmNlbnQgPSAuNSwgZW5naW5lID0gInN1bSIpDQoNCmRmX2NvbXBsWywgZ2FkX2lkeF0gPC0gZ2FkX3JlY29kZShkZl9jb21wbFssIGdhZF9pZHhdKQ0KZGZfY29tcGwkZ2FkIDwtIFNjb3JlTGlrZXJ0KGRmX2NvbXBsWywgZ2FkX2lkeF0sIG5hcGVyY2VudCA9IC41LCBlbmdpbmUgPSAic3VtIikNCg0KZGZfY29tcGxbLCBzbXNhZF9pZHhdIDwtIHNtc2FkX3JlY29kZShkZl9jb21wbFssIHNtc2FkX2lkeF0pDQpkZl9jb21wbCRzbXNhZCA8LSBTY29yZUxpa2VydChkZl9jb21wbFssIHNtc2FkX2lkeF0sIG5hcGVyY2VudCA9IC41LCBlbmdpbmUgPSAic3VtIikNCg0KZGZfY29tcGwkYWNlX3BhcnQxIDwtIFNjb3JlTGlrZXJ0KGRmX2NvbXBsWywgYWNlX3BhcnQxX2lkeF0sIG5hcGVyY2VudCA9IC41LCBlbmdpbmUgPSAic3VtIikNCmRmX2NvbXBsJGFjZV9wYXJ0MiA8LSBTY29yZUxpa2VydChkZl9jb21wbFssIGFjZV9wYXJ0Ml9pZHhdLCBuYXBlcmNlbnQgPSAuNSwgZW5naW5lID0gInN1bSIpDQpkZl9jb21wbCRhY2UgPC0gU2NvcmVMaWtlcnQoZGZfY29tcGxbLCBhY2VfaWR4XSwgbmFwZXJjZW50ID0gLjUsIGVuZ2luZSA9ICJzdW0iKQ0KDQojIGRmX2NvbXBsJG5lZGFfcGFydDEgPC0gU2NvcmVMaWtlcnQoZGZfY29tcGxbLCBuZWRhX3BhcnQxX2lkeF0sIG5hcGVyY2VudCA9IC41LCBlbmdpbmUgPSAic3VtIikNCmBgYA0KDQojIyBNZW50YWwgSGVhbHRoIGRlc2NyaXB0aXZlcw0KDQojIyMgU2NyZWVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Mjh9DQpkZlssIHNjcmVlbl8xX2lkeF0gJT4lICAgICAjIG1hcCh+IGF0dHIoLngsICJsYWJlbCIpKSAgIyBnZXQgaXRlbSB0ZXh0DQogIHNldE5hbWVzKA0KICAgIHB1cnJyOjptYXAoLiwgfiBhdHRyKC54LCAibGFiZWwiKSkgJT4lIA0KICAgICAgc3RyX3JlcGxhY2UoIsOObiB1bHRpbWVsZSBET1XEgi4qJCIsICIiKSAlPiUgIA0KICAgICAgc3RyX3dyYXAoNjApDQogICkgJT4lIA0KICBzY3JlZW5fMV9yZWNvZGUoKSAlPiUgDQogIG11dGF0ZV9hbGwoYXMuZmFjdG9yKSAlPiUgDQogIGxpa2VydCgpICU+JSANCiAgcGxvdCgpICsNCiAgdGhlbWUoIyB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQ0KDQpkZlssIHNjcmVlbl8yX2lkeF0gJT4lICAgICAjIG1hcCh+IGF0dHIoLngsICJsYWJlbCIpKSAgIyBnZXQgaXRlbSB0ZXh0DQogIHNldE5hbWVzKA0KICAgIHB1cnJyOjptYXAoLiwgfiBhdHRyKC54LCAibGFiZWwiKSkgJT4lIA0KICAgICAgc3RyX3JlcGxhY2UoIsOObiB1bHRpbWVsZSBET1XEgi4qJCIsICIiKSAlPiUgIA0KICAgICAgc3RyX3dyYXAoNjApDQogICkgJT4lIA0KICBzY3JlZW5fMl9yZWNvZGUoKSAlPiUgDQogIG11dGF0ZV9hbGwoYXMuZmFjdG9yKSAlPiUgDQogIGxpa2VydCgpICU+JSANCiAgcGxvdCgpICsNCiAgdGhlbWUoIyB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgDQpgYGANCg0KIyMjIFNhbWUgcGxvdCB3aXRob3V0IFN1aWNpZGUgDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KZGZbLCBzY3JlZW5fMl9pZHhdICU+JSAgICAgIyBtYXAofiBhdHRyKC54LCAibGFiZWwiKSkgICMgZ2V0IGl0ZW0gdGV4dA0KICBzZWxlY3QoLUcwMlE0OCkgJT4lICAjIHJlbW92ZSB0aGUgc3VpY2lkZSBpdGVtDQogIHNldE5hbWVzKA0KICAgIHB1cnJyOjptYXAoLiwgfiBhdHRyKC54LCAibGFiZWwiKSkgJT4lIA0KICAgICAgc3RyX3JlcGxhY2UoIsOObiB1bHRpbWVsZSBET1XEgi4qJCIsICIiKSAlPiUgIA0KICAgICAgc3RyX3dyYXAoNjApDQogICkgJT4lIA0KICBzY3JlZW5fMl9yZWNvZGUoKSAlPiUgDQogIG11dGF0ZV9hbGwoYXMuZmFjdG9yKSAlPiUgDQogIGxpa2VydCgpICU+JSANCiAgcGxvdCgpICsNCiAgdGhlbWUoIyB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgDQpgYGANCg0KIyMjIEFESEQNCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fQ0KZGZfY29tcGwkYWRoZCAlPiUgDQogIHF1aWNrX3Njb3JlX2hpc3QoIkFESEQiKQ0KYGBgDQoNCiMjIyBQSFEtOQ0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9DQpkZl9jb21wbCRwaHEgJT4lIA0KICBxdWlja19zY29yZV9oaXN0KHhsYWIgPSAiRGVwcmVzaWUiLCBuYS5ybSA9IFRSVUUpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9ICIoMTAsMTJdIiwgY29sb3IgPSAicmVkIikgICMgY3V0b2ZmIDExDQpgYGANCg0KIyMjIEdBRC03DQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0NCmRmX2NvbXBsJGdhZCAlPiUgDQogIHF1aWNrX3Njb3JlX2hpc3QoeGxhYiA9ICJEZXByZXNpZSIsIG5hLnJtID0gVFJVRSkgKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gIig4LDEwXSIsIGNvbG9yID0gInJlZCIpICAjIGN1dG9mZiAxMA0KYGBgDQoNCiMjIyBTTVNBRA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9DQpkZl9jb21wbCRzbXNhZCAlPiUgDQogIHF1aWNrX3Njb3JlX2hpc3QoeGxhYiA9ICJEZXByZXNpZSIsIG5hLnJtID0gVFJVRSkgKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gIigyMCwyNV0iLCBjb2xvciA9ICJyZWQiKSAgIyBjdXRvZmYgMjANCmBgYA0KDQoNCg0KDQo8IS0tIFNlc3Npb24gSW5mbyBhbmQgTGljZW5zZSAtLT4NCg0KPGJyPg0KDQojIFNlc3Npb24gSW5mbw0KYGBge3Igc2Vzc2lvbl9pbmZvLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnbWFya3VwJ30NCnNlc3Npb25JbmZvKCkgICAgDQpgYGANCg0KPCEtLSBGb290ZXIgLS0+DQombmJzcDsNCjxociAvPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPkEgd29yayBieSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQ2xhdWRpdVBhcGFzdGVyaS8iPkNsYXVkaXUgUGFwYXN0ZXJpPC9hPjwvcD4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDgwODA7Ij48ZW0+Y2xhdWRpdS5wYXBhc3RlcmlAZ21haWwuY29tPC9lbT48L3NwYW4+PC9wPg0KJm5ic3A7DQo=