library(AnnotationHub)

Attaching package: ‘AnnotationHub’

The following object is masked from ‘package:Biobase’:

    cache
library(GEOquery)
Setting options('download.file.method.GEOquery'='auto')
Setting options('GEOquery.inmemory.gpl'=FALSE)
library(data.table)
data.table 1.10.4
  The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way
  Documentation: ?data.table, example(data.table) and browseVignettes("data.table")
  Release notes, videos and slides: http://r-datatable.com

Attaching package: ‘data.table’

The following objects are masked from ‘package:reshape2’:

    dcast, melt

The following object is masked from ‘package:SummarizedExperiment’:

    shift

The following object is masked from ‘package:GenomicRanges’:

    shift

The following object is masked from ‘package:IRanges’:

    shift

The following objects are masked from ‘package:S4Vectors’:

    first, second
suppressMessages(library("DESeq2"))
hub = AnnotationHub()
snapshotDate(): 2017-04-25
gse = query(hub, "GSE62944")
suppl <- GEOquery::getGEOSuppFiles("GSE62944")
https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl/
OK
trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//GSE62944_01_27_15_TCGA_20_420_Clinical_Variables_7706_Samples.txt.gz'
Content type 'application/x-gzip' length 529880 bytes (517 KB)
==================================================
downloaded 517 KB

trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//GSE62944_01_27_15_TCGA_20_CancerType_Samples.txt.gz'
Content type 'application/x-gzip' length 57132 bytes (55 KB)
==================================================
downloaded 55 KB

trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//GSE62944_06_01_15_TCGA_24_548_Clinical_Variables_9264_Samples.txt.gz'
Content type 'application/x-gzip' length 1226302 bytes (1.2 MB)
==================================================
downloaded 1.2 MB

trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//GSE62944_06_01_15_TCGA_24_CancerType_Samples.txt.gz'
Content type 'application/x-gzip' length 73327 bytes (71 KB)
==================================================
downloaded 71 KB

trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//GSE62944_06_01_15_TCGA_24_Normal_CancerType_Samples.txt.gz'
Content type 'application/x-gzip' length 5585 bytes
==================================================
downloaded 5585 bytes

trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//GSE62944_RAW.tar'
Content type 'application/x-tar' length 6303805440 bytes (6011.8 MB)
==================================================
downloaded 6011.8 MB

trying URL 'https://ftp.ncbi.nlm.nih.gov/geo/series/GSE62nnn/GSE62944/suppl//filelist.txt'
Content type 'text/plain' length 997 bytes
==================================================
downloaded 997 bytes
clinvar <- read.table('../GSE62944_06_01_15_TCGA_24_548_Clinical_Variables_9264_Samples.txt', sep='\t', quote='', stringsAsFactors = F)
CancerType <- read.table('../GSE62944_06_01_15_TCGA_24_CancerType_Samples.txt', stringsAsFactors = F)
colnames(CancerType) <- c('ID', 'type')
NormalType <- read.table('../GSE62944_06_01_15_TCGA_24_Normal_CancerType_Samples.txt', stringsAsFactors = F)
colnames(NormalType) <- c('ID', 'type')
gbm.tumor <- subset(CancerType, type=='GBM')
gbm.normal <- subset(NormalType, type=='GBM')
gbm.normal.participants <- as.vector(sapply(gbm.normal$ID, function(x) paste(strsplit(x, "-")[[1]][1:3], collapse='-')))
gbm.tumor.participants <- as.vector(sapply(gbm.tumor$ID, function(x) paste(strsplit(x, "-")[[1]][1:3], collapse='-')))
gbm.tumor[gbm.tumor.participants %in% gbm.normal.participants,]

So we don’t have matched normals for GBM. But do we have it for say BRCA? (more easily obtainable tissue than brain)

brca.tumor <- subset(CancerType, type=='BRCA')
brca.normal <- subset(NormalType, type=='BRCA')
brca.normal.participants <- as.vector(sapply(brca.normal$ID, function(x) paste(strsplit(x, "-")[[1]][1:3], collapse='-')))
brca.tumor.participants <- as.vector(sapply(brca.tumor$ID, function(x) paste(strsplit(x, "-")[[1]][1:3], collapse='-')))
brca.tumor[brca.tumor.participants %in% brca.normal.participants,]

