knitr::opts_chunk$set(eval=FALSE)
library(dplyr)
library(magrittr)
library(purrr)
library(survival)
library(gtools)
library(stringr)
library(tidyverse)
library(survminer)
library(ggsurvfit)
library(pheatmap)
source("~/MRes_project_1/codes/5_plots/script/function.R")
ggsurvplot_customised <- function (fit_function, dataframe, pval_coord, break_time_by, title, 
                                   subtitle, legend_labs, p.val_method) {
  p <- ggsurvplot(fit = fit_function, data = dataframe, 
                  risk.table = TRUE, risk.table.height = 0.2, risk.table.y.text.col = TRUE, 
                  risk.table.y.text = FALSE, 
                  pval = TRUE, pval.method = FALSE, pval.coord = pval_coord, pval.size = 3, 
                  log.rank.weights = p.val_method, 
                  conf.int = TRUE, conf.int.style = "ribbon", 
                  ncensor.plot = TRUE, ncensor.plot.height = 0.2, censor.size = 1, 
                  censor.shape = 124, 
                  legend.title = "status", legend.labs = legend_labs, legend = "top", 
                  xlab = "Days", break.time.by = break_time_by, 
                  surv.median.line = "hv", 
                  fontsize = 3, font.family = "Arial", font.legend = c(9), size = 0.5, 
                  ggtheme = theme_light(), 
                  title = title, subtitle = subtitle, 
                  surv.scale = "percent")
  p <- customize_labels(p, font.title = c(9, "bold"), 
                        font.subtitle = c(9, "italic", "darkgrey"), font.x = c(9), 
                        font.y = c(9), font.xtickslab = c(8))
  p$plot <- p$plot + geom_vline(xintercept = c(1826), size = 0.3, alpha = 0.5)
  return(p)
}

load files

if(!file.exists("~/MRes_project_1/docs/GISTIC2/lung_arm_complete.txt")){
  tcga <- read.table("~/MRes_project_1/docs/GISTIC2/tcga/lung/broad_values_by_arm.txt", 
                     sep = "\t", header = T)
  mskcc <- read.table("~/MRes_project_1/docs/GISTIC2/cbioportal/lung_2/broad_values_by_arm.txt", 
                      sep = "\t", header = T)
  hh <- read.table("~/MRes_project_1/docs/GISTIC2/hh/lung_2/broad_values_by_arm.txt", 
                   sep = "\t", header = T)
  
  lung_arm <- left_join(tcga, mskcc, by="Chromosome.Arm")
  lung_arm <- left_join(lung_arm, hh, by="Chromosome.Arm")
  write.table(lung_arm, "~/MRes_project_1/docs/GISTIC2/lung_arm_complete.txt", 
              sep = "\t", col.names = T, row.names = F)
} else {
  lung_arm <- read.table("~/MRes_project_1/docs/GISTIC2/lung_arm_complete.txt", 
                         sep = "\t", header = T)
}

lung_arm[1:10, 1:10]

TCGA lung cancer dataset

All of these samples are from non-small cell lung cancer patients.

# if raw combined file not exist 
if(!file.exists("~/MRes_project_1/docs/00_mitéra/clinical/raw/lung/tcga_combined_raw.txt")){
  ## load 
  setwd("~/MRes_project_1/docs/00_mitéra/clinical/raw/lung")
  tcga_clinical_ucsc <- read.table("tcga_lung_clinical_ucsc.txt", header = T, sep = "\t")
  tcga_survival_ucsc <- read.table("tcga_lung_survival_ucsc.txt", header = T, sep = "\t")
  tcga_lusc_cbp <- read.table("lusc_tcga_clinical_data.tsv", header = T, sep = "\t")
  tcga_luad_cbp <- read.table("luad_tcga_clinical_data.tsv", header = T, sep = "\t")
  
  ## rename 
  tcga_clinical_ucsc <- tcga_clinical_ucsc %>% dplyr::rename(sample = sampleID)
  tcga_lusc_cbp <- tcga_lusc_cbp %>% dplyr::rename(sample = Sample.ID)
  tcga_luad_cbp <- tcga_luad_cbp %>% dplyr::rename(sample = Sample.ID) 
  
  ## join
  tcga <- left_join(tcga_clinical_ucsc, tcga_survival_ucsc, by="sample")
  cbp <- rbind(tcga_lusc_cbp[, intersect(colnames(tcga_lusc_cbp), colnames(tcga_luad_cbp))], 
               tcga_luad_cbp[, intersect(colnames(tcga_lusc_cbp), colnames(tcga_luad_cbp))])
  tcga <- left_join(tcga, cbp, by="sample")
  
  ## save 
  write.table(tcga, "~/MRes_project_1/docs/00_mitéra/clinical/raw/lung/tcga_combined_raw.txt", 
              sep = "\t", col.names = T, row.names = F, quote = F)
  
  
  ## if processed combine file not exist 
} else if(!file.exists("~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_combined.txt")){
  ## read in 
  tcga <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/raw/lung/tcga_combined_raw.txt", sep = "\t", header = T)
  
  ## remove useless columns by... 
  ## 1. more than 70% missing information 
  keep <- tcga %>% select_if(~is.numeric(.) | is.character(.)) %>% map_lgl(~sum(is.na(.) | . == "")/length(.) < 0.7)
  tcga <- tcga[keep]
  ## 2. column with same values across 
  keep <- function(x){
    x <- x[!is.na(x) & x != ""] ## not empty string or NA values 
    length(unique(x)) > 1} ## more than 1 unique values exist in the column
  tcga <- tcga %>% select(where(keep))
  ## 3. sample columns 
  rownames(tcga) <- tcga$sample ## store the samples as rownames 
  tcga <- tcga %>% select_if(~!is.character(.) | ## remove columns with TCGA beginning
                               (is.character(.) && 
                                  !any(startsWith(na.omit(.), "TCGA")))) 
  tcga$sample <- rownames(tcga) ## restore the sample column 
  ## 4. UUID columns 
  remove <- tcga %>% ## define uuid columns and extract their column names  
    select_if(~any(str_detect(., regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")))) %>%
    colnames() 
  tcga <- tcga %>% dplyr::select(setdiff(colnames(tcga), remove))
  
  ## combine columns 
  tcga <- tcga %>% mutate(Diagnosis.Age = if_else(is.na(Diagnosis.Age), 
                                                  age_at_initial_pathologic_diagnosis, Diagnosis.Age)) ## age 
  tcga$smoke_yr <- tcga$Stopped.Smoking.Year - tcga$Started.Smoking.Year
  
  ## now manually select the columns you wish to keep and rename them if necessary 
  tcga <- tcga %>% 
    select( 
      ## personal information 
      sample, Diagnosis.Age, gender, patient_id, 
      ## tumour information 
      pathologic_stage, pathologic_M, pathologic_N, pathologic_T, sample_type, 
      residual_tumor, Cancer.Type.Detailed, new_tumor_event_after_initial_treatment, 
      longest_dimension, intermediate_dimension, shortest_dimension, anatomic_neoplasm_subdivision,
      histological_type, Prior.Cancer.Diagnosis.Occurence, 
      ## life-style 
      number_pack_years_smoked, tobacco_smoking_history, smoke_yr, 
      ## treatment 
      history_of_neoadjuvant_treatment, targeted_molecular_therapy, radiation_therapy, 
      primary_therapy_outcome_success, followup_treatment_success, 
      ## genomic information 
      Mutation.Count, Fraction.Genome.Altered, TMB..nonsynonymous., 
      X_PANCAN_miRNA_PANCAN, X_PANCAN_mutation_PANCAN, 
      ## survival status 
      OS, OS.time, DSS, DSS.time, DFI, DFI.time, PFI, PFI.time
      ) %>% 
    rename(age = Diagnosis.Age, 
           sex = gender, 
           stage = pathologic_stage, 
           cancer_type = Cancer.Type.Detailed, 
           new_tumour = new_tumor_event_after_initial_treatment, 
           anatomy_coord = anatomic_neoplasm_subdivision, 
           pack_yr = number_pack_years_smoked, 
           tobacco = tobacco_smoking_history, 
           prior_cancer = Prior.Cancer.Diagnosis.Occurence, 
           neoadjuvant_therapy = history_of_neoadjuvant_treatment, 
           targeted_therapy = targeted_molecular_therapy, 
           primary_outcome = primary_therapy_outcome_success, 
           secondline_outcome = followup_treatment_success, 
           mutation_count = Mutation.Count, 
           FGA = Fraction.Genome.Altered, 
           TMB = TMB..nonsynonymous., 
           miRNA_cluster = X_PANCAN_miRNA_PANCAN, 
           mutation_cluster = X_PANCAN_mutation_PANCAN)
  
  ## add rownames 
  rownames(tcga) <- gsub("-", ".", tcga$sample)
  
  ## add the copy numbers to it 
  tcga_cna <- read.table("~/MRes_project_1/docs/GISTIC2/tcga/lung/broad_values_by_arm.txt",  ## read in 
                         sep = "\t", header = T, row.names = 1) %>% t() %>% as.data.frame()
  colnames(tcga_cna) <- paste0("chr", colnames(tcga_cna)) ## change rownames 
  tcga <- tcga[rownames(tcga_cna), ] ## align 
  tcga <- merge(tcga, tcga_cna, by="row.names")
  tcga$Row.names <- NULL
  
  ## change all empty strings to NA values 
  tcga <- lapply(tcga, function(x) ifelse(x == "", NA, x))
  tcga <- tcga %>% as.data.frame()
  
  ## selectively mutate some columns 
  tcga$sex <- ifelse(tcga$sex == "MALE", 1, 0) ## male = 1, female = 0
  tcga$new_tumour <- ifelse(tcga$new_tumour == "YES", 1, 0) ## yes = 1, no = 0
  tcga$prior_cancer <- ifelse(tcga$prior_cancer == "Yes", 1, 0) ## yes = 1, no = 0
  tcga$neoadjuvant_therapy <- ifelse(tcga$neoadjuvant_therapy == "Yes", 1, 0) ## yes = 1, no = 0
  tcga$targeted_therapy <- ifelse(tcga$targeted_therapy == "YES", 1, 0) ## yes = 1, no = 0
  tcga$radiation_therapy <- ifelse(tcga$radiation_therapy == "YES", 1, 0) ## yes = 1, no = 0
  tcga <- tcga %>% mutate(primary_outcome = case_when(
    primary_outcome == "Complete Remission/Response" ~ 2L,
    primary_outcome == "Partial Remission/Response" ~ 1L,
    primary_outcome == "Stable Disease" ~ 0L,
    primary_outcome == "Progressive Disease" ~ -1L,
    TRUE ~ NA_integer_
  ))
  tcga <- tcga %>% mutate(secondline_outcome = case_when(
    secondline_outcome == "Complete Remission/Response" ~ 2L,
    secondline_outcome == "Partial Remission/Response" ~ 1L,
    secondline_outcome == "Stable Disease" ~ 0L,
    secondline_outcome == "Progressive Disease" ~ -1L,
    TRUE ~ NA_integer_
  ))
  tcga$primary_response <- ifelse(tcga$primary_outcome > 0, 1, 0) ## if primary outcome is 1 or 2, then response = 1, else 0
  tcga$secondline_response <- ifelse(tcga$secondline_outcome > 0, 1, 0) ## same logic as above 
  tcga$stage <- roman2int(gsub("Stage\\s|A|B|C|Discrepancy|\\[|\\]", "", tcga$stage))
  tcga$pathologic_M <- gsub("M", "", tcga$pathologic_M) %>% as.numeric()
  tcga$pathologic_N <- gsub("N", "", tcga$pathologic_N) %>% as.numeric()
  tcga$pathologic_T <- gsub("T", "", tcga$pathologic_T) %>% as.numeric()
  tcga$sample_type <- ifelse(tcga$sample_type == "Primary Tumor", 0, 1) ## primary tumour = 0, recurrent = 1
  tcga$residual_tumor <- ifelse(tcga$residual_tumor == "RX", NA, tcga$residual_tumor)
  tcga$residual_tumor <- gsub("R", "", tcga$residual_tumor) %>% as.numeric() ## R0, no residual; R1, microscopic; R2, macroscopic
  tcga$cancer_type <- ifelse(tcga$cancer_type == "Lung Adenocarcinoma", 1, 0) ## 1 = LUAD, 0 = LUSC
  tcga$miRNA_cluster <- gsub("miRNA cluster ", "", tcga$miRNA_cluster) %>% as.numeric()
  tcga$mutation_cluster <- gsub("mutation cluster |mutation c1uster ", "", tcga$mutation_cluster) %>% as.numeric()
  tcga$anatomy_coord <- gsub(" \\(please specify\\)|\\[Discrepancy\\]", "", tcga$anatomy_coord)
  tcga$anatomy_coord <- ifelse(tcga$anatomy_coord == "", NA, tcga$anatomy_coord)
  
  ## except for character columns listed, make every other column numeric 
  character_cols <- c("sample", "anatomy_coord", "histological_type")
  tcga[, setdiff(colnames(tcga), character_cols)] <- apply(tcga[, setdiff(colnames(tcga), character_cols)], 2, as.numeric)

  ## save table 
  write.table(tcga, "~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_combined.txt", 
              sep = "\t", col.names = T, row.names = F, quote = F)
}
tcga <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_combined.txt", 
                   sep = "\t", header = TRUE)
rownames(tcga) <- tcga$sample

character_cols <- c("sample", "anatomy_coord", "histological_type")
survival_cols <- c("OS", "OS.time", "DSS", "DSS.time", "DFI", "DFI.time", "PFI", "PFI.time")
cna_cols <- colnames(tcga)[grep("^chr", colnames(tcga))]
numeric_cols <- setdiff(colnames(tcga), c(character_cols, survival_cols, cna_cols))

Cohort characteristics.

plot_list <- list()
plot_cols <- c("age", "stage", "longest_dimension", "intermediate_dimension", "shortest_dimension", 
             "pack_yr", "tobacco", "smoke_yr", "mutation_count", "FGA", "TMB")
for (i in plot_cols) {
  p <- ggplot(tcga, aes_string(x = "as.factor(sample_type)", y = i)) +
    geom_violin(trim = FALSE) +
    ggtitle(paste(i)) + xlab("sample type") + 
    theme(title = element_text(size = 8))
  plot_list[[i]] <- p
}
plot_grid <- wrap_plots(plot_list, ncol = floor(sqrt(length(plot_cols)))) 
plot_grid

Survival Analysis

Univariate Analysis

given a list of numeric columns numeric_cols perform univaraite analysis of all these columns against patient survival given as this formula: surv_obj <- Surv(time = tcga$OS.time, event = tcga$OS) and store the result in a dataframe called univarate with 5 columns (column name = HR, upper_95, lower_95, p_value, FDR) and rownames being names from numeric_cols.

## univariate analysis on overall survival 
univariate <- matrix(NA, nrow = length(numeric_cols), ncol = 5) %>% as.data.frame()
colnames(univariate) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(univariate) <- numeric_cols

for(i in numeric_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga[,i], data = tcga)
  test <- summary(test)
  
  univariate[i, "HR"] <- test$coefficients[1, 2]
  univariate[i, "p_value"] <- test$coefficients[1, 5]
  univariate[i, "upper_95"] <- test$conf.int[1, 4]
  univariate[i, "lower_95"] <- test$conf.int[1, 3]
}
univariate$FDR <- p.adjust(univariate$p_value, method = "fdr")
univariate$FDR <- round(univariate$FDR, digits = 4)

Multivariate analysis

given a list of numeric columns cna_cols perform multivariate analysis of all these columns against patient survival given as this formula: surv_obj <- Surv(time = tcga$OS.time, event = tcga$OS) with age, stage, and sex as initial covariates and store the result in a dataframe called multivariate_1 with 5 columns (column name = HR, upper_95, lower_95, p_value, FDR) and rownames being names from cna_cols.

## multivariate analysis on overall survival 
multivariate_1 <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(multivariate_1) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(multivariate_1) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga[,i]+age+sex+stage, data = tcga)
  test <- summary(test)
  
  multivariate_1[i, "HR"] <- test$coefficients[1, 2]
  multivariate_1[i, "p_value"] <- test$coefficients[1, 5]
  multivariate_1[i, "upper_95"] <- test$conf.int[1, 4]
  multivariate_1[i, "lower_95"] <- test$conf.int[1, 3]
}
multivariate_1$FDR <- p.adjust(multivariate_1$p_value, method = "fdr")
multivariate_1$FDR <- round(multivariate_1$FDR, digits = 4)
multivariate_1 <- multivariate_1 %>% dplyr::arrange(p_value)

Based on univariate analysis we identified the following factors as significantly associated with survival (fdr<0.05). but they do not necessary have biological meaning.
added residual_tumour, new_tumour, and radiation_therapy as covariate, remove sex from covariate

