Data Preprocessing
After looking at the table heads, there are a couple of issues that
we can see:
1) The sample labels aren't identical - some have extra elements at the beginning or end, which need to be standardized
2) The number of samples in each file aren't the same - for example, miRNA only has 541 samples, and lncRNA has 556. This also needs to be standardized to make sure only samples with all data are used.
Let’s start with step 1.
The general format of the data should look something like this:
‘TCGA-XX-XXXX-XX’, so let’s look at each file to see how we can fix
it.
lncRNA seems to have extra labels at the start which we can remove,
as well as underscores which we can convert to hyphens. However, what’s
also important here is that we have normal and tumor samples explictly
labeled, whereas other files use the ‘01’ marking for tumors and ‘11’
marking for normal samples. We need to adapt our lncRNA data to follow
this structure.
#We are going through each column in the lncRNA dataset
for (i in 1:ncol(lncRNA)) {
#If the column name - which is the sample ID - contains Normal, we'll add a -11 and format the name to remove the beginning and convert all underscores to hyphens.
if (grepl("Normal", colnames(lncRNA)[i], fixed = TRUE) == TRUE) {
colnames(lncRNA)[i] <- sub(".*-TC", "TC", colnames(lncRNA)[i])
colnames(lncRNA)[i] <- gsub("_", "-", colnames(lncRNA)[i])
colnames(lncRNA)[i] <- paste(colnames(lncRNA)[i], '-11', sep="")
} else {
#Otherwise, we'll still format the name, but we'll add a -01 at the end instead.
colnames(lncRNA)[i] <- sub(".*-TC", "TC", colnames(lncRNA)[i])
colnames(lncRNA)[i] <- gsub("_", "-", colnames(lncRNA)[i])
colnames(lncRNA)[i] <- paste(colnames(lncRNA)[i], '-01', sep="")
}
}
#We'll convert the first column to the standard name Gene_ID and remove the extra marker in the Ensemble ID after the decimal point.
colnames(lncRNA)[1] <- "Gene_ID"
lncRNA$Gene_ID <- sub("\\..*", "", lncRNA$Gene_ID)
head(lncRNA)
That looks more in line with the standard sample notation.
Both the methylation and the mRNA file have underscores that we can
convert to hyphens.
#We'll iterate over each column and convert the underscores to dashes, for both datasets. Then, we'll convert the first column to the Gene_ID label.
for (i in 1:ncol(mRNA)) {
colnames(mRNA)[i] <- gsub("_", "-", colnames(mRNA)[i])
}
colnames(mRNA)[1] <- "Gene_ID"
mRNA <- mRNA[30:20531,]
head(mRNA)
#for (i in 1:ncol(methylation)) {
# colnames(methylation)[i] <- gsub("_", "-", colnames(methylation)[i])
#}
#colnames(methylation)[1] <- "Gene_ID"
#head(methylation)
That seems to be fixed as well.
For miRNA data, there is a lot of extraneous data at the end about
sample and vials, which we don’t need, so let’s remove that.
#We'll iterate over the column names and remove any extraneous information after our normal or tumor sample labels, and then create the Gene_ID column.
for (i in 1:ncol(miRNA)) {
colnames(miRNA)[i] <- sub("_01.*", "_01", colnames(miRNA)[i])
colnames(miRNA)[i] <- sub("_11.*", "_11", colnames(miRNA)[i])
colnames(miRNA)[i] <- gsub("_", "-", colnames(miRNA)[i])
}
colnames(miRNA)[1] <- "Gene_ID"
miRNA$'miRNA-ID' <- NULL
miRNA <- miRNA[!grepl('precursor', miRNA$`miRNA-region`),]
miRNA <- miRNA[!grepl('stemloop', miRNA$`miRNA-region`),]
miRNA$'miRNA-region' <- NULL
head(miRNA)
Done!
For clinical data, we have our ‘Sample ID’ column with appropriate
notation, so we don’t need to change that.
Now, for step 2, we have to identify which samples are missing from
any of the files, as we only want data points present in each file. To
accomplish this, I am first going to access all the sample IDs from each
file. I’m then going to add them together to form a vector, and use the
table function to see how many times each value appears in the vector.
Given that we have 5 files of data, a sample present in all files should
appear at least 5 times. Thus, we will isolate any values that appear
less than 5 times.
#Here we access the specific sample names through indexing of the data (which starts from column 2).
clin_samples <- clinical$`Sample ID`
lnc_samples <- colnames(lncRNA)[2:557]
#meth_samples <- colnames(methylation)[5:571]
miR_samples <- colnames(miRNA)[2:1609]
mRNA_samples <- colnames(mRNA)[2:569]
#We concatenate all the sample data into a vector.
temp <- c(lnc_samples, miR_samples, mRNA_samples)
#Next, we count the occurrence of each unique sample ID in our vector using the table function - if a sample is present in all 4 datasets, it'll have a count of 4.
temp_table = table(temp)
#Now, we just want to keep the samples that have an occurrence of 4.
keep1 <- names(temp_table[temp_table >= 3])
keep1 <- c("Gene_ID", keep1)
Now, we will remove their columns/rows from each data file in a
sequential manner.
#Next, we just subset the datasets to only keep columns that match a value in our vector of accepted samples - using the subset and select functions.
miRNA_new <- subset(miRNA, select=c(keep1))
mRNA_new <- subset(mRNA, select=c(keep1))
#methylation_new <- subset(methylation, select=c(keep1))
lncRNA_new <- subset(lncRNA, select=c(keep1))
One additional step we need to take is to make sure that all our
tumor samples have clinical data available. Thus, I’m going to compare
our tumor samples (with the -01 ending) to our clinical sample IDs to
find and also remove any samples that don’t overlap, using a similar
method.
normal_samples
[1] "TCGA-BJ-A28R-11" "TCGA-BJ-A28W-11" "TCGA-BJ-A28X-11" "TCGA-BJ-A290-11" "TCGA-BJ-A2N7-11"
[6] "TCGA-BJ-A2N8-11" "TCGA-BJ-A2N9-11" "TCGA-BJ-A2NA-11" "TCGA-BJ-A3PR-11" "TCGA-BJ-A3PU-11"
[11] "TCGA-DO-A1JZ-11" "TCGA-E8-A2JQ-11" "TCGA-EL-A3GZ-11" "TCGA-EL-A3H1-11" "TCGA-EL-A3H2-11"
[16] "TCGA-EL-A3H7-11" "TCGA-EL-A3MW-11" "TCGA-EL-A3MX-11" "TCGA-EL-A3MY-11" "TCGA-EL-A3N2-11"
[21] "TCGA-EL-A3N3-11" "TCGA-EL-A3T0-11" "TCGA-EL-A3T1-11" "TCGA-EL-A3T2-11" "TCGA-EL-A3T3-11"
[26] "TCGA-EL-A3T6-11" "TCGA-EL-A3T7-11" "TCGA-EL-A3T8-11" "TCGA-EL-A3TA-11" "TCGA-EL-A3TB-11"
[31] "TCGA-EL-A3ZG-11" "TCGA-EL-A3ZH-11" "TCGA-EL-A3ZK-11" "TCGA-EL-A3ZL-11" "TCGA-EL-A3ZM-11"
[36] "TCGA-EL-A3ZO-11" "TCGA-EL-A3ZP-11" "TCGA-EL-A3ZQ-11" "TCGA-EL-A3ZR-11" "TCGA-EL-A3ZS-11"
[41] "TCGA-EL-A3ZT-11" "TCGA-EM-A1CS-11" "TCGA-EM-A1CT-11" "TCGA-EM-A1CU-11" "TCGA-EM-A1CV-11"
[46] "TCGA-EM-A1CW-11" "TCGA-EM-A1YC-11" "TCGA-EM-A3ST-11" "TCGA-ET-A2MX-11" "TCGA-ET-A2N5-11"
[51] "TCGA-ET-A3DP-11" "TCGA-ET-A3DW-11" "TCGA-FY-A3TY-11" "TCGA-GE-A2C6-11" "TCGA-H2-A2K9-11"
[56] "TCGA-H2-A3RI-11" "TCGA-KS-A41I-11" "TCGA-KS-A41J-11" "TCGA-KS-A41L-11"
Now, all our data formatting is done - each of our datasets is
composed of 542 samples, with 492 tumor samples (as the clinical data
suggests) and 50 normal samples. Before we move into our actual
analysis, we need to make sure all our samples have data points for the
RNAs being analyzed. Since a lot of the files have ‘NA’ values in them,
we can’t work with this, so we’ll just eliminate all rows containing an
NA.
library(dplyr)
Warning: package ‘dplyr’ was built under R version 4.2.2
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(readr)
Warning: package ‘readr’ was built under R version 4.2.2
library(edgeR)
Warning: package ‘edgeR’ was built under R version 4.2.2Loading required package: limma
Warning: package ‘limma’ was built under R version 4.2.2
#For each dataset, we are going to remove any rows with NA in them, and then convert it to a data frame to work with our DESeq2 functions.
miRNA_new[miRNA_new == "NA"] <- NA
miRNA_final <- miRNA_new[complete.cases(miRNA_new), ]
miRNA_final <- na.omit(miRNA_final)
miRNA_final = data.frame(miRNA_final)
mRNA_new[mRNA_new == "NA"] <- NA
mRNA_final <- mRNA_new[complete.cases(mRNA_new), ]
mRNA_final = data.frame(mRNA_final)
lncRNA_new[lncRNA_new == "NA"] <- NA
lncRNA_final <- lncRNA_new[complete.cases(lncRNA_new), ]
lncRNA_final = data.frame(lncRNA_final)
#methylation_new[methylation_new == "NA"] <- NA
#methylation_final <- methylation_new[complete.cases(methylation_new), ]
#methylation_final = data.frame(methylation_final)
Differential Gene Expression
We finally have our final datasets that we can work with. Let’s begin
with analysis.
We first should create a proper metadata variable to begin analysis,
by considering tumor and normal samples. However, there are different
levels of analysis we can conduct, which means we’ll create a couple of
metadata files based on clinical data.
First, let’s create a file with a simple distribution of group 0 for
normal tissue and group 1 for tumor tissue.
library(DESeq2)
library(ggplot2)
#Access sample IDs to form column 1, then check for the .01 tag to assign groups as 1 or 0 for tumor or normal.
metadata <- data.frame("Sample_ID"=c(colnames(lncRNA_final)[2:552]))
metadata$'Group' <- ifelse(grepl(".01", metadata$Sample_ID, fixed = TRUE) == TRUE, 1, 0)
metadata$Group <- as.factor(metadata$Group)
for (i in 1:551) {
sample <- metadata[i, 1]
sample2 <- gsub("\\.", "-", sample)
row1 <- clin_2[which(clin_2$sample == sample2), ]
metadata[i, c("OS_time")] <- as.numeric(row1$'OS.time')
metadata[i, c("OS_Status")] <- as.numeric(row1$'OS')
metadata[i, c("PFI_time")] <- as.numeric(row1$'PFI.time')
metadata[i, c("PFI_Status")] <- as.numeric(row1$'PFI')
metadata[i, c("DSS_time")] <- as.numeric(row1$'DSS.time')
metadata[i, c("DSS_Status")] <- as.numeric(row1$'DSS')
#if (grepl(".11", sample, fixed=TRUE) == TRUE) {
# metadata[i, c("days_to_death")] <- runif(1, 1000, 4000)
# metadata[i, c("Status")] <- 0
#} else{
# metadata[i, c("days_to_death")] <- as.numeric(group1) * 30
# metadata[i, c("Status")] <- as.numeric(row1$Survival_Group)
#}
}
Next, let’s create a metadata file that adds in recurrent samples as
being group 2, and primary samples as being group 1.
#Access sample IDs to form column 1, then if the tumor is normal, assign group 0. If the tumor is not normal, reference clinical data for disease free status, and assign group 2 to recurred samples.
metadata_recur <- data.frame("Sample_ID"=c(colnames(lncRNA_final)[2:552]))
for (i in 1:551) {
sample <- metadata_recur[i, 1]
sample2 <- gsub("\\.", "-", sample)
row1 <- clin_new[which(clin_new$Sample.ID == sample2), ]
group1 <- row1$Recurrence_Group
group2 <- row1$Overall.Survival..Months.
if (grepl(".11", sample, fixed=TRUE) == TRUE) {
metadata_recur[i, c("Group")] <- 0
metadata_recur[i, c("days_to_death")] <- runif(1, 1000, 4000)
metadata_recur[i, c("Status")] <- 0
} else {
metadata_recur[i, c("days_to_death")] <- as.numeric(group2) * 30
metadata_recur[i, c("Status")] <- as.numeric(row1$Survival_Group)
if (group1 == 1) {
metadata_recur[i, c("Group")] <- 1
} else{
metadata_recur[i, c("Group")] <- 2
}
}
}
metadata_recur$Group <- as.factor(metadata_recur$Group)
We can also create a metadata file to evaluate metastatic
vs. non-metastatic samples, which can form group 1 and 2
respectively.
#Access sample IDs to form column 1, then if the tumor is normal, assign group 0. If the tumor is not normal, reference clinical data for metastatic status, and assign group 1 to metastatic samples.
metadata_metas <- data.frame("Sample_ID"=c(colnames(lncRNA_final)[2:543]))
for (i in 1:542) {
sample <- metadata_metas[i, 1]
sample2 <- gsub("\\.", "-", sample)
row1 <- clin_new[which(clin_new$Sample.ID == sample2), ]
group1 <- row1$Metastasis_Group
if (grepl(".11", sample, fixed=TRUE) == TRUE) {
metadata_metas[i, c("Group")] <- 0
} else {
if (group1 == 1) {
metadata_metas[i, c("Group")] <- 1
} else{
metadata_metas[i, c("Group")] <- 2
}
metadata_metas[i, c("days_to_death")] <- row1$Overall.Survival..Months.
}
}
metadata_metas$Group <- as.factor(metadata_metas$Group)
#Need to convert the gene names to the actual row names, and remove that column
m_DESEQ <- mRNA_final[,-1]
rownames(m_DESEQ) <- mRNA_final$Gene_ID
library(GDCRNATools)
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
##############################################################################
Pathview is an open source software package distributed under GNU General
Public License version 3 (GPLv3). Details of GPLv3 is available at
http://www.gnu.org/licenses/gpl-3.0.html. Particullary, users are required to
formally cite the original Pathview paper (not just mention it) in publications
or products. For details, do citation("pathview") within R.
The pathview downloads and uses KEGG data. Non-academic uses may require a KEGG
license agreement (details at http://www.kegg.jp/kegg/legal.html).
##############################################################################
library("AnnotationDbi")
Warning: package ‘AnnotationDbi’ was built under R version 4.2.2
Attaching package: ‘AnnotationDbi’
The following object is masked from ‘package:dplyr’:
select
library("org.Hs.eg.db")
m_DESEQ <- m_DESEQ[30:20531,]
m_DESEQ$'ENTREZ' <- c(rownames(m_DESEQ))
m_DESEQ$'ENTREZ' <- gsub(".*\\|", "", m_DESEQ$'ENTREZ')
m_DESEQ$'Ensemble' <- mapIds(org.Hs.eg.db, keys=m_DESEQ$'ENTREZ', keytype="ENTREZID", column="ENSEMBL")
'select()' returned 1:many mapping between keys and columns
rownames(m_DESEQ) <- make.names(m_DESEQ$Ensemble, unique=TRUE)
m_DESEQ$Ensemble <- NULL
m_DESEQ$ENTREZ <- NULL
m_DESEQ <- m_DESEQ[complete.cases(m_DESEQ), ]
metadata_new <- data.frame(c(metadata$Sample_ID))
metadata_new$'Group' <- ifelse(metadata$Group == 0, 'NormalTissue', 'PrimaryTumor')
metadata_new$'days_to_death' <- metadata$days_to_death
#metadata_new$'days_to_last_follow_up' = NA
#metadata_test <- gdcParseMetadata(project.id='TCGA-THCA', data.type='RNAseq')
DEGAll <- gdcDEAnalysis(counts=round(m_DESEQ), group=metadata_new$Group, comparison='NormalTissue-PrimaryTumor', method='limma')
dePC_mRNA <- gdcDEReport(deg=DEGAll)
head(dePC_mRNA)
#Need to convert the gene names to the actual row names, and remove that column
mi_DESEQ <- miRNA_final[,-1]
rownames(mi_DESEQ) <- miRNA_final$Gene_ID
mi_DESEQ[] <- lapply(mi_DESEQ, as.numeric)
rownames(mi_DESEQ) <- sub("r", "R", rownames(mi_DESEQ))
mi_DESEQ <- mi_DESEQ[20:292,]
mi_DESEQ <- mi_DESEQ[!grepl('unannotated', rownames(mi_DESEQ)),]
mi_DESEQ <- na.omit(mi_DESEQ)
library(GDCRNATools)
library("AnnotationDbi")
library("org.Hs.eg.db")
DEGAll <- gdcDEAnalysis(counts=round(mi_DESEQ), group=metadata_new$Group, comparison='NormalTissue-PrimaryTumor', method='limma')
dePC_miRNA <- gdcDEReport(deg=DEGAll)
head(dePC_miRNA)
#Need to convert the gene names to the actual row names, and remove that column
lnc_DESEQ <- lncRNA_final[,-1]
rownames(lnc_DESEQ) <- lncRNA_final$Gene_ID
library(GDCRNATools)
library("AnnotationDbi")
library("org.Hs.eg.db")
metadata_new <- data.frame(c(metadata$Sample_ID))
metadata_new$'Group' <- ifelse(metadata$Group == 0, 'NormalTissue', 'PrimaryTumor')
DEGAll <- gdcDEAnalysis(counts=round(lnc_DESEQ), group=metadata_new$Group, comparison='NormalTissue-PrimaryTumor', method='limma')
dePC_lnc <- gdcDEReport(deg=DEGAll)
head(dePC_lnc)
NA
ceOutput <- gdcCEAnalysis(lnc = rownames(lnc_Expr_2),
pc = rownames(m_Expr_2),
lnc.targets = 'starBase',
pc.targets = 'starBase',
rna.expr = RNA_tot,
mir.expr = mi_Expr_2)
Step 1/3: Hypergenometric test done !
Error in mir.expr[mir, ] : subscript out of bounds
gdcBarPlot(dePC_miRNA, angle=45, data.type='miRNA')
lnc_Expr_2 <- lnc_Expr[rownames(lnc_Expr) %in% rownames(lnc_de),]
m_Expr_2 <- m_Expr[rownames(m_Expr) %in% rownames(m_de),]
mi_Expr_2 <- mi_Expr[rownames(mi_Expr) %in% rownames(dePC_miRNA), ]
RNA_tot = rbind(lnc_Expr_2, m_Expr_2)
mi_Expr_df <- data.frame(mi_Expr)
deLNC <- c('ENSG00000260920','ENSG00000242125','ENSG00000261211')
dePC <- c('ENSG00000043355','ENSG00000109586','ENSG00000144355', 'ENSG00000198626')
genes <- c(deLNC, dePC)
samples <- c('TCGA-2F-A9KO-01', 'TCGA-2F-A9KP-01',
'TCGA-2F-A9KQ-01', 'TCGA-2F-A9KR-01',
'TCGA-2F-A9KT-01', 'TCGA-2F-A9KW-01')
rnaExpr <- data.frame(matrix(c(2.7,7.0,4.9,6.9,4.6,2.5,
0.5,2.5,5.7,6.5,4.9,3.8,
2.1,2.9,5.9,5.7,4.5,3.5,
2.7,5.9,4.5,5.8,5.2,3.0,
2.5,2.2,5.3,4.4,4.4,2.9,
2.4,3.8,6.2,3.8,3.8,4.2,
1.0,2.0,3.0,4.0,5.0,6.0),7,6),
stringsAsFactors=FALSE)
rownames(rnaExpr) <- genes
colnames(rnaExpr) <- samples
mirExpr <- data.frame(matrix(c(7.7,7.4,7.9,8.9,8.6,9.5,
5.1,4.4,5.5,8.5,4.4,3.5,
4.9,5.5,6.9,6.1,5.5,4.1,
12.4,13.5,15.1,15.4,13.0,12.8,
2.5,2.2,5.3,4.4,4.4,2.9,
2.4,2.7,6.2,1.5,4.4,4.2,
1.0, 2.0, 3.0, 4.0, 5.0, 6.0),7,6),
stringsAsFactors=FALSE)
colnames(mirExpr) <- samples
rownames(mirExpr) <- c('hsa-miR-340-5p-mature','hsa-miR-181b-1-5p-mature',
'hsa-miR-181a-2-3p-mature', 'hsa-miR-195-5p-mature',
'hsa-miR-199b-5p','hsa-miR-182-5p', 'hsa-miR-146b-5p-mature')
ceOutput <- gdcCEAnalysis(lnc = deLNC,
pc = dePC,
lnc.targets = 'starBase',
pc.targets = 'starBase',
rna.expr = rnaExpr,
mir.expr = mirExpr)
Step 1/3: Hypergenometric test done !
Step 2/3: Correlation analysis done !
Step 3/3: Regulation pattern analysis done !
library(survminer)
Warning: package ‘survminer’ was built under R version 4.2.2Loading required package: ggplot2
Warning: package ‘ggplot2’ was built under R version 4.2.2Loading required package: ggpubr
Warning: package ‘ggpubr’ was built under R version 4.2.2
Attaching package: ‘survminer’
The following object is masked from ‘package:survival’:
myeloma
gene_1 <- RNA_tot_2_merged[RNA_tot_2_merged$Gene1_Quartile %in% c(1, 4),]
gene_1$Gene1_Quartile <- sub(4, 2, gene_1$Gene1_Quartile)
sfit_1 <- survfit(Surv(OS_time, OS_Status)~Gene1_Quartile, data=gene_1)
summary(sfit_1)
Call: survfit(formula = Surv(OS_time, OS_Status) ~ Gene1_Quartile,
data = gene_1)
Gene1_Quartile=1
time n.risk n.event survival std.err lower 95% CI upper 95% CI
243 132 1 0.992 0.00755 0.978 1.000
1019 69 1 0.978 0.01610 0.947 1.000
1500 44 1 0.956 0.02703 0.904 1.000
1597 41 1 0.933 0.03501 0.866 1.000
1734 38 1 0.908 0.04181 0.830 0.994
1753 37 1 0.883 0.04734 0.795 0.981
Gene1_Quartile=2
time n.risk n.event survival std.err lower 95% CI upper 95% CI
1.01e+03 6.50e+01 1.00e+00 9.85e-01 1.53e-02 9.55e-01 1.00e+00
ggsurvplot(sfit_1, conf.int=FALSE, pval=TRUE, risk.table=TRUE, risk.table.col="strata",
legend.labs=c("Low Expression", "High Expression"), legend.title="Group",
palette=c("dodgerblue2", "red3"),
title="Kaplan-Meier Curve for hsa-miR-146b-3p-mature", risk.table.height=0.3)


gene_2 <- RNA_tot_2_merged[RNA_tot_2_merged$Gene2_Quartile %in% c(1, 4),]
gene_2$Gene2_Quartile <- sub(4, 2, gene_2$Gene2_Quartile)
sfit_2 <- survfit(Surv(PFI_time, PFI_Status)~Gene2_Quartile, data=gene_2)
summary(sfit_2)
Call: survfit(formula = Surv(PFI_time, PFI_Status) ~ Gene2_Quartile,
data = gene_2)
Gene2_Quartile=1
time n.risk n.event survival std.err lower 95% CI upper 95% CI
30 138 1 0.993 0.00722 0.979 1.000
127 132 2 0.978 0.01273 0.953 1.000
158 130 1 0.970 0.01468 0.942 0.999
225 127 1 0.963 0.01644 0.931 0.995
267 124 2 0.947 0.01950 0.910 0.986
279 121 1 0.939 0.02085 0.899 0.981
329 120 1 0.931 0.02209 0.889 0.976
363 116 1 0.923 0.02332 0.879 0.970
385 113 1 0.915 0.02450 0.868 0.964
439 112 1 0.907 0.02561 0.858 0.959
445 110 1 0.899 0.02667 0.848 0.953
494 105 1 0.890 0.02775 0.837 0.946
526 103 1 0.882 0.02880 0.827 0.940
533 101 2 0.864 0.03076 0.806 0.927
544 98 1 0.855 0.03169 0.795 0.920
903 68 2 0.830 0.03540 0.764 0.902
1019 62 1 0.817 0.03727 0.747 0.893
1062 60 1 0.803 0.03906 0.730 0.883
1204 54 1 0.788 0.04107 0.712 0.873
1385 48 1 0.772 0.04337 0.691 0.862
Gene2_Quartile=2
time n.risk n.event survival std.err lower 95% CI upper 95% CI
113 133 1 0.992 0.00749 0.978 1.000
265 127 1 0.985 0.01076 0.964 1.000
711 82 1 0.973 0.01598 0.942 1.000
720 81 1 0.961 0.01979 0.923 1.000
781 76 1 0.948 0.02322 0.904 0.995
874 70 1 0.934 0.02654 0.884 0.988
966 62 1 0.919 0.03009 0.862 0.980
ggsurvplot(sfit_2, conf.int=FALSE, pval=TRUE, risk.table=TRUE, risk.table.col="strata",
legend.labs=c("Low Expression", "High Expression"), legend.title="Group",
palette=c("dodgerblue2", "red3"),
title="Kaplan-Meier Curve for FAM167B", risk.table.height=0.3)

gene_3 <- RNA_tot_2_merged[RNA_tot_2_merged$Gene3_Quartile %in% c(1, 4),]
gene_3$Gene3_Quartile <- sub(4, 2, gene_3$Gene3_Quartile)
sfit_3 <- survfit(Surv(PFI_time, PFI_Status)~Gene3_Quartile, data=gene_3)
summary(sfit_3)
Call: survfit(formula = Surv(PFI_time, PFI_Status) ~ Gene3_Quartile,
data = gene_3)
Gene3_Quartile=1
time n.risk n.event survival std.err lower 95% CI upper 95% CI
127 133 1 0.992 0.00749 0.978 1.000
225 128 2 0.977 0.01314 0.952 1.000
267 125 1 0.969 0.01518 0.940 0.999
329 122 1 0.961 0.01701 0.928 0.995
431 115 1 0.953 0.01881 0.917 0.990
533 107 1 0.944 0.02063 0.904 0.985
544 105 1 0.935 0.02231 0.892 0.980
711 93 1 0.925 0.02423 0.879 0.974
1062 66 1 0.911 0.02762 0.858 0.967
1215 53 1 0.894 0.03200 0.833 0.959
1385 39 1 0.871 0.03852 0.798 0.950
1785 28 1 0.840 0.04809 0.751 0.939
Gene3_Quartile=2
time n.risk n.event survival std.err lower 95% CI upper 95% CI
6 137 1 0.993 0.00727 0.979 1.000
113 134 1 0.985 0.01032 0.965 1.000
158 132 1 0.978 0.01266 0.953 1.000
174 131 3 0.955 0.01779 0.921 0.991
218 128 1 0.948 0.01915 0.911 0.986
267 126 1 0.940 0.02042 0.901 0.981
279 125 1 0.933 0.02160 0.892 0.976
411 114 1 0.925 0.02291 0.881 0.971
514 98 1 0.915 0.02454 0.868 0.965
577 87 1 0.905 0.02642 0.854 0.958
641 82 1 0.894 0.02831 0.840 0.951
781 71 1 0.881 0.03058 0.823 0.943
874 65 1 0.868 0.03298 0.805 0.935
903 62 2 0.840 0.03738 0.769 0.916
966 54 1 0.824 0.03979 0.750 0.906
1019 50 2 0.791 0.04451 0.709 0.883
1426 38 1 0.770 0.04796 0.682 0.870
1708 26 2 0.711 0.05983 0.603 0.839
ggsurvplot(sfit_3, conf.int=FALSE, pval=TRUE, risk.table=TRUE, risk.table.col="strata",
legend.labs=c("Low Expression", "High Expression"), legend.title="Group",
palette=c("dodgerblue2", "red3"),
title="Kaplan-Meier Curve for DNAH11", risk.table.height=0.3)

gene_4 <- RNA_tot_2_merged[RNA_tot_2_merged$Gene4_Quartile %in% c(1, 4),]
gene_4$Gene1_Quartile <- sub(4, 2, gene_4$Gene4_Quartile)
sfit_4 <- survfit(Surv(PFI_time, PFI_Status)~Gene4_Quartile, data=gene_4)
summary(sfit_4)
Call: survfit(formula = Surv(PFI_time, PFI_Status) ~ Gene4_Quartile,
data = gene_4)
Gene4_Quartile=1
time n.risk n.event survival std.err lower 95% CI upper 95% CI
6 138 1 0.993 0.00722 0.979 1.000
30 137 1 0.986 0.01017 0.966 1.000
110 132 1 0.978 0.01254 0.954 1.000
113 131 1 0.971 0.01450 0.943 0.999
127 130 1 0.963 0.01619 0.932 0.995
174 128 1 0.956 0.01773 0.921 0.991
204 126 1 0.948 0.01914 0.911 0.986
225 124 1 0.940 0.02046 0.901 0.981
265 120 1 0.933 0.02174 0.891 0.976
267 119 1 0.925 0.02292 0.881 0.971
279 117 1 0.917 0.02405 0.871 0.965
332 114 1 0.909 0.02515 0.861 0.959
363 109 1 0.900 0.02626 0.850 0.953
439 102 1 0.892 0.02745 0.839 0.947
514 95 1 0.882 0.02872 0.828 0.940
711 84 1 0.872 0.03024 0.814 0.933
874 71 1 0.859 0.03221 0.799 0.925
933 66 1 0.846 0.03425 0.782 0.916
1062 55 1 0.831 0.03692 0.762 0.907
1204 47 1 0.813 0.04015 0.738 0.896
1215 46 1 0.796 0.04299 0.716 0.885
1385 40 1 0.776 0.04629 0.690 0.872
1426 39 1 0.756 0.04919 0.665 0.859
1708 27 1 0.728 0.05476 0.628 0.844
1785 26 1 0.700 0.05938 0.593 0.826
Gene4_Quartile=4
time n.risk n.event survival std.err lower 95% CI upper 95% CI
127 131 1 0.992 0.0076 0.978 1.000
174 130 1 0.985 0.0107 0.964 1.000
279 125 1 0.977 0.0132 0.951 1.000
533 98 1 0.967 0.0164 0.935 1.000
641 84 1 0.955 0.0198 0.917 0.995
720 75 1 0.943 0.0233 0.898 0.989
966 60 2 0.911 0.0314 0.852 0.975
1019 55 1 0.895 0.0349 0.829 0.966
1708 27 1 0.862 0.0468 0.775 0.958
ggsurvplot(sfit_4, conf.int=FALSE, pval=TRUE, risk.table=TRUE, risk.table.col="strata",
legend.labs=c("Low Expression", "High Expression"), legend.title="Group",
palette=c("dodgerblue2", "red3"),
title="Kaplan-Meier Curve for BHMT2", risk.table.height=0.3)


LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyMgKkRhdGEgUmV0cmlldmFsKg0KDQpUaGlzIHByb2plY3QgaXMgZm9jdXNlZCBvbiBhbmFseXppbmcgdGhlIFRDR0EtVEhDQSBkYXRhIGZyb20gYSBtdWx0aW9taWNzIGFwcHJvYWNoLiBTcGVjaWZpY2FsbHksIHdlIHdpbGwgYmUgYW5hbHl6aW5nIG1STkEsIG1pUk5BLCBsbmNSTkEsIGFuZCBtZXRoeWxhdGlvbiBkYXRhIHRvIGRlc2NyaWJlIHRoZSB0cmVuZHMgYW5kIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgbXVsdGlvbWljIHByb2ZpbGVzIG9mIHBhdGllbnRzIGFuZCB0aGVpciBwcm9nbm9zdGljIGNoYXJhY3RlcmlzdGljcyAoZS5nLiBzdXJ2aXZhbCBhbmQvb3IgcmVjdXJyZW5jZSkuDQoNClRvIHN0YXJ0IG9mZiwgd2UgbmVlZCB0byBpbXBvcnQgdGhlIHJlbGV2YW50IGRhdGEgd2Ugd2lsbCBiZSB1c2luZy4gVGhpcyBkYXRhIGlzIHNvdXJjZWQgZnJvbSBUQ0dBIChUaGUgQ2FuY2VyIEdlbm9tZSBBdGxhcyksIGFsdGhvdWdoIHRoZSBtUk5BLCBtaVJOQSwgbWV0aHlsYXRpb24sIGFuZCBjbGluaWNhbCBkYXRhIGNhbWUgZnJvbSBGaXJlaG9zZSAoZnJvbSB0aGUgQnJvYWQgSW5zdGl0dXRlKSwgYW5kIHRoZSBsbmNSTkEgZGF0YSBjYW1lIGZyb20gVEFOUklDLg0KDQpMZXQncyBmaXJzdCBpbXBvcnQgdGhlIGRhdGFzZXRzIHdlIHdpbGwgYmUgd29ya2luZyB3aXRoLCBhbmQgYXNzaWduIHRoZW0gdG8gdmFyaWFibGVzLg0KYGBge3J9DQojSW5wdXR0aW5nIHRoZSBkYXRhIGludG8gdmFyaWFibGVzIHRoYXQgd2UgY2FuIG1hbmlwdWxhdGUNCmxpYnJhcnkocmVhZHhsKQ0KDQojSW5wdXR0aW5nIHRoZSBkYXRhIGludG8gdmFyaWFibGVzIHRoYXQgd2UgY2FuIG1hbmlwdWxhdGUNCmNsaW5pY2FsIDwtIHJlYWRfZXhjZWwoIlRIQ0FfQ2xpbmljYWxfRGF0YS54bHN4IikNCmNsaW5pY2FsXzIgPC0gcmVhZF9leGNlbCgiQ2xpbmljYWxfUG9zc2libGUueGxzeCIpDQpsbmNSTkEgPC0gcmVhZF9leGNlbCgiVEhDQV9sbmNSTkFfRGF0YS54bHN4IikNCiNtZXRoeWxhdGlvbiA8LSByZWFkX2V4Y2VsKCJUSENBX01ldGh5bGF0aW9uX0RhdGEueGxzeCIpDQptaVJOQSA8LSByZWFkX2V4Y2VsKCJUSENBX21pUk5BX0RhdGFfVGVzdC54bHN4IikNCm1STkEgPC0gcmVhZF9leGNlbCgiVEhDQV9tUk5BX0RhdGFfRmluYWwueGxzeCIpDQoNCmBgYA0KDQpMZXQncyBsb29rIGF0IHRoZSBoZWFkIG9mIHRoZXNlIHRhYmxlcyB0byB1bmRlcnN0YW5kIHRoZWlyIHN0cnVjdHVyZS4NCg0KYGBge3J9DQojQWNjZXNzaW5nIHRoZSBmaXJzdCBmZXcgcm93cyBvZiBlYWNoIGRhdGFzZXQNCmhlYWQoY2xpbmljYWwpDQpoZWFkKGxuY1JOQSkNCiNoZWFkKG1ldGh5bGF0aW9uKQ0KaGVhZChtaVJOQSkNCmhlYWQobVJOQSkNCmBgYA0KIyMgKkRhdGEgUHJlcHJvY2Vzc2luZyoNCg0KQWZ0ZXIgbG9va2luZyBhdCB0aGUgdGFibGUgaGVhZHMsIHRoZXJlIGFyZSBhIGNvdXBsZSBvZiBpc3N1ZXMgdGhhdCB3ZSBjYW4gc2VlOg0KDQogICAgMSkgVGhlIHNhbXBsZSBsYWJlbHMgYXJlbid0IGlkZW50aWNhbCAtIHNvbWUgaGF2ZSBleHRyYSBlbGVtZW50cyBhdCB0aGUgYmVnaW5uaW5nIG9yIGVuZCwgd2hpY2ggICAgICAgICBuZWVkIHRvIGJlIHN0YW5kYXJkaXplZA0KICAgIA0KICAgIDIpIFRoZSBudW1iZXIgb2Ygc2FtcGxlcyBpbiBlYWNoIGZpbGUgYXJlbid0IHRoZSBzYW1lIC0gZm9yIGV4YW1wbGUsIG1pUk5BIG9ubHkgaGFzIDU0MSBzYW1wbGVzLCAgICAgICAgYW5kIGxuY1JOQSBoYXMgNTU2LiBUaGlzIGFsc28gbmVlZHMgdG8gYmUgc3RhbmRhcmRpemVkIHRvIG1ha2Ugc3VyZSBvbmx5IHNhbXBsZXMgd2l0aCBhbGwgICAgICAgICAgIGRhdGEgYXJlIHVzZWQuDQoNCkxldCdzIHN0YXJ0IHdpdGggc3RlcCAxLg0KDQpUaGUgZ2VuZXJhbCBmb3JtYXQgb2YgdGhlIGRhdGEgc2hvdWxkIGxvb2sgc29tZXRoaW5nIGxpa2UgdGhpczogJ1RDR0EtWFgtWFhYWC1YWCcsIHNvIGxldCdzIGxvb2sgYXQgZWFjaCBmaWxlIHRvIHNlZSBob3cgd2UgY2FuIGZpeCBpdC4NCg0KbG5jUk5BIHNlZW1zIHRvIGhhdmUgZXh0cmEgbGFiZWxzIGF0IHRoZSBzdGFydCB3aGljaCB3ZSBjYW4gcmVtb3ZlLCBhcyB3ZWxsIGFzIHVuZGVyc2NvcmVzIHdoaWNoIHdlIGNhbiBjb252ZXJ0IHRvIGh5cGhlbnMuIEhvd2V2ZXIsIHdoYXQncyBhbHNvIGltcG9ydGFudCBoZXJlIGlzIHRoYXQgd2UgaGF2ZSBub3JtYWwgYW5kIHR1bW9yIHNhbXBsZXMgZXhwbGljdGx5IGxhYmVsZWQsIHdoZXJlYXMgb3RoZXIgZmlsZXMgdXNlIHRoZSAnMDEnIG1hcmtpbmcgZm9yIHR1bW9ycyBhbmQgJzExJyBtYXJraW5nIGZvciBub3JtYWwgc2FtcGxlcy4gV2UgbmVlZCB0byBhZGFwdCBvdXIgbG5jUk5BIGRhdGEgdG8gZm9sbG93IHRoaXMgc3RydWN0dXJlLg0KYGBge3J9DQojV2UgYXJlIGdvaW5nIHRocm91Z2ggZWFjaCBjb2x1bW4gaW4gdGhlIGxuY1JOQSBkYXRhc2V0DQpmb3IgKGkgaW4gMTpuY29sKGxuY1JOQSkpIHsNCiAgI0lmIHRoZSBjb2x1bW4gbmFtZSAtIHdoaWNoIGlzIHRoZSBzYW1wbGUgSUQgLSBjb250YWlucyBOb3JtYWwsIHdlJ2xsIGFkZCBhIC0xMSBhbmQgZm9ybWF0IHRoZSBuYW1lIHRvIHJlbW92ZSB0aGUgYmVnaW5uaW5nIGFuZCBjb252ZXJ0IGFsbCB1bmRlcnNjb3JlcyB0byBoeXBoZW5zLg0KICANCiAgaWYgKGdyZXBsKCJOb3JtYWwiLCBjb2xuYW1lcyhsbmNSTkEpW2ldLCBmaXhlZCA9IFRSVUUpID09IFRSVUUpIHsNCiAgICBjb2xuYW1lcyhsbmNSTkEpW2ldIDwtIHN1YigiLiotVEMiLCAiVEMiLCBjb2xuYW1lcyhsbmNSTkEpW2ldKQ0KICAgIGNvbG5hbWVzKGxuY1JOQSlbaV0gPC0gZ3N1YigiXyIsICItIiwgY29sbmFtZXMobG5jUk5BKVtpXSkNCiAgICBjb2xuYW1lcyhsbmNSTkEpW2ldIDwtIHBhc3RlKGNvbG5hbWVzKGxuY1JOQSlbaV0sICctMTEnLCBzZXA9IiIpDQogIH0gZWxzZSB7DQogICAgI090aGVyd2lzZSwgd2UnbGwgc3RpbGwgZm9ybWF0IHRoZSBuYW1lLCBidXQgd2UnbGwgYWRkIGEgLTAxIGF0IHRoZSBlbmQgaW5zdGVhZC4NCiAgICBjb2xuYW1lcyhsbmNSTkEpW2ldIDwtIHN1YigiLiotVEMiLCAiVEMiLCBjb2xuYW1lcyhsbmNSTkEpW2ldKQ0KICAgIGNvbG5hbWVzKGxuY1JOQSlbaV0gPC0gZ3N1YigiXyIsICItIiwgY29sbmFtZXMobG5jUk5BKVtpXSkNCiAgICBjb2xuYW1lcyhsbmNSTkEpW2ldIDwtIHBhc3RlKGNvbG5hbWVzKGxuY1JOQSlbaV0sICctMDEnLCBzZXA9IiIpDQogIH0NCiAgICANCn0NCg0KI1dlJ2xsIGNvbnZlcnQgdGhlIGZpcnN0IGNvbHVtbiB0byB0aGUgc3RhbmRhcmQgbmFtZSBHZW5lX0lEIGFuZCByZW1vdmUgdGhlIGV4dHJhIG1hcmtlciBpbiB0aGUgRW5zZW1ibGUgSUQgYWZ0ZXIgdGhlIGRlY2ltYWwgcG9pbnQuDQpjb2xuYW1lcyhsbmNSTkEpWzFdIDwtICJHZW5lX0lEIg0KbG5jUk5BJEdlbmVfSUQgPC0gc3ViKCJcXC4uKiIsICIiLCBsbmNSTkEkR2VuZV9JRCkNCmhlYWQobG5jUk5BKQ0KYGBgDQoNClRoYXQgbG9va3MgbW9yZSBpbiBsaW5lIHdpdGggdGhlIHN0YW5kYXJkIHNhbXBsZSBub3RhdGlvbi4NCg0KQm90aCB0aGUgbWV0aHlsYXRpb24gYW5kIHRoZSBtUk5BIGZpbGUgaGF2ZSB1bmRlcnNjb3JlcyB0aGF0IHdlIGNhbiBjb252ZXJ0IHRvIGh5cGhlbnMuDQoNCmBgYHtyfQ0KI1dlJ2xsIGl0ZXJhdGUgb3ZlciBlYWNoIGNvbHVtbiBhbmQgY29udmVydCB0aGUgdW5kZXJzY29yZXMgdG8gZGFzaGVzLCBmb3IgYm90aCBkYXRhc2V0cy4gVGhlbiwgd2UnbGwgY29udmVydCB0aGUgZmlyc3QgY29sdW1uIHRvIHRoZSBHZW5lX0lEIGxhYmVsLg0KZm9yIChpIGluIDE6bmNvbChtUk5BKSkgew0KICBjb2xuYW1lcyhtUk5BKVtpXSA8LSBnc3ViKCJfIiwgIi0iLCBjb2xuYW1lcyhtUk5BKVtpXSkNCn0NCmNvbG5hbWVzKG1STkEpWzFdIDwtICJHZW5lX0lEIg0KbVJOQSA8LSBtUk5BWzMwOjIwNTMxLF0NCmhlYWQobVJOQSkNCg0KI2ZvciAoaSBpbiAxOm5jb2wobWV0aHlsYXRpb24pKSB7DQojICBjb2xuYW1lcyhtZXRoeWxhdGlvbilbaV0gPC0gZ3N1YigiXyIsICItIiwgY29sbmFtZXMobWV0aHlsYXRpb24pW2ldKQ0KI30NCiNjb2xuYW1lcyhtZXRoeWxhdGlvbilbMV0gPC0gIkdlbmVfSUQiDQojaGVhZChtZXRoeWxhdGlvbikNCmBgYA0KVGhhdCBzZWVtcyB0byBiZSBmaXhlZCBhcyB3ZWxsLg0KDQpGb3IgbWlSTkEgZGF0YSwgdGhlcmUgaXMgYSBsb3Qgb2YgZXh0cmFuZW91cyBkYXRhIGF0IHRoZSBlbmQgYWJvdXQgc2FtcGxlIGFuZCB2aWFscywgd2hpY2ggd2UgZG9uJ3QgbmVlZCwgc28gbGV0J3MgcmVtb3ZlIHRoYXQuDQoNCmBgYHtyfQ0KI1dlJ2xsIGl0ZXJhdGUgb3ZlciB0aGUgY29sdW1uIG5hbWVzIGFuZCByZW1vdmUgYW55IGV4dHJhbmVvdXMgaW5mb3JtYXRpb24gYWZ0ZXIgb3VyIG5vcm1hbCBvciB0dW1vciBzYW1wbGUgbGFiZWxzLCBhbmQgdGhlbiBjcmVhdGUgdGhlIEdlbmVfSUQgY29sdW1uLg0KDQpmb3IgKGkgaW4gMTpuY29sKG1pUk5BKSkgew0KICBjb2xuYW1lcyhtaVJOQSlbaV0gPC0gc3ViKCJfMDEuKiIsICJfMDEiLCBjb2xuYW1lcyhtaVJOQSlbaV0pDQogIGNvbG5hbWVzKG1pUk5BKVtpXSA8LSBzdWIoIl8xMS4qIiwgIl8xMSIsIGNvbG5hbWVzKG1pUk5BKVtpXSkNCiAgY29sbmFtZXMobWlSTkEpW2ldIDwtIGdzdWIoIl8iLCAiLSIsIGNvbG5hbWVzKG1pUk5BKVtpXSkNCn0NCmNvbG5hbWVzKG1pUk5BKVsxXSA8LSAiR2VuZV9JRCINCm1pUk5BJCdtaVJOQS1JRCcgPC0gTlVMTA0KbWlSTkEgPC0gbWlSTkFbIWdyZXBsKCdwcmVjdXJzb3InLCBtaVJOQSRgbWlSTkEtcmVnaW9uYCksXQ0KbWlSTkEgPC0gbWlSTkFbIWdyZXBsKCdzdGVtbG9vcCcsIG1pUk5BJGBtaVJOQS1yZWdpb25gKSxdDQptaVJOQSQnbWlSTkEtcmVnaW9uJyA8LSBOVUxMDQpoZWFkKG1pUk5BKQ0KYGBgDQpEb25lIQ0KDQpGb3IgY2xpbmljYWwgZGF0YSwgd2UgaGF2ZSBvdXIgJ1NhbXBsZSBJRCcgY29sdW1uIHdpdGggYXBwcm9wcmlhdGUgbm90YXRpb24sIHNvIHdlIGRvbid0IG5lZWQgdG8gY2hhbmdlIHRoYXQuDQoNCk5vdywgZm9yIHN0ZXAgMiwgd2UgaGF2ZSB0byBpZGVudGlmeSB3aGljaCBzYW1wbGVzIGFyZSBtaXNzaW5nIGZyb20gYW55IG9mIHRoZSBmaWxlcywgYXMgd2Ugb25seSB3YW50IGRhdGEgcG9pbnRzIHByZXNlbnQgaW4gZWFjaCBmaWxlLiBUbyBhY2NvbXBsaXNoIHRoaXMsIEkgYW0gZmlyc3QgZ29pbmcgdG8gYWNjZXNzIGFsbCB0aGUgc2FtcGxlIElEcyBmcm9tIGVhY2ggZmlsZS4gSSdtIHRoZW4gZ29pbmcgdG8gYWRkIHRoZW0gdG9nZXRoZXIgdG8gZm9ybSBhIHZlY3RvciwgYW5kIHVzZSB0aGUgdGFibGUgZnVuY3Rpb24gdG8gc2VlIGhvdyBtYW55IHRpbWVzIGVhY2ggdmFsdWUgYXBwZWFycyBpbiB0aGUgdmVjdG9yLiBHaXZlbiB0aGF0IHdlIGhhdmUgNSBmaWxlcyBvZiBkYXRhLCBhIHNhbXBsZSBwcmVzZW50IGluIGFsbCBmaWxlcyBzaG91bGQgYXBwZWFyIGF0IGxlYXN0IDUgdGltZXMuIFRodXMsIHdlIHdpbGwgaXNvbGF0ZSBhbnkgdmFsdWVzIHRoYXQgYXBwZWFyIGxlc3MgdGhhbiA1IHRpbWVzLg0KDQpgYGB7cn0NCiNIZXJlIHdlIGFjY2VzcyB0aGUgc3BlY2lmaWMgc2FtcGxlIG5hbWVzIHRocm91Z2ggaW5kZXhpbmcgb2YgdGhlIGRhdGEgKHdoaWNoIHN0YXJ0cyBmcm9tIGNvbHVtbiAyKS4NCmNsaW5fc2FtcGxlcyA8LSBjbGluaWNhbCRgU2FtcGxlIElEYA0KbG5jX3NhbXBsZXMgPC0gY29sbmFtZXMobG5jUk5BKVsyOjU1N10NCiNtZXRoX3NhbXBsZXMgPC0gY29sbmFtZXMobWV0aHlsYXRpb24pWzU6NTcxXQ0KbWlSX3NhbXBsZXMgPC0gY29sbmFtZXMobWlSTkEpWzI6MTYwOV0NCm1STkFfc2FtcGxlcyA8LSBjb2xuYW1lcyhtUk5BKVsyOjU2OV0NCg0KI1dlIGNvbmNhdGVuYXRlIGFsbCB0aGUgc2FtcGxlIGRhdGEgaW50byBhIHZlY3Rvci4NCnRlbXAgPC0gYyhsbmNfc2FtcGxlcywgbWlSX3NhbXBsZXMsIG1STkFfc2FtcGxlcykNCiNOZXh0LCB3ZSBjb3VudCB0aGUgb2NjdXJyZW5jZSBvZiBlYWNoIHVuaXF1ZSBzYW1wbGUgSUQgaW4gb3VyIHZlY3RvciB1c2luZyB0aGUgdGFibGUgZnVuY3Rpb24gLSBpZiBhIHNhbXBsZSBpcyBwcmVzZW50IGluIGFsbCA0IGRhdGFzZXRzLCBpdCdsbCBoYXZlIGEgY291bnQgb2YgMy4NCnRlbXBfdGFibGUgPSB0YWJsZSh0ZW1wKQ0KI05vdywgd2UganVzdCB3YW50IHRvIGtlZXAgdGhlIHNhbXBsZXMgdGhhdCBoYXZlIGFuIG9jY3VycmVuY2Ugb2YgNC4NCmtlZXAxIDwtIG5hbWVzKHRlbXBfdGFibGVbdGVtcF90YWJsZSA+PSAzXSkNCmtlZXAxIDwtIGMoIkdlbmVfSUQiLCBrZWVwMSkNCg0KYGBgDQoNCk5vdywgd2Ugd2lsbCByZW1vdmUgdGhlaXIgY29sdW1ucy9yb3dzIGZyb20gZWFjaCBkYXRhIGZpbGUgaW4gYSBzZXF1ZW50aWFsIG1hbm5lci4NCg0KYGBge3J9DQojTmV4dCwgd2UganVzdCBzdWJzZXQgdGhlIGRhdGFzZXRzIHRvIG9ubHkga2VlcCBjb2x1bW5zIHRoYXQgbWF0Y2ggYSB2YWx1ZSBpbiBvdXIgdmVjdG9yIG9mIGFjY2VwdGVkIHNhbXBsZXMgLSB1c2luZyB0aGUgc3Vic2V0IGFuZCBzZWxlY3QgZnVuY3Rpb25zLg0KbWlSTkFfbmV3IDwtIHN1YnNldChtaVJOQSwgc2VsZWN0PWMoa2VlcDEpKQ0KbVJOQV9uZXcgPC0gc3Vic2V0KG1STkEsIHNlbGVjdD1jKGtlZXAxKSkNCiNtZXRoeWxhdGlvbl9uZXcgPC0gc3Vic2V0KG1ldGh5bGF0aW9uLCBzZWxlY3Q9YyhrZWVwMSkpDQpsbmNSTkFfbmV3IDwtIHN1YnNldChsbmNSTkEsIHNlbGVjdD1jKGtlZXAxKSkNCmBgYA0KDQpPbmUgYWRkaXRpb25hbCBzdGVwIHdlIG5lZWQgdG8gdGFrZSBpcyB0byBtYWtlIHN1cmUgdGhhdCBhbGwgb3VyIHR1bW9yIHNhbXBsZXMgaGF2ZSBjbGluaWNhbCBkYXRhIGF2YWlsYWJsZS4gVGh1cywgSSdtIGdvaW5nIHRvIGNvbXBhcmUgb3VyIHR1bW9yIHNhbXBsZXMgKHdpdGggdGhlIC0wMSBlbmRpbmcpIHRvIG91ciBjbGluaWNhbCBzYW1wbGUgSURzIHRvIGZpbmQgYW5kIGFsc28gcmVtb3ZlIGFueSBzYW1wbGVzIHRoYXQgZG9uJ3Qgb3ZlcmxhcCwgdXNpbmcgYSBzaW1pbGFyIG1ldGhvZC4NCg0KYGBge3J9DQojTm93LCBzaW5jZSBjbGluaWNhbCBkYXRhIG9ubHkgY29udGFpbnMgdHVtb3Igc2FtcGxlcywgd2UgbmVlZCB0byBzZXBhcmF0ZSBvdXQgb3VyIHR1bW9yIHNhbXBsZXMgYnkgc2VhcmNoaW5nIGZvciBhbGwgc2FtcGxlcyB3aXRoIHRoZSAtMDEgdGFnLg0KdHVtb3Jfc2FtcGxlcyA8LSBncmVwKCItMDEiLCBrZWVwMSwgdmFsdWU9VFJVRSkNCm5vcm1hbF9zYW1wbGVzIDwtIGdyZXAoIi0xMSIsIGtlZXAxLCB2YWx1ZT1UUlVFKQ0Kbm9ybWFsX3NhbXBsZXMNCg0KI1NhbWUgYXMgYWJvdmUgLSB2ZWN0b3IsIGNvdW50LCBrZWVwIGFueXRoaW5nIG9jY3VycmluZyB0d2ljZSBzaW5jZSB3ZSBhcmUgY29tcGFyaW5nIDIgZGF0YXNldHMuDQp0ZW1wMiA8LSBjKHR1bW9yX3NhbXBsZXMsIGNsaW5fc2FtcGxlcykNCnRlbXBfdGFibGVfMiA9IHRhYmxlKHRlbXAyKQ0Ka2VlcDIgPC0gbmFtZXModGVtcF90YWJsZV8yW3RlbXBfdGFibGVfMiA+PSAyXSkNCmtlZXAyIDwtIGMoa2VlcDIpDQoNCiNXZSB0aGVuIGRlbGV0ZSBhbnkgcm93cyB0aGF0IGRvbid0IGNvcnJlc3BvbmQgdG8gYSBzYW1wbGUgaW4gb3VyIGxpc3QsIGJ5IHVzaW5nIHRoZSBpbiBmdW5jdGlvbiB0byBvbmx5IGtlZXAgcm93cyB3aXRoIHZhbHVlcyBpbiBvdXIgdmVjdG9yLg0KDQpjbGluX25ldyA8LSBjbGluaWNhbFtjbGluaWNhbCRgU2FtcGxlIElEYCAlaW4lIGtlZXAyLF0NCmNsaW5fbmV3IDwtIGRhdGEuZnJhbWUoY2xpbl9uZXcpDQoNCmNsaW5fMiA8LSBjbGluaWNhbF8yW2NsaW5pY2FsXzIkc2FtcGxlICVpbiUga2VlcDEsXQ0KY2xpbl8yIDwtIGRhdGEuZnJhbWUoY2xpbl8yKQ0KDQpjbGluX25ldyQnTWV0YXN0YXNpc19Hcm91cCcgPC0gd2l0aChjbGluX25ldywgaWZlbHNlKGNsaW5fbmV3JEFtZXJpY2FuLkpvaW50LkNvbW1pdHRlZS5vbi5DYW5jZXIuTWV0YXN0YXNpcy5TdGFnZS5Db2RlID09ICJNMSIsIDEsIDIpKQ0KDQpjbGluX25ldyQnUmVjdXJyZW5jZV9Hcm91cCcgPC0gd2l0aChjbGluX25ldywgaWZlbHNlKGNsaW5fbmV3JERpc2Vhc2UuRnJlZS5TdGF0dXMgPT0gIjE6UmVjdXJyZWQvUHJvZ3Jlc3NlZCIsIDEsIDIpKQ0KDQpjbGluX25ldw0KYGBgDQoNCk5vdywgYWxsIG91ciBkYXRhIGZvcm1hdHRpbmcgaXMgZG9uZSAtIGVhY2ggb2Ygb3VyIGRhdGFzZXRzIGlzIGNvbXBvc2VkIG9mIDU0MiBzYW1wbGVzLCB3aXRoIDQ5MiB0dW1vciBzYW1wbGVzIChhcyB0aGUgY2xpbmljYWwgZGF0YSBzdWdnZXN0cykgYW5kIDUwIG5vcm1hbCBzYW1wbGVzLiBCZWZvcmUgd2UgbW92ZSBpbnRvIG91ciBhY3R1YWwgYW5hbHlzaXMsIHdlIG5lZWQgdG8gbWFrZSBzdXJlIGFsbCBvdXIgc2FtcGxlcyBoYXZlIGRhdGEgcG9pbnRzIGZvciB0aGUgUk5BcyBiZWluZyBhbmFseXplZC4gU2luY2UgYSBsb3Qgb2YgdGhlIGZpbGVzIGhhdmUgJ05BJyB2YWx1ZXMgaW4gdGhlbSwgd2UgY2FuJ3Qgd29yayB3aXRoIHRoaXMsIHNvIHdlJ2xsIGp1c3QgZWxpbWluYXRlIGFsbCByb3dzIGNvbnRhaW5pbmcgYW4gTkEuDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGVkZ2VSKQ0KI0ZvciBlYWNoIGRhdGFzZXQsIHdlIGFyZSBnb2luZyB0byByZW1vdmUgYW55IHJvd3Mgd2l0aCBOQSBpbiB0aGVtLCBhbmQgdGhlbiBjb252ZXJ0IGl0IHRvIGEgZGF0YSBmcmFtZSB0byB3b3JrIHdpdGggb3VyIERFU2VxMiBmdW5jdGlvbnMuDQptaVJOQV9uZXdbbWlSTkFfbmV3ID09ICJOQSJdIDwtIE5BDQptaVJOQV9maW5hbCA8LSBtaVJOQV9uZXdbY29tcGxldGUuY2FzZXMobWlSTkFfbmV3KSwgXQ0KbWlSTkFfZmluYWwgPC0gbmEub21pdChtaVJOQV9maW5hbCkNCm1pUk5BX2ZpbmFsID0gZGF0YS5mcmFtZShtaVJOQV9maW5hbCkNCg0KbVJOQV9uZXdbbVJOQV9uZXcgPT0gIk5BIl0gPC0gTkENCm1STkFfZmluYWwgPC0gbVJOQV9uZXdbY29tcGxldGUuY2FzZXMobVJOQV9uZXcpLCBdDQptUk5BX2ZpbmFsID0gZGF0YS5mcmFtZShtUk5BX2ZpbmFsKQ0KDQpsbmNSTkFfbmV3W2xuY1JOQV9uZXcgPT0gIk5BIl0gPC0gTkENCmxuY1JOQV9maW5hbCA8LSBsbmNSTkFfbmV3W2NvbXBsZXRlLmNhc2VzKGxuY1JOQV9uZXcpLCBdDQpsbmNSTkFfZmluYWwgPSBkYXRhLmZyYW1lKGxuY1JOQV9maW5hbCkNCg0KI21ldGh5bGF0aW9uX25ld1ttZXRoeWxhdGlvbl9uZXcgPT0gIk5BIl0gPC0gTkEgDQojbWV0aHlsYXRpb25fZmluYWwgPC0gbWV0aHlsYXRpb25fbmV3W2NvbXBsZXRlLmNhc2VzKG1ldGh5bGF0aW9uX25ldyksIF0NCiNtZXRoeWxhdGlvbl9maW5hbCA9IGRhdGEuZnJhbWUobWV0aHlsYXRpb25fZmluYWwpDQoNCmBgYA0KDQojIyAqRGlmZmVyZW50aWFsIEdlbmUgRXhwcmVzc2lvbioNCg0KDQpXZSBmaW5hbGx5IGhhdmUgb3VyIGZpbmFsIGRhdGFzZXRzIHRoYXQgd2UgY2FuIHdvcmsgd2l0aC4gTGV0J3MgYmVnaW4gd2l0aCBhbmFseXNpcy4gDQoNCldlIGZpcnN0IHNob3VsZCBjcmVhdGUgYSBwcm9wZXIgbWV0YWRhdGEgdmFyaWFibGUgdG8gYmVnaW4gYW5hbHlzaXMsIGJ5IGNvbnNpZGVyaW5nIHR1bW9yIGFuZCBub3JtYWwgc2FtcGxlcy4gSG93ZXZlciwgdGhlcmUgYXJlIGRpZmZlcmVudCBsZXZlbHMgb2YgYW5hbHlzaXMgd2UgY2FuIGNvbmR1Y3QsIHdoaWNoIG1lYW5zIHdlJ2xsIGNyZWF0ZSBhIGNvdXBsZSBvZiBtZXRhZGF0YSBmaWxlcyBiYXNlZCBvbiBjbGluaWNhbCBkYXRhLg0KDQpGaXJzdCwgbGV0J3MgY3JlYXRlIGEgZmlsZSB3aXRoIGEgc2ltcGxlIGRpc3RyaWJ1dGlvbiBvZiBncm91cCAwIGZvciBub3JtYWwgdGlzc3VlIGFuZCBncm91cCAxIGZvciB0dW1vciB0aXNzdWUuDQoNCmBgYHtyfQ0KbGlicmFyeShERVNlcTIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiNBY2Nlc3Mgc2FtcGxlIElEcyB0byBmb3JtIGNvbHVtbiAxLCB0aGVuIGNoZWNrIGZvciB0aGUgLjAxIHRhZyB0byBhc3NpZ24gZ3JvdXBzIGFzIDEgb3IgMCBmb3IgdHVtb3Igb3Igbm9ybWFsLg0KbWV0YWRhdGEgPC0gZGF0YS5mcmFtZSgiU2FtcGxlX0lEIj1jKGNvbG5hbWVzKGxuY1JOQV9maW5hbClbMjo1NTJdKSkNCm1ldGFkYXRhJCdHcm91cCcgPC0gaWZlbHNlKGdyZXBsKCIuMDEiLCBtZXRhZGF0YSRTYW1wbGVfSUQsIGZpeGVkID0gVFJVRSkgPT0gVFJVRSwgMSwgMCkNCm1ldGFkYXRhJEdyb3VwIDwtIGFzLmZhY3RvcihtZXRhZGF0YSRHcm91cCkNCg0KZm9yIChpIGluIDE6NTUxKSB7DQogIHNhbXBsZSA8LSBtZXRhZGF0YVtpLCAxXQ0KICBzYW1wbGUyIDwtIGdzdWIoIlxcLiIsICItIiwgc2FtcGxlKQ0KICByb3cxIDwtIGNsaW5fMlt3aGljaChjbGluXzIkc2FtcGxlID09IHNhbXBsZTIpLCBdDQogIG1ldGFkYXRhW2ksIGMoIk9TX3RpbWUiKV0gPC0gYXMubnVtZXJpYyhyb3cxJCdPUy50aW1lJykNCiAgbWV0YWRhdGFbaSwgYygiT1NfU3RhdHVzIildIDwtIGFzLm51bWVyaWMocm93MSQnT1MnKQ0KICBtZXRhZGF0YVtpLCBjKCJQRklfdGltZSIpXSA8LSBhcy5udW1lcmljKHJvdzEkJ1BGSS50aW1lJykNCiAgbWV0YWRhdGFbaSwgYygiUEZJX1N0YXR1cyIpXSA8LSBhcy5udW1lcmljKHJvdzEkJ1BGSScpDQogIG1ldGFkYXRhW2ksIGMoIkRTU190aW1lIildIDwtIGFzLm51bWVyaWMocm93MSQnRFNTLnRpbWUnKQ0KICBtZXRhZGF0YVtpLCBjKCJEU1NfU3RhdHVzIildIDwtIGFzLm51bWVyaWMocm93MSQnRFNTJykNCiAgI2lmIChncmVwbCgiLjExIiwgc2FtcGxlLCBmaXhlZD1UUlVFKSA9PSBUUlVFKSB7DQogICMgIG1ldGFkYXRhW2ksIGMoImRheXNfdG9fZGVhdGgiKV0gPC0gcnVuaWYoMSwgMTAwMCwgNDAwMCkNCiAgIyAgbWV0YWRhdGFbaSwgYygiU3RhdHVzIildIDwtIDANCiAgI30gZWxzZXsNCiAgIyAgbWV0YWRhdGFbaSwgYygiZGF5c190b19kZWF0aCIpXSA8LSBhcy5udW1lcmljKGdyb3VwMSkgKiAzMA0KICAjICBtZXRhZGF0YVtpLCBjKCJTdGF0dXMiKV0gPC0gYXMubnVtZXJpYyhyb3cxJFN1cnZpdmFsX0dyb3VwKQ0KICAjfQ0KfQ0KDQpgYGANCg0KTmV4dCwgbGV0J3MgY3JlYXRlIGEgbWV0YWRhdGEgZmlsZSB0aGF0IGFkZHMgaW4gcmVjdXJyZW50IHNhbXBsZXMgYXMgYmVpbmcgZ3JvdXAgMiwgYW5kIHByaW1hcnkgc2FtcGxlcyBhcyBiZWluZyBncm91cCAxLg0KDQpgYGB7cn0NCiNBY2Nlc3Mgc2FtcGxlIElEcyB0byBmb3JtIGNvbHVtbiAxLCB0aGVuIGlmIHRoZSB0dW1vciBpcyBub3JtYWwsIGFzc2lnbiBncm91cCAwLiBJZiB0aGUgdHVtb3IgaXMgbm90IG5vcm1hbCwgcmVmZXJlbmNlIGNsaW5pY2FsIGRhdGEgZm9yIGRpc2Vhc2UgZnJlZSBzdGF0dXMsIGFuZCBhc3NpZ24gZ3JvdXAgMiB0byByZWN1cnJlZCBzYW1wbGVzLg0KbWV0YWRhdGFfcmVjdXIgPC0gZGF0YS5mcmFtZSgiU2FtcGxlX0lEIj1jKGNvbG5hbWVzKGxuY1JOQV9maW5hbClbMjo1NTJdKSkNCmZvciAoaSBpbiAxOjU1MSkgew0KICBzYW1wbGUgPC0gbWV0YWRhdGFfcmVjdXJbaSwgMV0NCiAgc2FtcGxlMiA8LSBnc3ViKCJcXC4iLCAiLSIsIHNhbXBsZSkNCiAgcm93MSA8LSBjbGluX25ld1t3aGljaChjbGluX25ldyRTYW1wbGUuSUQgPT0gc2FtcGxlMiksIF0NCiAgZ3JvdXAxIDwtIHJvdzEkUmVjdXJyZW5jZV9Hcm91cA0KICBncm91cDIgPC0gcm93MSRPdmVyYWxsLlN1cnZpdmFsLi5Nb250aHMuDQogIGlmIChncmVwbCgiLjExIiwgc2FtcGxlLCBmaXhlZD1UUlVFKSA9PSBUUlVFKSB7DQogICAgbWV0YWRhdGFfcmVjdXJbaSwgYygiR3JvdXAiKV0gPC0gMA0KICAgIG1ldGFkYXRhX3JlY3VyW2ksIGMoImRheXNfdG9fZGVhdGgiKV0gPC0gcnVuaWYoMSwgMTAwMCwgNDAwMCkNCiAgICBtZXRhZGF0YV9yZWN1cltpLCBjKCJTdGF0dXMiKV0gPC0gMA0KICB9IGVsc2Ugew0KICAgIG1ldGFkYXRhX3JlY3VyW2ksIGMoImRheXNfdG9fZGVhdGgiKV0gPC0gYXMubnVtZXJpYyhncm91cDIpICogMzANCiAgICBtZXRhZGF0YV9yZWN1cltpLCBjKCJTdGF0dXMiKV0gPC0gYXMubnVtZXJpYyhyb3cxJFN1cnZpdmFsX0dyb3VwKQ0KICAgIGlmIChncm91cDEgPT0gMSkgew0KICAgICAgbWV0YWRhdGFfcmVjdXJbaSwgYygiR3JvdXAiKV0gPC0gMQ0KICAgIH0gZWxzZXsNCiAgICAgIG1ldGFkYXRhX3JlY3VyW2ksIGMoIkdyb3VwIildIDwtIDINCiAgICB9DQogIH0NCn0NCg0KbWV0YWRhdGFfcmVjdXIkR3JvdXAgPC0gYXMuZmFjdG9yKG1ldGFkYXRhX3JlY3VyJEdyb3VwKQ0KYGBgDQoNCldlIGNhbiBhbHNvIGNyZWF0ZSBhIG1ldGFkYXRhIGZpbGUgdG8gZXZhbHVhdGUgbWV0YXN0YXRpYyB2cy4gbm9uLW1ldGFzdGF0aWMgc2FtcGxlcywgd2hpY2ggY2FuIGZvcm0gZ3JvdXAgMSBhbmQgMiByZXNwZWN0aXZlbHkuDQoNCmBgYHtyfQ0KI0FjY2VzcyBzYW1wbGUgSURzIHRvIGZvcm0gY29sdW1uIDEsIHRoZW4gaWYgdGhlIHR1bW9yIGlzIG5vcm1hbCwgYXNzaWduIGdyb3VwIDAuIElmIHRoZSB0dW1vciBpcyBub3Qgbm9ybWFsLCByZWZlcmVuY2UgY2xpbmljYWwgZGF0YSBmb3IgbWV0YXN0YXRpYyBzdGF0dXMsIGFuZCBhc3NpZ24gZ3JvdXAgMSB0byBtZXRhc3RhdGljIHNhbXBsZXMuDQptZXRhZGF0YV9tZXRhcyA8LSBkYXRhLmZyYW1lKCJTYW1wbGVfSUQiPWMoY29sbmFtZXMobG5jUk5BX2ZpbmFsKVsyOjU0M10pKQ0KDQpmb3IgKGkgaW4gMTo1NDIpIHsNCiAgc2FtcGxlIDwtIG1ldGFkYXRhX21ldGFzW2ksIDFdDQogIHNhbXBsZTIgPC0gZ3N1YigiXFwuIiwgIi0iLCBzYW1wbGUpDQogIHJvdzEgPC0gY2xpbl9uZXdbd2hpY2goY2xpbl9uZXckU2FtcGxlLklEID09IHNhbXBsZTIpLCBdDQogIGdyb3VwMSA8LSByb3cxJE1ldGFzdGFzaXNfR3JvdXANCiAgaWYgKGdyZXBsKCIuMTEiLCBzYW1wbGUsIGZpeGVkPVRSVUUpID09IFRSVUUpIHsNCiAgICBtZXRhZGF0YV9tZXRhc1tpLCBjKCJHcm91cCIpXSA8LSAwDQogIH0gZWxzZSB7DQogICAgaWYgKGdyb3VwMSA9PSAxKSB7DQogICAgICBtZXRhZGF0YV9tZXRhc1tpLCBjKCJHcm91cCIpXSA8LSAxDQogICAgfSBlbHNlew0KICAgICAgbWV0YWRhdGFfbWV0YXNbaSwgYygiR3JvdXAiKV0gPC0gMg0KICAgIH0NCiAgICBtZXRhZGF0YV9tZXRhc1tpLCBjKCJkYXlzX3RvX2RlYXRoIildIDwtIHJvdzEkT3ZlcmFsbC5TdXJ2aXZhbC4uTW9udGhzLg0KICB9DQp9DQoNCm1ldGFkYXRhX21ldGFzJEdyb3VwIDwtIGFzLmZhY3RvcihtZXRhZGF0YV9tZXRhcyRHcm91cCkNCmBgYA0KDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQoNCg0KDQpgYGB7cn0NCiNOZWVkIHRvIGNvbnZlcnQgdGhlIGdlbmUgbmFtZXMgdG8gdGhlIGFjdHVhbCByb3cgbmFtZXMsIGFuZCByZW1vdmUgdGhhdCBjb2x1bW4NCm1fREVTRVEgPC0gbVJOQV9maW5hbFssLTFdDQpyb3duYW1lcyhtX0RFU0VRKSA8LSBtUk5BX2ZpbmFsJEdlbmVfSUQNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoR0RDUk5BVG9vbHMpDQpsaWJyYXJ5KCJBbm5vdGF0aW9uRGJpIikNCmxpYnJhcnkoIm9yZy5Icy5lZy5kYiIpDQoNCm1fREVTRVEgPC0gbV9ERVNFUVszMDoyMDUzMSxdDQptX0RFU0VRJCdFTlRSRVonIDwtIGMocm93bmFtZXMobV9ERVNFUSkpDQptX0RFU0VRJCdFTlRSRVonIDwtIGdzdWIoIi4qXFx8IiwgIiIsIG1fREVTRVEkJ0VOVFJFWicpDQptX0RFU0VRJCdFbnNlbWJsZScgPC0gbWFwSWRzKG9yZy5Icy5lZy5kYiwga2V5cz1tX0RFU0VRJCdFTlRSRVonLCBrZXl0eXBlPSJFTlRSRVpJRCIsIGNvbHVtbj0iRU5TRU1CTCIpDQpyb3duYW1lcyhtX0RFU0VRKSA8LSBtYWtlLm5hbWVzKG1fREVTRVEkRW5zZW1ibGUsIHVuaXF1ZT1UUlVFKQ0KbV9ERVNFUSRFbnNlbWJsZSA8LSBOVUxMDQptX0RFU0VRJEVOVFJFWiA8LSBOVUxMDQoNCm1fREVTRVEgPC0gbV9ERVNFUVtjb21wbGV0ZS5jYXNlcyhtX0RFU0VRKSwgXQ0KDQptZXRhZGF0YV9uZXcgPC0gZGF0YS5mcmFtZShjKG1ldGFkYXRhJFNhbXBsZV9JRCkpDQptZXRhZGF0YV9uZXckJ0dyb3VwJyA8LSBpZmVsc2UobWV0YWRhdGEkR3JvdXAgPT0gMCwgJ05vcm1hbFRpc3N1ZScsICdQcmltYXJ5VHVtb3InKQ0KbWV0YWRhdGFfbmV3JCdkYXlzX3RvX2RlYXRoJyA8LSBtZXRhZGF0YSRkYXlzX3RvX2RlYXRoDQojbWV0YWRhdGFfbmV3JCdkYXlzX3RvX2xhc3RfZm9sbG93X3VwJyA9IE5BDQoNCiNtZXRhZGF0YV90ZXN0IDwtIGdkY1BhcnNlTWV0YWRhdGEocHJvamVjdC5pZD0nVENHQS1USENBJywgZGF0YS50eXBlPSdSTkFzZXEnKQ0KDQpERUdBbGwgPC0gZ2RjREVBbmFseXNpcyhjb3VudHM9cm91bmQobV9ERVNFUSksIGdyb3VwPW1ldGFkYXRhX25ldyRHcm91cCwgY29tcGFyaXNvbj0nTm9ybWFsVGlzc3VlLVByaW1hcnlUdW1vcicsIG1ldGhvZD0nbGltbWEnKQ0KDQpkZVBDX21STkEgPC0gZ2RjREVSZXBvcnQoZGVnPURFR0FsbCkNCmhlYWQoZGVQQ19tUk5BKQ0KYGBgDQoNCmBgYHtyfQ0KI05lZWQgdG8gY29udmVydCB0aGUgZ2VuZSBuYW1lcyB0byB0aGUgYWN0dWFsIHJvdyBuYW1lcywgYW5kIHJlbW92ZSB0aGF0IGNvbHVtbg0KbWlfREVTRVEgPC0gbWlSTkFfZmluYWxbLC0xXQ0Kcm93bmFtZXMobWlfREVTRVEpIDwtIG1pUk5BX2ZpbmFsJEdlbmVfSUQNCm1pX0RFU0VRW10gPC0gbGFwcGx5KG1pX0RFU0VRLCBhcy5udW1lcmljKQ0Kcm93bmFtZXMobWlfREVTRVEpIDwtIHN1YigiciIsICJSIiwgcm93bmFtZXMobWlfREVTRVEpKQ0KbWlfREVTRVEgPC0gbWlfREVTRVFbMjA6MjkyLF0NCm1pX0RFU0VRIDwtIG1pX0RFU0VRWyFncmVwbCgndW5hbm5vdGF0ZWQnLCByb3duYW1lcyhtaV9ERVNFUSkpLF0NCm1pX0RFU0VRIDwtIG5hLm9taXQobWlfREVTRVEpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KEdEQ1JOQVRvb2xzKQ0KbGlicmFyeSgiQW5ub3RhdGlvbkRiaSIpDQpsaWJyYXJ5KCJvcmcuSHMuZWcuZGIiKQ0KDQpERUdBbGwgPC0gZ2RjREVBbmFseXNpcyhjb3VudHM9cm91bmQobWlfREVTRVEpLCBncm91cD1tZXRhZGF0YV9uZXckR3JvdXAsIGNvbXBhcmlzb249J05vcm1hbFRpc3N1ZS1QcmltYXJ5VHVtb3InLCBtZXRob2Q9J2xpbW1hJykNCg0KZGVQQ19taVJOQSA8LSBnZGNERVJlcG9ydChkZWc9REVHQWxsKQ0KaGVhZChkZVBDX21pUk5BKQ0KYGBgDQoNCg0KYGBge3J9DQojTmVlZCB0byBjb252ZXJ0IHRoZSBnZW5lIG5hbWVzIHRvIHRoZSBhY3R1YWwgcm93IG5hbWVzLCBhbmQgcmVtb3ZlIHRoYXQgY29sdW1uDQpsbmNfREVTRVEgPC0gbG5jUk5BX2ZpbmFsWywtMV0NCnJvd25hbWVzKGxuY19ERVNFUSkgPC0gbG5jUk5BX2ZpbmFsJEdlbmVfSUQNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoR0RDUk5BVG9vbHMpDQpsaWJyYXJ5KCJBbm5vdGF0aW9uRGJpIikNCmxpYnJhcnkoIm9yZy5Icy5lZy5kYiIpDQoNCm1ldGFkYXRhX25ldyA8LSBkYXRhLmZyYW1lKGMobWV0YWRhdGEkU2FtcGxlX0lEKSkNCm1ldGFkYXRhX25ldyQnR3JvdXAnIDwtIGlmZWxzZShtZXRhZGF0YSRHcm91cCA9PSAwLCAnTm9ybWFsVGlzc3VlJywgJ1ByaW1hcnlUdW1vcicpDQoNCkRFR0FsbCA8LSBnZGNERUFuYWx5c2lzKGNvdW50cz1yb3VuZChsbmNfREVTRVEpLCBncm91cD1tZXRhZGF0YV9uZXckR3JvdXAsIGNvbXBhcmlzb249J05vcm1hbFRpc3N1ZS1QcmltYXJ5VHVtb3InLCBtZXRob2Q9J2xpbW1hJykNCg0KZGVQQ19sbmMgPC0gZ2RjREVSZXBvcnQoZGVnPURFR0FsbCkNCmhlYWQoZGVQQ19sbmMpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShHRENSTkFUb29scykNCm1pX0V4cHIgPC0gZ2RjVm9vbU5vcm1hbGl6YXRpb24oY291bnRzPW1pX0RFU0VRLCBmaWx0ZXI9VFJVRSkNCmNvbG5hbWVzKG1pX0V4cHIpIDwtIGdzdWIoIlxcLiIsICItIiwgY29sbmFtZXMobWlfRXhwcikpDQoNCm1fRXhwciA8LSBnZGNWb29tTm9ybWFsaXphdGlvbihjb3VudHM9bV9ERVNFUSwgZmlsdGVyPVRSVUUpDQpjb2xuYW1lcyhtX0V4cHIpIDwtIGdzdWIoIlxcLiIsICItIiwgY29sbmFtZXMobV9FeHByKSkNCg0KbG5jX0V4cHIgPC0gZ2RjVm9vbU5vcm1hbGl6YXRpb24oY291bnRzPWxuY19ERVNFUSwgZmlsdGVyPVRSVUUpDQpjb2xuYW1lcyhsbmNfRXhwcikgPC0gZ3N1YigiXFwuIiwgIi0iLCBjb2xuYW1lcyhsbmNfRXhwcikpDQoNCmRlX1JOQSA8LSByYmluZChkZVBDX2xuYywgZGVQQ19tUk5BKQ0KbG5jX2RlIDwtIGRlX1JOQVtkZV9STkEkJ2dyb3VwJyA9PSAnbG9uZ19ub25fY29kaW5nJyxdDQptX2RlIDwtIGRlX1JOQVtkZV9STkEkJ2dyb3VwJyA9PSAncHJvdGVpbl9jb2RpbmcnLF0NCg0KZ2RjQmFyUGxvdChkZV9STkEsIGFuZ2xlPTQ1LCBkYXRhLnR5cGU9J1JOQXNlcScpDQoNCmVucmljaE91dHB1dCA8LSBnZGNFbnJpY2hBbmFseXNpcyhnZW5lPXJvd25hbWVzKG1fZGUpLCBzaW1wbGlmeT1UUlVFKQ0KZ2RjRW5yaWNoUGxvdChlbnJpY2htZW50PWVucmljaE91dHB1dCwgdHlwZT0nYmFyJywgY2F0ZWdvcnk9J0dPJywgbnVtLnRlcm1zPTUpDQoNCmdkY0JhclBsb3QobG5jX2RlLCBhbmdsZT00NSwgZGF0YS50eXBlPSdSTkFzZXEnKQ0KDQpnZGNCYXJQbG90KGRlUENfbWlSTkEsIGFuZ2xlPTQ1LCBkYXRhLnR5cGU9J21pUk5BcycpDQoNCmxuY19FeHByXzIgPC0gbG5jX0V4cHJbcm93bmFtZXMobG5jX0V4cHIpICVpbiUgcm93bmFtZXMobG5jX2RlKSxdDQptX0V4cHJfMiA8LSBtX0V4cHJbcm93bmFtZXMobV9FeHByKSAlaW4lIHJvd25hbWVzKG1fZGUpLF0NCg0KbWlfRXhwcl8yIDwtIG1pX0V4cHJbcm93bmFtZXMobWlfRXhwcikgJWluJSByb3duYW1lcyhkZVBDX21pUk5BKSwgXQ0KDQoNClJOQV90b3QgPSByYmluZChsbmNfRXhwcl8yLCBtX0V4cHJfMikNCm1pX0V4cHJfZGYgPC0gZGF0YS5mcmFtZShtaV9FeHByKQ0KDQpjZU91dHB1dCA8LSBnZGNDRUFuYWx5c2lzKGxuYyA9IHJvd25hbWVzKGxuY19FeHByXzIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwYyA9IHJvd25hbWVzKG1fRXhwcl8yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbG5jLnRhcmdldHMgPSAnc3RhckJhc2UnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwYy50YXJnZXRzID0gJ3N0YXJCYXNlJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcm5hLmV4cHIgPSBSTkFfdG90LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtaXIuZXhwciA9IG1pX0V4cHJfMikNCg0KDQpgYGANCg0KYGBge3J9DQpnZGNCYXJQbG90KGRlUENfbWlSTkEsIGFuZ2xlPTQ1LCBkYXRhLnR5cGU9J21pUk5BJykNCmxuY19FeHByXzIgPC0gbG5jX0V4cHJbcm93bmFtZXMobG5jX0V4cHIpICVpbiUgcm93bmFtZXMobG5jX2RlKSxdDQptX0V4cHJfMiA8LSBtX0V4cHJbcm93bmFtZXMobV9FeHByKSAlaW4lIHJvd25hbWVzKG1fZGUpLF0NCg0KbWlfRXhwcl8yIDwtIG1pX0V4cHJbcm93bmFtZXMobWlfRXhwcikgJWluJSByb3duYW1lcyhkZVBDX21pUk5BKSwgXQ0KDQoNClJOQV90b3QgPSByYmluZChsbmNfRXhwcl8yLCBtX0V4cHJfMikNCm1pX0V4cHJfZGYgPC0gZGF0YS5mcmFtZShtaV9FeHByKQ0KYGBgDQoNCg0KYGBge3J9DQpkZUxOQyA8LSBjKCdFTlNHMDAwMDAyNjA5MjAnLCdFTlNHMDAwMDAyNDIxMjUnLCdFTlNHMDAwMDAyNjEyMTEnKQ0KZGVQQyA8LSBjKCdFTlNHMDAwMDAwNDMzNTUnLCdFTlNHMDAwMDAxMDk1ODYnLCdFTlNHMDAwMDAxNDQzNTUnLCAnRU5TRzAwMDAwMTk4NjI2JykNCmdlbmVzIDwtIGMoZGVMTkMsIGRlUEMpDQpzYW1wbGVzIDwtIGMoJ1RDR0EtMkYtQTlLTy0wMScsICdUQ0dBLTJGLUE5S1AtMDEnLA0KJ1RDR0EtMkYtQTlLUS0wMScsICdUQ0dBLTJGLUE5S1ItMDEnLA0KJ1RDR0EtMkYtQTlLVC0wMScsICdUQ0dBLTJGLUE5S1ctMDEnKQ0Kcm5hRXhwciA8LSBkYXRhLmZyYW1lKG1hdHJpeChjKDIuNyw3LjAsNC45LDYuOSw0LjYsMi41LA0KMC41LDIuNSw1LjcsNi41LDQuOSwzLjgsDQoyLjEsMi45LDUuOSw1LjcsNC41LDMuNSwNCjIuNyw1LjksNC41LDUuOCw1LjIsMy4wLA0KMi41LDIuMiw1LjMsNC40LDQuNCwyLjksDQoyLjQsMy44LDYuMiwzLjgsMy44LDQuMiwNCjEuMCwyLjAsMy4wLDQuMCw1LjAsNi4wKSw3LDYpLA0Kc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkNCnJvd25hbWVzKHJuYUV4cHIpIDwtIGdlbmVzDQpjb2xuYW1lcyhybmFFeHByKSA8LSBzYW1wbGVzDQptaXJFeHByIDwtIGRhdGEuZnJhbWUobWF0cml4KGMoNy43LDcuNCw3LjksOC45LDguNiw5LjUsDQo1LjEsNC40LDUuNSw4LjUsNC40LDMuNSwNCjQuOSw1LjUsNi45LDYuMSw1LjUsNC4xLA0KMTIuNCwxMy41LDE1LjEsMTUuNCwxMy4wLDEyLjgsDQoyLjUsMi4yLDUuMyw0LjQsNC40LDIuOSwNCjIuNCwyLjcsNi4yLDEuNSw0LjQsNC4yLCANCjEuMCwgMi4wLCAzLjAsIDQuMCwgNS4wLCA2LjApLDcsNiksDQpzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQ0KY29sbmFtZXMobWlyRXhwcikgPC0gc2FtcGxlcw0Kcm93bmFtZXMobWlyRXhwcikgPC0gYygnaHNhLW1pUi0zNDAtNXAtbWF0dXJlJywnaHNhLW1pUi0xODFiLTEtNXAtbWF0dXJlJywNCidoc2EtbWlSLTE4MWEtMi0zcC1tYXR1cmUnLCAnaHNhLW1pUi0xOTUtNXAtbWF0dXJlJywNCidoc2EtbWlSLTE5OWItNXAnLCdoc2EtbWlSLTE4Mi01cCcsICdoc2EtbWlSLTE0NmItNXAtbWF0dXJlJykNCmNlT3V0cHV0IDwtIGdkY0NFQW5hbHlzaXMobG5jID0gZGVMTkMsDQpwYyA9IGRlUEMsDQpsbmMudGFyZ2V0cyA9ICdzdGFyQmFzZScsDQpwYy50YXJnZXRzID0gJ3N0YXJCYXNlJywNCnJuYS5leHByID0gcm5hRXhwciwNCm1pci5leHByID0gbWlyRXhwcikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShzdXJ2aXZhbCkNCmxpYnJhcnkoc3Vydm1pbmVyKQ0KDQoNCnMgPC0gU3VydihtZXRhZGF0YSRQRklfdGltZSwgbWV0YWRhdGEkUEZJX1N0YXR1cykNCg0Kc2ZpdCA8LSBzdXJ2Zml0KFN1cnYoT1NfdGltZSwgT1NfU3RhdHVzKX5QRklfU3RhdHVzLCBkYXRhPW1ldGFkYXRhKQ0Kc3VtbWFyeShzZml0KQ0KDQoNCmdnc3VydnBsb3Qoc2ZpdCwgY29uZi5pbnQ9VFJVRSwgcHZhbD1UUlVFLCByaXNrLnRhYmxlPVRSVUUsIHJpc2sudGFibGUuY29sPSJzdHJhdGEiLCANCiAgICAgICAgICAgbGVnZW5kLmxhYnM9YygiTm90LXJlY3VycmVudCIsICJSZWN1cnJlbnQiKSwgbGVnZW5kLnRpdGxlPSJHcm91cCIsICANCiAgICAgICAgICAgcGFsZXR0ZT1jKCJkb2RnZXJibHVlMiIsICJvcmNoaWQyIiksIA0KICAgICAgICAgICB0aXRsZT0iS2FwbGFuLU1laWVyIEN1cnZlIGZvciBUaHlyb2lkIENhbmNlciBTdXJ2aXZhbCIsIHJpc2sudGFibGUuaGVpZ2h0PTAuMykNCmBgYA0KDQoNCmBgYHtyfQ0KbW9kIDwtIGNveHBoKFN1cnYoT1NfdGltZSwgT1NfU3RhdHVzKX5QRklfU3RhdHVzLCBkYXRhPW1ldGFkYXRhKQ0Kc3VtbWFyeShtb2QpDQpyZWxhdGVkIDwtIGMoKQ0KcF92YWxzIDwtIGMoKQ0KaGF6YXJkcyA8LSBjKCkNCmxvd2VyXzk1IDwtIGMoKQ0KaGlnaGVyXzk1IDwtIGMoKQ0KUk5BX3RvdF8yIDwtIGFzLmRhdGEuZnJhbWUodChSTkFfdG90KSkNCmxuY19FeHByXzMgPC0gYXMuZGF0YS5mcmFtZSh0KGxuY19FeHByXzIpKQ0KbG5jX21lcmdlZCA8LSBjYmluZChsbmNfRXhwcl8zLCBtZXRhZGF0YSkNClJOQV90b3RfMl9tZXJnZWQgPC0gY2JpbmQoUk5BX3RvdF8yLCBtZXRhZGF0YSkNCg0KbWlfRXhwcl8zIDwtIGFzLmRhdGEuZnJhbWUodChtaV9FeHByXzIpKQ0KbWlfbWVyZ2VkIDwtIGNiaW5kKG1pX0V4cHJfMywgbWV0YWRhdGEpDQoNCmZ1bGxfbWVyZ2UgPC0gY2JpbmQobG5jX0V4cHJfMywgbWlfbWVyZ2VkKQ0KDQoNCmZvciAoaSBpbiAxOjExMCkgew0KICANCiAgbW9kMiA8LSBjb3hwaChTdXJ2KFBGSV90aW1lLCBQRklfU3RhdHVzKX5nZXQoY29sbmFtZXMoZnVsbF9tZXJnZSlbaV0pLCBkYXRhPWZ1bGxfbWVyZ2UpDQogIHBfdmFsIDwtIHN1bW1hcnkobW9kMikkY29lZmZpY2llbnRzWzEsNV0NCiAgaGF6YXJkIDwtIHN1bW1hcnkobW9kMikkY29lZmZpY2llbnRzWzEsMl0NCiAgbG93ZXJfY29uZiA8LSBzdW1tYXJ5KG1vZDIpJGNvbmYuaW50WzEsM10NCiAgaGlnaGVyX2NvbmYgPC0gc3VtbWFyeShtb2QyKSRjb25mLmludFsxLDRdDQogICNwcmludChwX3ZhbCkNCiAgaWYgKHBfdmFsIDw9IDAuMDEpIHsNCiAgICByZWxhdGVkIDwtIGMocmVsYXRlZCwgY29sbmFtZXMoZnVsbF9tZXJnZSlbaV0pDQogICAgcF92YWxzIDwtIGMocF92YWxzLCBwX3ZhbCkNCiAgICBoYXphcmRzIDwtIGMoaGF6YXJkcywgaGF6YXJkKQ0KICAgIGxvd2VyXzk1IDwtIGMobG93ZXJfOTUsIGxvd2VyX2NvbmYpDQogICAgaGlnaGVyXzk1IDwtIGMoaGlnaGVyXzk1LCBoaWdoZXJfY29uZikNCiAgICBwcmludChjb2xuYW1lcyhmdWxsX21lcmdlKVtpXSkNCiAgICBwcmludChzdW1tYXJ5KG1vZDIpKQ0KICB9DQp9DQoNCmxpYnJhcnkoZHBseXIpDQpSTkFfdG90XzJfbWVyZ2VkJCdHZW5lMV9RdWFydGlsZScgPC0gbnRpbGUoUk5BX3RvdF8yX21lcmdlZCRFTlNHMDAwMDAxODc2NzgsIDQpDQpSTkFfdG90XzJfbWVyZ2VkJCdHZW5lMl9RdWFydGlsZScgPC0gbnRpbGUoUk5BX3RvdF8yX21lcmdlZCRFTlNHMDAwMDAxODM2MTUsIDQpDQpSTkFfdG90XzJfbWVyZ2VkJCdHZW5lM19RdWFydGlsZScgPC0gbnRpbGUoUk5BX3RvdF8yX21lcmdlZCRFTlNHMDAwMDAxMDU4NzcsIDQpDQpSTkFfdG90XzJfbWVyZ2VkJCdHZW5lNF9RdWFydGlsZScgPC0gbnRpbGUoUk5BX3RvdF8yX21lcmdlZCRFTlNHMDAwMDAxMzI4NDAsIDQpDQoNCm1pX21lcmdlZCQnR2VuZTFfUXVhcnRpbGUnIDwtIG50aWxlKG1pX21lcmdlZCQnaHNhLW1pUi0xODFhLTItM3Atc3RhcicsIDQpDQptaV9tZXJnZWQkJ0dlbmUyX1F1YXJ0aWxlJyA8LSBudGlsZShtaV9tZXJnZWQkJ2hzYS1taVItMTQ2Yi0zcC1tYXR1cmUnLCA0KQ0KDQpnZW5lXzEgPC0gUk5BX3RvdF8yX21lcmdlZFtSTkFfdG90XzJfbWVyZ2VkJEdlbmUxX1F1YXJ0aWxlICVpbiUgYygxLCA0KSxdDQoNCmdlbmVfMSRHZW5lMV9RdWFydGlsZSA8LSBzdWIoNCwgMiwgZ2VuZV8xJEdlbmUxX1F1YXJ0aWxlKQ0Kc2ZpdF8xIDwtIHN1cnZmaXQoU3VydihPU190aW1lLCBPU19TdGF0dXMpfkdlbmUxX1F1YXJ0aWxlLCBkYXRhPWdlbmVfMSkNCnN1bW1hcnkoc2ZpdF8xKQ0KDQpnZ3N1cnZwbG90KHNmaXRfMSwgY29uZi5pbnQ9RkFMU0UsIHB2YWw9VFJVRSwgcmlzay50YWJsZT1UUlVFLCByaXNrLnRhYmxlLmNvbD0ic3RyYXRhIiwgDQogICAgICAgICAgIGxlZ2VuZC5sYWJzPWMoIkxvdyBFeHByZXNzaW9uIiwgIkhpZ2ggRXhwcmVzc2lvbiIpLCBsZWdlbmQudGl0bGU9Ikdyb3VwIiwgIA0KICAgICAgICAgICBwYWxldHRlPWMoImRvZGdlcmJsdWUyIiwgInJlZDMiKSwgDQogICAgICAgICAgIHRpdGxlPSJLYXBsYW4tTWVpZXIgQ3VydmUgZm9yIFNQUlk0Iiwgcmlzay50YWJsZS5oZWlnaHQ9MC4zKQ0KDQoNCmdlbmVfMiA8LSBSTkFfdG90XzJfbWVyZ2VkW1JOQV90b3RfMl9tZXJnZWQkR2VuZTJfUXVhcnRpbGUgJWluJSBjKDEsIDQpLF0NCg0KZ2VuZV8yJEdlbmUyX1F1YXJ0aWxlIDwtIHN1Yig0LCAyLCBnZW5lXzIkR2VuZTJfUXVhcnRpbGUpDQpzZml0XzIgPC0gc3VydmZpdChTdXJ2KFBGSV90aW1lLCBQRklfU3RhdHVzKX5HZW5lMl9RdWFydGlsZSwgZGF0YT1nZW5lXzIpDQpzdW1tYXJ5KHNmaXRfMikNCg0KZ2dzdXJ2cGxvdChzZml0XzIsIGNvbmYuaW50PUZBTFNFLCBwdmFsPVRSVUUsIHJpc2sudGFibGU9VFJVRSwgcmlzay50YWJsZS5jb2w9InN0cmF0YSIsIA0KICAgICAgICAgICBsZWdlbmQubGFicz1jKCJMb3cgRXhwcmVzc2lvbiIsICJIaWdoIEV4cHJlc3Npb24iKSwgbGVnZW5kLnRpdGxlPSJHcm91cCIsICANCiAgICAgICAgICAgcGFsZXR0ZT1jKCJkb2RnZXJibHVlMiIsICJyZWQzIiksIA0KICAgICAgICAgICB0aXRsZT0iS2FwbGFuLU1laWVyIEN1cnZlIGZvciBGQU0xNjdCIiwgcmlzay50YWJsZS5oZWlnaHQ9MC4zKQ0KDQpnZW5lXzMgPC0gUk5BX3RvdF8yX21lcmdlZFtSTkFfdG90XzJfbWVyZ2VkJEdlbmUzX1F1YXJ0aWxlICVpbiUgYygxLCA0KSxdDQoNCmdlbmVfMyRHZW5lM19RdWFydGlsZSA8LSBzdWIoNCwgMiwgZ2VuZV8zJEdlbmUzX1F1YXJ0aWxlKQ0Kc2ZpdF8zIDwtIHN1cnZmaXQoU3VydihQRklfdGltZSwgUEZJX1N0YXR1cyl+R2VuZTNfUXVhcnRpbGUsIGRhdGE9Z2VuZV8zKQ0Kc3VtbWFyeShzZml0XzMpDQoNCmdnc3VydnBsb3Qoc2ZpdF8zLCBjb25mLmludD1GQUxTRSwgcHZhbD1UUlVFLCByaXNrLnRhYmxlPVRSVUUsIHJpc2sudGFibGUuY29sPSJzdHJhdGEiLCANCiAgICAgICAgICAgbGVnZW5kLmxhYnM9YygiTG93IEV4cHJlc3Npb24iLCAiSGlnaCBFeHByZXNzaW9uIiksIGxlZ2VuZC50aXRsZT0iR3JvdXAiLCAgDQogICAgICAgICAgIHBhbGV0dGU9YygiZG9kZ2VyYmx1ZTIiLCAicmVkMyIpLCANCiAgICAgICAgICAgdGl0bGU9IkthcGxhbi1NZWllciBDdXJ2ZSBmb3IgRE5BSDExIiwgcmlzay50YWJsZS5oZWlnaHQ9MC4zKQ0KDQpnZW5lXzQgPC0gUk5BX3RvdF8yX21lcmdlZFtSTkFfdG90XzJfbWVyZ2VkJEdlbmU0X1F1YXJ0aWxlICVpbiUgYygxLCA0KSxdDQoNCmdlbmVfNCRHZW5lMV9RdWFydGlsZSA8LSBzdWIoNCwgMiwgZ2VuZV80JEdlbmU0X1F1YXJ0aWxlKQ0Kc2ZpdF80IDwtIHN1cnZmaXQoU3VydihQRklfdGltZSwgUEZJX1N0YXR1cyl+R2VuZTRfUXVhcnRpbGUsIGRhdGE9Z2VuZV80KQ0Kc3VtbWFyeShzZml0XzQpDQoNCmdnc3VydnBsb3Qoc2ZpdF80LCBjb25mLmludD1GQUxTRSwgcHZhbD1UUlVFLCByaXNrLnRhYmxlPVRSVUUsIHJpc2sudGFibGUuY29sPSJzdHJhdGEiLCANCiAgICAgICAgICAgbGVnZW5kLmxhYnM9YygiTG93IEV4cHJlc3Npb24iLCAiSGlnaCBFeHByZXNzaW9uIiksIGxlZ2VuZC50aXRsZT0iR3JvdXAiLCAgDQogICAgICAgICAgIHBhbGV0dGU9YygiZG9kZ2VyYmx1ZTIiLCAicmVkMyIpLCANCiAgICAgICAgICAgdGl0bGU9IkthcGxhbi1NZWllciBDdXJ2ZSBmb3IgQkhNVDIiLCByaXNrLnRhYmxlLmhlaWdodD0wLjMpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQpyZXMgPC0gZGF0YS5mcmFtZShyZWxhdGVkLCBwX3ZhbHMsIGhhemFyZHMsIGxvd2VyXzk1LCBoaWdoZXJfOTUpDQpyZXMkcmVsYXRlZCA8LSBkZV9STkFbcm93bmFtZXMoZGVfUk5BKSAlaW4lIHJlcyRyZWxhdGVkLF0kc3ltYm9sDQpwIDwtIA0KICByZXMgfD4NCiAgZ2dwbG90KGFlcyh5ID0gZmN0X3JldihyZWxhdGVkKSkpICsgDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQpwIDwtIHAgKw0KICBnZW9tX3BvaW50KGFlcyh4PWhhemFyZHMpLCBzaGFwZT0xNSwgc2l6ZT0zKSArDQogIGdlb21fbGluZXJhbmdlKGFlcyh4bWluPWxvd2VyXzk1LCB4bWF4PWhpZ2hlcl85NSkpDQoNCnAgPC0gcCArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiKSArDQogIGxhYnMoeD0iSGF6YXJkIFJhdGlvIiwgeT0iIikNCg0KcCA8LSBwICsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygxLDEzKSwgeGxpbT1jKDAsIDIpKQ0KDQpwIDwtIHAgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSAuMywgeSA9IDEzLCBsYWJlbCA9ICJMb3dlciByZWN1ciBjaGFuY2UiKSArDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDEuNywgeSA9IDEzLCBsYWJlbCA9ICJIaWdoZXIgcmVjdXIgY2hhbmNlIikNCg0KcF9taWQgPC0gcCArIA0KICB0aGVtZShheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy55PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC55PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpKQ0KDQpyZXNfcGxvdCA8LSByZXMgfD4NCiAgIyByb3VuZCBlc3RpbWF0ZXMgYW5kIDk1JSBDSXMgdG8gMiBkZWNpbWFsIHBsYWNlcyBmb3Igam91cm5hbCBzcGVjaWZpY2F0aW9ucw0KICBtdXRhdGUoYWNyb3NzKA0KICAgIGMoaGF6YXJkcywgbG93ZXJfOTUsIGhpZ2hlcl85NSksDQogICAgfiBzdHJfcGFkKA0KICAgICAgcm91bmQoLngsIDIpLA0KICAgICAgd2lkdGggPSA0LA0KICAgICAgcGFkID0gIjAiLA0KICAgICAgc2lkZSA9ICJyaWdodCINCiAgICApDQogICksDQogICMgYWRkIGFuICItIiBiZXR3ZWVuIEhSIGVzdGltYXRlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzDQogIGVzdGltYXRlX2xhYiA9IHBhc3RlMChoYXphcmRzLCAiICgiLCBsb3dlcl85NSwgIi0iLCBoaWdoZXJfOTUsICIpIikpIHw+DQogICMgcm91bmQgcC12YWx1ZXMgdG8gdHdvIGRlY2ltYWwgcGxhY2VzLCBleGNlcHQgaW4gY2FzZXMgd2hlcmUgcCA8IC4wMDENCiAgbXV0YXRlKHBfdmFscyA9IGNhc2Vfd2hlbigNCiAgICBwX3ZhbHMgPCAuMDAxIH4gIjwwLjAwMSIsDQogICAgcm91bmQocF92YWxzLCAyKSA9PSAuMDUgfiBhcy5jaGFyYWN0ZXIocm91bmQocF92YWxzLDMpKSwNCiAgICBwX3ZhbHMgPCAuMDEgfiBzdHJfcGFkKCAjIGlmIGxlc3MgdGhhbiAuMDEsIGdvIG9uZSBtb3JlIGRlY2ltYWwgcGxhY2UNCiAgICAgIGFzLmNoYXJhY3Rlcihyb3VuZChwX3ZhbHMsIDMpKSwNCiAgICAgIHdpZHRoID0gNCwNCiAgICAgIHBhZCA9ICIwIiwNCiAgICAgIHNpZGUgPSAicmlnaHQiDQogICAgKSwNCiAgICBUUlVFIH4gc3RyX3BhZCggIyBvdGhlcndpc2UganVzdCByb3VuZCB0byAyIGRlY2ltYWwgcGxhY2VzIGFuZCBwYWQgc3RyaW5nIHNvIHRoYXQgLjIgcmVhZHMgYXMgMC4yMA0KICAgICAgYXMuY2hhcmFjdGVyKHJvdW5kKHBfdmFscywgMikpLA0KICAgICAgd2lkdGggPSA0LA0KICAgICAgcGFkID0gIjAiLA0KICAgICAgc2lkZSA9ICJyaWdodCINCiAgICApDQogICkpIHw+DQogICMgYWRkIGEgcm93IG9mIGRhdGEgdGhhdCBhcmUgYWN0dWFsbHkgY29sdW1uIG5hbWVzIHdoaWNoIHdpbGwgYmUgc2hvd24gb24gdGhlIHBsb3QgaW4gdGhlIG5leHQgc3RlcA0KICBiaW5kX3Jvd3MoDQogICAgZGF0YS5mcmFtZSgNCiAgICAgIHJlbGF0ZWQgPSAiTW9kZWwiLA0KICAgICAgZXN0aW1hdGVfbGFiID0gIkhhemFyZCBSYXRpbyAoOTUlIENJKSIsDQogICAgICBsb3dlcl85NSA9ICIiLA0KICAgICAgaGlnaGVyXzk1ID0gIiIsDQogICAgICBwX3ZhbHMgPSAicC12YWx1ZSINCiAgICApDQogICkgfD4NCiAgbXV0YXRlKHJlbGF0ZWQgPSBmY3RfcmV2KGZjdF9yZWxldmVsKHJlbGF0ZWQsICJNb2RlbCIpKSkNCg0KcF9sZWZ0IDwtDQogIHJlc19wbG90ICB8Pg0KICBnZ3Bsb3QoYWVzKHkgPSByZWxhdGVkKSkNCg0KcF9sZWZ0IDwtIA0KICBwX2xlZnQgKw0KICBnZW9tX3RleHQoYWVzKHggPSAwLCBsYWJlbCA9IHJlbGF0ZWQpLCBoanVzdCA9IDAsIGZvbnRmYWNlID0gImJvbGQiKQ0KDQpwX2xlZnQgPC0gDQogIHBfbGVmdCArDQogIGdlb21fdGV4dCgNCiAgICBhZXMoeCA9IDIuNSwgbGFiZWwgPSBlc3RpbWF0ZV9sYWIpLA0KICAgIGhqdXN0ID0gMCwNCiAgICBmb250ZmFjZSA9IGlmZWxzZShyZXNfcGxvdCRlc3RpbWF0ZV9sYWIgPT0gIkhhemFyZCBSYXRpbyAoOTUlIENJKSIsICJib2xkIiwgInBsYWluIikNCiAgKQ0KDQpwX2xlZnQgPC0NCiAgcF9sZWZ0ICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDQpKQ0KDQpwX3JpZ2h0IDwtDQogIHJlc19wbG90ICB8Pg0KICBnZ3Bsb3QoKSArDQogIGdlb21fdGV4dCgNCiAgICBhZXMoeCA9IDAsIHkgPSByZWxhdGVkLCBsYWJlbCA9IHBfdmFscyksDQogICAgaGp1c3QgPSAwLA0KICAgIGZvbnRmYWNlID0gaWZlbHNlKHJlc19wbG90JHBfdmFscyA9PSAicC12YWx1ZSIsICJib2xkIiwgInBsYWluIikNCiAgKSArDQogIHRoZW1lX3ZvaWQoKQ0KDQpsYXlvdXQgPC0gYygNCiAgYXJlYSh0ID0gMCwgbCA9IDAsIGIgPSAzMCwgciA9IDMpLCAjIGxlZnQgcGxvdCwgc3RhcnRzIGF0IHRoZSB0b3Agb2YgdGhlIHBhZ2UgKDApIGFuZCBnb2VzIDMwIHVuaXRzIGRvd24gYW5kIDMgdW5pdHMgdG8gdGhlIHJpZ2h0DQogIGFyZWEodCA9IDEsIGwgPSA0LCBiID0gMzAsIHIgPSA5KSwgIyBtaWRkbGUgcGxvdCBzdGFydHMgYSBsaXR0bGUgbG93ZXIgKHQ9MSkgYmVjYXVzZSB0aGVyZSdzIG5vIHRpdGxlLiBzdGFydHMgMSB1bml0IHJpZ2h0IG9mIHRoZSBsZWZ0IHBsb3QgKGw9NCwgd2hlcmVhcyBsZWZ0IHBsb3QgaXMgcj0zKSwgZ29lcyB0byB0aGUgYm90dG9tIG9mIHRoZSBwYWdlICgzMCB1bml0cyksIGFuZCA2IHVuaXRzIGZ1cnRoZXIgb3ZlciBmcm9tIHRoZSBsZWZ0IHBsb3QgKHI9OSB3aGVyZWFzIGxlZnQgcGxvdCBpcyByPTMpDQogIGFyZWEodCA9IDAsIGwgPSA5LCBiID0gMzAsIHIgPSAxMSkgIyByaWdodCBtb3N0IHBsb3Qgc3RhcnRzIGF0IHRvcCBvZiBwYWdlLCBiZWdpbnMgd2hlcmUgbWlkZGxlIHBsb3QgZW5kcyAobD05LCBhbmQgbWlkZGxlIHBsb3QgaXMgcj05KSwgZ29lcyB0byBib3R0b20gb2YgcGFnZSAoYj0zMCksIGFuZCBleHRlbmRzIHR3byB1bml0cyB3aWRlIChyPTExKQ0KKQ0KIyBmaW5hbCBwbG90IGFycmFuZ2VtZW50DQpwX2xlZnQgKyBwX21pZCArIHBfcmlnaHQgKyBwbG90X2xheW91dChkZXNpZ24gPSBsYXlvdXQpDQoNCmBgYA0KDQo=