Cluster testing from Weinstock002 data 8DEC21
Libraries
library(dendextend)
library(DESeq2)
library(colorspace)
library(RColorBrewer)
library(DESeq2)
library(ggplot2)
library(dplyr)
library(reshape2)
library(plotly)
library(gridExtra)
library(gplots)
library(pals)
library(pheatmap)
library(colorspace)
library(scico)
Full PROseq data set analysis for TCL cell lines
https://talgalili.github.io/dendextend/articles/Cluster_Analysis.html
rld_all <- rlog(dds_pro, blind=TRUE)
#colnames(rld_all) <- paste0(sampleNames_all,"(",subTypes_all,")")
sampleDists_all <- dist(t(assay(rld_all)))
sampleDistMtx_all <- as.matrix(sampleDists_all)
rownames(sampleDistMtx_all) <- paste0(rld_all$sample,"_",rld_all$subtype)
colnames(sampleDistMtx_all) <- NULL
hclust_all <- hclust(sampleDists_all)
norm_all <- as.data.frame(counts(dds_pro, normalized=TRUE)) #think this is redundant with normcounts_all but keeping it for now
colnames(norm_all) <- dds_pro$sample
Do initial dendrograms and determine PCA contributors
plotPCA(rld_all, intgroup="subtype")

plotPCA(rld_all, intgroup="sample")

plot(hclust_all, labels=rownames(sampleDistMtx_all), main="PRO-seq All Sample dREG Dendrogram")
pdf("dREG_hclust.sample.pdf")
plot(hclust_all, labels=rownames(sampleDistMtx_all), main="PRO-seq All Sample dREG Dendrogram")
dev.off()
quartz_off_screen
2

Determine if you can adjust the number of PCA contributors to cleanly separate subtypes
plotPCA(rld_all, intgroup="subtype", ntop=100) + ggtitle("Top 100")

plotPCA(rld_all, intgroup="subtype", ntop=200) + ggtitle("Top 200")

plotPCA(rld_all, intgroup="subtype", ntop=500) + ggtitle("Top 500")

plotPCA(rld_all, intgroup="subtype", ntop=1000) + ggtitle("Top 1000")

plotPCA(rld_all, intgroup="subtype", ntop=2000) + ggtitle("Top 2000")

plotPCA(rld_all, intgroup="subtype", ntop=5000) + ggtitle("Top 5000")

plotPCA(rld_all, intgroup="subtype", ntop=10000) + ggtitle("Top 10000")

plotPCA(rld_all, intgroup="subtype", ntop=20000) + ggtitle("Top 20000")

plotPCA(rld_all, intgroup="subtype", ntop=50000) + ggtitle("Top 50000")

plotPCA(rld_all, intgroup="subtype", ntop=120888) + ggtitle("All")
pdf("dREG_pca.all.pdf")
plotPCA(rld_all, intgroup="subtype", ntop=100) + ggtitle("Top 100")
plotPCA(rld_all, intgroup="subtype", ntop=200) + ggtitle("Top 200")
plotPCA(rld_all, intgroup="subtype", ntop=500) + ggtitle("Top 500")
plotPCA(rld_all, intgroup="subtype", ntop=1000) + ggtitle("Top 1000")
plotPCA(rld_all, intgroup="subtype", ntop=2000) + ggtitle("Top 2000")
plotPCA(rld_all, intgroup="subtype", ntop=5000) + ggtitle("Top 5000")
plotPCA(rld_all, intgroup="subtype", ntop=10000) + ggtitle("Top 10000")
plotPCA(rld_all, intgroup="subtype", ntop=20000) + ggtitle("Top 20000")
plotPCA(rld_all, intgroup="subtype", ntop=50000) + ggtitle("Top 50000")
plotPCA(rld_all, intgroup="subtype", ntop=77061) + ggtitle("All")
dev.off()
quartz_off_screen
2

#Note: can make this a nicer grid with shared axes?
Rank dREG peaks by PCA contribution and measure variance and cumulative variance
#Load dREG peak annotations
dREG_annot2 <- read.table("../002_TCLs_p1000_dREGpeak_annotation.txt", sep="\t", header=TRUE)
#Define and rank top 10k PCA contributors
rv <- rowVars(assay(rld_all))
select <- order(rv, decreasing=TRUE)#[seq_len(min(10000, length(rv)))]
pc <- prcomp(t(assay(rld_all)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
pcRank_all <- data.frame("peakID"=rownames(loadings), "PCA.rank"=seq.int(nrow(loadings)))
#sweep(aload, 2, colSums(aload), "/")
###clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Generate list of dREG peak annotations
peakInfo_all <- merge(dREG_annot2, pcRank_all, by.x="peakID", by.y="peakID")
peakVar_all <- data.frame("peakID"=rownames(assay(rld_all)))
peakVar_all$rlog.variance <- rowVars(as.matrix(assay(rld_all)))
peakVar_all <- merge(peakInfo_all, peakVar_all, by.x="peakID", by.y="peakID")
pdf("variance.pdf")
ggplot(peakVar_all, aes(x=PCA.rank, y=rlog.variance)) + geom_line() + geom_vline(xintercept=5000, linetype="dotted")
dev.off()
null device
1
ggplot(peakVar_all, aes(x=PCA.rank, y=rlog.variance)) + geom_line() + geom_vline(xintercept=5000, linetype="dotted")
#add plot of fraction of explained variance.. running sum / total vs rank
peakVar_all <- peakVar_all[order(peakVar_all$PCA.rank),]
peakVar_all$cumulative.Variance <- cumsum(peakVar_all$rlog.variance)/sum(peakVar_all$rlog.variance)
pdf("cumulative_variance.pdf")
ggplot(peakVar_all, aes(x=PCA.rank, y=cumulative.Variance)) + geom_line() + geom_vline(xintercept=5000, linetype="dotted")
dev.off()
quartz_off_screen
2

ggplot(peakVar_all, aes(x=PCA.rank, y=cumulative.Variance)) + geom_line() + geom_vline(xintercept=5000, linetype="dotted")

Filter rld objects by samples… separate training set from “test” set (SUM149 and SUM159)
#Separate training and test set
filt <- which(!colnames(rld_all) %in% c("HUT78","HUT102", "Su9T01", "FEPD", "MOTN1", "OCILY12", "SMZ1"))
rld_train <- rld_all[,filt]
filt <- which(colnames(rld_all) %in% c("HUT78","HUT102", "Su9T01", "FEPD", "MOTN1", "OCILY12", "SMZ1"))
rld_test <- rld_all[,filt]
filt <- which(!colnames(norm_all) %in% c("HUT78","HUT102", "Su9T01", "FEPD", "MOTN1", "OCILY12", "SMZ1"))
norm_train <- norm_all[,filt]
filt <- which(colnames(norm_all) %in% c("HUT78","HUT102", "Su9T01", "FEPD", "MOTN1", "OCILY12", "SMZ1"))
norm_test <- norm_all[,filt]
Determine the number of PCA contributors necessary to cleanly separate subtypes
Sample grouping looks pretty good between 5k and 10k top contributors. Will look at these cutoffs in more detail.
Rank dREG peaks by PCA contribution and measure variance and cumulative variance
#Define and rank top 10k PCA contributors
rv <- rowVars(assay(rld_train))
select <- order(rv, decreasing=TRUE)#[seq_len(min(10000, length(rv)))]
pc <- prcomp(t(assay(rld_train)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
pcRank2 <- data.frame("peakID"=rownames(loadings), "PCA.rank"=seq.int(nrow(loadings)))
#sweep(aload, 2, colSums(aload), "/")
###clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Generate list of dREG peak annotations
peakInfo2 <- merge(dREG_annot2, pcRank2, by.x="peakID", by.y="peakID")
peakVar2 <- data.frame("peakID"=rownames(assay(rld_train)))
peakVar2$rlog.variance <- rowVars(as.matrix(assay(rld_train)))
peakVar2 <- merge(peakInfo2, peakVar2, by.x="peakID", by.y="peakID")
ggplot(peakVar2, aes(x=PCA.rank, y=rlog.variance)) + geom_line() + geom_vline(xintercept=c(500,1000,2000,5000,10000), linetype="dotted")

#add plot of fraction of explained variance.. running sum / total vs rank
peakVar2 <- peakVar2[order(peakVar2$PCA.rank),]
peakVar2$cumulative.Variance <- cumsum(peakVar2$rlog.variance)/sum(peakVar2$rlog.variance)
ggplot(peakVar2, aes(x=PCA.rank, y=cumulative.Variance)) + geom_line() + geom_vline(xintercept=c(500,1000,2000,5000,10000), linetype="dotted")

5k seems reasonable
Filter for top 5k PCA contributors
#filter normalized counts for top 5k PCA contributors
top5k <- filter(peakVar2, PCA.rank<=5000)$peakID
norm_top5k <- norm_train[which((rownames(norm_train) %in% top5k)==TRUE),]
rld_top5k_train <- subset(assay(rld_train), rownames(assay(rld_train)) %in% top5k)
rld_top5k_test <- subset(assay(rld_test), rownames(assay(rld_test)) %in% top5k)
rld_top5k_all <- subset(assay(rld_all), rownames(assay(rld_test)) %in% top5k)
Calculate sample distances with new top5k training and matched test sets, then calculate the correlation between the branchpoints of the two
d_train <- rld_top5k_train %>% dist %>% hclust %>% as.dendrogram
d_test <- rld_top5k_test %>% dist %>% hclust %>% as.dendrogram
d_all <- rld_top5k_all %>% dist %>% hclust %>% as.dendrogram
#compare clusters excluding unclustered to unclustered alone
d_train_test <- dendlist(train = d_train, test = d_test)
d_train_test %>% cor.dendlist
train test
train 1.0000000 0.3858571
test 0.3858571 1.0000000
d_train_test %>% cor.dendlist(method_coef = "spearman")
train test
train 1.0000000 0.3896877
test 0.3896877 1.0000000
Bk_plot(d_train, d_test, k = 2:30, xlim = c(2,30), main = "TCL Train Set vs non-significant clusters Bk plot")

#compare clusters excluding unclustered to clusters using all samples
d_train_all <- dendlist(train = d_train, all = d_all)
d_train_all %>% cor.dendlist
train all
train 1.0000000 0.4299217
all 0.4299217 1.0000000
d_train_all %>% cor.dendlist(method_coef = "spearman")
train all
train 1.00000 0.44151
all 0.44151 1.00000
Bk_plot(d_train, d_all, k = 2:30, xlim = c(2,30), main = "TCL Train Set vs All Samples Bk plot")

#compare clusters all sample clustering to unclustered alone
d_all_test <- dendlist(all = d_all, test = d_test)
d_all_test %>% cor.dendlist
all test
all 1.0000000 0.5231135
test 0.5231135 1.0000000
d_all_test %>% cor.dendlist(method_coef = "spearman")
all test
all 1.0000000 0.5082297
test 0.5082297 1.0000000
Bk_plot(d_all, d_test, k = 2:30, xlim = c(2,30), main = "All Samples vs. non-significant clusters Bk plot")

3k clusters?
Now some fun with Tanglegrams…
pre_tang_d_train_test <- d_train_test %>% ladderize %>% untangle %>% set("branches_k_color", k = 3)
train_branches_colors <- get_leaves_branches_col(pre_tang_d_train_test$train)
pre_tang_d_train_test %>% tanglegram(fast = T, color_lines = train_branches_colors)

pre_tang_d_train_all <- d_train_all %>% ladderize %>% untangle %>% set("branches_k_color", k = 3)
train_branches_colors <- get_leaves_branches_col(pre_tang_d_train_all$train)
pre_tang_d_train_all %>% tanglegram(fast = T, color_lines = train_branches_colors)

pre_tang_d_all_test <- d_all_test %>% ladderize %>% untangle %>% set("branches_k_color", k = 3)
train_branches_colors <- get_leaves_branches_col(pre_tang_d_all_test$all)
pre_tang_d_all_test %>% tanglegram(fast = T, color_lines = train_branches_colors)

The three different sets lead to drastically different cluster designations. Will attempt to look at overlap between cluster sets though it is somewhat arbitrary which samples end up being the hold-outs.
Only highlight genes clustered in common
#d_train_test_common <- d_train_test %>% prune_common_subtrees.dendlist
#d_train_test_common %>% untangle %>% tanglegram(common_subtrees_color_branches = TRUE)
#d_train_all_common <- d_train_all %>% prune_common_subtrees.dendlist
#d_train_all_common %>% untangle %>% tanglegram(common_subtrees_color_branches = TRUE)
#d_all_test_common <- d_all_test %>% prune_common_subtrees.dendlist
#d_all_test_common %>% untangle %>% tanglegram(common_subtrees_color_branches = TRUE)
Quite a few shared leaves between the training set and all. Let’s see what they are…
#d_train_test %>% nleaves
#d_train_test_common %>% nleaves
#d_train_all %>% nleaves
#d_train_all_common %>% nleaves
#d_all_test %>% nleaves
#d_all_test_common %>% nleaves
n leaves preserved between the subset and all samples.
Next is to figure a way to define expression/activity groups: - k-means as before - or - dynamic branch cutting -
using top 5k PCA contributors (as determined a reasonable cutoff in the variance plots)
#filter normalized counts for top 5k PCA contributors
top5k_all <- filter(peakVar_all, PCA.rank<=5000)$peakID
bot5k_all <- filter(peakVar_all, PCA.rank>115888)$peakID
norm_top5k_all <- norm_all[which((rownames(norm_all) %in% top5k_all)==TRUE),]
rld_top5k_all <- subset(assay(rld_all), rownames(assay(rld_all)) %in% top5k_all)
colnames(norm_top5k_all) <- colnames(rld_top5k_all)
rld_bot5k_all <- subset(assay(rld_all), rownames(assay(rld_all)) %in% bot5k_all)
(row.names(rld_top5k_all) %in% row.names(rld_bot5k_all))==FALSE #check dREGs pulled into top and bottom do not match- should run T for all
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[20] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[39] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[58] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[77] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[96] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[115] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[134] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[153] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[172] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[191] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[210] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[229] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[248] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[267] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[286] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[305] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[324] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[343] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[362] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[381] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[400] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[419] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[438] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[457] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[476] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[495] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[514] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[533] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[552] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[571] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[590] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[609] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[628] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[647] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[666] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[685] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[704] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[723] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[742] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[761] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[780] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[799] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[818] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[837] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[856] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[875] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[894] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[913] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[932] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[951] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[970] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[989] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[ reached getOption("max.print") -- omitted 4000 entries ]
#scale() function centers values +/- the mean of each column for normalized counts or rlog normalized counts
scaledata_count_top <- t(scale(t(norm_top5k_all))) # Centers and scales data.
scaledata_count_top <- scaledata_count_top[complete.cases(scaledata_count_top),] # Removes rows with nulls
scaledata_rld_top <- t(scale(t(rld_top5k_all))) # Centers and scales data.
scaledata_rld_top <- scaledata_rld_top[complete.cases(scaledata_rld_top),] # Removes rows with nulls
scaledata_rld_all <- t(scale(t(assay(rld_all))))
scaledata_rld_all <- scaledata_rld_all[complete.cases(scaledata_rld_all),]
scaledata_bot <- t(scale(t(rld_bot5k_all)))
scaledata_bot <- scaledata_bot[complete.cases(scaledata_bot),]
#also try with relative activity scaling
scaledata_rel_top <- data.frame(row.names=rownames(norm_top5k_all))
scaledata_rel_top$max.dREG.counts <- apply(norm_top5k_all[1:ncol(norm_top5k_all)], 1, max, na.rm=TRUE)
i=1
while (i<=ncol(norm_top5k_all)){
scaledata_rel_top[paste0(names(norm_top5k_all[i]))] <- norm_top5k_all[,i]/scaledata_rel_top$max.dREG.counts
i=i+1
}
#Generate column and row hierarchical clustering for each normalization method (all spearman for now)
hr_count <- hclust(as.dist(1-cor(t(scaledata_count_top), method="spearman")), method="complete") # Cluster rows by Pearson correlation.
hc_count <- hclust(as.dist(1-cor(scaledata_count_top, method="spearman")), method="complete") # Clusters columns by Spearman correlation.
hr_rld <- hclust(as.dist(1-cor(t(scaledata_count_top), method="spearman")), method="complete") # Cluster rows by Pearson correlation.
hc_rld <- hclust(as.dist(1-cor(scaledata_rld_top, method="spearman")), method="complete") # Clusters columns by Spearman correlation.
hr_bot <- hclust(as.dist(1-cor(t(scaledata_bot), method="spearman")), method="complete")
hr_rel <- hclust(as.dist(1-cor(t(scaledata_rel_top[,c(2:26)]), method="spearman")), method="complete") # Cluster rows by Pearson correlation.
hc_rel <- hclust(as.dist(1-cor(scaledata_rel_top[,c(2:26)], method="spearman")), method="complete") # Clusters columns by Spearman correlation.
Dynamic Branch Cutting Test (3-5)
library(dendextend)
cnt_cutk3 <- cutree(hr_count,k=3) #cut at specific height h or cut for a specific number of clusters k
cnt_cutk4 <- cutree(hr_count,k=4)
cnt_cutk5 <- cutree(hr_count,k=5)
rld_cutk2 <- cutree(hr_rld,k=2)
rld_cutk3 <- cutree(hr_rld,k=3)
rld_cutk4 <- cutree(hr_rld,k=4)
rld_cutk5 <- cutree(hr_rld,k=5)
rld_cutk6 <- cutree(hr_rld,k=6)
rld_cutk7 <- cutree(hr_rld,k=7)
rld_cutk8 <- cutree(hr_rld,k=8)
rld_cutk9 <- cutree(hr_rld,k=9)
rld_cutk10 <- cutree(hr_rld,k=10)
rld_bot5k_all <- as.integer(rep(0, 5000))
names(rld_bot5k_all) <- bot5k_all
rel_cutk3 <- cutree(hr_rel,k=3)
rel_cutk4 <- cutree(hr_rel,k=4)
rel_cutk5 <- cutree(hr_rel,k=5)
#plot the tree
TreeR_cnt = as.dendrogram(hr_count, method="average")
TreeR_rld = as.dendrogram(hr_rld, method="average")
TreeR_rel = as.dendrogram(hr_rel, method="average")
#define annotation bars
the_bars_k3 <- cbind(cnt_cutk3, rld_cutk3, rel_cutk3)
the_bars_k4 <- cbind(cnt_cutk4, rld_cutk4, rel_cutk4)
the_bars_k5 <- cbind(cnt_cutk5, rld_cutk5, rel_cutk5)
the_bars_cnt <- cbind(cnt_cutk3, cnt_cutk4, cnt_cutk5)
the_bars_rld <- cbind(rld_cutk3, rld_cutk4, rld_cutk5)
the_bars_rel <- cbind(rel_cutk3, rel_cutk4, rel_cutk5)
Compare clusters
plot(TreeR_rld,
leaflab = "none",
main = "dREG Peak Clustering (rlog) k=3",
ylab = "Height")
#this makes the bar
colored_bars(the_bars_k3, TreeR_rld, sort_by_labels_order = T, y_shift=-0.1, rowLabels = c("By Counts","By rLog","By Relative Activity"),cex.rowLabels=0.7)

plot(TreeR_rld,
leaflab = "none",
main = "dREG Peak Clustering (rlog) k=4",
ylab = "Height")
#this makes the bar
colored_bars(the_bars_k4, TreeR_rld, sort_by_labels_order = T, y_shift=-0.1, rowLabels = c("By Counts","By rLog","By Relative Activity"),cex.rowLabels=0.7)

plot(TreeR_rld,
leaflab = "none",
main = "dREG Peak Clustering (rlog) k=5",
ylab = "Height")
#this makes the bar
colored_bars(the_bars_k5, TreeR_rld, sort_by_labels_order = T, y_shift=-0.1, rowLabels = c("By Counts","By rLog","By Relative Activity"),cex.rowLabels=0.7)

Clustering is exactly the same regardless of method now!! This is great!
Compare clusters
plot(TreeR_cnt,
leaflab = "none",
main = "dREG Peak Clustering (counts)",
ylab = "Height")
#this makes the bar
colored_bars(the_bars_cnt, TreeR_cnt, sort_by_labels_order = T, y_shift=-0.1, rowLabels = c("k=3","k=4","k=5"),cex.rowLabels=0.7)

plot(TreeR_rld,
leaflab = "none",
main = "dREG Peak Clustering (rlog)",
ylab = "Height")
#this makes the bar
colored_bars(the_bars_rld, TreeR_rld, sort_by_labels_order = T, y_shift=-0.1, rowLabels = c("k=3","k=4","k=5"),cex.rowLabels=0.7)

plot(TreeR_rel,
leaflab = "none",
main = "dREG Peak Clustering (relative activity)",
ylab = "Height")
#this makes the bar
colored_bars(the_bars_rel, TreeR_rel, sort_by_labels_order = T, y_shift=-0.1, rowLabels = c("k=3","k=4","k=5"),cex.rowLabels=0.7)

Let’s see how well these clusters separate expression groups associated with different cell line subtypes…
data_all <- c("HUT102_ATLL",
"ST1_ATLL",
"Su9T01_ATLL",
"KARPAS299_ALK+ALCL",
"L82_ALK+ALCL",
"SUPM2_ALK+ALCL",
"SMZ1_PTCL_NOS",
"MYLA_CTCL",
"MAC2A_ALK-ALCL",
"KIJK_ALK+ALCL",
"SR786_ALK+ALCL",
"FEPD_ALK-ALCL",
"KARPAS384_SQGD_TCL",
"DL40_ALK-ALCL",
"OCILY12_PTCL_NOS",
"HUT78_CTCL",
"HH_CTCL",
"MJ_CTCL",
"MTA_NKT",
"MOTN1_T_LGL",
"NKL_NKT",
"DERL2_HS_TCL",
"KHYG1_NKL",
"SeAx_CTCL",
"SUDHL1_ALK+ALCL")
#Defining box plot functions
clust.core = function(i, dat, clusters) {
ind = (clusters == i)
colMeans(dat[ind,])
}
box <- function(clusters, scaledata_count_top, title){
cores <- sapply(unique(clusters), clust.core, scaledata_count_top, clusters)
#make a dataframe of cores by subtype
d <- data.frame(cbind(data_all, cores)) #subType list from beginning!
colnames(d) <-c("sample", paste0("clust_",1:ncol(cores)))
#get the data frame into long format for plotting
dmolten <- melt(d, id.vars = "sample")
#order by subtype
dmolten <- dmolten[order(dmolten$sample),]
dmolten$sample <- ordered(dmolten$sample, levels=unique(dmolten$sample))
# make the plot
p1 <- ggplot(dmolten, aes(x=sample, y=as.numeric(value), col=variable)) +
geom_boxplot() +
# geom_point() +
# geom_line() +
# scale_x_continuous(minor_breaks = NULL, breaks=c(as.numeric(levels(factor(dmolten$subtype))))) +
# scale_y_continuous() +
xlab("Sample") +
ylab("Activity") +
labs(title= paste0("Cluster Core Expression by Sample (",title,")"),color = "Cluster")
return(p1)
}
Make boxplots
box(rld_cutk2, scaledata_rld_all, "cutk2 rlog")

box(rld_cutk3, scaledata_rld_all, "cutk3 rlog")

box(rld_cutk4, scaledata_rld_all, "cutk4 rlog")

box(rld_cutk5, scaledata_rld_all, "cutk5 rlog")

box(rld_cutk6, scaledata_rld_all, "cutk6 rlog")

box(rld_cutk7, scaledata_rld_all, "cutk7 rlog")

box(rld_cutk8, scaledata_rld_all, "cutk8 rlog")

box(rld_cutk9, scaledata_rld_all, "cutk9 rlog")

box(rld_cutk10, scaledata_rld_all, "cutk10 rlog")

box(c(rld_cutk3,rld_bot5k_all), rbind(scaledata_rld_all,scaledata_bot), "cutk3 + static [\"clust_5\"] rlog")

box(rel_cutk3, scaledata_rel_top[,2:26], "cutk3 rel")

box(rel_cutk4, scaledata_rel_top[,2:26], "cutk4 rel")

box(rel_cutk5, scaledata_rel_top[,2:26], "cutk5 rel")

box(rel_cutk3, scaledata_count_top, "cutk3 count")

box(rel_cutk4, scaledata_count_top, "cutk4 count")

box(rel_cutk5, scaledata_count_top, "cutk5 count")

Properly by subtype instead of individual samples
data_all <- c("ATLL",
"ATLL",
"ATLL",
"ALK+ALCL",
"ALK+ALCL",
"ALK+ALCL",
"PTCL_NOS",
"CTCL",
"ALK-ALCL",
"ALK+ALCL",
"ALK+ALCL",
"ALK-ALCL",
"SQGD_TCL",
"ALK-ALCL",
"PTCL_NOS",
"CTCL",
"CTCL",
"CTCL",
"NKT",
"T_LGL",
"NKT",
"HS_TCL",
"NKL",
"CTCL",
"ALK+ALCL")
#Defining box plot functions
clust.core = function(i, dat, clusters) {
ind = (clusters == i)
colMeans(dat[ind,])
}
box <- function(clusters, scaledata_count_top, title){
cores <- sapply(unique(clusters), clust.core, scaledata_count_top, clusters)
#make a dataframe of cores by subtype
d <- data.frame(cbind(data_all, cores)) #subType list from beginning!
colnames(d) <-c("subtype", paste0("clust_",1:ncol(cores)))
#get the data frame into long format for plotting
dmolten <- melt(d, id.vars = "subtype")
#order by subtype
dmolten <- dmolten[order(dmolten$subtype),]
dmolten$subtype <- ordered(dmolten$subtype, levels=unique(dmolten$subtype))
# make the plot
p1 <- ggplot(dmolten, aes(x=subtype, y=as.numeric(value), col=variable)) +
geom_boxplot() +
# geom_point() +
# geom_line() +
# scale_x_continuous(minor_breaks = NULL, breaks=c(as.numeric(levels(factor(dmolten$subtype))))) +
# scale_y_continuous() +
xlab("Subtype") +
ylab("Activity") +
labs(title= paste0("Cluster Core Expression by Subtype (",title,")"),color = "Cluster")
return(p1)
}
Make boxplots
box(rld_cutk2, scaledata_rld_all, "cutk2 rlog")

box(rld_cutk3, scaledata_rld_all, "cutk3 rlog")

box(rld_cutk4, scaledata_rld_all, "cutk4 rlog")

box(rld_cutk5, scaledata_rld_all, "cutk5 rlog")

box(rld_cutk6, scaledata_rld_all, "cutk6 rlog")

box(rld_cutk7, scaledata_rld_all, "cutk7 rlog")

box(rld_cutk8, scaledata_rld_all, "cutk8 rlog")

box(rld_cutk9, scaledata_rld_all, "cutk9 rlog")

box(rld_cutk10, scaledata_rld_all, "cutk10 rlog")

box(c(rld_cutk3,rld_bot5k_all), rbind(scaledata_rld_all,scaledata_bot), "cutk3 + static [\"clust_5\"] rlog")

box(rel_cutk3, scaledata_rel_top[,2:26], "cutk3 rel")

box(rel_cutk4, scaledata_rel_top[,2:26], "cutk4 rel")

box(rel_cutk5, scaledata_rel_top[,2:26], "cutk5 rel")

box(rel_cutk3, scaledata_count_top, "cutk3 count")

box(rel_cutk4, scaledata_count_top, "cutk4 count")

box(rel_cutk5, scaledata_count_top, "cutk5 count")

Can’t make much sense of unique clustering between the samples or their subtypes. Considering subsetting out original data into clustering and nonclustering samples and moving on with individual cluster treatments for each from there.
Want to make a heatmap with the above clusters and a cluster-trait correlation heatmap…
Trait correlation (edit for this dataset)
traits <- data.frame(row.names=colnames(scaledata_rld_all))
#here I'm adding vectors of subtype traits to the dataframe
traits$'ATLL' <- c(1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) #corrected
traits$'ALK+ALCL' <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1) #corrected
traits$'ALK-ALCL' <- c(0,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0) #corrected
traits$'NKT' <- c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0) #corrected
traits$'CTCL' <- c(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0) #corrected
traits$'T_LGL' <- c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0) #corrected
traits$'SQGD_TCL' <- c(0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0) #corrected
traits$'NKL' <- c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0) #corrected
traits$'PTCL_NOS' <- c(0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0) #corrected
traits$'HS_TCL' <- c(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0) #corrected
#Extract the gene/sample numbers
nPeaks = nrow(scaledata_rld_all)
nSamples = ncol(scaledata_rld_all)
#p value calculation from WGCNA
corPvalueStudent = function(cor, nSamples) {
T=sqrt(nSamples-2) * cor/sqrt(1-cor^2)
2*pt(abs(T),nSamples-2, lower.tail = FALSE)
}
Make correlation heatmaps
nSamples=25
#Finalize clustering and branch cuts
clusters <- rld_cutk2
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=2)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk3
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=3)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk4
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=4)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk5
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=5)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk6
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=6)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk7
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=7)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk8
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=8)",
xlab = "Traits",
ylab = "Clusters")