## multivariate analysis on overall survival 
multivariate_2 <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(multivariate_2) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(multivariate_2) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga[,i]+age+stage+residual_tumor+new_tumour+radiation_therapy, data = tcga)
  test <- summary(test)
  
  multivariate_2[i, "HR"] <- test$coefficients[1, 2]
  multivariate_2[i, "p_value"] <- test$coefficients[1, 5]
  multivariate_2[i, "upper_95"] <- test$conf.int[1, 4]
  multivariate_2[i, "lower_95"] <- test$conf.int[1, 3]
}
multivariate_2$FDR <- p.adjust(multivariate_2$p_value, method = "fdr")
multivariate_2$FDR <- round(multivariate_2$FDR, digits = 4)
multivariate_2 <- multivariate_2 %>% dplyr::arrange(p_value)

Maybe should we separate LUAD and LUSC?

if(!file.exists("~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_luad.txt")){
  tcga_luad <- tcga %>% filter(cancer_type == 1)
  tcga_luad_msi <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/raw/lung/luad_MSI.txt", 
                              sep = "\t", header = T) %>% 
    dplyr::select(Sample.ID, MSI.MANTIS.Score) %>% 
    dplyr::rename(sample = Sample.ID, MSI = MSI.MANTIS.Score)
  tcga_luad_aneuploidy <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/raw/lung/luad_aneuploidy.txt", 
                                     sep = "\t", header = T) %>% 
    dplyr::select(Sample.ID, Aneuploidy.Score) %>% 
    dplyr::rename(sample = Sample.ID, aneuploidy = Aneuploidy.Score)
  tcga_luad <- left_join(tcga_luad, tcga_luad_msi, by="sample")
  tcga_luad <- left_join(tcga_luad, tcga_luad_aneuploidy, by="sample")
  write.table(tcga_luad, file = "~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_luad.txt", 
              sep = "\t", quote = F, col.names = T, row.names = F)
}

if(!file.exists("~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_lusc.txt")){
  tcga_lusc <- tcga %>% filter(cancer_type == 0)
  tcga_lusc_msi <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/raw/lung/lusc_MSI.txt", 
                              sep = "\t", header = T) %>% 
    dplyr::select(Sample.ID, MSI.MANTIS.Score) %>% 
    dplyr::rename(sample = Sample.ID, MSI = MSI.MANTIS.Score)
  tcga_lusc <- left_join(tcga_lusc, tcga_lusc_msi, by="sample")
  write.table(tcga_lusc, file = "~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_lusc.txt", 
              sep = "\t", quote = F, col.names = T, row.names = F)
}

Multivariate analysis for LUAD regressing out age, stage, and sex.

tcga_luad <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_luad.txt", 
                        sep = "\t", header = T)
rownames(tcga_luad) <- tcga_luad$sample

## multivariate analysis on overall survival with luad
luad <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(luad) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(luad) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga_luad[,i]+age+stage+sex, data = tcga_luad)
  test <- summary(test)
  
  luad[i, "HR"] <- test$coefficients[1, 2]
  luad[i, "p_value"] <- test$coefficients[1, 5]
  luad[i, "upper_95"] <- test$conf.int[1, 4]
  luad[i, "lower_95"] <- test$conf.int[1, 3]
}
luad$FDR <- p.adjust(luad$p_value, method = "fdr")
luad$FDR <- round(luad$FDR, digits = 4)
luad <- luad %>% dplyr::arrange(p_value)
tcga_lusc <- read.table("~/MRes_project_1/docs/00_mitéra/clinical/processed/lung/tcga_lusc.txt", 
                        sep = "\t", header = T)

## multivariate analysis on overall survival with lusc
lusc <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(lusc) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(lusc) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga_lusc[,i]+age+stage+sex, data = tcga_lusc)
  test <- summary(test)
  
  lusc[i, "HR"] <- test$coefficients[1, 2]
  lusc[i, "p_value"] <- test$coefficients[1, 5]
  lusc[i, "upper_95"] <- test$conf.int[1, 4]
  lusc[i, "lower_95"] <- test$conf.int[1, 3]
}
lusc$FDR <- p.adjust(lusc$p_value, method = "fdr")
lusc$FDR <- round(lusc$FDR, digits = 4)
lusc <- lusc %>% dplyr::arrange(p_value)

After experimenting, the top hit chromosomes are quite different in the two datasets, let’s first focus on lung adenocarcinoma. Covariate regresing out age, stage, sex, pack_yr, tobacco, FGA, mutation_count, and TMB. age, stage, and sex are regressed out a s personal information, pack_yr and tobacco are regressed out because smoking is shown to correlated with lung cancer tumorigenesis and survival advantage. FGA, mutation_count and TMB are regressed out because they are shown to have prognostic value in other studies.
First, let’s look at lung adenocarcinoma

## multivariate analysis on overall survival with luad
luad_2 <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(luad_2) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(luad_2) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga_luad[,i]+age+stage+sex+pack_yr+tobacco+FGA+mutation_count+TMB, data = tcga_luad)
  test <- summary(test)
  
  luad_2[i, "HR"] <- test$coefficients[1, 2]
  luad_2[i, "p_value"] <- test$coefficients[1, 5]
  luad_2[i, "upper_95"] <- test$conf.int[1, 4]
  luad_2[i, "lower_95"] <- test$conf.int[1, 3]
}
luad_2$FDR <- p.adjust(luad_2$p_value, method = "fdr")
luad_2$FDR <- round(luad_2$FDR, digits = 4)
luad_2 <- luad_2 %>% dplyr::arrange(p_value)

Next look at lung squamous cell carcinoma.

## multivariate analysis on overall survival with luad
lusc_2 <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(lusc_2) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(lusc_2) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga_lusc[,i]+age+stage+sex+pack_yr+tobacco+FGA+mutation_count+TMB, 
                data = tcga_lusc)
  test <- summary(test)
  
  lusc_2[i, "HR"] <- test$coefficients[1, 2]
  lusc_2[i, "p_value"] <- test$coefficients[1, 5]
  lusc_2[i, "upper_95"] <- test$conf.int[1, 4]
  lusc_2[i, "lower_95"] <- test$conf.int[1, 3]
}
lusc_2$FDR <- p.adjust(lusc_2$p_value, method = "fdr")
lusc_2$FDR <- round(lusc_2$FDR, digits = 4)
lusc_2 <- lusc_2 %>% dplyr::arrange(p_value)

Lastly, apply the covariates to complete lung cancer dataset.

## multivariate analysis on overall survival 
multivariate_3 <- matrix(NA, nrow = length(cna_cols), ncol = 5) %>% as.data.frame()
colnames(multivariate_3) <- c("HR", "upper_95", "lower_95", "p_value", "FDR")
rownames(multivariate_3) <- cna_cols

for(i in cna_cols){
  test <- coxph(Surv(time=OS.time, event=OS)~tcga[,i]+age+stage+sex+pack_yr+tobacco+FGA+mutation_count+TMB, data = tcga)
  test <- summary(test)
  
  multivariate_3[i, "HR"] <- test$coefficients[1, 2]
  multivariate_3[i, "p_value"] <- test$coefficients[1, 5]
  multivariate_3[i, "upper_95"] <- test$conf.int[1, 4]
  multivariate_3[i, "lower_95"] <- test$conf.int[1, 3]
}
multivariate_3$FDR <- p.adjust(multivariate_3$p_value, method = "fdr")
multivariate_3$FDR <- round(multivariate_3$FDR, digits = 4)
multivariate_3 <- multivariate_3 %>% dplyr::arrange(p_value)

Visualise the chromosome arm status in TCGA cancer

In all lung cancer

## in all lung cancer samples 
cna_status <- matrix(NA, nrow = 1, ncol = 3)
colnames(cna_status) <- c("amp", "del", "wt")

for(i in cna_cols){
  table <- ifelse(tcga[i]>0, "amp", ifelse(tcga[i] < 0, "del", "wt")) %>% table() %>% t() 
  cna_status <- rbind(cna_status, table)
}
cna_status <- cna_status[2:nrow(cna_status), ] %>% as.data.frame()
rownames(cna_status) <- cna_cols

Row_Sums <- rowSums(cna_status)
cna_status <- sweep(x = cna_status, MARGIN = 1, STATS = Row_Sums, FUN = "/") ## calculate fraction 
cna_status <- cna_status * 100 ## into percentage 

cna_status$chr_arms <- cna_cols

## stack bar plot 
cna_status_long <- cna_status %>% pivot_longer(cols = amp:wt, names_to = "Mutation", values_to = "Percentage")

# Create a stacked bar plot
p1 <- ggplot(cna_status_long, aes(x = chr_arms, y = Percentage, fill = Mutation)) +
  geom_bar(stat = "identity") + coord_flip()+
  labs(x = "chromosome arms", y = "Percentage") + theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1), 
        title = element_text(size = 8)) + 
  scale_fill_brewer(palette = "Set3") + 
  ggtitle("chr_arm status in TCGA lung cancer")

In lung adenocarcinoma

## in all lung cancer samples 
cna_status <- matrix(NA, nrow = 1, ncol = 3)
colnames(cna_status) <- c("amp", "del", "wt")

for(i in cna_cols){
  table <- ifelse(tcga_luad[i]>0, "amp", ifelse(tcga_luad[i] < 0, "del", "wt")) %>% table() %>% t() 
  cna_status <- rbind(cna_status, table)
}
cna_status <- cna_status[2:nrow(cna_status), ] %>% as.data.frame()
rownames(cna_status) <- cna_cols

Row_Sums <- rowSums(cna_status)
cna_status <- sweep(x = cna_status, MARGIN = 1, STATS = Row_Sums, FUN = "/") ## calculate fraction 
cna_status <- cna_status * 100 ## into percentage 

cna_status$chr_arms <- cna_cols

## stack bar plot 
cna_status_long <- cna_status %>% pivot_longer(cols = amp:wt, names_to = "Mutation", values_to = "Percentage")

# Create a stacked bar plot
p2 <- ggplot(cna_status_long, aes(x = chr_arms, y = Percentage, fill = Mutation)) +
  geom_bar(stat = "identity") + coord_flip()+
  labs(x = "chromosome arms", y = "Percentage") + theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1), 
        title = element_text(size = 8)) + 
  scale_fill_brewer(palette = "Set3") + 
  ggtitle("chr_arm status in TCGA LUAD")

In lung squamous cell carcinoma

## in all lung cancer samples 
cna_status <- matrix(NA, nrow = 1, ncol = 3)
colnames(cna_status) <- c("amp", "del", "wt")

for(i in cna_cols){
  table <- ifelse(tcga_lusc[i]>0, "amp", ifelse(tcga_lusc[i] < 0, "del", "wt")) %>% table() %>% t() 
  cna_status <- rbind(cna_status, table)
}
cna_status <- cna_status[2:nrow(cna_status), ] %>% as.data.frame()
rownames(cna_status) <- cna_cols

Row_Sums <- rowSums(cna_status)
cna_status <- sweep(x = cna_status, MARGIN = 1, STATS = Row_Sums, FUN = "/") ## calculate fraction 
cna_status <- cna_status * 100 ## into percentage 

cna_status$chr_arms <- cna_cols

## stack bar plot 
cna_status_long <- cna_status %>% pivot_longer(cols = amp:wt, names_to = "Mutation", values_to = "Percentage")

# Create a stacked bar plot
p3 <- ggplot(cna_status_long, aes(x = chr_arms, y = Percentage, fill = Mutation)) +
  geom_bar(stat = "identity") + coord_flip()+
  labs(x = "chromosome arms", y = "Percentage") + theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1), 
        title = element_text(size = 8)) + 
  scale_fill_brewer(palette = "Set3") + 
  ggtitle("chr_arm status in TCGA LUSC")

Forest plot.

multivariate_3$Index <- factor(rownames(multivariate_3), levels = rownames(multivariate_3))
p4 <- ggplot(multivariate_3, aes(x = Index, y = HR)) +
  geom_point() +
  geom_errorbar(aes(ymin = lower_95, ymax = upper_95), width = 0.2) +
  coord_flip() + # Flip coordinates to make it a traditional forest plot layout
  theme_bw() +
  labs(y = "log10 Hazard Ratio (HR)", x = "Chromosome Arms") +
  geom_hline(yintercept = 1) + 
  ggtitle("TCGA Lung Cancer") + ylim(floor(min(multivariate_3$lower_95)), ceiling(max(multivariate_3$upper_95))) + 
  theme(title = element_text(size = 9))

luad_2$Index <- factor(rownames(luad_2), levels = rownames(luad_2))
p5 <- ggplot(luad_2, aes(x = Index, y = HR)) +
  geom_point() +
  geom_errorbar(aes(ymin = lower_95, ymax = upper_95), width = 0.2) +
  coord_flip() + # Flip coordinates to make it a traditional forest plot layout
  theme_bw() +
  labs(y = "log10 Hazard Ratio (HR)", x = "Chromosome Arms") +
  geom_hline(yintercept = 1) + 
  ggtitle("TCGA LUAD") + ylim(floor(min(luad_2$lower_95)), ceiling(max(luad_2$upper_95))) + 
  theme(title = element_text(size = 9))

lusc_2$Index <- factor(rownames(lusc_2), levels = rownames(lusc_2))
p6 <- ggplot(lusc_2, aes(x = Index, y = HR)) +
  geom_point() +
  geom_errorbar(aes(ymin = lower_95, ymax = upper_95), width = 0.2) +
  coord_flip() + # Flip coordinates to make it a traditional forest plot layout
  theme_bw() +
  labs(y = "log10 Hazard Ratio (HR)", x = "Chromosome Arms") +
  geom_hline(yintercept = 1) + 
  ggtitle("TCGA LUSC") + ylim(floor(min(lusc_2$lower_95)), ceiling(max(lusc_2$upper_95))) + 
  theme(title = element_text(size = 9))

Kaplan Meier Plot

tcga_luad$chr15qStatus <- ifelse(tcga_luad$chr15q > 0, "amp", "wt")
tcga_luad$chr22qStatus <- ifelse(tcga_luad$chr22q > 0, "amp", "wt")

fit <- survfit(Surv(OS.time, OS) ~ as.factor(chr22qStatus), data = tcga_luad)
p7 <- ggsurvplot_customised(fit_function = fit, dataframe = tcga_luad, pval_coord = c(3500, 0.75), 
                            break_time_by = 1000, legend_labs = c("amp", "wt"), p.val_method = "1", 
                            title = "Kaplan-Meier Curve for TCGA LUAD", 
                            subtitle = "survival = OS, subtype = LUAD, n = 502, chr_arm = 22q")

fit <- survfit(Surv(OS.time, OS) ~ as.factor(chr15qStatus), data = tcga_luad)
p8 <- ggsurvplot_customised(fit_function = fit, dataframe = tcga_luad, pval_coord = c(3500, 0.75), 
                            break_time_by = 1000, legend_labs = c("amp", "wt"), p.val_method = "1", 
                            title = "Kaplan-Meier Curve for TCGA LUAD", 
                            subtitle = "survival = OS, subtype = LUAD, n = 502, chr_arm = 15q")
tcga_lusc$chr22qStatus <- ifelse(tcga_lusc$chr22q < 0, "del", "wt")
tcga_lusc$chr15qStatus <- ifelse(tcga_lusc$chr15q < 0, "del", "wt")

fit <- survfit(Surv(OS.time, OS) ~ as.factor(chr22qStatus), data = tcga_lusc)
p9 <- ggsurvplot_customised(fit_function = fit, dataframe = tcga_lusc, pval_coord = c(3500, 0.75), 
                            break_time_by = 500, legend_labs = c("del", "wt"), p.val_method = "1", 
                            title = "Kaplan-Meier Curve for TCGA LUSC", 
                            subtitle = "survival = OS, subtype = LUSC, n = 487, chr_arm = 22q")

fit <- survfit(Surv(OS.time, OS) ~ as.factor(chr15qStatus), data = tcga_lusc)
p10 <- ggsurvplot_customised(fit_function = fit, dataframe = tcga_lusc, pval_coord = c(3500, 0.75), 
                             break_time_by = 500, legend_labs = c("del", "wt"), p.val_method = "1", 
                            title = "Kaplan-Meier Curve for TCGA LUSC", 
                            subtitle = "survival = OS, subtype = LUSC, n = 487, chr_arm = 15q")
tcga$chr4pStatus <- ifelse(tcga$chr4p > 0, "amp", "wt")

