Introduction

This document demonstrates a strategy to adjust the p-values for a differential translation efficiency analysis using riborex. The dataset involves a time-course experiment studying the effect of radiation on glioblatoma cells. Briefly, two glioblastoma cell lines U251 (p53 mt) and U343 (p53 wt) were profiled using RNA-Seq and Ribo-Seq at 3 time points: 0h, 1h and 2h post radiation.

Utility functions

suppressMessages(library(riborex))
suppressMessages(library(fdrtool))
suppressMessages(library(cowplot))
annotations <- read.table(file.path('..', 'annotations', 
                                    'hg38_gene_names_stripped.tsv'), 
                          header = F, 
                          col.names = c('gene_id', 'gene_name', 
                                        'gene_type'),
                          stringsAsFactors = F)
rownames(annotations) <- annotations$gene_id
histone.genes.df <- read.table(file.path('..', 'annotations', 
                                         'histone_genes.tsv'), 
                               header = T, 
                               stringsAsFactors = F,
                               sep = '\t') 
histone.genes.1 <- annotations[grep('HIST', annotations$gene_name), ]$gene_id
histone.genes.2 <-annotations[annotations$gene_name %in% 
                                histone.genes.df$Approved.Symbol, ]$gene_id
# Add RP1-34B20.21 separately since symbol doesn't have HIST in it.
histone.genes <- unique(c(histone.genes.1, histone.genes.2, 'ENSG00000282988'))
readcounts.dir <- file.path('..', 'read_counts', 'byCDS')
results.dir <- file.path('..', 'results', 'translation_efficiency', 
                         'without_histones_edgeRD')
rna.design.file <- file.path('..', 'design_files', 'rna_seq_design.tsv')
ribo.design.file <- file.path('..', 'design_files', 'ribo_seq_design.tsv')
## Suffix of htseq-count output
counts.suffix <- '.CDS.counts.tsv'
rna.design.info <- read.table(rna.design.file, header=T, 
                              stringsAsFactors=FALSE)
ribo.design.info <- read.table(ribo.design.file, header=T, 
                               stringsAsFactors=FALSE)
count.reads <- function(design.info, dirname){
 files <- paste(design.info$SampleFile, counts.suffix, sep='')
 sampleName <- design.info$SampleName
 sampleTable <- data.frame(sampleName=sampleName, fileName=files)
 ddsHTSeq <- DESeqDataSetFromHTSeqCount(sampleTable = sampleTable, 
          directory = file.path(readcounts.dir, dirname),
          design = ~ 1)
 rownames(ddsHTSeq) <- gsub('\\.[0-9]+', '', rownames(ddsHTSeq))
 # Remove histones
 ddsHTSeq <- ddsHTSeq[!(rownames(ddsHTSeq) %in% histone.genes),]
 ddsHTSeq <- ddsHTSeq[ rowSums(counts(ddsHTSeq)) > 1, ]
 dds <- DESeq(ddsHTSeq)
 return(counts(dds))
}
filter_results <- function(df){
 df<- as.data.frame(df)
 df <- df[order(df$padj),]
 df$gene_name <- annotations[rownames(df),]$gene_name
 df.sig <- subset(df, padj<0.05)
 return (df.sig)
}
filter_results.edgeR <- function(df){
 df<- as.data.frame(df$table)
 df <- df[order(df$FDR),]
 df$gene_name <- annotations[rownames(df),]$gene_name
 df.sig <- subset(df, FDR<0.05)
 return (df.sig)
}
doPvalueAdjustment <- function(results){
  hist(results$pvalue,  main = 'DESeq2 unadjusted p-values', 
       xlab = 'Unadjusted p-values')
  results <- results[ !is.na(results$padj), ]
  results <- results[ !is.na(results$pvalue), ]
  results <- results[, -which(names(results) == 'padj')]
  resultsFDR <- fdrtool(results$stat, 
                        statistic= 'normal', 
                        plot = T)
  results[,'padj']  <- p.adjust(resultsFDR$pval,
                                method = 'BH')
  hist(resultsFDR$pval, 
       main = 'DESeq2 corrected p-values | Empirical null', 
       xlab = 'Corrected p-values')
  return (results)
}
plotPValueByNormalizedCount <- function(results){
  qs <- c(0, quantile(results$baseMean[results$baseMean > 0], 0:15/15))
  bins <- cut(results$baseMean, qs)
  levels(bins) <- paste0("~", round(signif((qs[-1] + qs[-length(qs)])/2, 2)))
  fractionSig <- tapply(results$pvalue, bins, function(p)
    mean(p < .05, na.rm = TRUE))
  barplot(fractionSig, xlab = "mean normalized count",
                     ylab = "fraction of raw p values < 0.05")
  
}
riborex.for.cellline <- function(rna.read.counts, ribo.read.counts, 
                                 cell.line, contrast, engine='DESeq2', 
                                 merge.T1=FALSE){
 rna.read.counts <- rna.read.counts[, grepl(cell.line, 
                                            colnames(rna.read.counts))]
 ribo.read.counts <- ribo.read.counts[, grepl(cell.line, 
                                              colnames(ribo.read.counts))]
 rna.conditions.time <- as.factor(as.vector(
   sapply(colnames(rna.read.counts), 
          function(x) unlist(strsplit(x, '_'))[3])))
 ribo.conditions.time <- as.factor(as.vector(
   sapply(colnames(ribo.read.counts), 
          function(x) unlist(strsplit(x, '_'))[4])))
 rna.conditions.cell <- as.factor(as.vector(
   sapply(colnames(rna.read.counts), 
          function(x) unlist(strsplit(x, '_'))[1])))
 ribo.conditions.cell <- as.factor(
   as.vector(sapply(colnames(ribo.read.counts), 
                    function(x) unlist(strsplit(x, '_'))[1])))
 
 if (merge.T1){
   levels(rna.conditions.time)[levels(rna.conditions.time)=='T0'] <- 'T0T1'
   levels(rna.conditions.time)[levels(rna.conditions.time)=='T1'] <- 'T0T1'
   levels(ribo.conditions.time)[levels(ribo.conditions.time)=='T0'] <- 'T0T1'
   levels(ribo.conditions.time)[levels(ribo.conditions.time)=='T1'] <- 'T0T1'
 }
 rna.conditions <- data.frame('time' = rna.conditions.time)
 ribo.conditions <- data.frame('time' = ribo.conditions.time)
 common.genes <- intersect(rownames(rna.read.counts), 
                           rownames(ribo.read.counts)) 
 rna.read.counts <- rna.read.counts[common.genes,]
 ribo.read.counts <- ribo.read.counts[common.genes,]
 colnames(rna.read.counts) <- paste(colnames(rna.read.counts),
                                    'RNA', sep='_')
 colnames(ribo.read.counts) <- paste(colnames(ribo.read.counts),
                                     'Ribo', sep='_')
 res <- riborex(rna.read.counts, 
                ribo.read.counts, 
                rna.conditions, 
                ribo.conditions, 
                contrast = contrast, 
                engine = engine)
 return (res)
}

Read data

rna.read.counts.all <- count.reads(rna.design.info, 'rna_seq')
the design is ~ 1 (just an intercept). is this intended?estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 19 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
ribo.read.counts.all <- count.reads(ribo.design.info, 'ribo_seq')
the design is ~ 1 (just an intercept). is this intended?estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 26 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
rna.conditions.time.all <- as.factor(
  as.vector(sapply(colnames(rna.read.counts.all), 
                   function(x) unlist(strsplit(x, '_'))[3])))
ribo.conditions.time.all <- as.factor(
  as.vector(sapply(colnames(ribo.read.counts.all), 
                   function(x) unlist(strsplit(x, '_'))[4])))
rna.conditions.cell.all <- as.factor(
  as.vector(sapply(colnames(rna.read.counts.all),
                   function(x) unlist(strsplit(x, '_'))[1])))
ribo.conditions.cell.all <- as.factor(as.vector(
  sapply(colnames(ribo.read.counts.all),
         function(x) unlist(strsplit(x, '_'))[1])))
rna.conditions.all <- data.frame('cell.type' = rna.conditions.cell.all, 
                                 'time' = rna.conditions.time.all)
ribo.conditions.all <- data.frame('cell.type' = ribo.conditions.cell.all, 
                                  'time' = ribo.conditions.time.all)
common.genes <- intersect(rownames(rna.read.counts.all), 
                          rownames(ribo.read.counts.all)) 
rna.read.counts.all <- rna.read.counts.all[common.genes,]
ribo.read.counts.all <- ribo.read.counts.all[common.genes,]
colnames(rna.read.counts.all) <- paste(colnames(rna.read.counts.all),
                                       'RNA', sep='_')
