1 Read, Clean, Recode, Merge

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read, Clean, Recode, Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Read files
folder <- "E:/Cinetic idei noi/Cinetic elevi"
file <- "A13 Tabel 3.xlsx"
setwd(folder)
Data <- rio::import(file.path(folder, file),
                           skip = 1)
## Tidy up data
# Function coalesce rows: colapse when NA, unite with "_" when not NA
coalesce2 <- function(...) {
  Reduce(function(x, y) {
    i <- which(is.na(x))
    j <- which(!is.na(x) & !is.na(y))
    x[i] <- y[i]
    x[j] <- paste(x[j], y[j], sep = "_")
    x},
    list(...))
}
colnames(Data) <- coalesce2(Data[2,], Data[3,])
Data <- Data[-c(1:3),]
## Check duplicate column names due to excel
tibble::enframe(names(Data)) %>% 
  dplyr::count(value) %>% 
  dplyr::filter(n > 1)
## Make valid column names (no duplicates)
validate.names = function(df){
  rtn = df
  valid_column_names = make.names(names = names(df), unique = TRUE, allow_ = TRUE)
  names(rtn) = valid_column_names
  rtn
}
Data <- 
  Data %>% 
  validate.names() %>%                                       # make.names()
  rename_all(~stringr::str_replace_all(., "\\.", "_"))       # make.names() uses ".", change to "_"
## Delete columns with only NA
Data <-
  Data %>%
  select_if(~!(all(is.na(.)) | all(. == "")))
## Rename columns corresponding to items
# Function to paste a string before column name if it doesnt already start with that string
paste_tocolnames <- function(vec_colnames, string_paste){
  ind <- grep(pattern = string_paste, vec_colnames)                   # ignore column that already has string patterm
  vec_colnames[-ind] <- paste0(string_paste, vec_colnames[-ind])      # paste pattern to the rest of them
  return(vec_colnames)
}
colnames(Data)[6:25] <- paste_tocolnames(colnames(Data)[6:25], "PANAS_pre_")
colnames(Data)[61:64] <- paste_tocolnames(colnames(Data)[61:64], "SRS_post_")
colnames(Data)[65:84] <- paste_tocolnames(colnames(Data)[65:84], "PANAS_post_")
Data <- 
  Data %>% 
  rename_all(~stringr::str_replace_all(., "_\\d", ""))              # delete pattern "_1" that was introduced for duplicate column names
colnames(Data) <- enc2native(colnames(Data))      # fix encoding
## Recode known missing values
# str(Data_psiho, list.len = ncol(Data_psiho))
# str(Data_psiho, list.len = ncol(Data_psiho))
Data <-
  Data %>%
  replace(. == "/", NA) %>%                                     # missing values are coded "/"
  replace(. == "-", NA) %>%                                     # missing values are coded "-"
  replace(. == "NA", NA)                                        # missing values are coded "NA"
## Check for non-numeric elements in data sets
check_numeric1 <- as.data.frame(sapply(Data, varhandle::check.numeric)) 
# sapply(check_numeric1, function(x) length(which(!x)))     # look at columns with non-numeric and count of non-numeric values
nonnumeric1 <- sapply(check_numeric1, function(x) which(!x, arr.ind = TRUE))    # find row numbers for non-numeric values
nonnumeric1[lapply(nonnumeric1, length) > 0]                                   # return only columns and rown numbers were non-numeric
## Recode to numeric
Data <- 
  Data %>% 
  mutate_at(vars(6:84), funs(as.numeric(as.character(.))))  
