##################
# LOAD LIBRARIES #
##################
suppressWarnings({suppressMessages({suppressPackageStartupMessages({
library(tidyverse)
library(magick)
library(uwot)
library(scales)
library(igraph)
library(RColorBrewer)
#remotes::install_github("czarnewski/niceRplots",force=T)
library(niceRplots)
library(openxlsx)
}) }) })
#########
# PATHS #
#########
result_dir <- "./Suppl.Tbl/"
if( isFALSE(dir.exists(result_dir)) ) { dir.create(result_dir,recursive = TRUE) }
#############
# LODA DATA #
#############
fig1a <- magick::image_read("../../resources/Scematic figure.pdf", density = 900 )
datasets_all_samples <- readRDS("../../results/03_normalize_data_output/datasets_all_samples.RDS")
metadata <- read.csv("../../data/metadata.csv",row.names = 1)
group_annotation <- factor(setNames(metadata$Luminal_gr,metadata$ID))
SNN_participant <- read.csv("../../results/04_clustering_output/participant_SNN_graph.csv",row.names = 1)
bac_communities <- read.csv("../../results/04_clustering_output/bacterial_communities.csv",row.names = 1)
TRX <- datasets_all_samples[["Tissue_RNAseq_V3_normalized"]]
sample_use <- colnames(TRX)[colSums(TRX)!=0]
#################
# COLOR PALETTS #
#################
lvl <- c("L. iners", "Gardnerella", "L. crispatus/acidophilus","Prevotella", "Atopobium","Sneathia", "L. jensenii", "Megasphaera", "Streptococcus", "Anaerococcus", "BVAB2", "Escherichia/Shigella", "BVAB1", "Dialister", "Mycoplasma", "Bifidobacterium", "Other")
pal <- c( "#0072B2", "#009E73","#D55E00", "#CC79A7", "#E69F00", "#999999")
taxa_pal <- c(RColorBrewer::brewer.pal(8,"Pastel2"),RColorBrewer::brewer.pal(8,"Pastel1"),"grey90")
# show_col(pal)
# , fig.height=6.2
# fig.height=7, fig.asp=1,
figlabels <- letters
layout(matrix(c(1,1,1,1,1,1,
2,2,2,2,2,2,
3,3,3,3,3,3,
5,6,7,7,8,8,
5,4,7,7,8,8,
5,4,7,7,8,8) , ncol= 6,byrow = T),
widths = c(1.87,1.42,.7,.8,.8,.7,.8),
heights = lcm(c(4.7,2,4.5,2,.5)) # height in cm
# heights = c(1.4,.55,1.4,.61,.75,0)
)
### A
#################################
# COHORT SCHEMATIC ILLUSTRATION #
#################################
par(mar=c(0.1,3.7,0.3,1)) #b,l,t,r
plot(c(0,1),c(0,1),axes=F,type="n",xlab="",ylab="",xaxs="i",yaxs="i")
rasterImage(fig1a, 0, 0, 1, 1)
#add label
add_letter(figlabels[1]); figlabels <- figlabels[-1]
### B
#############################
# DIVERSITY + TAX ABUNDANCE #
#############################
ASV <- list(c("Luminal_gr","ASV_Luminal_normalized"),
c("Tissue_gr","ASV_Tissue_normalized")
)
div_list <- list()
for(i in ASV){
x <- datasets_all_samples[[i[2]]]
gr <- factor(setNames(metadata[[i[1]]],metadata$ID))
dim(x)
x <- x[ rowSums(x>0) >= 3 , ]
#x_ <- x[ rowSums(x>0) , ]
dim(x)
temp <- t(t(2^x-1)/colSums(2^x-1))
shann <- vegan::diversity(t(temp),index = c("shannon") )
simp <- vegan::diversity(t(temp),index = c("simpson") )
invsimp <- vegan::diversity(t(temp),index = c("invsimpson") )
divers <- as.matrix(rbind(shann,simp,invsimp) )
divers[is.infinite(divers)] <- 0
rownames(divers) <- c("Shannon","Simpson","Inv Simpson")
div <- tibble(ID=names(shann),shann, simp, invsimp ) %>% rename_with(., ~paste0(c("ID","Shannon","Simpson","Inv Simpson")))
div_list[[length(div_list) + 1]] <- div
if(i[2] == "ASV_Tissue_normalized"){break}
par(mar=c(0,5,1.5,1.5)) #b,l,t,r
barlist( data = divers[,order(group_annotation)],
main = "", xlab="", #bg="white", #cex=.6,
genes = c("Shannon","Simpson","Inv Simpson"),
draw_mean_lines=F,col = pal[gr[order(group_annotation)]])
if(i[2] == "ASV_Luminal_normalized"){
end <- table(pal[factor(group_annotation[order(group_annotation)])])
end <- end[order(factor(names(end), levels = pal))]
end <- map_dbl(cumsum(end), ~ (.x * (par("usr")[2])/length(colnames(divers)))-.2 )
start <- c(0.5, map_dbl(end[1:4], ~.x+0.7))
axis(1, at = c(start, end), label = F, pos =3.3 , xpd=T, col="white",col.ticks="black")
map2(start, end, ~lines(x=c(.y, .x), y= c(3.3, 3.3), xpd=T, cex=.8))
t <- map2(start, end, ~(.x+.y)/2)
map2(t,levels(gr), ~text(x=.x, y=3.8, .y,xpd=T))
}
#add label
add_letter(figlabels[1]); figlabels <- figlabels[-1]
par(mar=c(1.5,5,1,1.5)) #b,l,t,r
temp[is.nan(temp)] <- 0
o <- order( rowSums(temp) , decreasing = T)
sample_o <- names(group_annotation)[ order( group_annotation )]
temp <- temp[o,sample_o]*100
temp <- rbind(temp[1:16,], Other = colSums(temp[17:nrow(temp),]) )
barplot( temp, las=2 , border = NA , yaxs="i", xaxs="i",ylab="abundance",main=gsub("_gr","",i[1]),font.main=1,
col = taxa_pal[factor(rownames(temp),levels = lvl)] ,names.arg = rep("",ncol(temp)))
points( (1:ncol(temp))*1.2 -.5, rep(par("usr")[3],ncol(temp))-2, bg="white",
col= c("tomato","orange","#d7d7d7")[as.numeric(metadata$BV_Diagnosis_v3)][order( group_annotation )],
pch=15,cex=.7,xpd=T)
text(par("usr")[2],par("usr")[3]-2,labels = " BV",cex=.5,xpd=T)
points( (1:ncol(temp))*1.2 -.5, rep(par("usr")[3],ncol(temp))-7,bg="white",
col= c("#d7d7d7","tomato")[as.numeric(metadata$HIVstatus)][order( group_annotation )],
pch=15,cex=.7,xpd=T)
text(par("usr")[2],par("usr")[3]-8,labels = " HIV",cex=.5,xpd=T)
l <- c("BV:","Normal","Intermediate","BV")
legend(x = 10, y = 111, #"bottom", inset = c(0, -0.5),
bty = "n", horiz=TRUE, cex=0.7, xpd = T,
border = "white",
legend = l, x.intersp=0.5, xjust=0,
text.width = c(0, map_dbl(l, ~strwidth(.x)/2)) ,
fill=c(NA, "#d7d7d7","orange","tomato"))
l2 <- c("HIV:","HIV-","HIV+")
legend(x = 80, y = 111, # bottom position: par("usr")[3]-5
bty = "n", horiz=TRUE, cex=0.7, xpd = T,
border = "white",
legend = l2, x.intersp=0.5,
text.width =c(0, map_dbl(l2, ~strwidth(.x)/2)),
fill=c(NA, "#d7d7d7", "tomato"))
}
###########
# LEGENDS #
###########
par(mar=c(0,0,0,.5)) #b,l,t,r
empty_plot()
legend(x = -0.04, y = 1.04,
legend = c("L1 L. crispatus/jensenii", "L2 L. iners", "L3 Gardnerella", "L4 High diverse", "L5 Other"),
xjust = 0,yjust = 1,title.adj = 0, ncol =1,
bty = "n",pch = 22,pt.cex = 2,cex = 1,xpd=T,title = "Study Groups",
pt.bg = pal)
par(mar=c(0,4.5,0,.5)) #b,l,t,r
empty_plot()
legend(x = par("usr")[c(1)],
y = par("usr")[c(4)],
legend = lvl[1:12],xjust = 0,yjust = 1,
bty = "n",pch = 22,pt.cex = 2,cex = 1,xpd=T,
pt.bg = taxa_pal)
par(mar=c(0,0,0,1)) #b,l,t,r
empty_plot()
legend(x = par("usr")[c(1)],
y = par("usr")[c(4)],
legend = lvl[13:17],xjust = 0,yjust = 1,
bty = "n",pch = 22,pt.cex = 2,cex = 1,xpd=T,
pt.bg = taxa_pal[13:17])
### C + D
################
# STUDY GROUPS #
################
### Louvain ###
g <- graph_from_adjacency_matrix(as.matrix(SNN_participant), mode = "undirected",diag = F,weighted = T)
set.seed(1)
l <- layout_with_fr(g,niter=3000,start.temp=30)
par(mar=c(0,0,0,1)) #b,l,t,r
plot( g , vertex.label.cex=0.000001 , vertex.color = pal[factor(group_annotation)] ,
edge.width= ( E(g)$weight / max(E(g)$weight)) ,
vertex.size=10, layout=l,
edge.color=colorRampPalette(c("grey95","black"))(90) [ round( E(g)$weight / max(E(g)$weight) * 88 )+1 ] )
title(main = "Louvain", line = -1, cex.main = 1)
#add label
add_letter(figlabels[1]); figlabels <- figlabels[-1]
### UMAP ###
all_microbiome <- datasets_all_samples[["ASV_Luminal_normalized"]]
all_microbiome <- all_microbiome[ rowSums(all_microbiome>0) >= 3 , ]
cors <- cor(all_microbiome[,], method = "pearson")
adj <- (1-cors)/2
U <- uwot::umap(adj,n_neighbors = 30)
plot( g , vertex.label.cex=0.000001 , vertex.color = pal[factor(group_annotation)] ,
edge.width= ( E(g)$weight / max(E(g)$weight)) ,layout=U,
vertex.size=10,
edge.color=colorRampPalette(c("grey95","black"))(90) [ round( E(g)$weight / max(E(g)$weight) * 88 )+1 ] )
title(main = "UMAP", line = -1, cex.main = 1)
#add label
add_letter(figlabels[1]); figlabels <- figlabels[-1]

Figure 1. Characterization of a highly diversemicrobiome in
cervicovaginal (luminal) samples from Kenyan sex workers.
Cervicovaginal lavage (luminal) and ectocervical tissue study samples
were assessed by 16S rRNA sequencing, gene expression, and protein
profiling. a Schematic drawing depicting the sampling
scheme and the resulting omics datasets. b Bar plots of
alpha diversity indices and taxonomy profiles for each individual
luminal sample. Color-coded squares above the stacked bar plots indicate
bacterial vaginosis (BV, binned Nugent’s scores): Gray: negative,
orange: intermediate, red: positive; and HIV diagnosis: Gray: HIV
seronegative, red: HIV seropositive. Two12-SNN graphs were constructed
using: c Louvain community detection algorithm, and d
Uniform Manifold Approximation (UMAP). The two graphs were overlayed in
color with the predefined luminal study groups. The undirected edges are
included in gray connecting the nodes
# Total Relative Abundance
raw <- c("ASV_Luminal", "ASV_Tissue") %>% set_names()
raw_list <- raw %>%
map(., ~read_csv(paste0("../../results/02_data_preprocessing_output/",.x,"_raw_counts.csv"))) %>%
map(., ~column_to_rownames(., var = "X1")) %>%
map(., ~dplyr::select(., any_of(sample_use)))
r <- raw_list %>%
map(., ~mutate(.,across(where(is.numeric), ~ ./sum(.))) ) %>%
map(., ~(rowSums(.x)/length(colnames(.x)) )*100 ) %>%
bind_rows(., .id="ID") %>%
pivot_longer(-ID) %>%
pivot_wider(names_from = ID, values_from = value) %>%
mutate_at(vars(name), ~replace(., ASV_Luminal<0.5514392, "Other")) %>%
mutate(name = ifelse(.$name=="Not assigned", "Other", .$name)) %>%
group_by(name) %>%
summarize(across(where(is.numeric), ~sum(.))) %>%
arrange(-ASV_Luminal) %>%
dplyr::rename(Luminal="ASV_Luminal",Tissue="ASV_Tissue") %>%
rename(Taxa="name") %>%
mutate(across(where(is.numeric), ~round(.x, digits = 1)))
# Alfa Diversity Stats
div_stat <- div_list %>%
set_names(map(ASV,1)) %>%
map(., ~summarise_if(.x, is.numeric, list(median=median, IQR=IQR), na.rm = TRUE)) %>%
map(., ~pivot_longer(.x, everything(), names_sep = "_", names_to = c(".value", "Stats"), )) %>%
bind_rows(.id = "Sample type") %>%
mutate("Sample type" = gsub("_gr", "", .$"Sample type")) %>%
mutate(across(where(is.numeric), ~round(.x, digits = 2)))
# Bacterial Communities
bac_communities <- bac_communities %>%
mutate("bacterial communities"= factor(paste0("BC",sprintf("%02d",bac_communities$Bact_com)))) %>%
select(-Bact_com) %>%
arrange(`bacterial communities`)
pages <- list("Total Relative Abundance"=r ,"Alfa Diversity"=div_stat, "Bacterial Communities"=bac_communities)
write.xlsx(pages, file=paste0(result_dir,"Suppl.Tbl.01",".xlsx"))
alpa_div <- set_names(div_list, c("Luminal","Tissue")) %>%
map2(., c("Luminal_gr", "Tissue_gr"), ~left_join(.x, select(metadata, ID, .y), by="ID")) %>%
map2(., c("Luminal_gr", "Tissue_gr"), ~select(.x, ID, .y, everything()))
write.xlsx(alpa_div, file=paste0(result_dir,"alpha_diversity",".xlsx"))
LS0tCnRpdGxlOiAiRmlndXJlIDEuTHVtaW5hbCBTdHVkeSBHcm91cHMiCmdlb21ldHJ5OiAibGVmdD0yY20scmlnaHQ9MmNtLHRvcD0yY20sYm90dG9tPTJjbSIKaGVhZGVyLWluY2x1ZGVzOiAKLSBcdXNlcGFja2FnZXtmbG9hdH0KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCmtuaXQ6IChmdW5jdGlvbihpbnB1dEZpbGUsIG91dF9kaXIsIC4uLikgewogICAgc291cmNlKCIuLi8uLi9jb2RlL2tuaXRfZnVuY3Rpb24uUiIpOwogICAgY3VzdG9tX2tuaXQoaW5wdXRGaWxlLCAiLi4vLi4vbGFiX2Jvb2svRmlndXJlMS8iLCAuLi4pCiAgICB9KQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgcmVzdWx0cyA9ICJob2xkIiwKICBtZXNzYWdlICAgID0gRkFMU0UsCiAgd2FybmluZyAgICA9IEZBTFNFLAogIGZpZy53aWR0aCA9IDYuNjkyOTEzMzg1OCwKICBmaWcucGF0aD0iLi9GaWd1cmVzLyIsCiAgZmlnLnByb2Nlc3MgPSBmdW5jdGlvbihmaWxlbmFtZSl7CiAgICBuZXdfZmlsZW5hbWUgPC0gc3RyaW5ncjo6c3RyX3JlbW92ZShzdHJpbmcgPSBmaWxlbmFtZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIi0xIikKICAgIGZzOjpmaWxlX21vdmUocGF0aCA9IGZpbGVuYW1lLCBuZXdfcGF0aCA9IG5ld19maWxlbmFtZSkKICAgIGlmZWxzZShmczo6ZmlsZV9leGlzdHMobmV3X2ZpbGVuYW1lKSwgbmV3X2ZpbGVuYW1lLCBmaWxlbmFtZSkKfSkKIyBzZXR3ZCgiL1VzZXJzL3ZpbGthbC93b3JrL0Jyb2xpZGVuc193b3JrL1Byb2plY3RzL2Jyb2xpZGVuXzUzMjUvcmVwb3J0cy9tYW51c2NyaXB0IikKIy5saWJQYXRocygiL1VzZXJzL3ZpbGthbC9BcHBsaWNhdGlvbnMvbWluaWNvbmRhMy9lbnZzL1BhdWxvc19yZXBvL2xpYi9SL2xpYnJhcnkiKQoKIyMjIyBGaWd1cmUgcmVxdWlyZW1lbnRzIE1pY3JvYmlvbWU6ICMjIyMKICAjIC0gd2lkdGggb2YgODUgbW0gZm9yIGhhbGYgcGFnZSB3aWR0aCBmaWd1cmUKICAjIC0gd2lkdGggb2YgMTcwIG1tIGZvciBmdWxsIHBhZ2Ugd2lkdGggZmlndXJlCiAgIyAtIG1heGltdW0gaGVpZ2h0IG9mIDIyNSBtbSBmb3IgZmlndXJlIGFuZCBsZWdlbmQKICAjIC0gaW1hZ2UgcmVzb2x1dGlvbiBvZiBhcHByb3hpbWF0ZWx5IDMwMCBkcGkgKGRvdHMgcGVyIGluY2gpIGF0IHRoZSBmaW5hbCBzaXplCgpgYGAKCmBgYHtyIExvYWQgZGF0YX0KIyMjIyMjIyMjIyMjIyMjIyMjCiMgTE9BRCBMSUJSQVJJRVMgIwojIyMjIyMjIyMjIyMjIyMjIyMKc3VwcHJlc3NXYXJuaW5ncyh7c3VwcHJlc3NNZXNzYWdlcyh7c3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHRpZHl2ZXJzZSkKICBsaWJyYXJ5KG1hZ2ljaykKICBsaWJyYXJ5KHV3b3QpCiAgbGlicmFyeShzY2FsZXMpCiAgbGlicmFyeShpZ3JhcGgpCiAgbGlicmFyeShSQ29sb3JCcmV3ZXIpCiAgI3JlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJjemFybmV3c2tpL25pY2VScGxvdHMiLGZvcmNlPVQpCiAgbGlicmFyeShuaWNlUnBsb3RzKQogIGxpYnJhcnkob3Blbnhsc3gpCn0pICB9KSAgfSkKCiMjIyMjIyMjIwojIFBBVEhTICMKIyMjIyMjIyMjCnJlc3VsdF9kaXIgPC0gIi4vU3VwcGwuVGJsLyIKaWYoIGlzRkFMU0UoZGlyLmV4aXN0cyhyZXN1bHRfZGlyKSkgKSB7IGRpci5jcmVhdGUocmVzdWx0X2RpcixyZWN1cnNpdmUgPSBUUlVFKSB9CgojIyMjIyMjIyMjIyMjCiMgTE9EQSBEQVRBICMKIyMjIyMjIyMjIyMjIwpmaWcxYSA8LSBtYWdpY2s6OmltYWdlX3JlYWQoIi4uLy4uL3Jlc291cmNlcy9TY2VtYXRpYyBmaWd1cmUucGRmIiwgZGVuc2l0eSA9IDkwMCApCmRhdGFzZXRzX2FsbF9zYW1wbGVzIDwtIHJlYWRSRFMoIi4uLy4uL3Jlc3VsdHMvMDNfbm9ybWFsaXplX2RhdGFfb3V0cHV0L2RhdGFzZXRzX2FsbF9zYW1wbGVzLlJEUyIpCm1ldGFkYXRhIDwtIHJlYWQuY3N2KCIuLi8uLi9kYXRhL21ldGFkYXRhLmNzdiIscm93Lm5hbWVzID0gMSkKZ3JvdXBfYW5ub3RhdGlvbiA8LSBmYWN0b3Ioc2V0TmFtZXMobWV0YWRhdGEkTHVtaW5hbF9ncixtZXRhZGF0YSRJRCkpCgpTTk5fcGFydGljaXBhbnQgPC0gcmVhZC5jc3YoIi4uLy4uL3Jlc3VsdHMvMDRfY2x1c3RlcmluZ19vdXRwdXQvcGFydGljaXBhbnRfU05OX2dyYXBoLmNzdiIscm93Lm5hbWVzID0gMSkKYmFjX2NvbW11bml0aWVzIDwtIHJlYWQuY3N2KCIuLi8uLi9yZXN1bHRzLzA0X2NsdXN0ZXJpbmdfb3V0cHV0L2JhY3RlcmlhbF9jb21tdW5pdGllcy5jc3YiLHJvdy5uYW1lcyA9IDEpCgpUUlggPC0gZGF0YXNldHNfYWxsX3NhbXBsZXNbWyJUaXNzdWVfUk5Bc2VxX1YzX25vcm1hbGl6ZWQiXV0Kc2FtcGxlX3VzZSA8LSBjb2xuYW1lcyhUUlgpW2NvbFN1bXMoVFJYKSE9MF0KCiMjIyMjIyMjIyMjIyMjIyMjCiMgQ09MT1IgUEFMRVRUUyAjCiMjIyMjIyMjIyMjIyMjIyMjCmx2bCA8LSBjKCJMLiBpbmVycyIsICJHYXJkbmVyZWxsYSIsICJMLiBjcmlzcGF0dXMvYWNpZG9waGlsdXMiLCJQcmV2b3RlbGxhIiwgIkF0b3BvYml1bSIsIlNuZWF0aGlhIiwgIkwuIGplbnNlbmlpIiwgIk1lZ2FzcGhhZXJhIiwgIlN0cmVwdG9jb2NjdXMiLCAiQW5hZXJvY29jY3VzIiwgIkJWQUIyIiwgIkVzY2hlcmljaGlhL1NoaWdlbGxhIiwgIkJWQUIxIiwgIkRpYWxpc3RlciIsICJNeWNvcGxhc21hIiwgIkJpZmlkb2JhY3Rlcml1bSIsICJPdGhlciIpCgpwYWwgPC0gYyggIiMwMDcyQjIiLCAiIzAwOUU3MyIsIiNENTVFMDAiLCAiI0NDNzlBNyIsICIjRTY5RjAwIiwgIiM5OTk5OTkiKQp0YXhhX3BhbCA8LSBjKFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg4LCJQYXN0ZWwyIiksUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDgsIlBhc3RlbDEiKSwiZ3JleTkwIikKIyBzaG93X2NvbChwYWwpCmBgYAoKCmBgYHtyIEZpZ3VyZSAxLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLnBvcz0idCIsIGZpZy5oZWlnaHQ9Ni4yfQojICwgZmlnLmhlaWdodD02LjIKIyBmaWcuaGVpZ2h0PTcsIGZpZy5hc3A9MSwKZmlnbGFiZWxzIDwtIGxldHRlcnMKCmxheW91dChtYXRyaXgoYygxLDEsMSwxLDEsMSwKICAgICAgICAgICAgICAgIDIsMiwyLDIsMiwyLAogICAgICAgICAgICAgICAgMywzLDMsMywzLDMsCiAgICAgICAgICAgICAgICA1LDYsNyw3LDgsOCwKICAgICAgICAgICAgICAgIDUsNCw3LDcsOCw4LAogICAgICAgICAgICAgICAgNSw0LDcsNyw4LDgpICwgbmNvbD0gNixieXJvdyA9IFQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGhzID0gYygxLjg3LDEuNDIsLjcsLjgsLjgsLjcsLjgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0cyA9IGxjbShjKDQuNywyLDQuNSwyLC41KSkgIyBoZWlnaHQgaW4gY20KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBoZWlnaHRzID0gYygxLjQsLjU1LDEuNCwuNjEsLjc1LDApCiAgICAgICApIAojIyMgQQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBDT0hPUlQgU0NIRU1BVElDIElMTFVTVFJBVElPTiAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpwYXIobWFyPWMoMC4xLDMuNywwLjMsMSkpICNiLGwsdCxyCnBsb3QoYygwLDEpLGMoMCwxKSxheGVzPUYsdHlwZT0ibiIseGxhYj0iIix5bGFiPSIiLHhheHM9ImkiLHlheHM9ImkiKQpyYXN0ZXJJbWFnZShmaWcxYSwgMCwgMCwgMSwgMSkKCiNhZGQgbGFiZWwKYWRkX2xldHRlcihmaWdsYWJlbHNbMV0pOyBmaWdsYWJlbHMgPC0gZmlnbGFiZWxzWy0xXQoKCiMjIyBCCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgRElWRVJTSVRZICsgVEFYIEFCVU5EQU5DRSAjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpBU1YgPC0gbGlzdChjKCJMdW1pbmFsX2dyIiwiQVNWX0x1bWluYWxfbm9ybWFsaXplZCIpLAogICAgICAgICAgICBjKCJUaXNzdWVfZ3IiLCJBU1ZfVGlzc3VlX25vcm1hbGl6ZWQiKQogICAgICAgICApCmRpdl9saXN0IDwtIGxpc3QoKQpmb3IoaSBpbiBBU1YpewogIHggPC0gZGF0YXNldHNfYWxsX3NhbXBsZXNbW2lbMl1dXQogIGdyIDwtIGZhY3RvcihzZXROYW1lcyhtZXRhZGF0YVtbaVsxXV1dLG1ldGFkYXRhJElEKSkKCiAgZGltKHgpCiAgeCA8LSB4WyByb3dTdW1zKHg+MCkgPj0gMyAsICBdCiAgI3hfIDwtIHhbIHJvd1N1bXMoeD4wKSAsICBdCiAgZGltKHgpCiAgdGVtcCA8LSB0KHQoMl54LTEpL2NvbFN1bXMoMl54LTEpKQoKICBzaGFubiA8LSB2ZWdhbjo6ZGl2ZXJzaXR5KHQodGVtcCksaW5kZXggPSBjKCJzaGFubm9uIikgKQogIHNpbXAgPC0gdmVnYW46OmRpdmVyc2l0eSh0KHRlbXApLGluZGV4ID0gYygic2ltcHNvbiIpICkKICBpbnZzaW1wIDwtIHZlZ2FuOjpkaXZlcnNpdHkodCh0ZW1wKSxpbmRleCA9IGMoImludnNpbXBzb24iKSApCiAgZGl2ZXJzIDwtIGFzLm1hdHJpeChyYmluZChzaGFubixzaW1wLGludnNpbXApICkKICBkaXZlcnNbaXMuaW5maW5pdGUoZGl2ZXJzKV0gPC0gMAogIHJvd25hbWVzKGRpdmVycykgPC0gYygiU2hhbm5vbiIsIlNpbXBzb24iLCJJbnYgU2ltcHNvbiIpCiAgCiAgZGl2IDwtIHRpYmJsZShJRD1uYW1lcyhzaGFubiksc2hhbm4sIHNpbXAsIGludnNpbXAgKSAlPiUgcmVuYW1lX3dpdGgoLiwgfnBhc3RlMChjKCJJRCIsIlNoYW5ub24iLCJTaW1wc29uIiwiSW52IFNpbXBzb24iKSkpCiAgZGl2X2xpc3RbW2xlbmd0aChkaXZfbGlzdCkgKyAxXV0gPC0gZGl2CiAgCiAgaWYoaVsyXSA9PSAiQVNWX1Rpc3N1ZV9ub3JtYWxpemVkIil7YnJlYWt9CiAgCiAgcGFyKG1hcj1jKDAsNSwxLjUsMS41KSkgI2IsbCx0LHIKICBiYXJsaXN0KCBkYXRhID0gZGl2ZXJzWyxvcmRlcihncm91cF9hbm5vdGF0aW9uKV0sCiAgICAgICAgIG1haW4gPSAiIiwgeGxhYj0iIiwgI2JnPSJ3aGl0ZSIsICNjZXg9LjYsIAogICAgICAgICBnZW5lcyA9IGMoIlNoYW5ub24iLCJTaW1wc29uIiwiSW52IFNpbXBzb24iKSwKICAgICAgICAgZHJhd19tZWFuX2xpbmVzPUYsY29sID0gcGFsW2dyW29yZGVyKGdyb3VwX2Fubm90YXRpb24pXV0pCiAgCiAgaWYoaVsyXSA9PSAiQVNWX0x1bWluYWxfbm9ybWFsaXplZCIpewogICAgZW5kIDwtIHRhYmxlKHBhbFtmYWN0b3IoZ3JvdXBfYW5ub3RhdGlvbltvcmRlcihncm91cF9hbm5vdGF0aW9uKV0pXSkKICAgIGVuZCA8LSBlbmRbb3JkZXIoZmFjdG9yKG5hbWVzKGVuZCksIGxldmVscyA9IHBhbCkpXQogICAgZW5kIDwtIG1hcF9kYmwoY3Vtc3VtKGVuZCksIH4gKC54ICogKHBhcigidXNyIilbMl0pL2xlbmd0aChjb2xuYW1lcyhkaXZlcnMpKSktLjIgKQogICAgc3RhcnQgPC0gYygwLjUsIG1hcF9kYmwoZW5kWzE6NF0sIH4ueCswLjcpKQogICAgCiAgICBheGlzKDEsIGF0ID0gYyhzdGFydCwgZW5kKSwgbGFiZWwgPSBGLCBwb3MgPTMuMyAsIHhwZD1ULCBjb2w9IndoaXRlIixjb2wudGlja3M9ImJsYWNrIikKICAgIG1hcDIoc3RhcnQsIGVuZCwgfmxpbmVzKHg9YygueSwgLngpLCB5PSBjKDMuMywgMy4zKSwgeHBkPVQsIGNleD0uOCkpCiAgICB0IDwtIG1hcDIoc3RhcnQsIGVuZCwgfigueCsueSkvMikKICAgIG1hcDIodCxsZXZlbHMoZ3IpLCB+dGV4dCh4PS54LCB5PTMuOCwgLnkseHBkPVQpKQogIH0KICAKICAjYWRkIGxhYmVsCiAgYWRkX2xldHRlcihmaWdsYWJlbHNbMV0pOyBmaWdsYWJlbHMgPC0gZmlnbGFiZWxzWy0xXQoKICBwYXIobWFyPWMoMS41LDUsMSwxLjUpKSAjYixsLHQscgogIHRlbXBbaXMubmFuKHRlbXApXSA8LSAwCgogIG8gPC0gb3JkZXIoIHJvd1N1bXModGVtcCkgLCBkZWNyZWFzaW5nID0gVCkKICBzYW1wbGVfbyA8LSBuYW1lcyhncm91cF9hbm5vdGF0aW9uKVsgb3JkZXIoIGdyb3VwX2Fubm90YXRpb24gKV0KICB0ZW1wIDwtIHRlbXBbbyxzYW1wbGVfb10qMTAwCiAgdGVtcCA8LSByYmluZCh0ZW1wWzE6MTYsXSwgT3RoZXIgPSBjb2xTdW1zKHRlbXBbMTc6bnJvdyh0ZW1wKSxdKSApCgogIGJhcnBsb3QoIHRlbXAsIGxhcz0yICwgYm9yZGVyID0gTkEgLCB5YXhzPSJpIiwgeGF4cz0iaSIseWxhYj0iYWJ1bmRhbmNlIixtYWluPWdzdWIoIl9nciIsIiIsaVsxXSksZm9udC5tYWluPTEsCiAgICAgICAgICAgY29sID0gdGF4YV9wYWxbZmFjdG9yKHJvd25hbWVzKHRlbXApLGxldmVscyA9IGx2bCldICxuYW1lcy5hcmcgPSByZXAoIiIsbmNvbCh0ZW1wKSkpCgogIHBvaW50cyggKDE6bmNvbCh0ZW1wKSkqMS4yIC0uNSwgcmVwKHBhcigidXNyIilbM10sbmNvbCh0ZW1wKSktMiwgYmc9IndoaXRlIiwKICAgICAgICBjb2w9IGMoInRvbWF0byIsIm9yYW5nZSIsIiNkN2Q3ZDciKVthcy5udW1lcmljKG1ldGFkYXRhJEJWX0RpYWdub3Npc192MyldW29yZGVyKCBncm91cF9hbm5vdGF0aW9uICldLAogICAgICAgIHBjaD0xNSxjZXg9LjcseHBkPVQpCiAgdGV4dChwYXIoInVzciIpWzJdLHBhcigidXNyIilbM10tMixsYWJlbHMgPSAiICAgICAgQlYiLGNleD0uNSx4cGQ9VCkKICBwb2ludHMoICgxOm5jb2wodGVtcCkpKjEuMiAtLjUsIHJlcChwYXIoInVzciIpWzNdLG5jb2wodGVtcCkpLTcsYmc9IndoaXRlIiwKICAgICAgICBjb2w9IGMoIiNkN2Q3ZDciLCJ0b21hdG8iKVthcy5udW1lcmljKG1ldGFkYXRhJEhJVnN0YXR1cyldW29yZGVyKCBncm91cF9hbm5vdGF0aW9uICldLAogICAgICAgIHBjaD0xNSxjZXg9LjcseHBkPVQpCiAgdGV4dChwYXIoInVzciIpWzJdLHBhcigidXNyIilbM10tOCxsYWJlbHMgPSAiICAgICAgIEhJViIsY2V4PS41LHhwZD1UKQoKICBsIDwtIGMoIkJWOiIsIk5vcm1hbCIsIkludGVybWVkaWF0ZSIsIkJWIikKICBsZWdlbmQoeCA9IDEwLCB5ID0gMTExLCAjImJvdHRvbSIsIGluc2V0ID0gYygwLCAtMC41KSwKICAgICAgICAgYnR5ID0gIm4iLCBob3Jpej1UUlVFLCBjZXg9MC43LCB4cGQgPSBULCAKICAgICAgICAgYm9yZGVyID0gIndoaXRlIiwgCiAgICAgICAgIGxlZ2VuZCA9IGwsIHguaW50ZXJzcD0wLjUsIHhqdXN0PTAsCiAgICAgICAgIHRleHQud2lkdGggPSBjKDAsIG1hcF9kYmwobCwgfnN0cndpZHRoKC54KS8yKSkgLAogICAgICAgICBmaWxsPWMoTkEsICIjZDdkN2Q3Iiwib3JhbmdlIiwidG9tYXRvIikpCiAgbDIgPC0gYygiSElWOiIsIkhJVi0iLCJISVYrIikKICBsZWdlbmQoeCA9IDgwLCB5ID0gMTExLCAjIGJvdHRvbSBwb3NpdGlvbjogcGFyKCJ1c3IiKVszXS01CiAgICAgICAgIGJ0eSA9ICJuIiwgaG9yaXo9VFJVRSwgY2V4PTAuNywgeHBkID0gVCwKICAgICAgICAgYm9yZGVyID0gIndoaXRlIiwKICAgICAgICAgbGVnZW5kID0gbDIsIHguaW50ZXJzcD0wLjUsIAogICAgICAgICB0ZXh0LndpZHRoID1jKDAsIG1hcF9kYmwobDIsIH5zdHJ3aWR0aCgueCkvMikpLAogICAgICAgICBmaWxsPWMoTkEsICIjZDdkN2Q3IiwgInRvbWF0byIpKQp9CgoKIyMjIyMjIyMjIyMKIyBMRUdFTkRTICMKIyMjIyMjIyMjIyMKcGFyKG1hcj1jKDAsMCwwLC41KSkgI2IsbCx0LHIKZW1wdHlfcGxvdCgpCmxlZ2VuZCh4ID0gLTAuMDQsIHkgPSAxLjA0LCAKICAgICAgIGxlZ2VuZCA9IGMoIkwxIEwuIGNyaXNwYXR1cy9qZW5zZW5paSIsICJMMiBMLiBpbmVycyIsICJMMyBHYXJkbmVyZWxsYSIsICJMNCBIaWdoIGRpdmVyc2UiLCAiTDUgT3RoZXIiKSwKICAgICAgIHhqdXN0ID0gMCx5anVzdCA9IDEsdGl0bGUuYWRqID0gMCwgIG5jb2wgPTEsCiAgICAgICBidHkgPSAibiIscGNoID0gMjIscHQuY2V4ID0gMixjZXggPSAxLHhwZD1ULHRpdGxlID0gIlN0dWR5IEdyb3VwcyIsCiAgICAgICBwdC5iZyA9IHBhbCkKCgpwYXIobWFyPWMoMCw0LjUsMCwuNSkpICNiLGwsdCxyCmVtcHR5X3Bsb3QoKQpsZWdlbmQoeCA9IHBhcigidXNyIilbYygxKV0sCiAgICAgICAgIHkgPSBwYXIoInVzciIpW2MoNCldLAogICAgICAgICBsZWdlbmQgPSBsdmxbMToxMl0seGp1c3QgPSAwLHlqdXN0ID0gMSwKICAgICAgICAgYnR5ID0gIm4iLHBjaCA9IDIyLHB0LmNleCA9IDIsY2V4ID0gMSx4cGQ9VCwKICAgICAgICAgcHQuYmcgPSB0YXhhX3BhbCkKCgpwYXIobWFyPWMoMCwwLDAsMSkpICNiLGwsdCxyCmVtcHR5X3Bsb3QoKQpsZWdlbmQoeCA9IHBhcigidXNyIilbYygxKV0sCiAgICAgICAgIHkgPSBwYXIoInVzciIpW2MoNCldLAogICAgICAgICBsZWdlbmQgPSBsdmxbMTM6MTddLHhqdXN0ID0gMCx5anVzdCA9IDEsCiAgICAgICAgIGJ0eSA9ICJuIixwY2ggPSAyMixwdC5jZXggPSAyLGNleCA9IDEseHBkPVQsCiAgICAgICAgIHB0LmJnID0gdGF4YV9wYWxbMTM6MTddKQoKCiMjIyBDICsgRAojIyMjIyMjIyMjIyMjIyMjCiMgU1RVRFkgR1JPVVBTICMKIyMjIyMjIyMjIyMjIyMjIwoKIyMjIExvdXZhaW4gIyMjCmcgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KGFzLm1hdHJpeChTTk5fcGFydGljaXBhbnQpLCBtb2RlID0gInVuZGlyZWN0ZWQiLGRpYWcgPSBGLHdlaWdodGVkID0gVCkKc2V0LnNlZWQoMSkKbCA8LSBsYXlvdXRfd2l0aF9mcihnLG5pdGVyPTMwMDAsc3RhcnQudGVtcD0zMCkKCnBhcihtYXI9YygwLDAsMCwxKSkgI2IsbCx0LHIKcGxvdCggZyAsIHZlcnRleC5sYWJlbC5jZXg9MC4wMDAwMDEgLCB2ZXJ0ZXguY29sb3IgPSBwYWxbZmFjdG9yKGdyb3VwX2Fubm90YXRpb24pXSAsCiAgICAgIGVkZ2Uud2lkdGg9ICAoIEUoZykkd2VpZ2h0IC8gbWF4KEUoZykkd2VpZ2h0KSkgLAogICAgICB2ZXJ0ZXguc2l6ZT0xMCwgbGF5b3V0PWwsCiAgICAgIGVkZ2UuY29sb3I9Y29sb3JSYW1wUGFsZXR0ZShjKCJncmV5OTUiLCJibGFjayIpKSg5MCkgWyByb3VuZCggRShnKSR3ZWlnaHQgLyBtYXgoRShnKSR3ZWlnaHQpICogODggKSsxIF0gKQp0aXRsZShtYWluID0gIkxvdXZhaW4iLCBsaW5lID0gLTEsIGNleC5tYWluID0gMSkKCiNhZGQgbGFiZWwKYWRkX2xldHRlcihmaWdsYWJlbHNbMV0pOyBmaWdsYWJlbHMgPC0gZmlnbGFiZWxzWy0xXQoKIyMjIFVNQVAgIyMjCmFsbF9taWNyb2Jpb21lIDwtIGRhdGFzZXRzX2FsbF9zYW1wbGVzW1siQVNWX0x1bWluYWxfbm9ybWFsaXplZCJdXQphbGxfbWljcm9iaW9tZSA8LSBhbGxfbWljcm9iaW9tZVsgcm93U3VtcyhhbGxfbWljcm9iaW9tZT4wKSA+PSAzICwgIF0KY29ycyA8LSBjb3IoYWxsX21pY3JvYmlvbWVbLF0sIG1ldGhvZCA9ICJwZWFyc29uIikKYWRqIDwtICgxLWNvcnMpLzIKVSA8LSB1d290Ojp1bWFwKGFkaixuX25laWdoYm9ycyA9IDMwKQpwbG90KCBnICwgdmVydGV4LmxhYmVsLmNleD0wLjAwMDAwMSAsIHZlcnRleC5jb2xvciA9IHBhbFtmYWN0b3IoZ3JvdXBfYW5ub3RhdGlvbildICwgCiAgICAgIGVkZ2Uud2lkdGg9ICAoIEUoZykkd2VpZ2h0IC8gbWF4KEUoZykkd2VpZ2h0KSkgLGxheW91dD1VLAogICAgICB2ZXJ0ZXguc2l6ZT0xMCwKICAgICAgZWRnZS5jb2xvcj1jb2xvclJhbXBQYWxldHRlKGMoImdyZXk5NSIsImJsYWNrIikpKDkwKSBbIHJvdW5kKCBFKGcpJHdlaWdodCAvIG1heChFKGcpJHdlaWdodCkgKiA4OCApKzEgXSApCnRpdGxlKG1haW4gPSAiVU1BUCIsIGxpbmUgPSAtMSwgY2V4Lm1haW4gPSAxKQoKI2FkZCBsYWJlbAphZGRfbGV0dGVyKGZpZ2xhYmVsc1sxXSk7IGZpZ2xhYmVscyA8LSBmaWdsYWJlbHNbLTFdCgpgYGAKCioqRmlndXJlIDEuIENoYXJhY3Rlcml6YXRpb24gb2YgYSBoaWdobHkgZGl2ZXJzZW1pY3JvYmlvbWUgaW4gY2Vydmljb3ZhZ2luYWwgKGx1bWluYWwpIHNhbXBsZXMgZnJvbSBLZW55YW4gc2V4IHdvcmtlcnMuKiogQ2Vydmljb3ZhZ2luYWwgbGF2YWdlIChsdW1pbmFsKSBhbmQgZWN0b2NlcnZpY2FsIHRpc3N1ZSBzdHVkeSBzYW1wbGVzIHdlcmUgYXNzZXNzZWQgYnkgMTZTIHJSTkEgc2VxdWVuY2luZywgZ2VuZSBleHByZXNzaW9uLCBhbmQgcHJvdGVpbiBwcm9maWxpbmcuICoqYSoqIFNjaGVtYXRpYyBkcmF3aW5nIGRlcGljdGluZyB0aGUgc2FtcGxpbmcgc2NoZW1lIGFuZCB0aGUgcmVzdWx0aW5nIG9taWNzIGRhdGFzZXRzLiAqKmIqKiBCYXIgcGxvdHMgb2YgYWxwaGEgZGl2ZXJzaXR5IGluZGljZXMgYW5kIHRheG9ub215IHByb2ZpbGVzIGZvciBlYWNoIGluZGl2aWR1YWwgbHVtaW5hbCBzYW1wbGUuIENvbG9yLWNvZGVkIHNxdWFyZXMgYWJvdmUgdGhlIHN0YWNrZWQgYmFyIHBsb3RzIGluZGljYXRlIGJhY3RlcmlhbCB2YWdpbm9zaXMgKEJWLCBiaW5uZWQgTnVnZW504oCZcyBzY29yZXMpOiBHcmF5OiBuZWdhdGl2ZSwgb3JhbmdlOiBpbnRlcm1lZGlhdGUsIHJlZDogcG9zaXRpdmU7IGFuZCBISVYgZGlhZ25vc2lzOiBHcmF5OiBISVYgc2Vyb25lZ2F0aXZlLCByZWQ6IEhJViBzZXJvcG9zaXRpdmUuIFR3bzEyLVNOTiBncmFwaHMgd2VyZSBjb25zdHJ1Y3RlZCB1c2luZzoKKipjKiogTG91dmFpbiBjb21tdW5pdHkgZGV0ZWN0aW9uIGFsZ29yaXRobSwgYW5kIGQgVW5pZm9ybSBNYW5pZm9sZCBBcHByb3hpbWF0aW9uIChVTUFQKS4gVGhlIHR3byBncmFwaHMgd2VyZSBvdmVybGF5ZWQgaW4gY29sb3Igd2l0aCB0aGUgcHJlZGVmaW5lZCBsdW1pbmFsIHN0dWR5IGdyb3Vwcy4gVGhlIHVuZGlyZWN0ZWQgZWRnZXMgYXJlIGluY2x1ZGVkIGluIGdyYXkgY29ubmVjdGluZyB0aGUgbm9kZXMKCmBgYHtyIFN1cHBsLiBUYWJsZSAxLn0KIyBUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UgCnJhdyA8LSBjKCJBU1ZfTHVtaW5hbCIsICJBU1ZfVGlzc3VlIikgJT4lIHNldF9uYW1lcygpCnJhd19saXN0IDwtIHJhdyAlPiUKICBtYXAoLiwgfnJlYWRfY3N2KHBhc3RlMCgiLi4vLi4vcmVzdWx0cy8wMl9kYXRhX3ByZXByb2Nlc3Npbmdfb3V0cHV0LyIsLngsIl9yYXdfY291bnRzLmNzdiIpKSkgICU+JQogIG1hcCguLCB+Y29sdW1uX3RvX3Jvd25hbWVzKC4sIHZhciA9ICJYMSIpKSAlPiUgICAgICAgICAgCiAgbWFwKC4sIH5kcGx5cjo6c2VsZWN0KC4sIGFueV9vZihzYW1wbGVfdXNlKSkpIAogICAgICAgICAgICAKciA8LSByYXdfbGlzdCAlPiUKICBtYXAoLiwgfm11dGF0ZSguLGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiAuL3N1bSguKSkpICkgJT4lCiAgbWFwKC4sIH4ocm93U3VtcygueCkvbGVuZ3RoKGNvbG5hbWVzKC54KSkgKSoxMDAgKSAlPiUKICBiaW5kX3Jvd3MoLiwgLmlkPSJJRCIpICU+JQogICAgcGl2b3RfbG9uZ2VyKC1JRCkgJT4lIAogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IElELCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUKICAgIG11dGF0ZV9hdCh2YXJzKG5hbWUpLCB+cmVwbGFjZSguLCBBU1ZfTHVtaW5hbDwwLjU1MTQzOTIsICJPdGhlciIpKSAlPiUKICAgIG11dGF0ZShuYW1lID0gaWZlbHNlKC4kbmFtZT09Ik5vdCBhc3NpZ25lZCIsICJPdGhlciIsIC4kbmFtZSkpICU+JQogICAgZ3JvdXBfYnkobmFtZSkgJT4lCiAgICBzdW1tYXJpemUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+c3VtKC4pKSkgJT4lCiAgICBhcnJhbmdlKC1BU1ZfTHVtaW5hbCkgJT4lCiAgICBkcGx5cjo6cmVuYW1lKEx1bWluYWw9IkFTVl9MdW1pbmFsIixUaXNzdWU9IkFTVl9UaXNzdWUiKSAlPiUKICAgIHJlbmFtZShUYXhhPSJuYW1lIikgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnJvdW5kKC54LCBkaWdpdHMgPSAxKSkpCiAgCiMgQWxmYSBEaXZlcnNpdHkgU3RhdHMKZGl2X3N0YXQgPC0gZGl2X2xpc3QgJT4lCiAgc2V0X25hbWVzKG1hcChBU1YsMSkpICU+JQogIG1hcCguLCB+c3VtbWFyaXNlX2lmKC54LCBpcy5udW1lcmljLCBsaXN0KG1lZGlhbj1tZWRpYW4sIElRUj1JUVIpLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBtYXAoLiwgfnBpdm90X2xvbmdlcigueCwgZXZlcnl0aGluZygpLCBuYW1lc19zZXAgPSAiXyIsIG5hbWVzX3RvID0gYygiLnZhbHVlIiwgIlN0YXRzIiksICkpICU+JQogIGJpbmRfcm93cyguaWQgPSAiU2FtcGxlIHR5cGUiKSAlPiUKICBtdXRhdGUoIlNhbXBsZSB0eXBlIiA9IGdzdWIoIl9nciIsICIiLCAuJCJTYW1wbGUgdHlwZSIpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+cm91bmQoLngsIGRpZ2l0cyA9IDIpKSkKCiMgQmFjdGVyaWFsIENvbW11bml0aWVzCmJhY19jb21tdW5pdGllcyA8LSBiYWNfY29tbXVuaXRpZXMgJT4lIAogIG11dGF0ZSgiYmFjdGVyaWFsIGNvbW11bml0aWVzIj0gZmFjdG9yKHBhc3RlMCgiQkMiLHNwcmludGYoIiUwMmQiLGJhY19jb21tdW5pdGllcyRCYWN0X2NvbSkpKSkgJT4lCiAgc2VsZWN0KC1CYWN0X2NvbSkgJT4lCiAgYXJyYW5nZShgYmFjdGVyaWFsIGNvbW11bml0aWVzYCkKCnBhZ2VzIDwtIGxpc3QoIlRvdGFsIFJlbGF0aXZlIEFidW5kYW5jZSI9ciAsIkFsZmEgRGl2ZXJzaXR5Ij1kaXZfc3RhdCwgIkJhY3RlcmlhbCBDb21tdW5pdGllcyI9YmFjX2NvbW11bml0aWVzKQp3cml0ZS54bHN4KHBhZ2VzLCBmaWxlPXBhc3RlMChyZXN1bHRfZGlyLCJTdXBwbC5UYmwuMDEiLCIueGxzeCIpKQphbHBhX2RpdiA8LSBzZXRfbmFtZXMoZGl2X2xpc3QsIGMoIkx1bWluYWwiLCJUaXNzdWUiKSkgJT4lCiAgbWFwMiguLCBjKCJMdW1pbmFsX2dyIiwgIlRpc3N1ZV9nciIpLCB+bGVmdF9qb2luKC54LCBzZWxlY3QobWV0YWRhdGEsIElELCAueSksIGJ5PSJJRCIpKSAlPiUKICBtYXAyKC4sIGMoIkx1bWluYWxfZ3IiLCAiVGlzc3VlX2dyIiksIH5zZWxlY3QoLngsIElELCAueSwgZXZlcnl0aGluZygpKSkKd3JpdGUueGxzeChhbHBhX2RpdiwgZmlsZT1wYXN0ZTAocmVzdWx0X2RpciwiYWxwaGFfZGl2ZXJzaXR5IiwiLnhsc3giKSkKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojIyMjIyMjIyMjIyMjCiMgVE9QIERHRXMgIwojIyMjIyMjIyMjIyMjCnBfdmFsIDwtIHB1bGwodG9wLCAiUFZhbHVlIikKdG9wX2RnZSA8LSAocF92YWwgPCAwLjAxKSAjJiAocm93U3VtcyggYWJzKHRvcFssZ3JlcCgibG9nRkMiLGNvbG5hbWVzKHRvcCkpXSkgPj0gbG9nMigxLjUpICkgPj0gMSkKdG9wX2RnZSA8LSB0b3AkR2VuZXNbIHRvcF9kZ2UgXQoKdG9wX1RSWF9jb3VudHMgPC0gZWRnZVI6OmNwbSh5LG5vcm1hbGl6ZWQubGliLnNpemVzID0gVCxsb2cgPSBUKVt0b3BfZGdlLCBdCnRvcF9UUlhfY291bnRzIDwtIHQoYXBwbHkodG9wX1RSWF9jb3VudHMsMSxmdW5jdGlvbih4KXtzY2FsZSh4LFQsVCl9KSkKdG9wX1RSWF9jb3VudHNbdG9wX1RSWF9jb3VudHMgPiA1XSA8LSA1CmNvbG5hbWVzKHRvcF9UUlhfY291bnRzKSA8LSBjb2xuYW1lcyhUUlhfY291bnRzKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBVTUFQIE9OIFRPUCBER0UgUk5Bc2VxICMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbXlwYXIoMiwzLG1hcj1jKDIsMiwyLDYpKQpzZXQuc2VlZCgxKQpVTUFQX1RSWCA8LSB1d290Ojp1bWFwKHQodG9wX1RSWF9jb3VudHMpLG5fbmVpZ2hib3JzID0gMTAsCiAgICAgICAgICAgICAgICAgbWV0cmljID0gImNvcnJlbGF0aW9uIixtaW5fZGlzdCA9IDAuMSxzcHJlYWQgPSA1LAogICAgICAgICAgICAgICAgIG5lZ2F0aXZlX3NhbXBsZV9yYXRlID0gMTApCnBsb3QoVU1BUF9UUlgsYmc9cGFsW2dyb3VwX2Fubm90YXRpb25bc2FtcGxlX3VzZV1dLG1haW49IlVNQVAgb24gdG9wIERHRSBSTkFzZXEiLAogICAgIHBjaD0yMSx4bGFiPSJVTUFQMSIseWxhYj0iVU1BUDIiLGZyYW1lPUYsYXhlcz1GKQpsZWdlbmQocGFyKCJ1c3IiKVsyXSxwYXIoInVzciIpWzRdLHRpdGxlLmFkaiA9IDAsCiAgICAgICBsZWdlbmQgPSBsZXZlbHMoZmFjdG9yKGdyb3VwX2Fubm90YXRpb24pKSx4anVzdCA9IDAseWp1c3QgPSAxLAogICAgICAgYnR5ID0gIm4iLHBjaCA9IDIxLHB0LmJnID0gcGFsLHB0LmNleCA9IDEseHBkPVQpCmBgYAoK