Data Retrieval

This project is focused on analyzing the TCGA-THCA data from a multiomics approach. Specifically, we will be analyzing mRNA, miRNA, lncRNA, and methylation data to describe the trends and relationships between the multiomic profiles of patients and their prognostic characteristics (e.g. survival and/or recurrence).

To start off, we need to import the relevant data we will be using. This data is sourced from TCGA (The Cancer Genome Atlas), although the mRNA, miRNA, methylation, and clinical data came from Firehose (from the Broad Institute), and the lncRNA data came from TANRIC.

Let’s first import the datasets we will be working with, and assign them to variables.

#Inputting the data into variables that we can manipulate
library(readxl)
Warning: package ‘readxl’ was built under R version 4.2.2

Let’s look at the head of these tables to understand their structure.

#Accessing the first few rows of each dataset
head(clinical)
head(lncRNA)
#head(methylation)
head(miRNA)
head(mRNA)

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=