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) {
  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 = ", "))
  }
  
  ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
         NA,
         rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
  )
}
##
# library(tidyverse)
# library(ggpubr)
# library(rstatix)
# library(broom)
# library(emmeans)
# library(rlang)


# Function ANCOVAPost
# Takes Long Data
ANCOVAPost_func <- 
  function(data, id_var, 
           time_var, pre_label, post_label,
           value_var = scores, cond_var, 
           assum_check = TRUE, posthoc = TRUE, 
           p_adjust_method = "bonferroni"){
  
  id_var_enq <- rlang::enquo(id_var)
  id_var_name <- rlang::as_name(id_var_enq)    
  time_var_enq <- rlang::enquo(time_var)
  time_var_name <- rlang::as_name(time_var_enq)
  pre_var_enq <- rlang::enquo(pre_label)
  pre_var_name <- rlang::as_name(pre_var_enq)  
  post_var_enq <- rlang::enquo(post_label)
  post_var_name <- rlang::as_name(post_var_enq)
  cond_var_enq <- rlang::enquo(cond_var)
  cond_var_name <- rlang::as_name(cond_var_enq)
  value_var_enq <- rlang::enquo(value_var)
  value_var_name <- rlang::as_name(value_var_enq) 
  
  data_wider <-
    data %>%
    dplyr::select(!!id_var_enq, !!time_var_enq, !!cond_var_enq, !!value_var_enq) %>%
    spread(key = time_var_name, value = value_var_name) # %>%     # if need to compute change score statistics go from here
    # mutate(difference = !!post_var_enq - !!pre_var_enq)  
    
  # Assumptions
  if(assum_check){
  cat("\n Linearity assumptionLinearity assumption (linear relationship between pre-test and post-test for each group) \n")
  # Create a scatter plot between the covariate (i.e., pretest) and the outcome variable (i.e., posttest)
  scatter_lin <-  
    ggscatter(data_wider, x = pre_var_name, y = post_var_name, color = cond_var_name, 
              add = "reg.line", title = "Linearity assumption") +
      stat_regline_equation(aes(label =  paste(..eq.label.., ..rr.label.., sep = "~~~~"), color = !!cond_var_enq))
  
  cat("\n Homogeneity of regression slopes (interaction term is n.s.) \n")
  data_wider %>% 
    anova_test(as.formula(paste0(post_var_name, " ~ ", cond_var_name, " * ", pre_var_name))) %>% 
    print()   
  
  cat("\n Normality of residuals (Model diagnostics & Shapiro Wilk) \n")
  # Fit the model, the covariate goes first
  model <- 
    lm(as.formula(paste0(post_var_name, " ~ ", cond_var_name, " + ", pre_var_name)),
       data = data_wider)
  cat("\n Inspect the model diagnostic metrics \n")
  model.metrics <- 
    augment(model) %>%
    dplyr::select(-.hat, -.sigma, -.fitted, -.se.fit)  %>%    # Remove details
    print()
  cat("\n Normality of residuals (Shapiro Wilk p>.05) \n")
  shapiro_test(model.metrics$.resid) %>% 
    print()
  
  cat("\n Homogeneity of variances (Levene’s test p>.05) \n")
  model.metrics %>% 
    levene_test(as.formula(paste0(".resid", " ~ ", cond_var_name)) ) %>%     
    print()
  
  cat("\n Outliers (needs to be 0) \n")
  model.metrics %>% 
    filter(abs(.std.resid) > 3) %>%
    as.data.frame() %>% 
    print()
  
  }
  
  cat("\n ANCOVAPost \n")
  res_ancova <- 
    data_wider %>% 
    anova_test(as.formula(paste0(post_var_name, " ~ ",  pre_var_name, " + ", cond_var_name)))       # the covariate needs to be first term 
  get_anova_table(res_ancova) %>% print()
  
  cat("\n Pairwise comparisons \n")
  pwc <- 
    data_wider %>% 
    emmeans_test(as.formula(paste0(post_var_name, " ~ ", cond_var_name)),       
                 covariate = !!pre_var_enq,
                 p.adjust.method = p_adjust_method)
  pwc %>% print()
  cat("\n Display the adjusted means of each group, also called as the estimated marginal means (emmeans) \n")
  get_emmeans(pwc) %>% print()
  
  # Visualization: line plots with p-values
  pwc <- 
    pwc %>% 
    add_xy_position(x = cond_var_name, fun = "mean_se")
  
  line_plot <- 
    ggline(get_emmeans(pwc), x = cond_var_name, y = "emmean") +
      geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0.2) + 
      stat_pvalue_manual(pwc, hide.ns = TRUE, tip.length = FALSE) +
      labs(subtitle = get_test_label(res_ancova, detailed = TRUE),
           caption = get_pwc_label(pwc))
  
  if(assum_check){
    list(scatter_lin, line_plot)
  }else{
    line_plot
  }
  
}

# ex.
# ANCOVAPost_func(new_anxiety, time_var = time, pre_label = pretest, post_label = posttest,
#           value_var = scores, cond_var = group, assum_check = TRUE, p_adjust_method = "bonferroni")
# library(tidyverse)
# library(ggpubr)
# library(rstatix)
# library(rlang)

# Define Function for Mixed Anova
tw_mixedANOVA_func <- 
  function(data, id_var, cond_var, time_var, value_var, 
           assum_check = TRUE, posthoc_sig_interac = FALSE, posthoc_ns_interac = FALSE,
           p_adjust_method = "bonferroni"){
    
    # input dataframe needs to have columns names diffrent from "variable" and "value" because it collides with rstatix::shapiro_test
    
    id_var_enq <- rlang::enquo(id_var)  
    cond_var_enq <- rlang::enquo(cond_var)
    cond_var_name <- rlang::as_name(cond_var_enq)
    time_var_enq <- rlang::enquo(time_var)
    time_var_name <- rlang::as_name(time_var_enq)
    value_var_enq <- rlang::enquo(value_var)
    value_var_name <- rlang::as_name(value_var_enq)
    
    data <-                  # need to subset becuase of strange contrasts error in anova_test()
      data %>%
      dplyr::select(!!id_var_enq, !!time_var_enq, !!cond_var_enq, !!value_var_enq) 
    
    # Assumptions
    if(assum_check){
      cat("\n Outliers \n")
      data %>%
        dplyr::group_by(!!time_var_enq, !!cond_var_enq) %>%
        rstatix::identify_outliers(!!value_var_enq) %>%                                  # outliers (needs to be 0)
        print()
      
      cat("\n Normality assumption (p>.05) \n")
      data %>%
        dplyr::group_by(!!time_var_enq, !!cond_var_enq) %>%
        rstatix::shapiro_test(!!value_var_enq) %>%                                        # normality assumption (p>.05)
        print()
      
      qq_plot <- 
        ggpubr::ggqqplot(data = data, value_var_name, ggtheme = theme_bw(), title = "QQ Plot") +
        ggplot2::facet_grid(vars(!!time_var_enq), vars(!!cond_var_enq), labeller = "label_both")    # QQ plot
      
      cat("\n Homogneity of variance assumption - Levene’s test (p>.05) \n")
      data %>%
        group_by(!!time_var_enq ) %>%
        levene_test(as.formula(paste0(value_var_name, " ~ ", cond_var_name))) %>%
        print()
      
      cat("\n Homogeneity of covariances assumption - Box’s test of equality of covariance matrices (p>.001) \n")
      box_m(data = data[, value_var_name, drop = FALSE], group = data[, cond_var_name, drop = TRUE]) %>%
        print
    }
    
    # Two-way rmANOVA - check for interaction (ex. F(2, 22) = 30.4, p < 0.0001)
    cat("\n Two-way rmANOVA \n")
    res_aov <- 
      anova_test(data = data, dv = !!value_var_enq, wid = !!id_var_enq,               # automatically does sphericity Mauchly’s test
                 within = !!time_var_enq, between = !!cond_var_enq)
    get_anova_table(res_aov) %>%  # ges: Greenhouse-Geisser sphericity correction is automatically applied to factors violating the sphericity assumption  
      print()
    
    
    # ------------------------------------------------------------------------
    
    #- Procedure for a significant two-way interaction -
    if(posthoc_sig_interac){
      cat("\n Effect of group at each time point - One-way ANOVA\n")
      one_way <- 
        data %>%
        group_by(!!time_var_enq) %>%
        anova_test(dv = !!value_var_enq, wid = !!id_var_enq, between = !!cond_var_enq) %>%
        get_anova_table() %>%
        adjust_pvalue(method = p_adjust_method)
      one_way %>% print()
      
      cat("\n Pairwise comparisons between group levels \n")
      pwc <- 
        data %>%
        group_by(!!time_var_enq) %>%
        pairwise_t_test(as.formula(paste0(value_var_name, " ~ ", cond_var_name)), 
                        p.adjust.method = p_adjust_method)
      pwc %>% print()
      cat("\n Effect of time at each level of exercises group  - One-way ANOVA \n")
      one_way2 <- 
        data %>%
        group_by(!!cond_var_enq) %>%
        anova_test(dv = !!value_var_enq, wid = !!id_var_enq, within = !!time_var_enq) %>%
        get_anova_table() %>%
        adjust_pvalue(method = p_adjust_method)
      one_way2 %>% print()
      
      cat("\n Pairwise comparisons between time points at each group levels (we have repeated measures by time) \n")
      pwc2 <-
        data %>%
        group_by(!!cond_var_enq) %>%
        pairwise_t_test(
          as.formula(paste0(value_var_name, " ~ ", time_var_name)),     # paste formula, not quosure
          paired = TRUE,
          p.adjust.method = p_adjust_method
        )
      pwc2  %>% print()
    }
    
    #- Procedure for non-significant two-way interaction- 
    # If the interaction is not significant, you need to interpret the main effects for each of the two variables: treatment and time.
    if(posthoc_ns_interac){
      cat("\n Comparisons for treatment variable \n")
      pwc_cond <-
        data %>%
        pairwise_t_test(
          as.formula(paste0(value_var_name, " ~ ", cond_var_name)),     # paste formula, not quosure             
          paired = FALSE,
          p.adjust.method = p_adjust_method
        )
      pwc_cond %>% print()
      cat("\n Comparisons for time variable \n")
      pwc_time <-
        data %>% 
        pairwise_t_test(
          as.formula(paste0(value_var_name, " ~ ", time_var_name)),     # paste formula, not quosure
          paired = TRUE,
          p.adjust.method = p_adjust_method
        )
      pwc_time %>% print()
    }
    
    # Visualization
    bx_plot <- 
      ggboxplot(data, x = time_var_name, y = value_var_name,
                color = cond_var_name, palette = "jco")
    pwc <- 
      pwc %>% 
      add_xy_position(x = time_var_name)
    bx_plot <- 
      bx_plot + 
      stat_pvalue_manual(pwc, tip.length = 0, hide.ns = TRUE) +
      labs(
        subtitle = get_test_label(res_aov, detailed = TRUE),
        caption = get_pwc_label(pwc)
      )
    
    if(assum_check){ 
      list(qq_plot, bx_plot)
    }else{
      bx_plot
    } 
    
  }

# ex. - run on long format
# tw_mixedANOVA_func(data = anxiety, id_var = id, cond_var = group, time_var = time, value_var = score,
#                 posthoc_sig_interac = TRUE, posthoc_ns_interac = TRUE)

2 Read, Clean, Recode

## Settings
cutoffPCL <- 32   # literature: 31-33 or 38 
algPCL <- data.frame(B = 1, C = 1, D = 2, E = 2)
algPCL_subclin <- data.frame(B = 1, C = 1, D = 1, E = 1)

cutoffMBI_Ex <- 2.20  
cutoffMBI_Cy <- 2
##

## Data
Data <- baseline_df
##

# Define column index:  index = col index; itemindex = index of item in questionnaire
indexSIG <- 60:67 - 10    # modified in new table by 10
indexMBI <- 68:83 - 10
indexPCL <- 159:178 - 10
itemindexMBI_Ex <- c(1, 3, 5, 11, 14)
itemindexMBI_Cy <- c(2, 7, 8, 13, 15)
itemindexMBI_Pe <- c(4, 6, 9, 10, 12, 16)

# Rename columns
# names(Data)[1:12] <- stringr::str_replace_all(names(Data)[1:12], "[[:blank:]]", "_")
# names(Data)[17] <- "Real_Email"
# names(Data)[18] <- "Real_Tel"
# names(Data)[19] <- "Real_Name"
# names(Data)[50] <- "Real_Age_categ"

names(Data)[40] <- "Age_categ"
names(Data)[41] <- "Sex"

names(Data)[names(Data) %in% names(Data[, indexSIG])]  <- c(sprintf("SIG_%01d", seq(1, 8)))
names(Data)[names(Data) %in% names(Data[, indexMBI])]  <- c(sprintf("MBI_%01d", seq(1, 16)))
names(Data)[names(Data) %in% names(Data[, indexPCL])]  <- c(sprintf("PCL_%01d", seq(1, 20)))


# Data <-
#   Data %>%
#   dplyr::filter(Response_Status == "completed")                          # select only complete cases
 

# Recode 
## 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
}
##

# lapply(Data[,indexPCL], unique)
Data[ ,indexPCL][ Data[ ,indexPCL] == "deloc"] <- "0"
Data[ ,indexPCL][ Data[ ,indexPCL] == "puțin"] <- "1"
Data[ ,indexPCL][ Data[ ,indexPCL] == "moderat"] <- "2"
Data[ ,indexPCL][ Data[ ,indexPCL] == "mult"] <- "3"
Data[ ,indexPCL][ Data[ ,indexPCL] == "foarte mult"] <- "4"
Data[ ,indexPCL][ Data[ ,indexPCL] == "Not Answered"] <- NA

Data[ ,indexSIG][ Data[ ,indexSIG] == "NU"] <- "0"
Data[ ,indexSIG][ Data[ ,indexSIG] == "?"] <- "1.5"
Data[ ,indexSIG][ Data[ ,indexSIG] == "DA"] <- "3"
Data[ ,indexSIG][ Data[ ,indexSIG] == "Not Answered"] <- NA

Data[ ,indexMBI] <- data.frame(lapply(Data[ ,indexMBI], 
                                      function(x) {gsub(".*Niciodat.*", "0", x)}), stringsAsFactors = FALSE)
Data[ ,indexMBI] <- data.frame(lapply(Data[ ,indexMBI], 
                                      function(x) {gsub(".*Zilnic.*", "6", x)}), stringsAsFactors = FALSE)
Data[ ,indexMBI][ Data[ ,indexMBI] == "Not Answered"] <- NA


Data[, indexSIG] <- colstonumeric(Data[, indexSIG])
Data[, indexMBI] <- colstonumeric(Data[, indexMBI])
Data[, indexPCL] <- colstonumeric(Data[, indexPCL])



# Scores
## 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, stat = "sum", natozero = FALSE, napercent = .1, tonumeric = FALSE, reversecols = NULL, min = NULL, max = NULL) {
  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(tonumeric) df <- colstonumeric(df)                           
  
  if(natozero) df[is.na(df)] <- 0                                    # NAs to 0 can help when stat = "mean" with na.rm = T because it keeps denominator constant
  
  if(stat == "sum"){
  df_res <- ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
                   NA,
                   rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0))
  }
  if(stat == "mean"){
    df_res <- ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
                     NA,
                     rowMeans(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0))
  }
  return(df_res)
}
##


# Score PCL
Data$PCL_Total <- ScoreLikert(Data[, indexPCL], napercent = .3)               # NA if NA threshold is exceeded 
Data$PCL_B <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 1:5))], napercent = 1)    # do nothing if NA threshold is exceeded
Data$PCL_C <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 6:7))], napercent = 1) 
Data$PCL_D <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 8:14))], napercent = 1)  
Data$PCL_E <- ScoreLikert(Data[, c(sprintf("PCL_%01d", 15:20))], napercent = 1)

# Score SIG
Data$SIG_Total <- ScoreLikert(Data[, indexSIG], napercent = .3)

# Score MBI
Data$MBI_Total <- ScoreLikert(Data[, indexMBI], napercent = .3, stat = "mean", natozero = TRUE)
Data$MBI_Ex <- ScoreLikert(Data[, c(sprintf("MBI_%01d", itemindexMBI_Ex))], napercent = 1, stat = "mean", natozero = TRUE)
Data$MBI_Cy <- ScoreLikert(Data[, c(sprintf("MBI_%01d", itemindexMBI_Cy))], napercent = 1, stat = "mean", natozero = TRUE)
Data$MBI_Pe <- ScoreLikert(Data[, c(sprintf("MBI_%01d", itemindexMBI_Pe))], napercent = 1, stat = "mean", natozero = TRUE)


# PCL Diagnostic Algorithm
itemsPCL_B <- c(sprintf("PCL_%01d", 1:5))
itemsPCL_C <- c(sprintf("PCL_%01d", 6:7))
itemsPCL_D <- c(sprintf("PCL_%01d", 8:14))
itemsPCL_E <- c(sprintf("PCL_%01d", 15:20))