fit <- survfit(Surv(OS.time, OS) ~ as.factor(chr4pStatus), data = tcga)
p11 <- ggsurvplot_customised(fit_function = fit, dataframe = tcga, pval_coord = c(3500, 0.75), 
                            break_time_by = 500, legend_labs = c("amp", "wt"), p.val_method = "1", 
                            title = "Kaplan-Meier Curve for TCGA LUSC+LUAD", 
                            subtitle = "survival = OS, subtype = LUSC+LUAD, n = 989, chr_arm = 4p")

Therapy association

Lung adenocarcinoma

p12 <- ggplot(tcga_luad, aes(x = as.factor(primary_outcome), y = chr15q))+geom_violin()+ggtitle("primary therapy, LUAD, 15q")
p13 <- ggplot(tcga_luad, aes(x = as.factor(primary_outcome), y = chr22q))+geom_violin()+ggtitle("primary therapy, LUAD, 22q")
p14 <- ggplot(tcga_luad, aes(x = as.factor(secondline_outcome), y = chr15q))+geom_violin()+ggtitle("secondline therapy, LUAD, 15q")
p15 <- ggplot(tcga_luad, aes(x = as.factor(secondline_outcome), y = chr22q))+geom_violin()+ggtitle("secondline therapy, LUAD, 22q")
aov(chr15q ~ as.factor(primary_outcome), data = tcga_luad) %>% summary()
aov(chr22q ~ as.factor(primary_outcome), data = tcga_luad) %>% summary()
aov(chr15q ~ as.factor(secondline_outcome), data = tcga_luad) %>% summary()
aov(chr22q ~ as.factor(secondline_outcome), data = tcga_luad) %>% summary()
p16 <- ggplot(tcga_luad, aes(x = as.factor(primary_response), y = chr15q))+geom_violin()+ggtitle("primary response, LUAD, 15q")
p17 <- ggplot(tcga_luad, aes(x = as.factor(primary_response), y = chr22q))+geom_violin()+ggtitle("primary response, LUAD, 22q")
p18 <- ggplot(tcga_luad, aes(x = as.factor(secondline_response), y = chr15q))+geom_violin()+ggtitle("secondline response, LUAD, 15q")
p19 <- ggplot(tcga_luad, aes(x = as.factor(secondline_response), y = chr22q))+geom_violin()+ggtitle("secondline response, LUAD, 22q")
wilcox.test(tcga_luad$chr15q[tcga_luad$primary_response == 1], tcga_luad$chr15q[tcga_luad$primary_response == 0])
wilcox.test(tcga_luad$chr22q[tcga_luad$primary_response == 1], tcga_luad$chr22q[tcga_luad$primary_response == 0])
wilcox.test(tcga_luad$chr15q[tcga_luad$secondline_response == 1], tcga_luad$chr15q[tcga_luad$secondline_response == 0])
wilcox.test(tcga_luad$chr22q[tcga_luad$secondline_response == 1], tcga_luad$chr22q[tcga_luad$secondline_response == 0])

Lung squamous cell carcinoma

