Heatmap DGEs and enrichment
##################
# DEG's FUNCTION #
##################
#group <- "Tissue_gr"
#group <- "Luminal_gr"
edgR_dge.fun <- function(group, confound) {
groups <- metadata[sample_use, group]
n_gr <- length(na.omit(unique(groups)))
if(any(is.na(groups))) {
groups <- replace_na(groups, "X")
}
if(confound==FALSE) {
c <- "_no_conf"
design <- model.matrix(~groups, data=metadata[sample_use,]) # without confounders
}else{
c <- "_conf"
design <- model.matrix(~groups+HIVstatus+Contraception,
data=metadata[sample_use,])
}
colnames(design) <- sub("groups","",colnames(design))
colnames(design) <- sub("\\(Intercept\\)","Intercept",colnames(design))
colnames(design) <- sub(" ","_",colnames(design))
y <- DGEList(counts=TRX_counts[,sample_use], remove.zeros = T)
y <- calcNormFactors(y,method = "TMM")
y <- estimateGLMCommonDisp(y,design)
y <- estimateGLMTagwiseDisp(y,design)
fit <- glmFit(y, design)
lrt <- glmLRT(fit,coef=2:n_gr) # with intercept
top <- topTags(lrt,adjust.method = "BH",n = "all",sort.by = "p.value")[[1]]
colnames(top) <- sub(group,"",colnames(top))
top <- cbind(LogFC.intercept=0,top) # with intercept
top <- rownames_to_column(top, var = "Genes")
return(list(design=design, y=y, fit=fit, lrt=lrt, top=top, c=c))
}
#######################
# ENRICHMENT FUNCTION #
#######################
# group_name <- "Luminal_gr"
# top <- dge_L$top
# y <- dge_L$y
# c <- dge_L$c
gene_mod_enrich.fun <- function(top, y, c, db, group_name, cuttoff){
p_val <- pull(top, "PValue")
top_dge <- (p_val < 0.01) #& (rowSums( abs(top[,grep("logFC",colnames(top))]) >= log2(1.5) ) >= 1)
top_dge <- top$Genes[ top_dge ]
top_TRX_counts <- edgeR::cpm(y,normalized.lib.sizes = T,log = T)[top_dge, ]
top_TRX_counts <- t(apply(top_TRX_counts,1,function(x){scale(x,T,T)}))
top_TRX_counts[top_TRX_counts > 5] <- 5
colnames(top_TRX_counts) <- colnames(TRX_counts)
h <- hclust( as.dist( (1- cor(t(top_TRX_counts)))/2 ), method = "ward.D2")
cuttoff <- cuttoff[names(cuttoff) == db]
gene_module <- cutree(h, h=cuttoff)
if(db == "GO"){
gmt_list <- GO_database}else{
gmt_list <- KEGG_database}
res_list <- lapply( unique( gene_module[h$order] ),function(x){
temp <- compute_enrichment(genes = names(gene_module)[gene_module==x],
gmt_list = gmt_list,
min_terms_pathway = 10,
max_terms_pathway = 300,
min_overlap = 3,
sort_by_pvalue = T)
temp <- temp[!grepl("REGULATION",rownames(temp)),]
return(temp)
} )
return(list(res_list=res_list, top_TRX_counts=top_TRX_counts,
gene_module=gene_module, cuttoff=cuttoff, h=h, c=c))
}
###########################
# PAIRWISE DEG's FUNCTION #
###########################
pairwise_dge.fun <- function(group, fit, design) {
groups <- metadata[sample_use, group]
levels <- as.character(sort(unique(groups),na.last = NA))
# without intercept:
n <- combn(levels,2)
g <- map_chr(seq_along(1:ncol(n)), ~paste(n[1,.x], n[2,.x], sep = "-"))
s <- seq_along(1:ncol(n)) %>% set_names(g)
#name <- map_chr(seq_along(1:ncol(n)), ~paste(str_extract(n[1,.x], "^g."), str_extract(n[2,.x], "^g."), sep = "_"))
# with intercept:
g <- sub(paste0("^(",levels[1], ")-(.*)"), '-\\2', g)
CONTRASTS <- makeContrasts( contrasts=g,
levels = design )
#fit2 <- contrasts.fit(fit, CONTRASTS)
#lrt_ <- glmLRT(fit2, coef = 2:5)
lrt <- map(s, ~ glmLRT(fit, contrast = CONTRASTS[,.x]))
top <- map(lrt, ~topTags(.x,adjust.method = "BH",n = "all",sort.by = "p.value")[[1]]) %>%
map(., ~rownames_to_column(.x, var = "Genes"))
results <- map_df(lrt, ~decideTests(.x, method="separate", p.value = 0.05))
summary <- bind_cols( "FDR<0.05"= c("Down","NotSig","Up"), summary(results))
colnames(summary) <- c("FDR<0.05", g)
top <- c(summary = list(summary), top)
return(list(lrt=lrt, top=top, CONTRASTS=CONTRASTS))
#return(list(lrt=lrt, top=top, CONTRASTS=CONTRASTS, results=results))
}
################################
# PAIRWISE ENRICHMENT FUNCTION #
################################
enrich_list <- function(x, gmt_list){
temp <- compute_enrichment(genes = x,
gmt_list = gmt_list,
min_terms_pathway = 10,
max_terms_pathway = 300,
min_overlap = 3,
sort_by_pvalue = T)
temp <- temp[!grepl("REGULATION",rownames(temp)),]
temp <- rownames_to_column(temp, var = "Terms")
return(temp)
}
TRX <- datasets_all_samples[["Tissue_RNAseq_V3_normalized"]]
TRX_counts <- round(2^TRX - 1)
TRX_counts <- TRX_counts [ rowSums(TRX_counts>0)>= 1 , ]
TRX_counts <- TRX_counts[,sample_use]
#########
# DEG's #
#########
dge_L <- edgR_dge.fun("Luminal_gr", confound=T)
dge_T <- edgR_dge.fun("Tissue_gr", confound=T)
###############
# ENRICHMENT #
##############
db <- c("GO", "KEGG") %>% set_names()
enrich_L <- db %>%
map(., ~gene_mod_enrich.fun(dge_L$top,dge_L$y,dge_L$c,
db = .x,
group_name = "Luminal_gr",
cuttoff = c(GO=2.5, KEGG=2.5)#3
))
enrich_T <- db %>%
map(., ~gene_mod_enrich.fun(dge_T$top,dge_T$y,dge_T$c,
db = .x,
group_name = "Tissue_gr",
cuttoff = c(GO=1.6, KEGG=1.6)
))
##################
# PAIRWISE DEG's #
##################
pairwise_dge_L <- pairwise_dge.fun(group = "Luminal_gr",
fit=dge_L$fit,
design=dge_L$design )
pairwise_dge_T <- pairwise_dge.fun(group = "Tissue_gr",
fit=dge_T$fit,
design=dge_T$design)
###############################
# PAIRWISE ENRICHMENT GO/KEGG #
###############################
#info_logFC <- map(top_dfs[[1]], ~table(abs(.x$logFC) > 1))
#info_PValue <- map(top_dfs[[1]], ~table(.$PValue < 0.01))
l_top <- list(Luminal = pairwise_dge_L$top[-1], Tissue = pairwise_dge_T$top[-1])
# up and down regulated genes seperatly
t_split <- modify_depth(l_top, 2, ~ .x %>%
dplyr::filter(., .$PValue < 0.01) %>%
#dplyr::filter(., abs(.$logFC) < 1) %>%
mutate(., reg = ifelse(.$logFC > 0, "up", "down")) %>%
split(., .$reg)
)
## GO enrichment
pairwise_GO <- map_depth(t_split, 3, ~enrich_list(.x$Genes, GO_database)) %>%
map_depth(., 2, ~bind_rows(.x, .id = "regulation"))
## KEGG enrichment
pairwise_KEGG <- map_depth(t_split, 3, ~enrich_list(.x$Genes, KEGG_database)) %>%
map_depth(., 2, ~bind_rows(.x, .id = "regulation"))
# DEG's across and pairwise
pages <- list(list(Across=dge_L$top), pairwise=pairwise_dge_L$top) %>% flatten()
write.xlsx(pages, file=paste0(result_dir,DEG_files[1]))
pages <- list(list(Across=dge_T$top), pairwise=pairwise_dge_T$top) %>% flatten()
write.xlsx(pages, file=paste0(result_dir,DEG_files[2]))
#Files with filtered p-value < 0.01
# Have to update the summary table, however the decideTests
# function does not provide support for p-value cutoffs only FDR
# therefore I need to write code to get the correct summary
p_L <- map(pairwise_dge_L$top[-1], ~filter(.x, `PValue`<0.01))
p_T <- map(pairwise_dge_T$top[-1], ~filter(.x, `PValue`<0.01))
pages <- list(list(Across=dge_L$top), pairwise=p_L) %>% flatten()
write.xlsx(pages, file=paste0(result_dir,DEG_files[1]))
pages <- list(list(Across=dge_T$top), pairwise=p_T) %>% flatten()
write.xlsx(pages, file=paste0(result_dir,DEG_files[2]))
# Enrichment Across
df_across <- enframe(list(Luminal=enrich_L, Tissue=enrich_T)) %>%
unnest_longer(value) %>%
mutate(res = map(.$value, "res_list")) %>%
unnest_longer(res) %>%
mutate(res = map(res, ~rownames_to_column(.x, var = "Terms"))) %>%
mutate(res = map(res, ~filter(.x, pvalue <= 0.01))) %>%
group_by(name, value_id) %>%
mutate(mod = row_number()) %>% ungroup() %>%
mutate(res = set_names(.$res, paste0(.$value_id,"_gene_module_",.$mod))) %>%
group_split(name) %>% set_names(., map(., ~unique(.x$name)))
write.xlsx(df_across[[1]]$res, file=paste0(result_dir,"Suppl.Tbl.05 Enrichment_Across_Luminal",".xlsx"))
write.xlsx(df_across[[2]]$res, file=paste0(result_dir,"Suppl.Tbl.09 Enrichment_Across_Tissue",".xlsx"))
# Enrichment pairwise
df_pairwise <- enframe(list(GO=pairwise_GO, KEGG=pairwise_KEGG)) %>%
unnest_longer(value) %>%
unnest_longer(value, names_repair ="unique") %>%
mutate(value = map(value, ~filter(.x, FDR <= 0.05))) %>%
mutate(value = set_names(.$value, paste0(.$name,"_",.$value_id...3))) %>%
group_split(value_id...4) %>% set_names(., map(., ~unique(.x$value_id...4)))
write.xlsx(df_pairwise[[1]]$value, file=paste0(result_dir,"Suppl.Tbl.06 Enrichment_Pairwise_Luminal",".xlsx"))
write.xlsx(df_pairwise[[2]]$value, file=paste0(result_dir,"Suppl.Tbl.10 Enrichment_Pairwise_Tissue",".xlsx"))