DataPCLAlg <-  
  Data %>% 
  dplyr::select(tidyselect::all_of(indexPCL)) %>% 
  dplyr::mutate_all(
    funs(case_when(
      . >=2 ~ 1,
      # . <2 ~ 0,
      is.na(.) ~ 0,
      TRUE  ~  0))) %>% 
  
  mutate(PCL_CritB = case_when(rowSums(.[,itemsPCL_B], na.rm = TRUE) >= algPCL$B ~ 1,      # algPCL <- data.frame(B = 1, C = 1, D = 2, E = 2)
                               # rowSums(.[,itemsPCL_B], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_CritC = case_when(rowSums(.[,itemsPCL_C], na.rm = TRUE) >= algPCL$C ~ 1,    
                               # rowSums(.[,itemsPCL_C], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_CritD = case_when(rowSums(.[,itemsPCL_D], na.rm = TRUE) >= algPCL$D ~ 1,   
                               # rowSums(.[,itemsPCL_D], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_CritE = case_when(rowSums(.[,itemsPCL_E], na.rm = TRUE) >= algPCL$E ~ 1,    
                               # rowSums(.[,itemsPCL_E], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_Alg = case_when(PCL_CritB == 1 & PCL_CritC == 1 & PCL_CritD == 1 & PCL_CritE == 1 ~ 1,
                             TRUE  ~  0)) 

Data$PCLAlg <- DataPCLAlg$PCL_Alg

DataPCLAlg_subclin <-  
  Data %>% 
  dplyr::select(tidyselect::all_of(indexPCL)) %>% 
  dplyr::mutate_all(
    funs(case_when(
      . >=2 ~ 1,
      # . <2 ~ 0,
      is.na(.) ~ 0,
      TRUE  ~  0))) %>% 
  
  mutate(PCL_CritB = case_when(rowSums(.[,itemsPCL_B], na.rm = TRUE) >= algPCL_subclin$B ~ 1,  
                               # rowSums(.[,itemsPCL_B], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_CritC = case_when(rowSums(.[,itemsPCL_C], na.rm = TRUE) >= algPCL_subclin$C ~ 1,    
                               # rowSums(.[,itemsPCL_C], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_CritD = case_when(rowSums(.[,itemsPCL_D], na.rm = TRUE) >= algPCL_subclin$D ~ 1,   
                               # rowSums(.[,itemsPCL_D], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_CritE = case_when(rowSums(.[,itemsPCL_E], na.rm = TRUE) >= algPCL_subclin$E ~ 1,    
                               # rowSums(.[,itemsPCL_E], na.rm = TRUE) <1 ~ 0,
                               TRUE  ~  0)) %>% 
  mutate(PCL_Alg_subclin = case_when(PCL_CritB == 1 & PCL_CritC == 1 & PCL_CritD == 1 & PCL_CritE == 1 ~ 1,
                                     TRUE  ~  0)) 

Data$PCLAlg_subclin <- DataPCLAlg_subclin$PCL_Alg_subclin

Data$MBI_Ex_cut <- ifelse(Data$MBI_Ex >= cutoffMBI_Ex, 1, 0)
Data$MBI_Cy_cut <- ifelse(Data$MBI_Cy >= cutoffMBI_Cy, 1, 0)


# Global Screening & Groups
df_screening <- Data[,c("ID", "nume", "e-mail", "Age_categ", "Sex",
                        "SIG_Total", "MBI_Ex_cut", "MBI_Cy_cut",
                        "PCL_Total", "PCL_B", "PCL_C", "PCL_D", "PCL_E", "PCLAlg", "PCLAlg_subclin")]
ids_ptsd <-
  df_screening %>%
    dplyr::filter(PCLAlg == 1) %>%
    dplyr::select(ID) %>%
    dplyr::pull()

ids_burn <-
  df_screening %>%
    dplyr::filter(MBI_Ex_cut == 1, MBI_Cy_cut == 1) %>%
    dplyr::select(ID) %>%
    dplyr::pull()

ids_old <-
  df_screening %>%
    dplyr::filter(Age_categ == "peste 65 ani") %>%
    dplyr::select(ID) %>%
    dplyr::pull()

ids_normal <-
   df_screening %>%
    dplyr::filter(!(ID %in% c(ids_ptsd, ids_burn, ids_old))) %>%
    dplyr::select(ID) %>%
    dplyr::pull()

intersect(ids_ptsd, ids_burn)   # 8 common
[1] "12B" "5C"  "8R"  "11R" "6X"  "9X"  "12X" "19X"
character(0)
character(0)
[1] TRUE

3 Outcome Measures

4 Dictator Game

# DG df
dg_df_pre <- rio::import(file.path(folder, file),
                                   skip = 0, which = "DictatorGame pre")
colnames(dg_df_pre)[4] <- "ID"
dg_df_pre <- 
  dg_df_pre %>%
  dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>%    # remove white spaces
  dplyr::mutate(ID = toupper(ID))                                         # to upper
all(dg_df_pre$ID == toupper(dg_df_pre$ID)) 
dg_df_post <- rio::import(file.path(folder, file),
                                   skip = 0, which = "DictatorGame post")
colnames(dg_df_post)[4] <- "ID"
dg_df_post <- 
  dg_df_post %>%
  dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>%    # remove white spaces
  dplyr::mutate(ID = toupper(ID))                                         # to upper
all(dg_df_post$ID == toupper(dg_df_post$ID)) 
colnames(dg_df_pre)[5:8] <- sprintf("DG_%d", 1:4)
colnames(dg_df_post)[5:8] <- sprintf("DG_%d", 1:4)


dg_df_pre <-
  dg_df_pre %>%
  dplyr::mutate(`Date Modified` = lubridate::ymd_hms(format(`Date Modified`, "%Y-%m-%d %H:%M:%S", tz = "UTC"))) %>%
  mutate_if(is.character, ~na_if(., "Not Answered"))

dg_df_post <-
  dg_df_post %>%
  dplyr::mutate(`Date Modified` = lubridate::ymd_hms(format(`Date Modified`, "%Y-%m-%d %H:%M:%S", tz = "UTC"))) %>%
  mutate_if(is.character, ~dplyr::na_if(., "Not Answered"))

dg_df_pre <-
  dg_df_pre %>%
  dplyr::mutate_at(vars(starts_with("DG_")), ~stringr::str_extract(., "[0-9]+")) %>%   # extracts first number (all games start with Player A, so always first number)
  dplyr::mutate_at(vars(starts_with("DG_")), as.numeric) %>%
  dplyr::mutate(Time = rep("Pre", nrow(.))) %>%
  dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR")) %>%
  select(`Date Modified`, ID, starts_with("DG_"), Time, Cond)

dg_df_post <-
  dg_df_post %>%
  dplyr::mutate_at(vars(starts_with("DG_")), ~stringr::str_extract(., "[0-9]+")) %>%   # extracts first number (all games start with Player A, so always first number)
  dplyr::mutate_at(vars(starts_with("DG_")), as.numeric) %>%
  dplyr::mutate(Time = rep("Post", nrow(.))) %>%
  dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR")) %>%
  select(`Date Modified`, ID, starts_with("DG_"), Time, Cond)

# Transform DG 0-900 egoism to 0-9 altruism
dg_trans_func <- function(x){trans <- 9 - x / 100}

dg_df_pre <-
  dg_df_pre %>%
  dplyr::mutate_at(vars(starts_with("DG_")), dg_trans_func) 

dg_df_post <-
  dg_df_post %>%
  dplyr::mutate_at(vars(starts_with("DG_")), dg_trans_func) 

# Unite DG data - Long Format
dg_united_long <- rbind(dg_df_pre, dg_df_post)
which(table(dg_united_long$ID)> 2 )     # IDs "3B" & "31X" have more than 2 trials
dg_united_long[dg_united_long$ID == "3B",]  # two Pres -- keep the first

–>

5 T test Dicatator Game

## DG - PTSD TR
#### DG_Total_Pre DG_Total_Post

## DG - PTSD CTRL
#### DG_Total_Pre DG_Total_Post

## DG - Burnout TR
#### DG_Total_Pre DG_Total_Post

## DG - Burnout CTRL
#### DG_Total_Pre DG_Total_Post

## DG - Old TR
#### DG_Total_Pre DG_Total_Post

## DG - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ",  : 
  argument "x" is missing, with no default
## DG - General Population TR
#### DG_Total_Pre DG_Total_Post

## DG - General Population CTRL
#### DG_Total_Pre DG_Total_Post

5.1 DG Normal Sample Size estimation

## DG - General Population TR
## Cohen's d 
## Sample Size estimation 