Loads of them! So we have no way but to work with GBM sameples from the same center.

gbm.normal.participants <- as.vector(sapply(gbm.normal$ID, function(x) paste(strsplit(x, "-")[[1]][1:2], collapse='-')))
gbm.tumor.participants <- as.vector(sapply(gbm.tumor$ID, function(x) paste(strsplit(x, "-")[[1]][1:2], collapse='-')))
gbm.06.samples <- gbm.tumor[gbm.tumor.participants %in% gbm.normal.participants,]
gbm.06.samples
all.tumor.counts <- read.table('../GBM_TCGA_featurecounts/GSM1536837_06_01_15_TCGA_24.tumor_Rsubread_FeatureCounts.txt')
all.normal.counts <- read.table('../GBM_TCGA_featurecounts/GSM1697009_06_01_15_TCGA_24.normal_Rsubread_FeatureCounts.txt')
gbm.tumor.counts <- all.tumor.counts[, colnames(all.tumor.counts) %in% gsub("-", ".", gbm.06.samples$ID)]
gbm.normal.counts <- all.normal.counts[, colnames(all.normal.counts) %in% gsub("-", ".", gbm.normal$ID)]
gbm.merged.counts <- cbind(gbm.tumor.counts, gbm.normal.counts)
write.table(gbm.merged.counts, '../GBM_TCGA_featurecounts/GBM.normal.tumour.featureCounts.tsv')
colData <- data.frame('ID' = c(gbm.normal$ID, gbm.06.samples$ID), 'condition' = c(rep('normal', length(gbm.normal$ID)),  rep('gbm', length(gbm.06.samples$ID))) )
rownames(colData) <- gsub("-", ".", colData$ID)
write.table(colData,  '../GBM_TCGA_featurecounts/GBM.normal.tumour.featureCounts.conditions.tsv')
  #merge(x=gbm.normal.counts, y=gbm.tumor.counts, all=TRUE)