colnames(ribo.read.counts.all) <- paste(colnames(ribo.read.counts.all),
                                        'Ribo', sep='_')
contrast.T1vsT0 <- c('time', 'T1', 'T0')
contrast.T24vsT0 <- c('time', 'T24', 'T0')
contrast.T24vsT1 <- c('time', 'T24', 'T1')

Transaltion Efficiency : T1 vs T0

We performed an exploratoy analysis which indicated that T1 and T0 samples are very similar at both RNA-Seq and Ribo-seq levels.

res.T1vsT0.edgeR <- riborex(rna.read.counts.all, 
                            ribo.read.counts.all, 
                            rna.conditions.all, 
                            ribo.conditions.all, 
                            contrast = contrast.T1vsT0,
                            engine = 'edgeR')
edgeR mode selected
combining design matrix
applying edgeR to modified design matrix
res.T1vsT0.sig.edgeR <- filter_results.edgeR(res.T1vsT0.edgeR)
res.T1vsT0.edgeRD <- riborex(rna.read.counts.all, 
                             ribo.read.counts.all, 
                             rna.conditions.all, 
                             ribo.conditions.all, 
                             contrast = contrast.T1vsT0,
                             engine = 'edgeRD')
edgeRD mode selected
combining design matrix
applying edgeR to modified design matrix
res.T1vsT0.sig.edgeRD <- filter_results.edgeR(res.T1vsT0.edgeRD)
res.T1vsT0.DESeq2 <- riborex(rna.read.counts.all, 
                             ribo.read.counts.all, 
                             rna.conditions.all, 
                             ribo.conditions.all, 
                             contrast = contrast.T1vsT0,
                             engine = 'DESeq2')
DESeq2 mode selected
combining design matrix
applying DESeq2 to modified design matrix
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
res.T1vsT0.sig.DESeq2 <- filter_results(res.T1vsT0.DESeq2)
#pdf('All_T1vsT0_DESeq2Adjust.pdf')
res.T1vsT0.DESeq2Adj <- doPvalueAdjustment(res.T1vsT0.DESeq2)
Step 1... determine cutoff point
Step 2... estimate parameters of null distribution and eta0
Step 3... compute p-values and estimate empirical PDF/CDF
Step 4... compute q-values and local fdr
Step 5... prepare for plotting

NA

#dev.off()
res.T1vsT0.sig.DESeq2Adj <- filter_results(res.T1vsT0.DESeq2Adj)
number_ticks <- function(n) {function(limits) pretty(limits, n)}
counts <- data.frame('tool'=c('edgeR', 'edgeRD', 'DESeq2', 'DESeq2 corrected'),
                     'DEgenes' = c(dim(res.T1vsT0.sig.edgeR)[1], 
                                   dim(res.T1vsT0.sig.edgeRD)[1], 
                                   dim(res.T1vsT0.sig.DESeq2)[1],
                                   dim(res.T1vsT0.sig.DESeq2Adj)[1]))
ggplot(counts, aes(tool, DEgenes, fill=tool)) +
  geom_col(position = 'dodge', width = 0.3) +  
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_y_continuous(breaks=number_ticks(12)) + ggtitle('All T1vsT0') +
  geom_text(aes(label=DEgenes), position=position_dodge(width=0.9), vjust=-0.25)
ggsave('comparison_All_T1vsT0.pdf')
Saving 7.29 x 4.5 in image

All T24 vs T1

res.T24vsT1.edgeR <- riborex(rna.read.counts.all, 
                             ribo.read.counts.all, 
                             rna.conditions.all, 
                             ribo.conditions.all, 
                             contrast = contrast.T24vsT1,
                             engine = 'edgeR')
edgeR mode selected
combining design matrix
applying edgeR to modified design matrix
res.T24vsT1.sig.edgeR <- filter_results.edgeR(res.T24vsT1.edgeR)
res.T24vsT1.edgeRD <- riborex(rna.read.counts.all, 
                              ribo.read.counts.all, 
                              rna.conditions.all, 
                              ribo.conditions.all, 
                              contrast = contrast.T24vsT1,
                              engine = 'edgeRD')
edgeRD mode selected
combining design matrix
applying edgeR to modified design matrix
res.T24vsT1.sig.edgeRD <- filter_results.edgeR(res.T24vsT1.edgeRD)
res.T24vsT1.DESeq2 <- riborex(rna.read.counts.all, 
                              ribo.read.counts.all, 
                              rna.conditions.all, 
                              ribo.conditions.all, 
                              contrast = contrast.T24vsT1,
                              engine = 'DESeq2')
DESeq2 mode selected
combining design matrix
applying DESeq2 to modified design matrix
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
res.T24vsT1.sig.DESeq2 <- filter_results(res.T24vsT1.DESeq2)
#pdf('All_T24vsT1_DESeq2Adjust.pdf')
res.T24vsT1.DESeq2Adj <- doPvalueAdjustment(res.T24vsT1.DESeq2)
Step 1... determine cutoff point
Step 2... estimate parameters of null distribution and eta0
Step 3... compute p-values and estimate empirical PDF/CDF
Step 4... compute q-values and local fdr
Step 5... prepare for plotting

NA

res.T24vsT1.sig.DESeq2Adj <- filter_results(res.T24vsT1.DESeq2Adj)
#dev.off()
counts <- data.frame('tool'=c('edgeR', 'edgeRD', 'DESeq2', 'DESeq2 corrected'),
                     'DEgenes' = c(dim(res.T24vsT1.sig.edgeR)[1], 
                                   dim(res.T24vsT1.sig.edgeRD)[1], 
                                   dim(res.T24vsT1.sig.DESeq2)[1],
                                   dim(res.T24vsT1.sig.DESeq2Adj)[1]))
ggplot(counts, aes(tool, DEgenes, fill=tool)) + 
  geom_col(position = 'dodge', width = 0.3) +  
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + 
  scale_y_continuous(breaks=number_ticks(12)) +
  ggtitle('All T24vsT1') +
  geom_text(aes(label=DEgenes), position=position_dodge(width=0.9), vjust=-0.25)
ggsave('comparison_All_T24vsT1.pdf')
Saving 7.29 x 4.5 in image

U251: T1 vs T0

U251.res.T1vsT0.edgeR <- riborex.for.cellline(rna.read.counts.all, 
                                        ribo.read.counts.all, 
                                        'U251', 
                                        contrast.T1vsT0,
                                        engine = 'edgeR')
edgeR mode selected
combining design matrix
applying edgeR to modified design matrix
U251.res.T1vsT0.sig.edgeR <- filter_results.edgeR(U251.res.T1vsT0.edgeR)
U251.res.T1vsT0.edgeRD <- riborex.for.cellline(rna.read.counts.all, 
                                        ribo.read.counts.all, 
                                        'U251', 
                                        contrast.T1vsT0,
                                        engine = 'edgeRD')
edgeRD mode selected
combining design matrix
applying edgeR to modified design matrix
U251.res.T1vsT0.sig.edgeRD <- filter_results.edgeR(U251.res.T1vsT0.edgeRD)
U251.res.T1vsT0.DESeq2 <- riborex.for.cellline(rna.read.counts.all, 
                                        ribo.read.counts.all, 
                                        'U251', 
                                        contrast.T1vsT0,
                                        engine = 'DESeq2')
DESeq2 mode selected
combining design matrix
applying DESeq2 to modified design matrix
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
U251.res.T1vsT0.sig.DESeq2 <- filter_results(U251.res.T1vsT0.DESeq2)
#pdf('U251_T1vsT0_DESeq2Adjust.pdf')
U251.res.T1vsT0.DESeq2Adj <- doPvalueAdjustment(U251.res.T1vsT0.DESeq2)
Step 1... determine cutoff point
Step 2... estimate parameters of null distribution and eta0
Step 3... compute p-values and estimate empirical PDF/CDF
Step 4... compute q-values and local fdr
Step 5... prepare for plotting

NA

#dev.off()
U251.res.T1vsT0.sig.DESeq2Adj <- filter_results(U251.res.T1vsT0.DESeq2Adj)
counts <- data.frame('tool' = c('edgeR', 'edgeRD', 'DESeq2', 'DESeq2 corrected'),
                     'DEgenes' = c(dim(U251.res.T1vsT0.sig.edgeR)[1], 
                                   dim(U251.res.T1vsT0.sig.edgeRD)[1], 
                                   dim(U251.res.T1vsT0.sig.DESeq2)[1],
                                   dim(U251.res.T1vsT0.sig.DESeq2Adj)[1]))