p20 <- ggplot(tcga_lusc, aes(x = as.factor(primary_outcome), y = chr15q))+geom_violin()+ggtitle("primary therapy, LUSC, 15q")
p21 <- ggplot(tcga_lusc, aes(x = as.factor(primary_outcome), y = chr22q))+geom_violin()+ggtitle("primary therapy, LUSC, 22q")
p22 <- ggplot(tcga_lusc, aes(x = as.factor(secondline_outcome), y = chr15q))+geom_violin()+ggtitle("secondline therapy, LUSC, 15q")
p23 <- ggplot(tcga_lusc, aes(x = as.factor(secondline_outcome), y = chr22q))+geom_violin()+ggtitle("secondline therapy, LUSC, 22q")
aov(chr15q ~ as.factor(primary_outcome), data = tcga_lusc) %>% summary()
aov(chr22q ~ as.factor(primary_outcome), data = tcga_lusc) %>% summary()
aov(chr15q ~ as.factor(secondline_outcome), data = tcga_lusc) %>% summary()
aov(chr22q ~ as.factor(secondline_outcome), data = tcga_lusc) %>% summary()
p24 <- ggplot(tcga_lusc, aes(x = as.factor(primary_response), y = chr15q))+geom_violin()+ggtitle("primary response, LUSC, 15q")
p25 <- ggplot(tcga_lusc, aes(x = as.factor(primary_response), y = chr22q))+geom_violin()+ggtitle("primary response, LUSC, 22q")
p26 <- ggplot(tcga_lusc, aes(x = as.factor(secondline_response), y = chr15q))+geom_violin()+ggtitle("secondline response, LUSC, 15q")
p27 <- ggplot(tcga_lusc, aes(x = as.factor(secondline_response), y = chr22q))+geom_violin()+ggtitle("secondline response, LUSC, 22q")
wilcox.test(tcga_lusc$chr15q[tcga_lusc$primary_response == 1], tcga_lusc$chr15q[tcga_lusc$primary_response == 0])
wilcox.test(tcga_lusc$chr22q[tcga_lusc$primary_response == 1], tcga_lusc$chr22q[tcga_lusc$primary_response == 0])
wilcox.test(tcga_lusc$chr15q[tcga_lusc$secondline_response == 1], tcga_lusc$chr15q[tcga_lusc$secondline_response == 0])
wilcox.test(tcga_lusc$chr22q[tcga_lusc$secondline_response == 1], tcga_lusc$chr22q[tcga_lusc$secondline_response == 0])
LS0tCnRpdGxlOiAiTHVuZyBjYW5jZXIgdGFyZ2V0IGFybSBzZWxlY3Rpb24iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KYGBge3Igc2V0dXB9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsPUZBTFNFKQpgYGAKCmBgYHtyIGxpYnJhcnl9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkoc3Vydml2YWwpCmxpYnJhcnkoZ3Rvb2xzKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHN1cnZtaW5lcikKbGlicmFyeShnZ3N1cnZmaXQpCmxpYnJhcnkocGhlYXRtYXApCnNvdXJjZSgifi9NUmVzX3Byb2plY3RfMS9jb2Rlcy81X3Bsb3RzL3NjcmlwdC9mdW5jdGlvbi5SIikKZ2dzdXJ2cGxvdF9jdXN0b21pc2VkIDwtIGZ1bmN0aW9uIChmaXRfZnVuY3Rpb24sIGRhdGFmcmFtZSwgcHZhbF9jb29yZCwgYnJlYWtfdGltZV9ieSwgdGl0bGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlLCBsZWdlbmRfbGFicywgcC52YWxfbWV0aG9kKSB7CiAgcCA8LSBnZ3N1cnZwbG90KGZpdCA9IGZpdF9mdW5jdGlvbiwgZGF0YSA9IGRhdGFmcmFtZSwgCiAgICAgICAgICAgICAgICAgIHJpc2sudGFibGUgPSBUUlVFLCByaXNrLnRhYmxlLmhlaWdodCA9IDAuMiwgcmlzay50YWJsZS55LnRleHQuY29sID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgIHJpc2sudGFibGUueS50ZXh0ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICBwdmFsID0gVFJVRSwgcHZhbC5tZXRob2QgPSBGQUxTRSwgcHZhbC5jb29yZCA9IHB2YWxfY29vcmQsIHB2YWwuc2l6ZSA9IDMsIAogICAgICAgICAgICAgICAgICBsb2cucmFuay53ZWlnaHRzID0gcC52YWxfbWV0aG9kLCAKICAgICAgICAgICAgICAgICAgY29uZi5pbnQgPSBUUlVFLCBjb25mLmludC5zdHlsZSA9ICJyaWJib24iLCAKICAgICAgICAgICAgICAgICAgbmNlbnNvci5wbG90ID0gVFJVRSwgbmNlbnNvci5wbG90LmhlaWdodCA9IDAuMiwgY2Vuc29yLnNpemUgPSAxLCAKICAgICAgICAgICAgICAgICAgY2Vuc29yLnNoYXBlID0gMTI0LCAKICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gInN0YXR1cyIsIGxlZ2VuZC5sYWJzID0gbGVnZW5kX2xhYnMsIGxlZ2VuZCA9ICJ0b3AiLCAKICAgICAgICAgICAgICAgICAgeGxhYiA9ICJEYXlzIiwgYnJlYWsudGltZS5ieSA9IGJyZWFrX3RpbWVfYnksIAogICAgICAgICAgICAgICAgICBzdXJ2Lm1lZGlhbi5saW5lID0gImh2IiwgCiAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMywgZm9udC5mYW1pbHkgPSAiQXJpYWwiLCBmb250LmxlZ2VuZCA9IGMoOSksIHNpemUgPSAwLjUsIAogICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbGlnaHQoKSwgCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gdGl0bGUsIHN1YnRpdGxlID0gc3VidGl0bGUsIAogICAgICAgICAgICAgICAgICBzdXJ2LnNjYWxlID0gInBlcmNlbnQiKQogIHAgPC0gY3VzdG9taXplX2xhYmVscyhwLCBmb250LnRpdGxlID0gYyg5LCAiYm9sZCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgZm9udC5zdWJ0aXRsZSA9IGMoOSwgIml0YWxpYyIsICJkYXJrZ3JleSIpLCBmb250LnggPSBjKDkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgZm9udC55ID0gYyg5KSwgZm9udC54dGlja3NsYWIgPSBjKDgpKQogIHAkcGxvdCA8LSBwJHBsb3QgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDE4MjYpLCBzaXplID0gMC4zLCBhbHBoYSA9IDAuNSkKICByZXR1cm4ocCkKfQpgYGAKCiMjIyMgbG9hZCBmaWxlcyAKYGBge3IgZ2lzdGljX2NuYX0KaWYoIWZpbGUuZXhpc3RzKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvR0lTVElDMi9sdW5nX2FybV9jb21wbGV0ZS50eHQiKSl7CiAgdGNnYSA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvR0lTVElDMi90Y2dhL2x1bmcvYnJvYWRfdmFsdWVzX2J5X2FybS50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVCkKICBtc2tjYyA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvR0lTVElDMi9jYmlvcG9ydGFsL2x1bmdfMi9icm9hZF92YWx1ZXNfYnlfYXJtLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVCkKICBoaCA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvR0lTVElDMi9oaC9sdW5nXzIvYnJvYWRfdmFsdWVzX2J5X2FybS50eHQiLCAKICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIGhlYWRlciA9IFQpCiAgCiAgbHVuZ19hcm0gPC0gbGVmdF9qb2luKHRjZ2EsIG1za2NjLCBieT0iQ2hyb21vc29tZS5Bcm0iKQogIGx1bmdfYXJtIDwtIGxlZnRfam9pbihsdW5nX2FybSwgaGgsIGJ5PSJDaHJvbW9zb21lLkFybSIpCiAgd3JpdGUudGFibGUobHVuZ19hcm0sICJ+L01SZXNfcHJvamVjdF8xL2RvY3MvR0lTVElDMi9sdW5nX2FybV9jb21wbGV0ZS50eHQiLCAKICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBULCByb3cubmFtZXMgPSBGKQp9IGVsc2UgewogIGx1bmdfYXJtIDwtIHJlYWQudGFibGUoIn4vTVJlc19wcm9qZWN0XzEvZG9jcy9HSVNUSUMyL2x1bmdfYXJtX2NvbXBsZXRlLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVCkKfQoKbHVuZ19hcm1bMToxMCwgMToxMF0KYGBgCgojIyBUQ0dBIGx1bmcgY2FuY2VyIGRhdGFzZXQgICAgICAKQWxsIG9mIHRoZXNlIHNhbXBsZXMgYXJlIGZyb20gbm9uLXNtYWxsIGNlbGwgbHVuZyBjYW5jZXIgcGF0aWVudHMuICAgICAKYGBge3IgdGNnYX0KIyBpZiByYXcgY29tYmluZWQgZmlsZSBub3QgZXhpc3QgCmlmKCFmaWxlLmV4aXN0cygifi9NUmVzX3Byb2plY3RfMS9kb2NzLzAwX21pdMOpcmEvY2xpbmljYWwvcmF3L2x1bmcvdGNnYV9jb21iaW5lZF9yYXcudHh0IikpewogICMjIGxvYWQgCiAgc2V0d2QoIn4vTVJlc19wcm9qZWN0XzEvZG9jcy8wMF9taXTDqXJhL2NsaW5pY2FsL3Jhdy9sdW5nIikKICB0Y2dhX2NsaW5pY2FsX3Vjc2MgPC0gcmVhZC50YWJsZSgidGNnYV9sdW5nX2NsaW5pY2FsX3Vjc2MudHh0IiwgaGVhZGVyID0gVCwgc2VwID0gIlx0IikKICB0Y2dhX3N1cnZpdmFsX3Vjc2MgPC0gcmVhZC50YWJsZSgidGNnYV9sdW5nX3N1cnZpdmFsX3Vjc2MudHh0IiwgaGVhZGVyID0gVCwgc2VwID0gIlx0IikKICB0Y2dhX2x1c2NfY2JwIDwtIHJlYWQudGFibGUoImx1c2NfdGNnYV9jbGluaWNhbF9kYXRhLnRzdiIsIGhlYWRlciA9IFQsIHNlcCA9ICJcdCIpCiAgdGNnYV9sdWFkX2NicCA8LSByZWFkLnRhYmxlKCJsdWFkX3RjZ2FfY2xpbmljYWxfZGF0YS50c3YiLCBoZWFkZXIgPSBULCBzZXAgPSAiXHQiKQogIAogICMjIHJlbmFtZSAKICB0Y2dhX2NsaW5pY2FsX3Vjc2MgPC0gdGNnYV9jbGluaWNhbF91Y3NjICU+JSBkcGx5cjo6cmVuYW1lKHNhbXBsZSA9IHNhbXBsZUlEKQogIHRjZ2FfbHVzY19jYnAgPC0gdGNnYV9sdXNjX2NicCAlPiUgZHBseXI6OnJlbmFtZShzYW1wbGUgPSBTYW1wbGUuSUQpCiAgdGNnYV9sdWFkX2NicCA8LSB0Y2dhX2x1YWRfY2JwICU+JSBkcGx5cjo6cmVuYW1lKHNhbXBsZSA9IFNhbXBsZS5JRCkgCiAgCiAgIyMgam9pbgogIHRjZ2EgPC0gbGVmdF9qb2luKHRjZ2FfY2xpbmljYWxfdWNzYywgdGNnYV9zdXJ2aXZhbF91Y3NjLCBieT0ic2FtcGxlIikKICBjYnAgPC0gcmJpbmQodGNnYV9sdXNjX2NicFssIGludGVyc2VjdChjb2xuYW1lcyh0Y2dhX2x1c2NfY2JwKSwgY29sbmFtZXModGNnYV9sdWFkX2NicCkpXSwgCiAgICAgICAgICAgICAgIHRjZ2FfbHVhZF9jYnBbLCBpbnRlcnNlY3QoY29sbmFtZXModGNnYV9sdXNjX2NicCksIGNvbG5hbWVzKHRjZ2FfbHVhZF9jYnApKV0pCiAgdGNnYSA8LSBsZWZ0X2pvaW4odGNnYSwgY2JwLCBieT0ic2FtcGxlIikKICAKICAjIyBzYXZlIAogIHdyaXRlLnRhYmxlKHRjZ2EsICJ+L01SZXNfcHJvamVjdF8xL2RvY3MvMDBfbWl0w6lyYS9jbGluaWNhbC9yYXcvbHVuZy90Y2dhX2NvbWJpbmVkX3Jhdy50eHQiLCAKICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBULCByb3cubmFtZXMgPSBGLCBxdW90ZSA9IEYpCiAgCiAgCiAgIyMgaWYgcHJvY2Vzc2VkIGNvbWJpbmUgZmlsZSBub3QgZXhpc3QgCn0gZWxzZSBpZighZmlsZS5leGlzdHMoIn4vTVJlc19wcm9qZWN0XzEvZG9jcy8wMF9taXTDqXJhL2NsaW5pY2FsL3Byb2Nlc3NlZC9sdW5nL3RjZ2FfY29tYmluZWQudHh0IikpewogICMjIHJlYWQgaW4gCiAgdGNnYSA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvMDBfbWl0w6lyYS9jbGluaWNhbC9yYXcvbHVuZy90Y2dhX2NvbWJpbmVkX3Jhdy50eHQiLCBzZXAgPSAiXHQiLCBoZWFkZXIgPSBUKQogIAogICMjIHJlbW92ZSB1c2VsZXNzIGNvbHVtbnMgYnkuLi4gCiAgIyMgMS4gbW9yZSB0aGFuIDcwJSBtaXNzaW5nIGluZm9ybWF0aW9uIAogIGtlZXAgPC0gdGNnYSAlPiUgc2VsZWN0X2lmKH5pcy5udW1lcmljKC4pIHwgaXMuY2hhcmFjdGVyKC4pKSAlPiUgbWFwX2xnbCh+c3VtKGlzLm5hKC4pIHwgLiA9PSAiIikvbGVuZ3RoKC4pIDwgMC43KQogIHRjZ2EgPC0gdGNnYVtrZWVwXQogICMjIDIuIGNvbHVtbiB3aXRoIHNhbWUgdmFsdWVzIGFjcm9zcyAKICBrZWVwIDwtIGZ1bmN0aW9uKHgpewogICAgeCA8LSB4WyFpcy5uYSh4KSAmIHggIT0gIiJdICMjIG5vdCBlbXB0eSBzdHJpbmcgb3IgTkEgdmFsdWVzIAogICAgbGVuZ3RoKHVuaXF1ZSh4KSkgPiAxfSAjIyBtb3JlIHRoYW4gMSB1bmlxdWUgdmFsdWVzIGV4aXN0IGluIHRoZSBjb2x1bW4KICB0Y2dhIDwtIHRjZ2EgJT4lIHNlbGVjdCh3aGVyZShrZWVwKSkKICAjIyAzLiBzYW1wbGUgY29sdW1ucyAKICByb3duYW1lcyh0Y2dhKSA8LSB0Y2dhJHNhbXBsZSAjIyBzdG9yZSB0aGUgc2FtcGxlcyBhcyByb3duYW1lcyAKICB0Y2dhIDwtIHRjZ2EgJT4lIHNlbGVjdF9pZih+IWlzLmNoYXJhY3RlciguKSB8ICMjIHJlbW92ZSBjb2x1bW5zIHdpdGggVENHQSBiZWdpbm5pbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChpcy5jaGFyYWN0ZXIoLikgJiYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhYW55KHN0YXJ0c1dpdGgobmEub21pdCguKSwgIlRDR0EiKSkpKSAKICB0Y2dhJHNhbXBsZSA8LSByb3duYW1lcyh0Y2dhKSAjIyByZXN0b3JlIHRoZSBzYW1wbGUgY29sdW1uIAogICMjIDQuIFVVSUQgY29sdW1ucyAKICByZW1vdmUgPC0gdGNnYSAlPiUgIyMgZGVmaW5lIHV1aWQgY29sdW1ucyBhbmQgZXh0cmFjdCB0aGVpciBjb2x1bW4gbmFtZXMgIAogICAgc2VsZWN0X2lmKH5hbnkoc3RyX2RldGVjdCguLCByZWdleCgiXlswLTlhLWZBLUZdezh9LVswLTlhLWZBLUZdezR9LVswLTlhLWZBLUZdezR9LVswLTlhLWZBLUZdezR9LVswLTlhLWZBLUZdezEyfSQiKSkpKSAlPiUKICAgIGNvbG5hbWVzKCkgCiAgdGNnYSA8LSB0Y2dhICU+JSBkcGx5cjo6c2VsZWN0KHNldGRpZmYoY29sbmFtZXModGNnYSksIHJlbW92ZSkpCiAgCiAgIyMgY29tYmluZSBjb2x1bW5zIAogIHRjZ2EgPC0gdGNnYSAlPiUgbXV0YXRlKERpYWdub3Npcy5BZ2UgPSBpZl9lbHNlKGlzLm5hKERpYWdub3Npcy5BZ2UpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfYXRfaW5pdGlhbF9wYXRob2xvZ2ljX2RpYWdub3NpcywgRGlhZ25vc2lzLkFnZSkpICMjIGFnZSAKICB0Y2dhJHNtb2tlX3lyIDwtIHRjZ2EkU3RvcHBlZC5TbW9raW5nLlllYXIgLSB0Y2dhJFN0YXJ0ZWQuU21va2luZy5ZZWFyCiAgCiAgIyMgbm93IG1hbnVhbGx5IHNlbGVjdCB0aGUgY29sdW1ucyB5b3Ugd2lzaCB0byBrZWVwIGFuZCByZW5hbWUgdGhlbSBpZiBuZWNlc3NhcnkgCiAgdGNnYSA8LSB0Y2dhICU+JSAKICAgIHNlbGVjdCggCiAgICAgICMjIHBlcnNvbmFsIGluZm9ybWF0aW9uIAogICAgICBzYW1wbGUsIERpYWdub3Npcy5BZ2UsIGdlbmRlciwgcGF0aWVudF9pZCwgCiAgICAgICMjIHR1bW91ciBpbmZvcm1hdGlvbiAKICAgICAgcGF0aG9sb2dpY19zdGFnZSwgcGF0aG9sb2dpY19NLCBwYXRob2xvZ2ljX04sIHBhdGhvbG9naWNfVCwgc2FtcGxlX3R5cGUsIAogICAgICByZXNpZHVhbF90dW1vciwgQ2FuY2VyLlR5cGUuRGV0YWlsZWQsIG5ld190dW1vcl9ldmVudF9hZnRlcl9pbml0aWFsX3RyZWF0bWVudCwgCiAgICAgIGxvbmdlc3RfZGltZW5zaW9uLCBpbnRlcm1lZGlhdGVfZGltZW5zaW9uLCBzaG9ydGVzdF9kaW1lbnNpb24sIGFuYXRvbWljX25lb3BsYXNtX3N1YmRpdmlzaW9uLAogICAgICBoaXN0b2xvZ2ljYWxfdHlwZSwgUHJpb3IuQ2FuY2VyLkRpYWdub3Npcy5PY2N1cmVuY2UsIAogICAgICAjIyBsaWZlLXN0eWxlIAogICAgICBudW1iZXJfcGFja195ZWFyc19zbW9rZWQsIHRvYmFjY29fc21va2luZ19oaXN0b3J5LCBzbW9rZV95ciwgCiAgICAgICMjIHRyZWF0bWVudCAKICAgICAgaGlzdG9yeV9vZl9uZW9hZGp1dmFudF90cmVhdG1lbnQsIHRhcmdldGVkX21vbGVjdWxhcl90aGVyYXB5LCByYWRpYXRpb25fdGhlcmFweSwgCiAgICAgIHByaW1hcnlfdGhlcmFweV9vdXRjb21lX3N1Y2Nlc3MsIGZvbGxvd3VwX3RyZWF0bWVudF9zdWNjZXNzLCAKICAgICAgIyMgZ2Vub21pYyBpbmZvcm1hdGlvbiAKICAgICAgTXV0YXRpb24uQ291bnQsIEZyYWN0aW9uLkdlbm9tZS5BbHRlcmVkLCBUTUIuLm5vbnN5bm9ueW1vdXMuLCAKICAgICAgWF9QQU5DQU5fbWlSTkFfUEFOQ0FOLCBYX1BBTkNBTl9tdXRhdGlvbl9QQU5DQU4sIAogICAgICAjIyBzdXJ2aXZhbCBzdGF0dXMgCiAgICAgIE9TLCBPUy50aW1lLCBEU1MsIERTUy50aW1lLCBERkksIERGSS50aW1lLCBQRkksIFBGSS50aW1lCiAgICAgICkgJT4lIAogICAgcmVuYW1lKGFnZSA9IERpYWdub3Npcy5BZ2UsIAogICAgICAgICAgIHNleCA9IGdlbmRlciwgCiAgICAgICAgICAgc3RhZ2UgPSBwYXRob2xvZ2ljX3N0YWdlLCAKICAgICAgICAgICBjYW5jZXJfdHlwZSA9IENhbmNlci5UeXBlLkRldGFpbGVkLCAKICAgICAgICAgICBuZXdfdHVtb3VyID0gbmV3X3R1bW9yX2V2ZW50X2FmdGVyX2luaXRpYWxfdHJlYXRtZW50LCAKICAgICAgICAgICBhbmF0b215X2Nvb3JkID0gYW5hdG9taWNfbmVvcGxhc21fc3ViZGl2aXNpb24sIAogICAgICAgICAgIHBhY2tfeXIgPSBudW1iZXJfcGFja195ZWFyc19zbW9rZWQsIAogICAgICAgICAgIHRvYmFjY28gPSB0b2JhY2NvX3Ntb2tpbmdfaGlzdG9yeSwgCiAgICAgICAgICAgcHJpb3JfY2FuY2VyID0gUHJpb3IuQ2FuY2VyLkRpYWdub3Npcy5PY2N1cmVuY2UsIAogICAgICAgICAgIG5lb2FkanV2YW50X3RoZXJhcHkgPSBoaXN0b3J5X29mX25lb2FkanV2YW50X3RyZWF0bWVudCwgCiAgICAgICAgICAgdGFyZ2V0ZWRfdGhlcmFweSA9IHRhcmdldGVkX21vbGVjdWxhcl90aGVyYXB5LCAKICAgICAgICAgICBwcmltYXJ5X291dGNvbWUgPSBwcmltYXJ5X3RoZXJhcHlfb3V0Y29tZV9zdWNjZXNzLCAKICAgICAgICAgICBzZWNvbmRsaW5lX291dGNvbWUgPSBmb2xsb3d1cF90cmVhdG1lbnRfc3VjY2VzcywgCiAgICAgICAgICAgbXV0YXRpb25fY291bnQgPSBNdXRhdGlvbi5Db3VudCwgCiAgICAgICAgICAgRkdBID0gRnJhY3Rpb24uR2Vub21lLkFsdGVyZWQsIAogICAgICAgICAgIFRNQiA9IFRNQi4ubm9uc3lub255bW91cy4sIAogICAgICAgICAgIG1pUk5BX2NsdXN0ZXIgPSBYX1BBTkNBTl9taVJOQV9QQU5DQU4sIAogICAgICAgICAgIG11dGF0aW9uX2NsdXN0ZXIgPSBYX1BBTkNBTl9tdXRhdGlvbl9QQU5DQU4pCiAgCiAgIyMgYWRkIHJvd25hbWVzIAogIHJvd25hbWVzKHRjZ2EpIDwtIGdzdWIoIi0iLCAiLiIsIHRjZ2Ekc2FtcGxlKQogIAogICMjIGFkZCB0aGUgY29weSBudW1iZXJzIHRvIGl0IAogIHRjZ2FfY25hIDwtIHJlYWQudGFibGUoIn4vTVJlc19wcm9qZWN0XzEvZG9jcy9HSVNUSUMyL3RjZ2EvbHVuZy9icm9hZF92YWx1ZXNfYnlfYXJtLnR4dCIsICAjIyByZWFkIGluIAogICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVCwgcm93Lm5hbWVzID0gMSkgJT4lIHQoKSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgY29sbmFtZXModGNnYV9jbmEpIDwtIHBhc3RlMCgiY2hyIiwgY29sbmFtZXModGNnYV9jbmEpKSAjIyBjaGFuZ2Ugcm93bmFtZXMgCiAgdGNnYSA8LSB0Y2dhW3Jvd25hbWVzKHRjZ2FfY25hKSwgXSAjIyBhbGlnbiAKICB0Y2dhIDwtIG1lcmdlKHRjZ2EsIHRjZ2FfY25hLCBieT0icm93Lm5hbWVzIikKICB0Y2dhJFJvdy5uYW1lcyA8LSBOVUxMCiAgCiAgIyMgY2hhbmdlIGFsbCBlbXB0eSBzdHJpbmdzIHRvIE5BIHZhbHVlcyAKICB0Y2dhIDwtIGxhcHBseSh0Y2dhLCBmdW5jdGlvbih4KSBpZmVsc2UoeCA9PSAiIiwgTkEsIHgpKQogIHRjZ2EgPC0gdGNnYSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgCiAgIyMgc2VsZWN0aXZlbHkgbXV0YXRlIHNvbWUgY29sdW1ucyAKICB0Y2dhJHNleCA8LSBpZmVsc2UodGNnYSRzZXggPT0gIk1BTEUiLCAxLCAwKSAjIyBtYWxlID0gMSwgZmVtYWxlID0gMAogIHRjZ2EkbmV3X3R1bW91ciA8LSBpZmVsc2UodGNnYSRuZXdfdHVtb3VyID09ICJZRVMiLCAxLCAwKSAjIyB5ZXMgPSAxLCBubyA9IDAKICB0Y2dhJHByaW9yX2NhbmNlciA8LSBpZmVsc2UodGNnYSRwcmlvcl9jYW5jZXIgPT0gIlllcyIsIDEsIDApICMjIHllcyA9IDEsIG5vID0gMAogIHRjZ2EkbmVvYWRqdXZhbnRfdGhlcmFweSA8LSBpZmVsc2UodGNnYSRuZW9hZGp1dmFudF90aGVyYXB5ID09ICJZZXMiLCAxLCAwKSAjIyB5ZXMgPSAxLCBubyA9IDAKICB0Y2dhJHRhcmdldGVkX3RoZXJhcHkgPC0gaWZlbHNlKHRjZ2EkdGFyZ2V0ZWRfdGhlcmFweSA9PSAiWUVTIiwgMSwgMCkgIyMgeWVzID0gMSwgbm8gPSAwCiAgdGNnYSRyYWRpYXRpb25fdGhlcmFweSA8LSBpZmVsc2UodGNnYSRyYWRpYXRpb25fdGhlcmFweSA9PSAiWUVTIiwgMSwgMCkgIyMgeWVzID0gMSwgbm8gPSAwCiAgdGNnYSA8LSB0Y2dhICU+JSBtdXRhdGUocHJpbWFyeV9vdXRjb21lID0gY2FzZV93aGVuKAogICAgcHJpbWFyeV9vdXRjb21lID09ICJDb21wbGV0ZSBSZW1pc3Npb24vUmVzcG9uc2UiIH4gMkwsCiAgICBwcmltYXJ5X291dGNvbWUgPT0gIlBhcnRpYWwgUmVtaXNzaW9uL1Jlc3BvbnNlIiB+IDFMLAogICAgcHJpbWFyeV9vdXRjb21lID09ICJTdGFibGUgRGlzZWFzZSIgfiAwTCwKICAgIHByaW1hcnlfb3V0Y29tZSA9PSAiUHJvZ3Jlc3NpdmUgRGlzZWFzZSIgfiAtMUwsCiAgICBUUlVFIH4gTkFfaW50ZWdlcl8KICApKQogIHRjZ2EgPC0gdGNnYSAlPiUgbXV0YXRlKHNlY29uZGxpbmVfb3V0Y29tZSA9IGNhc2Vfd2hlbigKICAgIHNlY29uZGxpbmVfb3V0Y29tZSA9PSAiQ29tcGxldGUgUmVtaXNzaW9uL1Jlc3BvbnNlIiB+IDJMLAogICAgc2Vjb25kbGluZV9vdXRjb21lID09ICJQYXJ0aWFsIFJlbWlzc2lvbi9SZXNwb25zZSIgfiAxTCwKICAgIHNlY29uZGxpbmVfb3V0Y29tZSA9PSAiU3RhYmxlIERpc2Vhc2UiIH4gMEwsCiAgICBzZWNvbmRsaW5lX291dGNvbWUgPT0gIlByb2dyZXNzaXZlIERpc2Vhc2UiIH4gLTFMLAogICAgVFJVRSB+IE5BX2ludGVnZXJfCiAgKSkKICB0Y2dhJHByaW1hcnlfcmVzcG9uc2UgPC0gaWZlbHNlKHRjZ2EkcHJpbWFyeV9vdXRjb21lID4gMCwgMSwgMCkgIyMgaWYgcHJpbWFyeSBvdXRjb21lIGlzIDEgb3IgMiwgdGhlbiByZXNwb25zZSA9IDEsIGVsc2UgMAogIHRjZ2Ekc2Vjb25kbGluZV9yZXNwb25zZSA8LSBpZmVsc2UodGNnYSRzZWNvbmRsaW5lX291dGNvbWUgPiAwLCAxLCAwKSAjIyBzYW1lIGxvZ2ljIGFzIGFib3ZlIAogIHRjZ2Ekc3RhZ2UgPC0gcm9tYW4yaW50KGdzdWIoIlN0YWdlXFxzfEF8QnxDfERpc2NyZXBhbmN5fFxcW3xcXF0iLCAiIiwgdGNnYSRzdGFnZSkpCiAgdGNnYSRwYXRob2xvZ2ljX00gPC0gZ3N1YigiTSIsICIiLCB0Y2dhJHBhdGhvbG9naWNfTSkgJT4lIGFzLm51bWVyaWMoKQogIHRjZ2EkcGF0aG9sb2dpY19OIDwtIGdzdWIoIk4iLCAiIiwgdGNnYSRwYXRob2xvZ2ljX04pICU+JSBhcy5udW1lcmljKCkKICB0Y2dhJHBhdGhvbG9naWNfVCA8LSBnc3ViKCJUIiwgIiIsIHRjZ2EkcGF0aG9sb2dpY19UKSAlPiUgYXMubnVtZXJpYygpCiAgdGNnYSRzYW1wbGVfdHlwZSA8LSBpZmVsc2UodGNnYSRzYW1wbGVfdHlwZSA9PSAiUHJpbWFyeSBUdW1vciIsIDAsIDEpICMjIHByaW1hcnkgdHVtb3VyID0gMCwgcmVjdXJyZW50ID0gMQogIHRjZ2EkcmVzaWR1YWxfdHVtb3IgPC0gaWZlbHNlKHRjZ2EkcmVzaWR1YWxfdHVtb3IgPT0gIlJYIiwgTkEsIHRjZ2EkcmVzaWR1YWxfdHVtb3IpCiAgdGNnYSRyZXNpZHVhbF90dW1vciA8LSBnc3ViKCJSIiwgIiIsIHRjZ2EkcmVzaWR1YWxfdHVtb3IpICU+JSBhcy5udW1lcmljKCkgIyMgUjAsIG5vIHJlc2lkdWFsOyBSMSwgbWljcm9zY29waWM7IFIyLCBtYWNyb3Njb3BpYwogIHRjZ2EkY2FuY2VyX3R5cGUgPC0gaWZlbHNlKHRjZ2EkY2FuY2VyX3R5cGUgPT0gIkx1bmcgQWRlbm9jYXJjaW5vbWEiLCAxLCAwKSAjIyAxID0gTFVBRCwgMCA9IExVU0MKICB0Y2dhJG1pUk5BX2NsdXN0ZXIgPC0gZ3N1YigibWlSTkEgY2x1c3RlciAiLCAiIiwgdGNnYSRtaVJOQV9jbHVzdGVyKSAlPiUgYXMubnVtZXJpYygpCiAgdGNnYSRtdXRhdGlvbl9jbHVzdGVyIDwtIGdzdWIoIm11dGF0aW9uIGNsdXN0ZXIgfG11dGF0aW9uIGMxdXN0ZXIgIiwgIiIsIHRjZ2EkbXV0YXRpb25fY2x1c3RlcikgJT4lIGFzLm51bWVyaWMoKQogIHRjZ2EkYW5hdG9teV9jb29yZCA8LSBnc3ViKCIgXFwocGxlYXNlIHNwZWNpZnlcXCl8XFxbRGlzY3JlcGFuY3lcXF0iLCAiIiwgdGNnYSRhbmF0b215X2Nvb3JkKQogIHRjZ2EkYW5hdG9teV9jb29yZCA8LSBpZmVsc2UodGNnYSRhbmF0b215X2Nvb3JkID09ICIiLCBOQSwgdGNnYSRhbmF0b215X2Nvb3JkKQogIAogICMjIGV4Y2VwdCBmb3IgY2hhcmFjdGVyIGNvbHVtbnMgbGlzdGVkLCBtYWtlIGV2ZXJ5IG90aGVyIGNvbHVtbiBudW1lcmljIAogIGNoYXJhY3Rlcl9jb2xzIDwtIGMoInNhbXBsZSIsICJhbmF0b215X2Nvb3JkIiwgImhpc3RvbG9naWNhbF90eXBlIikKICB0Y2dhWywgc2V0ZGlmZihjb2xuYW1lcyh0Y2dhKSwgY2hhcmFjdGVyX2NvbHMpXSA8LSBhcHBseSh0Y2dhWywgc2V0ZGlmZihjb2xuYW1lcyh0Y2dhKSwgY2hhcmFjdGVyX2NvbHMpXSwgMiwgYXMubnVtZXJpYykKCiAgIyMgc2F2ZSB0YWJsZSAKICB3cml0ZS50YWJsZSh0Y2dhLCAifi9NUmVzX3Byb2plY3RfMS9kb2NzLzAwX21pdMOpcmEvY2xpbmljYWwvcHJvY2Vzc2VkL2x1bmcvdGNnYV9jb21iaW5lZC50eHQiLCAKICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBULCByb3cubmFtZXMgPSBGLCBxdW90ZSA9IEYpCn0KYGBgCgpgYGB7ciBnZXRfY29sdW1uc30KdGNnYSA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvMDBfbWl0w6lyYS9jbGluaWNhbC9wcm9jZXNzZWQvbHVuZy90Y2dhX2NvbWJpbmVkLnR4dCIsIAogICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVFJVRSkKcm93bmFtZXModGNnYSkgPC0gdGNnYSRzYW1wbGUKCmNoYXJhY3Rlcl9jb2xzIDwtIGMoInNhbXBsZSIsICJhbmF0b215X2Nvb3JkIiwgImhpc3RvbG9naWNhbF90eXBlIikKc3Vydml2YWxfY29scyA8LSBjKCJPUyIsICJPUy50aW1lIiwgIkRTUyIsICJEU1MudGltZSIsICJERkkiLCAiREZJLnRpbWUiLCAiUEZJIiwgIlBGSS50aW1lIikKY25hX2NvbHMgPC0gY29sbmFtZXModGNnYSlbZ3JlcCgiXmNociIsIGNvbG5hbWVzKHRjZ2EpKV0KbnVtZXJpY19jb2xzIDwtIHNldGRpZmYoY29sbmFtZXModGNnYSksIGMoY2hhcmFjdGVyX2NvbHMsIHN1cnZpdmFsX2NvbHMsIGNuYV9jb2xzKSkKYGBgCgojIyMgQ29ob3J0IGNoYXJhY3RlcmlzdGljcy4gICAgIApgYGB7cn0KcGxvdF9saXN0IDwtIGxpc3QoKQpwbG90X2NvbHMgPC0gYygiYWdlIiwgInN0YWdlIiwgImxvbmdlc3RfZGltZW5zaW9uIiwgImludGVybWVkaWF0ZV9kaW1lbnNpb24iLCAic2hvcnRlc3RfZGltZW5zaW9uIiwgCiAgICAgICAgICAgICAicGFja195ciIsICJ0b2JhY2NvIiwgInNtb2tlX3lyIiwgIm11dGF0aW9uX2NvdW50IiwgIkZHQSIsICJUTUIiKQpmb3IgKGkgaW4gcGxvdF9jb2xzKSB7CiAgcCA8LSBnZ3Bsb3QodGNnYSwgYWVzX3N0cmluZyh4ID0gImFzLmZhY3RvcihzYW1wbGVfdHlwZSkiLCB5ID0gaSkpICsKICAgIGdlb21fdmlvbGluKHRyaW0gPSBGQUxTRSkgKwogICAgZ2d0aXRsZShwYXN0ZShpKSkgKyB4bGFiKCJzYW1wbGUgdHlwZSIpICsgCiAgICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiAgcGxvdF9saXN0W1tpXV0gPC0gcAp9CnBsb3RfZ3JpZCA8LSB3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbmNvbCA9IGZsb29yKHNxcnQobGVuZ3RoKHBsb3RfY29scykpKSkgCnBsb3RfZ3JpZApgYGAKCgojIyMgU3Vydml2YWwgQW5hbHlzaXMgICAgIAojIyMjIFVuaXZhcmlhdGUgQW5hbHlzaXMgICAgIApnaXZlbiBhIGxpc3Qgb2YgbnVtZXJpYyBjb2x1bW5zIGBudW1lcmljX2NvbHNgIHBlcmZvcm0gdW5pdmFyYWl0ZSBhbmFseXNpcyBvZiBhbGwgdGhlc2UgY29sdW1ucyBhZ2FpbnN0IHBhdGllbnQgc3Vydml2YWwgZ2l2ZW4gYXMgdGhpcyBmb3JtdWxhOiBgc3Vydl9vYmogPC0gU3Vydih0aW1lID0gdGNnYSRPUy50aW1lLCBldmVudCA9IHRjZ2EkT1MpYCBhbmQgc3RvcmUgdGhlIHJlc3VsdCBpbiBhIGRhdGFmcmFtZSBjYWxsZWQgYHVuaXZhcmF0ZWAgd2l0aCA1IGNvbHVtbnMgKGNvbHVtbiBuYW1lID0gSFIsIHVwcGVyXzk1LCBsb3dlcl85NSwgcF92YWx1ZSwgRkRSKSBhbmQgcm93bmFtZXMgYmVpbmcgbmFtZXMgZnJvbSBgbnVtZXJpY19jb2xzYC4gICAgCmBgYHtyIHVuaXZhcmlhdGVfYW5hbHlzaXN9CiMjIHVuaXZhcmlhdGUgYW5hbHlzaXMgb24gb3ZlcmFsbCBzdXJ2aXZhbCAKdW5pdmFyaWF0ZSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBsZW5ndGgobnVtZXJpY19jb2xzKSwgbmNvbCA9IDUpICU+JSBhcy5kYXRhLmZyYW1lKCkKY29sbmFtZXModW5pdmFyaWF0ZSkgPC0gYygiSFIiLCAidXBwZXJfOTUiLCAibG93ZXJfOTUiLCAicF92YWx1ZSIsICJGRFIiKQpyb3duYW1lcyh1bml2YXJpYXRlKSA8LSBudW1lcmljX2NvbHMKCmZvcihpIGluIG51bWVyaWNfY29scyl7CiAgdGVzdCA8LSBjb3hwaChTdXJ2KHRpbWU9T1MudGltZSwgZXZlbnQ9T1MpfnRjZ2FbLGldLCBkYXRhID0gdGNnYSkKICB0ZXN0IDwtIHN1bW1hcnkodGVzdCkKICAKICB1bml2YXJpYXRlW2ksICJIUiJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDJdCiAgdW5pdmFyaWF0ZVtpLCAicF92YWx1ZSJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDVdCiAgdW5pdmFyaWF0ZVtpLCAidXBwZXJfOTUiXSA8LSB0ZXN0JGNvbmYuaW50WzEsIDRdCiAgdW5pdmFyaWF0ZVtpLCAibG93ZXJfOTUiXSA8LSB0ZXN0JGNvbmYuaW50WzEsIDNdCn0KdW5pdmFyaWF0ZSRGRFIgPC0gcC5hZGp1c3QodW5pdmFyaWF0ZSRwX3ZhbHVlLCBtZXRob2QgPSAiZmRyIikKdW5pdmFyaWF0ZSRGRFIgPC0gcm91bmQodW5pdmFyaWF0ZSRGRFIsIGRpZ2l0cyA9IDQpCmBgYAoKIyMjIyBNdWx0aXZhcmlhdGUgYW5hbHlzaXMgICAgIApnaXZlbiBhIGxpc3Qgb2YgbnVtZXJpYyBjb2x1bW5zIGBjbmFfY29sc2AgcGVyZm9ybSBtdWx0aXZhcmlhdGUgYW5hbHlzaXMgb2YgYWxsIHRoZXNlIGNvbHVtbnMgYWdhaW5zdCBwYXRpZW50IHN1cnZpdmFsIGdpdmVuIGFzIHRoaXMgZm9ybXVsYTogYHN1cnZfb2JqIDwtIFN1cnYodGltZSA9IHRjZ2EkT1MudGltZSwgZXZlbnQgPSB0Y2dhJE9TKWAgd2l0aCBgYWdlYCwgYHN0YWdlYCwgYW5kIGBzZXhgIGFzIGluaXRpYWwgY292YXJpYXRlcyBhbmQgc3RvcmUgdGhlIHJlc3VsdCBpbiBhIGRhdGFmcmFtZSBjYWxsZWQgYG11bHRpdmFyaWF0ZV8xYCB3aXRoIDUgY29sdW1ucyAoY29sdW1uIG5hbWUgPSBIUiwgdXBwZXJfOTUsIGxvd2VyXzk1LCBwX3ZhbHVlLCBGRFIpIGFuZCByb3duYW1lcyBiZWluZyBuYW1lcyBmcm9tIGBjbmFfY29sc2AuICAgIApgYGB7ciBtdWx0aXZhcmlhdGVfMX0KIyMgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIG9uIG92ZXJhbGwgc3Vydml2YWwgCm11bHRpdmFyaWF0ZV8xIDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChjbmFfY29scyksIG5jb2wgPSA1KSAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbG5hbWVzKG11bHRpdmFyaWF0ZV8xKSA8LSBjKCJIUiIsICJ1cHBlcl85NSIsICJsb3dlcl85NSIsICJwX3ZhbHVlIiwgIkZEUiIpCnJvd25hbWVzKG11bHRpdmFyaWF0ZV8xKSA8LSBjbmFfY29scwoKZm9yKGkgaW4gY25hX2NvbHMpewogIHRlc3QgPC0gY294cGgoU3Vydih0aW1lPU9TLnRpbWUsIGV2ZW50PU9TKX50Y2dhWyxpXSthZ2Urc2V4K3N0YWdlLCBkYXRhID0gdGNnYSkKICB0ZXN0IDwtIHN1bW1hcnkodGVzdCkKICAKICBtdWx0aXZhcmlhdGVfMVtpLCAiSFIiXSA8LSB0ZXN0JGNvZWZmaWNpZW50c1sxLCAyXQogIG11bHRpdmFyaWF0ZV8xW2ksICJwX3ZhbHVlIl0gPC0gdGVzdCRjb2VmZmljaWVudHNbMSwgNV0KICBtdWx0aXZhcmlhdGVfMVtpLCAidXBwZXJfOTUiXSA8LSB0ZXN0JGNvbmYuaW50WzEsIDRdCiAgbXVsdGl2YXJpYXRlXzFbaSwgImxvd2VyXzk1Il0gPC0gdGVzdCRjb25mLmludFsxLCAzXQp9Cm11bHRpdmFyaWF0ZV8xJEZEUiA8LSBwLmFkanVzdChtdWx0aXZhcmlhdGVfMSRwX3ZhbHVlLCBtZXRob2QgPSAiZmRyIikKbXVsdGl2YXJpYXRlXzEkRkRSIDwtIHJvdW5kKG11bHRpdmFyaWF0ZV8xJEZEUiwgZGlnaXRzID0gNCkKbXVsdGl2YXJpYXRlXzEgPC0gbXVsdGl2YXJpYXRlXzEgJT4lIGRwbHlyOjphcnJhbmdlKHBfdmFsdWUpCmBgYAoKQmFzZWQgb24gdW5pdmFyaWF0ZSBhbmFseXNpcyB3ZSBpZGVudGlmaWVkIHRoZSBmb2xsb3dpbmcgZmFjdG9ycyBhcyBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBzdXJ2aXZhbCAoZmRyPDAuMDUpLiBidXQgdGhleSBkbyBub3QgbmVjZXNzYXJ5IGhhdmUgYmlvbG9naWNhbCBtZWFuaW5nLiAgICAgCmFkZGVkIGByZXNpZHVhbF90dW1vdXJgLCBgbmV3X3R1bW91cmAsIGFuZCBgcmFkaWF0aW9uX3RoZXJhcHlgIGFzIGNvdmFyaWF0ZSwgcmVtb3ZlIGBzZXhgIGZyb20gY292YXJpYXRlICAgIApgYGB7ciBtdWx0aXZhcmlhdGVfMn0KIyMgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIG9uIG92ZXJhbGwgc3Vydml2YWwgCm11bHRpdmFyaWF0ZV8yIDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChjbmFfY29scyksIG5jb2wgPSA1KSAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbG5hbWVzKG11bHRpdmFyaWF0ZV8yKSA8LSBjKCJIUiIsICJ1cHBlcl85NSIsICJsb3dlcl85NSIsICJwX3ZhbHVlIiwgIkZEUiIpCnJvd25hbWVzKG11bHRpdmFyaWF0ZV8yKSA8LSBjbmFfY29scwoKZm9yKGkgaW4gY25hX2NvbHMpewogIHRlc3QgPC0gY294cGgoU3Vydih0aW1lPU9TLnRpbWUsIGV2ZW50PU9TKX50Y2dhWyxpXSthZ2Urc3RhZ2UrcmVzaWR1YWxfdHVtb3IrbmV3X3R1bW91cityYWRpYXRpb25fdGhlcmFweSwgZGF0YSA9IHRjZ2EpCiAgdGVzdCA8LSBzdW1tYXJ5KHRlc3QpCiAgCiAgbXVsdGl2YXJpYXRlXzJbaSwgIkhSIl0gPC0gdGVzdCRjb2VmZmljaWVudHNbMSwgMl0KICBtdWx0aXZhcmlhdGVfMltpLCAicF92YWx1ZSJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDVdCiAgbXVsdGl2YXJpYXRlXzJbaSwgInVwcGVyXzk1Il0gPC0gdGVzdCRjb25mLmludFsxLCA0XQogIG11bHRpdmFyaWF0ZV8yW2ksICJsb3dlcl85NSJdIDwtIHRlc3QkY29uZi5pbnRbMSwgM10KfQptdWx0aXZhcmlhdGVfMiRGRFIgPC0gcC5hZGp1c3QobXVsdGl2YXJpYXRlXzIkcF92YWx1ZSwgbWV0aG9kID0gImZkciIpCm11bHRpdmFyaWF0ZV8yJEZEUiA8LSByb3VuZChtdWx0aXZhcmlhdGVfMiRGRFIsIGRpZ2l0cyA9IDQpCm11bHRpdmFyaWF0ZV8yIDwtIG11bHRpdmFyaWF0ZV8yICU+JSBkcGx5cjo6YXJyYW5nZShwX3ZhbHVlKQpgYGAKCk1heWJlIHNob3VsZCB3ZSBzZXBhcmF0ZSBMVUFEIGFuZCBMVVNDPyAKYGBge3Igc2VwYXJhdGVfc3VidHlwZXN9CmlmKCFmaWxlLmV4aXN0cygifi9NUmVzX3Byb2plY3RfMS9kb2NzLzAwX21pdMOpcmEvY2xpbmljYWwvcHJvY2Vzc2VkL2x1bmcvdGNnYV9sdWFkLnR4dCIpKXsKICB0Y2dhX2x1YWQgPC0gdGNnYSAlPiUgZmlsdGVyKGNhbmNlcl90eXBlID09IDEpCiAgdGNnYV9sdWFkX21zaSA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvMDBfbWl0w6lyYS9jbGluaWNhbC9yYXcvbHVuZy9sdWFkX01TSS50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVCkgJT4lIAogICAgZHBseXI6OnNlbGVjdChTYW1wbGUuSUQsIE1TSS5NQU5USVMuU2NvcmUpICU+JSAKICAgIGRwbHlyOjpyZW5hbWUoc2FtcGxlID0gU2FtcGxlLklELCBNU0kgPSBNU0kuTUFOVElTLlNjb3JlKQogIHRjZ2FfbHVhZF9hbmV1cGxvaWR5IDwtIHJlYWQudGFibGUoIn4vTVJlc19wcm9qZWN0XzEvZG9jcy8wMF9taXTDqXJhL2NsaW5pY2FsL3Jhdy9sdW5nL2x1YWRfYW5ldXBsb2lkeS50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIGhlYWRlciA9IFQpICU+JSAKICAgIGRwbHlyOjpzZWxlY3QoU2FtcGxlLklELCBBbmV1cGxvaWR5LlNjb3JlKSAlPiUgCiAgICBkcGx5cjo6cmVuYW1lKHNhbXBsZSA9IFNhbXBsZS5JRCwgYW5ldXBsb2lkeSA9IEFuZXVwbG9pZHkuU2NvcmUpCiAgdGNnYV9sdWFkIDwtIGxlZnRfam9pbih0Y2dhX2x1YWQsIHRjZ2FfbHVhZF9tc2ksIGJ5PSJzYW1wbGUiKQogIHRjZ2FfbHVhZCA8LSBsZWZ0X2pvaW4odGNnYV9sdWFkLCB0Y2dhX2x1YWRfYW5ldXBsb2lkeSwgYnk9InNhbXBsZSIpCiAgd3JpdGUudGFibGUodGNnYV9sdWFkLCBmaWxlID0gIn4vTVJlc19wcm9qZWN0XzEvZG9jcy8wMF9taXTDqXJhL2NsaW5pY2FsL3Byb2Nlc3NlZC9sdW5nL3RjZ2FfbHVhZC50eHQiLCAKICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBxdW90ZSA9IEYsIGNvbC5uYW1lcyA9IFQsIHJvdy5uYW1lcyA9IEYpCn0KCmlmKCFmaWxlLmV4aXN0cygifi9NUmVzX3Byb2plY3RfMS9kb2NzLzAwX21pdMOpcmEvY2xpbmljYWwvcHJvY2Vzc2VkL2x1bmcvdGNnYV9sdXNjLnR4dCIpKXsKICB0Y2dhX2x1c2MgPC0gdGNnYSAlPiUgZmlsdGVyKGNhbmNlcl90eXBlID09IDApCiAgdGNnYV9sdXNjX21zaSA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvMDBfbWl0w6lyYS9jbGluaWNhbC9yYXcvbHVuZy9sdXNjX01TSS50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgaGVhZGVyID0gVCkgJT4lIAogICAgZHBseXI6OnNlbGVjdChTYW1wbGUuSUQsIE1TSS5NQU5USVMuU2NvcmUpICU+JSAKICAgIGRwbHlyOjpyZW5hbWUoc2FtcGxlID0gU2FtcGxlLklELCBNU0kgPSBNU0kuTUFOVElTLlNjb3JlKQogIHRjZ2FfbHVzYyA8LSBsZWZ0X2pvaW4odGNnYV9sdXNjLCB0Y2dhX2x1c2NfbXNpLCBieT0ic2FtcGxlIikKICB3cml0ZS50YWJsZSh0Y2dhX2x1c2MsIGZpbGUgPSAifi9NUmVzX3Byb2plY3RfMS9kb2NzLzAwX21pdMOpcmEvY2xpbmljYWwvcHJvY2Vzc2VkL2x1bmcvdGNnYV9sdXNjLnR4dCIsIAogICAgICAgICAgICAgIHNlcCA9ICJcdCIsIHF1b3RlID0gRiwgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gRikKfQpgYGAKCk11bHRpdmFyaWF0ZSBhbmFseXNpcyBmb3IgTFVBRCByZWdyZXNzaW5nIG91dCBgYWdlYCwgYHN0YWdlYCwgYW5kIGBzZXhgLiAgICAgICAgIApgYGB7ciBsdWFkX211bHRpdmFyaWF0ZV8xfQp0Y2dhX2x1YWQgPC0gcmVhZC50YWJsZSgifi9NUmVzX3Byb2plY3RfMS9kb2NzLzAwX21pdMOpcmEvY2xpbmljYWwvcHJvY2Vzc2VkL2x1bmcvdGNnYV9sdWFkLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLCBoZWFkZXIgPSBUKQpyb3duYW1lcyh0Y2dhX2x1YWQpIDwtIHRjZ2FfbHVhZCRzYW1wbGUKCiMjIG11bHRpdmFyaWF0ZSBhbmFseXNpcyBvbiBvdmVyYWxsIHN1cnZpdmFsIHdpdGggbHVhZApsdWFkIDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChjbmFfY29scyksIG5jb2wgPSA1KSAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbG5hbWVzKGx1YWQpIDwtIGMoIkhSIiwgInVwcGVyXzk1IiwgImxvd2VyXzk1IiwgInBfdmFsdWUiLCAiRkRSIikKcm93bmFtZXMobHVhZCkgPC0gY25hX2NvbHMKCmZvcihpIGluIGNuYV9jb2xzKXsKICB0ZXN0IDwtIGNveHBoKFN1cnYodGltZT1PUy50aW1lLCBldmVudD1PUyl+dGNnYV9sdWFkWyxpXSthZ2Urc3RhZ2Urc2V4LCBkYXRhID0gdGNnYV9sdWFkKQogIHRlc3QgPC0gc3VtbWFyeSh0ZXN0KQogIAogIGx1YWRbaSwgIkhSIl0gPC0gdGVzdCRjb2VmZmljaWVudHNbMSwgMl0KICBsdWFkW2ksICJwX3ZhbHVlIl0gPC0gdGVzdCRjb2VmZmljaWVudHNbMSwgNV0KICBsdWFkW2ksICJ1cHBlcl85NSJdIDwtIHRlc3QkY29uZi5pbnRbMSwgNF0KICBsdWFkW2ksICJsb3dlcl85NSJdIDwtIHRlc3QkY29uZi5pbnRbMSwgM10KfQpsdWFkJEZEUiA8LSBwLmFkanVzdChsdWFkJHBfdmFsdWUsIG1ldGhvZCA9ICJmZHIiKQpsdWFkJEZEUiA8LSByb3VuZChsdWFkJEZEUiwgZGlnaXRzID0gNCkKbHVhZCA8LSBsdWFkICU+JSBkcGx5cjo6YXJyYW5nZShwX3ZhbHVlKQpgYGAKCmBgYHtyIGx1c2NfbXVsdGl2YXRpYXRlXzF9CnRjZ2FfbHVzYyA8LSByZWFkLnRhYmxlKCJ+L01SZXNfcHJvamVjdF8xL2RvY3MvMDBfbWl0w6lyYS9jbGluaWNhbC9wcm9jZXNzZWQvbHVuZy90Y2dhX2x1c2MudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIGhlYWRlciA9IFQpCgojIyBtdWx0aXZhcmlhdGUgYW5hbHlzaXMgb24gb3ZlcmFsbCBzdXJ2aXZhbCB3aXRoIGx1c2MKbHVzYyA8LSBtYXRyaXgoTkEsIG5yb3cgPSBsZW5ndGgoY25hX2NvbHMpLCBuY29sID0gNSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpjb2xuYW1lcyhsdXNjKSA8LSBjKCJIUiIsICJ1cHBlcl85NSIsICJsb3dlcl85NSIsICJwX3ZhbHVlIiwgIkZEUiIpCnJvd25hbWVzKGx1c2MpIDwtIGNuYV9jb2xzCgpmb3IoaSBpbiBjbmFfY29scyl7CiAgdGVzdCA8LSBjb3hwaChTdXJ2KHRpbWU9T1MudGltZSwgZXZlbnQ9T1MpfnRjZ2FfbHVzY1ssaV0rYWdlK3N0YWdlK3NleCwgZGF0YSA9IHRjZ2FfbHVzYykKICB0ZXN0IDwtIHN1bW1hcnkodGVzdCkKICAKICBsdXNjW2ksICJIUiJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDJdCiAgbHVzY1tpLCAicF92YWx1ZSJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDVdCiAgbHVzY1tpLCAidXBwZXJfOTUiXSA8LSB0ZXN0JGNvbmYuaW50WzEsIDRdCiAgbHVzY1tpLCAibG93ZXJfOTUiXSA8LSB0ZXN0JGNvbmYuaW50WzEsIDNdCn0KbHVzYyRGRFIgPC0gcC5hZGp1c3QobHVzYyRwX3ZhbHVlLCBtZXRob2QgPSAiZmRyIikKbHVzYyRGRFIgPC0gcm91bmQobHVzYyRGRFIsIGRpZ2l0cyA9IDQpCmx1c2MgPC0gbHVzYyAlPiUgZHBseXI6OmFycmFuZ2UocF92YWx1ZSkKCmBgYAoKQWZ0ZXIgZXhwZXJpbWVudGluZywgdGhlIHRvcCBoaXQgY2hyb21vc29tZXMgYXJlIHF1aXRlIGRpZmZlcmVudCBpbiB0aGUgdHdvIGRhdGFzZXRzLCBsZXQncyBmaXJzdCBmb2N1cyBvbiBsdW5nIGFkZW5vY2FyY2lub21hLiBDb3ZhcmlhdGUgcmVncmVzaW5nIG91dCBgYWdlYCwgYHN0YWdlYCwgYHNleGAsIGBwYWNrX3lyYCwgYHRvYmFjY29gLCBgRkdBYCwgYG11dGF0aW9uX2NvdW50YCwgYW5kIGBUTUJgLiBgYWdlYCwgYHN0YWdlYCwgYW5kIGBzZXhgIGFyZSByZWdyZXNzZWQgb3V0IGEgcyBwZXJzb25hbCBpbmZvcm1hdGlvbiwgYHBhY2tfeXJgIGFuZCBgdG9iYWNjb2AgYXJlIHJlZ3Jlc3NlZCBvdXQgYmVjYXVzZSBzbW9raW5nIGlzIHNob3duIHRvIGNvcnJlbGF0ZWQgd2l0aCBsdW5nIGNhbmNlciB0dW1vcmlnZW5lc2lzIGFuZCBzdXJ2aXZhbCBhZHZhbnRhZ2UuIGBGR0FgLCBgbXV0YXRpb25fY291bnRgIGFuZCBgVE1CYCBhcmUgcmVncmVzc2VkIG91dCBiZWNhdXNlIHRoZXkgYXJlIHNob3duIHRvIGhhdmUgcHJvZ25vc3RpYyB2YWx1ZSBpbiBvdGhlciBzdHVkaWVzLiAgIApGaXJzdCwgbGV0J3MgbG9vayBhdCBsdW5nIGFkZW5vY2FyY2lub21hICAgICAKYGBge3IgbHVhZF9tdWx0aXZhdGlhdGVfMn0KIyMgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIG9uIG92ZXJhbGwgc3Vydml2YWwgd2l0aCBsdWFkCmx1YWRfMiA8LSBtYXRyaXgoTkEsIG5yb3cgPSBsZW5ndGgoY25hX2NvbHMpLCBuY29sID0gNSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpjb2xuYW1lcyhsdWFkXzIpIDwtIGMoIkhSIiwgInVwcGVyXzk1IiwgImxvd2VyXzk1IiwgInBfdmFsdWUiLCAiRkRSIikKcm93bmFtZXMobHVhZF8yKSA8LSBjbmFfY29scwoKZm9yKGkgaW4gY25hX2NvbHMpewogIHRlc3QgPC0gY294cGgoU3Vydih0aW1lPU9TLnRpbWUsIGV2ZW50PU9TKX50Y2dhX2x1YWRbLGldK2FnZStzdGFnZStzZXgrcGFja195cit0b2JhY2NvK0ZHQSttdXRhdGlvbl9jb3VudCtUTUIsIGRhdGEgPSB0Y2dhX2x1YWQpCiAgdGVzdCA8LSBzdW1tYXJ5KHRlc3QpCiAgCiAgbHVhZF8yW2ksICJIUiJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDJdCiAgbHVhZF8yW2ksICJwX3ZhbHVlIl0gPC0gdGVzdCRjb2VmZmljaWVudHNbMSwgNV0KICBsdWFkXzJbaSwgInVwcGVyXzk1Il0gPC0gdGVzdCRjb25mLmludFsxLCA0XQogIGx1YWRfMltpLCAibG93ZXJfOTUiXSA8LSB0ZXN0JGNvbmYuaW50WzEsIDNdCn0KbHVhZF8yJEZEUiA8LSBwLmFkanVzdChsdWFkXzIkcF92YWx1ZSwgbWV0aG9kID0gImZkciIpCmx1YWRfMiRGRFIgPC0gcm91bmQobHVhZF8yJEZEUiwgZGlnaXRzID0gNCkKbHVhZF8yIDwtIGx1YWRfMiAlPiUgZHBseXI6OmFycmFuZ2UocF92YWx1ZSkKYGBgCgpOZXh0IGxvb2sgYXQgbHVuZyBzcXVhbW91cyBjZWxsIGNhcmNpbm9tYS4gICAgICAgIApgYGB7ciBsdXNjX211bHRpdmF0aWF0ZV8yfQojIyBtdWx0aXZhcmlhdGUgYW5hbHlzaXMgb24gb3ZlcmFsbCBzdXJ2aXZhbCB3aXRoIGx1YWQKbHVzY18yIDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChjbmFfY29scyksIG5jb2wgPSA1KSAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvbG5hbWVzKGx1c2NfMikgPC0gYygiSFIiLCAidXBwZXJfOTUiLCAibG93ZXJfOTUiLCAicF92YWx1ZSIsICJGRFIiKQpyb3duYW1lcyhsdXNjXzIpIDwtIGNuYV9jb2xzCgpmb3IoaSBpbiBjbmFfY29scyl7CiAgdGVzdCA8LSBjb3hwaChTdXJ2KHRpbWU9T1MudGltZSwgZXZlbnQ9T1MpfnRjZ2FfbHVzY1ssaV0rYWdlK3N0YWdlK3NleCtwYWNrX3lyK3RvYmFjY28rRkdBK211dGF0aW9uX2NvdW50K1RNQiwgCiAgICAgICAgICAgICAgICBkYXRhID0gdGNnYV9sdXNjKQogIHRlc3QgPC0gc3VtbWFyeSh0ZXN0KQogIAogIGx1c2NfMltpLCAiSFIiXSA8LSB0ZXN0JGNvZWZmaWNpZW50c1sxLCAyXQogIGx1c2NfMltpLCAicF92YWx1ZSJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDVdCiAgbHVzY18yW2ksICJ1cHBlcl85NSJdIDwtIHRlc3QkY29uZi5pbnRbMSwgNF0KICBsdXNjXzJbaSwgImxvd2VyXzk1Il0gPC0gdGVzdCRjb25mLmludFsxLCAzXQp9Cmx1c2NfMiRGRFIgPC0gcC5hZGp1c3QobHVzY18yJHBfdmFsdWUsIG1ldGhvZCA9ICJmZHIiKQpsdXNjXzIkRkRSIDwtIHJvdW5kKGx1c2NfMiRGRFIsIGRpZ2l0cyA9IDQpCmx1c2NfMiA8LSBsdXNjXzIgJT4lIGRwbHlyOjphcnJhbmdlKHBfdmFsdWUpCmBgYAoKTGFzdGx5LCBhcHBseSB0aGUgY292YXJpYXRlcyB0byBjb21wbGV0ZSBsdW5nIGNhbmNlciBkYXRhc2V0LiAgICAKYGBge3IgbXVsdGl2YXJpYXRlXzN9CiMjIG11bHRpdmFyaWF0ZSBhbmFseXNpcyBvbiBvdmVyYWxsIHN1cnZpdmFsIAptdWx0aXZhcmlhdGVfMyA8LSBtYXRyaXgoTkEsIG5yb3cgPSBsZW5ndGgoY25hX2NvbHMpLCBuY29sID0gNSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpjb2xuYW1lcyhtdWx0aXZhcmlhdGVfMykgPC0gYygiSFIiLCAidXBwZXJfOTUiLCAibG93ZXJfOTUiLCAicF92YWx1ZSIsICJGRFIiKQpyb3duYW1lcyhtdWx0aXZhcmlhdGVfMykgPC0gY25hX2NvbHMKCmZvcihpIGluIGNuYV9jb2xzKXsKICB0ZXN0IDwtIGNveHBoKFN1cnYodGltZT1PUy50aW1lLCBldmVudD1PUyl+dGNnYVssaV0rYWdlK3N0YWdlK3NleCtwYWNrX3lyK3RvYmFjY28rRkdBK211dGF0aW9uX2NvdW50K1RNQiwgZGF0YSA9IHRjZ2EpCiAgdGVzdCA8LSBzdW1tYXJ5KHRlc3QpCiAgCiAgbXVsdGl2YXJpYXRlXzNbaSwgIkhSIl0gPC0gdGVzdCRjb2VmZmljaWVudHNbMSwgMl0KICBtdWx0aXZhcmlhdGVfM1tpLCAicF92YWx1ZSJdIDwtIHRlc3QkY29lZmZpY2llbnRzWzEsIDVdCiAgbXVsdGl2YXJpYXRlXzNbaSwgInVwcGVyXzk1Il0gPC0gdGVzdCRjb25mLmludFsxLCA0XQogIG11bHRpdmFyaWF0ZV8zW2ksICJsb3dlcl85NSJdIDwtIHRlc3QkY29uZi5pbnRbMSwgM10KfQptdWx0aXZhcmlhdGVfMyRGRFIgPC0gcC5hZGp1c3QobXVsdGl2YXJpYXRlXzMkcF92YWx1ZSwgbWV0aG9kID0gImZkciIpCm11bHRpdmFyaWF0ZV8zJEZEUiA8LSByb3VuZChtdWx0aXZhcmlhdGVfMyRGRFIsIGRpZ2l0cyA9IDQpCm11bHRpdmFyaWF0ZV8zIDwtIG11bHRpdmFyaWF0ZV8zICU+JSBkcGx5cjo6YXJyYW5nZShwX3ZhbHVlKQpgYGAKCiMjIyMgVmlzdWFsaXNlIHRoZSBjaHJvbW9zb21lIGFybSBzdGF0dXMgaW4gVENHQSBjYW5jZXIgICAgICAKSW4gYWxsIGx1bmcgY2FuY2VyICAgICAgICAgICAgICAgIApgYGB7ciBjbmFfc3RhdHVzX2x1bmd9CiMjIGluIGFsbCBsdW5nIGNhbmNlciBzYW1wbGVzIApjbmFfc3RhdHVzIDwtIG1hdHJpeChOQSwgbnJvdyA9IDEsIG5jb2wgPSAzKQpjb2xuYW1lcyhjbmFfc3RhdHVzKSA8LSBjKCJhbXAiLCAiZGVsIiwgInd0IikKCmZvcihpIGluIGNuYV9jb2xzKXsKICB0YWJsZSA8LSBpZmVsc2UodGNnYVtpXT4wLCAiYW1wIiwgaWZlbHNlKHRjZ2FbaV0gPCAwLCAiZGVsIiwgInd0IikpICU+JSB0YWJsZSgpICU+JSB0KCkgCiAgY25hX3N0YXR1cyA8LSByYmluZChjbmFfc3RhdHVzLCB0YWJsZSkKfQpjbmFfc3RhdHVzIDwtIGNuYV9zdGF0dXNbMjpucm93KGNuYV9zdGF0dXMpLCBdICU+JSBhcy5kYXRhLmZyYW1lKCkKcm93bmFtZXMoY25hX3N0YXR1cykgPC0gY25hX2NvbHMKClJvd19TdW1zIDwtIHJvd1N1bXMoY25hX3N0YXR1cykKY25hX3N0YXR1cyA8LSBzd2VlcCh4ID0gY25hX3N0YXR1cywgTUFSR0lOID0gMSwgU1RBVFMgPSBSb3dfU3VtcywgRlVOID0gIi8iKSAjIyBjYWxjdWxhdGUgZnJhY3Rpb24gCmNuYV9zdGF0dXMgPC0gY25hX3N0YXR1cyAqIDEwMCAjIyBpbnRvIHBlcmNlbnRhZ2UgCgpjbmFfc3RhdHVzJGNocl9hcm1zIDwtIGNuYV9jb2xzCgojIyBzdGFjayBiYXIgcGxvdCAKY25hX3N0YXR1c19sb25nIDwtIGNuYV9zdGF0dXMgJT4lIHBpdm90X2xvbmdlcihjb2xzID0gYW1wOnd0LCBuYW1lc190byA9ICJNdXRhdGlvbiIsIHZhbHVlc190byA9ICJQZXJjZW50YWdlIikKCiMgQ3JlYXRlIGEgc3RhY2tlZCBiYXIgcGxvdApwMSA8LSBnZ3Bsb3QoY25hX3N0YXR1c19sb25nLCBhZXMoeCA9IGNocl9hcm1zLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IE11dGF0aW9uKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKSsKICBsYWJzKHggPSAiY2hyb21vc29tZSBhcm1zIiwgeSA9ICJQZXJjZW50YWdlIikgKyB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLCAKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKyAKICBnZ3RpdGxlKCJjaHJfYXJtIHN0YXR1cyBpbiBUQ0dBIGx1bmcgY2FuY2VyIikKYGBgCgpJbiBsdW5nIGFkZW5vY2FyY2lub21hICAgICAgICAgICAgICAgIApgYGB7ciBjbmFfc3RhdHVzX2x1YWR9CiMjIGluIGFsbCBsdW5nIGNhbmNlciBzYW1wbGVzIApjbmFfc3RhdHVzIDwtIG1hdHJpeChOQSwgbnJvdyA9IDEsIG5jb2wgPSAzKQpjb2xuYW1lcyhjbmFfc3RhdHVzKSA8LSBjKCJhbXAiLCAiZGVsIiwgInd0IikKCmZvcihpIGluIGNuYV9jb2xzKXsKICB0YWJsZSA8LSBpZmVsc2UodGNnYV9sdWFkW2ldPjAsICJhbXAiLCBpZmVsc2UodGNnYV9sdWFkW2ldIDwgMCwgImRlbCIsICJ3dCIpKSAlPiUgdGFibGUoKSAlPiUgdCgpIAogIGNuYV9zdGF0dXMgPC0gcmJpbmQoY25hX3N0YXR1cywgdGFibGUpCn0KY25hX3N0YXR1cyA8LSBjbmFfc3RhdHVzWzI6bnJvdyhjbmFfc3RhdHVzKSwgXSAlPiUgYXMuZGF0YS5mcmFtZSgpCnJvd25hbWVzKGNuYV9zdGF0dXMpIDwtIGNuYV9jb2xzCgpSb3dfU3VtcyA8LSByb3dTdW1zKGNuYV9zdGF0dXMpCmNuYV9zdGF0dXMgPC0gc3dlZXAoeCA9IGNuYV9zdGF0dXMsIE1BUkdJTiA9IDEsIFNUQVRTID0gUm93X1N1bXMsIEZVTiA9ICIvIikgIyMgY2FsY3VsYXRlIGZyYWN0aW9uIApjbmFfc3RhdHVzIDwtIGNuYV9zdGF0dXMgKiAxMDAgIyMgaW50byBwZXJjZW50YWdlIAoKY25hX3N0YXR1cyRjaHJfYXJtcyA8LSBjbmFfY29scwoKIyMgc3RhY2sgYmFyIHBsb3QgCmNuYV9zdGF0dXNfbG9uZyA8LSBjbmFfc3RhdHVzICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGFtcDp3dCwgbmFtZXNfdG8gPSAiTXV0YXRpb24iLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSIpCgojIENyZWF0ZSBhIHN0YWNrZWQgYmFyIHBsb3QKcDIgPC0gZ2dwbG90KGNuYV9zdGF0dXNfbG9uZywgYWVzKHggPSBjaHJfYXJtcywgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBNdXRhdGlvbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkrCiAgbGFicyh4ID0gImNocm9tb3NvbWUgYXJtcyIsIHkgPSAiUGVyY2VudGFnZSIpICsgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwgCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsgCiAgZ2d0aXRsZSgiY2hyX2FybSBzdGF0dXMgaW4gVENHQSBMVUFEIikKYGBgCgpJbiBsdW5nIHNxdWFtb3VzIGNlbGwgY2FyY2lub21hICAgICAgIApgYGB7ciBjbmFfc3RhdHVzX2x1c2N9CiMjIGluIGFsbCBsdW5nIGNhbmNlciBzYW1wbGVzIApjbmFfc3RhdHVzIDwtIG1hdHJpeChOQSwgbnJvdyA9IDEsIG5jb2wgPSAzKQpjb2xuYW1lcyhjbmFfc3RhdHVzKSA8LSBjKCJhbXAiLCAiZGVsIiwgInd0IikKCmZvcihpIGluIGNuYV9jb2xzKXsKICB0YWJsZSA8LSBpZmVsc2UodGNnYV9sdXNjW2ldPjAsICJhbXAiLCBpZmVsc2UodGNnYV9sdXNjW2ldIDwgMCwgImRlbCIsICJ3dCIpKSAlPiUgdGFibGUoKSAlPiUgdCgpIAogIGNuYV9zdGF0dXMgPC0gcmJpbmQoY25hX3N0YXR1cywgdGFibGUpCn0KY25hX3N0YXR1cyA8LSBjbmFfc3RhdHVzWzI6bnJvdyhjbmFfc3RhdHVzKSwgXSAlPiUgYXMuZGF0YS5mcmFtZSgpCnJvd25hbWVzKGNuYV9zdGF0dXMpIDwtIGNuYV9jb2xzCgpSb3dfU3VtcyA8LSByb3dTdW1zKGNuYV9zdGF0dXMpCmNuYV9zdGF0dXMgPC0gc3dlZXAoeCA9IGNuYV9zdGF0dXMsIE1BUkdJTiA9IDEsIFNUQVRTID0gUm93X1N1bXMsIEZVTiA9ICIvIikgIyMgY2FsY3VsYXRlIGZyYWN0aW9uIApjbmFfc3RhdHVzIDwtIGNuYV9zdGF0dXMgKiAxMDAgIyMgaW50byBwZXJjZW50YWdlIAoKY25hX3N0YXR1cyRjaHJfYXJtcyA8LSBjbmFfY29scwoKIyMgc3RhY2sgYmFyIHBsb3QgCmNuYV9zdGF0dXNfbG9uZyA8LSBjbmFfc3RhdHVzICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGFtcDp3dCwgbmFtZXNfdG8gPSAiTXV0YXRpb24iLCB2YWx1ZXNfdG8gPSAiUGVyY2VudGFnZSIpCgojIENyZWF0ZSBhIHN0YWNrZWQgYmFyIHBsb3QKcDMgPC0gZ2dwbG90KGNuYV9zdGF0dXNfbG9uZywgYWVzKHggPSBjaHJfYXJtcywgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBNdXRhdGlvbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkrCiAgbGFicyh4ID0gImNocm9tb3NvbWUgYXJtcyIsIHkgPSAiUGVyY2VudGFnZSIpICsgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwgCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsgCiAgZ2d0aXRsZSgiY2hyX2FybSBzdGF0dXMgaW4gVENHQSBMVVNDIikKYGBgCgojIyMjIEZvcmVzdCBwbG90LiAgICAgCmBgYHtyIGZvcmVzdF9wbG90c30KbXVsdGl2YXJpYXRlXzMkSW5kZXggPC0gZmFjdG9yKHJvd25hbWVzKG11bHRpdmFyaWF0ZV8zKSwgbGV2ZWxzID0gcm93bmFtZXMobXVsdGl2YXJpYXRlXzMpKQpwNCA8LSBnZ3Bsb3QobXVsdGl2YXJpYXRlXzMsIGFlcyh4ID0gSW5kZXgsIHkgPSBIUikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBsb3dlcl85NSwgeW1heCA9IHVwcGVyXzk1KSwgd2lkdGggPSAwLjIpICsKICBjb29yZF9mbGlwKCkgKyAjIEZsaXAgY29vcmRpbmF0ZXMgdG8gbWFrZSBpdCBhIHRyYWRpdGlvbmFsIGZvcmVzdCBwbG90IGxheW91dAogIHRoZW1lX2J3KCkgKwogIGxhYnMoeSA9ICJsb2cxMCBIYXphcmQgUmF0aW8gKEhSKSIsIHggPSAiQ2hyb21vc29tZSBBcm1zIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpICsgCiAgZ2d0aXRsZSgiVENHQSBMdW5nIENhbmNlciIpICsgeWxpbShmbG9vcihtaW4obXVsdGl2YXJpYXRlXzMkbG93ZXJfOTUpKSwgY2VpbGluZyhtYXgobXVsdGl2YXJpYXRlXzMkdXBwZXJfOTUpKSkgKyAKICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpCgpsdWFkXzIkSW5kZXggPC0gZmFjdG9yKHJvd25hbWVzKGx1YWRfMiksIGxldmVscyA9IHJvd25hbWVzKGx1YWRfMikpCnA1IDwtIGdncGxvdChsdWFkXzIsIGFlcyh4ID0gSW5kZXgsIHkgPSBIUikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBsb3dlcl85NSwgeW1heCA9IHVwcGVyXzk1KSwgd2lkdGggPSAwLjIpICsKICBjb29yZF9mbGlwKCkgKyAjIEZsaXAgY29vcmRpbmF0ZXMgdG8gbWFrZSBpdCBhIHRyYWRpdGlvbmFsIGZvcmVzdCBwbG90IGxheW91dAogIHRoZW1lX2J3KCkgKwogIGxhYnMoeSA9ICJsb2cxMCBIYXphcmQgUmF0aW8gKEhSKSIsIHggPSAiQ2hyb21vc29tZSBBcm1zIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpICsgCiAgZ2d0aXRsZSgiVENHQSBMVUFEIikgKyB5bGltKGZsb29yKG1pbihsdWFkXzIkbG93ZXJfOTUpKSwgY2VpbGluZyhtYXgobHVhZF8yJHVwcGVyXzk1KSkpICsgCiAgdGhlbWUodGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKQoKbHVzY18yJEluZGV4IDwtIGZhY3Rvcihyb3duYW1lcyhsdXNjXzIpLCBsZXZlbHMgPSByb3duYW1lcyhsdXNjXzIpKQpwNiA8LSBnZ3Bsb3QobHVzY18yLCBhZXMoeCA9IEluZGV4LCB5ID0gSFIpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXJfOTUsIHltYXggPSB1cHBlcl85NSksIHdpZHRoID0gMC4yKSArCiAgY29vcmRfZmxpcCgpICsgIyBGbGlwIGNvb3JkaW5hdGVzIHRvIG1ha2UgaXQgYSB0cmFkaXRpb25hbCBmb3Jlc3QgcGxvdCBsYXlvdXQKICB0aGVtZV9idygpICsKICBsYWJzKHkgPSAibG9nMTAgSGF6YXJkIFJhdGlvIChIUikiLCB4ID0gIkNocm9tb3NvbWUgQXJtcyIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxKSArIAogIGdndGl0bGUoIlRDR0EgTFVTQyIpICsgeWxpbShmbG9vcihtaW4obHVzY18yJGxvd2VyXzk1KSksIGNlaWxpbmcobWF4KGx1c2NfMiR1cHBlcl85NSkpKSArIAogIHRoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkKYGBgCgojIyMjIEthcGxhbiBNZWllciBQbG90ICAgICAgCmBgYHtyIGthcGxhbk1laWVyX2x1YWR9CnRjZ2FfbHVhZCRjaHIxNXFTdGF0dXMgPC0gaWZlbHNlKHRjZ2FfbHVhZCRjaHIxNXEgPiAwLCAiYW1wIiwgInd0IikKdGNnYV9sdWFkJGNocjIycVN0YXR1cyA8LSBpZmVsc2UodGNnYV9sdWFkJGNocjIycSA+IDAsICJhbXAiLCAid3QiKQoKZml0IDwtIHN1cnZmaXQoU3VydihPUy50aW1lLCBPUykgfiBhcy5mYWN0b3IoY2hyMjJxU3RhdHVzKSwgZGF0YSA9IHRjZ2FfbHVhZCkKcDcgPC0gZ2dzdXJ2cGxvdF9jdXN0b21pc2VkKGZpdF9mdW5jdGlvbiA9IGZpdCwgZGF0YWZyYW1lID0gdGNnYV9sdWFkLCBwdmFsX2Nvb3JkID0gYygzNTAwLCAwLjc1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha190aW1lX2J5ID0gMTAwMCwgbGVnZW5kX2xhYnMgPSBjKCJhbXAiLCAid3QiKSwgcC52YWxfbWV0aG9kID0gIjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkthcGxhbi1NZWllciBDdXJ2ZSBmb3IgVENHQSBMVUFEIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJzdXJ2aXZhbCA9IE9TLCBzdWJ0eXBlID0gTFVBRCwgbiA9IDUwMiwgY2hyX2FybSA9IDIycSIpCgpmaXQgPC0gc3VydmZpdChTdXJ2KE9TLnRpbWUsIE9TKSB+IGFzLmZhY3RvcihjaHIxNXFTdGF0dXMpLCBkYXRhID0gdGNnYV9sdWFkKQpwOCA8LSBnZ3N1cnZwbG90X2N1c3RvbWlzZWQoZml0X2Z1bmN0aW9uID0gZml0LCBkYXRhZnJhbWUgPSB0Y2dhX2x1YWQsIHB2YWxfY29vcmQgPSBjKDM1MDAsIDAuNzUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrX3RpbWVfYnkgPSAxMDAwLCBsZWdlbmRfbGFicyA9IGMoImFtcCIsICJ3dCIpLCBwLnZhbF9tZXRob2QgPSAiMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiS2FwbGFuLU1laWVyIEN1cnZlIGZvciBUQ0dBIExVQUQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gInN1cnZpdmFsID0gT1MsIHN1YnR5cGUgPSBMVUFELCBuID0gNTAyLCBjaHJfYXJtID0gMTVxIikKYGBgCgpgYGB7ciBrYXBsYW5NZWllcl9sdXNjfQp0Y2dhX2x1c2MkY2hyMjJxU3RhdHVzIDwtIGlmZWxzZSh0Y2dhX2x1c2MkY2hyMjJxIDwgMCwgImRlbCIsICJ3dCIpCnRjZ2FfbHVzYyRjaHIxNXFTdGF0dXMgPC0gaWZlbHNlKHRjZ2FfbHVzYyRjaHIxNXEgPCAwLCAiZGVsIiwgInd0IikKCmZpdCA8LSBzdXJ2Zml0KFN1cnYoT1MudGltZSwgT1MpIH4gYXMuZmFjdG9yKGNocjIycVN0YXR1cyksIGRhdGEgPSB0Y2dhX2x1c2MpCnA5IDwtIGdnc3VydnBsb3RfY3VzdG9taXNlZChmaXRfZnVuY3Rpb24gPSBmaXQsIGRhdGFmcmFtZSA9IHRjZ2FfbHVzYywgcHZhbF9jb29yZCA9IGMoMzUwMCwgMC43NSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtfdGltZV9ieSA9IDUwMCwgbGVnZW5kX2xhYnMgPSBjKCJkZWwiLCAid3QiKSwgcC52YWxfbWV0aG9kID0gIjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkthcGxhbi1NZWllciBDdXJ2ZSBmb3IgVENHQSBMVVNDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJzdXJ2aXZhbCA9IE9TLCBzdWJ0eXBlID0gTFVTQywgbiA9IDQ4NywgY2hyX2FybSA9IDIycSIpCgpmaXQgPC0gc3VydmZpdChTdXJ2KE9TLnRpbWUsIE9TKSB+IGFzLmZhY3RvcihjaHIxNXFTdGF0dXMpLCBkYXRhID0gdGNnYV9sdXNjKQpwMTAgPC0gZ2dzdXJ2cGxvdF9jdXN0b21pc2VkKGZpdF9mdW5jdGlvbiA9IGZpdCwgZGF0YWZyYW1lID0gdGNnYV9sdXNjLCBwdmFsX2Nvb3JkID0gYygzNTAwLCAwLjc1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtfdGltZV9ieSA9IDUwMCwgbGVnZW5kX2xhYnMgPSBjKCJkZWwiLCAid3QiKSwgcC52YWxfbWV0aG9kID0gIjEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkthcGxhbi1NZWllciBDdXJ2ZSBmb3IgVENHQSBMVVNDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJzdXJ2aXZhbCA9IE9TLCBzdWJ0eXBlID0gTFVTQywgbiA9IDQ4NywgY2hyX2FybSA9IDE1cSIpCgpgYGAKCmBgYHtyIGthcGxhbk1laWVyX2x1bmd9CnRjZ2EkY2hyNHBTdGF0dXMgPC0gaWZlbHNlKHRjZ2EkY2hyNHAgPiAwLCAiYW1wIiwgInd0IikKCmZpdCA8LSBzdXJ2Zml0KFN1cnYoT1MudGltZSwgT1MpIH4gYXMuZmFjdG9yKGNocjRwU3RhdHVzKSwgZGF0YSA9IHRjZ2EpCnAxMSA8LSBnZ3N1cnZwbG90X2N1c3RvbWlzZWQoZml0X2Z1bmN0aW9uID0gZml0LCBkYXRhZnJhbWUgPSB0Y2dhLCBwdmFsX2Nvb3JkID0gYygzNTAwLCAwLjc1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha190aW1lX2J5ID0gNTAwLCBsZWdlbmRfbGFicyA9IGMoImFtcCIsICJ3dCIpLCBwLnZhbF9tZXRob2QgPSAiMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiS2FwbGFuLU1laWVyIEN1cnZlIGZvciBUQ0dBIExVU0MrTFVBRCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAic3Vydml2YWwgPSBPUywgc3VidHlwZSA9IExVU0MrTFVBRCwgbiA9IDk4OSwgY2hyX2FybSA9IDRwIikKYGBgCgoKIyMjIFRoZXJhcHkgYXNzb2NpYXRpb24gICAgCiMjIyMgTHVuZyBhZGVub2NhcmNpbm9tYSAgICAgIApgYGB7ciB0aGVyYXB5X291dGNvbWV9CnAxMiA8LSBnZ3Bsb3QodGNnYV9sdWFkLCBhZXMoeCA9IGFzLmZhY3RvcihwcmltYXJ5X291dGNvbWUpLCB5ID0gY2hyMTVxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJwcmltYXJ5IHRoZXJhcHksIExVQUQsIDE1cSIpCnAxMyA8LSBnZ3Bsb3QodGNnYV9sdWFkLCBhZXMoeCA9IGFzLmZhY3RvcihwcmltYXJ5X291dGNvbWUpLCB5ID0gY2hyMjJxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJwcmltYXJ5IHRoZXJhcHksIExVQUQsIDIycSIpCnAxNCA8LSBnZ3Bsb3QodGNnYV9sdWFkLCBhZXMoeCA9IGFzLmZhY3RvcihzZWNvbmRsaW5lX291dGNvbWUpLCB5ID0gY2hyMTVxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJzZWNvbmRsaW5lIHRoZXJhcHksIExVQUQsIDE1cSIpCnAxNSA8LSBnZ3Bsb3QodGNnYV9sdWFkLCBhZXMoeCA9IGFzLmZhY3RvcihzZWNvbmRsaW5lX291dGNvbWUpLCB5ID0gY2hyMjJxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJzZWNvbmRsaW5lIHRoZXJhcHksIExVQUQsIDIycSIpCmBgYAoKYGBge3J9CmFvdihjaHIxNXEgfiBhcy5mYWN0b3IocHJpbWFyeV9vdXRjb21lKSwgZGF0YSA9IHRjZ2FfbHVhZCkgJT4lIHN1bW1hcnkoKQphb3YoY2hyMjJxIH4gYXMuZmFjdG9yKHByaW1hcnlfb3V0Y29tZSksIGRhdGEgPSB0Y2dhX2x1YWQpICU+JSBzdW1tYXJ5KCkKYW92KGNocjE1cSB+IGFzLmZhY3RvcihzZWNvbmRsaW5lX291dGNvbWUpLCBkYXRhID0gdGNnYV9sdWFkKSAlPiUgc3VtbWFyeSgpCmFvdihjaHIyMnEgfiBhcy5mYWN0b3Ioc2Vjb25kbGluZV9vdXRjb21lKSwgZGF0YSA9IHRjZ2FfbHVhZCkgJT4lIHN1bW1hcnkoKQpgYGAKCgpgYGB7ciB0aGVyYXB5X3Jlc3BvbnNlfQpwMTYgPC0gZ2dwbG90KHRjZ2FfbHVhZCwgYWVzKHggPSBhcy5mYWN0b3IocHJpbWFyeV9yZXNwb25zZSksIHkgPSBjaHIxNXEpKStnZW9tX3Zpb2xpbigpK2dndGl0bGUoInByaW1hcnkgcmVzcG9uc2UsIExVQUQsIDE1cSIpCnAxNyA8LSBnZ3Bsb3QodGNnYV9sdWFkLCBhZXMoeCA9IGFzLmZhY3RvcihwcmltYXJ5X3Jlc3BvbnNlKSwgeSA9IGNocjIycSkpK2dlb21fdmlvbGluKCkrZ2d0aXRsZSgicHJpbWFyeSByZXNwb25zZSwgTFVBRCwgMjJxIikKcDE4IDwtIGdncGxvdCh0Y2dhX2x1YWQsIGFlcyh4ID0gYXMuZmFjdG9yKHNlY29uZGxpbmVfcmVzcG9uc2UpLCB5ID0gY2hyMTVxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJzZWNvbmRsaW5lIHJlc3BvbnNlLCBMVUFELCAxNXEiKQpwMTkgPC0gZ2dwbG90KHRjZ2FfbHVhZCwgYWVzKHggPSBhcy5mYWN0b3Ioc2Vjb25kbGluZV9yZXNwb25zZSksIHkgPSBjaHIyMnEpKStnZW9tX3Zpb2xpbigpK2dndGl0bGUoInNlY29uZGxpbmUgcmVzcG9uc2UsIExVQUQsIDIycSIpCmBgYAoKYGBge3J9CndpbGNveC50ZXN0KHRjZ2FfbHVhZCRjaHIxNXFbdGNnYV9sdWFkJHByaW1hcnlfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVhZCRjaHIxNXFbdGNnYV9sdWFkJHByaW1hcnlfcmVzcG9uc2UgPT0gMF0pCndpbGNveC50ZXN0KHRjZ2FfbHVhZCRjaHIyMnFbdGNnYV9sdWFkJHByaW1hcnlfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVhZCRjaHIyMnFbdGNnYV9sdWFkJHByaW1hcnlfcmVzcG9uc2UgPT0gMF0pCndpbGNveC50ZXN0KHRjZ2FfbHVhZCRjaHIxNXFbdGNnYV9sdWFkJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVhZCRjaHIxNXFbdGNnYV9sdWFkJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMF0pCndpbGNveC50ZXN0KHRjZ2FfbHVhZCRjaHIyMnFbdGNnYV9sdWFkJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVhZCRjaHIyMnFbdGNnYV9sdWFkJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMF0pCmBgYAoKCgojIyMjIEx1bmcgc3F1YW1vdXMgY2VsbCBjYXJjaW5vbWEgICAgICAKYGBge3J9CnAyMCA8LSBnZ3Bsb3QodGNnYV9sdXNjLCBhZXMoeCA9IGFzLmZhY3RvcihwcmltYXJ5X291dGNvbWUpLCB5ID0gY2hyMTVxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJwcmltYXJ5IHRoZXJhcHksIExVU0MsIDE1cSIpCnAyMSA8LSBnZ3Bsb3QodGNnYV9sdXNjLCBhZXMoeCA9IGFzLmZhY3RvcihwcmltYXJ5X291dGNvbWUpLCB5ID0gY2hyMjJxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJwcmltYXJ5IHRoZXJhcHksIExVU0MsIDIycSIpCnAyMiA8LSBnZ3Bsb3QodGNnYV9sdXNjLCBhZXMoeCA9IGFzLmZhY3RvcihzZWNvbmRsaW5lX291dGNvbWUpLCB5ID0gY2hyMTVxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJzZWNvbmRsaW5lIHRoZXJhcHksIExVU0MsIDE1cSIpCnAyMyA8LSBnZ3Bsb3QodGNnYV9sdXNjLCBhZXMoeCA9IGFzLmZhY3RvcihzZWNvbmRsaW5lX291dGNvbWUpLCB5ID0gY2hyMjJxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJzZWNvbmRsaW5lIHRoZXJhcHksIExVU0MsIDIycSIpCmBgYAoKYGBge3J9CmFvdihjaHIxNXEgfiBhcy5mYWN0b3IocHJpbWFyeV9vdXRjb21lKSwgZGF0YSA9IHRjZ2FfbHVzYykgJT4lIHN1bW1hcnkoKQphb3YoY2hyMjJxIH4gYXMuZmFjdG9yKHByaW1hcnlfb3V0Y29tZSksIGRhdGEgPSB0Y2dhX2x1c2MpICU+JSBzdW1tYXJ5KCkKYW92KGNocjE1cSB+IGFzLmZhY3RvcihzZWNvbmRsaW5lX291dGNvbWUpLCBkYXRhID0gdGNnYV9sdXNjKSAlPiUgc3VtbWFyeSgpCmFvdihjaHIyMnEgfiBhcy5mYWN0b3Ioc2Vjb25kbGluZV9vdXRjb21lKSwgZGF0YSA9IHRjZ2FfbHVzYykgJT4lIHN1bW1hcnkoKQpgYGAKCmBgYHtyfQpwMjQgPC0gZ2dwbG90KHRjZ2FfbHVzYywgYWVzKHggPSBhcy5mYWN0b3IocHJpbWFyeV9yZXNwb25zZSksIHkgPSBjaHIxNXEpKStnZW9tX3Zpb2xpbigpK2dndGl0bGUoInByaW1hcnkgcmVzcG9uc2UsIExVU0MsIDE1cSIpCnAyNSA8LSBnZ3Bsb3QodGNnYV9sdXNjLCBhZXMoeCA9IGFzLmZhY3RvcihwcmltYXJ5X3Jlc3BvbnNlKSwgeSA9IGNocjIycSkpK2dlb21fdmlvbGluKCkrZ2d0aXRsZSgicHJpbWFyeSByZXNwb25zZSwgTFVTQywgMjJxIikKcDI2IDwtIGdncGxvdCh0Y2dhX2x1c2MsIGFlcyh4ID0gYXMuZmFjdG9yKHNlY29uZGxpbmVfcmVzcG9uc2UpLCB5ID0gY2hyMTVxKSkrZ2VvbV92aW9saW4oKStnZ3RpdGxlKCJzZWNvbmRsaW5lIHJlc3BvbnNlLCBMVVNDLCAxNXEiKQpwMjcgPC0gZ2dwbG90KHRjZ2FfbHVzYywgYWVzKHggPSBhcy5mYWN0b3Ioc2Vjb25kbGluZV9yZXNwb25zZSksIHkgPSBjaHIyMnEpKStnZW9tX3Zpb2xpbigpK2dndGl0bGUoInNlY29uZGxpbmUgcmVzcG9uc2UsIExVU0MsIDIycSIpCmBgYAoKYGBge3J9CndpbGNveC50ZXN0KHRjZ2FfbHVzYyRjaHIxNXFbdGNnYV9sdXNjJHByaW1hcnlfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVzYyRjaHIxNXFbdGNnYV9sdXNjJHByaW1hcnlfcmVzcG9uc2UgPT0gMF0pCndpbGNveC50ZXN0KHRjZ2FfbHVzYyRjaHIyMnFbdGNnYV9sdXNjJHByaW1hcnlfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVzYyRjaHIyMnFbdGNnYV9sdXNjJHByaW1hcnlfcmVzcG9uc2UgPT0gMF0pCndpbGNveC50ZXN0KHRjZ2FfbHVzYyRjaHIxNXFbdGNnYV9sdXNjJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVzYyRjaHIxNXFbdGNnYV9sdXNjJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMF0pCndpbGNveC50ZXN0KHRjZ2FfbHVzYyRjaHIyMnFbdGNnYV9sdXNjJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMV0sIHRjZ2FfbHVzYyRjaHIyMnFbdGNnYV9sdXNjJHNlY29uZGxpbmVfcmVzcG9uc2UgPT0gMF0pCmBgYAoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK