1 Introduction

This document is intended to provide an overview of TMRC3 samples which have been sequenced. It includes some plots and analyses showing the relationships among the samples as well as some differential analyses when possible.

2 Annotation

We take the annotation data from ensembl’s biomart instance. The genome which was used to map the data was hg38 revision 100. My default when using biomart is to load the data from 1 year before the current date.

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  
##                    
##                    
##                    
## 
hs_go <- sm(load_biomart_go()[["go"]])
hs_length <- hs_annot[, c("ensembl_gene_id", "cds_length")]
colnames(hs_length) <- c("ID", "length")

3 Sample Estimation

3.1 Generate expressionsets

The sample sheet is copied from our shared online sheet and updated with each release of sequencing data.

samplesheet <- "sample_sheets/tmrc3_samples_20210512.xlsx"

3.1.1 Hisat2 expressionsets

The first thing to note is the large range in coverage. There are multiple samples with coverage which is too low to use. These will be removed shortly.

In the following block I immediately exclude any non-coding reads as well.

## Create the expressionset and immediately pass it to a filter
## removing the non protein coding genes.
hs_expt <- create_expt(samplesheet,
                       file_column = "hg38100hisatfile",
                       savefile = glue::glue("rda/hs_expt_all-v{ver}.rda"),
                       gene_info = hs_annot) %>%
  exclude_genes_expt(column = "gene_biotype", method = "keep", pattern = "protein_coding")
## Reading the sample metadata.
## Dropped 113 rows from the sample metadata because they were blank.
## The sample definitions comprises: 131 rows(samples) and 79 columns(metadata fields).
## Reading count tables.
## Reading count files with read.table().
## /fs01/cbcb-lab/nelsayed/scratch/atb/rnaseq/lpanamensis_tmrc_2019/preprocessing/TMRC30001/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows.
## preprocessing/TMRC30002/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30003/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30004/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30005/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30006/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30007/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30008/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30009/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30010/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30015/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30011/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30012/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30013/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30016/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30017/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30050/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30052/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30071/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30056/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30058/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30105/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30094/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30080/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30103/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30018/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30107/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30083/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30019/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30082/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30093/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/TMRC30096/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30014/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30021/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30029/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30020/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30038/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30039/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30023/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30025/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30022/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30046/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30047/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30048/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30026/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30030/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30031/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30032/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30024/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30040/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30033/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30049/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30053/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30054/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/TMRC30037/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30027/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30028/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30034/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30035/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30036/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30044/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30055/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30068/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30070/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30041/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30042/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30043/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30045/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30059/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30060/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30061/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30062/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30063/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30051/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30064/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30065/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30066/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30067/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30057/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30069/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.
## preprocessing/TMRC30074/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30072/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30076/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30077/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30078/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30088/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30079/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30097/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30075/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30085/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30086/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30087/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30101/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30089/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30090/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30081/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30092/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30104/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30106/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/TMRC30095/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30108/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30130/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30124/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30131/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30109/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30084/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30098/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30099/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30100/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 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/TMRC30102/outputs/hisat2_hg38_100/r1_trimmed.count_hg38_100_sno_gene_gene_id.count.xz contains 21486 rows and merges to 21486 rows.
## preprocessing/TMRC30091/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/TMRC30073/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.
## Warning in create_expt(samplesheet, file_column = "hg38100hisatfile", savefile =
## glue::glue("rda/hs_expt_all-v{ver}.rda"), : Some samples were removed when cross
## referencing the samples against the 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'.
## The final expressionset has 21481 rows and 119 columns.
## Before removal, there were 21481 genes, now there are 19941.
## There are 13 samples which kept less than 90 percent counts.
## TMRC30015 TMRC30017 TMRC30019 TMRC30044 TMRC30045 TMRC30097 TMRC30075 TMRC30087 
##     79.24     85.72     89.75     80.34     73.33     89.90     86.97     83.63 
## TMRC30101 TMRC30104 TMRC30114 TMRC30131 TMRC30073 
##     88.41     80.29     87.62     86.82     89.26

3.1.1.1 Initial metrics

Once the data was loaded, there are a couple of metrics which may be plotted immediately.

nonzero <- plot_nonzero(hs_expt)
nonzero$plot
## Warning: ggrepel: 89 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

Najib doesn’t want this plot, but I am using it to check new samples, so will hide it from general use.

libsize <- plot_libsize(hs_expt)
libsize$plot

3.2 Minimum coverage sample filtering

I arbitrarily chose 11,000 non-zero genes as a minimum. We may want this to be higher.

hs_valid <- subset_expt(hs_expt, nonzero = 11000)
## The samples (and read coverage) removed when filtering 11000 non-zero genes are:
## TMRC30010 TMRC30050 TMRC30052 
##     52471    808149   3087347
## There were 119, now there are 116 samples.
valid_write <- sm(write_expt(hs_valid, excel = glue("excel/hs_valid-v{ver}.xlsx")))

4 Project Aims

The project seeks to determine the relationship of the innate immune response and inflammatory signaling to the clinical outcome of antileishmanial drug treatment. We will test the hypothesis that the profile of innate immune cell activation and their dynamics through the course of treatment differ between CL patients with prospectively determined therapeutic cure or failure.

This will be achieved through the characterization of the in vivo dynamics of blood-derived monocyte, neutrophil and eosinophil transcriptome before, during and at the end of treatment in CL patients. Cell-type specific transcriptomes, composite signatures and time-response expression profiles will be contrasted among patients with therapeutic cure or failure.

4.1 Preparation

To address these, I added to the end of the sample sheet columns named ‘condition’, ‘batch’, ‘donor’, and ‘time’. These are filled in with shorthand values according to the above.

4.2 Global view

Before addressing the questions explicitly by subsetting the data, I want to get a look at the samples as they are.

hs_valid <- hs_valid %>%
  set_expt_batches(fact = "cellssource") %>%
  set_expt_conditions(fact = "typeofcells") %>%
  set_expt_samplenames(newnames = pData(hs_valid)[["samplename"]])

all_norm <- sm(normalize_expt(hs_valid, transform = "log2", norm = "quant",
                              convert = "cpm", filter = TRUE))

all_pca <- plot_pca(all_norm, plot_labels = FALSE, plot_title = "PCA - Cell type")
pp(file = glue("images/tmrc3_pca_nolabels-v{ver}.png"), image = all_pca$plot)

write.csv(all_pca$table, file = "coords/hs_donor_pca_coords.csv")
plot_corheat(all_norm, plot_title = "Heirarchical clustering - cell types")$plot

4.3 Examine samples relevant to clinical outcome

Now let us consider only the samples for which we have a clinical outcome. These fall primarily into either ‘cured’ or ‘failed’, but some people have not yet returned to the clinic after the first or second visit. These are deemed ‘lost’.

chosen_colors <- c("#D95F02", "#7570B3", "#1B9E77", "#FF0000")
names(chosen_colors) <- c("cure", "failure", "lost", "null")
newnames <- pData(hs_valid)[["samplename"]]

hs_clinical <- hs_valid %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "typeofcells") %>%
  set_expt_colors(colors = chosen_colors) %>%
  set_expt_samplenames(newnames = newnames) %>%
  subset_expt(subset = "typeofcells!='PBMCs'&typeofcells!='Macrophages'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'sampleNames': 'names' attribute [116] must be the same length as the vector [87]
hs_clinical_norm <- sm(normalize_expt(hs_clinical, filter = TRUE, transform = "log2",
                                      convert = "cpm", norm = "quant"))
## Error in normalize_expt(hs_clinical, filter = TRUE, transform = "log2", : object 'hs_clinical' not found
clinical_pca <- plot_pca(hs_clinical_norm, plot_labels = FALSE, cis = NULL,
                         plot_title = "PCA - clinical samples")
## Error in plot_pca(hs_clinical_norm, plot_labels = FALSE, cis = NULL, plot_title = "PCA - clinical samples"): object 'hs_clinical_norm' not found
pp(file = glue("images/all_clinical_nobatch_pca-v{ver}.png"), image = clinical_pca$plot,
   height = 8, width = 20)
## Error in pp(file = glue("images/all_clinical_nobatch_pca-v{ver}.png"), : object 'clinical_pca' not found

4.3.1 Repeat without the biopsy samples

hs_clinical_nobiop <- hs_clinical %>%
  subset_expt(subset = "typeofcells!='Biopsy'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'sampleNames': object 'hs_clinical' not found
hs_clinical_nobiop_norm <- sm(normalize_expt(hs_clinical_nobiop, filter = TRUE, transform = "log2",
                                             convert = "cpm", norm = "quant"))
## Error in normalize_expt(hs_clinical_nobiop, filter = TRUE, transform = "log2", : object 'hs_clinical_nobiop' not found
clinical_nobiop_pca <- plot_pca(hs_clinical_nobiop_norm, plot_labels = FALSE, cis = NULL,
                                plot_title = "PCA - clinical samples without biopsies")
## Error in plot_pca(hs_clinical_nobiop_norm, plot_labels = FALSE, cis = NULL, : object 'hs_clinical_nobiop_norm' not found
pp(file = glue("images/all_clinical_nobiop_nobatch_pca-v{ver}.png"),
   image = clinical_nobiop_pca$plot)
## Error in pp(file = glue("images/all_clinical_nobiop_nobatch_pca-v{ver}.png"), : object 'clinical_nobiop_pca' not found

4.3.2 Attempt to correct for the surrogate variables

At this time we have two primary data structures of interest: hs_clinical and hs_clinical_nobiop

hs_clinical_nb <- normalize_expt(hs_clinical, filter = TRUE, batch = "svaseq",
                                 transform = "log2", convert = "cpm")
## Error in normalize_expt(hs_clinical, filter = TRUE, batch = "svaseq", : object 'hs_clinical' not found
clinical_batch_pca <- plot_pca(hs_clinical_nb, plot_labels = FALSE, cis = NULL,
                               plot_title = "PCA - clinical samples")
## Error in plot_pca(hs_clinical_nb, plot_labels = FALSE, cis = NULL, plot_title = "PCA - clinical samples"): object 'hs_clinical_nb' not found
clinical_batch_pca$plot
## Error in eval(expr, envir, enclos): object 'clinical_batch_pca' not found
hs_clinical_nobiop_nb <- sm(normalize_expt(hs_clinical_nobiop, filter = TRUE, batch = "svaseq",
                                           transform = "log2", convert = "cpm"))
## Error in normalize_expt(hs_clinical_nobiop, filter = TRUE, batch = "svaseq", : object 'hs_clinical_nobiop' not found
clinical_nobiop_batch_pca <- plot_pca(hs_clinical_nobiop_nb,
                                      plot_title = "PCA - clinical samples without biopsies",
                                      plot_labels = FALSE)
## Error in plot_pca(hs_clinical_nobiop_nb, plot_title = "PCA - clinical samples without biopsies", : object 'hs_clinical_nobiop_nb' not found
pp(file = "images/clinical_batch.png", image = clinical_nobiop_batch_pca$plot)
## Error in pp(file = "images/clinical_batch.png", image = clinical_nobiop_batch_pca$plot): object 'clinical_nobiop_batch_pca' not found
clinical_nobiop_batch_tsne <- plot_tsne(hs_clinical_nobiop_nb,
                                        plot_title = "tSNE - clinical samples without biopsies",
                                        plot_labels = FALSE)
## Error in plot_pca(..., pc_method = "tsne"): object 'hs_clinical_nobiop_nb' not found
clinical_nobiop_batch_tsne$plot
## Error in eval(expr, envir, enclos): object 'clinical_nobiop_batch_tsne' not found
test <- simple_varpart(hs_clinical_nobiop)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'pData': object 'hs_clinical_nobiop' not found
test$partition_plot
## Error in eval(expr, envir, enclos): object 'test' not found

4.4 Perform DE of the clinical samples cure vs. fail

individual_celltypes <- subset_expt(hs_clinical_nobiop, subset="condition!='lost'")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'sampleNames': object 'hs_clinical_nobiop' not found
hs_clinic_de <- sm(all_pairwise(individual_celltypes, model_batch = "svaseq", filter = TRUE))
## Error in normalize_expt(input, filter = filter): object 'individual_celltypes' not found
hs_clinic_table <- sm(combine_de_tables(
    hs_clinic_de,
    excel = glue::glue("excel/individual_celltypes_table-v{ver}.xlsx")))
## Error in combine_de_tables(hs_clinic_de, excel = glue::glue("excel/individual_celltypes_table-v{ver}.xlsx")): object 'hs_clinic_de' not found
hs_clinic_sig <- sm(extract_significant_genes(
    hs_clinic_table,
    excel = glue::glue("excel/individual_celltypes_sig-v{ver}.xlsx")))
## Error in extract_significant_genes(hs_clinic_table, excel = glue::glue("excel/individual_celltypes_sig-v{ver}.xlsx")): object 'hs_clinic_table' not found
hs_clinic_sig[["summary_df"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_sig' not found

4.4.1 Look at only the differential genes

A good suggestion from Theresa was to examine only the most variant genes from failure vs. cure and see how they change the clustering/etc results. This is my attempt to address this query.

hs_clinic_topn <- sm(extract_significant_genes(hs_clinic_table, n = 100))
## Error in extract_significant_genes(hs_clinic_table, n = 100): object 'hs_clinic_table' not found
table <- "failure_vs_cure"
wanted <- rbind(hs_clinic_topn[["deseq"]][["ups"]][[table]],
                hs_clinic_topn[["deseq"]][["downs"]][[table]])
## Error in eval(quote(list(...)), env): object 'hs_clinic_topn' not found
small_expt <- exclude_genes_expt(hs_clinical_nobiop, ids = rownames(wanted), method = "keep")
## Error in exclude_genes_expt(hs_clinical_nobiop, ids = rownames(wanted), : object 'hs_clinical_nobiop' not found
small_norm <- sm(normalize_expt(small_expt, transform = "log2", convert = "cpm",
                                norm = "quant", filter = TRUE))
## Error in normalize_expt(small_expt, transform = "log2", convert = "cpm", : object 'small_expt' not found
plot_pca(small_norm)$plot
## Error in plot_pca(small_norm): object 'small_norm' not found
small_nb <- normalize_expt(small_expt, transform = "log2", convert = "cpm",
                           batch = "svaseq", norm = "quant", filter = TRUE)
## Error in normalize_expt(small_expt, transform = "log2", convert = "cpm", : object 'small_expt' not found
plot_pca(small_nb)$plot
## Error in plot_pca(small_nb): object 'small_nb' not found
## DESeq2 MA plot of failure / cure
hs_clinic_table[["plots"]][["failure_vs_cure"]][["deseq_ma_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'hs_clinic_table' not found
## DESeq2 Volcano plot of failure / cure
hs_clinic_table[["plots"]][["failure_vs_cure"]][["deseq_vol_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'hs_clinic_table' not found

4.4.2 g:Profiler results using the significant up and down genes

ups <- hs_clinic_sig[["deseq"]][["ups"]][[1]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_sig' not found
downs <- hs_clinic_sig[["deseq"]][["downs"]][[1]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_sig' not found
hs_clinic_gprofiler_ups <- simple_gprofiler(ups)
## Error in simple_gprofiler(ups): object 'ups' not found
hs_clinic_gprofiler_ups[["pvalue_plots"]][["bpp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_gprofiler_ups' not found
hs_clinic_gprofiler_ups[["pvalue_plots"]][["mfp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_gprofiler_ups' not found
hs_clinic_gprofiler_ups[["pvalue_plots"]][["reactome_plot_over"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_gprofiler_ups' not found
##hs_try2 <- simple_gprofiler2(ups)

hs_clinic_gprofiler_downs <- simple_gprofiler(downs)
## Error in simple_gprofiler(downs): object 'downs' not found
hs_clinic_gprofiler_downs[["pvalue_plots"]][["bpp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_gprofiler_downs' not found
hs_clinic_gprofiler_downs[["pvalue_plots"]][["mfp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_gprofiler_downs' not found
hs_clinic_gprofiler_downs[["pvalue_plots"]][["reactome_plot_over"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_gprofiler_downs' not found

4.5 Perform GSVA on the clinical samples

hs_celltype_gsva_c2 <- sm(simple_gsva(individual_celltypes))
## Error in simple_gsva(individual_celltypes): object 'individual_celltypes' not found
hs_celltype_gsva_c2_sig <- sm(get_sig_gsva_categories(
    hs_celltype_gsva_c2,
    excel = "excel/individual_celltypes_gsva_c2.xlsx"))
## Error in get_sig_gsva_categories(hs_celltype_gsva_c2, excel = "excel/individual_celltypes_gsva_c2.xlsx"): object 'hs_celltype_gsva_c2' not found
broad_c7 <- GSEABase::getGmt("reference/msigdb/c7.all.v7.2.entrez.gmt",
                             collectionType = GSEABase::BroadCollection(category = "c7"),
                             geneIdType = GSEABase::EntrezIdentifier())
hs_celltype_gsva_c7 <- sm(simple_gsva(individual_celltypes, signatures = broad_c7,
                                      msig_xml = "reference/msigdb_v7.2.xml", cores = 10))
## Error in simple_gsva(individual_celltypes, signatures = broad_c7, msig_xml = "reference/msigdb_v7.2.xml", : object 'individual_celltypes' not found
hs_celltype_gsva_c7_sig <- sm(get_sig_gsva_categories(
    hs_celltype_gsva_c7,
    excel = "excel/individual_celltypes_gsva_c7.xlsx"))
## Error in get_sig_gsva_categories(hs_celltype_gsva_c7, excel = "excel/individual_celltypes_gsva_c7.xlsx"): object 'hs_celltype_gsva_c7' not found

5 Individual Cell types

The following blocks split the samples into a few groups by sample type and look at the distributions between them.

5.1 Implementation details

Get top/bottom n genes for each cell type, using clinical outcome as the factor of interest. For the moment, use sva for the DE analysis. Provide cpms for the top/bottom n genes.

Start with top/bottom 200. Perform default logFC and p-value as well.

5.1.1 Shared contrasts

Here is the contrast we will use throughput, I am leaving open the option to add more.

keepers <- list(
  "fail_vs_cure" = c("failure", "cure"))

5.2 Monocytes

5.2.1 Evaluate Monocyte samples

mono <- subset_expt(hs_valid, subset = "typeofcells=='Monocytes'") %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "donor") %>%
  set_expt_colors(colors = chosen_colors)
## There were 116, now there are 22 samples.
## FIXME set_expt_colors should speak up if there are mismatches here!!!

save_result <- save(mono, file = "rda/monocyte_expt.rda")
mono_norm <- normalize_expt(mono, convert = "cpm", filter = TRUE,
                            transform = "log2", norm = "quant")
## Removing 8966 low-count genes (10975 remaining).
## transform_counts: Found 9 values equal to 0, adding 1 to the matrix.
plt <- plot_pca(mono_norm, plot_labels = FALSE)$plot
pp(file = glue("images/mono_pca_normalized-v{ver}.pdf"), image = plt)

mono_nb <- normalize_expt(mono, convert = "cpm", filter = TRUE,
                          transform = "log2", batch = "svaseq")
## Removing 8966 low-count genes (10975 remaining).
## batch_counts: Before batch/surrogate estimation, 1202 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 13643 entries are 0<x<1: 6%.
## Setting 382 low elements to zero.
## transform_counts: Found 382 values equal to 0, adding 1 to the matrix.
plt <- plot_pca(mono_nb, plot_labels = FALSE)$plot
pp(file = glue("images/mono_pca_normalized_batch-v{ver}.pdf"), image = plt)

5.2.2 DE of Monocyte samples

5.2.2.1 Without sva

mono_de <- sm(all_pairwise(mono, model_batch = FALSE, filter = TRUE))
mono_tables <- sm(combine_de_tables(
    mono_de, keepers = keepers,
    excel = glue::glue("excel/monocyte_clinical_all_tables-v{ver}.xlsx")))
written <- write_xlsx(data = mono_tables[["data"]][[1]],
                      excel = glue::glue("excel/monocyte_clinical_table-v{ver}.xlsx"))
mono_sig <- sm(extract_significant_genes(mono_tables, according_to = "deseq"))
written <- write_xlsx(data = mono_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/monocyte_clinical_sigup-v{ver}.xlsx"))
written <- write_xlsx(data = mono_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/monocyte_clinical_sigdown-v{ver}.xlsx"))

mono_pct_sig <- sm(extract_significant_genes(mono_tables, n = 200,
                                             lfc = NULL, p = NULL, according_to = "deseq"))
written <- write_xlsx(data = mono_pct_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/monocyte_clinical_sigup_pct-v{ver}.xlsx"))
written <- write_xlsx(data = mono_pct_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/monocyte_clinical_sigdown_pct-v{ver}.xlsx"))
mono_sig$summary_df
## data frame with 0 columns and 1 row
## Print out a table of the cpm values for other explorations.
mono_cpm <- sm(normalize_expt(mono, convert = "cpm"))
written <- write_xlsx(data = exprs(mono_cpm),
                      excel = glue::glue("excel/monocyte_cpm_before_batch-v{ver}.xlsx"))
mono_bcpm <- sm(normalize_expt(mono, filter = TRUE, convert = "cpm", batch = "svaseq"))
written <- write_xlsx(data = exprs(mono_bcpm),
                      excel = glue::glue("excel/monocyte_cpm_after_batch-v{ver}.xlsx"))

5.2.2.2 With sva

mono_de_sva <- sm(all_pairwise(mono, model_batch = "svaseq", filter = TRUE))
mono_tables_sva <- sm(combine_de_tables(
    mono_de_sva, keepers = keepers,
    excel = glue::glue("excel/monocyte_clinical_all_tables_sva-v{ver}.xlsx")))
mono_sig_sva <- sm(extract_significant_genes(
    mono_tables_sva,
    excel = glue::glue("excel/monocyte_clinical_sig_tables_sva-v{ver}.xlsx"),
    according_to = "deseq"))

5.2.2.3 Monocyte DE plots

First print out the DE plots without and then with sva estimates.

## DESeq2 MA plot of failure / cure
mono_tables[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure
mono_tables[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot

## DESeq2 MA plot of failure / cure with svaseq
mono_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure with svaseq
mono_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot

5.2.2.5 Monocyte MSigDB query

broad_c7 <- GSEABase::getGmt("reference/msigdb/c7.all.v7.2.entrez.gmt",
                             collectionType = GSEABase::BroadCollection(category = "c7"),
                             geneIdType = GSEABase::EntrezIdentifier())

mono_up_goseq_msig <- goseq_msigdb(sig_genes = ups, signatures = broad_c7,
                                   signature_category = "c7", length_db = hs_length)
## Before conversion: 150, after conversion: 151.
## Warning: non-unique value when setting 'row.names': '51326'
## Error in `.rowNamesDF<-`(x, value = value): duplicate 'row.names' are not allowed
mono_down_goseq_msig <- goseq_msigdb(sig_genes = downs, signatures = broad_c7,
                                     signature_category = "c7", length_db = hs_length)
## Before conversion: 296, after conversion: 293.
## Before conversion: 227921, after conversion: 35341.
## Found 281 go_db genes and 293 length_db genes out of 293.

5.2.2.6 Plot of similar experiments

## Monocyte genes with increased expression in the failed samples
## share genes with the following experiments
mono_up_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'mono_up_goseq_msig' not found
## Monocyte genes with increased expression in the cured samples
## share genes with the following experiments
mono_down_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]

5.2.3 Evaluate Neutrophil samples

neut <- subset_expt(hs_valid, subset = "typeofcells=='Neutrophils'") %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "donor") %>%
  set_expt_colors(colors = chosen_colors)
## There were 116, now there are 21 samples.
save_result <- save(neut, file = "rda/neutrophil_expt.rda")
neut_norm <- sm(normalize_expt(neut, convert = "cpm", filter = TRUE, transform = "log2"))
plt <- plot_pca(neut_norm, plot_labels = FALSE)$plot
pp(file = glue("images/neut_pca_normalized-v{ver}.pdf"), image = plt)

neut_nb <- sm(normalize_expt(neut, convert = "cpm", filter = TRUE,
                             transform = "log2", batch = "svaseq"))
plt <- plot_pca(neut_nb, plot_labels = FALSE)$plot
pp(file = glue("images/neut_pca_normalized_svaseq-v{ver}.pdf"), image = plt)

5.2.4 DE of Netrophil samples

5.2.4.1 Without sva

neut_de <- sm(all_pairwise(neut, model_batch = FALSE, filter = TRUE))
neut_tables <- sm(combine_de_tables(
    neut_de, keepers = keepers,
    excel = glue::glue("excel/neutrophil_clinical_all_tables-v{ver}.xlsx")))
written <- write_xlsx(data = neut_tables[["data"]][[1]],
                      excel = glue::glue("excel/neutrophil_clinical_table-v{ver}.xlsx"))
neut_sig <- sm(extract_significant_genes(neut_tables, according_to = "deseq"))
written <- write_xlsx(data = neut_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/neutrophil_clinical_sigup-v{ver}.xlsx"))
written <- write_xlsx(data = neut_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/neutrophil_clinical_sigdown-v{ver}.xlsx"))

neut_pct_sig <- sm(extract_significant_genes(neut_tables, n = 200, lfc = NULL,
                                             p = NULL, according_to = "deseq"))
written <- write_xlsx(data = neut_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/neutrophil_clinical_sigup_pct-v{ver}.xlsx"))
written <- write_xlsx(data = neut_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/neutrophil_clinical_sigdown_pct-v{ver}.xlsx"))
neut_cpm <- sm(normalize_expt(neut, convert = "cpm"))
written <- write_xlsx(data = exprs(neut_cpm),
                      excel = glue::glue("excel/neutrophil_cpm_before_batch-v{ver}.xlsx"))
neut_bcpm <- sm(normalize_expt(neut, filter = TRUE, batch = "svaseq", convert = "cpm"))
written <- write_xlsx(data = exprs(neut_bcpm),
                      excel = glue::glue("excel/neutrophil_cpm_after_batch-v{ver}.xlsx"))

5.2.4.2 With sva

neut_de_sva <- sm(all_pairwise(neut, model_batch = "svaseq", filter = TRUE))
neut_tables_sva <- sm(combine_de_tables(
    neut_de_sva, keepers = keepers,
    excel = glue::glue("excel/neutrophil_clinical_all_tables_sva-v{ver}.xlsx")))
neut_sig_sva <- sm(extract_significant_genes(
    neut_tables_sva,
    excel = glue::glue("excel/neutrophil_clinical_sig_tables_sva-v{ver}.xlsx"),
    according_to = "deseq"))

5.2.4.3 Neutrophil DE plots

## DESeq2 MA plot of failure / cure
neut_tables[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure
neut_tables[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot

## DESeq2 MA plot of failure / cure with sva
neut_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure with sva
neut_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot

5.2.4.5 Neutrophil GSVA query

neut_up_goseq_msig <- goseq_msigdb(sig_genes = ups, signatures = broad_c7,
                                   signature_category = "c7", length_db = hs_length)
## Before conversion: 337, after conversion: 332.
## Before conversion: 227921, after conversion: 35341.
## Found 315 go_db genes and 332 length_db genes out of 332.
neut_down_goseq_msig <- goseq_msigdb(sig_genes = downs, signatures = broad_c7,
                                     signature_category = "c7", length_db = hs_length)
## Before conversion: 296, after conversion: 289.
## Before conversion: 227921, after conversion: 35341.
## Found 282 go_db genes and 289 length_db genes out of 289.

5.2.4.6 Plot of similar experiments

## Neutrophil genes with increased expression in the failed samples
## share genes with the following experiments
neut_up_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]

## Neutrophil genes with increased expression in the cured samples
## share genes with the following experiments
neut_down_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]

5.3 Eosinophils

5.3.1 Evaluate Eosinophil samples

eo <- subset_expt(hs_valid, subset = "typeofcells=='Eosinophils'") %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "donor") %>%
  set_expt_colors(colors = chosen_colors)
## There were 116, now there are 15 samples.
save_result <- save(eo, file = "rda/eosinophil_expt.rda")
eo_norm <- sm(normalize_expt(eo, convert = "cpm", transform = "log2",
                             norm = "quant", filter = TRUE))
plt <- plot_pca(eo_norm, plot_labels = FALSE)$plot
pp(file = glue("images/eo_pca_normalized-v{ver}.pdf"), image = plt)

eo_nb <- sm(normalize_expt(eo, convert = "cpm", transform = "log2",
                           filter = TRUE, batch = "svaseq"))
plot_pca(eo_nb)$plot

5.3.2 DE of Eosinophil samples

5.3.2.1 Withouth sva

eo_de <- sm(all_pairwise(eo, model_batch = FALSE, filter = TRUE))
eo_tables <- sm(combine_de_tables(
    eo_de, keepers = keepers,
    excel = glue::glue("excel/eosinophil_clinical_all_tables-v{ver}.xlsx")))
written <- write_xlsx(data = eo_tables[["data"]][[1]],
                      excel = glue::glue("excel/eosinophil_clinical_table-v{ver}.xlsx"))
eo_sig <- sm(extract_significant_genes(eo_tables, according_to = "deseq"))
written <- write_xlsx(data = eo_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/eosinophil_clinical_sigup-v{ver}.xlsx"))
written <- write_xlsx(data = eo_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/eosinophil_clinical_sigdown-v{ver}.xlsx"))

eo_pct_sig <- sm(extract_significant_genes(eo_tables, n = 200,
                                           lfc = NULL, p = NULL, according_to = "deseq"))
written <- write_xlsx(data = eo_pct_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/eosinophil_clinical_sigup_pct-v{ver}.xlsx"))
written <- write_xlsx(data = eo_pct_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/eosinophil_clinical_sigdown_pct-v{ver}.xlsx"))

eo_cpm <- sm(normalize_expt(eo, convert = "cpm"))
written <- write_xlsx(data = exprs(eo_cpm),
                      excel = glue::glue("excel/eosinophil_cpm_before_batch-v{ver}.xlsx"))
eo_bcpm <- sm(normalize_expt(eo, filter = TRUE, batch = "svaseq", convert = "cpm"))
written <- write_xlsx(data = exprs(eo_bcpm),
                      excel = glue::glue("excel/eosinophil_cpm_after_batch-v{ver}.xlsx"))

5.3.2.2 With sva

eo_de_sva <- sm(all_pairwise(eo, model_batch = "svaseq", filter = TRUE))
eo_tables_sva <- sm(combine_de_tables(
    eo_de_sva, keepers = keepers,
    excel = glue::glue("excel/eosinophil_clinical_all_tables_sva-v{ver}.xlsx")))
eo_sig_sva <- sm(extract_significant_genes(
    eo_tables_sva,
    excel = glue::glue("excel/eosinophil_clinical_sig_tables_sva-v{ver}.xlsx"),
    according_to = "deseq"))

5.3.2.3 Eosinophil DE plots

## DESeq2 MA plot of failure / cure
eo_tables[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure
eo_tables[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot

## DESeq2 MA plot of failure / cure with sva
eo_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure with sva
eo_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot

5.3.2.5 Eosinophil MSigDB query

eo_up_goseq_msig <- goseq_msigdb(sig_genes = ups, signatures = broad_c7,
                                 signature_category = "c7", length_db = hs_length)
## Before conversion: 240, after conversion: 237.
## Before conversion: 227921, after conversion: 35341.
## Found 222 go_db genes and 237 length_db genes out of 237.
eo_down_goseq_msig <- goseq_msigdb(sig_genes = downs, signatures = broad_c7,
                                   signature_category = "c7", length_db = hs_length)
## Before conversion: 208, after conversion: 207.
## Before conversion: 227921, after conversion: 35341.
## Found 196 go_db genes and 207 length_db genes out of 207.

5.3.2.6 Plot of similar experiments

## Eosinophil genes with increased expression in the failed samples
## share genes with the following experiments
eo_up_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]

## Eosinophil genes with increased expression in the cured samples
## share genes with the following experiments
eo_down_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]

5.4 Biopsies

5.4.1 Evaluate Biopsy samples

biop <- subset_expt(hs_valid, subset = "typeofcells=='Biopsy'") %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "donor") %>%
  set_expt_colors(colors = chosen_colors)
## There were 116, now there are 40 samples.
save_result <- save(biop, file = "rda/biopsy_expt.rda")
biop_norm <- normalize_expt(biop, filter = TRUE, convert = "cpm",
                            transform = "log2", norm = "quant")
## Removing 5816 low-count genes (14125 remaining).
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.
plt <- plot_pca(biop_norm, plot_labels = FALSE)$plot
## Error in data.frame(sampleid = as.character(design[["sampleid"]]), condition = design[[cond_column]], : arguments imply differing number of rows: 40, 11
pp(file = glue("images/biop_pca_normalized-v{ver}.pdf"), image = plt)

biop_nb <- sm(normalize_expt(biop, convert = "cpm", filter = TRUE,
                             transform = "log2", batch = "svaseq"))
plt <- plot_pca(biop_nb, plot_labels = FALSE)$plot
## Error in data.frame(sampleid = as.character(design[["sampleid"]]), condition = design[[cond_column]], : arguments imply differing number of rows: 40, 11
pp(file = glue("images/biop_pca_normalized_svaseq-v{ver}.pdf"), image = plt)

5.4.2 DE of Biopsy samples

5.4.2.1 Without sva

biop_de <- sm(all_pairwise(biop, model_batch = FALSE, filter = TRUE))
## Error in data.frame(sampleid = as.character(design[["sampleid"]]), condition = design[[cond_column]], : arguments imply differing number of rows: 40, 11
biop_tables <- combine_de_tables(biop_de, keepers = keepers,
                                 excel = glue::glue("excel/biopsy_clinical_all_tables-v{ver}.xlsx"))
## Deleting the file excel/biopsy_clinical_all_tables-v202104.xlsx before writing the tables.
## Error in combine_de_tables(biop_de, keepers = keepers, excel = glue::glue("excel/biopsy_clinical_all_tables-v{ver}.xlsx")): object 'biop_de' not found
written <- write_xlsx(data = biop_tables[["data"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_table-v{ver}.xlsx"))
## Error in write_xlsx(data = biop_tables[["data"]][[1]], excel = glue::glue("excel/biopsy_clinical_table-v{ver}.xlsx")): object 'biop_tables' not found
biop_sig <- extract_significant_genes(biop_tables, according_to = "deseq")
## Error in extract_significant_genes(biop_tables, according_to = "deseq"): object 'biop_tables' not found
##written <- write_xlsx(data = biop_sig[["deseq"]][["ups"]][[1]],
##                      excel = glue::glue("excel/biopsy_clinical_sigup-v{ver}.xlsx"))
written <- write_xlsx(data = biop_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_sigdown-v{ver}.xlsx"))
## Error in write_xlsx(data = biop_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/biopsy_clinical_sigdown-v{ver}.xlsx")): object 'biop_sig' not found
biop_pct_sig <- extract_significant_genes(biop_tables, n = 200, lfc = NULL, p = NULL, according_to = "deseq")
## Error in extract_significant_genes(biop_tables, n = 200, lfc = NULL, p = NULL, : object 'biop_tables' not found
written <- write_xlsx(data = biop_pct_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_sigup_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = biop_pct_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/biopsy_clinical_sigup_pct-v{ver}.xlsx")): object 'biop_pct_sig' not found
written <- write_xlsx(data = biop_pct_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_sigdown_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = biop_pct_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/biopsy_clinical_sigdown_pct-v{ver}.xlsx")): object 'biop_pct_sig' not found
biop_cpm <- sm(normalize_expt(biop, convert = "cpm"))
written <- write_xlsx(data = exprs(biop_cpm),
                      excel = glue::glue("excel/biopsy_cpm_before_batch-v{ver}.xlsx"))
biop_bcpm <- sm(normalize_expt(biop, filter = TRUE, batch = "svaseq", convert = "cpm"))
written <- write_xlsx(data = exprs(biop_bcpm),
                      excel = glue::glue("excel/biopsy_cpm_after_batch-v{ver}.xlsx"))

5.4.2.2 with sva

biop_de_sva <- sm(all_pairwise(biop, model_batch = "svaseq", filter = TRUE))
## Error in data.frame(sample = samples, factor = as.integer(as.factor(expt[["design"]][[batch_column]])), : arguments imply differing number of rows: 40, 11, 1
biop_tables_sva <- sm(combine_de_tables(
    biop_de_sva, keepers = keepers,
    excel = glue::glue("excel/biopsy_clinical_all_tables_sva-v{ver}.xlsx")))
## Error in combine_de_tables(biop_de_sva, keepers = keepers, excel = glue::glue("excel/biopsy_clinical_all_tables_sva-v{ver}.xlsx")): object 'biop_de_sva' not found
biop_sig_sva <- sm(extract_significant_genes(
    biop_tables_sva,
    excel = glue::glue("excel/biopsy_clinical_sig_tables_sva-v{ver}.xlsx"),
    according_to = "deseq"))
## Error in extract_significant_genes(biop_tables_sva, excel = glue::glue("excel/biopsy_clinical_sig_tables_sva-v{ver}.xlsx"), : object 'biop_tables_sva' not found

5.4.2.3 Biopsy DE plots

## DESeq2 MA plot of failure / cure
biop_tables[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'biop_tables' not found
## DESeq2 Volcano plot of failure / cure
biop_tables[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'biop_tables' not found
## DESeq2 MA plot of failure / cure
biop_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'biop_tables_sva' not found
## DESeq2 Volcano plot of failure / cure
biop_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'biop_tables_sva' not found

6 Monocytes by visit

  1. Can you please share with us a PCA (SVA and non-SVA) of the monocytes of the TMRC3 project, but labeling them based on the visit (V1, V2, V3)?
  2. Can you please share DE lists of V1 vs V2, V1 vs V3, V1 vs. V2+V3 and V2 vs V3?
visit_colors <- chosen_colors <- c("#D95F02", "#7570B3", "#1B9E77")
names(visit_colors) <- c(1, 2, 3)
mono_visit <- subset_expt(hs_valid, subset = "typeofcells=='Monocytes'") %>%
  set_expt_conditions(fact = "visitnumber") %>%
  set_expt_batches(fact = "clinicaloutcome") %>%
  set_expt_colors(colors = chosen_colors)
## There were 116, now there are 22 samples.
mono_visit_norm <- normalize_expt(mono_visit, filter = TRUE, norm = "quant", convert = "cpm",
                                  transform = "log2")
## Removing 8966 low-count genes (10975 remaining).
## transform_counts: Found 9 values equal to 0, adding 1 to the matrix.
mono_visit_pca <- plot_pca(mono_visit_norm)
## Potentially check over the experimental design, there appear to be missing values.
## Warning in plot_pca(mono_visit_norm): There are NA values in the component data.
## This can lead to weird plotting errors.
pp(file = "images/monocyte_by_visit.png", image = mono_visit_pca$plot)
## Warning: Removed 1 rows containing missing values (geom_point).
## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

mono_visit_nb <- normalize_expt(mono_visit, filter = TRUE, convert = "cpm",
                                batch = "svaseq", transform = "log2")
## Removing 8966 low-count genes (10975 remaining).
## batch_counts: Before batch/surrogate estimation, 1202 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 13643 entries are 0<x<1: 6%.
## Setting 333 low elements to zero.
## transform_counts: Found 333 values equal to 0, adding 1 to the matrix.
mono_visit_nb_pca <- plot_pca(mono_visit_nb)
## Potentially check over the experimental design, there appear to be missing values.
## Warning in plot_pca(mono_visit_nb): There are NA values in the component data.
## This can lead to weird plotting errors.
pp(file = "images/monocyte_by_visit_nb.png", image = mono_visit_nb_pca$plot)
## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

table(pData(mono_visit_norm)$batch)
## 
##    cure failure    lost 
##       6      10       5
keepers <- list(
    "second_vs_first" = c("c2", "c1"),
    "third_vs_second" = c("c3", "c2"),
    "third_vs_first" = c("c3", "c1"))
mono_visit_de <- all_pairwise(mono_visit, model_batch = "svaseq", filter = TRUE)
## batch_counts: Before batch/surrogate estimation, 1202 entries are x==0: 0%.
## Plotting a PCA before surrogate/batch inclusion.
## Potentially check over the experimental design, there appear to be missing values.
## Warning in plot_pca(pre_batch, plot_labels = FALSE, ...): There are NA values in
## the component data. This can lead to weird plotting errors.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## Removing 0 low-count genes (10975 remaining).
## batch_counts: Before batch/surrogate estimation, 1202 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 13643 entries are 0<x<1: 6%.
## Setting 333 low elements to zero.
## transform_counts: Found 333 values equal to 0, adding 1 to the matrix.
## Potentially check over the experimental design, there appear to be missing values.
## Warning in plot_pca(post_batch, plot_labels = FALSE, ...): There are NA values
## in the component data. This can lead to weird plotting errors.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
mono_visit_tables <- combine_de_tables(
    mono_visit_de,
    keepers = keepers,
    excel = glue::glue("excel/mono_visit_tables-v{ver}.xlsx"))
## Deleting the file excel/mono_visit_tables-v202104.xlsx before writing the tables.
## Warning: Removed 1 rows containing missing values (geom_point).
## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).
new_factor <- pData(mono_visit)[["condition"]]
not_one_idx <- new_factor != 1
new_factor[not_one_idx] <- "not_1"
mono_one_vs <- set_expt_conditions(mono_visit, new_factor)

mono_one_vs_de <- all_pairwise(mono_one_vs, model_batch = "svaseq", filter = TRUE)
## batch_counts: Before batch/surrogate estimation, 1202 entries are x==0: 0%.
## Plotting a PCA before surrogate/batch inclusion.
## Potentially check over the experimental design, there appear to be missing values.
## Warning in plot_pca(pre_batch, plot_labels = FALSE, ...): There are NA values in
## the component data. This can lead to weird plotting errors.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## Removing 0 low-count genes (10975 remaining).
## batch_counts: Before batch/surrogate estimation, 1202 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 13643 entries are 0<x<1: 6%.
## Setting 333 low elements to zero.
## transform_counts: Found 333 values equal to 0, adding 1 to the matrix.
## Potentially check over the experimental design, there appear to be missing values.
## Warning in plot_pca(post_batch, plot_labels = FALSE, ...): There are NA values
## in the component data. This can lead to weird plotting errors.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
mono_one_vs_tables <- combine_de_tables(
    mono_one_vs_de,
    excel = glue::glue("excel/mono_one_vs_tables-v{ver}.xlsx"))
## Deleting the file excel/mono_one_vs_tables-v202104.xlsx before writing the tables.
## Warning: Removed 1 rows containing missing values (geom_point).
## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

## Warning: Removed 1 rows containing missing values (geom_point).

7 Test TSP

In writing the following, I quickly realized that tspair was not joking when it said it is intended for small numbers of genes. For a full expressionset of human data it is struggling. I like the idea, it may prove worth while to spend some time optimizing the package so that it is more usable.

expt <- hs_clinical_nobiop

simple_tsp <- function(expt, column = "condition") {
  facts <- levels(as.factor(pData(expt)[[column]]))
  retlist <- list()
  if (length(facts) < 2) {
    stop("This requires factors with at least 2 levels.")
  } else if (length(facts) == 2) {
    retlist <- simple_tsp_pair(expt, column = column)
  } else {
    for (first in 1:(length(facts) - 1)) {
      for (second in 2:(length(facts))) {
        if (first < second) {
          name <- glue::glue("{facts[first]}_vs_{facts[second]}")
          message("Starting ", name, ".")
          substring <- glue::glue("{column}=='{facts[first]}'|{column}=='{facts[second]}'")
          subby <- subset_expt(expt, subset=as.character(substring))
          retlist[[name]] <- simple_tsp_pair(subby, column = column)
        }
      }
    }
  }
}

simple_tsp_pair <- function(subby, column = "condition", repetitions = 50) {
  tsp_input <- subby[["expressionset"]]
  tsp_output <- tspcalc(tsp_input, column)
  tsp_scores <- tspsig(tsp_input, column, B = repetitions)
}

tsp1 <- tspcalc(tsp_input, "condition")
if (!isTRUE(get0("skip_load"))) {
  pander::pander(sessionInfo())
  message(paste0("This is hpgltools commit: ", get_git_commit()))
  message(paste0("Saving to ", savefile))
  tmp <- sm(saveme(filename = savefile))
}
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 53433f808ad055552025c90161db331405085a9e
## This is hpgltools commit: Tue May 4 12:44:03 2021 -0400: 53433f808ad055552025c90161db331405085a9e
## Saving to tmrc3_02sample_estimation_v202104.rda.xz
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzMgQ29tcHJlaGVuc2l2ZSBEYXRhIEFuYWx5c2lzOiAyMDIxMDQiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICBjb2xsYXBzZWQ6IGZhbHNlCiAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAxMjAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3IgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICBkcGkgPSA5NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjEwNCIKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gIiVZJW0lZCIpCgpybWRfZmlsZSA8LSBnbHVlOjpnbHVlKCJ0bXJjM18wMnNhbXBsZV9lc3RpbWF0aW9uX3Z7dmVyfS5SbWQiKQpzYXZlZmlsZSA8LSBnc3ViKHBhdHRlcm4gPSAiXFwuUm1kIiwgcmVwbGFjZSA9ICJcXC5yZGFcXC54eiIsIHggPSBybWRfZmlsZSkKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyBkb2N1bWVudCBpcyBpbnRlbmRlZCB0byBwcm92aWRlIGFuIG92ZXJ2aWV3IG9mIFRNUkMzIHNhbXBsZXMgd2hpY2ggaGF2ZQpiZWVuIHNlcXVlbmNlZC4gIEl0IGluY2x1ZGVzIHNvbWUgcGxvdHMgYW5kIGFuYWx5c2VzIHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcHMKYW1vbmcgdGhlIHNhbXBsZXMgYXMgd2VsbCBhcyBzb21lIGRpZmZlcmVudGlhbCBhbmFseXNlcyB3aGVuIHBvc3NpYmxlLgoKIyBBbm5vdGF0aW9uCgpXZSB0YWtlIHRoZSBhbm5vdGF0aW9uIGRhdGEgZnJvbSBlbnNlbWJsJ3MgYmlvbWFydCBpbnN0YW5jZS4gIFRoZSBnZW5vbWUgd2hpY2gKd2FzIHVzZWQgdG8gbWFwIHRoZSBkYXRhIHdhcyBoZzM4IHJldmlzaW9uIDEwMC4gIE15IGRlZmF1bHQgd2hlbiB1c2luZyBiaW9tYXJ0IGlzCnRvIGxvYWQgdGhlIGRhdGEgZnJvbSAxIHllYXIgYmVmb3JlIHRoZSBjdXJyZW50IGRhdGUuCgpgYGB7ciBoc19hbm5vdH0KaHNfYW5ub3QgPC0gc20obG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHllYXIgPSAiMjAyMCIpKQpoc19hbm5vdCA8LSBoc19hbm5vdFtbImFubm90YXRpb24iXV0KaHNfYW5ub3RbWyJ0cmFuc2NyaXB0Il1dIDwtIHBhc3RlMChyb3duYW1lcyhoc19hbm5vdCksICIuIiwgaHNfYW5ub3RbWyJ2ZXJzaW9uIl1dKQpyb3duYW1lcyhoc19hbm5vdCkgPC0gbWFrZS5uYW1lcyhoc19hbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSwgdW5pcXVlID0gVFJVRSkKdHhfZ2VuZV9tYXAgPC0gaHNfYW5ub3RbLCBjKCJ0cmFuc2NyaXB0IiwgImVuc2VtYmxfZ2VuZV9pZCIpXQoKc3VtbWFyeShoc19hbm5vdCkKYGBgCgpgYGB7ciBoc19nb30KaHNfZ28gPC0gc20obG9hZF9iaW9tYXJ0X2dvKClbWyJnbyJdXSkKaHNfbGVuZ3RoIDwtIGhzX2Fubm90WywgYygiZW5zZW1ibF9nZW5lX2lkIiwgImNkc19sZW5ndGgiKV0KY29sbmFtZXMoaHNfbGVuZ3RoKSA8LSBjKCJJRCIsICJsZW5ndGgiKQpgYGAKCiMgU2FtcGxlIEVzdGltYXRpb24KCiMjIEdlbmVyYXRlIGV4cHJlc3Npb25zZXRzCgpUaGUgc2FtcGxlIHNoZWV0IGlzIGNvcGllZCBmcm9tIG91ciBzaGFyZWQgb25saW5lIHNoZWV0IGFuZCB1cGRhdGVkIHdpdGggZWFjaCByZWxlYXNlCm9mIHNlcXVlbmNpbmcgZGF0YS4KCmBgYHtyIHNhbXBsZXNoZWV0fQpzYW1wbGVzaGVldCA8LSAic2FtcGxlX3NoZWV0cy90bXJjM19zYW1wbGVzXzIwMjEwNTEyLnhsc3giCmBgYAoKIyMjIEhpc2F0MiBleHByZXNzaW9uc2V0cwoKVGhlIGZpcnN0IHRoaW5nIHRvIG5vdGUgaXMgdGhlIGxhcmdlIHJhbmdlIGluIGNvdmVyYWdlLiAgVGhlcmUgYXJlIG11bHRpcGxlCnNhbXBsZXMgd2l0aCBjb3ZlcmFnZSB3aGljaCBpcyB0b28gbG93IHRvIHVzZS4gIFRoZXNlIHdpbGwgYmUgcmVtb3ZlZCBzaG9ydGx5LgoKSW4gdGhlIGZvbGxvd2luZyBibG9jayBJIGltbWVkaWF0ZWx5IGV4Y2x1ZGUgYW55IG5vbi1jb2RpbmcgcmVhZHMgYXMgd2VsbC4KCmBgYHtyIGFsbF9uZXdfaGlzYXQyfQojIyBDcmVhdGUgdGhlIGV4cHJlc3Npb25zZXQgYW5kIGltbWVkaWF0ZWx5IHBhc3MgaXQgdG8gYSBmaWx0ZXIKIyMgcmVtb3ZpbmcgdGhlIG5vbiBwcm90ZWluIGNvZGluZyBnZW5lcy4KaHNfZXhwdCA8LSBjcmVhdGVfZXhwdChzYW1wbGVzaGVldCwKICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbiA9ICJoZzM4MTAwaGlzYXRmaWxlIiwKICAgICAgICAgICAgICAgICAgICAgICBzYXZlZmlsZSA9IGdsdWU6OmdsdWUoInJkYS9oc19leHB0X2FsbC12e3Zlcn0ucmRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvID0gaHNfYW5ub3QpICU+JQogIGV4Y2x1ZGVfZ2VuZXNfZXhwdChjb2x1bW4gPSAiZ2VuZV9iaW90eXBlIiwgbWV0aG9kID0gImtlZXAiLCBwYXR0ZXJuID0gInByb3RlaW5fY29kaW5nIikKYGBgCgojIyMjIEluaXRpYWwgbWV0cmljcwoKT25jZSB0aGUgZGF0YSB3YXMgbG9hZGVkLCB0aGVyZSBhcmUgYSBjb3VwbGUgb2YgbWV0cmljcyB3aGljaCBtYXkgYmUgcGxvdHRlZCBpbW1lZGlhdGVseS4KCmBgYHtyIGluaXRpYWxfbWV0cmljc30Kbm9uemVybyA8LSBwbG90X25vbnplcm8oaHNfZXhwdCkKbm9uemVybyRwbG90CmBgYAoKTmFqaWIgZG9lc24ndCB3YW50IHRoaXMgcGxvdCwgYnV0IEkgYW0gdXNpbmcgaXQgdG8gY2hlY2sgbmV3IHNhbXBsZXMsCnNvIHdpbGwgaGlkZSBpdCBmcm9tIGdlbmVyYWwgdXNlLgoKYGBge3IgbGlic2l6ZX0KbGlic2l6ZSA8LSBwbG90X2xpYnNpemUoaHNfZXhwdCkKbGlic2l6ZSRwbG90CmBgYAoKCiMjIE1pbmltdW0gY292ZXJhZ2Ugc2FtcGxlIGZpbHRlcmluZwoKSSBhcmJpdHJhcmlseSBjaG9zZSAxMSwwMDAgbm9uLXplcm8gZ2VuZXMgYXMgYSBtaW5pbXVtLiAgV2UgbWF5CndhbnQgdGhpcyB0byBiZSBoaWdoZXIuCgpgYGB7ciBoaXNhdDJfd3JpdGUsIGZpZy5zaG93ID0gImhpZGUifQpoc192YWxpZCA8LSBzdWJzZXRfZXhwdChoc19leHB0LCBub256ZXJvID0gMTEwMDApCgp2YWxpZF93cml0ZSA8LSBzbSh3cml0ZV9leHB0KGhzX3ZhbGlkLCBleGNlbCA9IGdsdWUoImV4Y2VsL2hzX3ZhbGlkLXZ7dmVyfS54bHN4IikpKQpgYGAKCiMgUHJvamVjdCBBaW1zCgpUaGUgcHJvamVjdCBzZWVrcyB0byBkZXRlcm1pbmUgdGhlIHJlbGF0aW9uc2hpcCBvZiB0aGUgaW5uYXRlIGltbXVuZSByZXNwb25zZQphbmQgaW5mbGFtbWF0b3J5IHNpZ25hbGluZyB0byB0aGUgY2xpbmljYWwgb3V0Y29tZSBvZiBhbnRpbGVpc2htYW5pYWwgZHJ1Zwp0cmVhdG1lbnQuIFdlIHdpbGwgdGVzdCB0aGUgaHlwb3RoZXNpcyB0aGF0IHRoZSBwcm9maWxlIG9mIGlubmF0ZSBpbW11bmUgY2VsbAphY3RpdmF0aW9uIGFuZCB0aGVpciBkeW5hbWljcyB0aHJvdWdoIHRoZSBjb3Vyc2Ugb2YgdHJlYXRtZW50IGRpZmZlciBiZXR3ZWVuIENMCnBhdGllbnRzIHdpdGggcHJvc3BlY3RpdmVseSBkZXRlcm1pbmVkIHRoZXJhcGV1dGljIGN1cmUgb3IgZmFpbHVyZS4KClRoaXMgd2lsbCBiZSBhY2hpZXZlZCB0aHJvdWdoIHRoZSBjaGFyYWN0ZXJpemF0aW9uIG9mIHRoZSBpbiB2aXZvIGR5bmFtaWNzIG9mCmJsb29kLWRlcml2ZWQgbW9ub2N5dGUsIG5ldXRyb3BoaWwgYW5kIGVvc2lub3BoaWwgdHJhbnNjcmlwdG9tZSBiZWZvcmUsIGR1cmluZwphbmQgYXQgdGhlIGVuZCBvZiB0cmVhdG1lbnQgaW4gQ0wgcGF0aWVudHMuIENlbGwtdHlwZSBzcGVjaWZpYyB0cmFuc2NyaXB0b21lcywKY29tcG9zaXRlIHNpZ25hdHVyZXMgYW5kIHRpbWUtcmVzcG9uc2UgZXhwcmVzc2lvbiBwcm9maWxlcyB3aWxsIGJlIGNvbnRyYXN0ZWQKYW1vbmcgcGF0aWVudHMgd2l0aCB0aGVyYXBldXRpYyBjdXJlIG9yIGZhaWx1cmUuCgojIyBQcmVwYXJhdGlvbgoKVG8gYWRkcmVzcyB0aGVzZSwgSSBhZGRlZCB0byB0aGUgZW5kIG9mIHRoZSBzYW1wbGUgc2hlZXQgY29sdW1ucyBuYW1lZAonY29uZGl0aW9uJywgJ2JhdGNoJywgJ2Rvbm9yJywgYW5kICd0aW1lJy4gIFRoZXNlIGFyZSBmaWxsZWQgaW4gd2l0aCBzaG9ydGhhbmQKdmFsdWVzIGFjY29yZGluZyB0byB0aGUgYWJvdmUuCgojIyBHbG9iYWwgdmlldwoKQmVmb3JlIGFkZHJlc3NpbmcgdGhlIHF1ZXN0aW9ucyBleHBsaWNpdGx5IGJ5IHN1YnNldHRpbmcgdGhlIGRhdGEsIEkgd2FudCB0byBnZXQKYSBsb29rIGF0IHRoZSBzYW1wbGVzIGFzIHRoZXkgYXJlLgoKYGBge3IgcHJlX3F1ZXN0aW9uc30KaHNfdmFsaWQgPC0gaHNfdmFsaWQgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImNlbGxzc291cmNlIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gInR5cGVvZmNlbGxzIikgJT4lCiAgc2V0X2V4cHRfc2FtcGxlbmFtZXMobmV3bmFtZXMgPSBwRGF0YShoc192YWxpZClbWyJzYW1wbGVuYW1lIl1dKQoKYWxsX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoaHNfdmFsaWQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkpCgphbGxfcGNhIDwtIHBsb3RfcGNhKGFsbF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFLCBwbG90X3RpdGxlID0gIlBDQSAtIENlbGwgdHlwZSIpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvdG1yYzNfcGNhX25vbGFiZWxzLXZ7dmVyfS5wbmciKSwgaW1hZ2UgPSBhbGxfcGNhJHBsb3QpCgp3cml0ZS5jc3YoYWxsX3BjYSR0YWJsZSwgZmlsZSA9ICJjb29yZHMvaHNfZG9ub3JfcGNhX2Nvb3Jkcy5jc3YiKQpwbG90X2NvcmhlYXQoYWxsX25vcm0sIHBsb3RfdGl0bGUgPSAiSGVpcmFyY2hpY2FsIGNsdXN0ZXJpbmcgLSBjZWxsIHR5cGVzIikkcGxvdApgYGAKCiMjIEV4YW1pbmUgc2FtcGxlcyByZWxldmFudCB0byBjbGluaWNhbCBvdXRjb21lCgpOb3cgbGV0IHVzIGNvbnNpZGVyIG9ubHkgdGhlIHNhbXBsZXMgZm9yIHdoaWNoIHdlIGhhdmUgYSBjbGluaWNhbCBvdXRjb21lLgpUaGVzZSBmYWxsIHByaW1hcmlseSBpbnRvIGVpdGhlciAnY3VyZWQnIG9yICdmYWlsZWQnLCBidXQgc29tZSBwZW9wbGUgaGF2ZSBub3QKeWV0IHJldHVybmVkIHRvIHRoZSBjbGluaWMgYWZ0ZXIgdGhlIGZpcnN0IG9yIHNlY29uZCB2aXNpdC4gIFRoZXNlIGFyZSBkZWVtZWQKJ2xvc3QnLgoKYGBge3IgYWxsX2NsaW5pY2FsfQpjaG9zZW5fY29sb3JzIDwtIGMoIiNEOTVGMDIiLCAiIzc1NzBCMyIsICIjMUI5RTc3IiwgIiNGRjAwMDAiKQpuYW1lcyhjaG9zZW5fY29sb3JzKSA8LSBjKCJjdXJlIiwgImZhaWx1cmUiLCAibG9zdCIsICJudWxsIikKbmV3bmFtZXMgPC0gcERhdGEoaHNfdmFsaWQpW1sic2FtcGxlbmFtZSJdXQoKaHNfY2xpbmljYWwgPC0gaHNfdmFsaWQgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJ0eXBlb2ZjZWxscyIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnMgPSBjaG9zZW5fY29sb3JzKSAlPiUKICBzZXRfZXhwdF9zYW1wbGVuYW1lcyhuZXduYW1lcyA9IG5ld25hbWVzKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQgPSAidHlwZW9mY2VsbHMhPSdQQk1DcycmdHlwZW9mY2VsbHMhPSdNYWNyb3BoYWdlcyciKQoKaHNfY2xpbmljYWxfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChoc19jbGluaWNhbCwgZmlsdGVyID0gVFJVRSwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgbm9ybSA9ICJxdWFudCIpKQpjbGluaWNhbF9wY2EgPC0gcGxvdF9wY2EoaHNfY2xpbmljYWxfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSwgY2lzID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiUENBIC0gY2xpbmljYWwgc2FtcGxlcyIpCnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvYWxsX2NsaW5pY2FsX25vYmF0Y2hfcGNhLXZ7dmVyfS5wbmciKSwgaW1hZ2UgPSBjbGluaWNhbF9wY2EkcGxvdCwKICAgaGVpZ2h0ID0gOCwgd2lkdGggPSAyMCkKYGBgCgojIyMgUmVwZWF0IHdpdGhvdXQgdGhlIGJpb3BzeSBzYW1wbGVzCgpgYGB7ciBpYmlkX25vYmlvcHN5fQpoc19jbGluaWNhbF9ub2Jpb3AgPC0gaHNfY2xpbmljYWwgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0ID0gInR5cGVvZmNlbGxzIT0nQmlvcHN5JyIpCgpoc19jbGluaWNhbF9ub2Jpb3Bfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChoc19jbGluaWNhbF9ub2Jpb3AsIGZpbHRlciA9IFRSVUUsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IikpCmNsaW5pY2FsX25vYmlvcF9wY2EgPC0gcGxvdF9wY2EoaHNfY2xpbmljYWxfbm9iaW9wX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UsIGNpcyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZSA9ICJQQ0EgLSBjbGluaWNhbCBzYW1wbGVzIHdpdGhvdXQgYmlvcHNpZXMiKQpwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL2FsbF9jbGluaWNhbF9ub2Jpb3Bfbm9iYXRjaF9wY2Etdnt2ZXJ9LnBuZyIpLAogICBpbWFnZSA9IGNsaW5pY2FsX25vYmlvcF9wY2EkcGxvdCkKYGBgCgojIyMgQXR0ZW1wdCB0byBjb3JyZWN0IGZvciB0aGUgc3Vycm9nYXRlIHZhcmlhYmxlcwoKQXQgdGhpcyB0aW1lIHdlIGhhdmUgdHdvIHByaW1hcnkgZGF0YSBzdHJ1Y3R1cmVzIG9mIGludGVyZXN0OiBoc19jbGluaWNhbCBhbmQgaHNfY2xpbmljYWxfbm9iaW9wCgpgYGB7ciBjbGluaWNhbF9zdmF9CmhzX2NsaW5pY2FsX25iIDwtIG5vcm1hbGl6ZV9leHB0KGhzX2NsaW5pY2FsLCBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIikKY2xpbmljYWxfYmF0Y2hfcGNhIDwtIHBsb3RfcGNhKGhzX2NsaW5pY2FsX25iLCBwbG90X2xhYmVscyA9IEZBTFNFLCBjaXMgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZSA9ICJQQ0EgLSBjbGluaWNhbCBzYW1wbGVzIikKY2xpbmljYWxfYmF0Y2hfcGNhJHBsb3QKCmhzX2NsaW5pY2FsX25vYmlvcF9uYiA8LSBzbShub3JtYWxpemVfZXhwdChoc19jbGluaWNhbF9ub2Jpb3AsIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIikpCmNsaW5pY2FsX25vYmlvcF9iYXRjaF9wY2EgPC0gcGxvdF9wY2EoaHNfY2xpbmljYWxfbm9iaW9wX25iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiUENBIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImltYWdlcy9jbGluaWNhbF9iYXRjaC5wbmciLCBpbWFnZSA9IGNsaW5pY2FsX25vYmlvcF9iYXRjaF9wY2EkcGxvdCkKCmNsaW5pY2FsX25vYmlvcF9iYXRjaF90c25lIDwtIHBsb3RfdHNuZShoc19jbGluaWNhbF9ub2Jpb3BfbmIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gInRTTkUgLSBjbGluaWNhbCBzYW1wbGVzIHdpdGhvdXQgYmlvcHNpZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKY2xpbmljYWxfbm9iaW9wX2JhdGNoX3RzbmUkcGxvdAoKdGVzdCA8LSBzaW1wbGVfdmFycGFydChoc19jbGluaWNhbF9ub2Jpb3ApCnRlc3QkcGFydGl0aW9uX3Bsb3QKYGBgCgojIyBQZXJmb3JtIERFIG9mIHRoZSBjbGluaWNhbCBzYW1wbGVzIGN1cmUgdnMuIGZhaWwKCmBgYHtyIGNsaW5pY2FsX2RlLCBmaWcuc2hvdz0iaGlkZSJ9CmluZGl2aWR1YWxfY2VsbHR5cGVzIDwtIHN1YnNldF9leHB0KGhzX2NsaW5pY2FsX25vYmlvcCwgc3Vic2V0PSJjb25kaXRpb24hPSdsb3N0JyIpCmhzX2NsaW5pY19kZSA8LSBzbShhbGxfcGFpcndpc2UoaW5kaXZpZHVhbF9jZWxsdHlwZXMsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpKQpoc19jbGluaWNfdGFibGUgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBoc19jbGluaWNfZGUsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2luZGl2aWR1YWxfY2VsbHR5cGVzX3RhYmxlLXZ7dmVyfS54bHN4IikpKQpoc19jbGluaWNfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBoc19jbGluaWNfdGFibGUsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2luZGl2aWR1YWxfY2VsbHR5cGVzX3NpZy12e3Zlcn0ueGxzeCIpKSkKCmhzX2NsaW5pY19zaWdbWyJzdW1tYXJ5X2RmIl1dCmBgYAoKIyMjIExvb2sgYXQgb25seSB0aGUgZGlmZmVyZW50aWFsIGdlbmVzCgpBIGdvb2Qgc3VnZ2VzdGlvbiBmcm9tIFRoZXJlc2Egd2FzIHRvIGV4YW1pbmUgb25seSB0aGUgbW9zdCB2YXJpYW50CmdlbmVzIGZyb20gZmFpbHVyZSB2cy4gY3VyZSBhbmQgc2VlIGhvdyB0aGV5IGNoYW5nZSB0aGUgY2x1c3RlcmluZy9ldGMKcmVzdWx0cy4gIFRoaXMgaXMgbXkgYXR0ZW1wdCB0byBhZGRyZXNzIHRoaXMgcXVlcnkuCgpgYGB7ciBzbWFsbF9leHBsb3JlfQpoc19jbGluaWNfdG9wbiA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGhzX2NsaW5pY190YWJsZSwgbiA9IDEwMCkpCnRhYmxlIDwtICJmYWlsdXJlX3ZzX2N1cmUiCndhbnRlZCA8LSByYmluZChoc19jbGluaWNfdG9wbltbImRlc2VxIl1dW1sidXBzIl1dW1t0YWJsZV1dLAogICAgICAgICAgICAgICAgaHNfY2xpbmljX3RvcG5bWyJkZXNlcSJdXVtbImRvd25zIl1dW1t0YWJsZV1dKQoKc21hbGxfZXhwdCA8LSBleGNsdWRlX2dlbmVzX2V4cHQoaHNfY2xpbmljYWxfbm9iaW9wLCBpZHMgPSByb3duYW1lcyh3YW50ZWQpLCBtZXRob2QgPSAia2VlcCIpCnNtYWxsX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoc21hbGxfZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpKQpwbG90X3BjYShzbWFsbF9ub3JtKSRwbG90CgpzbWFsbF9uYiA8LSBub3JtYWxpemVfZXhwdChzbWFsbF9leHB0LCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2ggPSAic3Zhc2VxIiwgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnBsb3RfcGNhKHNtYWxsX25iKSRwbG90CmBgYAoKYGBge3IgY2xpbmljYWxfcGxvdH0KIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKaHNfY2xpbmljX3RhYmxlW1sicGxvdHMiXV1bWyJmYWlsdXJlX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmhzX2NsaW5pY190YWJsZVtbInBsb3RzIl1dW1siZmFpbHVyZV92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIyMgZzpQcm9maWxlciByZXN1bHRzIHVzaW5nIHRoZSBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcwoKYGBge3IgcGVyZm9ybV9ncHJvZmlsZXJ9CnVwcyA8LSBoc19jbGluaWNfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXQpkb3ducyA8LSBoc19jbGluaWNfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dCgpoc19jbGluaWNfZ3Byb2ZpbGVyX3VwcyA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHVwcykKaHNfY2xpbmljX2dwcm9maWxlcl91cHNbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCmhzX2NsaW5pY19ncHJvZmlsZXJfdXBzW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpoc19jbGluaWNfZ3Byb2ZpbGVyX3Vwc1tbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQoKIyNoc190cnkyIDwtIHNpbXBsZV9ncHJvZmlsZXIyKHVwcykKCmhzX2NsaW5pY19ncHJvZmlsZXJfZG93bnMgPC0gc2ltcGxlX2dwcm9maWxlcihkb3ducykKaHNfY2xpbmljX2dwcm9maWxlcl9kb3duc1tbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KaHNfY2xpbmljX2dwcm9maWxlcl9kb3duc1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KaHNfY2xpbmljX2dwcm9maWxlcl9kb3duc1tbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIFBlcmZvcm0gR1NWQSBvbiB0aGUgY2xpbmljYWwgc2FtcGxlcwoKYGBge3IgZ3N2YSwgZmlnLnNob3cgPSAiaGlkZSJ9CmhzX2NlbGx0eXBlX2dzdmFfYzIgPC0gc20oc2ltcGxlX2dzdmEoaW5kaXZpZHVhbF9jZWxsdHlwZXMpKQpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZyA8LSBzbShnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIGhzX2NlbGx0eXBlX2dzdmFfYzIsCiAgICBleGNlbCA9ICJleGNlbC9pbmRpdmlkdWFsX2NlbGx0eXBlc19nc3ZhX2MyLnhsc3giKSkKCmJyb2FkX2M3IDwtIEdTRUFCYXNlOjpnZXRHbXQoInJlZmVyZW5jZS9tc2lnZGIvYzcuYWxsLnY3LjIuZW50cmV6LmdtdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGVjdGlvblR5cGUgPSBHU0VBQmFzZTo6QnJvYWRDb2xsZWN0aW9uKGNhdGVnb3J5ID0gImM3IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZUlkVHlwZSA9IEdTRUFCYXNlOjpFbnRyZXpJZGVudGlmaWVyKCkpCmhzX2NlbGx0eXBlX2dzdmFfYzcgPC0gc20oc2ltcGxlX2dzdmEoaW5kaXZpZHVhbF9jZWxsdHlwZXMsIHNpZ25hdHVyZXMgPSBicm9hZF9jNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2lnX3htbCA9ICJyZWZlcmVuY2UvbXNpZ2RiX3Y3LjIueG1sIiwgY29yZXMgPSAxMCkpCmhzX2NlbGx0eXBlX2dzdmFfYzdfc2lnIDwtIHNtKGdldF9zaWdfZ3N2YV9jYXRlZ29yaWVzKAogICAgaHNfY2VsbHR5cGVfZ3N2YV9jNywKICAgIGV4Y2VsID0gImV4Y2VsL2luZGl2aWR1YWxfY2VsbHR5cGVzX2dzdmFfYzcueGxzeCIpKQpgYGAKCiMjIyBQcmludCBzb21lIHBsb3RzIG9mIHRoZSBHU1ZBIG91dHB1dHMKCmBgYHtyIGdzdmFfcGxvdHN9CiMjIFRoZSByYXcgaGVhdG1hcCBvZiB0aGUgQzIgdmFsdWVzCmhzX2NlbGx0eXBlX2dzdmFfYzJfc2lnW1sicmF3X3Bsb3QiXV0KIyMgVGhlICdzaWduaWZpY2FuY2UnIHNjb3JlcyBvZiB0aGUgQzIgdmFsdWVzCmhzX2NlbGx0eXBlX2dzdmFfYzJfc2lnW1sic2NvcmVfcGxvdCJdXQojIyBUaGUgc3Vic2V0IG9mIHNjb3JlcyBmb3IgY2F0ZWdvcmllcyBkZWVtZWQgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQuCmhzX2NlbGx0eXBlX2dzdmFfYzJfc2lnW1sic3Vic2V0X3Bsb3QiXV0KCiMjIFRoZSByYXcgaGVhdG1hcCBvZiB0aGUgQzcgdmFsdWVzCmhzX2NlbGx0eXBlX2dzdmFfYzdfc2lnW1sicmF3X3Bsb3QiXV0KIyMgVGhlICdzaWduaWZpY2FuY2UnIHNjb3JlcyBvZiB0aGUgQzcgdmFsdWVzCmhzX2NlbGx0eXBlX2dzdmFfYzdfc2lnW1sic2NvcmVfcGxvdCJdXQojIyBUaGUgc3Vic2V0IG9mIHNjb3JlcyBmb3IgY2F0ZWdvcmllcyBkZWVtZWQgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQuCmhzX2NlbGx0eXBlX2dzdmFfYzdfc2lnW1sic3Vic2V0X3Bsb3QiXV0KYGBgCgojIEluZGl2aWR1YWwgQ2VsbCB0eXBlcwoKVGhlIGZvbGxvd2luZyBibG9ja3Mgc3BsaXQgdGhlIHNhbXBsZXMgaW50byBhIGZldyBncm91cHMgYnkgc2FtcGxlIHR5cGUgYW5kIGxvb2sKYXQgdGhlIGRpc3RyaWJ1dGlvbnMgYmV0d2VlbiB0aGVtLgoKIyMgSW1wbGVtZW50YXRpb24gZGV0YWlscwoKR2V0IHRvcC9ib3R0b20gbiBnZW5lcyBmb3IgZWFjaCBjZWxsIHR5cGUsIHVzaW5nIGNsaW5pY2FsIG91dGNvbWUgYXMgdGhlIGZhY3RvciBvZiBpbnRlcmVzdC4KRm9yIHRoZSBtb21lbnQsIHVzZSBzdmEgZm9yIHRoZSBERSBhbmFseXNpcy4KUHJvdmlkZSBjcG1zIGZvciB0aGUgdG9wL2JvdHRvbSBuIGdlbmVzLgoKU3RhcnQgd2l0aCB0b3AvYm90dG9tIDIwMC4KUGVyZm9ybSBkZWZhdWx0IGxvZ0ZDIGFuZCBwLXZhbHVlIGFzIHdlbGwuCgojIyMgU2hhcmVkIGNvbnRyYXN0cwoKSGVyZSBpcyB0aGUgY29udHJhc3Qgd2Ugd2lsbCB1c2UgdGhyb3VnaHB1dCwgSSBhbSBsZWF2aW5nIG9wZW4gdGhlIG9wdGlvbiB0byBhZGQgbW9yZS4KCmBgYHtyIGtlZXBlcnN9CmtlZXBlcnMgPC0gbGlzdCgKICAiZmFpbF92c19jdXJlIiA9IGMoImZhaWx1cmUiLCAiY3VyZSIpKQpgYGAKCiMjIE1vbm9jeXRlcwoKIyMjIEV2YWx1YXRlIE1vbm9jeXRlIHNhbXBsZXMKCmBgYHtyIG1vbm9jeXRlc30KbW9ubyA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0ID0gInR5cGVvZmNlbGxzPT0nTW9ub2N5dGVzJyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJjbGluaWNhbG91dGNvbWUiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZG9ub3IiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JzID0gY2hvc2VuX2NvbG9ycykKIyMgRklYTUUgc2V0X2V4cHRfY29sb3JzIHNob3VsZCBzcGVhayB1cCBpZiB0aGVyZSBhcmUgbWlzbWF0Y2hlcyBoZXJlISEhCgpzYXZlX3Jlc3VsdCA8LSBzYXZlKG1vbm8sIGZpbGUgPSAicmRhL21vbm9jeXRlX2V4cHQucmRhIikKbW9ub19ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KG1vbm8sIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgbm9ybSA9ICJxdWFudCIpCnBsdCA8LSBwbG90X3BjYShtb25vX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKcHAoZmlsZSA9IGdsdWUoImltYWdlcy9tb25vX3BjYV9ub3JtYWxpemVkLXZ7dmVyfS5wZGYiKSwgaW1hZ2UgPSBwbHQpCgptb25vX25iIDwtIG5vcm1hbGl6ZV9leHB0KG1vbm8sIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCnBsdCA8LSBwbG90X3BjYShtb25vX25iLCBwbG90X2xhYmVscyA9IEZBTFNFKSRwbG90CnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvbW9ub19wY2Ffbm9ybWFsaXplZF9iYXRjaC12e3Zlcn0ucGRmIiksIGltYWdlID0gcGx0KQpgYGAKCiMjIyBERSBvZiBNb25vY3l0ZSBzYW1wbGVzCgojIyMjIFdpdGhvdXQgc3ZhCgpgYGB7ciBkZV9tb25vY3l0ZSwgZmlnLnNob3cgPSAiaGlkZSJ9Cm1vbm9fZGUgPC0gc20oYWxsX3BhaXJ3aXNlKG1vbm8sIG1vZGVsX2JhdGNoID0gRkFMU0UsIGZpbHRlciA9IFRSVUUpKQptb25vX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIG1vbm9fZGUsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9hbGxfdGFibGVzLXZ7dmVyfS54bHN4IikpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG1vbm9fdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF90YWJsZS12e3Zlcn0ueGxzeCIpKQptb25vX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1vbm9fdGFibGVzLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBtb25vX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ3VwLXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbW9ub19zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ2Rvd24tdnt2ZXJ9Lnhsc3giKSkKCm1vbm9fcGN0X3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1vbm9fdGFibGVzLCBuID0gMjAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZmMgPSBOVUxMLCBwID0gTlVMTCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbW9ub19wY3Rfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfc2lndXBfcGN0LXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbW9ub19wY3Rfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9zaWdkb3duX3BjdC12e3Zlcn0ueGxzeCIpKQptb25vX3NpZyRzdW1tYXJ5X2RmCgojIyBQcmludCBvdXQgYSB0YWJsZSBvZiB0aGUgY3BtIHZhbHVlcyBmb3Igb3RoZXIgZXhwbG9yYXRpb25zLgptb25vX2NwbSA8LSBzbShub3JtYWxpemVfZXhwdChtb25vLCBjb252ZXJ0ID0gImNwbSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGV4cHJzKG1vbm9fY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY3BtX2JlZm9yZV9iYXRjaC12e3Zlcn0ueGxzeCIpKQptb25vX2JjcG0gPC0gc20obm9ybWFsaXplX2V4cHQobW9ubywgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9ICJzdmFzZXEiKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhtb25vX2JjcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jcG1fYWZ0ZXJfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMjIFdpdGggc3ZhCgpgYGB7ciBkZV9tb25vX3N2YSwgZmlnLnNob3cgPSAiaGlkZSJ9Cm1vbm9fZGVfc3ZhIDwtIHNtKGFsbF9wYWlyd2lzZShtb25vLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKSkKbW9ub190YWJsZXNfc3ZhIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgbW9ub19kZV9zdmEsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9hbGxfdGFibGVzX3N2YS12e3Zlcn0ueGxzeCIpKSkKbW9ub19zaWdfc3ZhIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBtb25vX3RhYmxlc19zdmEsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ190YWJsZXNfc3ZhLXZ7dmVyfS54bHN4IiksCiAgICBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKSkKYGBgCgojIyMjIE1vbm9jeXRlIERFIHBsb3RzCgpGaXJzdCBwcmludCBvdXQgdGhlIERFIHBsb3RzIHdpdGhvdXQgYW5kIHRoZW4gd2l0aCBzdmEgZXN0aW1hdGVzLgoKYGBge3IgbW9ub19kZV9wbG90c30KIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKbW9ub190YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX21hX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBWb2xjYW5vIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKbW9ub190YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZSB3aXRoIHN2YXNlcQptb25vX3RhYmxlc19zdmFbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX21hX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBWb2xjYW5vIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUgd2l0aCBzdmFzZXEKbW9ub190YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdApgYGAKCiMjIyMgTW9ub2N5dGUgb250b2xvZ3kgc2VhcmNoCgpgYGB7ciBtb25vX2dwcm9maWxlcn0KdXBzIDwtIG1vbm9fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KZG93bnMgPC0gbW9ub19zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siZmFpbF92c19jdXJlIl1dCgptb25vX3VwX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzID0gdXBzKQptb25vX3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQptb25vX3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQptb25vX3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sicmVhY3RvbWVfcGxvdF9vdmVyIl1dCgptb25vX2Rvd25fZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXMgPSBkb3ducykKbW9ub19kb3duX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQptb25vX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCm1vbm9fZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyMgTW9ub2N5dGUgTVNpZ0RCIHF1ZXJ5CgpgYGB7ciBtc2lnX21vbm9fZ29zZXEsIGZpZy5zaG93ID0gImhpZGUifQpicm9hZF9jNyA8LSBHU0VBQmFzZTo6Z2V0R210KCJyZWZlcmVuY2UvbXNpZ2RiL2M3LmFsbC52Ny4yLmVudHJlei5nbXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb25UeXBlID0gR1NFQUJhc2U6OkJyb2FkQ29sbGVjdGlvbihjYXRlZ29yeSA9ICJjNyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVJZFR5cGUgPSBHU0VBQmFzZTo6RW50cmV6SWRlbnRpZmllcigpKQoKbW9ub191cF9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXMgPSB1cHMsIHNpZ25hdHVyZXMgPSBicm9hZF9jNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVfY2F0ZWdvcnkgPSAiYzciLCBsZW5ndGhfZGIgPSBoc19sZW5ndGgpCgptb25vX2Rvd25fZ29zZXFfbXNpZyA8LSBnb3NlcV9tc2lnZGIoc2lnX2dlbmVzID0gZG93bnMsIHNpZ25hdHVyZXMgPSBicm9hZF9jNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJjNyIsIGxlbmd0aF9kYiA9IGhzX2xlbmd0aCkKYGBgCgojIyMjIFBsb3Qgb2Ygc2ltaWxhciBleHBlcmltZW50cwoKYGBge3IgbXNpZ19wbG90c30KIyMgTW9ub2N5dGUgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgZmFpbGVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCm1vbm9fdXBfZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KCiMjIE1vbm9jeXRlIGdlbmVzIHdpdGggaW5jcmVhc2VkIGV4cHJlc3Npb24gaW4gdGhlIGN1cmVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCm1vbm9fZG93bl9nb3NlcV9tc2lnW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyBFdmFsdWF0ZSBOZXV0cm9waGlsIHNhbXBsZXMKCmBgYHtyIG5ldXRyb3BoaWxzfQpuZXV0IDwtIHN1YnNldF9leHB0KGhzX3ZhbGlkLCBzdWJzZXQgPSAidHlwZW9mY2VsbHM9PSdOZXV0cm9waGlscyciKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImRvbm9yIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9ycyA9IGNob3Nlbl9jb2xvcnMpCgpzYXZlX3Jlc3VsdCA8LSBzYXZlKG5ldXQsIGZpbGUgPSAicmRhL25ldXRyb3BoaWxfZXhwdC5yZGEiKQpuZXV0X25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFLCB0cmFuc2Zvcm0gPSAibG9nMiIpKQpwbHQgPC0gcGxvdF9wY2EobmV1dF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKSRwbG90CnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvbmV1dF9wY2Ffbm9ybWFsaXplZC12e3Zlcn0ucGRmIiksIGltYWdlID0gcGx0KQoKbmV1dF9uYiA8LSBzbShub3JtYWxpemVfZXhwdChuZXV0LCBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBiYXRjaCA9ICJzdmFzZXEiKSkKcGx0IDwtIHBsb3RfcGNhKG5ldXRfbmIsIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKcHAoZmlsZSA9IGdsdWUoImltYWdlcy9uZXV0X3BjYV9ub3JtYWxpemVkX3N2YXNlcS12e3Zlcn0ucGRmIiksIGltYWdlID0gcGx0KQpgYGAKCiMjIyBERSBvZiBOZXRyb3BoaWwgc2FtcGxlcwoKIyMjIyBXaXRob3V0IHN2YQoKYGBge3IgbmV1dHJvcGhpbF9kZSwgZmlnLnNob3cgPSAiaGlkZSJ9Cm5ldXRfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKG5ldXQsIG1vZGVsX2JhdGNoID0gRkFMU0UsIGZpbHRlciA9IFRSVUUpKQpuZXV0X3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIG5ldXRfZGUsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX2FsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbmV1dF90YWJsZXNbWyJkYXRhIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfdGFibGUtdnt2ZXJ9Lnhsc3giKSkKbmV1dF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhuZXV0X3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ3VwLXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfc2lnZG93bi12e3Zlcn0ueGxzeCIpKQoKbmV1dF9wY3Rfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMobmV1dF90YWJsZXMsIG4gPSAyMDAsIGxmYyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAgPSBOVUxMLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBuZXV0X3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfc2lndXBfcGN0LXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfc2lnZG93bl9wY3Qtdnt2ZXJ9Lnhsc3giKSkKbmV1dF9jcG0gPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhuZXV0X2NwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY3BtX2JlZm9yZV9iYXRjaC12e3Zlcn0ueGxzeCIpKQpuZXV0X2JjcG0gPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIiwgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhuZXV0X2JjcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NwbV9hZnRlcl9iYXRjaC12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyMgV2l0aCBzdmEKCmBgYHtyIGRlX25ldXRfc3ZhLCBmaWcuc2hvdyA9ICJoaWRlIn0KbmV1dF9kZV9zdmEgPC0gc20oYWxsX3BhaXJ3aXNlKG5ldXQsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpKQpuZXV0X3RhYmxlc19zdmEgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBuZXV0X2RlX3N2YSwga2VlcGVycyA9IGtlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfYWxsX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSkpCm5ldXRfc2lnX3N2YSA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgbmV1dF90YWJsZXNfc3ZhLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ190YWJsZXNfc3ZhLXZ7dmVyfS54bHN4IiksCiAgICBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKSkKYGBgCgojIyMjIE5ldXRyb3BoaWwgREUgcGxvdHMKCmBgYHtyIG5ldXRfZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm5ldXRfdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm5ldXRfdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUgd2l0aCBzdmEKbmV1dF90YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3ZhCm5ldXRfdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIyMjIE5ldXRyb3BoaWwgb250b2xvZ3kgc2VhcmNoCgpgYGB7ciBuZXV0X2dwfQp1cHMgPC0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImZhaWxfdnNfY3VyZSJdXQpkb3ducyA8LSBuZXV0X3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KCm5ldXRfdXBfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXMgPSB1cHMpCm5ldXRfdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCm5ldXRfdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCm5ldXRfdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KCm5ldXRfZG93bl9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKGRvd25zKQpuZXV0X2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCm5ldXRfZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KbmV1dF9kb3duX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sicmVhY3RvbWVfcGxvdF9vdmVyIl1dCmBgYAoKIyMjIyBOZXV0cm9waGlsIEdTVkEgcXVlcnkKCmBgYHtyIG1zaWdfbmV1dF9nb3NlcSwgZmlnLnNob3cgPSAiaGlkZSJ9Cm5ldXRfdXBfZ29zZXFfbXNpZyA8LSBnb3NlcV9tc2lnZGIoc2lnX2dlbmVzID0gdXBzLCBzaWduYXR1cmVzID0gYnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlX2NhdGVnb3J5ID0gImM3IiwgbGVuZ3RoX2RiID0gaHNfbGVuZ3RoKQoKbmV1dF9kb3duX2dvc2VxX21zaWcgPC0gZ29zZXFfbXNpZ2RiKHNpZ19nZW5lcyA9IGRvd25zLCBzaWduYXR1cmVzID0gYnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVfY2F0ZWdvcnkgPSAiYzciLCBsZW5ndGhfZGIgPSBoc19sZW5ndGgpCmBgYAoKIyMjIyBQbG90IG9mIHNpbWlsYXIgZXhwZXJpbWVudHMKCmBgYHtyIG1zaWdfcGxvdHNfbmV1dH0KIyMgTmV1dHJvcGhpbCBnZW5lcyB3aXRoIGluY3JlYXNlZCBleHByZXNzaW9uIGluIHRoZSBmYWlsZWQgc2FtcGxlcwojIyBzaGFyZSBnZW5lcyB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwZXJpbWVudHMKbmV1dF91cF9nb3NlcV9tc2lnW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQoKIyMgTmV1dHJvcGhpbCBnZW5lcyB3aXRoIGluY3JlYXNlZCBleHByZXNzaW9uIGluIHRoZSBjdXJlZCBzYW1wbGVzCiMjIHNoYXJlIGdlbmVzIHdpdGggdGhlIGZvbGxvd2luZyBleHBlcmltZW50cwpuZXV0X2Rvd25fZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KYGBgCgojIyBFb3Npbm9waGlscwoKIyMjIEV2YWx1YXRlIEVvc2lub3BoaWwgc2FtcGxlcwoKYGBge3IgZW9zaW5vcGhpbHN9CmVvIDwtIHN1YnNldF9leHB0KGhzX3ZhbGlkLCBzdWJzZXQgPSAidHlwZW9mY2VsbHM9PSdFb3Npbm9waGlscyciKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImRvbm9yIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9ycyA9IGNob3Nlbl9jb2xvcnMpCgpzYXZlX3Jlc3VsdCA8LSBzYXZlKGVvLCBmaWxlID0gInJkYS9lb3Npbm9waGlsX2V4cHQucmRhIikKZW9fbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChlbywgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpKQpwbHQgPC0gcGxvdF9wY2EoZW9fbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkkcGxvdApwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL2VvX3BjYV9ub3JtYWxpemVkLXZ7dmVyfS5wZGYiKSwgaW1hZ2UgPSBwbHQpCgplb19uYiA8LSBzbShub3JtYWxpemVfZXhwdChlbywgY29udmVydCA9ICJjcG0iLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIpKQpwbG90X3BjYShlb19uYikkcGxvdApgYGAKCiMjIyBERSBvZiBFb3Npbm9waGlsIHNhbXBsZXMKCiMjIyMgV2l0aG91dGggc3ZhCgpgYGB7ciBlb3Npbm9waGlsX2RlLCBmaWcuc2hvdyA9ICJoaWRlIn0KZW9fZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGVvLCBtb2RlbF9iYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKZW9fdGFibGVzIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgZW9fZGUsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX2FsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZW9fdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX3RhYmxlLXZ7dmVyfS54bHN4IikpCmVvX3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGVvX3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZW9fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9zaWd1cC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGVvX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9zaWdkb3duLXZ7dmVyfS54bHN4IikpCgplb19wY3Rfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoZW9fdGFibGVzLCBuID0gMjAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGZjID0gTlVMTCwgcCA9IE5VTEwsIGFjY29yZGluZ190byA9ICJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGVvX3BjdF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX3NpZ3VwX3BjdC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGVvX3BjdF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY2xpbmljYWxfc2lnZG93bl9wY3Qtdnt2ZXJ9Lnhsc3giKSkKCmVvX2NwbSA8LSBzbShub3JtYWxpemVfZXhwdChlbywgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhlb19jcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NwbV9iZWZvcmVfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKZW9fYmNwbSA8LSBzbShub3JtYWxpemVfZXhwdChlbywgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIiwgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhlb19iY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jcG1fYWZ0ZXJfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMjIFdpdGggc3ZhCgpgYGB7ciBkZV9lb19zdmEsIGZpZy5zaG93ID0gImhpZGUifQplb19kZV9zdmEgPC0gc20oYWxsX3BhaXJ3aXNlKGVvLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKSkKZW9fdGFibGVzX3N2YSA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIGVvX2RlX3N2YSwga2VlcGVycyA9IGtlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY2xpbmljYWxfYWxsX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSkpCmVvX3NpZ19zdmEgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGVvX3RhYmxlc19zdmEsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY2xpbmljYWxfc2lnX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSwKICAgIGFjY29yZGluZ190byA9ICJkZXNlcSIpKQpgYGAKCiMjIyMgRW9zaW5vcGhpbCBERSBwbG90cwoKYGBge3IgZW9fZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmVvX3RhYmxlc1tbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQplb190YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZSB3aXRoIHN2YQplb190YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3ZhCmVvX3RhYmxlc19zdmFbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CmBgYAoKIyMjIyBFb3Npbm9waGlsIG9udG9sb2d5IHNlYXJjaAoKYGBge3IgZW9fZ3Byb2ZpbGVyfQp1cHMgPC0gZW9fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KZG93bnMgPC0gZW9fc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImZhaWxfdnNfY3VyZSJdXQoKZW9fdXBfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXMgPSB1cHMpCmVvX3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQplb191cF9ncFtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KZW9fdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KCmVvX2Rvd25fZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihkb3ducykKZW9fZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KZW9fZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KZW9fZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyMgRW9zaW5vcGhpbCBNU2lnREIgcXVlcnkKCmBgYHtyIG1zaWdfZW9fZ29zZXEsIGZpZy5zaG93ID0gImhpZGUifQplb191cF9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXMgPSB1cHMsIHNpZ25hdHVyZXMgPSBicm9hZF9jNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlX2NhdGVnb3J5ID0gImM3IiwgbGVuZ3RoX2RiID0gaHNfbGVuZ3RoKQoKZW9fZG93bl9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXMgPSBkb3ducywgc2lnbmF0dXJlcyA9IGJyb2FkX2M3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJjNyIsIGxlbmd0aF9kYiA9IGhzX2xlbmd0aCkKYGBgCgojIyMjIFBsb3Qgb2Ygc2ltaWxhciBleHBlcmltZW50cwoKYGBge3IgbXNpZ19wbG90c19lb30KIyMgRW9zaW5vcGhpbCBnZW5lcyB3aXRoIGluY3JlYXNlZCBleHByZXNzaW9uIGluIHRoZSBmYWlsZWQgc2FtcGxlcwojIyBzaGFyZSBnZW5lcyB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwZXJpbWVudHMKZW9fdXBfZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KCiMjIEVvc2lub3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgY3VyZWQgc2FtcGxlcwojIyBzaGFyZSBnZW5lcyB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwZXJpbWVudHMKZW9fZG93bl9nb3NlcV9tc2lnW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIEJpb3BzaWVzCgojIyMgRXZhbHVhdGUgQmlvcHN5IHNhbXBsZXMKCmBgYHtyIGJpb3BzaWVzfQpiaW9wIDwtIHN1YnNldF9leHB0KGhzX3ZhbGlkLCBzdWJzZXQgPSAidHlwZW9mY2VsbHM9PSdCaW9wc3knIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJkb25vciIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnMgPSBjaG9zZW5fY29sb3JzKQoKc2F2ZV9yZXN1bHQgPC0gc2F2ZShiaW9wLCBmaWxlID0gInJkYS9iaW9wc3lfZXhwdC5yZGEiKQpiaW9wX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoYmlvcCwgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBub3JtID0gInF1YW50IikKcGx0IDwtIHBsb3RfcGNhKGJpb3Bfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkkcGxvdApwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL2Jpb3BfcGNhX25vcm1hbGl6ZWQtdnt2ZXJ9LnBkZiIpLCBpbWFnZSA9IHBsdCkKCmJpb3BfbmIgPC0gc20obm9ybWFsaXplX2V4cHQoYmlvcCwgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikpCnBsdCA8LSBwbG90X3BjYShiaW9wX25iLCBwbG90X2xhYmVscyA9IEZBTFNFKSRwbG90CnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvYmlvcF9wY2Ffbm9ybWFsaXplZF9zdmFzZXEtdnt2ZXJ9LnBkZiIpLCBpbWFnZSA9IHBsdCkKYGBgCgojIyMgREUgb2YgQmlvcHN5IHNhbXBsZXMKCiMjIyMgV2l0aG91dCBzdmEKCmBgYHtyIGRlX2Jpb3BzeSwgZmlnLnNob3cgPSAiaGlkZSJ9CmJpb3BfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGJpb3AsIG1vZGVsX2JhdGNoID0gRkFMU0UsIGZpbHRlciA9IFRSVUUpKQpiaW9wX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcyhiaW9wX2RlLCBrZWVwZXJzID0ga2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfYWxsX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGJpb3BfdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfdGFibGUtdnt2ZXJ9Lnhsc3giKSkKYmlvcF9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhiaW9wX3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIikKIyN3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGJpb3Bfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKIyMgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfc2lndXAtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBiaW9wX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3NpZ2Rvd24tdnt2ZXJ9Lnhsc3giKSkKYmlvcF9wY3Rfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoYmlvcF90YWJsZXMsIG4gPSAyMDAsIGxmYyA9IE5VTEwsIHAgPSBOVUxMLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGJpb3BfcGN0X3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jbGluaWNhbF9zaWd1cF9wY3Qtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBiaW9wX3BjdF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jbGluaWNhbF9zaWdkb3duX3BjdC12e3Zlcn0ueGxzeCIpKQoKYmlvcF9jcG0gPC0gc20obm9ybWFsaXplX2V4cHQoYmlvcCwgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhiaW9wX2NwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jcG1fYmVmb3JlX2JhdGNoLXZ7dmVyfS54bHN4IikpCmJpb3BfYmNwbSA8LSBzbShub3JtYWxpemVfZXhwdChiaW9wLCBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiLCBjb252ZXJ0ID0gImNwbSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGV4cHJzKGJpb3BfYmNwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jcG1fYWZ0ZXJfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMjIHdpdGggc3ZhCgpgYGB7ciBkZV9iaW9wc3lfc3ZhLCBmaWcuc2hvdyA9ICJoaWRlIn0KYmlvcF9kZV9zdmEgPC0gc20oYWxsX3BhaXJ3aXNlKGJpb3AsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpKQpiaW9wX3RhYmxlc19zdmEgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBiaW9wX2RlX3N2YSwga2VlcGVycyA9IGtlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jbGluaWNhbF9hbGxfdGFibGVzX3N2YS12e3Zlcn0ueGxzeCIpKSkKYmlvcF9zaWdfc3ZhIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBiaW9wX3RhYmxlc19zdmEsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jbGluaWNhbF9zaWdfdGFibGVzX3N2YS12e3Zlcn0ueGxzeCIpLAogICAgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCmBgYAoKIyMjIyBCaW9wc3kgREUgcGxvdHMKCmBgYHtyIGJpb3BfZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmJpb3BfdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmJpb3BfdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKYmlvcF90YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmJpb3BfdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIE1vbm9jeXRlcyBieSB2aXNpdAoKIDEuIENhbiB5b3UgcGxlYXNlIHNoYXJlIHdpdGggdXMgYSBQQ0EgKFNWQSBhbmQgbm9uLVNWQSkgb2YgdGhlCiAgICBtb25vY3l0ZXMgb2YgdGhlIFRNUkMzIHByb2plY3QsIGJ1dCBsYWJlbGluZyB0aGVtIGJhc2VkIG9uIHRoZSB2aXNpdAogICAgKFYxLCBWMiwgVjMpPwogMi4gQ2FuIHlvdSBwbGVhc2Ugc2hhcmUgREUgbGlzdHMgb2YgVjEgdnMgVjIsIFYxIHZzIFYzLCBWMSB2cy4gVjIrVjMKICAgIGFuZCBWMiB2cyBWMz8KCmBgYHtyIG1vbm9jeXRlc19ieV92aXNpdH0KdmlzaXRfY29sb3JzIDwtIGNob3Nlbl9jb2xvcnMgPC0gYygiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiMxQjlFNzciKQpuYW1lcyh2aXNpdF9jb2xvcnMpIDwtIGMoMSwgMiwgMykKbW9ub192aXNpdCA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0ID0gInR5cGVvZmNlbGxzPT0nTW9ub2N5dGVzJyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJ2aXNpdG51bWJlciIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJjbGluaWNhbG91dGNvbWUiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JzID0gY2hvc2VuX2NvbG9ycykKCm1vbm9fdmlzaXRfbm9ybSA8LSBub3JtYWxpemVfZXhwdChtb25vX3Zpc2l0LCBmaWx0ZXIgPSBUUlVFLCBub3JtID0gInF1YW50IiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiKQptb25vX3Zpc2l0X3BjYSA8LSBwbG90X3BjYShtb25vX3Zpc2l0X25vcm0pCnBwKGZpbGUgPSAiaW1hZ2VzL21vbm9jeXRlX2J5X3Zpc2l0LnBuZyIsIGltYWdlID0gbW9ub192aXNpdF9wY2EkcGxvdCkKCm1vbm9fdmlzaXRfbmIgPC0gbm9ybWFsaXplX2V4cHQobW9ub192aXNpdCwgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gInN2YXNlcSIsIHRyYW5zZm9ybSA9ICJsb2cyIikKbW9ub192aXNpdF9uYl9wY2EgPC0gcGxvdF9wY2EobW9ub192aXNpdF9uYikKcHAoZmlsZSA9ICJpbWFnZXMvbW9ub2N5dGVfYnlfdmlzaXRfbmIucG5nIiwgaW1hZ2UgPSBtb25vX3Zpc2l0X25iX3BjYSRwbG90KQoKdGFibGUocERhdGEobW9ub192aXNpdF9ub3JtKSRiYXRjaCkKYGBgCgpgYGB7ciBtb25vX3Zpc2l0X2RlLCBmaWcuc2hvdyA9ICJoaWRlIn0Ka2VlcGVycyA8LSBsaXN0KAogICAgInNlY29uZF92c19maXJzdCIgPSBjKCJjMiIsICJjMSIpLAogICAgInRoaXJkX3ZzX3NlY29uZCIgPSBjKCJjMyIsICJjMiIpLAogICAgInRoaXJkX3ZzX2ZpcnN0IiA9IGMoImMzIiwgImMxIikpCm1vbm9fdmlzaXRfZGUgPC0gYWxsX3BhaXJ3aXNlKG1vbm9fdmlzaXQsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCgptb25vX3Zpc2l0X3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIG1vbm9fdmlzaXRfZGUsCiAgICBrZWVwZXJzID0ga2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub192aXNpdF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKYGBgCgpgYGB7ciB2MV92c19hbGx9Cm5ld19mYWN0b3IgPC0gcERhdGEobW9ub192aXNpdClbWyJjb25kaXRpb24iXV0Kbm90X29uZV9pZHggPC0gbmV3X2ZhY3RvciAhPSAxCm5ld19mYWN0b3Jbbm90X29uZV9pZHhdIDwtICJub3RfMSIKbW9ub19vbmVfdnMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtb25vX3Zpc2l0LCBuZXdfZmFjdG9yKQoKbW9ub19vbmVfdnNfZGUgPC0gYWxsX3BhaXJ3aXNlKG1vbm9fb25lX3ZzLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQoKbW9ub19vbmVfdnNfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbW9ub19vbmVfdnNfZGUsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9fb25lX3ZzX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgVGVzdCBUU1AKCkluIHdyaXRpbmcgdGhlIGZvbGxvd2luZywgSSBxdWlja2x5IHJlYWxpemVkIHRoYXQgdHNwYWlyIHdhcyBub3QKam9raW5nIHdoZW4gaXQgc2FpZCBpdCBpcyBpbnRlbmRlZCBmb3Igc21hbGwgbnVtYmVycyBvZiBnZW5lcy4gIEZvciBhCmZ1bGwgZXhwcmVzc2lvbnNldCBvZiBodW1hbiBkYXRhIGl0IGlzIHN0cnVnZ2xpbmcuICBJIGxpa2UgdGhlIGlkZWEsCml0IG1heSBwcm92ZSB3b3J0aCB3aGlsZSB0byBzcGVuZCBzb21lIHRpbWUgb3B0aW1pemluZyB0aGUgcGFja2FnZSBzbwp0aGF0IGl0IGlzIG1vcmUgdXNhYmxlLgoKYGBge3IgdHNwLCBldmFsID0gRkFMU0V9CmV4cHQgPC0gaHNfY2xpbmljYWxfbm9iaW9wCgpzaW1wbGVfdHNwIDwtIGZ1bmN0aW9uKGV4cHQsIGNvbHVtbiA9ICJjb25kaXRpb24iKSB7CiAgZmFjdHMgPC0gbGV2ZWxzKGFzLmZhY3RvcihwRGF0YShleHB0KVtbY29sdW1uXV0pKQogIHJldGxpc3QgPC0gbGlzdCgpCiAgaWYgKGxlbmd0aChmYWN0cykgPCAyKSB7CiAgICBzdG9wKCJUaGlzIHJlcXVpcmVzIGZhY3RvcnMgd2l0aCBhdCBsZWFzdCAyIGxldmVscy4iKQogIH0gZWxzZSBpZiAobGVuZ3RoKGZhY3RzKSA9PSAyKSB7CiAgICByZXRsaXN0IDwtIHNpbXBsZV90c3BfcGFpcihleHB0LCBjb2x1bW4gPSBjb2x1bW4pCiAgfSBlbHNlIHsKICAgIGZvciAoZmlyc3QgaW4gMToobGVuZ3RoKGZhY3RzKSAtIDEpKSB7CiAgICAgIGZvciAoc2Vjb25kIGluIDI6KGxlbmd0aChmYWN0cykpKSB7CiAgICAgICAgaWYgKGZpcnN0IDwgc2Vjb25kKSB7CiAgICAgICAgICBuYW1lIDwtIGdsdWU6OmdsdWUoIntmYWN0c1tmaXJzdF19X3ZzX3tmYWN0c1tzZWNvbmRdfSIpCiAgICAgICAgICBtZXNzYWdlKCJTdGFydGluZyAiLCBuYW1lLCAiLiIpCiAgICAgICAgICBzdWJzdHJpbmcgPC0gZ2x1ZTo6Z2x1ZSgie2NvbHVtbn09PSd7ZmFjdHNbZmlyc3RdfSd8e2NvbHVtbn09PSd7ZmFjdHNbc2Vjb25kXX0nIikKICAgICAgICAgIHN1YmJ5IDwtIHN1YnNldF9leHB0KGV4cHQsIHN1YnNldD1hcy5jaGFyYWN0ZXIoc3Vic3RyaW5nKSkKICAgICAgICAgIHJldGxpc3RbW25hbWVdXSA8LSBzaW1wbGVfdHNwX3BhaXIoc3ViYnksIGNvbHVtbiA9IGNvbHVtbikKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCnNpbXBsZV90c3BfcGFpciA8LSBmdW5jdGlvbihzdWJieSwgY29sdW1uID0gImNvbmRpdGlvbiIsIHJlcGV0aXRpb25zID0gNTApIHsKICB0c3BfaW5wdXQgPC0gc3ViYnlbWyJleHByZXNzaW9uc2V0Il1dCiAgdHNwX291dHB1dCA8LSB0c3BjYWxjKHRzcF9pbnB1dCwgY29sdW1uKQogIHRzcF9zY29yZXMgPC0gdHNwc2lnKHRzcF9pbnB1dCwgY29sdW1uLCBCID0gcmVwZXRpdGlvbnMpCn0KCnRzcDEgPC0gdHNwY2FsYyh0c3BfaW5wdXQsICJjb25kaXRpb24iKQoKYGBgCgpgYGB7ciBzYXZlbWV9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIHBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCiAgbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCiAgbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCBzYXZlZmlsZSkpCiAgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZSA9IHNhdmVmaWxlKSkKfQpgYGAKCmBgYHtyIGxvYWRtZV9hZnRlciwgZXZhbCA9IEZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=