Document creation Libraries
library(DESeq2)
library(Rsubread)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ tibble 3.1.4 ✓ purrr 0.3.4
✓ tidyr 1.1.3 ✓ stringr 1.4.0
✓ readr 2.0.1 ✓ forcats 0.5.1
── Conflicts ───────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::collapse() masks IRanges::collapse()
x gridExtra::combine() masks dplyr::combine(), Biobase::combine(), BiocGenerics::combine()
x dplyr::count() masks matrixStats::count()
x dplyr::desc() masks IRanges::desc()
x tidyr::expand() masks S4Vectors::expand()
x plotly::filter() masks dplyr::filter(), stats::filter()
x dplyr::first() masks S4Vectors::first()
x dplyr::lag() masks stats::lag()
x ggplot2::Position() masks BiocGenerics::Position(), base::Position()
x purrr::reduce() masks GenomicRanges::reduce(), IRanges::reduce()
x plotly::rename() masks dplyr::rename(), S4Vectors::rename()
x plotly::slice() masks dplyr::slice(), IRanges::slice()
library(pheatmap)
library(RColorBrewer)
library(ggplot2)
library(ggrepel)
library(ggpubr)
Attaching package: ‘ggpubr’
The following object is masked from ‘package:dendextend’:
rotate
library(cluster)
library(factoextra)
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(amap)
library(NbClust)
library(dplyr)
Set working directory to local workspace Save R markup, featurecounts results and full gtf there RNA featurecounts generated with ‘Homo_sapiens.GRCh38.99.gtf.gz’ file
setwd("/Users/kuroko/Dropbox (Partners HealthCare)/Weinstock NTC Collab/Experiments/TCL Cell Lines/Data/25 TCLs/MKJ R scripts")
getwd()
[1] "/Users/kuroko/Dropbox (Partners HealthCare)/Weinstock NTC Collab/Experiments/TCL Cell Lines/Data/25 TCLs/MKJ R scripts"
RNA
Load featurecounts results, configure as data frame object Setup metadata information and check naming consistency Remove non-counts columns in fc object
fc <- read.table("WholeGeneCounts_Weinstock002_RNA", sep="\t", header=TRUE, row.names=1)
fc2 <- as.data.frame(fc)
orig_names <- colnames(fc2[6:30])
colData_rna <- data.frame(row.names=orig_names, sample=c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2"), subtype=c("HS_TCL", "ALK-ALCL", "ALK-ALCL", "CTCL", "CTCL", "ATLL", "ALK+ALCL", "SQGD_TCL", "NKL", "ALK+ALCL", "ALK+ALCL", "ALK-ALCL", "CTCL", "T_LGL", "NKT", "CTCL", "NKT", "PTCL_NOS", "CTCL", "PTCL_NOS", "ALK+ALCL", "ATLL", "ATLL", "ALK+ALCL", "ALK+ALCL"))
all(rownames(colData_rna) %in% colnames(fc2))
[1] TRUE
fc3 <- subset(fc2, select=-c(Chr, Start, End, Strand, Length))
colnames(fc3) <- c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2")
Create DEseq object and save file Generate normalization factor with DEseq default
dds_rna <- DESeqDataSetFromMatrix(countData=fc3, colData=colData_rna, design=~sample)
Warning in DESeqDataSet(se, design = design, ignoreRank) :
some variables in design formula are characters, converting to factors
dds_rna <- estimateSizeFactors(dds_rna)
deseq_sizes_rna <- as.data.frame(sizeFactors(dds_rna))
row.names(deseq_sizes_rna) <- c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2")
deseq_sizes_rna
saveRDS(dds_rna, file="RNA_dds.rds")
Generate norm counts files and save to local directory
rawcounts_rna <- as.data.frame(counts(dds_rna, normalized=FALSE))
normcounts_rna <- as.data.frame(counts(dds_rna, normalized=TRUE))
colnames(rawcounts_rna) <- c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2")
colnames(normcounts_rna) <- c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2")
rownames(rawcounts_rna) <- sapply(strsplit(rownames(rawcounts_rna), split="[.]"), head, 1)
rownames(normcounts_rna) <- sapply(strsplit(rownames(normcounts_rna), split="[.]"), head, 1)
write.table(rawcounts_rna, file="RNA_rawcounts.txt", sep="\t", col.names=TRUE, row.names=TRUE, quote=FALSE)
write.table(normcounts_rna, file="RNA_normcounts.txt", sep="\t", col.names=TRUE, row.names=TRUE, quote=FALSE)
Data transformation for plot generation Top 500 contributors is the default for PCA Set ‘ntop’ to number of observations in the dds object
rld_rna <- rlog(dds_rna, blind=TRUE)
sampleDistsrna <- dist(t(assay(rld_rna)))
sampleDistMtxrna <- as.matrix(sampleDistsrna)
rownames(sampleDistMtxrna) <- paste0(rld_rna$sample)
colnames(sampleDistMtxrna) <- NULL
#Generate PCA plot (intgroup set equal to desired metadata variable)
plotPCA(rld_rna, intgroup = "subtype", ntop=60676) + ggtitle("RNA-seq PCA") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxrna), max.overlaps=50)

#top 500 PCA
plotPCA(rld_rna, intgroup = "subtype") + ggtitle("RNA-seq PCA Top 500") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxrna), max.overlaps=50)

#top 1000
plotPCA(rld_rna, intgroup = "subtype", ntop=1000) + ggtitle("RNA-seq PCA Top 1000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxrna), max.overlaps=50)

#top 5000
plotPCA(rld_rna, intgroup = "subtype", ntop=5000) + ggtitle("RNA-seq PCA Top 5000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxrna), max.overlaps=50)

#top 10000
plotPCA(rld_rna, intgroup = "subtype", ntop=10000) + ggtitle("RNA-seq PCA Top 10000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxrna), max.overlaps=50)

#top 15000
plotPCA(rld_rna, intgroup = "subtype", ntop=15000) + ggtitle("RNA-seq PCA Top 15000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxrna), max.overlaps=50)

Additional dendrogram plots
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255)
pheatmap(sampleDistMtxrna, col=colors, border_color=NA, show_colnames=FALSE, show_rownames=TRUE,
cluster_rows=TRUE, cluster_cols=TRUE, main="RNA Sample Distance Clustering")

plot(hclust(sampleDistsrna), labels=rownames(sampleDistMtxrna), main="RNA Sample Distance Dendrogram")

Assemble counts results
avg_rna <- data.frame(EnsemblID=rownames(normcounts_rna))
avg_rna$DERL2 <- (normcounts_rna$DERL2)
avg_rna$DL40 <- (normcounts_rna$DL40)
avg_rna$FEPD <- (normcounts_rna$FEPD)
avg_rna$HH <- (normcounts_rna$HH)
avg_rna$HUT78 <- (normcounts_rna$HUT78)
avg_rna$HUT102 <- (normcounts_rna$HUT102)
avg_rna$KARPAS299 <- (normcounts_rna$KARPAS299)
avg_rna$KARPAS384 <- (normcounts_rna$KARPAS384)
avg_rna$KHYG1 <- (normcounts_rna$KHYG1)
avg_rna$KIJK <- (normcounts_rna$KIJK)
avg_rna$L82 <- (normcounts_rna$L82)
avg_rna$MAC2A <- (normcounts_rna$MAC2A)
avg_rna$MJ <- (normcounts_rna$MJ)
avg_rna$MOTN1 <- (normcounts_rna$MOTN1)
avg_rna$MTA <- (normcounts_rna$MTA)
avg_rna$MYLA <- (normcounts_rna$MYLA)
avg_rna$NKL <- (normcounts_rna$NKL)
avg_rna$OCILY12 <- (normcounts_rna$OCILY12)
avg_rna$SeAx <- (normcounts_rna$SeAx)
avg_rna$SMZ1 <- (normcounts_rna$SMZ1)
avg_rna$SR786 <- (normcounts_rna$SR786)
avg_rna$ST1 <- (normcounts_rna$ST1)
avg_rna$Su9T01 <- (normcounts_rna$Su9T01)
avg_rna$SUDHL1 <- (normcounts_rna$SUDHL1)
avg_rna$SUPM2 <- (normcounts_rna$SUPM2)
avg_rna$max <- apply(avg_rna[c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2")], 1, max, na.rm=TRUE)
rel_rna <- data.frame(EnsemblID=avg_rna$EnsemblID)
rel_rna$DERL2 <- avg_rna$DERL2 / avg_rna$max
rel_rna$DL40 <- avg_rna$DL40 / avg_rna$max
rel_rna$FEPD <- avg_rna$FEPD / avg_rna$max
rel_rna$HH <- avg_rna$HH / avg_rna$max
rel_rna$HUT78 <- avg_rna$HUT78 / avg_rna$max
rel_rna$HUT102 <- avg_rna$HUT102 / avg_rna$max
rel_rna$KARPAS299 <- avg_rna$KARPAS299 / avg_rna$max
rel_rna$KARPAS384 <- avg_rna$KARPAS384 / avg_rna$max
rel_rna$KHYG1 <- avg_rna$KHYG1 / avg_rna$max
rel_rna$KIJK <- avg_rna$KIJK / avg_rna$max
rel_rna$L82 <- avg_rna$L82 / avg_rna$max
rel_rna$MAC2A <- avg_rna$MAC2A / avg_rna$max
rel_rna$MJ <- avg_rna$MJ / avg_rna$max
rel_rna$MOTN1 <- avg_rna$MOTN1 / avg_rna$max
rel_rna$MTA <- avg_rna$MTA / avg_rna$max
rel_rna$MYLA <- avg_rna$MYLA / avg_rna$max
rel_rna$NKL <- avg_rna$NKL / avg_rna$max
rel_rna$OCILY12 <- avg_rna$OCILY12 / avg_rna$max
rel_rna$SeAx <- avg_rna$SeAx / avg_rna$max
rel_rna$SMZ1 <- avg_rna$SMZ1 / avg_rna$max
rel_rna$SR786 <- avg_rna$SR786 / avg_rna$max
rel_rna$ST1 <- avg_rna$ST1 / avg_rna$max
rel_rna$Su9T01 <- avg_rna$Su9T01 / avg_rna$max
rel_rna$SUDHL1 <- avg_rna$SUDHL1 / avg_rna$max
rel_rna$SUPM2 <- avg_rna$SUPM2 / avg_rna$max
Data transform for variance assessment and sub-clustering
rv1 <- rowVars(assay(rld_rna))
select1 <- order(rv1, decreasing=TRUE)
pc1 <- prcomp(t(assay(rld_rna)[select1,]))
loadings1 <- as.data.frame(pc1$rotation)
aload1 <- abs(loadings1)
pcRank <- data.frame("EnsemblID"=rownames(loadings1), "PCA.rank"=seq.int(nrow(loadings1)))
sweep(aload1, 2, colSums(aload1), "/")
peakVar <- data.frame("EnsemblID"=rownames(assay(rld_rna)))
peakVar$rlog.variance <- rowVars(as.matrix(assay(rld_rna)))
peakVar <- merge(pcRank, peakVar, by.x="EnsemblID", by.y="EnsemblID")
ggplot(peakVar, aes(x=PCA.rank, y=rlog.variance)) + geom_line() + geom_vline(xintercept=c(500,1000,2000,5000,10000,10000,15000), linetype="dotted") + ggtitle("Variance per PC Contributor")

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

Removing Alk+ALCL to determine if PCA separation improves
dds_sub <- dds_rna[,-c(7,10,11,21,24,25)] #Excluding sample numbers of the ALK+ALCL
estimateSizeFactors(dds_sub) #Must re-calculate size factors after removing samples
class: DESeqDataSet
dim: 60676 19
metadata(1): version
assays(1): counts
rownames(60676): ENSG00000223972 ENSG00000227232 ... ENSG00000277475 ENSG00000268674
rowData names(0):
colnames(19):
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.DERL2.chrM.removed.bam
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.DL40.chrM.removed.bam ...
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.STI.chrM.removed.bam
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.Su9T01.chrM.removed.bam
colData names(3): sample subtype sizeFactor
dds_sub
class: DESeqDataSet
dim: 60676 19
metadata(1): version
assays(1): counts
rownames(60676): ENSG00000223972 ENSG00000227232 ... ENSG00000277475 ENSG00000268674
rowData names(0):
colnames(19):
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.DERL2.chrM.removed.bam
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.DL40.chrM.removed.bam ...
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.STI.chrM.removed.bam
X.n.scratch3.users.m.mkj13.RNA.mapping.Dedup.Mitoremoved.Su9T01.chrM.removed.bam
colData names(3): sample subtype sizeFactor
rld_sub <- rlog(dds_sub, blind=TRUE)
colnames(rld_sub) <- paste0(dds_sub$sample)
sampleDists_sub <- dist(t(assay(rld_sub)))
sampleDistMtx_sub <- as.matrix(sampleDists_sub)
rownames(sampleDistMtx_sub) <- colnames(rld_sub)
colnames(sampleDistMtx_sub) <- NULL
hclust_sub <- hclust(sampleDists_sub)
plot(hclust_sub, labels=rownames(sampleDistMtx_sub), main="RNA-seq subset Gene Dendrogram")

PCAs
plotPCA(rld_sub, intgroup = "subtype") + ggtitle("RNA-seq subset PCA Top 500") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=1000) + ggtitle("RNA-seq subset PCA Top 1000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=5000) + ggtitle("RNA-seq subset PCA Top 5000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=10000) + ggtitle("RNA-seq subset PCA Top 10000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=15000) + ggtitle("RNA-seq subset PCA Top 15000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=60676) + ggtitle("RNA-seq subset PCA All Contributors") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

PCA top contributors selection (5K to 20K)
rv <- rowVars(assay(rld_rna))
select <- order(rv, decreasing=TRUE)[seq_len(min(10000, length(rv)))]
#Changing the 10000 here will select a Different number of top contributors if desired
pc <- prcomp(t(assay(rld_rna)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
write.table(sweep(aload, 2, colSums(aload), "/"), file="Top 10000 RNA PCA Contributors.txt")
#Clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Merge top 10000 elements with their annotations
top10000 <- rel_rna[(rel_rna$EnsemblID %in% rownames(aload)),]
write.table(top10000, file="Top10000.txt", sep='\t')
RNA_rel <- rel_rna[(rel_rna$EnsemblID %in% top10000$EnsemblID),]
saveRDS(RNA_rel, file="RNA_rel.rds")
colnames(RNA_rel) <- c("EnsemblID", "DERL2.gene", "DL40.gene", "FEPD.gene", "HH.gene", "HUT78.gene", "HUT102.gene", "KARPAS299.gene", "KARPAS384.gene", "KHYG1.gene", "KIJK.gene", "L82.gene", "MAC2A.gene", "MJ.gene", "MOTN1.gene", "MTA.gene", "MYLA.gene", "NKL.gene", "OCILY12.gene", "SeAx.gene", "SMZ1.gene", "SR786.gene", "ST1.gene", "Su9T01.gene", "SUDHL1.gene", "SUPM2.gene")
head(top10000)
head(RNA_rel)
#Gap Stat Calculation
#set.seed(42)
#This sets the random number generator seed so it will always produce the same result. You can pick whatever number you'd like.
#gap_stat <- clusGap(RNA_rel[2:26], FUN = kmeans, nstart = 20, K.max = 24, B = 50)
#... = number of samples + 1
#Cluster Stat Plots
#fviz_nbclust(top10000[2:26], kmeans, method="wss", k.max=24) + theme_minimal() + ggtitle("Elbow Plot")
#fviz_gap_stat(gap_stat) + theme_minimal() + ggtitle("Gap Statistic")
#fviz_nbclust(top10000[2:26], kmeans, method="silhouette", k.max=24) + theme_minimal() + ggtitle("Silhouette Plot")
#k-means Clustering
CLARAk20 <- clara(top10000[2:26],20,medoids.x=TRUE)
CLARAk26 <- clara(top10000[2:26],26,medoids.x=TRUE)
CLARAk30 <- clara(top10000[2:26],30,medoids.x=TRUE)
CLARAk36 <- clara(top10000[2:26],36,medoids.x=TRUE)
CLARAk15 <- clara(top10000[2:26],15,medoids.x=TRUE)
CLARAk25 <- clara(top10000[2:26],25,medoids.x=TRUE)
CLARAk22 <- clara(top10000[2:26],22,medoids.x=TRUE)
top10000$k20 <- CLARAk20$clustering
top10000$k26 <- CLARAk26$clustering
top10000$k30 <- CLARAk30$clustering
top10000$k36 <- CLARAk36$clustering
top10000$k15 <- CLARAk15$clustering
top10000$k15 <- CLARAk15$clustering
top10000$k25 <- CLARAk25$clustering
top10000$k22 <- CLARAk22$clustering
#Displaying Heatmaps
#k-means 20
pheatmap(top10000[order(top10000[, 26+1]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+1])

#k-means 26
pheatmap(top10000[order(top10000[, 26+2]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+2])

#k-means 30
pheatmap(top10000[order(top10000[, 26+3]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+3])

#k-means 36
pheatmap(top10000[order(top10000[, 26+4]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+4])

#k-means 15
pheatmap(top10000[order(top10000[, 26+5]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+5])

#k-means 25
pheatmap(top10000[order(top10000[, 26+6]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+6])

#k-means 22
pheatmap(top10000[order(top10000[, 26+7]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10000[26+7])

–RNA END–
PRO
#Prepare dREG peak saf for featureCounts
dREG <- read.table("TCLs_s0.5p0.025_filtered.bed")
colnames(dREG) <- c("chromosome", "start", "end", "dREGpeakID", "dREGscore", "strand", "centerStart",
"centerEnd")
write.table(dREG, file="dREG readtable.txt", sep="\t", quote=F, row.names=F)
dREGsaf <- data.frame("GeneID"=dREG$dREGpeakID, "Chr"=dREG$chromosome, "Start"=dREG$start, "End"=dREG$end, "Strand"="+")
write.table(dREGsaf, file="dREG.saf", sep="\t", quote=F, row.names=F)
#Load sample SAM file list
#profiles <- c("")
#Run feautreCounts
#fc_dREG <- featureCounts(profiles, annot.ext=dREGsaf, isGTFAnnotationFile=FALSE, minMQS=10, countChimericFragments=FALSE, isPairedEnd=FALSE, strandSpecific=0, nthreads=8)
fc_pro <- read.table("dREGCounts_Weinstock002_pro", header=T, row.names=1)
fc_pro <- as.data.frame(fc_pro)
fc_pro <- subset(fc_pro, select=-c(Chr, Start, End, Strand, Length))
colnames(fc_pro) <- c("HUT102", "ST1", "Su9T01", "KARPAS299", "L82", "SUPM2", "SMZ1", "MYLA", "MAC2A", "KIJK", "SR786", "FEPD", "KARPAS384", "DL40", "OCILY12", "HUT78", "HH", "MJ", "MTA", "MOTN1", "NKL", "DERL2", "KHYG1", "SeAx", "SUDHL1")
#Load sample metadata (can add as much sample metadata as desired including cell type, drug treatment, etc)
colData_pro <- data.frame(row.names=colnames(fc_pro$counts), sample=c("HUT102", "ST1", "Su9T01", "KARPAS299", "L82", "SUPM2", "SMZ1", "MYLA", "MAC2A", "KIJK", "SR786", "FEPD", "KARPAS384", "DL40", "OCILY12", "HUT78", "HH", "MJ", "MTA", "MOTN1", "NKL", "DERL2", "KHYG1", "SeAx", "SUDHL1"), subtype=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"))
all((colData_pro$sample) %in% colnames(fc_pro))
[1] TRUE
#Create DESeq object and generate normalized counts
dds_pro <- DESeqDataSetFromMatrix(countData=fc_pro, colData=colData_pro, design=~sample)
Warning in DESeqDataSet(se, design = design, ignoreRank) :
some variables in design formula are characters, converting to factors
dds_pro <- estimateSizeFactors(dds_pro)
deseq_sizes_pro <- as.data.frame(sizeFactors(dds_pro))
deseq_sizes_pro
variable.names(dds_pro)
[1] "HUT102" "ST1" "Su9T01" "KARPAS299" "L82" "SUPM2" "SMZ1" "MYLA"
[9] "MAC2A" "KIJK" "SR786" "FEPD" "KARPAS384" "DL40" "OCILY12" "HUT78"
[17] "HH" "MJ" "MTA" "MOTN1" "NKL" "DERL2" "KHYG1" "SeAx"
[25] "SUDHL1"
keep <- rowMax(counts(dds_pro, normalize=TRUE)) >= 25
dds_pro <- dds_pro[keep,]
saveRDS(dds_pro, file="dREG_dds.rds")
dREG_readFilt <- dREG[dREG$dREGpeakID %in% rownames(dds_pro),]
write.table(dREG_readFilt, file="dREGpeaks.readFilt.bed", sep="\t", col.names=FALSE, row.names=FALSE,
quote=FALSE)
Generate norm counts files and save to local directory
rawcounts_pro <- as.data.frame(counts(dds_pro, normalized=FALSE))
normcounts_pro <- as.data.frame(counts(dds_pro, normalized=TRUE))
colnames(rawcounts_pro) <- c("HUT102", "ST1", "Su9T01", "KARPAS299", "L82", "SUPM2", "SMZ1", "MYLA", "MAC2A", "KIJK", "SR786", "FEPD", "KARPAS384", "DL40", "OCILY12", "HUT78", "HH", "MJ", "MTA", "MOTN1", "NKL", "DERL2", "KHYG1", "SeAx", "SUDHL1")
colnames(normcounts_pro) <- c("HUT102", "ST1", "Su9T01", "KARPAS299", "L82", "SUPM2", "SMZ1", "MYLA", "MAC2A", "KIJK", "SR786", "FEPD", "KARPAS384", "DL40", "OCILY12", "HUT78", "HH", "MJ", "MTA", "MOTN1", "NKL", "DERL2", "KHYG1", "SeAx", "SUDHL1")
write.table(rawcounts_pro, file="pro_rawcounts.txt", sep="\t", col.names=TRUE, row.names=TRUE, quote=FALSE)
write.table(normcounts_pro, file="pro_normcounts.txt", sep="\t", col.names=TRUE, row.names=TRUE, quote=FALSE)
Data transformation for plot generation Top 500 contributors is the default for PCA Set ‘ntop’ to number of observations in the dds object
rld_pro <- rlog(dds_pro, blind=TRUE)
sampleDistspro <- dist(t(assay(rld_pro)))
sampleDistMtxpro <- as.matrix(sampleDistspro)
rownames(sampleDistMtxpro) <- paste0(rld_pro$sample)
colnames(sampleDistMtxpro) <- NULL
#Generate PCA plot (intgroup set equal to desired metadata variable)
plotPCA(rld_pro, intgroup = "subtype", ntop=120888) + ggtitle("pro-seq PCA") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

#top 500 PCA
plotPCA(rld_pro, intgroup = "subtype") + ggtitle("pro-seq PCA Top 500") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

#top 1000 PCA
plotPCA(rld_pro, intgroup = "subtype", ntop=1000) + ggtitle("pro-seq PCA Top 1000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

#top 5000 PCA
plotPCA(rld_pro, intgroup = "subtype", ntop=5000) + ggtitle("pro-seq PCA Top 5000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

#top 10000 PCA
plotPCA(rld_pro, intgroup = "subtype", ntop=10000) + ggtitle("pro-seq PCA Top 10000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

#top 15000 PCA
plotPCA(rld_pro, intgroup = "subtype", ntop=15000) + ggtitle("pro-seq PCA Top 15000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

#top 20000 PCA
plotPCA(rld_pro, intgroup = "subtype", ntop=20000) + ggtitle("pro-seq PCA Top 20000") + scale_color_manual(breaks = c("ATLL", "ALK+ALCL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtxpro), max.overlaps=50)

Additional dendrogram plots
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255)
pheatmap(sampleDistMtxpro, col=colors, border_color=NA, show_colnames=FALSE, show_rownames=TRUE,
cluster_rows=TRUE, cluster_cols=TRUE, main="pro Sample Distance Clustering")

plot(hclust(sampleDistspro), labels=rownames(sampleDistMtxpro), main="pro Sample Distance Dendrogram")

Assemble counts results
avg_pro <- data.frame(peakID=rownames(normcounts_pro))
avg_pro$DERL2 <- (normcounts_pro$DERL2)
avg_pro$DL40 <- (normcounts_pro$DL40)
avg_pro$FEPD <- (normcounts_pro$FEPD)
avg_pro$HH <- (normcounts_pro$HH)
avg_pro$HUT78 <- (normcounts_pro$HUT78)
avg_pro$HUT102 <- (normcounts_pro$HUT102)
avg_pro$KARPAS299 <- (normcounts_pro$KARPAS299)
avg_pro$KARPAS384 <- (normcounts_pro$KARPAS384)
avg_pro$KHYG1 <- (normcounts_pro$KHYG1)
avg_pro$KIJK <- (normcounts_pro$KIJK)
avg_pro$L82 <- (normcounts_pro$L82)
avg_pro$MAC2A <- (normcounts_pro$MAC2A)
avg_pro$MJ <- (normcounts_pro$MJ)
avg_pro$MOTN1 <- (normcounts_pro$MOTN1)
avg_pro$MTA <- (normcounts_pro$MTA)
avg_pro$MYLA <- (normcounts_pro$MYLA)
avg_pro$NKL <- (normcounts_pro$NKL)
avg_pro$OCILY12 <- (normcounts_pro$OCILY12)
avg_pro$SeAx <- (normcounts_pro$SeAx)
avg_pro$SMZ1 <- (normcounts_pro$SMZ1)
avg_pro$SR786 <- (normcounts_pro$SR786)
avg_pro$ST1 <- (normcounts_pro$ST1)
avg_pro$Su9T01 <- (normcounts_pro$Su9T01)
avg_pro$SUDHL1 <- (normcounts_pro$SUDHL1)
avg_pro$SUPM2 <- (normcounts_pro$SUPM2)
avg_pro$max <- apply(avg_pro[c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS299", "KARPAS384", "KHYG1", "KIJK", "L82", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "SR786", "ST1", "Su9T01", "SUDHL1", "SUPM2")], 1, max, na.rm=TRUE)
rel_pro <- data.frame(peakID=avg_pro$peakID)
rel_pro$DERL2 <- avg_pro$DERL2 / avg_pro$max
rel_pro$DL40 <- avg_pro$DL40 / avg_pro$max
rel_pro$FEPD <- avg_pro$FEPD / avg_pro$max
rel_pro$HH <- avg_pro$HH / avg_pro$max
rel_pro$HUT78 <- avg_pro$HUT78 / avg_pro$max
rel_pro$HUT102 <- avg_pro$HUT102 / avg_pro$max
rel_pro$KARPAS299 <- avg_pro$KARPAS299 / avg_pro$max
rel_pro$KARPAS384 <- avg_pro$KARPAS384 / avg_pro$max
rel_pro$KHYG1 <- avg_pro$KHYG1 / avg_pro$max
rel_pro$KIJK <- avg_pro$KIJK / avg_pro$max
rel_pro$L82 <- avg_pro$L82 / avg_pro$max
rel_pro$MAC2A <- avg_pro$MAC2A / avg_pro$max
rel_pro$MJ <- avg_pro$MJ / avg_pro$max
rel_pro$MOTN1 <- avg_pro$MOTN1 / avg_pro$max
rel_pro$MTA <- avg_pro$MTA / avg_pro$max
rel_pro$MYLA <- avg_pro$MYLA / avg_pro$max
rel_pro$NKL <- avg_pro$NKL / avg_pro$max
rel_pro$OCILY12 <- avg_pro$OCILY12 / avg_pro$max
rel_pro$SeAx <- avg_pro$SeAx / avg_pro$max
rel_pro$SMZ1 <- avg_pro$SMZ1 / avg_pro$max
rel_pro$SR786 <- avg_pro$SR786 / avg_pro$max
rel_pro$ST1 <- avg_pro$ST1 / avg_pro$max
rel_pro$Su9T01 <- avg_pro$Su9T01 / avg_pro$max
rel_pro$SUDHL1 <- avg_pro$SUDHL1 / avg_pro$max
rel_pro$SUPM2 <- avg_pro$SUPM2 / avg_pro$max
PCA top contributors selection (5000 tried first)
dREG_annot <- read.table("002_TCLs_p1000_dREGpeak_annotation.txt", sep="\t", header=TRUE)
PRO_rel <- rel_pro
#check this
colnames(PRO_rel) <- c("dREGpeakID", "DERL2.enhancer", "DL40.enhancer", "FEPD.enhancer", "HH.enhancer", "HUT78.ehancer", "HUT102.enhancer", "KARPAS299.enhancer", "KARPAS384.enhancer", "KHYG1.enhancer", "KIJK.enhancer", "L82.enhancer", "MAC2A.ehancer", "MJ.enhancer", "MOTN1.enhancer", "MTA.enhancer", "MYLA.enhancer", "NKL.enhancer", "OCILY12.enhancer", "SeAx.ehancer", "SMZ1.enhancer", "SR786.enhancer", "ST1.enhancer", "Su9T01.enhancer", "SUDHL1.enhancer", "SUPM2.enhancer")
saveRDS(PRO_rel, file="pro_rel.rds")
head(PRO_rel)
rv <- rowVars(assay(rld_pro))
select <- order(rv, decreasing=TRUE)[seq_len(min(5000, length(rv)))]
#Changing the 5000 here will select a Different number of top contributors if desired
pc <- prcomp(t(assay(rld_pro)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
write.table(sweep(aload, 2, colSums(aload), "/"), file="Top 5000 pro PCA Contributors.txt")
#Clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Merge top 5000 elements with their annotations
top5000 <- dREG_annot[(dREG_annot$peakID %in% rownames(aload)),]
write.table(top5000, file="Top5000.txt", sep='\t')
ggplot(top5000, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("Top 5000 PCA Contributors dREGpeak Annotations")

ggplot(dREG_annot, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("All dREGpeak Annotations")

#filter results down by top contributors
pro_5000_rel <- rel_pro[(rel_pro$peakID %in% top5000$peakID),]
#Gap Stat Calculation
#set.seed(42)
#This sets the random number generator seed so it will always produce the same result. You can pick whatever number you'd like.
#gap_stat <- clusGap(pro_5000_rel[2:26], FUN = kmeans, nstart = 20, K.max = 24, B = 50)
#... = number of samples + 1
#Cluster Stat Plots
#fviz_nbclust(pro_5000_rel[2:26], kmeans, method="wss", k.max=24) + theme_minimal() + ggtitle("Elbow Plot")
#fviz_gap_stat(gap_stat) + theme_minimal() + ggtitle("Gap Statistic")
#fviz_nbclust(pro_5000_rel[2:26], kmeans, method="silhouette", k.max=24) + theme_minimal() + ggtitle("Silhouette Plot")
#k-means Clustering
CLARAk4 <- clara(pro_5000_rel[2:26],4,medoids.x=TRUE)
CLARAk5 <- clara(pro_5000_rel[2:26],5,medoids.x=TRUE)
CLARAk6 <- clara(pro_5000_rel[2:26],6,medoids.x=TRUE)
CLARAk7 <- clara(pro_5000_rel[2:26],7,medoids.x=TRUE)
CLARAk8 <- clara(pro_5000_rel[2:26],8,medoids.x=TRUE)
pro_5000_rel$k4 <- CLARAk4$clustering
pro_5000_rel$k5 <- CLARAk5$clustering
pro_5000_rel$k6 <- CLARAk6$clustering
pro_5000_rel$k7 <- CLARAk7$clustering
pro_5000_rel$k8 <- CLARAk8$clustering
#Displaying Heatmaps
#k-means 4
pheatmap(pro_5000_rel[order(pro_5000_rel[, 26+1]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=pro_5000_rel[26+1])

#k-means 5
pheatmap(pro_5000_rel[order(pro_5000_rel[, 26+2]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=pro_5000_rel[26+2])

#k-means 6
pheatmap(pro_5000_rel[order(pro_5000_rel[, 26+3]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=pro_5000_rel[26+3])

#k-means 7
pheatmap(pro_5000_rel[order(pro_5000_rel[, 26+4]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=pro_5000_rel[26+4])

#k-means 8
pheatmap(pro_5000_rel[order(pro_5000_rel[, 26+5]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=pro_5000_rel[26+5])

PCA top contributors (10K)
rv <- rowVars(assay(rld_pro))
select <- order(rv, decreasing=TRUE)[seq_len(min(10000, length(rv)))]
#Changing the 10000 here will select a Different number of top contributors if desired
pc <- prcomp(t(assay(rld_pro)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
write.table(sweep(aload, 2, colSums(aload), "/"), file="Top 10000 pro PCA Contributors.txt")
#Clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Merge top 10000 elements with their annotations
top10000 <- dREG_annot[(dREG_annot$peakID %in% rownames(aload)),]
write.table(top10000, file="Top10000.txt", sep='\t')
ggplot(top10000, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("Top 10000 PCA Contributors dREGpeak Annotations")

ggplot(dREG_annot, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("All dREGpeak Annotations")

#filter results down by top contributors
PRO_10000_rel <- rel_pro[(rel_pro$peakID %in% top10000$peakID),]
#Gap Stat Calculation
#set.seed(42)
#This sets the random number generator seed so it will always produce the same result. You can pick whatever number you'd like.
#gap_stat <- clusGap(pro_10000_rel[2:26], FUN = kmeans, nstart = 20, K.max = 24, B = 50)
#... = number of samples + 1
#Cluster Stat Plots
#fviz_nbclust(pro_10000_rel[2:26], kmeans, method="wss", k.max=24) + theme_minimal() + ggtitle("Elbow Plot")
#fviz_gap_stat(gap_stat) + theme_minimal() + ggtitle("Gap Statistic")
#fviz_nbclust(pro_10000_rel[2:26], kmeans, method="silhouette", k.max=24) + theme_minimal() + ggtitle("Silhouette Plot")
#k-means Clustering
CLARAk5 <- clara(PRO_10000_rel[2:26],5,medoids.x=TRUE)
CLARAk8 <- clara(PRO_10000_rel[2:26],8,medoids.x=TRUE)
CLARAk10 <- clara(PRO_10000_rel[2:26],10,medoids.x=TRUE)
CLARAk13 <- clara(PRO_10000_rel[2:26],13,medoids.x=TRUE)
CLARAk15 <- clara(PRO_10000_rel[2:26],15,medoids.x=TRUE)
CLARAk6 <- clara(PRO_10000_rel[2:26],6,medoids.x=TRUE)
CLARAk7 <- clara(PRO_10000_rel[2:26],7,medoids.x=TRUE)
CLARAk4 <- clara(PRO_10000_rel[2:26],4,medoids.x=TRUE)
PRO_10000_rel$k5 <- CLARAk5$clustering
PRO_10000_rel$k8 <- CLARAk8$clustering
PRO_10000_rel$k10 <- CLARAk10$clustering
PRO_10000_rel$k13 <- CLARAk13$clustering
PRO_10000_rel$k15 <- CLARAk15$clustering
PRO_10000_rel$k6 <- CLARAk6$clustering
PRO_10000_rel$k7 <- CLARAk7$clustering
PRO_10000_rel$k4 <- CLARAk4$clustering
#Displaying Heatmaps
#k-means 5
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+1]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+1])

#k-means 8
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+2]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+2])

#k-means 10
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+3]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+3])

#k-means 13
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+4]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+4])

#k-means 15
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+5]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+5])

#k-means 6
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+6]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+6])

#k-means 7
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+7]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+7])

#k-means 4
pheatmap(PRO_10000_rel[order(PRO_10000_rel[, 26+8]),][,2:26], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_10000_rel[26+8])

Separating by disease subset and re-clustering
dds_pro_sub <- dds_pro[,-c(7,13,15,19,20,21,22,23)] #Excluding sample numbers of entities that are not Alk+Alcl, Alk-Alcl, Atll, and Ctcl
estimateSizeFactors(dds_pro_sub) #Must re-calculate size factors after removing samples
class: DESeqDataSet
dim: 120888 17
metadata(1): version
assays(1): counts
rownames(120888): dREGpeak000003 dREGpeak000004 ... dREGpeak312454 dREGpeak312455
rowData names(0):
colnames(17): HUT102 ST1 ... SeAx SUDHL1
colData names(3): sample subtype sizeFactor
deseq_sizes_pro_sub <- as.data.frame(sizeFactors(dds_pro_sub))
deseq_sizes_pro_sub
rld_pro_sub <- rlog(dds_pro_sub, blind=TRUE)
colnames(rld_pro_sub) <- paste0(dds_pro_sub$sample)
sampleDists_pro_sub <- dist(t(assay(rld_pro_sub)))
sampleDistMtx_pro_sub <- as.matrix(sampleDists_pro_sub)
rownames(sampleDistMtx_pro_sub) <- colnames(rld_pro_sub)
colnames(sampleDistMtx_pro_sub) <- NULL
hclust_pro_sub <- hclust(sampleDists_pro_sub)
plot(hclust_pro_sub, labels=rownames(sampleDistMtx_pro_sub), main="Largest Entity dREG Dendrogram")

pro subset PCAs
#plotPCA(rld_sub, intgroup = "subtype") + ggtitle("RNA-seq subset PCA Top 500") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)
plotPCA(rld_pro_sub, intgroup = "subtype", ntop=1000) + ggtitle("pro-seq subset PCA Top 1000") + scale_color_manual(breaks = c("ATLL","ALK+ALCL", "CTCL", "ALK-ALCL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue")) + geom_text_repel(label=rownames(sampleDistMtx_pro_sub), max.overlaps=50)

plotPCA(rld_pro_sub, intgroup = "subtype", ntop=5000) + ggtitle("pro-seq subset PCA Top 5000") + scale_color_manual(breaks = c("ATLL","ALK+ALCL", "CTCL", "ALK-ALCL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue")) + geom_text_repel(label=rownames(sampleDistMtx_pro_sub), max.overlaps=50)

plotPCA(rld_pro_sub, intgroup = "subtype", ntop=10000) + ggtitle("pro-seq subset PCA Top 10000") + scale_color_manual(breaks = c("ATLL","ALK+ALCL", "CTCL", "ALK-ALCL"), values=c("darkgray", "chocolate4", "chartreuse3", "cadetblue")) + geom_text_repel(label=rownames(sampleDistMtx_pro_sub), max.overlaps=50)

#plotPCA(rld_sub, intgroup = "subtype", ntop=15000) + ggtitle("RNA-seq subset PCA Top 15000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)
#plotPCA(rld_sub, intgroup = "subtype", ntop=60676) + ggtitle("RNA-seq subset PCA All Contributors") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)
Generate norm counts file
normcounts_pro_sub <- as.data.frame(counts(dds_pro_sub, normalized=TRUE))
colnames(normcounts_pro_sub) <- c("HUT102", "ST1", "Su9T01", "KARPAS299", "L82", "SUPM2", "MYLA", "MAC2A", "KIJK", "SR786", "FEPD", "DL40", "HUT78", "HH", "MJ", "SeAx", "SUDHL1")
Additional dendrogram plots
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255)
pheatmap(sampleDistMtx_pro_sub, col=colors, border_color=NA, show_colnames=FALSE, show_rownames=TRUE,
cluster_rows=TRUE, cluster_cols=TRUE, main="pro subset Sample Distance Clustering")

plot(hclust(sampleDists_pro_sub), labels=rownames(sampleDistMtx_pro_sub), main="pro subset Sample Distance Dendrogram")

Assemble subset counts and average
avg_pro_sub <- data.frame(peakID=rownames(normcounts_pro_sub))
avg_pro_sub$HUT102 <- (normcounts_pro_sub$HUT102)
avg_pro_sub$ST1 <- (normcounts_pro_sub$ST1)
avg_pro_sub$Su9T01 <- (normcounts_pro_sub$Su9T01)
avg_pro_sub$KARPAS299 <- (normcounts_pro_sub$KARPAS299)
avg_pro_sub$L82 <- (normcounts_pro_sub$L82)
avg_pro_sub$SUPM2 <- (normcounts_pro_sub$SUPM2)
avg_pro_sub$MYLA <- (normcounts_pro_sub$MYLA)
avg_pro_sub$MAC2A <- (normcounts_pro_sub$MAC2A)
avg_pro_sub$KIJK <- (normcounts_pro_sub$KIJK)
avg_pro_sub$SR786 <- (normcounts_pro_sub$SR786)
avg_pro_sub$FEPD <- (normcounts_pro_sub$FEPD)
avg_pro_sub$DL40 <- (normcounts_pro_sub$DL40)
avg_pro_sub$HUT78 <- (normcounts_pro_sub$HUT78)
avg_pro_sub$HH <- (normcounts_pro_sub$HH)
avg_pro_sub$MJ <- (normcounts_pro_sub$MJ)
avg_pro_sub$SeAx <- (normcounts_pro_sub$SeAx)
avg_pro_sub$SUDHL1 <- (normcounts_pro_sub$SUDHL1)
avg_pro_sub$max <- apply(avg_pro_sub[c("HUT102", "ST1", "Su9T01", "KARPAS299", "L82", "SUPM2", "MYLA", "MAC2A", "KIJK", "SR786", "FEPD", "DL40", "HUT78", "HH", "MJ", "SeAx", "SUDHL1")], 1, max, na.rm=TRUE)
rel_pro_sub <- data.frame(peakID=avg_pro_sub$peakID)
rel_pro_sub$HUT102 <- avg_pro_sub$HUT102 / avg_pro_sub$max
rel_pro_sub$ST1 <- avg_pro_sub$ST1 / avg_pro_sub$max
rel_pro_sub$Su9T01 <- avg_pro_sub$Su9T01 / avg_pro_sub$max
rel_pro_sub$KARPAS299 <- avg_pro_sub$KARPAS299 / avg_pro_sub$max
rel_pro_sub$L82 <- avg_pro_sub$L82 / avg_pro_sub$max
rel_pro_sub$SUPM2 <- avg_pro_sub$SUPM2 / avg_pro_sub$max
rel_pro_sub$MYLA <- avg_pro_sub$MYLA / avg_pro_sub$max
rel_pro_sub$MAC2A <- avg_pro_sub$MAC2A / avg_pro_sub$max
rel_pro_sub$KIJK <- avg_pro_sub$KIJK / avg_pro_sub$max
rel_pro_sub$SR786 <- avg_pro_sub$SR786 / avg_pro_sub$max
rel_pro_sub$FEPD <- avg_pro_sub$FEPD / avg_pro_sub$max
rel_pro_sub$DL40 <- avg_pro_sub$DL40 / avg_pro_sub$max
rel_pro_sub$HUT78 <- avg_pro_sub$HUT78 / avg_pro_sub$max
rel_pro_sub$HH <- avg_pro_sub$HH / avg_pro_sub$max
rel_pro_sub$MJ <- avg_pro_sub$MJ / avg_pro_sub$max
rel_pro_sub$SeAx <- avg_pro_sub$SeAx / avg_pro_sub$max
rel_pro_sub$SUDHL1 <- avg_pro_sub$SUDHL1 / avg_pro_sub$max
PCA top contributors selection (5000)
#check this
colnames(rel_pro_sub) <- c("dREGpeakID", "HUT102.enhancer", "ST1.enhancer", "Su9T01.enhancer", "KARPAS299.enhancer", "L82.enhancer", "SUPM2.enhancer", "MYLA.enhancer", "MAC2A.ehancer", "KIJK.enhancer", "SR786.enhancer", "FEPD.enhancer", "DL40.enhancer", "HUT78.ehancer", "HH.enhancer", "MJ.enhancer", "SeAx.ehancer", "SUDHL1.enhancer")
rv2 <- rowVars(assay(rld_pro_sub))
select2 <- order(rv2, decreasing=TRUE)[seq_len(min(5000, length(rv2)))]
#Changing the 5000 here will select a Different number of top contributors if desired
pc2 <- prcomp(t(assay(rld_pro_sub)[select2,]))
loadings2 <- as.data.frame(pc2$rotation)
aload2 <- abs(loadings2)
write.table(sweep(aload, 2, colSums(aload2), "/"), file="Top 5000 pro sub PCA Contributors.txt")
##Merge top 5000 elements with their annotations
top5000 <- dREG_annot[(dREG_annot$peakID %in% rownames(aload2)),]
write.table(top5000, file="Top5000_pro_sub.txt", sep='\t')
ggplot(top5000, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("Top 5000 PCA subset Contributors dREGpeak Annotations")

ggplot(dREG_annot, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("All dREGpeak Annotations")

#filter results down by top contributors
PRO_5000_rel <- rel_pro_sub[(rel_pro_sub$dREGpeakID %in% top5000$peakID),]
#Gap Stat Calculation
#set.seed(42)
#This sets the random number generator seed so it will always produce the same result. You can pick whatever number you'd like.
#gap_stat <- clusGap(RNA_rel[2:26], FUN = kmeans, nstart = 20, K.max = 24, B = 50)
#... = number of samples + 1
#Cluster Stat Plots
#fviz_nbclust(top10000[2:26], kmeans, method="wss", k.max=24) + theme_minimal() + ggtitle("Elbow Plot")
#fviz_gap_stat(gap_stat) + theme_minimal() + ggtitle("Gap Statistic")
#fviz_nbclust(top10000[2:26], kmeans, method="silhouette", k.max=24) + theme_minimal() + ggtitle("Silhouette Plot")
#k-means Clustering
CLARAk15 <- clara(PRO_5000_rel[2:18],15,medoids.x=TRUE)
CLARAk20 <- clara(PRO_5000_rel[2:18],20,medoids.x=TRUE)
CLARAk22 <- clara(PRO_5000_rel[2:18],22,medoids.x=TRUE)
CLARAk25 <- clara(PRO_5000_rel[2:18],25,medoids.x=TRUE)
CLARAk26 <- clara(PRO_5000_rel[2:18],26,medoids.x=TRUE)
CLARAk30 <- clara(PRO_5000_rel[2:18],30,medoids.x=TRUE)
CLARAk36 <- clara(PRO_5000_rel[2:18],36,medoids.x=TRUE)
CLARAk4 <- clara(PRO_5000_rel[2:18],4,medoids.x=TRUE)
CLARAk6 <- clara(PRO_5000_rel[2:18],6,medoids.x=TRUE)
CLARAk10 <- clara(PRO_5000_rel[2:18],10,medoids.x=TRUE)
CLARAk3 <- clara(PRO_5000_rel[2:18],3,medoids.x=TRUE)
CLARAk5 <- clara(PRO_5000_rel[2:18],5,medoids.x=TRUE)
PRO_5000_rel$k15 <- CLARAk15$clustering
PRO_5000_rel$k20 <- CLARAk20$clustering
PRO_5000_rel$k22 <- CLARAk22$clustering
PRO_5000_rel$k25 <- CLARAk25$clustering
PRO_5000_rel$k26 <- CLARAk26$clustering
PRO_5000_rel$k30 <- CLARAk30$clustering
PRO_5000_rel$k36 <- CLARAk36$clustering
PRO_5000_rel$k4 <- CLARAk4$clustering
PRO_5000_rel$k6 <- CLARAk6$clustering
PRO_5000_rel$k10 <- CLARAk10$clustering
PRO_5000_rel$k3 <- CLARAk3$clustering
PRO_5000_rel$k5 <- CLARAk5$clustering
#Displaying Heatmaps
#k-means 15
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+1]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+1])

#k-means 20
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+2]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+2])

#k-means 22
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+3]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+3])

#k-means 25
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+4]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+4])

#k-means 26
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+5]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+5])

#k-means 30
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+6]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+6])

#k-means 36
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+7]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+7])