clusters <- rld_cutk9
cores <- sapply(unique(clusters), clust.core, scaledata_rld_all, clusters)
#correlate the cores to traits:
moduleTraitCor = cor(cores, traits, use= "p")
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
signif(moduleTraitPvalue, 1), ")", sep= "")
dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
heatmap.2(moduleTraitCor,
dendrogram = "none",
Colv =FALSE,
scale = c("none"),
col="heat.colors",
na.rm=TRUE,
cellnote = textMatrix,
notecol="grey30",
notecex=1,
trace=c("none"),
cexRow = 0.8,
cexCol = 0.8,
main = "Cluster-Trait Correlation (k=9)",
xlab = "Traits",
ylab = "Clusters")

#clusters <- c(rld_cutk4,rld_bop5k_all)
#cores <- sapply(unique(clusters), clust.core, rbind(scaledata_rld_top, scaledata_bot), clusters)
#correlate the cores to traits:
#moduleTraitCor = cor(cores, traits, use= "p")
#moduleTraitPvalue = corPvalueStudent(moduleTraitCor, nSamples)
#generate a text matrix of the correlation and pvalue
#textMatrix= paste(signif(moduleTraitCor, 2), "\n(",
#signif(moduleTraitPvalue, 1), ")", sep= "")
#dim(textMatrix)= dim(moduleTraitCor)
#plot a heatmap of the clusters by trait overlaying the corr/pvalue
#par(oma=c(1,0,1,1))
#heatmap.2(moduleTraitCor,
#dendrogram = "none",
#Colv =FALSE,
#scale = c("none"),
#col="heat.colors",
#na.rm=TRUE,
#cellnote = textMatrix,
#notecol="grey30",
#notecex=1,
#trace=c("none"),
#cexRow = 0.8,
#cexCol = 0.8,
#main = "Cluster-Trait Correlation (k=4 + Static [5k])",
#xlab = "Traits",
#ylab = "Clusters")
Make annotated scaled rlog heatmap
rld_df <- as.data.frame(scaledata_rld_top)
rld_df$k3 <- as.data.frame(rld_cutk3)$rld_cutk3
rld_df$k4 <- as.data.frame(rld_cutk4)$rld_cutk4
colors <- c('#e6194B','#3cb44b','#ffe119','#4363d8','#f58231','#911eb4','#42d4f4','#f032e6','#bfef45','#fabed4','#469990','#dcbeff','#9A6324','#fffac8','#800000','#aaffc3','#808000','#ffd8b1','#000075','#a9a9a9','#ffffff','#000000')
#High contrast colors for figures was pulled from https://sashamaps.net/docs/resources/20-colors/
pheatmap(rld_top5k_all,
#rld_df[order(rld_df[,12]),][,1:11],
#gaps_row = c(879,2298,4213),
cluster_cols=T,
cluster_rows=hr_rld,
#clustering_distance_rows = "euclidean",
#clustering_method = "complete",
scale="row",
cutree_rows=4,
cutree_cols=3,
border_color=NA,
show_rownames=F,
main="Top 5k dREG Peak PCA Contributors Hierarchical",
breaks=seq(-2,2,by=0.01),
color=ocean.balance(401),
#color=scico(401, palette = 'berlin'),
#color=colorRampPalette(c("blue", "white", "red"))(41),
annotation_row=rld_df[26:27],
annotation_col=data.frame(row.names=colnames(rld_df[,1:25]), Subtype = data_all),
annotation_colors=list(k3=c("blue", "green", "red"),
k4=c("purple", "blue", "green", "goldenrod1"),
Subtype=c("ATLL"= 'darkgray', "ALK+ALCL"= 'chocolate4', "CTCL"= 'chartreuse3', "ALK-ALCL"= 'cadetblue', "SQGD_TCL"= 'cyan3', "T_LGL"= 'red', "NKT"= 'lightpink', "HS_TCL"= 'black', "PTCL_NOS"= 'darkgoldenrod1', "NKL"= 'blueviolet'))
)

k means 4 looks like it’s picking up some significant groupings between samples. Will move forward with k=4
Redone cluster map with increased cut clusters and ordered by subtype Make annotated scaled rlog heatmap
rld_df2 <- as.data.frame(scaledata_rld_top)
rld_df2$k5 <- as.data.frame(rld_cutk5)$rld_cutk5
rld_df2$k6 <- as.data.frame(rld_cutk6)$rld_cutk6
rld_df2$k7 <- as.data.frame(rld_cutk7)$rld_cutk7
rld_df2$k8 <- as.data.frame(rld_cutk8)$rld_cutk8
rld_df2$k9 <- as.data.frame(rld_cutk9)$rld_cutk9
rld_df2$k10 <- as.data.frame(rld_cutk10)$rld_cutk10
colors <- c('#e6194B','#3cb44b','#ffe119','#4363d8','#f58231','#911eb4','#42d4f4','#f032e6','#bfef45','#fabed4','#469990','#dcbeff','#9A6324','#fffac8','#800000','#aaffc3','#808000','#ffd8b1','#000075','#a9a9a9','#ffffff','#000000')
#High contrast colors for figures was pulled from https://sashamaps.net/docs/resources/20-colors/
rld_df2 <- rld_df2[,c(9,12,14,25,6,5,11,4,10,19,21,23,16,8,24,18,17,22,1:3,20,13,7,15,26:31)]
data <- c("ALK-ALCL","ALK-ALCL","ALK-ALCL","ALK+ALCL","ALK+ALCL","ALK+ALCL","ALK+ALCL","ALK+ALCL","ALK+ALCL","NKT","NKT","NKL","CTCL","CTCL","CTCL","CTCL","CTCL","HS_TCL","ATLL","ATLL","ATLL","T_LGL","SQGD_TCL","PTCL_NOS","PTCL_NOS")
rld2 <- rld_top5k_all[,c(9,12,14,25,6,5,11,4,10,19,21,23,16,8,24,18,17,22,1:3,20,13,7,15)]
pheatmap(rld2,
#rld_df2[1:25],
#gaps_row = c(879,2298,4213),
cluster_cols=F,
cluster_rows=hr_rld,
#clustering_distance_rows = "euclidean",
#clustering_method = "complete",
scale="row",
cutree_rows=6,
cutree_cols=4,
border_color=NA,
show_rownames=F,
main="Top 5k dREG Peak PCA Contributors Hierarchical",
breaks=seq(-2,2,by=0.01),
color=ocean.balance(401),
#color=scico(401, palette = 'berlin'),
#color=colorRampPalette(c("blue", "white", "red"))(41),
annotation_row=rld_df2[26:31],
annotation_col=data.frame(row.names=colnames(rld_df2[,1:25]), Subtype = data),
annotation_colors=list(k5=c("blue", "green", "red", "black", "orange"),
k6=c("purple", "blue", "green", "red", "black", "orange"),
k7=c("yellow", "purple", "blue", "green", "red", "black", "orange"),
k8=c("pink", "yellow", "purple", "blue", "green", "red", "black", "orange"),
k9=c("white", "pink", "yellow", "purple", "blue", "green", "red", "black", "orange"),
k10=c("brown", "white", "pink", "yellow", "purple", "blue", "green", "red", "black", "orange"),
Subtype=c("ATLL"= 'darkgray', "ALK+ALCL"= 'chocolate4', "CTCL"= 'chartreuse3', "ALK-ALCL"= 'cadetblue', "SQGD_TCL"= 'cyan3', "T_LGL"= 'red', "NKT"= 'lightpink', "HS_TCL"= 'black', "PTCL_NOS"= 'darkgoldenrod1', "NKL"= 'blueviolet'))
)

