samplesheet <- "sample_sheets/tmrc3_samples_20210620.xlsx"

1 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")

2 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.

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.

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.
sanitize_columns <- c("visitnumber", "clinicaloutcome", "donor",
                      "typeofcells", "clinicalpresentation",
                      "condition", "batch")
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", meta_column = "ncrna_lost") %>%
  sanitize_expt_metadata(columns = sanitize_columns) %>%
  set_expt_factors(columns = sanitize_columns, class = "factor")
## Reading the sample metadata.
## Dropped 71 rows from the sample metadata because they were blank.
## The sample definitions comprises: 173 rows(samples) and 76 columns(metadata fields).
## 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 171 columns.
## Before removal, there were 21481 genes, now there are 19941.
## There are 17 samples which kept less than 90 percent counts.
## TMRC30015 TMRC30017 TMRC30019 TMRC30044 TMRC30045 TMRC30154 TMRC30097 TMRC30075 
##     79.24     85.72     89.75     80.34     73.33     83.20     89.90     86.97 
## TMRC30087 TMRC30101 TMRC30104 TMRC30114 TMRC30127 TMRC30120 TMRC30128 TMRC30131 
##     83.63     88.41     80.29     87.62     89.49     79.16     82.53     86.82 
## TMRC30073 
##     89.26
levels(pData(hs_expt[["expressionset"]])[["visitnumber"]]) <- list(
    '0' = "notapplicable", '1' = 1, '2' = 2, '3' = 3)

Split this data into CDS and lncRNA. Oh crap in order to do that I need to recount the data. Running now (20210518)

## lnc_expt <- create_expt(samplesheet,
##                         file_column = "hg38100lncfile",
##                         gene_info = hs_annot)

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: 143 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

ncrna_lost_df <- as.data.frame(pData(hs_expt)[["ncrna_lost"]])
rownames(ncrna_lost_df) <- rownames(pData(hs_expt))
colnames(ncrna_lost_df) <- "ncrna_lost"

tmpdf <- merge(nonzero$table, ncrna_lost_df, by = "row.names")
rownames(tmpdf) <- tmpdf[["Row.names"]]
tmpdf[["Row.names"]] <- NULL

ggplot(tmpdf, aes(x=ncrna_lost, y=nonzero_genes)) +
  ggplot2::geom_point() +
  ggplot2::ggtitle("Nonzero genes with respect to percent counts 
lost when ncRNA was removed.")

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
## subset_expt(): There were 171, now there are 168 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.

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

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", size_column = "visitnumber")
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’.

hs_clinical <- hs_valid %>%
  set_expt_conditions(fact = "clinicaloutcome") %>%
  set_expt_batches(fact = "typeofcells") %>%
  subset_expt(subset = "typeofcells!='pbmcs'&typeofcells!='macrophages'")
## subset_expt(): There were 168, now there are 148 samples.
chosen_colors <- c("#D95F02", "#7570B3", "#1B9E77", "#FF0000", "#FF0000")
names(chosen_colors) <- c("cure", "failure", "lost", "null", "notapplicable")
hs_clinical <- set_expt_colors(hs_clinical, colors = chosen_colors)
## Warning in set_expt_colors(hs_clinical, colors = chosen_colors): Colors for the
## following categories are not being used: nullnotapplicable.
newnames <- make.names(pData(hs_clinical)[["samplename"]], unique = TRUE)
hs_clinical <- set_expt_samplenames(hs_clinical, newnames = newnames)

hs_clinical_norm <- sm(normalize_expt(hs_clinical, filter = TRUE, transform = "log2",
                                      convert = "cpm", norm = "quant"))
clinical_pca <- plot_pca(hs_clinical_norm, plot_labels = FALSE,
                         size_column = "visitnumber", cis = NULL,
                         plot_title = "PCA - clinical samples")
pp(file = glue("images/all_clinical_nobatch_pca-v{ver}.png"), image = clinical_pca$plot,
   height = 8, width = 20)

4.3.1 Repeat without the biopsy samples

hs_clinical_nobiop <- hs_clinical %>%
  subset_expt(subset = "typeofcells!='biopsy'")
## subset_expt(): There were 148, now there are 98 samples.
hs_clinical_nobiop_norm <- sm(normalize_expt(hs_clinical_nobiop, filter = TRUE, transform = "log2",
                                             convert = "cpm", norm = "quant"))
clinical_nobiop_pca <- plot_pca(hs_clinical_nobiop_norm, plot_labels = FALSE, cis = NULL,
                                plot_title = "PCA - clinical samples without biopsies")
pp(file = glue("images/all_clinical_nobiop_nobatch_pca-v{ver}.png"),
   image = clinical_nobiop_pca$plot)

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")
## Removing 5255 low-count genes (14686 remaining).
## batch_counts: Before batch/surrogate estimation, 142925 entries are x==0: 7%.
## batch_counts: Before batch/surrogate estimation, 411125 entries are 0<x<1: 19%.
## Setting 22846 low elements to zero.
## transform_counts: Found 22846 values equal to 0, adding 1 to the matrix.
clinical_batch_pca <- plot_pca(hs_clinical_nb, plot_labels = FALSE, cis = NULL,
                               size_column = "visitnumber", plot_title = "PCA - clinical samples")
clinical_batch_pca$plot

hs_clinical_nobiop_nb <- sm(normalize_expt(hs_clinical_nobiop, filter = TRUE, batch = "svaseq",
                                           transform = "log2", convert = "cpm"))
clinical_nobiop_batch_pca <- plot_pca(hs_clinical_nobiop_nb,
                                      plot_title = "PCA - clinical samples without biopsies",
                                      plot_labels = FALSE)
pp(file = "images/clinical_batch.png", image = clinical_nobiop_batch_pca$plot)

test <- plot_pca(hs_clinical_nobiop_nb, size_column = "visitnumber",
                 plot_title = "PCA - clinical samples without biopsies",
                 plot_labels = FALSE)
test$plot

clinical_nobiop_batch_tsne <- plot_tsne(hs_clinical_nobiop_nb,
                                        plot_title = "tSNE - clinical samples without biopsies",
                                        plot_labels = FALSE)
clinical_nobiop_batch_tsne$plot

4.3.2.1 Look at remaining variance with variancePartition

test <- simple_varpart(hs_clinical_nobiop)
## 
## Total:104 s
test$partition_plot

4.4 Perform DE of the clinical samples cure vs. fail

individual_celltypes <- subset_expt(hs_clinical_nobiop, subset="condition!='lost'")
## subset_expt(): There were 98, now there are 83 samples.
hs_clinic_de <- sm(all_pairwise(individual_celltypes, model_batch = "svaseq", filter = TRUE))

hs_clinic_table <- sm(combine_de_tables(
    hs_clinic_de,
    excel = glue::glue("excel/individual_celltypes_table-v{ver}.xlsx")))

hs_clinic_sig <- sm(extract_significant_genes(
    hs_clinic_table,
    excel = glue::glue("excel/individual_celltypes_sig-v{ver}.xlsx")))

hs_clinic_sig[["summary_df"]]
##   limma_V1 limma_V2 edger_V1 edger_V2 deseq_V1 deseq_V2 ebseq_V1 ebseq_V2
## 1      142      110      207      174      201      189      100      166
##   basic_V1 basic_V2
## 1       57       19
hs_clinic_de[["comparison"]][["heat"]]
## NULL

4.4.1 Perform LRT with the clinical samples

I am not sure if we have enough samples across the three visit to completely work as well as we would like, but there is only 1 way to find out! Now that I think about it, one thing which might be awesome is to use cell type as an interacting factor…

4.4.1.1 With biopsy samples

I figure this might be a place where the biopsy samples might prove useful.

clinical_nolost <- subset_expt(hs_clinical, subset="condition!='lost'")
## subset_expt(): There were 148, now there are 131 samples.
lrt_visit_clinical_test <- sm(deseq_lrt(clinical_nolost, transform = "vst",
                                        interactor_column = "visitnumber",
                                        interest_column = "clinicaloutcome"))
## Error in nrow(lrg_significant): object 'lrg_significant' not found
lrt_visit_clinical_test[["favorite_genes"]]
## Error in eval(expr, envir, enclos): object 'lrt_visit_clinical_test' not found
lrt_celltype_clinical_test <- sm(deseq_lrt(clinical_nolost, transform = "vst",
                                           interactor_column = "typeofcells",
                                           interest_column = "clinicaloutcome"))
## Error in nrow(lrg_significant): object 'lrg_significant' not found
summary(lrt_celltype_clinical_test[["favorite_genes"]])
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'summary': object 'lrt_celltype_clinical_test' not found

4.4.2 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))
table <- "failure_vs_cure"
wanted <- rbind(hs_clinic_topn[["deseq"]][["ups"]][[table]],
                hs_clinic_topn[["deseq"]][["downs"]][[table]])

small_expt <- exclude_genes_expt(hs_clinical_nobiop, ids = rownames(wanted), method = "keep")
## Before removal, there were 19941 genes, now there are 200.
## There are 98 samples which kept less than 90 percent counts.
##  X1017n1  X1017m1  X1034n1  X1034n2  X1034m2 X1034m2.  X2052e1  X2052m2 
##   0.7276   0.4162   2.7013   3.0884   1.2799   1.2513   0.5507   0.5749 
##  X2052n2  X2052m3  X2052n3  X2065m1  X2065n1  X2066m1  X2066n1  X2065m2 
##   1.8012   0.6464   1.5493   1.0218   2.9441   0.3853   1.0215   0.5777 
##  X2065n2  X2065e2  X2066m2  X2066n2  X2066e2  X2068m1  X2068n1  X2068e1 
##   0.7291   1.2382   0.5166   0.8269   0.9474   0.5516   0.7353   1.1808 
##  X2072m1  X2072n1  X2072e1  X2071m1  X2071n1  X2071e1  X2073m1  X2073n1 
##   0.5416   0.7864   2.1099   0.7446   1.8134   0.9283   0.6518   1.9317 
##  X2073e1  X2068m2  X2068n2  X2068e2  X2072m2  X2072n2  X2072e2  X2073m2 
##   0.8120   0.3497   0.6980   0.7661   0.4201   1.0475   0.6019   0.9693 
##  X2073n2  X2073e2  X2066m3  X2066n3  X2066e3  X2065m3  X2065n3  X2065e3 
##   2.8379   0.7924   0.4418   0.9547   0.6221   0.3589   0.8420   0.5483 
##  X2068m3  X2068n3  X2068e3  X2072m3  X2072n3  X2072e3  X2073m3  X2073n3 
##   0.4487   0.7081   0.6811   0.7139   2.2444   0.7535   0.4998   0.8912 
##  X2073e3  X2162m1  X2162n1  X2162e1  X2162m2  X2162n2  X2162e2  X2162n3 
##   0.4817   0.4687   0.6579   0.8271   0.5095   0.7904   0.8386   0.8464 
##  X2162e3  X2167m1  X2167n1  X2167e1  X2168m1  X2168n1  X2168e1  X2168m2 
##   0.6290   0.6206   0.9449   1.0535   0.9953   2.3022   1.0149   0.9023 
##  X2168n2  X2168e2  X2167m2  X2167n2  X2167e2  X2167m3  X2167n3  X2167e3 
##   2.3564   0.8392   0.3654   0.9109   0.7656   0.7490   1.3369   1.2115 
##  X2168m3  X2168n3  X2168e3  X2172m1  X2172n1  X2172e1  X2173m1  X2173n1 
##   1.2749   3.6074   0.9863   0.3770   0.6949   0.4562   0.3371   0.4632 
##  X2172m3  X2172e3  X1168m1  X1168n1  X1168m2  X1168e2  X1168m3  X1168n3 
##   0.4955   0.7815   0.7637   1.6990   0.7457   0.5287   0.7347   1.2161 
##  X1167m3  X1167n3 
##   0.5319   1.1020
small_norm <- sm(normalize_expt(small_expt, transform = "log2", convert = "cpm",
                                norm = "quant", filter = TRUE))
plot_pca(small_norm)$plot
## Warning: ggrepel: 57 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

small_nb <- normalize_expt(small_expt, transform = "log2", convert = "cpm",
                           batch = "svaseq", norm = "quant", filter = TRUE)
## Warning in normalize_expt(small_expt, transform = "log2", convert = "cpm", :
## Quantile normalization and sva do not always play well together.
## Removing 0 low-count genes (200 remaining).
## batch_counts: Before batch/surrogate estimation, 12 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 1806 entries are 0<x<1: 9%.
## Setting 184 low elements to zero.
## transform_counts: Found 184 values equal to 0, adding 1 to the matrix.
plot_pca(small_nb)$plot

## DESeq2 MA plot of failure / cure
hs_clinic_table[["plots"]][["failure_vs_cure"]][["deseq_ma_plots"]]$plot

## DESeq2 Volcano plot of failure / cure
hs_clinic_table[["plots"]][["failure_vs_cure"]][["deseq_vol_plots"]]$plot

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