#k-means 4
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+8]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+8])

#k-means 6
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+9]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+9])

#k-means 10
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+10]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+10])

#k-means 3
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+11]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+11])

#k-means 5
pheatmap(PRO_5000_rel[order(PRO_5000_rel[, 18+12]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_5000_rel[18+12])

PCA top contributors (1000)
#check this
colnames(rel_pro_sub) <- c("dREGpeakID", "HUT102.enhancer", "ST1.enhancer", "Su9T01.enhancer", "KARPAS299.enhancer", "L82.enhancer", "SUPM2.enhancer", "MYLA.enhancer", "MAC2A.ehancer", "KIJK.enhancer", "SR786.enhancer", "FEPD.enhancer", "DL40.enhancer", "HUT78.ehancer", "HH.enhancer", "MJ.enhancer", "SeAx.ehancer", "SUDHL1.enhancer")
rv3 <- rowVars(assay(rld_pro_sub))
select3 <- order(rv3, decreasing=TRUE)[seq_len(min(1000, length(rv3)))]
#Changing the 1000 here will select a Different number of top contributors if desired
pc3 <- prcomp(t(assay(rld_pro_sub)[select3,]))
loadings3 <- as.data.frame(pc3$rotation)
aload3 <- abs(loadings3)
write.table(sweep(aload3, 2, colSums(aload3), "/"), file="Top 1000 pro sub PCA Contributors.txt")
##Merge top 1000 elements with their annotations
top1000 <- dREG_annot[(dREG_annot$peakID %in% rownames(aload3)),]
write.table(top1000, file="Top1000_pro_sub.txt", sep='\t')
ggplot(top1000, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("Top 5000 PCA subset Contributors dREGpeak Annotations")

ggplot(dREG_annot, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("All dREGpeak Annotations")

#filter results down by top contributors
PRO_1000_rel <- rel_pro_sub[(rel_pro_sub$dREGpeakID %in% top1000$peakID),]
#Gap Stat Calculation
#set.seed(42)
#This sets the random number generator seed so it will always produce the same result. You can pick whatever number you'd like.
#gap_stat <- clusGap(RNA_rel[2:26], FUN = kmeans, nstart = 20, K.max = 24, B = 50)
#... = number of samples + 1
#Cluster Stat Plots
#fviz_nbclust(top10000[2:26], kmeans, method="wss", k.max=24) + theme_minimal() + ggtitle("Elbow Plot")
#fviz_gap_stat(gap_stat) + theme_minimal() + ggtitle("Gap Statistic")
#fviz_nbclust(top10000[2:26], kmeans, method="silhouette", k.max=24) + theme_minimal() + ggtitle("Silhouette Plot")
#k-means Clustering
CLARAk3 <- clara(PRO_1000_rel[2:18],3,medoids.x=TRUE)
CLARAk4 <- clara(PRO_1000_rel[2:18],4,medoids.x=TRUE)
CLARAk5 <- clara(PRO_1000_rel[2:18],5,medoids.x=TRUE)
CLARAk6 <- clara(PRO_1000_rel[2:18],6,medoids.x=TRUE)
CLARAk7 <- clara(PRO_1000_rel[2:18],7,medoids.x=TRUE)
CLARAk8 <- clara(PRO_1000_rel[2:18],8,medoids.x=TRUE)
PRO_1000_rel$k3 <- CLARAk3$clustering
PRO_1000_rel$k4 <- CLARAk4$clustering
PRO_1000_rel$k5 <- CLARAk5$clustering
PRO_1000_rel$k6 <- CLARAk6$clustering
PRO_1000_rel$k7 <- CLARAk7$clustering
PRO_1000_rel$k8 <- CLARAk8$clustering
#Displaying Heatmaps
#k-means 3
pheatmap(PRO_1000_rel[order(PRO_1000_rel[, 18+1]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_1000_rel[18+1])

#k-means 4
pheatmap(PRO_1000_rel[order(PRO_1000_rel[, 18+2]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_1000_rel[18+2])

#k-means 5
pheatmap(PRO_1000_rel[order(PRO_1000_rel[, 18+3]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_1000_rel[18+3])

#k-means 6
pheatmap(PRO_1000_rel[order(PRO_1000_rel[, 18+4]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_1000_rel[18+4])

#k-means 7
pheatmap(PRO_1000_rel[order(PRO_1000_rel[, 18+5]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_1000_rel[18+5])

#k-means 8
pheatmap(PRO_1000_rel[order(PRO_1000_rel[, 18+6]),][,2:18], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=PRO_1000_rel[18+6])

Removing Alk+ALCL to determine if PCA separation improves
dds_sub <- dds_pro[,-c(4,5,6,10,11,25)] #Excluding sample numbers of the ALK+ALCL
estimateSizeFactors(dds_sub) #Must re-calculate size factors after removing samples
class: DESeqDataSet
dim: 120888 19
metadata(1): version
assays(1): counts
rownames(120888): dREGpeak000003 dREGpeak000004 ... dREGpeak312454 dREGpeak312455
rowData names(0):
colnames(19): HUT102 ST1 ... KHYG1 SeAx
colData names(3): sample subtype sizeFactor
dds_sub
class: DESeqDataSet
dim: 120888 19
metadata(1): version
assays(1): counts
rownames(120888): dREGpeak000003 dREGpeak000004 ... dREGpeak312454 dREGpeak312455
rowData names(0):
colnames(19): HUT102 ST1 ... KHYG1 SeAx
colData names(3): sample subtype sizeFactor
rld_sub <- rlog(dds_sub, blind=TRUE)
colnames(rld_sub) <- paste0(dds_sub$sample)
sampleDists_sub <- dist(t(assay(rld_sub)))
sampleDistMtx_sub <- as.matrix(sampleDists_sub)
rownames(sampleDistMtx_sub) <- colnames(rld_sub)
colnames(sampleDistMtx_sub) <- NULL
hclust_sub <- hclust(sampleDists_sub)
plot(hclust_sub, labels=rownames(sampleDistMtx_sub), main="PRO-seq subset Gene Dendrogram")

PCAs
plotPCA(rld_sub, intgroup = "subtype") + ggtitle("PRO-seq subset PCA Top 500") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=1000) + ggtitle("PRO-seq subset PCA Top 1000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=5000) + ggtitle("PRO-seq subset PCA Top 5000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=10000) + ggtitle("PRO-seq subset PCA Top 10000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=15000) + ggtitle("PRO-seq subset PCA Top 15000") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

plotPCA(rld_sub, intgroup = "subtype", ntop=120888) + ggtitle("PRO-seq subset PCA All Contributors") + scale_color_manual(breaks = c("ATLL", "CTCL", "ALK-ALCL", "SQGD_TCL", "T_LGL", "NKT", "HS_TCL", "PTCL_NOS", "NKL"), values=c("darkgray", "chartreuse3", "cadetblue", "cyan3", "red", "lightpink", "black", "darkgoldenrod1", "blueviolet")) + geom_text_repel(label=rownames(sampleDistMtx_sub), max.overlaps=50)

Additional dendrogram plots
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255)
pheatmap(sampleDistMtx_sub, col=colors, border_color=NA, show_colnames=FALSE, show_rownames=TRUE,
cluster_rows=TRUE, cluster_cols=TRUE, main="PRO subset Sample Distance Clustering")

plot(hclust(sampleDists_sub), labels=rownames(sampleDistMtx_sub), main="PRO subset Sample Distance Dendrogram")

Generate norm counts file
normcounts_sub <- as.data.frame(counts(dds_sub, normalized=TRUE))
colnames(normcounts_sub) <- c("HUT102", "ST1", "Su9T01", "SMZ1", "MYLA", "MAC2A", "FEPD", "KARPAS384", "DL40", "OCILY12", "HUT78", "HH", "MJ", "MTA", "MOTN1", "NKL", "DERL2", "KHYG1", "SeAx")
#write.table(normcounts_pro, file="pro_normcounts.txt", sep="\t", col.names=TRUE, row.names=TRUE, quote=FALSE)
Assemble counts results
avg_sub <- data.frame(peakID=rownames(normcounts_sub))
avg_sub$DERL2 <- (normcounts_sub$DERL2)
avg_sub$DL40 <- (normcounts_sub$DL40)
avg_sub$FEPD <- (normcounts_sub$FEPD)
avg_sub$HH <- (normcounts_sub$HH)
avg_sub$HUT78 <- (normcounts_sub$HUT78)
avg_sub$HUT102 <- (normcounts_sub$HUT102)
avg_sub$KARPAS384 <- (normcounts_sub$KARPAS384)
avg_sub$KHYG1 <- (normcounts_sub$KHYG1)
avg_sub$MAC2A <- (normcounts_sub$MAC2A)
avg_sub$MJ <- (normcounts_sub$MJ)
avg_sub$MOTN1 <- (normcounts_sub$MOTN1)
avg_sub$MTA <- (normcounts_sub$MTA)
avg_sub$MYLA <- (normcounts_sub$MYLA)
avg_sub$NKL <- (normcounts_sub$NKL)
avg_sub$OCILY12 <- (normcounts_sub$OCILY12)
avg_sub$SeAx <- (normcounts_sub$SeAx)
avg_sub$SMZ1 <- (normcounts_sub$SMZ1)
avg_sub$ST1 <- (normcounts_sub$ST1)
avg_sub$Su9T01 <- (normcounts_sub$Su9T01)
avg_sub$max <- apply(avg_sub[c("DERL2", "DL40", "FEPD", "HH", "HUT78", "HUT102", "KARPAS384", "KHYG1", "MAC2A", "MJ", "MOTN1", "MTA", "MYLA", "NKL", "OCILY12", "SeAx", "SMZ1", "ST1", "Su9T01")], 1, max, na.rm=TRUE)
rel_sub <- data.frame(peakID=avg_sub$peakID)
rel_sub$DERL2 <- avg_sub$DERL2 / avg_sub$max
rel_sub$DL40 <- avg_sub$DL40 / avg_sub$max
rel_sub$FEPD <- avg_sub$FEPD / avg_sub$max
rel_sub$HH <- avg_sub$HH / avg_sub$max
rel_sub$HUT78 <- avg_sub$HUT78 / avg_sub$max
rel_sub$HUT102 <- avg_sub$HUT102 / avg_sub$max
rel_sub$KARPAS384 <- avg_sub$KARPAS384 / avg_sub$max
rel_sub$KHYG1 <- avg_sub$KHYG1 / avg_sub$max
rel_sub$MAC2A <- avg_sub$MAC2A / avg_sub$max
rel_sub$MJ <- avg_sub$MJ / avg_sub$max
rel_sub$MOTN1 <- avg_sub$MOTN1 / avg_sub$max
rel_sub$MTA <- avg_sub$MTA / avg_sub$max
rel_sub$MYLA <- avg_sub$MYLA / avg_sub$max
rel_sub$NKL <- avg_sub$NKL / avg_sub$max
rel_sub$OCILY12 <- avg_sub$OCILY12 / avg_sub$max
rel_sub$SeAx <- avg_sub$SeAx / avg_sub$max
rel_sub$SMZ1 <- avg_sub$SMZ1 / avg_sub$max
rel_sub$ST1 <- avg_sub$ST1 / avg_sub$max
rel_sub$Su9T01 <- avg_sub$Su9T01 / avg_sub$max
PCA top contributors selection (5000 tried first)
#check this
colnames(rel_sub) <- c("dREGpeakID", "DERL2.enhancer", "DL40.enhancer", "FEPD.enhancer", "HH.enhancer", "HUT78.ehancer", "HUT102.enhancer", "KARPAS384.enhancer", "KHYG1.enhancer", "MAC2A.ehancer", "MJ.enhancer", "MOTN1.enhancer", "MTA.enhancer", "MYLA.enhancer", "NKL.enhancer", "OCILY12.enhancer", "SeAx.ehancer", "SMZ1.enhancer", "ST1.enhancer", "Su9T01.enhancer")
rv <- rowVars(assay(rld_sub))
select <- order(rv, decreasing=TRUE)[seq_len(min(5000, length(rv)))]
#Changing the 5000 here will select a Different number of top contributors if desired
pc <- prcomp(t(assay(rld_sub)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
write.table(sweep(aload, 2, colSums(aload), "/"), file="Top 5000 pro subset PCA Contributors.txt")
#Clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Merge top 5000 elements with their annotations
top5000 <- dREG_annot[(dREG_annot$peakID %in% rownames(aload)),]
#write.table(top5000, file="Top5000.txt", sep='\t')
#ggplot(top5000, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("Top 5000 PCA Contributors dREGpeak Annotations")
#ggplot(dREG_annot, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("All dREGpeak Annotations")
#filter results down by top contributors
sub_5000_rel <- rel_sub[(rel_sub$dREGpeakID %in% top5000$peakID),]
#Gap Stat Calculation
#set.seed(42)
#This sets the random number generator seed so it will always produce the same result. You can pick whatever number you'd like.
#gap_stat <- clusGap(pro_5000_rel[2:26], FUN = kmeans, nstart = 20, K.max = 24, B = 50)
#... = number of samples + 1
#Cluster Stat Plots
#fviz_nbclust(pro_5000_rel[2:26], kmeans, method="wss", k.max=24) + theme_minimal() + ggtitle("Elbow Plot")
#fviz_gap_stat(gap_stat) + theme_minimal() + ggtitle("Gap Statistic")
#fviz_nbclust(pro_5000_rel[2:26], kmeans, method="silhouette", k.max=24) + theme_minimal() + ggtitle("Silhouette Plot")
#k-means Clustering
CLARAk4 <- clara(sub_5000_rel[2:20],4,medoids.x=TRUE)
CLARAk5 <- clara(sub_5000_rel[2:20],5,medoids.x=TRUE)
CLARAk6 <- clara(sub_5000_rel[2:20],6,medoids.x=TRUE)
CLARAk7 <- clara(sub_5000_rel[2:20],7,medoids.x=TRUE)
CLARAk8 <- clara(sub_5000_rel[2:20],8,medoids.x=TRUE)
sub_5000_rel$k4 <- CLARAk4$clustering
sub_5000_rel$k5 <- CLARAk5$clustering
sub_5000_rel$k6 <- CLARAk6$clustering
sub_5000_rel$k7 <- CLARAk7$clustering
sub_5000_rel$k8 <- CLARAk8$clustering
#Displaying Heatmaps
#k-means 4
pheatmap(sub_5000_rel[order(sub_5000_rel[, 20+1]),][,2:20], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=sub_5000_rel[20+1])

#k-means 5
pheatmap(sub_5000_rel[order(sub_5000_rel[, 20+2]),][,2:20], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=sub_5000_rel[20+2])

#k-means 6
pheatmap(sub_5000_rel[order(sub_5000_rel[, 20+3]),][,2:20], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=sub_5000_rel[20+3])

#k-means 7
pheatmap(sub_5000_rel[order(sub_5000_rel[, 20+4]),][,2:20], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=sub_5000_rel[20+4])

#k-means 8
pheatmap(sub_5000_rel[order(sub_5000_rel[, 20+5]),][,2:20], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=sub_5000_rel[20+5])

–PRO END–
Combined PRO and RNA analysis
Load DESeq objects and annotations
#dds_rna <- readRDS("RNA_dds.rds")
#dds_pro <- readRDS("dREG_dds.rds")
dREGann <- read.table("002_TCLs_p1000_m1000000_gene-centric_closest-dREGpeaks.txt", sep="\t", header=T)
write.table(deseq_sizes_pro, file="DEseq size factors.txt", sep="\t", quote=F, row.names=T)
Make prelim dataframes
norm_rna <- as.data.frame(counts(dds_rna, normalized=TRUE))
rld_rna2 <- rlog(dds_rna, blind=TRUE)
colnames(norm_rna) <- dds_rna$sample #Simplified names from dds metadata
rel_rna2 <- data.frame("geneID"=rownames(norm_rna))
rel_rna2$max.gene.counts <- apply(norm_rna[1:ncol(norm_rna)], 1, max, na.rm=TRUE)
i=1
while (i<=ncol(norm_rna)){
rel_rna2[paste0(dds_rna$sample[i],".gene.rel")] <- norm_rna[,i]/rel_rna2$max.gene.counts
i=i+1
}
norm_pro <- as.data.frame(counts(dds_pro, normalized=TRUE))
colnames(norm_pro) <- dds_pro$sample #Simplified names from dds metadata
colnames(norm_pro)[2] <- "ST1" #Think there was a typo in this sample name
colnames(norm_rna)[7] <- "KARPAS299"
colnames(norm_rna)[8] <- "KARPAS384"
norm_pro <- norm_pro[names(norm_rna)] #reorder sample columns to match RNA-seq data
colnames(PRO_rel)[1] <- ("closest_peak")
#rel_pro2 <- data.frame("closest_peak"=rownames(norm_pro))
PRO_rel$max.dREG.counts <- apply(norm_pro[1:ncol(norm_pro)], 1, max, na.rm=TRUE)
PRO_rel <- PRO_rel[,c(1,27,2:26)] #reorder columns
#i=1
#while (i<=ncol(norm_pro)){
# rel_pro2[paste0(dds_pro$sample[i],".dREG.rel")] <- norm_pro[,i]/rel_pro2$max.dREG.counts
# i=i+1
#}
Selecting gene PCA contributors by variance
#Select top 10000 PCA contributors
rv <- rowVars(assay(rld_rna2))
select <- order(rv, decreasing=TRUE)[seq_len(min(10000, length(rv)))] #Changing the 500 here will select a different number of top contributors if desired
pc <- prcomp(t(assay(rld_rna2)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
sweep(aload, 2, colSums(aload), "/")
#Clean up variables
rm(rv)
rm(select)
rm(pc)
rm(loadings)
#Merge top 500 elements with their annotations
top10k_rel_rna <- rel_rna2[(rel_rna2$geneID %in% rownames(aload)),] #filter rel gene dataframe for top 10k
Determining clusters (k=30)
CLARA <- clara(top10k_rel_rna[3:27],30,medoids.x=TRUE)
top10k_rel_rna$k30 <- CLARA$clustering
pheatmap(top10k_rel_rna[order(top10k_rel_rna[,28]),][,3:27], cluster_cols=TRUE, cluster_rows=FALSE, border_color=NA, show_rownames=FALSE, annotation_row=top10k_rel_rna[28])

Data integration
gene_res <- rel_rna2[(!rel_rna2$geneID %in% top10k_rel_rna$geneID),] #filter out genes not in top 10k
gene_res$k30 <- NA #add value for genes not clustered
gene_res <- rbind(top10k_rel_rna, gene_res) #combine with top 10k genes with cluster designations
#gene_res$geneID <- sapply(strsplit(gene_res$geneID, split="[.]"), head, 1) #simplify geneIDs by removing version numbers
comb_res <- unique(merge(dREGann, gene_res, by.x="z", by.y="geneID", all.y=T))
colnames(comb_res)[1] <- "geneID"
comb_res <- merge(comb_res, PRO_rel, by.x="closest_peak", by.y="closest_peak", all.x=T) #combine with dREG peak data, keep genes without a closest dREG peak call
comb_res <- comb_res[,c(2:9,39,13:38,10:12,1,40:65)] #reorder columns
Gene-to-Enhancer concordance analysis – this generates a stat ranging from -1 (anti-correlated) to 0 (not correlated) to +1 (correlated) reported as Spearman rho
#note this will produce a lot of errors for rows that don't have a gene and a an enhancer, so I've silenced them here
spear <- c()
i <- 1
while(i<=nrow(comb_res)){
speari <- cor(as.numeric(factor(comb_res[i,11:35])),as.numeric(factor(comb_res[i,41:65])),method="spearman")
spear <- c(spear, speari)
i <- i+1
}
comb_res$Spearman.rho <- spear
Save output
write.table(comb_res, file="weinstock002.final.table.txt", sep="\t", quote=F, row.names=F)
dREGcountsann <- merge(PRO_rel, dREG_readFilt, by.x="closest_peak", by.y="dREGpeakID")
dREGcountsann <- dREGcountsann[,c(1,28:33,2:27)]
write.table(dREGcountsann, file="weinstock002.dREGs.txt", sep="\t", quote=F, row.names=F)
Correct output to include metadata for genes without nearest enhancer calls
library(dplyr)
#remove columns with annotation issue
comb_res_woEnh <- comb_res %>% filter(is.na(geneName))
comb_res_wEnh <- comb_res %>% filter(!is.na(geneName))
#Load original unfiltered annotations
comp_gtf <- read.table("Homo_sapiens.GRCh38.99.ucsc.gtf", sep="\t")
colnames(comp_gtf) <- c("chr", "source", "type", "start", "end", "score", "strand", "phase", "attributes")
#Function to extract metadata from gtf annotation
extract_attributes <- function(gtf_attributes, att_of_interest){
att <- strsplit(as.character(gtf_attributes), "; ")
att <- gsub("\"","",unlist(att))
att <- gsub(";","",unlist(att))
if(!is.null(unlist(strsplit(att[grep(att_of_interest, att)], " ")))){
return( unlist(strsplit(att[grep(att_of_interest, att)], " "))[2])
}else{
return(NA)}
}
#Extract desired information from gtf (geneID, geneName, biotype)
comp_gene <- filter(comp_gtf, type == "gene")
comp_gene$geneID <- unlist(lapply(comp_gene$attributes, extract_attributes, "gene_id"))
comp_gene$geneName <- unlist(lapply(comp_gene$attributes, extract_attributes, "gene_name"))
comp_gene$biotype <- unlist(lapply(comp_gene$attributes, extract_attributes, "gene_biotype"))
#Remove offending columns
#geneName,biotype,attributes,chr,start,end,strand
comb_res_woEnh <- comb_res_woEnh[,c(1,9:66)]
#Add back information
geneInfo <- data.frame("geneID"=comp_gene$geneID, "geneName"=comp_gene$geneName, "biotype"=comp_gene$biotype, "attributes"=comp_gene$attributes, "chr"=comp_gene$chr, "start"=comp_gene$start, "end"=comp_gene$end, "strand"=comp_gene$strand)
comb_res_woEnh_corr <- merge(geneInfo, comb_res_woEnh, by.x="geneID", by.y="geneID", all.y=T)
#Modify geneName and peak_counts
comb_res_woEnh_corr$peak_count <- 0
comb_res_woEnh_corr$geneName <- paste0(comb_res_woEnh_corr$geneName)
#Correcting geneNames in original
comb_res_wEnh$geneName <- substring(comb_res_wEnh$geneName, 1)
comb_res_wEnh$geneName <- paste0(comb_res_wEnh$geneName)
#Combining it all together
comb_res_corr <- rbind(comb_res_wEnh, comb_res_woEnh_corr)
write.table(comb_res_corr, file="weinstock.combined.results.corrected.txt", sep="\t", quote=F, row.names=F)
Combining full annotation to plot based on genomic category
filtered_res <- merge(dREG_annot, comb_res_corr, by.x="peakID", by.y="closest_peak", all.y=F)
write.table(filtered_res, file="Overlaping contribtors.txt", sep='\t', quote=F, row.names=F)
ggplot(filtered_res, aes(x=factor(1), fill=genomicCategory))+geom_bar(width=1)+coord_polar("y") + ggtitle("Overlapping PCA Contributors for Gene Expression and dREGpeak Annotations")

Generating normed counts table by top 50K contributors
rv <- rowVars(assay(rld_pro))
select <- order(rv, decreasing=TRUE)[seq_len(min(50000, length(rv)))]
#Changing the 50000 here will select a Different number of top contributors if desired
pc <- prcomp(t(assay(rld_pro)[select,]))
loadings <- as.data.frame(pc$rotation)
aload <- abs(loadings)
write.table(sweep(aload, 2, colSums(aload), "/"), file="Top 50000 PRO Contributors.txt")
top50k_rel_pro <- PRO_rel[(PRO_rel$closest_peak %in% rownames(aload)),] #filter rel gene dataframe for top 50k
CLARA <- clara(top50k_rel_pro[3:27],3,medoids.x=TRUE)
top50k_rel_pro$k3 <- CLARA$clustering
enhan_res <- PRO_rel[(PRO_rel$closest_peak %in% top50k_rel_pro$closest_peak),] #filter out genes not in top 50k
enhan_res$k3 <- NA #add value for genes not clustered
enhan_res <- top50k_rel_pro #combine with top 50k genes with cluster designations
comb_res <- unique(merge(dREG_annot, enhan_res, by.x="peakID", by.y="closest_peak", all.y=T))
Combination completed, further investigation into clusters ongoing - 8DEC21
LS0tCnRpdGxlOiAiQ29tYmluZWQgUFJPX1JOQSB3ZWIgYWNjZXNzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCkRvY3VtZW50IGNyZWF0aW9uCkxpYnJhcmllcwpgYGB7cn0KCgpsaWJyYXJ5KERFU2VxMikKbGlicmFyeShSc3VicmVhZCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoY2x1c3RlcikKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KGFtYXApCmxpYnJhcnkoTmJDbHVzdCkKbGlicmFyeShkcGx5cikKYGBgCgpTZXQgd29ya2luZyBkaXJlY3RvcnkgdG8gbG9jYWwgd29ya3NwYWNlClNhdmUgUiBtYXJrdXAsIGZlYXR1cmVjb3VudHMgcmVzdWx0cyBhbmQgZnVsbCBndGYgdGhlcmUKUk5BIGZlYXR1cmVjb3VudHMgZ2VuZXJhdGVkIHdpdGggJ0hvbW9fc2FwaWVucy5HUkNoMzguOTkuZ3RmLmd6JyBmaWxlCmBgYHtyfQpzZXR3ZCgiL1VzZXJzL2t1cm9rby9Ecm9wYm94IChQYXJ0bmVycyBIZWFsdGhDYXJlKS9XZWluc3RvY2sgTlRDIENvbGxhYi9FeHBlcmltZW50cy9UQ0wgQ2VsbCBMaW5lcy9EYXRhLzI1IFRDTHMvTUtKIFIgc2NyaXB0cyIpCmdldHdkKCkKYGBgCgpSTkEKCkxvYWQgZmVhdHVyZWNvdW50cyByZXN1bHRzLCBjb25maWd1cmUgYXMgZGF0YSBmcmFtZSBvYmplY3QKU2V0dXAgbWV0YWRhdGEgaW5mb3JtYXRpb24gYW5kIGNoZWNrIG5hbWluZyBjb25zaXN0ZW5jeQpSZW1vdmUgbm9uLWNvdW50cyBjb2x1bW5zIGluIGZjIG9iamVjdApgYGB7cn0KZmMgPC0gcmVhZC50YWJsZSgiV2hvbGVHZW5lQ291bnRzX1dlaW5zdG9jazAwMl9STkEiLCBzZXA9Ilx0IiwgaGVhZGVyPVRSVUUsIHJvdy5uYW1lcz0xKQpmYzIgPC0gYXMuZGF0YS5mcmFtZShmYykKb3JpZ19uYW1lcyA8LSBjb2xuYW1lcyhmYzJbNjozMF0pCmNvbERhdGFfcm5hIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzPW9yaWdfbmFtZXMsIHNhbXBsZT1jKCJERVJMMiIsICJETDQwIiwgIkZFUEQiLCAiSEgiLCAiSFVUNzgiLCAiSFVUMTAyIiwgICJLQVJQQVMyOTkiLCAgIktBUlBBUzM4NCIsICJLSFlHMSIsICJLSUpLIiwgIkw4MiIsICAiTUFDMkEiLCAgIk1KIiwgIk1PVE4xIiwgIk1UQSIsICJNWUxBIiwgIk5LTCIsICJPQ0lMWTEyIiwgIlNlQXgiLCAiU01aMSIsICJTUjc4NiIsICJTVDEiLCAgIlN1OVQwMSIsICJTVURITDEiLCAiU1VQTTIiKSwgc3VidHlwZT1jKCJIU19UQ0wiLCAiQUxLLUFMQ0wiLCAiQUxLLUFMQ0wiLCAgIkNUQ0wiLCAgIkNUQ0wiLCAgIkFUTEwiLCAiQUxLK0FMQ0wiLCAgIlNRR0RfVENMIiwgICJOS0wiLCAiQUxLK0FMQ0wiLCAiQUxLK0FMQ0wiLCAgIkFMSy1BTENMIiwgIkNUQ0wiLCAgIlRfTEdMIiwgIk5LVCIsICJDVENMIiwgIk5LVCIsICAiUFRDTF9OT1MiLCAiQ1RDTCIsICJQVENMX05PUyIsICJBTEsrQUxDTCIsICAiQVRMTCIsICJBVExMIiwgIkFMSytBTENMIiwgIkFMSytBTENMIikpCmFsbChyb3duYW1lcyhjb2xEYXRhX3JuYSkgJWluJSBjb2xuYW1lcyhmYzIpKQpmYzMgPC0gc3Vic2V0KGZjMiwgc2VsZWN0PS1jKENociwgU3RhcnQsIEVuZCwgU3RyYW5kLCBMZW5ndGgpKQpjb2xuYW1lcyhmYzMpIDwtIGMoIkRFUkwyIiwgIkRMNDAiLCAiRkVQRCIsICJISCIsICJIVVQ3OCIsICJIVVQxMDIiLCAgIktBUlBBUzI5OSIsICAiS0FSUEFTMzg0IiwgIktIWUcxIiwgIktJSksiLCAiTDgyIiwgICJNQUMyQSIsICAiTUoiLCAiTU9UTjEiLCAiTVRBIiwgIk1ZTEEiLCAiTktMIiwgIk9DSUxZMTIiLCAiU2VBeCIsICJTTVoxIiwgIlNSNzg2IiwgIlNUMSIsICAiU3U5VDAxIiwgIlNVREhMMSIsICJTVVBNMiIpCmBgYAoKQ3JlYXRlIERFc2VxIG9iamVjdCBhbmQgc2F2ZSBmaWxlIApHZW5lcmF0ZSBub3JtYWxpemF0aW9uIGZhY3RvciB3aXRoIERFc2VxIGRlZmF1bHQKYGBge3J9CmRkc19ybmEgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGE9ZmMzLCBjb2xEYXRhPWNvbERhdGFfcm5hLCBkZXNpZ249fnNhbXBsZSkKZGRzX3JuYSA8LSBlc3RpbWF0ZVNpemVGYWN0b3JzKGRkc19ybmEpCmRlc2VxX3NpemVzX3JuYSA8LSBhcy5kYXRhLmZyYW1lKHNpemVGYWN0b3JzKGRkc19ybmEpKQpyb3cubmFtZXMoZGVzZXFfc2l6ZXNfcm5hKSA8LSBjKCJERVJMMiIsICJETDQwIiwgIkZFUEQiLCAiSEgiLCAiSFVUNzgiLCAiSFVUMTAyIiwgIktBUlBBUzI5OSIsICJLQVJQQVMzODQiLCAiS0hZRzEiLCAiS0lKSyIsICJMODIiLCAgIk1BQzJBIiwgICJNSiIsICJNT1ROMSIsICJNVEEiLCAiTVlMQSIsICJOS0wiLCAiT0NJTFkxMiIsICJTZUF4IiwgIlNNWjEiLCAiU1I3ODYiLCAiU1QxIiwgICJTdTlUMDEiLCAiU1VESEwxIiwgIlNVUE0yIikKZGVzZXFfc2l6ZXNfcm5hCnNhdmVSRFMoZGRzX3JuYSwgZmlsZT0iUk5BX2Rkcy5yZHMiKQpgYGAKCkdlbmVyYXRlIG5vcm0gY291bnRzIGZpbGVzIGFuZCBzYXZlIHRvIGxvY2FsIGRpcmVjdG9yeQpgYGB7cn0KcmF3Y291bnRzX3JuYSA8LSBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHNfcm5hLCBub3JtYWxpemVkPUZBTFNFKSkKbm9ybWNvdW50c19ybmEgPC0gYXMuZGF0YS5mcmFtZShjb3VudHMoZGRzX3JuYSwgbm9ybWFsaXplZD1UUlVFKSkKY29sbmFtZXMocmF3Y291bnRzX3JuYSkgPC0gYygiREVSTDIiLCAiREw0MCIsICJGRVBEIiwgIkhIIiwgIkhVVDc4IiwgIkhVVDEwMiIsICAiS0FSUEFTMjk5IiwgICJLQVJQQVMzODQiLCAiS0hZRzEiLCAiS0lKSyIsICJMODIiLCAgIk1BQzJBIiwgICJNSiIsICJNT1ROMSIsICJNVEEiLCAiTVlMQSIsICJOS0wiLCAiT0NJTFkxMiIsICJTZUF4IiwgIlNNWjEiLCAiU1I3ODYiLCAiU1QxIiwgICJTdTlUMDEiLCAiU1VESEwxIiwgIlNVUE0yIikKY29sbmFtZXMobm9ybWNvdW50c19ybmEpIDwtIGMoIkRFUkwyIiwgIkRMNDAiLCAiRkVQRCIsICJISCIsICJIVVQ3OCIsICJIVVQxMDIiLCAgIktBUlBBUzI5OSIsICAiS0FSUEFTMzg0IiwgIktIWUcxIiwgIktJSksiLCAiTDgyIiwgICJNQUMyQSIsICAiTUoiLCAiTU9UTjEiLCAiTVRBIiwgIk1ZTEEiLCAiTktMIiwgIk9DSUxZMTIiLCAiU2VBeCIsICJTTVoxIiwgIlNSNzg2IiwgIlNUMSIsICAiU3U5VDAxIiwgIlNVREhMMSIsICJTVVBNMiIpCnJvd25hbWVzKHJhd2NvdW50c19ybmEpIDwtIHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhyYXdjb3VudHNfcm5hKSwgc3BsaXQ9IlsuXSIpLCBoZWFkLCAxKQpyb3duYW1lcyhub3JtY291bnRzX3JuYSkgPC0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG5vcm1jb3VudHNfcm5hKSwgc3BsaXQ9IlsuXSIpLCBoZWFkLCAxKQp3cml0ZS50YWJsZShyYXdjb3VudHNfcm5hLCBmaWxlPSJSTkFfcmF3Y291bnRzLnR4dCIsIHNlcD0iXHQiLCBjb2wubmFtZXM9VFJVRSwgcm93Lm5hbWVzPVRSVUUsIHF1b3RlPUZBTFNFKQp3cml0ZS50YWJsZShub3JtY291bnRzX3JuYSwgZmlsZT0iUk5BX25vcm1jb3VudHMudHh0Iiwgc2VwPSJcdCIsIGNvbC5uYW1lcz1UUlVFLCByb3cubmFtZXM9VFJVRSwgcXVvdGU9RkFMU0UpCmBgYAoKRGF0YSB0cmFuc2Zvcm1hdGlvbiBmb3IgcGxvdCBnZW5lcmF0aW9uClRvcCA1MDAgY29udHJpYnV0b3JzIGlzIHRoZSBkZWZhdWx0IGZvciBQQ0EgClNldCAnbnRvcCcgdG8gbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB0aGUgZGRzIG9iamVjdApgYGB7cn0KcmxkX3JuYSA8LSBybG9nKGRkc19ybmEsIGJsaW5kPVRSVUUpCnNhbXBsZURpc3Rzcm5hIDwtIGRpc3QodChhc3NheShybGRfcm5hKSkpCnNhbXBsZURpc3RNdHhybmEgPC0gYXMubWF0cml4KHNhbXBsZURpc3Rzcm5hKQpyb3duYW1lcyhzYW1wbGVEaXN0TXR4cm5hKSA8LSBwYXN0ZTAocmxkX3JuYSRzYW1wbGUpCmNvbG5hbWVzKHNhbXBsZURpc3RNdHhybmEpIDwtIE5VTEwKI0dlbmVyYXRlIFBDQSBwbG90IChpbnRncm91cCBzZXQgZXF1YWwgdG8gZGVzaXJlZCBtZXRhZGF0YSB2YXJpYWJsZSkKcGxvdFBDQShybGRfcm5hLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD02MDY3NikgKyBnZ3RpdGxlKCJSTkEtc2VxIFBDQSIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQUxLK0FMQ0wiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hvY29sYXRlNCIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhybmEpLCBtYXgub3ZlcmxhcHM9NTApCiN0b3AgNTAwIFBDQQpwbG90UENBKHJsZF9ybmEsIGludGdyb3VwID0gInN1YnR5cGUiKSArIGdndGl0bGUoIlJOQS1zZXEgUENBIFRvcCA1MDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkFMSytBTENMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNob2NvbGF0ZTQiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4cm5hKSwgbWF4Lm92ZXJsYXBzPTUwKQojdG9wIDEwMDAKcGxvdFBDQShybGRfcm5hLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xMDAwKSArIGdndGl0bGUoIlJOQS1zZXEgUENBIFRvcCAxMDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJBTEsrQUxDTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaG9jb2xhdGU0IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eHJuYSksIG1heC5vdmVybGFwcz01MCkKI3RvcCA1MDAwCnBsb3RQQ0EocmxkX3JuYSwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9NTAwMCkgKyBnZ3RpdGxlKCJSTkEtc2VxIFBDQSBUb3AgNTAwMCIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQUxLK0FMQ0wiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hvY29sYXRlNCIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhybmEpLCBtYXgub3ZlcmxhcHM9NTApCiN0b3AgMTAwMDAKcGxvdFBDQShybGRfcm5hLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xMDAwMCkgKyBnZ3RpdGxlKCJSTkEtc2VxIFBDQSBUb3AgMTAwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkFMSytBTENMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNob2NvbGF0ZTQiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4cm5hKSwgbWF4Lm92ZXJsYXBzPTUwKQojdG9wIDE1MDAwCnBsb3RQQ0EocmxkX3JuYSwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9MTUwMDApICsgZ2d0aXRsZSgiUk5BLXNlcSBQQ0EgVG9wIDE1MDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJBTEsrQUxDTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaG9jb2xhdGU0IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eHJuYSksIG1heC5vdmVybGFwcz01MCkKYGBgCgpBZGRpdGlvbmFsIGRlbmRyb2dyYW0gcGxvdHMKYGBge3J9CmNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKDksICJCbHVlcyIpKSkoMjU1KQpwaGVhdG1hcChzYW1wbGVEaXN0TXR4cm5hLCBjb2w9Y29sb3JzLCBib3JkZXJfY29sb3I9TkEsIHNob3dfY29sbmFtZXM9RkFMU0UsIHNob3dfcm93bmFtZXM9VFJVRSwKICAgICAgICAgY2x1c3Rlcl9yb3dzPVRSVUUsIGNsdXN0ZXJfY29scz1UUlVFLCBtYWluPSJSTkEgU2FtcGxlIERpc3RhbmNlIENsdXN0ZXJpbmciKQpwbG90KGhjbHVzdChzYW1wbGVEaXN0c3JuYSksIGxhYmVscz1yb3duYW1lcyhzYW1wbGVEaXN0TXR4cm5hKSwgbWFpbj0iUk5BIFNhbXBsZSBEaXN0YW5jZSBEZW5kcm9ncmFtIikKYGBgCgpBc3NlbWJsZSBjb3VudHMgcmVzdWx0cwpgYGB7cn0KYXZnX3JuYSA8LSBkYXRhLmZyYW1lKEVuc2VtYmxJRD1yb3duYW1lcyhub3JtY291bnRzX3JuYSkpCmF2Z19ybmEkREVSTDIgPC0gKG5vcm1jb3VudHNfcm5hJERFUkwyKQphdmdfcm5hJERMNDAgPC0gKG5vcm1jb3VudHNfcm5hJERMNDApCmF2Z19ybmEkRkVQRCA8LSAobm9ybWNvdW50c19ybmEkRkVQRCkKYXZnX3JuYSRISCA8LSAobm9ybWNvdW50c19ybmEkSEgpCmF2Z19ybmEkSFVUNzggPC0gKG5vcm1jb3VudHNfcm5hJEhVVDc4KQphdmdfcm5hJEhVVDEwMiA8LSAobm9ybWNvdW50c19ybmEkSFVUMTAyKQphdmdfcm5hJEtBUlBBUzI5OSA8LSAobm9ybWNvdW50c19ybmEkS0FSUEFTMjk5KQphdmdfcm5hJEtBUlBBUzM4NCA8LSAobm9ybWNvdW50c19ybmEkS0FSUEFTMzg0KQphdmdfcm5hJEtIWUcxIDwtIChub3JtY291bnRzX3JuYSRLSFlHMSkKYXZnX3JuYSRLSUpLIDwtIChub3JtY291bnRzX3JuYSRLSUpLKQphdmdfcm5hJEw4MiA8LSAobm9ybWNvdW50c19ybmEkTDgyKQphdmdfcm5hJE1BQzJBIDwtIChub3JtY291bnRzX3JuYSRNQUMyQSkKYXZnX3JuYSRNSiA8LSAobm9ybWNvdW50c19ybmEkTUopCmF2Z19ybmEkTU9UTjEgPC0gKG5vcm1jb3VudHNfcm5hJE1PVE4xKQphdmdfcm5hJE1UQSA8LSAobm9ybWNvdW50c19ybmEkTVRBKQphdmdfcm5hJE1ZTEEgPC0gKG5vcm1jb3VudHNfcm5hJE1ZTEEpCmF2Z19ybmEkTktMIDwtIChub3JtY291bnRzX3JuYSROS0wpCmF2Z19ybmEkT0NJTFkxMiA8LSAobm9ybWNvdW50c19ybmEkT0NJTFkxMikKYXZnX3JuYSRTZUF4IDwtIChub3JtY291bnRzX3JuYSRTZUF4KQphdmdfcm5hJFNNWjEgPC0gKG5vcm1jb3VudHNfcm5hJFNNWjEpCmF2Z19ybmEkU1I3ODYgPC0gKG5vcm1jb3VudHNfcm5hJFNSNzg2KQphdmdfcm5hJFNUMSA8LSAobm9ybWNvdW50c19ybmEkU1QxKQphdmdfcm5hJFN1OVQwMSA8LSAobm9ybWNvdW50c19ybmEkU3U5VDAxKQphdmdfcm5hJFNVREhMMSA8LSAobm9ybWNvdW50c19ybmEkU1VESEwxKQphdmdfcm5hJFNVUE0yIDwtIChub3JtY291bnRzX3JuYSRTVVBNMikKCmF2Z19ybmEkbWF4IDwtIGFwcGx5KGF2Z19ybmFbYygiREVSTDIiLCAiREw0MCIsICJGRVBEIiwgIkhIIiwgIkhVVDc4IiwgIkhVVDEwMiIsICJLQVJQQVMyOTkiLCAgIktBUlBBUzM4NCIsICJLSFlHMSIsICJLSUpLIiwgIkw4MiIsICAiTUFDMkEiLCAgIk1KIiwgIk1PVE4xIiwgIk1UQSIsICJNWUxBIiwgIk5LTCIsICJPQ0lMWTEyIiwgIlNlQXgiLCAiU01aMSIsICJTUjc4NiIsICJTVDEiLCAgIlN1OVQwMSIsICJTVURITDEiLCAiU1VQTTIiKV0sIDEsIG1heCwgbmEucm09VFJVRSkKcmVsX3JuYSA8LSBkYXRhLmZyYW1lKEVuc2VtYmxJRD1hdmdfcm5hJEVuc2VtYmxJRCkKcmVsX3JuYSRERVJMMiA8LSBhdmdfcm5hJERFUkwyIC8gYXZnX3JuYSRtYXgKcmVsX3JuYSRETDQwIDwtIGF2Z19ybmEkREw0MCAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkRkVQRCA8LSBhdmdfcm5hJEZFUEQgLyBhdmdfcm5hJG1heApyZWxfcm5hJEhIIDwtIGF2Z19ybmEkSEggLyBhdmdfcm5hJG1heApyZWxfcm5hJEhVVDc4IDwtIGF2Z19ybmEkSFVUNzggLyBhdmdfcm5hJG1heApyZWxfcm5hJEhVVDEwMiA8LSBhdmdfcm5hJEhVVDEwMiAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkS0FSUEFTMjk5IDwtIGF2Z19ybmEkS0FSUEFTMjk5IC8gYXZnX3JuYSRtYXgKcmVsX3JuYSRLQVJQQVMzODQgPC0gYXZnX3JuYSRLQVJQQVMzODQgLyBhdmdfcm5hJG1heApyZWxfcm5hJEtIWUcxIDwtIGF2Z19ybmEkS0hZRzEgLyBhdmdfcm5hJG1heApyZWxfcm5hJEtJSksgPC0gYXZnX3JuYSRLSUpLIC8gYXZnX3JuYSRtYXgKcmVsX3JuYSRMODIgPC0gYXZnX3JuYSRMODIgLyBhdmdfcm5hJG1heApyZWxfcm5hJE1BQzJBIDwtIGF2Z19ybmEkTUFDMkEgLyBhdmdfcm5hJG1heApyZWxfcm5hJE1KIDwtIGF2Z19ybmEkTUogLyBhdmdfcm5hJG1heApyZWxfcm5hJE1PVE4xIDwtIGF2Z19ybmEkTU9UTjEgLyBhdmdfcm5hJG1heApyZWxfcm5hJE1UQSA8LSBhdmdfcm5hJE1UQSAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkTVlMQSA8LSBhdmdfcm5hJE1ZTEEgLyBhdmdfcm5hJG1heApyZWxfcm5hJE5LTCA8LSBhdmdfcm5hJE5LTCAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkT0NJTFkxMiA8LSBhdmdfcm5hJE9DSUxZMTIgLyBhdmdfcm5hJG1heApyZWxfcm5hJFNlQXggPC0gYXZnX3JuYSRTZUF4IC8gYXZnX3JuYSRtYXgKcmVsX3JuYSRTTVoxIDwtIGF2Z19ybmEkU01aMSAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkU1I3ODYgPC0gYXZnX3JuYSRTUjc4NiAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkU1QxIDwtIGF2Z19ybmEkU1QxIC8gYXZnX3JuYSRtYXgKcmVsX3JuYSRTdTlUMDEgPC0gYXZnX3JuYSRTdTlUMDEgLyBhdmdfcm5hJG1heApyZWxfcm5hJFNVREhMMSA8LSBhdmdfcm5hJFNVREhMMSAvIGF2Z19ybmEkbWF4CnJlbF9ybmEkU1VQTTIgPC0gYXZnX3JuYSRTVVBNMiAvIGF2Z19ybmEkbWF4CmBgYAoKRGF0YSB0cmFuc2Zvcm0gZm9yIHZhcmlhbmNlIGFzc2Vzc21lbnQgYW5kIHN1Yi1jbHVzdGVyaW5nCmBgYHtyfQpydjEgPC0gcm93VmFycyhhc3NheShybGRfcm5hKSkKc2VsZWN0MSA8LSBvcmRlcihydjEsIGRlY3JlYXNpbmc9VFJVRSkKcGMxIDwtIHByY29tcCh0KGFzc2F5KHJsZF9ybmEpW3NlbGVjdDEsXSkpCmxvYWRpbmdzMSA8LSBhcy5kYXRhLmZyYW1lKHBjMSRyb3RhdGlvbikKYWxvYWQxIDwtIGFicyhsb2FkaW5nczEpCnBjUmFuayA8LSBkYXRhLmZyYW1lKCJFbnNlbWJsSUQiPXJvd25hbWVzKGxvYWRpbmdzMSksICJQQ0EucmFuayI9c2VxLmludChucm93KGxvYWRpbmdzMSkpKQpzd2VlcChhbG9hZDEsIDIsIGNvbFN1bXMoYWxvYWQxKSwgIi8iKQoKcGVha1ZhciA8LSBkYXRhLmZyYW1lKCJFbnNlbWJsSUQiPXJvd25hbWVzKGFzc2F5KHJsZF9ybmEpKSkKcGVha1ZhciRybG9nLnZhcmlhbmNlIDwtIHJvd1ZhcnMoYXMubWF0cml4KGFzc2F5KHJsZF9ybmEpKSkKcGVha1ZhciA8LSBtZXJnZShwY1JhbmssIHBlYWtWYXIsIGJ5Lng9IkVuc2VtYmxJRCIsIGJ5Lnk9IkVuc2VtYmxJRCIpCmdncGxvdChwZWFrVmFyLCBhZXMoeD1QQ0EucmFuaywgeT1ybG9nLnZhcmlhbmNlKSkgKyBnZW9tX2xpbmUoKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKDUwMCwxMDAwLDIwMDAsNTAwMCwxMDAwMCwxMDAwMCwxNTAwMCksIGxpbmV0eXBlPSJkb3R0ZWQiKSArIGdndGl0bGUoIlZhcmlhbmNlIHBlciBQQyBDb250cmlidXRvciIpCgojYWRkIHBsb3Qgb2YgZnJhY3Rpb24gb2YgZXhwbGFpbmVkIHZhcmlhbmNlLi4gcnVubmluZyBzdW0gLyB0b3RhbCB2cyByYW5rCnBlYWtWYXIgPC0gcGVha1ZhcltvcmRlcihwZWFrVmFyJFBDQS5yYW5rKSxdCnBlYWtWYXIkY3VtdWxhdGl2ZS5WYXJpYW5jZSA8LSBjdW1zdW0ocGVha1ZhciRybG9nLnZhcmlhbmNlKS9zdW0ocGVha1ZhciRybG9nLnZhcmlhbmNlKQpnZ3Bsb3QocGVha1ZhciwgYWVzKHg9UENBLnJhbmssIHk9Y3VtdWxhdGl2ZS5WYXJpYW5jZSkpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9Yyg1MDAsMTAwMCwyMDAwLDUwMDAsMTAwMDAsMTAwMDAsMTUwMDApLCBsaW5ldHlwZT0iZG90dGVkIikgKyBnZ3RpdGxlKCJDdW11bGF0aXZlIFZhcmlhbmNlIHBlciBQQyBSYW5rIikKYGBgCgpSZW1vdmluZyBBbGsrQUxDTCB0byBkZXRlcm1pbmUgaWYgUENBIHNlcGFyYXRpb24gaW1wcm92ZXMKYGBge3J9CmRkc19zdWIgPC0gZGRzX3JuYVssLWMoNywxMCwxMSwyMSwyNCwyNSldICNFeGNsdWRpbmcgc2FtcGxlIG51bWJlcnMgb2YgdGhlIEFMSytBTENMIAplc3RpbWF0ZVNpemVGYWN0b3JzKGRkc19zdWIpICNNdXN0IHJlLWNhbGN1bGF0ZSBzaXplIGZhY3RvcnMgYWZ0ZXIgcmVtb3Zpbmcgc2FtcGxlcwpkZHNfc3ViCgpybGRfc3ViIDwtIHJsb2coZGRzX3N1YiwgYmxpbmQ9VFJVRSkKY29sbmFtZXMocmxkX3N1YikgPC0gcGFzdGUwKGRkc19zdWIkc2FtcGxlKQpzYW1wbGVEaXN0c19zdWIgPC0gZGlzdCh0KGFzc2F5KHJsZF9zdWIpKSkKc2FtcGxlRGlzdE10eF9zdWIgPC0gYXMubWF0cml4KHNhbXBsZURpc3RzX3N1YikKcm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpIDwtIGNvbG5hbWVzKHJsZF9zdWIpCmNvbG5hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSA8LSBOVUxMCmhjbHVzdF9zdWIgPC0gaGNsdXN0KHNhbXBsZURpc3RzX3N1YikKCnBsb3QoaGNsdXN0X3N1YiwgbGFiZWxzPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWFpbj0iUk5BLXNlcSBzdWJzZXQgR2VuZSBEZW5kcm9ncmFtIikKCmBgYAoKUENBcwpgYGB7cn0KcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIikgKyBnZ3RpdGxlKCJSTkEtc2VxIHN1YnNldCBQQ0EgVG9wIDUwMCIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X3N1YiksIG1heC5vdmVybGFwcz01MCkKCnBsb3RQQ0EocmxkX3N1YiwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9MTAwMCkgKyBnZ3RpdGxlKCJSTkEtc2VxIHN1YnNldCBQQ0EgVG9wIDEwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpLCBtYXgub3ZlcmxhcHM9NTApCgpwbG90UENBKHJsZF9zdWIsIGludGdyb3VwID0gInN1YnR5cGUiLCBudG9wPTUwMDApICsgZ2d0aXRsZSgiUk5BLXNlcSBzdWJzZXQgUENBIFRvcCA1MDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xMDAwMCkgKyBnZ3RpdGxlKCJSTkEtc2VxIHN1YnNldCBQQ0EgVG9wIDEwMDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xNTAwMCkgKyBnZ3RpdGxlKCJSTkEtc2VxIHN1YnNldCBQQ0EgVG9wIDE1MDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD02MDY3NikgKyBnZ3RpdGxlKCJSTkEtc2VxIHN1YnNldCBQQ0EgQWxsIENvbnRyaWJ1dG9ycyIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X3N1YiksIG1heC5vdmVybGFwcz01MCkKYGBgCgpQQ0EgdG9wIGNvbnRyaWJ1dG9ycyBzZWxlY3Rpb24gKDVLIHRvIDIwSykKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcnYgPC0gcm93VmFycyhhc3NheShybGRfcm5hKSkKc2VsZWN0IDwtIG9yZGVyKHJ2LCBkZWNyZWFzaW5nPVRSVUUpW3NlcV9sZW4obWluKDEwMDAwLCBsZW5ndGgocnYpKSldIAojQ2hhbmdpbmcgdGhlIDEwMDAwIGhlcmUgd2lsbCBzZWxlY3QgYSBEaWZmZXJlbnQgbnVtYmVyIG9mIHRvcCBjb250cmlidXRvcnMgaWYgZGVzaXJlZApwYyA8LSBwcmNvbXAodChhc3NheShybGRfcm5hKVtzZWxlY3QsXSkpCmxvYWRpbmdzIDwtIGFzLmRhdGEuZnJhbWUocGMkcm90YXRpb24pCmFsb2FkIDwtIGFicyhsb2FkaW5ncykKd3JpdGUudGFibGUoc3dlZXAoYWxvYWQsIDIsIGNvbFN1bXMoYWxvYWQpLCAiLyIpLCBmaWxlPSJUb3AgMTAwMDAgUk5BIFBDQSBDb250cmlidXRvcnMudHh0IikKI0NsZWFuIHVwIHZhcmlhYmxlcwpybShydikKcm0oc2VsZWN0KQpybShwYykKcm0obG9hZGluZ3MpCiNNZXJnZSB0b3AgMTAwMDAgZWxlbWVudHMgd2l0aCB0aGVpciBhbm5vdGF0aW9ucwp0b3AxMDAwMCA8LSByZWxfcm5hWyhyZWxfcm5hJEVuc2VtYmxJRCAlaW4lIHJvd25hbWVzKGFsb2FkKSksXQp3cml0ZS50YWJsZSh0b3AxMDAwMCwgZmlsZT0iVG9wMTAwMDAudHh0Iiwgc2VwPSdcdCcpCgpSTkFfcmVsIDwtIHJlbF9ybmFbKHJlbF9ybmEkRW5zZW1ibElEICVpbiUgdG9wMTAwMDAkRW5zZW1ibElEKSxdCnNhdmVSRFMoUk5BX3JlbCwgZmlsZT0iUk5BX3JlbC5yZHMiKQpjb2xuYW1lcyhSTkFfcmVsKSA8LSBjKCJFbnNlbWJsSUQiLCAiREVSTDIuZ2VuZSIsICJETDQwLmdlbmUiLCAiRkVQRC5nZW5lIiwgIkhILmdlbmUiLCAiSFVUNzguZ2VuZSIsICJIVVQxMDIuZ2VuZSIsICAiS0FSUEFTMjk5LmdlbmUiLCAgIktBUlBBUzM4NC5nZW5lIiwgIktIWUcxLmdlbmUiLCAiS0lKSy5nZW5lIiwgIkw4Mi5nZW5lIiwgICJNQUMyQS5nZW5lIiwgICJNSi5nZW5lIiwgIk1PVE4xLmdlbmUiLCAiTVRBLmdlbmUiLCAiTVlMQS5nZW5lIiwgIk5LTC5nZW5lIiwgIk9DSUxZMTIuZ2VuZSIsICJTZUF4LmdlbmUiLCAiU01aMS5nZW5lIiwgIlNSNzg2LmdlbmUiLCAiU1QxLmdlbmUiLCAgIlN1OVQwMS5nZW5lIiwgIlNVREhMMS5nZW5lIiwgIlNVUE0yLmdlbmUiKQpoZWFkKHRvcDEwMDAwKQpoZWFkKFJOQV9yZWwpCiNHYXAgU3RhdCBDYWxjdWxhdGlvbgojc2V0LnNlZWQoNDIpIAojVGhpcyBzZXRzIHRoZSByYW5kb20gbnVtYmVyIGdlbmVyYXRvciBzZWVkIHNvIGl0IHdpbGwgYWx3YXlzIHByb2R1Y2UgdGhlIHNhbWUgcmVzdWx0LiBZb3UgY2FuIHBpY2sgd2hhdGV2ZXIgbnVtYmVyIHlvdSdkIGxpa2UuCiNnYXBfc3RhdCA8LSBjbHVzR2FwKFJOQV9yZWxbMjoyNl0sIEZVTiA9IGttZWFucywgbnN0YXJ0ID0gMjAsIEsubWF4ID0gMjQsIEIgPSA1MCkgCiMuLi4gPSBudW1iZXIgb2Ygc2FtcGxlcyArIDEKI0NsdXN0ZXIgU3RhdCBQbG90cwojZnZpel9uYmNsdXN0KHRvcDEwMDAwWzI6MjZdLCBrbWVhbnMsIG1ldGhvZD0id3NzIiwgay5tYXg9MjQpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiRWxib3cgUGxvdCIpCiNmdml6X2dhcF9zdGF0KGdhcF9zdGF0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkdhcCBTdGF0aXN0aWMiKQojZnZpel9uYmNsdXN0KHRvcDEwMDAwWzI6MjZdLCBrbWVhbnMsIG1ldGhvZD0ic2lsaG91ZXR0ZSIsIGsubWF4PTI0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIlNpbGhvdWV0dGUgUGxvdCIpCiNrLW1lYW5zIENsdXN0ZXJpbmcKQ0xBUkFrMjAgPC0gY2xhcmEodG9wMTAwMDBbMjoyNl0sMjAsbWVkb2lkcy54PVRSVUUpCkNMQVJBazI2IDwtIGNsYXJhKHRvcDEwMDAwWzI6MjZdLDI2LG1lZG9pZHMueD1UUlVFKQpDTEFSQWszMCA8LSBjbGFyYSh0b3AxMDAwMFsyOjI2XSwzMCxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrMzYgPC0gY2xhcmEodG9wMTAwMDBbMjoyNl0sMzYsbWVkb2lkcy54PVRSVUUpCkNMQVJBazE1IDwtIGNsYXJhKHRvcDEwMDAwWzI6MjZdLDE1LG1lZG9pZHMueD1UUlVFKQpDTEFSQWsyNSA8LSBjbGFyYSh0b3AxMDAwMFsyOjI2XSwyNSxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrMjIgPC0gY2xhcmEodG9wMTAwMDBbMjoyNl0sMjIsbWVkb2lkcy54PVRSVUUpCgp0b3AxMDAwMCRrMjAgPC0gQ0xBUkFrMjAkY2x1c3RlcmluZwp0b3AxMDAwMCRrMjYgPC0gQ0xBUkFrMjYkY2x1c3RlcmluZwp0b3AxMDAwMCRrMzAgPC0gQ0xBUkFrMzAkY2x1c3RlcmluZwp0b3AxMDAwMCRrMzYgPC0gQ0xBUkFrMzYkY2x1c3RlcmluZwp0b3AxMDAwMCRrMTUgPC0gQ0xBUkFrMTUkY2x1c3RlcmluZwp0b3AxMDAwMCRrMTUgPC0gQ0xBUkFrMTUkY2x1c3RlcmluZwp0b3AxMDAwMCRrMjUgPC0gQ0xBUkFrMjUkY2x1c3RlcmluZwp0b3AxMDAwMCRrMjIgPC0gQ0xBUkFrMjIkY2x1c3RlcmluZwoKCiNEaXNwbGF5aW5nIEhlYXRtYXBzCiNrLW1lYW5zIDIwCnBoZWF0bWFwKHRvcDEwMDAwW29yZGVyKHRvcDEwMDAwWywgMjYrMV0pLF1bLDI6MjZdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXRvcDEwMDAwWzI2KzFdKQojay1tZWFucyAyNgpwaGVhdG1hcCh0b3AxMDAwMFtvcmRlcih0b3AxMDAwMFssIDI2KzJdKSxdWywyOjI2XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz10b3AxMDAwMFsyNisyXSkKI2stbWVhbnMgMzAKcGhlYXRtYXAodG9wMTAwMDBbb3JkZXIodG9wMTAwMDBbLCAyNiszXSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9dG9wMTAwMDBbMjYrM10pCiNrLW1lYW5zIDM2CnBoZWF0bWFwKHRvcDEwMDAwW29yZGVyKHRvcDEwMDAwWywgMjYrNF0pLF1bLDI6MjZdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXRvcDEwMDAwWzI2KzRdKQojay1tZWFucyAxNQpwaGVhdG1hcCh0b3AxMDAwMFtvcmRlcih0b3AxMDAwMFssIDI2KzVdKSxdWywyOjI2XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz10b3AxMDAwMFsyNis1XSkKI2stbWVhbnMgMjUKcGhlYXRtYXAodG9wMTAwMDBbb3JkZXIodG9wMTAwMDBbLCAyNis2XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9dG9wMTAwMDBbMjYrNl0pCiNrLW1lYW5zIDIyIApwaGVhdG1hcCh0b3AxMDAwMFtvcmRlcih0b3AxMDAwMFssIDI2KzddKSxdWywyOjI2XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz10b3AxMDAwMFsyNis3XSkKYGBgCgotLVJOQSBFTkQtLQoKUFJPCgpgYGB7cn0KI1ByZXBhcmUgZFJFRyBwZWFrIHNhZiBmb3IgZmVhdHVyZUNvdW50cwpkUkVHIDwtIHJlYWQudGFibGUoIlRDTHNfczAuNXAwLjAyNV9maWx0ZXJlZC5iZWQiKQpjb2xuYW1lcyhkUkVHKSA8LSBjKCJjaHJvbW9zb21lIiwgInN0YXJ0IiwgImVuZCIsICJkUkVHcGVha0lEIiwgImRSRUdzY29yZSIsICJzdHJhbmQiLCAiY2VudGVyU3RhcnQiLAogICAgICAgICAgICAgICAgICAgICJjZW50ZXJFbmQiKQp3cml0ZS50YWJsZShkUkVHLCBmaWxlPSJkUkVHIHJlYWR0YWJsZS50eHQiLCBzZXA9Ilx0IiwgcXVvdGU9Riwgcm93Lm5hbWVzPUYpCmRSRUdzYWYgPC0gZGF0YS5mcmFtZSgiR2VuZUlEIj1kUkVHJGRSRUdwZWFrSUQsICJDaHIiPWRSRUckY2hyb21vc29tZSwgIlN0YXJ0Ij1kUkVHJHN0YXJ0LCAiRW5kIj1kUkVHJGVuZCwgIlN0cmFuZCI9IisiKQp3cml0ZS50YWJsZShkUkVHc2FmLCBmaWxlPSJkUkVHLnNhZiIsIHNlcD0iXHQiLCBxdW90ZT1GLCByb3cubmFtZXM9RikKI0xvYWQgc2FtcGxlIFNBTSBmaWxlIGxpc3QKI3Byb2ZpbGVzIDwtIGMoIiIpCgojUnVuIGZlYXV0cmVDb3VudHMKI2ZjX2RSRUcgPC0gZmVhdHVyZUNvdW50cyhwcm9maWxlcywgYW5ub3QuZXh0PWRSRUdzYWYsIGlzR1RGQW5ub3RhdGlvbkZpbGU9RkFMU0UsIG1pbk1RUz0xMCwgY291bnRDaGltZXJpY0ZyYWdtZW50cz1GQUxTRSwgaXNQYWlyZWRFbmQ9RkFMU0UsIHN0cmFuZFNwZWNpZmljPTAsIG50aHJlYWRzPTgpCmZjX3BybyA8LSByZWFkLnRhYmxlKCJkUkVHQ291bnRzX1dlaW5zdG9jazAwMl9wcm8iLCBoZWFkZXI9VCwgcm93Lm5hbWVzPTEpCmZjX3BybyA8LSBhcy5kYXRhLmZyYW1lKGZjX3BybykKZmNfcHJvIDwtIHN1YnNldChmY19wcm8sIHNlbGVjdD0tYyhDaHIsIFN0YXJ0LCBFbmQsIFN0cmFuZCwgTGVuZ3RoKSkKY29sbmFtZXMoZmNfcHJvKSA8LSBjKCJIVVQxMDIiLCAiU1QxIiwgIlN1OVQwMSIsICJLQVJQQVMyOTkiLCAiTDgyIiwgIlNVUE0yIiwgIlNNWjEiLCAiTVlMQSIsICJNQUMyQSIsICJLSUpLIiwgIlNSNzg2IiwgIkZFUEQiLCAiS0FSUEFTMzg0IiwgIkRMNDAiLCAiT0NJTFkxMiIsICJIVVQ3OCIsICJISCIsICJNSiIsICJNVEEiLCAiTU9UTjEiLCAiTktMIiwgIkRFUkwyIiwgIktIWUcxIiwgIlNlQXgiLCAiU1VESEwxIikKCiNMb2FkIHNhbXBsZSBtZXRhZGF0YSAoY2FuIGFkZCBhcyBtdWNoIHNhbXBsZSBtZXRhZGF0YSBhcyBkZXNpcmVkIGluY2x1ZGluZyBjZWxsIHR5cGUsIGRydWcgdHJlYXRtZW50LCBldGMpCmNvbERhdGFfcHJvIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzPWNvbG5hbWVzKGZjX3BybyRjb3VudHMpLCBzYW1wbGU9YygiSFVUMTAyIiwgIlNUMSIsICJTdTlUMDEiLCAiS0FSUEFTMjk5IiwgIkw4MiIsICJTVVBNMiIsICJTTVoxIiwgIk1ZTEEiLCAiTUFDMkEiLCAiS0lKSyIsICJTUjc4NiIsICJGRVBEIiwgIktBUlBBUzM4NCIsICJETDQwIiwgIk9DSUxZMTIiLCAiSFVUNzgiLCAiSEgiLCAiTUoiLCAiTVRBIiwgIk1PVE4xIiwgIk5LTCIsICJERVJMMiIsICJLSFlHMSIsICJTZUF4IiwgIlNVREhMMSIpLCBzdWJ0eXBlPWMoIkFUTEwiLCAiQVRMTCIsICJBVExMIiwgIkFMSytBTENMIiwgIkFMSytBTENMIiwgIkFMSytBTENMIiwgIlBUQ0xfTk9TIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiQUxLK0FMQ0wiLCAiQUxLK0FMQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiQUxLLUFMQ0wiLCAiUFRDTF9OT1MiLCAiQ1RDTCIsICJDVENMIiwgIkNUQ0wiLCAiTktUIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiTktMIiwgIkNUQ0wiLCAiQUxLK0FMQ0wiKSkKYWxsKChjb2xEYXRhX3BybyRzYW1wbGUpICVpbiUgY29sbmFtZXMoZmNfcHJvKSkKCiNDcmVhdGUgREVTZXEgb2JqZWN0IGFuZCBnZW5lcmF0ZSBub3JtYWxpemVkIGNvdW50cwpkZHNfcHJvIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhPWZjX3BybywgY29sRGF0YT1jb2xEYXRhX3BybywgZGVzaWduPX5zYW1wbGUpCmRkc19wcm8gPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhkZHNfcHJvKQpkZXNlcV9zaXplc19wcm8gPC0gYXMuZGF0YS5mcmFtZShzaXplRmFjdG9ycyhkZHNfcHJvKSkKZGVzZXFfc2l6ZXNfcHJvCnZhcmlhYmxlLm5hbWVzKGRkc19wcm8pCgprZWVwIDwtIHJvd01heChjb3VudHMoZGRzX3Bybywgbm9ybWFsaXplPVRSVUUpKSA+PSAyNQpkZHNfcHJvIDwtIGRkc19wcm9ba2VlcCxdCnNhdmVSRFMoZGRzX3BybywgZmlsZT0iZFJFR19kZHMucmRzIikKZFJFR19yZWFkRmlsdCA8LSBkUkVHW2RSRUckZFJFR3BlYWtJRCAlaW4lIHJvd25hbWVzKGRkc19wcm8pLF0Kd3JpdGUudGFibGUoZFJFR19yZWFkRmlsdCwgZmlsZT0iZFJFR3BlYWtzLnJlYWRGaWx0LmJlZCIsIHNlcD0iXHQiLCBjb2wubmFtZXM9RkFMU0UsIHJvdy5uYW1lcz1GQUxTRSwKICAgICAgICAgICAgcXVvdGU9RkFMU0UpCmBgYAoKR2VuZXJhdGUgbm9ybSBjb3VudHMgZmlsZXMgYW5kIHNhdmUgdG8gbG9jYWwgZGlyZWN0b3J5CmBgYHtyfQpyYXdjb3VudHNfcHJvIDwtIGFzLmRhdGEuZnJhbWUoY291bnRzKGRkc19wcm8sIG5vcm1hbGl6ZWQ9RkFMU0UpKQpub3JtY291bnRzX3BybyA8LSBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHNfcHJvLCBub3JtYWxpemVkPVRSVUUpKQpjb2xuYW1lcyhyYXdjb3VudHNfcHJvKSA8LSBjKCJIVVQxMDIiLCAiU1QxIiwgIlN1OVQwMSIsICJLQVJQQVMyOTkiLCAiTDgyIiwgIlNVUE0yIiwgIlNNWjEiLCAiTVlMQSIsICJNQUMyQSIsICJLSUpLIiwgIlNSNzg2IiwgIkZFUEQiLCAiS0FSUEFTMzg0IiwgIkRMNDAiLCAiT0NJTFkxMiIsICJIVVQ3OCIsICJISCIsICJNSiIsICJNVEEiLCAiTU9UTjEiLCAiTktMIiwgIkRFUkwyIiwgIktIWUcxIiwgIlNlQXgiLCAiU1VESEwxIikKY29sbmFtZXMobm9ybWNvdW50c19wcm8pIDwtIGMoIkhVVDEwMiIsICJTVDEiLCAiU3U5VDAxIiwgIktBUlBBUzI5OSIsICJMODIiLCAiU1VQTTIiLCAiU01aMSIsICJNWUxBIiwgIk1BQzJBIiwgIktJSksiLCAiU1I3ODYiLCAiRkVQRCIsICJLQVJQQVMzODQiLCAiREw0MCIsICJPQ0lMWTEyIiwgIkhVVDc4IiwgIkhIIiwgIk1KIiwgIk1UQSIsICJNT1ROMSIsICJOS0wiLCAiREVSTDIiLCAiS0hZRzEiLCAiU2VBeCIsICJTVURITDEiKQp3cml0ZS50YWJsZShyYXdjb3VudHNfcHJvLCBmaWxlPSJwcm9fcmF3Y291bnRzLnR4dCIsIHNlcD0iXHQiLCBjb2wubmFtZXM9VFJVRSwgcm93Lm5hbWVzPVRSVUUsIHF1b3RlPUZBTFNFKQp3cml0ZS50YWJsZShub3JtY291bnRzX3BybywgZmlsZT0icHJvX25vcm1jb3VudHMudHh0Iiwgc2VwPSJcdCIsIGNvbC5uYW1lcz1UUlVFLCByb3cubmFtZXM9VFJVRSwgcXVvdGU9RkFMU0UpCmBgYAoKRGF0YSB0cmFuc2Zvcm1hdGlvbiBmb3IgcGxvdCBnZW5lcmF0aW9uClRvcCA1MDAgY29udHJpYnV0b3JzIGlzIHRoZSBkZWZhdWx0IGZvciBQQ0EgClNldCAnbnRvcCcgdG8gbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB0aGUgZGRzIG9iamVjdApgYGB7cn0KcmxkX3BybyA8LSBybG9nKGRkc19wcm8sIGJsaW5kPVRSVUUpCnNhbXBsZURpc3RzcHJvIDwtIGRpc3QodChhc3NheShybGRfcHJvKSkpCnNhbXBsZURpc3RNdHhwcm8gPC0gYXMubWF0cml4KHNhbXBsZURpc3RzcHJvKQpyb3duYW1lcyhzYW1wbGVEaXN0TXR4cHJvKSA8LSBwYXN0ZTAocmxkX3BybyRzYW1wbGUpCmNvbG5hbWVzKHNhbXBsZURpc3RNdHhwcm8pIDwtIE5VTEwKI0dlbmVyYXRlIFBDQSBwbG90IChpbnRncm91cCBzZXQgZXF1YWwgdG8gZGVzaXJlZCBtZXRhZGF0YSB2YXJpYWJsZSkKcGxvdFBDQShybGRfcHJvLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xMjA4ODgpICsgZ2d0aXRsZSgicHJvLXNlcSBQQ0EiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkFMSytBTENMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNob2NvbGF0ZTQiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4cHJvKSwgbWF4Lm92ZXJsYXBzPTUwKQojdG9wIDUwMCBQQ0EKcGxvdFBDQShybGRfcHJvLCBpbnRncm91cCA9ICJzdWJ0eXBlIikgKyBnZ3RpdGxlKCJwcm8tc2VxIFBDQSBUb3AgNTAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJBTEsrQUxDTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaG9jb2xhdGU0IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eHBybyksIG1heC5vdmVybGFwcz01MCkKI3RvcCAxMDAwIFBDQQpwbG90UENBKHJsZF9wcm8sIGludGdyb3VwID0gInN1YnR5cGUiLCBudG9wPTEwMDApICsgZ2d0aXRsZSgicHJvLXNlcSBQQ0EgVG9wIDEwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkFMSytBTENMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNob2NvbGF0ZTQiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4cHJvKSwgbWF4Lm92ZXJsYXBzPTUwKQojdG9wIDUwMDAgUENBCnBsb3RQQ0EocmxkX3BybywgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9NTAwMCkgKyBnZ3RpdGxlKCJwcm8tc2VxIFBDQSBUb3AgNTAwMCIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQUxLK0FMQ0wiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hvY29sYXRlNCIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhwcm8pLCBtYXgub3ZlcmxhcHM9NTApCiN0b3AgMTAwMDAgUENBCnBsb3RQQ0EocmxkX3BybywgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9MTAwMDApICsgZ2d0aXRsZSgicHJvLXNlcSBQQ0EgVG9wIDEwMDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJBTEsrQUxDTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaG9jb2xhdGU0IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eHBybyksIG1heC5vdmVybGFwcz01MCkKI3RvcCAxNTAwMCBQQ0EKcGxvdFBDQShybGRfcHJvLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xNTAwMCkgKyBnZ3RpdGxlKCJwcm8tc2VxIFBDQSBUb3AgMTUwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkFMSytBTENMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNob2NvbGF0ZTQiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4cHJvKSwgbWF4Lm92ZXJsYXBzPTUwKQojdG9wIDIwMDAwIFBDQQpwbG90UENBKHJsZF9wcm8sIGludGdyb3VwID0gInN1YnR5cGUiLCBudG9wPTIwMDAwKSArIGdndGl0bGUoInByby1zZXEgUENBIFRvcCAyMDAwMCIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQUxLK0FMQ0wiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hvY29sYXRlNCIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhwcm8pLCBtYXgub3ZlcmxhcHM9NTApCmBgYAoKQWRkaXRpb25hbCBkZW5kcm9ncmFtIHBsb3RzCmBgYHtyfQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSkpKDI1NSkKcGhlYXRtYXAoc2FtcGxlRGlzdE10eHBybywgY29sPWNvbG9ycywgYm9yZGVyX2NvbG9yPU5BLCBzaG93X2NvbG5hbWVzPUZBTFNFLCBzaG93X3Jvd25hbWVzPVRSVUUsCiAgICAgICAgIGNsdXN0ZXJfcm93cz1UUlVFLCBjbHVzdGVyX2NvbHM9VFJVRSwgbWFpbj0icHJvIFNhbXBsZSBEaXN0YW5jZSBDbHVzdGVyaW5nIikKcGxvdChoY2x1c3Qoc2FtcGxlRGlzdHNwcm8pLCBsYWJlbHM9cm93bmFtZXMoc2FtcGxlRGlzdE10eHBybyksIG1haW49InBybyBTYW1wbGUgRGlzdGFuY2UgRGVuZHJvZ3JhbSIpCmBgYAoKQXNzZW1ibGUgY291bnRzIHJlc3VsdHMKYGBge3J9CmF2Z19wcm8gPC0gZGF0YS5mcmFtZShwZWFrSUQ9cm93bmFtZXMobm9ybWNvdW50c19wcm8pKQphdmdfcHJvJERFUkwyIDwtIChub3JtY291bnRzX3BybyRERVJMMikKYXZnX3BybyRETDQwIDwtIChub3JtY291bnRzX3BybyRETDQwKQphdmdfcHJvJEZFUEQgPC0gKG5vcm1jb3VudHNfcHJvJEZFUEQpCmF2Z19wcm8kSEggPC0gKG5vcm1jb3VudHNfcHJvJEhIKQphdmdfcHJvJEhVVDc4IDwtIChub3JtY291bnRzX3BybyRIVVQ3OCkKYXZnX3BybyRIVVQxMDIgPC0gKG5vcm1jb3VudHNfcHJvJEhVVDEwMikKYXZnX3BybyRLQVJQQVMyOTkgPC0gKG5vcm1jb3VudHNfcHJvJEtBUlBBUzI5OSkKYXZnX3BybyRLQVJQQVMzODQgPC0gKG5vcm1jb3VudHNfcHJvJEtBUlBBUzM4NCkKYXZnX3BybyRLSFlHMSA8LSAobm9ybWNvdW50c19wcm8kS0hZRzEpCmF2Z19wcm8kS0lKSyA8LSAobm9ybWNvdW50c19wcm8kS0lKSykKYXZnX3BybyRMODIgPC0gKG5vcm1jb3VudHNfcHJvJEw4MikKYXZnX3BybyRNQUMyQSA8LSAobm9ybWNvdW50c19wcm8kTUFDMkEpCmF2Z19wcm8kTUogPC0gKG5vcm1jb3VudHNfcHJvJE1KKQphdmdfcHJvJE1PVE4xIDwtIChub3JtY291bnRzX3BybyRNT1ROMSkKYXZnX3BybyRNVEEgPC0gKG5vcm1jb3VudHNfcHJvJE1UQSkKYXZnX3BybyRNWUxBIDwtIChub3JtY291bnRzX3BybyRNWUxBKQphdmdfcHJvJE5LTCA8LSAobm9ybWNvdW50c19wcm8kTktMKQphdmdfcHJvJE9DSUxZMTIgPC0gKG5vcm1jb3VudHNfcHJvJE9DSUxZMTIpCmF2Z19wcm8kU2VBeCA8LSAobm9ybWNvdW50c19wcm8kU2VBeCkKYXZnX3BybyRTTVoxIDwtIChub3JtY291bnRzX3BybyRTTVoxKQphdmdfcHJvJFNSNzg2IDwtIChub3JtY291bnRzX3BybyRTUjc4NikKYXZnX3BybyRTVDEgPC0gKG5vcm1jb3VudHNfcHJvJFNUMSkKYXZnX3BybyRTdTlUMDEgPC0gKG5vcm1jb3VudHNfcHJvJFN1OVQwMSkKYXZnX3BybyRTVURITDEgPC0gKG5vcm1jb3VudHNfcHJvJFNVREhMMSkKYXZnX3BybyRTVVBNMiA8LSAobm9ybWNvdW50c19wcm8kU1VQTTIpCgphdmdfcHJvJG1heCA8LSBhcHBseShhdmdfcHJvW2MoIkRFUkwyIiwgIkRMNDAiLCAiRkVQRCIsICJISCIsICJIVVQ3OCIsICJIVVQxMDIiLCAgIktBUlBBUzI5OSIsICAiS0FSUEFTMzg0IiwgIktIWUcxIiwgIktJSksiLCAiTDgyIiwgICJNQUMyQSIsICAiTUoiLCAiTU9UTjEiLCAiTVRBIiwgIk1ZTEEiLCAiTktMIiwgIk9DSUxZMTIiLCAiU2VBeCIsICJTTVoxIiwgIlNSNzg2IiwgIlNUMSIsICAiU3U5VDAxIiwgIlNVREhMMSIsICJTVVBNMiIpXSwgMSwgbWF4LCBuYS5ybT1UUlVFKQpyZWxfcHJvIDwtIGRhdGEuZnJhbWUocGVha0lEPWF2Z19wcm8kcGVha0lEKQpyZWxfcHJvJERFUkwyIDwtIGF2Z19wcm8kREVSTDIgLyBhdmdfcHJvJG1heApyZWxfcHJvJERMNDAgPC0gYXZnX3BybyRETDQwIC8gYXZnX3BybyRtYXgKcmVsX3BybyRGRVBEIDwtIGF2Z19wcm8kRkVQRCAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kSEggPC0gYXZnX3BybyRISCAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kSFVUNzggPC0gYXZnX3BybyRIVVQ3OCAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kSFVUMTAyIDwtIGF2Z19wcm8kSFVUMTAyIC8gYXZnX3BybyRtYXgKcmVsX3BybyRLQVJQQVMyOTkgPC0gYXZnX3BybyRLQVJQQVMyOTkgLyBhdmdfcHJvJG1heApyZWxfcHJvJEtBUlBBUzM4NCA8LSBhdmdfcHJvJEtBUlBBUzM4NCAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kS0hZRzEgPC0gYXZnX3BybyRLSFlHMSAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kS0lKSyA8LSBhdmdfcHJvJEtJSksgLyBhdmdfcHJvJG1heApyZWxfcHJvJEw4MiA8LSBhdmdfcHJvJEw4MiAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kTUFDMkEgPC0gYXZnX3BybyRNQUMyQSAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kTUogPC0gYXZnX3BybyRNSiAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kTU9UTjEgPC0gYXZnX3BybyRNT1ROMSAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kTVRBIDwtIGF2Z19wcm8kTVRBIC8gYXZnX3BybyRtYXgKcmVsX3BybyRNWUxBIDwtIGF2Z19wcm8kTVlMQSAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kTktMIDwtIGF2Z19wcm8kTktMIC8gYXZnX3BybyRtYXgKcmVsX3BybyRPQ0lMWTEyIDwtIGF2Z19wcm8kT0NJTFkxMiAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kU2VBeCA8LSBhdmdfcHJvJFNlQXggLyBhdmdfcHJvJG1heApyZWxfcHJvJFNNWjEgPC0gYXZnX3BybyRTTVoxIC8gYXZnX3BybyRtYXgKcmVsX3BybyRTUjc4NiA8LSBhdmdfcHJvJFNSNzg2IC8gYXZnX3BybyRtYXgKcmVsX3BybyRTVDEgPC0gYXZnX3BybyRTVDEgLyBhdmdfcHJvJG1heApyZWxfcHJvJFN1OVQwMSA8LSBhdmdfcHJvJFN1OVQwMSAvIGF2Z19wcm8kbWF4CnJlbF9wcm8kU1VESEwxIDwtIGF2Z19wcm8kU1VESEwxIC8gYXZnX3BybyRtYXgKcmVsX3BybyRTVVBNMiA8LSBhdmdfcHJvJFNVUE0yIC8gYXZnX3BybyRtYXgKYGBgCgpQQ0EgdG9wIGNvbnRyaWJ1dG9ycyBzZWxlY3Rpb24gKDUwMDAgdHJpZWQgZmlyc3QpCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRSRUdfYW5ub3QgPC0gcmVhZC50YWJsZSgiMDAyX1RDTHNfcDEwMDBfZFJFR3BlYWtfYW5ub3RhdGlvbi50eHQiLCBzZXA9Ilx0IiwgaGVhZGVyPVRSVUUpCgpQUk9fcmVsIDwtIHJlbF9wcm8KI2NoZWNrIHRoaXMKY29sbmFtZXMoUFJPX3JlbCkgPC0gYygiZFJFR3BlYWtJRCIsICJERVJMMi5lbmhhbmNlciIsICJETDQwLmVuaGFuY2VyIiwgIkZFUEQuZW5oYW5jZXIiLCAiSEguZW5oYW5jZXIiLCAiSFVUNzguZWhhbmNlciIsICJIVVQxMDIuZW5oYW5jZXIiLCAgIktBUlBBUzI5OS5lbmhhbmNlciIsICAiS0FSUEFTMzg0LmVuaGFuY2VyIiwgIktIWUcxLmVuaGFuY2VyIiwgIktJSksuZW5oYW5jZXIiLCAiTDgyLmVuaGFuY2VyIiwgICJNQUMyQS5laGFuY2VyIiwgICJNSi5lbmhhbmNlciIsICJNT1ROMS5lbmhhbmNlciIsICJNVEEuZW5oYW5jZXIiLCAiTVlMQS5lbmhhbmNlciIsICJOS0wuZW5oYW5jZXIiLCAiT0NJTFkxMi5lbmhhbmNlciIsICJTZUF4LmVoYW5jZXIiLCAiU01aMS5lbmhhbmNlciIsICJTUjc4Ni5lbmhhbmNlciIsICJTVDEuZW5oYW5jZXIiLCAgIlN1OVQwMS5lbmhhbmNlciIsICJTVURITDEuZW5oYW5jZXIiLCAiU1VQTTIuZW5oYW5jZXIiKQpzYXZlUkRTKFBST19yZWwsIGZpbGU9InByb19yZWwucmRzIikgCmhlYWQoUFJPX3JlbCkKCnJ2IDwtIHJvd1ZhcnMoYXNzYXkocmxkX3BybykpCnNlbGVjdCA8LSBvcmRlcihydiwgZGVjcmVhc2luZz1UUlVFKVtzZXFfbGVuKG1pbig1MDAwLCBsZW5ndGgocnYpKSldIAojQ2hhbmdpbmcgdGhlIDUwMDAgaGVyZSB3aWxsIHNlbGVjdCBhIERpZmZlcmVudCBudW1iZXIgb2YgdG9wIGNvbnRyaWJ1dG9ycyBpZiBkZXNpcmVkCnBjIDwtIHByY29tcCh0KGFzc2F5KHJsZF9wcm8pW3NlbGVjdCxdKSkKbG9hZGluZ3MgPC0gYXMuZGF0YS5mcmFtZShwYyRyb3RhdGlvbikKYWxvYWQgPC0gYWJzKGxvYWRpbmdzKQp3cml0ZS50YWJsZShzd2VlcChhbG9hZCwgMiwgY29sU3VtcyhhbG9hZCksICIvIiksIGZpbGU9IlRvcCA1MDAwIHBybyBQQ0EgQ29udHJpYnV0b3JzLnR4dCIpCiNDbGVhbiB1cCB2YXJpYWJsZXMKcm0ocnYpCnJtKHNlbGVjdCkKcm0ocGMpCnJtKGxvYWRpbmdzKQojTWVyZ2UgdG9wIDUwMDAgZWxlbWVudHMgd2l0aCB0aGVpciBhbm5vdGF0aW9ucwp0b3A1MDAwIDwtIGRSRUdfYW5ub3RbKGRSRUdfYW5ub3QkcGVha0lEICVpbiUgcm93bmFtZXMoYWxvYWQpKSxdCndyaXRlLnRhYmxlKHRvcDUwMDAsIGZpbGU9IlRvcDUwMDAudHh0Iiwgc2VwPSdcdCcpCmdncGxvdCh0b3A1MDAwLCBhZXMoeD1mYWN0b3IoMSksIGZpbGw9Z2Vub21pY0NhdGVnb3J5KSkrZ2VvbV9iYXIod2lkdGg9MSkrY29vcmRfcG9sYXIoInkiKSArIGdndGl0bGUoIlRvcCA1MDAwIFBDQSBDb250cmlidXRvcnMgZFJFR3BlYWsgQW5ub3RhdGlvbnMiKQpnZ3Bsb3QoZFJFR19hbm5vdCwgYWVzKHg9ZmFjdG9yKDEpLCBmaWxsPWdlbm9taWNDYXRlZ29yeSkpK2dlb21fYmFyKHdpZHRoPTEpK2Nvb3JkX3BvbGFyKCJ5IikgKyBnZ3RpdGxlKCJBbGwgZFJFR3BlYWsgQW5ub3RhdGlvbnMiKQoKI2ZpbHRlciByZXN1bHRzIGRvd24gYnkgdG9wIGNvbnRyaWJ1dG9ycwpwcm9fNTAwMF9yZWwgPC0gcmVsX3Byb1socmVsX3BybyRwZWFrSUQgJWluJSB0b3A1MDAwJHBlYWtJRCksXQojR2FwIFN0YXQgQ2FsY3VsYXRpb24KI3NldC5zZWVkKDQyKSAKI1RoaXMgc2V0cyB0aGUgcmFuZG9tIG51bWJlciBnZW5lcmF0b3Igc2VlZCBzbyBpdCB3aWxsIGFsd2F5cyBwcm9kdWNlIHRoZSBzYW1lIHJlc3VsdC4gWW91IGNhbiBwaWNrIHdoYXRldmVyIG51bWJlciB5b3UnZCBsaWtlLgojZ2FwX3N0YXQgPC0gY2x1c0dhcChwcm9fNTAwMF9yZWxbMjoyNl0sIEZVTiA9IGttZWFucywgbnN0YXJ0ID0gMjAsIEsubWF4ID0gMjQsIEIgPSA1MCkgCiMuLi4gPSBudW1iZXIgb2Ygc2FtcGxlcyArIDEKI0NsdXN0ZXIgU3RhdCBQbG90cwojZnZpel9uYmNsdXN0KHByb181MDAwX3JlbFsyOjI2XSwga21lYW5zLCBtZXRob2Q9IndzcyIsIGsubWF4PTI0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkVsYm93IFBsb3QiKQojZnZpel9nYXBfc3RhdChnYXBfc3RhdCkgKyB0aGVtZV9taW5pbWFsKCkgKyBnZ3RpdGxlKCJHYXAgU3RhdGlzdGljIikKI2Z2aXpfbmJjbHVzdChwcm9fNTAwMF9yZWxbMjoyNl0sIGttZWFucywgbWV0aG9kPSJzaWxob3VldHRlIiwgay5tYXg9MjQpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiU2lsaG91ZXR0ZSBQbG90IikKI2stbWVhbnMgQ2x1c3RlcmluZwpDTEFSQWs0IDwtIGNsYXJhKHByb181MDAwX3JlbFsyOjI2XSw0LG1lZG9pZHMueD1UUlVFKQpDTEFSQWs1IDwtIGNsYXJhKHByb181MDAwX3JlbFsyOjI2XSw1LG1lZG9pZHMueD1UUlVFKQpDTEFSQWs2IDwtIGNsYXJhKHByb181MDAwX3JlbFsyOjI2XSw2LG1lZG9pZHMueD1UUlVFKQpDTEFSQWs3IDwtIGNsYXJhKHByb181MDAwX3JlbFsyOjI2XSw3LG1lZG9pZHMueD1UUlVFKQpDTEFSQWs4IDwtIGNsYXJhKHByb181MDAwX3JlbFsyOjI2XSw4LG1lZG9pZHMueD1UUlVFKQoKcHJvXzUwMDBfcmVsJGs0IDwtIENMQVJBazQkY2x1c3RlcmluZwpwcm9fNTAwMF9yZWwkazUgPC0gQ0xBUkFrNSRjbHVzdGVyaW5nCnByb181MDAwX3JlbCRrNiA8LSBDTEFSQWs2JGNsdXN0ZXJpbmcKcHJvXzUwMDBfcmVsJGs3IDwtIENMQVJBazckY2x1c3RlcmluZwpwcm9fNTAwMF9yZWwkazggPC0gQ0xBUkFrOCRjbHVzdGVyaW5nCgojRGlzcGxheWluZyBIZWF0bWFwcwojay1tZWFucyA0CnBoZWF0bWFwKHByb181MDAwX3JlbFtvcmRlcihwcm9fNTAwMF9yZWxbLCAyNisxXSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9cHJvXzUwMDBfcmVsWzI2KzFdKQojay1tZWFucyA1CnBoZWF0bWFwKHByb181MDAwX3JlbFtvcmRlcihwcm9fNTAwMF9yZWxbLCAyNisyXSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9cHJvXzUwMDBfcmVsWzI2KzJdKQojay1tZWFucyA2CnBoZWF0bWFwKHByb181MDAwX3JlbFtvcmRlcihwcm9fNTAwMF9yZWxbLCAyNiszXSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9cHJvXzUwMDBfcmVsWzI2KzNdKQojay1tZWFucyA3CnBoZWF0bWFwKHByb181MDAwX3JlbFtvcmRlcihwcm9fNTAwMF9yZWxbLCAyNis0XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9cHJvXzUwMDBfcmVsWzI2KzRdKQojay1tZWFucyA4CnBoZWF0bWFwKHByb181MDAwX3JlbFtvcmRlcihwcm9fNTAwMF9yZWxbLCAyNis1XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9cHJvXzUwMDBfcmVsWzI2KzVdKQpgYGAKClBDQSB0b3AgY29udHJpYnV0b3JzICgxMEspCmBgYHtyfQpydiA8LSByb3dWYXJzKGFzc2F5KHJsZF9wcm8pKQpzZWxlY3QgPC0gb3JkZXIocnYsIGRlY3JlYXNpbmc9VFJVRSlbc2VxX2xlbihtaW4oMTAwMDAsIGxlbmd0aChydikpKV0gCiNDaGFuZ2luZyB0aGUgMTAwMDAgaGVyZSB3aWxsIHNlbGVjdCBhIERpZmZlcmVudCBudW1iZXIgb2YgdG9wIGNvbnRyaWJ1dG9ycyBpZiBkZXNpcmVkCnBjIDwtIHByY29tcCh0KGFzc2F5KHJsZF9wcm8pW3NlbGVjdCxdKSkKbG9hZGluZ3MgPC0gYXMuZGF0YS5mcmFtZShwYyRyb3RhdGlvbikKYWxvYWQgPC0gYWJzKGxvYWRpbmdzKQp3cml0ZS50YWJsZShzd2VlcChhbG9hZCwgMiwgY29sU3VtcyhhbG9hZCksICIvIiksIGZpbGU9IlRvcCAxMDAwMCBwcm8gUENBIENvbnRyaWJ1dG9ycy50eHQiKQojQ2xlYW4gdXAgdmFyaWFibGVzCnJtKHJ2KQpybShzZWxlY3QpCnJtKHBjKQpybShsb2FkaW5ncykKI01lcmdlIHRvcCAxMDAwMCBlbGVtZW50cyB3aXRoIHRoZWlyIGFubm90YXRpb25zCnRvcDEwMDAwIDwtIGRSRUdfYW5ub3RbKGRSRUdfYW5ub3QkcGVha0lEICVpbiUgcm93bmFtZXMoYWxvYWQpKSxdCndyaXRlLnRhYmxlKHRvcDEwMDAwLCBmaWxlPSJUb3AxMDAwMC50eHQiLCBzZXA9J1x0JykKZ2dwbG90KHRvcDEwMDAwLCBhZXMoeD1mYWN0b3IoMSksIGZpbGw9Z2Vub21pY0NhdGVnb3J5KSkrZ2VvbV9iYXIod2lkdGg9MSkrY29vcmRfcG9sYXIoInkiKSArIGdndGl0bGUoIlRvcCAxMDAwMCBQQ0EgQ29udHJpYnV0b3JzIGRSRUdwZWFrIEFubm90YXRpb25zIikKZ2dwbG90KGRSRUdfYW5ub3QsIGFlcyh4PWZhY3RvcigxKSwgZmlsbD1nZW5vbWljQ2F0ZWdvcnkpKStnZW9tX2Jhcih3aWR0aD0xKStjb29yZF9wb2xhcigieSIpICsgZ2d0aXRsZSgiQWxsIGRSRUdwZWFrIEFubm90YXRpb25zIikKCiNmaWx0ZXIgcmVzdWx0cyBkb3duIGJ5IHRvcCBjb250cmlidXRvcnMKUFJPXzEwMDAwX3JlbCA8LSByZWxfcHJvWyhyZWxfcHJvJHBlYWtJRCAlaW4lIHRvcDEwMDAwJHBlYWtJRCksXQojR2FwIFN0YXQgQ2FsY3VsYXRpb24KI3NldC5zZWVkKDQyKSAKI1RoaXMgc2V0cyB0aGUgcmFuZG9tIG51bWJlciBnZW5lcmF0b3Igc2VlZCBzbyBpdCB3aWxsIGFsd2F5cyBwcm9kdWNlIHRoZSBzYW1lIHJlc3VsdC4gWW91IGNhbiBwaWNrIHdoYXRldmVyIG51bWJlciB5b3UnZCBsaWtlLgojZ2FwX3N0YXQgPC0gY2x1c0dhcChwcm9fMTAwMDBfcmVsWzI6MjZdLCBGVU4gPSBrbWVhbnMsIG5zdGFydCA9IDIwLCBLLm1heCA9IDI0LCBCID0gNTApIAojLi4uID0gbnVtYmVyIG9mIHNhbXBsZXMgKyAxCiNDbHVzdGVyIFN0YXQgUGxvdHMKI2Z2aXpfbmJjbHVzdChwcm9fMTAwMDBfcmVsWzI6MjZdLCBrbWVhbnMsIG1ldGhvZD0id3NzIiwgay5tYXg9MjQpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiRWxib3cgUGxvdCIpCiNmdml6X2dhcF9zdGF0KGdhcF9zdGF0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkdhcCBTdGF0aXN0aWMiKQojZnZpel9uYmNsdXN0KHByb18xMDAwMF9yZWxbMjoyNl0sIGttZWFucywgbWV0aG9kPSJzaWxob3VldHRlIiwgay5tYXg9MjQpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiU2lsaG91ZXR0ZSBQbG90IikKI2stbWVhbnMgQ2x1c3RlcmluZwpDTEFSQWs1IDwtIGNsYXJhKFBST18xMDAwMF9yZWxbMjoyNl0sNSxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrOCA8LSBjbGFyYShQUk9fMTAwMDBfcmVsWzI6MjZdLDgsbWVkb2lkcy54PVRSVUUpCkNMQVJBazEwIDwtIGNsYXJhKFBST18xMDAwMF9yZWxbMjoyNl0sMTAsbWVkb2lkcy54PVRSVUUpCkNMQVJBazEzIDwtIGNsYXJhKFBST18xMDAwMF9yZWxbMjoyNl0sMTMsbWVkb2lkcy54PVRSVUUpCkNMQVJBazE1IDwtIGNsYXJhKFBST18xMDAwMF9yZWxbMjoyNl0sMTUsbWVkb2lkcy54PVRSVUUpCkNMQVJBazYgPC0gY2xhcmEoUFJPXzEwMDAwX3JlbFsyOjI2XSw2LG1lZG9pZHMueD1UUlVFKQpDTEFSQWs3IDwtIGNsYXJhKFBST18xMDAwMF9yZWxbMjoyNl0sNyxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNCA8LSBjbGFyYShQUk9fMTAwMDBfcmVsWzI6MjZdLDQsbWVkb2lkcy54PVRSVUUpCgoKUFJPXzEwMDAwX3JlbCRrNSA8LSBDTEFSQWs1JGNsdXN0ZXJpbmcKUFJPXzEwMDAwX3JlbCRrOCA8LSBDTEFSQWs4JGNsdXN0ZXJpbmcKUFJPXzEwMDAwX3JlbCRrMTAgPC0gQ0xBUkFrMTAkY2x1c3RlcmluZwpQUk9fMTAwMDBfcmVsJGsxMyA8LSBDTEFSQWsxMyRjbHVzdGVyaW5nClBST18xMDAwMF9yZWwkazE1IDwtIENMQVJBazE1JGNsdXN0ZXJpbmcKUFJPXzEwMDAwX3JlbCRrNiA8LSBDTEFSQWs2JGNsdXN0ZXJpbmcKUFJPXzEwMDAwX3JlbCRrNyA8LSBDTEFSQWs3JGNsdXN0ZXJpbmcKUFJPXzEwMDAwX3JlbCRrNCA8LSBDTEFSQWs0JGNsdXN0ZXJpbmcKCgoKI0Rpc3BsYXlpbmcgSGVhdG1hcHMKI2stbWVhbnMgNQpwaGVhdG1hcChQUk9fMTAwMDBfcmVsW29yZGVyKFBST18xMDAwMF9yZWxbLCAyNisxXSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDAwX3JlbFsyNisxXSkKI2stbWVhbnMgOApwaGVhdG1hcChQUk9fMTAwMDBfcmVsW29yZGVyKFBST18xMDAwMF9yZWxbLCAyNisyXSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDAwX3JlbFsyNisyXSkKI2stbWVhbnMgMTAKcGhlYXRtYXAoUFJPXzEwMDAwX3JlbFtvcmRlcihQUk9fMTAwMDBfcmVsWywgMjYrM10pLF1bLDI6MjZdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST18xMDAwMF9yZWxbMjYrM10pCiNrLW1lYW5zIDEzCnBoZWF0bWFwKFBST18xMDAwMF9yZWxbb3JkZXIoUFJPXzEwMDAwX3JlbFssIDI2KzRdKSxdWywyOjI2XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz1QUk9fMTAwMDBfcmVsWzI2KzRdKQojay1tZWFucyAxNQpwaGVhdG1hcChQUk9fMTAwMDBfcmVsW29yZGVyKFBST18xMDAwMF9yZWxbLCAyNis1XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDAwX3JlbFsyNis1XSkKI2stbWVhbnMgNgpwaGVhdG1hcChQUk9fMTAwMDBfcmVsW29yZGVyKFBST18xMDAwMF9yZWxbLCAyNis2XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDAwX3JlbFsyNis2XSkKI2stbWVhbnMgNwpwaGVhdG1hcChQUk9fMTAwMDBfcmVsW29yZGVyKFBST18xMDAwMF9yZWxbLCAyNis3XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDAwX3JlbFsyNis3XSkKI2stbWVhbnMgNApwaGVhdG1hcChQUk9fMTAwMDBfcmVsW29yZGVyKFBST18xMDAwMF9yZWxbLCAyNis4XSksXVssMjoyNl0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDAwX3JlbFsyNis4XSkKYGBgCgoKU2VwYXJhdGluZyBieSBkaXNlYXNlIHN1YnNldCBhbmQgcmUtY2x1c3RlcmluZwpgYGB7cn0KZGRzX3Byb19zdWIgPC0gZGRzX3Byb1ssLWMoNywxMywxNSwxOSwyMCwyMSwyMiwyMyldICNFeGNsdWRpbmcgc2FtcGxlIG51bWJlcnMgb2YgZW50aXRpZXMgdGhhdCBhcmUgbm90IEFsaytBbGNsLCBBbGstQWxjbCwgQXRsbCwgYW5kIEN0Y2wgCmVzdGltYXRlU2l6ZUZhY3RvcnMoZGRzX3Byb19zdWIpICNNdXN0IHJlLWNhbGN1bGF0ZSBzaXplIGZhY3RvcnMgYWZ0ZXIgcmVtb3Zpbmcgc2FtcGxlcwpkZXNlcV9zaXplc19wcm9fc3ViIDwtIGFzLmRhdGEuZnJhbWUoc2l6ZUZhY3RvcnMoZGRzX3Byb19zdWIpKQpkZXNlcV9zaXplc19wcm9fc3ViIAogIApybGRfcHJvX3N1YiA8LSBybG9nKGRkc19wcm9fc3ViLCBibGluZD1UUlVFKQpjb2xuYW1lcyhybGRfcHJvX3N1YikgPC0gcGFzdGUwKGRkc19wcm9fc3ViJHNhbXBsZSkKc2FtcGxlRGlzdHNfcHJvX3N1YiA8LSBkaXN0KHQoYXNzYXkocmxkX3Byb19zdWIpKSkKc2FtcGxlRGlzdE10eF9wcm9fc3ViIDwtIGFzLm1hdHJpeChzYW1wbGVEaXN0c19wcm9fc3ViKQpyb3duYW1lcyhzYW1wbGVEaXN0TXR4X3Byb19zdWIpIDwtIGNvbG5hbWVzKHJsZF9wcm9fc3ViKQpjb2xuYW1lcyhzYW1wbGVEaXN0TXR4X3Byb19zdWIpIDwtIE5VTEwKaGNsdXN0X3Byb19zdWIgPC0gaGNsdXN0KHNhbXBsZURpc3RzX3Byb19zdWIpCgpwbG90KGhjbHVzdF9wcm9fc3ViLCBsYWJlbHM9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9wcm9fc3ViKSwgbWFpbj0iTGFyZ2VzdCBFbnRpdHkgZFJFRyBEZW5kcm9ncmFtIikKYGBgCgpwcm8gc3Vic2V0IFBDQXMKYGBge3J9CiNwbG90UENBKHJsZF9zdWIsIGludGdyb3VwID0gInN1YnR5cGUiKSArIGdndGl0bGUoIlJOQS1zZXEgc3Vic2V0IFBDQSBUb3AgNTAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfcHJvX3N1YiwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9MTAwMCkgKyBnZ3RpdGxlKCJwcm8tc2VxIHN1YnNldCBQQ0EgVG9wIDEwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwiQUxLK0FMQ0wiLCAiQ1RDTCIsICJBTEstQUxDTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hvY29sYXRlNCIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9wcm9fc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfcHJvX3N1YiwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9NTAwMCkgKyBnZ3RpdGxlKCJwcm8tc2VxIHN1YnNldCBQQ0EgVG9wIDUwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwiQUxLK0FMQ0wiLCAiQ1RDTCIsICJBTEstQUxDTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hvY29sYXRlNCIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9wcm9fc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfcHJvX3N1YiwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9MTAwMDApICsgZ2d0aXRsZSgicHJvLXNlcSBzdWJzZXQgUENBIFRvcCAxMDAwMCIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCJBTEsrQUxDTCIsICJDVENMIiwgIkFMSy1BTENMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaG9jb2xhdGU0IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X3Byb19zdWIpLCBtYXgub3ZlcmxhcHM9NTApCgojcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xNTAwMCkgKyBnZ3RpdGxlKCJSTkEtc2VxIHN1YnNldCBQQ0EgVG9wIDE1MDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKI3Bsb3RQQ0EocmxkX3N1YiwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9NjA2NzYpICsgZ2d0aXRsZSgiUk5BLXNlcSBzdWJzZXQgUENBIEFsbCBDb250cmlidXRvcnMiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpLCBtYXgub3ZlcmxhcHM9NTApCmBgYAoKR2VuZXJhdGUgbm9ybSBjb3VudHMgZmlsZQpgYGB7cn0Kbm9ybWNvdW50c19wcm9fc3ViIDwtIGFzLmRhdGEuZnJhbWUoY291bnRzKGRkc19wcm9fc3ViLCBub3JtYWxpemVkPVRSVUUpKQpjb2xuYW1lcyhub3JtY291bnRzX3Byb19zdWIpIDwtIGMoIkhVVDEwMiIsICJTVDEiLCAiU3U5VDAxIiwgIktBUlBBUzI5OSIsICJMODIiLCAiU1VQTTIiLCAiTVlMQSIsICJNQUMyQSIsICJLSUpLIiwgIlNSNzg2IiwgIkZFUEQiLCAiREw0MCIsICJIVVQ3OCIsICJISCIsICJNSiIsICJTZUF4IiwgIlNVREhMMSIpCmBgYAoKQWRkaXRpb25hbCBkZW5kcm9ncmFtIHBsb3RzCmBgYHtyfQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSkpKDI1NSkKcGhlYXRtYXAoc2FtcGxlRGlzdE10eF9wcm9fc3ViLCBjb2w9Y29sb3JzLCBib3JkZXJfY29sb3I9TkEsIHNob3dfY29sbmFtZXM9RkFMU0UsIHNob3dfcm93bmFtZXM9VFJVRSwKICAgICAgICAgY2x1c3Rlcl9yb3dzPVRSVUUsIGNsdXN0ZXJfY29scz1UUlVFLCBtYWluPSJwcm8gc3Vic2V0IFNhbXBsZSBEaXN0YW5jZSBDbHVzdGVyaW5nIikKcGxvdChoY2x1c3Qoc2FtcGxlRGlzdHNfcHJvX3N1YiksIGxhYmVscz1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X3Byb19zdWIpLCBtYWluPSJwcm8gc3Vic2V0IFNhbXBsZSBEaXN0YW5jZSBEZW5kcm9ncmFtIikKYGBgCgpBc3NlbWJsZSBzdWJzZXQgY291bnRzIGFuZCBhdmVyYWdlCmBgYHtyfQphdmdfcHJvX3N1YiA8LSBkYXRhLmZyYW1lKHBlYWtJRD1yb3duYW1lcyhub3JtY291bnRzX3Byb19zdWIpKQphdmdfcHJvX3N1YiRIVVQxMDIgPC0gKG5vcm1jb3VudHNfcHJvX3N1YiRIVVQxMDIpCmF2Z19wcm9fc3ViJFNUMSA8LSAobm9ybWNvdW50c19wcm9fc3ViJFNUMSkKYXZnX3Byb19zdWIkU3U5VDAxIDwtIChub3JtY291bnRzX3Byb19zdWIkU3U5VDAxKQphdmdfcHJvX3N1YiRLQVJQQVMyOTkgPC0gKG5vcm1jb3VudHNfcHJvX3N1YiRLQVJQQVMyOTkpCmF2Z19wcm9fc3ViJEw4MiA8LSAobm9ybWNvdW50c19wcm9fc3ViJEw4MikKYXZnX3Byb19zdWIkU1VQTTIgPC0gKG5vcm1jb3VudHNfcHJvX3N1YiRTVVBNMikKYXZnX3Byb19zdWIkTVlMQSA8LSAobm9ybWNvdW50c19wcm9fc3ViJE1ZTEEpCmF2Z19wcm9fc3ViJE1BQzJBIDwtIChub3JtY291bnRzX3Byb19zdWIkTUFDMkEpCmF2Z19wcm9fc3ViJEtJSksgPC0gKG5vcm1jb3VudHNfcHJvX3N1YiRLSUpLKQphdmdfcHJvX3N1YiRTUjc4NiA8LSAobm9ybWNvdW50c19wcm9fc3ViJFNSNzg2KQphdmdfcHJvX3N1YiRGRVBEIDwtIChub3JtY291bnRzX3Byb19zdWIkRkVQRCkKYXZnX3Byb19zdWIkREw0MCA8LSAobm9ybWNvdW50c19wcm9fc3ViJERMNDApCmF2Z19wcm9fc3ViJEhVVDc4IDwtIChub3JtY291bnRzX3Byb19zdWIkSFVUNzgpCmF2Z19wcm9fc3ViJEhIIDwtIChub3JtY291bnRzX3Byb19zdWIkSEgpCmF2Z19wcm9fc3ViJE1KIDwtIChub3JtY291bnRzX3Byb19zdWIkTUopCmF2Z19wcm9fc3ViJFNlQXggPC0gKG5vcm1jb3VudHNfcHJvX3N1YiRTZUF4KQphdmdfcHJvX3N1YiRTVURITDEgPC0gKG5vcm1jb3VudHNfcHJvX3N1YiRTVURITDEpCgphdmdfcHJvX3N1YiRtYXggPC0gYXBwbHkoYXZnX3Byb19zdWJbYygiSFVUMTAyIiwgIlNUMSIsICJTdTlUMDEiLCAiS0FSUEFTMjk5IiwgIkw4MiIsICJTVVBNMiIsICJNWUxBIiwgIk1BQzJBIiwgIktJSksiLCAiU1I3ODYiLCAiRkVQRCIsICJETDQwIiwgIkhVVDc4IiwgIkhIIiwgIk1KIiwgIlNlQXgiLCAiU1VESEwxIildLCAxLCBtYXgsIG5hLnJtPVRSVUUpCnJlbF9wcm9fc3ViIDwtIGRhdGEuZnJhbWUocGVha0lEPWF2Z19wcm9fc3ViJHBlYWtJRCkKcmVsX3Byb19zdWIkSFVUMTAyIDwtIGF2Z19wcm9fc3ViJEhVVDEwMiAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRTVDEgPC0gYXZnX3Byb19zdWIkU1QxIC8gYXZnX3Byb19zdWIkbWF4CnJlbF9wcm9fc3ViJFN1OVQwMSA8LSBhdmdfcHJvX3N1YiRTdTlUMDEgLyBhdmdfcHJvX3N1YiRtYXgKcmVsX3Byb19zdWIkS0FSUEFTMjk5IDwtIGF2Z19wcm9fc3ViJEtBUlBBUzI5OSAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRMODIgPC0gYXZnX3Byb19zdWIkTDgyIC8gYXZnX3Byb19zdWIkbWF4CnJlbF9wcm9fc3ViJFNVUE0yIDwtIGF2Z19wcm9fc3ViJFNVUE0yIC8gYXZnX3Byb19zdWIkbWF4CnJlbF9wcm9fc3ViJE1ZTEEgPC0gYXZnX3Byb19zdWIkTVlMQSAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRNQUMyQSA8LSBhdmdfcHJvX3N1YiRNQUMyQSAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRLSUpLIDwtIGF2Z19wcm9fc3ViJEtJSksgLyBhdmdfcHJvX3N1YiRtYXgKcmVsX3Byb19zdWIkU1I3ODYgPC0gYXZnX3Byb19zdWIkU1I3ODYgLyBhdmdfcHJvX3N1YiRtYXgKcmVsX3Byb19zdWIkRkVQRCA8LSBhdmdfcHJvX3N1YiRGRVBEIC8gYXZnX3Byb19zdWIkbWF4CnJlbF9wcm9fc3ViJERMNDAgPC0gYXZnX3Byb19zdWIkREw0MCAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRIVVQ3OCA8LSBhdmdfcHJvX3N1YiRIVVQ3OCAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRISCA8LSBhdmdfcHJvX3N1YiRISCAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRNSiA8LSBhdmdfcHJvX3N1YiRNSiAvIGF2Z19wcm9fc3ViJG1heApyZWxfcHJvX3N1YiRTZUF4IDwtIGF2Z19wcm9fc3ViJFNlQXggLyBhdmdfcHJvX3N1YiRtYXgKcmVsX3Byb19zdWIkU1VESEwxIDwtIGF2Z19wcm9fc3ViJFNVREhMMSAvIGF2Z19wcm9fc3ViJG1heApgYGAKClBDQSB0b3AgY29udHJpYnV0b3JzIHNlbGVjdGlvbiAoNTAwMCkKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNjaGVjayB0aGlzCmNvbG5hbWVzKHJlbF9wcm9fc3ViKSA8LSBjKCJkUkVHcGVha0lEIiwgIkhVVDEwMi5lbmhhbmNlciIsICJTVDEuZW5oYW5jZXIiLCAiU3U5VDAxLmVuaGFuY2VyIiwgIktBUlBBUzI5OS5lbmhhbmNlciIsICJMODIuZW5oYW5jZXIiLCAiU1VQTTIuZW5oYW5jZXIiLCAiTVlMQS5lbmhhbmNlciIsICJNQUMyQS5laGFuY2VyIiwgIktJSksuZW5oYW5jZXIiLCAiU1I3ODYuZW5oYW5jZXIiLCAiRkVQRC5lbmhhbmNlciIsICJETDQwLmVuaGFuY2VyIiwgIkhVVDc4LmVoYW5jZXIiLCAiSEguZW5oYW5jZXIiLCAiTUouZW5oYW5jZXIiLCAgIlNlQXguZWhhbmNlciIsICJTVURITDEuZW5oYW5jZXIiKQoKcnYyIDwtIHJvd1ZhcnMoYXNzYXkocmxkX3Byb19zdWIpKQpzZWxlY3QyIDwtIG9yZGVyKHJ2MiwgZGVjcmVhc2luZz1UUlVFKVtzZXFfbGVuKG1pbig1MDAwLCBsZW5ndGgocnYyKSkpXSAKI0NoYW5naW5nIHRoZSA1MDAwIGhlcmUgd2lsbCBzZWxlY3QgYSBEaWZmZXJlbnQgbnVtYmVyIG9mIHRvcCBjb250cmlidXRvcnMgaWYgZGVzaXJlZApwYzIgPC0gcHJjb21wKHQoYXNzYXkocmxkX3Byb19zdWIpW3NlbGVjdDIsXSkpCmxvYWRpbmdzMiA8LSBhcy5kYXRhLmZyYW1lKHBjMiRyb3RhdGlvbikKYWxvYWQyIDwtIGFicyhsb2FkaW5nczIpCndyaXRlLnRhYmxlKHN3ZWVwKGFsb2FkLCAyLCBjb2xTdW1zKGFsb2FkMiksICIvIiksIGZpbGU9IlRvcCA1MDAwIHBybyBzdWIgUENBIENvbnRyaWJ1dG9ycy50eHQiKQoKIyNNZXJnZSB0b3AgNTAwMCBlbGVtZW50cyB3aXRoIHRoZWlyIGFubm90YXRpb25zCnRvcDUwMDAgPC0gZFJFR19hbm5vdFsoZFJFR19hbm5vdCRwZWFrSUQgJWluJSByb3duYW1lcyhhbG9hZDIpKSxdCndyaXRlLnRhYmxlKHRvcDUwMDAsIGZpbGU9IlRvcDUwMDBfcHJvX3N1Yi50eHQiLCBzZXA9J1x0JykKZ2dwbG90KHRvcDUwMDAsIGFlcyh4PWZhY3RvcigxKSwgZmlsbD1nZW5vbWljQ2F0ZWdvcnkpKStnZW9tX2Jhcih3aWR0aD0xKStjb29yZF9wb2xhcigieSIpICsgZ2d0aXRsZSgiVG9wIDUwMDAgUENBIHN1YnNldCBDb250cmlidXRvcnMgZFJFR3BlYWsgQW5ub3RhdGlvbnMiKQpnZ3Bsb3QoZFJFR19hbm5vdCwgYWVzKHg9ZmFjdG9yKDEpLCBmaWxsPWdlbm9taWNDYXRlZ29yeSkpK2dlb21fYmFyKHdpZHRoPTEpK2Nvb3JkX3BvbGFyKCJ5IikgKyBnZ3RpdGxlKCJBbGwgZFJFR3BlYWsgQW5ub3RhdGlvbnMiKQoKI2ZpbHRlciByZXN1bHRzIGRvd24gYnkgdG9wIGNvbnRyaWJ1dG9ycwpQUk9fNTAwMF9yZWwgPC0gcmVsX3Byb19zdWJbKHJlbF9wcm9fc3ViJGRSRUdwZWFrSUQgJWluJSB0b3A1MDAwJHBlYWtJRCksXQojR2FwIFN0YXQgQ2FsY3VsYXRpb24KI3NldC5zZWVkKDQyKSAKI1RoaXMgc2V0cyB0aGUgcmFuZG9tIG51bWJlciBnZW5lcmF0b3Igc2VlZCBzbyBpdCB3aWxsIGFsd2F5cyBwcm9kdWNlIHRoZSBzYW1lIHJlc3VsdC4gWW91IGNhbiBwaWNrIHdoYXRldmVyIG51bWJlciB5b3UnZCBsaWtlLgojZ2FwX3N0YXQgPC0gY2x1c0dhcChSTkFfcmVsWzI6MjZdLCBGVU4gPSBrbWVhbnMsIG5zdGFydCA9IDIwLCBLLm1heCA9IDI0LCBCID0gNTApIAojLi4uID0gbnVtYmVyIG9mIHNhbXBsZXMgKyAxCiNDbHVzdGVyIFN0YXQgUGxvdHMKI2Z2aXpfbmJjbHVzdCh0b3AxMDAwMFsyOjI2XSwga21lYW5zLCBtZXRob2Q9IndzcyIsIGsubWF4PTI0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkVsYm93IFBsb3QiKQojZnZpel9nYXBfc3RhdChnYXBfc3RhdCkgKyB0aGVtZV9taW5pbWFsKCkgKyBnZ3RpdGxlKCJHYXAgU3RhdGlzdGljIikKI2Z2aXpfbmJjbHVzdCh0b3AxMDAwMFsyOjI2XSwga21lYW5zLCBtZXRob2Q9InNpbGhvdWV0dGUiLCBrLm1heD0yNCkgKyB0aGVtZV9taW5pbWFsKCkgKyBnZ3RpdGxlKCJTaWxob3VldHRlIFBsb3QiKQojay1tZWFucyBDbHVzdGVyaW5nCkNMQVJBazE1IDwtIGNsYXJhKFBST181MDAwX3JlbFsyOjE4XSwxNSxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrMjAgPC0gY2xhcmEoUFJPXzUwMDBfcmVsWzI6MThdLDIwLG1lZG9pZHMueD1UUlVFKQpDTEFSQWsyMiA8LSBjbGFyYShQUk9fNTAwMF9yZWxbMjoxOF0sMjIsbWVkb2lkcy54PVRSVUUpCkNMQVJBazI1IDwtIGNsYXJhKFBST181MDAwX3JlbFsyOjE4XSwyNSxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrMjYgPC0gY2xhcmEoUFJPXzUwMDBfcmVsWzI6MThdLDI2LG1lZG9pZHMueD1UUlVFKQpDTEFSQWszMCA8LSBjbGFyYShQUk9fNTAwMF9yZWxbMjoxOF0sMzAsbWVkb2lkcy54PVRSVUUpCkNMQVJBazM2IDwtIGNsYXJhKFBST181MDAwX3JlbFsyOjE4XSwzNixtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNCA8LSBjbGFyYShQUk9fNTAwMF9yZWxbMjoxOF0sNCxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNiA8LSBjbGFyYShQUk9fNTAwMF9yZWxbMjoxOF0sNixtZWRvaWRzLng9VFJVRSkKQ0xBUkFrMTAgPC0gY2xhcmEoUFJPXzUwMDBfcmVsWzI6MThdLDEwLG1lZG9pZHMueD1UUlVFKQpDTEFSQWszIDwtIGNsYXJhKFBST181MDAwX3JlbFsyOjE4XSwzLG1lZG9pZHMueD1UUlVFKQpDTEFSQWs1IDwtIGNsYXJhKFBST181MDAwX3JlbFsyOjE4XSw1LG1lZG9pZHMueD1UUlVFKQoKClBST181MDAwX3JlbCRrMTUgPC0gQ0xBUkFrMTUkY2x1c3RlcmluZwpQUk9fNTAwMF9yZWwkazIwIDwtIENMQVJBazIwJGNsdXN0ZXJpbmcKUFJPXzUwMDBfcmVsJGsyMiA8LSBDTEFSQWsyMiRjbHVzdGVyaW5nClBST181MDAwX3JlbCRrMjUgPC0gQ0xBUkFrMjUkY2x1c3RlcmluZwpQUk9fNTAwMF9yZWwkazI2IDwtIENMQVJBazI2JGNsdXN0ZXJpbmcKUFJPXzUwMDBfcmVsJGszMCA8LSBDTEFSQWszMCRjbHVzdGVyaW5nClBST181MDAwX3JlbCRrMzYgPC0gQ0xBUkFrMzYkY2x1c3RlcmluZwpQUk9fNTAwMF9yZWwkazQgPC0gQ0xBUkFrNCRjbHVzdGVyaW5nClBST181MDAwX3JlbCRrNiA8LSBDTEFSQWs2JGNsdXN0ZXJpbmcKUFJPXzUwMDBfcmVsJGsxMCA8LSBDTEFSQWsxMCRjbHVzdGVyaW5nClBST181MDAwX3JlbCRrMyA8LSBDTEFSQWszJGNsdXN0ZXJpbmcKUFJPXzUwMDBfcmVsJGs1IDwtIENMQVJBazUkY2x1c3RlcmluZwoKCiNEaXNwbGF5aW5nIEhlYXRtYXBzCiNrLW1lYW5zIDE1CnBoZWF0bWFwKFBST181MDAwX3JlbFtvcmRlcihQUk9fNTAwMF9yZWxbLCAxOCsxXSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzUwMDBfcmVsWzE4KzFdKQojay1tZWFucyAyMApwaGVhdG1hcChQUk9fNTAwMF9yZWxbb3JkZXIoUFJPXzUwMDBfcmVsWywgMTgrMl0pLF1bLDI6MThdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST181MDAwX3JlbFsxOCsyXSkKI2stbWVhbnMgMjIgCnBoZWF0bWFwKFBST181MDAwX3JlbFtvcmRlcihQUk9fNTAwMF9yZWxbLCAxOCszXSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzUwMDBfcmVsWzE4KzNdKQojay1tZWFucyAyNQpwaGVhdG1hcChQUk9fNTAwMF9yZWxbb3JkZXIoUFJPXzUwMDBfcmVsWywgMTgrNF0pLF1bLDI6MThdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST181MDAwX3JlbFsxOCs0XSkKI2stbWVhbnMgMjYKcGhlYXRtYXAoUFJPXzUwMDBfcmVsW29yZGVyKFBST181MDAwX3JlbFssIDE4KzVdKSxdWywyOjE4XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz1QUk9fNTAwMF9yZWxbMTgrNV0pCiNrLW1lYW5zIDMwCnBoZWF0bWFwKFBST181MDAwX3JlbFtvcmRlcihQUk9fNTAwMF9yZWxbLCAxOCs2XSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzUwMDBfcmVsWzE4KzZdKQojay1tZWFucyAzNgpwaGVhdG1hcChQUk9fNTAwMF9yZWxbb3JkZXIoUFJPXzUwMDBfcmVsWywgMTgrN10pLF1bLDI6MThdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST181MDAwX3JlbFsxOCs3XSkKI2stbWVhbnMgNApwaGVhdG1hcChQUk9fNTAwMF9yZWxbb3JkZXIoUFJPXzUwMDBfcmVsWywgMTgrOF0pLF1bLDI6MThdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST181MDAwX3JlbFsxOCs4XSkKI2stbWVhbnMgNgpwaGVhdG1hcChQUk9fNTAwMF9yZWxbb3JkZXIoUFJPXzUwMDBfcmVsWywgMTgrOV0pLF1bLDI6MThdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST181MDAwX3JlbFsxOCs5XSkKI2stbWVhbnMgMTAKcGhlYXRtYXAoUFJPXzUwMDBfcmVsW29yZGVyKFBST181MDAwX3JlbFssIDE4KzEwXSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzUwMDBfcmVsWzE4KzEwXSkKI2stbWVhbnMgMwpwaGVhdG1hcChQUk9fNTAwMF9yZWxbb3JkZXIoUFJPXzUwMDBfcmVsWywgMTgrMTFdKSxdWywyOjE4XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz1QUk9fNTAwMF9yZWxbMTgrMTFdKQojay1tZWFucyA1CnBoZWF0bWFwKFBST181MDAwX3JlbFtvcmRlcihQUk9fNTAwMF9yZWxbLCAxOCsxMl0pLF1bLDI6MThdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PVBST181MDAwX3JlbFsxOCsxMl0pCmBgYAoKUENBIHRvcCBjb250cmlidXRvcnMgKDEwMDApCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojY2hlY2sgdGhpcwpjb2xuYW1lcyhyZWxfcHJvX3N1YikgPC0gYygiZFJFR3BlYWtJRCIsICJIVVQxMDIuZW5oYW5jZXIiLCAiU1QxLmVuaGFuY2VyIiwgIlN1OVQwMS5lbmhhbmNlciIsICJLQVJQQVMyOTkuZW5oYW5jZXIiLCAiTDgyLmVuaGFuY2VyIiwgIlNVUE0yLmVuaGFuY2VyIiwgIk1ZTEEuZW5oYW5jZXIiLCAiTUFDMkEuZWhhbmNlciIsICJLSUpLLmVuaGFuY2VyIiwgIlNSNzg2LmVuaGFuY2VyIiwgIkZFUEQuZW5oYW5jZXIiLCAiREw0MC5lbmhhbmNlciIsICJIVVQ3OC5laGFuY2VyIiwgIkhILmVuaGFuY2VyIiwgIk1KLmVuaGFuY2VyIiwgICJTZUF4LmVoYW5jZXIiLCAiU1VESEwxLmVuaGFuY2VyIikKCnJ2MyA8LSByb3dWYXJzKGFzc2F5KHJsZF9wcm9fc3ViKSkKc2VsZWN0MyA8LSBvcmRlcihydjMsIGRlY3JlYXNpbmc9VFJVRSlbc2VxX2xlbihtaW4oMTAwMCwgbGVuZ3RoKHJ2MykpKV0gCiNDaGFuZ2luZyB0aGUgMTAwMCBoZXJlIHdpbGwgc2VsZWN0IGEgRGlmZmVyZW50IG51bWJlciBvZiB0b3AgY29udHJpYnV0b3JzIGlmIGRlc2lyZWQKcGMzIDwtIHByY29tcCh0KGFzc2F5KHJsZF9wcm9fc3ViKVtzZWxlY3QzLF0pKQpsb2FkaW5nczMgPC0gYXMuZGF0YS5mcmFtZShwYzMkcm90YXRpb24pCmFsb2FkMyA8LSBhYnMobG9hZGluZ3MzKQp3cml0ZS50YWJsZShzd2VlcChhbG9hZDMsIDIsIGNvbFN1bXMoYWxvYWQzKSwgIi8iKSwgZmlsZT0iVG9wIDEwMDAgcHJvIHN1YiBQQ0EgQ29udHJpYnV0b3JzLnR4dCIpCgojI01lcmdlIHRvcCAxMDAwIGVsZW1lbnRzIHdpdGggdGhlaXIgYW5ub3RhdGlvbnMKdG9wMTAwMCA8LSBkUkVHX2Fubm90WyhkUkVHX2Fubm90JHBlYWtJRCAlaW4lIHJvd25hbWVzKGFsb2FkMykpLF0Kd3JpdGUudGFibGUodG9wMTAwMCwgZmlsZT0iVG9wMTAwMF9wcm9fc3ViLnR4dCIsIHNlcD0nXHQnKQpnZ3Bsb3QodG9wMTAwMCwgYWVzKHg9ZmFjdG9yKDEpLCBmaWxsPWdlbm9taWNDYXRlZ29yeSkpK2dlb21fYmFyKHdpZHRoPTEpK2Nvb3JkX3BvbGFyKCJ5IikgKyBnZ3RpdGxlKCJUb3AgNTAwMCBQQ0Egc3Vic2V0IENvbnRyaWJ1dG9ycyBkUkVHcGVhayBBbm5vdGF0aW9ucyIpCmdncGxvdChkUkVHX2Fubm90LCBhZXMoeD1mYWN0b3IoMSksIGZpbGw9Z2Vub21pY0NhdGVnb3J5KSkrZ2VvbV9iYXIod2lkdGg9MSkrY29vcmRfcG9sYXIoInkiKSArIGdndGl0bGUoIkFsbCBkUkVHcGVhayBBbm5vdGF0aW9ucyIpCgojZmlsdGVyIHJlc3VsdHMgZG93biBieSB0b3AgY29udHJpYnV0b3JzClBST18xMDAwX3JlbCA8LSByZWxfcHJvX3N1YlsocmVsX3Byb19zdWIkZFJFR3BlYWtJRCAlaW4lIHRvcDEwMDAkcGVha0lEKSxdCiNHYXAgU3RhdCBDYWxjdWxhdGlvbgojc2V0LnNlZWQoNDIpIAojVGhpcyBzZXRzIHRoZSByYW5kb20gbnVtYmVyIGdlbmVyYXRvciBzZWVkIHNvIGl0IHdpbGwgYWx3YXlzIHByb2R1Y2UgdGhlIHNhbWUgcmVzdWx0LiBZb3UgY2FuIHBpY2sgd2hhdGV2ZXIgbnVtYmVyIHlvdSdkIGxpa2UuCiNnYXBfc3RhdCA8LSBjbHVzR2FwKFJOQV9yZWxbMjoyNl0sIEZVTiA9IGttZWFucywgbnN0YXJ0ID0gMjAsIEsubWF4ID0gMjQsIEIgPSA1MCkgCiMuLi4gPSBudW1iZXIgb2Ygc2FtcGxlcyArIDEKI0NsdXN0ZXIgU3RhdCBQbG90cwojZnZpel9uYmNsdXN0KHRvcDEwMDAwWzI6MjZdLCBrbWVhbnMsIG1ldGhvZD0id3NzIiwgay5tYXg9MjQpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiRWxib3cgUGxvdCIpCiNmdml6X2dhcF9zdGF0KGdhcF9zdGF0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkdhcCBTdGF0aXN0aWMiKQojZnZpel9uYmNsdXN0KHRvcDEwMDAwWzI6MjZdLCBrbWVhbnMsIG1ldGhvZD0ic2lsaG91ZXR0ZSIsIGsubWF4PTI0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIlNpbGhvdWV0dGUgUGxvdCIpCiNrLW1lYW5zIENsdXN0ZXJpbmcKQ0xBUkFrMyA8LSBjbGFyYShQUk9fMTAwMF9yZWxbMjoxOF0sMyxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNCA8LSBjbGFyYShQUk9fMTAwMF9yZWxbMjoxOF0sNCxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNSA8LSBjbGFyYShQUk9fMTAwMF9yZWxbMjoxOF0sNSxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNiA8LSBjbGFyYShQUk9fMTAwMF9yZWxbMjoxOF0sNixtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNyA8LSBjbGFyYShQUk9fMTAwMF9yZWxbMjoxOF0sNyxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrOCA8LSBjbGFyYShQUk9fMTAwMF9yZWxbMjoxOF0sOCxtZWRvaWRzLng9VFJVRSkKCgpQUk9fMTAwMF9yZWwkazMgPC0gQ0xBUkFrMyRjbHVzdGVyaW5nClBST18xMDAwX3JlbCRrNCA8LSBDTEFSQWs0JGNsdXN0ZXJpbmcKUFJPXzEwMDBfcmVsJGs1IDwtIENMQVJBazUkY2x1c3RlcmluZwpQUk9fMTAwMF9yZWwkazYgPC0gQ0xBUkFrNiRjbHVzdGVyaW5nClBST18xMDAwX3JlbCRrNyA8LSBDTEFSQWs3JGNsdXN0ZXJpbmcKUFJPXzEwMDBfcmVsJGs4IDwtIENMQVJBazgkY2x1c3RlcmluZwoKCiNEaXNwbGF5aW5nIEhlYXRtYXBzCiNrLW1lYW5zIDMKcGhlYXRtYXAoUFJPXzEwMDBfcmVsW29yZGVyKFBST18xMDAwX3JlbFssIDE4KzFdKSxdWywyOjE4XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz1QUk9fMTAwMF9yZWxbMTgrMV0pCiNrLW1lYW5zIDQKcGhlYXRtYXAoUFJPXzEwMDBfcmVsW29yZGVyKFBST18xMDAwX3JlbFssIDE4KzJdKSxdWywyOjE4XSwgY2x1c3Rlcl9jb2xzPVRSVUUsIGNsdXN0ZXJfcm93cz1GQUxTRSwgYm9yZGVyX2NvbG9yPU5BLCBzaG93X3Jvd25hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX3Jvdz1QUk9fMTAwMF9yZWxbMTgrMl0pCiNrLW1lYW5zIDUgCnBoZWF0bWFwKFBST18xMDAwX3JlbFtvcmRlcihQUk9fMTAwMF9yZWxbLCAxOCszXSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDBfcmVsWzE4KzNdKQojay1tZWFucyA2CnBoZWF0bWFwKFBST18xMDAwX3JlbFtvcmRlcihQUk9fMTAwMF9yZWxbLCAxOCs0XSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDBfcmVsWzE4KzRdKQojay1tZWFucyA3CnBoZWF0bWFwKFBST18xMDAwX3JlbFtvcmRlcihQUk9fMTAwMF9yZWxbLCAxOCs1XSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDBfcmVsWzE4KzVdKQojay1tZWFucyA4CnBoZWF0bWFwKFBST18xMDAwX3JlbFtvcmRlcihQUk9fMTAwMF9yZWxbLCAxOCs2XSksXVssMjoxOF0sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9UFJPXzEwMDBfcmVsWzE4KzZdKQpgYGAKClJlbW92aW5nIEFsaytBTENMIHRvIGRldGVybWluZSBpZiBQQ0Egc2VwYXJhdGlvbiBpbXByb3ZlcwpgYGB7cn0KZGRzX3N1YiA8LSBkZHNfcHJvWywtYyg0LDUsNiwxMCwxMSwyNSldICNFeGNsdWRpbmcgc2FtcGxlIG51bWJlcnMgb2YgdGhlIEFMSytBTENMIAplc3RpbWF0ZVNpemVGYWN0b3JzKGRkc19zdWIpICNNdXN0IHJlLWNhbGN1bGF0ZSBzaXplIGZhY3RvcnMgYWZ0ZXIgcmVtb3Zpbmcgc2FtcGxlcwpkZHNfc3ViCgpybGRfc3ViIDwtIHJsb2coZGRzX3N1YiwgYmxpbmQ9VFJVRSkKY29sbmFtZXMocmxkX3N1YikgPC0gcGFzdGUwKGRkc19zdWIkc2FtcGxlKQpzYW1wbGVEaXN0c19zdWIgPC0gZGlzdCh0KGFzc2F5KHJsZF9zdWIpKSkKc2FtcGxlRGlzdE10eF9zdWIgPC0gYXMubWF0cml4KHNhbXBsZURpc3RzX3N1YikKcm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpIDwtIGNvbG5hbWVzKHJsZF9zdWIpCmNvbG5hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSA8LSBOVUxMCmhjbHVzdF9zdWIgPC0gaGNsdXN0KHNhbXBsZURpc3RzX3N1YikKCnBsb3QoaGNsdXN0X3N1YiwgbGFiZWxzPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWFpbj0iUFJPLXNlcSBzdWJzZXQgR2VuZSBEZW5kcm9ncmFtIikKCmBgYAoKUENBcwpgYGB7cn0KcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIikgKyBnZ3RpdGxlKCJQUk8tc2VxIHN1YnNldCBQQ0EgVG9wIDUwMCIpICsgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGMoIkFUTEwiLCAiQ1RDTCIsICJBTEstQUxDTCIsICJTUUdEX1RDTCIsICJUX0xHTCIsICJOS1QiLCAiSFNfVENMIiwgIlBUQ0xfTk9TIiwgIk5LTCIpLCB2YWx1ZXM9YygiZGFya2dyYXkiLCAiY2hhcnRyZXVzZTMiLCAiY2FkZXRibHVlIiwgImN5YW4zIiwgInJlZCIsICJsaWdodHBpbmsiLCAiYmxhY2siLCAiZGFya2dvbGRlbnJvZDEiLCAiYmx1ZXZpb2xldCIpKSArIGdlb21fdGV4dF9yZXBlbChsYWJlbD1yb3duYW1lcyhzYW1wbGVEaXN0TXR4X3N1YiksIG1heC5vdmVybGFwcz01MCkKCnBsb3RQQ0EocmxkX3N1YiwgaW50Z3JvdXAgPSAic3VidHlwZSIsIG50b3A9MTAwMCkgKyBnZ3RpdGxlKCJQUk8tc2VxIHN1YnNldCBQQ0EgVG9wIDEwMDAiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpLCBtYXgub3ZlcmxhcHM9NTApCgpwbG90UENBKHJsZF9zdWIsIGludGdyb3VwID0gInN1YnR5cGUiLCBudG9wPTUwMDApICsgZ2d0aXRsZSgiUFJPLXNlcSBzdWJzZXQgUENBIFRvcCA1MDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xMDAwMCkgKyBnZ3RpdGxlKCJQUk8tc2VxIHN1YnNldCBQQ0EgVG9wIDEwMDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xNTAwMCkgKyBnZ3RpdGxlKCJQUk8tc2VxIHN1YnNldCBQQ0EgVG9wIDE1MDAwIikgKyBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygiQVRMTCIsICJDVENMIiwgIkFMSy1BTENMIiwgIlNRR0RfVENMIiwgIlRfTEdMIiwgIk5LVCIsICJIU19UQ0wiLCAiUFRDTF9OT1MiLCAiTktMIiksIHZhbHVlcz1jKCJkYXJrZ3JheSIsICJjaGFydHJldXNlMyIsICJjYWRldGJsdWUiLCAiY3lhbjMiLCAicmVkIiwgImxpZ2h0cGluayIsICJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsICJibHVldmlvbGV0IikpICsgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsPXJvd25hbWVzKHNhbXBsZURpc3RNdHhfc3ViKSwgbWF4Lm92ZXJsYXBzPTUwKQoKcGxvdFBDQShybGRfc3ViLCBpbnRncm91cCA9ICJzdWJ0eXBlIiwgbnRvcD0xMjA4ODgpICsgZ2d0aXRsZSgiUFJPLXNlcSBzdWJzZXQgUENBIEFsbCBDb250cmlidXRvcnMiKSArIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCJBVExMIiwgIkNUQ0wiLCAiQUxLLUFMQ0wiLCAiU1FHRF9UQ0wiLCAiVF9MR0wiLCAiTktUIiwgIkhTX1RDTCIsICJQVENMX05PUyIsICJOS0wiKSwgdmFsdWVzPWMoImRhcmtncmF5IiwgImNoYXJ0cmV1c2UzIiwgImNhZGV0Ymx1ZSIsICJjeWFuMyIsICJyZWQiLCAibGlnaHRwaW5rIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsdWV2aW9sZXQiKSkgKyBnZW9tX3RleHRfcmVwZWwobGFiZWw9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpLCBtYXgub3ZlcmxhcHM9NTApCmBgYAoKQWRkaXRpb25hbCBkZW5kcm9ncmFtIHBsb3RzCmBgYHtyfQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSkpKDI1NSkKcGhlYXRtYXAoc2FtcGxlRGlzdE10eF9zdWIsIGNvbD1jb2xvcnMsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19jb2xuYW1lcz1GQUxTRSwgc2hvd19yb3duYW1lcz1UUlVFLAogICAgICAgICBjbHVzdGVyX3Jvd3M9VFJVRSwgY2x1c3Rlcl9jb2xzPVRSVUUsIG1haW49IlBSTyBzdWJzZXQgU2FtcGxlIERpc3RhbmNlIENsdXN0ZXJpbmciKQpwbG90KGhjbHVzdChzYW1wbGVEaXN0c19zdWIpLCBsYWJlbHM9cm93bmFtZXMoc2FtcGxlRGlzdE10eF9zdWIpLCBtYWluPSJQUk8gc3Vic2V0IFNhbXBsZSBEaXN0YW5jZSBEZW5kcm9ncmFtIikKYGBgCgpHZW5lcmF0ZSBub3JtIGNvdW50cyBmaWxlCmBgYHtyfQpub3JtY291bnRzX3N1YiA8LSBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHNfc3ViLCBub3JtYWxpemVkPVRSVUUpKQpjb2xuYW1lcyhub3JtY291bnRzX3N1YikgPC0gYygiSFVUMTAyIiwgIlNUMSIsICJTdTlUMDEiLCAiU01aMSIsICJNWUxBIiwgIk1BQzJBIiwgIkZFUEQiLCAiS0FSUEFTMzg0IiwgIkRMNDAiLCAiT0NJTFkxMiIsICJIVVQ3OCIsICJISCIsICJNSiIsICJNVEEiLCAiTU9UTjEiLCAiTktMIiwgIkRFUkwyIiwgIktIWUcxIiwgIlNlQXgiKQojd3JpdGUudGFibGUobm9ybWNvdW50c19wcm8sIGZpbGU9InByb19ub3JtY291bnRzLnR4dCIsIHNlcD0iXHQiLCBjb2wubmFtZXM9VFJVRSwgcm93Lm5hbWVzPVRSVUUsIHF1b3RlPUZBTFNFKQpgYGAKCkFzc2VtYmxlIGNvdW50cyByZXN1bHRzCmBgYHtyfQphdmdfc3ViIDwtIGRhdGEuZnJhbWUocGVha0lEPXJvd25hbWVzKG5vcm1jb3VudHNfc3ViKSkKYXZnX3N1YiRERVJMMiA8LSAobm9ybWNvdW50c19zdWIkREVSTDIpCmF2Z19zdWIkREw0MCA8LSAobm9ybWNvdW50c19zdWIkREw0MCkKYXZnX3N1YiRGRVBEIDwtIChub3JtY291bnRzX3N1YiRGRVBEKQphdmdfc3ViJEhIIDwtIChub3JtY291bnRzX3N1YiRISCkKYXZnX3N1YiRIVVQ3OCA8LSAobm9ybWNvdW50c19zdWIkSFVUNzgpCmF2Z19zdWIkSFVUMTAyIDwtIChub3JtY291bnRzX3N1YiRIVVQxMDIpCmF2Z19zdWIkS0FSUEFTMzg0IDwtIChub3JtY291bnRzX3N1YiRLQVJQQVMzODQpCmF2Z19zdWIkS0hZRzEgPC0gKG5vcm1jb3VudHNfc3ViJEtIWUcxKQphdmdfc3ViJE1BQzJBIDwtIChub3JtY291bnRzX3N1YiRNQUMyQSkKYXZnX3N1YiRNSiA8LSAobm9ybWNvdW50c19zdWIkTUopCmF2Z19zdWIkTU9UTjEgPC0gKG5vcm1jb3VudHNfc3ViJE1PVE4xKQphdmdfc3ViJE1UQSA8LSAobm9ybWNvdW50c19zdWIkTVRBKQphdmdfc3ViJE1ZTEEgPC0gKG5vcm1jb3VudHNfc3ViJE1ZTEEpCmF2Z19zdWIkTktMIDwtIChub3JtY291bnRzX3N1YiROS0wpCmF2Z19zdWIkT0NJTFkxMiA8LSAobm9ybWNvdW50c19zdWIkT0NJTFkxMikKYXZnX3N1YiRTZUF4IDwtIChub3JtY291bnRzX3N1YiRTZUF4KQphdmdfc3ViJFNNWjEgPC0gKG5vcm1jb3VudHNfc3ViJFNNWjEpCmF2Z19zdWIkU1QxIDwtIChub3JtY291bnRzX3N1YiRTVDEpCmF2Z19zdWIkU3U5VDAxIDwtIChub3JtY291bnRzX3N1YiRTdTlUMDEpCgphdmdfc3ViJG1heCA8LSBhcHBseShhdmdfc3ViW2MoIkRFUkwyIiwgIkRMNDAiLCAiRkVQRCIsICJISCIsICJIVVQ3OCIsICJIVVQxMDIiLCAiS0FSUEFTMzg0IiwgIktIWUcxIiwgIk1BQzJBIiwgIk1KIiwgIk1PVE4xIiwgIk1UQSIsICJNWUxBIiwgIk5LTCIsICJPQ0lMWTEyIiwgIlNlQXgiLCAiU01aMSIsICJTVDEiLCAiU3U5VDAxIildLCAxLCBtYXgsIG5hLnJtPVRSVUUpCnJlbF9zdWIgPC0gZGF0YS5mcmFtZShwZWFrSUQ9YXZnX3N1YiRwZWFrSUQpCnJlbF9zdWIkREVSTDIgPC0gYXZnX3N1YiRERVJMMiAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkREw0MCA8LSBhdmdfc3ViJERMNDAgLyBhdmdfc3ViJG1heApyZWxfc3ViJEZFUEQgPC0gYXZnX3N1YiRGRVBEIC8gYXZnX3N1YiRtYXgKcmVsX3N1YiRISCA8LSBhdmdfc3ViJEhIIC8gYXZnX3N1YiRtYXgKcmVsX3N1YiRIVVQ3OCA8LSBhdmdfc3ViJEhVVDc4IC8gYXZnX3N1YiRtYXgKcmVsX3N1YiRIVVQxMDIgPC0gYXZnX3N1YiRIVVQxMDIgLyBhdmdfc3ViJG1heApyZWxfc3ViJEtBUlBBUzM4NCA8LSBhdmdfc3ViJEtBUlBBUzM4NCAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkS0hZRzEgPC0gYXZnX3N1YiRLSFlHMSAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkTUFDMkEgPC0gYXZnX3N1YiRNQUMyQSAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkTUogPC0gYXZnX3N1YiRNSiAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkTU9UTjEgPC0gYXZnX3N1YiRNT1ROMSAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkTVRBIDwtIGF2Z19zdWIkTVRBIC8gYXZnX3N1YiRtYXgKcmVsX3N1YiRNWUxBIDwtIGF2Z19zdWIkTVlMQSAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkTktMIDwtIGF2Z19zdWIkTktMIC8gYXZnX3N1YiRtYXgKcmVsX3N1YiRPQ0lMWTEyIDwtIGF2Z19zdWIkT0NJTFkxMiAvIGF2Z19zdWIkbWF4CnJlbF9zdWIkU2VBeCA8LSBhdmdfc3ViJFNlQXggLyBhdmdfc3ViJG1heApyZWxfc3ViJFNNWjEgPC0gYXZnX3N1YiRTTVoxIC8gYXZnX3N1YiRtYXgKcmVsX3N1YiRTVDEgPC0gYXZnX3N1YiRTVDEgLyBhdmdfc3ViJG1heApyZWxfc3ViJFN1OVQwMSA8LSBhdmdfc3ViJFN1OVQwMSAvIGF2Z19zdWIkbWF4CmBgYAoKUENBIHRvcCBjb250cmlidXRvcnMgc2VsZWN0aW9uICg1MDAwIHRyaWVkIGZpcnN0KQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKI2NoZWNrIHRoaXMKY29sbmFtZXMocmVsX3N1YikgPC0gYygiZFJFR3BlYWtJRCIsICJERVJMMi5lbmhhbmNlciIsICJETDQwLmVuaGFuY2VyIiwgIkZFUEQuZW5oYW5jZXIiLCAiSEguZW5oYW5jZXIiLCAiSFVUNzguZWhhbmNlciIsICJIVVQxMDIuZW5oYW5jZXIiLCAiS0FSUEFTMzg0LmVuaGFuY2VyIiwgIktIWUcxLmVuaGFuY2VyIiwgIk1BQzJBLmVoYW5jZXIiLCAgIk1KLmVuaGFuY2VyIiwgIk1PVE4xLmVuaGFuY2VyIiwgIk1UQS5lbmhhbmNlciIsICJNWUxBLmVuaGFuY2VyIiwgIk5LTC5lbmhhbmNlciIsICJPQ0lMWTEyLmVuaGFuY2VyIiwgIlNlQXguZWhhbmNlciIsICJTTVoxLmVuaGFuY2VyIiwgIlNUMS5lbmhhbmNlciIsICJTdTlUMDEuZW5oYW5jZXIiKQoKcnYgPC0gcm93VmFycyhhc3NheShybGRfc3ViKSkKc2VsZWN0IDwtIG9yZGVyKHJ2LCBkZWNyZWFzaW5nPVRSVUUpW3NlcV9sZW4obWluKDUwMDAsIGxlbmd0aChydikpKV0gCiNDaGFuZ2luZyB0aGUgNTAwMCBoZXJlIHdpbGwgc2VsZWN0IGEgRGlmZmVyZW50IG51bWJlciBvZiB0b3AgY29udHJpYnV0b3JzIGlmIGRlc2lyZWQKcGMgPC0gcHJjb21wKHQoYXNzYXkocmxkX3N1Yilbc2VsZWN0LF0pKQpsb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjJHJvdGF0aW9uKQphbG9hZCA8LSBhYnMobG9hZGluZ3MpCndyaXRlLnRhYmxlKHN3ZWVwKGFsb2FkLCAyLCBjb2xTdW1zKGFsb2FkKSwgIi8iKSwgZmlsZT0iVG9wIDUwMDAgcHJvIHN1YnNldCBQQ0EgQ29udHJpYnV0b3JzLnR4dCIpCiNDbGVhbiB1cCB2YXJpYWJsZXMKcm0ocnYpCnJtKHNlbGVjdCkKcm0ocGMpCnJtKGxvYWRpbmdzKQojTWVyZ2UgdG9wIDUwMDAgZWxlbWVudHMgd2l0aCB0aGVpciBhbm5vdGF0aW9ucwp0b3A1MDAwIDwtIGRSRUdfYW5ub3RbKGRSRUdfYW5ub3QkcGVha0lEICVpbiUgcm93bmFtZXMoYWxvYWQpKSxdCiN3cml0ZS50YWJsZSh0b3A1MDAwLCBmaWxlPSJUb3A1MDAwLnR4dCIsIHNlcD0nXHQnKQojZ2dwbG90KHRvcDUwMDAsIGFlcyh4PWZhY3RvcigxKSwgZmlsbD1nZW5vbWljQ2F0ZWdvcnkpKStnZW9tX2Jhcih3aWR0aD0xKStjb29yZF9wb2xhcigieSIpICsgZ2d0aXRsZSgiVG9wIDUwMDAgUENBIENvbnRyaWJ1dG9ycyBkUkVHcGVhayBBbm5vdGF0aW9ucyIpCiNnZ3Bsb3QoZFJFR19hbm5vdCwgYWVzKHg9ZmFjdG9yKDEpLCBmaWxsPWdlbm9taWNDYXRlZ29yeSkpK2dlb21fYmFyKHdpZHRoPTEpK2Nvb3JkX3BvbGFyKCJ5IikgKyBnZ3RpdGxlKCJBbGwgZFJFR3BlYWsgQW5ub3RhdGlvbnMiKQoKI2ZpbHRlciByZXN1bHRzIGRvd24gYnkgdG9wIGNvbnRyaWJ1dG9ycwpzdWJfNTAwMF9yZWwgPC0gcmVsX3N1YlsocmVsX3N1YiRkUkVHcGVha0lEICVpbiUgdG9wNTAwMCRwZWFrSUQpLF0KI0dhcCBTdGF0IENhbGN1bGF0aW9uCiNzZXQuc2VlZCg0MikgCiNUaGlzIHNldHMgdGhlIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIHNlZWQgc28gaXQgd2lsbCBhbHdheXMgcHJvZHVjZSB0aGUgc2FtZSByZXN1bHQuIFlvdSBjYW4gcGljayB3aGF0ZXZlciBudW1iZXIgeW91J2QgbGlrZS4KI2dhcF9zdGF0IDwtIGNsdXNHYXAocHJvXzUwMDBfcmVsWzI6MjZdLCBGVU4gPSBrbWVhbnMsIG5zdGFydCA9IDIwLCBLLm1heCA9IDI0LCBCID0gNTApIAojLi4uID0gbnVtYmVyIG9mIHNhbXBsZXMgKyAxCiNDbHVzdGVyIFN0YXQgUGxvdHMKI2Z2aXpfbmJjbHVzdChwcm9fNTAwMF9yZWxbMjoyNl0sIGttZWFucywgbWV0aG9kPSJ3c3MiLCBrLm1heD0yNCkgKyB0aGVtZV9taW5pbWFsKCkgKyBnZ3RpdGxlKCJFbGJvdyBQbG90IikKI2Z2aXpfZ2FwX3N0YXQoZ2FwX3N0YXQpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiR2FwIFN0YXRpc3RpYyIpCiNmdml6X25iY2x1c3QocHJvXzUwMDBfcmVsWzI6MjZdLCBrbWVhbnMsIG1ldGhvZD0ic2lsaG91ZXR0ZSIsIGsubWF4PTI0KSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIlNpbGhvdWV0dGUgUGxvdCIpCiNrLW1lYW5zIENsdXN0ZXJpbmcKQ0xBUkFrNCA8LSBjbGFyYShzdWJfNTAwMF9yZWxbMjoyMF0sNCxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNSA8LSBjbGFyYShzdWJfNTAwMF9yZWxbMjoyMF0sNSxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNiA8LSBjbGFyYShzdWJfNTAwMF9yZWxbMjoyMF0sNixtZWRvaWRzLng9VFJVRSkKQ0xBUkFrNyA8LSBjbGFyYShzdWJfNTAwMF9yZWxbMjoyMF0sNyxtZWRvaWRzLng9VFJVRSkKQ0xBUkFrOCA8LSBjbGFyYShzdWJfNTAwMF9yZWxbMjoyMF0sOCxtZWRvaWRzLng9VFJVRSkKCnN1Yl81MDAwX3JlbCRrNCA8LSBDTEFSQWs0JGNsdXN0ZXJpbmcKc3ViXzUwMDBfcmVsJGs1IDwtIENMQVJBazUkY2x1c3RlcmluZwpzdWJfNTAwMF9yZWwkazYgPC0gQ0xBUkFrNiRjbHVzdGVyaW5nCnN1Yl81MDAwX3JlbCRrNyA8LSBDTEFSQWs3JGNsdXN0ZXJpbmcKc3ViXzUwMDBfcmVsJGs4IDwtIENMQVJBazgkY2x1c3RlcmluZwoKI0Rpc3BsYXlpbmcgSGVhdG1hcHMKI2stbWVhbnMgNApwaGVhdG1hcChzdWJfNTAwMF9yZWxbb3JkZXIoc3ViXzUwMDBfcmVsWywgMjArMV0pLF1bLDI6MjBdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXN1Yl81MDAwX3JlbFsyMCsxXSkKI2stbWVhbnMgNQpwaGVhdG1hcChzdWJfNTAwMF9yZWxbb3JkZXIoc3ViXzUwMDBfcmVsWywgMjArMl0pLF1bLDI6MjBdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXN1Yl81MDAwX3JlbFsyMCsyXSkKI2stbWVhbnMgNgpwaGVhdG1hcChzdWJfNTAwMF9yZWxbb3JkZXIoc3ViXzUwMDBfcmVsWywgMjArM10pLF1bLDI6MjBdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXN1Yl81MDAwX3JlbFsyMCszXSkKI2stbWVhbnMgNwpwaGVhdG1hcChzdWJfNTAwMF9yZWxbb3JkZXIoc3ViXzUwMDBfcmVsWywgMjArNF0pLF1bLDI6MjBdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXN1Yl81MDAwX3JlbFsyMCs0XSkKI2stbWVhbnMgOApwaGVhdG1hcChzdWJfNTAwMF9yZWxbb3JkZXIoc3ViXzUwMDBfcmVsWywgMjArNV0pLF1bLDI6MjBdLCBjbHVzdGVyX2NvbHM9VFJVRSwgY2x1c3Rlcl9yb3dzPUZBTFNFLCBib3JkZXJfY29sb3I9TkEsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fcm93PXN1Yl81MDAwX3JlbFsyMCs1XSkKYGBgCgotLVBSTyBFTkQtLQoKQ29tYmluZWQgUFJPIGFuZCBSTkEgYW5hbHlzaXMKCkxvYWQgREVTZXEgb2JqZWN0cyBhbmQgYW5ub3RhdGlvbnMKYGBge3J9CiNkZHNfcm5hIDwtIHJlYWRSRFMoIlJOQV9kZHMucmRzIikKI2Rkc19wcm8gPC0gcmVhZFJEUygiZFJFR19kZHMucmRzIikKZFJFR2FubiA8LSByZWFkLnRhYmxlKCIwMDJfVENMc19wMTAwMF9tMTAwMDAwMF9nZW5lLWNlbnRyaWNfY2xvc2VzdC1kUkVHcGVha3MudHh0Iiwgc2VwPSJcdCIsIGhlYWRlcj1UKQp3cml0ZS50YWJsZShkZXNlcV9zaXplc19wcm8sIGZpbGU9IkRFc2VxIHNpemUgZmFjdG9ycy50eHQiLCBzZXA9Ilx0IiwgcXVvdGU9Riwgcm93Lm5hbWVzPVQpCmBgYAoKTWFrZSBwcmVsaW0gZGF0YWZyYW1lcwpgYGB7cn0Kbm9ybV9ybmEgPC0gYXMuZGF0YS5mcmFtZShjb3VudHMoZGRzX3JuYSwgbm9ybWFsaXplZD1UUlVFKSkKcmxkX3JuYTIgPC0gcmxvZyhkZHNfcm5hLCBibGluZD1UUlVFKQoKY29sbmFtZXMobm9ybV9ybmEpIDwtIGRkc19ybmEkc2FtcGxlICNTaW1wbGlmaWVkIG5hbWVzIGZyb20gZGRzIG1ldGFkYXRhCgpyZWxfcm5hMiA8LSBkYXRhLmZyYW1lKCJnZW5lSUQiPXJvd25hbWVzKG5vcm1fcm5hKSkKcmVsX3JuYTIkbWF4LmdlbmUuY291bnRzIDwtIGFwcGx5KG5vcm1fcm5hWzE6bmNvbChub3JtX3JuYSldLCAxLCBtYXgsIG5hLnJtPVRSVUUpCmk9MQp3aGlsZSAoaTw9bmNvbChub3JtX3JuYSkpewogIHJlbF9ybmEyW3Bhc3RlMChkZHNfcm5hJHNhbXBsZVtpXSwiLmdlbmUucmVsIildIDwtIG5vcm1fcm5hWyxpXS9yZWxfcm5hMiRtYXguZ2VuZS5jb3VudHMKICBpPWkrMQp9Cgpub3JtX3BybyA8LSBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHNfcHJvLCBub3JtYWxpemVkPVRSVUUpKQoKY29sbmFtZXMobm9ybV9wcm8pIDwtIGRkc19wcm8kc2FtcGxlICNTaW1wbGlmaWVkIG5hbWVzIGZyb20gZGRzIG1ldGFkYXRhCmNvbG5hbWVzKG5vcm1fcHJvKVsyXSA8LSAiU1QxIiAjVGhpbmsgdGhlcmUgd2FzIGEgdHlwbyBpbiB0aGlzIHNhbXBsZSBuYW1lCmNvbG5hbWVzKG5vcm1fcm5hKVs3XSA8LSAiS0FSUEFTMjk5Igpjb2xuYW1lcyhub3JtX3JuYSlbOF0gPC0gIktBUlBBUzM4NCIKbm9ybV9wcm8gPC0gbm9ybV9wcm9bbmFtZXMobm9ybV9ybmEpXSAjcmVvcmRlciBzYW1wbGUgY29sdW1ucyB0byBtYXRjaCBSTkEtc2VxIGRhdGEKCmNvbG5hbWVzKFBST19yZWwpWzFdIDwtICgiY2xvc2VzdF9wZWFrIikKI3JlbF9wcm8yIDwtIGRhdGEuZnJhbWUoImNsb3Nlc3RfcGVhayI9cm93bmFtZXMobm9ybV9wcm8pKQpQUk9fcmVsJG1heC5kUkVHLmNvdW50cyA8LSBhcHBseShub3JtX3Byb1sxOm5jb2wobm9ybV9wcm8pXSwgMSwgbWF4LCBuYS5ybT1UUlVFKQpQUk9fcmVsIDwtIFBST19yZWxbLGMoMSwyNywyOjI2KV0gI3Jlb3JkZXIgY29sdW1ucwojaT0xCiN3aGlsZSAoaTw9bmNvbChub3JtX3BybykpewojICByZWxfcHJvMltwYXN0ZTAoZGRzX3BybyRzYW1wbGVbaV0sIi5kUkVHLnJlbCIpXSA8LSBub3JtX3Byb1ssaV0vcmVsX3BybzIkbWF4LmRSRUcuY291bnRzCiMgIGk9aSsxCiN9CmBgYAoKU2VsZWN0aW5nIGdlbmUgUENBIGNvbnRyaWJ1dG9ycyBieSB2YXJpYW5jZQpgYGB7cn0KI1NlbGVjdCB0b3AgMTAwMDAgUENBIGNvbnRyaWJ1dG9ycwpydiA8LSByb3dWYXJzKGFzc2F5KHJsZF9ybmEyKSkKc2VsZWN0IDwtIG9yZGVyKHJ2LCBkZWNyZWFzaW5nPVRSVUUpW3NlcV9sZW4obWluKDEwMDAwLCBsZW5ndGgocnYpKSldICNDaGFuZ2luZyB0aGUgNTAwIGhlcmUgd2lsbCBzZWxlY3QgYSBkaWZmZXJlbnQgbnVtYmVyIG9mIHRvcCBjb250cmlidXRvcnMgaWYgZGVzaXJlZApwYyA8LSBwcmNvbXAodChhc3NheShybGRfcm5hMilbc2VsZWN0LF0pKQpsb2FkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHBjJHJvdGF0aW9uKQphbG9hZCA8LSBhYnMobG9hZGluZ3MpCnN3ZWVwKGFsb2FkLCAyLCBjb2xTdW1zKGFsb2FkKSwgIi8iKQogCiNDbGVhbiB1cCB2YXJpYWJsZXMKcm0ocnYpCnJtKHNlbGVjdCkKcm0ocGMpCnJtKGxvYWRpbmdzKQogCiNNZXJnZSB0b3AgNTAwIGVsZW1lbnRzIHdpdGggdGhlaXIgYW5ub3RhdGlvbnMKdG9wMTBrX3JlbF9ybmEgPC0gcmVsX3JuYTJbKHJlbF9ybmEyJGdlbmVJRCAlaW4lIHJvd25hbWVzKGFsb2FkKSksXSAjZmlsdGVyIHJlbCBnZW5lIGRhdGFmcmFtZSBmb3IgdG9wIDEwawpgYGAKCkRldGVybWluaW5nIGNsdXN0ZXJzIChrPTMwKQpgYGB7cn0KQ0xBUkEgPC0gY2xhcmEodG9wMTBrX3JlbF9ybmFbMzoyN10sMzAsbWVkb2lkcy54PVRSVUUpCgp0b3AxMGtfcmVsX3JuYSRrMzAgPC0gQ0xBUkEkY2x1c3RlcmluZwoKcGhlYXRtYXAodG9wMTBrX3JlbF9ybmFbb3JkZXIodG9wMTBrX3JlbF9ybmFbLDI4XSksXVssMzoyN10sIGNsdXN0ZXJfY29scz1UUlVFLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIGJvcmRlcl9jb2xvcj1OQSwgc2hvd19yb3duYW1lcz1GQUxTRSwgYW5ub3RhdGlvbl9yb3c9dG9wMTBrX3JlbF9ybmFbMjhdKQpgYGAKCkRhdGEgaW50ZWdyYXRpb24KYGBge3J9CmdlbmVfcmVzIDwtIHJlbF9ybmEyWyghcmVsX3JuYTIkZ2VuZUlEICVpbiUgdG9wMTBrX3JlbF9ybmEkZ2VuZUlEKSxdICNmaWx0ZXIgb3V0IGdlbmVzIG5vdCBpbiB0b3AgMTBrCmdlbmVfcmVzJGszMCA8LSBOQSAjYWRkIHZhbHVlIGZvciBnZW5lcyBub3QgY2x1c3RlcmVkCmdlbmVfcmVzIDwtIHJiaW5kKHRvcDEwa19yZWxfcm5hLCBnZW5lX3JlcykgI2NvbWJpbmUgd2l0aCB0b3AgMTBrIGdlbmVzIHdpdGggY2x1c3RlciBkZXNpZ25hdGlvbnMKI2dlbmVfcmVzJGdlbmVJRCA8LSBzYXBwbHkoc3Ryc3BsaXQoZ2VuZV9yZXMkZ2VuZUlELCBzcGxpdD0iWy5dIiksIGhlYWQsIDEpICNzaW1wbGlmeSBnZW5lSURzIGJ5IHJlbW92aW5nIHZlcnNpb24gbnVtYmVycwoKY29tYl9yZXMgPC0gdW5pcXVlKG1lcmdlKGRSRUdhbm4sIGdlbmVfcmVzLCBieS54PSJ6IiwgYnkueT0iZ2VuZUlEIiwgYWxsLnk9VCkpCmNvbG5hbWVzKGNvbWJfcmVzKVsxXSA8LSAiZ2VuZUlEIiAKY29tYl9yZXMgPC0gbWVyZ2UoY29tYl9yZXMsIFBST19yZWwsIGJ5Lng9ImNsb3Nlc3RfcGVhayIsIGJ5Lnk9ImNsb3Nlc3RfcGVhayIsIGFsbC54PVQpICNjb21iaW5lIHdpdGggZFJFRyBwZWFrIGRhdGEsIGtlZXAgZ2VuZXMgd2l0aG91dCBhIGNsb3Nlc3QgZFJFRyBwZWFrIGNhbGwKCmNvbWJfcmVzIDwtIGNvbWJfcmVzWyxjKDI6OSwzOSwxMzozOCwxMDoxMiwxLDQwOjY1KV0gI3Jlb3JkZXIgY29sdW1ucwpgYGAKCkdlbmUtdG8tRW5oYW5jZXIgY29uY29yZGFuY2UgYW5hbHlzaXMgLS0gdGhpcyBnZW5lcmF0ZXMgYSBzdGF0IHJhbmdpbmcgZnJvbSAtMSAoYW50aS1jb3JyZWxhdGVkKSB0byAwIChub3QgY29ycmVsYXRlZCkgdG8gKzEgKGNvcnJlbGF0ZWQpIHJlcG9ydGVkIGFzIFNwZWFybWFuIHJobwpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KI25vdGUgdGhpcyB3aWxsIHByb2R1Y2UgYSBsb3Qgb2YgZXJyb3JzIGZvciByb3dzIHRoYXQgZG9uJ3QgaGF2ZSBhIGdlbmUgYW5kIGEgYW4gZW5oYW5jZXIsIHNvIEkndmUgc2lsZW5jZWQgdGhlbSBoZXJlCnNwZWFyIDwtIGMoKQppIDwtIDEKd2hpbGUoaTw9bnJvdyhjb21iX3JlcykpewogIHNwZWFyaSA8LSBjb3IoYXMubnVtZXJpYyhmYWN0b3IoY29tYl9yZXNbaSwxMTozNV0pKSxhcy5udW1lcmljKGZhY3Rvcihjb21iX3Jlc1tpLDQxOjY1XSkpLG1ldGhvZD0ic3BlYXJtYW4iKQogIHNwZWFyIDwtIGMoc3BlYXIsIHNwZWFyaSkKICBpIDwtIGkrMQp9Cgpjb21iX3JlcyRTcGVhcm1hbi5yaG8gPC0gc3BlYXIKYGBgCgpTYXZlIG91dHB1dApgYGB7cn0Kd3JpdGUudGFibGUoY29tYl9yZXMsIGZpbGU9IndlaW5zdG9jazAwMi5maW5hbC50YWJsZS50eHQiLCBzZXA9Ilx0IiwgcXVvdGU9Riwgcm93Lm5hbWVzPUYpCmRSRUdjb3VudHNhbm4gPC0gbWVyZ2UoUFJPX3JlbCwgZFJFR19yZWFkRmlsdCwgYnkueD0iY2xvc2VzdF9wZWFrIiwgYnkueT0iZFJFR3BlYWtJRCIpCmRSRUdjb3VudHNhbm4gPC0gZFJFR2NvdW50c2FublssYygxLDI4OjMzLDI6MjcpXQp3cml0ZS50YWJsZShkUkVHY291bnRzYW5uLCBmaWxlPSJ3ZWluc3RvY2swMDIuZFJFR3MudHh0Iiwgc2VwPSJcdCIsIHF1b3RlPUYsIHJvdy5uYW1lcz1GKQpgYGAKCkNvcnJlY3Qgb3V0cHV0IHRvIGluY2x1ZGUgbWV0YWRhdGEgZm9yIGdlbmVzIHdpdGhvdXQgbmVhcmVzdCBlbmhhbmNlciBjYWxscwpgYGB7cn0KbGlicmFyeShkcGx5cikKCiNyZW1vdmUgY29sdW1ucyB3aXRoIGFubm90YXRpb24gaXNzdWUKY29tYl9yZXNfd29FbmggPC0gY29tYl9yZXMgJT4lIGZpbHRlcihpcy5uYShnZW5lTmFtZSkpCmNvbWJfcmVzX3dFbmggPC0gY29tYl9yZXMgJT4lIGZpbHRlcighaXMubmEoZ2VuZU5hbWUpKQoKI0xvYWQgb3JpZ2luYWwgdW5maWx0ZXJlZCBhbm5vdGF0aW9ucwpjb21wX2d0ZiA8LSByZWFkLnRhYmxlKCJIb21vX3NhcGllbnMuR1JDaDM4Ljk5LnVjc2MuZ3RmIiwgc2VwPSJcdCIpCmNvbG5hbWVzKGNvbXBfZ3RmKSA8LSBjKCJjaHIiLCAic291cmNlIiwgInR5cGUiLCAic3RhcnQiLCAiZW5kIiwgInNjb3JlIiwgInN0cmFuZCIsICJwaGFzZSIsICJhdHRyaWJ1dGVzIikKCiNGdW5jdGlvbiB0byBleHRyYWN0IG1ldGFkYXRhIGZyb20gZ3RmIGFubm90YXRpb24KZXh0cmFjdF9hdHRyaWJ1dGVzIDwtIGZ1bmN0aW9uKGd0Zl9hdHRyaWJ1dGVzLCBhdHRfb2ZfaW50ZXJlc3QpewogIGF0dCA8LSBzdHJzcGxpdChhcy5jaGFyYWN0ZXIoZ3RmX2F0dHJpYnV0ZXMpLCAiOyAiKQogIGF0dCA8LSBnc3ViKCJcIiIsIiIsdW5saXN0KGF0dCkpCiAgYXR0IDwtIGdzdWIoIjsiLCIiLHVubGlzdChhdHQpKQogIGlmKCFpcy5udWxsKHVubGlzdChzdHJzcGxpdChhdHRbZ3JlcChhdHRfb2ZfaW50ZXJlc3QsIGF0dCldLCAiICIpKSkpewogICAgcmV0dXJuKCB1bmxpc3Qoc3Ryc3BsaXQoYXR0W2dyZXAoYXR0X29mX2ludGVyZXN0LCBhdHQpXSwgIiAiKSlbMl0pCiAgfWVsc2V7CiAgICByZXR1cm4oTkEpfQp9CgojRXh0cmFjdCBkZXNpcmVkIGluZm9ybWF0aW9uIGZyb20gZ3RmIChnZW5lSUQsIGdlbmVOYW1lLCBiaW90eXBlKQpjb21wX2dlbmUgPC0gZmlsdGVyKGNvbXBfZ3RmLCB0eXBlID09ICJnZW5lIikKY29tcF9nZW5lJGdlbmVJRCA8LSB1bmxpc3QobGFwcGx5KGNvbXBfZ2VuZSRhdHRyaWJ1dGVzLCBleHRyYWN0X2F0dHJpYnV0ZXMsICJnZW5lX2lkIikpCmNvbXBfZ2VuZSRnZW5lTmFtZSA8LSB1bmxpc3QobGFwcGx5KGNvbXBfZ2VuZSRhdHRyaWJ1dGVzLCBleHRyYWN0X2F0dHJpYnV0ZXMsICJnZW5lX25hbWUiKSkKY29tcF9nZW5lJGJpb3R5cGUgPC0gdW5saXN0KGxhcHBseShjb21wX2dlbmUkYXR0cmlidXRlcywgZXh0cmFjdF9hdHRyaWJ1dGVzLCAiZ2VuZV9iaW90eXBlIikpCgojUmVtb3ZlIG9mZmVuZGluZyBjb2x1bW5zCiNnZW5lTmFtZSxiaW90eXBlLGF0dHJpYnV0ZXMsY2hyLHN0YXJ0LGVuZCxzdHJhbmQKY29tYl9yZXNfd29FbmggPC0gY29tYl9yZXNfd29FbmhbLGMoMSw5OjY2KV0KCiNBZGQgYmFjayBpbmZvcm1hdGlvbgpnZW5lSW5mbyA8LSBkYXRhLmZyYW1lKCJnZW5lSUQiPWNvbXBfZ2VuZSRnZW5lSUQsICJnZW5lTmFtZSI9Y29tcF9nZW5lJGdlbmVOYW1lLCAiYmlvdHlwZSI9Y29tcF9nZW5lJGJpb3R5cGUsICJhdHRyaWJ1dGVzIj1jb21wX2dlbmUkYXR0cmlidXRlcywgImNociI9Y29tcF9nZW5lJGNociwgInN0YXJ0Ij1jb21wX2dlbmUkc3RhcnQsICJlbmQiPWNvbXBfZ2VuZSRlbmQsICJzdHJhbmQiPWNvbXBfZ2VuZSRzdHJhbmQpCmNvbWJfcmVzX3dvRW5oX2NvcnIgPC0gbWVyZ2UoZ2VuZUluZm8sIGNvbWJfcmVzX3dvRW5oLCBieS54PSJnZW5lSUQiLCBieS55PSJnZW5lSUQiLCBhbGwueT1UKQoKI01vZGlmeSBnZW5lTmFtZSBhbmQgcGVha19jb3VudHMKY29tYl9yZXNfd29FbmhfY29yciRwZWFrX2NvdW50IDwtIDAKY29tYl9yZXNfd29FbmhfY29yciRnZW5lTmFtZSA8LSBwYXN0ZTAoY29tYl9yZXNfd29FbmhfY29yciRnZW5lTmFtZSkKCiNDb3JyZWN0aW5nIGdlbmVOYW1lcyBpbiBvcmlnaW5hbApjb21iX3Jlc193RW5oJGdlbmVOYW1lIDwtIHN1YnN0cmluZyhjb21iX3Jlc193RW5oJGdlbmVOYW1lLCAxKQpjb21iX3Jlc193RW5oJGdlbmVOYW1lIDwtIHBhc3RlMChjb21iX3Jlc193RW5oJGdlbmVOYW1lKQoKI0NvbWJpbmluZyBpdCBhbGwgdG9nZXRoZXIKY29tYl9yZXNfY29yciA8LSByYmluZChjb21iX3Jlc193RW5oLCBjb21iX3Jlc193b0VuaF9jb3JyKQoKd3JpdGUudGFibGUoY29tYl9yZXNfY29yciwgZmlsZT0id2VpbnN0b2NrLmNvbWJpbmVkLnJlc3VsdHMuY29ycmVjdGVkLnR4dCIsIHNlcD0iXHQiLCBxdW90ZT1GLCByb3cubmFtZXM9RikKYGBgCgpDb21iaW5pbmcgZnVsbCBhbm5vdGF0aW9uIHRvIHBsb3QgYmFzZWQgb24gZ2Vub21pYyBjYXRlZ29yeQpgYGB7cn0KZmlsdGVyZWRfcmVzIDwtIG1lcmdlKGRSRUdfYW5ub3QsIGNvbWJfcmVzX2NvcnIsIGJ5Lng9InBlYWtJRCIsIGJ5Lnk9ImNsb3Nlc3RfcGVhayIsIGFsbC55PUYpCndyaXRlLnRhYmxlKGZpbHRlcmVkX3JlcywgZmlsZT0iT3ZlcmxhcGluZyBjb250cmlidG9ycy50eHQiLCBzZXA9J1x0JywgcXVvdGU9Riwgcm93Lm5hbWVzPUYpCmdncGxvdChmaWx0ZXJlZF9yZXMsIGFlcyh4PWZhY3RvcigxKSwgZmlsbD1nZW5vbWljQ2F0ZWdvcnkpKStnZW9tX2Jhcih3aWR0aD0xKStjb29yZF9wb2xhcigieSIpICsgZ2d0aXRsZSgiT3ZlcmxhcHBpbmcgUENBIENvbnRyaWJ1dG9ycyBmb3IgR2VuZSBFeHByZXNzaW9uIGFuZCBkUkVHcGVhayBBbm5vdGF0aW9ucyIpCmBgYAoKR2VuZXJhdGluZyBub3JtZWQgY291bnRzIHRhYmxlIGJ5IHRvcCA1MEsgY29udHJpYnV0b3JzCmBgYHtyfQpydiA8LSByb3dWYXJzKGFzc2F5KHJsZF9wcm8pKQpzZWxlY3QgPC0gb3JkZXIocnYsIGRlY3JlYXNpbmc9VFJVRSlbc2VxX2xlbihtaW4oNTAwMDAsIGxlbmd0aChydikpKV0gCiNDaGFuZ2luZyB0aGUgNTAwMDAgaGVyZSB3aWxsIHNlbGVjdCBhIERpZmZlcmVudCBudW1iZXIgb2YgdG9wIGNvbnRyaWJ1dG9ycyBpZiBkZXNpcmVkCnBjIDwtIHByY29tcCh0KGFzc2F5KHJsZF9wcm8pW3NlbGVjdCxdKSkKbG9hZGluZ3MgPC0gYXMuZGF0YS5mcmFtZShwYyRyb3RhdGlvbikKYWxvYWQgPC0gYWJzKGxvYWRpbmdzKQp3cml0ZS50YWJsZShzd2VlcChhbG9hZCwgMiwgY29sU3VtcyhhbG9hZCksICIvIiksIGZpbGU9IlRvcCA1MDAwMCBQUk8gQ29udHJpYnV0b3JzLnR4dCIpCgp0b3A1MGtfcmVsX3BybyA8LSBQUk9fcmVsWyhQUk9fcmVsJGNsb3Nlc3RfcGVhayAlaW4lIHJvd25hbWVzKGFsb2FkKSksXSAjZmlsdGVyIHJlbCBnZW5lIGRhdGFmcmFtZSBmb3IgdG9wIDUwawpDTEFSQSA8LSBjbGFyYSh0b3A1MGtfcmVsX3Byb1szOjI3XSwzLG1lZG9pZHMueD1UUlVFKQoKdG9wNTBrX3JlbF9wcm8kazMgPC0gQ0xBUkEkY2x1c3RlcmluZwoKZW5oYW5fcmVzIDwtIFBST19yZWxbKFBST19yZWwkY2xvc2VzdF9wZWFrICVpbiUgdG9wNTBrX3JlbF9wcm8kY2xvc2VzdF9wZWFrKSxdICNmaWx0ZXIgb3V0IGdlbmVzIG5vdCBpbiB0b3AgNTBrCmVuaGFuX3JlcyRrMyA8LSBOQSAjYWRkIHZhbHVlIGZvciBnZW5lcyBub3QgY2x1c3RlcmVkCmVuaGFuX3JlcyA8LSB0b3A1MGtfcmVsX3BybyAjY29tYmluZSB3aXRoIHRvcCA1MGsgZ2VuZXMgd2l0aCBjbHVzdGVyIGRlc2lnbmF0aW9ucwpjb21iX3JlcyA8LSB1bmlxdWUobWVyZ2UoZFJFR19hbm5vdCwgZW5oYW5fcmVzLCBieS54PSJwZWFrSUQiLCBieS55PSJjbG9zZXN0X3BlYWsiLCBhbGwueT1UKSkKCgpgYGAKCgpDb21iaW5hdGlvbiBjb21wbGV0ZWQsIGZ1cnRoZXIgaW52ZXN0aWdhdGlvbiBpbnRvIGNsdXN0ZXJzIG9uZ29pbmcgLSA4REVDMjE=