Save centered rlog data with clusters as table with dREG peak info
out <- data.frame(unique(row.names=names(c(rld_cutk4,bot5k_all)),
k2=c(rld_cutk2,bot5k_all),
k3=c(rld_cutk3,bot5k_all),
k4=c(rld_cutk4,bot5k_all)
))
Error in unique.default(row.names = names(c(rld_cutk4, bot5k_all)), k2 = c(rld_cutk2, :
argument "x" is missing, with no default
Integrate nearest/associated gene metrics to output above
Save PDF versions of figures for MS
#####Now for protein-coding genes##### ##Rerun on 10/21/21
Can we get similar sample clustering with dominant transcript genes or do we still have poor separation of the subtypes as seen before?
Load dds and generate other data tables
Do initial dendrograms and determine PCA contributors
Try PCA at different depths
Max separation ~500 top variance genes.. in line with expectations. Poor separation of mesenchymal from luminal as reflected in dendrogram.
Rank genes by PCA contribution and measure variance and cumulative variance
Results: Cutoff rlog variance cumulative variance 500 3.91504 13.3% 1k 3.06535 22.1% 2k 2.209018 35.4% 5k 1.161115 59.8% 10k 0.5271063 79.8% 20k 0.1786067 95.8% all 0 100%
#Completed re-analysis with corrected subtypes and colors on 10/21/21 AF
#####Try this later… #skipped 10/21/21 For test and all sets of cell lines, see which clustering method is best at separating k=3
####Don’t think this is needed here… #skipped 10/21/21 Height Branch Cutting Test
LS0tCnRpdGxlOiAiUFJPIFdlaW5zdG9jazAwMiBCcmFuY2hwb2ludCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQ2x1c3RlciB0ZXN0aW5nIGZyb20gV2VpbnN0b2NrMDAyIGRhdGEgOERFQzIxCgpMaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkoZGVuZGV4dGVuZCkKbGlicmFyeShERVNlcTIpCmxpYnJhcnkoY29sb3JzcGFjZSkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoREVTZXEyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShncGxvdHMpCmxpYnJhcnkocGFscykKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShjb2xvcnNwYWNlKQpsaWJyYXJ5KHNjaWNvKQpgYGAKCkZ1bGwgUFJPc2VxIGRhdGEgc2V0IGFuYWx5c2lzIGZvciBUQ0wgY2VsbCBsaW5lcwoKaHR0cHM6Ly90YWxnYWxpbGkuZ2l0aHViLmlvL2RlbmRleHRlbmQvYXJ0aWNsZXMvQ2x1c3Rlcl9BbmFseXNpcy5odG1sCmBgYHtyfQoKcmxkX2FsbCA8LSBybG9nKGRkc19wcm8sIGJsaW5kPVRSVUUpCiNjb2xuYW1lcyhybGRfYWxsKSA8LSBwYXN0ZTAoc2FtcGxlTmFtZXNfYWxsLCIoIixzdWJUeXBlc19hbGwsIikiKQpzYW1wbGVEaXN0c19hbGwgPC0gZGlzdCh0KGFzc2F5KHJsZF9hbGwpKSkKc2FtcGxlRGlzdE10eF9hbGwgPC0gYXMubWF0cml4KHNhbXBsZURpc3RzX2FsbCkKcm93bmFtZXMoc2FtcGxlRGlzdE10eF9hbGwpIDwtIHBhc3RlMChybGRfYWxsJHNhbXBsZSwiXyIscmxkX2FsbCRzdWJ0eXBlKQpjb2xuYW1lcyhzYW1wbGVEaXN0TXR4X2FsbCkgPC0gTlVMTApoY2x1c3RfYWxsIDwtIGhjbHVzdChzYW1wbGVEaXN0c19hbGwpCgpub3JtX2FsbCA8LSBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHNfcHJvLCBub3JtYWxpemVkPVRSVUUpKSAjdGhpbmsgdGhpcyBpcyByZWR1bmRhbnQgd2l0aCBub3JtY291bnRzX2FsbCBidXQga2VlcGluZyBpdCBmb3Igbm93CmNvbG5hbWVzKG5vcm1fYWxsKSA8LSBkZHNfcHJvJHNhbXBsZQpgYGAKCkRvIGluaXRpYWwgZGVuZHJvZ3JhbXMgYW5kIGRldGVybWluZSBQQ0EgY29udHJpYnV0b3JzCmBgYHtyfQpwbG90UENBKHJsZF9hbGwsIGludGdyb3VwPSJzdWJ0eXBlIikgCnBsb3RQQ0EocmxkX2FsbCwgaW50Z3JvdXA9InNhbXBsZSIpIApwbG90KGhjbHVzdF9hbGwsIGxhYmVscz1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X2FsbCksIG1haW49IlBSTy1zZXEgQWxsIFNhbXBsZSBkUkVHIERlbmRyb2dyYW0iKQpwZGYoImRSRUdfaGNsdXN0LnNhbXBsZS5wZGYiKQpwbG90KGhjbHVzdF9hbGwsIGxhYmVscz1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X2FsbCksIG1haW49IlBSTy1zZXEgQWxsIFNhbXBsZSBkUkVHIERlbmRyb2dyYW0iKQpkZXYub2ZmKCkKYGBgCgpEZXRlcm1pbmUgaWYgeW91IGNhbiBhZGp1c3QgdGhlIG51bWJlciBvZiBQQ0EgY29udHJpYnV0b3JzIHRvIGNsZWFubHkgc2VwYXJhdGUgc3VidHlwZXMKYGBge3J9CiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTAwKSArIGdndGl0bGUoIlRvcCAxMDAiKQogIHBsb3RQQ0EocmxkX2FsbCwgaW50Z3JvdXA9InN1YnR5cGUiLCBudG9wPTIwMCkgKyBnZ3RpdGxlKCJUb3AgMjAwIikKICBwbG90UENBKHJsZF9hbGwsIGludGdyb3VwPSJzdWJ0eXBlIiwgbnRvcD01MDApICsgZ2d0aXRsZSgiVG9wIDUwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTAwMCkgKyBnZ3RpdGxlKCJUb3AgMTAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MjAwMCkgKyBnZ3RpdGxlKCJUb3AgMjAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9NTAwMCkgKyBnZ3RpdGxlKCJUb3AgNTAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTAwMDApICsgZ2d0aXRsZSgiVG9wIDEwMDAwIikKICBwbG90UENBKHJsZF9hbGwsIGludGdyb3VwPSJzdWJ0eXBlIiwgbnRvcD0yMDAwMCkgKyBnZ3RpdGxlKCJUb3AgMjAwMDAiKQogIHBsb3RQQ0EocmxkX2FsbCwgaW50Z3JvdXA9InN1YnR5cGUiLCBudG9wPTUwMDAwKSArIGdndGl0bGUoIlRvcCA1MDAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTIwODg4KSArIGdndGl0bGUoIkFsbCIpCiAgCnBkZigiZFJFR19wY2EuYWxsLnBkZiIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTAwKSArIGdndGl0bGUoIlRvcCAxMDAiKQogIHBsb3RQQ0EocmxkX2FsbCwgaW50Z3JvdXA9InN1YnR5cGUiLCBudG9wPTIwMCkgKyBnZ3RpdGxlKCJUb3AgMjAwIikKICBwbG90UENBKHJsZF9hbGwsIGludGdyb3VwPSJzdWJ0eXBlIiwgbnRvcD01MDApICsgZ2d0aXRsZSgiVG9wIDUwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTAwMCkgKyBnZ3RpdGxlKCJUb3AgMTAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MjAwMCkgKyBnZ3RpdGxlKCJUb3AgMjAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9NTAwMCkgKyBnZ3RpdGxlKCJUb3AgNTAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9MTAwMDApICsgZ2d0aXRsZSgiVG9wIDEwMDAwIikKICBwbG90UENBKHJsZF9hbGwsIGludGdyb3VwPSJzdWJ0eXBlIiwgbnRvcD0yMDAwMCkgKyBnZ3RpdGxlKCJUb3AgMjAwMDAiKQogIHBsb3RQQ0EocmxkX2FsbCwgaW50Z3JvdXA9InN1YnR5cGUiLCBudG9wPTUwMDAwKSArIGdndGl0bGUoIlRvcCA1MDAwMCIpCiAgcGxvdFBDQShybGRfYWxsLCBpbnRncm91cD0ic3VidHlwZSIsIG50b3A9NzcwNjEpICsgZ2d0aXRsZSgiQWxsIikKZGV2Lm9mZigpCiNOb3RlOiBjYW4gbWFrZSB0aGlzIGEgbmljZXIgZ3JpZCB3aXRoIHNoYXJlZCBheGVzPwpgYGAKClJhbmsgZFJFRyBwZWFrcyBieSBQQ0EgY29udHJpYnV0aW9uIGFuZCBtZWFzdXJlIHZhcmlhbmNlIGFuZCBjdW11bGF0aXZlIHZhcmlhbmNlCmBgYHtyfQojTG9hZCBkUkVHIHBlYWsgYW5ub3RhdGlvbnMKZFJFR19hbm5vdDIgPC0gcmVhZC50YWJsZSgiLi4vMDAyX1RDTHNfcDEwMDBfZFJFR3BlYWtfYW5ub3RhdGlvbi50eHQiLCBzZXA9Ilx0IiwgaGVhZGVyPVRSVUUpCiNEZWZpbmUgYW5kIHJhbmsgdG9wIDEwayBQQ0EgY29udHJpYnV0b3JzCnJ2IDwtIHJvd1ZhcnMoYXNzYXkocmxkX2FsbCkpIApzZWxlY3QgPC0gb3JkZXIocnYsIGRlY3JlYXNpbmc9VFJVRSkjW3NlcV9sZW4obWluKDEwMDAwLCBsZW5ndGgocnYpKSldCnBjIDwtIHByY29tcCh0KGFzc2F5KHJsZF9hbGwpW3NlbGVjdCxdKSkKbG9hZGluZ3MgPC0gYXMuZGF0YS5mcmFtZShwYyRyb3RhdGlvbikKYWxvYWQgPC0gYWJzKGxvYWRpbmdzKQpwY1JhbmtfYWxsIDwtIGRhdGEuZnJhbWUoInBlYWtJRCI9cm93bmFtZXMobG9hZGluZ3MpLCAiUENBLnJhbmsiPXNlcS5pbnQobnJvdyhsb2FkaW5ncykpKQojc3dlZXAoYWxvYWQsIDIsIGNvbFN1bXMoYWxvYWQpLCAiLyIpCiMjI2NsZWFuIHVwIHZhcmlhYmxlcwpybShydikKcm0oc2VsZWN0KQpybShwYykKcm0obG9hZGluZ3MpCgojR2VuZXJhdGUgbGlzdCBvZiBkUkVHIHBlYWsgYW5ub3RhdGlvbnMKcGVha0luZm9fYWxsIDwtIG1lcmdlKGRSRUdfYW5ub3QyLCBwY1JhbmtfYWxsLCBieS54PSJwZWFrSUQiLCBieS55PSJwZWFrSUQiKQpwZWFrVmFyX2FsbCA8LSBkYXRhLmZyYW1lKCJwZWFrSUQiPXJvd25hbWVzKGFzc2F5KHJsZF9hbGwpKSkKcGVha1Zhcl9hbGwkcmxvZy52YXJpYW5jZSA8LSByb3dWYXJzKGFzLm1hdHJpeChhc3NheShybGRfYWxsKSkpCnBlYWtWYXJfYWxsIDwtIG1lcmdlKHBlYWtJbmZvX2FsbCwgcGVha1Zhcl9hbGwsIGJ5Lng9InBlYWtJRCIsIGJ5Lnk9InBlYWtJRCIpCnBkZigidmFyaWFuY2UucGRmIikKZ2dwbG90KHBlYWtWYXJfYWxsLCBhZXMoeD1QQ0EucmFuaywgeT1ybG9nLnZhcmlhbmNlKSkgKyBnZW9tX2xpbmUoKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD01MDAwLCBsaW5ldHlwZT0iZG90dGVkIikKZGV2Lm9mZigpCmdncGxvdChwZWFrVmFyX2FsbCwgYWVzKHg9UENBLnJhbmssIHk9cmxvZy52YXJpYW5jZSkpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9NTAwMCwgbGluZXR5cGU9ImRvdHRlZCIpCgojYWRkIHBsb3Qgb2YgZnJhY3Rpb24gb2YgZXhwbGFpbmVkIHZhcmlhbmNlLi4gcnVubmluZyBzdW0gLyB0b3RhbCB2cyByYW5rCnBlYWtWYXJfYWxsIDwtIHBlYWtWYXJfYWxsW29yZGVyKHBlYWtWYXJfYWxsJFBDQS5yYW5rKSxdCnBlYWtWYXJfYWxsJGN1bXVsYXRpdmUuVmFyaWFuY2UgPC0gY3Vtc3VtKHBlYWtWYXJfYWxsJHJsb2cudmFyaWFuY2UpL3N1bShwZWFrVmFyX2FsbCRybG9nLnZhcmlhbmNlKQpwZGYoImN1bXVsYXRpdmVfdmFyaWFuY2UucGRmIikKZ2dwbG90KHBlYWtWYXJfYWxsLCBhZXMoeD1QQ0EucmFuaywgeT1jdW11bGF0aXZlLlZhcmlhbmNlKSkgKyBnZW9tX2xpbmUoKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD01MDAwLCBsaW5ldHlwZT0iZG90dGVkIikKZGV2Lm9mZigpCmdncGxvdChwZWFrVmFyX2FsbCwgYWVzKHg9UENBLnJhbmssIHk9Y3VtdWxhdGl2ZS5WYXJpYW5jZSkpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9NTAwMCwgbGluZXR5cGU9ImRvdHRlZCIpCmBgYAoKRmlsdGVyIHJsZCBvYmplY3RzIGJ5IHNhbXBsZXMuLi4gc2VwYXJhdGUgdHJhaW5pbmcgc2V0IGZyb20gInRlc3QiIHNldCAoU1VNMTQ5IGFuZCBTVU0xNTkpCmBgYHtyfQojU2VwYXJhdGUgdHJhaW5pbmcgYW5kIHRlc3Qgc2V0CmZpbHQgPC0gd2hpY2goIWNvbG5hbWVzKHJsZF9hbGwpICVpbiUgYygiSFVUNzgiLCJIVVQxMDIiLCAiU3U5VDAxIiwgIkZFUEQiLCAiTU9UTjEiLCAiT0NJTFkxMiIsICJTTVoxIikpCnJsZF90cmFpbiA8LSBybGRfYWxsWyxmaWx0XQoKZmlsdCA8LSB3aGljaChjb2xuYW1lcyhybGRfYWxsKSAlaW4lIGMoIkhVVDc4IiwiSFVUMTAyIiwgIlN1OVQwMSIsICJGRVBEIiwgIk1PVE4xIiwgIk9DSUxZMTIiLCAiU01aMSIpKQpybGRfdGVzdCA8LSBybGRfYWxsWyxmaWx0XQoKZmlsdCA8LSB3aGljaCghY29sbmFtZXMobm9ybV9hbGwpICVpbiUgYygiSFVUNzgiLCJIVVQxMDIiLCAiU3U5VDAxIiwgIkZFUEQiLCAiTU9UTjEiLCAiT0NJTFkxMiIsICJTTVoxIikpCm5vcm1fdHJhaW4gPC0gbm9ybV9hbGxbLGZpbHRdCgpmaWx0IDwtIHdoaWNoKGNvbG5hbWVzKG5vcm1fYWxsKSAlaW4lIGMoIkhVVDc4IiwiSFVUMTAyIiwgIlN1OVQwMSIsICJGRVBEIiwgIk1PVE4xIiwgIk9DSUxZMTIiLCAiU01aMSIpKQpub3JtX3Rlc3QgPC0gbm9ybV9hbGxbLGZpbHRdCmBgYAoKRGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgUENBIGNvbnRyaWJ1dG9ycyBuZWNlc3NhcnkgdG8gY2xlYW5seSBzZXBhcmF0ZSBzdWJ0eXBlcwoKU2FtcGxlIGdyb3VwaW5nIGxvb2tzIHByZXR0eSBnb29kIGJldHdlZW4gNWsgYW5kIDEwayB0b3AgY29udHJpYnV0b3JzLiBXaWxsIGxvb2sgYXQgdGhlc2UgY3V0b2ZmcyBpbiBtb3JlIGRldGFpbC4KClJhbmsgZFJFRyBwZWFrcyBieSBQQ0EgY29udHJpYnV0aW9uIGFuZCBtZWFzdXJlIHZhcmlhbmNlIGFuZCBjdW11bGF0aXZlIHZhcmlhbmNlCmBgYHtyfQojRGVmaW5lIGFuZCByYW5rIHRvcCAxMGsgUENBIGNvbnRyaWJ1dG9ycwpydiA8LSByb3dWYXJzKGFzc2F5KHJsZF90cmFpbikpIApzZWxlY3QgPC0gb3JkZXIocnYsIGRlY3JlYXNpbmc9VFJVRSkjW3NlcV9sZW4obWluKDEwMDAwLCBsZW5ndGgocnYpKSldCnBjIDwtIHByY29tcCh0KGFzc2F5KHJsZF90cmFpbilbc2VsZWN0LF0pKQpsb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjJHJvdGF0aW9uKQphbG9hZCA8LSBhYnMobG9hZGluZ3MpCnBjUmFuazIgPC0gZGF0YS5mcmFtZSgicGVha0lEIj1yb3duYW1lcyhsb2FkaW5ncyksICJQQ0EucmFuayI9c2VxLmludChucm93KGxvYWRpbmdzKSkpCiNzd2VlcChhbG9hZCwgMiwgY29sU3VtcyhhbG9hZCksICIvIikKIyMjY2xlYW4gdXAgdmFyaWFibGVzCnJtKHJ2KQpybShzZWxlY3QpCnJtKHBjKQpybShsb2FkaW5ncykKCiNHZW5lcmF0ZSBsaXN0IG9mIGRSRUcgcGVhayBhbm5vdGF0aW9ucwpwZWFrSW5mbzIgPC0gbWVyZ2UoZFJFR19hbm5vdDIsIHBjUmFuazIsIGJ5Lng9InBlYWtJRCIsIGJ5Lnk9InBlYWtJRCIpCnBlYWtWYXIyIDwtIGRhdGEuZnJhbWUoInBlYWtJRCI9cm93bmFtZXMoYXNzYXkocmxkX3RyYWluKSkpCnBlYWtWYXIyJHJsb2cudmFyaWFuY2UgPC0gcm93VmFycyhhcy5tYXRyaXgoYXNzYXkocmxkX3RyYWluKSkpCnBlYWtWYXIyIDwtIG1lcmdlKHBlYWtJbmZvMiwgcGVha1ZhcjIsIGJ5Lng9InBlYWtJRCIsIGJ5Lnk9InBlYWtJRCIpCmdncGxvdChwZWFrVmFyMiwgYWVzKHg9UENBLnJhbmssIHk9cmxvZy52YXJpYW5jZSkpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9Yyg1MDAsMTAwMCwyMDAwLDUwMDAsMTAwMDApLCBsaW5ldHlwZT0iZG90dGVkIikKCiNhZGQgcGxvdCBvZiBmcmFjdGlvbiBvZiBleHBsYWluZWQgdmFyaWFuY2UuLiBydW5uaW5nIHN1bSAvIHRvdGFsIHZzIHJhbmsKcGVha1ZhcjIgPC0gcGVha1ZhcjJbb3JkZXIocGVha1ZhcjIkUENBLnJhbmspLF0KcGVha1ZhcjIkY3VtdWxhdGl2ZS5WYXJpYW5jZSA8LSBjdW1zdW0ocGVha1ZhcjIkcmxvZy52YXJpYW5jZSkvc3VtKHBlYWtWYXIyJHJsb2cudmFyaWFuY2UpCmdncGxvdChwZWFrVmFyMiwgYWVzKHg9UENBLnJhbmssIHk9Y3VtdWxhdGl2ZS5WYXJpYW5jZSkpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9Yyg1MDAsMTAwMCwyMDAwLDUwMDAsMTAwMDApLCBsaW5ldHlwZT0iZG90dGVkIikKYGBgCgo1ayBzZWVtcyByZWFzb25hYmxlCgpGaWx0ZXIgZm9yIHRvcCA1ayBQQ0EgY29udHJpYnV0b3JzCmBgYHtyfQojZmlsdGVyIG5vcm1hbGl6ZWQgY291bnRzIGZvciB0b3AgNWsgUENBIGNvbnRyaWJ1dG9ycwp0b3A1ayA8LSBmaWx0ZXIocGVha1ZhcjIsIFBDQS5yYW5rPD01MDAwKSRwZWFrSUQKbm9ybV90b3A1ayA8LSBub3JtX3RyYWluW3doaWNoKChyb3duYW1lcyhub3JtX3RyYWluKSAlaW4lIHRvcDVrKT09VFJVRSksXQpybGRfdG9wNWtfdHJhaW4gPC0gc3Vic2V0KGFzc2F5KHJsZF90cmFpbiksIHJvd25hbWVzKGFzc2F5KHJsZF90cmFpbikpICVpbiUgdG9wNWspCnJsZF90b3A1a190ZXN0IDwtIHN1YnNldChhc3NheShybGRfdGVzdCksIHJvd25hbWVzKGFzc2F5KHJsZF90ZXN0KSkgJWluJSB0b3A1aykKcmxkX3RvcDVrX2FsbCA8LSBzdWJzZXQoYXNzYXkocmxkX2FsbCksIHJvd25hbWVzKGFzc2F5KHJsZF90ZXN0KSkgJWluJSB0b3A1aykKYGBgCgpDYWxjdWxhdGUgc2FtcGxlIGRpc3RhbmNlcyB3aXRoIG5ldyB0b3A1ayB0cmFpbmluZyBhbmQgbWF0Y2hlZCB0ZXN0IHNldHMsIHRoZW4gY2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBicmFuY2hwb2ludHMgb2YgdGhlIHR3bwpgYGB7cn0KZF90cmFpbiA8LSBybGRfdG9wNWtfdHJhaW4gJT4lIGRpc3QgJT4lIGhjbHVzdCAlPiUgYXMuZGVuZHJvZ3JhbQpkX3Rlc3QgPC0gcmxkX3RvcDVrX3Rlc3QgJT4lIGRpc3QgJT4lIGhjbHVzdCAlPiUgYXMuZGVuZHJvZ3JhbQpkX2FsbCA8LSBybGRfdG9wNWtfYWxsICU+JSBkaXN0ICU+JSBoY2x1c3QgJT4lIGFzLmRlbmRyb2dyYW0KCiNjb21wYXJlIGNsdXN0ZXJzIGV4Y2x1ZGluZyB1bmNsdXN0ZXJlZCB0byB1bmNsdXN0ZXJlZCBhbG9uZQpkX3RyYWluX3Rlc3QgPC0gZGVuZGxpc3QodHJhaW4gPSBkX3RyYWluLCB0ZXN0ID0gZF90ZXN0KQpkX3RyYWluX3Rlc3QgJT4lIGNvci5kZW5kbGlzdApkX3RyYWluX3Rlc3QgJT4lIGNvci5kZW5kbGlzdChtZXRob2RfY29lZiA9ICJzcGVhcm1hbiIpCkJrX3Bsb3QoZF90cmFpbiwgZF90ZXN0LCBrID0gMjozMCwgeGxpbSA9IGMoMiwzMCksIG1haW4gPSAiVENMIFRyYWluIFNldCB2cyBub24tc2lnbmlmaWNhbnQgY2x1c3RlcnMgQmsgcGxvdCIpCgojY29tcGFyZSBjbHVzdGVycyBleGNsdWRpbmcgdW5jbHVzdGVyZWQgdG8gY2x1c3RlcnMgdXNpbmcgYWxsIHNhbXBsZXMKZF90cmFpbl9hbGwgPC0gZGVuZGxpc3QodHJhaW4gPSBkX3RyYWluLCBhbGwgPSBkX2FsbCkKZF90cmFpbl9hbGwgJT4lIGNvci5kZW5kbGlzdApkX3RyYWluX2FsbCAlPiUgY29yLmRlbmRsaXN0KG1ldGhvZF9jb2VmID0gInNwZWFybWFuIikKQmtfcGxvdChkX3RyYWluLCBkX2FsbCwgayA9IDI6MzAsIHhsaW0gPSBjKDIsMzApLCBtYWluID0gIlRDTCBUcmFpbiBTZXQgdnMgQWxsIFNhbXBsZXMgQmsgcGxvdCIpCgojY29tcGFyZSBjbHVzdGVycyBhbGwgc2FtcGxlIGNsdXN0ZXJpbmcgdG8gdW5jbHVzdGVyZWQgYWxvbmUKZF9hbGxfdGVzdCA8LSBkZW5kbGlzdChhbGwgPSBkX2FsbCwgdGVzdCA9IGRfdGVzdCkKZF9hbGxfdGVzdCAlPiUgY29yLmRlbmRsaXN0CmRfYWxsX3Rlc3QgJT4lIGNvci5kZW5kbGlzdChtZXRob2RfY29lZiA9ICJzcGVhcm1hbiIpCkJrX3Bsb3QoZF9hbGwsIGRfdGVzdCwgayA9IDI6MzAsIHhsaW0gPSBjKDIsMzApLCBtYWluID0gIkFsbCBTYW1wbGVzIHZzLiBub24tc2lnbmlmaWNhbnQgY2x1c3RlcnMgQmsgcGxvdCIpCmBgYAozayBjbHVzdGVycz8KCk5vdyBzb21lIGZ1biB3aXRoIFRhbmdsZWdyYW1zLi4uCmBgYHtyfQpwcmVfdGFuZ19kX3RyYWluX3Rlc3QgPC0gZF90cmFpbl90ZXN0ICU+JSBsYWRkZXJpemUgJT4lIHVudGFuZ2xlICU+JSBzZXQoImJyYW5jaGVzX2tfY29sb3IiLCBrID0gMykKdHJhaW5fYnJhbmNoZXNfY29sb3JzIDwtIGdldF9sZWF2ZXNfYnJhbmNoZXNfY29sKHByZV90YW5nX2RfdHJhaW5fdGVzdCR0cmFpbikKcHJlX3RhbmdfZF90cmFpbl90ZXN0ICU+JSB0YW5nbGVncmFtKGZhc3QgPSBULCBjb2xvcl9saW5lcyA9IHRyYWluX2JyYW5jaGVzX2NvbG9ycykKCnByZV90YW5nX2RfdHJhaW5fYWxsIDwtIGRfdHJhaW5fYWxsICU+JSBsYWRkZXJpemUgJT4lICB1bnRhbmdsZSAlPiUgc2V0KCJicmFuY2hlc19rX2NvbG9yIiwgayA9IDMpCnRyYWluX2JyYW5jaGVzX2NvbG9ycyA8LSBnZXRfbGVhdmVzX2JyYW5jaGVzX2NvbChwcmVfdGFuZ19kX3RyYWluX2FsbCR0cmFpbikKcHJlX3RhbmdfZF90cmFpbl9hbGwgJT4lIHRhbmdsZWdyYW0oZmFzdCA9IFQsIGNvbG9yX2xpbmVzID0gdHJhaW5fYnJhbmNoZXNfY29sb3JzKQoKcHJlX3RhbmdfZF9hbGxfdGVzdCA8LSBkX2FsbF90ZXN0ICU+JSBsYWRkZXJpemUgJT4lICB1bnRhbmdsZSAlPiUgc2V0KCJicmFuY2hlc19rX2NvbG9yIiwgayA9IDMpCnRyYWluX2JyYW5jaGVzX2NvbG9ycyA8LSBnZXRfbGVhdmVzX2JyYW5jaGVzX2NvbChwcmVfdGFuZ19kX2FsbF90ZXN0JGFsbCkKcHJlX3RhbmdfZF9hbGxfdGVzdCAlPiUgdGFuZ2xlZ3JhbShmYXN0ID0gVCwgY29sb3JfbGluZXMgPSB0cmFpbl9icmFuY2hlc19jb2xvcnMpCmBgYApUaGUgdGhyZWUgZGlmZmVyZW50IHNldHMgbGVhZCB0byBkcmFzdGljYWxseSBkaWZmZXJlbnQgY2x1c3RlciBkZXNpZ25hdGlvbnMuIFdpbGwgYXR0ZW1wdCB0byBsb29rIGF0IG92ZXJsYXAgYmV0d2VlbiBjbHVzdGVyIHNldHMgdGhvdWdoIGl0IGlzIHNvbWV3aGF0IGFyYml0cmFyeSB3aGljaCBzYW1wbGVzIGVuZCB1cCBiZWluZyB0aGUgaG9sZC1vdXRzLgoKT25seSBoaWdobGlnaHQgZ2VuZXMgY2x1c3RlcmVkIGluIGNvbW1vbiAKYGBge3J9CiNkX3RyYWluX3Rlc3RfY29tbW9uIDwtIGRfdHJhaW5fdGVzdCAlPiUgcHJ1bmVfY29tbW9uX3N1YnRyZWVzLmRlbmRsaXN0CiNkX3RyYWluX3Rlc3RfY29tbW9uICU+JSB1bnRhbmdsZSAlPiUgIHRhbmdsZWdyYW0oY29tbW9uX3N1YnRyZWVzX2NvbG9yX2JyYW5jaGVzID0gVFJVRSkKCiNkX3RyYWluX2FsbF9jb21tb24gPC0gZF90cmFpbl9hbGwgJT4lIHBydW5lX2NvbW1vbl9zdWJ0cmVlcy5kZW5kbGlzdAojZF90cmFpbl9hbGxfY29tbW9uICU+JSB1bnRhbmdsZSAlPiUgIHRhbmdsZWdyYW0oY29tbW9uX3N1YnRyZWVzX2NvbG9yX2JyYW5jaGVzID0gVFJVRSkKCiNkX2FsbF90ZXN0X2NvbW1vbiA8LSBkX2FsbF90ZXN0ICU+JSBwcnVuZV9jb21tb25fc3VidHJlZXMuZGVuZGxpc3QKI2RfYWxsX3Rlc3RfY29tbW9uICU+JSB1bnRhbmdsZSAlPiUgIHRhbmdsZWdyYW0oY29tbW9uX3N1YnRyZWVzX2NvbG9yX2JyYW5jaGVzID0gVFJVRSkKYGBgCgpRdWl0ZSBhIGZldyBzaGFyZWQgbGVhdmVzIGJldHdlZW4gdGhlIHRyYWluaW5nIHNldCBhbmQgYWxsLiBMZXQncyBzZWUgd2hhdCB0aGV5IGFyZS4uLiAKYGBge3J9CiNkX3RyYWluX3Rlc3QgJT4lIG5sZWF2ZXMKI2RfdHJhaW5fdGVzdF9jb21tb24gJT4lIG5sZWF2ZXMKCiNkX3RyYWluX2FsbCAlPiUgbmxlYXZlcwojZF90cmFpbl9hbGxfY29tbW9uICU+JSBubGVhdmVzCgojZF9hbGxfdGVzdCAlPiUgbmxlYXZlcwojZF9hbGxfdGVzdF9jb21tb24gJT4lIG5sZWF2ZXMKYGBgCm4gbGVhdmVzIHByZXNlcnZlZCBiZXR3ZWVuIHRoZSBzdWJzZXQgYW5kIGFsbCBzYW1wbGVzLgoKTmV4dCBpcyB0byBmaWd1cmUgYSB3YXkgdG8gZGVmaW5lIGV4cHJlc3Npb24vYWN0aXZpdHkgZ3JvdXBzOgotIGstbWVhbnMgYXMgYmVmb3JlIC0Kb3IKLSBkeW5hbWljIGJyYW5jaCBjdXR0aW5nIC0KCnVzaW5nIHRvcCA1ayBQQ0EgY29udHJpYnV0b3JzIChhcyBkZXRlcm1pbmVkIGEgcmVhc29uYWJsZSBjdXRvZmYgaW4gdGhlIHZhcmlhbmNlIHBsb3RzKQpgYGB7cn0KI2ZpbHRlciBub3JtYWxpemVkIGNvdW50cyBmb3IgdG9wIDVrIFBDQSBjb250cmlidXRvcnMKdG9wNWtfYWxsIDwtIGZpbHRlcihwZWFrVmFyX2FsbCwgUENBLnJhbms8PTUwMDApJHBlYWtJRApib3Q1a19hbGwgPC0gZmlsdGVyKHBlYWtWYXJfYWxsLCBQQ0EucmFuaz4xMTU4ODgpJHBlYWtJRApub3JtX3RvcDVrX2FsbCA8LSBub3JtX2FsbFt3aGljaCgocm93bmFtZXMobm9ybV9hbGwpICVpbiUgdG9wNWtfYWxsKT09VFJVRSksXQoKcmxkX3RvcDVrX2FsbCA8LSBzdWJzZXQoYXNzYXkocmxkX2FsbCksIHJvd25hbWVzKGFzc2F5KHJsZF9hbGwpKSAlaW4lIHRvcDVrX2FsbCkKY29sbmFtZXMobm9ybV90b3A1a19hbGwpIDwtIGNvbG5hbWVzKHJsZF90b3A1a19hbGwpCnJsZF9ib3Q1a19hbGwgPC0gc3Vic2V0KGFzc2F5KHJsZF9hbGwpLCByb3duYW1lcyhhc3NheShybGRfYWxsKSkgJWluJSBib3Q1a19hbGwpCihyb3cubmFtZXMocmxkX3RvcDVrX2FsbCkgJWluJSByb3cubmFtZXMocmxkX2JvdDVrX2FsbCkpPT1GQUxTRSAjY2hlY2sgZFJFR3MgcHVsbGVkIGludG8gdG9wIGFuZCBib3R0b20gZG8gbm90IG1hdGNoLSBzaG91bGQgcnVuIFQgZm9yIGFsbAoKI3NjYWxlKCkgZnVuY3Rpb24gY2VudGVycyB2YWx1ZXMgKy8tIHRoZSBtZWFuIG9mIGVhY2ggY29sdW1uIGZvciBub3JtYWxpemVkIGNvdW50cyBvciBybG9nIG5vcm1hbGl6ZWQgY291bnRzCnNjYWxlZGF0YV9jb3VudF90b3AgPC0gdChzY2FsZSh0KG5vcm1fdG9wNWtfYWxsKSkpICMgQ2VudGVycyBhbmQgc2NhbGVzIGRhdGEuCnNjYWxlZGF0YV9jb3VudF90b3AgPC0gc2NhbGVkYXRhX2NvdW50X3RvcFtjb21wbGV0ZS5jYXNlcyhzY2FsZWRhdGFfY291bnRfdG9wKSxdICMgUmVtb3ZlcyByb3dzIHdpdGggbnVsbHMKc2NhbGVkYXRhX3JsZF90b3AgPC0gdChzY2FsZSh0KHJsZF90b3A1a19hbGwpKSkgIyBDZW50ZXJzIGFuZCBzY2FsZXMgZGF0YS4Kc2NhbGVkYXRhX3JsZF90b3AgPC0gc2NhbGVkYXRhX3JsZF90b3BbY29tcGxldGUuY2FzZXMoc2NhbGVkYXRhX3JsZF90b3ApLF0gIyBSZW1vdmVzIHJvd3Mgd2l0aCBudWxscwoKc2NhbGVkYXRhX3JsZF9hbGwgPC0gdChzY2FsZSh0KGFzc2F5KHJsZF9hbGwpKSkpCnNjYWxlZGF0YV9ybGRfYWxsIDwtIHNjYWxlZGF0YV9ybGRfYWxsW2NvbXBsZXRlLmNhc2VzKHNjYWxlZGF0YV9ybGRfYWxsKSxdCgpzY2FsZWRhdGFfYm90IDwtIHQoc2NhbGUodChybGRfYm90NWtfYWxsKSkpCnNjYWxlZGF0YV9ib3QgPC0gc2NhbGVkYXRhX2JvdFtjb21wbGV0ZS5jYXNlcyhzY2FsZWRhdGFfYm90KSxdIAoKI2Fsc28gdHJ5IHdpdGggcmVsYXRpdmUgYWN0aXZpdHkgc2NhbGluZwpzY2FsZWRhdGFfcmVsX3RvcCA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcz1yb3duYW1lcyhub3JtX3RvcDVrX2FsbCkpCnNjYWxlZGF0YV9yZWxfdG9wJG1heC5kUkVHLmNvdW50cyA8LSBhcHBseShub3JtX3RvcDVrX2FsbFsxOm5jb2wobm9ybV90b3A1a19hbGwpXSwgMSwgbWF4LCBuYS5ybT1UUlVFKQppPTEKd2hpbGUgKGk8PW5jb2wobm9ybV90b3A1a19hbGwpKXsKICBzY2FsZWRhdGFfcmVsX3RvcFtwYXN0ZTAobmFtZXMobm9ybV90b3A1a19hbGxbaV0pKV0gPC0gbm9ybV90b3A1a19hbGxbLGldL3NjYWxlZGF0YV9yZWxfdG9wJG1heC5kUkVHLmNvdW50cwogIGk9aSsxCn0KCiNHZW5lcmF0ZSBjb2x1bW4gYW5kIHJvdyBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBmb3IgZWFjaCBub3JtYWxpemF0aW9uIG1ldGhvZCAoYWxsIHNwZWFybWFuIGZvciBub3cpCmhyX2NvdW50IDwtIGhjbHVzdChhcy5kaXN0KDEtY29yKHQoc2NhbGVkYXRhX2NvdW50X3RvcCksIG1ldGhvZD0ic3BlYXJtYW4iKSksIG1ldGhvZD0iY29tcGxldGUiKSAjIENsdXN0ZXIgcm93cyBieSBQZWFyc29uIGNvcnJlbGF0aW9uLgpoY19jb3VudCA8LSBoY2x1c3QoYXMuZGlzdCgxLWNvcihzY2FsZWRhdGFfY291bnRfdG9wLCBtZXRob2Q9InNwZWFybWFuIikpLCBtZXRob2Q9ImNvbXBsZXRlIikgIyBDbHVzdGVycyBjb2x1bW5zIGJ5IFNwZWFybWFuIGNvcnJlbGF0aW9uLgoKaHJfcmxkIDwtIGhjbHVzdChhcy5kaXN0KDEtY29yKHQoc2NhbGVkYXRhX2NvdW50X3RvcCksIG1ldGhvZD0ic3BlYXJtYW4iKSksIG1ldGhvZD0iY29tcGxldGUiKSAjIENsdXN0ZXIgcm93cyBieSBQZWFyc29uIGNvcnJlbGF0aW9uLgpoY19ybGQgPC0gaGNsdXN0KGFzLmRpc3QoMS1jb3Ioc2NhbGVkYXRhX3JsZF90b3AsIG1ldGhvZD0ic3BlYXJtYW4iKSksIG1ldGhvZD0iY29tcGxldGUiKSAjIENsdXN0ZXJzIGNvbHVtbnMgYnkgU3BlYXJtYW4gY29ycmVsYXRpb24uCgpocl9ib3QgPC0gaGNsdXN0KGFzLmRpc3QoMS1jb3IodChzY2FsZWRhdGFfYm90KSwgbWV0aG9kPSJzcGVhcm1hbiIpKSwgbWV0aG9kPSJjb21wbGV0ZSIpCgpocl9yZWwgPC0gaGNsdXN0KGFzLmRpc3QoMS1jb3IodChzY2FsZWRhdGFfcmVsX3RvcFssYygyOjI2KV0pLCBtZXRob2Q9InNwZWFybWFuIikpLCBtZXRob2Q9ImNvbXBsZXRlIikgIyBDbHVzdGVyIHJvd3MgYnkgUGVhcnNvbiBjb3JyZWxhdGlvbi4KaGNfcmVsIDwtIGhjbHVzdChhcy5kaXN0KDEtY29yKHNjYWxlZGF0YV9yZWxfdG9wWyxjKDI6MjYpXSwgbWV0aG9kPSJzcGVhcm1hbiIpKSwgbWV0aG9kPSJjb21wbGV0ZSIpICMgQ2x1c3RlcnMgY29sdW1ucyBieSBTcGVhcm1hbiBjb3JyZWxhdGlvbi4KYGBgCgpEeW5hbWljIEJyYW5jaCBDdXR0aW5nIFRlc3QgKDMtNSkKYGBge3J9CmxpYnJhcnkoZGVuZGV4dGVuZCkKCmNudF9jdXRrMyA8LSBjdXRyZWUoaHJfY291bnQsaz0zKSAjY3V0IGF0IHNwZWNpZmljIGhlaWdodCBoIG9yIGN1dCBmb3IgYSBzcGVjaWZpYyBudW1iZXIgb2YgY2x1c3RlcnMgawpjbnRfY3V0azQgPC0gY3V0cmVlKGhyX2NvdW50LGs9NCkKY250X2N1dGs1IDwtIGN1dHJlZShocl9jb3VudCxrPTUpCgpybGRfY3V0azIgPC0gY3V0cmVlKGhyX3JsZCxrPTIpCnJsZF9jdXRrMyA8LSBjdXRyZWUoaHJfcmxkLGs9MykKcmxkX2N1dGs0IDwtIGN1dHJlZShocl9ybGQsaz00KQpybGRfY3V0azUgPC0gY3V0cmVlKGhyX3JsZCxrPTUpCnJsZF9jdXRrNiA8LSBjdXRyZWUoaHJfcmxkLGs9NikKcmxkX2N1dGs3IDwtIGN1dHJlZShocl9ybGQsaz03KQpybGRfY3V0azggPC0gY3V0cmVlKGhyX3JsZCxrPTgpCnJsZF9jdXRrOSA8LSBjdXRyZWUoaHJfcmxkLGs9OSkKcmxkX2N1dGsxMCA8LSBjdXRyZWUoaHJfcmxkLGs9MTApCgpybGRfYm90NWtfYWxsIDwtIGFzLmludGVnZXIocmVwKDAsIDUwMDApKQpuYW1lcyhybGRfYm90NWtfYWxsKSA8LSBib3Q1a19hbGwKCnJlbF9jdXRrMyA8LSBjdXRyZWUoaHJfcmVsLGs9MykKcmVsX2N1dGs0IDwtIGN1dHJlZShocl9yZWwsaz00KQpyZWxfY3V0azUgPC0gY3V0cmVlKGhyX3JlbCxrPTUpCgojcGxvdCB0aGUgdHJlZQpUcmVlUl9jbnQgPSBhcy5kZW5kcm9ncmFtKGhyX2NvdW50LCBtZXRob2Q9ImF2ZXJhZ2UiKQpUcmVlUl9ybGQgPSBhcy5kZW5kcm9ncmFtKGhyX3JsZCwgbWV0aG9kPSJhdmVyYWdlIikKVHJlZVJfcmVsID0gYXMuZGVuZHJvZ3JhbShocl9yZWwsIG1ldGhvZD0iYXZlcmFnZSIpCgojZGVmaW5lIGFubm90YXRpb24gYmFycwp0aGVfYmFyc19rMyA8LSBjYmluZChjbnRfY3V0azMsIHJsZF9jdXRrMywgcmVsX2N1dGszKQp0aGVfYmFyc19rNCA8LSBjYmluZChjbnRfY3V0azQsIHJsZF9jdXRrNCwgcmVsX2N1dGs0KQp0aGVfYmFyc19rNSA8LSBjYmluZChjbnRfY3V0azUsIHJsZF9jdXRrNSwgcmVsX2N1dGs1KQoKdGhlX2JhcnNfY250IDwtIGNiaW5kKGNudF9jdXRrMywgY250X2N1dGs0LCBjbnRfY3V0azUpCnRoZV9iYXJzX3JsZCA8LSBjYmluZChybGRfY3V0azMsIHJsZF9jdXRrNCwgcmxkX2N1dGs1KQp0aGVfYmFyc19yZWwgPC0gY2JpbmQocmVsX2N1dGszLCByZWxfY3V0azQsIHJlbF9jdXRrNSkKYGBgCgpDb21wYXJlIGNsdXN0ZXJzCmBgYHtyfQpwbG90KFRyZWVSX3JsZCwKICAgICBsZWFmbGFiID0gIm5vbmUiLAogICAgIG1haW4gPSAiZFJFRyBQZWFrIENsdXN0ZXJpbmcgKHJsb2cpIGs9MyIsCiAgICAgeWxhYiA9ICJIZWlnaHQiKQoKI3RoaXMgbWFrZXMgdGhlIGJhcgpjb2xvcmVkX2JhcnModGhlX2JhcnNfazMsIFRyZWVSX3JsZCwgc29ydF9ieV9sYWJlbHNfb3JkZXIgPSBULCB5X3NoaWZ0PS0wLjEsIHJvd0xhYmVscyA9IGMoIkJ5IENvdW50cyIsIkJ5IHJMb2ciLCJCeSBSZWxhdGl2ZSBBY3Rpdml0eSIpLGNleC5yb3dMYWJlbHM9MC43KQoKcGxvdChUcmVlUl9ybGQsCiAgICAgbGVhZmxhYiA9ICJub25lIiwKICAgICBtYWluID0gImRSRUcgUGVhayBDbHVzdGVyaW5nIChybG9nKSBrPTQiLAogICAgIHlsYWIgPSAiSGVpZ2h0IikKCiN0aGlzIG1ha2VzIHRoZSBiYXIKY29sb3JlZF9iYXJzKHRoZV9iYXJzX2s0LCBUcmVlUl9ybGQsIHNvcnRfYnlfbGFiZWxzX29yZGVyID0gVCwgeV9zaGlmdD0tMC4xLCByb3dMYWJlbHMgPSBjKCJCeSBDb3VudHMiLCJCeSByTG9nIiwiQnkgUmVsYXRpdmUgQWN0aXZpdHkiKSxjZXgucm93TGFiZWxzPTAuNykKCnBsb3QoVHJlZVJfcmxkLAogICAgIGxlYWZsYWIgPSAibm9uZSIsCiAgICAgbWFpbiA9ICJkUkVHIFBlYWsgQ2x1c3RlcmluZyAocmxvZykgaz01IiwKICAgICB5bGFiID0gIkhlaWdodCIpCgojdGhpcyBtYWtlcyB0aGUgYmFyCmNvbG9yZWRfYmFycyh0aGVfYmFyc19rNSwgVHJlZVJfcmxkLCBzb3J0X2J5X2xhYmVsc19vcmRlciA9IFQsIHlfc2hpZnQ9LTAuMSwgcm93TGFiZWxzID0gYygiQnkgQ291bnRzIiwiQnkgckxvZyIsIkJ5IFJlbGF0aXZlIEFjdGl2aXR5IiksY2V4LnJvd0xhYmVscz0wLjcpCmBgYApDbHVzdGVyaW5nIGlzIGV4YWN0bHkgdGhlIHNhbWUgcmVnYXJkbGVzcyBvZiBtZXRob2Qgbm93ISEgVGhpcyBpcyBncmVhdCEKCkNvbXBhcmUgY2x1c3RlcnMKYGBge3J9CnBsb3QoVHJlZVJfY250LAogICAgIGxlYWZsYWIgPSAibm9uZSIsCiAgICAgbWFpbiA9ICJkUkVHIFBlYWsgQ2x1c3RlcmluZyAoY291bnRzKSIsCiAgICAgeWxhYiA9ICJIZWlnaHQiKQoKI3RoaXMgbWFrZXMgdGhlIGJhcgpjb2xvcmVkX2JhcnModGhlX2JhcnNfY250LCBUcmVlUl9jbnQsIHNvcnRfYnlfbGFiZWxzX29yZGVyID0gVCwgeV9zaGlmdD0tMC4xLCByb3dMYWJlbHMgPSBjKCJrPTMiLCJrPTQiLCJrPTUiKSxjZXgucm93TGFiZWxzPTAuNykKCnBsb3QoVHJlZVJfcmxkLAogICAgIGxlYWZsYWIgPSAibm9uZSIsCiAgICAgbWFpbiA9ICJkUkVHIFBlYWsgQ2x1c3RlcmluZyAocmxvZykiLAogICAgIHlsYWIgPSAiSGVpZ2h0IikKCiN0aGlzIG1ha2VzIHRoZSBiYXIKY29sb3JlZF9iYXJzKHRoZV9iYXJzX3JsZCwgVHJlZVJfcmxkLCBzb3J0X2J5X2xhYmVsc19vcmRlciA9IFQsIHlfc2hpZnQ9LTAuMSwgcm93TGFiZWxzID0gYygiaz0zIiwiaz00Iiwiaz01IiksY2V4LnJvd0xhYmVscz0wLjcpCgpwbG90KFRyZWVSX3JlbCwKICAgICBsZWFmbGFiID0gIm5vbmUiLAogICAgIG1haW4gPSAiZFJFRyBQZWFrIENsdXN0ZXJpbmcgKHJlbGF0aXZlIGFjdGl2aXR5KSIsCiAgICAgeWxhYiA9ICJIZWlnaHQiKQoKI3RoaXMgbWFrZXMgdGhlIGJhcgpjb2xvcmVkX2JhcnModGhlX2JhcnNfcmVsLCBUcmVlUl9yZWwsIHNvcnRfYnlfbGFiZWxzX29yZGVyID0gVCwgeV9zaGlmdD0tMC4xLCByb3dMYWJlbHMgPSBjKCJrPTMiLCJrPTQiLCJrPTUiKSxjZXgucm93TGFiZWxzPTAuNykKYGBgCgpMZXQncyBzZWUgaG93IHdlbGwgdGhlc2UgY2x1c3RlcnMgc2VwYXJhdGUgZXhwcmVzc2lvbiBncm91cHMgYXNzb2NpYXRlZCB3aXRoIGRpZmZlcmVudCBjZWxsIGxpbmUgc3VidHlwZXMuLi4KYGBge3J9CmRhdGFfYWxsIDwtIGMoIkhVVDEwMl9BVExMIiwKICAgICAgICAgICAgICAgICAiU1QxX0FUTEwiLAogICAgICAgICAgICAgICAgICJTdTlUMDFfQVRMTCIsIAogICAgICAgICAgICAgICAgICJLQVJQQVMyOTlfQUxLK0FMQ0wiLCAKICAgICAgICAgICAgICAgICAiTDgyX0FMSytBTENMIiwKICAgICAgICAgICAgICAgICAiU1VQTTJfQUxLK0FMQ0wiLAogICAgICAgICAgICAgICAgICJTTVoxX1BUQ0xfTk9TIiwKICAgICAgICAgICAgICAgICAiTVlMQV9DVENMIiwKICAgICAgICAgICAgICAgICAiTUFDMkFfQUxLLUFMQ0wiLAogICAgICAgICAgICAgICAgICJLSUpLX0FMSytBTENMIiwKICAgICAgICAgICAgICAgICAiU1I3ODZfQUxLK0FMQ0wiLAogICAgICAgICAgICAgICJGRVBEX0FMSy1BTENMIiwKICAgICAgICAgICAgICAgICAiS0FSUEFTMzg0X1NRR0RfVENMIiwKICAgICAgICAgICAgICAgICAiREw0MF9BTEstQUxDTCIsIAogICAgICAgICAgICAgICAgICJPQ0lMWTEyX1BUQ0xfTk9TIiwgCiAgICAgICAgICAgICAgICAgIkhVVDc4X0NUQ0wiLAogICAgICAgICAgICAgICAgICJISF9DVENMIiwKICAgICAgICAgICAgICAgICAiTUpfQ1RDTCIsCiAgICAgICAgICAgICAgICAgIk1UQV9OS1QiLAogICAgICAgICAgICAgICAgICJNT1ROMV9UX0xHTCIsCiAgICAgICAgICAgICAgICAgIk5LTF9OS1QiLAogICAgICAgICAgICAgICAgICJERVJMMl9IU19UQ0wiLAogICAgICAgICAgICAgICJLSFlHMV9OS0wiLAogICAgICAgICAgICAgICJTZUF4X0NUQ0wiLAogICAgICAgICAgICAgICJTVURITDFfQUxLK0FMQ0wiKQoKI0RlZmluaW5nIGJveCBwbG90IGZ1bmN0aW9ucwpjbHVzdC5jb3JlID0gZnVuY3Rpb24oaSwgZGF0LCBjbHVzdGVycykgewogIGluZCA9IChjbHVzdGVycyA9PSBpKQogIGNvbE1lYW5zKGRhdFtpbmQsXSkKfQoKYm94IDwtIGZ1bmN0aW9uKGNsdXN0ZXJzLCBzY2FsZWRhdGFfY291bnRfdG9wLCB0aXRsZSl7CmNvcmVzIDwtIHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLCBjbHVzdC5jb3JlLCBzY2FsZWRhdGFfY291bnRfdG9wLCBjbHVzdGVycykKCiNtYWtlIGEgZGF0YWZyYW1lIG9mIGNvcmVzIGJ5IHN1YnR5cGUKZCA8LSBkYXRhLmZyYW1lKGNiaW5kKGRhdGFfYWxsLCBjb3JlcykpICNzdWJUeXBlIGxpc3QgZnJvbSBiZWdpbm5pbmchCmNvbG5hbWVzKGQpIDwtYygic2FtcGxlIiwgcGFzdGUwKCJjbHVzdF8iLDE6bmNvbChjb3JlcykpKQoKI2dldCB0aGUgZGF0YSBmcmFtZSBpbnRvIGxvbmcgZm9ybWF0IGZvciBwbG90dGluZwpkbW9sdGVuIDwtIG1lbHQoZCwgaWQudmFycyA9ICJzYW1wbGUiKQojb3JkZXIgYnkgc3VidHlwZQpkbW9sdGVuIDwtIGRtb2x0ZW5bb3JkZXIoZG1vbHRlbiRzYW1wbGUpLF0KZG1vbHRlbiRzYW1wbGUgPC0gb3JkZXJlZChkbW9sdGVuJHNhbXBsZSwgbGV2ZWxzPXVuaXF1ZShkbW9sdGVuJHNhbXBsZSkpCgojIG1ha2UgdGhlIHBsb3QKcDEgPC0gZ2dwbG90KGRtb2x0ZW4sIGFlcyh4PXNhbXBsZSwgeT1hcy5udW1lcmljKHZhbHVlKSwgY29sPXZhcmlhYmxlKSkgKyAKICBnZW9tX2JveHBsb3QoKSArCiMgIGdlb21fcG9pbnQoKSArIAojICBnZW9tX2xpbmUoKSArCiMgIHNjYWxlX3hfY29udGludW91cyhtaW5vcl9icmVha3MgPSBOVUxMLCBicmVha3M9Yyhhcy5udW1lcmljKGxldmVscyhmYWN0b3IoZG1vbHRlbiRzdWJ0eXBlKSkpKSkgKwojICBzY2FsZV95X2NvbnRpbnVvdXMoKSArCiAgeGxhYigiU2FtcGxlIikgKwogIHlsYWIoIkFjdGl2aXR5IikgKwogIGxhYnModGl0bGU9IHBhc3RlMCgiQ2x1c3RlciBDb3JlIEV4cHJlc3Npb24gYnkgU2FtcGxlICgiLHRpdGxlLCIpIiksY29sb3IgPSAiQ2x1c3RlciIpCnJldHVybihwMSkKfQpgYGAKCk1ha2UgYm94cGxvdHMKYGBge3J9CmJveChybGRfY3V0azIsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azIgcmxvZyIpCmJveChybGRfY3V0azMsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azMgcmxvZyIpCmJveChybGRfY3V0azQsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azQgcmxvZyIpCmJveChybGRfY3V0azUsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azUgcmxvZyIpCmJveChybGRfY3V0azYsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azYgcmxvZyIpCmJveChybGRfY3V0azcsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azcgcmxvZyIpCmJveChybGRfY3V0azgsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azggcmxvZyIpCmJveChybGRfY3V0azksIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azkgcmxvZyIpCmJveChybGRfY3V0azEwLCBzY2FsZWRhdGFfcmxkX2FsbCwgImN1dGsxMCBybG9nIikKCmJveChjKHJsZF9jdXRrMyxybGRfYm90NWtfYWxsKSwgcmJpbmQoc2NhbGVkYXRhX3JsZF9hbGwsc2NhbGVkYXRhX2JvdCksICJjdXRrMyArIHN0YXRpYyBbXCJjbHVzdF81XCJdIHJsb2ciKQoKYm94KHJlbF9jdXRrMywgc2NhbGVkYXRhX3JlbF90b3BbLDI6MjZdLCAiY3V0azMgcmVsIikKYm94KHJlbF9jdXRrNCwgc2NhbGVkYXRhX3JlbF90b3BbLDI6MjZdLCAiY3V0azQgcmVsIikKYm94KHJlbF9jdXRrNSwgc2NhbGVkYXRhX3JlbF90b3BbLDI6MjZdLCAiY3V0azUgcmVsIikKCmJveChyZWxfY3V0azMsIHNjYWxlZGF0YV9jb3VudF90b3AsICJjdXRrMyBjb3VudCIpCmJveChyZWxfY3V0azQsIHNjYWxlZGF0YV9jb3VudF90b3AsICJjdXRrNCBjb3VudCIpCmJveChyZWxfY3V0azUsIHNjYWxlZGF0YV9jb3VudF90b3AsICJjdXRrNSBjb3VudCIpCmBgYAoKUHJvcGVybHkgYnkgc3VidHlwZSBpbnN0ZWFkIG9mIGluZGl2aWR1YWwgc2FtcGxlcwpgYGB7cn0KZGF0YV9hbGwgPC0gYygiQVRMTCIsCiAgICAgICAgICAgICAgICAgIkFUTEwiLAogICAgICAgICAgICAgICAgICJBVExMIiwgCiAgICAgICAgICAgICAgICAgIkFMSytBTENMIiwgCiAgICAgICAgICAgICAgICAgIkFMSytBTENMIiwKICAgICAgICAgICAgICAgICAiQUxLK0FMQ0wiLAogICAgICAgICAgICAgICAgICJQVENMX05PUyIsCiAgICAgICAgICAgICAgICAgIkNUQ0wiLAogICAgICAgICAgICAgICAgICJBTEstQUxDTCIsCiAgICAgICAgICAgICAgICAgIkFMSytBTENMIiwKICAgICAgICAgICAgICAgICAiQUxLK0FMQ0wiLAogICAgICAgICAgICAgICJBTEstQUxDTCIsCiAgICAgICAgICAgICAgICAgIlNRR0RfVENMIiwKICAgICAgICAgICAgICAgICAiQUxLLUFMQ0wiLCAKICAgICAgICAgICAgICAgICAiUFRDTF9OT1MiLCAKICAgICAgICAgICAgICAgICAiQ1RDTCIsCiAgICAgICAgICAgICAgICAgIkNUQ0wiLAogICAgICAgICAgICAgICAgICJDVENMIiwKICAgICAgICAgICAgICAgICAiTktUIiwKICAgICAgICAgICAgICAgICAiVF9MR0wiLAogICAgICAgICAgICAgICAgICJOS1QiLAogICAgICAgICAgICAgICAgICJIU19UQ0wiLAogICAgICAgICAgICAgICJOS0wiLAogICAgICAgICAgICAgICJDVENMIiwKICAgICAgICAgICAgICAiQUxLK0FMQ0wiKQoKI0RlZmluaW5nIGJveCBwbG90IGZ1bmN0aW9ucwpjbHVzdC5jb3JlID0gZnVuY3Rpb24oaSwgZGF0LCBjbHVzdGVycykgewogIGluZCA9IChjbHVzdGVycyA9PSBpKQogIGNvbE1lYW5zKGRhdFtpbmQsXSkKfQoKYm94IDwtIGZ1bmN0aW9uKGNsdXN0ZXJzLCBzY2FsZWRhdGFfY291bnRfdG9wLCB0aXRsZSl7CmNvcmVzIDwtIHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLCBjbHVzdC5jb3JlLCBzY2FsZWRhdGFfY291bnRfdG9wLCBjbHVzdGVycykKCiNtYWtlIGEgZGF0YWZyYW1lIG9mIGNvcmVzIGJ5IHN1YnR5cGUKZCA8LSBkYXRhLmZyYW1lKGNiaW5kKGRhdGFfYWxsLCBjb3JlcykpICNzdWJUeXBlIGxpc3QgZnJvbSBiZWdpbm5pbmchCmNvbG5hbWVzKGQpIDwtYygic3VidHlwZSIsIHBhc3RlMCgiY2x1c3RfIiwxOm5jb2woY29yZXMpKSkKCiNnZXQgdGhlIGRhdGEgZnJhbWUgaW50byBsb25nIGZvcm1hdCBmb3IgcGxvdHRpbmcKZG1vbHRlbiA8LSBtZWx0KGQsIGlkLnZhcnMgPSAic3VidHlwZSIpCiNvcmRlciBieSBzdWJ0eXBlCmRtb2x0ZW4gPC0gZG1vbHRlbltvcmRlcihkbW9sdGVuJHN1YnR5cGUpLF0KZG1vbHRlbiRzdWJ0eXBlIDwtIG9yZGVyZWQoZG1vbHRlbiRzdWJ0eXBlLCBsZXZlbHM9dW5pcXVlKGRtb2x0ZW4kc3VidHlwZSkpCgojIG1ha2UgdGhlIHBsb3QKcDEgPC0gZ2dwbG90KGRtb2x0ZW4sIGFlcyh4PXN1YnR5cGUsIHk9YXMubnVtZXJpYyh2YWx1ZSksIGNvbD12YXJpYWJsZSkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKwojICBnZW9tX3BvaW50KCkgKyAKIyAgZ2VvbV9saW5lKCkgKwojICBzY2FsZV94X2NvbnRpbnVvdXMobWlub3JfYnJlYWtzID0gTlVMTCwgYnJlYWtzPWMoYXMubnVtZXJpYyhsZXZlbHMoZmFjdG9yKGRtb2x0ZW4kc3VidHlwZSkpKSkpICsKIyAgc2NhbGVfeV9jb250aW51b3VzKCkgKwogIHhsYWIoIlN1YnR5cGUiKSArCiAgeWxhYigiQWN0aXZpdHkiKSArCiAgbGFicyh0aXRsZT0gcGFzdGUwKCJDbHVzdGVyIENvcmUgRXhwcmVzc2lvbiBieSBTdWJ0eXBlICgiLHRpdGxlLCIpIiksY29sb3IgPSAiQ2x1c3RlciIpCnJldHVybihwMSkKfQpgYGAKCk1ha2UgYm94cGxvdHMKYGBge3J9CmJveChybGRfY3V0azIsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azIgcmxvZyIpCmJveChybGRfY3V0azMsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azMgcmxvZyIpCmJveChybGRfY3V0azQsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azQgcmxvZyIpCmJveChybGRfY3V0azUsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azUgcmxvZyIpCmJveChybGRfY3V0azYsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azYgcmxvZyIpCmJveChybGRfY3V0azcsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azcgcmxvZyIpCmJveChybGRfY3V0azgsIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azggcmxvZyIpCmJveChybGRfY3V0azksIHNjYWxlZGF0YV9ybGRfYWxsLCAiY3V0azkgcmxvZyIpCmJveChybGRfY3V0azEwLCBzY2FsZWRhdGFfcmxkX2FsbCwgImN1dGsxMCBybG9nIikKCmJveChjKHJsZF9jdXRrMyxybGRfYm90NWtfYWxsKSwgcmJpbmQoc2NhbGVkYXRhX3JsZF9hbGwsc2NhbGVkYXRhX2JvdCksICJjdXRrMyArIHN0YXRpYyBbXCJjbHVzdF81XCJdIHJsb2ciKQoKYm94KHJlbF9jdXRrMywgc2NhbGVkYXRhX3JlbF90b3BbLDI6MjZdLCAiY3V0azMgcmVsIikKYm94KHJlbF9jdXRrNCwgc2NhbGVkYXRhX3JlbF90b3BbLDI6MjZdLCAiY3V0azQgcmVsIikKYm94KHJlbF9jdXRrNSwgc2NhbGVkYXRhX3JlbF90b3BbLDI6MjZdLCAiY3V0azUgcmVsIikKCmJveChyZWxfY3V0azMsIHNjYWxlZGF0YV9jb3VudF90b3AsICJjdXRrMyBjb3VudCIpCmJveChyZWxfY3V0azQsIHNjYWxlZGF0YV9jb3VudF90b3AsICJjdXRrNCBjb3VudCIpCmJveChyZWxfY3V0azUsIHNjYWxlZGF0YV9jb3VudF90b3AsICJjdXRrNSBjb3VudCIpCmBgYAoKQ2FuJ3QgbWFrZSBtdWNoIHNlbnNlIG9mIHVuaXF1ZSBjbHVzdGVyaW5nIGJldHdlZW4gdGhlIHNhbXBsZXMgb3IgdGhlaXIgc3VidHlwZXMuIENvbnNpZGVyaW5nIHN1YnNldHRpbmcgb3V0IG9yaWdpbmFsIGRhdGEgaW50byBjbHVzdGVyaW5nIGFuZCBub25jbHVzdGVyaW5nIHNhbXBsZXMgYW5kIG1vdmluZyBvbiB3aXRoIGluZGl2aWR1YWwgY2x1c3RlciB0cmVhdG1lbnRzIGZvciBlYWNoIGZyb20gdGhlcmUuCgpXYW50IHRvIG1ha2UgYSBoZWF0bWFwIHdpdGggdGhlIGFib3ZlIGNsdXN0ZXJzIGFuZCBhIGNsdXN0ZXItdHJhaXQgY29ycmVsYXRpb24gaGVhdG1hcC4uLgoKVHJhaXQgY29ycmVsYXRpb24gKGVkaXQgZm9yIHRoaXMgZGF0YXNldCkKYGBge3J9CnRyYWl0cyA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcz1jb2xuYW1lcyhzY2FsZWRhdGFfcmxkX2FsbCkpIAojaGVyZSBJJ20gYWRkaW5nIHZlY3RvcnMgb2Ygc3VidHlwZSB0cmFpdHMgdG8gdGhlIGRhdGFmcmFtZQp0cmFpdHMkJ0FUTEwnIDwtICAgICBjKDEsMSwxLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDApICNjb3JyZWN0ZWQKdHJhaXRzJCdBTEsrQUxDTCcgPC0gICAgICAgYygwLDAsMCwxLDEsMSwwLDAsMCwxLDEsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwxKSAjY29ycmVjdGVkCnRyYWl0cyQnQUxLLUFMQ0wnIDwtIGMoMCwwLDAsMCwwLDAsMCwwLDEsMCwwLDEsMCwxLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCkgI2NvcnJlY3RlZAp0cmFpdHMkJ05LVCcgPC0gICAgIGMoMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMSwwLDEsMCwwLDAsMCkgI2NvcnJlY3RlZAp0cmFpdHMkJ0NUQ0wnIDwtICAgICAgIGMoMCwwLDAsMCwwLDAsMCwxLDAsMCwwLDAsMCwwLDAsMSwxLDEsMCwwLDAsMCwwLDEsMCkgI2NvcnJlY3RlZAp0cmFpdHMkJ1RfTEdMJyA8LSBjKDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMSwwLDAsMCwwLDApICNjb3JyZWN0ZWQKdHJhaXRzJCdTUUdEX1RDTCcgPC0gICAgIGMoMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMSwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCkgI2NvcnJlY3RlZAp0cmFpdHMkJ05LTCcgPC0gICAgICAgYygwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDEsMCwwKSAjY29ycmVjdGVkCnRyYWl0cyQnUFRDTF9OT1MnIDwtIGMoMCwwLDAsMCwwLDAsMSwwLDAsMCwwLDAsMCwwLDEsMCwwLDAsMCwwLDAsMCwwLDAsMCkgI2NvcnJlY3RlZAp0cmFpdHMkJ0hTX1RDTCcgPC0gYygwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwxLDAsMCwwKSAjY29ycmVjdGVkCgojRXh0cmFjdCB0aGUgZ2VuZS9zYW1wbGUgbnVtYmVycwpuUGVha3MgPSBucm93KHNjYWxlZGF0YV9ybGRfYWxsKSAKblNhbXBsZXMgPSBuY29sKHNjYWxlZGF0YV9ybGRfYWxsKQoKI3AgdmFsdWUgY2FsY3VsYXRpb24gZnJvbSBXR0NOQQpjb3JQdmFsdWVTdHVkZW50ID0gZnVuY3Rpb24oY29yLCBuU2FtcGxlcykgewogIFQ9c3FydChuU2FtcGxlcy0yKSAqIGNvci9zcXJ0KDEtY29yXjIpCiAgMipwdChhYnMoVCksblNhbXBsZXMtMiwgbG93ZXIudGFpbCA9IEZBTFNFKQp9CmBgYAoKTWFrZSBjb3JyZWxhdGlvbiBoZWF0bWFwcwpgYGB7cn0KblNhbXBsZXM9MjUKCiNGaW5hbGl6ZSBjbHVzdGVyaW5nIGFuZCBicmFuY2ggY3V0cwpjbHVzdGVycyA8LSBybGRfY3V0azIKCmNvcmVzIDwtIHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLCBjbHVzdC5jb3JlLCBzY2FsZWRhdGFfcmxkX2FsbCwgY2x1c3RlcnMpCiNjb3JyZWxhdGUgdGhlIGNvcmVzIHRvIHRyYWl0czoKbW9kdWxlVHJhaXRDb3IgPSBjb3IoY29yZXMsIHRyYWl0cywgdXNlPSAicCIpCm1vZHVsZVRyYWl0UHZhbHVlID0gY29yUHZhbHVlU3R1ZGVudChtb2R1bGVUcmFpdENvciwgblNhbXBsZXMpCiNnZW5lcmF0ZSBhIHRleHQgbWF0cml4IG9mIHRoZSBjb3JyZWxhdGlvbiBhbmQgcHZhbHVlCnRleHRNYXRyaXg9IHBhc3RlKHNpZ25pZihtb2R1bGVUcmFpdENvciwgMiksICJcbigiLAogICAgICAgICAgICAgICAgICBzaWduaWYobW9kdWxlVHJhaXRQdmFsdWUsIDEpLCAiKSIsIHNlcD0gIiIpCmRpbSh0ZXh0TWF0cml4KT0gZGltKG1vZHVsZVRyYWl0Q29yKQojcGxvdCBhIGhlYXRtYXAgb2YgdGhlIGNsdXN0ZXJzIGJ5IHRyYWl0IG92ZXJsYXlpbmcgdGhlIGNvcnIvcHZhbHVlCiNwYXIob21hPWMoMSwwLDEsMSkpCmhlYXRtYXAuMihtb2R1bGVUcmFpdENvciwKICAgICAgICAgIGRlbmRyb2dyYW0gPSAibm9uZSIsCiAgICAgICAgICBDb2x2ID1GQUxTRSwKICAgICAgICAgIHNjYWxlID0gYygibm9uZSIpLAogICAgICAgICAgY29sPSJoZWF0LmNvbG9ycyIsCiAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgY2VsbG5vdGUgPSB0ZXh0TWF0cml4LAogICAgICAgICAgbm90ZWNvbD0iZ3JleTMwIiwKICAgICAgICAgIG5vdGVjZXg9MSwKICAgICAgICAgIHRyYWNlPWMoIm5vbmUiKSwKICAgICAgICAgIGNleFJvdyA9IDAuOCwKICAgICAgICAgIGNleENvbCA9IDAuOCwKICAgICAgICAgIG1haW4gPSAiQ2x1c3Rlci1UcmFpdCBDb3JyZWxhdGlvbiAoaz0yKSIsCiAgICAgICAgICB4bGFiID0gIlRyYWl0cyIsCiAgICAgICAgICB5bGFiID0gIkNsdXN0ZXJzIikKCmNsdXN0ZXJzIDwtIHJsZF9jdXRrMwoKY29yZXMgPC0gc2FwcGx5KHVuaXF1ZShjbHVzdGVycyksIGNsdXN0LmNvcmUsIHNjYWxlZGF0YV9ybGRfYWxsLCBjbHVzdGVycykKI2NvcnJlbGF0ZSB0aGUgY29yZXMgdG8gdHJhaXRzOgptb2R1bGVUcmFpdENvciA9IGNvcihjb3JlcywgdHJhaXRzLCB1c2U9ICJwIikKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCBuU2FtcGxlcykKI2dlbmVyYXRlIGEgdGV4dCBtYXRyaXggb2YgdGhlIGNvcnJlbGF0aW9uIGFuZCBwdmFsdWUKdGV4dE1hdHJpeD0gcGFzdGUoc2lnbmlmKG1vZHVsZVRyYWl0Q29yLCAyKSwgIlxuKCIsCiAgICAgICAgICAgICAgICAgIHNpZ25pZihtb2R1bGVUcmFpdFB2YWx1ZSwgMSksICIpIiwgc2VwPSAiIikKZGltKHRleHRNYXRyaXgpPSBkaW0obW9kdWxlVHJhaXRDb3IpCiNwbG90IGEgaGVhdG1hcCBvZiB0aGUgY2x1c3RlcnMgYnkgdHJhaXQgb3ZlcmxheWluZyB0aGUgY29yci9wdmFsdWUKI3BhcihvbWE9YygxLDAsMSwxKSkKaGVhdG1hcC4yKG1vZHVsZVRyYWl0Q29yLAogICAgICAgICAgZGVuZHJvZ3JhbSA9ICJub25lIiwKICAgICAgICAgIENvbHYgPUZBTFNFLAogICAgICAgICAgc2NhbGUgPSBjKCJub25lIiksCiAgICAgICAgICBjb2w9ImhlYXQuY29sb3JzIiwKICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICBjZWxsbm90ZSA9IHRleHRNYXRyaXgsCiAgICAgICAgICBub3RlY29sPSJncmV5MzAiLAogICAgICAgICAgbm90ZWNleD0xLAogICAgICAgICAgdHJhY2U9Yygibm9uZSIpLAogICAgICAgICAgY2V4Um93ID0gMC44LAogICAgICAgICAgY2V4Q29sID0gMC44LAogICAgICAgICAgbWFpbiA9ICJDbHVzdGVyLVRyYWl0IENvcnJlbGF0aW9uIChrPTMpIiwKICAgICAgICAgIHhsYWIgPSAiVHJhaXRzIiwKICAgICAgICAgIHlsYWIgPSAiQ2x1c3RlcnMiKQoKY2x1c3RlcnMgPC0gcmxkX2N1dGs0Cgpjb3JlcyA8LSBzYXBwbHkodW5pcXVlKGNsdXN0ZXJzKSwgY2x1c3QuY29yZSwgc2NhbGVkYXRhX3JsZF9hbGwsIGNsdXN0ZXJzKQojY29ycmVsYXRlIHRoZSBjb3JlcyB0byB0cmFpdHM6Cm1vZHVsZVRyYWl0Q29yID0gY29yKGNvcmVzLCB0cmFpdHMsIHVzZT0gInAiKQptb2R1bGVUcmFpdFB2YWx1ZSA9IGNvclB2YWx1ZVN0dWRlbnQobW9kdWxlVHJhaXRDb3IsIG5TYW1wbGVzKQojZ2VuZXJhdGUgYSB0ZXh0IG1hdHJpeCBvZiB0aGUgY29ycmVsYXRpb24gYW5kIHB2YWx1ZQp0ZXh0TWF0cml4PSBwYXN0ZShzaWduaWYobW9kdWxlVHJhaXRDb3IsIDIpLCAiXG4oIiwKICAgICAgICAgICAgICAgICAgc2lnbmlmKG1vZHVsZVRyYWl0UHZhbHVlLCAxKSwgIikiLCBzZXA9ICIiKQpkaW0odGV4dE1hdHJpeCk9IGRpbShtb2R1bGVUcmFpdENvcikKI3Bsb3QgYSBoZWF0bWFwIG9mIHRoZSBjbHVzdGVycyBieSB0cmFpdCBvdmVybGF5aW5nIHRoZSBjb3JyL3B2YWx1ZQojcGFyKG9tYT1jKDEsMCwxLDEpKQpoZWF0bWFwLjIobW9kdWxlVHJhaXRDb3IsCiAgICAgICAgICBkZW5kcm9ncmFtID0gIm5vbmUiLAogICAgICAgICAgQ29sdiA9RkFMU0UsCiAgICAgICAgICBzY2FsZSA9IGMoIm5vbmUiKSwKICAgICAgICAgIGNvbD0iaGVhdC5jb2xvcnMiLAogICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgIGNlbGxub3RlID0gdGV4dE1hdHJpeCwKICAgICAgICAgIG5vdGVjb2w9ImdyZXkzMCIsCiAgICAgICAgICBub3RlY2V4PTEsCiAgICAgICAgICB0cmFjZT1jKCJub25lIiksCiAgICAgICAgICBjZXhSb3cgPSAwLjgsCiAgICAgICAgICBjZXhDb2wgPSAwLjgsCiAgICAgICAgICBtYWluID0gIkNsdXN0ZXItVHJhaXQgQ29ycmVsYXRpb24gKGs9NCkiLAogICAgICAgICAgeGxhYiA9ICJUcmFpdHMiLAogICAgICAgICAgeWxhYiA9ICJDbHVzdGVycyIpCgpjbHVzdGVycyA8LSBybGRfY3V0azUKCmNvcmVzIDwtIHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLCBjbHVzdC5jb3JlLCBzY2FsZWRhdGFfcmxkX2FsbCwgY2x1c3RlcnMpCiNjb3JyZWxhdGUgdGhlIGNvcmVzIHRvIHRyYWl0czoKbW9kdWxlVHJhaXRDb3IgPSBjb3IoY29yZXMsIHRyYWl0cywgdXNlPSAicCIpCm1vZHVsZVRyYWl0UHZhbHVlID0gY29yUHZhbHVlU3R1ZGVudChtb2R1bGVUcmFpdENvciwgblNhbXBsZXMpCiNnZW5lcmF0ZSBhIHRleHQgbWF0cml4IG9mIHRoZSBjb3JyZWxhdGlvbiBhbmQgcHZhbHVlCnRleHRNYXRyaXg9IHBhc3RlKHNpZ25pZihtb2R1bGVUcmFpdENvciwgMiksICJcbigiLAogICAgICAgICAgICAgICAgICBzaWduaWYobW9kdWxlVHJhaXRQdmFsdWUsIDEpLCAiKSIsIHNlcD0gIiIpCmRpbSh0ZXh0TWF0cml4KT0gZGltKG1vZHVsZVRyYWl0Q29yKQojcGxvdCBhIGhlYXRtYXAgb2YgdGhlIGNsdXN0ZXJzIGJ5IHRyYWl0IG92ZXJsYXlpbmcgdGhlIGNvcnIvcHZhbHVlCiNwYXIob21hPWMoMSwwLDEsMSkpCmhlYXRtYXAuMihtb2R1bGVUcmFpdENvciwKICAgICAgICAgIGRlbmRyb2dyYW0gPSAibm9uZSIsCiAgICAgICAgICBDb2x2ID1GQUxTRSwKICAgICAgICAgIHNjYWxlID0gYygibm9uZSIpLAogICAgICAgICAgY29sPSJoZWF0LmNvbG9ycyIsCiAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgY2VsbG5vdGUgPSB0ZXh0TWF0cml4LAogICAgICAgICAgbm90ZWNvbD0iZ3JleTMwIiwKICAgICAgICAgIG5vdGVjZXg9MSwKICAgICAgICAgIHRyYWNlPWMoIm5vbmUiKSwKICAgICAgICAgIGNleFJvdyA9IDAuOCwKICAgICAgICAgIGNleENvbCA9IDAuOCwKICAgICAgICAgIG1haW4gPSAiQ2x1c3Rlci1UcmFpdCBDb3JyZWxhdGlvbiAoaz01KSIsCiAgICAgICAgICB4bGFiID0gIlRyYWl0cyIsCiAgICAgICAgICB5bGFiID0gIkNsdXN0ZXJzIikKCmNsdXN0ZXJzIDwtIHJsZF9jdXRrNgoKY29yZXMgPC0gc2FwcGx5KHVuaXF1ZShjbHVzdGVycyksIGNsdXN0LmNvcmUsIHNjYWxlZGF0YV9ybGRfYWxsLCBjbHVzdGVycykKI2NvcnJlbGF0ZSB0aGUgY29yZXMgdG8gdHJhaXRzOgptb2R1bGVUcmFpdENvciA9IGNvcihjb3JlcywgdHJhaXRzLCB1c2U9ICJwIikKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCBuU2FtcGxlcykKI2dlbmVyYXRlIGEgdGV4dCBtYXRyaXggb2YgdGhlIGNvcnJlbGF0aW9uIGFuZCBwdmFsdWUKdGV4dE1hdHJpeD0gcGFzdGUoc2lnbmlmKG1vZHVsZVRyYWl0Q29yLCAyKSwgIlxuKCIsCiAgICAgICAgICAgICAgICAgIHNpZ25pZihtb2R1bGVUcmFpdFB2YWx1ZSwgMSksICIpIiwgc2VwPSAiIikKZGltKHRleHRNYXRyaXgpPSBkaW0obW9kdWxlVHJhaXRDb3IpCiNwbG90IGEgaGVhdG1hcCBvZiB0aGUgY2x1c3RlcnMgYnkgdHJhaXQgb3ZlcmxheWluZyB0aGUgY29yci9wdmFsdWUKI3BhcihvbWE9YygxLDAsMSwxKSkKaGVhdG1hcC4yKG1vZHVsZVRyYWl0Q29yLAogICAgICAgICAgZGVuZHJvZ3JhbSA9ICJub25lIiwKICAgICAgICAgIENvbHYgPUZBTFNFLAogICAgICAgICAgc2NhbGUgPSBjKCJub25lIiksCiAgICAgICAgICBjb2w9ImhlYXQuY29sb3JzIiwKICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICBjZWxsbm90ZSA9IHRleHRNYXRyaXgsCiAgICAgICAgICBub3RlY29sPSJncmV5MzAiLAogICAgICAgICAgbm90ZWNleD0xLAogICAgICAgICAgdHJhY2U9Yygibm9uZSIpLAogICAgICAgICAgY2V4Um93ID0gMC44LAogICAgICAgICAgY2V4Q29sID0gMC44LAogICAgICAgICAgbWFpbiA9ICJDbHVzdGVyLVRyYWl0IENvcnJlbGF0aW9uIChrPTYpIiwKICAgICAgICAgIHhsYWIgPSAiVHJhaXRzIiwKICAgICAgICAgIHlsYWIgPSAiQ2x1c3RlcnMiKQoKY2x1c3RlcnMgPC0gcmxkX2N1dGs3Cgpjb3JlcyA8LSBzYXBwbHkodW5pcXVlKGNsdXN0ZXJzKSwgY2x1c3QuY29yZSwgc2NhbGVkYXRhX3JsZF9hbGwsIGNsdXN0ZXJzKQojY29ycmVsYXRlIHRoZSBjb3JlcyB0byB0cmFpdHM6Cm1vZHVsZVRyYWl0Q29yID0gY29yKGNvcmVzLCB0cmFpdHMsIHVzZT0gInAiKQptb2R1bGVUcmFpdFB2YWx1ZSA9IGNvclB2YWx1ZVN0dWRlbnQobW9kdWxlVHJhaXRDb3IsIG5TYW1wbGVzKQojZ2VuZXJhdGUgYSB0ZXh0IG1hdHJpeCBvZiB0aGUgY29ycmVsYXRpb24gYW5kIHB2YWx1ZQp0ZXh0TWF0cml4PSBwYXN0ZShzaWduaWYobW9kdWxlVHJhaXRDb3IsIDIpLCAiXG4oIiwKICAgICAgICAgICAgICAgICAgc2lnbmlmKG1vZHVsZVRyYWl0UHZhbHVlLCAxKSwgIikiLCBzZXA9ICIiKQpkaW0odGV4dE1hdHJpeCk9IGRpbShtb2R1bGVUcmFpdENvcikKI3Bsb3QgYSBoZWF0bWFwIG9mIHRoZSBjbHVzdGVycyBieSB0cmFpdCBvdmVybGF5aW5nIHRoZSBjb3JyL3B2YWx1ZQojcGFyKG9tYT1jKDEsMCwxLDEpKQpoZWF0bWFwLjIobW9kdWxlVHJhaXRDb3IsCiAgICAgICAgICBkZW5kcm9ncmFtID0gIm5vbmUiLAogICAgICAgICAgQ29sdiA9RkFMU0UsCiAgICAgICAgICBzY2FsZSA9IGMoIm5vbmUiKSwKICAgICAgICAgIGNvbD0iaGVhdC5jb2xvcnMiLAogICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgIGNlbGxub3RlID0gdGV4dE1hdHJpeCwKICAgICAgICAgIG5vdGVjb2w9ImdyZXkzMCIsCiAgICAgICAgICBub3RlY2V4PTEsCiAgICAgICAgICB0cmFjZT1jKCJub25lIiksCiAgICAgICAgICBjZXhSb3cgPSAwLjgsCiAgICAgICAgICBjZXhDb2wgPSAwLjgsCiAgICAgICAgICBtYWluID0gIkNsdXN0ZXItVHJhaXQgQ29ycmVsYXRpb24gKGs9NykiLAogICAgICAgICAgeGxhYiA9ICJUcmFpdHMiLAogICAgICAgICAgeWxhYiA9ICJDbHVzdGVycyIpCgpjbHVzdGVycyA8LSBybGRfY3V0azgKCmNvcmVzIDwtIHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLCBjbHVzdC5jb3JlLCBzY2FsZWRhdGFfcmxkX2FsbCwgY2x1c3RlcnMpCiNjb3JyZWxhdGUgdGhlIGNvcmVzIHRvIHRyYWl0czoKbW9kdWxlVHJhaXRDb3IgPSBjb3IoY29yZXMsIHRyYWl0cywgdXNlPSAicCIpCm1vZHVsZVRyYWl0UHZhbHVlID0gY29yUHZhbHVlU3R1ZGVudChtb2R1bGVUcmFpdENvciwgblNhbXBsZXMpCiNnZW5lcmF0ZSBhIHRleHQgbWF0cml4IG9mIHRoZSBjb3JyZWxhdGlvbiBhbmQgcHZhbHVlCnRleHRNYXRyaXg9IHBhc3RlKHNpZ25pZihtb2R1bGVUcmFpdENvciwgMiksICJcbigiLAogICAgICAgICAgICAgICAgICBzaWduaWYobW9kdWxlVHJhaXRQdmFsdWUsIDEpLCAiKSIsIHNlcD0gIiIpCmRpbSh0ZXh0TWF0cml4KT0gZGltKG1vZHVsZVRyYWl0Q29yKQojcGxvdCBhIGhlYXRtYXAgb2YgdGhlIGNsdXN0ZXJzIGJ5IHRyYWl0IG92ZXJsYXlpbmcgdGhlIGNvcnIvcHZhbHVlCiNwYXIob21hPWMoMSwwLDEsMSkpCmhlYXRtYXAuMihtb2R1bGVUcmFpdENvciwKICAgICAgICAgIGRlbmRyb2dyYW0gPSAibm9uZSIsCiAgICAgICAgICBDb2x2ID1GQUxTRSwKICAgICAgICAgIHNjYWxlID0gYygibm9uZSIpLAogICAgICAgICAgY29sPSJoZWF0LmNvbG9ycyIsCiAgICAgICAgICBuYS5ybT1UUlVFLAogICAgICAgICAgY2VsbG5vdGUgPSB0ZXh0TWF0cml4LAogICAgICAgICAgbm90ZWNvbD0iZ3JleTMwIiwKICAgICAgICAgIG5vdGVjZXg9MSwKICAgICAgICAgIHRyYWNlPWMoIm5vbmUiKSwKICAgICAgICAgIGNleFJvdyA9IDAuOCwKICAgICAgICAgIGNleENvbCA9IDAuOCwKICAgICAgICAgIG1haW4gPSAiQ2x1c3Rlci1UcmFpdCBDb3JyZWxhdGlvbiAoaz04KSIsCiAgICAgICAgICB4bGFiID0gIlRyYWl0cyIsCiAgICAgICAgICB5bGFiID0gIkNsdXN0ZXJzIikKCmNsdXN0ZXJzIDwtIHJsZF9jdXRrOQoKY29yZXMgPC0gc2FwcGx5KHVuaXF1ZShjbHVzdGVycyksIGNsdXN0LmNvcmUsIHNjYWxlZGF0YV9ybGRfYWxsLCBjbHVzdGVycykKI2NvcnJlbGF0ZSB0aGUgY29yZXMgdG8gdHJhaXRzOgptb2R1bGVUcmFpdENvciA9IGNvcihjb3JlcywgdHJhaXRzLCB1c2U9ICJwIikKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCBuU2FtcGxlcykKI2dlbmVyYXRlIGEgdGV4dCBtYXRyaXggb2YgdGhlIGNvcnJlbGF0aW9uIGFuZCBwdmFsdWUKdGV4dE1hdHJpeD0gcGFzdGUoc2lnbmlmKG1vZHVsZVRyYWl0Q29yLCAyKSwgIlxuKCIsCiAgICAgICAgICAgICAgICAgIHNpZ25pZihtb2R1bGVUcmFpdFB2YWx1ZSwgMSksICIpIiwgc2VwPSAiIikKZGltKHRleHRNYXRyaXgpPSBkaW0obW9kdWxlVHJhaXRDb3IpCiNwbG90IGEgaGVhdG1hcCBvZiB0aGUgY2x1c3RlcnMgYnkgdHJhaXQgb3ZlcmxheWluZyB0aGUgY29yci9wdmFsdWUKI3BhcihvbWE9YygxLDAsMSwxKSkKaGVhdG1hcC4yKG1vZHVsZVRyYWl0Q29yLAogICAgICAgICAgZGVuZHJvZ3JhbSA9ICJub25lIiwKICAgICAgICAgIENvbHYgPUZBTFNFLAogICAgICAgICAgc2NhbGUgPSBjKCJub25lIiksCiAgICAgICAgICBjb2w9ImhlYXQuY29sb3JzIiwKICAgICAgICAgIG5hLnJtPVRSVUUsCiAgICAgICAgICBjZWxsbm90ZSA9IHRleHRNYXRyaXgsCiAgICAgICAgICBub3RlY29sPSJncmV5MzAiLAogICAgICAgICAgbm90ZWNleD0xLAogICAgICAgICAgdHJhY2U9Yygibm9uZSIpLAogICAgICAgICAgY2V4Um93ID0gMC44LAogICAgICAgICAgY2V4Q29sID0gMC44LAogICAgICAgICAgbWFpbiA9ICJDbHVzdGVyLVRyYWl0IENvcnJlbGF0aW9uIChrPTkpIiwKICAgICAgICAgIHhsYWIgPSAiVHJhaXRzIiwKICAgICAgICAgIHlsYWIgPSAiQ2x1c3RlcnMiKQoKI2NsdXN0ZXJzIDwtIGMocmxkX2N1dGs0LHJsZF9ib3A1a19hbGwpCgojY29yZXMgPC0gc2FwcGx5KHVuaXF1ZShjbHVzdGVycyksIGNsdXN0LmNvcmUsIHJiaW5kKHNjYWxlZGF0YV9ybGRfdG9wLCBzY2FsZWRhdGFfYm90KSwgY2x1c3RlcnMpCiNjb3JyZWxhdGUgdGhlIGNvcmVzIHRvIHRyYWl0czoKI21vZHVsZVRyYWl0Q29yID0gY29yKGNvcmVzLCB0cmFpdHMsIHVzZT0gInAiKQojbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCBuU2FtcGxlcykKI2dlbmVyYXRlIGEgdGV4dCBtYXRyaXggb2YgdGhlIGNvcnJlbGF0aW9uIGFuZCBwdmFsdWUKI3RleHRNYXRyaXg9IHBhc3RlKHNpZ25pZihtb2R1bGVUcmFpdENvciwgMiksICJcbigiLAogICAgICAgICAgICAgICAgICAjc2lnbmlmKG1vZHVsZVRyYWl0UHZhbHVlLCAxKSwgIikiLCBzZXA9ICIiKQojZGltKHRleHRNYXRyaXgpPSBkaW0obW9kdWxlVHJhaXRDb3IpCiNwbG90IGEgaGVhdG1hcCBvZiB0aGUgY2x1c3RlcnMgYnkgdHJhaXQgb3ZlcmxheWluZyB0aGUgY29yci9wdmFsdWUKI3BhcihvbWE9YygxLDAsMSwxKSkKI2hlYXRtYXAuMihtb2R1bGVUcmFpdENvciwKICAgICAgICAgICNkZW5kcm9ncmFtID0gIm5vbmUiLAogICAgICAgICAgI0NvbHYgPUZBTFNFLAogICAgICAgICAgI3NjYWxlID0gYygibm9uZSIpLAogICAgICAgICAgI2NvbD0iaGVhdC5jb2xvcnMiLAogICAgICAgICAgI25hLnJtPVRSVUUsCiAgICAgICAgICAjY2VsbG5vdGUgPSB0ZXh0TWF0cml4LAogICAgICAgICAgI25vdGVjb2w9ImdyZXkzMCIsCiAgICAgICAgICAjbm90ZWNleD0xLAogICAgICAgICAgI3RyYWNlPWMoIm5vbmUiKSwKICAgICAgICAgICNjZXhSb3cgPSAwLjgsCiAgICAgICAgICAjY2V4Q29sID0gMC44LAogICAgICAgICAgI21haW4gPSAiQ2x1c3Rlci1UcmFpdCBDb3JyZWxhdGlvbiAoaz00ICsgU3RhdGljIFs1a10pIiwKICAgICAgICAgICN4bGFiID0gIlRyYWl0cyIsCiAgICAgICAgICAjeWxhYiA9ICJDbHVzdGVycyIpCmBgYAoKTWFrZSBhbm5vdGF0ZWQgc2NhbGVkIHJsb2cgaGVhdG1hcApgYGB7cn0KcmxkX2RmIDwtIGFzLmRhdGEuZnJhbWUoc2NhbGVkYXRhX3JsZF90b3ApCnJsZF9kZiRrMyA8LSBhcy5kYXRhLmZyYW1lKHJsZF9jdXRrMykkcmxkX2N1dGszCnJsZF9kZiRrNCA8LSBhcy5kYXRhLmZyYW1lKHJsZF9jdXRrNCkkcmxkX2N1dGs0Cgpjb2xvcnMgPC0gYygnI2U2MTk0QicsJyMzY2I0NGInLCcjZmZlMTE5JywnIzQzNjNkOCcsJyNmNTgyMzEnLCcjOTExZWI0JywnIzQyZDRmNCcsJyNmMDMyZTYnLCcjYmZlZjQ1JywnI2ZhYmVkNCcsJyM0Njk5OTAnLCcjZGNiZWZmJywnIzlBNjMyNCcsJyNmZmZhYzgnLCcjODAwMDAwJywnI2FhZmZjMycsJyM4MDgwMDAnLCcjZmZkOGIxJywnIzAwMDA3NScsJyNhOWE5YTknLCcjZmZmZmZmJywnIzAwMDAwMCcpCiNIaWdoIGNvbnRyYXN0IGNvbG9ycyBmb3IgZmlndXJlcyB3YXMgcHVsbGVkIGZyb20gaHR0cHM6Ly9zYXNoYW1hcHMubmV0L2RvY3MvcmVzb3VyY2VzLzIwLWNvbG9ycy8KCnBoZWF0bWFwKHJsZF90b3A1a19hbGwsCiAgICAgICAgICNybGRfZGZbb3JkZXIocmxkX2RmWywxMl0pLF1bLDE6MTFdLCAKICAgICAgICAgI2dhcHNfcm93ID0gYyg4NzksMjI5OCw0MjEzKSwgCiAgICAgICAgIGNsdXN0ZXJfY29scz1ULCAKICAgICAgICAgY2x1c3Rlcl9yb3dzPWhyX3JsZCwKICAgICAgICAgI2NsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJldWNsaWRlYW4iLAogICAgICAgICAjY2x1c3RlcmluZ19tZXRob2QgPSAiY29tcGxldGUiLAogICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgY3V0cmVlX3Jvd3M9NCwKICAgICAgICAgY3V0cmVlX2NvbHM9MywgCiAgICAgICAgIGJvcmRlcl9jb2xvcj1OQSwgCiAgICAgICAgIHNob3dfcm93bmFtZXM9RiwgCiAgICAgICAgIG1haW49IlRvcCA1ayBkUkVHIFBlYWsgUENBIENvbnRyaWJ1dG9ycyBIaWVyYXJjaGljYWwiLAogICAgICAgICBicmVha3M9c2VxKC0yLDIsYnk9MC4wMSksCiAgICAgICAgIGNvbG9yPW9jZWFuLmJhbGFuY2UoNDAxKSwKICAgICAgICAgI2NvbG9yPXNjaWNvKDQwMSwgcGFsZXR0ZSA9ICdiZXJsaW4nKSwKICAgICAgICAgI2NvbG9yPWNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkoNDEpLAogICAgICAgICBhbm5vdGF0aW9uX3Jvdz1ybGRfZGZbMjY6MjddLCAKICAgICAgICAgYW5ub3RhdGlvbl9jb2w9ZGF0YS5mcmFtZShyb3cubmFtZXM9Y29sbmFtZXMocmxkX2RmWywxOjI1XSksIFN1YnR5cGUgPSBkYXRhX2FsbCksIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycz1saXN0KGszPWMoImJsdWUiLCAiZ3JlZW4iLCAicmVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgazQ9YygicHVycGxlIiwgImJsdWUiLCAiZ3JlZW4iLCAiZ29sZGVucm9kMSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdWJ0eXBlPWMoIkFUTEwiPSAnZGFya2dyYXknLCAiQUxLK0FMQ0wiPSAnY2hvY29sYXRlNCcsICJDVENMIj0gJ2NoYXJ0cmV1c2UzJywgIkFMSy1BTENMIj0gJ2NhZGV0Ymx1ZScsICJTUUdEX1RDTCI9ICdjeWFuMycsICJUX0xHTCI9ICdyZWQnLCAiTktUIj0gJ2xpZ2h0cGluaycsICJIU19UQ0wiPSAnYmxhY2snLCAiUFRDTF9OT1MiPSAnZGFya2dvbGRlbnJvZDEnLCAiTktMIj0gJ2JsdWV2aW9sZXQnKSkKICAgICAgICAgKQpgYGAKayBtZWFucyA0IGxvb2tzIGxpa2UgaXQncyBwaWNraW5nIHVwIHNvbWUgc2lnbmlmaWNhbnQgZ3JvdXBpbmdzIGJldHdlZW4gc2FtcGxlcy4gV2lsbCBtb3ZlIGZvcndhcmQgd2l0aCBrPTQKClJlZG9uZSBjbHVzdGVyIG1hcCB3aXRoIGluY3JlYXNlZCBjdXQgY2x1c3RlcnMgYW5kIG9yZGVyZWQgYnkgc3VidHlwZQpNYWtlIGFubm90YXRlZCBzY2FsZWQgcmxvZyBoZWF0bWFwCmBgYHtyfQpybGRfZGYyIDwtIGFzLmRhdGEuZnJhbWUoc2NhbGVkYXRhX3JsZF90b3ApCnJsZF9kZjIkazUgPC0gYXMuZGF0YS5mcmFtZShybGRfY3V0azUpJHJsZF9jdXRrNQpybGRfZGYyJGs2IDwtIGFzLmRhdGEuZnJhbWUocmxkX2N1dGs2KSRybGRfY3V0azYKcmxkX2RmMiRrNyA8LSBhcy5kYXRhLmZyYW1lKHJsZF9jdXRrNykkcmxkX2N1dGs3CnJsZF9kZjIkazggPC0gYXMuZGF0YS5mcmFtZShybGRfY3V0azgpJHJsZF9jdXRrOApybGRfZGYyJGs5IDwtIGFzLmRhdGEuZnJhbWUocmxkX2N1dGs5KSRybGRfY3V0azkKcmxkX2RmMiRrMTAgPC0gYXMuZGF0YS5mcmFtZShybGRfY3V0azEwKSRybGRfY3V0azEwCgpjb2xvcnMgPC0gYygnI2U2MTk0QicsJyMzY2I0NGInLCcjZmZlMTE5JywnIzQzNjNkOCcsJyNmNTgyMzEnLCcjOTExZWI0JywnIzQyZDRmNCcsJyNmMDMyZTYnLCcjYmZlZjQ1JywnI2ZhYmVkNCcsJyM0Njk5OTAnLCcjZGNiZWZmJywnIzlBNjMyNCcsJyNmZmZhYzgnLCcjODAwMDAwJywnI2FhZmZjMycsJyM4MDgwMDAnLCcjZmZkOGIxJywnIzAwMDA3NScsJyNhOWE5YTknLCcjZmZmZmZmJywnIzAwMDAwMCcpCiNIaWdoIGNvbnRyYXN0IGNvbG9ycyBmb3IgZmlndXJlcyB3YXMgcHVsbGVkIGZyb20gaHR0cHM6Ly9zYXNoYW1hcHMubmV0L2RvY3MvcmVzb3VyY2VzLzIwLWNvbG9ycy8KCnJsZF9kZjIgPC0gcmxkX2RmMlssYyg5LDEyLDE0LDI1LDYsNSwxMSw0LDEwLDE5LDIxLDIzLDE2LDgsMjQsMTgsMTcsMjIsMTozLDIwLDEzLDcsMTUsMjY6MzEpXQpkYXRhIDwtIGMoIkFMSy1BTENMIiwiQUxLLUFMQ0wiLCJBTEstQUxDTCIsIkFMSytBTENMIiwiQUxLK0FMQ0wiLCJBTEsrQUxDTCIsIkFMSytBTENMIiwiQUxLK0FMQ0wiLCJBTEsrQUxDTCIsIk5LVCIsIk5LVCIsIk5LTCIsIkNUQ0wiLCJDVENMIiwiQ1RDTCIsIkNUQ0wiLCJDVENMIiwiSFNfVENMIiwiQVRMTCIsIkFUTEwiLCJBVExMIiwiVF9MR0wiLCJTUUdEX1RDTCIsIlBUQ0xfTk9TIiwiUFRDTF9OT1MiKQpybGQyIDwtIHJsZF90b3A1a19hbGxbLGMoOSwxMiwxNCwyNSw2LDUsMTEsNCwxMCwxOSwyMSwyMywxNiw4LDI0LDE4LDE3LDIyLDE6MywyMCwxMyw3LDE1KV0KCnBoZWF0bWFwKHJsZDIsCiAgICAgICAgICNybGRfZGYyWzE6MjVdLAogICAgICAgICAjZ2Fwc19yb3cgPSBjKDg3OSwyMjk4LDQyMTMpLCAKICAgICAgICAgY2x1c3Rlcl9jb2xzPUYsIAogICAgICAgICBjbHVzdGVyX3Jvd3M9aHJfcmxkLAogICAgICAgICAjY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZCA9ICJjb21wbGV0ZSIsCiAgICAgICAgIHNjYWxlPSJyb3ciLAogICAgICAgICBjdXRyZWVfcm93cz02LAogICAgICAgICBjdXRyZWVfY29scz00LCAKICAgICAgICAgYm9yZGVyX2NvbG9yPU5BLCAKICAgICAgICAgc2hvd19yb3duYW1lcz1GLCAKICAgICAgICAgbWFpbj0iVG9wIDVrIGRSRUcgUGVhayBQQ0EgQ29udHJpYnV0b3JzIEhpZXJhcmNoaWNhbCIsCiAgICAgICAgIGJyZWFrcz1zZXEoLTIsMixieT0wLjAxKSwKICAgICAgICAgY29sb3I9b2NlYW4uYmFsYW5jZSg0MDEpLAogICAgICAgICAjY29sb3I9c2NpY28oNDAxLCBwYWxldHRlID0gJ2JlcmxpbicpLAogICAgICAgICAjY29sb3I9Y29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSg0MSksCiAgICAgICAgIGFubm90YXRpb25fcm93PXJsZF9kZjJbMjY6MzFdLCAKICAgICAgICAgYW5ub3RhdGlvbl9jb2w9ZGF0YS5mcmFtZShyb3cubmFtZXM9Y29sbmFtZXMocmxkX2RmMlssMToyNV0pLCBTdWJ0eXBlID0gZGF0YSksIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycz1saXN0KGs1PWMoImJsdWUiLCAiZ3JlZW4iLCAicmVkIiwgImJsYWNrIiwgIm9yYW5nZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGs2PWMoInB1cnBsZSIsICJibHVlIiwgImdyZWVuIiwgInJlZCIsICJibGFjayIsICJvcmFuZ2UiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrNz1jKCJ5ZWxsb3ciLCAicHVycGxlIiwgImJsdWUiLCAiZ3JlZW4iLCAicmVkIiwgImJsYWNrIiwgIm9yYW5nZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGs4PWMoInBpbmsiLCAieWVsbG93IiwgInB1cnBsZSIsICJibHVlIiwgImdyZWVuIiwgInJlZCIsICJibGFjayIsICJvcmFuZ2UiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrOT1jKCJ3aGl0ZSIsICJwaW5rIiwgInllbGxvdyIsICJwdXJwbGUiLCAiYmx1ZSIsICJncmVlbiIsICJyZWQiLCAiYmxhY2siLCAib3JhbmdlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgazEwPWMoImJyb3duIiwgIndoaXRlIiwgInBpbmsiLCAieWVsbG93IiwgInB1cnBsZSIsICJibHVlIiwgImdyZWVuIiwgInJlZCIsICJibGFjayIsICJvcmFuZ2UiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdWJ0eXBlPWMoIkFUTEwiPSAnZGFya2dyYXknLCAiQUxLK0FMQ0wiPSAnY2hvY29sYXRlNCcsICJDVENMIj0gJ2NoYXJ0cmV1c2UzJywgIkFMSy1BTENMIj0gJ2NhZGV0Ymx1ZScsICJTUUdEX1RDTCI9ICdjeWFuMycsICJUX0xHTCI9ICdyZWQnLCAiTktUIj0gJ2xpZ2h0cGluaycsICJIU19UQ0wiPSAnYmxhY2snLCAiUFRDTF9OT1MiPSAnZGFya2dvbGRlbnJvZDEnLCAiTktMIj0gJ2JsdWV2aW9sZXQnKSkKICAgICAgICAgKQpgYGAKCgpTYXZlIGNlbnRlcmVkIHJsb2cgZGF0YSB3aXRoIGNsdXN0ZXJzIGFzIHRhYmxlIHdpdGggZFJFRyBwZWFrIGluZm8KYGBge3J9Cm91dCA8LSBkYXRhLmZyYW1lKHVuaXF1ZShyb3cubmFtZXM9bmFtZXMoYyhybGRfY3V0azQsYm90NWtfYWxsKSksIAogICAgICAgICAgICAgICAgICBrMj1jKHJsZF9jdXRrMixib3Q1a19hbGwpLCAKICAgICAgICAgICAgICAgICAgazM9YyhybGRfY3V0azMsYm90NWtfYWxsKSwgCiAgICAgICAgICAgICAgICAgIGs0PWMocmxkX2N1dGs0LGJvdDVrX2FsbCkKICAgICAgICAgICAgICAgICAgKSkKCm91dCA8LSBtZXJnZShwZWFrVmFyX2FsbCwgb3V0LCBieS54PSJwZWFrSUQiLCBieS55PTAsIGFsbC54PVQpCm91dCA8LSBtZXJnZShvdXQsIHNjYWxlZGF0YV9ybGRfYWxsLCBieS54PSJwZWFrSUQiLCBieS55PTAsIGFsbC54PVQpCgp3cml0ZS50YWJsZShvdXQsIGZpbGU9ImJyYW5jaHBvaW50X291dHB1dC50eHQiLCBzZXA9Ilx0IiwgY29sLm5hbWVzPVQsIHJvdy5uYW1lcz1GLCBxdW90ZT1GKQpgYGAKCkludGVncmF0ZSBuZWFyZXN0L2Fzc29jaWF0ZWQgZ2VuZSBtZXRyaWNzIHRvIG91dHB1dCBhYm92ZQpgYGB7cn0KZGlzdGFsIDwtIHJlYWQudGFibGUoIi4uL0RFU2VxL291dHB1dHMvUG9seWFrX3BhcmVudEFsbF9zMC41cDAuMDI1YzMwX3AxMDAwX20xMDAwMDAwX2Rpc3RhbF9kUkVHcGVha19jbG9zZXN0R2VuZXMudHh0IiwgaGVhZGVyPVQsIHNlcD0iXHQiKQoKcGVhazJnZW5lMSA8LSBwcm9tcHJveFssYygxLDEwLDExKV0KcGVhazJnZW5lMiA8LSBkaXN0YWxbLGMoMSwxMCwxMSldCmNvbG5hbWVzKHBlYWsyZ2VuZTIpIDwtIGNvbG5hbWVzKHBlYWsyZ2VuZTEpCnBlYWsyZ2VuZTIkZ2VuZU5hbWUgPC0gcGFzdGUwKCI9XCIiLHN1YnN0cmluZyhwZWFrMmdlbmUyJGdlbmVOYW1lLCAyKSwiXCIiKQpwZWFrMmdlbmUzIDwtIGRpc3RhbFssYygxLDIxLDIyKV0KY29sbmFtZXMocGVhazJnZW5lMykgPC0gY29sbmFtZXMocGVhazJnZW5lMSkKcGVhazJnZW5lMyRnZW5lTmFtZSA8LSBwYXN0ZTAoIj1cIiIsc3Vic3RyaW5nKHBlYWsyZ2VuZTMkZ2VuZU5hbWUsIDIpLCJcIiIpCnBlYWsyZ2VuZSA8LSByYmluZChwZWFrMmdlbmUxLHBlYWsyZ2VuZTIscGVhazJnZW5lMykKCnBlYWsyZ2VuZSA8LSBtZXJnZShwZWFrMmdlbmUsIG91dFssYygxLDE4KV0pCnBlYWsyZ2VuZSA8LSB1bmlxdWUocGVhazJnZW5lKQoKd3JpdGUudGFibGUocGVhazJnZW5lLCBmaWxlPSJicmFuY2hwb2ludF9hc3NvY19nZW5lcy50eHQiLCBzZXA9Ilx0IiwgY29sLm5hbWVzPVQsIHJvdy5uYW1lcz1GLCBxdW90ZT1GKQpgYGAKClNhdmUgUERGIHZlcnNpb25zIG9mIGZpZ3VyZXMgZm9yIE1TCmBgYHtyfQpybGRfZGYgPC0gYXMuZGF0YS5mcmFtZShzY2FsZWRhdGFfcmxkKQpybGRfZGYkazQgPC0gYXMuZGF0YS5mcmFtZShybGRfY3V0azQpJHJsZF9jdXRrNAoKcGRmKCJwbG90cy9jZW50cm9pZC5ib3hwbG90LnBkZiIpCmJveChjKHJsZF9jdXRrNCxybGRfYm90NWspLCByYmluZChzY2FsZWRhdGFfcmxkLHNjYWxlZGF0YV9ib3QpLCAiY3V0azQgKyBzdGF0aWMgW1wiY2x1c3RfNVwiXSBybG9nIikKZGV2Lm9mZigpCgpjbHVzdGVycyA8LSBybGRfY3V0azQKCmNvcmVzIDwtIHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLCBjbHVzdC5jb3JlLCBzY2FsZWRhdGFfcmxkLCBjbHVzdGVycykKI2NvcnJlbGF0ZSB0aGUgY29yZXMgdG8gdHJhaXRzOgptb2R1bGVUcmFpdENvciA9IGNvcihjb3JlcywgdHJhaXRzLCB1c2U9ICJwIikKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCBuU2FtcGxlcykKI2dlbmVyYXRlIGEgdGV4dCBtYXRyaXggb2YgdGhlIGNvcnJlbGF0aW9uIGFuZCBwdmFsdWUKdGV4dE1hdHJpeD0gcGFzdGUoc2lnbmlmKG1vZHVsZVRyYWl0Q29yLCAyKSwgIlxuKCIsCiAgICAgICAgICAgICAgICAgIHNpZ25pZihtb2R1bGVUcmFpdFB2YWx1ZSwgMSksICIpIiwgc2VwPSAiIikKZGltKHRleHRNYXRyaXgpPSBkaW0obW9kdWxlVHJhaXRDb3IpCiNwbG90IGEgaGVhdG1hcCBvZiB0aGUgY2x1c3RlcnMgYnkgdHJhaXQgb3ZlcmxheWluZyB0aGUgY29yci9wdmFsdWUKcGRmKCJwbG90cy9jbHVzdGVyLXRyYWl0LmhlYXRtYXAucGRmIikKcGFyKG9tYT1jKDEsMCwxLDEpKQpoZWF0bWFwLjIobW9kdWxlVHJhaXRDb3IsCiAgICAgICAgICBkZW5kcm9ncmFtID0gIm5vbmUiLAogICAgICAgICAgQ29sdiA9RkFMU0UsCiAgICAgICAgICBzY2FsZSA9IGMoIm5vbmUiKSwKICAgICAgICAgIGNvbD0iaGVhdC5jb2xvcnMiLAogICAgICAgICAgbmEucm09VFJVRSwKICAgICAgICAgIGNlbGxub3RlID0gdGV4dE1hdHJpeCwKICAgICAgICAgIG5vdGVjb2w9ImdyZXkzMCIsCiAgICAgICAgICBub3RlY2V4PTEsCiAgICAgICAgICB0cmFjZT1jKCJub25lIiksCiAgICAgICAgICBjZXhSb3cgPSAwLjgsCiAgICAgICAgICBjZXhDb2wgPSAwLjgsCiAgICAgICAgICBtYWluID0gIkNsdXN0ZXItVHJhaXQgQ29ycmVsYXRpb24gKGs9NCkiLAogICAgICAgICAgeGxhYiA9ICJUcmFpdHMiLAogICAgICAgICAgeWxhYiA9ICJDbHVzdGVycyIpCmRldi5vZmYoKQoKcGRmKCJwbG90cy9hY3Rpdml0eS5oZWF0bWFwLmJlcmxpbi5wZGYiKQpwaGVhdG1hcChybGRfdG9wNWtfYWxsLAogICAgICAgICAjcmxkX2RmW29yZGVyKHJsZF9kZlssMTJdKSxdWywxOjExXSwgCiAgICAgICAgICNnYXBzX3JvdyA9IGMoODc5LDIyOTgsNDIxMyksIAogICAgICAgICBjbHVzdGVyX2NvbHM9VCwgCiAgICAgICAgIGNsdXN0ZXJfcm93cz1ocl9ybGQsCiAgICAgICAgICNjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiZXVjbGlkZWFuIiwKICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kID0gImNvbXBsZXRlIiwKICAgICAgICAgc2NhbGU9InJvdyIsCiAgICAgICAgIGN1dHJlZV9yb3dzPTQsCiAgICAgICAgIGN1dHJlZV9jb2xzPTMsIAogICAgICAgICBib3JkZXJfY29sb3I9TkEsIAogICAgICAgICBzaG93X3Jvd25hbWVzPUYsIAogICAgICAgICBtYWluPSJUb3AgNWsgZFJFRyBQZWFrIFBDQSBDb250cmlidXRvcnMgSGllcmFyY2hpY2FsIiwKICAgICAgICAgYnJlYWtzPXNlcSgtMiwyLGJ5PTAuMDEpLAogICAgICAgICBjb2xvcj1zY2ljbyg0MDEsIHBhbGV0dGUgPSAnYmVybGluJyksCiAgICAgICAgICNjb2xvcj1jb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDQxKSwKICAgICAgICAgYW5ub3RhdGlvbl9yb3c9cmxkX2RmWzEyXSwgCiAgICAgICAgIGFubm90YXRpb25fY29sPWRhdGEuZnJhbWUocm93Lm5hbWVzPWNvbG5hbWVzKHJsZF9kZlssMToxMV0pLCBTdWJ0eXBlID0gc3ViVHlwZXNfYWxsKSwgCiAgICAgICAgIGFubm90YXRpb25fY29sb3JzPWxpc3QoazQ9YygicHVycGxlIiwgImJsdWUiLCAiZ3JlZW4iLCAiZ29sZGVucm9kMSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdWJ0eXBlPWMoIk1lc2VuY2h5bWFsIj0nZ3JlZW4nLCAiQmFzYWwiPSdyZWQnLCAiTHVtaW5hbCI9J2JsdWUnKSkKICAgICAgICAgKQpkZXYub2ZmKCkKCnBkZigicGxvdHMvYWN0aXZpdHkuaGVhdG1hcC5vY2Vhbi5wZGYiKQpwaGVhdG1hcChybGRfdG9wNWtfYWxsLAogICAgICAgICAjcmxkX2RmW29yZGVyKHJsZF9kZlssMTJdKSxdWywxOjExXSwgCiAgICAgICAgICNnYXBzX3JvdyA9IGMoODc5LDIyOTgsNDIxMyksIAogICAgICAgICBjbHVzdGVyX2NvbHM9VCwgCiAgICAgICAgIGNsdXN0ZXJfcm93cz1ocl9ybGQsCiAgICAgICAgICNjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiZXVjbGlkZWFuIiwKICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kID0gImNvbXBsZXRlIiwKICAgICAgICAgc2NhbGU9InJvdyIsCiAgICAgICAgIGN1dHJlZV9yb3dzPTQsCiAgICAgICAgIGN1dHJlZV9jb2xzPTMsIAogICAgICAgICBib3JkZXJfY29sb3I9TkEsIAogICAgICAgICBzaG93X3Jvd25hbWVzPUYsIAogICAgICAgICBtYWluPSJUb3AgNWsgZFJFRyBQZWFrIFBDQSBDb250cmlidXRvcnMgSGllcmFyY2hpY2FsIiwKICAgICAgICAgYnJlYWtzPXNlcSgtMiwyLGJ5PTAuMDEpLAogICAgICAgICBjb2xvcj1vY2Vhbi5iYWxhbmNlKDQwMSksCiAgICAgICAgIGFubm90YXRpb25fcm93PXJsZF9kZlsxMl0sIAogICAgICAgICBhbm5vdGF0aW9uX2NvbD1kYXRhLmZyYW1lKHJvdy5uYW1lcz1jb2xuYW1lcyhybGRfZGZbLDE6MTFdKSwgU3VidHlwZSA9IHN1YlR5cGVzX2FsbCksIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycz1saXN0KGs0PWMoInB1cnBsZSIsICJibHVlIiwgImdyZWVuIiwgImdvbGRlbnJvZDEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3VidHlwZT1jKCJNZXNlbmNoeW1hbCI9J2dyZWVuJywgIkJhc2FsIj0ncmVkJywgIkx1bWluYWwiPSdibHVlJykpCiAgICAgICAgICkKZGV2Lm9mZigpCmBgYAoKCiMjIyMjTm93IGZvciBwcm90ZWluLWNvZGluZyBnZW5lcyMjIyMjICMjUmVydW4gb24gMTAvMjEvMjEKCkNhbiB3ZSBnZXQgc2ltaWxhciBzYW1wbGUgY2x1c3RlcmluZyB3aXRoIGRvbWluYW50IHRyYW5zY3JpcHQgZ2VuZXMgb3IgZG8gd2Ugc3RpbGwgaGF2ZSBwb29yIHNlcGFyYXRpb24gb2YgdGhlIHN1YnR5cGVzIGFzIHNlZW4gYmVmb3JlPwoKTG9hZCBkZHMgYW5kIGdlbmVyYXRlIG90aGVyIGRhdGEgdGFibGVzCmBgYHtyfQpkZHNfZG9tVHJhbnMgPC0gcmVhZFJEUygiLi4vREVTZXEvUkRhdGEvcG9seWFrQWxsX2Rkc19kb21UcmFucy5yZHMiKQoKY29sbmFtZXMoZGRzX2RvbVRyYW5zKSA8LSBwYXN0ZTAoc2FtcGxlTmFtZXNfYWxsLCIoIixzdWJUeXBlc19hbGwsIikiKSAjc3dhcCBzYW1wbGUgbmFtZXMKZGRzX2RvbVRyYW5zJHNhbXBsZSA8LSBzYW1wbGVOYW1lc19hbGwgI3N3YXAgc2FtcGxlIG5hbWVzIGluIG1ldGFkYXRhCmRkc19kb21UcmFucyR0eXBlIDwtIHN1YlR5cGVzX2FsbCAjc3dhcCBzYW1wbGUgdHlwZXMgaW4gbWV0YWRhdGEKcmxkX2RvbVRyYW5zIDwtIHJsb2coZGRzX2RvbVRyYW5zLCBibGluZD1UUlVFKQojY29sbmFtZXMocmxkX2RvbVRyYW5zKSA8LSBwYXN0ZTAoc2FtcGxlTmFtZXNfYWxsLCIoIixzdWJUeXBlc19hbGwsIikiKQpzYW1wbGVEaXN0c19kb21UcmFucyA8LSBkaXN0KHQoYXNzYXkocmxkX2RvbVRyYW5zKSkpCnNhbXBsZURpc3RNdHhfZG9tVHJhbnMgPC0gYXMubWF0cml4KHNhbXBsZURpc3RzX2RvbVRyYW5zKQpyb3duYW1lcyhzYW1wbGVEaXN0TXR4X2RvbVRyYW5zKSA8LSBwYXN0ZTAocmxkX2RvbVRyYW5zJHNhbXBsZSwiXyIscmxkX2RvbVRyYW5zJHR5cGUpCmNvbG5hbWVzKHNhbXBsZURpc3RNdHhfZG9tVHJhbnMpIDwtIE5VTEwKaGNsdXN0X2RvbVRyYW5zIDwtIGhjbHVzdChzYW1wbGVEaXN0c19kb21UcmFucykKYGBgCgpEbyBpbml0aWFsIGRlbmRyb2dyYW1zIGFuZCBkZXRlcm1pbmUgUENBIGNvbnRyaWJ1dG9ycwpgYGB7cn0KcGxvdFBDQShybGRfZG9tVHJhbnMsIGludGdyb3VwPSJ0eXBlIikgCnBsb3RQQ0EocmxkX2RvbVRyYW5zLCBpbnRncm91cD0ic2FtcGxlIikKcGRmKCJwbG90cy9kb21UcmFuc19oY2x1c3Quc2FtcGxlLnBkZiIpCnBsb3QoaGNsdXN0X2RvbVRyYW5zLCBsYWJlbHM9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9kb21UcmFucyksIG1haW49IlBSTy1zZXEgRG9taW5hbnQgVHJhbnNjcmlwdCBEZW5kcm9ncmFtIikKZGV2Lm9mZigpCnBsb3QoaGNsdXN0X2RvbVRyYW5zLCBsYWJlbHM9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9kb21UcmFucyksIG1haW49IlBSTy1zZXEgRG9taW5hbnQgVHJhbnNjcmlwdCBEZW5kcm9ncmFtIikKYGBgCgpUcnkgUENBIGF0IGRpZmZlcmVudCBkZXB0aHMKYGBge3J9CiAgcGxvdFBDQShybGRfZG9tVHJhbnMsIGludGdyb3VwPSJ0eXBlIiwgbnRvcD0xMDApICsgZ2d0aXRsZSgiVG9wIDEwMCIpCiAgcGxvdFBDQShybGRfZG9tVHJhbnMsIGludGdyb3VwPSJ0eXBlIiwgbnRvcD0yMDApICsgZ2d0aXRsZSgiVG9wIDIwMCIpCiAgcGxvdFBDQShybGRfZG9tVHJhbnMsIGludGdyb3VwPSJ0eXBlIiwgbnRvcD01MDApICsgZ2d0aXRsZSgiVG9wIDUwMCIpCiAgcGxvdFBDQShybGRfZG9tVHJhbnMsIGludGdyb3VwPSJ0eXBlIiwgbnRvcD0xMDAwKSArIGdndGl0bGUoIlRvcCAxMDAwIikKICBwbG90UENBKHJsZF9kb21UcmFucywgaW50Z3JvdXA9InR5cGUiLCBudG9wPTIwMDApICsgZ2d0aXRsZSgiVG9wIDIwMDAiKQogIHBsb3RQQ0EocmxkX2RvbVRyYW5zLCBpbnRncm91cD0idHlwZSIsIG50b3A9NTAwMCkgKyBnZ3RpdGxlKCJUb3AgNTAwMCIpCiAgcGxvdFBDQShybGRfZG9tVHJhbnMsIGludGdyb3VwPSJ0eXBlIiwgbnRvcD0xMDAwMCkgKyBnZ3RpdGxlKCJUb3AgMTAwMDAiKQogIHBsb3RQQ0EocmxkX2RvbVRyYW5zLCBpbnRncm91cD0idHlwZSIsIG50b3A9MjAwMDApICsgZ2d0aXRsZSgiVG9wIDIwMDAwIikKICBwbG90UENBKHJsZF9kb21UcmFucywgaW50Z3JvdXA9InR5cGUiLCBudG9wPTMyMzc1KSArIGdndGl0bGUoIkFsbCIpCmBgYApNYXggc2VwYXJhdGlvbiB+NTAwIHRvcCB2YXJpYW5jZSBnZW5lcy4uIGluIGxpbmUgd2l0aCBleHBlY3RhdGlvbnMuIFBvb3Igc2VwYXJhdGlvbiBvZiBtZXNlbmNoeW1hbCBmcm9tIGx1bWluYWwgYXMgcmVmbGVjdGVkIGluIGRlbmRyb2dyYW0uCgpSYW5rIGdlbmVzIGJ5IFBDQSBjb250cmlidXRpb24gYW5kIG1lYXN1cmUgdmFyaWFuY2UgYW5kIGN1bXVsYXRpdmUgdmFyaWFuY2UKYGBge3J9CiNEZWZpbmUgYW5kIHJhbmsgdG9wIFBDQSBjb250cmlidXRvcnMKcnYgPC0gcm93VmFycyhhc3NheShybGRfZG9tVHJhbnMpKSAKc2VsZWN0IDwtIG9yZGVyKHJ2LCBkZWNyZWFzaW5nPVRSVUUpCnBjIDwtIHByY29tcCh0KGFzc2F5KHJsZF9kb21UcmFucylbc2VsZWN0LF0pKQpsb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjJHJvdGF0aW9uKQphbG9hZCA8LSBhYnMobG9hZGluZ3MpCnBjUmFua19kb21UcmFucyA8LSBkYXRhLmZyYW1lKCJnZW5lSUQiPXJvd25hbWVzKGxvYWRpbmdzKSwgIlBDQS5yYW5rIj1zZXEuaW50KG5yb3cobG9hZGluZ3MpKSkKc3dlZXAoYWxvYWQsIDIsIGNvbFN1bXMoYWxvYWQpLCAiLyIpCiMjI2NsZWFuIHVwIHZhcmlhYmxlcwpybShydikKcm0oc2VsZWN0KQpybShwYykKcm0obG9hZGluZ3MpCgojR2VuZXJhdGUgbGlzdCBvZiBnZW5lcwpnZW5lVmFyIDwtIGRhdGEuZnJhbWUoImdlbmVJRCI9cm93bmFtZXMoYXNzYXkocmxkX2RvbVRyYW5zKSkpCmdlbmVWYXIkcmxvZy52YXJpYW5jZSA8LSByb3dWYXJzKGFzLm1hdHJpeChhc3NheShybGRfZG9tVHJhbnMpKSkKZ2VuZVZhciA8LSBtZXJnZShwY1JhbmtfZG9tVHJhbnMsIGdlbmVWYXIsIGJ5Lng9ImdlbmVJRCIsIGJ5Lnk9ImdlbmVJRCIpCmdncGxvdChnZW5lVmFyLCBhZXMoeD1QQ0EucmFuaywgeT1ybG9nLnZhcmlhbmNlKSkgKyBnZW9tX2xpbmUoKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKDUwMCwxMDAwLDIwMDAsNTAwMCwxMDAwMCksIGxpbmV0eXBlPSJkb3R0ZWQiKQoKI2FkZCBwbG90IG9mIGZyYWN0aW9uIG9mIGV4cGxhaW5lZCB2YXJpYW5jZS4uIHJ1bm5pbmcgc3VtIC8gdG90YWwgdnMgcmFuawpnZW5lVmFyIDwtIGdlbmVWYXJbb3JkZXIoZ2VuZVZhciRQQ0EucmFuayksXQpnZW5lVmFyJGN1bXVsYXRpdmUuVmFyaWFuY2UgPC0gY3Vtc3VtKGdlbmVWYXIkcmxvZy52YXJpYW5jZSkvc3VtKGdlbmVWYXIkcmxvZy52YXJpYW5jZSkKZ2dwbG90KGdlbmVWYXIsIGFlcyh4PVBDQS5yYW5rLCB5PWN1bXVsYXRpdmUuVmFyaWFuY2UpKSArIGdlb21fbGluZSgpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoNTAwLDEwMDAsMjAwMCw1MDAwLDEwMDAwKSwgbGluZXR5cGU9ImRvdHRlZCIpCmBgYApSZXN1bHRzOgpDdXRvZmYgICAgcmxvZyB2YXJpYW5jZSAgIGN1bXVsYXRpdmUgdmFyaWFuY2UKNTAwICAgICAgIDMuOTE1MDQgICAgICAgICAxMy4zJQoxayAgICAgICAgMy4wNjUzNSAgICAgICAgIDIyLjElCjJrICAgICAgICAyLjIwOTAxOCAgICAgICAgMzUuNCUKNWsgICAgICAgIDEuMTYxMTE1ICAgICAgICA1OS44JQoxMGsgICAgICAgMC41MjcxMDYzICAgICAgIDc5LjglCjIwayAgICAgICAwLjE3ODYwNjcgICAgICAgOTUuOCUKYWxsICAgICAgIDAgICAgICAgICAgICAgICAxMDAlCgojQ29tcGxldGVkIHJlLWFuYWx5c2lzIHdpdGggY29ycmVjdGVkIHN1YnR5cGVzIGFuZCBjb2xvcnMgb24gMTAvMjEvMjEgQUYKCgoKIyMjIyNUcnkgdGhpcyBsYXRlci4uLiAgI3NraXBwZWQgMTAvMjEvMjEKRm9yIHRlc3QgYW5kIGFsbCBzZXRzIG9mIGNlbGwgbGluZXMsIHNlZSB3aGljaCBjbHVzdGVyaW5nIG1ldGhvZCBpcyBiZXN0IGF0IHNlcGFyYXRpbmcgaz0zCmBgYHtyfQpnZXRfb3JkZXJlZF8zX2NsdXN0ZXJzIDwtIGZ1bmN0aW9uKGRlbmQpIHsKICAgY3V0cmVlKGRlbmQsIGsgPSAzKVtvcmRlci5kZW5kcm9ncmFtKGRlbmQpXQp9CgpkZW5kXzNfY2x1c3RlcnMgPC0gbGFwcGx5KGlyaXNfZGVuZGxpc3QsIGdldF9vcmRlcmVkXzNfY2x1c3RlcnMpCgpjb21wYXJlX2NsdXN0ZXJzX3RvX2lyaXMgPC0gZnVuY3Rpb24oY2x1cykge0ZNX2luZGV4KGNsdXMsIHJlcCgxOjMsIGVhY2ggPSA1MCksIGFzc3VtZV9zb3J0ZWRfdmVjdG9ycyA9IFRSVUUpfQoKY2x1c3RlcnNfcGVyZm9ybWFuY2UgPC0gc2FwcGx5KGRlbmRfM19jbHVzdGVycywgY29tcGFyZV9jbHVzdGVyc190b19pcmlzKQpkb3RjaGFydChzb3J0KGNsdXN0ZXJzX3BlcmZvcm1hbmNlKSwgeGxpbSA9IGMoMC43LDEpLAogICAgICAgICB4bGFiID0gIkZvd2xrZXMtTWFsbG93cyBJbmRleCAoZnJvbSAwIHRvIDEpIiwKICAgICAgICAgbWFpbiA9ICJQZXJvcm1hbmNlIG9mIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcyBcbiBpbiBkZXRlY3RpbmcgdGhlIDMgc3BlY2llcyIsCiAgICAgICAgIHBjaCA9IDE5KQpgYGAKCiMjIyNEb24ndCB0aGluayB0aGlzIGlzIG5lZWRlZCBoZXJlLi4uICNza2lwcGVkIDEwLzIxLzIxCkhlaWdodCBCcmFuY2ggQ3V0dGluZyBUZXN0CmBgYHtyfQpybGRfY3V0aDEuNSA8LSBjdXRyZWUoaHIsaD0xLjUpCnJsZF9jdXRoMS42IDwtIGN1dHJlZShocixoPTEuNikKcmxkX2N1dGgxLjcgPC0gY3V0cmVlKGhyLGg9MS43KQoKcGxvdChUcmVlUiwKICAgICBsZWFmbGFiID0gIm5vbmUiLAogICAgIG1haW4gPSAiR2VuZSBDbHVzdGVyaW5nIiwKICAgICB5bGFiID0gIkhlaWdodCIpCnRoZV9iYXJzMiA8LSBjYmluZChjdXRoMS41LCBjdXRoMS42LCBjdXRoMS43LCBjdXRoMS44LCBjdXRoMS44NSwgY3V0aDEuOSkKY29sb3JlZF9iYXJzKHRoZV9iYXJzMiwgVHJlZVIsIHNvcnRfYnlfbGFiZWxzX29yZGVyID0gVCwgeV9zaGlmdD0tMC4xLCByb3dMYWJlbHMgPSBjKCJoPTEuNSIsImg9MS42IiwiaD0xLjciLCJoPTEuOCIsICJoPTEuODUiLCAiaD0xLjkiKSxjZXgucm93TGFiZWxzPTAuNykKCiN0aGlzIHdpbGwgYWRkIGxpbmVzIHNob3dpbmcgdGhlIGN1dCBoZWlnaHRzCmFibGluZShoPTEuNSwgbHR5ID0gMiwgY29sPSJncmV5IikKYWJsaW5lKGg9MS42LCBsdHkgPSAyLCBjb2w9ImdyZXkiKQphYmxpbmUoaD0xLjcsIGx0eSA9IDIsIGNvbD0iZ3JleSIpCmFibGluZShoPTEuOCwgbHR5ID0gMiwgY29sPSJncmV5IikKYWJsaW5lKGg9MS44NSwgbHR5ID0gMiwgY29sPSJncmV5IikKYWJsaW5lKGg9MS45LCBsdHkgPSAyLCBjb2w9ImdyZXkiKQpgYGA=