ups <- hs_clinic_sig[["deseq"]][["ups"]][[1]]
downs <- hs_clinic_sig[["deseq"]][["downs"]][[1]]

hs_clinic_gprofiler_ups <- simple_gprofiler(ups)
## Performing gProfiler GO search of 201 genes against hsapiens.
## GO search found 77 hits.
## Performing gProfiler KEGG search of 201 genes against hsapiens.
## KEGG search found 6 hits.
## Performing gProfiler REAC search of 201 genes against hsapiens.
## REAC search found 6 hits.
## Performing gProfiler MI search of 201 genes against hsapiens.
## MI search found 0 hits.
## Performing gProfiler TF search of 201 genes against hsapiens.
## TF search found 49 hits.
## Performing gProfiler CORUM search of 201 genes against hsapiens.
## CORUM search found 0 hits.
## Performing gProfiler HP search of 201 genes against hsapiens.
## HP search found 0 hits.
hs_clinic_gprofiler_ups[["pvalue_plots"]][["bpp_plot_over"]]

hs_clinic_gprofiler_ups[["pvalue_plots"]][["mfp_plot_over"]]

hs_clinic_gprofiler_ups[["pvalue_plots"]][["reactome_plot_over"]]

##hs_try2 <- simple_gprofiler2(ups)

hs_clinic_gprofiler_downs <- simple_gprofiler(downs)
## Performing gProfiler GO search of 189 genes against hsapiens.
## GO search found 71 hits.
## Performing gProfiler KEGG search of 189 genes against hsapiens.
## KEGG search found 3 hits.
## Performing gProfiler REAC search of 189 genes against hsapiens.
## REAC search found 7 hits.
## Performing gProfiler MI search of 189 genes against hsapiens.
## MI search found 0 hits.
## Performing gProfiler TF search of 189 genes against hsapiens.
## TF search found 9 hits.
## Performing gProfiler CORUM search of 189 genes against hsapiens.
## CORUM search found 4 hits.
## Performing gProfiler HP search of 189 genes against hsapiens.
## HP search found 0 hits.
hs_clinic_gprofiler_downs[["pvalue_plots"]][["bpp_plot_over"]]

hs_clinic_gprofiler_downs[["pvalue_plots"]][["mfp_plot_over"]]

hs_clinic_gprofiler_downs[["pvalue_plots"]][["reactome_plot_over"]]

4.5 Perform GSVA on the clinical samples

hs_celltype_gsva_c2 <- sm(simple_gsva(individual_celltypes))
hs_celltype_gsva_c2_sig <- sm(get_sig_gsva_categories(
    hs_celltype_gsva_c2,
    excel = "excel/individual_celltypes_gsva_c2.xlsx"))

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))
hs_celltype_gsva_c7_sig <- sm(get_sig_gsva_categories(
    hs_celltype_gsva_c7,
    excel = "excel/individual_celltypes_gsva_c7.xlsx"))

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)
## subset_expt(): There were 168, now there are 36 samples.
## Warning in set_expt_colors(., colors = chosen_colors): Colors for the following
## categories are not being used: nullnotapplicable.
## 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 8861 low-count genes (11080 remaining).
## transform_counts: Found 7 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 8861 low-count genes (11080 remaining).
## batch_counts: Before batch/surrogate estimation, 1726 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 24767 entries are 0<x<1: 6%.
## Setting 701 low elements to zero.
## transform_counts: Found 701 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: 116, after conversion: 116.
## Before conversion: 227921, after conversion: 35341.
## Found 113 go_db genes and 116 length_db genes out of 116.
mono_down_goseq_msig <- goseq_msigdb(sig_genes = downs, signatures = broad_c7,
                                     signature_category = "c7", length_db = hs_length)
## Before conversion: 207, after conversion: 206.
## Before conversion: 227921, after conversion: 35341.
## Found 197 go_db genes and 206 length_db genes out of 206.

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"]]

## 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)
## subset_expt(): There were 168, now there are 35 samples.
## Warning in set_expt_colors(., colors = chosen_colors): Colors for the following
## categories are not being used: nullnotapplicable.
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: 149, after conversion: 149.
## Before conversion: 227921, after conversion: 35341.
## Found 144 go_db genes and 149 length_db genes out of 149.
neut_down_goseq_msig <- goseq_msigdb(sig_genes = downs, signatures = broad_c7,
                                     signature_category = "c7", length_db = hs_length)
## Before conversion: 103, after conversion: 100.
## Before conversion: 227921, after conversion: 35341.
## Found 95 go_db genes and 100 length_db genes out of 100.

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)
## subset_expt(): There were 168, now there are 27 samples.
## Warning in set_expt_colors(., colors = chosen_colors): Colors for the following
## categories are not being used: nullnotapplicable.
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: 114, after conversion: 114.
## Before conversion: 227921, after conversion: 35341.
## Found 111 go_db genes and 114 length_db genes out of 114.
eo_down_goseq_msig <- goseq_msigdb(sig_genes = downs, signatures = broad_c7,
                                   signature_category = "c7", length_db = hs_length)
## Before conversion: 40, after conversion: 39.
## Before conversion: 227921, after conversion: 35341.
## Found 35 go_db genes and 39 length_db genes out of 39.

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)
## subset_expt(): There were 168, now there are 50 samples.
## Warning in set_expt_colors(., colors = chosen_colors): Colors for the following
## categories are not being used: nullnotapplicable.
save_result <- save(biop, file = "rda/biopsy_expt.rda")
biop_norm <- normalize_expt(biop, filter = TRUE, convert = "cpm",
                            transform = "log2", norm = "quant")