ggplot(counts, aes(tool, DEgenes, fill=tool)) +
  geom_col(position = 'dodge', width = 0.3) +  
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + 
  scale_y_continuous(breaks=number_ticks(12)) +
  ggtitle('U251 T1vsT0') +
  geom_text(aes(label=DEgenes), position=position_dodge(width=0.9), vjust=-0.25)
ggsave('comparison_U251_T1vsT0.pdf')
Saving 7.29 x 4.5 in image

U251.res.T24vsT1.edgeR <- riborex.for.cellline(rna.read.counts.all, 
                                               ribo.read.counts.all, 
                                               'U251', 
                                               contrast.T24vsT1,
                                               engine='edgeR')
edgeR mode selected
combining design matrix
applying edgeR to modified design matrix
U251.res.T24vsT1.sig.edgeR <- filter_results.edgeR(U251.res.T24vsT1.edgeR)
U251.res.T24vsT1.edgeRD <- riborex.for.cellline(rna.read.counts.all, 
                                         ribo.read.counts.all, 
                                         'U251', 
                                         contrast.T24vsT1,
                                         engine='edgeRD')
edgeRD mode selected
combining design matrix
applying edgeR to modified design matrix
U251.res.T24vsT1.sig.edgeRD <- filter_results.edgeR(U251.res.T24vsT1.edgeRD)
U251.res.T24vsT1.DESeq2 <- riborex.for.cellline(rna.read.counts.all, 
                                         ribo.read.counts.all, 
                                         'U251', 
                                         contrast.T24vsT1,
                                         engine='DESeq2')
DESeq2 mode selected
combining design matrix
applying DESeq2 to modified design matrix
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
U251.res.T24vsT1.sig.DESeq2 <- filter_results(U251.res.T24vsT1.DESeq2)
#pdf('U251_T24vsT1_DESeq2Adjust.pdf')
U251.res.T24vsT1.DESeq2Adj <- doPvalueAdjustment(U251.res.T24vsT1.DESeq2)
Step 1... determine cutoff point
Step 2... estimate parameters of null distribution and eta0
Step 3... compute p-values and estimate empirical PDF/CDF
Step 4... compute q-values and local fdr
Step 5... prepare for plotting

NA

#dev.off()
U251.res.T24vsT1.sig.DESeq2Adj <- filter_results(U251.res.T24vsT1.DESeq2Adj)
counts <- data.frame('tool'=c('edgeR', 'edgeRD', 'DESeq2', 'DESeq2 corrected'),
                     'DEgenes' = c(dim(U251.res.T24vsT1.sig.edgeR)[1], 
                                   dim(U251.res.T24vsT1.sig.edgeRD)[1], 
                                   dim(U251.res.T24vsT1.sig.DESeq2)[1],
                                   dim(U251.res.T24vsT1.sig.DESeq2Adj)[1]))
ggplot(counts, aes(tool, DEgenes, fill=tool)) + 
  geom_col(position = 'dodge', width = 0.3) +  
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + 
  scale_y_continuous(breaks=number_ticks(12)) +
  ggtitle('U251 T24vsT1') + 
  geom_text(aes(label=DEgenes), position=position_dodge(width=0.9), vjust=-0.25)
ggsave('comparison_U251_T24vsT1.pdf')
Saving 7.29 x 4.5 in image

U343: T1 vs T0

U343.res.T1vsT0.edgeR <- riborex.for.cellline(rna.read.counts.all, 
                                              ribo.read.counts.all, 
                                              'U343', 
                                              contrast.T1vsT0,
                                              engine = 'edgeR')
edgeR mode selected
combining design matrix
applying edgeR to modified design matrix
U343.res.T1vsT0.sig.edgeR <- filter_results.edgeR(U343.res.T1vsT0.edgeR)
U343.res.T1vsT0.edgeRD <- riborex.for.cellline(rna.read.counts.all, 
                                               ribo.read.counts.all, 
                                               'U343', 
                                               contrast.T1vsT0,
                                               engine = 'edgeRD')
edgeRD mode selected
combining design matrix
applying edgeR to modified design matrix
U343.res.T1vsT0.sig.edgeRD <- filter_results.edgeR(U343.res.T1vsT0.edgeRD)
U343.res.T1vsT0.DESeq2 <- riborex.for.cellline(rna.read.counts.all, 
                                               ribo.read.counts.all, 
                                               'U343', 
                                               contrast.T1vsT0,
                                               engine = 'DESeq2')
DESeq2 mode selected
combining design matrix
applying DESeq2 to modified design matrix
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
U343.res.T1vsT0.sig.DESeq2 <- filter_results(U343.res.T1vsT0.DESeq2)
#pdf('U343_T1vsT0_DESeq2Adjust.pdf')
U343.res.T1vsT0.DESeq2Adj <- doPvalueAdjustment(U343.res.T1vsT0.DESeq2)
Step 1... determine cutoff point
Step 2... estimate parameters of null distribution and eta0
Step 3... compute p-values and estimate empirical PDF/CDF
Step 4... compute q-values and local fdr
Step 5... prepare for plotting

NA

#dev.off()
U343.res.T1vsT0.sig.DESeq2Adj <- filter_results(U343.res.T1vsT0.DESeq2Adj)
counts <- data.frame('tool'=c('edgeR', 'edgeRD', 'DESeq2', 'DESeq2 corrected'),
                     'DEgenes' = c(dim(U343.res.T1vsT0.sig.edgeR)[1], 
                                   dim(U343.res.T1vsT0.sig.edgeRD)[1], 
                                   dim(U343.res.T1vsT0.sig.DESeq2)[1],
                                   dim(U343.res.T1vsT0.sig.DESeq2Adj)[1]))
ggplot(counts, aes(tool, DEgenes, fill=tool)) + 
  geom_col(position = 'dodge', width = 0.3) +  
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + scale_y_continuous(breaks=number_ticks(12)) +
  ggtitle('U343 T1vsT0') + geom_text(aes(label=DEgenes), position=position_dodge(width=0.9), vjust=-0.25)
ggsave('comparison_U343_T1vsT0.pdf')
Saving 7.29 x 4.5 in image

U343.res.T24vsT1.edgeR <- riborex.for.cellline(rna.read.counts.all, 
                                               ribo.read.counts.all, 
                                               'U343', 
                                               contrast.T24vsT1,
                                               engine='edgeR')
edgeR mode selected
combining design matrix
applying edgeR to modified design matrix
U343.res.T24vsT1.sig.edgeR <- filter_results.edgeR(U343.res.T24vsT1.edgeR)
U343.res.T24vsT1.edgeRD <- riborex.for.cellline(rna.read.counts.all, 
                                                ribo.read.counts.all, 
                                                'U343', 
                                                contrast.T24vsT1,
                                                engine='edgeRD')
edgeRD mode selected
combining design matrix
applying edgeR to modified design matrix
U343.res.T24vsT1.sig.edgeRD <- filter_results.edgeR(U343.res.T24vsT1.edgeRD)
U343.res.T24vsT1.DESeq2 <- riborex.for.cellline(rna.read.counts.all, 
                                                ribo.read.counts.all, 
                                                'U343', 
                                                contrast.T24vsT1,
                                                engine='DESeq2')
DESeq2 mode selected
combining design matrix
applying DESeq2 to modified design matrix
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
U343.res.T24vsT1.sig.DESeq2 <- filter_results(U343.res.T24vsT1.DESeq2)
#pdf('U343_T24vsT1_DESeq2Adjust.pdf')
U343.res.T24vsT1.DESeq2Adj <- doPvalueAdjustment(U343.res.T24vsT1.DESeq2)
Step 1... determine cutoff point
Step 2... estimate parameters of null distribution and eta0
Step 3... compute p-values and estimate empirical PDF/CDF
Step 4... compute q-values and local fdr
Step 5... prepare for plotting

NA

#dev.off()
U343.res.T24vsT1.sig.DESeq2Adj <- filter_results(U343.res.T24vsT1.DESeq2Adj)
counts <- data.frame('tool'=c('edgeR', 'edgeRD', 'DESeq2', 'DESeq2 corrected'),
                     'DEgenes' = c(dim(U343.res.T24vsT1.sig.edgeR)[1], 
                                   dim(U343.res.T24vsT1.sig.edgeRD)[1], 
                                   dim(U343.res.T24vsT1.sig.DESeq2)[1],
                                   dim(U343.res.T24vsT1.sig.DESeq2Adj)[1]))
ggplot(counts, aes(tool, DEgenes, fill=tool)) + 
  geom_col(position = 'dodge', width = 0.3) +  
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) + 
  scale_y_continuous(breaks=number_ticks(12)) +
  ggtitle('U343 T24vsT1') + 
  geom_text(aes(label=DEgenes), position=position_dodge(width=0.9), vjust=-0.25)