## DG - General Population CTRL
Error in samplesize_pairedttest(., ind = "ID", pre_var = "DG_Total_Pre",  : 
  unused argument (ind = "ID")
# Scales df
scale_df_pre <- rio::import(file.path(folder, file),
                           skip = 0, which = "Set teste zi 1 pre")
scale_df_pre <- scale_df_pre[,-2]
colnames(scale_df_pre)[1] <- "Date"
colnames(scale_df_pre)[2] <- "ID"
scale_df_pre <- 
  scale_df_pre %>%
  dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>%    # remove white spaces
  dplyr::mutate(ID = toupper(ID))                                         # to upper
all(scale_df_pre$ID == toupper(scale_df_pre$ID)) 
scale_df_post <- rio::import(file.path(folder, file),
                            skip = 0, which = "Set teste zi 5 post")
scale_df_post <- scale_df_post[,-2]
colnames(scale_df_post)[1] <- "Date"
colnames(scale_df_post)[2] <- "ID"
scale_df_post <- 
  scale_df_post %>%
  dplyr::mutate(ID = stringr::str_replace_all(ID, fixed(" "), "")) %>%    # remove white spaces
  dplyr::mutate(ID = toupper(ID))                                         # to upper
all(scale_df_post$ID == toupper(scale_df_post$ID))
all.equal(colnames(scale_df_post), colnames(scale_df_pre))   # setdiff(colnames(scale_df_post), colnames(scale_df_pre))
# Deal with Not Answer
scale_df_pre <-
  scale_df_pre %>%
  mutate_if(is.character, ~dplyr::na_if(., "Not Answered"))

scale_df_post <-
  scale_df_post %>%
  mutate_if(is.character, ~dplyr::na_if(., "Not Answered"))

# Add Condition
scale_df_pre <-
  scale_df_pre %>%
  dplyr::mutate(Time = rep("Pre", nrow(.))) %>%
  dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR"))

scale_df_post <-
  scale_df_post %>%
  dplyr::mutate(Time = rep("Post", nrow(.))) %>%
    dplyr::mutate(Cond = ifelse(stringr::str_detect(ID, "X"), "CTRL", "TR"))


## 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.  
index_item_panas <- 3:22
colnames(scale_df_pre)[index_item_panas] <- sprintf("PANAS_%d", 1:20)
colnames(scale_df_post)[index_item_panas] <- sprintf("PANAS_%d", 1:20)

scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas], 
                                      function(x) {gsub(".*în foarte mică măsură.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas], 
                                      function(x) {gsub(".*în mică măsură.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas], 
                                      function(x) {gsub(".*într-o oarecare măsură.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas], 
                                      function(x) {gsub(".*în mare măsură.*", "4", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_panas] <- data.frame(lapply(scale_df_pre[, index_item_panas], 
                                      function(x) {gsub(".*în foarte mare măsură.*", "5", x)}), stringsAsFactors = FALSE)

scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas], 
                                                      function(x) {gsub(".*în foarte mică măsură.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas], 
                                                      function(x) {gsub(".*în mică măsură.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas], 
                                                      function(x) {gsub(".*într-o oarecare măsură.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas], 
                                                      function(x) {gsub(".*în mare măsură.*", "4", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_panas] <- data.frame(lapply(scale_df_post[, index_item_panas], 
                                                      function(x) {gsub(".*în foarte mare măsură.*", "5", x)}), stringsAsFactors = FALSE)
# Scoring
scale_df_pre$PA_Total <- ScoreLikert(scale_df_pre[, index_item_panas][c(1, 3, 5, 9, 10, 12, 14, 16, 17, 19)], 
                                    tonumeric = TRUE, napercent = .11)                              # not more than 1 NAs for 10 items
scale_df_pre$NA_Total <- ScoreLikert(scale_df_pre[, index_item_panas][c(2, 4, 6, 7, 8, 11, 13, 15, 18, 20)],
                                    tonumeric = TRUE, napercent = .11)                              # not more than 1 NAs for 10 items

scale_df_post$PA_Total <- ScoreLikert(scale_df_post[, index_item_panas][c(1, 3, 5, 9, 10, 12, 14, 16, 17, 19)], 
                                     tonumeric = TRUE, napercent = .11)                              # not more than 1 NAs for 10 items
scale_df_post$NA_Total <- ScoreLikert(scale_df_post[, index_item_panas][c(2, 4, 6, 7, 8, 11, 13, 15, 18, 20)],
                                     tonumeric = TRUE, napercent = .11)                              # not more than 1 NAs for 10 items


## PSS-SF 14 (likert 0-4). Items 4, 5, 6, 7, 9, 10, and 13 are scored in reverse direction.
index_item_pss <- 23:36
index_item_revPSS <- c(4, 5, 6, 7, 9, 10, 13)
colnames(scale_df_pre)[index_item_pss] <- sprintf("PSS_%d", 1:14)
colnames(scale_df_post)[index_item_pss] <- sprintf("PSS_%d", 1:14)

scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss], 
                                      function(x) {gsub(".*niciodată.*", "0", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss], 
                                      function(x) {gsub(".*aproape niciodată.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss], 
                                      function(x) {gsub(".*uneori.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss], 
                                      function(x) {gsub(".*destul de des.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_pre[, index_item_pss] <- data.frame(lapply(scale_df_pre[, index_item_pss], 
                                      function(x) {gsub(".*foarte des.*", "4", x)}), stringsAsFactors = FALSE)

scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss], 
                                                    function(x) {gsub(".*niciodată.*", "0", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss], 
                                                    function(x) {gsub(".*aproape niciodată.*", "1", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss], 
                                                    function(x) {gsub(".*uneori.*", "2", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss], 
                                                    function(x) {gsub(".*destul de des.*", "3", x)}), stringsAsFactors = FALSE)
scale_df_post[, index_item_pss] <- data.frame(lapply(scale_df_post[, index_item_pss], 
                                                    function(x) {gsub(".*foarte des.*", "4", x)}), stringsAsFactors = FALSE)

# Score
scale_df_pre[, index_item_pss] <- colstonumeric(scale_df_pre[, index_item_pss])
scale_df_post[, index_item_pss] <- colstonumeric(scale_df_post[, index_item_pss])

scale_df_pre[, index_item_pss][index_item_revPSS] <- ReverseCode(scale_df_pre[, index_item_pss][index_item_revPSS], tonumeric = FALSE, min = 0, max = 4)
scale_df_post[, index_item_pss][index_item_revPSS] <- ReverseCode(scale_df_post[, index_item_pss][index_item_revPSS], tonumeric = FALSE, min = 0, max = 4)

scale_df_pre$PSS_Total <- ScoreLikert(scale_df_pre[, index_item_pss], napercent = .11)
scale_df_post$PSS_Total <- ScoreLikert(scale_df_post[, index_item_pss], napercent = .11)


# Unite scale df - Long Format
scale_united_long <- rbind(scale_df_pre, scale_df_post)

scale_united_long %>%
  count(ID) %>%
  print(n = Inf)  # ID "2B" has double record both in pre and post -- keep first in both, second record has NAs

–>

6 T test PSS

## PSS - PTSD TR
#### PSS_Total_Pre PSS_Total_Post

## PSS - PTSD CTRL
#### PSS_Total_Pre PSS_Total_Post

## PSS - Burnout TR
#### PSS_Total_Pre PSS_Total_Post

## PSS - Burnout CTRL
#### PSS_Total_Pre PSS_Total_Post

## PSS - Old TR
#### PSS_Total_Pre PSS_Total_Post

## PSS - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ",  : 
  argument "x" is missing, with no default
## PSS - General Population TR
#### PSS_Total_Pre PSS_Total_Post

## PSS - General Population CTRL
#### PSS_Total_Pre PSS_Total_Post

6.1 PSS Normal Sample Size estimation

## PSS - General Population TR
## Cohen's d 
## Sample Size estimation 

## PSS - General Population CTRL
## Cohen's d 
## Sample Size estimation 

7 T test PA

## PA - PTSD TR
#### PA_Total_Pre PA_Total_Post

## PA - PTSD CTRL
#### PA_Total_Pre PA_Total_Post

## PA - Burnout TR
#### PA_Total_Pre PA_Total_Post

## PA - Burnout CTRL
#### PA_Total_Pre PA_Total_Post

## PA - Old TR
#### PA_Total_Pre PA_Total_Post

## PA - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ",  : 
  argument "x" is missing, with no default
## PA - General Population TR
#### PA_Total_Pre PA_Total_Post

## PA - General Population CTRL
#### PA_Total_Pre PA_Total_Post

7.1 PA Normal Sample Size estimation

## PSS - General Population TR
## Cohen's d 
## Sample Size estimation 

## PSS - General Population CTRL
## Cohen's d 
## Sample Size estimation 

8 T test NA

## NA - PTSD TR
#### NA_Total_Pre NA_Total_Post

## NA - PTSD CTRL
#### NA_Total_Pre NA_Total_Post

## NA - Burnout TR
#### NA_Total_Pre NA_Total_Post

## NA - Burnout CTRL
#### NA_Total_Pre NA_Total_Post

## NA - Old TR
#### NA_Total_Pre NA_Total_Post

## NA - Old CTRL
Error in (function (x, cutpoints = c(0.3, 0.6, 0.8, 0.9, 0.95), symbols = if (numeric.x) c(" ",  : 
  argument "x" is missing, with no default
## NA - General Population TR
#### NA_Total_Pre NA_Total_Post

## NA - General Population CTRL
#### NA_Total_Pre NA_Total_Post

8.1 NA Normal Sample Size estimation

## PSS - General Population TR
## Cohen's d 
## Sample Size estimation 

## PSS - General Population CTRL
## Cohen's d 
## Sample Size estimation 


9 Session Info

R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 8.1 x64 (build 9600)

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] pwr_1.2-2                  rlang_0.4.6                emmeans_1.4.5              rio_0.5.16                 scales_1.1.0               ggpubr_0.2.5              
 [7] magrittr_1.5               tadaatoolbox_0.16.1        summarytools_0.8.8         rstatix_0.5.0              broom_0.5.6                PerformanceAnalytics_1.5.2
[13] xts_0.11-2                 zoo_1.8-4                  psych_1.9.12.31            forcats_0.5.0              stringr_1.4.0              dplyr_0.8.5               
[19] purrr_0.3.3                readr_1.3.1                tidyr_1.0.2                tibble_3.0.0               ggplot2_3.3.0              tidyverse_1.3.0           
[25] papaja_0.1.0.9842          pacman_0.5.1              

loaded via a namespace (and not attached):
 [1] nlme_3.1-140       bitops_1.0-6       matrixStats_0.54.0 fs_1.4.1           lubridate_1.7.4    httr_1.4.1         tools_3.6.1        backports_1.1.6   
 [9] R6_2.4.1           nortest_1.0-4      DBI_1.0.0          colorspace_1.4-1   withr_2.1.2        tidyselect_1.0.0   gridExtra_2.3      mnormt_1.5-6      
[17] pixiedust_0.8.6    curl_4.3           compiler_3.6.1     cli_2.0.2          rvest_0.3.5        expm_0.999-3       xml2_1.3.1         sandwich_2.5-0    
[25] labeling_0.3       mvtnorm_1.1-0      quadprog_1.5-5     digest_0.6.25      foreign_0.8-71     pkgconfig_2.0.3    htmltools_0.4.0    dbplyr_1.4.3      
[33] readxl_1.3.1       rstudioapi_0.11    pryr_0.1.4         farver_2.0.3       generics_0.0.2     jsonlite_1.6.1     zip_1.0.0          car_3.0-7         
[41] RCurl_1.95-4.11    rapportools_1.0    Matrix_1.2-17      Rcpp_1.0.4.6       DescTools_0.99.34  munsell_0.5.0      fansi_0.4.1        abind_1.4-5       
[49] viridis_0.5.1      lifecycle_0.2.0    multcomp_1.4-8     stringi_1.4.6      carData_3.0-2      MASS_7.3-51.4      plyr_1.8.6         grid_3.6.1        
[57] parallel_3.6.1     crayon_1.3.4       lattice_0.20-38    splines_3.6.1      haven_2.2.0        pander_0.6.3       hms_0.5.3          knitr_1.28        
[65] pillar_1.4.3       boot_1.3-22        estimability_1.3   ggsignif_0.4.0     codetools_0.2-16   reprex_0.3.0       glue_1.4.0         data.table_1.12.8 
[73] modelr_0.1.6       vctrs_0.2.4        cellranger_1.1.0   gtable_0.3.0       assertthat_0.2.1   xfun_0.13          openxlsx_4.1.0     xtable_1.8-4      
[81] coda_0.19-2        survival_2.44-1.1  viridisLite_0.3.0  TH.data_1.0-9      ellipsis_0.3.0    
 

A work by Claudiu Papasteri

 

LS0tDQp0aXRsZTogIjxicj4gUEE0IiANCnN1YnRpdGxlOiAiUmVwb3J0Ig0KYXV0aG9yOiAiPGJyPiBDbGF1ZGl1IFBhcGFzdGVyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVtICVZJylgIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgICAgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICB0aGVtZTogc3BhY2VsYWINCiAgICAgICAgICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbA0KICAgICAgICAgICAgZmlnX3dpZHRoOiAxMA0KICAgICAgICAgICAgZmlnX2hlaWdodDogOQ0KICAgICMgcGRmX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVycm9yID0gVFJVRSwNCiAgZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgICAgICAgDQogICJwc3ljaCIsICJQZXJmb3JtYW5jZUFuYWx5dGljcyIsICAgICAgICAgIA0KICAiYnJvb20iLCAicnN0YXRpeCIsDQogICJzdW1tYXJ5dG9vbHMiLCAidGFkYWF0b29sYm94IiwgICAgICAgICAgIA0KICAiZ2dwbG90MiIsICJnZ3B1YnIiLCAic2NhbGVzIiwgICAgICAgIA0KICAicmlvIiwNCiAgImdncHViciIsICJyc3RhdGl4IiwgImJyb29tIiwgImVtbWVhbnMiLCAicmxhbmciLA0KICAicHdyIg0KICAjICwgLi4uDQopDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFjbWFuOjpwX2xvYWQoY2hhciA9IHBhY2thZ2VzKQ0KDQojIFRoZW1lcyBmb3IgZ2dwbG90MiBwbG90aW5nIChoZXJlIHVzZWQgQVBBIHN0eWxlKQ0KdGhlbWVfc2V0KHRoZW1lX2FwYSgpKQ0KYGBgDQoNCg0KDQoNCg0KPCEtLSBSZXBvcnQgLS0+DQoNCiMgRGVmaW5lIGZ1bmN0aW9ucw0KDQpgYGB7ciBkZWZfZnVuY30NCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJlY29kZXMgdG8gbnVtZXJpYywgYnV0IHdhdGNoZXMgb3V0IHRvIGNvZXJjaW9uIHRvIG5vdCBpbnRyb2R1Y2UgTkFzDQpjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgdHJ5Q2F0Y2goew0KICAgIGRmX251bSA8LSBhcy5kYXRhLmZyYW1lKA0KICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHsgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpfSkpIA0KICB9LHdhcm5pbmcgPSBmdW5jdGlvbihzdG9wX29uX3dhcm5pbmcpIHsNCiAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgfSkgDQp9DQojIw0KIyMgRGVmaW5lIGZ1bmN0aW9uIHRoYXQgcmV2ZXJzZSBjb2RlcyBpdGVtcw0KUmV2ZXJzZUNvZGUgPC0gZnVuY3Rpb24oZGYsIHRvbnVtZXJpYyA9IEZBTFNFLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikNCiAgZGYgPC0gKG1heCArIG1pbikgLSBkZg0KfQ0KIyMNCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHNjb3JlcyBvbmx5IHJvd3Mgd2l0aCBsZXNzIHRoYW4gMTAlIE5BcyAocmV0dXJucyBOQSBpZiBhbGwgb3IgYWJvdmUgdGhyZXNob2xkIHBlcmNlbnRhZ2Ugb2Ygcm93cyBhcmUgTkEpOyBjYW4gcmV2ZXJzZSBjb2RlIGlmIHZlY3RvciBvZiBjb2x1bW4gaW5kZXhlcyBhbmQgbWluLCBtYXggYXJlIHByb3ZpZGVkLg0KU2NvcmVMaWtlcnQgPC0gZnVuY3Rpb24oZGYsIG5hcGVyY2VudCA9IC4xLCB0b251bWVyaWMgPSBGQUxTRSwgcmV2ZXJzZWNvbHMgPSBOVUxMLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIHJldmVyc2VfbGlzdCA8LSBsaXN0KHJldmVyc2Vjb2xzID0gcmV2ZXJzZWNvbHMsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KQ0KICByZXZlcnNlX2NoZWNrIDwtICFzYXBwbHkocmV2ZXJzZV9saXN0LCBpcy5udWxsKQ0KICANCiAgIyBSZWNvZGUgdG8gbnVtZXJpYywgYnV0IHdhdGNoIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KICBjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgICB0cnlDYXRjaCh7DQogICAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgeyBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSl9KSkgDQogICAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgICB9KSANCiAgfQ0KICANCiAgaWYodG9udW1lcmljKSBkZiA8LSBjb2xzdG9udW1lcmljKGRmKQ0KICANCiAgaWYoYWxsKHJldmVyc2VfY2hlY2spKXsNCiAgICBkZlsgLHJldmVyc2Vjb2xzXSA8LSAobWF4ICsgbWluKSAtIGRmWyAscmV2ZXJzZWNvbHNdDQogIH1lbHNlIGlmKGFueShyZXZlcnNlX2NoZWNrKSl7DQogICAgc3RvcCgiSW5zdWZpY2llbnQgaW5mbyBmb3IgcmV2ZXJzaW5nLiBQbGVhc2UgcHJvdmlkZTogIiwgcGFzdGUobmFtZXMocmV2ZXJzZV9saXN0KVshcmV2ZXJzZV9jaGVja10sIGNvbGxhcHNlID0gIiwgIikpDQogIH0NCiAgDQogIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgIE5BLA0KICAgICAgICAgcm93U3VtcyhkZiwgbmEucm0gPSBUUlVFKSAqIE5BIF4gKHJvd1N1bXMoIWlzLm5hKGRmKSkgPT0gMCkNCiAgKQ0KfQ0KIyMNCmBgYA0KDQoNCmBgYHtyIGRlZl9mdW5jX3R0ZXN0LCBoaWRlPVRSVUV9DQojIyBGdW5jIHQgdGVzdCBzaSBib3hwbG90IHNpbXBsdQ0KZnVuY190X2JveCA8LSBmdW5jdGlvbihkZiwgaW5kLCBwcmVfdmFyLCBwb3N0X3Zhcil7DQogIHZhcnMgPC0gYyhpbmQsIHByZV92YXIsIHBvc3RfdmFyKSAgICAgICAgICAgICAgICAjIHRvIGF2b2lkIG5ldyB0aWR5dmVyc2UgZXJyb3Igb2YgYW1iaWd1aXR5IGR1ZSB0byBleHRlcm5hbCB2ZWN0b3MNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KHRpZHlzZWxlY3Q6OmFsbF9vZih2YXJzKSkgJT4lIA0KICAgIHRpZHlyOjpkcm9wX25hKCkgJT4lDQogICAgZ2F0aGVyKHRpZHlzZWxlY3Q6OmFsbF9vZihwcmVfdmFyKSwgdGlkeXNlbGVjdDo6YWxsX29mKHBvc3RfdmFyKSwga2V5ID0gIkNvbmQiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JSANCiAgICBtdXRhdGVfYXQodmFycyhjKDEsIDIpKSwgYXMuZmFjdG9yKSAlPiUgDQogICAgbXV0YXRlKENvbmQgPSBmYWN0b3IoQ29uZCwgbGV2ZWxzID0gYyhwcmVfdmFyLCBwb3N0X3ZhcikpKSANCiAgDQogIHN0YXRfY29tcCA8LSBnZ3B1YnI6OmNvbXBhcmVfbWVhbnModmFsdWUgfiBDb25kLCBkYXRhID0gZGZfbW9kaWYsIG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFKQ0KICANCiAgc3RhdF9jb21wMiA8LQ0KICAgIGRmX21vZGlmICU+JSANCiAgICBkbyh0aWR5KHQudGVzdCguJHZhbHVlIH4gLiRDb25kLA0KICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgZGF0YT0uKSkpDQogIA0KICBwbG90IDwtIA0KICAgIGdncHVicjo6Z2dwYWlyZWQoZGZfbW9kaWYsIHggPSAiQ29uZCIsIHkgPSAidmFsdWUiLCBpZCA9IGluZCwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJDb25kIiwgbGluZS5jb2xvciA9ICJncmF5IiwgbGluZS5zaXplID0gMC40LA0KICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9IGMoIiMwMEFGQkIiLCAiI0ZDNEUwNyIpLCBsZWdlbmQgPSAibm9uZSIpICsNCiAgICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBsYWJlbC54ID0gYXMubnVtZXJpYyhkZl9tb2RpZiRDb25kKS0wLjQsIGxhYmVsLnkgPSBtYXgoZGZfbW9kaWYkdmFsdWUpKzAuNSkgKyANCiAgICAgIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSBUUlVFLCBsYWJlbCA9ICJwLnNpZ25pZiIsIGNvbXBhcmlzb25zID0gbGlzdChjKHByZV92YXIsIHBvc3RfdmFyKSkpDQogIA0KICBjYXQocGFzdGUwKCIjIyMjICIsIHByZV92YXIsICIgIiwgcG9zdF92YXIsICJcbiIsICJcbiIpKQ0KICBwcmludChzdGF0X2NvbXApDQogIHByaW50KHN0YXRfY29tcDIpDQogIHByaW50KHBsb3QpDQp9DQpgYGANCg0KDQpgYGB7ciBzYW1wbGVzaXplX2lkZXB0dGVzdH0NCnNhbXBsZXNpemVfcGFpcmVkdHRlc3QgPC0gZnVuY3Rpb24oZGYsIHByZV92YXIsIHBvc3RfdmFyKXsNCiAgdmFycyA8LSBjKHByZV92YXIsIHBvc3RfdmFyKSAgICAgICAgICAgICAgICAjIHRvIGF2b2lkIG5ldyB0aWR5dmVyc2UgZXJyb3Igb2YgYW1iaWd1aXR5IGR1ZSB0byBleHRlcm5hbCB2ZWN0b3MNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KHRpZHlzZWxlY3Q6OmFsbF9vZih2YXJzKSkgJT4lIA0KICAgIHRpZHlyOjpkcm9wX25hKCkgJT4lDQogICAgZ2F0aGVyKHRpZHlzZWxlY3Q6OmFsbF9vZihwcmVfdmFyKSwgdGlkeXNlbGVjdDo6YWxsX29mKHBvc3RfdmFyKSwga2V5ID0gIkNvbmQiLCB2YWx1ZSA9ICJ2YWx1ZSIpICU+JSANCiAgICBtdXRhdGUoQ29uZCA9IGZhY3RvcihDb25kLCBsZXZlbHMgPSBjKHByZV92YXIsIHBvc3RfdmFyKSkpIA0KICANCiAgY2F0KCIjIyBDb2hlbidzIGQgXG4iKQ0KICBlZmZfc2l6ZV90YWJsZSA8LQ0KICAgIGRmX21vZGlmICU+JQ0KICAgIGNvaGVuc19kKHZhbHVlIH4gQ29uZCwgcGFpcmVkID0gVFJVRSkgJT4lDQogICAgcHJpbnQoKQ0KICBlZmZfc2l6ZSA8LSBhcy5udW1lcmljKGVmZl9zaXplX3RhYmxlJGVmZnNpemUpDQoNCiAgY2F0KCIjIyBTYW1wbGUgU2l6ZSBlc3RpbWF0aW9uIFxuIikNCiAgc2FtcGxlX3NpemVfdGFibGUgPC0NCiAgICBwd3I6OnB3ci50LnRlc3QoZCA9IGVmZl9zaXplLCBzaWcubGV2ZWwgPSAuMDUsIHBvd2VyID0gLjgsIHR5cGUgPSAicGFpcmVkIiwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikgDQogIHNhbXBsZV9zaXplX3RhYmxlICU+JSBicm9vbTo6dGlkeSgpICU+JSBwcmludCgpDQoNCiAgcGxvdChzYW1wbGVfc2l6ZV90YWJsZSkNCn0gIA0KYGBgDQoNCg0KYGBge3IgZGVmX2Z1bmNfQU5DT1ZBUG9zdH0NCiMgbGlicmFyeSh0aWR5dmVyc2UpDQojIGxpYnJhcnkoZ2dwdWJyKQ0KIyBsaWJyYXJ5KHJzdGF0aXgpDQojIGxpYnJhcnkoYnJvb20pDQojIGxpYnJhcnkoZW1tZWFucykNCiMgbGlicmFyeShybGFuZykNCg0KDQojIEZ1bmN0aW9uIEFOQ09WQVBvc3QNCiMgVGFrZXMgTG9uZyBEYXRhDQpBTkNPVkFQb3N0X2Z1bmMgPC0gDQogIGZ1bmN0aW9uKGRhdGEsIGlkX3ZhciwgDQogICAgICAgICAgIHRpbWVfdmFyLCBwcmVfbGFiZWwsIHBvc3RfbGFiZWwsDQogICAgICAgICAgIHZhbHVlX3ZhciA9IHNjb3JlcywgY29uZF92YXIsIA0KICAgICAgICAgICBhc3N1bV9jaGVjayA9IFRSVUUsIHBvc3Rob2MgPSBUUlVFLCANCiAgICAgICAgICAgcF9hZGp1c3RfbWV0aG9kID0gImJvbmZlcnJvbmkiKXsNCiAgDQogIGlkX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKGlkX3ZhcikNCiAgaWRfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUoaWRfdmFyX2VucSkgICAgDQogIHRpbWVfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8odGltZV92YXIpDQogIHRpbWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodGltZV92YXJfZW5xKQ0KICBwcmVfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8ocHJlX2xhYmVsKQ0KICBwcmVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUocHJlX3Zhcl9lbnEpICANCiAgcG9zdF92YXJfZW5xIDwtIHJsYW5nOjplbnF1byhwb3N0X2xhYmVsKQ0KICBwb3N0X3Zhcl9uYW1lIDwtIHJsYW5nOjphc19uYW1lKHBvc3RfdmFyX2VucSkNCiAgY29uZF92YXJfZW5xIDwtIHJsYW5nOjplbnF1byhjb25kX3ZhcikNCiAgY29uZF92YXJfbmFtZSA8LSBybGFuZzo6YXNfbmFtZShjb25kX3Zhcl9lbnEpDQogIHZhbHVlX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKHZhbHVlX3ZhcikNCiAgdmFsdWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodmFsdWVfdmFyX2VucSkgDQogIA0KICBkYXRhX3dpZGVyIDwtDQogICAgZGF0YSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KCEhaWRfdmFyX2VucSwgISF0aW1lX3Zhcl9lbnEsICEhY29uZF92YXJfZW5xLCAhIXZhbHVlX3Zhcl9lbnEpICU+JQ0KICAgIHNwcmVhZChrZXkgPSB0aW1lX3Zhcl9uYW1lLCB2YWx1ZSA9IHZhbHVlX3Zhcl9uYW1lKSAjICU+JSAgICAgIyBpZiBuZWVkIHRvIGNvbXB1dGUgY2hhbmdlIHNjb3JlIHN0YXRpc3RpY3MgZ28gZnJvbSBoZXJlDQogICAgIyBtdXRhdGUoZGlmZmVyZW5jZSA9ICEhcG9zdF92YXJfZW5xIC0gISFwcmVfdmFyX2VucSkgIA0KICAgIA0KICAjIEFzc3VtcHRpb25zDQogIGlmKGFzc3VtX2NoZWNrKXsNCiAgY2F0KCJcbiBMaW5lYXJpdHkgYXNzdW1wdGlvbkxpbmVhcml0eSBhc3N1bXB0aW9uIChsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcHJlLXRlc3QgYW5kIHBvc3QtdGVzdCBmb3IgZWFjaCBncm91cCkgXG4iKQ0KICAjIENyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBiZXR3ZWVuIHRoZSBjb3ZhcmlhdGUgKGkuZS4sIHByZXRlc3QpIGFuZCB0aGUgb3V0Y29tZSB2YXJpYWJsZSAoaS5lLiwgcG9zdHRlc3QpDQogIHNjYXR0ZXJfbGluIDwtICANCiAgICBnZ3NjYXR0ZXIoZGF0YV93aWRlciwgeCA9IHByZV92YXJfbmFtZSwgeSA9IHBvc3RfdmFyX25hbWUsIGNvbG9yID0gY29uZF92YXJfbmFtZSwgDQogICAgICAgICAgICAgIGFkZCA9ICJyZWcubGluZSIsIHRpdGxlID0gIkxpbmVhcml0eSBhc3N1bXB0aW9uIikgKw0KICAgICAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGFlcyhsYWJlbCA9ICBwYXN0ZSguLmVxLmxhYmVsLi4sIC4ucnIubGFiZWwuLiwgc2VwID0gIn5+fn4iKSwgY29sb3IgPSAhIWNvbmRfdmFyX2VucSkpDQogIA0KICBjYXQoIlxuIEhvbW9nZW5laXR5IG9mIHJlZ3Jlc3Npb24gc2xvcGVzIChpbnRlcmFjdGlvbiB0ZXJtIGlzIG4ucy4pIFxuIikNCiAgZGF0YV93aWRlciAlPiUgDQogICAgYW5vdmFfdGVzdChhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSwgIiAqICIsIHByZV92YXJfbmFtZSkpKSAlPiUgDQogICAgcHJpbnQoKSAgIA0KICANCiAgY2F0KCJcbiBOb3JtYWxpdHkgb2YgcmVzaWR1YWxzIChNb2RlbCBkaWFnbm9zdGljcyAmIFNoYXBpcm8gV2lsaykgXG4iKQ0KICAjIEZpdCB0aGUgbW9kZWwsIHRoZSBjb3ZhcmlhdGUgZ29lcyBmaXJzdA0KICBtb2RlbCA8LSANCiAgICBsbShhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSwgIiArICIsIHByZV92YXJfbmFtZSkpLA0KICAgICAgIGRhdGEgPSBkYXRhX3dpZGVyKQ0KICBjYXQoIlxuIEluc3BlY3QgdGhlIG1vZGVsIGRpYWdub3N0aWMgbWV0cmljcyBcbiIpDQogIG1vZGVsLm1ldHJpY3MgPC0gDQogICAgYXVnbWVudChtb2RlbCkgJT4lDQogICAgZHBseXI6OnNlbGVjdCgtLmhhdCwgLS5zaWdtYSwgLS5maXR0ZWQsIC0uc2UuZml0KSAgJT4lICAgICMgUmVtb3ZlIGRldGFpbHMNCiAgICBwcmludCgpDQogIGNhdCgiXG4gTm9ybWFsaXR5IG9mIHJlc2lkdWFscyAoU2hhcGlybyBXaWxrIHA+LjA1KSBcbiIpDQogIHNoYXBpcm9fdGVzdChtb2RlbC5tZXRyaWNzJC5yZXNpZCkgJT4lIA0KICAgIHByaW50KCkNCiAgDQogIGNhdCgiXG4gSG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VzIChMZXZlbmXigJlzIHRlc3QgcD4uMDUpIFxuIikNCiAgbW9kZWwubWV0cmljcyAlPiUgDQogICAgbGV2ZW5lX3Rlc3QoYXMuZm9ybXVsYShwYXN0ZTAoIi5yZXNpZCIsICIgfiAiLCBjb25kX3Zhcl9uYW1lKSkgKSAlPiUgICAgIA0KICAgIHByaW50KCkNCiAgDQogIGNhdCgiXG4gT3V0bGllcnMgKG5lZWRzIHRvIGJlIDApIFxuIikNCiAgbW9kZWwubWV0cmljcyAlPiUgDQogICAgZmlsdGVyKGFicyguc3RkLnJlc2lkKSA+IDMpICU+JQ0KICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogICAgcHJpbnQoKQ0KICANCiAgfQ0KICANCiAgY2F0KCJcbiBBTkNPVkFQb3N0IFxuIikNCiAgcmVzX2FuY292YSA8LSANCiAgICBkYXRhX3dpZGVyICU+JSANCiAgICBhbm92YV90ZXN0KGFzLmZvcm11bGEocGFzdGUwKHBvc3RfdmFyX25hbWUsICIgfiAiLCAgcHJlX3Zhcl9uYW1lLCAiICsgIiwgY29uZF92YXJfbmFtZSkpKSAgICAgICAjIHRoZSBjb3ZhcmlhdGUgbmVlZHMgdG8gYmUgZmlyc3QgdGVybSANCiAgZ2V0X2Fub3ZhX3RhYmxlKHJlc19hbmNvdmEpICU+JSBwcmludCgpDQogIA0KICBjYXQoIlxuIFBhaXJ3aXNlIGNvbXBhcmlzb25zIFxuIikNCiAgcHdjIDwtIA0KICAgIGRhdGFfd2lkZXIgJT4lIA0KICAgIGVtbWVhbnNfdGVzdChhcy5mb3JtdWxhKHBhc3RlMChwb3N0X3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpLCAgICAgICANCiAgICAgICAgICAgICAgICAgY292YXJpYXRlID0gISFwcmVfdmFyX2VucSwNCiAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gcF9hZGp1c3RfbWV0aG9kKQ0KICBwd2MgJT4lIHByaW50KCkNCiAgY2F0KCJcbiBEaXNwbGF5IHRoZSBhZGp1c3RlZCBtZWFucyBvZiBlYWNoIGdyb3VwLCBhbHNvIGNhbGxlZCBhcyB0aGUgZXN0aW1hdGVkIG1hcmdpbmFsIG1lYW5zIChlbW1lYW5zKSBcbiIpDQogIGdldF9lbW1lYW5zKHB3YykgJT4lIHByaW50KCkNCiAgDQogICMgVmlzdWFsaXphdGlvbjogbGluZSBwbG90cyB3aXRoIHAtdmFsdWVzDQogIHB3YyA8LSANCiAgICBwd2MgJT4lIA0KICAgIGFkZF94eV9wb3NpdGlvbih4ID0gY29uZF92YXJfbmFtZSwgZnVuID0gIm1lYW5fc2UiKQ0KICANCiAgbGluZV9wbG90IDwtIA0KICAgIGdnbGluZShnZXRfZW1tZWFucyhwd2MpLCB4ID0gY29uZF92YXJfbmFtZSwgeSA9ICJlbW1lYW4iKSArDQogICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gY29uZi5sb3csIHltYXggPSBjb25mLmhpZ2gpLCB3aWR0aCA9IDAuMikgKyANCiAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChwd2MsIGhpZGUubnMgPSBUUlVFLCB0aXAubGVuZ3RoID0gRkFMU0UpICsNCiAgICAgIGxhYnMoc3VidGl0bGUgPSBnZXRfdGVzdF9sYWJlbChyZXNfYW5jb3ZhLCBkZXRhaWxlZCA9IFRSVUUpLA0KICAgICAgICAgICBjYXB0aW9uID0gZ2V0X3B3Y19sYWJlbChwd2MpKQ0KICANCiAgaWYoYXNzdW1fY2hlY2spew0KICAgIGxpc3Qoc2NhdHRlcl9saW4sIGxpbmVfcGxvdCkNCiAgfWVsc2V7DQogICAgbGluZV9wbG90DQogIH0NCiAgDQp9DQoNCiMgZXguDQojIEFOQ09WQVBvc3RfZnVuYyhuZXdfYW54aWV0eSwgdGltZV92YXIgPSB0aW1lLCBwcmVfbGFiZWwgPSBwcmV0ZXN0LCBwb3N0X2xhYmVsID0gcG9zdHRlc3QsDQojICAgICAgICAgICB2YWx1ZV92YXIgPSBzY29yZXMsIGNvbmRfdmFyID0gZ3JvdXAsIGFzc3VtX2NoZWNrID0gVFJVRSwgcF9hZGp1c3RfbWV0aG9kID0gImJvbmZlcnJvbmkiKQ0KYGBgDQoNCg0KYGBge3IgZGVmX2Z1bmNfbWl4ZWRBTk9WQX0NCiMgbGlicmFyeSh0aWR5dmVyc2UpDQojIGxpYnJhcnkoZ2dwdWJyKQ0KIyBsaWJyYXJ5KHJzdGF0aXgpDQojIGxpYnJhcnkocmxhbmcpDQoNCiMgRGVmaW5lIEZ1bmN0aW9uIGZvciBNaXhlZCBBbm92YQ0KdHdfbWl4ZWRBTk9WQV9mdW5jIDwtIA0KICBmdW5jdGlvbihkYXRhLCBpZF92YXIsIGNvbmRfdmFyLCB0aW1lX3ZhciwgdmFsdWVfdmFyLCANCiAgICAgICAgICAgYXNzdW1fY2hlY2sgPSBUUlVFLCBwb3N0aG9jX3NpZ19pbnRlcmFjID0gRkFMU0UsIHBvc3Rob2NfbnNfaW50ZXJhYyA9IEZBTFNFLA0KICAgICAgICAgICBwX2FkanVzdF9tZXRob2QgPSAiYm9uZmVycm9uaSIpew0KICAgIA0KICAgICMgaW5wdXQgZGF0YWZyYW1lIG5lZWRzIHRvIGhhdmUgY29sdW1ucyBuYW1lcyBkaWZmcmVudCBmcm9tICJ2YXJpYWJsZSIgYW5kICJ2YWx1ZSIgYmVjYXVzZSBpdCBjb2xsaWRlcyB3aXRoIHJzdGF0aXg6OnNoYXBpcm9fdGVzdA0KICAgIA0KICAgIGlkX3Zhcl9lbnEgPC0gcmxhbmc6OmVucXVvKGlkX3ZhcikgIA0KICAgIGNvbmRfdmFyX2VucSA8LSBybGFuZzo6ZW5xdW8oY29uZF92YXIpDQogICAgY29uZF92YXJfbmFtZSA8LSBybGFuZzo6YXNfbmFtZShjb25kX3Zhcl9lbnEpDQogICAgdGltZV92YXJfZW5xIDwtIHJsYW5nOjplbnF1byh0aW1lX3ZhcikNCiAgICB0aW1lX3Zhcl9uYW1lIDwtIHJsYW5nOjphc19uYW1lKHRpbWVfdmFyX2VucSkNCiAgICB2YWx1ZV92YXJfZW5xIDwtIHJsYW5nOjplbnF1byh2YWx1ZV92YXIpDQogICAgdmFsdWVfdmFyX25hbWUgPC0gcmxhbmc6OmFzX25hbWUodmFsdWVfdmFyX2VucSkNCiAgICANCiAgICBkYXRhIDwtICAgICAgICAgICAgICAgICAgIyBuZWVkIHRvIHN1YnNldCBiZWN1YXNlIG9mIHN0cmFuZ2UgY29udHJhc3RzIGVycm9yIGluIGFub3ZhX3Rlc3QoKQ0KICAgICAgZGF0YSAlPiUNCiAgICAgIGRwbHlyOjpzZWxlY3QoISFpZF92YXJfZW5xLCAhIXRpbWVfdmFyX2VucSwgISFjb25kX3Zhcl9lbnEsICEhdmFsdWVfdmFyX2VucSkgDQogICAgDQogICAgIyBBc3N1bXB0aW9ucw0KICAgIGlmKGFzc3VtX2NoZWNrKXsNCiAgICAgIGNhdCgiXG4gT3V0bGllcnMgXG4iKQ0KICAgICAgZGF0YSAlPiUNCiAgICAgICAgZHBseXI6Omdyb3VwX2J5KCEhdGltZV92YXJfZW5xLCAhIWNvbmRfdmFyX2VucSkgJT4lDQogICAgICAgIHJzdGF0aXg6OmlkZW50aWZ5X291dGxpZXJzKCEhdmFsdWVfdmFyX2VucSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgb3V0bGllcnMgKG5lZWRzIHRvIGJlIDApDQogICAgICAgIHByaW50KCkNCiAgICAgIA0KICAgICAgY2F0KCJcbiBOb3JtYWxpdHkgYXNzdW1wdGlvbiAocD4uMDUpIFxuIikNCiAgICAgIGRhdGEgJT4lDQogICAgICAgIGRwbHlyOjpncm91cF9ieSghIXRpbWVfdmFyX2VucSwgISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICByc3RhdGl4OjpzaGFwaXJvX3Rlc3QoISF2YWx1ZV92YXJfZW5xKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3JtYWxpdHkgYXNzdW1wdGlvbiAocD4uMDUpDQogICAgICAgIHByaW50KCkNCiAgICAgIA0KICAgICAgcXFfcGxvdCA8LSANCiAgICAgICAgZ2dwdWJyOjpnZ3FxcGxvdChkYXRhID0gZGF0YSwgdmFsdWVfdmFyX25hbWUsIGdndGhlbWUgPSB0aGVtZV9idygpLCB0aXRsZSA9ICJRUSBQbG90IikgKw0KICAgICAgICBnZ3Bsb3QyOjpmYWNldF9ncmlkKHZhcnMoISF0aW1lX3Zhcl9lbnEpLCB2YXJzKCEhY29uZF92YXJfZW5xKSwgbGFiZWxsZXIgPSAibGFiZWxfYm90aCIpICAgICMgUVEgcGxvdA0KICAgICAgDQogICAgICBjYXQoIlxuIEhvbW9nbmVpdHkgb2YgdmFyaWFuY2UgYXNzdW1wdGlvbiAtIExldmVuZeKAmXMgdGVzdCAocD4uMDUpIFxuIikNCiAgICAgIGRhdGEgJT4lDQogICAgICAgIGdyb3VwX2J5KCEhdGltZV92YXJfZW5xICkgJT4lDQogICAgICAgIGxldmVuZV90ZXN0KGFzLmZvcm11bGEocGFzdGUwKHZhbHVlX3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpKSAlPiUNCiAgICAgICAgcHJpbnQoKQ0KICAgICAgDQogICAgICBjYXQoIlxuIEhvbW9nZW5laXR5IG9mIGNvdmFyaWFuY2VzIGFzc3VtcHRpb24gLSBCb3jigJlzIHRlc3Qgb2YgZXF1YWxpdHkgb2YgY292YXJpYW5jZSBtYXRyaWNlcyAocD4uMDAxKSBcbiIpDQogICAgICBib3hfbShkYXRhID0gZGF0YVssIHZhbHVlX3Zhcl9uYW1lLCBkcm9wID0gRkFMU0VdLCBncm91cCA9IGRhdGFbLCBjb25kX3Zhcl9uYW1lLCBkcm9wID0gVFJVRV0pICU+JQ0KICAgICAgICBwcmludA0KICAgIH0NCiAgICANCiAgICAjIFR3by13YXkgcm1BTk9WQSAtIGNoZWNrIGZvciBpbnRlcmFjdGlvbiAoZXguIEYoMiwgMjIpID0gMzAuNCwgcCA8IDAuMDAwMSkNCiAgICBjYXQoIlxuIFR3by13YXkgcm1BTk9WQSBcbiIpDQogICAgcmVzX2FvdiA8LSANCiAgICAgIGFub3ZhX3Rlc3QoZGF0YSA9IGRhdGEsIGR2ID0gISF2YWx1ZV92YXJfZW5xLCB3aWQgPSAhIWlkX3Zhcl9lbnEsICAgICAgICAgICAgICAgIyBhdXRvbWF0aWNhbGx5IGRvZXMgc3BoZXJpY2l0eSBNYXVjaGx54oCZcyB0ZXN0DQogICAgICAgICAgICAgICAgIHdpdGhpbiA9ICEhdGltZV92YXJfZW5xLCBiZXR3ZWVuID0gISFjb25kX3Zhcl9lbnEpDQogICAgZ2V0X2Fub3ZhX3RhYmxlKHJlc19hb3YpICU+JSAgIyBnZXM6IEdyZWVuaG91c2UtR2Vpc3NlciBzcGhlcmljaXR5IGNvcnJlY3Rpb24gaXMgYXV0b21hdGljYWxseSBhcHBsaWVkIHRvIGZhY3RvcnMgdmlvbGF0aW5nIHRoZSBzcGhlcmljaXR5IGFzc3VtcHRpb24gIA0KICAgICAgcHJpbnQoKQ0KICAgIA0KICAgIA0KICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQogICAgDQogICAgIy0gUHJvY2VkdXJlIGZvciBhIHNpZ25pZmljYW50IHR3by13YXkgaW50ZXJhY3Rpb24gLQ0KICAgIGlmKHBvc3Rob2Nfc2lnX2ludGVyYWMpew0KICAgICAgY2F0KCJcbiBFZmZlY3Qgb2YgZ3JvdXAgYXQgZWFjaCB0aW1lIHBvaW50IC0gT25lLXdheSBBTk9WQVxuIikNCiAgICAgIG9uZV93YXkgPC0gDQogICAgICAgIGRhdGEgJT4lDQogICAgICAgIGdyb3VwX2J5KCEhdGltZV92YXJfZW5xKSAlPiUNCiAgICAgICAgYW5vdmFfdGVzdChkdiA9ICEhdmFsdWVfdmFyX2VucSwgd2lkID0gISFpZF92YXJfZW5xLCBiZXR3ZWVuID0gISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBnZXRfYW5vdmFfdGFibGUoKSAlPiUNCiAgICAgICAgYWRqdXN0X3B2YWx1ZShtZXRob2QgPSBwX2FkanVzdF9tZXRob2QpDQogICAgICBvbmVfd2F5ICU+JSBwcmludCgpDQogICAgICANCiAgICAgIGNhdCgiXG4gUGFpcndpc2UgY29tcGFyaXNvbnMgYmV0d2VlbiBncm91cCBsZXZlbHMgXG4iKQ0KICAgICAgcHdjIDwtIA0KICAgICAgICBkYXRhICU+JQ0KICAgICAgICBncm91cF9ieSghIXRpbWVfdmFyX2VucSkgJT4lDQogICAgICAgIHBhaXJ3aXNlX3RfdGVzdChhcy5mb3JtdWxhKHBhc3RlMCh2YWx1ZV92YXJfbmFtZSwgIiB+ICIsIGNvbmRfdmFyX25hbWUpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QpDQogICAgICBwd2MgJT4lIHByaW50KCkNCiAgICAgIGNhdCgiXG4gRWZmZWN0IG9mIHRpbWUgYXQgZWFjaCBsZXZlbCBvZiBleGVyY2lzZXMgZ3JvdXAgIC0gT25lLXdheSBBTk9WQSBcbiIpDQogICAgICBvbmVfd2F5MiA8LSANCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBhbm92YV90ZXN0KGR2ID0gISF2YWx1ZV92YXJfZW5xLCB3aWQgPSAhIWlkX3Zhcl9lbnEsIHdpdGhpbiA9ICEhdGltZV92YXJfZW5xKSAlPiUNCiAgICAgICAgZ2V0X2Fub3ZhX3RhYmxlKCkgJT4lDQogICAgICAgIGFkanVzdF9wdmFsdWUobWV0aG9kID0gcF9hZGp1c3RfbWV0aG9kKQ0KICAgICAgb25lX3dheTIgJT4lIHByaW50KCkNCiAgICAgIA0KICAgICAgY2F0KCJcbiBQYWlyd2lzZSBjb21wYXJpc29ucyBiZXR3ZWVuIHRpbWUgcG9pbnRzIGF0IGVhY2ggZ3JvdXAgbGV2ZWxzICh3ZSBoYXZlIHJlcGVhdGVkIG1lYXN1cmVzIGJ5IHRpbWUpIFxuIikNCiAgICAgIHB3YzIgPC0NCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoISFjb25kX3Zhcl9lbnEpICU+JQ0KICAgICAgICBwYWlyd2lzZV90X3Rlc3QoDQogICAgICAgICAgYXMuZm9ybXVsYShwYXN0ZTAodmFsdWVfdmFyX25hbWUsICIgfiAiLCB0aW1lX3Zhcl9uYW1lKSksICAgICAjIHBhc3RlIGZvcm11bGEsIG5vdCBxdW9zdXJlDQogICAgICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QNCiAgICAgICAgKQ0KICAgICAgcHdjMiAgJT4lIHByaW50KCkNCiAgICB9DQogICAgDQogICAgIy0gUHJvY2VkdXJlIGZvciBub24tc2lnbmlmaWNhbnQgdHdvLXdheSBpbnRlcmFjdGlvbi0gDQogICAgIyBJZiB0aGUgaW50ZXJhY3Rpb24gaXMgbm90IHNpZ25pZmljYW50LCB5b3UgbmVlZCB0byBpbnRlcnByZXQgdGhlIG1haW4gZWZmZWN0cyBmb3IgZWFjaCBvZiB0aGUgdHdvIHZhcmlhYmxlczogdHJlYXRtZW50IGFuZCB0aW1lLg0KICAgIGlmKHBvc3Rob2NfbnNfaW50ZXJhYyl7DQogICAgICBjYXQoIlxuIENvbXBhcmlzb25zIGZvciB0cmVhdG1lbnQgdmFyaWFibGUgXG4iKQ0KICAgICAgcHdjX2NvbmQgPC0NCiAgICAgICAgZGF0YSAlPiUNCiAgICAgICAgcGFpcndpc2VfdF90ZXN0KA0KICAgICAgICAgIGFzLmZvcm11bGEocGFzdGUwKHZhbHVlX3Zhcl9uYW1lLCAiIH4gIiwgY29uZF92YXJfbmFtZSkpLCAgICAgIyBwYXN0ZSBmb3JtdWxhLCBub3QgcXVvc3VyZSAgICAgICAgICAgICANCiAgICAgICAgICBwYWlyZWQgPSBGQUxTRSwNCiAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSBwX2FkanVzdF9tZXRob2QNCiAgICAgICAgKQ0KICAgICAgcHdjX2NvbmQgJT4lIHByaW50KCkNCiAgICAgIGNhdCgiXG4gQ29tcGFyaXNvbnMgZm9yIHRpbWUgdmFyaWFibGUgXG4iKQ0KICAgICAgcHdjX3RpbWUgPC0NCiAgICAgICAgZGF0YSAlPiUgDQogICAgICAgIHBhaXJ3aXNlX3RfdGVzdCgNCiAgICAgICAgICBhcy5mb3JtdWxhKHBhc3RlMCh2YWx1ZV92YXJfbmFtZSwgIiB+ICIsIHRpbWVfdmFyX25hbWUpKSwgICAgICMgcGFzdGUgZm9ybXVsYSwgbm90IHF1b3N1cmUNCiAgICAgICAgICBwYWlyZWQgPSBUUlVFLA0KICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9IHBfYWRqdXN0X21ldGhvZA0KICAgICAgICApDQogICAgICBwd2NfdGltZSAlPiUgcHJpbnQoKQ0KICAgIH0NCiAgICANCiAgICAjIFZpc3VhbGl6YXRpb24NCiAgICBieF9wbG90IDwtIA0KICAgICAgZ2dib3hwbG90KGRhdGEsIHggPSB0aW1lX3Zhcl9uYW1lLCB5ID0gdmFsdWVfdmFyX25hbWUsDQogICAgICAgICAgICAgICAgY29sb3IgPSBjb25kX3Zhcl9uYW1lLCBwYWxldHRlID0gImpjbyIpDQogICAgcHdjIDwtIA0KICAgICAgcHdjICU+JSANCiAgICAgIGFkZF94eV9wb3NpdGlvbih4ID0gdGltZV92YXJfbmFtZSkNCiAgICBieF9wbG90IDwtIA0KICAgICAgYnhfcGxvdCArIA0KICAgICAgc3RhdF9wdmFsdWVfbWFudWFsKHB3YywgdGlwLmxlbmd0aCA9IDAsIGhpZGUubnMgPSBUUlVFKSArDQogICAgICBsYWJzKA0KICAgICAgICBzdWJ0aXRsZSA9IGdldF90ZXN0X2xhYmVsKHJlc19hb3YsIGRldGFpbGVkID0gVFJVRSksDQogICAgICAgIGNhcHRpb24gPSBnZXRfcHdjX2xhYmVsKHB3YykNCiAgICAgICkNCiAgICANCiAgICBpZihhc3N1bV9jaGVjayl7IA0KICAgICAgbGlzdChxcV9wbG90LCBieF9wbG90KQ0KICAgIH1lbHNlew0KICAgICAgYnhfcGxvdA0KICAgIH0gDQogICAgDQogIH0NCg0KIyBleC4gLSBydW4gb24gbG9uZyBmb3JtYXQNCiMgdHdfbWl4ZWRBTk9WQV9mdW5jKGRhdGEgPSBhbnhpZXR5LCBpZF92YXIgPSBpZCwgY29uZF92YXIgPSBncm91cCwgdGltZV92YXIgPSB0aW1lLCB2YWx1ZV92YXIgPSBzY29yZSwNCiMgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpgYGANCg0KDQoNCiMgUmVhZCwgQ2xlYW4sIFJlY29kZQ0KDQpgYGB7ciByZWRfY2xlYW5fcmVjb2RlX21lcmdlLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCiN+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+DQojIFJlYWQsIENsZWFuLCBSZWNvZGUsIFVuaXRlDQojfn5+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+fg0KDQojIyBSZWFkIGZpbGVzDQpmb2xkZXIgPC0gIkM6L1VzZXJzL01paGFpL0Rlc2t0b3AvUiBOb3RlYm9va3Mvbm90ZWJvb2tzL1BBNC1yZXBvcnQiDQpmaWxlIDwtICJEYXRlX3B0X2FuYWxpemFfUEE0b25saW5lLnhsc3giDQoNCnNldHdkKGZvbGRlcikNCg0KIyBJRCBkZg0KaWRfZGYgPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKGZvbGRlciwgZmlsZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDEsIHdoaWNoID0gIklELXVyaSBhdHJpYnVpdGUiKSAgIA0KaWRfZGYgPC0gDQogIGlkX2RmICU+JQ0KICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKElELCBmaXhlZCgiICIpLCAiIikpICAgICAjIHJlbW92ZSB3aGl0ZSBzcGFjZXMNCmFsbChpZF9kZiRJRCA9PSB0b3VwcGVyKGlkX2RmJElEKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjaGVjayBpZiBhbGwgYXJlIHVwcGVyIGNhc2UNCg0KZmlyc3Rmb3JtX2RmIDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aChmb2xkZXIsIGZpbGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAwLCB3aGljaCA9ICJGb3JtdWxhciBkZSDDrm5zY3JpZXJlIMiZaSBjb25zaW0iKSANCmNvbG5hbWVzKGZpcnN0Zm9ybV9kZilbN10gPC0gImUtbWFpbCINCg0KYmFzZWxpbmVfZGYgPC0gZHBseXI6OmxlZnRfam9pbihpZF9kZiwgZmlyc3Rmb3JtX2RmLCBieSA9ICJlLW1haWwiKQ0KYmFzZWxpbmVfZGYgPC0gYmFzZWxpbmVfZGZbLCBjKDQ6OSwgMiwgMTA6bmNvbChiYXNlbGluZV9kZiksIDEsMyldICAgICAgICMgbW92ZSBjb2xzIGZyb20gaWRfZGYgdG8gYmFjayBzbyB3ZSBoYXZlIG1hdGNoaW5nIGNvbHMgaW5kZXggZm9yIGJhc2VsaW5lX2RmICYgZmlyc3Rmb3JtX2RmDQphbGwuZXF1YWwoY29sbmFtZXMoYmFzZWxpbmVfZGYpWzE6NzJdLCBjb2xuYW1lcyhmaXJzdGZvcm1fZGYpWzE6NzJdKSAgICAgICAgICAgICAjIGNoZWNrIGlmIGNvbG5hbWVzIG1hdGNoLCBleGNlcHQgSUQgYW5kIG5hbWUgdGhhdCB3aGVyZSBhZGRlZA0KDQp0YWJsZShiYXNlbGluZV9kZiRJRCkgIyBJRCA5QyBpcyBkb3VibGVkLCBjb21wbGV0ZWQgMiB0aW1lcw0Kd2hpY2goYmFzZWxpbmVfZGYkSUQgPT0gIjlDIikgICMgSUQgOUMgcm93IDI3IGlzIHBhcnRpYWxseSBjb21wbGV0ZWQsIGV4Y3V0ZWQgaXQNCmJhc2VsaW5lX2RmIDwtIGJhc2VsaW5lX2RmWy0yNyAsXQ0KYGBgDQoNCg0KYGBge3IgZGFzZH0NCiMjIFNldHRpbmdzDQpjdXRvZmZQQ0wgPC0gMzIgICAjIGxpdGVyYXR1cmU6IDMxLTMzIG9yIDM4IA0KYWxnUENMIDwtIGRhdGEuZnJhbWUoQiA9IDEsIEMgPSAxLCBEID0gMiwgRSA9IDIpDQphbGdQQ0xfc3ViY2xpbiA8LSBkYXRhLmZyYW1lKEIgPSAxLCBDID0gMSwgRCA9IDEsIEUgPSAxKQ0KDQpjdXRvZmZNQklfRXggPC0gMi4yMCAgDQpjdXRvZmZNQklfQ3kgPC0gMg0KIyMNCg0KIyMgRGF0YQ0KRGF0YSA8LSBiYXNlbGluZV9kZg0KIyMNCg0KIyBEZWZpbmUgY29sdW1uIGluZGV4OiAgaW5kZXggPSBjb2wgaW5kZXg7IGl0ZW1pbmRleCA9IGluZGV4IG9mIGl0ZW0gaW4gcXVlc3Rpb25uYWlyZQ0KaW5kZXhTSUcgPC0gNjA6NjcgLSAxMCAgICAjIG1vZGlmaWVkIGluIG5ldyB0YWJsZSBieSAxMA0KaW5kZXhNQkkgPC0gNjg6ODMgLSAxMA0KaW5kZXhQQ0wgPC0gMTU5OjE3OCAtIDEwDQppdGVtaW5kZXhNQklfRXggPC0gYygxLCAzLCA1LCAxMSwgMTQpDQppdGVtaW5kZXhNQklfQ3kgPC0gYygyLCA3LCA4LCAxMywgMTUpDQppdGVtaW5kZXhNQklfUGUgPC0gYyg0LCA2LCA5LCAxMCwgMTIsIDE2KQ0KDQojIFJlbmFtZSBjb2x1bW5zDQojIG5hbWVzKERhdGEpWzE6MTJdIDwtIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChuYW1lcyhEYXRhKVsxOjEyXSwgIltbOmJsYW5rOl1dIiwgIl8iKQ0KIyBuYW1lcyhEYXRhKVsxN10gPC0gIlJlYWxfRW1haWwiDQojIG5hbWVzKERhdGEpWzE4XSA8LSAiUmVhbF9UZWwiDQojIG5hbWVzKERhdGEpWzE5XSA8LSAiUmVhbF9OYW1lIg0KIyBuYW1lcyhEYXRhKVs1MF0gPC0gIlJlYWxfQWdlX2NhdGVnIg0KDQpuYW1lcyhEYXRhKVs0MF0gPC0gIkFnZV9jYXRlZyINCm5hbWVzKERhdGEpWzQxXSA8LSAiU2V4Ig0KDQpuYW1lcyhEYXRhKVtuYW1lcyhEYXRhKSAlaW4lIG5hbWVzKERhdGFbLCBpbmRleFNJR10pXSAgPC0gYyhzcHJpbnRmKCJTSUdfJTAxZCIsIHNlcSgxLCA4KSkpDQpuYW1lcyhEYXRhKVtuYW1lcyhEYXRhKSAlaW4lIG5hbWVzKERhdGFbLCBpbmRleE1CSV0pXSAgPC0gYyhzcHJpbnRmKCJNQklfJTAxZCIsIHNlcSgxLCAxNikpKQ0KbmFtZXMoRGF0YSlbbmFtZXMoRGF0YSkgJWluJSBuYW1lcyhEYXRhWywgaW5kZXhQQ0xdKV0gIDwtIGMoc3ByaW50ZigiUENMXyUwMWQiLCBzZXEoMSwgMjApKSkNCg0KDQojIERhdGEgPC0NCiMgICBEYXRhICU+JQ0KIyAgIGRwbHlyOjpmaWx0ZXIoUmVzcG9uc2VfU3RhdHVzID09ICJjb21wbGV0ZWQiKSAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzZWxlY3Qgb25seSBjb21wbGV0ZSBjYXNlcw0KIA0KDQojIFJlY29kZSANCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJlY29kZXMgdG8gbnVtZXJpYywgYnV0IHdhdGNoZXMgb3V0IHRvIGNvZXJjaW9uIHRvIG5vdCBpbnRyb2R1Y2UgTkFzDQpjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgdHJ5Q2F0Y2goew0KICAgIGRmX251bSA8LSBhcy5kYXRhLmZyYW1lKA0KICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHsgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpfSkpIA0KICB9LHdhcm5pbmcgPSBmdW5jdGlvbihzdG9wX29uX3dhcm5pbmcpIHsNCiAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgfSkgDQp9DQojIw0KIyMgRGVmaW5lIGZ1bmN0aW9uIHRoYXQgcmV2ZXJzZSBjb2RlcyBpdGVtcw0KUmV2ZXJzZUNvZGUgPC0gZnVuY3Rpb24oZGYsIHRvbnVtZXJpYyA9IEZBTFNFLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikNCiAgZGYgPC0gKG1heCArIG1pbikgLSBkZg0KfQ0KIyMNCg0KIyBsYXBwbHkoRGF0YVssaW5kZXhQQ0xdLCB1bmlxdWUpDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJkZWxvYyJdIDwtICIwIg0KRGF0YVsgLGluZGV4UENMXVsgRGF0YVsgLGluZGV4UENMXSA9PSAicHXIm2luIl0gPC0gIjEiDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJtb2RlcmF0Il0gPC0gIjIiDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJtdWx0Il0gPC0gIjMiDQpEYXRhWyAsaW5kZXhQQ0xdWyBEYXRhWyAsaW5kZXhQQ0xdID09ICJmb2FydGUgbXVsdCJdIDwtICI0Ig0KRGF0YVsgLGluZGV4UENMXVsgRGF0YVsgLGluZGV4UENMXSA9PSAiTm90IEFuc3dlcmVkIl0gPC0gTkENCg0KRGF0YVsgLGluZGV4U0lHXVsgRGF0YVsgLGluZGV4U0lHXSA9PSAiTlUiXSA8LSAiMCINCkRhdGFbICxpbmRleFNJR11bIERhdGFbICxpbmRleFNJR10gPT0gIj8iXSA8LSAiMS41Ig0KRGF0YVsgLGluZGV4U0lHXVsgRGF0YVsgLGluZGV4U0lHXSA9PSAiREEiXSA8LSAiMyINCkRhdGFbICxpbmRleFNJR11bIERhdGFbICxpbmRleFNJR10gPT0gIk5vdCBBbnN3ZXJlZCJdIDwtIE5BDQoNCkRhdGFbICxpbmRleE1CSV0gPC0gZGF0YS5mcmFtZShsYXBwbHkoRGF0YVsgLGluZGV4TUJJXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKk5pY2lvZGF0LioiLCAiMCIsIHgpfSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCkRhdGFbICxpbmRleE1CSV0gPC0gZGF0YS5mcmFtZShsYXBwbHkoRGF0YVsgLGluZGV4TUJJXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKlppbG5pYy4qIiwgIjYiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpEYXRhWyAsaW5kZXhNQkldWyBEYXRhWyAsaW5kZXhNQkldID09ICJOb3QgQW5zd2VyZWQiXSA8LSBOQQ0KDQoNCkRhdGFbLCBpbmRleFNJR10gPC0gY29sc3RvbnVtZXJpYyhEYXRhWywgaW5kZXhTSUddKQ0KRGF0YVssIGluZGV4TUJJXSA8LSBjb2xzdG9udW1lcmljKERhdGFbLCBpbmRleE1CSV0pDQpEYXRhWywgaW5kZXhQQ0xdIDwtIGNvbHN0b251bWVyaWMoRGF0YVssIGluZGV4UENMXSkNCg0KDQoNCiMgU2NvcmVzDQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBzY29yZXMgb25seSByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXMgKHJldHVybnMgTkEgaWYgYWxsIG9yIGFib3ZlIHRocmVzaG9sZCBwZXJjZW50YWdlIG9mIHJvd3MgYXJlIE5BKTsgY2FuIHJldmVyc2UgY29kZSBpZiB2ZWN0b3Igb2YgY29sdW1uIGluZGV4ZXMgYW5kIG1pbiwgbWF4IGFyZSBwcm92aWRlZC4NClNjb3JlTGlrZXJ0IDwtIGZ1bmN0aW9uKGRmLCBzdGF0ID0gInN1bSIsIG5hdG96ZXJvID0gRkFMU0UsIG5hcGVyY2VudCA9IC4xLCB0b251bWVyaWMgPSBGQUxTRSwgcmV2ZXJzZWNvbHMgPSBOVUxMLCBtaW4gPSBOVUxMLCBtYXggPSBOVUxMKSB7DQogIHJldmVyc2VfbGlzdCA8LSBsaXN0KHJldmVyc2Vjb2xzID0gcmV2ZXJzZWNvbHMsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KQ0KICByZXZlcnNlX2NoZWNrIDwtICFzYXBwbHkocmV2ZXJzZV9saXN0LCBpcy5udWxsKQ0KICANCiAgIyBSZWNvZGUgdG8gbnVtZXJpYywgYnV0IHdhdGNoIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KICBjb2xzdG9udW1lcmljIDwtIGZ1bmN0aW9uKGRmKXsNCiAgICB0cnlDYXRjaCh7DQogICAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgICAgbGFwcGx5KGRmLA0KICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgeyBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4KSl9KSkgDQogICAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgICBtZXNzYWdlKCJTdG9wZWQgdGhlIGV4ZWN1dGlvbiBvZiBudW1lcmljIGNvbnZlcnNpb246ICIsIGNvbmRpdGlvbk1lc3NhZ2Uoc3RvcF9vbl93YXJuaW5nKSkNCiAgICB9KSANCiAgfQ0KICANCiAgaWYodG9udW1lcmljKSBkZiA8LSBjb2xzdG9udW1lcmljKGRmKQ0KICANCiAgaWYoYWxsKHJldmVyc2VfY2hlY2spKXsNCiAgICBkZlsgLHJldmVyc2Vjb2xzXSA8LSAobWF4ICsgbWluKSAtIGRmWyAscmV2ZXJzZWNvbHNdDQogIH1lbHNlIGlmKGFueShyZXZlcnNlX2NoZWNrKSl7DQogICAgc3RvcCgiSW5zdWZpY2llbnQgaW5mbyBmb3IgcmV2ZXJzaW5nLiBQbGVhc2UgcHJvdmlkZTogIiwgcGFzdGUobmFtZXMocmV2ZXJzZV9saXN0KVshcmV2ZXJzZV9jaGVja10sIGNvbGxhcHNlID0gIiwgIikpDQogIH0NCiAgDQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgDQogIGlmKG5hdG96ZXJvKSBkZltpcy5uYShkZildIDwtIDAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE5BcyB0byAwIGNhbiBoZWxwIHdoZW4gc3RhdCA9ICJtZWFuIiB3aXRoIG5hLnJtID0gVCBiZWNhdXNlIGl0IGtlZXBzIGRlbm9taW5hdG9yIGNvbnN0YW50DQogIA0KICBpZihzdGF0ID09ICJzdW0iKXsNCiAgZGZfcmVzIDwtIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgICAgICAgICAgICBOQSwNCiAgICAgICAgICAgICAgICAgICByb3dTdW1zKGRmLCBuYS5ybSA9IFRSVUUpICogTkEgXiAocm93U3VtcyghaXMubmEoZGYpKSA9PSAwKSkNCiAgfQ0KICBpZihzdGF0ID09ICJtZWFuIil7DQogICAgZGZfcmVzIDwtIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgICAgICAgICAgICAgIE5BLA0KICAgICAgICAgICAgICAgICAgICAgcm93TWVhbnMoZGYsIG5hLnJtID0gVFJVRSkgKiBOQSBeIChyb3dTdW1zKCFpcy5uYShkZikpID09IDApKQ0KICB9DQogIHJldHVybihkZl9yZXMpDQp9DQojIw0KDQoNCiMgU2NvcmUgUENMDQpEYXRhJFBDTF9Ub3RhbCA8LSBTY29yZUxpa2VydChEYXRhWywgaW5kZXhQQ0xdLCBuYXBlcmNlbnQgPSAuMykgICAgICAgICAgICAgICAjIE5BIGlmIE5BIHRocmVzaG9sZCBpcyBleGNlZWRlZCANCkRhdGEkUENMX0IgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiUENMXyUwMWQiLCAxOjUpKV0sIG5hcGVyY2VudCA9IDEpICAgICMgZG8gbm90aGluZyBpZiBOQSB0aHJlc2hvbGQgaXMgZXhjZWVkZWQNCkRhdGEkUENMX0MgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiUENMXyUwMWQiLCA2OjcpKV0sIG5hcGVyY2VudCA9IDEpIA0KRGF0YSRQQ0xfRCA8LSBTY29yZUxpa2VydChEYXRhWywgYyhzcHJpbnRmKCJQQ0xfJTAxZCIsIDg6MTQpKV0sIG5hcGVyY2VudCA9IDEpICANCkRhdGEkUENMX0UgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiUENMXyUwMWQiLCAxNToyMCkpXSwgbmFwZXJjZW50ID0gMSkNCg0KIyBTY29yZSBTSUcNCkRhdGEkU0lHX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KERhdGFbLCBpbmRleFNJR10sIG5hcGVyY2VudCA9IC4zKQ0KDQojIFNjb3JlIE1CSQ0KRGF0YSRNQklfVG90YWwgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGluZGV4TUJJXSwgbmFwZXJjZW50ID0gLjMsIHN0YXQgPSAibWVhbiIsIG5hdG96ZXJvID0gVFJVRSkNCkRhdGEkTUJJX0V4IDwtIFNjb3JlTGlrZXJ0KERhdGFbLCBjKHNwcmludGYoIk1CSV8lMDFkIiwgaXRlbWluZGV4TUJJX0V4KSldLCBuYXBlcmNlbnQgPSAxLCBzdGF0ID0gIm1lYW4iLCBuYXRvemVybyA9IFRSVUUpDQpEYXRhJE1CSV9DeSA8LSBTY29yZUxpa2VydChEYXRhWywgYyhzcHJpbnRmKCJNQklfJTAxZCIsIGl0ZW1pbmRleE1CSV9DeSkpXSwgbmFwZXJjZW50ID0gMSwgc3RhdCA9ICJtZWFuIiwgbmF0b3plcm8gPSBUUlVFKQ0KRGF0YSRNQklfUGUgPC0gU2NvcmVMaWtlcnQoRGF0YVssIGMoc3ByaW50ZigiTUJJXyUwMWQiLCBpdGVtaW5kZXhNQklfUGUpKV0sIG5hcGVyY2VudCA9IDEsIHN0YXQgPSAibWVhbiIsIG5hdG96ZXJvID0gVFJVRSkNCg0KDQojIFBDTCBEaWFnbm9zdGljIEFsZ29yaXRobQ0KaXRlbXNQQ0xfQiA8LSBjKHNwcmludGYoIlBDTF8lMDFkIiwgMTo1KSkNCml0ZW1zUENMX0MgPC0gYyhzcHJpbnRmKCJQQ0xfJTAxZCIsIDY6NykpDQppdGVtc1BDTF9EIDwtIGMoc3ByaW50ZigiUENMXyUwMWQiLCA4OjE0KSkNCml0ZW1zUENMX0UgPC0gYyhzcHJpbnRmKCJQQ0xfJTAxZCIsIDE1OjIwKSkNCg0KRGF0YVBDTEFsZyA8LSAgDQogIERhdGEgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHRpZHlzZWxlY3Q6OmFsbF9vZihpbmRleFBDTCkpICU+JSANCiAgZHBseXI6Om11dGF0ZV9hbGwoDQogICAgZnVucyhjYXNlX3doZW4oDQogICAgICAuID49MiB+IDEsDQogICAgICAjIC4gPDIgfiAwLA0KICAgICAgaXMubmEoLikgfiAwLA0KICAgICAgVFJVRSAgfiAgMCkpKSAlPiUgDQogIA0KICBtdXRhdGUoUENMX0NyaXRCID0gY2FzZV93aGVuKHJvd1N1bXMoLlssaXRlbXNQQ0xfQl0sIG5hLnJtID0gVFJVRSkgPj0gYWxnUENMJEIgfiAxLCAgICAgICMgYWxnUENMIDwtIGRhdGEuZnJhbWUoQiA9IDEsIEMgPSAxLCBEID0gMiwgRSA9IDIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByb3dTdW1zKC5bLGl0ZW1zUENMX0JdLCBuYS5ybSA9IFRSVUUpIDwxIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgJT4lIA0KICBtdXRhdGUoUENMX0NyaXRDID0gY2FzZV93aGVuKHJvd1N1bXMoLlssaXRlbXNQQ0xfQ10sIG5hLnJtID0gVFJVRSkgPj0gYWxnUENMJEMgfiAxLCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfQ10sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQ3JpdEQgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9EXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0wkRCB+IDEsICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByb3dTdW1zKC5bLGl0ZW1zUENMX0RdLCBuYS5ybSA9IFRSVUUpIDwxIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgJT4lIA0KICBtdXRhdGUoUENMX0NyaXRFID0gY2FzZV93aGVuKHJvd1N1bXMoLlssaXRlbXNQQ0xfRV0sIG5hLnJtID0gVFJVRSkgPj0gYWxnUENMJEUgfiAxLCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfRV0sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQWxnID0gY2FzZV93aGVuKFBDTF9Dcml0QiA9PSAxICYgUENMX0NyaXRDID09IDEgJiBQQ0xfQ3JpdEQgPT0gMSAmIFBDTF9Dcml0RSA9PSAxIH4gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSAgfiAgMCkpIA0KDQpEYXRhJFBDTEFsZyA8LSBEYXRhUENMQWxnJFBDTF9BbGcNCg0KRGF0YVBDTEFsZ19zdWJjbGluIDwtICANCiAgRGF0YSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodGlkeXNlbGVjdDo6YWxsX29mKGluZGV4UENMKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlX2FsbCgNCiAgICBmdW5zKGNhc2Vfd2hlbigNCiAgICAgIC4gPj0yIH4gMSwNCiAgICAgICMgLiA8MiB+IDAsDQogICAgICBpcy5uYSguKSB+IDAsDQogICAgICBUUlVFICB+ICAwKSkpICU+JSANCiAgDQogIG11dGF0ZShQQ0xfQ3JpdEIgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9CXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0xfc3ViY2xpbiRCIH4gMSwgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcm93U3VtcyguWyxpdGVtc1BDTF9CXSwgbmEucm0gPSBUUlVFKSA8MSB+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSAgfiAgMCkpICU+JSANCiAgbXV0YXRlKFBDTF9Dcml0QyA9IGNhc2Vfd2hlbihyb3dTdW1zKC5bLGl0ZW1zUENMX0NdLCBuYS5ybSA9IFRSVUUpID49IGFsZ1BDTF9zdWJjbGluJEMgfiAxLCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfQ10sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQ3JpdEQgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9EXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0xfc3ViY2xpbiREIH4gMSwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJvd1N1bXMoLlssaXRlbXNQQ0xfRF0sIG5hLnJtID0gVFJVRSkgPDEgfiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDApKSAlPiUgDQogIG11dGF0ZShQQ0xfQ3JpdEUgPSBjYXNlX3doZW4ocm93U3VtcyguWyxpdGVtc1BDTF9FXSwgbmEucm0gPSBUUlVFKSA+PSBhbGdQQ0xfc3ViY2xpbiRFIH4gMSwgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByb3dTdW1zKC5bLGl0ZW1zUENMX0VdLCBuYS5ybSA9IFRSVUUpIDwxIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgJT4lIA0KICBtdXRhdGUoUENMX0FsZ19zdWJjbGluID0gY2FzZV93aGVuKFBDTF9Dcml0QiA9PSAxICYgUENMX0NyaXRDID09IDEgJiBQQ0xfQ3JpdEQgPT0gMSAmIFBDTF9Dcml0RSA9PSAxIH4gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFICB+ICAwKSkgDQoNCkRhdGEkUENMQWxnX3N1YmNsaW4gPC0gRGF0YVBDTEFsZ19zdWJjbGluJFBDTF9BbGdfc3ViY2xpbg0KDQpEYXRhJE1CSV9FeF9jdXQgPC0gaWZlbHNlKERhdGEkTUJJX0V4ID49IGN1dG9mZk1CSV9FeCwgMSwgMCkNCkRhdGEkTUJJX0N5X2N1dCA8LSBpZmVsc2UoRGF0YSRNQklfQ3kgPj0gY3V0b2ZmTUJJX0N5LCAxLCAwKQ0KDQoNCiMgR2xvYmFsIFNjcmVlbmluZyAmIEdyb3Vwcw0KZGZfc2NyZWVuaW5nIDwtIERhdGFbLGMoIklEIiwgIm51bWUiLCAiZS1tYWlsIiwgIkFnZV9jYXRlZyIsICJTZXgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIlNJR19Ub3RhbCIsICJNQklfRXhfY3V0IiwgIk1CSV9DeV9jdXQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIlBDTF9Ub3RhbCIsICJQQ0xfQiIsICJQQ0xfQyIsICJQQ0xfRCIsICJQQ0xfRSIsICJQQ0xBbGciLCAiUENMQWxnX3N1YmNsaW4iKV0NCmlkc19wdHNkIDwtDQogIGRmX3NjcmVlbmluZyAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKFBDTEFsZyA9PSAxKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmlkc19idXJuIDwtDQogIGRmX3NjcmVlbmluZyAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKE1CSV9FeF9jdXQgPT0gMSwgTUJJX0N5X2N1dCA9PSAxKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmlkc19vbGQgPC0NCiAgZGZfc2NyZWVuaW5nICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXIoQWdlX2NhdGVnID09ICJwZXN0ZSA2NSBhbmkiKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmlkc19ub3JtYWwgPC0NCiAgIGRmX3NjcmVlbmluZyAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKCEoSUQgJWluJSBjKGlkc19wdHNkLCBpZHNfYnVybiwgaWRzX29sZCkpKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KElEKSAlPiUNCiAgICBkcGx5cjo6cHVsbCgpDQoNCmludGVyc2VjdChpZHNfcHRzZCwgaWRzX2J1cm4pICAgIyA4IGNvbW1vbg0KaW50ZXJzZWN0KGlkc19wdHNkLCBpZHNfb2xkKSAgICAjIG5vIG9sZCB3aXRoIFBUU0QNCmludGVyc2VjdChpZHNfcHRzZCwgaWRzX29sZCkgICAgIyBubyBvbGQgd2l0aCBCdXJuIE91dA0KbGVuZ3RoKHVuaXF1ZShjKGlkc19wdHNkLCBpZHNfYnVybiwgaWRzX29sZCwgaWRzX25vcm1hbCkpKSA9PSA3NiAgIyBhbGwgZ29vZA0KDQoNCmlkc19ncm91cHNfZGY8LSANCiAgRGF0YSAlPiUNCiAgZHBseXI6OnNlbGVjdCgxNzMsIDE3NToxODgpDQpgYGANCg0KDQoNCg0KIyBPdXRjb21lIE1lYXN1cmVzDQoNCiMgRGljdGF0b3IgR2FtZQ0KDQpgYGB7ciBkZ19zY29yaW5nLCByZXN1bHRzPSdoaWRlJ30NCiMgREcgZGYNCmRnX2RmX3ByZSA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDAsIHdoaWNoID0gIkRpY3RhdG9yR2FtZSBwcmUiKQ0KY29sbmFtZXMoZGdfZGZfcHJlKVs0XSA8LSAiSUQiDQpkZ19kZl9wcmUgPC0gDQogIGRnX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChJRCwgZml4ZWQoIiAiKSwgIiIpKSAlPiUgICAgIyByZW1vdmUgd2hpdGUgc3BhY2VzDQogIGRwbHlyOjptdXRhdGUoSUQgPSB0b3VwcGVyKElEKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdG8gdXBwZXINCmFsbChkZ19kZl9wcmUkSUQgPT0gdG91cHBlcihkZ19kZl9wcmUkSUQpKSANCg0KZGdfZGZfcG9zdCA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDAsIHdoaWNoID0gIkRpY3RhdG9yR2FtZSBwb3N0IikNCmNvbG5hbWVzKGRnX2RmX3Bvc3QpWzRdIDwtICJJRCINCmRnX2RmX3Bvc3QgPC0gDQogIGRnX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGUoSUQgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoSUQsIGZpeGVkKCIgIiksICIiKSkgJT4lICAgICMgcmVtb3ZlIHdoaXRlIHNwYWNlcw0KICBkcGx5cjo6bXV0YXRlKElEID0gdG91cHBlcihJRCkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRvIHVwcGVyDQphbGwoZGdfZGZfcG9zdCRJRCA9PSB0b3VwcGVyKGRnX2RmX3Bvc3QkSUQpKSANCg0KY29sbmFtZXMoZGdfZGZfcHJlKVs1OjhdIDwtIHNwcmludGYoIkRHXyVkIiwgMTo0KQ0KY29sbmFtZXMoZGdfZGZfcG9zdClbNTo4XSA8LSBzcHJpbnRmKCJER18lZCIsIDE6NCkNCg0KDQpkZ19kZl9wcmUgPC0NCiAgZGdfZGZfcHJlICU+JQ0KICBkcGx5cjo6bXV0YXRlKGBEYXRlIE1vZGlmaWVkYCA9IGx1YnJpZGF0ZTo6eW1kX2htcyhmb3JtYXQoYERhdGUgTW9kaWZpZWRgLCAiJVktJW0tJWQgJUg6JU06JVMiLCB0eiA9ICJVVEMiKSkpICU+JQ0KICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCB+bmFfaWYoLiwgIk5vdCBBbnN3ZXJlZCIpKQ0KDQpkZ19kZl9wb3N0IDwtDQogIGRnX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGUoYERhdGUgTW9kaWZpZWRgID0gbHVicmlkYXRlOjp5bWRfaG1zKGZvcm1hdChgRGF0ZSBNb2RpZmllZGAsICIlWS0lbS0lZCAlSDolTTolUyIsIHR6ID0gIlVUQyIpKSkgJT4lDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIH5kcGx5cjo6bmFfaWYoLiwgIk5vdCBBbnN3ZXJlZCIpKQ0KDQpkZ19kZl9wcmUgPC0NCiAgZGdfZGZfcHJlICU+JQ0KICBkcGx5cjo6bXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoIkRHXyIpKSwgfnN0cmluZ3I6OnN0cl9leHRyYWN0KC4sICJbMC05XSsiKSkgJT4lICAgIyBleHRyYWN0cyBmaXJzdCBudW1iZXIgKGFsbCBnYW1lcyBzdGFydCB3aXRoIFBsYXllciBBLCBzbyBhbHdheXMgZmlyc3QgbnVtYmVyKQ0KICBkcGx5cjo6bXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoIkRHXyIpKSwgYXMubnVtZXJpYykgJT4lDQogIGRwbHlyOjptdXRhdGUoVGltZSA9IHJlcCgiUHJlIiwgbnJvdyguKSkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKENvbmQgPSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChJRCwgIlgiKSwgIkNUUkwiLCAiVFIiKSkgJT4lDQogIHNlbGVjdChgRGF0ZSBNb2RpZmllZGAsIElELCBzdGFydHNfd2l0aCgiREdfIiksIFRpbWUsIENvbmQpDQoNCmRnX2RmX3Bvc3QgPC0NCiAgZGdfZGZfcG9zdCAlPiUNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJER18iKSksIH5zdHJpbmdyOjpzdHJfZXh0cmFjdCguLCAiWzAtOV0rIikpICU+JSAgICMgZXh0cmFjdHMgZmlyc3QgbnVtYmVyIChhbGwgZ2FtZXMgc3RhcnQgd2l0aCBQbGF5ZXIgQSwgc28gYWx3YXlzIGZpcnN0IG51bWJlcikNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJER18iKSksIGFzLm51bWVyaWMpICU+JQ0KICBkcGx5cjo6bXV0YXRlKFRpbWUgPSByZXAoIlBvc3QiLCBucm93KC4pKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoQ29uZCA9IGlmZWxzZShzdHJpbmdyOjpzdHJfZGV0ZWN0KElELCAiWCIpLCAiQ1RSTCIsICJUUiIpKSAlPiUNCiAgc2VsZWN0KGBEYXRlIE1vZGlmaWVkYCwgSUQsIHN0YXJ0c193aXRoKCJER18iKSwgVGltZSwgQ29uZCkNCg0KIyBUcmFuc2Zvcm0gREcgMC05MDAgZWdvaXNtIHRvIDAtOSBhbHRydWlzbQ0KZGdfdHJhbnNfZnVuYyA8LSBmdW5jdGlvbih4KXt0cmFucyA8LSA5IC0geCAvIDEwMH0NCg0KZGdfZGZfcHJlIDwtDQogIGRnX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKHN0YXJ0c193aXRoKCJER18iKSksIGRnX3RyYW5zX2Z1bmMpIA0KDQpkZ19kZl9wb3N0IDwtDQogIGRnX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGVfYXQodmFycyhzdGFydHNfd2l0aCgiREdfIikpLCBkZ190cmFuc19mdW5jKSANCg0KIyBVbml0ZSBERyBkYXRhIC0gTG9uZyBGb3JtYXQNCmRnX3VuaXRlZF9sb25nIDwtIHJiaW5kKGRnX2RmX3ByZSwgZGdfZGZfcG9zdCkNCndoaWNoKHRhYmxlKGRnX3VuaXRlZF9sb25nJElEKT4gMiApICAgICAjIElEcyAiM0IiICYgIjMxWCIgaGF2ZSBtb3JlIHRoYW4gMiB0cmlhbHMNCmRnX3VuaXRlZF9sb25nW2RnX3VuaXRlZF9sb25nJElEID09ICIzQiIsXSAgIyB0d28gUHJlcyAtLSBrZWVwIHRoZSBmaXJzdA0KZGdfdW5pdGVkX2xvbmcgPC0gZGdfdW5pdGVkX2xvbmdbLTU1LCBdDQpkZ191bml0ZWRfbG9uZ1tkZ191bml0ZWRfbG9uZyRJRCA9PSAiMzFYIixdICMgdHdvIFByZXMgLS0ga2VlcCB0aGUgZmlyc3QNCmRnX3VuaXRlZF9sb25nIDwtIGRnX3VuaXRlZF9sb25nWy03MywgXQ0KDQpkZ191bml0ZWRfbG9uZyRER19Ub3RhbCA8LSByb3dTdW1zKGRnX3VuaXRlZF9sb25nWywgc3ByaW50ZigiREdfJWQiLCAxOjQpXSwgbmEucm0gPSBUUlVFKSANCg0KIyBVbml0ZSBERyBkYXRhIC0gV2lkZSBGb3JtYXQNCmRnX3VuaXRlZF93aWRlIDwtDQogIGRnX3VuaXRlZF9sb25nICU+JQ0KICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFRpbWUsIHZhbHVlc19mcm9tID0gYygiRGF0ZSBNb2RpZmllZCIsIHNwcmludGYoIkRHXyVkIiwgMTo0KSwgIkRHX1RvdGFsIikpDQojIGRnX3VuaXRlZF93aWRlMiA8LSBkcGx5cjo6bGVmdF9qb2luKGRnX3VuaXRlZF93aWRlLCBpZHNfZ3JvdXBzX2RmLCBieSA9ICJJRCIpICAgICAjIG5vIG5lZWQgdG8gbWVyZ2UsIGFscmVhZHkgaGF2ZSBpZHMgZm9yIGdyb3VwcyBzdG9yZWQNCg0KYGBgDQoNCjwhLS0NCmBgYHtyIG1peGVkYW5vdmFfZGd9DQpjYXQoIk1peGVkIEFOT1ZBIC0gREcgd2hvbGUgc2FtcGxlIChub3QgYnkgZ3JvdXBzKSIpDQojIE1peGVkIEFOT1ZBDQpkZ191bml0ZWRfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoSUQpICU+JQ0KICBmaWx0ZXIobigpID4gMSkgJT4lICAgICAjIGtlZXAgb25seSBjb21wbGV0ZSBjYXNlcw0KICB1bmdyb3VwKCkgJT4lIA0KICB0d19taXhlZEFOT1ZBX2Z1bmMoZGF0YSA9IC4sIGlkX3ZhciA9IElELCBjb25kX3ZhciA9IENvbmQsIHRpbWVfdmFyID0gVGltZSwgdmFsdWVfdmFyID0gREdfVG90YWwsDQogICAgICAgICAgICAgICAgICBwb3N0aG9jX3NpZ19pbnRlcmFjID0gVFJVRSwgcG9zdGhvY19uc19pbnRlcmFjID0gVFJVRSkNCmBgYA0KLS0+DQoNCiMgVCB0ZXN0IERpY2F0YXRvciBHYW1lDQoNCmBgYHtyIHR0ZXN0X2J5Z3JvdXBfZGd9DQojIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBjKGlkc19wdHNkLCBpZHNfYnVybiwgaWRzX29sZCwgaWRzX25vcm1hbCkpICU+JQ0KDQpjYXQoIiMjIERHIC0gUFRTRCBUUiIpDQpkZ191bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19wdHNkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQpjYXQoIiMjIERHIC0gUFRTRCBDVFJMIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX3B0c2QpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIkRHX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIkRHX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgREcgLSBCdXJub3V0IFRSIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX2J1cm4pICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJER19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJER19Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgREcgLSBCdXJub3V0IENUUkwiKQ0KZGdfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfYnVybikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQoNCg0KY2F0KCIjIyBERyAtIE9sZCBUUiIpDQpkZ191bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJER19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJER19Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgREcgLSBPbGQgQ1RSTCIpDQpkZ191bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIkRHX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIkRHX1RvdGFsX1Bvc3QiKQ0KDQpjYXQoIiMjIERHIC0gR2VuZXJhbCBQb3B1bGF0aW9uIFRSIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIkRHX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIkRHX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBERyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCmRnX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQpgYGANCg0KIyMgREcgTm9ybWFsIFNhbXBsZSBTaXplIGVzdGltYXRpb24NCg0KYGBge3IgZGdfc2FtcGxlc2l6ZX0NCmNhdCgiIyMgREcgLSBHZW5lcmFsIFBvcHVsYXRpb24gVFIiKQ0KZGdfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiREdfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiREdfVG90YWxfUG9zdCIpDQpjYXQoIiMjIERHIC0gR2VuZXJhbCBQb3B1bGF0aW9uIENUUkwiKQ0KZGdfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIHNhbXBsZXNpemVfcGFpcmVkdHRlc3QoLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJER19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJER19Ub3RhbF9Qb3N0IikNCmBgYA0KDQoNCmBgYHtyIHNjYWxlX3Njb3JpbmcsIHJlc3VsdHM9J2hpZGUnfQ0KIyBTY2FsZXMgZGYNCnNjYWxlX2RmX3ByZSA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAwLCB3aGljaCA9ICJTZXQgdGVzdGUgemkgMSBwcmUiKQ0Kc2NhbGVfZGZfcHJlIDwtIHNjYWxlX2RmX3ByZVssLTJdDQpjb2xuYW1lcyhzY2FsZV9kZl9wcmUpWzFdIDwtICJEYXRlIg0KY29sbmFtZXMoc2NhbGVfZGZfcHJlKVsyXSA8LSAiSUQiDQpzY2FsZV9kZl9wcmUgPC0gDQogIHNjYWxlX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbChJRCwgZml4ZWQoIiAiKSwgIiIpKSAlPiUgICAgIyByZW1vdmUgd2hpdGUgc3BhY2VzDQogIGRwbHlyOjptdXRhdGUoSUQgPSB0b3VwcGVyKElEKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdG8gdXBwZXINCmFsbChzY2FsZV9kZl9wcmUkSUQgPT0gdG91cHBlcihzY2FsZV9kZl9wcmUkSUQpKSANCg0Kc2NhbGVfZGZfcG9zdCA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2lwID0gMCwgd2hpY2ggPSAiU2V0IHRlc3RlIHppIDUgcG9zdCIpDQpzY2FsZV9kZl9wb3N0IDwtIHNjYWxlX2RmX3Bvc3RbLC0yXQ0KY29sbmFtZXMoc2NhbGVfZGZfcG9zdClbMV0gPC0gIkRhdGUiDQpjb2xuYW1lcyhzY2FsZV9kZl9wb3N0KVsyXSA8LSAiSUQiDQpzY2FsZV9kZl9wb3N0IDwtIA0KICBzY2FsZV9kZl9wb3N0ICU+JQ0KICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKElELCBmaXhlZCgiICIpLCAiIikpICU+JSAgICAjIHJlbW92ZSB3aGl0ZSBzcGFjZXMNCiAgZHBseXI6Om11dGF0ZShJRCA9IHRvdXBwZXIoSUQpKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0byB1cHBlcg0KYWxsKHNjYWxlX2RmX3Bvc3QkSUQgPT0gdG91cHBlcihzY2FsZV9kZl9wb3N0JElEKSkNCg0KYWxsLmVxdWFsKGNvbG5hbWVzKHNjYWxlX2RmX3Bvc3QpLCBjb2xuYW1lcyhzY2FsZV9kZl9wcmUpKSAgICMgc2V0ZGlmZihjb2xuYW1lcyhzY2FsZV9kZl9wb3N0KSwgY29sbmFtZXMoc2NhbGVfZGZfcHJlKSkNCg0KIyBEZWFsIHdpdGggTm90IEFuc3dlcg0Kc2NhbGVfZGZfcHJlIDwtDQogIHNjYWxlX2RmX3ByZSAlPiUNCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgfmRwbHlyOjpuYV9pZiguLCAiTm90IEFuc3dlcmVkIikpDQoNCnNjYWxlX2RmX3Bvc3QgPC0NCiAgc2NhbGVfZGZfcG9zdCAlPiUNCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgfmRwbHlyOjpuYV9pZiguLCAiTm90IEFuc3dlcmVkIikpDQoNCiMgQWRkIENvbmRpdGlvbg0Kc2NhbGVfZGZfcHJlIDwtDQogIHNjYWxlX2RmX3ByZSAlPiUNCiAgZHBseXI6Om11dGF0ZShUaW1lID0gcmVwKCJQcmUiLCBucm93KC4pKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoQ29uZCA9IGlmZWxzZShzdHJpbmdyOjpzdHJfZGV0ZWN0KElELCAiWCIpLCAiQ1RSTCIsICJUUiIpKQ0KDQpzY2FsZV9kZl9wb3N0IDwtDQogIHNjYWxlX2RmX3Bvc3QgJT4lDQogIGRwbHlyOjptdXRhdGUoVGltZSA9IHJlcCgiUG9zdCIsIG5yb3coLikpKSAlPiUNCiAgICBkcGx5cjo6bXV0YXRlKENvbmQgPSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChJRCwgIlgiKSwgIkNUUkwiLCAiVFIiKSkNCg0KDQojIyBQQU5BUzogUG9zaXRpdmUgQWZmZWN0IFNjb3JlID0gc3VtIGl0ZW1zIDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkuIE5lZ2F0aXZlIEFmZmVjdCBTY29yZSA9IHN1bSBpdGVtcyAyLCA0LCA2LCA3LCA4LCAxMSwgMTMsIDE1LCAxOCwgMjAuICANCmluZGV4X2l0ZW1fcGFuYXMgPC0gMzoyMg0KY29sbmFtZXMoc2NhbGVfZGZfcHJlKVtpbmRleF9pdGVtX3BhbmFzXSA8LSBzcHJpbnRmKCJQQU5BU18lZCIsIDE6MjApDQpjb2xuYW1lcyhzY2FsZV9kZl9wb3N0KVtpbmRleF9pdGVtX3BhbmFzXSA8LSBzcHJpbnRmKCJQQU5BU18lZCIsIDE6MjApDQoNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcGFuYXNdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qw65uIGZvYXJ0ZSBtaWPEgyBtxINzdXLEgy4qIiwgIjEiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBtaWPEgyBtxINzdXLEgy4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubnRyLW8gb2FyZWNhcmUgbcSDc3VyxIMuKiIsICIzIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wYW5hc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLirDrm4gbWFyZSBtxINzdXLEgy4qIiwgIjQiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBmb2FydGUgbWFyZSBtxINzdXLEgy4qIiwgIjUiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCnNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3BhbmFzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qw65uIGZvYXJ0ZSBtaWPEgyBtxINzdXLEgy4qIiwgIjEiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBtaWPEgyBtxINzdXLEgy4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubnRyLW8gb2FyZWNhcmUgbcSDc3VyxIMuKiIsICIzIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3BhbmFzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLirDrm4gbWFyZSBtxINzdXLEgy4qIiwgIjQiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wYW5hc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKsOubiBmb2FydGUgbWFyZSBtxINzdXLEgy4qIiwgIjUiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQojIFNjb3JpbmcNCnNjYWxlX2RmX3ByZSRQQV9Ub3RhbCA8LSBTY29yZUxpa2VydChzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3BhbmFzXVtjKDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b251bWVyaWMgPSBUUlVFLCBuYXBlcmNlbnQgPSAuMTEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3QgbW9yZSB0aGFuIDEgTkFzIGZvciAxMCBpdGVtcw0Kc2NhbGVfZGZfcHJlJE5BX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KHNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcGFuYXNdW2MoMiwgNCwgNiwgNywgOCwgMTEsIDEzLCAxNSwgMTgsIDIwKV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b251bWVyaWMgPSBUUlVFLCBuYXBlcmNlbnQgPSAuMTEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBub3QgbW9yZSB0aGFuIDEgTkFzIGZvciAxMCBpdGVtcw0KDQpzY2FsZV9kZl9wb3N0JFBBX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3BhbmFzXVtjKDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9udW1lcmljID0gVFJVRSwgbmFwZXJjZW50ID0gLjExKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTAgaXRlbXMNCnNjYWxlX2RmX3Bvc3QkTkFfVG90YWwgPC0gU2NvcmVMaWtlcnQoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcGFuYXNdW2MoMiwgNCwgNiwgNywgOCwgMTEsIDEzLCAxNSwgMTgsIDIwKV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9udW1lcmljID0gVFJVRSwgbmFwZXJjZW50ID0gLjExKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTAgaXRlbXMNCg0KDQojIyBQU1MtU0YgMTQgKGxpa2VydCAwLTQpLiBJdGVtcyA0LCA1LCA2LCA3LCA5LCAxMCwgYW5kIDEzIGFyZSBzY29yZWQgaW4gcmV2ZXJzZSBkaXJlY3Rpb24uDQppbmRleF9pdGVtX3BzcyA8LSAyMzozNg0KaW5kZXhfaXRlbV9yZXZQU1MgPC0gYyg0LCA1LCA2LCA3LCA5LCAxMCwgMTMpDQpjb2xuYW1lcyhzY2FsZV9kZl9wcmUpW2luZGV4X2l0ZW1fcHNzXSA8LSBzcHJpbnRmKCJQU1NfJWQiLCAxOjE0KQ0KY29sbmFtZXMoc2NhbGVfZGZfcG9zdClbaW5kZXhfaXRlbV9wc3NdIDwtIHNwcmludGYoIlBTU18lZCIsIDE6MTQpDQoNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLipuaWNpb2RhdMSDLioiLCAiMCIsIHgpfSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLiphcHJvYXBlIG5pY2lvZGF0xIMuKiIsICIxIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKnVuZW9yaS4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qZGVzdHVsIGRlIGRlcy4qIiwgIjMiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wcmVbLCBpbmRleF9pdGVtX3Bzc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qZm9hcnRlIGRlcy4qIiwgIjQiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCnNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10gPC0gZGF0YS5mcmFtZShsYXBwbHkoc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcHNzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkge2dzdWIoIi4qbmljaW9kYXTEgy4qIiwgIjAiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKmFwcm9hcGUgbmljaW9kYXTEgy4qIiwgIjEiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKnVuZW9yaS4qIiwgIjIiLCB4KX0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdIDwtIGRhdGEuZnJhbWUobGFwcGx5KHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHtnc3ViKCIuKmRlc3R1bCBkZSBkZXMuKiIsICIzIiwgeCl9KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcHNzXSA8LSBkYXRhLmZyYW1lKGxhcHBseShzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7Z3N1YigiLipmb2FydGUgZGVzLioiLCAiNCIsIHgpfSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0KIyBTY29yZQ0Kc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdIDwtIGNvbHN0b251bWVyaWMoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdKQ0Kc2NhbGVfZGZfcG9zdFssIGluZGV4X2l0ZW1fcHNzXSA8LSBjb2xzdG9udW1lcmljKHNjYWxlX2RmX3Bvc3RbLCBpbmRleF9pdGVtX3Bzc10pDQoNCnNjYWxlX2RmX3ByZVssIGluZGV4X2l0ZW1fcHNzXVtpbmRleF9pdGVtX3JldlBTU10gPC0gUmV2ZXJzZUNvZGUoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdW2luZGV4X2l0ZW1fcmV2UFNTXSwgdG9udW1lcmljID0gRkFMU0UsIG1pbiA9IDAsIG1heCA9IDQpDQpzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdW2luZGV4X2l0ZW1fcmV2UFNTXSA8LSBSZXZlcnNlQ29kZShzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdW2luZGV4X2l0ZW1fcmV2UFNTXSwgdG9udW1lcmljID0gRkFMU0UsIG1pbiA9IDAsIG1heCA9IDQpDQoNCnNjYWxlX2RmX3ByZSRQU1NfVG90YWwgPC0gU2NvcmVMaWtlcnQoc2NhbGVfZGZfcHJlWywgaW5kZXhfaXRlbV9wc3NdLCBuYXBlcmNlbnQgPSAuMTEpDQpzY2FsZV9kZl9wb3N0JFBTU19Ub3RhbCA8LSBTY29yZUxpa2VydChzY2FsZV9kZl9wb3N0WywgaW5kZXhfaXRlbV9wc3NdLCBuYXBlcmNlbnQgPSAuMTEpDQoNCg0KIyBVbml0ZSBzY2FsZSBkZiAtIExvbmcgRm9ybWF0DQpzY2FsZV91bml0ZWRfbG9uZyA8LSByYmluZChzY2FsZV9kZl9wcmUsIHNjYWxlX2RmX3Bvc3QpDQoNCnNjYWxlX3VuaXRlZF9sb25nICU+JQ0KICBjb3VudChJRCkgJT4lDQogIHByaW50KG4gPSBJbmYpICAjIElEICIyQiIgaGFzIGRvdWJsZSByZWNvcmQgYm90aCBpbiBwcmUgYW5kIHBvc3QgLS0ga2VlcCBmaXJzdCBpbiBib3RoLCBzZWNvbmQgcmVjb3JkIGhhcyBOQXMNCg0KIyBzY2FsZV91bml0ZWRfbG9uZ1tzY2FsZV91bml0ZWRfbG9uZyRJRCA9PSAiMkIiLF0NCnNjYWxlX3VuaXRlZF9sb25nIDwtIHNjYWxlX3VuaXRlZF9sb25nWy0yNixdDQpzY2FsZV91bml0ZWRfbG9uZyA8LSBzY2FsZV91bml0ZWRfbG9uZ1stMTAyLF0NCg0KDQojIFVuaXRlIERHIGRhdGEgLSBXaWRlIEZvcm1hdA0Kc2NhbGVfdW5pdGVkX3dpZGUgPC0NCiAgc2NhbGVfdW5pdGVkX2xvbmcgJT4lDQogIGRwbHlyOjpzZWxlY3QoSUQsIERhdGUsIFRpbWUsIENvbmQsIFBBX1RvdGFsLCBOQV9Ub3RhbCwgUFNTX1RvdGFsKSAlPiUNCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBUaW1lLCB2YWx1ZXNfZnJvbSA9IGMoIkRhdGUiLCAiUEFfVG90YWwiLCAiTkFfVG90YWwiLCAiUFNTX1RvdGFsIikpDQoNCmBgYA0KDQoNCjwhLS0NCmBgYHtyIG1peGVkYW5vdmFfc2NhbGVzfQ0KY2F0KCJNaXhlZCBBTk9WQSAtIFBTUyB3aG9sZSBzYW1wbGUgKG5vdCBieSBncm91cHMpIikNCiMgTWl4ZWQgQU5PVkENCnNjYWxlX3VuaXRlZF9sb25nICU+JQ0KICBncm91cF9ieShJRCkgJT4lDQogIGZpbHRlcihuKCkgPiAxKSAlPiUgICAgICMga2VlcCBvbmx5IGNvbXBsZXRlIGNhc2VzIC0tIGhlcmUgYXJlIG9ubHkgY29tcGxldGUNCiAgdW5ncm91cCgpICU+JSANCiAgdHdfbWl4ZWRBTk9WQV9mdW5jKGRhdGEgPSAuLCBpZF92YXIgPSBJRCwgY29uZF92YXIgPSBDb25kLCB0aW1lX3ZhciA9IFRpbWUsIHZhbHVlX3ZhciA9IFBTU19Ub3RhbCwNCiAgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpjYXQoIk1peGVkIEFOT1ZBIC0gUEEgd2hvbGUgc2FtcGxlIChub3QgYnkgZ3JvdXBzKSIpDQpzY2FsZV91bml0ZWRfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoSUQpICU+JQ0KICBmaWx0ZXIobigpID4gMSkgJT4lICAgICAjIGtlZXAgb25seSBjb21wbGV0ZSBjYXNlcyAtLSBoZXJlIGFyZSBvbmx5IGNvbXBsZXRlDQogIHVuZ3JvdXAoKSAlPiUgDQogIHR3X21peGVkQU5PVkFfZnVuYyhkYXRhID0gLiwgaWRfdmFyID0gSUQsIGNvbmRfdmFyID0gQ29uZCwgdGltZV92YXIgPSBUaW1lLCB2YWx1ZV92YXIgPSBQQV9Ub3RhbCwNCiAgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KDQpjYXQoIk1peGVkIEFOT1ZBIC0gTkEgd2hvbGUgc2FtcGxlIChub3QgYnkgZ3JvdXBzKSIpDQpzY2FsZV91bml0ZWRfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoSUQpICU+JQ0KICBmaWx0ZXIobigpID4gMSkgJT4lICAgICAjIGtlZXAgb25seSBjb21wbGV0ZSBjYXNlcyAtLSBoZXJlIGFyZSBvbmx5IGNvbXBsZXRlDQogIHVuZ3JvdXAoKSAlPiUgDQogIHR3X21peGVkQU5PVkFfZnVuYyhkYXRhID0gLiwgaWRfdmFyID0gSUQsIGNvbmRfdmFyID0gQ29uZCwgdGltZV92YXIgPSBUaW1lLCB2YWx1ZV92YXIgPSBOQV9Ub3RhbCwNCiAgICAgICAgICAgICAgICAgIHBvc3Rob2Nfc2lnX2ludGVyYWMgPSBUUlVFLCBwb3N0aG9jX25zX2ludGVyYWMgPSBUUlVFKQ0KYGBgDQotLT4NCg0KIyBUIHRlc3QgUFNTDQoNCmBgYHtyIHR0ZXN0X2J5Z3JvdXBfcHNzfQ0KIyBkcGx5cjo6ZmlsdGVyKElEICVpbiUgYyhpZHNfcHRzZCwgaWRzX2J1cm4sIGlkc19vbGQsIGlkc19ub3JtYWwpKSAlPiUNCg0KY2F0KCIjIyBQU1MgLSBQVFNEIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX3B0c2QpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQU1NfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUFNTX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBQU1MgLSBQVFNEIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfcHRzZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCg0KDQpjYXQoIiMjIFBTUyAtIEJ1cm5vdXQgVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfYnVybikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBTU19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQU1NfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIEJ1cm5vdXQgQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19idXJuKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQU1NfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUFNTX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgUFNTIC0gT2xkIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX29sZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBTU19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQU1NfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIE9sZCBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX29sZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCg0KY2F0KCIjIyBQU1MgLSBHZW5lcmFsIFBvcHVsYXRpb24gVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUFNTIC0gR2VuZXJhbCBQb3B1bGF0aW9uIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQU1NfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUFNTX1RvdGFsX1Bvc3QiKQ0KYGBgDQoNCiMjIFBTUyBOb3JtYWwgU2FtcGxlIFNpemUgZXN0aW1hdGlvbg0KDQpgYGB7ciBzYW1wbGVzaXplX3Bzc30NCmNhdCgiIyMgUFNTIC0gR2VuZXJhbCBQb3B1bGF0aW9uIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgc2FtcGxlc2l6ZV9wYWlyZWR0dGVzdCguLCBwcmVfdmFyID0gIlBTU19Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQU1NfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiUFNTX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBTU19Ub3RhbF9Qb3N0IikNCmBgYA0KDQoNCiMgVCB0ZXN0IFBBDQoNCmBgYHtyIHR0ZXN0X2J5Z3JvdXBfcGF9DQpjYXQoIiMjIFBBIC0gUFRTRCBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19wdHNkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBBIC0gUFRTRCBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX3B0c2QpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBBX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBBX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgUEEgLSBCdXJub3V0IFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX2J1cm4pICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUEEgLSBCdXJub3V0IENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfYnVybikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQoNCg0KY2F0KCIjIyBQQSAtIE9sZCBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJQQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJQQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUEEgLSBPbGQgQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19vbGQpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBBX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBBX1RvdGFsX1Bvc3QiKQ0KDQpjYXQoIiMjIFBBIC0gR2VuZXJhbCBQb3B1bGF0aW9uIFRSIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIlBBX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIlBBX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBQQSAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQoNCmBgYA0KDQojIyBQQSBOb3JtYWwgU2FtcGxlIFNpemUgZXN0aW1hdGlvbg0KDQpgYGB7ciBzYW1wbGVzaXplX3BhfQ0KY2F0KCIjIyBQU1MgLSBHZW5lcmFsIFBvcHVsYXRpb24gVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIFBTUyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX25vcm1hbCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ1RSTCIpICU+JQ0KICBzYW1wbGVzaXplX3BhaXJlZHR0ZXN0KC4sIHByZV92YXIgPSAiUEFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiUEFfVG90YWxfUG9zdCIpDQpgYGANCg0KDQojIFQgdGVzdCBOQQ0KDQpgYGB7ciB0dGVzdF9ieWdyb3VwX25hfQ0KY2F0KCIjIyBOQSAtIFBUU0QgVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfcHRzZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiVFIiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5BX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIk5BX1RvdGFsX1Bvc3QiKQ0KY2F0KCIjIyBOQSAtIFBUU0QgQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19wdHNkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCg0KDQpjYXQoIiMjIE5BIC0gQnVybm91dCBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19idXJuKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiTkFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiTkFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIE5BIC0gQnVybm91dCBDVFJMIikNCnNjYWxlX3VuaXRlZF93aWRlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKElEICVpbiUgaWRzX2J1cm4pICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5BX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIk5BX1RvdGFsX1Bvc3QiKQ0KDQoNCmNhdCgiIyMgTkEgLSBPbGQgVFIiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfb2xkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJUUiIpICU+JQ0KICBmdW5jX3RfYm94KC4sIGluZCA9ICJJRCIsIHByZV92YXIgPSAiTkFfVG90YWxfUHJlIiwgcG9zdF92YXIgPSAiTkFfVG90YWxfUG9zdCIpDQpjYXQoIiMjIE5BIC0gT2xkIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfb2xkKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCg0KY2F0KCIjIyBOQSAtIEdlbmVyYWwgUG9wdWxhdGlvbiBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19ub3JtYWwpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIGZ1bmNfdF9ib3goLiwgaW5kID0gIklEIiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgTkEgLSBHZW5lcmFsIFBvcHVsYXRpb24gQ1RSTCIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19ub3JtYWwpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNUUkwiKSAlPiUNCiAgZnVuY190X2JveCguLCBpbmQgPSAiSUQiLCBwcmVfdmFyID0gIk5BX1RvdGFsX1ByZSIsIHBvc3RfdmFyID0gIk5BX1RvdGFsX1Bvc3QiKQ0KYGBgDQoNCiMjIE5BIE5vcm1hbCBTYW1wbGUgU2l6ZSBlc3RpbWF0aW9uDQoNCmBgYHtyIHNhbXBsZXNpemVfbmF9DQpjYXQoIiMjIFBTUyAtIEdlbmVyYWwgUG9wdWxhdGlvbiBUUiIpDQpzY2FsZV91bml0ZWRfd2lkZSAlPiUNCiAgZHBseXI6OmZpbHRlcihJRCAlaW4lIGlkc19ub3JtYWwpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIlRSIikgJT4lDQogIHNhbXBsZXNpemVfcGFpcmVkdHRlc3QoLiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCmNhdCgiIyMgUFNTIC0gR2VuZXJhbCBQb3B1bGF0aW9uIENUUkwiKQ0Kc2NhbGVfdW5pdGVkX3dpZGUgJT4lDQogIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBpZHNfbm9ybWFsKSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJDVFJMIikgJT4lDQogIHNhbXBsZXNpemVfcGFpcmVkdHRlc3QoLiwgcHJlX3ZhciA9ICJOQV9Ub3RhbF9QcmUiLCBwb3N0X3ZhciA9ICJOQV9Ub3RhbF9Qb3N0IikNCmBgYA0KDQoNCg0KDQo8IS0tIFNlc3Npb24gSW5mbyBhbmQgTGljZW5zZSAtLT4NCg0KPGJyPg0KDQojIFNlc3Npb24gSW5mbw0KYGBge3Igc2Vzc2lvbl9pbmZvLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnbWFya3VwJ30NCnNlc3Npb25JbmZvKCkgICAgDQpgYGANCg0KPCEtLSBGb290ZXIgLS0+DQombmJzcDsNCjxociAvPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPkEgd29yayBieSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQ2xhdWRpdVBhcGFzdGVyaS8iPkNsYXVkaXUgUGFwYXN0ZXJpPC9hPjwvcD4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDgwODA7Ij48ZW0+Y2xhdWRpdS5wYXBhc3RlcmlAZ21haWwuY29tPC9lbT48L3NwYW4+PC9wPg0KJm5ic3A7DQo=