## Recode ID 
Data <-
  Data %>%
  dplyr::rename(ID = `Indica_tiv_subiect`) 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Scoring Questionnaires
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Define function that calculates RowSums but only for rows with less than 10% NAs; and return NA if all row values are NA 
SpecialRowSums <- function(df, napercent = .1) {
  ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
         NA,
         rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
  )
}
## --  APS NOT ADMINISTERED --
## APS: simple sum 
# Data_teatru$`APS pre_Total` <- SpecialRowSums(Data_teatru[ ,sprintf("APS pre_%d", 1:16)], napercent = .13)  # not more than 2 NAs for 16 items
# Data_teatru$`APS post_Total` <- SpecialRowSums(Data_teatru[ ,sprintf("APS post_%d", 1:16)], napercent = .13)
## --  PSS NOT ADMINISTERED --
## PSS-SF 14: Items 4, 5, 6, 7, 9, 10, and 13 are scored in reverse direction.
# keys_PSS <- c(1,1,1,-1,-1,-1,-1,1,-1,-1,1,1,-1,1)
# 
# Data_teatru$`PPS pre_Total` <- 
#   SpecialRowSums(
#   psych::reverse.code(items = Data_teatru[ ,sprintf("PPS pre_%d", 1:14)], keys = keys_PSS,  mini = 0, maxi = 4),
#   napercent = .1)  # not more than 1 NAs for 14 items 
# Data_teatru$`PPS post_Total` <- 
#   SpecialRowSums(
#     psych::reverse.code(items = Data_teatru[ ,sprintf("PPS post_%d", 1:14)], keys = keys_PSS,  mini = 0, maxi = 4),
#     napercent = .1)
## PANAS: Positive Affect Score = sum items 1, 3, 5, 9, 10, 12, 14, 16, 17, 19. Negative Affect Score = sum items 2, 4, 6, 7, 8, 11, 13, 15, 18, 20.
Data$PA_pre_Total <- SpecialRowSums(Data[ ,5 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11) # not more than 1 NAs for 10 items
Data$NA_pre_Total <- SpecialRowSums(Data[ ,5 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
Data$PA_post_Total <- SpecialRowSums(Data[ ,64 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11) 
Data$NA_post_Total <- SpecialRowSums(Data[ ,64 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
## Make data frames for Etapa III and IV
Data_III <- subset(Data, Etapa == "III")
Data_IV <- subset(Data, Etapa == "IV")

2 Sample descriptives

cat("## Number of subjects")
## Number of subjects
Data %>% 
 dplyr::summarise(count = dplyr::n_distinct(ID))
cat("## Number of subjects by Etapa")
## Number of subjects by Etapa
Data %>%
 group_by(Etapa) %>%
 dplyr::summarise(count = dplyr::n_distinct(ID))

3 Define Funtion for Pre-Post Comparison

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   OUTCOMES PRE-POST INTERVENTION   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function to run for diffrent dataframes (in this case: Etapa III and Iv)
## Func wilcox, t test & simple boxplot
func_wilcox_box <- function(df, ind, pre_var, post_var){
  df_modif <-
    df %>%
    select(ind, pre_var, post_var) %>% 
    tidyr::drop_na() %>%
    gather(pre_var, post_var, key = "Cond", value = "value") %>% 
    mutate_at(vars(c(1, 2)), funs(as.factor)) %>% 
    mutate(Cond = factor(Cond, levels = c(pre_var, post_var))) 
  
  stat_comp <- ggpubr::compare_means(value ~ Cond, data = df_modif, method = "wilcox.test", paired = TRUE)
  
  stat_comp2 <-
    df_modif %>% 
    do(tidy(t.test(.$value ~ .$Cond,
                   paired = TRUE,
                   data=.)))
  
  plot <- 
    ggpubr::ggpaired(df_modif, x = "Cond", y = "value", id = ind, 
                     color = "Cond", line.color = "gray", line.size = 0.4,
                     palette = c("#00AFBB", "#FC4E07"), legend = "none") +
      stat_summary(fun.data = mean_se,  colour = "darkred") +
      ggpubr::stat_compare_means(method = "wilcox.test", paired = TRUE, label.x = as.numeric(df_modif$Cond)-0.4, label.y = max(df_modif$value)+4) + 
      ggpubr::stat_compare_means(method = "wilcox.test", paired = TRUE, label = "p.signif", comparisons = list(c(pre_var, post_var)))
  
  cat(paste0("#### ", pre_var, " ", post_var, "\n", "\n"))
  print(stat_comp)
  print(stat_comp2)
  print(plot)
}

4 IOS

4.1 IOS Pre-Post Intervention - Whole Sample

## Run function func_wilcox_box() on whole sample
func_wilcox_box(Data, "ID", "IOS_pre", "IOS_post") 

4.1.0.1 IOS_pre IOS_post

4.2 IOS Pre-Post Intervention for each Etapa

## Run function func_wilcox_box() for Etapa III
cat("### Etapa III")

4.2.1 Etapa III

func_wilcox_box(Data_III, "ID", "IOS_pre", "IOS_post") 

4.2.1.1 IOS_pre IOS_post

## Run function for func_wilcox_box() Etapa IV
cat("### Etapa IV")

4.2.2 Etapa IV

func_wilcox_box(Data_IV, "ID", "IOS_pre", "IOS_post") 

4.2.2.1 IOS_pre IOS_post

5 PANAS

5.1 PANAS Pre-Post Intervention - Whole Sample

## Run function func_wilcox_box() on whole sample
func_wilcox_box(Data, "ID", "PA_pre_Total", "PA_post_Total") 

5.1.0.1 PA_pre_Total PA_post_Total

func_wilcox_box(Data, "ID", "NA_pre_Total", "NA_post_Total") 

5.1.0.2 NA_pre_Total NA_post_Total

5.2 PANAS Pre-Post Intervention for each Etapa

## Run function func_wilcox_box() for Etapa III
cat("### Etapa III")

5.2.1 Etapa III

func_wilcox_box(Data_III, "ID", "PA_pre_Total", "PA_post_Total") 

5.2.1.1 PA_pre_Total PA_post_Total

func_wilcox_box(Data_III, "ID", "NA_pre_Total", "NA_post_Total") 

5.2.1.2 NA_pre_Total NA_post_Total

## Run function for func_wilcox_box() Etapa IV
cat("### Etapa IV")

5.2.2 Etapa IV

func_wilcox_box(Data_IV, "ID", "PA_pre_Total", "PA_post_Total") 

5.2.2.1 PA_pre_Total PA_post_Total

func_wilcox_box(Data_IV, "ID", "NA_pre_Total", "NA_post_Total")

5.2.2.2 NA_pre_Total NA_post_Total

6 VAS variables for Etapa III

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   Variables multiple measurements in zi    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function plot pre-ex1-ex2-..-post data for Etapa III
plot_preexpost_ex <- function(df, pre_var, post_x1_var, post_x2_var, post_x3_var, post_x4_var, post_x5_var, post_x6_var){
  df_modif <-
    df %>%
    gather(pre_var, post_x1_var, post_x2_var, post_x3_var, post_x4_var, post_x5_var, post_x6_var, key = "variable", value = "value") %>%
    mutate(variable = factor(variable, levels = c(pre_var, post_x1_var, post_x2_var, post_x3_var, post_x4_var, post_x5_var, post_x6_var)))
    
  # Wilcox test
  stat.test1 <-
    df_modif %>%
    # group_by(Etapa) %>%                             # no need .. going by Etapa separatly
    tidyr::drop_na(value) %>%                                 # filter so grouping factor levels get droped and we can compare with uneven levels
    rstatix::wilcox_test(value ~ variable) %>%                # pairwise
    rstatix::add_significance("p") %>%
    filter(p.signif != "ns")
  
  # t test
  stat.test2 <-
    df_modif %>%
    # group_by(Etapa) %>%                                # no need .. going by Etapa separatly
    tidyr::drop_na(value) %>%                                 # filter so grouping factor levels get droped and we can compare with uneven levels
    rstatix::t_test(value ~ variable) %>%                # pairwise
    rstatix::add_significance("p") %>%                                    
    filter(p.signif != "ns") 
  
  p<-
    ggplot(df_modif, aes(y = value, x = variable)) +
      # facet_wrap(~Etapa, nrow = 1) +                     # no need .. going by Etapa separatly
      ggtitle(deparse(substitute(df))) + 
      geom_boxplot() + stat_summary(fun.data = mean_se,  colour = "darkred") +
      theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
      ggpubr::stat_pvalue_manual(stat.test1, label = "p.signif",
                         y.position = seq(max(df_modif$value, na.rm = TRUE)+2, max(df_modif$value, na.rm = TRUE)*2,
                                          length.out = nrow(stat.test1)))                                                  # very hacky
  cat("#### Wilcoxon test")
  return(stat.test1) %>% print(n = Inf)
  cat("#### t test")
  return(stat.test2) %>% print(n = Inf)
  p
}
cat("## VAS stres")                # names(Data[, grep("VAS_stres", names(Data))])

6.1 VAS stres

plot_preexpost_ex(Data_III, 
                  "VAS_stres_pre", "VAS_stres_post_ex1", 
                  "VAS_stres_post_ex2", "VAS_stres_post_ex3",
                  "VAS_stres_post_ex4", "VAS_stres_post_ex5", "VAS_stres_post_ex6")

6.1.0.1 Wilcoxon test

6.1.0.2 t test

cat("## VAS stare de bine")       # names(Data[, grep("VAS_stare_de", names(Data))])

6.2 VAS stare de bine

plot_preexpost_ex(Data_III,
                  "VAS_stare_de_bine_pre", "VAS_stare_de_bine_post_ex1", 
                  "VAS_stare_de_bine_post_ex2", "VAS_stare_de_bine_post_ex3",
                  "VAS_stare_de_bine_post_ex4", "VAS_stare_de_bine_post_ex5", "VAS_stare_de_bine_post_ex6")

6.2.0.1 Wilcoxon test

6.2.0.2 t test

cat("## VAS corp")                # names(Data[, grep("VAS_corp", names(Data))])

6.3 VAS corp

plot_preexpost_ex(Data_III, 
                  "VAS_corp_pre", "VAS_corp_post_ex1",
                  "VAS_corp_post_ex2", "VAS_corp_post_ex3",
                  "VAS_corp_post_ex4", "VAS_corp_post_ex5", "VAS_corp_post_ex6")

6.3.0.1 Wilcoxon test

6.3.0.2 t test

7 VAS variables for Etapa IV

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   Variables multiple measurements in zi    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Function plot pre-ex1-ex2-..-post data for Etapa III
plot_preexpost_ex4 <- function(df, pre_var, post_x1_var, post_x2_var){
  df_modif <-
    df %>%
    gather(pre_var, post_x1_var, post_x2_var, key = "variable", value = "value") %>%
    mutate(variable = factor(variable, levels = c(pre_var, post_x1_var, post_x2_var)))
    
  # Wilcox test
  stat.test1 <-
    df_modif %>%
    # group_by(Etapa) %>%                             # no need .. going by Etapa separatly
    tidyr::drop_na(value) %>%                                 # filter so grouping factor levels get droped and we can compare with uneven levels
    rstatix::wilcox_test(value ~ variable) %>%                # pairwise
    rstatix::add_significance("p") %>%
    filter(p.signif != "ns")
  
  # t test
  stat.test2 <-
    df_modif %>%
    # group_by(Etapa) %>%                                # no need .. going by Etapa separatly
    tidyr::drop_na(value) %>%                                 # filter so grouping factor levels get droped and we can compare with uneven levels
    rstatix::t_test(value ~ variable) %>%                # pairwise
    rstatix::add_significance("p") %>%                                    
    filter(p.signif != "ns") 
  
  p <-
    ggplot(df_modif, aes(y = value, x = variable)) +
      # facet_wrap(~Etapa, nrow = 1) +                     # no need .. going by Etapa separatly
      ggtitle(deparse(substitute(df))) + 
      geom_boxplot() + stat_summary(fun.data = mean_se,  colour = "darkred") +
      theme(axis.text.x = element_text(angle = 90, hjust = 1)) 
  
  if(dim(stat.test1)[1] != 0) {     # do this only if the significance dataframe has > 0 rows
    p <- 
      p +
      ggpubr::stat_pvalue_manual(stat.test1, label = "p.signif",
                         y.position = seq(max(df_modif$value, na.rm = TRUE)+2, max(df_modif$value, na.rm = TRUE)*2,
                                          length.out = nrow(stat.test1)))                                                  # very hacky
  }
  
  cat("#### Wilcoxon test")
  return(stat.test1) %>% print(n = Inf)
  cat("#### t test")
  return(stat.test2) %>% print(n = Inf)
  p
}
cat("## VAS stres")                # names(Data[, grep("VAS_stres", names(Data))])

7.1 VAS stres

plot_preexpost_ex4(Data_IV, 
                  "VAS_stres_pre", "VAS_stres_post_ex1", "VAS_stres_post_ex2")

7.1.0.1 Wilcoxon test

7.1.0.2 t test

cat("## VAS stare de bine")       # names(Data[, grep("VAS_stare_de", names(Data))])

7.2 VAS stare de bine

plot_preexpost_ex4(Data_IV,
                  "VAS_stare_de_bine_pre", "VAS_stare_de_bine_post_ex1", "VAS_stare_de_bine_post_ex2")

7.2.0.1 Wilcoxon test

7.2.0.2 t test

cat("## VAS corp")                # names(Data[, grep("VAS_corp", names(Data))])

7.3 VAS corp

plot_preexpost_ex4(Data_IV, 
                  "VAS_corp_pre", "VAS_corp_post_ex1", "VAS_corp_post_ex2")

7.3.0.1 Wilcoxon test

7.3.0.2 t test



8 Session Info

R version 3.5.2 (2018-12-20)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

Matrix products: default

locale:
[1] LC_COLLATE=Romanian_Romania.1250  LC_CTYPE=Romanian_Romania.1250    LC_MONETARY=Romanian_Romania.1250 LC_NUMERIC=C                     
[5] LC_TIME=Romanian_Romania.1250    

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

other attached packages:
 [1] bindrcpp_0.2.2             rio_0.5.16                 scales_1.0.0               ggpubr_0.2                 magrittr_1.5              
 [6] tadaatoolbox_0.16.1        summarytools_0.9.3         rstatix_0.1.2              broom_0.5.1                PerformanceAnalytics_1.5.2
[11] xts_0.11-2                 zoo_1.8-4                  psych_1.8.10               plyr_1.8.4                 forcats_0.3.0             
[16] stringr_1.3.1              dplyr_0.7.8                purrr_0.2.5                readr_1.3.0                tidyr_0.8.2               
[21] tibble_1.4.2               ggplot2_3.2.0              tidyverse_1.2.1            papaja_0.1.0.9842          pacman_0.5.1              

loaded via a namespace (and not attached):
 [1] nlme_3.1-137       bitops_1.0-6       matrixStats_0.54.0 lubridate_1.7.4    httr_1.4.0         tools_3.5.2        backports_1.1.3   
 [8] R6_2.4.0           nortest_1.0-4      lazyeval_0.2.1     colorspace_1.3-2   withr_2.1.2        tidyselect_0.2.5   gridExtra_2.3     
[15] mnormt_1.5-5       pixiedust_0.8.6    curl_4.0           compiler_3.5.2     cli_1.0.1          rvest_0.3.2        expm_0.999-3      
[22] xml2_1.2.0         labeling_0.3       checkmate_1.8.5    mvtnorm_1.0-11     quadprog_1.5-5     digest_0.6.18      foreign_0.8-71    
[29] pkgconfig_2.0.2    htmltools_0.3.6    manipulate_1.0.1   pwr_1.2-2          rlang_0.4.0        readxl_1.1.0       rstudioapi_0.8    
[36] pryr_0.1.4         bindr_0.1.1        generics_0.0.2     jsonlite_1.6       zip_1.0.0          car_3.0-2          RCurl_1.95-4.11   
[43] rapportools_1.0    Matrix_1.2-15      Rcpp_1.0.2         DescTools_0.99.28  munsell_0.5.0      abind_1.4-5        viridis_0.5.1     
[50] stringi_1.2.4      yaml_2.2.0         carData_3.0-2      MASS_7.3-51.1      grid_3.5.2         parallel_3.5.2     crayon_1.3.4      
[57] lattice_0.20-38    haven_2.1.1        pander_0.6.3       hms_0.4.2          magick_2.0         knitr_1.24         pillar_1.3.1      
[64] varhandle_2.0.3    tcltk_3.5.2        boot_1.3-20        ggsignif_0.4.0     codetools_0.2-15   glue_1.3.1         data.table_1.12.2 
[71] modelr_0.1.2       cellranger_1.1.0   gtable_0.2.0       assertthat_0.2.1   xfun_0.8           openxlsx_4.1.0     viridisLite_0.3.0 
 

A work by Claudiu Papasteri

claudiu.papasteri@gmail.com

 

LS0tDQp0aXRsZTogIjxicj4gRHJhbWEgRXhlcmNpc2VzIiANCnN1YnRpdGxlOiAiQ2luZXRpYyBTdW1tZXIgU2Nob29sIg0KYXV0aG9yOiAiPGJyPiBDbGF1ZGl1IFBhcGFzdGVyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVtICVZJylgIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgICAgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICB0aGVtZTogc3BhY2VsYWINCiAgICAgICAgICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbA0KICAgICAgICAgICAgZmlnX3dpZHRoOiAxMA0KICAgICAgICAgICAgZmlnX2hlaWdodDogOQ0KICAgICMgd29yZF9kb2N1bWVudCAgICAgICAgDQogICAgIyBwZGZfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBUUlVFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgInBseXIiLCAgICAgIA0KICAicHN5Y2giLCAiUGVyZm9ybWFuY2VBbmFseXRpY3MiLCAgICAgICAgICANCiAgImJyb29tIiwgInJzdGF0aXgiLA0KICAic3VtbWFyeXRvb2xzIiwgInRhZGFhdG9vbGJveCIsICAgICAgICAgICANCiAgImdncGxvdDIiLCAiZ2dwdWJyIiwgInNjYWxlcyIsICAgICAgICANCiAgInJpbyINCiAgIyAsIC4uLg0KKQ0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcykNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdGluZyAoaGVyZSB1c2VkIEFQQSBzdHlsZSkNCnRoZW1lX3NldCh0aGVtZV9hcGEoKSkNCg0KDQojIFRhYmxlcyBrbml0dGluZyB0byBXb3JkDQpkb2MudHlwZSA8LSBrbml0cjo6b3B0c19rbml0JGdldCgncm1hcmtkb3duLnBhbmRvYy50bycpICAjIHRoZW4gZm9ybWF0IHRhYmxlcyB1c2luZyBhbiBpZiBzdGF0ZW1lbnQgbGlrZToNCiMgaWYgKGRvYy50eXBlID09ICJkb2N4IikgeyBwYW5kZXI6OnBhbmRlcihkZikgfSBlbHNlIHsga25pdHI6OmthYmxlKGRmKSB9DQpgYGANCg0KDQoNCg0KDQo8IS0tIFJlcG9ydCAtLT4NCg0KDQojIFJlYWQsIENsZWFuLCBSZWNvZGUsIE1lcmdlDQoNCmBgYHtyIHJlZF9jbGVhbl9yZWNvZGVfbWVyZ2UsIHJlc3VsdHM9J2hpZGUnfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgUmVhZCwgQ2xlYW4sIFJlY29kZSwgVW5pdGUNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQoNCiMjIFJlYWQgZmlsZXMNCmZvbGRlciA8LSAiRTovQ2luZXRpYyBpZGVpIG5vaS9DaW5ldGljIGVsZXZpIg0KZmlsZSA8LSAiQTEzIFRhYmVsIDMueGxzeCINCg0Kc2V0d2QoZm9sZGVyKQ0KRGF0YSA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQojIyBUaWR5IHVwIGRhdGENCiMgRnVuY3Rpb24gY29hbGVzY2Ugcm93czogY29sYXBzZSB3aGVuIE5BLCB1bml0ZSB3aXRoICJfIiB3aGVuIG5vdCBOQQ0KY29hbGVzY2UyIDwtIGZ1bmN0aW9uKC4uLikgew0KICBSZWR1Y2UoZnVuY3Rpb24oeCwgeSkgew0KICAgIGkgPC0gd2hpY2goaXMubmEoeCkpDQogICAgaiA8LSB3aGljaCghaXMubmEoeCkgJiAhaXMubmEoeSkpDQogICAgeFtpXSA8LSB5W2ldDQogICAgeFtqXSA8LSBwYXN0ZSh4W2pdLCB5W2pdLCBzZXAgPSAiXyIpDQogICAgeH0sDQogICAgbGlzdCguLi4pKQ0KfQ0KDQpjb2xuYW1lcyhEYXRhKSA8LSBjb2FsZXNjZTIoRGF0YVsyLF0sIERhdGFbMyxdKQ0KRGF0YSA8LSBEYXRhWy1jKDE6MyksXQ0KDQoNCiMjIENoZWNrIGR1cGxpY2F0ZSBjb2x1bW4gbmFtZXMgZHVlIHRvIGV4Y2VsDQp0aWJibGU6OmVuZnJhbWUobmFtZXMoRGF0YSkpICU+JSANCiAgZHBseXI6OmNvdW50KHZhbHVlKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIobiA+IDEpDQoNCiMjIE1ha2UgdmFsaWQgY29sdW1uIG5hbWVzIChubyBkdXBsaWNhdGVzKQ0KdmFsaWRhdGUubmFtZXMgPSBmdW5jdGlvbihkZil7DQogIHJ0biA9IGRmDQogIHZhbGlkX2NvbHVtbl9uYW1lcyA9IG1ha2UubmFtZXMobmFtZXMgPSBuYW1lcyhkZiksIHVuaXF1ZSA9IFRSVUUsIGFsbG93XyA9IFRSVUUpDQogIG5hbWVzKHJ0bikgPSB2YWxpZF9jb2x1bW5fbmFtZXMNCiAgcnRuDQp9DQoNCkRhdGEgPC0gDQogIERhdGEgJT4lIA0KICB2YWxpZGF0ZS5uYW1lcygpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWFrZS5uYW1lcygpDQogIHJlbmFtZV9hbGwofnN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCguLCAiXFwuIiwgIl8iKSkgICAgICAgIyBtYWtlLm5hbWVzKCkgdXNlcyAiLiIsIGNoYW5nZSB0byAiXyINCg0KIyMgRGVsZXRlIGNvbHVtbnMgd2l0aCBvbmx5IE5BDQpEYXRhIDwtDQogIERhdGEgJT4lDQogIHNlbGVjdF9pZih+IShhbGwoaXMubmEoLikpIHwgYWxsKC4gPT0gIiIpKSkNCg0KDQojIyBSZW5hbWUgY29sdW1ucyBjb3JyZXNwb25kaW5nIHRvIGl0ZW1zDQojIEZ1bmN0aW9uIHRvIHBhc3RlIGEgc3RyaW5nIGJlZm9yZSBjb2x1bW4gbmFtZSBpZiBpdCBkb2VzbnQgYWxyZWFkeSBzdGFydCB3aXRoIHRoYXQgc3RyaW5nDQpwYXN0ZV90b2NvbG5hbWVzIDwtIGZ1bmN0aW9uKHZlY19jb2xuYW1lcywgc3RyaW5nX3Bhc3RlKXsNCiAgaW5kIDwtIGdyZXAocGF0dGVybiA9IHN0cmluZ19wYXN0ZSwgdmVjX2NvbG5hbWVzKSAgICAgICAgICAgICAgICAgICAjIGlnbm9yZSBjb2x1bW4gdGhhdCBhbHJlYWR5IGhhcyBzdHJpbmcgcGF0dGVybQ0KICB2ZWNfY29sbmFtZXNbLWluZF0gPC0gcGFzdGUwKHN0cmluZ19wYXN0ZSwgdmVjX2NvbG5hbWVzWy1pbmRdKSAgICAgICMgcGFzdGUgcGF0dGVybiB0byB0aGUgcmVzdCBvZiB0aGVtDQogIHJldHVybih2ZWNfY29sbmFtZXMpDQp9DQoNCmNvbG5hbWVzKERhdGEpWzY6MjVdIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YSlbNjoyNV0sICJQQU5BU19wcmVfIikNCmNvbG5hbWVzKERhdGEpWzYxOjY0XSA8LSBwYXN0ZV90b2NvbG5hbWVzKGNvbG5hbWVzKERhdGEpWzYxOjY0XSwgIlNSU19wb3N0XyIpDQpjb2xuYW1lcyhEYXRhKVs2NTo4NF0gPC0gcGFzdGVfdG9jb2xuYW1lcyhjb2xuYW1lcyhEYXRhKVs2NTo4NF0sICJQQU5BU19wb3N0XyIpDQoNCkRhdGEgPC0gDQogIERhdGEgJT4lIA0KICByZW5hbWVfYWxsKH5zdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoLiwgIl9cXGQiLCAiIikpICAgICAgICAgICAgICAjIGRlbGV0ZSBwYXR0ZXJuICJfMSIgdGhhdCB3YXMgaW50cm9kdWNlZCBmb3IgZHVwbGljYXRlIGNvbHVtbiBuYW1lcw0KDQpjb2xuYW1lcyhEYXRhKSA8LSBlbmMybmF0aXZlKGNvbG5hbWVzKERhdGEpKSAgICAgICMgZml4IGVuY29kaW5nDQoNCg0KIyMgUmVjb2RlIGtub3duIG1pc3NpbmcgdmFsdWVzDQojIHN0cihEYXRhX3BzaWhvLCBsaXN0LmxlbiA9IG5jb2woRGF0YV9wc2lobykpDQojIHN0cihEYXRhX3BzaWhvLCBsaXN0LmxlbiA9IG5jb2woRGF0YV9wc2lobykpDQpEYXRhIDwtDQogIERhdGEgJT4lDQogIHJlcGxhY2UoLiA9PSAiLyIsIE5BKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcyBhcmUgY29kZWQgIi8iDQogIHJlcGxhY2UoLiA9PSAiLSIsIE5BKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcyBhcmUgY29kZWQgIi0iDQogIHJlcGxhY2UoLiA9PSAiTkEiLCBOQSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcyBhcmUgY29kZWQgIk5BIg0KDQoNCiMjIENoZWNrIGZvciBub24tbnVtZXJpYyBlbGVtZW50cyBpbiBkYXRhIHNldHMNCmNoZWNrX251bWVyaWMxIDwtIGFzLmRhdGEuZnJhbWUoc2FwcGx5KERhdGEsIHZhcmhhbmRsZTo6Y2hlY2subnVtZXJpYykpIA0KIyBzYXBwbHkoY2hlY2tfbnVtZXJpYzEsIGZ1bmN0aW9uKHgpIGxlbmd0aCh3aGljaCgheCkpKSAgICAgIyBsb29rIGF0IGNvbHVtbnMgd2l0aCBub24tbnVtZXJpYyBhbmQgY291bnQgb2Ygbm9uLW51bWVyaWMgdmFsdWVzDQoNCm5vbm51bWVyaWMxIDwtIHNhcHBseShjaGVja19udW1lcmljMSwgZnVuY3Rpb24oeCkgd2hpY2goIXgsIGFyci5pbmQgPSBUUlVFKSkgICAgIyBmaW5kIHJvdyBudW1iZXJzIGZvciBub24tbnVtZXJpYyB2YWx1ZXMNCm5vbm51bWVyaWMxW2xhcHBseShub25udW1lcmljMSwgbGVuZ3RoKSA+IDBdICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJldHVybiBvbmx5IGNvbHVtbnMgYW5kIHJvd24gbnVtYmVycyB3ZXJlIG5vbi1udW1lcmljDQoNCiMjIFJlY29kZSB0byBudW1lcmljDQpEYXRhIDwtIA0KICBEYXRhICU+JSANCiAgbXV0YXRlX2F0KHZhcnMoNjo4NCksIGZ1bnMoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoLikpKSkgIA0KDQojIyBSZWNvZGUgSUQgDQpEYXRhIDwtDQogIERhdGEgJT4lDQogIGRwbHlyOjpyZW5hbWUoSUQgPSBgSW5kaWNhX3Rpdl9zdWJpZWN0YCkgDQoNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIFNjb3JpbmcgUXVlc3Rpb25uYWlyZXMNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBjYWxjdWxhdGVzIFJvd1N1bXMgYnV0IG9ubHkgZm9yIHJvd3Mgd2l0aCBsZXNzIHRoYW4gMTAlIE5BczsgYW5kIHJldHVybiBOQSBpZiBhbGwgcm93IHZhbHVlcyBhcmUgTkEgDQpTcGVjaWFsUm93U3VtcyA8LSBmdW5jdGlvbihkZiwgbmFwZXJjZW50ID0gLjEpIHsNCiAgaWZlbHNlKHJvd1N1bXMoaXMubmEoZGYpKSA+IG5jb2woZGYpICogbmFwZXJjZW50LA0KICAgICAgICAgTkEsDQogICAgICAgICByb3dTdW1zKGRmLCBuYS5ybSA9IFRSVUUpICogTkEgXiAocm93U3VtcyghaXMubmEoZGYpKSA9PSAwKQ0KICApDQp9DQoNCiMjIC0tICBBUFMgTk9UIEFETUlOSVNURVJFRCAtLQ0KIyMgQVBTOiBzaW1wbGUgc3VtIA0KIyBEYXRhX3RlYXRydSRgQVBTIHByZV9Ub3RhbGAgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YV90ZWF0cnVbICxzcHJpbnRmKCJBUFMgcHJlXyVkIiwgMToxNildLCBuYXBlcmNlbnQgPSAuMTMpICAjIG5vdCBtb3JlIHRoYW4gMiBOQXMgZm9yIDE2IGl0ZW1zDQojIERhdGFfdGVhdHJ1JGBBUFMgcG9zdF9Ub3RhbGAgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YV90ZWF0cnVbICxzcHJpbnRmKCJBUFMgcG9zdF8lZCIsIDE6MTYpXSwgbmFwZXJjZW50ID0gLjEzKQ0KDQojIyAtLSAgUFNTIE5PVCBBRE1JTklTVEVSRUQgLS0NCiMjIFBTUy1TRiAxNDogSXRlbXMgNCwgNSwgNiwgNywgOSwgMTAsIGFuZCAxMyBhcmUgc2NvcmVkIGluIHJldmVyc2UgZGlyZWN0aW9uLg0KIyBrZXlzX1BTUyA8LSBjKDEsMSwxLC0xLC0xLC0xLC0xLDEsLTEsLTEsMSwxLC0xLDEpDQojIA0KIyBEYXRhX3RlYXRydSRgUFBTIHByZV9Ub3RhbGAgPC0gDQojICAgU3BlY2lhbFJvd1N1bXMoDQojICAgcHN5Y2g6OnJldmVyc2UuY29kZShpdGVtcyA9IERhdGFfdGVhdHJ1WyAsc3ByaW50ZigiUFBTIHByZV8lZCIsIDE6MTQpXSwga2V5cyA9IGtleXNfUFNTLCAgbWluaSA9IDAsIG1heGkgPSA0KSwNCiMgICBuYXBlcmNlbnQgPSAuMSkgICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTQgaXRlbXMgDQojIERhdGFfdGVhdHJ1JGBQUFMgcG9zdF9Ub3RhbGAgPC0gDQojICAgU3BlY2lhbFJvd1N1bXMoDQojICAgICBwc3ljaDo6cmV2ZXJzZS5jb2RlKGl0ZW1zID0gRGF0YV90ZWF0cnVbICxzcHJpbnRmKCJQUFMgcG9zdF8lZCIsIDE6MTQpXSwga2V5cyA9IGtleXNfUFNTLCAgbWluaSA9IDAsIG1heGkgPSA0KSwNCiMgICAgIG5hcGVyY2VudCA9IC4xKQ0KDQoNCiMjIFBBTkFTOiBQb3NpdGl2ZSBBZmZlY3QgU2NvcmUgPSBzdW0gaXRlbXMgMSwgMywgNSwgOSwgMTAsIDEyLCAxNCwgMTYsIDE3LCAxOS4gTmVnYXRpdmUgQWZmZWN0IFNjb3JlID0gc3VtIGl0ZW1zIDIsIDQsIDYsIDcsIDgsIDExLCAxMywgMTUsIDE4LCAyMC4NCkRhdGEkUEFfcHJlX1RvdGFsIDwtIFNwZWNpYWxSb3dTdW1zKERhdGFbICw1ICsgYygxLDMsNSw5LDEwLDEyLDE0LDE2LDE3LDE5KV0sIG5hcGVyY2VudCA9IC4xMSkgIyBub3QgbW9yZSB0aGFuIDEgTkFzIGZvciAxMCBpdGVtcw0KRGF0YSROQV9wcmVfVG90YWwgPC0gU3BlY2lhbFJvd1N1bXMoRGF0YVsgLDUgKyBjKDIsNCw2LDcsOCwxMSwxMywxNSwxOCwyMCldLCBuYXBlcmNlbnQgPSAuMTEpDQoNCkRhdGEkUEFfcG9zdF9Ub3RhbCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhWyAsNjQgKyBjKDEsMyw1LDksMTAsMTIsMTQsMTYsMTcsMTkpXSwgbmFwZXJjZW50ID0gLjExKSANCkRhdGEkTkFfcG9zdF9Ub3RhbCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhWyAsNjQgKyBjKDIsNCw2LDcsOCwxMSwxMywxNSwxOCwyMCldLCBuYXBlcmNlbnQgPSAuMTEpDQoNCg0KIyMgTWFrZSBkYXRhIGZyYW1lcyBmb3IgRXRhcGEgSUlJIGFuZCBJVg0KRGF0YV9JSUkgPC0gc3Vic2V0KERhdGEsIEV0YXBhID09ICJJSUkiKQ0KRGF0YV9JViA8LSBzdWJzZXQoRGF0YSwgRXRhcGEgPT0gIklWIikNCmBgYA0KDQoNCiMgU2FtcGxlIGRlc2NyaXB0aXZlcw0KDQpgYGB7ciBzYW1wbGVfZGVzY30NCmNhdCgiIyMgTnVtYmVyIG9mIHN1YmplY3RzIikNCkRhdGEgJT4lIA0KIGRwbHlyOjpzdW1tYXJpc2UoY291bnQgPSBkcGx5cjo6bl9kaXN0aW5jdChJRCkpDQoNCmNhdCgiIyMgTnVtYmVyIG9mIHN1YmplY3RzIGJ5IEV0YXBhIikNCkRhdGEgJT4lDQogZ3JvdXBfYnkoRXRhcGEpICU+JQ0KIGRwbHlyOjpzdW1tYXJpc2UoY291bnQgPSBkcGx5cjo6bl9kaXN0aW5jdChJRCkpDQpgYGANCg0KDQojIERlZmluZSBGdW50aW9uIGZvciBQcmUtUG9zdCBDb21wYXJpc29uDQoNCmBgYHtyIGZ1bmNfd2lsY294fQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fiAgIE9VVENPTUVTIFBSRS1QT1NUIElOVEVSVkVOVElPTiAgIH5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMjIEZ1bmN0aW9uIHRvIHJ1biBmb3IgZGlmZnJlbnQgZGF0YWZyYW1lcyAoaW4gdGhpcyBjYXNlOiBFdGFwYSBJSUkgYW5kIEl2KQ0KIyMgRnVuYyB3aWxjb3gsIHQgdGVzdCAmIHNpbXBsZSBib3hwbG90DQpmdW5jX3dpbGNveF9ib3ggPC0gZnVuY3Rpb24oZGYsIGluZCwgcHJlX3ZhciwgcG9zdF92YXIpew0KICBkZl9tb2RpZiA8LQ0KICAgIGRmICU+JQ0KICAgIHNlbGVjdChpbmQsIHByZV92YXIsIHBvc3RfdmFyKSAlPiUgDQogICAgdGlkeXI6OmRyb3BfbmEoKSAlPiUNCiAgICBnYXRoZXIocHJlX3ZhciwgcG9zdF92YXIsIGtleSA9ICJDb25kIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUgDQogICAgbXV0YXRlX2F0KHZhcnMoYygxLCAyKSksIGZ1bnMoYXMuZmFjdG9yKSkgJT4lIA0KICAgIG11dGF0ZShDb25kID0gZmFjdG9yKENvbmQsIGxldmVscyA9IGMocHJlX3ZhciwgcG9zdF92YXIpKSkgDQogIA0KICBzdGF0X2NvbXAgPC0gZ2dwdWJyOjpjb21wYXJlX21lYW5zKHZhbHVlIH4gQ29uZCwgZGF0YSA9IGRmX21vZGlmLCBtZXRob2QgPSAid2lsY294LnRlc3QiLCBwYWlyZWQgPSBUUlVFKQ0KICANCiAgc3RhdF9jb21wMiA8LQ0KICAgIGRmX21vZGlmICU+JSANCiAgICBkbyh0aWR5KHQudGVzdCguJHZhbHVlIH4gLiRDb25kLA0KICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgZGF0YT0uKSkpDQogIA0KICBwbG90IDwtIA0KICAgIGdncHVicjo6Z2dwYWlyZWQoZGZfbW9kaWYsIHggPSAiQ29uZCIsIHkgPSAidmFsdWUiLCBpZCA9IGluZCwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJDb25kIiwgbGluZS5jb2xvciA9ICJncmF5IiwgbGluZS5zaXplID0gMC40LA0KICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9IGMoIiMwMEFGQkIiLCAiI0ZDNEUwNyIpLCBsZWdlbmQgPSAibm9uZSIpICsNCiAgICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsIHBhaXJlZCA9IFRSVUUsIGxhYmVsLnggPSBhcy5udW1lcmljKGRmX21vZGlmJENvbmQpLTAuNCwgbGFiZWwueSA9IG1heChkZl9tb2RpZiR2YWx1ZSkrNCkgKyANCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsIHBhaXJlZCA9IFRSVUUsIGxhYmVsID0gInAuc2lnbmlmIiwgY29tcGFyaXNvbnMgPSBsaXN0KGMocHJlX3ZhciwgcG9zdF92YXIpKSkNCiAgDQogIGNhdChwYXN0ZTAoIiMjIyMgIiwgcHJlX3ZhciwgIiAiLCBwb3N0X3ZhciwgIlxuIiwgIlxuIikpDQogIHByaW50KHN0YXRfY29tcCkNCiAgcHJpbnQoc3RhdF9jb21wMikNCiAgcHJpbnQocGxvdCkNCn0NCmBgYA0KDQojIElPUw0KIyMgSU9TIFByZS1Qb3N0IEludGVydmVudGlvbiAtIFdob2xlIFNhbXBsZQ0KDQpgYGB7ciBpb3Nfd2hvbGVzYW1wbGUsIGZpZy53aWR0aD02LCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5oZWlnaHQ9OCwgcmVzdWx0cz0nYXNpcyd9DQojIyBSdW4gZnVuY3Rpb24gZnVuY193aWxjb3hfYm94KCkgb24gd2hvbGUgc2FtcGxlDQpmdW5jX3dpbGNveF9ib3goRGF0YSwgIklEIiwgIklPU19wcmUiLCAiSU9TX3Bvc3QiKSANCmBgYA0KDQoNCiMjIElPUyBQcmUtUG9zdCBJbnRlcnZlbnRpb24gZm9yIGVhY2ggRXRhcGENCg0KYGBge3IgaW9zX2V0YXBhLCBmaWcud2lkdGg9NiwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuaGVpZ2h0PTgsIHJlc3VsdHM9J2FzaXMnfQ0KIyMgUnVuIGZ1bmN0aW9uIGZ1bmNfd2lsY294X2JveCgpIGZvciBFdGFwYSBJSUkNCmNhdCgiIyMjIEV0YXBhIElJSSIpDQpmdW5jX3dpbGNveF9ib3goRGF0YV9JSUksICJJRCIsICJJT1NfcHJlIiwgIklPU19wb3N0IikgDQoNCiMjIFJ1biBmdW5jdGlvbiBmb3IgZnVuY193aWxjb3hfYm94KCkgRXRhcGEgSVYNCmNhdCgiIyMjIEV0YXBhIElWIikNCmZ1bmNfd2lsY294X2JveChEYXRhX0lWLCAiSUQiLCAiSU9TX3ByZSIsICJJT1NfcG9zdCIpIA0KYGBgDQoNCiMgUEFOQVMNCiMjIFBBTkFTIFByZS1Qb3N0IEludGVydmVudGlvbiAtIFdob2xlIFNhbXBsZQ0KDQpgYGB7ciBwYW5hc193aG9sZXNhbXBsZSwgZmlnLndpZHRoPTYsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmhlaWdodD04LCByZXN1bHRzPSdhc2lzJ30NCiMjIFJ1biBmdW5jdGlvbiBmdW5jX3dpbGNveF9ib3goKSBvbiB3aG9sZSBzYW1wbGUNCmZ1bmNfd2lsY294X2JveChEYXRhLCAiSUQiLCAiUEFfcHJlX1RvdGFsIiwgIlBBX3Bvc3RfVG90YWwiKSANCmZ1bmNfd2lsY294X2JveChEYXRhLCAiSUQiLCAiTkFfcHJlX1RvdGFsIiwgIk5BX3Bvc3RfVG90YWwiKSANCmBgYA0KDQoNCiMjIFBBTkFTIFByZS1Qb3N0IEludGVydmVudGlvbiBmb3IgZWFjaCBFdGFwYQ0KDQpgYGB7ciBwYW5hc19ldGFwYSwgZmlnLndpZHRoPTYsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmhlaWdodD04LCByZXN1bHRzPSdhc2lzJ30NCiMjIFJ1biBmdW5jdGlvbiBmdW5jX3dpbGNveF9ib3goKSBmb3IgRXRhcGEgSUlJDQpjYXQoIiMjIyBFdGFwYSBJSUkiKQ0KZnVuY193aWxjb3hfYm94KERhdGFfSUlJLCAiSUQiLCAiUEFfcHJlX1RvdGFsIiwgIlBBX3Bvc3RfVG90YWwiKSANCmZ1bmNfd2lsY294X2JveChEYXRhX0lJSSwgIklEIiwgIk5BX3ByZV9Ub3RhbCIsICJOQV9wb3N0X1RvdGFsIikgDQoNCiMjIFJ1biBmdW5jdGlvbiBmb3IgZnVuY193aWxjb3hfYm94KCkgRXRhcGEgSVYNCmNhdCgiIyMjIEV0YXBhIElWIikNCmZ1bmNfd2lsY294X2JveChEYXRhX0lWLCAiSUQiLCAiUEFfcHJlX1RvdGFsIiwgIlBBX3Bvc3RfVG90YWwiKSANCmZ1bmNfd2lsY294X2JveChEYXRhX0lWLCAiSUQiLCAiTkFfcHJlX1RvdGFsIiwgIk5BX3Bvc3RfVG90YWwiKQ0KYGBgDQoNCg0KIyBWQVMgdmFyaWFibGVzIGZvciBFdGFwYSBJSUkNCg0KYGBge3IgdmFzX3ZhcmlhYmxlc19ldGFwYTMsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD0xMiwgcmVzdWx0cz0nYXNpcyd9DQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+ICAgVmFyaWFibGVzIG11bHRpcGxlIG1lYXN1cmVtZW50cyBpbiB6aSAgICB+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyMgRnVuY3Rpb24gcGxvdCBwcmUtZXgxLWV4Mi0uLi1wb3N0IGRhdGEgZm9yIEV0YXBhIElJSQ0KcGxvdF9wcmVleHBvc3RfZXggPC0gZnVuY3Rpb24oZGYsIHByZV92YXIsIHBvc3RfeDFfdmFyLCBwb3N0X3gyX3ZhciwgcG9zdF94M192YXIsIHBvc3RfeDRfdmFyLCBwb3N0X3g1X3ZhciwgcG9zdF94Nl92YXIpew0KICBkZl9tb2RpZiA8LQ0KICAgIGRmICU+JQ0KICAgIGdhdGhlcihwcmVfdmFyLCBwb3N0X3gxX3ZhciwgcG9zdF94Ml92YXIsIHBvc3RfeDNfdmFyLCBwb3N0X3g0X3ZhciwgcG9zdF94NV92YXIsIHBvc3RfeDZfdmFyLCBrZXkgPSAidmFyaWFibGUiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh2YXJpYWJsZSA9IGZhY3Rvcih2YXJpYWJsZSwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3gxX3ZhciwgcG9zdF94Ml92YXIsIHBvc3RfeDNfdmFyLCBwb3N0X3g0X3ZhciwgcG9zdF94NV92YXIsIHBvc3RfeDZfdmFyKSkpDQogICAgDQogICMgV2lsY294IHRlc3QNCiAgc3RhdC50ZXN0MSA8LQ0KICAgIGRmX21vZGlmICU+JQ0KICAgICMgZ3JvdXBfYnkoRXRhcGEpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBubyBuZWVkIC4uIGdvaW5nIGJ5IEV0YXBhIHNlcGFyYXRseQ0KICAgIHRpZHlyOjpkcm9wX25hKHZhbHVlKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZpbHRlciBzbyBncm91cGluZyBmYWN0b3IgbGV2ZWxzIGdldCBkcm9wZWQgYW5kIHdlIGNhbiBjb21wYXJlIHdpdGggdW5ldmVuIGxldmVscw0KICAgIHJzdGF0aXg6OndpbGNveF90ZXN0KHZhbHVlIH4gdmFyaWFibGUpICU+JSAgICAgICAgICAgICAgICAjIHBhaXJ3aXNlDQogICAgcnN0YXRpeDo6YWRkX3NpZ25pZmljYW5jZSgicCIpICU+JQ0KICAgIGZpbHRlcihwLnNpZ25pZiAhPSAibnMiKQ0KICANCiAgIyB0IHRlc3QNCiAgc3RhdC50ZXN0MiA8LQ0KICAgIGRmX21vZGlmICU+JQ0KICAgICMgZ3JvdXBfYnkoRXRhcGEpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBubyBuZWVkIC4uIGdvaW5nIGJ5IEV0YXBhIHNlcGFyYXRseQ0KICAgIHRpZHlyOjpkcm9wX25hKHZhbHVlKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZpbHRlciBzbyBncm91cGluZyBmYWN0b3IgbGV2ZWxzIGdldCBkcm9wZWQgYW5kIHdlIGNhbiBjb21wYXJlIHdpdGggdW5ldmVuIGxldmVscw0KICAgIHJzdGF0aXg6OnRfdGVzdCh2YWx1ZSB+IHZhcmlhYmxlKSAlPiUgICAgICAgICAgICAgICAgIyBwYWlyd2lzZQ0KICAgIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UoInAiKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICBmaWx0ZXIocC5zaWduaWYgIT0gIm5zIikgDQogIA0KICBwPC0NCiAgICBnZ3Bsb3QoZGZfbW9kaWYsIGFlcyh5ID0gdmFsdWUsIHggPSB2YXJpYWJsZSkpICsNCiAgICAgICMgZmFjZXRfd3JhcCh+RXRhcGEsIG5yb3cgPSAxKSArICAgICAgICAgICAgICAgICAgICAgIyBubyBuZWVkIC4uIGdvaW5nIGJ5IEV0YXBhIHNlcGFyYXRseQ0KICAgICAgZ2d0aXRsZShkZXBhcnNlKHN1YnN0aXR1dGUoZGYpKSkgKyANCiAgICAgIGdlb21fYm94cGxvdCgpICsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKw0KICAgICAgZ2dwdWJyOjpzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0MSwgbGFiZWwgPSAicC5zaWduaWYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkucG9zaXRpb24gPSBzZXEobWF4KGRmX21vZGlmJHZhbHVlLCBuYS5ybSA9IFRSVUUpKzIsIG1heChkZl9tb2RpZiR2YWx1ZSwgbmEucm0gPSBUUlVFKSoyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IG5yb3coc3RhdC50ZXN0MSkpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB2ZXJ5IGhhY2t5DQogIGNhdCgiIyMjIyBXaWxjb3hvbiB0ZXN0IikNCiAgcmV0dXJuKHN0YXQudGVzdDEpICU+JSBwcmludChuID0gSW5mKQ0KICBjYXQoIiMjIyMgdCB0ZXN0IikNCiAgcmV0dXJuKHN0YXQudGVzdDIpICU+JSBwcmludChuID0gSW5mKQ0KICBwDQp9DQoNCg0KY2F0KCIjIyBWQVMgc3RyZXMiKSAgICAgICAgICAgICAgICAjIG5hbWVzKERhdGFbLCBncmVwKCJWQVNfc3RyZXMiLCBuYW1lcyhEYXRhKSldKQ0KcGxvdF9wcmVleHBvc3RfZXgoRGF0YV9JSUksIA0KICAgICAgICAgICAgICAgICAgIlZBU19zdHJlc19wcmUiLCAiVkFTX3N0cmVzX3Bvc3RfZXgxIiwgDQogICAgICAgICAgICAgICAgICAiVkFTX3N0cmVzX3Bvc3RfZXgyIiwgIlZBU19zdHJlc19wb3N0X2V4MyIsDQogICAgICAgICAgICAgICAgICAiVkFTX3N0cmVzX3Bvc3RfZXg0IiwgIlZBU19zdHJlc19wb3N0X2V4NSIsICJWQVNfc3RyZXNfcG9zdF9leDYiKQ0KDQoNCmNhdCgiIyMgVkFTIHN0YXJlIGRlIGJpbmUiKSAgICAgICAjIG5hbWVzKERhdGFbLCBncmVwKCJWQVNfc3RhcmVfZGUiLCBuYW1lcyhEYXRhKSldKQ0KcGxvdF9wcmVleHBvc3RfZXgoRGF0YV9JSUksDQogICAgICAgICAgICAgICAgICAiVkFTX3N0YXJlX2RlX2JpbmVfcHJlIiwgIlZBU19zdGFyZV9kZV9iaW5lX3Bvc3RfZXgxIiwgDQogICAgICAgICAgICAgICAgICAiVkFTX3N0YXJlX2RlX2JpbmVfcG9zdF9leDIiLCAiVkFTX3N0YXJlX2RlX2JpbmVfcG9zdF9leDMiLA0KICAgICAgICAgICAgICAgICAgIlZBU19zdGFyZV9kZV9iaW5lX3Bvc3RfZXg0IiwgIlZBU19zdGFyZV9kZV9iaW5lX3Bvc3RfZXg1IiwgIlZBU19zdGFyZV9kZV9iaW5lX3Bvc3RfZXg2IikNCg0KDQpjYXQoIiMjIFZBUyBjb3JwIikgICAgICAgICAgICAgICAgIyBuYW1lcyhEYXRhWywgZ3JlcCgiVkFTX2NvcnAiLCBuYW1lcyhEYXRhKSldKQ0KcGxvdF9wcmVleHBvc3RfZXgoRGF0YV9JSUksIA0KICAgICAgICAgICAgICAgICAgIlZBU19jb3JwX3ByZSIsICJWQVNfY29ycF9wb3N0X2V4MSIsDQogICAgICAgICAgICAgICAgICAiVkFTX2NvcnBfcG9zdF9leDIiLCAiVkFTX2NvcnBfcG9zdF9leDMiLA0KICAgICAgICAgICAgICAgICAgIlZBU19jb3JwX3Bvc3RfZXg0IiwgIlZBU19jb3JwX3Bvc3RfZXg1IiwgIlZBU19jb3JwX3Bvc3RfZXg2IikNCmBgYA0KDQoNCiMgVkFTIHZhcmlhYmxlcyBmb3IgRXRhcGEgSVYNCg0KYGBge3IgdmFzX3ZhcmlhYmxlc19ldGFwYTQsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTgsIHJlc3VsdHM9J2FzaXMnfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fiAgIFZhcmlhYmxlcyBtdWx0aXBsZSBtZWFzdXJlbWVudHMgaW4gemkgICAgfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMjIEZ1bmN0aW9uIHBsb3QgcHJlLWV4MS1leDItLi4tcG9zdCBkYXRhIGZvciBFdGFwYSBJSUkNCnBsb3RfcHJlZXhwb3N0X2V4NCA8LSBmdW5jdGlvbihkZiwgcHJlX3ZhciwgcG9zdF94MV92YXIsIHBvc3RfeDJfdmFyKXsNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBnYXRoZXIocHJlX3ZhciwgcG9zdF94MV92YXIsIHBvc3RfeDJfdmFyLCBrZXkgPSAidmFyaWFibGUiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh2YXJpYWJsZSA9IGZhY3Rvcih2YXJpYWJsZSwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3gxX3ZhciwgcG9zdF94Ml92YXIpKSkNCiAgICANCiAgIyBXaWxjb3ggdGVzdA0KICBzdGF0LnRlc3QxIDwtDQogICAgZGZfbW9kaWYgJT4lDQogICAgIyBncm91cF9ieShFdGFwYSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG5vIG5lZWQgLi4gZ29pbmcgYnkgRXRhcGEgc2VwYXJhdGx5DQogICAgdGlkeXI6OmRyb3BfbmEodmFsdWUpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyIHNvIGdyb3VwaW5nIGZhY3RvciBsZXZlbHMgZ2V0IGRyb3BlZCBhbmQgd2UgY2FuIGNvbXBhcmUgd2l0aCB1bmV2ZW4gbGV2ZWxzDQogICAgcnN0YXRpeDo6d2lsY294X3Rlc3QodmFsdWUgfiB2YXJpYWJsZSkgJT4lICAgICAgICAgICAgICAgICMgcGFpcndpc2UNCiAgICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKCJwIikgJT4lDQogICAgZmlsdGVyKHAuc2lnbmlmICE9ICJucyIpDQogIA0KICAjIHQgdGVzdA0KICBzdGF0LnRlc3QyIDwtDQogICAgZGZfbW9kaWYgJT4lDQogICAgIyBncm91cF9ieShFdGFwYSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG5vIG5lZWQgLi4gZ29pbmcgYnkgRXRhcGEgc2VwYXJhdGx5DQogICAgdGlkeXI6OmRyb3BfbmEodmFsdWUpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyIHNvIGdyb3VwaW5nIGZhY3RvciBsZXZlbHMgZ2V0IGRyb3BlZCBhbmQgd2UgY2FuIGNvbXBhcmUgd2l0aCB1bmV2ZW4gbGV2ZWxzDQogICAgcnN0YXRpeDo6dF90ZXN0KHZhbHVlIH4gdmFyaWFibGUpICU+JSAgICAgICAgICAgICAgICAjIHBhaXJ3aXNlDQogICAgcnN0YXRpeDo6YWRkX3NpZ25pZmljYW5jZSgicCIpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIGZpbHRlcihwLnNpZ25pZiAhPSAibnMiKSANCiAgDQogIHAgPC0NCiAgICBnZ3Bsb3QoZGZfbW9kaWYsIGFlcyh5ID0gdmFsdWUsIHggPSB2YXJpYWJsZSkpICsNCiAgICAgICMgZmFjZXRfd3JhcCh+RXRhcGEsIG5yb3cgPSAxKSArICAgICAgICAgICAgICAgICAgICAgIyBubyBuZWVkIC4uIGdvaW5nIGJ5IEV0YXBhIHNlcGFyYXRseQ0KICAgICAgZ2d0aXRsZShkZXBhcnNlKHN1YnN0aXR1dGUoZGYpKSkgKyANCiAgICAgIGdlb21fYm94cGxvdCgpICsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgDQogIA0KICBpZihkaW0oc3RhdC50ZXN0MSlbMV0gIT0gMCkgeyAgICAgIyBkbyB0aGlzIG9ubHkgaWYgdGhlIHNpZ25pZmljYW5jZSBkYXRhZnJhbWUgaGFzID4gMCByb3dzDQogICAgcCA8LSANCiAgICAgIHAgKw0KICAgICAgZ2dwdWJyOjpzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0MSwgbGFiZWwgPSAicC5zaWduaWYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkucG9zaXRpb24gPSBzZXEobWF4KGRmX21vZGlmJHZhbHVlLCBuYS5ybSA9IFRSVUUpKzIsIG1heChkZl9tb2RpZiR2YWx1ZSwgbmEucm0gPSBUUlVFKSoyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IG5yb3coc3RhdC50ZXN0MSkpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB2ZXJ5IGhhY2t5DQogIH0NCiAgDQogIGNhdCgiIyMjIyBXaWxjb3hvbiB0ZXN0IikNCiAgcmV0dXJuKHN0YXQudGVzdDEpICU+JSBwcmludChuID0gSW5mKQ0KICBjYXQoIiMjIyMgdCB0ZXN0IikNCiAgcmV0dXJuKHN0YXQudGVzdDIpICU+JSBwcmludChuID0gSW5mKQ0KICBwDQp9DQoNCg0KY2F0KCIjIyBWQVMgc3RyZXMiKSAgICAgICAgICAgICAgICAjIG5hbWVzKERhdGFbLCBncmVwKCJWQVNfc3RyZXMiLCBuYW1lcyhEYXRhKSldKQ0KcGxvdF9wcmVleHBvc3RfZXg0KERhdGFfSVYsIA0KICAgICAgICAgICAgICAgICAgIlZBU19zdHJlc19wcmUiLCAiVkFTX3N0cmVzX3Bvc3RfZXgxIiwgIlZBU19zdHJlc19wb3N0X2V4MiIpDQoNCg0KY2F0KCIjIyBWQVMgc3RhcmUgZGUgYmluZSIpICAgICAgICMgbmFtZXMoRGF0YVssIGdyZXAoIlZBU19zdGFyZV9kZSIsIG5hbWVzKERhdGEpKV0pDQpwbG90X3ByZWV4cG9zdF9leDQoRGF0YV9JViwNCiAgICAgICAgICAgICAgICAgICJWQVNfc3RhcmVfZGVfYmluZV9wcmUiLCAiVkFTX3N0YXJlX2RlX2JpbmVfcG9zdF9leDEiLCAiVkFTX3N0YXJlX2RlX2JpbmVfcG9zdF9leDIiKQ0KDQoNCmNhdCgiIyMgVkFTIGNvcnAiKSAgICAgICAgICAgICAgICAjIG5hbWVzKERhdGFbLCBncmVwKCJWQVNfY29ycCIsIG5hbWVzKERhdGEpKV0pDQpwbG90X3ByZWV4cG9zdF9leDQoRGF0YV9JViwgDQogICAgICAgICAgICAgICAgICAiVkFTX2NvcnBfcHJlIiwgIlZBU19jb3JwX3Bvc3RfZXgxIiwgIlZBU19jb3JwX3Bvc3RfZXgyIikNCmBgYA0KDQoNCg0KDQo8YnI+DQoNCg0KDQoNCg0KPCEtLSBTZXNzaW9uIEluZm8gYW5kIExpY2Vuc2UgLS0+DQoNCjxicj4NCg0KIyBTZXNzaW9uIEluZm8NCmBgYHtyIHNlc3Npb25faW5mbywgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ21hcmt1cCd9DQpzZXNzaW9uSW5mbygpICAgIA0KYGBgDQoNCjwhLS0gRm9vdGVyIC0tPg0KJm5ic3A7DQo8aHIgLz4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij5BIHdvcmsgYnkgPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL0NsYXVkaXVQYXBhc3RlcmkvIj5DbGF1ZGl1IFBhcGFzdGVyaTwvYT48L3A+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODA4MDgwOyI+PGVtPmNsYXVkaXUucGFwYXN0ZXJpQGdtYWlsLmNvbTwvZW0+PC9zcGFuPjwvcD4NCiZuYnNwOw0K