1 Introduction

There is one important caveat: I only just remembered to queue up the salmon quantifications on the cluster. They should finish shortly, but this should nevertheless give a good idea of how similar the results are and the degree to which salmon/hisat2 agree.

Even before starting, I am willing to bet a very large sum that my salmon numbers will be nearly or completely identical to the numbers from dragen. Before moving on to compare my hisat numbers to dragen’s salmon, I bet that when we compare the count tables on a per-sample basis, the correlations are > 0.9 for every sample.

2 Annotation

hs_annot <- sm(load_biomart_annotations(year = "2020"))
hs_annot <- hs_annot[["annotation"]]
hs_annot[["transcript"]] <- paste0(rownames(hs_annot), ".", hs_annot[["version"]])
rownames(hs_annot) <- make.names(hs_annot[["ensembl_gene_id"]], unique = TRUE)
tx_gene_map <- hs_annot[, c("transcript", "ensembl_gene_id")]

summary(hs_annot)
##  ensembl_transcript_id ensembl_gene_id       version     transcript_version
##  Length:227921         Length:227921      Min.   : 1.0   Min.   : 1.00     
##  Class :character      Class :character   1st Qu.: 6.0   1st Qu.: 1.00     
##  Mode  :character      Mode  :character   Median :12.0   Median : 1.00     
##                                           Mean   :10.7   Mean   : 3.08     
##                                           3rd Qu.:16.0   3rd Qu.: 5.00     
##                                           Max.   :29.0   Max.   :17.00     
##                                                                            
##  hgnc_symbol        description        gene_biotype         cds_length    
##  Length:227921      Length:227921      Length:227921      Min.   :     3  
##  Class :character   Class :character   Class :character   1st Qu.:   357  
##  Mode  :character   Mode  :character   Mode  :character   Median :   694  
##                                                           Mean   :  1139  
##                                                           3rd Qu.:  1446  
##                                                           Max.   :107976  
##                                                           NA's   :127343  
##  chromosome_name       strand          start_position      end_position     
##  Length:227921      Length:227921      Min.   :5.77e+02   Min.   :6.47e+02  
##  Class :character   Class :character   1st Qu.:3.11e+07   1st Qu.:3.12e+07  
##  Mode  :character   Mode  :character   Median :6.04e+07   Median :6.06e+07  
##                                        Mean   :7.41e+07   Mean   :7.42e+07  
##                                        3rd Qu.:1.09e+08   3rd Qu.:1.09e+08  
##                                        Max.   :2.49e+08   Max.   :2.49e+08  
##                                                                             
##   transcript       
##  Length:227921     
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 

3 Fun!

hisat <- create_expt("sample_sheets/dragen_samples_202105.xlsx", file = "hg38100hisatfile",
                     gene_info = hs_annot) %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "typeofcells")
## Reading the sample metadata.
## The sample definitions comprises: 8 rows(samples) and 58 columns(metadata fields).
## Reading count tables.
## Reading count files with read.table().
## /fs01/cbcb-lab/nelsayed/scratch/atb/rnaseq/lpanamensis_tmrc_2019/preprocessing/TMRC30109/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows.
## preprocessing/TMRC30110/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30111/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30112/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30113/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30114/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30115/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30116/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## Finished reading count data.
## Matched 21452 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 21481 rows and 8 columns.
dragen <- create_expt("sample_sheets/dragen_samples_202105.xlsx", file = "hg3891salmonfile",
                      gene_info = hs_annot, tx_gene_map = tx_gene_map) %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "typeofcells")
## Reading the sample metadata.
## The sample definitions comprises: 8 rows(samples) and 58 columns(metadata fields).
## Reading count tables.
## Using the transcript to gene mapping.
## Reading salmon data with tximport.
## Finished reading count data.
## Matched 35866 annotations and counts.
## Bringing together the count matrix and gene information.
## The mapped IDs are not the rownames of your gene information, changing them now.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 35866 rows and 8 columns.
hisat_norm <- normalize_expt(hisat, filter = TRUE, norm = "quant",
                             convert = "cpm", transform = "log2")