## Removing 5752 low-count genes (14189 remaining).
## transform_counts: Found 16 values equal to 0, adding 1 to the matrix.
plt <- plot_pca(biop_norm, plot_labels = FALSE)$plot
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
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))
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-v202106.xlsx before writing the tables.
written <- write_xlsx(data = biop_tables[["data"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_table-v{ver}.xlsx"))
biop_sig <- extract_significant_genes(biop_tables, according_to = "deseq")
##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"))
biop_pct_sig <- extract_significant_genes(biop_tables, n = 200, lfc = NULL, p = NULL, according_to = "deseq")
## Getting the top and bottom 200 genes.
written <- write_xlsx(data = biop_pct_sig[["deseq"]][["ups"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_sigup_pct-v{ver}.xlsx"))
written <- write_xlsx(data = biop_pct_sig[["deseq"]][["downs"]][[1]],
                      excel = glue::glue("excel/biopsy_clinical_sigdown_pct-v{ver}.xlsx"))

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))
biop_tables_sva <- sm(combine_de_tables(
    biop_de_sva, keepers = keepers,
    excel = glue::glue("excel/biopsy_clinical_all_tables_sva-v{ver}.xlsx")))
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"))

5.4.2.3 Biopsy DE plots

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

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

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

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

6 Look for shared genes among Monocytes/Neutrophils/Eosinophils

We have three variables containing the ‘significant’ DE genes for the three cell types. For this I am choosing (for the moment) to use the sva data.

## mono_sig_sva, neut_sig_sva, eo_sig_sva
sig_vectors <- list(
    "monocytes" = c(rownames(mono_sig_sva[["deseq"]][["ups"]][["fail_vs_cure"]]),
                    rownames(mono_sig_sva[["deseq"]][["downs"]][["fail_vs_cure"]])),
    "neutrophils" = c(rownames(neut_sig_sva[["deseq"]][["ups"]][["fail_vs_cure"]]),
                      rownames(neut_sig_sva[["deseq"]][["downs"]][["fail_vs_cure"]])),
    "eosinophils" =  c(rownames(eo_sig_sva[["deseq"]][["ups"]][["fail_vs_cure"]]),
                       rownames(eo_sig_sva[["deseq"]][["downs"]][["fail_vs_cure"]])))

shared_vector <- Vennerable::Venn(Sets = sig_vectors)
Vennerable::plot(shared_vector, doWeights = FALSE)

shared_ids <- shared_vector@IntersectionSets[["111"]]
shared_expt <- exclude_genes_expt(hs_clinical, ids = shared_ids, method = "keep")
## Before removal, there were 19941 genes, now there are 23.
## There are 148 samples which kept less than 90 percent counts.
##  X1017n1  X1017m1  X1034n1 X1034bp1  X1034n2  X1034m2 X1034m2. X2050bp1 
##  0.09618  0.09574  1.36052  0.45728  1.66473  0.57028  0.54732  0.19514 
## X2052bp1  X2052e1  X2052m2  X2052n2  X2052m3  X2052n3  X2065m1  X2065n1 
##  0.46300  0.04695  0.15612  0.32061  0.20004  0.28746  0.24780  0.99756 
## X2065bp1  X2066m1  X2066n1 X2066bp1  X2065m2  X2065n2  X2065e2  X2066m2 
##  0.50189  0.09884  0.18213  0.37438  0.09035  0.06769  0.04269  0.10083 
##  X2066n2  X2066e2  X2068m1  X2068n1  X2068e1 X2068bp1  X2072m1  X2072n1 
##  0.12348  0.04596  0.06585  0.08253  0.04199  0.22971  0.06952  0.08924 
##  X2072e1 X2072bp1  X2071m1  X2071n1  X2071e1 X2071bp1  X2073m1  X2073n1 
##  0.03975  0.22404  0.16805  0.64400  0.07191  0.29254  0.17698  0.73538 
##  X2073e1 X2073bp1  X2068m2  X2068n2  X2068e2  X2072m2  X2072n2  X2072e2 
##  0.10784  0.34703  0.08602  0.11732  0.05140  0.10111  0.13478  0.05578 
##  X2073m2  X2073n2  X2073e2  X2066m3  X2066n3  X2066e3  X2065m3  X2065n3 
##  0.36766  1.52085  0.24028  0.10646  0.12149  0.04346  0.09801  0.10366 
##  X2065e3  X2068m3  X2068n3  X2068e3  X2072m3  X2072n3  X2072e3 X2159bp1 
##  0.03510  0.07402  0.08672  0.04494  0.22587  0.85090  0.10602  0.28181 
##  X2073m3  X2073n3  X2073e3  X2162m1  X2162n1  X2162e1 X2162bp1  X2162m2 
##  0.16457  0.31538  0.08631  0.08197  0.09055  0.05417  0.26041  0.11265 
##  X2162n2  X2162e2  X2162n3  X2162e3  X2167m1  X2167n1  X2167e1 X2167bp1 
##  0.12397  0.07943  0.18645  0.05671  0.14654  0.07029  0.12166  0.25303 
##  X2168m1  X2168n1  X2168e1 X2168bp1  X2168m2  X2168n2  X2168e2  X2167m2 
##  0.38955  1.16962  0.24932  0.42659  0.34443  1.21392  0.21625  0.08277 
##  X2167n2  X2167e2  X2167m3  X2167n3  X2167e3  X2168m3  X2168n3  X2168e3 
##  0.08672  0.02541  0.14818  0.08081  0.08518  0.47671  1.74663  0.35040 
##  X2172m1  X2172n1  X2172e1 X2172bp1  X2173m1  X2173n1 X2173bp1  X2172m3 
##  0.08611  0.07582  0.04167  0.50228  0.08284  0.07457  0.27043  0.14335 
##  X2172e3 X1154bp1  X2008.1  X2008.2  X2008.3  X1029.1  X1029.2  X1029.3 
##  0.09091  0.28539  0.23131  0.15783  0.22867  0.22776  0.21855  0.18686 
##  X1036.1  X1036.2  X1036.3  X1037.1  X1037.2  X1037.3  X1031.1  X1031.2 
##  0.45938  0.30700  0.22476  0.36593  0.16479  0.15420  0.38822  0.21053 
##  X1031.3  X2002.1  X2002.3  X2009.1  X2009.2  X2010.1  X2010.2  X2010.3 
##  0.24431  0.33992  0.13768  0.23662  0.15738  0.29477  0.28700  0.17601 
##  X1019.1  X1019.2  X1019.3  X2004.1  X2004.2  X2004.3  X2001.1  X2001.2 
##  0.52085  0.36943  0.28509  0.25365  0.21867  0.18717  0.27900  0.18098 
##  X2001.3  X2003.1  X2003.2  X2003.3  X1168m1  X1168n1  X1168m2  X1168e2 
##  0.13415  0.53556  0.18122  0.18324  0.26484  0.52693  0.25146  0.08427 
##  X1168m3  X1168n3  X1167m3  X1167n3 
##  0.28475  0.39542  0.13990  0.13891
shared_written <- write_expt(shared_expt,
                             excel = glue::glue("excel/shared_across_celltypes-v{ver}.xlsx"))
## Deleting the file excel/shared_across_celltypes-v202106.xlsx before writing the tables.
## Writing the first sheet, containing a legend and some summary data.
## Warning: ggrepel: 140 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 127 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## plot labels was not set and there are more than 100 samples, disabling it.
## plot labels was not set and there are more than 100 samples, disabling it.
## 
## Total:0 s
## Warning: ggrepel: 142 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 116 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## 
## Total:0 s

7 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)
## subset_expt(): There were 168, now there are 36 samples.
mono_visit_norm <- normalize_expt(mono_visit, filter = TRUE, norm = "quant", convert = "cpm",
                                  transform = "log2")
## Removing 8861 low-count genes (11080 remaining).
## transform_counts: Found 7 values equal to 0, adding 1 to the matrix.
mono_visit_pca <- plot_pca(mono_visit_norm)
pp(file = "images/monocyte_by_visit.png", image = mono_visit_pca$plot)

mono_visit_nb <- normalize_expt(mono_visit, filter = TRUE, convert = "cpm",
                                batch = "svaseq", transform = "log2")
## Removing 8861 low-count genes (11080 remaining).
## batch_counts: Before batch/surrogate estimation, 1726 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 24767 entries are 0<x<1: 6%.
## Setting 563 low elements to zero.
## transform_counts: Found 563 values equal to 0, adding 1 to the matrix.
mono_visit_nb_pca <- plot_pca(mono_visit_nb)
pp(file = "images/monocyte_by_visit_nb.png", image = mono_visit_nb_pca$plot)

table(pData(mono_visit_norm)$batch)
## 
##    cure failure    lost 
##      15      15       6
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, 1726 entries are x==0: 0%.
## Plotting a PCA before surrogate/batch inclusion.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## Removing 0 low-count genes (11080 remaining).
## batch_counts: Before batch/surrogate estimation, 1726 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 24767 entries are 0<x<1: 6%.
## Setting 563 low elements to zero.
## transform_counts: Found 563 values equal to 0, adding 1 to the matrix.
## 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-v202106.xlsx before writing the tables.
new_factor <- as.character(pData(mono_visit)[["visitnumber"]])
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, 1726 entries are x==0: 0%.
## Plotting a PCA before surrogate/batch inclusion.
## Using svaseq to visualize before/after batch inclusion.
## Performing a test normalization with: raw
## Removing 0 low-count genes (11080 remaining).
## batch_counts: Before batch/surrogate estimation, 1726 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 24767 entries are 0<x<1: 6%.
## Setting 569 low elements to zero.
## transform_counts: Found 569 values equal to 0, adding 1 to the matrix.
## 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-v202106.xlsx before writing the tables.

8 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 f80b9b77ce0f5b0c13e9172e5cf51a94eaadaa9e
## This is hpgltools commit: Mon Jun 28 14:14:28 2021 -0400: f80b9b77ce0f5b0c13e9172e5cf51a94eaadaa9e
## Saving to tmrc3_02sample_estimation_v202106.rda.xz
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiVE1SQzMgQ29tcHJlaGVuc2l2ZSBEYXRhIEFuYWx5c2lzOiAyMDIxMDYiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICBjb2xsYXBzZWQ6IGZhbHNlCiAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAxMjAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3IgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICBkcGkgPSA5NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjEwNiIKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gIiVZJW0lZCIpCgpybWRfZmlsZSA8LSBnbHVlOjpnbHVlKCJ0bXJjM18wMnNhbXBsZV9lc3RpbWF0aW9uX3Z7dmVyfS5SbWQiKQpzYXZlZmlsZSA8LSBnc3ViKHBhdHRlcm4gPSAiXFwuUm1kIiwgcmVwbGFjZSA9ICJcXC5yZGFcXC54eiIsIHggPSBybWRfZmlsZSkKYGBgCgpgYGB7ciBzYW1wbGVzaGVldH0Kc2FtcGxlc2hlZXQgPC0gInNhbXBsZV9zaGVldHMvdG1yYzNfc2FtcGxlc18yMDIxMDYyMC54bHN4IgpgYGAKCiMgQW5ub3RhdGlvbgoKV2UgdGFrZSB0aGUgYW5ub3RhdGlvbiBkYXRhIGZyb20gZW5zZW1ibCdzIGJpb21hcnQgaW5zdGFuY2UuICBUaGUgZ2Vub21lIHdoaWNoCndhcyB1c2VkIHRvIG1hcCB0aGUgZGF0YSB3YXMgaGczOCByZXZpc2lvbiAxMDAuICBNeSBkZWZhdWx0IHdoZW4gdXNpbmcgYmlvbWFydCBpcwp0byBsb2FkIHRoZSBkYXRhIGZyb20gMSB5ZWFyIGJlZm9yZSB0aGUgY3VycmVudCBkYXRlLgoKYGBge3IgaHNfYW5ub3R9CmhzX2Fubm90IDwtIHNtKGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucyh5ZWFyID0gIjIwMjAiKSkKaHNfYW5ub3QgPC0gaHNfYW5ub3RbWyJhbm5vdGF0aW9uIl1dCmhzX2Fubm90W1sidHJhbnNjcmlwdCJdXSA8LSBwYXN0ZTAocm93bmFtZXMoaHNfYW5ub3QpLCAiLiIsIGhzX2Fubm90W1sidmVyc2lvbiJdXSkKcm93bmFtZXMoaHNfYW5ub3QpIDwtIG1ha2UubmFtZXMoaHNfYW5ub3RbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZSA9IFRSVUUpCnR4X2dlbmVfbWFwIDwtIGhzX2Fubm90WywgYygidHJhbnNjcmlwdCIsICJlbnNlbWJsX2dlbmVfaWQiKV0KCnN1bW1hcnkoaHNfYW5ub3QpCmBgYAoKYGBge3IgaHNfZ299CmhzX2dvIDwtIHNtKGxvYWRfYmlvbWFydF9nbygpW1siZ28iXV0pCmhzX2xlbmd0aCA8LSBoc19hbm5vdFssIGMoImVuc2VtYmxfZ2VuZV9pZCIsICJjZHNfbGVuZ3RoIildCmNvbG5hbWVzKGhzX2xlbmd0aCkgPC0gYygiSUQiLCAibGVuZ3RoIikKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyBkb2N1bWVudCBpcyBpbnRlbmRlZCB0byBwcm92aWRlIGFuIG92ZXJ2aWV3IG9mIFRNUkMzIHNhbXBsZXMgd2hpY2ggaGF2ZQpiZWVuIHNlcXVlbmNlZC4gIEl0IGluY2x1ZGVzIHNvbWUgcGxvdHMgYW5kIGFuYWx5c2VzIHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcHMKYW1vbmcgdGhlIHNhbXBsZXMgYXMgd2VsbCBhcyBzb21lIGRpZmZlcmVudGlhbCBhbmFseXNlcyB3aGVuIHBvc3NpYmxlLgoKIyBTYW1wbGUgRXN0aW1hdGlvbgoKIyMgR2VuZXJhdGUgZXhwcmVzc2lvbnNldHMKClRoZSBzYW1wbGUgc2hlZXQgaXMgY29waWVkIGZyb20gb3VyIHNoYXJlZCBvbmxpbmUgc2hlZXQgYW5kIHVwZGF0ZWQgd2l0aCBlYWNoIHJlbGVhc2UKb2Ygc2VxdWVuY2luZyBkYXRhLgoKCiMjIyBIaXNhdDIgZXhwcmVzc2lvbnNldHMKClRoZSBmaXJzdCB0aGluZyB0byBub3RlIGlzIHRoZSBsYXJnZSByYW5nZSBpbiBjb3ZlcmFnZS4gIFRoZXJlIGFyZSBtdWx0aXBsZQpzYW1wbGVzIHdpdGggY292ZXJhZ2Ugd2hpY2ggaXMgdG9vIGxvdyB0byB1c2UuICBUaGVzZSB3aWxsIGJlIHJlbW92ZWQgc2hvcnRseS4KCkluIHRoZSBmb2xsb3dpbmcgYmxvY2sgSSBpbW1lZGlhdGVseSBleGNsdWRlIGFueSBub24tY29kaW5nIHJlYWRzIGFzIHdlbGwuCgpgYGB7ciBhbGxfbmV3X2hpc2F0Mn0KIyMgQ3JlYXRlIHRoZSBleHByZXNzaW9uc2V0IGFuZCBpbW1lZGlhdGVseSBwYXNzIGl0IHRvIGEgZmlsdGVyCiMjIHJlbW92aW5nIHRoZSBub24gcHJvdGVpbiBjb2RpbmcgZ2VuZXMuCnNhbml0aXplX2NvbHVtbnMgPC0gYygidmlzaXRudW1iZXIiLCAiY2xpbmljYWxvdXRjb21lIiwgImRvbm9yIiwKICAgICAgICAgICAgICAgICAgICAgICJ0eXBlb2ZjZWxscyIsICJjbGluaWNhbHByZXNlbnRhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAiY29uZGl0aW9uIiwgImJhdGNoIikKaHNfZXhwdCA8LSBjcmVhdGVfZXhwdChzYW1wbGVzaGVldCwKICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbiA9ICJoZzM4MTAwaGlzYXRmaWxlIiwKICAgICAgICAgICAgICAgICAgICAgICBzYXZlZmlsZSA9IGdsdWU6OmdsdWUoInJkYS9oc19leHB0X2FsbC12e3Zlcn0ucmRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvID0gaHNfYW5ub3QpICU+JQogIGV4Y2x1ZGVfZ2VuZXNfZXhwdChjb2x1bW4gPSAiZ2VuZV9iaW90eXBlIiwgbWV0aG9kID0gImtlZXAiLAogICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gInByb3RlaW5fY29kaW5nIiwgbWV0YV9jb2x1bW4gPSAibmNybmFfbG9zdCIpICU+JQogIHNhbml0aXplX2V4cHRfbWV0YWRhdGEoY29sdW1ucyA9IHNhbml0aXplX2NvbHVtbnMpICU+JQogIHNldF9leHB0X2ZhY3RvcnMoY29sdW1ucyA9IHNhbml0aXplX2NvbHVtbnMsIGNsYXNzID0gImZhY3RvciIpCgpsZXZlbHMocERhdGEoaHNfZXhwdFtbImV4cHJlc3Npb25zZXQiXV0pW1sidmlzaXRudW1iZXIiXV0pIDwtIGxpc3QoCiAgICAnMCcgPSAibm90YXBwbGljYWJsZSIsICcxJyA9IDEsICcyJyA9IDIsICczJyA9IDMpCmBgYAoKU3BsaXQgdGhpcyBkYXRhIGludG8gQ0RTIGFuZCBsbmNSTkEuICBPaCBjcmFwIGluIG9yZGVyIHRvIGRvIHRoYXQgSSBuZWVkIHRvIHJlY291bnQgdGhlIGRhdGEuClJ1bm5pbmcgbm93ICgyMDIxMDUxOCkKCmBgYHtyIGxuY19jZHN9CiMjIGxuY19leHB0IDwtIGNyZWF0ZV9leHB0KHNhbXBsZXNoZWV0LAojIyAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbiA9ICJoZzM4MTAwbG5jZmlsZSIsCiMjICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IGhzX2Fubm90KQpgYGAKCiMjIyMgSW5pdGlhbCBtZXRyaWNzCgpPbmNlIHRoZSBkYXRhIHdhcyBsb2FkZWQsIHRoZXJlIGFyZSBhIGNvdXBsZSBvZiBtZXRyaWNzIHdoaWNoIG1heSBiZSBwbG90dGVkIGltbWVkaWF0ZWx5LgoKYGBge3IgaW5pdGlhbF9tZXRyaWNzfQpub256ZXJvIDwtIHBsb3Rfbm9uemVybyhoc19leHB0KQpub256ZXJvJHBsb3QKCm5jcm5hX2xvc3RfZGYgPC0gYXMuZGF0YS5mcmFtZShwRGF0YShoc19leHB0KVtbIm5jcm5hX2xvc3QiXV0pCnJvd25hbWVzKG5jcm5hX2xvc3RfZGYpIDwtIHJvd25hbWVzKHBEYXRhKGhzX2V4cHQpKQpjb2xuYW1lcyhuY3JuYV9sb3N0X2RmKSA8LSAibmNybmFfbG9zdCIKCnRtcGRmIDwtIG1lcmdlKG5vbnplcm8kdGFibGUsIG5jcm5hX2xvc3RfZGYsIGJ5ID0gInJvdy5uYW1lcyIpCnJvd25hbWVzKHRtcGRmKSA8LSB0bXBkZltbIlJvdy5uYW1lcyJdXQp0bXBkZltbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCgpnZ3Bsb3QodG1wZGYsIGFlcyh4PW5jcm5hX2xvc3QsIHk9bm9uemVyb19nZW5lcykpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KCkgKwogIGdncGxvdDI6OmdndGl0bGUoIk5vbnplcm8gZ2VuZXMgd2l0aCByZXNwZWN0IHRvIHBlcmNlbnQgY291bnRzIApsb3N0IHdoZW4gbmNSTkEgd2FzIHJlbW92ZWQuIikKYGBgCgpOYWppYiBkb2Vzbid0IHdhbnQgdGhpcyBwbG90LCBidXQgSSBhbSB1c2luZyBpdCB0byBjaGVjayBuZXcgc2FtcGxlcywKc28gd2lsbCBoaWRlIGl0IGZyb20gZ2VuZXJhbCB1c2UuCgpgYGB7ciBsaWJzaXplfQpsaWJzaXplIDwtIHBsb3RfbGlic2l6ZShoc19leHB0KQpsaWJzaXplJHBsb3QKYGBgCgojIyBNaW5pbXVtIGNvdmVyYWdlIHNhbXBsZSBmaWx0ZXJpbmcKCkkgYXJiaXRyYXJpbHkgY2hvc2UgMTEsMDAwIG5vbi16ZXJvIGdlbmVzIGFzIGEgbWluaW11bS4gIFdlIG1heQp3YW50IHRoaXMgdG8gYmUgaGlnaGVyLgoKYGBge3IgaGlzYXQyX3dyaXRlLCBmaWcuc2hvdyA9ICJoaWRlIn0KaHNfdmFsaWQgPC0gc3Vic2V0X2V4cHQoaHNfZXhwdCwgbm9uemVybyA9IDExMDAwKQoKdmFsaWRfd3JpdGUgPC0gc20od3JpdGVfZXhwdChoc192YWxpZCwgZXhjZWwgPSBnbHVlKCJleGNlbC9oc192YWxpZC12e3Zlcn0ueGxzeCIpKSkKYGBgCgojIFByb2plY3QgQWltcwoKVGhlIHByb2plY3Qgc2Vla3MgdG8gZGV0ZXJtaW5lIHRoZSByZWxhdGlvbnNoaXAgb2YgdGhlIGlubmF0ZSBpbW11bmUgcmVzcG9uc2UKYW5kIGluZmxhbW1hdG9yeSBzaWduYWxpbmcgdG8gdGhlIGNsaW5pY2FsIG91dGNvbWUgb2YgYW50aWxlaXNobWFuaWFsIGRydWcKdHJlYXRtZW50LiBXZSB3aWxsIHRlc3QgdGhlIGh5cG90aGVzaXMgdGhhdCB0aGUgcHJvZmlsZSBvZiBpbm5hdGUgaW1tdW5lIGNlbGwKYWN0aXZhdGlvbiBhbmQgdGhlaXIgZHluYW1pY3MgdGhyb3VnaCB0aGUgY291cnNlIG9mIHRyZWF0bWVudCBkaWZmZXIgYmV0d2VlbiBDTApwYXRpZW50cyB3aXRoIHByb3NwZWN0aXZlbHkgZGV0ZXJtaW5lZCB0aGVyYXBldXRpYyBjdXJlIG9yIGZhaWx1cmUuCgpUaGlzIHdpbGwgYmUgYWNoaWV2ZWQgdGhyb3VnaCB0aGUgY2hhcmFjdGVyaXphdGlvbiBvZiB0aGUgaW4gdml2byBkeW5hbWljcyBvZgpibG9vZC1kZXJpdmVkIG1vbm9jeXRlLCBuZXV0cm9waGlsIGFuZCBlb3Npbm9waGlsIHRyYW5zY3JpcHRvbWUgYmVmb3JlLCBkdXJpbmcKYW5kIGF0IHRoZSBlbmQgb2YgdHJlYXRtZW50IGluIENMIHBhdGllbnRzLiBDZWxsLXR5cGUgc3BlY2lmaWMgdHJhbnNjcmlwdG9tZXMsCmNvbXBvc2l0ZSBzaWduYXR1cmVzIGFuZCB0aW1lLXJlc3BvbnNlIGV4cHJlc3Npb24gcHJvZmlsZXMgd2lsbCBiZSBjb250cmFzdGVkCmFtb25nIHBhdGllbnRzIHdpdGggdGhlcmFwZXV0aWMgY3VyZSBvciBmYWlsdXJlLgoKIyMgUHJlcGFyYXRpb24KClRvIGFkZHJlc3MgdGhlc2UsIEkgYWRkZWQgdG8gdGhlIGVuZCBvZiB0aGUgc2FtcGxlIHNoZWV0IGNvbHVtbnMgbmFtZWQKJ2NvbmRpdGlvbicsICdiYXRjaCcsICdkb25vcicsIGFuZCAndGltZScuICBUaGVzZSBhcmUgZmlsbGVkIGluIHdpdGggc2hvcnRoYW5kCnZhbHVlcyBhY2NvcmRpbmcgdG8gdGhlIGFib3ZlLgoKIyMgR2xvYmFsIHZpZXcKCkJlZm9yZSBhZGRyZXNzaW5nIHRoZSBxdWVzdGlvbnMgZXhwbGljaXRseSBieSBzdWJzZXR0aW5nIHRoZSBkYXRhLCBJIHdhbnQgdG8gZ2V0CmEgbG9vayBhdCB0aGUgc2FtcGxlcyBhcyB0aGV5IGFyZS4KCmBgYHtyIHByZV9xdWVzdGlvbnN9Cm5ld19uYW1lcyA8LSBwRGF0YShoc192YWxpZClbWyJzYW1wbGVuYW1lIl1dCmhzX3ZhbGlkIDwtIGhzX3ZhbGlkICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJjZWxsc3NvdXJjZSIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJ0eXBlb2ZjZWxscyIpICU+JQogIHNldF9leHB0X3NhbXBsZW5hbWVzKG5ld25hbWVzID0gbmV3X25hbWVzKQoKYWxsX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoaHNfdmFsaWQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSkpCgphbGxfcGNhIDwtIHBsb3RfcGNhKGFsbF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiUENBIC0gQ2VsbCB0eXBlIiwgc2l6ZV9jb2x1bW4gPSAidmlzaXRudW1iZXIiKQpwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL3RtcmMzX3BjYV9ub2xhYmVscy12e3Zlcn0ucG5nIiksIGltYWdlID0gYWxsX3BjYSRwbG90KQoKd3JpdGUuY3N2KGFsbF9wY2EkdGFibGUsIGZpbGUgPSAiY29vcmRzL2hzX2Rvbm9yX3BjYV9jb29yZHMuY3N2IikKcGxvdF9jb3JoZWF0KGFsbF9ub3JtLCBwbG90X3RpdGxlID0gIkhlaXJhcmNoaWNhbCBjbHVzdGVyaW5nOgogICAgICAgICBjZWxsIHR5cGVzIikkcGxvdApgYGAKCiMjIEV4YW1pbmUgc2FtcGxlcyByZWxldmFudCB0byBjbGluaWNhbCBvdXRjb21lCgpOb3cgbGV0IHVzIGNvbnNpZGVyIG9ubHkgdGhlIHNhbXBsZXMgZm9yIHdoaWNoIHdlIGhhdmUgYSBjbGluaWNhbCBvdXRjb21lLgpUaGVzZSBmYWxsIHByaW1hcmlseSBpbnRvIGVpdGhlciAnY3VyZWQnIG9yICdmYWlsZWQnLCBidXQgc29tZSBwZW9wbGUgaGF2ZSBub3QKeWV0IHJldHVybmVkIHRvIHRoZSBjbGluaWMgYWZ0ZXIgdGhlIGZpcnN0IG9yIHNlY29uZCB2aXNpdC4gIFRoZXNlIGFyZSBkZWVtZWQKJ2xvc3QnLgoKYGBge3IgYWxsX2NsaW5pY2FsfQpoc19jbGluaWNhbCA8LSBoc192YWxpZCAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gInR5cGVvZmNlbGxzIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0ID0gInR5cGVvZmNlbGxzIT0ncGJtY3MnJnR5cGVvZmNlbGxzIT0nbWFjcm9waGFnZXMnIikKCmNob3Nlbl9jb2xvcnMgPC0gYygiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiMxQjlFNzciLCAiI0ZGMDAwMCIsICIjRkYwMDAwIikKbmFtZXMoY2hvc2VuX2NvbG9ycykgPC0gYygiY3VyZSIsICJmYWlsdXJlIiwgImxvc3QiLCAibnVsbCIsICJub3RhcHBsaWNhYmxlIikKaHNfY2xpbmljYWwgPC0gc2V0X2V4cHRfY29sb3JzKGhzX2NsaW5pY2FsLCBjb2xvcnMgPSBjaG9zZW5fY29sb3JzKQoKbmV3bmFtZXMgPC0gbWFrZS5uYW1lcyhwRGF0YShoc19jbGluaWNhbClbWyJzYW1wbGVuYW1lIl1dLCB1bmlxdWUgPSBUUlVFKQpoc19jbGluaWNhbCA8LSBzZXRfZXhwdF9zYW1wbGVuYW1lcyhoc19jbGluaWNhbCwgbmV3bmFtZXMgPSBuZXduYW1lcykKCmhzX2NsaW5pY2FsX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoaHNfY2xpbmljYWwsIGZpbHRlciA9IFRSVUUsIHRyYW5zZm9ybSA9ICJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gImNwbSIsIG5vcm0gPSAicXVhbnQiKSkKY2xpbmljYWxfcGNhIDwtIHBsb3RfcGNhKGhzX2NsaW5pY2FsX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBzaXplX2NvbHVtbiA9ICJ2aXNpdG51bWJlciIsIGNpcyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIlBDQSAtIGNsaW5pY2FsIHNhbXBsZXMiKQpwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL2FsbF9jbGluaWNhbF9ub2JhdGNoX3BjYS12e3Zlcn0ucG5nIiksIGltYWdlID0gY2xpbmljYWxfcGNhJHBsb3QsCiAgIGhlaWdodCA9IDgsIHdpZHRoID0gMjApCmBgYAoKIyMjIFJlcGVhdCB3aXRob3V0IHRoZSBiaW9wc3kgc2FtcGxlcwoKYGBge3IgaWJpZF9ub2Jpb3BzeX0KaHNfY2xpbmljYWxfbm9iaW9wIDwtIGhzX2NsaW5pY2FsICU+JQogIHN1YnNldF9leHB0KHN1YnNldCA9ICJ0eXBlb2ZjZWxscyE9J2Jpb3BzeSciKQoKaHNfY2xpbmljYWxfbm9iaW9wX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoaHNfY2xpbmljYWxfbm9iaW9wLCBmaWx0ZXIgPSBUUlVFLCB0cmFuc2Zvcm0gPSAibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQgPSAiY3BtIiwgbm9ybSA9ICJxdWFudCIpKQpjbGluaWNhbF9ub2Jpb3BfcGNhIDwtIHBsb3RfcGNhKGhzX2NsaW5pY2FsX25vYmlvcF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFLCBjaXMgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiUENBIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIikKcHAoZmlsZSA9IGdsdWUoImltYWdlcy9hbGxfY2xpbmljYWxfbm9iaW9wX25vYmF0Y2hfcGNhLXZ7dmVyfS5wbmciKSwKICAgaW1hZ2UgPSBjbGluaWNhbF9ub2Jpb3BfcGNhJHBsb3QpCmBgYAoKIyMjIEF0dGVtcHQgdG8gY29ycmVjdCBmb3IgdGhlIHN1cnJvZ2F0ZSB2YXJpYWJsZXMKCkF0IHRoaXMgdGltZSB3ZSBoYXZlIHR3byBwcmltYXJ5IGRhdGEgc3RydWN0dXJlcyBvZiBpbnRlcmVzdDogaHNfY2xpbmljYWwgYW5kIGhzX2NsaW5pY2FsX25vYmlvcAoKYGBge3IgY2xpbmljYWxfc3ZhfQpoc19jbGluaWNhbF9uYiA8LSBub3JtYWxpemVfZXhwdChoc19jbGluaWNhbCwgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIpCmNsaW5pY2FsX2JhdGNoX3BjYSA8LSBwbG90X3BjYShoc19jbGluaWNhbF9uYiwgcGxvdF9sYWJlbHMgPSBGQUxTRSwgY2lzID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVfY29sdW1uID0gInZpc2l0bnVtYmVyIiwgcGxvdF90aXRsZSA9ICJQQ0EgLSBjbGluaWNhbCBzYW1wbGVzIikKY2xpbmljYWxfYmF0Y2hfcGNhJHBsb3QKCmhzX2NsaW5pY2FsX25vYmlvcF9uYiA8LSBzbShub3JtYWxpemVfZXhwdChoc19jbGluaWNhbF9ub2Jpb3AsIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIikpCmNsaW5pY2FsX25vYmlvcF9iYXRjaF9wY2EgPC0gcGxvdF9wY2EoaHNfY2xpbmljYWxfbm9iaW9wX25iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGUgPSAiUENBIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscyA9IEZBTFNFKQpwcChmaWxlID0gImltYWdlcy9jbGluaWNhbF9iYXRjaC5wbmciLCBpbWFnZSA9IGNsaW5pY2FsX25vYmlvcF9iYXRjaF9wY2EkcGxvdCkKdGVzdCA8LSBwbG90X3BjYShoc19jbGluaWNhbF9ub2Jpb3BfbmIsIHNpemVfY29sdW1uID0gInZpc2l0bnVtYmVyIiwKICAgICAgICAgICAgICAgICBwbG90X3RpdGxlID0gIlBDQSAtIGNsaW5pY2FsIHNhbXBsZXMgd2l0aG91dCBiaW9wc2llcyIsCiAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGQUxTRSkKdGVzdCRwbG90CgpjbGluaWNhbF9ub2Jpb3BfYmF0Y2hfdHNuZSA8LSBwbG90X3RzbmUoaHNfY2xpbmljYWxfbm9iaW9wX25iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZSA9ICJ0U05FIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRkFMU0UpCmNsaW5pY2FsX25vYmlvcF9iYXRjaF90c25lJHBsb3QKYGBgCgojIyMjIExvb2sgYXQgcmVtYWluaW5nIHZhcmlhbmNlIHdpdGggdmFyaWFuY2VQYXJ0aXRpb24KCmBgYHtyIHZhcmlhbmNlX3BhcnRpdGlvbn0KdGVzdCA8LSBzaW1wbGVfdmFycGFydChoc19jbGluaWNhbF9ub2Jpb3ApCnRlc3QkcGFydGl0aW9uX3Bsb3QKYGBgCgojIyBQZXJmb3JtIERFIG9mIHRoZSBjbGluaWNhbCBzYW1wbGVzIGN1cmUgdnMuIGZhaWwKCmBgYHtyIGNsaW5pY2FsX2RlLCBmaWcuc2hvdz0iaGlkZSJ9CmluZGl2aWR1YWxfY2VsbHR5cGVzIDwtIHN1YnNldF9leHB0KGhzX2NsaW5pY2FsX25vYmlvcCwgc3Vic2V0PSJjb25kaXRpb24hPSdsb3N0JyIpCmhzX2NsaW5pY19kZSA8LSBzbShhbGxfcGFpcndpc2UoaW5kaXZpZHVhbF9jZWxsdHlwZXMsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpKQoKaHNfY2xpbmljX3RhYmxlIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgaHNfY2xpbmljX2RlLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9pbmRpdmlkdWFsX2NlbGx0eXBlc190YWJsZS12e3Zlcn0ueGxzeCIpKSkKCmhzX2NsaW5pY19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGhzX2NsaW5pY190YWJsZSwKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvaW5kaXZpZHVhbF9jZWxsdHlwZXNfc2lnLXZ7dmVyfS54bHN4IikpKQoKaHNfY2xpbmljX3NpZ1tbInN1bW1hcnlfZGYiXV0KYGBgCgpgYGB7ciBkZV9oZWF0bWFwfQpoc19jbGluaWNfZGVbWyJjb21wYXJpc29uIl1dW1siaGVhdCJdXQpgYGAKCiMjIyBQZXJmb3JtIExSVCB3aXRoIHRoZSBjbGluaWNhbCBzYW1wbGVzCgpJIGFtIG5vdCBzdXJlIGlmIHdlIGhhdmUgZW5vdWdoIHNhbXBsZXMgYWNyb3NzIHRoZSB0aHJlZSB2aXNpdCB0bwpjb21wbGV0ZWx5IHdvcmsgYXMgd2VsbCBhcyB3ZSB3b3VsZCBsaWtlLCBidXQgdGhlcmUgaXMgb25seSAxIHdheSB0bwpmaW5kIG91dCEgIE5vdyB0aGF0IEkgdGhpbmsgYWJvdXQgaXQsIG9uZSB0aGluZyB3aGljaCBtaWdodCBiZSBhd2Vzb21lCmlzIHRvIHVzZSBjZWxsIHR5cGUgYXMgYW4gaW50ZXJhY3RpbmcgZmFjdG9yLi4uCgojIyMjIFdpdGggYmlvcHN5IHNhbXBsZXMKCkkgZmlndXJlIHRoaXMgbWlnaHQgYmUgYSBwbGFjZSB3aGVyZSB0aGUgYmlvcHN5IHNhbXBsZXMgbWlnaHQgcHJvdmUgdXNlZnVsLgoKYGBge3IgbHJ0X3Rlc3R9CmNsaW5pY2FsX25vbG9zdCA8LSBzdWJzZXRfZXhwdChoc19jbGluaWNhbCwgc3Vic2V0PSJjb25kaXRpb24hPSdsb3N0JyIpCmxydF92aXNpdF9jbGluaWNhbF90ZXN0IDwtIHNtKGRlc2VxX2xydChjbGluaWNhbF9ub2xvc3QsIHRyYW5zZm9ybSA9ICJ2c3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rvcl9jb2x1bW4gPSAidmlzaXRudW1iZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJlc3RfY29sdW1uID0gImNsaW5pY2Fsb3V0Y29tZSIpKQpscnRfdmlzaXRfY2xpbmljYWxfdGVzdFtbImZhdm9yaXRlX2dlbmVzIl1dCgpscnRfY2VsbHR5cGVfY2xpbmljYWxfdGVzdCA8LSBzbShkZXNlcV9scnQoY2xpbmljYWxfbm9sb3N0LCB0cmFuc2Zvcm0gPSAidnN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyYWN0b3JfY29sdW1uID0gInR5cGVvZmNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyZXN0X2NvbHVtbiA9ICJjbGluaWNhbG91dGNvbWUiKSkKc3VtbWFyeShscnRfY2VsbHR5cGVfY2xpbmljYWxfdGVzdFtbImZhdm9yaXRlX2dlbmVzIl1dKQpgYGAKCiMjIyBMb29rIGF0IG9ubHkgdGhlIGRpZmZlcmVudGlhbCBnZW5lcwoKQSBnb29kIHN1Z2dlc3Rpb24gZnJvbSBUaGVyZXNhIHdhcyB0byBleGFtaW5lIG9ubHkgdGhlIG1vc3QgdmFyaWFudApnZW5lcyBmcm9tIGZhaWx1cmUgdnMuIGN1cmUgYW5kIHNlZSBob3cgdGhleSBjaGFuZ2UgdGhlIGNsdXN0ZXJpbmcvZXRjCnJlc3VsdHMuICBUaGlzIGlzIG15IGF0dGVtcHQgdG8gYWRkcmVzcyB0aGlzIHF1ZXJ5LgoKYGBge3Igc21hbGxfZXhwbG9yZX0KaHNfY2xpbmljX3RvcG4gPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhoc19jbGluaWNfdGFibGUsIG4gPSAxMDApKQp0YWJsZSA8LSAiZmFpbHVyZV92c19jdXJlIgp3YW50ZWQgPC0gcmJpbmQoaHNfY2xpbmljX3RvcG5bWyJkZXNlcSJdXVtbInVwcyJdXVtbdGFibGVdXSwKICAgICAgICAgICAgICAgIGhzX2NsaW5pY190b3BuW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbdGFibGVdXSkKCnNtYWxsX2V4cHQgPC0gZXhjbHVkZV9nZW5lc19leHB0KGhzX2NsaW5pY2FsX25vYmlvcCwgaWRzID0gcm93bmFtZXMod2FudGVkKSwgbWV0aG9kID0gImtlZXAiKQpzbWFsbF9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KHNtYWxsX2V4cHQsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKSkKcGxvdF9wY2Eoc21hbGxfbm9ybSkkcGxvdAoKc21hbGxfbmIgPC0gbm9ybWFsaXplX2V4cHQoc21hbGxfZXhwdCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gInN2YXNlcSIsIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQpwbG90X3BjYShzbWFsbF9uYikkcGxvdApgYGAKCmBgYHtyIGNsaW5pY2FsX3Bsb3R9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmhzX2NsaW5pY190YWJsZVtbInBsb3RzIl1dW1siZmFpbHVyZV92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpoc19jbGluaWNfdGFibGVbWyJwbG90cyJdXVtbImZhaWx1cmVfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CmBgYAoKIyMjIGc6UHJvZmlsZXIgcmVzdWx0cyB1c2luZyB0aGUgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMKCmBgYHtyIHBlcmZvcm1fZ3Byb2ZpbGVyfQp1cHMgPC0gaHNfY2xpbmljX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0KZG93bnMgPC0gaHNfY2xpbmljX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXQoKaHNfY2xpbmljX2dwcm9maWxlcl91cHMgPC0gc2ltcGxlX2dwcm9maWxlcih1cHMpCmhzX2NsaW5pY19ncHJvZmlsZXJfdXBzW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQpoc19jbGluaWNfZ3Byb2ZpbGVyX3Vwc1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KaHNfY2xpbmljX2dwcm9maWxlcl91cHNbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KCiMjaHNfdHJ5MiA8LSBzaW1wbGVfZ3Byb2ZpbGVyMih1cHMpCgpoc19jbGluaWNfZ3Byb2ZpbGVyX2Rvd25zIDwtIHNpbXBsZV9ncHJvZmlsZXIoZG93bnMpCmhzX2NsaW5pY19ncHJvZmlsZXJfZG93bnNbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCmhzX2NsaW5pY19ncHJvZmlsZXJfZG93bnNbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmhzX2NsaW5pY19ncHJvZmlsZXJfZG93bnNbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KYGBgCgojIyBQZXJmb3JtIEdTVkEgb24gdGhlIGNsaW5pY2FsIHNhbXBsZXMKCmBgYHtyIGdzdmEsIGZpZy5zaG93ID0gImhpZGUifQpoc19jZWxsdHlwZV9nc3ZhX2MyIDwtIHNtKHNpbXBsZV9nc3ZhKGluZGl2aWR1YWxfY2VsbHR5cGVzKSkKaHNfY2VsbHR5cGVfZ3N2YV9jMl9zaWcgPC0gc20oZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoCiAgICBoc19jZWxsdHlwZV9nc3ZhX2MyLAogICAgZXhjZWwgPSAiZXhjZWwvaW5kaXZpZHVhbF9jZWxsdHlwZXNfZ3N2YV9jMi54bHN4IikpCgpicm9hZF9jNyA8LSBHU0VBQmFzZTo6Z2V0R210KCJyZWZlcmVuY2UvbXNpZ2RiL2M3LmFsbC52Ny4yLmVudHJlei5nbXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb25UeXBlID0gR1NFQUJhc2U6OkJyb2FkQ29sbGVjdGlvbihjYXRlZ29yeSA9ICJjNyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVJZFR5cGUgPSBHU0VBQmFzZTo6RW50cmV6SWRlbnRpZmllcigpKQpoc19jZWxsdHlwZV9nc3ZhX2M3IDwtIHNtKHNpbXBsZV9nc3ZhKGluZGl2aWR1YWxfY2VsbHR5cGVzLCBzaWduYXR1cmVzID0gYnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNpZ194bWwgPSAicmVmZXJlbmNlL21zaWdkYl92Ny4yLnhtbCIsIGNvcmVzID0gMTApKQpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZyA8LSBzbShnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIGhzX2NlbGx0eXBlX2dzdmFfYzcsCiAgICBleGNlbCA9ICJleGNlbC9pbmRpdmlkdWFsX2NlbGx0eXBlc19nc3ZhX2M3Lnhsc3giKSkKYGBgCgojIyMgUHJpbnQgc29tZSBwbG90cyBvZiB0aGUgR1NWQSBvdXRwdXRzCgpgYGB7ciBnc3ZhX3Bsb3RzfQojIyBUaGUgcmF3IGhlYXRtYXAgb2YgdGhlIEMyIHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZ1tbInJhd19wbG90Il1dCiMjIFRoZSAnc2lnbmlmaWNhbmNlJyBzY29yZXMgb2YgdGhlIEMyIHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZ1tbInNjb3JlX3Bsb3QiXV0KIyMgVGhlIHN1YnNldCBvZiBzY29yZXMgZm9yIGNhdGVnb3JpZXMgZGVlbWVkIHNpZ25pZmljYW50bHkgZGlmZmVyZW50Lgpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZ1tbInN1YnNldF9wbG90Il1dCgojIyBUaGUgcmF3IGhlYXRtYXAgb2YgdGhlIEM3IHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZ1tbInJhd19wbG90Il1dCiMjIFRoZSAnc2lnbmlmaWNhbmNlJyBzY29yZXMgb2YgdGhlIEM3IHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZ1tbInNjb3JlX3Bsb3QiXV0KIyMgVGhlIHN1YnNldCBvZiBzY29yZXMgZm9yIGNhdGVnb3JpZXMgZGVlbWVkIHNpZ25pZmljYW50bHkgZGlmZmVyZW50Lgpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZ1tbInN1YnNldF9wbG90Il1dCmBgYAoKIyBJbmRpdmlkdWFsIENlbGwgdHlwZXMKClRoZSBmb2xsb3dpbmcgYmxvY2tzIHNwbGl0IHRoZSBzYW1wbGVzIGludG8gYSBmZXcgZ3JvdXBzIGJ5IHNhbXBsZSB0eXBlIGFuZCBsb29rCmF0IHRoZSBkaXN0cmlidXRpb25zIGJldHdlZW4gdGhlbS4KCiMjIEltcGxlbWVudGF0aW9uIGRldGFpbHMKCkdldCB0b3AvYm90dG9tIG4gZ2VuZXMgZm9yIGVhY2ggY2VsbCB0eXBlLCB1c2luZyBjbGluaWNhbCBvdXRjb21lIGFzIHRoZSBmYWN0b3Igb2YgaW50ZXJlc3QuCkZvciB0aGUgbW9tZW50LCB1c2Ugc3ZhIGZvciB0aGUgREUgYW5hbHlzaXMuClByb3ZpZGUgY3BtcyBmb3IgdGhlIHRvcC9ib3R0b20gbiBnZW5lcy4KClN0YXJ0IHdpdGggdG9wL2JvdHRvbSAyMDAuClBlcmZvcm0gZGVmYXVsdCBsb2dGQyBhbmQgcC12YWx1ZSBhcyB3ZWxsLgoKIyMjIFNoYXJlZCBjb250cmFzdHMKCkhlcmUgaXMgdGhlIGNvbnRyYXN0IHdlIHdpbGwgdXNlIHRocm91Z2hwdXQsIEkgYW0gbGVhdmluZyBvcGVuIHRoZSBvcHRpb24gdG8gYWRkIG1vcmUuCgpgYGB7ciBrZWVwZXJzfQprZWVwZXJzIDwtIGxpc3QoCiAgImZhaWxfdnNfY3VyZSIgPSBjKCJmYWlsdXJlIiwgImN1cmUiKSkKYGBgCgojIyBNb25vY3l0ZXMKCiMjIyBFdmFsdWF0ZSBNb25vY3l0ZSBzYW1wbGVzCgpgYGB7ciBtb25vY3l0ZXN9Cm1vbm8gPC0gc3Vic2V0X2V4cHQoaHNfdmFsaWQsIHN1YnNldCA9ICJ0eXBlb2ZjZWxscz09J21vbm9jeXRlcyciKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImRvbm9yIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9ycyA9IGNob3Nlbl9jb2xvcnMpCiMjIEZJWE1FIHNldF9leHB0X2NvbG9ycyBzaG91bGQgc3BlYWsgdXAgaWYgdGhlcmUgYXJlIG1pc21hdGNoZXMgaGVyZSEhIQoKc2F2ZV9yZXN1bHQgPC0gc2F2ZShtb25vLCBmaWxlID0gInJkYS9tb25vY3l0ZV9leHB0LnJkYSIpCm1vbm9fbm9ybSA8LSBub3JtYWxpemVfZXhwdChtb25vLCBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIG5vcm0gPSAicXVhbnQiKQpwbHQgPC0gcGxvdF9wY2EobW9ub19ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKSRwbG90CnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvbW9ub19wY2Ffbm9ybWFsaXplZC12e3Zlcn0ucGRmIiksIGltYWdlID0gcGx0KQoKbW9ub19uYiA8LSBub3JtYWxpemVfZXhwdChtb25vLCBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBiYXRjaCA9ICJzdmFzZXEiKQpwbHQgPC0gcGxvdF9wY2EobW9ub19uYiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkkcGxvdApwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL21vbm9fcGNhX25vcm1hbGl6ZWRfYmF0Y2gtdnt2ZXJ9LnBkZiIpLCBpbWFnZSA9IHBsdCkKYGBgCgojIyMgREUgb2YgTW9ub2N5dGUgc2FtcGxlcwoKIyMjIyBXaXRob3V0IHN2YQoKYGBge3IgZGVfbW9ub2N5dGUsIGZpZy5zaG93ID0gImhpZGUifQptb25vX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShtb25vLCBtb2RlbF9iYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKbW9ub190YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBtb25vX2RlLCBrZWVwZXJzID0ga2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfYWxsX3RhYmxlcy12e3Zlcn0ueGxzeCIpKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBtb25vX3RhYmxlc1tbImRhdGEiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfdGFibGUtdnt2ZXJ9Lnhsc3giKSkKbW9ub19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhtb25vX3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbW9ub19zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9zaWd1cC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG1vbm9fc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9zaWdkb3duLXZ7dmVyfS54bHN4IikpCgptb25vX3BjdF9zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhtb25vX3RhYmxlcywgbiA9IDIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGZjID0gTlVMTCwgcCA9IE5VTEwsIGFjY29yZGluZ190byA9ICJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG1vbm9fcGN0X3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ3VwX3BjdC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG1vbm9fcGN0X3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfc2lnZG93bl9wY3Qtdnt2ZXJ9Lnhsc3giKSkKbW9ub19zaWckc3VtbWFyeV9kZgoKIyMgUHJpbnQgb3V0IGEgdGFibGUgb2YgdGhlIGNwbSB2YWx1ZXMgZm9yIG90aGVyIGV4cGxvcmF0aW9ucy4KbW9ub19jcG0gPC0gc20obm9ybWFsaXplX2V4cHQobW9ubywgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhtb25vX2NwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NwbV9iZWZvcmVfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKbW9ub19iY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1vbm8sIGZpbHRlciA9IFRSVUUsIGNvbnZlcnQgPSAiY3BtIiwgYmF0Y2ggPSAic3Zhc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZXhwcnMobW9ub19iY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBXaXRoIHN2YQoKYGBge3IgZGVfbW9ub19zdmEsIGZpZy5zaG93ID0gImhpZGUifQptb25vX2RlX3N2YSA8LSBzbShhbGxfcGFpcndpc2UobW9ubywgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkpCm1vbm9fdGFibGVzX3N2YSA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIG1vbm9fZGVfc3ZhLCBrZWVwZXJzID0ga2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfYWxsX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSkpCm1vbm9fc2lnX3N2YSA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgbW9ub190YWJsZXNfc3ZhLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9zaWdfdGFibGVzX3N2YS12e3Zlcn0ueGxzeCIpLAogICAgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCmBgYAoKIyMjIyBNb25vY3l0ZSBERSBwbG90cwoKRmlyc3QgcHJpbnQgb3V0IHRoZSBERSBwbG90cyB3aXRob3V0IGFuZCB0aGVuIHdpdGggc3ZhIGVzdGltYXRlcy4KCmBgYHtyIG1vbm9fZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm1vbm9fdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm1vbm9fdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUgd2l0aCBzdmFzZXEKbW9ub190YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3Zhc2VxCm1vbm9fdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIyMjIE1vbm9jeXRlIG9udG9sb2d5IHNlYXJjaAoKYGBge3IgbW9ub19ncHJvZmlsZXJ9CnVwcyA8LSBtb25vX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siZmFpbF92c19jdXJlIl1dCmRvd25zIDwtIG1vbm9fc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImZhaWxfdnNfY3VyZSJdXQoKbW9ub191cF9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNpZ19nZW5lcyA9IHVwcykKbW9ub191cF9ncFtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KbW9ub191cF9ncFtbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KbW9ub191cF9ncFtbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQoKbW9ub19kb3duX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzID0gZG93bnMpCm1vbm9fZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KbW9ub19kb3duX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQptb25vX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KYGBgCgojIyMjIE1vbm9jeXRlIE1TaWdEQiBxdWVyeQoKYGBge3IgbXNpZ19tb25vX2dvc2VxLCBmaWcuc2hvdyA9ICJoaWRlIn0KYnJvYWRfYzcgPC0gR1NFQUJhc2U6OmdldEdtdCgicmVmZXJlbmNlL21zaWdkYi9jNy5hbGwudjcuMi5lbnRyZXouZ210IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsZWN0aW9uVHlwZSA9IEdTRUFCYXNlOjpCcm9hZENvbGxlY3Rpb24oY2F0ZWdvcnkgPSAiYzciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lSWRUeXBlID0gR1NFQUJhc2U6OkVudHJleklkZW50aWZpZXIoKSkKCm1vbm9fdXBfZ29zZXFfbXNpZyA8LSBnb3NlcV9tc2lnZGIoc2lnX2dlbmVzID0gdXBzLCBzaWduYXR1cmVzID0gYnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlX2NhdGVnb3J5ID0gImM3IiwgbGVuZ3RoX2RiID0gaHNfbGVuZ3RoKQoKbW9ub19kb3duX2dvc2VxX21zaWcgPC0gZ29zZXFfbXNpZ2RiKHNpZ19nZW5lcyA9IGRvd25zLCBzaWduYXR1cmVzID0gYnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVfY2F0ZWdvcnkgPSAiYzciLCBsZW5ndGhfZGIgPSBoc19sZW5ndGgpCmBgYAoKIyMjIyBQbG90IG9mIHNpbWlsYXIgZXhwZXJpbWVudHMKCmBgYHtyIG1zaWdfcGxvdHN9CiMjIE1vbm9jeXRlIGdlbmVzIHdpdGggaW5jcmVhc2VkIGV4cHJlc3Npb24gaW4gdGhlIGZhaWxlZCBzYW1wbGVzCiMjIHNoYXJlIGdlbmVzIHdpdGggdGhlIGZvbGxvd2luZyBleHBlcmltZW50cwptb25vX3VwX2dvc2VxX21zaWdbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCgojIyBNb25vY3l0ZSBnZW5lcyB3aXRoIGluY3JlYXNlZCBleHByZXNzaW9uIGluIHRoZSBjdXJlZCBzYW1wbGVzCiMjIHNoYXJlIGdlbmVzIHdpdGggdGhlIGZvbGxvd2luZyBleHBlcmltZW50cwptb25vX2Rvd25fZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KYGBgCgojIyMgRXZhbHVhdGUgTmV1dHJvcGhpbCBzYW1wbGVzCgpgYGB7ciBuZXV0cm9waGlsc30KbmV1dCA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0ID0gInR5cGVvZmNlbGxzPT0nbmV1dHJvcGhpbHMnIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJkb25vciIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnMgPSBjaG9zZW5fY29sb3JzKQoKc2F2ZV9yZXN1bHQgPC0gc2F2ZShuZXV0LCBmaWxlID0gInJkYS9uZXV0cm9waGlsX2V4cHQucmRhIikKbmV1dF9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG5ldXQsIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSwgdHJhbnNmb3JtID0gImxvZzIiKSkKcGx0IDwtIHBsb3RfcGNhKG5ldXRfbm9ybSwgcGxvdF9sYWJlbHMgPSBGQUxTRSkkcGxvdApwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL25ldXRfcGNhX25vcm1hbGl6ZWQtdnt2ZXJ9LnBkZiIpLCBpbWFnZSA9IHBsdCkKCm5ldXRfbmIgPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikpCnBsdCA8LSBwbG90X3BjYShuZXV0X25iLCBwbG90X2xhYmVscyA9IEZBTFNFKSRwbG90CnBwKGZpbGUgPSBnbHVlKCJpbWFnZXMvbmV1dF9wY2Ffbm9ybWFsaXplZF9zdmFzZXEtdnt2ZXJ9LnBkZiIpLCBpbWFnZSA9IHBsdCkKYGBgCgojIyMgREUgb2YgTmV0cm9waGlsIHNhbXBsZXMKCiMjIyMgV2l0aG91dCBzdmEKCmBgYHtyIG5ldXRyb3BoaWxfZGUsIGZpZy5zaG93ID0gImhpZGUifQpuZXV0X2RlIDwtIHNtKGFsbF9wYWlyd2lzZShuZXV0LCBtb2RlbF9iYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKbmV1dF90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBuZXV0X2RlLCBrZWVwZXJzID0ga2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbmV1dHJvcGhpbF9jbGluaWNhbF9hbGxfdGFibGVzLXZ7dmVyfS54bHN4IikpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG5ldXRfdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3RhYmxlLXZ7dmVyfS54bHN4IikpCm5ldXRfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMobmV1dF90YWJsZXMsIGFjY29yZGluZ190byA9ICJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG5ldXRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbmV1dHJvcGhpbF9jbGluaWNhbF9zaWd1cC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG5ldXRfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ2Rvd24tdnt2ZXJ9Lnhsc3giKSkKCm5ldXRfcGN0X3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG5ldXRfdGFibGVzLCBuID0gMjAwLCBsZmMgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwID0gTlVMTCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ3VwX3BjdC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IG5ldXRfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ2Rvd25fcGN0LXZ7dmVyfS54bHN4IikpCm5ldXRfY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG5ldXQsIGNvbnZlcnQgPSAiY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZXhwcnMobmV1dF9jcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NwbV9iZWZvcmVfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKbmV1dF9iY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG5ldXQsIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIsIGNvbnZlcnQgPSAiY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZXhwcnMobmV1dF9iY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbmV1dHJvcGhpbF9jcG1fYWZ0ZXJfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMjIFdpdGggc3ZhCgpgYGB7ciBkZV9uZXV0X3N2YSwgZmlnLnNob3cgPSAiaGlkZSJ9Cm5ldXRfZGVfc3ZhIDwtIHNtKGFsbF9wYWlyd2lzZShuZXV0LCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKSkKbmV1dF90YWJsZXNfc3ZhIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgbmV1dF9kZV9zdmEsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX2FsbF90YWJsZXNfc3ZhLXZ7dmVyfS54bHN4IikpKQpuZXV0X3NpZ19zdmEgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIG5ldXRfdGFibGVzX3N2YSwKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvbmV1dHJvcGhpbF9jbGluaWNhbF9zaWdfdGFibGVzX3N2YS12e3Zlcn0ueGxzeCIpLAogICAgYWNjb3JkaW5nX3RvID0gImRlc2VxIikpCmBgYAoKIyMjIyBOZXV0cm9waGlsIERFIHBsb3RzCgpgYGB7ciBuZXV0X2RlX3Bsb3RzfQojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpuZXV0X3RhYmxlc1tbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpuZXV0X3RhYmxlc1tbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3ZhCm5ldXRfdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZSB3aXRoIHN2YQpuZXV0X3RhYmxlc19zdmFbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CmBgYAoKIyMjIyBOZXV0cm9waGlsIG9udG9sb2d5IHNlYXJjaAoKYGBge3IgbmV1dF9ncH0KdXBzIDwtIG5ldXRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KZG93bnMgPC0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siZmFpbF92c19jdXJlIl1dCgpuZXV0X3VwX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzID0gdXBzKQpuZXV0X3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQpuZXV0X3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpuZXV0X3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sicmVhY3RvbWVfcGxvdF9vdmVyIl1dCgpuZXV0X2Rvd25fZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihkb3ducykKbmV1dF9kb3duX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQpuZXV0X2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCm5ldXRfZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyMgTmV1dHJvcGhpbCBHU1ZBIHF1ZXJ5CgpgYGB7ciBtc2lnX25ldXRfZ29zZXEsIGZpZy5zaG93ID0gImhpZGUifQpuZXV0X3VwX2dvc2VxX21zaWcgPC0gZ29zZXFfbXNpZ2RiKHNpZ19nZW5lcyA9IHVwcywgc2lnbmF0dXJlcyA9IGJyb2FkX2M3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJjNyIsIGxlbmd0aF9kYiA9IGhzX2xlbmd0aCkKCm5ldXRfZG93bl9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXMgPSBkb3ducywgc2lnbmF0dXJlcyA9IGJyb2FkX2M3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlX2NhdGVnb3J5ID0gImM3IiwgbGVuZ3RoX2RiID0gaHNfbGVuZ3RoKQpgYGAKCiMjIyMgUGxvdCBvZiBzaW1pbGFyIGV4cGVyaW1lbnRzCgpgYGB7ciBtc2lnX3Bsb3RzX25ldXR9CiMjIE5ldXRyb3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgZmFpbGVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCm5ldXRfdXBfZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KCiMjIE5ldXRyb3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgY3VyZWQgc2FtcGxlcwojIyBzaGFyZSBnZW5lcyB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwZXJpbWVudHMKbmV1dF9kb3duX2dvc2VxX21zaWdbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmBgYAoKIyMgRW9zaW5vcGhpbHMKCiMjIyBFdmFsdWF0ZSBFb3Npbm9waGlsIHNhbXBsZXMKCmBgYHtyIGVvc2lub3BoaWxzfQplbyA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0ID0gInR5cGVvZmNlbGxzPT0nZW9zaW5vcGhpbHMnIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJkb25vciIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnMgPSBjaG9zZW5fY29sb3JzKQoKc2F2ZV9yZXN1bHQgPC0gc2F2ZShlbywgZmlsZSA9ICJyZGEvZW9zaW5vcGhpbF9leHB0LnJkYSIpCmVvX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoZW8sIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKSkKcGx0IDwtIHBsb3RfcGNhKGVvX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKcHAoZmlsZSA9IGdsdWUoImltYWdlcy9lb19wY2Ffbm9ybWFsaXplZC12e3Zlcn0ucGRmIiksIGltYWdlID0gcGx0KQoKZW9fbmIgPC0gc20obm9ybWFsaXplX2V4cHQoZW8sIGNvbnZlcnQgPSAiY3BtIiwgdHJhbnNmb3JtID0gImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiKSkKcGxvdF9wY2EoZW9fbmIpJHBsb3QKYGBgCgojIyMgREUgb2YgRW9zaW5vcGhpbCBzYW1wbGVzCgojIyMjIFdpdGhvdXRoIHN2YQoKYGBge3IgZW9zaW5vcGhpbF9kZSwgZmlnLnNob3cgPSAiaGlkZSJ9CmVvX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShlbywgbW9kZWxfYmF0Y2ggPSBGQUxTRSwgZmlsdGVyID0gVFJVRSkpCmVvX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIGVvX2RlLCBrZWVwZXJzID0ga2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9hbGxfdGFibGVzLXZ7dmVyfS54bHN4IikpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGVvX3RhYmxlc1tbImRhdGEiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF90YWJsZS12e3Zlcn0ueGxzeCIpKQplb19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhlb190YWJsZXMsIGFjY29yZGluZ190byA9ICJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YSA9IGVvX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY2xpbmljYWxfc2lndXAtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBlb19zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY2xpbmljYWxfc2lnZG93bi12e3Zlcn0ueGxzeCIpKQoKZW9fcGN0X3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGVvX3RhYmxlcywgbiA9IDIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxmYyA9IE5VTEwsIHAgPSBOVUxMLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBlb19wY3Rfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9zaWd1cF9wY3Qtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBlb19wY3Rfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX3NpZ2Rvd25fcGN0LXZ7dmVyfS54bHN4IikpCgplb19jcG0gPC0gc20obm9ybWFsaXplX2V4cHQoZW8sIGNvbnZlcnQgPSAiY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZXhwcnMoZW9fY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jcG1fYmVmb3JlX2JhdGNoLXZ7dmVyfS54bHN4IikpCmVvX2JjcG0gPC0gc20obm9ybWFsaXplX2V4cHQoZW8sIGZpbHRlciA9IFRSVUUsIGJhdGNoID0gInN2YXNlcSIsIGNvbnZlcnQgPSAiY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZXhwcnMoZW9fYmNwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBXaXRoIHN2YQoKYGBge3IgZGVfZW9fc3ZhLCBmaWcuc2hvdyA9ICJoaWRlIn0KZW9fZGVfc3ZhIDwtIHNtKGFsbF9wYWlyd2lzZShlbywgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkpCmVvX3RhYmxlc19zdmEgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBlb19kZV9zdmEsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX2FsbF90YWJsZXNfc3ZhLXZ7dmVyfS54bHN4IikpKQplb19zaWdfc3ZhIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBlb190YWJsZXNfc3ZhLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX3NpZ190YWJsZXNfc3ZhLXZ7dmVyfS54bHN4IiksCiAgICBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiKSkKYGBgCgojIyMjIEVvc2lub3BoaWwgREUgcGxvdHMKCmBgYHtyIGVvX2RlX3Bsb3RzfQojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQplb190YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX21hX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBWb2xjYW5vIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKZW9fdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUgd2l0aCBzdmEKZW9fdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZSB3aXRoIHN2YQplb190YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdApgYGAKCiMjIyMgRW9zaW5vcGhpbCBvbnRvbG9neSBzZWFyY2gKCmBgYHtyIGVvX2dwcm9maWxlcn0KdXBzIDwtIGVvX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siZmFpbF92c19jdXJlIl1dCmRvd25zIDwtIGVvX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KCmVvX3VwX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2lnX2dlbmVzID0gdXBzKQplb191cF9ncFtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KZW9fdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmVvX3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sicmVhY3RvbWVfcGxvdF9vdmVyIl1dCgplb19kb3duX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoZG93bnMpCmVvX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCmVvX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmVvX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KYGBgCgojIyMjIEVvc2lub3BoaWwgTVNpZ0RCIHF1ZXJ5CgpgYGB7ciBtc2lnX2VvX2dvc2VxLCBmaWcuc2hvdyA9ICJoaWRlIn0KZW9fdXBfZ29zZXFfbXNpZyA8LSBnb3NlcV9tc2lnZGIoc2lnX2dlbmVzID0gdXBzLCBzaWduYXR1cmVzID0gYnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJjNyIsIGxlbmd0aF9kYiA9IGhzX2xlbmd0aCkKCmVvX2Rvd25fZ29zZXFfbXNpZyA8LSBnb3NlcV9tc2lnZGIoc2lnX2dlbmVzID0gZG93bnMsIHNpZ25hdHVyZXMgPSBicm9hZF9jNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVfY2F0ZWdvcnkgPSAiYzciLCBsZW5ndGhfZGIgPSBoc19sZW5ndGgpCmBgYAoKIyMjIyBQbG90IG9mIHNpbWlsYXIgZXhwZXJpbWVudHMKCmBgYHtyIG1zaWdfcGxvdHNfZW99CiMjIEVvc2lub3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgZmFpbGVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCmVvX3VwX2dvc2VxX21zaWdbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCgojIyBFb3Npbm9waGlsIGdlbmVzIHdpdGggaW5jcmVhc2VkIGV4cHJlc3Npb24gaW4gdGhlIGN1cmVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCmVvX2Rvd25fZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KYGBgCgojIyBCaW9wc2llcwoKIyMjIEV2YWx1YXRlIEJpb3BzeSBzYW1wbGVzCgpgYGB7ciBiaW9wc2llc30KYmlvcCA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0ID0gInR5cGVvZmNlbGxzPT0nYmlvcHN5JyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJjbGluaWNhbG91dGNvbWUiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZG9ub3IiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JzID0gY2hvc2VuX2NvbG9ycykKCnNhdmVfcmVzdWx0IDwtIHNhdmUoYmlvcCwgZmlsZSA9ICJyZGEvYmlvcHN5X2V4cHQucmRhIikKYmlvcF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KGJpb3AsIGZpbHRlciA9IFRSVUUsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgbm9ybSA9ICJxdWFudCIpCnBsdCA8LSBwbG90X3BjYShiaW9wX25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UpJHBsb3QKcHAoZmlsZSA9IGdsdWUoImltYWdlcy9iaW9wX3BjYV9ub3JtYWxpemVkLXZ7dmVyfS5wZGYiKSwgaW1hZ2UgPSBwbHQpCgpiaW9wX25iIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGJpb3AsIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpKQpwbHQgPC0gcGxvdF9wY2EoYmlvcF9uYiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkkcGxvdApwcChmaWxlID0gZ2x1ZSgiaW1hZ2VzL2Jpb3BfcGNhX25vcm1hbGl6ZWRfc3Zhc2VxLXZ7dmVyfS5wZGYiKSwgaW1hZ2UgPSBwbHQpCmBgYAoKIyMjIERFIG9mIEJpb3BzeSBzYW1wbGVzCgojIyMjIFdpdGhvdXQgc3ZhCgpgYGB7ciBkZV9iaW9wc3ksIGZpZy5zaG93ID0gImhpZGUifQpiaW9wX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShiaW9wLCBtb2RlbF9iYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKSkKYmlvcF90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoYmlvcF9kZSwga2VlcGVycyA9IGtlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX2FsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBiaW9wX3RhYmxlc1tbImRhdGEiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3RhYmxlLXZ7dmVyfS54bHN4IikpCmJpb3Bfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoYmlvcF90YWJsZXMsIGFjY29yZGluZ190byA9ICJkZXNlcSIpCiMjd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBiaW9wX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiMjICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3NpZ3VwLXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gYmlvcF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jbGluaWNhbF9zaWdkb3duLXZ7dmVyfS54bHN4IikpCmJpb3BfcGN0X3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGJpb3BfdGFibGVzLCBuID0gMjAwLCBsZmMgPSBOVUxMLCBwID0gTlVMTCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIikKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBiaW9wX3BjdF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfc2lndXBfcGN0LXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gYmlvcF9wY3Rfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfc2lnZG93bl9wY3Qtdnt2ZXJ9Lnhsc3giKSkKCmJpb3BfY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGJpb3AsIGNvbnZlcnQgPSAiY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhID0gZXhwcnMoYmlvcF9jcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY3BtX2JlZm9yZV9iYXRjaC12e3Zlcn0ueGxzeCIpKQpiaW9wX2JjcG0gPC0gc20obm9ybWFsaXplX2V4cHQoYmlvcCwgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIiwgY29udmVydCA9ICJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBleHBycyhiaW9wX2JjcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyB3aXRoIHN2YQoKYGBge3IgZGVfYmlvcHN5X3N2YSwgZmlnLnNob3cgPSAiaGlkZSJ9CmJpb3BfZGVfc3ZhIDwtIHNtKGFsbF9wYWlyd2lzZShiaW9wLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKSkKYmlvcF90YWJsZXNfc3ZhIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgYmlvcF9kZV9zdmEsIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfYWxsX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSkpCmJpb3Bfc2lnX3N2YSA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgYmlvcF90YWJsZXNfc3ZhLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfc2lnX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSwKICAgIGFjY29yZGluZ190byA9ICJkZXNlcSIpKQpgYGAKCiMjIyMgQmlvcHN5IERFIHBsb3RzCgpgYGB7ciBiaW9wX2RlX3Bsb3RzfQojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpiaW9wX3RhYmxlc1tbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpiaW9wX3RhYmxlc1tbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmJpb3BfdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpiaW9wX3RhYmxlc19zdmFbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CmBgYAoKIyBMb29rIGZvciBzaGFyZWQgZ2VuZXMgYW1vbmcgTW9ub2N5dGVzL05ldXRyb3BoaWxzL0Vvc2lub3BoaWxzCgpXZSBoYXZlIHRocmVlIHZhcmlhYmxlcyBjb250YWluaW5nIHRoZSAnc2lnbmlmaWNhbnQnIERFIGdlbmVzIGZvciB0aGUKdGhyZWUgY2VsbCB0eXBlcy4gIEZvciB0aGlzIEkgYW0gY2hvb3NpbmcgKGZvciB0aGUgbW9tZW50KSB0byB1c2UgdGhlCnN2YSBkYXRhLgoKYGBge3Igc2hhcmVkX2J5X3R5cGV9CiMjIG1vbm9fc2lnX3N2YSwgbmV1dF9zaWdfc3ZhLCBlb19zaWdfc3ZhCnNpZ192ZWN0b3JzIDwtIGxpc3QoCiAgICAibW9ub2N5dGVzIiA9IGMocm93bmFtZXMobW9ub19zaWdfc3ZhW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0pLAogICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKG1vbm9fc2lnX3N2YVtbImRlc2VxIl1dW1siZG93bnMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0pKSwKICAgICJuZXV0cm9waGlscyIgPSBjKHJvd25hbWVzKG5ldXRfc2lnX3N2YVtbImRlc2VxIl1dW1sidXBzIl1dW1siZmFpbF92c19jdXJlIl1dKSwKICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKG5ldXRfc2lnX3N2YVtbImRlc2VxIl1dW1siZG93bnMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0pKSwKICAgICJlb3Npbm9waGlscyIgPSAgYyhyb3duYW1lcyhlb19zaWdfc3ZhW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0pLAogICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKGVvX3NpZ19zdmFbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siZmFpbF92c19jdXJlIl1dKSkpCgpzaGFyZWRfdmVjdG9yIDwtIFZlbm5lcmFibGU6OlZlbm4oU2V0cyA9IHNpZ192ZWN0b3JzKQpWZW5uZXJhYmxlOjpwbG90KHNoYXJlZF92ZWN0b3IsIGRvV2VpZ2h0cyA9IEZBTFNFKQoKc2hhcmVkX2lkcyA8LSBzaGFyZWRfdmVjdG9yQEludGVyc2VjdGlvblNldHNbWyIxMTEiXV0Kc2hhcmVkX2V4cHQgPC0gZXhjbHVkZV9nZW5lc19leHB0KGhzX2NsaW5pY2FsLCBpZHMgPSBzaGFyZWRfaWRzLCBtZXRob2QgPSAia2VlcCIpCnNoYXJlZF93cml0dGVuIDwtIHdyaXRlX2V4cHQoc2hhcmVkX2V4cHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9zaGFyZWRfYWNyb3NzX2NlbGx0eXBlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgTW9ub2N5dGVzIGJ5IHZpc2l0CgogMS4gQ2FuIHlvdSBwbGVhc2Ugc2hhcmUgd2l0aCB1cyBhIFBDQSAoU1ZBIGFuZCBub24tU1ZBKSBvZiB0aGUKICAgIG1vbm9jeXRlcyBvZiB0aGUgVE1SQzMgcHJvamVjdCwgYnV0IGxhYmVsaW5nIHRoZW0gYmFzZWQgb24gdGhlIHZpc2l0CiAgICAoVjEsIFYyLCBWMyk/CiAyLiBDYW4geW91IHBsZWFzZSBzaGFyZSBERSBsaXN0cyBvZiBWMSB2cyBWMiwgVjEgdnMgVjMsIFYxIHZzLiBWMitWMwogICAgYW5kIFYyIHZzIFYzPwoKYGBge3IgbW9ub2N5dGVzX2J5X3Zpc2l0fQp2aXNpdF9jb2xvcnMgPC0gY2hvc2VuX2NvbG9ycyA8LSBjKCIjRDk1RjAyIiwgIiM3NTcwQjMiLCAiIzFCOUU3NyIpCm5hbWVzKHZpc2l0X2NvbG9ycykgPC0gYygxLCAyLCAzKQptb25vX3Zpc2l0IDwtIHN1YnNldF9leHB0KGhzX3ZhbGlkLCBzdWJzZXQgPSAidHlwZW9mY2VsbHM9PSdtb25vY3l0ZXMnIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0ID0gInZpc2l0bnVtYmVyIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnMgPSBjaG9zZW5fY29sb3JzKQoKbW9ub192aXNpdF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KG1vbm9fdmlzaXQsIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIpCm1vbm9fdmlzaXRfcGNhIDwtIHBsb3RfcGNhKG1vbm9fdmlzaXRfbm9ybSkKcHAoZmlsZSA9ICJpbWFnZXMvbW9ub2N5dGVfYnlfdmlzaXQucG5nIiwgaW1hZ2UgPSBtb25vX3Zpc2l0X3BjYSRwbG90KQoKbW9ub192aXNpdF9uYiA8LSBub3JtYWxpemVfZXhwdChtb25vX3Zpc2l0LCBmaWx0ZXIgPSBUUlVFLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2ggPSAic3Zhc2VxIiwgdHJhbnNmb3JtID0gImxvZzIiKQptb25vX3Zpc2l0X25iX3BjYSA8LSBwbG90X3BjYShtb25vX3Zpc2l0X25iKQpwcChmaWxlID0gImltYWdlcy9tb25vY3l0ZV9ieV92aXNpdF9uYi5wbmciLCBpbWFnZSA9IG1vbm9fdmlzaXRfbmJfcGNhJHBsb3QpCgp0YWJsZShwRGF0YShtb25vX3Zpc2l0X25vcm0pJGJhdGNoKQpgYGAKCmBgYHtyIG1vbm9fdmlzaXRfZGUsIGZpZy5zaG93ID0gImhpZGUifQprZWVwZXJzIDwtIGxpc3QoCiAgICAic2Vjb25kX3ZzX2ZpcnN0IiA9IGMoImMyIiwgImMxIiksCiAgICAidGhpcmRfdnNfc2Vjb25kIiA9IGMoImMzIiwgImMyIiksCiAgICAidGhpcmRfdnNfZmlyc3QiID0gYygiYzMiLCAiYzEiKSkKbW9ub192aXNpdF9kZSA8LSBhbGxfcGFpcndpc2UobW9ub192aXNpdCwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKCm1vbm9fdmlzaXRfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbW9ub192aXNpdF9kZSwKICAgIGtlZXBlcnMgPSBrZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJleGNlbC9tb25vX3Zpc2l0X3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCmBgYHtyIHYxX3ZzX2FsbH0KbmV3X2ZhY3RvciA8LSBhcy5jaGFyYWN0ZXIocERhdGEobW9ub192aXNpdClbWyJ2aXNpdG51bWJlciJdXSkKbm90X29uZV9pZHggPC0gbmV3X2ZhY3RvciAhPSAxCm5ld19mYWN0b3Jbbm90X29uZV9pZHhdIDwtICJub3RfMSIKbW9ub19vbmVfdnMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtb25vX3Zpc2l0LCBuZXdfZmFjdG9yKQoKbW9ub19vbmVfdnNfZGUgPC0gYWxsX3BhaXJ3aXNlKG1vbm9fb25lX3ZzLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQoKbW9ub19vbmVfdnNfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbW9ub19vbmVfdnNfZGUsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImV4Y2VsL21vbm9fb25lX3ZzX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgVGVzdCBUU1AKCkluIHdyaXRpbmcgdGhlIGZvbGxvd2luZywgSSBxdWlja2x5IHJlYWxpemVkIHRoYXQgdHNwYWlyIHdhcyBub3QKam9raW5nIHdoZW4gaXQgc2FpZCBpdCBpcyBpbnRlbmRlZCBmb3Igc21hbGwgbnVtYmVycyBvZiBnZW5lcy4gIEZvciBhCmZ1bGwgZXhwcmVzc2lvbnNldCBvZiBodW1hbiBkYXRhIGl0IGlzIHN0cnVnZ2xpbmcuICBJIGxpa2UgdGhlIGlkZWEsCml0IG1heSBwcm92ZSB3b3J0aCB3aGlsZSB0byBzcGVuZCBzb21lIHRpbWUgb3B0aW1pemluZyB0aGUgcGFja2FnZSBzbwp0aGF0IGl0IGlzIG1vcmUgdXNhYmxlLgoKYGBge3IgdHNwLCBldmFsID0gRkFMU0V9CmV4cHQgPC0gaHNfY2xpbmljYWxfbm9iaW9wCgpzaW1wbGVfdHNwIDwtIGZ1bmN0aW9uKGV4cHQsIGNvbHVtbiA9ICJjb25kaXRpb24iKSB7CiAgZmFjdHMgPC0gbGV2ZWxzKGFzLmZhY3RvcihwRGF0YShleHB0KVtbY29sdW1uXV0pKQogIHJldGxpc3QgPC0gbGlzdCgpCiAgaWYgKGxlbmd0aChmYWN0cykgPCAyKSB7CiAgICBzdG9wKCJUaGlzIHJlcXVpcmVzIGZhY3RvcnMgd2l0aCBhdCBsZWFzdCAyIGxldmVscy4iKQogIH0gZWxzZSBpZiAobGVuZ3RoKGZhY3RzKSA9PSAyKSB7CiAgICByZXRsaXN0IDwtIHNpbXBsZV90c3BfcGFpcihleHB0LCBjb2x1bW4gPSBjb2x1bW4pCiAgfSBlbHNlIHsKICAgIGZvciAoZmlyc3QgaW4gMToobGVuZ3RoKGZhY3RzKSAtIDEpKSB7CiAgICAgIGZvciAoc2Vjb25kIGluIDI6KGxlbmd0aChmYWN0cykpKSB7CiAgICAgICAgaWYgKGZpcnN0IDwgc2Vjb25kKSB7CiAgICAgICAgICBuYW1lIDwtIGdsdWU6OmdsdWUoIntmYWN0c1tmaXJzdF19X3ZzX3tmYWN0c1tzZWNvbmRdfSIpCiAgICAgICAgICBtZXNzYWdlKCJTdGFydGluZyAiLCBuYW1lLCAiLiIpCiAgICAgICAgICBzdWJzdHJpbmcgPC0gZ2x1ZTo6Z2x1ZSgie2NvbHVtbn09PSd7ZmFjdHNbZmlyc3RdfSd8e2NvbHVtbn09PSd7ZmFjdHNbc2Vjb25kXX0nIikKICAgICAgICAgIHN1YmJ5IDwtIHN1YnNldF9leHB0KGV4cHQsIHN1YnNldD1hcy5jaGFyYWN0ZXIoc3Vic3RyaW5nKSkKICAgICAgICAgIHJldGxpc3RbW25hbWVdXSA8LSBzaW1wbGVfdHNwX3BhaXIoc3ViYnksIGNvbHVtbiA9IGNvbHVtbikKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCnNpbXBsZV90c3BfcGFpciA8LSBmdW5jdGlvbihzdWJieSwgY29sdW1uID0gImNvbmRpdGlvbiIsIHJlcGV0aXRpb25zID0gNTApIHsKICB0c3BfaW5wdXQgPC0gc3ViYnlbWyJleHByZXNzaW9uc2V0Il1dCiAgdHNwX291dHB1dCA8LSB0c3BjYWxjKHRzcF9pbnB1dCwgY29sdW1uKQogIHRzcF9zY29yZXMgPC0gdHNwc2lnKHRzcF9pbnB1dCwgY29sdW1uLCBCID0gcmVwZXRpdGlvbnMpCn0KCnRzcDEgPC0gdHNwY2FsYyh0c3BfaW5wdXQsICJjb25kaXRpb24iKQoKYGBgCgpgYGB7ciBzYXZlbWV9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIHBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCiAgbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCiAgbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCBzYXZlZmlsZSkpCiAgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZSA9IHNhdmVmaWxlKSkKfQpgYGAKCmBgYHtyIGxvYWRtZV9hZnRlciwgZXZhbCA9IEZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=