do_DE_analysis <- function(countData, colData){
  stopifnot(rownames(colData) %in% colnames(countData))
  countData <- countData[, rownames(colData)]
  
  
  ddsCounts <- DESeqDataSetFromMatrix(countData=countData, colData=colData, design=~condition)
  featureData <- data.frame(gene=rownames(countData))
  mcols(ddsCounts) <- DataFrame(mcols(ddsCounts), featureData)
  ## We dont need version numbers
  ## Filter genes with atleast 2 count
  ddsCounts <- ddsCounts[ rowSums(counts(ddsCounts)) > 1,  ]
  
  ddsCounts$condition<-factor(ddsCounts$condition, levels=c('normal','gbm'))
  dds <- DESeq(ddsCounts)
  res <- results(dds, contrast=c('condition', 'gbm', 'normal'))
  resOrdered <- res[order(res$padj),]
  return(resOrdered)
}
countData <- as.matrix(gbm.merged.counts)
results.full <- do_DE_analysis(countData, colData)  
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 864 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
set.seed(42)
## randomly sample 5 samples from GBM so that we match the control samples
subsampled.gbm <- sample(gbm.06.samples$ID, 5)
subsampled.tumor.counts <- all.tumor.counts[, colnames(all.tumor.counts) %in% gsub("-", ".", subsampled.gbm)]
subsampled.counts <- cbind(subsampled.tumor.counts, gbm.normal.counts)
subsampled.colData <- data.frame('ID' = c(gbm.normal$ID, subsampled.gbm), 'condition' = c(rep('normal', length(gbm.normal$ID)),  rep('gbm', length(subsampled.gbm))) )
rownames(subsampled.colData) <- gsub("-", ".", subsampled.colData$ID)
results.subsampled <- do_DE_analysis(as.matrix(subsampled.counts), subsampled.colData)  
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
resSig.full <- as.data.frame(subset(results.full, padj<0.01))
resSig.subsampled <- as.data.frame(subset(results.subsampled, padj<0.01))
length(intersect(rownames(resSig.full), rownames(resSig.subsampled)))
[1] 6001
length(rownames(resSig.full))
[1] 8605
length(rownames(resSig.subsampled))
[1] 6965
length(intersect(rownames(resSig.full), rownames(resSig.subsampled)))/length(union(rownames(resSig.full), rownames(resSig.subsampled)))
[1] 0.6271293
LS0tCnRpdGxlOiAiVENHQSBHQk0gbm9ybWFsIHZzIGNvbnRyb2wgREUgYW5hbHlzaXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KEFubm90YXRpb25IdWIpCmxpYnJhcnkoR0VPcXVlcnkpCmxpYnJhcnkoZGF0YS50YWJsZSkKYGBgCgpgYGB7cn0Kc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KCJERVNlcTIiKSkKCmh1YiA9IEFubm90YXRpb25IdWIoKQpnc2UgPSBxdWVyeShodWIsICJHU0U2Mjk0NCIpCmBgYAoKYGBge3J9CnN1cHBsIDwtIEdFT3F1ZXJ5OjpnZXRHRU9TdXBwRmlsZXMoIkdTRTYyOTQ0IikKYGBgCgoKCgpgYGB7cn0KY2xpbnZhciA8LSByZWFkLnRhYmxlKCcuLi9HU0U2Mjk0NF8wNl8wMV8xNV9UQ0dBXzI0XzU0OF9DbGluaWNhbF9WYXJpYWJsZXNfOTI2NF9TYW1wbGVzLnR4dCcsIHNlcD0nXHQnLCBxdW90ZT0nJywgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCkNhbmNlclR5cGUgPC0gcmVhZC50YWJsZSgnLi4vR1NFNjI5NDRfMDZfMDFfMTVfVENHQV8yNF9DYW5jZXJUeXBlX1NhbXBsZXMudHh0Jywgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKENhbmNlclR5cGUpIDwtIGMoJ0lEJywgJ3R5cGUnKQpOb3JtYWxUeXBlIDwtIHJlYWQudGFibGUoJy4uL0dTRTYyOTQ0XzA2XzAxXzE1X1RDR0FfMjRfTm9ybWFsX0NhbmNlclR5cGVfU2FtcGxlcy50eHQnLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKY29sbmFtZXMoTm9ybWFsVHlwZSkgPC0gYygnSUQnLCAndHlwZScpCmBgYAoKYGBge3J9CmdibS50dW1vciA8LSBzdWJzZXQoQ2FuY2VyVHlwZSwgdHlwZT09J0dCTScpCmdibS5ub3JtYWwgPC0gc3Vic2V0KE5vcm1hbFR5cGUsIHR5cGU9PSdHQk0nKQoKZ2JtLm5vcm1hbC5wYXJ0aWNpcGFudHMgPC0gYXMudmVjdG9yKHNhcHBseShnYm0ubm9ybWFsJElELCBmdW5jdGlvbih4KSBwYXN0ZShzdHJzcGxpdCh4LCAiLSIpW1sxXV1bMTozXSwgY29sbGFwc2U9Jy0nKSkpCmdibS50dW1vci5wYXJ0aWNpcGFudHMgPC0gYXMudmVjdG9yKHNhcHBseShnYm0udHVtb3IkSUQsIGZ1bmN0aW9uKHgpIHBhc3RlKHN0cnNwbGl0KHgsICItIilbWzFdXVsxOjNdLCBjb2xsYXBzZT0nLScpKSkKZ2JtLnR1bW9yW2dibS50dW1vci5wYXJ0aWNpcGFudHMgJWluJSBnYm0ubm9ybWFsLnBhcnRpY2lwYW50cyxdCmBgYAoKU28gd2UgZG9uJ3QgaGF2ZSBtYXRjaGVkIG5vcm1hbHMgZm9yIEdCTS4gQnV0IGRvIHdlIGhhdmUgaXQgZm9yIHNheSBCUkNBPyAobW9yZSBlYXNpbHkgb2J0YWluYWJsZSB0aXNzdWUgdGhhbiBicmFpbikKCgpgYGB7cn0KYnJjYS50dW1vciA8LSBzdWJzZXQoQ2FuY2VyVHlwZSwgdHlwZT09J0JSQ0EnKQpicmNhLm5vcm1hbCA8LSBzdWJzZXQoTm9ybWFsVHlwZSwgdHlwZT09J0JSQ0EnKQoKYnJjYS5ub3JtYWwucGFydGljaXBhbnRzIDwtIGFzLnZlY3RvcihzYXBwbHkoYnJjYS5ub3JtYWwkSUQsIGZ1bmN0aW9uKHgpIHBhc3RlKHN0cnNwbGl0KHgsICItIilbWzFdXVsxOjNdLCBjb2xsYXBzZT0nLScpKSkKYnJjYS50dW1vci5wYXJ0aWNpcGFudHMgPC0gYXMudmVjdG9yKHNhcHBseShicmNhLnR1bW9yJElELCBmdW5jdGlvbih4KSBwYXN0ZShzdHJzcGxpdCh4LCAiLSIpW1sxXV1bMTozXSwgY29sbGFwc2U9Jy0nKSkpCmJyY2EudHVtb3JbYnJjYS50dW1vci5wYXJ0aWNpcGFudHMgJWluJSBicmNhLm5vcm1hbC5wYXJ0aWNpcGFudHMsXQpgYGAKCkxvYWRzIG9mIHRoZW0hIFNvIHdlIGhhdmUgbm8gd2F5IGJ1dCB0byB3b3JrIHdpdGggR0JNIHNhbWVwbGVzIGZyb20gdGhlIHNhbWUgY2VudGVyLgoKCgpgYGB7cn0KZ2JtLm5vcm1hbC5wYXJ0aWNpcGFudHMgPC0gYXMudmVjdG9yKHNhcHBseShnYm0ubm9ybWFsJElELCBmdW5jdGlvbih4KSBwYXN0ZShzdHJzcGxpdCh4LCAiLSIpW1sxXV1bMToyXSwgY29sbGFwc2U9Jy0nKSkpCmdibS50dW1vci5wYXJ0aWNpcGFudHMgPC0gYXMudmVjdG9yKHNhcHBseShnYm0udHVtb3IkSUQsIGZ1bmN0aW9uKHgpIHBhc3RlKHN0cnNwbGl0KHgsICItIilbWzFdXVsxOjJdLCBjb2xsYXBzZT0nLScpKSkKZ2JtLjA2LnNhbXBsZXMgPC0gZ2JtLnR1bW9yW2dibS50dW1vci5wYXJ0aWNpcGFudHMgJWluJSBnYm0ubm9ybWFsLnBhcnRpY2lwYW50cyxdCmdibS4wNi5zYW1wbGVzCmBgYAoKYGBge3J9CmFsbC50dW1vci5jb3VudHMgPC0gcmVhZC50YWJsZSgnLi4vR0JNX1RDR0FfZmVhdHVyZWNvdW50cy9HU00xNTM2ODM3XzA2XzAxXzE1X1RDR0FfMjQudHVtb3JfUnN1YnJlYWRfRmVhdHVyZUNvdW50cy50eHQnKQphbGwubm9ybWFsLmNvdW50cyA8LSByZWFkLnRhYmxlKCcuLi9HQk1fVENHQV9mZWF0dXJlY291bnRzL0dTTTE2OTcwMDlfMDZfMDFfMTVfVENHQV8yNC5ub3JtYWxfUnN1YnJlYWRfRmVhdHVyZUNvdW50cy50eHQnKQoKYGBgCgpgYGB7cn0KCmdibS50dW1vci5jb3VudHMgPC0gYWxsLnR1bW9yLmNvdW50c1ssIGNvbG5hbWVzKGFsbC50dW1vci5jb3VudHMpICVpbiUgZ3N1YigiLSIsICIuIiwgZ2JtLjA2LnNhbXBsZXMkSUQpXQpnYm0ubm9ybWFsLmNvdW50cyA8LSBhbGwubm9ybWFsLmNvdW50c1ssIGNvbG5hbWVzKGFsbC5ub3JtYWwuY291bnRzKSAlaW4lIGdzdWIoIi0iLCAiLiIsIGdibS5ub3JtYWwkSUQpXQpnYm0ubWVyZ2VkLmNvdW50cyA8LSBjYmluZChnYm0udHVtb3IuY291bnRzLCBnYm0ubm9ybWFsLmNvdW50cykKd3JpdGUudGFibGUoZ2JtLm1lcmdlZC5jb3VudHMsICcuLi9HQk1fVENHQV9mZWF0dXJlY291bnRzL0dCTS5ub3JtYWwudHVtb3VyLmZlYXR1cmVDb3VudHMudHN2JykKY29sRGF0YSA8LSBkYXRhLmZyYW1lKCdJRCcgPSBjKGdibS5ub3JtYWwkSUQsIGdibS4wNi5zYW1wbGVzJElEKSwgJ2NvbmRpdGlvbicgPSBjKHJlcCgnbm9ybWFsJywgbGVuZ3RoKGdibS5ub3JtYWwkSUQpKSwgIHJlcCgnZ2JtJywgbGVuZ3RoKGdibS4wNi5zYW1wbGVzJElEKSkpICkKcm93bmFtZXMoY29sRGF0YSkgPC0gZ3N1YigiLSIsICIuIiwgY29sRGF0YSRJRCkKd3JpdGUudGFibGUoY29sRGF0YSwgICcuLi9HQk1fVENHQV9mZWF0dXJlY291bnRzL0dCTS5ub3JtYWwudHVtb3VyLmZlYXR1cmVDb3VudHMuY29uZGl0aW9ucy50c3YnKQoKICAjbWVyZ2UoeD1nYm0ubm9ybWFsLmNvdW50cywgeT1nYm0udHVtb3IuY291bnRzLCBhbGw9VFJVRSkKYGBgCgoKYGBge3J9CmRvX0RFX2FuYWx5c2lzIDwtIGZ1bmN0aW9uKGNvdW50RGF0YSwgY29sRGF0YSl7CiAgc3RvcGlmbm90KHJvd25hbWVzKGNvbERhdGEpICVpbiUgY29sbmFtZXMoY291bnREYXRhKSkKICBjb3VudERhdGEgPC0gY291bnREYXRhWywgcm93bmFtZXMoY29sRGF0YSldCiAgCiAgCiAgZGRzQ291bnRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhPWNvdW50RGF0YSwgY29sRGF0YT1jb2xEYXRhLCBkZXNpZ249fmNvbmRpdGlvbikKICBmZWF0dXJlRGF0YSA8LSBkYXRhLmZyYW1lKGdlbmU9cm93bmFtZXMoY291bnREYXRhKSkKICBtY29scyhkZHNDb3VudHMpIDwtIERhdGFGcmFtZShtY29scyhkZHNDb3VudHMpLCBmZWF0dXJlRGF0YSkKICAjIyBXZSBkb250IG5lZWQgdmVyc2lvbiBudW1iZXJzCiAgIyMgRmlsdGVyIGdlbmVzIHdpdGggYXRsZWFzdCAyIGNvdW50CiAgZGRzQ291bnRzIDwtIGRkc0NvdW50c1sgcm93U3Vtcyhjb3VudHMoZGRzQ291bnRzKSkgPiAxLCAgXQogIAogIGRkc0NvdW50cyRjb25kaXRpb248LWZhY3RvcihkZHNDb3VudHMkY29uZGl0aW9uLCBsZXZlbHM9Yygnbm9ybWFsJywnZ2JtJykpCiAgZGRzIDwtIERFU2VxKGRkc0NvdW50cykKICByZXMgPC0gcmVzdWx0cyhkZHMsIGNvbnRyYXN0PWMoJ2NvbmRpdGlvbicsICdnYm0nLCAnbm9ybWFsJykpCiAgcmVzT3JkZXJlZCA8LSByZXNbb3JkZXIocmVzJHBhZGopLF0KICByZXR1cm4ocmVzT3JkZXJlZCkKCn0KY291bnREYXRhIDwtIGFzLm1hdHJpeChnYm0ubWVyZ2VkLmNvdW50cykKcmVzdWx0cy5mdWxsIDwtIGRvX0RFX2FuYWx5c2lzKGNvdW50RGF0YSwgY29sRGF0YSkgIAoKYGBgCgoKCmBgYHtyfQpzZXQuc2VlZCg0MikKCiMjIHJhbmRvbWx5IHNhbXBsZSA1IHNhbXBsZXMgZnJvbSBHQk0gc28gdGhhdCB3ZSBtYXRjaCB0aGUgY29udHJvbCBzYW1wbGVzCgpzdWJzYW1wbGVkLmdibSA8LSBzYW1wbGUoZ2JtLjA2LnNhbXBsZXMkSUQsIDUpCnN1YnNhbXBsZWQudHVtb3IuY291bnRzIDwtIGFsbC50dW1vci5jb3VudHNbLCBjb2xuYW1lcyhhbGwudHVtb3IuY291bnRzKSAlaW4lIGdzdWIoIi0iLCAiLiIsIHN1YnNhbXBsZWQuZ2JtKV0Kc3Vic2FtcGxlZC5jb3VudHMgPC0gY2JpbmQoc3Vic2FtcGxlZC50dW1vci5jb3VudHMsIGdibS5ub3JtYWwuY291bnRzKQpzdWJzYW1wbGVkLmNvbERhdGEgPC0gZGF0YS5mcmFtZSgnSUQnID0gYyhnYm0ubm9ybWFsJElELCBzdWJzYW1wbGVkLmdibSksICdjb25kaXRpb24nID0gYyhyZXAoJ25vcm1hbCcsIGxlbmd0aChnYm0ubm9ybWFsJElEKSksICByZXAoJ2dibScsIGxlbmd0aChzdWJzYW1wbGVkLmdibSkpKSApCnJvd25hbWVzKHN1YnNhbXBsZWQuY29sRGF0YSkgPC0gZ3N1YigiLSIsICIuIiwgc3Vic2FtcGxlZC5jb2xEYXRhJElEKQoKcmVzdWx0cy5zdWJzYW1wbGVkIDwtIGRvX0RFX2FuYWx5c2lzKGFzLm1hdHJpeChzdWJzYW1wbGVkLmNvdW50cyksIHN1YnNhbXBsZWQuY29sRGF0YSkgIAoKCmBgYAoKYGBge3J9CnJlc1NpZy5mdWxsIDwtIGFzLmRhdGEuZnJhbWUoc3Vic2V0KHJlc3VsdHMuZnVsbCwgcGFkajwwLjAxKSkKcmVzU2lnLnN1YnNhbXBsZWQgPC0gYXMuZGF0YS5mcmFtZShzdWJzZXQocmVzdWx0cy5zdWJzYW1wbGVkLCBwYWRqPDAuMDEpKQpgYGAKCgpgYGB7cn0KbGVuZ3RoKGludGVyc2VjdChyb3duYW1lcyhyZXNTaWcuZnVsbCksIHJvd25hbWVzKHJlc1NpZy5zdWJzYW1wbGVkKSkpCmBgYAoKYGBge3J9Cmxlbmd0aChyb3duYW1lcyhyZXNTaWcuZnVsbCkpCmBgYApgYGB7cn0KbGVuZ3RoKHJvd25hbWVzKHJlc1NpZy5zdWJzYW1wbGVkKSkKYGBgCgpgYGB7cn0KbGVuZ3RoKGludGVyc2VjdChyb3duYW1lcyhyZXNTaWcuZnVsbCksIHJvd25hbWVzKHJlc1NpZy5zdWJzYW1wbGVkKSkpL2xlbmd0aCh1bmlvbihyb3duYW1lcyhyZXNTaWcuZnVsbCksIHJvd25hbWVzKHJlc1NpZy5zdWJzYW1wbGVkKSkpCmBgYAo=