## Removing 8507 low-count genes (12974 remaining).
## transform_counts: Found 142 values equal to 0, adding 1 to the matrix.
plot_pca(hisat_norm)$plot

dragen_norm <- normalize_expt(dragen, filter = TRUE, norm = "quant",
                              convert = "cpm", transform = "log2")
## Removing 28054 low-count genes (7812 remaining).
## transform_counts: Found 30473 values equal to 0, adding 1 to the matrix.
plot_pca(dragen_norm)$plot

merged_table <- merge(exprs(hisat), exprs(dragen), by = "row.names")
cor.test(merged_table[["TMRC30109.x"]], merged_table[["TMRC30109.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30109.x"]] and merged_table[["TMRC30109.y"]]
## t = 415, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9882 0.9896
## sample estimates:
##    cor 
## 0.9889
cor.test(merged_table[["TMRC30110.x"]], merged_table[["TMRC30110.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30110.x"]] and merged_table[["TMRC30110.y"]]
## t = 345, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9831 0.9851
## sample estimates:
##    cor 
## 0.9841
cor.test(merged_table[["TMRC30111.x"]], merged_table[["TMRC30111.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30111.x"]] and merged_table[["TMRC30111.y"]]
## t = 452, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9900 0.9912
## sample estimates:
##    cor 
## 0.9906
cor.test(merged_table[["TMRC30112.x"]], merged_table[["TMRC30112.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30112.x"]] and merged_table[["TMRC30112.y"]]
## t = 247, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9678 0.9716
## sample estimates:
##    cor 
## 0.9698
cor.test(merged_table[["TMRC30113.x"]], merged_table[["TMRC30113.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30113.x"]] and merged_table[["TMRC30113.y"]]
## t = 141, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9095 0.9197
## sample estimates:
##    cor 
## 0.9147
cor.test(merged_table[["TMRC30114.x"]], merged_table[["TMRC30114.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30114.x"]] and merged_table[["TMRC30114.y"]]
## t = 133, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9004 0.9116
## sample estimates:
##    cor 
## 0.9061
cor.test(merged_table[["TMRC30115.x"]], merged_table[["TMRC30115.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30115.x"]] and merged_table[["TMRC30115.y"]]
## t = 294, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.9769 0.9796
## sample estimates:
##    cor 
## 0.9782
cor.test(merged_table[["TMRC30116.x"]], merged_table[["TMRC30116.y"]])
## 
##  Pearson's product-moment correlation
## 
## data:  merged_table[["TMRC30116.x"]] and merged_table[["TMRC30116.y"]]
## t = 107, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.8567 0.8726
## sample estimates:
##    cor 
## 0.8648

Well, I was not completely correct, 30116 is a little lower.

3.1 Perform a quick DE

hisat_de <- all_pairwise(hisat, model_batch = FALSE)
## Plotting a PCA before surrogate/batch inclusion.
## Assuming no batch in model for testing pca.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
dragen_de <- all_pairwise(dragen, model_batch = FALSE)
## Plotting a PCA before surrogate/batch inclusion.
## Assuming no batch in model for testing pca.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
hisat_table <- combine_de_tables(hisat_de)
dragen_table <- combine_de_tables(dragen_de)

3.2 Compare the results and show some plots

comparison <- compare_de_results(hisat_table, dragen_table)
## Testing method: limma.
## Adding method: limma to the set.
## Testing method: deseq.
## Adding method: deseq to the set.
## Testing method: edger.
## Adding method: edger to the set.
##  Starting method limma, table Failure_vs_Cure.
## Warning in cor(x = fs[["x"]], y = fs[["y"]], method = cor_method): the standard
## deviation is zero
##  Starting method deseq, table Failure_vs_Cure.
## Warning in cor(x = fs[["x"]], y = fs[["y"]], method = cor_method): the standard
## deviation is zero
##  Starting method edger, table Failure_vs_Cure.
## Warning in cor(x = fs[["x"]], y = fs[["y"]], method = cor_method): the standard
## deviation is zero
tt <- merge(hisat_table[["data"]][[1]], dragen_table[["data"]][[1]], by = "row.names")
cor.test(tt[, "deseq_logfc.x"], tt[, "deseq_logfc.y"])
## 
##  Pearson's product-moment correlation
## 
## data:  tt[, "deseq_logfc.x"] and tt[, "deseq_logfc.y"]
## t = 45, df = 3879, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.5669 0.6081
## sample estimates:
##    cor 
## 0.5879
hmm <- plot_linear_scatter(tt[, c("deseq_logfc.x", "deseq_logfc.y")])
hmm$scatter

Keep in mind that I explicitly did not filter the input before passing it to DESeq/limma/EdgeR, thus this is a worst-case scenario comparison between the two methods, especially given the large range of coverage.

The dots on the y-axis are where htseq has decided not to count a given gene, presumably because of the quality scores returned by hisat2, multi-mapping, or due to difficult to handle introns.

The dots on the x-axis are where salmon has discounted the results for a given gene, presumably because of a multi-gene family.

Lets prove myself right or wrong…

hisat_de2 <- all_pairwise(hisat, model_batch = FALSE, filter = TRUE)
## Plotting a PCA before surrogate/batch inclusion.
## Assuming no batch in model for testing pca.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
dragen_de2 <- all_pairwise(dragen, model_batch = FALSE, filter = TRUE)
## Plotting a PCA before surrogate/batch inclusion.
## Assuming no batch in model for testing pca.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
hisat_table2 <- combine_de_tables(hisat_de2)
dragen_table2 <- combine_de_tables(dragen_de2)
comparison2 <- compare_de_results(hisat_table2, dragen_table2)
## Testing method: limma.
## Adding method: limma to the set.
## Testing method: deseq.
## Adding method: deseq to the set.
## Testing method: edger.
## Adding method: edger to the set.
##  Starting method limma, table Failure_vs_Cure.
## Warning in cor(x = fs[["x"]], y = fs[["y"]], method = cor_method): the standard
## deviation is zero
##  Starting method deseq, table Failure_vs_Cure.
##  Starting method edger, table Failure_vs_Cure.
comparison2[["logfc"]]
## Failure_vs_Cure 
##          0.7556
tt <- merge(hisat_table2[["data"]][[1]], dragen_table2[["data"]][[1]], by = "row.names")
cor.test(tt[, "deseq_logfc.x"], tt[, "deseq_logfc.y"])
## 
##  Pearson's product-moment correlation
## 
## data:  tt[, "deseq_logfc.x"] and tt[, "deseq_logfc.y"]
## t = 43, df = 975, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7829 0.8269
## sample estimates:
##   cor 
## 0.806
hmm2 <- plot_linear_scatter(tt[, c("deseq_logfc.x", "deseq_logfc.y")])
hmm2$scatter

hmm2$cor
## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 43, df = 975, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.7829 0.8269
## sample estimates:
##   cor 
## 0.806
hmm2 <- plot_linear_scatter(tt[, c("limma_logfc.x", "limma_logfc.y")])
hmm2$scatter

hmm2$cor
## 
##  Pearson's product-moment correlation
## 
## data:  df[, 1] and df[, 2]
## t = 27, df = 975, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.6209 0.6921
## sample estimates:
##   cor 
## 0.658
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiUXVpY2sgYW5kIGRpcnR5IGNvbXBhcmlzb24gb2YgaGlzYXQyIHZzIERyYWdlbidzIHNhbG1vbiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgIGNvbGxhcHNlZDogZmFsc2UKICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGhwZ2x0b29scykKdHQgPC0gc20oZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDEyMCwKICAgICAgICAgICAgICAgICAgICAgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSAxMiwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgIGRwaSA9IDk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cyA9IDQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMikpCnZlciA8LSAiMjAyMTA1IgpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQgPSAiJVklbSVkIikKCnJtZF9maWxlIDwtIGdsdWU6OmdsdWUoImNvbXBhcmVfZHJhZ2VuLlJtZCIpCnNhdmVmaWxlIDwtIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHJtZF9maWxlKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGVyZSBpcyBvbmUgaW1wb3J0YW50IGNhdmVhdDogSSBvbmx5IGp1c3QgcmVtZW1iZXJlZCB0byBxdWV1ZSB1cCB0aGUKc2FsbW9uIHF1YW50aWZpY2F0aW9ucyBvbiB0aGUgY2x1c3Rlci4gIFRoZXkgc2hvdWxkIGZpbmlzaCBzaG9ydGx5LApidXQgdGhpcyBzaG91bGQgbmV2ZXJ0aGVsZXNzIGdpdmUgYSBnb29kIGlkZWEgb2YgaG93IHNpbWlsYXIgdGhlCnJlc3VsdHMgYXJlIGFuZCB0aGUgZGVncmVlIHRvIHdoaWNoIHNhbG1vbi9oaXNhdDIgYWdyZWUuCgpFdmVuIGJlZm9yZSBzdGFydGluZywgSSBhbSB3aWxsaW5nIHRvIGJldCBhIHZlcnkgbGFyZ2Ugc3VtIHRoYXQgbXkKc2FsbW9uIG51bWJlcnMgd2lsbCBiZSBuZWFybHkgb3IgY29tcGxldGVseSBpZGVudGljYWwgdG8gdGhlIG51bWJlcnMKZnJvbSBkcmFnZW4uICBCZWZvcmUgbW92aW5nIG9uIHRvIGNvbXBhcmUgbXkgaGlzYXQgbnVtYmVycyB0byBkcmFnZW4ncwpzYWxtb24sIEkgYmV0IHRoYXQgd2hlbiB3ZSBjb21wYXJlIHRoZSBjb3VudCB0YWJsZXMgb24gYSBwZXItc2FtcGxlCmJhc2lzLCB0aGUgY29ycmVsYXRpb25zIGFyZSA+IDAuOSBmb3IgZXZlcnkgc2FtcGxlLgoKIyBBbm5vdGF0aW9uCgpgYGB7ciBoc19hbm5vdH0KaHNfYW5ub3QgPC0gc20obG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHllYXIgPSAiMjAyMCIpKQpoc19hbm5vdCA8LSBoc19hbm5vdFtbImFubm90YXRpb24iXV0KaHNfYW5ub3RbWyJ0cmFuc2NyaXB0Il1dIDwtIHBhc3RlMChyb3duYW1lcyhoc19hbm5vdCksICIuIiwgaHNfYW5ub3RbWyJ2ZXJzaW9uIl1dKQpyb3duYW1lcyhoc19hbm5vdCkgPC0gbWFrZS5uYW1lcyhoc19hbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSwgdW5pcXVlID0gVFJVRSkKdHhfZ2VuZV9tYXAgPC0gaHNfYW5ub3RbLCBjKCJ0cmFuc2NyaXB0IiwgImVuc2VtYmxfZ2VuZV9pZCIpXQoKc3VtbWFyeShoc19hbm5vdCkKYGBgCgojIEZ1biEKCmBgYHtyIGhpc2F0fQpoaXNhdCA8LSBjcmVhdGVfZXhwdCgic2FtcGxlX3NoZWV0cy9kcmFnZW5fc2FtcGxlc18yMDIxMDUueGxzeCIsIGZpbGUgPSAiaGczODEwMGhpc2F0ZmlsZSIsCiAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGhzX2Fubm90KSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gInR5cGVvZmNlbGxzIikKZHJhZ2VuIDwtIGNyZWF0ZV9leHB0KCJzYW1wbGVfc2hlZXRzL2RyYWdlbl9zYW1wbGVzXzIwMjEwNS54bHN4IiwgZmlsZSA9ICJoZzM4OTFzYWxtb25maWxlIiwKICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGhzX2Fubm90LCB0eF9nZW5lX21hcCA9IHR4X2dlbmVfbWFwKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gInR5cGVvZmNlbGxzIikKCmhpc2F0X25vcm0gPC0gbm9ybWFsaXplX2V4cHQoaGlzYXQsIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiKQpwbG90X3BjYShoaXNhdF9ub3JtKSRwbG90CgpkcmFnZW5fbm9ybSA8LSBub3JtYWxpemVfZXhwdChkcmFnZW4sIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIHRyYW5zZm9ybSA9ICJsb2cyIikKcGxvdF9wY2EoZHJhZ2VuX25vcm0pJHBsb3QKCm1lcmdlZF90YWJsZSA8LSBtZXJnZShleHBycyhoaXNhdCksIGV4cHJzKGRyYWdlbiksIGJ5ID0gInJvdy5uYW1lcyIpCmNvci50ZXN0KG1lcmdlZF90YWJsZVtbIlRNUkMzMDEwOS54Il1dLCBtZXJnZWRfdGFibGVbWyJUTVJDMzAxMDkueSJdXSkKY29yLnRlc3QobWVyZ2VkX3RhYmxlW1siVE1SQzMwMTEwLngiXV0sIG1lcmdlZF90YWJsZVtbIlRNUkMzMDExMC55Il1dKQpjb3IudGVzdChtZXJnZWRfdGFibGVbWyJUTVJDMzAxMTEueCJdXSwgbWVyZ2VkX3RhYmxlW1siVE1SQzMwMTExLnkiXV0pCmNvci50ZXN0KG1lcmdlZF90YWJsZVtbIlRNUkMzMDExMi54Il1dLCBtZXJnZWRfdGFibGVbWyJUTVJDMzAxMTIueSJdXSkKY29yLnRlc3QobWVyZ2VkX3RhYmxlW1siVE1SQzMwMTEzLngiXV0sIG1lcmdlZF90YWJsZVtbIlRNUkMzMDExMy55Il1dKQpjb3IudGVzdChtZXJnZWRfdGFibGVbWyJUTVJDMzAxMTQueCJdXSwgbWVyZ2VkX3RhYmxlW1siVE1SQzMwMTE0LnkiXV0pCmNvci50ZXN0KG1lcmdlZF90YWJsZVtbIlRNUkMzMDExNS54Il1dLCBtZXJnZWRfdGFibGVbWyJUTVJDMzAxMTUueSJdXSkKY29yLnRlc3QobWVyZ2VkX3RhYmxlW1siVE1SQzMwMTE2LngiXV0sIG1lcmdlZF90YWJsZVtbIlRNUkMzMDExNi55Il1dKQpgYGAKCldlbGwsIEkgd2FzIG5vdCBjb21wbGV0ZWx5IGNvcnJlY3QsIDMwMTE2IGlzIGEgbGl0dGxlIGxvd2VyLgoKIyMgUGVyZm9ybSBhIHF1aWNrIERFCgpgYGB7ciBkZSwgZmlnLnNob3cgPSAiaGlkZSJ9Cmhpc2F0X2RlIDwtIGFsbF9wYWlyd2lzZShoaXNhdCwgbW9kZWxfYmF0Y2ggPSBGQUxTRSkKZHJhZ2VuX2RlIDwtIGFsbF9wYWlyd2lzZShkcmFnZW4sIG1vZGVsX2JhdGNoID0gRkFMU0UpCmhpc2F0X3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKGhpc2F0X2RlKQpkcmFnZW5fdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoZHJhZ2VuX2RlKQpgYGAKCiMjIENvbXBhcmUgdGhlIHJlc3VsdHMgYW5kIHNob3cgc29tZSBwbG90cwoKYGBge3IgY29tcGFyZV9kZX0KY29tcGFyaXNvbiA8LSBjb21wYXJlX2RlX3Jlc3VsdHMoaGlzYXRfdGFibGUsIGRyYWdlbl90YWJsZSkKdHQgPC0gbWVyZ2UoaGlzYXRfdGFibGVbWyJkYXRhIl1dW1sxXV0sIGRyYWdlbl90YWJsZVtbImRhdGEiXV1bWzFdXSwgYnkgPSAicm93Lm5hbWVzIikKY29yLnRlc3QodHRbLCAiZGVzZXFfbG9nZmMueCJdLCB0dFssICJkZXNlcV9sb2dmYy55Il0pCmhtbSA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKHR0WywgYygiZGVzZXFfbG9nZmMueCIsICJkZXNlcV9sb2dmYy55IildKQpobW0kc2NhdHRlcgpgYGAKCktlZXAgaW4gbWluZCB0aGF0IEkgZXhwbGljaXRseSBkaWQgbm90IGZpbHRlciB0aGUgaW5wdXQgYmVmb3JlIHBhc3NpbmcKaXQgdG8gREVTZXEvbGltbWEvRWRnZVIsIHRodXMgdGhpcyBpcyBhIHdvcnN0LWNhc2Ugc2NlbmFyaW8gY29tcGFyaXNvbgpiZXR3ZWVuIHRoZSB0d28gbWV0aG9kcywgZXNwZWNpYWxseSBnaXZlbiB0aGUgbGFyZ2UgcmFuZ2Ugb2YgY292ZXJhZ2UuCgpUaGUgZG90cyBvbiB0aGUgeS1heGlzIGFyZSB3aGVyZSBodHNlcSBoYXMgZGVjaWRlZCBub3QgdG8gY291bnQgYQpnaXZlbiBnZW5lLCBwcmVzdW1hYmx5IGJlY2F1c2Ugb2YgdGhlIHF1YWxpdHkgc2NvcmVzIHJldHVybmVkIGJ5Cmhpc2F0MiwgbXVsdGktbWFwcGluZywgb3IgZHVlIHRvIGRpZmZpY3VsdCB0byBoYW5kbGUgaW50cm9ucy4KClRoZSBkb3RzIG9uIHRoZSB4LWF4aXMgYXJlIHdoZXJlIHNhbG1vbiBoYXMgZGlzY291bnRlZCB0aGUgcmVzdWx0cyBmb3IKYSBnaXZlbiBnZW5lLCBwcmVzdW1hYmx5IGJlY2F1c2Ugb2YgYSBtdWx0aS1nZW5lIGZhbWlseS4KCkxldHMgcHJvdmUgbXlzZWxmIHJpZ2h0IG9yIHdyb25nLi4uCgpgYGB7ciByZWRvLCBmaWcuc2hvdyA9ICJoaWRlIn0KaGlzYXRfZGUyIDwtIGFsbF9wYWlyd2lzZShoaXNhdCwgbW9kZWxfYmF0Y2ggPSBGQUxTRSwgZmlsdGVyID0gVFJVRSkKZHJhZ2VuX2RlMiA8LSBhbGxfcGFpcndpc2UoZHJhZ2VuLCBtb2RlbF9iYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKQpoaXNhdF90YWJsZTIgPC0gY29tYmluZV9kZV90YWJsZXMoaGlzYXRfZGUyKQpkcmFnZW5fdGFibGUyIDwtIGNvbWJpbmVfZGVfdGFibGVzKGRyYWdlbl9kZTIpCmBgYAoKYGBge3IgY29tcGFyZV9kZTJ9CmNvbXBhcmlzb24yIDwtIGNvbXBhcmVfZGVfcmVzdWx0cyhoaXNhdF90YWJsZTIsIGRyYWdlbl90YWJsZTIpCmNvbXBhcmlzb24yW1sibG9nZmMiXV0KdHQgPC0gbWVyZ2UoaGlzYXRfdGFibGUyW1siZGF0YSJdXVtbMV1dLCBkcmFnZW5fdGFibGUyW1siZGF0YSJdXVtbMV1dLCBieSA9ICJyb3cubmFtZXMiKQpjb3IudGVzdCh0dFssICJkZXNlcV9sb2dmYy54Il0sIHR0WywgImRlc2VxX2xvZ2ZjLnkiXSkKCmhtbTIgPC0gcGxvdF9saW5lYXJfc2NhdHRlcih0dFssIGMoImRlc2VxX2xvZ2ZjLngiLCAiZGVzZXFfbG9nZmMueSIpXSkKaG1tMiRzY2F0dGVyCmhtbTIkY29yCgpobW0yIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIodHRbLCBjKCJsaW1tYV9sb2dmYy54IiwgImxpbW1hX2xvZ2ZjLnkiKV0pCmhtbTIkc2NhdHRlcgpobW0yJGNvcgpgYGAKCmBgYHtyIGxvYWRtZV9hZnRlciwgZXZhbCA9IEZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=