Figure. 4-5. Characterization of the host transcriptome as
stratified by the luminal microbiome study groups. The luminal
samples were assessed for differential gene expression across the study
groups. a Differential gene expression analysis was
applied across the five luminal study groups. Significant DEGs (p-value
< 0.01) were divided into six modules by hierarchical agglomerative
clustering using inverse Pearson’s correlation as distance measure and
Ward’s method (“ward. D2”) for linkage. Enrichment analysis was
performed on each module using both the KEGG and GO databases. The three
most significant terms were included in the heatmap. b
Pairwise enrichment analysis of protein-protein interactions of
transcription factors (TF-PPI). Top-10 up- and down regulated
transcription factors with p-value < 0.01 were included in the bar
plots
metadata <- metadata %>%
mutate(L_T_groups = paste0(.$Luminal_gr, .$Tissue_gr)) %>%
mutate(L_T_groups = ifelse(grepl("L2T2|L2T3", .$L_T_groups), .$L_T_groups, NA))
dge_LT <- edgR_dge.fun("L_T_groups", confound=T)
enrich_LT <- db %>%
map(., ~gene_mod_enrich.fun(dge_LT$top,dge_LT$y,dge_LT$c,
db = .x,
group_name = "L_T_groups",
cuttoff = c(GO=2, KEGG=2) # c(GO=2, KEGG=2.7)
))
# Plot the L2T2 vs L2T3 heatmap:
#pal <- c("#54ba63","#ad58c6","#d03e7a","#4cb6a9","#bb6fac","#cca442","#8fb53c","#6a7ecd","#63813e","#c46570","#b3743e","#d35238")
#plot_heatmap.fun(enrich_LT, "KEGG", "L_T_groups", "L_T_groups")
t <- dge_LT$top %>% filter(PValue <= 0.01)
df_across <- enframe(list(LtoT=enrich_LT)) %>%
unnest_longer(value) %>%
mutate(res = map(.$value, "res_list")) %>%
unnest_longer(res) %>%
mutate(res = map(res, ~rownames_to_column(.x, var = "Terms"))) %>%
mutate(res = map(res, ~filter(.x, pvalue <= 0.01))) %>%
group_by(name, value_id) %>%
mutate(mod = row_number()) %>% ungroup() %>%
mutate(res = set_names(.$res, paste0(.$value_id,"_gene_module_",.$mod))) %>%
group_split(name) %>% set_names(., map(., ~unique(.x$name)))
pages <- list(list("DEGs L2T2 vs L2T3"=t), df_across[[1]]$res) %>% flatten()
write.xlsx(pages, file=paste0(result_dir,"Suppl.Tbl.12 L2T2_L2T3_DEGs_and_enrichment.xlsx"))
igraph network plot
# 1. Change the groups of interest by assigning condition_use
# 2. Change the number of genes to be included in the network by changing n
# look at tempD_i and tempU_i to see how many genes was significant
# 3. Adjust the size of the gene nodes and text in the graph by changing; square, circle and txt
# combinations
sheets <- map(DEG_files, ~excel_sheets(paste0(result_dir, .x))[-c(1:2)] ) %>%
map(., ~set_names(.x))
# Set enrichment conditions
n <- 10 # maximum number of TF's to plot
# sizes:
square <- 10
cricle <- 8
txt <- .7
# Create a graph from the list of UP and DOWN regulated genes
i_graph <- function(temp_i, n, square, cricle){
temp <- lapply( 1:n, function(x){ strsplit(as.character(temp_i$Genes[x]),split = ";")[[1]] } )
temp <- map(temp, purrr::discard, is.na) %>% compact() # removes NA
names(temp) <- temp_i$`Transcription Factor`[1:length(temp)]
temp2 <- lapply( names(temp) , function(x){ rep(x,length(temp[[x]])) })
temp <- cbind(unlist(temp2),unlist(temp))
g <- graph_from_data_frame(temp,directed = F)
v_shape <- ifelse( names(V(g)) %in% unique(temp[,1]) , "square" , "circle" )
v_color <- ifelse( names(V(g)) %in% unique(temp[,1]) , "honeydew" , "cornsilk" )
v_size <- ifelse( names(V(g)) %in% unique(temp[,1]) , square , cricle )
return(list(g=g, v_shape=v_shape, v_color=v_color, v_size=v_size))
}
# Test parameters
# i <- "TF_PPI_Tissue"
# i <- "TF_TRRUST_enrichment"
# gr_name <- "Tissue"
# comp <- sheets
# Save all combination plots in one file
save_pdf.fun <- function(i, gr_name, comp){
temp_i_name <- grep(i,list.files(paste0(result_dir),full.names=F),value=T)
p <- map(comp, ~read_xlsx(paste0(result_dir, temp_i_name), sheet = .x))
p_split <- p %>%
imap(., ~.x %>%
mutate(Regulation = paste0(.y, "_", .$Regulation)) %>%
split(., .$Regulation)
) %>% compact() %>% flatten()
obj_igraph <- imap(p_split, ~i_graph(.x, n, square, cricle))
par(mar = c(0, 0, .7, 0)) #bottom, left, top, right
pdf(file = paste0(result_dir, "Plots/", i, "_network_",".pdf", sep=""))
p <- imap(obj_igraph,
~with(.x,
plot.igraph(g, label=V(g), page = T,
main = paste0(str_replace(.y, "_", " ")," regulated genes"),
layout=layout_with_kk(g), vertex.label.color="black" ,
vertex.size=v_size, vertex.label.cex=txt, vertex.label.font=2,
vertex.shape=v_shape, vertex.color=v_color, marigin = c(-1,-4,0,0),
vertex.frame.color="grey60", curved=F)
))
dev.off()
}
# if(isFALSE(dir.exists(paste0(result_dir,"")))){dir.create(paste0("../",result.dir),recursive = TRUE)}
# save_pdf.fun("TF_PPI_Luminal", "Luminal", comp = sheets[[1]])
# save_pdf.fun("TF_PPI_Tissue", "Tissue", comp = sheets[[2]])
LS0tCnRpdGxlOiAiRmlndXJlIDQuICYgNS4gREdFJ3MgYW5kIEVucmljaG1lbnQiCmdlb21ldHJ5OiAibGVmdD0yY20scmlnaHQ9MmNtLHRvcD0yY20sYm90dG9tPTJjbSIKaGVhZGVyLWluY2x1ZGVzOiAKLSBcdXNlcGFja2FnZXtmbG9hdH0KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCmtuaXQ6IChmdW5jdGlvbihpbnB1dEZpbGUsIG91dF9kaXIsIC4uLikgewogICAgc291cmNlKCIuLi8uLi9jb2RlL2tuaXRfZnVuY3Rpb24uUiIpOwogICAgY3VzdG9tX2tuaXQoaW5wdXRGaWxlLCAiLi4vLi4vbGFiX2Jvb2svRmlndXJlNC01LyIsIC4uLikKICAgIH0pCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICByZXN1bHRzICAgID0gImhvbGQiLAogIG1lc3NhZ2UgICAgPSBGQUxTRSwKICB3YXJuaW5nICAgID0gRkFMU0UsCiAgZmlnLndpZHRoICA9IDYuNjkyOTEzMzg1OCwKICBmaWcuYWxpZ24gID0gImNlbnRlciIsCiAgZmlnLnBhdGggICA9ICIuL0ZpZ3VyZXMvIiwKICBmaWcucHJvY2VzcyA9IGZ1bmN0aW9uKGZpbGVuYW1lKXsKICAgIG5ld19maWxlbmFtZSA8LSBzdHJpbmdyOjpzdHJfcmVtb3ZlKHN0cmluZyA9IGZpbGVuYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLTEiKQogICAgZnM6OmZpbGVfbW92ZShwYXRoID0gZmlsZW5hbWUsIG5ld19wYXRoID0gbmV3X2ZpbGVuYW1lKQogICAgaWZlbHNlKGZzOjpmaWxlX2V4aXN0cyhuZXdfZmlsZW5hbWUpLCBuZXdfZmlsZW5hbWUsIGZpbGVuYW1lKQp9KQojIHNldHdkKCIvVXNlcnMvdmlsa2FsL3dvcmsvQnJvbGlkZW5zX3dvcmsvUHJvamVjdHMvYnJvbGlkZW5fNTMyNS9yZXBvcnRzL21hbnVzY3JpcHQiKQpgYGAKCmBgYHtyIExvYWQtZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMjIyMjIyMjIyMjIyMjIyMjCiMgTE9BRCBMSUJSQVJJRVMgIwojIyMjIyMjIyMjIyMjIyMjIyMKc3VwcHJlc3NXYXJuaW5ncyh7c3VwcHJlc3NNZXNzYWdlcyh7c3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHRpZHl2ZXJzZSkKICBsaWJyYXJ5KGVkZ2VSKQogIGxpYnJhcnkob3Blbnhsc3gpCiAgbGlicmFyeShzY2FsZXMpCiAgbGlicmFyeShmZ3NlYSkKICBsaWJyYXJ5KFJDb2xvckJyZXdlcikKICAjcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImN6YXJuZXdza2kvbmljZVJwbG90cyIsZm9yY2U9VCkKICBsaWJyYXJ5KG5pY2VScGxvdHMpCiAgbGlicmFyeShyZWFkeGwpCiAgbGlicmFyeShlbnJpY2hSKQogIGxpYnJhcnkoaWdyYXBoKQogIGxpYnJhcnkocmFmYWxpYikKfSkgIH0pICB9KQoKIyMjIyMjIyMjCiMgUEFUSFMgIwojIyMjIyMjIyMKcmVzdWx0X2RpciA8LSAiLi9TdXBwbC5UYmwvIgppZiggaXNGQUxTRShkaXIuZXhpc3RzKHJlc3VsdF9kaXIpKSApIHsgZGlyLmNyZWF0ZShyZXN1bHRfZGlyLHJlY3Vyc2l2ZSA9IFRSVUUpIH0KCkRFR19maWxlcyA8LSBjKCJTdXBwbC5UYmwuMDQgREVHc19MdW1pbmFsLnhsc3giLAogICAgICAgICAgICAgICAiU3VwcGwuVGJsLjA4IERFR3NfVGlzc3VlLnhsc3giKQplbnJpY2hSX2ZpbGVzIDwtIGMoIlN1cHBsLlRibC4wNyBURl9QUElfTHVtaW5hbC54bHN4IiwKICAgICAgICAgICAgICAgICAgICJTdXBwbC5UYmwuMTEgVEZfUFBJX1Rpc3N1ZS54bHN4IikKCiMjIyMjIyMjIyMjIyMKIyBMT0RBIERBVEEgIwojIyMjIyMjIyMjIyMjCmRhdGFzZXRzX2FsbF9zYW1wbGVzIDwtIHJlYWRSRFMoIi4uLy4uL3Jlc3VsdHMvMDNfbm9ybWFsaXplX2RhdGFfb3V0cHV0L2RhdGFzZXRzX2FsbF9zYW1wbGVzLlJEUyIpCm1ldGFkYXRhIDwtIHJlYWQuY3N2KCIuLi8uLi9kYXRhL21ldGFkYXRhLmNzdiIscm93Lm5hbWVzID0gMSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnNhbXBsZV91c2UgPC0gbWV0YWRhdGEkSUQKZ3JfbmFtZSA8LSBjKCJMdW1pbmFsIiwgIlRpc3N1ZSIpCgpzb3VyY2UoIi4uLy4uL2NvZGUvZW5yaWNobWVudF9mdW5jdGlvbi5SIikKR09fZGF0YWJhc2UgPC0gZmdzZWE6OmdtdFBhdGh3YXlzKCIuLi8uLi9yZXNvdXJjZXMvS0VHR19HT19kYXRhYmFzZS9jNS5icC52Ni4yLnN5bWJvbHMuZ210LnR4dCIpCktFR0dfZGF0YWJhc2UgPC0gZmdzZWE6OmdtdFBhdGh3YXlzKCIuLi8uLi9yZXNvdXJjZXMvS0VHR19HT19kYXRhYmFzZS9jMi5jcC5rZWdnLnY2LjIuc3ltYm9scy5nbXQudHh0IikKCiMjIyMjIyMjIyMjIyMjIyMjIwojIERFRklORSBDVVRPRkZTICMKIyMjIyMjIyMjIyMjIyMjIyMjCmRnZV9jdXRvZmYgPC0gMC4wMSAjIHAtdmFsdWUKZW5yaWNoX2N1dG9mZiA8LSAwLjEgIyBwLXZhbHVlCm5vX2dlbmVzX2N1dG9mZiA8LSAzCmNvbF9uYW1lIDwtIHBhc3RlMCgiZ2VuZXNfaW4ocFZhbHVlPCIsZGdlX2N1dG9mZiwiKSIpCgojIyMjIyMjIyMjIyMjIyMjIwojIENPTE9SIFBBTEVUVFMgIwojIyMjIyMjIyMjIyMjIyMjIwpwYWwgPC0gYyggIiMwMDcyQjIiLCAiIzAwOUU3MyIsIiNENTVFMDAiLCAiI0NDNzlBNyIsICIjRTY5RjAwIiwgIiM5OTk5OTkiKQp0YXhhX3BhbCA8LSBjKFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg4LCJQYXN0ZWwyIiksUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDgsIlBhc3RlbDEiKSwiZ3JleTkwIikKYGBgCgojIyBIZWF0bWFwIERHRXMgYW5kIGVucmljaG1lbnQKYGBge3IgQWNyb3NzIGZ1bmN0aW9ucywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMjIyMjIyMjIyMjIyMjIyMjCiMgREVHJ3MgRlVOQ1RJT04gIwojIyMjIyMjIyMjIyMjIyMjIyMKI2dyb3VwIDwtICJUaXNzdWVfZ3IiCiNncm91cCA8LSAiTHVtaW5hbF9nciIKZWRnUl9kZ2UuZnVuIDwtIGZ1bmN0aW9uKGdyb3VwLCBjb25mb3VuZCkgewogIAogIGdyb3VwcyA8LSBtZXRhZGF0YVtzYW1wbGVfdXNlLCBncm91cF0KICBuX2dyIDwtIGxlbmd0aChuYS5vbWl0KHVuaXF1ZShncm91cHMpKSkKICAKICBpZihhbnkoaXMubmEoZ3JvdXBzKSkpIHsKICAgIGdyb3VwcyA8LSByZXBsYWNlX25hKGdyb3VwcywgIlgiKQogIH0KCiAgaWYoY29uZm91bmQ9PUZBTFNFKSB7CiAgICBjIDwtICJfbm9fY29uZiIKICAgIGRlc2lnbiA8LSBtb2RlbC5tYXRyaXgofmdyb3VwcywgZGF0YT1tZXRhZGF0YVtzYW1wbGVfdXNlLF0pICMgd2l0aG91dCBjb25mb3VuZGVycwogIH1lbHNlewogICAgYyA8LSAiX2NvbmYiCiAgICBkZXNpZ24gPC0gbW9kZWwubWF0cml4KH5ncm91cHMrSElWc3RhdHVzK0NvbnRyYWNlcHRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPW1ldGFkYXRhW3NhbXBsZV91c2UsXSkKICB9CiAgCiAgY29sbmFtZXMoZGVzaWduKSA8LSBzdWIoImdyb3VwcyIsIiIsY29sbmFtZXMoZGVzaWduKSkKICBjb2xuYW1lcyhkZXNpZ24pIDwtIHN1YigiXFwoSW50ZXJjZXB0XFwpIiwiSW50ZXJjZXB0Iixjb2xuYW1lcyhkZXNpZ24pKQogIGNvbG5hbWVzKGRlc2lnbikgPC0gc3ViKCIgIiwiXyIsY29sbmFtZXMoZGVzaWduKSkKICAKICB5IDwtIERHRUxpc3QoY291bnRzPVRSWF9jb3VudHNbLHNhbXBsZV91c2VdLCByZW1vdmUuemVyb3MgPSBUKQogIHkgPC0gY2FsY05vcm1GYWN0b3JzKHksbWV0aG9kID0gIlRNTSIpCiAgeSA8LSBlc3RpbWF0ZUdMTUNvbW1vbkRpc3AoeSxkZXNpZ24pCiAgeSA8LSBlc3RpbWF0ZUdMTVRhZ3dpc2VEaXNwKHksZGVzaWduKQogIGZpdCA8LSBnbG1GaXQoeSwgZGVzaWduKQogIAogIGxydCA8LSBnbG1MUlQoZml0LGNvZWY9MjpuX2dyKSAjIHdpdGggaW50ZXJjZXB0CiAgdG9wIDwtIHRvcFRhZ3MobHJ0LGFkanVzdC5tZXRob2QgPSAiQkgiLG4gPSAiYWxsIixzb3J0LmJ5ID0gInAudmFsdWUiKVtbMV1dCiAgY29sbmFtZXModG9wKSA8LSBzdWIoZ3JvdXAsIiIsY29sbmFtZXModG9wKSkKICB0b3AgPC0gY2JpbmQoTG9nRkMuaW50ZXJjZXB0PTAsdG9wKSAjIHdpdGggaW50ZXJjZXB0CiAgdG9wIDwtICByb3duYW1lc190b19jb2x1bW4odG9wLCB2YXIgPSAiR2VuZXMiKQogIApyZXR1cm4obGlzdChkZXNpZ249ZGVzaWduLCB5PXksIGZpdD1maXQsIGxydD1scnQsIHRvcD10b3AsIGM9YykpCn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgRU5SSUNITUVOVCBGVU5DVElPTiAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgZ3JvdXBfbmFtZSA8LSAiTHVtaW5hbF9nciIKIyB0b3AgPC0gZGdlX0wkdG9wCiMgeSA8LSBkZ2VfTCR5CiMgYyA8LSBkZ2VfTCRjCmdlbmVfbW9kX2VucmljaC5mdW4gPC0gZnVuY3Rpb24odG9wLCB5LCBjLCBkYiwgZ3JvdXBfbmFtZSwgY3V0dG9mZil7CiAgcF92YWwgPC0gcHVsbCh0b3AsICJQVmFsdWUiKQogIHRvcF9kZ2UgPC0gKHBfdmFsIDwgMC4wMSkgIyYgKHJvd1N1bXMoIGFicyh0b3BbLGdyZXAoImxvZ0ZDIixjb2xuYW1lcyh0b3ApKV0pID49IGxvZzIoMS41KSApID49IDEpCiAgdG9wX2RnZSA8LSB0b3AkR2VuZXNbIHRvcF9kZ2UgXQogIAogIHRvcF9UUlhfY291bnRzIDwtIGVkZ2VSOjpjcG0oeSxub3JtYWxpemVkLmxpYi5zaXplcyA9IFQsbG9nID0gVClbdG9wX2RnZSwgXQogIHRvcF9UUlhfY291bnRzIDwtIHQoYXBwbHkodG9wX1RSWF9jb3VudHMsMSxmdW5jdGlvbih4KXtzY2FsZSh4LFQsVCl9KSkKICB0b3BfVFJYX2NvdW50c1t0b3BfVFJYX2NvdW50cyA+IDVdIDwtIDUKICBjb2xuYW1lcyh0b3BfVFJYX2NvdW50cykgPC0gY29sbmFtZXMoVFJYX2NvdW50cykKICAKICAKICBoIDwtIGhjbHVzdCggYXMuZGlzdCggKDEtIGNvcih0KHRvcF9UUlhfY291bnRzKSkpLzIgKSwgbWV0aG9kID0gIndhcmQuRDIiKQogIGN1dHRvZmYgPC0gY3V0dG9mZltuYW1lcyhjdXR0b2ZmKSA9PSBkYl0KICBnZW5lX21vZHVsZSA8LSBjdXRyZWUoaCwgaD1jdXR0b2ZmKQogIAogIGlmKGRiID09ICJHTyIpewogIGdtdF9saXN0IDwtIEdPX2RhdGFiYXNlfWVsc2V7CiAgZ210X2xpc3QgPC0gS0VHR19kYXRhYmFzZX0KICByZXNfbGlzdCA8LSBsYXBwbHkoIHVuaXF1ZSggZ2VuZV9tb2R1bGVbaCRvcmRlcl0gKSxmdW5jdGlvbih4KXsKICAgIHRlbXAgPC0gY29tcHV0ZV9lbnJpY2htZW50KGdlbmVzID0gbmFtZXMoZ2VuZV9tb2R1bGUpW2dlbmVfbW9kdWxlPT14XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ210X2xpc3QgPSBnbXRfbGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX3Rlcm1zX3BhdGh3YXkgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3Rlcm1zX3BhdGh3YXkgPSAzMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbl9vdmVybGFwID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc29ydF9ieV9wdmFsdWUgPSBUKQogICAgdGVtcCA8LSB0ZW1wWyFncmVwbCgiUkVHVUxBVElPTiIscm93bmFtZXModGVtcCkpLF0KICAgIHJldHVybih0ZW1wKQogIH0gKQogIAogIHJldHVybihsaXN0KHJlc19saXN0PXJlc19saXN0LCB0b3BfVFJYX2NvdW50cz10b3BfVFJYX2NvdW50cywgCiAgICAgICAgICAgICAgZ2VuZV9tb2R1bGU9Z2VuZV9tb2R1bGUsIGN1dHRvZmY9Y3V0dG9mZiwgaD1oLCBjPWMpKQp9CgpgYGAKCmBgYHtyIFBhaXJ3aXNlLWZ1bmN0aW9ucywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUEFJUldJU0UgREVHJ3MgRlVOQ1RJT04gIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKcGFpcndpc2VfZGdlLmZ1biA8LSBmdW5jdGlvbihncm91cCwgZml0LCBkZXNpZ24pIHsKICBncm91cHMgPC0gbWV0YWRhdGFbc2FtcGxlX3VzZSwgZ3JvdXBdCiAgbGV2ZWxzIDwtIGFzLmNoYXJhY3Rlcihzb3J0KHVuaXF1ZShncm91cHMpLG5hLmxhc3QgPSBOQSkpCiAgCiAgIyB3aXRob3V0IGludGVyY2VwdDoKICBuIDwtIGNvbWJuKGxldmVscywyKSAKICBnIDwtIG1hcF9jaHIoc2VxX2Fsb25nKDE6bmNvbChuKSksIH5wYXN0ZShuWzEsLnhdLCBuWzIsLnhdLCBzZXAgPSAiLSIpKQogIHMgPC0gc2VxX2Fsb25nKDE6bmNvbChuKSkgJT4lIHNldF9uYW1lcyhnKQogICNuYW1lIDwtIG1hcF9jaHIoc2VxX2Fsb25nKDE6bmNvbChuKSksIH5wYXN0ZShzdHJfZXh0cmFjdChuWzEsLnhdLCAiXmcuIiksIHN0cl9leHRyYWN0KG5bMiwueF0sICJeZy4iKSwgc2VwID0gIl8iKSkKICAKICAjIHdpdGggaW50ZXJjZXB0OgogIGcgPC0gc3ViKHBhc3RlMCgiXigiLGxldmVsc1sxXSwgIiktKC4qKSIpLCAnLVxcMicsIGcpCiAgCiAgQ09OVFJBU1RTIDwtIG1ha2VDb250cmFzdHMoIGNvbnRyYXN0cz1nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBkZXNpZ24gKQogIAogICNmaXQyIDwtIGNvbnRyYXN0cy5maXQoZml0LCBDT05UUkFTVFMpCiAgI2xydF8gPC0gZ2xtTFJUKGZpdDIsIGNvZWYgPSAyOjUpCiAgbHJ0IDwtIG1hcChzLCB+IGdsbUxSVChmaXQsIGNvbnRyYXN0ID0gQ09OVFJBU1RTWywueF0pKQogIHRvcCA8LSBtYXAobHJ0LCB+dG9wVGFncygueCxhZGp1c3QubWV0aG9kID0gIkJIIixuID0gImFsbCIsc29ydC5ieSA9ICJwLnZhbHVlIilbWzFdXSkgJT4lIAogICAgICAgICBtYXAoLiwgfnJvd25hbWVzX3RvX2NvbHVtbigueCwgdmFyID0gIkdlbmVzIikpCiAgCiAgcmVzdWx0cyA8LSBtYXBfZGYobHJ0LCB+ZGVjaWRlVGVzdHMoLngsIG1ldGhvZD0ic2VwYXJhdGUiLCBwLnZhbHVlID0gMC4wNSkpCiAgc3VtbWFyeSA8LSBiaW5kX2NvbHMoICJGRFI8MC4wNSI9IGMoIkRvd24iLCJOb3RTaWciLCJVcCIpLCBzdW1tYXJ5KHJlc3VsdHMpKQogIGNvbG5hbWVzKHN1bW1hcnkpIDwtIGMoIkZEUjwwLjA1IiwgZykKICB0b3AgPC0gYyhzdW1tYXJ5ID0gbGlzdChzdW1tYXJ5KSwgdG9wKQogIApyZXR1cm4obGlzdChscnQ9bHJ0LCB0b3A9dG9wLCBDT05UUkFTVFM9Q09OVFJBU1RTKSkKI3JldHVybihsaXN0KGxydD1scnQsIHRvcD10b3AsIENPTlRSQVNUUz1DT05UUkFTVFMsIHJlc3VsdHM9cmVzdWx0cykpCn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBQQUlSV0lTRSBFTlJJQ0hNRU5UIEZVTkNUSU9OICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKZW5yaWNoX2xpc3QgPC0gZnVuY3Rpb24oeCwgZ210X2xpc3QpewogIHRlbXAgPC0gY29tcHV0ZV9lbnJpY2htZW50KGdlbmVzID0geCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdtdF9saXN0ID0gZ210X2xpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fdGVybXNfcGF0aHdheSA9IDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3Rlcm1zX3BhdGh3YXkgPSAzMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fb3ZlcmxhcCA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3J0X2J5X3B2YWx1ZSA9IFQpCiAgdGVtcCA8LSB0ZW1wWyFncmVwbCgiUkVHVUxBVElPTiIscm93bmFtZXModGVtcCkpLF0KICB0ZW1wIDwtIHJvd25hbWVzX3RvX2NvbHVtbih0ZW1wLCB2YXIgPSAiVGVybXMiKQogIHJldHVybih0ZW1wKQp9IApgYGAKCmBgYHtyIEFjcm9zcy10YWJsZXMsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTcsIHdhcm5pbmc9Rn0KVFJYIDwtIGRhdGFzZXRzX2FsbF9zYW1wbGVzW1siVGlzc3VlX1JOQXNlcV9WM19ub3JtYWxpemVkIl1dClRSWF9jb3VudHMgPC0gcm91bmQoMl5UUlggLSAxKQpUUlhfY291bnRzIDwtIFRSWF9jb3VudHMgWyByb3dTdW1zKFRSWF9jb3VudHM+MCk+PSAxICwgXQpUUlhfY291bnRzIDwtIFRSWF9jb3VudHNbLHNhbXBsZV91c2VdCgojIyMjIyMjIyMKIyBERUcncyAjCiMjIyMjIyMjIwpkZ2VfTCA8LSBlZGdSX2RnZS5mdW4oIkx1bWluYWxfZ3IiLCBjb25mb3VuZD1UKQpkZ2VfVCA8LSBlZGdSX2RnZS5mdW4oIlRpc3N1ZV9nciIsIGNvbmZvdW5kPVQpCgoKIyMjIyMjIyMjIyMjIyMjCiMgRU5SSUNITUVOVCAjCiMjIyMjIyMjIyMjIyMjCmRiIDwtIGMoIkdPIiwgIktFR0ciKSAlPiUgc2V0X25hbWVzKCkKZW5yaWNoX0wgPC0gZGIgJT4lCiAgbWFwKC4sIH5nZW5lX21vZF9lbnJpY2guZnVuKGRnZV9MJHRvcCxkZ2VfTCR5LGRnZV9MJGMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRiID0gLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX25hbWUgPSAiTHVtaW5hbF9nciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXR0b2ZmID0gYyhHTz0yLjUsIEtFR0c9Mi41KSMzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpIAplbnJpY2hfVCA8LSBkYiAlPiUKICBtYXAoLiwgfmdlbmVfbW9kX2VucmljaC5mdW4oZGdlX1QkdG9wLGRnZV9UJHksZGdlX1QkYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGIgPSAueCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfbmFtZSA9ICJUaXNzdWVfZ3IiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXR0b2ZmID0gYyhHTz0xLjYsIEtFR0c9MS42KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKQoKYGBgCgpgYGB7ciBQYWlyd2lzZS10YWJsZXN9CiMjIyMjIyMjIyMjIyMjIyMjIwojIFBBSVJXSVNFIERFRydzICMKIyMjIyMjIyMjIyMjIyMjIyMjCnBhaXJ3aXNlX2RnZV9MIDwtIHBhaXJ3aXNlX2RnZS5mdW4oZ3JvdXAgPSAiTHVtaW5hbF9nciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdD1kZ2VfTCRmaXQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbj1kZ2VfTCRkZXNpZ24gKQpwYWlyd2lzZV9kZ2VfVCA8LSBwYWlyd2lzZV9kZ2UuZnVuKGdyb3VwID0gIlRpc3N1ZV9nciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml0PWRnZV9UJGZpdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ249ZGdlX1QkZGVzaWduKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFBBSVJXSVNFIEVOUklDSE1FTlQgR08vS0VHRyAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI2luZm9fbG9nRkMgPC0gbWFwKHRvcF9kZnNbWzFdXSwgfnRhYmxlKGFicygueCRsb2dGQykgPiAxKSkKI2luZm9fUFZhbHVlIDwtIG1hcCh0b3BfZGZzW1sxXV0sIH50YWJsZSguJFBWYWx1ZSA8IDAuMDEpKQoKbF90b3AgPC0gbGlzdChMdW1pbmFsID0gcGFpcndpc2VfZGdlX0wkdG9wWy0xXSwgVGlzc3VlID0gcGFpcndpc2VfZGdlX1QkdG9wWy0xXSkKIyB1cCBhbmQgZG93biByZWd1bGF0ZWQgZ2VuZXMgc2VwZXJhdGx5CnRfc3BsaXQgPC0gbW9kaWZ5X2RlcHRoKGxfdG9wLCAyLCB+IC54ICU+JQogICAgICAgIGRwbHlyOjpmaWx0ZXIoLiwgLiRQVmFsdWUgPCAwLjAxKSAlPiUKICAgICAgICAjZHBseXI6OmZpbHRlciguLCBhYnMoLiRsb2dGQykgPCAxKSAlPiUKICAgICAgICBtdXRhdGUoLiwgcmVnID0gaWZlbHNlKC4kbG9nRkMgPiAwLCAidXAiLCAiZG93biIpKSAlPiUKICAgICAgICBzcGxpdCguLCAuJHJlZykKICApCgojIyBHTyBlbnJpY2htZW50IApwYWlyd2lzZV9HTyA8LSBtYXBfZGVwdGgodF9zcGxpdCwgMywgfmVucmljaF9saXN0KC54JEdlbmVzLCBHT19kYXRhYmFzZSkpICU+JQogIG1hcF9kZXB0aCguLCAyLCB+YmluZF9yb3dzKC54LCAuaWQgPSAicmVndWxhdGlvbiIpKSAKIyMgS0VHRyBlbnJpY2htZW50CnBhaXJ3aXNlX0tFR0cgPC0gbWFwX2RlcHRoKHRfc3BsaXQsIDMsIH5lbnJpY2hfbGlzdCgueCRHZW5lcywgS0VHR19kYXRhYmFzZSkpICU+JQogIG1hcF9kZXB0aCguLCAyLCB+YmluZF9yb3dzKC54LCAuaWQgPSAicmVndWxhdGlvbiIpKSAKIApgYGAKCmBgYHtyIFN1cHBsLiBUYmwuIDQgJiA4fQojIERFRydzIGFjcm9zcyBhbmQgcGFpcndpc2UKcGFnZXMgPC0gbGlzdChsaXN0KEFjcm9zcz1kZ2VfTCR0b3ApLCBwYWlyd2lzZT1wYWlyd2lzZV9kZ2VfTCR0b3ApICU+JSBmbGF0dGVuKCkKd3JpdGUueGxzeChwYWdlcywgZmlsZT1wYXN0ZTAocmVzdWx0X2RpcixERUdfZmlsZXNbMV0pKQoKcGFnZXMgPC0gbGlzdChsaXN0KEFjcm9zcz1kZ2VfVCR0b3ApLCBwYWlyd2lzZT1wYWlyd2lzZV9kZ2VfVCR0b3ApICU+JSBmbGF0dGVuKCkKd3JpdGUueGxzeChwYWdlcywgZmlsZT1wYXN0ZTAocmVzdWx0X2RpcixERUdfZmlsZXNbMl0pKQoKI0ZpbGVzIHdpdGggZmlsdGVyZWQgcC12YWx1ZSA8IDAuMDEgCiMgSGF2ZSB0byB1cGRhdGUgdGhlIHN1bW1hcnkgdGFibGUsIGhvd2V2ZXIgdGhlIGRlY2lkZVRlc3RzCiMgZnVuY3Rpb24gZG9lcyBub3QgcHJvdmlkZSBzdXBwb3J0IGZvciBwLXZhbHVlIGN1dG9mZnMgb25seSBGRFIKIyB0aGVyZWZvcmUgSSBuZWVkIHRvIHdyaXRlIGNvZGUgdG8gZ2V0IHRoZSBjb3JyZWN0IHN1bW1hcnkKCnBfTCA8LSBtYXAocGFpcndpc2VfZGdlX0wkdG9wWy0xXSwgfmZpbHRlcigueCwgYFBWYWx1ZWA8MC4wMSkpCnBfVCA8LSBtYXAocGFpcndpc2VfZGdlX1QkdG9wWy0xXSwgfmZpbHRlcigueCwgYFBWYWx1ZWA8MC4wMSkpCgpwYWdlcyA8LSBsaXN0KGxpc3QoQWNyb3NzPWRnZV9MJHRvcCksIHBhaXJ3aXNlPXBfTCkgJT4lIGZsYXR0ZW4oKQp3cml0ZS54bHN4KHBhZ2VzLCBmaWxlPXBhc3RlMChyZXN1bHRfZGlyLERFR19maWxlc1sxXSkpCgpwYWdlcyA8LSBsaXN0KGxpc3QoQWNyb3NzPWRnZV9UJHRvcCksIHBhaXJ3aXNlPXBfVCkgJT4lIGZsYXR0ZW4oKQp3cml0ZS54bHN4KHBhZ2VzLCBmaWxlPXBhc3RlMChyZXN1bHRfZGlyLERFR19maWxlc1syXSkpCmBgYAoKYGBge3IgU3VwcGwuIFRibC4gNSw2ICYgOSwxMCwgZXZhbD1GQUxTRX0KIyBFbnJpY2htZW50IEFjcm9zcwpkZl9hY3Jvc3MgPC0gZW5mcmFtZShsaXN0KEx1bWluYWw9ZW5yaWNoX0wsIFRpc3N1ZT1lbnJpY2hfVCkpICU+JSAgCiAgdW5uZXN0X2xvbmdlcih2YWx1ZSkgJT4lCiAgbXV0YXRlKHJlcyA9IG1hcCguJHZhbHVlLCAicmVzX2xpc3QiKSkgJT4lCiAgdW5uZXN0X2xvbmdlcihyZXMpICU+JQogIG11dGF0ZShyZXMgPSBtYXAocmVzLCB+cm93bmFtZXNfdG9fY29sdW1uKC54LCB2YXIgPSAiVGVybXMiKSkpICU+JQogIG11dGF0ZShyZXMgPSBtYXAocmVzLCB+ZmlsdGVyKC54LCBwdmFsdWUgPD0gMC4wMSkpKSAlPiUKICBncm91cF9ieShuYW1lLCB2YWx1ZV9pZCkgJT4lCiAgbXV0YXRlKG1vZCA9IHJvd19udW1iZXIoKSkgJT4lIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUocmVzID0gc2V0X25hbWVzKC4kcmVzLCBwYXN0ZTAoLiR2YWx1ZV9pZCwiX2dlbmVfbW9kdWxlXyIsLiRtb2QpKSkgJT4lCiAgZ3JvdXBfc3BsaXQobmFtZSkgJT4lIHNldF9uYW1lcyguLCBtYXAoLiwgfnVuaXF1ZSgueCRuYW1lKSkpCgp3cml0ZS54bHN4KGRmX2Fjcm9zc1tbMV1dJHJlcywgZmlsZT1wYXN0ZTAocmVzdWx0X2RpciwiU3VwcGwuVGJsLjA1IEVucmljaG1lbnRfQWNyb3NzX0x1bWluYWwiLCIueGxzeCIpKQp3cml0ZS54bHN4KGRmX2Fjcm9zc1tbMl1dJHJlcywgZmlsZT1wYXN0ZTAocmVzdWx0X2RpciwiU3VwcGwuVGJsLjA5IEVucmljaG1lbnRfQWNyb3NzX1Rpc3N1ZSIsIi54bHN4IikpCgojIEVucmljaG1lbnQgcGFpcndpc2UKZGZfcGFpcndpc2UgPC0gZW5mcmFtZShsaXN0KEdPPXBhaXJ3aXNlX0dPLCBLRUdHPXBhaXJ3aXNlX0tFR0cpKSAlPiUKICB1bm5lc3RfbG9uZ2VyKHZhbHVlKSAlPiUKICB1bm5lc3RfbG9uZ2VyKHZhbHVlLCBuYW1lc19yZXBhaXIgPSJ1bmlxdWUiKSAlPiUKICBtdXRhdGUodmFsdWUgPSBtYXAodmFsdWUsIH5maWx0ZXIoLngsIEZEUiA8PSAwLjA1KSkpICU+JQogIG11dGF0ZSh2YWx1ZSA9IHNldF9uYW1lcyguJHZhbHVlLCBwYXN0ZTAoLiRuYW1lLCJfIiwuJHZhbHVlX2lkLi4uMykpKSAlPiUKICBncm91cF9zcGxpdCh2YWx1ZV9pZC4uLjQpICU+JSBzZXRfbmFtZXMoLiwgbWFwKC4sIH51bmlxdWUoLngkdmFsdWVfaWQuLi40KSkpCiAgCndyaXRlLnhsc3goZGZfcGFpcndpc2VbWzFdXSR2YWx1ZSwgZmlsZT1wYXN0ZTAocmVzdWx0X2RpciwiU3VwcGwuVGJsLjA2IEVucmljaG1lbnRfUGFpcndpc2VfTHVtaW5hbCIsIi54bHN4IikpCndyaXRlLnhsc3goZGZfcGFpcndpc2VbWzJdXSR2YWx1ZSwgZmlsZT1wYXN0ZTAocmVzdWx0X2RpciwiU3VwcGwuVGJsLjEwIEVucmljaG1lbnRfUGFpcndpc2VfVGlzc3VlIiwiLnhsc3giKSkKYGBgCgpgYGB7ciBURi1QUEktQW5hbHlzaXMtZnVuY3Rpb24sIGluY2x1ZGU9RkFMU0V9CiMgZmlsZW5hbWUgPC0gREVHX2ZpbGVzWzFdCiMgZ3JfbmFtZSA8LSBncl9uYW1lWzFdCiMgb3V0ZmlsZSA8LSBlbnJpY2hSX2ZpbGVzWzFdClRGX1BQSV9hbmFseXNpcy5mdW4gPC0gZnVuY3Rpb24ocmVzdWx0X2RpciwgZmlsZW5hbWUsIGdyX25hbWUsIG91dGZpbGUpIHsKICAjIEdldCBERUcncyBmaWxlcyBhbmQgZmlsdGVyIHAtdmFsdWUgPCAwLjAxCiAgc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cyhwYXN0ZTAocmVzdWx0X2RpciwgZmlsZW5hbWUpKSAlPiUgc2V0X25hbWVzKC4pICU+JSAuWy1jKDE6MildCiAgZGV0YWJsZXMgPC0gbWFwKHNoZWV0cywgfnJlYWRfeGxzeChwYXN0ZTAocmVzdWx0X2RpciwgZmlsZW5hbWUpLCBzaGVldCA9IC54LCBjb2xfbmFtZXMgPSBUUlVFKSkgJT4lCiAgICBtYXAoLix+bXV0YXRlKC54LCBERSA9IGlmZWxzZSgueCRQVmFsdWUgPiBkZ2VfY3V0b2ZmICwgMCwgaWZlbHNlKC54JGxvZ0ZDIDwgMCwgLTEsIDEgKSkpKSAlPiUgCiAgICBtYXAoLix+ZmlsdGVyKC4sIC4kUFZhbHVlIDw9IDAuMDEpKQogICAgCiAgICAjIFJ1bm5pbmcgZW5yaWNobWVudHMgZm9yIHVwLSBvciBkb3duLXJlZ3VsYXRlZCBnZW5lcwogICAgc2F2ZV9sIDwtIGxpc3QoKQogICAgZm9yKGkgaW4gc2hlZXRzICl7CiAgICAgIG1lc3NhZ2UocGFzdGUwKCJQcm9jZXNzaW5nIGNvbXBhcmlzc29uICAgIiwgaSkpCiAgICAgIHRlbXAgPC0gZGV0YWJsZXNbW2ldXQogICAgICB0ZW1wIDwtIHRlbXBbICFkdXBsaWNhdGVkKHRlbXAkR2VuZXMpICYgIWlzLm5hKHRlbXAkR2VuZXMpICwgXQogICAgICB0ZW1wIDwtIG11dGF0ZSh0ZW1wLCByb3duYW1lcyA9IEdlbmVzKQogICAgICB0ZW1wIDwtIGNvbHVtbl90b19yb3duYW1lcyh0ZW1wLCB2YXIgPSAicm93bmFtZXMiKSAKICAgICAgCiAgICAgIHNhdmVfZiA8LSBsaXN0KCkKICAgICAgZm9yKGogaW4gYygxLC0xKSl7CiAgICAgICAgZ2VuZV9saXN0IDwtIHRlbXAkR2VuZXNbIHRlbXAkREUgPT0gaiBdCiAgICAgICAgCiAgICAgICAgI1RyYW5zY3JpcHRpb25fRmFjdG9yX1BQSXMKICAgICAgICBmIDwtIGVucmljaHIoZ2VuZXMgPSBnZW5lX2xpc3QsIGRhdGFiYXNlcyA9ICJUcmFuc2NyaXB0aW9uX0ZhY3Rvcl9QUElzIilbWzFdXQogICAgICAgIGlmIChpcy5kYXRhLmZyYW1lKGYpICYmIG5yb3coZik+MCl7CiAgICAgICAgICBmIDwtIGZbb3JkZXIoZiRQLnZhbHVlLGRlY3JlYXNpbmcgPSBGKSwgLWMoNTo2KV0KICAgICAgICAgIGYgPC0gY2JpbmQoIlRyYW5zY3JpcHRpb24gRmFjdG9yIj1mW1siVGVybSJdXSwgc2V0TmFtZXMobGlzdChsZW5ndGgoZ2VuZV9saXN0KSksIGNvbF9uYW1lKSwgZlssLWMoMSldKQogICAgICAgICAgZiA8LSBmW2YkUC52YWx1ZSA8IGVucmljaF9jdXRvZmYgJiBhcy5udW1lcmljKHNhcHBseShzdHJzcGxpdChmWywiT3ZlcmxhcCJdLCIvIiksIltbIiwgMSkpID49IG5vX2dlbmVzX2N1dG9mZixdCiAgICAgICAgICBmX24gPC0gc2V0X25hbWVzKGxpc3QoZiksIHBhc3RlMChpZmVsc2Uoaj09MSwidXAiLCJkb3duIikpKSAKICAgICAgICAgIHNhdmVfZiA8LSBhcHBlbmQoc2F2ZV9mLCBmX24pCgogICAgICAgIH1lbHNle2lmKGxlbmd0aChzYXZlX2YpID09IDApe3NhdmVfZiA8LSBhcHBlbmQoc2F2ZV9mLCBmX24pfSB9CiAgICAgIH0KICAgICAgbCA8LSBiaW5kX3Jvd3Moc2F2ZV9mLCAuaWQgPSAiUmVndWxhdGlvbiIpICU+JQogICAgICAgIGZpbHRlcihBZGp1c3RlZC5QLnZhbHVlIDw9IDAuMDUpCiAgICAgIGwgPC0gc2V0X25hbWVzKGxpc3QobCksIHBhc3RlMChpKSkKICAgICAgc2F2ZV9sIDwtIGFwcGVuZChzYXZlX2wsIGwgKSAKICAgIH0gCiAgICB3cml0ZS54bHN4KHNhdmVfbCwgZmlsZT1wYXN0ZTAocmVzdWx0X2Rpciwgb3V0ZmlsZSksIHJvdy5uYW1lcz1GQUxTRSkKICB9CmBgYAoKYGBge3IgVEYtUFBJLUFuYWx5c2lzLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpURl9QUElfYW5hbHlzaXMuZnVuKHJlc3VsdF9kaXIsIERFR19maWxlc1sxXSwgZ3JfbmFtZVsxXSwgZW5yaWNoUl9maWxlc1sxXSkgIyB3cml0ZXMgU3VwcGwuVGJsLjA3ClRGX1BQSV9hbmFseXNpcy5mdW4ocmVzdWx0X2RpciwgREVHX2ZpbGVzWzJdLCBncl9uYW1lWzJdLCBlbnJpY2hSX2ZpbGVzWzJdKSAjIHdyaXRlcyBTdXBwbC5UYmwuMTEKYGBgCgoKYGBge3IgcGxvdC1mdW5jdGlvbnMsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBHTy9LRUdHIEhFQVRNQVAgRlVOQ1RJT04gIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgc2FtcGxlX3VzZSA8LSBtZXRhZGF0YSRJRAojIGdyID0gIlRpc3N1ZV9nciIKIyBuYW1lID0gIlRpc3N1ZSIKIyBlbnJpY2ggPSBlbnJpY2hfVAojIGRiIDwtICJHTyIKIyBkYiA8LSAiS0VHRyIKIyBwbG90X2hlYXRtYXAuZnVuKGVucmljaF9ULCBkYiwgIlRpc3N1ZV9nciIsICJUaXNzdWUiKQpwbG90X2hlYXRtYXAuZnVuIDwtIGZ1bmN0aW9uKGVucmljaCwgZGIsIGdyLCBuYW1lLCBOPTMsIExheW91dCl7CiAgZmlnbGFiZWxzIDwtIGxldHRlcnMKICBkZiA8LSBuYS5vbWl0KG1ldGFkYXRhW3NhbXBsZV91c2UsIGMoZ3IsICJJRCIpXSkKICBkZiA8LSBhcnJhbmdlKGRmLCBkZlsxXSkKICBzYW1wbGVzIDwtIGRmWywgIklEIl0KICBuYW1lcyhzYW1wbGVzKSA8LSBkZlssIGdyXQogIAogIGNvbmYgPC0gcGx1Y2soZW5yaWNoLCBkYiwgImMiKQogIGggPC0gcGx1Y2soZW5yaWNoLCBkYiwgImgiKQogIGN1dHRvZmYgPC0gcGx1Y2soZW5yaWNoLCBkYiwgImN1dHRvZmYiKQogIHJlc19saXN0IDwtIHBsdWNrKGVucmljaCwgZGIsICJyZXNfbGlzdCIpCiAgdG9wX1RSWF9jb3VudHMgPC0gcGx1Y2soZW5yaWNoLCBkYiwgInRvcF9UUlhfY291bnRzIilbLHNhbXBsZXNdCiAgZ2VuZV9tb2R1bGUgPC0gcGx1Y2soZW5yaWNoLCBkYiwgImdlbmVfbW9kdWxlIikKICAKICBpZihtaXNzaW5nKExheW91dCkpewogICAgbGF5b3V0KG1hdHJpeChjKDEsMiwzLDQsNSwKICAgICAgICAgICAgICAgICAgMSwyLDMsNCwgNSksCiAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLG5jb2wgPSA1LGJ5cm93ID0gVCksd2lkdGhzID0gYygxLDMuNSwuMzYsOCw4KSkKICB9ZWxzZXtsYXlvdXQoTGF5b3V0W1sxXV0sTGF5b3V0W1syXV0sTGF5b3V0W1szXV0pfQoKICAjIERlbmRvZ3JhbQogIHBhcihtYXI9Yyg0LC4xLDIuNSwuMSkpICNib3R0b20sIGxlZnQsIHRvcCwgcmlnaHQgIAogIHBsb3QoIHJldihhcy5kZW5kcm9ncmFtKGgpKSAsIHhsaW09YyhtYXgoaCRoZWlnaHQpLC0uMiksaG9yaXogPSBULCBsZWFmbGFiID0gIm5vbmUiLHhheHM9ImkiLHlheHM9ImkiLGF4ZXM9VCkKICB0aXRsZSh4bGFiPSJIZWlnaHQiLCBsaW5lPTIpCiAgYWJsaW5lKHY9Y3V0dG9mZix4cGQ9Rixjb2w9InJlZCIsbHR5PTIpCiAgcG9pbnRzKCByZXAoLS4xLGxlbmd0aChnZW5lX21vZHVsZSkpLAogICAgICAgICAgc2VxKGxlbmd0aChnZW5lX21vZHVsZSksMSxsZW5ndGgub3V0ID0gbGVuZ3RoKGdlbmVfbW9kdWxlKSksCiAgICAgICAgICBjb2w9dGF4YV9wYWxbZmFjdG9yKGdlbmVfbW9kdWxlW2gkb3JkZXJdKV0sCiAgICAgICAgICBwY2g9MTUsY2V4PS41LHhwZD1GKQogIAogICNhZGQgbGFiZWwKICBhZGRfbGV0dGVyKGZpZ2xhYmVsc1sxXSk7IGZpZ2xhYmVscyA8LSBmaWdsYWJlbHNbLTFdCiAgCiAgIyBIZWF0bWFwCiAgaW1hZ2UoIHQodG9wX1RSWF9jb3VudHNbaCRvcmRlcixwdWxsKGRmLCAiSUQiKV1bbnJvdyh0b3BfVFJYX2NvdW50cyk6MSxdKSwKICAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShjKCJuYXZ5IiwibmF2eSIsImdyZXk5NSIsImZpcmVicmljazQiLCJmaXJlYnJpY2s0IikgKSg5OSksCiAgICAgICAgIGJyZWFrcyA9IHNlcSgtNSw1LGxlbmd0aC5vdXQgPSAxMDApLGF4ZXM9RikKICBtdGV4dCgiICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhbmQgS0VHRy9HTyBwYXRod2F5cyIsIHNpZGU9MywgbGFzID0gMSwgY2V4ID0gLjcsIGxpbmUgPTEuNSx4cGQ9VCwgZm9udCA9IDIpCiAgdGl0bGUoeGxhYj0iU3R1ZHkgR3JvdXBzIiwgbGluZT0xKQogIAogICMgU3R1ZHkgR3JvdXAgYnJhY2tldHMKICBlbmQgPC0gdGFibGUocGFsW2ZhY3RvcihuYW1lcyhzYW1wbGVzKSlbIG9yZGVyKGRmWzFdKV1dKQogIGVuZCA8LSBlbmRbb3JkZXIoZmFjdG9yKG5hbWVzKGVuZCksIGxldmVscyA9IHBhbCkpXQogIGVuZCA8LSBtYXBfZGJsKGN1bXN1bShlbmQpLCB+ICgueCAqIChwYXIoInVzciIpWzJdKS9sZW5ndGgoc2FtcGxlcyktLjAxNykgKQogIHN0YXJ0IDwtIGMoMCwgbWFwX2RibChlbmRbMTo0XSwgfi54KzAuMDE3KSkKICBlbmQgPC0gYyhlbmRbMTpsZW5ndGgoZW5kKS0xXSwgcGFyKCJ1c3IiKVsyXS0uMDA1KQogIAogIGF4aXMoMSwgYXQgPSBjKHN0YXJ0LCBlbmQpLCBsYWJlbCA9IEYsIHBvcyA9MS4wMjkgLCB4cGQ9VCwgY29sPSJ3aGl0ZSIsY29sLnRpY2tzPSJibGFjayIpCiAgbWFwMihzdGFydCwgZW5kLCB+bGluZXMoeD1jKC55LCAueCksIHk9IGMoMS4wMjksIDEuMDI5KSwgeHBkPVQsIGNleD0uOCkpCiAgIyB0ZXh0IGxhYmVscwogIHQgPC0gbWFwMihzdGFydCwgZW5kLCB+KC54Ky55KS8yKQogIHBhcihtYXI9YygzLC4yLDIsLjIpKSAjYm90dG9tLCBsZWZ0LCB0b3AsIHJpZ2h0ICAKICBtYXAyKHQsbGV2ZWxzKGZhY3RvcihuYW1lcyhzYW1wbGVzKSkpLCB+dGV4dCh4PS54LCB5PTEuMDQ1LCAueSx4cGQ9VCwgY2V4PS44KSkKICAKICAjIyBNZXRhIGluZm8gYmFycwogIHBhcihtYXI9YygzLC4xLDIsLjEpKSAjYm90dG9tLCBsZWZ0LCB0b3AsIHJpZ2h0ICAKICBtYXAoYyguMDAyNSwgLjAwNyksIH5wb2ludHMoIHNlcSgwLDEsbGVuZ3RoLm91dCA9IGxlbmd0aChzYW1wbGVzKSkscmVwKHBhcigidXNyIilbNF0sbGVuZ3RoKHNhbXBsZXMpKSsueCwKICAgICAgICAgIGNvbD1wYWxbZmFjdG9yKG5hbWVzKHNhbXBsZXMpKVsgb3JkZXIoZGZbMV0pXV0sCiAgICAgICAgICBwY2g9MTUseHBkPUYsY2V4PS4zKSApCiAgcG9pbnRzKCBzZXEoMCwxLGxlbmd0aC5vdXQgPSBuY29sKHRvcF9UUlhfY291bnRzKSkscmVwKHBhcigidXNyIilbM10sbmNvbCh0b3BfVFJYX2NvdW50cykpLS4wMDgsCiAgICAgICAgICBjb2w9YygidG9tYXRvIiwib3JhbmdlIiwiI2Q3ZDdkNyIpWyBmYWN0b3IobWV0YWRhdGFbc2FtcGxlcywiQlZfRGlhZ25vc2lzX3YzIl1bb3JkZXIoZGZbMV0pXSkgXSwKICAgICAgICAgIHBjaD0xNSx4cGQ9RixjZXg9LjMpIAogIHBvaW50cyggc2VxKDAsMSxsZW5ndGgub3V0ID0gbmNvbCh0b3BfVFJYX2NvdW50cykpLHJlcChwYXIoInVzciIpWzNdLG5jb2wodG9wX1RSWF9jb3VudHMpKS0uMDIyLAogICAgICAgICAgY29sPSBjKCIjZDdkN2Q3IiwidG9tYXRvIilbIGZhY3RvcihtZXRhZGF0YVtzYW1wbGVzLCJISVZzdGF0dXMiXVtvcmRlcihkZlsxXSldKSBdLAogICAgICAgICAgcGNoPTE1LHhwZD1GLGNleD0uMykKICAKICAjIyBHZW5lIG1vZHVsZSBlbnJpY2htZW50CiAgbmFtZXMocmVzX2xpc3QpIDwtIHVuaXF1ZSggZ2VuZV9tb2R1bGVbaCRvcmRlcl0gKQogIAogIHB2YWx1ZXMgPC0gdW5saXN0KGxhcHBseShyZXNfbGlzdCxmdW5jdGlvbih4KXsgLWxvZzEwKHgkcHZhbHVlKSBbMTpOXSB9KSkKICAjIHB2YWx1ZXMgPC0gdW5saXN0KGxhcHBseShyZXNfbGlzdCxmdW5jdGlvbih4KXsgeCRqYWNjYXJkX2luZGV4IFsxOk5dIH0pKQogIHB2YWx1ZXNbaXMubmEocHZhbHVlcyldIDwtIDAKICB0ZXJtcyA8LSB1bmxpc3QobGFwcGx5KHJlc19saXN0LGZ1bmN0aW9uKHgpeyByb3duYW1lcyh4KSBbMTpOXSB9KSkKICB0ZXJtc1tpcy5uYSh0ZXJtcyldIDwtICIiCiAgdGVybXMgPC0gZ3N1YigiXyIsICIgIiwgdGVybXMpCiAgdGVybXMgPC0gZ3N1YigiKEdPIHxLRUdHICl8KFxcdyspIiwgIlxcMVxcTFxcMiIsIHRlcm1zLCBwZXJsID0gVFJVRSkKICB0ZXJtcyA8LSBnc3ViKCJlbmRvcGxhc21pYyByZXRpY3VsdW0iLCAiRVIiLCB0ZXJtcywgcGVybCA9IFRSVUUpCiAgZ2VuZXMgPC0gdW5saXN0KGxhcHBseShyZXNfbGlzdCxmdW5jdGlvbih4KXsgeCRnZW5lcyBbMTpOXSB9KSkKICBnZW5lc1tpcy5uYShnZW5lcyldIDwtICIiCiAgCiAgI3B2YWx1ZXMgPC0gc2V0TmFtZXMocHZhbHVlcyxwYXN0ZTAodGVybXMsIiAoIixnZW5lcywiKSIpKQogIHB2YWx1ZXMgPC0gc2V0TmFtZXMocHZhbHVlcyxwYXN0ZTAodGVybXMsIiIpKQogIG1vZHVsZV9jb2xvciA8LSB1bmxpc3QobGFwcGx5KG5hbWVzKHJlc19saXN0KSxmdW5jdGlvbih4KXsgcmVwKHgsTikgfSkpCiAgCiAgdGVtcCA8LSBmYWN0b3IoIHJldihnZW5lX21vZHVsZSksIGxldmVscyA9IHVuaXF1ZSggZ2VuZV9tb2R1bGVbaCRvcmRlcl0gKSkKICBwYXIobWFyPWMoNCwwLDIuNSwuMSkpICNib3R0b20sIGxlZnQsIHRvcCwgcmlnaHQgIAogIHBsb3Rfc2Fua2V5KCBkYXRhLmZyYW1lKHRlbXAsdGVtcCksIHBhbCA9IHRheGFfcGFsW2FzLm51bWVyaWMobGV2ZWxzKHRlbXApKV0sIAogICAgICAgICAgICAgICB1c2VfdzIgPSBGICwgcGxvdF9sYWJlbHMgPSBUICxnYXB2ID0gLjAxLGdhcDJ2ID0gMCAseGF4cz0iaSIsCiAgICAgICAgICAgICAgIHlheHM9ImkiLHBsb3Rfd2VpZ2h0cyA9IEYpCiAgCiAgdGV4dChwYXIoInVzciIpWzFdKzAuMDA4LHBhcigidXNyIilbM10tLjAwOCxsYWJlbHMgPSAiICAgICBCViIsY2V4PS42LCB4cGQ9VCkKICB0ZXh0KHBhcigidXNyIilbMV0rMC4wMDgscGFyKCJ1c3IiKVszXS0uMDI4LGxhYmVscyA9ICIgICAgICBISVYiLGNleD0uNiwgeHBkPVQpCiAgCiAgIyBLRUdHCiAgaWYobmFtZSA9PSAiVGlzc3VlIikKICB7cGFyKG1hcj1jKDQsLjEsMi41LDEzKSl9ZWxzZSAjYm90dG9tLCBsZWZ0LCB0b3AsIHJpZ2h0ICAKICAgICAge3BhcihtYXI9Yyg0LC4xLDIuNSw4KSl9CiAgYmFycGxvdCggcmV2KHB2YWx1ZXMpICwgaG9yaXogPSBUICwgY29sPSB0YXhhX3BhbFtmYWN0b3IocmV2KG1vZHVsZV9jb2xvcikpXSwKICAgICAgICAgICB4YXhzPSJpIix5YXhzPSJpIix4bGltPWMoMCwxLjIqbWF4KHB2YWx1ZXMpKSx5bGFiPSIiLGxhcz0xLAogICAgICAgICAgIG5hbWVzLmFyZyA9ICIiLHhwZCA9IEZBTFNFKQogIGFibGluZSh2PTIseHBkPUYsY29sPSJyZWQiLGx0eT0yKQogIHBvaW50cyggcmV2KHB2YWx1ZXMpLCBzZXEoMSxsZW5ndGgocHZhbHVlcykgKSoxLjItLjUscGNoPTIxLAogICAgICAgICAgYmc9dGF4YV9wYWxbZmFjdG9yKHJldihtb2R1bGVfY29sb3IpKV0gKQogIHRpdGxlKHhsYWI9Ii1sb2cxMChwLXZhbHVlKSIsIGxpbmU9MikKICB0ZXh0KCByZXYocHZhbHVlcykrc3Ryd2lkdGgoIkwiKSAsIHNlcSgxLGxlbmd0aChwdmFsdWVzKSApKjEuMi0uNSwgCiAgICAgICAgYWRqPTAsY2V4PS45LHhwZD1ULHJldihnc3ViKCJcXChcXCkiLCIiLG5hbWVzKHB2YWx1ZXMpKSApKQogIHRleHQoIHJldihwdmFsdWVzKStzdHJ3aWR0aCgiTCIpICwgc2VxKDEsbGVuZ3RoKHB2YWx1ZXMpICkqMS4yLS41LCAKICAgICAgICBsYWJlbHMgPSByZXYoc3ViKCIgWyhdLioiLCIiLG5hbWVzKHB2YWx1ZXMpKSApLCBhZGo9MCxjZXg9LjksCiAgICAgICAgY29sID0gcGFzdGUwKHRheGFfcGFsW2ZhY3RvcihyZXYobW9kdWxlX2NvbG9yKSldLDkwKSAseHBkPVQpCiAgCiAgIyBHTwogIHJlc19saXN0IDwtIHBsdWNrKGVucmljaCwgIkdPIiwgInJlc19saXN0IikKICAKICAjIyBHZW5lIG1vZHVsZSBlbnJpY2htZW50CiAgbmFtZXMocmVzX2xpc3QpIDwtIHVuaXF1ZSggZ2VuZV9tb2R1bGVbaCRvcmRlcl0gKQogIHB2YWx1ZXMgPC0gdW5saXN0KGxhcHBseShyZXNfbGlzdCxmdW5jdGlvbih4KXsgLWxvZzEwKHgkcHZhbHVlKSBbMTpOXSB9KSkKCiAgcHZhbHVlc1tpcy5uYShwdmFsdWVzKV0gPC0gMAogIHRlcm1zIDwtIHVubGlzdChsYXBwbHkocmVzX2xpc3QsZnVuY3Rpb24oeCl7IHJvd25hbWVzKHgpIFsxOk5dIH0pKQogIHRlcm1zW2lzLm5hKHRlcm1zKV0gPC0gIiIKICB0ZXJtcyA8LSBnc3ViKCJfIiwgIiAiLCB0ZXJtcykKICB0ZXJtcyA8LSBnc3ViKCIoR08gfEtFR0cgKXwoXFx3KykiLCAiXFwxXFxMXFwyIiwgdGVybXMsIHBlcmwgPSBUUlVFKQogIHRlcm1zIDwtIGdzdWIoImVuZG9wbGFzbWljIHJldGljdWx1bSIsICJFUiIsIHRlcm1zLCBwZXJsID0gVFJVRSkKICB0ZXJtcyA8LSBnc3ViKCJlc3RhYmxpc2htZW50IG9mICIsICIiLCB0ZXJtcywgcGVybCA9IFRSVUUpCiAgZ2VuZXMgPC0gdW5saXN0KGxhcHBseShyZXNfbGlzdCxmdW5jdGlvbih4KXsgeCRnZW5lcyBbMTpOXSB9KSkKICBnZW5lc1tpcy5uYShnZW5lcyldIDwtICIiCiAgcHZhbHVlcyA8LSBzZXROYW1lcyhwdmFsdWVzLHBhc3RlMCh0ZXJtcywiIikpCiAgbW9kdWxlX2NvbG9yIDwtIHVubGlzdChsYXBwbHkobmFtZXMocmVzX2xpc3QpLGZ1bmN0aW9uKHgpeyByZXAoeCxOKSB9KSkKICAKICBiYXJwbG90KCByZXYocHZhbHVlcykgLCBob3JpeiA9IFQgLCBjb2w9IHRheGFfcGFsW2ZhY3RvcihyZXYobW9kdWxlX2NvbG9yKSldLAogICAgICAgICAgIHhheHM9ImkiLHlheHM9ImkiLHhsaW09YygwLDEuMiptYXgocHZhbHVlcykpLHlsYWI9IiIsbGFzPTEsCiAgICAgICAgICAgbmFtZXMuYXJnID0gIiIseHBkID0gRkFMU0UpCiAgYWJsaW5lKHY9Mix4cGQ9Rixjb2w9InJlZCIsbHR5PTIpCiAgcG9pbnRzKCByZXYocHZhbHVlcyksIHNlcSgxLGxlbmd0aChwdmFsdWVzKSApKjEuMi0uNSxwY2g9MjEsCiAgICAgICAgICBiZz10YXhhX3BhbFtmYWN0b3IocmV2KG1vZHVsZV9jb2xvcikpXSApCiAgdGl0bGUoeGxhYj0iLWxvZzEwKHAtdmFsdWUpIiwgbGluZT0yKQogIHRleHQoIHJldihwdmFsdWVzKStzdHJ3aWR0aCgiTCIpICwgc2VxKDEsbGVuZ3RoKHB2YWx1ZXMpICkqMS4yLS41LCAKICAgICAgICBhZGo9MCxjZXg9LjkseHBkPVQscmV2KGdzdWIoIlxcKFxcKSIsIiIsbmFtZXMocHZhbHVlcykpICkpCiAgdGV4dCggcmV2KHB2YWx1ZXMpK3N0cndpZHRoKCJMIikgLCBzZXEoMSxsZW5ndGgocHZhbHVlcykgKSoxLjItLjUsIAogICAgICAgIGxhYmVscyA9IHJldihzdWIoIiBbKF0uKiIsIiIsbmFtZXMocHZhbHVlcykpICksIGFkaj0wLGNleD0uOSwKICAgICAgICBjb2wgPSBwYXN0ZTAodGF4YV9wYWxbZmFjdG9yKHJldihtb2R1bGVfY29sb3IpKV0sOTApICx4cGQ9VCkKfQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEFTU0VNQkxFIFBMT1RTIEZVTkNUSU9OICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgY29tcGFyaXNvbiA8LSBzaGVldHMKIyBlbnJpY2htZW50X2RiIDwtICJURl9QUElfZW5yaWNobWVudCIKIyBkZWdzIDwtIGVucmljaF9UCiMgZ3JvdXAgPC0gIlRpc3N1ZV9nciIgCiMgZ3JfbmFtZSA8LSAiVGlzc3VlIgphcnJhbmdlX3Bsb3RzLmZ1biA8LSBmdW5jdGlvbihkZWdzLCBncm91cCwgZ3JfbmFtZSwgY29tcGFyaXNvbiwgZW5yaWNobWVudF9kYiwgZmlsZSwgTGF5b3V0KXsKICAKICAjIyMgQQogICMjIyMjIyMjIyMjIyMjIyMjIyMKICAjIEdPL0tFR0cgSEVBVE1BUCAjCiAgIyMjIyMjIyMjIyMjIyMjIyMjIwogIHBsb3RfaGVhdG1hcC5mdW4oZGVncywgIktFR0ciLCBncm91cCwgZ3JfbmFtZSwgTGF5b3V0PUxheW91dCkKICAKICAKICAjIyMgQgogICMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICMgVEYgUFBJIEVOUklDSE1FTlQgIwogICMjIyMjIyMjIyMjIyMjIyMjIyMjIwogICMgQ3JlYXRlIHBsb3QgZm9yIGVhY2ggZW5yaWNobWVudAogIG4gPC0gMTAKICBmb3IoIHggaW4gY29tcGFyaXNvbiApewogIGZvciggaSBpbiBlbnJpY2htZW50X2RiICl7CiAgICBERCA8LSBJbmYKICAgIFVVIDwtIDAKICAgIG5hbWVzX0REIDwtICIiCiAgICBuYW1lc19VVSA8LSAiIgogICAgCiAgICBmX0RPV04gPC0gcmVhZF94bHN4KHBhc3RlMChyZXN1bHRfZGlyLCBmaWxlKSwgc2hlZXQgPSB4KSAlPiUgZmlsdGVyKFJlZ3VsYXRpb24gPT0gImRvd24iKQogICAgZl9VUCA8LSByZWFkX3hsc3gocGFzdGUwKHJlc3VsdF9kaXIsIGZpbGUpLCBzaGVldCA9IHgpICU+JSBmaWx0ZXIoUmVndWxhdGlvbiA9PSAidXAiKQogICAgCiAgICBpZiAoaXMuZGF0YS5mcmFtZShmX0RPV04pICYmIG5yb3coZl9ET1dOKT4wKXsKICAgICAgdGVtcERfZSA8LSBmX0RPV04KICAgICAgREQgPC0gbG9nMTAodGVtcERfZSRQLnZhbHVlKVsxOm1pbihuLGxlbmd0aCh0ZW1wRF9lJFAudmFsdWUpKV0KICAgICAgbmFtZXNfREQgPC0gKGFzLmNoYXJhY3Rlcih0ZW1wRF9lJCJUcmFuc2NyaXB0aW9uIEZhY3RvciIpKVsxOm1pbihuLGxlbmd0aCh0ZW1wRF9lJFAudmFsdWUpKV0KICAgIH0KICAgIGlmIChpcy5kYXRhLmZyYW1lKGZfRE9XTikgJiYgbnJvdyhmX0RPV04pPjApewogICAgICB0ZW1wVV9lIDwtIGZfVVAKICAgICAgVVUgPC0gcmV2KC1sb2cxMCh0ZW1wVV9lJFAudmFsdWUpWzE6bWluKG4sbGVuZ3RoKHRlbXBVX2UkUC52YWx1ZSkpXSkKICAgICAgbmFtZXNfVVUgPC0gcmV2KGFzLmNoYXJhY3Rlcih0ZW1wVV9lJCJUcmFuc2NyaXB0aW9uIEZhY3RvciIpWzE6bWluKG4sbGVuZ3RoKHRlbXBVX2UkUC52YWx1ZSkpXSkKICAgIH0KICAgIAogICAgY29tYiA8LSBjKCBERC9hYnMobWF4KGFicyhERCkpKSAsIFVVL2FicyhtYXgoYWJzKFVVKSkpICkKICAgIGNvbWIgPC0gcmVwbGFjZV9uYShjb21iLCAwKQogIAogICAgaWYgKGlkZW50aWNhbChjb21iLCBjKDAsMCkpKXtuZXh0fQoKICAgIHBhcihtYXIgPSBjKDEuMiwgNC43LCAyLjIsIDEpKSAgI2JvdHRvbSwgbGVmdCwgdG9wLCByaWdodAogICAgYmFycGxvdCggYyhyZXAoTkEsIGVhY2g9MjAtbGVuZ3RoKGNvbWIpKSwgY29tYiksICAKICAgICAgICAgICAgIHhsaW09YygtMS4xLDEuMSksIGNleC5uYW1lcyA9IC45LAogICAgICAgICAgICAgbmFtZXMuYXJnID0gYyhyZXAoIiIsIGVhY2g9MjAtbGVuZ3RoKGNvbWIpKSxuYW1lc19ERCwgbmFtZXNfVVUgKSwgCiAgICAgICAgICAgICBob3JpeiA9IFQsIGxhcz0gMSwgYm9yZGVyPU5BLCB4YXh0PSduJywgbGluZT0tLjIsCiAgICAgICAgICAgICBjb2wgPSBjKHJlcChOQSwgZWFjaD0yMC1sZW5ndGgoY29tYikpLCAKICAgICAgICAgICAgICAgICAgICAgcmV2KGNvbG9yUmFtcFBhbGV0dGUoIGMoImZpcmVicmljazMiLCJncmF5IiwibmF2eSIpICkoMTkpKVsoY29tYisxKSo5KzFdKQogICAgKQogICAgdGl0bGUobWFpbj1wYXN0ZSh4LCBzdHJfcmVwbGFjZV9hbGwoaSwgIl8iLCIgIiksIHNlcD0iXG4iKSwgbGluZSA9IDAuMSwgY2V4Lm1haW49MSkKICAgIAogICAgaWYoeCA9PSAiTDEtTDIiIHwgeCA9PSAiVDEtVDIiKXthZGRfbGV0dGVyKCJiIil9CiAgICBwb2ludHNfeSA8LSByZXYoc2VxKHBhcigidXNyIilbNF0tMS40NSwgYnk9LTEuMiwgbGVuZ3RoPWxlbmd0aChjKFVVLEREKSkpKQogICAgICAgICAgICAgcG9pbnRzKCBjb21iICwgcG9pbnRzX3ksCiAgICAgICAgICAgICAgICAgICAgIGJnPWNvbG9yUmFtcFBhbGV0dGUoIGMoIm5hdnkiLCJncmF5IiwiZmlyZWJyaWNrMyIpICkoMTkpWyhjb21iKzEpKjkrMV0sCiAgICAgICAgICAgICAgICAgICAgIHBjaD0yMSwgY29sPSJibGFjayIsY2V4PTEuNSkKICAgICAgICAgICAgIGxpbmVzKHg9YygwLCAwKSwgeT0gYyhwb2ludHNfeVsxXS0uNiwgcGFyKCJ1c3IiKVs0XS0xKSkgCiAgICAgICAgICAgICBsaW5lcyh4PWMoLTIvYWJzKG1heChhYnMoREQpKSksLTIvYWJzKG1heChhYnMoREQpKSkpLCAKICAgICAgICAgICAgICAgICAgIHk9IGMocG9pbnRzX3lbMV0tLjYsIHBhcigidXNyIilbNF0tMSksIGx0eT1jKDMpKSAjIHB2YWw9MC4wMQogICAgICAgICAgICAgbGluZXMoeD1jKDIvYWJzKG1heChhYnMoVVUpKSksMi9hYnMobWF4KGFicyhVVSkpKSksIAogICAgICAgICAgICAgICAgICAgeT0gYyhwb2ludHNfeVsxXS0uNiwgcGFyKCJ1c3IiKVs0XS0xKSwgbHR5PWMoMykpICMgcHZhbD0wLjAxCiAgICAgICAgICAgICB0ZXh0KDAscG9pbnRzX3lbMV0tMS41LCAiLWxvZzEwIHAtdmFsdWUiLCB4cGQ9VCkKICAgIH0KICB9Cn0KYGBgCgpgYGB7ciBGaWd1cmUgNCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD02fQojIExheW91dApsIDwtIGxpc3QobWF0ID0gbWF0cml4KGMoMSwyLDMsNCw0LDQsNSw1LDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAxLDIsMyw0LDQsNCw1LDUsNSwKICAgICAgICAgICAgICAgICAgICAgICAgIDYsNiw2LDcsNyw4LDgsOSw5LAogICAgICAgICAgICAgICAgICAgICAgICAgMTAsMTAsMTAsMTEsMTEsMTIsMTIsMTMsMTMpLAogICAgICAgICAgICAgICAgbnJvdyA9IDMsbmNvbCA9IDksYnlyb3cgPSBUKSwKICAgICAgICAgIHdpZHRocyA9IGMoMS4xNCwzLjUsLjM2LDIuNSwyLjUsMi41LDIuNSwyLjUsMi41KSwKICAgICAgICAgIGhlaWd0aCA9IGMoMSwxLDEuNSkKICAgICAgICAgICkKI2xheW91dC5zaG93KGxheW91dChsW1sxXV0sbFtbMl1dLGxbWzNdXSkpCgpzaGVldHMgPC0gZXhjZWxfc2hlZXRzKHBhc3RlMChyZXN1bHRfZGlyLCBERUdfZmlsZXNbMV0pKSAlPiUgc2V0X25hbWVzKC4pICU+JSAuWy1jKDE6MildCmFycmFuZ2VfcGxvdHMuZnVuKGVucmljaF9MLCAiTHVtaW5hbF9nciIsICJMdW1pbmFsIiwgc2hlZXRzLCAiVEZfUFBJX2VucmljaG1lbnQiLCBlbnJpY2hSX2ZpbGVzWzFdLCBMYXlvdXQgPSBsKQoKIyB0ZXN0IGZpZ3VyZQojIGRldi5jb3B5MnBkZihmaWxlPXBhc3RlMCgiLi90ZXN0LnBkZiIpLAojICAgICB3aWR0aCA9IDYuNiwKIyAgICAgaGVpZ2h0ID0gNiwgcGFwZXIgPSAiYTQiCiMgICAgICkKYGBgCgpgYGB7ciBGaWd1cmUgNSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD02LCBjcm9wID0gVFJVRX0Ka25pdHI6OmtuaXRfaG9va3Mkc2V0KGNyb3AgPSBrbml0cjo6aG9va19wZGZjcm9wKQojIExheW91dApsIDwtIGxpc3QobWF0ID0gbWF0cml4KGMoMSwyLDMsNCw0LDQsNSw1LDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAxLDIsMyw0LDQsNCw1LDUsNSwKICAgICAgICAgICAgICAgICAgICAgICAgIDYsNiw2LDcsNyw4LDgsOSw5LAogICAgICAgICAgICAgICAgICAgICAgICAgMTAsMTAsMTAsMTEsMTEsMTIsMTIsMTMsMTMpLAogICAgICAgICAgICAgICAgbnJvdyA9IDMsbmNvbCA9IDksYnlyb3cgPSBUKSwKICAgICAgICAgIHdpZHRocyA9IGMoMS4xNCwzLjUsLjM2LDIuNSwyLjUsMi41LDIuNSwyLjUsMi41KSwKICAgICAgICAgIGhlaWd0aCA9IGMoMSwxLDEuNSkKICAgICAgICAgICkKCnNoZWV0cyA8LSBleGNlbF9zaGVldHMocGFzdGUwKHJlc3VsdF9kaXIsIERFR19maWxlc1syXSkpICU+JSBzZXRfbmFtZXMoLikgJT4lIC5bLWMoMToyKV0KYXJyYW5nZV9wbG90cy5mdW4oZW5yaWNoX1QsICJUaXNzdWVfZ3IiLCAiVGlzc3VlIiwgc2hlZXRzLCAiVEZfUFBJX2VucmljaG1lbnQiLCBlbnJpY2hSX2ZpbGVzWzJdLCBMYXlvdXQgPSBsKQoKIyBkZXYuY29weTJwZGYoZmlsZT1wYXN0ZTAoIi4vdGVzdC5wZGYiKSwKIyAgICAgd2lkdGggPSA2LjYsCiMgICAgIGhlaWdodCA9IDYsIHBhcGVyID0gImE0IgojICAgICApCmBgYAoKKipGaWd1cmUuIDQtNS4gQ2hhcmFjdGVyaXphdGlvbiBvZiB0aGUgaG9zdCB0cmFuc2NyaXB0b21lIGFzIHN0cmF0aWZpZWQgYnkgdGhlIGx1bWluYWwgbWljcm9iaW9tZSBzdHVkeSBncm91cHMuKiogVGhlIGx1bWluYWwgc2FtcGxlcyB3ZXJlIGFzc2Vzc2VkIGZvciBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFjcm9zcyB0aGUgc3R1ZHkgZ3JvdXBzLiAqKmEqKiBEaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzIHdhcyBhcHBsaWVkIGFjcm9zcyB0aGUgZml2ZSBsdW1pbmFsIHN0dWR5IGdyb3Vwcy4gU2lnbmlmaWNhbnQgREVHcyAocC12YWx1ZSA8IDAuMDEpIHdlcmUgZGl2aWRlZCBpbnRvIHNpeCBtb2R1bGVzIGJ5IGhpZXJhcmNoaWNhbCBhZ2dsb21lcmF0aXZlIGNsdXN0ZXJpbmcgdXNpbmcgaW52ZXJzZSBQZWFyc29u4oCZcyBjb3JyZWxhdGlvbiBhcyBkaXN0YW5jZSBtZWFzdXJlIGFuZCBXYXJk4oCZcyBtZXRob2QgKOKAnHdhcmQuIEQy4oCdKSBmb3IgbGlua2FnZS4gRW5yaWNobWVudCBhbmFseXNpcyB3YXMgcGVyZm9ybWVkIG9uIGVhY2ggbW9kdWxlIHVzaW5nIGJvdGggdGhlIEtFR0cgYW5kIEdPIGRhdGFiYXNlcy4gVGhlIHRocmVlIG1vc3Qgc2lnbmlmaWNhbnQgdGVybXMgd2VyZSBpbmNsdWRlZCBpbiB0aGUgaGVhdG1hcC4gKipiKiogUGFpcndpc2UgZW5yaWNobWVudCBhbmFseXNpcyBvZiBwcm90ZWluLXByb3RlaW4gaW50ZXJhY3Rpb25zIG9mIHRyYW5zY3JpcHRpb24gZmFjdG9ycyAoVEYtUFBJKS4gVG9wLTEwIHVwLSBhbmQgZG93biByZWd1bGF0ZWQgdHJhbnNjcmlwdGlvbiBmYWN0b3JzIHdpdGggcC12YWx1ZSA8IDAuMDEgd2VyZSBpbmNsdWRlZCBpbiB0aGUgYmFyIHBsb3RzCgpgYGB7ciBTdXBwbC4gVGJsLiAxMn0KbWV0YWRhdGEgPC0gbWV0YWRhdGEgJT4lIAogIG11dGF0ZShMX1RfZ3JvdXBzID0gcGFzdGUwKC4kTHVtaW5hbF9nciwgLiRUaXNzdWVfZ3IpKSAlPiUKICBtdXRhdGUoTF9UX2dyb3VwcyA9IGlmZWxzZShncmVwbCgiTDJUMnxMMlQzIiwgLiRMX1RfZ3JvdXBzKSwgLiRMX1RfZ3JvdXBzLCBOQSkpCgpkZ2VfTFQgPC0gZWRnUl9kZ2UuZnVuKCJMX1RfZ3JvdXBzIiwgY29uZm91bmQ9VCkKZW5yaWNoX0xUIDwtIGRiICU+JQogIG1hcCguLCB+Z2VuZV9tb2RfZW5yaWNoLmZ1bihkZ2VfTFQkdG9wLGRnZV9MVCR5LGRnZV9MVCRjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYiA9IC54LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9uYW1lID0gIkxfVF9ncm91cHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXR0b2ZmID0gYyhHTz0yLCBLRUdHPTIpICMgYyhHTz0yLCBLRUdHPTIuNykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkKCiMgUGxvdCB0aGUgTDJUMiB2cyBMMlQzIGhlYXRtYXA6CiNwYWwgPC0gYygiIzU0YmE2MyIsIiNhZDU4YzYiLCIjZDAzZTdhIiwiIzRjYjZhOSIsIiNiYjZmYWMiLCIjY2NhNDQyIiwiIzhmYjUzYyIsIiM2YTdlY2QiLCIjNjM4MTNlIiwiI2M0NjU3MCIsIiNiMzc0M2UiLCIjZDM1MjM4IikKI3Bsb3RfaGVhdG1hcC5mdW4oZW5yaWNoX0xULCAiS0VHRyIsICJMX1RfZ3JvdXBzIiwgIkxfVF9ncm91cHMiKQoKdCA8LSBkZ2VfTFQkdG9wICU+JSBmaWx0ZXIoUFZhbHVlIDw9IDAuMDEpCgpkZl9hY3Jvc3MgPC0gZW5mcmFtZShsaXN0KEx0b1Q9ZW5yaWNoX0xUKSkgJT4lICAKICB1bm5lc3RfbG9uZ2VyKHZhbHVlKSAlPiUKICBtdXRhdGUocmVzID0gbWFwKC4kdmFsdWUsICJyZXNfbGlzdCIpKSAlPiUKICB1bm5lc3RfbG9uZ2VyKHJlcykgJT4lCiAgbXV0YXRlKHJlcyA9IG1hcChyZXMsIH5yb3duYW1lc190b19jb2x1bW4oLngsIHZhciA9ICJUZXJtcyIpKSkgJT4lCiAgbXV0YXRlKHJlcyA9IG1hcChyZXMsIH5maWx0ZXIoLngsIHB2YWx1ZSA8PSAwLjAxKSkpICU+JQogIGdyb3VwX2J5KG5hbWUsIHZhbHVlX2lkKSAlPiUKICBtdXRhdGUobW9kID0gcm93X251bWJlcigpKSAlPiUgdW5ncm91cCgpICU+JQogIG11dGF0ZShyZXMgPSBzZXRfbmFtZXMoLiRyZXMsIHBhc3RlMCguJHZhbHVlX2lkLCJfZ2VuZV9tb2R1bGVfIiwuJG1vZCkpKSAlPiUKICBncm91cF9zcGxpdChuYW1lKSAlPiUgc2V0X25hbWVzKC4sIG1hcCguLCB+dW5pcXVlKC54JG5hbWUpKSkKCgpwYWdlcyA8LSBsaXN0KGxpc3QoIkRFR3MgTDJUMiB2cyBMMlQzIj10KSwgZGZfYWNyb3NzW1sxXV0kcmVzKSAlPiUgZmxhdHRlbigpCndyaXRlLnhsc3gocGFnZXMsIGZpbGU9cGFzdGUwKHJlc3VsdF9kaXIsIlN1cHBsLlRibC4xMiBMMlQyX0wyVDNfREVHc19hbmRfZW5yaWNobWVudC54bHN4IikpIApgYGAKIAojIyBpZ3JhcGggbmV0d29yayBwbG90CmBgYHtyIGlncmFwaC1uZXR3b3JrLCBldmFsPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIDEuIENoYW5nZSB0aGUgZ3JvdXBzIG9mIGludGVyZXN0IGJ5IGFzc2lnbmluZyBjb25kaXRpb25fdXNlCiMgMi4gQ2hhbmdlIHRoZSBudW1iZXIgb2YgZ2VuZXMgdG8gYmUgaW5jbHVkZWQgaW4gdGhlIG5ldHdvcmsgYnkgY2hhbmdpbmcgbgojICAgIGxvb2sgYXQgdGVtcERfaSBhbmQgdGVtcFVfaSB0byBzZWUgaG93IG1hbnkgZ2VuZXMgd2FzIHNpZ25pZmljYW50CiMgMy4gQWRqdXN0IHRoZSBzaXplIG9mIHRoZSBnZW5lIG5vZGVzIGFuZCB0ZXh0IGluIHRoZSBncmFwaCBieSBjaGFuZ2luZzsgc3F1YXJlLCBjaXJjbGUgYW5kIHR4dAoKIyBjb21iaW5hdGlvbnMKc2hlZXRzIDwtIG1hcChERUdfZmlsZXMsIH5leGNlbF9zaGVldHMocGFzdGUwKHJlc3VsdF9kaXIsIC54KSlbLWMoMToyKV0gKSAlPiUKICBtYXAoLiwgfnNldF9uYW1lcygueCkpCgojIFNldCBlbnJpY2htZW50IGNvbmRpdGlvbnMKbiA8LSAxMCAgIyBtYXhpbXVtIG51bWJlciBvZiBURidzIHRvIHBsb3QKIyBzaXplczoKc3F1YXJlIDwtIDEwCmNyaWNsZSA8LSA4CnR4dCA8LSAuNwogIAojIENyZWF0ZSBhIGdyYXBoIGZyb20gdGhlIGxpc3Qgb2YgVVAgYW5kIERPV04gcmVndWxhdGVkIGdlbmVzCmlfZ3JhcGggPC0gZnVuY3Rpb24odGVtcF9pLCBuLCBzcXVhcmUsIGNyaWNsZSl7CiAgdGVtcCA8LSBsYXBwbHkoIDE6biwgZnVuY3Rpb24oeCl7IHN0cnNwbGl0KGFzLmNoYXJhY3Rlcih0ZW1wX2kkR2VuZXNbeF0pLHNwbGl0ID0gIjsiKVtbMV1dICB9ICkKICB0ZW1wIDwtIG1hcCh0ZW1wLCBwdXJycjo6ZGlzY2FyZCwgaXMubmEpICU+JSBjb21wYWN0KCkgIyByZW1vdmVzIE5BCiAgbmFtZXModGVtcCkgPC0gdGVtcF9pJGBUcmFuc2NyaXB0aW9uIEZhY3RvcmBbMTpsZW5ndGgodGVtcCldCiAgdGVtcDIgPC0gbGFwcGx5KCBuYW1lcyh0ZW1wKSAsIGZ1bmN0aW9uKHgpeyByZXAoeCxsZW5ndGgodGVtcFtbeF1dKSkgfSkKICB0ZW1wIDwtIGNiaW5kKHVubGlzdCh0ZW1wMiksdW5saXN0KHRlbXApKQogIGcgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHRlbXAsZGlyZWN0ZWQgPSBGKQogIHZfc2hhcGUgPC0gaWZlbHNlKCBuYW1lcyhWKGcpKSAlaW4lIHVuaXF1ZSh0ZW1wWywxXSkgLCAic3F1YXJlIiAsICJjaXJjbGUiICkKICB2X2NvbG9yIDwtIGlmZWxzZSggbmFtZXMoVihnKSkgJWluJSB1bmlxdWUodGVtcFssMV0pICwgImhvbmV5ZGV3IiAsICJjb3Juc2lsayIgKQogIHZfc2l6ZSA8LSBpZmVsc2UoIG5hbWVzKFYoZykpICVpbiUgdW5pcXVlKHRlbXBbLDFdKSAsIHNxdWFyZSAsIGNyaWNsZSApIAogIAogIHJldHVybihsaXN0KGc9Zywgdl9zaGFwZT12X3NoYXBlLCB2X2NvbG9yPXZfY29sb3IsIHZfc2l6ZT12X3NpemUpKQogIH0KCgojIFRlc3QgcGFyYW1ldGVycwojIGkgPC0gIlRGX1BQSV9UaXNzdWUiCiMgaSA8LSAiVEZfVFJSVVNUX2VucmljaG1lbnQiCiMgZ3JfbmFtZSA8LSAiVGlzc3VlIgojIGNvbXAgPC0gc2hlZXRzCgojIFNhdmUgYWxsIGNvbWJpbmF0aW9uIHBsb3RzIGluIG9uZSBmaWxlCnNhdmVfcGRmLmZ1biA8LSBmdW5jdGlvbihpLCBncl9uYW1lLCBjb21wKXsKICB0ZW1wX2lfbmFtZSA8LSBncmVwKGksbGlzdC5maWxlcyhwYXN0ZTAocmVzdWx0X2RpciksZnVsbC5uYW1lcz1GKSx2YWx1ZT1UKQogIHAgPC0gbWFwKGNvbXAsIH5yZWFkX3hsc3gocGFzdGUwKHJlc3VsdF9kaXIsIHRlbXBfaV9uYW1lKSwgc2hlZXQgPSAueCkpIAogIAogIHBfc3BsaXQgPC0gcCAlPiUKICAgIGltYXAoLiwgfi54ICU+JQogICAgICAgICAgbXV0YXRlKFJlZ3VsYXRpb24gPSBwYXN0ZTAoLnksICJfIiwgLiRSZWd1bGF0aW9uKSkgJT4lCiAgICAgICAgICBzcGxpdCguLCAuJFJlZ3VsYXRpb24pCiAgICAgICAgICApICU+JSBjb21wYWN0KCkgJT4lIGZsYXR0ZW4oKQogIAogIG9ial9pZ3JhcGggPC0gaW1hcChwX3NwbGl0LCB+aV9ncmFwaCgueCwgbiwgc3F1YXJlLCBjcmljbGUpKQogIAogIAogIHBhcihtYXIgPSBjKDAsIDAsIC43LCAwKSkgICNib3R0b20sIGxlZnQsIHRvcCwgcmlnaHQKICBwZGYoZmlsZSA9IHBhc3RlMChyZXN1bHRfZGlyLCAiUGxvdHMvIiwgaSwgIl9uZXR3b3JrXyIsIi5wZGYiLCBzZXA9IiIpKQogICAgcCA8LSBpbWFwKG9ial9pZ3JhcGgsCiAgICAgICAgIH53aXRoKC54LCAKICAgICAgICAgICAgICAgICBwbG90LmlncmFwaChnLCBsYWJlbD1WKGcpLCBwYWdlID0gVCwKICAgICAgICAgICAgICAgICBtYWluID0gcGFzdGUwKHN0cl9yZXBsYWNlKC55LCAiXyIsICIgIiksIiByZWd1bGF0ZWQgZ2VuZXMiKSwKICAgICAgICAgICAgICAgICBsYXlvdXQ9bGF5b3V0X3dpdGhfa2soZyksIHZlcnRleC5sYWJlbC5jb2xvcj0iYmxhY2siICwKICAgICAgICAgICAgICAgICB2ZXJ0ZXguc2l6ZT12X3NpemUsIHZlcnRleC5sYWJlbC5jZXg9dHh0LCB2ZXJ0ZXgubGFiZWwuZm9udD0yLCAKICAgICAgICAgICAgICAgICB2ZXJ0ZXguc2hhcGU9dl9zaGFwZSwgdmVydGV4LmNvbG9yPXZfY29sb3IsIG1hcmlnaW4gPSBjKC0xLC00LDAsMCksCiAgICAgICAgICAgICAgICAgdmVydGV4LmZyYW1lLmNvbG9yPSJncmV5NjAiLCBjdXJ2ZWQ9RikKICAgICAgICAgICAgICAgCiAgICApKQogICAgZGV2Lm9mZigpCn0KCiMgaWYoaXNGQUxTRShkaXIuZXhpc3RzKHBhc3RlMChyZXN1bHRfZGlyLCIiKSkpKXtkaXIuY3JlYXRlKHBhc3RlMCgiLi4vIixyZXN1bHQuZGlyKSxyZWN1cnNpdmUgPSBUUlVFKX0KIyBzYXZlX3BkZi5mdW4oIlRGX1BQSV9MdW1pbmFsIiwgIkx1bWluYWwiLCBjb21wID0gc2hlZXRzW1sxXV0pCiMgc2F2ZV9wZGYuZnVuKCJURl9QUElfVGlzc3VlIiwgIlRpc3N1ZSIsIGNvbXAgPSBzaGVldHNbWzJdXSkKCmBgYAo=