ggsave('comparison_U343_T24vsT1.pdf')
Saving 7.29 x 4.5 in image

LS0tCnRpdGxlOiAiQWNjb3VudGluZyBmb3Igb3ZlcmRpc3BlcnNpb24gaW4gUmlib3JleCIKc3VidGl0bGU6IFdoZW4gdGhlIHRoZW9yZXRpY2FsIGRpc3RyaWJ1dGlvbiBpcyB0b28gdGhlb3JldGljYWwuCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCiMgSW50cm9kdWN0aW9uCgpUaGlzICBkb2N1bWVudCBkZW1vbnN0cmF0ZXMgYSBzdHJhdGVneSB0byBhZGp1c3QgdGhlIHAtdmFsdWVzIGZvciBhIGRpZmZlcmVudGlhbCB0cmFuc2xhdGlvbiBlZmZpY2llbmN5IGFuYWx5c2lzIHVzaW5nIHJpYm9yZXguIFRoZSBkYXRhc2V0IGludm9sdmVzIGEgdGltZS1jb3Vyc2UgZXhwZXJpbWVudCBzdHVkeWluZyB0aGUgZWZmZWN0IG9mIHJhZGlhdGlvbiBvbiBnbGlvYmxhdG9tYSBjZWxscy4gQnJpZWZseSwgdHdvIGdsaW9ibGFzdG9tYSBjZWxsIGxpbmVzIFUyNTEgKHA1MyBtdCkgYW5kIFUzNDMgKHA1MyB3dCkgd2VyZSBwcm9maWxlZCB1c2luZyBSTkEtU2VxIGFuZCBSaWJvLVNlcSBhdCAzIHRpbWUgcG9pbnRzOiAwaCwgMWggYW5kIDJoIHBvc3QgcmFkaWF0aW9uLgoKIyBVdGlsaXR5IGZ1bmN0aW9ucwpgYGB7cn0Kc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHJpYm9yZXgpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZmRydG9vbCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShjb3dwbG90KSkKCmFubm90YXRpb25zIDwtIHJlYWQudGFibGUoZmlsZS5wYXRoKCcuLicsICdhbm5vdGF0aW9ucycsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaGczOF9nZW5lX25hbWVzX3N0cmlwcGVkLnRzdicpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCdnZW5lX2lkJywgJ2dlbmVfbmFtZScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2dlbmVfdHlwZScpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpyb3duYW1lcyhhbm5vdGF0aW9ucykgPC0gYW5ub3RhdGlvbnMkZ2VuZV9pZAoKCmhpc3RvbmUuZ2VuZXMuZGYgPC0gcmVhZC50YWJsZShmaWxlLnBhdGgoJy4uJywgJ2Fubm90YXRpb25zJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2hpc3RvbmVfZ2VuZXMudHN2JyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICdcdCcpIApoaXN0b25lLmdlbmVzLjEgPC0gYW5ub3RhdGlvbnNbZ3JlcCgnSElTVCcsIGFubm90YXRpb25zJGdlbmVfbmFtZSksIF0kZ2VuZV9pZApoaXN0b25lLmdlbmVzLjIgPC1hbm5vdGF0aW9uc1thbm5vdGF0aW9ucyRnZW5lX25hbWUgJWluJSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaXN0b25lLmdlbmVzLmRmJEFwcHJvdmVkLlN5bWJvbCwgXSRnZW5lX2lkCiMgQWRkIFJQMS0zNEIyMC4yMSBzZXBhcmF0ZWx5IHNpbmNlIHN5bWJvbCBkb2Vzbid0IGhhdmUgSElTVCBpbiBpdC4KaGlzdG9uZS5nZW5lcyA8LSB1bmlxdWUoYyhoaXN0b25lLmdlbmVzLjEsIGhpc3RvbmUuZ2VuZXMuMiwgJ0VOU0cwMDAwMDI4Mjk4OCcpKQoKCnJlYWRjb3VudHMuZGlyIDwtIGZpbGUucGF0aCgnLi4nLCAncmVhZF9jb3VudHMnLCAnYnlDRFMnKQpyZXN1bHRzLmRpciA8LSBmaWxlLnBhdGgoJy4uJywgJ3Jlc3VsdHMnLCAndHJhbnNsYXRpb25fZWZmaWNpZW5jeScsIAogICAgICAgICAgICAgICAgICAgICAgICAgJ3dpdGhvdXRfaGlzdG9uZXNfZWRnZVJEJykKcm5hLmRlc2lnbi5maWxlIDwtIGZpbGUucGF0aCgnLi4nLCAnZGVzaWduX2ZpbGVzJywgJ3JuYV9zZXFfZGVzaWduLnRzdicpCnJpYm8uZGVzaWduLmZpbGUgPC0gZmlsZS5wYXRoKCcuLicsICdkZXNpZ25fZmlsZXMnLCAncmlib19zZXFfZGVzaWduLnRzdicpCgojIyBTdWZmaXggb2YgaHRzZXEtY291bnQgb3V0cHV0CmNvdW50cy5zdWZmaXggPC0gJy5DRFMuY291bnRzLnRzdicKCnJuYS5kZXNpZ24uaW5mbyA8LSByZWFkLnRhYmxlKHJuYS5kZXNpZ24uZmlsZSwgaGVhZGVyPVQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQpyaWJvLmRlc2lnbi5pbmZvIDwtIHJlYWQudGFibGUocmliby5kZXNpZ24uZmlsZSwgaGVhZGVyPVQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKCgpjb3VudC5yZWFkcyA8LSBmdW5jdGlvbihkZXNpZ24uaW5mbywgZGlybmFtZSl7CiBmaWxlcyA8LSBwYXN0ZShkZXNpZ24uaW5mbyRTYW1wbGVGaWxlLCBjb3VudHMuc3VmZml4LCBzZXA9JycpCiBzYW1wbGVOYW1lIDwtIGRlc2lnbi5pbmZvJFNhbXBsZU5hbWUKIHNhbXBsZVRhYmxlIDwtIGRhdGEuZnJhbWUoc2FtcGxlTmFtZT1zYW1wbGVOYW1lLCBmaWxlTmFtZT1maWxlcykKIGRkc0hUU2VxIDwtIERFU2VxRGF0YVNldEZyb21IVFNlcUNvdW50KHNhbXBsZVRhYmxlID0gc2FtcGxlVGFibGUsIAogICAgICAgICAgZGlyZWN0b3J5ID0gZmlsZS5wYXRoKHJlYWRjb3VudHMuZGlyLCBkaXJuYW1lKSwKICAgICAgICAgIGRlc2lnbiA9IH4gMSkKIHJvd25hbWVzKGRkc0hUU2VxKSA8LSBnc3ViKCdcXC5bMC05XSsnLCAnJywgcm93bmFtZXMoZGRzSFRTZXEpKQogIyBSZW1vdmUgaGlzdG9uZXMKIGRkc0hUU2VxIDwtIGRkc0hUU2VxWyEocm93bmFtZXMoZGRzSFRTZXEpICVpbiUgaGlzdG9uZS5nZW5lcyksXQogZGRzSFRTZXEgPC0gZGRzSFRTZXFbIHJvd1N1bXMoY291bnRzKGRkc0hUU2VxKSkgPiAxLCBdCiBkZHMgPC0gREVTZXEoZGRzSFRTZXEpCgogcmV0dXJuKGNvdW50cyhkZHMpKQp9CgpmaWx0ZXJfcmVzdWx0cyA8LSBmdW5jdGlvbihkZil7CiBkZjwtIGFzLmRhdGEuZnJhbWUoZGYpCiBkZiA8LSBkZltvcmRlcihkZiRwYWRqKSxdCiBkZiRnZW5lX25hbWUgPC0gYW5ub3RhdGlvbnNbcm93bmFtZXMoZGYpLF0kZ2VuZV9uYW1lCiBkZi5zaWcgPC0gc3Vic2V0KGRmLCBwYWRqPDAuMDUpCiByZXR1cm4gKGRmLnNpZykKfQoKZmlsdGVyX3Jlc3VsdHMuZWRnZVIgPC0gZnVuY3Rpb24oZGYpewogZGY8LSBhcy5kYXRhLmZyYW1lKGRmJHRhYmxlKQogZGYgPC0gZGZbb3JkZXIoZGYkRkRSKSxdCiBkZiRnZW5lX25hbWUgPC0gYW5ub3RhdGlvbnNbcm93bmFtZXMoZGYpLF0kZ2VuZV9uYW1lCiBkZi5zaWcgPC0gc3Vic2V0KGRmLCBGRFI8MC4wNSkKIHJldHVybiAoZGYuc2lnKQp9Cgpkb1B2YWx1ZUFkanVzdG1lbnQgPC0gZnVuY3Rpb24ocmVzdWx0cyl7CiAgaGlzdChyZXN1bHRzJHB2YWx1ZSwgIG1haW4gPSAnREVTZXEyIHVuYWRqdXN0ZWQgcC12YWx1ZXMnLCAKICAgICAgIHhsYWIgPSAnVW5hZGp1c3RlZCBwLXZhbHVlcycpCiAgcmVzdWx0cyA8LSByZXN1bHRzWyAhaXMubmEocmVzdWx0cyRwYWRqKSwgXQogIHJlc3VsdHMgPC0gcmVzdWx0c1sgIWlzLm5hKHJlc3VsdHMkcHZhbHVlKSwgXQogIHJlc3VsdHMgPC0gcmVzdWx0c1ssIC13aGljaChuYW1lcyhyZXN1bHRzKSA9PSAncGFkaicpXQogIHJlc3VsdHNGRFIgPC0gZmRydG9vbChyZXN1bHRzJHN0YXQsIAogICAgICAgICAgICAgICAgICAgICAgICBzdGF0aXN0aWM9ICdub3JtYWwnLCAKICAgICAgICAgICAgICAgICAgICAgICAgcGxvdCA9IFQpCiAgcmVzdWx0c1ssJ3BhZGonXSAgPC0gcC5hZGp1c3QocmVzdWx0c0ZEUiRwdmFsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICdCSCcpCiAgaGlzdChyZXN1bHRzRkRSJHB2YWwsIAogICAgICAgbWFpbiA9ICdERVNlcTIgY29ycmVjdGVkIHAtdmFsdWVzIHwgRW1waXJpY2FsIG51bGwnLCAKICAgICAgIHhsYWIgPSAnQ29ycmVjdGVkIHAtdmFsdWVzJykKICByZXR1cm4gKHJlc3VsdHMpCn0KCgoKcGxvdFBWYWx1ZUJ5Tm9ybWFsaXplZENvdW50IDwtIGZ1bmN0aW9uKHJlc3VsdHMpewogIHFzIDwtIGMoMCwgcXVhbnRpbGUocmVzdWx0cyRiYXNlTWVhbltyZXN1bHRzJGJhc2VNZWFuID4gMF0sIDA6MTUvMTUpKQogIGJpbnMgPC0gY3V0KHJlc3VsdHMkYmFzZU1lYW4sIHFzKQogIGxldmVscyhiaW5zKSA8LSBwYXN0ZTAoIn4iLCByb3VuZChzaWduaWYoKHFzWy0xXSArIHFzWy1sZW5ndGgocXMpXSkvMiwgMikpKQogIGZyYWN0aW9uU2lnIDwtIHRhcHBseShyZXN1bHRzJHB2YWx1ZSwgYmlucywgZnVuY3Rpb24ocCkKICAgIG1lYW4ocCA8IC4wNSwgbmEucm0gPSBUUlVFKSkKICBiYXJwbG90KGZyYWN0aW9uU2lnLCB4bGFiID0gIm1lYW4gbm9ybWFsaXplZCBjb3VudCIsCiAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiZnJhY3Rpb24gb2YgcmF3IHAgdmFsdWVzIDwgMC4wNSIpCiAgCn0KCgpyaWJvcmV4LmZvci5jZWxsbGluZSA8LSBmdW5jdGlvbihybmEucmVhZC5jb3VudHMsIHJpYm8ucmVhZC5jb3VudHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZWxsLmxpbmUsIGNvbnRyYXN0LCBlbmdpbmU9J0RFU2VxMicsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXJnZS5UMT1GQUxTRSl7CiBybmEucmVhZC5jb3VudHMgPC0gcm5hLnJlYWQuY291bnRzWywgZ3JlcGwoY2VsbC5saW5lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhybmEucmVhZC5jb3VudHMpKV0KIHJpYm8ucmVhZC5jb3VudHMgPC0gcmliby5yZWFkLmNvdW50c1ssIGdyZXBsKGNlbGwubGluZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhyaWJvLnJlYWQuY291bnRzKSldCiBybmEuY29uZGl0aW9ucy50aW1lIDwtIGFzLmZhY3Rvcihhcy52ZWN0b3IoCiAgIHNhcHBseShjb2xuYW1lcyhybmEucmVhZC5jb3VudHMpLCAKICAgICAgICAgIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAnXycpKVszXSkpKQogcmliby5jb25kaXRpb25zLnRpbWUgPC0gYXMuZmFjdG9yKGFzLnZlY3RvcigKICAgc2FwcGx5KGNvbG5hbWVzKHJpYm8ucmVhZC5jb3VudHMpLCAKICAgICAgICAgIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAnXycpKVs0XSkpKQogcm5hLmNvbmRpdGlvbnMuY2VsbCA8LSBhcy5mYWN0b3IoYXMudmVjdG9yKAogICBzYXBwbHkoY29sbmFtZXMocm5hLnJlYWQuY291bnRzKSwgCiAgICAgICAgICBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgJ18nKSlbMV0pKSkKIHJpYm8uY29uZGl0aW9ucy5jZWxsIDwtIGFzLmZhY3RvcigKICAgYXMudmVjdG9yKHNhcHBseShjb2xuYW1lcyhyaWJvLnJlYWQuY291bnRzKSwgCiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICdfJykpWzFdKSkpCiAKIGlmIChtZXJnZS5UMSl7CiAgIGxldmVscyhybmEuY29uZGl0aW9ucy50aW1lKVtsZXZlbHMocm5hLmNvbmRpdGlvbnMudGltZSk9PSdUMCddIDwtICdUMFQxJwogICBsZXZlbHMocm5hLmNvbmRpdGlvbnMudGltZSlbbGV2ZWxzKHJuYS5jb25kaXRpb25zLnRpbWUpPT0nVDEnXSA8LSAnVDBUMScKICAgbGV2ZWxzKHJpYm8uY29uZGl0aW9ucy50aW1lKVtsZXZlbHMocmliby5jb25kaXRpb25zLnRpbWUpPT0nVDAnXSA8LSAnVDBUMScKICAgbGV2ZWxzKHJpYm8uY29uZGl0aW9ucy50aW1lKVtsZXZlbHMocmliby5jb25kaXRpb25zLnRpbWUpPT0nVDEnXSA8LSAnVDBUMScKIH0KIHJuYS5jb25kaXRpb25zIDwtIGRhdGEuZnJhbWUoJ3RpbWUnID0gcm5hLmNvbmRpdGlvbnMudGltZSkKIHJpYm8uY29uZGl0aW9ucyA8LSBkYXRhLmZyYW1lKCd0aW1lJyA9IHJpYm8uY29uZGl0aW9ucy50aW1lKQogY29tbW9uLmdlbmVzIDwtIGludGVyc2VjdChyb3duYW1lcyhybmEucmVhZC5jb3VudHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMocmliby5yZWFkLmNvdW50cykpIAogcm5hLnJlYWQuY291bnRzIDwtIHJuYS5yZWFkLmNvdW50c1tjb21tb24uZ2VuZXMsXQogcmliby5yZWFkLmNvdW50cyA8LSByaWJvLnJlYWQuY291bnRzW2NvbW1vbi5nZW5lcyxdCiBjb2xuYW1lcyhybmEucmVhZC5jb3VudHMpIDwtIHBhc3RlKGNvbG5hbWVzKHJuYS5yZWFkLmNvdW50cyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdSTkEnLCBzZXA9J18nKQogY29sbmFtZXMocmliby5yZWFkLmNvdW50cykgPC0gcGFzdGUoY29sbmFtZXMocmliby5yZWFkLmNvdW50cyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmlibycsIHNlcD0nXycpCiByZXMgPC0gcmlib3JleChybmEucmVhZC5jb3VudHMsIAogICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cywgCiAgICAgICAgICAgICAgICBybmEuY29uZGl0aW9ucywgCiAgICAgICAgICAgICAgICByaWJvLmNvbmRpdGlvbnMsIAogICAgICAgICAgICAgICAgY29udHJhc3QgPSBjb250cmFzdCwgCiAgICAgICAgICAgICAgICBlbmdpbmUgPSBlbmdpbmUpCiByZXR1cm4gKHJlcykKfQoKYGBgCgojIFJlYWQgZGF0YQoKYGBge3J9CnJuYS5yZWFkLmNvdW50cy5hbGwgPC0gY291bnQucmVhZHMocm5hLmRlc2lnbi5pbmZvLCAncm5hX3NlcScpCnJpYm8ucmVhZC5jb3VudHMuYWxsIDwtIGNvdW50LnJlYWRzKHJpYm8uZGVzaWduLmluZm8sICdyaWJvX3NlcScpCgpybmEuY29uZGl0aW9ucy50aW1lLmFsbCA8LSBhcy5mYWN0b3IoCiAgYXMudmVjdG9yKHNhcHBseShjb2xuYW1lcyhybmEucmVhZC5jb3VudHMuYWxsKSwgCiAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgJ18nKSlbM10pKSkKcmliby5jb25kaXRpb25zLnRpbWUuYWxsIDwtIGFzLmZhY3RvcigKICBhcy52ZWN0b3Ioc2FwcGx5KGNvbG5hbWVzKHJpYm8ucmVhZC5jb3VudHMuYWxsKSwgCiAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgJ18nKSlbNF0pKSkKcm5hLmNvbmRpdGlvbnMuY2VsbC5hbGwgPC0gYXMuZmFjdG9yKAogIGFzLnZlY3RvcihzYXBwbHkoY29sbmFtZXMocm5hLnJlYWQuY291bnRzLmFsbCksCiAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgJ18nKSlbMV0pKSkKcmliby5jb25kaXRpb25zLmNlbGwuYWxsIDwtIGFzLmZhY3Rvcihhcy52ZWN0b3IoCiAgc2FwcGx5KGNvbG5hbWVzKHJpYm8ucmVhZC5jb3VudHMuYWxsKSwKICAgICAgICAgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICdfJykpWzFdKSkpCgpybmEuY29uZGl0aW9ucy5hbGwgPC0gZGF0YS5mcmFtZSgnY2VsbC50eXBlJyA9IHJuYS5jb25kaXRpb25zLmNlbGwuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3RpbWUnID0gcm5hLmNvbmRpdGlvbnMudGltZS5hbGwpCnJpYm8uY29uZGl0aW9ucy5hbGwgPC0gZGF0YS5mcmFtZSgnY2VsbC50eXBlJyA9IHJpYm8uY29uZGl0aW9ucy5jZWxsLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAndGltZScgPSByaWJvLmNvbmRpdGlvbnMudGltZS5hbGwpCgpjb21tb24uZ2VuZXMgPC0gaW50ZXJzZWN0KHJvd25hbWVzKHJuYS5yZWFkLmNvdW50cy5hbGwpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhyaWJvLnJlYWQuY291bnRzLmFsbCkpIAoKcm5hLnJlYWQuY291bnRzLmFsbCA8LSBybmEucmVhZC5jb3VudHMuYWxsW2NvbW1vbi5nZW5lcyxdCnJpYm8ucmVhZC5jb3VudHMuYWxsIDwtIHJpYm8ucmVhZC5jb3VudHMuYWxsW2NvbW1vbi5nZW5lcyxdCgpjb2xuYW1lcyhybmEucmVhZC5jb3VudHMuYWxsKSA8LSBwYXN0ZShjb2xuYW1lcyhybmEucmVhZC5jb3VudHMuYWxsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JOQScsIHNlcD0nXycpCmNvbG5hbWVzKHJpYm8ucmVhZC5jb3VudHMuYWxsKSA8LSBwYXN0ZShjb2xuYW1lcyhyaWJvLnJlYWQuY291bnRzLmFsbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmlibycsIHNlcD0nXycpCgpjb250cmFzdC5UMXZzVDAgPC0gYygndGltZScsICdUMScsICdUMCcpCmNvbnRyYXN0LlQyNHZzVDAgPC0gYygndGltZScsICdUMjQnLCAnVDAnKQpjb250cmFzdC5UMjR2c1QxIDwtIGMoJ3RpbWUnLCAnVDI0JywgJ1QxJykKYGBgCgojIFRyYW5zYWx0aW9uIEVmZmljaWVuY3kgOiBUMSB2cyBUMApXZSBwZXJmb3JtZWQgYW4gZXhwbG9yYXRveSBhbmFseXNpcyB3aGljaCBpbmRpY2F0ZWQgdGhhdCBUMSBhbmQgVDAgc2FtcGxlcyBhcmUgdmVyeSBzaW1pbGFyIGF0IGJvdGggUk5BLVNlcSBhbmQgUmliby1zZXEgbGV2ZWxzLgpgYGB7cn0KcmVzLlQxdnNUMC5lZGdlUiA8LSByaWJvcmV4KHJuYS5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm5hLmNvbmRpdGlvbnMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpYm8uY29uZGl0aW9ucy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjb250cmFzdC5UMXZzVDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmUgPSAnZWRnZVInKQpyZXMuVDF2c1QwLnNpZy5lZGdlUiA8LSBmaWx0ZXJfcmVzdWx0cy5lZGdlUihyZXMuVDF2c1QwLmVkZ2VSKQpyZXMuVDF2c1QwLmVkZ2VSRCA8LSByaWJvcmV4KHJuYS5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpYm8ucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybmEuY29uZGl0aW9ucy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpYm8uY29uZGl0aW9ucy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gY29udHJhc3QuVDF2c1QwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICdlZGdlUkQnKQpyZXMuVDF2c1QwLnNpZy5lZGdlUkQgPC0gZmlsdGVyX3Jlc3VsdHMuZWRnZVIocmVzLlQxdnNUMC5lZGdlUkQpCnJlcy5UMXZzVDAuREVTZXEyIDwtIHJpYm9yZXgocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJuYS5jb25kaXRpb25zLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5jb25kaXRpb25zLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjb250cmFzdC5UMXZzVDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5naW5lID0gJ0RFU2VxMicpCnJlcy5UMXZzVDAuc2lnLkRFU2VxMiA8LSBmaWx0ZXJfcmVzdWx0cyhyZXMuVDF2c1QwLkRFU2VxMikKI3BkZignQWxsX1QxdnNUMF9ERVNlcTJBZGp1c3QucGRmJykKcmVzLlQxdnNUMC5ERVNlcTJBZGogPC0gZG9QdmFsdWVBZGp1c3RtZW50KHJlcy5UMXZzVDAuREVTZXEyKQojZGV2Lm9mZigpCnJlcy5UMXZzVDAuc2lnLkRFU2VxMkFkaiA8LSBmaWx0ZXJfcmVzdWx0cyhyZXMuVDF2c1QwLkRFU2VxMkFkaikKYGBgCgpgYGB7cn0KbnVtYmVyX3RpY2tzIDwtIGZ1bmN0aW9uKG4pIHtmdW5jdGlvbihsaW1pdHMpIHByZXR0eShsaW1pdHMsIG4pfQoKY291bnRzIDwtIGRhdGEuZnJhbWUoJ3Rvb2wnPWMoJ2VkZ2VSJywgJ2VkZ2VSRCcsICdERVNlcTInLCAnREVTZXEyIGNvcnJlY3RlZCcpLAogICAgICAgICAgICAgICAgICAgICAnREVnZW5lcycgPSBjKGRpbShyZXMuVDF2c1QwLnNpZy5lZGdlUilbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShyZXMuVDF2c1QwLnNpZy5lZGdlUkQpWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0ocmVzLlQxdnNUMC5zaWcuREVTZXEyKVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0ocmVzLlQxdnNUMC5zaWcuREVTZXEyQWRqKVsxXSkpCmdncGxvdChjb3VudHMsIGFlcyh0b29sLCBERWdlbmVzLCBmaWxsPXRvb2wpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAnZG9kZ2UnLCB3aWR0aCA9IDAuMykgKyAgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9bnVtYmVyX3RpY2tzKDEyKSkgKyBnZ3RpdGxlKCdBbGwgVDF2c1QwJykgKwogIGdlb21fdGV4dChhZXMobGFiZWw9REVnZW5lcyksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHZqdXN0PS0wLjI1KQpnZ3NhdmUoJ2NvbXBhcmlzb25fQWxsX1QxdnNUMC5wZGYnKQpgYGAKIyBBbGwgVDI0IHZzIFQxIAoKYGBge3J9CnJlcy5UMjR2c1QxLmVkZ2VSIDwtIHJpYm9yZXgocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJuYS5jb25kaXRpb25zLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5jb25kaXRpb25zLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjb250cmFzdC5UMjR2c1QxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICdlZGdlUicpCnJlcy5UMjR2c1QxLnNpZy5lZGdlUiA8LSBmaWx0ZXJfcmVzdWx0cy5lZGdlUihyZXMuVDI0dnNUMS5lZGdlUikKcmVzLlQyNHZzVDEuZWRnZVJEIDwtIHJpYm9yZXgocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpYm8ucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm5hLmNvbmRpdGlvbnMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5jb25kaXRpb25zLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gY29udHJhc3QuVDI0dnNUMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5naW5lID0gJ2VkZ2VSRCcpCnJlcy5UMjR2c1QxLnNpZy5lZGdlUkQgPC0gZmlsdGVyX3Jlc3VsdHMuZWRnZVIocmVzLlQyNHZzVDEuZWRnZVJEKQpyZXMuVDI0dnNUMS5ERVNlcTIgPC0gcmlib3JleChybmEucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybmEuY29uZGl0aW9ucy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWJvLmNvbmRpdGlvbnMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjb250cmFzdC5UMjR2c1QxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmUgPSAnREVTZXEyJykKcmVzLlQyNHZzVDEuc2lnLkRFU2VxMiA8LSBmaWx0ZXJfcmVzdWx0cyhyZXMuVDI0dnNUMS5ERVNlcTIpCiNwZGYoJ0FsbF9UMjR2c1QxX0RFU2VxMkFkanVzdC5wZGYnKQpyZXMuVDI0dnNUMS5ERVNlcTJBZGogPC0gZG9QdmFsdWVBZGp1c3RtZW50KHJlcy5UMjR2c1QxLkRFU2VxMikKcmVzLlQyNHZzVDEuc2lnLkRFU2VxMkFkaiA8LSBmaWx0ZXJfcmVzdWx0cyhyZXMuVDI0dnNUMS5ERVNlcTJBZGopCiNkZXYub2ZmKCkKYGBgCgpgYGB7cn0KY291bnRzIDwtIGRhdGEuZnJhbWUoJ3Rvb2wnPWMoJ2VkZ2VSJywgJ2VkZ2VSRCcsICdERVNlcTInLCAnREVTZXEyIGNvcnJlY3RlZCcpLAogICAgICAgICAgICAgICAgICAgICAnREVnZW5lcycgPSBjKGRpbShyZXMuVDI0dnNUMS5zaWcuZWRnZVIpWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0ocmVzLlQyNHZzVDEuc2lnLmVkZ2VSRClbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShyZXMuVDI0dnNUMS5zaWcuREVTZXEyKVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0ocmVzLlQyNHZzVDEuc2lnLkRFU2VxMkFkailbMV0pKQpnZ3Bsb3QoY291bnRzLCBhZXModG9vbCwgREVnZW5lcywgZmlsbD10b29sKSkgKyAKICBnZW9tX2NvbChwb3NpdGlvbiA9ICdkb2RnZScsIHdpZHRoID0gMC4zKSArICAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9bnVtYmVyX3RpY2tzKDEyKSkgKwogIGdndGl0bGUoJ0FsbCBUMjR2c1QxJykgKwogIGdlb21fdGV4dChhZXMobGFiZWw9REVnZW5lcyksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHZqdXN0PS0wLjI1KQpnZ3NhdmUoJ2NvbXBhcmlzb25fQWxsX1QyNHZzVDEucGRmJykKYGBgCgojIFUyNTE6IFQxIHZzIFQwCgpgYGB7cn0KVTI1MS5yZXMuVDF2c1QwLmVkZ2VSIDwtIHJpYm9yZXguZm9yLmNlbGxsaW5lKHJuYS5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1UyNTEnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0LlQxdnNUMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICdlZGdlUicpClUyNTEucmVzLlQxdnNUMC5zaWcuZWRnZVIgPC0gZmlsdGVyX3Jlc3VsdHMuZWRnZVIoVTI1MS5yZXMuVDF2c1QwLmVkZ2VSKQpVMjUxLnJlcy5UMXZzVDAuZWRnZVJEIDwtIHJpYm9yZXguZm9yLmNlbGxsaW5lKHJuYS5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1UyNTEnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0LlQxdnNUMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICdlZGdlUkQnKQpVMjUxLnJlcy5UMXZzVDAuc2lnLmVkZ2VSRCA8LSBmaWx0ZXJfcmVzdWx0cy5lZGdlUihVMjUxLnJlcy5UMXZzVDAuZWRnZVJEKQpVMjUxLnJlcy5UMXZzVDAuREVTZXEyIDwtIHJpYm9yZXguZm9yLmNlbGxsaW5lKHJuYS5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1UyNTEnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0LlQxdnNUMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICdERVNlcTInKQpVMjUxLnJlcy5UMXZzVDAuc2lnLkRFU2VxMiA8LSBmaWx0ZXJfcmVzdWx0cyhVMjUxLnJlcy5UMXZzVDAuREVTZXEyKQojcGRmKCdVMjUxX1QxdnNUMF9ERVNlcTJBZGp1c3QucGRmJykKVTI1MS5yZXMuVDF2c1QwLkRFU2VxMkFkaiA8LSBkb1B2YWx1ZUFkanVzdG1lbnQoVTI1MS5yZXMuVDF2c1QwLkRFU2VxMikKI2Rldi5vZmYoKQpVMjUxLnJlcy5UMXZzVDAuc2lnLkRFU2VxMkFkaiA8LSBmaWx0ZXJfcmVzdWx0cyhVMjUxLnJlcy5UMXZzVDAuREVTZXEyQWRqKQpgYGAKCmBgYHtyfQpjb3VudHMgPC0gZGF0YS5mcmFtZSgndG9vbCcgPSBjKCdlZGdlUicsICdlZGdlUkQnLCAnREVTZXEyJywgJ0RFU2VxMiBjb3JyZWN0ZWQnKSwKICAgICAgICAgICAgICAgICAgICAgJ0RFZ2VuZXMnID0gYyhkaW0oVTI1MS5yZXMuVDF2c1QwLnNpZy5lZGdlUilbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMjUxLnJlcy5UMXZzVDAuc2lnLmVkZ2VSRClbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMjUxLnJlcy5UMXZzVDAuc2lnLkRFU2VxMilbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltKFUyNTEucmVzLlQxdnNUMC5zaWcuREVTZXEyQWRqKVsxXSkpCmdncGxvdChjb3VudHMsIGFlcyh0b29sLCBERWdlbmVzLCBmaWxsPXRvb2wpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAnZG9kZ2UnLCB3aWR0aCA9IDAuMykgKyAgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPW51bWJlcl90aWNrcygxMikpICsKICBnZ3RpdGxlKCdVMjUxIFQxdnNUMCcpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPURFZ2VuZXMpLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB2anVzdD0tMC4yNSkKZ2dzYXZlKCdjb21wYXJpc29uX1UyNTFfVDF2c1QwLnBkZicpCmBgYAoKYGBge3J9ClUyNTEucmVzLlQyNHZzVDEuZWRnZVIgPC0gcmlib3JleC5mb3IuY2VsbGxpbmUocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMjUxJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QuVDI0dnNUMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmU9J2VkZ2VSJykKVTI1MS5yZXMuVDI0dnNUMS5zaWcuZWRnZVIgPC0gZmlsdGVyX3Jlc3VsdHMuZWRnZVIoVTI1MS5yZXMuVDI0dnNUMS5lZGdlUikKVTI1MS5yZXMuVDI0dnNUMS5lZGdlUkQgPC0gcmlib3JleC5mb3IuY2VsbGxpbmUocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMjUxJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QuVDI0dnNUMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmU9J2VkZ2VSRCcpClUyNTEucmVzLlQyNHZzVDEuc2lnLmVkZ2VSRCA8LSBmaWx0ZXJfcmVzdWx0cy5lZGdlUihVMjUxLnJlcy5UMjR2c1QxLmVkZ2VSRCkKVTI1MS5yZXMuVDI0dnNUMS5ERVNlcTIgPC0gcmlib3JleC5mb3IuY2VsbGxpbmUocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMjUxJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QuVDI0dnNUMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmU9J0RFU2VxMicpClUyNTEucmVzLlQyNHZzVDEuc2lnLkRFU2VxMiA8LSBmaWx0ZXJfcmVzdWx0cyhVMjUxLnJlcy5UMjR2c1QxLkRFU2VxMikKI3BkZignVTI1MV9UMjR2c1QxX0RFU2VxMkFkanVzdC5wZGYnKQpVMjUxLnJlcy5UMjR2c1QxLkRFU2VxMkFkaiA8LSBkb1B2YWx1ZUFkanVzdG1lbnQoVTI1MS5yZXMuVDI0dnNUMS5ERVNlcTIpCiNkZXYub2ZmKCkKVTI1MS5yZXMuVDI0dnNUMS5zaWcuREVTZXEyQWRqIDwtIGZpbHRlcl9yZXN1bHRzKFUyNTEucmVzLlQyNHZzVDEuREVTZXEyQWRqKQpgYGAKCmBgYHtyfQpjb3VudHMgPC0gZGF0YS5mcmFtZSgndG9vbCc9YygnZWRnZVInLCAnZWRnZVJEJywgJ0RFU2VxMicsICdERVNlcTIgY29ycmVjdGVkJyksCiAgICAgICAgICAgICAgICAgICAgICdERWdlbmVzJyA9IGMoZGltKFUyNTEucmVzLlQyNHZzVDEuc2lnLmVkZ2VSKVsxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltKFUyNTEucmVzLlQyNHZzVDEuc2lnLmVkZ2VSRClbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMjUxLnJlcy5UMjR2c1QxLnNpZy5ERVNlcTIpWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMjUxLnJlcy5UMjR2c1QxLnNpZy5ERVNlcTJBZGopWzFdKSkKZ2dwbG90KGNvdW50cywgYWVzKHRvb2wsIERFZ2VuZXMsIGZpbGw9dG9vbCkpICsgCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAnZG9kZ2UnLCB3aWR0aCA9IDAuMykgKyAgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPW51bWJlcl90aWNrcygxMikpICsKICBnZ3RpdGxlKCdVMjUxIFQyNHZzVDEnKSArIAogIGdlb21fdGV4dChhZXMobGFiZWw9REVnZW5lcyksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHZqdXN0PS0wLjI1KQpnZ3NhdmUoJ2NvbXBhcmlzb25fVTI1MV9UMjR2c1QxLnBkZicpCmBgYAoKIyBVMzQzOiBUMSB2cyBUMAoKYGBge3J9ClUzNDMucmVzLlQxdnNUMC5lZGdlUiA8LSByaWJvcmV4LmZvci5jZWxsbGluZShybmEucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpYm8ucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMzQzJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdC5UMXZzVDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmUgPSAnZWRnZVInKQpVMzQzLnJlcy5UMXZzVDAuc2lnLmVkZ2VSIDwtIGZpbHRlcl9yZXN1bHRzLmVkZ2VSKFUzNDMucmVzLlQxdnNUMC5lZGdlUikKVTM0My5yZXMuVDF2c1QwLmVkZ2VSRCA8LSByaWJvcmV4LmZvci5jZWxsbGluZShybmEucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWJvLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1UzNDMnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdC5UMXZzVDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5naW5lID0gJ2VkZ2VSRCcpClUzNDMucmVzLlQxdnNUMC5zaWcuZWRnZVJEIDwtIGZpbHRlcl9yZXN1bHRzLmVkZ2VSKFUzNDMucmVzLlQxdnNUMC5lZGdlUkQpClUzNDMucmVzLlQxdnNUMC5ERVNlcTIgPC0gcmlib3JleC5mb3IuY2VsbGxpbmUocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMzQzJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QuVDF2c1QwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICdERVNlcTInKQpVMzQzLnJlcy5UMXZzVDAuc2lnLkRFU2VxMiA8LSBmaWx0ZXJfcmVzdWx0cyhVMzQzLnJlcy5UMXZzVDAuREVTZXEyKQojcGRmKCdVMzQzX1QxdnNUMF9ERVNlcTJBZGp1c3QucGRmJykKVTM0My5yZXMuVDF2c1QwLkRFU2VxMkFkaiA8LSBkb1B2YWx1ZUFkanVzdG1lbnQoVTM0My5yZXMuVDF2c1QwLkRFU2VxMikKI2Rldi5vZmYoKQpVMzQzLnJlcy5UMXZzVDAuc2lnLkRFU2VxMkFkaiA8LSBmaWx0ZXJfcmVzdWx0cyhVMzQzLnJlcy5UMXZzVDAuREVTZXEyQWRqKQpgYGAKCmBgYHtyfQpjb3VudHMgPC0gZGF0YS5mcmFtZSgndG9vbCc9YygnZWRnZVInLCAnZWRnZVJEJywgJ0RFU2VxMicsICdERVNlcTIgY29ycmVjdGVkJyksCiAgICAgICAgICAgICAgICAgICAgICdERWdlbmVzJyA9IGMoZGltKFUzNDMucmVzLlQxdnNUMC5zaWcuZWRnZVIpWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0oVTM0My5yZXMuVDF2c1QwLnNpZy5lZGdlUkQpWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0oVTM0My5yZXMuVDF2c1QwLnNpZy5ERVNlcTIpWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMzQzLnJlcy5UMXZzVDAuc2lnLkRFU2VxMkFkailbMV0pKQpnZ3Bsb3QoY291bnRzLCBhZXModG9vbCwgREVnZW5lcywgZmlsbD10b29sKSkgKyAKICBnZW9tX2NvbChwb3NpdGlvbiA9ICdkb2RnZScsIHdpZHRoID0gMC4zKSArICAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3M9bnVtYmVyX3RpY2tzKDEyKSkgKwogIGdndGl0bGUoJ1UzNDMgVDF2c1QwJykgKyBnZW9tX3RleHQoYWVzKGxhYmVsPURFZ2VuZXMpLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB2anVzdD0tMC4yNSkKZ2dzYXZlKCdjb21wYXJpc29uX1UzNDNfVDF2c1QwLnBkZicpCmBgYAoKYGBge3J9ClUzNDMucmVzLlQyNHZzVDEuZWRnZVIgPC0gcmlib3JleC5mb3IuY2VsbGxpbmUocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmliby5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMzQzJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QuVDI0dnNUMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmdpbmU9J2VkZ2VSJykKVTM0My5yZXMuVDI0dnNUMS5zaWcuZWRnZVIgPC0gZmlsdGVyX3Jlc3VsdHMuZWRnZVIoVTM0My5yZXMuVDI0dnNUMS5lZGdlUikKVTM0My5yZXMuVDI0dnNUMS5lZGdlUkQgPC0gcmlib3JleC5mb3IuY2VsbGxpbmUocm5hLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpYm8ucmVhZC5jb3VudHMuYWxsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1UzNDMnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QuVDI0dnNUMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5naW5lPSdlZGdlUkQnKQpVMzQzLnJlcy5UMjR2c1QxLnNpZy5lZGdlUkQgPC0gZmlsdGVyX3Jlc3VsdHMuZWRnZVIoVTM0My5yZXMuVDI0dnNUMS5lZGdlUkQpClUzNDMucmVzLlQyNHZzVDEuREVTZXEyIDwtIHJpYm9yZXguZm9yLmNlbGxsaW5lKHJuYS5yZWFkLmNvdW50cy5hbGwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWJvLnJlYWQuY291bnRzLmFsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVMzQzJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0LlQyNHZzVDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZT0nREVTZXEyJykKVTM0My5yZXMuVDI0dnNUMS5zaWcuREVTZXEyIDwtIGZpbHRlcl9yZXN1bHRzKFUzNDMucmVzLlQyNHZzVDEuREVTZXEyKQojcGRmKCdVMzQzX1QyNHZzVDFfREVTZXEyQWRqdXN0LnBkZicpClUzNDMucmVzLlQyNHZzVDEuREVTZXEyQWRqIDwtIGRvUHZhbHVlQWRqdXN0bWVudChVMzQzLnJlcy5UMjR2c1QxLkRFU2VxMikKI2Rldi5vZmYoKQpVMzQzLnJlcy5UMjR2c1QxLnNpZy5ERVNlcTJBZGogPC0gZmlsdGVyX3Jlc3VsdHMoVTM0My5yZXMuVDI0dnNUMS5ERVNlcTJBZGopCmBgYAoKCmBgYHtyfQpjb3VudHMgPC0gZGF0YS5mcmFtZSgndG9vbCc9YygnZWRnZVInLCAnZWRnZVJEJywgJ0RFU2VxMicsICdERVNlcTIgY29ycmVjdGVkJyksCiAgICAgICAgICAgICAgICAgICAgICdERWdlbmVzJyA9IGMoZGltKFUzNDMucmVzLlQyNHZzVDEuc2lnLmVkZ2VSKVsxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltKFUzNDMucmVzLlQyNHZzVDEuc2lnLmVkZ2VSRClbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMzQzLnJlcy5UMjR2c1QxLnNpZy5ERVNlcTIpWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbShVMzQzLnJlcy5UMjR2c1QxLnNpZy5ERVNlcTJBZGopWzFdKSkKZ2dwbG90KGNvdW50cywgYWVzKHRvb2wsIERFZ2VuZXMsIGZpbGw9dG9vbCkpICsgCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAnZG9kZ2UnLCB3aWR0aCA9IDAuMykgKyAgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPW51bWJlcl90aWNrcygxMikpICsKICBnZ3RpdGxlKCdVMzQzIFQyNHZzVDEnKSArIAogIGdlb21fdGV4dChhZXMobGFiZWw9REVnZW5lcyksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHZqdXN0PS0wLjI1KQpnZ3NhdmUoJ2NvbXBhcmlzb25fVTM0M19UMjR2c1QxLnBkZicpCmBgYA==